[ecflow] 02/50: ecflow 4.1.0
Alastair McKinstry
mckinstry at moszumanska.debian.org
Wed Sep 20 15:30:32 UTC 2017
This is an automated email from the git hooks/post-receive script.
mckinstry pushed a commit to branch debian/master
in repository ecflow.
commit 8c55d4ddf9e24cd30fe187fc5511b60c74597d9f
Author: Alastair McKinstry <mckinstry at debian.org>
Date: Tue Jul 26 16:57:30 2016 +0100
ecflow 4.1.0
---
ACore/CMakeLists.txt | 41 +
ACore/Jamfile.jam | 46 +
ACore/ecflow_source_build_dir.h.in | 7 +
{ecflow_4_0_7/ACore => ACore}/ecflow_version.h.in | 0
ACore/src/Archive.hpp | 57 +
ACore/src/ArgvCreator.cpp | 53 +
ACore/src/ArgvCreator.hpp | 43 +
ACore/src/AssertTimer.cpp | 32 +
ACore/src/AssertTimer.hpp | 43 +
ACore/src/Calendar.cpp | 386 +
ACore/src/Calendar.hpp | 255 +
ACore/src/CalendarUpdateParams.hpp | 71 +
ACore/src/CheckPt.hpp | 42 +
ACore/src/Child.cpp | 167 +
ACore/src/Child.hpp | 61 +
ACore/src/DState.cpp | 136 +
ACore/src/DState.hpp | 72 +
ACore/src/DurationTimer.hpp | 39 +
ACore/src/Ecf.cpp | 66 +
ACore/src/Ecf.hpp | 92 +
ACore/src/EcfPortLock.hpp | 84 +
ACore/src/Extract.cpp | 125 +
ACore/src/Extract.hpp | 57 +
ACore/src/File.cpp | 975 +++
ACore/src/File.hpp | 154 +
ACore/src/File_r.cpp | 24 +
ACore/src/File_r.hpp | 42 +
ACore/src/Host.cpp | 93 +
ACore/src/Host.hpp | 54 +
ACore/src/Indentor.cpp | 31 +
ACore/src/Indentor.hpp | 37 +
ACore/src/Log.cpp | 347 +
ACore/src/Log.hpp | 166 +
ACore/src/LogVerification.cpp | 138 +
ACore/src/LogVerification.hpp | 41 +
ACore/src/NOrder.cpp | 55 +
ACore/src/NOrder.hpp | 31 +
ACore/src/NState.cpp | 113 +
ACore/src/NState.hpp | 69 +
ACore/src/NodePath.cpp | 83 +
ACore/src/NodePath.hpp | 46 +
ACore/src/Passwd.cpp | 84 +
ACore/src/Passwd.hpp | 47 +
ACore/src/PrintStyle.cpp | 53 +
ACore/src/PrintStyle.hpp | 50 +
ACore/src/SState.cpp | 58 +
ACore/src/SState.hpp | 46 +
ACore/src/Serialization.hpp | 135 +
ACore/src/SerializationTest.hpp | 71 +
ACore/src/Stl.hpp | 71 +
ACore/src/Str.cpp | 346 +
ACore/src/Str.hpp | 150 +
ACore/src/TimeSeries.cpp | 836 ++
ACore/src/TimeSeries.hpp | 215 +
ACore/src/TimeSlot.cpp | 89 +
ACore/src/TimeSlot.hpp | 86 +
ACore/src/TimeStamp.cpp | 40 +
ACore/src/TimeStamp.hpp | 35 +
ACore/src/Version.cpp | 131 +
ACore/src/Version.hpp | 56 +
ACore/src/WhiteListFile.cpp | 250 +
ACore/src/WhiteListFile.hpp | 60 +
ACore/src/boost_archive.cpp | 60 +
ACore/src/boost_archive.hpp | 96 +
ACore/src/ecflow_version.h | 10 +
.../src/polymorphic_portable_archive.hpp | 0
.../ACore => ACore}/src/portable_archive.hpp | 0
.../src/portable_archive_exception.hpp | 0
.../src/portable_binary_archive.hpp | 0
.../src/portable_binary_iarchive.cpp | 0
.../src/portable_binary_iarchive.hpp | 0
.../src/portable_binary_oarchive.cpp | 0
.../src/portable_binary_oarchive.hpp | 0
.../ACore => ACore}/src/portable_iarchive.hpp | 0
.../ACore => ACore}/src/portable_oarchive.hpp | 0
ACore/test/TestArgvCreator.cpp | 67 +
ACore/test/TestCalendar.cpp | 502 ++
ACore/test/TestExceptionSafety.cpp | 51 +
ACore/test/TestFile.cpp | 312 +
ACore/test/TestGetUserDetails.cpp | 57 +
ACore/test/TestLog.cpp | 365 +
ACore/test/TestMigration.cpp | 73 +
ACore/test/TestNodePath.cpp | 148 +
ACore/test/TestRealCalendar.cpp | 355 +
ACore/test/TestSerialisation.cpp | 135 +
ACore/test/TestStackTrace.cpp | 80 +
ACore/test/TestStr.cpp | 694 ++
ACore/test/TestTimeSeries.cpp | 676 ++
ACore/test/TestTimeSlot.cpp | 109 +
ACore/test/TestVersion.cpp | 85 +
ACore/test/TestVersioning.cpp | 68 +
ACore/test/TestVersioning.hpp | 97 +
ACore/test/TestWhiteListFile.cpp | 279 +
.../test/data/badWhiteListFiles/bad2.lists | 0
.../test/data/badWhiteListFiles/bad3.lists | 0
.../test/data/badWhiteListFiles/bad5.lists | 0
.../test/data/badWhiteListFiles/badsms.lists | 0
.../data/goodWhiteListFiles/all_read_access.lists | 16 +
.../data/goodWhiteListFiles/all_write_access.lists | 14 +
ACore/test/data/goodWhiteListFiles/empty.lists | 1 +
ACore/test/data/goodWhiteListFiles/good1.lists | 15 +
ACore/test/data/goodWhiteListFiles/goodsms.lists | 6 +
.../test/data/migration/calendar_v1.9 | 0
.../test/data/migration/timeseries_10_10_v1_9 | 0
.../migration/timeseries_default_constructor_v1.9 | 0
.../test/data/migration/timeslot_1_1_v1_9 | 0
.../test/data/migration/timeslot_99_59_v1_9 | 0
.../migration/timeslot_default_constructor_v1.9 | 0
{ecflow_4_0_7/ANattr => ANattr}/CMakeLists.txt | 0
ANattr/jamfile.jam | 44 +
ANattr/src/AutoCancelAttr.cpp | 103 +
ANattr/src/AutoCancelAttr.hpp | 59 +
ANattr/src/ClockAttr.cpp | 169 +
ANattr/src/ClockAttr.hpp | 100 +
ANattr/src/CronAttr.cpp | 724 ++
ANattr/src/CronAttr.hpp | 140 +
ANattr/src/DateAttr.cpp | 298 +
ANattr/src/DateAttr.hpp | 102 +
ANattr/src/DayAttr.cpp | 196 +
ANattr/src/DayAttr.hpp | 90 +
ANattr/src/LateAttr.cpp | 241 +
ANattr/src/LateAttr.hpp | 117 +
ANattr/src/NodeAttr.cpp | 366 +
ANattr/src/NodeAttr.hpp | 211 +
ANattr/src/RepeatAttr.cpp | 974 +++
ANattr/src/RepeatAttr.hpp | 487 ++
ANattr/src/TimeAttr.cpp | 188 +
ANattr/src/TimeAttr.hpp | 134 +
ANattr/src/TodayAttr.cpp | 193 +
ANattr/src/TodayAttr.hpp | 185 +
ANattr/src/Variable.cpp | 92 +
ANattr/src/Variable.hpp | 75 +
ANattr/src/VerifyAttr.cpp | 77 +
ANattr/src/VerifyAttr.hpp | 73 +
ANattr/src/Zombie.cpp | 216 +
ANattr/src/Zombie.hpp | 167 +
ANattr/src/ZombieAttr.cpp | 242 +
ANattr/src/ZombieAttr.hpp | 82 +
ANattr/test/TestAttrSerialization.cpp | 297 +
ANattr/test/TestCron.cpp | 439 +
ANattr/test/TestDayAttr.cpp | 77 +
ANattr/test/TestLabel.cpp | 83 +
ANattr/test/TestLateAttr.cpp | 285 +
ANattr/test/TestMigration.cpp | 187 +
ANattr/test/TestRepeat.cpp | 592 ++
ANattr/test/TestTimeAttr.cpp | 345 +
ANattr/test/TestTodayAttr.cpp | 181 +
ANattr/test/TestVariable.cpp | 57 +
.../default_constructor_v1_9/AutoCancelAttr | 0
.../migration/default_constructor_v1_9/ClockAttr | 0
.../migration/default_constructor_v1_9/CronAttr | 0
.../migration/default_constructor_v1_9/DateAttr | 0
.../migration/default_constructor_v1_9/DayAttr | 0
.../data/migration/default_constructor_v1_9/Event | 0
.../data/migration/default_constructor_v1_9/Label | 0
.../migration/default_constructor_v1_9/LateAttr | 0
.../data/migration/default_constructor_v1_9/Meter | 0
.../migration/default_constructor_v1_9/RepeatDate | 0
.../default_constructor_v1_9/RepeatEnumerated | 0
.../default_constructor_v1_9/RepeatInteger | 0
.../default_constructor_v1_9/RepeatString | 0
.../migration/default_constructor_v1_9/TimeAttr | 0
.../migration/default_constructor_v1_9/TodayAttr | 0
.../migration/default_constructor_v1_9/Variable | 0
.../migration/default_constructor_v1_9/VerifyAttr | 0
.../migration/default_constructor_v1_9/ZombieAttr | 0
ANattr/test/data/migration/v1_9/AutoCancelAttr | 1 +
ANattr/test/data/migration/v1_9/AutoCancelAttr_1 | 1 +
ANattr/test/data/migration/v1_9/ClockAttr | 1 +
ANattr/test/data/migration/v1_9/CronAttr | 1 +
ANattr/test/data/migration/v1_9/DateAttr | 1 +
ANattr/test/data/migration/v1_9/DayAttr | 1 +
ANattr/test/data/migration/v1_9/Event_1 | 1 +
ANattr/test/data/migration/v1_9/Event_2 | 1 +
ANattr/test/data/migration/v1_9/Label | 1 +
ANattr/test/data/migration/v1_9/LateAttr | 1 +
ANattr/test/data/migration/v1_9/Meter | 1 +
ANattr/test/data/migration/v1_9/RepeatDate | 2 +
ANattr/test/data/migration/v1_9/RepeatEnumerated | 2 +
ANattr/test/data/migration/v1_9/RepeatInteger | 2 +
ANattr/test/data/migration/v1_9/RepeatString | 2 +
ANattr/test/data/migration/v1_9/TimeAttr | 1 +
ANattr/test/data/migration/v1_9/TodayAttr | 1 +
ANattr/test/data/migration/v1_9/Variable | 1 +
ANattr/test/data/migration/v1_9/VerifyAttr | 1 +
ANattr/test/data/migration/v1_9/ZombieAttr | 1 +
ANattr/test/data/migration/v1_9/ZombieAttr1 | 1 +
ANode/CMakeLists.txt | 79 +
ANode/jamfile.jam | 64 +
ANode/src/AbstractObserver.hpp | 35 +
ANode/src/Alias.cpp | 165 +
ANode/src/Alias.hpp | 94 +
ANode/src/Aspect.hpp | 42 +
ANode/src/ChildAttrs.cpp | 556 ++
ANode/src/ChildAttrs.hpp | 135 +
ANode/src/ClientSuiteMgr.cpp | 280 +
ANode/src/ClientSuiteMgr.hpp | 118 +
ANode/src/ClientSuites.cpp | 332 +
ANode/src/ClientSuites.hpp | 145 +
ANode/src/CmdContext.cpp | 29 +
ANode/src/CmdContext.hpp | 36 +
ANode/src/Defs.cpp | 1519 ++++
ANode/src/Defs.hpp | 427 +
ANode/src/DefsDelta.cpp | 81 +
ANode/src/DefsDelta.hpp | 88 +
ANode/src/EcfFile.cpp | 1425 +++
ANode/src/EcfFile.hpp | 118 +
ANode/src/ExprAst.cpp | 1238 +++
ANode/src/ExprAst.hpp | 520 ++
ANode/src/ExprAstVisitor.cpp | 74 +
ANode/src/ExprAstVisitor.hpp | 148 +
ANode/src/ExprDuplicate.cpp | 61 +
ANode/src/ExprDuplicate.hpp | 44 +
ANode/src/ExprParser.cpp | 950 ++
ANode/src/ExprParser.hpp | 64 +
ANode/src/Expression.cpp | 237 +
ANode/src/Expression.hpp | 153 +
ANode/src/Family.cpp | 196 +
ANode/src/Family.hpp | 86 +
ANode/src/Flag.cpp | 165 +
ANode/src/Flag.hpp | 119 +
ANode/src/InLimit.cpp | 83 +
ANode/src/InLimit.hpp | 72 +
ANode/src/InLimitMgr.cpp | 436 +
ANode/src/InLimitMgr.hpp | 131 +
ANode/src/JobCreationCtrl.cpp | 32 +
ANode/src/JobCreationCtrl.hpp | 52 +
ANode/src/JobProfiler.cpp | 70 +
ANode/src/JobProfiler.hpp | 52 +
ANode/src/Jobs.cpp | 126 +
ANode/src/Jobs.hpp | 69 +
ANode/src/JobsParam.cpp | 31 +
ANode/src/JobsParam.hpp | 84 +
ANode/src/Limit.cpp | 209 +
ANode/src/Limit.hpp | 93 +
ANode/src/LimitFwd.hpp | 22 +
ANode/src/Memento.cpp | 114 +
ANode/src/Memento.hpp | 743 ++
ANode/src/MiscAttrs.cpp | 178 +
ANode/src/MiscAttrs.hpp | 89 +
ANode/src/Node.cpp | 1961 +++++
ANode/src/Node.hpp | 764 ++
ANode/src/NodeAdd.cpp | 299 +
ANode/src/NodeChange.cpp | 195 +
ANode/src/NodeContainer.cpp | 1013 +++
ANode/src/NodeContainer.hpp | 151 +
ANode/src/NodeDelete.cpp | 272 +
ANode/src/NodeFind.cpp | 781 ++
ANode/src/NodeFwd.hpp | 107 +
ANode/src/NodeMemento.cpp | 584 ++
ANode/src/NodeState.hpp | 65 +
ANode/src/NodeTreeVisitor.cpp | 23 +
ANode/src/NodeTreeVisitor.hpp | 40 +
ANode/src/ResolveExternsVisitor.cpp | 125 +
ANode/src/ResolveExternsVisitor.hpp | 81 +
ANode/src/ServerState.cpp | 467 +
ANode/src/ServerState.hpp | 140 +
ANode/src/Signal.cpp | 66 +
ANode/src/Signal.hpp | 38 +
ANode/src/Submittable.cpp | 955 ++
ANode/src/Submittable.hpp | 206 +
ANode/src/Suite.cpp | 767 ++
ANode/src/Suite.hpp | 178 +
ANode/src/SuiteChanged.cpp | 89 +
ANode/src/SuiteChanged.hpp | 68 +
ANode/src/System.cpp | 411 +
ANode/src/System.hpp | 89 +
ANode/src/Task.cpp | 809 ++
ANode/src/Task.hpp | 172 +
ANode/src/TaskScriptGenerator.cpp | 263 +
ANode/src/TaskScriptGenerator.hpp | 46 +
ANode/src/TimeDepAttrs.cpp | 872 ++
ANode/src/TimeDepAttrs.hpp | 149 +
ANode/test/MyDefsFixture.hpp | 249 +
ANode/test/TestAdd.cpp | 51 +
ANode/test/TestAlias.cpp | 103 +
ANode/test/TestChangeMgrSingleton.cpp | 122 +
ANode/test/TestDefStatus.cpp | 154 +
ANode/test/TestDefs.cpp | 84 +
ANode/test/TestEcfFile.cpp | 1184 +++
ANode/test/TestEnviromentSubstitution.cpp | 85 +
ANode/test/TestExprParser.cpp | 399 +
ANode/test/TestExprRepeatDateArithmetic.cpp | 216 +
ANode/test/TestFindAbsNodePath.cpp | 75 +
ANode/test/TestFlag.cpp | 75 +
ANode/test/TestHistoryParser.cpp | 93 +
ANode/test/TestInLimit.cpp | 76 +
ANode/test/TestJobCreator.cpp | 120 +
ANode/test/TestJobProfiler.cpp | 89 +
ANode/test/TestLimit.cpp | 184 +
ANode/test/TestMigration.cpp | 113 +
ANode/test/TestMissNextTimeSlot.cpp | 114 +
ANode/test/TestNodeBeginReque.cpp | 75 +
ANode/test/TestNodeState.cpp | 127 +
ANode/test/TestOrder.cpp | 336 +
ANode/test/TestPersistence.cpp | 79 +
ANode/test/TestPreProcessing.cpp | 231 +
ANode/test/TestReplace.cpp | 575 ++
ANode/test/TestSetState.cpp | 140 +
ANode/test/TestSingleExprParse.cpp | 76 +
ANode/test/TestSmsLocator.cpp | 128 +
ANode/test/TestTaskScriptGenerator.cpp | 205 +
ANode/test/TestTimeDependencies.cpp | 116 +
ANode/test/TestVariableGeneration.cpp | 93 +
ANode/test/TestVariableInheritance.cpp | 78 +
ANode/test/TestVariableSubstitution.cpp | 438 +
ANode/test/TestVariableSubstitutionDefs.cpp | 174 +
ANode/test/TestZombies.cpp | 81 +
ANode/test/Test_ECFLOW-195.cpp | 97 +
ANode/test/Test_ECFLOW-247.cpp | 102 +
ANode/test/Test_ECFLOW-417.cpp | 157 +
.../ANode => ANode}/test/data/SMSHOME/suite.man | 0
.../test/data/SMSHOME/suite/family.man | 0
ANode/test/data/SMSHOME/suite/family/head.h | 44 +
.../test/data/SMSHOME/suite/family/t1.ecf | 0
.../test/data/SMSHOME/suite/family/t2.ecf | 0
.../test/data/SMSHOME/suite/family/t3.ecf | 0
ANode/test/data/SMSHOME/suite/family/tail.h | 10 +
.../test/data/SMSHOME/suite1_task1.ecf | 0
.../test/data/SMSHOME/suite1_task2.ecf | 0
.../test/data/SMSHOME/suite1_task3.ecf | 0
.../ANode => ANode}/test/data/SMSHOME2/bad/bad.ecf | 0
.../test/data/SMSHOME2/bad/bad1.ecf | 0
.../test/data/SMSHOME2/bad/bad10.ecf | 0
.../test/data/SMSHOME2/bad/bad11.ecf | 0
.../test/data/SMSHOME2/bad/bad2.ecf | 0
.../test/data/SMSHOME2/bad/bad3.ecf | 0
.../test/data/SMSHOME2/bad/bad4.ecf | 0
.../test/data/SMSHOME2/bad/bad5.ecf | 0
.../test/data/SMSHOME2/bad/bad6.ecf | 0
.../test/data/SMSHOME2/bad/bad7.ecf | 0
.../test/data/SMSHOME2/bad/bad8.ecf | 0
.../test/data/SMSHOME2/bad/bad9.ecf | 0
.../test/data/SMSHOME2/bad/bad_ecfmicro.ecf | 0
.../test/data/SMSHOME2/bad/bad_ecfmicro_1.ecf | 0
.../data/SMSHOME2/bad/includes/recursive_head.h | 14 +
.../test/data/SMSHOME2/good/.gitignore | 0
.../test/data/SMSHOME2/good/ecf_micro_2.ecf | 0
.../test/data/SMSHOME2/good/ecfmicro.ecf | 0
.../test/data/SMSHOME2/good/good.ecf | 0
.../test/data/SMSHOME2/good/good1.ecf | 0
ANode/test/data/SMSHOME2/good/includes/config.h | 1527 ++++
ANode/test/data/SMSHOME2/good/includes/config.oc.h | 197 +
ANode/test/data/SMSHOME2/good/includes/endt.h | 13 +
ANode/test/data/SMSHOME2/good/includes/head.h | 43 +
ANode/test/data/SMSHOME2/good/includes/law.h | 43 +
.../test/data/SMSHOME2/good/includes/qsub.h | 0
ANode/test/data/SMSHOME2/good/includes/rcp.h | 41 +
ANode/test/data/SMSHOME2/good/includes/set_traps.h | 6 +
ANode/test/data/SMSHOME2/good/includes/setup.h | 535 ++
ANode/test/data/SMSHOME2/good/includes/sms.h | 55 +
ANode/test/data/SMSHOME2/good/includes/tail.h | 10 +
ANode/test/data/SMSHOME2/good/includes/trap.h | 137 +
.../test/data/SMSHOME2/good/micro_in_comment.ecf | 0
.../test/data/SMSHOME2/good/operations.ecf | 0
{ecflow_4_0_7/ANode => ANode}/test/data/common.h | 0
ANode/test/data/includes/a.h | 2 +
ANode/test/data/includes/b.h | 1 +
ANode/test/data/includes/head.h | 65 +
.../ANode => ANode}/test/data/includes/manual.h | 0
.../test/data/includes/simple_head.h | 0
.../test/data/includes/simple_tail.h | 0
ANode/test/data/includes/tail.h | 19 +
.../test/data/includes/used_variables.h | 0
.../data/includes/used_variables_with_comments.h | 0
ANode/test/data/includes2/fred.h | 7 +
.../data/migration/default_constructor/Defs.def | 0
.../data/migration/default_constructor/Family.def | 0
.../data/migration/default_constructor/Limit.def | 0
.../data/migration/default_constructor/Suite.def | 0
.../data/migration/default_constructor/Task.def | 0
ANode/test/data/migration/fixture/boost.checkpt | 77 +
AParser/CMakeLists.txt | 74 +
AParser/Jamfile.jam | 126 +
AParser/src/AutoCancelParser.cpp | 55 +
AParser/src/AutoCancelParser.hpp | 27 +
AParser/src/CalendarParser.cpp | 39 +
AParser/src/CalendarParser.hpp | 28 +
AParser/src/ClockParser.cpp | 143 +
AParser/src/ClockParser.hpp | 29 +
AParser/src/CronParser.cpp | 47 +
AParser/src/CronParser.hpp | 30 +
AParser/src/DateParser.cpp | 51 +
AParser/src/DateParser.hpp | 28 +
AParser/src/DayParser.cpp | 46 +
AParser/src/DayParser.hpp | 27 +
AParser/src/DefsParser.cpp | 425 +
AParser/src/DefsParser.hpp | 27 +
AParser/src/DefsStateParser.cpp | 42 +
AParser/src/DefsStateParser.hpp | 35 +
AParser/src/DefsStatusParser.cpp | 52 +
AParser/src/DefsStatusParser.hpp | 28 +
AParser/src/DefsStructureParser.cpp | 220 +
AParser/src/DefsStructureParser.hpp | 79 +
AParser/src/EventParser.cpp | 75 +
AParser/src/EventParser.hpp | 28 +
AParser/src/ExternParser.cpp | 48 +
AParser/src/ExternParser.hpp | 41 +
AParser/src/InlimitParser.cpp | 45 +
AParser/src/InlimitParser.hpp | 28 +
AParser/src/LabelParser.cpp | 35 +
AParser/src/LabelParser.hpp | 28 +
AParser/src/LateParser.cpp | 44 +
AParser/src/LateParser.hpp | 27 +
AParser/src/LimitParser.cpp | 64 +
AParser/src/LimitParser.hpp | 28 +
AParser/src/MeterParser.cpp | 54 +
AParser/src/MeterParser.hpp | 28 +
AParser/src/Parser.cpp | 167 +
AParser/src/Parser.hpp | 80 +
AParser/src/RepeatParser.cpp | 178 +
AParser/src/RepeatParser.hpp | 33 +
AParser/src/TimeParser.cpp | 48 +
AParser/src/TimeParser.hpp | 28 +
AParser/src/TodayParser.cpp | 45 +
AParser/src/TodayParser.hpp | 28 +
AParser/src/TriggerParser.cpp | 180 +
AParser/src/TriggerParser.hpp | 46 +
AParser/src/VariableParser.cpp | 103 +
AParser/src/VariableParser.hpp | 48 +
AParser/src/VerifyParser.cpp | 53 +
AParser/src/VerifyParser.hpp | 29 +
AParser/src/ZombieAttrParser.cpp | 39 +
AParser/src/ZombieAttrParser.hpp | 27 +
AParser/test/ParseOnly.cpp | 51 +
AParser/test/ParseTimer.cpp | 224 +
AParser/test/PersistHelper.cpp | 237 +
AParser/test/PersistHelper.hpp | 58 +
AParser/test/TestAutoAddExterns.cpp | 69 +
AParser/test/TestDefsStructurePersistAndReload.cpp | 96 +
AParser/test/TestJobGenPerf.cpp | 84 +
AParser/test/TestMigration.cpp | 429 +
AParser/test/TestParser.cpp | 121 +
AParser/test/TestSingleDefsFile.cpp | 304 +
AParser/test/TestVariableParsing.cpp | 81 +
.../test/data/bad_defs/clock/clock1.def | 0
.../test/data/bad_defs/clock/clock2.def | 0
.../test/data/bad_defs/cron/cron1.def | 0
.../test/data/bad_defs/cron/cron2.def | 0
.../test/data/bad_defs/cron/cron3.def | 0
.../test/data/bad_defs/cron/cron4.def | 0
.../test/data/bad_defs/cron/cron5.def | 0
.../test/data/bad_defs/cron/cron5_1.def | 0
.../test/data/bad_defs/cron/cron6.def | 0
.../test/data/bad_defs/cron/cron7.def | 0
.../test/data/bad_defs/cron/repeat_with_cron.def | 0
.../test/data/bad_defs/date/date.def | 0
.../test/data/bad_defs/date/date0.def | 0
.../test/data/bad_defs/date/date1.def | 0
.../test/data/bad_defs/date/date2.def | 0
.../test/data/bad_defs/date/date3.def | 0
.../test/data/bad_defs/date/date4.def | 0
.../test/data/bad_defs/date/date5.def | 0
.../test/data/bad_defs/day/day.def | 0
.../test/data/bad_defs/defstatus/defstatus.def | 0
.../test/data/bad_defs/event/event_1.def | 0
.../test/data/bad_defs/event/event_2.def | 0
.../test/data/bad_defs/event/event_3.def | 0
.../test/data/bad_defs/event/event_4.def | 0
.../test/data/bad_defs/event/simple_event.txt | 0
.../test/data/bad_defs/extern/bad.def | 0
.../test/data/bad_defs/extern/complete.def | 0
.../test/data/bad_defs/extern/trigger1.def | 0
.../test/data/bad_defs/extern/trigger2.def | 0
.../test/data/bad_defs/family/family.def | 0
.../test/data/bad_defs/family/family_1.def | 0
.../test/data/bad_defs/family/simple_family.txt | 0
.../test/data/bad_defs/inlimit/limit.def | 0
.../test/data/bad_defs/inlimit/limt2.def | 0
.../test/data/bad_defs/late/late.def | 0
.../test/data/bad_defs/late/late2.def | 0
.../test/data/bad_defs/late/late3.def | 0
.../test/data/bad_defs/late/late4.def | 0
.../test/data/bad_defs/limit/limit.def | 0
.../test/data/bad_defs/meter/meter.def | 0
.../test/data/bad_defs/meter/meter2.def | 0
.../test/data/bad_defs/meter/meter3.def | 0
.../data/bad_defs/repeat/date_missing_name.def | 3 +
.../bad_defs/repeat/duplicate_repeats_per_node.def | 4 +
.../test/data/bad_defs/repeat/invalid_dates.def | 3 +
.../test/data/bad_defs/repeat/invalid_dates_2.def | 3 +
AParser/test/data/bad_defs/repeat/repeat_date1.def | 3 +
AParser/test/data/bad_defs/repeat/repeat_date2.def | 3 +
AParser/test/data/bad_defs/repeat/repeat_date3.def | 3 +
.../test/data/bad_defs/repeat/repeat_integer.def | 5 +
AParser/test/data/bad_defs/repeat/repeat_month.def | 4 +
.../test/data/bad_defs/repeat/repeat_with_cron.def | 4 +
AParser/test/data/bad_defs/repeat/repeat_year.def | 3 +
.../data/bad_defs/repeat/string_missing_name.def | 3 +
.../test/data/bad_defs/suite/clock.def | 0
.../test/data/bad_defs/suite/clock1.def | 0
.../test/data/bad_defs/suite/simple_suite.txt | 0
.../test/data/bad_defs/task/simple_task.txt | 0
.../test/data/bad_defs/task/task.def | 0
.../test/data/bad_defs/task/task_1.def | 0
.../test/data/bad_defs/time/time.def | 0
.../test/data/bad_defs/time/time_1.def | 0
.../test/data/bad_defs/time/time_2.def | 0
.../test/data/bad_defs/time/time_3.def | 0
.../test/data/bad_defs/time/time_4.def | 0
.../test/data/bad_defs/time/time_5.def | 0
.../test/data/bad_defs/time/time_6.def | 0
.../test/data/bad_defs/time/time_7.def | 0
.../test/data/bad_defs/time/time_8.def | 0
.../test/data/bad_defs/today/today.def | 0
.../test/data/bad_defs/today/today1.def | 0
.../test/data/bad_defs/trigger/bad_trigger2.txt | 0
.../test/data/bad_defs/trigger/bad_trigger3.txt | 0
.../test/data/bad_defs/trigger/bad_trigger4.txt | 0
.../test/data/bad_defs/trigger/bad_trigger5.txt | 0
.../test/data/bad_defs/trigger/complex.def | 0
.../test/data/bad_defs/trigger/divide_by_zero.txt | 0
.../test/data/bad_defs/trigger/extern_trigger.def | 0
.../test/data/bad_defs/trigger/modulo_by_zero.txt | 0
.../trigger/simple_trigger_bad_expression.txt | 0
.../test/data/bad_defs/trigger/trigger.txt | 0
.../test/data/bad_defs/trigger/trigger_1.def | 0
.../test/data/bad_defs/variable/bad.def | 0
.../test/data/bad_defs/variable/bad1.def | 0
.../test/data/bad_defs/variable/bad2.def | 0
.../test/data/bad_defs/variable/bad3.def | 0
.../test/data/bad_defs/variable/bad4.def | 0
.../test/data/bad_defs/variable/bad5.def | 0
.../test/data/bad_defs/variable/comment.def | 0
.../test/data/bad_defs/variable/comment2.def | 0
.../test/data/bad_defs/verify/verfiy3.def | 0
.../test/data/bad_defs/verify/verify.def | 0
.../test/data/bad_defs/verify/verify2.def | 0
.../test/data/bad_defs/verify/verify4.def | 0
.../test/data/bad_defs/zombie/bad.def | 0
.../test/data/bad_defs/zombie/bad2.def | 0
.../test/data/bad_defs/zombie/bad3.def | 0
.../test/data/bad_defs/zombie/bad4.def | 0
.../test/data/bad_defs/zombie/bad5.def | 0
.../test/data/good_defs/clock/clock.def | 0
.../test/data/good_defs/clock/clock1.def | 0
.../test/data/good_defs/clock/clock2.def | 0
.../test/data/good_defs/clock/clock3.def | 0
.../test/data/good_defs/clock/clock4.def | 0
.../test/data/good_defs/clock/clock5.def | 0
.../test/data/good_defs/clock/clock6.def | 0
.../test/data/good_defs/comment/comment.txt | 0
.../test/data/good_defs/complete/complete.def | 0
.../test/data/good_defs/complete/complex.def | 0
.../test/data/good_defs/cron/cron.def | 0
.../test/data/good_defs/cron/cron1.def | 0
.../test/data/good_defs/cron/cron2.def | 0
.../test/data/good_defs/date/date.def | 0
.../test/data/good_defs/day/day.def | 0
.../test/data/good_defs/defstatus/defstatus.txt | 0
.../test/data/good_defs/edit/edit.def | 0
.../test/data/good_defs/event/event_1.def | 0
.../test/data/good_defs/event/event_2.def | 0
.../test/data/good_defs/event/family_event.def | 0
.../test/data/good_defs/event/spaces.def | 0
.../test/data/good_defs/event/suite_event.def | 0
.../test/data/good_defs/extern/extern.def | 0
.../test/data/good_defs/extern/first.def | 0
.../test/data/good_defs/extern/plain.def | 0
.../test/data/good_defs/extern/second.def | 0
.../test/data/good_defs/extern/simple_extern.def | 0
.../data/good_defs/family/hierarchical_family.txt | 0
.../test/data/good_defs/family/missingEnds.txt | 0
.../test/data/good_defs/family/simple_family.txt | 0
.../test/data/good_defs/label/label.txt | 0
.../data/good_defs/label/multi_line_lables.def | 0
.../test/data/good_defs/label/spaces.def | 0
.../test/data/good_defs/late/late.def | 0
.../test/data/good_defs/lifecycle.txt | 0
.../test/data/good_defs/limit/limit.def | 0
.../test/data/good_defs/limit/limit2.def | 0
.../test/data/good_defs/meter/negative.def | 0
.../test/data/good_defs/meter/simple_meter.txt | 0
.../test/data/good_defs/meter/spaces.def | 0
AParser/test/data/good_defs/repeat/repeat_date.def | 10 +
.../test/data/good_defs/repeat/repeat_day.def | 0
.../good_defs/repeat/repeat_enumerate_quotes.def | 0
.../data/good_defs/repeat/repeat_enumerated.def | 0
.../test/data/good_defs/repeat/repeat_file.def | 0
.../test/data/good_defs/repeat/repeat_integer.def | 0
.../data/good_defs/repeat/repeat_integer_1.def | 0
.../data/good_defs/repeat/repeat_integer_2.def | 0
.../test/data/good_defs/repeat/repeat_string.def | 0
.../data/good_defs/repeat/repeat_string_quotes.def | 0
.../good_defs/suite/multi_statements_per_line.def | 0
.../test/data/good_defs/suite/multi_suite.def | 0
.../test/data/good_defs/suite/simple_suite.txt | 0
.../data/good_defs/suite/suite_with_hierarchy.def | 0
.../test/data/good_defs/suite/suite_with_task.def | 0
.../test/data/good_defs/task/simple_task.txt | 0
.../test/data/good_defs/task/spaces.def | 0
.../test/data/good_defs/task/task.def | 0
.../test/data/good_defs/time/time.def | 0
.../test/data/good_defs/time/time_1.def | 0
.../test/data/good_defs/time/time_2.def | 0
.../test/data/good_defs/today/today.def | 0
.../test/data/good_defs/today/today1.def | 0
.../test/data/good_defs/trigger/anded_ored.def | 0
.../test/data/good_defs/trigger/complex_hier.def | 0
.../data/good_defs/trigger/complex_trigger.txt | 0
.../test/data/good_defs/trigger/extension.def | 0
.../test/data/good_defs/trigger/simple_trigger.txt | 0
.../data/good_defs/trigger/trigger_references.def | 0
.../test/data/good_defs/variable/alias.def | 0
.../test/data/good_defs/variable/duplicate.def | 0
.../test/data/good_defs/variable/variable.txt | 0
.../test/data/good_defs/verify/verify.def | 0
.../test/data/good_defs/zombie/zombie.def | 0
.../test/data/good_defs_state/defs/defs_state.def | 4 +
AParser/test/data/single_defs/ECFLOW-417.def | 6 +
.../test/data/single_defs/ealadin.def | 0
.../test/data/single_defs/mega.def | 0
.../test/data/single_defs/test_auto_add_extern.def | 0
.../test/data/single_defs/test_complete.def | 0
.../test/data/single_defs/test_repeat.def | 0
Base/CMakeLists.txt | 110 +
Base/Jamfile.jam | 70 +
Base/src/AbstractClientEnv.hpp | 66 +
Base/src/AbstractServer.hpp | 193 +
Base/src/Client.cpp | 343 +
Base/src/Client.hpp | 83 +
Base/src/ClientToServerRequest.cpp | 58 +
Base/src/ClientToServerRequest.hpp | 67 +
Base/src/Cmd.hpp | 27 +
Base/src/Connection.hpp | 315 +
Base/src/Gnuplot.cpp | 379 +
Base/src/Gnuplot.hpp | 78 +
Base/src/ServerReply.cpp | 38 +
Base/src/ServerReply.hpp | 144 +
Base/src/ServerToClientResponse.cpp | 70 +
Base/src/ServerToClientResponse.hpp | 62 +
Base/src/Stats.cpp | 333 +
Base/src/Stats.hpp | 216 +
Base/src/WhyCmd.cpp | 58 +
Base/src/WhyCmd.hpp | 37 +
Base/src/ZombieCtrl.cpp | 772 ++
Base/src/ZombieCtrl.hpp | 143 +
Base/src/cts/AlterCmd.cpp | 1030 +++
Base/src/cts/BeginCmd.cpp | 177 +
Base/src/cts/CFileCmd.cpp | 309 +
Base/src/cts/CSyncCmd.cpp | 160 +
Base/src/cts/CheckPtCmd.cpp | 203 +
Base/src/cts/ClientHandleCmd.cpp | 331 +
Base/src/cts/ClientToServerCmd.cpp | 206 +
Base/src/cts/ClientToServerCmd.hpp | 1847 ++++
Base/src/cts/CtsApi.cpp | 710 ++
Base/src/cts/CtsApi.hpp | 216 +
Base/src/cts/CtsCmd.cpp | 409 +
Base/src/cts/CtsCmdRegistry.cpp | 145 +
Base/src/cts/CtsCmdRegistry.hpp | 56 +
Base/src/cts/CtsNodeCmd.cpp | 338 +
Base/src/cts/EditHistoryMgr.cpp | 120 +
Base/src/cts/EditHistoryMgr.hpp | 42 +
Base/src/cts/EditScriptCmd.cpp | 400 +
Base/src/cts/ForceCmd.cpp | 258 +
Base/src/cts/FreeDepCmd.cpp | 156 +
Base/src/cts/GroupCTSCmd.cpp | 301 +
Base/src/cts/LoadDefsCmd.cpp | 154 +
Base/src/cts/LogCmd.cpp | 258 +
Base/src/cts/LogMessageCmd.cpp | 72 +
Base/src/cts/OrderNodeCmd.cpp | 110 +
Base/src/cts/PathsCmd.cpp | 514 ++
Base/src/cts/PlugCmd.cpp | 392 +
Base/src/cts/ReplaceNodeCmd.cpp | 203 +
Base/src/cts/RequeueNodeCmd.cpp | 236 +
Base/src/cts/RunNodeCmd.cpp | 173 +
Base/src/cts/ServerVersionCmd.cpp | 80 +
Base/src/cts/ShowCmd.cpp | 104 +
Base/src/cts/TaskApi.cpp | 80 +
Base/src/cts/TaskApi.hpp | 43 +
Base/src/cts/TaskCmds.cpp | 923 ++
Base/src/cts/UserCmd.cpp | 154 +
Base/src/cts/ZombieCmd.cpp | 232 +
Base/src/stc/DefsCmd.cpp | 99 +
Base/src/stc/DefsCmd.hpp | 52 +
Base/src/stc/ErrorCmd.cpp | 63 +
Base/src/stc/ErrorCmd.hpp | 45 +
Base/src/stc/GroupSTCCmd.cpp | 124 +
Base/src/stc/GroupSTCCmd.hpp | 44 +
Base/src/stc/PreAllocatedReply.cpp | 201 +
Base/src/stc/PreAllocatedReply.hpp | 71 +
Base/src/stc/SClientHandleCmd.cpp | 34 +
Base/src/stc/SClientHandleCmd.hpp | 42 +
Base/src/stc/SClientHandleSuitesCmd.cpp | 118 +
Base/src/stc/SClientHandleSuitesCmd.hpp | 47 +
Base/src/stc/SNewsCmd.cpp | 262 +
Base/src/stc/SNewsCmd.hpp | 63 +
Base/src/stc/SNodeCmd.cpp | 144 +
Base/src/stc/SNodeCmd.hpp | 58 +
Base/src/stc/SServerLoadCmd.cpp | 46 +
Base/src/stc/SServerLoadCmd.hpp | 48 +
Base/src/stc/SStatsCmd.cpp | 57 +
Base/src/stc/SStatsCmd.hpp | 50 +
Base/src/stc/SStringCmd.cpp | 46 +
Base/src/stc/SStringCmd.hpp | 54 +
Base/src/stc/SStringVecCmd.cpp | 50 +
Base/src/stc/SStringVecCmd.hpp | 46 +
Base/src/stc/SSuitesCmd.cpp | 86 +
Base/src/stc/SSuitesCmd.hpp | 48 +
Base/src/stc/SSyncCmd.cpp | 466 +
Base/src/stc/SSyncCmd.hpp | 160 +
Base/src/stc/ServerToClientCmd.cpp | 26 +
Base/src/stc/ServerToClientCmd.hpp | 62 +
Base/src/stc/StcCmd.cpp | 69 +
Base/src/stc/StcCmd.hpp | 57 +
Base/src/stc/ZombieGetCmd.cpp | 66 +
Base/src/stc/ZombieGetCmd.hpp | 49 +
Base/test/MockServer.hpp | 98 +
Base/test/TestAlterCmd.cpp | 827 ++
Base/test/TestClientHandleCmd.cpp | 260 +
Base/test/TestCmd.cpp | 109 +
Base/test/TestDeleteNodeCmd.cpp | 198 +
Base/test/TestECFLOW-189.cpp | 85 +
Base/test/TestForceCmd.cpp | 920 ++
Base/test/TestFreeDepCmd.cpp | 304 +
Base/test/TestHelper.hpp | 90 +
Base/test/TestLimit.cpp | 669 ++
Base/test/TestLogCmd.cpp | 95 +
Base/test/TestMeterCmd.cpp | 96 +
Base/test/TestProgramOptions.cpp | 160 +
Base/test/TestRequest.cpp | 316 +
Base/test/TestRequeueNodeCmd.cpp | 248 +
Base/test/TestResolveDependencies.cpp | 277 +
Base/test/TestSSyncCmd.cpp | 379 +
Base/test/TestSSyncCmdOrder.cpp | 231 +
Base/test/TestSSyncCmd_CH1.cpp | 674 ++
...MAKE_failed_tests.txt => CMAKE_failed_tests.txt | 0
CMakeLists.txt | 285 +
ecflow_4_0_7/COPYING => COPYING | 0
CSim/CMakeLists.txt | 53 +
CSim/jamfile.jam | 95 +
CSim/src/Analyser.cpp | 57 +
CSim/src/Analyser.hpp | 31 +
CSim/src/AstAnalyserVisitor.cpp | 58 +
CSim/src/AstAnalyserVisitor.hpp | 64 +
CSim/src/DefsAnalyserVisitor.cpp | 167 +
CSim/src/DefsAnalyserVisitor.hpp | 47 +
CSim/src/FlatAnalyserVisitor.cpp | 111 +
CSim/src/FlatAnalyserVisitor.hpp | 43 +
CSim/src/Simulator.cpp | 360 +
CSim/src/Simulator.hpp | 61 +
CSim/src/SimulatorVisitor.cpp | 148 +
CSim/src/SimulatorVisitor.hpp | 73 +
CSim/test/TestAnalysis.cpp | 82 +
CSim/test/TestAutoCancel.cpp | 304 +
CSim/test/TestMeter.cpp | 108 +
CSim/test/TestRepeat.cpp | 448 +
CSim/test/TestSimulator.cpp | 135 +
CSim/test/TestSingleSimulator.cpp | 107 +
CSim/test/TestTime.cpp | 380 +
CSim/test/TestToday.cpp | 158 +
CSim/test/TestUtil.cpp | 28 +
CSim/test/TestUtil.hpp | 36 +
.../CSim => CSim}/test/data/bad_defs/today.def | 0
.../CSim => CSim}/test/data/bad_defs/xde.def | 0
CSim/test/data/bad_defs/xde.def.log | 5 +
.../test/data/good_defs/ECFLOW-130/radarlvl2.def | 0
.../data/good_defs/ECFLOW-130/radarlvl2.def.log | 3131 +++++++
.../test/data/good_defs/SingleDefsTest/test.def | 0
.../data/good_defs/SingleDefsTest/test.def.glog | 42 +
.../data/good_defs/SingleDefsTest/test.def.log | 42 +
.../test/data/good_defs/cron/cron.def | 0
CSim/test/data/good_defs/cron/cron.def.log | 146 +
.../test/data/good_defs/cron/cron2.def | 0
CSim/test/data/good_defs/cron/cron2.def.log | 55 +
.../test/data/good_defs/cron/cron3.def | 0
CSim/test/data/good_defs/cron/cron3.def.log | 81 +
.../test/data/good_defs/cron/cron4.def | 0
CSim/test/data/good_defs/cron/cron4.def.log | 809 ++
.../test/data/good_defs/cron/cron5.def | 0
CSim/test/data/good_defs/cron/cron5.def.log | 107 +
.../test/data/good_defs/cron/cron6.def | 0
CSim/test/data/good_defs/cron/cron6.def.log | 55 +
.../test/data/good_defs/cron/cron7.def | 0
CSim/test/data/good_defs/cron/cron7.def.log | 4735 ++++++++++
.../CSim => CSim}/test/data/good_defs/day/day.def | 0
CSim/test/data/good_defs/day/day.def.log | 29 +
.../test/data/good_defs/day/hybrid_day.def | 0
CSim/test/data/good_defs/day/hybrid_day.def.log | 18 +
.../test/data/good_defs/misc/liefcycle.def | 0
CSim/test/data/good_defs/misc/liefcycle.def.log | 44 +
.../test/data/good_defs/misc/time.def | 0
CSim/test/data/good_defs/misc/time.def.log | 42 +
CSim/test/data/good_defs/operations/loop.def | 24 +
CSim/test/data/good_defs/operations/loop.def.log | 9230 ++++++++++++++++++++
CSim/test/data/good_defs/operations/mars.def | 10 +
CSim/test/data/good_defs/operations/mars.def.log | 81 +
CSim/test/data/good_defs/operations/naw.def | 208 +
CSim/test/data/good_defs/operations/naw.def.log | 270 +
CSim/test/data/good_defs/operations/xbe.def | 9134 +++++++++++++++++++
CSim/test/data/good_defs/operations/xbe.def.log | 2149 +++++
CSim/test/data/good_defs/operations/xde.def.glog | 4 +
CSim/test/data/good_defs/operations/xfi.def | 265 +
CSim/test/data/good_defs/operations/xfi.def.log | 609 ++
CSim/test/data/good_defs/operations/xpt.def | 2562 ++++++
CSim/test/data/good_defs/operations/xpt.def.log | 4946 +++++++++++
.../test/data/good_defs/today/today.def | 0
CSim/test/data/good_defs/today/today.def.log | 12 +
.../test/data/good_defs/today/today2.def | 0
CSim/test/data/good_defs/today/today2.def.log | 66 +
.../test/data/good_defs/today/today_range.def | 0
CSim/test/data/good_defs/today/today_range.def.log | 62 +
CSim/test/data/test_analysys.def.log | 4 +
.../data/test_autocancel_ast_node_reset.def.log | 46 +
.../data/test_autocancel_family_and_task.def.log | 46 +
CSim/test/data/test_autocancel_suite.def.log | 43 +
CSim/test/data/test_autocancel_task.def.log | 43 +
CSim/test/data/test_autocancel_task_1.def.log | 16 +
CSim/test/data/test_meter.def.log | 20 +
.../data/test_multiple_times_and_dates.def.log | 55 +
.../test_multiple_times_and_dates_hybrid.def.log | 31 +
.../test/data/test_multiple_times_and_days.def.log | 55 +
.../test_multiple_times_and_days_hybrid.def.log | 45 +
CSim/test/data/test_repeat_date.def.log | 212 +
CSim/test/data/test_repeat_date_for_loop.def.log | 356 +
CSim/test/data/test_repeat_date_for_loop2.def.log | 681 ++
CSim/test/data/test_repeat_enumerated.def.log | 44 +
CSim/test/data/test_repeat_integer.def.log | 75 +
.../test/data/test_repeat_integer_relative.def.log | 59 +
CSim/test/data/test_repeat_string.def.log | 30 +
CSim/test/data/test_repeat_with_cron.def.log | 104 +
CSim/test/data/test_time.def.log | 16 +
CSim/test/data/test_time_and_date.def.log | 16 +
.../test/data/test_time_and_tomorrows_date.def.log | 16 +
CSim/test/data/test_time_series.def.log | 81 +
CSim/test/data/test_today.def.log | 29 +
CSim/test/data/test_today_time_and_date.def.log | 16 +
CSim/test/data/test_today_time_series.def.log | 68 +
.../data/test_two_autocancel_in_hierarchy.def.log | 17 +
{ecflow_4_0_7/Client => Client}/.gitignore | 0
Client/CMakeLists.txt | 129 +
Client/Jamfile.jam | 137 +
{ecflow_4_0_7/Client => Client}/ecf_hostsfile | 0
Client/src/ClientEnvironment.cpp | 394 +
Client/src/ClientEnvironment.hpp | 150 +
Client/src/ClientInvoker.cpp | 1315 +++
Client/src/ClientInvoker.hpp | 365 +
Client/src/ClientMain.cpp | 32 +
Client/src/ClientOptions.cpp | 329 +
Client/src/ClientOptions.hpp | 50 +
Client/src/Rtt.cpp | 180 +
Client/src/Rtt.hpp | 62 +
Client/src/UrlCmd.cpp | 66 +
Client/src/UrlCmd.hpp | 40 +
Client/test/InvokeServer.hpp | 157 +
Client/test/SCPort.cpp | 63 +
Client/test/SCPort.hpp | 44 +
Client/test/TestCheckPtDefsCmd.cpp | 237 +
Client/test/TestClientEnvironment.cpp | 256 +
Client/test/TestClientInterface.cpp | 564 ++
Client/test/TestClientInvoker.cpp | 63 +
Client/test/TestClientTimeout.cpp | 77 +
Client/test/TestGroupCmd.cpp | 219 +
Client/test/TestJobGenOnly.cpp | 96 +
Client/test/TestLifeCycle.cpp | 216 +
Client/test/TestLoadDefsCmd.cpp | 158 +
Client/test/TestMigration.cpp | 119 +
Client/test/TestPlugCmd.cpp | 321 +
Client/test/TestRtt.cpp | 53 +
Client/test/TestServer.cpp | 318 +
Client/test/TestServerAndLifeCycle.cpp | 247 +
Client/test/TestServerLoad.cpp | 103 +
Client/test/TestSignalSIGTERM.cpp | 82 +
Client/test/TestSinglePerf.cpp | 271 +
Client/test/TestUrlCmd.cpp | 65 +
Client/test/TestWhiteListFile.cpp | 93 +
.../test/data/ECF_HOME/includes/head.h | 0
.../test/data/ECF_HOME/includes/tail.h | 0
.../test/data/ECF_HOME/suite/family/head.h | 0
.../test/data/ECF_HOME/suite/family/t1.ecf | 0
.../test/data/ECF_HOME/suite/family/t2.ecf | 0
.../test/data/ECF_HOME/suite/family/t3.ecf | 0
.../test/data/ECF_HOME/suite/family/tail.h | 0
{ecflow_4_0_7/Client => Client}/test/data/bad.def | 0
.../Client => Client}/test/data/first.def | 0
.../Client => Client}/test/data/good_hostfile | 0
.../Client => Client}/test/data/jobgenonly.def | 0
.../Client => Client}/test/data/lifecycle.txt | 0
Client/test/data/ref_analysis.dat | 33 +
Client/test/data/rtt.dat | 753 ++
.../Client => Client}/test/data/second.def | 0
Doc/.pydevproject | 7 +
.../Doc => Doc}/user-manual/client_options.docx | Bin
Doc/user-manual/user_manual.docx | Bin 0 -> 507282 bytes
.../Doc => Doc}/user-manual/user_manual.pdf | Bin
Jamroot.jam | 187 +
ecflow_4_0_7/LICENSE => LICENSE | 0
NOTICE | 71 +
Pyext/.gitignore | 3 +
Pyext/.pydevproject | 7 +
Pyext/CMakeLists.txt | 181 +
Pyext/ecflow/__init__.py | 18 +
Pyext/jamfile.jam | 206 +
.../migrate/abort_and_label_bug.def | 0
.../Pyext => Pyext}/migrate/aborted_reason_bug.def | 0
Pyext/migrate/ecflow_migrate.py | 416 +
.../Pyext => Pyext}/migrate/history_bug.def | 0
.../Pyext => Pyext}/migrate/label_bug.def | 0
.../Pyext => Pyext}/migrate/no_migration.def | 0
Pyext/migrate/py_u_TestMigrate.py | 192 +
.../Pyext => Pyext}/migrate/variable_bug.def | 0
Pyext/samples/ListVariables.py | 65 +
Pyext/samples/TestBench.py | 204 +
Pyext/samples/TestJobGenPerf.py | 155 +
Pyext/samples/TestServerGetDefs.py | 59 +
Pyext/samples/check_modules.py | 88 +
Pyext/samples/cray.py | 2175 +++++
Pyext/samples/def2def.py | 274 +
Pyext/samples/ecf.py | 1045 +++
Pyext/samples/printdefs.py | 178 +
Pyext/samples/resume.py | 80 +
Pyext/samples/sms2ecf.py | 193 +
Pyext/script.py | 11 +
Pyext/setup.py.in | 137 +
Pyext/src/BoostPythonUtil.cpp | 56 +
Pyext/src/BoostPythonUtil.hpp | 37 +
Pyext/src/ClientDoc.cpp | 1419 +++
Pyext/src/ClientDoc.hpp | 92 +
Pyext/src/DefsDoc.cpp | 800 ++
Pyext/src/DefsDoc.hpp | 71 +
Pyext/src/EcfExt.cpp | 45 +
Pyext/src/ExportClient.cpp | 336 +
Pyext/src/ExportCore.cpp | 246 +
Pyext/src/ExportDefs.cpp | 189 +
Pyext/src/ExportNode.cpp | 341 +
Pyext/src/ExportNodeAttr.cpp | 415 +
Pyext/src/ExportSuiteAndFamily.cpp | 91 +
Pyext/src/ExportTask.cpp | 66 +
Pyext/src/NodeAttrDoc.cpp | 567 ++
Pyext/src/NodeAttrDoc.hpp | 54 +
Pyext/test/CleanupOnlineTutorial.py | 28 +
.../Pyext => Pyext}/test/TestEmbedded.cpp | 0
Pyext/test/TestEmbeddedEcf.cpp | 84 +
{ecflow_4_0_7/Pyext => Pyext}/test/data/.gitignore | 0
.../test/data/ECF_HOME/suite_job_gen/family/t1.ecf | 0
.../test/data/ECF_HOME/suite_job_gen/family/t2.ecf | 0
.../test/data/ECF_HOME/suite_job_gen/family/t3.ecf | 0
Pyext/test/data/includes/head.h | 45 +
.../Pyext => Pyext}/test/data/includes/tail.h | 0
.../test/data/python_includes/head.py | 0
.../test/data/python_includes/tail.py | 0
Pyext/test/ecflow_test_util.py | 223 +
Pyext/test/py_s_TestClientApi.py | 1570 ++++
Pyext/test/py_s_TestPythonChildApi.py | 140 +
Pyext/test/py_u_TestAddDelete.py | 520 ++
Pyext/test/py_u_TestAddDeleteError.py | 86 +
Pyext/test/py_u_TestAddDeleteFunc.py | 311 +
Pyext/test/py_u_TestAddNodeFunc.py | 69 +
Pyext/test/py_u_TestDefs.py | 221 +
Pyext/test/py_u_TestDefsCheck.py | 72 +
Pyext/test/py_u_TestDerivable.py | 28 +
Pyext/test/py_u_TestEcf.py | 38 +
Pyext/test/py_u_TestError.py | 443 +
Pyext/test/py_u_TestFind.py | 76 +
Pyext/test/py_u_TestFlag.py | 91 +
Pyext/test/py_u_TestGeneratedVariable.py | 76 +
Pyext/test/py_u_TestGetAllTasks.py | 103 +
Pyext/test/py_u_TestJobGeneration.py | 135 +
Pyext/test/py_u_TestParent.py | 77 +
Pyext/test/py_u_TestRepeatArithmetic.py | 52 +
Pyext/test/py_u_TestSimulator.py | 82 +
Pyext/test/py_u_TestTraversal.py | 221 +
Pyext/test/py_u_TestUserManual.py | 156 +
Pyext/test/py_u_TestWith.py | 79 +
Pyext/test/test.ddoc | 18 +
{ecflow_4_0_7/Pyext => Pyext}/unicode.py | 0
README | 198 +
{ecflow_4_0_7/Server => Server}/CMakeLists.txt | 0
Server/Jamfile.jam | 93 +
Server/server_environment.cfg | 153 +
Server/src/CConnection.cpp | 237 +
Server/src/CConnection.hpp | 74 +
Server/src/CheckPtSaver.cpp | 243 +
Server/src/CheckPtSaver.hpp | 86 +
Server/src/NodeTreeTraverser.cpp | 396 +
Server/src/NodeTreeTraverser.hpp | 86 +
Server/src/Server.cpp | 716 ++
Server/src/Server.hpp | 159 +
Server/src/ServerEnvironment.cpp | 579 ++
Server/src/ServerEnvironment.hpp | 212 +
Server/src/ServerMain.cpp | 79 +
Server/src/ServerOptions.cpp | 160 +
Server/src/ServerOptions.hpp | 38 +
Server/test/TestServer1.cpp | 150 +
Server/test/TestServerEnvironment.cpp | 366 +
Test/CMakeLists.txt | 79 +
Test/DummyMain.cpp | 13 +
Test/Jamfile.jam | 115 +
Test/TestAbortCmd.cpp | 99 +
Test/TestAlias.cpp | 218 +
Test/TestClkSync.cpp | 85 +
Test/TestComplete.cpp | 178 +
Test/TestCron.cpp | 145 +
Test/TestCtsWaitCmd.cpp | 216 +
Test/TestEvents.cpp | 107 +
Test/TestFileCmd.cpp | 132 +
Test/TestHandle.cpp | 390 +
Test/TestKillCmd.cpp | 149 +
Test/TestLate.cpp | 136 +
Test/TestLimit.cpp | 118 +
Test/TestOrderCmd.cpp | 216 +
Test/TestRepeat.cpp | 338 +
Test/TestRequeueNode.cpp | 112 +
Test/TestRunner.cpp | 21 +
Test/TestServer.cpp | 135 +
Test/TestSingle.cpp | 182 +
Test/TestSuspend.cpp | 228 +
Test/TestToday.cpp | 201 +
Test/TestTrigger.cpp | 92 +
Test/TestWhyCmd.cpp | 538 ++
Test/TestZombies.cpp | 948 ++
Test/Test_ECF_SCRIPT_CMD.cpp | 86 +
Test/Test_Time.cpp | 387 +
Test/data/.gitignore | 6 +
{ecflow_4_0_7/Test => Test}/data/includes/head.h | 0
{ecflow_4_0_7/Test => Test}/data/includes/tail.h | 0
{ecflow_4_0_7/Test => Test}/samples/cron.def | 0
{ecflow_4_0_7/Test => Test}/samples/time.def | 0
{ecflow_4_0_7/Test => Test}/samples/today.def | 0
Test/src/ServerTestHarness.cpp | 558 ++
Test/src/ServerTestHarness.hpp | 109 +
Test/src/TestFixture.cpp | 415 +
Test/src/TestFixture.hpp | 103 +
Test/src/ZombieUtil.hpp | 38 +
Test/src/ZombieUtill.cpp | 184 +
Test/test.ddoc | 102 +
VERSION.cmake | 7 +
Viewer/CMakeLists.txt | 17 +
Viewer/images/add.svg | 185 +
Viewer/images/add_info.svg | 531 ++
Viewer/images/add_tab.svg | 301 +
Viewer/images/add_table.svg | 422 +
Viewer/images/add_tree.svg | 537 ++
Viewer/images/arrow_down.svg | 117 +
Viewer/images/arrow_up.svg | 117 +
Viewer/images/attribute.svg | 180 +
Viewer/images/bookmark.svg | 130 +
Viewer/images/case_sensitive.svg | 207 +
Viewer/images/chain.svg | 78 +
Viewer/images/clear_left.svg | 134 +
Viewer/images/close.svg | 242 +
Viewer/images/colour.svg | 283 +
Viewer/images/configure.svg | 170 +
Viewer/images/directory_arrow.svg | 107 +
Viewer/images/dock_close.svg | 206 +
Viewer/images/dock_config.svg | 93 +
Viewer/images/dock_float.svg | 180 +
Viewer/images/dock_menu_indicator.png | Bin 0 -> 225 bytes
Viewer/images/dock_menu_indicator.svg | 121 +
Viewer/images/drawer_close.svg | 143 +
Viewer/images/drawer_open.svg | 143 +
Viewer/images/edit.svg | 206 +
Viewer/images/editcopy.svg | 167 +
Viewer/images/editpaste.svg | 185 +
Viewer/images/error.svg | 214 +
Viewer/images/exit.svg | 141 +
Viewer/images/favourite.svg | 130 +
Viewer/images/favourite_empty.svg | 120 +
Viewer/images/filesave.svg | 234 +
Viewer/images/filter.svg | 173 +
Viewer/images/filter_decor.svg | 157 +
Viewer/images/filter_edit.svg | 179 +
Viewer/images/font.svg | 261 +
Viewer/images/fontsize_down.svg | 215 +
Viewer/images/fontsize_up.svg | 215 +
Viewer/images/genvar.svg | 180 +
Viewer/images/genvar_shadow.svg | 180 +
Viewer/images/goto_line.svg | 321 +
Viewer/images/grey_info.svg | 207 +
Viewer/images/icon_Apply.png | Bin 0 -> 328 bytes
Viewer/images/icon_Chat.png | Bin 0 -> 300 bytes
Viewer/images/icon_Check.png | Bin 0 -> 455 bytes
Viewer/images/icon_Complete.png | Bin 0 -> 281 bytes
Viewer/images/icon_Edit.png | Bin 0 -> 462 bytes
Viewer/images/icon_Info.png | Bin 0 -> 364 bytes
Viewer/images/icon_Jobstatus.png | Bin 0 -> 292 bytes
Viewer/images/icon_Josstatus3.png | Bin 0 -> 292 bytes
Viewer/images/icon_Load.png | Bin 0 -> 255 bytes
Viewer/images/icon_Manual.png | Bin 0 -> 521 bytes
Viewer/images/icon_Merge.png | Bin 0 -> 269 bytes
Viewer/images/icon_Messages.png | Bin 0 -> 367 bytes
Viewer/images/icon_Output.png | Bin 0 -> 469 bytes
Viewer/images/icon_QuickFind.png | Bin 0 -> 242 bytes
Viewer/images/icon_Script.png | Bin 0 -> 524 bytes
Viewer/images/icon_Search.png | Bin 0 -> 551 bytes
Viewer/images/icon_Status.png | Bin 0 -> 649 bytes
Viewer/images/icon_Submit.png | Bin 0 -> 328 bytes
Viewer/images/icon_Time_line.png | Bin 0 -> 311 bytes
Viewer/images/icon_Triggers.png | Bin 0 -> 260 bytes
Viewer/images/icon_Update.png | Bin 0 -> 649 bytes
Viewer/images/icon_Use_external_editor.png | Bin 0 -> 379 bytes
Viewer/images/icon_Use_external_viewer.png | Bin 0 -> 333 bytes
Viewer/images/icon_Variables.png | Bin 0 -> 246 bytes
Viewer/images/icon_W.png | Bin 0 -> 791 bytes
Viewer/images/icon_Why_.png | Bin 0 -> 402 bytes
Viewer/images/icon_Z.png | Bin 0 -> 791 bytes
Viewer/images/icon_Zbw.png | Bin 0 -> 501 bytes
Viewer/images/icon_calendar.png | Bin 0 -> 335 bytes
Viewer/images/icon_calendar.svg | 259 +
Viewer/images/icon_clock.png | Bin 0 -> 311 bytes
Viewer/images/icon_clock.svg | 283 +
Viewer/images/icon_complete.png | Bin 0 -> 281 bytes
Viewer/images/icon_complete.svg | 100 +
Viewer/images/icon_defstatus.png | Bin 0 -> 1031 bytes
Viewer/images/icon_folded.png | Bin 0 -> 236 bytes
Viewer/images/icon_late.png | Bin 0 -> 319 bytes
Viewer/images/icon_late.svg | 105 +
Viewer/images/icon_limit0.png | Bin 0 -> 243 bytes
Viewer/images/icon_limit1.png | Bin 0 -> 293 bytes
Viewer/images/icon_limit2.png | Bin 0 -> 290 bytes
Viewer/images/icon_locked.png | Bin 0 -> 270 bytes
Viewer/images/icon_memo.png | Bin 0 -> 607 bytes
Viewer/images/icon_message.png | Bin 0 -> 367 bytes
Viewer/images/icon_message.svg | 295 +
Viewer/images/icon_migrated.png | Bin 0 -> 350 bytes
Viewer/images/icon_node_log.svg | 214 +
Viewer/images/icon_noway.png | Bin 0 -> 281 bytes
Viewer/images/icon_rerun.png | Bin 0 -> 368 bytes
Viewer/images/icon_rerun.svg | 208 +
Viewer/images/icon_slow.svg | 234 +
Viewer/images/icon_waiting.png | Bin 0 -> 273 bytes
Viewer/images/icon_waiting.svg | 291 +
Viewer/images/icon_zombie.svg | 220 +
Viewer/images/info.svg | 234 +
Viewer/images/job.svg | 328 +
Viewer/images/large_file_search.svg | 163 +
Viewer/images/log_error.svg | 218 +
Viewer/images/log_info.svg | 220 +
Viewer/images/manage_server.svg | 763 ++
Viewer/images/manual.svg | 126 +
Viewer/images/manual_ori.svg | 426 +
Viewer/images/node_log.svg | 291 +
Viewer/images/notification.svg | 202 +
Viewer/images/output.svg | 226 +
Viewer/images/overview.svg | 231 +
Viewer/images/padlock.svg | 213 +
Viewer/images/path_arrow.svg | 107 +
Viewer/images/reload.svg | 238 +
Viewer/images/reload_black.svg | 246 +
Viewer/images/reload_one.svg | 238 +
Viewer/images/rescue.svg | 299 +
Viewer/images/reset.svg | 282 +
Viewer/images/reset_to_default.svg | 238 +
Viewer/images/script.svg | 293 +
Viewer/images/search.svg | 172 +
Viewer/images/search_decor.svg | 299 +
Viewer/images/search_decor_large_file_mode.svg | 352 +
Viewer/images/select_all.svg | 99 +
Viewer/images/server.svg | 689 ++
Viewer/images/server_log.svg | 196 +
Viewer/images/show_shadowed.svg | 219 +
Viewer/images/spinning_wheel.gif | Bin 0 -> 1849 bytes
Viewer/images/splash_screen.png | Bin 0 -> 59519 bytes
Viewer/images/splash_screen.svg | 943 ++
Viewer/images/status.svg | 222 +
Viewer/images/submit.svg | 117 +
Viewer/images/sync.svg | 401 +
Viewer/images/terminate.svg | 230 +
Viewer/images/tree_branch_end.png | Bin 0 -> 902 bytes
Viewer/images/tree_branch_more.png | Bin 0 -> 894 bytes
Viewer/images/tree_vline.png | Bin 0 -> 923 bytes
Viewer/images/unknown.svg | 198 +
Viewer/images/unselect_all.svg | 93 +
Viewer/images/variable.svg | 219 +
Viewer/images/warning.svg | 238 +
Viewer/images/why.svg | 220 +
Viewer/images/zombie.svg | 220 +
Viewer/scripts/CMakeLists.txt | 30 +
Viewer/scripts/ecflow_ui.in | 242 +
Viewer/src/AboutDialog.cpp | 74 +
Viewer/src/AboutDialog.hpp | 25 +
Viewer/src/AboutDialog.ui | 206 +
Viewer/src/AbstractNodeModel.cpp | 175 +
Viewer/src/AbstractNodeModel.hpp | 86 +
Viewer/src/AbstractSearchLine.cpp | 208 +
Viewer/src/AbstractSearchLine.hpp | 66 +
Viewer/src/AbstractTextEditSearchInterface.cpp | 25 +
Viewer/src/AbstractTextEditSearchInterface.hpp | 39 +
Viewer/src/ActionHandler.cpp | 205 +
Viewer/src/ActionHandler.hpp | 42 +
Viewer/src/Animation.cpp | 113 +
Viewer/src/Animation.hpp | 62 +
Viewer/src/AttributeEditor.cpp | 359 +
Viewer/src/AttributeEditor.hpp | 72 +
Viewer/src/AttributeEditorDialog.ui | 122 +
Viewer/src/AttributeEditorFactory.cpp | 37 +
Viewer/src/AttributeEditorFactory.hpp | 42 +
Viewer/src/AttributeSearchPanel.cpp | 365 +
Viewer/src/AttributeSearchPanel.hpp | 56 +
Viewer/src/AttributeView.hpp | 9 +
Viewer/src/CMakeLists.txt | 414 +
Viewer/src/CaseSensitiveButton.cpp | 32 +
Viewer/src/CaseSensitiveButton.hpp | 35 +
.../flags.cmake => Viewer/src/ChangeManagerAccess | 0
Viewer/src/ChangeNotify.cpp | 400 +
Viewer/src/ChangeNotify.hpp | 85 +
Viewer/src/ChangeNotifyDialog.cpp | 492 ++
Viewer/src/ChangeNotifyDialog.hpp | 95 +
Viewer/src/ChangeNotifyDialog.ui | 96 +
Viewer/src/ChangeNotifyDialogWidget.ui | 53 +
Viewer/src/ChangeNotifyEditor.cpp | 368 +
Viewer/src/ChangeNotifyEditor.hpp | 90 +
Viewer/src/ChangeNotifyEditor.ui | 44 +
Viewer/src/ChangeNotifyModel.cpp | 241 +
Viewer/src/ChangeNotifyModel.hpp | 58 +
Viewer/src/ChangeNotifyWidget.cpp | 229 +
Viewer/src/ChangeNotifyWidget.hpp | 73 +
Viewer/src/CodeItemWidget.cpp | 70 +
Viewer/src/CodeItemWidget.hpp | 40 +
Viewer/src/CodeItemWidget.ui | 204 +
Viewer/src/ComboMulti.cpp | 269 +
Viewer/src/ComboMulti.hpp | 71 +
Viewer/src/CommandDesignerWidget.cpp | 656 ++
Viewer/src/CommandDesignerWidget.hpp | 103 +
Viewer/src/CommandDesignerWidget.ui | 396 +
Viewer/src/ConfigListDelegate.cpp | 89 +
Viewer/src/ConfigListDelegate.hpp | 38 +
Viewer/src/ConnectState.cpp | 96 +
Viewer/src/ConnectState.hpp | 47 +
Viewer/src/CustomCommandDialog.cpp | 20 +
Viewer/src/CustomCommandDialog.hpp | 36 +
Viewer/src/CustomCommandDialog.ui | 80 +
Viewer/src/CustomCommandHandler.cpp | 342 +
Viewer/src/CustomCommandHandler.hpp | 113 +
Viewer/src/CustomListWidget.cpp | 100 +
Viewer/src/CustomListWidget.hpp | 41 +
Viewer/src/CustomTabWidget.cpp | 57 +
Viewer/src/CustomTabWidget.hpp | 28 +
Viewer/src/Dashboard.cpp | 544 ++
Viewer/src/Dashboard.hpp | 91 +
Viewer/src/DashboardDialog.cpp | 114 +
Viewer/src/DashboardDialog.hpp | 44 +
Viewer/src/DashboardDialog.ui | 73 +
Viewer/src/DashboardDock.cpp | 182 +
Viewer/src/DashboardDock.hpp | 60 +
Viewer/src/DashboardDockTitleWidget.ui | 198 +
Viewer/src/DashboardTitle.cpp | 169 +
Viewer/src/DashboardTitle.hpp | 57 +
Viewer/src/DashboardWidget.hpp | 59 +
Viewer/src/DirectoryHandler.cpp | 362 +
Viewer/src/DirectoryHandler.hpp | 54 +
Viewer/src/EditItemWidget.cpp | 151 +
Viewer/src/EditItemWidget.hpp | 58 +
Viewer/src/EditItemWidget.ui | 211 +
Viewer/src/EditProvider.cpp | 125 +
Viewer/src/EditProvider.hpp | 34 +
Viewer/src/EditorInfoLabel.cpp | 86 +
Viewer/src/EditorInfoLabel.hpp | 27 +
Viewer/src/ExpandState.cpp | 217 +
Viewer/src/ExpandState.hpp | 90 +
Viewer/src/FileInfoLabel.cpp | 275 +
Viewer/src/FileInfoLabel.hpp | 39 +
Viewer/src/FileWatcher.cpp | 39 +
Viewer/src/FileWatcher.hpp | 37 +
Viewer/src/FilterWidget.cpp | 497 ++
Viewer/src/FilterWidget.hpp | 97 +
Viewer/src/FlagSet.hpp | 32 +
Viewer/src/GotoLineDialog.cpp | 78 +
Viewer/src/GotoLineDialog.hpp | 37 +
Viewer/src/GotoLineDialog.ui | 92 +
Viewer/src/Highlighter.cpp | 110 +
Viewer/src/Highlighter.hpp | 40 +
Viewer/src/HistoryItemWidget.cpp | 156 +
Viewer/src/HistoryItemWidget.hpp | 53 +
Viewer/src/HistoryItemWidget.ui | 142 +
Viewer/src/IconProvider.cpp | 167 +
Viewer/src/IconProvider.hpp | 71 +
Viewer/src/InfoPanel.cpp | 751 ++
Viewer/src/InfoPanel.hpp | 120 +
Viewer/src/InfoPanel.ui | 86 +
Viewer/src/InfoPanelHandler.cpp | 133 +
Viewer/src/InfoPanelHandler.hpp | 74 +
Viewer/src/InfoPanelItem.cpp | 264 +
Viewer/src/InfoPanelItem.hpp | 115 +
Viewer/src/InfoPresenter.hpp | 43 +
Viewer/src/InfoProvider.cpp | 287 +
Viewer/src/InfoProvider.hpp | 106 +
Viewer/src/JobItemWidget.cpp | 96 +
Viewer/src/JobItemWidget.hpp | 43 +
Viewer/src/LabelEditor.cpp | 132 +
Viewer/src/LabelEditor.hpp | 50 +
Viewer/src/LabelEditorWidget.ui | 64 +
Viewer/src/LimitEditor.cpp | 163 +
Viewer/src/LimitEditor.hpp | 52 +
Viewer/src/LimitEditorWidget.ui | 67 +
Viewer/src/LineEdit.cpp | 109 +
Viewer/src/LineEdit.hpp | 42 +
Viewer/src/LogEvent.cpp | 315 +
Viewer/src/LogEvent.hpp | 61 +
Viewer/src/LogModel.cpp | 361 +
Viewer/src/LogModel.hpp | 72 +
Viewer/src/LogProvider.cpp | 247 +
Viewer/src/LogProvider.hpp | 51 +
Viewer/src/LogServer.cpp | 252 +
Viewer/src/LogServer.hpp | 43 +
Viewer/src/MainWindow.cpp | 753 ++
Viewer/src/MainWindow.hpp | 106 +
Viewer/src/MainWindow.ui | 350 +
Viewer/src/ManualItemWidget.cpp | 103 +
Viewer/src/ManualItemWidget.hpp | 40 +
Viewer/src/MenuConfigDialog.cpp | 111 +
Viewer/src/MenuConfigDialog.hpp | 88 +
Viewer/src/MenuConfigDialog.ui | 256 +
Viewer/src/MenuHandler.cpp | 830 ++
Viewer/src/MenuHandler.hpp | 166 +
Viewer/src/MessageItemWidget.cpp | 90 +
Viewer/src/MessageItemWidget.hpp | 44 +
Viewer/src/MessageItemWidget.ui | 128 +
Viewer/src/MessageLabel.cpp | 233 +
Viewer/src/MessageLabel.hpp | 48 +
Viewer/src/MeterEditor.cpp | 135 +
Viewer/src/MeterEditor.hpp | 52 +
Viewer/src/MeterEditorWidget.ui | 99 +
Viewer/src/ModelColumn.cpp | 72 +
Viewer/src/ModelColumn.hpp | 58 +
Viewer/src/NodeExpression.cpp | 902 ++
Viewer/src/NodeExpression.hpp | 421 +
Viewer/src/NodeFilterDialog.cpp | 126 +
Viewer/src/NodeFilterDialog.hpp | 46 +
Viewer/src/NodeFilterDialog.ui | 69 +
Viewer/src/NodeObserver.hpp | 29 +
Viewer/src/NodePanel.cpp | 375 +
Viewer/src/NodePanel.hpp | 78 +
Viewer/src/NodePathWidget.cpp | 958 ++
Viewer/src/NodePathWidget.hpp | 189 +
Viewer/src/NodeQuery.cpp | 671 ++
Viewer/src/NodeQuery.hpp | 179 +
Viewer/src/NodeQueryCombo.cpp | 43 +
Viewer/src/NodeQueryCombo.hpp | 29 +
Viewer/src/NodeQueryEditor.cpp | 730 ++
Viewer/src/NodeQueryEditor.hpp | 102 +
Viewer/src/NodeQueryEditor.ui | 371 +
Viewer/src/NodeQueryEngine.cpp | 302 +
Viewer/src/NodeQueryEngine.hpp | 91 +
Viewer/src/NodeQueryHandler.cpp | 115 +
Viewer/src/NodeQueryHandler.hpp | 46 +
Viewer/src/NodeQueryResult.cpp | 420 +
Viewer/src/NodeQueryResult.hpp | 133 +
Viewer/src/NodeQueryResultModel.cpp | 318 +
Viewer/src/NodeQueryResultModel.hpp | 68 +
Viewer/src/NodeQueryResultTmp.hpp | 31 +
Viewer/src/NodeQueryResultView.cpp | 276 +
Viewer/src/NodeQueryResultView.hpp | 70 +
Viewer/src/NodeQuerySaveDialog.ui | 87 +
Viewer/src/NodeQueryViewDelegate.cpp | 262 +
Viewer/src/NodeQueryViewDelegate.hpp | 48 +
Viewer/src/NodeSearchDialog.cpp | 114 +
Viewer/src/NodeSearchDialog.hpp | 46 +
Viewer/src/NodeSearchDialog.ui | 37 +
Viewer/src/NodeSearchWidget.cpp | 304 +
Viewer/src/NodeSearchWidget.hpp | 64 +
Viewer/src/NodeSearchWidget.ui | 157 +
Viewer/src/NodeViewBase.cpp | 15 +
Viewer/src/NodeViewBase.hpp | 41 +
Viewer/src/NodeViewDelegate.cpp | 1145 +++
Viewer/src/NodeViewDelegate.hpp | 94 +
Viewer/src/NodeWidget.cpp | 164 +
Viewer/src/NodeWidget.hpp | 83 +
Viewer/src/OneLineTextEdit.cpp | 66 +
Viewer/src/OneLineTextEdit.hpp | 33 +
Viewer/src/OutputBrowser.cpp | 304 +
Viewer/src/OutputBrowser.hpp | 95 +
Viewer/src/OutputCache.cpp | 200 +
Viewer/src/OutputCache.hpp | 73 +
Viewer/src/OutputClient.cpp | 63 +
Viewer/src/OutputClient.hpp | 63 +
Viewer/src/OutputDirClient.cpp | 173 +
Viewer/src/OutputDirClient.hpp | 46 +
Viewer/src/OutputDirProvider.cpp | 273 +
Viewer/src/OutputDirProvider.hpp | 49 +
Viewer/src/OutputFetchInfo.cpp | 192 +
Viewer/src/OutputFetchInfo.hpp | 36 +
Viewer/src/OutputFileClient.cpp | 198 +
Viewer/src/OutputFileClient.hpp | 51 +
Viewer/src/OutputFileProvider.cpp | 447 +
Viewer/src/OutputFileProvider.hpp | 56 +
Viewer/src/OutputItemWidget.cpp | 586 ++
Viewer/src/OutputItemWidget.hpp | 82 +
Viewer/src/OutputItemWidget.ui | 249 +
Viewer/src/OutputModel.cpp | 310 +
Viewer/src/OutputModel.hpp | 57 +
Viewer/src/OverviewItemWidget.cpp | 146 +
Viewer/src/OverviewItemWidget.hpp | 44 +
Viewer/src/OverviewProvider.cpp | 276 +
Viewer/src/OverviewProvider.hpp | 36 +
Viewer/src/Palette.cpp | 115 +
Viewer/src/Palette.hpp | 24 +
Viewer/src/PlainTextEdit.cpp | 529 ++
Viewer/src/PlainTextEdit.hpp | 98 +
Viewer/src/PlainTextSearchInterface.cpp | 212 +
Viewer/src/PlainTextSearchInterface.hpp | 40 +
Viewer/src/PlainTextSearchLine.cpp | 333 +
Viewer/src/PlainTextSearchLine.hpp | 69 +
Viewer/src/PropertyDialog.cpp | 212 +
Viewer/src/PropertyDialog.hpp | 63 +
Viewer/src/PropertyDialog.ui | 100 +
Viewer/src/PropertyEditor.cpp | 568 ++
Viewer/src/PropertyEditor.hpp | 65 +
Viewer/src/PropertyEditor.ui | 132 +
Viewer/src/PropertyLine.cpp | 930 ++
Viewer/src/PropertyLine.hpp | 357 +
Viewer/src/PropertyMapper.cpp | 36 +
Viewer/src/PropertyMapper.hpp | 22 +
Viewer/src/RepeatEditor.cpp | 388 +
Viewer/src/RepeatEditor.hpp | 112 +
Viewer/src/RepeatEditorWidget.ui | 112 +
Viewer/src/SaveSessionAsDialog.cpp | 120 +
Viewer/src/SaveSessionAsDialog.hpp | 41 +
Viewer/src/SaveSessionAsDialog.ui | 111 +
Viewer/src/ScriptItemWidget.cpp | 109 +
Viewer/src/ScriptItemWidget.hpp | 40 +
Viewer/src/SearchLineWidget.ui | 212 +
Viewer/src/ServerAddDialog.ui | 120 +
Viewer/src/ServerComQueue.cpp | 393 +
Viewer/src/ServerComQueue.hpp | 80 +
Viewer/src/ServerComThread.cpp | 613 ++
Viewer/src/ServerComThread.hpp | 87 +
Viewer/src/ServerDefsAccess.cpp | 29 +
Viewer/src/ServerDefsAccess.hpp | 34 +
Viewer/src/ServerDialog.ui | 178 +
Viewer/src/ServerEditDialog.ui | 130 +
Viewer/src/ServerFilter.cpp | 202 +
Viewer/src/ServerFilter.hpp | 68 +
Viewer/src/ServerHandler.cpp | 1547 ++++
Viewer/src/ServerHandler.hpp | 212 +
Viewer/src/ServerItem.cpp | 124 +
Viewer/src/ServerItem.hpp | 81 +
Viewer/src/ServerList.cpp | 328 +
Viewer/src/ServerList.hpp | 72 +
Viewer/src/ServerListDialog.cpp | 848 ++
Viewer/src/ServerListDialog.hpp | 168 +
Viewer/src/ServerListDialog.ui | 290 +
Viewer/src/ServerObserver.hpp | 37 +
Viewer/src/ServerSettingsItemWidget.cpp | 129 +
Viewer/src/ServerSettingsItemWidget.hpp | 49 +
Viewer/src/ServerSettingsItemWidget.ui | 45 +
Viewer/src/ServerWidget.ui | 121 +
Viewer/src/SessionDialog.cpp | 262 +
Viewer/src/SessionDialog.hpp | 48 +
Viewer/src/SessionDialog.ui | 134 +
Viewer/src/SessionHandler.cpp | 364 +
Viewer/src/SessionHandler.hpp | 87 +
Viewer/src/SessionRenameDialog.cpp | 49 +
Viewer/src/SessionRenameDialog.hpp | 40 +
Viewer/src/SessionRenameDialog.ui | 81 +
Viewer/src/Sound.cpp | 158 +
Viewer/src/Sound.hpp | 54 +
Viewer/src/StringMatchCombo.cpp | 49 +
Viewer/src/StringMatchCombo.hpp | 30 +
Viewer/src/StringMatchMode.cpp | 56 +
Viewer/src/StringMatchMode.hpp | 41 +
Viewer/src/SuiteFilter.cpp | 316 +
Viewer/src/SuiteFilter.hpp | 113 +
Viewer/src/SuiteFilterObserver.hpp | 25 +
Viewer/src/SuiteItemWidget.cpp | 261 +
Viewer/src/SuiteItemWidget.hpp | 61 +
Viewer/src/SuiteItemWidget.ui | 252 +
Viewer/src/SuiteModel.cpp | 254 +
Viewer/src/SuiteModel.hpp | 47 +
Viewer/src/TabWidget.cpp | 278 +
Viewer/src/TabWidget.hpp | 67 +
Viewer/src/TableFilterWidget.cpp | 102 +
Viewer/src/TableFilterWidget.hpp | 42 +
Viewer/src/TableFilterWidget.ui | 79 +
Viewer/src/TableNodeModel.cpp | 365 +
Viewer/src/TableNodeModel.hpp | 85 +
Viewer/src/TableNodeSortModel.cpp | 52 +
Viewer/src/TableNodeSortModel.hpp | 41 +
Viewer/src/TableNodeView.cpp | 606 ++
Viewer/src/TableNodeView.hpp | 122 +
Viewer/src/TableNodeViewDelegate.cpp | 255 +
Viewer/src/TableNodeViewDelegate.hpp | 51 +
Viewer/src/TableNodeWidget.cpp | 400 +
Viewer/src/TableNodeWidget.hpp | 46 +
Viewer/src/TableNodeWidget.ui | 77 +
Viewer/src/TextEditSearchLine.cpp | 243 +
Viewer/src/TextEditSearchLine.hpp | 57 +
Viewer/src/TextPager/TextPagerCursor.cpp | 780 ++
Viewer/src/TextPager/TextPagerCursor.hpp | 140 +
Viewer/src/TextPager/TextPagerCursor_p.hpp | 214 +
Viewer/src/TextPager/TextPagerDocument.cpp | 1795 ++++
Viewer/src/TextPager/TextPagerDocument.hpp | 176 +
Viewer/src/TextPager/TextPagerDocument_p.hpp | 703 ++
Viewer/src/TextPager/TextPagerEdit.cpp | 1896 ++++
Viewer/src/TextPager/TextPagerEdit.hpp | 226 +
Viewer/src/TextPager/TextPagerEdit_p.hpp | 146 +
Viewer/src/TextPager/TextPagerLayout_p.cpp | 454 +
Viewer/src/TextPager/TextPagerLayout_p.hpp | 125 +
.../src/TextPager/TextPagerSearchHighlighter.cpp | 145 +
.../src/TextPager/TextPagerSearchHighlighter.hpp | 43 +
Viewer/src/TextPager/TextPagerSearchInterface.cpp | 218 +
Viewer/src/TextPager/TextPagerSearchInterface.hpp | 40 +
Viewer/src/TextPager/TextPagerSection.cpp | 66 +
Viewer/src/TextPager/TextPagerSection.hpp | 75 +
Viewer/src/TextPager/TextPagerSection_p.hpp | 34 +
Viewer/src/TextPager/TextPagerWidget.cpp | 113 +
Viewer/src/TextPager/TextPagerWidget.hpp | 53 +
Viewer/src/TextPager/WeakPointer.hpp | 16 +
Viewer/src/TextPager/syntaxhighlighter.cpp | 133 +
Viewer/src/TextPager/syntaxhighlighter.hpp | 78 +
Viewer/src/TimeItemWidget.cpp | 44 +
Viewer/src/TimeItemWidget.hpp | 45 +
Viewer/src/TimeItemWidget.ui | 206 +
Viewer/src/TreeNodeModel.cpp | 1117 +++
Viewer/src/TreeNodeModel.hpp | 117 +
Viewer/src/TreeNodeView.cpp | 656 ++
Viewer/src/TreeNodeView.hpp | 99 +
Viewer/src/TreeNodeViewDelegate.cpp | 1058 +++
Viewer/src/TreeNodeViewDelegate.hpp | 93 +
Viewer/src/TreeNodeWidget.cpp | 252 +
Viewer/src/TreeNodeWidget.hpp | 54 +
Viewer/src/TreeNodeWidget.ui | 72 +
Viewer/src/TreeView.cpp | 28 +
Viewer/src/TreeView.hpp | 21 +
Viewer/src/TriggerItemWidget.cpp | 53 +
Viewer/src/TriggerItemWidget.hpp | 39 +
Viewer/src/TriggerItemWidget.ui | 72 +
Viewer/src/TriggerView.cpp | 422 +
Viewer/src/TriggerView.hpp | 44 +
Viewer/src/UpdateTimer.cpp | 20 +
Viewer/src/UpdateTimer.hpp | 22 +
Viewer/src/UserMessage.cpp | 73 +
Viewer/src/UserMessage.hpp | 40 +
Viewer/src/VAttribute.cpp | 79 +
Viewer/src/VAttribute.hpp | 51 +
Viewer/src/VAttributeType.cpp | 1280 +++
Viewer/src/VAttributeType.hpp | 56 +
Viewer/src/VConfig.cpp | 635 ++
Viewer/src/VConfig.hpp | 64 +
Viewer/src/VConfigLoader.cpp | 51 +
Viewer/src/VConfigLoader.hpp | 40 +
Viewer/src/VDir.cpp | 99 +
Viewer/src/VDir.hpp | 66 +
Viewer/src/VFile.cpp | 265 +
Viewer/src/VFile.hpp | 98 +
Viewer/src/VFileInfo.cpp | 107 +
Viewer/src/VFileInfo.hpp | 31 +
Viewer/src/VFilter.cpp | 597 ++
Viewer/src/VFilter.hpp | 188 +
Viewer/src/VIcon.cpp | 422 +
Viewer/src/VIcon.hpp | 54 +
Viewer/src/VInfo.cpp | 390 +
Viewer/src/VInfo.hpp | 271 +
Viewer/src/VItem.hpp | 66 +
Viewer/src/VModelData.cpp | 1137 +++
Viewer/src/VModelData.hpp | 276 +
Viewer/src/VNState.cpp | 226 +
Viewer/src/VNState.hpp | 59 +
Viewer/src/VNode.cpp | 1323 +++
Viewer/src/VNode.hpp | 322 +
Viewer/src/VNodeList.cpp | 327 +
Viewer/src/VNodeList.hpp | 98 +
Viewer/src/VParam.cpp | 235 +
Viewer/src/VParam.hpp | 73 +
Viewer/src/VProperty.cpp | 530 ++
Viewer/src/VProperty.hpp | 136 +
Viewer/src/VRepeat.cpp | 215 +
Viewer/src/VRepeat.hpp | 94 +
Viewer/src/VReply.cpp | 57 +
Viewer/src/VReply.hpp | 93 +
Viewer/src/VSState.cpp | 121 +
Viewer/src/VSState.hpp | 44 +
Viewer/src/VServerSettings.cpp | 227 +
Viewer/src/VServerSettings.hpp | 68 +
Viewer/src/VSettings.cpp | 288 +
Viewer/src/VSettings.hpp | 107 +
Viewer/src/VTask.cpp | 117 +
Viewer/src/VTask.hpp | 91 +
Viewer/src/VTaskNode.cpp | 179 +
Viewer/src/VTaskNode.hpp | 53 +
Viewer/src/VTaskObserver.hpp | 22 +
Viewer/src/VTree.cpp | 322 +
Viewer/src/VTree.hpp | 97 +
Viewer/src/VariableAddDialog.ui | 140 +
Viewer/src/VariableItemWidget.cpp | 1128 +++
Viewer/src/VariableItemWidget.hpp | 159 +
Viewer/src/VariableItemWidget.ui | 261 +
Viewer/src/VariableModel.cpp | 759 ++
Viewer/src/VariableModel.hpp | 123 +
Viewer/src/VariableModelData.cpp | 863 ++
Viewer/src/VariableModelData.hpp | 121 +
Viewer/src/VariableModelDataObserver.hpp | 23 +
Viewer/src/VariablePropDialog.ui | 138 +
Viewer/src/VariableSearchLine.cpp | 146 +
Viewer/src/VariableSearchLine.hpp | 47 +
Viewer/src/VariableView.cpp | 317 +
Viewer/src/VariableView.hpp | 55 +
Viewer/src/Viewer.hpp | 25 +
Viewer/src/ViewerMain.cpp | 147 +
Viewer/src/WhyItemWidget.cpp | 92 +
Viewer/src/WhyItemWidget.hpp | 43 +
Viewer/src/ZombieItemWidget.cpp | 294 +
Viewer/src/ZombieItemWidget.hpp | 68 +
Viewer/src/ZombieItemWidget.ui | 247 +
Viewer/src/ZombieModel.cpp | 197 +
Viewer/src/ZombieModel.hpp | 40 +
Viewer/src/viewer.qrc | 93 +
bin/ecbuild | 442 +
ecflow_4_0_7/boost-build.jam => boost-build.jam | 0
build_scripts/.pydevproject | 7 +
build_scripts/aix_fix/README | 118 +
.../aix_fix/boost_1_53_0/README | 0
.../aix_fix/boost_1_53_0/thread.cpp | 0
.../aix_fix/force_include.hpp | 0
.../aix_fix/force_include.hpp_boost_1.44 | 0
.../aix_fix/header_diff_item2.txt | 0
build_scripts/aix_fix/path.hpp | 714 ++
.../build => build_scripts}/aix_fix/singleton.hpp | 0
build_scripts/boost_1_47_fix.sh | 46 +
build_scripts/boost_1_48_fix.sh | 52 +
build_scripts/boost_1_51_fix.sh | 36 +
build_scripts/boost_1_53_fix.sh | 51 +
build_scripts/boost_1_56_fix.sh | 14 +
build_scripts/boost_1_57_fix.sh | 54 +
build_scripts/boost_build.sh | 178 +
build_scripts/clean.sh | 67 +
.../cray_fix/boost_1_55_0/README | 0
.../cray_fix/boost_1_55_0/cray.hpp | 0
.../cray_fix/boost_1_55_0/smalldiff | 0
build_scripts/cray_fix/swap.sh | 100 +
build_scripts/cray_fix/update_cray_swap.sh | 9 +
.../fix/boost_1_56_0/shared_ptr_helper.hpp | 0
build_scripts/hpux_fix/README | 199 +
.../hpux_fix/boost_1_51_0/future.hpp | 0
.../hpux_fix/boost_1_51_0/overflow_helpers.hpp | 0
.../hpux_fix/boost_1_51_0/system_clocks.hpp | 232 +
.../hpux_fix/boost_1_51_0/utf8_codecvt_facet.ipp | 0
.../hpux_fix/boost_1_53_0/README | 0
.../hpux_fix/boost_1_53_0/smart_cast.hpp | 0
.../hpux_fix/boost_1_53_0/utf8_codecvt_facet.ipp | 0
.../build => build_scripts}/hpux_fix/cstdint.hpp | 0
.../hpux_fix/socket_ops.hpp | 0
.../hpux_fix/utf8_codecvt_facet.cpp | 0
build_scripts/kill_ecf.sh | 24 +
build_scripts/massif.sh | 33 +
build_scripts/migrate.sh | 15 +
build_scripts/profile.sh | 59 +
build_scripts/rmbin.sh | 23 +
build_scripts/site_config/install.ddoc | 105 +
build_scripts/site_config/issues.ddoc | 35 +
build_scripts/site_config/site-config-AIX.jam | 100 +
build_scripts/site_config/site-config-HPUX.jam | 111 +
build_scripts/site_config/site-config-Linux.jam | 83 +
.../site_config/site-config-Linux64-clang.jam | 84 +
.../site_config/site-config-Linux64-intel.jam | 91 +
build_scripts/site_config/site-config-Linux64.jam | 94 +
build_scripts/site_config/site-config-cray.jam | 197 +
build_scripts/tar_ecflow.sh | 146 +
build_scripts/test.sh | 186 +
build_scripts/update_site_config.sh | 83 +
build_scripts/val.sh | 53 +
cmake.sh | 243 +
.../cmake => cmake}/2.8/CMakePushCheckState.cmake | 0
.../cmake => cmake}/CheckFortranCompilerFlag.cmake | 0
cmake/CheckFortranSourceCompiles.cmake | 94 +
cmake/FindADSM.cmake | 43 +
cmake/FindAEC.cmake | 32 +
cmake/FindAIO.cmake | 66 +
cmake/FindArmadillo.cmake | 43 +
cmake/FindCMath.cmake | 26 +
cmake/FindCairo.cmake | 59 +
cmake/FindDl.cmake | 23 +
cmake/FindEMOS.cmake | 35 +
cmake/FindFDB.cmake | 35 +
cmake/FindGeoTIFF.cmake | 38 +
cmake/FindHPSS.cmake | 39 +
cmake/FindLEX.cmake | 129 +
cmake/FindLibGFortran.cmake | 53 +
cmake/FindLibIFort.cmake | 50 +
cmake/FindMKL.cmake | 77 +
cmake/FindNDBM.cmake | 34 +
cmake/FindNetCDF.cmake | 164 +
cmake/FindNetCDF3.cmake | 113 +
cmake/FindODB.cmake | 53 +
cmake/FindOpenCL.cmake | 70 +
cmake/FindOpenJPEG.cmake | 42 +
cmake/FindPGIFortran.cmake | 49 +
cmake/FindPango.cmake | 33 +
cmake/FindPangoCairo.cmake | 96 +
cmake/FindProj4.cmake | 69 +
cmake/FindREADLINE.cmake | 87 +
cmake/FindRPCGEN.cmake | 20 +
cmake/FindRealtime.cmake | 24 +
cmake/FindSZip.cmake | 30 +
cmake/FindTrilinos.cmake | 49 +
cmake/FindViennaCL.cmake | 39 +
cmake/FindXLFortranLibs.cmake | 51 +
cmake/FindYACC.cmake | 157 +
cmake/Findgrib_api.cmake | 133 +
cmake/Findodb_api.cmake | 97 +
cmake/Findspot.cmake | 65 +
cmake/VERSION.cmake | 7 +
cmake/compiler_flags/Clang_C.cmake | 13 +
cmake/compiler_flags/Clang_CXX.cmake | 13 +
cmake/compiler_flags/Cray_C.cmake | 14 +
cmake/compiler_flags/Cray_CXX.cmake | 14 +
cmake/compiler_flags/Cray_Fortran.cmake | 15 +
cmake/compiler_flags/GNU_C.cmake | 18 +
cmake/compiler_flags/GNU_CXX.cmake | 18 +
cmake/compiler_flags/GNU_Fortran.cmake | 21 +
cmake/compiler_flags/Intel_C.cmake | 13 +
cmake/compiler_flags/Intel_CXX.cmake | 13 +
cmake/compiler_flags/Intel_Fortran.cmake | 14 +
cmake/compiler_flags/PGI_C.cmake | 11 +
cmake/compiler_flags/PGI_CXX.cmake | 11 +
cmake/compiler_flags/PGI_Fortran.cmake | 11 +
.../contrib/CheckFortranCompilerFlag.cmake | 0
.../contrib/CheckFortranSourceCompiles.cmake | 0
cmake/contrib/FindEigen3.cmake | 97 +
cmake/contrib/FindFFTW.cmake | 217 +
cmake/contrib/FindNetCDF4.cmake | 337 +
{ecbuild/cmake => cmake}/contrib/FindNumPy.cmake | 0
.../contrib/GetGitRevisionDescription.cmake | 0
cmake/contrib/GetGitRevisionDescription.cmake.in | 42 +
.../contrib/GreatCMakeCookOff/.gitattributes | 0
.../contrib/GreatCMakeCookOff/.gitignore | 0
.../contrib/GreatCMakeCookOff/AddCPP11Flags.cmake | 0
.../contrib/GreatCMakeCookOff/AddGTest.cmake | 0
.../GreatCMakeCookOff/CheckCXX11Features.cmake | 0
.../contrib/GreatCMakeCookOff/CheckIsNaN.cmake | 0
.../contrib/GreatCMakeCookOff/FindEigen.cmake | 0
.../contrib/GreatCMakeCookOff/LICENSE | 0
.../contrib/GreatCMakeCookOff/README.md | 0
.../contrib/GreatCMakeCookOff/TestCMake.cmake | 0
.../GreatCMakeCookOff/cpp11/__func__-N2340.cpp | 0
.../contrib/GreatCMakeCookOff/cpp11/auto-N2546.cpp | 0
.../GreatCMakeCookOff/cpp11/begin_function.cc | 0
.../GreatCMakeCookOff/cpp11/constexpr-N2235.cpp | 0
.../cpp11/constructor_delegate.cpp | 0
.../contrib/GreatCMakeCookOff/cpp11/cstdint.cpp | 0
.../GreatCMakeCookOff/cpp11/decltype-N2343.cpp | 0
.../cpp11/deleted_constructor.cpp | 0
.../cpp11/deleted_constructor_fail_compile.cpp | 0
.../contrib/GreatCMakeCookOff/cpp11/enable_if.cpp | 0
.../GreatCMakeCookOff/cpp11/explicit_cast.cpp | 0
.../GreatCMakeCookOff/cpp11/initialization.cpp | 0
.../GreatCMakeCookOff/cpp11/lambda-N2927.cpp | 0
.../GreatCMakeCookOff/cpp11/long_double.cpp | 0
.../GreatCMakeCookOff/cpp11/long_long-N1811.cpp | 0
.../contrib/GreatCMakeCookOff/cpp11/noexcept.cpp | 0
.../GreatCMakeCookOff/cpp11/nullptr-N2431.cpp | 0
.../cpp11/nullptr-N2431_fail_compile.cpp | 0
.../contrib/GreatCMakeCookOff/cpp11/override.cpp | 0
.../cpp11/override_fail_compile.cpp | 0
.../GreatCMakeCookOff/cpp11/random_device.cpp | 0
.../cpp11/rvalue_references-N2118.cpp | 0
.../contrib/GreatCMakeCookOff/cpp11/shared_ptr.cpp | 0
.../cpp11/sizeof_member-N2253.cpp | 0
.../cpp11/static_assert-N1720.cpp | 0
.../cpp11/static_assert-N1720_fail_compile.cpp | 0
.../GreatCMakeCookOff/cpp11/template_alias.cpp | 0
.../cpp11/trivial_type_traits.cpp | 0
.../GreatCMakeCookOff/cpp11/type_traits.cpp | 0
.../contrib/GreatCMakeCookOff/cpp11/unique_ptr.cpp | 0
.../cpp11/variadic_templates-N2555.cpp | 0
.../contrib/GreatCMakeCookOff/tests/addgtest.cmake | 0
.../GreatCMakeCookOff/tests/checkcpp11flags.cmake | 0
.../GreatCMakeCookOff/tests/checkisnan.cmake | 0
.../tests/cpp11/allfeatures.cmake | 0
.../tests/cpp11/check_features.cmake | 0
.../tests/cpp11/parse_input_features.cmake | 0
cmake/ecbuild-config-version.cmake | 12 +
cmake/ecbuild-config.cmake | 97 +
cmake/ecbuild_add_c_flags.cmake | 92 +
cmake/ecbuild_add_cxx11_flags.cmake | 35 +
cmake/ecbuild_add_cxx_flags.cmake | 92 +
cmake/ecbuild_add_executable.cmake | 381 +
cmake/ecbuild_add_extra_search_paths.cmake | 33 +
cmake/ecbuild_add_fortran_flags.cmake | 98 +
cmake/ecbuild_add_library.cmake | 587 ++
cmake/ecbuild_add_option.cmake | 314 +
cmake/ecbuild_add_persistent.cmake | 85 +
cmake/ecbuild_add_resources.cmake | 151 +
cmake/ecbuild_add_test.cmake | 471 +
cmake/ecbuild_append_to_rpath.cmake | 97 +
cmake/ecbuild_bundle.cmake | 174 +
cmake/ecbuild_cache.cmake | 95 +
cmake/ecbuild_check_c_source_return.cmake | 154 +
cmake/ecbuild_check_compiler.cmake | 156 +
cmake/ecbuild_check_cxx11.cmake | 132 +
cmake/ecbuild_check_cxx_source_return.cmake | 163 +
cmake/ecbuild_check_fortran_source_return.cmake | 155 +
cmake/ecbuild_check_functions.cmake | 172 +
cmake/ecbuild_check_os.cmake | 396 +
cmake/ecbuild_compiler_flags.cmake | 97 +
cmake/ecbuild_config.h.in | 192 +
cmake/ecbuild_declare_project.cmake | 193 +
cmake/ecbuild_define_build_types.cmake | 59 +
cmake/ecbuild_define_libs_and_execs_target.cmake | 29 +
cmake/ecbuild_define_links_target.cmake | 74 +
cmake/ecbuild_define_options.cmake | 52 +
cmake/ecbuild_define_paths.cmake | 41 +
cmake/ecbuild_define_uninstall.cmake | 7 +
cmake/ecbuild_dont_pack.cmake | 82 +
cmake/ecbuild_download_resource.cmake | 47 +
cmake/ecbuild_echo_targets.cmake | 233 +
cmake/ecbuild_enable_fortran.cmake | 81 +
cmake/ecbuild_features.cmake | 98 +
cmake/ecbuild_find_fortranlibs.cmake | 163 +
cmake/ecbuild_find_lexyacc.cmake | 92 +
cmake/ecbuild_find_mpi.cmake | 328 +
cmake/ecbuild_find_omp.cmake | 259 +
cmake/ecbuild_find_package.cmake | 325 +
cmake/ecbuild_find_perl.cmake | 73 +
cmake/ecbuild_find_python.cmake | 205 +
cmake/ecbuild_generate_config_headers.cmake | 63 +
cmake/ecbuild_generate_fortran_interfaces.cmake | 143 +
cmake/ecbuild_generate_rpc.cmake | 100 +
cmake/ecbuild_generate_yy.cmake | 201 +
cmake/ecbuild_get_cxx11_flags.cmake | 71 +
cmake/ecbuild_get_date.cmake | 52 +
cmake/ecbuild_get_resources.cmake | 52 +
cmake/ecbuild_get_test_data.cmake | 390 +
cmake/ecbuild_git.cmake | 298 +
cmake/ecbuild_install_project.cmake | 432 +
cmake/ecbuild_list_add_pattern.cmake | 102 +
cmake/ecbuild_list_exclude_pattern.cmake | 88 +
cmake/ecbuild_list_extra_search_paths.cmake | 81 +
cmake/ecbuild_list_macros.cmake | 58 +
cmake/ecbuild_log.cmake | 256 +
cmake/ecbuild_pkgconfig.cmake | 421 +
cmake/ecbuild_policies.cmake | 67 +
cmake/ecbuild_print_summary.cmake | 104 +
cmake/ecbuild_project_files.cmake | 75 +
cmake/ecbuild_remove_fortran_flags.cmake | 61 +
cmake/ecbuild_requires_macro_version.cmake | 27 +
cmake/ecbuild_separate_sources.cmake | 91 +
cmake/ecbuild_setup_test_framework.cmake | 45 +
cmake/ecbuild_source_flags.cmake | 30 +
cmake/ecbuild_system.cmake | 266 +
cmake/ecbuild_uninstall.cmake.in | 21 +
cmake/ecbuild_use_package.cmake | 289 +
cmake/ecbuild_version.h.in | 20 +
cmake/ecbuild_warn_unused_files.cmake | 77 +
cmake/fcm-make-interfaces.cfg | 31 +
cmake/gen_source_flags.py | 84 +
cmake/include/ecbuild/boost_test_framework.h | 17 +
{ecbuild/cmake => cmake}/md5.in | 0
cmake/pkg-config.pc.in | 35 +
.../project-config-version.cmake.in | 0
cmake/project-config.cmake.in | 97 +
cmake/pymain.c | 5 +
cmake/sg.pl | 573 ++
{ecbuild/cmake => cmake}/sha1.in | 0
ecbuild/.cproject | 66 -
ecbuild/.gitignore | 2 -
ecbuild/.project | 27 -
ecbuild/.settings/language.settings.xml | 25 -
ecbuild/AUTHORS | 12 -
ecbuild/CMakeLists.txt | 48 -
ecbuild/COPYING | 201 -
ecbuild/INSTALL | 19 -
ecbuild/LICENSE | 190 -
ecbuild/NOTICE | 10 -
ecbuild/VERSION.cmake | 1 -
ecbuild/bin/CMakeLists.txt | 17 -
ecbuild/bin/apply_license.sh | 55 -
ecbuild/bin/check_install.sh | 76 -
ecbuild/bin/ecbuild | 267 -
ecbuild/bin/git-meld | 3 -
ecbuild/bin/git-mproj | 54 -
ecbuild/bin/license.pl | 150 -
ecbuild/cmake/CMakeLists.txt | 5 -
ecbuild/cmake/CheckFortranSourceCompiles.cmake | 94 -
ecbuild/cmake/FindADSM.cmake | 43 -
ecbuild/cmake/FindAEC.cmake | 34 -
ecbuild/cmake/FindAIO.cmake | 66 -
ecbuild/cmake/FindArmadillo.cmake | 33 -
ecbuild/cmake/FindCMath.cmake | 23 -
ecbuild/cmake/FindCairo.cmake | 58 -
ecbuild/cmake/FindDl.cmake | 20 -
ecbuild/cmake/FindEMOS.cmake | 37 -
ecbuild/cmake/FindEcLib.cmake | 49 -
ecbuild/cmake/FindEcregrid.cmake | 48 -
ecbuild/cmake/FindFDB.cmake | 35 -
ecbuild/cmake/FindGeoTIFF.cmake | 37 -
ecbuild/cmake/FindHPSS.cmake | 39 -
ecbuild/cmake/FindLEX.cmake | 129 -
ecbuild/cmake/FindLegacyFDB.cmake | 35 -
ecbuild/cmake/FindLibGFortran.cmake | 52 -
ecbuild/cmake/FindNDBM.cmake | 34 -
ecbuild/cmake/FindNetCDF.cmake | 167 -
ecbuild/cmake/FindNetCDF3.cmake | 129 -
ecbuild/cmake/FindODB.cmake | 53 -
ecbuild/cmake/FindOpenJPEG.cmake | 43 -
ecbuild/cmake/FindPGIFortran.cmake | 46 -
ecbuild/cmake/FindPango.cmake | 33 -
ecbuild/cmake/FindPangoCairo.cmake | 91 -
ecbuild/cmake/FindProj4.cmake | 67 -
ecbuild/cmake/FindREADLINE.cmake | 87 -
ecbuild/cmake/FindRPCGEN.cmake | 20 -
ecbuild/cmake/FindRealtime.cmake | 22 -
ecbuild/cmake/FindSZip.cmake | 32 -
ecbuild/cmake/FindScin.cmake | 48 -
ecbuild/cmake/FindTrilinos.cmake | 52 -
ecbuild/cmake/FindXLFortranLibs.cmake | 49 -
ecbuild/cmake/FindYACC.cmake | 157 -
ecbuild/cmake/Findgrib_api.cmake | 135 -
ecbuild/cmake/Findodb_api.cmake | 99 -
ecbuild/cmake/Findspot.cmake | 67 -
ecbuild/cmake/VERSION.cmake | 7 -
ecbuild/cmake/contrib/FindEigen3.cmake | 93 -
ecbuild/cmake/contrib/FindFFTW.cmake | 124 -
ecbuild/cmake/contrib/FindNetCDF4.cmake | 314 -
.../contrib/GetGitRevisionDescription.cmake.in | 38 -
.../contrib/GreatCMakeCookOff/tests/CMakeLists.txt | 12 -
.../GreatCMakeCookOff/tests/cpp11/CMakeLists.txt | 3 -
ecbuild/cmake/ecbuild_add_cxx11_flags.cmake | 25 -
ecbuild/cmake/ecbuild_add_executable.cmake | 197 -
ecbuild/cmake/ecbuild_add_extra_search_paths.cmake | 34 -
ecbuild/cmake/ecbuild_add_library.cmake | 328 -
ecbuild/cmake/ecbuild_add_option.cmake | 194 -
ecbuild/cmake/ecbuild_add_persistent.cmake | 61 -
ecbuild/cmake/ecbuild_add_resources.cmake | 158 -
ecbuild/cmake/ecbuild_add_test.cmake | 315 -
ecbuild/cmake/ecbuild_append_to_rpath.cmake | 82 -
ecbuild/cmake/ecbuild_bundle.cmake | 284 -
ecbuild/cmake/ecbuild_cache.cmake | 65 -
ecbuild/cmake/ecbuild_check_c_source.cmake | 161 -
ecbuild/cmake/ecbuild_check_compiler.cmake | 141 -
ecbuild/cmake/ecbuild_check_cxx11.cmake | 67 -
ecbuild/cmake/ecbuild_check_cxx_source.cmake | 160 -
ecbuild/cmake/ecbuild_check_fortran_source.cmake | 157 -
ecbuild/cmake/ecbuild_check_functions.cmake | 125 -
ecbuild/cmake/ecbuild_check_os.cmake | 342 -
ecbuild/cmake/ecbuild_config.h.in | 167 -
ecbuild/cmake/ecbuild_debug_var.cmake | 35 -
ecbuild/cmake/ecbuild_declare_project.cmake | 151 -
ecbuild/cmake/ecbuild_define_build_types.cmake | 110 -
ecbuild/cmake/ecbuild_define_options.cmake | 40 -
ecbuild/cmake/ecbuild_define_paths.cmake | 41 -
ecbuild/cmake/ecbuild_echo_targets.cmake | 198 -
ecbuild/cmake/ecbuild_enable_fortran.cmake | 56 -
ecbuild/cmake/ecbuild_find_fortranlibs.cmake | 131 -
ecbuild/cmake/ecbuild_find_lexyacc.cmake | 60 -
ecbuild/cmake/ecbuild_find_mpi.cmake | 230 -
ecbuild/cmake/ecbuild_find_omp.cmake | 204 -
ecbuild/cmake/ecbuild_find_package.cmake | 190 -
ecbuild/cmake/ecbuild_find_perl.cmake | 45 -
ecbuild/cmake/ecbuild_find_python.cmake | 131 -
.../cmake/ecbuild_generate_config_headers.cmake | 47 -
ecbuild/cmake/ecbuild_generate_rpc.cmake | 73 -
ecbuild/cmake/ecbuild_generate_yy.cmake | 113 -
ecbuild/cmake/ecbuild_get_date.cmake | 32 -
ecbuild/cmake/ecbuild_get_resources.cmake | 52 -
ecbuild/cmake/ecbuild_get_test_data.cmake | 271 -
ecbuild/cmake/ecbuild_install_package.cmake | 286 -
ecbuild/cmake/ecbuild_links_target.cmake | 74 -
.../cmake/ecbuild_list_extra_search_paths.cmake | 108 -
ecbuild/cmake/ecbuild_list_macros.cmake | 57 -
ecbuild/cmake/ecbuild_pkgconfig.cmake | 365 -
ecbuild/cmake/ecbuild_print_summary.cmake | 115 -
ecbuild/cmake/ecbuild_project_files.cmake | 73 -
ecbuild/cmake/ecbuild_requires_macro_version.cmake | 15 -
ecbuild/cmake/ecbuild_separate_sources.cmake | 63 -
ecbuild/cmake/ecbuild_setup_test_framework.cmake | 42 -
ecbuild/cmake/ecbuild_system.cmake | 281 -
ecbuild/cmake/ecbuild_use_package.cmake | 206 -
ecbuild/cmake/ecbuild_version.h.in | 20 -
ecbuild/cmake/ecbuild_warn_unused_files.cmake | 58 -
.../cmake/include/ecbuild/boost_test_framework.h | 17 -
ecbuild/cmake/pkg-config.pc.in | 35 -
ecbuild/cmake/project-config.cmake.in | 80 -
ecbuild/cmake/sg.pl | 573 --
ecbuild/examples/cpp/bar/CMakeLists.txt | 60 -
ecbuild/examples/cpp/bar/VERSION.cmake | 1 -
ecbuild/examples/cpp/bar/bar.c | 6 -
ecbuild/examples/cpp/bar/bar.h | 6 -
ecbuild/examples/cpp/bar/main.cc | 10 -
ecbuild/examples/cpp/bar/test.cc | 13 -
.../examples/cpp/boost-python-lib/CMakeLists.txt | 60 -
ecbuild/examples/cpp/boost-python-lib/mypython.py | 10 -
.../examples/cpp/boost-python-lib/pythonlib.cpp | 6 -
.../examples/cpp/boost-python-lib/pythonlib.hpp | 6 -
ecbuild/examples/cpp/foo/CMakeLists.txt | 62 -
ecbuild/examples/cpp/foo/VERSION.cmake | 1 -
ecbuild/examples/cpp/foo/foo.c | 4 -
ecbuild/examples/cpp/foo/foo.h | 6 -
ecbuild/examples/cpp/foo/main.cc | 10 -
ecbuild/examples/cpp/foo/test.cc | 13 -
ecbuild/examples/fortran/CMakeLists.txt | 21 -
ecbuild/examples/fortran/area_circle.f90 | 15 -
ecbuild/examples/fortran/area_circle.h | 5 -
ecbuild/examples/fortran/circle.f90 | 11 -
ecbuild/examples/fortran/constants.f90 | 12 -
ecbuild/examples/fortran/lolo_circle.f90 | 0
ecbuild/examples/fortran/main.F90 | 25 -
ecbuild/project_summary.cmake | 21 -
ecbuild/share/CMakeLists.txt | 3 -
ecbuild/share/ecbuild/cmake | 1 -
.../share/ecbuild/toolchains/ecmwf-XC30-Cray.cmake | 63 -
ecbuild/share/ecmwf_license_header.txt | 8 -
ecflow_4_0_7/.gitignore | 39 -
ecflow_4_0_7/ACore/CMakeLists.txt | 34 -
ecflow_4_0_7/ACore/Jamfile.jam | 46 -
ecflow_4_0_7/ACore/doc/File_r.cpp_old | 48 -
ecflow_4_0_7/ACore/doc/StackTrace.cpp_old | 107 -
ecflow_4_0_7/ACore/doc/StackTrace.hpp_old | 37 -
ecflow_4_0_7/ACore/fred.o | Bin 74080 -> 0 bytes
ecflow_4_0_7/ACore/src/Archive.hpp | 57 -
ecflow_4_0_7/ACore/src/ArgvCreator.cpp | 53 -
ecflow_4_0_7/ACore/src/ArgvCreator.hpp | 43 -
ecflow_4_0_7/ACore/src/AssertTimer.cpp | 32 -
ecflow_4_0_7/ACore/src/AssertTimer.hpp | 43 -
ecflow_4_0_7/ACore/src/Calendar.cpp | 383 -
ecflow_4_0_7/ACore/src/Calendar.hpp | 255 -
ecflow_4_0_7/ACore/src/CalendarUpdateParams.hpp | 71 -
ecflow_4_0_7/ACore/src/CheckPt.hpp | 42 -
ecflow_4_0_7/ACore/src/Child.cpp | 167 -
ecflow_4_0_7/ACore/src/Child.hpp | 61 -
ecflow_4_0_7/ACore/src/DState.cpp | 136 -
ecflow_4_0_7/ACore/src/DState.hpp | 72 -
ecflow_4_0_7/ACore/src/DurationTimer.hpp | 39 -
ecflow_4_0_7/ACore/src/Ecf.cpp | 66 -
ecflow_4_0_7/ACore/src/Ecf.hpp | 92 -
ecflow_4_0_7/ACore/src/Extract.cpp | 125 -
ecflow_4_0_7/ACore/src/Extract.hpp | 57 -
ecflow_4_0_7/ACore/src/File.cpp | 984 ---
ecflow_4_0_7/ACore/src/File.hpp | 152 -
ecflow_4_0_7/ACore/src/File_r.cpp | 24 -
ecflow_4_0_7/ACore/src/File_r.hpp | 42 -
ecflow_4_0_7/ACore/src/Host.cpp | 82 -
ecflow_4_0_7/ACore/src/Host.hpp | 52 -
ecflow_4_0_7/ACore/src/Indentor.cpp | 31 -
ecflow_4_0_7/ACore/src/Indentor.hpp | 37 -
ecflow_4_0_7/ACore/src/Log.cpp | 343 -
ecflow_4_0_7/ACore/src/Log.hpp | 166 -
ecflow_4_0_7/ACore/src/LogVerification.cpp | 138 -
ecflow_4_0_7/ACore/src/LogVerification.hpp | 41 -
ecflow_4_0_7/ACore/src/NOrder.cpp | 55 -
ecflow_4_0_7/ACore/src/NOrder.hpp | 31 -
ecflow_4_0_7/ACore/src/NState.cpp | 113 -
ecflow_4_0_7/ACore/src/NState.hpp | 69 -
ecflow_4_0_7/ACore/src/NodePath.cpp | 83 -
ecflow_4_0_7/ACore/src/NodePath.hpp | 46 -
ecflow_4_0_7/ACore/src/Passwd.cpp | 84 -
ecflow_4_0_7/ACore/src/Passwd.hpp | 47 -
ecflow_4_0_7/ACore/src/PrintStyle.cpp | 53 -
ecflow_4_0_7/ACore/src/PrintStyle.hpp | 50 -
ecflow_4_0_7/ACore/src/SState.cpp | 58 -
ecflow_4_0_7/ACore/src/SState.hpp | 46 -
ecflow_4_0_7/ACore/src/Serialization.hpp | 135 -
ecflow_4_0_7/ACore/src/SerializationTest.hpp | 71 -
ecflow_4_0_7/ACore/src/Stl.hpp | 71 -
ecflow_4_0_7/ACore/src/Str.cpp | 346 -
ecflow_4_0_7/ACore/src/Str.hpp | 150 -
ecflow_4_0_7/ACore/src/TimeSeries.cpp | 836 --
ecflow_4_0_7/ACore/src/TimeSeries.hpp | 215 -
ecflow_4_0_7/ACore/src/TimeSlot.cpp | 89 -
ecflow_4_0_7/ACore/src/TimeSlot.hpp | 86 -
ecflow_4_0_7/ACore/src/TimeStamp.cpp | 40 -
ecflow_4_0_7/ACore/src/TimeStamp.hpp | 35 -
ecflow_4_0_7/ACore/src/Version.cpp | 131 -
ecflow_4_0_7/ACore/src/Version.hpp | 56 -
ecflow_4_0_7/ACore/src/WhiteListFile.cpp | 163 -
ecflow_4_0_7/ACore/src/WhiteListFile.hpp | 47 -
ecflow_4_0_7/ACore/src/boost_archive.cpp | 60 -
ecflow_4_0_7/ACore/src/boost_archive.hpp | 96 -
ecflow_4_0_7/ACore/src/ecflow_version.h | 10 -
ecflow_4_0_7/ACore/test/TestArgvCreator.cpp | 67 -
ecflow_4_0_7/ACore/test/TestCalendar.cpp | 454 -
ecflow_4_0_7/ACore/test/TestExceptionSafety.cpp | 51 -
ecflow_4_0_7/ACore/test/TestFile.cpp | 312 -
ecflow_4_0_7/ACore/test/TestGetUserDetails.cpp | 57 -
ecflow_4_0_7/ACore/test/TestLog.cpp | 365 -
ecflow_4_0_7/ACore/test/TestMigration.cpp | 73 -
ecflow_4_0_7/ACore/test/TestNodePath.cpp | 148 -
ecflow_4_0_7/ACore/test/TestRealCalendar.cpp | 355 -
ecflow_4_0_7/ACore/test/TestSerialisation.cpp | 135 -
ecflow_4_0_7/ACore/test/TestStackTrace.cpp | 80 -
ecflow_4_0_7/ACore/test/TestStr.cpp | 694 --
ecflow_4_0_7/ACore/test/TestTimeSeries.cpp | 676 --
ecflow_4_0_7/ACore/test/TestTimeSlot.cpp | 109 -
ecflow_4_0_7/ACore/test/TestVersion.cpp | 85 -
ecflow_4_0_7/ACore/test/TestVersioning.cpp | 68 -
ecflow_4_0_7/ACore/test/TestVersioning.hpp | 97 -
ecflow_4_0_7/ACore/test/TestWhiteListFile.cpp | 148 -
.../ACore/test/data/goodWhiteListFiles/good1.lists | 22 -
.../test/data/goodWhiteListFiles/goodsms.lists | 7 -
ecflow_4_0_7/ANattr/jamfile.jam | 44 -
ecflow_4_0_7/ANattr/src/AutoCancelAttr.cpp | 103 -
ecflow_4_0_7/ANattr/src/AutoCancelAttr.hpp | 59 -
ecflow_4_0_7/ANattr/src/ClockAttr.cpp | 169 -
ecflow_4_0_7/ANattr/src/ClockAttr.hpp | 100 -
ecflow_4_0_7/ANattr/src/CronAttr.cpp | 724 --
ecflow_4_0_7/ANattr/src/CronAttr.hpp | 140 -
ecflow_4_0_7/ANattr/src/DateAttr.cpp | 293 -
ecflow_4_0_7/ANattr/src/DateAttr.hpp | 102 -
ecflow_4_0_7/ANattr/src/DayAttr.cpp | 192 -
ecflow_4_0_7/ANattr/src/DayAttr.hpp | 90 -
ecflow_4_0_7/ANattr/src/LateAttr.cpp | 126 -
ecflow_4_0_7/ANattr/src/LateAttr.hpp | 105 -
ecflow_4_0_7/ANattr/src/NodeAttr.cpp | 366 -
ecflow_4_0_7/ANattr/src/NodeAttr.hpp | 211 -
ecflow_4_0_7/ANattr/src/RepeatAttr.cpp | 957 --
ecflow_4_0_7/ANattr/src/RepeatAttr.hpp | 479 -
ecflow_4_0_7/ANattr/src/TimeAttr.cpp | 188 -
ecflow_4_0_7/ANattr/src/TimeAttr.hpp | 134 -
ecflow_4_0_7/ANattr/src/TodayAttr.cpp | 193 -
ecflow_4_0_7/ANattr/src/TodayAttr.hpp | 185 -
ecflow_4_0_7/ANattr/src/Variable.cpp | 87 -
ecflow_4_0_7/ANattr/src/Variable.hpp | 74 -
ecflow_4_0_7/ANattr/src/VerifyAttr.cpp | 77 -
ecflow_4_0_7/ANattr/src/VerifyAttr.hpp | 73 -
ecflow_4_0_7/ANattr/src/Zombie.cpp | 216 -
ecflow_4_0_7/ANattr/src/Zombie.hpp | 166 -
ecflow_4_0_7/ANattr/src/ZombieAttr.cpp | 240 -
ecflow_4_0_7/ANattr/src/ZombieAttr.hpp | 82 -
ecflow_4_0_7/ANattr/test/TestAttrSerialization.cpp | 297 -
ecflow_4_0_7/ANattr/test/TestCron.cpp | 439 -
ecflow_4_0_7/ANattr/test/TestDayAttr.cpp | 78 -
ecflow_4_0_7/ANattr/test/TestLabel.cpp | 83 -
ecflow_4_0_7/ANattr/test/TestMigration.cpp | 185 -
ecflow_4_0_7/ANattr/test/TestRepeat.cpp | 425 -
ecflow_4_0_7/ANattr/test/TestTimeAttr.cpp | 345 -
ecflow_4_0_7/ANattr/test/TestTodayAttr.cpp | 181 -
ecflow_4_0_7/ANattr/test/TestVariable.cpp | 57 -
.../ANattr/test/data/migration/v1_9/AutoCancelAttr | 1 -
.../test/data/migration/v1_9/AutoCancelAttr_1 | 1 -
.../ANattr/test/data/migration/v1_9/ClockAttr | 1 -
.../ANattr/test/data/migration/v1_9/CronAttr | 1 -
.../ANattr/test/data/migration/v1_9/DateAttr | 1 -
.../ANattr/test/data/migration/v1_9/DayAttr | 1 -
.../ANattr/test/data/migration/v1_9/Event_1 | 1 -
.../ANattr/test/data/migration/v1_9/Event_2 | 1 -
ecflow_4_0_7/ANattr/test/data/migration/v1_9/Label | 1 -
.../ANattr/test/data/migration/v1_9/LateAttr | 1 -
ecflow_4_0_7/ANattr/test/data/migration/v1_9/Meter | 1 -
.../ANattr/test/data/migration/v1_9/RepeatDate | 2 -
.../test/data/migration/v1_9/RepeatEnumerated | 2 -
.../ANattr/test/data/migration/v1_9/RepeatInteger | 2 -
.../ANattr/test/data/migration/v1_9/RepeatString | 2 -
.../ANattr/test/data/migration/v1_9/TimeAttr | 1 -
.../ANattr/test/data/migration/v1_9/TodayAttr | 1 -
.../ANattr/test/data/migration/v1_9/Variable | 1 -
.../ANattr/test/data/migration/v1_9/VerifyAttr | 1 -
.../ANattr/test/data/migration/v1_9/ZombieAttr | 1 -
ecflow_4_0_7/ANode/CMakeLists.txt | 72 -
ecflow_4_0_7/ANode/jamfile.jam | 64 -
ecflow_4_0_7/ANode/src/AbstractObserver.hpp | 35 -
ecflow_4_0_7/ANode/src/Alias.cpp | 168 -
ecflow_4_0_7/ANode/src/Alias.hpp | 94 -
ecflow_4_0_7/ANode/src/Aspect.hpp | 42 -
ecflow_4_0_7/ANode/src/ChangeMgrSingleton.cpp | 253 -
ecflow_4_0_7/ANode/src/ChangeMgrSingleton.hpp | 107 -
ecflow_4_0_7/ANode/src/ChildAttrs.cpp | 545 --
ecflow_4_0_7/ANode/src/ChildAttrs.hpp | 132 -
ecflow_4_0_7/ANode/src/ClientSuiteMgr.cpp | 280 -
ecflow_4_0_7/ANode/src/ClientSuiteMgr.hpp | 118 -
ecflow_4_0_7/ANode/src/ClientSuites.cpp | 332 -
ecflow_4_0_7/ANode/src/ClientSuites.hpp | 145 -
ecflow_4_0_7/ANode/src/CmdContext.cpp | 29 -
ecflow_4_0_7/ANode/src/CmdContext.hpp | 36 -
ecflow_4_0_7/ANode/src/Defs.cpp | 1468 ----
ecflow_4_0_7/ANode/src/Defs.hpp | 399 -
ecflow_4_0_7/ANode/src/DefsDelta.cpp | 80 -
ecflow_4_0_7/ANode/src/DefsDelta.hpp | 88 -
ecflow_4_0_7/ANode/src/EcfFile.cpp | 1348 ---
ecflow_4_0_7/ANode/src/EcfFile.hpp | 107 -
ecflow_4_0_7/ANode/src/ExprAst.cpp | 1238 ---
ecflow_4_0_7/ANode/src/ExprAst.hpp | 516 --
ecflow_4_0_7/ANode/src/ExprAstVisitor.cpp | 74 -
ecflow_4_0_7/ANode/src/ExprAstVisitor.hpp | 148 -
ecflow_4_0_7/ANode/src/ExprDuplicate.cpp | 61 -
ecflow_4_0_7/ANode/src/ExprDuplicate.hpp | 44 -
ecflow_4_0_7/ANode/src/ExprParser.cpp | 933 --
ecflow_4_0_7/ANode/src/ExprParser.hpp | 64 -
ecflow_4_0_7/ANode/src/Expression.cpp | 237 -
ecflow_4_0_7/ANode/src/Expression.hpp | 153 -
ecflow_4_0_7/ANode/src/Family.cpp | 202 -
ecflow_4_0_7/ANode/src/Family.hpp | 86 -
ecflow_4_0_7/ANode/src/Flag.cpp | 164 -
ecflow_4_0_7/ANode/src/Flag.hpp | 119 -
ecflow_4_0_7/ANode/src/InLimit.cpp | 83 -
ecflow_4_0_7/ANode/src/InLimit.hpp | 72 -
ecflow_4_0_7/ANode/src/InLimitMgr.cpp | 436 -
ecflow_4_0_7/ANode/src/InLimitMgr.hpp | 131 -
ecflow_4_0_7/ANode/src/JobCreationCtrl.cpp | 32 -
ecflow_4_0_7/ANode/src/JobCreationCtrl.hpp | 52 -
ecflow_4_0_7/ANode/src/JobProfiler.cpp | 81 -
ecflow_4_0_7/ANode/src/JobProfiler.hpp | 53 -
ecflow_4_0_7/ANode/src/Jobs.cpp | 126 -
ecflow_4_0_7/ANode/src/Jobs.hpp | 69 -
ecflow_4_0_7/ANode/src/JobsParam.hpp | 81 -
ecflow_4_0_7/ANode/src/Limit.cpp | 209 -
ecflow_4_0_7/ANode/src/Limit.hpp | 89 -
ecflow_4_0_7/ANode/src/LimitFwd.hpp | 22 -
ecflow_4_0_7/ANode/src/Memento.cpp | 113 -
ecflow_4_0_7/ANode/src/Memento.hpp | 742 --
ecflow_4_0_7/ANode/src/MiscAttrs.cpp | 178 -
ecflow_4_0_7/ANode/src/MiscAttrs.hpp | 89 -
ecflow_4_0_7/ANode/src/Node.cpp | 1870 ----
ecflow_4_0_7/ANode/src/Node.hpp | 748 --
ecflow_4_0_7/ANode/src/NodeAdd.cpp | 299 -
ecflow_4_0_7/ANode/src/NodeChange.cpp | 188 -
ecflow_4_0_7/ANode/src/NodeContainer.cpp | 1000 ---
ecflow_4_0_7/ANode/src/NodeContainer.hpp | 151 -
ecflow_4_0_7/ANode/src/NodeDelete.cpp | 263 -
ecflow_4_0_7/ANode/src/NodeFind.cpp | 738 --
ecflow_4_0_7/ANode/src/NodeFwd.hpp | 107 -
ecflow_4_0_7/ANode/src/NodeMemento.cpp | 585 --
ecflow_4_0_7/ANode/src/NodeState.hpp | 70 -
ecflow_4_0_7/ANode/src/NodeTreeVisitor.cpp | 23 -
ecflow_4_0_7/ANode/src/NodeTreeVisitor.hpp | 40 -
ecflow_4_0_7/ANode/src/ResolveExternsVisitor.cpp | 125 -
ecflow_4_0_7/ANode/src/ResolveExternsVisitor.hpp | 81 -
ecflow_4_0_7/ANode/src/ServerState.cpp | 455 -
ecflow_4_0_7/ANode/src/ServerState.hpp | 139 -
ecflow_4_0_7/ANode/src/Signal.cpp | 66 -
ecflow_4_0_7/ANode/src/Signal.hpp | 38 -
ecflow_4_0_7/ANode/src/Submittable.cpp | 906 --
ecflow_4_0_7/ANode/src/Submittable.hpp | 196 -
ecflow_4_0_7/ANode/src/Suite.cpp | 727 --
ecflow_4_0_7/ANode/src/Suite.hpp | 175 -
ecflow_4_0_7/ANode/src/SuiteChanged.cpp | 89 -
ecflow_4_0_7/ANode/src/SuiteChanged.hpp | 68 -
ecflow_4_0_7/ANode/src/System.cpp | 411 -
ecflow_4_0_7/ANode/src/System.hpp | 89 -
ecflow_4_0_7/ANode/src/Task.cpp | 804 --
ecflow_4_0_7/ANode/src/Task.hpp | 172 -
ecflow_4_0_7/ANode/src/TaskScriptGenerator.cpp | 263 -
ecflow_4_0_7/ANode/src/TaskScriptGenerator.hpp | 46 -
ecflow_4_0_7/ANode/src/TimeDepAttrs.cpp | 872 --
ecflow_4_0_7/ANode/src/TimeDepAttrs.hpp | 148 -
ecflow_4_0_7/ANode/test/MyDefsFixture.hpp | 249 -
ecflow_4_0_7/ANode/test/TestAdd.cpp | 51 -
ecflow_4_0_7/ANode/test/TestAlias.cpp | 103 -
ecflow_4_0_7/ANode/test/TestChangeMgrSingleton.cpp | 130 -
ecflow_4_0_7/ANode/test/TestDefStatus.cpp | 154 -
ecflow_4_0_7/ANode/test/TestDefs.cpp | 84 -
ecflow_4_0_7/ANode/test/TestEcfFile.cpp | 857 --
.../ANode/test/TestEnviromentSubstitution.cpp | 85 -
ecflow_4_0_7/ANode/test/TestExprParser.cpp | 393 -
.../ANode/test/TestExprRepeatDateArithmetic.cpp | 216 -
ecflow_4_0_7/ANode/test/TestFindAbsNodePath.cpp | 75 -
ecflow_4_0_7/ANode/test/TestFlag.cpp | 75 -
ecflow_4_0_7/ANode/test/TestHistoryParser.cpp | 93 -
ecflow_4_0_7/ANode/test/TestInLimit.cpp | 76 -
ecflow_4_0_7/ANode/test/TestJobCreator.cpp | 121 -
ecflow_4_0_7/ANode/test/TestJobProfiler.cpp | 89 -
ecflow_4_0_7/ANode/test/TestLimit.cpp | 157 -
ecflow_4_0_7/ANode/test/TestMigration.cpp | 113 -
ecflow_4_0_7/ANode/test/TestMissNextTimeSlot.cpp | 114 -
ecflow_4_0_7/ANode/test/TestNodeBeginReque.cpp | 75 -
ecflow_4_0_7/ANode/test/TestOrder.cpp | 336 -
ecflow_4_0_7/ANode/test/TestPersistence.cpp | 79 -
ecflow_4_0_7/ANode/test/TestPreProcessing.cpp | 232 -
ecflow_4_0_7/ANode/test/TestReplace.cpp | 575 --
ecflow_4_0_7/ANode/test/TestSetState.cpp | 97 -
ecflow_4_0_7/ANode/test/TestSingleExprParse.cpp | 67 -
ecflow_4_0_7/ANode/test/TestSmsLocator.cpp | 128 -
.../ANode/test/TestTaskScriptGenerator.cpp | 205 -
ecflow_4_0_7/ANode/test/TestVariableGeneration.cpp | 93 -
.../ANode/test/TestVariableInheritance.cpp | 78 -
.../ANode/test/TestVariableSubstitution.cpp | 438 -
.../ANode/test/TestVariableSubstitutionDefs.cpp | 174 -
ecflow_4_0_7/ANode/test/TestZombies.cpp | 77 -
ecflow_4_0_7/ANode/test/Test_ECFLOW-195.cpp | 97 -
.../ANode/test/data/SMSHOME/suite/family/head.h | 44 -
.../ANode/test/data/SMSHOME/suite/family/tail.h | 10 -
.../data/SMSHOME2/bad/includes/recursive_head.h | 14 -
.../test/data/SMSHOME2/good/includes/config.h | 1527 ----
.../test/data/SMSHOME2/good/includes/config.oc.h | 197 -
.../ANode/test/data/SMSHOME2/good/includes/endt.h | 13 -
.../ANode/test/data/SMSHOME2/good/includes/head.h | 43 -
.../ANode/test/data/SMSHOME2/good/includes/law.h | 43 -
.../ANode/test/data/SMSHOME2/good/includes/rcp.h | 41 -
.../test/data/SMSHOME2/good/includes/set_traps.h | 6 -
.../ANode/test/data/SMSHOME2/good/includes/setup.h | 535 --
.../ANode/test/data/SMSHOME2/good/includes/sms.h | 55 -
.../ANode/test/data/SMSHOME2/good/includes/tail.h | 10 -
.../ANode/test/data/SMSHOME2/good/includes/trap.h | 137 -
ecflow_4_0_7/ANode/test/data/includes/head.h | 65 -
ecflow_4_0_7/ANode/test/data/includes/tail.h | 19 -
.../test/data/migration/fixture/boost_1_47.checkpt | 77 -
ecflow_4_0_7/AParser/CMakeLists.txt | 71 -
ecflow_4_0_7/AParser/Jamfile.jam | 126 -
ecflow_4_0_7/AParser/src/AutoCancelParser.cpp | 55 -
ecflow_4_0_7/AParser/src/AutoCancelParser.hpp | 27 -
ecflow_4_0_7/AParser/src/CalendarParser.cpp | 39 -
ecflow_4_0_7/AParser/src/CalendarParser.hpp | 28 -
ecflow_4_0_7/AParser/src/ClockParser.cpp | 143 -
ecflow_4_0_7/AParser/src/ClockParser.hpp | 29 -
ecflow_4_0_7/AParser/src/CronParser.cpp | 47 -
ecflow_4_0_7/AParser/src/CronParser.hpp | 30 -
ecflow_4_0_7/AParser/src/DateParser.cpp | 51 -
ecflow_4_0_7/AParser/src/DateParser.hpp | 28 -
ecflow_4_0_7/AParser/src/DayParser.cpp | 46 -
ecflow_4_0_7/AParser/src/DayParser.hpp | 27 -
ecflow_4_0_7/AParser/src/DefsParser.cpp | 425 -
ecflow_4_0_7/AParser/src/DefsParser.hpp | 27 -
ecflow_4_0_7/AParser/src/DefsStateParser.cpp | 42 -
ecflow_4_0_7/AParser/src/DefsStateParser.hpp | 35 -
ecflow_4_0_7/AParser/src/DefsStatusParser.cpp | 52 -
ecflow_4_0_7/AParser/src/DefsStatusParser.hpp | 28 -
ecflow_4_0_7/AParser/src/DefsStructureParser.cpp | 220 -
ecflow_4_0_7/AParser/src/DefsStructureParser.hpp | 79 -
ecflow_4_0_7/AParser/src/EventParser.cpp | 75 -
ecflow_4_0_7/AParser/src/EventParser.hpp | 28 -
ecflow_4_0_7/AParser/src/ExternParser.cpp | 48 -
ecflow_4_0_7/AParser/src/ExternParser.hpp | 41 -
ecflow_4_0_7/AParser/src/InlimitParser.cpp | 45 -
ecflow_4_0_7/AParser/src/InlimitParser.hpp | 28 -
ecflow_4_0_7/AParser/src/LabelParser.cpp | 35 -
ecflow_4_0_7/AParser/src/LabelParser.hpp | 28 -
ecflow_4_0_7/AParser/src/LateParser.cpp | 73 -
ecflow_4_0_7/AParser/src/LateParser.hpp | 27 -
ecflow_4_0_7/AParser/src/LimitParser.cpp | 64 -
ecflow_4_0_7/AParser/src/LimitParser.hpp | 28 -
ecflow_4_0_7/AParser/src/MeterParser.cpp | 54 -
ecflow_4_0_7/AParser/src/MeterParser.hpp | 28 -
ecflow_4_0_7/AParser/src/Parser.cpp | 167 -
ecflow_4_0_7/AParser/src/Parser.hpp | 80 -
ecflow_4_0_7/AParser/src/RepeatParser.cpp | 178 -
ecflow_4_0_7/AParser/src/RepeatParser.hpp | 33 -
ecflow_4_0_7/AParser/src/TimeParser.cpp | 48 -
ecflow_4_0_7/AParser/src/TimeParser.hpp | 28 -
ecflow_4_0_7/AParser/src/TodayParser.cpp | 45 -
ecflow_4_0_7/AParser/src/TodayParser.hpp | 28 -
ecflow_4_0_7/AParser/src/TriggerParser.cpp | 180 -
ecflow_4_0_7/AParser/src/TriggerParser.hpp | 46 -
ecflow_4_0_7/AParser/src/VariableParser.cpp | 103 -
ecflow_4_0_7/AParser/src/VariableParser.hpp | 48 -
ecflow_4_0_7/AParser/src/VerifyParser.cpp | 53 -
ecflow_4_0_7/AParser/src/VerifyParser.hpp | 29 -
ecflow_4_0_7/AParser/src/ZombieAttrParser.cpp | 39 -
ecflow_4_0_7/AParser/src/ZombieAttrParser.hpp | 27 -
ecflow_4_0_7/AParser/test/ParseOnly.cpp | 51 -
ecflow_4_0_7/AParser/test/ParseTimer.cpp | 224 -
ecflow_4_0_7/AParser/test/PersistHelper.cpp | 237 -
ecflow_4_0_7/AParser/test/PersistHelper.hpp | 58 -
ecflow_4_0_7/AParser/test/TestAutoAddExterns.cpp | 69 -
.../test/TestDefsStructurePersistAndReload.cpp | 96 -
ecflow_4_0_7/AParser/test/TestJobGenPerf.cpp | 84 -
ecflow_4_0_7/AParser/test/TestMigration.cpp | 427 -
ecflow_4_0_7/AParser/test/TestParser.cpp | 125 -
ecflow_4_0_7/AParser/test/TestSingleDefsFile.cpp | 304 -
ecflow_4_0_7/AParser/test/TestVariableParsing.cpp | 81 -
.../data/bad_defs/repeat/date_missing_name.def | 3 -
.../bad_defs/repeat/duplicate_repeats_per_node.def | 4 -
.../test/data/bad_defs/repeat/invalid_dates.def | 5 -
.../test/data/bad_defs/repeat/invalid_dates_2.def | 5 -
.../test/data/bad_defs/repeat/repeat_integer.def | 7 -
.../test/data/bad_defs/repeat/repeat_month.def | 4 -
.../test/data/bad_defs/repeat/repeat_with_cron.def | 5 -
.../test/data/bad_defs/repeat/repeat_year.def | 4 -
.../data/bad_defs/repeat/string_missing_name.def | 4 -
.../test/data/good_defs/repeat/repeat_date.def | 6 -
.../test/data/good_defs_state/defs/defs_state.def | 4 -
ecflow_4_0_7/Base/CMakeLists.txt | 108 -
ecflow_4_0_7/Base/Jamfile.jam | 70 -
ecflow_4_0_7/Base/src/AbstractClientEnv.hpp | 66 -
ecflow_4_0_7/Base/src/AbstractServer.hpp | 193 -
ecflow_4_0_7/Base/src/Client.cpp | 342 -
ecflow_4_0_7/Base/src/Client.hpp | 83 -
ecflow_4_0_7/Base/src/ClientToServerRequest.cpp | 58 -
ecflow_4_0_7/Base/src/ClientToServerRequest.hpp | 67 -
ecflow_4_0_7/Base/src/Cmd.hpp | 27 -
ecflow_4_0_7/Base/src/Connection.hpp | 315 -
ecflow_4_0_7/Base/src/Gnuplot.cpp | 358 -
ecflow_4_0_7/Base/src/Gnuplot.hpp | 69 -
ecflow_4_0_7/Base/src/ServerReply.cpp | 36 -
ecflow_4_0_7/Base/src/ServerReply.hpp | 138 -
ecflow_4_0_7/Base/src/ServerToClientResponse.cpp | 70 -
ecflow_4_0_7/Base/src/ServerToClientResponse.hpp | 62 -
ecflow_4_0_7/Base/src/Stats.cpp | 333 -
ecflow_4_0_7/Base/src/Stats.hpp | 216 -
ecflow_4_0_7/Base/src/WhyCmd.cpp | 58 -
ecflow_4_0_7/Base/src/WhyCmd.hpp | 37 -
ecflow_4_0_7/Base/src/ZombieCtrl.cpp | 772 --
ecflow_4_0_7/Base/src/ZombieCtrl.hpp | 142 -
ecflow_4_0_7/Base/src/cts/AlterCmd.cpp | 977 ---
ecflow_4_0_7/Base/src/cts/BeginCmd.cpp | 177 -
ecflow_4_0_7/Base/src/cts/CFileCmd.cpp | 309 -
ecflow_4_0_7/Base/src/cts/CSyncCmd.cpp | 156 -
ecflow_4_0_7/Base/src/cts/CheckPtCmd.cpp | 202 -
ecflow_4_0_7/Base/src/cts/ClientHandleCmd.cpp | 336 -
ecflow_4_0_7/Base/src/cts/ClientToServerCmd.cpp | 194 -
ecflow_4_0_7/Base/src/cts/ClientToServerCmd.hpp | 1828 ----
ecflow_4_0_7/Base/src/cts/CtsApi.cpp | 710 --
ecflow_4_0_7/Base/src/cts/CtsApi.hpp | 216 -
ecflow_4_0_7/Base/src/cts/CtsCmd.cpp | 390 -
ecflow_4_0_7/Base/src/cts/CtsCmdRegistry.cpp | 145 -
ecflow_4_0_7/Base/src/cts/CtsCmdRegistry.hpp | 56 -
ecflow_4_0_7/Base/src/cts/CtsNodeCmd.cpp | 338 -
ecflow_4_0_7/Base/src/cts/EditHistoryMgr.cpp | 88 -
ecflow_4_0_7/Base/src/cts/EditHistoryMgr.hpp | 41 -
ecflow_4_0_7/Base/src/cts/EditScriptCmd.cpp | 400 -
ecflow_4_0_7/Base/src/cts/ForceCmd.cpp | 259 -
ecflow_4_0_7/Base/src/cts/FreeDepCmd.cpp | 154 -
ecflow_4_0_7/Base/src/cts/GroupCTSCmd.cpp | 293 -
ecflow_4_0_7/Base/src/cts/LoadDefsCmd.cpp | 154 -
ecflow_4_0_7/Base/src/cts/LogCmd.cpp | 234 -
ecflow_4_0_7/Base/src/cts/LogMessageCmd.cpp | 72 -
ecflow_4_0_7/Base/src/cts/OrderNodeCmd.cpp | 110 -
ecflow_4_0_7/Base/src/cts/PathsCmd.cpp | 505 --
ecflow_4_0_7/Base/src/cts/PlugCmd.cpp | 392 -
ecflow_4_0_7/Base/src/cts/ReplaceNodeCmd.cpp | 203 -
ecflow_4_0_7/Base/src/cts/RequeueNodeCmd.cpp | 219 -
ecflow_4_0_7/Base/src/cts/RunNodeCmd.cpp | 170 -
ecflow_4_0_7/Base/src/cts/ServerVersionCmd.cpp | 80 -
ecflow_4_0_7/Base/src/cts/ShowCmd.cpp | 104 -
ecflow_4_0_7/Base/src/cts/TaskApi.cpp | 80 -
ecflow_4_0_7/Base/src/cts/TaskApi.hpp | 43 -
ecflow_4_0_7/Base/src/cts/TaskCmds.cpp | 923 --
ecflow_4_0_7/Base/src/cts/UserCmd.cpp | 126 -
ecflow_4_0_7/Base/src/cts/ZombieCmd.cpp | 226 -
ecflow_4_0_7/Base/src/stc/DefsCmd.cpp | 99 -
ecflow_4_0_7/Base/src/stc/DefsCmd.hpp | 52 -
ecflow_4_0_7/Base/src/stc/ErrorCmd.cpp | 63 -
ecflow_4_0_7/Base/src/stc/ErrorCmd.hpp | 45 -
ecflow_4_0_7/Base/src/stc/GroupSTCCmd.cpp | 124 -
ecflow_4_0_7/Base/src/stc/GroupSTCCmd.hpp | 44 -
ecflow_4_0_7/Base/src/stc/PreAllocatedReply.cpp | 201 -
ecflow_4_0_7/Base/src/stc/PreAllocatedReply.hpp | 71 -
ecflow_4_0_7/Base/src/stc/SClientHandleCmd.cpp | 34 -
ecflow_4_0_7/Base/src/stc/SClientHandleCmd.hpp | 42 -
.../Base/src/stc/SClientHandleSuitesCmd.cpp | 118 -
.../Base/src/stc/SClientHandleSuitesCmd.hpp | 47 -
ecflow_4_0_7/Base/src/stc/SNewsCmd.cpp | 262 -
ecflow_4_0_7/Base/src/stc/SNewsCmd.hpp | 63 -
ecflow_4_0_7/Base/src/stc/SNodeCmd.cpp | 144 -
ecflow_4_0_7/Base/src/stc/SNodeCmd.hpp | 58 -
ecflow_4_0_7/Base/src/stc/SServerLoadCmd.cpp | 45 -
ecflow_4_0_7/Base/src/stc/SServerLoadCmd.hpp | 48 -
ecflow_4_0_7/Base/src/stc/SStatsCmd.cpp | 57 -
ecflow_4_0_7/Base/src/stc/SStatsCmd.hpp | 50 -
ecflow_4_0_7/Base/src/stc/SStringCmd.cpp | 46 -
ecflow_4_0_7/Base/src/stc/SStringCmd.hpp | 54 -
ecflow_4_0_7/Base/src/stc/SStringVecCmd.cpp | 50 -
ecflow_4_0_7/Base/src/stc/SStringVecCmd.hpp | 46 -
ecflow_4_0_7/Base/src/stc/SSuitesCmd.cpp | 86 -
ecflow_4_0_7/Base/src/stc/SSuitesCmd.hpp | 48 -
ecflow_4_0_7/Base/src/stc/SSyncCmd.cpp | 466 -
ecflow_4_0_7/Base/src/stc/SSyncCmd.hpp | 160 -
ecflow_4_0_7/Base/src/stc/ServerToClientCmd.cpp | 26 -
ecflow_4_0_7/Base/src/stc/ServerToClientCmd.hpp | 62 -
ecflow_4_0_7/Base/src/stc/StcCmd.cpp | 69 -
ecflow_4_0_7/Base/src/stc/StcCmd.hpp | 57 -
ecflow_4_0_7/Base/src/stc/ZombieGetCmd.cpp | 66 -
ecflow_4_0_7/Base/src/stc/ZombieGetCmd.hpp | 49 -
ecflow_4_0_7/Base/test/MockServer.hpp | 98 -
ecflow_4_0_7/Base/test/TestAlterCmd.cpp | 780 --
ecflow_4_0_7/Base/test/TestClientHandleCmd.cpp | 260 -
ecflow_4_0_7/Base/test/TestCmd.cpp | 109 -
ecflow_4_0_7/Base/test/TestDeleteNodeCmd.cpp | 163 -
ecflow_4_0_7/Base/test/TestECFLOW-189.cpp | 87 -
ecflow_4_0_7/Base/test/TestForceCmd.cpp | 922 --
ecflow_4_0_7/Base/test/TestFreeDepCmd.cpp | 304 -
ecflow_4_0_7/Base/test/TestHelper.hpp | 90 -
ecflow_4_0_7/Base/test/TestLimit.cpp | 669 --
ecflow_4_0_7/Base/test/TestMeterCmd.cpp | 96 -
ecflow_4_0_7/Base/test/TestRequest.cpp | 316 -
ecflow_4_0_7/Base/test/TestRequeueNodeCmd.cpp | 150 -
ecflow_4_0_7/Base/test/TestResolveDependencies.cpp | 277 -
ecflow_4_0_7/Base/test/TestSSyncCmd.cpp | 383 -
ecflow_4_0_7/Base/test/TestSSyncCmdOrder.cpp | 233 -
ecflow_4_0_7/Base/test/TestSSyncCmd_CH1.cpp | 678 --
ecflow_4_0_7/CMakeLists.txt | 191 -
ecflow_4_0_7/CSim/CMakeLists.txt | 50 -
ecflow_4_0_7/CSim/jamfile.jam | 95 -
ecflow_4_0_7/CSim/src/Analyser.cpp | 57 -
ecflow_4_0_7/CSim/src/Analyser.hpp | 31 -
ecflow_4_0_7/CSim/src/AstAnalyserVisitor.cpp | 58 -
ecflow_4_0_7/CSim/src/AstAnalyserVisitor.hpp | 64 -
ecflow_4_0_7/CSim/src/DefsAnalyserVisitor.cpp | 167 -
ecflow_4_0_7/CSim/src/DefsAnalyserVisitor.hpp | 47 -
ecflow_4_0_7/CSim/src/FlatAnalyserVisitor.cpp | 111 -
ecflow_4_0_7/CSim/src/FlatAnalyserVisitor.hpp | 43 -
ecflow_4_0_7/CSim/src/Simulator.cpp | 360 -
ecflow_4_0_7/CSim/src/Simulator.hpp | 61 -
ecflow_4_0_7/CSim/src/SimulatorVisitor.cpp | 148 -
ecflow_4_0_7/CSim/src/SimulatorVisitor.hpp | 73 -
ecflow_4_0_7/CSim/test/TestAnalysis.cpp | 82 -
ecflow_4_0_7/CSim/test/TestAutoCancel.cpp | 271 -
ecflow_4_0_7/CSim/test/TestMeter.cpp | 108 -
ecflow_4_0_7/CSim/test/TestRepeat.cpp | 412 -
ecflow_4_0_7/CSim/test/TestSimulator.cpp | 135 -
ecflow_4_0_7/CSim/test/TestSingleSimulator.cpp | 107 -
ecflow_4_0_7/CSim/test/TestTime.cpp | 380 -
ecflow_4_0_7/CSim/test/TestToday.cpp | 158 -
ecflow_4_0_7/CSim/test/TestUtil.cpp | 28 -
ecflow_4_0_7/CSim/test/TestUtil.hpp | 36 -
ecflow_4_0_7/Client/CMakeLists.txt | 125 -
ecflow_4_0_7/Client/Jamfile.jam | 137 -
ecflow_4_0_7/Client/doc/config_file.doc | 63 -
ecflow_4_0_7/Client/doc/environment.cfg | 68 -
ecflow_4_0_7/Client/src/ClientEnvironment.cpp | 391 -
ecflow_4_0_7/Client/src/ClientEnvironment.hpp | 150 -
ecflow_4_0_7/Client/src/ClientInvoker.cpp | 1321 ---
ecflow_4_0_7/Client/src/ClientInvoker.hpp | 365 -
ecflow_4_0_7/Client/src/ClientMain.cpp | 32 -
ecflow_4_0_7/Client/src/ClientOptions.cpp | 328 -
ecflow_4_0_7/Client/src/ClientOptions.hpp | 50 -
ecflow_4_0_7/Client/src/Rtt.cpp | 180 -
ecflow_4_0_7/Client/src/Rtt.hpp | 62 -
ecflow_4_0_7/Client/src/UrlCmd.cpp | 66 -
ecflow_4_0_7/Client/src/UrlCmd.hpp | 40 -
ecflow_4_0_7/Client/test/EcfPortLock.hpp | 79 -
ecflow_4_0_7/Client/test/InvokeServer.hpp | 158 -
ecflow_4_0_7/Client/test/SCPort.cpp | 42 -
ecflow_4_0_7/Client/test/SCPort.hpp | 42 -
ecflow_4_0_7/Client/test/TestCheckPtDefsCmd.cpp | 237 -
ecflow_4_0_7/Client/test/TestClientEnvironment.cpp | 256 -
ecflow_4_0_7/Client/test/TestClientInterface.cpp | 515 --
ecflow_4_0_7/Client/test/TestClientInvoker.cpp | 63 -
ecflow_4_0_7/Client/test/TestClientTimeout.cpp | 77 -
ecflow_4_0_7/Client/test/TestGroupCmd.cpp | 219 -
ecflow_4_0_7/Client/test/TestJobGenOnly.cpp | 97 -
ecflow_4_0_7/Client/test/TestLifeCycle.cpp | 216 -
ecflow_4_0_7/Client/test/TestLoadDefsCmd.cpp | 160 -
ecflow_4_0_7/Client/test/TestMigration.cpp | 107 -
ecflow_4_0_7/Client/test/TestPlugCmd.cpp | 321 -
ecflow_4_0_7/Client/test/TestRtt.cpp | 53 -
ecflow_4_0_7/Client/test/TestServer.cpp | 318 -
.../Client/test/TestServerAndLifeCycle.cpp | 249 -
ecflow_4_0_7/Client/test/TestSignalSIGTERM.cpp | 82 -
ecflow_4_0_7/Client/test/TestSinglePerf.cpp | 211 -
ecflow_4_0_7/Client/test/TestUrlCmd.cpp | 65 -
ecflow_4_0_7/Client/test/TestWhiteListFile.cpp | 88 -
ecflow_4_0_7/Doc/user-manual/user_manual.docx | Bin 555789 -> 0 bytes
ecflow_4_0_7/Jamroot.jam | 187 -
ecflow_4_0_7/Makefile | 9 -
ecflow_4_0_7/Makefile.old | 24 -
ecflow_4_0_7/NOTICE | 56 -
ecflow_4_0_7/Pyext/.gitignore | 2 -
ecflow_4_0_7/Pyext/CMakeLists.txt | 143 -
ecflow_4_0_7/Pyext/doc/jamfile.jam | 299 -
ecflow_4_0_7/Pyext/doc/overload.txt | 14 -
ecflow_4_0_7/Pyext/ecflow/__init__.py | 12 -
ecflow_4_0_7/Pyext/jamfile.jam | 205 -
ecflow_4_0_7/Pyext/migrate/ecflow_migrate.py | 416 -
ecflow_4_0_7/Pyext/migrate/py_u_TestMigrate.py | 189 -
ecflow_4_0_7/Pyext/samples/ListVariables.py | 65 -
ecflow_4_0_7/Pyext/samples/TestBench.py | 200 -
ecflow_4_0_7/Pyext/samples/TestJobGenPerf.py | 155 -
ecflow_4_0_7/Pyext/samples/TestServerGetDefs.py | 59 -
ecflow_4_0_7/Pyext/samples/ecf.py | 1012 ---
ecflow_4_0_7/Pyext/samples/printdefs.py | 178 -
ecflow_4_0_7/Pyext/script.py | 11 -
ecflow_4_0_7/Pyext/setup.py.in | 135 -
ecflow_4_0_7/Pyext/src/BoostPythonUtil.cpp | 56 -
ecflow_4_0_7/Pyext/src/BoostPythonUtil.hpp | 37 -
ecflow_4_0_7/Pyext/src/ClientDoc.cpp | 1419 ---
ecflow_4_0_7/Pyext/src/ClientDoc.hpp | 92 -
ecflow_4_0_7/Pyext/src/DefsDoc.cpp | 800 --
ecflow_4_0_7/Pyext/src/DefsDoc.hpp | 71 -
ecflow_4_0_7/Pyext/src/EcfExt.cpp | 45 -
ecflow_4_0_7/Pyext/src/ExportClient.cpp | 329 -
ecflow_4_0_7/Pyext/src/ExportCore.cpp | 247 -
ecflow_4_0_7/Pyext/src/ExportDefs.cpp | 189 -
ecflow_4_0_7/Pyext/src/ExportNode.cpp | 279 -
ecflow_4_0_7/Pyext/src/ExportNodeAttr.cpp | 386 -
ecflow_4_0_7/Pyext/src/ExportSuiteAndFamily.cpp | 91 -
ecflow_4_0_7/Pyext/src/ExportTask.cpp | 66 -
ecflow_4_0_7/Pyext/src/NodeAttrDoc.cpp | 567 --
ecflow_4_0_7/Pyext/src/NodeAttrDoc.hpp | 54 -
ecflow_4_0_7/Pyext/test/CleanupOnlineTutorial.py | 28 -
ecflow_4_0_7/Pyext/test/TestEmbeddedEcf.cpp | 84 -
ecflow_4_0_7/Pyext/test/data/includes/head.h | 45 -
ecflow_4_0_7/Pyext/test/ecflow_test_util.py | 220 -
ecflow_4_0_7/Pyext/test/py_s_TestClientApi.py | 1539 ----
ecflow_4_0_7/Pyext/test/py_s_TestPythonChildApi.py | 140 -
ecflow_4_0_7/Pyext/test/py_u_TestAddDelete.py | 484 -
ecflow_4_0_7/Pyext/test/py_u_TestAddDeleteError.py | 86 -
ecflow_4_0_7/Pyext/test/py_u_TestAddDeleteFunc.py | 311 -
ecflow_4_0_7/Pyext/test/py_u_TestAddNodeFunc.py | 69 -
ecflow_4_0_7/Pyext/test/py_u_TestDefs.py | 221 -
ecflow_4_0_7/Pyext/test/py_u_TestDefsCheck.py | 72 -
ecflow_4_0_7/Pyext/test/py_u_TestDerivable.py | 28 -
ecflow_4_0_7/Pyext/test/py_u_TestEcf.py | 38 -
ecflow_4_0_7/Pyext/test/py_u_TestError.py | 443 -
ecflow_4_0_7/Pyext/test/py_u_TestFind.py | 54 -
.../Pyext/test/py_u_TestGeneratedVariable.py | 76 -
ecflow_4_0_7/Pyext/test/py_u_TestGetAllTasks.py | 73 -
ecflow_4_0_7/Pyext/test/py_u_TestJobGeneration.py | 135 -
ecflow_4_0_7/Pyext/test/py_u_TestParent.py | 77 -
.../Pyext/test/py_u_TestRepeatArithmetic.py | 52 -
ecflow_4_0_7/Pyext/test/py_u_TestSimulator.py | 82 -
ecflow_4_0_7/Pyext/test/py_u_TestTraversal.py | 221 -
ecflow_4_0_7/Pyext/test/py_u_TestUserManual.py | 156 -
ecflow_4_0_7/Pyext/test/py_u_TestWith.py | 79 -
ecflow_4_0_7/README | 157 -
ecflow_4_0_7/Server/Jamfile.jam | 93 -
ecflow_4_0_7/Server/server_environment.cfg | 153 -
ecflow_4_0_7/Server/src/CConnection.cpp | 237 -
ecflow_4_0_7/Server/src/CConnection.hpp | 74 -
ecflow_4_0_7/Server/src/CheckPtSaver.cpp | 243 -
ecflow_4_0_7/Server/src/CheckPtSaver.hpp | 86 -
ecflow_4_0_7/Server/src/NodeTreeTraverser.cpp | 396 -
ecflow_4_0_7/Server/src/NodeTreeTraverser.hpp | 86 -
ecflow_4_0_7/Server/src/Server.cpp | 716 --
ecflow_4_0_7/Server/src/Server.hpp | 159 -
ecflow_4_0_7/Server/src/ServerEnvironment.cpp | 635 --
ecflow_4_0_7/Server/src/ServerEnvironment.hpp | 216 -
ecflow_4_0_7/Server/src/ServerMain.cpp | 79 -
ecflow_4_0_7/Server/src/ServerOptions.cpp | 160 -
ecflow_4_0_7/Server/src/ServerOptions.hpp | 38 -
ecflow_4_0_7/Server/test/TestServer1.cpp | 135 -
ecflow_4_0_7/Server/test/TestServerEnvironment.cpp | 364 -
ecflow_4_0_7/Test/CMakeLists.txt | 75 -
ecflow_4_0_7/Test/DummyMain.cpp | 13 -
ecflow_4_0_7/Test/Jamfile.jam | 115 -
ecflow_4_0_7/Test/TestAbortCmd.cpp | 99 -
ecflow_4_0_7/Test/TestAlias.cpp | 218 -
ecflow_4_0_7/Test/TestClkSync.cpp | 85 -
ecflow_4_0_7/Test/TestComplete.cpp | 178 -
ecflow_4_0_7/Test/TestCron.cpp | 145 -
ecflow_4_0_7/Test/TestCtsWaitCmd.cpp | 216 -
ecflow_4_0_7/Test/TestEvents.cpp | 107 -
ecflow_4_0_7/Test/TestFileCmd.cpp | 132 -
ecflow_4_0_7/Test/TestHandle.cpp | 391 -
ecflow_4_0_7/Test/TestKillCmd.cpp | 149 -
ecflow_4_0_7/Test/TestLate.cpp | 85 -
ecflow_4_0_7/Test/TestLimit.cpp | 118 -
ecflow_4_0_7/Test/TestOrderCmd.cpp | 216 -
ecflow_4_0_7/Test/TestRepeat.cpp | 338 -
ecflow_4_0_7/Test/TestRequeueNode.cpp | 112 -
ecflow_4_0_7/Test/TestRunner.cpp | 21 -
ecflow_4_0_7/Test/TestServer.cpp | 135 -
ecflow_4_0_7/Test/TestSingle.cpp | 182 -
ecflow_4_0_7/Test/TestSuspend.cpp | 228 -
ecflow_4_0_7/Test/TestToday.cpp | 201 -
ecflow_4_0_7/Test/TestTrigger.cpp | 92 -
ecflow_4_0_7/Test/TestWhyCmd.cpp | 538 --
ecflow_4_0_7/Test/TestZombies.cpp | 948 --
ecflow_4_0_7/Test/Test_Time.cpp | 387 -
ecflow_4_0_7/Test/data/.gitignore | 2 -
ecflow_4_0_7/Test/src/ServerTestHarness.cpp | 558 --
ecflow_4_0_7/Test/src/ServerTestHarness.hpp | 109 -
ecflow_4_0_7/Test/src/TestFixture.cpp | 381 -
ecflow_4_0_7/Test/src/TestFixture.hpp | 103 -
ecflow_4_0_7/Test/src/ZombieUtil.hpp | 38 -
ecflow_4_0_7/Test/src/ZombieUtill.cpp | 184 -
ecflow_4_0_7/VERSION.cmake | 7 -
ecflow_4_0_7/build/aix_fix/README | 118 -
ecflow_4_0_7/build/aix_fix/path.hpp | 714 --
ecflow_4_0_7/build/boost_1_47_fix.sh | 46 -
ecflow_4_0_7/build/boost_1_48_fix.sh | 52 -
ecflow_4_0_7/build/boost_1_51_fix.sh | 36 -
ecflow_4_0_7/build/boost_1_53_fix.sh | 53 -
ecflow_4_0_7/build/boost_1_56_fix.sh | 14 -
ecflow_4_0_7/build/boost_1_57_fix.sh | 54 -
ecflow_4_0_7/build/boost_build.sh | 152 -
ecflow_4_0_7/build/clean.sh | 64 -
ecflow_4_0_7/build/cray_fix/swap.sh | 100 -
ecflow_4_0_7/build/cray_fix/update_cray_swap.sh | 9 -
ecflow_4_0_7/build/hpux_fix/README | 199 -
.../build/hpux_fix/boost_1_51_0/system_clocks.hpp | 234 -
ecflow_4_0_7/build/install_ecflow.sh | 258 -
ecflow_4_0_7/build/kill_ecf.sh | 26 -
ecflow_4_0_7/build/massif.sh | 33 -
ecflow_4_0_7/build/migrate.sh | 15 -
ecflow_4_0_7/build/p4_sync.sh | 27 -
ecflow_4_0_7/build/rmbin.sh | 23 -
ecflow_4_0_7/build/site_config/site-config-AIX.jam | 108 -
.../build/site_config/site-config-HPUX.jam | 113 -
.../build/site_config/site-config-Linux.jam | 91 -
.../site_config/site-config-Linux64-clang.jam | 91 -
.../site_config/site-config-Linux64-intel.jam | 98 -
.../build/site_config/site-config-Linux64.jam | 96 -
.../build/site_config/site-config-cray.jam | 203 -
ecflow_4_0_7/build/tar_ecflow.sh | 146 -
ecflow_4_0_7/build/tar_ecflow_doc.sh | 78 -
ecflow_4_0_7/build/test.sh | 185 -
ecflow_4_0_7/build/update_site_config.sh | 83 -
ecflow_4_0_7/cmake.sh | 53 -
ecflow_4_0_7/configure.sh | 69 -
ecflow_4_0_7/tools/ecf_cmd | 868 --
ecflow_4_0_7/tools/ecf_kill | 243 -
ecflow_4_0_7/tools/ecf_status | 209 -
ecflow_4_0_7/tools/ecf_submit | 868 --
ecflow_4_0_7/tools/ecflow_logsvr.pl | Bin 2674 -> 0 bytes
ecflow_4_0_7/tools/ecflow_logsvr.sh | 51 -
ecflow_4_0_7/tools/ecflow_start.sh | 283 -
ecflow_4_0_7/tools/ecflow_stop.sh | 111 -
ecflow_4_0_7/tools/noconnect.sh | 32 -
ecflow_4_0_7/view/CMakeLists.txt | 278 -
ecflow_4_0_7/view/Jamfile.jam | 117 -
ecflow_4_0_7/view/Makefile | 99 -
ecflow_4_0_7/view/install_server.sh | 29 -
ecflow_4_0_7/view/servers | 48 -
ecflow_4_0_7/view/servers.od | 8 -
ecflow_4_0_7/view/src/ArrayP.h | 60 -
ecflow_4_0_7/view/src/Hyper.c | 1589 ----
ecflow_4_0_7/view/src/Hyper.h | 119 -
ecflow_4_0_7/view/src/HyperP.h | 110 -
ecflow_4_0_7/view/src/SimpleBase.c | 1304 ---
ecflow_4_0_7/view/src/SimpleBase.h | 95 -
ecflow_4_0_7/view/src/SimpleBaseP.h | 133 -
ecflow_4_0_7/view/src/SimpleGraph.c | 1324 ---
ecflow_4_0_7/view/src/SimpleGraph.h | 42 -
ecflow_4_0_7/view/src/SimpleGraphP.h | 72 -
ecflow_4_0_7/view/src/SimpleTime.c | 784 --
ecflow_4_0_7/view/src/SimpleTime.h | 76 -
ecflow_4_0_7/view/src/SimpleTimeP.h | 74 -
ecflow_4_0_7/view/src/SimpleTree.c | 656 --
ecflow_4_0_7/view/src/SimpleTree.h | 49 -
ecflow_4_0_7/view/src/SimpleTreeP.h | 60 -
ecflow_4_0_7/view/src/Tab.c | 784 --
ecflow_4_0_7/view/src/Tab.h | 66 -
ecflow_4_0_7/view/src/TabP.h | 80 -
ecflow_4_0_7/view/src/aborted.cc | 33 -
ecflow_4_0_7/view/src/aborted.h | 109 -
ecflow_4_0_7/view/src/alerts.cc | 26 -
ecflow_4_0_7/view/src/alias.cc | 38 -
ecflow_4_0_7/view/src/arch.h | 20 -
ecflow_4_0_7/view/src/array.cc | 79 -
ecflow_4_0_7/view/src/array.h | 131 -
ecflow_4_0_7/view/src/ask.cc | 46 -
ecflow_4_0_7/view/src/ask.h | 41 -
ecflow_4_0_7/view/src/autoAlarm.h | 42 -
ecflow_4_0_7/view/src/auto_alarm.cc | 47 -
ecflow_4_0_7/view/src/auto_alarm.h | 44 -
ecflow_4_0_7/view/src/base.cc | 203 -
ecflow_4_0_7/view/src/base.h | 65 -
ecflow_4_0_7/view/src/bool.h | 25 -
ecflow_4_0_7/view/src/choice.h | 37 -
ecflow_4_0_7/view/src/collector.cc | 280 -
ecflow_4_0_7/view/src/collector.h | 100 -
ecflow_4_0_7/view/src/colors_prefs.cc | 24 -
ecflow_4_0_7/view/src/colors_prefs.h | 47 -
ecflow_4_0_7/view/src/configurable.cc | 23 -
ecflow_4_0_7/view/src/configurable.h | 38 -
ecflow_4_0_7/view/src/configurator.h | 128 -
ecflow_4_0_7/view/src/confirm.cc | 44 -
ecflow_4_0_7/view/src/confirm.h | 40 -
ecflow_4_0_7/view/src/counted.cc | 37 -
ecflow_4_0_7/view/src/counted.h | 124 -
ecflow_4_0_7/view/src/date.cc | 106 -
ecflow_4_0_7/view/src/date.h | 48 -
ecflow_4_0_7/view/src/depend.cc | 72 -
ecflow_4_0_7/view/src/depend.h | 126 -
ecflow_4_0_7/view/src/dialog.cc | 83 -
ecflow_4_0_7/view/src/dialog.h | 50 -
ecflow_4_0_7/view/src/directory.cc | 72 -
ecflow_4_0_7/view/src/directory.h | 40 -
ecflow_4_0_7/view/src/doer.sh | 29 -
ecflow_4_0_7/view/src/dummy_node.cc | 58 -
ecflow_4_0_7/view/src/dummy_node.h | 53 -
ecflow_4_0_7/view/src/ecf_node.cc | 1193 ---
ecflow_4_0_7/view/src/ecf_node.h | 582 --
ecflow_4_0_7/view/src/ecflow.cc | 289 -
ecflow_4_0_7/view/src/ecflow.h | 258 -
ecflow_4_0_7/view/src/ecflowview.cc | 165 -
ecflow_4_0_7/view/src/ecflowview.h | 53 -
ecflow_4_0_7/view/src/ecflowview.menu | 313 -
ecflow_4_0_7/view/src/ecflowview.menu.h | 317 -
ecflow_4_0_7/view/src/edit.cc | 264 -
ecflow_4_0_7/view/src/edit.h | 76 -
ecflow_4_0_7/view/src/edit_label.cc | 86 -
ecflow_4_0_7/view/src/edit_label.h | 137 -
ecflow_4_0_7/view/src/edit_limit.cc | 146 -
ecflow_4_0_7/view/src/edit_limit.h | 60 -
ecflow_4_0_7/view/src/edit_meter.cc | 91 -
ecflow_4_0_7/view/src/edit_meter.h | 137 -
ecflow_4_0_7/view/src/edit_repeat.cc | 140 -
ecflow_4_0_7/view/src/edit_repeat.h | 51 -
ecflow_4_0_7/view/src/edit_variable.cc | 70 -
ecflow_4_0_7/view/src/edit_variable.h | 58 -
ecflow_4_0_7/view/src/editor.cc | 47 -
ecflow_4_0_7/view/src/editor.h | 108 -
ecflow_4_0_7/view/src/error.cc | 38 -
ecflow_4_0_7/view/src/error.h | 106 -
ecflow_4_0_7/view/src/eval.h | 49 -
ecflow_4_0_7/view/src/event_node.cc | 75 -
ecflow_4_0_7/view/src/event_node.h | 42 -
ecflow_4_0_7/view/src/events.h | 132 -
ecflow_4_0_7/view/src/extent.h | 74 -
ecflow_4_0_7/view/src/external.cc | 64 -
ecflow_4_0_7/view/src/external.h | 53 -
ecflow_4_0_7/view/src/find.cc | 173 -
ecflow_4_0_7/view/src/find.h | 58 -
ecflow_4_0_7/view/src/flags.cc | 85 -
ecflow_4_0_7/view/src/flags.h | 117 -
ecflow_4_0_7/view/src/fonts_prefs.cc | 24 -
ecflow_4_0_7/view/src/fonts_prefs.h | 133 -
ecflow_4_0_7/view/src/fsb.cc | 91 -
ecflow_4_0_7/view/src/fsb.h | 125 -
ecflow_4_0_7/view/src/gen_translator.h | 25 -
ecflow_4_0_7/view/src/globals.cc | 92 -
ecflow_4_0_7/view/src/globals.h | 53 -
ecflow_4_0_7/view/src/graph_layout.cc | 455 -
ecflow_4_0_7/view/src/graph_layout.h | 74 -
ecflow_4_0_7/view/src/gui.cc | 377 -
ecflow_4_0_7/view/src/gui.h | 83 -
ecflow_4_0_7/view/src/history.cc | 116 -
ecflow_4_0_7/view/src/history.h | 59 -
ecflow_4_0_7/view/src/host.cc | 1791 ----
ecflow_4_0_7/view/src/host.h | 353 -
ecflow_4_0_7/view/src/host_prefs.cc | 24 -
ecflow_4_0_7/view/src/host_prefs.h | 46 -
ecflow_4_0_7/view/src/html_lister.cc | 72 -
ecflow_4_0_7/view/src/html_lister.h | 133 -
ecflow_4_0_7/view/src/http.cc | 112 -
ecflow_4_0_7/view/src/http.h | 143 -
ecflow_4_0_7/view/src/hyper_lister.cc | 73 -
ecflow_4_0_7/view/src/hyper_lister.h | 57 -
ecflow_4_0_7/view/src/icon_Josstatus3.cc | 41 -
ecflow_4_0_7/view/src/icon_W.cc | 86 -
ecflow_4_0_7/view/src/info.cc | 55 -
ecflow_4_0_7/view/src/info.h | 46 -
ecflow_4_0_7/view/src/init.cc | 36 -
ecflow_4_0_7/view/src/init.h | 127 -
ecflow_4_0_7/view/src/inlimit_node.cc | 71 -
ecflow_4_0_7/view/src/inlimit_node.h | 49 -
ecflow_4_0_7/view/src/input.cc | 67 -
ecflow_4_0_7/view/src/input.h | 127 -
ecflow_4_0_7/view/src/interface.cc | 26 -
ecflow_4_0_7/view/src/interface.h | 55 -
ecflow_4_0_7/view/src/job.cc | 61 -
ecflow_4_0_7/view/src/job.h | 65 -
ecflow_4_0_7/view/src/jobcheck_panel.cc | 92 -
ecflow_4_0_7/view/src/jobcheck_panel.h | 66 -
ecflow_4_0_7/view/src/jobstatus.cc | 109 -
ecflow_4_0_7/view/src/jobstatus.h | 71 -
ecflow_4_0_7/view/src/label.cc | 89 -
ecflow_4_0_7/view/src/label_node.h | 53 -
ecflow_4_0_7/view/src/late.cc | 32 -
ecflow_4_0_7/view/src/late.h | 109 -
ecflow_4_0_7/view/src/late_node.cc | 29 -
ecflow_4_0_7/view/src/late_node.h | 49 -
ecflow_4_0_7/view/src/layout.cc | 26 -
ecflow_4_0_7/view/src/layout.h | 134 -
ecflow_4_0_7/view/src/lexyacc.h | 70 -
ecflow_4_0_7/view/src/libicon/icon_Apply.cc | 42 -
ecflow_4_0_7/view/src/libicon/icon_Apply.xpm | 40 -
ecflow_4_0_7/view/src/libicon/icon_Chat.cc | 41 -
ecflow_4_0_7/view/src/libicon/icon_Chat.xpm | 39 -
ecflow_4_0_7/view/src/libicon/icon_Check.cc | 71 -
ecflow_4_0_7/view/src/libicon/icon_Check.xpm | 69 -
ecflow_4_0_7/view/src/libicon/icon_Edit.cc | 47 -
ecflow_4_0_7/view/src/libicon/icon_Edit.xpm | 43 -
ecflow_4_0_7/view/src/libicon/icon_Info.cc | 40 -
ecflow_4_0_7/view/src/libicon/icon_Info.xpm | 39 -
ecflow_4_0_7/view/src/libicon/icon_Jobstatus.cc | 41 -
ecflow_4_0_7/view/src/libicon/icon_Jobstatus.xpm | 39 -
ecflow_4_0_7/view/src/libicon/icon_Josstatus3.xpm | 39 -
ecflow_4_0_7/view/src/libicon/icon_Load.cc | 39 -
ecflow_4_0_7/view/src/libicon/icon_Load.xpm | 38 -
ecflow_4_0_7/view/src/libicon/icon_Manual.cc | 56 -
ecflow_4_0_7/view/src/libicon/icon_Manual.xpm | 54 -
ecflow_4_0_7/view/src/libicon/icon_Merge.cc | 40 -
ecflow_4_0_7/view/src/libicon/icon_Merge.xpm | 38 -
ecflow_4_0_7/view/src/libicon/icon_Messages.cc | 40 -
ecflow_4_0_7/view/src/libicon/icon_Messages.xpm | 41 -
ecflow_4_0_7/view/src/libicon/icon_Output.cc | 45 -
ecflow_4_0_7/view/src/libicon/icon_Output.xpm | 42 -
ecflow_4_0_7/view/src/libicon/icon_QuickFind.cc | 38 -
ecflow_4_0_7/view/src/libicon/icon_QuickFind.xpm | 36 -
ecflow_4_0_7/view/src/libicon/icon_Script.cc | 43 -
ecflow_4_0_7/view/src/libicon/icon_Script.xpm | 41 -
ecflow_4_0_7/view/src/libicon/icon_Search.cc | 49 -
ecflow_4_0_7/view/src/libicon/icon_Search.xpm | 45 -
ecflow_4_0_7/view/src/libicon/icon_Status.cc | 50 -
ecflow_4_0_7/view/src/libicon/icon_Status.xpm | 48 -
ecflow_4_0_7/view/src/libicon/icon_Submit.cc | 42 -
ecflow_4_0_7/view/src/libicon/icon_Submit.xpm | 40 -
ecflow_4_0_7/view/src/libicon/icon_Time_line.cc | 42 -
ecflow_4_0_7/view/src/libicon/icon_Time_line.xpm | 40 -
ecflow_4_0_7/view/src/libicon/icon_Triggers.cc | 39 -
ecflow_4_0_7/view/src/libicon/icon_Triggers.xpm | 37 -
ecflow_4_0_7/view/src/libicon/icon_Update.cc | 50 -
ecflow_4_0_7/view/src/libicon/icon_Update.xpm | 48 -
.../view/src/libicon/icon_Use_external_editor.cc | 43 -
.../view/src/libicon/icon_Use_external_editor.xpm | 43 -
.../view/src/libicon/icon_Use_external_viewer.cc | 42 -
.../view/src/libicon/icon_Use_external_viewer.xpm | 40 -
ecflow_4_0_7/view/src/libicon/icon_Variables.cc | 38 -
ecflow_4_0_7/view/src/libicon/icon_Variables.xpm | 36 -
ecflow_4_0_7/view/src/libicon/icon_W.xpm | 84 -
ecflow_4_0_7/view/src/libicon/icon_Why_.cc | 42 -
ecflow_4_0_7/view/src/libicon/icon_Z.cc | 86 -
ecflow_4_0_7/view/src/libicon/icon_calendar.cc | 40 -
ecflow_4_0_7/view/src/libicon/icon_calendar.xpm | 38 -
ecflow_4_0_7/view/src/libicon/icon_clock.cc | 42 -
ecflow_4_0_7/view/src/libicon/icon_clock.xpm | 40 -
ecflow_4_0_7/view/src/libicon/icon_clock_free.cc | 42 -
ecflow_4_0_7/view/src/libicon/icon_complete.cc | 65 -
ecflow_4_0_7/view/src/libicon/icon_complete.xpm | 57 -
ecflow_4_0_7/view/src/libicon/icon_defstatus.cc | 164 -
ecflow_4_0_7/view/src/libicon/icon_defstatus.xpm | 162 -
ecflow_4_0_7/view/src/libicon/icon_folded.cc | 39 -
ecflow_4_0_7/view/src/libicon/icon_folded.xpm | 37 -
ecflow_4_0_7/view/src/libicon/icon_late.cc | 39 -
ecflow_4_0_7/view/src/libicon/icon_late.xpm | 37 -
ecflow_4_0_7/view/src/libicon/icon_limit0.cc | 32 -
ecflow_4_0_7/view/src/libicon/icon_limit0.xpm | 30 -
ecflow_4_0_7/view/src/libicon/icon_limit1.cc | 34 -
ecflow_4_0_7/view/src/libicon/icon_limit1.xpm | 32 -
ecflow_4_0_7/view/src/libicon/icon_limit2.cc | 34 -
ecflow_4_0_7/view/src/libicon/icon_limit2.xpm | 32 -
ecflow_4_0_7/view/src/libicon/icon_locked.cc | 40 -
ecflow_4_0_7/view/src/libicon/icon_locked.xpm | 38 -
ecflow_4_0_7/view/src/libicon/icon_memo.cc | 15 -
ecflow_4_0_7/view/src/libicon/icon_memo.xpm | 67 -
ecflow_4_0_7/view/src/libicon/icon_message.cc | 40 -
ecflow_4_0_7/view/src/libicon/icon_message.xpm | 41 -
ecflow_4_0_7/view/src/libicon/icon_migrated.cc | 40 -
ecflow_4_0_7/view/src/libicon/icon_migrated.xpm | 37 -
ecflow_4_0_7/view/src/libicon/icon_noway.cc | 65 -
ecflow_4_0_7/view/src/libicon/icon_noway.xpm | 63 -
ecflow_4_0_7/view/src/libicon/icon_rerun.cc | 39 -
ecflow_4_0_7/view/src/libicon/icon_rerun.xpm | 37 -
ecflow_4_0_7/view/src/libicon/icon_waiting.cc | 38 -
ecflow_4_0_7/view/src/libicon/icon_waiting.xpm | 36 -
ecflow_4_0_7/view/src/libui/uiask.cc | 84 -
ecflow_4_0_7/view/src/libui/uiconfirm.cc | 79 -
ecflow_4_0_7/view/src/libui/uiedit_label.cc | 139 -
ecflow_4_0_7/view/src/libui/uierror.cc | 72 -
ecflow_4_0_7/view/src/libui/uifsb.cc | 80 -
ecflow_4_0_7/view/src/libui/uijobstatus.cc | 150 -
ecflow_4_0_7/view/src/libui/uijobstatus.h | 48 -
ecflow_4_0_7/view/src/libui/uimenu.cc | 229 -
ecflow_4_0_7/view/src/libui/uitop.cc | 1053 ---
ecflow_4_0_7/view/src/libxec/xec_Cursor.c | 52 -
ecflow_4_0_7/view/src/libxec/xec_Label.c | 42 -
ecflow_4_0_7/view/src/libxec/xec_List.c | 276 -
ecflow_4_0_7/view/src/libxec/xec_Regexp.c | 91 -
ecflow_4_0_7/view/src/libxec/xec_Strings.c | 134 -
ecflow_4_0_7/view/src/libxec/xec_Text.c | 551 --
ecflow_4_0_7/view/src/libxec/xec_Toggle.c | 41 -
ecflow_4_0_7/view/src/libxec/xec_Widget.c | 215 -
ecflow_4_0_7/view/src/limit_node.cc | 459 -
ecflow_4_0_7/view/src/limit_node.h | 74 -
ecflow_4_0_7/view/src/line.c | 42 -
ecflow_4_0_7/view/src/lister.cc | 65 -
ecflow_4_0_7/view/src/lister.h | 42 -
ecflow_4_0_7/view/src/log_event.cc | 355 -
ecflow_4_0_7/view/src/log_event.h | 132 -
ecflow_4_0_7/view/src/log_file.h | 129 -
ecflow_4_0_7/view/src/logsvr.cc | 246 -
ecflow_4_0_7/view/src/logsvr.h | 54 -
ecflow_4_0_7/view/src/mail.cc | 246 -
ecflow_4_0_7/view/src/mail.h | 67 -
ecflow_4_0_7/view/src/manual.cc | 53 -
ecflow_4_0_7/view/src/manual.h | 66 -
ecflow_4_0_7/view/src/menu2c.sh | 16 -
ecflow_4_0_7/view/src/menu_prefs.cc | 75 -
ecflow_4_0_7/view/src/menu_prefs.h | 60 -
ecflow_4_0_7/view/src/menul.c | 3230 -------
ecflow_4_0_7/view/src/menul.l | 230 -
ecflow_4_0_7/view/src/menus.cc | 796 --
ecflow_4_0_7/view/src/menus.h | 73 -
ecflow_4_0_7/view/src/menuy.c | 2428 -----
ecflow_4_0_7/view/src/menuy.y | 328 -
ecflow_4_0_7/view/src/messages.cc | 78 -
ecflow_4_0_7/view/src/messages.h | 68 -
ecflow_4_0_7/view/src/meter_node.cc | 160 -
ecflow_4_0_7/view/src/meter_node.h | 59 -
ecflow_4_0_7/view/src/node.cc | 1086 ---
ecflow_4_0_7/view/src/node.h | 350 -
ecflow_4_0_7/view/src/node_alert.cc | 112 -
ecflow_4_0_7/view/src/node_alert.h | 76 -
ecflow_4_0_7/view/src/node_editor.cc | 66 -
ecflow_4_0_7/view/src/node_editor.h | 134 -
ecflow_4_0_7/view/src/node_list.cc | 129 -
ecflow_4_0_7/view/src/node_list.h | 62 -
ecflow_4_0_7/view/src/node_lister.h | 41 -
ecflow_4_0_7/view/src/node_window.cc | 253 -
ecflow_4_0_7/view/src/node_window.h | 73 -
ecflow_4_0_7/view/src/not_enqueued.cc | 32 -
ecflow_4_0_7/view/src/not_enqueued.h | 45 -
ecflow_4_0_7/view/src/observable.cc | 79 -
ecflow_4_0_7/view/src/observable.h | 45 -
ecflow_4_0_7/view/src/observer.cc | 48 -
ecflow_4_0_7/view/src/observer.h | 48 -
ecflow_4_0_7/view/src/opener.h | 126 -
ecflow_4_0_7/view/src/option.cc | 205 -
ecflow_4_0_7/view/src/option.h | 48 -
ecflow_4_0_7/view/src/option_panel.cc | 60 -
ecflow_4_0_7/view/src/option_panel.h | 58 -
ecflow_4_0_7/view/src/output.cc | 221 -
ecflow_4_0_7/view/src/output.h | 67 -
ecflow_4_0_7/view/src/panel.cc | 125 -
ecflow_4_0_7/view/src/panel.h | 110 -
ecflow_4_0_7/view/src/panel_factories.h | 40 -
ecflow_4_0_7/view/src/panel_window.cc | 432 -
ecflow_4_0_7/view/src/panel_window.h | 118 -
ecflow_4_0_7/view/src/parser.cc | 101 -
ecflow_4_0_7/view/src/parser.h | 125 -
ecflow_4_0_7/view/src/passwrd.cc | 71 -
ecflow_4_0_7/view/src/passwrd.h | 116 -
ecflow_4_0_7/view/src/persist.cc | 149 -
ecflow_4_0_7/view/src/persist.h | 139 -
ecflow_4_0_7/view/src/pixmap.cc | 103 -
ecflow_4_0_7/view/src/pixmap.h | 53 -
ecflow_4_0_7/view/src/pref_editor.cc | 87 -
ecflow_4_0_7/view/src/pref_editor.h | 55 -
ecflow_4_0_7/view/src/pref_window.cc | 54 -
ecflow_4_0_7/view/src/pref_window.h | 51 -
ecflow_4_0_7/view/src/prefs.cc | 41 -
ecflow_4_0_7/view/src/prefs.h | 126 -
ecflow_4_0_7/view/src/re.h | 54 -
ecflow_4_0_7/view/src/reach.cc | 255 -
ecflow_4_0_7/view/src/reach.h | 48 -
ecflow_4_0_7/view/src/relation.cc | 186 -
ecflow_4_0_7/view/src/relation.h | 74 -
ecflow_4_0_7/view/src/repeat.h | 151 -
ecflow_4_0_7/view/src/repeat_node.cc | 308 -
ecflow_4_0_7/view/src/repeat_node.h | 66 -
ecflow_4_0_7/view/src/resource.cc | 112 -
ecflow_4_0_7/view/src/resource.h | 71 -
ecflow_4_0_7/view/src/restart.cc | 32 -
ecflow_4_0_7/view/src/restart.h | 109 -
ecflow_4_0_7/view/src/result.cc | 32 -
ecflow_4_0_7/view/src/result.h | 38 -
ecflow_4_0_7/view/src/runnable.cc | 64 -
ecflow_4_0_7/view/src/runnable.h | 49 -
ecflow_4_0_7/view/src/script_panel.cc | 61 -
ecflow_4_0_7/view/src/script_panel.h | 64 -
ecflow_4_0_7/view/src/scripting.cc | 390 -
ecflow_4_0_7/view/src/scripting.h | 49 -
ecflow_4_0_7/view/src/search.cc | 288 -
ecflow_4_0_7/view/src/search.h | 82 -
ecflow_4_0_7/view/src/searchable.cc | 151 -
ecflow_4_0_7/view/src/searchable.h | 61 -
ecflow_4_0_7/view/src/selection.cc | 153 -
ecflow_4_0_7/view/src/selection.h | 56 -
ecflow_4_0_7/view/src/server.cc | 179 -
ecflow_4_0_7/view/src/server.h | 40 -
ecflow_4_0_7/view/src/servers_prefs.cc | 259 -
ecflow_4_0_7/view/src/servers_prefs.h | 79 -
ecflow_4_0_7/view/src/show.cc | 93 -
ecflow_4_0_7/view/src/show.h | 104 -
ecflow_4_0_7/view/src/simple_node.cc | 1062 ---
ecflow_4_0_7/view/src/simple_node.h | 158 -
ecflow_4_0_7/view/src/singleton.h | 32 -
ecflow_4_0_7/view/src/str.cc | 99 -
ecflow_4_0_7/view/src/str.h | 59 -
ecflow_4_0_7/view/src/substitute.cc | 139 -
ecflow_4_0_7/view/src/substitute.h | 55 -
ecflow_4_0_7/view/src/suites_panel.cc | 146 -
ecflow_4_0_7/view/src/suites_panel.h | 54 -
ecflow_4_0_7/view/src/super_node.cc | 96 -
ecflow_4_0_7/view/src/super_node.h | 72 -
ecflow_4_0_7/view/src/task_node.cc | 281 -
ecflow_4_0_7/view/src/task_node.h | 58 -
ecflow_4_0_7/view/src/text_layout.cc | 123 -
ecflow_4_0_7/view/src/text_layout.h | 143 -
ecflow_4_0_7/view/src/text_lister.h | 79 -
ecflow_4_0_7/view/src/text_window.cc | 194 -
ecflow_4_0_7/view/src/text_window.h | 65 -
ecflow_4_0_7/view/src/time.cc | 163 -
ecflow_4_0_7/view/src/time_node.h | 49 -
ecflow_4_0_7/view/src/timeout.cc | 86 -
ecflow_4_0_7/view/src/timeout.h | 53 -
ecflow_4_0_7/view/src/timetable_panel.cc | 731 --
ecflow_4_0_7/view/src/timetable_panel.h | 123 -
ecflow_4_0_7/view/src/tip.cc | 114 -
ecflow_4_0_7/view/src/tip.h | 52 -
ecflow_4_0_7/view/src/tmp_file.cc | 109 -
ecflow_4_0_7/view/src/tmp_file.h | 83 -
ecflow_4_0_7/view/src/tmpnam.c | 63 -
ecflow_4_0_7/view/src/to_check.h | 40 -
ecflow_4_0_7/view/src/top.cc | 512 --
ecflow_4_0_7/view/src/top.h | 72 -
ecflow_4_0_7/view/src/translator.cc | 211 -
ecflow_4_0_7/view/src/translator.h | 114 -
ecflow_4_0_7/view/src/tree.cc | 340 -
ecflow_4_0_7/view/src/tree.h | 105 -
ecflow_4_0_7/view/src/trigger_lister.h | 41 -
ecflow_4_0_7/view/src/trigger_node.cc | 274 -
ecflow_4_0_7/view/src/trigger_node.h | 59 -
ecflow_4_0_7/view/src/trigger_panel.cc | 160 -
ecflow_4_0_7/view/src/trigger_panel.h | 85 -
ecflow_4_0_7/view/src/url.cc | 240 -
ecflow_4_0_7/view/src/url.h | 142 -
ecflow_4_0_7/view/src/user_prefs.cc | 24 -
ecflow_4_0_7/view/src/user_prefs.h | 49 -
ecflow_4_0_7/view/src/users.cc | 62 -
ecflow_4_0_7/view/src/users.h | 136 -
ecflow_4_0_7/view/src/variable_node.cc | 135 -
ecflow_4_0_7/view/src/variable_node.h | 54 -
ecflow_4_0_7/view/src/variables.cc | 417 -
ecflow_4_0_7/view/src/variables.h | 58 -
ecflow_4_0_7/view/src/viewer.cc | 57 -
ecflow_4_0_7/view/src/viewer.h | 134 -
ecflow_4_0_7/view/src/why.cc | 64 -
ecflow_4_0_7/view/src/why.h | 49 -
ecflow_4_0_7/view/src/window.cc | 59 -
ecflow_4_0_7/view/src/window.h | 44 -
ecflow_4_0_7/view/src/x.c | 19 -
ecflow_4_0_7/view/src/xcdp.menu | 257 -
ecflow_4_0_7/view/src/xcdp.menu.h | 258 -
ecflow_4_0_7/view/src/xdclass.h | 225 -
ecflow_4_0_7/view/src/xdxmdialog.cc | 66 -
ecflow_4_0_7/view/src/xdxtclass.cc | 223 -
ecflow_4_0_7/view/src/xec.h | 24 -
ecflow_4_0_7/view/src/xecp.h | 75 -
ecflow_4_0_7/view/src/xmstring.cc | 107 -
ecflow_4_0_7/view/src/xmstring.h | 128 -
ecflow_4_0_7/view/src/xnode.cc | 56 -
ecflow_4_0_7/view/src/xnode.h | 85 -
ecflow_4_0_7/view/src/xresources.h | 628 --
ecflow_4_0_7/view/src/zombie.h | 39 -
ecflow_4_0_7/view/src/zombies_panel.cc | 125 -
ecflow_4_0_7/view/src/zombies_panel.h | 62 -
ecflow_4_0_7/view/test/TestRunner.cpp | 21 -
ecflow_4_0_7/view/test/TestView.cpp | 126 -
ecflow_4_0_7/view/test/ViewTestFixture.hpp | 33 -
install.sh | 59 +
.../project_summary.cmake => project_summary.cmake | 0
share/CMakeLists.txt | 3 +
share/ecbuild/toolchains/ecmwf-XC30-Cray.cmake | 56 +
share/ecbuild/toolchains/ecmwf-XC30-GNU.cmake | 52 +
share/ecbuild/toolchains/ecmwf-XC30-Intel.cmake | 73 +
share/ecflow/etc/CMakeLists.txt | 27 +
share/ecflow/etc/ecflowview_attribute_conf.json | 51 +
share/ecflow/etc/ecflowview_gui.json | 462 +
share/ecflow/etc/ecflowview_gui_server.json | 74 +
share/ecflow/etc/ecflowview_highlighter.json | 251 +
share/ecflow/etc/ecflowview_icon_conf.json | 80 +
share/ecflow/etc/ecflowview_menus.json | 720 ++
share/ecflow/etc/ecflowview_notification_conf.json | 297 +
share/ecflow/etc/ecflowview_nstate_conf.json | 123 +
share/ecflow/etc/ecflowview_palette.json | 54 +
share/ecflow/etc/ecflowview_panel_conf.json | 68 +
share/ecflow/etc/ecflowview_panels.json | 152 +
share/ecflow/etc/ecflowview_server_conf.json | 160 +
share/ecflow/etc/ecflowview_sstate_conf.json | 57 +
share/ecflow/etc/ecflowview_view_conf.json | 233 +
share/ecflow/etc/sounds/CMakeLists.txt | 13 +
share/ecflow/etc/sounds/tone.ogg | Bin 0 -> 14686 bytes
share/ecflow/etc/viewer.qss | 370 +
tools/ecf_cmd | 859 ++
tools/ecflow_fuse.py | 591 ++
tools/ecflow_load.sh | 55 +
tools/ecflow_logsvr.pl | Bin 0 -> 2981 bytes
tools/ecflow_logsvr.sh | 57 +
tools/ecflow_show_load.sh | 87 +
tools/ecflow_start.sh | 238 +
tools/ecflow_stop.sh | 114 +
tools/ecflow_suite_gen.sh | 159 +
tools/noconnect.sh | 32 +
ecflow_4_0_7/version.sh => version.sh | 0
view/CMakeLists.txt | 264 +
view/Jamfile.jam | 118 +
{ecflow_4_0_7/view => view}/data/includes/head.h | 0
{ecflow_4_0_7/view => view}/data/includes/tail.h | 0
view/servers | 9 +
view/src/ArrayP.h | 60 +
view/src/Hyper.c | 1585 ++++
view/src/Hyper.h | 119 +
view/src/HyperP.h | 110 +
view/src/SimpleBase.c | 1296 +++
view/src/SimpleBase.h | 95 +
view/src/SimpleBaseP.h | 133 +
view/src/SimpleGraph.c | 1313 +++
view/src/SimpleGraph.h | 42 +
view/src/SimpleGraphP.h | 72 +
view/src/SimpleTime.c | 767 ++
view/src/SimpleTime.h | 76 +
view/src/SimpleTimeP.h | 74 +
view/src/SimpleTree.c | 656 ++
view/src/SimpleTree.h | 49 +
view/src/SimpleTreeP.h | 60 +
view/src/Tab.c | 784 ++
view/src/Tab.h | 66 +
view/src/TabP.h | 80 +
view/src/aborted.cc | 33 +
view/src/aborted.h | 109 +
view/src/alerts.cc | 26 +
view/src/alias.cc | 38 +
view/src/arch.h | 20 +
view/src/array.cc | 79 +
view/src/array.h | 131 +
view/src/ask.cc | 46 +
view/src/ask.h | 41 +
view/src/autoAlarm.h | 42 +
view/src/auto_alarm.cc | 47 +
view/src/auto_alarm.h | 44 +
view/src/base.cc | 203 +
view/src/base.h | 65 +
view/src/bool.h | 25 +
{ecflow_4_0_7/view => view}/src/cdp.cmd | 0
view/src/choice.h | 37 +
view/src/collector.cc | 282 +
view/src/collector.h | 100 +
view/src/colors_prefs.cc | 24 +
view/src/colors_prefs.h | 47 +
view/src/configurable.cc | 23 +
view/src/configurable.h | 38 +
view/src/configurator.h | 128 +
view/src/confirm.cc | 44 +
view/src/confirm.h | 40 +
view/src/counted.cc | 37 +
view/src/counted.h | 124 +
view/src/date.cc | 106 +
view/src/date.h | 48 +
view/src/depend.cc | 72 +
view/src/depend.h | 126 +
view/src/dialog.cc | 83 +
view/src/dialog.h | 50 +
view/src/directory.cc | 72 +
view/src/directory.h | 40 +
view/src/doer.sh | 29 +
view/src/dummy_node.cc | 58 +
view/src/dummy_node.h | 53 +
{ecflow_4_0_7/view => view}/src/ecf.cmd | 0
view/src/ecf_node.cc | 1497 ++++
view/src/ecf_node.h | 582 ++
view/src/ecflow.cc | 297 +
view/src/ecflow.h | 258 +
view/src/ecflowview.cc | 165 +
view/src/ecflowview.h | 53 +
view/src/ecflowview.menu | 350 +
view/src/ecflowview.menu.h | 351 +
view/src/edit.cc | 265 +
view/src/edit.h | 76 +
view/src/edit_label.cc | 86 +
view/src/edit_label.h | 137 +
view/src/edit_limit.cc | 146 +
view/src/edit_limit.h | 60 +
view/src/edit_meter.cc | 91 +
view/src/edit_meter.h | 137 +
view/src/edit_repeat.cc | 140 +
view/src/edit_repeat.h | 51 +
view/src/edit_variable.cc | 70 +
view/src/edit_variable.h | 58 +
view/src/editor.cc | 47 +
view/src/editor.h | 108 +
view/src/error.cc | 38 +
view/src/error.h | 106 +
view/src/eval.h | 49 +
view/src/event_node.cc | 75 +
view/src/event_node.h | 42 +
view/src/events.h | 132 +
view/src/extent.h | 74 +
view/src/external.cc | 64 +
view/src/external.h | 53 +
view/src/find.cc | 173 +
view/src/find.h | 58 +
view/src/flags.cc | 85 +
view/src/flags.h | 117 +
view/src/fonts_prefs.cc | 24 +
view/src/fonts_prefs.h | 133 +
view/src/fsb.cc | 91 +
view/src/fsb.h | 125 +
{ecflow_4_0_7/view => view}/src/gen.sh | 0
view/src/gen_translator.h | 25 +
view/src/globals.cc | 92 +
view/src/globals.h | 53 +
view/src/graph_layout.cc | 455 +
view/src/graph_layout.h | 74 +
view/src/gui.cc | 377 +
view/src/gui.h | 83 +
view/src/history.cc | 116 +
view/src/history.h | 59 +
view/src/host.cc | 1892 ++++
view/src/host.h | 354 +
view/src/host_prefs.cc | 24 +
view/src/host_prefs.h | 46 +
view/src/html_lister.cc | 72 +
view/src/html_lister.h | 133 +
view/src/http.cc | 112 +
view/src/http.h | 143 +
view/src/hyper_lister.cc | 73 +
view/src/hyper_lister.h | 57 +
view/src/icon_Josstatus3.cc | 41 +
view/src/icon_W.cc | 86 +
{ecflow_4_0_7/view => view}/src/icon_byrule.cc | 0
{ecflow_4_0_7/view => view}/src/icon_cmd_failed.cc | 0
.../view => view}/src/icon_edit_failed.cc | 0
.../view => view}/src/icon_force_abort.cc | 0
{ecflow_4_0_7/view => view}/src/icon_killed.cc | 0
{ecflow_4_0_7/view => view}/src/icon_no_script.cc | 0
{ecflow_4_0_7/view => view}/src/icon_queuelimit.cc | 0
.../view => view}/src/icon_task_aborted.cc | 0
{ecflow_4_0_7/view => view}/src/icon_user_edit.cc | 0
view/src/info.cc | 55 +
view/src/info.h | 46 +
view/src/init.cc | 36 +
view/src/init.h | 127 +
view/src/inlimit_node.cc | 71 +
view/src/inlimit_node.h | 49 +
view/src/input.cc | 67 +
view/src/input.h | 127 +
view/src/interface.cc | 26 +
view/src/interface.h | 55 +
view/src/job.cc | 61 +
view/src/job.h | 65 +
view/src/jobcheck_panel.cc | 93 +
view/src/jobcheck_panel.h | 66 +
view/src/jobstatus.cc | 109 +
view/src/jobstatus.h | 71 +
view/src/label.cc | 94 +
view/src/label_node.h | 53 +
view/src/late.cc | 32 +
view/src/late.h | 109 +
view/src/late_node.cc | 29 +
view/src/late_node.h | 49 +
view/src/layout.cc | 26 +
view/src/layout.h | 134 +
view/src/lexyacc.h | 70 +
view/src/libicon/icon_Apply.cc | 42 +
view/src/libicon/icon_Apply.xpm | 40 +
view/src/libicon/icon_Chat.cc | 41 +
view/src/libicon/icon_Chat.xpm | 39 +
view/src/libicon/icon_Check.cc | 71 +
view/src/libicon/icon_Check.xpm | 69 +
view/src/libicon/icon_Edit.cc | 47 +
view/src/libicon/icon_Edit.xpm | 43 +
view/src/libicon/icon_Info.cc | 40 +
view/src/libicon/icon_Info.xpm | 39 +
view/src/libicon/icon_Jobstatus.cc | 41 +
view/src/libicon/icon_Jobstatus.xpm | 39 +
view/src/libicon/icon_Josstatus3.xpm | 39 +
view/src/libicon/icon_Load.cc | 39 +
view/src/libicon/icon_Load.xpm | 38 +
view/src/libicon/icon_Manual.cc | 56 +
view/src/libicon/icon_Manual.xpm | 54 +
view/src/libicon/icon_Merge.cc | 40 +
view/src/libicon/icon_Merge.xpm | 38 +
view/src/libicon/icon_Messages.cc | 40 +
view/src/libicon/icon_Messages.xpm | 41 +
view/src/libicon/icon_Output.cc | 45 +
view/src/libicon/icon_Output.xpm | 42 +
view/src/libicon/icon_QuickFind.cc | 38 +
view/src/libicon/icon_QuickFind.xpm | 36 +
view/src/libicon/icon_Script.cc | 43 +
view/src/libicon/icon_Script.xpm | 41 +
view/src/libicon/icon_Search.cc | 49 +
view/src/libicon/icon_Search.xpm | 45 +
view/src/libicon/icon_Status.cc | 50 +
view/src/libicon/icon_Status.xpm | 48 +
view/src/libicon/icon_Submit.cc | 42 +
view/src/libicon/icon_Submit.xpm | 40 +
view/src/libicon/icon_Time_line.cc | 42 +
view/src/libicon/icon_Time_line.xpm | 40 +
view/src/libicon/icon_Triggers.cc | 39 +
view/src/libicon/icon_Triggers.xpm | 37 +
view/src/libicon/icon_Update.cc | 50 +
view/src/libicon/icon_Update.xpm | 48 +
view/src/libicon/icon_Use_external_editor.cc | 43 +
view/src/libicon/icon_Use_external_editor.xpm | 43 +
view/src/libicon/icon_Use_external_viewer.cc | 42 +
view/src/libicon/icon_Use_external_viewer.xpm | 40 +
view/src/libicon/icon_Variables.cc | 38 +
view/src/libicon/icon_Variables.xpm | 36 +
view/src/libicon/icon_W.xpm | 84 +
view/src/libicon/icon_Why_.cc | 42 +
.../view => view}/src/libicon/icon_Why_.xpm | 0
view/src/libicon/icon_Z.cc | 86 +
{ecflow_4_0_7/view => view}/src/libicon/icon_Z.xpm | 0
.../view => view}/src/libicon/icon_Zbw.cc | 0
.../view => view}/src/libicon/icon_Zbw.xpm | 0
view/src/libicon/icon_calendar.cc | 40 +
view/src/libicon/icon_calendar.xpm | 38 +
view/src/libicon/icon_clock.cc | 42 +
view/src/libicon/icon_clock.xpm | 40 +
view/src/libicon/icon_clock_free.cc | 42 +
view/src/libicon/icon_complete.cc | 65 +
view/src/libicon/icon_complete.xpm | 57 +
view/src/libicon/icon_defstatus.cc | 164 +
view/src/libicon/icon_defstatus.xpm | 162 +
view/src/libicon/icon_folded.cc | 39 +
view/src/libicon/icon_folded.xpm | 37 +
view/src/libicon/icon_late.cc | 39 +
view/src/libicon/icon_late.xpm | 37 +
view/src/libicon/icon_limit0.cc | 32 +
view/src/libicon/icon_limit0.xpm | 30 +
view/src/libicon/icon_limit1.cc | 34 +
view/src/libicon/icon_limit1.xpm | 32 +
view/src/libicon/icon_limit2.cc | 34 +
view/src/libicon/icon_limit2.xpm | 32 +
view/src/libicon/icon_locked.cc | 40 +
view/src/libicon/icon_locked.xpm | 38 +
view/src/libicon/icon_memo.cc | 15 +
view/src/libicon/icon_memo.xpm | 67 +
view/src/libicon/icon_message.cc | 40 +
view/src/libicon/icon_message.xpm | 41 +
view/src/libicon/icon_migrated.cc | 40 +
view/src/libicon/icon_migrated.xpm | 37 +
view/src/libicon/icon_noway.cc | 65 +
view/src/libicon/icon_noway.xpm | 63 +
view/src/libicon/icon_rerun.cc | 39 +
view/src/libicon/icon_rerun.xpm | 37 +
view/src/libicon/icon_waiting.cc | 38 +
view/src/libicon/icon_waiting.xpm | 36 +
{ecflow_4_0_7/view => view}/src/libicon/xpm2cc | 0
view/src/libui/uiask.cc | 86 +
{ecflow_4_0_7/view => view}/src/libui/uiask.h | 0
.../view => view}/src/libui/uicollector.cc | 0
.../view => view}/src/libui/uicollector.h | 0
{ecflow_4_0_7/view => view}/src/libui/uicolors.cc | 0
{ecflow_4_0_7/view => view}/src/libui/uicolors.h | 0
view/src/libui/uiconfirm.cc | 81 +
{ecflow_4_0_7/view => view}/src/libui/uiconfirm.h | 0
{ecflow_4_0_7/view => view}/src/libui/uidepend.cc | 0
{ecflow_4_0_7/view => view}/src/libui/uidepend.h | 0
{ecflow_4_0_7/view => view}/src/libui/uiedit.cc | 0
{ecflow_4_0_7/view => view}/src/libui/uiedit.h | 0
view/src/libui/uiedit_label.cc | 141 +
.../view => view}/src/libui/uiedit_label.h | 0
.../view => view}/src/libui/uiedit_limit.cc | 0
.../view => view}/src/libui/uiedit_limit.h | 0
.../view => view}/src/libui/uiedit_meter.cc | 0
.../view => view}/src/libui/uiedit_meter.h | 0
.../view => view}/src/libui/uiedit_repeat.cc | 0
.../view => view}/src/libui/uiedit_repeat.h | 0
.../view => view}/src/libui/uiedit_variable.cc | 0
.../view => view}/src/libui/uiedit_variable.h | 0
view/src/libui/uierror.cc | 73 +
{ecflow_4_0_7/view => view}/src/libui/uierror.h | 0
{ecflow_4_0_7/view => view}/src/libui/uifind.cc | 0
{ecflow_4_0_7/view => view}/src/libui/uifind.h | 0
{ecflow_4_0_7/view => view}/src/libui/uifonts.cc | 0
{ecflow_4_0_7/view => view}/src/libui/uifonts.h | 0
view/src/libui/uifsb.cc | 80 +
{ecflow_4_0_7/view => view}/src/libui/uifsb.h | 0
{ecflow_4_0_7/view => view}/src/libui/uihistory.cc | 0
{ecflow_4_0_7/view => view}/src/libui/uihistory.h | 0
{ecflow_4_0_7/view => view}/src/libui/uiinfo.cc | 0
{ecflow_4_0_7/view => view}/src/libui/uiinfo.h | 0
{ecflow_4_0_7/view => view}/src/libui/uijob.cc | 0
{ecflow_4_0_7/view => view}/src/libui/uijob.h | 0
.../view => view}/src/libui/uijobcheck.cc | 0
{ecflow_4_0_7/view => view}/src/libui/uijobcheck.h | 0
view/src/libui/uijobstatus.cc | 150 +
view/src/libui/uijobstatus.h | 48 +
{ecflow_4_0_7/view => view}/src/libui/uimail.cc | 0
{ecflow_4_0_7/view => view}/src/libui/uimail.h | 0
{ecflow_4_0_7/view => view}/src/libui/uimanual.cc | 0
{ecflow_4_0_7/view => view}/src/libui/uimanual.h | 0
view/src/libui/uimenu.cc | 229 +
{ecflow_4_0_7/view => view}/src/libui/uimenu.h | 0
.../view => view}/src/libui/uimessages.cc | 0
{ecflow_4_0_7/view => view}/src/libui/uimessages.h | 0
.../view => view}/src/libui/uinode_alert.cc | 0
.../view => view}/src/libui/uinode_alert.h | 0
{ecflow_4_0_7/view => view}/src/libui/uioption.cc | 0
{ecflow_4_0_7/view => view}/src/libui/uioption.h | 0
{ecflow_4_0_7/view => view}/src/libui/uioutput.cc | 0
{ecflow_4_0_7/view => view}/src/libui/uioutput.h | 0
{ecflow_4_0_7/view => view}/src/libui/uipanel.cc | 0
{ecflow_4_0_7/view => view}/src/libui/uipanel.h | 0
{ecflow_4_0_7/view => view}/src/libui/uipasswd.cc | 0
{ecflow_4_0_7/view => view}/src/libui/uipasswd.h | 0
{ecflow_4_0_7/view => view}/src/libui/uipref.cc | 0
{ecflow_4_0_7/view => view}/src/libui/uipref.h | 0
{ecflow_4_0_7/view => view}/src/libui/uiscript.cc | 0
{ecflow_4_0_7/view => view}/src/libui/uiscript.h | 0
{ecflow_4_0_7/view => view}/src/libui/uisearch.cc | 0
{ecflow_4_0_7/view => view}/src/libui/uisearch.h | 0
{ecflow_4_0_7/view => view}/src/libui/uiservers.cc | 0
{ecflow_4_0_7/view => view}/src/libui/uiservers.h | 0
{ecflow_4_0_7/view => view}/src/libui/uisuites.cc | 0
{ecflow_4_0_7/view => view}/src/libui/uisuites.h | 0
.../view => view}/src/libui/uitimetable.cc | 0
.../view => view}/src/libui/uitimetable.h | 0
{ecflow_4_0_7/view => view}/src/libui/uitip.cc | 0
{ecflow_4_0_7/view => view}/src/libui/uitip.h | 0
view/src/libui/uitop.cc | 1056 +++
{ecflow_4_0_7/view => view}/src/libui/uitop.h | 0
{ecflow_4_0_7/view => view}/src/libui/uitree.cc | 0
{ecflow_4_0_7/view => view}/src/libui/uitree.h | 0
.../view => view}/src/libui/uitriggers.cc | 0
{ecflow_4_0_7/view => view}/src/libui/uitriggers.h | 0
{ecflow_4_0_7/view => view}/src/libui/uiuser.cc | 0
{ecflow_4_0_7/view => view}/src/libui/uiuser.h | 0
{ecflow_4_0_7/view => view}/src/libui/uiusers.cc | 0
{ecflow_4_0_7/view => view}/src/libui/uiusers.h | 0
.../view => view}/src/libui/uivariables.cc | 0
.../view => view}/src/libui/uivariables.h | 0
{ecflow_4_0_7/view => view}/src/libui/uiwhy.cc | 0
{ecflow_4_0_7/view => view}/src/libui/uiwhy.h | 0
{ecflow_4_0_7/view => view}/src/libui/uizombies.cc | 0
{ecflow_4_0_7/view => view}/src/libui/uizombies.h | 0
view/src/libxec/xec_Cursor.c | 52 +
view/src/libxec/xec_Label.c | 42 +
view/src/libxec/xec_List.c | 276 +
view/src/libxec/xec_Regexp.c | 91 +
view/src/libxec/xec_Strings.c | 134 +
view/src/libxec/xec_Text.c | 547 ++
view/src/libxec/xec_Toggle.c | 41 +
view/src/libxec/xec_Widget.c | 215 +
view/src/limit_node.cc | 459 +
view/src/limit_node.h | 74 +
view/src/line.c | 42 +
view/src/lister.cc | 65 +
view/src/lister.h | 42 +
view/src/log_event.cc | 355 +
view/src/log_event.h | 132 +
view/src/log_file.h | 129 +
view/src/logsvr.cc | 244 +
view/src/logsvr.h | 54 +
view/src/mail.cc | 246 +
view/src/mail.h | 67 +
view/src/manual.cc | 53 +
view/src/manual.h | 66 +
view/src/menu2c.sh | 16 +
view/src/menu_prefs.cc | 75 +
view/src/menu_prefs.h | 60 +
view/src/menul.c | 3227 +++++++
view/src/menul.l | 230 +
view/src/menus.cc | 796 ++
view/src/menus.h | 73 +
view/src/menuy.c | 2380 +++++
view/src/menuy.y | 328 +
view/src/messages.cc | 78 +
view/src/messages.h | 68 +
view/src/meter_node.cc | 160 +
view/src/meter_node.h | 59 +
view/src/node.cc | 1089 +++
view/src/node.h | 350 +
view/src/node_alert.cc | 112 +
view/src/node_alert.h | 76 +
view/src/node_editor.cc | 66 +
view/src/node_editor.h | 134 +
view/src/node_list.cc | 129 +
view/src/node_list.h | 62 +
view/src/node_lister.h | 41 +
view/src/node_window.cc | 253 +
view/src/node_window.h | 73 +
view/src/not_enqueued.cc | 32 +
view/src/not_enqueued.h | 45 +
view/src/observable.cc | 79 +
view/src/observable.h | 45 +
view/src/observer.cc | 48 +
view/src/observer.h | 48 +
view/src/opener.h | 126 +
view/src/option.cc | 205 +
view/src/option.h | 48 +
view/src/option_panel.cc | 60 +
view/src/option_panel.h | 58 +
view/src/output.cc | 226 +
view/src/output.h | 67 +
view/src/panel.cc | 125 +
view/src/panel.h | 110 +
view/src/panel_factories.h | 40 +
view/src/panel_window.cc | 432 +
view/src/panel_window.h | 118 +
view/src/parser.cc | 101 +
view/src/parser.h | 125 +
view/src/passwrd.cc | 71 +
view/src/passwrd.h | 116 +
{ecflow_4_0_7/view => view}/src/patch.pl | 0
view/src/persist.cc | 149 +
view/src/persist.h | 139 +
view/src/pixmap.cc | 103 +
view/src/pixmap.h | 53 +
view/src/pref_editor.cc | 87 +
view/src/pref_editor.h | 55 +
view/src/pref_window.cc | 54 +
view/src/pref_window.h | 51 +
view/src/prefs.cc | 41 +
view/src/prefs.h | 126 +
view/src/re.h | 54 +
view/src/reach.cc | 255 +
view/src/reach.h | 48 +
view/src/relation.cc | 186 +
view/src/relation.h | 74 +
view/src/repeat.h | 168 +
view/src/repeat_node.cc | 309 +
view/src/repeat_node.h | 66 +
view/src/resource.cc | 112 +
view/src/resource.h | 71 +
view/src/restart.cc | 32 +
view/src/restart.h | 109 +
view/src/result.cc | 32 +
view/src/result.h | 38 +
view/src/runnable.cc | 64 +
view/src/runnable.h | 49 +
view/src/script_panel.cc | 61 +
view/src/script_panel.h | 64 +
view/src/scripting.cc | 390 +
view/src/scripting.h | 49 +
view/src/search.cc | 288 +
view/src/search.h | 82 +
view/src/searchable.cc | 151 +
view/src/searchable.h | 61 +
view/src/selection.cc | 153 +
view/src/selection.h | 56 +
view/src/server.cc | 179 +
view/src/server.h | 40 +
view/src/servers_prefs.cc | 259 +
view/src/servers_prefs.h | 79 +
view/src/show.cc | 93 +
view/src/show.h | 104 +
view/src/simple_node.cc | 1085 +++
view/src/simple_node.h | 158 +
view/src/singleton.h | 32 +
{ecflow_4_0_7/view => view}/src/std.h | 0
{ecflow_4_0_7/view => view}/src/stl.h | 0
view/src/str.cc | 99 +
view/src/str.h | 59 +
view/src/substitute.cc | 139 +
view/src/substitute.h | 55 +
view/src/suites_panel.cc | 146 +
view/src/suites_panel.h | 54 +
view/src/super_node.cc | 96 +
view/src/super_node.h | 72 +
view/src/task_node.cc | 280 +
view/src/task_node.h | 58 +
view/src/text_layout.cc | 123 +
view/src/text_layout.h | 143 +
view/src/text_lister.h | 79 +
view/src/text_window.cc | 194 +
view/src/text_window.h | 65 +
view/src/time.cc | 163 +
view/src/time_node.h | 49 +
view/src/timeout.cc | 86 +
view/src/timeout.h | 53 +
view/src/timetable_panel.cc | 731 ++
view/src/timetable_panel.h | 123 +
view/src/tip.cc | 114 +
view/src/tip.h | 52 +
view/src/tmp_file.cc | 109 +
view/src/tmp_file.h | 83 +
view/src/tmpnam.c | 63 +
view/src/to_check.h | 40 +
view/src/top.cc | 512 ++
view/src/top.h | 72 +
{ecflow_4_0_7/view => view}/src/trans.sh | 0
view/src/translator.cc | 211 +
view/src/translator.h | 114 +
view/src/tree.cc | 340 +
view/src/tree.h | 105 +
view/src/trigger_lister.h | 41 +
view/src/trigger_node.cc | 274 +
view/src/trigger_node.h | 59 +
view/src/trigger_panel.cc | 160 +
view/src/trigger_panel.h | 85 +
view/src/url.cc | 240 +
view/src/url.h | 142 +
view/src/user_prefs.cc | 24 +
view/src/user_prefs.h | 49 +
view/src/users.cc | 62 +
view/src/users.h | 136 +
view/src/variable_node.cc | 135 +
view/src/variable_node.h | 54 +
view/src/variables.cc | 442 +
view/src/variables.h | 58 +
view/src/viewer.cc | 57 +
view/src/viewer.h | 134 +
view/src/why.cc | 64 +
view/src/why.h | 49 +
view/src/window.cc | 59 +
view/src/window.h | 44 +
view/src/x.c | 19 +
view/src/xcdp.menu | 257 +
view/src/xcdp.menu.h | 258 +
view/src/xdclass.h | 225 +
view/src/xdxmdialog.cc | 66 +
view/src/xdxtclass.cc | 223 +
view/src/xec.h | 24 +
view/src/xecp.h | 75 +
view/src/xmstring.cc | 107 +
view/src/xmstring.h | 128 +
view/src/xnode.cc | 56 +
view/src/xnode.h | 85 +
view/src/xresources.h | 659 ++
view/src/zombie.h | 39 +
view/src/zombies_panel.cc | 125 +
view/src/zombies_panel.h | 62 +
view/test/TestRunner.cpp | 21 +
view/test/TestView.cpp | 128 +
view/test/ViewTestFixture.hpp | 33 +
{ecflow_4_0_7/view => view}/test/test_flags.sh | 0
{ecflow_4_0_7/view => view}/tool/reload.sdef | 0
3661 files changed, 350969 insertions(+), 193706 deletions(-)
diff --git a/ACore/CMakeLists.txt b/ACore/CMakeLists.txt
new file mode 100644
index 0000000..ae9d824
--- /dev/null
+++ b/ACore/CMakeLists.txt
@@ -0,0 +1,41 @@
+# Note:
+# If new src or test is added make sure you touch this file
+#
+
+# Only really needed for File.cpp
+add_definitions( -DCMAKE )
+
+# We place generated file in /ACore/src/ so that we can still use boost build
+configure_file( ecflow_version.h.in ${CMAKE_SOURCE_DIR}/ACore/src/ecflow_version.h )
+
+# place in binary directory since this is different for each user
+configure_file( ecflow_source_build_dir.h.in ${CMAKE_BINARY_DIR}/ecflow_source_build_dir.h )
+
+# Use transitive nature: i.e if any lib/exe uses lib core, they
+# will also inherit the boost libs.
+#
+file( GLOB srcs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp" )
+ecbuild_add_library( TARGET core
+ NOINSTALL
+ TYPE STATIC
+ SOURCES ${srcs}
+ INCLUDES src
+ ${Boost_INCLUDE_DIRS}
+ ${CMAKE_BINARY_DIR}
+ )
+
+# This ensures that for debug config, we only link with debug boost libs, for other configs, we link with optimised boost libs
+target_link_libraries(core debug ${Boost_SERIALIZATION_LIBRARY_DEBUG} ${Boost_SERIALIZATION_LIBRARY_RELEASE}
+ debug ${Boost_SYSTEM_LIBRARY_DEBUG} ${Boost_SYSTEM_LIBRARY_RELEASE}
+ debug ${Boost_FILESYSTEM_LIBRARY_DEBUG} ${Boost_FILESYSTEM_LIBRARY_RELEASE}
+ debug ${Boost_DATE_TIME_LIBRARY_DEBUG} ${Boost_DATE_TIME_LIBRARY_RELEASE})
+
+#
+# By use'ing BOOST tag we indicate this test should link with boost test libs
+#
+file( GLOB test_srcs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "test/*.cpp" )
+ecbuild_add_test( TARGET u_acore
+ BOOST
+ SOURCES ${test_srcs}
+ LIBS core
+ )
diff --git a/ACore/Jamfile.jam b/ACore/Jamfile.jam
new file mode 100755
index 0000000..d24b8f6
--- /dev/null
+++ b/ACore/Jamfile.jam
@@ -0,0 +1,46 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+#
+# Core project. define project so that this project can be referenced
+# from other projects
+#
+project theCore ;
+
+# The <include> means we will automatically add this directory to the include path
+# of any other target that uses this lib.
+#
+# <use> does not mean dependency, it simply used to control the link order
+# in our case, we want all the boost libraries to appears after the core library
+# on the link line.
+#
+lib core : [ glob src/*.cpp ]
+ : <link>static
+ <variant>debug:<define>DEBUG
+ <use>/site-config//boost_system
+ <use>/site-config//boost_filesystem
+ <use>/site-config//boost_test
+ <use>/site-config//boost_serialization
+ <use>/site-config//boost_datetime
+ <use>/site-config//boost_program_options
+ :
+ : <include>../ACore/src
+ ;
+
+#
+# boost_datetime is only required for formatting. i.e to call to_simple_string
+# cerr << to_simple_string(calendar.suiteTime()) << "\n";
+#
+exe u_acore : [ glob test/*.cpp ]
+ core
+ /site-config//boost_system
+ /site-config//boost_filesystem
+ /site-config//boost_serialization
+ /site-config//boost_datetime
+ /site-config//boost_test
+ : <variant>debug:<define>DEBUG
+ ;
diff --git a/ACore/ecflow_source_build_dir.h.in b/ACore/ecflow_source_build_dir.h.in
new file mode 100644
index 0000000..88421ac
--- /dev/null
+++ b/ACore/ecflow_source_build_dir.h.in
@@ -0,0 +1,7 @@
+#ifndef ecflow_source_build_dir_h
+#define ecflow_source_build_dir_h
+
+#define CMAKE_ECFLOW_SOURCE_DIR "@PROJECT_SOURCE_DIR@"
+#define CMAKE_ECFLOW_BUILD_DIR "@PROJECT_BINARY_DIR@"
+
+#endif
diff --git a/ecflow_4_0_7/ACore/ecflow_version.h.in b/ACore/ecflow_version.h.in
similarity index 100%
rename from ecflow_4_0_7/ACore/ecflow_version.h.in
rename to ACore/ecflow_version.h.in
diff --git a/ACore/src/Archive.hpp b/ACore/src/Archive.hpp
new file mode 100644
index 0000000..1d86bb1
--- /dev/null
+++ b/ACore/src/Archive.hpp
@@ -0,0 +1,57 @@
+#ifndef ARCHIVE_HPP_
+#define ARCHIVE_HPP_
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #11 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <boost/noncopyable.hpp>
+
+namespace ecf {
+
+// This class allows multiple archives to be used
+// Since it will allow Archive::Type to be passed as a parameter, when multiple archives exist
+class Archive : private boost::noncopyable {
+public:
+
+ enum Type {
+ TEXT = 0,
+ PORTABLE_BINARY = 1,
+ BINARY = 2,
+ EOS_PORTABLE_BINARY = 3
+ };
+
+ static Type default_archive() {
+
+#if defined(BINARY_ARCHIVE)
+ return BINARY;
+#endif
+
+#if defined(PORTABLE_BINARY_ARCHIVE)
+ return PORTABLE_BINARY;
+#endif
+
+#if defined(EOS_PORTABLE_BINARY_ARCHIVE)
+ return EOS_PORTABLE_BINARY;
+#endif
+
+ return TEXT;
+ }
+
+private:
+ Archive();
+};
+
+}
+#endif
diff --git a/ACore/src/ArgvCreator.cpp b/ACore/src/ArgvCreator.cpp
new file mode 100644
index 0000000..ff5debc
--- /dev/null
+++ b/ACore/src/ArgvCreator.cpp
@@ -0,0 +1,53 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "ArgvCreator.hpp"
+#include <sstream>
+#include <assert.h>
+#include <cstdlib> // for malloc/free and gcc 4.4.3, not required for gcc 4.2.1
+#include <cstring> // for strcpy and gcc 4.4.3, not required for gcc 4.2.1
+using namespace std;
+
+ArgvCreator::ArgvCreator( const std::vector<std::string>& theArgs)
+{
+ // Create a Argv array
+ argc_ = theArgs.size();
+ argv_ = (char **) malloc ((argc_ + 1) * sizeof (char *));
+
+ assert(argv_ != NULL);
+
+ for(size_t i = 0; i < theArgs.size(); i++) {
+ argv_[i] = (char*) malloc (sizeof (char *) * (theArgs[i].size() + 1)); // allow +1 for \0
+ strcpy (argv_[i], theArgs[i].c_str() );
+ }
+ argv_[argc_] = NULL;
+}
+
+// Destroys argv array
+ArgvCreator::~ArgvCreator()
+{
+ // remove argv array
+ for (char** scan = argv_; *scan != NULL; scan++) { free (*scan);}
+ free (argv_);
+}
+
+std::string ArgvCreator::toString() const
+{
+ std::stringstream ss;
+ for(int i=0; i < argc_; i++) { ss << " arg" << i << ":('" << argv_[i] << "')";}
+ return ss.str();
+}
+
diff --git a/ACore/src/ArgvCreator.hpp b/ACore/src/ArgvCreator.hpp
new file mode 100644
index 0000000..2461d71
--- /dev/null
+++ b/ACore/src/ArgvCreator.hpp
@@ -0,0 +1,43 @@
+#ifndef ARGVCREATOR_HPP_
+#define ARGVCREATOR_HPP_
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <boost/noncopyable.hpp>
+#include <vector>
+#include <string>
+
+class ArgvCreator : private boost::noncopyable {
+public:
+ // Create argc/argv from a vector of strings
+ ArgvCreator(const std::vector<std::string> & );
+
+ // Destroys argv array
+ ~ArgvCreator();
+
+ int argc() const { return argc_;}
+ char** argv() const { return argv_;}
+
+ // for debug
+ std::string toString() const;
+
+private:
+ int argc_;
+ char** argv_;
+};
+
+#endif
diff --git a/ACore/src/AssertTimer.cpp b/ACore/src/AssertTimer.cpp
new file mode 100644
index 0000000..8185940
--- /dev/null
+++ b/ACore/src/AssertTimer.cpp
@@ -0,0 +1,32 @@
+#
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Simple class the assert when time constraint not met
+//============================================================================
+#include "AssertTimer.hpp"
+#include "Log.hpp"
+#include <iostream>
+
+namespace ecf {
+
+AssertTimer::~AssertTimer()
+{
+ if (doAssert_ && timeConstraint_ > 0) {
+ int d = duration();
+ if (d >= timeConstraint_) {
+ std::cout << "AssertTimer::~AssertTimer() duration(" << d << ") >= timeConstraint(" << timeConstraint_ << ")\n";
+ }
+ LOG_ASSERT( d < timeConstraint_, "AssertTimer::~AssertTimer()");
+ }
+}
+}
diff --git a/ACore/src/AssertTimer.hpp b/ACore/src/AssertTimer.hpp
new file mode 100644
index 0000000..6aadf84
--- /dev/null
+++ b/ACore/src/AssertTimer.hpp
@@ -0,0 +1,43 @@
+#ifndef ASSERTTIMER_HPP_
+#define ASSERTTIMER_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Simple class the assert when time constraint not met
+//============================================================================
+#include "Calendar.hpp"
+
+
+namespace ecf {
+
+// Local timer class used to ensure, job submission takes less than 60 seconds
+class AssertTimer {
+public:
+ AssertTimer(int t, bool doAssert = true)
+ : timeConstraint_(t), doAssert_(doAssert), start_time_(Calendar::second_clock_time()) {}
+ ~AssertTimer();
+
+ int timeConstraint() const { return timeConstraint_;}
+
+ int duration() const {
+ boost::posix_time::time_duration duration = Calendar::second_clock_time() - start_time_;
+ return duration.total_seconds();
+ }
+private:
+ int timeConstraint_;
+ bool doAssert_;
+ boost::posix_time::ptime start_time_;
+};
+
+}
+#endif /* ASSERTTIMER_HPP_ */
diff --git a/ACore/src/Calendar.cpp b/ACore/src/Calendar.cpp
new file mode 100644
index 0000000..f014eb9
--- /dev/null
+++ b/ACore/src/Calendar.cpp
@@ -0,0 +1,386 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #65 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include <boost/date_time/posix_time/time_formatters.hpp> // requires boost date and time lib, for to_simple_string
+#include "Calendar.hpp"
+#include "CalendarUpdateParams.hpp"
+#include "Log.hpp"
+#include "Ecf.hpp"
+#include "Extract.hpp"
+
+using namespace std;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+
+//#define DEBUG_CALENDAR 1;
+
+namespace ecf {
+
+Calendar::Calendar()
+: ctype_(Calendar::REAL),
+ dayChanged_(false),
+ startStopWithServer_(false),
+ day_of_week_(-1),
+ day_of_year_(-1),
+ day_of_month_(-1),
+ month_(-1),
+ year_(-1)
+{
+}
+
+Calendar::Calendar(const Calendar& rhs)
+{
+ assign(rhs);
+}
+
+Calendar& Calendar::operator=( const Calendar& rhs)
+{
+ assign(rhs);
+ return *this;
+}
+
+bool Calendar::operator==( const Calendar& rhs) const
+{
+ // Only used for testing the persistence of calendar
+ // Note: We specifically ignore initLocalTime_ and lastTime_ since they are initialised with the current time.
+ // Otherwise For migration testing, it will fail
+
+ if (ctype_ != rhs.ctype_) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) std::cout << "Calendar::operator== ctypes don't match\n";
+#endif
+ return false;
+ }
+ if (initTime_ !=rhs.initTime_) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) std::cout << "Calendar::operator== initTime_ don't match\n";
+#endif
+ return false;
+ }
+ if (suiteTime_ !=rhs.suiteTime_) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) std::cout << "Calendar::operator== suiteTime_ don't match\n";
+#endif
+ return false;
+ }
+ if (duration_ !=rhs.duration_) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) std::cout << "Calendar::operator== duration_ don't match\n";
+#endif
+ return false;
+ }
+ if (dayChanged_ !=rhs.dayChanged_) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) std::cout << "Calendar::operator== dayChanged_ don't match\n";
+#endif
+ return false;
+ }
+ if (startStopWithServer_ != rhs.startStopWithServer_) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) std::cout << "Calendar::operator== startStopWithServer_ don't match\n";
+#endif
+ return false;
+ }
+ if (calendarIncrement_ !=rhs.calendarIncrement_) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) std::cout << "Calendar::operator== calendarIncrement_ don't match\n";
+#endif
+ return false;
+ }
+
+ return true;
+}
+
+void Calendar::assign( const Calendar& rhs)
+{
+ ctype_ = rhs.ctype_;
+ initTime_ = rhs.initTime_;
+ suiteTime_ = rhs.suiteTime_;
+ duration_ = rhs.duration_;
+ dayChanged_ = rhs.dayChanged_;
+ startStopWithServer_ = rhs.startStopWithServer_;
+ initLocalTime_ = rhs.initLocalTime_;
+ lastTime_ = rhs.lastTime_;
+ calendarIncrement_ = rhs.calendarIncrement_;
+
+ day_of_week_ = rhs.day_of_week_; // Cache
+ day_of_year_ = rhs.day_of_year_; // Cache
+ day_of_month_ = rhs.day_of_month_; // Cache
+ month_ = rhs.month_; // Cache
+ year_ = rhs.year_; // Cache
+}
+
+void Calendar::init(Clock_t clock, bool startStopWithServer)
+{
+ ctype_ = clock;
+ startStopWithServer_ = startStopWithServer;
+}
+
+void Calendar::init(const boost::posix_time::ptime& time, Clock_t clock, bool startStopWithServer)
+{
+ init(clock,startStopWithServer);
+ begin(time);
+}
+
+/// Start the Calendar. Parameter time can include gain.
+void Calendar::begin(const boost::posix_time::ptime& the_time)
+{
+ duration_ = time_duration(0,0,0,0);
+ calendarIncrement_ = time_duration(0,1,0,0); // This will get overwritten on update
+ // But allows some tests to run
+ suiteTime_ = the_time; // includes gain _IF_ it was specified
+ initTime_ = the_time; // includes gain
+ dayChanged_ = false;
+ initLocalTime_ = second_clock_time(); // for real time clock
+ lastTime_ = initLocalTime_; // for real time clock
+
+ // Cache the most common requests
+ update_cache();
+}
+
+void Calendar::update( const ecf::CalendarUpdateParams & calUpdateParams )
+{
+ assert(!suiteTime_.is_special()); // begin has not been called.
+
+ // Get the day of week before we update calendar, then same after to determine if the day changed
+ boost::gregorian::date currentdate = suiteTime_.date();
+ int theDayOfWeek = currentdate.day_of_week().as_number();
+
+ // However there are two ways of incremented/updating calendar.
+ if ( !startStopWithServer_ && !calUpdateParams.forTest() ) {
+
+ if (calUpdateParams.serverPollPeriod().total_seconds() < 60) {
+ // 0/ We are still testing. User wants to speed up calendar.
+ // i.e. if server poll period is 2 seconds, we increment calendar by 1 minute
+
+ time_duration one_minute(0,1,0,0);
+ duration_ += one_minute;
+ suiteTime_ += one_minute;
+ calendarIncrement_ = one_minute;
+
+#ifdef DEBUG_CALENDAR
+ std::cout << "Calendar::update: if (calUpdateParams.serverPollPeriod().total_seconds() < 60) { \n";
+#endif
+ }
+ else {
+ // 1. Always Maintain phase with system clock. The calUpdateParams.timeNow()
+ // time was constructed from a system call in the server.
+ //
+ // Take a difference, which means we can ignore dates
+ const ptime& time_now = calUpdateParams.timeNow();
+ assert(!time_now.is_special()); // This should have been set
+ duration_ = time_period( initLocalTime_, time_now ).length();
+ calendarIncrement_ = time_now - lastTime_;
+ suiteTime_ += calendarIncrement_;
+ lastTime_ = time_now;
+#ifdef DEBUG_CALENDAR
+ std::cout << "Calendar::update: if ( !startStopWithServer_ && !calUpdateParams.forTest() ) { \n";
+#endif
+ }
+ }
+ else {
+ // 2. Update calendar based on server poll period/ Job submission interval
+ // _OR_ For TESTING allow calendar to be speeded up.
+ // Note: for simulation serverPollPeriod could be 1 hour
+ duration_ += calUpdateParams.serverPollPeriod();
+ suiteTime_ += calUpdateParams.serverPollPeriod();
+ calendarIncrement_ = calUpdateParams.serverPollPeriod();
+#ifdef DEBUG_CALENDAR
+ std::cout << "Calendar::update: calUpdateParams.serverPollPeriod() = " << calUpdateParams.serverPollPeriod() << "\n";
+#endif
+ }
+
+ // Day change required for both REAL and HYBRID. See TimeDependencies.ddoc for reason
+ // This must be done before change date back. (i.e in hybrid case, below)
+ int new_day_of_week = suiteTime_.date().day_of_week().as_number();
+ if (theDayOfWeek != new_day_of_week) dayChanged_ = true;
+ else dayChanged_ = false;
+
+ // With the hybrid calendar the date does not change
+ if ( ctype_ == Calendar::HYBRID) {
+ if (suiteTime_.date() != initTime_.date()) {
+
+#ifdef DEBUG_CALENDAR
+ cout << "HYBRID: (suiteTime_.date() != initTime_.date()) suiteTime_ = " << to_simple_string(suiteTime_) << "\n";
+#endif
+
+ time_duration td = suiteTime_.time_of_day();
+
+ suiteTime_ = ptime( initTime_.date(), td);
+
+#ifdef DEBUG_CALENDAR
+ cout << "suiteTime_ = " << to_simple_string(suiteTime_) << "\n";
+#endif
+ }
+ }
+
+ // update_cache *MUST* be last, so we can take into account hybrid. Date does NOT change.
+ // See ECFLOW-458
+ update_cache();
+
+#ifdef DEBUG_CALENDAR
+ cout << " Calendar::update serverPollPeriod = " << to_simple_string(calUpdateParams.serverPollPeriod()) << " " << toString() << endl;
+#endif
+}
+
+void Calendar::update_cache() const
+{
+ // begin() has not been called yet
+ if (suiteTime_.is_special()) return;
+
+ boost::gregorian::date newDate = suiteTime_.date();
+ day_of_week_ = newDate.day_of_week().as_number();
+ day_of_year_ = newDate.day_of_year();
+ day_of_month_ = newDate.day();
+ month_ = newDate.month();
+ year_ = newDate.year();
+}
+int Calendar::day_of_week() const { if (day_of_week_ == -1) update_cache(); return day_of_week_;}
+int Calendar::day_of_year() const { if (day_of_week_ == -1) update_cache(); return day_of_year_;}
+int Calendar::day_of_month() const { if (day_of_week_ == -1) update_cache(); return day_of_month_;}
+int Calendar::month() const { if (day_of_week_ == -1) update_cache(); return month_;}
+int Calendar::year() const { if (day_of_week_ == -1) update_cache(); return year_;}
+
+
+void Calendar::update(const boost::posix_time::time_duration& serverPollPeriod)
+{
+ CalendarUpdateParams p(serverPollPeriod);
+ update( p );
+}
+
+void Calendar::update(const boost::posix_time::ptime& time_now)
+{
+ // Used for test even though for_test is false, as we want to test that path in UNIT tests
+ // Tests: path 1. shown above. Note: we pass minutes(1), to ensure path 1. is taken
+ CalendarUpdateParams p( time_now, minutes(1), true /* server running */, false/* for Test*/ );
+ update( p );
+}
+
+boost::gregorian::date Calendar::date() const
+{
+ return suiteTime_.date();
+}
+
+/// for debug
+void Calendar::dump(const std::string& title) const
+{
+ LOG(Log::LOG,title
+ << " duration_(" << to_simple_string(duration_)
+ << ") initTime_(" << to_simple_string(initTime_)
+ << ") suiteTime_(" << to_simple_string(suiteTime_) << ")"
+ );
+}
+
+std::string Calendar::toString() const
+{
+ std::stringstream ss;
+ ss << "hybrid(" << hybrid()
+ << ") duration_(" << to_simple_string(duration_)
+ << ") initTime_(" << to_simple_string(initTime_)
+ << ") suiteTime_(" << to_simple_string(suiteTime_)
+ << ") dayChanged_(" << dayChanged_ << ")";
+ ss << " calendarIncrement_(" << to_simple_string(calendarIncrement_) << ")";
+
+ if (day_of_week_ == 0) ss << " SUNDAY";
+ else if (day_of_week_ == 1) ss << " MONDAY";
+ else if (day_of_week_ == 2) ss << " TUESDAY";
+ else if (day_of_week_ == 3) ss << " WEDNESDAY";
+ else if (day_of_week_ == 4) ss << " THURSDAY";
+ else if (day_of_week_ == 5) ss << " FRIDAY";
+ else if (day_of_week_ == 6) ss << " SATURDAY";
+
+ return ss.str();
+}
+
+
+std::string Calendar::write_state() const
+{
+ if ( initTime_.is_special() ) return string();
+
+ bool calendarIncrement__changed = (!calendarIncrement_.is_special() && calendarIncrement_.total_seconds() != 0);
+
+ // cType is obtained from the suite clock attribute, and not persisted
+ std::stringstream ss;
+ ss << " initTime:" << to_simple_string(initTime_);
+ ss << " suiteTime:" << to_simple_string(suiteTime_);
+ ss << " duration:" << to_simple_string(duration_);
+ ss << " initLocalTime:" << to_simple_string(initLocalTime_);
+ ss << " lastTime:" << to_simple_string(lastTime_);
+ if (calendarIncrement__changed) ss << " calendarIncrement:" << to_simple_string(calendarIncrement_);
+
+ if (dayChanged_) ss << " dayChanged:" << dayChanged_;
+ return ss.str();
+}
+
+void Calendar::read_state(const std::string& line,const std::vector<std::string>& lineTokens)
+{
+ // initTime:2012-Jul-16 16:19:35 suiteTime:2012-Jul-16 16:19:35 duration:00:00:00 dayChanged:0 initLocalTime:2012-Jul-16 16:19:35 lastTime:2012-Jul-16 16:19:35 calendarIncrement:00:00:00
+// std::cout << "Calendar::read_state:" << line << "\n";
+ std::string time;
+ for(size_t i = 0; i < lineTokens.size(); i++) {
+ time.clear();
+ if (lineTokens[i].find("initTime:") != std::string::npos ) {
+ if (!Extract::split_get_second(lineTokens[i],time)) throw std::runtime_error( "Calendar::read_state failed: (initTime)");
+ if (i + 1 < lineTokens.size()) { time += " "; time += lineTokens[i+1]; }
+ else throw std::runtime_error( "Calendar::read_state failed: 1");
+ initTime_ = time_from_string(time);
+ }
+ else if (lineTokens[i].find("suiteTime:") != std::string::npos ) {
+ if (!Extract::split_get_second(lineTokens[i],time)) throw std::runtime_error( "Calendar::read_state failed: (suiteTime)");
+ if (i + 1 < lineTokens.size()) { time += " "; time += lineTokens[i+1]; }
+ else throw std::runtime_error( "Calendar::read_state failed: 1");
+ suiteTime_ = time_from_string(time);
+ }
+ else if (lineTokens[i].find("initLocalTime:") != std::string::npos ) {
+ if (!Extract::split_get_second(lineTokens[i],time)) throw std::runtime_error( "Calendar::read_state failed: (initLocalTime)");
+ if (i + 1 < lineTokens.size()) { time += " "; time += lineTokens[i+1]; }
+ else throw std::runtime_error( "Calendar::read_state failed: 1");
+ initLocalTime_ = time_from_string(time);
+ }
+ else if (lineTokens[i].find("lastTime:") != std::string::npos ) {
+ if (!Extract::split_get_second(lineTokens[i],time)) throw std::runtime_error( "Calendar::read_state failed: (lastTime)");
+ if (i + 1 < lineTokens.size()) { time += " "; time += lineTokens[i+1]; }
+ else throw std::runtime_error( "Calendar::read_state failed: 1");
+ lastTime_ = time_from_string(time);
+ }
+ else if (lineTokens[i].find("duration:") != std::string::npos ) {
+ if (!Extract::split_get_second(lineTokens[i],time)) throw std::runtime_error( "Calendar::read_state failed: (duration)");
+ duration_ = duration_from_string(time);
+ }
+ else if (lineTokens[i].find("calendarIncrement:") != std::string::npos ) {
+ if (!Extract::split_get_second(lineTokens[i],time)) throw std::runtime_error( "Calendar::read_state failed: (calendarIncrement)");
+ calendarIncrement_ = duration_from_string(time);
+ }
+ else if (lineTokens[i] == "dayChanged:1") dayChanged_ = true;
+ }
+}
+
+bool Calendar::checkInvariants(std::string& errorMsg) const
+{
+ if (!duration_.is_special()) {
+ if (duration_.is_negative()) {
+ errorMsg += "Calendar::checkInvariants duration is negative "+ toString() + "\n";
+ return false;
+ }
+ }
+ return true;
+}
+
+boost::posix_time::ptime Calendar::second_clock_time()
+{
+ /// Chose UTC since it s compatible with boost deadline timer
+ return second_clock::universal_time(); // UTC
+}
+
+}
diff --git a/ACore/src/Calendar.hpp b/ACore/src/Calendar.hpp
new file mode 100644
index 0000000..92c3af5
--- /dev/null
+++ b/ACore/src/Calendar.hpp
@@ -0,0 +1,255 @@
+#ifndef CALENDAR_HPP_
+#define CALENDAR_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #48 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : The calendar object is initialised when the suite begins.
+// The calendar encapsulates date and time. The date is derived from the time.
+//
+// After each update the calendar will store the time_duration between the init() function
+// call and the update() function call.
+// The calendar is to be used for all reference to time and date
+// This will stop different time functionality from getting out of step.
+//
+// Examples of Use of calendar are:
+// o Generated time variables
+// o Time dependent attributes: TimeAttr,TodaySeries,CronAttr,DateAttr,DayAttr
+// ****************************************************************************
+// ** A time attribute can have a +, which means time relative to suite start
+// ** This is stored on the TimeSeries, as it isNode/Attribute specific.
+// ** i.e repeated families will have its own relative start time.
+// *****************************************************************************
+//
+// DESIGN CONSIDERATIONS:
+// Real and Hybrid:
+// Real
+// calendar is like a normal calendar where time and date are related
+// and day/date changes at midnight.
+// Hybrid:
+// There is currently confusion about how this is supposed to work.
+// The date is not supposed to change. (According to John date updates at suite restart?)
+// This has important implications, i.e does the day change ?
+// If the day does not change, then many of suites will never complete.
+// i.e if we use repeat, with a single time series, "time 10:00"
+// *** This relies on a day change to reset time attribute at midnight. ****
+// Conclusion: Will support day change for both REAL and HYBRID (date does not change)
+//
+// Calendar Updates:
+// How and when should we update the calendar?
+// In both the approaches below we need to make a distinction/separation
+// between the server poll and calendar update. This is required for testing
+//
+// o Poll/Job submission interval in server is used to update calendar .
+// +: No time slots will be missed. even if server is suspended/restarted.
+// since suspending the server, also suspends the calendar updates
+// +: Suite relative times will continue to work even after server stopped/started
+// +: Avoids additional system call.
+// +: Lead's to more deterministic behaviour
+// -: If server is suspended and restarted the calendar will NOT be in
+// phase with system clock. (Its not clear to me why this should be an issue?)
+// ?: If the server is run for several days is there a possibility for the poll
+// update to get out of skew with real time. This is only possible if
+// job dependencies take more the 60 seconds to resolve.
+// *** THIS FUNCTIONALITY NEEDS TO BE ADVERTISED, SO THAT USERS ARE AWARE OF IT
+// *** THIS FUNCTIONALITY IS AVAILABLE VIA -s flag on the clock attribute .i.e
+// *** the -s stand's for stop start clock in line with the server
+// clock real 20.1.2007 +01:00 -s
+// clock hybrid -s
+//
+// o Poll/Job submission interval in server is used Initiate an update of calendar via a system call.
+// +: calendar is always in phase with system clock.
+// Many task job dependencies depend on ordering based on real time.
+// -: Requires additional system call for each poll in the server
+// -: Time slots can be missed. (i.e if server suspended/restarted).
+// There is no catch up. (?? See TimeDependencies.ddoc)
+// -: Relative times will not be adhered too, when server stopped/started.
+// -: Will require more manual intervention ?
+//
+// Conclusion:: The clock attribute will be changed to add both capabilities
+//
+// Resolution: Will support 1 minute resolution:
+//============================================================================
+
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/date_time/posix_time/conversion.hpp>
+#include <boost/date_time/posix_time/time_serialize.hpp>
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/level.hpp>
+#include <boost/serialization/tracking.hpp>
+
+namespace ecf {
+
+class CalendarUpdateParams; // forward declare
+
+class Calendar {
+public:
+ enum Clock_t {
+ REAL, // like a normal clock
+ HYBRID // date does not change, but will support day change. See Above.
+ };
+
+ /// Defaults to the REAL clock
+ Calendar();
+ Calendar(const Calendar&);
+ Calendar& operator=( const Calendar&);
+ bool operator==( const Calendar&) const;
+
+ /// Initialise the Calendar.
+ /// The boolean startStopWithServer allows us to choose how we update the calendar:
+ // False: Use system time to update the calendar:
+ // True : Use the server poll, to update the calendar
+ void init(Clock_t clock, bool startStopWithServer = false);
+
+ // for test init and begin calendar
+ void init(const boost::posix_time::ptime& time, Clock_t clock = Calendar::REAL, bool startStopWithServer = false);
+
+ /// Start the Calendar. Parameter time can include gain.
+ void begin(const boost::posix_time::ptime& time);
+
+ /// Update the calendar using the input. Will Store internally the time duration
+ /// between the init() function call and the last update.
+ /// The for_test parameter is *ONLY* used if we are using real time calendar
+ void update(const ecf::CalendarUpdateParams &);
+
+ // Used for test only, will call the function above
+ void update(const boost::posix_time::time_duration&);
+ void update(const boost::posix_time::ptime& time_now);
+
+ // The following were added as a performance optimisation
+ // Represent a day within a week (range 0==Sun to 6==Sat)
+ int day_of_week() const; // same as suiteTime().date().day_of_week().as_number()
+ int day_of_year() const; // same as suiteTime().date().day_of_year()
+ int day_of_month() const; // same as suiteTime().date().day()
+ int month() const; // same as suiteTime().date().month()
+ int year() const; // same as suiteTime().date().year()
+
+ /// returns true if the day changed, this will update for REAL and HYBRID .
+ bool dayChanged() const { return dayChanged_;}
+
+ /// returns the last calendar increment
+ const boost::posix_time::time_duration& calendarIncrement() const { return calendarIncrement_;}
+
+ /// return the init() time + the accumulated duration from calls to update(...)
+ /// This should only be used when this calendar is real.
+ const boost::posix_time::ptime& suiteTime() const { return suiteTime_;}
+
+ // duration since last call to init, essentially suite duration
+ const boost::posix_time::time_duration& duration() const { return duration_;}
+
+ /// return real time, when the calendar was begun/initialised.
+ /// This is used to update the duration_, which is recorded for each state change in the node
+ /// Hence to when we can compute when a state change occurred by using:
+ /// boost::posix_time::ptime time_of_state_change = begin_time() + node->get_state().second(duration)
+ const boost::posix_time::ptime& begin_time() const { return initLocalTime_;}
+
+ /// return the date, for real calendar this corresponds to the date on suiteTime_
+ /// for hybrid, the date does not change, and hence we return date for initTime_
+ boost::gregorian::date date() const;
+
+ /// The calendar type. For hybrid clocks the date does not update.
+ bool hybrid() const { return (ctype_ == Calendar::HYBRID) ? true : false; }
+
+ /// for debug, must link with boost date and time library
+ void dump(const std::string& title) const;
+
+ /// for debug, must link with boost date and time library
+ std::string toString() const;
+
+ std::string write_state() const;
+ void read_state(const std::string& line,const std::vector<std::string>& lineTokens);
+
+ bool checkInvariants(std::string& errorMsg) const;
+
+ // allow Suite memento to update calendar type
+ void set_clock_type( Clock_t ct) { ctype_ = ct;}
+
+ /// Will return either second_clock::universal_time()/UTC ( the other alternative is second_clock::local_time() )
+ /// This is because boost deadline timer is based on UTC clock
+ /// >>> The deadline_timer typedef is based on a UTC clock, and all operations (expires_at, expires_from_now) work in UTC time.
+ /// >>> If you want it to use a different clock (such as the local time clock), you can use basic_deadline_timer<> with your own traits class.
+ /// >>> Please see the "Timers" example.
+ /// Taken from boost date/time doc
+ /// If you want exact agreement with wall-clock time, you must use either UTC or local time. If you compute a duration
+ // by subtracting one UTC time from another and you want an answer accurate to the second, the two times must not be
+ // too far in the future because leap seconds affect the count but are only determined about 6 months in advance. With
+ // local times a future duration calculation could be off by an entire hour, since legislatures can and do change DST
+ // rules at will.
+ // If you want to handle wall-clock times in the future, you won't be able (in the general case) to calculate exact durations,
+ // for the same reasons described above.
+ // If you want accurate calculations with future times, you will have to use TAI or an equivalent, but the mapping from
+ // TAI to UTC or local time depends on leap seconds, so you will not have exact agreement with wall-clock time.
+ static boost::posix_time::ptime second_clock_time();
+
+
+private:
+ void assign( const Calendar& rhs);
+
+ Clock_t ctype_; // *NOT* persisted: can be derived from suite clock attribute
+ boost::posix_time::ptime initTime_; // When calendar was started, suite time(could be in the past OR real time)
+ boost::posix_time::ptime suiteTime_; // The suite time for hybrid DATE does not change.
+ boost::posix_time::time_duration duration_; // duration since last call to init/begin, used on Node for late and autocancel
+ bool dayChanged_;
+ bool startStopWithServer_; //*NOT* persisted: false means real time calendar, can be derived from suite clock attribute
+
+ boost::posix_time::ptime initLocalTime_; // Real Time: When calendar was started, used to work out duration_
+ boost::posix_time::ptime lastTime_; // Real Time: Used to calculate calendarIncrement
+
+ boost::posix_time::time_duration calendarIncrement_;
+
+private:
+ void update_cache() const;
+ mutable int day_of_week_; // Cache
+ mutable int day_of_year_; // Cache
+ mutable int day_of_month_; // Cache
+ mutable int month_; // Cache
+ mutable int year_; // Cache
+
+private:
+ // Note: The *only* reason to serialise the calendar is so that we can support
+ // why() command on the client side. By default calendar is initialised in the *server*
+ // at begin time, from the clock attribute
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/)
+ {
+ if (Archive::is_saving::value) {
+ if ( initTime_.is_special() ) {
+ // Initialise the ptimes to avoid serialisation exceptions
+ // The serialisation of ptime makes use of exceptions, especially
+ // when dealing with a date that has *not* been initialised.
+ // To avoid this we take a small hit to initialise the calendar with
+ // time now. This will get overriden with suite clock at begin
+ begin(second_clock_time());
+ }
+ }
+
+ ar & initTime_;
+ ar & suiteTime_;
+ ar & duration_;
+ ar & dayChanged_;
+ ar & initLocalTime_;
+ ar & lastTime_;
+ ar & calendarIncrement_;
+ }
+};
+}
+
+
+// eliminate serialization overhead at the cost of
+// never being able to increase the version.
+BOOST_CLASS_IMPLEMENTATION(ecf::Calendar, boost::serialization::object_serializable)
+
+// eliminate object tracking (even if serialized through a pointer)
+// at the risk of a programming error creating duplicate objects.
+BOOST_CLASS_TRACKING(ecf::Calendar,boost::serialization::track_never);
+
+#endif
diff --git a/ACore/src/CalendarUpdateParams.hpp b/ACore/src/CalendarUpdateParams.hpp
new file mode 100644
index 0000000..df36d3c
--- /dev/null
+++ b/ACore/src/CalendarUpdateParams.hpp
@@ -0,0 +1,71 @@
+#ifndef CALENDARUPDATEPARAMS_HPP_
+#define CALENDARUPDATEPARAMS_HPP_
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Collate Argument list to update calendar
+//
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+
+#include <boost/noncopyable.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+namespace ecf {
+
+class CalendarUpdateParams : private boost::noncopyable {
+public:
+
+ // For use in the server
+ CalendarUpdateParams(const boost::posix_time::ptime& time_now,
+ const boost::posix_time::time_duration& serverPollPeriod,
+ bool serverRunning)
+ : timeNow_(time_now),
+ serverPollPeriod_(serverPollPeriod),
+ serverRunning_( serverRunning ),
+ forTest_( false )
+ {}
+
+
+ // For use in the simulator/ unit tests
+ CalendarUpdateParams(const boost::posix_time::time_duration& serverPollPeriod)
+ : timeNow_( boost::date_time::not_a_date_time),
+ serverPollPeriod_(serverPollPeriod),
+ serverRunning_( true ),
+ forTest_( true )
+ {}
+
+ // For use in test
+ CalendarUpdateParams(const boost::posix_time::ptime& time_now,
+ const boost::posix_time::time_duration& serverPollPeriod,
+ bool serverRunning,
+ bool forTest)
+ : timeNow_(time_now),
+ serverPollPeriod_(serverPollPeriod),
+ serverRunning_( serverRunning ),
+ forTest_( forTest )
+ {}
+
+ const boost::posix_time::ptime& timeNow() const { return timeNow_;}
+ const boost::posix_time::time_duration& serverPollPeriod() const { return serverPollPeriod_;}
+ bool serverRunning() const { return serverRunning_; }
+ bool forTest() const { return forTest_;}
+
+private:
+ boost::posix_time::ptime timeNow_; // Current time and date, not used in simulator
+ boost::posix_time::time_duration serverPollPeriod_; // equivalent to calendar increment
+ bool serverRunning_; // Is the server running or stopped
+ bool forTest_; // Used with Simulator
+};
+}
+#endif /* CALENDARUPDATEPARAMS_HPP_ */
diff --git a/ACore/src/CheckPt.hpp b/ACore/src/CheckPt.hpp
new file mode 100644
index 0000000..00ef9ab
--- /dev/null
+++ b/ACore/src/CheckPt.hpp
@@ -0,0 +1,42 @@
+#ifndef CHECKPT_HPP_
+#define CHECKPT_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+// This class is used to ONLY serialise the edit history when check pointing
+// Also Provides enums for check pointing
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/noncopyable.hpp>
+
+namespace ecf {
+
+class CheckPt : private boost::noncopyable {
+public:
+ /// NEVER - the check pt file is never saved
+ /// ON_TIME - the check pt file is saved periodically. specified by checkPtInterval.
+ /// ALWAYS - the check pt file is saved after any state change
+ /// UNDEFINED - Internal use only
+ enum Mode { NEVER, ON_TIME, ALWAYS, UNDEFINED};
+
+ /// The interval between automatic saves of check point by server
+ static int default_interval() { return 120;}
+
+ /// If saving check point takes longer than the alarm time, raise late flag on the server
+ static int default_save_time_alarm() { return 30;}
+
+private:
+ CheckPt();
+};
+
+}
+#endif
diff --git a/ACore/src/Child.cpp b/ACore/src/Child.cpp
new file mode 100644
index 0000000..40c5aac
--- /dev/null
+++ b/ACore/src/Child.cpp
@@ -0,0 +1,167 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Specifies the different kinds of child commands
+// These are specified in the job file, and communicate with the server
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <assert.h>
+
+#include "Child.hpp"
+#include "Str.hpp"
+
+namespace ecf {
+
+std::string Child::to_string(Child::ZombieType zt)
+{
+ switch (zt) {
+ case Child::USER: return "user"; break;
+ case Child::PATH: return "path"; break;
+ case Child::ECF: return "ecf"; break;
+ case Child::NOT_SET: return "not_set"; break;
+ }
+ return std::string();
+}
+
+Child::ZombieType Child::zombie_type(const std::string& s)
+{
+ if (s == "user") return Child::USER;
+ if (s == "ecf") return Child::ECF;
+ if (s == "path") return Child::PATH;
+ return Child::NOT_SET;
+}
+
+bool Child::valid_zombie_type( const std::string& s)
+{
+ if (s == "user") return true;
+ if (s == "ecf") return true;
+ if (s == "path") return true;
+ return false;
+}
+
+std::string Child::to_string(const std::vector<Child::CmdType>& vec)
+{
+ std::string ret;
+ for(size_t i =0; i < vec.size(); ++i) {
+ if (i == 0) ret += to_string(vec[i]);
+ else {
+ ret += ",";
+ ret += to_string(vec[i]);
+ }
+ }
+ return ret;
+}
+
+std::string Child::to_string( Child::CmdType ct)
+{
+ switch (ct) {
+ case Child::INIT: return "init"; break;
+ case Child::EVENT: return "event"; break;
+ case Child::METER: return "meter"; break;
+ case Child::LABEL: return "label"; break;
+ case Child::WAIT: return "wait"; break;
+ case Child::ABORT: return "abort"; break;
+ case Child::COMPLETE: return "complete"; break;
+ }
+ assert(false);
+ return "init";
+}
+
+std::vector<Child::CmdType> Child::child_cmds(const std::string& s)
+{
+ // expect single or , separated tokens
+ std::vector<std::string> tokens;
+ Str::split(s,tokens,",");
+ std::vector<Child::CmdType> ret; ret.reserve(tokens.size());
+ for(size_t i =0; i < tokens.size(); ++i) {
+ ret.push_back(child_cmd(tokens[i]));
+ }
+ return ret;
+}
+
+Child::CmdType Child::child_cmd( const std::string& s)
+{
+ if (s == "init") return Child::INIT;
+ if (s == "event") return Child::EVENT;
+ if (s == "meter") return Child::METER;
+ if (s == "label") return Child::LABEL;
+ if (s == "wait") return Child::WAIT;
+ if (s == "abort") return Child::ABORT;
+ if (s == "complete") return Child::COMPLETE;
+ assert(false);
+ return Child::INIT;
+}
+
+bool Child::valid_child_cmds( const std::string& s)
+{
+ // empty means all children
+ if (s.empty()) return true;
+
+ // expect single or , separated tokens
+ std::vector<std::string> tokens;
+ Str::split(s,tokens,",");
+ for(size_t i =0; i < tokens.size(); ++i) {
+ if (!valid_child_cmd(tokens[i])) return false;
+ }
+ return true;
+}
+
+bool Child::valid_child_cmd( const std::string& s)
+{
+ if (s == "init") return true;
+ if (s == "event") return true;
+ if (s == "meter") return true;
+ if (s == "label") return true;
+ if (s == "wait") return true;
+ if (s == "abort") return true;
+ if (s == "complete") return true;
+ return false;
+}
+
+//=====================================================================
+
+bool User::valid_user_action( const std::string& s)
+{
+ if (s == "fob") return true;
+ if (s == "fail") return true;
+ if (s == "adopt") return true;
+ if (s == "remove") return true;
+ if (s == "block") return true;
+ if (s == "kill") return true;
+ return false;
+}
+
+User::Action User::user_action( const std::string& s)
+{
+ if (s == "fob") return User::FOB;
+ if (s == "fail") return User::FAIL;
+ if (s == "adopt") return User::ADOPT;
+ if (s == "remove") return User::REMOVE;
+ if (s == "block") return User::BLOCK;
+ if (s == "kill") return User::KILL;
+ return User::BLOCK;
+}
+
+std::string User::to_string(User::Action uc)
+{
+ switch (uc) {
+ case User::FOB: return "fob"; break;
+ case User::FAIL: return "fail"; break;
+ case User::ADOPT: return "adopt"; break;
+ case User::REMOVE: return "remove"; break;
+ case User::BLOCK: return "block"; break;
+ case User::KILL: return "kill"; break;
+ }
+ assert(false);
+ return std::string();
+}
+
+}
diff --git a/ACore/src/Child.hpp b/ACore/src/Child.hpp
new file mode 100644
index 0000000..421e22a
--- /dev/null
+++ b/ACore/src/Child.hpp
@@ -0,0 +1,61 @@
+#ifndef CHILD_HPP_
+#define CHILD_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Specifies the different kinds of child commands
+// These are specified in the job file, and communicate with the server
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <string>
+#include <vector>
+#include <boost/noncopyable.hpp>
+
+namespace ecf {
+
+class Child : private boost::noncopyable {
+public:
+ enum CmdType { INIT, EVENT, METER, LABEL, WAIT, ABORT, COMPLETE };
+
+ enum ZombieType { USER, ECF, PATH , NOT_SET };
+
+ static std::string to_string(ZombieType);
+ static bool valid_zombie_type( const std::string& );
+ static ZombieType zombie_type( const std::string&);
+
+ static std::string to_string(const std::vector<Child::CmdType>&);
+ static std::string to_string( Child::CmdType );
+ static std::vector<Child::CmdType> child_cmds(const std::string&);
+ static Child::CmdType child_cmd(const std::string&);
+
+ /// Expect a , separated string
+ static bool valid_child_cmds( const std::string& );
+ static bool valid_child_cmd( const std::string& );
+
+private:
+ Child();
+};
+
+
+class User : private boost::noncopyable {
+public:
+ enum Action { FOB, FAIL, ADOPT, REMOVE, BLOCK, KILL };
+
+ static bool valid_user_action( const std::string& );
+ static Action user_action( const std::string& );
+ static std::string to_string(Action);
+
+private:
+ User();
+};
+
+}
+#endif
diff --git a/ACore/src/DState.cpp b/ACore/src/DState.cpp
new file mode 100644
index 0000000..2ca9a36
--- /dev/null
+++ b/ACore/src/DState.cpp
@@ -0,0 +1,136 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <assert.h>
+#include <iostream>
+#include "DState.hpp"
+#include "Ecf.hpp"
+
+void DState::setState( State s ) {
+ state_= s;
+ state_change_no_ = Ecf::incr_state_change_no();
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "DState::setState\n";
+#endif
+}
+
+NState::State DState::convert(DState::State display_state)
+{
+ switch (display_state) {
+ case DState::UNKNOWN: return NState::UNKNOWN; break;
+ case DState::COMPLETE: return NState::COMPLETE; break;
+ case DState::SUSPENDED: return NState::UNKNOWN; break;
+ case DState::QUEUED: return NState::QUEUED; break;
+ case DState::ABORTED: return NState::ABORTED; break;
+ case DState::SUBMITTED: return NState::SUBMITTED; break;
+ case DState::ACTIVE: return NState::ACTIVE; break;
+ }
+ return NState::UNKNOWN;
+}
+
+const char* DState::toString( DState::State s ) {
+ switch ( s ) {
+ case DState::UNKNOWN:
+ return "unknown";
+ break;
+ case DState::COMPLETE:
+ return "complete";
+ break;
+ case DState::QUEUED:
+ return "queued";
+ break;
+ case DState::ABORTED:
+ return "aborted";
+ break;
+ case DState::SUBMITTED:
+ return "submitted";
+ break;
+ case DState::SUSPENDED:
+ return "suspended";
+ break;
+ case DState::ACTIVE:
+ return "active";
+ break;
+ default:
+ assert(false);break;
+ }
+ assert(false);
+ return NULL;
+}
+
+DState::State DState::toState( const std::string& str ) {
+ if ( str == "complete" )
+ return DState::COMPLETE;
+ if ( str == "unknown" )
+ return DState::UNKNOWN;
+ if ( str == "queued" )
+ return DState::QUEUED;
+ if ( str == "aborted" )
+ return DState::ABORTED;
+ if ( str == "submitted" )
+ return DState::SUBMITTED;
+ if ( str == "suspended" )
+ return DState::SUSPENDED;
+ if ( str == "active" )
+ return DState::ACTIVE;
+ assert(false);
+ return DState::UNKNOWN;
+}
+
+bool DState::isValid( const std::string& state ) {
+ if ( state == "complete" )
+ return true;
+ if ( state == "suspended" )
+ return true;
+ if ( state == "unknown" )
+ return true;
+ if ( state == "aborted" )
+ return true;
+ if ( state == "submitted" )
+ return true;
+ if ( state == "active" )
+ return true;
+ if ( state == "queued" )
+ return true;
+ return false;
+}
+
+std::vector< std::string > DState::allStates() {
+ std::vector< std::string > vec;
+ vec.reserve( 7 );
+ vec.push_back( "complete" );
+ vec.push_back( "unknown" );
+ vec.push_back( "queued" );
+ vec.push_back( "aborted" );
+ vec.push_back( "submitted" );
+ vec.push_back( "suspended" );
+ vec.push_back( "active" );
+ return vec;
+}
+
+std::vector<DState::State> DState::states()
+{
+ std::vector< DState::State > vec;
+ vec.reserve( 7 );
+ vec.push_back( DState::UNKNOWN );
+ vec.push_back( DState::COMPLETE );
+ vec.push_back( DState::QUEUED );
+ vec.push_back( DState::ABORTED );
+ vec.push_back( DState::SUBMITTED );
+ vec.push_back( DState::ACTIVE );
+ vec.push_back( DState::SUSPENDED );
+ return vec;
+}
+
diff --git a/ACore/src/DState.hpp b/ACore/src/DState.hpp
new file mode 100644
index 0000000..cb2bcd7
--- /dev/null
+++ b/ACore/src/DState.hpp
@@ -0,0 +1,72 @@
+#ifndef DSTATE_HPP_
+#define DSTATE_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <string>
+#include <vector>
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/level.hpp>
+#include <boost/serialization/tracking.hpp>
+#include "NState.hpp"
+
+// DState: stores the state of a node.
+// *The class DState just used to define the enum, however we also
+// needed to know when the state changed. Hence the use of state_change_no
+// Uses default copy constructor and destructor, and equality
+class DState {
+public:
+ enum State { UNKNOWN =0, COMPLETE=1, QUEUED=2, ABORTED=3, SUBMITTED=4, ACTIVE=5, SUSPENDED=6};
+ DState(State s): state_(s), state_change_no_(0) {}
+ DState(): state_(QUEUED),state_change_no_(0) {}
+
+ State state() const { return state_;}
+ void setState(State);
+
+ // The state_change_no is never reset. Must be incremented if it can affect equality
+ unsigned int state_change_no() const { return state_change_no_; }
+
+ bool operator==(const DState& rhs) const { return state_ == rhs.state_;}
+ bool operator!=(const DState& rhs) const { return state_ != rhs.state_;}
+ bool operator==(State s) const { return s == state_;}
+ bool operator!=(State s) const { return s != state_;}
+
+ static DState::State default_state() { return DState::QUEUED; }
+ static NState::State convert(DState::State);
+ static const char* toString(DState::State s);
+ static const char* toString(const DState& ns) { return toString(ns.state());}
+ static DState::State toState(const std::string& state);
+ static bool isValid(const std::string& state);
+ static std::vector<std::string> allStates();
+ static std::vector<DState::State> states();
+
+private:
+ State state_;
+ unsigned int state_change_no_; // *not* persisted, only used on server side
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/)
+ {
+ ar & state_;
+ }
+};
+
+// This should ONLY be added to objects that are *NOT* serialised through a pointer
+BOOST_CLASS_IMPLEMENTATION(DState, boost::serialization::object_serializable);
+BOOST_CLASS_TRACKING(DState,boost::serialization::track_never);
+
+#endif
diff --git a/ACore/src/DurationTimer.hpp b/ACore/src/DurationTimer.hpp
new file mode 100644
index 0000000..ba87c3b
--- /dev/null
+++ b/ACore/src/DurationTimer.hpp
@@ -0,0 +1,39 @@
+#ifndef DURATIONTIMER_HPP_
+#define DURATIONTIMER_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Simple class the reports wall clock time duration
+//============================================================================
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+namespace ecf {
+
+class DurationTimer {
+public:
+ DurationTimer() : start_time_(boost::posix_time::microsec_clock::universal_time()) {}
+ ~DurationTimer() {}
+
+ int duration() const {
+ boost::posix_time::time_duration duration = boost::posix_time::microsec_clock::universal_time() - start_time_;
+ return duration.total_seconds();
+ }
+
+ boost::posix_time::time_duration elapsed() const { return boost::posix_time::microsec_clock::universal_time() - start_time_;}
+
+private:
+ boost::posix_time::ptime start_time_;
+};
+
+}
+#endif
diff --git a/ACore/src/Ecf.cpp b/ACore/src/Ecf.cpp
new file mode 100644
index 0000000..bf14ceb
--- /dev/null
+++ b/ACore/src/Ecf.cpp
@@ -0,0 +1,66 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #16 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Provides globals used by server
+//============================================================================
+
+#include "Ecf.hpp"
+
+bool Ecf::server_ = false;
+bool Ecf::debug_equality_ = false;
+unsigned int Ecf::debug_level_ = 0;
+unsigned int Ecf::state_change_no_ = 0;
+unsigned int Ecf::modify_change_no_ = 0;
+
+const char* Ecf::SERVER_NAME() { static const char* SERVER_NAME = "ecflow_server"; return SERVER_NAME;}
+const char* Ecf::CLIENT_NAME() { static const char* CLIENT_NAME = "ecflow_client"; return CLIENT_NAME;}
+
+const std::string& Ecf::LOG_FILE() { static const std::string LOG_FILE = "ecf.log"; return LOG_FILE;}
+const std::string& Ecf::CHECKPT() { static const std::string CHECKPT= "ecf.check"; return CHECKPT;}
+const std::string& Ecf::BACKUP_CHECKPT() { static const std::string BACKUP_CHECKPT= "ecf.check.b";return BACKUP_CHECKPT;}
+const std::string& Ecf::MICRO() { static const std::string MICRO= "%";return MICRO;}
+const std::string& Ecf::JOB_CMD() { static const std::string JOB_CMD= "%ECF_JOB% 1> %ECF_JOBOUT% 2>&1";return JOB_CMD;}
+const std::string& Ecf::KILL_CMD() { static const std::string KILL_CMD= "kill -15 %ECF_RID%";return KILL_CMD;} // "${ECF_KILL:=/home/ma/emos/bin/ecfkill} %USER% %HOST% %ECF_RID% %ECF_JOB% > %ECF_JOB%.kill 2>&1";
+const std::string& Ecf::STATUS_CMD() { static const std::string STATUS_CMD= "ps --sid %ECF_RID% -f";return STATUS_CMD;}// "${ECF_STAT:=/home/ma/emos/bin/ecfstatus} %USER% %HOST% %ECF_RID% %ECF_JOB% > %ECF_JOB%.stat 2>&1";
+const std::string& Ecf::URL_CMD() { static const std::string URL_CMD= "${BROWSER:=firefox} -remote 'openURL(%ECF_URL_BASE%/%ECF_URL%)'";return URL_CMD;}
+const std::string& Ecf::URL_BASE() { static const std::string URL_BASE= "https://software.ecmwf.int";return URL_BASE;}
+const std::string& Ecf::URL() { static const std::string URL = "wiki/display/ECFLOW/Home";return URL;}
+
+
+unsigned int Ecf::incr_state_change_no() {
+ if ( server_ ) {
+ return ++state_change_no_;
+ }
+ return state_change_no_;
+}
+
+unsigned int Ecf::incr_modify_change_no() {
+
+ if ( server_ ) {
+ return ++modify_change_no_;
+ }
+ return modify_change_no_;
+}
+
+// =======================================================
+
+EcfPreserveChangeNo::EcfPreserveChangeNo()
+: state_change_no_(Ecf::state_change_no()),
+ modify_change_no_(Ecf::modify_change_no())
+{}
+
+EcfPreserveChangeNo::~EcfPreserveChangeNo()
+{
+ Ecf::set_state_change_no(state_change_no_);
+ Ecf::set_modify_change_no(modify_change_no_);
+}
+
diff --git a/ACore/src/Ecf.hpp b/ACore/src/Ecf.hpp
new file mode 100644
index 0000000..3037784
--- /dev/null
+++ b/ACore/src/Ecf.hpp
@@ -0,0 +1,92 @@
+#ifndef ECF_HPP_
+#define ECF_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #13 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Provides globals used by server for determining change
+//============================================================================
+
+#include <boost/noncopyable.hpp>
+#include <string>
+
+// class Ecf: This class is used in the server to determine incremental changes
+// to the data model. Each Node/attribute stores a state change no
+// When ever there is a change, we increment local state change
+// number with this global.
+// When making large scale changes, ie nodes added or deleted we use modify change no
+// Note: The client will need to at some point copy over the full defs
+// at this point the state change no add modify number is also copied.
+// The client passes these two number back to server, the server then
+// uses these two numbers to determine what's changed.
+//
+class Ecf : private boost::noncopyable {
+public:
+ /// Increment and then return state change no
+ static unsigned int incr_state_change_no() ;
+ static unsigned int state_change_no() { return state_change_no_; }
+ static void set_state_change_no(unsigned int x) { state_change_no_ = x;}
+
+ /// The modify_change_no_ is used for node addition and deletion and re-ordering
+ static unsigned int incr_modify_change_no();
+ static unsigned int modify_change_no() { return modify_change_no_; }
+ static void set_modify_change_no(unsigned int x) { modify_change_no_ = x;}
+
+ /// Returns true if we are on the server side.
+ /// Only in server side do we increment state/modify numbers
+ /// Also used in debug/test: Allows print to add know if in server/client
+ static bool server() { return server_;}
+
+ /// Should only be set by the server, made public so that testing can also set it
+ /// Only in server side do we increment state/modify numbers
+ static void set_server(bool f) { server_ = f;}
+
+ static bool debug_equality() { return debug_equality_;}
+ static void set_debug_equality(bool f) { debug_equality_ = f;}
+
+ // ECFLOW-99
+ static unsigned int debug_level() { return debug_level_;}
+ static void set_debug_level(unsigned int level) { debug_level_ = level;}
+
+ static const char* SERVER_NAME();
+ static const char* CLIENT_NAME();
+
+ static const std::string& LOG_FILE();
+ static const std::string& CHECKPT();
+ static const std::string& BACKUP_CHECKPT();
+ static const std::string& MICRO();
+ static const std::string& JOB_CMD();
+ static const std::string& KILL_CMD();
+ static const std::string& STATUS_CMD();
+ static const std::string& URL_CMD();
+ static const std::string& URL_BASE();
+ static const std::string& URL();
+
+private:
+
+ Ecf(){}
+ static bool server_;
+ static bool debug_equality_;
+ static unsigned int debug_level_;
+ static unsigned int state_change_no_;
+ static unsigned int modify_change_no_;
+};
+
+/// Make sure the Ecf number don't change
+class EcfPreserveChangeNo {
+public:
+ EcfPreserveChangeNo();
+ ~EcfPreserveChangeNo();
+private:
+ unsigned int state_change_no_;
+ unsigned int modify_change_no_;
+};
+#endif
diff --git a/ACore/src/EcfPortLock.hpp b/ACore/src/EcfPortLock.hpp
new file mode 100644
index 0000000..9b98c57
--- /dev/null
+++ b/ACore/src/EcfPortLock.hpp
@@ -0,0 +1,84 @@
+#ifndef ECF_PORT_LOCK_HPP_
+#define ECF_PORT_LOCK_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : This class is used in TEST only
+// It allows functionality to create a lock file file, so that different process
+// can avoid creating server with same port number
+//
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <boost/noncopyable.hpp>
+#include "boost/filesystem.hpp"
+#include "boost/filesystem/operations.hpp"
+#include <boost/lexical_cast.hpp>
+#include <sstream>
+#include <iostream>
+#include "File.hpp"
+
+namespace ecf {
+
+class EcfPortLock : private boost::noncopyable {
+public:
+
+ static bool is_free(int port)
+ {
+ std::string the_port = boost::lexical_cast<std::string>(port);
+ if (boost::filesystem::exists(port_file(the_port))) {
+ // std::cout << "EcfPortLock::is_free returning FALSE\n ";
+ return false;
+ }
+ // std::cout << "EcfPortLock::is_free returning TRUE\n ";
+ return true;
+ }
+
+ static void create(const std::string& the_port)
+ {
+ std::string the_file = port_file( the_port );
+// std::cout << "EcfPortLock::create " << the_file << " ---------------------------------------------------\n";
+ std::string errorMsg;
+ if (!ecf::File::create(the_file,"",errorMsg)) {
+ std::stringstream sb;
+ sb << "EcfPortLock::create_free_port_file : could not create file " << the_file;
+ throw std::runtime_error(sb.str());
+ }
+ }
+
+ static void remove(const std::string& the_port)
+ {
+ std::string the_file = port_file(the_port);
+// std::cout << "EcfPortLock::remove " << the_file << " --------------------------------------------------\n";
+ boost::filesystem::remove(the_file);
+ }
+
+private:
+ EcfPortLock();
+
+ static std::string port_file(const std::string& the_port)
+ {
+ // We need the *SAME* location so that different process find the same file.
+ // When going across compiler the root_build_dir is not sufficient
+ char* ecf_port_lock_dir = getenv("ECF_PORT_LOCK_DIR");
+ std::string path;
+ if (ecf_port_lock_dir) path = ecf_port_lock_dir;
+ else path = File::root_build_dir();
+
+ path += "/ECF_PORT_used_";
+ path += the_port;
+ path += ".lock";
+
+ return path;
+ }
+};
+}
+#endif
diff --git a/ACore/src/Extract.cpp b/ACore/src/Extract.cpp
new file mode 100644
index 0000000..e8788eb
--- /dev/null
+++ b/ACore/src/Extract.cpp
@@ -0,0 +1,125 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <boost/lexical_cast.hpp>
+#include <boost/date_time/posix_time/time_formatters.hpp> // requires boost date and time lib
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include "Extract.hpp"
+#include "Stl.hpp"
+#include "Str.hpp"
+
+#include <sstream>
+#include <fstream>
+
+//#define DEBUG_PARSER 1
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+using namespace boost::gregorian;
+
+template<class T>
+ostream& operator<<(ostream& os, const vector<T>& v) {
+ copy(v.begin(), v.end(), ostream_iterator<T>(cout, ","));
+ return os;
+}
+
+bool Extract::pathAndName(const std::string& token, std::string& path, std::string& name)
+{
+// cout << "Extract::pathAndName token = " << token << "\n";
+ // can have:
+ // /suite/family:obj path = /suite/family name = obj
+ // /suite/family path = /suite/family name =
+ // obj path = name = obj
+ if (token.empty()) return false;
+
+ size_t colonPos = token.find_first_of(':');
+ if (colonPos == string::npos) {
+ if (token[0] == '/') {
+ path = token; // token of the form /a/b/c, ie no name
+ }
+ else {
+ name = token;
+ }
+ }
+ else {
+ path = token.substr(0,colonPos);
+ name = token.substr(colonPos+1);
+ }
+
+// cout << "Extract::pathAndName token=" << token << " path= '" << path << "' name= '" << name << "'\n";
+ return true;
+}
+
+bool Extract::split_get_second(const std::string& str, std::string& ret,char separator)
+{
+ // HH:MM
+ // return MM;
+ size_t colonPos = str.find_first_of(separator);
+ if (colonPos == string::npos) return false;
+ ret = str.substr(colonPos+1);
+ return true;
+}
+
+/// extract integer or throw an std::runtime exception on failure
+int Extract::theInt( const std::string& token, const std::string& errorMsg )
+{
+ int the_int = -1;
+ try {
+ the_int = boost::lexical_cast< int >( token );
+ }
+ catch ( boost::bad_lexical_cast& e ) {
+ throw std::runtime_error(errorMsg );
+ }
+ return the_int;
+}
+
+/// extract YMD, integer of the form yyyymmdd
+int Extract::ymd(const std::string& ymdToken, std::string& errorMsg)
+{
+ if (ymdToken.size() != 8) throw std::runtime_error( errorMsg + " YMD must be 8 characters i.e yyyymmdd");
+
+ // Use date lib to check YMD
+ try { boost::gregorian::date(from_undelimited_string(ymdToken)); }
+ catch (std::exception& e) {
+ errorMsg += "\n";
+ errorMsg += e.what();
+ throw std::runtime_error( errorMsg + " YMD is not a valid date" );
+ }
+
+ return theInt(ymdToken,errorMsg);
+}
+
+int Extract::optionalInt( const std::vector<std::string>& lineTokens,
+ int pos,
+ int defaultValue,
+ const std::string& errorMsg )
+{
+ // token0 token1 token2 token3 size = 4
+ // pos0 pos1 pos2 pos3
+ //
+ // could have line of the form
+ // repeat integer variable 1 2 #a comment
+ // repeat integer variable 3 4 # a comment
+ // hence we must check the first character, and not the complete token
+
+ int the_int = defaultValue;
+ if (static_cast<int>(lineTokens.size()) >= pos+1 && lineTokens[pos][0] != '#' ) {
+
+ the_int = theInt(lineTokens[pos],errorMsg);
+ }
+ return the_int;
+}
diff --git a/ACore/src/Extract.hpp b/ACore/src/Extract.hpp
new file mode 100644
index 0000000..b32926f
--- /dev/null
+++ b/ACore/src/Extract.hpp
@@ -0,0 +1,57 @@
+#ifndef EXTRACT_HPP_
+#define EXTRACT_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <string>
+#include <vector>
+#include <boost/noncopyable.hpp>
+
+class Extract : private boost::noncopyable {
+public:
+
+ // token if of the form:
+ // /path/to/home:obj OR obj
+ // path = /path/to/home path = ""
+ // name = obj name = obj
+ // return true for ok or false for error
+ static bool pathAndName(const std::string& token, std::string& path, std::string& name);
+
+ // Given str = HH:MM
+ // return MM;
+ static bool split_get_second(const std::string& str, std::string& ret,char separator = ':');
+
+ /// extract integer or throw an std::runtime_error on failure,
+ /// the error message passed in is used to configure the returned exception
+ static int theInt(const std::string& token,const std::string& errorContext) ;
+
+ /// extract YMD, integer of the form yyyymmdd, will throw std::runtime_error on failure
+ /// the error message passed in is used to configure the returned exception
+ static int ymd(const std::string& token, std::string& errorContext);
+
+ /// extract optional int, else return -1
+ /// the error message passed in is used to configure the returned exception
+ // could have line of the form
+ // repeat integer variable 1 2 #a comment
+ // repeat integer variable 3 4 # a comment
+ // hence we must check the first character, and not the complete token
+ static int optionalInt(const std::vector<std::string>& lineTokens,
+ int pos,int defaultvalue,const std::string& errorContext);
+private:
+ Extract();
+};
+
+#endif
diff --git a/ACore/src/File.cpp b/ACore/src/File.cpp
new file mode 100644
index 0000000..652a42c
--- /dev/null
+++ b/ACore/src/File.cpp
@@ -0,0 +1,975 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #70 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : This class is used as a helper class
+//============================================================================
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+
+#include "boost/filesystem.hpp"
+#include "boost/filesystem/operations.hpp"
+#include <boost/token_functions.hpp>
+#include <boost/algorithm/string/trim.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/foreach.hpp>
+#include <boost/tokenizer.hpp>
+
+#include "File.hpp"
+#include "File_r.hpp"
+#include "Log.hpp"
+#include "NodePath.hpp"
+#include "Str.hpp"
+#include "Ecf.hpp"
+#include "ecflow_version.h"
+
+#ifdef CMAKE
+#include "ecflow_source_build_dir.h"
+#endif
+
+using namespace std;
+using namespace boost;
+namespace fs = boost::filesystem;
+
+//#define DEBUG_SERVER_PATH 1
+//#define DEBUG_CLIENT_PATH 1
+
+namespace ecf {
+
+size_t File::MAX_LINES() { return 10000; }
+const std::string& File::JOB_EXTN() { static const std::string JOB_EXTN = ".job"; return JOB_EXTN; }
+const std::string& File::MAN_EXTN() { static const std::string MAN_EXTN = ".man"; return MAN_EXTN; }
+const std::string& File::USR_EXTN() { static const std::string USR_EXTN = ".usr"; return USR_EXTN; }
+const std::string& File::ECF_EXTN() { static const std::string ECF_EXTN = ".ecf"; return ECF_EXTN; }
+
+
+/// Search for the file, in $PATH return the first path that matches or an empty file, if not
+std::string File::which(const std::string& file)
+{
+ std::string env_paths = getenv("PATH");
+ if (!env_paths.empty()) {
+ std::string path;
+ std::vector<std::string> paths;
+ Str::split(env_paths,paths,":");
+ size_t path_size = paths.size();
+ for(size_t i=0; i < path_size; ++i) {
+ path.clear();
+ path = paths[i];
+ path += '/';
+ path += file;
+ if (fs::exists(path)) {
+ return paths[i];
+ }
+ }
+ }
+ return std::string();
+}
+
+std::string File::getExt(const std::string& s)
+{
+ size_t i = s.rfind('.',s.length());
+ if (i != std::string::npos) {
+ return s.substr(i+1);
+ }
+ return string();
+}
+
+void File::replaceExt(std::string& file, const std::string& newExt)
+{
+ string::size_type i = file.rfind('.',file.length());
+ if (i != string::npos) file.replace(i+1,newExt.length(), newExt);
+}
+
+bool File::splitFileIntoLines(const std::string& filename, std::vector<std::string>& lines,bool ignoreEmptyLine)
+{
+ std::ifstream the_file(filename.c_str(),std::ios_base::in);
+ if ( !the_file ) return false;
+ lines.reserve(lines.size() + 100);
+
+ // Note if we use: while( getline( theEcfFile, line)), then we will miss the *last* *empty* line
+
+// int i = 0;
+ string line;
+ while ( std::getline(the_file,line) ) {
+// i++;
+// cout << i << ": " << line << "\n";
+ if (ignoreEmptyLine && line.empty()) continue;
+ lines.push_back(line);
+ }
+
+// METHOD1
+// Note Another way to split lines of a file was to use a tokenizer.
+// Much slower ~ 2.5 slower,
+// ifstream ifs(filename.c_str());
+// if (!ifs) return false;
+//
+// // Note: ss.str() returns a temporary std::string.
+// // boost::tokenizer stores a reference to the string.
+// // The temporary string is destroyed and tokenizer is left with a dangling reference.
+// // hence take a copy
+// std::stringstream ss; ss << ifs.rdbuf(); // Read the whole file into a string
+// std::string theFileAsString = ss.str(); // take a copy as ss.str() returns a temporary
+// // // while tokenizer stores a reference
+// if (ignoreEmptyLine) {
+// char_separator<char> sep("\n",0,boost::drop_empty_tokens);
+// typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+// tokenizer tokens(theFileAsString, sep);
+// std::copy(tokens.begin(), tokens.end(), back_inserter(lines));
+// }
+// else {
+// char_separator<char> sep("\n",0,boost::keep_empty_tokens);
+// typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+// tokenizer tokens(theFileAsString, sep);
+// std::copy(tokens.begin(), tokens.end(), back_inserter(lines));
+// }
+
+ // METHOD 2:
+ // Note: The implementation below is 2.5 times slower
+ // std::ifstream ifs(filename.c_str());
+ // if (!ifs) return false;
+ //
+ // std::istreambuf_iterator<char> file_iter(ifs);
+ // std::istreambuf_iterator<char> end_of_stream;
+ //
+ // typedef boost::tokenizer<boost::char_separator<char>,
+ // std::istreambuf_iterator<char> > tokenizer;
+ //
+ // boost::char_separator<char> sep("\n");
+ // tokenizer tokens(file_iter,end_of_stream, sep);
+ // std::copy(tokens.begin(), tokens.end(), back_inserter(lines));
+
+ // The current implementation is 2.5 times faster then method 1, and ~4 times faster than method 2
+ return true;
+}
+
+
+std::string File::get_last_n_lines(const std::string& filename,int last_n_lines, std::string& error_msg)
+{
+ if ( last_n_lines <= 0 ) return string();
+
+ std::ifstream source( filename.c_str(), std::ios_base::in );
+ if (!source) {
+ error_msg = "File::get_last_n_lines: Could not open file " + filename;
+ return string();
+ }
+
+ size_t const granularity = 100 * last_n_lines;
+ source.seekg( 0, std::ios_base::end );
+ size_t size = static_cast<size_t>( source.tellg() );
+ std::vector<char> buffer;
+ int newlineCount = 0;
+ while ( source
+ && buffer.size() != size
+ && newlineCount < last_n_lines ) {
+ buffer.resize( std::min( buffer.size() + granularity, size ) );
+ source.seekg( -static_cast<std::streamoff>( buffer.size() ),
+ std::ios_base::end );
+#if defined(HPUX) || defined(_AIX)
+ source.read( &(buffer.front()), buffer.size() );
+#else
+ source.read( buffer.data(), buffer.size() );
+#endif
+ newlineCount = std::count( buffer.begin(), buffer.end(), '\n');
+ }
+
+ std::vector<char>::iterator start = buffer.begin();
+ while ( newlineCount > last_n_lines ) {
+ start = std::find( start, buffer.end(), '\n' ) + 1;
+ -- newlineCount;
+ }
+
+ //std::vector<char>::iterator end = remove( start, buffer.end(), '\r' ); // for windows
+ return std::string( start, buffer.end() );
+}
+
+
+std::string File::get_first_n_lines(const std::string& filename,int n_lines, std::string& error_msg)
+{
+ if ( n_lines <= 0 ) return string();
+
+ std::ifstream source( filename.c_str(), std::ios_base::in );
+ if (!source) {
+ error_msg = "File::get_first_n_lines: Could not open file " + filename;
+ return string();
+ }
+
+ std::string ret; ret.reserve(1024);
+ std::string line;
+
+ int count = 0;
+ while ( std::getline(source,line) && count < n_lines) {
+
+ ret += line;
+ ret += "\n";
+ count++;
+ }
+
+ return ret;
+}
+
+/// Opens the file and returns the contents
+bool File::open(const std::string& filePath, std::string& contents)
+{
+ std::ifstream infile( filePath.c_str() , std::ios_base::in);
+ if ( ! infile) return false;
+
+ std::ostringstream temp;
+ temp << infile.rdbuf();
+ contents = temp.str();
+ return true;
+}
+
+//std::string File::tmpFile(std::string& contents)
+//{
+//
+//}
+
+
+bool File::create(const std::string& filename,const std::vector<std::string>& lines, std::string& errorMsg)
+{
+ // For very large file. This is about 1 second quicker. Than using streams
+ // See Test: TestFile.cpp:test_file_create_perf
+ FILE * theFile = fopen (filename.c_str(),"w");
+ if (theFile==NULL) {
+ std::stringstream ss;
+ ss << "Could not create file '" << filename << "'\n";
+ errorMsg += ss.str();
+ return false;
+ }
+ size_t size = lines.size();
+ for (size_t i = 0; i < size; ++i) {
+ if (i != 0) {
+ if (fputs("\n",theFile) == EOF) {
+ std::stringstream ss;
+ ss << "Could not write to file '" << filename << "'\n";
+ errorMsg += ss.str();
+ fclose (theFile);
+ return false;
+ }
+ }
+ if (fputs(lines[i].c_str(),theFile) == EOF) {
+ std::stringstream ss;
+ ss << "Could not write to file '" << filename << "'\n";
+ errorMsg += ss.str();
+ fclose (theFile);
+ return false;
+ }
+ }
+ fclose (theFile);
+
+// std::ofstream theFile( filename.c_str() );
+// if ( !theFile ) {
+// /// Could be: [ no permissions | file system full | locked by another process ]
+// std::stringstream ss;
+// ss << "Could not create file '" << filename << "'\n";
+// errorMsg += ss.str();
+// return false;
+// }
+// size_t size = lines.size();
+// for (size_t i = 0; i < size; ++i) {
+// if (i != 0) theFile << "\n";
+// theFile << lines[i];
+// }
+// if (!theFile.good()) {
+// std::stringstream ss;
+// ss << "Could not write to file '" << filename << "'\n";
+// errorMsg += ss.str();
+// theFile.close();
+// return false;
+// }
+// theFile.close();
+
+ return true;
+}
+
+bool File::create(const std::string& filename, const std::string& contents, std::string& errorMsg)
+{
+ std::ofstream theFile( filename.c_str() );
+ if ( !theFile ) {
+ std::stringstream ss;
+ ss << "Could not create file '" << filename << "'\n";
+ errorMsg += ss.str();
+ return false;
+ }
+
+ theFile << contents;
+ if (!theFile.good()) {
+ std::stringstream ss;
+ ss << "Could not write to file '" << filename << "'\n";
+ errorMsg += ss.str();
+ theFile.close();
+ return false;
+ }
+ theFile.close();
+
+ // This is actually 12% slower for large file:
+// FILE * theFile = fopen (filename.c_str(),"w");
+// if (theFile==NULL) {
+// std::stringstream ss;
+// ss << "Could not create file '" << filename << "'\n";
+// errorMsg += ss.str();
+// return false;
+// }
+// if (fputs(contents.c_str(),theFile) == EOF) {
+// std::stringstream ss;
+// ss << "Could not write to file '" << filename << "'\n";
+// errorMsg += ss.str();
+// fclose (theFile);
+// return false;
+// }
+// fclose (theFile);
+ return true;
+}
+
+bool File::find(
+ const boost::filesystem::path& dir_path, // from this directory downwards,
+ const std::string& file_name, // search for this name,
+ boost::filesystem::path& path_found // placing path here if found
+ )
+{
+// std::cout << "Searching '" << dir_path << "' for " << file_name << "\n";
+ if ( !fs::exists( dir_path ) )
+ return false;
+
+ fs::directory_iterator end_itr; // default construction yields past-the-end
+ for (fs::directory_iterator itr( dir_path ); itr != end_itr; ++itr) {
+
+ if ( fs::is_directory( itr->status() ) ) {
+
+ if ( File::find( itr->path(), file_name, path_found ) )
+ return true;
+ }
+ else if ( itr->path().filename() == file_name ) // see below
+ {
+ path_found = itr->path();
+ return true;
+ }
+ }
+ return false;
+}
+
+void File::findAll(
+ const boost::filesystem::path& dir_path, // from this directory downwards
+ const std::string& file_name, // search for this name,
+ std::vector<boost::filesystem::path>& paths_found // placing path here if found
+ )
+{
+ if ( !fs::exists( dir_path ) ) return;
+
+ fs::directory_iterator end_itr; // default construction yields past-the-end
+ for (fs::directory_iterator itr( dir_path ); itr != end_itr; ++itr) {
+
+ if ( fs::is_directory( itr->status() ) ) {
+
+ findAll( itr->path(), file_name, paths_found ) ;
+ }
+ else if ( itr->path().filename() == file_name ) // see below
+ {
+ paths_found.push_back( itr->path() );
+ }
+ }
+}
+
+std::string File::findPath(
+ const boost::filesystem::path& dir_path, // from this directory downwards
+ const std::string& file_name, // search for this name,
+ const std::string& leafDir // path must contain this string
+ )
+{
+ std::vector< fs::path > paths;
+ File::findAll( dir_path, file_name, paths );
+ if ( !paths.empty() ) {
+
+ // find the path that has leafDir in it.
+ BOOST_FOREACH(fs::path path, paths) {
+ std::string thePath = path.string();
+ if (thePath.rfind(leafDir) != std::string::npos) return thePath;
+ }
+ }
+ return std::string();
+}
+
+
+std::string File::findPath(
+ const boost::filesystem::path& dir_path, // from this directory downwards
+ const std::string& file_name, // search for this name,
+ const std::vector<std::string>& tokens // path must contain all these tokens
+)
+{
+ std::vector< fs::path > paths;
+ File::findAll( dir_path, file_name, paths );
+ if ( !paths.empty() ) {
+
+ // find the path that has all the tokens specified by the vector tokens
+ BOOST_FOREACH(fs::path path, paths) {
+ std::string thePath = path.string();
+ size_t matches = 0;
+ BOOST_FOREACH(const std::string& required_path_tokens, tokens) {
+ if (thePath.rfind(required_path_tokens) != std::string::npos) matches++;
+ }
+ if (matches == tokens.size()) return thePath;
+ }
+ }
+ return std::string();
+}
+
+//#define INTEL_DEBUG_ME 1
+bool File::createMissingDirectories(const std::string& pathToFileOrDir)
+{
+#ifdef INTEL_DEBUG_ME
+ std::cout << "File::createMissingDirectories " << pathToFileOrDir << std::endl;
+#endif
+ if (pathToFileOrDir.empty()) return false;
+
+ // Avoid making unnecessary system calls, by checking to see if directory exists first
+ fs::path fs_path(pathToFileOrDir);
+ if (fs_path.extension().empty()) {
+
+#ifdef INTEL_DEBUG_ME
+ std::cout << " pure directory no extension" << std::endl;
+#endif
+ // pure directory
+ if (fs::exists(pathToFileOrDir)) {
+
+#ifdef INTEL_DEBUG_ME
+ std::cout << " " << pathToFileOrDir << " already exists " << std::endl;
+#endif
+
+ return true;
+ }
+ }
+ else {
+
+#ifdef INTEL_DEBUG_ME
+ std::cout << " pure directory *has* extension" << std::endl;
+#endif
+ // could be /tmp/fred/sms.job, see if /tmp/fred exists
+ if (fs::exists(fs_path.parent_path())) {
+
+#ifdef INTEL_DEBUG_ME
+ std::cout << " " << pathToFileOrDir << " already exists " << std::endl;
+#endif
+ return true;
+ }
+ }
+
+ std::vector<std::string> thePath;
+ NodePath::split(pathToFileOrDir, thePath);
+ try {
+ if ( !thePath.empty() ) {
+
+#ifdef INTEL_DEBUG_ME
+ std::cout << " last file " << thePath.back() << std::endl;
+#endif
+
+ // pathToFileOrDir is of form: /tmp/fred/sms.job
+ // we should only create directories for /tmp/fred
+ if ( thePath.back().find( "." ) != std::string::npos ) {
+ // assume the last token represents a file, hence dont create a directory
+#ifdef INTEL_DEBUG_ME
+ std::cout << " last file " << thePath.back() << " has a *dot* ignoring "<< std::endl;
+#endif
+ thePath.pop_back();
+ }
+
+ std::string pathToCreate;
+
+ // if original path had leading slash then add it here, to preserve path
+ if (pathToFileOrDir[0] == '/') pathToCreate += Str::PATH_SEPERATOR();
+
+ for (size_t i = 0; i < thePath.size(); i++) {
+ pathToCreate += thePath[i];
+ if ( !fs::exists( pathToCreate ) ) {
+#ifdef INTEL_DEBUG_ME
+ std::cout << " " << pathToCreate << " does not exist, creating directory " << std::endl;
+#endif
+ fs::create_directory( pathToCreate );
+ }
+ pathToCreate += Str::PATH_SEPERATOR();
+ }
+ }
+ else {
+#ifdef INTEL_DEBUG_ME
+ std::cout << " NO path component in " << pathToFileOrDir << std::endl;
+#endif
+
+ if ( pathToFileOrDir.find( "." ) != std::string::npos ) {
+ // assume represents a file, hence don't create a directory fred.job1
+#ifdef INTEL_DEBUG_ME
+ std::cout << " assuming " << pathToFileOrDir << " is a file, found a dot, returning without creating dir " << std::endl;
+#endif
+ return true;
+ }
+
+ // assume is a dir
+#ifdef INTEL_DEBUG_ME
+ std::cout << " about to create dir " << pathToFileOrDir << std::endl;
+#endif
+
+ fs::create_directory( pathToFileOrDir );
+ }
+ }
+ catch ( const std::exception & ex ) {
+#ifdef INTEL_DEBUG_ME
+ std::cout << " Exception " << ex.what() << " could not create dir " << pathToFileOrDir << std::endl;
+#endif
+ return false;
+ }
+ return true;
+}
+
+
+/// Create directories the boost way, with additional check to see if directories exist first
+bool File::createDirectories(const std::string& pathToDir)
+{
+ if (pathToDir.empty()) return false;
+ if (fs::exists(pathToDir)) return true;
+
+ try {
+ return fs::create_directories(pathToDir);
+ }
+ catch (std::exception&) {}
+ return false;
+}
+
+/// Returns the difference between 2 files.
+std::string File::diff(const std::string& file,
+ const std::string& file2,
+ const std::vector<std::string>& ignoreVec,
+ std::string& errorMsg,
+ bool ignoreBlanksLine)
+{
+ if (!fs::exists(file)) {
+ errorMsg += "First argument File " + file + " does not exist";
+ return std::string();
+ }
+ if (!fs::exists(file2)) {
+ errorMsg += "Second argument File " + file2 + " does not exist";
+ return std::string();
+ }
+
+ std::vector<std::string> fileLines;
+ std::vector<std::string> file2Lines;
+
+ if (!splitFileIntoLines(file, fileLines, ignoreBlanksLine)) {
+ errorMsg += "First argument File " + file + " could not be opened";
+ return std::string();
+ }
+ if (!splitFileIntoLines(file2, file2Lines, ignoreBlanksLine)) {
+ errorMsg += "Second argument File " + file2 + " could not be opened";
+ return std::string();
+ }
+
+ if ( fileLines != file2Lines) {
+ std::stringstream ss;
+ if (fileLines.size() != file2Lines.size()) ss << "Expected size " << file2Lines.size() << " but found " << fileLines.size() <<"\n";
+
+ for(size_t i=0; i < fileLines.size() || i < file2Lines.size(); ++i) {
+
+ if (i < fileLines.size() && i < file2Lines.size()) {
+
+ if (fileLines[i] != file2Lines[i]) {
+ bool doIgnore = false;
+ BOOST_FOREACH(const std::string& ignore, ignoreVec) {
+ if ( fileLines[i].find(ignore) != std::string::npos || file2Lines[i].find(ignore) != std::string::npos ) {
+ doIgnore = true; break;
+ }
+ }
+ if (doIgnore) continue;
+ ss << "Mismatch at " << i << "(" << fileLines[i] << ") ----> (" << file2Lines[i] << ")\n";
+ }
+// else {
+// ss << " " << i << " (" << fileLines[i] << ") ----> (" << file2Lines[i] << ")\n";
+// }
+ }
+ else {
+ ss << "Mismatch at " << i ;
+ if (i < fileLines.size() ) ss << " (" << fileLines[i] << ") ";
+ else ss << " ( ---- ) ";
+
+ if (i < file2Lines.size()) ss << "(" << file2Lines[i] << ")\n";
+ else ss << "( --- )\n";
+ }
+ }
+ return ss.str();
+ }
+ return std::string();
+}
+
+std::string File::backwardSearch( const std::string& rootPath, const std::string& nodePath, const std::string& fileExtn )
+{
+ // Do a backward search of rootPath + nodePath
+ // If task path if of the form /suite/family/family2/task, then we keep
+ // on consuming the first path token this should leave:
+ // <root-path>/suite/family/family2/task.ecf
+ // <root-path>/family/family2/task.ecf
+ // <root-path>/family2/task.ecf
+ // <root-path>/task.ecf
+ // See page 21 of SMS user guide
+
+ vector<std::string> nodePathTokens;
+ NodePath::split(nodePath, nodePathTokens);
+ LOG_ASSERT(!nodePathTokens.empty(),"");
+
+ std::string leafName; // i.e. task in the example above
+ if ( !nodePathTokens.empty() ) leafName = nodePathTokens[ nodePathTokens.size() -1 ] ;
+
+#ifdef DEBUG_TASK_LOCATION
+ cout << "backwardSearch Node " << nodePath << " using root path " << rootPath << " nodePathTokens.size() = " << nodePathTokens.size() << "\n";
+#endif
+ while ( nodePathTokens.size() > 0 ) {
+
+ // Reconstitute the path
+ std::string path = NodePath::createPath( nodePathTokens ) ;
+ path += fileExtn; // .ecf, .man , etc
+
+ std::string combinedPath = rootPath;
+ combinedPath += path;
+
+ try {
+ if ( fs::exists( combinedPath )) {
+#ifdef DEBUG_TASK_LOCATION
+ cout << "backwardSearch Node " << nodePath << " the path " << combinedPath << " exists\n";
+#endif
+ return combinedPath;
+ }
+#ifdef DEBUG_TASK_LOCATION
+ else cout << " backwardSearch Node " << nodePath << " the path " << combinedPath << " DOEST NOT EXIST\n";
+#endif
+ }
+ catch (fs::filesystem_error& e) {
+#ifdef DEBUG_TASK_LOCATION
+ std::cout << "Task::backwardSearch Caught exception for fs::exists('" << combinedPath <<"')\n" << e.what() << "\n";
+#endif
+ }
+
+ nodePathTokens.erase(nodePathTokens.begin()); // consume first path token
+ }
+
+ // Look for file in the root path
+ std::string ecf_file = leafName + fileExtn;
+ fs::path ecf_filePath = fs::path( fs::path(rootPath) / ecf_file );
+ if (fs::exists(ecf_filePath)) {
+#ifdef DEBUG_TASK_LOCATION
+ std::cout << "backwardSearch Node " << leafName << " Found " << ecf_file << " in root path '" << rootPath << "'\n";
+#endif
+ std::string result = ecf_filePath.string(); // is returned by reference hence must take a copy
+ return result ;
+ }
+
+ // failed to find file via backward search
+ return string();
+}
+
+// Remove a directory recursively ****
+bool File::removeDir( const boost::filesystem::path& p)
+{
+ try {
+ fs::directory_iterator end;
+ for(fs::directory_iterator it(p); it != end; ++it) {
+ if (fs::is_directory(*it)) {
+ if (!removeDir(*it)) {
+ return false;
+ }
+ }
+ else {
+ fs::remove(*it);
+ }
+ }
+ }
+ catch (fs::filesystem_error& e) {
+ return false;
+ }
+
+ // Finally remove dir itself
+ fs::remove(p);
+
+ return true;
+}
+
+// =======================================================================================================
+// bjam
+// =======================================================================================================
+#ifndef CMAKE
+
+static std::string bjam_workspace_dir()
+{
+ // We need the *SAME* location so that different process find the same file. Get to the workspace directory
+ boost::filesystem::path current_path = boost::filesystem::current_path();
+ std::string stem = current_path.stem().string();
+ int count = 0;
+ while( stem.find("ecflow") == std::string::npos) {
+ current_path = current_path.parent_path();
+ stem = current_path.stem().string();
+ count++;
+ if (count == 100) {
+ char* workspace = getenv("WK");
+ if (workspace == NULL) {
+ throw std::runtime_error("File::bjam_workspace_dir() failed to find ecflow in a directory name, up the directory tree and WK undefined");
+ }
+ std::string the_workspace_dir = workspace;
+ return the_workspace_dir;
+ }
+ }
+ std::string the_workspace_dir = current_path.string(); // cos string is returned by reference
+ return the_workspace_dir;
+}
+
+static std::string find_bjam_ecf_server_path()
+{
+#ifdef DEBUG_SERVER_PATH
+ cout << " File::find_ecf_server_path() using bjam\n";
+#endif
+
+ // bjam uses in source tree, for build, which is in the workspace dir
+ std::string bin_dir = bjam_workspace_dir() + "/Server/bin/";
+
+#ifdef DEBUG_SERVER_PATH
+ cout << " Searching under: " << bin_dir << "\n";
+#endif
+
+ // We need to take into account that on linux, we may have the GNU and CLANG executables
+ // Hence we need to distinguish between them.
+ std::vector<std::string> required_path_tokens;
+
+ // We have 3 variants debug,release,profile
+#ifdef DEBUG
+
+ required_path_tokens.push_back(std::string("debug"));
+#if defined(__clang__)
+ required_path_tokens.push_back(std::string("clang"));
+#endif
+
+ return File::findPath( bin_dir, Ecf::SERVER_NAME(), required_path_tokens );
+
+#else
+
+ required_path_tokens.push_back(std::string("release"));
+#if defined(__clang__)
+ required_path_tokens.push_back(std::string("clang"));
+#endif
+
+ std::string path = File::findPath( bin_dir, Ecf::SERVER_NAME(), required_path_tokens );
+ if (path.empty()) {
+
+ required_path_tokens.clear();
+ required_path_tokens.push_back(std::string("profile"));
+#if defined(__clang__)
+ required_path_tokens.push_back(std::string("clang"));
+#endif
+
+ path = File::findPath( bin_dir, Ecf::SERVER_NAME(), required_path_tokens );
+ }
+ return path;
+#endif
+}
+
+static std::string find_bjam_ecf_client_path()
+{
+#ifdef DEBUG_CLIENT_PATH
+ cout << " find_bjam_ecf_client_path \n";
+#endif
+
+ // Bjam uses, in source build
+ std::string binDir = bjam_workspace_dir() + "/Client/bin/";
+
+ // We need to take into account that on linux, we may have the GNU and CLANG executables
+ // Hence we need to distinguish between them.
+ std::vector<std::string> required_path_tokens;
+
+ // We have 3 variants debug,release,profile
+#ifdef DEBUG
+
+ required_path_tokens.push_back(std::string("debug"));
+#if defined(__clang__)
+ required_path_tokens.push_back(std::string("clang"));
+#endif
+
+ return File::findPath( binDir, Ecf::CLIENT_NAME(), required_path_tokens );
+
+#else
+
+ required_path_tokens.push_back(std::string("release"));
+#if defined(__clang__)
+ required_path_tokens.push_back(std::string("clang"));
+#endif
+
+ std::string path = File::findPath( binDir, Ecf::CLIENT_NAME(), required_path_tokens );
+ if (path.empty()) {
+
+ required_path_tokens.clear();
+ required_path_tokens.push_back(std::string("profile"));
+#if defined(__clang__)
+ required_path_tokens.push_back(std::string("clang"));
+#endif
+
+ path = File::findPath( binDir, Ecf::CLIENT_NAME(), required_path_tokens );
+ }
+ return path;
+#endif
+}
+#endif
+
+
+
+std::string File::find_ecf_server_path()
+{
+#ifdef CMAKE
+ std::string path = CMAKE_ECFLOW_BUILD_DIR;
+ path += "/bin/";
+ path += Ecf::SERVER_NAME();
+
+#ifdef DEBUG_SERVER_PATH
+ cout << " File::find_ecf_server_path() path = " << path << "\n";
+#endif
+
+ return path;
+
+#else
+
+ return find_bjam_ecf_server_path();
+#endif
+}
+
+std::string File::find_ecf_client_path()
+{
+#ifdef CMAKE
+ std::string path = CMAKE_ECFLOW_BUILD_DIR;
+ path += "/bin/";
+ path += Ecf::CLIENT_NAME();
+
+#ifdef DEBUG_CLIENT_PATH
+ cout << " File::find_ecf_client_path() returning path " << path << "\n";
+#endif
+
+ return path;
+
+#else
+
+ return find_bjam_ecf_client_path();
+#endif
+}
+
+
+std::string File::test_data(const std::string& rel_path, const std::string& dir)
+{
+ std::string test_file;
+ char* work_space = getenv("WK"); // for ecbuild
+ if (work_space != NULL ) {
+ test_file = std::string(work_space);
+ if (!rel_path.empty() && rel_path[0] != '/' ) test_file += "/";
+ test_file += rel_path;
+ }
+ else {
+ std::string work_space = root_source_dir();
+ if (!work_space.empty()) {
+ test_file = work_space;
+ if (!rel_path.empty() && rel_path[0] != '/' ) test_file += "/";
+ test_file += rel_path;
+ }
+ else {
+ fs::path current_path = fs::current_path();
+ if (current_path.stem() == dir ) {
+
+ // remove first path, expecting "dir/path/path1" remove dir
+ std::string::size_type pos = rel_path.find("/",1); // skip over any leading /
+ if (pos != std::string::npos) {
+ test_file += rel_path.substr(pos+1); // skip over '/' to be left with path/path1, making it relative
+ }
+ else {
+ test_file += rel_path;
+ }
+ }
+ else {
+ test_file += rel_path;
+ }
+ }
+ }
+ return test_file;
+}
+
+
+std::string File::root_source_dir()
+{
+#ifdef CMAKE
+ return CMAKE_ECFLOW_SOURCE_DIR;
+#endif
+
+ // bjam
+ fs::path current_path = fs::current_path();
+ std::string the_current_path = current_path.string();
+ std::string version_cmake = the_current_path + "/VERSION.cmake";
+ if (fs::exists(version_cmake)) {
+ return the_current_path;
+ }
+
+ std::string stem = current_path.stem().string();
+ int count = 0;
+ while( stem.find("ecflow") == std::string::npos) {
+ current_path = current_path.parent_path();
+
+ // bjam
+ std::string version_cmake = std::string(current_path.string()) + "/VERSION.cmake";
+ if (fs::exists(version_cmake)) {
+ std::string the_root_source_dir = current_path.string(); // cos current_path.string() is returned by reference
+ return the_root_source_dir;
+ }
+
+ stem = current_path.stem().string();
+ count++;
+ if (count == 1000) break;
+ }
+ return string();
+}
+
+std::string File::root_build_dir()
+{
+ fs::path current_path = fs::current_path();
+ std::string the_current_path = current_path.string();
+
+ // bjam
+ std::string version_cmake = the_current_path + "/VERSION.cmake";
+ if (fs::exists(version_cmake)) return the_current_path;
+
+ // cmake
+ std::string cmake_cache = the_current_path + "/CMakeCache.txt";
+ if (fs::exists(cmake_cache)) return the_current_path;
+
+
+ // bjam or cmake
+ std::string stem = current_path.stem().string();
+ int count = 0;
+ while( stem.find("ecflow") == std::string::npos) {
+ current_path = current_path.parent_path();
+
+ the_current_path = current_path.string(); // cos current_path.string() is returned by reference
+
+ // bjam
+ std::string version_cmake = the_current_path + "/VERSION.cmake";
+ if (fs::exists(version_cmake)) return the_current_path;
+
+ // cmake
+ std::string cmake_cache = the_current_path + "/CMakeCache.txt";
+ if (fs::exists(cmake_cache)) return the_current_path;
+
+ stem = current_path.stem().string();
+ count++;
+ if (count == 1000) throw std::runtime_error("File::root_build_dir() failed to find ecflow in a directory name, up the directory tree");
+ }
+
+ throw std::runtime_error("File::root_build_dir() failed to find root build directory");
+ return std::string();
+}
+
+
+}
diff --git a/ACore/src/File.hpp b/ACore/src/File.hpp
new file mode 100644
index 0000000..7bab2a0
--- /dev/null
+++ b/ACore/src/File.hpp
@@ -0,0 +1,154 @@
+#ifndef FILE_HPP_
+#define FILE_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #41 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : This class is used as a helper class for file utilities
+//============================================================================
+
+#include <boost/noncopyable.hpp>
+#include <boost/filesystem/path.hpp>
+#include <string>
+#include <vector>
+
+
+namespace ecf {
+
+class File : private boost::noncopyable {
+public:
+
+ static size_t MAX_LINES(); // max number of lines, default to 10000
+ static const std::string& JOB_EXTN(); // ".job"
+ static const std::string& MAN_EXTN(); // ".man"
+ static const std::string& USR_EXTN(); // ".usr"
+ static const std::string& ECF_EXTN(); // ".ecf"
+
+ /// Search for the file, in $PATH return the first path that matches or an empty file, if not
+ static std::string which(const std::string& file);
+
+ /// expect string of the form ".ecf" or ".sms"
+ static void set_ecf_extn(const std::string&);
+ static const std::string& ecf_extn(); // return ".ecf" | ".sms" | ".py"
+
+ /// return the file extension
+ static std::string getExt(const std::string& file);
+
+ /// replace file extension with a new one
+ static void replaceExt(std::string& file, const std::string& newExt);
+
+ /// returns the input files, split into a vector of string, where each string
+ /// represent a line in the file. returns true if file open ok , false otherwise
+ /// The additional parameter ignoreEmptyLine can be used to ignore empty lines
+ /// **Always reads _WHOLE_ file. Not suitable for very large files **
+ static bool splitFileIntoLines(const std::string& filename, std::vector<std::string>& lines, bool ignoreEmptyLine = false);
+
+ /// This is suitable for large files. > several gigabytes, since it does load the entire file
+ static std::string get_last_n_lines(const std::string& filename,int last_n_lines, std::string& error_msg);
+
+ /// returns the first n line of a file, does not read all the file, hence suitable for very large files
+ static std::string get_first_n_lines(const std::string& filename,int n_lines, std::string& error_msg);
+
+ /// Opens the file and returns the contents
+ static bool open(const std::string& filePath, std::string& contents);
+
+ /// Given a file spath, and a vector of lines, creates a file. returns true if success
+ /// else returns false and an error message
+ static bool create(const std::string& filename, const std::vector<std::string>& lines, std::string& errorMsg);
+ static bool create(const std::string& filename, const std::string& contents, std::string& errorMsg);
+
+ /// recursively look for a file, given a starting directory
+ /// Return the first file that matches
+ /// return true if file found false otherwise
+ static bool find(
+ const boost::filesystem::path& dir_path, // from this directory downwards
+ const std::string& file_name, // search for this name,
+ boost::filesystem::path& path_found // placing path here if found
+ );
+
+ /// recursively look for a file, given a starting directory
+ /// Returns _ALL_ files that match
+ static void findAll(
+ const boost::filesystem::path& dir_path, // from this directory downwards
+ const std::string& file_name, // search for this name,
+ std::vector<boost::filesystem::path>& paths_found // placing path here if found
+ );
+
+
+ /// recursively look for a file, given a starting directory and path token
+ /// Returns the first match found
+ static std::string findPath(
+ const boost::filesystem::path& dir_path, // from this directory downwards
+ const std::string& file_name, // search for this name,
+ const std::string& leafDir // path must contain this string
+ );
+
+ static std::string findPath(
+ const boost::filesystem::path& dir_path, // from this directory downwards
+ const std::string& file_name, // search for this name,
+ const std::vector<std::string>& tokens // path must contain all these tokens
+ );
+
+ /// Create missing directories. This is *NOT* the same as boost::create_directories
+ /// as that only works with directories. This function assumes that if a "." exist
+ /// in the string it represents a file.
+ /// Hence this function handles:
+ /// /tmp/some/dir/fred.job // i.e the directories /tmp/some/dir/ will be created
+ /// /tmp/some/dir
+ /// fred // will create the directory fred
+ /// fred.job // just return true
+ static bool createMissingDirectories(const std::string& pathToFileOrDir);
+
+ /// Create directories the boost way, with additional check to see if directories exist first
+ static bool createDirectories(const std::string& pathToDir);
+
+ /// Returns the difference between 2 files.
+ /// Ignore lines that contain strings in the ignoreVec
+ static std::string diff(const std::string& file,
+ const std::string& file2,
+ const std::vector<std::string>& ignoreVec,
+ std::string& errorMsg,
+ bool ignoreBlanksLine = true);
+
+ /// Do a backward search of rootPath + nodePath + fileExtn
+ /// If task path if of the form /suite/family/family2/task, then we keep
+ /// on consuming the first path token this should leave:
+ /// <root-path>/suite/family/family2/task.ecf
+ /// <root-path>/family/family2/task.ecf
+ /// <root-path>/family2/task.ecf
+ /// <root-path>/task.ecf
+ /// See page 21 of SMS user guide
+ //
+ /// Returns an empty string if file not found
+ static std::string backwardSearch( const std::string& rootPath, const std::string& nodePath, const std::string& fileExtn );
+
+ // Remove a directory recursively ****
+ static bool removeDir( const boost::filesystem::path& p);
+
+
+ // Locate the path to the server exe
+ static std::string find_ecf_server_path();
+
+ // Locate the path to the client exe
+ static std::string find_ecf_client_path();
+
+ // Locate test data
+ static std::string test_data(const std::string& rel_path, const std::string& dir);
+
+ // return root source
+ static std::string root_source_dir();
+ static std::string root_build_dir();
+};
+
+}
+
+#endif /* FILE_HPP_ */
diff --git a/ACore/src/File_r.cpp b/ACore/src/File_r.cpp
new file mode 100644
index 0000000..a073d80
--- /dev/null
+++ b/ACore/src/File_r.cpp
@@ -0,0 +1,24 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : This class is used as a helper class
+//============================================================================
+
+#include <iostream>
+#include "File_r.hpp"
+
+using namespace std;
+using namespace ecf;
+
+File_r::File_r(const std::string& file_name) : file_name_(file_name), fp_(file_name.c_str(), std::ios_base::in) {}
+File_r::~File_r() { fp_.close(); }
+
diff --git a/ACore/src/File_r.hpp b/ACore/src/File_r.hpp
new file mode 100644
index 0000000..ad3d067
--- /dev/null
+++ b/ACore/src/File_r.hpp
@@ -0,0 +1,42 @@
+#ifndef FILE_R_HPP_
+#define FILE_R_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : This class is used as a helper class for file utilities
+//============================================================================
+
+#include <boost/noncopyable.hpp>
+#include <string>
+#include <fstream>
+
+namespace ecf {
+
+class File_r : private boost::noncopyable {
+public:
+ File_r(const std::string& file_name);
+ ~File_r();
+
+ bool ok() const { return (fp_) ? true : false; }
+ bool good() const { return fp_.good(); }
+ void getline(std::string& line) { std::getline(fp_,line); }
+ const std::string& file_name() const { return file_name_; }
+
+private:
+ std::string file_name_;
+ std::ifstream fp_;
+};
+
+}
+
+#endif
diff --git a/ACore/src/Host.cpp b/ACore/src/Host.cpp
new file mode 100644
index 0000000..9800f54
--- /dev/null
+++ b/ACore/src/Host.cpp
@@ -0,0 +1,93 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #8 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : This class is used as a helper class
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <unistd.h> // for gethostname
+#include <stdexcept>
+#include "Host.hpp"
+#include "Str.hpp"
+#include "Ecf.hpp"
+
+using namespace std;
+
+namespace ecf {
+
+Host::Host() {
+ get_host_name();
+}
+
+Host::Host(const std::string& host)
+: the_host_name_(host)
+{
+ if (the_host_name_ == Str::LOCALHOST()) {
+ get_host_name();
+ }
+}
+
+void Host::get_host_name() {
+ char hostNameArray[255];
+ if (gethostname(hostNameArray,255) != -1) {
+ the_host_name_ = string(hostNameArray);
+ }
+ else {
+ std::runtime_error("Host::Host() failed, could not get host name?\n");
+ }
+}
+
+std::string Host::name() const { return the_host_name_; }
+
+std::string Host::ecf_log_file(const std::string& port) const
+{
+ return prefix_host_and_port(port,Ecf::LOG_FILE());
+}
+
+std::string Host::ecf_checkpt_file(const std::string& port) const
+{
+ return prefix_host_and_port(port,Ecf::CHECKPT());
+}
+
+std::string Host::ecf_backup_checkpt_file(const std::string& port) const
+{
+ return prefix_host_and_port(port,Ecf::BACKUP_CHECKPT());
+}
+
+std::string Host::ecf_lists_file(const std::string& port) const
+{
+ return prefix_host_and_port(port,Str::WHITE_LIST_FILE());
+}
+
+std::string Host::prefix_host_and_port( const std::string& port,const std::string& file_name ) const
+{
+ // The file name may include a path. /user/avi/fred.log
+ // fred.log -> <host>.<port>.fred.log
+ // /user/avi/fred.log -> /user/avi/fred.log
+ if (!file_name.empty() && file_name.find("/") != std::string::npos ) {
+ return file_name;
+ }
+ std::string ret = host_port_prefix(port);
+ ret += ".";
+ ret += file_name;
+ return ret;
+}
+
+std::string Host::host_port_prefix(const std::string& port) const {
+ std::string ret = the_host_name_;
+ if (!port.empty()) {
+ ret += ".";
+ ret += port;
+ }
+ return ret;
+}
+
+}
diff --git a/ACore/src/Host.hpp b/ACore/src/Host.hpp
new file mode 100644
index 0000000..f0172a7
--- /dev/null
+++ b/ACore/src/Host.hpp
@@ -0,0 +1,54 @@
+#ifndef HOST_HPP_
+#define HOST_HPP_
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <boost/noncopyable.hpp>
+#include <string>
+
+namespace ecf {
+
+class Host : private boost::noncopyable {
+public:
+ /// can throw std::runtime_error if the gethostname fails
+ Host();
+ Host(const std::string& host);
+
+ /// return the host name
+ std::string name() const;
+
+ /// returns the log file name
+ std::string ecf_log_file(const std::string& port) const;
+
+ /// return checkPoint file
+ std::string ecf_checkpt_file(const std::string& port) const;
+
+ /// return backup checkPoint file
+ std::string ecf_backup_checkpt_file(const std::string& port) const;
+
+ /// return ecf.list file. White list file used for authentication
+ std::string ecf_lists_file(const std::string& port) const;
+
+ /// Given a port and file name, will return <host>.<port>.file_name
+ std::string prefix_host_and_port( const std::string& port,const std::string& list_file ) const;
+
+private:
+ std::string host_port_prefix(const std::string& port) const;
+ void get_host_name();
+ std::string the_host_name_;
+};
+}
+#endif
diff --git a/ACore/src/Indentor.cpp b/ACore/src/Indentor.cpp
new file mode 100644
index 0000000..9d97783
--- /dev/null
+++ b/ACore/src/Indentor.cpp
@@ -0,0 +1,31 @@
+//============================================================================
+// Name : Indentor
+// Author : Avi
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "Indentor.hpp"
+
+namespace ecf {
+
+int Indentor::index_ = 0;
+
+
+std::ostream& Indentor::indent( std::ostream& os, int char_spaces)
+{
+ int spaces = index_ * char_spaces;
+ for (int i = 0; i != spaces; i++)
+ os << " ";
+ return os;
+}
+
+}
diff --git a/ACore/src/Indentor.hpp b/ACore/src/Indentor.hpp
new file mode 100644
index 0000000..e535c4b
--- /dev/null
+++ b/ACore/src/Indentor.hpp
@@ -0,0 +1,37 @@
+#ifndef INDENTOR_HPP_
+#define INDENTOR_HPP_
+//============================================================================
+// Name : Indentor
+// Author : Avi
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : This class is used as a helper class to provide indented output
+//============================================================================
+#include <ostream>
+
+namespace ecf {
+
+class Indentor {
+public:
+ Indentor() {
+ ++index_;
+ }
+ ~Indentor() {
+ --index_;
+ }
+
+ static std::ostream& indent( std::ostream& os , int char_spaces = 2);
+
+private:
+ static int index_;
+};
+
+}
+#endif
diff --git a/ACore/src/Log.cpp b/ACore/src/Log.cpp
new file mode 100644
index 0000000..54f73c4
--- /dev/null
+++ b/ACore/src/Log.cpp
@@ -0,0 +1,347 @@
+//============================================================================
+// Name : Log
+// Author : Avi
+// Revision : $Revision: #57 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Simple singleton implementation of log
+//============================================================================
+#include <assert.h>
+#include <vector>
+#include <iostream>
+
+#include "boost/filesystem/path.hpp"
+#include "boost/filesystem/operations.hpp"
+
+#include "Log.hpp"
+#include "File.hpp"
+#include "Str.hpp"
+#include "Indentor.hpp"
+#include "TimeStamp.hpp"
+
+//#define DEBUG_BLOCKING_DISK_IO 1
+//#if DEBUG_BLOCKING_DISK_IO
+//#include "DurationTimer.hpp"
+//#endif
+
+using namespace std;
+namespace fs = boost::filesystem;
+
+namespace ecf {
+
+Log* Log::instance_ = NULL;
+bool LogToCout::flag_ = false;
+
+void Log::create(const std::string& filename)
+{
+ if ( instance_ == NULL) {
+ instance_ = new Log(filename);
+ }
+}
+
+void Log::destroy()
+{
+ if (instance_) instance_->flush();
+
+ delete instance_;
+ instance_ = NULL;
+}
+
+Log::Log(const std::string& fileName)
+: fileName_(fileName), logImpl_( new LogImpl(fileName) )
+{
+}
+
+Log::~Log()
+{
+ delete logImpl_;
+ logImpl_ = NULL;
+}
+
+
+bool Log::log(Log::LogType lt,const std::string& message)
+{
+ if (!logImpl_) {
+ logImpl_ = new LogImpl(fileName_) ;
+ }
+ return logImpl_->log(lt,message);
+}
+
+bool Log::log_no_newline(Log::LogType lt,const std::string& message)
+{
+ if (!logImpl_) {
+ logImpl_ = new LogImpl(fileName_) ;
+ }
+ return logImpl_->log_no_newline(lt,message);
+}
+
+bool Log::append(const std::string& message)
+{
+ if (!logImpl_) {
+ logImpl_ = new LogImpl(fileName_) ;
+ }
+ return logImpl_->append(message);
+}
+
+void Log::cache_time_stamp()
+{
+ if (!logImpl_) {
+ logImpl_ = new LogImpl(fileName_) ;
+ }
+ logImpl_->create_time_stamp();
+}
+
+const std::string& Log::get_cached_time_stamp() const
+{
+ if (!logImpl_) {
+ return Str::EMPTY();
+ }
+ return logImpl_->get_cached_time_stamp();
+}
+
+void Log::flush()
+{
+ // will close ofstream and force data to be written to disk.
+ // Forcing writing to physical medium can't be guaranteed though!
+ delete logImpl_;
+ logImpl_ = NULL;
+}
+
+void Log::clear()
+{
+ flush();
+
+ // Open and truncate the file.
+ std::ofstream logfile(fileName_.c_str(), ios::out | ios::trunc);
+ if (logfile.is_open()) {
+ logfile.close(); // force buffers to flush
+ }
+}
+
+void Log::new_path(const std::string& the_new_path)
+{
+ check_new_path(the_new_path);
+
+ // flush and close log file
+ flush();
+
+ fileName_ = the_new_path;
+}
+
+void Log::check_new_path(const std::string& new_path)
+{
+ if (new_path.empty()) {
+ throw std::runtime_error("Log::check_new_path: No path name specified for the new log file");
+ }
+
+ fs::path the_new_path = new_path;
+
+ // Allow paths like "fred.log"
+ fs::path parent_path = the_new_path.parent_path();
+ //std::cout << "the_new_path.parent_path() = " << parent_path << "\n";
+ if (!parent_path.empty()) {
+
+ if (!fs::exists(parent_path)) {
+ std::stringstream ss;
+ ss << "Log::check_new_path: Can not create new log file, since the directory part " << parent_path << " does not exist\n";
+ throw std::runtime_error(ss.str());
+ }
+ }
+
+ // Now check that path does not correspond to a directory, can't use that as the new log file location
+ if (fs::is_directory(the_new_path)) {
+ std::stringstream ss;
+ ss << "LogCmd::LogCmd: Can not create new log file, since the path correspond to a directory " << the_new_path << "\n";
+ throw std::runtime_error(ss.str());
+ }
+}
+
+std::string Log::path() const
+{
+ if (!fileName_.empty() && fileName_[0] == '/') {
+ // Path is absolute return as is
+ return fileName_;
+ }
+ std::string the_path = fs::current_path().string();
+ the_path += "/";
+ the_path += fileName_;
+ return the_path;
+}
+
+std::string Log::contents(int get_last_n_lines)
+{
+ if ( get_last_n_lines == 0 ) {
+ return string();
+ }
+
+ // Close the file. Log file may be buffered, hence flush first
+ flush();
+
+ std::string error_msg;
+ if (get_last_n_lines > 0 ) {
+ return File::get_last_n_lines(fileName_,get_last_n_lines,error_msg);
+ }
+ return File::get_first_n_lines(fileName_,std::abs(get_last_n_lines),error_msg);
+}
+
+bool log(Log::LogType lt,const std::string& message)
+{
+ if (Log::instance()) {
+ return Log::instance()->log(lt,message);
+ }
+ else {
+ if (LogToCout::ok()) {
+ Indentor::indent(cout) << message << endl;
+ }
+ }
+ return true;
+}
+
+bool log_no_newline(Log::LogType lt,const std::string& message)
+{
+ if (Log::instance()) {
+ return Log::instance()->log_no_newline(lt,message);
+ }
+ else {
+ if (LogToCout::ok()) {
+ Indentor::indent(cout) << message << endl;
+ }
+ }
+ return true;
+}
+
+bool log_append(const std::string& message)
+{
+ if (Log::instance()) {
+ return Log::instance()->append(message);
+ }
+ else {
+ if (LogToCout::ok()) {
+ Indentor::indent(cout) << message << endl;
+ }
+ }
+ return true;
+}
+
+void log_assert(char const* expr,char const* file, long line, const std::string& message)
+{
+ std::stringstream ss;
+ ss << "ASSERT failure: " << expr << " at " << file << ":" << line << " " << message;
+ std::string assert_msg = ss.str();
+ cerr << assert_msg << "\n";
+ if (Log::instance()) {
+ Log::instance()->log(Log::ERR,assert_msg);
+ exit(1);
+ }
+}
+
+// returns vec = MSG, LOG, ERR, WAR, DBG, OTH
+void Log::get_log_types(std::vector<std::string>& vec)
+{
+ vec.reserve(6);
+ vec.push_back("MSG");
+ vec.push_back("LOG");
+ vec.push_back("ERR");
+ vec.push_back("WAR");
+ vec.push_back("DBG");
+ vec.push_back("OTH");
+}
+
+//======================================================================================================
+LogImpl::LogImpl(const std::string& filename)
+: file_(filename.c_str(), ios::out | ios::app)
+{
+ if (!file_.is_open()) {
+ std::cerr << "LogImpl::LogImpl: Could not open log file '" << filename << "'\n";
+ std::runtime_error("LogImpl::LogImpl: Could not open log file " + filename);
+ }
+}
+
+LogImpl::~LogImpl() {}
+
+
+static void append_log_type(std::string& str, Log::LogType lt)
+{
+ switch (lt) {
+ case Log::MSG: str.append("MSG:"); break;
+ case Log::LOG: str.append("LOG:"); break;
+ case Log::ERR: str.append("ERR:"); break;
+ case Log::WAR: str.append("WAR:"); break;
+ case Log::DBG: str.append("DBG:"); break;
+ case Log::OTH: str.append("OTH:"); break;
+ default: assert(false); break;
+ }
+}
+
+bool LogImpl::do_log(Log::LogType lt,const std::string& message, bool newline)
+{
+//#if DEBUG_BLOCKING_DISK_IO
+// ecf::DurationTimer timer;
+//#endif
+
+ // XXX:[HH:MM:SS D.M.YYYY] chd:fullname [+additional information]
+ // XXX:[HH:MM:SS D.M.YYYY] --<user_cmd> [+additional information]
+ if (time_stamp_.empty() || lt == Log::ERR || lt == Log::WAR || lt == Log::DBG ) create_time_stamp();
+
+ // re-use memory allocated to log_type_and_time_stamp_
+ log_type_and_time_stamp_.clear();
+ append_log_type(log_type_and_time_stamp_,lt);
+ log_type_and_time_stamp_ += time_stamp_;
+
+ if (message.find("\n") == std::string::npos) {
+ file_ << log_type_and_time_stamp_ << message;
+ if (newline) file_ << endl;
+ }
+ else {
+ // If message has \n then split into multiple lines
+ std::vector< std::string > lines;
+ Str::split(message,lines,"\n");
+ size_t theSize = lines.size();
+ for(size_t i = 0; i < theSize; ++i) {
+ file_ << log_type_and_time_stamp_ << lines[i] << endl; // flush EACH line
+ }
+ }
+
+ // Check to see, if writing to file was ok.
+ return check_file_write(message);
+
+//#if DEBUG_BLOCKING_DISK_IO
+// long total_seconds = timer.elapsed().total_seconds();
+// if (total_seconds >= 1) {
+// std::stringstream ss;
+// ss << " took " << total_seconds << " seconds **************************************************************";
+// std::string time_taken = ss.str();
+// file_ << log_type_and_time_stamp_ << message << time_taken << "\n";
+// cout << log_type_and_time_stamp_ << message << time_taken << "\n";
+// }
+//#endif
+}
+
+bool LogImpl::append(const std::string& message)
+{
+ file_ << message << endl;
+ return check_file_write(message);
+}
+
+bool LogImpl::check_file_write(const std::string& message) const
+{
+ bool file_is_good = file_.good();
+ if (!file_is_good) cout << "LogImpl::append: Could not write to log file! File system full? Try --log=flush !" << endl;
+ if (LogToCout::ok() || !file_is_good) {
+ Indentor::indent(cout) << message << endl;
+ }
+ return file_is_good;
+}
+
+void LogImpl::create_time_stamp()
+{
+ TimeStamp::now(time_stamp_);
+}
+
+}
diff --git a/ACore/src/Log.hpp b/ACore/src/Log.hpp
new file mode 100644
index 0000000..a0bbad3
--- /dev/null
+++ b/ACore/src/Log.hpp
@@ -0,0 +1,166 @@
+#ifndef LOG_HPP_
+#define LOG_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name : Log
+// Author : Avi
+// Revision : $Revision: #31 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Simple singleton implementation of log
+//
+// Please note how do we guarantee that file is actually written to disk:
+// a/ Each log entry should call std::endl
+// b/ Call flush() on the ofstream
+// c/ The two methods will force ofstream buffer to be written to disk
+// Well NOT REALLY dues to file caching by the OS.
+// The strongest hint we can give th OS to actually write to the physical medium
+// is to close the file. (This does not guarantee it, but is the closest we can achieve)
+//
+// Why is this an issue ? Testing on cross platform HPUX/linux, requires that
+// testing has access to the ECF log file. Initially the log file held an
+// ofstream of log file as a data member. However this meant that flushing
+// did not guarantee writing ECF log file to disk. Testing requires that we
+// are able to clear and copy the log file for comparison.
+// Hence we use another level of indirection, so that we able to close the
+// log file, and hence can ensure that it gets written to disk
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <vector>
+#include <string>
+#include <fstream>
+#include <sstream>
+#include <boost/noncopyable.hpp>
+#include <boost/lambda/lambda.hpp>
+
+namespace ecf {
+
+class LogImpl;
+
+class Log : private boost::noncopyable {
+public:
+ enum LogType { MSG, LOG, ERR, WAR, DBG, OTH };
+ static void create(const std::string& filename);
+ static void destroy();
+ static Log* instance() { return instance_;}
+
+ /// If file is closed will open it
+ /// Outputs t the file a message of type XXX:[HH:MM:SS D.M.YYYY] message
+ /// where XXX is one of the LogType
+ ///
+ /// If the message has multiple newlines these are split
+ /// LogType ERR,WAR,DBG will create a time stamp, otherwise the last cached
+ /// time stamp is used.
+ bool log(LogType,const std::string& message);
+
+ /// Single line message is placed in log file without a newline
+ bool log_no_newline(LogType,const std::string& message);
+
+ /// Append to log file file and add newline
+ bool append(const std::string& message);
+
+ /// Set the time stamp once for each request.
+ void cache_time_stamp();
+
+ /// Return the last cached time stamp. Used for time stamping edit history
+ const std::string& get_cached_time_stamp() const;
+
+ /// returns the contents of the log file, or the last n lines
+ /// Will throw an std::runtime_error if the log file can not be opened
+ /// Will close the file.
+ static int get_last_n_lines_default() { return 100;}
+ std::string contents(int get_last_n_lines);
+
+ /// Will call flush and close the file. See notes above
+ void flush();
+
+ /// clear the log file. Required for testing
+ void clear();
+
+ /// Close the existing log file, and new start writing to the new location
+ void new_path(const std::string& the_path);
+
+ /// Returns the current log file path name
+ std::string path() const;
+
+ // returns vec = MSG, LOG, ERR, WAR, DBG, OTH
+ static void get_log_types(std::vector<std::string>&);
+
+private:
+
+ /// make sure path is not a directory & path has a parent directory.
+ /// Will throw std::runtime_error for errors
+ static void check_new_path(const std::string& the_new_path);
+
+private:
+ ~Log();
+ Log(const std::string& filename);
+ static Log* instance_;
+
+ std::string fileName_;
+ LogImpl* logImpl_;
+};
+
+/// The LogImpl allows the ofstream object to be closed, and so provide strongest
+/// hint to OS that we want file to be written to physical medium.
+/// This is required for testing purposes, as each test run needs to clear/copy
+/// the log file
+class LogImpl : private boost::noncopyable {
+public:
+ LogImpl(const std::string& filename);
+ ~LogImpl();
+
+ bool log(Log::LogType lt,const std::string& message) { return do_log(lt,message,true); }
+ bool log_no_newline(Log::LogType lt,const std::string& message) { return do_log(lt,message,false); }
+ bool append(const std::string& message);
+
+ void create_time_stamp();
+ const std::string& get_cached_time_stamp() const { return time_stamp_;}
+
+private:
+ bool do_log(Log::LogType,const std::string& message, bool newline);
+ bool check_file_write(const std::string& message) const;
+
+private:
+ std::string time_stamp_;
+ mutable std::ofstream file_;
+
+ std::string log_type_and_time_stamp_; // re-use memory
+};
+
+/// Utility class used for debug. Enables log file messages to be written to standard out
+class LogToCout : private boost::noncopyable {
+public:
+ LogToCout() { flag_ = true;}
+ ~LogToCout() { flag_ = false;}
+ static bool ok() { return flag_;}
+private:
+ static bool flag_;
+};
+
+bool log(Log::LogType,const std::string& message);
+bool log_no_newline(Log::LogType,const std::string& message);
+bool log_append(const std::string& message);
+void log_assert(char const* expr,char const* file, long line, const std::string& message);
+
+// allow user to do the following:
+// LOG(Log::WAR,"this is " << path << " ok ");
+//
+// helper, see STRINGIZE() macro
+template <typename Functor>
+std::string stringize_f(Functor const & f) {
+ std::ostringstream out;
+ f(out);
+ return out.str();
+}
+#define STRINGIZE(EXPRESSION) (ecf::stringize_f(boost::lambda::_1 << EXPRESSION))
+#define LOG(level, EXPRESSION) ecf::log(level, STRINGIZE(EXPRESSION))
+#define LOG_ASSERT(expr,EXPRESSION) ((expr)? ((void)0): ecf::log_assert(#expr, __FILE__, __LINE__, STRINGIZE(EXPRESSION)))
+
+}
+
+#endif
diff --git a/ACore/src/LogVerification.cpp b/ACore/src/LogVerification.cpp
new file mode 100644
index 0000000..b9865b1
--- /dev/null
+++ b/ACore/src/LogVerification.cpp
@@ -0,0 +1,138 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <iostream>
+#include <sstream>
+
+#include "LogVerification.hpp"
+#include "File.hpp"
+#include "Str.hpp"
+#include "NState.hpp"
+
+using namespace std;
+
+namespace ecf {
+
+bool LogVerification::extractNodePathAndState( const std::string& logfile,
+ std::vector< std::pair< std::string, std::string > >& pathStateVec,
+ std::string& errorMsg )
+{
+ // The log file format we are interested is :
+ // 0 1 2 3
+ // LOG:[14:37:00 20.5.2010] submitted: /test_abort_cmd/family0/abort duration_(00:00:00) initTime_(2010-May-20 14:37:00) suiteTime_(2010-May-20 14:37:00)
+
+ // Open log file, and collate of the node paths and corresponding states
+ std::vector<std::string> lines;
+ if (!File::splitFileIntoLines(logfile,lines)) {
+ errorMsg = "Could not open log file " + logfile + " for test verification";
+ return false;
+ }
+
+ int line_number = 0;
+ for(std::vector<std::string>::iterator i=lines.begin(); i!=lines.end(); ++i) {
+
+ line_number++;
+ if ((*i).find("LOG:") == std::string::npos) {
+ continue; // State changes have type Log::LOG
+ }
+
+ std::vector< std::string > lineTokens;
+ Str::split(*i, lineTokens);
+ if (lineTokens.size() < 3) {
+ continue;
+ }
+
+ std::string theState = lineTokens[2];
+ theState.erase( theState.size() -1); // remove ':' at the end
+ if (!NState::isValid( theState )) {
+ continue;
+ }
+ // cout << line_number << Str::COLON() << *i << "\n";
+
+ pathStateVec.push_back( std::make_pair(lineTokens[3], theState ) );
+ }
+ return true;
+}
+
+static bool searchVec(
+ const std::vector< std::pair< std::string, std::string > >& goldenLines,
+ const std::pair< std::string, std::string >& line,
+ size_t start_index)
+{
+ for(size_t i = start_index; i < goldenLines.size(); i++) {
+ if ( goldenLines[i] == line) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool LogVerification::compareNodeStates( const std::string& logfile, const std::string& goldenRefLogFile, std::string& errorMsg)
+{
+ // Open log files, and extract just the state changes
+ std::vector< std::pair< std::string, std::string > > lines,goldenLines;
+ if (!extractNodePathAndState(logfile,lines,errorMsg)) return false;
+ if (!extractNodePathAndState(goldenRefLogFile,goldenLines,errorMsg)) return false;
+
+ if ( lines != goldenLines) {
+ std::stringstream ss;
+ ss << "Log file " << logfile << " does not match golden reference file " << goldenRefLogFile << "\n";
+ if (lines.size() != goldenLines.size()) ss << "Expected log file size " << goldenLines.size() << " but found " << lines.size() <<"\n";
+
+ bool errorFnd = false;
+ for(size_t i=0; i < lines.size() || i < goldenLines.size(); ++i) {
+
+ std::string theLine,theGoldenLine;
+ if (i < lines.size() ) theLine = lines[i].second + Str::COLON() + lines[i].first;
+ if (i < goldenLines.size()) theGoldenLine = goldenLines[i].second + Str::COLON() + goldenLines[i].first;
+
+ if (i < lines.size() && i < goldenLines.size()) {
+
+ if (lines[i] != goldenLines[i]) {
+ // Please note that we can't do an exact compare for certain state changes
+ // submitted -->active
+ // active -->complete
+ // Since this can be OS/scheduler dependent and hence order dependent
+ // To compensate look search Golden file
+ if (lines[i].second == "submitted" || lines[i].second == "active" || lines[i].second == "complete") {
+ // search for line in golden file
+ if (searchVec(goldenLines,lines[i],0)) {
+ continue;
+ }
+ }
+
+ ss << "Mismatch at " << i << " log(" << theLine << ") golden(" << theGoldenLine << ")\n";
+ errorFnd = true;
+ }
+ else {
+ ss << " " << i << " log(" << theLine << ") golden(" << theGoldenLine << ")\n";
+ }
+ }
+ else {
+ errorFnd = true;
+ ss << "Mismatch at " << i ;
+ if (i < lines.size() ) ss << " log(" << theLine << ") ";
+ else ss << " log( ---- ) ";
+
+ if (i < goldenLines.size()) ss << "golden(" << theGoldenLine << ")\n";
+ else ss << "golden( --- )\n";
+ }
+ }
+ if (errorFnd) errorMsg = ss.str();
+ }
+
+ return errorMsg.empty();
+}
+
+}
diff --git a/ACore/src/LogVerification.hpp b/ACore/src/LogVerification.hpp
new file mode 100644
index 0000000..40c2e72
--- /dev/null
+++ b/ACore/src/LogVerification.hpp
@@ -0,0 +1,41 @@
+#ifndef LOG_VERIFICATION_HPP_
+#define LOG_VERIFICATION_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <vector>
+#include <string>
+#include <boost/noncopyable.hpp>
+
+namespace ecf {
+
+class LogVerification : private boost::noncopyable {
+public:
+
+ /// Given a log file, extract in order. The node_path and the state
+ static bool extractNodePathAndState(const std::string& logfile,
+ std::vector< std::pair<std::string,std::string> >& pathStateVec,
+ std::string& errorMsg);
+
+ /// Will compare the input log file, with gold reference.
+ /// Will compare the node state changes only
+ /// Compensate for states that are scheduler dependent
+ static bool compareNodeStates( const std::string& logfile, const std::string& goldenRefLogFile, std::string& errormsg);
+
+private:
+ LogVerification() {}
+};
+}
+#endif
diff --git a/ACore/src/NOrder.cpp b/ACore/src/NOrder.cpp
new file mode 100644
index 0000000..c736255
--- /dev/null
+++ b/ACore/src/NOrder.cpp
@@ -0,0 +1,55 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "NOrder.hpp"
+#include <assert.h>
+
+std::string NOrder::toString(NOrder::Order s) {
+ switch (s) {
+ case NOrder::TOP: return "top"; break;
+ case NOrder::BOTTOM: return "bottom"; break;
+ case NOrder::ALPHA: return "alpha"; break;
+ case NOrder::ORDER: return "order"; break;
+ case NOrder::UP: return "up"; break;
+ case NOrder::DOWN: return "down"; break;
+ default: assert(false); break;
+ }
+ assert(false);
+ return std::string();
+}
+
+NOrder::Order NOrder::toOrder(const std::string& str)
+{
+ if (str == "top") return NOrder::TOP;
+ if (str == "bottom") return NOrder::BOTTOM;
+ if (str == "alpha") return NOrder::ALPHA;
+ if (str == "order") return NOrder::ORDER;
+ if (str == "up") return NOrder::UP;
+ if (str == "down") return NOrder::DOWN;
+ assert(false);
+ return NOrder::TOP;
+}
+
+bool NOrder::isValid(const std::string& state)
+{
+ if (state == "top") return true;
+ if (state == "bottom") return true;
+ if (state == "alpha") return true;
+ if (state == "order") return true;
+ if (state == "up") return true;
+ if (state == "down") return true;
+ return false;
+}
+
diff --git a/ACore/src/NOrder.hpp b/ACore/src/NOrder.hpp
new file mode 100644
index 0000000..2f93b73
--- /dev/null
+++ b/ACore/src/NOrder.hpp
@@ -0,0 +1,31 @@
+#ifndef NORDER_HPP_
+#define NORDER_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <string>
+
+class NOrder {
+ NOrder() {}
+public:
+ enum Order { TOP, BOTTOM, ALPHA, ORDER, UP, DOWN };
+
+ static std::string toString(NOrder::Order);
+ static NOrder::Order toOrder(const std::string&);
+ static bool isValid(const std::string& order);
+};
+
+#endif
diff --git a/ACore/src/NState.cpp b/ACore/src/NState.cpp
new file mode 100644
index 0000000..210792d
--- /dev/null
+++ b/ACore/src/NState.cpp
@@ -0,0 +1,113 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #20 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <assert.h>
+#include <iostream>
+#include "NState.hpp"
+#include "Ecf.hpp"
+
+void NState::setState( State s ) {
+ state_= s;
+ state_change_no_ = Ecf::incr_state_change_no();
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "NState::setState\n";
+#endif
+}
+
+const char* NState::toString( NState::State s ) {
+ switch ( s ) {
+ case NState::UNKNOWN:
+ return "unknown";
+ break;
+ case NState::COMPLETE:
+ return "complete";
+ break;
+ case NState::QUEUED:
+ return "queued";
+ break;
+ case NState::ABORTED:
+ return "aborted";
+ break;
+ case NState::SUBMITTED:
+ return "submitted";
+ break;
+ case NState::ACTIVE:
+ return "active";
+ break;
+ default:
+ assert(false); break;
+ }
+ assert(false);
+ return NULL;
+}
+
+NState::State NState::toState( const std::string& str ) {
+ if ( str == "complete" )
+ return NState::COMPLETE;
+ if ( str == "unknown" )
+ return NState::UNKNOWN;
+ if ( str == "queued" )
+ return NState::QUEUED;
+ if ( str == "aborted" )
+ return NState::ABORTED;
+ if ( str == "submitted" )
+ return NState::SUBMITTED;
+ if ( str == "active" )
+ return NState::ACTIVE;
+ assert(false);
+ return NState::UNKNOWN;
+}
+
+bool NState::isValid( const std::string& state ) {
+ if ( state == "complete" )
+ return true;
+ if ( state == "unknown" )
+ return true;
+ if ( state == "queued" )
+ return true;
+ if ( state == "aborted" )
+ return true;
+ if ( state == "submitted" )
+ return true;
+ if ( state == "active" )
+ return true;
+ return false;
+}
+
+std::vector< std::string > NState::allStates() {
+ std::vector< std::string > vec;
+ vec.reserve( 6 );
+ vec.push_back( "complete" );
+ vec.push_back( "unknown" );
+ vec.push_back( "queued" );
+ vec.push_back( "aborted" );
+ vec.push_back( "submitted" );
+ vec.push_back( "active" );
+ return vec;
+}
+
+std::vector<NState::State> NState::states()
+{
+ std::vector< NState::State > vec;
+ vec.reserve( 6 );
+ vec.push_back( NState::UNKNOWN );
+ vec.push_back( NState::COMPLETE );
+ vec.push_back( NState::QUEUED );
+ vec.push_back( NState::ABORTED );
+ vec.push_back( NState::SUBMITTED );
+ vec.push_back( NState::ACTIVE );
+ return vec;
+}
diff --git a/ACore/src/NState.hpp b/ACore/src/NState.hpp
new file mode 100644
index 0000000..2601462
--- /dev/null
+++ b/ACore/src/NState.hpp
@@ -0,0 +1,69 @@
+#ifndef NSTATE_HPP_
+#define NSTATE_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #16 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <string>
+#include <vector>
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/level.hpp>
+#include <boost/serialization/tracking.hpp>
+
+// NState: stores the state of a node.
+// *The class NState just used to define the enum, however we also
+// needed to know when the state changed. Hence the use of state_change_no
+// Uses default copy constructor and destructor, and equality
+class NState {
+public:
+ enum State { UNKNOWN =0, COMPLETE=1, QUEUED=2, ABORTED=3, SUBMITTED=4, ACTIVE=5 };
+ NState(State s): state_(s), state_change_no_(0) {}
+ NState(): state_(UNKNOWN),state_change_no_(0) {}
+
+ State state() const { return state_;}
+ void setState(State);
+
+ // The state_change_no is never reset. Must be incremented if it can affect equality
+ unsigned int state_change_no() const { return state_change_no_; }
+
+ bool operator==(const NState& rhs) const { return state_ == rhs.state_;}
+ bool operator!=(const NState& rhs) const { return state_ != rhs.state_;}
+ bool operator==(State s) const { return s == state_;}
+ bool operator!=(State s) const { return s != state_;}
+
+ static const char* toString(NState::State s);
+ static const char* toString(const NState& ns) { return toString(ns.state());}
+ static NState::State toState(const std::string& state);
+ static bool isValid(const std::string& state);
+ static std::vector<std::string> allStates();
+ static std::vector<NState::State> states();
+
+private:
+ State state_;
+ unsigned int state_change_no_; // *not* persisted, only used on server side
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/)
+ {
+ ar & state_;
+ }
+};
+
+// This should ONLY be added to objects that are *NOT* serialised through a pointer
+BOOST_CLASS_IMPLEMENTATION(NState, boost::serialization::object_serializable);
+BOOST_CLASS_TRACKING(NState,boost::serialization::track_never);
+
+#endif
diff --git a/ACore/src/NodePath.cpp b/ACore/src/NodePath.cpp
new file mode 100644
index 0000000..e3cae23
--- /dev/null
+++ b/ACore/src/NodePath.cpp
@@ -0,0 +1,83 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #9 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <iostream>
+#include <boost/algorithm/string/trim.hpp>
+
+#include "NodePath.hpp"
+#include "Str.hpp"
+
+using namespace ecf;
+
+void NodePath::split( const std::string& path, std::vector<std::string>& thePath)
+{
+ /// The path is of the form "/suite/family/task"
+ Str::split(path,thePath,Str::PATH_SEPERATOR());
+
+ // This is the original implementation, found to be a lot slower
+ // See timing tests at the end of TestNodePathextractor.cpp
+ // typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+ // boost::char_separator<char> sep("/");
+ // tokenizer tokens(path_, sep);
+ // copy(tokens.begin(), tokens.end(), back_inserter(thePath));
+}
+
+bool NodePath::extractHostPort(const std::string& path,std::string& host, std::string& port)
+{
+ if (path.empty()) return false;
+
+ std::vector<std::string> thePath;
+ NodePath::split(path,thePath);
+
+ if (thePath.empty()) return false;
+
+ //<host>:<port>/suite/family/task
+ // first path should be of form <host>:<port>
+ size_t colonPos = thePath[0].find_first_of(':');
+ if (colonPos == std::string::npos) return false;
+
+ host = thePath[0].substr(0,colonPos);
+ port = thePath[0].substr(colonPos+1);
+
+ boost::algorithm::trim(host);
+ boost::algorithm::trim(port);
+ if (host.empty()) return false;
+ if (port.empty()) return false;
+
+ return true;
+}
+
+
+std::string NodePath::createPath(const std::vector<std::string>& vec)
+{
+ if (vec.empty()) return std::string();
+
+ std::string ret;
+ size_t size = vec.size();
+ for(size_t i = 0; i < size; i++) {
+ ret += Str::PATH_SEPERATOR();
+ ret += vec[i];
+ }
+ return ret;
+}
+
+std::string NodePath::removeHostPortFromPath(const std::string& path)
+{
+ std::vector<std::string> pathVec;
+ NodePath::split(path,pathVec);
+ pathVec.erase( pathVec.begin() );
+ return NodePath::createPath(pathVec);
+}
+
diff --git a/ACore/src/NodePath.hpp b/ACore/src/NodePath.hpp
new file mode 100644
index 0000000..e4e05c7
--- /dev/null
+++ b/ACore/src/NodePath.hpp
@@ -0,0 +1,46 @@
+#ifndef NODEPATH_HPP_
+#define NODEPATH_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <boost/noncopyable.hpp>
+#include <string>
+#include <vector>
+
+class NodePath : private boost::noncopyable {
+public:
+ /// returns the path as a vector of strings, preserving the order
+ /// Note: multiple path separator '/' are treated as one separator.
+ /// Mimics unix path conventions. hence
+ /// '/suite//family///task' will be extracted as 'suite','family','task'
+ static void split(const std::string& path,std::vector<std::string>&);
+
+ /// If the path name if form:
+ /// //<host>:<port>/suite/family/task
+ /// The extract the host and port, return OK if successful
+ static bool extractHostPort(const std::string& path, std::string& host, std::string& port);
+
+ /// Given a vector of strings , create a path. "suite","family", returns /suite/family
+ static std::string createPath(const std::vector<std::string>&);
+
+ /// Given a path like: //localhost:3141/suite/family/task
+ /// returns /suite/family/task
+ static std::string removeHostPortFromPath(const std::string& path);
+
+private:
+ NodePath();
+
+};
+#endif
diff --git a/ACore/src/Passwd.cpp b/ACore/src/Passwd.cpp
new file mode 100644
index 0000000..443442e
--- /dev/null
+++ b/ACore/src/Passwd.cpp
@@ -0,0 +1,84 @@
+//============================================================================
+// Name : Passwd.hpp
+// Author : Avi
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "Passwd.hpp"
+#include <iostream>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+//extern char *crypt(const char *key, const char *salt);
+
+
+double ecf_drand48();
+
+
+std::string Passwd::generate()
+{
+ char pw[9];
+ for (int i = 0; i < 8; i++) { /* generate a random password */
+
+ pw[i] = 64.0 * ecf_drand48() + '.'; /* Just crack this one! */
+ if ( pw[i] > '9' ) pw[i] += 7;
+ if ( pw[i] > 'Z' ) pw[i] += 6;
+ }
+ pw[8] = '\0';
+ return std::string (pw);
+}
+
+//std::string Passwd::doCrypt( const std::string& passwd ) {
+// /**************************************************************************
+// ? Crypt the passwd.
+// = Crypted password in static area.
+// ************************************o*************************************/
+// char salt[3];
+//
+// for (int i = 0; i < 2; i++) {
+// salt[i] = 64.0 * ecf_drand48() + '.';
+// if ( salt[i] > '9' ) salt[i] += 7;
+// if ( salt[i] > 'Z' ) salt[i] += 6;
+// }
+// salt[2] = '\0';
+//
+// return std::string( crypt( passwd.c_str(), salt ));
+//}
+
+
+double ecf_drand48()
+/**************************************************************************
+ ? Random number with time dependent seed.
+ = [0.0 - 1.0)
+ ~ drand48(3) srand48(3) rand(3)
+ ************************************o*************************************/
+{
+ // extern double drand48();
+ // extern void srand48();
+ static int been_here;
+
+ if ( !been_here ) {
+#if defined(RAND_ONLY)
+ srand( (int) time(NULL) + getpid() );
+#else
+ srand48( (long) time( NULL ) + getpid() );
+#endif
+ been_here = 1;
+ }
+
+#if defined(RAND_ONLY)
+ return (rand()&0xffff) / 65535.0001;
+#else
+ return drand48();
+#endif
+}
diff --git a/ACore/src/Passwd.hpp b/ACore/src/Passwd.hpp
new file mode 100644
index 0000000..c0c6e0c
--- /dev/null
+++ b/ACore/src/Passwd.hpp
@@ -0,0 +1,47 @@
+#ifndef PASSWD_HPP_
+#define PASSWD_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+// The tasks send by the ECF will have GENERATED PASSWORD that is not
+// stored into the any file (except the job file). It only exist in the
+// ECF_server-memory. If the ECF server fails and a new one is started, it must be
+// told (by operator) to accept the messages from the unknown jobs.
+//
+// The GENERATED PASSWORDs are stored into the CHECKPOINT file. So if the
+// ECF fails and is RESTARTed from a valid CHECKPOINT file, the ECF gets
+// to know about the tasks.
+//
+// The user passwords are kept in a file. When ever an user logs into
+// the ECF or changes the "level" of privileges while already in the
+// file is consulted.
+//============================================================================
+
+#include <boost/noncopyable.hpp>
+#include <string>
+
+class Passwd : private boost::noncopyable {
+public:
+
+ /// generate a random password
+ static std::string generate();
+
+ /// encrypt the password
+// static std::string doCrypt( const std::string& generated);
+
+private:
+ Passwd();
+};
+
+#endif
diff --git a/ACore/src/PrintStyle.cpp b/ACore/src/PrintStyle.cpp
new file mode 100644
index 0000000..f0e87ae
--- /dev/null
+++ b/ACore/src/PrintStyle.cpp
@@ -0,0 +1,53 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "PrintStyle.hpp"
+#include <iostream>
+
+static PrintStyle::Type_t style_ = PrintStyle::NOTHING;
+
+PrintStyle::Type_t PrintStyle::getStyle()
+{
+ return style_;
+}
+
+void PrintStyle::setStyle(PrintStyle::Type_t f)
+{
+ style_ = f;
+}
+
+bool PrintStyle::defsStyle() {
+ if (getStyle() == PrintStyle::DEFS || getStyle() == PrintStyle::NOTHING) {
+ return true;
+ }
+ return false;
+}
+
+std::string PrintStyle::to_string()
+{
+ return to_string(getStyle());
+}
+
+std::string PrintStyle::to_string(PrintStyle::Type_t t)
+{
+ switch ( t ) {
+ case PrintStyle::NOTHING: return "NOTHING";break;
+ case PrintStyle::DEFS: return "DEFS";break;
+ case PrintStyle::STATE: return "STATE";break;
+ case PrintStyle::MIGRATE: return "MIGRATE";break;
+ }
+ return std::string();
+}
+
diff --git a/ACore/src/PrintStyle.hpp b/ACore/src/PrintStyle.hpp
new file mode 100644
index 0000000..d49add3
--- /dev/null
+++ b/ACore/src/PrintStyle.hpp
@@ -0,0 +1,50 @@
+#ifndef PRINTSTYLE_HPP_
+#define PRINTSTYLE_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #12 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <boost/noncopyable.hpp>
+#include <string>
+
+class PrintStyle : private boost::noncopyable {
+public:
+ // Used by the show Cmd
+ enum Type_t {
+ NOTHING = 0, // Does nothing
+ DEFS = 1, // Output the definition that is fully parse-able
+ STATE = 2, // Output definition that includes Node state, and AST, fully parseable
+ MIGRATE = 3 // Output the definition that is fully parse-able & includes state
+ };
+
+ PrintStyle(Type_t t) : old_style_(getStyle()) { setStyle(t);}
+ ~PrintStyle() { setStyle(old_style_); } // reset to old style on destruction
+
+
+ /// We want to control the output, so that we can dump in old style defs format
+ /// or choose to dump for debug.
+ static Type_t getStyle() ;
+ static void setStyle(Type_t) ;
+
+ static bool defsStyle();
+
+ // return current style as a string
+ static std::string to_string();
+ static std::string to_string(PrintStyle::Type_t);
+
+private:
+ Type_t old_style_;
+};
+
+#endif
diff --git a/ACore/src/SState.cpp b/ACore/src/SState.cpp
new file mode 100644
index 0000000..21f7576
--- /dev/null
+++ b/ACore/src/SState.cpp
@@ -0,0 +1,58 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "SState.hpp"
+#include <assert.h>
+
+std::string SState::to_string(int status)
+{
+ if (status == 0) return "HALTED";
+ else if (status == 1) return "SHUTDOWN";
+ else if (status == 2) return "RUNNING";
+ return "UNKNOWN??";
+}
+
+std::string SState::to_string(SState::State state)
+{
+ switch (state) {
+ case SState::HALTED: return "HALTED"; break;
+ case SState::SHUTDOWN: return "SHUTDOWN"; break;
+ case SState::RUNNING: return "RUNNING"; break;
+ }
+ return "UNKNOWN??";
+}
+
+SState::State SState::toState( const std::string& str ) {
+ if ( str == "HALTED" )
+ return SState::HALTED;
+ if ( str == "SHUTDOWN" )
+ return SState::SHUTDOWN;
+ if ( str == "RUNNING" )
+ return SState::RUNNING;
+ assert(false);
+ return SState::HALTED;
+}
+
+bool SState::isValid( const std::string& state ) {
+ if ( state == "HALTED" )
+ return true;
+ if ( state == "SHUTDOWN" )
+ return true;
+ if ( state == "queued" )
+ return true;
+ if ( state == "RUNNING" )
+ return true;
+ return false;
+}
diff --git a/ACore/src/SState.hpp b/ACore/src/SState.hpp
new file mode 100644
index 0000000..73eb4a8
--- /dev/null
+++ b/ACore/src/SState.hpp
@@ -0,0 +1,46 @@
+#ifndef S_STATE_HPP_
+#define S_STATE_HPP_
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <string>
+#include <boost/noncopyable.hpp>
+
+class SState : private boost::noncopyable {
+public:
+ /// The following table shows the effect of state, on server behaviour:
+ ///
+ /// User Request Task Request Job Scheduling Check-pointing
+ /// RUNNING yes yes yes yes
+ /// SHUTDOWN yes yes no yes
+ /// HALTED yes no no no
+ enum State {
+ HALTED,
+ SHUTDOWN,
+ RUNNING
+ };
+
+ /// Given an integer return the server state as a string.
+ /// if int is not 0,1,2 return "UNKNOWN
+ static std::string to_string(int status);
+ static std::string to_string(SState::State);
+
+ static SState::State toState(const std::string& state);
+ static bool isValid(const std::string& state);
+
+private:
+ SState();
+};
+#endif
diff --git a/ACore/src/Serialization.hpp b/ACore/src/Serialization.hpp
new file mode 100644
index 0000000..5aafe84
--- /dev/null
+++ b/ACore/src/Serialization.hpp
@@ -0,0 +1,135 @@
+#ifndef SERIALIZATION_HPP_
+#define SERIALIZATION_HPP_
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #14 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Simple class that defines the Archive types used for
+// Serialisation
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <string>
+#include <iostream>
+#include <fstream>
+
+#include "boost_archive.hpp"
+#include "Archive.hpp"
+
+namespace ecf {
+
+/// These function do *NOT* trap boost::archive::archive_exception since we want it
+/// to propagate up.
+
+template< typename T >
+void save(const std::string& fileName, const T& ts, ecf::Archive::Type at = ecf::Archive::default_archive())
+{
+ // Argument added if in future we want to allow multiple archives, so we can choose
+#if defined(BINARY_ARCHIVE)
+ std::ofstream ofs( fileName.c_str(), std::ios::binary );
+ boost::archive::binary_oarchive oa( ofs );
+ oa << ts;
+#elif defined(PORTABLE_BINARY_ARCHIVE)
+ std::ofstream ofs( fileName.c_str(), std::ios::binary );
+ portable_binary_oarchive oa(ofs);
+ oa << ts;
+#elif defined(EOS_PORTABLE_BINARY_ARCHIVE)
+ std::ofstream ofs( fileName.c_str(), std::ios::binary );
+ eos::portable_oarchive oa(ofs);
+ oa << ts;
+#else
+ std::ofstream ofs( fileName.c_str() );
+ boost::archive::text_oarchive oa( ofs );
+ oa << ts;
+#endif
+}
+
+template< typename T >
+void save_as_string(std::string& outbound_data, const T& t)
+{
+ std::ostringstream archive_stream;
+
+#if defined(BINARY_ARCHIVE)
+ boost::archive::binary_oarchive archive( archive_stream );
+ archive << t;
+ outbound_data = archive_stream.str();
+ // std::cout << "save_as_string BINARY " << outbound_data_ << "\n";
+#elif defined(PORTABLE_BINARY_ARCHIVE)
+ portable_binary_oarchive archive( archive_stream );
+ archive << t;
+ outbound_data = archive_stream.str();
+ // std::cout << "save_as_string PORTABLE_BINARY " << outbound_data_ << "\n";
+#elif defined(EOS_PORTABLE_BINARY_ARCHIVE)
+ eos::portable_oarchive archive( archive_stream );
+ archive << t;
+ outbound_data = archive_stream.str();
+ // std::cout << "save_as_string EOS_PORTABLE_BINARY " << outbound_data_ << "\n";
+#else
+ boost::archive::text_oarchive archive( archive_stream );
+ archive << t;
+ outbound_data = archive_stream.str();
+#endif
+}
+
+template< typename T >
+void restore_from_string(const std::string& archive_data, T& t)
+{
+ std::istringstream archive_stream(archive_data);
+
+#if defined(BINARY_ARCHIVE)
+ // std::cout << "restore_from_string Archive BINARY\n";
+ boost::archive::binary_iarchive archive( archive_stream );
+
+#elif defined(PORTABLE_BINARY_ARCHIVE)
+ // std::cout << "restore_from_string Archive PORTABLE_BINARY\n";
+ portable_binary_iarchive archive( archive_stream );
+
+#elif defined(EOS_PORTABLE_BINARY_ARCHIVE)
+ // std::cout << "restore_from_string Archive EOS_PORTABLE_BINARY\n";
+ eos::portable_iarchive archive( archive_stream );
+
+#else
+ // std::cout << "restore_from_string Archive TEXT\n";
+ boost::archive::text_iarchive archive( archive_stream );
+
+#endif
+
+ archive >> t;
+}
+
+
+
+template< typename T >
+void restore(const std::string& fileName, T& restored, ecf::Archive::Type at = ecf::Archive::default_archive())
+{
+ // Argument added if in future we want to allow multiple archives, so we can choose
+
+#if defined(BINARY_ARCHIVE)
+ std::ifstream ifs( fileName.c_str(), std::ios::binary );
+ boost::archive::binary_iarchive ia( ifs );
+ ia >> restored;
+#elif defined(PORTABLE_BINARY_ARCHIVE)
+ std::ifstream ifs( fileName.c_str(), std::ios::binary );
+ portable_binary_iarchive ia( ifs );
+ ia >> restored;
+#elif defined(EOS_PORTABLE_BINARY_ARCHIVE)
+ std::ifstream ifs( fileName.c_str(), std::ios::binary );
+ eos::portable_iarchive ia( ifs );
+ ia >> restored;
+#else
+ std::ifstream ifs( fileName.c_str() );
+ boost::archive::text_iarchive ia( ifs );
+ ia >> restored;
+#endif
+}
+
+}
+#endif
diff --git a/ACore/src/SerializationTest.hpp b/ACore/src/SerializationTest.hpp
new file mode 100644
index 0000000..3bc231f
--- /dev/null
+++ b/ACore/src/SerializationTest.hpp
@@ -0,0 +1,71 @@
+#ifndef SERIALIZATION_TEST_HPP_
+#define SERIALIZATION_TEST_HPP_
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #16 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Simple class that defines the Archive types used for
+// Serialisation
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "Serialization.hpp"
+
+namespace ecf {
+
+// The following template functions are used test/debug only
+template < typename T >
+void do_restore(const std::string& fileName, const T& saved)
+{
+ T restored;
+ try { ecf::restore(fileName,restored); }
+ catch ( std::exception& e) { BOOST_CHECK_MESSAGE(false,"Restore failed because: " << e.what()); }
+ BOOST_CHECK_MESSAGE(saved == restored,"save and restored don't match for " << fileName << "\n");
+// BOOST_CHECK_MESSAGE(saved == restored," save and restored don't match\n" << saved << "\n" << restored );
+}
+
+template < typename T >
+void doRestore(const std::string& fileName, const T& saved)
+{
+ do_restore(fileName,saved);
+ std::remove(fileName.c_str());
+}
+
+template < typename T >
+void doSave(const std::string& fileName, const T& saved)
+{
+ try { ecf::save(fileName,saved); }
+ catch ( std::exception& e) { BOOST_CHECK_MESSAGE(false,"Save failed because: " << e.what()); }
+}
+
+template < typename T >
+void doSave(const std::string& fileName)
+{
+ T saved;
+ doSave(fileName,saved);
+}
+
+template < typename T >
+void doSaveAndRestore(const std::string& fileName, const T& saved)
+{
+ doSave(fileName,saved);
+ doRestore(fileName,saved);
+}
+
+template < typename T >
+void doSaveAndRestore(const std::string& fileName)
+{
+ T saved;
+ doSaveAndRestore(fileName,saved);
+}
+
+}
+#endif
diff --git a/ACore/src/Stl.hpp b/ACore/src/Stl.hpp
new file mode 100644
index 0000000..efab80d
--- /dev/null
+++ b/ACore/src/Stl.hpp
@@ -0,0 +1,71 @@
+#ifndef STL_HPP_
+#define STL_HPP_
+//============================================================================
+// Name : stl
+// Author : Avi
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+/*****************************************************************************
+ * Standard Library Include Files *
+ *****************************************************************************/
+#include <algorithm> //for for_each()
+//#include <iostream>
+
+
+namespace ecf
+{
+ /// Helper struct that will aid the deletion of Pointer from a container
+ template <typename T> struct TSeqDeletor {
+ void operator () (T pointer) {
+ // std::cout << "Destroy of this pointer" << std::endl;
+ delete pointer;
+ pointer = 0;
+ }
+ };
+ /// This function can be used to delete the pointers in a container
+ /// i.e int main (int argc, char **argv) {
+ /// std::vector <std::string *> vect;
+ /// vect.push_back (new std::string ("Stephane"));
+ /// DeletePtrs (vect);
+ /// }
+ template <typename Container> void DeletePtrs (Container& pContainer) {
+ std::for_each( pContainer.begin (),
+ pContainer.end (),
+ TSeqDeletor<typename Container::value_type> ());
+ pContainer.clear();
+ }
+
+
+ /// Helper struct that will aid the deletion of Pointer from a Associative container
+ template <typename TPair> struct TAsoDeletor {
+ void operator () (TPair& tElem) {
+ if(tElem.second) {
+ delete tElem.second;
+ }
+ }
+ };
+ /// This function can be used to delete the pointers in a Assoc container
+ /// i.e int main (int argc, char **argv) {
+ /// std::map <int,std::string *> theMap;
+ /// theMap[0] = new std::string ("Stephane");
+ /// AssoDeletePtrs(theMap);
+ /// }
+ template <typename Container> void AssoDeletePtrs (Container& pContainer) {
+ std::for_each( pContainer.begin (),
+ pContainer.end (),
+ TAsoDeletor<typename Container::value_type> ());
+ pContainer.clear();
+ }
+}
+
+#endif /* STL_HPP_ */
diff --git a/ACore/src/Str.cpp b/ACore/src/Str.cpp
new file mode 100644
index 0000000..71f287c
--- /dev/null
+++ b/ACore/src/Str.cpp
@@ -0,0 +1,346 @@
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #49 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : This class is used as a helper class
+//============================================================================
+#include <boost/algorithm/string/replace.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include "Str.hpp"
+
+using namespace std;
+
+namespace ecf {
+
+const char* VALID_NODE_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.";
+
+const char* Str::CHILD_CMD() { static const char* CHILD_CMD = "chd:"; return CHILD_CMD; }
+const char* Str::USER_CMD() { static const char* USER_CMD = "--"; return USER_CMD; }
+const char* Str::SVR_CMD() { static const char* SVR_CMD = "svr:"; return SVR_CMD; } // Only for automatic check_pt
+
+const std::string& Str::EMPTY() { static std::string empty = std::string(); return empty;}
+const std::string& Str::ROOT_PATH() { static std::string root_path = "/"; return root_path;}
+const std::string& Str::PATH_SEPERATOR() { static std::string path_sep = "/"; return path_sep;}
+const std::string& Str::COLON() { static std::string colon = ":"; return colon;}
+
+
+const std::string& Str::STATE_CHANGE() { static std::string state_change = " state change "; return state_change;}
+
+const std::string& Str::TASK() { static std::string task = "TASK"; return task; }
+const std::string& Str::FAMILY() { static std::string family = "FAMILY"; return family;}
+const std::string& Str::SUITE() { static std::string suite = "SUITE"; return suite;}
+const std::string& Str::ALIAS() { static std::string alias = "ALIAS"; return alias; }
+
+const std::string& Str::DEFAULT_PORT_NUMBER() { static std::string port_number = "3141"; return port_number;}
+const std::string& Str::LOCALHOST() { static std::string localhost = "localhost"; return localhost;}
+
+const std::string& Str::ECF_PORT() { static std::string ECF_PORT = "ECF_PORT"; return ECF_PORT;}
+const std::string& Str::ECF_RID() { static std::string ECF_RID = "ECF_RID"; return ECF_RID;}
+const std::string& Str::ECF_TRYNO() { static std::string ECF_TRYNO = "ECF_TRYNO"; return ECF_TRYNO;}
+const std::string& Str::ECF_TRIES() { static std::string ECF_TRIES = "ECF_TRIES"; return ECF_TRIES;}
+const std::string& Str::ECF_NAME() { static std::string ECF_NAME = "ECF_NAME"; return ECF_NAME; }
+const std::string& Str::ECF_NODE() { static std::string ECF_NODE = "ECF_NODE"; return ECF_NODE;}
+const std::string& Str::ECF_PASS() { static std::string ECF_PASS = "ECF_PASS";return ECF_PASS;}
+const std::string& Str::ECF_JOB() { static std::string ECF_JOB = "ECF_JOB"; return ECF_JOB;}
+const std::string& Str::ECF_JOBOUT() { static std::string ECF_JOBOUT = "ECF_JOBOUT"; return ECF_JOBOUT;}
+const std::string& Str::ECF_SCRIPT() { static std::string ECF_SCRIPT = "ECF_SCRIPT"; return ECF_SCRIPT;}
+const std::string& Str::ECF_DUMMY_TASK() { static std::string ECF_DUMMY_TASK = "ECF_DUMMY_TASK"; return ECF_DUMMY_TASK;}
+const std::string& Str::ECF_MICRO() { static std::string ECF_MICRO = "ECF_MICRO"; return ECF_MICRO;}
+const std::string& Str::ECF_FILES() { static std::string ECF_FILES = "ECF_FILES"; return ECF_FILES;}
+const std::string& Str::ECF_FETCH() { static std::string ECF_FETCH = "ECF_FETCH"; return ECF_FETCH;}
+const std::string& Str::ECF_KILL_CMD() { static std::string ECF_KILL_CMD = "ECF_KILL_CMD"; return ECF_KILL_CMD;}
+const std::string& Str::ECF_STATUS_CMD() { static std::string ECF_STATUS_CMD = "ECF_STATUS_CMD"; return ECF_STATUS_CMD;}
+
+const std::string& Str::ECF_HOME() { static std::string ECF_HOME = "ECF_HOME"; return ECF_HOME;}
+const std::string& Str::ECF_INCLUDE() { static std::string ECF_INCLUDE = "ECF_INCLUDE"; return ECF_INCLUDE;}
+const std::string& Str::ECF_JOB_CMD() { static std::string ECF_JOB_CMD = "ECF_JOB_CMD"; return ECF_JOB_CMD;}
+const std::string& Str::ECF_OUT() { static std::string ECF_OUT = "ECF_OUT"; return ECF_OUT;}
+const std::string& Str::ECF_EXTN() { static std::string ECF_EXTN = "ECF_EXTN"; return ECF_EXTN;}
+const std::string& Str::ECF_LOG() { static std::string ECF_LOG = "ECF_LOG"; return ECF_LOG;}
+
+
+const std::string& Str::WHITE_LIST_FILE() { static std::string WHITE_LIST_FILE = "ecf.lists"; return WHITE_LIST_FILE;}
+
+const std::string& Str::ALPHANUMERIC_UNDERSCORE()
+{
+ static string ALPHANUMERIC_UNDERSCORE = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
+ return ALPHANUMERIC_UNDERSCORE;
+}
+
+const std::string& Str::NUMERIC() { static string NUMERIC = "0123456789"; return NUMERIC; }
+
+void Str::removeQuotes(std::string& s)
+{
+ if (!s.empty()) {
+ if (s[0] == '"' && s[s.size()-1] == '"') {
+ s.erase(s.begin());
+ s.erase(s.begin() + s.size()-1);
+ }
+ }
+}
+// 047 is octal for '
+void Str::removeSingleQuotes(std::string& s)
+{
+ if (!s.empty()) {
+ if (s[0] == 047 && s[s.size()-1] == 047) {
+ s.erase(s.begin());
+ s.erase(s.begin() + s.size()-1);
+ }
+ }
+}
+
+bool Str::replace(std::string& jobLine, const std::string& stringToFind, const std::string& stringToRplace)
+{
+ size_t pos = jobLine.find(stringToFind);
+ if (pos != string::npos) {
+ jobLine.replace(pos,stringToFind.length(),stringToRplace);
+ return true;
+ }
+ return false;
+}
+
+bool Str::replace_all(std::string& subject, const std::string& search, const std::string& replace)
+{
+ bool replaced = false ;
+ size_t pos = 0;
+ while ((pos = subject.find(search, pos)) != std::string::npos) {
+ subject.replace(pos, search.length(), replace);
+ pos += replace.length();
+ replaced = true;
+ }
+ return replaced;
+}
+
+bool Str::extract_data_member_value(const std::string& str, const std::string& data_member_name, std::string& data_member_value)
+{
+ // 012345678901234567,
+ // str=cmd 1 user:mao
+ // data_member_name=user:
+ // data_member_value=ma0
+ std::string::size_type start = str.find(data_member_name);
+ if (start != std::string::npos) {
+ start += data_member_name.size();
+ data_member_value.clear();
+ for(size_t i = start; i < str.size(); i++) {
+ if (str[i] == ' ') break;
+ data_member_value += str[i];
+ }
+ return true;
+ }
+ return false;
+}
+
+
+void Str::replaceall(std::string& subject, const std::string& search, const std::string& replace)
+{
+ boost::replace_all(subject, search, replace);
+}
+
+void Str::split(const std::string& line, std::vector< std::string >& tokens,const std::string& delimiters )
+{
+ // ***************************************************************************
+ // Time for split 1000000 times = 5.81
+
+ // Skip delimiters at beginning.
+ string::size_type lastPos = line.find_first_not_of( delimiters, 0 );
+
+ // Find first "non-delimiter".
+ string::size_type pos = line.find_first_of( delimiters, lastPos );
+
+ while ( string::npos != pos || string::npos != lastPos ) {
+ tokens.push_back( line.substr( lastPos, pos - lastPos ) ); // Found a token, add it to the vector.
+ lastPos = line.find_first_not_of( delimiters, pos ); // Skip delimiters. Note the "not_of"
+ pos = line.find_first_of( delimiters, lastPos ); // Find next "non-delimiter"
+ }
+
+// // ***************************************************************************
+// // Time for split 1000000 times = 11.66
+//
+// // FAILS: with line = "\n", since I expect at least one token of "\n"
+// int i = 0;
+// char ch;
+// string word;
+// while ( (ch = line[i++]) ) {
+// if ( isspace( ch ) ) {
+// if ( !word.empty() ) tokens.push_back( word );
+// word = "";
+// }
+// else word += ch;
+// }
+// if ( !word.empty() ) tokens.push_back( word );
+
+// // ******************************************************************************
+// // Time for boost split > 20 seconds, this
+// boost::algorithm::split(result, line, std::bind2nd(std::equal_to<char>(), ' '));
+//
+// // ***************************************************************************
+// // Time for split 1000000 times = 30.38
+//
+// // FAILS: with line = "\n", since I expect at least one token of "\n"
+// char_separator< char > sep( " ",0, boost::drop_empty_tokens );
+// typedef boost::tokenizer< boost::char_separator< char > > tokenizer;
+// tokenizer theTokenizer( line, sep );
+// // std::copy( theTokenizer.begin(), theTokenizer.end(), back_inserter( tokens ) );
+//
+// for(tokenizer::iterator beg=theTokenizer.begin(); beg!=theTokenizer.end();++beg){
+// string token = *beg;
+// boost::algorithm::trim(token);
+// if (token.empty()) continue;
+// tokens.push_back(token);
+// }
+}
+
+static bool caseInsCharCompare(char a, char b) { return (toupper(a) == toupper(b)); }
+
+bool Str::caseInsCompare( const std::string& s1, const std::string& s2)
+{
+ return ( (s1.size() == s2.size()) && equal(s1.begin(),s1.end(), s2.begin(), caseInsCharCompare));
+}
+
+
+struct case_insensitive_less : public std::binary_function< char,char,bool >
+{
+ bool operator () (char x, char y) const {
+ if (toupper(x) == toupper(y)) {
+ return x > y;
+ }
+ return toupper( static_cast< unsigned char >(x)) <
+ toupper( static_cast< unsigned char >(y));
+ }
+};
+bool Str::caseInsLess( const std::string& a, const std::string& b)
+{
+ return std::lexicographical_compare( a.begin(),a.end(),
+ b.begin(),b.end(), case_insensitive_less() );
+}
+
+
+struct case_insensitive_greater : public std::binary_function< char,char,bool >
+{
+ bool operator () (char x, char y) const {
+ if (toupper(x) == toupper(y)) {
+ return x < y;
+ }
+ return toupper( static_cast< unsigned char >(x)) >
+ toupper( static_cast< unsigned char >(y));
+ }
+};
+bool Str::caseInsGreater( const std::string& a, const std::string& b)
+{
+ return std::lexicographical_compare( a.begin(),a.end(),
+ b.begin(),b.end(), case_insensitive_greater() );
+}
+
+
+bool Str::valid_name(const std::string& name, std::string &msg)
+{
+ // valid names are alphabetic (alphanumeric | underscore | .)
+ // however we can't have a leading '.' as that can interfere with trigger expressions
+
+ // verify that the string is not empty
+ if ( name.empty() ) {
+ msg = "Invalid name. Empty string.";
+ return false;
+ }
+
+ // verify that the first character is alphabetic or has underscore
+ bool result = Str::ALPHANUMERIC_UNDERSCORE().find( name[0], 0 ) != string::npos;
+ if ( !result ) {
+ msg = "Valid names can only consist of alphanumeric characters "
+ ",underscores and dots. The first character can not be a dot: ";
+ msg += name;
+ return false;
+ }
+
+ // verify that any other characters are alphanumeric or underscore
+ if (name.size() > 1) {
+ result = name.find_first_not_of(VALID_NODE_CHARS, 1) == string::npos;
+ if ( !result ) {
+ msg = "Valid names can only consist of alphanumeric characters "
+ ",underscores and dots. The first character can not be a dot: ";
+ msg += name;
+ }
+ }
+
+ return result;
+}
+
+bool Str::valid_name(const std::string& name)
+{
+ // valid names are alphabetic (alphanumeric | underscore | .)
+ // however we can't have a leading '.' as that can interfere with trigger expressions
+
+ // verify that the string is not empty
+ if ( name.empty() ) {
+ return false;
+ }
+
+ // verify that the first character is alphabetic or has underscore
+ bool result = Str::ALPHANUMERIC_UNDERSCORE().find( name[0], 0 ) != string::npos;
+ if ( !result ) {
+ return false;
+ }
+
+ // verify that any other characters are alphanumeric or underscore
+ if (name.size() > 1) {
+ result = name.find_first_not_of(VALID_NODE_CHARS, 1) == string::npos;
+ }
+
+ return result;
+}
+
+int Str::to_int( const std::string& the_str, int error_return)
+{
+ if ( the_str.find_first_of( Str::NUMERIC(), 0 ) != std::string::npos ) {
+ try {
+ return boost::lexical_cast< int >( the_str );
+ }
+ catch ( boost::bad_lexical_cast&) {}
+ }
+ return error_return;
+}
+
+bool Str::truncate_at_start( std::string& fileContents, size_t max_lines)
+{
+ if (fileContents.empty()) return false;
+
+ /// Truncate from the front
+ size_t no_of_new_lines = 0;
+ for(size_t i =fileContents.size()-1; i >0; --i) {
+ if (fileContents[i] == '\n') no_of_new_lines++;
+ if ( no_of_new_lines >= max_lines) {
+ fileContents.erase(fileContents.begin(),fileContents.begin() + i +1); //skip new line at start of file
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Str::truncate_at_end( std::string& fileContents, size_t max_lines)
+{
+ if (fileContents.empty()) return false;
+
+ /// Truncate from the back
+ size_t no_of_new_lines = 0;
+ size_t the_size = fileContents.size();
+ for(size_t i =0; i < the_size; ++i) {
+ if (fileContents[i] == '\n') no_of_new_lines++;
+ if ( no_of_new_lines >= max_lines) {
+ fileContents.erase(fileContents.begin()+i+1,fileContents.end()); //skip new line at end of file
+ return true;
+ }
+ }
+ return false;
+}
+
+}
diff --git a/ACore/src/Str.hpp b/ACore/src/Str.hpp
new file mode 100644
index 0000000..0a8b4a9
--- /dev/null
+++ b/ACore/src/Str.hpp
@@ -0,0 +1,150 @@
+#ifndef STR_HPP_
+#define STR_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #50 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : This class is used as a helper class
+//============================================================================
+#include <string.h> //for strcmp
+#include <string>
+#include <vector>
+#include <limits>
+#include <boost/noncopyable.hpp>
+
+namespace ecf {
+
+class Str : private boost::noncopyable {
+public:
+ static int reserve_4() { return 4; }
+ static int reserve_8() { return 8; }
+ static int reserve_16() { return 17; }
+ static int reserve_32() { return 32; }
+ static int reserve_64() { return 64; }
+
+ // remove any quotes on the string, else does nothing
+ // "fred" -> fred
+ // fred -> fred
+ static void removeQuotes(std::string&);
+
+ // remove any single quotes on the string, else does nothing
+ // 'fred' -> fred
+ // fred -> fred
+ static void removeSingleQuotes(std::string&);
+
+ /// Find 'stringToFind' in 'jobLine' and replace with string 'stringToRplace'
+ /// return true if replace ok else returns false;
+ static bool replace(std::string& jobLine, const std::string& stringToFind, const std::string& stringToRplace);
+ static bool replace_all(std::string& jobLine, const std::string& stringToFind, const std::string& stringToRplace);
+ static void replaceall(std::string& jobLine, const std::string& stringToFind, const std::string& stringToRplace);
+
+ // extract data member value, ie given a string of the form:
+ // str=cmd a b fred:value
+ // data_member_name=fred:
+ // extract value
+ static bool extract_data_member_value(const std::string& str, const std::string& data_member_name, std::string& data_member_value);
+
+ /// split string using default delimiters of space and tab as a separator;
+ /// The split is based on *ANY* of the characters in the delimiters.
+ /// **** Hence a delimiter of "==" will still split "a = complete"
+ /// **** sequential delimiter character are ignored ****
+ static void split(const std::string& str,
+ std::vector< std::string >& lineTokens,
+ const std::string& delimiters = " \t");
+
+ /// case in sensitive string comparison
+ static bool caseInsCompare( const std::string& str1, const std::string& str2);
+
+ /// case insenstive less
+ static bool caseInsLess( const std::string& str1, const std::string& str2);
+
+ /// case insenstive Greater
+ static bool caseInsGreater( const std::string& str1, const std::string& str2);
+
+ /// Used for checking node names
+ static bool valid_name(const std::string& name, std::string &msg);
+ static bool valid_name(const std::string& name);
+
+ /// Use this function when you are not sure if string is convertible to an integer.
+ /// This function will check if string has a numeric first & hence faster than
+ /// using boost::lexical_cast< int > alone. Will trap any exception
+ /// will return numeric_limits<int>::max() for invalid conversions
+ static int to_int( const std::string&, int error_return = std::numeric_limits<int>::max() );
+
+ /// Truncate the input string at the start/end if exceeds max_lines_ newlines
+ /// returns true if truncated false otherwise
+ static bool truncate_at_start( std::string& fileContents, size_t max_lines_);
+ static bool truncate_at_end( std::string& fileContents, size_t max_lines_);
+
+ /// Only use strcmp if the first characters are the same
+ static int local_strcmp(const char* s, const char* t)
+ {
+ return (*s != *t ? *s - *t : strcmp(s, t));
+ }
+
+ // returns a static string of alpha numerics and underscore
+ static const std::string& ALPHANUMERIC_UNDERSCORE();
+
+ // returns a static string of numerics chars
+ static const std::string& NUMERIC();
+
+ static const char* CHILD_CMD();
+ static const char* USER_CMD();
+ static const char* SVR_CMD(); // Only for automatic check_pt
+
+ // Allows string to be returned by reference
+ static const std::string& EMPTY() ;
+ static const std::string& ROOT_PATH(); // "/"
+ static const std::string& PATH_SEPERATOR() ; // "/"
+ static const std::string& COLON() ; // ":"
+
+ static const std::string& STATE_CHANGE();
+
+ static const std::string& TASK();
+ static const std::string& FAMILY();
+ static const std::string& SUITE();
+ static const std::string& ALIAS();
+
+ static const std::string& DEFAULT_PORT_NUMBER(); // "3141"
+ static const std::string& LOCALHOST();
+
+ static const std::string& ECF_PORT();
+ static const std::string& ECF_RID();
+ static const std::string& ECF_TRYNO();
+ static const std::string& ECF_TRIES();
+ static const std::string& ECF_NAME();
+ static const std::string& ECF_NODE();
+ static const std::string& ECF_PASS();
+ static const std::string& ECF_JOB();
+ static const std::string& ECF_JOBOUT();
+ static const std::string& ECF_SCRIPT();
+ static const std::string& ECF_DUMMY_TASK();
+ static const std::string& ECF_MICRO();
+ static const std::string& ECF_FILES();
+ static const std::string& ECF_FETCH();
+ static const std::string& ECF_KILL_CMD();
+ static const std::string& ECF_STATUS_CMD();
+
+ static const std::string& ECF_HOME();
+ static const std::string& ECF_INCLUDE();
+ static const std::string& ECF_JOB_CMD();
+ static const std::string& ECF_OUT();
+ static const std::string& ECF_EXTN();
+ static const std::string& ECF_LOG();
+
+ static const std::string& WHITE_LIST_FILE();
+private:
+ Str(){}
+};
+
+}
+
+#endif
diff --git a/ACore/src/TimeSeries.cpp b/ACore/src/TimeSeries.cpp
new file mode 100644
index 0000000..1466ffa
--- /dev/null
+++ b/ACore/src/TimeSeries.cpp
@@ -0,0 +1,836 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #78 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <boost/date_time/posix_time/time_formatters.hpp> // requires boost date and time lib
+#include "TimeSeries.hpp"
+#include "Indentor.hpp"
+#include "Calendar.hpp"
+#include "Log.hpp"
+#include "Str.hpp"
+#include "Ecf.hpp"
+#include "Extract.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+
+//#define DEBUG_TIME_SERIES 1
+//#define DEBUG_TIME_SERIES_IS_FREE 1
+
+static void testTimeSlot( const ecf::TimeSlot& ts)
+{
+ if (ts.hour() < 0 || ts.hour() > 23) {
+ std::stringstream ss; ss << "TimeSeries: time hour(" << ts.hour() << ") must be in range 0-23";
+ throw std::out_of_range(ss.str());
+ }
+ if (ts.minute() < 0 || ts.minute() > 59) {
+ std::stringstream ss; ss << "TimeSeries: time minute(" << ts.minute() << ") must be in range 0-59";
+ throw std::out_of_range(ss.str());
+ }
+}
+
+namespace ecf {
+
+TimeSeries::TimeSeries()
+: relativeToSuiteStart_(false),
+ isValid_(true),
+ relativeDuration_(0,0,0,0),
+ lastTimeSlot_(0,0,0,0) {}
+
+TimeSeries::TimeSeries(int hour, int minute, bool relative)
+: relativeToSuiteStart_(relative),
+ isValid_(true),
+ start_(hour,minute),
+ nextTimeSlot_(hour,minute),
+ relativeDuration_(0,0,0,0),
+ lastTimeSlot_(start_.duration())
+{
+ testTimeSlot(start_);
+}
+
+TimeSeries::TimeSeries(const TimeSlot& t,bool relative)
+: relativeToSuiteStart_(relative),
+ isValid_(true),
+ start_(t),
+ nextTimeSlot_(t),
+ relativeDuration_(0,0,0,0),
+ lastTimeSlot_(t.duration())
+{
+ testTimeSlot(start_);
+}
+
+TimeSeries::TimeSeries(const TimeSlot& start, const TimeSlot& finish, const TimeSlot& incr,bool relative)
+: relativeToSuiteStart_(relative),
+ isValid_(true),
+ start_( start ),
+ finish_( finish ),
+ incr_( incr ),
+ nextTimeSlot_( start ),
+ relativeDuration_(0,0,0,0)
+{
+ testTimeSlot(start);
+ testTimeSlot(finish);
+ testTimeSlot(incr);
+
+ if (!finish_.isNULL()) {
+ if (incr_.isNULL()) {
+ std::stringstream ss;
+ ss << "TimeSeries::TimeSeries: Invalid time series: Finish specified without an increment";
+ throw std::out_of_range( ss.str() );
+ }
+ }
+
+ if (start.duration() > finish.duration()) {
+ std::stringstream ss;
+ ss << "TimeSeries::TimeSeries: Invalid time series: Start time("
+ << start.toString() << ") is greater than end time(" << finish.toString() << ")";
+ throw std::out_of_range( ss.str() );
+ }
+ if ( incr.hour() == 0 && incr.minute() == 0 ) {
+ throw std::out_of_range( "TimeSeries::TimeSeries Invalid time series: Increment must be greater than 0 minutes.");
+ }
+ boost::posix_time::time_duration diff = finish.duration() - start.duration();
+ if ( incr.duration() > diff) {
+ std::stringstream ss;
+ ss << "TimeSeries::TimeSeries: Invalid time series: Increment(" << incr.toString() << ") is greater than duration "
+ << to_simple_string(diff)
+ << " between start(" << start.toString() << ") and finish(" << finish.toString() << ")";
+ throw std::out_of_range(ss.str());
+ }
+
+ compute_last_time_slot();
+
+#ifdef DEBUG_TIME_SERIES
+ cout << "TimeSeries::TimeSeries " << dump() << "\n";
+#endif
+}
+
+bool TimeSeries::operator<(const TimeSeries& rhs) const
+{
+ return start_ < rhs.start_;
+}
+
+void TimeSeries::compute_last_time_slot()
+{
+ if (!finish_.isNULL()) {
+ lastTimeSlot_ = start_.duration();
+ while ( lastTimeSlot_ <= finish_.duration()) lastTimeSlot_ += incr_.duration();
+ lastTimeSlot_ -= incr_.duration();
+ }
+}
+
+bool TimeSeries::calendarChanged( const ecf::Calendar& c )
+{
+ if ( relativeToSuiteStart_ ) {
+ relativeDuration_ += c.calendarIncrement();
+ return true;
+ }
+ else if (c.dayChanged()) {
+
+ // Clear expired flag and next slot. Needed since requue will expire flag when past time slot
+ // Hence we need something to reset. Otherwise for next day isFree will always return false;
+ isValid_ = true;
+ nextTimeSlot_ = start_;
+ return true;
+ }
+ return false;
+}
+
+bool TimeSeries::resetRelativeDuration()
+{
+ if ( relativeToSuiteStart_ ) {
+ relativeDuration_ = time_duration(0,0,0,0);
+ return true;
+ }
+#ifdef DEBUG_TIME_SERIES
+ cout << "TimeSeries::resetRelativeDuration " << dump() << "\n";
+#endif
+ return false;
+}
+
+void TimeSeries::reset(const ecf::Calendar& c)
+{
+ isValid_ = true;
+ nextTimeSlot_ = start_;
+
+ (void)resetRelativeDuration();
+
+ // Note: **difference between reset and re-queue,
+ // Hence if at begin(), time slot same as current time, allow job to run.
+ // reset : while( current_time > nextTimeSlot_.duration()) { // need for why command
+ // if (current_time > start_.duration() ) {
+ // requeue: while( current_time >= nextTimeSlot_.duration()) {
+ // if (current_time >= start_.duration() ) {
+
+ // Update nextTimeSlot_ so that why command works out of the box, when nodes have been begun.
+ // *if* the current time is *AT* the start do *not* increment nextTimeSlot_, otherwise we will miss first time slot
+ time_duration current_time = duration(c);
+ if (hasIncrement()) {
+
+ // only used when we have a series
+ suiteTimeAtReque_ = TimeSlot(c.suiteTime().time_of_day());
+ //cout << "TimeSeries::reset suiteTimeAtReque_: " << suiteTimeAtReque_ << " =====================================================\n";
+
+ while( current_time > nextTimeSlot_.duration()) {
+ time_duration value = nextTimeSlot_.duration();
+ value += incr_.duration();
+ nextTimeSlot_ = TimeSlot(value.hours(),value.minutes());
+ }
+ if (nextTimeSlot_ > finish_) {
+ isValid_ = false; // time has expired
+ }
+ }
+ else {
+ if (current_time > start_.duration() ) {
+ isValid_ = false; // time has expired
+ }
+ }
+
+#ifdef DEBUG_TIME_SERIES
+ LogToCout toCoutAsWell;
+ LOG(Log::DBG," TimeSeries::reset " << dump());
+#endif
+}
+
+void TimeSeries::requeue(const ecf::Calendar& c,bool reset_next_time_slot)
+{
+ // cout << "TimeSeries::requeue " << c.toString() << "\n";
+
+ // *RESET* to handle case where time slot has been advanced, but at requeue it must be reset
+ // This is important otherwise user can never reset and time slot that had been advanced
+ // by using miss_next_time_slot()
+ if (reset_next_time_slot) {
+ isValid_ = true;
+ nextTimeSlot_ = start_;
+ }
+
+ // time 13:00 // nextTimeSlot_ is initialised to 13:00, on TimeSeries::requeue() invalidate time series
+ // // to stop multiple job submissions on same time slot
+ // -------------------- nextTimeSlot_
+ // | -------------- isValid = false
+ // V V
+ // 10:00 11:00 12:00 13:00 14:00 15:00 16:00 17:00 18:00 19:00 20:00
+ // | | | | | | | | | | |
+ // ------time----------->
+ //
+ // TimeSeries::requeue(..) is called at the *re-queue* stage. *after*:
+ // a/ task has completed
+ // b/ checkForRequeue() has passed.
+ // hence if we get here for a single slot time, where calendar time >= start time
+ // then this time series is no longer valid. This will stop multiple job submission
+ // for the same time slot
+ time_duration current_time = duration(c);
+ if (!hasIncrement()) {
+ if (current_time >= start_.duration() ) {
+ isValid_ = false; // time has expired
+#ifdef DEBUG_TIME_SERIES
+ LOG(Log::DBG," TimeSeries::increment (duration(c) >= start_.duration() ) " << toString() << " duration=" << to_simple_string(duration(c)));
+#endif
+ }
+ return;
+ }
+
+ // only used when we have a series
+ suiteTimeAtReque_ = TimeSlot(c.suiteTime().time_of_day());
+// cout << "TimeSeries::requeue suiteTimeAtReque_: " << suiteTimeAtReque_ << " =====================================================\n";
+
+ // the nextTimeSlot_ needs to be set to a multiple of incr
+ // However the nextTimeSlot_ can not just be incremented by incr
+ // since we can't assume that a task completes within the given time slots
+ // *hence increments to NEXT TIME SLOT large than calendar time.
+ // time 10::00 20:00 01:00
+ // --------------------------------------------------------nextTimeSlot_ must greater than current time.
+ // | --------isValid = false
+ // V V
+ // 10:00 11:00 12:00 13:00 14:00 15:00 16:00 17:00 18:00 19:00 20:00 21:00
+ // | | | | | | | | | | | |
+ // ------time---->
+ //
+ while( current_time >= nextTimeSlot_.duration()) {
+ time_duration value = nextTimeSlot_.duration();
+ value += incr_.duration();
+ nextTimeSlot_ = TimeSlot(value.hours(),value.minutes());
+#ifdef DEBUG_TIME_SERIES
+ LOG(Log::DBG," TimeSeries::increment " << toString());
+#endif
+ }
+
+ if (nextTimeSlot_ > finish_) {
+ isValid_ = false; // time has expired
+ suiteTimeAtReque_ = TimeSlot(); // expire for new requeue
+#ifdef DEBUG_TIME_SERIES
+ LOG(Log::DBG," TimeSeries::increment " << toString());
+#endif
+ }
+}
+
+TimeSlot TimeSeries::compute_next_time_slot(const ecf::Calendar& c) const
+{
+ // This functionality needs to mirror TimeSeries::requeue
+ time_duration current_time = duration(c);
+ if (!hasIncrement()) {
+ if (current_time >= start_.duration() ) {
+ return TimeSlot(); // time has expired
+ }
+ return start_;
+ }
+
+ TimeSlot nextTimeSlot = start_;
+ while( current_time >= nextTimeSlot.duration()) {
+ time_duration value = nextTimeSlot.duration();
+ value += incr_.duration();
+ nextTimeSlot = TimeSlot(value.hours(),value.minutes());
+ }
+
+ if (nextTimeSlot > finish_) {
+ return TimeSlot(); // time has expired
+ }
+ return nextTimeSlot;
+}
+
+bool TimeSeries::requeueable(const ecf::Calendar& c) const
+{
+ boost::posix_time::time_duration calendar_time = duration(c);
+ if (calendar_time < start().duration()) return true;
+ if (hasIncrement()) {
+ if (calendar_time < finish().duration()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool TimeSeries::isFree(const ecf::Calendar& calendar) const
+{
+#ifdef DEBUG_TIME_SERIES_IS_FREE
+ LogToCout toCoutAsWell; Indentor indent;
+#endif
+
+ if (!isValid_) {
+ // time has expired, hence time is not free
+#ifdef DEBUG_TIME_SERIES_IS_FREE
+ LOG(Log::DBG,"TimeSeries::isFree (!isValid_) HOLDING " << dump());
+#endif
+ return false;
+ }
+
+ // Matched calendar duration with the current value of the time series
+ // or match with one of time slots.
+
+ // Note:: the definition file has time series format of hh:mm this
+ // means we have a minute resolution. The clock/calendar
+ // duration has seconds based resolution. hence we must
+ // compensate for this.
+ //
+ // time 10:00 20:00 01:00
+ // start
+ // | ----- next time slot --- finish
+ // | | |
+ // V V V
+ // 10:00 11:00 12:00 13:00 14:00 15:00 16:00 17:00 18:00 19:00 20:00
+ // | | | | | | | | | | |
+ // ------time---->
+ //
+ bool ret = match_duration_with_time_series(duration(calendar));
+// if (ret) {
+// std::cout << "TimeSeries::isFree " << dump() << " is free at calendar: " << calendar.toString() << "\n";
+// }
+ return ret;
+}
+
+
+bool TimeSeries::match_duration_with_time_series(const boost::posix_time::time_duration& relative_or_real_td) const
+{
+#ifdef DEBUG_TIME_SERIES_IS_FREE
+ Indentor ident;
+#endif
+
+ if ( !hasIncrement() ) {
+ // We ignore seconds, hence +00:02 will match 2.58 (two minutes 58 seconds) relative duration
+ time_duration start_td = start_.duration();
+ if ( relative_or_real_td.hours() == start_td.hours() && relative_or_real_td.minutes() == start_td.minutes()) {
+#ifdef DEBUG_TIME_SERIES_IS_FREE
+ LOG(Log::DBG,"TimeSeries::match_duration_with_time_series " << dump() << " FREE at " << to_simple_string(relative_or_real_td));
+#endif
+ return true;
+ }
+
+#ifdef DEBUG_TIME_SERIES_IS_FREE
+ LOG(Log::DBG,"TimeSeries::match_duration_with_time_series " << dump() << " HOLDING at " << to_simple_string(relative_or_real_td));
+#endif
+ return false;
+ }
+
+ time_duration endDuration = finish_.duration();
+ time_duration incrDuration = incr_.duration();
+ time_duration nextTimeSlot_td = nextTimeSlot_.duration();
+ long hours = relative_or_real_td.hours();
+ long minutes = relative_or_real_td.minutes();
+ while ( nextTimeSlot_td <= endDuration ) {
+
+ if ( hours == nextTimeSlot_td.hours() && minutes == nextTimeSlot_td.minutes()) {
+#ifdef DEBUG_TIME_SERIES_IS_FREE
+ LOG(Log::DBG,"TimeSeries::match_duration_with_time_series (nextTimeSlot_td == duration) " << dump()
+ << " FREE at " << to_simple_string(relative_or_real_td));
+#endif
+ return true;
+ }
+ nextTimeSlot_td += incrDuration;
+ }
+
+#ifdef DEBUG_TIME_SERIES
+ LOG(Log::DBG,"TimeSeries::matches HOLDING (nextTimeSlot_td > endDuration) " << dump() << " HOLDING at " << to_simple_string(relative_or_real_td));
+#endif
+ return false;
+}
+
+void TimeSeries::miss_next_time_slot()
+{
+ if ( !hasIncrement()) {
+ // single slot, does not have a next time slot, hence expire time
+ isValid_ = false;
+ }
+ else {
+ time_duration value = nextTimeSlot_.duration();
+ value += incr_.duration();
+ nextTimeSlot_ = TimeSlot(value.hours(),value.minutes());
+ if (nextTimeSlot_ > finish_) {
+ // time has expired,
+ isValid_ = false;
+ }
+ }
+}
+
+bool TimeSeries::checkForRequeue( const ecf::Calendar& calendar, const TimeSlot& the_min, const TimeSlot& the_max) const
+{
+ // ************************************************************************
+ // THIS IS CALLED IN THE CONTEXT WHERE NODE HAS COMPLETED. Hence ****asyncronous****
+ // RETURNING TRUE FROM HERE WILL FORCE NODE TO QUEUED STATE
+ // HENCE THIS FUNCTION MUST RETURN FALSE, WHEN END OF TIME SLOT HAS BEEN REACHED/expired
+ // The resolution is in minutes
+ // *************************************************************************
+ //cout << "TimeSeries::checkForRequeue " << calendar.toString() << "\n";
+
+ if (!isValid_) {
+ // time has expired, hence can no longer re-queues, i.e no future time dependency
+ return false;
+ }
+
+ if ( hasIncrement()) {
+ // Note if we are equal to the finish and were called as part of completeCmd
+ // then completeCmd will initiate a job submission immediately
+ // start 00:01
+ // finish 00:04 Node will be queued 4 times
+ // incr 00:01
+
+ // If the current value is greater that finish, then returning true would increment
+ // value past the end, and force node state to be stuck in state queue.
+ if ( nextTimeSlot_ > finish_ ) {
+ return false;
+ }
+
+ // ECFLOW-130 jobs that start before midnight and finish after midnight should not requeue
+ if (!suiteTimeAtReque_.isNULL()){
+ TimeSlot suiteTimeNow(calendar.suiteTime().time_of_day());
+ //cout << "TimeSeries::checkForRequeue suiteTimeNow = " << suiteTimeNow << " =====================================================\n";
+ // we use >= specifically for unit test, to pass.
+ if ( suiteTimeNow >= suiteTimeAtReque_) {
+ // normal flow, i.e same day
+ suiteTimeAtReque_ = TimeSlot(); // make NULL, allow reque to reset.
+ }
+ else {
+ // The day changed between (requeue/reset):->queued->submitted->active->complete->(checkForRequeue)
+ //cout << "TimeSeries::checkForRequeue day changed =====================================================\n";
+ return false;
+ }
+ }
+
+ time_duration calendar_duration = duration(calendar);
+ if ( calendar_duration < lastTimeSlot_) {
+ return true;
+ }
+ return false;
+ }
+
+ // *** When we have a single time slots we can not make a decision, whether
+ // *** we should re-queue based on this attribute *alone*. (i.e when we have > 1 time/today attributes)
+ // *** Hence we pass min and max time slots, over all the time bases attributes of the same kind.
+ // *** In our case we only do this for Time and Today attributes.
+ // *** The the_min/the_max have been computed for all attribute (i.e single time slots and ranges)
+
+ // We have a single time slot, *OR* multiple with same time slot
+ if (the_min == the_max) {
+ return false;
+ }
+
+ // The the_min/the_max takes into account *all* start/finish Time and Today attributes
+ time_duration calendar_duration = duration(calendar);
+ if (calendar_duration < the_max.duration()) {
+ return true;
+ }
+
+ return false;
+}
+
+
+void TimeSeries::min_max_time_slots(TimeSlot& the_min, TimeSlot& the_max) const
+{
+ if (the_min.isNULL() || start_ < the_min) the_min = start_;
+ if (the_max.isNULL() || start_ > the_max) the_max = start_;
+ if (hasIncrement()) {
+ if (finish_ < the_min) the_min = finish_;
+ if (finish_ > the_max) the_max = finish_;
+ }
+}
+
+
+void TimeSeries::why(const ecf::Calendar& c, std::string& theReasonWhy) const
+{
+ std::stringstream ss;
+ ss << " ( next run time is ";
+ if (relativeToSuiteStart_) ss << "+";
+ ss << nextTimeSlot_.toString();
+
+
+ TimeSlot currentTime = TimeSlot(duration(c));
+ ss << ", current suite time is ";
+ if (relativeToSuiteStart_) ss << "+";
+ ss << currentTime.toString() << " )";
+ theReasonWhy += ss.str();
+}
+
+boost::posix_time::time_duration TimeSeries::duration(const ecf::Calendar& c ) const
+{
+ // return with a minute resolution
+ if ( relativeToSuiteStart_ ) {
+
+ // relative to suite start only
+ return boost::posix_time::time_duration( relativeDuration_.hours(), relativeDuration_.minutes(), 0, 0 );
+ }
+
+ LOG_ASSERT(!c.suiteTime().is_special(),"init has not been called on calendar. TimeSeries::duration");
+ time_duration time_of_day = c.suiteTime().time_of_day();
+ return boost::posix_time::time_duration( time_of_day.hours(), time_of_day.minutes(), 0, 0 );
+}
+
+
+void TimeSeries::free_slots(std::vector<boost::posix_time::time_duration>& vec) const
+{
+ if (hasIncrement()) {
+
+ time_duration i = start_.duration();
+ time_duration endDuration = finish_.duration();
+ time_duration incrDuration = incr_.duration();
+ while ( i < endDuration ) {
+ vec.push_back(i);
+ i += incrDuration;
+ }
+ vec.push_back(finish_.duration());
+ return;
+ }
+
+ vec.push_back(start_.duration());
+}
+
+bool TimeSeries::structureEquals(const TimeSeries& rhs) const
+{
+ if (relativeToSuiteStart_ != rhs.relativeToSuiteStart_) return false;
+ if ( start_ != rhs.start_) return false;
+ if ( finish_ != rhs.finish_) return false;
+ if ( incr_ != rhs.incr_) return false;
+ return true;
+}
+
+bool TimeSeries::operator==(const TimeSeries& rhs) const
+{
+ // additional state
+ if (isValid_ != rhs.isValid_) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "TimeSeries::operator== ( isValid_ != rhs.isValid_) \n";
+ }
+#endif
+ return false;
+ }
+ if (nextTimeSlot_ != rhs.nextTimeSlot_) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "TimeSeries::operator== ( nextTimeSlot_ != rhs.nextTimeSlot_) \n";
+ }
+#endif
+ return false;
+ }
+ if (relativeDuration_ != rhs.relativeDuration_) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "TimeSeries::operator== ( relativeDuration_ != rhs.relativeDuration_) \n";
+ }
+#endif
+ return false;
+ }
+ return structureEquals(rhs);
+}
+
+std::ostream& TimeSeries::print(std::ostream& os) const
+{
+ os << toString() << "\n";
+ return os;
+}
+
+std::string TimeSeries::toString() const
+{
+ std::string ret ;
+ if (relativeToSuiteStart_) ret += "+";
+ ret += start_.toString();
+ if (!finish_.isNULL()) {
+ ret += " ";
+ ret += finish_.toString();
+ ret += " ";
+ ret += incr_.toString();
+ }
+ return ret;
+}
+
+std::string TimeSeries::dump() const
+{
+ std::stringstream ss;
+ ss << toString();
+ ss << " isValid_(" << isValid_ << ")";
+ ss << " value(" << nextTimeSlot_.toString() << ")";
+ ss << " relativeDuration_(" << to_simple_string( relativeDuration_) << ")";
+ ss << " lastTimeSlot_(" << to_simple_string(lastTimeSlot_) << ")";
+ return ss.str();
+}
+
+bool TimeSeries::checkInvariants(std::string& errormsg) const
+{
+ if (!finish_.isNULL()) {
+ if (incr_.isNULL()) {
+ errormsg += "TimeSeries::checkInvariants increment cannot be NULL when we have a time series";
+ cout << errormsg << " " << toString() << "\n";
+ return false;
+ }
+ if (incr_.hour() == 0 && incr_.minute() == 0) {
+ errormsg += "TimeSeries::checkInvariants increment must greater than zero";
+ cout << errormsg << " " << toString() << "\n";
+ return false;
+ }
+
+ if (start_.duration() > finish_.duration() ) {
+ errormsg += "TimeSeries::checkInvariants Invalid time series start() > finish()";
+ cout << errormsg << " " << toString() << "\n";
+ return false;
+ }
+
+ if (lastTimeSlot_ <= start_.duration() && lastTimeSlot_ > finish_.duration()) {
+ errormsg += "TimeSeries::checkInvariants Invalid last time slot";
+ cout << errormsg << " " << toString() << "\n";
+ return false;
+ }
+ }
+ if ( relativeDuration_.is_special()) {
+ errormsg += "TimeSeries::checkInvariants relativeDuration_ should not be special";
+ cout << errormsg << " " << toString() << "\n";
+ return false;
+ }
+ if (relativeToSuiteStart_ && relativeDuration_.hours() > 99) {
+ errormsg += "TimeSeries::checkInvariants. Max relative duration is 99 hours & 59 minutes";
+ cout << errormsg << " " << toString() << "\n";
+ return false;
+ }
+
+
+ if (!relativeToSuiteStart_ && relativeDuration_.total_seconds() > 0) {
+ errormsg += "TimeSeries::checkInvariants Can only have RelativeDuration if relativeToSuiteStart_ flag is set";
+ cout << errormsg << " " << toString() << "\n";
+ return false;
+ }
+
+ return true;
+}
+
+std::ostream& operator<<(std::ostream& os, const TimeSeries* d) {
+ if (d) return d->print(os);
+ return os << "TimeSlot == NULL";
+}
+std::ostream& operator<<(std::ostream& os, const TimeSeries& d) { return d.print(os); }
+
+
+ecf::TimeSeries TimeSeries::create(const std::string& str)
+{
+ std::vector<std::string> lineTokens;
+ Str::split(str,lineTokens);
+ size_t index = 0;
+ return TimeSeries::create(index,lineTokens );
+}
+
+std::string TimeSeries::state_to_string(bool isFree) const
+{
+ // *IMPORTANT* we *CANT* use ';' character, since is used in the parser, when we have
+ // multiple statement on a single line i.e.
+ // task a; task b;
+ // Hence use of '/' character
+ // time 10:30 # free isValid:false nextTimeSlot/10:30 relativeDuration/00:00:00
+ std::string ret;
+ bool next_time_slot_changed = ( nextTimeSlot_ != start_);
+ bool relative_duration_changed = (!relativeDuration_.is_special() && relativeDuration_.total_seconds() != 0);
+ if (isFree || !isValid_ || next_time_slot_changed || relative_duration_changed) {
+ ret += " #";
+ if (isFree) ret += " free";
+ if (!isValid_) ret += " isValid:false";
+ if (next_time_slot_changed) { ret += " nextTimeSlot/"; ret += nextTimeSlot_.toString(); }
+ if (relative_duration_changed) { ret += " relativeDuration/"; ret += to_simple_string(relativeDuration_); }
+ }
+ return ret;
+}
+
+void TimeSeries::parse_state(size_t index,const std::vector<std::string>& lineTokens, ecf::TimeSeries& ts)
+{
+ // *IMPORTANT* we *CANT* use ';' character, since is used in the parser, when we have
+ // multiple statement on a single line i.e.
+ // task a; task b;
+ // Hence use of '/' character
+ //
+ // Here free is attribute state & not time series state hence ignore
+ // time 10:30 # free isValid:false nextTimeSlot/10:30 relativeDuration/00:00:00
+ // cron 10:00 20:00 01:00 # free isValid:false nextTimeSlot/10:30 relativeDuration/00:00:00
+ bool comment_fnd = false;
+ for(size_t i = index; i < lineTokens.size(); i++) {
+ if (comment_fnd) {
+ if (lineTokens[i] == "isValid:false") { ts.isValid_ = false; continue;}
+ if (lineTokens[i].find("nextTimeSlot") != std::string::npos) {
+ std::string nextTimeSlot;
+ if (Extract::split_get_second(lineTokens[i],nextTimeSlot,'/')) {
+ // Note: we do *not* check for valid time since nextTimeSlot, can be incremented past 24 hours, ie
+ // cron 00:00 18:00 06:00 # isValid:false nextTimeSlot/24:00
+ int startHour = -1;
+ int startMin = -1;
+ getTime( nextTimeSlot, startHour, startMin, false/*check_time*/);
+ ts.nextTimeSlot_ = TimeSlot(startHour, startMin);
+ }
+ else throw std::runtime_error("TimeSeries::parse_state: could not extract state.");
+ }
+ if (lineTokens[i].find("relativeDuration") != std::string::npos) {
+ std::string relativeDuration;
+ if (Extract::split_get_second(lineTokens[i],relativeDuration,'/')) {
+ ts.relativeDuration_ = time_duration(duration_from_string(relativeDuration));
+ }
+ else throw std::runtime_error("TimeSeries::parse_state: could not extract state.");
+ }
+ }
+ if (lineTokens[i] == "#") comment_fnd = true;
+ }
+ ts.compute_last_time_slot();
+}
+
+ecf::TimeSeries TimeSeries::create( size_t& index,const std::vector<std::string>& lineTokens,bool read_state )
+{
+ assert( index < lineTokens.size() );
+ int startHour = -1;
+ int startMin = -1;
+
+ // cron 10:00 20:00 01:00
+ // index is on 10:00, ie index should have value of 1 in this case
+ string startStr = lineTokens[index];
+ bool relative = false;
+ if ( startStr[0] == '+' ) {
+ relative = true;
+ startStr.erase( startStr.begin() ); // remove leading +
+ // string must be of form 12:00
+ }
+ getTime( startStr, startHour, startMin );
+ TimeSlot start( startHour, startMin );
+
+ index++; // on 20:00
+ if ( index < lineTokens.size() && lineTokens[index][0] != '#' ) {
+
+ // if third token is not a comment the time must be of the form
+ // cron 10:00 20:00 01:00
+ if ( index+1 >= lineTokens.size() ) throw std::runtime_error( "TimeSeries::create: Invalid time series :");
+
+ int finishHour = -1;
+ int finishMin = -1;
+ getTime( lineTokens[index], finishHour, finishMin );
+ TimeSlot finish( finishHour, finishMin );
+
+ index++;
+
+ int incrHour = -1;
+ int incrMin = -1;
+ getTime( lineTokens[index], incrHour, incrMin );
+ TimeSlot incr( incrHour, incrMin );
+
+
+ if (read_state) {
+ TimeSeries ts(start,finish,incr,relative);
+ parse_state(index,lineTokens,ts);
+ return ts;
+ }
+ return TimeSeries(start,finish,incr,relative);
+ }
+
+ if (read_state) {
+ TimeSeries ts(start,relative);
+ parse_state(index,lineTokens,ts);
+ return ts;
+ }
+ return TimeSeries(start,relative);
+}
+
+bool TimeSeries::getTime(const std::string& time, int& hour, int& min,bool check_time)
+{
+ // HH:MM
+ // +HH:MM for other clients
+ size_t colonPos = time.find_first_of(':');
+ if (colonPos == string::npos) throw std::runtime_error("TimeSeries::getTime: Invalid time :'" + time + "'");
+
+ std::string theHour ;
+ bool relative = false;
+ if ( time[0] == '+') {
+ relative = true;
+ theHour = time.substr(1,colonPos-1);
+ }
+ else theHour = time.substr(0,colonPos);
+
+ std::string theMin = time.substr(colonPos+1);
+
+ if (theHour.size() != 2) throw std::runtime_error("TimeSeries::getTime: Invalid hour :" + theHour);
+ if (theMin.size() != 2) throw std::runtime_error("TimeSeries::getTime: Invalid minute :" + theMin);
+
+ hour = Extract::theInt(theHour,"TimeSeries::getTime: hour must be a integer : " + theHour);
+ min = Extract::theInt(theMin,"TimeSeries::getTime: minute must be integer : " + theMin);
+
+ if (check_time) testTime(hour,min);
+ return relative;
+}
+
+void TimeSeries::testTime(int hour, int minute)
+{
+ if (hour == -1 || minute == -1) {
+ throw std::runtime_error("TimeSeries::testTime: Failed to extract time");
+ }
+ if (hour < 0 || hour > 23) {
+ std::stringstream ss; ss << "TimeSeries::testTime: time hour(" << hour << ") must be in range 0-23";
+ throw std::runtime_error(ss.str());
+ }
+ if (minute < 0 || minute > 59) {
+ std::stringstream ss; ss << "TimeSeries::testTime: time minute(" << minute << ") must be in range 0-59";
+ throw std::runtime_error(ss.str());
+ }
+}
+
+}
+
diff --git a/ACore/src/TimeSeries.hpp b/ACore/src/TimeSeries.hpp
new file mode 100644
index 0000000..c2d9198
--- /dev/null
+++ b/ACore/src/TimeSeries.hpp
@@ -0,0 +1,215 @@
+#ifndef TIMESERIES_HPP_
+#define TIMESERIES_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #57 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : A single or set of times
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "TimeSlot.hpp"
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/date_time/posix_time/time_serialize.hpp>
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/level.hpp>
+#include <boost/serialization/tracking.hpp>
+
+namespace ecf { class Calendar;} // forward declare class
+
+namespace ecf {
+/// TimeSeries can have a single time slot or a series of time slots
+///
+///
+/// We need nextTimeSlot_ data member to record the next valid time slot, otherwise when
+/// we have a time series, all times within the time series would be valid for
+/// Job submission. We do not know how long a job will run, hence when incrementing
+/// the nextTimeSlot_, we need the *NEXT* available time slot *after* the current calendar time.
+///
+/// Usage pattern is :
+/// TimeSeries.calendarChanged() // Called every minute. Calls isFree(). Once free we stay free, until requeue.
+/// // At midnight clear time expiration and reset next time slot
+/// TimeSeries.isFree(..) // called when node is QUEUED:
+/// // during dependency evaluation, checks next time slot, against calendar time
+/// // Once free a node stays free, until requeue()
+/// TimeSeries.checkForRequeue(); // called when node is COMPLETE: Checks if next available time slot is valid
+/// // *Must* return false for last time slot
+/// // ECFLOW-130 jobs that start before midnight and finish after midnight should not requeue
+/// TimeSeries.requeue(); // called when node is re-queued.
+/// // Sets value to next valid time slot after calendar time.
+/// // Can *expire* the time, relies on TimeSeries.calendarChanged() to clear time expiration
+/// // after midnight
+/// ECFLOW-130 jobs that start before midnight and finish after midnight should not requeue
+
+// Use compiler, destructor, copy constructor and assignment operator
+class TimeSeries {
+public:
+ TimeSeries();
+ TimeSeries(int hour, int minute, bool relativeToSuiteStart = false );
+ TimeSeries(const TimeSlot&, bool relativeToSuiteStart = false );
+ TimeSeries(const TimeSlot& start, const TimeSlot& finish, const TimeSlot& incr,bool relativeToSuiteStart = false);
+
+ bool operator<(const TimeSeries& rhs) const;
+
+ // returns true if a state change is made
+ // Will clear time expiration flag at midnight
+ bool calendarChanged( const ecf::Calendar& c);
+
+ // relative duration stored locally since it can be reset, when used with repeats
+ // returns true if relative duration is reset/ i.e state change has been made
+ bool resetRelativeDuration();
+ void reset(const ecf::Calendar& c);
+
+ // Increment time series. Will find the next time slot after current calendar
+ // record the current suite time, to check of jobs finish after midnight
+ void requeue(const ecf::Calendar& c,bool reset_next_time_slot = true);
+
+ // Since we can miss next time slot , allow its computation for the
+ // use with why command, returns a NULL timeslot if next time is invalid
+ // This functionality will mirror the requeue(..) function
+ TimeSlot compute_next_time_slot(const ecf::Calendar& c) const;
+
+ // Return true calendar is before or within scheduled time
+ bool requeueable(const ecf::Calendar& c) const;
+
+ /// if relativeToSuiteStart returns the relative duration, else returns calendar suite time of day.
+ /// The returned resolution is in minutes
+ boost::posix_time::time_duration duration(const ecf::Calendar& calendar ) const;
+
+ /// If time has expired, returns false
+ /// Note: relative means relative to suite start, or relative to the beginning of repeated node.
+ /// Is of the form hh:mm. This means relative has a range 00:00->99.59
+ /// For a single slot time series, should not be re queued again, and hence
+ /// should fail checkForRequeue. Likewise when the the current value is
+ /// the finish, then node should also not be re queued, otherwise the
+ /// node will be stuck in queued state.
+ bool isFree(const ecf::Calendar& calendar) const;
+
+ /// For single slot time based attributes we need additional context (i.e the_min,the_max parameter)
+ /// in order to determine whether we should re-queue.
+ /// Additionally when we have a time range, what if the last jobs runs over midnight. In this case
+ /// we need to return false. i.e do not re-queue ECFLOW-130
+ bool checkForRequeue( const ecf::Calendar& calendar, const TimeSlot& the_min, const TimeSlot& the_max) const;
+
+ void min_max_time_slots(TimeSlot& the_min, TimeSlot& the_max) const;
+
+ // Called when explicitly Free holding time dependency. via FreeDepCmd
+ // We want to avoid the next time slot.
+ void miss_next_time_slot();
+
+ void why(const ecf::Calendar&, std::string& theReasonWhy) const;
+
+ bool hasIncrement() const { return !finish_.isNULL();}
+ const TimeSlot& start() const { return start_; }
+ const TimeSlot& finish() const { return finish_;}
+ const TimeSlot& incr() const { return incr_; }
+ const TimeSlot& value() const { return nextTimeSlot_; }
+ bool relative() const { return relativeToSuiteStart_; }
+ void free_slots(std::vector<boost::posix_time::time_duration>& ) const;
+
+ std::ostream& print(std::ostream&) const;
+ bool operator==(const TimeSeries& rhs) const;
+ bool operator!=(const TimeSeries& rhs) const { return !operator==(rhs);}
+ bool structureEquals(const TimeSeries& rhs) const;
+
+ /// returns true if no time specified
+ bool isNULL() const { return start_.isNULL(); }
+
+ std::string state_to_string(bool isFree) const;
+ std::string toString() const;
+ std::string dump() const;
+ bool checkInvariants(std::string& errormsg) const;
+
+ /// expects HH:MM or +HH:MM will throw std:runtime_error for errors,
+ /// *if* hour not in range(0-24), minutes(0-59), *and* check_time parameter is enabled
+ static bool getTime(const std::string& time, int& hour, int& min, bool check_time = true);
+
+ /// extract string like
+ /// time +00:00 20:00 00:10 # this is a comment which will be ignored. index = 1
+ /// time +20:00 // index = 1
+ /// today 20:00 // index = 1
+ /// +00:00 20:00 00:10 // index = 0
+ /// +20:00 // index = 0
+ /// will throw std:runtime_error for errors
+ /// will assert if index >= lineTokens.size()
+ static ecf::TimeSeries create(size_t& index, // where we should start
+ const std::vector<std::string>& lineTokens,
+ bool read_state = false);
+
+ // like above but string should not contain "time"
+ static ecf::TimeSeries create(const std::string& str);
+
+ // Parse state associated with the time series: Ignores attributes like free.
+ static void parse_state(size_t index,const std::vector<std::string>& lineTokens, ecf::TimeSeries& ts);
+ void set_isValid(bool b) { isValid_= b;} // for test only
+ void set_next_time_slot( const TimeSlot& ts) { nextTimeSlot_ = ts; } // needed for test only
+ const TimeSlot& get_next_time_slot() const { return nextTimeSlot_;}
+
+ // Is the time still valid, return false means time has expired.
+ bool is_valid() const { return isValid_;}
+private:
+
+ static void testTime(int hour, int minute);
+
+ // HANDLE CASE WHERE FINISH MINUTES IS NOT DIVISIBLE BY THE INCREMENT
+ // time 00:00 23:59 00:10 last valid time is 23:50
+ // time 00:30 23:59 04:00 last valid time is 20:30
+ // The last valid time here is 23:50/20:30 must return false, to stop node being
+ // stuck in queued mode In the case where the FINISH is NOT a multiple of the increment
+ // Need a different mechanism to determine the end.
+ void compute_last_time_slot(); // only call for series
+
+ bool match_duration_with_time_series(const boost::posix_time::time_duration& relative_or_real_td) const;
+ boost::posix_time::time_duration relativeDuration() const;
+
+private:
+ bool relativeToSuiteStart_;
+ bool isValid_; // Needed for single slot to avoid multiple jobs submissions
+ TimeSlot start_;
+ TimeSlot finish_;
+ TimeSlot incr_;
+ TimeSlot nextTimeSlot_; // nextTimeSlot_ >= start && is incremented by incr
+ mutable TimeSlot suiteTimeAtReque_; // NOT persisted, check of day change, between requeue -> checkForRequeue, when we have series
+ boost::posix_time::time_duration relativeDuration_;
+ boost::posix_time::time_duration lastTimeSlot_; // Only used when we have a series, can be generated
+
+private:
+ // Note: isValid_ is persisted for use by why() command on the client side.
+ // Note: nextTimeSlot_ is persisted for use by why() command on the client side.
+ // Note: relativeDuration_ is persisted for use by why() command on the client side.
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/)
+ {
+ ar & relativeToSuiteStart_;
+ ar & isValid_;
+ ar & start_;
+ ar & finish_;
+ ar & incr_;
+ ar & nextTimeSlot_;
+ ar & relativeDuration_;
+
+ if (Archive::is_loading::value) {
+ if (!finish_.isNULL()) {
+ compute_last_time_slot();
+ }
+ }
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, const TimeSeries*);
+std::ostream& operator<<(std::ostream& os, const TimeSeries&);
+}
+
+// This should ONLY be added to objects that are *NOT* serialised through a pointer
+BOOST_CLASS_IMPLEMENTATION(ecf::TimeSeries, boost::serialization::object_serializable);
+BOOST_CLASS_TRACKING(ecf::TimeSeries,boost::serialization::track_never);
+
+#endif
diff --git a/ACore/src/TimeSlot.cpp b/ACore/src/TimeSlot.cpp
new file mode 100644
index 0000000..e7d6911
--- /dev/null
+++ b/ACore/src/TimeSlot.cpp
@@ -0,0 +1,89 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #16 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "TimeSlot.hpp"
+#include "Calendar.hpp"
+#include "Str.hpp"
+
+using namespace boost::posix_time;
+
+namespace ecf {
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+bool TimeSlot::operator<(const TimeSlot& rhs) const
+{
+ if (hour_ < rhs.hour()) return true;
+ if (hour_ == rhs.hour()) {
+ return minute_ < rhs.minute();
+ }
+ return false;
+}
+
+bool TimeSlot::operator>(const TimeSlot& rhs) const
+{
+ if (hour_ > rhs.hour()) return true;
+ if (hour_ == rhs.hour()) {
+ return minute_ > rhs.minute();
+ }
+ return false;
+}
+
+bool TimeSlot::operator<=( const TimeSlot& rhs ) const
+{
+ if (operator<(rhs)) return true;
+ return operator==(rhs);
+}
+
+
+bool TimeSlot::operator>=( const TimeSlot& rhs ) const
+{
+ if (operator>(rhs)) return true;
+ return operator==(rhs);
+}
+
+
+std::ostream& TimeSlot::print(std::ostream& os) const
+{
+ os << toString();
+ return os;
+}
+
+std::string TimeSlot::toString() const
+{
+ std::stringstream ss;
+ if (hour_ < 10) ss << "0" << hour_;
+ else ss << hour_;
+
+ ss << Str::COLON();
+ if (minute_ < 10) ss << "0" << minute_;
+ else ss << minute_;
+ return ss.str();
+}
+
+boost::posix_time::time_duration TimeSlot::duration() const
+{
+ assert(!isNULL());
+ return boost::posix_time::time_duration( hours(hour_) + minutes(minute_) ) ;
+}
+
+
+std::ostream& operator<<(std::ostream& os, const TimeSlot* d) {
+ if (d) return d->print(os);
+ return os << "TimeSlot == NULL";
+}
+std::ostream& operator<<(std::ostream& os, const TimeSlot& d) { return d.print(os); }
+
+}
diff --git a/ACore/src/TimeSlot.hpp b/ACore/src/TimeSlot.hpp
new file mode 100644
index 0000000..08ee8b1
--- /dev/null
+++ b/ACore/src/TimeSlot.hpp
@@ -0,0 +1,86 @@
+#ifndef TIMESLOT_HPP_
+#define TIMESLOT_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #11 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "boost/date_time/posix_time/posix_time_types.hpp"
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/level.hpp>
+#include <boost/serialization/tracking.hpp>
+#include <ostream>
+
+namespace ecf {
+
+// Use compiler , generated destructor, assignment, copy constructor
+// *relative* times can extend to a maximum of 99 hours and 59 seconds
+//
+// TimeSlot is used in many other attributes, i.e. like AutoCancelAttr
+// in this case user can specify days, which we convert to hours, hence it
+// is possible for a TimeSlot hour to have any integer value
+class TimeSlot {
+public:
+ TimeSlot()
+ : hour_(0), minute_(0),isNull_(true) {}
+ TimeSlot(int hour, int min)
+ : hour_(hour), minute_(min),isNull_(false)
+ { assert(hour >= 0 && min >=0 ); }
+ TimeSlot(const boost::posix_time::time_duration& td)
+ : hour_(td.hours()), minute_(td.minutes()),isNull_(false)
+ { assert( hour_ < 60 && minute_ < 60);}
+
+ bool operator==(const TimeSlot& rhs) const
+ { return ((hour_ == rhs.hour_) && (minute_ == rhs.minute_) && (isNull_ == rhs.isNull_));}
+ bool operator!=(const TimeSlot& rhs) const
+ { return !operator==(rhs);}
+
+ bool operator<(const TimeSlot& rhs) const;
+ bool operator>(const TimeSlot& rhs) const;
+ bool operator<=(const TimeSlot& rhs) const;
+ bool operator>=(const TimeSlot& rhs) const;
+
+ int hour() const { return hour_;}
+ int minute() const { return minute_;}
+ bool isNULL() const { return isNull_; }
+ std::ostream& print(std::ostream&) const;
+
+ /// returns the corresponding duration.
+ boost::posix_time::time_duration duration() const;
+
+ // returns struct in the format hh:mm
+ std::string toString() const;
+
+private:
+ unsigned short hour_;
+ unsigned short minute_;
+ bool isNull_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/) {
+ ar & hour_;
+ ar & minute_;
+ ar & isNull_;
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, const TimeSlot*);
+std::ostream& operator<<(std::ostream& os, const TimeSlot&);
+}
+
+// This should ONLY be added to objects that are *NOT* serialised through a pointer
+BOOST_CLASS_IMPLEMENTATION(ecf::TimeSlot, boost::serialization::object_serializable);
+BOOST_CLASS_TRACKING(ecf::TimeSlot,boost::serialization::track_never);
+
+#endif
diff --git a/ACore/src/TimeStamp.cpp b/ACore/src/TimeStamp.cpp
new file mode 100644
index 0000000..f95a02d
--- /dev/null
+++ b/ACore/src/TimeStamp.cpp
@@ -0,0 +1,40 @@
+//============================================================================
+// Name : Log
+// Author : Avi
+// Revision : $Revision: #57 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Simple singleton implementation of log
+//============================================================================
+#include "TimeStamp.hpp"
+#include <cstdio>
+
+using namespace std;
+
+namespace ecf {
+
+std::string TimeStamp::now()
+{
+ std::string time_stamp;
+ now(time_stamp);
+ return time_stamp;
+}
+
+void TimeStamp::now(std::string& time_stamp)
+{
+ char t_fmt[255];
+ time_t stamp = time( NULL);
+ struct tm *tod = localtime(&stamp);
+ sprintf(t_fmt, "[%02d:%02d:%02d %d.%d.%d] ", tod->tm_hour, tod->tm_min, tod->tm_sec,
+ tod->tm_mday, tod->tm_mon + 1, tod->tm_year + 1900);
+
+ time_stamp = t_fmt;
+}
+
+}
diff --git a/ACore/src/TimeStamp.hpp b/ACore/src/TimeStamp.hpp
new file mode 100644
index 0000000..cf232cd
--- /dev/null
+++ b/ACore/src/TimeStamp.hpp
@@ -0,0 +1,35 @@
+#ifndef TIMESTAMP_HPP_
+#define TIMESTAMP_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name : Log
+// Author : Avi
+// Revision : $Revision: #31 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <string>
+#include <boost/noncopyable.hpp>
+
+namespace ecf {
+
+// returns a string of format : "[%02d:%02d:%02d %d.%d.%d] "
+// "[hour:min:sec day.month.year] "
+// i.e "[05:26:20 29.10.2014] "
+class TimeStamp : private boost::noncopyable {
+public:
+ static std::string now();
+ static void now(std::string&);
+private:
+ TimeStamp();
+};
+
+}
+
+#endif
diff --git a/ACore/src/Version.cpp b/ACore/src/Version.cpp
new file mode 100644
index 0000000..4da8049
--- /dev/null
+++ b/ACore/src/Version.cpp
@@ -0,0 +1,131 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #132 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <sstream>
+#include "Version.hpp"
+#include "ecflow_version.h"
+#include <boost/version.hpp>
+
+namespace ecf {
+
+// ********************************************************************
+// IMPORTANT:
+// The version number is extracted externally.
+// see ACore/doc/extracting_version_number.ddoc
+//
+// See ACore/src/ecflow_version.h"
+// This file is generated from $WK/VERSION.cmake when cmake is run, i.e
+// sh -x $WK/cmake.sh debug
+//
+// It is also extracted by python, from VERSION.CMAKE check build_scripts/nightly/build.py
+// This minimises the places where we have hard code the version number.
+//
+// When changing the version change remember to:
+// - re-login into remote system to update ECFLOW_INSTALL_DIR & ECFLOW_PYTHON_INSTALL_DIR
+// required for interactive install
+//
+// To Install a new version on all the different platforms:
+// . build_scripts/nightly/quick_install_.sh
+// This is because the definition hold's the last version.
+// Hence we must rerun to update the version.
+//
+// ************************************************************************************
+// Use <minor_number>rc<number> for release candidates, Once release we revert back:
+// 0rc1 -> 0
+// 10rc3 -> 10
+// ************************************************************************************
+//
+// **Please update file history.ddoc with the changed made for each release ***
+// ********************************************************************
+#ifdef DEBUG
+const std::string Version::TAG = " (debug)"; // Old tag: beta(debug)
+#else
+const std::string Version::TAG = ""; // Old tag: beta
+#endif
+
+
+// See: http://www.cmake.org/cmake/help/cmake_tutorial.html
+// For defining version numbers. This is done is a separate file
+// that is then included
+std::string Version::description()
+{
+ std::stringstream ss;
+ ss << "Ecflow" << Version::TAG << " version(" << ECFLOW_RELEASE << "." << ECFLOW_MAJOR << "." << ECFLOW_MINOR;
+
+ ss << ") boost(" << Version::boost() << ")";
+ std::string the_comp = compiler();
+ if (!the_comp.empty()) ss << " compiler(" << the_comp << ")";
+
+ ss << " protocol(";
+#if defined(BINARY_ARCHIVE)
+ ss << "BINARY_ARCHIVE)";
+#elif defined(PORTABLE_BINARY_ARCHIVE)
+ ss << "PORTABLE_BINARY_ARCHIVE)";
+#elif defined(EOS_PORTABLE_BINARY_ARCHIVE)
+ ss << "EOS_PORTABLE_BINARY_ARCHIVE)";
+#else
+ ss << "TEXT_ARCHIVE)";
+#endif
+
+ ss << " Compiled on " << __DATE__ << " " << __TIME__;
+ return ss.str();
+}
+
+std::string Version::version()
+{
+ std::stringstream ss;
+ ss << "ecflow_" << ECFLOW_RELEASE << "_" << ECFLOW_MAJOR << "_" << ECFLOW_MINOR;
+ return ss.str();
+}
+
+std::string Version::raw()
+{
+ std::stringstream ss;
+ ss << ECFLOW_RELEASE << "." << ECFLOW_MAJOR << "." << ECFLOW_MINOR;
+ return ss.str();
+}
+
+std::string Version::boost()
+{
+ std::stringstream ss;
+ ss << BOOST_VERSION / 100000 << "." // major version
+ << BOOST_VERSION / 100 % 1000 << "." // minor version
+ << BOOST_VERSION % 100; // patch level
+ return ss.str();
+}
+
+std::string Version::compiler()
+{
+ std::stringstream ss;
+#if defined(_AIX)
+ ss << "aix " << __IBMCPP__ ;
+#elif defined(HPUX)
+ ss << "aCC " << __HP_aCC ; // type aCC +help, this will show compiler manual, search for Predefined Macros
+#else
+#if defined(__clang__)
+ // To find the list of defines for clang use:
+ // echo | /usr/local/apps/clang/current/bin/clang++ -dM -E -
+ ss << "clang " << __clang_major__ << "." << __clang_minor__ ;
+#elif defined(__INTEL_COMPILER)
+ ss << "intel " << __INTEL_COMPILER;
+#elif defined(_CRAYC)
+ ss << "cray " << _CRAYC;
+#else
+ ss << "gcc " << __GNUC__ << "." << __GNUC_MINOR__ << "." << __GNUC_PATCHLEVEL__;
+#endif
+#endif
+ return ss.str();
+}
+
+}
diff --git a/ACore/src/Version.hpp b/ACore/src/Version.hpp
new file mode 100644
index 0000000..19d79ff
--- /dev/null
+++ b/ACore/src/Version.hpp
@@ -0,0 +1,56 @@
+#ifndef VERSION_HPP_
+#define VERSION_HPP_
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #15 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Holds the version of ECFlow. Checked against definition file
+// For each major release the major number should be
+// incremented.
+// If the parsing comes across a construct it does not recognize, then
+// an exception is thrown. i.e if a construct added in release 2.0 of ECF
+// is read in by version 1.0 of ECF. The exception should indicate the
+// current release
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <boost/noncopyable.hpp>
+#include <string>
+
+namespace ecf {
+
+class Version : private boost::noncopyable {
+public:
+ /// Outputs a string of the form:
+ /// ECF <tag> version release_.major_.minor_
+ static std::string description();
+
+ /// Outputs string of form: ecflow_<release>_<major>_<minor>
+ /// This could be used by install
+ static std::string version();
+
+ /// Outputs string of form: <release>.<major>.<minor>
+ static std::string raw();
+
+private:
+ Version();
+
+ static const std::string TAG; // alpha, beta, release
+
+private:
+ /// return version of the boost library
+ static std::string boost();
+
+ // Return the version of the compiler. Can return empty string
+ static std::string compiler();
+};
+}
+#endif
diff --git a/ACore/src/WhiteListFile.cpp b/ACore/src/WhiteListFile.cpp
new file mode 100644
index 0000000..fb3932f
--- /dev/null
+++ b/ACore/src/WhiteListFile.cpp
@@ -0,0 +1,250 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Parser for white list file
+//============================================================================
+#include <pwd.h> /* getpwuid */
+#include <vector>
+#include <iostream>
+#include <boost/lexical_cast.hpp>
+#include <boost/algorithm/string/trim.hpp>
+
+#include "WhiteListFile.hpp"
+#include "File.hpp"
+#include "Str.hpp"
+#include "Log.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+
+WhiteListFile::WhiteListFile()
+: all_users_have_read_access_(false),
+ all_users_have_write_access_(false)
+{
+}
+
+WhiteListFile::~WhiteListFile() {}
+
+
+bool WhiteListFile::allow_read_access(const std::string& user) const
+{
+ if (all_users_have_read_access_) return true;
+ if (users_with_read_access_.empty() && users_with_write_access_.empty() ) return true;
+
+ if (users_with_read_access_.find(user) != users_with_read_access_.end()) {
+ return true;
+ }
+ return false;
+}
+
+bool WhiteListFile::allow_write_access(const std::string& user) const
+{
+ if (all_users_have_write_access_) return true;
+ if (users_with_read_access_.empty() && users_with_write_access_.empty() ) return true;
+
+ if (users_with_write_access_.find(user) != users_with_write_access_.end()) {
+ return true;
+ }
+ return false;
+}
+
+bool WhiteListFile::load(const std::string& file, bool debug, std::string& errorMsg )
+{
+ if (debug) {
+ std::cout << " White list file " << file << " opening...\n";
+ }
+
+ white_list_file_ = file;
+ all_users_have_read_access_ = false;
+ all_users_have_write_access_ = false;
+ users_with_read_access_.clear();
+ users_with_write_access_.clear();
+
+
+ std::vector<std::string> lines;
+ if (File::splitFileIntoLines(white_list_file_,lines,true /* ignore empty lines */)) {
+
+ bool foundVersionNumber = false; // can read from version 4.4.5 onwards
+ for(size_t i = 0; i < lines.size(); ++i) {
+
+ if (lines[i].empty()) continue;
+ if (lines[i][0] == '#') continue; // ignore comments
+
+ std::string theLine = lines[i];
+ boost::algorithm::trim(theLine); // don't know why we get leading/trailing spaces
+
+ std::vector< std::string > lineTokens;
+ Str::split( theLine, lineTokens );
+ if ( lineTokens.empty() ) continue;
+
+
+ // version should be at the start
+ if (!foundVersionNumber) {
+
+ if (!validateVersionNumber(lineTokens[0], errorMsg )) {
+ std::stringstream ss;
+ ss << " " << i + 1 << ": " << lines[i] << "\n";
+ ss << "for ECF_LISTS file " << white_list_file_ << "\n";
+ errorMsg += ss.str();
+ return false;
+ }
+ foundVersionNumber = true;
+ continue;
+ }
+ else {
+ add_user(lineTokens[0]);
+ }
+ }
+
+ if (debug) std::cout << dump_valid_users() << "\n";
+
+ return true;
+ }
+
+ errorMsg += "Could not open file specified by ECF_LISTS ";
+ errorMsg += white_list_file_;
+ errorMsg += "\n";
+ if (debug) std::cout << dump_valid_users() << "\n";
+ return false;
+}
+
+std::string WhiteListFile::dump_valid_users() const
+{
+ std::stringstream ss;
+ ss << "ECF_LISTS = '" << white_list_file_ << "'\n";
+ if (users_with_read_access_.empty() && users_with_write_access_.empty()) ss << " No users specified. Everyone has read/write access\n";
+ if (all_users_have_read_access_) ss << " All users have read access\n";
+ if (all_users_have_write_access_) ss << " All users have write access\n";
+
+ std::set<std::string>::const_iterator i;
+ for(i=users_with_read_access_.begin(); i!= users_with_read_access_.end(); ++i) {
+ ss << " User: " << (*i) << " has read access\n";
+ }
+ for(i=users_with_write_access_.begin(); i!= users_with_write_access_.end(); ++i) {
+ ss << " User: " << (*i) << " has read/write access\n";
+ }
+
+ return ss.str();
+}
+
+bool WhiteListFile::validateVersionNumber(const std::string& line, std::string& errorMsg) const
+{
+ // Expect 4.4.14, Current syntax in force after 4.4.5
+ // If first character is NUMERIC and we have dots
+ bool firstCharIsNumeric = Str::NUMERIC().find( line[0], 0 ) != string::npos;
+ if ( firstCharIsNumeric && line.find( "." ) != string::npos) {
+
+ std::vector< std::string > versionNumberTokens;
+ Str::split( line, versionNumberTokens, "." );
+ if ( versionNumberTokens.size() != 3 ) {
+ std::stringstream ss;
+ ss << "Expected version of the form <int>.<int>.<int> i.e 4.4.14. but found invalid version number\n";
+ errorMsg += ss.str();
+ return false;
+ }
+
+ try {
+ int major = boost::lexical_cast< int >( versionNumberTokens[0] );
+ int minor = boost::lexical_cast< int >( versionNumberTokens[1] );
+ int part = boost::lexical_cast< int >( versionNumberTokens[2] );
+ if ( major < 4 ) {
+ errorMsg += "Only white list files with a version >= 4.4.5 is supported\n";
+ return false;
+ }
+ if ( major == 4 && minor < 4 ) {
+ errorMsg += "Only white list files with a version >= 4.4.5 is supported\n";
+ return false;
+ }
+ if ( major == 4 && minor == 4 && part < 5) {
+ errorMsg += "Only white list files with a version >= 4.4.5 is supported\n";
+ return false;
+ }
+ }
+ catch ( boost::bad_lexical_cast& ) {
+ errorMsg += "Invalid version number \n";
+ return false;
+ }
+
+ return true;
+ }
+
+ errorMsg +="The version number not found. The version number must appear before the users.\n";
+ return false;
+}
+
+
+void WhiteListFile::add_user(const std::string& line )
+{
+ LOG_ASSERT(!line.empty(), "");
+ if (line[0] == '-') {
+
+ // Read access
+ std::string user = line;
+ user.erase(user.begin());
+
+ // if we see -* all users have read access
+ if (user == "*") {
+ all_users_have_read_access_ = true;
+ users_with_read_access_.clear();
+ }
+ else {
+ if (!all_users_have_read_access_)
+ users_with_read_access_.insert(user);
+ }
+ return;
+ }
+
+ // write access , this also IMPLIES read access
+ // if we see * all users have read and write access
+ if (line == "*") {
+ all_users_have_write_access_ = true;
+ all_users_have_read_access_ = true;
+ users_with_write_access_.clear();
+ users_with_read_access_.clear();
+ }
+ else {
+ if (!all_users_have_read_access_)
+ users_with_read_access_.insert(line);
+ if (!all_users_have_write_access_)
+ users_with_write_access_.insert(line);
+ }
+}
+
+bool WhiteListFile::createWithReadAccess( const std::string& pathToFile,std::string& errorMsg)
+{
+ std::vector<std::string> lines; lines.reserve( 2 );
+
+ lines.push_back("4.4.14");
+
+ string user = "-";
+ struct passwd * thePassWord = getpwuid ( getuid() );
+ user += string( thePassWord->pw_name ) ; // equivalent to the login name
+
+ lines.push_back(user);
+
+ return File::create(pathToFile,lines,errorMsg);
+}
+
+bool WhiteListFile::createWithWriteAccess( const std::string& pathToFile , std::string& errorMsg)
+{
+ std::vector<std::string> lines; lines.reserve( 2 );
+
+ lines.push_back("4.4.14");
+
+ struct passwd * thePassWord = getpwuid ( getuid() );
+ string user( thePassWord->pw_name ) ; // equivalent to the login name
+
+ lines.push_back(user);
+
+ return File::create(pathToFile,lines,errorMsg);
+}
diff --git a/ACore/src/WhiteListFile.hpp b/ACore/src/WhiteListFile.hpp
new file mode 100644
index 0000000..dd8c8d1
--- /dev/null
+++ b/ACore/src/WhiteListFile.hpp
@@ -0,0 +1,60 @@
+#ifndef WHITELISTFILE_CPP_
+#define WHITELISTFILE_CPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Parser for while list file
+//============================================================================
+
+#include <boost/noncopyable.hpp>
+#include <string>
+#include <set>
+
+// ----------------------------------------------------------------
+// The whitelist file, is used to indicate users who are allowed
+// read/write access to the server when calling *user* commands
+
+class WhiteListFile : private boost::noncopyable {
+public:
+ WhiteListFile();
+ ~WhiteListFile();
+
+ bool allow_read_access(const std::string& user) const;
+ bool allow_write_access(const std::string& user) const;
+ std::string dump_valid_users() const;
+
+ // Parse the file if any errors found return false and errorMsg
+ // The parser expects version number 4.4.5
+ bool load(const std::string& file,bool debug, std::string& errorMsg);
+
+
+ // Function used in test:
+ // Will overwrite the existing file
+ static bool createWithReadAccess( const std::string& pathToFile, std::string& errorMsg);
+ static bool createWithWriteAccess( const std::string& pathToFile, std::string& errorMsg);
+
+ size_t read_access_size() const { return users_with_read_access_.size(); }
+ size_t write_access_size() const { return users_with_write_access_.size(); }
+
+private:
+
+ bool validateVersionNumber(const std::string& line, std::string& errorMsg) const;
+ void add_user(const std::string& token);
+
+ bool all_users_have_read_access_;
+ bool all_users_have_write_access_;
+ std::string white_list_file_;
+ std::set<std::string> users_with_read_access_;
+ std::set<std::string> users_with_write_access_;
+};
+
+#endif
diff --git a/ACore/src/boost_archive.cpp b/ACore/src/boost_archive.cpp
new file mode 100644
index 0000000..48a3067
--- /dev/null
+++ b/ACore/src/boost_archive.cpp
@@ -0,0 +1,60 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #11 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <stdio.h>
+#include <sstream>
+#include <boost/lexical_cast.hpp>
+
+#include "Str.hpp"
+#include "boost_archive.hpp"
+
+using namespace ecf;
+
+// return the current archive version
+int boost_archive::version()
+{
+ std::stringstream ss;
+
+#if defined(BINARY_ARCHIVE)
+ boost::archive::binary_oarchive oa( ss );
+#elif defined(PORTABLE_BINARY_ARCHIVE)
+ portable_binary_oarchive oa(ss);
+#elif defined(EOS_PORTABLE_BINARY_ARCHIVE)
+ eos::portable_oarchive oa(ss);
+#else
+ boost::archive::text_oarchive oa( ss );
+#endif
+
+ return oa.get_library_version();
+}
+
+
+// extract the boost archive version
+int boost_archive::extract_version(const std::string& boost_serial_str)
+{
+ int version = 0;
+ sscanf(boost_serial_str.c_str(),"22 serialization::archive %d",&version);
+ return version;
+}
+
+bool boost_archive::replace_version(std::string& boost_serial_str, int the_new_version)
+{
+ int version = extract_version(boost_serial_str);
+ std::string old_version = boost::lexical_cast<std::string>(version);
+ std::string new_version = boost::lexical_cast<std::string>(the_new_version);
+ return Str::replace(boost_serial_str,old_version,new_version);
+}
+
+
diff --git a/ACore/src/boost_archive.hpp b/ACore/src/boost_archive.hpp
new file mode 100644
index 0000000..409c7ea
--- /dev/null
+++ b/ACore/src/boost_archive.hpp
@@ -0,0 +1,96 @@
+#ifndef BOOST_ARCHIVE_HPP_
+#define BOOST_ARCHIVE_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : This class has come about due to a bug with boost archive
+// includes. i.e if the same set of includes are not defined
+// in different compilations units. Then _NO_ errors/warnings are
+// issued instead we get a crash at run time when serialising
+// via base pointer.
+//
+// To get round this code will use this include to collate the
+// archives used in a single place.
+//============================================================================
+
+#if defined(TEXT_ARCHIVE) || !defined(BINARY_ARCHIVE) && !defined(PORTABLE_BINARY_ARCHIVE) && !defined(EOS_PORTABLE_BINARY_ARCHIVE)
+#include <boost/archive/text_iarchive.hpp>
+#include <boost/archive/text_oarchive.hpp>
+#endif
+
+#if defined(BINARY_ARCHIVE)
+#include <boost/archive/binary_oarchive.hpp>
+#include <boost/archive/binary_iarchive.hpp>
+#endif
+
+#if defined(PORTABLE_BINARY_ARCHIVE)
+#include "portable_binary_oarchive.hpp"
+#include "portable_binary_iarchive.hpp"
+#endif
+
+#if defined(EOS_PORTABLE_BINARY_ARCHIVE)
+#include "portable_oarchive.hpp"
+#include "portable_iarchive.hpp"
+#endif
+
+#include <boost/noncopyable.hpp>
+
+namespace ecf {
+
+/// Utility class for boost archive version
+///
+/// Boost archive version is specified in: $BOOST_ROOT/libs/serialization/src/basic_archive.cpp
+///
+/// boost 1.47 serialisation library archive version = 9
+/// boost 1.53 serialisation library archive version = 10
+/// boost 1.56 serialisation library archive version = 11 // however no change in library ?
+/// boost 1.57 serialisation library archive version = 11
+///
+/// boost supports old -> new only. In our case typically new_client needs to talk to old server
+/// Hence if new client archive version is newer we need to set to archive version used by server.
+/// *providing* there are compatible.
+///
+/// To enable this, user can export variable ECF_ALLOW_NEW_CLIENT_OLD_SERVER:
+///
+/// We expect following syntax:
+/// option 1/ export ECF_ALLOW_NEW_CLIENT_OLD_SERVER=<int>
+/// This for use ecflow_client command line
+///
+/// option 2/ export ECF_ALLOW_NEW_CLIENT_OLD_SERVER=<host>:<port>:<int>,<host>:<port>:<int>,<host>:<port>:<int>
+/// This for use with ui/viewer where we can have multiple clients, each could
+/// connect to different server version and hence archive.
+///
+/// export ECF_ALLOW_NEW_CLIENT_OLD_SERVER=10, the number used, must be the archive version
+/// that the boost server was built with.
+///
+class boost_archive : private boost::noncopyable {
+public:
+
+ // return the current archive version
+ static int version();
+
+ // extract the boost archive version, assumes text archive *****
+ static int extract_version(const std::string&);
+
+ // replace archive version, return true if replace worked.
+ static bool replace_version(std::string&, int new_version);
+
+ // avoid hard coding
+ static int version_1_47() { return 9;}
+
+private:
+ boost_archive();
+};
+
+}
+#endif
diff --git a/ACore/src/ecflow_version.h b/ACore/src/ecflow_version.h
new file mode 100644
index 0000000..64fa31a
--- /dev/null
+++ b/ACore/src/ecflow_version.h
@@ -0,0 +1,10 @@
+#ifndef ecflow_version_config_h
+#define ecflow_version_config_h
+
+#define ECFLOW_VERSION "4.1.0"
+
+#define ECFLOW_RELEASE "4"
+#define ECFLOW_MAJOR "1"
+#define ECFLOW_MINOR "0"
+
+#endif
diff --git a/ecflow_4_0_7/ACore/src/polymorphic_portable_archive.hpp b/ACore/src/polymorphic_portable_archive.hpp
similarity index 100%
rename from ecflow_4_0_7/ACore/src/polymorphic_portable_archive.hpp
rename to ACore/src/polymorphic_portable_archive.hpp
diff --git a/ecflow_4_0_7/ACore/src/portable_archive.hpp b/ACore/src/portable_archive.hpp
similarity index 100%
rename from ecflow_4_0_7/ACore/src/portable_archive.hpp
rename to ACore/src/portable_archive.hpp
diff --git a/ecflow_4_0_7/ACore/src/portable_archive_exception.hpp b/ACore/src/portable_archive_exception.hpp
similarity index 100%
rename from ecflow_4_0_7/ACore/src/portable_archive_exception.hpp
rename to ACore/src/portable_archive_exception.hpp
diff --git a/ecflow_4_0_7/ACore/src/portable_binary_archive.hpp b/ACore/src/portable_binary_archive.hpp
similarity index 100%
rename from ecflow_4_0_7/ACore/src/portable_binary_archive.hpp
rename to ACore/src/portable_binary_archive.hpp
diff --git a/ecflow_4_0_7/ACore/src/portable_binary_iarchive.cpp b/ACore/src/portable_binary_iarchive.cpp
similarity index 100%
rename from ecflow_4_0_7/ACore/src/portable_binary_iarchive.cpp
rename to ACore/src/portable_binary_iarchive.cpp
diff --git a/ecflow_4_0_7/ACore/src/portable_binary_iarchive.hpp b/ACore/src/portable_binary_iarchive.hpp
similarity index 100%
rename from ecflow_4_0_7/ACore/src/portable_binary_iarchive.hpp
rename to ACore/src/portable_binary_iarchive.hpp
diff --git a/ecflow_4_0_7/ACore/src/portable_binary_oarchive.cpp b/ACore/src/portable_binary_oarchive.cpp
similarity index 100%
rename from ecflow_4_0_7/ACore/src/portable_binary_oarchive.cpp
rename to ACore/src/portable_binary_oarchive.cpp
diff --git a/ecflow_4_0_7/ACore/src/portable_binary_oarchive.hpp b/ACore/src/portable_binary_oarchive.hpp
similarity index 100%
rename from ecflow_4_0_7/ACore/src/portable_binary_oarchive.hpp
rename to ACore/src/portable_binary_oarchive.hpp
diff --git a/ecflow_4_0_7/ACore/src/portable_iarchive.hpp b/ACore/src/portable_iarchive.hpp
similarity index 100%
rename from ecflow_4_0_7/ACore/src/portable_iarchive.hpp
rename to ACore/src/portable_iarchive.hpp
diff --git a/ecflow_4_0_7/ACore/src/portable_oarchive.hpp b/ACore/src/portable_oarchive.hpp
similarity index 100%
rename from ecflow_4_0_7/ACore/src/portable_oarchive.hpp
rename to ACore/src/portable_oarchive.hpp
diff --git a/ACore/test/TestArgvCreator.cpp b/ACore/test/TestArgvCreator.cpp
new file mode 100644
index 0000000..ab2883b
--- /dev/null
+++ b/ACore/test/TestArgvCreator.cpp
@@ -0,0 +1,67 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <boost/test/unit_test.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include <iostream>
+#include "ArgvCreator.hpp"
+
+using namespace boost;
+using namespace std;
+
+BOOST_AUTO_TEST_SUITE( CoreTestSuite )
+
+static void doCheck(const std::vector<std::string>& theArgs)
+{
+ ArgvCreator argvCr(theArgs);
+// cout << argvCr.toSString() << "\n";
+ BOOST_CHECK_MESSAGE(argvCr.argc() == static_cast<int>(theArgs.size()), " argc incorrect");
+
+ char** argv = argvCr.argv();
+ for(int i=0; i < argvCr.argc(); i++) {
+ BOOST_CHECK_MESSAGE(string(argv[i]) == theArgs[i],"Mismatch in args expected " << theArgs[i] << " but found " << argv[i]);
+// cout << i << ": " << argv[i] << "\n";
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_ArgvCreator )
+{
+ cout << "ACore:: ...test_ArgvCreator" << flush ;
+
+ // O args
+ std::vector<std::string> theArgs;
+ doCheck(theArgs);
+
+ // 1 args
+ theArgs.push_back("arg1");
+ doCheck(theArgs);
+
+ // 2 args
+ theArgs.clear();
+ theArgs.push_back("arg1");
+ theArgs.push_back("arg2");
+ doCheck(theArgs);
+
+ // 10 args
+ theArgs.clear();
+ for(int i = 0; i < 10; i++) {
+ string theArg("arg");
+ theArg += lexical_cast<string>(i);
+ theArgs.push_back(theArg );
+ }
+ doCheck(theArgs);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ACore/test/TestCalendar.cpp b/ACore/test/TestCalendar.cpp
new file mode 100644
index 0000000..60d151e
--- /dev/null
+++ b/ACore/test/TestCalendar.cpp
@@ -0,0 +1,502 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #20 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <boost/test/unit_test.hpp>
+#include <boost/date_time/posix_time/time_formatters.hpp>
+
+#include "Calendar.hpp"
+#include "TimeSeries.hpp"
+#include "Str.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::posix_time;
+using namespace boost::gregorian;
+
+BOOST_AUTO_TEST_SUITE( CoreTestSuite )
+
+
+//static boost::posix_time::time_duration diff_d(boost::posix_time::time_duration t1, boost::posix_time::time_duration t2)
+//{
+// // t2 > t1 otherwise assume we have gone over midnight
+// if (t2 > t1) return t2 - t1;
+//
+// boost::posix_time::time_duration midnight(24,0,0);
+// boost::posix_time::time_duration diff_from_midnight = midnight - t1;
+// std::cout << to_simple_string(diff_from_midnight) << "\n";
+//
+// return diff_from_midnight + t2;
+//}
+//
+//BOOST_AUTO_TEST_CASE( test_calendar_3 )
+//{
+// cout << "ACore:: ...test_calendar_3\n";
+//
+// Calendar calendar;
+// BOOST_CHECK_MESSAGE(calendar.hybrid(),"Default calendar type should be hybrid");
+//
+// // init the calendar to 2009, Feb, 10th, 15 minutes past midnight
+//
+// boost::posix_time::time_duration t1(23,0,0);
+// boost::posix_time::time_duration t2(1,0,0);
+// boost::posix_time::time_duration expected(2,0,0);
+//// std::cout << to_simple_string(t1) << "\n";
+//// std::cout << to_simple_string(t2) << "\n";
+//// std::cout << to_simple_string(t1 - t2) << "\n";
+//// std::cout << to_simple_string(t2 - t1) << "\n";
+//
+// BOOST_CHECK_MESSAGE(diff_d(t1,t2) == expected," Expected " << to_simple_string(expected) << " but found " << to_simple_string(diff_d(t1,t2)));
+//}
+
+
+
+BOOST_AUTO_TEST_CASE( test_calendar_state_parsing )
+{
+ cout << "ACore:: ...test_calendar_state_parsing\n";
+
+ Calendar calendar;
+ BOOST_CHECK_MESSAGE(!calendar.hybrid(),"Default calendar type should be real");
+
+ // init the calendar to 2009, Feb, 10th, then write out the state
+ boost::gregorian::date theDate(2009,2,10);
+ ptime time(theDate, hours(23) + minutes(59));
+ calendar.init(time, Calendar::REAL);
+ std::string calendar_state = calendar.write_state();
+
+ // read the state, into a different calendar & compare
+ std::vector<std::string> lineTokens;
+ Str::split(calendar_state,lineTokens);
+ Calendar calendar2;
+ calendar2.read_state(calendar_state,lineTokens);
+ BOOST_CHECK_MESSAGE(calendar == calendar2,"Calendar should be the same\n" << calendar.toString() << "\n" << calendar2.toString());
+
+ // Update calendar.
+ calendar.update(minutes(2));
+ BOOST_CHECK_MESSAGE(!(calendar == calendar2),"Calendar should be different");
+
+ // re-compare after reloading state
+ lineTokens.clear();
+ calendar_state = calendar.write_state();
+ Str::split(calendar_state,lineTokens);
+ calendar2.read_state(calendar_state,lineTokens);
+ BOOST_CHECK_MESSAGE(calendar == calendar2,"Calendar should be the same");
+}
+
+BOOST_AUTO_TEST_CASE( test_calendar_1 )
+{
+ cout << "ACore:: ...test_calendar_1\n";
+
+ Calendar calendar;
+ BOOST_CHECK_MESSAGE(!calendar.hybrid(),"Default calendar type should be real");
+
+ // init the calendar to 2009, Feb, 10th, 15 minutes past midnight
+ boost::gregorian::date theDate(2009,2,10);
+ ptime time(theDate, hours(23) + minutes(59));
+ calendar.init(time, Calendar::HYBRID);
+ BOOST_CHECK_MESSAGE(calendar.hybrid(),"init failed to reset calendar type");
+
+ calendar.update(minutes(2));
+}
+
+
+BOOST_AUTO_TEST_CASE( test_calendar )
+{
+ cout << "ACore:: ...test_calendar_basic\n";
+
+ Calendar calendar;
+ BOOST_CHECK_MESSAGE(!calendar.hybrid(),"Default calendar type should be real");
+
+ // init the calendar to 2009, Feb, 10th, 15 minutes past midnight
+ boost::gregorian::date theDate(2009,2,10);
+ ptime time(theDate, minutes(15));
+ calendar.init(time, Calendar::REAL);
+ BOOST_CHECK_MESSAGE(!calendar.hybrid(),"Calendar should now be REAL");
+
+ std::string expectedTime = "2009-Feb-10 00:15:00";
+ std::string actualTime = to_simple_string(calendar.suiteTime());
+ BOOST_CHECK_MESSAGE( actualTime == expectedTime,"Expected '" << expectedTime << "' but found " << actualTime);
+
+
+ time_duration td = hours(1) + minutes(10);
+ calendar.update(td);
+ expectedTime = "2009-Feb-10 01:25:00";
+ actualTime = to_simple_string(calendar.suiteTime());
+ BOOST_CHECK_MESSAGE( actualTime == expectedTime,"Expected '" << expectedTime << "' but found " << actualTime);
+
+
+ // Increment by 24 hours
+ calendar.update(hours(24));
+ expectedTime = "2009-Feb-11 01:25:00";
+ actualTime = to_simple_string(calendar.suiteTime());
+ BOOST_CHECK_MESSAGE( actualTime == expectedTime,"Expected '" << expectedTime << "' but found " << actualTime);
+}
+
+BOOST_AUTO_TEST_CASE( test_calendar_time_series_relative )
+{
+ cout << "ACore:: ...test_calendar_time_series_relative\n";
+
+ // init the calendar to 2009, Feb, 10th, 0 minutes past midnight
+ Calendar calendar;
+ calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::HYBRID);
+
+ std::string expectedTime = "2010-Feb-10 00:00:00";
+ std::string actualTime = to_simple_string(calendar.suiteTime());
+ BOOST_CHECK_MESSAGE( actualTime == expectedTime,"Expected '" << expectedTime << "' but found " << actualTime);
+
+ // Create a test when we can match a time series. Need to sync hour with suite time
+ // at hour 1, suite time should also be 01:00, for test to work
+ //
+ // Create the time series: start 10:00
+ // finish 20:00
+ // incr 1:00
+ TimeSeries timeSeries(TimeSlot(10,0), TimeSlot(20,0), TimeSlot(1,0), true/*relative*/);
+
+ for(int hour=1; hour < 24; hour++) {
+ // Update calendar every hour, then see we can match time series, *RELATIVE* to suite start
+ calendar.update( time_duration( hours(1) ) );
+ timeSeries.calendarChanged( calendar );
+
+// cerr << "hour = " << hour << " suiteTime " << to_simple_string(calendar.suiteTime()) << "\n";
+ if (hour >= timeSeries.start().hour() && hour <=timeSeries.finish().hour()) {
+ BOOST_CHECK_MESSAGE(timeSeries.isFree(calendar),"Calendar should match relative time series at hour " << hour );
+ }
+ else {
+ BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar),"Calendar should NOT match relative time series at hour " << hour );
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_calendar_time_series_relative_complex )
+{
+ cout << "ACore:: ...test_calendar_time_series_relative_complex\n";
+
+ // init the calendar to 2009, Feb, 10th, 0 minutes past midnight
+ Calendar calendar;
+ calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::HYBRID);
+
+ // Create a test when we can match a time series
+ // Create the time series: start 10:00
+ // finish 20:00
+ // incr 00:15
+ TimeSeries timeSeries(TimeSlot(10,0), TimeSlot(20,0), TimeSlot(0,15),true/*relative*/);
+
+ for(int hour=0; hour < 24; hour++) {
+ for( int minute=0; minute<60; minute++) {
+
+ // Update calendar every hour, then see we can match time series, *RELATIVE* to suite start
+ calendar.update( minutes(1) );
+ timeSeries.calendarChanged( calendar );
+
+ tm suiteTm = to_tm(calendar.suiteTime());
+
+ bool matches = timeSeries.isFree(calendar);
+
+ bool intersects = ( suiteTm.tm_hour >= timeSeries.start().hour() &&
+ suiteTm.tm_hour <= timeSeries.finish().hour() &&
+ (suiteTm.tm_min == 0 || suiteTm.tm_min % timeSeries.incr().minute() == 0)
+ );
+ // Ovoid overshooting past end of series
+ bool boundaryOk = true;
+ if ( suiteTm.tm_hour == timeSeries.finish().hour() ) {
+ boundaryOk = (suiteTm.tm_min <= timeSeries.finish().minute());
+ }
+
+ if ( intersects && boundaryOk )
+ {
+ BOOST_CHECK_MESSAGE(matches,
+ "Calendar should match relative time series at "
+ << suiteTm.tm_hour << Str::COLON() << suiteTm.tm_min
+ << " suite time = " << to_simple_string(calendar.suiteTime()));
+ if (!matches) {
+ cerr << "suiteTm.tm_hour =" << suiteTm.tm_hour << " suiteTm.tm_min = " << suiteTm.tm_min
+ << " timeSeries.start().hour() " << timeSeries.start().hour()
+ << " timeSeries.start().minute() " << timeSeries.start().minute()
+ << " timeSeries.finish().hour() " << timeSeries.finish().hour()
+ << " timeSeries.finish().minute() " << timeSeries.finish().minute()
+ << " suiteTm.tm_min % 15 = " << suiteTm.tm_min % 15
+ << "\n";
+ }
+ }
+ else {
+ BOOST_CHECK_MESSAGE(!matches,
+ "Calendar should NOT match relative time series at "
+ << suiteTm.tm_hour << Str::COLON() << suiteTm.tm_min
+ << " suite time = " << to_simple_string(calendar.suiteTime()));
+
+ if (matches) {
+ cerr << "suiteTm.tm_hour =" << suiteTm.tm_hour << " suiteTm.tm_min = " << suiteTm.tm_min
+ << " timeSeries.start().hour() " << timeSeries.start().hour()
+ << " timeSeries.start().minute() " << timeSeries.start().minute()
+ << " timeSeries.finish().hour() " << timeSeries.finish().hour()
+ << " timeSeries.finish().minute() " << timeSeries.finish().minute()
+ << " suiteTm.tm_min % 15 = " << suiteTm.tm_min % 15
+ << "\n";
+ }
+ }
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_calendar_time_series_real )
+{
+ cout << "ACore:: ...test_calendar_time_series_real\n";
+
+ // init the calendar to 2009, Feb, 10th, 0 minutes past midnight
+ Calendar calendar;
+ calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::REAL);
+
+ std::string expectedTime = "2010-Feb-10 00:00:00";
+ std::string actualTime = to_simple_string(calendar.suiteTime());
+ BOOST_CHECK_MESSAGE( actualTime == expectedTime,"Expected '" << expectedTime << "' but found " << actualTime);
+
+ // Create a test when we can match a time series
+ // Create the time series: start 10:00
+ // finish 20:00
+ // incr 1:00
+ TimeSeries timeSeries(TimeSlot(10,0), TimeSlot(20,0), TimeSlot(1,0));
+
+ for(int hour=1; hour < 24; hour++) {
+ // Update calendar every hour, then see we can match time series, in REAL
+ // Update will set the local time from the computers system clock, however
+ // for testing this will need to be overriden below.
+ calendar.update( time_duration( hours(1) ) );
+
+ // cerr << "hour = " << hour << " suiteTime " << to_simple_string(calendar.suiteTime()) << "\n";
+ if (hour >= timeSeries.start().hour() && hour <=timeSeries.finish().hour()) {
+ BOOST_CHECK_MESSAGE(timeSeries.isFree(calendar),"Calendar should match time series at hour " << hour );
+ }
+ else {
+ BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar),"Calendar should NOT match time series at hour " << hour );
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_calendar_time_series_real_complex )
+{
+ cout << "ACore:: ...test_calendar_time_series_real_complex\n";
+
+ // init the calendar to 2009, Feb, 10th, 0 minutes past midnight
+ Calendar calendar;
+ calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::REAL);
+
+ // Create a test when we can match a time series
+ // Create the time series: start 10:00
+ // finish 20:00
+ // incr 00:15
+ TimeSeries timeSeries(TimeSlot(10,0), TimeSlot(20,0), TimeSlot(0,15));
+
+ for(int hour=0; hour < 24; hour++) {
+ for( int minute=0; minute<60; minute++) {
+
+ // Update calendar every minute, then see we can match time series, *RELATIVE* to suite start
+ calendar.update( minutes(1) );
+
+ tm suiteTm = to_tm(calendar.suiteTime());
+
+ bool matches = timeSeries.isFree(calendar);
+
+ bool intersects = ( suiteTm.tm_hour >= timeSeries.start().hour() &&
+ suiteTm.tm_hour <= timeSeries.finish().hour() &&
+ (suiteTm.tm_min == 0 || suiteTm.tm_min % timeSeries.incr().minute() == 0)
+ );
+ // Ovoid overshooting past end of series
+ bool boundaryOk = true;
+ if ( suiteTm.tm_hour == timeSeries.finish().hour() ) {
+ boundaryOk = (suiteTm.tm_min <= timeSeries.finish().minute());
+ }
+
+ if ( intersects && boundaryOk )
+ {
+ BOOST_CHECK_MESSAGE(matches,
+ "Calendar should match relative time series at "
+ << suiteTm.tm_hour <<":"<< suiteTm.tm_min
+ << " suite time = " << to_simple_string(calendar.suiteTime()));
+ if (!matches) {
+ cerr << "suiteTm.tm_hour =" << suiteTm.tm_hour << " suiteTm.tm_min = " << suiteTm.tm_min
+ << " timeSeries.start().hour() " << timeSeries.start().hour()
+ << " timeSeries.start().minute() " << timeSeries.start().minute()
+ << " timeSeries.finish().hour() " << timeSeries.finish().hour()
+ << " timeSeries.finish().minute() " << timeSeries.finish().minute()
+ << " suiteTm.tm_min % 15 = " << suiteTm.tm_min % 15
+ << "\n";
+ }
+ }
+ else {
+ BOOST_CHECK_MESSAGE(!matches,
+ "Calendar should NOT match relative time series at "
+ << suiteTm.tm_hour <<":"<< suiteTm.tm_min
+ << " suite time = " << to_simple_string(calendar.suiteTime()));
+
+ if (matches) {
+ cerr << "suiteTm.tm_hour =" << suiteTm.tm_hour << " suiteTm.tm_min = " << suiteTm.tm_min
+ << " timeSeries.start().hour() " << timeSeries.start().hour()
+ << " timeSeries.start().minute() " << timeSeries.start().minute()
+ << " timeSeries.finish().hour() " << timeSeries.finish().hour()
+ << " timeSeries.finish().minute() " << timeSeries.finish().minute()
+ << " suiteTm.tm_min % 15 = " << suiteTm.tm_min % 15
+ << "\n";
+ }
+ }
+ }
+ }
+}
+
+
+BOOST_AUTO_TEST_CASE( test_calendar_hybrid )
+{
+ cout << "ACore:: ...test_calendar_hybrid\n";
+
+ // The hybrid calendar should not change the suite date.
+ // Test by updateing calendar by more than 24 hours
+
+ // init the calendar to 2009, Feb, 10th, 0 minutes past midnight
+ Calendar calendar;
+ calendar.init(ptime(date(2010,2,10), minutes(0)),Calendar::HYBRID);
+ BOOST_CHECK_MESSAGE(calendar.hybrid(),"calendar type should be hybrid");
+
+
+ std::string expectedTime = "2010-Feb-10 00:00:00";
+ std::string actualTime = to_simple_string(calendar.suiteTime());
+ BOOST_CHECK_MESSAGE( actualTime == expectedTime,"Expected '" << expectedTime << "' but found " << actualTime);
+
+ std::string expectedDate = "2010-Feb-10";
+
+ // Check cache is correct
+ int expected_day_of_week = calendar.day_of_week();
+ int expected_day_of_year = calendar.day_of_year();
+ int expected_day_of_month = calendar.day_of_month();
+ int expected_month = calendar.month();
+ int expected_year = calendar.year();
+
+ for(int hour=1; hour < 73; hour++) {
+ // Update calendar every hour, for 73 hours
+ // the date should be the same, i.e 2009, Feb, 10th
+
+ ptime timeBeforeUpdate = calendar.suiteTime();
+
+ calendar.update( time_duration( hours(1) ) );
+
+ ptime timeAfterUpdate = calendar.suiteTime();
+
+// cerr << "hour = " << hour << " timeBeforeUpdate " << to_simple_string(timeBeforeUpdate)
+// << " timeAfterUpdate = " << to_simple_string(timeAfterUpdate) << "\n";
+
+ if (hour != 24 && hour != 48 && hour != 72) {
+ time_period diff(timeBeforeUpdate,timeAfterUpdate);
+ time_duration gap = diff.length();
+ BOOST_CHECK_MESSAGE( gap.hours() == 1,"Expected one hour difference but found " << gap.hours() << " at hour " << hour);
+ }
+
+ std::string actualDate = to_simple_string(calendar.suiteTime().date());
+ BOOST_CHECK_MESSAGE( actualDate == expectedDate,"Expected '" << expectedDate << "' but found " << actualDate << " at hour " << hour);
+
+ // check cache ECFLOW-458
+ int actual_day_of_week = calendar.day_of_week();
+ int actual_day_of_year = calendar.day_of_year();
+ int actual_day_of_month = calendar.day_of_month();
+ int actual_month = calendar.month();
+ int actual_year = calendar.year();
+ BOOST_CHECK_MESSAGE( actual_day_of_week == expected_day_of_week,"Expected day of week '" << expected_day_of_week << "' but found " << actual_day_of_week << " at hour " << hour);
+ BOOST_CHECK_MESSAGE( actual_day_of_year == expected_day_of_year,"Expected day of year '" << expected_day_of_year << "' but found " << actual_day_of_year << " at hour " << hour);
+ BOOST_CHECK_MESSAGE( actual_day_of_month == expected_day_of_month,"Expected day of month '" << expected_day_of_month << "' but found " << actual_day_of_month << " at hour " << hour);
+ BOOST_CHECK_MESSAGE( actual_month == expected_month,"Expected month '" << expected_month << "' but found " << actual_month << " at hour " << hour);
+ BOOST_CHECK_MESSAGE( actual_year == expected_year,"Expected year '" << expected_year << "' but found " << actual_year << " at hour " << hour);
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_day_changed_for_real )
+{
+ cout << "ACore:: ...test_day_changed_for_real\n";
+
+ // init the calendar to 2009, Feb, 10th, 0 minutes past midnight
+ Calendar calendar;
+ calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::REAL);
+ BOOST_CHECK_MESSAGE(!calendar.hybrid(),"calendar type should be real");
+
+ // Check cache is correct
+ int expected_day_of_week = calendar.day_of_week();
+ int expected_day_of_year = calendar.day_of_year();
+ int expected_day_of_month = calendar.day_of_month();
+
+ for(int hour=1; hour < 73; hour++) {
+ // Update calendar every hour, for 72 hours
+ calendar.update( time_duration( hours(1) ) );
+
+ if (hour == 24 || hour == 48 || hour == 72) {
+ BOOST_CHECK_MESSAGE( calendar.dayChanged(),"Expected day change at hour " << hour << " calendar " << calendar.toString());
+ expected_day_of_week++;
+ expected_day_of_year++;
+ expected_day_of_month++;
+ }
+ else {
+ BOOST_CHECK_MESSAGE( !calendar.dayChanged(),"Un-Expected day change at hour " << hour << " calendar " << calendar.toString());
+ }
+
+ // check cache ECFLOW-458
+ int actual_day_of_week = calendar.day_of_week();
+ int actual_day_of_year = calendar.day_of_year();
+ int actual_day_of_month = calendar.day_of_month();
+ BOOST_CHECK_MESSAGE( actual_day_of_week == expected_day_of_week,"Expected day of week '" << expected_day_of_week << "' but found " << actual_day_of_week << " at hour " << hour);
+ BOOST_CHECK_MESSAGE( actual_day_of_year == expected_day_of_year,"Expected day of year '" << expected_day_of_year << "' but found " << actual_day_of_year << " at hour " << hour);
+ BOOST_CHECK_MESSAGE( actual_day_of_month == expected_day_of_month,"Expected day of month '" << expected_day_of_month << "' but found " << actual_day_of_month << " at hour " << hour);
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_day_changed_for_hybrid )
+{
+ cout << "ACore:: ...test_day_changed_for_hybrid\n";
+
+ // init the calendar
+ Calendar calendar; // default clock is real
+ calendar.init(ptime(date(2015,10,31), minutes(0)),Calendar::HYBRID);
+ BOOST_CHECK_MESSAGE(calendar.hybrid(),"calendar type should be hybrid");
+
+ // HYBRID calendars allow for day change but not date.
+ std::string expected_date = to_simple_string(calendar.date());
+
+ // Check cache is correct
+ int expected_day_of_week = calendar.day_of_week();
+ int expected_day_of_year = calendar.day_of_year();
+ int expected_day_of_month = calendar.day_of_month();
+
+ for(int hour=1; hour < 73; hour++) {
+ // Update calendar every hour, for 72 hours
+ calendar.update( time_duration( hours(1) ) );
+
+ BOOST_CHECK_MESSAGE( expected_date == to_simple_string(calendar.date()) ,
+ "Unexpected date change for hybrid calendar at hour " << hour);
+
+ // Day should change even for hybrid calendar,
+ if (hour == 24 || hour == 48 || hour == 72) {
+ BOOST_CHECK_MESSAGE( calendar.dayChanged(),"Expected day change at hour " << hour << " calendar " << calendar.toString());
+ }
+ else {
+ BOOST_CHECK_MESSAGE( !calendar.dayChanged(),"Un-Expected day change at hour " << hour << " calendar " << calendar.toString());
+ }
+
+ // check cache ECFLOW-458
+ int actual_day_of_week = calendar.day_of_week();
+ int actual_day_of_year = calendar.day_of_year();
+ int actual_day_of_month = calendar.day_of_month();
+ BOOST_CHECK_MESSAGE( actual_day_of_week == expected_day_of_week,"Expected day of week '" << expected_day_of_week << "' but found " << actual_day_of_week << " at hour " << hour);
+ BOOST_CHECK_MESSAGE( actual_day_of_year == expected_day_of_year,"Expected day of year '" << expected_day_of_year << "' but found " << actual_day_of_year << " at hour " << hour);
+ BOOST_CHECK_MESSAGE( actual_day_of_month == expected_day_of_month,"Expected day of month '" << expected_day_of_month << "' but found " << actual_day_of_month << " at hour " << hour);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ACore/test/TestExceptionSafety.cpp b/ACore/test/TestExceptionSafety.cpp
new file mode 100644
index 0000000..2c9efa4
--- /dev/null
+++ b/ACore/test/TestExceptionSafety.cpp
@@ -0,0 +1,51 @@
+////============================================================================
+//// Name :
+//// Author : Avi
+//// Revision : $Revision: #5 $
+////
+//// Copyright 2009-2016 ECMWF.
+//// This software is licensed under the terms of the Apache Licence version 2.0
+//// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+//// In applying this licence, ECMWF does not waive the privileges and immunities
+//// granted to it by virtue of its status as an intergovernmental organisation
+//// nor does it submit to any jurisdiction.
+////
+//// Description :
+////============================================================================
+//#include <boost/test/unit_test.hpp>
+//#include <boost/bind.hpp>
+//
+//#include <boost/test/exception_safety.hpp>
+//#include <boost/test/mock_object.hpp>
+//#include <boost/make_shared.hpp>
+//#include <boost/shared_ptr.hpp>
+//
+//using namespace std;
+//using namespace boost::itest;
+//
+//BOOST_AUTO_TEST_SUITE( CoreTestSuite )
+//
+//// Example of how to check for for exception safety
+//// COMMENTED OUT SINCE THIS CAUSES THOUSANDS OF VALGRIND ERRORS
+//
+//template<class T1, class T2>
+//void algo(
+// boost::shared_ptr<T1> x,
+// boost::shared_ptr<T2> y) {}
+//
+//typedef mock_object<> Mock;
+//typedef boost::shared_ptr<Mock> SharedMock;
+//
+//BOOST_TEST_EXCEPTION_SAFETY( fail_test )
+//{
+// algo( SharedMock( new Mock() ),
+// SharedMock( new Mock() ));
+//}
+//
+//BOOST_TEST_EXCEPTION_SAFETY( success_test )
+//{
+// algo( boost::make_shared<Mock>(),
+// boost::make_shared<Mock>());
+//}
+//
+//BOOST_AUTO_TEST_SUITE_END()
diff --git a/ACore/test/TestFile.cpp b/ACore/test/TestFile.cpp
new file mode 100644
index 0000000..84204a5
--- /dev/null
+++ b/ACore/test/TestFile.cpp
@@ -0,0 +1,312 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #24 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/timer.hpp>
+#include <boost/foreach.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <stdlib.h> // for getenv()
+
+#include "DurationTimer.hpp"
+#include "File.hpp"
+#include "NodePath.hpp"
+
+using namespace boost;
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( CoreTestSuite )
+
+//#define FILE_PERF_CHECK_IMPLEMENTATIONS 1;
+
+BOOST_AUTO_TEST_CASE( test_splitFileIntoLines )
+{
+ // This is sanity test for splitFileIntoLines used extensively
+ cout << "ACore:: ...test_splitFileIntoLines\n";
+
+ std::string path = File::test_data("ACore/test/data/test_splitFileIntoLines.txt","ACore");
+
+ std::string theText = "This is a test string";
+ {
+ {
+ std::ofstream file_with_one_line( path.c_str() );
+ file_with_one_line << theText;
+ }
+
+ std::vector<std::string> lines;
+ BOOST_CHECK_MESSAGE( File::splitFileIntoLines(path,lines)," Failed to open file " << path);
+ BOOST_CHECK_MESSAGE( lines.size() == 1," Expected 1 line but found " << lines.size());
+
+ fs::remove(path); // Remove the file. Comment out for debugging
+ }
+
+ {
+ {
+ std::ofstream file_with_one_line( path.c_str() );
+ file_with_one_line << theText << "\n"; // addition of '/n' , should still be one line
+ }
+
+ std::vector<std::string> lines;
+ BOOST_CHECK_MESSAGE( File::splitFileIntoLines(path,lines)," Failed to open file " << path);
+ BOOST_CHECK_MESSAGE( lines.size() == 1," Expected 1 line but found " << lines.size());
+
+ fs::remove(path); // Remove the file. Comment out for debugging
+ }
+
+ {
+ {
+ std::ofstream file_with_two_line( path.c_str() );
+ file_with_two_line << theText << "\n";
+ file_with_two_line << theText;
+ }
+
+ std::vector<std::string> lines;
+ BOOST_CHECK_MESSAGE( File::splitFileIntoLines(path,lines)," Failed to open file " << path);
+ BOOST_CHECK_MESSAGE( lines.size() == 2," Expected 2 line but found " << lines.size());
+
+ fs::remove(path); // Remove the file. Comment out for debugging
+ }
+
+ {
+ {
+ std::ofstream file_with_three_line( path.c_str() );
+ file_with_three_line << theText << "\n";
+ file_with_three_line << theText << "\n";
+ file_with_three_line << theText;
+ }
+
+ std::vector<std::string> lines;
+ BOOST_CHECK_MESSAGE( File::splitFileIntoLines(path,lines)," Failed to open file " << path);
+ BOOST_CHECK_MESSAGE( lines.size() == 3," Expected 3 line but found " << lines.size());
+
+ fs::remove(path); // Remove the file. Comment out for debugging
+ }
+
+ {
+ {
+ std::ofstream file_with_three_line( path.c_str() );
+ file_with_three_line << theText << "\n";
+ file_with_three_line << theText << "\n";
+ file_with_three_line << theText << "\n";
+ }
+
+ std::vector<std::string> lines;
+ BOOST_CHECK_MESSAGE( File::splitFileIntoLines(path,lines)," Failed to open file " << path);
+ BOOST_CHECK_MESSAGE( lines.size() == 3," Expected 3 line but found " << lines.size());
+
+ fs::remove(path); // Remove the file. Comment out for debugging
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_file_tokenizer )
+{
+ cout << "ACore:: ...test_file_tokenizer\n";
+
+ std::string path = File::test_data("ACore/test/data/test_file_tokenizer.txt","ACore");
+
+ size_t linesWithText = 100;
+ std::string theText = "This is a test string";
+ {
+ std::ofstream file( path.c_str() );
+ for(size_t i =0; i < linesWithText; i++) {
+ if (i % 2 == 0) file << "\n"; // 51 empty lines
+ file << theText << "\n"; // 100 text lines
+ }
+ }
+ {
+ std::vector<std::string> lines;
+ BOOST_CHECK_MESSAGE( File::splitFileIntoLines(path,lines,true/*ignore empty lines*/)," Failed to open file " << path);
+ BOOST_CHECK_MESSAGE( lines.size() == linesWithText,"Expected " << linesWithText << " but found " << lines.size());
+ BOOST_CHECK_MESSAGE( lines[0] == theText,"Expected '" << theText << "' but found " << lines[0]);
+ BOOST_CHECK_MESSAGE( lines[linesWithText-1] == theText,"Expected '" << theText << "' but found " << lines[linesWithText-1]);
+
+ lines.clear();
+ size_t totalLines = 151;
+ BOOST_CHECK_MESSAGE( File::splitFileIntoLines(path,lines)," Failed to open file " << path);
+ BOOST_CHECK_MESSAGE( lines.size() == totalLines-1,"Expected " << totalLines-1 << " but found " << lines.size());
+ BOOST_CHECK_MESSAGE( lines[0] == "","Expected empty string but found " << lines[0]);
+ BOOST_CHECK_MESSAGE( lines[1] == theText,"Expected '" << theText << "' but found " << lines[1]);
+ BOOST_CHECK_MESSAGE( lines[2] == theText,"Expected '" << theText << "' but found " << lines[2]);
+ BOOST_CHECK_MESSAGE( lines[3] == "","Expected empty string but found " << lines[3]);
+ }
+
+#ifdef FILE_PERF_CHECK_IMPLEMENTATIONS
+ {
+ size_t openFileNTimes = 100000;
+ boost::timer timer; // measures CPU, replace with cpu_timer with boost > 1.51, measures cpu & elapsed
+ for (size_t i = 0; i < openFileNTimes; i++) {
+ std::vector<std::string> lines;
+ BOOST_CHECK_MESSAGE( File::splitFileIntoLines(path,lines)," Failed to open file " << path);
+ }
+ cout << "Time for opening file " << openFileNTimes << " times = " << timer.elapsed() << "\n";
+ }
+#endif
+
+ // Remove the file. Comment out for debugging
+ fs::remove(path);
+}
+
+BOOST_AUTO_TEST_CASE( test_file_backwardSearch )
+{
+ cout << "ACore:: ...test_file_backwardSearch\n";
+
+ std::string nodePath = "dir0/dir1/dir2/dir3/dir4/dir5";
+ std::string rootPath = File::test_data("ACore/test/data","ACore");
+ std::string expected = File::test_data("ACore/test/data/","ACore") + nodePath;
+
+ std::string path = rootPath;
+ std::string dir = "dir";
+ for(int i = 0; i < 6; i++) {
+ path += "/" + dir + boost::lexical_cast<std::string>(i);
+ }
+ // Should have test/data/dir0/dir1/dir3/dir3/dir4/dir5
+ // or ACore/test/data/dir0/dir1/dir3/dir3/dir4/dir5
+ BOOST_REQUIRE_MESSAGE(path == expected," Error expected " << expected << " but found " << path);
+
+ // Create the missing directories
+ BOOST_REQUIRE_MESSAGE(File::createDirectories(path),"Failed to create dirs");
+
+ // Create a file in each of the directories. See Page 21 SMS User Guide.
+ std::vector<std::string> fileContents; fileContents.push_back("something");
+ vector<std::string> nodePathTokens;
+ NodePath::split(nodePath,nodePathTokens);
+ while ( nodePathTokens.size() > 0 ) {
+
+ // Reconstitute the path
+ std::string path = NodePath::createPath(nodePathTokens);
+ std::string combinedPath = rootPath + path;
+
+ BOOST_REQUIRE_MESSAGE(File::createDirectories(combinedPath),"Failed to create dirs " << combinedPath);
+
+ combinedPath += File::ECF_EXTN(); // .ecf, .man , etc
+
+ //std::cout << "Creating file " << combinedPath << "\n";
+ std::string errorMsg;
+ BOOST_REQUIRE_MESSAGE(File::create(combinedPath,fileContents,errorMsg),"Failed to create " << combinedPath << " because " << errorMsg);
+
+ nodePathTokens.erase(nodePathTokens.begin()); // consume first path token
+ }
+
+ // Now do a backward search for them
+ int filesFound = 0;
+ for(int i = 0; i < 6; i++) {
+ std::string theFile = File::backwardSearch(rootPath,nodePath,File::ECF_EXTN() );
+ BOOST_CHECK_MESSAGE( !theFile.empty(), i << ": Failed to find dir5.ecf with rootPath " << rootPath << " and node path " << nodePath);
+ if (!theFile.empty()) {
+ filesFound++;
+// std::cout << "About to remove file " << theFile << "\n";
+ fs::remove(theFile); // remove it so we don't find it again.
+ }
+ }
+ // Expect the following files to be found:
+ // test/data/dir0/dir1/dir2/dir3/dir4/dir5.ecf
+ // test/data/dir1/dir2/dir3/dir4/dir5.ecf
+ // test/data/dir2/dir3/dir4/dir5.ecf
+ // test/data/dir3/dir4/dir5.ecf
+ // test/data/dir4/dir5.ecf
+ // test/data/dir5.ecf
+ BOOST_CHECK_MESSAGE( filesFound == 6 ," expect to find 6 files but found " << filesFound );
+
+ // Remove the test dir. Comment out for debugging
+ for(int i = 0; i < 6; i++) {
+ path = rootPath + "/" + dir + boost::lexical_cast<std::string>(i);
+ BOOST_CHECK_MESSAGE(File::removeDir( path ),"Failed to remove dir " << path);
+ }
+}
+
+
+BOOST_AUTO_TEST_CASE( test_create_missing_directories )
+{
+ cout << "ACore:: ...test_create_missing_directories";
+
+ // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode.
+ if (getenv("ECFLOW_CRAY_BATCH")) {
+ cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n";
+ return;
+ }
+ cout << "\n";
+
+ std::string nodePath = "dir0/dir1/dir2/dir3/dir4/dir5";
+ std::string rootPath = File::test_data("ACore/test/data","ACore");
+ std::string expected = File::test_data("ACore/test/data/","ACore") + nodePath;
+
+ std::string dir_remove = rootPath + "/dir0";
+ {
+ // Test basics first, expect "ACore/test/data/dir0/dir1/dir2/dir3/dir4/dir5" to be created
+ BOOST_CHECK_MESSAGE(File::createMissingDirectories(expected),expected << " expected directories to be created");
+ BOOST_CHECK_MESSAGE(fs::exists(expected),expected << " directory not created");
+
+ // remove the directory
+ BOOST_CHECK_MESSAGE(File::removeDir( dir_remove ),"Failed to remove dir " << dir_remove);
+
+// fs::path fs_path(expected);
+// std::cout << "parent path " << fs_path.parent_path() << "\n";
+// std::cout << "root path " << fs_path.root_path() << "\n";
+// std::cout << "root name " << fs_path.root_name() << "\n";
+// std::cout << "root directory " << fs_path.root_directory() << "\n";
+// std::cout << "relative_path " << fs_path.relative_path() << "\n";
+// std::cout << "filename " << fs_path.filename() << "\n";
+// std::cout << "stem " << fs_path.stem() << "\n";
+// std::cout << "extension " << fs_path.extension() << "\n";
+ }
+ {
+ // Test "ACore/test/data/dir0/dir1/dir2/dir3/dir4/dir5/fred.ecf" to be created
+ std::string dir_with_file = expected + "/fred.ecf";
+ BOOST_CHECK_MESSAGE(File::createMissingDirectories(dir_with_file),"Expected '" << dir_with_file << "' to be created");
+ BOOST_CHECK_MESSAGE(fs::exists(expected),expected << " directory not created");
+
+ // remove the directory
+ BOOST_CHECK_MESSAGE(File::removeDir( dir_remove ),"Failed to remove dir " << dir_remove);
+
+// fs::path fs_path(dir_with_file);
+// std::cout << "parent path " << fs_path.parent_path() << "\n";
+// std::cout << "root path " << fs_path.root_path() << "\n";
+// std::cout << "root name " << fs_path.root_name() << "\n";
+// std::cout << "root directory " << fs_path.root_directory() << "\n";
+// std::cout << "relative_path " << fs_path.relative_path() << "\n";
+// std::cout << "filename " << fs_path.filename() << "\n";
+// std::cout << "stem " << fs_path.stem() << "\n";
+// std::cout << "extension " << fs_path.extension() << "\n";
+ }
+
+ {
+ // Create directories twice. Need to minimise call to fstat
+ BOOST_CHECK_MESSAGE(File::createMissingDirectories(expected),"expected file to be created");
+ BOOST_CHECK_MESSAGE(File::createMissingDirectories(expected),"expected file to be created");
+ BOOST_CHECK_MESSAGE(fs::exists(expected),expected << " directory not created");
+
+ // remove the directory
+ BOOST_CHECK_MESSAGE(File::removeDir( dir_remove ),"Failed to remove dir " << dir_remove);
+ }
+
+ {
+ // Create directories twice. Need to minimise call to fstat
+ std::string dir_with_file = expected + "/fred.ecf";
+ BOOST_CHECK_MESSAGE(File::createMissingDirectories(dir_with_file),"expected file to be created");
+ BOOST_CHECK_MESSAGE(File::createMissingDirectories(dir_with_file),"expected file to be created");
+ BOOST_CHECK_MESSAGE(fs::exists(expected),expected << " directory not created");
+
+ // remove the directory
+ BOOST_CHECK_MESSAGE(File::removeDir( dir_remove ),"Failed to remove dir " << dir_remove);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ACore/test/TestGetUserDetails.cpp b/ACore/test/TestGetUserDetails.cpp
new file mode 100644
index 0000000..55a74df
--- /dev/null
+++ b/ACore/test/TestGetUserDetails.cpp
@@ -0,0 +1,57 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+//#include <boost/test/unit_test.hpp>
+//#include <string>
+//#include <iostream>
+//
+//
+//#include <pwd.h> /* getpwdid */
+//#include <sys/types.h>
+//#include <unistd.h>
+//#include <stdio.h>
+//
+//using namespace std;
+//using namespace ecf;
+//
+//BOOST_AUTO_TEST_SUITE( CoreTestSuite )
+
+//BOOST_AUTO_TEST_CASE( test_get_user_details )
+//{
+// cout << "ACore:: ...test_get_user_details\n";
+//
+//
+// struct passwd *passwd; /* man getpwuid */
+//
+// passwd = getpwuid ( getuid()); /* Get the uid of the running processand use it to get a record from /etc/passwd */
+//
+// printf("\n The Real User Name is %s ", passwd->pw_gecos);
+//
+// printf("\n The Login Name is %s ", passwd->pw_name);
+//
+// printf("\n The Home Directory is %s", passwd->pw_dir);
+//
+// printf("\n The Login Shell is %s ", passwd->pw_shell);
+//
+// printf("\n The Passwd is %s ", getpwuid(getuid())->pw_passwd);
+//
+// printf("\n The uid is %lu ", (unsigned long) getpwuid(getuid())->pw_uid);
+//
+// printf("\n The gid is %lu \n\n", (unsigned long) getpwuid(getuid())->pw_gid);
+//}
+
+//BOOST_AUTO_TEST_SUITE_END()
+
+
diff --git a/ACore/test/TestLog.cpp b/ACore/test/TestLog.cpp
new file mode 100644
index 0000000..a0495b9
--- /dev/null
+++ b/ACore/test/TestLog.cpp
@@ -0,0 +1,365 @@
+//============================================================================
+// Name : Request
+// Author : Avi
+// Revision : $Revision: #21 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <iostream>
+#include <fstream>
+#include <stdlib.h> // for getenv()
+#include <string>
+
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+
+#include "Log.hpp"
+#include "File.hpp"
+#include "DurationTimer.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( CoreTestSuite )
+
+static std::string getLogPath() {
+
+ return File::test_data("ACore/test/logfile.txt","ACore");
+}
+
+BOOST_AUTO_TEST_CASE( test_log )
+{
+ cout << "ACore:: ...test_log\n";
+
+ std::string path = getLogPath();
+
+ // delete the log file if it exists.
+ fs::remove(path);
+ BOOST_CHECK_MESSAGE(!fs::exists( path ), "log file not deleted " << path << " not created \n");
+
+ Log::create(path);
+ LOG(Log::MSG,"First Message");
+ LOG(Log::LOG,"LOG");
+ LOG(Log::ERR,"ERROR");
+ LOG(Log::WAR,"WARNING");
+ LOG(Log::DBG,"DEBUG");
+ LOG(Log::OTH,"OTHER");
+ log(Log::OTH,"test: void log(Log::LogType,const std::string& message)");
+
+ LOG(Log::OTH,"test: LOG(level,path << path) " << path << " " << path);
+
+ Log::instance()->log(Log::OTH,"OTHER2");
+
+ BOOST_CHECK_MESSAGE(fs::exists( path ), "log file " << path << " not created \n");
+}
+
+BOOST_AUTO_TEST_CASE( test_log_append )
+{
+ cout << "ACore:: ...test_log_append\n";
+
+ std::string path = getLogPath();
+
+ BOOST_CHECK_MESSAGE(fs::exists( path ), "log file " << path << " not created by previous test\n");
+
+ LOG(Log::MSG,"Last Message");
+
+ // Load the log file into a vector, of strings, and test content
+ std::vector<std::string> lines;
+ BOOST_REQUIRE_MESSAGE(File::splitFileIntoLines(path,lines,true/*IGNORE EMPTY LINE AT THE END*/),"Failed to open log file");
+ BOOST_REQUIRE(lines.size() != 0);
+ BOOST_CHECK_MESSAGE(lines.size() == 10," Expected 10 lines in log, but found " << lines.size() << "\n");
+ BOOST_CHECK_MESSAGE(lines[0].find("First Message") != string::npos,"Expected first line to contain 'First Message' but found " << lines[0] << "\n");
+ BOOST_CHECK_MESSAGE(lines.back().find("Last Message") != string::npos,"Expected last line to contain 'Last Message' but found " << lines.back() << "\n");
+
+ // Clear the log file. Comment out for debugging
+ Log::instance()->clear();
+ BOOST_CHECK_MESSAGE(fs::file_size( path ) == 0, "Clear of log file failed\n");
+
+ // Remove the log file. Comment out for debugging
+ fs::remove(path);
+
+ // Explicitly destroy log. To keep valgrind happy
+ Log::destroy();
+}
+
+
+BOOST_AUTO_TEST_CASE( test_log_path )
+{
+ cout << "ACore:: ...test_log_path\n";
+
+ Log::create("test_log_path.log");
+
+ // make sure path returned is absolute
+ std::string path = Log::instance()->path();
+ BOOST_REQUIRE_MESSAGE(path[0] == '/',"Expected absolute paths for log file but found " << path);
+
+ // Remove the log file. Comment out for debugging
+ fs::remove(path);
+
+ // Explicitly destroy log. To keep valgrind happy
+ Log::destroy();
+}
+
+BOOST_AUTO_TEST_CASE( test_log_new_path_errors )
+{
+ cout << "ACore:: ...test_log_new_path_errors\n";
+
+ // delete the log file if it exists.
+ fs::remove(getLogPath());
+
+ // create a now log file.
+ Log::create(getLogPath());
+ LOG(Log::MSG,"First Message");
+ LOG(Log::LOG,"LOG");
+
+ // Specify bad paths for new log file
+ // First test empty path throws
+ BOOST_REQUIRE_THROW(Log::instance()->new_path(""),std::runtime_error);
+
+ // If a path is specified make sure parent directory exists
+ fs::path current_path = fs::current_path();
+ std::string path2 = current_path.string();
+ path2 += "/a/made/up/path/fred.log";
+ //cout << path2<< "\n";
+ BOOST_REQUIRE_THROW(Log::instance()->new_path(path2),std::runtime_error);
+
+ // Make sure path does not correspond to a directory
+ // cout << "parent directory: " << current_path.parent_path() << "\n";
+ BOOST_REQUIRE_THROW(Log::instance()->new_path( current_path.parent_path().string() ),std::runtime_error);
+
+// {
+// fs::path valid_path = getLogPath();
+// std::cout << "valid_path = " << valid_path << "\n";
+// std::cout << "valid_path.root_path(): " << valid_path.root_path() << "\n";
+// std::cout << "valid_path.root_name() : " << valid_path.root_name() << "\n";
+// std::cout << "valid_path.root_directory() : " << valid_path.root_directory() << "\n";
+// std::cout << "valid_path.relative_path() : " << valid_path.relative_path() << "\n";
+// std::cout << "valid_path.parent_path() : " << valid_path.parent_path() << "\n";
+// std::cout << "valid_path.filename() : " << valid_path.filename() << "\n";
+// std::cout << "valid_path.stem() : " << valid_path.stem() << "\n";
+// std::cout << "valid_path.extension() : " << valid_path.extension() << "\n";
+// }
+
+ // Remove the log file. Comment out for debugging
+ fs::remove(Log::instance()->path());
+
+ // Explicitly destroy log. To keep valgrind happy
+ Log::destroy();
+}
+
+
+BOOST_AUTO_TEST_CASE( test_log_new_path )
+{
+ cout << "ACore:: ...test_log_new_path\n";
+
+ // delete the log file if it exists.
+ fs::remove(getLogPath());
+
+ // create a new log file.
+ Log::create(getLogPath());
+ BOOST_CHECK_MESSAGE(fs::exists( Log::instance()->path() ), "Log file should be created after explicit call to Log::create()\n");
+ LOG(Log::LOG,"LOG");
+ fs::remove(Log::instance()->path());
+
+
+ // Specify a new log path. Path could be a relative path like "test/logfile.log"
+ std::string relative_path = File::test_data("ACore/test/logfile.log","ACore");
+
+ BOOST_REQUIRE_NO_THROW(Log::instance()->new_path( relative_path ));
+ BOOST_CHECK_MESSAGE(!fs::exists( Log::instance()->path() ), "Log file should *NOT* be created until first message is logged\n");
+ LOG(Log::LOG,"LOG");
+ BOOST_CHECK_MESSAGE(fs::exists( Log::instance()->path() ), "Log file should be created after first message is logged\n");
+ fs::remove(Log::instance()->path());
+
+
+ // Specify a new log path. This time we just specify a file name, without a path.
+ BOOST_REQUIRE_NO_THROW(Log::instance()->new_path( "testlog.log" ));
+ BOOST_CHECK_MESSAGE(!fs::exists( Log::instance()->path() ), "Log file should not be created until first message is logged\n");
+ // File not created until a message is logged
+ LOG(Log::LOG,"LOG");
+ BOOST_CHECK_MESSAGE(fs::exists( Log::instance()->path() ), "Log file should be created after first message is logged\n");
+ fs::remove(Log::instance()->path());
+
+ // Explicitly destroy log. To keep valgrind happy
+ Log::destroy();
+}
+
+BOOST_AUTO_TEST_CASE( test_get_last_n_lines_from_log )
+{
+ cout << "ACore:: ...test_get_last_n_lines_from_log\n";
+
+ // delete the log file if it exists.
+ std::string path = getLogPath();
+ fs::remove(path);
+ BOOST_CHECK_MESSAGE(!fs::exists( path ), "log file not deleted " << path << " not created \n");
+
+ // Create the log file;
+ Log::create(path);
+ BOOST_CHECK_MESSAGE(fs::exists( path ), "log file " << path << " not created \n");
+
+ // Log file should be empty
+ const int NO_OF_LINES_IN_LOG_FILE = 200;
+ {
+ for(int i =0; i < NO_OF_LINES_IN_LOG_FILE; i++) {
+ std::string line = Log::instance()->contents(i);
+ BOOST_CHECK_MESSAGE(line.empty(), "Expected empty string but found\n" << line);
+ }
+ }
+
+ // Populate the log file
+ std::string msg = "This is message ";
+ for(int i = 0; i < NO_OF_LINES_IN_LOG_FILE; ++i) LOG(Log::MSG,msg << i);
+
+ // Now check, getting the lines
+ {
+ std::string line = Log::instance()->contents(0);
+ BOOST_CHECK_MESSAGE(line.empty(), "Expected empty string but found\n" << line);
+ }
+ {
+ // Check we get back the number of line requested
+ for(int i = 0; i< NO_OF_LINES_IN_LOG_FILE; i++) {
+ std::string lines = Log::instance()->contents(i);
+ int newlineCount = std::count( lines.begin(), lines.end(), '\n');
+ BOOST_CHECK_MESSAGE(i == newlineCount, "expected to " << i << " newlines but found " << newlineCount);
+ }
+ }
+ {
+ // Check we get back *ALL* lines requested
+ std::string lines = Log::instance()->contents(NO_OF_LINES_IN_LOG_FILE);
+ for(int i = 0; i< NO_OF_LINES_IN_LOG_FILE; i++) {
+ std::stringstream ss; ss << msg << i;
+ std::string str_to_find = ss.str();
+ BOOST_CHECK_MESSAGE(lines.find(str_to_find) != std::string::npos, "expected to find " << str_to_find << " in the log file");
+ }
+ }
+
+ {
+ // Request more than is available, should only get back whats there
+ std::string lines = Log::instance()->contents(NO_OF_LINES_IN_LOG_FILE*2);
+ int newlineCount = std::count( lines.begin(), lines.end(), '\n');
+ BOOST_CHECK_MESSAGE(NO_OF_LINES_IN_LOG_FILE == newlineCount, "expected " << NO_OF_LINES_IN_LOG_FILE << " newlines but found " << newlineCount);
+ }
+
+ fs::remove(Log::instance()->path());
+
+ // Explicitly destroy log. To keep valgrind happy
+ Log::destroy();
+}
+
+BOOST_AUTO_TEST_CASE( test_get_first_n_lines_from_log )
+{
+ cout << "ACore:: ...test_get_first_n_lines_from_log\n";
+
+ // delete the log file if it exists.
+ std::string path = getLogPath();
+ fs::remove(path);
+ BOOST_CHECK_MESSAGE(!fs::exists( path ), "log file not deleted " << path << " not created \n");
+
+ // Create the log file;
+ Log::create(path);
+ BOOST_CHECK_MESSAGE(fs::exists( path ), "log file " << path << " not created \n");
+
+ // Populate the log file
+ const int NO_OF_LINES_IN_LOG_FILE = 200;
+ std::string msg = "This is message ";
+ for(int i = 0; i < NO_OF_LINES_IN_LOG_FILE; ++i) LOG(Log::MSG,msg << i);
+
+ // Now check, getting the lines
+ {
+ // Get the first line
+ std::string line = Log::instance()->contents(-1);
+ std::string expected = msg + "0";
+ BOOST_CHECK_MESSAGE(line.find(expected) != std::string::npos, "Expected '" << expected << "' but found\n" << line);
+ }
+ {
+ // Get the first & second line
+ std::string line = Log::instance()->contents(-2);
+ std::string expected0 = msg + "0";
+ std::string expected1 = msg + "1";
+ BOOST_CHECK_MESSAGE(line.find(expected0) != std::string::npos, "Expected '" << expected0 << "' but found\n" << line);
+ BOOST_CHECK_MESSAGE(line.find(expected1) != std::string::npos, "Expected '" << expected1 << "' but found\n" << line);
+ }
+ {
+ // Check we get back the number of line requested
+ for(int i = 0; i< NO_OF_LINES_IN_LOG_FILE; i++) {
+ std::string lines = Log::instance()->contents(-i);
+ int newlineCount = std::count( lines.begin(), lines.end(), '\n');
+ BOOST_CHECK_MESSAGE(i == newlineCount, "expected to " << i << " newlines but found " << newlineCount);
+ }
+ }
+ {
+ std::string lines = Log::instance()->contents(-NO_OF_LINES_IN_LOG_FILE);
+ for(int i = 0; i < NO_OF_LINES_IN_LOG_FILE; i++){
+ std::stringstream ss; ss << msg << i;
+ std::string expected = ss.str();
+ BOOST_CHECK_MESSAGE(lines.find(expected) != std::string::npos, "Expected '" << expected << "' but found for i " << i);
+ }
+ }
+
+ {
+ // Request more than is available, should only get back whats there
+ std::string lines = Log::instance()->contents(-NO_OF_LINES_IN_LOG_FILE*2);
+ int newlineCount = std::count( lines.begin(), lines.end(), '\n');
+ BOOST_CHECK_MESSAGE(NO_OF_LINES_IN_LOG_FILE == newlineCount, "expected " << NO_OF_LINES_IN_LOG_FILE << " newlines but found " << newlineCount);
+ }
+
+ fs::remove(Log::instance()->path());
+
+ // Explicitly destroy log. To keep valgrind happy
+ Log::destroy();
+}
+
+
+BOOST_AUTO_TEST_CASE( test_get_log_timing )
+{
+ cout << "ACore:: ...test_get_log_timing: " << flush;
+
+ // *************************************************************************************
+ // This test was used with *DIFFERENT* implementations for Log::instance()->contents(1)
+ // What is shows, is that for optimal performance we should *NOT* load the entire log file
+ // This can be several giga bytes.
+ // **************************************************************************************
+
+ // delete the log file if it exists.
+ std::string path = getLogPath();
+ fs::remove(getLogPath());
+ BOOST_CHECK_MESSAGE(!fs::exists( path ), "log file not deleted " << path << " not created \n");
+
+ // Create the log file;
+ Log::create(path);
+ BOOST_CHECK_MESSAGE(fs::exists( path ), "log file " << path << " not created \n");
+
+ // Populate the log file
+ const int NO_OF_LINES_IN_LOG_FILE = 20000;
+ std::string msg = "This is message ";
+ for(int i = 0; i < NO_OF_LINES_IN_LOG_FILE; ++i) LOG(Log::MSG,msg << i);
+
+ DurationTimer timer;
+
+ {
+ const int LOOP = 100;
+ for(int i = 0; i< LOOP; i++) {
+ std::string lines = Log::instance()->contents(1);
+ BOOST_CHECK_MESSAGE(!lines.empty(), "expected entry");
+ }
+ }
+
+ fs::remove(Log::instance()->path());
+
+ // Explicitly destroy log. To keep valgrind happy
+ Log::destroy();
+
+ cout << timer.duration() << "s\n" << flush;
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ACore/test/TestMigration.cpp b/ACore/test/TestMigration.cpp
new file mode 100644
index 0000000..b33373d
--- /dev/null
+++ b/ACore/test/TestMigration.cpp
@@ -0,0 +1,73 @@
+#if defined(TEXT_ARCHIVE) || !defined(BINARY_ARCHIVE) && !defined(PORTABLE_BINARY_ARCHIVE) && !defined(EOS_PORTABLE_BINARY_ARCHIVE)
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <stdlib.h> // for getenv()
+
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+
+#include "TimeSeries.hpp"
+#include "SerializationTest.hpp"
+#include "Calendar.hpp"
+#include "File.hpp"
+#include "Ecf.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::posix_time;
+using namespace boost::gregorian;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( CoreTestSuite )
+
+// If you are updating the tests, *MAKE SURE* to check out test/data/migration/* files
+//#define UPDATE_TESTS 1
+
+BOOST_AUTO_TEST_CASE( test_migration_restore_1_9 )
+{
+ cout << "ACore:: ...test_migration_restore_1_9\n";
+
+ std::string file_name = File::test_data("ACore/test/data/migration/","ACore");
+
+ // Note: default calendar constructor will init with current time: Hence set for comparison
+ Calendar calendar;
+ boost::gregorian::date theDate(2011,2,10);
+ ptime time(theDate, hours(23) + minutes(59));
+ calendar.init(time, Calendar::REAL); // Calendar type is derived from the clock attribute & hence is not persisted
+ Ecf::set_debug_equality(true);
+
+#ifdef UPDATE_TESTS
+ doSave<TimeSlot>(file_name + "timeslot_default_constructor_v1.9");
+ doSave<TimeSeries>(file_name + "timeseries_default_constructor_v1.9");
+ doSave<Calendar>(file_name + "calendar_v1.9",calendar);
+ doSave(file_name + "timeslot_1_1_v1_9",TimeSlot(1,1));
+ doSave(file_name + "timeslot_99_59_v1_9",TimeSlot(99,59));
+ doSave(file_name + "timeseries_10_10_v1_9",TimeSeries(TimeSlot(10,10)));
+#else
+ do_restore<TimeSlot>(file_name + "timeslot_default_constructor_v1.9",TimeSlot());
+ do_restore<TimeSeries>(file_name + "timeseries_default_constructor_v1.9",TimeSeries());
+ do_restore<Calendar>(file_name + "calendar_v1.9",calendar);
+ do_restore<TimeSlot>(file_name + "timeslot_1_1_v1_9",TimeSlot(1,1));
+ do_restore<TimeSlot>(file_name + "timeslot_99_59_v1_9",TimeSlot(99,59));
+ do_restore<TimeSeries>(file_name + "timeseries_10_10_v1_9",TimeSeries(TimeSlot(10,10)));
+#endif
+ Ecf::set_debug_equality(false);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+#endif
diff --git a/ACore/test/TestNodePath.cpp b/ACore/test/TestNodePath.cpp
new file mode 100644
index 0000000..88fbb06
--- /dev/null
+++ b/ACore/test/TestNodePath.cpp
@@ -0,0 +1,148 @@
+#define BOOST_TEST_MODULE TestCore
+//============================================================================
+// Name : Request
+// Author : Avi
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <string>
+#include <iostream>
+
+#include <boost/test/unit_test.hpp>
+#include <boost/timer.hpp>
+
+#include "NodePath.hpp"
+
+using namespace std;
+
+BOOST_AUTO_TEST_SUITE( CoreTestSuite )
+
+static void checkPath( const std::vector<std::string>& expectedPath, const std::string& path )
+{
+ std::vector<std::string> thePath;
+ NodePath::split(path,thePath);
+ if ( thePath != expectedPath ) {
+ BOOST_CHECK_MESSAGE(false,"Failed for " << path );
+ std::cout << "Expected '";
+ std::copy (expectedPath.begin(), expectedPath.end(), std::ostream_iterator <std::string> (std::cout, " "));
+ std::cout << "'\nbut found '";
+ std::copy (thePath.begin(), thePath.end(), std::ostream_iterator <std::string> (std::cout, " "));
+ std::cout << "'\n";
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_path_extractor_constructor )
+{
+ cout << "ACore:: ...test_path_extractor_constructor\n";
+ BOOST_CHECK(true); // stop boost test from complaining about no checks
+
+ std::vector<std::string> theExpectedPath;
+ checkPath(theExpectedPath,"");
+
+ theExpectedPath.push_back("suite");
+ checkPath(theExpectedPath,"/suite");
+ checkPath(theExpectedPath,"suite");
+}
+
+BOOST_AUTO_TEST_CASE( test_path_extractor )
+{
+ cout << "ACore:: ...test_path_extractor\n";
+ BOOST_CHECK(true); // stop boost test from complaining about no checks
+
+ std::vector<std::string> theExpectedPath;
+ theExpectedPath.push_back("suite");
+ theExpectedPath.push_back("family");
+ theExpectedPath.push_back("task");
+
+ checkPath(theExpectedPath,"/suite/family/task");
+ checkPath(theExpectedPath,"/suite/family/task/");
+}
+
+BOOST_AUTO_TEST_CASE( test_unix_path_extractor )
+{
+ cout << "ACore:: ...test_unix_path_extractor\n";
+ BOOST_CHECK(true); // stop boost test from complaining about no checks
+
+ // On Unix multiple '/' are treated as one.
+ std::vector<std::string> theExpectedPath;
+ theExpectedPath.push_back("suite");
+ theExpectedPath.push_back("family");
+ theExpectedPath.push_back("task");
+
+ checkPath(theExpectedPath,"/suite///family////task");
+ checkPath(theExpectedPath,"/suite///family////task//");
+ checkPath(theExpectedPath,"//suite///family////task//");
+ checkPath(theExpectedPath,"///suite///family////task//");
+ checkPath(theExpectedPath,"///suite///family////task///");
+}
+
+BOOST_AUTO_TEST_CASE( test_extractHostPort )
+{
+ cout << "ACore:: ...test_extractHostPort\n";
+
+ std::string path;
+ std::string host;
+ std::string port;
+ BOOST_CHECK_MESSAGE(!NodePath::extractHostPort(path,host,port), "expected failure");
+
+ path = "Apath";
+ BOOST_CHECK_MESSAGE(!NodePath::extractHostPort(path,host,port), "expected failure");
+
+ path = " : ";
+ BOOST_CHECK_MESSAGE(!NodePath::extractHostPort(path,host,port), "expected failure");
+
+ path = "host:";
+ BOOST_CHECK_MESSAGE(!NodePath::extractHostPort(path,host,port), "expected failure");
+
+ path = ":port";
+ BOOST_CHECK_MESSAGE(!NodePath::extractHostPort(path,host,port), "expected failure");
+
+ path = "host:port";
+ BOOST_CHECK_MESSAGE(NodePath::extractHostPort(path,host,port), "expected success " << host << ":" << port);
+ BOOST_CHECK_MESSAGE(host == "host" && port == "port", "expected 'host:port' found " << host << ":" << port);
+
+ path = "//host:port";
+ BOOST_CHECK_MESSAGE(NodePath::extractHostPort(path,host,port), "expected success " << host << ":" << port);
+ BOOST_CHECK_MESSAGE(host == "host" && port == "port", "expected 'host:port' found " << host << ":" << port);
+
+ path = "//host:port/";
+ BOOST_CHECK_MESSAGE(NodePath::extractHostPort(path,host,port), "expected success " << host << ":" << port);
+ BOOST_CHECK_MESSAGE(host == "host" && port == "port", "expected 'host:port' found " << host << ":" << port);
+
+ path = "//host:port/suite";
+ BOOST_CHECK_MESSAGE(NodePath::extractHostPort(path,host,port), "expected success " << host << ":" << port);
+ BOOST_CHECK_MESSAGE(host == "host" && port == "port", "expected 'host:port' found " << host << ":" << port);
+
+ path = "//host:port/suite/family/task";
+ BOOST_CHECK_MESSAGE(NodePath::extractHostPort(path,host,port), "expected success " << host << ":" << port);
+ BOOST_CHECK_MESSAGE(host == "host" && port == "port", "expected 'host:port' found " << host << ":" << port);
+}
+
+//BOOST_AUTO_TEST_CASE( test_NodePath_perf )
+//{
+// cout << "ACore:: ...test_NodePath_perf \n";
+//
+// // Using
+// // boost tokenizer timing: 9.73
+// // Str::split : 5.15
+// boost::timer timer; // measures CPU, replace with cpu_timer with boost > 1.51, measures cpu & elapsed
+// int n= 1000000 ;
+// for(int i = 0; i < n; i++) {
+// std::vector<std::string> thePath;
+// NodePath::split("/this/is/a/test/string/that/will/be/usedto/check/perf",thePath);
+// }
+//
+// cout << "Timing for " << n << " NodePath is " << timer.elapsed() << endl;
+//}
+
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ACore/test/TestRealCalendar.cpp b/ACore/test/TestRealCalendar.cpp
new file mode 100644
index 0000000..f60b683
--- /dev/null
+++ b/ACore/test/TestRealCalendar.cpp
@@ -0,0 +1,355 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <boost/test/unit_test.hpp>
+#include <string>
+#include <iostream>
+#include <fstream>
+
+#include "Calendar.hpp"
+#include "TimeSeries.hpp"
+#include <boost/date_time/posix_time/time_formatters.hpp>
+
+using namespace std;
+using namespace ecf;
+using namespace boost::posix_time;
+using namespace boost::gregorian;
+
+BOOST_AUTO_TEST_SUITE( CoreTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_REAL_calendar )
+{
+ cout << "ACore:: ...test_REAL_calendar\n";
+
+ // init the calendar to 2009, Feb, 10th,
+ boost::gregorian::date theDate(2009,2,10);
+ ptime time(theDate, hours(22) + minutes(10));
+
+ Calendar calendar;
+ calendar.init(time, Calendar::REAL);
+
+ // record the time for the test
+ boost::posix_time::ptime theSuiteTime = calendar.suiteTime();
+ boost::posix_time::time_duration theDuration = calendar.duration();
+
+ // Take time now and add 2 minutes, use this to update calendar by 2 minutes
+ boost::posix_time::ptime time_now = Calendar::second_clock_time();
+ time_now += minutes(2);
+ theSuiteTime += minutes(2);
+ theDuration += minutes(2);
+
+ calendar.update(time_now);
+
+ BOOST_CHECK_MESSAGE( calendar.suiteTime() == theSuiteTime," Expected " << to_simple_string(theSuiteTime) << " but found " << to_simple_string(calendar.suiteTime()) );
+ BOOST_CHECK_MESSAGE( calendar.duration() == theDuration," Expected " << to_simple_string(theDuration) << " but found " << to_simple_string(calendar.duration()) );
+
+ time_now += hours(24);
+ theSuiteTime += hours(24);
+ theDuration += hours(24);
+
+ calendar.update(time_now);
+
+ BOOST_CHECK_MESSAGE( calendar.suiteTime() == theSuiteTime," Expected " << to_simple_string(theSuiteTime) << " but found " << to_simple_string(calendar.suiteTime()) );
+ BOOST_CHECK_MESSAGE( calendar.duration() == theDuration," Expected " << to_simple_string(theDuration) << " but found " << to_simple_string(calendar.duration()) );
+}
+
+
+BOOST_AUTO_TEST_CASE( test_REAL_calendar_time_series_relative_complex )
+{
+ cout << "ACore:: ...test_REAL_calendar_time_series_relative_complex\n";
+
+ // init the calendar to 2009, Feb, 10th, 0 minutes past midnight
+ Calendar calendar;
+ calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::HYBRID);
+
+ // Create a test when we can match a time series
+ // Create the time series: start 10:00
+ // finish 20:00
+ // incr 00:15
+ TimeSeries timeSeries(TimeSlot(10,0), TimeSlot(20,0), TimeSlot(0,15),true/*relative*/);
+
+ boost::posix_time::ptime time_now = Calendar::second_clock_time();
+
+ for(int hour=0; hour < 24; hour++) {
+ for( int minute=0; minute<60; minute++) {
+
+ // Update calendar every hour, then see we can match time series, *RELATIVE* to suite start
+ time_now += minutes(1);
+
+ calendar.update(time_now);
+
+ timeSeries.calendarChanged( calendar );
+
+ tm suiteTm = to_tm(calendar.suiteTime());
+
+ bool matches = timeSeries.isFree(calendar);
+
+ bool intersects = ( suiteTm.tm_hour >= timeSeries.start().hour() &&
+ suiteTm.tm_hour <= timeSeries.finish().hour() &&
+ (suiteTm.tm_min == 0 || suiteTm.tm_min % timeSeries.incr().minute() == 0)
+ );
+ // Ovoid overshooting past end of series
+ bool boundaryOk = true;
+ if ( suiteTm.tm_hour == timeSeries.finish().hour() ) {
+ boundaryOk = (suiteTm.tm_min <= timeSeries.finish().minute());
+ }
+
+ if ( intersects && boundaryOk )
+ {
+ BOOST_CHECK_MESSAGE(matches,
+ "Calendar should match relative time series at "
+ << suiteTm.tm_hour <<":"<< suiteTm.tm_min
+ << " suite time = " << to_simple_string(calendar.suiteTime()));
+ if (!matches) {
+ cerr << "suiteTm.tm_hour =" << suiteTm.tm_hour << " suiteTm.tm_min = " << suiteTm.tm_min
+ << " timeSeries.start().hour() " << timeSeries.start().hour()
+ << " timeSeries.start().minute() " << timeSeries.start().minute()
+ << " timeSeries.finish().hour() " << timeSeries.finish().hour()
+ << " timeSeries.finish().minute() " << timeSeries.finish().minute()
+ << " suiteTm.tm_min % 15 = " << suiteTm.tm_min % 15
+ << "\n";
+ }
+ }
+ else {
+ BOOST_CHECK_MESSAGE(!matches,
+ "Calendar should NOT match relative time series at "
+ << suiteTm.tm_hour <<":"<< suiteTm.tm_min
+ << " suite time = " << to_simple_string(calendar.suiteTime()));
+
+ if (matches) {
+ cerr << "suiteTm.tm_hour =" << suiteTm.tm_hour << " suiteTm.tm_min = " << suiteTm.tm_min
+ << " timeSeries.start().hour() " << timeSeries.start().hour()
+ << " timeSeries.start().minute() " << timeSeries.start().minute()
+ << " timeSeries.finish().hour() " << timeSeries.finish().hour()
+ << " timeSeries.finish().minute() " << timeSeries.finish().minute()
+ << " suiteTm.tm_min % 15 = " << suiteTm.tm_min % 15
+ << "\n";
+ }
+ }
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_REAL_calendar_time_series)
+{
+ cout << "ACore:: ...test_REAL_calendar_time_series\n";
+
+ // init the calendar to 2009, Feb, 10th, 0 minutes past midnight
+ Calendar calendar;
+ calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::REAL);
+
+ // Create a test when we can match a time series
+ // Create the time series: start 10:00
+ // finish 20:00
+ // incr 1:00
+ TimeSeries timeSeries(TimeSlot(10,0), TimeSlot(20,0), TimeSlot(1,0));
+
+ boost::posix_time::ptime time_now = Calendar::second_clock_time();
+
+ for(int hour=1; hour < 24; hour++) {
+ // Update calendar every hour, then see we can match time series, in REAL
+ // Update will set the local time from the computers system clock, however
+ // for testing this will need to be overriden below.
+
+ time_now += hours(1);
+
+ calendar.update(time_now);
+
+ // cerr << "hour = " << hour << " suiteTime " << to_simple_string(calendar.suiteTime()) << "\n";
+ if (hour >= timeSeries.start().hour() && hour <=timeSeries.finish().hour()) {
+ BOOST_CHECK_MESSAGE(timeSeries.isFree(calendar),"Calendar should match time series at hour " << hour );
+ }
+ else {
+ BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar),"Calendar should NOT match time series at hour " << hour );
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_REAL_calendar_time_series_complex )
+{
+ cout << "ACore:: ...test_REAL_calendar_time_series_complex\n";
+
+ // init the calendar to 2009, Feb, 10th, 0 minutes past midnight
+ Calendar calendar;
+ calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::REAL);
+
+ // Create a test when we can match a time series
+ // Create the time series: start 10:00
+ // finish 20:00
+ // incr 00:15
+ TimeSeries timeSeries(TimeSlot(10,0), TimeSlot(20,0), TimeSlot(0,15));
+
+ boost::posix_time::ptime time_now = Calendar::second_clock_time();
+
+ for(int hour=0; hour < 24; hour++) {
+ for( int minute=0; minute<60; minute++) {
+
+ // Update calendar every minute, then see we can match time series, *RELATIVE* to suite start
+ time_now += minutes(1);
+ calendar.update(time_now);
+
+ tm suiteTm = to_tm(calendar.suiteTime());
+
+ bool matches = timeSeries.isFree(calendar);
+
+ bool intersects = ( suiteTm.tm_hour >= timeSeries.start().hour() &&
+ suiteTm.tm_hour <= timeSeries.finish().hour() &&
+ (suiteTm.tm_min == 0 || suiteTm.tm_min % timeSeries.incr().minute() == 0)
+ );
+ // Ovoid overshooting past end of series
+ bool boundaryOk = true;
+ if ( suiteTm.tm_hour == timeSeries.finish().hour() ) {
+ boundaryOk = (suiteTm.tm_min <= timeSeries.finish().minute());
+ }
+
+ if ( intersects && boundaryOk )
+ {
+ BOOST_CHECK_MESSAGE(matches,
+ "Calendar should match relative time series at "
+ << suiteTm.tm_hour <<":"<< suiteTm.tm_min
+ << " suite time = " << to_simple_string(calendar.suiteTime()));
+ if (!matches) {
+ cerr << "suiteTm.tm_hour =" << suiteTm.tm_hour << " suiteTm.tm_min = " << suiteTm.tm_min
+ << " timeSeries.start().hour() " << timeSeries.start().hour()
+ << " timeSeries.start().minute() " << timeSeries.start().minute()
+ << " timeSeries.finish().hour() " << timeSeries.finish().hour()
+ << " timeSeries.finish().minute() " << timeSeries.finish().minute()
+ << " suiteTm.tm_min % 15 = " << suiteTm.tm_min % 15
+ << "\n";
+ }
+ }
+ else {
+ BOOST_CHECK_MESSAGE(!matches,
+ "Calendar should NOT match relative time series at "
+ << suiteTm.tm_hour <<":"<< suiteTm.tm_min
+ << " suite time = " << to_simple_string(calendar.suiteTime()));
+
+ if (matches) {
+ cerr << "suiteTm.tm_hour =" << suiteTm.tm_hour << " suiteTm.tm_min = " << suiteTm.tm_min
+ << " timeSeries.start().hour() " << timeSeries.start().hour()
+ << " timeSeries.start().minute() " << timeSeries.start().minute()
+ << " timeSeries.finish().hour() " << timeSeries.finish().hour()
+ << " timeSeries.finish().minute() " << timeSeries.finish().minute()
+ << " suiteTm.tm_min % 15 = " << suiteTm.tm_min % 15
+ << "\n";
+ }
+ }
+ }
+ }
+}
+
+
+BOOST_AUTO_TEST_CASE( test_REAL_calendar_hybrid_date )
+{
+ cout << "ACore:: ...test_REAL_calendar_hybrid_date\n";
+
+ // The hybrid calendar should not change the suite date.
+ // Test by updateing calendar by more than 24 hours
+
+ // init the calendar to 2009, Feb, 10th, 0 minutes past midnight
+ Calendar calendar;
+ calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::HYBRID);
+
+
+ std::string expectedDate = "2010-Feb-10";
+ boost::posix_time::ptime time_now = Calendar::second_clock_time();
+
+ for(int hour=1; hour < 60; hour++) {
+ // Update calendar every hour, for 60 hours
+ // the date should be the same, i.e 2009, Feb, 10th
+
+ ptime timeBeforeUpdate = calendar.suiteTime();
+
+ time_now += hours(1);
+
+ calendar.update(time_now);
+
+ ptime timeAfterUpdate = calendar.suiteTime();
+
+// cerr << "hour = " << hour << " timeBeforeUpdate " << to_simple_string(timeBeforeUpdate)
+// << " timeAfterUpdate = " << to_simple_string(timeAfterUpdate) << "\n";
+
+ if (hour != 24 && hour != 48) {
+ time_period diff(timeBeforeUpdate,timeAfterUpdate);
+ time_duration gap = diff.length();
+ BOOST_CHECK_MESSAGE( gap.hours() == 1,"Expected one hour difference but found " << gap.hours() << " at hour " << hour);
+ }
+
+ std::string actualDate = to_simple_string(calendar.suiteTime().date());
+ BOOST_CHECK_MESSAGE( actualDate == expectedDate,"Expected '" << expectedDate << "' but found " << actualDate << " at hour " << hour);
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_REAL_day_changed )
+{
+ cout << "ACore:: ...test_REAL_day_changed \n";
+
+ // init the calendar to 2009, Feb, 10th, 0 minutes past midnight
+ Calendar calendar;
+ calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::REAL);
+ BOOST_CHECK_MESSAGE(!calendar.hybrid(),"calendar type should be real");
+
+ boost::posix_time::ptime time_now = Calendar::second_clock_time();
+
+ for(int hour=1; hour < 73; hour++) {
+ // Update calendar every hour, for 72 hours
+
+ time_now += hours(1);
+
+ calendar.update(time_now);
+
+ if (hour == 24 || hour == 48 || hour == 72) {
+ BOOST_CHECK_MESSAGE( calendar.dayChanged(),"Expected day change at hour " << hour << " calendar " << calendar.toString());
+ }
+ else {
+ BOOST_CHECK_MESSAGE( !calendar.dayChanged(),"Un-Expected day change at hour " << hour << " calendar " << calendar.toString());
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_REAL_day_changed_for_hybrid )
+{
+ cout << "ACore:: ...test_REAL_day_changed_for_hybrid\n";
+
+ // init the calendar to 2009, Feb, 10th, 0 minutes past midnight
+ Calendar calendar;
+ calendar.init(ptime(date(2010,2,10), minutes(0)),Calendar::HYBRID);
+ BOOST_CHECK_MESSAGE(calendar.hybrid(),"calendar type should be real");
+
+ // HYBRID calendars allow for day change but not date.
+ std::string expected_date = to_simple_string(calendar.date());
+
+ boost::posix_time::ptime time_now = Calendar::second_clock_time();
+
+ for(int hour=1; hour < 73; hour++) {
+ // Update calendar every hour, for 72 hours
+
+ time_now += hours(1);
+ calendar.update(time_now);
+
+ BOOST_CHECK_MESSAGE( expected_date == to_simple_string(calendar.date()) ,
+ "Unexpected date change for hybrid calendar at hour " << hour);
+
+ // Day should change even for hybrid calendar,
+ if (hour == 24 || hour == 48 || hour == 72) {
+ BOOST_CHECK_MESSAGE( calendar.dayChanged(),"Expected day change at hour " << hour << " calendar " << calendar.toString());
+ }
+ else {
+ BOOST_CHECK_MESSAGE( !calendar.dayChanged(),"Un-Expected day change at hour " << hour << " calendar " << calendar.toString());
+ }
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ACore/test/TestSerialisation.cpp b/ACore/test/TestSerialisation.cpp
new file mode 100644
index 0000000..42482b8
--- /dev/null
+++ b/ACore/test/TestSerialisation.cpp
@@ -0,0 +1,135 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #12 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <boost/test/unit_test.hpp>
+#include "TimeSeries.hpp"
+#include "SerializationTest.hpp"
+#include "Calendar.hpp"
+#include "boost_archive.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::posix_time;
+using namespace boost::gregorian;
+
+static std::string fileName = "test.txt";
+
+BOOST_AUTO_TEST_SUITE( CoreTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_archive_version )
+{
+ cout << "ACore:: ...test_archive_version: ";
+ // Boost 1.47 archive version = 9
+ // Bosst 1.53 archive version = 10
+ BOOST_CHECK_MESSAGE(boost_archive::version() >= 9,"Expected boost archive version >= 9");
+ std::cout << boost_archive::version() << "\n";
+}
+
+BOOST_AUTO_TEST_CASE( test_extract_archive_version )
+{
+ cout << "ACore:: ...test_extract_archive_version\n";
+
+ // get the archive version:
+ std::string boost_serial_str = "22 serialization::archive 9 0 0 0 0 1 1 0";
+ BOOST_CHECK_MESSAGE(boost_archive::extract_version(boost_serial_str) == 9,"Expected version to be 9 but found " << boost_archive::extract_version(boost_serial_str));
+
+ boost_serial_str = "22 serialization::archive 10 0 0 0 0 1 1 0";
+ BOOST_CHECK_MESSAGE(boost_archive::extract_version(boost_serial_str) == 10,"Expected version to be 10 but found " << boost_archive::extract_version(boost_serial_str));
+
+ boost_serial_str = "22 serialization::archive 999 0 0 0 0 1 1 0";
+ BOOST_CHECK_MESSAGE(boost_archive::extract_version(boost_serial_str) == 999,"Expected version to be 999 but found " << boost_archive::extract_version(boost_serial_str));
+
+ // error
+ boost_serial_str = "22 serialization::archive";
+ BOOST_CHECK_MESSAGE(boost_archive::extract_version(boost_serial_str) == 0,"Expected version to be 0 but found " << boost_archive::extract_version(boost_serial_str));
+}
+
+
+BOOST_AUTO_TEST_CASE( test_replace_archive_version )
+{
+ cout << "ACore:: ...test_replace_archive_version\n";
+
+ std::string boost_serial_str = "22 serialization::archive 9 0 0 0 0 1 1 0";
+ std::string expected = "22 serialization::archive 10 0 0 0 0 1 1 0";
+ BOOST_CHECK(boost_archive::replace_version(boost_serial_str,10));
+ BOOST_CHECK_MESSAGE(boost_serial_str == expected,"Expected '" << expected << "' but found '" << boost_serial_str << "'");
+
+ boost_serial_str = "22 serialization::archive 10 0 0 0 0 1 1 0";
+ expected = "22 serialization::archive 9 0 0 0 0 1 1 0";
+ BOOST_CHECK(boost_archive::replace_version(boost_serial_str,9));
+ BOOST_CHECK_MESSAGE(boost_serial_str == expected,"Expected '" << expected << "' but found '" << boost_serial_str << "'");
+
+ boost_serial_str = "22 serialization::archive 10 10 10";
+ expected = "22 serialization::archive 11 10 10";
+ BOOST_CHECK(boost_archive::replace_version(boost_serial_str,11));
+ BOOST_CHECK_MESSAGE(boost_serial_str == expected,"Expected '" << expected << "' but found '" << boost_serial_str << "'");
+
+ boost_serial_str = "22 serialization::archive 10 10 10";
+ expected = "22 serialization::archive 44444 10 10";
+ BOOST_CHECK(boost_archive::replace_version(boost_serial_str,44444));
+ BOOST_CHECK_MESSAGE(boost_serial_str == expected,"Expected '" << expected << "' but found '" << boost_serial_str << "'");
+
+ // error
+ boost_serial_str = "22 serialization::archive ";
+ expected = "22 serialization::archive ";
+ BOOST_CHECK(!boost_archive::replace_version(boost_serial_str,11));
+ BOOST_CHECK_MESSAGE(boost_serial_str == expected,"Expected '" << expected << "' but found '" << boost_serial_str << "'");
+}
+
+BOOST_AUTO_TEST_CASE( test_calendar_serialisation )
+{
+ cout << "ACore:: ...test_calendar_serialisation \n";
+
+ Calendar cal;
+ doSaveAndRestore(fileName,cal);
+}
+
+BOOST_AUTO_TEST_CASE( test_TimeSlot_serialisation )
+{
+ cout << "ACore:: ...test_TimeSlot_serialisation \n";
+
+ {
+ doSaveAndRestore<TimeSlot>(fileName);
+ }
+
+ {
+ TimeSlot saved(1,1);
+ doSaveAndRestore(fileName,saved);
+ }
+
+ {
+ TimeSlot saved(99,59);
+ doSaveAndRestore(fileName,saved);
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_TimeSeries_serialisation )
+{
+ cout << "ACore:: ...test_TimeSeries_serialisation \n";
+
+ {
+ doSaveAndRestore<TimeSeries>(fileName);
+ }
+ {
+ TimeSeries saved = TimeSeries(TimeSlot(10,10));
+ doSaveAndRestore(fileName,saved);
+ }
+ {
+ TimeSeries saved = TimeSeries(TimeSlot(0,0),TimeSlot(10,10),TimeSlot(0,10));
+ doSaveAndRestore(fileName,saved);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ACore/test/TestStackTrace.cpp b/ACore/test/TestStackTrace.cpp
new file mode 100644
index 0000000..6eabc4a
--- /dev/null
+++ b/ACore/test/TestStackTrace.cpp
@@ -0,0 +1,80 @@
+////============================================================================
+//// Name :
+//// Author : Avi
+//// Revision : $Revision: #8 $
+////
+//// Copyright 2009-2016 ECMWF.
+//// This software is licensed under the terms of the Apache Licence version 2.0
+//// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+//// In applying this licence, ECMWF does not waive the privileges and immunities
+//// granted to it by virtue of its status as an intergovernmental organisation
+//// nor does it submit to any jurisdiction.
+////
+//// Description :
+////============================================================================
+//#include <boost/test/unit_test.hpp>
+//#include "boost/filesystem/operations.hpp"
+//#include "boost/filesystem/path.hpp"
+//#include <iostream>
+//#include <fstream>
+////#include "StackTrace.hpp"
+//
+//
+//using namespace boost;
+//using namespace std;
+//using namespace ecf;
+//namespace fs = boost::filesystem;
+//
+//BOOST_AUTO_TEST_SUITE( CoreTestSuite )
+//
+//class MyClass {
+//public:
+// std::string MemFunc( const std::string &someParam )
+// {
+// int depth = 5;
+// return StackTrace::dump( __FILE__, __LINE__, depth );
+// }
+//};
+//
+//std::string func2( const char *something )
+//{
+// MyClass a;
+// return a.MemFunc( something );
+//}
+//
+//std::string func1( int param1, const std::string ¶m2 )
+//{
+// return func2( param2.c_str() );
+//}
+//
+////BOOST_AUTO_TEST_CASE( test_stack_trace )
+////{
+////#if defined(__GNUC__)
+//// cout << "ACore:: ...test_stack_trace\n";
+//// std::string traceback = func1( 1, "TestString" );
+////
+//// std::string expected;
+//// fs::path current_path = fs::current_path();
+//// if (current_path.stem() == "ACore" ) {
+////// cout << "current_path.stem() == ACore )\n";
+//// expected = "Call Stack from test/TestStackTrace.cpp:28\n"
+//// " CoreTestSuite::MyClass::MemFunc(std::string const&)\n"
+//// " CoreTestSuite::func2(char const*)\n"
+//// " CoreTestSuite::func1(int, std::string const&)\n"
+//// " CoreTestSuite::test_stack_trace::test_method()\n";
+//// }
+//// else {
+////// cout << "current_path.stem() != ACore )\n";
+//// expected = "Call Stack from ACore/test/TestStackTrace.cpp:28\n"
+//// " CoreTestSuite::MyClass::MemFunc(std::string const&)\n"
+//// " CoreTestSuite::func2(char const*)\n"
+//// " CoreTestSuite::func1(int, std::string const&)\n"
+//// " CoreTestSuite::test_stack_trace::test_method()\n";
+//// }
+//// BOOST_CHECK_MESSAGE (traceback == expected,"Mismatch expected\n'" << expected << "'\n but found\n'" << traceback << "'");
+////#endif
+////}
+//
+//BOOST_AUTO_TEST_SUITE_END()
+//
+//
diff --git a/ACore/test/TestStr.cpp b/ACore/test/TestStr.cpp
new file mode 100644
index 0000000..d3c460b
--- /dev/null
+++ b/ACore/test/TestStr.cpp
@@ -0,0 +1,694 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #24 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <string>
+#include <iostream>
+#include <fstream>
+
+#include <boost/test/unit_test.hpp>
+#include <boost/timer.hpp>
+#include <boost/foreach.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/bind.hpp>
+#include <boost/algorithm/string/split.hpp>
+
+#include "Str.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost;
+
+//#define STRING_SPLIT_IMPLEMENTATIONS_PERF_CHECK_ 1;
+
+
+BOOST_AUTO_TEST_SUITE( CoreTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_str )
+{
+ cout << "ACore:: ...test_str\n";
+
+ {
+ std::string str;
+ std::string expected;
+ Str::removeQuotes(str);
+ BOOST_CHECK_MESSAGE(str == expected," Expected " << expected << " but found " << str);
+
+ str = "\"\""; expected = "";
+ Str::removeQuotes(str);
+ BOOST_CHECK_MESSAGE(str == expected," Expected " << expected << " but found " << str);
+
+ str = "fred"; expected = "fred";
+ Str::removeQuotes(str);
+ BOOST_CHECK_MESSAGE(str == expected," Expected " << expected << " but found " << str);
+
+ str = "\"fred\""; expected = "fred";
+ Str::removeQuotes(str);
+ BOOST_CHECK_MESSAGE(str == expected," Expected " << expected << " but found " << str);
+ }
+ {
+ std::string str;
+ std::string expected;
+ Str::removeSingleQuotes(str);
+ BOOST_CHECK_MESSAGE(str == expected," Expected " << expected << " but found " << str);
+
+ str = "''"; expected = "";
+ Str::removeSingleQuotes(str);
+ BOOST_CHECK_MESSAGE(str == expected," Expected " << expected << " but found " << str);
+
+ str = "fred"; expected = "fred";
+ Str::removeSingleQuotes(str);
+ BOOST_CHECK_MESSAGE(str == expected," Expected " << expected << " but found " << str);
+
+ str = "'fred'"; expected = "fred";
+ Str::removeSingleQuotes(str);
+ BOOST_CHECK_MESSAGE(str == expected," Expected " << expected << " but found " << str);
+ }
+ {
+ string test;
+ BOOST_CHECK_MESSAGE(!Str::truncate_at_start(test,7),"Empty sring should return false");
+
+ test= "this\nis\na\nstring\nwith\nlots\nof\nnew\nline";
+ string expected = "line";
+ BOOST_CHECK_MESSAGE(Str::truncate_at_start(test,1) && test==expected,"Expected:\n" << expected << "\nbut found:\n" << test);
+
+ test= "this\nis\na\nstring\nwith\nlots\nof\nnew\nline";
+ expected = "a\nstring\nwith\nlots\nof\nnew\nline";
+ BOOST_CHECK_MESSAGE(Str::truncate_at_start(test,7) && test==expected,"Expected:\n" << expected << "\nbut found:\n" << test);
+
+ test= "this\nis\na\nstring\nwith\nlots\nof\nnew\nline";
+ expected = test;
+ BOOST_CHECK_MESSAGE(!Str::truncate_at_start(test,9) && test==expected,"Expected:\n" << expected << "\nbut found:\n" << test);
+ }
+ {
+ string test;
+ BOOST_CHECK_MESSAGE(!Str::truncate_at_end(test,7),"Empty string should return false");
+
+ test= "this\nis\na\nstring\nwith\nlots\nof\nnew\nline";
+ string expected = "this\n";
+ BOOST_CHECK_MESSAGE(Str::truncate_at_end(test,1) && test==expected,"Expected:\n" << expected << "\nbut found:\n" << test);
+
+ test= "this\nis\na\nstring\nwith\nlots\nof\nnew\nline";
+ expected = "this\nis\n";
+ BOOST_CHECK_MESSAGE(Str::truncate_at_end(test,2) && test==expected,"Expected:\n" << expected << "\nbut found:\n" << test);
+
+ test= "this\nis\na\nstring\nwith\nlots\nof\nnew\nline";
+ expected= "this\nis\na\nstring\nwith\nlots\nof\n";
+ BOOST_CHECK_MESSAGE(Str::truncate_at_end(test,7) && test==expected,"Expected:\n" << expected << "\nbut found:\n" << test);
+
+ test= "this\nis\na\nstring\nwith\nlots\nof\nnew\nline";
+ expected = test;
+ BOOST_CHECK_MESSAGE(!Str::truncate_at_end(test,9) && test==expected,"Expected:\n" << expected << "\nbut found:\n" << test);
+ }
+}
+
+static void check(const std::string& line,
+ const std::vector<std::string>& result,
+ const std::vector<std::string>& expected )
+{
+ BOOST_CHECK_MESSAGE(result.size() == expected.size(),"expected size " << expected.size() << " but found " << result.size() << " for '" << line << "'");
+ BOOST_CHECK_MESSAGE(result == expected,"Str::split failed for '" << line << "'");
+ if (result != expected) {
+ cout << "Actual :"; BOOST_FOREACH(const string& t, result) { cout << "'" << t << "'"; } cout << "\n";
+ cout << "Expected:"; BOOST_FOREACH(const string& t, expected) { cout << "'" << t << "'"; } cout << "\n";
+ }
+}
+
+//BOOST_AUTO_TEST_CASE( test_boost_str_split )
+//{
+// cout << "ACore:: ...test_boost_str_split\n";
+//
+// std::string line = "This is a string ";
+// std::vector<std::string> expected;
+// expected.push_back("This"); expected.push_back("is"); expected.push_back("a"); expected.push_back("string");
+// expected.push_back(""); expected.push_back("");
+//
+// std::vector<std::string> result;
+// boost::algorithm::split(result, line, std::bind2nd(std::equal_to<char>(), ' ')); // default is compress off, preserve empty tokens
+// check(line,result,expected);
+//
+// expected.pop_back();
+// result.clear();
+// boost::algorithm::split(result, line, std::bind2nd(std::equal_to<char>(), ' '),boost::algorithm::token_compress_on);
+// check(line,result,expected);
+//
+// // boost::split(v, s, boost::lambda::_1 == ' ');
+//}
+
+
+BOOST_AUTO_TEST_CASE( test_str_split )
+{
+ cout << "ACore:: ...test_str_split\n";
+
+ std::string line = "This is a string";
+ std::vector<std::string> expected;
+ expected.push_back("This"); expected.push_back("is"); expected.push_back("a"); expected.push_back("string");
+ std::vector<std::string> result;
+ Str::split(line,result);
+ check(line,result,expected);
+
+
+ line.clear(); expected.clear(); result.clear();
+ line = " ";
+ Str::split(line,result);
+ check(line,result,expected);
+
+ line.clear(); expected.clear(); result.clear();
+ line = "a";
+ expected.push_back("a");
+ Str::split(line,result);
+ check(line,result,expected);
+
+ // Some implementation fail this test
+ line.clear(); expected.clear(); result.clear();
+ line = "\n";
+ expected.push_back("\n");
+ Str::split(line,result);
+ check(line,result,expected);
+
+ line.clear(); expected.clear(); result.clear();
+ line = "a ";
+ expected.push_back("a");
+ Str::split(line,result);
+ check(line,result,expected);
+
+ line.clear(); expected.clear(); result.clear();
+ line = " a";
+ expected.push_back("a");
+ Str::split(line,result);
+ check(line,result,expected);
+
+ line.clear(); expected.clear(); result.clear();
+ line = " a"; // check tabs
+ expected.push_back("a");
+ Str::split(line,result);
+ check(line,result,expected);
+
+ line.clear(); expected.clear(); result.clear();
+ line = " a "; // check sequential tabs
+ expected.push_back("a");
+ Str::split(line,result);
+ check(line,result,expected);
+
+ line.clear(); expected.clear(); result.clear();
+ line = " a ";
+ expected.push_back("a");
+ Str::split(line,result);
+ check(line,result,expected);
+
+ line.clear(); expected.clear(); result.clear();
+ line = " a b c d ";
+ expected.push_back("a"); expected.push_back("b"); expected.push_back("c"); expected.push_back("d");
+ Str::split(line,result);
+ check(line,result,expected);
+
+ line.clear(); expected.clear(); result.clear();
+ line = " - ! $ % ^ & * ( ) - + ?";
+ expected.push_back("-"); expected.push_back("!"); expected.push_back("$");
+ expected.push_back("%"); expected.push_back("^"); expected.push_back("&"); expected.push_back("*");
+ expected.push_back("("); expected.push_back(")"); expected.push_back("-"); expected.push_back("+");
+ expected.push_back("?");
+ Str::split(line,result);
+ check(line,result,expected);
+
+ // Check tabs
+ line.clear(); expected.clear(); result.clear();
+ line = " verify complete:8 # 4 sundays in october hence expect 8 task completions";
+ expected.push_back("verify");expected.push_back("complete:8");expected.push_back("#");expected.push_back("4");
+ expected.push_back("sundays");expected.push_back("in");expected.push_back("october");expected.push_back("hence");
+ expected.push_back("expect");expected.push_back("8");expected.push_back("task");expected.push_back("completions");
+ Str::split(line,result);
+ check(line,result,expected);
+
+#ifdef STRING_SPLIT_IMPLEMENTATIONS_PERF_CHECK_
+ {
+ line = "This is a long string that is going to be used to test the performance of splitting with different Implementations extra empty tokens ";
+ size_t times = 1000000;
+ boost::timer timer; // measures CPU, replace with cpu_timer with boost > 1.51, measures cpu & elapsed
+ for (size_t i = 0; i < times; i++) {
+ result.clear();
+// boost::algorithm::split(result, line, std::bind2nd(std::equal_to<char>(), ' '),boost::algorithm::token_compress_on); // 3.2 times slower, but preserves empty tokens
+ Str::split(line,result);
+ }
+ cout << "Time for Str::split " << times << " times = " << timer.elapsed() << "\n";
+ }
+#endif
+}
+
+
+static void test_replace( std::string& testStr, const std::string& find, const std::string& replace, const std::string& expected)
+{
+ BOOST_CHECK_MESSAGE(Str::replace(testStr,find,replace), "Replace failed for " << testStr << " find(" << find << ") replace(" << replace << ")");
+ BOOST_CHECK_MESSAGE(testStr == expected,"Expected '" << expected << "' but found '" << testStr <<"'");
+}
+
+static void test_replace_all( std::string& testStr, const std::string& find, const std::string& replace, const std::string& expected)
+{
+ std::string testStrCopy = testStr;
+
+ BOOST_CHECK_MESSAGE(Str::replace_all(testStr,find,replace), "Replace failed for " << testStr << " find(" << find << ") replace(" << replace << ")");
+ BOOST_CHECK_MESSAGE(testStr == expected,"Expected '" << expected << "' but found '" << testStr <<"'");
+
+ Str::replaceall(testStrCopy,find,replace);
+ BOOST_CHECK_MESSAGE(testStr == testStrCopy,"Expected '" << testStrCopy << "' but found '" << testStr <<"'");
+}
+
+
+BOOST_AUTO_TEST_CASE( test_str_replace )
+{
+ cout << "ACore:: ...test_str_replace\n";
+
+ std::string testStr = "This is a string";
+ test_replace(testStr,"This","That","That is a string");
+
+ testStr = "This is a string";
+ test_replace(testStr,"This is a string","","");
+
+ testStr = "This is a string";
+ test_replace(testStr,"is a","was a","This was a string");
+
+ testStr = "This\n is a string";
+ test_replace(testStr,"\n","\\n","This\\n is a string");
+
+ testStr = "This\n is\n a\n string\n";
+ test_replace_all(testStr,"\n","\\n","This\\n is\\n a\\n string\\n");
+
+ // Test case insenstive string comparison
+ BOOST_CHECK_MESSAGE(Str::caseInsCompare("","")," bug1");
+ BOOST_CHECK_MESSAGE(!Str::caseInsCompare("Str","Str1")," bug1");
+ BOOST_CHECK_MESSAGE(!Str::caseInsCompare("","Str1")," bug1");
+ BOOST_CHECK_MESSAGE(Str::caseInsCompare("Str","STR")," bug1");
+ BOOST_CHECK_MESSAGE(Str::caseInsCompare("Case","CaSE")," bug1");
+}
+
+BOOST_AUTO_TEST_CASE( test_str_replace_all )
+{
+ cout << "ACore:: ...test_str_replace_all\n";
+
+ std::string testStr = "This is a string";
+ test_replace_all(testStr,"This","That","That is a string");
+
+ testStr = "This is a string";
+ test_replace_all(testStr,"This is a string","","");
+
+ testStr = "This is a string";
+ test_replace_all(testStr,"is a","was a","This was a string");
+
+ testStr = "This\n is a string";
+ test_replace_all(testStr,"\n","\\n","This\\n is a string");
+
+ testStr = "This\n is\n a\n string\n";
+ test_replace_all(testStr,"\n","\\n","This\\n is\\n a\\n string\\n");
+
+ testStr = "This\n is\n a\n string\n";
+ test_replace_all(testStr,"\n","","This is a string");
+}
+
+BOOST_AUTO_TEST_CASE( test_str_to_int )
+{
+ cout << "ACore:: ...test_str(to_int)\n";
+ BOOST_CHECK_MESSAGE(Str::to_int("0") == 0,"Expected 0");
+ BOOST_CHECK_MESSAGE(Str::to_int("1") == 1,"Expected 1");
+ BOOST_CHECK_MESSAGE(Str::to_int("-0") == 0,"Expected 0");
+ BOOST_CHECK_MESSAGE(Str::to_int("-1") == -1,"Expected -1");
+ BOOST_CHECK_MESSAGE(Str::to_int("") == std::numeric_limits<int>::max(),"Expected max int");
+ BOOST_CHECK_MESSAGE(Str::to_int("-") == std::numeric_limits<int>::max(),"Expected max int");
+ BOOST_CHECK_MESSAGE(Str::to_int(" ") == std::numeric_limits<int>::max(),"Expected max int");
+ BOOST_CHECK_MESSAGE(Str::to_int("q") == std::numeric_limits<int>::max(),"Expected max int");
+ BOOST_CHECK_MESSAGE(Str::to_int("q22") == std::numeric_limits<int>::max(),"Expected max int");
+ BOOST_CHECK_MESSAGE(Str::to_int("q22",-1) == -1,"Expected -1 on failure");
+ BOOST_CHECK_MESSAGE(Str::to_int("99 99") == std::numeric_limits<int>::max(),"Expected max int");
+ BOOST_CHECK_MESSAGE(Str::to_int("99 99",0) == 0,"Expected 0 for failure");
+}
+
+BOOST_AUTO_TEST_CASE( test_extract_data_member_value )
+{
+ cout << "ACore:: ...test_extract_data_member_value\n";
+ std::string expected = "value";
+ std::string actual;
+ std::string str = "aa bb c fred:value";
+ BOOST_CHECK_MESSAGE(Str::extract_data_member_value(str,"fred:",actual)," failed");
+ BOOST_CHECK_MESSAGE(expected == actual,"expected '" << expected << "' but found '" << actual << "'");
+
+
+ str = "fred:x bill:zzz jake:12345 1234:99 6677";
+ expected = "x";
+ BOOST_CHECK_MESSAGE(Str::extract_data_member_value(str,"fred:",actual)," failed");
+ BOOST_CHECK_MESSAGE(expected == actual,"expected '" << expected << "' but found '" << actual << "'");
+
+ expected = "zzz";
+ BOOST_CHECK_MESSAGE(Str::extract_data_member_value(str,"bill:",actual)," failed");
+ BOOST_CHECK_MESSAGE(expected == actual,"expected '" << expected << "' but found '" << actual << "'");
+
+ expected = "12345";
+ BOOST_CHECK_MESSAGE(Str::extract_data_member_value(str,"jake:",actual)," failed");
+ BOOST_CHECK_MESSAGE(expected == actual,"expected '" << expected << "' but found '" << actual << "'");
+
+ expected = "99";
+ BOOST_CHECK_MESSAGE(Str::extract_data_member_value(str,"1234:",actual)," failed");
+ BOOST_CHECK_MESSAGE(expected == actual,"expected '" << expected << "' but found '" << actual << "'");
+
+ expected = "77";
+ BOOST_CHECK_MESSAGE(Str::extract_data_member_value(str,"66",actual)," failed");
+ BOOST_CHECK_MESSAGE(expected == actual,"expected '" << expected << "' but found '" << actual << "'");
+}
+
+
+std::string toString(const std::vector<std::string>& c)
+{
+ std::stringstream ss;
+ std::copy (c.begin(), c.end(), std::ostream_iterator <std::string> (ss, ", "));
+ return ss.str();
+}
+
+BOOST_AUTO_TEST_CASE( test_str_less_greater)
+{
+ cout << "ACore:: ...test_str_less_greater\n";
+
+ std::vector<std::string> expected;
+ expected.push_back("a1");
+ expected.push_back("A2");
+ expected.push_back("b1");
+ expected.push_back("B2");
+ expected.push_back("c");
+
+ std::vector<std::string> expectedGreater;
+ expectedGreater.push_back("c");
+ expectedGreater.push_back("B2");
+ expectedGreater.push_back("b1");
+ expectedGreater.push_back("A2");
+ expectedGreater.push_back("a1");
+
+ std::vector<std::string> vec;
+ vec.push_back("c");
+ vec.push_back("A2");
+ vec.push_back("a1");
+ vec.push_back("b1");
+ vec.push_back("B2");
+
+ std::sort(vec.begin(),vec.end(),Str::caseInsLess);
+ BOOST_REQUIRE_MESSAGE( vec == expected,"expected " << toString(expected) << " but found " << toString(vec) );
+
+ std::sort(vec.begin(),vec.end(),Str::caseInsGreater);
+ BOOST_REQUIRE_MESSAGE( vec == expectedGreater,"expected " << toString(expectedGreater) << " but found " << toString(vec) );
+
+ // --------------------------------------------------------------------
+
+ expected.clear();
+ expected.push_back("a");
+ expected.push_back("A");
+ expected.push_back("b");
+ expected.push_back("B");
+ expected.push_back("c");
+
+ expectedGreater.clear();
+ expectedGreater.push_back("c");
+ expectedGreater.push_back("B");
+ expectedGreater.push_back("b");
+ expectedGreater.push_back("A");
+ expectedGreater.push_back("a");
+
+ vec.clear();
+ vec.push_back("c");
+ vec.push_back("B");
+ vec.push_back("A");
+ vec.push_back("b");
+ vec.push_back("a");
+
+ std::sort(vec.begin(),vec.end(),Str::caseInsLess);
+ BOOST_REQUIRE_MESSAGE( vec == expected,"expected " << toString(expected) << " but found " << toString(vec) );
+
+ std::sort(vec.begin(),vec.end(),Str::caseInsGreater);
+ BOOST_REQUIRE_MESSAGE( vec == expectedGreater,"expected " << toString(expectedGreater) << " but found " << toString(vec) );
+
+ // --------------------------------------------------------------------
+
+ expected.clear();
+ expected.push_back("1234");
+ expected.push_back("baSE");
+ expected.push_back("Base");
+ expected.push_back("case");
+ expected.push_back("CaSe");
+ expected.push_back("suite");
+ expected.push_back("SUITE");
+
+ expectedGreater.clear();
+ expectedGreater.push_back("SUITE");
+ expectedGreater.push_back("suite");
+ expectedGreater.push_back("CaSe");
+ expectedGreater.push_back("case");
+ expectedGreater.push_back("Base");
+ expectedGreater.push_back("baSE");
+ expectedGreater.push_back("1234");
+
+ vec.clear();
+ vec.push_back("suite");
+ vec.push_back("SUITE");
+ vec.push_back("baSE");
+ vec.push_back("Base");
+ vec.push_back("case");
+ vec.push_back("CaSe");
+ vec.push_back("1234");
+
+ std::sort(vec.begin(),vec.end(),Str::caseInsLess);
+ BOOST_REQUIRE_MESSAGE( vec == expected,"expected " << toString(expected) << " but found " << toString(vec) );
+
+ std::sort(vec.begin(),vec.end(),Str::caseInsGreater);
+ BOOST_REQUIRE_MESSAGE( vec == expectedGreater,"expected " << toString(expectedGreater) << " but found " << toString(vec) );
+}
+
+
+//// ==============================================================
+//// Timing to find the fastest looping
+//// ==============================================================
+//class Fred {
+//public:
+// Fred(int i = 0) : i_(i) { /*std::cout << "Fred constructor\n"*/;}
+// Fred(const Fred& rhs) : i_(rhs.i_) { /*std::cout << "Fred copy constructor\n";*/ }
+// Fred& operator=(const Fred& rhs) { /*std::cout << "assignment operator\n";*/ i_ = rhs.i_; return *this;}
+// ~Fred() { /*std::cout << "Fred destructor\n";*/}
+//
+// void inc() { i_++;}
+//private:
+// int i_;
+//};
+//
+//BOOST_AUTO_TEST_CASE( test_loop )
+//{
+// // DEBUG release shows BOOST_FOREACH has worst perf, however in release mode its par with the fastest.
+// size_t vecSize = 20000000;
+// std::vector<Fred> vec;
+// vec.reserve(vecSize);
+// for (size_t i = 0; i < vecSize ; i++) { vec.push_back(Fred(i));}
+//
+// boost::timer timer; // measures CPU, replace with cpu_timer with boost > 1.51, measures cpu & elapsed
+// BOOST_FOREACH(Fred& fred, vec) { fred.inc(); }
+// cout << "Time: BOOST_FOREACH(Fred& fred, vec) { fred.inc(); } " << timer.elapsed() << "\n";
+//
+// timer.restart();
+// std::for_each(vec.begin(),vec.end(),boost::bind(&Fred::inc,_1) );
+// cout << "Time: std::for_each(vec.begin(),vec.end(),boost::bind(&Fred::inc,_1) ); " << timer.elapsed() << "\n";
+//
+// timer.restart();
+// std::vector<Fred>::iterator theEnd = vec.end();
+// for (std::vector<Fred>::iterator i = vec.begin(); i < theEnd ; i++) { (*i).inc(); }
+// cout << "Time: for (std::vector<Fred>::iterator i = vec.begin(); i < theEnd ; i++) { (*i).inc(); } " << timer.elapsed() << "\n";
+//
+// timer.restart();
+// std::for_each(vec.begin(),vec.end(),std::mem_fun_ref(&Fred::inc) );
+// cout << "Time: std::for_each(vec.begin();vec.end(),std::mem_fun_ref(&Fred::inc)) " << timer.elapsed() << "\n";
+//
+// timer.restart();
+// size_t theSize = vec.size();
+// for (size_t i = 0; i < theSize ; i++) { vec[i].inc(); }
+// cout << "Time: for (size_t i = 0; i < theSize ; i++) { vec[i].inc(); } " << timer.elapsed() << "\n";
+//}
+
+
+/// ==============================================================
+/// Timing to find the fastest conversion from string to int
+/// ==============================================================
+//static void methodX( const std::string& str,
+// std::vector<std::string>& stringRes,
+// std::vector<int>& numberRes)
+//{
+// // 0.81
+// // for bad conversion istringstream seems to return 0, hence add guard
+// if ( str.find_first_of( Str::NUMERIC(), 0 ) != std::string::npos ) {
+// int number = 0;
+// std::istringstream ( str ) >> number;
+// numberRes.push_back( number );
+// }
+// else {
+// stringRes.push_back( str );
+// }
+//}
+//
+//
+//static void method1( const std::string& str,
+// std::vector<std::string>& stringRes,
+// std::vector<int>& numberRes)
+//{
+// // 12.2
+// try {
+// int number = boost::lexical_cast< int >( str );
+// numberRes.push_back( number );
+// }
+// catch ( boost::bad_lexical_cast& ) {
+// stringRes.push_back( str );
+// }
+//}
+//
+//static void method2( const std::string& str,
+// std::vector<std::string>& stringRes,
+// std::vector<int>& numberRes)
+//{
+// // 0.6
+// if ( str.find_first_of( Str::NUMERIC(), 0 ) != std::string::npos ) {
+// try {
+// int number = boost::lexical_cast< int >( str );
+// numberRes.push_back( number );
+// }
+// catch ( boost::bad_lexical_cast& ) {
+// stringRes.push_back( str );
+// }
+// }
+// else {
+// stringRes.push_back( str );
+// }
+//}
+//
+//static void method3( const std::string& str,
+// std::vector<std::string>& stringRes,
+// std::vector<int>& numberRes)
+//{
+// // 0.14
+// // atoi return 0 for errors,
+// int number = atoi(str.c_str()); //does not handle errors
+// if (number == 0 && str.size() != 1) {
+// stringRes.push_back( str );
+// }
+// else {
+// numberRes.push_back( number );
+// }
+//}
+//
+//
+//BOOST_AUTO_TEST_CASE( test_lexical_cast_perf )
+//{
+// cout << "ACore:: ...test_string_to_int_conversion\n";
+//
+// size_t the_size = 1000000;
+// std::vector<std::string> stringTokens;
+// std::vector<std::string> numberTokens;
+// std::vector<int> expectedNumberRes;
+// for(size_t i=0; i < the_size; i++) { stringTokens.push_back("astring");}
+// for(size_t i=0; i < the_size; i++) {
+// numberTokens.push_back(boost::lexical_cast<string>(i));
+// expectedNumberRes.push_back(i);
+// }
+//
+// std::vector<std::string> stringRes; stringTokens.reserve(stringTokens.size());
+// std::vector<int> numberRes; numberRes.reserve(expectedNumberRes.size());
+//
+// {
+// boost::timer timer; // measures CPU, replace with cpu_timer with boost > 1.51, measures cpu & elapsed
+// for(size_t i =0; i < stringTokens.size(); i++) {
+// method1(stringTokens[i], stringRes, numberRes );
+// }
+// for(size_t i =0; i < numberTokens.size(); i++) {
+// method1(numberTokens[i], stringRes, numberRes );
+// }
+// cout << "Time for method1 elapsed time = " << timer.elapsed() << "\n";
+// BOOST_CHECK_MESSAGE(numberRes == expectedNumberRes," method 1 wrong");
+// BOOST_CHECK_MESSAGE(stringTokens == stringRes,"method 1 wrong");
+// numberRes.clear();
+// stringRes.clear();
+// }
+//
+// {
+// boost::timer timer; // measures CPU, replace with cpu_timer with boost > 1.51, measures cpu & elapsed
+// for(size_t i =0; i < stringTokens.size(); i++) {
+// methodX(stringTokens[i], stringRes, numberRes );
+// }
+// for(size_t i =0; i < numberTokens.size(); i++) {
+// methodX(numberTokens[i], stringRes, numberRes );
+// }
+// cout << "Time for methodX elapsed time = " << timer.elapsed() << "\n";
+// BOOST_CHECK_MESSAGE(numberRes == expectedNumberRes," method X wrong");
+// BOOST_CHECK_MESSAGE(stringTokens == stringRes,"method X wrong");
+// numberRes.clear();
+// stringRes.clear();
+// }
+//
+// {
+// boost::timer timer; // measures CPU, replace with cpu_timer with boost > 1.51, measures cpu & elapsed
+// for(size_t i =0; i < stringTokens.size(); i++) {
+// method2(stringTokens[i], stringRes, numberRes );
+// }
+// for(size_t i =0; i < numberTokens.size(); i++) {
+// method2(numberTokens[i], stringRes, numberRes );
+// }
+// cout << "Time for method2 elapsed time = " << timer.elapsed() << "\n";
+// BOOST_CHECK_MESSAGE(numberRes == expectedNumberRes,"method 2 wrong");
+// BOOST_CHECK_MESSAGE(stringTokens == stringRes,"method 2 wrong");
+// numberRes.clear();
+// stringRes.clear();
+// }
+//
+// {
+// boost::timer timer; // measures CPU, replace with cpu_timer with boost > 1.51, measures cpu & elapsed
+// for(size_t i =0; i < stringTokens.size(); i++) {
+// method3(stringTokens[i], stringRes, numberRes );
+// }
+// for(size_t i =0; i < numberTokens.size(); i++) {
+// method3(numberTokens[i], stringRes, numberRes );
+// }
+// cout << "Time for method3 elapsed time = " << timer.elapsed() << "\n";
+// BOOST_CHECK_MESSAGE(numberRes == expectedNumberRes," method3 wrong numberRes.size()=" << numberRes.size() << " expected size = " << expectedNumberRes.size());
+// BOOST_CHECK_MESSAGE(stringTokens == stringRes," method3 wrong stringRes.size()=" << stringRes.size() << " expected size = " << stringTokens.size());
+// numberRes.clear();
+// stringRes.clear();
+// }
+//}
+
+//BOOST_AUTO_TEST_CASE( test_int_to_str_perf )
+//{
+// cout << "ACore:: ...test_int_to_str_perf\n";
+//
+// // Lexical_cast is approx twice as fast as using streams
+// // time for ostream = 0.97
+// // time for lexical_cast = 0.45
+//
+// const int the_size = 1000000;
+// {
+// boost::timer timer; // measures CPU, replace with cpu_timer with boost > 1.51, measures cpu & elapsed
+// for(size_t i =0; i < the_size; i++) {
+// std::ostringstream st;
+// st << i;
+// std::string s = st.str();
+// }
+// cout << "Time for int to string using ostringstream elapsed time = " << timer.elapsed() << "\n";
+// }
+//
+//
+// {
+// boost::timer timer; // measures CPU, replace with cpu_timer with boost > 1.51, measures cpu & elapsed
+// for(size_t i =0; i < the_size; i++) {
+// std::string s = boost::lexical_cast<std::string>(i);
+// }
+// cout << "Time for int to string using boost::lexical_cast elapsed time = " << timer.elapsed() << "\n";
+// }
+//}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ACore/test/TestTimeSeries.cpp b/ACore/test/TestTimeSeries.cpp
new file mode 100644
index 0000000..3296532
--- /dev/null
+++ b/ACore/test/TestTimeSeries.cpp
@@ -0,0 +1,676 @@
+//============================================================================
+// Name : Request
+// Author : Avi
+// Revision : $Revision: #32 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/date_time/posix_time/time_formatters.hpp>
+
+#include <string>
+#include <iostream>
+#include <fstream>
+#include "TimeSeries.hpp"
+#include "Calendar.hpp"
+#include "Str.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::posix_time;
+using namespace boost::gregorian;
+
+using namespace boost;
+
+BOOST_AUTO_TEST_SUITE( CoreTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_time_series_min_max_time_slots )
+{
+ cout << "ACore:: ...test_time_series_min_max_time_slots\n";
+
+ TimeSlot the_min;
+ TimeSlot the_max;
+
+ TimeSeries a(9,0,true);
+ a.min_max_time_slots(the_min,the_max);
+ BOOST_CHECK_MESSAGE( the_min == TimeSlot(9,0),"Max min time slot failed");
+ BOOST_CHECK_MESSAGE( the_max == TimeSlot(9,0),"Max min time slot failed");
+
+ TimeSeries b(TimeSlot(10,12),false);
+ b.min_max_time_slots(the_min,the_max);
+ BOOST_CHECK_MESSAGE( the_min == TimeSlot(9,0),"Max min time slot failed");
+ BOOST_CHECK_MESSAGE( the_max == TimeSlot(10,12),"Max min time slot failed");
+
+ TimeSeries c(TimeSlot(0,10), TimeSlot(10,13), TimeSlot(0,1));
+ c.min_max_time_slots(the_min,the_max);
+ BOOST_CHECK_MESSAGE( the_min == TimeSlot(0,10),"Max min time slot failed");
+ BOOST_CHECK_MESSAGE( the_max == TimeSlot(10,13),"Max min time slot failed");
+
+ TimeSeries x;
+ x.min_max_time_slots(the_min,the_max);
+ BOOST_CHECK_MESSAGE( the_min == TimeSlot(),"Max min time slot failed");
+ BOOST_CHECK_MESSAGE( the_max == TimeSlot(10,13),"Max min time slot failed");
+
+}
+
+
+BOOST_AUTO_TEST_CASE( test_time_series_constrcution )
+{
+ cout << "ACore:: ...test_time_series_constrcution\n";
+
+ {
+ TimeSeries x;
+ TimeSeries y;
+ BOOST_CHECK_MESSAGE( x == y,"Equality operator expected to succeed");
+
+ TimeSeries a(10,12,true);
+ TimeSeries b(10,12,true);
+ BOOST_CHECK_MESSAGE( a == b,"Equality operator expected to succeed");
+
+ TimeSeries c(10,12,false);
+ TimeSeries d(10,12,false);
+ BOOST_CHECK_MESSAGE( c == d,"Equality operator expected to succeed");
+
+ TimeSeries e(TimeSlot(14,59),false);
+ TimeSeries f(TimeSlot(14,59),false);
+ BOOST_CHECK_MESSAGE( e == f,"Equality operator expected to succeed");
+
+ TimeSeries g(TimeSlot(0,10), TimeSlot(10,4), TimeSlot(0,1));
+ TimeSeries h(TimeSlot(0,10), TimeSlot(10,4), TimeSlot(0,1));
+ BOOST_CHECK_MESSAGE( g == h,"Equality operator expected to succeed");
+ }
+ {
+ TimeSeries a(10,12,false);
+ TimeSeries b(10,12,true);
+ BOOST_CHECK_MESSAGE( a != b,"Equality operator expected to fail");
+
+ TimeSeries c(10,13,false);
+ TimeSeries d(10,12,false);
+ BOOST_CHECK_MESSAGE( c != d,"Equality operator expected to fail");
+
+ TimeSeries e(TimeSlot(14,59),false);
+ TimeSeries f(TimeSlot(14,10),false);
+ BOOST_CHECK_MESSAGE( e != f,"Equality operator expected to fail");
+
+ TimeSeries g(TimeSlot(0,10), TimeSlot(10,4), TimeSlot(0,1), true);
+ TimeSeries h(TimeSlot(0,10), TimeSlot(10,4), TimeSlot(0,1), false);
+ BOOST_CHECK_MESSAGE( g != h,"Equality operator expected to fail");
+ }
+
+ /// Basic test for time series of getters and setters
+ TimeSeries timeSeries(TimeSlot(0,1), TimeSlot(0,4), TimeSlot(0,1));
+ BOOST_CHECK_MESSAGE(timeSeries.hasIncrement(),"expected increment");
+ std::string errMsg; BOOST_CHECK_MESSAGE(timeSeries.checkInvariants(errMsg),errMsg);
+
+ TimeSeries another = timeSeries;
+ BOOST_CHECK_MESSAGE(another == timeSeries,"copy constructor failed for TimeSeries ");
+ BOOST_CHECK_MESSAGE(another.checkInvariants(errMsg),errMsg);
+ BOOST_CHECK_MESSAGE(timeSeries.checkInvariants(errMsg),errMsg);
+
+ TimeSeries timeSeries2(TimeSlot(0,1), TimeSlot(0,4), TimeSlot(0,1));
+ BOOST_CHECK_MESSAGE(timeSeries2.checkInvariants(errMsg),errMsg);
+ another = timeSeries2;
+ BOOST_CHECK_MESSAGE(another == timeSeries2,"assignment operator failed for TimeSeries ");
+ BOOST_CHECK_MESSAGE(another.checkInvariants(errMsg),errMsg);
+
+ TimeSeries timeSeries3(TimeSlot(0,1));
+ BOOST_CHECK_MESSAGE(timeSeries3.checkInvariants(errMsg),errMsg);
+}
+
+BOOST_AUTO_TEST_CASE( test_time_series )
+{
+ cout << "ACore:: ...test_time_series\n";
+
+ /// Basic test for time series of getters and setters
+ TimeSeries timeSeries(TimeSlot(0,1), TimeSlot(0,4), TimeSlot(0,1));
+ BOOST_CHECK_MESSAGE(timeSeries.hasIncrement(),"expected increment");
+
+ std::string expected = "00:01:00";
+ std::string actual = to_simple_string(timeSeries.start().duration());
+ BOOST_CHECK_MESSAGE(expected == actual," expected " << expected << " but found " << actual );
+
+ expected = "00:04:00";
+ actual = to_simple_string(timeSeries.finish().duration());
+ BOOST_CHECK_MESSAGE(expected == actual," expected " << expected << " but found " << actual );
+
+ expected = "00:01:00";
+ actual = to_simple_string(timeSeries.incr().duration());
+ BOOST_CHECK_MESSAGE(expected == actual," expected " << expected << " but found " << actual );
+
+
+ TimeSeries timeSeries2(TimeSlot(0,1));
+ BOOST_CHECK_MESSAGE(!timeSeries2.hasIncrement(),"Not expecting time series");
+}
+
+BOOST_AUTO_TEST_CASE( test_time_series_increment_real )
+{
+ cout << "ACore:: ...test_time_series_increment_real\n";
+
+ // Test time series with a calendar, we update calendar then
+ // test time series isFree(), and checkForRequeue
+ Calendar c;
+ c.init(ptime(date(2010,2,10), minutes(0)), Calendar::REAL);
+
+
+ // Create a test when we can match a time series. Need to sync hour with suite time
+ // at hour 1, suite time should also be 01:00, for test to work
+ //
+ // Create the time series: start 10:00
+ // finish 20:00
+ // incr 1:00
+ TimeSeries timeSeries(TimeSlot(10,0), TimeSlot(20,0), TimeSlot(1,0), true/* relative */);
+ TimeSeries timeSeries2(TimeSlot(11,0), TimeSlot(15,0), TimeSlot(1,0), true/* relative */);
+ TimeSeries timeSeries3(TimeSlot(15,0), true/* relative */);
+
+ TimeSlot t1_min, t1_max,t2_min,t2_max,t3_min,t3_max;
+ timeSeries.min_max_time_slots(t1_min, t1_max);
+ timeSeries2.min_max_time_slots(t2_min, t2_max);
+ timeSeries3.min_max_time_slots(t3_min, t3_max);
+ BOOST_CHECK_MESSAGE(t1_min == TimeSlot(10,0) && t1_max == TimeSlot(20,0),"Not as expected");
+ BOOST_CHECK_MESSAGE(t2_min == TimeSlot(11,0) && t2_max == TimeSlot(15,0),"Not as expected");
+ BOOST_CHECK_MESSAGE(t3_min == TimeSlot(15,0) && t3_max == TimeSlot(15,0),"Not as expected");
+
+ // Follow normal process
+ timeSeries.reset( c );
+ timeSeries2.reset( c );
+ timeSeries3.reset( c );
+
+ for(int hour=1; hour < 24; hour++) {
+ // Update calendar every hour, then see we can match time series, *RELATIVE* to suite start
+ c.update( time_duration( hours(1) ) );
+ timeSeries.calendarChanged( c );
+ timeSeries2.calendarChanged( c );
+ timeSeries3.calendarChanged( c );
+
+// cerr << "hour = " << hour << " calendar_duration " << to_simple_string(timeSeries.duration(c))
+// << " timeSeries=" << timeSeries.toString() << " timeSeries2=" << timeSeries2.toString() << " timeSeries3=" << timeSeries3.toString() << "\n";
+ if (hour < timeSeries.start().hour()) {
+ BOOST_CHECK_MESSAGE(timeSeries.checkForRequeue(c,t1_min,t1_max)," Time series " << timeSeries.toString() << "checkForRequeue should pass at " << hour );
+ BOOST_CHECK_MESSAGE(!timeSeries.isFree(c),"Time series " << timeSeries.toString() << " should NOT be free at hour " << hour );
+ }
+ else if (hour >= timeSeries.start().hour() && hour <= timeSeries.finish().hour()) {
+ BOOST_CHECK_MESSAGE(timeSeries.isFree(c),"Time series " << timeSeries.toString() << " should be free at hour " << hour );
+
+ /// At the last hour checkForRequeue should return false; This ensures that value will
+ /// not get incremented and so, should leave node in the complete state.
+ if ( hour < timeSeries.finish().hour()) {
+ BOOST_CHECK_MESSAGE(timeSeries.checkForRequeue(c,t1_min,t1_max),"Time series " << timeSeries.toString() << " checkForRequeue should be free at hour " << hour );
+ }
+ else {
+ BOOST_CHECK_MESSAGE(!timeSeries.checkForRequeue(c,t1_min,t1_max),"Time series " << timeSeries.toString() << "checkForRequeue should Not free at hour " << hour );
+ }
+ }
+ else {
+ BOOST_CHECK_MESSAGE(!timeSeries.isFree(c),"Time series " << timeSeries.toString() << " should NOT be free at hour " << hour );
+ BOOST_CHECK_MESSAGE(!timeSeries.checkForRequeue(c,t1_min,t1_max)," Time series " << timeSeries.toString() << " should fail at " << hour );
+ }
+
+
+ if (hour < timeSeries2.start().hour()) {
+ BOOST_CHECK_MESSAGE(timeSeries2.checkForRequeue(c,t1_min,t1_max)," Time series " << timeSeries2.toString() << "checkForRequeue should pass at " << hour );
+ BOOST_CHECK_MESSAGE(!timeSeries2.isFree(c),"Time series " << timeSeries2.toString() << " should NOT be free at hour " << hour );
+ }
+ else if (hour >= timeSeries2.start().hour() && hour <=timeSeries2.finish().hour()) {
+ BOOST_CHECK_MESSAGE(timeSeries2.isFree(c),"Time series " << timeSeries2.toString() << " should be free at hour " << hour );
+
+ /// At the last hour checkForRequeue should return false;
+ if ( hour < timeSeries2.finish().hour()) {
+ BOOST_CHECK_MESSAGE(timeSeries2.checkForRequeue(c,t2_min,t2_max),"Time series " << timeSeries2.toString() << " checkForRequeue should be free at hour " << hour );
+ }
+ else {
+ BOOST_CHECK_MESSAGE(!timeSeries2.checkForRequeue(c,t2_min,t2_max),"Time series " << timeSeries2.toString() << "checkForRequeue should Not free at hour " << hour );
+ }
+ }
+ else {
+ BOOST_CHECK_MESSAGE(!timeSeries2.isFree(c),"Time series " << timeSeries2.toString() << " not be free at hour " << hour );
+ BOOST_CHECK_MESSAGE(!timeSeries2.checkForRequeue(c,t2_min,t2_max)," Time series " << timeSeries2.toString() << " should fail at " << hour );
+ }
+
+
+ if (hour == timeSeries3.start().hour() ) {
+ BOOST_CHECK_MESSAGE(timeSeries3.isFree(c),"Time series " << timeSeries3.toString() << " should be free at hour " << hour );
+ }
+ else if (hour < timeSeries3.start().hour()) {
+ BOOST_CHECK_MESSAGE(!timeSeries3.isFree(c),"Time series " << timeSeries3.toString() << " isFree should fail at hour " << hour );
+ }
+ else if (hour > timeSeries3.start().hour()) {
+ BOOST_CHECK_MESSAGE(!timeSeries3.isFree(c),"Time series " << timeSeries3.toString() << " is Free should fail at hour " << hour );
+ }
+ BOOST_CHECK_MESSAGE(!timeSeries3.checkForRequeue(c,t3_min,t3_max)," Time series " << timeSeries3.toString() << " checkForRequeue should fail at " << hour );
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_time_series_requeueable_and_compute_next_time_slot )
+{
+ cout << "ACore:: ...test_time_series_requeueable_and_compute_next_time_slot\n";
+
+ // Test time series with a calendar, we update calendar then
+ // test time series requeueable(), and compute_next_time_slot
+ // This are used with the WHY command
+ Calendar c;
+ c.init(ptime(date(2010,2,10), minutes(0)), Calendar::REAL);
+
+
+ // Create a test when we can match a time series. Need to sync hour with suite time
+ // at hour 1, suite time should also be 01:00, for test to work
+ //
+ // Create the time series: start 10:00
+ // finish 20:00
+ // incr 1:00
+ TimeSeries timeSeries(TimeSlot(10,0), TimeSlot(20,0), TimeSlot(1,0), true/* relative */);
+ TimeSeries timeSeries2(TimeSlot(11,0), TimeSlot(15,0), TimeSlot(1,0), true/* relative */);
+ TimeSeries timeSeries3(TimeSlot(15,0), true/* relative */);
+
+ for(int hour=1; hour < 24; hour++) {
+ // Update calendar every hour, then see we can match time series,
+ c.update( time_duration( hours(1) ) );
+ timeSeries.calendarChanged( c );
+ timeSeries2.calendarChanged( c );
+ timeSeries3.calendarChanged( c );
+
+// cerr << "hour = " << hour << " calendar_duration " << to_simple_string(timeSeries.duration(c))
+// << " timeSeries=" << timeSeries.toString() << " timeSeries2=" << timeSeries2.toString() << " timeSeries3=" << timeSeries3.toString() << "\n";
+ if (hour < timeSeries.start().hour()) {
+ TimeSlot next_time_slot = timeSeries.compute_next_time_slot(c);
+ TimeSlot expected(10,0);
+ BOOST_CHECK_MESSAGE(next_time_slot ==expected," Time series " << timeSeries.toString() << " at " << hour << " expected next time slot at " << expected.toString() << " but found " << next_time_slot.toString());
+ BOOST_CHECK_MESSAGE(timeSeries.requeueable(c),"Time series " << timeSeries.toString() << " should be requeueable at hour " << hour );
+ }
+ else if (hour == timeSeries.start().hour() ) {
+ TimeSlot next_time_slot = timeSeries.compute_next_time_slot(c);
+ TimeSlot expected(11,0);
+ BOOST_CHECK_MESSAGE(next_time_slot == expected," Time series " << timeSeries.toString() << " at " << hour << " expected next time slot at " << expected.toString() << " but found " << next_time_slot.toString());
+ BOOST_CHECK_MESSAGE(timeSeries.requeueable(c),"Time series " << timeSeries.toString() << " should be requeueable at hour " << hour );
+ }
+ else if (hour > timeSeries.start().hour() && hour < timeSeries.finish().hour()) {
+ TimeSlot next_time_slot = timeSeries.compute_next_time_slot(c);
+ TimeSlot expected(hour+1,0);
+ BOOST_CHECK_MESSAGE(next_time_slot == expected," Time series " << timeSeries.toString() << " at " << hour << " expected next time slot at " << expected.toString() << " but found " << next_time_slot.toString());
+ BOOST_CHECK_MESSAGE(timeSeries.requeueable(c),"Time series " << timeSeries.toString() << " should be requeueable at hour " << hour );
+ }
+ else if (hour == timeSeries.finish().hour()) {
+ TimeSlot next_time_slot = timeSeries.compute_next_time_slot(c);
+ BOOST_CHECK_MESSAGE(next_time_slot.isNULL()," Time series " << timeSeries.toString() << " at " << hour << " expected next time slot to be NULL");
+ BOOST_CHECK_MESSAGE(!timeSeries.requeueable(c),"Time series " << timeSeries.toString() << " should NOT be requeueable at hour " << hour );
+ }
+ else if (hour > timeSeries.finish().hour()) {
+ TimeSlot next_time_slot = timeSeries.compute_next_time_slot(c);
+ BOOST_CHECK_MESSAGE(next_time_slot.isNULL()," Time series " << timeSeries.toString() << " at " << hour << " expected next time slot to be NULL");
+ BOOST_CHECK_MESSAGE(!timeSeries.requeueable(c),"Time series " << timeSeries.toString() << " should NOT be requeueable at hour " << hour );
+ }
+
+
+ if (hour < timeSeries2.start().hour()) {
+ TimeSlot next_time_slot = timeSeries2.compute_next_time_slot(c);
+ TimeSlot expected(11,0);
+ BOOST_CHECK_MESSAGE(next_time_slot ==expected," Time series " << timeSeries2.toString() << " at " << hour << " expected next time slot at " << expected.toString() << " but found " << next_time_slot.toString());
+ BOOST_CHECK_MESSAGE(timeSeries2.requeueable(c),"Time series " << timeSeries2.toString() << " should be requeueable at hour " << hour );
+ }
+ else if (hour == timeSeries2.start().hour() ) {
+ TimeSlot next_time_slot = timeSeries2.compute_next_time_slot(c);
+ TimeSlot expected(12,0);
+ BOOST_CHECK_MESSAGE(next_time_slot == expected," Time series " << timeSeries2.toString() << " at " << hour << " expected next time slot at " << expected.toString() << " but found " << next_time_slot.toString());
+ BOOST_CHECK_MESSAGE(timeSeries2.requeueable(c),"Time series " << timeSeries2.toString() << " should NOT be requeueable at hour " << hour );
+ }
+ else if (hour > timeSeries2.start().hour() && hour < timeSeries2.finish().hour()) {
+ TimeSlot next_time_slot = timeSeries2.compute_next_time_slot(c);
+ TimeSlot expected(hour+1,0);
+ BOOST_CHECK_MESSAGE(next_time_slot == expected," Time series " << timeSeries2.toString() << " at " << hour << " expected next time slot at " << expected.toString() << " but found " << next_time_slot.toString());
+ BOOST_CHECK_MESSAGE(timeSeries2.requeueable(c),"Time series " << timeSeries2.toString() << " should be requeueable at hour " << hour );
+ }
+ else if (hour == timeSeries2.finish().hour()) {
+ TimeSlot next_time_slot = timeSeries2.compute_next_time_slot(c);
+ BOOST_CHECK_MESSAGE(next_time_slot.isNULL()," Time series " << timeSeries2.toString() << " at " << hour << " expected next time slot to be NULL");
+ BOOST_CHECK_MESSAGE(!timeSeries2.requeueable(c),"Time series " << timeSeries2.toString() << " should NOT be requeueable at hour " << hour );
+ }
+ else if (hour > timeSeries2.finish().hour()) {
+ TimeSlot next_time_slot = timeSeries2.compute_next_time_slot(c);
+ BOOST_CHECK_MESSAGE(next_time_slot.isNULL()," Time series " << timeSeries2.toString() << " at " << hour << " expected next time slot to be NULL");
+ BOOST_CHECK_MESSAGE(!timeSeries2.requeueable(c),"Time series " << timeSeries2.toString() << " should NOT be requeueable at hour " << hour );
+ }
+
+
+ if (hour < timeSeries3.start().hour()) {
+ TimeSlot next_time_slot = timeSeries3.compute_next_time_slot(c);
+ TimeSlot expected(15,0);
+ BOOST_CHECK_MESSAGE(next_time_slot ==expected," Time series " << timeSeries3.toString() << " at " << hour << " expected next time slot at " << expected.toString() << " but found " << next_time_slot.toString());
+ BOOST_CHECK_MESSAGE(timeSeries3.requeueable(c),"Time series " << timeSeries3.toString() << " should be requeueable at hour " << hour );
+ }
+ else if (hour == timeSeries3.start().hour() ) {
+ TimeSlot next_time_slot = timeSeries3.compute_next_time_slot(c);
+ BOOST_CHECK_MESSAGE(next_time_slot.isNULL()," Time series " << timeSeries3.toString() << " at " << hour << " expected next time slot to be NULL");
+ BOOST_CHECK_MESSAGE(!timeSeries3.requeueable(c),"Time series " << timeSeries3.toString() << " should NOT be requeueable at hour " << hour );
+ }
+ else if (hour > timeSeries3.start().hour()) {
+ TimeSlot next_time_slot = timeSeries3.compute_next_time_slot(c);
+ BOOST_CHECK_MESSAGE(next_time_slot.isNULL()," Time series " << timeSeries3.toString() << " at " << hour << " expected next time slot to be NULL");
+ BOOST_CHECK_MESSAGE(!timeSeries3.requeueable(c),"Time series " << timeSeries3.toString() << " should NOT be requeueable at hour " << hour );
+ }
+ }
+}
+
+
+BOOST_AUTO_TEST_CASE( test_time_series_finish_not_divisble_by_increment )
+{
+ cout << "ACore:: ...test_time_series_finish_not_divisble_by_increment\n";
+
+ // HANDLE CASE WHERE FINISH MINUTES IS NOT DIVISIBLE BY THE INCREMENT
+
+ // Test time series with a calendar, we update calendar then
+ // test time series isFree(), and checkForRequeue
+ Calendar calendar;
+ calendar.init(ptime(date(2008,10,8), hours(0) ), Calendar::REAL);
+
+ // Create a test when we can match a time series.
+ // NOTE: Finish minute is not a multiple of INCREMENT hence last valid time slot is 23:50
+ //
+ // Create the time series: start 00:00
+ // finish 23:59
+ // incr 00:10
+ TimeSeries timeSeries(TimeSlot(0,0), TimeSlot(23,59), TimeSlot(0,10), false/* relative */);
+ TimeSeries timeSeries2(TimeSlot(0,30), TimeSlot(23,59), TimeSlot(4,0), false/* relative */);
+
+ TimeSlot t1_min, t1_max,t2_min,t2_max;
+ timeSeries.min_max_time_slots(t1_min, t1_max);
+ timeSeries2.min_max_time_slots(t2_min, t2_max);
+ BOOST_CHECK_MESSAGE(t1_min == TimeSlot(0,0) && t1_max == TimeSlot(23,59),"Not as expected");
+ BOOST_CHECK_MESSAGE(t2_min == TimeSlot(0,30) && t2_max == TimeSlot(23,59),"Not as expected");
+
+ time_duration last = hours(23) + minutes(50); // last valid time is 23:50
+ time_duration last2 = hours(20) + minutes(30); // last valid time is 20:30
+
+ // follow normal process
+ timeSeries.reset(calendar);
+ timeSeries2.reset(calendar);
+
+ for(int hour=0; hour < 24; hour++) {
+ for( int minute=0; minute<60; minute++) {
+
+ calendar.update( minutes(1) );
+ timeSeries.calendarChanged(calendar);
+ timeSeries2.calendarChanged(calendar);
+
+ //cout << to_simple_string(calendar.suiteTime()) << "\n";
+
+ if (calendar.dayChanged()) {
+ BOOST_CHECK_MESSAGE(timeSeries.checkForRequeue(calendar,t1_min,t1_max)," expected " << timeSeries.toString() << " checkForRequeue to pass at " << to_simple_string(calendar.suiteTime()));
+ }
+ else if ( calendar.suiteTime().time_of_day() < timeSeries.start().duration()) {
+ BOOST_CHECK_MESSAGE(timeSeries.checkForRequeue(calendar,t1_min,t1_max)," expected " << timeSeries.toString() << " checkForRequeue to pass at " << to_simple_string(calendar.suiteTime()) );
+ }
+ else if ( calendar.suiteTime().time_of_day() >= timeSeries.start().duration() && calendar.suiteTime().time_of_day() < last ) {
+ BOOST_CHECK_MESSAGE(timeSeries.checkForRequeue(calendar,t1_min,t1_max)," expected " << timeSeries.toString() << " checkForRequeue to pass at " << to_simple_string(calendar.suiteTime()) );
+ }
+ else {
+ BOOST_CHECK_MESSAGE(!timeSeries.checkForRequeue(calendar,t1_min,t1_max)," expected " << timeSeries.toString() << " checkForRequeue to fail at " << to_simple_string(calendar.suiteTime()) );
+ }
+
+ if (calendar.dayChanged()) {
+ BOOST_CHECK_MESSAGE(timeSeries2.checkForRequeue(calendar,t2_min,t2_max)," expected " << timeSeries2.toString() << " checkForRequeue to pass at " << to_simple_string(calendar.suiteTime()));
+ }
+ else if ( calendar.suiteTime().time_of_day() < timeSeries2.start().duration()) {
+ BOOST_CHECK_MESSAGE(timeSeries2.checkForRequeue(calendar,t2_min,t2_max)," expected " << timeSeries2.toString() << " checkForRequeue to pass at " << to_simple_string(calendar.suiteTime()) );
+ }
+ else if ( calendar.suiteTime().time_of_day() >= timeSeries2.start().duration() && calendar.suiteTime().time_of_day() < last2 ) {
+ BOOST_CHECK_MESSAGE(timeSeries2.checkForRequeue(calendar,t2_min,t2_max)," expected " << timeSeries2.toString() << " checkForRequeue to pass at " << to_simple_string(calendar.suiteTime()));
+ }
+ else {
+ BOOST_CHECK_MESSAGE(!timeSeries2.checkForRequeue(calendar,t2_min,t2_max)," expected " << timeSeries2.toString() << " checkForRequeue to fail at " << to_simple_string(calendar.suiteTime()));
+ }
+
+// if (calendar.dayChanged()) {
+// timeSeries.reset(calendar);
+// timeSeries2.reset(calendar);
+// }
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_time_series_miss_time_slot )
+{
+ cout << "ACore:: ...test_time_series_miss_time_slot\n";
+
+ Calendar calendar;
+ calendar.init(ptime(date(2008,10,8), hours(10) ), Calendar::REAL);
+
+ // Create a test when we can match a time series.
+ // NOTE: Finish minute is not a multiple of INCREMENT hence last valid time slot is 23:50
+ //
+ // Create the time series: start 10:00
+ // finish 23:59
+ // incr 00:10
+ TimeSeries timeSeries(TimeSlot(10,0), TimeSlot(23,59), TimeSlot(0,10), false/* relative */);
+ timeSeries.miss_next_time_slot(); // will increment next_time_slot
+ BOOST_CHECK_MESSAGE(timeSeries.value() == TimeSlot(10,10), "miss time slot not working ");
+
+ timeSeries.miss_next_time_slot(); // will increment next_time_slot
+ BOOST_CHECK_MESSAGE(timeSeries.value() == TimeSlot(10,20), "miss time slot not working ");
+
+ // requeue time series,
+ timeSeries.requeue(calendar); // calendar time is at midnight 10:00
+ BOOST_CHECK_MESSAGE(timeSeries.value() == TimeSlot(10,10),"Expected requeue to reset time series");
+}
+
+BOOST_AUTO_TEST_CASE( test_time_series_miss_time_slot_1 )
+{
+ cout << "ACore:: ...test_time_series_miss_time_slot_1\n";
+
+ // Create calendar before time series
+ {
+ Calendar calendar;
+ calendar.init(ptime(date(2008,10,8), hours(9) ), Calendar::REAL); // 09:00
+
+ TimeSeries timeSeries(10,0, false/* relative */); // 10:00
+
+ TimeSlot t1_min, t1_max;
+ timeSeries.min_max_time_slots(t1_min, t1_max);
+ BOOST_CHECK_MESSAGE(t1_min == TimeSlot(10,0) && t1_max == TimeSlot(10,0),"Not as expected");
+
+
+ BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar), "Expected time holding at 10:00 since calendar is 09:00");
+ BOOST_CHECK_MESSAGE(!timeSeries.checkForRequeue(calendar,t1_min,t1_max), "Expected checkForRequeue to return false always");
+
+ timeSeries.miss_next_time_slot();
+ BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar), "Expected time to hold");
+ BOOST_CHECK_MESSAGE(!timeSeries.checkForRequeue(calendar,t1_min,t1_max), "Expected checkForRequeue to return false");
+
+ timeSeries.requeue(calendar);
+ BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar), "Expected time holding at 10:00 since calendar is 09:00");
+ BOOST_CHECK_MESSAGE(!timeSeries.checkForRequeue(calendar,t1_min,t1_max), "Expected checkForRequeue to return false after Requeue");
+ }
+ {
+ // Create a time after the time series
+ Calendar calendar;
+ calendar.init(ptime(date(2008,10,8), hours(11) ), Calendar::REAL); // 11:00
+
+ TimeSeries timeSeries(10,0, false/* relative */); // 10:00
+
+ TimeSlot t1_min, t1_max;
+ timeSeries.min_max_time_slots(t1_min, t1_max);
+ BOOST_CHECK_MESSAGE(t1_min == TimeSlot(10,0) && t1_max == TimeSlot(10,0),"Not as expected");
+
+
+ BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar), "Expected time NOT to be free, since calendar time is after time slot");
+ BOOST_CHECK_MESSAGE(!timeSeries.checkForRequeue(calendar,t1_min,t1_max), "Expected checkForRequeue to return false, since calendar time > slot time");
+
+ timeSeries.miss_next_time_slot();
+ BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar), "Expected time to hold");
+ BOOST_CHECK_MESSAGE(!timeSeries.checkForRequeue(calendar,t1_min,t1_max), "Expected checkForRequeue to return false");
+
+ timeSeries.requeue(calendar);
+ BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar), "Expected time to hold, since calendar time is after time slot");
+ BOOST_CHECK_MESSAGE(!timeSeries.checkForRequeue(calendar,t1_min,t1_max), "Expected checkForRequeue to return false,since calendar time is after time slot");
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_time_series_reset )
+{
+ cout << "ACore:: ...test_time_series_reset\n";
+
+
+ // Create a test when we can match a time series.
+ // NOTE: Finish minute is not a multiple of INCREMENT hence last valid time slot is 23:50
+ //
+ // Create the time series: start 10:00
+ // finish 23:59
+ // incr 00:10
+ TimeSeries timeSeries(TimeSlot(10,0), TimeSlot(23,59), TimeSlot(0,10), false/* relative */);
+ BOOST_CHECK_MESSAGE(timeSeries.value() == TimeSlot(10,0), "defaults not correct");
+
+ { // set calendar before time series start & then reset
+
+ Calendar calendar;
+ calendar.init(ptime(date(2008,10,8), hours(9) ), Calendar::REAL);
+ timeSeries.reset(calendar);
+ BOOST_CHECK_MESSAGE(timeSeries.value() == TimeSlot(10,0), "Reset should set value(next_valid_time_slot) to start." << timeSeries.dump());
+
+ timeSeries.miss_next_time_slot();
+
+ timeSeries.requeue(calendar);
+ BOOST_CHECK_MESSAGE(timeSeries.value() == TimeSlot(10,0), "requeue should set value(next_valid_time_slot) to start."<< timeSeries.dump());
+ }
+ { // set calendar at time series start & then reset
+
+ Calendar calendar;
+ calendar.init(ptime(date(2008,10,8), hours(10) ), Calendar::REAL);
+ timeSeries.reset(calendar);
+ BOOST_CHECK_MESSAGE(timeSeries.value() == TimeSlot(10,0), "Reset should set value(next_valid_time_slot) to start."<< timeSeries.dump());
+
+ timeSeries.miss_next_time_slot();
+
+ timeSeries.requeue(calendar);
+ BOOST_CHECK_MESSAGE(timeSeries.value() == TimeSlot(10,10), "requeue should set value(next_valid_time_slot) to start."<< timeSeries.dump());
+ }
+ { // set calendar after time series start & before time series end, then reset
+
+ Calendar calendar;
+ calendar.init(ptime(date(2008,10,8), hours(11) ), Calendar::REAL);
+ timeSeries.reset(calendar);
+ BOOST_CHECK_MESSAGE(timeSeries.value() == TimeSlot(11,0), "Reset should update free slot."<< timeSeries.dump());
+
+ timeSeries.miss_next_time_slot();
+
+ timeSeries.requeue(calendar);
+ BOOST_CHECK_MESSAGE(timeSeries.value() == TimeSlot(11,10), "requeue should update to first time slot."<< timeSeries.dump());
+ }
+}
+
+
+BOOST_AUTO_TEST_CASE( test_time_series_parsing )
+{
+ cout << "ACore:: ...test_time_series_parsing\n";
+
+ BOOST_CHECK_MESSAGE(TimeSeries::create("00:30") == ecf::TimeSeries(0,30), "Error ");
+ BOOST_CHECK_MESSAGE(TimeSeries::create("+00:30") == ecf::TimeSeries(0,30,true), "Error ");
+
+ ecf::TimeSlot start(0,30);
+ ecf::TimeSlot finish(21,03);
+ ecf::TimeSlot incr(1,30);
+ BOOST_CHECK_MESSAGE(TimeSeries::create("00:30 21:03 01:30") == ecf::TimeSeries(start,finish,incr), "Error");
+ BOOST_CHECK_MESSAGE(TimeSeries::create("+00:30 21:03 01:30") == ecf::TimeSeries(start,finish,incr,true), "Error");
+}
+
+BOOST_AUTO_TEST_CASE( test_time_series_state_parsing )
+{
+ cout << "ACore:: ...test_time_series_state_parsing\n";
+
+ /// extract string like
+ /// time +00:00 20:00 00:10 # this is a comment which will be ignored. index = 1
+ /// time +20:00 // index = 1
+ /// today 20:00 // index = 1
+ /// +00:00 20:00 00:10 // index = 0
+ /// +20:00 // index = 0
+ /// will throw std:runtime_error for errors
+ /// will assert if index >= lineTokens.size()
+ {
+ size_t index = 0;
+ std::string the_time = "+00:00 20:00 00:10";
+ std::vector<std::string> lineTokens;
+ Str::split(the_time,lineTokens);
+ BOOST_CHECK_MESSAGE(TimeSeries::create(index,lineTokens) == ecf::TimeSeries(TimeSlot(0,0),TimeSlot(20,0),TimeSlot(0,10),true), "Error");
+ }
+ {
+ size_t index = 0;
+ std::string the_time = "+10:10";
+ std::vector<std::string> lineTokens;
+ Str::split(the_time,lineTokens);
+ BOOST_CHECK_MESSAGE(TimeSeries::create(index,lineTokens) == ecf::TimeSeries(TimeSlot(10,10),true), "Error");
+ }
+ {
+ size_t index = 0;
+ std::string the_time = "+10:10 # free isValid:false";
+ ecf::TimeSeries expected(TimeSlot(10,10),true);
+ expected.set_isValid(false);
+
+ std::vector<std::string> lineTokens;
+ Str::split(the_time,lineTokens);
+ ecf::TimeSeries parsed_ts = TimeSeries::create(index,lineTokens,true);
+ BOOST_CHECK_MESSAGE(parsed_ts == expected,
+ "Expected \n'" << expected.toString() << expected.state_to_string(false) << "'" <<
+ " But found \n'" << parsed_ts.toString() << parsed_ts.state_to_string(false) << "'");
+ }
+ {
+ size_t index = 0;
+ std::string the_time = "+10:10 # free isValid:false nextTimeSlot/10:10 relativeDuration/00:00:00";
+ ecf::TimeSeries expected(TimeSlot(10,10),true);
+ expected.set_isValid(false);
+
+ std::vector<std::string> lineTokens;
+ Str::split(the_time,lineTokens);
+ ecf::TimeSeries parsed_ts = TimeSeries::create(index,lineTokens,true);
+ BOOST_CHECK_MESSAGE(parsed_ts == expected,
+ "Expected \n'" << expected.toString() << expected.state_to_string(false) << "'" <<
+ " But found\n'" << parsed_ts.toString() << parsed_ts.state_to_string(false) << "'");
+ }
+ {
+ // Update relative duration
+ size_t index = 0;
+ std::string the_time = "+10:10 # free isValid:false nextTimeSlot/10:10 relativeDuration/01:00:00";
+ ecf::TimeSeries expected(TimeSlot(10,10),true);
+ expected.set_isValid(false);
+
+ Calendar calendar;
+ calendar.init(ptime(date(2008,10,8), hours(0) ), Calendar::REAL);
+ calendar.update( time_duration( hours(1) ) );
+ expected.calendarChanged( calendar );
+
+ std::vector<std::string> lineTokens;
+ Str::split(the_time,lineTokens);
+ ecf::TimeSeries parsed_ts = TimeSeries::create(index,lineTokens,true);
+ BOOST_CHECK_MESSAGE(parsed_ts == expected,
+ "Expected \n'" << expected.toString() << expected.state_to_string(false) << "'" <<
+ " But found\n'" << parsed_ts.toString() << parsed_ts.state_to_string(false) << "'");
+ }
+
+ {
+ // Update nextTimeSlot, create calendar at 09:00 and increment time series.
+ std::string the_time = "09:00 12:00 01:00 # isValid:false nextTimeSlot/10:00 relativeDuration/00:00:00";
+ ecf::TimeSeries expected(TimeSlot(9,0),TimeSlot(12,0),TimeSlot(1,0),false);
+ expected.set_isValid(false);
+
+ Calendar calendar;
+ calendar.init(ptime(date(2008,10,8), hours(9) ), Calendar::REAL);
+ expected.requeue( calendar ); // this will reset isValid to true
+ expected.set_isValid(false);
+
+ std::vector<std::string> lineTokens;
+ Str::split(the_time,lineTokens);
+ size_t index = 0;
+ ecf::TimeSeries parsed_ts = TimeSeries::create(index,lineTokens,true);
+
+ BOOST_CHECK_MESSAGE(parsed_ts == expected,
+ "Expected \n'" << expected.dump() << expected.state_to_string(false) << "'" <<
+ " But found\n'" << parsed_ts.dump() << parsed_ts.state_to_string(false) << "'");
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ACore/test/TestTimeSlot.cpp b/ACore/test/TestTimeSlot.cpp
new file mode 100644
index 0000000..4db33dc
--- /dev/null
+++ b/ACore/test/TestTimeSlot.cpp
@@ -0,0 +1,109 @@
+//============================================================================
+// Name : Request
+// Author : Avi
+// Revision : $Revision: #29 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/date_time/posix_time/time_formatters.hpp>
+
+#include <string>
+#include <iostream>
+#include <fstream>
+#include "TimeSeries.hpp"
+#include "Calendar.hpp"
+#include "Str.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::posix_time;
+using namespace boost::gregorian;
+
+using namespace boost;
+
+BOOST_AUTO_TEST_SUITE( CoreTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_time_slot )
+{
+ cout << "ACore:: ...test_time_slot\n";
+
+ // test timeslot operator
+ {
+ TimeSlot x;
+ TimeSlot y;
+ BOOST_CHECK_MESSAGE( x.isNULL(),"Expected NULL");
+ BOOST_CHECK_MESSAGE( y.isNULL(),"Expected NULL");
+ BOOST_CHECK_MESSAGE( x == y,"Equality operator expected to succeed");
+ BOOST_CHECK_MESSAGE( !(x < y),"Less than operator expected to fail");
+ BOOST_CHECK_MESSAGE( !(x > y),"Greater than operator expected to fail");
+ BOOST_CHECK_MESSAGE( x <= y,"<= operator expected to succeed");
+ BOOST_CHECK_MESSAGE( x >= y,">= operator expected to succeed");
+ BOOST_CHECK_MESSAGE( y <= x,"<= operator expected to succeed");
+ BOOST_CHECK_MESSAGE( y >= x,">= operator expected to succeed");
+
+ TimeSlot a(10,12);
+ TimeSlot b(10,12);
+ BOOST_CHECK_MESSAGE( !a.isNULL(),"Expected NOT NULL");
+ BOOST_CHECK_MESSAGE( !b.isNULL(),"Expected NOT NULL");
+ BOOST_CHECK_MESSAGE( a == b,"Equality operator expected to succeed");
+ BOOST_CHECK_MESSAGE( !(a < b),"Less than operator expected to fail");
+ BOOST_CHECK_MESSAGE( !(a > b),"Greater than operator expected to fail");
+ BOOST_CHECK_MESSAGE( a <= b,"<= operator expected to succeed");
+ BOOST_CHECK_MESSAGE( a >= b,">= operator expected to succeed");
+ BOOST_CHECK_MESSAGE( b <= a,"<= operator expected to succeed");
+ BOOST_CHECK_MESSAGE( b >= a,">= operator expected to succeed");
+
+ TimeSlot c(0,0);
+ TimeSlot d(0,0);
+ BOOST_CHECK_MESSAGE( !c.isNULL(),"Expected NOT NULL");
+ BOOST_CHECK_MESSAGE( !d.isNULL(),"Expected NOT NULL");
+ BOOST_CHECK_MESSAGE( c == d,"Equality operator expected to succeed");
+ BOOST_CHECK_MESSAGE( !(c < d),"Less than operator expected to fail");
+ BOOST_CHECK_MESSAGE( !(c > d),"Greater than operator expected to fail");
+ BOOST_CHECK_MESSAGE( c <= d,"<= operator expected to succeed");
+ BOOST_CHECK_MESSAGE( c >= d,">= operator expected to succeed");
+ BOOST_CHECK_MESSAGE( d <= c,"<= operator expected to succeed");
+ BOOST_CHECK_MESSAGE( d >= c,">= operator expected to succeed");
+
+ TimeSlot a1(10,1);
+ TimeSlot b1(10,12);
+ BOOST_CHECK_MESSAGE( !a1.isNULL(),"Expected NOT NULL");
+ BOOST_CHECK_MESSAGE( !b1.isNULL(),"Expected NOT NULL");
+ BOOST_CHECK_MESSAGE( a1 != b1,"Equality operator expected to fail");
+ BOOST_CHECK_MESSAGE( a1 < b1,"Less than operator expected to succeed");
+ BOOST_CHECK_MESSAGE( !(a1 > b1),"Greater than operator expected to fail");
+ BOOST_CHECK_MESSAGE( !(a1 >= b1),">= than operator expected to fail");
+ BOOST_CHECK_MESSAGE( b1 > a1,"Greater than operator expected to succeed");
+ BOOST_CHECK_MESSAGE( b1 >= a1,">= expected to succeed");
+
+ TimeSlot xx(10,1);
+ TimeSlot yy(23,12);
+ BOOST_CHECK_MESSAGE( xx != yy,"Equality operator expected to fail");
+ BOOST_CHECK_MESSAGE( xx < yy,"Less than operator expected to succeed");
+ BOOST_CHECK_MESSAGE( xx <= yy,"<= operator expected to succeed");
+ BOOST_CHECK_MESSAGE( yy > xx,"Greater than operator expected to succeed");
+ BOOST_CHECK_MESSAGE( yy >= xx,">= operator expected to succeed");
+ BOOST_CHECK_MESSAGE( !(xx > yy),"Greater than operator expected to fail");
+ BOOST_CHECK_MESSAGE( !(xx >= yy),">= operator expected to fail");
+
+ TimeSlot x1(11,0);
+ TimeSlot y1(10,0);
+ BOOST_CHECK_MESSAGE( x1 != y1,"Equality operator expected to fail");
+ BOOST_CHECK_MESSAGE( !(x1 < y1),"Less than operator expected to fail");
+ BOOST_CHECK_MESSAGE( !(x1 <= y1),"<= operator expected to fail");
+ BOOST_CHECK_MESSAGE( x1 > y1,"Greater than operator expected to succced");
+ BOOST_CHECK_MESSAGE( x1 >= y1,">= operator expected to succced");
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ACore/test/TestVersion.cpp b/ACore/test/TestVersion.cpp
new file mode 100644
index 0000000..1eced7d
--- /dev/null
+++ b/ACore/test/TestVersion.cpp
@@ -0,0 +1,85 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #23 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <string>
+#include <iostream>
+#include <boost/test/unit_test.hpp>
+#include "Version.hpp"
+#include "boost_archive.hpp"
+#include "File.hpp"
+#include "Str.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost;
+
+BOOST_AUTO_TEST_SUITE( CoreTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_version )
+{
+ std::string desc = Version::description();
+ BOOST_CHECK_MESSAGE(!desc.empty(),"Expected version");
+ cout << "ACore:: ...test_version:" << desc << endl;
+}
+
+BOOST_AUTO_TEST_CASE( boost_serialisation_archive_version )
+{
+ cout << "ACore:: ...boost_serialisation_archive_version: " << ecf::boost_archive::version() << endl;
+ BOOST_REQUIRE_MESSAGE(ecf::boost_archive::version() != 0,"keep boost from complaining");
+}
+
+
+BOOST_AUTO_TEST_CASE( test_version_against_VERSION_cmake )
+{
+ cout << "ACore:: ...test_version_against_VERSION_cmake" << endl;
+
+ // Open the file VERSION.cmake
+ std::string version_cmake_file = File::root_source_dir() + "/VERSION.cmake";
+ std::vector<std::string> lines;
+ BOOST_REQUIRE_MESSAGE(File::splitFileIntoLines(version_cmake_file,lines,true/* impore empty lines */),"Failed to open file " << version_cmake_file);
+ BOOST_REQUIRE_MESSAGE(!lines.empty(),"File " << version_cmake_file << " does not contain version info ??");
+
+ // Expecting lines like:
+ // set( ECFLOW_RELEASE "4" )
+ // set( ECFLOW_MAJOR "0" )
+ // set( ECFLOW_MINOR "4" )
+ // set( ${PROJECT_NAME}_VERSION_STR "${ECFLOW_RELEASE}.${ECFLOW_MAJOR}.${ECFLOW_MINOR}" )
+ // Compare against VERSION
+ std::string ecflow_release,ecflow_major,ecflow_minor;
+ for(size_t i =0; i < lines.size(); ++i) {
+ std::vector<std::string> tokens;
+ Str::split(lines[i],tokens);
+
+ // expecting third token to contain version data
+ if (lines[i].find("set( ECFLOW_RELEASE") != std::string::npos && tokens.size() >= 3) {
+ ecflow_release = tokens[2];
+ Str::removeQuotes(ecflow_release);
+ }
+ if (lines[i].find("set( ECFLOW_MAJOR") != std::string::npos && tokens.size() >= 3) {
+ ecflow_major = tokens[2];
+ Str::removeQuotes(ecflow_major);
+ }
+ if (lines[i].find("set( ECFLOW_MINOR") != std::string::npos && tokens.size() >= 3) {
+ ecflow_minor = tokens[2];
+ Str::removeQuotes(ecflow_minor);
+ }
+ }
+
+ std::string extracted_version = ecflow_release + "." + ecflow_major + "." + ecflow_minor;
+
+ // The if they don't match, we have failed to regenrate and check in ecflow_version.h
+ BOOST_REQUIRE_MESSAGE(Version::raw() == extracted_version,"\n Expected " << extracted_version << " but found " << Version::raw() << ", Please regenerate file $WK/ACore/src/ecflow_version.h by calling 'sh -x $WK/cmake.sh debug'");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ACore/test/TestVersioning.cpp b/ACore/test/TestVersioning.cpp
new file mode 100644
index 0000000..608886a
--- /dev/null
+++ b/ACore/test/TestVersioning.cpp
@@ -0,0 +1,68 @@
+//============================================================================
+// Name : Request
+// Author : Avi
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <fstream>
+#include <boost/test/unit_test.hpp>
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/version.hpp>
+#include "boost/filesystem/operations.hpp"
+
+#include "TestVersioning.hpp"
+#include "Serialization.hpp"
+
+using namespace std;
+using namespace boost;
+
+BOOST_AUTO_TEST_SUITE( CoreTestSuite )
+
+// This class will create a Class X. This is serialised.
+// This class is then reloaded, with different kinds of version changes, to base version 0;
+// Note: we simulate different release of class X, by using name spaces
+// This is possible since the name space is not written.
+BOOST_AUTO_TEST_CASE( test_versioning )
+{
+ cout << "ACore:: ...test_versioning\n";
+ {
+ // write out version 0; This will be reloaded with different version of X
+ const version0::X t = version0::X(10);
+ ecf::save("version0",t);
+ }
+
+ {
+ // Version 1 adds a new data member: i.e min_
+ version_new_data_member::X t;
+ ecf::restore("version0",t);
+ BOOST_CHECK_MESSAGE(t == version_new_data_member::X(10,0),"Should be the same");
+ }
+
+ {
+ // Version 1 change data member name: from hour_ -> hours_:
+ // This required no change at all. Since serialisation relies on order.
+ version_change_dm_name::X t;
+ ecf::restore("version0",t);
+ BOOST_CHECK_MESSAGE(t == version_change_dm_name::X(10),"Should be the same");
+ }
+
+ {
+ // Version 1 change data member type: from int -> string :
+ version_change_dm_type::X t;
+ ecf::restore("version0",t);
+ BOOST_CHECK_MESSAGE(t == version_change_dm_type::X("10"),"Reading integer as string expected '10', but found string " << t.str());
+ }
+
+ // remove the generate file
+ boost::filesystem::remove("version0");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ACore/test/TestVersioning.hpp b/ACore/test/TestVersioning.hpp
new file mode 100644
index 0000000..17f7d6c
--- /dev/null
+++ b/ACore/test/TestVersioning.hpp
@@ -0,0 +1,97 @@
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+#include <boost/serialization/string.hpp>
+#include <boost/serialization/version.hpp>
+#include <boost/lexical_cast.hpp>
+#include <iostream>
+
+
+/// To simulate changing of data model over time, we will
+/// namespace's. The actual serialisation does not appears to
+/// persist the name space
+
+namespace version0 {
+class X {
+public:
+ X(int h = 0) : hour_(h) {}
+ bool operator==(const X& rhs) const { return hour_ == rhs.hour_; }
+private:
+ int hour_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int version) {
+ ar & hour_;
+ }
+};
+}
+
+namespace version_new_data_member {
+class X {
+public:
+ X(int h = 0, int m =0) : hour_(h),min_(m) {}
+ bool operator==(const X& rhs) const { return hour_ == rhs.hour_ && min_ == rhs.min_; }
+private:
+ int hour_;
+ int min_;
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int version) {
+ // When *loading* the version pertains to loaded version in the data
+ // When *saving* the version always pertains to the latest version
+ ar & hour_;
+ if (version > 0) ar & min_;
+ }
+};
+}
+BOOST_CLASS_VERSION(version_new_data_member::X, 1)
+
+namespace version_change_dm_name {
+class X {
+public:
+ X(int h = 0) : hours_(h) {}
+ bool operator==(const X& rhs) const { return hours_ == rhs.hours_; }
+private:
+ int hours_;
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int version) {
+ ar & hours_;
+ }
+};
+}
+BOOST_CLASS_VERSION(version_change_dm_name::X, 1)
+
+namespace version_change_dm_type {
+class X {
+public:
+ X(const std::string& h = "") : hour_(h) {}
+ bool operator==(const X& rhs) const { return hour_ == rhs.hour_; }
+ std::string str() const { return hour_; }
+private:
+ std::string hour_;
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int version) {
+ // When *loading* the version pertains to loaded version in the data
+ // When *saving* the version always pertains to the latest version
+ if (version == 0) {
+ // Change data member type: int(version0)--->string(version1)
+ int the_old_hour = 0;
+ ar & the_old_hour;
+ hour_ = boost::lexical_cast<std::string>(the_old_hour);
+ }
+ else {
+ ar & hour_;
+ }
+ }
+};
+}
+BOOST_CLASS_VERSION(version_change_dm_type::X, 1)
diff --git a/ACore/test/TestWhiteListFile.cpp b/ACore/test/TestWhiteListFile.cpp
new file mode 100644
index 0000000..4efdcdc
--- /dev/null
+++ b/ACore/test/TestWhiteListFile.cpp
@@ -0,0 +1,279 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #11 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <boost/test/unit_test.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/archive/tmpdir.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/foreach.hpp>
+#include "boost/progress.hpp"
+
+#include <iostream>
+#include <fstream>
+
+#include "WhiteListFile.hpp"
+#include "File.hpp"
+
+namespace fs = boost::filesystem;
+using namespace std;
+using namespace ecf;
+
+//#define DEBUG_ME 1
+
+BOOST_AUTO_TEST_SUITE( CoreTestSuite )
+
+void test_white_list_files(const std::string& directory, bool pass)
+{
+ fs::path full_path( fs::initial_path<fs::path>() );
+ full_path = fs::system_complete( fs::path( directory ) );
+
+ BOOST_CHECK(fs::exists( full_path ));
+ BOOST_CHECK(fs::is_directory( full_path ));
+
+ //std::cout << "\nIn directory: " << full_path.directory_string() << "\n\n";
+ fs::directory_iterator end_iter;
+ for ( fs::directory_iterator dir_itr( full_path ); dir_itr != end_iter; ++dir_itr )
+ {
+ try
+ {
+ fs::path relPath(directory + "/" + dir_itr->path().filename().string());
+
+ // recurse down directories
+ if ( fs::is_directory(dir_itr->status()) ) {
+ test_white_list_files(relPath.string(),pass);
+ continue;
+ }
+
+#if DEBUG_ME
+ std::cout << "......Parsing file " << relPath.string() << "\n";
+#endif
+
+ WhiteListFile theFile;
+ std::string errorMsg;
+ bool parsedOk = theFile.load(relPath.string(),false/*debug*/, errorMsg);
+ if (pass) {
+ // Test expected to pass
+ BOOST_CHECK_MESSAGE(parsedOk,"Failed to parse file " << relPath << "\n" << errorMsg);
+ }
+ else {
+ // test expected to fail
+ BOOST_CHECK_MESSAGE(!parsedOk,"Parse expected to fail for " << relPath << "\n" << errorMsg);
+#if DEBUG_ME
+ cout << "\n" << errorMsg << "\n";
+#endif
+ }
+ }
+ catch ( const std::exception & ex )
+ {
+ std::cout << dir_itr->path().filename() << " " << ex.what() << std::endl;
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_parsing_for_good_white_list_files )
+{
+ cout << "ACore:: ...test_parsing_for_good_white_list_files\n";
+
+ std::string path = File::test_data("ACore/test/data/goodWhiteListFiles","ACore");
+
+ // All the files in this directory are expected to pass
+ test_white_list_files(path, true);
+}
+
+BOOST_AUTO_TEST_CASE( test_parsing_for_bad_white_list_files )
+{
+ cout << "ACore:: ...test_parsing_for_bad_white_list_files\n";
+
+ std::string path = File::test_data("ACore/test/data/badWhiteListFiles","ACore");
+
+ // All the files in this directory are expected to fail
+ test_white_list_files(path, false);
+}
+
+BOOST_AUTO_TEST_CASE( test_white_list_empty_file )
+{
+ cout << "ACore:: ...test_white_list_empty_file\n";
+
+ std::string path = File::test_data("ACore/test/data/goodWhiteListFiles/empty.lists","ACore");
+
+ WhiteListFile theFile;
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE(theFile.load(path,false, errorMsg),"Failed to parse file " << path << "\n" << errorMsg);
+
+ BOOST_REQUIRE_MESSAGE(0 == theFile.read_access_size(), "expected 0 users with read access but found " << theFile.read_access_size() );
+ BOOST_REQUIRE_MESSAGE(0 == theFile.write_access_size(),"expected 0 users with write access but found " << theFile.write_access_size() );
+
+ // test random user
+ BOOST_REQUIRE_MESSAGE( theFile.allow_read_access("xxxx"),"Expected user xxxx to have read access ");
+ BOOST_REQUIRE_MESSAGE( theFile.allow_read_access("xxtt"),"Expected user xxtt to have read access ");
+
+ BOOST_REQUIRE_MESSAGE( theFile.allow_write_access("yyyy"),"Expected user yyyy to have write access ");
+ BOOST_REQUIRE_MESSAGE( theFile.allow_write_access("zzzz"),"Expected user zzzz to have write access ");
+}
+
+BOOST_AUTO_TEST_CASE( test_white_list )
+{
+ cout << "ACore:: ...test_white_list\n";
+
+ std::string path = File::test_data("ACore/test/data/goodWhiteListFiles/good1.lists","ACore");
+
+ WhiteListFile theFile;
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE(theFile.load(path,false, errorMsg),"Failed to parse file " << path << "\n" << errorMsg);
+
+ // make sure we find all the users and the access right are correct
+// uid1 # a comment
+// uid2 # a comment
+// cog # a comment
+//
+// #
+// # Read only uisers
+// #
+// -fred # a comment
+// -bill # a comment
+// -jake # a comment
+ std::vector<std::string> expected_users_with_read_access;
+ expected_users_with_read_access.push_back( std::string("fred") );
+ expected_users_with_read_access.push_back( std::string("bill") );
+ expected_users_with_read_access.push_back( std::string("jake") );
+
+ expected_users_with_read_access.push_back( std::string("uid1") ); // users with write access also have read access
+ expected_users_with_read_access.push_back( std::string("uid2") ); // users with write access also have read access
+ expected_users_with_read_access.push_back( std::string("cog") ); // users with write access also have read access
+
+ std::vector<std::string> expected_users_with_read_write_access;
+ expected_users_with_read_write_access.push_back( std::string("uid1"));
+ expected_users_with_read_write_access.push_back( std::string("uid2"));
+ expected_users_with_read_write_access.push_back( std::string("cog"));
+
+ BOOST_REQUIRE_MESSAGE(expected_users_with_read_access.size() == theFile.read_access_size(),
+ " expected " << expected_users_with_read_access.size() << " users with read access but found " << theFile.read_access_size() );
+ BOOST_REQUIRE_MESSAGE(expected_users_with_read_write_access.size() == theFile.write_access_size(),
+ " expected " << expected_users_with_read_write_access.size() << " users with write access but found " << theFile.write_access_size() );
+
+
+ std::vector< std::string >::const_iterator i;
+ for(i=expected_users_with_read_access.begin(); i!= expected_users_with_read_access.end(); ++i) {
+ BOOST_REQUIRE_MESSAGE( theFile.allow_read_access(*i),"Expected user " << *i << " to have read access ");
+ }
+ for(i=expected_users_with_read_write_access.begin(); i!= expected_users_with_read_write_access.end(); ++i) {
+ BOOST_REQUIRE_MESSAGE( theFile.allow_write_access(*i),"Expected user " << *i << " to have write access ");
+ }
+
+ // test random user
+ BOOST_REQUIRE_MESSAGE( !theFile.allow_read_access("xxxx"),"Expected user xxxx to NOT have read access ");
+ BOOST_REQUIRE_MESSAGE( !theFile.allow_read_access("*"),"Expected user * to NOT have read access ");
+
+ BOOST_REQUIRE_MESSAGE( !theFile.allow_write_access("yyyy"),"Expected user yyyy to NOT have write access ");
+ BOOST_REQUIRE_MESSAGE( !theFile.allow_write_access("zzzz"),"Expected user zzzz to NOT have write access ");
+}
+
+BOOST_AUTO_TEST_CASE( test_white_list_all_users_have_read_access )
+{
+ cout << "ACore:: ...test_white_list_all_users_have_read_access\n";
+
+ std::string path = File::test_data("ACore/test/data/goodWhiteListFiles/all_read_access.lists","ACore");
+
+ WhiteListFile theFile;
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE(theFile.load(path,false, errorMsg),"Failed to parse file " << path << "\n" << errorMsg);
+
+ // make sure we find all the users and the access right are correct
+//# These user have read and write access to the server
+//uid1 # a comment
+//uid2 # a comment
+//cog # a comment
+//
+//
+//# Read only users
+//-*
+//-fred # a comment
+//-bill # a comment
+//-jake # a comment
+
+ std::vector<std::string> expected_users_with_read_write_access;
+ expected_users_with_read_write_access.push_back( std::string("uid1"));
+ expected_users_with_read_write_access.push_back( std::string("uid2"));
+ expected_users_with_read_write_access.push_back( std::string("cog"));
+
+ // When all users have read access, the read access size should be empty
+ BOOST_REQUIRE_MESSAGE(theFile.read_access_size() == 0, " expected 0 but found " << theFile.read_access_size() );
+
+ BOOST_REQUIRE_MESSAGE(expected_users_with_read_write_access.size() == theFile.write_access_size(),
+ " expected " << expected_users_with_read_write_access.size() << " users with write access but found " << theFile.write_access_size() );
+
+ // Any user should have read write access
+ BOOST_REQUIRE_MESSAGE( theFile.allow_read_access("fred"),"Expected user fred to have read access ");
+ BOOST_REQUIRE_MESSAGE( theFile.allow_read_access("bill"),"Expected user bill to have read access ");
+ BOOST_REQUIRE_MESSAGE( theFile.allow_read_access("xxxx"),"Expected user xxxx to have read access ");
+ BOOST_REQUIRE_MESSAGE( theFile.allow_read_access("uid1"),"Expected user xxxx to have read access ");
+ BOOST_REQUIRE_MESSAGE( theFile.allow_read_access("uid2"),"Expected user xxxx to have read access ");
+ BOOST_REQUIRE_MESSAGE( theFile.allow_read_access("cog"),"Expected user xxxx to have read access ");
+
+ std::vector< std::string >::const_iterator i;
+ for(i=expected_users_with_read_write_access.begin(); i!= expected_users_with_read_write_access.end(); ++i) {
+ BOOST_REQUIRE_MESSAGE( theFile.allow_write_access(*i),"Expected user " << *i << " to have write access ");
+ }
+
+ // test random user for write access
+ BOOST_REQUIRE_MESSAGE( !theFile.allow_write_access("yyyy"),"Expected user yyyy to NOT have write access ");
+ BOOST_REQUIRE_MESSAGE( !theFile.allow_write_access("zzzz"),"Expected user zzzz to NOT have write access ");
+}
+
+
+BOOST_AUTO_TEST_CASE( test_white_list_all_users_have_write_access )
+{
+ cout << "ACore:: ...test_white_list_all_users_have_write_access\n";
+
+ std::string path = File::test_data("ACore/test/data/goodWhiteListFiles/all_write_access.lists","ACore");
+
+ WhiteListFile theFile;
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE(theFile.load(path,false, errorMsg),"Failed to parse file " << path << "\n" << errorMsg);
+
+ // make sure we find all the users and the access right are correct
+// uid1 # a comment
+// uid2 # a comment
+// cog # a comment
+// *
+//
+// # Read only users
+// -*
+// -fred # a comment
+// -bill # a comment
+// -jake # a comment
+
+ // When all users have read access, the read access size should be empty
+ BOOST_REQUIRE_MESSAGE(theFile.read_access_size() == 0, " expected 0 but found " << theFile.read_access_size() );
+ BOOST_REQUIRE_MESSAGE(theFile.write_access_size() == 0, " expected 0 but found " << theFile.read_access_size() );
+
+ // Any user should have read access
+ BOOST_REQUIRE_MESSAGE( theFile.allow_read_access("fred"),"Expected user fred to have read access ");
+ BOOST_REQUIRE_MESSAGE( theFile.allow_read_access("bill"),"Expected user bill to have read access ");
+ BOOST_REQUIRE_MESSAGE( theFile.allow_read_access("xxxx"),"Expected user xxxx to have read access ");
+ BOOST_REQUIRE_MESSAGE( theFile.allow_read_access("uid1"),"Expected user xxxx to have read access ");
+ BOOST_REQUIRE_MESSAGE( theFile.allow_read_access("uid2"),"Expected user xxxx to have read access ");
+ BOOST_REQUIRE_MESSAGE( theFile.allow_read_access("cog"),"Expected user xxxx to have read access ");
+
+ // Any user should have read write access
+ BOOST_REQUIRE_MESSAGE( theFile.allow_write_access("fred"),"Expected user fred to have read access ");
+ BOOST_REQUIRE_MESSAGE( theFile.allow_write_access("bill"),"Expected user bill to have read access ");
+ BOOST_REQUIRE_MESSAGE( theFile.allow_write_access("xxxx"),"Expected user xxxx to have read access ");
+ BOOST_REQUIRE_MESSAGE( theFile.allow_write_access("uid1"),"Expected user xxxx to have read access ");
+ BOOST_REQUIRE_MESSAGE( theFile.allow_write_access("uid2"),"Expected user xxxx to have read access ");
+ BOOST_REQUIRE_MESSAGE( theFile.allow_write_access("cog"),"Expected user xxxx to have read access ");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ACore/test/data/badWhiteListFiles/bad2.lists b/ACore/test/data/badWhiteListFiles/bad2.lists
similarity index 100%
rename from ecflow_4_0_7/ACore/test/data/badWhiteListFiles/bad2.lists
rename to ACore/test/data/badWhiteListFiles/bad2.lists
diff --git a/ecflow_4_0_7/ACore/test/data/badWhiteListFiles/bad3.lists b/ACore/test/data/badWhiteListFiles/bad3.lists
similarity index 100%
rename from ecflow_4_0_7/ACore/test/data/badWhiteListFiles/bad3.lists
rename to ACore/test/data/badWhiteListFiles/bad3.lists
diff --git a/ecflow_4_0_7/ACore/test/data/badWhiteListFiles/bad5.lists b/ACore/test/data/badWhiteListFiles/bad5.lists
similarity index 100%
rename from ecflow_4_0_7/ACore/test/data/badWhiteListFiles/bad5.lists
rename to ACore/test/data/badWhiteListFiles/bad5.lists
diff --git a/ecflow_4_0_7/ACore/test/data/badWhiteListFiles/badsms.lists b/ACore/test/data/badWhiteListFiles/badsms.lists
similarity index 100%
rename from ecflow_4_0_7/ACore/test/data/badWhiteListFiles/badsms.lists
rename to ACore/test/data/badWhiteListFiles/badsms.lists
diff --git a/ACore/test/data/goodWhiteListFiles/all_read_access.lists b/ACore/test/data/goodWhiteListFiles/all_read_access.lists
new file mode 100644
index 0000000..be5268d
--- /dev/null
+++ b/ACore/test/data/goodWhiteListFiles/all_read_access.lists
@@ -0,0 +1,16 @@
+#
+4.4.14 # comment
+
+# These user have read and write access to the server
+uid1 # a comment
+uid2 # a comment
+cog # a comment
+
+
+# Read only users
+-*
+-fred # a comment
+-bill # a comment
+-jake # a comment
+
+# a comment
diff --git a/ACore/test/data/goodWhiteListFiles/all_write_access.lists b/ACore/test/data/goodWhiteListFiles/all_write_access.lists
new file mode 100644
index 0000000..a015e07
--- /dev/null
+++ b/ACore/test/data/goodWhiteListFiles/all_write_access.lists
@@ -0,0 +1,14 @@
+
+4.4.14 # comment
+
+# These user have read and write access to the server
+uid1
+uid2
+cog
+* # all users have read and write access
+
+# Read only users
+-*
+-fred # a comment
+-bill # a comment
+-jake # a comment
diff --git a/ACore/test/data/goodWhiteListFiles/empty.lists b/ACore/test/data/goodWhiteListFiles/empty.lists
new file mode 100644
index 0000000..b3b7d7b
--- /dev/null
+++ b/ACore/test/data/goodWhiteListFiles/empty.lists
@@ -0,0 +1 @@
+4.4.14 # comment
\ No newline at end of file
diff --git a/ACore/test/data/goodWhiteListFiles/good1.lists b/ACore/test/data/goodWhiteListFiles/good1.lists
new file mode 100644
index 0000000..c2639ff
--- /dev/null
+++ b/ACore/test/data/goodWhiteListFiles/good1.lists
@@ -0,0 +1,15 @@
+#
+4.4.14 # comment
+
+# These user have read and write access to the server
+uid1 # a comment
+uid2 # a comment
+cog # a comment
+
+
+# Read only users
+-fred # a comment
+-bill # a comment
+-jake # a comment
+
+# a comment
diff --git a/ACore/test/data/goodWhiteListFiles/goodsms.lists b/ACore/test/data/goodWhiteListFiles/goodsms.lists
new file mode 100644
index 0000000..a6015c1
--- /dev/null
+++ b/ACore/test/data/goodWhiteListFiles/goodsms.lists
@@ -0,0 +1,6 @@
+
+4.4.14 # comment
+
+uid1
+uid2
+cog
diff --git a/ecflow_4_0_7/ACore/test/data/migration/calendar_v1.9 b/ACore/test/data/migration/calendar_v1.9
similarity index 100%
rename from ecflow_4_0_7/ACore/test/data/migration/calendar_v1.9
rename to ACore/test/data/migration/calendar_v1.9
diff --git a/ecflow_4_0_7/ACore/test/data/migration/timeseries_10_10_v1_9 b/ACore/test/data/migration/timeseries_10_10_v1_9
similarity index 100%
rename from ecflow_4_0_7/ACore/test/data/migration/timeseries_10_10_v1_9
rename to ACore/test/data/migration/timeseries_10_10_v1_9
diff --git a/ecflow_4_0_7/ACore/test/data/migration/timeseries_default_constructor_v1.9 b/ACore/test/data/migration/timeseries_default_constructor_v1.9
similarity index 100%
rename from ecflow_4_0_7/ACore/test/data/migration/timeseries_default_constructor_v1.9
rename to ACore/test/data/migration/timeseries_default_constructor_v1.9
diff --git a/ecflow_4_0_7/ACore/test/data/migration/timeslot_1_1_v1_9 b/ACore/test/data/migration/timeslot_1_1_v1_9
similarity index 100%
rename from ecflow_4_0_7/ACore/test/data/migration/timeslot_1_1_v1_9
rename to ACore/test/data/migration/timeslot_1_1_v1_9
diff --git a/ecflow_4_0_7/ACore/test/data/migration/timeslot_99_59_v1_9 b/ACore/test/data/migration/timeslot_99_59_v1_9
similarity index 100%
rename from ecflow_4_0_7/ACore/test/data/migration/timeslot_99_59_v1_9
rename to ACore/test/data/migration/timeslot_99_59_v1_9
diff --git a/ecflow_4_0_7/ACore/test/data/migration/timeslot_default_constructor_v1.9 b/ACore/test/data/migration/timeslot_default_constructor_v1.9
similarity index 100%
rename from ecflow_4_0_7/ACore/test/data/migration/timeslot_default_constructor_v1.9
rename to ACore/test/data/migration/timeslot_default_constructor_v1.9
diff --git a/ecflow_4_0_7/ANattr/CMakeLists.txt b/ANattr/CMakeLists.txt
similarity index 100%
rename from ecflow_4_0_7/ANattr/CMakeLists.txt
rename to ANattr/CMakeLists.txt
diff --git a/ANattr/jamfile.jam b/ANattr/jamfile.jam
new file mode 100644
index 0000000..211f2fc
--- /dev/null
+++ b/ANattr/jamfile.jam
@@ -0,0 +1,44 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+#
+# Node attribute project
+#
+project theNodeAttr ;
+
+use-project theCore : ../ACore ;
+
+# The <include> means we will automatically add this directory to the include path
+# of any other target that uses this lib
+#
+lib nodeattr : [ glob src/*.cpp ]
+ : <link>static
+ <variant>debug:<define>DEBUG
+ <use>/theCore//core
+ <use>/site-config//boost_system
+ <use>/site-config//boost_serialization
+ <use>/site-config//boost_filesystem
+ <use>/site-config//boost_datetime
+ <use>/site-config//boost_test
+ :
+ : <include>../ANattr/src
+ ;
+
+#
+# boost_datetime is only required for formatting. i.e to call to_simple_string
+# cerr << to_simple_string(calendar.suiteTime()) << "\n";
+#
+exe u_anattr : [ glob test/*.cpp ]
+ /theCore//core
+ nodeattr
+ /site-config//boost_system
+ /site-config//boost_filesystem
+ /site-config//boost_serialization
+ /site-config//boost_datetime
+ /site-config//boost_test
+ : <variant>debug:<define>DEBUG
+ ;
\ No newline at end of file
diff --git a/ANattr/src/AutoCancelAttr.cpp b/ANattr/src/AutoCancelAttr.cpp
new file mode 100644
index 0000000..140568e
--- /dev/null
+++ b/ANattr/src/AutoCancelAttr.cpp
@@ -0,0 +1,103 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #9 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <sstream>
+
+#include "AutoCancelAttr.hpp"
+#include "Calendar.hpp"
+#include "Indentor.hpp"
+#include "Log.hpp"
+
+#ifdef DEBUG
+#include <boost/date_time/posix_time/time_formatters.hpp>
+#endif
+
+using namespace std;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+
+namespace ecf {
+
+std::ostream& AutoCancelAttr::print(std::ostream& os) const
+{
+ Indentor in;
+ Indentor::indent(os) << "autocancel ";
+ if (days_) {
+ os << timeStruct_.hour()/24 << "\n";
+ return os;
+ }
+
+ if (relative_) os << "+";
+ timeStruct_.print(os);
+ os << "\n";
+ return os;
+}
+
+std::string AutoCancelAttr::toString() const
+{
+ std::stringstream ss;
+ ss << "autocancel ";
+ if (days_) {
+ ss << timeStruct_.hour()/24;
+ return ss.str();
+ }
+
+ if (relative_) ss << "+";
+ ss << timeStruct_.toString();
+ return ss.str();
+}
+
+
+bool AutoCancelAttr::operator==(const AutoCancelAttr& rhs) const
+{
+ if (relative_ != rhs.relative_) return false;
+ if (days_ != rhs.days_) return false;
+ return timeStruct_.operator==(rhs.timeStruct_);
+}
+
+bool AutoCancelAttr::isFree(const ecf::Calendar& calendar,const boost::posix_time::time_duration& suiteDurationAtComplete) const
+{
+ // suiteTime()
+ // suiteDurationAtComplete autocancel time calendar duration
+ // | | |
+ // V V V
+ // ----------------------------------------------------------------------------------> time
+ // ^ ^
+ // |--------elapsed time---------------------------------------|
+ //
+ //
+
+ if ( relative_ ) {
+ time_duration timeElapsedAfterComplete = calendar.duration() - suiteDurationAtComplete;
+ LOG_ASSERT(!timeElapsedAfterComplete.is_negative(),"should always be positive or some things gone wrong");
+ if (timeElapsedAfterComplete >= timeStruct_.duration()) {
+ return true;
+ }
+ }
+ else {
+ // real time
+//#ifdef DEBUG
+// cout << "real time timeStruct_(" << to_simple_string(timeStruct_.duration())
+// << ") calendar.suiteTime().time_of_day(" << to_simple_string(calendar.suiteTime().time_of_day()) << ")\n";
+//#endif
+ if (calendar.suiteTime().time_of_day() >= timeStruct_.duration()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+}
diff --git a/ANattr/src/AutoCancelAttr.hpp b/ANattr/src/AutoCancelAttr.hpp
new file mode 100644
index 0000000..654e8d8
--- /dev/null
+++ b/ANattr/src/AutoCancelAttr.hpp
@@ -0,0 +1,59 @@
+#ifndef AUTOCANCELATTR_HPP_
+#define AUTOCANCELATTR_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #9 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "TimeSlot.hpp"
+
+namespace ecf { class Calendar;} // forward declare class
+
+namespace ecf {
+
+// Use compiler , destructor, assignment, copy constructor
+class AutoCancelAttr {
+public:
+ AutoCancelAttr() : relative_(true),days_(false) {}
+ AutoCancelAttr(int hour, int minute, bool relative ) : timeStruct_(hour, minute), relative_(relative), days_(false) {}
+ AutoCancelAttr(const TimeSlot& ts, bool relative ) : timeStruct_(ts), relative_(relative), days_(false) {}
+ AutoCancelAttr(int days) : timeStruct_( TimeSlot(days*24,0) ), relative_(true), days_(true) {}
+
+ std::ostream& print(std::ostream&) const;
+ bool operator==(const AutoCancelAttr& rhs) const;
+ bool isFree(const ecf::Calendar&, const boost::posix_time::time_duration& suiteDurationAtComplete) const;
+
+ std::string toString() const;
+
+ const TimeSlot& time() const { return timeStruct_;}
+ bool relative() const { return relative_; }
+ bool days() const { return days_; }
+
+private:
+ TimeSlot timeStruct_;
+ bool relative_;
+ bool days_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/)
+ {
+ ar & timeStruct_;
+ ar & relative_;
+ ar & days_;
+ }
+};
+
+}
+#endif
+
diff --git a/ANattr/src/ClockAttr.cpp b/ANattr/src/ClockAttr.cpp
new file mode 100644
index 0000000..2d374ad
--- /dev/null
+++ b/ANattr/src/ClockAttr.cpp
@@ -0,0 +1,169 @@
+//============================================================================
+// Name : NodeTree.cpp
+// Author : Avi
+// Revision : $Revision: #21 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "ClockAttr.hpp"
+#include "DateAttr.hpp"
+#include "Indentor.hpp"
+#include "Calendar.hpp"
+#include "Ecf.hpp"
+
+#include <boost/foreach.hpp>
+#include <assert.h>
+#include <sstream>
+
+using namespace std;
+using namespace ecf;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+
+//==========================================================================================
+
+ClockAttr::ClockAttr(const boost::posix_time::ptime& time, bool hybrid,bool positiveGain)
+: hybrid_(hybrid), positiveGain_(positiveGain), startStopWithServer_(false),
+ gain_(0), day_(0),month_(0),year_(0),
+ state_change_no_(Ecf::incr_state_change_no())
+{
+ boost::gregorian::date theDate = time.date();
+ day_ = theDate.day();
+ month_ = theDate.month();
+ year_ = theDate.year();
+
+ tm t = to_tm(time);
+ gain_ = t.tm_hour *3600 + t.tm_min*60 + t.tm_sec;
+}
+
+ClockAttr::ClockAttr(int day, int month, int year, bool hybrid )
+: hybrid_(hybrid), positiveGain_(false), startStopWithServer_(false),
+ gain_(0), day_(day),month_(month),year_(year),
+ state_change_no_(Ecf::incr_state_change_no())
+{
+ // Will throw std::out_of_range exception
+ DateAttr::checkDate(day,month,year,false /* for calendars we don't allow wild carding */);
+}
+
+ClockAttr::ClockAttr(bool hybrid)
+: hybrid_(hybrid), positiveGain_(false), startStopWithServer_(false),
+ gain_(0), day_(0),month_(0),year_(0),
+ state_change_no_(Ecf::incr_state_change_no()) {}
+
+std::ostream& ClockAttr::print(std::ostream& os) const
+{
+ Indentor in;
+ Indentor::indent(os) << toString() << "\n";
+ return os;
+}
+
+std::string ClockAttr::toString() const
+{
+ std::stringstream ss;
+ ss << "clock ";
+ if (hybrid_) ss << "hybrid ";
+ else ss << "real ";
+
+ if (day_ != 0) ss << day_ << "." << month_ << "." << year_ << " ";
+
+ if (gain_ != 0) {
+ if (positiveGain_) ss << "+";
+ ss << gain_;
+ }
+
+ if ( startStopWithServer_) ss << " -s";
+
+ return ss.str();
+}
+
+bool ClockAttr::operator==(const ClockAttr& rhs) const
+{
+ if (hybrid_ != rhs.hybrid_) return false;
+ if (positiveGain_ != rhs.positiveGain_) return false;
+ if (startStopWithServer_ != rhs.startStopWithServer_) return false;
+
+ if (day_ != rhs.day_) return false;
+ if (month_ != rhs.month_) return false;
+ if (year_ != rhs.year_) return false;
+
+ if (gain_ != rhs.gain_) return false;
+
+ return true;
+}
+
+void ClockAttr::date(int day, int month, int year)
+{
+ // Will throw std::out_of_range exception
+ DateAttr::checkDate(day,month,year,false /* for calendars we don't allow wild carding */);
+ day_ = day;
+ month_ = month;
+ year_ = year;
+ state_change_no_ = Ecf::incr_state_change_no();
+}
+
+void ClockAttr::set_gain(int hour,int min,bool positiveGain)
+{
+ positiveGain_ = positiveGain;
+ gain_ = (hour * 3600) + min *60;
+ state_change_no_ = Ecf::incr_state_change_no();
+}
+
+void ClockAttr::set_gain_in_seconds(long theGain,bool positiveGain)
+{
+ positiveGain_ = positiveGain;
+ gain_ = theGain;
+ state_change_no_ = Ecf::incr_state_change_no();
+}
+
+void ClockAttr::startStopWithServer(bool f) {
+ startStopWithServer_ = f;
+ state_change_no_ = Ecf::incr_state_change_no();
+}
+
+void ClockAttr::hybrid( bool f ) {
+ hybrid_ = f;
+ state_change_no_ = Ecf::incr_state_change_no();
+}
+
+void ClockAttr::sync() {
+ // When begin_calendar() is called we will sync with computer clock.
+ gain_ = 0;
+ day_ = 0;
+ month_ = 0 ;
+ year_ = 0;
+ state_change_no_ = Ecf::incr_state_change_no();
+}
+
+void ClockAttr::init_calendar(ecf::Calendar& calendar)
+{
+ Calendar::Clock_t clockType = (hybrid_) ? Calendar::HYBRID : Calendar::REAL;
+ calendar.init(clockType, startStopWithServer_);
+}
+
+void ClockAttr::begin_calendar(ecf::Calendar& calendar)
+{
+ using namespace boost::posix_time;
+ using namespace boost::gregorian;
+
+ if (day_ != 0) {
+ // Use the date given. ie we start from midnight on the given day + gain.
+ boost::gregorian::date theDate(year_,month_,day_);
+ ptime the_time(theDate, seconds(gain_));
+ calendar.begin(the_time);
+ }
+ else {
+ // Get the local time, second level resolution, based on the time zone settings of the computer.
+ ptime the_time(Calendar::second_clock_time());
+ the_time += seconds(gain_);
+ calendar.begin(the_time);
+ }
+}
+
diff --git a/ANattr/src/ClockAttr.hpp b/ANattr/src/ClockAttr.hpp
new file mode 100644
index 0000000..ae581f1
--- /dev/null
+++ b/ANattr/src/ClockAttr.hpp
@@ -0,0 +1,100 @@
+#ifndef CLOCKATTR_HPP_
+#define CLOCKATTR_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #18 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <ostream>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/serialization/serialization.hpp>
+
+namespace ecf { class Calendar;} // forward declare class that is in a namesapce
+
+/// The clock attribute is defined on the suite ONLY
+/// Use default copy constructor and assignment operator, destructor
+/// The clock attribute is used to initialise the calendar object
+/// **********************************************************************
+/// In the OLD sms the date is actually used as a gain factor(well at least
+/// according to the user/reference manual), in the ec-flow
+/// a date, is a date. i.e. it allows us to start a suite in the past.
+///
+/// The Constructor will update the State change number, since it can be added
+/// by the AlterCmd. in the Client Context, state change number is not incremented
+/// ************************************************************************
+///
+class ClockAttr {
+public:
+ /// The following constructor is used for test only. It allows us to
+ /// create a clock attribute initialised with given date and time
+ ClockAttr(const boost::posix_time::ptime&, bool hybrid = false, bool positiveGain = true);
+ ClockAttr(int day, int month, int year, bool hybrid = false );
+ ClockAttr(bool hybrid = false);
+
+ std::ostream& print(std::ostream&) const;
+ bool operator==(const ClockAttr& rhs) const;
+
+ void date(int day, int month, int year);
+ void set_gain(int hour,int min,bool positiveGain = true);
+ void set_gain_in_seconds(long theGain,bool positiveGain = true);
+
+ void startStopWithServer(bool f);
+ bool startStopWithServer() const { return startStopWithServer_; }
+ void hybrid( bool f );
+
+ // clear local attributes so, than when we re-queue suite, we sync with computer clock
+ void sync();
+
+ void init_calendar(ecf::Calendar&);
+ void begin_calendar(ecf::Calendar&);
+
+ // The state_change_no is never reset. Must be incremented if it can affect equality
+ unsigned int state_change_no() const { return state_change_no_; }
+
+ // access
+ int day() const { return day_; }
+ int month() const { return month_; }
+ int year() const { return year_; }
+ long gain() const { return gain_;}
+ bool positive_gain() const { return positiveGain_;}
+ bool hybrid() const { return hybrid_;}
+ bool is_virtual() const { return startStopWithServer_;}
+ std::string toString() const;
+
+private:
+ bool hybrid_;
+ bool positiveGain_;
+ bool startStopWithServer_; // see Calendar.hpp for more details
+ long gain_; // in seconds
+ int day_;
+ int month_;
+ int year_;
+
+ unsigned int state_change_no_; // *not* persisted, only used on server side
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/)
+ {
+ ar & hybrid_;
+ ar & positiveGain_;
+ ar & startStopWithServer_;
+ ar & gain_;
+ ar & day_;
+ ar & month_;
+ ar & year_;
+ }
+};
+
+#endif
diff --git a/ANattr/src/CronAttr.cpp b/ANattr/src/CronAttr.cpp
new file mode 100644
index 0000000..ad7e785
--- /dev/null
+++ b/ANattr/src/CronAttr.cpp
@@ -0,0 +1,724 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #59 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <sstream>
+
+#include <boost/foreach.hpp>
+#include <boost/date_time/posix_time/time_formatters.hpp> // requires boost date and time lib
+#include <boost/algorithm/string/trim.hpp>
+#include <boost/tokenizer.hpp>
+#include <boost/token_functions.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include "CronAttr.hpp"
+#include "Indentor.hpp"
+#include "Calendar.hpp"
+#include "PrintStyle.hpp"
+#include "Str.hpp"
+#include "Ecf.hpp"
+#include "Log.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+
+//#define DEBUG_CRON_ATTR 1
+//#define DEBUG_CRON_PARSING 1
+
+namespace ecf {
+
+CronAttr::CronAttr() : makeFree_(false),state_change_no_(0) {}
+
+void CronAttr::addWeekDays( const std::vector<int>& w)
+{
+ weekDays_ = w;
+ BOOST_FOREACH(int day,weekDays_) {
+ if (day < 0 || day > 6) {
+ std::stringstream ss; ss << "Invalid range for day(" << day << ") of the week expected range is 0==Sun to 6==Sat";
+ throw std::out_of_range(ss.str());
+ }
+ }
+}
+void CronAttr::addDaysOfMonth( const std::vector<int>& d)
+{
+ daysOfMonth_ = d;
+ BOOST_FOREACH(int day_of_month,daysOfMonth_) {
+ if (day_of_month < 1 || day_of_month > 31) {
+ std::stringstream ss; ss << "Invalid range for day of month(" << day_of_month << ") expected range is 1-31";
+ throw std::out_of_range(ss.str());
+ }
+ }
+}
+
+void CronAttr::addMonths( const std::vector<int>& m)
+{
+ months_ = m;
+ BOOST_FOREACH(int month,months_) {
+ if (month < 1 || month > 12) {
+ std::stringstream ss; ss << "Invalid range for month(" << month << ") expected range is 1==Jan to 12==Dec";
+ throw std::out_of_range(ss.str());
+ }
+ }
+}
+
+std::ostream& CronAttr::print(std::ostream& os) const
+{
+ Indentor in;
+ Indentor::indent(os) << toString();
+ if (!PrintStyle::defsStyle()) {
+ os << timeSeries_.state_to_string(makeFree_);
+ }
+ os << "\n";
+ return os;
+}
+
+std::string CronAttr::toString() const
+{
+ std::stringstream ss;
+ ss << "cron ";
+ if (!weekDays_.empty()) {
+ ss << "-w ";
+ for(size_t i=0; i<weekDays_.size();++i) {
+ ss << weekDays_[i];
+ if (i !=weekDays_.size()-1) ss << ",";
+ }
+ ss << " ";
+ }
+ if (!daysOfMonth_.empty()) {
+ ss << "-d ";
+ for(size_t i=0; i<daysOfMonth_.size();++i) {
+ ss << daysOfMonth_[i];
+ if (i !=daysOfMonth_.size()-1) ss << ",";
+ }
+ ss << " ";
+ }
+ if (!months_.empty()) {
+ ss << "-m ";
+ for(size_t i=0; i<months_.size();++i) {
+ ss << months_[i];
+ if (i !=months_.size()-1) ss << ",";
+ }
+ ss << " ";
+ }
+
+ ss << timeSeries_.toString(); // no new line added, up to caller
+ return ss.str();
+}
+
+std::string CronAttr::dump() const
+{
+ std::stringstream ss; ss << toString();
+ if (makeFree_) ss << " (free)";
+ else ss << " (holding)";
+ return ss.str();
+}
+
+bool CronAttr::operator==(const CronAttr& rhs) const
+{
+ if (makeFree_ != rhs.makeFree_) {
+ return false;
+ }
+
+ if (weekDays_ != rhs.weekDays_) return false;
+ if (daysOfMonth_ != rhs.daysOfMonth_) return false;
+ if (months_ != rhs.months_) return false;
+ return timeSeries_.operator==(rhs.timeSeries_);
+}
+bool CronAttr::structureEquals(const CronAttr& rhs) const
+{
+ if (weekDays_ != rhs.weekDays_) return false;
+ if (daysOfMonth_ != rhs.daysOfMonth_) return false;
+ if (months_ != rhs.months_) return false;
+ return timeSeries_.structureEquals(rhs.timeSeries_);
+}
+
+void CronAttr::calendarChanged( const ecf::Calendar& c )
+{
+ if ( makeFree_ ) {
+ return;
+ }
+
+ // This assumes that calendarChanged will set TimeSeries::isValid = true, at day change
+ if (timeSeries_.calendarChanged(c)) {
+ state_change_no_ = Ecf::incr_state_change_no();
+ }
+
+ // Once a cron is free, it stays free until re-queue
+ if (isFree(c)) {
+ setFree();
+ }
+ // A cron is always re-queable, hence we use isFree to control when it can actually run.
+}
+
+void CronAttr::resetRelativeDuration()
+{
+ if (timeSeries_.resetRelativeDuration()) {
+ state_change_no_ = Ecf::incr_state_change_no();
+ }
+}
+
+void CronAttr::setFree() {
+ makeFree_ = true;
+ state_change_no_ = Ecf::incr_state_change_no();
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "CronAttr::setFree()\n";
+#endif
+}
+
+void CronAttr::clearFree() {
+ makeFree_ = false;
+ state_change_no_ = Ecf::incr_state_change_no();
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "CronAttr::clearFree()\n";
+#endif
+}
+
+void CronAttr::miss_next_time_slot()
+{
+ // A cron attribute with a single time slot is repeated indefinitely hence always re-queues
+ timeSeries_.miss_next_time_slot();
+ state_change_no_ = Ecf::incr_state_change_no();
+}
+
+// **************************************************************************************
+// FOR DEBUG THIS IS THE MAIN FUNCTION, AS THIS DECIDES WHETHER WE CONTINE OR STOP
+// **************************************************************************************
+bool CronAttr::checkForRequeue( const ecf::Calendar& calendar) const
+{
+ // checkForRequeue is called when a task/family has reach the complete state
+ // This simple checks if node should be put in re-queued state
+ // A cron is always re-queable
+
+ // Hence: In order to use this it should be used in conjunction with a
+ // with a parent node that has complete expression, (& maybe a dummy task)
+ // This will allow its use with a parent repeat somewhere in the hierarchy
+ return true;
+}
+
+bool CronAttr::validForHybrid(const ecf::Calendar& calendar) const
+{
+ if (timeSeries_.hasIncrement()) {
+ if (!months_.empty() ) return false; // relies on day change
+ if (!daysOfMonth_.empty() ) return false; // relies on day change
+ if (!weekDays_.empty() ) {
+ if ( weekDays_.size() != 1) return false; // relies on day change
+
+ return ( weekDays_[0] == calendar.day_of_week() );
+ }
+
+ // cron 10:00 20:00 01:00 // valid for hybrid ?
+ return true;
+ }
+
+ // A time series that does not have an increment runs indefinitely and hence relies on day change
+ // cron 23:00
+ return false;
+}
+
+bool CronAttr::why(const ecf::Calendar& c, std::string& theReasonWhy) const
+{
+ // This will logically AND all the times
+ if (isFree(c)) return false;
+
+ // We are here because:
+ // 1/ Not on a valid time slot in the time series
+ // *OR*
+ // 2/ Logical *AND* of day of week, day of month, or month returned false
+ theReasonWhy += "is cron dependent";
+
+ // Lets say that the time series was NOT free.
+ // First check if week day, day of month, month, matches
+ if ( is_day_of_week_day_of_month_and_month_free(c)) {
+
+ if (timeSeries_.is_valid()) {
+
+ // This can apply to single and series
+ boost::posix_time::time_duration calendar_time = timeSeries_.duration(c);
+ if (calendar_time < timeSeries_.start().duration()) {
+ timeSeries_.why(c, theReasonWhy);
+ return true;
+ }
+
+ // calendar_time >= timeSeries_.start().duration()
+ if (timeSeries_.hasIncrement()) {
+ if (calendar_time < timeSeries_.finish().duration()) {
+ timeSeries_.why(c, theReasonWhy);
+ return true;
+ }
+ }
+ }
+ // calendar_time >= timeSeries_.start().duration() && calendar_time >= timeSeries_.finish().duration()
+ // past the end of time slot, find next valid date
+ }
+
+ // take into account, user can use run/force complete to miss time slots
+ bool do_a_requeue = timeSeries_.requeueable(c);
+ if (do_a_requeue && weekDays_.empty() && daysOfMonth_.empty() && months_.empty()) {
+ TimeSlot the_next_time_slot = timeSeries_.compute_next_time_slot(c);
+ if (the_next_time_slot.isNULL() ) {
+ theReasonWhy += " ( *re-queue* to run at this time ";
+ }
+ else {
+ theReasonWhy += " ( *re-queue* to run at ";
+ theReasonWhy += the_next_time_slot.toString() ;
+ }
+
+ theReasonWhy += ", otherwise next run is at ";
+ }
+ else {
+ theReasonWhy += " ( next run is at ";
+ }
+
+ // Find the *NEXT* date that matches, and use the first time slot
+ boost::gregorian::date the_next_date = next_date(c);
+ theReasonWhy += timeSeries_.start().toString();
+ theReasonWhy += " ";
+ theReasonWhy += to_simple_string( the_next_date );
+
+ std::stringstream ss;
+ TimeSlot currentTime = TimeSlot(timeSeries_.duration(c));
+ ss << ", current time ";
+ if (timeSeries_.relative()) ss << "+";
+ ss << currentTime.toString() << " " << to_simple_string(c.date()) << " )";
+ theReasonWhy += ss.str();
+ return true;
+}
+
+void CronAttr::reset(const ecf::Calendar& c)
+{
+ clearFree();
+ timeSeries_.reset(c);
+}
+
+void CronAttr::requeue(const ecf::Calendar& c, bool reset_next_time_slot)
+{
+ clearFree();
+ timeSeries_.requeue(c,reset_next_time_slot);
+}
+
+bool CronAttr::isFree(const ecf::Calendar& c) const
+{
+ // The FreeDepCmd can be used to free the crons,
+ if (makeFree_) {
+ return true;
+ }
+
+ if (!timeSeries_.isFree(c)) return false;
+
+ // Ok time series is Free
+
+ // ********************************************************************
+ // IMPORTANT: when we have multiple week days, days of month and months
+ // Then we are *ONLY* free, if *ALL* are free, i.e we need AND behaviour
+ // ********************************************************************
+ return is_day_of_week_day_of_month_and_month_free(c);
+}
+
+
+bool CronAttr::is_day_of_week_day_of_month_and_month_free( const ecf::Calendar& c) const
+{
+ bool the_week_day_matches = weekDays_.empty(); // week day matches if no week days
+ bool the_day_of_month_matches = daysOfMonth_.empty(); // day of month if no days of month
+ bool the_month_matches = months_.empty(); // month matches if no months
+
+ if ( !weekDays_.empty()) the_week_day_matches = week_day_matches(c.day_of_week());
+ if ( !daysOfMonth_.empty()) the_day_of_month_matches = day_of_month_matches(c.day_of_month());
+ if ( !months_.empty() ) the_month_matches = month_matches(c.month());
+
+ return ( the_week_day_matches && the_day_of_month_matches && the_month_matches) ;
+}
+
+bool CronAttr::week_day_matches( int theDayOfWeek ) const
+{
+ BOOST_FOREACH(int theWeekDay, weekDays_) {
+ if ( theDayOfWeek == theWeekDay) return true;
+ }
+ return false;
+}
+
+bool CronAttr::day_of_month_matches(int theDayOfMonth) const
+{
+ BOOST_FOREACH(int dayOfMonth, daysOfMonth_) {
+ if ( theDayOfMonth == dayOfMonth) return true;
+ }
+ return false;
+}
+
+bool CronAttr::month_matches(int theMonth) const
+{
+ BOOST_FOREACH(int month, months_) {
+ if ( theMonth == month) return true;
+ }
+ return false;
+}
+
+//------------------------------------------------------------------
+//int CronAttr::max_month() const {
+// int max = -1;
+// BOOST_FOREACH(int month, months_) {
+// max = std::max(month,max);
+// }
+// return max;
+//}
+
+//int CronAttr::max_day_of_month() const
+//{
+// int max = -1;
+// BOOST_FOREACH(int dayOfMonth, daysOfMonth_) {
+// max = std::max(dayOfMonth,max);
+// }
+// return max;
+//}
+
+//int CronAttr::max_day_of_week() const
+//{
+// int max = -1;
+// BOOST_FOREACH(int theWeekDay, weekDays_) {
+// max = std::max(theWeekDay,max);
+// }
+// return max;
+//}
+
+//-------------------------------------------------------------------------------
+//int CronAttr::min_month() const{
+// int min = std::numeric_limits<int>::max();
+// BOOST_FOREACH(int month, months_) {
+// min = std::min(month,min);
+// }
+// return min;
+//}
+
+//int CronAttr::min_day_of_month() const
+//{
+// int min = std::numeric_limits<int>::max();
+// BOOST_FOREACH(int dayOfMonth, daysOfMonth_) {
+// min = std::min(dayOfMonth,min);
+// }
+// return min;
+//}
+//
+//int CronAttr::min_day_of_week() const
+//{
+// int min = std::numeric_limits<int>::max();
+// BOOST_FOREACH(int theWeekDay, weekDays_) {
+// min = std::min(theWeekDay,min);
+// }
+// return min;
+//}
+//------------------------------------------------------------
+
+
+bool CronAttr::checkInvariants(std::string& errormsg) const
+{
+ return timeSeries_.checkInvariants(errormsg);
+}
+
+
+//--------------------------------------------------------------
+
+boost::gregorian::date CronAttr::last_day_of_month(const ecf::Calendar& calendar) const
+{
+ boost::gregorian::date todays_date = calendar.date();
+ boost::gregorian::date lastdayOfMonth = todays_date.end_of_month();
+ boost::gregorian::date_duration one_day(1);
+
+// cout << "CronAttr::last_day_of_month " << calendar.toString() << " \n";
+
+ boost::gregorian::date max_date(neg_infin);
+ while ( todays_date <= lastdayOfMonth ) {
+
+ // deal with case where we have:
+ // cron -w 0,1 -m 5,6,7,8
+ // Find the last Sunday/Monday for *THIS* month
+ for (size_t i = 0; i < weekDays_.size(); ++i) {
+ if ( todays_date.day_of_week().as_number() == weekDays_[i] ) {
+// cout << "CronAttr::last_day_of_month ( todays_date.day_of_week().as_number() == weekDays_[i] ) " << weekDays_[i] << "\n";
+ if ( todays_date > max_date ) {
+ max_date = todays_date;
+// cout << "CronAttr::last_day_of_month max_date = " << to_simple_string(max_date) << "\n";
+ }
+
+ // The day of week MAY NOT MATCH the day of month
+ // deal with case where we have:
+ // cron -w 0,1 -d 14,15,16
+ // Find the last date for *THIS* month
+ for (size_t d = 0; d < daysOfMonth_.size(); ++d) {
+ if ( todays_date.day() == daysOfMonth_[d] ) {
+// cout << "CronAttr::last_day_of_month **( todays_date.day() == daysOfMonth_[d] ) " << daysOfMonth_[d] << "\n";
+ if ( todays_date > max_date ) {
+ max_date = todays_date;
+// cout << "CronAttr::last_day_of_month max_date = " << to_simple_string(max_date) << "\n";
+ }
+ }
+ }
+ }
+ }
+
+ // deal with case where we have:
+ // cron -d 14,15,16 -m 5,6,7,8
+ // Find the last date for *THIS* month
+ for (size_t d = 0; d < daysOfMonth_.size(); ++d) {
+ if ( todays_date.day() == daysOfMonth_[d] ) {
+// cout << "CronAttr::last_day_of_month ( todays_date.day() == daysOfMonth_[d] ) " << daysOfMonth_[d] << "\n";
+ if ( todays_date > max_date ) {
+ max_date = todays_date;
+// cout << "CronAttr::last_day_of_month max_date = " << to_simple_string(max_date) << "\n";
+ }
+ }
+ }
+
+ todays_date += one_day;
+ }
+ return max_date;
+}
+
+boost::gregorian::date CronAttr::next_date(const ecf::Calendar& calendar) const
+{
+ // Find the next date that matches, day of week, day of year, and month
+ // that is greater than todays date. This *ASSUMES* day of week, day of month,
+ // and month is *ANDED* together
+
+ boost::gregorian::date_duration one_day(1);
+ boost::gregorian::date future_date = calendar.date(); // todays date
+ future_date += one_day; // add one day, so its in the future
+
+ while ( 1 ) {
+
+ bool week_day_matches = weekDays_.empty(); // week day matches if no week days
+ bool day_of_month_matches = daysOfMonth_.empty(); // day of month if no days of month
+ bool month_matches = months_.empty(); // month matches if no months
+
+ // deal with case where we have: cron -w 0,1
+ for (size_t i = 0; i < weekDays_.size(); ++i) {
+ if ( future_date.day_of_week().as_number() == weekDays_[i] ) {
+ week_day_matches = true;
+ break;
+ }
+ }
+
+ // deal with case where we have: cron -w 0,1 -d 14,15,16
+ for (size_t d = 0; d < daysOfMonth_.size(); ++d) {
+ if ( future_date.day() == daysOfMonth_[d] ) {
+ day_of_month_matches = true;
+ break;
+ }
+ }
+
+ // deal with case where we have: cron -w 0,1 -d 14,15,16 -m 8, 9
+ for (size_t m = 0; m < months_.size(); ++m) {
+ if ( future_date.month() == months_[m] ) {
+ month_matches = true;
+ break;
+ }
+ }
+
+ // if it all matches, then return the future day
+ if ( week_day_matches && day_of_month_matches && month_matches) {
+ break; // return future_date, replaced with break to keep HPUX compiler happy
+ // otherwise it complains that return at the end of the function is
+ // unreachable
+ }
+
+ future_date += one_day;
+ }
+ return future_date; // should never happen, i.e we can find future date that matches
+}
+
+
+//=========================================================================================================
+// code for parsing a cron:
+
+static bool isComment(const std::string& token)
+{
+ if (token.find("#") == std::string::npos) return false;
+ return true;
+}
+
+static bool isTimeSpec(const std::string& token)
+{
+ if (token.find(Str::COLON()) == std::string::npos) return false;
+ return true;
+}
+
+static bool isOption(const std::string& token)
+{
+ if (token.find("-w") != std::string::npos) return true;
+ if (token.find("-d") != std::string::npos) return true;
+ if (token.find("-m") != std::string::npos) return true;
+ return false;
+}
+
+static std::string nextToken( size_t& index, const std::vector<std::string >& lineTokens)
+{
+ assert(index < lineTokens.size());
+ index++;
+ if (index < lineTokens.size()) {
+#ifdef DEBUG_CRON_PARSING
+ cerr << "nextToken lineTokens[" << index << "] = " << lineTokens[index] << "\n";
+#endif
+ return lineTokens[index];
+ }
+#ifdef DEBUG_CRON_PARSING
+ cerr << "nextToken empty \n";
+#endif
+ return string();
+}
+
+std::vector<int> extractOption(
+ size_t& index,
+ const std::vector<std::string >& lineTokens,
+ const std::string& option)
+{
+ // cron -w 0 -m 5,6,7,8 10:00 20:00 01:00
+ assert(index < lineTokens.size());
+
+ // Collate the list of integers, these may have been separated by spaces
+ // since we stop on option or time spec, the top level code should decrement index
+ std::string theIntList;
+ while ( index < lineTokens.size() && ( !isOption(lineTokens[index]) || !isTimeSpec(lineTokens[index]) )) {
+ string theNextToken = nextToken(index,lineTokens);
+ if (theNextToken.empty()) break;
+ if (isOption( theNextToken )) break;
+ if (isTimeSpec( theNextToken )) break;
+ theIntList += theNextToken;
+ }
+#ifdef DEBUG_CRON_PARSING
+ cerr << "theIntList = " << theIntList << "\n";
+#endif
+
+ // should have 0,1,2,3
+ std::vector< int > theIntVec;
+ char_separator< char > sep( ",", 0, boost::drop_empty_tokens );
+ typedef boost::tokenizer< boost::char_separator< char > > tokenizer;
+ tokenizer theTokenizer( theIntList, sep );
+
+ for (tokenizer::iterator beg = theTokenizer.begin(); beg != theTokenizer.end(); ++beg) {
+ string theIntToken = *beg;
+ boost::algorithm::trim( theIntToken );
+ if ( theIntToken.empty() ) continue;
+
+ try {
+ int theInt = boost::lexical_cast< int >( theIntToken );
+ theIntVec.push_back( theInt );
+ }
+ catch ( boost::bad_lexical_cast& ) {
+ std::stringstream ss; ss << "Invalid cron option: " << option ;
+ throw std::runtime_error( ss.str() );
+ }
+ }
+ return theIntVec;
+}
+
+void extractOption(CronAttr& cronAttr, size_t& index, const std::vector<std::string >& lineTokens)
+{
+ assert(index < lineTokens.size());
+ if (lineTokens[index] == "-w") {
+ cronAttr.addWeekDays( extractOption(index, lineTokens, "week days" ) );
+ }
+ else if (lineTokens[index] == "-d") {
+ cronAttr.addDaysOfMonth( extractOption(index, lineTokens, "Days of the month" ) );
+ }
+ else if (lineTokens[index] == "-m") {
+ cronAttr.addMonths( extractOption(index, lineTokens,"Months" ) );
+ }
+ else throw std::runtime_error( "extractOption: Invalid cron option :" + lineTokens[index] );
+}
+
+void CronAttr::parse( CronAttr& cronAttr, const std::vector<std::string>& lineTokens, size_t index, bool parse_state )
+{
+ // cron 23:00 # run every day at 23:00
+ // cron 10:00 20:00 01:00 # run every hour between 10am and 8pm
+ // cron -w 0,1 10:00 # run every sunday and monday at 10am
+ // cron -d 10,11,12 12:00 # run 10th, 11th and 12th of each month at noon
+ // cron -m 1,2,3 12:00 # run on Jan,Feb and March every day at noon.
+ // cron -w 0 -m 5,6,7,8 10:00 20:00 01:00 # run every sunday, between May-Aug, every hour between 10am and 8pm
+
+ // make *sure* a time spec is specified
+ bool time_spec_specified = false;
+ while (index < lineTokens.size() ) {
+
+ std::string token = lineTokens[index];
+#ifdef DEBUG_CRON_PARSING
+ cerr << "CronAttr::doParse " << token << "\n";
+#endif
+ if (isOption(token)) {
+#ifdef DEBUG_CRON_PARSING
+ cerr << "CronAttr::doParse isOption \n";
+#endif
+ extractOption(cronAttr,index,lineTokens);
+ index--; // since we did a look ahead
+ }
+ else if (!time_spec_specified && isTimeSpec(token)) {
+#ifdef DEBUG_CRON_PARSING
+ cerr << "CronAttr::doParse isTimeSpec \n";
+#endif
+ // index is passed by *reference*, and used skip over time series
+ cronAttr.addTimeSeries( TimeSeries::create(index,lineTokens, parse_state) );
+ time_spec_specified = true;
+ if (parse_state) {
+ // if index is on the comment, back track, so that we can add cron state( free)
+ if (index < lineTokens.size() && lineTokens[index] == "#") {
+ index--;
+ }
+ }
+ else break; // need to read state after comment
+ }
+ else if (isComment(token)) {
+ // cron -m 1,2,3 12:00 # free
+ if (parse_state && index+1 < lineTokens.size()) {
+ if ( lineTokens[index+1] == "free") {
+ cronAttr.setFree();
+ }
+ }
+ break;
+ }
+ index++;
+ }
+
+ if (!time_spec_specified) {
+ throw std::runtime_error( "Invalid cron, no time specified");
+ }
+
+#ifdef DEBUG_CRON_PARSING
+ cronAttr.print(cerr); cerr <<"\n";
+#endif
+}
+
+CronAttr CronAttr::create(const std::string& cronString)
+{
+ std::vector<std::string> lineTokens;
+ Str::split(cronString,lineTokens);
+
+ CronAttr theCronAttr;
+ if ( lineTokens.empty() ) {
+ return theCronAttr;
+ }
+
+ // adjust the index
+ size_t index = 0;
+ if ( lineTokens[0] == "cron") {
+ index = 1;
+ }
+
+ parse(theCronAttr,lineTokens,index);
+ return theCronAttr;
+}
+
+
+}
+
diff --git a/ANattr/src/CronAttr.hpp b/ANattr/src/CronAttr.hpp
new file mode 100644
index 0000000..891bfeb
--- /dev/null
+++ b/ANattr/src/CronAttr.hpp
@@ -0,0 +1,140 @@
+#ifndef CRONATTR_HPP_
+#define CRONATTR_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #32 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "TimeSeries.hpp"
+#include <boost/serialization/vector.hpp> // no need to include <vector>
+#include <boost/serialization/level.hpp>
+#include <boost/serialization/tracking.hpp>
+
+namespace ecf { class Calendar;} // forward declare class
+
+namespace ecf {
+
+// *****************************************************************
+// A cron attribute with a single time slot is repeated indefinitely
+// ******************************************************************
+// Use compiler , destructor, assignment, copy constructor,
+class CronAttr {
+public:
+ CronAttr();
+
+ std::ostream& print(std::ostream&) const;
+ bool operator==(const CronAttr& rhs) const;
+ bool operator<(const CronAttr& rhs) const { return timeSeries_ < rhs.timeSeries_; }
+ bool structureEquals(const CronAttr& rhs) const;
+
+ void addWeekDays( const std::vector<int>& w);
+ void addDaysOfMonth( const std::vector<int>& d);
+ void addMonths( const std::vector<int>& m);
+
+ void addTimeSeries( const TimeSlot& s, const TimeSlot& f, const TimeSlot& i) { timeSeries_ = TimeSeries(s,f,i);}
+ void addTimeSeries( const TimeSeries& ts ) { timeSeries_ = ts;}
+ void add_time_series( int h, int m, bool relative = false ) { timeSeries_ = TimeSeries(h,m,relative);}
+
+ // Once a cron is free its stays free, until re-queue is called
+ void calendarChanged( const ecf::Calendar& c ); // can set attribute free
+ void resetRelativeDuration();
+
+ void reset(const ecf::Calendar& c);
+ void requeue(const ecf::Calendar& c,bool reset_next_time_slot = true);
+
+ void miss_next_time_slot();
+ void setFree(); // ensures that isFree() always returns true
+ bool isSetFree() const { return makeFree_; }
+ bool isFree( const ecf::Calendar&) const;
+ bool checkForRequeue( const ecf::Calendar&) const;
+ bool validForHybrid(const ecf::Calendar&) const;
+ bool why(const ecf::Calendar&, std::string& theReasonWhy) const;
+
+ // The state_change_no is never reset. Must be incremented if it can affect equality
+ // Note: changes in state of timeSeries_, i.e affect the equality operator (used in test)
+ // must be captured. i.e things like relative duration & next_time_slot are
+ // reported by the Why command, & hence need to be synced.
+ unsigned int state_change_no() const { return state_change_no_; }
+
+ bool checkInvariants(std::string& errormsg) const;
+
+ //Query:
+ const TimeSeries& time() const { return timeSeries_;}
+ const TimeSeries& time_series() const { return timeSeries_;}
+ std::vector<int>::const_iterator week_days_begin() const { return weekDays_.begin();}
+ std::vector<int>::const_iterator week_days_end() const { return weekDays_.end(); }
+ std::vector<int>::const_iterator days_of_month_begin() const { return daysOfMonth_.begin();}
+ std::vector<int>::const_iterator days_of_month_end() const { return daysOfMonth_.end(); }
+ std::vector<int>::const_iterator months_begin() const { return months_.begin();}
+ std::vector<int>::const_iterator months_end() const { return months_.end(); }
+
+ std::string name() const { return toString(); } /* ABO */
+ std::string toString() const;
+ std::string dump() const;
+
+ /// parse the line tokens an create a cron attribute. Can throw std::runtime_error
+ /// The index parameter allows us to parse:
+ /// cron -w 0,1 10:00 // index = 1
+ /// -w 0,1 10:00 // index = 0
+ /// Expect to parse:
+ /// cron 23:00 # run every day at 23:00
+ /// cron 10:00 20:00 01:00 # run every hour between 10am and 8pm
+ /// cron -w 0,1 10:00 # run every sunday and monday at 10am
+ /// cron -d 10,11,12 12:00 # run 10th, 11th and 12th of each month at noon
+ /// cron -m 1,2,3 12:00 # run on Jan,Feb and March every day at noon.
+ /// cron -w 0 -m 5,6,7,8 10:00 20:00 01:00 # run every sunday, between May-Aug, every hour between 10am and 8pm
+ static void parse( CronAttr&, const std::vector<std::string >& lineTokens, size_t index, bool parse_state = false );
+ static CronAttr create(const std::string& cronString);
+
+private:
+ void clearFree(); // resets the free flag
+ bool is_day_of_week_day_of_month_and_month_free( const ecf::Calendar&) const;
+
+ bool week_day_matches(int) const;
+ bool day_of_month_matches(int) const;
+ bool month_matches(int) const;
+
+// int max_month() const;
+// int max_day_of_month() const;
+// int max_day_of_week() const;
+// int min_month() const;
+// int min_day_of_month() const;
+// int min_day_of_week() const;
+
+ boost::gregorian::date last_day_of_month(const ecf::Calendar& calendar) const;
+ boost::gregorian::date next_date(const ecf::Calendar& calendar) const;
+
+ TimeSeries timeSeries_;
+ std::vector<int> weekDays_;
+ std::vector<int> daysOfMonth_;
+ std::vector<int> months_;
+ bool makeFree_; // persisted for use by why() on client side
+ unsigned int state_change_no_; // *not* persisted, only used on server side
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/) {
+ ar & timeSeries_;
+ ar & weekDays_;
+ ar & daysOfMonth_;
+ ar & months_;
+ ar & makeFree_;
+ }
+};
+}
+
+// This should ONLY be added to objects that are *NOT* serialised through a pointer
+BOOST_CLASS_IMPLEMENTATION(ecf::CronAttr, boost::serialization::object_serializable);
+BOOST_CLASS_TRACKING(ecf::CronAttr,boost::serialization::track_never);
+
+#endif /* CRONATTR_HPP_ */
diff --git a/ANattr/src/DateAttr.cpp b/ANattr/src/DateAttr.cpp
new file mode 100644
index 0000000..ae7c104
--- /dev/null
+++ b/ANattr/src/DateAttr.cpp
@@ -0,0 +1,298 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #31 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <assert.h>
+#include <sstream>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include "DateAttr.hpp"
+#include "Extract.hpp"
+#include "Indentor.hpp"
+#include "Calendar.hpp"
+#include "PrintStyle.hpp"
+#include "Ecf.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+
+//==========================================================================================
+
+DateAttr::DateAttr( int day, int month, int year )
+: day_( day ), month_( month ), year_( year ), makeFree_( false ), state_change_no_(0)
+{
+ checkDate(day_,month_,year_,true /* allow wild cards */);
+}
+
+bool DateAttr::operator<(const DateAttr& rhs) const {
+ if (year_ < rhs.year_) return true;
+ if (year_ == rhs.year_) {
+ if (month_ < rhs.month_ ) return true;
+ if (month_ == rhs.month_) {
+ return day_ < rhs.day_;
+ }
+ }
+ return false;
+}
+
+void DateAttr::checkDate(int day, int month, int year, bool allow_wild_cards)
+{
+ if (allow_wild_cards) {
+ if (day != 0 && (day < 1 || day > 31 )) {
+ throw std::out_of_range( "Invalid Date(day,month,year) : the day >= 0 and day < 31, where 0 means wild card ");
+ }
+ if (month !=0 && ( month < 1 || month > 12 )) {
+ throw std::out_of_range( "Invalid Date(day,month,year): the month >=0 and month <= 12, where 0 means wild card");
+ }
+ if (year < 0) {
+ throw std::out_of_range( "Invalid Date(day,month,year): the year >=0, where 0 means wild card");
+ }
+ }
+ else {
+ if (day < 1 || day > 31 ) {
+ throw std::out_of_range( "Invalid date attribute : the day >= 1 and day < 31");
+ }
+ if (month < 1 || month > 12 ) {
+ throw std::out_of_range( "Invalid date attribute: the month >=1 and month <= 12");
+ }
+ if (year <= 0) {
+ throw std::out_of_range( "Invalid date attribute: the year >0");
+ }
+ }
+
+ if ( day != 0 && month != 0 && year != 0 ) {
+
+ // let boost validate the date
+ boost::gregorian::date theDate( year, month, day );
+ }
+}
+
+void DateAttr::calendarChanged( const ecf::Calendar& c )
+{
+ // See ECFLOW-337
+ if (c.dayChanged()) {
+ clearFree();
+ }
+
+ if (makeFree_) {
+ return;
+ }
+ else if (isFree(c)) {
+ setFree();
+ }
+}
+
+void DateAttr::setFree() {
+ makeFree_ = true;
+ state_change_no_ = Ecf::incr_state_change_no();
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "DateAttr::setFree()\n";
+#endif
+}
+
+void DateAttr::clearFree() {
+ makeFree_ = false;
+ state_change_no_ = Ecf::incr_state_change_no();
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "DateAttr::clearFree()\n";
+#endif
+}
+
+bool DateAttr::isFree(const ecf::Calendar& calendar) const
+{
+ // The FreeDepCmd can be used to free the dates,
+ if (makeFree_) {
+ return true;
+ }
+ return is_free(calendar);
+}
+
+bool DateAttr::is_free(const ecf::Calendar& calendar) const
+{
+ bool dayMatches = true;
+ bool monthMatches = true;
+ bool yearMatches = true;
+ if (day_ != 0) dayMatches = calendar.day_of_month() == day_;
+ if (month_ != 0) monthMatches = calendar.month() == month_;
+ if (year_ != 0) yearMatches = calendar.year() == year_;
+
+ return ( dayMatches && monthMatches && yearMatches);
+}
+
+bool DateAttr::checkForRequeue( const ecf::Calendar& calendar) const
+{
+ // if calendar is hybrid, we can't re-queue
+ if (calendar.hybrid()) {
+ return false;
+ }
+
+ // checkForRequeue is called when we are deciding whether to re-queue the node.
+ // If this date is in the future, they we should re-queue
+ if ( day_ != 0 && month_ != 0 && year_ != 0) {
+ date theDate(year_,month_,day_);
+ if (theDate > calendar.date()) {
+//#ifdef DEBUG
+// cout << toString() << " > " << " calendar date " << to_simple_string( calendar.date()) << "\n";
+//#endif
+ return true;
+ }
+ return false;
+ }
+
+ bool futureDayMatches = true;
+ bool futureMonthMatches = true;
+ bool futureYearMatches = true;
+ if (day_ != 0) futureDayMatches = day_ > calendar.day_of_month() ;
+ if (month_ != 0) futureMonthMatches = month_ > calendar.month() ;
+ if (year_ != 0) futureYearMatches = year_ > calendar.year() ;
+
+//#ifdef DEBUG
+// if ( futureDayMatches ) {
+// cout << "futureDayMatches " << toString() << " > " << calendar.day_of_month() << "\n";
+// }
+// if ( futureMonthMatches ) {
+// cout << "futureMonthMatches " << toString() << " > " << calendar.month() << "\n";
+// }
+// if ( futureYearMatches ) {
+// cout << "futureYearMatches " << toString() << " > " << calendar.year() << "\n";
+// }
+//#endif
+
+ return ( futureDayMatches || futureMonthMatches || futureYearMatches);
+}
+
+bool DateAttr::validForHybrid(const ecf::Calendar& calendar) const
+{
+ if (day_ == 0) return false; // relies on day change i.e. date *.10.2009
+ if (month_ == 0) return false; // relies on day change i.e. date 12.*.2009
+ if (year_ == 0) return false; // relies on day change i.e. date 12.10.*
+
+ // if the date matches exactly for today
+ return (day_ == calendar.day_of_month() && month_ == calendar.month() && year_ == calendar.year() );
+}
+
+bool DateAttr::why(const ecf::Calendar& c, std::string& theReasonWhy) const
+{
+ if (isFree(c)) return false;
+
+ std::stringstream ss;
+ ss << " is date dependent ( next run on " << toString() << " the current date is ";
+ ss << c.day_of_month() << "/" << c.month() << "/" << c.year() << " )";
+ theReasonWhy += ss.str();
+ return true;
+}
+
+std::ostream& DateAttr::print(std::ostream& os) const
+{
+ Indentor in;
+ Indentor::indent(os) << toString();
+ if (!PrintStyle::defsStyle()) {
+ if (makeFree_) os << " # free";
+ }
+ os << "\n";
+ return os;
+}
+
+std::string DateAttr::toString() const
+{
+ std::stringstream ss;
+ ss << "date ";
+ if (day_ == 0) ss << "*.";
+ else ss << day_ << ".";
+
+ if (month_ == 0) ss << "*.";
+ else ss << month_ << ".";
+
+ if (year_ == 0) ss << "*";
+ else ss << year_;
+
+ return ss.str();
+}
+
+std::string DateAttr::dump() const
+{
+ std::stringstream ss; ss << toString();
+ if (makeFree_) ss << " (free)";
+ else ss << " (holding)";
+ return ss.str();
+}
+
+
+bool DateAttr::operator==(const DateAttr& rhs) const
+{
+ if (makeFree_ != rhs.makeFree_) {
+ return false;
+ }
+ return structureEquals(rhs);
+}
+bool DateAttr::structureEquals(const DateAttr& rhs) const
+{
+ if (day_ != rhs.day_) return false;
+ if (month_ != rhs.month_) return false;
+ if (year_ != rhs.year_) return false;
+ return true;
+}
+
+DateAttr DateAttr::create(const std::string& dateString)
+{
+ int day = -1,month = -1,year = -1;
+ getDate(dateString,day,month,year);
+ return DateAttr(day,month,year);
+}
+
+void DateAttr::getDate(const std::string& date,int& day,int& month,int& year)
+{
+ size_t firstDotPos = date.find_first_of('.');
+ size_t lastDotPos = date.find_first_of('.',firstDotPos+1);
+ if (firstDotPos == std::string::npos) throw std::runtime_error( "DateAttr::getDate Invalid date missing first dot :" + date );
+ if (lastDotPos == std::string::npos) throw std::runtime_error( "DateAttr::getDate: Invalid date missing second dot :" + date );
+ if (firstDotPos == lastDotPos) throw std::runtime_error( "DateAttr::getDate: Invalid date :" + date );
+
+
+ std::string theDay = date.substr(0,firstDotPos);
+ std::string theMonth = date.substr(firstDotPos+1, (lastDotPos-firstDotPos)-1);
+ std::string theYear = date.substr(lastDotPos+1);
+
+ if (theDay == "*") day = 0;
+ else {
+ day = Extract::theInt(theDay,"DateAttr::getDate: Invalid day :" + date);
+ if (day < 1 || day > 31) throw std::runtime_error("DateAttr::getDate: Invalid clock date: " + date );
+ }
+
+
+ if (theMonth == "*") month = 0;
+ else {
+ month = Extract::theInt(theMonth,"DateAttr::getDate: Invalid month :" + date);
+ if (month < 1 || month > 12) throw std::runtime_error("DateAttr::getDate Invalid clock date: " + date );
+ }
+
+ if (theYear == "*") year = 0;
+ else year = Extract::theInt(theYear,"DateAttr::getDate: Invalid year :" + date);
+
+
+ if (day == -1 || month == -1 || year == -1) throw std::runtime_error("DateAttr::getDate: Invalid clock date:" + date );
+
+ // let boost validate the date
+ if ( day != 0 && month != 0 && year != 0) {
+
+ boost::gregorian::date theDate(year,month,day);
+ }
+
+// cerr << " DateParser::getDate date=" << date << " day=" << day << " month=" << month << " year=" << year << "\n";
+}
+
diff --git a/ANattr/src/DateAttr.hpp b/ANattr/src/DateAttr.hpp
new file mode 100644
index 0000000..383c032
--- /dev/null
+++ b/ANattr/src/DateAttr.hpp
@@ -0,0 +1,102 @@
+#ifndef DATEATTR_HPP_
+#define DATEATTR_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #24 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Note: calendarChanged() once a Date is free, it stays free
+// It relies on parent cron/repeat to re-queue
+//============================================================================
+
+#include <ostream>
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/level.hpp>
+#include <boost/serialization/tracking.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+namespace ecf { class Calendar;} // forward declare class that is in a name space
+
+// Use default copy constructor, assignment operator, destructor
+// Value of 0 for day,month,year means *, i.e. means any value
+class DateAttr {
+public:
+ DateAttr(int day, int month, int year); // will throw std::out_of_range for if invalid date
+ DateAttr()
+ : day_(0), month_(0), year_(0), makeFree_(false),
+ state_change_no_(0) {} // for serialisation
+ DateAttr(const boost::gregorian::date& date)
+ : day_(date.day()), month_(date.month()), year_(date.year()), makeFree_(false),
+ state_change_no_(0) {} // for test
+
+ std::ostream& print(std::ostream&) const;
+ bool operator==(const DateAttr& rhs) const;
+ bool operator<(const DateAttr& rhs) const;
+ bool structureEquals(const DateAttr& rhs) const;
+
+ void setFree(); // ensures that isFree() always returns true
+ void clearFree(); // resets the free flag
+ bool isSetFree() const { return makeFree_; }
+ void calendarChanged( const ecf::Calendar& c ); // can set attribute free
+ bool isFree(const ecf::Calendar&) const;
+ bool checkForRequeue( const ecf::Calendar&) const;
+ bool validForHybrid(const ecf::Calendar&) const;
+ bool why(const ecf::Calendar&, std::string& theReasonWhy) const;
+
+ // The state_change_no is never reset. Must be incremented if it can affect equality
+ unsigned int state_change_no() const { return state_change_no_; }
+
+ std::string name() const { return toString(); } /* ABO */
+ std::string toString() const;
+ std::string dump() const;
+
+ /// Check the date, will throw std::out_of_range or derivative if invalid
+ static void checkDate(int day, int month, int year, bool allow_wild_cards);
+
+ /// Extract the date, if return integer is zero, date was of the *, i.e. any day,month,year
+ /// will throw std::runtime_error for parse errors
+ /// expect:
+ /// 15.11.2009
+ /// 15.*.*
+ /// *.1.*
+ static void getDate(const std::string& date,int& day,int& month,int& year);
+ static DateAttr create(const std::string& dateString);
+
+ // access
+ int day() const { return day_; }
+ int month() const { return month_; }
+ int year() const { return year_; }
+
+private:
+ bool is_free(const ecf::Calendar&) const; // ignores makeFree_
+
+private:
+ int day_;
+ int month_;
+ int year_;
+ bool makeFree_; // persisted for use by why() on client side
+ unsigned int state_change_no_; // *not* persisted, only used on server side
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/)
+ {
+ ar & day_;
+ ar & month_;
+ ar & year_;
+ ar & makeFree_;
+ }
+};
+
+// This should ONLY be added to objects that are *NOT* serialised through a pointer
+BOOST_CLASS_IMPLEMENTATION(DateAttr, boost::serialization::object_serializable);
+BOOST_CLASS_TRACKING(DateAttr,boost::serialization::track_never);
+
+#endif
diff --git a/ANattr/src/DayAttr.cpp b/ANattr/src/DayAttr.cpp
new file mode 100644
index 0000000..22812cf
--- /dev/null
+++ b/ANattr/src/DayAttr.cpp
@@ -0,0 +1,196 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #32 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <assert.h>
+#include <sstream>
+
+#include "DayAttr.hpp"
+#include "Indentor.hpp"
+#include "Calendar.hpp"
+#include "PrintStyle.hpp"
+#include "Ecf.hpp"
+
+using namespace std;
+using namespace ecf;
+
+//===============================================================================
+
+static std::string theDay(DayAttr::Day_t day)
+{
+ switch (day) {
+ case DayAttr::SUNDAY: return "sunday"; break;
+ case DayAttr::MONDAY: return "monday"; break;
+ case DayAttr::TUESDAY: return "tuesday"; break;
+ case DayAttr::WEDNESDAY: return "wednesday"; break;
+ case DayAttr::THURSDAY: return "thursday"; break;
+ case DayAttr::FRIDAY: return "friday"; break;
+ case DayAttr::SATURDAY: return "saturday"; break;
+ default: assert(false);break;
+ }
+ return std::string();
+}
+
+//===============================================================================
+
+void DayAttr::calendarChanged( const ecf::Calendar& c )
+{
+ // See ECFLOW-337
+ if (c.dayChanged()) {
+ clearFree();
+ }
+ if (makeFree_) {
+ return;
+ }
+ else if (isFree(c)) {
+ setFree();
+ }
+}
+
+bool DayAttr::isFree(const ecf::Calendar& calendar) const
+{
+ // The FreeDepCmd can be used to free the dates,
+ if (makeFree_) {
+ return true;
+ }
+ return is_free(calendar);
+}
+
+bool DayAttr::is_free(const ecf::Calendar& calendar) const
+{
+ return (calendar.day_of_week() == day_);
+}
+
+void DayAttr::setFree() {
+ makeFree_ = true;
+ state_change_no_ = Ecf::incr_state_change_no();
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "DayAttr::setFree()\n";
+#endif
+}
+
+void DayAttr::clearFree() {
+ makeFree_ = false;
+ state_change_no_ = Ecf::incr_state_change_no();
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "DayAttr::clearFree()\n";
+#endif
+}
+
+bool DayAttr::checkForRequeue( const ecf::Calendar& calendar) const
+{
+ // if calendar is hybrid, we can't requeue
+ if (calendar.hybrid()) {
+ return false;
+ }
+
+ // checkForRequeue is called when we are deciding whether to re-queue the node.
+ // If this date is in the future, they we should re-queue
+ return (day_ > calendar.day_of_week() );
+}
+
+bool DayAttr::validForHybrid(const ecf::Calendar& calendar) const
+{
+ return isFree(calendar);
+}
+
+bool DayAttr::why(const ecf::Calendar& c, std::string& theReasonWhy) const
+{
+ if (isFree(c)) return false;
+
+ theReasonWhy += " is day dependent ( next run on ";
+ theReasonWhy += theDay(day_);
+ theReasonWhy += " the current day is ";
+ theReasonWhy += theDay(static_cast<DayAttr::Day_t>(c.day_of_week()));
+ theReasonWhy += " )";
+ return true;
+}
+
+std::ostream& DayAttr::print(std::ostream& os) const
+{
+ Indentor in;
+ Indentor::indent(os) << toString();
+ if (!PrintStyle::defsStyle()) {
+ if (makeFree_) os << " # free";
+ }
+ os << "\n";
+ return os;
+}
+
+std::string DayAttr::toString() const
+{
+ std::string ret = "day ";
+ ret += theDay(day_);
+ return ret;
+}
+
+std::string DayAttr::dump() const
+{
+ std::stringstream ss;
+ ss << toString();
+ if (makeFree_) ss << " (free)";
+ else ss << " (holding)";
+ return ss.str();
+}
+
+bool DayAttr::operator==(const DayAttr& rhs) const
+{
+ if (makeFree_ != rhs.makeFree_) {
+ return false;
+ }
+ return structureEquals(rhs);
+}
+
+bool DayAttr::structureEquals(const DayAttr& rhs) const
+{
+ return (day_ == rhs.day_);
+}
+
+
+DayAttr DayAttr::create(const std::string& dayStr)
+{
+ return DayAttr( getDay(dayStr) );
+}
+
+DayAttr::Day_t DayAttr::getDay(const std::string& day)
+{
+ if (day == "monday") return DayAttr::MONDAY;
+ if (day == "tuesday") return DayAttr::TUESDAY;
+ if (day == "wednesday") return DayAttr::WEDNESDAY;
+ if (day == "thursday") return DayAttr::THURSDAY;
+ if (day == "friday") return DayAttr::FRIDAY;
+ if (day == "saturday") return DayAttr::SATURDAY;
+ if (day == "sunday") return DayAttr::SUNDAY;
+
+ std::stringstream ss;
+ ss << "Invalid day(" << day << ") specification expected one of [monday,tuesday,wednesday,thursday,friday,saturday,sunday]: ";
+ throw std::runtime_error(ss.str());
+
+ return DayAttr::SUNDAY;
+}
+
+std::vector< std::string > DayAttr::allDays() {
+ std::vector< std::string > vec;
+ vec.reserve( 7 );
+ vec.push_back("monday");
+ vec.push_back("tuesday");
+ vec.push_back("wednesday");
+ vec.push_back("thursday");
+ vec.push_back("friday");
+ vec.push_back("saturday");
+ vec.push_back("sunday");
+ return vec;
+}
+
diff --git a/ANattr/src/DayAttr.hpp b/ANattr/src/DayAttr.hpp
new file mode 100644
index 0000000..8284432
--- /dev/null
+++ b/ANattr/src/DayAttr.hpp
@@ -0,0 +1,90 @@
+#ifndef DAYATTR_HPP_
+#define DAYATTR_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #27 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Note: calendarChanged() once a day is free, it stays free
+// It relies on parent cron/repeat to re-queue
+//============================================================================
+
+#include <ostream>
+#include <vector>
+#include <string>
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/level.hpp>
+#include <boost/serialization/tracking.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+namespace ecf { class Calendar;} // forward declare class that is in a name space
+
+// Use default copy constructor, assignment operator, destructor
+class DayAttr {
+public:
+ enum Day_t { SUNDAY=0, MONDAY=1, TUESDAY=2, WEDNESDAY=3, THURSDAY=4, FRIDAY=5, SATURDAY=6 };
+ DayAttr() : day_(DayAttr::SUNDAY), makeFree_(false),state_change_no_(0) {}
+ DayAttr(Day_t day) : day_(day), makeFree_(false),state_change_no_(0) {}
+ DayAttr(const boost::gregorian::date& date)
+ : day_(static_cast<DayAttr::Day_t>(date.day_of_week().as_number())), makeFree_(false),state_change_no_(0) {}
+
+ std::ostream& print(std::ostream&) const;
+ bool operator==(const DayAttr& rhs) const;
+ bool operator<(const DayAttr& rhs) const { return day_ < rhs.day_; }
+ bool structureEquals(const DayAttr& rhs) const;
+
+ void setFree(); // ensures that isFree() always returns true
+ void clearFree(); // resets the free flag
+ bool isSetFree() const { return makeFree_; }
+ void calendarChanged( const ecf::Calendar& c ) ; // can set attribute free
+ bool isFree(const ecf::Calendar&) const;
+ bool checkForRequeue( const ecf::Calendar&) const;
+ bool validForHybrid(const ecf::Calendar&) const;
+ bool why(const ecf::Calendar&, std::string& theReasonWhy) const;
+
+ // The state_change_no is never reset. Must be incremented if it can affect equality
+ unsigned int state_change_no() const { return state_change_no_; }
+
+ std::string name() const { return toString(); } /* ABO */
+ std::string toString() const;
+ std::string dump() const;
+
+ // return the days, if input is not valid will throw a runtime_error
+ static DayAttr create(const std::string& dayStr);
+ static DayAttr::Day_t getDay(const std::string&);
+
+ static std::vector<std::string> allDays();
+
+ // access
+ DayAttr::Day_t day() const { return day_;}
+
+private:
+ bool is_free(const ecf::Calendar&) const; // ignores makeFree_
+
+private:
+ DayAttr::Day_t day_;
+ bool makeFree_; // persisted for use by why() on client side
+ unsigned int state_change_no_; // *not* persisted, only used on server side
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/)
+ {
+ ar & day_;
+ ar & makeFree_;
+ }
+};
+
+// This should ONLY be added to objects that are *NOT* serialised through a pointer
+BOOST_CLASS_IMPLEMENTATION(DayAttr, boost::serialization::object_serializable);
+BOOST_CLASS_TRACKING(DayAttr,boost::serialization::track_never);
+
+
+#endif
diff --git a/ANattr/src/LateAttr.cpp b/ANattr/src/LateAttr.cpp
new file mode 100644
index 0000000..9813361
--- /dev/null
+++ b/ANattr/src/LateAttr.cpp
@@ -0,0 +1,241 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #16 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <sstream>
+#include <boost/foreach.hpp>
+
+#include "LateAttr.hpp"
+#include "Indentor.hpp"
+#include "Calendar.hpp"
+#include "Ecf.hpp"
+#include "PrintStyle.hpp"
+#include "TimeSeries.hpp"
+#include "Str.hpp"
+
+using namespace std;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+
+namespace ecf {
+
+LateAttr::LateAttr() : completeIsRelative_(false),isLate_(false),state_change_no_(0) {}
+
+std::ostream& LateAttr::print(std::ostream& os) const
+{
+ Indentor in;
+ Indentor::indent(os) << toString();
+ if (!PrintStyle::defsStyle()) {
+ if (isLate_) os << " # late";
+ }
+ os << "\n";
+ return os;
+}
+
+std::string LateAttr::toString() const
+{
+ std::string ret = "late";
+ if (!submitted_.isNULL()) {
+ ret += " -s +";
+ ret += submitted_.toString();
+ }
+ if (!active_.isNULL()) {
+ ret += " -a ";
+ ret += active_.toString();
+ }
+ if (!complete_.isNULL()) {
+ ret += " -c ";
+ if (completeIsRelative_) ret += "+";
+ ret += complete_.toString();
+ }
+ return ret;
+}
+
+bool LateAttr::operator==(const LateAttr& rhs) const
+{
+ if ( completeIsRelative_ != rhs.completeIsRelative_) return false;
+ if ( submitted_ != rhs.submitted_) return false;
+ if ( active_ != rhs.active_) return false;
+ if ( complete_ != rhs.complete_) return false;
+ if ( isLate_ != rhs.isLate_) return false;
+ return true;
+}
+
+bool LateAttr::isNull() const
+{
+ return ( submitted_.isNULL() && active_.isNULL() && complete_.isNULL());
+}
+
+void LateAttr::checkForLateness( const std::pair<NState,boost::posix_time::time_duration>& state,
+ const ecf::Calendar& calendar )
+{
+ if (isLate_ || isNull()) {
+ return;
+ }
+ if (check_for_lateness(state,calendar)) {
+ setLate(true);
+ }
+}
+
+bool LateAttr::check_for_lateness( const std::pair<NState,boost::posix_time::time_duration>& state, const ecf::Calendar& calendar ) const
+{
+ if (isNull()) return false;
+
+ if (state.first == NState::SUBMITTED || state.first == NState::QUEUED) {
+
+ // Submitted is always relative, ASSUME this means relative to suite start
+ if (state.first == NState::SUBMITTED && !submitted_.isNULL()) {
+
+ // ECFLOW-322
+ // The late attr check for being late in submitted state, is always *RELATIVE*
+ // Previously we had:
+ //
+ // if ( calendar.duration() >= submitted_.duration() ) {
+ // setLate(true);
+ // return;
+ // }
+ // This is incorrect since calendar.duration() is essentially duration until
+ // the last call to Calendar::init() i.e suite duration time. Hence late was
+ // set straight away.
+ //
+ // to check for submitted, we need the duration *after* state went into submitted state
+ // state.second is when state went SUBMITTED, relative to suite start
+ boost::posix_time::time_duration time_in_submitted_state = calendar.duration() - state.second ;
+ if ( time_in_submitted_state >= submitted_.duration()) {
+ return true;
+ }
+ }
+
+ // In Submitted or queued state, check for active, in REAL time
+ if (!active_.isNULL() && calendar.suiteTime().time_of_day() >= active_.duration()) {
+ return true;
+ }
+ }
+ else if ( state.first == NState::ACTIVE && !complete_.isNULL()) {
+ if ( completeIsRelative_) {
+ // to check for complete, we need the duration when state went into active state
+ // state.second is when state went ACTIVE, relative to suite start
+ boost::posix_time::time_duration runtime = calendar.duration() - state.second ;
+ if ( runtime >= complete_.duration()) {
+ return true;
+ }
+ }
+ else {
+ // Real time
+ if (calendar.suiteTime().time_of_day() >= complete_.duration()) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void LateAttr::setLate(bool f)
+{
+ if (f != isLate_) {
+ // minimise changes to state_change_no_
+ isLate_ = f;
+ state_change_no_ = Ecf::incr_state_change_no();
+ }
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "LateAttr::setLate changed=" << (f != isLate_) << "\n";
+#endif
+}
+
+void LateAttr::override_with(LateAttr* in_late)
+{
+ if (in_late) {
+ if (!in_late->submitted().isNULL()) submitted_ = in_late->submitted();
+ if (!in_late->active().isNULL()) active_ = in_late->active();
+ if (!in_late->complete().isNULL()) complete_ = in_late->complete();
+ completeIsRelative_ = in_late->complete_is_relative();
+
+ // DO NOT override isLate_, because if the parent is late, we do not want *ALL* children to be set late
+ // isLate_ = in_late->isLate();
+ }
+}
+
+void LateAttr::parse(LateAttr& lateAttr, const std::string& line, const std::vector<std::string>& lineTokens, size_t index )
+{
+ // late -s +00:15 -a 20:00 -c +02:00 #The option can be in any order
+ // 0 1 2 3 4 5 6 7 8 9 10 11 12 13
+ // late -s +00:15 -c +02:00 # not all options are needed
+ // 0 1 2 3 4 5
+
+ assert(lateAttr.isNull());
+
+ size_t line_token_size = lineTokens.size();
+ for(size_t i = index; i < line_token_size; i += 1) {
+ if (lineTokens[i][0] == '#') break;
+
+ if ( lineTokens[i] == "-s") {
+ if ( !lateAttr.submitted().isNULL() ) throw std::runtime_error( "LateParser::doParse: Invalid late, submitted specified twice :" + line );
+ if (i + 1 < line_token_size) {
+ int hour = -1; int min = -1;
+ TimeSeries::getTime(lineTokens[i+1],hour,min);
+ lateAttr.addSubmitted( TimeSlot(hour,min) );
+ i++;
+ }
+ else throw std::runtime_error( "LateParser::doParse: Invalid late, submitted time not specified :" + line );
+ }
+ else if ( lineTokens[i] == "-a") {
+ if ( !lateAttr.active().isNULL() ) throw std::runtime_error( "LateParser::doParse: Invalid late, active specified twice :" + line );
+ if (i + 1 < line_token_size) {
+ int hour = -1; int min = -1;
+ TimeSeries::getTime(lineTokens[i+1],hour,min);
+ lateAttr.addActive( TimeSlot(hour,min) );
+ i++;
+ }
+ else throw std::runtime_error( "LateParser::doParse: Invalid late, active time not specified :" + line );
+ }
+ else if ( lineTokens[i] == "-c") {
+ if ( !lateAttr.complete().isNULL() ) throw std::runtime_error( "LateParser::doParse: Invalid late, complete specified twice :" + line );
+ if (i + 1 < line_token_size) {
+ int hour = -1; int min = -1;
+ bool relative = TimeSeries::getTime(lineTokens[i+1],hour,min);
+ lateAttr.addComplete( TimeSlot(hour,min), relative );
+ i++;
+ }
+ else throw std::runtime_error( "LateParser::doParse: Invalid late, active time not specified :" + line );
+ }
+ else throw std::runtime_error( "LateParser::doParse:5: Invalid late :" + line );
+ }
+
+ if (lateAttr.isNull()) {
+ throw std::runtime_error( "LateParser::doParse:6: Invalid late :" + line );
+ }
+}
+
+LateAttr LateAttr::create(const std::string& lateString)
+{
+ std::vector<std::string> lineTokens;
+ Str::split(lateString,lineTokens);
+
+ if ( lineTokens.empty() ) {
+ throw std::runtime_error("LateParser::create: empty string no late specified ?" + lateString );
+ }
+
+ // adjust the index
+ size_t index = 0;
+ if ( lineTokens[0] == "late") {
+ index = 1;
+ }
+
+ LateAttr lateAttr;
+ parse(lateAttr,lateString,lineTokens,index);
+ return lateAttr;
+}
+
+
+}
diff --git a/ANattr/src/LateAttr.hpp b/ANattr/src/LateAttr.hpp
new file mode 100644
index 0000000..3888962
--- /dev/null
+++ b/ANattr/src/LateAttr.hpp
@@ -0,0 +1,117 @@
+#ifndef LATEATTR_HPP_
+#define LATEATTR_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #13 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include "TimeSlot.hpp"
+#include "NState.hpp"
+
+namespace ecf { class Calendar;} // forward declare class
+
+namespace ecf {
+/// ========================================================================
+/// Use compiler, destructor, assignment, copy constructor,
+///
+/// ************************************************************************
+/// late attribute: Only applies to a task, it can be set on suite/family
+/// but this is treated as an inherited attribute.
+/// late attribute lower down the hierarchy overrides it.
+/// ************************************************************************
+/// The late late attribute will not work correctly when the suites clock
+/// start and stops with the server. Since the late relies on real time
+/// for some of its functionality.
+/// -s submitted: The time node can stay submitted (format [+]hh:mm). submitted is always
+/// relative, so + is simple ignored, if present. If the node stays submitted
+/// longer than the time specified, the late flag is set
+/// -a Active : The time of day the node must have become active (format hh:mm). If the node
+/// is still queued or submitted, the late flag is set
+/// -c Complete : The time node must become complete (format {+}hh:mm). If relative, time is
+/// taken from the time the node became active, otherwise node must be complete by
+/// the time given.
+/// ========================================================================
+class LateAttr {
+public:
+ LateAttr();
+
+ std::ostream& print(std::ostream&) const;
+ bool operator==(const LateAttr& rhs) const;
+
+ void addSubmitted( const TimeSlot& s) { submitted_ = s; }
+ void add_submitted(int hour, int minute) { submitted_ = TimeSlot(hour,minute); }
+ void addActive( const TimeSlot& s ) { active_ = s; }
+ void add_active(int hour, int minute) { active_ = TimeSlot(hour,minute); }
+ void addComplete( const TimeSlot& s, bool relative) { complete_ = s; completeIsRelative_ = relative;}
+ void add_complete(int hour, int minute,bool relative) { complete_ = TimeSlot(hour,minute); completeIsRelative_ = relative; }
+
+ const TimeSlot& submitted() const { return submitted_; }
+ const TimeSlot& active() const { return active_; }
+ const TimeSlot& complete() const { return complete_; }
+ bool complete_is_relative() const { return completeIsRelative_; }
+
+ /// i.e no time structs specified
+ bool isNull() const;
+
+ /// Given the state and time of state change, and calendar work out if we are late
+ /// if we are sets the late flag
+ void checkForLateness( const std::pair<NState,boost::posix_time::time_duration>& state, const ecf::Calendar& c );
+ bool check_for_lateness( const std::pair<NState,boost::posix_time::time_duration>& state, const ecf::Calendar& c ) const;
+
+ /// To be used by GUI to inform used that a node is late
+ bool isLate() const { return isLate_;}
+
+ /// To be called at begin and re-queue time
+ void reset() { setLate(false); }
+
+ // Overide this late attributes with the settings form the input.
+ void override_with(LateAttr*);
+
+ // The state_change_no is never reset. Must be incremented if it can affect equality
+ unsigned int state_change_no() const { return state_change_no_; }
+
+ /// set flag to be late
+ void setLate(bool f);
+
+ std::string toString() const;
+ std::string name() const { return toString(); }
+
+ static void parse(LateAttr&, const std::string& line, const std::vector<std::string >& lineTokens, size_t index);
+ static LateAttr create(const std::string& lateString);
+
+private:
+
+ TimeSlot submitted_; // relative by default
+ TimeSlot active_;
+ TimeSlot complete_;
+
+ bool completeIsRelative_;
+ bool isLate_;
+
+ unsigned int state_change_no_; // *not* persisted, only used on server side
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/) {
+ ar & submitted_;
+ ar & active_;
+ ar & complete_;
+ ar & completeIsRelative_;
+ ar & isLate_;
+ }
+};
+
+}
+#endif
diff --git a/ANattr/src/NodeAttr.cpp b/ANattr/src/NodeAttr.cpp
new file mode 100644
index 0000000..fb91f99
--- /dev/null
+++ b/ANattr/src/NodeAttr.cpp
@@ -0,0 +1,366 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #67 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <assert.h>
+#include <sstream>
+
+#include <boost/foreach.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include "NodeAttr.hpp"
+#include "Indentor.hpp"
+#include "Calendar.hpp"
+#include "PrintStyle.hpp"
+#include "Str.hpp"
+#include "Ecf.hpp"
+
+using namespace std;
+using namespace ecf;
+
+const std::string& Event::SET() { static const std::string SET = "set"; return SET; }
+const std::string& Event::CLEAR() { static const std::string CLEAR = "clear"; return CLEAR; }
+const Event& Event::EMPTY() { static const Event EVENT = Event(); return EVENT ; }
+const Meter& Meter::EMPTY() { static const Meter METER = Meter(); return METER ; }
+const Label& Label::EMPTY() { static const Label LABEL = Label(); return LABEL ; }
+
+////////////////////////////////////////////////////////////////////////////////////////////
+
+Event::Event( int number, const std::string& eventName )
+: value_( false ), number_( number ), name_( eventName ), used_( false ), state_change_no_( 0 )
+{
+ if ( !eventName.empty() ) {
+ string msg;
+ if ( !Str::valid_name( eventName, msg ) ) {
+ throw std::runtime_error( "Event::Event: Invalid event name : " + msg );
+ }
+ }
+}
+
+Event::Event( const std::string& eventName )
+: value_( false ), number_( std::numeric_limits<int>::max() ), name_( eventName ), used_( false ), state_change_no_( 0 )
+{
+ if ( eventName.empty() ) {
+ throw std::runtime_error( "Event::Event: Invalid event name : name must be specified if no number supplied");
+ }
+
+ // If the eventName is a integer, then treat it as such, by setting number_ and clearing name_
+ // This was added after migration failed, since *python* api allowed:
+ // ta.add_event(1);
+ // ta.add_event("1");
+ // and when we called ecflow_client --migrate/--get it generated
+ // event 1
+ // event 1
+ // which then did *not* load.
+ //
+ // Test for numeric, and then casting, is ****faster***** than relying on exception alone
+ if ( eventName.find_first_of( Str::NUMERIC() ) != std::string::npos ) {
+ try {
+ number_ = boost::lexical_cast< int >( eventName );
+ name_.clear();
+ return;
+ }
+ catch ( boost::bad_lexical_cast& ) {
+ // cast failed, a real string, carry on
+ }
+ }
+
+ string msg;
+ if ( !Str::valid_name( eventName, msg ) ) {
+ throw std::runtime_error( "Event::Event: Invalid event name : " + msg );
+ }
+}
+
+void Event::set_value( bool b ) {
+ value_ = b;
+ state_change_no_ = Ecf::incr_state_change_no();
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Event::set_value\n";
+#endif
+}
+
+std::string Event::name_or_number() const {
+ if ( name_.empty() ) {
+ std::stringstream ss;
+ ss << number_;
+ return ss.str();
+ }
+ return name_;
+}
+
+bool Event::operator==( const Event& rhs ) const {
+ if ( value_ != rhs.value_ ) {
+ return false;
+ }
+ if ( number_ != rhs.number_ ) {
+ return false;
+ }
+ if ( name_ != rhs.name_ ) {
+ return false;
+ }
+ return true;
+}
+
+std::ostream& Event::print( std::ostream& os ) const {
+ Indentor in;
+ Indentor::indent( os ) << toString();
+ if ( !PrintStyle::defsStyle() ) {
+ if (value_) os << " # " << Event::SET();
+ }
+ os << "\n";
+ return os;
+}
+
+std::string Event::toString() const {
+ std::stringstream ss;
+ if ( number_ == std::numeric_limits< int >::max() )
+ ss << "event " << name_;
+ else ss << "event " << number_ << " " << name_;
+ return ss.str();
+}
+
+std::string Event::dump() const {
+ std::stringstream ss;
+ ss << toString() << " value(" << value_ << ") used(" << used_ << ")";
+ return ss.str();
+}
+
+bool Event::isValidState( const std::string& state ) {
+ if ( state == Event::SET() )
+ return true;
+ if ( state == Event::CLEAR() )
+ return true;
+ return false;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////
+
+Meter::Meter( const std::string& name, int min, int max, int colorChange ) :
+ min_( min ), max_( max ), value_( min ), colorChange_( colorChange ),
+ name_( name ), used_( false ), state_change_no_( 0 )
+{
+ if ( !Str::valid_name( name ) ) {
+ throw std::runtime_error("Meter::Meter: Invalid Meter name: " + name);
+ }
+
+ if ( min > max )
+ throw std::out_of_range( "Meter::Meter: Invalid Meter(name,min,max,color_change) : min must be less than max" );
+
+ if (colorChange == std::numeric_limits<int>::max()) {
+ colorChange_ = max_;
+ }
+
+ if ( colorChange_ < min || colorChange_ > max ) {
+ std::stringstream ss;
+ ss << "Meter::Meter: Invalid Meter(name,min,max,color_change) color_change(" << colorChange_ << ") must be between min(" << min_ << ") and max(" << max_ << ")";
+ throw std::out_of_range( ss.str() );
+ }
+}
+
+void Meter::set_value( int v ) {
+
+ if (!isValidValue( v )) {
+ std::stringstream ss;
+ ss << "Meter::set_value(int): The meter(" << name_ << ") value must be in the range[" << min() << "-" << max() << "] but found '" << v << "'";
+ throw std::runtime_error( ss.str() );
+ }
+
+ value_ = v;
+ state_change_no_ = Ecf::incr_state_change_no();
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Meter::set_value\n";
+#endif
+}
+
+bool Meter::operator==( const Meter& rhs ) const {
+ if ( value_ != rhs.value_ ) {
+ return false;
+ }
+ if ( min_ != rhs.min_ ) {
+ return false;
+ }
+ if ( max_ != rhs.max_ ) {
+ return false;
+ }
+ if ( colorChange_ != rhs.colorChange_ ) {
+ return false;
+ }
+ if ( name_ != rhs.name_ ) {
+ return false;
+ }
+ return true;
+}
+
+std::ostream& Meter::print( std::ostream& os ) const {
+ Indentor in;
+ Indentor::indent( os ) << toString();
+ if ( !PrintStyle::defsStyle() ) {
+ if (value_ != min_) os << " # " << value_;
+ }
+ os << "\n";
+ return os;
+}
+
+std::string Meter::toString() const {
+ std::stringstream ss;
+ ss << "meter " << name_ << " " << min_ << " " << max_ << " " << colorChange_;
+ return ss.str();
+}
+
+std::string Meter::dump() const {
+ std::stringstream ss;
+ ss << "meter " << name_ << " min(" << min_ << ") max (" << max_
+ << ") colorChange(" << colorChange_ << ") value(" << value_
+ << ") used(" << used_ << ")";
+ return ss.str();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+
+Label::Label(const std::string& name, const std::string& l)
+: name_(name),value_(l),state_change_no_(0)
+{
+ if ( !Str::valid_name( name ) ) {
+ throw std::runtime_error("Label::Label: Invalid Label name :" + name);
+ }
+}
+
+
+std::ostream& Label::print( std::ostream& os ) const {
+
+ Indentor in;
+ Indentor::indent( os ) << toString();
+ if (!PrintStyle::defsStyle()) {
+ if (!new_value_.empty()) {
+ if (new_value_.find("\n") == std::string::npos) {
+ os << " # \"" << new_value_ << "\"";
+ }
+ else {
+ std::string value = new_value_;
+ Str::replaceall(value,"\n","\\n");
+ os << " # \"" << value << "\"";
+ }
+ }
+ }
+ os << "\n";
+ return os;
+}
+
+std::string Label::toString() const {
+ // parsing always STRIPS the quotes, hence add them back
+ std::string ret; ret.reserve(name_.size() + value_.size() + 10);
+ ret += "label ";
+ ret += name_;
+ ret += " \"";
+ if (value_.find("\n") == std::string::npos) ret += value_;
+ else {
+ // replace \n, otherwise re-parse will fail
+ std::string value = value_;
+ Str::replaceall(value,"\n","\\n");
+ ret += value;
+ }
+ ret += "\"";
+ return ret;
+}
+
+std::string Label::dump() const {
+ std::stringstream ss;
+ ss << toString() << " : \"" << new_value_ << "\"";
+ return ss.str();
+}
+
+void Label::set_new_value( const std::string& l ) {
+ new_value_ = l;
+ state_change_no_ = Ecf::incr_state_change_no();
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Label::set_new_value\n";
+#endif
+}
+
+void Label::reset() {
+ new_value_.clear();
+ state_change_no_ = Ecf::incr_state_change_no();
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Label::reset()\n";
+#endif
+}
+
+
+void Label::parse(const std::string& line, std::vector<std::string >& lineTokens, bool parse_state)
+{
+ if ( lineTokens.size() < 3 )
+ throw std::runtime_error( "Label::parse: Invalid label :" + line );
+
+ name_ = lineTokens[1];
+
+ // parsing will always STRIP single or double quotes, print will add double quotes
+ // label simple_label 'ecgems'
+ if ( lineTokens.size() == 3 ) {
+ Str::removeQuotes(lineTokens[2]);
+ Str::removeSingleQuotes(lineTokens[2]);
+ value_ = lineTokens[2];
+ if (value_.find("\\n") != std::string::npos) {
+ Str::replaceall(value_,"\\n","\n");
+ }
+ }
+ else {
+
+ // label complex_label "smsfetch -F %ECF_FILES% -I %ECF_INCLUDE%" # fred
+ // label simple_label "fred" # "smsfetch -F %ECF_FILES% -I %ECF_INCLUDE%"
+ std::string value; value.reserve(line.size());
+ size_t line_token_size = lineTokens.size();
+ for (size_t i = 2; i < line_token_size; ++i) {
+ if ( lineTokens[i].at( 0 ) == '#' ) break;
+ if ( i != 2 ) value += " ";
+ value += lineTokens[i];
+ }
+
+ Str::removeQuotes(value);
+ Str::removeSingleQuotes(value);
+ value_ = value;
+ if (value_.find("\\n") != std::string::npos) {
+ Str::replaceall(value_,"\\n","\n");
+ }
+
+
+ // state
+ if (parse_state) {
+ // label name "value" # "new value"
+ bool comment_fnd = false;
+ size_t first_quote_after_comment = 0;
+ size_t last_quote_after_comment = 0;
+ for(size_t i = line.size()-1; i > 0; i--) {
+ if (line[i] == '#') { comment_fnd = true; break; }
+ if (line[i] == '"') {
+ if (last_quote_after_comment == 0) last_quote_after_comment = i;
+ first_quote_after_comment = i;
+ }
+ }
+ if (comment_fnd && first_quote_after_comment != last_quote_after_comment) {
+ std::string new_value = line.substr(first_quote_after_comment+1,last_quote_after_comment-first_quote_after_comment-1);
+ //std::cout << "new label = '" << new_value << "'\n";
+ new_value_ = new_value;
+
+ if (new_value_.find("\\n") != std::string::npos) {
+ Str::replaceall(new_value_,"\\n","\n");
+ }
+ }
+ }
+ }
+}
+
diff --git a/ANattr/src/NodeAttr.hpp b/ANattr/src/NodeAttr.hpp
new file mode 100644
index 0000000..f8ee5b4
--- /dev/null
+++ b/ANattr/src/NodeAttr.hpp
@@ -0,0 +1,211 @@
+#ifndef NODEATTR_HPP_
+#define NODEATTR_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #61 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <ostream>
+#include <vector>
+#include <limits> // for std::numeric_limits<int>::max()
+
+#include <boost/operators.hpp>
+#include <boost/utility.hpp>
+
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/set.hpp> // no need to include <set>
+#include <boost/serialization/string.hpp> // no need to include <string>
+#include <boost/serialization/level.hpp>
+#include <boost/serialization/tracking.hpp>
+
+////////////////////////////////////////////////////////////////////////////////////////
+// Class Label:
+// Use compiler , generated destructor, assignment, copy constructor
+class Label : public boost::equality_comparable<Label> {
+public:
+ Label(const std::string& name, const std::string& l);
+ Label() : state_change_no_(0) {}
+
+ std::ostream& print(std::ostream&) const;
+ const std::string& name() const { return name_;}
+ const std::string& value() const { return value_;}
+ const std::string& new_value() const { return new_value_;}
+ void set_new_value(const std::string& new_label);
+ void reset();
+ bool empty() const { return name_.empty(); }
+
+ // The state_change_no is never reset. Must be incremented if it can affect equality
+ unsigned int state_change_no() const { return state_change_no_; }
+
+ // 2 kinds of equality, structure and state
+ friend bool operator==(const Label& lhs,const Label& rhs) {
+ if (lhs.name_ != rhs.name_ ) {
+ //std::cout << "lhs.name_ '" << lhs.name_ << "' != rhs.name_ '" << rhs.name_ << "'\n";
+ return false;
+ }
+ if (lhs.new_value_ != rhs.new_value_) {
+ //std::cout << "lhs.new_value_ '" << lhs.new_value_ << "' != rhs.new_value_ '" << rhs.new_value_ << "'\n";
+ return false;
+ }
+ if ( lhs.value_ != rhs.value_ ) {
+ //std::cout << "lhs.value_ '" << lhs.value_ << "' != rhs.value_ '" << rhs.value_ << "'\n";
+ return false;
+ }
+ return true;
+ }
+
+ std::string toString() const;
+ std::string dump() const;
+
+ void parse(const std::string& line, std::vector<std::string >& lineTokens, bool parse_state);
+ static const Label& EMPTY(); // Added to support return by reference
+
+private:
+ std::string name_;
+ std::string value_;
+ std::string new_value_;
+ unsigned int state_change_no_; // *not* persisted, only used on server side
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/)
+ {
+ ar & name_;
+ ar & value_;
+ ar & new_value_;
+ }
+};
+
+
+// Class Event:
+// events with the number 007 are the same as 7.
+// Use compiler , generated destructor, assignment, copy constructor
+//
+// Don't use -1, to represent that no number was specified, as on
+// AIX portable binary archive can't cope with this
+// use std::numeric_limits<int>::max()
+class Event {
+public:
+ Event(int number, const std::string& eventName = "");
+ Event(const std::string& eventName);
+ Event()
+ : value_(false),
+ number_(std::numeric_limits<int>::max()),
+ used_(false),
+ state_change_no_(0){}
+
+ std::string name_or_number() const; // if name present return, else return number
+ const std::string& name() const { return name_;}
+ std::ostream& print(std::ostream&) const;
+ bool value() const { return value_;}
+ void reset() { set_value(false);}
+ bool empty() const { return (name_.empty() && number_ == std::numeric_limits<int>::max()); }
+
+ int number() const { return number_;}
+ bool operator==(const Event& rhs) const;
+ void set_value(bool b); // updates state_change_no_
+ bool usedInTrigger() const { return used_;}
+ void usedInTrigger(bool b) { used_ = b;}
+
+ unsigned int state_change_no() const { return state_change_no_;}
+
+ std::string toString() const;
+ std::string dump() const;
+
+ static bool isValidState(const std::string&); // return true for "set" | "clear"
+ static const std::string& SET();
+ static const std::string& CLEAR();
+ static const Event& EMPTY(); // Added to support return by reference
+
+private:
+ bool value_;
+ int number_;
+ std::string name_;
+ bool used_; // used by the simulator not persisted
+ unsigned int state_change_no_; // *not* persisted, only used on server side
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/)
+ {
+ ar & value_;
+ ar & number_;
+ ar & name_;
+ }
+};
+
+// Class Meter:
+// Use compiler , generated destructor, assignment, copy constructor
+// For this class we don't check the value member for the equality functionality
+// Can have negative min/max however max >= min, and color change should be in the
+// range min-max
+class Meter {
+public:
+ Meter(const std::string& name,int min, int max, int colorChange = std::numeric_limits<int>::max());
+ Meter() : min_(0),max_(0), value_(0),colorChange_(0),used_(false), state_change_no_(0){}
+
+ std::ostream& print(std::ostream&) const;
+ void reset() { set_value(min_);}
+ void set_value(int v); // can throw throw std::runtime_error if out of range
+ bool empty() const { return name_.empty(); }
+
+ const std::string& name() const { return name_;}
+ int value() const { return value_;}
+ int min() const { return min_;}
+ int max() const { return max_;}
+ int colorChange() const { return colorChange_;}
+
+ // The state_change_no is never reset. Must be incremented if it can affect equality
+ unsigned int state_change_no() const { return state_change_no_; }
+
+ bool operator==(const Meter& rhs) const;
+
+ bool usedInTrigger() const { return used_;}
+ void usedInTrigger(bool b) { used_ = b;}
+ std::string toString() const;
+ std::string dump() const;
+
+ static const Meter& EMPTY(); // Added to support return by reference
+
+private:
+
+ bool isValidValue(int v) const { return (v >= min_ && v <= max_); }
+
+ int min_;
+ int max_;
+ int value_;
+ int colorChange_;
+ std::string name_;
+ bool used_; // used by the simulator not persisted
+ unsigned int state_change_no_; // *not* persisted, only used on server side
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/)
+ {
+ ar & min_;
+ ar & max_;
+ ar & value_;
+ ar & colorChange_;
+ ar & name_;
+ }
+};
+
+// This should ONLY be added to objects that are *NOT* serialised through a pointer
+BOOST_CLASS_IMPLEMENTATION(Meter, boost::serialization::object_serializable);
+BOOST_CLASS_IMPLEMENTATION(Event, boost::serialization::object_serializable);
+BOOST_CLASS_IMPLEMENTATION(Label, boost::serialization::object_serializable);
+BOOST_CLASS_TRACKING(Meter,boost::serialization::track_never);
+BOOST_CLASS_TRACKING(Event,boost::serialization::track_never);
+BOOST_CLASS_TRACKING(Label,boost::serialization::track_never);
+#endif
diff --git a/ANattr/src/RepeatAttr.cpp b/ANattr/src/RepeatAttr.cpp
new file mode 100644
index 0000000..c2c1d7f
--- /dev/null
+++ b/ANattr/src/RepeatAttr.cpp
@@ -0,0 +1,974 @@
+//============================================================================
+// Name : NodeTree.cpp
+// Author : Avi
+// Revision : $Revision: #57 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <assert.h>
+#include <sstream>
+
+#include <boost/foreach.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/date_time/posix_time/time_formatters.hpp> // requires boost date and time lib
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include "RepeatAttr.hpp"
+#include "Indentor.hpp"
+#include "Ecf.hpp"
+#include "Log.hpp"
+#include "Str.hpp"
+#include "PrintStyle.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+
+const Repeat& Repeat::EMPTY() { static const Repeat REPEAT = Repeat(); return REPEAT; }
+
+//=========================================================================
+
+Repeat::Repeat() : repeatType_(NULL) {}
+Repeat::Repeat( const RepeatDate& r) : repeatType_(new RepeatDate(r)) {}
+Repeat::Repeat( const RepeatInteger& r) : repeatType_(new RepeatInteger(r)) {}
+Repeat::Repeat( const RepeatEnumerated& r) : repeatType_(new RepeatEnumerated(r)) {}
+Repeat::Repeat( const RepeatString& r) : repeatType_(new RepeatString(r)) {}
+Repeat::Repeat( const RepeatDay& r) : repeatType_(new RepeatDay(r)) {}
+
+Repeat::~Repeat() { delete repeatType_;}
+
+Repeat::Repeat( const Repeat& rhs) : repeatType_(NULL)
+{
+ // Do stuff that could throw exception first
+ RepeatBase* clone = NULL;
+ if ( rhs.repeatType_) {
+ clone = rhs.repeatType_->clone();
+ }
+
+ // Change state
+ repeatType_ = clone;
+}
+
+Repeat& Repeat::operator=(const Repeat& rhs)
+{
+ // Do stuff that could throw exception first
+ RepeatBase* clone = NULL;
+ if ( rhs.repeatType_) {
+ clone = rhs.repeatType_->clone();
+ }
+
+ // Change state
+ delete repeatType_; repeatType_ = NULL;
+ repeatType_ = clone;
+
+ return *this;
+}
+
+bool Repeat::operator==(const Repeat& rhs) const
+{
+ if (!repeatType_ && rhs.repeatType_) return false;
+ if (repeatType_ && !rhs.repeatType_) return false;
+ if (!repeatType_ && !rhs.repeatType_) return true ;
+ return repeatType_->compare(rhs.repeatType_);
+}
+
+const std::string& Repeat::name() const {
+ return (repeatType_) ? repeatType_->name() : Str::EMPTY();
+}
+
+const Variable& Repeat::gen_variable() const
+{
+ return (repeatType_) ? repeatType_->gen_variable() : Variable::EMPTY();
+}
+
+void Repeat::update_repeat_genvar() const
+{
+ if (repeatType_) {
+ // **** reset name since generated variables are not persisted
+ repeatType_->set_gen_variable().set_name( repeatType_->name() );
+
+ // valueAsString() use the last_valid_value() which should always be in range.
+ // Note repeat::value() can be on e past the last valid value, at expiration of Repeat loop
+ // However Repeat::last_valid_value() will just return the last valid value.
+ repeatType_->set_gen_variable().set_value( repeatType_->valueAsString() );
+ }
+}
+
+
+std::ostream& Repeat::print( std::ostream& os ) const {
+ if (repeatType_) {
+ Indentor in;
+ Indentor::indent(os) << toString() << "\n";
+ }
+ return os;
+}
+
+// =========================================================================
+RepeatBase::~RepeatBase() {}
+
+void RepeatBase::incr_state_change_no()
+{
+ state_change_no_ = Ecf::incr_state_change_no();
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "RepeatBase::incr_state_change_no()\n";
+#endif
+}
+
+// =========================================================================
+
+long sms_repeat_julian_to_date(long jdate)
+{
+ long x,y,d,m,e;
+ long day,month,year;
+
+ x = 4 * jdate - 6884477;
+ y = (x / 146097) * 100;
+ e = x % 146097;
+ d = e / 4;
+
+ x = 4 * d + 3;
+ y = (x / 1461) + y;
+ e = x % 1461;
+ d = e / 4 + 1;
+
+ x = 5 * d - 3;
+ m = x / 153 + 1;
+ e = x % 153;
+ d = e / 5 + 1;
+
+ if( m < 11 )
+ month = m + 2;
+ else
+ month = m - 10;
+
+
+ day = d;
+ year = y + m / 11;
+
+ return year * 10000 + month * 100 + day;
+}
+
+long sms_repeat_date_to_julian(long ddate)
+{
+ long m1,y1,a,b,c,d,j1;
+ long month,day,year;
+
+ year = ddate / 10000;
+ ddate %= 10000;
+ month = ddate / 100;
+ ddate %= 100;
+ day = ddate;
+
+ if (month > 2)
+ {
+ m1 = month - 3;
+ y1 = year;
+ }
+ else
+ {
+ m1 = month + 9;
+ y1 = year - 1;
+ }
+ a = 146097*(y1/100)/4;
+ d = y1 % 100;
+ b = 1461*d/4;
+ c = (153*m1+2)/5+day+1721119;
+ j1 = a+b+c;
+
+ return(j1);
+}
+
+RepeatDate::RepeatDate( const std::string& variable,
+ int start,
+ int end,
+ int delta /* always in days*/
+) : RepeatBase(variable), start_(start), end_(end), delta_(delta), value_(start)
+{
+ if ( !Str::valid_name( variable ) ) {
+ throw std::runtime_error("RepeatDate::RepeatDate: Invalid name: " + variable);
+ }
+
+ if (delta == 0) {
+ std::stringstream ss; ss << "repeat " << variable << " " << start << " " << end << " " << delta;
+ throw std::runtime_error("Invalid Repeat date: the delta can not be zero" + ss.str());
+ }
+
+ std::string theStart = boost::lexical_cast< std::string >(start);
+ if (theStart.size() != 8) {
+ std::stringstream ss; ss << "repeat " << variable << " " << start << " " << end << " " << delta;
+ throw std::runtime_error("Invalid Repeat date: The start is not a valid date. Please use yyyymmdd format." + ss.str());
+ }
+ std::string theEnd = boost::lexical_cast< std::string >(end);
+ if (theEnd.size() != 8) {
+ std::stringstream ss; ss << "repeat " << variable << " " << start << " " << end << " " << delta;
+ throw std::runtime_error("Invalid Repeat date: The end is not a valid date. Please use yyyymmdd format." + ss.str());
+ }
+
+
+ if (delta_ > 0) {
+ // assert end => start
+ if (!(end >= start)) {
+ std::stringstream ss; ss << "repeat " << variable << " " << start << " " << end << " " << delta;
+ throw std::runtime_error("Invalid Repeat date: The end must be greater than the start date, when delta is positive " + ss.str());
+ }
+ }
+ else {
+ // assert start >= end
+ if (!(start >= end)) {
+ std::stringstream ss; ss << "repeat " << variable << " " << start << " " << end << " " << delta;
+ throw std::runtime_error("Invalid Repeat date: The start must be greater than the end date, when delta is negative " + ss.str());
+ }
+ }
+
+ // Use date lib to check YMD
+ try {
+ boost::gregorian::date(from_undelimited_string(theStart));
+ boost::gregorian::date(from_undelimited_string(theEnd));
+ }
+ catch (std::exception& e) {
+ std::stringstream ss; ss << "repeat " << variable << " " << start << " " << end << " " << delta;
+ throw std::runtime_error("Invalid Repeat date: The start/end is not a valid date." + ss.str());
+ }
+}
+
+bool RepeatDate::compare(RepeatBase* rb) const
+{
+ RepeatDate* rhs = dynamic_cast<RepeatDate*>(rb);
+ if(!rhs) return false;
+ return operator==(*rhs);
+}
+
+void RepeatDate::setToLastValue()
+{
+ value_ = end_;
+ incr_state_change_no();
+}
+
+long RepeatDate::last_valid_value() const
+{
+ if (delta_ > 0) {
+ if (value_ < start_) return start_;
+ if (value_ > end_) return end_;
+ return value_;
+ }
+ if (value_ > start_) return start_;
+ if (value_ < end_) return end_;
+ return value_;
+}
+
+long RepeatDate::last_valid_value_minus(int val) const
+{
+ long last_value = last_valid_value();
+ long julian = sms_repeat_date_to_julian(last_value);
+ julian -= val;
+ return sms_repeat_julian_to_date(julian);
+}
+
+long RepeatDate::last_valid_value_plus(int val) const
+{
+ long last_value = last_valid_value();
+ long julian = sms_repeat_date_to_julian(last_value);
+ julian += val;
+ return sms_repeat_julian_to_date(julian);
+}
+
+void RepeatDate::reset() {
+ value_ = start_;
+ incr_state_change_no();
+}
+
+std::string RepeatDate::toString() const
+{
+ std::stringstream ss;
+ ss << "repeat date " << name_ << " " << start_ << " " << end_ << " " << delta_;
+ if (!PrintStyle::defsStyle() && (value_ != start_)) {
+ ss << " # " << value_;
+ }
+ return ss.str();
+}
+std::string RepeatDate::dump() const
+{
+ std::stringstream ss;
+ ss << toString() << " value(" << value_ << ")";
+ return ss.str();
+}
+
+bool RepeatDate::operator==(const RepeatDate& rhs) const
+{
+ if (name_ != rhs.name_) {
+ return false;
+ }
+ if (start_ != rhs.start_) {
+ return false;
+ }
+ if (end_ != rhs.end_) {
+ return false;
+ }
+ if (delta_ != rhs.delta_) {
+ return false;
+ }
+ if (value_ != rhs.value_) {
+ return false;
+ }
+ return true;
+}
+
+std::string RepeatDate::valueAsString() const
+{
+ /// will throw a boost::bad_lexical_cast& if value is not convertible to a string
+ try {
+ return boost::lexical_cast< std::string >( last_valid_value() );
+ }
+ catch ( boost::bad_lexical_cast& ) {
+ LOG_ASSERT(false,"RepeatDate::valueAsString(): could not convert value " << value_ << " to a string");
+ }
+ return string();
+}
+
+std::string RepeatDate::value_as_string(int index) const
+{
+ /// will throw a boost::bad_lexical_cast& if value is not convertible to a string
+ try {
+ return boost::lexical_cast< std::string >( index );
+ }
+ catch ( boost::bad_lexical_cast& ) {}
+ return string();
+}
+
+void RepeatDate::increment()
+{
+ long julian = sms_repeat_date_to_julian(value_);
+ julian += delta_;
+ value_ = sms_repeat_julian_to_date(julian);
+
+ incr_state_change_no();
+}
+
+void RepeatDate::change( const std::string& newdate)
+{
+ if (newdate.size() != 8) {
+ std::stringstream ss;
+ ss << "RepeatDate::change: " << toString() << " The new date is not valid, expected 8 characters in yyyymmdd format but found " << newdate;
+ throw std::runtime_error(ss.str());
+ }
+
+ long the_new_date = 0;
+ try {
+ the_new_date = boost::lexical_cast< long >( newdate );
+ }
+ catch ( boost::bad_lexical_cast& ) {
+ std::stringstream ss;
+ ss << "RepeatDate::change: " << toString() << " The new date(" << newdate << ") is not convertible to an long";
+ throw std::runtime_error(ss.str());
+ }
+
+ // Use date lib to check YMD
+ try { boost::gregorian::date(from_undelimited_string(newdate));}
+ catch (std::exception& e) {
+ std::stringstream ss;
+ ss << "RepeatDate::change: " << toString() << " The new date(" << newdate << ") is not valid";
+ throw std::runtime_error(ss.str());
+ }
+
+ changeValue(the_new_date);
+}
+
+void RepeatDate::changeValue(long the_new_date)
+{
+ if (delta_ > 0) {
+ if (the_new_date < start_ || the_new_date > end_) {
+ std::stringstream ss;
+ ss << "RepeatDate::changeValue: " << toString() << "\nThe new date should be in the range[" << start_ << " : " << end_ << "] but found " << the_new_date;
+ throw std::runtime_error(ss.str());
+ }
+ }
+ else {
+ if (the_new_date > start_ || the_new_date < end_) {
+ std::stringstream ss;
+ ss << "RepeatDate::changeValue: " << toString() << "\nThe new date should be in the range[" << start_ << " : " << end_ << "] but found " << the_new_date;
+ throw std::runtime_error(ss.str());
+ }
+ }
+
+ // Check new value is in step. ECFLOW-325 repeat date 7
+ long julian_new_date = sms_repeat_date_to_julian(the_new_date);
+ long julian_start = sms_repeat_date_to_julian(start_);
+ long diff = julian_new_date - julian_start;
+ if ( diff % delta_ != 0 ) {
+ std::stringstream ss;
+ ss << "RepeatDate::changeValue: " << toString() << "\nThe new date " << the_new_date << " is not in line with the delta/step";
+ throw std::runtime_error(ss.str());
+ }
+
+ set_value(the_new_date);
+}
+
+void RepeatDate::set_value(long the_new_date)
+{
+ // Note: the node is incremented one past, the last value
+ // In Node we increment() then check for validity
+ // hence the_new_value may be outside of the valid range.
+ // This can be seen when do a incremental sync,
+ // *hence* allow memento to copy the value as is.
+ value_ = the_new_date;
+ incr_state_change_no();
+}
+
+//======================================================================================
+
+RepeatInteger::RepeatInteger( const std::string& variable, int start, int end, int delta ) :
+ RepeatBase( variable ), start_( start ), end_( end ), delta_( delta ), value_( start )
+{
+// cout << toString() << "\n";
+ if ( !Str::valid_name( variable ) ) {
+ throw std::runtime_error("RepeatInteger: Invalid name: " + variable);
+ }
+}
+RepeatInteger::RepeatInteger() : start_( 0 ), end_( 0 ), delta_( 0 ), value_( 0 ) {}
+
+bool RepeatInteger::compare(RepeatBase* rb) const
+{
+ RepeatInteger* rhs = dynamic_cast<RepeatInteger*>(rb);
+ if(!rhs) return false;
+ return operator==(*rhs);
+}
+
+void RepeatInteger::reset() {
+ value_ = start_;
+ incr_state_change_no();
+}
+
+long RepeatInteger::last_valid_value() const
+{
+ if (delta_ > 0) {
+ if (value_ < start_) return start_;
+ if (value_ > end_) return end_;
+ return value_;
+ }
+ if (value_ > start_) return start_;
+ if (value_ < end_) return end_;
+ return value_;
+}
+
+void RepeatInteger::increment() {
+ value_ += delta_;
+ incr_state_change_no();
+}
+
+void RepeatInteger::change( const std::string& newValue)
+{
+ long the_new_value = 0;
+ try {
+ the_new_value = boost::lexical_cast< long >( newValue );
+ }
+ catch ( boost::bad_lexical_cast& ) {
+ std::stringstream ss;
+ ss << "RepeatInteger::change:" << toString() << " The new value(" << newValue << ") is not convertible to an long";
+ throw std::runtime_error( ss.str() );
+ }
+ changeValue(the_new_value);
+}
+
+void RepeatInteger::changeValue(long the_new_value)
+{
+ if (delta_ > 0) {
+ if (the_new_value < start_ || the_new_value > end_ ) {
+ std::stringstream ss;
+ ss << "RepeatInteger::changeValue:" << toString() << ". The new value should be in the range[" << start_ << "-" << end_ << "] but found " << the_new_value;
+ throw std::runtime_error(ss.str());
+ }
+ }
+ else {
+ if (the_new_value > start_ || the_new_value < end_ ) {
+ std::stringstream ss;
+ ss << "RepeatInteger::changeValue:" << toString() << ". The new value should be in the range[" << start_ << "-" << end_ << "] but found " << the_new_value;
+ throw std::runtime_error(ss.str());
+ }
+ }
+ set_value(the_new_value);
+}
+
+void RepeatInteger::set_value(long the_new_value)
+{
+ // To be used by Memento only. as it does no checking
+ // Note: the node is incremented one past, the last value
+ // In Node we increment() then check for validity
+ // hence the_new_value may be outside of the valid range.
+ // This can be seen when do a incremental sync,
+ // *hence* allow memento to copy the value as is.
+ value_ = the_new_value;
+ incr_state_change_no();
+}
+
+void RepeatInteger::setToLastValue()
+{
+ value_ = end_;
+ incr_state_change_no();
+}
+
+std::string RepeatInteger::toString() const
+{
+ std::stringstream ss;
+ ss << "repeat integer " << name_ << " " << start_ << " " << end_;
+ if (delta_ != 1) ss << " " << delta_;
+ if (!PrintStyle::defsStyle() && (value_ != start_)) {
+ ss << " # " << value_;
+ }
+ return ss.str();
+}
+std::string RepeatInteger::dump() const
+{
+ std::stringstream ss;
+ ss << toString() << " value(" << value_ << ")";
+ return ss.str();
+}
+
+bool RepeatInteger::operator==(const RepeatInteger& rhs) const
+{
+ if (name_ != rhs.name_) {
+ return false;
+ }
+ if (start_ != rhs.start_) {
+ return false;
+ }
+ if (end_ != rhs.end_) {
+ return false;
+ }
+ if (delta_ != rhs.delta_) {
+ return false;
+ }
+ if (value_ != rhs.value_) {
+ return false;
+ }
+ return true;
+}
+
+std::string RepeatInteger::valueAsString() const
+{
+ /// will throw a boost::bad_lexical_cast& if value is not convertible to a string
+ try {
+ return boost::lexical_cast< std::string >( last_valid_value() );
+ }
+ catch ( boost::bad_lexical_cast& ) { LOG_ASSERT(false,"");}
+ return string();
+}
+
+std::string RepeatInteger::value_as_string(int index) const
+{
+ /// will throw a boost::bad_lexical_cast& if value is not convertible to a string
+ try {
+ return boost::lexical_cast< std::string >( index );
+ }
+ catch ( boost::bad_lexical_cast& ) {}
+ return string();
+}
+
+//void RepeatInteger::truncate(int theLength)
+//{
+//// cout << " RepeatInteger::truncate by " << theLength << " BEFORE " << toString();
+//
+// LOG_ASSERT(theLength < length(),"");
+// end_ = start_ + (theLength * delta_);
+//
+//// cout << " AFTER " << toString() << "\n";
+//}
+
+//======================================================================================
+
+RepeatEnumerated::RepeatEnumerated( const std::string& variable, const std::vector<std::string>& theEnums)
+: RepeatBase(variable), theEnums_(theEnums), currentIndex_(0)
+{
+ if ( !Str::valid_name( variable ) ) {
+ throw std::runtime_error("RepeatEnumerated: Invalid name: " + variable);
+ }
+}
+
+int RepeatEnumerated::end() const {
+ if ( theEnums_.empty() ) return 0;
+ return static_cast<int>(theEnums_.size()-1);
+}
+
+bool RepeatEnumerated::compare(RepeatBase* rb) const
+{
+ RepeatEnumerated* rhs = dynamic_cast<RepeatEnumerated*>(rb);
+ if(!rhs) return false;
+ return operator==(*rhs);
+}
+
+std::string RepeatEnumerated::toString() const
+{
+ std::stringstream ss;
+ ss << "repeat enumerated " << name_;
+ BOOST_FOREACH(const string& s, theEnums_) { ss << " \"" << s << "\""; }
+ if (!PrintStyle::defsStyle() && (currentIndex_ != 0)) {
+ ss << " # " << currentIndex_;
+ }
+ return ss.str();
+}
+std::string RepeatEnumerated::dump() const
+{
+ std::stringstream ss;
+ ss << toString() << " ordinal-value(" << value() << ") value-as-string(" << valueAsString() << ")";
+ return ss.str();
+}
+
+void RepeatEnumerated::reset() {
+ currentIndex_ = 0;
+ incr_state_change_no();
+}
+
+void RepeatEnumerated::increment() {
+ currentIndex_++;
+ incr_state_change_no();
+}
+
+long RepeatEnumerated::value() const
+{
+ if (currentIndex_ >= 0 && currentIndex_ < static_cast<int>(theEnums_.size()) ) {
+ try {
+ return boost::lexical_cast<int>( theEnums_[currentIndex_] );
+ }
+ catch ( boost::bad_lexical_cast& ) {
+ // Ignore and return currentIndex_
+ }
+ }
+ return currentIndex_;
+}
+
+long RepeatEnumerated::last_valid_value() const
+{
+ if (!theEnums_.empty()) {
+ if (currentIndex_ < 0) {
+ try { return boost::lexical_cast<int>( theEnums_[0] ); }
+ catch ( boost::bad_lexical_cast& ) { /* Ignore and return first index */ }
+ return 0;
+ }
+ if (currentIndex_ >= static_cast<int>(theEnums_.size())) {
+
+ try { return boost::lexical_cast<int>( theEnums_[theEnums_.size()-1] ); }
+ catch ( boost::bad_lexical_cast& ) { /* Ignore and return last index */ }
+ return static_cast<long>(theEnums_.size()-1);
+ }
+
+ // return current value as integer or as index
+ return value();
+ }
+ return 0;
+}
+
+void RepeatEnumerated::setToLastValue()
+{
+ currentIndex_ = static_cast< int > ( theEnums_.size() - 1);
+ if (currentIndex_ < 0) currentIndex_ = 0;
+ incr_state_change_no();
+}
+
+std::string RepeatEnumerated::valueAsString() const
+{
+ // This must always return a valid value
+ if (!theEnums_.empty()) {
+
+ // Returns the last valid value
+ if (currentIndex_ < 0)
+ return theEnums_[0]; // return first
+
+ if (currentIndex_ >= static_cast<int>(theEnums_.size())) {
+ return theEnums_[theEnums_.size()-1]; // return last
+ }
+
+ return theEnums_[currentIndex_];
+ }
+ return std::string();
+}
+
+std::string RepeatEnumerated::value_as_string(int index) const
+{
+ if (index >= 0 && index < static_cast<int>(theEnums_.size())) {
+ return theEnums_[index];
+ }
+ return std::string();
+}
+
+void RepeatEnumerated::change( const std::string& newValue)
+{
+ // See if if matches one of the enums
+ for(size_t i = 0; i < theEnums_.size(); i++) {
+ if ( theEnums_[i] == newValue) {
+ currentIndex_ = i;
+ incr_state_change_no();
+ return;
+ }
+ }
+
+ // If the value is convertible to an integer, treat as an index
+ try {
+ long the_new_value = boost::lexical_cast< long >( newValue );
+ changeValue(the_new_value); // can throw if out of range
+ return;
+ }
+ catch ( boost::bad_lexical_cast& ) {}
+
+
+ std::stringstream ss;
+ ss << "RepeatEnumerated::change:" << toString() << "\nThe new value " << newValue << " is not a valid index or a member of the enumerated list\n";
+ throw std::runtime_error(ss.str());
+}
+
+void RepeatEnumerated::changeValue( long the_new_value)
+{
+ if ( the_new_value < 0 || the_new_value >= static_cast<int>(theEnums_.size())) {
+ std::stringstream ss;
+ ss << "RepeatEnumerated::changeValue:" << toString() << "\nThe new value '" << the_new_value << "' is not a valid index ";
+ ss << "expected range[0-" << theEnums_.size()-1 << "] but found '" << the_new_value << "'";
+ throw std::runtime_error( ss.str() );
+ }
+ set_value(the_new_value);
+}
+
+void RepeatEnumerated::set_value(long the_new_value)
+{
+ // Note: the node is incremented one past, the last value
+ // In Node we increment() then check for validity
+ // hence the_new_value may be outside of the valid range.
+ // This can be seen when do a incremental sync,
+ // *hence* allow memento to copy the value as is.
+ currentIndex_ = the_new_value;
+ incr_state_change_no();
+}
+
+bool RepeatEnumerated::operator==(const RepeatEnumerated& rhs) const
+{
+ if (name_ != rhs.name_) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "RepeatEnumerated::operator==( name_(" << name_ << ") != rhs.name_(" << rhs.name_ << "))\n";
+ }
+#endif
+ return false;
+ }
+ if (theEnums_ != rhs.theEnums_) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "RepeatEnumerated::operator==( theEnums_ != rhs.theEnums_ )\n";
+ }
+#endif
+ return false;
+ }
+ if (currentIndex_ != rhs.currentIndex_) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "RepeatEnumerated::operator==( currentIndex_(" << currentIndex_ << ") != rhs.currentIndex_(" << rhs.currentIndex_ << "))\n";
+ }
+#endif
+ return false;
+ }
+ return true;
+}
+
+//void RepeatEnumerated::truncate(int theLength)
+//{
+//// cout << " RepeatEnumerated::truncate by " << theLength << " BEFORE " << toString();
+//
+// LOG_ASSERT(theLength < length(),"");
+// while ( static_cast<int>(theEnums_.size()) > theLength) {
+// theEnums_.pop_back();
+// }
+//
+//// cout << " AFTER " << toString() << "\n";
+//}
+
+//======================================================================================
+
+RepeatString::RepeatString( const std::string& variable, const std::vector<std::string>& theEnums)
+: RepeatBase(variable), theStrings_(theEnums), currentIndex_(0)
+{
+ if ( !Str::valid_name( variable ) ) {
+ throw std::runtime_error("RepeatString:: Invalid name: " + variable);
+ }
+}
+
+int RepeatString::end() const {
+ if ( theStrings_.empty() ) return 0;
+ return static_cast<int>(theStrings_.size()-1);
+}
+
+bool RepeatString::compare(RepeatBase* rb) const
+{
+ RepeatString* rhs = dynamic_cast<RepeatString*>(rb);
+ if(!rhs) return false;
+ return operator==(*rhs);
+}
+
+std::string RepeatString::toString() const
+{
+ std::stringstream ss;
+ ss << "repeat string " << name_;
+ BOOST_FOREACH(const string& s, theStrings_) { ss << " \"" << s << "\""; }
+ if (!PrintStyle::defsStyle() && (currentIndex_ != 0)) {
+ ss << " # " << value();
+ }
+ return ss.str();
+}
+std::string RepeatString::dump() const
+{
+ std::stringstream ss;
+ ss << toString() << " ordinal-value(" << value() << ") value-as-string(" << valueAsString() << ")";
+ return ss.str();
+}
+
+void RepeatString::reset() {
+ currentIndex_ = 0;
+ incr_state_change_no();
+}
+
+long RepeatString::last_valid_value() const
+{
+ if (!theStrings_.empty()) {
+ if (currentIndex_ < 0) return 0;
+ if (currentIndex_ >= static_cast<int>(theStrings_.size())) return static_cast<long>(theStrings_.size()-1);
+ return currentIndex_;
+ }
+ return 0;
+}
+
+void RepeatString::increment() {
+ currentIndex_++;
+ incr_state_change_no();
+}
+
+void RepeatString::setToLastValue() {
+ currentIndex_ = static_cast<int>(theStrings_.size()-1);
+ if (currentIndex_ < 0) currentIndex_ = 0;
+ incr_state_change_no();
+}
+
+std::string RepeatString::valueAsString() const
+{
+ if (!theStrings_.empty()) return theStrings_[last_valid_value()];
+ return std::string();
+}
+
+std::string RepeatString::value_as_string(int index) const
+{
+ if (index >= 0 && index < static_cast<int>(theStrings_.size())) {
+ return theStrings_[index];
+ }
+ return std::string();
+}
+
+void RepeatString::change( const std::string& newValue)
+{
+ // See if if matches one of the strings
+ for(size_t i = 0; i < theStrings_.size(); i++) {
+ if ( theStrings_[i] == newValue) {
+ currentIndex_ = i;
+ incr_state_change_no();
+ return;
+ }
+ }
+
+ // If the value is convertible to an integer, treat as an index
+ try {
+ long the_new_value = boost::lexical_cast< int >( newValue );
+ changeValue(the_new_value);
+ return;
+ }
+ catch ( boost::bad_lexical_cast& ) {}
+
+ std::stringstream ss;
+ ss << "RepeatString::change: " << toString() << "\nThe new value " << newValue << " is not a valid index or member of the string list";
+ throw std::runtime_error(ss.str());
+}
+
+void RepeatString::changeValue( long the_new_value)
+{
+ if ( the_new_value < 0 || the_new_value >= static_cast<int>(theStrings_.size())) {
+ std::stringstream ss;
+ ss << "RepeatString::change: " << toString() << " The new the integer " << the_new_value << " is not a valid index ";
+ ss << "expected range[0-" << theStrings_.size()-1 << "]'";
+ throw std::runtime_error( ss.str() );
+ }
+ set_value(the_new_value);
+}
+
+void RepeatString::set_value(long the_new_value)
+{
+ // Note: the node is incremented one past, the last value
+ // In Node we increment() then check for validity
+ // hence the_new_value may be outside of the valid range.
+ // This can be seen when do a incremental sync,
+ // *hence* allow memento to copy the value as is.
+ currentIndex_ = the_new_value;
+ incr_state_change_no();
+}
+
+bool RepeatString::operator==(const RepeatString& rhs) const
+{
+ if (name_ != rhs.name_) {
+ return false;
+ }
+ if (theStrings_ != rhs.theStrings_) {
+ return false;
+ }
+ if (currentIndex_ != rhs.currentIndex_) {
+ return false;
+ }
+ return true;
+}
+
+//void RepeatString::truncate(int theLength)
+//{
+//// cout << " RepeatString::truncate by " << theLength << " BEFORE " << toString();
+//
+// LOG_ASSERT(theLength < length(),"");
+// while ( static_cast<int>(theStrings_.size()) > theLength) {
+// theStrings_.pop_back();
+// }
+//
+//// cout << " AFTER " << toString() << "\n";
+//}
+
+//=======================================================================================
+
+bool RepeatDay::compare(RepeatBase* rb) const
+{
+ RepeatDay* rhs = dynamic_cast<RepeatDay*>(rb);
+ if(!rhs) return false;
+ return operator==(*rhs);
+}
+
+std::string RepeatDay::toString() const
+{
+ std::stringstream ss;
+ ss << "repeat day " << step_;
+ return ss.str();
+}
+
+std::string RepeatDay::dump() const
+{
+ return toString();
+}
+
+bool RepeatDay::operator==(const RepeatDay& rhs) const
+{
+ if (step_ != rhs.step_) {
+ return false;
+ }
+ return true;
+}
+
+BOOST_CLASS_EXPORT_IMPLEMENT(RepeatDate);
+BOOST_CLASS_EXPORT_IMPLEMENT(RepeatInteger);
+BOOST_CLASS_EXPORT_IMPLEMENT(RepeatEnumerated);
+BOOST_CLASS_EXPORT_IMPLEMENT(RepeatString);
+BOOST_CLASS_EXPORT_IMPLEMENT(RepeatDay);
diff --git a/ANattr/src/RepeatAttr.hpp b/ANattr/src/RepeatAttr.hpp
new file mode 100644
index 0000000..68982f7
--- /dev/null
+++ b/ANattr/src/RepeatAttr.hpp
@@ -0,0 +1,487 @@
+#ifndef REPEATATTR_HPP_
+#define REPEATATTR_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #51 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Repeat Attribute. Please note that for repeat string, enumeration
+// the positional index is used for evaluation.
+//
+// Simulation: Simulation must not affect the real job submission in the server.
+// o Infinite repeats cause problems with simulation, hence we have
+// a mechanism to stop this, when reset is called, via server this is disabled
+// o The other problem is long repeats. The current solution truncates the
+// repeats. However this is not acceptable and has been commented out,
+// until we can find a better way. (i.e need a simulation mode, where
+// we can truncate a length, this would be ignored in the server)
+//============================================================================
+
+#include <ostream>
+#include "boost_archive.hpp" // collates boost archive includes
+
+#include <boost/serialization/base_object.hpp>
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/vector.hpp> // no need to include <vector>
+#include <boost/serialization/string.hpp> // no need to include <string>
+#include <boost/serialization/assume_abstract.hpp>
+#include <boost/serialization/export.hpp> // explicit code for exports (place last) , needed for BOOST_CLASS_EXPORT
+
+#include <boost/utility.hpp>
+
+#include "Variable.hpp"
+
+/////////////////////////////////////////////////////////////////////////
+// Node can only have one repeat.
+//
+class RepeatBase {
+public:
+ RepeatBase(const std::string& name) : state_change_no_(0), name_(name) {}
+ RepeatBase() : state_change_no_(0) {}
+ virtual ~RepeatBase();
+
+ /// make non virtual so that it can be in-lined. Called millions of times
+ const std::string& name() const { return name_; }
+ const Variable& gen_variable() const { return var_; }
+ Variable& set_gen_variable() const { return var_; }
+
+ virtual int start() const = 0;
+ virtual int end() const = 0;
+ virtual int step() const = 0;
+
+ // After Repeat expiration the last call to increment() can cause
+ // value to be beyond the last valid value
+ // Depending on the kind of repeat the returned can be value or the current index
+ // RepeatDate -> value
+ // RepeatString -> index into array of strings
+ // RepeatInteger -> value
+ // RepeatEnumerated -> index | value return value at index if cast-able to integer, otherwise return index ******
+ // RepeatDay -> value
+ virtual long value() const = 0;
+
+ // Depending on the kind of repeat the returned can be value or *current* index
+ // RepeatDate -> value
+ // RepeatString -> index ( will always return a index)
+ // RepeatInteger -> value
+ // RepeatEnumerated -> index ( will always return a index)
+ // RepeatDay -> value
+ virtual long index_or_value() const = 0;
+ virtual void increment() = 0;
+
+ // returns a value with in the range start/end
+ // Hence at Repeat expiration will return value associated with end()
+ virtual long last_valid_value() const = 0;
+ virtual long last_valid_value_minus(int val) const { return last_valid_value() - val;}
+ virtual long last_valid_value_plus(int val) const { return last_valid_value() + val;}
+
+ virtual RepeatBase* clone() const = 0;
+ virtual bool compare(RepeatBase*) const = 0;
+ virtual bool valid() const = 0;
+ virtual void setToLastValue() = 0;
+ virtual std::string valueAsString() const = 0; // uses last_valid_value
+ virtual std::string value_as_string(int index) const = 0;// used in test only
+ virtual void reset() = 0;
+ virtual void change(const std::string& newValue) = 0; // can throw std::runtime_error
+ virtual void changeValue(long newValue) = 0; // can throw std::runtime_error
+ virtual void set_value(long new_value_or_index) = 0; // will NOT throw, allows any value
+ virtual std::string toString() const = 0;
+ virtual std::string dump() const = 0;
+
+ unsigned int state_change_no() const { return state_change_no_;}
+
+ /// Simulator functions:
+ virtual bool isInfinite() const = 0;
+ virtual bool makeInfiniteInValid() { return false;}
+ // virtual int length() const = 0;
+ // virtual void truncate(int length) = 0;
+
+ virtual bool is_repeat_day() const { return false; }
+
+protected:
+ void incr_state_change_no();
+
+ unsigned int state_change_no_; // *not* persisted, only used on server side
+ std::string name_;
+ mutable Variable var_; // *not* persisted
+
+private:
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive& ar, const unsigned int /*version*/)
+ {
+ ar & name_;
+ }
+};
+
+///
+/// The date has no meaning in a physical sense, only used as a for loop over dates
+class RepeatDate : public RepeatBase {
+public:
+ RepeatDate( const std::string& variable, int start, int end, int delta = 1/* always in days*/);
+ RepeatDate() : start_(0), end_(0), delta_(0), value_(0) {}
+
+ virtual int start() const { return start_; }
+ virtual int end() const { return end_; }
+ virtual int step() const { return delta_; }
+ virtual long value() const { return value_; }
+ virtual long index_or_value() const { return value_;}
+ virtual long last_valid_value() const;
+ virtual long last_valid_value_minus(int value) const;
+ virtual long last_valid_value_plus(int value) const;
+
+ void delta(int d) { delta_ = d;}
+ bool operator==(const RepeatDate& rhs) const;
+
+ virtual RepeatDate* clone() const { return new RepeatDate(name_, start_, end_, delta_, value_) ; }
+ virtual bool compare(RepeatBase*) const;
+ virtual bool valid() const { return (delta_ > 0) ? ( value_ <= end_) : (value_ >= end_); }
+ virtual std::string valueAsString() const;
+ virtual std::string value_as_string(int index) const;
+ virtual void setToLastValue();
+ virtual void reset();
+ virtual void increment();
+ virtual void change(const std::string& newValue); // can throw std::runtime_error
+ virtual void changeValue(long newValue); // can throw std::runtime_error
+ virtual void set_value(long newValue); // will NOT throw, allows any value
+
+ virtual std::string toString() const;
+ virtual std::string dump() const;
+
+ /// Simulator functions:
+ virtual bool isInfinite() const { return false;}
+ // virtual int length() const; // for use by simulator
+ // virtual void truncate(int); // for use by simulator
+
+private:
+ RepeatDate( const std::string& name, int start, int end, int delta, long value)
+ : RepeatBase(name),start_(start),end_(end),delta_(delta),value_(value) {}
+
+private:
+ int start_;
+ int end_;
+ int delta_;
+ long value_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/) {
+ ar & boost::serialization::base_object<RepeatBase>(*this);
+ ar & start_;
+ ar & end_;
+ ar & delta_;
+ ar & value_;
+ }
+};
+
+class RepeatInteger : public RepeatBase {
+public:
+ RepeatInteger( const std::string& variable, int start, int end, int delta = 1);
+ RepeatInteger();
+
+ bool operator==(const RepeatInteger& rhs) const;
+
+ virtual int start() const { return start_; }
+ virtual int end() const { return end_; }
+ virtual int step() const { return delta_;}
+ virtual long value() const { return value_;}
+ virtual long index_or_value() const { return value_;}
+ virtual long last_valid_value() const;
+
+ virtual RepeatInteger* clone() const { return new RepeatInteger(name_, start_, end_, delta_, value_); }
+ virtual bool compare(RepeatBase*) const;
+ virtual bool valid() const { return (delta_ > 0) ? ( value_ <= end_) : (value_ >= end_); }
+ virtual std::string valueAsString() const;
+ virtual std::string value_as_string(int index) const;
+ virtual void setToLastValue();
+ virtual void reset();
+ virtual void increment();
+ virtual void change(const std::string& newValue); // can throw std::runtime_error
+ virtual void changeValue(long newValue); // can throw std::runtime_error
+ virtual void set_value(long newValue); // will NOT throw, allows any value
+ virtual std::string toString() const;
+ virtual std::string dump() const;
+
+ /// Simulator functions:
+ virtual bool isInfinite() const { return false;}
+ // virtual int length() const { return std::abs( (end_-start_)+1/delta_ ) ;}
+ // virtual void truncate(int);
+
+private:
+ RepeatInteger( const std::string& name, int start, int end, int delta, long value)
+ : RepeatBase(name), start_(start), end_(end), delta_(delta), value_(value) {}
+
+private:
+ int start_;
+ int end_;
+ int delta_;
+ long value_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/) {
+ ar & boost::serialization::base_object<RepeatBase>(*this);
+ ar & start_;
+ ar & end_;
+ ar & delta_;
+ ar & value_;
+ }
+};
+
+// Note:: Difference between RepeatEnumerated and RepeatString, is that
+// RepeatEnumerated::value() will return the value at the index if cast-able to integer,
+// whereas RepeatString::value() will always return the index.
+class RepeatEnumerated : public RepeatBase {
+public:
+ RepeatEnumerated( const std::string& variable, const std::vector<std::string>& theEnums);
+ RepeatEnumerated() : currentIndex_(0) {}
+
+ bool operator==(const RepeatEnumerated& rhs) const;
+
+ virtual int start() const { return 0; }
+ virtual int end() const;
+ virtual int step() const { return 1 ;}
+ virtual long value() const; // return value at index if cast-able to integer, otherwise return index
+ virtual long index_or_value() const { return currentIndex_;}
+ virtual long last_valid_value() const;
+
+ virtual RepeatBase* clone() const { return new RepeatEnumerated(name_,theEnums_,currentIndex_); }
+ virtual bool compare(RepeatBase*) const;
+ virtual bool valid() const { return (currentIndex_ >=0 && currentIndex_ < static_cast<int>(theEnums_.size())); }
+ virtual std::string valueAsString() const;
+ virtual std::string value_as_string(int index) const;
+ virtual void setToLastValue();
+ virtual void reset();
+ virtual void increment();
+ virtual void change(const std::string& newValue); // can throw std::runtime_error
+ virtual void changeValue(long newValue); // can throw std::runtime_error
+ virtual void set_value(long newValue); // will NOT throw, allows any value
+ virtual std::string toString() const;
+ virtual std::string dump() const;
+
+ /// Simulator functions:
+ virtual bool isInfinite() const { return false;}
+ // virtual int length() const { return static_cast<int>(theEnums_.size());} // for use by simulator
+ // virtual void truncate(int); // for use by simulator
+
+private:
+ RepeatEnumerated( const std::string& variable, const std::vector<std::string>& theEnums, int index)
+ : RepeatBase(variable), theEnums_(theEnums), currentIndex_(index) {}
+
+private:
+ std::vector<std::string> theEnums_;
+ int currentIndex_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/) {
+ ar & boost::serialization::base_object<RepeatBase>(*this);
+ ar & theEnums_;
+ ar & currentIndex_;
+ }
+};
+
+class RepeatString : public RepeatBase {
+public:
+ RepeatString( const std::string& variable, const std::vector<std::string>& theEnums);
+ RepeatString() : currentIndex_(0) {}
+
+ bool operator==(const RepeatString& rhs) const;
+
+ virtual int start() const { return 0; }
+ virtual int end() const;
+ virtual int step() const { return 1;}
+ virtual long value() const { return currentIndex_;}
+ virtual long index_or_value() const { return currentIndex_;}
+ virtual long last_valid_value() const; // returns the index
+
+ virtual RepeatBase* clone() const { return new RepeatString(name_,theStrings_,currentIndex_); }
+ virtual bool compare(RepeatBase*) const;
+ virtual bool valid() const { return (currentIndex_ >=0 && currentIndex_ < static_cast<int>(theStrings_.size())); }
+ virtual std::string valueAsString() const;
+ virtual std::string value_as_string(int index) const;
+ virtual void setToLastValue();
+ virtual void reset();
+ virtual void increment();
+ virtual void change(const std::string& newValue); // can throw std::runtime_error
+ virtual void changeValue(long newValue); // can throw std::runtime_error
+ virtual void set_value(long newValue); // will NOT throw, allows any value
+ virtual std::string toString() const;
+ virtual std::string dump() const;
+
+ /// Simulator functions:
+ virtual bool isInfinite() const { return false;}
+ // virtual int length() const { return static_cast<int>(theStrings_.size());}
+ // virtual void truncate(int);
+
+private:
+ RepeatString( const std::string& variable, const std::vector<std::string>& theEnums, int index)
+ : RepeatBase(variable), theStrings_(theEnums), currentIndex_(index) {}
+
+private:
+ std::vector<std::string> theStrings_;
+ int currentIndex_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/) {
+ ar & boost::serialization::base_object<RepeatBase>(*this);
+ ar & theStrings_;
+ ar & currentIndex_;
+ }
+};
+
+/// The current repeat day is not that well defined or deterministic.
+/// **** Currently I have not come across any suites that use an end-date ****
+/// o If the suite has defined a real clock
+/// then number of repeats is deterministic
+/// However if the end-date is less than suite clock this should be reported as error
+/// o Currently under the hybrid clock the date is not updated, this raises
+/// a whole lot of issues. (We don't wont a separate calendar, just for this).
+/// o If there is _no_ suite clock, then we must use the current day
+/// now the number of repeats varies, and if end-date is less than the current
+/// day we need to report an error
+/// Its not clear what behaviour is required here, hence I will not implement
+/// the end-date functionality. Until there is clear requirement is this area.
+/// end-date will be treated as a parser error.
+/// The minimum deterministic functionality here is to implement the infinite
+/// repeat that has no end date
+///
+/// RepeatDay do not really have a name: However we need maintain invariant that all NON-empty repeats
+/// have a name. Hence the name will be as day
+/// Note: this applies to the clone as well
+class RepeatDay : public RepeatBase {
+public:
+ RepeatDay( int step ) : RepeatBase("day"), step_(step),valid_(true) {}
+ RepeatDay() : step_(1),valid_(true) {}
+
+ bool operator==(const RepeatDay& rhs) const;
+
+ virtual int start() const { return 0; }
+ virtual int end() const { return 0; }
+ virtual int step() const { return step_;}
+ virtual void increment() { /* do nothing */ }
+ virtual long value() const { return step_;}
+ virtual long index_or_value() const { return step_;}
+ virtual long last_valid_value() const { return step_;}
+
+ virtual RepeatBase* clone() const { return new RepeatDay(step_,valid_); }
+ virtual bool compare(RepeatBase*) const;
+ virtual bool valid() const { return valid_;}
+ virtual std::string valueAsString() const { return std::string(); } ;
+ virtual std::string value_as_string(int index) const { return std::string(); }
+ virtual void setToLastValue() { /* do nothing ?? */ }
+ virtual void reset() { valid_ = true; }
+ virtual void change(const std::string& /*newValue*/) { /* do nothing */ }
+ virtual void changeValue( long /*newValue*/) { /* do nothing */ }
+ virtual void set_value(long /*newValue*/) { /* do nothing */ }
+ virtual std::string toString() const;
+ virtual std::string dump() const;
+
+ /// Simulator functions:
+ virtual bool isInfinite() const { return true;}
+ virtual bool makeInfiniteInValid() { valid_ = false; return true;}
+ // virtual int length() const { return 0;} // because its infinite for use by simulator
+ // virtual void truncate(int) {}
+
+ virtual bool is_repeat_day() const { return true; }
+
+private:
+ RepeatDay( int step, bool valid) : RepeatBase("day"), step_(step),valid_(valid) {}
+
+private:
+ int step_;
+ bool valid_; // not persisted since only used in simulator
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/) {
+ ar & boost::serialization::base_object<RepeatBase>(*this);
+ ar & step_;
+ }
+};
+
+class Repeat {
+public:
+ Repeat(); // for serialisation
+ Repeat( const RepeatDate& );
+ Repeat( const RepeatInteger& );
+ Repeat( const RepeatEnumerated& );
+ Repeat( const RepeatString& );
+ Repeat( const RepeatDay& );
+ Repeat( const Repeat& );
+ ~Repeat();
+ Repeat& operator=(const Repeat& rhs);
+ bool operator==(const Repeat& rhs) const;
+
+ bool empty() const { return (repeatType_) ? false : true; }
+ void clear() { delete repeatType_; repeatType_ = 0;}
+
+ const std::string& name() const;
+ const Variable& gen_variable() const;
+ void update_repeat_genvar() const;
+
+ int start() const { return (repeatType_) ? repeatType_->start() : 0;}
+ int end() const { return (repeatType_) ? repeatType_->end() : 0;}
+ int step() const { return (repeatType_) ? repeatType_->step() : 0;}
+ long value() const { return (repeatType_) ? repeatType_->value() : 0;}
+ long index_or_value() const { return (repeatType_) ? repeatType_->index_or_value() : 0;}
+ long last_valid_value() const { return (repeatType_) ? repeatType_->last_valid_value() : 0;}
+ long last_valid_value_minus(int val) const { return (repeatType_) ? repeatType_->last_valid_value_minus(val) : -val;}
+ long last_valid_value_plus(int val) const { return (repeatType_) ? repeatType_->last_valid_value_plus(val) : val;}
+
+ std::ostream& print(std::ostream& os) const;
+ bool valid() const { return (repeatType_) ? repeatType_->valid() : false;}
+ void setToLastValue() { if (repeatType_) repeatType_->setToLastValue() ; }
+ std::string valueAsString() const { return (repeatType_) ? repeatType_->valueAsString() : std::string(); }
+ std::string value_as_string(int index) const { return (repeatType_) ? repeatType_->value_as_string(index) : std::string(); }
+ void reset() { if (repeatType_) repeatType_->reset();}
+ void increment() { if (repeatType_) repeatType_->increment();}
+ void change( const std::string& newValue ) { if (repeatType_) repeatType_->change(newValue); }
+ void changeValue( long newValue ) { if (repeatType_) repeatType_->changeValue(newValue); }
+ void set_value( long newValue ) { if (repeatType_) repeatType_->set_value(newValue); }
+ std::string toString() const { return (repeatType_) ? repeatType_->toString() : std::string();}
+ std::string dump() const { return (repeatType_) ? repeatType_->dump() : std::string();} // additional state
+ unsigned int state_change_no() const { return (repeatType_) ? repeatType_->state_change_no() : 0; }
+
+ /// simulator functions: Note: any flags set by makeInfiniteInValid() are reset by reset()
+ bool isInfinite() const { return (repeatType_) ? repeatType_->isInfinite() : false;}
+ bool makeInfiniteInValid() { return (repeatType_) ? repeatType_->makeInfiniteInValid() : false; } // for simulator only
+ // int length() const { return (repeatType_) ? repeatType_->length() : 0;} // for simulator only
+ // void truncate(int length) { if (repeatType_) repeatType_->truncate(length);} // for simulator only
+
+ // Allows Repeat's to be returned by reference
+ static const Repeat& EMPTY();
+
+ bool is_repeat_day() const { return (repeatType_) ? repeatType_->is_repeat_day() : false; }
+
+ /// Expose base for the GUI only, use with caution
+ RepeatBase* repeatBase() const { return repeatType_;}
+
+private:
+ RepeatBase* repeatType_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/) {
+ ar & repeatType_;
+ }
+};
+
+BOOST_CLASS_EXPORT_KEY(RepeatDate)
+BOOST_CLASS_EXPORT_KEY(RepeatInteger)
+BOOST_CLASS_EXPORT_KEY(RepeatEnumerated)
+BOOST_CLASS_EXPORT_KEY(RepeatString)
+BOOST_CLASS_EXPORT_KEY(RepeatDay)
+
+// This should ONLY be added to objects that are *NOT* serialised through a pointer
+BOOST_CLASS_IMPLEMENTATION(Repeat, boost::serialization::object_serializable)
+BOOST_CLASS_TRACKING(Repeat,boost::serialization::track_never);
+
+#endif
diff --git a/ANattr/src/TimeAttr.cpp b/ANattr/src/TimeAttr.cpp
new file mode 100644
index 0000000..de45244
--- /dev/null
+++ b/ANattr/src/TimeAttr.cpp
@@ -0,0 +1,188 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #40 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <sstream>
+
+#include "TimeAttr.hpp"
+#include "Indentor.hpp"
+#include "Calendar.hpp"
+#include "PrintStyle.hpp"
+#include "Ecf.hpp"
+
+namespace ecf {
+
+void TimeAttr::calendarChanged( const ecf::Calendar& c )
+{
+ if ( makeFree_ ) {
+ return;
+ }
+
+ if (timeSeries_.calendarChanged(c)) {
+ state_change_no_ = Ecf::incr_state_change_no();
+ }
+
+ // For a time series, we rely on the re queue to reset makeFree
+ if (isFree(c)) {
+ setFree();
+ }
+}
+
+void TimeAttr::resetRelativeDuration()
+{
+ if (timeSeries_.resetRelativeDuration()) {
+ state_change_no_ = Ecf::incr_state_change_no();
+ }
+}
+
+std::ostream& TimeAttr::print(std::ostream& os) const
+{
+ Indentor in;
+ Indentor::indent(os) << toString();
+ if (!PrintStyle::defsStyle()) {
+ os << timeSeries_.state_to_string(makeFree_);
+ }
+ os << "\n";
+ return os;
+}
+
+std::string TimeAttr::toString() const
+{
+ std::string ret = "time ";
+ ret += timeSeries_.toString();
+ return ret;
+}
+
+std::string TimeAttr::dump() const
+{
+ std::stringstream ss;
+ ss << "time ";
+
+ if (makeFree_) ss << "(free) ";
+ else ss << "(holding) ";
+
+ ss << timeSeries_.dump();
+
+ return ss.str();
+}
+
+bool TimeAttr::operator==(const TimeAttr& rhs) const
+{
+ if (makeFree_ != rhs.makeFree_) {
+ return false;
+ }
+ return timeSeries_.operator==(rhs.timeSeries_);
+}
+
+bool TimeAttr::structureEquals(const TimeAttr& rhs) const
+{
+ return timeSeries_.structureEquals(rhs.timeSeries_);
+}
+
+bool TimeAttr::isFree(const ecf::Calendar& calendar) const
+{
+ // The FreeDepCmd can be used to free the time,
+ if (makeFree_) {
+ return true;
+ }
+ return is_free(calendar);
+}
+
+bool TimeAttr::is_free(const ecf::Calendar& calendar) const
+{
+ return timeSeries_.isFree(calendar);
+}
+
+void TimeAttr::setFree() {
+ makeFree_ = true;
+ state_change_no_ = Ecf::incr_state_change_no();
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "TimeAttr::setFree()\n";
+#endif
+}
+
+void TimeAttr::clearFree() {
+ makeFree_ = false;
+ state_change_no_ = Ecf::incr_state_change_no();
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "TimeAttr::clearFree()\n";
+#endif
+}
+
+void TimeAttr::miss_next_time_slot()
+{
+ timeSeries_.miss_next_time_slot();
+ state_change_no_ = Ecf::incr_state_change_no();
+}
+
+
+bool TimeAttr::why(const ecf::Calendar& c, std::string& theReasonWhy) const
+{
+ if (isFree(c)) return false;
+ theReasonWhy += "is time dependent";
+
+ // Check to see if time has expired, if has not, then report why
+ if (timeSeries_.is_valid()) {
+ // This can apply to single and series
+ boost::posix_time::time_duration calendar_time = timeSeries_.duration(c);
+ if (calendar_time < timeSeries_.start().duration()) {
+ timeSeries_.why(c, theReasonWhy);
+ return true;
+ }
+
+ // calendar_time >= timeSeries_.start().duration()
+ if (timeSeries_.hasIncrement()) {
+ if (calendar_time < timeSeries_.finish().duration()) {
+ timeSeries_.why(c, theReasonWhy);
+ return true;
+ }
+ }
+ // calendar_time >= timeSeries_.start().duration() && calendar_time >= timeSeries_.finish().duration()
+ // past the end of time slot, hence this should not hold job generation,
+ }
+
+ // the time has expired
+ theReasonWhy += " ( '";
+ theReasonWhy += toString();
+ theReasonWhy += "' has expired,";
+
+ // take into account, user can use run/force complete to miss time slots
+ bool do_a_requeue = timeSeries_.requeueable(c);
+ if (do_a_requeue) {
+ TimeSlot the_next_time_slot = timeSeries_.compute_next_time_slot(c);
+ if (the_next_time_slot.isNULL() || !timeSeries_.hasIncrement() ) {
+ theReasonWhy += " *re-queue* to run at this time";
+ }
+ else {
+ theReasonWhy += " *re-queue* to run at ";
+ theReasonWhy += the_next_time_slot.toString() ;
+ }
+ }
+ else {
+ boost::gregorian::date_duration one_day(1);
+ boost::gregorian::date the_next_date = c.date(); // todays date
+ the_next_date += one_day; // add one day, so its in the future
+
+ theReasonWhy += " next run tomorrow at ";
+ theReasonWhy += timeSeries_.start().toString();
+ theReasonWhy += " ";
+ theReasonWhy += to_simple_string( the_next_date );
+ }
+ theReasonWhy += " )";
+
+ return true;
+}
+}
diff --git a/ANattr/src/TimeAttr.hpp b/ANattr/src/TimeAttr.hpp
new file mode 100644
index 0000000..bc357e9
--- /dev/null
+++ b/ANattr/src/TimeAttr.hpp
@@ -0,0 +1,134 @@
+#ifndef TIMEATTR_HPP_
+#define TIMEATTR_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #32 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//
+/// isFree is called when a node is queued.If it returns true, Task can be submitted
+/// checkForReque: is called when a node has completed, and need to determine if it should run again.
+/// These are different/orthogonal concerns.
+/// There is a *separate* issue of whether nodes should be queued when a node is *manually*
+/// a/ Set complete
+/// b/ Runs and then completes
+///
+/// For a *single* time slot we can't requeue.
+/// Hence we checkForReque that takes as parameters max/min time slots, so we **treat**
+/// Multiple single slot as a series.
+///
+/// isFree:hhhhhhhhhhhhhhhhh
+/// Begin:
+/// V
+///checkForReque:rrrrrrrrrrrrrrrrhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh 10:00
+///checkForReque:rrrrrrrrrrrrrrrrrrrrrrrrrrrrrhhhhhhhhhhhhhhhhhhhhhhh 11:00
+///checkForReque:rrrrrrrrrrrrrrrrrrrrrrrrrrrrrhhhhhhhhhhhhhhhhhhhhhhh for both 10:00 and 11:000 together
+/// isFree:hhhhhhhhhhhhhhhhffffffffffffffffffffffffffffffffffff *once* free we stay free (single slot *only*)
+/// begin : | |
+/// V | |
+/// Time ======================0============0==============0=============
+/// 10:00 11:00 Midnight
+//
+/// isFree:hhhhhhhhhhhhhhhhhh
+/// V
+/// CheckForReque:rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+/// isFree:hhhhhhhFhhhhFhhhhFhhhhFhhhhFhhhhFhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+/// V | | | | | | |
+/// Time ================o====|====|====|====|====0========0====================
+/// 10:00 1 2 3 4 15:00 Midnight
+///
+/// If the job starts at 10:00 but takes more than 1 hour, then it will miss the 11:00 slot
+/// and will have to start at 12:00
+//============================================================================
+#include <boost/serialization/tracking.hpp>
+#include <boost/serialization/level.hpp>
+#include "TimeSeries.hpp"
+
+namespace ecf { class Calendar;} // forward declare class
+
+namespace ecf {
+
+// Use compiler , destructor, assignment, copy constructor,
+class TimeAttr {
+public:
+ TimeAttr() : makeFree_(false), state_change_no_(0) {}
+ TimeAttr(int hour, int minute, bool relative = false )
+ : timeSeries_(hour, minute,relative), makeFree_(false),state_change_no_(0) {}
+ TimeAttr(const TimeSlot& t, bool relative = false )
+ : timeSeries_(t,relative), makeFree_(false),state_change_no_(0) {}
+ TimeAttr(const TimeSeries& ts)
+ : timeSeries_(ts), makeFree_(false),state_change_no_(0) {}
+ TimeAttr(const TimeSlot& start, const TimeSlot& finish, const TimeSlot& incr, bool relative = false)
+ : timeSeries_(start,finish,incr,relative), makeFree_(false),state_change_no_(0) {}
+
+ std::ostream& print(std::ostream&) const;
+ bool operator==(const TimeAttr& rhs) const;
+ bool operator<(const TimeAttr& rhs) const { return timeSeries_ < rhs.timeSeries_; }
+ bool structureEquals(const TimeAttr& rhs) const;
+
+ /// This can set attribute as free, once free its stays free, until re-queue/reset
+ void calendarChanged( const ecf::Calendar& c ); // can set attribute free
+ void resetRelativeDuration();
+
+ void reset(const ecf::Calendar& c)
+ { clearFree(); timeSeries_.reset(c); } // updates state_change_no_
+ void requeue(const ecf::Calendar& c,bool reset_next_time_slot = true)
+ { clearFree(); timeSeries_.requeue(c,reset_next_time_slot);} // updates state_change_no_
+
+ void miss_next_time_slot(); // updates state_change_no_
+ void setFree(); // ensures that isFree() always returns true, updates state_change_no_
+ bool isSetFree() const { return makeFree_; }
+ bool isFree(const ecf::Calendar&) const;
+ bool checkForRequeue( const ecf::Calendar& c,const TimeSlot& the_min,const TimeSlot& the_max) const
+ { return timeSeries_.checkForRequeue(c,the_min,the_max);}
+ void min_max_time_slots(TimeSlot& the_min, TimeSlot& the_max) const {timeSeries_.min_max_time_slots(the_min,the_max);}
+ bool why(const ecf::Calendar&, std::string& theReasonWhy) const;
+
+ bool checkInvariants(std::string& errormsg) const { return timeSeries_.checkInvariants(errormsg);}
+
+ // The state_change_no is never reset. Must be incremented if it can affect equality
+ // Note: changes in state of timeSeries_, i.e affect the equality operator (used in test)
+ // must be captured. i.e things like relative duration & next_time_slot are
+ // reported by the Why command, & hence need to be synced.
+ unsigned int state_change_no() const { return state_change_no_; }
+
+ std::string name() const { return toString(); } /* ABO */
+ std::string toString() const;
+ std::string dump() const;
+
+ // access
+ const TimeSeries& time_series() const { return timeSeries_; }
+
+private:
+ void clearFree(); // resets the free flag, updates state_change_no_
+ bool is_free(const ecf::Calendar&) const; // ignores makeFree_
+
+private:
+ TimeSeries timeSeries_;
+ bool makeFree_;
+ unsigned int state_change_no_; // *not* persisted, only used on server side
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/)
+ {
+ ar & timeSeries_;
+ ar & makeFree_; // Only persisted for testing, see usage of isSetFree()
+ }
+};
+
+}
+
+// This should ONLY be added to objects that are *NOT* serialised through a pointer
+BOOST_CLASS_IMPLEMENTATION(ecf::TimeAttr, boost::serialization::object_serializable);
+BOOST_CLASS_TRACKING(ecf::TimeAttr,boost::serialization::track_never);
+
+#endif
diff --git a/ANattr/src/TodayAttr.cpp b/ANattr/src/TodayAttr.cpp
new file mode 100644
index 0000000..a9068cb
--- /dev/null
+++ b/ANattr/src/TodayAttr.cpp
@@ -0,0 +1,193 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #38 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <sstream>
+
+#include "TodayAttr.hpp"
+#include "Calendar.hpp"
+#include "Indentor.hpp"
+#include "Log.hpp"
+#include "PrintStyle.hpp"
+#include "Ecf.hpp"
+
+using namespace std;
+
+namespace ecf {
+
+std::ostream& TodayAttr::print(std::ostream& os) const
+{
+ Indentor in;
+ Indentor::indent(os) << toString();
+ if (!PrintStyle::defsStyle()) {
+ os << timeSeries_.state_to_string(makeFree_);
+ }
+ os << "\n";
+ return os;
+}
+
+std::string TodayAttr::toString() const
+{
+ std::string ret = "today ";
+ ret += timeSeries_.toString();
+ return ret;
+}
+
+std::string TodayAttr::dump() const
+{
+ std::stringstream ss;
+ ss << "today ";
+
+ if (PrintStyle::getStyle() == PrintStyle::STATE) {
+ if (makeFree_) ss << "(free) ";
+ else ss << "(holding) ";
+ }
+
+ ss << timeSeries_.toString();
+
+ return ss.str();
+}
+
+bool TodayAttr::operator==(const TodayAttr& rhs) const
+{
+ if (makeFree_ != rhs.makeFree_) {
+ return false;
+ }
+ return timeSeries_.operator==(rhs.timeSeries_);
+}
+
+bool TodayAttr::structureEquals(const TodayAttr& rhs) const
+{
+ return timeSeries_.structureEquals(rhs.timeSeries_);
+}
+
+void TodayAttr::miss_next_time_slot()
+{
+ timeSeries_.miss_next_time_slot();
+ state_change_no_ = Ecf::incr_state_change_no();
+}
+
+void TodayAttr::setFree()
+{
+ makeFree_ = true;
+ state_change_no_ = Ecf::incr_state_change_no();
+}
+
+void TodayAttr::clearFree() {
+ makeFree_ = false;
+ state_change_no_ = Ecf::incr_state_change_no();
+}
+
+void TodayAttr::calendarChanged( const ecf::Calendar& c )
+{
+ if ( makeFree_ ) {
+ return;
+ }
+
+ if (timeSeries_.calendarChanged(c)) {
+ state_change_no_ = Ecf::incr_state_change_no();
+ }
+
+ // For a time series, we rely on the re queue to reset makeFree
+ if (isFree(c)) {
+ setFree();
+ }
+}
+
+void TodayAttr::resetRelativeDuration() {
+ if (timeSeries_.resetRelativeDuration()) {
+ state_change_no_ = Ecf::incr_state_change_no();
+ }
+}
+
+bool TodayAttr::isFree(const ecf::Calendar& calendar) const
+{
+ // The FreeDepCmd can be used to free the today,
+ if (makeFree_) {
+// LOG(Log::DBG," TodayAttr::isFree makeFree_");
+ return true;
+ }
+ return is_free(calendar);
+}
+
+bool TodayAttr::is_free(const ecf::Calendar& calendar) const
+{
+ if (!timeSeries_.hasIncrement()) {
+ if (timeSeries_.duration(calendar) > timeSeries_.start().duration() ) {
+ return true;
+ }
+ }
+
+ // For time series(/range), this is already handle by timeSeries_
+ // If timer expired return false. otherwise must match one time slot in the range/series
+ return timeSeries_.isFree(calendar);
+}
+
+bool TodayAttr::why(const ecf::Calendar& c, std::string& theReasonWhy) const
+{
+ if (isFree(c)) return false;
+ theReasonWhy += "is today dependent";
+
+ // Check to see if time has expired, if has not, then report why
+ if (timeSeries_.is_valid()) {
+ // This can apply to single and series
+ boost::posix_time::time_duration calendar_time = timeSeries_.duration(c);
+ if (calendar_time < timeSeries_.start().duration()) {
+ timeSeries_.why(c, theReasonWhy);
+ return true;
+ }
+
+ // calendar_time >= timeSeries_.start().duration()
+ if (timeSeries_.hasIncrement()) {
+ if (calendar_time < timeSeries_.finish().duration()) {
+ timeSeries_.why(c, theReasonWhy);
+ return true;
+ }
+ }
+ // calendar_time >= timeSeries_.start().duration() && calendar_time >= timeSeries_.finish().duration()
+ // past the end of time slot, hence this should not hold job generation,
+ }
+
+ // the today has expired,
+ theReasonWhy += " ( '";
+ theReasonWhy += toString();
+ theReasonWhy += "' has expired,";
+
+ // take into account, user can use run/force complete to miss time slots
+ bool do_a_requeue = timeSeries_.requeueable(c);
+ if (do_a_requeue) {
+ TimeSlot the_next_time_slot = timeSeries_.compute_next_time_slot(c);
+ if (the_next_time_slot.isNULL() || !timeSeries_.hasIncrement() ) {
+ theReasonWhy += " *re-queue* to run at this time";
+ }
+ else {
+ theReasonWhy += " *re-queue* to run at";
+ theReasonWhy += the_next_time_slot.toString() ;
+ }
+ }
+ else {
+ boost::gregorian::date_duration one_day(1);
+ boost::gregorian::date the_next_date = c.date(); // todays date
+ the_next_date += one_day; // add one day, so its in the future
+
+ theReasonWhy += " next run tomorrow at ";
+ theReasonWhy += timeSeries_.start().toString();
+ theReasonWhy += " ";
+ theReasonWhy += to_simple_string( the_next_date );
+ }
+ theReasonWhy += " )";
+
+ return true;
+}
+
+}
diff --git a/ANattr/src/TodayAttr.hpp b/ANattr/src/TodayAttr.hpp
new file mode 100644
index 0000000..2ea163d
--- /dev/null
+++ b/ANattr/src/TodayAttr.hpp
@@ -0,0 +1,185 @@
+#ifndef TODAYATTR_HPP_
+#define TODAYATTR_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #30 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : The Today attribute is heavily tied to the begin command
+// Real Clock:
+// 1/ Suite Begin time > Today time
+// If the suite 'begin' time is past the time given for today
+// the node is free to run.
+// 2/ Suite Begin time < Today Time
+// The node will 'hold' until current time > today time
+// 3/ Suite time, has passed midnight(next day)
+// then today command will permanently hold the node
+// 4/ Under Real/hybrid clocks today will hold node after
+// current is past last today time.
+//
+// take following example when we have a single time slot:
+// today 10:00
+// isFree:-----free-----
+// begin:
+// V
+// checkForReque:rrrrrrrrrrrrrrrrhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+// isFree:hhhhhhhhhhhhhhhh|fffffffffffffffffffffffffffffffffffffff *once* free we stay free (single slot *only*)
+// begin:
+// V
+// Today ======================0=====================0=================
+// 10:00 Midnight
+//
+// Difference between time and today. If begin is started after the time slot
+// then the node is free to re-run
+//
+// When we have a today time series:
+// today 10:00 20:00 01:00
+//
+// *** If the begin time is past 10:00 in the case above then the
+// *** node should is free to run once. However for a range its different
+// *** if suite begin time is past 20:00 then the node is held.
+//.
+// At 10am the Node is free, when node completes, it is re-queued
+// At 11am the Node is free, when node completes, it is re-queued
+// ....
+// At 20pm the Node is free, when node completes, it is *NOT* re-queued.
+//--------------------------------------------------------------------------------
+/// isFree is called when a node is queued. if it returns true, Task can be submitted
+/// checkForReque: is called when a node has completed, and need to determine if it should run again.
+/// These are different/orthogonal concerns.
+/// There is a *separate* issue of whether nodes should be queued when a node is *manually*
+/// a/ Set complete
+/// b/ Runs and then completes
+///
+/// For a *single* time slot we can't requeue.
+/// ****However we could have a set of time slots *****
+///
+/// isFree:ffffffffffffffff
+/// Begin:
+/// V
+///checkForReque:hhhhhhhhhhhhhhhhhrrrrrrrrhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+/// isFree:hhhhhhhhhhhhhhhh|fffffffffffffffffffffffffffffffffffffff
+/// begin :
+/// V
+/// Today ======================0========0===========0====================
+/// 10:00 11:00 Midnight
+/// isFree:hhhhhhhhhhhhhhhhhh
+/// V
+/// CheckForReque:hhhhhhhrrrrrrrrrrrrrrrrrrrrrrrrrhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+/// isFree:hhhhhhhFhhhhFhhhhFhhhhFhhhhFhhhhFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+/// V | | | | | | |
+/// Today ================o====|====|====|====|====0========0====================
+/// 10:00 1 2 3 4 15:00 Midnight
+///
+/// If the job starts at 10:00 but takes more than 1 hour, then it will miss the 11:00 slot
+/// and will have to start at 12:00
+//============================================================================
+
+#include <boost/serialization/level.hpp>
+#include <boost/serialization/tracking.hpp>
+
+#include "TimeSeries.hpp"
+
+
+namespace ecf { class Calendar;} // forward declare class
+
+namespace ecf {
+
+// Use compiler , destructor, assignment, copy constructor
+class TodayAttr {
+public:
+ TodayAttr() : makeFree_(false), state_change_no_(0) {}
+ TodayAttr(int hour, int minute, bool relative = false )
+ : timeSeries_(hour, minute,relative), makeFree_(false),state_change_no_(0) {}
+ TodayAttr(const TimeSlot& t, bool relative = false )
+ : timeSeries_(t,relative), makeFree_(false),state_change_no_(0) {}
+ TodayAttr(const TimeSeries& ts)
+ : timeSeries_(ts), makeFree_(false),state_change_no_(0) {}
+ TodayAttr(const TimeSlot& start, const TimeSlot& finish, const TimeSlot& incr,bool relative = false)
+ : timeSeries_(start,finish,incr,relative), makeFree_(false),state_change_no_(0) {}
+
+ std::ostream& print(std::ostream&) const;
+ bool operator==(const TodayAttr& rhs) const;
+ bool operator<(const TodayAttr& rhs) const { return timeSeries_ < rhs.timeSeries_; }
+ bool structureEquals(const TodayAttr& rhs) const;
+
+ /// This can set attribute as free, once free its stays free, until re-queue/reset
+ void calendarChanged( const ecf::Calendar& c );
+ void resetRelativeDuration();
+
+ void reset(const ecf::Calendar& c) { clearFree(); timeSeries_.reset(c);} // updates state_change_no_
+ void requeue(const ecf::Calendar& c,bool reset_next_time_slot = true)
+ { clearFree(); timeSeries_.requeue(c,reset_next_time_slot);} // updates state_change_no_
+
+ void miss_next_time_slot(); // updates state_change_no_
+ void setFree(); // ensures that isFree() always returns true, updates state_change_no_
+ bool isSetFree() const { return makeFree_; }
+
+ // This is used when we have a *single* today attribute
+ // single-slot is free, if calendar time >= today_time
+ // (range) is free, if calendar time == (one of the time ranges)
+ bool isFree(const ecf::Calendar&) const;
+
+ // This is used when we have a *multiple* today attribute
+ // (single | range) is free, if calendar time == (one of the time ranges)
+ // if timer *expired* returns false
+ // task t1
+ // today 09:00
+ // today 10:00
+ // If current times is 11:00, then we will return false.
+ // since both 09:00 and 10:00 have expired
+ // Multiple single today, should behave like a today with a range.
+ bool isFreeMultipleContext(const ecf::Calendar& c) const { return timeSeries_.isFree(c); }
+
+
+ bool checkForRequeue( const ecf::Calendar& c,const TimeSlot& the_min,const TimeSlot& the_max) const
+ { return timeSeries_.checkForRequeue(c,the_min,the_max);}
+ void min_max_time_slots(TimeSlot& the_min, TimeSlot& the_max) const {timeSeries_.min_max_time_slots(the_min,the_max);}
+ bool why(const ecf::Calendar&, std::string& theReasonWhy) const;
+ bool checkInvariants(std::string& errormsg) const { return timeSeries_.checkInvariants(errormsg);}
+
+ // The state_change_no is never reset. Must be incremented if it can affect equality
+ // Note: changes in state of timeSeries_, i.e affect the equality operator (used in test)
+ // must be captured. i.e things like relative duration & next_time_slot are
+ // reported by the Why command, & hence need to be synced.
+ unsigned int state_change_no() const { return state_change_no_; }
+
+ std::string name() const { return toString(); } /* ABO */
+ std::string toString() const;
+ std::string dump() const;
+
+ // access
+ const TimeSeries& time_series() const { return timeSeries_; }
+
+private:
+ void clearFree(); // resets the free flag, updates state_change_no_
+ bool is_free(const ecf::Calendar&) const; // ignores makeFree_
+
+private:
+ TimeSeries timeSeries_;
+ bool makeFree_; // persisted for use by why() on client side && for state changes
+ unsigned int state_change_no_; // *not* persisted, only used on server side
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/)
+ {
+ ar & timeSeries_;
+ ar & makeFree_;
+ }
+};
+
+}
+
+// This should ONLY be added to objects that are *NOT* serialised through a pointer
+BOOST_CLASS_IMPLEMENTATION(ecf::TodayAttr, boost::serialization::object_serializable);
+BOOST_CLASS_TRACKING(ecf::TodayAttr,boost::serialization::track_never);
+
+#endif
diff --git a/ANattr/src/Variable.cpp b/ANattr/src/Variable.cpp
new file mode 100644
index 0000000..4050880
--- /dev/null
+++ b/ANattr/src/Variable.cpp
@@ -0,0 +1,92 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #56 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <sstream>
+#include <stdexcept>
+
+#include "Variable.hpp"
+#include "Indentor.hpp"
+#include "Str.hpp"
+
+using namespace std;
+using namespace ecf;
+
+// init static's
+const Variable& Variable::EMPTY() { static const Variable VARIABLE = Variable(); return VARIABLE; }
+
+////////////////////////////////////////////////////////////////////////////////////////////
+
+Variable::Variable(const std::string& name, const std::string& value)
+: name_(name), value_(value)
+{
+ std::string msg;
+ if ( !Str::valid_name( name,msg ) ) {
+ throw std::runtime_error("Variable::Variable: Invalid Variable name: " + msg);
+ }
+}
+
+int Variable::value() const
+{
+ // see if the value is convertible to a integer
+ return Str::to_int( value_, 0/* value to return if conversion fails*/);
+}
+
+bool Variable::operator==( const Variable& rhs ) const {
+ if ( value_ != rhs.value_ )
+ return false;
+ if ( name_ != rhs.name_ )
+ return false;
+ return true;
+}
+
+std::ostream& Variable::print( std::ostream& os ) const {
+ // see notes in VariableParser.h
+ // Hence we do the following:
+ // a/ On parsing always remove quotes ie single or double
+ // b/ On serialising always add single quotes
+ Indentor in;
+ return Indentor::indent( os ) << toString() << "\n";
+}
+
+std::ostream& Variable::print_generated( std::ostream& os ) const {
+ Indentor in;
+ return Indentor::indent( os ) << "# " << toString() << "\n";
+}
+
+std::string Variable::toString() const
+{
+ std::string ret; ret.reserve(name_.size() + value_.size() + 8);
+ ret += "edit ";
+ ret += name_;
+ ret += " '";
+ if (value_.find("\n") == std::string::npos) ret += value_;
+ else {
+ // replace \n, otherwise re-parse will fail
+ std::string value = value_;
+ Str::replaceall(value,"\n","\\n");
+ ret += value;
+ }
+ ret += "'";
+ return ret;
+}
+
+
+std::string Variable::dump() const
+{
+ std::stringstream ss;
+ ss << toString() << " value(" << value() << ")";
+ return ss.str();
+}
+
diff --git a/ANattr/src/Variable.hpp b/ANattr/src/Variable.hpp
new file mode 100644
index 0000000..678f3c0
--- /dev/null
+++ b/ANattr/src/Variable.hpp
@@ -0,0 +1,75 @@
+#ifndef VARIABLE_HPP_
+#define VARIABLE_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #56 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <ostream>
+
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/string.hpp> // no need to include <string>
+#include <boost/serialization/tracking.hpp>
+#include <boost/serialization/level.hpp>
+
+////////////////////////////////////////////////////////////////////////////////////////
+// Class Variable:
+// Use compiler , generated destructor, assignment, copy constructor
+class Variable {
+public:
+ // This constructor added as an optimisation to avoid, checking variable names.
+ // i.e the generated variables, and created by the default constructors of Suite/Family/Task etc
+ // These are called during serialisation, hence to avoid checking generated names, we know are valid
+ // use this constructor. The bool is used as a dummy argument, so that we call the right constructor
+ Variable(const std::string& name, const std::string& value, bool /*check_names_dummy*/)
+ : name_(name), value_(value) {}
+ Variable(const std::string& name, const std::string& value);
+ Variable() {}
+
+ const std::string& name() const { return name_;}
+ std::ostream& print(std::ostream&) const;
+ std::ostream& print_generated(std::ostream&) const;
+ bool empty() const { return name_.empty(); }
+
+ void set_value(const std::string& v) { value_ = v; }
+ const std::string& theValue() const { return value_;}
+ int value() const;
+
+ void set_name(const std::string& v) { name_ = v; }
+ std::string& value_by_ref() { return value_;}
+
+ bool operator==(const Variable& rhs) const;
+ std::string toString() const;
+ std::string dump() const;
+
+ // Added to support return by reference
+ static const Variable& EMPTY();
+
+private:
+ std::string name_;
+ std::string value_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/)
+ {
+ ar & name_;
+ ar & value_;
+ }
+};
+
+// This should ONLY be added to objects that are *NOT* serialised through a pointer
+BOOST_CLASS_IMPLEMENTATION(Variable, boost::serialization::object_serializable)
+BOOST_CLASS_TRACKING(Variable,boost::serialization::track_never);
+
+#endif
diff --git a/ANattr/src/VerifyAttr.cpp b/ANattr/src/VerifyAttr.cpp
new file mode 100644
index 0000000..9cfca3e
--- /dev/null
+++ b/ANattr/src/VerifyAttr.cpp
@@ -0,0 +1,77 @@
+//============================================================================
+// Name : NodeTree.cpp
+// Author : Avi
+// Revision : $Revision: #19 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <sstream>
+#include <iostream>
+
+#include "VerifyAttr.hpp"
+#include "PrintStyle.hpp"
+#include "Indentor.hpp"
+#include "NState.hpp"
+#include "Ecf.hpp"
+#include "Str.hpp"
+
+using namespace ecf;
+
+bool VerifyAttr::operator==(const VerifyAttr& rhs) const
+{
+ if (state_ != rhs.state_) return false;
+ if (expected_ != rhs.expected_) return false;
+ return true;
+}
+
+std::ostream& VerifyAttr::print(std::ostream& os) const
+{
+ Indentor in;
+ Indentor::indent(os) << toString();
+ if (!PrintStyle::defsStyle()) {
+ os << " # " << actual_;
+ }
+ os << "\n";
+ return os;
+}
+
+void VerifyAttr::incrementActual() {
+ actual_++;
+ state_change_no_ = Ecf::incr_state_change_no();
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "VerifyAttr::incrementActual()\n";
+#endif
+}
+
+void VerifyAttr::reset() {
+ actual_ = 0;
+ state_change_no_ = Ecf::incr_state_change_no();
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "VerifyAttr::reset()\n";
+#endif
+}
+
+std::string VerifyAttr::toString() const
+{
+ std::stringstream ss;
+ ss << "verify " << NState::toString(state_) << Str::COLON() << expected_;
+ return ss.str();
+}
+
+std::string VerifyAttr::dump() const
+{
+ std::stringstream ss;
+ ss << "verify " << NState::toString(state_) << Str::COLON() << expected_;
+ ss << " actual(" << actual_ << ")";
+ return ss.str();
+}
+
diff --git a/ANattr/src/VerifyAttr.hpp b/ANattr/src/VerifyAttr.hpp
new file mode 100644
index 0000000..5bab60e
--- /dev/null
+++ b/ANattr/src/VerifyAttr.hpp
@@ -0,0 +1,73 @@
+#ifndef VERIFYATTR_HPP_
+#define VERIFYATTR_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <ostream>
+
+#include <boost/operators.hpp>
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/level.hpp>
+#include <boost/serialization/tracking.hpp>
+
+#include "NState.hpp"
+
+
+// Class VerifyAttr:
+// This class is only used for testing/verification purposes. It allows us to
+// embed expected number of states, within the definition file and so
+// reduce the need for golden log files.
+// Use compiler , generated destructor, assignment, copy constructor
+class VerifyAttr {
+public:
+ VerifyAttr(NState::State state,int expected)
+ : state_(state), expected_(expected), actual_(0), state_change_no_(0) {}
+ VerifyAttr()
+ : state_(NState::UNKNOWN), expected_(0), actual_(0),state_change_no_(0) {}
+
+ bool operator==(const VerifyAttr& rhs) const;
+ std::ostream& print(std::ostream&) const;
+
+ NState::State state() const { return state_;}
+ int expected() const { return expected_;}
+ int actual() const { return actual_;}
+ void incrementActual();
+ void reset();
+
+ // The state_change_no is never reset. Must be incremented if it can affect equality
+ unsigned int state_change_no() const { return state_change_no_; }
+
+ std::string toString() const;
+ std::string dump() const;
+
+private:
+ NState::State state_;
+ int expected_;
+ int actual_;
+ unsigned int state_change_no_; // *not* persisted, only used on server side
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/) {
+ ar & state_;
+ ar & expected_;
+ ar & actual_;
+ }
+};
+
+// This should ONLY be added to objects that are *NOT* serialised through a pointer
+BOOST_CLASS_IMPLEMENTATION(VerifyAttr, boost::serialization::object_serializable)
+BOOST_CLASS_TRACKING(VerifyAttr,boost::serialization::track_never);
+
+#endif
diff --git a/ANattr/src/Zombie.cpp b/ANattr/src/Zombie.cpp
new file mode 100644
index 0000000..bbe60fd
--- /dev/null
+++ b/ANattr/src/Zombie.cpp
@@ -0,0 +1,216 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #15 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Holds the zombie structure
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/foreach.hpp>
+
+#include "Zombie.hpp"
+#include "Calendar.hpp"
+
+using namespace ecf;
+using namespace std;
+
+// support return by reference
+const Zombie& Zombie::EMPTY() { static const Zombie ZOMBIE = Zombie(); return ZOMBIE; }
+Zombie& Zombie::EMPTY_() { static Zombie ZOMBIE = Zombie(); return ZOMBIE; }
+
+Zombie::Zombie( ecf::Child::ZombieType zombie_type,
+ ecf::Child::CmdType cmd,
+ const ZombieAttr& attr,
+ const std::string& pathToTask,
+ const std::string& jobsPassword,
+ const std::string& process_or_remote_id,
+ int try_no
+)
+: user_action_(User::BLOCK),
+ try_no_(try_no),
+ duration_(0),
+ calls_(1),
+ zombie_type_(zombie_type),
+ last_child_cmd_(cmd),
+ path_to_task_(pathToTask),
+ jobs_password_(jobsPassword),
+ process_or_remote_id_(process_or_remote_id),
+ user_action_set_(false),
+ attr_(attr),
+ creation_time_( Calendar::second_clock_time() )
+{}
+
+Zombie::Zombie()
+: user_action_(User::BLOCK),
+ try_no_(0),
+ duration_(0),
+ calls_(1),
+ zombie_type_(Child::USER),
+ last_child_cmd_(Child::INIT),
+ user_action_set_(false)
+{}
+
+std::string Zombie::type_str() const
+{
+ return Child::to_string(zombie_type_);
+}
+
+ecf::User::Action Zombie::user_action() const
+{
+ // User action needs to take into account, last child command and setting on attr_
+ if (fob()) return User::FOB;
+ else if (block()) return User::BLOCK;
+ else if (fail()) return User::FAIL;
+ else if (remove()) return User::REMOVE;
+ else if (kill()) return User::KILL;
+ else if (adopt()) return User::ADOPT;
+
+ return User::BLOCK; // the default action
+}
+
+std::string Zombie::user_action_str() const {
+ std::string ret;
+ if (manual_user_action()) ret = "manual-";
+ else ret = "auto-";
+ ret += User::to_string(user_action());
+ return ret;
+}
+
+/// accessors
+bool Zombie::fob() const {
+ if (user_action_set_) return user_action_ == User::FOB;
+ return attr_.fob(last_child_cmd_);
+}
+bool Zombie::fail() const {
+ if (user_action_set_) return user_action_ == User::FAIL;
+ return attr_.fail(last_child_cmd_);
+}
+bool Zombie::adopt() const {
+ if (user_action_set_) return user_action_ == User::ADOPT;
+ return attr_.adopt(last_child_cmd_);
+}
+bool Zombie::block() const {
+ if (user_action_set_) return user_action_ == User::BLOCK;
+ return attr_.block(last_child_cmd_);
+}
+bool Zombie::remove() const {
+ if (user_action_set_) return user_action_ == User::REMOVE;
+ return attr_.remove(last_child_cmd_);
+}
+bool Zombie::kill() const {
+ if (user_action_set_) return user_action_ == User::KILL;
+ return attr_.kill(last_child_cmd_);
+}
+
+int Zombie::allowed_age() const
+{
+ return attr_.zombie_lifetime();
+}
+
+void Zombie::set_fob() { user_action_ = User::FOB; user_action_set_ = true;}
+void Zombie::set_fail() { user_action_ = User::FAIL; user_action_set_ = true;}
+void Zombie::set_adopt() { user_action_ = User::ADOPT; user_action_set_ = true;}
+void Zombie::set_block() { user_action_ = User::BLOCK; user_action_set_ = true;}
+void Zombie::set_kill() { user_action_ = User::KILL; user_action_set_ = true;}
+
+
+std::ostream& operator<<(std::ostream& os, const Zombie& z)
+{
+ os << z.path_to_task() << " ";
+ os << z.type_str() << " ";
+ os << z.duration() << " ";
+ os << z.jobs_password() << " ";
+ os << z.process_or_remote_id() << "<pid> ";
+ os << z.try_no() << " ";
+ os << "calls(" << z.calls() << ") ";
+ os << z.user_action_str();
+ os << " ";
+ os << Child::to_string(z.last_child_cmd());
+ return os;
+}
+
+
+std::string Zombie::pretty_print(const std::vector<Zombie>& zombies,int indent)
+{
+ std::stringstream ss;
+ std::vector<std::string> list;
+ pretty_print(zombies, list, indent);
+ for (size_t i=0; i<list.size(); ++i) {
+ ss << list[i] << "\n";
+ }
+ return ss.str();
+}
+
+void Zombie::pretty_print(const std::vector<Zombie>& zombies,
+ std::vector<std::string>& list,
+ int indent)
+{
+ string path("task-path");
+ string type("type");
+ string password("password");
+ string rid("process-id");
+ string duration("duration");
+ string calls("calls");
+ string try_no("try_no");
+ string user_action("action");
+ string child_type("child");
+
+ size_t path_width = path.size();
+ size_t type_width = type.size();
+ size_t duration_width = duration.size();
+ size_t password_width = password.size();
+ size_t tryno_width = try_no.size();
+ size_t rid_width = rid.size();
+ size_t user_action_width = 13; // max of FOB,FAIL,ADOPT,BLOCK,REMOVE + (manual- | auto- )
+ size_t child_type_width = 8; // max of INIT,COMPLETE,EVENT,METER,LABEL,WAIT,ABORT
+ size_t calls_width = calls.size();
+
+ BOOST_FOREACH(const Zombie& z, zombies) {
+ path_width = std::max(path_width,z.path_to_task().size());
+ type_width = std::max(type_width,z.type_str().size());
+ password_width = std::max(password_width,z.jobs_password().size());
+ rid_width = std::max(rid_width,z.process_or_remote_id().size());
+ std::string no_of_calls = boost::lexical_cast<std::string>(z.calls());
+ calls_width = std::max(calls_width,no_of_calls.size());
+
+ std::string try_no_int = boost::lexical_cast<std::string>(z.try_no());
+ tryno_width = std::max(tryno_width,try_no_int.size());
+ }
+
+ std::stringstream ss;
+ if (indent != 0) for(int i = 0; i < indent; i++) ss << " ";
+ ss << left << setw(path_width) << path << " "
+ << setw(type_width) << type << " "
+ << setw(duration_width) << duration << " "
+ << setw(password_width) << password << " "
+ << setw(rid_width) << rid << " "
+ << setw(tryno_width) << try_no << " "
+ << setw(user_action_width) << user_action << " "
+ << setw(child_type_width) << child_type << " "
+ << setw(calls_width) << calls
+ ;
+
+ list.push_back(ss.str());
+
+ BOOST_FOREACH(const Zombie& z, zombies) {
+ std::stringstream ss;
+ if (indent != 0) for(int i = 0; i < indent; i++) ss << " ";
+ ss << left << setw(path_width) << z.path_to_task() << " "
+ << setw(type_width) << z.type_str() << " "
+ << setw(duration_width) << z.duration() << " "
+ << setw(password_width) << z.jobs_password() << " "
+ << setw(rid_width) << z.process_or_remote_id() << " "
+ << setw(tryno_width) << z.try_no() << " "
+ << setw(user_action_width) << z.user_action_str() << " "
+ << setw(child_type_width) << Child::to_string(z.last_child_cmd()) << " "
+ << setw(calls_width) << z.calls()
+ ;
+ list.push_back(ss.str());
+ }
+}
diff --git a/ANattr/src/Zombie.hpp b/ANattr/src/Zombie.hpp
new file mode 100644
index 0000000..4bfed12
--- /dev/null
+++ b/ANattr/src/Zombie.hpp
@@ -0,0 +1,167 @@
+#ifndef ZOMBIE_HPP_
+#define ZOMBIE_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #15 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Holds the zombie structure
+// WE have 3 structures:
+// Jobs(path,password,process_id)
+// Complications ONLY init command provides process_id.
+// Task(path,password,process_id)
+// Zombie(path,password,process_id)
+// Issues:
+// At the extreme we can have *2* Jobs running at one go. Typically user commands
+// that have a force parameter, will create 'user' zombies.
+// ** the command can be invoked at any time, i.e we could invoke
+// ** the user command, whilst the task is in SUBMITTED state
+// ** This will go through and create user zombie. However at this stage we have *NO* process_id
+// ** since the job has not started. Zombie(path,password)
+// When the Task init command is called, we get given a process_id.
+// ** HOWEVER ** need to determine if this is from the real child cmd or from the zombie
+// ** We search zombie list, and compare zombies, by path and password
+// ** if a match is found, we update the zombie id.
+//
+// IMPORTANT:: Automated test:
+// If a child command provides just path and password, this is *NOT*
+// enough information to disambiguate a zombie from a real job.
+// To work around this the job file has been updated to add ECF_RID=$$
+//
+// IMPORTANT:: For command line interface we just have the task path.
+// i,e we don't want to expose password, and user will not easily
+// know the process or remote id. Hence we will make do with the
+// task path. We just find the first zombie, and act up on it
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <string>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/level.hpp>
+#include <boost/serialization/tracking.hpp>
+#include "Child.hpp"
+#include "ZombieAttr.hpp"
+
+/// Use default copy constructor ,assignment operator and destructor
+class Zombie {
+public:
+ Zombie( ecf::Child::ZombieType zombie_type, // The kind of zombie
+ ecf::Child::CmdType child_cmd, // The Child command, that lead to this zombie
+ const ZombieAttr& attr, // will hold Action if set on node tree
+ const std::string& pathToTask, // from child ipc
+ const std::string& jobsPassword, // from child ipc
+ const std::string& process_or_remote_id,// from child ipc
+ int try_no
+ );
+ Zombie();
+
+/// accessors
+ // distinguish between manual and automatic user action. manual take precedence
+ bool manual_user_action() const { return user_action_set_;}
+ bool fob() const;
+ bool fail() const ;
+ bool adopt() const;
+ bool block() const;
+ bool remove() const;
+ bool kill() const;
+
+ ecf::Child::ZombieType type() const { return zombie_type_;}
+ ecf::Child::CmdType last_child_cmd() const { return last_child_cmd_; }
+ const ZombieAttr& attr() const { return attr_;}
+ int calls() const { return calls_;}
+
+ std::string type_str() const;
+ const std::string& jobs_password() const { return jobs_password_; }
+ const std::string& path_to_task() const { return path_to_task_; }
+ const std::string& process_or_remote_id() const { return process_or_remote_id_; }
+ int try_no() const { return try_no_; }
+ int duration() const { return duration_; }
+ ecf::User::Action user_action() const;
+ std::string user_action_str() const;
+
+
+ const boost::posix_time::ptime& creation_time() const { return creation_time_; }
+
+ bool empty() const { return path_to_task_.empty(); }
+
+ /// returns in seconds the age the zombie is allowed to live
+ /// Server typically checks every 60 seconds, hence this is lowest valid value that has effect
+ int allowed_age() const;
+
+/// mutators
+ void set_attr( const ZombieAttr& attr) { attr_ = attr;}
+ void set_process_or_remote_id( const std::string& s) { process_or_remote_id_ = s;}
+ void set_last_child_cmd( ecf::Child::CmdType c) { last_child_cmd_ = c;}
+ void set_type(ecf::Child::ZombieType zt) { zombie_type_ = zt; }
+
+ /// User action must take precedence over Zombie attribute settings on node tree
+ ///
+ /// Note: user_action to remove zombie is immediate hence no need to for set_remove()
+ /// Whereas for the other we want to store the action so that when next child
+ /// command communicate with the server, the action is applied.
+ void set_duration(int d) { duration_ = d;}
+ void set_fob();
+ void set_fail();
+ void set_adopt();
+ void set_block();
+ void set_kill();
+
+ void increment_calls() { calls_++;}
+
+ // write to standard out a title and list of zombies
+ static std::string pretty_print(const std::vector<Zombie>& zombies, int indent = 0);
+ static void pretty_print(const std::vector<Zombie>& zombies,
+ std::vector<std::string>& list,
+ int indent = 0);
+
+// MISC:
+ // Added to support return by reference
+ static const Zombie& EMPTY() ;
+ static Zombie& EMPTY_();
+
+private:
+
+ ecf::User::Action user_action_; // [ fob, fail, remove, adopt, block ]
+ int try_no_; // task try number, set on construction
+ int duration_; // How long zombie been alive
+ int calls_; // Number of times we have communicated with server.
+ ecf::Child::ZombieType zombie_type_; // [ ecf, path, user ]
+ ecf::Child::CmdType last_child_cmd_; // [ init | event | meter | label | wait | abort | complete ]
+ std::string path_to_task_; // set on construction
+ std::string jobs_password_; // set on construction
+ std::string process_or_remote_id_; // set on construction
+
+ bool user_action_set_; // Differentiate manual from automated, response, manual take precedence
+ ZombieAttr attr_; // Default or attribute obtained from node tree.
+ boost::posix_time::ptime creation_time_;// When zombie was created. Needed to control lifetime
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+
+ ar & user_action_;
+ ar & try_no_;
+ ar & duration_;
+ ar & calls_;
+ ar & zombie_type_;
+ ar & last_child_cmd_;
+ ar & path_to_task_;
+ ar & jobs_password_;
+ ar & process_or_remote_id_;
+ ar & user_action_set_;
+ ar & attr_;
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, const Zombie&);
+
+// This should ONLY be added to objects that are *NOT* serialised through a pointer
+BOOST_CLASS_IMPLEMENTATION(Zombie, boost::serialization::object_serializable)
+BOOST_CLASS_TRACKING(Zombie,boost::serialization::track_never);
+#endif
diff --git a/ANattr/src/ZombieAttr.cpp b/ANattr/src/ZombieAttr.cpp
new file mode 100644
index 0000000..1be0a57
--- /dev/null
+++ b/ANattr/src/ZombieAttr.cpp
@@ -0,0 +1,242 @@
+//============================================================================
+// Name : NodeTree.cpp
+// Author : Avi
+// Revision : $Revision: #13 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <sstream>
+#include <iostream>
+#include <assert.h>
+#include <boost/tokenizer.hpp>
+#include <boost/token_functions.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include "ZombieAttr.hpp"
+#include "Indentor.hpp"
+#include "Str.hpp"
+
+using namespace ecf;
+using namespace boost;
+using namespace std;
+
+/// int statics
+static int ecf_zombie_life_time = 3600;
+static int user_zombie_life_time = 300;
+static int path_zombie_life_time = 900;
+
+const ZombieAttr& ZombieAttr::EMPTY() { static const ZombieAttr ZOMBIEATTR = ZombieAttr(); return ZOMBIEATTR; }
+
+// Constructor ==============================================================================
+ZombieAttr::ZombieAttr(ecf::Child::ZombieType t, const std::vector<ecf::Child::CmdType>& c, ecf::User::Action a, int zombie_lifetime)
+ : zombie_type_(t), action_(a), zombie_lifetime_(zombie_lifetime), child_cmds_(c)
+{
+ /// Server typically checks every 60 seconds, hence this is lowest valid value for
+ /// zombie_lifetime_ is 60 seconds
+ if (zombie_lifetime_ <= 59) {
+ switch (zombie_type_) {
+ case Child::USER: zombie_lifetime_ = user_zombie_life_time; break;
+ case Child::PATH: zombie_lifetime_ = path_zombie_life_time; break;
+ case Child::ECF: zombie_lifetime_ = ecf_zombie_life_time; break;
+ case Child::NOT_SET: assert(false); break;
+ }
+ }
+}
+
+bool ZombieAttr::operator==(const ZombieAttr& rhs) const
+{
+ if (zombie_type_ != rhs.zombie_type_) return false;
+ if (action_ != rhs.action_) return false;
+ if (zombie_lifetime_ != rhs.zombie_lifetime_) return false;
+ if (child_cmds_ != rhs.child_cmds_) return false;
+ return true;
+}
+
+std::ostream& ZombieAttr::print(std::ostream& os) const
+{
+ Indentor in;
+ Indentor::indent(os) << toString();
+ os << "\n";
+ return os;
+}
+
+std::string ZombieAttr::toString() const
+{
+ /// format is zombie_type : child_cmds(optional) : action : zombie_lifetime_(optional)
+ std::stringstream ss;
+ ss << "zombie " << Child::to_string(zombie_type_)
+ << Str::COLON()
+ << User::to_string(action_)
+ << Str::COLON()
+ << Child::to_string(child_cmds_)
+ << Str::COLON()
+ << zombie_lifetime_
+ ;
+
+ return ss.str();
+}
+
+bool ZombieAttr::fob( ecf::Child::CmdType child_cmd) const
+{
+ if ( action_ != User::FOB) return false;
+ if ( child_cmds_.empty()) return true;
+
+ // If we have child commands specified, then the action is only applicable for that child cmd
+ // for all other child cmds we block
+ for(size_t i = 0; i < child_cmds_.size(); i++) {
+ if (child_cmds_[i] == child_cmd ) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool ZombieAttr::fail( ecf::Child::CmdType child_cmd) const
+{
+ if ( action_ != User::FAIL) return false;
+ if ( child_cmds_.empty()) return true;
+
+ // If we have child commands specified, then the action is only applicable for that child cmd
+ // for all other child cmds we block
+ for(size_t i = 0; i < child_cmds_.size(); i++) {
+ if (child_cmds_[i] == child_cmd ) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool ZombieAttr::adopt( ecf::Child::CmdType child_cmd) const
+{
+ if ( action_ != User::ADOPT) return false;
+ if ( child_cmds_.empty()) return true;
+
+ // If we have child commands specified, then the action is only applicable for that child cmd
+ // for all other child cmds we block
+ for(size_t i = 0; i < child_cmds_.size(); i++) {
+ if (child_cmds_[i] == child_cmd ) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool ZombieAttr::remove( ecf::Child::CmdType child_cmd) const
+{
+ if ( action_ != User::REMOVE) return false;
+ if ( child_cmds_.empty()) return true;
+
+ // If we have child commands specified, then the action is only applicable for that child cmd
+ // for all other child cmds we block
+ for(size_t i = 0; i < child_cmds_.size(); i++) {
+ if (child_cmds_[i] == child_cmd ) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool ZombieAttr::block( ecf::Child::CmdType child_cmd) const
+{
+ if ( action_ != User::BLOCK) return false;
+ if ( child_cmds_.empty()) return true;
+
+ // If we have child commands specified, then the action is only applicable for that child cmd
+ // for all other child cmds we block
+ for(size_t i = 0; i < child_cmds_.size(); i++) {
+ if (child_cmds_[i] == child_cmd ) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool ZombieAttr::kill( ecf::Child::CmdType child_cmd) const
+{
+ if ( action_ != User::KILL) return false;
+ if ( child_cmds_.empty()) return true;
+
+ // If we have child commands specified, then the action is only applicable for that child cmd
+ // for all other child cmds we block
+ for(size_t i = 0; i < child_cmds_.size(); i++) {
+ if (child_cmds_[i] == child_cmd ) {
+ return true;
+ }
+ }
+ return false;
+}
+
+ZombieAttr ZombieAttr::create(const std::string& string_to_parse)
+{
+ /// Use boost tokenizer instead of Str::split, as it allows preservation of empty tokens
+ char_separator<char> sep(":","",boost::keep_empty_tokens);
+ typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+ tokenizer tokenise(string_to_parse, sep);
+ std::vector<std::string> tokens;
+ std::copy(tokenise.begin(), tokenise.end(), back_inserter(tokens));
+ if (tokens.size() < 2) throw std::runtime_error("ZombieAttr::create failed: Invalid zombie type " + string_to_parse);
+
+ /// expects <zombie_type>:<user_action>:child_cmds:zombie_lifetime
+ string str_zombie_type;
+ string action_str;
+ string child_cmds;
+ string lifetime;
+ size_t tokens_size = tokens.size() ;
+ for(size_t i =0; i < tokens_size ; i++) {
+ // cout << " token " << i << ": '" << tokens[i] << "'\n";
+ if (i == 0) { str_zombie_type = tokens[i]; continue;}
+ if (i == 1) { action_str = tokens[i]; continue;}
+ if (i == 2) { child_cmds = tokens[i]; continue;}
+ if (i == 3) { lifetime = tokens[i]; continue;}
+ throw std::runtime_error("ZombieAttr::create failed: Invalid zombie tokens " + string_to_parse);
+ }
+ //std::cout << " zombie_type = " << str_zombie_type << " user_action = " << action_str << " child_cmds = " << child_cmds<< " zombie_lifetime = " << lifetime << "\n";
+
+ if (!Child::valid_zombie_type(str_zombie_type))
+ throw std::runtime_error("ZombieAttr::create failed: Invalid zombie type, expected one of [ user | ecf | path ] but found " + str_zombie_type + string(":") + string_to_parse);
+
+ if ( !action_str.empty() && !User::valid_user_action(action_str)) {
+ throw std::runtime_error("ZombieAttr::create failed: Invalid user action, expected one of [ fob | fail | remove | block | adopt | kill ] but found " + action_str + string(":") + string_to_parse);
+ }
+
+ if ( !child_cmds.empty() && !Child::valid_child_cmds(child_cmds)) {
+ throw std::runtime_error("ZombieAttr::create failed: Invalid child type, expected one or more of [ init,event,meter,label,wait,abort,complete] but found " + tokens[2] + string(":") + string_to_parse);
+ }
+
+ int zombie_lifetime = -1;
+ if ( !lifetime.empty() ) {
+ try { zombie_lifetime = boost::lexical_cast<int>(lifetime);}
+ catch ( boost::bad_lexical_cast& ) {
+ throw std::runtime_error("ZombieAttr::create failed: Zombie life time must be convertible to an integer " + lifetime + string(":") + string_to_parse);
+ }
+ }
+
+ if (action_str.empty() && zombie_lifetime == -1)
+ throw std::runtime_error("ZombieAttr::create failed: User Action(fob,fail,remove,adopt,block) or lifetime must be specified: " + string_to_parse);
+
+ Child::ZombieType zombie_type = Child::zombie_type(str_zombie_type);
+ User::Action action = User::user_action(action_str);
+ vector<Child::CmdType> childVec = Child::child_cmds(child_cmds);
+
+ /// If zombie_lifetime is still -1 constructor will reset to standard defaults
+ return ZombieAttr(zombie_type,childVec,action,zombie_lifetime) ;
+}
+
+ZombieAttr ZombieAttr::get_default_attr(ecf::Child::ZombieType zt)
+{
+ switch (zt) {
+ case Child::USER: return ZombieAttr(Child::USER,std::vector<ecf::Child::CmdType>(), User::BLOCK, user_zombie_life_time); break;
+ case Child::PATH: return ZombieAttr(Child::PATH,std::vector<ecf::Child::CmdType>(), User::BLOCK, path_zombie_life_time); break;
+ case Child::ECF: return ZombieAttr(Child::ECF, std::vector<ecf::Child::CmdType>(), User::BLOCK, ecf_zombie_life_time); break;
+ case Child::NOT_SET: break;
+ }
+ return ZombieAttr(Child::ECF, std::vector<ecf::Child::CmdType>(), User::BLOCK, ecf_zombie_life_time);
+}
+
diff --git a/ANattr/src/ZombieAttr.hpp b/ANattr/src/ZombieAttr.hpp
new file mode 100644
index 0000000..3be4652
--- /dev/null
+++ b/ANattr/src/ZombieAttr.hpp
@@ -0,0 +1,82 @@
+#ifndef ZOMBIE_ATTR_HPP_
+#define ZOMBIE_ATTR_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #9 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <ostream>
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/level.hpp>
+#include <boost/serialization/tracking.hpp>
+#include "Child.hpp"
+
+// Class ZombieAttr:
+// Use compiler , generated destructor, assignment, copy constructor
+// ZombieAttr does *not* have any changeable state
+class ZombieAttr {
+public:
+ ZombieAttr(ecf::Child::ZombieType t, const std::vector<ecf::Child::CmdType>& c, ecf::User::Action a, int zombie_lifetime = 0);
+ ZombieAttr() : zombie_type_(ecf::Child::NOT_SET), action_(ecf::User::BLOCK), zombie_lifetime_(0) {}
+
+ bool operator==(const ZombieAttr& rhs) const;
+ std::ostream& print(std::ostream&) const;
+ bool empty() const { return zombie_type_ == ecf::Child::NOT_SET; }
+
+ ecf::Child::ZombieType zombie_type() const { return zombie_type_;}
+ ecf::User::Action action() const { return action_; }
+ int zombie_lifetime() const { return zombie_lifetime_; }
+ const std::vector<ecf::Child::CmdType>& child_cmds() const { return child_cmds_; }
+
+ std::vector<ecf::Child::CmdType>::const_iterator child_begin() const { return child_cmds_.begin();} // for python
+ std::vector<ecf::Child::CmdType>::const_iterator child_end() const { return child_cmds_.end(); } // for python
+
+ std::string toString() const;
+
+ bool fob( ecf::Child::CmdType ) const;
+ bool fail( ecf::Child::CmdType ) const;
+ bool adopt( ecf::Child::CmdType ) const;
+ bool block( ecf::Child::CmdType ) const;
+ bool remove( ecf::Child::CmdType ) const;
+ bool kill( ecf::Child::CmdType ) const;
+
+ /// Create from a string. Will throw std::runtime_error of parse errors
+ /// expects <zombie_type>:<user_action>:child_cmds:zombie_lifetime
+ static ZombieAttr create(const std::string& str);
+
+ // Added to support return by reference
+ static const ZombieAttr& EMPTY();
+
+ // Provide the default behaviour
+ static ZombieAttr get_default_attr(ecf::Child::ZombieType);
+
+private:
+ ecf::Child::ZombieType zombie_type_; // User,path or ecf
+ ecf::User::Action action_; // fob, fail,remove, adopt, block, kill
+ int zombie_lifetime_; // How long zombie lives in server
+ std::vector<ecf::Child::CmdType> child_cmds_; // init, event, meter,label, complete
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/) {
+ ar & zombie_type_;
+ ar & action_;
+ ar & zombie_lifetime_;
+ ar & child_cmds_;
+ }
+};
+
+// This should ONLY be added to objects that are *NOT* serialised through a pointer
+BOOST_CLASS_IMPLEMENTATION(ZombieAttr, boost::serialization::object_serializable)
+BOOST_CLASS_TRACKING(ZombieAttr,boost::serialization::track_never);
+
+#endif
diff --git a/ANattr/test/TestAttrSerialization.cpp b/ANattr/test/TestAttrSerialization.cpp
new file mode 100644
index 0000000..854d894
--- /dev/null
+++ b/ANattr/test/TestAttrSerialization.cpp
@@ -0,0 +1,297 @@
+#define BOOST_TEST_MODULE TestANattr
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #24 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <boost/test/unit_test.hpp>
+#include <boost/make_shared.hpp>
+
+#include "TodayAttr.hpp"
+#include "TimeAttr.hpp"
+#include "VerifyAttr.hpp"
+#include "RepeatAttr.hpp"
+#include "LateAttr.hpp"
+#include "DayAttr.hpp"
+#include "DateAttr.hpp"
+#include "CronAttr.hpp"
+#include "ClockAttr.hpp"
+#include "AutoCancelAttr.hpp"
+#include "NodeAttr.hpp"
+#include "Variable.hpp"
+#include "ZombieAttr.hpp"
+#include "Calendar.hpp"
+#include "SerializationTest.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+
+// Globals used throughout the test
+static std::string fileName = "test.txt";
+
+BOOST_AUTO_TEST_SUITE( ANattrTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_AttrDefaultConstructor_serialisation )
+{
+ cout << "ANattr:: ...test_AttrDefaultConstructor_serialisation \n";
+
+ doSaveAndRestore<VerifyAttr>(fileName);
+ doSaveAndRestore<TodayAttr>(fileName);
+ doSaveAndRestore<TimeAttr>(fileName);
+ doSaveAndRestore<RepeatDate>(fileName);
+ doSaveAndRestore<RepeatInteger>(fileName);
+ doSaveAndRestore<RepeatEnumerated>(fileName);
+ doSaveAndRestore<RepeatString>(fileName);
+ doSaveAndRestore<LateAttr>(fileName);
+ doSaveAndRestore<DayAttr>(fileName);
+ doSaveAndRestore<DateAttr>(fileName);
+ doSaveAndRestore<CronAttr>(fileName);
+ doSaveAndRestore<ClockAttr>(fileName);
+ doSaveAndRestore<AutoCancelAttr>(fileName);
+ doSaveAndRestore<Label>(fileName);
+ doSaveAndRestore<Variable>(fileName);
+ doSaveAndRestore<Event>(fileName);
+ doSaveAndRestore<Meter>(fileName);
+ doSaveAndRestore<ZombieAttr>(fileName);
+}
+
+BOOST_AUTO_TEST_CASE( test_VerifyAttr_serialisation )
+{
+ cout << "ANattr:: ...test_VerifyAttr_serialisation \n";
+ VerifyAttr saved(NState::COMPLETE,10);
+ doSaveAndRestore(fileName,saved);
+}
+
+BOOST_AUTO_TEST_CASE( test_TodayAttr_serialisation )
+{
+ cout << "ANattr:: ...test_TodayAttr_serialisation \n";
+ {
+ TodayAttr saved(TimeSlot(10,12));
+ doSaveAndRestore(fileName,saved);
+ }
+ {
+ TodayAttr saved(TimeSlot(0,0),TimeSlot(10,12),TimeSlot(1,0));
+ doSaveAndRestore(fileName,saved);
+ }
+ {
+ TodayAttr saved(TimeSeries(TimeSlot(10,12)));
+ doSaveAndRestore(fileName,saved);
+ }
+ {
+ TodayAttr saved(TimeSeries(TimeSlot(10,12)));
+ doSaveAndRestore(fileName,saved);
+ }
+}
+
+
+BOOST_AUTO_TEST_CASE( test_TimeAttr_serialisation )
+{
+ cout << "ANattr:: ...test_TimeAttr_serialisation \n";
+ {
+ TimeAttr saved(TimeSlot(10,12));
+ doSaveAndRestore(fileName,saved);
+ }
+ {
+ TimeAttr saved(TimeSlot(0,0),TimeSlot(10,12),TimeSlot(1,0));
+ doSaveAndRestore(fileName,saved);
+ }
+ {
+ TimeAttr saved(TimeSeries(TimeSlot(10,12)));
+ doSaveAndRestore(fileName,saved);
+ }
+}
+
+
+BOOST_AUTO_TEST_CASE( test_RepeatAttr_serialisation )
+{
+ cout << "ANattr:: ...test_RepeatAttr_serialisation \n";
+ {
+ RepeatDate saved("varname",20101210,20101230,3);
+ doSaveAndRestore(fileName,saved);
+ }
+ {
+ RepeatInteger saved("varname",0,10,1);
+ doSaveAndRestore(fileName,saved);
+ }
+ {
+ std::vector<std::string> theVec; theVec.push_back("a"); theVec.push_back("b");
+ RepeatEnumerated saved = RepeatEnumerated("varname",theVec);
+ doSaveAndRestore(fileName,saved);
+ }
+ {
+ std::vector<std::string> theVec; theVec.push_back("a");
+ RepeatString saved = RepeatString("varname",theVec);
+ doSaveAndRestore(fileName,saved);
+ }
+
+
+ {
+ Repeat saved(RepeatDate("varname",20101210,20101230,3));
+ doSaveAndRestore(fileName,saved);
+ }
+ {
+ Repeat saved(RepeatInteger("varname",0,10,1));
+ doSaveAndRestore(fileName,saved);
+ }
+ {
+ std::vector<std::string> theVec; theVec.push_back("a"); theVec.push_back("b");
+ Repeat saved(RepeatEnumerated("varname",theVec));
+ doSaveAndRestore(fileName,saved);
+ }
+ {
+ std::vector<std::string> theVec; theVec.push_back("a");
+ Repeat saved(RepeatString("varname",theVec));
+ doSaveAndRestore(fileName,saved);
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_LateAttr_serialisation )
+{
+ cout << "ANattr:: ...test_LateAttr_serialisation \n";
+ LateAttr saved;
+ saved.addSubmitted(TimeSlot(10,12));
+ saved.addActive(TimeSlot(10,12));
+ saved.addComplete(TimeSlot(10,12),true);
+ doSaveAndRestore(fileName,saved);
+
+}
+
+BOOST_AUTO_TEST_CASE( test_DayAttr_serialisation )
+{
+ cout << "ANattr:: ...test_DayAttr_serialisation\n";
+ std::vector< DayAttr::Day_t > dvec;
+ dvec.push_back(DayAttr::SUNDAY);
+ dvec.push_back(DayAttr::MONDAY);
+ dvec.push_back(DayAttr::TUESDAY);
+ dvec.push_back(DayAttr::WEDNESDAY);
+ dvec.push_back(DayAttr::THURSDAY);
+ dvec.push_back(DayAttr::FRIDAY);
+ dvec.push_back(DayAttr::SATURDAY);
+ for(size_t d = 0; d < dvec.size(); d++) {
+ DayAttr saved(dvec[d]);
+ doSaveAndRestore(fileName,saved);
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_DateAttr_serialisation )
+{
+ cout << "ANattr:: ...test_DateAttr_serialisation\n";
+ DateAttr saved(1,1,2010);
+ doSaveAndRestore(fileName,saved);
+}
+
+BOOST_AUTO_TEST_CASE( test_CronAttr_serialisation )
+{
+ cout << "ANattr:: ...test_CronAttr_serialisation\n";
+ CronAttr saved;
+ std::vector<int> weekDays; weekDays.push_back(1); weekDays.push_back(2);
+ std::vector<int> daysOfMonth; daysOfMonth.push_back(1); daysOfMonth.push_back(2);
+ std::vector<int> months; months.push_back(1); months.push_back(2);
+ saved.addWeekDays(weekDays);
+ saved.addDaysOfMonth(daysOfMonth);
+ saved.addMonths(months);
+ saved.addTimeSeries(TimeSlot(0,0),TimeSlot(20,0),TimeSlot(0,1));
+
+ doSaveAndRestore(fileName,saved);
+}
+
+BOOST_AUTO_TEST_CASE( test_ClockAttr_serialisation )
+{
+ cout << "ANattr:: ...test_ClockAttr_serialisation\n";
+ {
+ ClockAttr saved(false);
+ saved.date(1,1,2009);
+ saved.set_gain_in_seconds(3600);
+ saved.startStopWithServer(true);
+
+ doSaveAndRestore(fileName,saved);
+ }
+ {
+ ClockAttr saved(Calendar::second_clock_time());
+ doSaveAndRestore(fileName,saved);
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_AutoCancelAttr_serialisation )
+{
+ cout << "ANattr:: ...test_AutoCancelAttr_serialisation\n";
+ {
+ AutoCancelAttr saved(100);
+ doSaveAndRestore(fileName,saved);
+ }
+ {
+ AutoCancelAttr saved( TimeSlot(12,10), true) ;
+ doSaveAndRestore(fileName,saved);
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_Label_serialisation )
+{
+ cout << "ANattr:: ...test_Label_serialisation\n";
+ {
+ Label saved("labelName","some text");
+ doSaveAndRestore(fileName,saved);
+ }
+}
+
+
+BOOST_AUTO_TEST_CASE( test_Variable_serialisation )
+{
+ cout << "ANattr:: ...test_Variable_serialisation\n";
+ Variable saved("varname","var value 123 12 =");
+ doSaveAndRestore(fileName,saved);
+}
+
+BOOST_AUTO_TEST_CASE( test_Event_serialisation )
+{
+ cout << "ANattr:: ...test_Event_serialisation\n";
+ {
+ Event saved(3);
+ doSaveAndRestore(fileName,saved);
+ }
+ {
+ Event saved(10+1,"event_name");
+ doSaveAndRestore(fileName,saved);
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_Meter_serialisation )
+{
+ cout << "ANattr:: ...test_Meter_serialisation\n";
+ Meter saved("meter",0,20,20);
+ doSaveAndRestore(fileName,saved);
+}
+
+
+BOOST_AUTO_TEST_CASE( test_zombie_attr_serialisation )
+{
+ cout << "ANattr:: ...test_zombie_attr_serialisation\n";
+
+ std::vector<ecf::Child::CmdType> child_cmds;
+ child_cmds.push_back(ecf::Child::INIT);
+ child_cmds.push_back(ecf::Child::EVENT);
+ child_cmds.push_back(ecf::Child::METER);
+ child_cmds.push_back(ecf::Child::LABEL);
+ child_cmds.push_back(ecf::Child::WAIT);
+ child_cmds.push_back(ecf::Child::ABORT);
+ child_cmds.push_back(ecf::Child::COMPLETE);
+
+ doSaveAndRestore(fileName,ZombieAttr(ecf::Child::USER, child_cmds, ecf::User::FOB,10));
+ doSaveAndRestore(fileName,ZombieAttr(ecf::Child::PATH, child_cmds, ecf::User::FAIL,10));
+ doSaveAndRestore(fileName,ZombieAttr(ecf::Child::ECF, child_cmds, ecf::User::BLOCK,10));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ANattr/test/TestCron.cpp b/ANattr/test/TestCron.cpp
new file mode 100644
index 0000000..4552866
--- /dev/null
+++ b/ANattr/test/TestCron.cpp
@@ -0,0 +1,439 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #14 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <boost/test/unit_test.hpp>
+#include <boost/date_time/posix_time/time_formatters.hpp>
+
+#include "CronAttr.hpp"
+#include "TimeSeries.hpp"
+#include "Calendar.hpp"
+#include "Str.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::posix_time;
+using namespace boost::gregorian;
+
+BOOST_AUTO_TEST_SUITE( ANattrTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_cron_parsing )
+{
+ cout << "ANattr:: ...test_cron_parsing\n";
+ TimeSlot start(10,10);
+ TimeSlot finish(23,10);
+ TimeSlot incr(0,1);
+
+ {
+ CronAttr cron;
+ CronAttr parsedCron;
+ BOOST_CHECK_MESSAGE(parsedCron.structureEquals(cron),"Expected " << cron.toString() << " but found " << parsedCron.toString());
+ }
+ {
+ CronAttr cron; cron.add_time_series(10,10,false);
+ CronAttr parsedCron = CronAttr::create("cron 10:10");
+ BOOST_CHECK_MESSAGE(parsedCron.structureEquals(cron),"Expected " << cron.toString() << " but found " << parsedCron.toString());
+ }
+ {
+ CronAttr cron; cron.add_time_series(10,10,true);
+ CronAttr parsedCron = CronAttr::create("cron +10:10");
+ BOOST_CHECK_MESSAGE(parsedCron.structureEquals(cron),"Expected " << cron.toString() << " but found " << parsedCron.toString());
+ }
+ {
+ CronAttr cron; cron.addTimeSeries(start,finish,incr);
+ CronAttr parsedCron = CronAttr::create("cron 10:10 23:10 00:01");
+ BOOST_CHECK_MESSAGE(parsedCron.structureEquals(cron),"Expected " << cron.toString() << " but found " << parsedCron.toString());
+ }
+
+ std::vector<int> week_days;
+ week_days.push_back(0);
+ week_days.push_back(1);
+ week_days.push_back(2);
+ week_days.push_back(3);
+ week_days.push_back(4);
+ week_days.push_back(5);
+ week_days.push_back(6);
+ {
+ CronAttr cron;
+ cron.addWeekDays(week_days);
+ cron.add_time_series(10,10,true);
+ CronAttr parsedCron = CronAttr::create("cron -w 0,1,2,3,4,5,6 +10:10");
+ BOOST_CHECK_MESSAGE(parsedCron.structureEquals(cron),"Expected " << cron.toString() << " but found " << parsedCron.toString());
+ }
+
+ std::vector<int> days_of_month;
+ days_of_month.push_back(1);
+ days_of_month.push_back(3);
+ days_of_month.push_back(4);
+ days_of_month.push_back(5);
+ days_of_month.push_back(6);
+ days_of_month.push_back(24);
+ days_of_month.push_back(25);
+ {
+ CronAttr cron;
+ cron.addDaysOfMonth(days_of_month);
+ cron.add_time_series(10,10,true);
+ CronAttr parsedCron = CronAttr::create("cron -d 1,3,4,5,6,24,25 +10:10");
+ BOOST_CHECK_MESSAGE(parsedCron.structureEquals(cron),"Expected " << cron.toString() << " but found " << parsedCron.toString());
+ }
+
+ std::vector<int> months;
+ months.push_back(1);
+ months.push_back(2);
+ months.push_back(3);
+ months.push_back(4);
+ months.push_back(5);
+ months.push_back(6);
+ months.push_back(7);
+ months.push_back(8);
+ months.push_back(9);
+ months.push_back(10);
+ months.push_back(11);
+ months.push_back(12);
+ {
+ CronAttr cron;
+ cron.addMonths(months);
+ cron.add_time_series(10,10,true);
+ CronAttr parsedCron = CronAttr::create("cron -m 1,2,3,4,5,6,7,8,9,10,11,12 +10:10");
+ BOOST_CHECK_MESSAGE(parsedCron.structureEquals(cron),"Expected " << cron.toString() << " but found " << parsedCron.toString());
+ }
+
+ {
+ CronAttr cron;
+ cron.addWeekDays(week_days);
+ cron.addDaysOfMonth(days_of_month);
+ cron.addMonths(months);
+ cron.addTimeSeries(start,finish,incr);
+ CronAttr parsedCron = CronAttr::create("cron -w 0,1,2,3,4,5,6 -d 1,3,4,5,6,24,25 -m 1,2,3,4,5,6,7,8,9,10,11,12 10:10 23:10 00:01");
+ BOOST_CHECK_MESSAGE(parsedCron.structureEquals(cron),"Expected " << cron.toString() << " but found " << parsedCron.toString());
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_cron_state_parsing )
+{
+ cout << "ANattr:: ...test_cron_state_parsing\n";
+
+ size_t index = 1; // to get over the cron
+ {
+ std::string line = "cron 04:30 # isValid:false";
+ std::vector<std::string> lineTokens;
+ Str::split(line,lineTokens);
+ bool parse_state = true;
+ CronAttr parsed_cronAttr;
+ CronAttr::parse( parsed_cronAttr,lineTokens, index, parse_state);
+
+ CronAttr expected;
+ TimeSeries series(4,30);
+ series.set_isValid(false); // to match isValid:false
+ expected.addTimeSeries(series);
+ BOOST_CHECK_MESSAGE(parsed_cronAttr == expected,"Expected " << expected.dump() << " : " << expected.time().dump()
+ << " but found " << parsed_cronAttr.dump() << " : " << parsed_cronAttr.time().dump());
+ }
+
+ {
+ std::string line = "cron 04:30 # free isValid:false";
+ std::vector<std::string> lineTokens;
+ Str::split(line,lineTokens);
+ bool parse_state = true;
+ CronAttr parsed_cronAttr;
+ CronAttr::parse( parsed_cronAttr,lineTokens, index, parse_state);
+
+ CronAttr expected;
+ TimeSeries series(4,30);
+ series.set_isValid(false); // to match isValid:false
+ expected.addTimeSeries(series);
+ expected.setFree();
+ BOOST_CHECK_MESSAGE(parsed_cronAttr == expected,"Expected " << expected.dump() << " : " << expected.time().dump()
+ << " but found " << parsed_cronAttr.dump() << " : " << parsed_cronAttr.time().dump());
+ }
+
+ {
+ std::string line = "cron 00:01 23:59 01:00 # nextTimeSlot/12:01";
+ std::vector<std::string> lineTokens;
+ Str::split(line,lineTokens);
+ bool parse_state = true;
+ CronAttr parsed_cronAttr;
+ CronAttr::parse( parsed_cronAttr,lineTokens, index, parse_state);
+
+ CronAttr expected;
+ TimeSlot start(0,1);
+ TimeSlot finish(23,59);
+ TimeSlot incr(1,0);
+ TimeSeries series(start, finish,incr);
+ series.set_next_time_slot(TimeSlot(12,1));
+ expected.addTimeSeries(series);
+ BOOST_CHECK_MESSAGE(parsed_cronAttr == expected,"Expected " << expected.dump() << " : " << expected.time().dump()
+ << " but found " << parsed_cronAttr.dump() << " : " << parsed_cronAttr.time().dump());
+ }
+
+ {
+ std::string line = "cron 00:01 23:59 01:00 # free nextTimeSlot/12:01";
+ std::vector<std::string> lineTokens;
+ Str::split(line,lineTokens);
+ bool parse_state = true;
+ CronAttr parsed_cronAttr;
+ CronAttr::parse( parsed_cronAttr,lineTokens, index, parse_state);
+
+ CronAttr expected;
+ TimeSlot start(0,1);
+ TimeSlot finish(23,59);
+ TimeSlot incr(1,0);
+ TimeSeries series(start, finish,incr);
+ series.set_next_time_slot(TimeSlot(12,1));
+ expected.addTimeSeries(series);
+ expected.setFree();
+ BOOST_CHECK_MESSAGE(parsed_cronAttr == expected,"Expected " << expected.dump() << " : " << expected.time().dump()
+ << " but found " << parsed_cronAttr.dump() << " : " << parsed_cronAttr.time().dump());
+ }
+ {
+ std::string line = "cron 00:00 18:00 06:00 # isValid:false nextTimeSlot/24:00";
+ std::vector<std::string> lineTokens;
+ Str::split(line,lineTokens);
+ bool parse_state = true;
+ CronAttr parsed_cronAttr;
+ CronAttr::parse( parsed_cronAttr,lineTokens, index, parse_state);
+
+ CronAttr expected;
+ TimeSlot start(0,0);
+ TimeSlot finish(18,0);
+ TimeSlot incr(6,0);
+ TimeSeries series(start, finish,incr);
+ series.set_next_time_slot(TimeSlot(24,0));
+ series.set_isValid(false); // to match isValid:false
+ expected.addTimeSeries(series);
+ BOOST_CHECK_MESSAGE(parsed_cronAttr == expected,"Expected " << expected.dump() << " : " << expected.time().dump()
+ << " but found " << parsed_cronAttr.dump() << " : " << parsed_cronAttr.time().dump());
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_cron_once_free_stays_free)
+{
+ cout << "ANattr:: ...test_cron_once_free_stays_free\n";
+
+ Calendar calendar;
+ calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::REAL);
+
+ TimeSeries timeSeriesX(TimeSlot(10,0), TimeSlot(20,0), TimeSlot(1,0), false/* relative */);
+ TimeSeries timeSeries2X(TimeSlot(11,0), TimeSlot(15,0), TimeSlot(1,0), false/* relative */);
+ TimeSeries timeSeries3X(TimeSlot(15,0), false/* relative */);
+ TimeSeries timeSeries4X(TimeSlot(0,0), false/* relative */);
+
+ CronAttr timeSeries; timeSeries.addTimeSeries(timeSeriesX );
+ CronAttr timeSeries2; timeSeries2.addTimeSeries(timeSeries2X );
+ CronAttr timeSeries3; timeSeries3.addTimeSeries(timeSeries3X );
+ CronAttr timeSeries4; timeSeries4.addTimeSeries(timeSeries4X );
+
+ std::vector<boost::posix_time::time_duration> timeSeries_free_slots;
+ std::vector<boost::posix_time::time_duration> timeSeries2_free_slots;
+ timeSeries.time_series().free_slots(timeSeries_free_slots);
+ timeSeries2.time_series().free_slots(timeSeries2_free_slots);
+ BOOST_CHECK_MESSAGE(timeSeries_free_slots.size() == 11,"Expected 11 free slots for " << timeSeries.toString() << " but found " << timeSeries_free_slots.size());
+ BOOST_CHECK_MESSAGE(timeSeries2_free_slots.size() == 5,"Expected 5 free slots for " << timeSeries2.toString() << " but found " << timeSeries_free_slots.size());
+
+ bool day_changed = false; // after midnight make sure we keep day_changed
+ for(int m=1; m < 96; m++) {
+ calendar.update( time_duration( minutes(30) ) );
+ if (!day_changed) {
+ day_changed = calendar.dayChanged();
+ }
+ boost::posix_time::time_duration time = calendar.suiteTime().time_of_day();
+ // cout << time << " day_changed(" << day_changed << ")\n";
+
+ timeSeries.calendarChanged( calendar );
+ timeSeries2.calendarChanged( calendar );
+ timeSeries3.calendarChanged( calendar );
+ timeSeries4.calendarChanged( calendar );
+
+ // cron should always reque regardless of time series
+ BOOST_CHECK_MESSAGE(timeSeries.checkForRequeue(calendar),timeSeries.toString() << " checkForRequeue should be true at time " << time );
+ BOOST_CHECK_MESSAGE(timeSeries2.checkForRequeue(calendar),timeSeries2.toString() << " checkForRequeue should be true at time " << time );
+ BOOST_CHECK_MESSAGE(timeSeries3.checkForRequeue(calendar),timeSeries3.toString() << " checkForRequeue should be true at time " << time );
+ BOOST_CHECK_MESSAGE(timeSeries4.checkForRequeue(calendar),timeSeries4.toString() << " checkForRequeue should be true at time " << time );
+
+ // **********************************************************************************
+ // When a cron (regardless of whether its single slot or time series) is free, it stays free,
+ // until explicitly re-queued,
+ // ***********************************************************************************
+
+ if (time < timeSeries.time_series().start().duration()) {
+ if (!day_changed) BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar),timeSeries.toString() << " should NOT be free at time " << time );
+ else BOOST_CHECK_MESSAGE(timeSeries.isFree(calendar),timeSeries.toString() << " should be free at time " << time );
+ }
+ else if (time >= timeSeries.time_series().start().duration()) {
+ BOOST_CHECK_MESSAGE(timeSeries.isFree(calendar),timeSeries.toString() << " should be free at time " << time );
+ }
+
+
+ if (time < timeSeries2.time_series().start().duration()) {
+ if (!day_changed) BOOST_CHECK_MESSAGE(!timeSeries2.isFree(calendar),timeSeries2.toString() << " should NOT be free at time " << time );
+ else BOOST_CHECK_MESSAGE(timeSeries.isFree(calendar),timeSeries.toString() << " should be free at time " << time );
+ }
+ else if (time >= timeSeries2.time_series().start().duration()) {
+ BOOST_CHECK_MESSAGE(timeSeries2.isFree(calendar),timeSeries2.toString() << " should be free at time " << time );
+ }
+
+ if (!day_changed) {
+ if (time == timeSeries3.time_series().start().duration() ) {
+ BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries3.toString() << " should be free at time " << time );
+ }
+ else if (time > timeSeries3.time_series().start().duration()) {
+ BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries3.toString() << " isFree, once free should stay free at time " << time );
+ }
+ }
+ else {
+ BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries3.toString() << " should be free at time after day change " << time );
+ }
+
+
+ // single slot at midnight, Once a single slot if Free it *stays* free until explicitly requeued, (i.e by parent repeat/cron)
+ if (!day_changed) {
+ if (time == timeSeries4.time_series().start().duration() ) {
+ BOOST_CHECK_MESSAGE(timeSeries4.isFree(calendar),timeSeries4.toString() << " should be free at time " << time );
+ }
+ else {
+ BOOST_CHECK_MESSAGE(!timeSeries4.isFree(calendar),timeSeries4.toString() << " day_changed(" << day_changed << ") isFree should fail at time " << time );
+ }
+ }
+ else {
+ BOOST_CHECK_MESSAGE(timeSeries4.isFree(calendar),timeSeries4.toString() << " day_changed(" << day_changed << ") isFree should pass at time " << time );
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_cron_time_series)
+{
+ cout << "ANattr:: ...test_cron_time_series\n";
+
+ // See TimeAttr.hpp for rules concerning isFree() and checkForReque()
+ // test time attr isFree(), and checkForRequeue
+ Calendar calendar;
+ calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::REAL);
+
+ TimeSeries timeSeriesX(TimeSlot(10,0), TimeSlot(20,0), TimeSlot(1,0), false/* relative */);
+ TimeSeries timeSeries2X(TimeSlot(11,0), TimeSlot(15,0), TimeSlot(1,0), false/* relative */);
+ TimeSeries timeSeries3X(TimeSlot(15,0), false/* relative */);
+ TimeSeries timeSeries4X(TimeSlot(0,0), false/* relative */);
+
+ CronAttr timeSeries; timeSeries.addTimeSeries(timeSeriesX );
+ CronAttr timeSeries2; timeSeries2.addTimeSeries(timeSeries2X );
+ CronAttr timeSeries3; timeSeries3.addTimeSeries(timeSeries3X );
+ CronAttr timeSeries4; timeSeries4.addTimeSeries(timeSeries4X );
+
+ std::vector<boost::posix_time::time_duration> timeSeries_free_slots;
+ std::vector<boost::posix_time::time_duration> timeSeries2_free_slots;
+ timeSeries.time_series().free_slots(timeSeries_free_slots);
+ timeSeries2.time_series().free_slots(timeSeries2_free_slots);
+ BOOST_CHECK_MESSAGE(timeSeries_free_slots.size() == 11,"Expected 11 free slots for " << timeSeries.toString() << " but found " << timeSeries_free_slots.size());
+ BOOST_CHECK_MESSAGE(timeSeries2_free_slots.size() == 5,"Expected 5 free slots for " << timeSeries2.toString() << " but found " << timeSeries_free_slots.size());
+
+ bool day_changed = false; // after midnight make sure we keep day_changed
+ for(int m=1; m < 96; m++) {
+ calendar.update( time_duration( minutes(30) ) );
+ if (!day_changed) {
+ day_changed = calendar.dayChanged();
+ }
+ boost::posix_time::time_duration time = calendar.suiteTime().time_of_day();
+// cout << time << " day_changed(" << day_changed << ")\n";
+
+ timeSeries.calendarChanged( calendar );
+ timeSeries2.calendarChanged( calendar );
+ timeSeries3.calendarChanged( calendar );
+ timeSeries4.calendarChanged( calendar );
+
+ // cron should always reque regardless of time series
+ BOOST_CHECK_MESSAGE(timeSeries.checkForRequeue(calendar),timeSeries.toString() << " checkForRequeue should be true at time " << time );
+ BOOST_CHECK_MESSAGE(timeSeries2.checkForRequeue(calendar),timeSeries2.toString() << " checkForRequeue should be true at time " << time );
+ BOOST_CHECK_MESSAGE(timeSeries3.checkForRequeue(calendar),timeSeries3.toString() << " checkForRequeue should be true at time " << time );
+ BOOST_CHECK_MESSAGE(timeSeries4.checkForRequeue(calendar),timeSeries4.toString() << " checkForRequeue should be true at time " << time );
+
+ // **********************************************************************************
+ // When a cron (regardless of whether its single slot or time series) is free, it stays free
+ // However in order to test crons with time series, we will re-queue ate the end of this loop
+ // ***********************************************************************************
+
+ if (time < timeSeries.time_series().start().duration()) {
+ BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar),timeSeries.toString() << " should NOT be free at time " << time );
+ }
+ else if (time >= timeSeries.time_series().start().duration() && time <=timeSeries.time_series().finish().duration()) {
+
+ bool matches_free_slot = false;
+ for(size_t i = 0; i < timeSeries_free_slots.size(); i++) {
+ if (time == timeSeries_free_slots[i]) { matches_free_slot = true; break; }
+ }
+ if (matches_free_slot) BOOST_CHECK_MESSAGE(timeSeries.isFree(calendar),timeSeries.toString() << " should be free at time " << time );
+ else BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar),timeSeries.toString() << " should be fail at time " << time );
+ }
+ else {
+ BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar),timeSeries.toString() << " should be holding at time " << time );
+ }
+
+
+ if (time < timeSeries2.time_series().start().duration()) {
+ BOOST_CHECK_MESSAGE(!timeSeries2.isFree(calendar),timeSeries2.toString() << " should NOT be free at time " << time );
+ }
+ else if (time >= timeSeries2.time_series().start().duration() && time <=timeSeries2.time_series().finish().duration()) {
+
+ bool matches_free_slot = false;
+ for(size_t i = 0; i < timeSeries2_free_slots.size(); i++) {
+ if (time == timeSeries2_free_slots[i]) { matches_free_slot = true; break;}
+ }
+ if (matches_free_slot) BOOST_CHECK_MESSAGE(timeSeries2.isFree(calendar),timeSeries2.toString() << " should be free at time " << time );
+ else BOOST_CHECK_MESSAGE(!timeSeries2.isFree(calendar),timeSeries2.toString() << " should be fail at time " << time );
+ }
+ else {
+ BOOST_CHECK_MESSAGE(!timeSeries2.isFree(calendar),timeSeries2.toString() << " should be holding at time " << time );
+ }
+
+
+ // Single slot, Once a single slot if Free it *stays* free until explicitly requeued, (i.e by parent repeat/cron)
+ if (!day_changed) {
+ if (time == timeSeries3.time_series().start().duration() ) {
+ BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries3.toString() << " should be free at time " << time );
+ }
+ else if (time > timeSeries3.time_series().start().duration()) {
+ BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries3.toString() << " isFree, once free should stay free at time " << time );
+ }
+ }
+ else {
+ BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries3.toString() << " should be free at time after day change " << time );
+ }
+
+
+ // single slot at midnight, Once a single slot if Free it *stays* free until explicitly requeued, (i.e by parent repeat/cron)
+ if (!day_changed) {
+ if (time == timeSeries4.time_series().start().duration() ) {
+ BOOST_CHECK_MESSAGE(timeSeries4.isFree(calendar),timeSeries4.toString() << " should be free at time " << time );
+ }
+ else {
+ BOOST_CHECK_MESSAGE(!timeSeries4.isFree(calendar),timeSeries4.toString() << " day_changed(" << day_changed << ") isFree should fail at time " << time );
+ }
+ }
+ else {
+ BOOST_CHECK_MESSAGE(timeSeries4.isFree(calendar),timeSeries4.toString() << " day_changed(" << day_changed << ") isFree should pass at time " << time );
+ }
+
+ // Typically when a cron is free, it stays free, until it is re-queued
+ // However in order to test isFree for cron with time inetrvals, we need to re-queue
+ timeSeries.requeue( calendar );
+ timeSeries2.requeue( calendar );
+
+ // Do not requeue cron 00, and cron 15, so that we can check for free
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/ANattr/test/TestDayAttr.cpp b/ANattr/test/TestDayAttr.cpp
new file mode 100644
index 0000000..2486db1
--- /dev/null
+++ b/ANattr/test/TestDayAttr.cpp
@@ -0,0 +1,77 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #14 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <boost/test/unit_test.hpp>
+#include <boost/date_time/posix_time/time_formatters.hpp>
+
+#include "DayAttr.hpp"
+#include "Calendar.hpp"
+#include "Str.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::posix_time;
+using namespace boost::gregorian;
+
+BOOST_AUTO_TEST_SUITE( ANattrTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_day_attr)
+{
+ cout << "ANattr:: ...test_day_attr\n";
+
+ // See TimeAttr.hpp for rules concerning isFree() and checkForReque()
+ // test time attr isFree(), and checkForRequeue
+ Calendar calendar;
+ calendar.init(ptime(date(2013,7,9), minutes(0)), Calendar::REAL); // tuesday
+
+ // Represent a day within a week (range 0==Sun to 6==Sat)
+ BOOST_CHECK_MESSAGE(calendar.day_of_week() == 2 ," Expected tuesday(2) but found " << calendar.day_of_week() );
+
+ DayAttr day(DayAttr::WEDNESDAY);
+
+ int day_changed = 0; // after midnight make sure we keep day_changed
+ // day_changed = 0; tuesday
+ // day_changed = 1; wednesday
+ // day_changed = 3; thursday
+ for(int m=1; m < 96; m++) {
+ calendar.update( time_duration( hours(1) ) );
+ if (calendar.dayChanged()) day_changed++;
+
+ // cout << " day_changed(" << day_changed << ") calendar.day_of_week() = " << calendar.day_of_week() << "\n";
+
+ day.calendarChanged( calendar );
+
+ if ( calendar.day_of_week() < day.day() ) {
+ BOOST_CHECK_MESSAGE(!day.isFree(calendar),day.toString() << " is free should fail at day " << calendar.day_of_week() );
+ BOOST_CHECK_MESSAGE(day.checkForRequeue(calendar),day.toString() << " checkForRequeue should pass at " << calendar.day_of_week() );
+ }
+ else if (calendar.day_of_week() == day.day() ) {
+ BOOST_CHECK_MESSAGE(day.isFree(calendar),day.toString() << " is free should pass at day " << calendar.day_of_week() );
+ BOOST_CHECK_MESSAGE(!day.checkForRequeue(calendar),day.toString() << " checkForRequeue should fail at " << calendar.day_of_week() );
+ }
+ else {
+ BOOST_CHECK_MESSAGE(calendar.day_of_week() > day.day(),"");
+ BOOST_CHECK_MESSAGE(!day.isFree(calendar),day.toString() << " is free should fail at day " << calendar.day_of_week() );
+ BOOST_CHECK_MESSAGE(!day.checkForRequeue(calendar),day.toString() << " checkForRequeue should fail at " << calendar.day_of_week() );
+ }
+ }
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/ANattr/test/TestLabel.cpp b/ANattr/test/TestLabel.cpp
new file mode 100644
index 0000000..5425a4f
--- /dev/null
+++ b/ANattr/test/TestLabel.cpp
@@ -0,0 +1,83 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #14 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <boost/test/unit_test.hpp>
+
+#include "NodeAttr.hpp"
+#include "Str.hpp"
+
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( ANattrTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_label_parsing )
+{
+ cout << "ANattr:: ...test_label_parsing\n";
+ {
+ std::string line = "label name \"value\"";
+ std::vector<string> linetokens;
+ Str::split(line,linetokens);
+
+ Label label;
+ label.parse(line,linetokens, false);
+
+ Label expected("name","value");
+ BOOST_CHECK_MESSAGE(label == expected,"Expected " << expected.toString() << " but found " << label.toString());
+ BOOST_CHECK_MESSAGE(label.dump() == expected.dump(),"Expected " << expected.dump() << " but found " << label.dump());
+ }
+ {
+ std::string line = "label name \"value\\nvalue\"";
+ std::vector<string> linetokens;
+ Str::split(line,linetokens);
+
+ Label label;
+ label.parse(line,linetokens, false);
+
+ Label expected("name","value\nvalue");
+ BOOST_CHECK_MESSAGE(label == expected,"Expected " << expected.toString() << " but found " << label.toString());
+ BOOST_CHECK_MESSAGE(label.dump() == expected.dump(),"Expected " << expected.dump() << " but found " << label.dump());
+ }
+ {
+ std::string line = "label name \"value that is multiple token !!!! 23445 !^ & * ( )\"";
+ std::vector<string> linetokens;
+ Str::split(line,linetokens);
+
+ Label label;
+ label.parse(line,linetokens, false);
+
+ Label expected("name","value that is multiple token !!!! 23445 !^ & * ( )");
+ BOOST_CHECK_MESSAGE(label == expected,"Expected " << expected.toString() << " but found " << label.toString());
+ BOOST_CHECK_MESSAGE(label.dump() == expected.dump(),"Expected " << expected.dump() << " but found " << label.dump());
+ }
+ {
+ std::string line = "label name \"value\\n that\\n is\\n multiple\\n token\\n and\\n new\\n \\nlines\"";
+ std::vector<string> linetokens;
+ Str::split(line,linetokens);
+
+ Label label;
+ label.parse(line,linetokens, false);
+
+ Label expected("name","value\n that\n is\n multiple\n token\n and\n new\n \nlines");
+ BOOST_CHECK_MESSAGE(label == expected,"Expected " << expected.toString() << " but found " << label.toString());
+ BOOST_CHECK_MESSAGE(label.dump() == expected.dump(),"Expected " << expected.dump() << " but found " << label.dump());
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/ANattr/test/TestLateAttr.cpp b/ANattr/test/TestLateAttr.cpp
new file mode 100644
index 0000000..31212e8
--- /dev/null
+++ b/ANattr/test/TestLateAttr.cpp
@@ -0,0 +1,285 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #14 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <boost/test/unit_test.hpp>
+#include <boost/date_time/posix_time/time_formatters.hpp>
+
+#include "LateAttr.hpp"
+#include "Calendar.hpp"
+#include "Str.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::posix_time;
+using namespace boost::gregorian;
+
+BOOST_AUTO_TEST_SUITE( ANattrTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_late_attr_submitted )
+{
+ cout << "ANattr:: ...test_late_attr_submitted\n";
+
+ //REF: ECFLOW-322
+ Calendar calendar;
+ calendar.init(ptime(date(2013,7,9), minutes(0)), Calendar::REAL); // tuesday
+
+ /// -s submitted: The time node can stay submitted (format [+]hh:mm). submitted is always
+ /// relative, so + is simple ignored, if present. If the node stays submitted
+ /// longer than the time specified, the late flag is set
+ /// -a Active : The time of day the node must have become active (format hh:mm). If the node
+ /// is still queued or submitted, the late flag is set
+ /// -c Complete : The time node must become complete (format {+}hh:mm). If relative, time is
+ /// taken from the time the node became active, otherwise node must be complete by
+ /// the time given.
+ ecf::LateAttr lateAttr;
+ lateAttr.addSubmitted( ecf::TimeSlot(0,4) );
+
+ calendar.update( time_duration( minutes(1) ) );
+ calendar.update( time_duration( minutes(1) ) );
+ calendar.update( time_duration( minutes(1) ) );
+ calendar.update( time_duration( minutes(1) ) );
+ calendar.update( time_duration( minutes(1) ) );
+
+ // set submitted state at 00:05:00
+ //cout << "start:" << to_simple_string(calendar.suiteTime()) << "\n";
+ std::pair<NState,boost::posix_time::time_duration> state = std::make_pair(NState::SUBMITTED, calendar.duration() );
+
+ // after four minutes in submitted state, we should be late
+ for(int m=1; m < 10; m++) {
+ calendar.update( time_duration( minutes(1) ) );
+ //cout << "m=" << m << " " << to_simple_string(calendar.suiteTime()) << "\n";
+
+ lateAttr.checkForLateness(state, calendar );
+ //if (lateAttr.isLate()) {
+ // cout << "late at m=" << m << " " << to_simple_string(calendar.suiteTime()) << "\n";
+ //}
+
+ if ( m >= 4 ) {
+ BOOST_CHECK_MESSAGE( lateAttr.isLate()," expected to be late at " << to_simple_string(calendar.suiteTime()));
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_late_attr_active )
+{
+ cout << "ANattr:: ...test_late_attr_active\n";
+
+ Calendar calendar;
+ calendar.init(ptime(date(2013,7,9), minutes(0)), Calendar::REAL); // tuesday
+
+ /// -s submitted: The time node can stay submitted (format [+]hh:mm). submitted is always
+ /// relative, so + is simple ignored, if present. If the node stays submitted
+ /// longer than the time specified, the late flag is set
+ /// -a Active : The time of day the node must have become active (format hh:mm). If the node
+ /// is still queued or submitted, the late flag is set
+ /// -c Complete : The time node must become complete (format {+}hh:mm). If relative, time is
+ /// taken from the time the node became active, otherwise node must be complete by
+ /// the time given.
+
+ ecf::LateAttr lateAttr;
+ lateAttr.addActive( ecf::TimeSlot(10,0) );
+
+ // set submitted state at 00:00:00
+ //cout << "start:" << to_simple_string(calendar.suiteTime()) << "\n";
+ std::pair<NState,boost::posix_time::time_duration> state = std::make_pair(NState::SUBMITTED, calendar.duration() );
+
+ // after 10 hours we, if we are not active, we should be late
+ for(int m=1; m < 23; m++) {
+ calendar.update( time_duration( hours(1) ) );
+ //cout << "m=" << m << " " << to_simple_string(calendar.suiteTime()) << "\n";
+
+ lateAttr.checkForLateness(state, calendar );
+// if (lateAttr.isLate()) {
+// cout << "late at m=" << m << " " << to_simple_string(calendar.suiteTime()) << "\n";
+// }
+
+ if ( m >= 10 ) {
+ BOOST_CHECK_MESSAGE( lateAttr.isLate()," expected to be late at " << to_simple_string(calendar.suiteTime()));
+ }
+ }
+}
+
+
+BOOST_AUTO_TEST_CASE( test_late_attr_complete_relative )
+{
+ cout << "ANattr:: ...test_late_attr_complete_relative\n";
+
+ Calendar calendar;
+ calendar.init(ptime(date(2013,7,9), minutes(0)), Calendar::REAL); // tuesday
+
+ /// -s submitted: The time node can stay submitted (format [+]hh:mm). submitted is always
+ /// relative, so + is simple ignored, if present. If the node stays submitted
+ /// longer than the time specified, the late flag is set
+ /// -a Active : The time of day the node must have become active (format hh:mm). If the node
+ /// is still queued or submitted, the late flag is set
+ /// -c Complete : The time node must become complete (format {+}hh:mm). If relative, time is
+ /// taken from the time the node became active, otherwise node must be complete by
+ /// the time given.
+
+ ecf::LateAttr lateAttr;
+ lateAttr.addComplete( ecf::TimeSlot(0,15), true);
+
+ // set active state at 00:00:00
+// cout << "start:" << to_simple_string(calendar.suiteTime()) << "\n";
+ std::pair<NState,boost::posix_time::time_duration> state = std::make_pair(NState::ACTIVE, calendar.duration() );
+
+ // after 15 minutes relative, if we are not complete, we should be late
+ for(int m=1; m < 23; m++) {
+ calendar.update( time_duration( minutes(1) ) );
+// cout << "m=" << m << " " << to_simple_string(calendar.suiteTime()) << "\n";
+
+ lateAttr.checkForLateness(state, calendar );
+// if (lateAttr.isLate()) {
+// cout << "late at m=" << m << " " << to_simple_string(calendar.suiteTime()) << "\n";
+// }
+
+ if ( m >= 15 ) {
+ BOOST_CHECK_MESSAGE( lateAttr.isLate()," expected to be late at " << to_simple_string(calendar.suiteTime()));
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_late_attr_complete_real )
+{
+ cout << "ANattr:: ...test_late_attr_complete_real\n";
+
+ Calendar calendar;
+ calendar.init(ptime(date(2013,7,9), minutes(0)), Calendar::REAL); // tuesday
+
+ /// -s submitted: The time node can stay submitted (format [+]hh:mm). submitted is always
+ /// relative, so + is simple ignored, if present. If the node stays submitted
+ /// longer than the time specified, the late flag is set
+ /// -a Active : The time of day the node must have become active (format hh:mm). If the node
+ /// is still queued or submitted, the late flag is set
+ /// -c Complete : The time node must become complete (format {+}hh:mm). If relative, time is
+ /// taken from the time the node became active, otherwise node must be complete by
+ /// the time given.
+
+ ecf::LateAttr lateAttr;
+ lateAttr.addComplete( ecf::TimeSlot(3,0), false);
+
+ // set active state at 00:00:00
+// cout << "start:" << to_simple_string(calendar.suiteTime()) << "\n";
+ std::pair<NState,boost::posix_time::time_duration> state = std::make_pair(NState::ACTIVE, calendar.duration() );
+
+ // after 3 hours we, if we are not complete, we should be late
+ for(int m=1; m < 7; m++) {
+
+ calendar.update( time_duration( hours(1) ) );
+// cout << "m=" << m << " " << to_simple_string(calendar.suiteTime()) << "\n";
+
+ lateAttr.checkForLateness(state, calendar );
+// if (lateAttr.isLate()) {
+// cout << "late at m=" << m << " " << to_simple_string(calendar.suiteTime()) << "\n";
+// }
+
+ if ( m >= 3 ) {
+ BOOST_CHECK_MESSAGE( lateAttr.isLate()," expected to be late at " << to_simple_string(calendar.suiteTime()));
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_late_parsing )
+{
+ cout << "ANattr:: ...test_late_parsing\n";
+ TimeSlot start(10,10);
+ TimeSlot finish(23,10);
+ {
+ LateAttr late;
+ LateAttr parsedlate;
+ BOOST_CHECK_MESSAGE(late == parsedlate ,"Expected " << late.toString() << " but found " << parsedlate.toString());
+ }
+ {
+ LateAttr late; late.addSubmitted(start);
+ LateAttr parsedLate = LateAttr::create("late -s 10:10");
+ BOOST_CHECK_MESSAGE(late == parsedLate,"Expected " << late.toString() << " but found " << parsedLate.toString());
+ parsedLate = LateAttr::create("-s 10:10");
+ BOOST_CHECK_MESSAGE(late == parsedLate,"Expected " << late.toString() << " but found " << parsedLate.toString());
+ }
+ {
+ LateAttr late; late.addActive(finish);
+ LateAttr parsedLate = LateAttr::create("late -a 23:10");
+ BOOST_CHECK_MESSAGE(late == parsedLate,"Expected " << late.toString() << " but found " << parsedLate.toString());
+ parsedLate = LateAttr::create("-a 23:10");
+ BOOST_CHECK_MESSAGE(late == parsedLate,"Expected " << late.toString() << " but found " << parsedLate.toString());
+ }
+ {
+ LateAttr late; late.addComplete(finish,false);
+ LateAttr parsedLate = LateAttr::create("late -c 23:10");
+ BOOST_CHECK_MESSAGE(late == parsedLate,"Expected " << late.toString() << " but found " << parsedLate.toString());
+ parsedLate = LateAttr::create("-c 23:10");
+ BOOST_CHECK_MESSAGE(late == parsedLate,"Expected " << late.toString() << " but found " << parsedLate.toString());
+ }
+ {
+ LateAttr late; late.addComplete(finish,true);
+ LateAttr parsedLate = LateAttr::create("late -c +23:10");
+ BOOST_CHECK_MESSAGE(late == parsedLate,"Expected " << late.toString() << " but found " << parsedLate.toString());
+ parsedLate = LateAttr::create("-c +23:10");
+ BOOST_CHECK_MESSAGE(late == parsedLate,"Expected " << late.toString() << " but found " << parsedLate.toString());
+ }
+ {
+ LateAttr late; late.addComplete(finish,true);
+ LateAttr parsedLate = LateAttr::create("late -c +23:10");
+ BOOST_CHECK_MESSAGE(late == parsedLate,"Expected " << late.toString() << " but found " << parsedLate.toString());
+ parsedLate = LateAttr::create("-c +23:10");
+ BOOST_CHECK_MESSAGE(late == parsedLate,"Expected " << late.toString() << " but found " << parsedLate.toString());
+ }
+ {
+ LateAttr late; late.addSubmitted(start); late.addActive(finish);late.addComplete(finish,true);
+ LateAttr parsedLate = LateAttr::create("late -s 10:10 -a 23:10 -c +23:10");
+ BOOST_CHECK_MESSAGE(late == parsedLate,"Expected " << late.toString() << " but found " << parsedLate.toString());
+ parsedLate = LateAttr::create("-s 10:10 -a 23:10 -c +23:10");
+ BOOST_CHECK_MESSAGE(late == parsedLate,"Expected " << late.toString() << " but found " << parsedLate.toString());
+ }
+ {
+ LateAttr late; late.addSubmitted(start); late.addActive(finish);late.addComplete(finish,true);
+ LateAttr parsedLate = LateAttr::create("late -c +23:10 -s 10:10 -a 23:10 ");
+ BOOST_CHECK_MESSAGE(late == parsedLate,"Expected " << late.toString() << " but found " << parsedLate.toString());
+ parsedLate = LateAttr::create("-c +23:10 -s 10:10 -a 23:10 ");
+ BOOST_CHECK_MESSAGE(late == parsedLate,"Expected " << late.toString() << " but found " << parsedLate.toString());
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_late_parsing_errors )
+{
+ cout << "ANattr:: ...test_late_parsing_errors\n";
+ BOOST_REQUIRE_THROW( (void)LateAttr::create(""),std::runtime_error);
+ BOOST_REQUIRE_THROW( (void)LateAttr::create("late"),std::runtime_error);
+ BOOST_REQUIRE_THROW( (void)LateAttr::create("late 10:10"),std::runtime_error);
+ BOOST_REQUIRE_THROW( (void)LateAttr::create("late -s 100:10"),std::runtime_error);
+ BOOST_REQUIRE_THROW( (void)LateAttr::create("late -s 10:107"),std::runtime_error);
+ BOOST_REQUIRE_THROW( (void)LateAttr::create("10:10"),std::runtime_error);
+ BOOST_REQUIRE_THROW( (void)LateAttr::create("late -a"),std::runtime_error);
+ BOOST_REQUIRE_THROW( (void)LateAttr::create("-a"),std::runtime_error);
+ BOOST_REQUIRE_THROW( (void)LateAttr::create("-c"),std::runtime_error);
+ BOOST_REQUIRE_THROW( (void)LateAttr::create("-s"),std::runtime_error);
+ BOOST_REQUIRE_THROW( (void)LateAttr::create("late -c -s 10:10 -a 23:10"),std::runtime_error);
+ BOOST_REQUIRE_THROW( (void)LateAttr::create("late -c +23:10 -s -a 23:10"),std::runtime_error);
+ BOOST_REQUIRE_THROW( (void)LateAttr::create("late -c +23:105 -s 10:10 -a 23:10"),std::runtime_error);
+ BOOST_REQUIRE_THROW( (void)LateAttr::create("late -c +23:10 -c +23:10 -s 10:10 -a 23:10"),std::runtime_error);
+ BOOST_REQUIRE_THROW( (void)LateAttr::create("late -c +23:10 -s 10:10 -a 23:10 -a 23:10"),std::runtime_error);
+ BOOST_REQUIRE_THROW( (void)LateAttr::create("late -c +23:10 -s 10:10 -s 10:10 -a 23:10"),std::runtime_error);
+ BOOST_REQUIRE_THROW( (void)LateAttr::create("late -c -s -a"),std::runtime_error);
+ BOOST_REQUIRE_THROW( (void)LateAttr::create("late +23:10 10:10 23:10"),std::runtime_error);
+
+ BOOST_CHECK_THROW( (void)LateAttr::create("late -a 23:11 -c"),std::runtime_error);
+ BOOST_CHECK_THROW( (void)LateAttr::create("late -c +23:10 -s 10:10 -a"),std::runtime_error);
+ BOOST_CHECK_THROW( (void)LateAttr::create("late -c +23:10 -s 10:10 -a 11:11 -s"),std::runtime_error);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ANattr/test/TestMigration.cpp b/ANattr/test/TestMigration.cpp
new file mode 100644
index 0000000..d3f0a1d
--- /dev/null
+++ b/ANattr/test/TestMigration.cpp
@@ -0,0 +1,187 @@
+#if defined(TEXT_ARCHIVE) || !defined(BINARY_ARCHIVE) && !defined(PORTABLE_BINARY_ARCHIVE) && !defined(EOS_PORTABLE_BINARY_ARCHIVE)
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #13 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <boost/test/unit_test.hpp>
+
+#include "TodayAttr.hpp"
+#include "TimeAttr.hpp"
+#include "VerifyAttr.hpp"
+#include "RepeatAttr.hpp"
+#include "LateAttr.hpp"
+#include "DayAttr.hpp"
+#include "DateAttr.hpp"
+#include "CronAttr.hpp"
+#include "ClockAttr.hpp"
+#include "AutoCancelAttr.hpp"
+#include "NodeAttr.hpp"
+#include "Variable.hpp"
+#include "ZombieAttr.hpp"
+#include "Calendar.hpp"
+#include "SerializationTest.hpp"
+#include "TimeSeries.hpp"
+#include "File.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::posix_time;
+using namespace boost::gregorian;
+namespace fs = boost::filesystem;
+
+//#define UPDATE_TESTS 1
+
+
+BOOST_AUTO_TEST_SUITE( ANattrTestSuite )
+
+// These test are used for future release. They help to ensure that we have
+// backward compatibility.i.e future release can open file, created by an earlier release
+//
+BOOST_AUTO_TEST_CASE( test_migration_restore_def_con )
+{
+ cout << "ANattr:: ...test_migration_restore_def_con\n";
+
+ std::string file_name = File::test_data("ANattr/test/data/migration/default_constructor_v1_9/","ANattr");
+
+ // Create migration data
+#ifdef UPDATE_TESTS
+ doSave(file_name + "VerifyAttr",VerifyAttr());
+ doSave(file_name + "TodayAttr",TodayAttr());
+ doSave(file_name + "TimeAttr",TimeAttr());
+ doSave(file_name + "RepeatDate",RepeatDate());
+ doSave(file_name + "RepeatInteger",RepeatInteger());
+ doSave(file_name + "RepeatEnumerated",RepeatEnumerated());
+ doSave(file_name + "RepeatString",RepeatString());
+ doSave(file_name + "LateAttr",LateAttr());
+ doSave(file_name + "DayAttr",DayAttr());
+ doSave(file_name + "DateAttr",DateAttr());
+ doSave(file_name + "CronAttr",CronAttr());
+ doSave(file_name + "ClockAttr",ClockAttr());
+ doSave(file_name + "AutoCancelAttr",AutoCancelAttr());
+ doSave(file_name + "Label",Label());
+ doSave(file_name + "Variable",Variable());
+ doSave(file_name + "Event",Event());
+ doSave(file_name + "Meter",Meter());
+ doSave(file_name + "ZombieAttr",ZombieAttr());
+#endif
+
+ do_restore<VerifyAttr>(file_name + "VerifyAttr",VerifyAttr());
+ do_restore<TodayAttr>(file_name + "TodayAttr",TodayAttr());
+ do_restore<TimeAttr>(file_name + "TimeAttr",TimeAttr());
+ do_restore<RepeatDate>(file_name + "RepeatDate",RepeatDate());
+ do_restore<RepeatInteger>(file_name + "RepeatInteger",RepeatInteger());
+ do_restore<RepeatEnumerated>(file_name + "RepeatEnumerated",RepeatEnumerated());
+ do_restore<RepeatString>(file_name + "RepeatString",RepeatString());
+ do_restore<LateAttr>(file_name + "LateAttr",LateAttr());
+ do_restore<DayAttr>(file_name + "DayAttr",DayAttr());
+ do_restore<DateAttr>(file_name + "DateAttr",DateAttr());
+ do_restore<CronAttr>(file_name + "CronAttr",CronAttr());
+ do_restore<AutoCancelAttr>(file_name + "AutoCancelAttr",AutoCancelAttr());
+ do_restore<Label>(file_name + "Label",Label());
+ do_restore<Variable>(file_name + "Variable",Variable());
+ do_restore<Event>(file_name + "Event",Event());
+ do_restore<Meter>(file_name + "Meter",Meter());
+ do_restore<ZombieAttr>(file_name + "ZombieAttr",ZombieAttr());
+}
+
+BOOST_AUTO_TEST_CASE( test_migration_restore )
+{
+ cout << "ANattr:: ...test_migration_restore\n";
+
+ std::string file_name = File::test_data("ANattr/test/data/migration/v1_9/","ANattr");
+
+ std::vector<std::string> theVec; theVec.push_back("a"); theVec.push_back("b");
+ LateAttr lateattr;
+ lateattr.addSubmitted(TimeSlot(10,12));
+ lateattr.addActive(TimeSlot(10,12));
+ lateattr.addComplete(TimeSlot(10,12),true);
+
+ CronAttr cron_attr;
+ std::vector<int> weekDays; weekDays.push_back(1); weekDays.push_back(2);
+ std::vector<int> daysOfMonth; daysOfMonth.push_back(1); daysOfMonth.push_back(2);
+ std::vector<int> months; months.push_back(1); months.push_back(2);
+ cron_attr.addWeekDays(weekDays);
+ cron_attr.addDaysOfMonth(daysOfMonth);
+ cron_attr.addMonths(months);
+ cron_attr.addTimeSeries(TimeSlot(0,0),TimeSlot(20,0),TimeSlot(0,1));
+
+ ClockAttr clock_attr(false);
+ clock_attr.date(1,1,2009);
+ clock_attr.set_gain_in_seconds(3600);
+ clock_attr.startStopWithServer(true);
+
+ std::vector<ecf::Child::CmdType> child_cmds;
+ child_cmds.push_back(ecf::Child::INIT);
+ child_cmds.push_back(ecf::Child::EVENT);
+ child_cmds.push_back(ecf::Child::METER);
+ child_cmds.push_back(ecf::Child::LABEL);
+ child_cmds.push_back(ecf::Child::WAIT);
+ child_cmds.push_back(ecf::Child::ABORT);
+ child_cmds.push_back(ecf::Child::COMPLETE);
+
+ Label label("name","value");
+ label.set_new_value("new_value");
+
+#ifdef UPDATE_TESTS
+ // Create migration data
+ doSave(file_name + "VerifyAttr",VerifyAttr(NState::COMPLETE,3));
+ doSave(file_name + "TodayAttr",TodayAttr(10,12));
+ doSave(file_name + "TimeAttr",TimeAttr(10,12));
+ doSave(file_name + "RepeatDate",RepeatDate("date",20110112,20110115));
+ doSave(file_name + "RepeatInteger",RepeatInteger("integer",0,100,2));
+ doSave(file_name + "RepeatEnumerated",RepeatEnumerated("enum",theVec));
+ doSave(file_name + "RepeatString",RepeatString("string",theVec));
+ doSave(file_name + "LateAttr",lateattr);
+ doSave(file_name + "DayAttr",DayAttr(DayAttr::MONDAY));
+ doSave(file_name + "DateAttr",DateAttr(12,12,2012));
+ doSave(file_name + "CronAttr",cron_attr);
+ doSave(file_name + "ClockAttr",clock_attr);
+ doSave(file_name + "AutoCancelAttr",AutoCancelAttr(100));
+ doSave(file_name + "AutoCancelAttr_1",AutoCancelAttr(TimeSlot(10,12),true));
+ doSave(file_name + "Label",label);
+// doSave(file_name + "Limit",limit);
+ doSave(file_name + "Variable",Variable("var_name","var_value"));
+ doSave(file_name + "Event_1",Event(1));
+ doSave(file_name + "Event_2",Event("event"));
+ doSave(file_name + "Meter",Meter("meter",10,100,100));
+ doSave(file_name + "ZombieAttr",ZombieAttr(ecf::Child::USER, child_cmds, ecf::User::FOB));
+ doSave(file_name + "ZombieAttr1",ZombieAttr(ecf::Child::USER, child_cmds, ecf::User::FOB,500));
+#endif
+
+ do_restore<VerifyAttr>(file_name + "VerifyAttr",VerifyAttr(NState::COMPLETE,3));
+ do_restore<TodayAttr>(file_name + "TodayAttr",TodayAttr(10,12));
+ do_restore<TimeAttr>(file_name + "TimeAttr",TimeAttr(10,12));
+ do_restore<RepeatDate>(file_name + "RepeatDate",RepeatDate("date",20110112,20110115));
+ do_restore<RepeatInteger>(file_name + "RepeatInteger",RepeatInteger("integer",0,100,2));
+ do_restore<RepeatEnumerated>(file_name + "RepeatEnumerated",RepeatEnumerated("enum",theVec));
+ do_restore<RepeatString>(file_name + "RepeatString",RepeatString("string",theVec));
+ do_restore<LateAttr>(file_name + "LateAttr",lateattr);
+ do_restore<DayAttr>(file_name + "DayAttr",DayAttr(DayAttr::MONDAY));
+ do_restore<DateAttr>(file_name + "DateAttr",DateAttr(12,12,2012));
+ do_restore<CronAttr>(file_name + "CronAttr",cron_attr);
+ do_restore<ClockAttr>(file_name + "ClockAttr",clock_attr);
+ do_restore<AutoCancelAttr>(file_name + "AutoCancelAttr",AutoCancelAttr(100));
+ do_restore<AutoCancelAttr>(file_name + "AutoCancelAttr_1",AutoCancelAttr(TimeSlot(10,12),true));
+ do_restore<Label>(file_name + "Label",label);
+ do_restore<Variable>(file_name + "Variable",Variable("var_name","var_value"));
+ do_restore<Event>(file_name + "Event_1",Event(1));
+ do_restore<Event>(file_name + "Event_2",Event("event"));
+ do_restore<Meter>(file_name + "Meter",Meter("meter",10,100,100));
+ do_restore<ZombieAttr>(file_name + "ZombieAttr",ZombieAttr(ecf::Child::USER, child_cmds, ecf::User::FOB));
+ do_restore<ZombieAttr>(file_name + "ZombieAttr1",ZombieAttr(ecf::Child::USER, child_cmds, ecf::User::FOB,500));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+#endif
diff --git a/ANattr/test/TestRepeat.cpp b/ANattr/test/TestRepeat.cpp
new file mode 100644
index 0000000..4a60d66
--- /dev/null
+++ b/ANattr/test/TestRepeat.cpp
@@ -0,0 +1,592 @@
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #16 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <boost/test/unit_test.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/date_time/posix_time/time_formatters.hpp> // requires boost date and time lib
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include "RepeatAttr.hpp"
+
+using namespace std;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+
+BOOST_AUTO_TEST_SUITE( ANattrTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_repeat_invariants )
+{
+ cout << "ANattr:: ...test_repeat_invariants\n";
+
+ std::vector<std::string> stringList; stringList.reserve(3);
+ stringList.push_back("a");
+ stringList.push_back("b");
+ stringList.push_back("c");
+
+ // Test the invariant that Non empty repeat must have a name
+ {
+ Repeat empty;
+ Repeat empty2;
+ BOOST_CHECK_MESSAGE(empty.empty(),"Construction");
+ BOOST_CHECK_MESSAGE(empty.name().empty(),"Construction");
+ BOOST_CHECK_MESSAGE(empty == empty2,"Equality failed");
+ }
+ {
+ Repeat rep(RepeatDate("YMD",20090916,20090930,1));
+ BOOST_CHECK_MESSAGE(!rep.empty()," Repeat should not be empty");
+ BOOST_CHECK_MESSAGE(!rep.name().empty(),"name should not be empty");
+ BOOST_CHECK_MESSAGE(rep.name() == "YMD","name not as expected");
+ BOOST_CHECK_MESSAGE(rep.start() == 20090916,"Start should be 20090916");
+ BOOST_CHECK_MESSAGE(rep.end() == 20090930,"end should be 20090930");
+ BOOST_CHECK_MESSAGE(rep.step() == 1,"step should be 1");
+ BOOST_CHECK_MESSAGE(rep.value() == 20090916,"value should be 20090916");
+ BOOST_CHECK_MESSAGE(rep.last_valid_value() == 20090916,"last_valid_value should be 20090916");
+
+ Repeat cloned = Repeat(rep);
+ BOOST_CHECK_MESSAGE(cloned == rep,"Equality failed");
+ BOOST_CHECK_MESSAGE(cloned.name() == "YMD","not as expected");
+ BOOST_CHECK_MESSAGE(cloned.start() == 20090916,"not as expected");
+ BOOST_CHECK_MESSAGE(cloned.end() == 20090930,"not as expected");
+ BOOST_CHECK_MESSAGE(cloned.step() == 1,"not as expected");
+ BOOST_CHECK_MESSAGE(cloned.value() == 20090916,"not as expected");
+ BOOST_CHECK_MESSAGE(cloned.valueAsString() == "20090916","not as expected");
+ BOOST_CHECK_MESSAGE(cloned.last_valid_value() == 20090916,"last_valid_value should be 20090916");
+
+ RepeatDate empty;
+ BOOST_CHECK_MESSAGE(empty.start() == 0,"Start should be 0");
+ BOOST_CHECK_MESSAGE(empty.end() == 0,"end should be 0");
+ BOOST_CHECK_MESSAGE(empty.step() == 0,"step should be 0");
+ BOOST_CHECK_MESSAGE(empty.value() == 0,"delta should be 0");
+ BOOST_CHECK_MESSAGE(empty.name().empty(),"name should be empty");
+ BOOST_CHECK_MESSAGE(empty.name() == "","name not as expected");
+ }
+ {
+ Repeat rep(RepeatDate("YMD",20090930,20090916,-1));
+ BOOST_CHECK_MESSAGE(!rep.empty()," Repeat should not be empty");
+ BOOST_CHECK_MESSAGE(!rep.name().empty(),"name should not be empty");
+ BOOST_CHECK_MESSAGE(rep.name() == "YMD","name not as expected");
+ BOOST_CHECK_MESSAGE(rep.start() == 20090930,"Start should be 20090930");
+ BOOST_CHECK_MESSAGE(rep.end() == 20090916,"end should be 20090916");
+ BOOST_CHECK_MESSAGE(rep.step() == -1,"step should be -1");
+ BOOST_CHECK_MESSAGE(rep.value() == 20090930,"value should be 20090930");
+ BOOST_CHECK_MESSAGE(rep.last_valid_value() == 20090930,"last_valid_value should be 20090930");
+
+ Repeat cloned = Repeat(rep);
+ BOOST_CHECK_MESSAGE(cloned == rep,"Equality failed");
+ BOOST_CHECK_MESSAGE(cloned.name() == "YMD","not as expected");
+ BOOST_CHECK_MESSAGE(cloned.start() == 20090930,"not as expected");
+ BOOST_CHECK_MESSAGE(cloned.end() == 20090916,"not as expected");
+ BOOST_CHECK_MESSAGE(cloned.step() == -1,"not as expected");
+ BOOST_CHECK_MESSAGE(cloned.value() == 20090930,"not as expected");
+ BOOST_CHECK_MESSAGE(cloned.valueAsString() == "20090930","not as expected");
+ BOOST_CHECK_MESSAGE(cloned.last_valid_value() == 20090930,"last_valid_value should be 20090930");
+ }
+ {
+ Repeat rep(RepeatDate("YMD",20090916,20090916,1));
+ BOOST_CHECK_MESSAGE(rep.start() == 20090916,"Start should be 20090916");
+ BOOST_CHECK_MESSAGE(rep.end() == 20090916,"end should be 20090916");
+ BOOST_CHECK_MESSAGE(rep.step() == 1,"step should be 1");
+ BOOST_CHECK_MESSAGE(rep.value() == 20090916,"value should be 20090916");
+ BOOST_CHECK_MESSAGE(rep.last_valid_value() == 20090916,"delta should be 20090916");
+ rep.increment();
+ BOOST_CHECK_MESSAGE(!rep.valid(),"RepeatDate should not be valid");
+ BOOST_CHECK_MESSAGE(rep.value() == 20090917,"value should be 20090916");
+ BOOST_CHECK_MESSAGE(rep.last_valid_value() == 20090916,"last_valid_value should be 20090916");
+ }
+ {
+ Repeat rep(RepeatDate("YMD",20090916,20090916,-1));
+ BOOST_CHECK_MESSAGE(rep.start() == 20090916,"Start should be 20090916");
+ BOOST_CHECK_MESSAGE(rep.end() == 20090916,"end should be 20090916");
+ BOOST_CHECK_MESSAGE(rep.step() == -1,"step should be -1");
+ BOOST_CHECK_MESSAGE(rep.value() == 20090916,"value should be 20090916");
+ BOOST_CHECK_MESSAGE(rep.last_valid_value() == 20090916,"last_valid_value should be 20090916");
+ rep.increment();
+ BOOST_CHECK_MESSAGE(!rep.valid(),"RepeatDate should not be valid");
+ BOOST_CHECK_MESSAGE(rep.value() == 20090915,"value should be 20090915");
+ BOOST_CHECK_MESSAGE(rep.last_valid_value() == 20090916,"last_valid_value should be 20090916");
+ }
+
+
+ {
+ Repeat rep(RepeatEnumerated("AEnum",stringList));
+ BOOST_CHECK_MESSAGE(!rep.empty()," Repeat should not be empty");
+ BOOST_CHECK_MESSAGE(!rep.name().empty(),"name should not be empty");
+ BOOST_CHECK_MESSAGE(rep.name() == "AEnum","name not as expected");
+
+ Repeat cloned = Repeat(rep);
+ BOOST_CHECK_MESSAGE(cloned == rep,"Equality failed");
+ BOOST_CHECK_MESSAGE(cloned.name() == "AEnum","not as expected");
+ BOOST_CHECK_MESSAGE(cloned.start() == 0,"not as expected");
+ BOOST_CHECK_MESSAGE(cloned.step() == 1,"not as expected");
+ BOOST_CHECK_MESSAGE(cloned.value() == 0,"not as expected");
+ BOOST_CHECK_MESSAGE(cloned.valueAsString() == "a","not as expected");
+
+ RepeatEnumerated empty;
+ BOOST_CHECK_MESSAGE(empty.start() == 0,"Start should be 0");
+ BOOST_CHECK_MESSAGE(empty.end() == 0,"end should be 0");
+ BOOST_CHECK_MESSAGE(empty.step() == 1,"default step should be 1");
+ BOOST_CHECK_MESSAGE(empty.value() == 0,"delta should be 0");
+ BOOST_CHECK_MESSAGE(empty.name().empty(),"name should be empty");
+ BOOST_CHECK_MESSAGE(empty.name() == "","name not as expected");
+ }
+ {
+ Repeat rep(RepeatInteger("rep",0,100,1));
+ BOOST_CHECK_MESSAGE(!rep.empty()," Repeat should not be empty");
+ BOOST_CHECK_MESSAGE(!rep.name().empty(),"name should not be empty");
+ BOOST_CHECK_MESSAGE(rep.name() == "rep","name not as expected");
+
+ Repeat cloned = Repeat(rep);
+ BOOST_CHECK_MESSAGE(cloned == rep,"Equality failed");
+ BOOST_CHECK_MESSAGE(cloned.name() == "rep","not as expected");
+ BOOST_CHECK_MESSAGE(cloned.start() == 0,"not as expected");
+ BOOST_CHECK_MESSAGE(cloned.end() == 100,"not as expected");
+ BOOST_CHECK_MESSAGE(cloned.step() == 1,"not as expected");
+ BOOST_CHECK_MESSAGE(cloned.value() == 0,"not as expected");
+
+ RepeatInteger empty;
+ BOOST_CHECK_MESSAGE(empty.start() == 0,"Start should be 0");
+ BOOST_CHECK_MESSAGE(empty.end() == 0,"end should be 0");
+ BOOST_CHECK_MESSAGE(empty.step() == 0,"default step should be 0 but found" << empty.step());
+ BOOST_CHECK_MESSAGE(empty.value() == 0,"delta should be 0");
+ BOOST_CHECK_MESSAGE(empty.name().empty(),"name should be empty");
+ BOOST_CHECK_MESSAGE(empty.name() == "","name not as expected");
+ }
+ {
+ Repeat rep(RepeatDay(2));
+ BOOST_CHECK_MESSAGE(!rep.empty()," Repeat should not be empty");
+ BOOST_CHECK_MESSAGE(!rep.name().empty(),"name should not be empty");
+ BOOST_CHECK_MESSAGE(rep.name() == "day","name not as expected");
+
+ Repeat cloned = Repeat(rep);
+ BOOST_CHECK_MESSAGE(cloned == rep,"Equality failed");
+ BOOST_CHECK_MESSAGE(cloned.name() == "day","name not as expected");
+ BOOST_CHECK_MESSAGE(cloned.step() == 2,"step not as expected");
+
+ RepeatDay empty;
+ BOOST_CHECK_MESSAGE(empty.start() == 0,"Start should be 0");
+ BOOST_CHECK_MESSAGE(empty.end() == 0,"end should be 0");
+ BOOST_CHECK_MESSAGE(empty.step() == 1,"default step should be 0 but found " << empty.step());
+ BOOST_CHECK_MESSAGE(empty.value() == 1,"value should be 0 but found " << empty.value());
+ BOOST_CHECK_MESSAGE(empty.name().empty(),"name should be empty");
+ BOOST_CHECK_MESSAGE(empty.name() == "","name not as expected");
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_repeat )
+{
+ cout << "ANattr:: ...test_repeat \n";
+
+ std::vector<std::string> stringList; stringList.reserve(3);
+ stringList.push_back("a");
+ stringList.push_back("b");
+ stringList.push_back("c");
+
+ Repeat empty;
+ Repeat empty2;
+
+ {
+ Repeat l1(RepeatDate("YMD",20090916,20090930,1));
+ Repeat l2(RepeatDate("YMD",20090916,20090930,1));
+ BOOST_CHECK_MESSAGE(!l1.empty(),"Construction failed");
+ BOOST_CHECK_MESSAGE(!l2.empty(),"Construction failed");
+ BOOST_CHECK_MESSAGE(l1 == l2,"Equality failed");
+ BOOST_CHECK_MESSAGE(!(l1 == empty),"Equality failed");
+
+ Repeat l1a(RepeatDate("YMD",20090930,20090916,-1));
+ Repeat l2a(RepeatDate("YMD",20090930,20090916,-1));
+ BOOST_CHECK_MESSAGE(!l1a.empty(),"Construction failed");
+ BOOST_CHECK_MESSAGE(!l2a.empty(),"Construction failed");
+ BOOST_CHECK_MESSAGE(l1a == l2a,"Equality failed");
+ BOOST_CHECK_MESSAGE(!(l1a == empty),"Equality failed");
+
+ Repeat la(RepeatEnumerated("AEnum",stringList));
+ Repeat lb(RepeatEnumerated("AEnum",stringList));
+ BOOST_CHECK_MESSAGE(!la.empty(),"Construction failed");
+ BOOST_CHECK_MESSAGE(!lb.empty(),"Construction failed");
+ BOOST_CHECK_MESSAGE(la == lb,"Equality failed");
+ BOOST_CHECK_MESSAGE(!(la == empty),"Equality failed");
+
+ Repeat lc(RepeatString("RepeatString",stringList));
+ Repeat ld(RepeatString("RepeatString",stringList));
+ BOOST_CHECK_MESSAGE(!lc.empty(),"Construction failed");
+ BOOST_CHECK_MESSAGE(!ld.empty(),"Construction failed");
+ BOOST_CHECK_MESSAGE(lc == lc,"Equality failed");
+ BOOST_CHECK_MESSAGE(!(lc == empty),"Equality failed");
+
+ Repeat le(RepeatInteger("rep",0,100,1));
+ Repeat lf(RepeatInteger("rep",0,100,1));
+ BOOST_CHECK_MESSAGE(!le.empty(),"Construction failed");
+ BOOST_CHECK_MESSAGE(!lf.empty(),"Construction failed");
+ BOOST_CHECK_MESSAGE(le == lf,"Equality failed");
+ BOOST_CHECK_MESSAGE(!(le == empty),"Equality failed");
+
+ l1.clear();
+ l2.clear();
+ la.clear();
+ lb.clear();
+ lc.clear();
+ ld.clear();
+ le.clear();
+ lf.clear();
+ BOOST_CHECK_MESSAGE(l1 == empty,"Clear failed");
+ BOOST_CHECK_MESSAGE(l2 == empty,"Clear failed");
+ BOOST_CHECK_MESSAGE(la == empty,"Clear failed");
+ BOOST_CHECK_MESSAGE(lb == empty,"Clear failed");
+ BOOST_CHECK_MESSAGE(lc == empty,"Clear failed");
+ BOOST_CHECK_MESSAGE(ld == empty,"Clear failed");
+ BOOST_CHECK_MESSAGE(le == empty,"Clear failed");
+ BOOST_CHECK_MESSAGE(lf == empty,"Clear failed");
+ }
+
+ {
+ Repeat l1(RepeatDate("YMD",20090916,20090930,1));
+ Repeat l2;
+ l2 = l1;
+ BOOST_CHECK_MESSAGE(l1 == l2,"Assignment failed");
+
+ l2 = empty;
+ BOOST_CHECK_MESSAGE(l2 == empty,"Assignment failed");
+
+ Repeat la(RepeatEnumerated("AEnum",stringList));
+ Repeat lb;
+ lb = la;
+ BOOST_CHECK_MESSAGE(la == lb,"Assignment failed");
+
+ Repeat lc(RepeatString("RepeatString",stringList));
+ Repeat ld;
+ ld = lc;
+ BOOST_CHECK_MESSAGE(lc == ld,"Assignment failed");
+
+ Repeat le(RepeatInteger("rep",0,100,1));
+ Repeat lf;
+ lf = le;
+ BOOST_CHECK_MESSAGE(le == lf,"Assignment failed");
+ }
+
+ {
+ Repeat l1(RepeatDate("YMD",20090916,20090930,1));
+
+ Repeat l2 = l1;
+ BOOST_CHECK_MESSAGE(l1 == l2,"Copy construction failed");
+
+ Repeat la(RepeatEnumerated("AEnum",stringList));
+ Repeat lb = la;
+ BOOST_CHECK_MESSAGE(la == lb,"Copy construction failed");
+
+ Repeat lc(RepeatString("RepeatString",stringList));
+ Repeat ld = lc;
+ BOOST_CHECK_MESSAGE(lc == ld,"Copy construction failed");
+
+ Repeat le(RepeatInteger("rep",0,100,1));
+ Repeat lf = le;
+ BOOST_CHECK_MESSAGE(le == lf,"Copy construction failed");
+
+ Repeat empty_1( empty );
+ BOOST_CHECK_MESSAGE(empty_1 == empty,"Copy construction failed");
+ }
+
+ {
+ BOOST_CHECK_MESSAGE(empty.name() == string()," empty failed");
+ BOOST_CHECK_MESSAGE(empty.valid() == false," empty failed");
+ BOOST_CHECK_MESSAGE(empty.value() == 0," empty failed");
+ empty.setToLastValue();
+ BOOST_CHECK_MESSAGE(empty.valueAsString() == string()," empty failed");
+ empty.reset();
+ empty.increment();
+ empty.change("fred");
+ BOOST_CHECK_MESSAGE(empty.valueAsString() == string()," empty failed");
+ empty.changeValue(10);
+ BOOST_CHECK_MESSAGE(empty.valueAsString() == string()," empty failed");
+ BOOST_CHECK_MESSAGE(empty.isInfinite() == false," empty failed");
+ BOOST_CHECK_MESSAGE(empty.toString() == string()," empty failed");
+ BOOST_CHECK_MESSAGE(empty.state_change_no() ==0," empty failed");
+ }
+
+ {
+ Repeat day(RepeatDay(2));
+ Repeat day2 = day;
+ BOOST_CHECK_MESSAGE(day == day2,"Copy construction failed");
+
+ BOOST_CHECK_MESSAGE(day.makeInfiniteInValid(),"Should return true");
+ BOOST_CHECK_MESSAGE(!day.valid(),"Should return false after makeInfiniteInValid");
+ day.reset();
+ BOOST_CHECK_MESSAGE(day.valid(),"Should return true after reset");
+ }
+}
+
+
+BOOST_AUTO_TEST_CASE( test_repeat_last_value )
+{
+ cout << "ANattr:: ...test_repeat_last_value \n";
+
+ {
+ Repeat rep(RepeatDate("YMD",20090916,20090930,1));
+ rep.setToLastValue();
+ BOOST_CHECK_MESSAGE(rep.value() == 20090930,"Set to last value did not work, expected 20090930 but found " << rep.value());
+ }
+ {
+ Repeat rep(RepeatDate("YMD",20090930,20090916,-1));
+ rep.setToLastValue();
+ BOOST_CHECK_MESSAGE(rep.value() == 20090916,"Set to last value did not work, expected 20090916 but found " << rep.value());
+ }
+
+ std::vector<std::string> stringList; stringList.reserve(3);
+ stringList.push_back("a");
+ stringList.push_back("b");
+ stringList.push_back("c");
+ {
+ Repeat rep(RepeatEnumerated("AEnum",stringList));
+ rep.setToLastValue();
+ BOOST_CHECK_MESSAGE(rep.value() == 2,"Set to last value did not work, expected 2 but found " << rep.value());
+ BOOST_CHECK_MESSAGE(rep.valueAsString() == "c","Set to last value did not work, expected 'c' but found " << rep.valueAsString());
+ BOOST_CHECK_MESSAGE(rep.value_as_string(0) == "a"," Expected 'a' but found " << rep.value_as_string(0));
+ BOOST_CHECK_MESSAGE(rep.value_as_string(1) == "b"," Expected 'b' but found " << rep.value_as_string(1));
+ BOOST_CHECK_MESSAGE(rep.value_as_string(2) == "c"," Expected 'c' but found " << rep.value_as_string(2));
+ }
+ {
+ Repeat rep(RepeatString("Str",stringList));
+ rep.setToLastValue();
+ BOOST_CHECK_MESSAGE(rep.value() == 2,"Set to last value did not work, expected 2 but found " << rep.value());
+ BOOST_CHECK_MESSAGE(rep.valueAsString() == "c","Set to last value did not work, expected 'c' but found " << rep.valueAsString());
+ BOOST_CHECK_MESSAGE(rep.value_as_string(0) == "a"," Expected 'a' but found " << rep.value_as_string(0));
+ BOOST_CHECK_MESSAGE(rep.value_as_string(1) == "b"," Expected 'b' but found " << rep.value_as_string(1));
+ BOOST_CHECK_MESSAGE(rep.value_as_string(2) == "c"," Expected 'c' but found " << rep.value_as_string(2));
+ }
+
+ {
+ Repeat rep(RepeatInteger("integer",0,10,1));
+ rep.setToLastValue();
+ BOOST_CHECK_MESSAGE(rep.value() == 10,"Set to last value did not work, expected 10 but found " << rep.value());
+ BOOST_CHECK_MESSAGE(rep.value_as_string(0) == "0"," Expected '0' but found " << rep.value_as_string(0));
+ BOOST_CHECK_MESSAGE(rep.value_as_string(1) == "1"," Expected '1' but found " << rep.value_as_string(1));
+ BOOST_CHECK_MESSAGE(rep.value_as_string(2) == "2"," Expected '2' but found " << rep.value_as_string(2));
+ }
+ {
+ Repeat rep(RepeatInteger("integer",10,0,-1));
+ rep.setToLastValue();
+ BOOST_CHECK_MESSAGE(rep.value() == 0,"Set to last value did not work, expected 0 but found " << rep.value());
+ BOOST_CHECK_MESSAGE(rep.value_as_string(0) == "0"," Expected '0' but found " << rep.value_as_string(0));
+ BOOST_CHECK_MESSAGE(rep.value_as_string(1) == "1"," Expected '1' but found " << rep.value_as_string(1));
+ BOOST_CHECK_MESSAGE(rep.value_as_string(2) == "2"," Expected '2' but found " << rep.value_as_string(2));
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_repeat_enumerated_as_string_integers )
+{
+ cout << "ANattr:: ...test_repeat_enumerated_as_string_integers\n";
+
+ std::vector<std::string> stringList; stringList.reserve(3);
+ stringList.push_back("20130101");
+ stringList.push_back("20130102");
+ stringList.push_back("20130103");
+ {
+ Repeat rep(RepeatEnumerated("AEnum",stringList));
+ // Note: valueAsString should return string at the last valid index
+
+ BOOST_CHECK_MESSAGE(rep.valid(),"Expected rep to be valid");
+ BOOST_CHECK_MESSAGE(rep.value() == 20130101," Expected 20130101 but found " << rep.value());
+ BOOST_CHECK_MESSAGE(rep.last_valid_value() == 20130101," Expected 20130101 but found " << rep.last_valid_value());
+ BOOST_CHECK_MESSAGE(rep.valueAsString() == "20130101"," Expected '20130101' but found " << rep.valueAsString());
+ BOOST_CHECK_MESSAGE(rep.value_as_string(0) == "20130101"," Expected '20130101' but found " << rep.value_as_string(0));
+
+ rep.increment();
+ BOOST_CHECK_MESSAGE(rep.valid(),"Expected rep to be valid");
+ BOOST_CHECK_MESSAGE(rep.value() == 20130102," Expected 20130102 but found " << rep.value());
+ BOOST_CHECK_MESSAGE(rep.last_valid_value() == 20130102," Expected 20130102 but found " << rep.last_valid_value());
+ BOOST_CHECK_MESSAGE(rep.valueAsString() == "20130102"," Expected '20130102' but found " << rep.valueAsString());
+ BOOST_CHECK_MESSAGE(rep.value_as_string(1) == "20130102"," Expected '20130102' but found " << rep.value_as_string(1));
+
+ rep.increment();
+ BOOST_CHECK_MESSAGE(rep.value() == 20130103," Expected 20130103 but found " << rep.value());
+ BOOST_CHECK_MESSAGE(rep.last_valid_value() == 20130103," Expected 20130103 but found " << rep.last_valid_value());
+ BOOST_CHECK_MESSAGE(rep.valueAsString() == "20130103"," Expected '20130103' but found " << rep.valueAsString());
+ BOOST_CHECK_MESSAGE(rep.value_as_string(2) == "20130103"," Expected '20130103' but found " << rep.value_as_string(2));
+
+ rep.increment();
+ BOOST_CHECK_MESSAGE(!rep.valid(),"Expected rep to be in-valid");
+ BOOST_CHECK_MESSAGE(rep.last_valid_value() == 20130103," Expected 20130103 but found " << rep.last_valid_value());
+ BOOST_CHECK_MESSAGE(rep.valueAsString() == "20130103"," Expected '20130103' but found " << rep.valueAsString());
+
+ rep.increment();
+ BOOST_CHECK_MESSAGE(!rep.valid(),"Expected rep to be in-valid");
+ BOOST_CHECK_MESSAGE(rep.last_valid_value() == 20130103," Expected 20130103 but found " << rep.last_valid_value());
+ BOOST_CHECK_MESSAGE(rep.valueAsString() == "20130103"," Expected '20130103' but found " << rep.valueAsString());
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_repeat_increment )
+{
+ cout << "ANattr:: ...test_repeat_increment \n";
+
+ {
+ Repeat rep(RepeatDate("YMD",20090916,20090920,1));
+ while( rep.valid()) { rep.increment(); }
+ BOOST_CHECK_MESSAGE(rep.value() == 20090921,"expected 20090921 but found " << rep.value());
+ BOOST_CHECK_MESSAGE(rep.last_valid_value() == 20090920,"expected 20090920 but found " << rep.last_valid_value());
+ }
+ {
+ Repeat rep(RepeatDate("YMD",20090920,20090916,-1));
+ while( rep.valid()) { rep.increment(); }
+ BOOST_CHECK_MESSAGE(rep.value() == 20090915,"expected 20090915 but found " << rep.value());
+ BOOST_CHECK_MESSAGE(rep.last_valid_value() == 20090916,"expected 20090916 but found " << rep.last_valid_value());
+ }
+
+ {
+ Repeat rep(RepeatDate("YMD",20150514,20150730,7));
+ while( rep.valid()) { rep.increment();
+ //cout << "YMD: " << rep.value() << "\n";
+ }
+ BOOST_CHECK_MESSAGE(rep.value() == 20150806,"expected 20150806 but found " << rep.value());
+ BOOST_CHECK_MESSAGE(rep.last_valid_value() == 20150730,"expected 20150730 but found " << rep.last_valid_value());
+ }
+ {
+ Repeat rep(RepeatDate("YMD",20150730,20150514,-7));
+ while( rep.valid()) {
+ rep.increment();
+ //cout << "YMD: " << rep.value() << "\n";
+ }
+ BOOST_CHECK_MESSAGE(rep.value() == 20150507,"expected 20150507 but found " << rep.value());
+ BOOST_CHECK_MESSAGE(rep.last_valid_value() == 20150514,"expected 20150514 but found " << rep.last_valid_value());
+ }
+
+ std::vector<std::string> stringList; stringList.reserve(3);
+ stringList.push_back("a");
+ stringList.push_back("b");
+ stringList.push_back("c");
+ {
+ Repeat rep(RepeatEnumerated("AEnum",stringList));
+ while( rep.valid()) { rep.increment(); }
+ BOOST_CHECK_MESSAGE(rep.value() == 3," Expected 3 but found " << rep.value());
+ BOOST_CHECK_MESSAGE(rep.last_valid_value() == 2," Expected 2 but found " << rep.last_valid_value());
+ }
+ {
+ Repeat rep(RepeatString("Str",stringList));
+ while( rep.valid()) { rep.increment(); }
+ BOOST_CHECK_MESSAGE(rep.value() == 3," Expected 3 but found " << rep.value());
+ BOOST_CHECK_MESSAGE(rep.last_valid_value() == 2," Expected 2 but found " << rep.last_valid_value());
+ }
+ {
+ Repeat rep(RepeatInteger("integer",0,10,1));
+ while( rep.valid()) { rep.increment(); }
+ BOOST_CHECK_MESSAGE(rep.value() == 11," Expected 11 but found " << rep.value());
+ BOOST_CHECK_MESSAGE(rep.last_valid_value() == 10," Expected 10 but found " << rep.last_valid_value());
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_repeat_date_change_value )
+{
+ cout << "ANattr:: ...test_repeat_date_change_value \n";
+ {
+ Repeat rep2(RepeatDate("YMD",20150514,20150730,7));
+ Repeat rep(RepeatDate("YMD",20150514,20150730,7));
+ BOOST_CHECK_MESSAGE(rep.valid(),"expected valid at start ");
+
+ while( rep.valid() ) {
+ rep2.change(boost::lexical_cast<std::string>(rep.value()));
+ BOOST_CHECK_MESSAGE(rep.value() == rep2.value(),"expected same value, but found " << rep.value() << " " << rep2.value());
+ rep.increment();
+ }
+ }
+ {
+ Repeat rep2(RepeatDate("YMD",20150730,20150514,-7));
+ Repeat rep(RepeatDate("YMD",20150730,20150514,-7));
+ BOOST_CHECK_MESSAGE(rep.valid(),"expected valid at start ");
+
+ while( rep.valid() ) {
+ rep2.change(boost::lexical_cast<std::string>(rep.value()));
+ BOOST_CHECK_MESSAGE(rep.value() == rep2.value(),"expected same value, but found " << rep.value() << " " << rep2.value());
+ rep.increment();
+ }
+ }
+}
+
+
+BOOST_AUTO_TEST_CASE( test_repeat_date_errors )
+{
+ cout << "ANattr:: ...test_repeat_date_errors \n";
+
+ BOOST_REQUIRE_THROW( RepeatDate("",20090916,20090920,1),std::runtime_error);
+ BOOST_REQUIRE_THROW( RepeatDate("YMD",200909161,20090920,1),std::runtime_error); // start > 8
+ BOOST_REQUIRE_THROW( RepeatDate("YMD",20090916,200909201,1),std::runtime_error); // end > 8
+ BOOST_REQUIRE_THROW( RepeatDate("YMD",20090016,200909201,1),std::runtime_error); // invalid start month
+ BOOST_REQUIRE_THROW( RepeatDate("YMD",20090900,20090920,1),std::runtime_error); // invalid start day
+ BOOST_REQUIRE_THROW( RepeatDate("YMD",20090916,20090020,1),std::runtime_error); // invalid end month
+ BOOST_REQUIRE_THROW( RepeatDate("YMD",20090916,20090900,1),std::runtime_error); // invalid end day
+ BOOST_REQUIRE_THROW( RepeatDate("YMD",20090916,20090920,0),std::runtime_error); // delta can not be zero
+
+ BOOST_REQUIRE_THROW( RepeatDate("YMD",20090920,20090916,1),std::runtime_error); // start day > end day, and delta > 0
+ BOOST_REQUIRE_THROW( RepeatDate("YMD",20090916,20090920,-1),std::runtime_error); // start day < end day, and delta < 0
+
+ RepeatDate date("YMD",20150514,20150730,7);
+ BOOST_REQUIRE_THROW( date.changeValue(20150513),std::runtime_error); // outside of range
+ BOOST_REQUIRE_THROW( date.changeValue(20150731),std::runtime_error); // outside of range
+ BOOST_REQUIRE_THROW( date.changeValue(20150801),std::runtime_error); // outside of range
+
+ BOOST_REQUIRE_THROW( date.changeValue(20150515),std::runtime_error); // not a valid step
+ BOOST_REQUIRE_THROW( date.changeValue(20150516),std::runtime_error); // not a valid step
+ BOOST_REQUIRE_THROW( date.changeValue(20150517),std::runtime_error); // not a valid step
+ BOOST_REQUIRE_THROW( date.changeValue(20150518),std::runtime_error); // not a valid step
+ BOOST_REQUIRE_THROW( date.changeValue(20150519),std::runtime_error); // not a valid step
+ BOOST_REQUIRE_THROW( date.changeValue(20150520),std::runtime_error); // not a valid step
+ BOOST_REQUIRE_THROW( date.changeValue(20150522),std::runtime_error); // not a valid step
+
+ RepeatDate date1("YMD",20150730,20150514,-7);
+ BOOST_REQUIRE_THROW( date1.changeValue(20150731),std::runtime_error); // outside of range
+ BOOST_REQUIRE_THROW( date1.changeValue(20150813),std::runtime_error); // outside of range
+ BOOST_REQUIRE_THROW( date1.changeValue(20150513),std::runtime_error); // outside of range
+ BOOST_REQUIRE_THROW( date1.changeValue(20150413),std::runtime_error); // outside of range
+
+ BOOST_REQUIRE_THROW( date.changeValue(20150729),std::runtime_error); // not a valid step
+ BOOST_REQUIRE_THROW( date.changeValue(20150728),std::runtime_error); // not a valid step
+ BOOST_REQUIRE_THROW( date.changeValue(20150515),std::runtime_error); // not a valid step
+}
+
+static void check_date(int start, int end, int delta)
+{
+ boost::gregorian::date bdate(from_undelimited_string(boost::lexical_cast<std::string>(start)));
+
+ Repeat rep(RepeatDate("YMD",start,end,delta));
+ Repeat rep2(RepeatDate("YMD",start,end,delta));
+ while (rep.valid()) {
+
+ // xref repeat date with boost date, essentially checking bdate with rep
+ string str_value = boost::lexical_cast<std::string>(rep.value());
+ boost::gregorian::date date2(from_undelimited_string( str_value ));
+ BOOST_CHECK_MESSAGE(bdate == date2 ,"expected same value, but found " << bdate << " " << date2);
+
+ // check change value
+ rep2.change(str_value);
+ BOOST_CHECK_MESSAGE(rep.value() == rep2.value(),"expected same value, but found " << rep.value() << " " << rep2.value());
+
+ // increment repeat and boost date
+ rep.increment();
+ bdate += days(delta);
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_repeat_date_xref_to_boost_date )
+{
+ cout << "ANattr:: ...test_repeat_date_xref_to_boost_date \n";
+
+ check_date(19800101,20621231,1);
+ check_date(19800101,20621231,7);
+ check_date(20621231,19800101,-7);
+ check_date(20150514,20150730,7);
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/ANattr/test/TestTimeAttr.cpp b/ANattr/test/TestTimeAttr.cpp
new file mode 100644
index 0000000..38956d9
--- /dev/null
+++ b/ANattr/test/TestTimeAttr.cpp
@@ -0,0 +1,345 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #14 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <boost/test/unit_test.hpp>
+#include <boost/date_time/posix_time/time_formatters.hpp>
+
+#include "TimeAttr.hpp"
+#include "TimeSeries.hpp"
+#include "Calendar.hpp"
+#include "Str.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::posix_time;
+using namespace boost::gregorian;
+
+BOOST_AUTO_TEST_SUITE( ANattrTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_time_attr)
+{
+ cout << "ANattr:: ...test_time_attr\n";
+
+ // See TimeAttr.hpp for rules concerning isFree() and checkForReque()
+ // test time attr isFree(), and checkForRequeue
+ Calendar calendar;
+ calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::REAL);
+
+ // Create a test when we can match a time series. Need to sync hour with suite time
+ // at hour 1, suite time should also be 01:00, for test to work
+ //
+ // Create the time series: start 10:00
+ // finish 20:00
+ // incr 1:00
+ TimeSeries timeSeriesX(TimeSlot(10,0), TimeSlot(20,0), TimeSlot(1,0), false/* relative */);
+ TimeSeries timeSeries2X(TimeSlot(11,0), TimeSlot(15,0), TimeSlot(1,0), false/* relative */);
+ TimeSeries timeSeries3X(TimeSlot(15,0), false/* relative */);
+ TimeSeries timeSeries4X(TimeSlot(0,0), false/* relative */);
+
+ TimeSlot t1_min, t1_max,t2_min,t2_max,t3_min,t3_max,t4_min,t4_max;
+ timeSeriesX.min_max_time_slots(t1_min, t1_max);
+ timeSeries2X.min_max_time_slots(t2_min, t2_max);
+ timeSeries3X.min_max_time_slots(t3_min, t3_max);
+ timeSeries4X.min_max_time_slots(t4_min, t4_max);
+ BOOST_CHECK_MESSAGE(t1_min == TimeSlot(10,0) && t1_max == TimeSlot(20,0),"Not as expected");
+ BOOST_CHECK_MESSAGE(t2_min == TimeSlot(11,0) && t2_max == TimeSlot(15,0),"Not as expected");
+ BOOST_CHECK_MESSAGE(t3_min == TimeSlot(15,0) && t3_max == TimeSlot(15,0),"Not as expected");
+ BOOST_CHECK_MESSAGE(t4_min == TimeSlot(0,0) && t4_max == TimeSlot(0,0),"Not as expected");
+
+ TimeAttr timeSeries(timeSeriesX);
+ TimeAttr timeSeries2(timeSeries2X);
+ TimeAttr timeSeries3(timeSeries3X);
+ TimeAttr timeSeries4(timeSeries4X);
+
+ std::vector<boost::posix_time::time_duration> timeSeries_free_slots;
+ std::vector<boost::posix_time::time_duration> timeSeries2_free_slots;
+ timeSeries.time_series().free_slots(timeSeries_free_slots);
+ timeSeries2.time_series().free_slots(timeSeries2_free_slots);
+ BOOST_CHECK_MESSAGE(timeSeries_free_slots.size() == 11,"Expected 11 free slots for " << timeSeries.toString() << " but found " << timeSeries_free_slots.size());
+ BOOST_CHECK_MESSAGE(timeSeries2_free_slots.size() == 5,"Expected 5 free slots for " << timeSeries2.toString() << " but found " << timeSeries_free_slots.size());
+// cout << "time " << timeSeries.toString() << " free slots:";
+// for(size_t i = 0; i < timeSeries_free_slots.size(); i++) cout << timeSeries_free_slots[i] << " ";
+// cout << "\n";
+
+ // follow normal process
+ timeSeries.reset( calendar );
+ timeSeries2.reset( calendar );
+ timeSeries3.reset( calendar );
+ timeSeries4.reset( calendar );
+
+ bool day_changed = false; // after midnight make sure we keep day_changed
+ for(int m=1; m < 96; m++) {
+ calendar.update( time_duration( minutes(30) ) );
+ if (!day_changed) day_changed = calendar.dayChanged();
+
+ boost::posix_time::time_duration time = calendar.suiteTime().time_of_day();
+ //cout << time << " day_changed(" << day_changed << ")\n";
+
+ timeSeries.calendarChanged( calendar );
+ timeSeries2.calendarChanged( calendar );
+ timeSeries3.calendarChanged( calendar );
+ timeSeries4.calendarChanged( calendar );
+
+ //cout << to_simple_string(calendar.suiteTime()) << "\n";
+
+ if (calendar.dayChanged()) {
+ BOOST_CHECK_MESSAGE(timeSeries.checkForRequeue(calendar,t1_min,t1_max)," expected " << timeSeries.toString() << " checkForRequeue to pass at " << to_simple_string(calendar.suiteTime()));
+ }
+ else if (time < timeSeries.time_series().start().duration()) {
+ BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar),timeSeries.toString() << " should NOT be free at time " << time );
+ BOOST_CHECK_MESSAGE(timeSeries.checkForRequeue(calendar,t1_min,t1_max),timeSeries.toString() << " checkForRequeue should pass at " << time );
+ }
+ else if (time >= timeSeries.time_series().start().duration() && time <=timeSeries.time_series().finish().duration()) {
+
+ bool matches_free_slot = false;
+ for(size_t i = 0; i < timeSeries_free_slots.size(); i++) {
+ if (time == timeSeries_free_slots[i]) { matches_free_slot = true; break; }
+ }
+ if (matches_free_slot) BOOST_CHECK_MESSAGE(timeSeries.isFree(calendar),timeSeries.toString() << " should be free at time " << time );
+ else BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar),timeSeries.toString() << " should be fail at time " << time );
+
+ /// At the last hour checkForRequeue should return false; This ensures that value will
+ /// not get incremented and so, should leave node in the complete state.
+ if ( time < timeSeries.time_series().finish().duration()) {
+ BOOST_CHECK_MESSAGE(timeSeries.checkForRequeue(calendar,t1_min,t1_max),timeSeries.toString() << " checkForRequeue should be free at time " << time );
+ }
+ else {
+ BOOST_CHECK_MESSAGE(!timeSeries.checkForRequeue(calendar,t1_min,t1_max),timeSeries.toString() << "checkForRequeue should Not free at time " << time );
+ }
+ }
+ else {
+ BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar),timeSeries.toString() << " should be holding at time " << time );
+ BOOST_CHECK_MESSAGE(!timeSeries.checkForRequeue(calendar,t1_min,t1_max),timeSeries.toString() << " should fail at " << time );
+ }
+
+
+ if (calendar.dayChanged()) {
+ BOOST_CHECK_MESSAGE(timeSeries2.checkForRequeue(calendar,t2_min,t2_max)," expected " << timeSeries2.toString() << " checkForRequeue to pass at " << to_simple_string(calendar.suiteTime()));
+ }
+ else if (time < timeSeries2.time_series().start().duration()) {
+ BOOST_CHECK_MESSAGE(!timeSeries2.isFree(calendar),timeSeries2.toString() << " should NOT be free at time " << time );
+ BOOST_CHECK_MESSAGE(timeSeries2.checkForRequeue(calendar,t2_min,t2_max),timeSeries2.toString() << " checkForRequeue should pass at " << time );
+ }
+ else if (time >= timeSeries2.time_series().start().duration() && time <=timeSeries2.time_series().finish().duration()) {
+
+ bool matches_free_slot = false;
+ for(size_t i = 0; i < timeSeries2_free_slots.size(); i++) {
+ if (time == timeSeries2_free_slots[i]) { matches_free_slot = true; break;}
+ }
+ if (matches_free_slot) BOOST_CHECK_MESSAGE(timeSeries2.isFree(calendar),timeSeries2.toString() << " should be free at time " << time );
+ else BOOST_CHECK_MESSAGE(!timeSeries2.isFree(calendar),timeSeries2.toString() << " should be fail at time " << time );
+
+
+ /// At the last time checkForRequeue should return false; This ensures that value will
+ /// not get incremented and so, should leave node in the complete state.
+ if ( time < timeSeries2.time_series().finish().duration()) {
+ BOOST_CHECK_MESSAGE(timeSeries2.checkForRequeue(calendar,t2_min,t2_max),timeSeries2.toString() << " checkForRequeue should be free at time " << time );
+ }
+ else {
+ BOOST_CHECK_MESSAGE(!timeSeries2.checkForRequeue(calendar,t2_min,t2_max),timeSeries2.toString() << "checkForRequeue should Not free at time " << time );
+ }
+ }
+ else {
+ BOOST_CHECK_MESSAGE(!timeSeries2.isFree(calendar),timeSeries2.toString() << " should be holding at time " << time );
+ BOOST_CHECK_MESSAGE(!timeSeries2.checkForRequeue(calendar,t2_min,t2_max),timeSeries2.toString() << " should fail at " << time );
+ }
+
+
+ // Single slot, Once a single slot is Free it *stays* free until explicitly requeued, (i.e by parent repeat/cron)
+ if (!day_changed) {
+ if (time < timeSeries3.time_series().start().duration()) {
+ BOOST_CHECK_MESSAGE(!timeSeries3.isFree(calendar),timeSeries3.toString() << " should be fail at time " << time );
+ }
+ else if (time == timeSeries3.time_series().start().duration() ) {
+ BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries3.toString() << " should be free at time " << time );
+ }
+ else if (time > timeSeries3.time_series().start().duration()) {
+ BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries3.toString() << " isFree should pass at time " << time );
+ }
+ }
+ else {
+ BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries3.toString() << " should be free at time after day change" << time );
+ }
+ BOOST_CHECK_MESSAGE(!timeSeries3.checkForRequeue(calendar,t3_min,t3_max),timeSeries3.toString() << " checkForRequeue should fail at " << time );
+
+
+ // single slot at midnight, Once a single slot if Free it *stays* free until explicitly requeued, (i.e by parent repeat/cron)
+ if (!day_changed) {
+ if (time == timeSeries4.time_series().start().duration() ) {
+ BOOST_CHECK_MESSAGE(timeSeries4.isFree(calendar),timeSeries4.toString() << " should be free at time " << time );
+ }
+ else {
+ BOOST_CHECK_MESSAGE(!timeSeries4.isFree(calendar),timeSeries4.toString() << " day_changed(" << day_changed << ") isFree should fail at time " << time );
+ }
+ }
+ else {
+ BOOST_CHECK_MESSAGE(timeSeries4.isFree(calendar),timeSeries4.toString() << " day_changed(" << day_changed << ") isFree should pass at time " << time );
+ }
+ BOOST_CHECK_MESSAGE(!timeSeries4.checkForRequeue(calendar,t4_min,t4_max),timeSeries4.toString() << " checkForRequeue should fail at " << time );
+
+
+ // Typically when a time is free, it stays free, until it is re-queued
+ // However in order to test isFree for time with time intervals, we need to re-queue
+ timeSeries.requeue( calendar );
+ timeSeries2.requeue( calendar );
+
+ // Do not requeue time 00, and time 15, so that we can check for free
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_time_once_free_stays_free)
+{
+ cout << "ANattr:: ...test_time_once_free_stays_free\n";
+
+ Calendar calendar;
+ calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::REAL);
+
+ TimeSeries timeSeriesX(TimeSlot(10,0), TimeSlot(20,0), TimeSlot(1,0), false/* relative */);
+ TimeSeries timeSeries2X(TimeSlot(11,0), TimeSlot(15,0), TimeSlot(1,0), false/* relative */);
+ TimeSeries timeSeries3X(TimeSlot(15,0), false/* relative */);
+ TimeSeries timeSeries4X(TimeSlot(0,0), false/* relative */);
+
+ TimeAttr timeSeries(timeSeriesX );
+ TimeAttr timeSeries2(timeSeries2X );
+ TimeAttr timeSeries3(timeSeries3X );
+ TimeAttr timeSeries4(timeSeries4X );
+
+ bool day_changed = false; // after midnight make sure we keep day_changed
+ for(int m=1; m < 96; m++) {
+ calendar.update( time_duration( minutes(30) ) );
+ if (!day_changed) {
+ day_changed = calendar.dayChanged();
+ }
+ boost::posix_time::time_duration time = calendar.suiteTime().time_of_day();
+ // cout << time << " day_changed(" << day_changed << ")\n";
+
+ timeSeries.calendarChanged( calendar );
+ timeSeries2.calendarChanged( calendar );
+ timeSeries3.calendarChanged( calendar );
+ timeSeries4.calendarChanged( calendar );
+
+ // **********************************************************************************
+ // When a time (regardless of whether its single slot or time series) is free, it stays free,
+ // until explicitly re-queued,
+ // ***********************************************************************************
+
+ if (time < timeSeries.time_series().start().duration()) {
+ if (!day_changed) BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar),timeSeries.toString() << " should NOT be free at time " << time );
+ else BOOST_CHECK_MESSAGE(timeSeries.isFree(calendar),timeSeries.toString() << " should be free at time " << time );
+ }
+ else if (time >= timeSeries.time_series().start().duration()) {
+ BOOST_CHECK_MESSAGE(timeSeries.isFree(calendar),timeSeries.toString() << " should be free at time " << time );
+ }
+
+
+ if (time < timeSeries2.time_series().start().duration()) {
+ if (!day_changed) BOOST_CHECK_MESSAGE(!timeSeries2.isFree(calendar),timeSeries2.toString() << " should NOT be free at time " << time );
+ else BOOST_CHECK_MESSAGE(timeSeries.isFree(calendar),timeSeries.toString() << " should be free at time " << time );
+ }
+ else if (time >= timeSeries2.time_series().start().duration()) {
+ BOOST_CHECK_MESSAGE(timeSeries2.isFree(calendar),timeSeries2.toString() << " should be free at time " << time );
+ }
+
+ if (!day_changed) {
+ if (time == timeSeries3.time_series().start().duration() ) {
+ BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries3.toString() << " should be free at time " << time );
+ }
+ else if (time > timeSeries3.time_series().start().duration()) {
+ BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries3.toString() << " isFree, once free should stay free at time " << time );
+ }
+ }
+ else {
+ BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries3.toString() << " should be free at time after day change " << time );
+ }
+
+
+ // single slot at midnight, Once a single slot if Free it *stays* free until explicitly requeued, (i.e by parent repeat/cron)
+ if (!day_changed) {
+ if (time == timeSeries4.time_series().start().duration() ) {
+ BOOST_CHECK_MESSAGE(timeSeries4.isFree(calendar),timeSeries4.toString() << " should be free at time " << time );
+ }
+ else {
+ BOOST_CHECK_MESSAGE(!timeSeries4.isFree(calendar),timeSeries4.toString() << " day_changed(" << day_changed << ") isFree should fail at time " << time );
+ }
+ }
+ else {
+ BOOST_CHECK_MESSAGE(timeSeries4.isFree(calendar),timeSeries4.toString() << " day_changed(" << day_changed << ") isFree should pass at time " << time );
+ }
+ }
+}
+
+
+BOOST_AUTO_TEST_CASE( test_time_attr_multiples )
+{
+ cout << "ANattr:: ...test_time_attr_multiples\n";
+
+ // See TimeAttr.hpp for rules concerning isFree() and checkForReque()
+ // test time attr isFree(), and checkForRequeue
+ Calendar calendar;
+ calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::REAL);
+
+ TimeSeries timeSeries1530(TimeSlot(15,30), false/* relative */);
+ TimeSeries timeSeries1630(TimeSlot(16,30), false/* relative */);
+ TimeSeries timeSeries2030(TimeSlot(20,30), false/* relative */);
+
+ TimeSlot t1_min, t1_max;
+ timeSeries1530.min_max_time_slots(t1_min, t1_max);
+ timeSeries1630.min_max_time_slots(t1_min, t1_max);
+ timeSeries2030.min_max_time_slots(t1_min, t1_max);
+ BOOST_CHECK_MESSAGE(t1_min == TimeSlot(15,30) && t1_max == TimeSlot(20,30),"Not as expected");
+
+ TimeAttr timeSeries(timeSeries1530);
+ TimeAttr timeSeries2(timeSeries1630);
+ TimeAttr timeSeries3(timeSeries2030);
+
+ bool day_changed = false; // after midnight make sure we keep day_changed
+ for(int m=1; m < 96; m++) {
+ calendar.update( time_duration( minutes(30) ) );
+ if (!day_changed) {
+ day_changed = calendar.dayChanged();
+ }
+ boost::posix_time::time_duration time = calendar.suiteTime().time_of_day();
+ // cout << time << " day_changed(" << day_changed << ")\n";
+
+ timeSeries.calendarChanged( calendar );
+ timeSeries2.calendarChanged( calendar );
+ timeSeries3.calendarChanged( calendar );
+
+ if (!day_changed) {
+ if ( time < t1_max.duration()) {
+ BOOST_CHECK_MESSAGE(timeSeries.checkForRequeue(calendar,t1_min,t1_max),timeSeries.toString() << " checkForRequeue should pass at " << time );
+ BOOST_CHECK_MESSAGE(timeSeries2.checkForRequeue(calendar,t1_min,t1_max),timeSeries2.toString() << " checkForRequeue should pass at " << time );
+ BOOST_CHECK_MESSAGE(timeSeries3.checkForRequeue(calendar,t1_min,t1_max),timeSeries3.toString() << " checkForRequeue should pass at " << time );
+ }
+ else {
+ BOOST_CHECK_MESSAGE(!timeSeries.checkForRequeue(calendar,t1_min,t1_max),timeSeries.toString() << " checkForRequeue should fail at " << time );
+ BOOST_CHECK_MESSAGE(!timeSeries2.checkForRequeue(calendar,t1_min,t1_max),timeSeries2.toString() << " checkForRequeue should fail at " << time );
+ BOOST_CHECK_MESSAGE(!timeSeries3.checkForRequeue(calendar,t1_min,t1_max),timeSeries3.toString() << " checkForRequeue should fail at " << time );
+ }
+ }
+ else {
+ // Once a single slot if Free it *stays* free until explicitly requeued, (i.e by parent repeat/cron)
+ BOOST_CHECK_MESSAGE(timeSeries.isFree(calendar),timeSeries.toString() << " day_changed(" << day_changed << ") isFree should pass at time " << time );
+ BOOST_CHECK_MESSAGE(timeSeries2.isFree(calendar),timeSeries2.toString() << " day_changed(" << day_changed << ") isFree should pass at time " << time );
+ BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries2.toString() << " day_changed(" << day_changed << ") isFree should pass at time " << time );
+ }
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/ANattr/test/TestTodayAttr.cpp b/ANattr/test/TestTodayAttr.cpp
new file mode 100644
index 0000000..f31e493
--- /dev/null
+++ b/ANattr/test/TestTodayAttr.cpp
@@ -0,0 +1,181 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #14 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <boost/test/unit_test.hpp>
+#include <boost/date_time/posix_time/time_formatters.hpp>
+
+#include "TodayAttr.hpp"
+#include "TimeSeries.hpp"
+#include "Calendar.hpp"
+#include "Str.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::posix_time;
+using namespace boost::gregorian;
+
+BOOST_AUTO_TEST_SUITE( ANattrTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_today_attr)
+{
+ cout << "ANattr:: ...test_today_attr\n";
+
+ // See TodayAttr.hpp for rules concerning isFree() and checkForReque()
+ // test today attr isFree(), and checkForRequeue
+ Calendar calendar;
+ calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::REAL);
+
+ // Create a test when we can match a time series. Need to sync hour with suite time
+ // at hour 1, suite time should also be 01:00, for test to work
+ //
+ // Create the time series: start 10:00
+ // finish 20:00
+ // incr 1:00
+ TimeSeries timeSeriesX(TimeSlot(10,0), TimeSlot(20,0), TimeSlot(1,0), false/* relative */);
+ TimeSeries timeSeries2X(TimeSlot(11,0), TimeSlot(15,0), TimeSlot(1,0), false/* relative */);
+ TimeSeries timeSeries3X(TimeSlot(15,0), false/* relative */);
+
+ TimeSlot t1_min, t1_max,t2_min,t2_max,t3_min,t3_max;
+ timeSeriesX.min_max_time_slots(t1_min, t1_max);
+ timeSeries2X.min_max_time_slots(t2_min, t2_max);
+ timeSeries3X.min_max_time_slots(t3_min, t3_max);
+ BOOST_CHECK_MESSAGE(t1_min == TimeSlot(10,0) && t1_max == TimeSlot(20,0),"Not as expected");
+ BOOST_CHECK_MESSAGE(t2_min == TimeSlot(11,0) && t2_max == TimeSlot(15,0),"Not as expected");
+ BOOST_CHECK_MESSAGE(t3_min == TimeSlot(15,0) && t3_max == TimeSlot(15,0),"Not as expected");
+
+
+ TodayAttr timeSeries(timeSeriesX);
+ TodayAttr timeSeries2(timeSeries2X);
+ TodayAttr timeSeries3(timeSeries3X);
+
+ std::vector<boost::posix_time::time_duration> timeSeries_free_slots;
+ std::vector<boost::posix_time::time_duration> timeSeries2_free_slots;
+ timeSeries.time_series().free_slots(timeSeries_free_slots);
+ timeSeries2.time_series().free_slots(timeSeries2_free_slots);
+ BOOST_CHECK_MESSAGE(timeSeries_free_slots.size() == 11,"Expected 11 free slots for " << timeSeries.toString() << " but found " << timeSeries_free_slots.size());
+ BOOST_CHECK_MESSAGE(timeSeries2_free_slots.size() == 5,"Expected 5 free slots for " << timeSeries2.toString() << " but found " << timeSeries_free_slots.size());
+
+ // follow normal process
+ timeSeries.reset( calendar );
+ timeSeries2.reset( calendar );
+ timeSeries3.reset( calendar );
+
+ bool day_changed = false; // after midnight make sure we keep day_changed
+ for(int m=1; m < 96; m++) {
+ calendar.update( time_duration( minutes(30) ) );
+ if (!day_changed) {
+ day_changed = calendar.dayChanged();
+ }
+ boost::posix_time::time_duration time = calendar.suiteTime().time_of_day();
+// cout << time << " day_changed(" << day_changed << ")\n";
+
+ timeSeries.calendarChanged( calendar );
+ timeSeries2.calendarChanged( calendar );
+ timeSeries3.calendarChanged( calendar );
+
+ if (!day_changed) {
+
+ if (time < timeSeries.time_series().start().duration()) {
+ BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar),timeSeries.toString() << " should NOT be free at time " << time );
+ BOOST_CHECK_MESSAGE(timeSeries.checkForRequeue(calendar,t1_min,t1_max),timeSeries.toString() << " should pass at " << time );
+ }
+ else if (time >= timeSeries.time_series().start().duration() && time <=timeSeries.time_series().finish().duration()) {
+
+ bool matches_free_slot = false;
+ for(size_t i = 0; i < timeSeries_free_slots.size(); i++) {
+ if (time == timeSeries_free_slots[i]) { matches_free_slot = true; break; }
+ }
+ // no else branch since once today is free it stays free, unti re-queue
+ if (matches_free_slot) BOOST_CHECK_MESSAGE(timeSeries.isFree(calendar),timeSeries.toString() << " should be free at time " << time );
+
+ /// At the last time checkForRequeue should return false; This ensures that value will
+ /// not get incremented and so, should leave node in the complete state.
+ if ( time < timeSeries.time_series().finish().duration()) {
+ BOOST_CHECK_MESSAGE(timeSeries.checkForRequeue(calendar,t1_min,t1_max),timeSeries.toString() << " checkForRequeue should be free at time " << time );
+ }
+ else {
+ BOOST_CHECK_MESSAGE(!timeSeries.checkForRequeue(calendar,t1_min,t1_max),timeSeries.toString() << "checkForRequeue should Not free at time " << time );
+ }
+ }
+ else {
+ // After end time, a Today Attr should be free to run.
+ BOOST_CHECK_MESSAGE(timeSeries.isFree(calendar),timeSeries.toString() << " should be free at time " << time );
+ BOOST_CHECK_MESSAGE(!timeSeries.checkForRequeue(calendar,t1_min,t1_max),timeSeries.toString() << " should fail at " << time );
+ }
+ }
+ else {
+ // Once a today time series is free, it stays free
+ BOOST_CHECK_MESSAGE(timeSeries.isFree(calendar),timeSeries.toString() << " should be free at time " << time );
+ }
+
+
+ if (!day_changed) {
+ if (time < timeSeries2.time_series().start().duration()) {
+ BOOST_CHECK_MESSAGE(!timeSeries2.isFree(calendar),timeSeries2.toString() << " should NOT be free at time " << time );
+ BOOST_CHECK_MESSAGE(timeSeries2.checkForRequeue(calendar,t2_min,t2_max),timeSeries2.toString() << " should pass at " << time );
+ }
+ else if (time >= timeSeries2.time_series().start().duration() && time <=timeSeries2.time_series().finish().duration()) {
+
+ bool matches_free_slot = false;
+ for(size_t i = 0; i < timeSeries2_free_slots.size(); i++) {
+ if (time == timeSeries2_free_slots[i]) { matches_free_slot = true; break; }
+ }
+ if (matches_free_slot) BOOST_CHECK_MESSAGE(timeSeries2.isFree(calendar),timeSeries2.toString() << " should be free at time " << time );
+
+ /// At the last time checkForRequeue should return false; This ensures that value will
+ /// not get incremented and so, should leave node in the complete state.
+ if ( time < timeSeries2.time_series().finish().duration()) {
+ BOOST_CHECK_MESSAGE(timeSeries2.checkForRequeue(calendar,t2_min,t2_max),timeSeries2.toString() << " checkForRequeue should be free at time " << time );
+ }
+ else {
+ BOOST_CHECK_MESSAGE(!timeSeries2.checkForRequeue(calendar,t2_min,t2_max),timeSeries2.toString() << "checkForRequeue should Not free at time " << time );
+ }
+ }
+ else {
+ // After end time, a Today Attr should be free to run.
+ BOOST_CHECK_MESSAGE(timeSeries2.isFree(calendar),timeSeries2.toString() << " should be holding at time " << time );
+ BOOST_CHECK_MESSAGE(!timeSeries2.checkForRequeue(calendar,t2_min,t2_max),timeSeries2.toString() << " should fail at " << time );
+ }
+ }
+ else {
+ // Once a today time series is free, it stays free
+ BOOST_CHECK_MESSAGE(timeSeries2.isFree(calendar),timeSeries2.toString() << " should be holding at time " << time );
+ }
+
+ // Single slot
+ if (!day_changed) {
+ if (time == timeSeries3.time_series().start().duration() ) {
+ BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries3.toString() << " should be free at time " << time );
+ }
+ else if (time < timeSeries3.time_series().start().duration()) {
+ BOOST_CHECK_MESSAGE(!timeSeries3.isFree(calendar),timeSeries3.toString() << " isFree should fail at time " << time );
+ }
+ else if (time > timeSeries3.time_series().start().duration()) {
+ BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries3.toString() << " isFree should fail at time " << time );
+ }
+ }
+ else {
+ // Once a single slot if Free it *stays* free until explicitly requeued, (i.e by parent repeat/cron)
+ BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries3.toString() << " isFree should fail at time " << time );
+ }
+ BOOST_CHECK_MESSAGE(!timeSeries3.checkForRequeue(calendar,t3_min,t3_max),timeSeries3.toString() << " checkForRequeue should fail at " << time );
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/ANattr/test/TestVariable.cpp b/ANattr/test/TestVariable.cpp
new file mode 100644
index 0000000..4f33cf2
--- /dev/null
+++ b/ANattr/test/TestVariable.cpp
@@ -0,0 +1,57 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #14 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <iostream>
+#include <boost/test/unit_test.hpp>
+
+#include "Variable.hpp"
+#include "Str.hpp"
+
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( ANattrTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_multi_line_variable_values )
+{
+ cout << "ANattr:: ...test_multi_line_variable_values\n";
+
+ {
+ Variable var("name","value");
+ BOOST_CHECK_MESSAGE(var.name() == "name","name not as expected");
+ BOOST_CHECK_MESSAGE(var.theValue() == "value","value not as expected");
+
+ std::string expected = "edit name 'value'";
+ BOOST_CHECK_MESSAGE(var.toString() == expected,"expected " << expected << " but found " << var.toString());
+ }
+ {
+ Variable var("name","");
+ std::string expected = "edit name ''";
+ BOOST_CHECK_MESSAGE(var.toString() == expected,"expected " << expected << " but found " << var.toString());
+ }
+ {
+ Variable var("name","value\n");
+ std::string expected = "edit name 'value\\n'";
+ BOOST_CHECK_MESSAGE(var.toString() == expected,"expected " << expected << " but found " << var.toString());
+ }
+ {
+ Variable var("name","val1\nxxx\nval2");
+ std::string expected = "edit name 'val1\\nxxx\\nval2'";
+ BOOST_CHECK_MESSAGE(var.toString() == expected,"expected " << expected << " but found " << var.toString());
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/AutoCancelAttr b/ANattr/test/data/migration/default_constructor_v1_9/AutoCancelAttr
similarity index 100%
rename from ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/AutoCancelAttr
rename to ANattr/test/data/migration/default_constructor_v1_9/AutoCancelAttr
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/ClockAttr b/ANattr/test/data/migration/default_constructor_v1_9/ClockAttr
similarity index 100%
rename from ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/ClockAttr
rename to ANattr/test/data/migration/default_constructor_v1_9/ClockAttr
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/CronAttr b/ANattr/test/data/migration/default_constructor_v1_9/CronAttr
similarity index 100%
rename from ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/CronAttr
rename to ANattr/test/data/migration/default_constructor_v1_9/CronAttr
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/DateAttr b/ANattr/test/data/migration/default_constructor_v1_9/DateAttr
similarity index 100%
rename from ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/DateAttr
rename to ANattr/test/data/migration/default_constructor_v1_9/DateAttr
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/DayAttr b/ANattr/test/data/migration/default_constructor_v1_9/DayAttr
similarity index 100%
rename from ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/DayAttr
rename to ANattr/test/data/migration/default_constructor_v1_9/DayAttr
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/Event b/ANattr/test/data/migration/default_constructor_v1_9/Event
similarity index 100%
rename from ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/Event
rename to ANattr/test/data/migration/default_constructor_v1_9/Event
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/Label b/ANattr/test/data/migration/default_constructor_v1_9/Label
similarity index 100%
rename from ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/Label
rename to ANattr/test/data/migration/default_constructor_v1_9/Label
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/LateAttr b/ANattr/test/data/migration/default_constructor_v1_9/LateAttr
similarity index 100%
rename from ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/LateAttr
rename to ANattr/test/data/migration/default_constructor_v1_9/LateAttr
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/Meter b/ANattr/test/data/migration/default_constructor_v1_9/Meter
similarity index 100%
rename from ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/Meter
rename to ANattr/test/data/migration/default_constructor_v1_9/Meter
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/RepeatDate b/ANattr/test/data/migration/default_constructor_v1_9/RepeatDate
similarity index 100%
rename from ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/RepeatDate
rename to ANattr/test/data/migration/default_constructor_v1_9/RepeatDate
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/RepeatEnumerated b/ANattr/test/data/migration/default_constructor_v1_9/RepeatEnumerated
similarity index 100%
rename from ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/RepeatEnumerated
rename to ANattr/test/data/migration/default_constructor_v1_9/RepeatEnumerated
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/RepeatInteger b/ANattr/test/data/migration/default_constructor_v1_9/RepeatInteger
similarity index 100%
rename from ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/RepeatInteger
rename to ANattr/test/data/migration/default_constructor_v1_9/RepeatInteger
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/RepeatString b/ANattr/test/data/migration/default_constructor_v1_9/RepeatString
similarity index 100%
rename from ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/RepeatString
rename to ANattr/test/data/migration/default_constructor_v1_9/RepeatString
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/TimeAttr b/ANattr/test/data/migration/default_constructor_v1_9/TimeAttr
similarity index 100%
rename from ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/TimeAttr
rename to ANattr/test/data/migration/default_constructor_v1_9/TimeAttr
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/TodayAttr b/ANattr/test/data/migration/default_constructor_v1_9/TodayAttr
similarity index 100%
rename from ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/TodayAttr
rename to ANattr/test/data/migration/default_constructor_v1_9/TodayAttr
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/Variable b/ANattr/test/data/migration/default_constructor_v1_9/Variable
similarity index 100%
rename from ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/Variable
rename to ANattr/test/data/migration/default_constructor_v1_9/Variable
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/VerifyAttr b/ANattr/test/data/migration/default_constructor_v1_9/VerifyAttr
similarity index 100%
rename from ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/VerifyAttr
rename to ANattr/test/data/migration/default_constructor_v1_9/VerifyAttr
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/ZombieAttr b/ANattr/test/data/migration/default_constructor_v1_9/ZombieAttr
similarity index 100%
rename from ecflow_4_0_7/ANattr/test/data/migration/default_constructor_v1_9/ZombieAttr
rename to ANattr/test/data/migration/default_constructor_v1_9/ZombieAttr
diff --git a/ANattr/test/data/migration/v1_9/AutoCancelAttr b/ANattr/test/data/migration/v1_9/AutoCancelAttr
new file mode 100644
index 0000000..b5be3e5
--- /dev/null
+++ b/ANattr/test/data/migration/v1_9/AutoCancelAttr
@@ -0,0 +1 @@
+22 serialization::archive 10 0 0 2400 0 0 1 1
diff --git a/ANattr/test/data/migration/v1_9/AutoCancelAttr_1 b/ANattr/test/data/migration/v1_9/AutoCancelAttr_1
new file mode 100644
index 0000000..42f3e2c
--- /dev/null
+++ b/ANattr/test/data/migration/v1_9/AutoCancelAttr_1
@@ -0,0 +1 @@
+22 serialization::archive 10 0 0 10 12 0 1 0
diff --git a/ANattr/test/data/migration/v1_9/ClockAttr b/ANattr/test/data/migration/v1_9/ClockAttr
new file mode 100644
index 0000000..8ac5292
--- /dev/null
+++ b/ANattr/test/data/migration/v1_9/ClockAttr
@@ -0,0 +1 @@
+22 serialization::archive 10 0 0 0 1 1 3600 1 1 2009
diff --git a/ANattr/test/data/migration/v1_9/CronAttr b/ANattr/test/data/migration/v1_9/CronAttr
new file mode 100644
index 0000000..52a4002
--- /dev/null
+++ b/ANattr/test/data/migration/v1_9/CronAttr
@@ -0,0 +1 @@
+22 serialization::archive 10 0 1 0 0 0 20 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 2 0 1 2 2 0 1 2 2 0 1 2 0
diff --git a/ANattr/test/data/migration/v1_9/DateAttr b/ANattr/test/data/migration/v1_9/DateAttr
new file mode 100644
index 0000000..fad3b28
--- /dev/null
+++ b/ANattr/test/data/migration/v1_9/DateAttr
@@ -0,0 +1 @@
+22 serialization::archive 10 12 12 2012 0
diff --git a/ANattr/test/data/migration/v1_9/DayAttr b/ANattr/test/data/migration/v1_9/DayAttr
new file mode 100644
index 0000000..013a5bd
--- /dev/null
+++ b/ANattr/test/data/migration/v1_9/DayAttr
@@ -0,0 +1 @@
+22 serialization::archive 10 1 0
diff --git a/ANattr/test/data/migration/v1_9/Event_1 b/ANattr/test/data/migration/v1_9/Event_1
new file mode 100644
index 0000000..fe58c1d
--- /dev/null
+++ b/ANattr/test/data/migration/v1_9/Event_1
@@ -0,0 +1 @@
+22 serialization::archive 10 0 1 0
diff --git a/ANattr/test/data/migration/v1_9/Event_2 b/ANattr/test/data/migration/v1_9/Event_2
new file mode 100644
index 0000000..c9c4b6f
--- /dev/null
+++ b/ANattr/test/data/migration/v1_9/Event_2
@@ -0,0 +1 @@
+22 serialization::archive 10 0 2147483647 5 event
diff --git a/ANattr/test/data/migration/v1_9/Label b/ANattr/test/data/migration/v1_9/Label
new file mode 100644
index 0000000..e2c9aa8
--- /dev/null
+++ b/ANattr/test/data/migration/v1_9/Label
@@ -0,0 +1 @@
+22 serialization::archive 10 4 name 5 value 9 new_value
diff --git a/ANattr/test/data/migration/v1_9/LateAttr b/ANattr/test/data/migration/v1_9/LateAttr
new file mode 100644
index 0000000..3ff04b4
--- /dev/null
+++ b/ANattr/test/data/migration/v1_9/LateAttr
@@ -0,0 +1 @@
+22 serialization::archive 10 0 0 10 12 0 10 12 0 10 12 0 1 0
diff --git a/ANattr/test/data/migration/v1_9/Meter b/ANattr/test/data/migration/v1_9/Meter
new file mode 100644
index 0000000..54ba15b
--- /dev/null
+++ b/ANattr/test/data/migration/v1_9/Meter
@@ -0,0 +1 @@
+22 serialization::archive 10 10 100 10 100 5 meter
diff --git a/ANattr/test/data/migration/v1_9/RepeatDate b/ANattr/test/data/migration/v1_9/RepeatDate
new file mode 100644
index 0000000..f27cf1d
--- /dev/null
+++ b/ANattr/test/data/migration/v1_9/RepeatDate
@@ -0,0 +1,2 @@
+22 serialization::archive 10 1 0
+0 0 0 4 date 20110112 20110115 1 20110112
diff --git a/ANattr/test/data/migration/v1_9/RepeatEnumerated b/ANattr/test/data/migration/v1_9/RepeatEnumerated
new file mode 100644
index 0000000..f99058b
--- /dev/null
+++ b/ANattr/test/data/migration/v1_9/RepeatEnumerated
@@ -0,0 +1,2 @@
+22 serialization::archive 10 1 0
+0 0 0 4 enum 0 0 2 0 1 a 1 b 0
diff --git a/ANattr/test/data/migration/v1_9/RepeatInteger b/ANattr/test/data/migration/v1_9/RepeatInteger
new file mode 100644
index 0000000..254a009
--- /dev/null
+++ b/ANattr/test/data/migration/v1_9/RepeatInteger
@@ -0,0 +1,2 @@
+22 serialization::archive 10 1 0
+0 0 0 7 integer 0 100 2 0
diff --git a/ANattr/test/data/migration/v1_9/RepeatString b/ANattr/test/data/migration/v1_9/RepeatString
new file mode 100644
index 0000000..3c3764e
--- /dev/null
+++ b/ANattr/test/data/migration/v1_9/RepeatString
@@ -0,0 +1,2 @@
+22 serialization::archive 10 1 0
+0 0 0 6 string 0 0 2 0 1 a 1 b 0
diff --git a/ANattr/test/data/migration/v1_9/TimeAttr b/ANattr/test/data/migration/v1_9/TimeAttr
new file mode 100644
index 0000000..340ed6c
--- /dev/null
+++ b/ANattr/test/data/migration/v1_9/TimeAttr
@@ -0,0 +1 @@
+22 serialization::archive 10 0 1 10 12 0 0 0 1 0 0 1 10 12 0 0 0 0 0 0 0 0 0
diff --git a/ANattr/test/data/migration/v1_9/TodayAttr b/ANattr/test/data/migration/v1_9/TodayAttr
new file mode 100644
index 0000000..340ed6c
--- /dev/null
+++ b/ANattr/test/data/migration/v1_9/TodayAttr
@@ -0,0 +1 @@
+22 serialization::archive 10 0 1 10 12 0 0 0 1 0 0 1 10 12 0 0 0 0 0 0 0 0 0
diff --git a/ANattr/test/data/migration/v1_9/Variable b/ANattr/test/data/migration/v1_9/Variable
new file mode 100644
index 0000000..4ba6118
--- /dev/null
+++ b/ANattr/test/data/migration/v1_9/Variable
@@ -0,0 +1 @@
+22 serialization::archive 10 8 var_name 9 var_value
diff --git a/ANattr/test/data/migration/v1_9/VerifyAttr b/ANattr/test/data/migration/v1_9/VerifyAttr
new file mode 100644
index 0000000..047dfa6
--- /dev/null
+++ b/ANattr/test/data/migration/v1_9/VerifyAttr
@@ -0,0 +1 @@
+22 serialization::archive 10 1 3 0
diff --git a/ANattr/test/data/migration/v1_9/ZombieAttr b/ANattr/test/data/migration/v1_9/ZombieAttr
new file mode 100644
index 0000000..5c368d0
--- /dev/null
+++ b/ANattr/test/data/migration/v1_9/ZombieAttr
@@ -0,0 +1 @@
+22 serialization::archive 10 0 0 300 0 0 7 0 0 1 2 3 4 5 6
diff --git a/ANattr/test/data/migration/v1_9/ZombieAttr1 b/ANattr/test/data/migration/v1_9/ZombieAttr1
new file mode 100644
index 0000000..4b061ea
--- /dev/null
+++ b/ANattr/test/data/migration/v1_9/ZombieAttr1
@@ -0,0 +1 @@
+22 serialization::archive 10 0 0 500 0 0 7 0 0 1 2 3 4 5 6
diff --git a/ANode/CMakeLists.txt b/ANode/CMakeLists.txt
new file mode 100644
index 0000000..8246f8c
--- /dev/null
+++ b/ANode/CMakeLists.txt
@@ -0,0 +1,79 @@
+# Note:
+# If new src or test cpp files are added make sure you touch this file
+#
+
+file( GLOB srcs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp" )
+
+ecbuild_add_library( TARGET node
+ NOINSTALL
+ TYPE STATIC
+ SOURCES ${srcs}
+ LIBS nodeattr core
+ INCLUDES src
+ ../ACore/src
+ ../ANattr/src
+ )
+
+# Use following to populate list:
+# cd $WK/ANode
+# find test -name \*.cpp | sort
+
+# no way to exclude file ?
+#file( GLOB test_srcs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "test/*.cpp" )
+
+list( APPEND test_srcs
+test/Test_ECFLOW-195.cpp
+test/Test_ECFLOW-247.cpp
+test/Test_ECFLOW-417.cpp
+test/TestAdd.cpp
+test/TestAlias.cpp
+test/TestChangeMgrSingleton.cpp
+test/TestDefStatus.cpp
+test/TestDefs.cpp
+test/TestEcfFile.cpp
+test/TestEnviromentSubstitution.cpp
+test/TestExprParser.cpp
+test/TestExprRepeatDateArithmetic.cpp
+test/TestFindAbsNodePath.cpp
+test/TestFlag.cpp
+test/TestHistoryParser.cpp
+test/TestInLimit.cpp
+test/TestJobCreator.cpp
+test/TestJobProfiler.cpp
+test/TestLimit.cpp
+test/TestMigration.cpp
+test/TestMissNextTimeSlot.cpp
+test/TestNodeBeginReque.cpp
+test/TestNodeState.cpp
+test/TestOrder.cpp
+test/TestPersistence.cpp
+test/TestPreProcessing.cpp
+test/TestReplace.cpp
+test/TestSetState.cpp
+test/TestSmsLocator.cpp
+test/TestTaskScriptGenerator.cpp
+test/TestTimeDependencies.cpp
+test/TestVariableGeneration.cpp
+test/TestVariableInheritance.cpp
+test/TestVariableSubstitution.cpp
+test/TestVariableSubstitutionDefs.cpp
+test/TestZombies.cpp
+)
+
+ecbuild_add_test(TARGET u_anode
+ BOOST
+ SOURCES ${test_srcs}
+ LIBS node
+ TEST_DEPENDS u_anattr
+ )
+
+if (ENABLE_ALL_TESTS)
+ list( APPEND stest_srcs test/TestSingleExprParse.cpp )
+ ecbuild_add_test( TARGET u_anode_stest
+ BOOST
+ SOURCES ${stest_srcs}
+ LIBS node
+ TEST_DEPENDS u_anattr
+ )
+endif()
+
diff --git a/ANode/jamfile.jam b/ANode/jamfile.jam
new file mode 100644
index 0000000..d4336ea
--- /dev/null
+++ b/ANode/jamfile.jam
@@ -0,0 +1,64 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+#
+# Node project
+#
+project theNode ;
+
+use-project theCore : ../ACore ;
+use-project theNodeAttr : ../ANattr ;
+
+
+# The <include> means we will automatically add this directory to the include path
+# of any other target that uses this lib
+#
+lib node : [ glob src/*.cpp ]
+ : <link>static
+ <variant>debug:<define>DEBUG
+ <use>/theCore//core
+ <use>/theNodeAttr//nodeattr
+ <use>/site-config//boost_system
+ <use>/site-config//boost_serialization
+ <use>/site-config//boost_filesystem
+ <use>/site-config//boost_datetime
+ <use>/site-config//boost_test
+ :
+ : <include>../ANode/src
+ ;
+
+
+#
+# This is *ONLY* required when the define ECFLOW_MT is used, (used by Signal.cpp)
+lib pthread ;
+
+exe u_anode : [ glob test/*.cpp : test/TestSingleExprParse.cpp ]
+ pthread
+ /theCore//core
+ /theNodeAttr//nodeattr
+ node
+ /site-config//boost_system
+ /site-config//boost_serialization
+ /site-config//boost_filesystem
+ /site-config//boost_datetime
+ /site-config//boost_test
+ : <variant>debug:<define>DEBUG
+ ;
+
+
+exe u_anode_stest : test/TestSingleExprParse.cpp
+ pthread
+ /theCore//core
+ /theNodeAttr//nodeattr
+ node
+ /site-config//boost_system
+ /site-config//boost_serialization
+ /site-config//boost_filesystem
+ /site-config//boost_datetime
+ /site-config//boost_test
+ : <variant>debug:<define>DEBUG
+ ;
diff --git a/ANode/src/AbstractObserver.hpp b/ANode/src/AbstractObserver.hpp
new file mode 100644
index 0000000..c3759c0
--- /dev/null
+++ b/ANode/src/AbstractObserver.hpp
@@ -0,0 +1,35 @@
+#ifndef ABSTRACT_OBSERVER_HPP_
+#define ABSTRACT_OBSERVER_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <vector>
+#include "Aspect.hpp"
+class Node;
+class Defs;
+
+class AbstractObserver {
+public:
+ virtual ~AbstractObserver() {}
+
+ virtual void update(const Node*, const std::vector<ecf::Aspect::Type>&) = 0;
+ virtual void update(const Defs*, const std::vector<ecf::Aspect::Type>&) = 0;
+
+ /// After this call, the node will be deleted, hence observers must *NOT* use the pointers
+ virtual void update_delete(const Node*) {}
+ virtual void update_delete(const Defs*) {}
+};
+
+#endif
diff --git a/ANode/src/Alias.cpp b/ANode/src/Alias.cpp
new file mode 100644
index 0000000..491558c
--- /dev/null
+++ b/ANode/src/Alias.cpp
@@ -0,0 +1,165 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #19 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <assert.h>
+#include <sstream>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include "boost/filesystem/exception.hpp"
+#include <boost/lexical_cast.hpp>
+#include <boost/make_shared.hpp>
+
+#include "Alias.hpp"
+#include "Defs.hpp"
+#include "Ecf.hpp"
+#include "Log.hpp"
+#include "Stl.hpp"
+#include "Str.hpp"
+#include "File.hpp"
+#include "Indentor.hpp"
+#include "PrintStyle.hpp"
+
+namespace fs = boost::filesystem;
+using namespace ecf;
+using namespace std;
+using namespace boost;
+
+//==================================================================================
+Alias::Alias( const std::string& name )
+: Submittable(name)
+{
+ set_state_only(NState::QUEUED);
+}
+
+Alias::Alias()
+{
+ set_state_only(NState::QUEUED);
+}
+
+Alias::~Alias()
+{
+ if (!Ecf::server()) {
+ notify_delete();
+ }
+}
+
+alias_ptr Alias::create(const std::string& name)
+{
+ return boost::make_shared<Alias>( name );
+}
+
+bool Alias::operator==(const Alias& rhs) const
+{
+ return Submittable::operator==(rhs);
+}
+
+std::ostream& Alias::print(std::ostream& os) const
+{
+ Indentor in;
+ Indentor::indent(os) << "alias " << name();
+ if (!PrintStyle::defsStyle()) {
+ std::string st = write_state();
+ if (!st.empty()) os << " #" << st;
+ }
+ os << "\n";
+
+ Node::print(os);
+
+ // Generated variable are not persisted since they are created on demand
+ // There *NO* point in printing them they will always be empty
+ return os;
+}
+std::ostream& operator<<(std::ostream& os, const Alias& d) { return d.print(os); }
+
+void Alias::begin()
+{
+ Submittable::begin();
+}
+
+void Alias::requeue(bool resetRepeats, int clear_suspended_in_child_nodes,bool reset_next_time_slot)
+{
+ Submittable::requeue(resetRepeats,clear_suspended_in_child_nodes,reset_next_time_slot);
+}
+
+const std::string& Alias::debugType() const { return ecf::Str::ALIAS();}
+
+node_ptr Alias::removeChild(Node*)
+{
+ LOG_ASSERT(false,"");
+ return node_ptr();
+}
+
+bool Alias::addChild( node_ptr , size_t )
+{
+ LOG_ASSERT(false,"");
+ return false;
+}
+
+size_t Alias::child_position(const Node*) const
+{
+ return std::numeric_limits<std::size_t>::max();
+}
+
+bool Alias::isAddChildOk( Node* alias, std::string& errorMsg) const
+{
+ errorMsg += "Can not add children to a Alias";
+ return false;
+}
+
+void Alias::handleStateChange()
+{
+ /// Increment/decrement limits based on the current state
+ update_limits();
+
+ // Aliases are stand alone, they do no requeue or bubble up/down state changes
+ // i.e no requeue since they have no time dependencies, or repeat
+}
+
+const std::string& Alias::script_extension() const
+{
+ return File::USR_EXTN();
+}
+
+void Alias::collateChanges(DefsDelta& changes) const
+{
+ /// All changes to Alias should be on ONE compound_memento_ptr
+ compound_memento_ptr comp;
+ Submittable::incremental_changes(changes, comp);
+}
+
+void Alias::get_all_nodes(std::vector<node_ptr>& nodes) const
+{
+ nodes.push_back(non_const_this());
+}
+
+// Functions unique to aliases
+void Alias::add_alias_variable(const std::string& name, const std::string& value)
+{
+ if (name.empty()) {
+ throw std::runtime_error("Alias::add_alias_variable: Variable with empty name");
+ }
+
+ // The bool argument to variable, allows addition of Variable without name checking
+ addVariable( Variable(name,value,false));
+}
+
+node_ptr Alias::find_node_up_the_tree(const std::string& name) const
+{
+ Node* the_parent = parent();
+ if (the_parent) return the_parent->find_node_up_the_tree(name);
+ return node_ptr();
+}
+
diff --git a/ANode/src/Alias.hpp b/ANode/src/Alias.hpp
new file mode 100644
index 0000000..976be31
--- /dev/null
+++ b/ANode/src/Alias.hpp
@@ -0,0 +1,94 @@
+#ifndef ALIAS_HPP_
+#define ALIAS_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #17 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include "Submittable.hpp"
+
+class Alias : public Submittable {
+public:
+ Alias(const std::string& name);
+ Alias();
+ virtual ~Alias();
+
+ static alias_ptr create(const std::string& name);
+
+ std::ostream& print(std::ostream&) const;
+ bool operator==(const Alias& rhs) const;
+
+ /// Overridden to reset the try number
+ /// The tasks job can be invoked multiple times. For each invocation we want to preserve
+ /// the output. The try number is used in SMSJOB/SMSJOBOUT to preserve the output when
+ /// there are multiple runs. re-queue/begin() resets the try Number
+ virtual void begin();
+ virtual void requeue(bool resetRepeats, int clear_suspended_in_child_nodes, bool reset_next_time_slot);
+
+ virtual Suite* suite() const { return parent()->suite(); }
+ virtual Defs* defs() const { return (parent()) ? parent()->defs() : NULL;} // exposed to python hence check for NULL first
+ virtual Alias* isAlias() const { return const_cast<Alias*>(this);}
+ virtual Submittable* isSubmittable() const { return const_cast<Alias*>(this); }
+
+ virtual const std::string& debugType() const;
+
+ virtual node_ptr removeChild( Node* child);
+ virtual bool addChild( node_ptr child, size_t position = std::numeric_limits<std::size_t>::max());
+ virtual bool isAddChildOk( Node* child, std::string& errorMsg) const;
+
+ virtual const std::string& script_extension() const;
+
+ virtual void collateChanges(DefsDelta&) const;
+ void set_memento(const SubmittableMemento* m,std::vector<ecf::Aspect::Type>& aspects) { Submittable::set_memento(m,aspects); }
+
+ virtual node_ptr find_node_up_the_tree(const std::string& name) const;
+
+ // Pure node Functions that are not implemented for aliases
+ virtual node_ptr find_relative_node(const std::vector<std::string>&) {return node_ptr();}
+
+ virtual void get_all_nodes(std::vector<node_ptr>& nodes) const;
+
+// Functions unique to aliases
+ // Alias variable names by pass checking of valid names, allowing anything
+ void add_alias_variable(const std::string& name, const std::string& value);
+
+private:
+ virtual size_t child_position(const Node*) const;
+
+ /// Job creation checking is typically called from python API
+ /// This has been disabled for Aliases
+ virtual void check_job_creation( job_creation_ctrl_ptr) {}
+
+ // Overridden from Node to increment/decrement limits only
+ // i.e we do not update parent computed states for aliases
+ virtual void handleStateChange();
+
+ // Pure node Functions that are not implemented for aliases
+ virtual void accept(ecf::NodeTreeVisitor&){}
+ virtual void acceptVisitTraversor(ecf::NodeTreeVisitor&){}
+ virtual void get_all_tasks(std::vector<task_ptr>&) const {}
+ virtual void get_all_aliases(std::vector<alias_ptr>&) const {}
+ virtual void getAllNodes(std::vector<Node*>&) const {}
+ virtual void getAllTasks(std::vector<Task*>&) const {}
+ virtual void getAllSubmittables(std::vector<Submittable*>&) const {}
+ virtual void get_all_active_submittables(std::vector<Submittable*>&) const {}
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/) {
+ ar & boost::serialization::base_object<Submittable>(*this); // Serialise base class information
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, const Alias&);
+
+#endif
diff --git a/ANode/src/Aspect.hpp b/ANode/src/Aspect.hpp
new file mode 100644
index 0000000..f67e3d9
--- /dev/null
+++ b/ANode/src/Aspect.hpp
@@ -0,0 +1,42 @@
+#ifndef ASPECT_HPP_
+#define ASPECT_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//
+// This class is used to provide observers with more info regarding
+// whats changed. used as a part of the observer pattern
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+
+#include <boost/noncopyable.hpp>
+
+namespace ecf {
+
+class Aspect : private boost::noncopyable {
+public:
+ enum Type { NOT_DEFINED, ORDER, ADD_REMOVE_NODE, ADD_REMOVE_ATTR,
+ METER, EVENT, LABEL, LIMIT, STATE, DEFSTATUS, SUSPENDED,
+ SERVER_STATE, SERVER_VARIABLE, EXPR_TRIGGER, EXPR_COMPLETE, REPEAT,
+ NODE_VARIABLE, LATE, TODAY, TIME,DAY, CRON, DATE,
+ FLAG, SUBMITTABLE, SUITE_CLOCK, SUITE_BEGIN, SUITE_CALENDAR,
+ ALIAS_NUMBER
+ };
+
+private:
+ Aspect();
+};
+
+}
+
+#endif
diff --git a/ANode/src/ChildAttrs.cpp b/ANode/src/ChildAttrs.cpp
new file mode 100644
index 0000000..dd1a2a7
--- /dev/null
+++ b/ANode/src/ChildAttrs.cpp
@@ -0,0 +1,556 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #285 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <assert.h>
+
+#include "ChildAttrs.hpp"
+#include "Str.hpp"
+#include "Ecf.hpp"
+#include "Memento.hpp"
+
+using namespace ecf;
+using namespace std;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+void ChildAttrs::begin()
+{
+ for(size_t i = 0; i < meters_.size(); i++) { meters_[i].reset(); }
+ for(size_t i = 0; i < events_.size(); i++) { events_[i].reset(); }
+ for(size_t i = 0; i < labels_.size(); i++) { labels_[i].reset(); }
+}
+
+void ChildAttrs::requeue()
+{
+ for(size_t i = 0; i < meters_.size(); i++) { meters_[i].reset(); }
+ for(size_t i = 0; i < events_.size(); i++) { events_[i].reset(); }
+
+ // ECFLOW-195, only clear labels, if they are on Suites/Family not tasks(typically only specified on tasks)
+ if (node_ && node_->isNodeContainer()) {
+ for(size_t i = 0; i < labels_.size(); i++) { labels_[i].reset(); }
+ }
+}
+
+void ChildAttrs::requeue_labels()
+{
+ // ECFLOW-195, clear labels before a task is run.
+ for(size_t i = 0; i < labels_.size(); i++) { labels_[i].reset(); }
+}
+
+void ChildAttrs::clear()
+{
+ meters_.clear();
+ events_.clear();
+ labels_.clear();
+}
+
+bool ChildAttrs::set_event_used_in_trigger(const std::string& event_name_or_number)
+{
+ if (events_.empty()) {
+ return false;
+ }
+
+ // find by name first
+ size_t theSize = events_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ if (events_[i].name() == event_name_or_number) {
+ events_[i].usedInTrigger( true );
+ return true;
+ }
+ }
+
+ // Test for numeric, and then casting, is ****faster***** than relying on exception alone
+ if ( event_name_or_number.find_first_of( Str::NUMERIC(), 0 ) != std::string::npos ) {
+ try {
+ int eventNumber = boost::lexical_cast< int >( event_name_or_number );
+ for(size_t i = 0; i < theSize; i++) {
+ if (events_[i].number() == eventNumber) {
+ events_[i].usedInTrigger( true );
+ return true;;
+ }
+ }
+ }
+ catch ( boost::bad_lexical_cast&) {}
+ }
+ return false;
+}
+
+bool ChildAttrs::set_meter_used_in_trigger(const std::string& meter_name)
+{
+ size_t the_meter_size = meters_.size();
+ for(size_t i = 0; i < the_meter_size ; ++i) {
+ if (meters_[i].name() == meter_name ) {
+ meters_[i].usedInTrigger( true );
+ return true;
+ }
+ }
+ return false;
+}
+
+bool ChildAttrs::set_event( const std::string& event_name_or_number) {
+ BOOST_FOREACH(Event& e, events_) {
+ if (e.name_or_number() == event_name_or_number) {
+ e.set_value( true );
+ return true;
+ }
+ }
+ return false;
+}
+bool ChildAttrs::set_event(const std::string& event_name_or_number ,bool value)
+{
+ if (events_.empty()) {
+ return false;
+ }
+
+ // find by name first
+ size_t theSize = events_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ if (events_[i].name() == event_name_or_number) {
+ events_[i].set_value( value );
+ return true;
+ }
+ }
+
+ // Test for numeric, and then casting, is ****faster***** than relying on exception alone
+ if ( event_name_or_number.find_first_of( Str::NUMERIC(), 0 ) != std::string::npos ) {
+ try {
+ int eventNumber = boost::lexical_cast< int >( event_name_or_number );
+ for(size_t i = 0; i < theSize; i++) {
+ if (events_[i].number() == eventNumber) {
+ events_[i].set_value( value );
+ return true;;
+ }
+ }
+ }
+ catch ( boost::bad_lexical_cast&) {}
+ }
+ return false;
+}
+
+bool ChildAttrs::set_meter(const std::string& meter_name,int value)
+{
+ size_t the_meter_size = meters_.size();
+ for(size_t i = 0; i < the_meter_size ; ++i) {
+ if (meters_[i].name() == meter_name) {
+ meters_[i].set_value( value);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool ChildAttrs::clear_event(const std::string& event_name_or_number ){
+ BOOST_FOREACH(Event& e, events_) {
+ if (e.name_or_number() == event_name_or_number) {
+ e.set_value( false );
+ return true;
+ }
+ }
+ return false;
+}
+
+void ChildAttrs::changeLabel(const std::string& name,const std::string& value)
+{
+ size_t theSize = labels_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ if (labels_[i].name() == name) {
+ labels_[i].set_new_value( value );
+ return;
+ }
+ }
+ throw std::runtime_error("ChildAttrs::changeLabel: Could not find label " + name);
+}
+
+void ChildAttrs::changeEvent(const std::string& event_name_or_number,const std::string& setOrClear)
+{
+ bool value;
+ if (!setOrClear.empty()) {
+ if (setOrClear != Event::SET() && setOrClear != Event::CLEAR() ) {
+ throw std::runtime_error("ChildAttrs::changeEvent: Expected empty string, 'set' or 'clear' but found " + setOrClear + " for event " + event_name_or_number);
+ }
+ value = (setOrClear == Event::SET());
+ }
+ else value = true;
+
+ changeEvent(event_name_or_number,value);
+}
+void ChildAttrs::changeEvent(const std::string& event_name_or_number,bool value)
+{
+ if (set_event(event_name_or_number,value)) return;
+ throw std::runtime_error("ChildAttrs::changeEvent: Could not find event " + event_name_or_number);
+}
+
+void ChildAttrs::changeMeter(const std::string& meter_name,const std::string& value)
+{
+ int theValue = 0;
+ try {
+ theValue = boost::lexical_cast< int >( value );
+ }
+ catch ( boost::bad_lexical_cast& ) {
+ throw std::runtime_error( "ChildAttrs::changeMeter expected integer value but found " + value);
+ }
+ changeMeter(meter_name,theValue);
+}
+void ChildAttrs::changeMeter(const std::string& meter_name,int value)
+{
+ if (set_meter(meter_name,value)) return;
+ throw std::runtime_error("ChildAttrs::changeMeter: Could not find meter " + meter_name);
+}
+
+std::ostream& ChildAttrs::print(std::ostream& os) const
+{
+ BOOST_FOREACH(const Label& la, labels_ ) { la.print(os); }
+ BOOST_FOREACH(const Meter& m, meters_ ) { m.print(os); }
+ BOOST_FOREACH(const Event& e, events_ ) { e.print(os); }
+ return os;
+}
+
+bool ChildAttrs::operator==(const ChildAttrs& rhs) const
+{
+ if (labels_.size() != rhs.labels_.size()) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "ChildAttrs::operator== (labels_.size() != rhs.labels_.size()) " << node_->debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ for(unsigned i = 0; i < labels_.size(); ++i) {
+ if (labels_[i] != rhs.labels_[i]) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "ChildAttrs::operator== (labels_[i] != rhs.labels_[i]) " << node_->debugNodePath() << "\n";
+ std::cout << " lhs = " << labels_[i].dump() << "\n";
+ std::cout << " rhs = " << rhs.labels_[i].dump() << "\n";
+ }
+#endif
+ return false;
+ }
+ }
+
+ if (meters_.size() != rhs.meters_.size()) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "ChildAttrs::operator== (meters_.size() != rhs.meters_.size()) " << node_->debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ for(size_t i = 0; i < meters_.size(); ++i) {
+ if (!(meters_[i] == rhs.meters_[i] )) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "ChildAttrs::operator== (!(meters_[i] == rhs.meters_[i] )) " << node_->debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ }
+ if (events_.size() != rhs.events_.size()) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "ChildAttrs::operator== (events_.size() != rhs.events_.size()) " << node_->debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ for(size_t i = 0; i < events_.size(); ++i) {
+ if (!(events_[i] == rhs.events_[i] )) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "ChildAttrs::operator== (!(events_[i] == rhs.events_[i] )) " << node_->debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ }
+ return true;
+}
+
+bool ChildAttrs::getLabelValue(const std::string& labelName, std::string& value) const
+{
+ size_t theSize = labels_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ if (labels_[i].name() == labelName) {
+ if (!(labels_[i].new_value().empty())) value = labels_[i].new_value();
+ else value = labels_[i].value();
+ return true;
+ }
+ }
+ return false;
+}
+
+bool ChildAttrs::getLabelNewValue(const std::string& labelName, std::string& value) const
+{
+ size_t theSize = labels_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ if (labels_[i].name() == labelName) {
+ value = labels_[i].new_value();
+ return true;
+ }
+ }
+ return false;
+}
+
+void ChildAttrs::addLabel( const Label& l)
+{
+ if (findLabel(l.name())) {
+ std::stringstream ss;
+ ss << "Add Label failed: Duplicate label of name '" << l.name() << "' already exist for node " << node_->debugNodePath();
+ throw std::runtime_error( ss.str() );
+ }
+ labels_.push_back( l );
+ node_->state_change_no_ = Ecf::incr_state_change_no();
+}
+
+void ChildAttrs::addMeter( const Meter& m)
+{
+ const Meter& meter = findMeter(m.name());
+ if (!meter.empty()) {
+ std::stringstream ss;
+ ss << "Add Meter failed: Duplicate Meter of name '" << m.name() << "' already exist for node " << node_->debugNodePath();
+ throw std::runtime_error( ss.str() );
+ }
+ meters_.push_back( m );
+ node_->state_change_no_ = Ecf::incr_state_change_no();
+}
+
+void ChildAttrs::addEvent( const Event& e)
+{
+ const Event& event = findEvent(e);
+ if (!event.empty()) {
+ std::stringstream ss;
+ ss << "Add Event failed: Duplicate Event of name '" << e.name_or_number() << "' already exist for node " << node_->debugNodePath();
+ throw std::runtime_error( ss.str() );
+ }
+ events_.push_back( e );
+ node_->state_change_no_ = Ecf::incr_state_change_no();
+}
+
+
+void ChildAttrs::deleteEvent(const std::string& name)
+{
+ if (name.empty()) {
+ events_.clear();
+ node_->state_change_no_ = Ecf::incr_state_change_no();
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "ChildAttrs::deleteEvent\n";
+#endif
+ return;
+ }
+
+ size_t theSize = events_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ if (events_[i].name_or_number() == name) {
+ events_.erase( events_.begin() + i );
+ node_->state_change_no_ = Ecf::incr_state_change_no();
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "ChildAttrs::deleteEvent\n";
+#endif
+ return;
+ }
+ }
+ throw std::runtime_error("ChildAttrs::deleteEvent: Can not find event: " + name);
+}
+
+void ChildAttrs::deleteMeter(const std::string& name)
+{
+ if (name.empty()) {
+ meters_.clear();
+ node_->state_change_no_ = Ecf::incr_state_change_no();
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Expression::clearFree()\n";
+#endif
+ return;
+ }
+
+ size_t theSize = meters_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ if (meters_[i].name() == name) {
+ meters_.erase( meters_.begin() + i );
+ node_->state_change_no_ = Ecf::incr_state_change_no();
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Expression::clearFree()\n";
+#endif
+ return;
+ }
+ }
+ throw std::runtime_error("ChildAttrs::deleteMeter: Can not find meter: " + name);
+}
+
+void ChildAttrs::deleteLabel(const std::string& name)
+{
+ if (name.empty()) {
+ labels_.clear();
+ node_->state_change_no_ = Ecf::incr_state_change_no();
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "ChildAttrs::deleteLabel\n";
+#endif
+ return;
+ }
+
+ size_t theSize = labels_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ if (labels_[i].name() == name) {
+ labels_.erase( labels_.begin() + i );
+ node_->state_change_no_ = Ecf::incr_state_change_no();
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "ChildAttrs::deleteLabel\n";
+#endif
+ return;
+ }
+ }
+ throw std::runtime_error("ChildAttrs::deleteLabel: Can not find label: " + name);
+}
+
+
+const Event& ChildAttrs::findEvent(const Event& theEvent) const
+{
+ size_t theSize = events_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ if (events_[i] == theEvent) {
+ return events_[i];
+ }
+ }
+ return Event::EMPTY();
+}
+
+const Event& ChildAttrs::findEventByNumber(int number) const
+{
+ size_t theSize = events_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ if (events_[i].number() == number) {
+ return events_[i];
+ }
+ }
+ return Event::EMPTY();
+}
+
+const Event& ChildAttrs::findEventByName( const std::string& event_name) const
+{
+ size_t theSize = events_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ if (events_[i].name() == event_name) {
+ return events_[i];
+ }
+ }
+ return Event::EMPTY();
+}
+
+const Event& ChildAttrs::findEventByNameOrNumber( const std::string& theName) const
+{
+ const Event& event = findEventByName(theName);
+ if (!event.empty()) {
+ return event;
+ }
+
+ // Test for numeric, and then casting, is ****faster***** than relying on exception alone
+ if ( theName.find_first_of( Str::NUMERIC(), 0 ) != std::string::npos ) {
+ try {
+ int eventNumber = boost::lexical_cast< int >( theName );
+ return findEventByNumber(eventNumber);
+ }
+ catch ( boost::bad_lexical_cast&) {}
+ }
+ return Event::EMPTY();
+}
+
+
+
+const Meter& ChildAttrs::findMeter(const std::string& name) const
+{
+ size_t theSize = meters_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ if (meters_[i].name() == name) {
+ return meters_[i];
+ }
+ }
+ return Meter::EMPTY();
+}
+
+Meter& ChildAttrs::find_meter(const std::string& name)
+{
+ size_t theSize = meters_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ if (meters_[i].name() == name) {
+ return meters_[i];
+ }
+ }
+ return const_cast<Meter&>(Meter::EMPTY());
+}
+
+bool ChildAttrs::findLabel(const std::string& name) const
+{
+ size_t theSize = labels_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ if (labels_[i].name() == name) {
+ return true;
+ }
+ }
+ return false;
+}
+
+const Label& ChildAttrs::find_label(const std::string& name) const
+{
+ size_t theSize = labels_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ if (labels_[i].name() == name) {
+ return labels_[i];
+ }
+ }
+ return Label::EMPTY();
+}
+
+
+void ChildAttrs::set_memento( const NodeEventMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+
+#ifdef DEBUG_MEMENTO
+ std::cout << "ChildAttrs::set_memento(const NodeEventMemento* memento) " << node_->debugNodePath() << "\n";
+#endif
+
+ if (set_event(memento->event_.name_or_number(), memento->event_.value())) {
+ aspects.push_back(ecf::Aspect::EVENT);
+ return;
+ }
+ addEvent( memento->event_);
+}
+
+void ChildAttrs::set_memento( const NodeMeterMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+
+#ifdef DEBUG_MEMENTO
+ std::cout << "ChildAttrs::set_memento(const NodeMeterMemento* memento) " << node_->debugNodePath() << "\n";
+#endif
+
+ if (set_meter(memento->meter_.name(), memento->meter_.value())) {
+ aspects.push_back(ecf::Aspect::METER);
+ return;
+ }
+ addMeter(memento->meter_);
+}
+
+void ChildAttrs::set_memento( const NodeLabelMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+
+#ifdef DEBUG_MEMENTO
+ std::cout << "ChildAttrs::set_memento(const NodeLabelMemento* memento) " << node_->debugNodePath() << "\n";
+#endif
+
+ size_t theSize = labels_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ if (labels_[i].name() == memento->label_.name()) {
+ labels_[i] = memento->label_;
+ aspects.push_back(ecf::Aspect::LABEL);
+ return;
+ }
+ }
+ addLabel(memento->label_);
+}
diff --git a/ANode/src/ChildAttrs.hpp b/ANode/src/ChildAttrs.hpp
new file mode 100644
index 0000000..4776aa9
--- /dev/null
+++ b/ANode/src/ChildAttrs.hpp
@@ -0,0 +1,135 @@
+#ifndef CHILD_ATTRS_HPP_
+#define CHILD_ATTRS_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #234 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <ostream>
+#include <vector>
+
+#include <boost/noncopyable.hpp>
+#include <boost/serialization/base_object.hpp>
+#include <boost/serialization/utility.hpp>
+
+#include "NodeAttr.hpp"
+#include "NodeFwd.hpp"
+#include "Aspect.hpp"
+
+class ChildAttrs : private boost::noncopyable {
+public:
+ ChildAttrs(Node* node) : node_(node) {}
+ ChildAttrs() : node_(NULL) {}
+ ~ChildAttrs() {}
+
+ // needed by node serialisation
+ void set_node(Node* n) { node_ = n; }
+
+ void begin();
+ void requeue();
+ void requeue_labels();
+
+ // standard functions: ==============================================
+ std::ostream& print(std::ostream&) const;
+ bool operator==(const ChildAttrs& rhs) const;
+
+// state related functions: ========================================
+
+ // Access functions: ======================================================
+ const std::vector<Meter>& meters() const { return meters_;}
+ const std::vector<Event>& events() const { return events_;}
+ const std::vector<Label>& labels() const { return labels_;}
+
+ // Add functions: ===============================================================
+ void addEvent( const Event& ); // will throw std::runtime_error if duplicate
+ void addMeter( const Meter& ); // will throw std::runtime_error if duplicate
+ void addLabel( const Label& ); // will throw std::runtime_error if duplicate
+
+ // Delete functions: can throw std::runtime_error ===================================
+ // if name argument is empty, delete all attributes of that type
+ // Can throw std::runtime_error of the attribute can not be found
+ void deleteEvent(const std::string& name);
+ void deleteMeter(const std::string& name);
+ void deleteLabel(const std::string& name);
+
+ // Change functions: ================================================================
+ /// returns true the change was made else false, Can throw std::runtime_error for parse errors
+ void changeEvent(const std::string& name,const std::string& setOrClear = "");
+ void changeEvent(const std::string& name,bool value);
+ void changeMeter(const std::string& name,const std::string& value);
+ void changeMeter(const std::string& name,int value);
+ void changeLabel(const std::string& name,const std::string& value);
+
+ bool set_meter(const std::string& name,int value); // does not throw if meter not found
+ bool set_event(const std::string& name,bool value); // does not throw if event not found
+
+ // Used in the force cmd
+ bool set_event( const std::string& event_name_or_number);
+ bool clear_event( const std::string& event_name_or_number);
+
+ // mementos functions:
+ void set_memento(const NodeEventMemento*,std::vector<ecf::Aspect::Type>& aspects );
+ void set_memento(const NodeMeterMemento*,std::vector<ecf::Aspect::Type>& aspects );
+ void set_memento(const NodeLabelMemento*,std::vector<ecf::Aspect::Type>& aspects );
+
+ // Find functions: ============================================================
+ bool findLabel(const std::string& name) const;
+ const Label& find_label(const std::string& name) const;
+ const Meter& findMeter(const std::string& name) const;
+ Meter& find_meter(const std::string& name);
+ const Event& findEvent(const Event&) const;
+ const Event& findEventByNameOrNumber( const std::string& name) const;
+ bool getLabelValue(const std::string& labelName, std::string& value) const;
+ bool getLabelNewValue(const std::string& labelName, std::string& value) const;
+
+private:
+
+ const Event& findEventByNumber(int number) const;
+ const Event& findEventByName( const std::string& name) const;
+ bool set_meter_used_in_trigger(const std::string& name);
+ bool set_event_used_in_trigger(const std::string& name);
+
+private: // allow simulator access
+ std::vector<Meter>& ref_meters() { return meters_;} // allow simulator set meter value
+ std::vector<Event>& ref_events() { return events_;} // allow simulator set event value
+
+private: // All mementos access
+ void clear(); /// Clear *ALL* internal attributes
+
+private: /// For use by python interface,
+ friend class Node;
+ std::vector<Meter>::const_iterator meter_begin() const { return meters_.begin();}
+ std::vector<Meter>::const_iterator meter_end() const { return meters_.end();}
+ std::vector<Event>::const_iterator event_begin() const { return events_.begin();}
+ std::vector<Event>::const_iterator event_end() const { return events_.end();}
+ std::vector<Label>::const_iterator label_begin() const { return labels_.begin();}
+ std::vector<Label>::const_iterator label_end() const { return labels_.end();}
+
+private:
+ std::vector<Meter> meters_;
+ std::vector<Event> events_;
+ std::vector<Label> labels_;
+
+private:
+ Node* node_; // *NOT* persisted must be set by the parent class
+
+private:
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/) {
+ ar & meters_;
+ ar & events_;
+ ar & labels_;
+ }
+};
+#endif
diff --git a/ANode/src/ClientSuiteMgr.cpp b/ANode/src/ClientSuiteMgr.cpp
new file mode 100644
index 0000000..281b1bf
--- /dev/null
+++ b/ANode/src/ClientSuiteMgr.cpp
@@ -0,0 +1,280 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #23 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/bind.hpp>
+
+#include "ClientSuiteMgr.hpp"
+#include "Defs.hpp"
+#include "DefsDelta.hpp"
+#include "Ecf.hpp"
+
+using namespace ecf;
+using namespace std;
+
+//#define DEBUG_HANDLE 1
+
+ClientSuiteMgr::ClientSuiteMgr(Defs* defs) : defs_(defs) {}
+
+unsigned int ClientSuiteMgr::create_client_suite(bool auto_add_new_suites, const std::vector<std::string>& suites, const std::string& the_user)
+{
+ // The handle must be unique. If there are holes, re-use them, i.e
+ // 1,2,3,4,5 user deletes handle 3 ===> 1,2,4,5
+ // Hence re-use handle 3
+ bool found_hole = false;
+ unsigned int new_handle = 1;
+ for(size_t i = 0; i < clientSuites_.size(); i++) {
+ if (clientSuites_[i].handle() == new_handle) {
+ new_handle++;
+ }
+ else {
+ found_hole = true;
+ break;
+ }
+ }
+ if (!found_hole) new_handle = clientSuites_.size() + 1;
+
+ clientSuites_.push_back( ClientSuites(defs_,new_handle,auto_add_new_suites,suites,the_user) );
+
+ // aesthetics only
+ std::sort(clientSuites_.begin(),clientSuites_.end(),
+ boost::bind(std::less<unsigned int>(),
+ boost::bind(&ClientSuites::handle,_1),
+ boost::bind(&ClientSuites::handle,_2)));
+
+ // make sure all suites in ClientSuites are in same order as Defs suites
+ update_suite_order();
+
+#ifdef DEBUG_HANDLE
+ std::cout << "ClientSuiteMgr::create_client_suite: " << dump() << "\n";
+#endif
+ return new_handle;
+}
+
+void ClientSuiteMgr::remove_client_suite(unsigned int client_handle)
+{
+ size_t client_suites_size = clientSuites_.size();
+ for(size_t i = 0; i < client_suites_size; i++) {
+ if (clientSuites_[i].handle() == client_handle) {
+ clientSuites_.erase( clientSuites_.begin() + i);
+#ifdef DEBUG_HANDLE
+ std::cout << "ClientSuiteMgr::remove_client_suite: handle(" << client_handle << ") " << dump() << "\n";
+#endif
+ return;
+ }
+ }
+ std::stringstream ss; ss << "ClientSuiteMgr::remove_registered_suite: handle(" << client_handle << ") does not exist";
+ throw std::runtime_error(ss.str());
+}
+
+void ClientSuiteMgr::remove_client_suites(const std::string& user_to_drop)
+{
+ bool did_drop = false;
+ for(std::vector<ecf::ClientSuites>::iterator i = clientSuites_.begin(); i!= clientSuites_.end(); ++i) {
+ if ((*i).user() == user_to_drop) {
+ did_drop = true;
+ clientSuites_.erase(i--);
+ }
+ }
+
+ if (!did_drop) {
+ std::stringstream ss; ss << "ClientSuiteMgr::remove_registered_suites: user(" << user_to_drop << ") has no registered handles";
+ throw std::runtime_error(ss.str());
+ }
+
+#ifdef DEBUG_HANDLE
+ std::cout << "ClientSuiteMgr::remove_client_suites: user_to_drop(" << user_to_drop << ") " << dump() << "\n";
+#endif
+}
+
+void ClientSuiteMgr::add_suites(unsigned int client_handle, const std::vector<std::string>& suites)
+{
+ size_t client_suites_size = clientSuites_.size();
+ for(size_t i = 0; i < client_suites_size; i++) {
+ if (clientSuites_[i].handle() == client_handle) {
+ for(size_t s = 0; s < suites.size(); s++) {
+ clientSuites_[i].add_suite(suites[s]);
+ }
+#ifdef DEBUG_HANDLE
+ std::cout << "ClientSuiteMgr::add_suites: client_handle(" << client_handle << ") " << dump() << "\n";
+#endif
+ update_suite_order();
+ return;
+ }
+ }
+ std::stringstream ss; ss << "ClientSuiteMgr::add_suites: handle(" << client_handle << ") does not exist";
+ throw std::runtime_error(ss.str());
+}
+
+
+void ClientSuiteMgr::remove_suites(unsigned int client_handle, const std::vector<std::string>& suites)
+{
+ size_t client_suites_size = clientSuites_.size();
+ for(size_t i = 0; i < client_suites_size; i++) {
+ if (clientSuites_[i].handle() == client_handle) {
+ for(size_t s = 0; s < suites.size(); s++) {
+ clientSuites_[i].remove_suite(suites[s]);
+ }
+#ifdef DEBUG_HANDLE
+ std::cout << "ClientSuiteMgr::remove_suites: client_handle(" << client_handle << ") " << dump() << "\n";
+#endif
+ return;
+ }
+ }
+ std::stringstream ss; ss << "ClientSuiteMgr::remove_suites: handle(" << client_handle << ") does not exist";
+ throw std::runtime_error(ss.str());
+}
+
+
+void ClientSuiteMgr::auto_add_new_suites(unsigned int client_handle, bool auto_add_new_suites)
+{
+ size_t client_suites_size = clientSuites_.size();
+ for(size_t i = 0; i < client_suites_size; i++) {
+ if (clientSuites_[i].handle() == client_handle) {
+ clientSuites_[i].add_new_suite(auto_add_new_suites);
+
+#ifdef DEBUG_HANDLE
+ std::cout << "ClientSuiteMgr::auto_add_new_suites: client_handle(" << client_handle << ") auto_add_new_suites(" << auto_add_new_suites << ") " << dump() << "\n";
+#endif
+ return;
+ }
+ }
+ std::stringstream ss; ss << "ClientSuiteMgr::auto_add_new_suites: handle(" << client_handle << ") does not exist";
+ throw std::runtime_error(ss.str());
+}
+
+bool ClientSuiteMgr::valid_handle(unsigned int client_handle) const
+{
+ size_t client_suites_size = clientSuites_.size();
+ for(size_t i = 0; i < client_suites_size; i++) {
+ if (clientSuites_[i].handle() == client_handle) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/// returns true if the handle was created, or suites added or removed from it
+bool ClientSuiteMgr::handle_changed( unsigned int client_handle )
+{
+ size_t client_suites_size = clientSuites_.size();
+ for(size_t i = 0; i < client_suites_size; i++) {
+ if (clientSuites_[i].handle() == client_handle) {
+ return clientSuites_[i].handle_changed();
+ }
+ }
+ return false;
+}
+
+void ClientSuiteMgr::collateChanges(unsigned int client_handle, DefsDelta& changes) const
+{
+ // collate changes over the suites that match the client handle
+ size_t client_suites_size = clientSuites_.size();
+ for(size_t i = 0; i < client_suites_size; i++) {
+ if ( clientSuites_[i].handle() == client_handle) {
+ clientSuites_[i].collateChanges(changes);
+ return;
+ }
+ }
+}
+
+void ClientSuiteMgr::suites(unsigned int client_handle, std::vector<std::string>& names) const
+{
+ size_t client_suites_size = clientSuites_.size();
+ for(size_t i = 0; i < client_suites_size; i++) {
+ if ( clientSuites_[i].handle() == client_handle) {
+ clientSuites_[i].suites(names);
+ return;
+ }
+ }
+}
+
+defs_ptr ClientSuiteMgr::create_defs(unsigned int client_handle, defs_ptr server_defs) const
+{
+ size_t client_suites_size = clientSuites_.size();
+ for(size_t i = 0; i < client_suites_size; i++) {
+ if (clientSuites_[i].handle() == client_handle) {
+ return clientSuites_[i].create_defs(server_defs);
+ }
+ }
+ return defs_ptr();
+}
+
+void ClientSuiteMgr::max_change_no(
+ unsigned int client_handle,
+ unsigned int& max_state_change_no ,
+ unsigned int& max_modify_change_no)
+{
+ size_t client_suites_size = clientSuites_.size();
+ for(size_t i = 0; i < client_suites_size; i++) {
+ if (clientSuites_[i].handle() == client_handle) {
+ clientSuites_[i].max_change_no(max_state_change_no,max_modify_change_no);
+ return;
+ }
+ }
+ std::stringstream ss; ss << "ClientSuiteMgr::max_change_no: handle(" << client_handle << ") does not exist in server. Server may have died? Please re-register suites";
+ throw std::runtime_error(ss.str());
+}
+
+
+void ClientSuiteMgr::suite_added_in_defs(suite_ptr suite)
+{
+ size_t client_suites_size = clientSuites_.size();
+ for(size_t i = 0; i < client_suites_size; i++) {
+ clientSuites_[i].suite_added_in_defs(suite);
+ clientSuites_[i].update_suite_order();
+ }
+}
+
+void ClientSuiteMgr::suite_deleted_in_defs(suite_ptr suite)
+{
+ size_t client_suites_size = clientSuites_.size();
+ for(size_t i = 0; i < client_suites_size; i++) {
+ clientSuites_[i].suite_deleted_in_defs(suite);
+ }
+}
+
+void ClientSuiteMgr::update_suite_order()
+{
+ size_t client_suites_size = clientSuites_.size();
+ for(size_t i = 0; i < client_suites_size; i++) {
+ clientSuites_[i].update_suite_order();
+ }
+}
+
+
+std::string ClientSuiteMgr::dump_max_change_no() const
+{
+ std::stringstream ss;
+ ss << "ClientSuiteMgr::dump_max_change_no: ECF:(" << Ecf::state_change_no() << "," << Ecf::modify_change_no() << ")\n";
+ size_t client_suites_size = clientSuites_.size();
+ for(size_t i = 0; i < client_suites_size; i++) {
+ unsigned int max_state_change_no = 0;
+ unsigned int max_modify_change_no = 0;
+ clientSuites_[i].max_change_no(max_state_change_no,max_modify_change_no);
+ ss << "handle: " << clientSuites_[i].handle() << " max(" << max_state_change_no << "," << max_modify_change_no << ")\n";
+ }
+ return ss.str();
+}
+
+/// For debug dumps
+std::string ClientSuiteMgr::dump() const
+{
+ size_t client_suites_size = clientSuites_.size();
+ std::stringstream ss;
+ ss << "ECF:(" << Ecf::state_change_no() << "," << Ecf::modify_change_no() << ") clientSuites_.size(" << client_suites_size << ")\n";
+ for(size_t i = 0; i < client_suites_size; i++) {
+ ss << clientSuites_[i].dump() << "\n";
+ }
+ return ss.str();
+}
diff --git a/ANode/src/ClientSuiteMgr.hpp b/ANode/src/ClientSuiteMgr.hpp
new file mode 100644
index 0000000..f63458f
--- /dev/null
+++ b/ANode/src/ClientSuiteMgr.hpp
@@ -0,0 +1,118 @@
+#ifndef CLIENT_SUITES_MGR_HPP_
+#define CLIENT_SUITES_MGR_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #24 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//
+// The client may only want to view a small subset of the suites available
+// in a defs file. This class manages the client handles
+//
+// Users are allowed to register interest in suite that have not yet been added
+// This will only work provided we have a definition
+//
+// Only handle with value > 0 are valid. This is because sync() and news() command
+// take a client_handle. By reserving a client handle of zero, we can sync with the
+// full defs.
+//
+// ***************************************************************************
+// Note: Change of suite order is handled by OrderMemento
+// and *NOT* by the ClientSuiteMgr, however whenever suites are
+// registered and added/deleted:
+// then:
+// defs_ptr create_defs(unsigned int client_handle) const;
+//
+// Will return the suites in the same order as the defs
+// ****************************************************************************
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <boost/noncopyable.hpp>
+#include "ClientSuites.hpp"
+class DefsDelta;
+
+class ClientSuiteMgr : private boost::noncopyable {
+public:
+ ClientSuiteMgr(Defs*);
+
+ /// Create a client suite, and return the handle associated with the created object
+ unsigned int create_client_suite(bool auto_add_new_suites, const std::vector<std::string>& suites, const std::string& user);
+
+
+ /// These function can throw std::runtime_error if the handle can not be found
+ void remove_client_suite(unsigned int client_handle);
+ void remove_client_suites(const std::string& user_to_drop);
+ void add_suites(unsigned int client_handle, const std::vector<std::string>& suites);
+ void remove_suites(unsigned int client_handle, const std::vector<std::string>& suites);
+ void auto_add_new_suites(unsigned int client_handle, bool auto_add_new_suites);
+
+ /// Return true if the input handle is valid
+ bool valid_handle(unsigned int client_handle) const;
+
+ /// returns true if the handle was created, or suites added or removed from it
+ /// The handle change flag is reset when create_defs is called
+ bool handle_changed( unsigned int client_handle );
+
+
+ /// Collect all the state changes, so that only small subset is returned to client
+ /// When nodes are added/deleted we use the modify_change_no_, in this case
+ /// the whole defs is returned. Both integers are returned back to the client
+ /// so that, the client then sends the integers back to server, so we can determine
+ /// what's changed.
+ void collateChanges(unsigned int client_handle,DefsDelta&) const;
+
+
+ // Only return the defs state and suites that the client has registered in the client handle
+ // *HOWEVER* if the client has registered all the suites, just return the server defs
+ // *with* the updated change numbers
+ // *OTHERWISE*
+ /// This will also compute the **maximum** state and modify change numbers over
+ /// the suites managed by the client handle.
+ /// and then set it on the newly created defs.
+ /// It also takes special precaution *NOT* to change Ecf::state_change_no() and Ecf::modify_change_no()
+ /// This will clear the handle_changed flag
+ defs_ptr create_defs(unsigned int client_handle, defs_ptr server_defs) const;
+
+ /// Used to determine the change, will throw if handle not found
+ void max_change_no(unsigned int client_handle,unsigned int& max_state_change_no , unsigned int& max_modify_change_no);
+
+ /// Accessor
+ const std::vector<ecf::ClientSuites>& clientSuites() const { return clientSuites_;}
+
+ /// returns the list of suites associated with a handle, Used by ecFlowview
+ void suites(unsigned int client_handle, std::vector<std::string>& names) const;
+
+ /// A suite is being added in the definition.
+ /// If the suite was previously registered *UPDATE* its suite_ptr
+ /// Otherwise if any ClientSuites registered for automatic inclusion of new suite, add them in
+ void suite_added_in_defs(suite_ptr);
+
+ /// The suite is being deleted in the definition, reset the suite_ptr
+ /// Deleted suites STAY registered, until explicitly dropped.
+ void suite_deleted_in_defs(suite_ptr);
+
+ /// Update suites to be in same order as Defs.
+ void update_suite_order();
+
+ /// remove all client Suites
+ void clear() { clientSuites_.clear(); }
+
+ /// Returns a string which has the max state change and modify numbers for each handle
+ std::string dump_max_change_no() const;
+
+ /// For debug dumps
+ std::string dump() const;
+
+private:
+ std::vector<ecf::ClientSuites> clientSuites_;
+ Defs* defs_;
+};
+#endif
diff --git a/ANode/src/ClientSuites.cpp b/ANode/src/ClientSuites.cpp
new file mode 100644
index 0000000..b7caddb
--- /dev/null
+++ b/ANode/src/ClientSuites.cpp
@@ -0,0 +1,332 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #35 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <boost/bind.hpp>
+
+#include "ClientSuites.hpp"
+#include "Suite.hpp"
+#include "Defs.hpp"
+#include "DefsDelta.hpp"
+#include "Ecf.hpp"
+
+//#define DEBUG_ME 1
+
+namespace ecf {
+
+ClientSuites::ClientSuites(Defs* defs,unsigned int handle, bool auto_add_new_suites, const std::vector<std::string>& suites,const std::string& user)
+: defs_(defs),
+ handle_(handle),
+ state_change_no_(0),
+ modify_change_no_(0),
+ auto_add_new_suites_(auto_add_new_suites),
+ handle_changed_(false),
+ user_(user)
+{
+ BOOST_FOREACH(const std::string& s, suites) {
+ add_suite(s);
+ }
+}
+
+void ClientSuites::add_suite(const std::string& s)
+{
+ suite_ptr suite = defs_->findSuite(s);
+ if (suite.get()) {
+ add_suite(suite);
+ }
+ else {
+ std::vector<HSuite>::iterator i = find_suite(s);
+ if (i != suites_.end()) {
+ (*i).weak_suite_ptr_ = weak_suite_ptr();
+ }
+ else {
+ suites_.push_back( HSuite(s) );
+ }
+ }
+}
+
+void ClientSuites::add_suite(suite_ptr suite)
+{
+ if (suite.get()) {
+
+ // *IMPORTANT* update weak_suite_ptr_
+ std::vector<HSuite>::iterator i = find_suite(suite->name());
+ if (i != suites_.end()) {
+ (*i).weak_suite_ptr_ = weak_suite_ptr(suite);
+ }
+ else {
+ suites_.push_back( HSuite(suite->name(),weak_suite_ptr(suite)) );
+ }
+ handle_changed_ = true;
+
+#ifdef DEBUG_ME
+ i = suites_.find_suite(suite->name());
+ assert(i != suites_.end());
+ assert((*i).weak_suite_ptr_.lock().get());
+#endif
+ }
+}
+
+void ClientSuites::remove_suite(const std::string& s)
+{
+ std::vector<HSuite>::iterator i = find_suite(s);
+ if (i != suites_.end()) {
+ if ( (*i).weak_suite_ptr_.lock().get() ) {
+ handle_changed_ = true;
+ }
+ suites_.erase(i);
+ }
+}
+
+bool ClientSuites::remove_suite(suite_ptr suite)
+{
+ if (suite.get()) {
+ std::vector<HSuite>::iterator i = find_suite(suite->name());
+ if (i != suites_.end()) {
+ handle_changed_ = true;
+ suites_.erase(i);
+ return true;
+ }
+ }
+ return false;
+}
+
+
+void ClientSuites::suite_added_in_defs(suite_ptr suite)
+{
+ if (auto_add_new_suites_) add_suite(suite);
+ else {
+ // *IF* and *ONLY IF* the suite was previously registered added, *UPDATE* its suite_ptr
+ std::vector<HSuite>::iterator i = find_suite(suite->name());
+ if (i != suites_.end()) {
+ // previously registered suite, update
+ add_suite(suite);
+ }
+ }
+}
+
+void ClientSuites::suite_deleted_in_defs(suite_ptr suite)
+{
+ // Deleted suites are *NOT* automatically removed
+ // They have to be moved explicitly by the user. Reset to weak ptr
+ if (suite.get()) {
+ std::vector<HSuite>::iterator i = find_suite(suite->name());
+ if (i != suites_.end()) {
+ handle_changed_ = true;
+ modify_change_no_ = Ecf::modify_change_no(); // need to pass back to client
+ (*i).weak_suite_ptr_ = weak_suite_ptr(); // reset suite ptr, not strictly necessary
+ }
+ }
+}
+
+void ClientSuites::collateChanges(DefsDelta& changes) const
+{
+ BOOST_FOREACH(const HSuite& s, suites_) {
+ suite_ptr suite = s.weak_suite_ptr_.lock();
+ if (suite.get()) {
+ if (suite->state_change_no() > changes.client_state_change_no()) {
+ suite->collateChanges( changes );
+ }
+ }
+ }
+}
+
+defs_ptr ClientSuites::create_defs(defs_ptr server_defs) const
+{
+ /// Clear handle changed, so we can detect suites added or removed for this handle
+ handle_changed_ = false;
+
+ // If the user has registered *ALL* the suites just return the server defs
+ std::vector<HSuite>::const_iterator suites_end = suites_.end();
+ if (suites_.size() == server_defs->suiteVec().size()) {
+ size_t real_suite_count = 0;
+ for(std::vector<HSuite>::const_iterator i = suites_.begin(); i != suites_end; ++i) {
+ suite_ptr suite = (*i).weak_suite_ptr_.lock();
+ if (suite.get()) real_suite_count++;
+ }
+ if ( real_suite_count == server_defs->suiteVec().size()) {
+
+ server_defs->set_state_change_no( Ecf::state_change_no() );
+ server_defs->set_modify_change_no( Ecf::modify_change_no() );
+
+ // Update local modify_change_no_ *AND* state_change_no_
+ // ***** Note: Otherwise NewsCmd which computes change numbers over
+ // ***** registered suites will not be correct. causing unnecessary sync's
+ modify_change_no_ = Ecf::modify_change_no();
+ state_change_no_ = Ecf::state_change_no();
+ return server_defs;
+ }
+ }
+
+
+ // CREATE NEW DEFS, using the registered suites
+ //
+ // *** We do not use local state_change_no_. That is used ONLY when all suites ***
+ // *** are registered. ***
+ //
+ // add_suite() below will incremented the modify_change_no.
+ // We don't want to do this, as change for suites *not in* the our handle will get skewed
+ // This class ensure that any changes made are reset to their original values
+ EcfPreserveChangeNo preserveChangeNo;
+
+ // Create defs to be sent to the client, with the registered suites.
+ defs_ptr newly_created_defs = Defs::create();
+ {
+ // Initialise the defs state. We need to reflect the real state.
+ newly_created_defs->set_state( server_defs->state() );
+
+ // Initialise the server state
+ newly_created_defs->set_server().set_state( server_defs->server().get_state() );
+ newly_created_defs->set_server().set_user_variables( server_defs->server().user_variables() );
+ newly_created_defs->set_server().set_server_variables( server_defs->server().server_variables() );
+ }
+
+
+ // Store the state/modify change number to the newly created defs *over* the objects that have changed
+ unsigned int the_max_state_change_no = server_defs->defs_only_max_state_change_no();
+ unsigned int the_max_modify_change_no = 0;
+
+ // Handle suites that get deleted. Need a full sync
+ the_max_modify_change_no = std::max( the_max_modify_change_no, modify_change_no_ );
+
+ // Suites should already be in order
+ for(std::vector<HSuite>::const_iterator i = suites_.begin(); i != suites_end; ++i) {
+ suite_ptr suite = (*i).weak_suite_ptr_.lock();
+ if (suite.get()) {
+
+ // Preserve the change/modify numbers, as these will updated on the suite, by addSuite() below
+ unsigned int suite_state_change_no = suite->state_change_no();
+ unsigned int suite_modify_change_no = suite->modify_change_no();
+
+ the_max_state_change_no = std::max( the_max_state_change_no, suite_state_change_no );
+ the_max_modify_change_no = std::max( the_max_modify_change_no, suite_modify_change_no );
+
+ // To avoid copying the suites, we will just add the suites, to the newly created defs
+ // However this presents a problem with the suites defs pointer. To avoid corrupting
+ // the server, we must reset the defs pointer.
+ // The newly_created_defs/Defs serialisation will re-adjust the suites defs pointer
+ Defs* old_defs = suite->defs();
+
+ // This will end up setting the suite's defs pointer to 'newly_created_defs'.
+ // This is wrong, since we only have a single suite
+ suite->set_defs(NULL); // otherwise addSuite, will complain
+ newly_created_defs->addSuite(suite); // will update modify_change_no, see comment at top
+
+ suite->set_defs(old_defs); // reset the defs, since addSuite() changed defs ptr
+ suite->set_state_change_no(suite_state_change_no); // reset in case addSuite() changed this
+ suite->set_modify_change_no(suite_modify_change_no); // reset in case addSuite() changed this
+ }
+ }
+
+ // Store the max in the defs, for transmission to client. The client uses this for syncing
+ newly_created_defs->set_state_change_no(the_max_state_change_no);
+ newly_created_defs->set_modify_change_no(the_max_modify_change_no);
+ return newly_created_defs;
+}
+
+
+void ClientSuites::max_change_no(unsigned int& the_max_state_change_no,unsigned int& the_max_modify_change_no ) const
+{
+ /// get the max state change_no due to:
+ /// o Defs state changed
+ /// o Suite order changed
+ /// o Defs flag changed
+ /// o Defs server state changed.
+ /// o Defs server variables changed
+ the_max_state_change_no = defs_->defs_only_max_state_change_no();
+
+ // Take into account case where all suites are registered
+ the_max_state_change_no = std::max( the_max_state_change_no, state_change_no_ );
+
+ // Take into account registered suites that get deleted, and where all suites registered
+ the_max_modify_change_no = 0;
+ the_max_modify_change_no = std::max( the_max_modify_change_no, modify_change_no_ );
+
+ BOOST_FOREACH(const HSuite& p, suites_) {
+ suite_ptr suite = p.weak_suite_ptr_.lock();
+ if (suite.get()) {
+ the_max_modify_change_no = std::max( the_max_modify_change_no, suite->modify_change_no() );
+ the_max_state_change_no = std::max( the_max_state_change_no, suite->state_change_no() );
+ }
+ }
+}
+
+void ClientSuites::suites(std::vector<std::string>& names) const
+{
+ names.reserve(suites_.size());
+ std::vector<HSuite>::const_iterator suites_end = suites_.end();
+ for(std::vector<HSuite>::const_iterator i = suites_.begin(); i != suites_end; ++i) {
+ names.push_back( (*i).name_ );
+ }
+}
+
+std::string ClientSuites::dump() const
+{
+ unsigned int maxstatechangeno = 0;
+ unsigned int maxmodifychangeno = 0;
+ max_change_no(maxstatechangeno,maxmodifychangeno);
+
+ std::stringstream ss;
+ ss << " handle(" << handle() << ") user(" << user_ << ") auto_add_new_suites(" << auto_add_new_suites_
+ << ") suites_.size(" << suites_.size() << ") suites(";
+
+ std::vector<HSuite>::const_iterator suites_end = suites_.end();
+ for(std::vector<HSuite>::const_iterator i = suites_.begin(); i != suites_end; ++i) {
+ suite_ptr suite = (*i).weak_suite_ptr_.lock();
+ if (suite.get()) {
+ ss << " " << suite->name();
+ }
+ else {
+ ss << " " << (*i).name_ << ":NULL";
+ }
+ }
+ ss << ") max(" << maxstatechangeno << "," << maxmodifychangeno << ")";
+ return ss.str();
+}
+
+
+void ClientSuites::update_suite_order()
+{
+ const std::vector<suite_ptr>& server_suite_vec = defs_->suiteVec();
+ size_t server_suite_vec_size = server_suite_vec.size();
+
+ std::vector<HSuite>::iterator suites_end = suites_.end();
+ for(std::vector<HSuite>::iterator i = suites_.begin(); i != suites_end; ++i) {
+ for(size_t s = 0; s < server_suite_vec_size; s++) {
+ if ((*i).name_ == server_suite_vec[s]->name()) {
+ (*i).index_ = static_cast<int>(s);
+ break;
+ }
+ }
+ }
+
+ std::sort(suites_.begin(),suites_.end(),
+ boost::bind(std::less<int>(),
+ boost::bind(&HSuite::index_,_1),
+ boost::bind(&HSuite::index_,_2)));
+
+}
+
+std::vector<HSuite>::iterator ClientSuites::find_suite(const std::string& name)
+{
+ std::vector<HSuite>::iterator suites_end = suites_.end();
+ for(std::vector<HSuite>::iterator i = suites_.begin(); i != suites_end; ++i) {
+ if ((*i).name_ == name) {
+ return i;
+ }
+ }
+ return suites_end;
+}
+
+}
diff --git a/ANode/src/ClientSuites.hpp b/ANode/src/ClientSuites.hpp
new file mode 100644
index 0000000..156c114
--- /dev/null
+++ b/ANode/src/ClientSuites.hpp
@@ -0,0 +1,145 @@
+#ifndef CLIENT_SUITES_HPP_
+#define CLIENT_SUITES_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #26 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+// The definition file could hold hundreds of suites, however the client
+// may only be interested in a small subset. By allowing the client to register
+// the suites they are interested in, we can reduce the network traffic
+// when they ask for updates.(ie via sync or news)
+// When the Client registers an interest in suites it is returned a handle,
+// this handle must is passed back to the server as a reference, with the sync'ing commands
+//
+// Users are allowed to register interest in suite that have not yet been added
+// This will only work provided we have a definition
+//
+// ***************************************************************************
+// Note: Change of suite order is handled by OrderMemento
+// and *NOT* by the ClientSuites, however whenever suites are:
+// registered and added/deleted:
+// then:
+// defs_ptr create_defs(Defs* server_defs) const;
+//
+// Will return the suites in the same order as the defs
+// ****************************************************************************
+//
+// Uses compiler generated copy constructor and destructor
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <string>
+#include <vector>
+#include <limits>
+#include "NodeFwd.hpp"
+
+namespace ecf {
+
+struct HSuite {
+ HSuite(const std::string& name, weak_suite_ptr p, int index = std::numeric_limits<int>::max())
+ : name_(name), weak_suite_ptr_(p),index_(index) {}
+
+ HSuite(const std::string& name )
+ : name_(name),index_(std::numeric_limits<int>::max()) {}
+
+ std::string name_; // suite name
+ weak_suite_ptr weak_suite_ptr_; // does suite exist in defs, need to lock, to find out
+ int index_; // suites in handles must be in same order as defs
+};
+
+class ClientSuites {
+public:
+ /// Will automatically create a unique handle
+ ClientSuites(Defs*,unsigned int handle, bool auto_add_new_suites, const std::vector<std::string>& suites , const std::string& user);
+
+ /// Return the handle, returned to the client, and required for all correspondence
+ /// between client server. This value is always > 0
+ unsigned int handle() const { return handle_;}
+
+ /// return the user who requested this handle
+ const std::string& user() const { return user_; }
+
+ /// The handle changed flag is set to true whenever a ClinetSuites is created
+ /// or when suites are added/removed from it. The alternative way would have
+ /// been to update the modify change number, but this would have affected all handles
+ bool handle_changed() const { return handle_changed_; }
+
+ /// Add an interest to this suite
+ void add_suite(const std::string&);
+ void add_suite(suite_ptr);
+
+ /// no longer interested in this suite. Explicit remove
+ void remove_suite(const std::string&);
+ bool remove_suite(suite_ptr);
+
+ /// A new suite is being added in the definition.
+ /// If it was already registered update the suite ptr
+ /// If auto add new suite enabled,register it
+ void suite_added_in_defs(suite_ptr);
+
+ /// The suite is being deleted, update modify_change_no. So we do a full sync
+ /// RESETs suite ptr. Deleted suites are *NOT* automatically removed
+ void suite_deleted_in_defs(suite_ptr);
+
+ /// Collate the incremental changes, made to my suites
+ void collateChanges(DefsDelta& changes) const;
+
+ // Only return the defs state and suites that the client has registered in this suite
+ // *HOWEVER* if the client has registered all the suites, just return the server defs
+ // *with* the updated change numbers
+ // *OTHERWISE*
+ /// Creates a new defs, by adding the suites to the defs
+ /// The defs is to be transferred to the client
+ /// Suites are returned in the same order as the defs
+ /// We avoid copying, but need to adjust suites defs pointer
+ /// This will clear the handle_changed_ flag
+ defs_ptr create_defs(defs_ptr server_defs) const;
+
+ // iterates overs its suites and return max state and modify change numbers
+ void max_change_no(unsigned int& state_change_no,unsigned int& modify_change_no ) const;
+
+ /// Enable/disable interest in new suites.
+ /// if the flag is true, when ever new suites are added to the defs
+ /// The internal list is updated.
+ void add_new_suite( bool flag ) { auto_add_new_suites_ = flag;}
+ bool auto_add_new_suites() const { return auto_add_new_suites_;}
+
+ /// returns the list of suites
+ void suites(std::vector<std::string>& names) const;
+
+ /// Update suites to be in same order as Defs.
+ /// This should be done externally to avoid update after individual add
+ void update_suite_order();
+
+ /// For debug dumps
+ std::string dump() const;
+
+private:
+ std::vector<HSuite>::iterator find_suite(const std::string& name);
+
+private:
+ Defs* defs_;
+ unsigned int handle_; // This must be unique
+
+ // The modify_change_no_ is required specifically when a registered suite is deleted
+ // Both modify_change_no_ & state_change_no_ are required when user has registered
+ // with *ALL* the suites. In this case we need to ensure that after a SYNC/create_defs
+ // the NewsCmd call to max_change_no() is in sync with global change numbers.
+ mutable unsigned int state_change_no_;
+ mutable unsigned int modify_change_no_;
+
+ bool auto_add_new_suites_;
+ mutable bool handle_changed_; // set when handle created, or when suites added/removed
+ std::string user_; // user who create this handle
+ std::vector<HSuite> suites_;
+};
+}
+#endif
diff --git a/ANode/src/CmdContext.cpp b/ANode/src/CmdContext.cpp
new file mode 100644
index 0000000..19165c2
--- /dev/null
+++ b/ANode/src/CmdContext.cpp
@@ -0,0 +1,29 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #16 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "CmdContext.hpp"
+
+namespace ecf {
+bool CmdContext::in_command_ = false;
+
+CmdContext::CmdContext()
+{
+ in_command_ = true;
+}
+
+CmdContext::~CmdContext()
+{
+ in_command_ = false;
+}
+
+}
diff --git a/ANode/src/CmdContext.hpp b/ANode/src/CmdContext.hpp
new file mode 100644
index 0000000..60d5815
--- /dev/null
+++ b/ANode/src/CmdContext.hpp
@@ -0,0 +1,36 @@
+#ifndef CMD_CONTEXT_HPP_
+#define CMD_CONTEXT_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #14 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+// This class allow client to determine whether they are in a middle
+// of a command.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <boost/noncopyable.hpp>
+
+namespace ecf {
+
+class CmdContext : private boost::noncopyable {
+public:
+ CmdContext();
+ ~CmdContext();
+
+ static bool in_command() { return in_command_; }
+
+private:
+ static bool in_command_;
+};
+}
+
+#endif
diff --git a/ANode/src/Defs.cpp b/ANode/src/Defs.cpp
new file mode 100644
index 0000000..66fb6f9
--- /dev/null
+++ b/ANode/src/Defs.cpp
@@ -0,0 +1,1519 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #270 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <assert.h>
+#include <sstream>
+#include <fstream>
+#include <boost/bind.hpp>
+#include <boost/make_shared.hpp>
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "Log.hpp"
+#include "PrintStyle.hpp"
+#include "NodeTreeVisitor.hpp"
+#include "Str.hpp"
+#include "Extract.hpp"
+#include "NodePath.hpp"
+#include "Stl.hpp"
+#include "Ecf.hpp"
+#include "NodeState.hpp"
+#include "ExprAst.hpp" // required for persistence
+#include "Serialization.hpp" // collates boost archive includes
+#include "JobCreationCtrl.hpp"
+#include "ResolveExternsVisitor.hpp"
+#include "DefsDelta.hpp"
+#include "ExprDuplicate.hpp"
+#include "Version.hpp"
+#include "Indentor.hpp"
+#include "AbstractObserver.hpp"
+
+using namespace ecf;
+using namespace std;
+
+//#define DEBUG_JOB_SUBMISSION 1
+//#define DEBUG_MEMENTO 1
+
+Defs::Defs() :
+ state_change_no_(0),
+ modify_change_no_( 0 ),
+ updateCalendarCount_(0),
+ order_state_change_no_(0),
+ save_edit_history_(false),
+ client_suite_mgr_(this),
+ in_notification_(false)
+{
+}
+
+defs_ptr Defs::create()
+{
+ return boost::make_shared<Defs>();
+}
+
+Defs::~Defs()
+{
+// cout << " Deleting defs "\n";
+ if (!Ecf::server() ) {
+ notify_delete();
+ }
+
+ // Duplicate AST are held in a static map. Delete them, to avoid valgrind complaining
+ ExprDuplicate reclaim_cloned_ast_memory;
+}
+
+///// State relation functions: ==================================================
+NState::State Defs::state() const
+{
+ return state_.state();
+}
+
+void Defs::set_state_only(NState::State the_new_state)
+{
+ state_.setState( the_new_state ); // this will update state_change_no
+}
+
+void Defs::set_state(NState::State the_new_state)
+{
+ set_state_only( the_new_state ); // this will update state_change_no
+
+ // Log the state change
+ // " " + submitted(max) + ": /"
+ // reserve : 1 + 9 + 3 = 13
+ std::string log_state_change; log_state_change.reserve(13);
+ log_state_change += " ";
+ log_state_change += NState::toString(the_new_state);
+ log_state_change += ": /";
+ ecf::log(Log::LOG,log_state_change);
+}
+
+void Defs::set_most_significant_state()
+{
+ NState::State computedStateOfImmediateChildren = ecf::theComputedNodeState(suiteVec_, true /* immediate children only */ );
+ if (computedStateOfImmediateChildren != state_.state() )
+ set_state( computedStateOfImmediateChildren );
+}
+
+/// Others ======================================================================
+void Defs::check_job_creation( job_creation_ctrl_ptr jobCtrl )
+{
+ /// Job generation checking. is done via the python API
+ /// As such it done directly on the Defs.
+ /// However Job generation checking will end up changing the states of the DEFS
+ /// If this defs is loaded into the server the state of each node may be surprising. (i.e submitted)
+ /// Hence we need to reset the state.
+
+ if (!jobCtrl.get()) {
+ throw std::runtime_error("Defs::check_job_creation: NULL JobCreationCtrl passed");
+ }
+
+ // This function should NOT really change the data model
+ // The changed state is reset, hence we need to preserve change and modify numbers
+ EcfPreserveChangeNo preserveChangeNo;
+
+ // Do *not* modify suspended state of child nodes
+ int clear_suspended_in_child_nodes = -1;
+
+ if (jobCtrl->node_path().empty()) {
+
+ size_t theSize = suiteVec_.size();
+ for(size_t s = 0; s < theSize; s++) {
+ /// begin will cause creation of generated variables. The generated variables
+ /// are use in client scripts and used to locate the ecf files
+ suiteVec_[s]->begin();
+ suiteVec_[s]->check_job_creation( jobCtrl ) ;
+
+ /// reset the state
+ suiteVec_[s]->requeue(true,clear_suspended_in_child_nodes,true);
+ suiteVec_[s]->reset_begin();
+ suiteVec_[s]->setStateOnlyHierarchically( NState::UNKNOWN );
+ }
+ }
+ else {
+
+ node_ptr node = findAbsNode( jobCtrl->node_path() );
+ if (node.get()) {
+ /// begin will cause creation of generated variables. The generated variables
+ /// are use in client scripts and used to locate the ecf files
+ node->suite()->begin();
+ node->check_job_creation( jobCtrl );
+
+ /// reset the state
+ node->requeue(true,clear_suspended_in_child_nodes,true);
+ node->suite()->reset_begin();
+ node->setStateOnlyHierarchically( NState::UNKNOWN );
+ }
+ else {
+ std::stringstream ss;
+ ss << "Defs::check_job_creation: failed as node path '" << jobCtrl->node_path() << "' does not exist.\n";
+ jobCtrl->error_msg() = ss.str();
+ }
+ }
+}
+
+void Defs::do_generate_scripts( const std::map<std::string,std::string>& override) const
+{
+ size_t theSize = suiteVec_.size();
+ for(size_t s = 0; s < theSize; s++) {
+ suiteVec_[s]->generate_scripts(override);
+ }
+}
+void Defs::generate_scripts() const
+{
+ std::map<std::string,std::string> override;
+ do_generate_scripts(override);
+}
+
+
+void Defs::updateCalendar( const ecf::CalendarUpdateParams & calUpdateParams)
+{
+ /// Collate any auto cancelled nodes as a result of calendar update
+ std::vector<node_ptr> auto_cancelled_nodes;
+
+ // updateCalendarCount_ is only used in *test*
+ updateCalendarCount_++;
+
+ size_t theSize = suiteVec_.size();
+ for(size_t s = 0; s < theSize; s++) {
+ suiteVec_[s]->updateCalendar( calUpdateParams, auto_cancelled_nodes);
+ }
+
+ // Permanently remove any auto-cancelled nodes.
+ if ( !auto_cancelled_nodes.empty() ) {
+ std::vector<node_ptr>::iterator theNodeEnd = auto_cancelled_nodes.end();
+ string msg;
+ for(std::vector<node_ptr>::iterator n = auto_cancelled_nodes.begin(); n != theNodeEnd; ++n) {
+ // If we have two autocancel in the hierarchy, with same attributes. Then
+ // (*n)->remove() on the second will fail( with a crash, SuiteChanged0 destructor, no suite pointer)
+ // since it would already be detached. See ECFLOW-556
+ // By checking we can still reach the Defs we know we are not detached
+ if ((*n)->defs()) {
+ msg.clear(); msg = "autocancel "; msg += (*n)->debugNodePath();
+ ecf::log(Log::MSG,msg);
+ (*n)->remove();
+ }
+ }
+ }
+}
+
+
+void Defs::absorb(Defs* input_defs, bool force)
+{
+ // Dont absorb myself.
+ if (input_defs == this) {
+ return;
+ }
+
+ // updateCalendarCount_ is *only* used in test, reset whenever a new defs is loaded
+ updateCalendarCount_ = 0;
+
+ // We must make a copy, otherwise we are iterating over a vector that is being deleted
+ std::vector<suite_ptr> suiteVecCopy = input_defs->suiteVec();
+ size_t theSize = suiteVecCopy.size();
+ for(size_t s = 0; s < theSize; s++) {
+
+ /// regardless remove the suite from the input defs
+ suite_ptr the_input_suite = input_defs->removeSuite(suiteVecCopy[s]);
+
+ if (force) {
+ /// The suite of the same name exists. remove it from *existing* defs
+ suite_ptr existing_suite = findSuite( the_input_suite->name() );
+ if (existing_suite.get()) {
+ removeSuite( existing_suite );
+ }
+ }
+
+ /// Add the suite. Will throw if suite of same name already exists.
+ /// This stops accidental overwrite
+ addSuite( the_input_suite );
+ }
+ LOG_ASSERT( input_defs->suiteVec().empty(),"Defs::absorb");
+
+ // Copy over server user variables
+ set_server().add_or_update_user_variables( input_defs->server().user_variables() );
+
+ // This only works on the client side. since server does not store externs
+ const set<string>& ex = input_defs->externs();
+ for(set<string>::const_iterator i = ex.begin(); i != ex.end(); ++i) {
+ add_extern(*i);
+ }
+}
+
+void Defs::accept(ecf::NodeTreeVisitor& v)
+{
+ v.visitDefs(this);
+ size_t theSuiteVecSize = suiteVec_.size();
+ for(size_t i = 0; i < theSuiteVecSize; i++) { suiteVec_[i]->accept(v); }
+}
+
+void Defs::acceptVisitTraversor(ecf::NodeTreeVisitor& v)
+{
+ LOG_ASSERT(v.traverseObjectStructureViaVisitors(),"");
+ v.visitDefs(this);
+}
+
+bool Defs::verification(std::string& errorMsg) const
+{
+ size_t theSuiteVecSize = suiteVec_.size();
+ for(size_t i = 0; i < theSuiteVecSize; i++) { suiteVec_[i]->verification(errorMsg); }
+ return errorMsg.empty();
+}
+
+suite_ptr Defs::add_suite(const std::string& name)
+{
+ if (findSuite(name).get()) {
+ std::stringstream ss;
+ ss << "Add Suite failed: A Suite of name '" << name << "' already exist";
+ throw std::runtime_error( ss.str() );
+ }
+ suite_ptr the_suite = Suite::create(name);
+ add_suite_only( the_suite , std::numeric_limits<std::size_t>::max());
+ return the_suite;
+}
+
+void Defs::addSuite(suite_ptr s, size_t position)
+{
+ if (findSuite(s->name()).get()) {
+ std::stringstream ss;
+ ss << "Add Suite failed: A Suite of name '" << s->name() << "' already exist";
+ throw std::runtime_error( ss.str() );
+ }
+ add_suite_only( s , position);
+}
+
+void Defs::add_suite_only(suite_ptr s, size_t position)
+{
+ if (s->defs()) {
+ std::stringstream ss;
+ ss << "Add Suite failed: The suite of name '" << s->name() << "' already owned by another Defs ";
+ throw std::runtime_error( ss.str() );
+ }
+
+ s->set_defs(this);
+ if (position >= suiteVec_.size()) {
+ suiteVec_.push_back(s);
+ }
+ else {
+ suiteVec_.insert( suiteVec_.begin() + position, s);
+ }
+ Ecf::incr_modify_change_no();
+ client_suite_mgr_.suite_added_in_defs(s);
+}
+
+suite_ptr Defs::removeSuite(suite_ptr s)
+{
+ std::vector<suite_ptr>::iterator i = std::find(suiteVec_.begin(), suiteVec_.end(),s);
+ if ( i != suiteVec_.end()) {
+ s->set_defs(NULL); // allows suite to added to different defs
+ suiteVec_.erase(i); // iterator invalidated
+ Ecf::incr_modify_change_no();
+ client_suite_mgr_.suite_deleted_in_defs(s); // must be after Ecf::incr_modify_change_no();
+ return s; // transfer ownership of suite
+ }
+
+ // Something serious has gone wrong. Can not find the suite
+ cout << "Defs::removeSuite: assert failure: suite '" << s->name() << "' suiteVec_.size() = " << suiteVec_.size() << "\n";
+ for(unsigned i = 0; i < suiteVec_.size(); ++i) { cout << i << " " << suiteVec_[i]->name() << "\n";}
+ LOG_ASSERT(false,"Defs::removeSuite the suite not found");
+ return suite_ptr();
+}
+
+size_t Defs::child_position(const Node* child) const
+{
+ size_t vecSize = suiteVec_.size();
+ for(size_t t = 0; t < vecSize; t++) {
+ if (suiteVec_[t].get() == child) {
+ return t;
+ }
+ }
+ return std::numeric_limits<std::size_t>::max();
+}
+
+node_ptr Defs::removeChild(Node* child)
+{
+ size_t vecSize = suiteVec_.size();
+ for(size_t t = 0; t < vecSize; t++) {
+ if (suiteVec_[t].get() == child) {
+ Ecf::incr_modify_change_no();
+ suiteVec_[t]->set_defs(NULL); // Must be set to NULL, allows suite to be added to different defs
+ client_suite_mgr_.suite_deleted_in_defs(suiteVec_[t]); // must be after Ecf::incr_modify_change_no();
+ node_ptr node = boost::dynamic_pointer_cast<Node>(suiteVec_[t]);
+ suiteVec_.erase( suiteVec_.begin() + t);
+ return node ;
+ }
+ }
+
+ // Something has gone wrong.
+ cout << "Defs::removeChild: assert failed: suite '" << child->name() << "' suiteVec_.size() = " << suiteVec_.size() << "\n";
+ for(unsigned i = 0; i < suiteVec_.size(); ++i) { cout << i << " " << suiteVec_[i]->name() << "\n";}
+ LOG_ASSERT(false,"Defs::removeChild,the suite not found");
+ return node_ptr();
+}
+
+bool Defs::addChild( node_ptr child, size_t position)
+{
+ LOG_ASSERT(child.get(),"");
+ LOG_ASSERT(child->isSuite(),"");
+
+ // *** CANT construct shared_ptr from a raw pointer, must use dynamic_pointer_cast,
+ // *** otherwise the reference counts will get messed up.
+ // If the suite of the same exists, it is deleted first
+ addSuite( boost::dynamic_pointer_cast<Suite>( child ), position );
+ return true;
+}
+
+void Defs::add_extern(const std::string& ex )
+{
+ if (ex.empty()) {
+ throw std::runtime_error("Defs::add_extern: Can not add empty extern");
+ }
+ externs_.insert(ex);
+}
+
+void Defs::auto_add_externs(bool remove_existing_externs_first)
+{
+ if (remove_existing_externs_first) {
+ externs_.clear();
+ }
+ /// Automatically add externs
+ ResolveExternsVisitor visitor(this);
+ acceptVisitTraversor(visitor);
+}
+
+void Defs::beginSuite(suite_ptr suite)
+{
+ if (!suite.get()) throw std::runtime_error( "Defs::beginSuite: Begin failed as suite is not loaded" );
+
+ if (!suite->begun()) {
+ // Hierarchical set the state. Handle case where we have children that are all defstatus complete
+ // and hence needs parent set to complete. See Simulator/good_defs/operations/naw.def
+ // family naw
+ // family general
+ // time 06:00
+ // task metgrams
+ // defstatus complete
+ // task equipot
+ // defstatus complete
+ // endfamily
+ suite->begin();
+
+ set_most_significant_state();
+ }
+ else {
+ LOG(Log::WAR,"Suite " << suite->name() << " has already begun");
+ }
+}
+
+void Defs::beginAll()
+{
+ bool at_least_one_suite_begun = false;
+ size_t theSuiteVecSize = suiteVec_.size();
+ for(size_t s = 0; s < theSuiteVecSize; s++) {
+ if ( !suiteVec_[s]->begun() ) {
+ suiteVec_[s]->begin();
+ at_least_one_suite_begun = true;
+ }
+ }
+
+ if ( at_least_one_suite_begun ) {
+ set_most_significant_state();
+ }
+}
+
+void Defs::reset_begin()
+{
+ std::for_each(suiteVec_.begin(),suiteVec_.end(),boost::bind(&Suite::reset_begin,_1));
+}
+
+void Defs::requeue()
+{
+ bool edit_history_set = flag().is_set(ecf::Flag::MESSAGE);
+ flag_.reset();
+ if (edit_history_set) flag().set(ecf::Flag::MESSAGE);
+
+ int clear_suspended_in_child_nodes = 0;
+ size_t theSuiteVecSize = suiteVec_.size();
+ for(size_t s = 0; s < theSuiteVecSize; s++) {
+ suiteVec_[s]->requeue( true /* reset repeats */,
+ clear_suspended_in_child_nodes,
+ true /* reset_next_time_slot */);
+ }
+
+ set_most_significant_state();
+}
+
+
+void Defs::check_suite_can_begin(suite_ptr suite) const
+{
+ NState::State suiteState = suite->state();
+ if (!suite->begun() && suiteState != NState::UNKNOWN && suiteState != NState::COMPLETE) {
+ int count = 0;
+ std::vector<Task*> tasks;
+ getAllTasks(tasks);
+ std::stringstream ts;
+ for(size_t i =0; i < tasks.size(); i++) {
+ if (tasks[i]->state() == NState::ACTIVE || tasks[i]->state() == NState::SUBMITTED) {
+ ts << " " << tasks[i]->absNodePath() << "\n";
+ count++;
+ }
+ }
+ /// allow suite to begin even its aborted provide no tasks in active or submitted states
+ if (count > 0) {
+ std::stringstream ss;
+ ss << "Begin failed as suite "
+ << suite->name() << "(computed state=" << NState::toString(suiteState)
+ << ") can only begin if its in UNKNOWN or COMPLETE state\n";
+ ss << "Found " << count << " tasks with state 'active' or 'submitted'\n";
+ ss << ts.str();
+ ss << "Use the force argument to bypass this check, at the risk of creating zombies\n";
+ throw std::runtime_error( ss.str() );
+ }
+ }
+}
+
+bool Defs::hasTimeDependencies() const
+{
+ size_t theSuiteVecSize = suiteVec_.size();
+ for(size_t s = 0; s < theSuiteVecSize; s++) {
+ if ( suiteVec_[s]->hasTimeDependencies() ) return true;
+ }
+ return false;
+}
+
+std::ostream& Defs::print(std::ostream& os) const
+{
+ os << "# " << ecf::Version::raw() << "\n";
+ if (!PrintStyle::defsStyle()) {
+ os << write_state();
+ }
+ if (PrintStyle::getStyle() == PrintStyle::STATE) {
+ os << "# server variable\n";
+ const std::vector<Variable>& server_variables = server().server_variables();
+ BOOST_FOREACH(const Variable& var, server_variables) { var.print_generated(os);}
+ os << "# user variable\n";
+ const std::vector<Variable>& user_variables = server().user_variables();
+ BOOST_FOREACH(const Variable& var, user_variables) { var.print_generated(os);}
+ }
+
+ set<string>::const_iterator extern_end = externs_.end();
+ for(set<string>::const_iterator i = externs_.begin(); i != extern_end; ++i) {
+ os << "extern " << *i << "\n";
+ }
+ size_t the_size = suiteVec_.size();
+ for(size_t s = 0; s < the_size; s++) {
+ os << *suiteVec_[s];
+ }
+ return os;
+}
+
+std::string Defs::write_state() const
+{
+ // *IMPORTANT* we *CANT* use ';' character, since is used in the parser, when we have
+ // multiple statement on a single line i.e.
+ // task a; task b;
+ // *IMPORTANT* make sure name are unique, i.e can't have state: and server_state:
+ // Otherwise read_state() will mess up
+ std::stringstream os;
+ os << "defs_state";
+ os << " " << PrintStyle::to_string();
+ if (state_ != NState::UNKNOWN) os << " state>:" << NState::toString(state_); // make <state> is unique
+ if (flag_.flag() != 0) os << " flag:" << flag_.to_string();
+ if (state_change_no_ != 0) os << " state_change:" << state_change_no_;
+ if (modify_change_no_ != 0) os << " modify_change:" << modify_change_no_;
+ if (server().get_state() != ServerState::default_state()) os << " server_state:" << SState::to_string(server().get_state());
+ os << "\n";
+
+ // This read by the DefsStateParser
+ const std::vector<Variable>& theServerEnv = server().user_variables();
+ for(size_t i = 0; i < theServerEnv.size(); ++i) {
+ theServerEnv[i].print(os);
+ }
+
+ // READ by Defs::read_history()
+ // We need to define a separator for the message, will to allow it to be re-read
+ // This separator can not be :
+ // ' ' space, used in the messages
+ // % Used in job submission
+ // : Used in time, and name (:ma0)
+ // [] Used in time
+ // integers used in the time.
+ // - Used in commands
+ if (PrintStyle::getStyle() == PrintStyle::MIGRATE || save_edit_history_) {
+ Indentor in;
+ std::map<std::string, std::deque<std::string> >::const_iterator i;
+ for(i=edit_history_.begin(); i != edit_history_.end(); ++i) {
+ Indentor::indent( os ) << "history " << (*i).first << " ";// node path
+ const std::deque<std::string>& vec = (*i).second; // list of requests
+ for(std::deque<std::string>::const_iterator c = vec.begin(); c != vec.end(); ++c) {
+
+ // We expect to output a single newline, hence if there are additional new lines
+ // It can mess up, re-parse. i.e during alter change label/value, user could have added newlines
+ if ((*c).find("\n") == std::string::npos) os << "\b" << *c;
+ else {
+ std::string h = *c;
+ Str::replaceall(h,"\n","\\n");
+ os << "\b" << h;
+ }
+ }
+ os << "\n";
+ }
+ save_edit_history_ = false;
+ }
+ return os.str();
+}
+
+void Defs::read_state(const std::string& line,const std::vector<std::string>& lineTokens)
+{
+// cout << "line = " << line << "\n";
+ std::string token;
+ for(size_t i = 2; i < lineTokens.size(); i++) {
+ token.clear();
+ if (lineTokens[i].find("state>:") != std::string::npos) {
+ if (!Extract::split_get_second(lineTokens[i],token)) throw std::runtime_error( "Defs::read_state: state extraction failed : " + lineTokens[i] );
+ if (!NState::isValid(token)) throw std::runtime_error( "Defs::read_state: invalid state specified : " + token );
+ set_state_only(NState::toState(token));
+ }
+ else if (lineTokens[i].find("flag:") != std::string::npos) {
+ if (!Extract::split_get_second(lineTokens[i],token))throw std::runtime_error( "Defs::read_state: Invalid flag specified : " + line );
+ flag().set_flag(token); // this can throw
+ }
+ else if (lineTokens[i].find("state_change:") != std::string::npos) {
+ if (!Extract::split_get_second(lineTokens[i],token)) throw std::runtime_error( "Defs::read_state: Invalid state_change specified : " + line );
+ int sc = Extract::theInt(token,"Defs::read_state: invalid state_change specified : " + line);
+ set_state_change_no(sc);
+ }
+ else if (lineTokens[i].find("modify_change:") != std::string::npos) {
+ if (!Extract::split_get_second(lineTokens[i],token)) throw std::runtime_error( "Defs::read_state: Invalid modify_change specified : " + line );
+ int mc = Extract::theInt(token,"Defs::read_state: invalid state_change specified : " + line);
+ set_modify_change_no(mc);
+ }
+ else if (lineTokens[i].find("server_state:") != std::string::npos) {
+ if (!Extract::split_get_second(lineTokens[i],token)) throw std::runtime_error( "Defs::read_state: Invalid server_state specified : " + line );
+ if (!SState::isValid(token)) throw std::runtime_error( "Defs::read_state: Invalid server_state specified : " + line );
+ set_server().set_state(SState::toState(token));
+ }
+ }
+}
+
+void Defs::read_history(const std::string& line,const std::vector<std::string>& lineTokens)
+{
+ // expect:
+ // history <node_path> \bmsg1\bmsg2
+ // The message can contain spaces,
+ // Multiple spaces will be lost !!
+ if ( lineTokens.size() < 2 ) throw std::runtime_error( "Defs::read_history: Invalid history " + line );
+
+ DefsHistoryParser parser;
+ parser.parse(line);
+
+ const std::vector<std::string>& parsed_messages = parser.parsed_messages();
+ for(size_t i = 0; i < parsed_messages.size(); i++) {
+ add_edit_history(lineTokens[1],parsed_messages[i]);
+ }
+}
+
+bool Defs::compare_edit_history(const Defs& rhs) const
+{
+ if (edit_history_ != rhs.edit_history_) return false;
+ return true;
+}
+
+
+bool Defs::operator==(const Defs& rhs) const
+{
+ if ( state() != rhs.state()) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Defs::operator== state(" << NState::toString(state()) << ") != rhs.state(" << NState::toString(rhs.state()) << ")) \n";
+ }
+#endif
+ return false;
+ }
+
+ if ( server_ != rhs.server() ) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Defs::operator== server_ != rhs.server())\n";
+ }
+#endif
+ return false;
+ }
+
+ if ( flag_ != rhs.flag_) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Defs::operator== ( flag_ != rhs.flag_) : '" << flag_.to_string() << "' != '" << rhs.flag_.to_string() << "'\n";
+ }
+#endif
+ return false;
+ }
+
+ /// Note:: WE specifically exclude testing of externs.
+ /// Externs are not persisted, hence can not take part in comparison
+ /// Externs only live on the client side.
+
+ if ( suiteVec_.size() != rhs.suiteVec_.size()) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Defs::operator== suiteVec_.size(" << suiteVec_.size() << ") != rhs.suiteVec_.size( " << rhs.suiteVec_.size() << ") \n";
+ }
+#endif
+ return false;
+ }
+ for(unsigned i =0; i < suiteVec_.size(); ++i) {
+ if ( !( *(suiteVec_[i]) == *(rhs.suiteVec_[i]) )) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Defs::operator== !( *(suiteVec_[i]) == *(rhs.suiteVec_[i]) )\n";
+ }
+#endif
+ return false;
+ }
+ }
+ return true;
+}
+
+node_ptr Defs::findAbsNode(const std::string& pathToNode) const
+{
+// std::cout << "Defs::findAbsNode " << pathToNode << "\n";
+ // The pathToNode is of the form:
+ // /suite
+ // /suite/family
+ // /suite/family/task
+ // /suite/family/family/family/task
+
+ std::vector<std::string> theNodeNames; theNodeNames.reserve(4);
+ NodePath::split(pathToNode,theNodeNames);
+ if ( theNodeNames.empty() ) {
+ return node_ptr();
+ }
+
+
+ size_t child_pos = 0 ; // unused
+ size_t pathSize = theNodeNames.size();
+ size_t theSuiteVecSize = suiteVec_.size();
+ for(size_t s = 0; s < theSuiteVecSize; s++) {
+
+ size_t index = 0;
+ if (theNodeNames[index] == suiteVec_[s]->name()) {
+
+ node_ptr the_node = suiteVec_[s];
+ if (pathSize == 1) return the_node;
+ index++; // skip over suite,
+
+ while (index < pathSize) {
+ the_node = the_node->findImmediateChild(theNodeNames[index],child_pos);
+ if (the_node) {
+ if (index == pathSize - 1) return the_node;
+ index++;
+ }
+ else {
+ return node_ptr();
+ }
+ }
+ return node_ptr();
+ }
+ }
+
+ return node_ptr();
+}
+
+node_ptr Defs::find_closest_matching_node(const std::string& pathToNode) const
+{
+ std::vector<std::string> theNodeNames;
+ NodePath::split(pathToNode,theNodeNames);
+ if ( theNodeNames.empty() ) return node_ptr();
+
+ node_ptr closest_matching_node;
+ int index = 0;
+ size_t theSuiteVecSize = suiteVec_.size();
+ for(size_t s = 0; s < theSuiteVecSize; s++) {
+ suiteVec_[s]->find_closest_matching_node(theNodeNames,index,closest_matching_node);
+ if (closest_matching_node.get()) return closest_matching_node;
+ }
+ return node_ptr();
+}
+
+
+bool Defs::find_extern( const std::string& pathToNode , const std::string& node_attr_name ) const
+{
+ if (externs_.empty()) {
+ return false;
+ }
+
+ if (node_attr_name.empty()) {
+ if (externs_.find(pathToNode) != externs_.end()) {
+ return true;
+ }
+ return false;
+ }
+
+ std::string extern_path = pathToNode;
+ extern_path += Str::COLON();
+ extern_path += node_attr_name;
+
+ if (externs_.find(extern_path) != externs_.end()) {
+ return true;
+ }
+ return false;
+}
+
+
+suite_ptr Defs::findSuite(const std::string& name) const
+{
+ size_t theSuiteVecSize = suiteVec_.size();
+ for(size_t s = 0; s < theSuiteVecSize; s++) {
+ if (suiteVec_[s]->name() == name) {
+ return suiteVec_[s];
+ }
+ }
+ return suite_ptr();
+}
+
+bool Defs::check(std::string& errorMsg,std::string& warningMsg) const
+{
+ size_t theSuiteVecSize = suiteVec_.size();
+ for(size_t s = 0; s < theSuiteVecSize; s++) { suiteVec_[s]->check(errorMsg,warningMsg); }
+ return errorMsg.empty();
+}
+
+void Defs::getAllTasks(std::vector<Task*>& tasks) const
+{
+ size_t theSuiteVecSize = suiteVec_.size();
+ for(size_t s = 0; s < theSuiteVecSize; s++) { suiteVec_[s]->getAllTasks(tasks);}
+}
+
+void Defs::getAllSubmittables(std::vector<Submittable*>& tasks) const
+{
+ size_t theSuiteVecSize = suiteVec_.size();
+ for(size_t s = 0; s < theSuiteVecSize; s++) { suiteVec_[s]->getAllSubmittables(tasks);}
+}
+
+void Defs::get_all_active_submittables(std::vector<Submittable*>& tasks) const
+{
+ size_t theSuiteVecSize = suiteVec_.size();
+ for(size_t s = 0; s < theSuiteVecSize; s++) { suiteVec_[s]->get_all_active_submittables(tasks);}
+}
+
+void Defs::get_all_tasks(std::vector<task_ptr>& tasks) const
+{
+ size_t theSuiteVecSize = suiteVec_.size();
+ for(size_t s = 0; s < theSuiteVecSize; s++) { suiteVec_[s]->get_all_tasks(tasks);}
+}
+
+void Defs::get_all_nodes(std::vector<node_ptr>& nodes) const
+{
+ size_t theSuiteVecSize = suiteVec_.size();
+ for(size_t s = 0; s < theSuiteVecSize; s++) { suiteVec_[s]->get_all_nodes(nodes);}
+}
+
+void Defs::get_all_aliases(std::vector<alias_ptr>& aliases) const
+{
+ size_t theSuiteVecSize = suiteVec_.size();
+ for(size_t s = 0; s < theSuiteVecSize; s++) { suiteVec_[s]->get_all_aliases(aliases);}
+}
+
+void Defs::getAllFamilies(std::vector<Family*>& vec) const
+{
+ size_t theSuiteVecSize = suiteVec_.size();
+ for(size_t s = 0; s < theSuiteVecSize; s++) { suiteVec_[s]->getAllFamilies(vec);}
+}
+
+void Defs::getAllNodes(std::vector<Node*>& vec) const
+{
+ size_t theSuiteVecSize = suiteVec_.size();
+ vec.reserve(vec.size() + theSuiteVecSize);
+ for(size_t s = 0; s < theSuiteVecSize; s++) {
+ vec.push_back(suiteVec_[s].get());
+ suiteVec_[s]->getAllNodes(vec);
+ }
+}
+
+void Defs::getAllAstNodes(std::set<Node*>& theSet) const
+{
+ size_t theSuiteVecSize = suiteVec_.size();
+ for(size_t s = 0; s < theSuiteVecSize; s++) { suiteVec_[s]->getAllAstNodes(theSet);}
+}
+
+bool Defs::deleteChild(Node* nodeToBeDeleted)
+{
+ Node* parent = nodeToBeDeleted->parent();
+ if (parent) return parent->doDeleteChild(nodeToBeDeleted);
+ return doDeleteChild(nodeToBeDeleted);
+}
+
+bool Defs::doDeleteChild(Node* nodeToBeDeleted)
+{
+// std::cout << "Defs::doDeleteChild nodeToBeDeleted = " << nodeToBeDeleted->debugNodePath() << "\n";
+
+ std::vector<suite_ptr>::iterator theSuiteEnd = suiteVec_.end();
+ for(std::vector<suite_ptr>::iterator s = suiteVec_.begin(); s!=theSuiteEnd; ++s) {
+ if ( (*s).get() == nodeToBeDeleted) {
+ Ecf::incr_modify_change_no();
+ client_suite_mgr_.suite_deleted_in_defs(*s); // must be after Ecf::incr_modify_change_no();
+ (*s)->set_defs(NULL); // Must be set to NULL, allows re-added to a different defs
+ suiteVec_.erase(s);
+ set_most_significant_state(); // must be after suiteVec_.erase(s);
+ return true;
+ }
+ }
+
+ // recurse down only if we did not remove the suite
+ for(std::vector<suite_ptr>::iterator s = suiteVec_.begin(); s!=theSuiteEnd; ++s) {
+ // SuiteChanged is called within doDeleteChild
+ if ((*s)->doDeleteChild(nodeToBeDeleted)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Defs::replaceChild(const std::string& path,
+ const defs_ptr& clientDefs,
+ bool createNodesAsNeeded,
+ bool force,
+ std::string& errorMsg)
+{
+ node_ptr clientNode = clientDefs->findAbsNode( path );
+ if (! clientNode.get() ) {
+ errorMsg = "Can not replace node since path "; errorMsg += path;
+ errorMsg += " does not exist on the client definition";
+ return false;
+ }
+
+ node_ptr serverNode = findAbsNode( path ) ;
+ if (!force && serverNode.get()) {
+ // Check if serverNode has child tasks in submitted or active states
+ vector<Task*> taskVec;
+ serverNode->getAllTasks(taskVec); // taskVec will be empty if serverNode is a task
+ int count = 0;
+ BOOST_FOREACH(Task* t, taskVec) { if (t->state() == NState::ACTIVE || t->state() == NState::SUBMITTED) count++;}
+ if (count != 0) {
+ std::stringstream ss;
+ ss << "Can not replace node " << serverNode->debugNodePath() << " because it has " << count << " tasks which are active or submitted\n";
+ ss << "Please use the 'force' option to bypass this check, at the expense of creating zombies\n";
+ errorMsg += ss.str();
+ return false;
+ }
+ }
+
+ /// REPLACE ===========================================================
+ if (!createNodesAsNeeded || serverNode.get()) {
+ // Then the child must exist in the server defs (i.e. this)
+ if (! serverNode.get() ) {
+ errorMsg = "Can not replace child since path "; errorMsg += path;
+ errorMsg += " does not exist on the server definition. Please use <parent> option";
+ return false;
+ }
+ // HAVE a FULL match in the server
+
+ // Copy over begun and suspended states
+ if (serverNode->suite()->begun()) clientNode->begin();
+ if (serverNode->isSuspended()) clientNode->suspend();
+
+ // Find the position of the server node relative to its peers
+ // We use this to re-add client node at the same position
+ size_t child_pos = serverNode->position();
+
+ // Delete node on the server, Must recurse down
+ Node* parentNodeOnServer = serverNode->parent();
+ deleteChild(serverNode.get());
+
+ // Remove reference in the client defs to clientNode and detach from its parent
+ // transfer ownership to the server
+ bool addOk = false;
+ node_ptr client_node_to_add = clientNode->remove();
+ if ( parentNodeOnServer ) addOk = parentNodeOnServer->addChild( client_node_to_add , child_pos);
+ else addOk = addChild( client_node_to_add , child_pos);
+ LOG_ASSERT(addOk,"");
+
+ client_node_to_add->set_most_significant_state_up_node_tree();
+
+ // The changes have been made, do a sanity test, check trigger expressions
+ std::string warning_msg;
+ return client_node_to_add->suite()->check(errorMsg,warning_msg);
+ }
+
+
+ // ADD ======================================================================
+ // Create/Add nodes as needed for a *PARTIAL* match
+ // If the path is /a/b/c/d/e/f it may be that path /a/b already exists
+ // hence we need only create the missing nodes c, d, e, f
+ LOG_ASSERT( serverNode == NULL, "" );
+ node_ptr server_parent;
+ Node* last_client_child = clientNode.get(); // remember the last child
+ Node* client_parent = clientNode->parent();
+ while (client_parent) {
+ server_parent = findAbsNode( client_parent->absNodePath() );
+ if (server_parent ) {
+ break;
+ }
+ last_client_child = client_parent;
+ client_parent = client_parent->parent();
+ }
+ if (server_parent.get() == NULL) {
+ // NOT EVEN A PARTIAL path match, hence move over WHOLE suite, detach from client and add to server
+ node_ptr client_suite_to_add = clientNode->suite()->remove();
+ bool addOk = addChild( client_suite_to_add );
+ LOG_ASSERT( addOk ,"");
+ client_suite_to_add->set_most_significant_state_up_node_tree();
+
+ // The changes have been made, do a sanity test, check trigger expressions
+ std::string warning_msg;
+ return client_suite_to_add->suite()->check(errorMsg,warning_msg);
+ }
+
+
+ // PARTIAL PATH MATCH,
+ LOG_ASSERT( last_client_child ,"");
+ LOG_ASSERT( client_parent ,"");
+ LOG_ASSERT( last_client_child->parent() == client_parent ,"");
+ LOG_ASSERT( client_parent->absNodePath() == server_parent->absNodePath() ,"");
+
+ /// If the child of same name exist we *replace* at the same position otherwise we *add* it to the end
+ size_t client_child_pos = last_client_child->position();
+
+ size_t server_child_pos; // will be set to std::numeric_limits<std::size_t>::max(), if child not found
+ node_ptr server_child = server_parent->findImmediateChild(last_client_child->name(),server_child_pos);
+ if (server_child.get()) {
+
+ // Copy over suspended state
+ if (server_child->isSuspended()) {
+ last_client_child->suspend();
+ }
+
+ // Child of same name exist on the server, hence remove it
+ deleteChild(server_child.get());
+ }
+
+ /// copy over begin/queued status
+ if (server_parent->suite()->begun()) {
+ last_client_child->begin();
+ }
+
+ node_ptr client_node_to_add = last_client_child->remove();
+ bool addOk = server_parent->addChild( client_node_to_add , client_child_pos);
+ LOG_ASSERT( addOk,"" );
+ client_node_to_add->set_most_significant_state_up_node_tree();
+
+ // The changes have been made, do a sanity test, check trigger expressions
+ std::string warning_msg;
+ return client_node_to_add->suite()->check(errorMsg,warning_msg);
+}
+
+void Defs::save_as_checkpt(const std::string& the_fileName,ecf::Archive::Type at) const
+{
+ // only_save_edit_history_when_check_pointing or if explicitly requested
+ save_edit_history_ = true; // this is reset after edit_history is saved
+
+ /// Can throw archive exception
+ ecf::save(the_fileName,*this,at);
+}
+
+void Defs::save_checkpt_as_string(std::string& output) const
+{
+ // only_save_edit_history_when_check_pointing or if explicitly requested
+ save_edit_history_ = true; // this is reset after edit_history is saved
+
+ ecf::save_as_string(output,*this);
+}
+
+void Defs::restore_from_checkpt(const std::string& the_fileName,ecf::Archive::Type at)
+{
+// cout << "Defs::restore_from_checkpt " << the_fileName << "\n";
+
+ if (the_fileName.empty()) return;
+
+ // deleting existing content first. *** Note: Server environment left as is ****
+ clear();
+
+ ecf::restore(the_fileName, (*this), at);
+
+ // Reset the state and modify numbers, **After the restore**
+ state_change_no_ = Ecf::state_change_no();
+ modify_change_no_ = Ecf::modify_change_no();
+
+// cout << "Restored: " << suiteVec_.size() << " suites\n";
+}
+
+void Defs::clear()
+{
+ // Duplicate AST are held in a static map.
+ ExprDuplicate reclaim_cloned_ast_memory;
+
+ // *** Note: Server environment left as is ****
+ suiteVec_.clear();
+ externs_.clear();
+ client_suite_mgr_.clear();
+ state_.setState(NState::UNKNOWN);
+ edit_history_.clear();
+ save_edit_history_ = false;
+ Ecf::incr_modify_change_no();
+}
+
+bool Defs::checkInvariants(std::string& errorMsg) const
+{
+ size_t vecSize = suiteVec_.size();
+ for(size_t s = 0; s < vecSize; s++) {
+ if (suiteVec_[s]->defs() != this) {
+ std::stringstream ss;
+ ss << "Defs::checkInvariants suite->defs() function not correct. Child suite parent ptr not correct\n";
+ ss << "For suite " << suiteVec_[s]->name();
+ errorMsg += ss.str();
+ return false;
+ }
+ if (!suiteVec_[s]->checkInvariants(errorMsg)) {
+ return false;
+ }
+ }
+
+ if (Ecf::server()) {
+ /// The change no should NOT be greater than Ecf::state_change_no()
+
+ if (state_change_no_ > Ecf::state_change_no() ) {
+ std::stringstream ss;
+ ss << "Defs::checkInvariants: state_change_no(" << state_.state_change_no() << ") > Ecf::state_change_no(" << Ecf::state_change_no() << ")\n";
+ errorMsg += ss.str();
+ return false;
+ }
+ if (modify_change_no_ > Ecf::modify_change_no() ) {
+ std::stringstream ss;
+ ss << "Defs::checkInvariants: modify_change_no_(" << modify_change_no_ << ") > Ecf::modify_change_no(" << Ecf::modify_change_no() << ")\n";
+ errorMsg += ss.str();
+ return false;
+ }
+
+ if (flag_.state_change_no() > Ecf::state_change_no() ) {
+ std::stringstream ss;
+ ss << "Defs::checkInvariants: flag.state_change_no()(" << flag_.state_change_no() << ") > Ecf::state_change_no(" << Ecf::state_change_no() << ")\n";
+ errorMsg += ss.str();
+ return false;
+ }
+
+
+ if (state_.state_change_no() > Ecf::state_change_no() ) {
+ std::stringstream ss;
+ ss << "Defs::checkInvariants: state_.state_change_no()(" << state_.state_change_no() << ") > Ecf::state_change_no(" << Ecf::state_change_no() << ")\n";
+ errorMsg += ss.str();
+ return false;
+ }
+
+ if (server_.state_change_no() > Ecf::state_change_no() ) {
+ std::stringstream ss;
+ ss << "Defs::checkInvariants: server_.state_change_no()(" << server_.state_change_no() << ") > Ecf::state_change_no(" << Ecf::state_change_no() << ")\n";
+ errorMsg += ss.str();
+ return false;
+ }
+ }
+ return true;
+}
+
+void Defs::order(Node* immediateChild, NOrder::Order ord)
+{
+ switch (ord) {
+ case NOrder::TOP: {
+ for(std::vector<suite_ptr>::iterator i = suiteVec_.begin(); i != suiteVec_.end(); ++i) {
+ suite_ptr s = (*i);
+ if (s.get() == immediateChild) {
+ suiteVec_.erase(i);
+ suiteVec_.insert(suiteVec_.begin(),s);
+ client_suite_mgr_.update_suite_order();
+ order_state_change_no_ = Ecf::incr_state_change_no();
+ return;
+ }
+ }
+ throw std::runtime_error("Defs::order: TOP, immediate child suite not found");
+ }
+ case NOrder::BOTTOM: {
+ for(std::vector<suite_ptr>::iterator i = suiteVec_.begin(); i != suiteVec_.end(); ++i) {
+ suite_ptr s = (*i);
+ if (s.get() == immediateChild) {
+ suiteVec_.erase(i);
+ suiteVec_.push_back(s);
+ order_state_change_no_ = Ecf::incr_state_change_no();
+ client_suite_mgr_.update_suite_order();
+ return;
+ }
+ }
+ throw std::runtime_error("Defs::order: BOTTOM, immediate child suite not found");
+ }
+ case NOrder::ALPHA: {
+ std::sort(suiteVec_.begin(),suiteVec_.end(),
+ boost::bind(Str::caseInsLess,
+ boost::bind(&Node::name,_1),
+ boost::bind(&Node::name,_2)));
+ order_state_change_no_ = Ecf::incr_state_change_no();
+ client_suite_mgr_.update_suite_order();
+ break;
+ }
+ case NOrder::ORDER: {
+ std::sort(suiteVec_.begin(),suiteVec_.end(),
+ boost::bind(Str::caseInsGreater,
+ boost::bind(&Node::name,_1),
+ boost::bind(&Node::name,_2)));
+ order_state_change_no_ = Ecf::incr_state_change_no();
+ client_suite_mgr_.update_suite_order();
+ break;
+ }
+ case NOrder::UP: {
+ for(size_t t = 0; t < suiteVec_.size();t++) {
+ if ( suiteVec_[t].get() == immediateChild) {
+ if (t != 0) {
+ suite_ptr s = suiteVec_[t];
+ suiteVec_.erase(suiteVec_.begin()+t);
+ t--;
+ suiteVec_.insert(suiteVec_.begin()+t,s);
+ order_state_change_no_ = Ecf::incr_state_change_no();
+ }
+ client_suite_mgr_.update_suite_order();
+ return;
+ }
+ }
+ throw std::runtime_error("Defs::order: UP, immediate child suite not found");
+ }
+ case NOrder::DOWN: {
+ for(size_t t = 0; t < suiteVec_.size();t++) {
+ if ( suiteVec_[t].get() == immediateChild) {
+ if (t != suiteVec_.size()-1) {
+ suite_ptr s = suiteVec_[t];
+ suiteVec_.erase(suiteVec_.begin()+t);
+ t++;
+ suiteVec_.insert(suiteVec_.begin()+t,s);
+ order_state_change_no_ = Ecf::incr_state_change_no();
+ }
+ client_suite_mgr_.update_suite_order();
+ return;
+ }
+ }
+ throw std::runtime_error("Defs::order: DOWN, immediate child suite not found");
+ }
+ }
+}
+
+void Defs::top_down_why(std::vector<std::string>& theReasonWhy) const
+{
+ why(theReasonWhy);
+ size_t theSuiteVecSize = suiteVec_.size();
+ for(size_t s = 0; s < theSuiteVecSize; s++) { suiteVec_[s]->top_down_why(theReasonWhy);}
+}
+
+void Defs::why(std::vector<std::string>& theReasonWhy) const
+{
+ if (isSuspended()) {
+ std::string the_reason = "The server is *not* RUNNING.";
+ theReasonWhy.push_back(the_reason);
+ }
+ else if (state() != NState::QUEUED && state() != NState::ABORTED) {
+ std::stringstream ss;
+ ss << "The definition state(" << NState::toString(state()) << ") is not queued or aborted.";
+ theReasonWhy.push_back(ss.str());
+ }
+ server_.why(theReasonWhy);
+}
+
+std::string Defs::toString() const
+{
+ // Let the Client control the print style
+ std::stringstream ss;
+ ss << this;
+ return ss.str();
+}
+
+// Memento functions
+void Defs::collateChanges(unsigned int client_handle, DefsDelta& incremental_changes) const
+{
+ // Collate any small scale changes to the defs
+ collate_defs_changes_only(incremental_changes);
+
+ if (0 == client_handle) {
+ // small scale changes. Collate changes over all suites.
+ // Suite stores the maximum state change, over *all* its children, this is used by client handle mechanism
+ // and here to avoid traversing down the hierarchy.
+ // ******** We must trap all child changes under the suite. See class SuiteChanged
+ // ******** otherwise some attribute sync's will be missed
+ size_t theSuiteVecSize = suiteVec_.size();
+ for(size_t s = 0; s < theSuiteVecSize; s++) {
+ if (suiteVec_[s]->state_change_no() > incremental_changes.client_state_change_no() ) {
+ // *IF* node/attribute change no > client_state_change_no
+ // *THEN*
+ // Create a memento, and store in incremental_changes_
+ suiteVec_[s]->collateChanges(incremental_changes);
+ }
+ }
+ }
+ else {
+
+ // small scale changes over the suites in our handle, determine what's changed,
+ // relative to each node and attributes client_state_change_no.
+ // *IF* node/attribute change no > client_state_change_no
+ // *THEN*
+ // Create a memento, and store in incremental_changes_
+ client_suite_mgr_.collateChanges(client_handle,incremental_changes);
+ }
+}
+
+void Defs::collate_defs_changes_only(DefsDelta& incremental_changes) const
+{
+ // ************************************************************************************************
+ // determine if defs state changed. make sure this is in sync with defs_only_max_state_change_no()
+ // ************************************************************************************************
+ compound_memento_ptr comp;
+ if (state_.state_change_no() > incremental_changes.client_state_change_no()) {
+ if (!comp.get()) comp = boost::make_shared<CompoundMemento>(Str::ROOT_PATH());
+ comp->add( boost::make_shared<StateMemento>( state_.state()) );
+ }
+ if (order_state_change_no_ > incremental_changes.client_state_change_no()) {
+ if (!comp.get()) comp = boost::make_shared<CompoundMemento>(Str::ROOT_PATH());
+ std::vector<std::string> order; order.reserve(suiteVec_.size());
+ for(size_t i =0; i < suiteVec_.size(); i++) order.push_back( suiteVec_[i]->name());
+ comp->add( boost::make_shared<OrderMemento>( order ) );
+ }
+
+ // Determine if the flag changed
+ if (flag_.state_change_no() > incremental_changes.client_state_change_no()) {
+ if (!comp.get()) comp = boost::make_shared<CompoundMemento>(Str::ROOT_PATH());
+ comp->add( boost::make_shared<FlagMemento>( flag_ ) );
+ }
+
+ // determine if defs server state, currently only watch server state. i.e HALTED, SHUTDOWN, RUNNING
+ if (server_.state_change_no() > incremental_changes.client_state_change_no()) {
+ if (!comp.get()) comp = boost::make_shared<CompoundMemento>(Str::ROOT_PATH());
+ comp->add( boost::make_shared<ServerStateMemento>( server_.get_state() ) );
+ }
+ if (server_.variable_state_change_no() > incremental_changes.client_state_change_no()) {
+ if (!comp.get()) comp = boost::make_shared<CompoundMemento>(Str::ROOT_PATH());
+ comp->add( boost::make_shared<ServerVariableMemento>( server_.user_variables() ) );
+ }
+
+ if (comp.get() ) {
+ incremental_changes.add( comp );
+ }
+}
+
+unsigned int Defs::defs_only_max_state_change_no() const
+{
+ // ************************************************************************************************
+ // make sure this is in sync with collate_defs_changes_only()
+ // ************************************************************************************************
+ unsigned int max_change_no = 0;
+ max_change_no = std::max( max_change_no, state_.state_change_no());
+ max_change_no = std::max( max_change_no, order_state_change_no_);
+ max_change_no = std::max( max_change_no, flag_.state_change_no());
+ max_change_no = std::max( max_change_no, server_.state_change_no());
+ max_change_no = std::max( max_change_no, server_.variable_state_change_no());
+ return max_change_no;
+}
+
+void Defs::set_memento(const StateMemento* memento,std::vector<ecf::Aspect::Type>& aspects) {
+
+#ifdef DEBUG_MEMENTO
+ std::cout << "Defs::set_memento(const StateMemento* memento)\n";
+#endif
+ aspects.push_back(ecf::Aspect::STATE);
+ set_state( memento->state_ );
+}
+
+void Defs::set_memento( const ServerStateMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+#ifdef DEBUG_MEMENTO
+ std::cout << "Defs::set_memento(const ServerStateMemento* memento)\n";
+#endif
+ aspects.push_back(ecf::Aspect::SERVER_STATE);
+ server_.set_state( memento->state_ );
+}
+
+void Defs::set_memento( const ServerVariableMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+#ifdef DEBUG_MEMENTO
+ std::cout << "Defs::set_memento(const ServerVariableMemento* memento)\n";
+#endif
+
+ if (server_.user_variables().size() != memento->serverEnv_.size()) {
+ aspects.push_back(ecf::Aspect::ADD_REMOVE_ATTR);
+ }
+
+ aspects.push_back(ecf::Aspect::SERVER_VARIABLE);
+
+ server_.set_user_variables( memento->serverEnv_);
+}
+
+void Defs::set_memento( const OrderMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+#ifdef DEBUG_MEMENTO
+ std::cout << "Defs::set_memento(const OrderMemento* memento)\n";
+#endif
+ // Order the suites
+
+ // Order nodeVec_ according to memento ordering
+ const std::vector<std::string>& order = memento->order_;
+
+ // NOTE: When we have handles only a small subset of the suites, are returned
+ // Whereas order will always contain all the suites.
+ // Hence we need to handle the case where: order.size() != suiteVec_.size()
+
+ std::vector<suite_ptr> vec; vec.reserve(suiteVec_.size());
+ size_t node_vec_size = suiteVec_.size();
+ for(size_t i = 0; i < order.size(); i++) {
+ for(size_t t = 0; t < node_vec_size; t++) {
+ if (order[i] == suiteVec_[t]->name()) {
+ vec.push_back(suiteVec_[t]);
+ break;
+ }
+ }
+ }
+ if (vec.size() != suiteVec_.size()) {
+ std::cout << "Defs::set_memento could not find all the names\n";
+ return;
+ }
+ aspects.push_back(ecf::Aspect::ORDER);
+ suiteVec_ = vec;
+}
+
+void Defs::set_memento( const FlagMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+
+#ifdef DEBUG_MEMENTO
+ std::cout << "Defs::set_memento(const FlagMemento* memento)\n";
+#endif
+ aspects.push_back(ecf::Aspect::FLAG);
+ flag_.set_flag( memento->flag_.flag() );
+}
+
+// =====================================================================
+
+void Defs::add_edit_history(const std::string& path, const std::string& request)
+{
+ std::map<std::string, std::deque<std::string> >::iterator i = edit_history_.find(path);
+ if (i == edit_history_.end()) {
+ std::deque<std::string> vec; vec.push_back(request);
+ edit_history_.insert( std::make_pair(path,vec) );
+ }
+ else {
+ (*i).second.push_back(request);
+ if ((*i).second.size() > Defs::max_edit_history_size_per_node()) {
+ (*i).second.pop_front();
+ }
+ }
+}
+
+const std::deque<std::string>& Defs::get_edit_history(const std::string& path) const
+{
+ std::map<std::string, std::deque<std::string> >::const_iterator i = edit_history_.find(path);
+ if (i != edit_history_.end()) {
+ return (*i).second;
+ }
+ return empty_edit_history();
+}
+
+const std::deque<std::string>& Defs::empty_edit_history()
+{
+ static std::deque<std::string> static_edit_history;
+ return static_edit_history;
+}
+
+// =====================================================================================
+
+void Defs::notify_delete()
+{
+ // make a copy, to avoid iterating over observer list that is being changed
+ std::vector<AbstractObserver*> copy_of_observers = observers_;
+ for(size_t i = 0; i < copy_of_observers.size(); i++) {
+ copy_of_observers[i]->update_delete(this);
+ }
+
+ /// Check to make sure that the Observer called detach
+ /// We can not call detach ourselves, since the the client needs to
+ /// call detach in the case where the graphical tree is destroyed by user
+ /// In this case the Subject/Node is being deleted.
+ assert(observers_.empty());
+}
+
+void Defs::notify(const std::vector<ecf::Aspect::Type>& aspects)
+{
+ for(size_t i = 0; i < observers_.size(); i++) {
+ observers_[i]->update(this,aspects);
+ }
+}
+
+void Defs::attach(AbstractObserver* obs)
+{
+ observers_.push_back(obs);
+}
+
+void Defs::detach(AbstractObserver* obs)
+{
+ for(size_t i = 0; i < observers_.size(); i++) {
+ if (observers_[i] == obs) {
+ observers_.erase( observers_.begin() + i) ;
+ return;
+ }
+ }
+}
+
+// =====================================================================================
+
+std::ostream& operator<<(std::ostream& os, const Defs* d)
+{
+ if (d) return d->print(os);
+ return os << "DEFS == NULL\n";
+}
+std::ostream& operator<<(std::ostream& os, const Defs& d) { return d.print(os); }
+
+// =========================================================================
+
+DefsHistoryParser::DefsHistoryParser() {
+ Log::get_log_types(log_types_);
+}
+
+void DefsHistoryParser::parse(const std::string& line)
+{
+ size_t pos = line.find("\b");
+ if (pos != std::string::npos) {
+ // keep compatibility with current way of writing history
+ std::string requests = line.substr(pos);
+ Str::split(requests,parsed_messages_,"\b");
+ return;
+ }
+
+ // fallback, split line based on looking for logType like 'MSG:[' | 'LOG:['
+ string::size_type first = find_log(line,0);
+ if (first == std::string::npos) return;
+
+ string::size_type next = find_log(line,first + 4);
+ if (next == std::string::npos ) {
+ parsed_messages_.push_back( line.substr( first ) );
+ return;
+ }
+
+ while (next != std::string::npos) {
+ parsed_messages_.push_back( line.substr( first, next - first ) );
+ first = next;
+ next = find_log(line,first + 4);
+
+ if (next == std::string::npos ) {
+ parsed_messages_.push_back( line.substr( first ) );
+ return;
+ }
+ }
+}
+
+string::size_type DefsHistoryParser::find_log(const std::string& line, string::size_type pos) const
+{
+ for(size_t i = 0; i < log_types_.size(); i++) {
+ std::string log_type = log_types_[i];
+ log_type += ":[";
+ string::size_type log_type_pos = line.find( log_type, pos );
+ if (log_type_pos != std::string::npos) {
+ return log_type_pos;
+ }
+ }
+ return std::string::npos;
+}
diff --git a/ANode/src/Defs.hpp b/ANode/src/Defs.hpp
new file mode 100644
index 0000000..7fb43bf
--- /dev/null
+++ b/ANode/src/Defs.hpp
@@ -0,0 +1,427 @@
+#ifndef DEFS_HPP_
+#define DEFS_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #165 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+// class defs: The root of the node tree. Holds all the suites:
+// Externs are not persisted, why ?:
+// o Externs are un-resolved references to node paths in trigger expressions and inlimits
+// These references can be dynamically generated.
+// o Saves on network bandwidth and checkpoint file size
+//
+// Hence externs are *ONLY* used on the client side.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <ostream>
+#include <set>
+
+#include <boost/noncopyable.hpp>
+#include "boost/date_time/posix_time/posix_time_types.hpp"
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/utility.hpp>
+#include <boost/serialization/vector.hpp> // no need to include <vector>
+#include <boost/serialization/deque.hpp> // no need to include <deque>
+#include <boost/serialization/map.hpp> // no need to include <map>
+#include <boost/serialization/string.hpp> // no need to include <string>
+#include <boost/serialization/shared_ptr.hpp> // no need to include shared_ptr
+#include <boost/foreach.hpp> // used so often just placed here for convenience
+
+#include "ServerState.hpp"
+#include "ClientSuiteMgr.hpp"
+#include "NState.hpp"
+#include "NOrder.hpp"
+#include "NodeFwd.hpp"
+#include "JobCreationCtrl.hpp"
+#include "Suite.hpp"
+#include "CheckPt.hpp"
+#include "Archive.hpp"
+
+class Limit;
+class AbstractObserver;
+namespace ecf { class NodeTreeVisitor; class CalendarUpdateParams; } // forward declare
+
+class Defs : private boost::noncopyable {
+public:
+ static defs_ptr create();
+ Defs();
+ ~Defs();
+
+ bool operator==(const Defs& rhs) const;
+ std::ostream& print(std::ostream&) const ;
+
+ /// State related functions:
+ /// Defs acts like the root node.
+ void set_state(NState::State);
+ void set_state_only(NState::State);
+ NState::State state() const;
+ void set_most_significant_state();
+
+ // The defs does not need suspend()/resume() as this is controlled by the server states
+ // The defs can not schedule jobs when HALTED or SHUTDOWN, i.e. not RUNNING, this is same as suspended
+ bool isSuspended() const { return (server().get_state() != SState::RUNNING); }
+
+ /// Python based checking
+ /// Will create a temporary variable ECF_JOB so the job generation is done to a temporary directory
+ /// For TEST ONLY. Will generated jobs from the given node path
+ /// if the no path defined will generate jobs for all tasks
+ /// Job generation here is INDEPENDENT of the dependencies
+ /// Will call begin(). this updated generated variables which are used
+ /// **during variable substitution in job generation.
+ /// Note: All Tasks that fail to create jobs are returned in jobCtrl
+ /// This is because some Tasks are dummy, they have no associated ecf.
+ /// since they will never be run. This can be determined if they have
+ /// trigger expression like "1 == 0"
+ void check_job_creation( job_creation_ctrl_ptr jobCtrl);
+
+ /// Automatically generated '.ecf' scripts for this definition
+ /// It uses the contents of the definition to parameterise what gets
+ /// generated, and the location of the files. Will throw std::runtime_error for errors
+ /// Assumes: ECF_HOME specified and accessible for all Tasks, otherwise std::runtime_error is raised
+ /// If ECF_FILES is specified, then scripts are generated under this directory
+ /// otherwise ECF_HOME is used. The missing directories are automatically added.
+ /// IF ECF_INCLUDE must be specified.The head.h and tail.h includes will
+ /// use angle brackets, i.e %include <head.h>.
+ /// If ECF_CLIENT_EXE_PATH variable is added, child command will use this, otherwise
+ /// will use ecflow_client, and assume this accessible on the path.
+ /// Will not generated scripts for tasks with ECF_DUMMY_TASK specified.
+ void generate_scripts() const;
+
+ /// Update calendar and time dependent variables. This must be called by the polling mechanism,
+ /// This will *ONLY* have an effect after begin() command has been called
+ ///
+ /// Some suites can elect to ignore calendar updates when the server is not running
+ /// This allows normal and relative time dependencies to be honoured, even if the
+ /// server is started/stopped many times.
+ /// Updating the calendar can lead to state changes in the server. i.e when time related
+ /// dependencies are free'd
+ void updateCalendar( const ecf::CalendarUpdateParams &);
+
+ /// returns the number of times the calendar has been updated. For DEBUG
+ unsigned int updateCalendarCount() const { return updateCalendarCount_;}
+
+ // Implements visitor pattern
+ void accept(ecf::NodeTreeVisitor&); // Node Tree structure does the traversal
+ void acceptVisitTraversor(ecf::NodeTreeVisitor& v); // visitor does traversal
+
+ /// Moves all the data from input defs into this definition. By default
+ /// suite of the same name, are left alone, unless the force option is used.
+ /// i.e with force any suites of the same name will overwrite the suite of
+ /// the same name in this definition.
+ /// externs and server user variables are appended to.
+ /// The input defs will be left with NO suites
+ void absorb(Defs*, bool force);
+
+ std::string name() const { return "/";} /* ABO */
+
+ /// Add a suite to the definition, will throw std::runtime_error if duplicate
+ suite_ptr add_suite(const std::string& name);
+ void addSuite(suite_ptr,size_t position = std::numeric_limits<std::size_t>::max());
+ size_t child_position(const Node*) const;
+
+ /// Externs refer to Nodes or, variable, events, meter, repeat, or generated variable
+ /// not currently defined. If the object(variable, event,meter, repeat, or generate variable name)
+ /// is empty the path can refer to a Task, Family of Suite
+ /// extern can have absolute and relative paths
+ /// Typically used in a trigger or complete expression
+ /// Path can be off the form:
+ /// extern /suite/family
+ /// extern /suite/family:repeat_name
+ /// extern ../family:repeat_name
+ void add_extern(const std::string& nodePath );
+
+ /// Scan the trigger and complete expressions, and automatically add extern's
+ /// i.e where the node paths, and references, to event, meters, edit and repeat variables,
+ /// don't exist, in this defs.
+ void auto_add_externs(bool remove_existing_externs_first = true);
+
+
+ /// Flag the chosen suite, so that it can resolve dependencies. This also
+ /// changes the state of all children to QUEUED/defstatus and initialise the node attributes
+ /// Once a suite is begun, it stays in that state
+ void beginSuite(suite_ptr);
+
+ /// Enables all suites to resolve dependencies
+ /// Once a suite is begun, it stays in that state
+ void beginAll();
+
+ /// Reset the begin state. **** ONLY to be used for test ********
+ void reset_begin();
+
+ /// throws runtime_error if suite cant begin
+ void check_suite_can_begin(suite_ptr) const;
+
+ /// Will requeue all suites. Current used in test only
+ void requeue();
+
+ /// returns true if defs has cron,time,day,date or today time dependencies
+ bool hasTimeDependencies() const;
+
+ /// This function is called when ALL definition has been parsed successfully
+ /// Client Side:: The client side has externs, hence any references to node paths
+ /// in the triggers expression, that are un-resolved and not in
+ /// the extern;s are reported as errors/warnings
+ /// Likewise for inlimit references to Limits
+ /// Server Side:: There are no externs hence, check will report all unresolved
+ /// references as errors.
+ /// Note the AST will be demand loaded in the server. Since they are not persisted.
+ /// we will also resolve inLimit references to Limits. Note inlimit may also
+ /// reference paths, which are externs::
+ // ****** Spirit based AST construction is very expensive ********
+ // ****** Need to replace at some point in future ********
+ bool check(std::string& errorMsg,std::string& warningMsg) const;
+
+ /// Assumes input argument is of the form /suite/family/task, /suite/family/family/task
+ node_ptr findAbsNode(const std::string& pathToNode) const;
+ bool find_extern( const std::string& pathToNode,const std::string& node_attr_name) const;
+ suite_ptr findSuite(const std::string& name) const;
+ const std::vector<suite_ptr>& suiteVec() const { return suiteVec_;}
+
+ /// Given a path, /suite/family/task, find node which is the closest
+ node_ptr find_closest_matching_node(const std::string& pathToNode) const;
+
+ void getAllFamilies(std::vector<Family*>&) const;
+ void getAllNodes(std::vector<Node*>&) const;
+ void getAllTasks(std::vector<Task*>&) const;
+ void getAllSubmittables(std::vector<Submittable*>&) const;
+ void get_all_active_submittables(std::vector<Submittable*>&) const;
+ void get_all_nodes(std::vector<node_ptr>&) const;
+ void get_all_tasks(std::vector<task_ptr>&) const;
+ void get_all_aliases(std::vector<alias_ptr>&) const;
+ void getAllAstNodes(std::set<Node*>&) const;
+ const std::set<std::string>& externs() const { return externs_; }
+
+ /// Get/set for server state.
+ const ServerState& server() const { return server_;}
+ ServerState& set_server() { return server_;}
+
+ /// find all %VAR% and replaces with variable values, returns false on the
+ /// first variable that can't be found, cmd will be left half processed.
+ /// Will search for ECF_MICRO, if not found assumes % as the micro char
+ bool variableSubsitution(std::string& cmd) const { return server_.variableSubsitution(cmd);}
+
+ /// returns true if definition file passes its verification
+ /// If the definition file contains verify attribute, this function will check
+ /// expected number of state changes corresponds to the actual number of state changes
+ bool verification(std::string& errorMsg) const;
+
+ /// generic way of deleting a Node.
+ /// This should always succeed else something is seriously wrong
+ bool deleteChild(Node*);
+
+ /// Adopt the child specified by 'path' from the clientDef.
+ /// If node at path already exists in this instance, it is replaced.
+ /// if createNodesAsNeeded = false, then the path must exist on this defs
+ /// otherwise an error message is issued.
+ /// if createNodesAsNeeded = true, and the path does not exist on this defs
+ /// then the missing path nodes are created.
+ /// In both the client and this defs the trigger references and cleared first.
+ bool replaceChild(const std::string& path,
+ const defs_ptr& clientDef,
+ bool createNodesAsNeeded,
+ bool force,
+ std::string& errormsg);
+
+ // Order the suite
+ void order(Node* immediateChild, NOrder::Order);
+
+ /// determines why the node is not running.
+ void top_down_why(std::vector<std::string>& theReasonWhy) const;
+ void why(std::vector<std::string>& theReasonWhy) const;
+
+ /// Function to save the defs as a checkpoint file. File saved to the file name
+ /// Can throw exception
+ void save_as_checkpt(const std::string& fileName,ecf::Archive::Type = ecf::Archive::default_archive()) const;
+ void save_checkpt_as_string(std::string& check_pt) const;
+
+ /// Function to restore the defs from a check point file.
+ /// If the Defs file has content, this is deleted first, i.e. suites, externs,
+ /// Can throw an exception
+ void restore_from_checkpt(const std::string& fileName,ecf::Archive::Type = ecf::Archive::default_archive());
+
+ /// Delete suites, externs, client handles, reset suspended, and locate state
+ /// etc but Server environment left as is:
+ void clear();
+
+ ecf::Flag& flag() { return flag_;}
+ const ecf::Flag& get_flag() const { return flag_;}
+
+ void add_edit_history(const std::string& path, const std::string& request);
+ const std::deque<std::string>& get_edit_history(const std::string& path) const;
+ void save_edit_history(bool f) const { save_edit_history_ = f ;}
+ static const std::deque<std::string>& empty_edit_history();
+ static size_t max_edit_history_size_per_node() { return 20; }
+
+ /// Memento functions:
+ void collateChanges(unsigned int client_handle,DefsDelta&) const;
+ void set_memento(const StateMemento*,std::vector<ecf::Aspect::Type>& aspects );
+ void set_memento(const ServerStateMemento*,std::vector<ecf::Aspect::Type>& aspects );
+ void set_memento(const ServerVariableMemento*,std::vector<ecf::Aspect::Type>& aspects );
+ void set_memento(const OrderMemento*,std::vector<ecf::Aspect::Type>& aspects );
+ void set_memento(const FlagMemento*,std::vector<ecf::Aspect::Type>& aspects );
+
+ /// Find the max state change number for defs only. This includes:
+ /// o the Defs state.
+ /// o the Defs suspend state
+ /// o the Defs server state.
+ unsigned int defs_only_max_state_change_no() const;
+
+ /// Change functions, used for *transferring* change number, from server to client
+ void set_state_change_no( unsigned int x ) { state_change_no_ = x;}
+ unsigned int state_change_no() const { return state_change_no_; }
+ void set_modify_change_no( unsigned int x ) { modify_change_no_ = x;}
+ unsigned int modify_change_no() const { return modify_change_no_; }
+
+ ClientSuiteMgr& client_suite_mgr() { return client_suite_mgr_;}
+
+ // Provided for python interface
+ std::string toString() const;
+
+ // Will recurse down.
+ bool doDeleteChild(Node* nodeToBeDeleted);
+
+ bool checkInvariants(std::string& errorMsg) const;
+
+ void read_state(const std::string& line,const std::vector<std::string>& lineTokens);
+ void read_history(const std::string& line,const std::vector<std::string>& lineTokens);
+ bool compare_edit_history(const Defs&) const;
+private:
+ void do_generate_scripts( const std::map<std::string,std::string>& override) const;
+ std::string write_state() const;
+ void collate_defs_changes_only(DefsDelta&) const;
+ void setupDefaultEnv();
+ void add_suite_only(suite_ptr, size_t position);
+
+ /// Removes the suite, from defs returned as auto_ptr, asserts if suite does not exist
+ suite_ptr removeSuite(suite_ptr);
+ node_ptr removeChild(Node*);
+ bool addChild( node_ptr, size_t position = std::numeric_limits<std::size_t>::max());
+ friend class Node;
+
+ /// For use by python interface,
+ std::vector<suite_ptr>::const_iterator suite_begin() const { return suiteVec_.begin();}
+ std::vector<suite_ptr>::const_iterator suite_end() const { return suiteVec_.end();}
+ std::set<std::string>::const_iterator extern_begin() const { return externs_.begin();}
+ std::set<std::string>::const_iterator extern_end() const { return externs_.end();}
+ std::vector<Variable>::const_iterator user_variables_begin() const { return server_.user_variables().begin();}
+ std::vector<Variable>::const_iterator user_variables_end() const { return server_.user_variables().end();}
+ std::vector<Variable>::const_iterator server_variables_begin() const { return server_.server_variables().begin();}
+ std::vector<Variable>::const_iterator server_variables_end() const { return server_.server_variables().end();}
+
+ friend void export_Defs();
+
+private:
+ /// Note: restoring form a check point file will reset, defs state and modify numbers
+ unsigned int state_change_no_; // persisted since passed to client, however side effect, is it will be in checkpoint file
+ unsigned int modify_change_no_; // persisted since passed to client, however side effect, is it will be in checkpoint file
+ unsigned int updateCalendarCount_;
+ unsigned int order_state_change_no_; // *NOT* persisted
+ NState state_; // state & change_no, i,e attribute changed
+ ServerState server_;
+ std::vector<suite_ptr> suiteVec_;
+ std::map<std::string, std::deque<std::string> > edit_history_; // path,request
+ mutable bool save_edit_history_; // NOT persisted
+ ecf::Flag flag_;
+
+ ClientSuiteMgr client_suite_mgr_; // NOT persisted
+
+ /// Externs are *NEVER* loaded in the server, since they can be computed and
+ /// save on network band with, and check point file size.
+ std::set<std::string> externs_; // NOT persisted
+
+ friend class SaveEditHistoryWhenCheckPointing;
+
+private:
+ /// Observer notifications Start. Allow client to query if they are in syncing with server
+ void notify_start() { in_notification_ = true; }
+ void notify_end() { in_notification_ = false; }
+ bool in_notification_;
+ std::vector<AbstractObserver*> observers_;
+ friend class ChangeStartNotification;
+ void notify_delete();
+public:
+ void notify(const std::vector<ecf::Aspect::Type>& aspects);
+ void attach(AbstractObserver*);
+ void detach(AbstractObserver*);
+ bool in_notification() const { return in_notification_;}
+
+private:
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/)
+ {
+ ar & state_change_no_;
+ ar & modify_change_no_;
+ ar & updateCalendarCount_;
+ ar & state_;
+ ar & server_;
+ ar & suiteVec_;
+ ar & flag_;
+
+ // only save the edit history when check pointing.
+ if (Archive::is_saving::value) {
+ if (save_edit_history_) {
+ ar & edit_history_;
+ save_edit_history_ = false; // reset
+ }
+ else {
+ std::map<std::string, std::deque<std::string> > empty_edit_history;
+ ar & empty_edit_history;
+ }
+ }
+ else {
+ ar & edit_history_;
+ }
+
+ if (Archive::is_loading::value) {
+ size_t vec_size = suiteVec_.size();
+ for(size_t i = 0; i < vec_size; i++) {
+ suiteVec_[i]->set_defs(this);
+ }
+ }
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, const Defs*);
+std::ostream& operator<<(std::ostream& os, const Defs&);
+
+// =====================================================================
+// This class is used to read the History
+class DefsHistoryParser : private boost::noncopyable {
+public:
+ DefsHistoryParser();
+
+ void parse(const std::string& line);
+ const std::vector<std::string>& parsed_messages() const { return parsed_messages_;}
+
+private:
+
+ std::string::size_type find_log(const std::string& line, std::string::size_type pos) const;
+
+private:
+ std::vector<std::string> log_types_;
+ std::vector<std::string> parsed_messages_;
+};
+
+
+
+// Start notification. End notification automatically signalled, Even if exception raised.
+class ChangeStartNotification : private boost::noncopyable {
+public:
+ ChangeStartNotification(defs_ptr defs) : defs_ptr_(defs) { defs_ptr_->notify_start();}
+ ~ChangeStartNotification() { defs_ptr_->notify_end();}
+private:
+ defs_ptr defs_ptr_;
+};
+
+
+#endif /* DEFS_HPP_ */
diff --git a/ANode/src/DefsDelta.cpp b/ANode/src/DefsDelta.cpp
new file mode 100644
index 0000000..d1aadf3
--- /dev/null
+++ b/ANode/src/DefsDelta.cpp
@@ -0,0 +1,81 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #23 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/bind.hpp>
+#include "DefsDelta.hpp"
+using namespace std;
+
+//#define DEBUG_MEMENTO 1
+
+//===============================================================
+// DefsDelta
+
+/// Defs delta can be re-used. reset all data members
+void DefsDelta::init(unsigned int client_state_change_no)
+{
+ client_state_change_no_ = client_state_change_no;
+
+ server_state_change_no_ = 0;
+ server_modify_change_no_ = 0;
+ compound_mementos_.clear();
+}
+
+
+bool DefsDelta::incremental_sync(defs_ptr client_def, std::vector<std::string>& changed_nodes) const
+{
+ if (!client_def.get()) return false;
+
+ if (client_def->in_notification()) {
+ // For debug: place a break point here: It appear as Change manager observers, has called another client to server command
+ std::cout << "ecflow:ClientInvoker::incremental_sync() called in the middle of notification(server->client sync)\n";
+ std::cout << "It appears that change observer have called *ANOTHER* client->server command in the middle synchronising client definition\n";
+ }
+
+ /// - Sets notification flag, so that observers can also query if they are in the middle of notification.
+ ChangeStartNotification start_notification(client_def);
+
+ // Update the client defs with latest server *handle* based state change/modify number
+ // to keep pace with the state changes. Passed back later on, to get further changes
+ client_def->set_state_change_no( server_state_change_no_);
+ client_def->set_modify_change_no( server_modify_change_no_ );
+
+ try {
+#ifdef DEBUG_MEMENTO
+ std::cout << "DefsDelta::incremental_sync compound_mementos_.size() = " << compound_mementos_.size() << "\n";
+#endif
+ std::for_each(compound_mementos_.begin(),compound_mementos_.end(),
+ boost::bind(&CompoundMemento::incremental_sync,_1,client_def,boost::ref(changed_nodes)));
+ }
+ catch ( std::exception& e) {
+ throw std::runtime_error("Could not apply incremental server changes to client defs, because: " + string(e.what()));
+ }
+
+ // For each compound memento, we should have a changed node,
+ // If the assertion fails, then the sync in the observers, would have called another client->server command in the middle synchronising
+ if ( compound_mementos_.size() != changed_nodes.size()) {
+ std::cout << "DefsDelta::incremental_sync: ERROR **** compound_mementos_.size() " << compound_mementos_.size() << " changed_nodes.size(): " << changed_nodes.size() << " differ.\n";
+ }
+#ifdef DEBUG
+ assert( compound_mementos_.size() == changed_nodes.size()); // FIXME restore for long term GUI test
+#endif
+
+ // return true if there were any changes made
+ return !compound_mementos_.empty();
+}
+
+void DefsDelta::add(compound_memento_ptr memento)
+{
+ compound_mementos_.push_back(memento);
+}
+
diff --git a/ANode/src/DefsDelta.hpp b/ANode/src/DefsDelta.hpp
new file mode 100644
index 0000000..9b057f1
--- /dev/null
+++ b/ANode/src/DefsDelta.hpp
@@ -0,0 +1,88 @@
+#ifndef DEFS_DELTA_HPP_
+#define DEFS_DELTA_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #23 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+// class DefsDelta: holds a list of incremental changes made in the server.
+// This class is created in the server, and transferred to the client
+// The client use it to syncronize with the server, without the need
+// for asking for the full defs.
+//
+// When the client request the incremental changes, it also passes its client_state_change_no.
+// The client_state_change number is used in the server side to determine what's changed.
+// These changes are collated with add() and transferred to the client.
+// The client then calls incremental_sync() which will apply the changes to the client defs
+// so bringing it in sync with the server defs.
+//
+// Note:: updating state_change_no() on the *client side* a no-op() it has no effect
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/serialization/level.hpp>
+#include <boost/serialization/tracking.hpp>
+#include "Memento.hpp"
+
+class DefsDelta : private boost::noncopyable {
+public:
+ ///=========================================================================
+ /// *Server side*
+ DefsDelta(unsigned int client_state_change_no)
+ : client_state_change_no_(client_state_change_no),
+ server_state_change_no_(0),
+ server_modify_change_no_(0) {}
+
+ /// This class can be re-used hence init() should reset all data members
+ void init(unsigned int client_state_change_no);
+
+ /// Add the compound memento, ie. store all memento's for a *given* node.
+ void add(compound_memento_ptr);
+
+ void set_server_state_change_no( unsigned int s) { server_state_change_no_ = s ; }
+ void set_server_modify_change_no( unsigned int s) { server_modify_change_no_ = s ; }
+ unsigned int get_server_state_change_no() const { return server_state_change_no_; }
+ unsigned int get_server_modify_change_no() const { return server_modify_change_no_; }
+
+ ///=========================================================================
+ /// *Client side*
+ /// Applies the mementos to the client defs and record all changed nodes.
+ /// Can raise std::runtime_error.
+ /// Note:: updating state_change_no() on the *client side* has *no effect*
+ bool incremental_sync(defs_ptr client_def, std::vector<std::string>& changed_nodes) const;
+
+
+ /// =========================================================================
+ // The client state change number. Used to determine what's changed
+ unsigned int client_state_change_no() const { return client_state_change_no_;}
+
+ /// return the number of compound mementos
+ size_t size() const { return compound_mementos_.size(); }
+
+private:
+ unsigned int client_state_change_no_; // *no* need to persist since only used on server side
+
+ unsigned int server_state_change_no_;
+ unsigned int server_modify_change_no_;
+ std::vector<compound_memento_ptr> compound_mementos_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & server_state_change_no_;
+ ar & server_modify_change_no_;
+ ar & compound_mementos_;
+ }
+};
+
+// This should ONLY be added to objects that are *NOT* serialised through a pointer
+BOOST_CLASS_IMPLEMENTATION(DefsDelta, boost::serialization::object_serializable)
+BOOST_CLASS_TRACKING(DefsDelta,boost::serialization::track_never);
+
+#endif
diff --git a/ANode/src/EcfFile.cpp b/ANode/src/EcfFile.cpp
new file mode 100644
index 0000000..2650ca3
--- /dev/null
+++ b/ANode/src/EcfFile.cpp
@@ -0,0 +1,1425 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #66 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <set>
+#include <sstream>
+#include <sys/stat.h>
+
+#include "boost/foreach.hpp"
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/algorithm/string/trim.hpp>
+
+#include "EcfFile.hpp"
+#include "Log.hpp"
+#include "Str.hpp"
+#include "Ecf.hpp"
+#include "File.hpp"
+#include "Task.hpp"
+#include "JobsParam.hpp"
+
+namespace fs = boost::filesystem;
+using namespace std;
+using namespace ecf;
+using namespace boost;
+
+//#define DEBUG_ECF_ 1
+//#define DEBUG_PRE_PROCESS 1
+//#define DEBUG_PRE_PROCESS_INCLUDES 1 // be careful with this as it will skew the diffs in test code
+//#define DEBUG_MIGRATE 1 // for TEST ONLY
+
+//#define DEBUG_PRE_PROCESS_OUTPUT 1
+//#define DEBUG_VAR_SUB_OUTPUT 1
+//#define DEBUG_MAN_FILE 1
+
+static const char* T_NOOP = "nopp";
+static const char* T_COMMENT = "comment";
+static const char* T_MANUAL = "manual";
+static const char* T_END = "end";
+static const char* T_ECFMICRO = "ecfmicro";
+static const char* T_INCLUDE = "include";
+static const char* T_INCLUDENOPP = "includenopp";
+
+static void vector_to_string(const std::vector<std::string>& vec, std::string& str)
+{
+ // Determine size of string, to avoid reallocation
+ size_t the_string_size = 0;
+ size_t theSize = vec.size();
+ for(size_t i = 0; i < theSize; i++) { the_string_size += vec[i].size() + 1; } // +1 is for "\n";
+ str.reserve( str.size() + the_string_size);
+
+ // populate string using the vector
+ for(size_t i = 0; i < theSize; i++) {
+ str += vec[i];
+ str += "\n";
+ }
+}
+
+// ==================================================================================
+// Avoid making any data model/defs state changes. Changes like:
+// node_->flag().set(ecf::Flag::NO_SCRIPT);
+// Which will cause a state change.
+// If the script fails then it is up to the calling Task to set this flag
+// This class is also used to extract the scripts/manual, etc form
+// a read only command. hence this class can not make state changes
+// ===================================================================================
+EcfFile::EcfFile( Node* t,
+ const std::string& pathToEcfFileOrCommand,
+ EcfFile::ScriptType script_type
+)
+: node_( t ),
+ script_path_or_cmd_( pathToEcfFileOrCommand ),
+ script_type_( script_type )
+{
+ node_->findParentUserVariableValue(Str::ECF_MICRO(),ecfMicroCache_);
+ if ( ecfMicroCache_.empty() || ecfMicroCache_.size() != 1) {
+ std::stringstream ss;
+ ss << "EcfFile::EcfFile: Node " << t->absNodePath() << " is referencing a invalid ECF_MICRO variable(' " << ecfMicroCache_ << "). ECF_MICRO when overridden, must be a single character.";
+ throw std::runtime_error(ss.str());
+ }
+
+#ifdef DEBUG_ECF_
+ cout << " EcfFile::EcfFile pathToEcfFileOrCommand = " << script_path_or_cmd_ << " script_type = " << script_type << "\n";
+#endif
+}
+
+void EcfFile::manual(std::string& theManual)
+{
+ /// Pre-process the file accessible from the server
+ std::vector<std::string> lines;
+ std::string error_msg;
+ EcfFile::Type file_type = (node_->isSubmittable()) ? EcfFile::SCRIPT : EcfFile::MANUAL ;
+ if (!open_script_file(script_path_or_cmd_, file_type, lines, error_msg)) {
+ std::stringstream ss; ss << "EcfFile::manual: For node " << node_->debugNodePath() << ", failed to open file " << script_path_or_cmd_ << " : " << error_msg;
+ throw std::runtime_error(ss.str());
+ }
+
+ // expand all %includes this will expand %includenopp by enclosing in %nopp %end, will populate jobLines_
+ if (!preProcess(lines,error_msg)) {
+ std::stringstream ss; ss << "EcfFile::manual: For node " << node_->debugNodePath() << ", failed to pre-process file " << script_path_or_cmd_ << " : " << error_msg;
+ throw std::runtime_error(ss.str());
+ }
+
+ // perform variable sub's but don't error if failure
+ try {
+ JobsParam dummy; // create jobs = false, spawn jobs = false
+ variableSubstituition(dummy);
+ }
+ catch (...) {}
+
+ vector<string> theManualLines;
+ if (!extractManual(jobLines_,theManualLines,error_msg)) {
+ std::stringstream ss;
+ ss << "EcfFile::manual: extraction failed for task " << node_->absNodePath() << " " << error_msg;
+ throw std::runtime_error(ss.str());
+ }
+
+ if (theManualLines.empty()) {
+ // There is no %manual -> %end in the file. However this may be .man file for Suites/Family
+ // For this case just include the pre-processed contents as is, ie since the whole file
+ // is the manual
+ if (node_->isNodeContainer()) {
+ vector_to_string(jobLines_,theManual);
+ return;
+ }
+ }
+
+ vector_to_string(theManualLines,theManual);
+}
+
+void EcfFile::script(std::string& theScript) const
+{
+ if ( script_type_ == EcfFile::ECF_FILE) {
+ if (!File::open(script_path_or_cmd_,theScript)) {
+ std::stringstream ss;
+ ss << "EcfFile::script: Could not open script for task/alias " << node_->absNodePath() << " at path " << script_path_or_cmd_;
+ throw std::runtime_error(ss.str());
+ }
+ return;
+ }
+ std::vector<std::string> lines;
+ std::string error_msg;
+ if (!open_script_file(script_path_or_cmd_, EcfFile::SCRIPT, lines, error_msg)) {
+ std::stringstream ss;
+ ss << "EcfFile::script: Could not open script for task/alias " << node_->absNodePath() << " using command " << script_path_or_cmd_;
+ throw std::runtime_error(ss.str());
+ }
+ vector_to_string(lines,theScript);
+}
+
+void EcfFile::pre_process(std::vector<std::string>& user_edit_file, std::string& pre_processed_file)
+{
+ // expand all %includes this will expand %includenopp by enclosing in %nopp %end, will populate jobLines_
+ std::string errormsg;
+ if (!preProcess(user_edit_file,errormsg)) {
+ throw std::runtime_error("EcfFile::pre_process: Failed to pre_process user edit file " + errormsg);
+ }
+
+ vector_to_string(jobLines_,pre_processed_file);
+}
+
+void EcfFile::pre_process(std::string& pre_processed_file)
+{
+ /// Pre-process the ECF file accessible from the server
+ std::vector<std::string> lines;
+ std::string error_msg;
+ if (!open_script_file(script_path_or_cmd_, EcfFile::SCRIPT, lines, error_msg)) {
+ std::stringstream ss;
+ ss << "EcfFile::pre_process: Failed to open file " << script_path_or_cmd_ << " : " << error_msg;
+ throw std::runtime_error(ss.str());
+ }
+
+ // expand all %includes this will expand %includenopp by enclosing in %nopp %end, will populate jobLines_
+ if (!preProcess(lines,error_msg)) {
+ throw std::runtime_error("EcfFile::pre_process: Failed to pre_process: " + error_msg);
+ }
+
+ /// Find Used variables, *after* all %includes expanded, can throw std::runtime_error
+ get_used_variables(pre_processed_file);
+
+ /// Add pre-processed content
+ vector_to_string(jobLines_,pre_processed_file);
+}
+
+void EcfFile::edit_used_variables(std::string& return_script_with_used_variables)
+{
+ std::string errorMsg;
+ std::vector<std::string> lines;
+ if (!open_script_file(script_path_or_cmd_, EcfFile::SCRIPT, lines, errorMsg)) {
+ throw std::runtime_error( "EcfFile::edit_used_variables: Open script failed : " + errorMsg ) ;
+ }
+
+ // Copy the script file, *BEFORE* expanding the includes
+ std::string script;
+ vector_to_string(lines,script);
+
+ // expand all %includes
+ if (!preProcess(lines, errorMsg)) {
+ throw std::runtime_error( "EcfFile::edit_used_variables: PreProcess script failed : " + errorMsg ) ;
+ }
+
+ /// Find Used variables, *after* all %includes expanded, Can throw std::runtime_error
+ get_used_variables(return_script_with_used_variables);
+
+ /// Return Used variables and SCRIPT before pre-processing
+ return_script_with_used_variables += script;
+}
+
+
+const std::string& EcfFile::create_job( JobsParam& jobsParam)
+{
+#ifdef DEBUG_ECF_
+ cout << "EcfFile::createJob task " << node_->absNodePath() << " script_path_or_cmd_ = " << script_path_or_cmd_ << "\n";
+#endif
+
+ // NOTE: When editing pure python jobs, we may have *NO* variable specified, but only user_edit_file
+ // hence whenever we have user_edit_file, we should follow the else part below
+ std::string error_msg;
+ std::vector<std::string> lines;
+ if (jobsParam.user_edit_variables().empty() && jobsParam.user_edit_file().empty()) {
+ /// The typical *NORMAL* path
+ if (!open_script_file(script_path_or_cmd_, EcfFile::SCRIPT, lines, error_msg)) {
+ throw std::runtime_error("EcfFile::create_job: failed " + error_msg );
+ }
+ }
+ else {
+ // *USER* edit, two kinds
+ if (jobsParam.user_edit_file().empty()) {
+ // *USE* user variables, but ECF file accessible from the server
+ if (!open_script_file(script_path_or_cmd_, EcfFile::SCRIPT, lines, jobsParam.errorMsg())) {
+ throw std::runtime_error("EcfFile::create_job: User variables, Could not open script: " + error_msg );
+ }
+ }
+ else {
+ // *USE* the user supplied ECF file *AND* user variables
+ lines = jobsParam.user_edit_file();
+ }
+ }
+
+ // expand all %includes this will expand %includenopp by enclosing in %nopp %end
+ if (!preProcess(lines,error_msg)) {
+ throw std::runtime_error("EcfFile::create_job: pre process failed " + error_msg );
+ }
+
+#ifdef DEBUG_PRE_PROCESS_OUTPUT
+ std::string err;
+ File::create("preProcess" + get_extn(),jobLines_,err);
+#endif
+
+ // _IF_ ECF_CLIENT is specified provide Special support for migration.
+ // The variable ECF_CLIENT is used to specify the path to client exe.
+ // This is then used to replace smsinit,smscomplete, smsevent,smsmeter.smslabel,smsabort
+ std::string clientPath;
+ if (node_->findParentUserVariableValue("ECF_CLIENT", clientPath)) {
+ if (!replaceSmsChildCmdsWithEcf(clientPath,error_msg) ) {
+ throw std::runtime_error("EcfFile::create_job: ECF_CLIENT replacement failed " + error_msg );
+ }
+#ifdef DEBUG_MIGRATE
+ std::string err;
+ File::create("migrate" + get_extn(),jobLines_,err);
+#endif
+ }
+
+ /// Will use *USER* supplied edit variables in preference to node tree variable *IF* supplied
+ /// expand %VAR% or %VAR:sub% & replace %% with %
+ // Allow variable substitution in comment and manual blocks. But if it fails, don't report as an error
+ variableSubstituition(jobsParam);
+
+#ifdef DEBUG_VAR_SUB_OUTPUT
+ std::string err1;
+ File::create("variableSub" + get_extn(),jobLines_,err1);
+#endif
+
+#ifdef DEBUG_MAN_FILE
+ if (!doCreateManFile(error_msg)) {
+ throw std::runtime_error("EcfFile::create_job: manual file creation failed " + error_msg );
+ }
+#endif
+
+ /// Create the user file for tasks, when submitting without aliases, before removing comments
+ if (node_->isTask() && !jobsParam.user_edit_variables().empty()) {
+ doCreateUsrFile();
+ }
+
+ removeCommentAndManual();
+ remove_nopp_end_tokens();
+
+ return doCreateJobFile(jobsParam/* this is only past in for profiling */); // create job on disk
+}
+
+void EcfFile::extract_used_variables(NameValueMap& used_variables_as_map,const std::vector<std::string> &script_lines)
+{
+ // we only process the contents of the FIRST %comment %end
+ bool comment = false;
+ size_t theSize = script_lines.size();
+ for(size_t i=0; i < theSize; ++i) {
+
+ // std::cout << "EcfFile::extract_used_variables found:'" << script_lines[i] << "\n";
+ if (script_lines[i].empty()) continue;
+
+ // take into account micro char during variable substitution
+ string::size_type ecfmicro_pos = script_lines[i].find(Ecf::MICRO());
+ if ( ecfmicro_pos == 0) {
+
+ // We can not do variable substitution between %nopp/%end
+ if (script_lines[i].find(T_COMMENT) == 1) { comment = true; continue;}
+ if (script_lines[i].find(T_NOOP) == 1) { return;}
+ if (script_lines[i].find(T_MANUAL) == 1) { return;}
+ if (script_lines[i].find(T_END) == 1) { return; }
+ }
+
+ if (comment) {
+
+ // expect name = value
+ string::size_type equal_pos = script_lines[i].find("=");
+ if ( equal_pos == string::npos) continue;
+ string name = script_lines[i].substr(0,equal_pos);
+ string value = script_lines[i].substr(equal_pos+1);
+ boost::algorithm::trim(name);
+ boost::algorithm::trim(value);
+
+ //std::cout << " extracted as '" << name << "' = '" << value << "'\n";
+ used_variables_as_map.insert( std::make_pair(name, value) );
+ }
+ }
+}
+
+bool EcfFile::preProcess(std::vector<std::string>& script_lines, std::string& errormsg)
+{
+ /// Clear existing jobLines
+ jobLines_.clear();
+ jobLines_.reserve(512); // estimate for includes
+
+ // get the cached ECF_MICRO variable, typically its one char.
+ string ecfMicro = ecfMicroCache_;
+
+#ifdef DEBUG_PRE_PROCESS
+ cout << " EcfFile::preProcess task:" << node_->absNodePath() << " script_path_or_cmd_=" << script_path_or_cmd_ << " ecfMicro = " << ecfMicro << "\n";
+ for(size_t i=0; i < script_lines.size(); ++i) { cerr << " script_lines[i] = " << i << " " << script_lines[i] << "\n"; }
+#endif
+
+ // include pre-processing on the included file.
+ // Note: include directives _in_ manual/comment should he handled.
+ // only include directives in %nopp/%end are ignored
+ std::set<std::string> globalIncludedFileSet; // test for recursive includes
+ int recursive_count = 0;
+ std::vector<std::string> tokens; // re-use to save memory
+ std::vector<std::string> includeLines; // re-use to save memory
+ std::vector<std::string> included_files;
+
+ // constant until ecfmicro changes, then reset
+ string pp_nopp = ecfMicro; pp_nopp += T_NOOP;
+ string pp_comment = ecfMicro; pp_comment += T_COMMENT;
+ string pp_manual = ecfMicro; pp_manual += T_MANUAL;
+ string pp_end = ecfMicro; pp_end += T_END;
+
+ while (1) {
+
+ std::set<std::string> localIncludedFileSet;
+ bool nopp = false; bool comment = false; bool manual = false;
+ for(size_t i=0; i < script_lines.size(); ++i) {
+
+ const std::string& script_line = script_lines[i];
+
+ jobLines_.push_back(script_line); // copy line
+
+ // For variable substitution % can occur anywhere on the line, for pre -processing of
+ // %ecfmicro,%manual,%comment,%end,%include,%includenopp it must be the very *first* character
+ string::size_type ecfmicro_pos = script_line.find(ecfMicro);
+ if (ecfmicro_pos == string::npos) continue;
+
+ if (!nopp && !comment && !manual) {
+ // For variable substitution '%' can occur anywhere on the line.
+ // Check for Mismatched micro i.e %FRED or %FRED%%
+ if (ecfmicro_pos != 0) {
+ int ecfMicroCount = countEcfMicro( script_line, ecfMicro );
+ if (ecfMicroCount % 2 != 0 ) {
+ std::stringstream ss;
+ ss << "Mismatched ecfmicro(" << ecfMicro << ") count(" << ecfMicroCount << ") '" << script_line << "' in " << script_path_or_cmd_;
+ errormsg += ss.str();
+ dump_expanded_script_file(i,script_lines);
+ return false;
+ }
+ }
+ }
+
+ // %ecfmicro,%manual,%comment,%end,%include,%includenopp it must be the very *first* character
+ if (ecfmicro_pos != 0) continue; //handle 'garbage%include'
+
+#ifdef DEBUG_PRE_PROCESS
+ std::cout << i << ": " << script_line << "\n";
+#endif
+ if (script_line.find(pp_manual) == 0) {
+ if (comment || manual) {
+ std::stringstream ss; ss << "Embedded comments/manuals not supported '" << script_line << "' at " << script_path_or_cmd_;
+ errormsg += ss.str();
+ dump_expanded_script_file(i,script_lines);
+ return false;
+ }
+ manual = true ; continue;
+ }
+ if (script_line.find(pp_comment) == 0) {
+ if (comment || manual) {
+ std::stringstream ss; ss << "Embedded comments/manuals not supported '" << script_line << "' at " << script_path_or_cmd_;
+ errormsg += ss.str();
+ dump_expanded_script_file(i,script_lines);
+ return false;
+ }
+ comment = true ; continue;
+ }
+ if (script_line.find(pp_nopp) == 0) {
+ if (nopp) {
+ std::stringstream ss; ss << "Embedded nopp not supported '" << script_line << "' in " << script_path_or_cmd_;
+ errormsg += ss.str();
+ dump_expanded_script_file(i,script_lines);
+ return false;
+ }
+ nopp = true ; continue;
+ }
+ if (script_line.find(pp_end) == 0) {
+ if (comment) { comment = false; continue;}
+ if (manual) { manual = false; continue;}
+ if (nopp) { nopp = false; continue;}
+ std::stringstream ss;
+ ss << pp_end << " found with no matching %comment | %manual | %nopp at '" << script_line << "' at path " << script_path_or_cmd_;
+ errormsg += ss.str();
+ dump_expanded_script_file(i,script_lines);
+ return false;
+ }
+ if (nopp) continue;
+
+ tokens.clear();
+ Str::split( script_line, tokens );
+
+ // Handle ecfmicro replacement ================================================================================
+ if (script_line.find(T_ECFMICRO) == 1) { // %ecfmicro #
+ // keep %ecfmicro in jobs file later processing, i.e for comments/manuals
+
+ if (tokens.size() < 2) {
+ std::stringstream ss;
+ ss << "ecfmicro does not have a replacement character, in " << script_path_or_cmd_;
+ errormsg += ss.str();
+ return false;
+ }
+
+ // This is typically a single character, however $/£ will be multi-character i.e size 2
+ ecfMicro = tokens[1];
+ if (ecfMicro.size() > 2) {
+ std::stringstream ss;
+ ss << "Expected ecfmicro replacement to be a single character, but found '" << ecfMicro << "' " << ecfMicro.size() << " in file : " << script_path_or_cmd_;
+ errormsg += ss.str();
+ return false;
+ }
+
+ pp_nopp = ecfMicro; pp_nopp += T_NOOP;
+ pp_comment = ecfMicro; pp_comment += T_COMMENT;
+ pp_manual = ecfMicro; pp_manual += T_MANUAL;
+ pp_end = ecfMicro; pp_end += T_END;
+
+ continue;
+ }
+
+ // Handle the includes ===================================================================================
+ if (tokens.size() < 2) continue;
+
+ bool includenopp = (script_line.find(T_INCLUDENOPP) == 1);
+ bool file_to_include = false;
+ if (!includenopp) {
+ // Notice we only do recursive includes for %include
+ file_to_include = (script_line.find(T_INCLUDE) != string::npos);
+ }
+ if (!file_to_include && !includenopp) continue;
+
+ // remove %include since were going to expand it.
+ jobLines_.pop_back();
+ included_files.push_back(script_line);
+
+#ifdef DEBUG_PRE_PROCESS_INCLUDES
+ // Output the includes for debug purposes. Will appear in preProcess.ecf
+ // Note: Will interfere with diff
+ jobLines_.push_back("========== include of " + tokens[1] + " ===========================");
+#endif
+
+ std::string includedFile = getIncludedFilePath(tokens[1], script_line, errormsg);
+ if (!errormsg.empty()) return false;
+ localIncludedFileSet.insert(includedFile);
+#ifdef DEBUG_PRE_PROCESS
+ cout << "EcfFile::preProcess processing " << includedFile << "\n";
+#endif
+
+ includeLines.clear();
+ if (!open_script_file(includedFile, EcfFile::INCLUDE, includeLines, errormsg)) {
+ return false;
+ }
+
+
+ // append included script_lines to jobsLines
+ if (includenopp) jobLines_.push_back(ecfMicro + T_NOOP);
+ std::copy( includeLines.begin(), includeLines.end(), std::back_inserter( jobLines_ ) );
+ if (includenopp) jobLines_.push_back(ecfMicro + T_END);
+ }
+
+
+ if (nopp) {
+ std::stringstream ss;
+ ss << "Unterminated nopp, matching 'end' is missing for " << script_path_or_cmd_;
+ errormsg += ss.str();
+ dump_expanded_script_file(1,script_lines);
+ return false;
+ }
+
+ // Check for recursive includes. some includes like %include <endt.h>
+ // are included many times, but the include is not recursive.
+ // To get round this will use a simple count.
+ BOOST_FOREACH(const string& theInclude, localIncludedFileSet) {
+
+ if (globalIncludedFileSet.find(theInclude) != globalIncludedFileSet.end()) {
+
+ if ( recursive_count > 10) {
+ std::stringstream ss;
+ ss << "Recursive include of file " << theInclude << " for " << script_path_or_cmd_;
+ errormsg += ss.str();
+ return false;
+ }
+ recursive_count++;
+ }
+ else globalIncludedFileSet.insert(theInclude);
+ }
+
+ if (included_files.empty()) break;
+ else {
+ // repeat until no %include left
+ included_files.clear();
+ script_lines = jobLines_;
+ jobLines_.clear();
+ }
+ }
+ return true;
+}
+
+bool EcfFile::open_script_file(
+ const std::string& file_or_cmd,
+ EcfFile::Type type,
+ std::vector<std::string>& lines,
+ std::string& errormsg) const
+{
+#ifdef DEBUG_ECF_
+ std::cout << "EcfFile::open_script_file file(" << file_or_cmd << ") type(" << fileType(type) << ")\n";
+#endif
+ if (file_or_cmd.empty()) {
+ std::stringstream ss;
+ ss << "EcfFile::open_script_file: Could not open ecf " << fileType(type) << " file. Input File/cmd string is empty.";
+ errormsg += ss.str();
+ return false;
+ }
+
+ switch (script_type_) {
+ case ECF_FILE: {
+ if ( ! File::splitFileIntoLines(file_or_cmd, lines) ) {
+ std::stringstream ss; ss << "Could not open " << fileType(type) << " file:" << file_or_cmd;
+ errormsg += ss.str();
+ return false;
+ }
+ break;
+ }
+
+ case ECF_FETCH_CMD: {
+ // Not tested.
+ string theFile ;
+ string theCommand = file_or_cmd; // variables have already been substituted
+ switch (type) {
+ case EcfFile::SCRIPT: { theCommand += " -s "; theFile = node_->name() + get_extn(); break;}
+ case EcfFile::INCLUDE: theCommand += " -i "; break;
+ case EcfFile::MANUAL: { theCommand += " -m "; theFile = node_->name() + get_extn(); break;}
+ case EcfFile::COMMENT: { theCommand += " -c "; theFile = node_->name() + get_extn(); break;}
+ }
+ theCommand += theFile;
+ if (!do_popen(theCommand,type,lines,errormsg)) return false;
+ break;
+ }
+
+ case ECF_SCRIPT_CMD: {
+ switch (type) {
+ case EcfFile::SCRIPT: {
+ if (!do_popen(file_or_cmd,type,lines,errormsg)) return false;
+ break;
+ }
+ case EcfFile::INCLUDE:
+ case EcfFile::MANUAL:
+ case EcfFile::COMMENT:
+ if ( ! File::splitFileIntoLines(file_or_cmd, lines) ) {
+ std::stringstream ss; ss << "Could not open " << fileType(type) << " file:" << file_or_cmd;
+ errormsg += ss.str();
+ return false;
+ }
+ break;
+ }
+ break;
+ }
+ }
+ return true;
+}
+
+bool EcfFile::do_popen(const std::string& the_cmd, EcfFile::Type type, std::vector<std::string>& lines, std::string& errormsg) const
+{
+ FILE *fp = popen(the_cmd.c_str(),"r");
+ if (!fp) {
+ std::stringstream ss;
+ ss << "Could not open " << fileType(type) << " via cmd " << the_cmd << " for task " << node_->absNodePath() << " ";
+ errormsg += ss.str();
+ return false;
+ }
+ char line[LINE_MAX];
+ while( fgets(line,LINE_MAX,fp) ) {
+ lines.push_back(line);
+ // remove any trailing new lines
+ std::string& the_line = lines.back();
+ if (!the_line.empty() && the_line[the_line.size()-1] == '\n') {
+ the_line.erase(the_line.begin() + the_line.size()-1);
+ }
+ }
+ pclose(fp);
+ return true;
+}
+
+std::string EcfFile::fileType(EcfFile::Type t)
+{
+ switch (t) {
+ case EcfFile::SCRIPT: return "script"; break;
+ case EcfFile::INCLUDE: return "include"; break;
+ case EcfFile::MANUAL: return "manual"; break;
+ case EcfFile::COMMENT: return "comment"; break;
+ }
+ assert(false);
+ return string();
+}
+
+static void replace( string::size_type commentPos,
+ std::string& jobLine,
+ const std::string& smsChildCmd,
+ const std::string& ecfEquiv,
+ const std::string& clientPath)
+{
+ string::size_type childPos = jobLine.find(smsChildCmd);
+ if ( childPos != std::string::npos ) {
+ if ( commentPos == std::string::npos) {
+ std::string replace = clientPath;
+ replace += ecfEquiv;
+ Str::replace(jobLine,smsChildCmd,replace);
+ }
+ else if ( childPos < commentPos) {
+ std::string replace = clientPath;
+ replace += ecfEquiv;
+ Str::replace(jobLine,smsChildCmd,replace);
+ }
+ }
+}
+
+bool EcfFile::replaceSmsChildCmdsWithEcf(const std::string& clientPath, std::string& errormsg)
+{
+ // smsinit $$ ---> ECF_CLIENT(value) --init=$$
+ // smscomplete ---> ECF_CLIENT(value)
+ // smsevent eventname ---> ECF_CLIENT(value) --event=eventname
+ // smsmeter metername value ---> ECF_CLIENT(value) --meter=metername value
+ // smslabel value ---> ECF_CLIENT(value) --label=value
+ // smswait expr ---> ECF_CLIENT(value) --wait=expr
+ // smsabort ---> ECF_CLIENT(value) --abort
+ size_t jobLines_size = jobLines_.size();
+ for(size_t i=0; i < jobLines_size; ++i) {
+
+ // ONLY do the replacement if there is no leading comment
+ string::size_type commentPos = jobLines_[i].find("#");
+ replace(commentPos, jobLines_[i], "smsinit", " --init ", clientPath);
+ replace(commentPos, jobLines_[i], "smscomplete"," --complete ", clientPath);
+ replace(commentPos, jobLines_[i], "smsabort", " --abort ", clientPath);
+ replace(commentPos, jobLines_[i], "smsevent", " --event ", clientPath);
+ replace(commentPos, jobLines_[i], "smsmeter", " --meter ", clientPath);
+ replace(commentPos, jobLines_[i], "smslabel", " --label ", clientPath);
+ replace(commentPos, jobLines_[i], "smswait", " --wait ", clientPath);
+ }
+ return true;
+}
+
+void EcfFile::variableSubstituition(JobsParam& jobsParam)
+{
+ // Allow variable substitution in comment and manual blocks.
+ // But if it fails, don't report as an error
+
+ // get the cached ECF_MICRO variable, typically its one char.
+ string ecfMicro = ecfMicroCache_;
+ char microChar = ecfMicro[0];
+
+ // We need a stack to properly implement nopp. This is required since we need to pair
+ // the %end, with nopp. i.e need to handle
+ // %nopp
+ // %comment
+ // %end // this is paired with comment
+ // %end // This is paired with nopp
+ const int NOPP = 0;
+ const int COMMENT = 1;
+ const int MANUAL = 2;
+ std::vector<int> pp_stack;
+ std::vector<std::string> tokens;
+
+ bool nopp = false;
+ size_t jobLines_size = jobLines_.size();
+ for(size_t i=0; i < jobLines_size; ++i) {
+
+ if (jobLines_[i].empty()) continue;
+
+ // take into account micro char during variable substitution
+ string::size_type ecfmicro_pos = jobLines_[i].find(ecfMicro);
+ if (ecfmicro_pos == 0) {
+
+ // We can not do variable substitution between %nopp/%end
+ if (jobLines_[i].find(T_MANUAL) == 1) { pp_stack.push_back(MANUAL); continue; }
+ if (jobLines_[i].find(T_COMMENT) == 1) { pp_stack.push_back(COMMENT); continue; }
+ if (jobLines_[i].find(T_NOOP) == 1) { pp_stack.push_back(NOPP); nopp = true; continue; }
+ if (jobLines_[i].find(T_END) == 1) {
+ if (pp_stack.empty()) throw std::runtime_error("EcfFile::variableSubstituition: failed unpaired %end");
+ int last_directive = pp_stack.back(); pp_stack.pop_back();
+ if (last_directive == NOPP) nopp = false;
+ continue;
+ }
+
+ if (jobLines_[i].find(T_ECFMICRO) == 1) { // %ecfmicro #
+
+ tokens.clear();
+ Str::split( jobLines_[i], tokens );
+ if (tokens.size() < 2) {
+ std::stringstream ss; ss << "ecfmicro does not have a replacement character, in " << script_path_or_cmd_;
+ throw std::runtime_error("EcfFile::variableSubstituition: failed : " + ss.str());
+ }
+ ecfMicro = tokens[1];
+ microChar = ecfMicro[0];
+ continue; // no point in doing variable subs on %ecfmicro ^
+ }
+ }
+ if ( nopp ) continue;
+
+
+ /// For variable substitution % can occur anywhere on the line
+ if (ecfmicro_pos != string::npos) {
+
+ /// In the *NORMAL* flow jobsParam.user_edit_variables() will be EMPTY
+ if ( !node_->variable_substitution( jobLines_[i], jobsParam.user_edit_variables(), microChar ) ) {
+
+ // Allow variable substitution in comment and manual blocks.
+ // But if it fails, don't report as an error
+ int last_directive = -1;
+ if (!pp_stack.empty()) last_directive = pp_stack.back();
+ if ( last_directive == COMMENT || last_directive == MANUAL) continue;
+
+ std::stringstream ss; ss << "EcfFile::variableSubstituition: failed : '" << jobLines_[i] << "'";
+ dump_expanded_script_file( i, jobLines_ );
+ throw std::runtime_error(ss.str());
+ }
+ }
+ }
+}
+
+
+void EcfFile::get_used_variables(std::string& used_variables) const
+{
+ /// Find Used variables, *after* all %includes expanded
+ NameValueMap used_variables_map;
+ std::string errorMsg;
+ if (!get_used_variables(used_variables_map, errorMsg) ) {
+ throw std::runtime_error( "EcfFile::get_used_variables: Extract used variables failed : " + errorMsg ) ;
+ }
+
+ if (!used_variables_map.empty()) {
+
+ // add %comment - edit user variable, %end - ecf user variable
+ used_variables = ecfMicroCache_;
+ used_variables += "comment - ecf user variables\n";
+
+ // ***************************************************************************************
+ // Custom handling of dynamic variables, i.e ECF_TRYNO, ECF_PASS and
+ // any variable that embeds a try number, i.e. ECF_JOB, ECF_JOBOUT
+ // This is required since the try number is *always* incremented *before* job submission,
+ // hence the value extracted from the job file will *not* be accurate, hence we exclude it.
+ // This way at job submission we use the latest/correct value, which is in-sync with JOB OUTPUT
+ // Note: Otherwise the job output will not be in sync
+ //
+ // Custom handling of ECF_PORT,ECF_NODE,ECF_NAME do not show these variables, these variables
+ // including ECF_PASS appear in the script. If the user accidentally edits them,
+ // Child communication with the server will be broken. Hence not shown
+ //
+ // All the above are examples of generated variables, which should not really be edited
+ // The used variables are typically *user* variable *in* the scripts, that user may need
+ // to modify. Hence we have also excluded generated variables SUITE, FAMILY, TASK
+ // ****************************************************************************************
+ std::pair<std::string, std::string> item;
+ BOOST_FOREACH(item, used_variables_map) {
+ if ( item.first.find(Str::ECF_TRYNO()) != std::string::npos) continue;
+ if ( item.first.find(Str::ECF_JOB()) != std::string::npos) continue;
+ if ( item.first.find(Str::ECF_JOBOUT()) != std::string::npos) continue;
+ if ( item.first.find(Str::ECF_PASS()) != std::string::npos) continue;
+ if ( item.first.find(Str::ECF_PORT()) != std::string::npos) continue;
+ if ( item.first.find(Str::ECF_NODE()) != std::string::npos) continue;
+ if ( item.first.find(Str::ECF_NAME()) != std::string::npos) continue;
+
+ // We must use exact match, to avoid user variables like ESUITE,EFAMILY,ETASK
+ if ( item.first == Str::TASK()) continue;
+ if ( item.first == Str::FAMILY()) continue;
+ if ( item.first == "FAMILY1") continue;
+ if ( item.first == Str::SUITE()) continue;
+ used_variables += item.first;
+ used_variables += " = ";
+ used_variables += item.second;
+ used_variables += "\n";
+ }
+
+ used_variables += ecfMicroCache_;
+ used_variables += "end - ecf user variables\n";
+ }
+}
+
+bool EcfFile::get_used_variables(NameValueMap& used_variables, std::string& errormsg) const
+{
+ // get the cached ECF_MICRO variable, typically its one char.
+ string ecfMicro = ecfMicroCache_;
+
+ char microChar = ecfMicro[0];
+
+ // We need a stack to properly implement nopp. This is required since we need to pair
+ // the %end, with nopp. i.e need to handle
+ // %nopp
+ // %comment
+ // %end // this is paired with comment
+ // %end // This is paired with nopp
+ const int NOPP = 0;
+ const int COMMENT = 1;
+ const int MANUAL = 2;
+ std::vector<int> pp_stack;
+
+ bool nopp = false;
+ std::stringstream ss;
+ std::vector<std::string> tokens;
+
+ size_t job_lines_size = jobLines_.size();
+ for(size_t i=0; i < job_lines_size; ++i) {
+
+ if (jobLines_[i].empty()) continue;
+
+ // take into account micro char during variable substitution
+ string::size_type ecfmicro_pos = jobLines_[i].find(ecfMicro);
+ if (ecfmicro_pos == 0) {
+
+ // We can not do variable substitution between %nopp/%end
+ if (jobLines_[i].find(T_MANUAL) == 1) { pp_stack.push_back(MANUAL); continue; }
+ if (jobLines_[i].find(T_COMMENT) == 1) { pp_stack.push_back(COMMENT); continue; }
+ if (jobLines_[i].find(T_NOOP) == 1) { pp_stack.push_back(NOPP); nopp = true; continue; }
+ if (jobLines_[i].find(T_END) == 1) {
+ if (pp_stack.empty()) throw std::runtime_error("EcfFile::get_used_variables: failed unpaired %end");
+ int last_directive = pp_stack.back(); pp_stack.pop_back();
+ if (last_directive == NOPP) nopp = false;
+ continue;
+ }
+
+ if (!nopp && jobLines_[i].find(T_ECFMICRO) == 1) { // %ecfmicro #
+
+ tokens.clear();
+ Str::split( jobLines_[i], tokens );
+ if (tokens.size() < 2) {
+ std::stringstream ss; ss << "ecfmicro does not have a replacement character, in " << script_path_or_cmd_;
+ throw std::runtime_error("EcfFile::get_used_variables: failed : " + ss.str());
+ }
+ ecfMicro = tokens[1];
+ microChar = ecfMicro[0];
+ continue;
+ }
+ }
+ if ( nopp ) continue;
+
+
+ if (ecfmicro_pos != string::npos) {
+
+ /// *Note:* currently this modifies jobLines_[i]
+ std::string line_copy = jobLines_[i]; // avoid modifying the jobs Lines, end up doing variable substitution
+ if ( !node_->find_all_used_variables( line_copy, used_variables, microChar ) ) {
+
+ // Allow variable substitution in comment and manual blocks.
+ // But if it fails, dont report as an error
+ int last_directive = -1;
+ if (!pp_stack.empty()) last_directive = pp_stack.back();
+ if ( last_directive == COMMENT || last_directive == MANUAL) continue;
+
+ ss << "Variable find failed for '" << jobLines_[i] << "' microChar='" << microChar << "' ";
+ dump_expanded_script_file( i, jobLines_ );
+ }
+ }
+ }
+
+ // Append to error message if any
+ errormsg += ss.str();
+
+ return errormsg.empty();
+}
+
+
+const std::string& EcfFile::doCreateJobFile(JobsParam& jobsParam) const
+{
+ if ( jobLines_.size() > 1 ) {
+ // Guard against ecf file that exist's but is empty,
+ // no point in creating empty job files for them
+
+ // ECF_JOB is used with ECF_JOB_CMD when submitting a job.
+ // First look for a user variable of name ECF_JOB, otherwise look for
+ // the generated variable, hence this should never fail.
+ // *This* assumes that:
+ // a/ if the user has overiden ECF_JOB then it has been specified at the task level
+ // Otherwise findParentVariableValue will find the generated ECF_JOB on the task
+ // b/ The value of the user variable has a valid directory paths and job file name
+ // c/ The user will lose the try number.
+ std::string ecf_job;
+ if (!node_->findParentVariableValue(Str::ECF_JOB(), ecf_job)) {
+ LOG_ASSERT( !ecf_job.empty() ,"EcfFile::doCreateJobFile: ECF_JOB should have been generated, program error");
+ }
+
+ // *** The location of the ECF_ file may not always be the same as the location
+ // *** of the job file. Job file location is specified by ECF_JOB
+ //cout << "EcfFile::createJob ecf " << script_path_or_cmd_ << " ECF_JOB(" << ecf_job << ")\n";
+
+ if (!File::createMissingDirectories(ecf_job)) {
+ std::stringstream ss;
+ ss << "EcfFile::doCreateJobFile: Could not create missing directories for ECF_JOB " << ecf_job << " File system full?";
+ throw std::runtime_error(ss.str());
+ }
+
+ // Create the jobs file.
+ std::string error_msg;
+ if (!File::create(ecf_job, jobLines_,error_msg)) {
+ std::stringstream ss;
+ ss << "EcfFile::doCreateJobFile: Could not create job file " << ecf_job << " " << error_msg << " File system full?";
+ throw std::runtime_error(ss.str());
+ }
+
+ // make the job file executable
+ if ( chmod( ecf_job.c_str(), 0755 ) != 0 ) {
+ std::stringstream ss;
+ ss << "EcfFile::doCreateJobFile: Could not make job file " << ecf_job << " executable by using chmod";
+ throw std::runtime_error(ss.str());
+ }
+
+ // record job size, for placement into log files
+ size_t job_output_size = 0;
+ size_t jobLines_size = jobLines_.size();
+ for(size_t i = 0; i < jobLines_size; ++i) job_output_size += jobLines_[i].size();
+ job_output_size += jobLines_size; // take into account new lines for each line of output
+ job_size_ = "job_size:";
+ job_size_ += boost::lexical_cast<std::string>(job_output_size);
+ return job_size_;
+ }
+
+ std::stringstream ss;
+ ss << "EcfFile::doCreateJobFile: The ecf file '" << script_path_or_cmd_ << "' that is associated with task '" << node_->absNodePath() << "' is empty";
+ throw std::runtime_error(ss.str());
+}
+
+boost::filesystem::path EcfFile::file_creation_path() const
+{
+ return fs::path(script_or_job_path());
+}
+
+std::string EcfFile::script_or_job_path() const
+{
+ if (script_type_ == ECF_FILE) return script_path_or_cmd_;
+
+ // ECF_FETCH or ECF_SCRIPT_CMD
+ std::string ecf_job;
+ (void)node_->findParentVariableValue(Str::ECF_JOB(), ecf_job);
+ return ecf_job;
+}
+
+bool EcfFile::doCreateManFile( std::string& errormsg)
+{
+ vector<string> manFile;
+ if (!extractManual(jobLines_,manFile,errormsg)) {
+ return false;
+ }
+ if ( !manFile.empty() ) {
+
+ // find the directory associated with job file and place Man file there.
+ fs::path script_file_path = file_creation_path();
+ fs::path parent_path = script_file_path.parent_path();
+ if ( fs::is_directory( parent_path ) ) {
+
+ fs::path theManFilePath( parent_path.string() + '/' + node_->name() + File::MAN_EXTN() );
+
+ // cout << "EcfFile::doCreateManFile job " << manFile.string() << "\n";
+ if (!File::create(theManFilePath.string(),manFile,errormsg)) return false;
+ }
+ else {
+ std::stringstream ss;
+ ss << "man file creation failed. The path '" << script_file_path.parent_path() << "' is not a directory";
+ errormsg += ss.str();
+ return false;
+ }
+ }
+ return true;
+}
+
+
+void EcfFile::doCreateUsrFile() const
+{
+ // find the directory associated with ecf file and place .usr file there.
+ fs::path script_file_path = file_creation_path();
+ fs::path parent_path = script_file_path.parent_path();
+ if ( fs::is_directory( parent_path ) ) {
+
+ fs::path theUsrFilePath( parent_path.string() + '/' + node_->name() + File::USR_EXTN() );
+
+ // cout << "EcfFile::doCreateUsrFile job " << theUsrFilePath.string() << "\n";
+ std::string error_msg;
+ if (!File::create(theUsrFilePath.string(),jobLines_,error_msg)) {
+ throw std::runtime_error("EcfFile::doCreateUsrFile: file creation failed : " + error_msg);
+ }
+ }
+ else {
+ std::stringstream ss;
+ ss << "EcfFile::doCreateUsrFile: file creation failed. The path '" << script_file_path.parent_path() << "' is not a directory";
+ throw std::runtime_error(ss.str());
+ }
+}
+
+
+bool EcfFile::extractManual(const std::vector< std::string >& lines,
+ std::vector< std::string >& theManualLines,
+ std::string& errormsg) const
+{
+ // Note: we have already done pre-processing, ie since the manual is obtained after
+ // all the includes have been pre-procssed, hence most errors should have been caught
+ // get the cached ECF_MICRO variable, typically its one char.
+ string ecfMicro = ecfMicroCache_;
+ std::vector<std::string> tokens;
+
+ bool add = false;
+ for (std::vector< std::string >::const_iterator i = lines.begin(); i!= lines.end(); ++i){
+ if ( (*i).find(ecfMicro) == 0) {
+ if ( (*i).find( T_MANUAL ) == 1 ) { add = true; continue; }
+ if ( add && (*i).find( T_END ) == 1 ) { add = false; continue; }
+
+ if ((*i).find(T_ECFMICRO) == 1) { // %ecfmicro #
+ tokens.clear();
+ Str::split( (*i), tokens );
+ if (tokens.size() < 2) {
+ std::stringstream ss; ss << "ecfmicro does not have a replacement character, in " << script_path_or_cmd_;
+ errormsg += ss.str();
+ return false;
+ }
+ ecfMicro = tokens[1];
+ if (ecfMicro.size() > 2) {
+ std::stringstream ss; ss << "Expected ecfmicro replacement to be a single character, but found '" << ecfMicro << "' " << ecfMicro.size() << " in file : " << script_path_or_cmd_;
+ errormsg += ss.str();
+ return false;
+ }
+ continue;
+ }
+ }
+ if (add) { theManualLines.push_back(*i); }
+ }
+ if (add) {
+ std::stringstream ss; ss << "Unterminated manual. Matching 'end' is missing, for " << script_path_or_cmd_;
+ errormsg += ss.str();
+ dump_expanded_script_file(1,lines);
+ return false;
+ }
+ return true;
+}
+
+std::string EcfFile::getIncludedFilePath( const std::string& includedFile,
+ const std::string& line,
+ std::string& errormsg)
+{
+ // Include can have following format:
+ // %include /tmp/file.name -> /tmp/filename
+ // %include file.name -> filename
+ // %include "../file.name" -> script_file_location/../file.name
+ // %include "./file.name" -> script_file_location/./file.name
+ // %include "file.name" -> %ECF_HOME%/%SUITE%/%FAMILY%/filename
+ // %include <file.name> -> %ECF_INCLUDE%/filename
+ // When ECF_INCLUDE -> path1:path2:path3
+ // %include <file.name> -> path1/filename || path2/filename || path3/filename
+ //
+ // %include <file.name> -> ECF_HOME/filename
+
+ std::string the_include_file = includedFile.substr( 1, includedFile.size() - 2 );
+ if ( includedFile.size() >=2 && includedFile[1] == '/') {
+ // filename starts with '/' no interpretation return as in
+ // %include </home/ecf/fred.ecf>
+ // %include "/home/ecf/fred.ecf"
+ return the_include_file;
+ }
+
+ std::stringstream ss;
+ if ( includedFile[0] == '<' ) {
+ // %include <filename> can be one of:
+ // o When ECF_INCLUDE is a single path -> path1/filename
+ // o When ECF_INCLUDE is a multi path -> path1:path2:path3 -> ECFLOW-261
+ // -> path1/filename || path2/filename || path3/filename
+ // o ECF_HOME/filename
+ std::string ecf_include;
+ if (node_->findParentUserVariableValue( Str::ECF_INCLUDE() , ecf_include ) && !ecf_include.empty() ) {
+
+ // if ECF_INCLUDE is a set a paths, search in order. i.e like $PATH
+ if (ecf_include.find(':') != std::string::npos) {
+ std::vector<std::string> include_paths;
+ Str::split(ecf_include,include_paths,":");
+ for(size_t i =0; i < include_paths.size();i++) {
+ ecf_include.clear();
+ ecf_include = include_paths[i];
+ ecf_include += '/';
+ ecf_include += the_include_file;
+
+ // Don't rely on hard coded paths. Added for testing, but could be generally useful
+ // since in test scenario ECF_INCLUDE is defined relative to $ECF_HOME
+ node_->variable_dollar_subsitution(ecf_include);
+
+ if (fs::exists(ecf_include)) return ecf_include;
+ }
+ }
+ else {
+ ecf_include += '/';
+ ecf_include += the_include_file;
+ node_->variable_dollar_subsitution(ecf_include);
+ if (fs::exists(ecf_include)) return ecf_include;
+ }
+
+ // ECF_INCLUDE is specified *BUT* the file does *NOT* exist, Look in ECF_HOME
+ }
+
+ // WE get HERE *if* ECF_INCLUDE not specified, or if specified but file *not found*
+ ecf_include.clear();
+ node_->findParentVariableValue( Str::ECF_HOME() , ecf_include );
+ if (ecf_include.empty()) {
+ ss << "ECF_INCLUDE/ECF_HOME not specified, for task " << node_->absNodePath() << " at " << line;
+ errormsg += ss.str();
+ return string();
+ }
+
+ ecf_include += '/';
+ ecf_include += the_include_file;
+
+ return ecf_include;
+ }
+ else if ( includedFile[0] == '"' ) {
+
+ // we have two forms: "head.h" & "../head.h"
+
+ // ECFLOW-274 need to allow:
+ // - %include "../fred.h" # this one directory up
+ // - %include "./fred.h" # this is at the same level as script
+ std::string path;
+ if ( includedFile.find("./") == 1 || includedFile.find("../") == 1) {
+ // remove the leading and trailing '"'
+ std::string the_included_file = includedFile;
+ Str::removeQuotes(the_included_file);
+
+ // Get the root path, i.e. script_or_job_path() is of the form "/user/home/ma/mao/course/t1.ecf || /user/home/ma/mao/course/t1.job"
+ // we need "/user/home/ma/mao/course/"
+ std::string the_script_or_job_path = script_or_job_path();
+ std::string::size_type last_slash = the_script_or_job_path.rfind("/");
+ if (last_slash != std::string::npos) {
+ path = the_script_or_job_path.substr( 0, last_slash + 1 );
+ path += the_included_file;
+ // std::cout << "path == " << path << "\n";
+ return path;
+ }
+ }
+
+ // include contents of %ECF_HOME%/%SUITE%/%FAMILY%/filename
+ node_->findParentUserVariableValue( Str::ECF_HOME() , path);
+ if ( path.empty() ) {
+ ss << "ECF_HOME not specified, for task " << node_->absNodePath() << " at " << line;
+ errormsg += ss.str();
+ return string();
+ }
+ path += '/';
+ std::string suite;
+ node_->findParentVariableValue( "SUITE" , suite); // SUITE is a generated variable
+ if ( suite.empty() ) {
+ ss << "SUITE not specified, for task " << node_->absNodePath() << " at " << line;
+ errormsg += ss.str();
+ return string();
+ }
+ path += suite;
+ path += '/';
+ std::string family;
+ node_->findParentVariableValue( "FAMILY" , family); // FAMILY is a generated variable
+ if ( family.empty() ) {
+ ss << "FAMILY not specified, for task " << node_->absNodePath() << " at " << line;
+ errormsg += ss.str();
+ return string();
+ }
+ path += family;
+ path += '/';
+ path += the_include_file ; // "filename"
+ return path;
+ }
+
+ // File either has an absolute pathname or is in the current working dir.
+ // include file name as is, from current working directory
+ return includedFile;
+}
+
+void EcfFile::removeCommentAndManual()
+{
+ // get the cached ECF_MICRO variable, typically its one char.
+ string ecfMicro = ecfMicroCache_;
+
+ // We need a stack to properly implement nopp. This is required since we need to pair
+ // the %end, with nopp. i.e need to handle
+ // %nopp
+ // %comment
+ // %end // this is paired with comment
+ // %end // This is paired with nopp
+ const int NOPP = 0;
+ const int COMMENT = 1;
+ const int MANUAL = 2;
+ bool nopp = false;
+ bool erase = false;
+ std::vector<int> pp_stack;
+ std::vector<std::string> tokens;
+
+ for(std::vector<std::string>::iterator i=jobLines_.begin(); i!=jobLines_.end(); ++i) {
+
+ // take into account micro char during removal of comment/manual
+ string::size_type ecfmicro_pos = (*i).find(ecfMicro);
+ if (ecfmicro_pos == 0) {
+
+ // We can not remove comments/manuals between %nopp/%end
+ if ((*i).find(T_MANUAL) == 1) {
+ pp_stack.push_back(MANUAL);
+ if (nopp) continue;
+
+ // cerr << "EcfFile::removeCommentAndManual erase = " << erase << " " << *i << "\n";
+ jobLines_.erase( i-- ); // remove %manual
+ if (erase) {
+ std::stringstream ss; ss << "EcfFile::removeCommentAndManual: Embedded manuals are not allowed in " << script_path_or_cmd_;
+ throw std::runtime_error( ss.str() );
+ }
+ erase = true;
+ continue;
+ }
+
+ if ((*i).find(T_COMMENT) == 1) {
+ pp_stack.push_back(COMMENT);
+ if (nopp) continue;
+
+ // cerr << "EcfFile::removeCommentAndManual erase = " << erase << " " << *i << "\n";
+ jobLines_.erase( i-- ); // remove %comment
+ if (erase) {
+ std::stringstream ss; ss << "EcfFile::removeCommentAndManual: Embedded comments are not allowed in " << script_path_or_cmd_;
+ throw std::runtime_error( ss.str() );
+ }
+ erase = true;
+ continue;
+ }
+
+ if ((*i).find(T_NOOP) == 1) { pp_stack.push_back(NOPP); nopp = true; continue; }
+
+ if ((*i).find(T_END) == 1) {
+ if (pp_stack.empty()) throw std::runtime_error("EcfFile::removeCommentAndManual: failed unpaired %end");
+ int last_directive = pp_stack.back(); pp_stack.pop_back();
+ if (last_directive == NOPP) nopp = false;
+ else {
+// cerr << "EcfFile::removeCommentAndManual erase = " << erase << " " << *i << "\n";
+ if (erase) {
+ jobLines_.erase( i-- ); // remove %end associated with %comment and %manual
+ erase = false;
+ }
+ }
+ continue;
+ }
+
+ if (!nopp && (*i).find(T_ECFMICRO) == 1) {
+
+ tokens.clear();
+ Str::split( (*i), tokens );
+ if (tokens.size() < 2) {
+ std::stringstream ss; ss << "ecfmicro does not have a replacement character, in " << script_path_or_cmd_;
+ throw std::runtime_error("EcfFile::removeCommentAndManual: failed " + ss.str());
+ }
+ ecfMicro = tokens[1];
+ }
+ }
+ if ( nopp ) continue;
+
+ // remove all line between %comment and %end | %manual and %end
+ if (erase) {
+ jobLines_.erase( i-- );
+ }
+ }
+
+ if (erase) {
+ std::stringstream ss;
+ ss << "Unterminated comment/manual. Matching 'end' is missing, in " << script_path_or_cmd_;
+ throw std::runtime_error("EcfFile::removeCommentAndManual: failed " + ss.str());
+ }
+}
+
+void EcfFile::remove_nopp_end_tokens()
+{
+ // get the cached ECF_MICRO variable, typically its one char.
+ string ecfMicro = ecfMicroCache_;
+
+ // We need a stack to properly implement nopp. This is required since we need to pair
+ // the %end, with nopp. i.e need to handle
+ // %nopp
+ // %comment
+ // %end // this is paired with comment **** this should stay ****
+ // %end // This is paired with nopp **** this should be deleted ****
+ const int NOPP = 0;
+ const int COMMENT = 1;
+ const int MANUAL = 2;
+ std::vector<int> pp_stack;
+ std::vector< std::string > tokens;
+ bool nopp = false;
+ bool erase = false;
+
+ for(std::vector<std::string>::iterator i=jobLines_.begin(); i!=jobLines_.end(); ++i) {
+
+ string::size_type ecfmicro_pos = (*i).find(ecfMicro);
+ if ( ecfmicro_pos == 0) {
+
+ if ((*i).find(T_MANUAL) == 1) { pp_stack.push_back(MANUAL); continue; }
+ if ((*i).find(T_COMMENT) == 1) { pp_stack.push_back(COMMENT); continue; }
+ if ((*i).find(T_END) == 1) {
+ if (pp_stack.empty()) throw std::runtime_error("EcfFile::remove_nopp_end_tokens: failed unpaired %end");
+ int last_directive = pp_stack.back(); pp_stack.pop_back();
+ if (last_directive == NOPP) {
+ nopp = false;
+ jobLines_.erase( i-- ); // remove %end associated with %nopp
+ erase = false;
+ }
+ continue;
+ }
+ if ((*i).find(T_NOOP) == 1) {
+ pp_stack.push_back(NOPP); nopp = true;
+ jobLines_.erase( i-- ); // remove %nopp
+ if (erase) {
+ std::stringstream ss; ss << "Embedded nopp are not allowed " << script_path_or_cmd_;
+ throw std::runtime_error("EcfFile::remove_nopp_end_tokens: failed " + ss.str());
+ }
+ erase = true;
+ continue;
+ }
+ if (!nopp && (*i).find(T_ECFMICRO) == 1) { // %ecfmicro #
+
+ tokens.clear();
+ Str::split( *i, tokens );
+ if (tokens.size() < 2) {
+ std::stringstream ss;
+ ss << "ecfmicro does not have a replacement character, in " << script_path_or_cmd_;
+ throw std::runtime_error("EcfFile::remove_nopp_end_tokens: failed " + ss.str());
+ }
+
+ ecfMicro = tokens[1]; // override ecfMicro char
+ jobLines_.erase( i-- ); // remove %ecfmicro &
+ continue;
+ }
+ }
+ }
+
+ if (erase) {
+ std::stringstream ss;
+ ss << "Unterminated nopp. Matching 'end' is missing, in " << script_path_or_cmd_;
+ throw std::runtime_error("EcfFile::remove_nopp_end_tokens: failed " + ss.str());
+ }
+}
+
+int EcfFile::countEcfMicro(const std::string& line, const std::string& ecfMicro)
+{
+ if (line.find("#") != string::npos) {
+ // ignore ecfmicro character in comments
+ return 0;
+ }
+
+ /// Pound char could be more than one char ?
+ int count = 0;
+ if ( !ecfMicro.empty()) {
+ const char theChar = ecfMicro[0];
+ size_t end = line.size();
+ for(size_t i = 0; i < end; ++i) {
+ if (line[i] == theChar) {
+ count++;
+ }
+ }
+ }
+ // cerr << "line " << line << " count = " << count << "\n";
+ return count;
+}
+
+void EcfFile::dump_expanded_script_file(size_t i, const std::vector<std::string>& lines)
+{
+#ifdef DEBUG_PRE_PROCESS
+ if (i != 0) std::cout << "\nSee file tmp.ecf around line number " << i-1 << "\n";
+ std::string err;
+ if (!File::create("tmp" + get_extn(),lines,err)) std::cout << "Could not create file tmp.ecf\n";
+#endif
+}
+
+/// returns the extension, i.e for task->.ecf for alias->.usr
+const std::string& EcfFile::get_extn() const
+{
+ Submittable* task_or_alias = node_->isSubmittable();
+ if (task_or_alias) return task_or_alias->script_extension();
+ else {
+ std::stringstream ss; ss << "EcfFile::get_extn(): Can only return extension for task/alias but found " << node_->debugNodePath();
+ throw std::runtime_error(ss.str());
+ }
+ return Str::EMPTY();
+}
diff --git a/ANode/src/EcfFile.hpp b/ANode/src/EcfFile.hpp
new file mode 100644
index 0000000..c9ada94
--- /dev/null
+++ b/ANode/src/EcfFile.hpp
@@ -0,0 +1,118 @@
+#ifndef ECF_FILE_HPP_
+#define ECF_FILE_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #23 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include "NodeFwd.hpp"
+
+/// This class is used in the pre-processing of files( .ecf or .usr or .man typically)
+/// It is used to to create the job file.
+///
+///
+/// Please note the %manual is only created on request from the file cmd.
+/// Even then it is extracted as a string. i.e. no .man file is
+/// created. This is left to the client.
+/// When returning the manual we pre-process the files first
+///
+/// However for testing purpose this capability may be retained.
+class EcfFile {
+public:
+ enum ScriptType { ECF_FILE, // Look for .ecf file, uses default algorithm to find %includes
+ ECF_FETCH_CMD, // pre-process output of ECF_FETCH, all %includes use same command
+ ECF_SCRIPT_CMD // pre-process output of ECF_SCRIPT_CMD, uses default algorithm to find %includes
+ };
+
+ /// use default copy constructor, assignment, destructor
+ /// ECF_FETCH is used obtain the script from running a command i.e.
+ /// from the version control system. This has not been implemented yet.
+ EcfFile(Node*, const std::string& path_to_script_or_fetch_cmd, EcfFile::ScriptType = ECF_FILE );
+
+ // The path to the ecf file, empty path means that ecf file could not be located
+ bool valid() const { return !script_path_or_cmd_.empty();}
+
+ /// This function will return the contents of %manual -> %end for the input file
+ /// It will pre-process the file, then extract the manual form all the pre-processed files
+ /// Will throw std::runtime_error for errors
+ void manual(std::string& theManual);
+
+ /// returns the script
+ /// Will throw std::runtime_error for errors
+ void script(std::string& theScript) const;
+
+ /// Create the job file from with script of a task or alias.
+ /// Note: the location of the ecf file may not be the same as the job file
+ /// For creating the job we must use ECF_JOB
+ ///
+ /// _IF_ ECF_CLIENT is specified provide Special support for migration. TEST ONLY
+ /// The variable ECF_CLIENT is used to specify the path to client exe.
+ /// This is then used to replace smsinit,smscomplete, smsevent,smsmeter.smslabel,smsabort
+ /// This function will start the pre processing
+ /// Will throw std::runtime_error for errors
+ const std::string& create_job( JobsParam&);
+
+ /// Process the script file, to add all the used variables, add the start of the file
+ /// between %comment %end, The augmented script is returned in file_with_used_variables
+ /// Will throw std::runtime_error for errors
+ void edit_used_variables(std::string& file_with_used_variables);
+
+ /// Pre-processing involves include expansion and variable substitution
+ /// Will throw std::runtime_error if pre processing fails
+ void pre_process(std::string& pre_processed_file);
+ void pre_process(std::vector<std::string> & user_edit_file, std::string& pre_processed_file);
+
+ /// Searches for the first %comment, then extracts all variables of the form
+ /// <name> = <value>
+ /// and places into map
+ static void extract_used_variables(NameValueMap& used_variables_as_map,const std::vector<std::string> &script_lines);
+
+private:
+ enum Type { SCRIPT, INCLUDE, MANUAL, COMMENT };
+ static std::string fileType(EcfFile::Type);
+
+ bool open_script_file(const std::string& file, EcfFile::Type, std::vector<std::string>& lines, std::string& errormsg) const;
+ bool preProcess(std::vector<std::string>& script_lines, std::string& errormsg);
+ bool replaceSmsChildCmdsWithEcf(const std::string& clientPath, std::string& errormsg);
+ std::string getIncludedFilePath( const std::string& include, const std::string& line, std::string& errormsg);
+ void variableSubstituition(JobsParam&);
+ const std::string& doCreateJobFile(JobsParam&) const;
+ bool doCreateManFile(std::string& errormsg);
+ bool extractManual(const std::vector< std::string >& lines, std::vector< std::string >& theManualLines, std::string& errormsg) const;
+ void removeCommentAndManual();
+ void remove_nopp_end_tokens();
+
+ static int countEcfMicro(const std::string& line, const std::string& ecfMicro);
+ static void dump_expanded_script_file(size_t i, const std::vector<std::string>& lines); // for DEBUG
+
+ /// returns the extension, i.e for task->.ecf for alias->.usr, will throw if node_ is not task or alias
+ const std::string& get_extn() const;
+
+ bool do_popen(const std::string& the_cmd, EcfFile::Type, std::vector<std::string>& lines, std::string& errormsg) const;
+
+ boost::filesystem::path file_creation_path() const;
+ std::string script_or_job_path() const;
+
+/// User edit functions:
+ void get_used_variables(std::string& used_variables) const;
+ bool get_used_variables(NameValueMap& used_variables, std::string& errorMsg) const;
+ void doCreateUsrFile() const;
+
+ Node* node_; // Task or Alias or Container when pre-processing the man files
+ std::string ecfMicroCache_; // cache value of ECF_MICRO
+ std::string script_path_or_cmd_; // path to .ecf, .usr file or command
+ mutable std::string job_size_; // to be placed in log file during job submission
+ EcfFile::ScriptType script_type_; // get script from a file, or from running a command
+ std::vector<std::string> jobLines_; // Lines that will form the job file.
+};
+
+#endif
diff --git a/ANode/src/ExprAst.cpp b/ANode/src/ExprAst.cpp
new file mode 100644
index 0000000..94bc3a2
--- /dev/null
+++ b/ANode/src/ExprAst.cpp
@@ -0,0 +1,1238 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #57 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <vector>
+#include <boost/foreach.hpp>
+
+#include "ExprAst.hpp"
+#include "Indentor.hpp"
+#include "ExprAstVisitor.hpp"
+#include "Node.hpp"
+#include "Log.hpp"
+#include "Str.hpp"
+
+using namespace ecf;
+using namespace std;
+
+////////////////////////////////////////////////////////////////////////////////////
+
+Ast::~Ast() {}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+AstTop::~AstTop() { delete root_;}
+
+void AstTop::accept(ExprAstVisitor& v)
+{
+ v.visitTop(this);
+ root_->accept(v);
+}
+
+AstTop* AstTop::clone() const
+{
+ AstTop* top = new AstTop();
+ top->addChild( root_->clone() );
+ return top;
+}
+
+bool AstTop::evaluate() const
+{
+ if (root_) {
+ return root_->evaluate();
+ }
+
+ LOG_ASSERT(false,"AstTop::evaluate(): assert failed, AST top has no root/children");
+ return false;
+}
+
+bool AstTop::check(std::string& error_msg) const
+{
+ if (root_) {
+ return root_->check(error_msg);
+ }
+ return true;
+}
+
+std::ostream& AstTop::print(std::ostream& os) const
+{
+ Indentor in;
+ Indentor::indent(os) << "# AST\n";
+ if (root_) {
+ Indentor in;
+ return root_->print(os);
+ }
+ return os;
+}
+
+void AstTop::print_flat(std::ostream& os,bool add_bracket) const
+{
+ if (root_) {
+ root_->print_flat(os,add_bracket);
+ }
+}
+
+//#define DEBUG_WHY 1
+bool AstTop::why(std::string& theReasonWhy) const
+{
+ if (evaluate()) {
+#ifdef DEBUG_WHY
+ std::cout << " AstTop::why evaluate returning\n";
+#endif
+ return false;
+ }
+ return root_->why(theReasonWhy);
+}
+
+std::string AstTop::expression(bool why) const
+{
+ std::string ret = exprType_;
+ if (root_) {
+ ret += " ";
+ ret += root_->expression(why);
+ }
+ return ret;
+}
+
+void AstTop::setParentNode(Node* p)
+{
+ if (root_) root_->setParentNode(p);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+
+AstRoot::~AstRoot() {
+ delete left_;
+ delete right_;
+ left_ = 0;
+ right_ = 0;
+}
+
+void AstRoot::accept(ExprAstVisitor& v)
+{
+ v.visitRoot(this);
+ left_->accept(v);
+ if (right_) right_->accept(v); // right_ is empty for Not
+}
+
+bool AstRoot::check(std::string& error_msg) const
+{
+ if (left_ && !left_->check(error_msg)) return false;
+ if (right_ && !right_->check(error_msg)) return false;
+ return true;
+}
+
+void AstRoot::addChild( Ast* n )
+{
+ LOG_ASSERT(n,"");
+
+ if ( !left_ ) {
+ left_ = n;
+ return;
+ }
+ if ( !right_ ) {
+ right_ = n;
+ return;
+ }
+
+ LOG_ASSERT(false,"AstRoot::addChild: assert failed: root already has left and right children\n");
+}
+
+std::ostream& AstRoot::print( std::ostream& os ) const {
+ if (left_->isRoot()) {
+ Indentor in;
+ left_->print( os );
+ }
+ else left_->print( os );
+
+ if (right_) { // right_ is empty for Not
+ if (right_->isRoot()) {
+ Indentor in;
+ right_->print( os );
+ }
+ else right_->print( os ); ;
+ }
+ return os;
+}
+
+bool AstRoot::why(std::string& theReasonWhy) const
+{
+ if (evaluate()) {
+#ifdef DEBUG_WHY
+ std::cout << " AstRoot::why evaluates returning\n";
+#endif
+ return false;
+ }
+
+ theReasonWhy = "expression ";
+ theReasonWhy += expression(true); // provide additional state
+ theReasonWhy += " does not evaluate";
+#ifdef DEBUG_WHY
+ std::cout << " AstRoot::why reason = " << theReasonWhy << "\n";
+#endif
+ return true;
+}
+
+void AstRoot::setParentNode(Node* p)
+{
+ if (left_) left_->setParentNode(p);
+ if (right_) right_->setParentNode(p);
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+void AstNot::accept(ExprAstVisitor& v)
+{
+ AstRoot::accept(v);
+ v.visitNot(this);
+}
+
+AstNot* AstNot::clone() const
+{
+ AstNot* ast = new AstNot();
+ if (left_) ast->addChild( left_->clone() );
+ return ast;
+}
+
+std::ostream& AstNot::print( std::ostream& os ) const {
+ Indentor::indent( os ) << "# NOT evaluate(" << evaluate() << ")";
+ if (right_) os << " # ERROR has right_";
+ os << "\n";
+ return AstRoot::print( os );
+}
+
+void AstNot::print_flat( std::ostream& os,bool add_bracket) const {
+ os << name_;
+ if (left_) {
+ if (add_bracket) os << "(";
+ left_->print_flat(os,add_bracket);
+ if (add_bracket) os << ")";
+ }
+}
+
+std::string AstNot::expression(bool why) const
+{
+ std::string ret = "NOT ";
+ ret += left_->expression(why);
+ return ret;
+}
+////////////////////////////////////////////////////////////////////////////////////
+
+void AstPlus::accept(ExprAstVisitor& v)
+{
+ AstRoot::accept(v);
+ v.visitPlus(this);
+}
+
+AstPlus* AstPlus::clone() const
+{
+ AstPlus* ast = new AstPlus();
+ if (left_) ast->addChild( left_->clone() );
+ if (right_) ast->addChild( right_->clone() );
+ return ast;
+}
+
+std::ostream& AstPlus::print( std::ostream& os ) const {
+ Indentor::indent( os ) << "# PLUS value(" << value() << ")";
+ if (!left_) os << " # ERROR has no left_";
+ if (!right_) os << " # ERROR has no right_";
+ os << "\n";
+ return AstRoot::print( os );
+}
+
+void AstPlus::print_flat(std::ostream& os,bool add_bracket) const {
+ if (add_bracket) os << "(";
+ if (left_) left_->print_flat(os,add_bracket);
+ os << " + ";
+ if (right_) right_->print_flat(os,add_bracket);
+ if (add_bracket) os << ")";
+}
+
+std::string AstPlus::expression(bool why) const
+{
+ std::string ret;
+ if (left_) ret += left_->expression(why);
+ ret += " + ";
+ if (right_) ret += right_->expression(why);
+ return ret;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+void AstMinus::accept(ExprAstVisitor& v)
+{
+ AstRoot::accept(v);
+ v.visitMinus(this);
+}
+
+AstMinus* AstMinus::clone() const
+{
+ AstMinus* ast = new AstMinus();
+ if (left_) ast->addChild( left_->clone() );
+ if (right_) ast->addChild( right_->clone() );
+ return ast;
+}
+
+std::ostream& AstMinus::print( std::ostream& os ) const {
+ Indentor::indent( os ) << "# MINUS value(" << value() << ")";
+ if (!left_) os << " # ERROR has no left_";
+ if (!right_) os << " # ERROR has no right_";
+ os << "\n";
+ return AstRoot::print( os );
+}
+
+void AstMinus::print_flat(std::ostream& os,bool add_bracket) const {
+ if (add_bracket) os << "(";
+ if (left_) left_->print_flat(os,add_bracket);
+ os << " - ";
+ if (right_) right_->print_flat(os,add_bracket);
+ if (add_bracket) os << ")";
+}
+
+std::string AstMinus::expression(bool why) const
+{
+ std::string ret;
+ if (left_) ret += left_->expression(why);
+ ret += " - ";
+ if (right_) ret += right_->expression(why);
+ return ret;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+void AstDivide::accept(ExprAstVisitor& v)
+{
+ AstRoot::accept(v);
+ v.visitDivide(this);
+}
+
+AstDivide* AstDivide::clone() const
+{
+ AstDivide* ast = new AstDivide();
+ if (left_) ast->addChild( left_->clone() );
+ if (right_) ast->addChild( right_->clone() );
+ return ast;
+}
+
+bool AstDivide::check(std::string& error_msg) const
+{
+ if (right_ && right_->value() == 0) {
+ error_msg = "Divide by zero in trigger expression";
+ return false;
+ }
+ return true;
+}
+
+int AstDivide::value() const {
+ if (right_->value() == 0) {
+ log(Log::ERR,"Divide by zero in trigger/complete expression");
+ return 0;
+ }
+ return (left_->value() / right_->value()) ;
+}
+
+std::ostream& AstDivide::print( std::ostream& os ) const {
+ Indentor::indent( os ) << "# DIVIDE value(" << value() << ")";
+ if (!left_) os << " # ERROR has no left_";
+ if (!right_) os << " # ERROR has no right_";
+ os << "\n";
+ return AstRoot::print( os );
+}
+
+void AstDivide::print_flat(std::ostream& os,bool add_bracket) const {
+ if (add_bracket) os << "(";
+ if (left_) left_->print_flat(os,add_bracket);
+ os << " / ";
+ if (right_) right_->print_flat(os,add_bracket);
+ if (add_bracket) os << ")";
+}
+
+std::string AstDivide::expression(bool why) const
+{
+ std::string ret;
+ if (left_) ret += left_->expression(why);
+ ret += " / ";
+ if (right_) ret += right_->expression(why);
+ return ret;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+void AstMultiply::accept(ExprAstVisitor& v)
+{
+ AstRoot::accept(v);
+ v.visitMultiply(this);
+}
+
+AstMultiply* AstMultiply::clone() const
+{
+ AstMultiply* ast = new AstMultiply();
+ if (left_) ast->addChild( left_->clone() );
+ if (right_) ast->addChild( right_->clone() );
+ return ast;
+}
+
+std::ostream& AstMultiply::print( std::ostream& os ) const {
+ Indentor::indent( os ) << "# MULTIPLY value(" << value() << ")";
+ if (!left_) os << " # ERROR has no left_";
+ if (!right_) os << " # ERROR has no right_";
+ os << "\n";
+ return AstRoot::print( os );
+}
+
+void AstMultiply::print_flat(std::ostream& os,bool add_bracket) const {
+ if (add_bracket) os << "(";
+ if (left_) left_->print_flat(os,add_bracket);
+ os << " * ";
+ if (right_) right_->print_flat(os,add_bracket);
+ if (add_bracket) os << ")";
+}
+
+std::string AstMultiply::expression(bool why) const
+{
+ std::string ret;
+ if (left_) ret += left_->expression(why);
+ ret += " * ";
+ if (right_) ret += right_->expression(why);
+ return ret;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+void AstModulo::accept(ExprAstVisitor& v)
+{
+ AstRoot::accept(v);
+ v.visitModulo(this);
+}
+
+AstModulo* AstModulo::clone() const
+{
+ AstModulo* ast = new AstModulo();
+ if (left_) ast->addChild( left_->clone() );
+ if (right_) ast->addChild( right_->clone() );
+ return ast;
+}
+
+bool AstModulo::check(std::string& error_msg) const
+{
+ if (right_ && right_->value() == 0) {
+ error_msg = "Modulo by zero in trigger expression";
+ return false;
+ }
+ return true;
+}
+
+int AstModulo::value() const
+{
+ if (right_->value() == 0) {
+ log(Log::ERR,"Modulo by zero in trigger/complete expression");
+ return 0;
+ }
+ return (left_->value() % right_->value());
+}
+
+std::ostream& AstModulo::print( std::ostream& os ) const {
+ Indentor::indent( os ) << "# Modulo value(" << value() << ")";
+ if (!left_) os << " # ERROR has no left_";
+ if (!right_) os << " # ERROR has no right_";
+ os << "\n";
+ return AstRoot::print( os );
+}
+
+void AstModulo::print_flat(std::ostream& os,bool add_bracket) const {
+ if (add_bracket) os << "(";
+ if (left_) left_->print_flat(os,add_bracket);
+ os << " % ";
+ if (right_) right_->print_flat(os,add_bracket);
+ if (add_bracket) os << ")";
+}
+
+std::string AstModulo::expression(bool why) const
+{
+ std::string ret;
+ if (left_) ret += left_->expression(why);
+ ret += " % ";
+ if (right_) ret += right_->expression(why);
+ return ret;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+void AstAnd::accept(ExprAstVisitor& v)
+{
+ AstRoot::accept(v);
+ v.visitAnd(this);
+}
+
+AstAnd* AstAnd::clone() const
+{
+ AstAnd* ast = new AstAnd();
+ if (left_) ast->addChild( left_->clone() );
+ if (right_) ast->addChild( right_->clone() );
+ return ast;
+}
+
+std::ostream& AstAnd::print( std::ostream& os ) const {
+ Indentor::indent( os ) << "# AND evaluate(" << evaluate() << ")";
+ if (!left_) os << " # ERROR has no left_";
+ if (!right_) os << " # ERROR has no right_";
+ os << "\n";
+ return AstRoot::print( os );
+}
+
+void AstAnd::print_flat(std::ostream& os,bool add_bracket) const {
+ if (add_bracket) os << "(";
+ if (left_) left_->print_flat(os,add_bracket);
+ os << " and ";
+ if (right_) right_->print_flat(os,add_bracket);
+ if (add_bracket) os << ")";
+}
+
+std::string AstAnd::expression(bool why) const
+{
+ std::string ret("(");
+ if (left_) ret += left_->expression(why);
+ ret += " AND ";
+ if (right_) ret += right_->expression(why);
+ ret += ")";
+ return ret;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+void AstOr::accept(ExprAstVisitor& v)
+{
+ AstRoot::accept(v);
+ v.visitOr(this);
+}
+
+AstOr* AstOr::clone() const
+{
+ AstOr* ast = new AstOr();
+ if (left_) ast->addChild( left_->clone() );
+ if (right_) ast->addChild( right_->clone() );
+ return ast;
+}
+
+std::ostream& AstOr::print( std::ostream& os ) const {
+ Indentor::indent( os ) << "# OR evaluate(" << evaluate() << ")";
+ if (!left_) os << " # ERROR has no left_";
+ if (!right_) os << " # ERROR has no right_";
+ os << "\n";
+ return AstRoot::print( os );
+}
+
+void AstOr::print_flat(std::ostream& os,bool add_bracket) const {
+ if (add_bracket) os << "(";
+ if (left_) left_->print_flat(os,add_bracket);
+ os << " or ";
+ if (right_) right_->print_flat(os,add_bracket);
+ if (add_bracket) os << ")";
+}
+
+std::string AstOr::expression(bool why) const
+{
+ std::string ret("(");
+ if (left_) ret += left_->expression(why);
+ ret += " OR ";
+ if (right_) ret += right_->expression(why);
+ ret += ")";
+ return ret;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+void AstEqual::accept(ExprAstVisitor& v)
+{
+ AstRoot::accept(v);
+ v.visitEqual(this);
+}
+
+AstEqual* AstEqual::clone() const
+{
+ AstEqual* ast = new AstEqual();
+ if (left_) ast->addChild( left_->clone() );
+ if (right_) ast->addChild( right_->clone() );
+ return ast;
+}
+
+std::ostream& AstEqual::print( std::ostream& os ) const {
+ Indentor::indent( os ) << "# EQUAL evaluate(" << evaluate() << ")";
+ if (!left_) os << " # ERROR has no left_";
+ if (!right_) os << " # ERROR has no right_";
+ os << "\n";
+ return AstRoot::print( os );
+}
+
+void AstEqual::print_flat(std::ostream& os,bool add_bracket) const {
+ if (add_bracket) os << "(";
+ if (left_) left_->print_flat(os,add_bracket);
+ os << " == ";
+ if (right_) right_->print_flat(os,add_bracket);
+ if (add_bracket) os << ")";
+}
+
+std::string AstEqual::expression(bool why) const
+{
+ std::string ret("(");
+ if (left_) ret += left_->expression(why);
+ ret += " == ";
+ if (right_) ret += right_->expression(why);
+ ret += ")";
+ return ret;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+void AstNotEqual::accept(ExprAstVisitor& v)
+{
+ AstRoot::accept(v);
+ v.visitNotEqual(this);
+}
+AstNotEqual* AstNotEqual::clone() const
+{
+ AstNotEqual* ast = new AstNotEqual();
+ if (left_) ast->addChild( left_->clone() );
+ if (right_) ast->addChild( right_->clone() );
+ return ast;
+}
+
+std::ostream& AstNotEqual::print( std::ostream& os ) const {
+ Indentor::indent( os ) << "# NOT_EQUAL evaluate(" << evaluate() << ")";
+ if (!left_) os << " # ERROR has no left_";
+ if (!right_) os << " # ERROR has no right_";
+ os << "\n";
+ return AstRoot::print( os );
+}
+
+void AstNotEqual::print_flat(std::ostream& os,bool add_bracket) const {
+ if (add_bracket) os << "(";
+ if (left_) left_->print_flat(os,add_bracket);
+ os << " != ";
+ if (right_) right_->print_flat(os,add_bracket);
+ if (add_bracket) os << ")";
+}
+
+std::string AstNotEqual::expression(bool why) const
+{
+ std::string ret("(");
+ if (left_) ret += left_->expression(why);
+ ret += " != ";
+ if (right_) ret += right_->expression(why);
+ ret += ")";
+ return ret;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+void AstLessEqual::accept(ExprAstVisitor& v)
+{
+ AstRoot::accept(v);
+ v.visitLessEqual(this);
+}
+AstLessEqual* AstLessEqual::clone() const
+{
+ AstLessEqual* ast = new AstLessEqual();
+ if (left_) ast->addChild( left_->clone() );
+ if (right_) ast->addChild( right_->clone() );
+ return ast;
+}
+
+std::ostream& AstLessEqual::print( std::ostream& os ) const {
+ Indentor::indent( os ) << "# LESS_EQUAL evaluate(" << evaluate() << ")";
+ if (!left_) os << " # ERROR has no left_";
+ if (!right_) os << " # ERROR has no right_";
+ os << "\n";
+ return AstRoot::print( os );
+}
+void AstLessEqual::print_flat(std::ostream& os,bool add_bracket) const {
+ if (add_bracket) os << "(";
+ if (left_) left_->print_flat(os,add_bracket);
+ os << " <= ";
+ if (right_) right_->print_flat(os,add_bracket);
+ if (add_bracket) os << ")";
+}
+std::string AstLessEqual::expression(bool why) const
+{
+ std::string ret("(");
+ if (left_) ret += left_->expression(why);
+ ret += " <= ";
+ if (right_) ret += right_->expression(why);
+ ret += ")";
+ return ret;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+void AstGreaterEqual::accept(ExprAstVisitor& v)
+{
+ AstRoot::accept(v);
+ v.visitGreaterEqual(this);
+}
+AstGreaterEqual* AstGreaterEqual::clone() const
+{
+ AstGreaterEqual* ast = new AstGreaterEqual();
+ if (left_) ast->addChild( left_->clone() );
+ if (right_) ast->addChild( right_->clone() );
+ return ast;
+}
+
+std::ostream& AstGreaterEqual::print( std::ostream& os ) const {
+ Indentor::indent( os ) << "# GREATER_EQUAL evaluate(" << evaluate() << ")";
+ if (!left_) os << " # ERROR has no left_";
+ if (!right_) os << " # ERROR has no right_";
+ os << "\n";
+ return AstRoot::print( os );
+}
+void AstGreaterEqual::print_flat(std::ostream& os,bool add_bracket) const {
+ if (add_bracket) os << "(";
+ if (left_) left_->print_flat(os,add_bracket);
+ os << " >= ";
+ if (right_) right_->print_flat(os,add_bracket);
+ if (add_bracket) os << ")";
+}
+
+std::string AstGreaterEqual::expression(bool why) const
+{
+ std::string ret("(");
+ if (left_) ret += left_->expression(why);
+ ret += " >= ";
+ if (right_) ret += right_->expression(why);
+ ret += ")";
+ return ret;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+void AstGreaterThan::accept(ExprAstVisitor& v)
+{
+ AstRoot::accept(v);
+ v.visitGreaterThan(this);
+}
+AstGreaterThan* AstGreaterThan::clone() const
+{
+ AstGreaterThan* ast = new AstGreaterThan();
+ if (left_) ast->addChild( left_->clone() );
+ if (right_) ast->addChild( right_->clone() );
+ return ast;
+}
+
+std::ostream& AstGreaterThan::print( std::ostream& os ) const {
+ Indentor::indent( os ) << "# GREATER_THAN evaluate(" << evaluate() << ")";
+ if (!left_) os << " # ERROR has no left_";
+ if (!right_) os << " # ERROR has no right_";
+ os << "\n";
+ return AstRoot::print( os );
+}
+void AstGreaterThan::print_flat(std::ostream& os,bool add_bracket) const {
+ if (add_bracket) os << "(";
+ if (left_) left_->print_flat(os,add_bracket);
+ os << " > ";
+ if (right_) right_->print_flat(os,add_bracket);
+ if (add_bracket) os << ")";
+}
+
+std::string AstGreaterThan::expression(bool why) const
+{
+ std::string ret("(");
+ if (left_) ret += left_->expression(why);
+ ret += " > ";
+ if (right_) ret += right_->expression(why);
+ ret += ")";
+ return ret;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+void AstLessThan::accept(ExprAstVisitor& v)
+{
+ AstRoot::accept(v);
+ v.visitLessThan(this);
+}
+
+AstLessThan* AstLessThan::clone() const
+{
+ AstLessThan* ast = new AstLessThan();
+ if (left_) ast->addChild( left_->clone() );
+ if (right_) ast->addChild( right_->clone() );
+ return ast;
+}
+
+std::ostream& AstLessThan::print( std::ostream& os ) const {
+ Indentor::indent( os ) << "# LESS_THAN evaluate(" << evaluate() << ")";
+ if (!left_) os << " # ERROR has no left_";
+ if (!right_) os << " # ERROR has no right_";
+ os << "\n";
+ return AstRoot::print( os );
+}
+void AstLessThan::print_flat(std::ostream& os,bool add_bracket) const {
+ if (add_bracket) os << "(";
+ if (left_) left_->print_flat(os,add_bracket);
+ os << " < ";
+ if (right_) right_->print_flat(os,add_bracket);
+ if (add_bracket) os << ")";
+}
+std::string AstLessThan::expression(bool why) const
+{
+ std::string ret("(");
+ if (left_) ret += left_->expression(why);
+ ret += " < ";
+ if (right_) ret += right_->expression(why);
+ ret += ")";
+ return ret;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+void AstLeaf::accept(ExprAstVisitor& v)
+{
+ v.visitLeaf(this);
+}
+
+///////////////////////////////////////////////////////////////////////////////////
+void AstInteger::accept(ExprAstVisitor& v)
+{
+ v.visitInteger(this); // Not calling base
+}
+
+AstInteger* AstInteger::clone() const
+{
+ AstInteger* ast = new AstInteger(value_);
+ return ast;
+}
+
+std::ostream& AstInteger::print( std::ostream& os ) const {
+ Indentor in;
+ return Indentor::indent( os ) << "# LEAF_INTEGER " << value() << "\n";
+}
+
+void AstInteger::print_flat(std::ostream& os,bool /*add_bracket*/) const {
+ os << value_;
+}
+
+std::string AstInteger::expression(bool /*why*/) const
+{
+ std::stringstream ss;
+ ss << value();
+ return ss.str();
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+
+void AstString::accept(ExprAstVisitor& v)
+{
+ v.visitString(this); // Not calling base
+}
+
+AstString* AstString::clone() const
+{
+ return new AstString(value_);
+}
+
+std::ostream& AstString::print( std::ostream& os ) const {
+ Indentor in;
+ return Indentor::indent( os ) << "# LEAF_STRING " << value_ << " value() = " << value() << "\n";
+}
+void AstString::print_flat(std::ostream& os,bool /*add_bracket*/) const {
+ os << value_;
+}
+
+std::string AstString::expression(bool /*why*/) const
+{
+ return value_;
+}
+
+int AstString::value() const
+{
+ if (value_ == Event::SET()) { // allow us to compare with a event and a string
+ return 1;
+ }
+ if (value_ == Event::CLEAR()) { // allow us to compare with a event and a string
+ return 0;
+ }
+ // see if the value is convertible to a integer
+ return Str::to_int( value_, 0/* value to return if conversion fails*/);
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+void AstNodeState::accept(ExprAstVisitor& v)
+{
+ v.visitNodeState(this); // Not calling base
+}
+
+AstNodeState* AstNodeState::clone() const
+{
+ return new AstNodeState(state_);
+}
+
+std::ostream& AstNodeState::print( std::ostream& os ) const {
+ Indentor in;
+ return Indentor::indent( os ) << "# LEAF_NODE_STATE "
+ << DState::toString( state_ ) << "(" << value() << ")\n";
+}
+
+void AstNodeState::print_flat(std::ostream& os,bool /*add_bracket*/) const {
+ os << DState::toString( state_ ) ;
+}
+
+std::string AstNodeState::expression(bool why) const
+{
+ return DState::toString(state_);
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+void AstEventState::accept(ExprAstVisitor& v)
+{
+ v.visitEventState(this); // Not calling base
+}
+
+AstEventState* AstEventState::clone() const
+{
+ return new AstEventState(state_);
+}
+
+std::ostream& AstEventState::print( std::ostream& os ) const {
+ Indentor in;
+ return Indentor::indent( os ) << "# LEAF_EVENT_STATE " << state_ << "\n";
+}
+
+void AstEventState::print_flat(std::ostream& os,bool /*add_bracket*/) const {
+ if (state_) os << Event::SET();
+ else os << Event::CLEAR();
+}
+
+std::string AstEventState::expression(bool /*why*/) const
+{
+ if (state_) return Event::SET();
+ return Event::CLEAR();
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+void AstNode::accept(ExprAstVisitor& v)
+{
+ v.visitNode(this); // Not calling base
+}
+
+AstNode* AstNode::clone() const
+{
+ return new AstNode(nodePath_);
+}
+
+DState::State AstNode::state() const
+{
+ // This function is called hundreds of millions of times
+ Node* refNode = referencedNode(); // call once, could be expensive
+ if (refNode) return refNode->dstate();
+ return DState::UNKNOWN;
+}
+
+Node* AstNode::referencedNode() const
+{
+ // This function is called hundreds of millions of times
+ // One of the server CPU **bottleneck's** is weak ptr locking
+ // Note: gprof does not report on in-lined functions ?
+ Node* ref = get_ref_node();
+ if ( ref ) {
+ return ref;
+ }
+ if ( parentNode_ ) {
+ std::string errorMsg;
+ ref_node_ = parentNode_->findReferencedNode( nodePath_, errorMsg );
+ return get_ref_node(); // can be NULL
+ }
+ return NULL;
+}
+
+Node* AstNode::referencedNode(std::string& errorMsg) const
+{
+ Node* ref = get_ref_node();
+ if ( ref ) {
+ return ref;
+ }
+ if ( parentNode_ ) {
+ ref_node_ = parentNode_->findReferencedNode( nodePath_, errorMsg );
+ return get_ref_node(); // can be NULL
+ }
+ return NULL;
+}
+
+std::ostream& AstNode::print( std::ostream& os ) const {
+
+ Node* refNode = referencedNode(); // Only call once
+ Indentor in;
+
+ if ( refNode ) {
+ Indentor::indent( os ) << "# LEAF_NODE node_(Found) nodePath_('" << nodePath_ << "') ";
+ os << DState::toString( refNode->dstate() ) << "(" << static_cast<int>( refNode->dstate()) << ")\n";
+ }
+ else {
+ Indentor::indent( os ) << "# LEAF_NODE node_(NULL) nodePath_('" << nodePath_ << "') ";
+ os << DState::toString( DState::UNKNOWN ) << "(" << static_cast<int>(DState::UNKNOWN) << ")\n";
+ }
+ return os;
+}
+
+void AstNode::print_flat(std::ostream& os,bool /*add_bracket*/) const {
+ os << nodePath_;
+}
+
+std::string AstNode::expression(bool why) const
+{
+ if (why) {
+ Node* refNode = referencedNode(); // Only call once
+ std::string ret = nodePath_;
+ if ( refNode ) {
+ ret += "(";
+ ret += DState::toString( refNode->dstate() );
+ ret += ")";
+ return ret;
+ }
+ else {
+ ret += "(?";
+ ret += DState::toString( DState::UNKNOWN );
+ ret += ")";
+ }
+ return ret;
+ }
+ return nodePath_;
+}
+
+
+
+////////////////////////////////////////////////////////////////////////////////////
+
+void AstVariable::accept(ExprAstVisitor& v)
+{
+ v.visitVariable(this); // Not calling base
+}
+
+AstVariable* AstVariable::clone() const
+{
+ return new AstVariable(nodePath_,name_);
+}
+
+int AstVariable::value() const
+{
+ VariableHelper varHelper(this);
+ return varHelper.value();
+}
+
+int AstVariable::minus(Ast* right) const
+{
+ VariableHelper varHelper(this);
+ return varHelper.minus(right->value());
+}
+
+int AstVariable::plus(Ast* right) const
+{
+ VariableHelper varHelper(this);
+ return varHelper.plus(right->value());
+}
+
+std::ostream& AstVariable::print( std::ostream& os ) const
+{
+ VariableHelper varHelper(this);
+ return varHelper.print(os);
+}
+
+void AstVariable::print_flat(std::ostream& os,bool /*add_bracket*/) const
+{
+ os << nodePath_ << Str::COLON() << name_;
+}
+
+std::string AstVariable::expression(bool why) const
+{
+ if (why) {
+ VariableHelper varHelper(this);
+ std::string ret = nodePath_;
+ if ( !varHelper.theReferenceNode() ) ret += "(?)";
+ ret += Str::COLON();
+ ret += name_;
+ ret += "(";
+
+ std::string varType;
+ int theValue;
+ varHelper.varTypeAndValue(varType,theValue);
+
+ std::stringstream ss; ss << "<type=" << varType << "> <value=" << theValue << ">";
+ ret += ss.str();
+
+ ret += ")";
+ return ret;
+ }
+ return nodePath_ + Str::COLON() + name_;
+}
+
+Node* AstVariable::referencedNode() const
+{
+ Node* ref = get_ref_node();
+ if ( ref ) {
+ return ref;
+ }
+ if ( parentNode_ ) {
+ std::string ignoredErrorMsg;
+ ref_node_ = parentNode_->findReferencedNode( nodePath_, name_, ignoredErrorMsg );
+ return get_ref_node(); // can be NULL
+ }
+ return NULL;
+}
+
+Node* AstVariable::referencedNode(std::string& errorMsg) const
+{
+ Node* ref = get_ref_node();
+ if ( ref ) {
+ return ref;
+ }
+ if ( parentNode_ ) {
+ ref_node_ = parentNode_->findReferencedNode( nodePath_, name_, errorMsg );
+ return get_ref_node(); // can be NULL
+ }
+ return NULL;
+}
+
+
+// ===============================================================================
+// class VariableHelper:
+// ===============================================================================
+VariableHelper::VariableHelper(const AstVariable* astVariable)
+: astVariable_(astVariable), theReferenceNode_(NULL)
+{
+ // For *this* constructor we don't care about errors'
+ std::string errorMsg;
+ theReferenceNode_ = astVariable_->referencedNode( errorMsg );
+ if ( !theReferenceNode_ ) {
+ // A node can be NULL if :
+ // 1/ parentNode is NOT set
+ // 2/ when its a extern path. i.e corresponding suite not loaded yet
+ return;
+ }
+ LOG_ASSERT(errorMsg.empty(),""); // when a reference node is found, the error msg should be empty
+}
+
+// ***NOTE*** This constructor is called during AST construction***. i.e AstResolveVisitor
+// ********** It is used to report errors and to Flag whether meter or event is used
+// ********** in a trigger expression for the simulator
+VariableHelper::VariableHelper(const AstVariable* astVariable, std::string& errorMsg)
+: astVariable_(astVariable), theReferenceNode_(NULL)
+{
+ // for *this* constructor we want to report errors
+ theReferenceNode_ = astVariable_->referencedNode( errorMsg );
+ if ( !theReferenceNode_ ) {
+ // A node can be NULL if :
+ // 1/ parentNode is NOT set
+ // 2/ when its a extern path. i.e corresponding suite not loaded yet
+ return;
+ }
+ LOG_ASSERT(errorMsg.empty(),""); // when a reference node is found, the error msg should be empty
+
+ // Find in order, event, meter, user variable, repeat, generated variable
+ // ALSO: if meter or event mark as used in trigger, for simulator
+ if (theReferenceNode_->findExprVariable( astVariable_->name() ) ) {
+ return;
+ }
+
+ std::stringstream ss;
+ ss << "From expression Variable " << astVariable_->nodePath() << Str::COLON() << astVariable_->name() ;
+ ss << " the referenced node is " << theReferenceNode_->debugNodePath() << "\n";
+ errorMsg += ss.str();
+ errorMsg += "Could not find event, meter, variable, repeat, or generated variable of name('";
+ errorMsg += astVariable_->name();
+ errorMsg += "') on node ";
+ errorMsg += theReferenceNode_->debugNodePath();
+ errorMsg += "\n";
+
+ // FAILED to find astVar->name(), for node theReferenceNode on event, meter,
+ // user variable, repeat, generated variable
+ // SET theReferenceNode_ to NULL, since it does nor reference the Expression variable
+ theReferenceNode_ = NULL;
+}
+
+int VariableHelper::value() const
+{
+ if ( theReferenceNode_ ) {
+ return theReferenceNode_->findExprVariableValue(astVariable_->name());
+ }
+ return 0;
+}
+
+int VariableHelper::plus(int val) const
+{
+ if ( theReferenceNode_ ) {
+ return theReferenceNode_->findExprVariableValueAndPlus(astVariable_->name(),val);
+ }
+ return val;
+}
+
+ int VariableHelper::minus(int val) const
+ {
+ if ( theReferenceNode_ ) {
+ return theReferenceNode_->findExprVariableValueAndMinus(astVariable_->name(),val);
+ }
+ return -val;
+ }
+
+void VariableHelper::varTypeAndValue(std::string& varType, int & theValue) const
+{
+ if ( theReferenceNode_ ) {
+ theValue = theReferenceNode_->findExprVariableValueAndType( astVariable_->name(), varType );
+ return;
+ }
+ varType = "variable-not-found";
+ theValue = 0;
+}
+
+std::ostream& VariableHelper::print( std::ostream& os ) const
+{
+ Indentor in;
+ Indentor::indent( os ) << "# " << astVariable_->nodePath() << Str::COLON() << astVariable_->name();
+
+ if ( theReferenceNode_ ) {
+ os << " (";
+ theReferenceNode_->findExprVariableAndPrint(astVariable_->name(), os);
+ os << ")";
+ }
+ else {
+ os << " referencedNode(NULL) nodePath_('" << astVariable_->nodePath() << "') value(0)";
+ }
+ os << "\n";
+ return os;
+}
+
+std::ostream& operator<<( std::ostream& os, const Ast& d){return d.print( os );}
+std::ostream& operator<<( std::ostream& os, const AstTop& d){return d.print( os );}
+std::ostream& operator<<( std::ostream& os, const AstRoot& d ) {return d.print( os );}
+std::ostream& operator<<( std::ostream& os, const AstNot& d ) {return d.print( os );}
+std::ostream& operator<<( std::ostream& os, const AstPlus& d ) {return d.print( os );}
+std::ostream& operator<<( std::ostream& os, const AstMinus& d ) {return d.print( os );}
+std::ostream& operator<<( std::ostream& os, const AstDivide& d ) {return d.print( os );}
+std::ostream& operator<<( std::ostream& os, const AstMultiply& d ) {return d.print( os );}
+std::ostream& operator<<( std::ostream& os, const AstModulo& d ) {return d.print( os );}
+std::ostream& operator<<( std::ostream& os, const AstAnd& d ) {return d.print( os );}
+std::ostream& operator<<( std::ostream& os, const AstOr& d ) {return d.print( os );}
+std::ostream& operator<<( std::ostream& os, const AstEqual& d ) {return d.print( os );}
+std::ostream& operator<<( std::ostream& os, const AstNotEqual& d ) {return d.print( os );}
+std::ostream& operator<<( std::ostream& os, const AstLessEqual& d ) {return d.print( os );}
+std::ostream& operator<<( std::ostream& os, const AstGreaterEqual& d ) {return d.print( os );}
+std::ostream& operator<<( std::ostream& os, const AstGreaterThan& d ) {return d.print( os );}
+std::ostream& operator<<( std::ostream& os, const AstLessThan& d ) {return d.print( os );}
+std::ostream& operator<<( std::ostream& os, const AstLeaf& d ) {return d.print( os );}
+std::ostream& operator<<( std::ostream& os, const AstInteger& d) {return d.print( os );}
+std::ostream& operator<<( std::ostream& os, const AstString& d) {return d.print( os );}
+std::ostream& operator<<( std::ostream& os, const AstNodeState& d) {return d.print( os );}
+std::ostream& operator<<( std::ostream& os, const AstEventState& d) {return d.print( os );}
+std::ostream& operator<<( std::ostream& os, const AstNode& d ) {return d.print( os );}
+std::ostream& operator<<( std::ostream& os, const AstVariable& d ) {return d.print( os );}
diff --git a/ANode/src/ExprAst.hpp b/ANode/src/ExprAst.hpp
new file mode 100644
index 0000000..7a9ecbf
--- /dev/null
+++ b/ANode/src/ExprAst.hpp
@@ -0,0 +1,520 @@
+#ifndef EXPRAST_HPP_
+#define EXPRAST_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #42 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+// The AST is now demand created, and hence we no longer need to persist it
+
+#include <vector>
+#include <assert.h>
+#include <iostream>
+#include <boost/noncopyable.hpp>
+
+#include "DState.hpp"
+#include "NodeFwd.hpp"
+namespace ecf { class ExprAstVisitor;} // forward declare class
+
+//////////////////////////////////////////////////////////////////////////////////
+class Ast {
+public:
+ Ast() {}
+ virtual ~Ast();
+
+ virtual void accept(ecf::ExprAstVisitor&) = 0;
+ virtual Ast* clone() const = 0;
+
+ virtual void addChild(Ast*) {}
+ virtual Ast* left() const { return NULL;}
+ virtual Ast* right() const { return NULL;}
+ virtual bool evaluate() const { assert(false); return false;}
+ virtual bool isleaf() const { return false; }
+ virtual bool isRoot() const { return false; }
+ virtual AstTop* isTop() const { return NULL; }
+ virtual bool empty() const { return true; }
+ virtual int value() const { assert(false); return 0;} // only valid for leaf or operators
+ virtual bool check(std::string& error_msg) const { return true; } // check divide or modulo by zero
+
+ virtual std::ostream& print(std::ostream&) const = 0;
+ virtual void print_flat(std::ostream&,bool add_brackets = false) const = 0; // used for test
+ virtual bool why(std::string& /*theReasonWhy*/) const { return false;}
+ virtual std::string type() const = 0;
+ virtual void exprType(const std::string&) {}
+ std::string name() { return expression(false); } /* ABO */
+ virtual std::string expression(bool why = false) const = 0; // recreate expression from AST, if why show additional state
+
+ // Use for data arithmetic for REPEAT Date, Use default implementation for others
+ // Currently *ONLY* works if repeat variable in on LHS
+ virtual int minus(Ast* right) const { return (value() - right->value());}
+ virtual int plus(Ast* right) const { return (value() + right->value());}
+
+ virtual void setParentNode(Node*){} // traverse and set for interested nodes
+};
+
+class AstTop : public Ast {
+public:
+ AstTop() : root_(NULL) {}
+ virtual ~AstTop();
+
+ virtual void accept(ecf::ExprAstVisitor&);
+ virtual AstTop* clone() const;
+
+ virtual Ast* left() const { return root_;}
+ virtual void addChild(Ast* r) { root_ = r;}
+ virtual AstTop* isTop() const { return const_cast<AstTop*>(this); }
+ virtual bool evaluate() const;
+ virtual bool check(std::string& error_msg) const;
+
+ virtual bool empty() const { return (root_) ? false : true ; }
+ virtual std::ostream& print(std::ostream&) const ;
+ virtual void print_flat(std::ostream&,bool add_brackets = false) const;
+ virtual bool why(std::string& theReasonWhy) const;
+ virtual std::string type() const { return stype();}
+ virtual void exprType(const std::string& s) { exprType_ = s;}
+ static std::string stype() { return "top";}
+ virtual std::string expression(bool why = false) const;
+ virtual void setParentNode(Node*);
+
+private:
+ Ast* root_;
+ std::string exprType_; // trigger or complete
+};
+
+// This if one of AND, OR, == != <= >=
+class AstRoot : public Ast {
+public:
+ AstRoot() :left_(NULL), right_(NULL) {}
+ virtual ~AstRoot();
+
+ virtual bool check(std::string& error_msg) const;
+ virtual void accept(ecf::ExprAstVisitor&);
+ virtual void addChild(Ast* n);
+ virtual Ast* left() const { return left_;}
+ virtual Ast* right() const { return right_;}
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool why(std::string& theReasonWhy) const;
+ virtual bool isRoot() const { return true;}
+ virtual bool empty() const { return (left_ && right_) ? false : true ; }
+ virtual void setParentNode(Node*);
+
+ virtual void set_root_name(const std::string&) {}
+protected:
+ Ast* left_;
+ Ast* right_;
+};
+
+class AstNot : public AstRoot {
+public:
+ AstNot() : name_("! ") {}
+ virtual void accept(ecf::ExprAstVisitor&);
+ virtual AstNot* clone() const;
+
+ virtual bool evaluate() const { assert(!right_); return ! left_->evaluate();}
+ virtual int value() const { assert(!right_); return ! left_->value();}
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual void print_flat(std::ostream&,bool add_brackets = false) const;
+ virtual std::string type() const { return stype();}
+ virtual std::string expression(bool why = false) const;
+ static std::string stype() { return "not";}
+ virtual void set_root_name(const std::string& n) { name_ = n;}
+private:
+ std::string name_;
+};
+
+
+class AstPlus : public AstRoot {
+public:
+ AstPlus() {}
+ virtual void accept(ecf::ExprAstVisitor&);
+ virtual AstPlus* clone() const;
+
+ virtual bool evaluate() const { return true;}
+ virtual int value() const { return left_->plus(right_);}
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual void print_flat(std::ostream&,bool add_brackets = false) const;
+ virtual std::string type() const { return stype();}
+ virtual std::string expression(bool why = false) const;
+ static std::string stype() { return "plus";}
+};
+
+class AstMinus : public AstRoot {
+public:
+ AstMinus() {}
+ virtual void accept(ecf::ExprAstVisitor&);
+ virtual AstMinus* clone() const;
+
+ virtual bool evaluate() const { return true;}
+ virtual int value() const { return left_->minus(right_); }
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual void print_flat(std::ostream&,bool add_brackets = false) const;
+ virtual std::string type() const { return stype();}
+ virtual std::string expression(bool why = false) const;
+ static std::string stype() { return "minus";}
+};
+
+class AstDivide : public AstRoot {
+public:
+ AstDivide() {}
+ virtual void accept(ecf::ExprAstVisitor&);
+ virtual AstDivide* clone() const;
+ virtual bool evaluate() const { return true;}
+ virtual bool check(std::string& error_msg) const;
+ virtual int value() const; // Log error if right hand side has value of zero
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual void print_flat(std::ostream&,bool add_brackets = false) const;
+ virtual std::string type() const { return stype();}
+ virtual std::string expression(bool why = false) const;
+ static std::string stype() { return "divide";}
+};
+
+class AstMultiply : public AstRoot {
+public:
+ AstMultiply() {}
+ virtual void accept(ecf::ExprAstVisitor&);
+ virtual AstMultiply* clone() const;
+ virtual bool evaluate() const { return true;}
+ virtual int value() const { return (left_->value() * right_->value());}
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual void print_flat(std::ostream&,bool add_brackets = false) const;
+ virtual std::string type() const { return stype();}
+ virtual std::string expression(bool why = false) const;
+ static std::string stype() { return "multiply";}
+};
+
+class AstModulo : public AstRoot {
+public:
+ AstModulo(){}
+ virtual void accept(ecf::ExprAstVisitor&);
+ virtual AstModulo* clone() const;
+ virtual bool check(std::string& error_msg) const;
+ virtual bool evaluate() const { return true;}
+ virtual int value() const; // Log error if right hand side has value of zero
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual void print_flat(std::ostream&,bool add_brackets = false) const;
+ virtual std::string type() const { return stype();}
+ virtual std::string expression(bool why = false) const;
+ static std::string stype() { return "modulo";}
+};
+
+
+class AstAnd : public AstRoot {
+public:
+ AstAnd() {}
+ virtual void accept(ecf::ExprAstVisitor&);
+ virtual AstAnd* clone() const;
+ virtual bool evaluate() const { return (left_->evaluate() && right_->evaluate());}
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual void print_flat(std::ostream&,bool add_brackets = false) const;
+ virtual std::string type() const { return stype();}
+ virtual std::string expression(bool why = false) const;
+ static std::string stype() { return "and";}
+};
+
+class AstOr : public AstRoot {
+public:
+ AstOr() {}
+ virtual void accept(ecf::ExprAstVisitor&);
+ virtual AstOr* clone() const;
+ virtual bool evaluate() const { return (left_->evaluate() || right_->evaluate());}
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual void print_flat(std::ostream&,bool add_brackets = false) const;
+ virtual std::string type() const { return stype();}
+ virtual std::string expression(bool why = false) const;
+ static std::string stype() { return "or";}
+};
+
+class AstEqual : public AstRoot {
+public:
+ AstEqual() {}
+ virtual void accept(ecf::ExprAstVisitor&);
+ virtual AstEqual* clone() const;
+ virtual bool evaluate() const { return (left_->value() == right_->value()); }
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual void print_flat(std::ostream&,bool add_brackets = false) const;
+ virtual std::string type() const { return stype();}
+ virtual std::string expression(bool why = false) const;
+ static std::string stype() { return "equal";}
+};
+
+class AstNotEqual : public AstRoot {
+public:
+ AstNotEqual() {}
+ virtual void accept(ecf::ExprAstVisitor&);
+ virtual AstNotEqual* clone() const;
+ virtual bool evaluate() const { return (left_->value() != right_->value()); }
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual void print_flat(std::ostream&,bool add_brackets = false) const;
+ virtual std::string type() const { return stype();}
+ virtual std::string expression(bool why = false) const;
+ static std::string stype() { return "not-equal";}
+};
+
+class AstLessEqual : public AstRoot {
+public:
+ AstLessEqual() {}
+ virtual void accept(ecf::ExprAstVisitor&);
+ virtual AstLessEqual* clone() const;
+ virtual bool evaluate() const { return (left_->value() <= right_->value()); }
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual void print_flat(std::ostream&,bool add_brackets = false) const;
+ virtual std::string type() const { return stype();}
+ virtual std::string expression(bool why = false) const;
+ static std::string stype() { return "less-equal";}
+};
+
+class AstGreaterEqual : public AstRoot {
+public:
+ AstGreaterEqual() {}
+ virtual bool evaluate() const { return (left_->value() >= right_->value()); }
+ virtual void accept(ecf::ExprAstVisitor&);
+ virtual AstGreaterEqual* clone() const;
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual void print_flat(std::ostream&,bool add_brackets = false) const;
+ virtual std::string type() const { return stype();}
+ virtual std::string expression(bool why = false) const;
+ static std::string stype() { return "greater-equal";}
+};
+
+
+class AstGreaterThan : public AstRoot {
+public:
+ AstGreaterThan() {}
+
+ virtual bool evaluate() const { return (left_->value() > right_->value()); }
+ virtual void accept(ecf::ExprAstVisitor&);
+ virtual AstGreaterThan* clone() const;
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual void print_flat(std::ostream&,bool add_brackets = false) const;
+ virtual std::string type() const { return stype();}
+ virtual std::string expression(bool why = false) const;
+ static std::string stype() { return "greater-than";}
+};
+
+
+class AstLessThan : public AstRoot {
+public:
+ AstLessThan() {}
+
+ virtual bool evaluate() const { return (left_->value() < right_->value()); }
+ virtual void accept(ecf::ExprAstVisitor&);
+ virtual AstLessThan* clone() const;
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual void print_flat(std::ostream&,bool add_brackets = false) const;
+ virtual std::string type() const { return stype();}
+ virtual std::string expression(bool why = false) const;
+ static std::string stype() { return "less-than";}
+};
+
+//=============================================================================================
+/// class AstLeaf
+/// represents Integer, String, Node State, event State, Node, variable
+/// These always represent the right side of the tree
+class AstLeaf : public Ast {
+public:
+ AstLeaf() {}
+ virtual void accept(ecf::ExprAstVisitor&);
+ virtual bool isleaf() const { return true; }
+};
+
+class AstInteger : public AstLeaf {
+public:
+ AstInteger(int value) : value_(value) {}
+
+ virtual bool evaluate() const { return value_; } // -1 -2 1 2 3 evaluates to true, 0 returns false
+ virtual void accept(ecf::ExprAstVisitor&);
+ virtual AstInteger* clone() const;
+ virtual int value() const { return value_;}
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual void print_flat(std::ostream&,bool add_brackets = false) const;
+ virtual std::string type() const { return stype();}
+ virtual std::string expression(bool why = false) const;
+ static std::string stype() { return "integer";}
+private:
+ int value_;
+};
+
+class AstString : public AstLeaf {
+public:
+ AstString(const std::string& s) : value_(s) {}
+
+ virtual void accept(ecf::ExprAstVisitor&);
+ virtual AstString* clone() const;
+ virtual int value() const;
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual void print_flat(std::ostream&,bool add_brackets = false) const;
+ virtual std::string type() const { return stype();}
+ virtual std::string expression(bool why = false) const;
+ static std::string stype() { return "string";}
+private:
+ std::string value_;
+};
+
+
+class AstNodeState : public AstLeaf {
+public:
+ AstNodeState(DState::State s) : state_(s) {}
+
+ virtual void accept(ecf::ExprAstVisitor&);
+ virtual AstNodeState* clone() const;
+ virtual int value() const { return static_cast<int>(state_);}
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual void print_flat(std::ostream&,bool add_brackets = false) const;
+ virtual std::string type() const { return stype();}
+ virtual std::string expression(bool why = false) const;
+ static std::string stype() { return "node-state";}
+private:
+ DState::State state_;
+};
+
+class AstEventState : public AstLeaf {
+public:
+ AstEventState(bool b) : state_(b) {}
+
+ virtual void accept(ecf::ExprAstVisitor&);
+ virtual AstEventState* clone() const;
+ virtual int value() const { return state_;}
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual void print_flat(std::ostream&,bool add_brackets = false) const;
+ virtual std::string type() const { return stype();}
+ virtual std::string expression(bool why = false) const;
+ static std::string stype() { return "event-state";}
+private:
+ bool state_;
+};
+
+
+/// This class will need to determine the corresponding node pointer
+/// This is required so that during evaluation we don't need to search for the Node.
+/// represent nodeName(a), dotPath(./a), dot dot path(../a/b)
+///
+/// A Node without a corresponding Node* will return the integer value of
+/// DState::UNKNOWN for the value() function. This will allow for trigger
+/// of the form: trigger a == complete or a == unknown
+/// to be evaluated.
+
+class AstNode : public AstLeaf {
+public:
+ AstNode(const std::string& n) : parentNode_(NULL), nodePath_(n) {}
+
+ virtual void accept(ecf::ExprAstVisitor&);
+ virtual AstNode* clone() const;
+ virtual int value() const { return static_cast<int>(state());}
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual void print_flat(std::ostream&,bool add_brackets = false) const;
+ virtual std::string type() const { return stype();}
+ virtual std::string expression(bool why = false) const;
+ virtual void setParentNode(Node* n) { parentNode_ = n; }
+ static std::string stype() { return "node";}
+
+ const std::string& nodePath() const { return nodePath_;}
+ Node* referencedNode() const;
+ Node* referencedNode(std::string& errorMsg) const;
+ Node* parentNode() const { return parentNode_; }
+ DState::State state() const;
+
+private:
+ Node* get_ref_node() const { return ref_node_.lock().get(); }
+ Node* parentNode_; // should always be non null, before evaluate.
+ std::string nodePath_;
+ mutable weak_node_ptr ref_node_;
+};
+
+/// A variable: This can reference in the CURRENT order:
+/// event,
+/// meter,
+/// user variable,
+/// repeat variable, for enumerated/string we use the positional value
+/// generated variable
+class AstVariable : public AstLeaf {
+public:
+ AstVariable(const std::string& nodePath, const std::string& variablename)
+ : parentNode_(NULL), nodePath_(nodePath), name_(variablename) {}
+
+ virtual void accept(ecf::ExprAstVisitor&);
+ virtual AstVariable* clone() const;
+ virtual int value() const;
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual void print_flat(std::ostream&,bool add_brackets = false) const;
+ virtual std::string type() const { return stype();}
+ virtual std::string expression(bool why = false) const;
+ virtual void setParentNode(Node* n) { parentNode_ = n; }
+
+ virtual int minus(Ast* right) const;
+ virtual int plus(Ast* right) const;
+
+ Node* parentNode() const { return parentNode_; }
+ Node* referencedNode() const;
+ Node* referencedNode(std::string& errorMsg) const;
+
+ static std::string stype() { return "variable";}
+ const std::string& nodePath() const { return nodePath_;}
+ const std::string& name() const { return name_;}
+
+private:
+ Node* get_ref_node() const { return ref_node_.lock().get(); }
+
+ Node* parentNode_;
+ std::string nodePath_;
+ std::string name_;
+ mutable weak_node_ptr ref_node_;
+};
+
+// Helper class
+class VariableHelper : private boost::noncopyable {
+public:
+ VariableHelper(const AstVariable* astVariable);
+ VariableHelper(const AstVariable* astVariable, std::string& errorMsg);
+
+ int value() const;
+ int plus(int)const;
+ int minus(int)const;
+
+ std::ostream& print(std::ostream& os) const;
+ Node* theReferenceNode() const { return theReferenceNode_;}
+
+ void varTypeAndValue(std::string& varType, int & value) const;
+
+private:
+ const AstVariable* astVariable_;
+ Node* theReferenceNode_;
+};
+
+
+//17
+std::ostream& operator<<(std::ostream& os, const Ast&);
+std::ostream& operator<<(std::ostream& os, const AstTop&);
+std::ostream& operator<<(std::ostream& os, const AstRoot&);
+std::ostream& operator<<(std::ostream& os, const AstNot&);
+std::ostream& operator<<(std::ostream& os, const AstPlus&);
+std::ostream& operator<<(std::ostream& os, const AstMinus&);
+std::ostream& operator<<(std::ostream& os, const AstMultiply&);
+std::ostream& operator<<(std::ostream& os, const AstDivide&);
+std::ostream& operator<<(std::ostream& os, const AstModulo&);
+std::ostream& operator<<(std::ostream& os, const AstAnd&);
+std::ostream& operator<<(std::ostream& os, const AstOr&);
+std::ostream& operator<<(std::ostream& os, const AstEqual&);
+std::ostream& operator<<(std::ostream& os, const AstNotEqual&);
+std::ostream& operator<<(std::ostream& os, const AstLessEqual&);
+std::ostream& operator<<(std::ostream& os, const AstGreaterEqual&);
+std::ostream& operator<<(std::ostream& os, const AstGreaterThan&);
+std::ostream& operator<<(std::ostream& os, const AstLessThan&);
+std::ostream& operator<<(std::ostream& os, const AstLeaf&);
+std::ostream& operator<<(std::ostream& os, const AstInteger&);
+std::ostream& operator<<(std::ostream& os, const AstString&);
+std::ostream& operator<<(std::ostream& os, const AstNodeState&);
+std::ostream& operator<<(std::ostream& os, const AstEventState&);
+std::ostream& operator<<(std::ostream& os, const AstNode&);
+std::ostream& operator<<(std::ostream& os, const AstVariable&);
+
+#endif
diff --git a/ANode/src/ExprAstVisitor.cpp b/ANode/src/ExprAstVisitor.cpp
new file mode 100644
index 0000000..aa5a13b
--- /dev/null
+++ b/ANode/src/ExprAstVisitor.cpp
@@ -0,0 +1,74 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #9 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "ExprAstVisitor.hpp"
+#include "ExprAst.hpp"
+#include "Node.hpp"
+#include "Log.hpp"
+
+namespace ecf {
+
+//======================================================================================
+
+ExprAstVisitor::~ExprAstVisitor(){}
+
+//======================================================================================
+AstResolveVisitor::AstResolveVisitor(const Node* node) : triggerNode_(node) {}
+AstResolveVisitor::~AstResolveVisitor() {}
+
+void AstResolveVisitor::visitNode(AstNode* astNode)
+{
+ //std::cout << "AstResolveVisitor::visitNode errorMsg = " << errorMsg_ << "\n";
+ if ( errorMsg_.empty()) {
+
+ astNode->setParentNode(const_cast<Node*>(triggerNode_));
+ Node* node = astNode->referencedNode( errorMsg_ );
+ if ( !node ) {
+ // A node can be NULL when its a extern path. In this case errorMsg should be empty
+ return ;
+ }
+ LOG_ASSERT(errorMsg_.empty(),""); // found Node, make sure errorMsg is empty
+ }
+}
+
+void AstResolveVisitor::visitVariable(AstVariable* astVar)
+{
+ if ( errorMsg_.empty() ) {
+
+ astVar->setParentNode(const_cast<Node*>(triggerNode_));
+
+ /// Use VariableHelper to populate errorMsg_
+ VariableHelper varHelper(astVar,errorMsg_);
+ }
+}
+
+//===========================================================================================================
+
+AstCollateNodesVisitor::AstCollateNodesVisitor( std::set<Node*>& s) : theSet_(s) {}
+AstCollateNodesVisitor::~AstCollateNodesVisitor() {}
+
+void AstCollateNodesVisitor::visitNode(AstNode* astNode)
+{
+ Node* referencedNode = astNode->referencedNode(); // could be expensive, hence don't call twice
+ if ( referencedNode ) theSet_.insert(referencedNode);
+}
+
+void AstCollateNodesVisitor::visitVariable(AstVariable* astVar)
+{
+ Node* referencedNode = astVar->referencedNode(); // could be expensive, hence don't call twice
+ if ( referencedNode ) theSet_.insert(referencedNode);
+}
+
+}
diff --git a/ANode/src/ExprAstVisitor.hpp b/ANode/src/ExprAstVisitor.hpp
new file mode 100644
index 0000000..4e6670c
--- /dev/null
+++ b/ANode/src/ExprAstVisitor.hpp
@@ -0,0 +1,148 @@
+#ifndef EXPRASTVISITOR_HPP_
+#define EXPRASTVISITOR_HPP_
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <set>
+#include <string>
+class Node;
+
+class Ast;
+class AstTop;
+class AstRoot;
+class AstAnd;
+class AstNot;
+class AstPlus;
+class AstMinus;
+class AstDivide;
+class AstMultiply;
+class AstModulo;
+class AstOr;
+class AstEqual;
+class AstNotEqual;
+class AstLessEqual;
+class AstGreaterEqual;
+class AstLessThan;
+class AstGreaterThan;
+class AstLeaf;
+class AstInteger;
+class AstString;
+class AstNodeState;
+class AstEventState;
+class AstNode;
+class AstVariable;
+
+namespace ecf {
+
+class ExprAstVisitor {
+public:
+ virtual ~ExprAstVisitor();
+
+ virtual void visitTop(AstTop*) = 0;
+ virtual void visitRoot(AstRoot*) = 0;
+ virtual void visitAnd(AstAnd*) = 0;
+ virtual void visitNot(AstNot*) = 0;
+ virtual void visitPlus(AstPlus*) = 0;
+ virtual void visitMinus(AstMinus*) = 0;
+ virtual void visitDivide(AstDivide*) = 0;
+ virtual void visitMultiply(AstMultiply*) = 0;
+ virtual void visitModulo(AstModulo*) = 0;
+ virtual void visitOr(AstOr*) = 0;
+ virtual void visitEqual(AstEqual*) = 0;
+ virtual void visitNotEqual(AstNotEqual*) = 0;
+ virtual void visitLessEqual(AstLessEqual*) = 0;
+ virtual void visitGreaterEqual(AstGreaterEqual*) = 0;
+ virtual void visitGreaterThan(AstGreaterThan*) = 0;
+ virtual void visitLessThan(AstLessThan*) = 0;
+ virtual void visitLeaf(AstLeaf*) = 0;
+ virtual void visitInteger(AstInteger*) = 0;
+ virtual void visitString(AstString*) = 0;
+ virtual void visitNodeState(AstNodeState*) = 0;
+ virtual void visitEventState(AstEventState*) = 0;
+ virtual void visitNode(AstNode*) = 0;
+ virtual void visitVariable(AstVariable*) = 0;
+};
+
+class AstResolveVisitor : public ExprAstVisitor {
+public:
+ AstResolveVisitor(const Node* );
+ virtual ~AstResolveVisitor();
+
+ const std::string& errorMsg() const { return errorMsg_;}
+
+ virtual void visitTop(AstTop*){}
+ virtual void visitRoot(AstRoot*){}
+ virtual void visitAnd(AstAnd*){}
+ virtual void visitNot(AstNot*){}
+ virtual void visitPlus(AstPlus*){}
+ virtual void visitMinus(AstMinus*){}
+ virtual void visitDivide(AstDivide*){}
+ virtual void visitMultiply(AstMultiply*){}
+ virtual void visitModulo(AstModulo*){}
+ virtual void visitOr(AstOr*){}
+ virtual void visitEqual(AstEqual*){}
+ virtual void visitNotEqual(AstNotEqual*){}
+ virtual void visitLessEqual(AstLessEqual*){}
+ virtual void visitGreaterEqual(AstGreaterEqual*){}
+ virtual void visitGreaterThan(AstGreaterThan*){}
+ virtual void visitLessThan(AstLessThan*){}
+ virtual void visitLeaf(AstLeaf*){}
+ virtual void visitInteger(AstInteger*){}
+ virtual void visitString(AstString*){}
+ virtual void visitNodeState(AstNodeState*){}
+ virtual void visitEventState(AstEventState*){}
+ virtual void visitNode(AstNode*);
+ virtual void visitVariable(AstVariable*);
+
+private:
+ const Node* triggerNode_;
+ std::string errorMsg_;
+};
+
+class AstCollateNodesVisitor : public ExprAstVisitor {
+public:
+ AstCollateNodesVisitor( std::set<Node*>& );
+ virtual ~AstCollateNodesVisitor();
+
+ virtual void visitTop(AstTop*){}
+ virtual void visitRoot(AstRoot*){}
+ virtual void visitAnd(AstAnd*){}
+ virtual void visitNot(AstNot*){}
+ virtual void visitPlus(AstPlus*){}
+ virtual void visitMinus(AstMinus*){}
+ virtual void visitDivide(AstDivide*){}
+ virtual void visitMultiply(AstMultiply*){}
+ virtual void visitModulo(AstModulo*){}
+ virtual void visitOr(AstOr*){}
+ virtual void visitEqual(AstEqual*){}
+ virtual void visitNotEqual(AstNotEqual*){}
+ virtual void visitLessEqual(AstLessEqual*){}
+ virtual void visitGreaterEqual(AstGreaterEqual*){}
+ virtual void visitGreaterThan(AstGreaterThan*){}
+ virtual void visitLessThan(AstLessThan*){}
+ virtual void visitLeaf(AstLeaf*){}
+ virtual void visitInteger(AstInteger*){}
+ virtual void visitString(AstString*){}
+ virtual void visitNodeState(AstNodeState*){}
+ virtual void visitEventState(AstEventState*){}
+ virtual void visitNode(AstNode*);
+ virtual void visitVariable(AstVariable*);
+
+private:
+ std::set<Node*>& theSet_;
+};
+}
+#endif /* EXPRASTVISITOR_HPP_ */
diff --git a/ANode/src/ExprDuplicate.cpp b/ANode/src/ExprDuplicate.cpp
new file mode 100644
index 0000000..ee45892
--- /dev/null
+++ b/ANode/src/ExprDuplicate.cpp
@@ -0,0 +1,61 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #23 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#if defined(HPUX)
+#include <map>
+#else
+#include <boost/unordered_map.hpp>
+#endif
+#include <boost/foreach.hpp>
+
+#include "ExprDuplicate.hpp"
+#include "ExprAst.hpp"
+
+////////////////////////////////////////////////////////////////////////////
+using namespace std;
+
+#if defined(HPUX)
+// boost 1.51 HPUX has problems with boost::unordered_map
+static std::map< std::string, AstTop* > duplicate_expr;
+typedef std::map< std::string, AstTop* > my_map;
+#else
+static boost::unordered_map< std::string, AstTop* > duplicate_expr;
+typedef boost::unordered_map< std::string, AstTop* > my_map;
+#endif
+
+
+ExprDuplicate::~ExprDuplicate()
+{
+// cout << "ExprDuplicate::~ExprDuplicate()\n";
+ BOOST_FOREACH(my_map::value_type i, duplicate_expr) {
+ AstTop* top = i.second;
+ delete top;
+ }
+ duplicate_expr.clear();
+}
+
+std::auto_ptr<AstTop> ExprDuplicate::find(const std::string& expr)
+{
+ my_map::const_iterator it = duplicate_expr.find(expr);
+ if (it != duplicate_expr.end()) {
+ return std::auto_ptr<AstTop>((*it).second->clone());
+ }
+ return std::auto_ptr<AstTop>();
+}
+
+void ExprDuplicate::add(const std::string& expr,AstTop* ast)
+{
+ assert(!expr.empty() && ast);
+ duplicate_expr.insert( std::make_pair(expr,ast->clone()));
+}
diff --git a/ANode/src/ExprDuplicate.hpp b/ANode/src/ExprDuplicate.hpp
new file mode 100644
index 0000000..a89e8f7
--- /dev/null
+++ b/ANode/src/ExprDuplicate.hpp
@@ -0,0 +1,44 @@
+#ifndef EXPR_DUPLICATE_
+#define EXPR_DUPLICATE_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #11 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+// =========================================================================
+// For large designs > 90% of triggers are identical.
+// We take advantage of this by using a map to store a *CLONED* ast
+// This saves a huge amount on re-parsing using spirit classic.
+//
+// This cloned AST is maintained in a static map, hence we need to
+// manage the lifetime, to avoid valgrind complaining.
+// =========================================================================
+
+#include <string>
+#include <memory> // for auto_ptr
+#include <boost/noncopyable.hpp>
+class AstTop;
+
+// reclaim memory allocated in map, Avoid valgrind errors
+class ExprDuplicate : private boost::noncopyable {
+public:
+ ExprDuplicate() {}
+ ~ExprDuplicate();
+
+ // Find the expr in the map, if found returns a CLONED ast, else NULL
+ static std::auto_ptr<AstTop> find(const std::string& expr);
+
+ // Add the expr to the map, the ast is cloned.
+ static void add(const std::string& expr,AstTop*);
+};
+
+#endif
diff --git a/ANode/src/ExprParser.cpp b/ANode/src/ExprParser.cpp
new file mode 100644
index 0000000..ebc2bc7
--- /dev/null
+++ b/ANode/src/ExprParser.cpp
@@ -0,0 +1,950 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #30 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+// Un-comment these for selective for debugging. At the moment because we have added
+// ast generation BOOST_SPIRIT_DEBUG is to verbose, making debugging a pain.
+// Tpyically I will comment out ONLY BOOST_SPIRIT_DEBUG and enable all the others
+//#define BOOST_SPIRIT_DEBUG
+//#define BOOST_SPIRIT_DUMP_PARSETREE_AS_XML
+//#define PRINT_TREE
+//#define PRINT_AST_TRAVERSAL
+//#define PRINT_AST
+
+#include <boost/spirit/include/classic.hpp>
+#include <boost/spirit/include/classic_core.hpp>
+#include <boost/spirit/include/classic_actor.hpp>
+#include <boost/spirit/include/classic_attribute.hpp>
+#include <boost/spirit/include/classic_confix.hpp>
+#include <boost/spirit/include/phoenix1_binders.hpp>
+#include <boost/spirit/include/classic_ast.hpp>
+#include <boost/spirit/include/classic_tree_to_xml.hpp>
+
+#include "boost/lambda/lambda.hpp"
+#include "boost/lambda/bind.hpp"
+#include "boost/cast.hpp"
+#include <boost/foreach.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/algorithm/string/trim.hpp>
+
+#include <iostream>
+#include <string>
+#include <utility>
+#include <stack>
+#include <sstream>
+#include <map>
+
+#include "ExprParser.hpp"
+#include "ExprAst.hpp"
+#include "ExprDuplicate.hpp"
+#include "Indentor.hpp"
+#include "Log.hpp"
+#include "Str.hpp"
+
+// Reference
+//‘*’ Zero or more
+//‘!’ Zero or one
+//‘+’ One or more
+//‘>>’ Sequence/concatenation
+//‘|’ alternate
+//‘-‘ not
+
+////////////////////////////////////////////////////////////////////////////
+using namespace ecf;
+using namespace std;
+using namespace boost::spirit;
+using namespace phoenix;
+using namespace BOOST_SPIRIT_CLASSIC_NS;
+
+/////////////////////////////////////////////////////////////////////////////
+typedef tree_match<const char*> treematch_t;
+typedef treematch_t::tree_iterator tree_iter_t;
+
+//////////////////////////////////////////////////////////////////////////////
+
+struct ExpressionGrammer : public grammar<ExpressionGrammer>
+{
+ // The parser object is copied a lot, so only use reference/pointer variables as data members
+ ExpressionGrammer(){}
+ ~ExpressionGrammer(){}
+
+ static const int integer_ID = 1;
+ static const int dot_path_ID = 2;
+ static const int equal_1_ID = 3;
+ static const int equal_2_ID = 4;
+ static const int not_equal_1_ID = 5;
+ static const int not_equal_2_ID = 6;
+ static const int node_name_ID = 7;
+ static const int greater_equals_1_ID = 8;
+ static const int greater_equals_2_ID = 9;
+ static const int less_equals_1_ID = 10;
+ static const int less_equals_2_ID = 11;
+ static const int less_than_1_ID = 12;
+ static const int less_than_2_ID = 13;
+ static const int greater_than_1_ID = 14;
+ static const int greater_than_2_ID = 15;
+ static const int node_state_unknown_ID = 16;
+
+ static const int node_state_complete_ID = 18;
+ static const int node_state_queued_ID = 19;
+ static const int node_state_submitted_ID = 20;
+ static const int node_state_active_ID = 21;
+ static const int node_state_aborted_ID = 22;
+ static const int not1_ID = 23;
+ static const int not2_ID = 24;
+ static const int not3_ID = 25;
+ static const int and_ID = 26;
+ static const int or_ID = 27;
+ static const int event_ID = 28;
+ static const int dot_dot_path_ID = 29;
+ static const int event_name_ID = 30;
+ static const int base_trigger_ID = 31;
+ static const int sub_expression_ID = 32;
+ static const int grouping_ID = 33;
+ static const int node_path_state_ID = 34;
+ static const int absolute_path_ID = 35;
+ static const int some_string_ID = 36;
+ static const int variable_ID = 37;
+ static const int variable_path_ID = 38;
+ static const int normal_variable_path_ID = 39;
+ static const int grouped_variable_path_ID = 40;
+ static const int variable_expression_ID = 41;
+ static const int plus_ID = 42;
+ static const int minus_ID = 43;
+ static const int multiply_ID = 44;
+ static const int divide_ID = 45;
+ static const int modulo_ID = 46;
+
+ template <typename ScannerT>
+ struct definition {
+ rule<ScannerT,parser_tag<integer_ID> > integer;
+ rule<ScannerT,parser_tag<plus_ID> > plus;
+ rule<ScannerT,parser_tag<minus_ID> > minus;
+ rule<ScannerT,parser_tag<multiply_ID> > multiply;
+ rule<ScannerT,parser_tag<divide_ID> > divide;
+ rule<ScannerT,parser_tag<modulo_ID> > modulo;
+
+ rule<ScannerT,parser_tag<equal_1_ID> > equal_1;
+ rule<ScannerT,parser_tag<equal_2_ID> > equal_2;
+ rule<ScannerT,parser_tag<not_equal_1_ID> > not_equal_1;
+ rule<ScannerT,parser_tag<not_equal_2_ID> > not_equal_2;
+ rule<ScannerT,parser_tag<node_name_ID> > nodename;
+
+ rule<ScannerT,parser_tag<greater_equals_1_ID> > greater_equals_1;
+ rule<ScannerT,parser_tag<greater_equals_2_ID> > greater_equals_2;
+ rule<ScannerT,parser_tag<less_equals_1_ID> > less_equals_1;
+ rule<ScannerT,parser_tag<less_equals_2_ID> > less_equals_2;
+
+ rule<ScannerT,parser_tag<less_than_1_ID> > less_than_1;
+ rule<ScannerT,parser_tag<less_than_2_ID> > less_than_2;
+ rule<ScannerT,parser_tag<greater_than_1_ID> > greater_than_1;
+ rule<ScannerT,parser_tag<greater_than_2_ID> > greater_than_2;
+
+ rule<ScannerT,parser_tag<node_state_unknown_ID> > node_state_unknown;
+ rule<ScannerT,parser_tag<node_state_complete_ID> > node_state_complete;
+ rule<ScannerT,parser_tag<node_state_queued_ID> > node_state_queued;
+ rule<ScannerT,parser_tag<node_state_submitted_ID> > node_state_submitted;
+ rule<ScannerT,parser_tag<node_state_active_ID> > node_state_active;
+ rule<ScannerT,parser_tag<node_state_aborted_ID> > node_state_aborted;
+
+ rule<ScannerT,parser_tag<not1_ID> > not1_r;
+ rule<ScannerT,parser_tag<not2_ID> > not2_r;
+ rule<ScannerT,parser_tag<not3_ID> > not3_r;
+ rule<ScannerT,parser_tag<and_ID> > and_r;
+ rule<ScannerT,parser_tag<or_ID> > or_r;
+ rule<ScannerT,parser_tag<event_ID> > event;
+
+ rule<ScannerT,parser_tag<dot_path_ID> > dotpath;
+ rule<ScannerT,parser_tag<dot_dot_path_ID> > dotdotpath;
+ rule<ScannerT,parser_tag<absolute_path_ID> > absolutepath;
+ rule<ScannerT,parser_tag<event_name_ID> > eventname;
+
+ rule<ScannerT,parser_tag<base_trigger_ID> > baseTrigger;
+ rule<ScannerT,parser_tag<sub_expression_ID> > subexpression;
+ rule<ScannerT,parser_tag<grouping_ID> > grouping;
+ rule<ScannerT,parser_tag<node_path_state_ID> > nodepathstate;
+
+ rule<ScannerT,parser_tag<some_string_ID> > some_string;
+ rule<ScannerT,parser_tag<variable_ID> > variable;
+ rule<ScannerT,parser_tag<variable_path_ID> > variable_path;
+ rule<ScannerT,parser_tag<normal_variable_path_ID> > normal_variable_path;
+ rule<ScannerT,parser_tag<grouped_variable_path_ID> > grouped_variable_path;
+ rule<ScannerT,parser_tag<variable_expression_ID> > variable_expression;
+
+ rule<ScannerT> not_r,less_than_comparable,expression,andExpr,orExpr,operators;
+ rule<ScannerT> nodestate, equality_comparible, and_or, nodepath ;
+ rule<ScannerT> andsubexpression, orsubexpression,integerComparison,notGrouping ;
+
+ // ‘*’ Zero or more
+ // ‘!’ Zero or one
+ // ‘+’ One or more
+ // ‘>>’ Sequence/concatenation
+ // ‘|’ alternate
+ // ‘-‘ not
+ definition(ExpressionGrammer const& /*self*/)
+ {
+ nodename
+ = leaf_node_d[
+ lexeme_d [ (alnum_p || ch_p('_')) >> *(alnum_p || ch_p('_')) ]
+ ]
+ ;
+
+ // Can be /suite/family/task
+ // family/task
+ // family
+ absolutepath
+ = leaf_node_d[
+ !(str_p("/")) >> nodename
+ >> *(
+ + str_p("/") >> nodename
+ )
+ ]
+ ;
+ dotdotpath // a kind of relative path
+ = leaf_node_d[
+ str_p("..")
+ >> *(
+ + str_p("/") >> str_p("..")
+ )
+ >> +(
+ + str_p("/") >> nodename
+ )
+ ]
+ ;
+ dotpath = leaf_node_d[ str_p(".") >> +( str_p("/") >> nodename) ];
+ nodepath = absolutepath | dotdotpath | dotpath ;
+
+ // Integer is distinct from task/family names that are integers, since nodes with integer
+ // names that occur in trigger/complete expression must have path ./0 ./1
+ integer = leaf_node_d[ uint_p ];
+ plus = root_node_d [ str_p("+") ];
+ minus = root_node_d [ str_p("-") ];
+ divide = root_node_d [ str_p("/") ];
+ multiply = root_node_d [ str_p("*") ];
+ modulo = root_node_d [ str_p("%") ];
+ operators = plus | minus | divide | multiply | modulo ;
+
+ equal_1 = root_node_d [ str_p("==") ];
+ equal_2 = root_node_d [ str_p("eq") ];
+ not_equal_1 = root_node_d [ str_p("!=") ];
+ not_equal_2 = root_node_d [ str_p("ne") ];
+ equality_comparible = equal_1 | equal_2 | not_equal_2 | not_equal_1;
+
+ greater_equals_1 = root_node_d [ str_p(">=") ];
+ greater_equals_2 = root_node_d [ str_p("ge") ];
+ less_equals_1 = root_node_d [ str_p("<=") ];
+ less_equals_2 = root_node_d [ str_p("le") ];
+ less_than_1 = root_node_d [ str_p("<") ];
+ less_than_2 = root_node_d [ str_p("lt") ];
+ greater_than_1 = root_node_d [ str_p(">") ];
+ greater_than_2 = root_node_d [ str_p("gt") ];
+ // Prioritise to most common first, to speed up parsing
+ less_than_comparable
+ = greater_equals_2
+ | less_equals_2
+ | greater_than_2
+ | less_than_2
+ | greater_equals_1
+ | less_equals_1
+ | less_than_1
+ | greater_than_1
+ ;
+
+ not1_r = root_node_d [ str_p("not ") ];
+ not2_r = root_node_d [ str_p("~") ];
+ not3_r = root_node_d [ str_p("!") ];
+ not_r = not1_r | not3_r | not2_r;
+
+ and_r = root_node_d [ str_p("and") ] || root_node_d [ str_p("&&") ] ;
+ or_r = root_node_d [ str_p("or") ] || root_node_d [ str_p("||") ] ;
+ and_or = and_r | or_r;
+
+
+ eventname = leaf_node_d [ nodename ];
+ event
+ = nodepath
+ >> discard_node_d[ ch_p(':') ]
+ >> eventname
+ ;
+
+ some_string = leaf_node_d[ str_p("set") ] || leaf_node_d[ str_p("clear")] ;
+
+ variable = leaf_node_d [ nodename ];
+ normal_variable_path
+ = nodepath
+ >> discard_node_d[ ch_p(':') ]
+ >> variable
+ >> !(operators >> (integer | normal_variable_path))
+ ;
+ grouped_variable_path
+ = discard_node_d[ ch_p('(') ]
+ >> normal_variable_path
+ >> discard_node_d[ ch_p(')') ]
+ ;
+ variable_path = grouped_variable_path | normal_variable_path ;
+
+ variable_expression
+ = variable_path
+ >> ( less_than_comparable | equality_comparible )
+ >> !not_r
+ >> ( variable_path | integer | some_string )
+ ;
+
+
+ node_state_unknown = root_node_d [ str_p("unknown") ];
+ node_state_complete = root_node_d [ str_p("complete") ];
+ node_state_queued = root_node_d [ str_p("queued") ];
+ node_state_submitted = root_node_d [ str_p("submitted") ];
+ node_state_active = root_node_d [ str_p("active") ];
+ node_state_aborted = root_node_d [ str_p("aborted") ];
+ nodestate
+ = node_state_complete
+ | node_state_aborted
+ | node_state_active
+ | node_state_queued
+ | node_state_submitted
+ | node_state_unknown
+ ;
+ nodepathstate = nodepath >> equality_comparible >> nodestate;
+
+ integerComparison = integer >> ( less_than_comparable | equality_comparible) >> ( integer | variable_path );
+
+ baseTrigger
+ = !not_r
+ >> (
+ nodepathstate
+ | variable_expression
+ | event // event if of the form 'a:name'
+ | integerComparison // 1 eq 1
+ )
+ ;
+ andExpr = baseTrigger >> and_r >> baseTrigger;
+ orExpr = baseTrigger >> or_r >> baseTrigger;
+
+ // We need to take special care so that 'and' has a higher priority then 'or'
+ andsubexpression = andExpr >> *(and_or >> subexpression);
+
+ orsubexpression = baseTrigger >> +(or_r >> subexpression);
+
+ subexpression = (andsubexpression | orsubexpression | baseTrigger | notGrouping | integer)
+ >> *(and_or >> subexpression );
+
+ grouping
+ = discard_node_d[ ch_p('(') ]
+ >> subexpression
+ >> discard_node_d[ ch_p(')') ]
+ ;
+
+ notGrouping = !not_r >> grouping >> *(and_or >> subexpression);
+ expression = ( notGrouping | subexpression ) >> end_p;
+
+ BOOST_SPIRIT_DEBUG_NODE(notGrouping);
+ BOOST_SPIRIT_DEBUG_NODE(expression);
+ BOOST_SPIRIT_DEBUG_NODE(andExpr);
+ BOOST_SPIRIT_DEBUG_NODE(not_r);
+ BOOST_SPIRIT_DEBUG_NODE(not1_r);
+ BOOST_SPIRIT_DEBUG_NODE(not2_r);
+ BOOST_SPIRIT_DEBUG_NODE(orExpr);
+ BOOST_SPIRIT_DEBUG_NODE(expression);
+ BOOST_SPIRIT_DEBUG_NODE(nodename);
+ BOOST_SPIRIT_DEBUG_NODE(nodepath);
+ BOOST_SPIRIT_DEBUG_NODE(dotdotpath);
+ BOOST_SPIRIT_DEBUG_NODE(dotpath);
+ BOOST_SPIRIT_DEBUG_NODE(absolutepath);
+ BOOST_SPIRIT_DEBUG_NODE(event);
+ BOOST_SPIRIT_DEBUG_NODE(less_than_comparable);
+ BOOST_SPIRIT_DEBUG_NODE(nodestate);
+ BOOST_SPIRIT_DEBUG_NODE(equality_comparible);
+ BOOST_SPIRIT_DEBUG_NODE(equal_1);
+ BOOST_SPIRIT_DEBUG_NODE(equal_2);
+ BOOST_SPIRIT_DEBUG_NODE(not_equal_1);
+ BOOST_SPIRIT_DEBUG_NODE(not_equal_2);
+ BOOST_SPIRIT_DEBUG_NODE(and_or);
+ BOOST_SPIRIT_DEBUG_NODE(operators);
+ BOOST_SPIRIT_DEBUG_NODE(baseTrigger);
+ BOOST_SPIRIT_DEBUG_NODE(subexpression);
+ BOOST_SPIRIT_DEBUG_NODE(andsubexpression);
+ BOOST_SPIRIT_DEBUG_NODE(orsubexpression);
+ BOOST_SPIRIT_DEBUG_NODE(grouping);
+ BOOST_SPIRIT_DEBUG_NODE(nodepathstate);
+ BOOST_SPIRIT_DEBUG_NODE(integer);
+ BOOST_SPIRIT_DEBUG_NODE(some_string);
+ BOOST_SPIRIT_DEBUG_NODE(variable);
+ BOOST_SPIRIT_DEBUG_NODE(variable_path);
+ BOOST_SPIRIT_DEBUG_NODE(variable_expression);
+ BOOST_SPIRIT_DEBUG_NODE(integerComparison);
+ };
+
+ rule<ScannerT> const& start() const { return expression; }
+ };
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+
+void print(tree_parse_info<> info,
+ const std::string& expr,
+ const std::map< parser_id, std::string >& rule_names);
+
+AstTop* createAst( tree_parse_info< > info,
+ const std::string& expr,
+ const std::map< parser_id, std::string >& rule_names );
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+
+ExprParser::ExprParser( const std::string& expression ): expr_(expression) {}
+
+static std::map< parser_id, std::string > rule_names;
+static void populate_rule_names()
+{
+ if (rule_names.empty()) {
+ rule_names[ExpressionGrammer::equal_1_ID] = "EQUALS";
+ rule_names[ExpressionGrammer::equal_2_ID] = "EQUALS";
+ rule_names[ExpressionGrammer::not_equal_1_ID] = "NOT_EQUAL";
+ rule_names[ExpressionGrammer::not_equal_2_ID] = "NOT_EQUAL";
+ rule_names[ExpressionGrammer::greater_equals_1_ID] = "GREATER_THAN_OR_EQUALS";
+ rule_names[ExpressionGrammer::greater_equals_2_ID] = "GREATER_THAN_OR_EQUALS";
+ rule_names[ExpressionGrammer::less_equals_1_ID] = "LESS_THAN_OR_EQUALS";
+ rule_names[ExpressionGrammer::less_equals_2_ID] = "LESS_THAN_OR_EQUALS";
+ rule_names[ExpressionGrammer::less_than_1_ID] = "LESS_THAN";
+ rule_names[ExpressionGrammer::less_than_2_ID] = "LESS_THAN";
+ rule_names[ExpressionGrammer::greater_than_1_ID] = "GREATER_THAN";
+ rule_names[ExpressionGrammer::greater_than_2_ID] = "GREATER_THAN";
+ rule_names[ExpressionGrammer::not1_ID ] = "NOT";
+ rule_names[ExpressionGrammer::not2_ID ] = "NOT";
+ rule_names[ExpressionGrammer::not3_ID ] = "NOT";
+ rule_names[ExpressionGrammer::and_ID ] = "AND";
+ rule_names[ExpressionGrammer::or_ID ] = "OR";
+ rule_names[ExpressionGrammer::node_name_ID] = "NODE_NAME";
+ rule_names[ExpressionGrammer::node_state_unknown_ID ] = "UNKNOWN";
+ rule_names[ExpressionGrammer::node_state_complete_ID ] = "COMPLETE";
+ rule_names[ExpressionGrammer::node_state_queued_ID ] = "QUEUED";
+ rule_names[ExpressionGrammer::node_state_submitted_ID ] = "SUBMITTED";
+ rule_names[ExpressionGrammer::node_state_active_ID ] = "ACTIVE";
+ rule_names[ExpressionGrammer::node_state_aborted_ID ] = "ABORTED";
+ rule_names[ExpressionGrammer::integer_ID] = "INTEGER";
+ rule_names[ExpressionGrammer::event_ID ] = "EVENT";
+ rule_names[ExpressionGrammer::dot_path_ID ] = "DOT_PATH";
+ rule_names[ExpressionGrammer::dot_dot_path_ID ] = "DOT_DOT_PATH";
+ rule_names[ExpressionGrammer::absolute_path_ID ] = "ABSOLUTE_PATH";
+ rule_names[ExpressionGrammer::event_name_ID ] = "EVENT_NAME";
+
+ rule_names[ExpressionGrammer::base_trigger_ID ] = "BASE_TRIGGER";
+ rule_names[ExpressionGrammer::sub_expression_ID ] = "SUB_EXPRESSION";
+ rule_names[ExpressionGrammer::grouping_ID ] = "GROUPING";
+ rule_names[ExpressionGrammer::node_path_state_ID ] = "NODE_PATH_STATE";
+
+ rule_names[ExpressionGrammer::some_string_ID ] = "STRING";
+ rule_names[ExpressionGrammer::variable_ID ] = "VARIABLE";
+ rule_names[ExpressionGrammer::variable_path_ID ] = "VARIABLE_PATH";
+ rule_names[ExpressionGrammer::grouped_variable_path_ID ] = "GROUPED_VARIABLE_PATH";
+ rule_names[ExpressionGrammer::normal_variable_path_ID ] = "NORMAL_VARIABLE_PATH";
+ rule_names[ExpressionGrammer::variable_expression_ID ] = "VARIABLE_EXPRESSION";
+ }
+}
+
+bool ExprParser::doParse(std::string& errorMsg)
+{
+ if (expr_.empty()) {
+ errorMsg = "Expression is empty";
+ return false;
+ }
+
+ // =========================================================================
+ // For large designs > 90% of triggers are identical.
+ // We take advantage of this by only parsing the expression once
+ // and storing then Abstract Syntax tree( via cloning ) using a map
+ // This saves a huge amount of CPU time in re-parsing using spirit classic.
+ // =========================================================================
+ ast_ = ExprDuplicate::find(expr_);
+ if (ast_.get()) {
+ return true;
+ }
+
+ SimpleExprParser simpleParser(expr_);
+ if (simpleParser.doParse()) {
+ ast_ = simpleParser.ast();
+ ExprDuplicate::add(expr_,ast_.get()); // bypass spirit if same expression used
+ return true;
+ }
+
+ // SPIRIT CLASSIC parsing: very slooooow....
+ ExpressionGrammer grammer;
+ BOOST_SPIRIT_DEBUG_NODE(grammer);
+
+ // Use parser that generates a abstract syntax tree
+ tree_parse_info<> info = ast_parse( expr_.c_str(), grammer, space_p);
+ if (info.full) {
+
+ populate_rule_names();
+
+#if defined(BOOST_SPIRIT_DUMP_PARSETREE_AS_XML)
+ tree_to_xml( cout, info.trees, expr_.c_str(), rule_names );
+#endif
+#if defined(PRINT_TREE)
+ print(info,expr_,rule_names);
+#endif
+ // Spirit has created a AST for us. However it is not use able as is
+ // we will traverse the AST and create our OWN persist-able AST.
+ ast_.reset( createAst(info,expr_,rule_names) );
+ if (ast_->empty()) errorMsg = "Abstract syntax tree creation failed";
+ else {
+ ExprDuplicate::add(expr_,ast_.get());
+ }
+ return errorMsg.empty();
+ }
+ else {
+ std::stringstream ss;
+ ss << "Parsing failed\n";
+ ss << "length = " << std::dec << info.length << "\n";
+ ss << "stopped at: \": " << info.stop << "\"\n";
+ errorMsg = ss.str();
+ }
+ return false;
+}
+
+
+// The evaluation function for the AST
+void do_print(const tree_iter_t& i, const std::map< parser_id, std::string >& rule_names)
+{
+ Indentor in;
+ std::map< parser_id, std::string >::const_iterator iter = rule_names.find(i->value.id());
+ if (iter != rule_names.end()) {
+ Indentor::indent(cout) << "Rule " << (*iter).second
+ << " " << string( i->value.begin(), i->value.end() ) << endl;
+ }
+ else {
+ Indentor::indent(cout) << "Unknown rule "
+ << " " << string( i->value.begin(), i->value.end() ) << endl;
+ }
+
+ Indentor in2;
+ for (tree_iter_t t = i->children.begin(); t != i->children.end(); ++t) {
+ do_print( t, rule_names );
+ }
+}
+
+void print(tree_parse_info<> info,
+ const std::string& expr,
+ const std::map< parser_id, std::string >& rule_names)
+{
+ std::cout << "\nPRINT_TREE " << expr << "\n";
+ do_print(info.trees.begin(),rule_names);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+
+AstRoot* createRootNode(const tree_iter_t& i, const std::map< parser_id, std::string >& rule_names)
+{
+#if defined(PRINT_AST_TRAVERSAL)
+ Indentor in;
+ std::map< parser_id, std::string >::const_iterator iter = rule_names.find(i->value.id());
+ if (iter != rule_names.end()) {
+ Indentor::indent(cout) << "Root Rule " << (*iter).second
+ << " " << string( i->value.begin(), i->value.end() ) << endl;
+ }
+ else {
+ Indentor::indent(cout) << "Unknown root rule "
+ << " " << string( i->value.begin(), i->value.end() ) << endl;
+ }
+#endif
+
+ if ( i->value.id() == ExpressionGrammer::equal_1_ID ) return new AstEqual();
+ if ( i->value.id() == ExpressionGrammer::equal_2_ID ) return new AstEqual();
+ if ( i->value.id() == ExpressionGrammer::and_ID ) return new AstAnd();
+ if ( i->value.id() == ExpressionGrammer::or_ID ) return new AstOr();
+ if ( i->value.id() == ExpressionGrammer::not1_ID ) return new AstNot();
+ if ( i->value.id() == ExpressionGrammer::not2_ID ) return new AstNot();
+ if ( i->value.id() == ExpressionGrammer::not3_ID ) return new AstNot();
+ if ( i->value.id() == ExpressionGrammer::plus_ID ) return new AstPlus();
+
+ if ( i->value.id() == ExpressionGrammer::not_equal_1_ID ) return new AstNotEqual();
+ if ( i->value.id() == ExpressionGrammer::not_equal_2_ID ) return new AstNotEqual();
+ if ( i->value.id() == ExpressionGrammer::greater_equals_1_ID ) return new AstGreaterEqual();
+ if ( i->value.id() == ExpressionGrammer::greater_equals_2_ID ) return new AstGreaterEqual();
+ if ( i->value.id() == ExpressionGrammer::less_equals_1_ID ) return new AstLessEqual();
+ if ( i->value.id() == ExpressionGrammer::less_equals_2_ID ) return new AstLessEqual();
+ if ( i->value.id() == ExpressionGrammer::less_than_1_ID ) return new AstLessThan();
+ if ( i->value.id() == ExpressionGrammer::less_than_2_ID ) return new AstLessThan();
+ if ( i->value.id() == ExpressionGrammer::greater_than_1_ID ) return new AstGreaterThan();
+ if ( i->value.id() == ExpressionGrammer::greater_than_2_ID ) return new AstGreaterThan();
+
+ if ( i->value.id() == ExpressionGrammer::minus_ID ) return new AstMinus();
+ if ( i->value.id() == ExpressionGrammer::multiply_ID ) return new AstMultiply();
+ if ( i->value.id() == ExpressionGrammer::divide_ID ) return new AstDivide();
+ if ( i->value.id() == ExpressionGrammer::modulo_ID ) return new AstModulo();
+ LOG_ASSERT(false,"");
+ return NULL;
+}
+
+Ast* createAst( const tree_iter_t& i, const std::map< parser_id, std::string >& rule_names ) {
+#if defined(PRINT_AST_TRAVERSAL)
+ Indentor in;
+ std::map< parser_id, std::string >::const_iterator iter = rule_names.find(i->value.id());
+ if (iter != rule_names.end()) {
+ Indentor::indent(cout) << "Create AST Rule " << (*iter).second
+ << " '" << string( i->value.begin(), i->value.end() ) << "'\n";
+ }
+ else {
+ Indentor::indent(cout) << "Create AST Unknown rule "
+ << " '" << string( i->value.begin(), i->value.end() ) << "'\n";
+ }
+#endif
+
+
+ if ( i->value.id() == ExpressionGrammer::node_name_ID) {
+
+ string thevalue( i->value.begin(), i->value.end() );
+ boost::algorithm::trim(thevalue); // don't know why we get leading/trailing spaces
+ LOG_ASSERT( !thevalue.empty(), "" );
+ return new AstNode( thevalue );
+ }
+ else if ( i->value.id() == ExpressionGrammer::node_state_complete_ID) {
+
+ return new AstNodeState( DState::COMPLETE );
+ }
+ else if ( i->value.id() == ExpressionGrammer::normal_variable_path_ID) {
+
+ LOG_ASSERT((i->children.size() == 2 || i->children.size() == 4), "");
+ tree_iter_t theNodePathIter = i->children.begin();
+ tree_iter_t theNameIter = i->children.begin()+1;
+
+ string nodePath( theNodePathIter->value.begin(), theNodePathIter->value.end() );
+ string name( theNameIter->value.begin(), theNameIter->value.end() );
+ boost::algorithm::trim(nodePath); // don't know why we get leading/trailing spaces
+ boost::algorithm::trim(name); // don't know why we get leading/trailing spaces
+
+ if ( i->children.size() == 4) {
+ AstRoot* operatorRoot = createRootNode( i->children.begin()+2, rule_names );
+ Ast* astInteger = createAst(i->children.begin()+3, rule_names);
+
+ operatorRoot->addChild( new AstVariable( nodePath, name ));
+ operatorRoot->addChild(astInteger);
+ return operatorRoot;
+ }
+
+ return new AstVariable( nodePath, name );
+ }
+ else if ( i->value.id() == ExpressionGrammer::dot_dot_path_ID) {
+
+ string thevalue( i->value.begin(), i->value.end() );
+ boost::algorithm::trim(thevalue); // don't know why we get leading/trailing spaces
+ LOG_ASSERT( !thevalue.empty() , "");
+ return new AstNode( thevalue );
+ }
+ if ( i->value.id() == ExpressionGrammer::absolute_path_ID) {
+
+ string thevalue( i->value.begin(), i->value.end() );
+ boost::algorithm::trim(thevalue); // don't know why we get leading/trailing spaces
+ LOG_ASSERT( !thevalue.empty() ,"");
+ return new AstNode( thevalue );
+ }
+ else if ( i->value.id() == ExpressionGrammer::dot_path_ID) {
+
+ string thevalue( i->value.begin(), i->value.end() );
+ boost::algorithm::trim(thevalue); // don't know why we get leading/trailing spaces
+ LOG_ASSERT( !thevalue.empty() , "");
+ return new AstNode( thevalue );
+ }
+ else if ( i->value.id() == ExpressionGrammer::event_ID) {
+
+ LOG_ASSERT(i->children.size() >= 2, "");
+ tree_iter_t theNodePathIter = i->children.begin();
+ tree_iter_t theEventNameIter = i->children.begin()+1;
+
+ string nodePath( theNodePathIter->value.begin(), theNodePathIter->value.end() );
+ string eventName( theEventNameIter->value.begin(), theEventNameIter->value.end() );
+ boost::algorithm::trim(nodePath); // don't know why we get leading/trailing spaces
+ boost::algorithm::trim(eventName); // don't know why we get leading/trailing spaces
+
+ return new AstVariable( nodePath, eventName );
+ }
+ else if ( i->value.id() == ExpressionGrammer::some_string_ID) {
+
+ string thevalue( i->value.begin(), i->value.end() );
+ boost::algorithm::trim(thevalue); // don't know why we get leading/trailing spaces
+ return new AstString(thevalue);
+ }
+ else if ( i->value.id() == ExpressionGrammer::integer_ID) {
+
+ string thevalue( i->value.begin(), i->value.end() );
+ boost::algorithm::trim(thevalue); // don't know why we get leading/trailing spaces
+ int theInt = boost::lexical_cast<int>(thevalue);
+ return new AstInteger(theInt);
+ }
+ else if ( i->value.id() == ExpressionGrammer::node_state_aborted_ID) {
+
+ return new AstNodeState( DState::ABORTED );
+ }
+ else if ( i->value.id() == ExpressionGrammer::node_state_active_ID) {
+
+ return new AstNodeState( DState::ACTIVE );
+ }
+ else if ( i->value.id() == ExpressionGrammer::node_state_queued_ID) {
+
+ return new AstNodeState( DState::QUEUED );
+ }
+ else if ( i->value.id() == ExpressionGrammer::node_state_submitted_ID) {
+
+ return new AstNodeState( DState::SUBMITTED );
+ }
+ else if ( i->value.id() == ExpressionGrammer::node_state_unknown_ID) {
+
+ return new AstNodeState( DState::UNKNOWN );
+ }
+
+ return NULL;
+}
+
+// Needed so that testing , when recreating expression uses same name for not.
+static void set_not_name(AstRoot* not_root, boost::spirit::classic::parser_id id)
+{
+ if (not_root) {
+ if (id == ExpressionGrammer::not1_ID) not_root->set_root_name("not ");
+ if (id == ExpressionGrammer::not2_ID) not_root->set_root_name("~ ");
+ if (id == ExpressionGrammer::not3_ID) not_root->set_root_name("! ");
+ }
+}
+
+// The evaluation function for the AST
+Ast* doCreateAst( const tree_iter_t& i,
+ const std::map< parser_id, std::string >& rule_names,
+ Ast* top)
+{
+#if defined(PRINT_AST_TRAVERSAL)
+ Indentor in;
+ std::map< parser_id, std::string >::const_iterator iter = rule_names.find(i->value.id());
+ if (iter != rule_names.end()) {
+ Indentor::indent(cout) << "Rule " << (*iter).second
+ << " " << string( i->value.begin(), i->value.end() ) << endl;
+ }
+ else {
+ Indentor::indent(cout) << "Unknown rule "
+ << " " << string( i->value.begin(), i->value.end() ) << endl;
+ }
+#endif
+
+ Indentor in2;
+ if ( i->value.id() == ExpressionGrammer::event_ID ) {
+ // Event need to handled in a custom way
+ LOG_ASSERT(i->children.size() == 2,"");
+ if (i->children.size() == 2) {
+ // a:eventname || ../a/b:eventname
+ // child 1: path a || ../a/b
+ // child 2: event name
+ // WE add an event state so that when the event is evaluated it is compared to true
+ Ast* someRoot = new AstEqual();
+ Ast* leftEvent = createAst(i, rule_names);
+ Ast* rightEvent = new AstEventState( true );
+ someRoot->addChild(leftEvent);
+ someRoot->addChild(rightEvent);
+ top->addChild(someRoot);
+ }
+ }
+ else if (i->children.size() == 4 &&
+ (i->children.begin()->value.id() == ExpressionGrammer::not1_ID ||
+ i->children.begin()->value.id() == ExpressionGrammer::not2_ID ||
+ i->children.begin()->value.id() == ExpressionGrammer::not3_ID) ) {
+ // child 0: notRoot 0
+ // child 1: notChild +1
+ // child 2: someRoot(i.e ==,!=) +2
+ // child 3: right +3
+ // Create as: someRoot
+ // notRoot right
+ // notChild
+ LOG_ASSERT((i->children.begin()->value.id() == ExpressionGrammer::not1_ID ||
+ i->children.begin()->value.id() == ExpressionGrammer::not2_ID ||
+ i->children.begin()->value.id() == ExpressionGrammer::not3_ID),"");
+ AstRoot* notRoot = createRootNode( i->children.begin(), rule_names );
+ set_not_name(notRoot,i->children.begin()->value.id());
+
+ Ast* notChild = doCreateAst( i->children.begin() + 1, rule_names, notRoot/*top*/ );
+ if (notChild) notRoot->addChild(notChild);
+
+ AstRoot* someRoot = createRootNode( i->children.begin() + 2, rule_names );
+ someRoot->addChild(notRoot); //left
+
+ Ast* right = doCreateAst( i->children.begin() + 3, rule_names, someRoot/* top*/ );
+ if (right) someRoot->addChild(right);
+ top->addChild(someRoot);
+ }
+ else if (i->children.size() == 4 && i->value.id() == ExpressionGrammer::variable_expression_ID ) {
+ LOG_ASSERT((i->children.begin()->value.id() == ExpressionGrammer::normal_variable_path_ID), "");
+ // child 0: NORMAL_VARIABLE_PATH 0
+ // child 1: someRoot(i.e ==,!=) +1
+ // child 2: NOT +2
+ // child 3: integer | variable +3
+ //
+ // Create as: someRoot
+ // varPath notRoot
+ // notChild
+ AstRoot* someRoot = createRootNode( i->children.begin()+1, rule_names );
+ Ast* varPath = doCreateAst( i->children.begin(), rule_names, someRoot/*top*/ );
+
+ AstRoot* notRoot = createRootNode( i->children.begin()+2, rule_names );
+ Ast* notChild = doCreateAst( i->children.begin() + 3, rule_names, notRoot/*top*/ );
+
+ notRoot->addChild(notChild);
+
+ someRoot->addChild(varPath); //left
+ someRoot->addChild(notRoot); //right
+ top->addChild(someRoot);
+ }
+ else if (i->children.size() == 3) {
+ // child 1: left 0
+ // child 2: root(i.e ==,!=) +1
+ // child 3: right +2
+ AstRoot* someRoot = createRootNode( i->children.begin() + 1, rule_names );
+ Ast* left = doCreateAst( i->children.begin(), rule_names, someRoot );
+ Ast* right = doCreateAst( i->children.begin() + 2, rule_names, someRoot );
+ if (left) someRoot->addChild(left);
+ if (right) someRoot->addChild(right);
+ top->addChild(someRoot);
+ }
+ else if (i->children.size() == 2 &&
+ (i->children.begin()->value.id() == ExpressionGrammer::not1_ID ||
+ i->children.begin()->value.id() == ExpressionGrammer::not2_ID ||
+ i->children.begin()->value.id() == ExpressionGrammer::not3_ID ) ) {
+ // child 1: not 0
+ // child 2: left +1
+ AstRoot* someRoot = createRootNode( i->children.begin(), rule_names );
+ set_not_name(someRoot,i->children.begin()->value.id());
+
+ Ast* left = doCreateAst( i->children.begin() + 1, rule_names, someRoot );
+ if (left) someRoot->addChild(left);
+ top->addChild(someRoot);
+ }
+ else {
+ return createAst(i,rule_names);
+ }
+ return NULL;
+}
+
+AstTop* createAst( tree_parse_info< > info,
+ const std::string& expr,
+ const std::map< parser_id, std::string >& rule_names
+)
+{
+#if defined(PRINT_AST_TRAVERSAL)
+ std::cout << "\nPRINT_AST_TRAVERSAL " << expr << "\n";
+#endif
+
+ std::auto_ptr<AstTop> ast(new AstTop);
+ (void)doCreateAst(info.trees.begin(),rule_names,ast.get());
+
+#if defined(PRINT_AST)
+ if (ast.get()) {
+ std::cout << "\nPRINT_AST " << expr << "\n";
+ std::cout << *ast.get();
+ }
+#endif
+ return ast.release();
+}
+
+///////////////////////////////////////////////////////////////////////////
+// SimpleExprParser
+//////////////////////////////////////////////////////////////////////////
+
+bool has_complex_expressions(const std::string& expr)
+{
+ // we allow . and /
+ if (expr.find('(') != string::npos) return true;
+ if (expr.find(':') != string::npos) return true;
+ if (expr.find('.') != string::npos) return true;
+ if (expr.find('/') != string::npos) return true;
+ if (expr.find(" not ") != string::npos) return true;
+ if (expr.find(" and ") != string::npos) return true;
+ if (expr.find(" or ") != string::npos) return true;
+ if (expr.find('!') != string::npos) return true;
+ if (expr.find("&&") != string::npos) return true;
+ if (expr.find("||") != string::npos) return true;
+ if (expr.find('<') != string::npos) return true;
+ if (expr.find('>') != string::npos) return true;
+ if (expr.find('+') != string::npos) return true;
+ if (expr.find('-') != string::npos) return true;
+ if (expr.find('*') != string::npos) return true;
+ if (expr.find('~') != string::npos) return true;
+ if (expr.find(" ne ") != string::npos) return true;
+ if (expr.find(" ge ") != string::npos) return true;
+ if (expr.find("<=") != string::npos) return true;
+ if (expr.find(">=") != string::npos) return true;
+ if (expr.find(" le ") != string::npos) return true;
+ if (expr.find(" gt ") != string::npos) return true;
+ if (expr.find(" lt ") != string::npos) return true;
+ return false;
+}
+
+bool SimpleExprParser::doParse()
+{
+ // 3199.def 57Mg
+ // a == b, || a eq b i.e simple 76940
+ // complex 39240
+ if (has_complex_expressions(expr_)) {
+ return false;
+ }
+
+ // look for path == <state> || path eq state
+ // This gets round issue with Str::split:
+ // "a = complete" will be split
+ // since will split on *ANY* of character, and hence this would not be reported as an error
+ std::vector<std::string> tokens;
+ if (expr_.find("==") != string::npos) {
+ Str::split(expr_, tokens, "==");
+ }
+ else if (expr_.find(" eq ") != string::npos) {
+ Str::split(expr_, tokens, " eq ");
+ }
+ else {
+ return false;
+ }
+
+ if (tokens.size() == 2) {
+
+ boost::algorithm::trim(tokens[0]);
+ boost::algorithm::trim(tokens[1]);
+
+ if (tokens[0].find(' ') != string::npos) {
+// cout << "Found space " << expr_ << "\n";
+ return false;
+ }
+
+ if (DState::isValid(tokens[1])) {
+
+ ast_.reset(new AstTop);
+ Ast* someRoot = new AstEqual();
+ someRoot->addChild(new AstNode(tokens[0]));
+ someRoot->addChild(new AstNodeState(DState::toState(tokens[1])));
+ ast_->addChild(someRoot);
+// cout << "simple expr : " << expr_ << " `" << tokens[0] << "' = '" << tokens[1] << "'\n";
+ return true;
+ }
+ else {
+ try {
+ int left = boost::lexical_cast<int>(tokens[0]);
+ int right = boost::lexical_cast<int>(tokens[1]);
+ ast_.reset(new AstTop);
+ Ast* someRoot = new AstEqual();
+ someRoot->addChild(new AstInteger(left));
+ someRoot->addChild(new AstInteger(right));
+ ast_->addChild(someRoot);
+// cout << "simple INT expr : " << expr_ << " `" << tokens[0] << "' = '" << tokens[1] << "'\n";
+ return true;
+ }
+ catch ( boost::bad_lexical_cast& e ) {
+// cout << "simple INT FAILED expr : " << expr_ << " `" << tokens[0] << "' = '"
+// << tokens[1] << "'\n";
+ }
+ }
+ }
+ return false;
+}
diff --git a/ANode/src/ExprParser.hpp b/ANode/src/ExprParser.hpp
new file mode 100644
index 0000000..93ae7b3
--- /dev/null
+++ b/ANode/src/ExprParser.hpp
@@ -0,0 +1,64 @@
+#ifndef EXPRPARSER_HPP_
+#define EXPRPARSER_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #12 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <string>
+#include <memory> // for auto_ptr
+#include <boost/noncopyable.hpp>
+#include "ExprAst.hpp"
+
+
+/// This class will parse a expression and create the abstract syntax tree
+/// It will own the AST unless specifically released calling ast();
+class ExprParser : private boost::noncopyable {
+public:
+ ExprParser(const std::string& expression);
+
+ /// Parse the expression, return true if parse OK false otherwise
+ /// if false is returned, and error message is returned
+ bool doParse(std::string& errorMsg);
+
+ /// return the Abstract syntax tree, and release memory
+ std::auto_ptr<AstTop> ast() { return ast_;}
+
+ /// return the Abstract syntax tree, without release memory
+ AstTop* getAst() const { return ast_.get();}
+
+private:
+ std::auto_ptr<AstTop> ast_;
+ std::string expr_;
+};
+
+// This class was added to mitigate the slowness of the boost classic spirit parser
+// we will recognise very simple expression, and bypass spirit. Very limited
+// But the simple expression do form a very large subset
+class SimpleExprParser : private boost::noncopyable {
+public:
+ SimpleExprParser(const std::string& expression) : expr_(expression) {}
+
+ /// Parse the expression, return true if parse OK false otherwise
+ bool doParse();
+
+ /// return the Abstract syntax tree, and release memory
+ std::auto_ptr<AstTop> ast() { return ast_;}
+
+private:
+ const std::string& expr_;
+ std::auto_ptr<AstTop> ast_;
+};
+
+#endif
diff --git a/ANode/src/Expression.cpp b/ANode/src/Expression.cpp
new file mode 100644
index 0000000..8e4842e
--- /dev/null
+++ b/ANode/src/Expression.cpp
@@ -0,0 +1,237 @@
+//============================================================================
+// Name : NodeTree.cpp
+// Author : Avi
+// Revision : $Revision: #18 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <assert.h>
+#include <sstream>
+
+#include "Expression.hpp"
+#include "Indentor.hpp"
+#include "ExprParser.hpp"
+#include "Ecf.hpp"
+#include "ExprAstVisitor.hpp"
+#include "Node.hpp"
+#include "Log.hpp"
+#include "PrintStyle.hpp"
+
+using namespace std;
+using namespace ecf;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+std::string PartExpression::toString(const std::string& exprType) const
+{
+ std::stringstream ss;
+ ss << exprType; // trigger or complete
+ switch (exp_type_) {
+ case PartExpression::FIRST: ss << " ";break;
+ case PartExpression::AND: ss << " -a ";break;
+ case PartExpression::OR: ss << " -o ";break;
+ default: assert(false); break;
+ }
+ ss << exp_ << "\n";
+ return ss.str();
+}
+
+std::ostream& PartExpression::print(std::ostream& os,const std::string& exprType, bool isFree) const
+{
+ Indentor in;
+ Indentor::indent(os) << exprType;
+ switch (exp_type_) {
+ case PartExpression::FIRST: os << " ";break;
+ case PartExpression::AND: os << " -a ";break;
+ case PartExpression::OR: os << " -o ";break;
+ default: assert(false); break;
+ }
+ os << exp_;
+
+ if ( !PrintStyle::defsStyle()) {
+ if (exp_type_ == PartExpression::FIRST) {
+ if (isFree) os << " # free";
+ }
+ }
+ os << "\n";
+ return os;
+}
+
+std::auto_ptr<AstTop> PartExpression::parseExpressions(std::string& errorMsg) const
+{
+ //#ifdef DEBUG
+ // cout << "PartExpression::parseExpressions '" << exp_ << "'\n";
+ //#endif
+ if (!exp_.empty()) {
+ ExprParser expressionParser(exp_);
+ if (expressionParser.doParse( errorMsg)) {
+
+ // returns new allocated memory, if no errors
+ std::auto_ptr<AstTop> ast = expressionParser.ast();
+
+ if (errorMsg.empty()) LOG_ASSERT(ast.get(),"");
+ else LOG_ASSERT(!ast.get(), "");
+
+ return ast;
+ }
+ }
+ return std::auto_ptr<AstTop>();
+}
+
+//===========================================================================
+
+Expression::Expression(const std::string& expression)
+: makeFree_(false), state_change_no_(0), theCombinedAst_(0)
+{
+ add(PartExpression(expression));
+}
+
+Expression::Expression(const PartExpression& exp)
+: makeFree_(false), state_change_no_(0),theCombinedAst_(0)
+{
+ add(exp);
+}
+
+Expression::Expression()
+: makeFree_(false), state_change_no_(0), theCombinedAst_(0) {}
+
+Expression::Expression(const Expression& rhs)
+: vec_(rhs.vec_), makeFree_(rhs.makeFree_), state_change_no_(0),theCombinedAst_(0) {}
+
+std::ostream& Expression::print(std::ostream& os, const std::string& exprType) const
+{
+ BOOST_FOREACH(const PartExpression& expr, vec_ ) {
+ expr.print(os,exprType,makeFree_);
+ }
+ return os;
+}
+
+std::string Expression::expression() const
+{
+ string ret;
+ std::vector<PartExpression>::const_iterator theEnd = vec_.end();
+ for(std::vector<PartExpression>::const_iterator expr = vec_.begin(); expr!= theEnd; ++expr) {
+ if ( (*expr).andExpr() ) ret += " AND ";
+ else if ( (*expr).orExpr() ) ret += " OR ";
+ ret += (*expr).expression();
+ }
+ return ret;
+}
+
+void Expression::add(const PartExpression& t)
+{
+ if (vec_.empty()) {
+ // The first expression should not have AND or OR
+ if (t.andExpr() || t.orExpr()) {
+ std::stringstream ss;
+ ss << "Expression::add: expression " << t.expression() << " failed: The first expression should not have AND or OR set";
+ throw std::runtime_error( ss.str() );
+ }
+ }
+ else {
+ // Subsequent expression must be AND or OR expressions
+ if (!t.andExpr() && !t.orExpr()) {
+ std::stringstream ss;
+ ss << "Expression::add: expression " << t.expression() << " failed: Subsequent expression must have AND or OR set";
+ throw std::runtime_error( ss.str() );
+ }
+ }
+ vec_.push_back(t);
+ // cout << "Expression::add " << expression() << "\n";
+}
+
+// ============================================================================
+// CREATE AST tree for each expression, and COMBINE AST for each expression into a single AST.
+// ============================================================================
+void Expression::createAST( Node* node, const std::string& exprType, std::string& errorMsg ) const
+{
+ size_t theSize = vec_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ std::string localErrorMsg;
+ std::auto_ptr<AstTop> ast = vec_[i].parseExpressions( localErrorMsg );
+ if ( ast.get() ) {
+
+ // We can have multiple trigger/complete expression, combine to a single AST tree
+ if (theCombinedAst_.get()) {
+ // Must be trigger with -a(and) or -o(or) option's
+ LOG_ASSERT(theCombinedAst_->isTop(),"");
+ LOG_ASSERT(ast->isTop(),"");
+ /* Combine AST tree
+ top top2 (this top needs to be deleted) top top2
+ | | ===> | |
+ root1 root2 newRoot NULL;
+ / \
+ root1 root2
+ */
+ Ast* newRoot = NULL;
+ if ( vec_[i].andExpr() ) newRoot = new AstAnd();
+ else if ( vec_[i].orExpr() ) newRoot = new AstOr();
+ else LOG_ASSERT(false,""); // what else can it be.
+
+ if ( newRoot ) {
+ newRoot->addChild(theCombinedAst_->left());
+ newRoot->addChild(ast->left());
+ theCombinedAst_->addChild(newRoot); // will overwrite
+
+ // Since we have transferred over root2 it must be set to NULL for top2,
+ // to avoid its child destruction
+ ast->addChild(NULL); // since its an auto_ptr, no need for explicit delete
+ }
+ }
+ else {
+ // The very first expression should _NOT_ be AND/OR trigger. (i.e no -o | -a)
+ LOG_ASSERT((!vec_[i].andExpr()) && (!vec_[i].orExpr()), "");
+ theCombinedAst_ = ast; // transfer ownership
+ theCombinedAst_->exprType(exprType);
+ }
+ // cout << "****************************************************************\n";
+ // cout << theCombinedAst->expression() << "\n";
+ // cout << *theCombinedAst << "\n";
+ }
+ else {
+ std::stringstream ss;
+ ss << "Failed to parse " << vec_[i].toString(exprType) << " at " << node->debugNodePath()
+ << " because " << localErrorMsg << "\n\n";
+ errorMsg += ss.str();
+ }
+ }
+
+ if ( theCombinedAst_.get() ) {
+ theCombinedAst_->setParentNode(node);
+ }
+}
+
+void Expression::setFree()
+{
+ // Only update for a real change
+ if (!makeFree_) {
+ state_change_no_ = Ecf::incr_state_change_no();
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Expression::setFree()\n";
+#endif
+ }
+ makeFree_ = true;
+}
+
+void Expression::clearFree()
+{
+ // Only update for a real change
+ if (makeFree_) {
+ state_change_no_ = Ecf::incr_state_change_no();
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Expression::clearFree()\n";
+#endif
+ }
+ makeFree_ = false;
+}
+
diff --git a/ANode/src/Expression.hpp b/ANode/src/Expression.hpp
new file mode 100644
index 0000000..3bd02bd
--- /dev/null
+++ b/ANode/src/Expression.hpp
@@ -0,0 +1,153 @@
+#ifndef EXPRESSION_HPP_
+#define EXPRESSION_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #20 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <ostream>
+#include <memory> // for auto_ptr
+
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/vector.hpp> // no need to include <vector>
+#include <boost/serialization/string.hpp> // no need to include <string>
+
+#include "ExprAst.hpp"
+class Node;
+
+/// class PartExpression:
+/// Hold a single expression, optional can specify whether it is to be And' or
+/// 'Ored' when used as a part of a larger expression.
+/// Uses compiler , generated destructor, assignment, copy constructor
+class PartExpression {
+public:
+ enum ExprType { FIRST, AND, OR };
+
+ PartExpression(const std::string& expression)
+ : exp_(expression), exp_type_(FIRST) {}
+
+ PartExpression(const std::string& expression, bool and_type)
+ : exp_(expression), exp_type_( (and_type) ? AND : OR) {}
+
+ PartExpression()
+ : exp_type_(FIRST) {}
+
+ const std::string& expression() const { return exp_;}
+ bool andExpr() const { return (exp_type_ == AND) ? true : false ;}
+ bool orExpr() const { return (exp_type_ == OR) ? true : false ;}
+
+ std::string toString(const std::string& exprType) const;
+ std::ostream& print(std::ostream&,const std::string& exprType,bool isFree) const;
+
+ bool operator==(const PartExpression& rhs) const {
+ return exp_type_ == rhs.exp_type_ && exp_ == rhs.exp_;
+ }
+ bool operator!=(const PartExpression& rhs) const { return !operator==(rhs); }
+
+ /// Parse the expression and create the abstract syntax tree
+ std::auto_ptr<AstTop> parseExpressions(std::string& errorMsg) const;
+
+private:
+ std::string exp_;
+ ExprType exp_type_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/)
+ {
+ ar & exp_;
+ ar & exp_type_;
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////////////
+// Class Expression:
+// A Expression occur in a Trigger or Complete statement
+// This class hold a number of part expression.
+// It can also create a single AST from the part expressions
+// NOTE: Distinguish between parser errors, and node path resolution
+// Here we are only concerned with parser errors.
+// Use compiler , generated destructor, assignment, copy constructor
+class Expression {
+public:
+ Expression(const std::string& expression);
+ Expression(const PartExpression& );
+ Expression();
+ Expression(const Expression& rhs);
+
+ bool operator==( const Expression& rhs) const{
+ if (makeFree_ != rhs.makeFree_) return false;
+ return vec_ == rhs.vec_;
+ }
+ bool operator!=( const Expression& rhs) const {
+ return !operator==(rhs);
+ }
+
+ /// User should add "trigger" or "complete" at the start.
+ /// The part expression's are combined and returned as a single string
+ std::string expression() const;
+
+ /// Need to pass in trigger tag, since expression may be split over multiple lines
+ /// trigger "a == complete"
+ /// trigger -a "b == complete"
+ std::ostream& print(std::ostream&,const std::string& exprType) const;
+
+ /// Use when we want to add compose a large expression form a set of smaller ones
+ void add( const PartExpression& t );
+
+ // ==============================================================================================
+ // CREATE AST tree for each expression and COMBINE AST for each expression into a single AST.
+ // ==============================================================================================
+ void createAST( Node* parent_node, const std::string& exprType, std::string& errorMsg ) const;
+ AstTop* get_ast() const { return theCombinedAst_.get(); } // can return NULL
+
+ /// Placed here rather than the expression tree. Since the expression
+ /// tree is created on demand, and is not persisted
+ void setFree(); // hence must be used before evaluate
+ void clearFree(); // resets the free flag
+ bool isFree() const { return makeFree_;}
+
+ // The state_change_no is never reset. Must be incremented if it can affect equality
+ unsigned int state_change_no() const { return state_change_no_; }
+
+private: /// For use by python interface,
+ friend void export_Node();
+ std::vector<PartExpression>::const_iterator part_begin() const { return vec_.begin();}
+ std::vector<PartExpression>::const_iterator part_end() const { return vec_.end();}
+
+private:
+ std::vector<PartExpression> vec_;
+ bool makeFree_;
+
+ unsigned int state_change_no_; // *not* persisted, only used on server side
+
+ // They are created on demand. reasons:
+ // 1/ Help with AIX serialisation
+ // 2/ Help to reduce network traffic
+ mutable std::auto_ptr< AstTop > theCombinedAst_; // *not* persisted, demand created
+
+private:
+ // prevent assignment since we have an auto_ptr
+ Expression& operator=(Expression const& f);
+
+private:
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/)
+ {
+ ar & vec_;
+ ar & makeFree_;
+ }
+};
+#endif
diff --git a/ANode/src/Family.cpp b/ANode/src/Family.cpp
new file mode 100644
index 0000000..34311bd
--- /dev/null
+++ b/ANode/src/Family.cpp
@@ -0,0 +1,196 @@
+//============================================================================
+// Name : NodeTree.cpp
+// Author : Avi
+// Revision : $Revision: #64 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <assert.h>
+#include <sstream>
+#include <boost/make_shared.hpp>
+
+#include "Family.hpp"
+#include "Log.hpp"
+#include "PrintStyle.hpp"
+#include "NodeTreeVisitor.hpp"
+#include "Ecf.hpp"
+
+#include "Stl.hpp"
+#include "Str.hpp"
+#include "Indentor.hpp"
+#include "DefsDelta.hpp"
+#include "JobsParam.hpp"
+
+using namespace ecf;
+using namespace std;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// The false below is used as a dummy argument to call the Variable constructor that does not
+// Check the variable names. i.e we know they are valid
+Family::~Family()
+{
+ if (!Ecf::server()) {
+ notify_delete();
+ }
+
+ delete fam_gen_variables_;
+}
+
+family_ptr Family::create(const std::string& name)
+{
+ return boost::make_shared<Family>( name );
+}
+
+void Family::accept(ecf::NodeTreeVisitor& v)
+{
+ v.visitFamily(this);
+ NodeContainer::accept(v);
+}
+
+void Family::acceptVisitTraversor(ecf::NodeTreeVisitor& v)
+{
+ v.visitFamily(this);
+}
+
+void Family::begin()
+{
+ NodeContainer::begin();
+ update_generated_variables();
+}
+
+bool Family::resolveDependencies(JobsParam& jobsParam)
+{
+ if (jobsParam.check_for_job_generation_timeout()) return false;
+
+ return NodeContainer::resolveDependencies(jobsParam);
+}
+
+void Family::requeue(bool resetRepeats, int clear_suspended_in_child_nodes, bool reset_next_time_slot)
+{
+ NodeContainer::requeue(resetRepeats,clear_suspended_in_child_nodes,reset_next_time_slot);
+ update_generated_variables();
+}
+
+bool Family::operator==(const Family& rhs) const
+{
+ return NodeContainer::operator==(rhs);
+}
+
+std::ostream& Family::print(std::ostream& os) const
+{
+ // Generated variable are not persisted since they are created on demand
+ // There *NO* point in printing them they will always be empty
+
+ Indentor in;
+ Indentor::indent(os) << "family " << name();
+ if (!PrintStyle::defsStyle()) {
+ std::string st = write_state();
+ if (!st.empty()) os << " #" << st;
+ }
+ os << "\n";
+
+ Node::print(os);
+ NodeContainer::print(os);
+ Indentor::indent(os) << "endfamily\n";
+ return os;
+}
+
+std::string Family::write_state() const
+{
+ return NodeContainer::write_state();
+}
+void Family::read_state(const std::string& line,const std::vector<std::string>& lineTokens)
+{
+ NodeContainer::read_state(line,lineTokens);
+}
+
+const std::string& Family::debugType() const { return ecf::Str::FAMILY();}
+
+std::ostream& operator<<(std::ostream& os, const Family& d) { return d.print(os); }
+
+void Family::collateChanges(DefsDelta& changes) const
+{
+ /// All changes to family should be on ONE compound_memento_ptr
+ compound_memento_ptr compound;
+ NodeContainer::incremental_changes(changes, compound);
+
+ // Traversal
+ NodeContainer::collateChanges(changes);
+}
+
+// generated variables --------------------------------------------------------------------------
+
+void Family::update_generated_variables() const
+{
+ if (!fam_gen_variables_) fam_gen_variables_ = new FamGenVariables(this);
+ fam_gen_variables_->update_generated_variables();
+ update_repeat_genvar();
+}
+
+const Variable& Family::findGenVariable(const std::string& name) const
+{
+ // Generally it should be never the case that the values are empty
+ // Since the user is assumed to have called begin(), which force
+ // the generation of generated variables
+
+ // AST can reference generated variables. Currently integer based values
+ // The family names can be integers
+
+ if (!fam_gen_variables_) update_generated_variables();
+ const Variable& gen_var = fam_gen_variables_->findGenVariable(name);
+ if (!gen_var.empty()) return gen_var;
+
+ return NodeContainer::findGenVariable(name);
+}
+
+void Family::gen_variables(std::vector<Variable>& vec) const
+{
+ if (!fam_gen_variables_) update_generated_variables();
+
+ vec.reserve(vec.size() + 3);
+ fam_gen_variables_->gen_variables(vec);
+ NodeContainer::gen_variables(vec);
+}
+
+// ================================================================
+
+FamGenVariables::FamGenVariables(const Family* f)
+ : family_(f),
+ genvar_family_("FAMILY", "", false),
+ genvar_family1_("FAMILY1", "", false) {}
+
+void FamGenVariables::update_generated_variables() const
+{
+ // This function is called during:
+ // o begin()
+ // o requeue()
+ // Since family generated not persisted, allow for demand creation by client
+ genvar_family1_.set_value(family_->name());
+
+ // FAMILY is the full path excluding the suite, there is *NO* leading slash
+ std::string path = family_->absNodePath();
+ string::size_type secondSlash = path.find('/',1);
+ path.erase(0,secondSlash+1);
+ genvar_family_.set_value(path);
+}
+
+const Variable& FamGenVariables::findGenVariable(const std::string& name) const
+{
+ if (genvar_family_.name() == name) return genvar_family_;
+ if (genvar_family1_.name() == name) return genvar_family1_;
+ return Variable::EMPTY();
+}
+
+void FamGenVariables::gen_variables(std::vector<Variable>& vec) const
+{
+ vec.push_back(genvar_family_);
+ vec.push_back(genvar_family1_);
+}
diff --git a/ANode/src/Family.hpp b/ANode/src/Family.hpp
new file mode 100644
index 0000000..12a4f79
--- /dev/null
+++ b/ANode/src/Family.hpp
@@ -0,0 +1,86 @@
+#ifndef FAMILY_HPP_
+#define FAMILY_HPP_
+
+//============================================================================
+// Name : NodeTree.hpp
+// Author : Avi
+// Revision : $Revision: #37 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "NodeContainer.hpp"
+class FamGenVariables;
+
+class Family : public NodeContainer {
+public:
+ Family( const std::string& name ) : NodeContainer(name),fam_gen_variables_(NULL) {}
+ Family() : fam_gen_variables_(NULL) {}
+ virtual ~Family();
+
+ static family_ptr create(const std::string& name);
+
+ virtual Suite* suite() const { return parent()->suite(); }
+ virtual Defs* defs() const { return (parent()) ? parent()->defs() : NULL;} // exposed to python hence check for NULL first
+ virtual Family* isFamily() const { return const_cast<Family*>(this);}
+ virtual NodeContainer* isNodeContainer() const { return const_cast<Family*>(this); }
+
+ virtual void begin();
+ virtual bool resolveDependencies(JobsParam& ); // overriden to speicy family for job profiler
+ virtual void requeue(bool resetRepeats, int clear_suspended_in_child_nodes, bool reset_next_time_slot);
+ virtual void accept(ecf::NodeTreeVisitor&);
+ virtual void acceptVisitTraversor(ecf::NodeTreeVisitor& v);
+ virtual void update_generated_variables() const;
+ virtual const Variable& findGenVariable(const std::string& name) const;
+ virtual void gen_variables(std::vector<Variable>&) const;
+
+ virtual const std::string& debugType() const;
+
+ std::ostream& print(std::ostream&) const;
+ bool operator==(const Family& rhs) const;
+
+ virtual void collateChanges(DefsDelta&) const;
+ void set_memento(const OrderMemento* m,std::vector<ecf::Aspect::Type>& aspects) { NodeContainer::set_memento(m,aspects); }
+ void set_memento(const ChildrenMemento* m,std::vector<ecf::Aspect::Type>& aspects) { NodeContainer::set_memento(m,aspects); }
+
+ virtual void read_state(const std::string& line,const std::vector<std::string>& lineTokens);
+private:
+ virtual std::string write_state() const;
+
+ mutable FamGenVariables* fam_gen_variables_;
+
+private:
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/) {
+ ar & boost::serialization::base_object<NodeContainer>(*this);
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, const Family&);
+
+
+// We can have several thousands Families. This class helps in avoiding
+// the creation of generated variables until required.
+// This improves client->server down load times by avoiding thousands of string constructions
+class FamGenVariables : private boost::noncopyable {
+public:
+ FamGenVariables(const Family*);
+
+ void update_generated_variables() const;
+ const Variable& findGenVariable(const std::string& name) const;
+ void gen_variables(std::vector<Variable>& vec) const;
+
+private:
+ const Family* family_;
+ mutable Variable genvar_family_;
+ mutable Variable genvar_family1_;
+};
+#endif
diff --git a/ANode/src/Flag.cpp b/ANode/src/Flag.cpp
new file mode 100644
index 0000000..20533f3
--- /dev/null
+++ b/ANode/src/Flag.cpp
@@ -0,0 +1,165 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #12 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <stdexcept>
+#include <iostream>
+#include "Flag.hpp"
+#include "Ecf.hpp"
+#include "Str.hpp"
+
+namespace ecf {
+
+void Flag::set(Flag::Type flag)
+{
+ if (!is_set(flag)) {
+ // minimize changes to state_change_no_
+ flag_ |= (1<<flag);
+ state_change_no_ = Ecf::incr_state_change_no();
+ }
+}
+
+void Flag::clear(Flag::Type flag )
+{
+ if (is_set(flag)) {
+ // minimize changes to state_change_no_
+ flag_ &= ~(1<<flag);
+ state_change_no_ = Ecf::incr_state_change_no();
+ }
+}
+
+void Flag::reset() {
+ flag_ = 0;
+ state_change_no_ = Ecf::incr_state_change_no();
+}
+
+std::vector<Flag::Type> Flag::list()
+{
+ std::vector<Flag::Type> ret; ret.reserve(15);
+ ret.push_back(Flag::FORCE_ABORT);
+ ret.push_back(Flag::USER_EDIT);
+ ret.push_back(Flag::TASK_ABORTED);
+ ret.push_back(Flag::EDIT_FAILED);
+ ret.push_back(Flag::JOBCMD_FAILED);
+ ret.push_back(Flag::NO_SCRIPT);
+ ret.push_back(Flag::KILLED);
+ ret.push_back(Flag::MIGRATED);
+ ret.push_back(Flag::LATE);
+ ret.push_back(Flag::MESSAGE);
+ ret.push_back(Flag::BYRULE);
+ ret.push_back(Flag::QUEUELIMIT);
+ ret.push_back(Flag::WAIT);
+ ret.push_back(Flag::LOCKED);
+ ret.push_back(Flag::ZOMBIE);
+ ret.push_back(Flag::NO_REQUE_IF_SINGLE_TIME_DEP);
+ return ret;
+}
+
+std::string Flag::enum_to_string(Flag::Type flag) {
+
+ switch ( flag ) {
+ case Flag::FORCE_ABORT: return "force_aborted"; break;
+ case Flag::USER_EDIT : return "user_edit"; break;
+ case Flag::TASK_ABORTED: return "task_aborted"; break;
+ case Flag::EDIT_FAILED: return "edit_failed"; break;
+ case Flag::JOBCMD_FAILED:return "ecfcmd_failed"; break;
+ case Flag::NO_SCRIPT: return "no_script"; break;
+ case Flag::KILLED: return "killed"; break;
+ case Flag::MIGRATED: return "migrated"; break;
+ case Flag::LATE: return "late"; break;
+ case Flag::MESSAGE: return "message"; break;
+ case Flag::BYRULE: return "by_rule"; break;
+ case Flag::QUEUELIMIT: return "queue_limit"; break;
+ case Flag::WAIT: return "task_waiting"; break;
+ case Flag::LOCKED: return "locked"; break;
+ case Flag::ZOMBIE: return "zombie"; break;
+ case Flag::NO_REQUE_IF_SINGLE_TIME_DEP: return "no_reque"; break;
+ case Flag::NOT_SET: return "not_set"; break;
+ default: break;
+ };
+ return std::string();
+}
+
+
+Flag::Type Flag::string_to_flag_type(const std::string& s)
+{
+ if (s == "force_aborted") return Flag::FORCE_ABORT;
+ if (s == "user_edit") return Flag::USER_EDIT;
+ if (s == "task_aborted") return Flag::TASK_ABORTED;
+ if (s == "edit_failed") return Flag::EDIT_FAILED;
+ if (s == "ecfcmd_failed") return Flag::JOBCMD_FAILED;
+ if (s == "no_script") return Flag::NO_SCRIPT;
+ if (s == "killed") return Flag::KILLED;
+ if (s == "migrated") return Flag::MIGRATED;
+ if (s == "late") return Flag::LATE;
+ if (s == "message") return Flag::MESSAGE;
+ if (s == "by_rule") return Flag::BYRULE;
+ if (s == "queue_limit") return Flag::QUEUELIMIT;
+ if (s == "task_waiting") return Flag::WAIT;
+ if (s == "locked") return Flag::LOCKED;
+ if (s == "zombie") return Flag::ZOMBIE;
+ if (s == "no_reque") return Flag::NO_REQUE_IF_SINGLE_TIME_DEP;
+ return Flag::NOT_SET;
+}
+
+void Flag::valid_flag_type(std::vector<std::string>& vec)
+{
+ vec.reserve(15);
+ vec.push_back("force_aborted");
+ vec.push_back("user_edit");
+ vec.push_back("task_aborted");
+ vec.push_back("edit_failed");
+ vec.push_back("ecfcmd_failed");
+ vec.push_back("no_script");
+ vec.push_back("killed");
+ vec.push_back("migrated");
+ vec.push_back("late");
+ vec.push_back("message");
+ vec.push_back("by_rule");
+ vec.push_back("queue_limit");
+ vec.push_back("task_waiting");
+ vec.push_back("locked");
+ vec.push_back("zombie");
+ vec.push_back("no_reque");
+}
+
+std::string Flag::to_string() const
+{
+ std::string ret;
+ std::vector<Flag::Type> flag_list = Flag::list();
+ for (size_t i = 0; i < flag_list.size(); ++i) {
+ if ( is_set( flag_list[i] ) ) {
+ if (!ret.empty()) ret += ',';
+ ret += enum_to_string( flag_list[i]);
+ }
+ }
+ return ret;
+}
+
+void Flag::set_flag(const std::string& flags)
+{
+ std::vector< std::string > the_flags_vec;
+ Str::split(flags,the_flags_vec,",");
+
+ for(size_t i =0; i < the_flags_vec.size(); i++) {
+ Flag::Type ft = string_to_flag_type(the_flags_vec[i]);
+ if (ft == Flag::NOT_SET) {
+ throw std::runtime_error("Flag::set_flag: Unknown flag types found: " + the_flags_vec[i]);
+ }
+ set(ft);
+ }
+}
+
+
+}
diff --git a/ANode/src/Flag.hpp b/ANode/src/Flag.hpp
new file mode 100644
index 0000000..665568a
--- /dev/null
+++ b/ANode/src/Flag.hpp
@@ -0,0 +1,119 @@
+#ifndef FLAG_HPP_
+#define FLAG_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #15 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <vector>
+#include <string>
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/level.hpp>
+#include <boost/serialization/tracking.hpp>
+
+namespace ecf {
+
+/// Flag are used store what has happened to a node. These are shown as icon in ecFlowview
+/// Uses compiler generated copy constructor, assignment operator and destructor
+
+/// During interactive use. A Node can be *forced to complete*, or forced to *run*
+/// Typically the user may want to force a node to complete, if they are trying
+/// to update the repeat variable.
+///
+/// In either case we need to miss a time slot, this is done by setting the
+/// NO_REQUE_IF_SINGLE_TIME_DEP, then at REQUE time we query the flag, if it was set
+/// we avoid resetting the time slots. effectively missing the next time slot.
+///
+/// This functionality is only required during interactive force or run
+/// However if the job aborted, we need to clear NO_REQUE_IF_SINGLE_TIME_DEP, i.e
+/// time 10:00
+/// time 11:00
+/// If at 9.00am use the run command, we want to miss the 10:00 time slot.
+/// However if the run at 9.00 fails, and we run again, we also miss 11:00 time slot
+/// to avoid this if the job aborts, we clear NO_REQUE_IF_SINGLE_TIME_DEP flag.
+
+class Flag {
+public:
+ Flag() : flag_(0),state_change_no_(0) {}
+
+ /// The BYRULE is used to distinguish between tasks that have RUN and completed
+ /// and those that have completed by complete expression.
+ enum Type {
+ FORCE_ABORT = 0, // Node* do not run when try_no > ECF_TRIES, and task aborted by user
+ USER_EDIT = 1, // task
+ TASK_ABORTED = 2, // task*
+ EDIT_FAILED = 3, // task*
+ JOBCMD_FAILED = 4, // task*
+ NO_SCRIPT = 5, // task*
+ KILLED = 6, // task* do not run when try_no > ECF_TRIES, and task killed by user
+ MIGRATED = 7, // Node ( NOT USED currently )
+ LATE = 8, // Node attribute, Task is late, or Defs checkpt takes to long
+ MESSAGE = 9, // Node
+ BYRULE = 10, // Node*, set if node is set to complete by complete trigger expression
+ QUEUELIMIT = 11, // Node ( NOT USED currently)
+ WAIT = 12, // task* Set/cleared but never queried ? ( NOT USED currently )
+ LOCKED = 13, // Server ( NOT USED currently)
+ ZOMBIE = 14, // task* Set/cleared but never queried ? ( NOT USED currently )
+ NO_REQUE_IF_SINGLE_TIME_DEP = 15, //
+ NOT_SET = 16
+ };
+
+ bool operator==(const Flag& rhs) const { return flag_ == rhs.flag_; }
+ bool operator!=(const Flag& rhs) const { return !operator==(rhs); }
+
+
+ // Flag functions:
+ void set(Type flag);
+ void clear(Type flag );
+ bool is_set(Type flag) const { return ( flag_ & (1 << flag)); }
+
+ void reset();
+ int flag() const { return flag_;}
+ void set_flag(int f) { flag_ = f; }
+ void set_flag(const std::string& flags); // these are comma separated
+
+ /// returns a comma separated list of all flags set
+ std::string to_string() const;
+
+ /// returns the string equivalent
+ static std::string enum_to_string(Flag::Type flag);
+
+ /// Used to determine change in state relative to client
+ unsigned int state_change_no() const { return state_change_no_; }
+
+ /// returns the list of all flag types
+ static std::vector<Flag::Type> list();
+
+ /// Converts from string to flag types.
+ static Flag::Type string_to_flag_type(const std::string& s);
+
+ /// valid flag types, than can be used in AlterCmd
+ static void valid_flag_type(std::vector<std::string>& vec);
+
+private:
+ int flag_;
+ unsigned int state_change_no_; // *not* persisted, only used on server side
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/) {
+ ar & flag_;
+ }
+};
+}
+
+// This should ONLY be added to objects that are *NOT* serialised through a pointer
+BOOST_CLASS_IMPLEMENTATION(ecf::Flag, boost::serialization::object_serializable)
+BOOST_CLASS_TRACKING(ecf::Flag,boost::serialization::track_never);
+
+#endif
diff --git a/ANode/src/InLimit.cpp b/ANode/src/InLimit.cpp
new file mode 100644
index 0000000..86adb56
--- /dev/null
+++ b/ANode/src/InLimit.cpp
@@ -0,0 +1,83 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #64 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <assert.h>
+#include <sstream>
+#include <stdexcept>
+
+#include "InLimit.hpp"
+#include "Limit.hpp"
+#include "Indentor.hpp"
+#include "PrintStyle.hpp"
+#include "Str.hpp"
+#include "Ecf.hpp"
+
+using namespace std;
+using namespace ecf;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+
+InLimit::InLimit(const std::string& name, const std::string& pathToNode, int tokens)
+: name_(name),pathToNode_(pathToNode),tokens_(tokens)
+{
+ if ( !Str::valid_name( name ) ) {
+ throw std::runtime_error("InLimit::InLimit: Invalid InLimit name: " + name);
+ }
+}
+
+bool InLimit::operator==( const InLimit& rhs ) const
+{
+ if ( pathToNode_ != rhs.pathToNode_ ) {
+ //#ifdef DEBUG
+ // std::cout << "InLimit::operator== pathToNode_ != rhs.pathToNode_\n";
+ //#endif
+ return false;
+ }
+ if ( name_ != rhs.name_ ) {
+ //#ifdef DEBUG
+ // std::cout << "InLimit::operator== name_ != rhs.name_\n";
+ //#endif
+ return false;
+ }
+ if ( tokens_ != rhs.tokens_ ) {
+ //#ifdef DEBUG
+ // std::cout << "InLimit::operator== tokens_(" << tokens_ << ") != rhs.tokens_(" << rhs.tokens_ << ") \n";
+ //#endif
+ return false;
+ }
+
+ // Note: comparison does not look at Limit pointers
+ return true;
+}
+
+std::ostream& InLimit::print( std::ostream& os ) const {
+ Indentor in;
+ Indentor::indent( os ) << toString();
+ if ( PrintStyle::getStyle() == PrintStyle::STATE) {
+ if ( limit() )
+ os << " # referenced limit(value) " << limit()->theLimit() << "(" << limit()->value() << ")";
+ }
+ os << "\n";
+ return os;
+}
+
+std::string InLimit::toString() const {
+ std::stringstream ss;
+ if ( pathToNode_.empty() ) ss << "inlimit " << name_;
+ else ss << "inlimit " << pathToNode_ << Str::COLON() << name_;
+ if ( tokens_ != 1 ) ss << " " << tokens_;
+ return ss.str();
+}
+
diff --git a/ANode/src/InLimit.hpp b/ANode/src/InLimit.hpp
new file mode 100644
index 0000000..13051db
--- /dev/null
+++ b/ANode/src/InLimit.hpp
@@ -0,0 +1,72 @@
+#ifndef INLIMIT_HPP_
+#define INLIMIT_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #61 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <ostream>
+
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/string.hpp> // no need to include <string>
+#include <boost/serialization/weak_ptr.hpp>
+
+#include "LimitFwd.hpp"
+
+
+// Inlimit. Multiple inlimits on same Node are logically ANDED
+// inlimit limitName // This will consume one token in the limit <limitName>
+// inlimit limitName 10 // This will consume 10 tokens in the limit <limitName>
+// inlimit -n limitName // Only applicable to a family, does not matter how many tasks
+// // the family has, will only consume one token in the family
+// // This is like showing that family is active/ has at least
+// // one task that is submitted <<<<NOT SUPPORTED YET>>>>>>
+//
+// Inlimit of the same name specified on a task take priority over the family
+class InLimit {
+public:
+ InLimit(const std::string& name,
+ const std::string& pathToNode = std::string(),
+ int tokens = 1);
+ InLimit() : tokens_(1) {}
+
+ std::ostream& print(std::ostream&) const;
+ bool operator==(const InLimit& rhs) const;
+
+ const std::string& name() const { return name_;} // must be defined
+ const std::string& pathToNode() const { return pathToNode_;} // can be empty,the node referenced by the In-Limit, this should hold the Limit.
+ int tokens() const { return tokens_;}
+
+ std::string toString() const;
+
+private:
+ void limit( limit_ptr l) { limit_ = boost::weak_ptr<Limit>(l);}
+ Limit* limit() const { return limit_.lock().get();} // can return NULL
+ friend class InLimitMgr;
+
+private:
+ std::string name_;
+ std::string pathToNode_;
+ int tokens_;
+ boost::weak_ptr<Limit> limit_; // NOT persisted since computed on the fly
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/) {
+ ar & name_;
+ ar & pathToNode_; // can be empty
+ ar & tokens_;
+ }
+};
+
+#endif
diff --git a/ANode/src/InLimitMgr.cpp b/ANode/src/InLimitMgr.cpp
new file mode 100644
index 0000000..80da4e2
--- /dev/null
+++ b/ANode/src/InLimitMgr.cpp
@@ -0,0 +1,436 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #28 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <assert.h>
+#include <boost/foreach.hpp>
+#include <boost/make_shared.hpp>
+
+#include "InLimitMgr.hpp"
+#include "Limit.hpp"
+#include "Node.hpp"
+#include "Memento.hpp"
+#include "Ecf.hpp"
+#include "Str.hpp"
+
+using namespace ecf;
+using namespace std;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+std::ostream& InLimitMgr::print(std::ostream& os) const
+{
+ BOOST_FOREACH(const InLimit& i, inLimitVec_) { i.print(os); }
+ return os;
+}
+
+bool InLimitMgr::operator==(const InLimitMgr& rhs) const
+{
+ if (inLimitVec_.size() != rhs.inLimitVec_.size()) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "InLimitMgr::operator== inLimitVec_.size() != rhs.inLimitVec_.size() " << node_->debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ for(size_t i = 0; i < inLimitVec_.size(); ++i) {
+ if (!(inLimitVec_[i] == rhs.inLimitVec_[i] )) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "InLimitMgr::operator== (!(inLimitVec_[i] == rhs.inLimitVec_[i] )) " << node_->debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ }
+ return true;
+}
+
+void InLimitMgr::addInLimit(const InLimit& l )
+{
+ if (!findInLimitByNameAndPath(l)) {
+ inLimitVec_.push_back( l );
+ return;
+ }
+ throw std::runtime_error( "Add InLimit failed: Duplicate InLimit see node " + node_->debugNodePath() );
+}
+
+bool InLimitMgr::deleteInlimit(const std::string& name)
+{
+ if (name.empty()) {
+ inLimitVec_.clear();
+ return true;
+ }
+
+ for(size_t i = 0; i < inLimitVec_.size(); i++) {
+ if (inLimitVec_[i].name() == name) {
+ inLimitVec_.erase( inLimitVec_.begin() + i );
+ return true;
+ }
+ }
+ throw std::runtime_error("InLimitMgr::deleteInlimit: Can not find inlimit: " + name);
+}
+
+Limit* InLimitMgr::findLimitViaInLimit(const InLimit& theInLimit) const
+{
+ // Use in *test* only
+ size_t theSize = inLimitVec_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ if (inLimitVec_[i].name() == theInLimit.name() && inLimitVec_[i].pathToNode() == theInLimit.pathToNode()) {
+ resolveInLimit(inLimitVec_[i]);
+ return inLimitVec_[i].limit() ;
+ }
+ }
+ return NULL;
+}
+
+bool InLimitMgr::findInLimitByNameAndPath(const InLimit& theInLimit) const
+{
+ size_t theSize = inLimitVec_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ if (inLimitVec_[i].name() == theInLimit.name() && inLimitVec_[i].pathToNode() == theInLimit.pathToNode()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void InLimitMgr::get_memento( compound_memento_ptr& comp) const
+{
+#ifdef DEBUG_MEMENTO
+ std::cout << "InLimitMgr::get_memento " << node_->debugNodePath() << "\n";
+#endif
+
+ BOOST_FOREACH(const InLimit& l, inLimitVec_ ) { comp->add( boost::make_shared<NodeInLimitMemento>( l) ); }
+}
+
+
+bool InLimitMgr::inLimit() const
+{
+ // Check in we are in limit.
+ // ** WE need to do a lookahead. hence we pass down inlimit tokens **
+ // In the case we have multiple inlimits
+ // then we are only in limit if _ALL_ are in limit. This is like
+ // a logical AND.
+ if (!inLimitVec_.empty()) {
+
+ resolveInLimitReferences();
+
+ int inlimitsWithLimits = 0;
+ int inlimitCount = 0;
+ size_t theSize = inLimitVec_.size();
+ for(size_t i = 0; i < theSize; i++ ) {
+ Limit* limit = inLimitVec_[i].limit();
+ if (limit) {
+ inlimitsWithLimits++;
+ if (limit->inLimit( inLimitVec_[i].tokens() )) {
+ inlimitCount++;
+ }
+ }
+ }
+
+ return (inlimitsWithLimits == inlimitCount ) ;
+ }
+
+ return true;
+}
+
+void InLimitMgr::incrementInLimit( std::set<Limit*>& limitSet,const std::string& task_path) const
+{
+// cout << "InLimitMgr::incrementInLimit " << node_->absNodePath() << endl;
+
+ // *NOTE* each limit is incremented if within LIMIT, and that
+ // has not previously been updated.
+ // we could have the same in limit at the task and family level.
+ // in this case the task takes priority.
+ // suite suite
+ // family family
+ // inlimit limitname 12
+ // task t1
+ // inlimit limitname 4
+ // endfamily
+ // endsuite
+ //
+ // In this case the limit <limitname> is incremented by 4 _only_
+ //
+ // Note: It is illegal for a node to have the same inlimit but with
+ // different tokens:
+ //
+ // task t1
+ // inlimit limitname 4
+ // inlimit limitname 2 // illegal and trapped by parser
+
+ resolveInLimitReferences();
+
+ BOOST_FOREACH(const InLimit& inlimit, inLimitVec_) {
+ Limit* limit = inlimit.limit();
+ if (limit && limitSet.find(limit) == limitSet.end()) {
+ limitSet.insert(limit);
+ // cout << "InLimitMgr::incrementInLimit " << node_->absNodePath() << " LIMIT incremented " << endl;
+ limit->increment( inlimit.tokens(), task_path);
+ }
+ }
+}
+
+void InLimitMgr::decrementInLimit( std::set<Limit*>& limitSet,const std::string& task_path) const
+{
+ // *NOTE* each limit is incremented if within LIMIT, and that
+ // has not previously been updated.
+ // we could have the same in limit at the task and family level.
+ // in this case the task takes priority.
+ // suite suite
+ // family family
+ // inlimit limitname 12
+ // task t1
+ // inlimit limitname 4
+ // endfamily
+ // endsuite
+ //
+ // In this case the limit <limitname> is incremented by 4 _only_
+ //
+ // Note: It is illegal for a node to have the same inlimit but with
+ // different tokens:
+ //
+ // task t1
+ // inlimit limitname 4
+ // inlimit limitname 2 // illegal and trapped by parser
+ resolveInLimitReferences();
+
+ BOOST_FOREACH(const InLimit& inlimit, inLimitVec_) {
+ Limit* limit = inlimit.limit();
+ if (limit && limitSet.find(limit) == limitSet.end()) {
+ limitSet.insert(limit);
+ // cout << "InLimitMgr::incrementInLimit " << node_->absNodePath() << " LIMIT incremented " << endl;
+ limit->decrement( inlimit.tokens(), task_path);
+ }
+ }
+}
+
+
+//#define DEBUG_WHY 1
+
+static void add_consumed_paths(Limit* limit, std::stringstream& ss)
+{
+ ss << "(";
+ const std::set<std::string>& consumed_paths = limit->paths();
+ int count = 0;
+ for (std::set<std::string>::const_iterator i = consumed_paths.begin(); i!=consumed_paths.end(); ++i) {
+ if ( 4 == count) { ss << "..."; break; }
+ ss << (*i) << ",";
+ count++;
+ }
+ ss << ")";
+}
+
+void InLimitMgr::why(std::vector<std::string>& vec) const
+{
+#ifdef DEBUG_WHY
+ std::cout << "InLimitMgr::why " << node_->debugNodePath() << "\n";
+#endif
+
+ // Note: if this correspond to a leaf node, like a task. Then it may not be
+ // sufficient to just check in limits at this level. Will need to look up hierarchy.
+ if (inLimit()) {
+#ifdef DEBUG_WHY
+ std::cout << " Node " << node_->debugNodePath() << " is *in limit*, checking parent\n";
+#endif
+ Node* theParent = node_->parent();
+ while( theParent ) {
+
+ if (theParent->check_in_limit()) {
+// std::cout << " Parent " << theParent->debugNodePath() << " is *in limit* \n";
+ theParent = theParent->parent();
+ }
+ else {
+// std::cout << " Parent " << theParent->debugNodePath() << " Not in limit \n";
+ for(size_t i = 0; i < theParent->inlimits().size(); i++ ) {
+ Limit* limit = theParent->inlimits()[i].limit();
+ if (limit && !limit->inLimit( theParent->inlimits()[i].tokens() )) {
+ std::stringstream ss;
+ if ( theParent->inlimits()[i].pathToNode().empty())
+ ss << "limit " << limit->name() << " is full";
+ else
+ ss << "limit " << theParent->inlimits()[i].pathToNode() << Str::COLON() << limit->name() << " is full";
+
+ // show node paths that have consumed a limit, Only show first 5, Otherwise string may be too long
+ add_consumed_paths(limit,ss);
+
+ vec.push_back(ss.str());
+ }
+ }
+ break;
+ }
+ }
+ }
+ else {
+#ifdef DEBUG_WHY
+ std::cout << " InLimitMgr::why " << node_->debugNodePath() << " NOT in limit\n";
+#endif
+ for(size_t i = 0; i < inLimitVec_.size(); i++ ) {
+ Limit* limit = inLimitVec_[i].limit();
+ if (limit && !limit->inLimit(inLimitVec_[i].tokens())) {
+ std::stringstream ss;
+ if ( inLimitVec_[i].pathToNode().empty())
+ ss << "limit " << limit->name() << " is full";
+ else
+ ss << "limit " << inLimitVec_[i].pathToNode() << Str::COLON() << limit->name() << " is full";
+
+ // show node paths that have consumed a limit, Only show first 5, Otherwise string may be too long
+ add_consumed_paths(limit,ss);
+
+ vec.push_back(ss.str());
+ }
+ }
+ }
+}
+
+void InLimitMgr::check(std::string& errorMsg, std::string& warningMsg,bool reportErrors, bool reportWarnings) const
+{
+ size_t theSize = inLimitVec_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ (void)find_limit(inLimitVec_[i], errorMsg, warningMsg, reportErrors, reportWarnings) ;
+ }
+}
+
+void InLimitMgr::resolveInLimit(InLimit& inLimit,std::string& errorMsg, std::string& warningMsg,bool reportErrors, bool reportWarnings) const
+{
+// cout << "Inlimit " << inLimit.toString() << "\n";
+
+ /// if limit pointer already setup use them. These are shared ptr backed, Hence if deleted beneath use should return 0;
+ if (inLimit.limit()) {
+// cout << "InLimitMgr::resolveInLimit " << inLimit.toString() << " Reusing limit ptr \n";
+ return;
+ }
+
+ /// Find the limit referenced by the InLimit. i.e. Link inLimit to its LIMIT
+ /// The return value can be NULL
+ limit_ptr referencedLimit = find_limit(inLimit,errorMsg,warningMsg,reportErrors,reportWarnings);
+ inLimit.limit( referencedLimit );
+}
+
+void InLimitMgr::auto_add_inlimit_externs(Defs* defs) const
+{
+ std::string errorMsg;
+ std::string warningMsg;
+ size_t theSize = inLimitVec_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ limit_ptr referencedLimit = find_limit(inLimitVec_[i],errorMsg,warningMsg,false,false);
+ if (!referencedLimit.get()) {
+ if (inLimitVec_[i].pathToNode().empty()) defs->add_extern( inLimitVec_[i].name() );
+ else defs->add_extern( inLimitVec_[i].pathToNode() + ":" + inLimitVec_[i].name());
+ }
+ }
+}
+
+limit_ptr InLimitMgr::find_limit(const InLimit& inLimit, std::string& errorMsg, std::string& warningMsg,bool reportErrors, bool reportWarnings) const
+{
+ if (inLimit.pathToNode().empty()) {
+
+ // cout << "inLimit.pathToNode().empty() search " << debugType() << " " << node_->absNodePath() << "\n";
+ limit_ptr referencedLimit = node_->findLimitUpNodeTree( inLimit.name() );
+ if ( referencedLimit.get() ) return referencedLimit;
+
+ if (reportWarnings) {
+
+ // See if the name is defined, as an extern, in which case *DONT* warn:
+ // This is client side specific, since server does not have externs.
+ if (node_->defs()->find_extern(inLimit.name(),Str::EMPTY())) {
+ return referencedLimit; // this is empty/NULL
+ }
+
+ std::stringstream ss;
+ ss << "Warning: ";
+ ss << node_->debugType() << " " << node_->absNodePath() << " has a " << inLimit.toString() << ", which can not be found on the parent nodes\n";
+ warningMsg += ss.str();
+ }
+ return referencedLimit; // this is empty/NULL
+ }
+
+ // *FIND* the node referenced by the In-Limit, this should hold the Limit.
+ // cout << "Inlimit path not empty \n";
+ string warning_message;
+ node_ptr referenceNode = node_->findReferencedNode( inLimit.pathToNode(), inLimit.name(), warning_message);
+ if (!referenceNode.get()) {
+ /// Could not find the node which *HOLDS* the limit
+ if (reportWarnings) {
+
+ // OK a little bit of duplication, since findReferencedNode, will also look for externs
+ // See if the Path:name is defined as an extern, in which case *DONT* warn:
+ // This is client side specific, since server does not have externs.
+ if (node_->defs()->find_extern(inLimit.pathToNode(),inLimit.name())) {
+ return limit_ptr();
+ }
+
+ std::stringstream ss;
+ ss << "Warning: " << node_->debugType() << " " << node_->absNodePath() << " has a " << inLimit.toString() << ", which can not be found\n";
+ warningMsg += ss.str();
+ }
+ return limit_ptr();
+ }
+
+ // *FOUND* the node which should hold the Limit.
+ limit_ptr referencedLimit = referenceNode->find_limit( inLimit.name() );
+ if (!referencedLimit.get()) {
+
+ // See if the name is defined, as an extern, in which case *DONT* warn:
+ // This is client side specific, since server does not have externs.
+ if (node_->defs()->find_extern(inLimit.pathToNode(),inLimit.name())) {
+ return limit_ptr();
+ }
+
+ if (reportWarnings) {
+ std::stringstream ss;
+ ss << node_->debugType() << " " << node_->absNodePath() << " has a " << inLimit.toString() << " :";
+ ss << "The referenced " << referenceNode->debugType() << " '" << referenceNode->absNodePath() << "' does not define the limit " << inLimit.name() << "\n";
+ warning_message += ss.str();
+ warningMsg += "Warning: ";
+ warningMsg += warning_message;
+ warningMsg += "\n";
+ }
+ return referencedLimit; // this is empty/NULL
+ }
+
+ // *FOUND* the referenced LIMIT. inlimit tokens must be less than limit.
+ if ( inLimit.tokens() > referencedLimit->theLimit() ) {
+ if (reportErrors) {
+ // in limit exceeds the LIMIT value
+ std::stringstream ss;
+ ss << node_->debugType() << " " << node_->absNodePath() << " has a " << inLimit.toString() << " reference\n";
+ ss << " with value '" << inLimit.tokens() << "' which exceeds '" << referencedLimit->theLimit() << "' defined on the Limit\n";
+ errorMsg += ss.str();
+ }
+ }
+ return referencedLimit;
+}
+
+void InLimitMgr::resolveInLimit(InLimit& inLimit) const
+{
+ // Used in *test* only
+ std::string errorMsg;
+ std::string warningMsg;
+ resolveInLimit(inLimit, errorMsg, warningMsg, false, false );
+}
+
+void InLimitMgr::resolveInLimitReferences() const
+{
+ size_t theSize = inLimitVec_.size();
+ if (theSize > 0) {
+ std::string warningMsg;
+ std::string errorMsg;
+ for(size_t i = 0; i < theSize; i++) {
+ resolveInLimit(inLimitVec_[i], errorMsg, warningMsg, false, false) ;
+ }
+ }
+}
+
diff --git a/ANode/src/InLimitMgr.hpp b/ANode/src/InLimitMgr.hpp
new file mode 100644
index 0000000..62b0f24
--- /dev/null
+++ b/ANode/src/InLimitMgr.hpp
@@ -0,0 +1,131 @@
+#ifndef IN_LIMIT_MGR_HPP_
+#define IN_LIMIT_MGR_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #16 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <ostream>
+#include <set>
+
+#include <boost/noncopyable.hpp>
+#include <boost/serialization/utility.hpp>
+#include <boost/serialization/vector.hpp> // no need to include <vector>
+#include <boost/serialization/level.hpp>
+#include <boost/serialization/tracking.hpp>
+
+#include "InLimit.hpp"
+#include "LimitFwd.hpp"
+#include "NodeFwd.hpp"
+
+// class InLimitMgr:
+// Design notes:
+// Please note: when ever we want access the inlimits, limit ptrs we
+// must resolve(/compute them first). This save on client code which
+// modifies the node tree from having handle it.
+// If this proves to be a bottle next. We could add a caching mechanism
+// base on the Ecf class,so that we need only update the pointers
+// when a structural modification is made.
+//
+class InLimitMgr : private boost::noncopyable {
+public:
+ InLimitMgr(Node* n) : node_(n) {}
+ InLimitMgr() : node_(NULL) {}
+
+// standard functions: ==============================================
+ std::ostream& print(std::ostream&) const;
+ bool operator==(const InLimitMgr& rhs) const;
+ void clear() { inLimitVec_.clear(); }
+
+// Access functions: ======================================================
+ const std::vector<InLimit>& inlimits() const { return inLimitVec_; }
+
+// Add functions: ===============================================================
+ void addInLimit(const InLimit& ); // will throw std::runtime_error if duplicate
+
+// Delete functions: can throw std::runtime_error ===================================
+ // if name argument is empty, delete all attributes of that type
+ // if delete was successful return true, else return false.
+ // Can throw std::runtime_error if the attribute can not be found
+ bool deleteInlimit(const std::string& name);
+
+// mementos functions:
+ void get_memento(compound_memento_ptr& comp) const;
+
+// Find functions: ============================================================
+ /// *** This will resolve the in limits first ***
+ /// Used in *test* only
+ Limit* findLimitViaInLimit(const InLimit& ) const;
+
+ bool findInLimitByNameAndPath(const InLimit& ) const; // use name,path,token,
+
+// Why:
+ void why(std::vector<std::string>& vec) const;
+
+// Limit functions:
+
+ /// Are the in limits pointers to the Limits in limit.
+ /// This is a very heavily used function. *******
+ /// *** This will resolve the in limits first ***
+ bool inLimit() const;
+
+ /// After job submission we need to increment the in limit, to indicate that a
+ /// resource is consumed.
+ /// *** This will resolve the in limits first ***
+ void incrementInLimit(
+ std::set<Limit*>& limitSet, // The set ensure we only update once
+ const std::string& task_path // The task that was submitted, and hence caused Limit to increment
+ ) const;
+
+ /// After job aborts or completes we need to decrement the in limit, to indicate that
+ /// additional resource is available.
+ /// *** This will resolve the in limits first ***
+ void decrementInLimit(
+ std::set<Limit*>& limitSet, // The set ensure we only update once
+ const std::string& task_path // The task that completed or aborted. Gives up the token
+ ) const;
+
+ /// Check to see if inlimit's can reference their Limits
+ void check(std::string& errorMsg, std::string& warningMsg,bool reportErrors, bool reportWarnings) const;
+
+ /// Add externs where the inlimit reference to limits can not be resolved
+ void auto_add_inlimit_externs(Defs*) const;
+
+ /// Needed by python interface
+ std::vector<InLimit>::const_iterator inlimit_begin() const { return inLimitVec_.begin();}
+ std::vector<InLimit>::const_iterator inlimit_end() const { return inLimitVec_.end();}
+
+private:
+ /// Setup in-limits, to point to their limits,
+ void resolveInLimitReferences() const;
+ void resolveInLimit(InLimit&,std::string& errorMsg, std::string& warningMsg,bool reportErrors, bool reportWarnings) const;
+ void resolveInLimit(InLimit&) const;
+
+ limit_ptr find_limit(const InLimit&, std::string& errorMsg, std::string& warningMsg,bool reportErrors, bool reportWarnings) const;
+
+private:
+ Node* node_; // Not persisted, constructor will always set this up.
+
+ mutable std::vector<InLimit> inLimitVec_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/) {
+ ar & inLimitVec_;
+ }
+};
+
+// This should ONLY be added to objects that are *NOT* serialised through a pointer
+BOOST_CLASS_IMPLEMENTATION(InLimitMgr, boost::serialization::object_serializable)
+BOOST_CLASS_TRACKING(InLimitMgr,boost::serialization::track_never);
+
+#endif
diff --git a/ANode/src/JobCreationCtrl.cpp b/ANode/src/JobCreationCtrl.cpp
new file mode 100644
index 0000000..9360359
--- /dev/null
+++ b/ANode/src/JobCreationCtrl.cpp
@@ -0,0 +1,32 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <iostream>
+#include <stdlib.h> // for getenv()
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include "JobCreationCtrl.hpp"
+
+namespace fs = boost::filesystem;
+
+void JobCreationCtrl::generate_temp_dir()
+{
+ if (!getenv("TMPDIR")) throw std::runtime_error("JobCreationCtrl::generate_temp_dir(), The environment variable TMPDIR is not defined");
+ tempDirForJobGeneration_ = getenv("TMPDIR");
+ tempDirForJobGeneration_ += "/ecf_check_job_creation";
+ if (fs::exists(tempDirForJobGeneration_)) fs::remove_all(tempDirForJobGeneration_);
+ std::cout << "JobCreationCtrl::generate_temp_dir() " << tempDirForJobGeneration_ << "\n";
+}
diff --git a/ANode/src/JobCreationCtrl.hpp b/ANode/src/JobCreationCtrl.hpp
new file mode 100644
index 0000000..99589f6
--- /dev/null
+++ b/ANode/src/JobCreationCtrl.hpp
@@ -0,0 +1,52 @@
+#ifndef JOBS_GEN_CTRL_HPP_
+#define JOBS_GEN_CTRL_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <string>
+#include <vector>
+
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/noncopyable.hpp>
+
+#include "NodeFwd.hpp"
+
+// Used as a utility class for testing Job creation
+// Collates data during the node tree traversal
+// Note: For testing purposes we do not always want to create jobs
+class JobCreationCtrl : public boost::enable_shared_from_this<JobCreationCtrl>, private boost::noncopyable {
+public:
+ JobCreationCtrl() {}
+
+ void set_node_path( const std::string& absNodePath ) { absNodePath_ = absNodePath;}
+ const std::string& node_path() const { return absNodePath_;}
+
+ void generate_temp_dir();
+ void set_dir_for_job_creation( const std::string& tempDirForJobGeneration ) { tempDirForJobGeneration_ = tempDirForJobGeneration; }
+ const std::string& dir_for_job_creation() { return tempDirForJobGeneration_;}
+
+ std::string& error_msg() { return errorMsg_;}
+ const std::string& get_error_msg() const { return errorMsg_;}
+
+ void push_back_failing_submittable(submittable_ptr t) { fail_submittables_.push_back(t); }
+ const std::vector<weak_submittable_ptr>& fail_submittables() const { return fail_submittables_;}
+
+private:
+ std::string absNodePath_;
+ std::string tempDirForJobGeneration_;
+ std::string errorMsg_;
+ std::vector<weak_submittable_ptr> fail_submittables_;
+};
+#endif
diff --git a/ANode/src/JobProfiler.cpp b/ANode/src/JobProfiler.cpp
new file mode 100644
index 0000000..e5d22d3
--- /dev/null
+++ b/ANode/src/JobProfiler.cpp
@@ -0,0 +1,70 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #18 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <boost/lexical_cast.hpp>
+#include "JobProfiler.hpp"
+#include "JobsParam.hpp"
+#include "Task.hpp"
+#include "Str.hpp"
+#include "Log.hpp"
+
+using namespace ecf;
+using namespace std;
+
+// Connection and client timeout issues can be replicated by adding
+// - sleep(1) in EcfFile , i.e when creating the job output
+//
+
+static size_t task_threshold_ = 4000;
+
+namespace ecf {
+
+int JobProfiler::task_threshold_default() { return 4000;}
+
+// =================================================================================
+JobProfiler::JobProfiler(Task* node,JobsParam& jobsParam, size_t threshold)
+: node_(node),
+ jobsParam_(jobsParam),
+ start_time_(boost::posix_time::microsec_clock::universal_time()),
+ threshold_(threshold)
+{
+ if (!jobsParam_.next_poll_time().is_special() && start_time_ >= jobsParam_.next_poll_time()) {
+ jobsParam_.set_timed_out_of_job_generation(start_time_);
+ }
+}
+
+JobProfiler::~JobProfiler()
+{
+ if (node_) {
+ boost::posix_time::time_duration duration = boost::posix_time::microsec_clock::universal_time() - start_time_;
+ size_t time_taken = duration.total_milliseconds();
+
+ // When testing we set submitJobsInterval to < 0
+ if (jobsParam_.submitJobsInterval() < 0 ) {
+ time_taken = threshold_ + 1;
+ }
+
+ if ( time_taken > threshold_) {
+ std::stringstream ss;
+ ss << "Job generation for task " << node_->absNodePath() << " took " << time_taken << "ms, Exceeds ECF_TASK_THRESHOLD(" << threshold_ << "ms)";
+ log(Log::WAR,ss.str());
+ }
+ }
+}
+
+void JobProfiler::set_task_threshold(size_t threshold){task_threshold_ = threshold;}
+size_t JobProfiler::task_threshold() { return task_threshold_; }
+
+}
diff --git a/ANode/src/JobProfiler.hpp b/ANode/src/JobProfiler.hpp
new file mode 100644
index 0000000..f5e827d
--- /dev/null
+++ b/ANode/src/JobProfiler.hpp
@@ -0,0 +1,52 @@
+#ifndef JOB_PROFILER_HPP_
+#define JOB_PROFILER_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+// This class is used to aid profiling of the job generation step.
+// This will be used to identify those suite/familiy/tasks that take the most
+// amount of time, *when* we exceed the jobs generation interval.
+// In particular if we have output that is many megabtyes, it can affect
+// the performance of the server, especially when the server is running
+// on virtual machines
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/noncopyable.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include "NodeFwd.hpp"
+class JobsParam;
+
+namespace ecf {
+
+class JobProfiler : private boost::noncopyable {
+public:
+ // Note: 1000 milliseconds = 1 second
+ JobProfiler(Task*,JobsParam&,size_t threshold /* expected to be milli seconds */);
+ ~JobProfiler();
+
+ static void set_task_threshold(size_t threshold);
+ static size_t task_threshold();
+
+ static int task_threshold_default();
+
+private:
+ Task* node_;
+ JobsParam& jobsParam_;
+ boost::posix_time::ptime start_time_;
+ size_t threshold_;
+};
+
+}
+
+
+#endif
diff --git a/ANode/src/Jobs.cpp b/ANode/src/Jobs.cpp
new file mode 100644
index 0000000..42a3fe4
--- /dev/null
+++ b/ANode/src/Jobs.cpp
@@ -0,0 +1,126 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #18 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <assert.h>
+
+#include "Jobs.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "Log.hpp"
+#include "DurationTimer.hpp"
+#include "JobsParam.hpp"
+#include "Signal.hpp"
+#include "System.hpp"
+#include "SuiteChanged.hpp"
+#include "JobProfiler.hpp"
+
+using namespace ecf;
+using namespace std;
+
+//#define DEBUG_JOB_SUBMISSION 1
+
+bool Jobs::generate( JobsParam& jobsParam) const
+{
+#ifdef DEBUG_JOB_SUBMISSION
+ cout << "\n" << "Jobs::generate (" << jobsParam.logDebugMessage() << ") create jobs(" << jobsParam.createJobs() << ")";
+ if (defs_) cout << " server_state(" << SState::to_string(defs_->server().get_state()) << ")\n";
+#endif
+
+ // dependency resolving and job submission must be less than submitJobsInterval seconds
+ // Note: Duration timer makes a system call
+ DurationTimer durationTimer;
+
+#ifdef DEBUG_JOB_SUBMISSION
+ LogToCout toCoutAsWell;
+ LOG(Log::DBG,"-->Job submission start " << jobsParam.logDebugMessage());
+#endif
+ {
+ // Constructor does nothing, destructor will un-block SIGCHLD
+ // This will allow child process termination to handled by the signal handler in System
+ // The desctructor will then re-block SIGCHLD
+ Signal unblock_on_desctruction_then_reblock;
+
+ // *******************************************************************
+ // **** JOB submission *MUST* be done sequentially, as each task could
+ // **** be affected by a resource/limit, and hence affect subsequent
+ // **** job submission
+ // *******************************************************************
+
+ if (defs_) {
+ if (defs_->server().get_state() == SState::RUNNING) {
+ const std::vector<suite_ptr>& suiteVec = defs_->suiteVec();
+ size_t theSize = suiteVec.size();
+ for(size_t i = 0; i < theSize; i++) {
+ // SuiteChanged moved internal to Suite::resolveDependencies. i.e on fast path
+ // and when suites not begun we save a constructor/destructor calls
+ (void)suiteVec[i]->resolveDependencies(jobsParam);
+ }
+ }
+ }
+ else {
+ if (!node_->isParentSuspended()) {
+ // suite, family, task
+ SuiteChanged1 changed(node_->suite());
+ (void)node_->resolveDependencies( jobsParam );
+ }
+ }
+
+ // *****************************************************************
+ // Should end up calling signal handler here for any pending SIGCHLD
+ // *****************************************************************
+ }
+
+ // Process children that have terminated
+ System::instance()->processTerminatedChildren();
+
+#ifdef DEBUG_JOB_SUBMISSION
+ LOG(Log::DBG,"-->Job submission finish interval = "
+ << jobsParam.submitJobsInterval()
+ << " time taken = " << durationTimer.duration()
+ << " Tasks/Aliases submitted " << jobsParam.submitted().size()
+ << " " << jobsParam.getErrorMsg()
+ );
+#endif
+
+ if (durationTimer.duration() > jobsParam.submitJobsInterval()) {
+ LOG(Log::ERR,"Jobs::generate: job generation time(" << durationTimer.duration() << " seconds) is greater than job submission interval of " << jobsParam.submitJobsInterval() << " seconds!!");
+ }
+ return jobsParam.getErrorMsg().empty();
+}
+
+bool Jobs::generate() const
+{
+ Defs* defs = NULL;
+ if (defs_) {
+ defs = defs_;
+ LOG_ASSERT( defs != NULL ,"defs_ == NULL");
+ }
+ else {
+ defs = node_->defs();
+ LOG_ASSERT( defs != NULL ,"node_->defs() == NULL");
+ }
+
+ if (defs->server().get_state() == SState::RUNNING) {
+ LOG_ASSERT( defs->server().jobSubmissionInterval() != 0 ,"");
+ JobsParam jobsParam( defs->server().jobSubmissionInterval(), defs->server().jobGeneration() );
+#ifdef DEBUG_JOB_SUBMISSION
+ jobsParam.logDebugMessage(" from Jobs::generate()/Server");
+#endif
+
+ return generate( jobsParam );
+ }
+ return false;
+}
diff --git a/ANode/src/Jobs.hpp b/ANode/src/Jobs.hpp
new file mode 100644
index 0000000..49343fd
--- /dev/null
+++ b/ANode/src/Jobs.hpp
@@ -0,0 +1,69 @@
+#ifndef JOBS_HPP_
+#define JOBS_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/noncopyable.hpp>
+#include "NodeFwd.hpp"
+
+/// Job generation involves:
+/// 1/ resolving dependencies. This means we look at day,date,time and triggers,
+/// and check to to see if a node is free or still holding.
+/// When a node is free of its dependencies, a job can be created.
+/// Note: for a node that is suspended, job generation is disabled.
+/// In this case the time dependencies are still checked.
+/// and if free are marked as such. later on if the node is resumed
+/// we check dependencies and create the jobs
+/// 2/ Creating jobs. Pre processing and variable substitution
+/// 3/ Changing state of task to submitted.
+/// 4/ Increment the inlimit references, for successful job submission
+/// 5/ Error/Complete must decrement limits
+/// 6/ Set up signal handlers to monitor child job, so that on failure
+// Change state to ABORTED and decrement limit references
+///
+/// Job submission *MUST* be done sequentially,as each job submission could
+/// consume a resource(i.e like a limit), which can affect subsequent jobs.
+///
+/// The process of resolving dependencies and submitting all the tasks, must take
+/// less than 60 seconds. As this is resolution of the clock.
+/// For testing purposes this can be changed and also we do not always want
+/// to create jobs.
+///
+/// Return true, if job submission ok, else false and error message in JobsParam
+///
+/// The jobs file are shell scripts, which have IPC(child commands) which talk to
+/// to the server. Since the scripts are user created, they can include, errors:
+/// o multiple call to complete
+/// To guard against this, we should *not* clear reset password in the complete
+/// Otherwise we will registered as a zombie.
+/// o Failure to call complete (maybe due to early exit in the job file)
+/// There is not much we can do here, the job will stay active.
+/// o Path do not match, since the node tree, in the server has been deleted
+/// Typically the job will hold on the child commands.
+///
+/// Note: in real life test 99% of job generation is done after child command
+class Jobs : private boost::noncopyable {
+public:
+ Jobs(const defs_ptr& d) : defs_(d.get()), node_(NULL) {}
+ Jobs(Defs* d) : defs_(d), node_(NULL) {}
+ Jobs(Node* d) : defs_(NULL), node_(d) {}
+
+ bool generate( JobsParam& ) const;
+ bool generate() const;
+
+private:
+ Defs* defs_;
+ Node* node_;
+};
+#endif
diff --git a/ANode/src/JobsParam.cpp b/ANode/src/JobsParam.cpp
new file mode 100644
index 0000000..a715073
--- /dev/null
+++ b/ANode/src/JobsParam.cpp
@@ -0,0 +1,31 @@
+//============================================================================
+// Name : time
+// Author : Avi
+// Revision : $Revision: #14 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "JobsParam.hpp"
+
+
+bool JobsParam::check_for_job_generation_timeout()
+{
+ if (timed_out_of_job_generation_) {
+ return true;
+ }
+
+ boost::posix_time::ptime start_time = boost::posix_time::microsec_clock::universal_time();
+ if (!next_poll_time_.is_special() && start_time >= next_poll_time_) {
+ set_timed_out_of_job_generation(start_time);
+ return true;
+ }
+ return false;
+}
diff --git a/ANode/src/JobsParam.hpp b/ANode/src/JobsParam.hpp
new file mode 100644
index 0000000..667d8b9
--- /dev/null
+++ b/ANode/src/JobsParam.hpp
@@ -0,0 +1,84 @@
+#ifndef JOBSPARAM_HPP_
+#define JOBSPARAM_HPP_
+//============================================================================
+// Name : time
+// Author : Avi
+// Revision : $Revision: #14 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/noncopyable.hpp>
+#include "NodeFwd.hpp"
+
+// Used as a utility class for controlling job creation.
+// Collates data during the node tree traversal
+// Note: For testing purposes we do not always want to create jobs or spawn jobs
+class JobsParam : private boost::noncopyable {
+public:
+ // This constructor is used in test
+ JobsParam(bool createJobs = false)
+ : timed_out_of_job_generation_(false),
+ createJobs_(createJobs), spawnJobs_(false), submitJobsInterval_(60){}
+
+ JobsParam(int submitJobsInterval, bool createJobs, bool spawn_jobs = true)
+ : timed_out_of_job_generation_(false),
+ createJobs_(createJobs),spawnJobs_(spawn_jobs), submitJobsInterval_(submitJobsInterval)
+ { if (!createJobs_) spawnJobs_ = false;}
+
+ std::string& errorMsg() { return errorMsg_;}
+ const std::string& getErrorMsg() const { return errorMsg_;}
+
+ void push_back_submittable(Submittable* t) { submitted_.push_back(t); }
+ const std::vector<Submittable*>& submitted() const { return submitted_;}
+
+ bool createJobs() const { return createJobs_;}
+ bool spawnJobs() const { return spawnJobs_;}
+
+ /// returns the number of seconds at which we should check time dependencies
+ /// this includes evaluating trigger dependencies and submit the corresponding jobs.
+ /// This is set at 60 seconds. But will vary for debug purposes only.
+ int submitJobsInterval() const { return submitJobsInterval_;}
+
+ /// Allow user to set the debug message that appears in log file when job submission starts
+ void logDebugMessage(const std::string& s) { debugMsg_ = s;}
+ const std::string& logDebugMessage() const { return debugMsg_;}
+
+ void set_user_edit_variables(const NameValueMap& v) { user_edit_variables_ = v;}
+ const NameValueMap& user_edit_variables() const { return user_edit_variables_;}
+
+ void set_user_edit_file(const std::vector<std::string>& file) { user_edit_file_ = file;}
+ const std::vector<std::string>& user_edit_file() const { return user_edit_file_; }
+
+ // Functions to aid timing of job generation
+ void set_next_poll_time(const boost::posix_time::ptime& next_poll_time) { next_poll_time_ = next_poll_time;}
+ const boost::posix_time::ptime& next_poll_time() const { return next_poll_time_;}
+ const boost::posix_time::ptime& time_out_time() const { return time_out_time_;}
+ void set_timed_out_of_job_generation(const boost::posix_time::ptime& t) { time_out_time_ = t; timed_out_of_job_generation_ = true;}
+ bool timed_out_of_job_generation() const { return timed_out_of_job_generation_; }
+
+ // ensure that we avoid job generation close the server poll time.
+ bool check_for_job_generation_timeout();
+
+private:
+ bool timed_out_of_job_generation_;
+ bool createJobs_;
+ bool spawnJobs_;
+ int submitJobsInterval_;
+ std::string errorMsg_;
+ std::string debugMsg_;
+ std::vector<Submittable*> submitted_;
+ std::vector<std::string> user_edit_file_;
+ NameValueMap user_edit_variables_; // Used for User edit
+ boost::posix_time::ptime next_poll_time_; // Aid early exit from job generation, if it takes to long
+ boost::posix_time::ptime time_out_time_; // When we actually timed out must >= next_poll_time_
+};
+#endif
diff --git a/ANode/src/Limit.cpp b/ANode/src/Limit.cpp
new file mode 100644
index 0000000..2b6e58c
--- /dev/null
+++ b/ANode/src/Limit.cpp
@@ -0,0 +1,209 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #64 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <assert.h>
+#include <sstream>
+
+#include "Limit.hpp"
+#include "Indentor.hpp"
+#include "PrintStyle.hpp"
+#include "Str.hpp"
+#include "Ecf.hpp"
+#include "Suite.hpp"
+
+using namespace std;
+using namespace ecf;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+
+Limit::Limit(const std::string& name,int limit)
+: state_change_no_(0),name_(name),theLimit_(limit),value_(0),node_(0)
+{
+ if ( !Str::valid_name( name ) ) {
+ throw std::runtime_error("Limit::Limit: Invalid Limit name: " + name);
+ }
+}
+
+Limit::Limit(const std::string& name,int limit, int value, const std::set<std::string>& paths)
+: state_change_no_(0),name_(name),theLimit_(limit),value_(value),paths_(paths),node_(0)
+{
+ if ( !Str::valid_name( name ) ) {
+ throw std::runtime_error("Limit::Limit: Invalid Limit name: " + name);
+ }
+}
+
+Limit::Limit(const Limit& rhs)
+: state_change_no_(0), name_(rhs.name_),theLimit_(rhs.theLimit_),value_(rhs.value_),paths_(rhs.paths_),node_(0)
+{
+}
+
+bool Limit::operator==( const Limit& rhs ) const {
+ if ( value_ != rhs.value_ ) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Limit::operator==value_(" << value_ << ") != rhs.value_(" << rhs.value_ << ") " << toString() << " rhs(" << rhs.toString() << ")\n";
+ }
+#endif
+ return false;
+ }
+ if ( theLimit_ != rhs.theLimit_ ) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Limit::operator==( theLimit_ != rhs.theLimit_) " << toString() << " rhs(" << rhs.toString() << ")\n";
+ }
+#endif
+ return false;
+ }
+ if ( name_ != rhs.name_ ) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Limit::operator==( name_ != rhs.name_ ) " << toString() << " rhs(" << rhs.toString() << ")\n";
+ }
+#endif
+ return false;
+ }
+ if ( paths_ != rhs.paths_ ) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Limit::operator==( paths_ != rhs.paths_ ) " << toString() << " rhs(" << rhs.toString() << ")\n";
+ }
+#endif
+ return false;
+ }
+ return true;
+}
+
+std::ostream& Limit::print( std::ostream& os ) const {
+ Indentor in;
+ Indentor::indent( os ) << toString();
+ if (!PrintStyle::defsStyle()) {
+ if (value_ != 0) {
+ os << " # " << value_;
+ for(std::set<std::string>::const_iterator i = paths_.begin(); i != paths_.end(); ++i) {
+ os << " " << (*i);
+ }
+ }
+ }
+ os << "\n";
+ return os;
+}
+
+std::string Limit::toString() const {
+ std::stringstream ss;
+ ss << "limit " << name_ << " " << theLimit_;
+ return ss.str();
+}
+
+void Limit::decrement( int tokens , const std::string& abs_node_path) {
+
+ // cout << "Limit::decrement name = " << name_ << " current value_ = " << value_ << " limit = " << theLimit_ << " consume tokens = " << tokens << " path = " << abs_node_path << "\n";
+ // Note: we previously had 'if (value_ > 0) {
+ // However if the user had manually changed the value_, then we could be left with paths_, that would never have been cleared
+ if (delete_path(abs_node_path)) {
+ // delete_path() will increment state_change_no
+ value_ -= tokens;
+ if ( value_ < 0 ) {
+ value_ = 0;
+ paths_.clear();
+ }
+ }
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Limit::decrement\n";
+#endif
+ // cout << "Limit::decrement name = " << name_ << " current value_ = " << value_ << "\n";
+}
+
+void Limit::increment( int tokens , const std::string& abs_node_path) {
+ // cout << "Limit::increment name = " << name_ << " current value_ = " << value_ << " limit = " << theLimit_ << " consume tokens = " << tokens << " path = " << abs_node_path << "\n";
+
+ // increment should keep increasing limit value, *EVEN* if over the limit. See ECFLOW-324
+ // Note: previously we had:
+ // if ( value_ < theLimit_ ) {
+
+ if (paths_.find(abs_node_path) == paths_.end()) {
+
+ paths_.insert( abs_node_path );
+ value_ += tokens;
+ update_change_no();
+ }
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Limit::increment\n";
+#endif
+ // cout << "Limit::increment name = " << name_ << " current value_ = " << value_ << "\n";
+}
+
+void Limit::setValue( int v )
+{
+ value_ = v;
+ update_change_no();
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << " Limit::setValue() value_ = " << value_ << "\n";
+#endif
+}
+
+void Limit::setLimit(int v)
+{
+ theLimit_ = v;
+ update_change_no();
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << " Limit::setLimit() theLimit_ = " << value_ << "\n";
+#endif
+}
+
+void Limit::set_paths(const std::set<std::string>& paths)
+{
+ paths_ = paths;
+ update_change_no();
+}
+
+void Limit::set_state(int limit, int value, const std::set<std::string>& paths)
+{
+ value_ = value;
+ theLimit_ = limit;
+ paths_ = paths;
+ update_change_no();
+}
+
+bool Limit::delete_path( const std::string& abs_node_path)
+{
+ std::set<std::string>::iterator i = paths_.find(abs_node_path);
+ if (i != paths_.end()) {
+ paths_.erase(i);
+ update_change_no();
+ return true;
+ }
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Limit::delete_path() \n";
+#endif
+ return false;
+}
+
+void Limit::reset() {
+ paths_.clear();
+ setValue(0); // will increment state_change_no_
+}
+
+void Limit::update_change_no()
+{
+ state_change_no_ = Ecf::incr_state_change_no();
+ if (node_) {
+ Suite* suite = node_->suite();
+ if (suite) suite->set_state_change_no(state_change_no_);
+ }
+}
diff --git a/ANode/src/Limit.hpp b/ANode/src/Limit.hpp
new file mode 100644
index 0000000..2382d28
--- /dev/null
+++ b/ANode/src/Limit.hpp
@@ -0,0 +1,93 @@
+#ifndef LIMIT_HPP_
+#define LIMIT_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #61 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Limit was placed in the ANode category because inlimit
+// can reference Limit on *ANOTHER* suite. This presents
+// A problem with incremental sync, since that requires
+// access to a parent/suite, to mark the suite as changed.
+// To get round this issue the Node will set the
+// parent pointer on the Limit this then makes it easy
+// for incremental sync, since we directly access the parent suite
+//============================================================================
+
+#include <ostream>
+
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/set.hpp> // no need to include <set>
+#include <boost/serialization/string.hpp> // no need to include <string>
+class Node;
+
+// Class Limit: The limit is zero based, hence if limit is 10, increment must use < 10
+class Limit {
+public:
+ Limit(const std::string& name,int limit);
+ Limit(const std::string& name,int limit, int value, const std::set<std::string>& paths);
+ Limit() : state_change_no_(0), theLimit_(0), value_(0),node_(0) {}
+ Limit(const Limit& rhs);
+
+ std::ostream& print(std::ostream&) const;
+ bool operator==(const Limit& rhs) const;
+ const std::string& name() const { return name_;}
+
+ void set_node(Node* n) { node_ = n; }
+
+ void setValue(int v);
+ void setLimit(int v);
+ void set_state(int limit, int value,const std::set<std::string>& p); // for use by memento
+ void set_paths(const std::set<std::string>& p);
+
+ bool delete_path( const std::string& abs_node_path); // for use by AlterCmd
+ const std::set<std::string>& paths() const { return paths_;}
+
+ int value() const { return value_;}
+ bool inLimit(int inlimit_tokens) const { return ((value_ + inlimit_tokens) <= theLimit_);}
+ int theLimit() const { return theLimit_;}
+ void increment(int tokens, const std::string& abs_node_path);
+ void decrement(int tokens, const std::string& abs_node_path);
+ void reset();
+
+ // The state_change_no is never reset. Must be incremented if it can affect equality
+ unsigned int state_change_no() const { return state_change_no_; }
+
+ // for python interface
+ std::string toString() const;
+
+ // ECFLOW-518, we can't use:
+ // std::set<std::string>::const_iterator paths_begin() const { return paths_.begin();}
+ // std::set<std::string>::const_iterator paths_end() const { return paths_.end();}
+ // because boost python does not support std::set<std::string> out of the box
+ // we will wrap and return list instead. See ExportNodeAttr.cpp
+
+private:
+ void update_change_no();
+
+private:
+ unsigned int state_change_no_; // *not* persisted, only used on server side
+ std::string name_;
+ int theLimit_;
+ int value_;
+ std::set<std::string> paths_; // Updated via increment()/decrement()/reset(). Typically task paths
+ Node* node_ ; // The parent NOT persisted
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/) {
+ ar & name_;
+ ar & theLimit_;
+ ar & value_;
+ ar & paths_;
+ }
+};
+
+#endif
diff --git a/ANode/src/LimitFwd.hpp b/ANode/src/LimitFwd.hpp
new file mode 100644
index 0000000..f3e3b1c
--- /dev/null
+++ b/ANode/src/LimitFwd.hpp
@@ -0,0 +1,22 @@
+#ifndef LIMIT_FWD_HPP_
+#define LIMIT_FWD_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/shared_ptr.hpp>
+
+class Limit;
+typedef boost::shared_ptr<Limit> limit_ptr;
+
+#endif
diff --git a/ANode/src/Memento.cpp b/ANode/src/Memento.cpp
new file mode 100644
index 0000000..b541789
--- /dev/null
+++ b/ANode/src/Memento.cpp
@@ -0,0 +1,114 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #32 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "Memento.hpp"
+#include "Str.hpp"
+
+using namespace std;
+using namespace ecf;
+
+//#define DEBUG_MEMENTO 1
+
+// ===============================================================
+Memento::~Memento() {}
+
+// ===============================================================
+void CompoundMemento::incremental_sync(defs_ptr client_def,std::vector<std::string>& changed_nodes) const
+{
+ /// Clear out aspects, for this Memento.
+ /// Aspects are added via do_incremental_* / set_mememto functions
+ /// AND in *this* function when node attributes have been added or deleted.
+ aspects_.clear();
+
+ // Record changes nodes for the Python interface
+ changed_nodes.push_back(absNodePath_);
+
+ node_ptr node = client_def->findAbsNode(absNodePath_);
+ if (!node.get()) {
+ if ( absNodePath_ != Str::ROOT_PATH()) throw std::runtime_error("CompoundMemento::incremental_sync: could not find path " + absNodePath_ );
+
+#ifdef DEBUG_MEMENTO
+ cout << "CompoundMemento::incremental_sync: ROOT_PATH changed_nodes.size()=" << changed_nodes.size() << "\n";
+#endif
+ BOOST_FOREACH(memento_ptr m, vec_) {
+ m->do_incremental_defs_sync( client_def.get(), aspects_);
+ }
+
+ /// Notify any interested parties incremental changes
+ /// Aspects records the kind of changes.
+ client_def->notify( aspects_);
+ }
+ else {
+
+#ifdef DEBUG_MEMENTO
+ cout << "CompoundMemento::incremental_sync: " << node->debugNodePath() << " changed_nodes.size()=" << changed_nodes.size() << "\n";
+#endif
+
+ if (clear_attributes_) {
+ aspects_.push_back(ecf::Aspect::ADD_REMOVE_ATTR);
+ node->clear();
+ }
+
+ Task* task = node->isTask();
+ Alias* alias = node->isAlias();
+ Suite* suite = node->isSuite();
+ Family* family = node->isFamily();
+
+ BOOST_FOREACH(memento_ptr m, vec_) {
+// std::cout << "memento = " << typeid(*m.get()).name() << "\n";
+ if (task) m->do_incremental_task_sync( task, aspects_ );
+ else if (alias) m->do_incremental_alias_sync( alias, aspects_ );
+ else if (suite) m->do_incremental_suite_sync( suite , aspects_);
+ else if (family) m->do_incremental_family_sync( family, aspects_ );
+ m->do_incremental_node_sync( node.get(), aspects_ );
+ }
+
+ /// Notify any interested parties that Node has made incremental changes
+ /// Aspects records the kind of changes.
+ node->notify( aspects_ );
+ }
+}
+
+BOOST_CLASS_EXPORT_IMPLEMENT(StateMemento);
+BOOST_CLASS_EXPORT_IMPLEMENT(NodeDefStatusDeltaMemento);
+BOOST_CLASS_EXPORT_IMPLEMENT(SuspendedMemento);
+BOOST_CLASS_EXPORT_IMPLEMENT(ServerStateMemento);
+BOOST_CLASS_EXPORT_IMPLEMENT(ServerVariableMemento);
+BOOST_CLASS_EXPORT_IMPLEMENT(NodeEventMemento);
+BOOST_CLASS_EXPORT_IMPLEMENT(NodeMeterMemento);
+BOOST_CLASS_EXPORT_IMPLEMENT(NodeLabelMemento);
+BOOST_CLASS_EXPORT_IMPLEMENT(NodeTriggerMemento);
+BOOST_CLASS_EXPORT_IMPLEMENT(NodeCompleteMemento);
+BOOST_CLASS_EXPORT_IMPLEMENT(NodeRepeatMemento);
+BOOST_CLASS_EXPORT_IMPLEMENT(NodeLimitMemento);
+BOOST_CLASS_EXPORT_IMPLEMENT(NodeInLimitMemento);
+BOOST_CLASS_EXPORT_IMPLEMENT(NodeVariableMemento);
+BOOST_CLASS_EXPORT_IMPLEMENT(NodeLateMemento);
+BOOST_CLASS_EXPORT_IMPLEMENT(NodeTodayMemento);
+BOOST_CLASS_EXPORT_IMPLEMENT(NodeTimeMemento);
+BOOST_CLASS_EXPORT_IMPLEMENT(NodeDayMemento);
+BOOST_CLASS_EXPORT_IMPLEMENT(NodeCronMemento);
+BOOST_CLASS_EXPORT_IMPLEMENT(NodeDateMemento);
+BOOST_CLASS_EXPORT_IMPLEMENT(NodeZombieMemento);
+BOOST_CLASS_EXPORT_IMPLEMENT(NodeVerifyMemento);
+BOOST_CLASS_EXPORT_IMPLEMENT(FlagMemento);
+BOOST_CLASS_EXPORT_IMPLEMENT(SubmittableMemento);
+BOOST_CLASS_EXPORT_IMPLEMENT(SuiteClockMemento);
+BOOST_CLASS_EXPORT_IMPLEMENT(SuiteBeginDeltaMemento);
+BOOST_CLASS_EXPORT_IMPLEMENT(SuiteCalendarMemento);
+BOOST_CLASS_EXPORT_IMPLEMENT(OrderMemento);
+BOOST_CLASS_EXPORT_IMPLEMENT(ChildrenMemento);
+BOOST_CLASS_EXPORT_IMPLEMENT(AliasChildrenMemento);
+BOOST_CLASS_EXPORT_IMPLEMENT(AliasNumberMemento);
diff --git a/ANode/src/Memento.hpp b/ANode/src/Memento.hpp
new file mode 100644
index 0000000..0d707d2
--- /dev/null
+++ b/ANode/src/Memento.hpp
@@ -0,0 +1,743 @@
+#ifndef MEMENTO_HPP_
+#define MEMENTO_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #41 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : class Memento
+// Class's derived from Memento are stored on DefsDelta.
+// DefsDelta is transferred from Server to Client during a sync
+// See SSyncCmd.hpp
+//
+// Are created in the server, but used by the client to sync.
+//
+// Used to capture incremental change of state, to node, and node attributes
+// Serve as a base class of all memento's
+// Later on the client side, the changes can be applied. via incremental_sync()
+// The are several kind of changes that we can capture:
+// a/ simple state changes,
+// b/ Change in attribute structure
+// c/ Deletion of attribute
+// d/ Addition of an attribute
+// e/ Add/delete of a Family/task
+// f/ Add/Delete of suite
+//
+// The main emphasis here is to capture a,b,c,d,e. This is easily handled by state_change_no.
+// option f/ is handled via a full update and hence does not use mementos
+//
+// ISSUES: AIX has issues with TOC(table of contents) overflow. This is heavily
+// influenced by the number of global symbols. Unfortunately each boost serializiable
+// type, greatly increases the number of globals.
+// Hence we need to ensure we use the minimum number of serializable types.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "Alias.hpp"
+
+#include "boost_archive.hpp" // collates boost archive includes
+#include <boost/serialization/export.hpp>
+#include <boost/serialization/deque.hpp> // no need to include <deque>
+
+//#define DEBUG_MEMENTO 1
+
+class Memento : private boost::noncopyable {
+public:
+ virtual ~Memento();
+private:
+ /// Applies the mementos to the client side defs. Can raise std::runtime_error
+ virtual void do_incremental_node_sync(Node*,std::vector<ecf::Aspect::Type>& aspects) const {}
+ virtual void do_incremental_task_sync(Task*,std::vector<ecf::Aspect::Type>& aspects) const {}
+ virtual void do_incremental_alias_sync(Alias*,std::vector<ecf::Aspect::Type>& aspects) const {}
+ virtual void do_incremental_suite_sync(Suite*,std::vector<ecf::Aspect::Type>& aspects) const {}
+ virtual void do_incremental_family_sync(Family*,std::vector<ecf::Aspect::Type>& aspects) const {}
+ virtual void do_incremental_defs_sync(Defs*,std::vector<ecf::Aspect::Type>& aspects) const {}
+ friend class CompoundMemento;
+
+private:
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {}
+};
+BOOST_SERIALIZATION_ASSUME_ABSTRACT(Memento)
+
+
+// Used for storing all the memento's associated with a single node
+// This allow us to make only *ONE* call to find the node.
+// The mementos are then applied to this single node.
+class CompoundMemento {
+public:
+ CompoundMemento(const std::string& absNodePath)
+ : clear_attributes_(false),absNodePath_(absNodePath) {}
+
+ CompoundMemento() : clear_attributes_(false) {} // for serialization
+
+ void incremental_sync(defs_ptr client_def, std::vector<std::string>& changed_nodes) const;
+ void add(memento_ptr m) { vec_.push_back(m); }
+ void clear_attributes() { clear_attributes_ = true;}
+
+private:
+
+ bool clear_attributes_;
+ std::string absNodePath_;
+ std::vector<memento_ptr> vec_;
+ mutable std::vector<ecf::Aspect::Type> aspects_; // not persisted only used on client side
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & clear_attributes_;
+ ar & absNodePath_;
+ ar & vec_;
+ }
+};
+
+
+class StateMemento : public Memento {
+public:
+ StateMemento(NState::State state) : state_(state) {}
+ StateMemento() : state_(NState::UNKNOWN) {}
+private:
+ virtual void do_incremental_node_sync(Node* n,std::vector<ecf::Aspect::Type>& aspects) const { n->set_memento(this,aspects);}
+ virtual void do_incremental_defs_sync(Defs* defs,std::vector<ecf::Aspect::Type>& aspects) const { defs->set_memento(this,aspects);}
+
+ NState::State state_;
+ friend class Node;
+ friend class Defs;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object<Memento>(*this);
+ ar & state_;
+ }
+};
+
+class OrderMemento : public Memento {
+public:
+ OrderMemento(const std::vector<std::string>& order) : order_(order) {}
+ OrderMemento() {}
+private:
+ virtual void do_incremental_defs_sync(Defs* defs,std::vector<ecf::Aspect::Type>& aspects) const { defs->set_memento(this,aspects);}
+ virtual void do_incremental_suite_sync(Suite* s,std::vector<ecf::Aspect::Type>& aspects) const { s->set_memento(this,aspects);}
+ virtual void do_incremental_family_sync(Family* f,std::vector<ecf::Aspect::Type>& aspects) const { f->set_memento(this,aspects);}
+ virtual void do_incremental_task_sync(Task* t,std::vector<ecf::Aspect::Type>& aspects) const { t->set_memento(this,aspects);}
+
+ std::vector<std::string> order_;
+ friend class NodeContainer;
+ friend class Task;
+ friend class Defs;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object<Memento>(*this);
+ ar & order_;
+ }
+};
+
+class ChildrenMemento : public Memento {
+public:
+ ChildrenMemento(const std::vector<node_ptr>& children) : children_(children) {}
+ ChildrenMemento() {}
+private:
+ virtual void do_incremental_suite_sync(Suite* s,std::vector<ecf::Aspect::Type>& aspects) const { s->set_memento(this,aspects);}
+ virtual void do_incremental_family_sync(Family* f,std::vector<ecf::Aspect::Type>& aspects) const { f->set_memento(this,aspects);}
+
+ std::vector<node_ptr> children_;
+ friend class NodeContainer;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+
+ ar.register_type(static_cast<Task *>(NULL));
+ ar.register_type(static_cast<Family *>(NULL));
+
+ ar & boost::serialization::base_object<Memento>(*this);
+ ar & children_;
+ }
+};
+
+class AliasChildrenMemento : public Memento {
+public:
+ AliasChildrenMemento(const std::vector<alias_ptr>& children) : children_(children) {}
+ AliasChildrenMemento() {}
+private:
+ virtual void do_incremental_task_sync(Task* t,std::vector<ecf::Aspect::Type>& aspects) const { t->set_memento(this,aspects);}
+
+ std::vector<alias_ptr> children_;
+ friend class Task;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+
+ ar.register_type(static_cast<Alias *>(NULL));
+
+ ar & boost::serialization::base_object<Memento>(*this);
+ ar & children_;
+ }
+};
+
+class AliasNumberMemento : public Memento {
+public:
+ AliasNumberMemento(unsigned int alias_no ) : alias_no_(alias_no) {}
+ AliasNumberMemento() : alias_no_(0) {}
+private:
+ virtual void do_incremental_task_sync(Task* t,std::vector<ecf::Aspect::Type>& aspects) const { t->set_memento(this,aspects);}
+
+ unsigned int alias_no_;
+ friend class Task;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object<Memento>(*this);
+ ar & alias_no_;
+ }
+};
+
+
+class SuspendedMemento : public Memento {
+public:
+ SuspendedMemento(bool suspended) : suspended_(suspended) {}
+ SuspendedMemento() : suspended_(false) {}
+private:
+ virtual void do_incremental_node_sync(Node* n,std::vector<ecf::Aspect::Type>& aspects) const { n->set_memento(this,aspects);}
+
+ bool suspended_;
+ friend class Node;
+ friend class Defs;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object<Memento>(*this);
+ ar & suspended_;
+ }
+};
+
+class ServerStateMemento : public Memento {
+public:
+ ServerStateMemento(SState::State s) : state_(s) {}
+ ServerStateMemento() : state_(SState::HALTED) {}
+private:
+ virtual void do_incremental_defs_sync(Defs* defs,std::vector<ecf::Aspect::Type>& aspects) const { defs->set_memento(this,aspects);}
+
+ SState::State state_;
+ friend class Defs;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object<Memento>(*this);
+ ar & state_;
+ }
+};
+
+class ServerVariableMemento : public Memento {
+public:
+ ServerVariableMemento(const std::vector<Variable>& vec) : serverEnv_(vec) {}
+ ServerVariableMemento() {}
+private:
+ virtual void do_incremental_defs_sync(Defs* defs,std::vector<ecf::Aspect::Type>& aspects) const { defs->set_memento(this,aspects);}
+
+ std::vector<Variable> serverEnv_;
+ friend class Defs;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object<Memento>(*this);
+ ar & serverEnv_;
+ }
+};
+
+class NodeDefStatusDeltaMemento : public Memento {
+public:
+ NodeDefStatusDeltaMemento(DState::State state) : state_(state) {}
+ NodeDefStatusDeltaMemento() : state_(DState::UNKNOWN) {}
+private:
+ virtual void do_incremental_node_sync(Node* n,std::vector<ecf::Aspect::Type>& aspects) const { n->set_memento(this,aspects);}
+
+ DState::State state_;
+ friend class Node;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object<Memento>(*this);
+ ar & state_;
+ }
+};
+
+class NodeEventMemento : public Memento {
+public:
+ NodeEventMemento( const Event& e) : event_(e) {}
+ NodeEventMemento(){}
+private:
+ virtual void do_incremental_node_sync(Node* n,std::vector<ecf::Aspect::Type>& aspects) const { n->set_memento(this,aspects);}
+
+ Event event_;
+ friend class Node;
+ friend class ChildAttrs;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object<Memento>(*this);
+ ar & event_;
+ }
+};
+
+class NodeMeterMemento : public Memento {
+public:
+ NodeMeterMemento(const Meter& e) : meter_(e) {}
+ NodeMeterMemento() {}
+private:
+ virtual void do_incremental_node_sync(Node* n,std::vector<ecf::Aspect::Type>& aspects) const { n->set_memento(this,aspects);}
+
+ Meter meter_;
+ friend class Node;
+ friend class ChildAttrs;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object<Memento>(*this);
+ ar & meter_;
+ }
+};
+
+class NodeLabelMemento : public Memento {
+public:
+ NodeLabelMemento( const Label& e) : label_(e) {}
+ NodeLabelMemento(){}
+private:
+ virtual void do_incremental_node_sync(Node* n,std::vector<ecf::Aspect::Type>& aspects) const { n->set_memento(this,aspects);}
+
+ Label label_;
+ friend class Node;
+ friend class ChildAttrs;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object<Memento>(*this);
+ ar & label_;
+ }
+};
+
+
+class NodeTriggerMemento : public Memento {
+public:
+ NodeTriggerMemento(const Expression& e) : exp_(e) {}
+ NodeTriggerMemento() {}
+private:
+ virtual void do_incremental_node_sync(Node* n,std::vector<ecf::Aspect::Type>& aspects) const { n->set_memento(this,aspects);}
+
+ Expression exp_;
+ friend class Node;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object<Memento>(*this);
+ ar & exp_;
+ }
+};
+
+class NodeCompleteMemento : public Memento {
+public:
+ NodeCompleteMemento(const Expression& e) : exp_(e) {}
+ NodeCompleteMemento() {}
+private:
+ virtual void do_incremental_node_sync(Node* n,std::vector<ecf::Aspect::Type>& aspects) const { n->set_memento(this,aspects);}
+
+ Expression exp_;
+ friend class Node;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object<Memento>(*this);
+ ar & exp_;
+ }
+};
+
+class NodeRepeatMemento : public Memento {
+public:
+ NodeRepeatMemento( const Repeat& e ) : repeat_(e) {}
+ NodeRepeatMemento() {}
+private:
+ virtual void do_incremental_node_sync(Node* n,std::vector<ecf::Aspect::Type>& aspects) const { n->set_memento(this,aspects);}
+
+ Repeat repeat_;
+ friend class Node;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object<Memento>(*this);
+ ar & repeat_;
+ }
+};
+
+class NodeLimitMemento : public Memento {
+public:
+ NodeLimitMemento( const Limit& e) : limit_( e ) {}
+ NodeLimitMemento() {}
+private:
+ virtual void do_incremental_node_sync(Node* n,std::vector<ecf::Aspect::Type>& aspects) const { n->set_memento(this,aspects);}
+
+ Limit limit_;
+ friend class Node;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object<Memento>(*this);
+ ar & limit_;
+ }
+};
+
+class NodeInLimitMemento : public Memento {
+public:
+ NodeInLimitMemento( const InLimit& e) : inlimit_( e ) {}
+ NodeInLimitMemento() {}
+private:
+ virtual void do_incremental_node_sync(Node* n,std::vector<ecf::Aspect::Type>& aspects) const { n->set_memento(this,aspects);}
+
+ InLimit inlimit_;
+ friend class Node;
+ friend class InLimitMgr;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object<Memento>(*this);
+ ar & inlimit_;
+ }
+};
+
+class NodeVariableMemento : public Memento {
+public:
+ NodeVariableMemento( const Variable& e) : var_(e) {}
+ NodeVariableMemento(){}
+private:
+ virtual void do_incremental_node_sync(Node* n,std::vector<ecf::Aspect::Type>& aspects) const { n->set_memento(this,aspects);}
+
+ Variable var_;
+ friend class Node;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object<Memento>(*this);
+ ar & var_;
+ }
+};
+
+class NodeLateMemento : public Memento {
+public:
+ NodeLateMemento( const ecf::LateAttr& e) : late_(e) {}
+ NodeLateMemento() {}
+private:
+ virtual void do_incremental_node_sync(Node* n,std::vector<ecf::Aspect::Type>& aspects) const { n->set_memento(this,aspects);}
+
+ ecf::LateAttr late_;
+ friend class Node;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object<Memento>(*this);
+ ar & late_;
+ }
+};
+
+class FlagMemento : public Memento {
+public:
+ FlagMemento( const ecf::Flag& e) : flag_(e) {}
+ FlagMemento() {}
+private:
+ virtual void do_incremental_node_sync(Node* n,std::vector<ecf::Aspect::Type>& aspects) const { n->set_memento(this,aspects);}
+ virtual void do_incremental_defs_sync(Defs* defs,std::vector<ecf::Aspect::Type>& aspects) const { defs->set_memento(this,aspects);}
+
+ ecf::Flag flag_;
+ friend class Node;
+ friend class Defs;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object<Memento>(*this);
+ ar & flag_;
+ }
+};
+
+class NodeTodayMemento : public Memento {
+public:
+ NodeTodayMemento( const ecf::TodayAttr& attr) : attr_(attr) {}
+ NodeTodayMemento() {}
+private:
+ virtual void do_incremental_node_sync(Node* n,std::vector<ecf::Aspect::Type>& aspects) const { n->set_memento(this,aspects);}
+
+ ecf::TodayAttr attr_;
+ friend class Node;
+ friend class TimeDepAttrs;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object<Memento>(*this);
+ ar & attr_;
+ }
+};
+
+class NodeTimeMemento : public Memento {
+public:
+ NodeTimeMemento( const ecf::TimeAttr& attr) : attr_(attr) {}
+ NodeTimeMemento() {}
+private:
+ virtual void do_incremental_node_sync(Node* n,std::vector<ecf::Aspect::Type>& aspects) const { n->set_memento(this,aspects);}
+
+ ecf::TimeAttr attr_;
+ friend class Node;
+ friend class TimeDepAttrs;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object<Memento>(*this);
+ ar & attr_;
+ }
+};
+
+class NodeDayMemento : public Memento {
+public:
+ NodeDayMemento( const DayAttr& attr) : attr_(attr) {}
+ NodeDayMemento(){}
+private:
+ virtual void do_incremental_node_sync(Node* n,std::vector<ecf::Aspect::Type>& aspects) const { n->set_memento(this,aspects);}
+
+ DayAttr attr_;
+ friend class Node;
+ friend class TimeDepAttrs;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object<Memento>(*this);
+ ar & attr_;
+ }
+};
+
+class NodeCronMemento : public Memento {
+public:
+ NodeCronMemento( const ecf::CronAttr& attr) : attr_(attr) {}
+ NodeCronMemento() {}
+private:
+ virtual void do_incremental_node_sync(Node* n,std::vector<ecf::Aspect::Type>& aspects) const { n->set_memento(this,aspects);}
+
+ ecf::CronAttr attr_;
+ friend class Node;
+ friend class TimeDepAttrs;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object<Memento>(*this);
+ ar & attr_;
+ }
+};
+
+class NodeDateMemento : public Memento {
+public:
+ NodeDateMemento( const DateAttr& attr) : attr_(attr) {}
+ NodeDateMemento() {}
+private:
+ virtual void do_incremental_node_sync(Node* n,std::vector<ecf::Aspect::Type>& aspects) const { n->set_memento(this,aspects);}
+
+ DateAttr attr_;
+ friend class Node;
+ friend class TimeDepAttrs;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object<Memento>(*this);
+ ar & attr_;
+ }
+};
+
+class NodeZombieMemento : public Memento {
+public:
+ NodeZombieMemento(const ZombieAttr& attr) : attr_(attr) {}
+ NodeZombieMemento() {}
+private:
+ virtual void do_incremental_node_sync(Node* n,std::vector<ecf::Aspect::Type>& aspects) const { n->set_memento(this,aspects);}
+
+ ZombieAttr attr_;
+ friend class Node;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object<Memento>(*this);
+ ar & attr_;
+ }
+};
+
+
+class NodeVerifyMemento : public Memento {
+public:
+ NodeVerifyMemento(const std::vector<VerifyAttr>& attr) : verifys_(attr) {}
+ NodeVerifyMemento() {}
+private:
+ virtual void do_incremental_node_sync(Node* n,std::vector<ecf::Aspect::Type>& aspects) const { n->set_memento(this,aspects);}
+
+ std::vector<VerifyAttr> verifys_;
+ friend class Node;
+ friend class MiscAttrs;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object<Memento>(*this);
+ ar & verifys_;
+ }
+};
+
+class SubmittableMemento : public Memento {
+public:
+ SubmittableMemento( const std::string& jobsPassword,
+ const std::string& process_or_remote_id,
+ const std::string& abortedReason,
+ int tryNo
+ ) :
+ jobsPassword_( jobsPassword ),
+ process_or_remote_id_( process_or_remote_id ),
+ abortedReason_( abortedReason ),
+ tryNo_( tryNo ) {}
+ SubmittableMemento() : tryNo_(0) {}
+private:
+ virtual void do_incremental_task_sync(Task* n,std::vector<ecf::Aspect::Type>& aspects) const { n->set_memento(this,aspects);}
+ virtual void do_incremental_alias_sync(Alias* n,std::vector<ecf::Aspect::Type>& aspects) const { n->set_memento(this,aspects);}
+
+ std::string jobsPassword_;
+ std::string process_or_remote_id_;
+ std::string abortedReason_;
+ int tryNo_;
+ friend class Submittable;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object<Memento>(*this);
+ ar & jobsPassword_;
+ ar & process_or_remote_id_;
+ ar & abortedReason_;
+ ar & tryNo_;
+ }
+};
+
+class SuiteClockMemento : public Memento {
+public:
+ SuiteClockMemento( const ClockAttr& c ) : clockAttr_(c) {}
+ SuiteClockMemento() {}
+private:
+ virtual void do_incremental_suite_sync(Suite* n,std::vector<ecf::Aspect::Type>& aspects) const { n->set_memento(this,aspects);}
+
+ ClockAttr clockAttr_;
+ friend class Suite;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object<Memento>(*this);
+ ar & clockAttr_;
+ }
+};
+
+class SuiteBeginDeltaMemento : public Memento {
+public:
+ SuiteBeginDeltaMemento(bool begun) : begun_(begun) {}
+ SuiteBeginDeltaMemento() : begun_(false) {}
+private:
+ virtual void do_incremental_suite_sync(Suite* n,std::vector<ecf::Aspect::Type>& aspects) const { n->set_memento(this,aspects);}
+
+ bool begun_;
+ friend class Suite;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object<Memento>(*this);
+ ar & begun_;
+ }
+};
+
+class SuiteCalendarMemento : public Memento {
+public:
+ SuiteCalendarMemento(const ecf::Calendar& cal) : calendar_(cal) {}
+ SuiteCalendarMemento() {}
+private:
+ virtual void do_incremental_suite_sync(Suite* n,std::vector<ecf::Aspect::Type>& aspects) const { n->set_memento(this,aspects);}
+
+ ecf::Calendar calendar_; // *Only* persisted since used by the why() on client side
+ friend class Suite;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object<Memento>(*this);
+ ar & calendar_;
+ }
+};
+
+
+BOOST_CLASS_EXPORT_KEY(StateMemento);
+BOOST_CLASS_EXPORT_KEY(NodeDefStatusDeltaMemento);
+BOOST_CLASS_EXPORT_KEY(SuspendedMemento);
+BOOST_CLASS_EXPORT_KEY(ServerStateMemento);
+BOOST_CLASS_EXPORT_KEY(ServerVariableMemento);
+BOOST_CLASS_EXPORT_KEY(NodeEventMemento);
+BOOST_CLASS_EXPORT_KEY(NodeMeterMemento);
+BOOST_CLASS_EXPORT_KEY(NodeLabelMemento);
+BOOST_CLASS_EXPORT_KEY(NodeTriggerMemento);
+BOOST_CLASS_EXPORT_KEY(NodeCompleteMemento);
+BOOST_CLASS_EXPORT_KEY(NodeRepeatMemento);
+BOOST_CLASS_EXPORT_KEY(NodeLimitMemento);
+BOOST_CLASS_EXPORT_KEY(NodeInLimitMemento);
+BOOST_CLASS_EXPORT_KEY(NodeVariableMemento);
+BOOST_CLASS_EXPORT_KEY(NodeLateMemento);
+BOOST_CLASS_EXPORT_KEY(NodeTodayMemento);
+BOOST_CLASS_EXPORT_KEY(NodeTimeMemento);
+BOOST_CLASS_EXPORT_KEY(NodeDayMemento);
+BOOST_CLASS_EXPORT_KEY(NodeCronMemento);
+BOOST_CLASS_EXPORT_KEY(NodeDateMemento);
+BOOST_CLASS_EXPORT_KEY(NodeZombieMemento);
+BOOST_CLASS_EXPORT_KEY(FlagMemento);
+BOOST_CLASS_EXPORT_KEY(NodeVerifyMemento);
+BOOST_CLASS_EXPORT_KEY(SubmittableMemento);
+BOOST_CLASS_EXPORT_KEY(SuiteClockMemento);
+BOOST_CLASS_EXPORT_KEY(SuiteBeginDeltaMemento);
+BOOST_CLASS_EXPORT_KEY(SuiteCalendarMemento);
+BOOST_CLASS_EXPORT_KEY(OrderMemento);
+BOOST_CLASS_EXPORT_KEY(ChildrenMemento);
+BOOST_CLASS_EXPORT_KEY(AliasChildrenMemento);
+BOOST_CLASS_EXPORT_KEY(AliasNumberMemento);
+
+#endif
diff --git a/ANode/src/MiscAttrs.cpp b/ANode/src/MiscAttrs.cpp
new file mode 100644
index 0000000..5f7a0e5
--- /dev/null
+++ b/ANode/src/MiscAttrs.cpp
@@ -0,0 +1,178 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #286 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <assert.h>
+#include "Defs.hpp"
+#include "Suite.hpp"
+
+#include "MiscAttrs.hpp"
+#include "Str.hpp"
+#include "Log.hpp"
+#include "Ecf.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+void MiscAttrs::begin()
+{
+ // reset verification
+ for(size_t i = 0; i < verifys_.size(); i++) { verifys_[i].reset(); }
+}
+
+std::ostream& MiscAttrs::print(std::ostream& os) const
+{
+ BOOST_FOREACH(const ZombieAttr& z, zombies_) { z.print(os); }
+ BOOST_FOREACH(const VerifyAttr& v, verifys_ ) { v.print(os); }
+ return os;
+}
+
+bool MiscAttrs::operator==(const MiscAttrs& rhs) const
+{
+ if (zombies_.size() != rhs.zombies_.size()) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "MiscAttrs::operator== (zombies_.size() != rhs.zombies_.size()) " << node_->debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ for(unsigned i = 0; i < zombies_.size(); ++i) {
+ if (!(zombies_[i] == rhs.zombies_[i]) ) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "MiscAttrs::operator== (!(zombies_[i] == rhs.zombies_[i]) " << node_->debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ }
+
+ if (verifys_.size() != rhs.verifys_.size()) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "MiscAttrs::operator== (verifys_.size() != rhs.verifys_.size()) " << node_->debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ for(unsigned i = 0; i < verifys_.size(); ++i) {
+ if (!(verifys_[i] == rhs.verifys_[i] )) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "MiscAttrs::operator== (!(verifys_[i] == rhs.verifys_[i] )) " << node_->debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ }
+ return true;
+}
+
+
+void MiscAttrs::verification(std::string& errorMsg) const
+{
+ BOOST_FOREACH(const VerifyAttr& v, verifys_) {
+ if (v.expected() != v.actual()) {
+ std::stringstream ss;
+ ss << node_->debugNodePath() << " expected " << v.expected() << " " << NState::toString(v.state()) << " but found " << v.actual() << "\n";
+ errorMsg += ss.str();
+ }
+ }
+}
+
+void MiscAttrs::addZombie( const ZombieAttr& z)
+{
+ const ZombieAttr& theFndOne = findZombie( z.zombie_type() );
+ if (!theFndOne.empty()) {
+ std::stringstream ss;
+ ss << "MiscAttrs::addZombie: Node " << node_->absNodePath() << " already has a zombie attribute of type " << Child::to_string(theFndOne.zombie_type()) << "\n";
+ throw std::runtime_error(ss.str());
+ }
+ zombies_.push_back( z );
+ node_->state_change_no_ = Ecf::incr_state_change_no(); // Only add where used in AlterCmd
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "MiscAttrs::addZombie()\n";
+#endif
+}
+
+
+void MiscAttrs::deleteZombie(const std::string& zombie_type)
+{
+ if (zombie_type.empty()) {
+ zombies_.clear();
+ node_->state_change_no_ = Ecf::incr_state_change_no();
+ return;
+ }
+
+ if (!Child::valid_zombie_type(zombie_type)) {
+ throw std::runtime_error("MiscAttrs::deleteZombie failed: Expected one of [ ecf | path | user ] or empty string but found " + zombie_type);
+ }
+ delete_zombie( Child::zombie_type(zombie_type) );
+}
+
+void MiscAttrs::delete_zombie(Child::ZombieType zt)
+{
+ for(size_t i = 0; i < zombies_.size(); ++i) {
+ if (zombies_[i].zombie_type() == zt) {
+ zombies_.erase( zombies_.begin() + i );
+ node_->state_change_no_ = Ecf::incr_state_change_no();
+ return;
+ }
+ }
+}
+
+
+const ZombieAttr& MiscAttrs::findZombie( ecf::Child::ZombieType zombie_type) const
+{
+ /// There should only be one of each type
+ for(size_t i = 0; i < zombies_.size(); i++) {
+ if ( zombies_[i].zombie_type() == zombie_type ) {
+ return zombies_[i];
+ }
+ }
+ return ZombieAttr::EMPTY();
+}
+
+void MiscAttrs::addVerify( const VerifyAttr& v )
+{
+ if (findVerify(v)) {
+ std::stringstream ss;
+ ss << "Add Verify failed: Duplicate '" << v.toString() << "' already exist for node " << node_->debugNodePath();
+ throw std::runtime_error( ss.str() );
+ }
+ verifys_.push_back(v);
+ node_->state_change_no_ = Ecf::incr_state_change_no();
+}
+
+bool MiscAttrs::findVerify(const VerifyAttr& v) const
+{
+ size_t theSize = verifys_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ if (verifys_[i].state() == v.state() ) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void MiscAttrs::clear()
+{
+ zombies_.clear(); // can be added/removed via AlterCmd
+ verifys_.clear();
+}
diff --git a/ANode/src/MiscAttrs.hpp b/ANode/src/MiscAttrs.hpp
new file mode 100644
index 0000000..91f93a3
--- /dev/null
+++ b/ANode/src/MiscAttrs.hpp
@@ -0,0 +1,89 @@
+#ifndef MISC_ATTRS_HPP_
+#define MISC_ATTRS_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #235 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <ostream>
+
+#include <boost/noncopyable.hpp>
+#include <boost/serialization/base_object.hpp>
+#include <boost/serialization/utility.hpp>
+#include <boost/serialization/vector.hpp> // no need to include <vector>
+
+#include "ZombieAttr.hpp"
+#include "VerifyAttr.hpp"
+#include "NodeFwd.hpp"
+
+class MiscAttrs : private boost::noncopyable {
+public:
+ MiscAttrs(Node* node) : node_(node) {}
+ MiscAttrs() : node_(NULL) {}
+
+ // needed by node serialisation
+ void set_node(Node* n) { node_ = n; }
+
+ void begin();
+
+ // standard functions: ==============================================
+ std::ostream& print(std::ostream&) const;
+ bool operator==(const MiscAttrs& ) const;
+
+ // Access functions: ======================================================
+ const std::vector<VerifyAttr>& verifys() const { return verifys_;}
+ const std::vector<ZombieAttr>& zombies() const { return zombies_; }
+
+ // Add functions: ===============================================================
+ void addVerify( const VerifyAttr& ); // for testing and verification Can throw std::runtime_error
+ void addZombie( const ZombieAttr& ); // will throw std::runtime_error if duplicate
+
+ // Delete functions: can throw std::runtime_error ===================================
+ // if name argument is empty, delete all attributes of that type
+ // Can throw std::runtime_error of the attribute can not be found
+ void delete_zombie(const ecf::Child::ZombieType);
+ void deleteZombie(const std::string& type); // string must be one of [ user | ecf | path ]
+
+ // Change functions: ================================================================
+ /// returns true the change was made else false, Can throw std::runtime_error for parse errors
+
+ // Find functions: ============================================================
+ bool findVerify(const VerifyAttr& ) const;
+ const ZombieAttr& findZombie( ecf::Child::ZombieType ) const;
+
+ void verification(std::string& errorMsg) const;
+
+private:
+ void clear(); /// Clear *ALL* internal attributes
+
+ std::vector<ZombieAttr>::const_iterator zombie_begin() const { return zombies_.begin();}
+ std::vector<ZombieAttr>::const_iterator zombie_end() const { return zombies_.end();}
+ std::vector<VerifyAttr>::const_iterator verify_begin() const { return verifys_.begin();}
+ std::vector<VerifyAttr>::const_iterator verify_end() const { return verifys_.end();}
+
+private:
+ Node* node_; // *NOT* persisted must be set by the parent class
+ friend class Node;
+
+private:
+ std::vector<ZombieAttr> zombies_;
+ std::vector<VerifyAttr> verifys_; // used for statistics and test verification
+
+private:
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/) {
+ ar & zombies_;
+ ar & verifys_;
+ }
+};
+#endif
diff --git a/ANode/src/Node.cpp b/ANode/src/Node.cpp
new file mode 100644
index 0000000..a0b5437
--- /dev/null
+++ b/ANode/src/Node.cpp
@@ -0,0 +1,1961 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #305 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <assert.h>
+#include <deque>
+
+#include <boost/bind.hpp>
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Task.hpp"
+#include "Extract.hpp"
+
+#include "NodeState.hpp"
+#include "NodePath.hpp"
+#include "Stl.hpp"
+#include "Str.hpp"
+#include "Indentor.hpp"
+#include "ExprAst.hpp"
+#include "Log.hpp"
+#include "PrintStyle.hpp"
+#include "JobsParam.hpp"
+#include "ExprAstVisitor.hpp"
+#include "Ecf.hpp"
+#include "SuiteChanged.hpp"
+#include "CmdContext.hpp"
+#include "AbstractObserver.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+//#define DEBUG_DEPENDENCIES 1
+//#define DEBUG_REQUEUE 1
+//#define DEBUG_FIND_REFERENCED_NODE 1
+
+Node::Node(const std::string& n)
+: parent_(NULL),name_(n),
+ suspended_(false),
+ state_( std::make_pair(NState(),time_duration(0,0,0,0)) ),
+ completeExpr_(NULL),
+ triggerExpr_(NULL),
+ lateAttr_(NULL),
+ autoCancel_(NULL),
+ time_dep_attrs_(NULL),
+ child_attrs_(NULL),
+ misc_attrs_(NULL),
+ inLimitMgr_(this),
+ state_change_no_(0),variable_change_no_(0),suspended_change_no_(0),
+ graphic_ptr_(0)
+{
+ string msg;
+ if (!Str::valid_name(n, msg)) {
+ throw std::runtime_error("Invalid node name : " + msg);
+ }
+}
+
+Node::Node()
+: parent_(NULL),
+ suspended_(false),
+ state_( std::make_pair(NState(),time_duration(0,0,0,0)) ),
+ completeExpr_(NULL),
+ triggerExpr_(NULL),
+ lateAttr_(NULL),
+ autoCancel_(NULL),
+ time_dep_attrs_(NULL),
+ child_attrs_(NULL),
+ misc_attrs_(NULL),
+ inLimitMgr_(this),
+ state_change_no_(0),variable_change_no_(0),suspended_change_no_(0),
+ graphic_ptr_(0)
+{}
+
+Node::~Node() {
+ delete completeExpr_;
+ delete triggerExpr_;
+ delete lateAttr_;
+ delete autoCancel_;
+ delete time_dep_attrs_;
+ delete child_attrs_;
+ delete misc_attrs_;
+}
+
+bool Node::isParentSuspended() const
+{
+ Node* theParent = parent();
+ if (theParent) {
+ if (theParent->isSuspended()) return true;
+ return theParent->isParentSuspended();
+ }
+ return defs()->isSuspended(); // obtained from the server states
+}
+
+void Node::resume()
+{
+ if ( suspended_) {
+ clearSuspended();
+ }
+}
+
+void Node::clearSuspended()
+{
+ /// Guard against unnecessary creation of memento's
+ if (suspended_) {
+ suspended_ = false;
+ suspended_change_no_ = Ecf::incr_state_change_no();
+ }
+}
+
+void Node::suspend()
+{
+ // Typically called via user action or via defstatus
+ suspended_ = true;
+ suspended_change_no_ = Ecf::incr_state_change_no();
+}
+
+void Node::begin()
+{
+ // Set the state without causing any side effects
+ initState(0);
+
+ clearTrigger();
+ clearComplete();
+
+ flag_.reset();
+ repeat_.reset(); // if repeat is empty reset() does nothing
+
+ if (lateAttr_) lateAttr_->reset();
+ if (child_attrs_) child_attrs_->begin();
+ if (misc_attrs_) misc_attrs_->begin();
+ for(size_t i = 0; i < limitVec_.size(); i++) { limitVec_[i]->reset(); }
+
+ // Let time base attributes use, relative duration if applicable
+ if (time_dep_attrs_) {
+ time_dep_attrs_->begin();
+ time_dep_attrs_->markHybridTimeDependentsAsComplete();
+ }
+
+ // DO *NOT* call update_generated_variables(). Called on a type specific bases, for begin
+ // Typically we need only call update_generated_variables() for a task, at job creation time.
+ // so that ECF_OUT, ECF_TRYNO, ECF_JOBOUT, ECF_PASS(jobsPassword_) can be updated.
+ // However the generated variables are used when within job generation and can be referenced by AST
+ // Hence to avoid excessive memory consumption, they are created on demand
+}
+
+void Node::requeue(
+ bool resetRepeats,
+ int clear_suspended_in_child_nodes,
+ bool do_reset_next_time_slot)
+{
+#ifdef DEBUG_REQUEUE
+ LOG(Log::DBG," Node::requeue() " << absNodePath() << " resetRepeats = " << resetRepeats);
+#endif
+ /// Note: we don't reset verify attributes as they record state stat's
+
+ // Set the state without causing any side effects
+ initState(clear_suspended_in_child_nodes);
+
+ clearTrigger();
+ clearComplete();
+
+ if (resetRepeats) repeat_.reset(); // if repeat is empty reset() does nothing
+
+
+ /// If a job takes longer than it slots, then that slot is missed, and next slot is used
+ /// Note we do *NOT* reset for requeue as we want to advance the valid time slots.
+ /// *NOTE* Update calendar will *free* time dependencies *even* time series. They rely
+ /// on this function to clear the time dependencies so they *HOLD* the task.
+ if ( time_dep_attrs_ ) {
+
+ /// Requeue has several contexts:
+ /// 1/ manual requeue
+ /// 2/ automated requeue due to repeats
+ /// 3/ automated requeue due to time dependencies
+ /// For manual and automated reueue due to repeat's we always clear Flag::NO_REQUE_IF_SINGLE_TIME_DEP
+ /// since in those context we do NOT want miss any time slots
+ bool reset_next_time_slot = true;
+ if (do_reset_next_time_slot) {
+ reset_next_time_slot = true;
+ }
+ else {
+ if (flag().is_set(Flag::NO_REQUE_IF_SINGLE_TIME_DEP)) {
+ /// If we have done an interactive run or complete, *dont* increment next_time_slot_
+ /// allow next time on time based attributes to be incremented and *not* reset,
+ /// when force and run commands used
+ reset_next_time_slot = false;
+ }
+ }
+
+ time_dep_attrs_->requeue(reset_next_time_slot);
+ time_dep_attrs_->markHybridTimeDependentsAsComplete();
+ }
+
+
+ // reset the flags, however remember if edit were made
+ bool edit_history_set = flag().is_set(ecf::Flag::MESSAGE);
+ flag_.reset(); // will CLEAR NO_REQUE_IF_SINGLE_TIME_DEP
+ if (edit_history_set) flag().set(ecf::Flag::MESSAGE);
+
+
+ if (lateAttr_) lateAttr_->reset();
+ if (child_attrs_) child_attrs_->requeue();
+
+ for(size_t i = 0; i < limitVec_.size(); i++) { limitVec_[i]->reset(); }
+
+ // ECFLOW-196, ensure the re-queue release tokens held by Limits higher up the tree.
+ // Note: Its safe to call decrementInLimit, even when no limit consumed
+ std::set<Limit*> limitSet; // ensure local limit have preference over parent
+ decrementInLimit(limitSet); // will recurse up, expensive but needed
+}
+
+
+void Node::requeue_time_attrs()
+{
+ // Note: we *dont* mark hybrid time dependencies as complete.
+ // i.e. since this is called during alter command, it could be that
+ // the task is in a submitted or active state.
+ if (time_dep_attrs_) time_dep_attrs_->requeue(true);
+}
+
+void Node::requeue_labels()
+{
+ if (child_attrs_) child_attrs_->requeue_labels();
+}
+
+void Node::miss_next_time_slot()
+{
+ // Why do we need to set NO_REQUE_IF_SINGLE_TIME_DEP flag ?
+ // This is required when we have time based attributes, which we want to miss.
+ // time 10:00
+ // time 12:00
+ // Essentially this avoids an automated job run, *IF* the job was run manually for a given time slot.
+ // If we call this function before 10:00, we want to miss the next time slot (i.e. 10:00)
+ // and want to *requeue*, for 12:00 time slot. However at re-queue, we need to ensure
+ // we do *not* reset the 10:00 time slot. hence by setting NO_REQUE_IF_SINGLE_TIME_DEP
+ // we allow requeue to query this flag, and hence avoid resetting the time based attribute
+ // Note: requeue will *always* clear NO_REQUE_IF_SINGLE_TIME_DEP afterwards.
+ //
+ // In the case above when we reach the last time slot, there is *NO* automatic requeue, and
+ // hence, *no* clearing of NO_REQUE_IF_SINGLE_TIME_DEP flag.
+ // This will then be up to any top level parent that has a Repeat/cron to force a requeue
+ // when all the children are complete. *or* user does a manual re-queue
+ //
+ // Additionally if the job *aborts*, we clear NO_REQUE_IF_SINGLE_TIME_DEP if it was set.
+ // Otherwise if manually run again, we will miss further time slots.
+ if ( time_dep_attrs_) {
+
+ /// Handle abort
+ /// The flag: NO_REQUE_IF_SINGLE_TIME_DEP is *only* set when doing an interactive force complete or run command.
+ /// What happens if the job aborts during the run command ?
+ /// time 10:00
+ /// time 11:00
+ /// If at 9.00am we used the run command, we want to miss the 10:00 time slot.
+ /// However if the run at 9.00 fails, and we run again, we also miss 11:00 time slot.
+ /// During the run the flag is still set.
+ /// Hence *ONLY* miss the next time slot *IF* Flag::NO_REQUE_IF_SINGLE_TIME_DEP is NOT set
+ if (!flag().is_set(Flag::NO_REQUE_IF_SINGLE_TIME_DEP)) {
+
+ SuiteChanged0 changed(shared_from_this());
+ flag().set(Flag::NO_REQUE_IF_SINGLE_TIME_DEP);
+
+ time_dep_attrs_->miss_next_time_slot();
+ }
+ }
+}
+
+void Node::calendarChanged(
+ const ecf::Calendar& c,
+ std::vector<node_ptr>& auto_cancelled_nodes,
+ const ecf::LateAttr*)
+{
+ if (time_dep_attrs_) {
+ time_dep_attrs_->calendarChanged(c);
+ }
+
+ if (checkForAutoCancel(c)) {
+ auto_cancelled_nodes.push_back(shared_from_this());
+ }
+}
+
+void Node::check_for_lateness(const ecf::Calendar& c,const ecf::LateAttr* inherited_late)
+{
+ // Late flag should ONLY be set on Submittable
+ if (lateAttr_) {
+ // Only check for lateness if we are not late.
+ if (!lateAttr_->isLate()) {
+ if (!inherited_late || inherited_late->isNull()) checkForLateness(c);
+ else {
+ LateAttr overidden_late = *inherited_late;
+ overidden_late.override_with(lateAttr_);
+ if (overidden_late.check_for_lateness( state_, c)) {
+ lateAttr_->setLate(true);
+ flag().set(ecf::Flag::LATE);
+ }
+ }
+ }
+ }
+ else {
+ // inherited late, we can only set late flag.
+ if (inherited_late && !flag().is_set(ecf::Flag::LATE) && inherited_late->check_for_lateness(state_, c)) {
+ flag().set(ecf::Flag::LATE);
+ }
+ }
+}
+
+void Node::checkForLateness(const ecf::Calendar& c)
+{
+ if (lateAttr_ && lateAttr_->check_for_lateness(state_,c)) {
+ lateAttr_->setLate(true);
+ flag().set(ecf::Flag::LATE);
+ cout << "Node::checkForLateness late flag set on " << absNodePath() << "\n";
+ }
+}
+
+void Node::initState(int clear_suspended_in_child_nodes)
+{
+ if (defStatus_ == DState::SUSPENDED) {
+ /// Note: DState::SUSPENDED is not a real state, its really a user interaction
+ /// Replace with suspend, and set underlying state as queued
+ suspend();
+ setStateOnly( NState::QUEUED );
+ }
+ else {
+
+ if (clear_suspended_in_child_nodes > 0) {
+ clearSuspended();
+ }
+
+ // convert DState --> NState.
+ // NOTE:: NState does *NOT* have SUSPENDED
+ setStateOnly( DState::convert( defStatus_.state()) );
+ }
+}
+
+void Node::requeueOrSetMostSignificantStateUpNodeTree()
+{
+ // Get the computed state of my immediate children
+ // *** A family can be marked as complete, via complete trigger when not all its children
+ // *** are complete, hence computedState() *MUST* first check the immediate state ,
+ // *** before considering its immediate children
+ NState::State computedStateOfImmediateChildren = computedState(Node::IMMEDIATE_CHILDREN);
+
+#ifdef DEBUG_REQUEUE
+ LogToCout toCoutAsWell; cout << "\n";
+ Indentor indent;
+ LOG(Log::DBG,"requeueOrSetMostSignificantStateUpNodeTree() " << debugNodePath() << "(" << NState::toString(state()) << ") computed(" << NState::toString(computedStateOfImmediateChildren) << ")");
+#endif
+
+ if (computedStateOfImmediateChildren == NState::COMPLETE ) {
+
+ // set most significant state of my immediate children
+ // Record: That Suite/Family completed.
+ if ( computedStateOfImmediateChildren != state() ) {
+ setStateOnly( computedStateOfImmediateChildren );
+ }
+
+ // For automated re-queue do *not* clear suspended state in *child* nodes
+ int clear_suspended_in_child_nodes = -1;
+
+ if (!repeat_.empty()) {
+
+ repeat_.increment();
+
+ // If the repeat is still valid, re-queue the node
+#ifdef DEBUG_REQUEUE
+ LOG(Log::DBG,"requeueOrSetMostSignificantStateUpNodeTree " << debugNodePath() << " for repeat " << repeat_.toString());
+#endif
+ if ( repeat_.valid() ) {
+#ifdef DEBUG_REQUEUE
+ LOG(Log::DBG,"requeueOrSetMostSignificantStateUpNodeTree() VALID for requeue " << debugNodePath() << " for repeat at " << repeat_.toString());
+#endif
+
+ /// reset relative duration down the hierarchy from this point. Only valid when we have repeats
+ /// Note: Going down hierarchy is wasted if there are no relative time attributes
+ resetRelativeDuration();
+
+ // Remove effects of RUN and Force complete interactive commands
+ // For automated re-queue *DUE* to Repeats, *CLEAR* any user interaction that would miss the next time slots. *Down* the hierarchy
+ // This handles the case where a user, has manually intervened (i.e via run or complete) and we had a time attribute
+ // That time attribute will have expired, typically we show next day. In the case where we have a parent repeat
+ // we need to clear the flag, otherwise the task/family with time based attribute would wait for next day.
+ requeue( false /* don't reset repeats */,
+ clear_suspended_in_child_nodes,
+ true /* reset_next_time_slot */ );
+ set_most_significant_state_up_node_tree();
+ return;
+ }
+ }
+
+ /// If user has *INTERACTIVLY* forced changed in state to complete *OR* run the job.
+ /// This would cause Node to miss the next time slot. i.e expire the time slot
+ /// In which case testTimeDependenciesForRequeue should return false for a single time/today dependency
+ /// and not requeue the node.
+ if (time_dep_attrs_ && time_dep_attrs_->testTimeDependenciesForRequeue()) {
+
+ // This is the only place we do not explicitly reset_next_time_slot
+ bool reset_next_time_slot = false;
+
+ // Remove effects of RUN and Force complete interactive commands, *BUT* only if *not* applied to this cron
+ if (!time_dep_attrs_->crons().empty()) {
+ if (!flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP)) {
+ reset_next_time_slot = true ;
+ }
+ }
+
+ requeue( false /* don't reset repeats */,
+ clear_suspended_in_child_nodes,
+ reset_next_time_slot );
+ set_most_significant_state_up_node_tree();
+ return;
+ }
+ }
+
+ // In case compute state is other that COMPLETE, update. i,e for Family/Suite
+ if ( computedStateOfImmediateChildren != state() ) {
+ setStateOnly( computedStateOfImmediateChildren );
+ }
+
+
+ // recurse up the node tree
+ Node* theParentNode = parent();
+ if (theParentNode) {
+ theParentNode->requeueOrSetMostSignificantStateUpNodeTree();
+ }
+ else {
+ // No parent, hence next level is the root, ie the Defs
+ // Reflect the status of all the suite's
+ // **** This should not recurse down, just reflect status of suites
+ defs()->set_most_significant_state();
+ }
+}
+
+void Node::set_most_significant_state_up_node_tree()
+{
+ if (isTask()) {
+ parent()->set_most_significant_state_up_node_tree();
+ return;
+ }
+
+ // set most significant state of my immediate children
+ NState::State computedStateOfImmediateChildren = computedState(Node::IMMEDIATE_CHILDREN);
+ if ( computedStateOfImmediateChildren != state() ) {
+ setStateOnly( computedStateOfImmediateChildren );
+ }
+
+ // recurse up the node tree
+ Node* theParentNode = parent();
+ if (theParentNode) {
+ theParentNode->set_most_significant_state_up_node_tree();
+ }
+ else {
+ // No parent, hence next level is the root, ie the Defs
+ // Reflect the status of all the suite's
+ // **** This should not recurse down, just reflect status of suites
+ defs()->set_most_significant_state();
+ }
+}
+void Node::resetRelativeDuration()
+{
+ if (time_dep_attrs_) time_dep_attrs_->resetRelativeDuration();
+}
+
+
+// Returning false, *STOPS* further traversal *DOWN* the node tree
+bool Node::resolveDependencies(JobsParam& jobsParam)
+{
+ // This function is called:
+ // a/ Periodically by the server, i.e every minute
+ // b/ Asyncrousnly, after child command, via job submission
+#ifdef DEBUG_DEPENDENCIES
+ LogToCout toCoutAsWell; cout << "\n";
+ LOG(Log::DBG," " << debugNodePath() << "::resolveDependencies " << NState::toString(state()) << " AT " << suite()->calendar().toString());
+#endif
+
+ // Improve the granularity for the check for lateness (during job submission). See SUP-873 "late" functionality
+ if (lateAttr_ && isSubmittable()) {
+ // since the suite() traverse up the tree, only call when have a late attribute
+ checkForLateness(suite()->calendar());
+ }
+
+ if (isSuspended()) {
+#ifdef DEBUG_DEPENDENCIES
+ LOG(Log::DBG," Node::resolveDependencies() " << absNodePath() << " HOLDING as node state " << NState::toString(state()) << " is SUSPENDED " );
+#endif
+ return false;
+ }
+
+ if (state() == NState::COMPLETE) {
+#ifdef DEBUG_DEPENDENCIES
+ LOG(Log::DBG," Node::resolveDependencies() " << absNodePath() << " HOLDING as node state " << NState::toString(state()) << " is not valid for job submission" );
+#endif
+ return false;
+ }
+
+ if (time_dep_attrs_ && !time_dep_attrs_->timeDependenciesFree()) {
+#ifdef DEBUG_DEPENDENCIES
+ const Calendar& calendar = suite()->calendar();
+ LOG(Log::DBG," Node::resolveDependencies() " << absNodePath() << " HOLDING due to time dependencies at " << calendar.toString());
+#endif
+ return false;
+ }
+
+ // Complete *MUST* be evaluated before trigger. As it can affect the other
+ // i.e A state change to COMPLETE, in which case no need to submit tasks
+ // However if the complete does *not* evaluate it should *NOT* hold the node.
+ if ( evaluateComplete() ) {
+ if (completeAst()) {
+
+ flag().set(ecf::Flag::BYRULE);
+
+ // If we are a parent sets the state first. then set state on all the children
+ set_state_hierarchically( NState::COMPLETE,false); // reset try no and decrement inlimit resources & update repeats
+
+#ifdef DEBUG_DEPENDENCIES
+ LOG(Log::DBG," Node::resolveDependencies() " << absNodePath() << " HOLDING since evaluation of COMPLETE");
+#endif
+ // We have a complete By returning false here, we stop dependency evaluation for any children
+ return false;
+ }
+ }
+ // No complete, or we have a complete that does not evaluate.(this should not hold the node)
+
+
+ if ( evaluateTrigger() ) {
+ // WE only get here **IF** :
+ // 1/ There is no trigger
+ // 2/ WE have a trigger and it evaluates to true
+#ifdef DEBUG_DEPENDENCIES
+ LOG(Log::DBG," Node::resolveDependencies() " << absNodePath() << " FREE of TRIGGER");
+#endif
+ return true;
+ }
+
+ // We *have* a trigger and it does not evaluate, hold the node
+#ifdef DEBUG_DEPENDENCIES
+ LOG(Log::DBG," Node::resolveDependencies() " << absNodePath() << " HOLDING due to TRIGGER");
+#endif
+ return false;
+}
+
+void Node::freeTrigger() const
+{
+ if (triggerExpr_) triggerExpr_->setFree();
+}
+
+void Node::clearTrigger() const
+{
+ if (triggerExpr_) triggerExpr_->clearFree();
+}
+
+void Node::freeComplete() const
+{
+ if (completeExpr_) completeExpr_->setFree();
+}
+
+void Node::clearComplete() const
+{
+ if (completeExpr_) completeExpr_->clearFree();
+}
+
+void Node::freeHoldingDateDependencies()
+{
+ if (time_dep_attrs_) time_dep_attrs_->freeHoldingDateDependencies();
+}
+
+void Node::freeHoldingTimeDependencies()
+{
+ if (time_dep_attrs_) time_dep_attrs_->freeHoldingTimeDependencies();
+}
+
+bool Node::checkForAutoCancel(const ecf::Calendar& calendar) const
+{
+ if ( autoCancel_ && state() == NState::COMPLETE) {
+ if (autoCancel_->isFree(calendar,state_.second)) {
+
+ /// *Only* delete this node if we don't create zombies
+ /// anywhere for our children
+ vector<Task*> taskVec;
+ getAllTasks(taskVec);
+ BOOST_FOREACH(Task* t, taskVec) {
+ if (t->state() == NState::ACTIVE || t->state() == NState::SUBMITTED) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Node::evaluateComplete() const
+{
+ // Complete *MUST* be evaluate before trigger. As it can affect the other
+ AstTop* theCompeteAst = completeAst();
+ if (theCompeteAst) {
+ // *NOTE* if we have a non NULL complete ast, we must have complete expression
+ // The freed state is stored on the expression ( i.e not on the ast)
+ // ISSUE: Complete expression can not be by-passed in the GUI
+ if (completeExpr_->isFree() || theCompeteAst->evaluate()) {
+
+ // Note: if a task has been set complete, the use may decide to place into queued state( via GUI)
+ // In which case, we *want* this complete expression to be re-evaluated.
+ // Hence the old code below has been commented out.
+ // >>old: Set the complete as free, until begin()/requeue, // Only update state change no, if state has changed.
+ // >>old:if (!completeExpr_->isFree()) freeComplete();
+
+ // ECFLOW-247 Family goes complete despite active child
+ // Typically we have a complete expression on the family i/e f1/t1 == complete
+ // However if we have another child that is active,submitted forcing family to complete will cause zombies
+ // Another child could be a family which could be aborted.
+ // if computedState state is:
+ // NState::ABORTED -> don't complete if any of the children are aborted -> ECFLOW-247
+ // This can hide active/submitted nodes, as abort has higher priority, could cause zombies
+ // NState::ACTIVE -> can cause zombies
+ // NState::SUBMITTED -> can cause zombies
+ // hence only allow complete is we are in a NState::QUEUED state
+ NState::State theComputedState = computedState(Node::HIERARCHICAL);
+ if ( theComputedState != NState::QUEUED ) {
+#ifdef DEBUG_DEPENDENCIES
+ LOG(Log::DBG," Node::evaluateComplete() " << absNodePath() << " AST evaluation succeeded *BUT* " << debugType() << " has children in ACTIVE or SUBMITTED States" );
+#endif
+ return false;
+ }
+
+#ifdef DEBUG_DEPENDENCIES
+ LOG(Log::DBG," Node::evaluateComplete() " << debugNodePath() << " FREE, COMPLETE AST evaluation succeeded " );
+#endif
+ return true;
+ }
+ else {
+ /// *IMPORTANT* When a complete does not evaluate, it should *NOT* stop further tree walking
+#ifdef DEBUG_DEPENDENCIES
+ LOG(Log::DBG," Node::evaluateComplete() " << debugNodePath() << " HOLDING, COMPLETE AST evaluation failed" );
+#endif
+ return false;
+ }
+ }
+ return true;
+}
+
+bool Node::evaluateTrigger() const
+{
+ AstTop* theTriggerAst = triggerAst();
+ if (theTriggerAst) {
+
+ // Note 1: A trigger can be freed by the ForceCmd
+ // Note 2: if we have a non NULL trigger ast, we must have trigger expression
+ // Note 3: The freed state is stored on the expression ( i.e *NOT* on the ast (abstract syntax tree) )
+ if (triggerExpr_->isFree() || theTriggerAst->evaluate()) {
+
+ // *ALWAYS* evaluate trigger expression unless user has forcibly removed trigger dependencies
+ // ******** This allows force queued functionality, to work as expected, since trigger's will be honoured
+ // The old code below has been commented out.
+ // >> old: Set the trigger as free, until begin()/requeue. Only update state change no, when required
+ // >> old: if (!triggerExpr_->isFree()) freeTrigger();
+
+#ifdef DEBUG_DEPENDENCIES
+ LOG(Log::DBG," Node::evaluateTrigger() " << debugNodePath() << " FREE, TRIGGER AST evaluation succeeded" );
+#endif
+ return true;
+ }
+
+#ifdef DEBUG_DEPENDENCIES
+ LOG(Log::DBG," Node::evaluateTrigger() " << debugNodePath() << " HOLDING TRIGGER AST evaluation failed" );
+#endif
+ return false; // evaluation failed. this Node holds
+ }
+
+#ifdef DEBUG_DEPENDENCIES
+ LOG(Log::DBG," Node::evaluateTrigger() " << debugNodePath() << " FREE NO TRIGGER defined" );
+#endif
+ return true;
+}
+
+const std::string& Node::abortedReason() const { return Str::EMPTY(); }
+
+void Node::set_state(NState::State s, bool force, const std::string& additional_info_to_log)
+{
+ setStateOnly(s,false,additional_info_to_log);
+
+ // Handle any state change specific functionality. This will update any repeats
+ // This is a virtual function, since we want different behaviour during state change
+ handleStateChange();
+}
+
+void Node::setStateOnly(NState::State newState, bool force, const std::string& additional_info_to_log)
+{
+ Suite* theSuite = suite();
+ const Calendar& calendar = theSuite->calendar();
+
+#ifdef DEBUG_JOB_SUBMISSION_INTERVAL
+ // check sub submission interval/calendar increment for tasks only
+ // The job submission interval is set/obtained from the server environment and
+ // is configurable for testing.
+ // **** This is only used when jobSubmissionInterval is less than 60 ****
+ // We are attempting to refine job submission interval such that it is just
+ // greater than time taken for state change from submit->active->complete
+ // There by speeding up the test where we generate .ecf
+
+ // Ignore this during simulation, ie defs()->server().jobSubmissionInterval() = 0; for simulation
+ int jobSubmissionInterval = theSuite->defs()->server().jobSubmissionInterval();
+ if (isSubmittable() && jobSubmissionInterval != 0 && jobSubmissionInterval < 60) {
+
+ if (newState == NState::SUBMITTED) submit_to_complete_duration_ = Calendar::second_clock_time();
+ else if (newState == NState::COMPLETE && !submit_to_complete_duration_.is_special()) {
+
+ // Under HYBRID we can go from UNKNOWN->COMPLETE, missing out SUBMITTED
+ // hence: submit_to_complete_duration_ is never initialised
+ // ie when we have a,date,cron dependency that relies on a day change
+
+ time_duration td = (Calendar::second_clock_time() - submit_to_complete_duration_);
+ // cout << debugNodePath() << " submit->active->complete time = " << td.total_seconds() << " seconds.\n";
+
+ // Avoid this check if we have meters. as we wait a second between each meter update
+ if ( td.total_seconds() >= jobSubmissionInterval && ((!child_attrs_) || child_attrs_->meters().empty())) {
+
+ const Variable& do_check = theSuite->findVariable("CHECK_TASK_DURATION_LESS_THAN_SERVER_POLL");
+ if (!do_check.empty()) {
+ // cout << "Calendar::second_clock_time() = " << to_simple_string(Calendar::second_clock_time()) << "\n";
+ // cout << "submit_to_complete_duration_ = " << to_simple_string(submit_to_complete_duration_) << "\n";
+ // cout << "(Calendar::second_clock_time() - submit_to_complete_duration_) = " << to_simple_string(td) << "\n";
+ cout << "Testing::" << debugNodePath() << " For each job submission interval of " << jobSubmissionInterval
+ << " seconds, the calendar is increment by 60 seconds.\n"
+ << " The job submission interval is too small as it takes " << td.total_seconds()
+ << " seconds for state change of submit->active->complete, for an empty job.\n"
+ << " Please increase the job submission interval to at least " << (td.total_seconds() + 1) << " seconds.\n";
+ }
+ }
+ }
+ }
+#endif
+
+ // Change format is significant it is used in verification of log files
+ // Please change/update LogVerification::extractNodePathAndState() all verification relies on this one function
+ // " " + submitted(max) + ": " + path(estimate) + " try-no: " + try_no(estimate) + " reason: " + reason(estimate)
+ // reserve : 1 + 9 + 2 + 100 + 9 + 3 + 9 + 12 = 145
+ std::string log_state_change; log_state_change.reserve(145 + additional_info_to_log.size());
+ log_state_change += " ";
+ log_state_change += NState::toString(newState);
+ log_state_change += ": ";
+ log_state_change += absNodePath();
+ if (!additional_info_to_log.empty()) {
+ log_state_change += " ";
+ log_state_change += additional_info_to_log;
+ }
+
+ if ( newState == NState::ABORTED) {
+ if (force) flag().set(ecf::Flag::FORCE_ABORT);
+ Submittable* submittable = isSubmittable();
+ if ( submittable ) {
+ flag().set(ecf::Flag::TASK_ABORTED);
+ log_state_change += " try-no: ";
+ log_state_change += submittable->tryNo();
+ log_state_change += " reason: ";
+ log_state_change += abortedReason();
+ }
+ }
+ else {
+ flag().clear(ecf::Flag::TASK_ABORTED);
+ flag().clear(ecf::Flag::FORCE_ABORT);
+ }
+
+ // SUP-408 what does submitted mean in log?
+ // We want to mimimize calls to create a new time stamp in the log file.
+ // A time stamp is automatically created, whenever a *new* client request is received, & then cached
+ // However we can get a change in state, during tree traversal, when a node is free of its dependencies
+ // If we were to just log the message it would use the last cached time stamp. Giving misleading info:
+ // Since state changes are bubbled up, we need only update the time stamp for tasks, when not in a command
+ if (!CmdContext::in_command() && isTask() && Log::instance()) {
+ //std::cout << "!!!!! NOT in cmd context updating time stamp before logging\n";
+ Log::instance()->cache_time_stamp();
+ }
+
+ ecf::log(Log::LOG,log_state_change); // Note: log type, must be same for debug & release for test, i.e for log file verification
+
+ state_.first.setState(newState); // this will update state_change_no
+ state_.second = calendar.duration(); // record state change duration for late, autocancel,etc
+
+ // Record state changes for verification
+ if (misc_attrs_) {
+ size_t theSize = misc_attrs_->verifys_.size();
+ for(size_t i = 0; i < theSize; i++ ) {
+ if (misc_attrs_->verifys_[i].state() == newState) misc_attrs_->verifys_[i].incrementActual();
+ }
+ }
+}
+
+boost::posix_time::ptime Node::state_change_time() const
+{
+ const Calendar& calendar = suite()->calendar();
+ boost::posix_time::ptime the_state_change_time = calendar.begin_time();
+ the_state_change_time += state_.second; // state_.second is calendar duration relative to calendar begin_time
+ return the_state_change_time;
+}
+
+
+DState::State Node::dstate() const {
+
+ // ECFLOW-139, check for suspended must be done first
+ if (isSuspended()) return DState::SUSPENDED;
+
+ switch ( state() ) {
+ case NState::COMPLETE: return DState::COMPLETE; break;
+ case NState::ABORTED: return DState::ABORTED; break;
+ case NState::ACTIVE: return DState::ACTIVE; break;
+ case NState::SUBMITTED: return DState::SUBMITTED; break;
+ case NState::QUEUED: return DState::QUEUED; break;
+ case NState::UNKNOWN: return DState::UNKNOWN; break;
+ }
+ return DState::UNKNOWN;
+}
+
+bool Node::set_event( const std::string& event_name_or_number) {
+ if (child_attrs_) return child_attrs_->set_event(event_name_or_number);
+ return false;
+}
+bool Node::clear_event(const std::string& event_name_or_number ){
+ if (child_attrs_) return child_attrs_->clear_event(event_name_or_number);
+ return false;
+}
+
+void Node::setRepeatToLastValue()
+{
+ repeat_.setToLastValue(); // no op for empty repeat
+ repeat_.increment(); // make repeat invalid
+}
+
+bool Node::check_in_limit_up_node_tree() const
+{
+ if (!inLimitMgr_.inLimit()) return false;
+
+ Node* theParent = parent();
+ while (theParent) {
+ if (!theParent->inLimitMgr_.inLimit()) return false;
+ theParent = theParent->parent();
+ }
+ return true;
+}
+
+void Node::incrementInLimit(std::set<Limit*>& limitSet) const
+{
+ // cout << "Node::incrementInLimit " << absNodePath() << endl;
+ std::string the_abs_node_path = absNodePath();
+ inLimitMgr_.incrementInLimit(limitSet,the_abs_node_path);
+
+ Node* theParent = parent();
+ while (theParent) {
+ theParent->inLimitMgr_.incrementInLimit(limitSet,the_abs_node_path);
+ theParent = theParent->parent();
+ }
+}
+
+void Node::decrementInLimit(std::set<Limit*>& limitSet) const
+{
+ // cout << "Node::decrementInLimit " << absNodePath() << endl;
+ std::string the_abs_node_path = absNodePath();
+ inLimitMgr_.decrementInLimit(limitSet,the_abs_node_path);
+
+ Node* theParent = parent();
+ while (theParent) {
+ theParent->inLimitMgr_.decrementInLimit(limitSet,the_abs_node_path);
+ theParent = theParent->parent();
+ }
+}
+
+static bool search_user_edit_variables( const std::string& name, std::string& value, const NameValueMap& user_edit_variables )
+{
+ NameValueMap::const_iterator i = user_edit_variables.find(name);
+ if (i != user_edit_variables.end()) {
+ if (((*i).second).empty()) {
+ // when we call --edit_script submit file, before a job is submitted the values
+ // of generated variables like ECF_RID, ECF_TRYNO, ECF_NAME, ECF_PASS, ECF_JOB, ECF_JOBOUT, ECF_SCRIPT
+ // will be empty. In this case return false, so that we pick up the values from the node.
+ return false;
+ }
+ value = (*i).second;
+ return true;
+ }
+ return false;
+}
+
+//#define DEBUG_S 1
+bool Node::variableSubsitution(std::string& cmd) const
+{
+ char micro = '%';
+ std::string micro_char;
+ findParentUserVariableValue(Str::ECF_MICRO(),micro_char);
+ if (!micro_char.empty() && micro_char.size() == 1) {
+ micro = micro_char[0];
+ }
+
+ NameValueMap user_edit_variables;
+ return variable_substitution(cmd,user_edit_variables,micro);
+}
+
+bool Node::variable_substitution(std::string& cmd, const NameValueMap& user_edit_variables, char micro) const
+{
+ // scan the command for variables, and substitute
+ // edit cmd "/home/ma/map/sms/smsfectch -F %ECF_FILES% -I %ECF_INCLUDE%"
+ // We can also have
+ //
+ // "%<VAR>:<substitute>% i.e if VAR exist use it, else use substitute
+ //
+ // ************************************************************************************************************
+ // Special case handling for user variables, and generated variables, which take precedence over node variables
+ // ************************************************************************************************************
+ //
+ // i.e VAR is defined as BILL
+ // %VAR:fred --f% will either be "BILL" or if VAR is not defined "fred --f"
+ //
+ // Infinite recursion. Its possible to end up with infinite recursion:
+ // edit hello '%hello%' # string like %hello% will cause infinite recursion
+ // edit fred '%bill%'
+ // edit bill '%fred%' # should be 10
+ // To prevent this we will use a simple count
+#ifdef DEBUG_S
+ cout << "cmd = " << cmd << "\n";
+#endif
+ bool double_micro_found = false;
+ std::string::size_type pos = 0;
+ int count = 0;
+ while ( 1 ) {
+ // A while loop here is used to:
+ // a/ Allow for multiple substitution on a single line. i.e %ECF_FILES% -I %ECF_INCLUDE%"
+ // b/ Allow for recursive substitution. %fred% -> %bill%--> 10
+
+ size_t firstPercentPos = cmd.find( micro, pos );
+ if ( firstPercentPos == string::npos ) break;
+
+ size_t secondPercentPos = cmd.find( micro, firstPercentPos + 1 );
+ if ( secondPercentPos == string::npos ) break;
+
+ if ( secondPercentPos - firstPercentPos <= 1 ) {
+ // handle %% with no characters in between, skip over
+ // i.e to handle "printf %%02d %HOUR:00%" --> "printf %02d 00" i.e if HOUR not defined
+ pos = secondPercentPos + 1;
+ double_micro_found = true;
+ continue;
+ }
+ else pos = 0;
+
+ string percentVar( cmd.begin() + firstPercentPos+1, cmd.begin() + secondPercentPos );
+#ifdef DEBUG_S
+ cout << " Found percentVar " << percentVar << "\n";
+#endif
+
+
+ // ****************************************************************************************
+ // Look for generated variables first:
+ // Variable like ECF_PASS can be overridden, i.e. with FREE_JOBS_PASSWORD
+ // However for job file generation we should use use the generated variables first.
+ // if the user removes ECF_PASS then we are stuck with the wrong value in the script file
+ // FREE_JOBS_PASSWORD is left for the server to deal with
+ bool generated_variable = false;
+ if ( percentVar.find("ECF_") != std::string::npos) {
+ if ( percentVar.find(Str::ECF_PASS()) != std::string::npos) generated_variable = true;
+ else if ( percentVar.find(Str::ECF_TRYNO()) != std::string::npos) generated_variable = true;
+ else if ( percentVar.find(Str::ECF_JOB()) != std::string::npos) generated_variable = true;
+ else if ( percentVar.find(Str::ECF_JOBOUT()) != std::string::npos) generated_variable = true;
+ else if ( percentVar.find(Str::ECF_PORT()) != std::string::npos) generated_variable = true;
+ else if ( percentVar.find(Str::ECF_NODE()) != std::string::npos) generated_variable = true;
+ else if ( percentVar.find(Str::ECF_NAME()) != std::string::npos) generated_variable = true;
+ }
+
+ // First search user variable (*ONLY* set when doing user edit's the script)
+ // Handle case: cmd = "%fred:bill% and where we have user variable "fred:bill"
+ // Handle case: cmd = "%fred% and where we have user variable "fred"
+ // If we fail to find the variable we return false.
+ // Note: When a variable is found, it can have an empty value which is still valid
+ std::string varValue;
+ if (search_user_edit_variables(percentVar,varValue,user_edit_variables)) {
+ cmd.replace( firstPercentPos, secondPercentPos - firstPercentPos + 1, varValue );
+ }
+ else if (generated_variable && find_parent_gen_variable_value(percentVar,varValue)) {
+
+ cmd.replace( firstPercentPos, secondPercentPos - firstPercentPos + 1, varValue );
+ }
+ else if (findParentVariableValue( percentVar ,varValue)) {
+ // For alias we could have added variables with %A:0%, %A:1%. Aliases allow variables with ':' in the name
+ cmd.replace( firstPercentPos, secondPercentPos - firstPercentPos + 1, varValue );
+ }
+ else {
+
+ size_t firstColon = percentVar.find( ':' );
+ if (firstColon != string::npos) {
+
+ string var(percentVar.begin(), percentVar.begin() + firstColon);
+#ifdef DEBUG_S
+ cout << " var " << var << "\n";
+#endif
+
+ if (search_user_edit_variables(var,varValue,user_edit_variables)) {
+#ifdef DEBUG_S
+ cout << " user var value = " << varValue << "\n";
+#endif
+ cmd.replace(firstPercentPos,secondPercentPos-firstPercentPos+1,varValue);
+ }
+ else if (generated_variable && find_parent_gen_variable_value(var,varValue)) {
+#ifdef DEBUG_S
+ cout << " generated var value = " << varValue << "\n";
+#endif
+ cmd.replace( firstPercentPos, secondPercentPos - firstPercentPos + 1, varValue );
+ }
+ else if (findParentVariableValue( var, varValue )) {
+ // Note: variable can exist, but have an empty value
+#ifdef DEBUG_S
+ cout << " var value = " << varValue << "\n";
+#endif
+ // replace the "%VAR:fred --f%" with var
+ cmd.replace(firstPercentPos,secondPercentPos-firstPercentPos+1,varValue);
+ }
+ else {
+ string substitute (percentVar.begin()+ firstColon+1, percentVar.end());
+#ifdef DEBUG_S
+ cout << " substitute value = " << substitute << "\n";
+#endif
+ cmd.replace(firstPercentPos,secondPercentPos-firstPercentPos+1,substitute);
+ }
+#ifdef DEBUG_S
+ cout << " cmd = " << cmd << "\n";
+#endif
+ }
+ else {
+ // No Colon, Can't find in user variables, or node variable, hence can't go any further
+ return false;
+ }
+ }
+
+ // Simple Check for infinite recursion
+ if (count > 1000) return false;
+ count++;
+ }
+
+ if (double_micro_found) {
+ // replace all double micro with a single micro, this must be a single parse
+ // date +%%Y%%m%%d" ==> date +%Y%m%d
+ // %%%% ==> %% // i.e single parse
+ std::string doubleEcfMicro;
+ doubleEcfMicro += micro;
+ doubleEcfMicro += micro;
+ size_t last_pos = 0;
+ while ( 1 ) {
+ string::size_type ecf_double_micro_pos = cmd.find( doubleEcfMicro , last_pos);
+ if ( ecf_double_micro_pos != std::string::npos ) {
+ cmd.erase( cmd.begin() + ecf_double_micro_pos );
+ last_pos = ecf_double_micro_pos + 1;
+ }
+ else break;
+ }
+ }
+
+ return true;
+}
+
+bool Node::find_all_used_variables(std::string& cmd, NameValueMap& used_variables, char micro) const
+{
+#ifdef DEBUG_S
+ cout << "cmd = " << cmd << "\n";
+#endif
+ int count = 0;
+ while ( 1 ) {
+ // A while loop here is used to:
+ // a/ Allow for multiple substitution on a single line. i.e %ECF_FILES% -I %ECF_INCLUDE%"
+ // b/ Allow for recursive substitution. %fred% -> %bill%--> 10
+
+ size_t firstPercentPos = cmd.find( micro );
+ if ( firstPercentPos == string::npos ) break;
+ size_t secondPercentPos = cmd.find( micro, firstPercentPos + 1 );
+ if ( secondPercentPos == string::npos ) break;
+ if ( secondPercentPos - firstPercentPos <= 1 ) break; // handle %% with no characters in between
+
+
+ string percentVar( cmd.begin() + firstPercentPos+1, cmd.begin() + secondPercentPos );
+#ifdef DEBUG_S
+ cout << " Found percentVar " << percentVar << "\n";
+#endif
+
+ size_t firstColon = percentVar.find( ':' );
+ if (firstColon != string::npos) {
+
+ string var (percentVar.begin(), percentVar.begin() + firstColon);
+#ifdef DEBUG_S
+ cout << " var " << var << "\n";
+#endif
+
+ std::string varValue;
+ if (findParentVariableValue( var, varValue )) {
+ // Note: variable can exist, but have an empty value
+#ifdef DEBUG_S
+ cout << " var value = " << theFoundVariable.value() << "\n";
+#endif
+ // %VAR:fred% ---> name("VAR:fred") value(theFoundVariable.value())
+ used_variables.insert( std::make_pair(percentVar,varValue) );
+
+ // replace the "%VAR:fred --f%" with variable value, so that we dont process it again
+ cmd.replace(firstPercentPos,secondPercentPos-firstPercentPos+1,varValue);
+ }
+ else {
+ string substitute (percentVar.begin()+ firstColon+1, percentVar.end());
+#ifdef DEBUG_S
+ cout << " substitute value = " << substitute << "\n";
+#endif
+
+ // %VAR:fred% ---> name("VAR:fred") value(fred)
+ used_variables.insert( std::make_pair(percentVar,substitute));
+
+ cmd.replace(firstPercentPos,secondPercentPos-firstPercentPos+1,substitute);
+ }
+#ifdef DEBUG_S
+ cout << " cmd = " << cmd << "\n";
+#endif
+ }
+ else {
+
+ // If we fail to find the variable we return false.
+ // Note: When a variable is found, it can have an empty value
+ // which is still valid
+ std::string varValue;
+ if (!findParentVariableValue( percentVar ,varValue)) return false;
+
+ used_variables.insert( std::make_pair(percentVar,varValue) );
+ cmd.replace( firstPercentPos, secondPercentPos - firstPercentPos + 1, varValue );
+ }
+
+ // Simple Check for infinite recursion
+ if (count > 100) return false;
+ count++;
+ }
+ return true;
+}
+
+
+bool Node::variable_dollar_subsitution(std::string& cmd)
+{
+ // scan command for environment variables, and substitute
+ // edit ECF_INCLUDE $ECF_HOME/include
+
+ while ( 1 ) {
+ size_t firstPos = cmd.find( '$' );
+ if ( firstPos == string::npos ) break;
+
+ size_t secondPos = cmd.find_first_not_of( Str::ALPHANUMERIC_UNDERSCORE(), firstPos + 1 );
+ if ( secondPos == string::npos ) secondPos = cmd.size();
+ if ( secondPos - firstPos <= 1 ) break; // handle $/ with no characters in between
+
+ string env( cmd.begin() + firstPos+1, cmd.begin() + secondPos );
+ //cout << "find env " << env << "\n";
+
+ std::string envValue;
+ if (! findParentVariableValue( env,envValue )) {
+ //cout << " could not find " << env << "\n";
+ return false;
+ }
+
+ cmd.replace( firstPos, secondPos - firstPos , envValue );
+ }
+ return true;
+}
+
+
+std::string Node::completeExpression() const
+{
+ if (completeExpr_) {
+ string ret = "complete ";
+ ret += completeExpr_->expression();
+ return ret;
+ }
+ return string();
+}
+
+std::string Node::triggerExpression() const
+{
+ if (triggerExpr_) {
+ string ret = "trigger ";
+ ret += triggerExpr_->expression();
+ return ret;
+ }
+ return string();
+}
+
+
+static void check_expressions(const Node* node, bool trigger, std::string& errorMsg)
+{
+ Ast* ast = NULL;
+ if (trigger) ast = node->triggerAst();
+ else ast = node->completeAst();
+ if ( ast ) {
+ // The expression have been parsed and we have created the abstract syntax tree
+ // Try to resolve the path/node references in the expressions
+ // Also resolve references to events,meter,repeats variables.
+ AstResolveVisitor astVisitor(node);
+ ast->accept(astVisitor);
+
+ if ( !astVisitor.errorMsg().empty() ) {
+ errorMsg += "Expression node tree references failed for ";
+ if ( trigger ) errorMsg += node->triggerExpression();
+ else errorMsg += node->completeExpression();
+ errorMsg += "' at ";
+ errorMsg += node->absNodePath();
+ errorMsg += "\n ";
+ errorMsg += astVisitor.errorMsg();
+ }
+ }
+}
+
+bool Node::check(std::string& errorMsg, std::string& warningMsg) const
+{
+ //#ifdef DEBUG
+ // cout << "Node::check " << debugNodePath() << " complete and trigger\n";
+ //#endif
+
+ /// ************************************************************************************
+ /// *IMPORTANT side effec: *
+ /// The simulator relies AstResolveVisitor to set usedInTriggger() for events and meters
+ /// *************************************************************************************
+
+ /// Make Sure: To sure capture parser errors:
+ /// defs which fail parse errors should not be allowed to be loaded into the server
+ /// Even if the code parses, check the expression for divide by zero, for divide and modulo operators
+ AstTop* ctop = completeAst(errorMsg);
+ if (ctop && !ctop->check(errorMsg)) {
+ errorMsg += " ";
+ if (completeExpr_) errorMsg += completeExpr_->expression();
+ errorMsg += " on ";
+ errorMsg += debugNodePath();
+ }
+ AstTop* ttop = triggerAst(errorMsg);
+ if (ttop && !ttop->check(errorMsg)) {
+ errorMsg += " ";
+ if (triggerExpr_) errorMsg += triggerExpr_->expression();
+ errorMsg += " on ";
+ errorMsg += debugNodePath();
+ }
+
+
+ // capture node path resolve errors
+ check_expressions(this, true,errorMsg);
+ check_expressions(this, false,errorMsg);
+
+ // check inLimit references to limits.
+ // Client: Unresolved references, which are not in the externs reported as errors/warnings
+ // Server: There are no exerns, all unresolved references reported as errors
+ bool reportErrors = true;
+ bool reportWarnings = true;
+ inLimitMgr_.check(errorMsg,warningMsg,reportErrors, reportWarnings);
+
+ return errorMsg.empty();
+}
+
+std::string Node::write_state() const
+{
+ // *IMPORTANT* we *CANT* use ';' character, since is used in the parser, when we have
+ // multiple statement on a single line i.e.
+ // task a; task b;
+ // If attribute correspond to the defaults don't write then out
+ std::string ret;
+ if (state() != NState::UNKNOWN) {
+ ret += " state:";
+ ret += NState::toString(state());
+ }
+ if (state_.second.total_seconds() != 0) {
+ ret += " dur:";
+ ret += to_simple_string(state_.second);
+ }
+ if (flag_.flag() != 0) {
+ ret += " flag:";
+ ret += flag_.to_string();
+ }
+ if (suspended_) {
+ ret += " suspended:1";
+ }
+ return ret;
+}
+
+void Node::read_state(const std::string& line,const std::vector<std::string>& lineTokens)
+{
+ std::string token;
+ for(size_t i = 0; i < lineTokens.size(); i++) {
+ token.clear();
+ if (lineTokens[i].find("state:") != std::string::npos ) {
+ if (!Extract::split_get_second(lineTokens[i],token)) throw std::runtime_error( "Node::read_state Invalid state specified for suite " + name());
+ if (!NState::isValid(token)) throw std::runtime_error( "Node::read_state Invalid state specified for node : " + name() );
+ set_state_only(NState::toState(token));
+ }
+ else if (lineTokens[i].find("flag:") != std::string::npos ) {
+ if (!Extract::split_get_second(lineTokens[i],token)) throw std::runtime_error( "Node::read_state invalid flags for node " + name());
+ flag().set_flag(token); // this can throw
+ }
+ else if (lineTokens[i].find("dur:") != std::string::npos ) {
+ if (!Extract::split_get_second(lineTokens[i],token)) throw std::runtime_error( "Node::read_state invalid duration for node: " + name());
+ state_.second = duration_from_string(token);
+ }
+ else if (lineTokens[i] == "suspended:1") suspend();
+ }
+}
+
+std::ostream& Node::print(std::ostream& os) const
+{
+ if ( defStatus_ != DState::default_state() ) {
+ Indentor in;
+ Indentor::indent(os) << "defstatus " << DState::toString(defStatus_) << "\n";
+ }
+
+ if (lateAttr_) lateAttr_->print(os);
+
+ if (completeExpr_) {
+ completeExpr_-> print(os,"complete");
+ if ( PrintStyle::getStyle() == PrintStyle::STATE ) {
+ Indentor in;
+ if (completeExpr_->isFree()) Indentor::indent(os) << "# (free)\n";
+ if ( completeAst() ) {
+ if (!defs()) {
+ // Full defs is required for extern checking, and finding absolute node paths
+ // Hence print will with no defs can give in-accurate information
+ Indentor in;
+ Indentor::indent(os) << "# Warning: Full/correct AST evaluation requires the definition\n";
+ }
+ completeAst()->print(os);
+ }
+ }
+ }
+ if (triggerExpr_) {
+ triggerExpr_->print(os,"trigger");
+ if ( PrintStyle::getStyle() == PrintStyle::STATE ) {
+ Indentor in;
+ if (triggerExpr_->isFree()) Indentor::indent(os) << "# (free)\n";
+ if ( triggerAst() ) {
+ if (!defs()) {
+ Indentor in;
+ Indentor::indent(os) << "# Warning: Full/correct AST evaluation requires the definition\n";
+ }
+ triggerAst()->print(os);
+ }
+ }
+ }
+ repeat_.print(os);
+
+ BOOST_FOREACH(const Variable& v, varVec_ ) { v.print(os); }
+
+ if ( PrintStyle::getStyle() == PrintStyle::STATE ) {
+ // Distinguish normal variable from generated, by adding a #
+ // This also allows it be read in again and compared in the AParser/tests
+ std::vector<Variable> gvec;
+ gen_variables(gvec);
+ BOOST_FOREACH(const Variable& v, gvec ) { v.print_generated(os); }
+ }
+
+ BOOST_FOREACH(limit_ptr l, limitVec_) { l->print(os); }
+ inLimitMgr_.print(os);
+ if (child_attrs_) child_attrs_->print(os);
+ if (time_dep_attrs_) time_dep_attrs_->print(os);
+ if (misc_attrs_) misc_attrs_->print(os);
+ if (autoCancel_) autoCancel_->print(os);
+
+ return os;
+}
+
+std::string Node::to_string() const
+{
+ std::stringstream ss;
+ print(ss);
+ return ss.str();
+}
+
+bool Node::operator==(const Node& rhs) const
+{
+ if ( name_ != rhs.name_) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Node::operator==( name_(" << name_ << ") != rhs.name_(" << rhs.name_ << ")) for: " << debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ if ( state() != rhs.state()) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Node::operator== state(" << NState::toString(state()) << ") != rhs.state(" << NState::toString(rhs.state()) << ")) " << debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ if ( defStatus_ != rhs.defStatus_) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Node::operator== ( defStatus_ != rhs.defStatus_) " << debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ if ( suspended_ != rhs.suspended_) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Node::operator== suspended_ != rhs.suspended_ " << debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+
+ if ( flag_ != rhs.flag_) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Node::operator== ( flag_ != rhs.flag_) : '" << flag_.to_string() << "' != '" << rhs.flag_.to_string() << "' : " << debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+
+ if ( (triggerExpr_ && !rhs.triggerExpr_) || (!triggerExpr_ && rhs.triggerExpr_) ) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Node::operator== (triggerExpr_ && !rhs.triggerExpr_) || (!triggerExpr_&& rhs.triggerExpr_) " << debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ if ( triggerExpr_ && rhs.triggerExpr_ && (*triggerExpr_ != *rhs.triggerExpr_) ) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Node::operator== triggerExpr_ && rhs.triggerExpr_ && (*triggerExpr_ != *rhs.triggerExpr_) " << debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+
+ if ( (completeExpr_ && !rhs.completeExpr_) || (!completeExpr_ && rhs.completeExpr_) ) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Node::operator== (completeExpr_ && !rhs.completeExpr_) || (!completeExpr_&& rhs.completeExpr_) " << debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ if ( completeExpr_ && rhs.completeExpr_ && (*completeExpr_ != *rhs.completeExpr_) ) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Node::operator== completeExpr_ && rhs.completeExpr_ && (*completeExpr_ != *rhs.completeExpr_) " << debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+
+
+ if (varVec_.size() != rhs.varVec_.size()) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Node::operator== (varVec_.size() != rhs.varVec_.size()) " << debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ for(unsigned i = 0; i < varVec_.size(); ++i) {
+ if (!(varVec_[i] == rhs.varVec_[i] )) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Node::operator== (!(varVec_[i] == rhs.varVec_[i] )) " << debugNodePath() << "\n";
+ std::cout << " varVec_[i] name = '" << varVec_[i].name() << "' value = '" << varVec_[i].theValue() << "'\n";
+ std::cout << " rhs.varVec_[i] name = '" << rhs.varVec_[i].name() << "' value = '" << rhs.varVec_[i].theValue() << "'\n";
+ }
+#endif
+ return false;
+ }
+ }
+ // We dont compare genvar as this is only used in server environment
+
+ if (!(inLimitMgr_ == rhs.inLimitMgr_)) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Node::operator== (!(inLimitMgr == rhs.inLimitMgr)) " << debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+
+ if (limitVec_.size() != rhs.limitVec_.size()) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Node::operator== (limitVec_.size() != rhs.limitVec_.size()) " << debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ for(unsigned i = 0; i < limitVec_.size(); ++i) {
+ if (!(*limitVec_[i] == *rhs.limitVec_[i] )) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Node::operator== (!(*limitVec_[i] == *rhs.limitVec_[i] )) " << debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ }
+
+ if (( time_dep_attrs_ && !rhs.time_dep_attrs_) || ( !time_dep_attrs_ && rhs.time_dep_attrs_)){
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Node::operator== (( time_dep_attrs_ && !rhs.time_dep_attrs_) || ( !time_dep_attrs_ && rhs.time_dep_attrs_)) " << debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ if ( time_dep_attrs_ && rhs.time_dep_attrs_ && !(*time_dep_attrs_ == *rhs.time_dep_attrs_)) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Node::operator== ( time_dep_attrs_ && rhs.time_dep_attrs_ && !(*time_dep_attrs_ == *(rhs.time_dep_attrs_))) " << debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+
+ if (( child_attrs_ && !rhs.child_attrs_) || ( !child_attrs_ && rhs.child_attrs_)){
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Node::operator== (( child_attrs_ && !rhs.child_attrs_) || ( !child_attrs_ && rhs.child_attrs_)) " << debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ if ( child_attrs_ && rhs.child_attrs_ && !(*child_attrs_ == *rhs.child_attrs_)) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Node::operator== ( child_attrs_ && rhs.child_attrs_ && !(*child_attrs_ == *(rhs.child_attrs_))) " << debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+
+ if (( misc_attrs_ && !rhs.misc_attrs_) || ( !misc_attrs_ && rhs.misc_attrs_)){
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Node::operator== (( misc_attrs_ && !rhs.misc_attrs_) || ( !misc_attrs_ && rhs.misc_attrs_)) " << debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ if ( misc_attrs_ && rhs.misc_attrs_ && !(*misc_attrs_ == *rhs.misc_attrs_)) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Node::operator== ( misc_attrs_ && rhs.misc_attrs_ && !(*misc_attrs_ == *(rhs.misc_attrs_))) " << debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+
+ if (autoCancel_ && !rhs.autoCancel_) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Node::operator== if (autoCancel_ && !rhs.autoCancel_) " << debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ if (!autoCancel_ && rhs.autoCancel_) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Node::operator== if (!autoCancel_ && rhs.autoCancel_) " << debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ if (autoCancel_ && rhs.autoCancel_ && !(*autoCancel_ == *rhs.autoCancel_)) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Node::operator== (autoCancel_ && rhs.autoCancel_ && !(*autoCancel_ == *rhs.autoCancel_)) " << debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+
+
+ if (!(repeat_ == rhs.repeat_)) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Node::operator== if (!(repeat_ == rhs.repeat_)) " << debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+
+
+ if (( lateAttr_ && !rhs.lateAttr_) || ( !lateAttr_ && rhs.lateAttr_)){
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Node::operator== (( lateAttr_ && !rhs.lateAttr_) || ( !lateAttr_ && rhs.lateAttr_)) " << debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ if ( lateAttr_ && rhs.lateAttr_ && !(*lateAttr_ == *rhs.lateAttr_)) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Node::operator== ( lateAttr_ && rhs.lateAttr_ && !(*lateAttr_ == *(rhs.lateAttr_))) " << debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+
+ return true;
+}
+
+
+//#define DEBUG_WHY 1
+
+void Node::top_down_why(std::vector<std::string>& theReasonWhy) const
+{
+ why(theReasonWhy);
+}
+
+void Node::bottom_up_why(std::vector<std::string>& theReasonWhy) const
+{
+ defs()->why(theReasonWhy);
+
+ std::vector<Node*> vec;
+ vec.push_back(const_cast<Node*>(this));
+ Node* theParent = parent();
+ while (theParent) {
+ vec.push_back(theParent);
+ theParent = theParent->parent();
+ }
+ vector<Node*>::reverse_iterator r_end = vec.rend();
+ for(vector<Node*>::reverse_iterator r = vec.rbegin(); r!=r_end; ++r) {
+ (*r)->why(theReasonWhy);
+ }
+}
+
+void Node::why(std::vector<std::string>& vec) const
+{
+#ifdef DEBUG_WHY
+ std::cout << "Node::why " << debugNodePath() << " (" << NState::toString(state()) << ")\n";
+#endif
+ if (isSuspended()) {
+ std::string theReasonWhy = "The node '";
+ theReasonWhy += debugNodePath();
+ theReasonWhy += "' is suspended.";
+ vec.push_back(theReasonWhy);
+ }
+ else if (state() != NState::QUEUED && state() != NState::ABORTED) {
+ std::stringstream ss;
+ ss << "The node '" << debugNodePath() << "' (" << NState::toString(state()) << ") is not queued or aborted.";
+ vec.push_back(ss.str());
+
+ // When task is active/submitted no point, going any further.
+ // However for FAMILY/SUITE we still need to proceed
+ if (isTask()) return;
+ }
+
+ // Check limits using in limit manager
+ inLimitMgr_.why(vec);
+
+ // Prefix <node-type> <path> <state>
+ std::string prefix = debugType();
+ prefix += " ";
+ prefix += absNodePath();
+ prefix += " (";
+ prefix += NState::toString(state());
+ prefix += ") ";
+
+ if (time_dep_attrs_) {
+#ifdef DEBUG_WHY
+ std::cout << " Node::why " << debugNodePath() << " checking time dependencies\n";
+#endif
+ // postfix = <attr-type dependent> <next run time > < optional current state>
+ time_dep_attrs_->why(vec,prefix);
+ }
+
+ // **************************************************************************************
+ // If we have a complete expression that does not evaluate then it should *NOT* hold the node.
+ // The complete expression is used to set node to complete, when it evaluates and hence
+ // should not prevent further tree walking. evaluate each leaf branch
+ // **************************************************************************************
+ AstTop* theTriggerAst = triggerAst();
+ if (theTriggerAst) {
+ // Note 1: A trigger can be freed by the ForceCmd
+ // Note 2: if we have a non NULL trigger ast, we must have trigger expression
+ // Note 3: The freed state is stored on the expression ( i.e *NOT* on the ast (abstract syntax tree) )
+ if (!triggerExpr_->isFree() ) {
+
+#ifdef DEBUG_WHY
+ std::cout << " Node::why " << debugNodePath() << " checking trigger dependencies\n";
+#endif
+ std::string postFix;
+ if (theTriggerAst->why(postFix)) { vec.push_back(prefix + postFix); }
+ }
+ }
+}
+
+bool Node::checkInvariants(std::string& errorMsg) const
+{
+ if (time_dep_attrs_) {
+ if (!time_dep_attrs_->checkInvariants(errorMsg)) {
+ return false;
+ }
+ }
+ if (!repeat_.empty()) {
+ if (repeat_.name().empty()) {
+ errorMsg += "Repeat name empty ???";
+ return false;
+ }
+ }
+ return true;
+}
+
+std::string Node::absNodePath() const
+{
+ std::vector<std::string> vec; vec.reserve(Str::reserve_16());
+ vec.push_back(name());
+ Node* theParent = parent();
+ while (theParent) {
+ vec.push_back(theParent->name());
+ theParent = theParent->parent();
+ }
+ std::string ret; ret.reserve(Str::reserve_64());
+ vector<string>::reverse_iterator r_end = vec.rend();
+ for(vector<string>::reverse_iterator r = vec.rbegin(); r!=r_end; ++r) {
+ ret += '/';
+ ret += *r;
+ }
+
+ // // Another algorithm broadly similar results
+ // std::string ret; ret.reserve(Str::reserve_64());
+ // ret += '/';
+ // ret += name();
+ // Node* theParent = parent();
+ // while (theParent) {
+ // ret.insert(0,"/");
+ // ret.insert(1,theParent->name());
+ // theParent = theParent->parent();
+ // }
+
+ return ret;
+}
+
+std::string Node::debugNodePath() const
+{
+ std::string ret = debugType();
+ ret += Str::COLON();
+ ret += absNodePath();
+ return ret;
+}
+
+void Node::verification(std::string& errorMsg) const
+{
+ if (misc_attrs_) misc_attrs_->verification(errorMsg);
+}
+
+void Node::getAllAstNodes(std::set<Node*>& theSet) const
+{
+ if ( completeAst() ) {
+ AstCollateNodesVisitor astVisitor(theSet);
+ completeAst()->accept(astVisitor);
+ }
+ if ( triggerAst() ) {
+ AstCollateNodesVisitor astVisitor(theSet);
+ triggerAst()->accept(astVisitor);
+ }
+}
+
+AstTop* Node::completeAst() const
+{
+ if (completeExpr_) {
+ std::string ignoredErrorMsg;
+ (void) completeAst(ignoredErrorMsg);
+ return completeExpr_->get_ast();
+ }
+ return NULL;
+}
+
+AstTop* Node::triggerAst() const
+{
+ if (triggerExpr_) {
+ std::string ignoredErrorMsg;
+ (void) triggerAst(ignoredErrorMsg);
+ return triggerExpr_->get_ast();
+ }
+ return NULL;
+}
+
+AstTop* Node::completeAst(std::string& errorMsg) const
+{
+ if (completeExpr_ && completeExpr_->get_ast() == NULL) {
+ completeExpr_->createAST(const_cast<Node*>(this),"complete",errorMsg);
+#ifdef DEBUG
+ if (errorMsg.empty()) LOG_ASSERT(completeExpr_->get_ast(),"");
+#endif
+ return completeExpr_->get_ast();
+ }
+ return NULL;
+}
+
+AstTop* Node::triggerAst(std::string& errorMsg) const
+{
+ if (triggerExpr_ && triggerExpr_->get_ast() == NULL) {
+ triggerExpr_->createAST(const_cast<Node*>(this),"trigger",errorMsg);
+#ifdef DEBUG
+ if (errorMsg.empty()) LOG_ASSERT(triggerExpr_->get_ast(),"");
+#endif
+ return triggerExpr_->get_ast();
+ }
+ return NULL;
+}
+
+node_ptr Node::remove()
+{
+ SuiteChanged0 changed(shared_from_this());
+
+ Node* theParent = parent();
+ if ( theParent ) return theParent->removeChild( this );
+ return defs()->removeChild( this );
+}
+
+bool Node::getLabelValue(const std::string& labelName, std::string& value) const
+{
+ if (child_attrs_) return child_attrs_->getLabelValue(labelName,value);
+ return false;
+}
+
+bool Node::getLabelNewValue(const std::string& labelName, std::string& value) const
+{
+ if (child_attrs_) return child_attrs_->getLabelNewValue(labelName,value);
+ return false;
+}
+
+size_t Node::position() const
+{
+ Node* theParent = parent();
+ if (theParent) {
+ return theParent->child_position(this);
+ }
+ else {
+ Defs* theDefs = defs();
+ if (theDefs) {
+ return theDefs->child_position(this);
+ }
+ }
+ return std::numeric_limits<std::size_t>::max();
+}
+
+
+void Node::gen_variables(std::vector<Variable>& vec) const
+{
+ if (!repeat_.empty()) {
+ vec.push_back(repeat_.gen_variable());
+ }
+}
+
+const Variable& Node::findGenVariable(const std::string& name) const
+{
+ if (!repeat_.empty() && repeat_.name() == name) return repeat_.gen_variable();
+ return Variable::EMPTY();
+}
+
+void Node::update_repeat_genvar() const
+{
+ if (!repeat_.empty()) {
+ repeat_.update_repeat_genvar();
+ }
+}
+
+void Node::notify_delete()
+{
+ // make a copy, to avoid iterating over observer list that is being changed
+ std::vector<AbstractObserver*> copy_of_observers = observers_;
+ for(size_t i = 0; i < copy_of_observers.size(); i++) {
+ copy_of_observers[i]->update_delete(this);
+ }
+
+ /// Check to make sure that the Observer called detach
+ /// We can not call detach ourselves, since the the client needs to
+ /// call detach in the case where the graphical tree is destroyed by user
+ /// In this case the Subject/Node is being deleted.
+ assert(observers_.empty());
+
+#ifdef DEBUG_NODE
+ if (!observers_.empty()) {
+ /// Its not safe to call debugNodePath()/absNodePath() since that will traverse the parent
+ /// This may not be safe during a delete.
+ std::cout << "notify_delete : Node is not observed : " << name() << "\n";
+ }
+#endif
+}
+
+void Node::notify(const std::vector<ecf::Aspect::Type>& aspects)
+{
+ for(size_t i = 0; i < observers_.size(); i++) {
+ observers_[i]->update(this,aspects);
+ }
+}
+
+void Node::attach(AbstractObserver* obs)
+{
+ observers_.push_back(obs);
+}
+
+void Node::detach(AbstractObserver* obs)
+{
+ for(size_t i = 0; i < observers_.size(); i++) {
+ if (observers_[i] == obs) {
+ observers_.erase( observers_.begin() + i) ;
+ return;
+ }
+ }
+}
+
+
+static std::vector<ecf::TimeAttr> timeVec_;
+static std::vector<ecf::TodayAttr> todayVec_;
+static std::vector<DateAttr> dates_;
+static std::vector<DayAttr> days_;
+static std::vector<ecf::CronAttr> crons_;
+const std::vector<ecf::TimeAttr>& Node::timeVec() const { if (time_dep_attrs_) return time_dep_attrs_->timeVec(); return timeVec_; }
+const std::vector<ecf::TodayAttr>& Node::todayVec() const { if (time_dep_attrs_) return time_dep_attrs_->todayVec();return todayVec_; }
+const std::vector<DateAttr>& Node::dates() const { if (time_dep_attrs_) return time_dep_attrs_->dates(); return dates_; }
+const std::vector<DayAttr>& Node::days() const { if (time_dep_attrs_) return time_dep_attrs_->days(); return days_; }
+const std::vector<ecf::CronAttr>& Node::crons() const { if (time_dep_attrs_) return time_dep_attrs_->crons(); return crons_; }
+std::vector<ecf::TimeAttr>::const_iterator Node::time_begin() const { if (time_dep_attrs_) return time_dep_attrs_->time_begin(); return timeVec_.begin();}
+std::vector<ecf::TimeAttr>::const_iterator Node::time_end() const { if (time_dep_attrs_) return time_dep_attrs_->time_end(); return timeVec_.end();}
+std::vector<ecf::TodayAttr>::const_iterator Node::today_begin() const { if (time_dep_attrs_) return time_dep_attrs_->today_begin(); return todayVec_.begin();}
+std::vector<ecf::TodayAttr>::const_iterator Node::today_end() const { if (time_dep_attrs_) return time_dep_attrs_->today_end(); return todayVec_.end();}
+std::vector<DateAttr>::const_iterator Node::date_begin() const { if (time_dep_attrs_) return time_dep_attrs_->date_begin(); return dates_.begin();}
+std::vector<DateAttr>::const_iterator Node::date_end() const { if (time_dep_attrs_) return time_dep_attrs_->date_end(); return dates_.end();}
+std::vector<DayAttr>::const_iterator Node::day_begin() const { if (time_dep_attrs_) return time_dep_attrs_->day_begin(); return days_.begin();}
+std::vector<DayAttr>::const_iterator Node::day_end() const { if (time_dep_attrs_) return time_dep_attrs_->day_end(); return days_.end();}
+std::vector<ecf::CronAttr>::const_iterator Node::cron_begin() const { if (time_dep_attrs_) return time_dep_attrs_->cron_begin(); return crons_.begin();}
+std::vector<ecf::CronAttr>::const_iterator Node::cron_end() const { if (time_dep_attrs_) return time_dep_attrs_->cron_end(); return crons_.end();}
+
+static std::vector<Meter> meters_;
+static std::vector<Event> events_;
+static std::vector<Label> labels_;
+const std::vector<Meter>& Node::meters() const { if (child_attrs_) return child_attrs_->meters(); return meters_;}
+const std::vector<Event>& Node::events() const { if (child_attrs_) return child_attrs_->events(); return events_;}
+const std::vector<Label>& Node::labels() const { if (child_attrs_) return child_attrs_->labels(); return labels_;}
+std::vector<Meter>& Node::ref_meters() { if (child_attrs_) return child_attrs_->ref_meters(); return meters_;} // allow simulator set meter value
+std::vector<Event>& Node::ref_events() { if (child_attrs_) return child_attrs_->ref_events(); return events_;} // allow simulator set event value
+std::vector<Meter>::const_iterator Node::meter_begin() const { if (child_attrs_) return child_attrs_->meter_begin(); return meters_.begin();}
+std::vector<Meter>::const_iterator Node::meter_end() const { if (child_attrs_) return child_attrs_->meter_end(); return meters_.end();}
+std::vector<Event>::const_iterator Node::event_begin() const { if (child_attrs_) return child_attrs_->event_begin(); return events_.begin();}
+std::vector<Event>::const_iterator Node::event_end() const { if (child_attrs_) return child_attrs_->event_end(); return events_.end();}
+std::vector<Label>::const_iterator Node::label_begin() const { if (child_attrs_) return child_attrs_->label_begin(); return labels_.begin();}
+std::vector<Label>::const_iterator Node::label_end() const { if (child_attrs_) return child_attrs_->label_end(); return labels_.end();}
+
+static std::vector<VerifyAttr> verifys_;
+static std::vector<ZombieAttr> zombies_;
+const std::vector<VerifyAttr>& Node::verifys() const { if (misc_attrs_) return misc_attrs_->verifys(); return verifys_;}
+const std::vector<ZombieAttr>& Node::zombies() const { if (misc_attrs_) return misc_attrs_->zombies(); return zombies_; }
+std::vector<ZombieAttr>::const_iterator Node::zombie_begin() const { if (misc_attrs_) return misc_attrs_->zombie_begin(); return zombies_.begin();}
+std::vector<ZombieAttr>::const_iterator Node::zombie_end() const { if (misc_attrs_) return misc_attrs_->zombie_end(); return zombies_.end();}
+std::vector<VerifyAttr>::const_iterator Node::verify_begin() const { if (misc_attrs_) return misc_attrs_->verify_begin(); return verifys_.begin();}
+std::vector<VerifyAttr>::const_iterator Node::verify_end() const { if (misc_attrs_) return misc_attrs_->verify_end(); return verifys_.end();}
diff --git a/ANode/src/Node.hpp b/ANode/src/Node.hpp
new file mode 100644
index 0000000..79f6053
--- /dev/null
+++ b/ANode/src/Node.hpp
@@ -0,0 +1,764 @@
+#ifndef NODE_HPP_
+#define NODE_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #251 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//
+// Node: The node class does NOT serialise the triggers and complete.
+// These are created on demand in the server.
+// However when the client code loads the definition file, the Defs::check
+// will create AST for trigger and complete expressions.
+// Because:
+// 1/ the AST are created, so that any parser errors can be _reported_ to the user
+// 2/ References in the AST expressions are resolved, and errors flagged.
+// This information could have been saved, however was _not_.
+// Because:
+// 1/ problems on AIX
+// 2/ Cut down on IPC load between client/server
+//
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <ostream>
+#include <set>
+#include <limits>
+
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/serialization/base_object.hpp>
+#include <boost/serialization/utility.hpp>
+#include <boost/serialization/vector.hpp> // no need to include <vector>
+#include <boost/serialization/string.hpp> // no need to include <string>
+#include <boost/serialization/shared_ptr.hpp> // no need to include shared_ptr
+#include <boost/foreach.hpp> // used so often just placed here for convenience
+
+#include "DState.hpp"
+#include "NOrder.hpp"
+#include "NodeAttr.hpp"
+#include "Limit.hpp"
+#include "InLimit.hpp"
+#include "Variable.hpp"
+#include "LateAttr.hpp"
+#include "RepeatAttr.hpp"
+#include "AutoCancelAttr.hpp"
+#include "Expression.hpp"
+#include "InLimitMgr.hpp"
+#include "TimeDepAttrs.hpp"
+#include "ChildAttrs.hpp"
+#include "MiscAttrs.hpp"
+#include "NodeFwd.hpp"
+#include "Flag.hpp"
+#include "Aspect.hpp"
+
+class AbstractObserver;
+namespace ecf { class Simulator; class SimulatorVisitor; class DefsAnalyserVisitor; class FlatAnalyserVisitor; } // forward declare for friendship
+namespace ecf { class Calendar; class NodeTreeVisitor; } // forward declare class
+
+class Node : public boost::enable_shared_from_this<Node>, private boost::noncopyable {
+protected:
+ Node(const std::string& name);
+ Node();
+public:
+ virtual ~Node();
+
+ /// The Parent Must set the parent pointer. For a Suite however this will be NULL
+ void set_parent(Node* p) { parent_ = p; }
+
+ // Server called functions:
+ /// Required when we have time attributes, when time related attribute are free they stay free
+ virtual void calendarChanged(const ecf::Calendar&, std::vector<node_ptr>& auto_cancelled_nodes,const ecf::LateAttr* inherited_late);
+
+ /// resolving dependencies means we look at day,date,time and triggers and check to
+ /// to see if a node is free or still holding. When a node if free of its dependencies and limits
+ /// Its state is changed to submitted. When a task is in a the submitted state its
+ /// associated ecf file can be submitted.
+ /// ************************************************************************************
+ /// There is no point in resolving child dependencies if the parent is not FREE
+ // We will return a bool, true means we are free, false for holding
+ // *************************************************************************************
+ virtual bool resolveDependencies(JobsParam& jobsParam);
+
+ /// Command related functions:
+ /// suspend generation of jobs. Below this node.
+ /// Note: When a node is suspended. time/date dependencies are still handled
+ /// A node which is free of time is marked.
+ /// Note: suspended is *NOT* a node state. It just an *attribute*. NState::State
+ /// represents all the life cycle change a Node can go through. Suspended does
+ /// not real fit into this and has been separated out.
+ bool isSuspended() const { return suspended_; }
+ bool isParentSuspended() const;
+ void suspend();
+
+ /// resume generation of jobs, and kick of an immediate job generation
+ /// If not previously suspended does nothing
+ void resume();
+
+ /// Kill the task if it is active. For NodeContainers do it hierarchically
+ /// will throw std::runtime_error for any errors
+ virtual void kill(const std::string& zombie_pid = "") = 0;
+
+ /// Show status of a node. For NodeContainers do it hierarchically
+ /// will throw std::runtime_error for any errors
+ virtual void status() = 0;
+
+ /// Order the node using the second parameter
+ virtual void order(Node*/*immediateChild*/, NOrder::Order) {}
+
+ /// For suites it allows dependencies to be resolved, and changes state to defStatus
+ virtual void begin();
+
+ /// re queue this node. States are reset to defStatus
+ /// Typically resetRepeats is set to true, when called from user command
+ /// or when re-queue is called from NodeContainer/parent
+ ///
+ /// With user interaction : we need to clear the suspended state for *child* nodes
+ /// To distinguish between child and parent, we use a integer 'level'
+ /// This was done so that if user had suspended a task deep in the hierarchy. (which is then
+ /// not displayed in the GUI), and then chooses to re-queue at a *high* level,
+ /// we need to clear child suspended state.(Principle of least surprise)
+ /// However we will preserve def status.
+ /// If a user re-queues a node that is suspended then it stays suspended
+ /// We use -1 to mean leave suspended state as is
+ ///
+ /// When the user issues force-complete or run interactive commands, we want to miss
+ /// the next-time slot. (i.e to avoid running the job again).
+ /// This is done by using NO_REQUE_IF_SINGLE_TIME_DEP flag.
+ /// The flag remain set until we get to *this* function. We use it to avoid
+ /// resetting the time slots, effectively missing the next time slot. we then clear the flag.
+ /// However if the JOB *abort* we clear NO_REQUE_IF_SINGLE_TIME_DEP
+ /// Otherwise if we run again, we miss additional time slots necessarily
+ virtual void requeue(bool resetRepeats,
+ int clear_suspended_in_child_nodes,
+ bool reset_next_time_slot);
+
+ /// Re queue the time based attributes only.
+ /// Used as a part of Alter (clock) functionality.
+ /// Note: Under the hybrid clock this will not mark node as complete, (if we have day,date,cron attributes)
+ /// Since alter clock, should not change node state. This is left for user to re-queue the suite
+ virtual void requeue_time_attrs();
+
+ /// Previously < 4.0.6 requeue always reset the labels on requeue.
+ /// However ECFLOW-195 suggest some user prefer to see the last label value.
+ /// hence we will only reset the labels on the tasks when task is being run.
+ void requeue_labels();
+
+ /// This functionality is only required during interactive force or run
+ /// Avoid running the task on the same time slot, by missing the next time slot.
+ /// Requires we set a flag, to avoid the requeue resetting the time slots
+ void miss_next_time_slot();
+
+ /// Recursively run the tasks under this node, ignore suspend,limits,triggers, and time dependencies
+ /// if force is set, run even if task is submitted or active. (will create zombies)
+ virtual bool run(JobsParam& jobsParam, bool force) = 0;
+
+ /// Recursively determines why the node is not running.
+ virtual void top_down_why(std::vector<std::string>& theReasonWhy) const;
+ void bottom_up_why(std::vector<std::string>& theReasonWhy) const;
+
+ void freeTrigger() const;
+ void clearTrigger() const;
+ void freeComplete() const;
+ void clearComplete() const;
+ void freeHoldingDateDependencies();
+ void freeHoldingTimeDependencies();
+
+ // Used in the force cmd
+ bool set_event( const std::string& event_name_or_number);
+ bool clear_event( const std::string& event_name_or_number);
+ void setRepeatToLastValue();
+ virtual void setRepeatToLastValueHierarchically() { setRepeatToLastValue(); }
+
+ /// find all %VAR% and replaces with variable values, returns false on the
+ /// first variable that can't be found, cmd will be left half processed.
+ /// Will search for ECF_MICRO, if not found assumes % as the micro char
+ bool variableSubsitution(std::string& cmd) const;
+
+ bool variable_substitution(std::string& cmd, const NameValueMap& user_edit_variables, char micro = '%') const;
+
+ /// Find all %VAR% and add to the list, there can be more than one. i.e %ECF_FILES% -I %ECF_INCLUDE%"
+ bool find_all_used_variables(std::string& cmd, NameValueMap& used_variables, char micro = '%') const;
+
+ /// Find all environment variables, in the input string and substitute.
+ /// with correspondingly named variable value.
+ /// i.e search for ${ENV} and replace
+ bool variable_dollar_subsitution(std::string& cmd);
+
+ /// Resolve inlimit references to limits, and check trigger and complete expression
+ virtual bool check(std::string& errorMsg,std::string& warningMsg) const;
+
+ /// Generated variables. Suites can have thousands of tasks. If the generated variables associated with
+ /// tasks are sent to the client, it can amount to a very large network traffic.
+ /// To minimise this bandwidth the generated variables for tasks/families are not persisted.
+ /// However client can demand create the generated variable by calling this function.
+ virtual void update_generated_variables() const = 0;
+
+ /// generates job file independent of dependencies
+ virtual void check_job_creation( job_creation_ctrl_ptr jobCtrl) = 0;
+
+ node_ptr remove(); // gets the parent then calls removeChild
+ virtual node_ptr removeChild( Node* child) = 0;
+ virtual bool addChild( node_ptr child,size_t position = std::numeric_limits<std::size_t>::max()) = 0; // return false if child of same name exist, leak!!!
+ virtual bool isAddChildOk( Node* child, std::string& errorMsg) const = 0; // return false if child of same name
+
+ virtual void verification(std::string& errorMsg) const;
+
+ /// See defs.hpp
+ virtual void generate_scripts( const std::map<std::string,std::string>& override) const = 0;
+
+ // standard functions: ==============================================
+ virtual std::ostream& print(std::ostream&) const;
+ bool operator==(const Node& rhs) const;
+ virtual bool checkInvariants(std::string& errorMsg) const;
+
+ /// Implements the visitor pattren
+ virtual void accept(ecf::NodeTreeVisitor&) = 0;
+ virtual void acceptVisitTraversor(ecf::NodeTreeVisitor&) = 0; // Visitor does the traversal
+
+// state related functions: ========================================
+
+ /// If the task was aborted provide the reason, default returns empty string
+ /// Only the task will return the reason for abort.
+ virtual const std::string& abortedReason() const;
+
+ /// This state added as an convenience, it includes Suspended attribute returned as enum
+ DState:: State dstate() const;
+
+ /// This represents the persisted/saved state // First = NState, Second = time_duration
+ /// The State represent the life cycle changes of a node.
+ NState::State state() const { return state_.first.state(); }
+
+ /// return the state and duration time(relative to when suite was begun) when the state change happened
+ std::pair<NState,boost::posix_time::time_duration> get_state() const { return state_;}
+
+ /// Set the state, this can have side affects. To handle state changes
+ /// Should family triggers use saved state, or computed state.
+ /// *** If we use computed state, this may be wrong, since computed state
+ /// *** does not take repeats, or time dependencies into account
+ /// *** Hence after each state change, we bubble up node tree, work out if
+ /// *** Node is free of repeat, and time dependencies,
+ /// ** Every time we set the state on a nodecontainer, we call handleStateChange
+ /// ** This by default works out the most significant state of the children
+ /// ** ie. the computed state. Hence setting the state on Suite/Family is really
+ /// ** meaningless, since it will always be the computed state.
+ void set_state(NState::State s, bool force = false, const std::string& additional_info_to_log = "");
+ virtual void set_state_hierarchically(NState::State s, bool force) { set_state(s,force); }
+
+ /// Set state only, has no side effects
+ void setStateOnly(NState::State s, bool force = false, const std::string& additional_info_to_log = "");
+ virtual void setStateOnlyHierarchically(NState::State s, bool force = false) { setStateOnly(s,force); }
+
+ /// This returns the time of state change: (relative to real time when the suite calendar was begun)
+ /// The returned time is *real time/computer UTC time* and *not* suite real time.
+ boost::posix_time::ptime state_change_time() const;
+
+ /// Sets the default status the node should have when the begin/re-queue is called
+ /// *Distinguish* between adding a def status and changing it.
+ /// Changing via defStatus_.setState(s); should alter state_change_no
+ void addDefStatus(DState::State s ) { defStatus_ = DState(s); }
+ DState::State defStatus() const { return defStatus_.state(); }
+
+ // Query functions: =========================================================
+ /// returns my parent, for suite will return NULL;
+ Node* parent() const { return parent_;}
+ virtual Suite* suite() const = 0;
+ virtual Defs* defs() const = 0;
+
+ // Performance hack, to avoid casts
+ virtual Task* isTask() const { return NULL;}
+ virtual Alias* isAlias() const { return NULL;}
+ virtual Submittable* isSubmittable() const { return NULL;}
+ virtual NodeContainer* isNodeContainer() const { return NULL;}
+ virtual Family* isFamily() const { return NULL;}
+ virtual Suite* isSuite() const { return NULL;}
+
+ /// returns the absolute node path
+ std::string absNodePath() const;
+ virtual const std::string& debugType() const = 0;
+
+ /// returns abs node path preceded by the type of the node
+ std::string debugNodePath() const;
+
+ /// returns true if this node OR any of its children
+ /// has cron,time,day,date or today time dependencies
+ virtual bool hasTimeDependencies() const { return (time_dep_attrs_) ? true : false; }
+ bool isTimeFree() const { return (time_dep_attrs_) ? time_dep_attrs_->timeDependenciesFree() : false;}
+
+
+ /// A hierarchical function
+ virtual bool hasAutoCancel() const { return (autoCancel_) ? true : false;}
+
+
+ // Access functions: ======================================================
+ const std::string& name() const { return name_; }
+ std::string toString() const { return name_; } // keep ecflowview/ecf_node.h happy
+ const Repeat& repeat() const { return repeat_;} // can be empty()
+ const std::vector<Variable>& variables()const { return varVec_;}
+ const std::vector<limit_ptr>& limits() const { return limitVec_;}
+ const std::vector<InLimit>& inlimits() const { return inLimitMgr_.inlimits(); }
+ const std::vector<Meter>& meters() const;
+ const std::vector<Event>& events() const;
+ const std::vector<Label>& labels() const;
+ const std::vector<ecf::TimeAttr>& timeVec() const;
+ const std::vector<ecf::TodayAttr>& todayVec() const;
+ const std::vector<DateAttr>& dates() const;
+ const std::vector<DayAttr>& days() const;
+ const std::vector<ecf::CronAttr>& crons() const;
+ const std::vector<VerifyAttr>& verifys() const;
+ const std::vector<ZombieAttr>& zombies() const;
+ TimeDepAttrs* get_time_dep_attrs() const { return time_dep_attrs_;} // can be NULL
+ ecf::LateAttr* get_late() const { return lateAttr_;}
+ ecf::AutoCancelAttr* get_autocancel() const { return autoCancel_;}
+ ecf::Flag& flag() { return flag_;}
+ const ecf::Flag& get_flag() const { return flag_;}
+
+ virtual void gen_variables(std::vector<Variable>&) const;
+ bool getLabelValue(const std::string& name, std::string& value) const;
+ bool getLabelNewValue(const std::string& name, std::string& value) const;
+
+ // Use get_trigger()/get_complete() for determining if we have trigger
+ // and complete expressions. This is many times faster than calling
+ // triggerAst()/completeAst() as this will force a parse and construction
+ // of Abstract syntax tree, first time it is called.
+ Expression* get_trigger() const { return triggerExpr_;}
+ Expression* get_complete() const { return completeExpr_;}
+ AstTop* completeAst() const; // Will create AST on demand
+ AstTop* triggerAst() const; // Will create AST on demand
+ std::string completeExpression() const;
+ std::string triggerExpression() const;
+
+ virtual void get_all_tasks(std::vector<task_ptr>&) const = 0;
+ virtual void get_all_nodes(std::vector<node_ptr>&) const = 0;
+ virtual void get_all_aliases(std::vector<alias_ptr>&) const = 0;
+ virtual void getAllTasks(std::vector<Task*>&) const = 0;
+ virtual void getAllSubmittables(std::vector<Submittable*>&) const = 0;
+ virtual void get_all_active_submittables(std::vector<Submittable*>&) const = 0;
+ virtual void getAllNodes(std::vector<Node*>&) const = 0;
+ virtual void getAllAstNodes(std::set<Node*>&) const;
+
+ /// returns the immediate children
+ virtual void immediateChildren(std::vector<node_ptr>&) const {}
+
+ /// retrieve _ALL_ children by hierarchically traversing down the node tree
+ virtual void allChildren(std::set<Node*>&) const {}
+
+ // Add functions: ===============================================================
+ void addVerify( const VerifyAttr& ); // for testing and verification Can throw std::runtime_error
+ void addVariable(const Variable& ); // will throw std::runtime_error if duplicate
+ void add_variable(const std::string& name, const std::string& value );// will write to std:out if duplicates
+ void add_variable_int(const std::string& name, int);// will throw std::runtime_error if duplicate
+
+ void add_trigger(const std::string&); // use for short complete expressions,Can throw std::runtime_error
+ void add_complete(const std::string&); // use for short complete expressions,Can throw std::runtime_error
+ void add_trigger_expr(const Expression&); // Can throw std::runtime_error
+ void add_complete_expr(const Expression&); // Can throw std::runtime_error
+ void add_part_trigger(const PartExpression& ); // for adding multiple and/or expression,Can throw std::runtime_error
+ void add_part_complete(const PartExpression& ); // for adding multiple and/or expression,Can throw std::runtime_error
+
+ void addTime( const ecf::TimeAttr& );
+ void addToday( const ecf::TodayAttr& );
+ void addDate( const DateAttr& );
+ void addDay( const DayAttr& );
+ void addCron( const ecf::CronAttr& );
+
+ void addLimit(const Limit& ); // will throw std::runtime_error if duplicate
+ void addInLimit(const InLimit& l) { inLimitMgr_.addInLimit(l);} // will throw std::runtime_error if duplicate
+ void auto_add_inlimit_externs(Defs* defs) { inLimitMgr_.auto_add_inlimit_externs(defs);}
+ void addEvent( const Event& ); // will throw std::runtime_error if duplicate
+ void addMeter( const Meter& ); // will throw std::runtime_error if duplicate
+ void addLabel( const Label& ); // will throw std::runtime_error if duplicate
+ void addAutoCancel( const ecf::AutoCancelAttr& );
+ void addLate( const ecf::LateAttr& );
+ void addRepeat( const Repeat& ); // will throw std::runtime_error if duplicate
+ void addZombie( const ZombieAttr& ); // will throw std::runtime_error if duplicate
+
+
+ // Delete functions: can throw std::runtime_error ===================================
+ // if name argument is empty, delete all attributes of that type
+ // Can throw std::runtime_error of the attribute can not be found
+ void deleteTime(const std::string& name );
+ void delete_time( const ecf::TimeAttr& );
+ void deleteToday(const std::string& name);
+ void delete_today(const ecf::TodayAttr&);
+ void deleteDate(const std::string& name);
+ void delete_date(const DateAttr&);
+ void deleteDay(const std::string& name);
+ void delete_day(const DayAttr&);
+ void deleteCron(const std::string& name);
+ void delete_cron(const ecf::CronAttr&);
+
+ void delete_zombie(const ecf::Child::ZombieType);
+ void deleteVariable( const std::string& name);
+ void deleteEvent(const std::string& name);
+ void deleteMeter(const std::string& name);
+ void deleteLabel(const std::string& name);
+ void deleteTrigger();
+ void deleteComplete();
+ void deleteRepeat();
+ void deleteLimit(const std::string& name);
+ void delete_limit_path(const std::string& limit_name, const std::string& limit_path);
+ void deleteInlimit(const std::string& name);
+ void deleteZombie(const std::string& type); // string must be one of [ user | ecf | path ]
+ void deleteLate();
+
+ // Change functions: ================================================================
+ /// returns true the change was made else false, Can throw std::runtime_error for parse errors
+ void changeVariable(const std::string& name,const std::string& value);
+ void changeEvent(const std::string& name,const std::string& setOrClear = "");
+ void changeEvent(const std::string& name,bool value);
+ void changeMeter(const std::string& name,const std::string& value);
+ void changeMeter(const std::string& name,int value);
+ void changeLabel(const std::string& name,const std::string& value);
+ void changeTrigger(const std::string& expression);
+ void changeComplete(const std::string& expression);
+ void changeRepeat(const std::string& value);
+ void changeLimitMax(const std::string& name,const std::string& maxValue);
+ void changeLimitMax(const std::string& name,int maxValue);
+ void changeLimitValue(const std::string& name,const std::string& value);
+ void changeLimitValue(const std::string& name,int value);
+ void changeDefstatus(const std::string& state);
+ void changeLate(const ecf::LateAttr&);
+
+ bool set_meter(const std::string& name,int value); // does not throw if meter not found
+ bool set_event(const std::string& name,bool value); // does not throw if event not found
+
+ void increment_repeat(); // used in test only
+
+ // mementos functions:
+ /// Collect all the state changes, so that only small subset is returned to client
+ virtual void collateChanges(DefsDelta& ) const = 0;
+ void incremental_changes(DefsDelta&, compound_memento_ptr& comp) const;
+
+ void set_memento(const StateMemento*,std::vector<ecf::Aspect::Type>& aspects );
+ void set_memento(const NodeDefStatusDeltaMemento*,std::vector<ecf::Aspect::Type>& aspects );
+ void set_memento(const SuspendedMemento*,std::vector<ecf::Aspect::Type>& aspects );
+ void set_memento(const NodeEventMemento*,std::vector<ecf::Aspect::Type>& aspects );
+ void set_memento(const NodeMeterMemento*,std::vector<ecf::Aspect::Type>& aspects );
+ void set_memento(const NodeLabelMemento*,std::vector<ecf::Aspect::Type>& aspects );
+ void set_memento(const NodeTriggerMemento*,std::vector<ecf::Aspect::Type>& aspects );
+ void set_memento(const NodeCompleteMemento*,std::vector<ecf::Aspect::Type>& aspects );
+ void set_memento(const NodeRepeatMemento*,std::vector<ecf::Aspect::Type>& aspects );
+ void set_memento(const NodeLimitMemento*,std::vector<ecf::Aspect::Type>& aspects );
+ void set_memento(const NodeInLimitMemento*,std::vector<ecf::Aspect::Type>& aspects );
+ void set_memento(const NodeVariableMemento*,std::vector<ecf::Aspect::Type>& aspects );
+ void set_memento(const NodeLateMemento*,std::vector<ecf::Aspect::Type>& aspects );
+ void set_memento(const NodeTodayMemento*,std::vector<ecf::Aspect::Type>& aspects );
+ void set_memento(const NodeTimeMemento*,std::vector<ecf::Aspect::Type>& aspects );
+ void set_memento(const NodeDayMemento*,std::vector<ecf::Aspect::Type>& aspects );
+ void set_memento(const NodeCronMemento*,std::vector<ecf::Aspect::Type>& aspects );
+ void set_memento(const NodeDateMemento*,std::vector<ecf::Aspect::Type>& aspects );
+ void set_memento(const NodeZombieMemento*,std::vector<ecf::Aspect::Type>& aspects );
+ void set_memento(const NodeVerifyMemento*,std::vector<ecf::Aspect::Type>& aspects );
+ void set_memento(const FlagMemento*,std::vector<ecf::Aspect::Type>& aspects );
+
+ // Find functions: ============================================================
+ // Will search for a node by name(ie not a path) first on siblings, then on a parent
+ // then up the node tree, will stop at the suite .
+ virtual node_ptr find_node_up_the_tree(const std::string& name) const = 0;
+
+ // This is used to find relative nodes.
+ virtual node_ptr find_relative_node(const std::vector<std::string>& pathToNode) = 0;
+
+ /// Look for user,generated and repeat variables
+ /// Find variable corresponding to the given name, by search up the parent hierarchy
+ /// ** We need to distinguish between a variable the exists, but has an empty value
+ /// ** hence we return true if variable is found, and false otherwise
+ bool findParentVariableValue(const std::string& name, std::string& theValue) const;
+
+ /// Look for the parent generated variable only
+ bool find_parent_gen_variable_value(const std::string& name, std::string& theValue) const;
+
+ /// Only looks at user variables
+ /// Find variable corresponding to the given name, by search up the parent hierarchy
+ /// Use when we know that variable is user defined. This is more efficient than
+ /// calling findParentVariableValue.
+ /// *** We need to distinguish between a variable the exists, but has an empty value
+ /// *** hence we return true if variable is found, and false otherwise
+ bool findParentUserVariableValue(const std::string& name, std::string& theValue) const;
+
+ /// This function should be used, when we don't care about the distinctions between
+ /// a variable that exist but has a empty value, and variable not found.(still return empty string)
+ /// Useful when we want to return by reference
+ const std::string& find_parent_user_variable_value(const std::string& name) const;
+
+ /// Search up the hierarchy, simply checks for existence independent of variable vlaue
+ bool user_variable_exists(const std::string& name) const;
+
+ virtual node_ptr findImmediateChild(const std::string& /*name*/, size_t& /*child_pos*/) const { return node_ptr();}
+ const Variable& findVariable(const std::string& name) const;
+ const Variable& find_parent_variable(const std::string& name) const;
+ virtual const Variable& findGenVariable(const std::string& name) const;
+ bool findVariableValue( const std::string& name, std::string& returnedValue) const;
+ bool findGenVariableValue( const std::string& name, std::string& returnedValue) const;
+
+ bool findVerify(const VerifyAttr& ) const;
+ bool findLimit(const Limit& ) const;
+ bool findLabel(const std::string& name) const;
+ const Label& find_label(const std::string& name) const;
+ limit_ptr find_limit(const std::string& name) const;
+ limit_ptr findLimitUpNodeTree(const std::string& name) const;
+ Limit* findLimitViaInLimit(const InLimit& l) const { return inLimitMgr_.findLimitViaInLimit(l); } // used in *test* only
+ bool findInLimitByNameAndPath(const InLimit& l) const { return inLimitMgr_.findInLimitByNameAndPath(l); } // use name,path,token,
+ const Repeat& findRepeat(const std::string& name) const;
+ const Meter& findMeter(const std::string& name) const;
+ Meter& find_meter(const std::string& name);
+ const Event& findEvent(const Event&) const;
+ const Event& findEventByNameOrNumber( const std::string& name) const;
+
+ const ZombieAttr& findZombie( ecf::Child::ZombieType ) const;
+ bool findParentZombie(ecf::Child::ZombieType, ZombieAttr&) const;
+
+ /// Finds the referenced node. The node path can be relative or absolute or a extern path
+ /// however if its an extern path, and corresponding suite is loaded, but we still
+ /// can't find the path, then an error is returned
+ node_ptr findReferencedNode(const std::string& nodePath, std::string& errorMsg) const;
+ node_ptr findReferencedNode(const std::string& nodePath, const std::string& externObj, std::string& errorMsg) const;
+
+ /// return true if we can find a event, meter, user, repeat or generated variable with the given name
+ bool findExprVariable( const std::string& name); // update event & meter as used in trigger for simulator
+
+ /// The status of family/suite is the inherited most significant status of all its children
+ enum TraverseType { IMMEDIATE_CHILDREN, HIERARCHICAL };
+ virtual NState::State computedState(Node::TraverseType) const = 0;
+
+ /// Sets the most significant state up the node tree. Ignores tasks
+ void set_most_significant_state_up_node_tree();
+
+ /// For use with GUI only
+ void set_graphic_ptr(void* p) { graphic_ptr_ = p; }
+ void* graphic_ptr() const { return graphic_ptr_;}
+
+ /// returns the position of this node relative to its peers
+ /// If not attached to parent returns std::numeric_limits<std::size_t>::max();
+ size_t position() const;
+
+ /// called at the end of state change function
+ /// ** Every time we set the state on a nodecontainer, we call handleStateChange
+ /// ** This by default works out the most significant state of the children
+ /// ** ie. the computed state. Hence setting the state on Suite/Family is really
+ /// ** meaningless, since it will always be the computed state.
+ /// ** For Aliases we only update the limits, and do not bubble up state changes
+ virtual void handleStateChange() = 0; // can end up changing state
+
+protected:
+ /// Used in conjunction with Node::position()
+ /// returns std::numeric_limits<std::size_t>::max() if child not found
+ virtual size_t child_position(const Node*) const = 0;
+
+ /// The set_state_only() requires a correctly formed tree, ie since it needs suite()/calendar
+ /// to initialise the duration. We need a way set the state directly. For initialization
+ void set_state_only(NState::State s) { state_.first.setState(s);}
+
+ /// based on the *current* state increment or decrements the limits
+ /// Should *only* be called within a task
+ virtual void update_limits() = 0;
+
+ /// After job submission we need to increment the in limit, to indicate that a
+ /// resource is consumed. The set ensure we only update once during a traversal
+ void incrementInLimit(std::set<Limit*>& limitSet) const;
+
+ /// After job aborts or completes we need to decrement the in limit, to indicate that
+ /// additional resource is available. The set ensure we only update once during a traversal
+ void decrementInLimit(std::set<Limit*>& limitSet) const;
+
+ friend class InLimitMgr;
+ bool check_in_limit() const { return inLimitMgr_.inLimit(); }
+ bool check_in_limit_up_node_tree() const;
+
+
+ friend class Defs;
+ friend class Family;
+ friend class NodeContainer;
+ virtual bool doDeleteChild(Node* child) { return false;}
+
+
+ /// This function is called as a part of handling state change.
+ /// When a suite completes it can be re-queued due to:
+ /// o repeat attribute
+ /// When going up the hierarchy we should not reset Repeats
+ /// The inner repeat must complete before parent repeat (if any) is incremented
+ /// (i.e Mimics a nested loops)
+ /// o Time, Today, cron attributes
+ ///
+ /// Otherwise we need to traverse up the node tree and set the most significant state
+ void requeueOrSetMostSignificantStateUpNodeTree();
+ virtual void resetRelativeDuration();
+
+ node_ptr non_const_this() const;
+
+ void update_repeat_genvar() const;
+
+ // returns node state without trailing new lines
+ virtual std::string write_state() const;
+ virtual void read_state(const std::string& line,const std::vector<std::string>& lineTokens);
+
+ // Observer notifications
+protected:
+ std::vector<AbstractObserver*> observers_;
+ void notify_delete();
+ void checkForLateness( const ecf::Calendar& );
+ void check_for_lateness(const ecf::Calendar& c,const ecf::LateAttr*);
+
+public:
+ void notify(const std::vector<ecf::Aspect::Type>& aspects);
+ void attach(AbstractObserver*);
+ void detach(AbstractObserver*);
+
+private:
+ void why(std::vector<std::string>& theReasonWhy) const;
+ /// Function used as a part of trigger and complete expressions.
+ /// The search pattern is event,meter,user-variable,repeat, generated-variable
+ int findExprVariableValue( const std::string& name) const;
+ int findExprVariableValueAndPlus(const std::string& name, int val) const;
+ int findExprVariableValueAndMinus(const std::string& name, int val) const;
+ int findExprVariableValueAndType( const std::string& name, std::string& varType) const;
+ void findExprVariableAndPrint( const std::string& name, std::ostream& os) const;
+ friend class VariableHelper;
+
+private:
+ bool checkForAutoCancel(const ecf::Calendar& c) const;
+
+ void add_trigger_expression(const Expression&); // Can throw std::runtime_error
+ void add_complete_expression(const Expression&); // Can throw std::runtime_error
+ const Event& findEventByNumber(int number) const;
+ const Event& findEventByName( const std::string& name) const;
+ bool set_meter_used_in_trigger(const std::string& name);
+ bool set_event_used_in_trigger(const std::string& name);
+
+ /// When the begin/re-queue is called this function will initialise the state
+ /// on the node. If node has a default state this is applied to the node, and
+ /// hierarchically to all the children
+ /// Can also clear suspended see re-queue()
+ void initState(int clear_suspended_in_child_nodes);
+
+ // Clear the node suspended and update state change number, no other side effects
+ void clearSuspended();
+
+private: // alow simulator access
+ friend class ecf::DefsAnalyserVisitor;
+ friend class ecf::FlatAnalyserVisitor;
+ friend class ecf::SimulatorVisitor;
+ friend class ecf::Simulator;
+ std::vector<Meter>& ref_meters();// allow simulator set meter value
+ std::vector<Event>& ref_events();// allow simulator set event value
+ Repeat& ref_repeat() { return repeat_;} // allow simulator to modify repeat
+
+ /// Note: If the complete expression evaluation fails. we should continue resolving dependencies
+ /// If the complete expression evaluation evaluates, then we set node to complete
+ bool evaluateComplete() const;
+ bool evaluateTrigger() const;
+ bool timeDependenciesFree() const;
+
+ AstTop* completeAst(std::string& errorMsg) const; // Will create AST on demand
+ AstTop* triggerAst(std::string& errorMsg) const; // Will create AST on demand
+
+private: // All mementos access
+ friend class CompoundMemento;
+ void clear(); /// Clear *ALL* internal attributes
+
+private: /// For use by python interface,
+ friend void export_Node();
+ friend void export_Task();
+ friend void export_SuiteAndFamily();
+ std::vector<Meter>::const_iterator meter_begin() const;
+ std::vector<Meter>::const_iterator meter_end() const;
+ std::vector<Event>::const_iterator event_begin() const;
+ std::vector<Event>::const_iterator event_end() const;
+ std::vector<Label>::const_iterator label_begin() const;
+ std::vector<Label>::const_iterator label_end() const;
+ std::vector<ecf::TimeAttr>::const_iterator time_begin() const;
+ std::vector<ecf::TimeAttr>::const_iterator time_end() const;
+ std::vector<ecf::TodayAttr>::const_iterator today_begin() const;
+ std::vector<ecf::TodayAttr>::const_iterator today_end() const ;
+ std::vector<DateAttr>::const_iterator date_begin() const ;
+ std::vector<DateAttr>::const_iterator date_end() const;
+ std::vector<DayAttr>::const_iterator day_begin() const ;
+ std::vector<DayAttr>::const_iterator day_end() const;
+ std::vector<ecf::CronAttr>::const_iterator cron_begin() const ;
+ std::vector<ecf::CronAttr>::const_iterator cron_end() const;
+ std::vector<ZombieAttr>::const_iterator zombie_begin() const;
+ std::vector<ZombieAttr>::const_iterator zombie_end() const;
+ std::vector<VerifyAttr>::const_iterator verify_begin() const;
+ std::vector<VerifyAttr>::const_iterator verify_end() const;
+ std::vector<Variable>::const_iterator variable_begin() const { return varVec_.begin();}
+ std::vector<Variable>::const_iterator variable_end() const { return varVec_.end();}
+ std::vector<limit_ptr>::const_iterator limit_begin() const { return limitVec_.begin();}
+ std::vector<limit_ptr>::const_iterator limit_end() const { return limitVec_.end();}
+ std::vector<InLimit>::const_iterator inlimit_begin() const { return inLimitMgr_.inlimit_begin();}
+ std::vector<InLimit>::const_iterator inlimit_end() const { return inLimitMgr_.inlimit_end();}
+ std::string to_string() const; // For python interface
+
+private:
+ Node* parent_; // *NOT* persisted must be set by the parent class
+ std::string name_;
+ bool suspended_;
+ std::pair<NState,boost::posix_time::time_duration> state_; // state and duration since suite start when state changed
+ DState defStatus_; // default value is QUEUED
+
+ mutable Expression* completeExpr_; // can only have one complete expression
+ mutable Expression* triggerExpr_; // can only have one trigger expression
+
+ ecf::LateAttr* lateAttr_; // Can only have one late attribute per node
+ ecf::AutoCancelAttr* autoCancel_; // Can only have 1 auto cancel per node
+ TimeDepAttrs* time_dep_attrs_;
+ ChildAttrs* child_attrs_; // event meter & lables
+ MiscAttrs* misc_attrs_; // VerifyAttr(used for statistics and test verification) & Zombies
+ Repeat repeat_; // each node can only have one repeat. By value, since has pimpl
+
+ std::vector<Variable> varVec_;
+ std::vector<limit_ptr> limitVec_; // Ptrs since many in-limits can point to a single limit
+ InLimitMgr inLimitMgr_; // manages the inlimit
+
+ ecf::Flag flag_;
+
+ unsigned int state_change_no_; // *not* persisted, only used on server side,Used to indicate addition or deletion of attribute
+ unsigned int variable_change_no_; // *not* persisted, placed here rather than Variable, to save memory
+ unsigned int suspended_change_no_; // *not* persisted,
+
+#ifdef DEBUG
+ boost::posix_time::ptime submit_to_complete_duration_; // *not* persisted
+#endif
+
+ void* graphic_ptr_; // for use with the gui only
+
+ friend class TimeDepAttrs;
+ friend class ChildAttrs;
+ friend class MiscAttrs;
+
+private:
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/) {
+ ar & name_;
+ ar & state_;
+ ar & suspended_;
+ ar & defStatus_;
+ ar & completeExpr_;
+ ar & triggerExpr_;
+ ar & lateAttr_;
+ ar & autoCancel_;
+ ar & time_dep_attrs_;
+ ar & child_attrs_;
+ ar & misc_attrs_; // VerifyAttr & Zombies
+ ar & repeat_;
+ ar & varVec_;
+ ar & limitVec_;
+ ar & inLimitMgr_;
+ ar & flag_;
+
+ if (Archive::is_loading::value) {
+ if (time_dep_attrs_) time_dep_attrs_->set_node(this);
+ if (child_attrs_) child_attrs_->set_node(this);
+ if (misc_attrs_) misc_attrs_->set_node(this);
+ for(std::vector<limit_ptr>::iterator i = limitVec_.begin(); i!= limitVec_.end(); ++i) (*i)->set_node(this);
+ }
+ }
+};
+#endif
diff --git a/ANode/src/NodeAdd.cpp b/ANode/src/NodeAdd.cpp
new file mode 100644
index 0000000..af97318
--- /dev/null
+++ b/ANode/src/NodeAdd.cpp
@@ -0,0 +1,299 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #50 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/make_shared.hpp>
+#include <boost/lexical_cast.hpp>
+#include "Node.hpp"
+#include "Ecf.hpp"
+
+using namespace ecf;
+using namespace std;
+
+void Node::addVariable(const Variable& v )
+{
+ state_change_no_ = Ecf::incr_state_change_no();
+
+ const std::string& variable_name = v.name();
+ size_t theSize = varVec_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ if (varVec_[i].name() == variable_name) {
+ // Variable already exist, *UPDATE* its value
+ varVec_[i].set_value(v.theValue());
+ if (0 == Ecf::debug_level())
+ std::cout << "Node::addVariable: Variable of name '" << v.name() << "' already exist for node " << debugNodePath() << " updating with value '" << v.theValue() << "'\n";
+ return;
+ }
+ }
+
+ if (varVec_.capacity() == 0) varVec_.reserve(5);
+ varVec_.push_back( v );
+}
+
+void Node::add_variable(const std::string& name, const std::string& value )
+{
+ addVariable( Variable(name, value) );
+}
+
+void Node::add_variable_int(const std::string& name, int some_int )
+{
+ std::string value = boost::lexical_cast<std::string>(some_int);
+ addVariable( Variable(name, value) );
+}
+
+void Node::add_trigger(const std::string& string_expression)
+{
+ add_trigger_expression(Expression(string_expression));
+}
+void Node::add_complete(const std::string& string_expression)
+{
+ add_complete_expression(Expression(string_expression));
+}
+void Node::add_trigger_expr(const Expression& expr)
+{
+ add_trigger_expression(expr);
+}
+void Node::add_complete_expr(const Expression& expr)
+{
+ add_complete_expression(expr);
+}
+void Node::add_trigger_expression(const Expression& t)
+{
+ if ( triggerExpr_ ) {
+ std::stringstream ss;
+ ss << "Node::add_trigger_expression. A Node(" << absNodePath() << " can only have one trigger ";
+ ss << "to add large triggers use multiple calls to Node::add_part_trigger( PartExpression('t1 == complete') )";
+ throw std::runtime_error( ss.str() );
+ }
+ triggerExpr_ = new Expression(t);
+ state_change_no_ = Ecf::incr_state_change_no();
+}
+
+void Node::add_complete_expression(const Expression& t)
+{
+ if ( completeExpr_ ) {
+ std::stringstream ss;
+ ss << "Node::add_complete_expression. A Node(" << absNodePath() << " can only have one complete expression ";
+ ss << "to add large complete expressions use multiple calls to Node::add_part_complete( PartExpression('t1 == complete') )";
+ throw std::runtime_error( ss.str() );
+ }
+ completeExpr_ = new Expression(t);
+ state_change_no_ = Ecf::incr_state_change_no();
+}
+
+void Node::add_part_trigger(const PartExpression& part)
+{
+ if (!triggerExpr_) triggerExpr_ = new Expression();
+ triggerExpr_->add( part );
+ state_change_no_ = Ecf::incr_state_change_no();
+}
+void Node::add_part_complete(const PartExpression& part)
+{
+ if (!completeExpr_) completeExpr_ = new Expression();
+ completeExpr_->add( part );
+ state_change_no_ = Ecf::incr_state_change_no();
+}
+
+
+void Node::addTime(const ecf::TimeAttr& t)
+{
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Node::addTime\n";
+#endif
+
+ if (isSuite()) {
+ throw std::runtime_error("Can not add time based dependency on a suite");
+ }
+
+ if (!time_dep_attrs_) time_dep_attrs_ = new TimeDepAttrs(this);
+ time_dep_attrs_->addTime(t); // will call Ecf::incr_state_change_no();
+}
+
+void Node::addToday(const ecf::TodayAttr& t)
+{
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Node::addToday()\n";
+#endif
+
+ if (isSuite()) {
+ throw std::runtime_error("Can not add time based dependency on a suite");
+ }
+
+ if (!time_dep_attrs_) time_dep_attrs_ = new TimeDepAttrs(this);
+ time_dep_attrs_->addToday(t); // will call Ecf::incr_state_change_no();
+}
+
+void Node::addDate( const DateAttr& d)
+{
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Node::addDate()\n";
+#endif
+
+ // By disallowing what effect would if have on existing suites ?
+ if (isSuite()) {
+ throw std::runtime_error("Can not add time based dependency on a suite"); // Added at 4.0.2
+ }
+
+ if (!time_dep_attrs_) time_dep_attrs_ = new TimeDepAttrs(this);
+ time_dep_attrs_->addDate(d); // will call Ecf::incr_state_change_no();
+}
+
+void Node::addDay( const DayAttr& d)
+{
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Node::addDay\n";
+#endif
+
+ // By disallowing what effect would if have on existing suites ?
+ if (isSuite()) {
+ throw std::runtime_error("Can not add time based dependency on a suite"); // Added at 4.0.2
+ }
+
+ if (!time_dep_attrs_) time_dep_attrs_ = new TimeDepAttrs(this);
+ time_dep_attrs_->addDay(d); // will call Ecf::incr_state_change_no();
+}
+
+void Node::addCron( const CronAttr& d)
+{
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Node::addCron()\n";
+#endif
+
+ if (d.time().isNULL()) {
+ throw std::runtime_error("Node::addCron: The cron is in-complete, no time specified");
+ }
+ if (d.time().hasIncrement() && !repeat_.empty()) {
+ std::stringstream ss;
+ ss << "Node::addCron: Node " << absNodePath() << " already has a repeat. Inappropriate to add two looping structures at the same level\n";
+ throw std::runtime_error(ss.str());
+ }
+
+ if (!time_dep_attrs_) time_dep_attrs_ = new TimeDepAttrs(this);
+ time_dep_attrs_->addCron(d); // will call Ecf::incr_state_change_no();
+}
+
+
+void Node::addLabel( const Label& l)
+{
+ if (child_attrs_) {
+ child_attrs_->addLabel(l); // can throw
+ return;
+ }
+ child_attrs_ = new ChildAttrs(this);
+ child_attrs_->addLabel(l);
+}
+
+void Node::addMeter( const Meter& m)
+{
+// if ( isSuite() ) {
+// throw std::runtime_error("Node::addMeter: Can not add meter to a Suite");
+// }
+
+ if (child_attrs_) {
+ child_attrs_->addMeter(m); // can throw
+ return;
+ }
+ child_attrs_ = new ChildAttrs(this);
+ child_attrs_->addMeter(m);
+}
+
+void Node::addEvent( const Event& e)
+{
+ if (child_attrs_) {
+ child_attrs_->addEvent(e); // can throw
+ return;
+ }
+ child_attrs_ = new ChildAttrs(this);
+ child_attrs_->addEvent(e);
+}
+
+void Node::addLimit(const Limit& l )
+{
+ if (findLimit(l)) {
+ std::stringstream ss;
+ ss << "Add Limit failed: Duplicate Limit of name '" << l.name() << "' already exist for node " << debugNodePath();
+ throw std::runtime_error( ss.str() );
+ }
+ limit_ptr the_limit = boost::make_shared<Limit>(l);
+ the_limit->set_node(this);
+ limitVec_.push_back( the_limit );
+ state_change_no_ = Ecf::incr_state_change_no();
+}
+
+static void throwIfRepeatAllreadyExists(Node* node)
+{
+ if (!node->repeat().empty()) {
+ std::stringstream ss;
+ ss << "Add Repeat failed: Repeat of name '" << node->repeat().name() << "' already exist for node " << node->debugNodePath();
+ throw std::runtime_error( ss.str() );
+ }
+
+ if (!node->crons().empty()) {
+ std::stringstream ss;
+ ss << "Node::addRepeat: Node " << node->absNodePath() << " already has a cron. Inappropriate to add two looping structures at the same level\n";
+ throw std::runtime_error(ss.str());
+ }
+}
+void Node::addRepeat( const Repeat& r ){
+ throwIfRepeatAllreadyExists(this);
+ repeat_ = Repeat(r);
+ repeat_.update_repeat_genvar();
+ state_change_no_ = Ecf::incr_state_change_no();
+}
+
+void Node::addAutoCancel( const AutoCancelAttr& ac)
+{
+ if (autoCancel_) {
+ std::stringstream ss;
+ ss << "Node::addAutoCancel: A node can only have one Autocancel, see node " << debugNodePath();
+ throw std::runtime_error( ss.str() );
+ }
+ autoCancel_ = new ecf::AutoCancelAttr(ac);
+ state_change_no_ = Ecf::incr_state_change_no();
+}
+
+void Node::addLate( const ecf::LateAttr& l )
+{
+ if (! lateAttr_) {
+ lateAttr_ = new ecf::LateAttr(l);
+ state_change_no_ = Ecf::incr_state_change_no();
+ return;
+ }
+ throw std::runtime_error("Add Late failed: A node can only have one Late attribute, see node " + debugNodePath() );
+}
+
+
+void Node::addVerify( const VerifyAttr& v )
+{
+ if (misc_attrs_) {
+ misc_attrs_->addVerify(v); // can throw
+ return;
+ }
+ misc_attrs_ = new MiscAttrs(this);
+ misc_attrs_->addVerify(v);
+}
+
+void Node::addZombie( const ZombieAttr& z)
+{
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Node::addZombie()\n";
+#endif
+
+ if (misc_attrs_) {
+ misc_attrs_->addZombie(z); // can throw
+ return;
+ }
+ misc_attrs_ = new MiscAttrs(this);
+ misc_attrs_->addZombie(z);
+
+}
diff --git a/ANode/src/NodeChange.cpp b/ANode/src/NodeChange.cpp
new file mode 100644
index 0000000..839592d
--- /dev/null
+++ b/ANode/src/NodeChange.cpp
@@ -0,0 +1,195 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #33 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <boost/lexical_cast.hpp>
+
+#include "Node.hpp"
+#include "ExprAst.hpp"
+#include "Stl.hpp"
+#include "NState.hpp"
+#include "Ecf.hpp"
+#include "Str.hpp"
+
+using namespace ecf;
+using namespace std;
+
+void Node::changeVariable(const std::string& name,const std::string& value)
+{
+ size_t theSize = varVec_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ if (varVec_[i].name() == name) {
+ varVec_[i].set_value( value );
+ variable_change_no_ = Ecf::incr_state_change_no();
+ return;
+ }
+ }
+ throw std::runtime_error("Node::changeVariable: Could not find variable " + name);
+}
+
+bool Node::set_event(const std::string& event_name_or_number ,bool value)
+{
+ if (child_attrs_) return child_attrs_->set_event(event_name_or_number,value);
+ return false;
+}
+
+bool Node::set_event_used_in_trigger(const std::string& event_name_or_number)
+{
+ if (child_attrs_) return child_attrs_->set_event_used_in_trigger(event_name_or_number);
+ return false;
+}
+void Node::changeEvent(const std::string& event_name_or_number,const std::string& setOrClear)
+{
+ if (child_attrs_) return child_attrs_->changeEvent(event_name_or_number,setOrClear);
+}
+void Node::changeEvent(const std::string& event_name_or_number,bool value)
+{
+ if (child_attrs_) {
+ child_attrs_->changeEvent(event_name_or_number,value);
+ return;
+ }
+ throw std::runtime_error("Node::changeEvent: Could not find event " + event_name_or_number);
+}
+
+bool Node::set_meter(const std::string& meter_name,int value)
+{
+ if (child_attrs_) return child_attrs_->set_meter(meter_name,value);
+ return false;
+}
+bool Node::set_meter_used_in_trigger(const std::string& meter_name)
+{
+ if (child_attrs_) return child_attrs_->set_meter_used_in_trigger(meter_name);
+ return false;
+}
+void Node::changeMeter(const std::string& meter_name,const std::string& value)
+{
+ if (child_attrs_) {
+ child_attrs_->changeMeter(meter_name,value);
+ return;
+ }
+ throw std::runtime_error("Node::changeMeter: Could not find meter " + meter_name);
+}
+void Node::changeMeter(const std::string& meter_name,int value)
+{
+ if (child_attrs_) {
+ child_attrs_->changeMeter(meter_name,value);
+ return;
+ }
+ throw std::runtime_error("Node::changeMeter: Could not find meter " + meter_name);
+}
+
+void Node::changeLabel(const std::string& name,const std::string& value)
+{
+ if (child_attrs_) {
+ child_attrs_->changeLabel(name,value);
+ return;
+ }
+ throw std::runtime_error("Node::changeLabel: Could not find label " + name);
+}
+
+void Node::changeTrigger(const std::string& expression)
+{
+ PartExpression part(expression);
+ string parseErrorMsg;
+ std::auto_ptr<AstTop> ast = part.parseExpressions( parseErrorMsg );
+ if (!ast.get()) {
+ std::stringstream ss;
+ ss << "Node::changeTrigger: Failed to parse expression '" << expression << "'. " << parseErrorMsg;
+ throw std::runtime_error( ss.str() );
+ }
+
+ deleteTrigger();
+ add_trigger( expression );
+}
+
+void Node::changeComplete(const std::string& expression)
+{
+ PartExpression part(expression);
+ string parseErrorMsg;
+ std::auto_ptr<AstTop> ast = part.parseExpressions( parseErrorMsg );
+ if (!ast.get()) {
+ std::stringstream ss;
+ ss << "Node::changeComplete: Failed to parse expression '" << expression << "'. " << parseErrorMsg;
+ throw std::runtime_error( ss.str() );
+ }
+
+ deleteComplete();
+ add_complete( expression );
+}
+
+void Node::changeRepeat(const std::string& value)
+{
+ if (repeat_.empty()) throw std::runtime_error("Node::changeRepeat: Could not find repeat on " + absNodePath());
+ repeat_.change( value ); // this can throw std::runtime_error
+}
+
+void Node::increment_repeat()
+{
+ if (repeat_.empty()) throw std::runtime_error("Node::increment_repeat: Could not find repeat on " + absNodePath());
+ repeat_.increment();
+}
+
+void Node::changeLimitMax(const std::string& name,const std::string& maxValue)
+{
+ int theValue = 0;
+ try {
+ theValue = boost::lexical_cast< int >( maxValue );
+ }
+ catch ( boost::bad_lexical_cast& ) {
+ throw std::runtime_error( "Node::changeLimitMax expected integer value but found " + maxValue);
+ }
+ changeLimitMax(name, theValue);
+}
+
+void Node::changeLimitMax(const std::string& name,int maxValue)
+{
+ limit_ptr limit = find_limit(name);
+ if (!limit.get()) throw std::runtime_error("Node::changeLimitMax: Could not find limit " + name);
+ limit->setLimit( maxValue );
+}
+
+void Node::changeLimitValue(const std::string& name,const std::string& value)
+{
+ int theValue = 0;
+ try {
+ theValue = boost::lexical_cast< int >( value );
+ }
+ catch ( boost::bad_lexical_cast& ) {
+ throw std::runtime_error( "Node::changeLimitValue expected integer value but found " + value);
+ }
+ changeLimitValue(name,theValue);
+}
+
+void Node::changeLimitValue(const std::string& name,int value)
+{
+ limit_ptr limit = find_limit(name);
+ if (!limit.get()) throw std::runtime_error("Node::changeLimitValue: Could not find limit " + name);
+ limit->setValue( value );
+}
+
+void Node::changeDefstatus(const std::string& theState)
+{
+ if (!DState::isValid(theState)) {
+ throw std::runtime_error( "Node::changeDefstatus expected a state but found " + theState);
+ }
+
+ // Updates state_change_no on the defStatus
+ defStatus_.setState( DState::toState(theState) );
+}
+
+void Node::changeLate(const ecf::LateAttr& late)
+{
+ if (lateAttr_) delete lateAttr_;
+ lateAttr_ = new ecf::LateAttr(late);
+ state_change_no_ = Ecf::incr_state_change_no();
+}
diff --git a/ANode/src/NodeContainer.cpp b/ANode/src/NodeContainer.cpp
new file mode 100644
index 0000000..72c7622
--- /dev/null
+++ b/ANode/src/NodeContainer.cpp
@@ -0,0 +1,1013 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #135 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <limits>
+#include <assert.h>
+#include <sstream>
+#include <boost/bind.hpp>
+#include <boost/make_shared.hpp>
+
+#include "NodeContainer.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "Defs.hpp"
+#include "Log.hpp"
+#include "JobsParam.hpp"
+#include "NodeTreeVisitor.hpp"
+
+#include "Stl.hpp"
+#include "Indentor.hpp"
+#include "ExprAst.hpp"
+#include "NodeState.hpp"
+#include "Ecf.hpp"
+#include "NodeState.hpp"
+#include "SuiteChanged.hpp"
+#include "DefsDelta.hpp"
+#include "Str.hpp"
+
+using namespace ecf;
+using namespace std;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+//#define DEBUG_FIND_NODE 1
+//#define DEBUG_JOB_SUBMISSION 1
+
+/////////////////////////////////////////////////////////////////////////////////////////
+NodeContainer::NodeContainer( const std::string& name )
+: Node(name),order_state_change_no_(0), add_remove_state_change_no_(0) {}
+NodeContainer::NodeContainer()
+: order_state_change_no_(0),add_remove_state_change_no_(0) {}
+NodeContainer::~NodeContainer() {}
+
+void NodeContainer::accept(ecf::NodeTreeVisitor& v)
+{
+ v.visitNodeContainer(this);
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) { nodeVec_[t]->accept(v); }
+}
+
+void NodeContainer::acceptVisitTraversor(ecf::NodeTreeVisitor& v)
+{
+ v.visitNodeContainer(this);
+}
+
+void NodeContainer::begin()
+{
+ Node::begin();
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) { nodeVec_[t]->begin(); }
+ handle_defstatus_propagation();
+}
+
+void NodeContainer::requeue(
+ bool resetRepeats,
+ int clear_suspended_in_child_nodes,
+ bool reset_next_time_slot
+ )
+{
+// LOG(Log::DBG," " << debugType() << "::requeue() " << absNodePath() << " resetRepeats = " << resetRepeats);
+ Node::requeue(resetRepeats,clear_suspended_in_child_nodes,reset_next_time_slot);
+
+ // For negative numbers, do nothing, i.e do not clear
+ if (clear_suspended_in_child_nodes >=0) clear_suspended_in_child_nodes++;
+
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) {
+ nodeVec_[t]->requeue(true /*reset child repeats. Moot for tasks*/,
+ clear_suspended_in_child_nodes,
+ reset_next_time_slot);
+ }
+ handle_defstatus_propagation();
+}
+
+void NodeContainer::requeue_time_attrs()
+{
+ Node::requeue_time_attrs();
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) {
+ nodeVec_[t]->requeue_time_attrs();
+ }
+}
+
+void NodeContainer::handle_defstatus_propagation()
+{
+ if ( defStatus_ == DState::COMPLETE ) {
+ /// A defstatus of complete and *ONLY* complete should always be applied
+ /// hierarchically downwards
+ setStateOnlyHierarchically(NState::COMPLETE);
+ }
+ else if ( defStatus_ == DState::default_state() ) {
+ /// Reflect that the status of the children.
+ /// *However* do NOT override the defstatus setting
+ NState::State theSignificantStateOfImmediateChildren = computedState( Node::IMMEDIATE_CHILDREN );
+ if ( theSignificantStateOfImmediateChildren != state()) {
+ setStateOnly( theSignificantStateOfImmediateChildren );
+ }
+ }
+}
+
+void NodeContainer::resetRelativeDuration()
+{
+ Node::resetRelativeDuration();
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) { nodeVec_[t]->resetRelativeDuration(); }
+}
+
+bool NodeContainer::run(JobsParam& jobsParam, bool force)
+{
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) { (void) nodeVec_[t]->run(jobsParam,force); }
+ return jobsParam.getErrorMsg().empty();
+}
+
+void NodeContainer::kill(const std::string& /* zombie_pid, only valid for single task */)
+{
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) { nodeVec_[t]->kill(); }
+}
+
+void NodeContainer::status()
+{
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) { nodeVec_[t]->status(); }
+}
+
+void NodeContainer::top_down_why(std::vector<std::string>& theReasonWhy) const
+{
+ Node::why(theReasonWhy);
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) { nodeVec_[t]->top_down_why(theReasonWhy); }
+}
+
+void NodeContainer::incremental_changes( DefsDelta& changes, compound_memento_ptr& comp) const
+{
+ /// There no point doing a OrderMemento if children have been added/delete
+ if (add_remove_state_change_no_ > changes.client_state_change_no()) {
+ if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
+ comp->add( boost::make_shared<ChildrenMemento>( nodeVec_ ) );
+ }
+ else if (order_state_change_no_ > changes.client_state_change_no()) {
+ if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
+ std::vector<std::string> order_vec; order_vec.reserve(nodeVec_.size());
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t i =0; i < node_vec_size; i++) order_vec.push_back( nodeVec_[i]->name());
+ comp->add( boost::make_shared<OrderMemento>( order_vec ) );
+ }
+
+ Node::incremental_changes(changes, comp);
+}
+
+void NodeContainer::set_memento( const OrderMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+#ifdef DEBUG_MEMENTO
+ std::cout << "NodeContainer::set_memento( const OrderMemento* ) " << debugNodePath() << "\n";
+#endif
+
+ // Order nodeVec_ according to memento ordering
+ const std::vector<std::string>& order = memento->order_;
+ if (order.size() != nodeVec_.size()) {
+ // something gone wrong.
+ std::cout << "NodeContainer::set_memento OrderMemento, memento.size() " << order.size() << " Not the same as nodeVec_size() " << nodeVec_.size() << "\n";
+ return;
+ }
+
+ std::vector<node_ptr> vec; vec.reserve(nodeVec_.size());
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t i = 0; i < order.size(); i++) {
+ for(size_t t = 0; t < node_vec_size; t++) {
+ if (order[i] == nodeVec_[t]->name()) {
+ vec.push_back(nodeVec_[t]);
+ break;
+ }
+ }
+ }
+ if (vec.size() != nodeVec_.size()) {
+ std::cout << "NodeContainer::set_memento could not find all the names\n";
+ return;
+ }
+
+ aspects.push_back(ecf::Aspect::ORDER);
+ nodeVec_ = vec;
+}
+
+void NodeContainer::set_memento( const ChildrenMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+#ifdef DEBUG_MEMENTO
+ std::cout << "NodeContainer::set_memento( const OrderMemento* ) " << debugNodePath() << "\n";
+#endif
+ aspects.push_back(ecf::Aspect::ADD_REMOVE_NODE);
+ nodeVec_ = memento->children_;
+
+ // setup child parent pointers
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) {
+ nodeVec_[t]->set_parent(this);
+ }
+}
+
+
+void NodeContainer::collateChanges(DefsDelta& changes) const
+{
+ /// There no point in traversing children of we have added/removed children
+ /// since ChildrenMemento will copy all children.
+ if (add_remove_state_change_no_ > changes.client_state_change_no()) {
+ return;
+ }
+
+ // Traversal to children
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) { nodeVec_[t]->collateChanges(changes); }
+}
+
+void NodeContainer::order(Node* immediateChild, NOrder::Order ord)
+{
+ SuiteChanged1 changed(suite());
+ switch (ord) {
+ case NOrder::TOP: {
+ for(std::vector<node_ptr>::iterator i = nodeVec_.begin(); i != nodeVec_.end(); ++i) {
+ if ((*i).get() == immediateChild) {
+ node_ptr node = (*i);
+ nodeVec_.erase(i);
+ nodeVec_.insert(nodeVec_.begin(),node);
+ order_state_change_no_ = Ecf::incr_state_change_no();
+ return;
+ }
+ }
+ throw std::runtime_error("NodeContainer::order TOP, immediate child not found");
+ }
+ case NOrder::BOTTOM: {
+ for(std::vector<node_ptr>::iterator i = nodeVec_.begin(); i != nodeVec_.end(); ++i) {
+ if ((*i).get() == immediateChild) {
+ node_ptr node = (*i);
+ nodeVec_.erase(i);
+ nodeVec_.push_back(node);
+ order_state_change_no_ = Ecf::incr_state_change_no();
+ return;
+ }
+ }
+ throw std::runtime_error("NodeContainer::order BOTTOM, immediate child not found");
+ }
+ case NOrder::ALPHA: {
+ std::sort(nodeVec_.begin(),nodeVec_.end(),
+ boost::bind(Str::caseInsLess,
+ boost::bind(&Node::name,_1),
+ boost::bind(&Node::name,_2)));
+ order_state_change_no_ = Ecf::incr_state_change_no();
+ break;
+ }
+ case NOrder::ORDER: {
+ std::sort(nodeVec_.begin(),nodeVec_.end(),
+ boost::bind(Str::caseInsGreater,
+ boost::bind(&Node::name,_1),
+ boost::bind(&Node::name,_2)));
+ order_state_change_no_ = Ecf::incr_state_change_no();
+ break;
+ }
+ case NOrder::UP: {
+ for(size_t t = 0; t < nodeVec_.size();t++) {
+ if ( nodeVec_[t].get() == immediateChild) {
+ if (t != 0) {
+ node_ptr node = nodeVec_[t];
+ nodeVec_.erase(nodeVec_.begin()+t);
+ t--;
+ nodeVec_.insert(nodeVec_.begin()+t,node);
+ order_state_change_no_ = Ecf::incr_state_change_no();
+ }
+ return;
+ }
+ }
+ throw std::runtime_error("NodeContainer::order UP, immediate child not found");
+ }
+ case NOrder::DOWN: {
+ for(size_t t = 0; t < nodeVec_.size();t++) {
+ if ( nodeVec_[t].get() == immediateChild) {
+ if (t != nodeVec_.size()-1) {
+ node_ptr node = nodeVec_[t];
+ nodeVec_.erase(nodeVec_.begin()+t);
+ t++;
+ nodeVec_.insert(nodeVec_.begin()+t,node);
+ order_state_change_no_ = Ecf::incr_state_change_no();
+ }
+ return;
+ }
+ }
+ throw std::runtime_error("NodeContainer::order DOWN, immediate child not found");
+ }
+ }
+}
+
+void NodeContainer::calendarChanged(
+ const ecf::Calendar& c,
+ std::vector<node_ptr>& auto_cancelled_nodes,
+ const ecf::LateAttr* inherited_late)
+{
+ // The late attribute is inherited, we only set late on the task/alias
+ Node::calendarChanged(c,auto_cancelled_nodes,NULL);
+
+
+ LateAttr overridden_late;
+ if (inherited_late && !inherited_late->isNull()) {
+ overridden_late = *inherited_late;
+ }
+ if (lateAttr_ != inherited_late) {
+ overridden_late.override_with(lateAttr_);
+ }
+
+
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) {
+ nodeVec_[t]->calendarChanged(c,auto_cancelled_nodes,&overridden_late);
+ }
+}
+
+bool NodeContainer::hasAutoCancel() const
+{
+ if (Node::hasAutoCancel()) return true;
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) { if (nodeVec_[t]->hasAutoCancel()) return true; }
+ return false;
+}
+
+bool NodeContainer::resolveDependencies(JobsParam& jobsParam)
+{
+ // Don't evaluate children unless parent is free. BOMB out early for this case.
+ // Note:: Task::resolveDependencies() will check inLimit up front. *** THIS CHECKS UP THE HIERARCHY ***
+ // Note:: Node::resolveDependencies() may have forced family node to complete, should have have
+ // returned false in this case, to stop any job submission
+ if ( ! Node::resolveDependencies(jobsParam) ) {
+
+#ifdef DEBUG_JOB_SUBMISSION
+ LOG(Log::DBG, " NodeContainer::resolveDependencies " << absNodePath() << " could not resolve dependencies, may have completed");
+ cout << "NodeContainer::resolveDependencies " << absNodePath() << " could not resolve dependencies may have completed" << endl;
+#endif
+ return false;
+ }
+
+ /// During *top down* traversal we check in limits at this level. Done here rather than
+ /// in Node::resolveDependencies(). Otherwise this particular check will get duplicated
+ /// since the task, will do *bottom up* traversal.
+ if (!check_in_limit()) {
+#ifdef DEBUG_DEPENDENCIES
+ LOG(Log::DBG," NodeContainer::resolveDependencies() " << absNodePath() << " HOLDING due to inLIMIT");
+#endif
+ return false;
+ }
+
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) {
+ // Note: we don't bomb out early here. Since a later child could be free. i.e f1/ty or t4
+ // child t1 holding
+ // child t2 holding
+ // child f1 free
+ // child tx holding
+ // child ty free
+ // child t3 holding
+ // child t4 free
+ (void) nodeVec_[t]->resolveDependencies(jobsParam) ;
+ }
+ return true;
+}
+
+NState::State NodeContainer::computedState(Node::TraverseType traverseType) const
+{
+ if (nodeVec_.empty()) {
+ /// Note: theComputedNodeState will return unknown if no children, in this
+ /// case just return the current state.
+ return state();
+ }
+
+ // returns the computed state depending on traverseType
+ // If not IMMEDIATE_CHILDREN, will recurse down calling each child's computedState() function
+ return ecf::theComputedNodeState(nodeVec_, (traverseType == Node::IMMEDIATE_CHILDREN) );
+}
+
+node_ptr NodeContainer::removeChild(Node* child)
+{
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) {
+ if (nodeVec_[t].get() == child) {
+ node_ptr node = boost::dynamic_pointer_cast<Node>(nodeVec_[t]);
+ child->set_parent(NULL); // must set to NULL, allows it to be re-added to different parent
+ nodeVec_.erase( nodeVec_.begin() + t);
+ add_remove_state_change_no_ = Ecf::incr_state_change_no();
+ return node ;
+ }
+ }
+ // Should never happen
+ LOG_ASSERT(false,"NodeContainer::removeChild: Could not remove child");
+ return node_ptr();
+}
+
+bool NodeContainer::addChild( node_ptr child, size_t position)
+{
+ // *** CANT construct shared_ptr from a raw pointer, must use dynamic_pointer_cast,
+ // *** otherwise the reference counts will get messed up.
+ try {
+ if ( child->isTask() ) {
+ // can throw if duplicate names
+ addTask( boost::dynamic_pointer_cast<Task>(child), position );
+ return true;
+ }
+
+ if ( child->isFamily() ) {
+ // can throw if duplicate names
+ addFamily( boost::dynamic_pointer_cast<Family>(child), position );
+ return true;
+ }
+ }
+ catch ( std::runtime_error &e) {}
+
+ // Duplicate names, or trying to add a Suite?
+ return false;
+}
+
+bool NodeContainer::isAddChildOk( Node* theChild, std::string& errorMsg) const
+{
+ Task* theTaskChild = theChild->isTask();
+ if ( theTaskChild ) {
+
+ task_ptr theTask = findTask(theChild->name());
+ if (!theTask.get()) return true;
+
+ std::stringstream ss;
+ ss << "Task of name " << theChild->name() << " already exist in container node " << name() ;
+ errorMsg += ss.str();
+ return false;
+ }
+
+ Family* theFamilyChild = theChild->isFamily();
+ if ( theFamilyChild ) {
+
+ family_ptr theFamily = findFamily(theChild->name());
+ if (!theFamily.get()) return true;
+
+ std::stringstream ss;
+ ss << "Family of name " << theChild->name() << " already exist in container node " << name() ;
+ errorMsg += ss.str();
+ return false;
+ }
+
+ Suite* theSuite = theChild->isSuite();
+ if ( theSuite ) {
+ errorMsg += "Can not add a suite as child.";
+ return false;
+ }
+
+ errorMsg += "Unknown node type";
+ return false;
+}
+
+void NodeContainer::handleStateChange()
+{
+ // Increment any repeats & requeue
+ requeueOrSetMostSignificantStateUpNodeTree();
+}
+
+size_t NodeContainer::child_position(const Node* child) const
+{
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) {
+ if (nodeVec_[t].get() == child) {
+ return t;
+ }
+ }
+ return std::numeric_limits<std::size_t>::max();
+}
+
+task_ptr NodeContainer::add_task(const std::string& task_name)
+{
+ if (findTask(task_name).get()) {
+ std::stringstream ss;
+ ss << "Add Task failed: A task of name '" << task_name << "' already exist on node " << debugNodePath();
+ throw std::runtime_error( ss.str() );
+ }
+ task_ptr the_task = Task::create(task_name);
+ add_task_only(the_task);
+ return the_task;
+}
+
+family_ptr NodeContainer::add_family(const std::string& family_name)
+{
+ if (findFamily(family_name).get()) {
+ std::stringstream ss;
+ ss << "Add Family failed: A Family of name '" << family_name << "' already exist on node " << debugNodePath();
+ throw std::runtime_error( ss.str() );
+ }
+ family_ptr the_family = Family::create(family_name);
+ add_family_only( the_family );
+ return the_family;
+}
+
+void NodeContainer::addTask(task_ptr t,size_t position)
+{
+ if (findTask(t->name()).get()) {
+ std::stringstream ss;
+ ss << "Add Task failed: A task of name '" << t->name() << "' already exist on node " << debugNodePath();
+ throw std::runtime_error( ss.str() );
+ }
+ add_task_only( t, position);
+}
+
+void NodeContainer::add_task_only( task_ptr t, size_t position)
+{
+ if (t->parent()) {
+ std::stringstream ss;
+ ss << debugNodePath() << ": Add Task failed: A task of name '" << t->name() << "' is already owned by another node" ;
+ throw std::runtime_error( ss.str() );
+ }
+
+ t->set_parent(this);
+ if (position >= nodeVec_.size()) {
+ nodeVec_.push_back( t );
+ }
+ else {
+ nodeVec_.insert( nodeVec_.begin() + position, t);
+ }
+ add_remove_state_change_no_ = Ecf::incr_state_change_no();
+}
+
+void NodeContainer::add_family_only( family_ptr f, size_t position)
+{
+ if (f->parent()) {
+ std::stringstream ss;
+ ss << debugNodePath() << ": Add Family failed: A family of name '" << f->name() << "' is already owned by another node";
+ throw std::runtime_error( ss.str() );
+ }
+
+ f->set_parent(this);
+ if (position >= nodeVec_.size()) {
+ nodeVec_.push_back( f );
+ }
+ else {
+ nodeVec_.insert( nodeVec_.begin() + position, f);
+ }
+ add_remove_state_change_no_ = Ecf::incr_state_change_no();
+}
+
+
+void NodeContainer::addFamily(family_ptr f,size_t position)
+{
+ if (findFamily(f->name()).get()) {
+ std::stringstream ss;
+ ss << "Add Family failed: A Family of name '" << f->name() << "' already exist on node " << debugNodePath();
+ throw std::runtime_error( ss.str() );
+ }
+ add_family_only( f, position );
+}
+
+node_ptr NodeContainer::findImmediateChild(const std::string& theName, size_t& child_pos) const
+{
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) {
+ if (nodeVec_[t]->name() == theName) {
+ child_pos = t;
+ return nodeVec_[t];
+ }
+ }
+ child_pos = std::numeric_limits<std::size_t>::max();
+ return node_ptr();
+}
+
+node_ptr NodeContainer::find_node_up_the_tree(const std::string& the_name) const
+{
+ if (name() == the_name) {
+ return non_const_this();
+ }
+
+ size_t not_used;
+ node_ptr fnd_node = findImmediateChild(the_name,not_used);
+ if (fnd_node) return fnd_node;
+
+ Node* the_parent = parent();
+ if (the_parent) return the_parent->find_node_up_the_tree(the_name);
+ return node_ptr();
+}
+
+
+node_ptr NodeContainer::find_relative_node( const std::vector< std::string >& pathToNode)
+{
+//#ifdef DEBUG_FIND_NODE
+// cout << "NodeContainer::find_relative_node for '" << name()
+// << "' path = '" << pathToNode << "\n";
+// cout << " tasks = "; BOOST_FOREACH(task_ptr t, nodeVec_ ) { cout << " " << t->name(); } cout << "\n";
+// cout << " family = "; BOOST_FOREACH(family_ptr f, familyVec_ ) { cout << " " << f->name();} cout << "\n";
+//#endif
+ if (pathToNode.empty()) return node_ptr();
+ int pathSize = static_cast<int>(pathToNode.size());
+
+#ifdef DEBUG_FIND_NODE
+ cout << "NodeContainer::find_relative_node name = '" << name() << "' pathToNode[0] = '" << pathToNode[0] << "'\n";
+#endif
+
+ if (pathSize == 1 && name() == pathToNode[0]) {
+ // Match the Container i.e family or suite
+ return shared_from_this();
+ }
+
+ // Must match all children
+ int index = 0;
+ size_t child_pos = 0 ; // unused
+ node_ptr the_node = shared_from_this();
+ while (index < pathSize) {
+ the_node = the_node->findImmediateChild(pathToNode[index],child_pos);
+ if (the_node) {
+ if (index == pathSize - 1) return the_node;
+ index++;
+ }
+ else {
+ return node_ptr();
+ }
+ }
+ return node_ptr();
+}
+
+void NodeContainer::find_closest_matching_node( const std::vector< std::string >& pathToNode, int indexIntoPathNode, node_ptr& closest_matching_node )
+{
+ int pathSize = static_cast<int>(pathToNode.size());
+ if (indexIntoPathNode >= pathSize) return;
+
+ int index = indexIntoPathNode;
+ if (name() == pathToNode[indexIntoPathNode]) {
+
+ closest_matching_node = shared_from_this();
+
+ // Match the Container i.e family or suite
+ bool lastIndex = ( indexIntoPathNode == pathSize - 1);
+ if ( lastIndex ) {
+ return;
+ }
+
+ // Match the Children, i.e. go down the hierarchy
+ index++;
+ match_closest_children(pathToNode,index,closest_matching_node);
+ }
+}
+
+void NodeContainer::match_closest_children(const std::vector<std::string>& pathToNode, int indexIntoPathNode, node_ptr& closest_matching_node)
+{
+ int pathSize = static_cast<int>(pathToNode.size());
+ if (indexIntoPathNode >= pathSize) return;
+
+ bool lastIndex = ( indexIntoPathNode == pathSize - 1);
+ if ( lastIndex ) {
+ // even if the name matches, its only valid if the index is the last index
+ // i.e if we have a suite like /a/b/c/d/e
+ // and a path like /a/b/c/d/e/f/g
+ // In this we will match with e but it not valid since its not the last index
+ size_t task_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < task_vec_size; t++) {
+ if (nodeVec_[t]->name() == pathToNode[indexIntoPathNode]) {
+ closest_matching_node = nodeVec_[t];
+ return;
+ }
+ }
+ }
+ else {
+ // Path to node is of the form "/family/task" or "/family/family/task"
+ // Path to node is of the form "/suite/task" or "/suite/family/task"
+ size_t family_vec_size = nodeVec_.size();
+ for(size_t f = 0; f < family_vec_size; f++) {
+ Family* family = nodeVec_[f]->isFamily();
+ if (family) {
+ node_ptr matching_node;
+ family->find_closest_matching_node(pathToNode, indexIntoPathNode,matching_node);
+ if (matching_node.get()) {
+ closest_matching_node = matching_node;
+ return;
+ }
+ }
+ }
+ }
+}
+
+family_ptr NodeContainer::findFamily(const std::string& familyName) const
+{
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t f = 0; f < node_vec_size; f++) {
+ if (nodeVec_[f]->name() == familyName && nodeVec_[f]->isFamily()) {
+ return boost::dynamic_pointer_cast<Family>(nodeVec_[f]);
+ }
+ }
+ return family_ptr();
+}
+
+task_ptr NodeContainer::findTask(const std::string& taskName) const
+{
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) {
+ if (nodeVec_[t]->name() == taskName && nodeVec_[t]->isTask()) {
+ return boost::dynamic_pointer_cast<Task>(nodeVec_[t]);
+ }
+ }
+ return task_ptr();
+}
+
+bool NodeContainer::hasTimeDependencies() const
+{
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) { if (nodeVec_[t]->hasTimeDependencies()) return true;}
+ return false;
+}
+
+void NodeContainer::immediateChildren(std::vector<node_ptr>& theChildren) const
+{
+ size_t task_vec_size = nodeVec_.size();
+ theChildren.reserve( theChildren.size() + task_vec_size);
+ for(size_t t = 0; t < task_vec_size; t++) {
+ theChildren.push_back( nodeVec_[t] );
+ }
+}
+
+void NodeContainer::allChildren(std::set<Node*>& theSet) const
+{
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t f = 0; f < node_vec_size; f++) {
+ theSet.insert(nodeVec_[f].get());
+ nodeVec_[f]->allChildren(theSet);
+ }
+}
+
+void NodeContainer::getAllFamilies(std::vector<Family*>& vec) const
+{
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t f = 0; f < node_vec_size; f++) {
+ Family* family = nodeVec_[f]->isFamily();
+ if ( family ) {
+ vec.push_back(family);
+ family->getAllFamilies(vec);
+ }
+ }
+}
+
+void NodeContainer::getAllNodes(std::vector<Node*>& vec) const
+{
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) {
+ vec.push_back(nodeVec_[t].get());
+ nodeVec_[t]->getAllNodes(vec);
+ }
+}
+
+void NodeContainer::getAllTasks(std::vector<Task*>& tasks) const
+{
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) {
+ nodeVec_[t]->getAllTasks(tasks);
+ }
+}
+
+void NodeContainer::getAllSubmittables(std::vector<Submittable*>& tasks) const
+{
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) {
+ nodeVec_[t]->getAllSubmittables(tasks);
+ }
+}
+
+void NodeContainer::get_all_active_submittables(std::vector<Submittable*>& tasks) const
+{
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) {
+ nodeVec_[t]->get_all_active_submittables(tasks);
+ }
+}
+
+void NodeContainer::get_all_tasks(std::vector<task_ptr>& tasks) const
+{
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) {
+ nodeVec_[t]->get_all_tasks(tasks);
+ }
+}
+
+void NodeContainer::get_all_nodes(std::vector<node_ptr>& nodes) const
+{
+ nodes.push_back(non_const_this());
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) {
+ nodeVec_[t]->get_all_nodes(nodes);
+ }
+}
+
+void NodeContainer::get_all_aliases(std::vector<alias_ptr>& aliases) const
+{
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) {
+ nodeVec_[t]->get_all_aliases(aliases);
+ }
+}
+
+void NodeContainer::getAllAstNodes(std::set<Node*>& vec) const
+{
+ Node::getAllAstNodes(vec);
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) { nodeVec_[t]->getAllAstNodes(vec); }
+}
+
+bool NodeContainer::check(std::string& errorMsg, std::string& warningMsg) const
+{
+ Node::check(errorMsg, warningMsg);
+
+ // recursive to handle hierarchical families
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) {
+ nodeVec_[t]->check(errorMsg,warningMsg);
+ // if (!errorMsg.empty()) break;
+ }
+
+ return errorMsg.empty();
+}
+
+std::vector<task_ptr> NodeContainer::taskVec() const
+{
+ size_t node_vec_size = nodeVec_.size();
+ std::vector<task_ptr> vec; vec.reserve(node_vec_size);
+ for(size_t t = 0; t < node_vec_size; t++) {
+ if (nodeVec_[t]->isTask()) {
+ vec.push_back( boost::dynamic_pointer_cast<Task>(nodeVec_[t]) );
+ }
+ }
+ return vec;
+}
+
+std::vector<family_ptr> NodeContainer::familyVec() const
+{
+ std::vector<family_ptr> vec;
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) {
+ if (nodeVec_[t]->isFamily()) {
+ vec.push_back( boost::dynamic_pointer_cast<Family>(nodeVec_[t]) );
+ }
+ }
+ return vec;
+}
+
+bool NodeContainer::operator==(const NodeContainer& rhs) const
+{
+ size_t node_vec_size = nodeVec_.size();
+ if ( node_vec_size != rhs.nodeVec_.size()) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "NodeContainer::operator== node_vec_size != rhs.nodeVec_.size() " << absNodePath() << "\n";
+ std::cout << " nodeVec_.size() = " << node_vec_size << " rhs.nodeVec_.size() = " << rhs.nodeVec_.size() << "\n";
+ }
+#endif
+ return false;
+ }
+
+ for(size_t i =0; i < node_vec_size; ++i) {
+
+ Task* task = nodeVec_[i]->isTask();
+ if (task) {
+ Task* rhs_task = rhs.nodeVec_[i]->isTask();
+ if ( !rhs_task ) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "NodeContainer::operator== if ( !rhs_task ) " << absNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+
+ if ( !( *task == *rhs_task )) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "NodeContainer::operator== if ( !( *task == *rhs_task )) " << absNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ }
+ else {
+ Family* rhs_family = rhs.nodeVec_[i]->isFamily();
+ if ( !rhs_family ) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "NodeContainer::operator== if ( !rhs_family ) " << absNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+
+ Family* family = nodeVec_[i]->isFamily(); LOG_ASSERT( family, "" );
+ if ( !( *family == *rhs_family )) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "NodeContainer::operator== if ( !( *family == *rhs_family )) " << absNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ }
+ }
+
+ return Node::operator==(rhs);
+}
+
+std::ostream& NodeContainer::print(std::ostream& os) const
+{
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) { nodeVec_[t]->print( os ); }
+ return os;
+}
+
+bool NodeContainer::checkInvariants(std::string& errorMsg) const
+{
+ if (!Node::checkInvariants(errorMsg)) return false;
+
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) {
+ if (nodeVec_[t]->parent() != this) {
+ errorMsg += "NodeContainer::checkInvariants family/task parent() not correct";
+ return false;
+ }
+ if (!nodeVec_[t]->checkInvariants(errorMsg)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void NodeContainer::verification(std::string& errorMsg) const
+{
+ Node::verification(errorMsg);
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) { nodeVec_[t]->verification(errorMsg); }
+}
+
+void NodeContainer::setRepeatToLastValueHierarchically()
+{
+ setRepeatToLastValue();
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) { nodeVec_[t]->setRepeatToLastValueHierarchically(); }
+}
+
+void NodeContainer::setStateOnlyHierarchically(NState::State s,bool force)
+{
+ setStateOnly(s,force);
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) { nodeVec_[t]->setStateOnlyHierarchically(s,force); }
+}
+
+void NodeContainer::set_state_hierarchically(NState::State s, bool force)
+{
+ setStateOnlyHierarchically(s,force);
+ if (force) {
+ // *force* is only set via ForceCmd.
+ update_limits(); // hierarchical
+ }
+ handleStateChange(); // non-hierarchical
+}
+
+void NodeContainer::update_limits()
+{
+ /// Only tasks can affect the limits, hence no point calling locally
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) { nodeVec_[t]->update_limits(); }
+}
+
+bool NodeContainer::doDeleteChild(Node* child)
+{
+ SuiteChanged1 changed(suite());
+ std::vector<node_ptr>::iterator theTaskEnd = nodeVec_.end();
+ for(std::vector<node_ptr>::iterator t = nodeVec_.begin(); t!=theTaskEnd; ++t) {
+ if ( (*t).get() == child) {
+ child->set_parent(NULL); // must set to NULL, allow it to be re-added to different parent
+ nodeVec_.erase(t);
+ add_remove_state_change_no_ = Ecf::incr_state_change_no();
+ set_most_significant_state_up_node_tree();
+ return true;
+ }
+ if ((*t)->doDeleteChild(child)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void NodeContainer::check_job_creation( job_creation_ctrl_ptr jobCtrl) {
+
+ if (defStatus() != DState::COMPLETE) {
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) { nodeVec_[t]->check_job_creation( jobCtrl ); }
+ }
+}
+
+void NodeContainer::generate_scripts( const std::map<std::string,std::string>& override) const
+{
+ size_t node_vec_size = nodeVec_.size();
+ for(size_t t = 0; t < node_vec_size; t++) {
+ nodeVec_[t]->generate_scripts( override );
+ }
+}
diff --git a/ANode/src/NodeContainer.hpp b/ANode/src/NodeContainer.hpp
new file mode 100644
index 0000000..737ce69
--- /dev/null
+++ b/ANode/src/NodeContainer.hpp
@@ -0,0 +1,151 @@
+#ifndef NODE_CONTAINER_HPP_
+#define NODE_CONTAINER_HPP_
+
+//============================================================================
+// Name : NodeContainer.hpp
+// Author : Avi
+// Revision : $Revision: #88 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : A class that holds families and tasks
+//============================================================================
+
+#include <limits>
+#include "Node.hpp"
+
+class NodeContainer : public Node {
+public:
+ NodeContainer ( const std::string& name );
+ NodeContainer();
+ virtual ~NodeContainer();
+
+ virtual void accept(ecf::NodeTreeVisitor&);
+ virtual void acceptVisitTraversor(ecf::NodeTreeVisitor& v);
+ virtual void begin();
+ virtual void requeue( bool resetRepeats,
+ int clear_suspended_in_child_nodes,
+ bool reset_next_time_slot);
+ virtual void requeue_time_attrs();
+ virtual void resetRelativeDuration();
+ virtual bool run(JobsParam& jobsParam, bool force);
+ virtual void kill(const std::string& zombie_pid = "");
+ virtual void status();
+ virtual void top_down_why(std::vector<std::string>& theReasonWhy) const;
+ virtual void collateChanges(DefsDelta&) const;
+ void set_memento(const OrderMemento*,std::vector<ecf::Aspect::Type>& aspects );
+ void set_memento(const ChildrenMemento*,std::vector<ecf::Aspect::Type>& aspects );
+ virtual void order(Node* immediateChild, NOrder::Order);
+
+ virtual bool hasAutoCancel() const;
+ virtual void calendarChanged(const ecf::Calendar&,std::vector<node_ptr>& auto_cancelled_nodes,const ecf::LateAttr* inherited_late);
+ virtual bool resolveDependencies(JobsParam& );
+ virtual bool check(std::string& errorMsg, std::string& warningMsg) const;
+
+ task_ptr add_task(const std::string& task_name);
+ family_ptr add_family(const std::string& family_name);
+ void addTask( task_ptr , size_t position = std::numeric_limits<std::size_t>::max());
+ void addFamily( family_ptr, size_t position = std::numeric_limits<std::size_t>::max());
+
+ virtual void immediateChildren(std::vector<node_ptr>&) const;
+ virtual void allChildren(std::set<Node*>&) const;
+
+ virtual node_ptr findImmediateChild(const std::string& name,size_t& child_pos) const;
+ virtual node_ptr find_node_up_the_tree(const std::string& name) const;
+
+ virtual node_ptr find_relative_node(const std::vector<std::string>& pathToNode);
+ void find_closest_matching_node( const std::vector< std::string >& pathToNode, int indexIntoPathNode, node_ptr& closest_matching_node );
+
+ family_ptr findFamily(const std::string& familyName) const;
+ task_ptr findTask(const std::string& taskName) const;
+ void getAllFamilies(std::vector<Family*>&) const;
+ virtual void getAllNodes(std::vector<Node*>&) const;
+ virtual void getAllTasks(std::vector<Task*>&) const;
+ virtual void getAllSubmittables(std::vector<Submittable*>&) const;
+ virtual void get_all_active_submittables(std::vector<Submittable*>&) const;
+ virtual void get_all_tasks(std::vector<task_ptr>&) const;
+ virtual void get_all_nodes(std::vector<node_ptr>&) const;
+ virtual void get_all_aliases(std::vector<alias_ptr>&) const;
+ virtual void getAllAstNodes(std::set<Node*>&) const;
+ const std::vector<node_ptr>& nodeVec() const { return nodeVec_;}
+ std::vector<task_ptr> taskVec() const;
+ std::vector<family_ptr> familyVec() const;
+
+ std::ostream& print(std::ostream&) const;
+ bool operator==(const NodeContainer& rhs) const;
+
+ virtual bool hasTimeDependencies() const;
+
+ virtual void check_job_creation( job_creation_ctrl_ptr jobCtrl);
+ virtual void generate_scripts( const std::map<std::string,std::string>& override) const;
+
+ virtual bool checkInvariants(std::string& errorMsg) const;
+ virtual void verification(std::string& errorMsg) const;
+
+ virtual NState::State computedState(Node::TraverseType) const;
+
+ virtual node_ptr removeChild( Node* child);
+ virtual bool addChild( node_ptr child,size_t position = std::numeric_limits<std::size_t>::max());
+ virtual bool isAddChildOk( Node* child, std::string& errorMsg) const;
+
+ virtual void setRepeatToLastValueHierarchically();
+ virtual void setStateOnlyHierarchically(NState::State s,bool force = false);
+ virtual void set_state_hierarchically(NState::State s, bool force);
+ virtual void update_limits();
+
+private:
+ virtual size_t child_position(const Node*) const;
+ void add_task_only( task_ptr ,size_t position = std::numeric_limits<std::size_t>::max());
+ void add_family_only( family_ptr ,size_t position = std::numeric_limits<std::size_t>::max());
+
+ void handle_defstatus_propagation();
+ void match_closest_children(const std::vector<std::string>& pathToNode, int indexIntoPathToNode,node_ptr& closest_matching_node);
+
+ virtual void handleStateChange(); // called when a state change happens
+
+ friend class Defs;
+ friend class Family;
+ virtual bool doDeleteChild(Node* child);
+
+ /// For use by python interface,
+ std::vector<node_ptr>::const_iterator node_begin() const { return nodeVec_.begin();}
+ std::vector<node_ptr>::const_iterator node_end() const { return nodeVec_.end();}
+ friend void export_SuiteAndFamily();
+
+protected:
+ unsigned int order_state_change_no_; // no need to persist
+ unsigned int add_remove_state_change_no_;// no need to persist
+
+ void incremental_changes( DefsDelta& changes, compound_memento_ptr& comp) const;
+
+private:
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/)
+ {
+ ar.register_type(static_cast<Task *>(NULL));
+ ar.register_type(static_cast<Family *>(NULL));
+
+ // serialise base class information
+ ar & boost::serialization::base_object<Node>(*this);
+ ar & nodeVec_;
+
+ // Setup the parent pointers. Since they are not serialised
+ if (Archive::is_loading::value) {
+ size_t vec_size = nodeVec_.size();
+ for(size_t i = 0; i < vec_size; i++) {
+ nodeVec_[i]->set_parent(this);
+ }
+ }
+ }
+
+private:
+ std::vector<node_ptr> nodeVec_;
+};
+
+#endif
diff --git a/ANode/src/NodeDelete.cpp b/ANode/src/NodeDelete.cpp
new file mode 100644
index 0000000..9a56fca
--- /dev/null
+++ b/ANode/src/NodeDelete.cpp
@@ -0,0 +1,272 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #26 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include "Node.hpp"
+#include "ExprAst.hpp"
+#include "Stl.hpp"
+#include "Ecf.hpp"
+
+using namespace ecf;
+using namespace std;
+
+void Node::deleteTime(const std::string& name )
+{
+ if (time_dep_attrs_) {
+ time_dep_attrs_->deleteTime(name);
+ return;
+ }
+ throw std::runtime_error("Node::delete_time: Can not find time attribute: ");
+}
+
+void Node::delete_time( const ecf::TimeAttr& attr )
+{
+ if (time_dep_attrs_) {
+ time_dep_attrs_->delete_time(attr);
+ return;
+ }
+ throw std::runtime_error("Node::delete_time: Can not find time attribute: ");
+}
+
+void Node::deleteToday(const std::string& name)
+{
+ if (time_dep_attrs_) {
+ time_dep_attrs_->deleteToday(name);
+ return;
+ }
+ throw std::runtime_error("Node::delete_today: Can not find today attribute: ");
+}
+
+void Node::delete_today(const ecf::TodayAttr& attr)
+{
+ if (time_dep_attrs_) {
+ time_dep_attrs_->delete_today(attr);
+ return;
+ }
+ throw std::runtime_error("Node::delete_today: Can not find today attribute: " + attr.toString());
+}
+
+void Node::deleteDate(const std::string& name)
+{
+ if (time_dep_attrs_) {
+ time_dep_attrs_->deleteDate(name);
+ return;
+ }
+ throw std::runtime_error("Node::delete_date: Can not find date attribute: ");
+}
+
+void Node::delete_date(const DateAttr& attr)
+{
+ if (time_dep_attrs_) {
+ time_dep_attrs_->delete_date(attr);
+ return;
+ }
+ throw std::runtime_error("Node::delete_date: Can not find date attribute: " + attr.toString());
+}
+
+void Node::deleteDay(const std::string& name)
+{
+ if (time_dep_attrs_) {
+ time_dep_attrs_->deleteDay(name);
+ return;
+ }
+ throw std::runtime_error("Node::delete_day: Can not find day attribute: ");
+}
+
+void Node::delete_day(const DayAttr& attr)
+{
+ if (time_dep_attrs_) {
+ time_dep_attrs_->delete_day(attr);
+ return;
+ }
+ throw std::runtime_error("Node::delete_day: Can not find day attribute: " + attr.toString());
+}
+
+void Node::deleteCron(const std::string& name)
+{
+ if (time_dep_attrs_) {
+ time_dep_attrs_->deleteCron(name);
+ return;
+ }
+ throw std::runtime_error("Node::delete_cron: Can not find cron attribute: ");
+}
+
+void Node::delete_cron(const ecf::CronAttr& attr)
+{
+ if (time_dep_attrs_) {
+ time_dep_attrs_->delete_cron(attr);
+ return;
+ }
+ throw std::runtime_error("Node::delete_cron: Can not find cron attribute: " + attr.toString());
+}
+
+void Node::deleteVariable( const std::string& name)
+{
+ if (name.empty()) {
+ varVec_.clear(); // delete all
+ state_change_no_ = Ecf::incr_state_change_no();
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Node::deleteVariable\n";
+#endif
+ return;
+ }
+
+ size_t theSize = varVec_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ if (varVec_[i].name() == name) {
+ varVec_.erase( varVec_.begin() + i );
+ state_change_no_ = Ecf::incr_state_change_no();
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Node::deleteVariable\n";
+#endif
+ return;
+ }
+ }
+ throw std::runtime_error("Node::deleteVariable: Can not find variable of name " + name);
+}
+
+void Node::deleteEvent(const std::string& name)
+{
+ if (child_attrs_) {
+ child_attrs_->deleteEvent(name);
+ return;
+ }
+ throw std::runtime_error("Node::deleteEvent: Can not find event: " + name);
+}
+
+void Node::deleteMeter(const std::string& name)
+{
+ if (child_attrs_) {
+ child_attrs_->deleteMeter(name);
+ return;
+ }
+ throw std::runtime_error("Node::deleteMeter: Can not find meter: " + name);
+}
+
+void Node::deleteLabel(const std::string& name)
+{
+ if (child_attrs_) {
+ child_attrs_->deleteLabel(name);
+ return;
+ }
+ throw std::runtime_error("Node::deleteLabel: Can not find label: " + name);
+}
+
+void Node::deleteTrigger()
+{
+ if (triggerExpr_) {
+ delete triggerExpr_; triggerExpr_ = NULL;
+ state_change_no_ = Ecf::incr_state_change_no();
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Node::deleteTrigger()\n";
+#endif
+ }
+}
+
+void Node::deleteComplete()
+{
+ if (completeExpr_) {
+ delete completeExpr_; completeExpr_ = NULL;
+ state_change_no_ = Ecf::incr_state_change_no();
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Node::deleteComplete()\n";
+#endif
+ }
+}
+
+void Node::deleteRepeat()
+{
+ if (!repeat_.empty()) {
+ repeat_.clear(); // will delete the pimple
+ state_change_no_ = Ecf::incr_state_change_no();
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Node::deleteRepeat())\n";
+#endif
+ }
+}
+
+void Node::deleteLimit(const std::string& name)
+{
+ if (name.empty()) {
+ limitVec_.clear();
+ state_change_no_ = Ecf::incr_state_change_no();
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Node::deleteLimit\n";
+#endif
+ return;
+ }
+
+ size_t theSize = limitVec_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ if (limitVec_[i]->name() == name) {
+ limitVec_.erase( limitVec_.begin() + i );
+ state_change_no_ = Ecf::incr_state_change_no();
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Node::deleteLimit\n";
+#endif
+ return;
+ }
+ }
+ throw std::runtime_error("Node::deleteLimit: Can not find limit: " + name);
+}
+
+void Node::delete_limit_path(const std::string& name,const std::string& path)
+{
+ if (name.empty()) {
+ throw std::runtime_error("Node::delete_limit_path: the limit name must be provided");
+ }
+ if (path.empty()) {
+ throw std::runtime_error("Node::delete_limit_path: the limit path must be provided");
+ }
+
+ size_t theSize = limitVec_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ if (limitVec_[i]->name() == name) {
+ limitVec_[i]->delete_path(path); // will update state change no
+ return;
+ }
+ }
+ throw std::runtime_error("Node::delete_limit_path: Can not find limit: " + name);
+}
+
+void Node::deleteInlimit(const std::string& name)
+{
+ // if name exists but no corresponding in limit found raises an exception
+ if (inLimitMgr_.deleteInlimit(name)) {
+ state_change_no_ = Ecf::incr_state_change_no();
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Node::deleteInlimit\n";
+#endif
+ }
+}
+
+void Node::deleteZombie(const std::string& zombie_type)
+{
+ if (misc_attrs_) misc_attrs_->deleteZombie(zombie_type);
+}
+
+void Node::delete_zombie(Child::ZombieType zt)
+{
+ if (misc_attrs_) misc_attrs_->delete_zombie(zt);
+}
+
+void Node::deleteLate()
+{
+ delete lateAttr_;
+ lateAttr_ = NULL;
+ state_change_no_ = Ecf::incr_state_change_no();
+}
+
+
diff --git a/ANode/src/NodeFind.cpp b/ANode/src/NodeFind.cpp
new file mode 100644
index 0000000..d21d133
--- /dev/null
+++ b/ANode/src/NodeFind.cpp
@@ -0,0 +1,781 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #53 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "Node.hpp"
+#include "Str.hpp"
+#include "NodePath.hpp"
+#include "Defs.hpp"
+#include "Log.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+
+/// Output a vector to cout
+template<class T>
+ostream& operator<<(ostream& os, const vector<T>& v)
+{
+ copy(v.begin(), v.end(), ostream_iterator<T>(cout, " "));
+ return os;
+}
+
+bool Node::findParentVariableValue(const std::string& name, std::string& theValue) const
+{
+ if (findVariableValue(name,theValue)) return true;
+ const Repeat& repeat = findRepeat(name);
+ if (!repeat.empty()) { theValue = repeat.valueAsString(); return true; }
+ if (findGenVariableValue(name,theValue)) return true;
+
+
+ Node* theParent = parent();
+ while (theParent) {
+
+ if (theParent->findVariableValue(name,theValue)) return true;
+ const Repeat& repeatVar = theParent->findRepeat(name);
+ if (!repeatVar.empty()) { theValue = repeatVar.valueAsString(); return true; }
+ if (theParent->findGenVariableValue(name,theValue)) return true;
+
+ theParent = theParent->parent();
+ }
+
+ // If all else fails search defs environment, returns empty string if match not found
+ // The defs environment is constructed via:
+ // o/ default settings for ECF_HOME,ECF_LOG, ECF_CHECK,ECF_CHECKOLD,ECF_CHECKINTERVAL
+ // ECF_INTERVAL ECF_CHECKMODE ECF_JOB_CMD ECF_MICRO ECF_TRIES ECF_PORT, ECF_NODE
+ // o/ These values are updated from the server environment when the BEGIN cmd is called.
+ Defs* the_defs = defs();
+ if ( the_defs ) {
+ theValue = the_defs->server().find_variable(name);
+ if ( !theValue.empty() ) return true;
+ }
+ return false; // the variable can not be found
+}
+
+bool Node::find_parent_gen_variable_value(const std::string& name, std::string& theValue) const
+{
+ if (findGenVariableValue(name,theValue)) return true;
+
+ Node* theParent = parent();
+ while (theParent) {
+ if (theParent->findGenVariableValue(name,theValue)) return true;
+ theParent = theParent->parent();
+ }
+
+ // If all else fails search defs environment, returns empty string if match not found
+ // The defs environment is constructed via:
+ // o/ default settings for ECF_HOME,ECF_LOG, ECF_CHECK,ECF_CHECKOLD,ECF_CHECKINTERVAL
+ // ECF_INTERVAL ECF_CHECKMODE ECF_JOB_CMD ECF_MICRO ECF_TRIES ECF_PORT, ECF_NODE
+ // o/ These values are updated from the server environment when the BEGIN cmd is called.
+ Defs* the_defs = defs();
+ if ( the_defs ) {
+ theValue = the_defs->server().find_variable(name);
+ if ( !theValue.empty() ) return true;
+ }
+ return false; // the variable can not be found
+}
+
+bool Node::findParentUserVariableValue(const std::string& name, std::string& theValue) const
+{
+ if (findVariableValue(name,theValue)) return true;
+
+ Node* theParent = parent();
+ while (theParent) {
+ if (theParent->findVariableValue(name,theValue)) return true;
+ theParent = theParent->parent();
+ }
+
+ // If all else fails search defs environment, returns empty string if match not found
+ Defs* the_defs = defs();
+ if ( the_defs ) {
+ // Note: when calling ecflow_client --get_state=/suite/task
+ // The node can be detached from the defs.
+ theValue = the_defs->server().find_variable(name);
+ if ( !theValue.empty() ) return true;
+ }
+ return false; // the variable can not be found
+}
+
+const std::string& Node::find_parent_user_variable_value(const std::string& name) const
+{
+ const Variable& var = findVariable(name);
+ if (!var.empty()) return var.theValue();
+
+ Node* theParent = parent();
+ while (theParent) {
+ const Variable& pvar = theParent->findVariable(name);
+ if (!pvar.empty()) return pvar.theValue();
+ theParent = theParent->parent();
+ }
+
+ Defs* the_defs = defs();
+ if ( the_defs ) {
+ // Note: when calling ecflow_client --get_state=/suite/task
+ // The node can be detached from the defs.
+ return the_defs->server().find_variable(name);
+ }
+ return Str::EMPTY();
+}
+
+bool Node::user_variable_exists(const std::string& name) const
+{
+ const Variable& var = findVariable(name);
+ if (!var.empty()) return true;
+
+ Node* theParent = parent();
+ while (theParent) {
+ const Variable& pvar = theParent->findVariable(name);
+ if (!pvar.empty()) return true;
+ theParent = theParent->parent();
+ }
+
+ // If all else fails search defs environment, returns empty string if match not found
+ Defs* the_defs = defs();
+ if ( the_defs ) {
+ // Note: when calling ecflow_client --get_state=/suite/task
+ // The node can be detached from the defs.
+ return the_defs->server().variable_exists(name);
+ }
+ return false;
+}
+
+const Variable& Node::findVariable(const std::string& name) const
+{
+ size_t theSize = varVec_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ if (varVec_[i].name() == name) {
+ return varVec_[i];
+ }
+ }
+ return Variable::EMPTY();
+}
+
+const Variable& Node::find_parent_variable(const std::string& name) const
+{
+ const Variable& var = findVariable(name);
+ if (!var.empty()) return var;
+
+ Node* theParent = parent();
+ while (theParent) {
+ const Variable& pvar = theParent->findVariable(name);
+ if (!pvar.empty()) return pvar;
+ theParent = theParent->parent();
+ }
+
+ // If all else fails search defs environment
+ Defs* the_defs = defs();
+ if ( the_defs ) {
+ return the_defs->server().findVariable(name);
+ }
+
+ return Variable::EMPTY();
+}
+
+bool Node::findVariableValue( const std::string& name, std::string& returnedValue) const
+{
+ const Variable& var = findVariable(name);
+ if (!var.empty()) {
+ returnedValue = var.theValue();
+ return true;
+ }
+ return false;
+}
+
+bool Node::findGenVariableValue( const std::string& name, std::string& returnedValue) const
+{
+ const Variable& genVar = findGenVariable(name);
+ if (!genVar.empty()) {
+ returnedValue = genVar.theValue();
+ return true;
+ }
+ return false;
+}
+
+
+bool Node::findLimit(const Limit& theLimit) const
+{
+ size_t theSize = limitVec_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ if (limitVec_[i]->name() == theLimit.name()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+limit_ptr Node::find_limit(const std::string& theName) const
+{
+ size_t theSize = limitVec_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ if (limitVec_[i]->name() == theName) {
+ return limitVec_[i];
+ }
+ }
+ return limit_ptr();
+}
+
+limit_ptr Node::findLimitUpNodeTree(const std::string& name) const
+{
+ limit_ptr theFndLimit = find_limit(name);
+ if (theFndLimit.get()) return theFndLimit;
+
+ Node* theParent = parent();
+ while (theParent != NULL) {
+
+ limit_ptr theFndLimit = theParent->find_limit(name);
+ if (theFndLimit.get()) return theFndLimit;
+
+ theParent = theParent->parent();
+ }
+ return limit_ptr();
+}
+
+
+const Event& Node::findEvent(const Event& theEvent) const
+{
+ if (child_attrs_) return child_attrs_->findEvent(theEvent);
+ return Event::EMPTY();
+}
+
+const Event& Node::findEventByNumber(int number) const
+{
+ if (child_attrs_) return child_attrs_->findEventByNumber(number);
+ return Event::EMPTY();
+}
+
+const Event& Node::findEventByName( const std::string& event_name) const
+{
+ if (child_attrs_) return child_attrs_->findEventByName(event_name);
+ return Event::EMPTY();
+}
+
+const Event& Node::findEventByNameOrNumber( const std::string& theName) const
+{
+ if (child_attrs_) return child_attrs_->findEventByNameOrNumber(theName);
+ return Event::EMPTY();
+}
+const Meter& Node::findMeter(const std::string& name) const
+{
+ if (child_attrs_) return child_attrs_->findMeter(name);
+ return Meter::EMPTY();
+}
+
+Meter& Node::find_meter(const std::string& name)
+{
+ if (child_attrs_) return child_attrs_->find_meter(name);
+ return const_cast<Meter&>(Meter::EMPTY());
+}
+
+bool Node::findLabel(const std::string& name) const
+{
+ if (child_attrs_) return child_attrs_->findLabel(name);
+ return false;
+}
+
+const Label& Node::find_label(const std::string& name) const
+{
+ if (child_attrs_) return child_attrs_->find_label(name);
+ return Label::EMPTY();
+}
+
+bool Node::findVerify(const VerifyAttr& v) const
+{
+ if (misc_attrs_) return misc_attrs_->findVerify(v);
+ return false;
+}
+
+const Repeat& Node::findRepeat(const std::string& name) const
+{
+ if (!repeat_.empty() && repeat_.name() == name) {
+ return repeat_;
+ }
+ return Repeat::EMPTY();
+}
+
+
+bool Node::findExprVariable( const std::string& name)
+{
+ // if event found return true. also mark this event so simulator know its used in a trigger
+ if ( set_event_used_in_trigger(name) ) {
+ return true;
+ }
+
+ // if meter found mark as used in trigger for simulator and return
+ if ( set_meter_used_in_trigger(name) ) {
+ return true;
+ }
+
+ const Variable& user_variable = findVariable( name );
+ if (!user_variable.empty()) return true;
+
+ const Repeat& repeat = findRepeat( name );
+ if (!repeat.empty()) return true;
+
+ const Variable& gen_variable = findGenVariable( name );
+ if (!gen_variable.empty()) return true;
+
+ return false;
+}
+
+int Node::findExprVariableValue( const std::string& name) const
+{
+ const Event& event = findEventByNameOrNumber( name );
+ if ( !event.empty() ) return (event.value() ? 1 : 0);
+
+ const Meter& meter = findMeter( name );
+ if ( !meter.empty() ) return meter.value();
+
+ const Variable& variable = findVariable( name );
+ if ( !variable.empty() ) return variable.value();
+
+ const Repeat& repeat = findRepeat( name );
+ if ( !repeat.empty() ) {
+ // RepeatDate last_valid_value() returns the date by its real value as a long
+ // RepeatInteger last_valid_value() returns the value, by the current value of integer
+ // RepeatEnumerated last_valid_value() returns the current value if cast-able to integer otherwise position/index,
+ // (i.e. since enum can be anything)
+ // RepeatString last_valid_value() returns the current position/index ( Alternatives ? )
+ // RepeatDay last_valid_value() returns the current step
+ // Note: At Repeat expiration Repeat::value() may be out of range of start-end
+ // But Repeat::last_valid_value() should always be in range, hence at Repeat expiration
+ // will return the last valid value.
+ return repeat.last_valid_value();
+ }
+
+ const Variable& gen_variable = findGenVariable( name );
+ if ( !gen_variable.empty() ) return gen_variable.value();
+ return 0;
+}
+
+int Node::findExprVariableValueAndPlus(const std::string& name, int val) const
+{
+ const Event& event = findEventByNameOrNumber( name );
+ if ( !event.empty() ) return ((event.value() ? 1 : 0) + val);
+
+ const Meter& meter = findMeter( name );
+ if ( !meter.empty() ) return (meter.value() + val);
+
+ const Variable& variable = findVariable( name );
+ if ( !variable.empty() ) return (variable.value() + val);
+
+ const Repeat& repeat = findRepeat( name );
+ if ( !repeat.empty() ) {
+ // RepeatDate last_valid_value() returns the date by its real value as a long
+ // RepeatInteger last_valid_value() returns the value, by the current value of integer
+ // RepeatEnumerated last_valid_value() returns the current value if cast-able as integer otherwise position/index,
+ // (i.e. since enum can be anything)
+ // RepeatString last_valid_value() returns the current position/index ( Alternatives ? )
+ // RepeatDay last_valid_value() returns the current step
+ // Note: At Repeat expiration Repeat::value() may be out of range of start-end
+ // But Repeat::last_valid_value() should always be in range, hence at Repeat expiration
+ // will return the last valid value.
+ return repeat.last_valid_value_plus(val);
+ }
+
+ const Variable& gen_variable = findGenVariable( name );
+ if ( !gen_variable.empty() ) return (gen_variable.value()+val);
+ return val;
+}
+
+int Node::findExprVariableValueAndMinus(const std::string& name, int val) const
+{
+ const Event& event = findEventByNameOrNumber( name );
+ if ( !event.empty() ) return ( (event.value() ? 1 : 0) - val);
+
+ const Meter& meter = findMeter( name );
+ if ( !meter.empty() ) return (meter.value() - val );
+
+ const Variable& variable = findVariable( name );
+ if ( !variable.empty() ) return (variable.value() - val);
+
+ const Repeat& repeat = findRepeat( name );
+ if ( !repeat.empty() ) {
+ // RepeatDate last_valid_value() returns the date by its real value as a long
+ // RepeatInteger last_valid_value() returns the value, by the current value of integer
+ // RepeatEnumerated last_valid_value() returns the current value if cast-able as integer, else position/index, (
+ // i.e. since enum can be anything)
+ // RepeatString last_valid_value() returns the current position/index ( Alternatives ? )
+ // RepeatDay last_valid_value() returns the current step
+ // Note: At Repeat expiration Repeat::value() may be out of range of start-end
+ // But Repeat::last_valid_value() should always be in range, hence at Repeat expiration
+ // will return the last valid value.
+ return repeat.last_valid_value_minus(val);
+ }
+
+ const Variable& gen_variable = findGenVariable( name );
+ if ( !gen_variable.empty() ) return (gen_variable.value() - val);
+ return -val;
+}
+
+int Node::findExprVariableValueAndType( const std::string& name, std::string& varType) const
+{
+ const Event& event = findEventByNameOrNumber( name );
+ if ( !event.empty() ) {
+ varType = "event";
+ return (event.value() ? 1 : 0);
+ }
+ const Meter& meter = findMeter( name );
+ if ( !meter.empty() ) {
+ varType = "meter";
+ return meter.value();
+ }
+ const Variable& variable = findVariable( name );
+ if ( !variable.empty() ) {
+ varType = "user-variable";
+ return variable.value();
+ }
+ const Repeat& repeat = findRepeat( name );
+ if ( !repeat.empty() ) {
+ varType = "repeat";
+ return repeat.last_valid_value();
+ }
+ const Variable& gen_variable = findGenVariable( name );
+ if ( !gen_variable.empty() ) {
+ varType = "gen-variable";
+ return gen_variable.value();
+ }
+ varType = "variable-not-found";
+ return 0;
+}
+
+void Node::findExprVariableAndPrint( const std::string& name, ostream& os) const
+{
+ const Event& event = findEventByNameOrNumber( name );
+ if ( !event.empty() ) {
+ os << event.dump();
+ return;
+ }
+ const Meter& meter = findMeter( name );
+ if ( !meter.empty() ) {
+ os << meter.dump();
+ return;
+ }
+ const Variable& variable = findVariable( name );
+ if ( !variable.empty() ) {
+ os << "USER-VARIABLE " << variable.dump();
+ return;
+ }
+ const Repeat& repeat = findRepeat( name );
+ if ( !repeat.empty() ) {
+ os << repeat.dump();
+ return;
+ }
+ const Variable& gen_variable = findGenVariable( name );
+ if ( !gen_variable.empty() ) {
+ os << "GEN-VARIABLE " << gen_variable.dump();
+ return;
+ }
+}
+
+
+node_ptr findRelativeNode( const vector<std::string>& theExtractedPath,node_ptr triggerNode, std::string& errorMsg )
+{
+ // The referenced node could be itself(error) or most likely a sibling node.
+ int extractedPathSize = static_cast<int>(theExtractedPath.size());
+ if (extractedPathSize == 1 && triggerNode->name() == theExtractedPath[0]) {
+ // self referencing node ?
+ return triggerNode;
+ }
+
+ // Can only find *sibling* if triggerNode has a parent
+ if (!triggerNode->parent()) {
+ errorMsg = "Parent empty. Could not find referenced node\n";
+ return node_ptr();
+ }
+ if (extractedPathSize == 1) {
+ size_t child_pos; // not used
+ node_ptr theNode = triggerNode->parent()->findImmediateChild(theExtractedPath[0],child_pos);
+ if ( theNode.get() ) {
+ return theNode;
+ }
+ }
+
+ node_ptr constNode = triggerNode->parent()->find_relative_node(theExtractedPath);
+ if (constNode.get()) {
+ return constNode;
+ }
+
+ errorMsg = "Could not find node '";
+ if (extractedPathSize == 1) errorMsg += theExtractedPath[0];
+ else { BOOST_FOREACH(const string& s, theExtractedPath) { errorMsg += s; errorMsg += Str::PATH_SEPERATOR();} }
+ errorMsg += "' from node ";
+ errorMsg += triggerNode->absNodePath();
+ if (extractedPathSize == 1) {
+ errorMsg += " . Expected '";
+ errorMsg += theExtractedPath[0];
+ errorMsg += "' to be a sibling.";
+ }
+ errorMsg += "\n";
+ return node_ptr();
+}
+
+
+node_ptr Node::non_const_this() const {
+ return const_pointer_cast<Node>(shared_from_this());
+}
+
+node_ptr Node::findReferencedNode(const std::string& nodePath, std::string& errorMsg) const
+{
+ return findReferencedNode(nodePath,Str::EMPTY(),errorMsg);
+}
+node_ptr Node::findReferencedNode(const std::string& nodePath, const std::string& extern_obj, std::string& errorMsg) const
+{
+ Defs* theDefs = defs();
+ if (!theDefs) {
+ // In the case where we have a stand alone Node. i.e no parent set. The Defs will be NULL.
+ // Take the case where we want to dump the state of a single node.
+ // ecflow_client --get_state=/test/f2 --port=4141
+ // Here we are printing the state of the Node only, *NO* defs is returned.
+ // The print will cause the AST to be evaluated. The trigger evaluation will required chasing
+ // down reference nodes. Hence we will end up here. Rather than crashing, just return a NULL Pointer.
+ return node_ptr();
+ }
+
+ /// findReferencedNode:: is used to locate references:
+ /// a/ Trigger & complete expressions, this is where extern_obj is used.
+ /// b/ Inlimit nodepaths.
+ /// In *both* the case above, the node path may not exist, in the definition. Hence::
+ /// On client side:: references not defined in externs are considered errors
+ /// On server side:: No extern's are stored, hence for unresolved node paths, we return NULL
+
+#ifdef DEBUG_FIND_REFERENCED_NODE
+ string debug_path = "Searching for path " + nodePath + " from " + debugType() + Str::COLON() + absNodePath() + "\n";
+#endif
+
+ // if an absolute path cut in early
+ if (!nodePath.empty() && nodePath[0] == '/') {
+
+#ifdef DEBUG_FIND_REFERENCED_NODE
+ debug_path += "(!nodePath.empty() && nodePath[0] == '/') \n";
+#endif
+
+ // Must be a absolute path. i.e /suite/family/path
+ node_ptr constNode = theDefs->findAbsNode(nodePath);
+ if (constNode.get()) {
+ return constNode;
+ }
+
+ // *NOTE*: The server does *NOT* store externs, hence the check below, will always return false, for the server:
+ // Must be an extern:
+ // extern /referenceSuite/family/task:obj
+ // extern /referenceSuite/family/task
+ if (theDefs->find_extern(nodePath,extern_obj)) {
+
+ // =================================================================
+ // **Client side* specific: Only client side defs, stores extrens
+ // =================================================================
+#ifdef DEBUG_FIND_REFERENCED_NODE
+ debug_path += "theDefs->find_extern(nodePath) \n";
+#endif
+
+ // return NULL *without* setting an error message as node path is defined as an extern
+
+ // OK: the node path appears in the extern list. This may be because that suite has not been loaded.
+ // *** If the suite is loaded, then its an error that we did not
+ // *** locate the node. i.e in the previous call to defs->findAbsNode(nodePath);
+ vector<string> theExtractedPath;
+ NodePath::split(nodePath, theExtractedPath );
+
+ std::string referenceSuite = theExtractedPath[0];
+ if (theDefs->findSuite(referenceSuite)) {
+ // The suite referenced in the extern is LOADED, but path did not resolve,
+ // in previous call to defs->findAbsNode(nodePath);
+ errorMsg = "Extern path ";
+ errorMsg += nodePath;
+ errorMsg += " does not exist on suite ";
+ errorMsg += referenceSuite;
+ errorMsg += "\n";
+#ifdef DEBUG_FIND_REFERENCED_NODE
+ errorMsg += debug_path;
+#endif
+ }
+
+ // Its an extern path that references a suite thats NOT loaded yet
+ return node_ptr();
+ }
+
+ errorMsg = ": Could not find referenced node, using absolute path '";
+ errorMsg += nodePath;
+ errorMsg += "\n";
+ return node_ptr();
+ }
+
+ /// =============================================================================
+ /// Path is something other than ABSOLUTE path
+ /// =============================================================================
+ vector<string> theExtractedPath;
+ NodePath::split( nodePath, theExtractedPath );
+
+#ifdef DEBUG_FIND_REFERENCED_NODE
+ debug_path += "extracted path = ";
+ BOOST_FOREACH(const string& s, theExtractedPath) { debug_path += ",";debug_path += s;}
+ debug_path += "\n";
+#endif
+
+ if ( theExtractedPath.empty() ) {
+ std::stringstream ss;
+ ss << ": Could not find referenced node '" << nodePath << "' from node " << absNodePath() << "\n";
+ errorMsg = ss.str();
+#ifdef DEBUG_FIND_REFERENCED_NODE
+ errorMsg += debug_path;
+#endif
+ return node_ptr();
+ }
+
+
+ // i.e " a == complete" =====> nodePath = a
+ if ( theExtractedPath.size() == 1) {
+#ifdef DEBUG_FIND_REFERENCED_NODE
+ debug_path += "( theExtractedPath.size() == 1)\n";
+#endif
+ // Search for a relative node first
+ string localErrorMsg;
+ node_ptr res = findRelativeNode(theExtractedPath,non_const_this(),localErrorMsg);
+#ifdef DEBUG_FIND_REFERENCED_NODE
+ if (!localErrorMsg.empty()) {
+ debug_path += localErrorMsg;
+ localErrorMsg = debug_path;
+ }
+#endif
+
+ if (!res.get()) {
+ // lets see if its in an extern Node. extern can have absolute and relative paths
+ // In this case it will be a relative path, hence no point trying to see if suite
+ // is loaded
+ if (theDefs->find_extern(nodePath,extern_obj)) {
+ // =================================================================
+ // **Client side* specific: Only client side defs, stores externs
+ // =================================================================
+ // The path exist in the extern and we know its relative
+ return node_ptr();
+ }
+ }
+
+ errorMsg += localErrorMsg;
+ return res;
+ }
+
+ // handle Node path of type a/b/c
+ if (theExtractedPath.size() >= 2 && theExtractedPath[0] != "." && theExtractedPath[0] != "..") {
+#ifdef DEBUG_FIND_REFERENCED_NODE
+ debug_path += "(theExtractedPath.size() >= 2 && theExtractedPath[0] != \".\") && theExtractedPath[0] != \"..\"\n";
+#endif
+ // First check to see see if its in the externs
+ if (theDefs->find_extern(nodePath,extern_obj)) {
+ // =================================================================
+ // **Client side* specific: Only client side defs, stores externs
+ // =================================================================
+ // The path a/b/c exist in the extern and we know its relative
+ // Again no point in checking to see if suite is loaded if path is relative
+ return node_ptr();
+ }
+
+ // In this case its equivalent to: ./a/b/c
+ theExtractedPath.insert(theExtractedPath.begin(),".");
+ }
+
+ // node path == "./a"
+ if ( theExtractedPath.size() >= 2 && theExtractedPath[0] == ".") {
+#ifdef DEBUG_FIND_REFERENCED_NODE
+ debug_path += "theExtractedPath.size() == 2 && theExtractedPath[0] == \".\" \n";
+#endif
+ theExtractedPath.erase( theExtractedPath.begin() + 0);
+ node_ptr res = findRelativeNode(theExtractedPath,non_const_this(),errorMsg);
+#ifdef DEBUG_FIND_REFERENCED_NODE
+ if (!errorMsg.empty()) {
+ debug_path += errorMsg;
+ errorMsg = debug_path;
+ }
+#endif
+ return res;
+ }
+
+ // ********************************************************************
+ // Note ./ This means go to the parent, then search down, i.e sibling
+ // ../ This means go to the parents parent
+ // This may be confusing, but this is how Axel expects it, hence I will use
+ // the same understanding
+ // **********************************************************************
+ // Handle node path of the type "../a/b/c" "../../a/b/c"
+ if ( theExtractedPath.size() >= 2 && theExtractedPath[0] == "..") {
+
+#ifdef DEBUG_FIND_REFERENCED_NODE
+ debug_path += "( theExtractedPath.size() >= 2 && theExtractedPath[0] == \"..\")\n";
+#endif
+
+ Node* theParent = parent(); // get past the first parent
+ while ( static_cast<int>(theExtractedPath.size()) &&
+ theParent &&
+ theExtractedPath[0] == ".." )
+ {
+ theExtractedPath.erase( theExtractedPath.begin() + 0);
+ theParent = theParent->parent(); // for each .. go up a parent
+#ifdef DEBUG_FIND_REFERENCED_NODE
+ debug_path += "..: thepParent = ";
+ if (theParent) debug_path += theParent->absNodePath();
+ else debug_path += "NULL";
+#endif
+ }
+
+ if ( theParent ) {
+
+#ifdef DEBUG_FIND_REFERENCED_NODE
+ debug_path += "searching = " + theParent->name() + "\n";
+ BOOST_FOREACH(const std::string& s , theExtractedPath) { debug_path += Str::PATH_SEPERATOR() + s; }
+ debug_path += "\n";
+#endif
+
+ node_ptr constNode = theParent->find_relative_node(theExtractedPath);
+ if (constNode) {
+ return constNode;
+ }
+ }
+ }
+
+ errorMsg = "Unrecognised path ";
+ errorMsg += nodePath;
+ errorMsg += " for Node ";
+ errorMsg += absNodePath();
+ errorMsg += "\n";
+#ifdef DEBUG_FIND_REFERENCED_NODE
+ errorMsg += debug_path;
+#endif
+ return node_ptr();
+}
+
+const ZombieAttr& Node::findZombie( ecf::Child::ZombieType zombie_type) const
+{
+ if (misc_attrs_) return misc_attrs_->findZombie(zombie_type);
+ return ZombieAttr::EMPTY();
+}
+
+bool Node::findParentZombie(ecf::Child::ZombieType z_type, ZombieAttr& z) const
+{
+ const ZombieAttr& the_zombie = findZombie(z_type);
+ if ( !the_zombie.empty() ) {
+ z = the_zombie;
+ return true;
+ }
+
+ Node* theParent = parent();
+ while (theParent) {
+ const ZombieAttr& the_zombie = theParent->findZombie(z_type);
+ if ( !the_zombie.empty() ) {
+ z = the_zombie;
+ return true;
+ }
+ theParent = theParent->parent();
+ }
+ return false;
+}
diff --git a/ANode/src/NodeFwd.hpp b/ANode/src/NodeFwd.hpp
new file mode 100644
index 0000000..0a0287a
--- /dev/null
+++ b/ANode/src/NodeFwd.hpp
@@ -0,0 +1,107 @@
+#ifndef NODE_FWD_HPP_
+#define NODE_FWD_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #44 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+#include <vector>
+#include <string>
+#include <map>
+
+class AbstractObserver;
+class Suite;
+class Family;
+class Task;
+class Alias;
+class Submittable;
+class Node;
+class Defs;
+class Repeat;
+class Expression;
+class Memento;
+class CompoundMemento;
+class ClockAttr;
+class JobCreationCtrl;
+class Event;
+class Meter;
+class Repeat;
+class Variable;
+
+namespace ecf { class LateAttr; class AutoCancelAttr; } // forward declare class
+
+typedef boost::shared_ptr<Memento> memento_ptr;
+typedef boost::shared_ptr<CompoundMemento> compound_memento_ptr;
+typedef boost::shared_ptr<ClockAttr> clock_ptr;
+
+typedef boost::shared_ptr<JobCreationCtrl> job_creation_ctrl_ptr;
+typedef boost::shared_ptr<Node> node_ptr;
+typedef boost::shared_ptr<Task> task_ptr;
+typedef boost::shared_ptr<Alias> alias_ptr;
+typedef boost::shared_ptr<Submittable> submittable_ptr;
+typedef boost::shared_ptr<Family> family_ptr;
+typedef boost::shared_ptr<Suite> suite_ptr;
+typedef boost::shared_ptr<Defs> defs_ptr;
+
+typedef boost::weak_ptr<Defs> weak_defs_ptr;
+typedef boost::weak_ptr<Suite> weak_suite_ptr;
+typedef boost::weak_ptr<Task> weak_task_ptr;
+typedef boost::weak_ptr<Alias> weak_alias_ptr;
+typedef boost::weak_ptr<Submittable> weak_submittable_ptr;
+typedef boost::weak_ptr<Node> weak_node_ptr;
+
+typedef std::map<std::string,std::string> NameValueMap;
+
+typedef std::vector< std::pair< std::string,std::string> > NameValueVec;
+
+
+class NodeContainer;
+class DefsDelta;
+class JobsParam;
+class JobCreationCtrl;
+class AstTop;
+
+class StateMemento;
+class NodeDefStatusDeltaMemento;
+class SuspendedMemento;
+class ServerStateMemento;
+class ServerVariableMemento;
+class NodeEventMemento;
+class NodeMeterMemento;
+class NodeLabelMemento;
+class NodeTriggerMemento;
+class NodeCompleteMemento;
+class NodeRepeatMemento;
+class NodeLimitMemento;
+class NodeInLimitMemento;
+class NodeVariableMemento;
+class NodeLateMemento;
+class NodeTodayMemento;
+class NodeTimeMemento;
+class NodeDayMemento;
+class NodeCronMemento;
+class NodeDateMemento;
+class NodeZombieMemento;
+class NodeVerifyMemento;
+class FlagMemento;
+class SubmittableMemento;
+class SuiteClockMemento;
+class SuiteBeginDeltaMemento;
+class SuiteCalendarMemento;
+class OrderMemento;
+class ChildrenMemento;
+class AliasChildrenMemento;
+class AliasNumberMemento;
+
+#endif
diff --git a/ANode/src/NodeMemento.cpp b/ANode/src/NodeMemento.cpp
new file mode 100644
index 0000000..26059ce
--- /dev/null
+++ b/ANode/src/NodeMemento.cpp
@@ -0,0 +1,584 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #48 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/make_shared.hpp>
+
+#include "Suite.hpp"
+#include "Ecf.hpp"
+#include "DefsDelta.hpp"
+#include "ExprAst.hpp"
+#include "Stl.hpp"
+
+using namespace ecf;
+using namespace std;
+
+//#define DEBUG_MEMENTO 1
+
+/// CompoundMemento relies all clearing all attributes
+void Node::clear()
+{
+ delete lateAttr_; lateAttr_ = NULL;
+ delete completeExpr_; completeExpr_ = NULL;
+ delete triggerExpr_; triggerExpr_ = NULL;
+
+ // ************************************************************
+ // Note: auto cancel does not have any changeable state
+ // Hence it is not cleared. Hence no need for memento
+ // ************************************************************
+
+ if (time_dep_attrs_) time_dep_attrs_->clear();
+ if (child_attrs_) child_attrs_->clear();
+ if (misc_attrs_) misc_attrs_->clear(); // zombies can be added/removed via AlterCmd
+ repeat_.clear();
+ varVec_.clear();
+ limitVec_.clear();
+ inLimitMgr_.clear();
+}
+
+void Node::incremental_changes( DefsDelta& changes, compound_memento_ptr& comp) const
+{
+#ifdef DEBUG_MEMENTO
+ std::cout << "Node::incremental_changes(DefsDelta& changes) " << debugNodePath() << "\n";
+#endif
+
+ unsigned int client_state_change_no = changes.client_state_change_no();
+
+ // determine if state changed
+ if (state_.first.state_change_no() > client_state_change_no) {
+ if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
+ comp->add( boost::make_shared<StateMemento>( state_.first.state()) );
+ }
+
+ // determine if def status changed
+ if (defStatus_.state_change_no() > client_state_change_no) {
+ if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
+ comp->add( boost::make_shared<NodeDefStatusDeltaMemento>( defStatus_.state()) );
+ }
+
+ // determine if node suspend changed
+ if (suspended_change_no_ > client_state_change_no) {
+ if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
+ comp->add( boost::make_shared<SuspendedMemento>( suspended_) );
+ }
+
+ // Determine if node attributes DELETED or ADDED, We copy **all** internal state
+ // When applying on the client side, we clear all node attributes( ie Node::clear())
+ // and re-add
+ if (state_change_no_ > client_state_change_no) {
+
+ /// *****************************************************************************************
+ /// Node attributes DELETED or ADDED, i.e we call comp->clear_attributes()
+ /// *****************************************************************************************
+
+#ifdef DEBUG_MEMENTO
+ std::cout << " Node::incremental_changes() Attributes added or deleted\n";
+#endif
+ // Note: auto-cancel does not have any alterable state hence, *NO* memento
+
+ if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
+ comp->clear_attributes();
+
+ if (child_attrs_) {
+ const std::vector<Meter>& meter_attrs = child_attrs_->meters();
+ BOOST_FOREACH(const Meter& m, meter_attrs ) { comp->add( boost::make_shared<NodeMeterMemento>( m) ); }
+
+ const std::vector<Event>& event_attrs = child_attrs_->events();
+ BOOST_FOREACH(const Event& e, event_attrs ) { comp->add( boost::make_shared<NodeEventMemento>( e) ); }
+
+ const std::vector<Label>& label_attrs = child_attrs_->labels();
+ BOOST_FOREACH(const Label& l, label_attrs ) { comp->add( boost::make_shared<NodeLabelMemento>( l) ); }
+ }
+ if (time_dep_attrs_) {
+ const std::vector<ecf::TodayAttr>& today_attrs = time_dep_attrs_->todayVec();
+ BOOST_FOREACH(const ecf::TodayAttr& attr, today_attrs){ comp->add( boost::make_shared<NodeTodayMemento>( attr) ); }
+
+ const std::vector<ecf::TimeAttr>& time_attrs = time_dep_attrs_->timeVec();
+ BOOST_FOREACH(const ecf::TimeAttr& attr, time_attrs ) { comp->add( boost::make_shared<NodeTimeMemento>( attr) ); }
+
+ const std::vector<DayAttr>& day_attrs = time_dep_attrs_->days();
+ BOOST_FOREACH(const DayAttr& attr, day_attrs ) { comp->add( boost::make_shared<NodeDayMemento>( attr) ); }
+
+ const std::vector<DateAttr>& dates_attrs = time_dep_attrs_->dates();
+ BOOST_FOREACH(const DateAttr& attr, dates_attrs ) { comp->add( boost::make_shared<NodeDateMemento>( attr) ); }
+
+ const std::vector<ecf::CronAttr>& cron_attrs = time_dep_attrs_->crons();
+ BOOST_FOREACH(const CronAttr& attr, cron_attrs ) { comp->add( boost::make_shared<NodeCronMemento>( attr) ); }
+ }
+ if (misc_attrs_) {
+ const std::vector<VerifyAttr>& verify_attrs = misc_attrs_->verifys();
+ if (!verify_attrs.empty()) comp->add( boost::make_shared<NodeVerifyMemento>( verify_attrs) );
+
+ const std::vector<ZombieAttr>& zombie_attrs = misc_attrs_->zombies();
+ BOOST_FOREACH(const ZombieAttr& attr, zombie_attrs){ comp->add( boost::make_shared<NodeZombieMemento>( attr) ); }
+ }
+
+ BOOST_FOREACH(limit_ptr l, limitVec_ ) { comp->add( boost::make_shared<NodeLimitMemento>( *l) ); }
+ BOOST_FOREACH(const Variable& v, varVec_ ) { comp->add( boost::make_shared<NodeVariableMemento>( v) ); }
+
+ inLimitMgr_.get_memento(comp);
+
+ if (triggerExpr_) comp->add( boost::make_shared<NodeTriggerMemento>( *triggerExpr_) );
+ if (completeExpr_) comp->add( boost::make_shared<NodeCompleteMemento>( *completeExpr_ ) );
+ if (!repeat_.empty()) comp->add( boost::make_shared<NodeRepeatMemento>( repeat_) );
+ if (lateAttr_) comp->add( boost::make_shared<NodeLateMemento>( *lateAttr_) );
+
+ changes.add( comp );
+ return;
+ }
+
+ /// *****************************************************************************************
+ /// Node attributes CHANGED
+ /// *****************************************************************************************
+
+ // ** if start to Change ZombieAttr then it needs to be added here, currently we only add/delete.
+
+ if (child_attrs_) {
+
+ // determine if event value changed.
+ const std::vector<Event>& event_attrs = child_attrs_->events();
+ BOOST_FOREACH(const Event& e, event_attrs ) {
+ if (e.state_change_no() > client_state_change_no) {
+ if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
+ comp->add( boost::make_shared<NodeEventMemento>(e) );
+ }
+ }
+
+ // determine if Meter changed.
+ const std::vector<Meter>& meter_attrs = child_attrs_->meters();
+ BOOST_FOREACH(const Meter& m, meter_attrs ) {
+ if (m.state_change_no() > client_state_change_no) {
+ if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
+ comp->add( boost::make_shared<NodeMeterMemento>( m) );
+ }
+ }
+
+ // determine if labels changed.
+ const std::vector<Label>& label_attrs = child_attrs_->labels();
+ BOOST_FOREACH(const Label& l, label_attrs ) {
+ if (l.state_change_no() > client_state_change_no) {
+ if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
+ comp->add( boost::make_shared<NodeLabelMemento>( l) );
+ }
+ }
+ }
+
+ // Determine if the time related dependency changed
+ if (time_dep_attrs_) {
+
+ const std::vector<ecf::TodayAttr>& today_attrs = time_dep_attrs_->todayVec();
+ BOOST_FOREACH(const TodayAttr& attr, today_attrs ) {
+ if (attr.state_change_no() > client_state_change_no) {
+ if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
+ comp->add( boost::make_shared<NodeTodayMemento>( attr) );
+ }
+ }
+
+ const std::vector<ecf::TimeAttr>& time_attrs = time_dep_attrs_->timeVec();
+ BOOST_FOREACH(const TimeAttr& attr, time_attrs ) {
+ if (attr.state_change_no() > client_state_change_no) {
+ if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
+ comp->add( boost::make_shared<NodeTimeMemento>( attr) );
+ }
+ }
+
+ const std::vector<DayAttr>& day_attrs = time_dep_attrs_->days();
+ BOOST_FOREACH(const DayAttr& attr, day_attrs ) {
+ if (attr.state_change_no() > client_state_change_no) {
+ if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
+ comp->add( boost::make_shared<NodeDayMemento>( attr) );
+ }
+ }
+
+ const std::vector<DateAttr>& dates_attrs = time_dep_attrs_->dates();
+ BOOST_FOREACH(const DateAttr& attr, dates_attrs ) {
+ if (attr.state_change_no() > client_state_change_no) {
+ if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
+ comp->add( boost::make_shared<NodeDateMemento>( attr) );
+ }
+ }
+
+ const std::vector<ecf::CronAttr>& cron_attrs = time_dep_attrs_->crons();
+ BOOST_FOREACH(const CronAttr& attr, cron_attrs ) {
+ if (attr.state_change_no() > client_state_change_no) {
+ if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
+ comp->add( boost::make_shared<NodeCronMemento>( attr) );
+ }
+ }
+ }
+
+ if (misc_attrs_) {
+ // zombies have no state that changes
+ // If one verify changes then copy all. Avoids having to work out which one changed
+ const std::vector<VerifyAttr>& verify_attrs = misc_attrs_->verifys();
+ BOOST_FOREACH(const VerifyAttr& v, verify_attrs ) {
+ if (v.state_change_no() > client_state_change_no) {
+ if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
+ comp->add( boost::make_shared<NodeVerifyMemento>( verify_attrs) );
+ break;
+ }
+ }
+ }
+
+ // determine if the trigger or complete changed
+ if (triggerExpr_ && triggerExpr_->state_change_no() > client_state_change_no) {
+ if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
+ comp->add( boost::make_shared<NodeTriggerMemento>( *triggerExpr_) );
+ }
+ if (completeExpr_ && completeExpr_->state_change_no() > client_state_change_no) {
+ if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
+ comp->add( boost::make_shared<NodeCompleteMemento>( *completeExpr_) );
+ }
+
+ // determine if the repeat changed
+ if (!repeat_.empty() && repeat_.state_change_no() > client_state_change_no) {
+ if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
+ comp->add( boost::make_shared<NodeRepeatMemento>( repeat_) );
+ }
+
+ // determine if limits changed.
+ BOOST_FOREACH(limit_ptr l, limitVec_ ) {
+ if (l->state_change_no() > client_state_change_no) {
+ if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
+ comp->add( boost::make_shared<NodeLimitMemento>( *l) );
+ }
+ }
+
+ // determine if variable values changed. Copy all variables. Save on having variable_change_no_ per variable
+ if (variable_change_no_ > client_state_change_no) {
+ if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
+ BOOST_FOREACH(const Variable& v, varVec_ ) { comp->add( boost::make_shared<NodeVariableMemento>( v) ); }
+ }
+
+ // Determine if the late attribute has changed
+ if (lateAttr_ && lateAttr_->state_change_no() > client_state_change_no) {
+ if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
+ comp->add( boost::make_shared<NodeLateMemento>( *lateAttr_) );
+ }
+
+ // Determine if the flag changed
+ if (flag_.state_change_no() > client_state_change_no) {
+ if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
+ comp->add( boost::make_shared<FlagMemento>( flag_ ) );
+ }
+
+
+ if (comp.get() ) {
+ changes.add( comp );
+ }
+}
+
+
+void Node::set_memento(const StateMemento* memento,std::vector<ecf::Aspect::Type>& aspects) {
+
+#ifdef DEBUG_MEMENTO
+ std::cout << "Node::set_memento(const StateMemento* memento) " << debugNodePath() << " " << NState::toString(memento->state_) << "\n";
+#endif
+ aspects.push_back(ecf::Aspect::STATE);
+ setStateOnly( memento->state_ );
+}
+
+
+void Node::set_memento( const NodeDefStatusDeltaMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+#ifdef DEBUG_MEMENTO
+ std::cout << "Node::set_memento(const NodeDefStatusDeltaMemento* memento) " << debugNodePath() << "\n";
+#endif
+ aspects.push_back(ecf::Aspect::DEFSTATUS);
+ defStatus_.setState( memento->state_ );
+}
+
+
+void Node::set_memento( const SuspendedMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+#ifdef DEBUG_MEMENTO
+ std::cout << "Node::set_memento(const SuspendedMemento* memento) " << debugNodePath() << "\n";
+#endif
+ aspects.push_back(ecf::Aspect::SUSPENDED);
+ if (memento->suspended_) suspend();
+ else clearSuspended();
+}
+
+
+void Node::set_memento( const NodeEventMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+
+#ifdef DEBUG_MEMENTO
+ std::cout << "Node::set_memento(const NodeEventMemento* memento) " << debugNodePath() << "\n";
+#endif
+ if (child_attrs_) {
+ child_attrs_->set_memento(memento,aspects);
+ return;
+ }
+ addEvent( memento->event_);
+}
+
+void Node::set_memento( const NodeMeterMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+
+#ifdef DEBUG_MEMENTO
+ std::cout << "Node::set_memento(const NodeMeterMemento* memento) " << debugNodePath() << "\n";
+#endif
+ if (child_attrs_) {
+ child_attrs_->set_memento(memento,aspects);
+ return;
+ }
+ addMeter(memento->meter_);
+}
+
+void Node::set_memento( const NodeLabelMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+
+#ifdef DEBUG_MEMENTO
+ std::cout << "Node::set_memento(const NodeLabelMemento* memento) " << debugNodePath() << "\n";
+#endif
+ if (child_attrs_) {
+ child_attrs_->set_memento(memento,aspects);
+ return;
+ }
+ addLabel(memento->label_);
+}
+
+void Node::set_memento( const NodeTriggerMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+
+#ifdef DEBUG_MEMENTO
+ std::cout << "Node::set_memento(const NodeTriggerMemento* memento) " << debugNodePath() << "\n";
+#endif
+
+ if (triggerExpr_) {
+ aspects.push_back(ecf::Aspect::EXPR_TRIGGER);
+ if (memento->exp_.isFree()) freeTrigger();
+ else clearTrigger();
+ return;
+ }
+
+ // ADD_REMOVE_ATTR aspect
+ add_trigger_expression( memento->exp_);
+}
+
+void Node::set_memento( const NodeCompleteMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+
+#ifdef DEBUG_MEMENTO
+ std::cout << "Node::set_memento(const NodeCompleteMemento* memento) " << debugNodePath() << "\n";
+#endif
+
+ if (completeExpr_) {
+ aspects.push_back(ecf::Aspect::EXPR_COMPLETE);
+ if (memento->exp_.isFree()) freeComplete();
+ else clearComplete();
+ return;
+ }
+
+ // ADD_REMOVE_ATTR aspect
+ add_complete_expression( memento->exp_);
+}
+
+void Node::set_memento( const NodeRepeatMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+
+#ifdef DEBUG_MEMENTO
+ std::cout << "Node::set_memento(const NodeRepeatMemento* memento) " << debugNodePath() << "\n";
+#endif
+
+ if (!repeat_.empty()) {
+ aspects.push_back(ecf::Aspect::REPEAT);
+
+ // Note: the node is incremented one past, the last value
+ // In Node we increment() then check for validity
+ // hence the_new_value may be outside of the valid range.
+ // This can be seen when do a incremental sync,
+ // *hence* allow memento to copy the value as is.
+ repeat_.set_value(memento->repeat_.index_or_value());
+
+ // Alternative, but expensive since relies on cloning and coping potentially very large vectors
+ // repeat_ = memento->repeat_;
+ return;
+ }
+
+ // ADD_REMOVE_ATTR aspect
+ addRepeat(memento->repeat_);
+}
+
+void Node::set_memento( const NodeLimitMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+
+#ifdef DEBUG_MEMENTO
+ std::cout << "Node::set_memento(const NodeLimitMemento* memento) " << debugNodePath() << " " << memento->limit_.toString() << "\n";
+#endif
+
+ limit_ptr limit = find_limit(memento->limit_.name());
+ if (limit.get()) {
+ aspects.push_back(ecf::Aspect::LIMIT);
+ limit->set_state( memento->limit_.theLimit(), memento->limit_.value(), memento->limit_.paths() );
+ return;
+ }
+
+ // ADD_REMOVE_ATTR aspect
+ addLimit(memento->limit_);
+}
+
+void Node::set_memento( const NodeInLimitMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+
+#ifdef DEBUG_MEMENTO
+ std::cout << "Node::set_memento(const NodeInLimitMemento* memento) " << debugNodePath() << "\n";
+#endif
+
+ // ADD_REMOVE_ATTR aspect only, since no state
+
+ addInLimit(memento->inlimit_);
+}
+
+void Node::set_memento( const NodeVariableMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+
+#ifdef DEBUG_MEMENTO
+ std::cout << "Node::set_memento(const NodeVariableMemento* memento) " << debugNodePath() << "\n";
+#endif
+
+
+ size_t theSize = varVec_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ if (varVec_[i].name() == memento->var_.name()) {
+ varVec_[i].set_value( memento->var_.theValue() );
+ aspects.push_back(ecf::Aspect::NODE_VARIABLE);
+ return;
+ }
+ }
+
+ // ADD_REMOVE_ATTR aspect
+ addVariable(memento->var_);
+}
+
+void Node::set_memento( const NodeLateMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+
+#ifdef DEBUG_MEMENTO
+ std::cout << "Node::set_memento(const NodeLateMemento* memento) " << debugNodePath() << "\n";
+#endif
+
+ if (lateAttr_) {
+ aspects.push_back(ecf::Aspect::LATE);
+ lateAttr_->setLate(memento->late_.isLate());
+ return;
+ }
+
+ // ADD_REMOVE_ATTR aspect
+ addLate(memento->late_);
+}
+
+void Node::set_memento( const NodeTodayMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+
+#ifdef DEBUG_MEMENTO
+ std::cout << "Node::set_memento(const NodeTodayMemento* memento) " << debugNodePath() << "\n";
+#endif
+
+ if (time_dep_attrs_ && time_dep_attrs_->set_memento(memento,aspects) ) {
+ aspects.push_back(ecf::Aspect::TODAY);
+ return;
+ }
+
+ // ADD_REMOVE_ATTR aspect
+ addToday(memento->attr_);
+}
+
+void Node::set_memento( const NodeTimeMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+
+#ifdef DEBUG_MEMENTO
+ std::cout << "Node::set_memento(const NodeTimeMemento* memento) " << debugNodePath() << "\n";
+#endif
+
+ if (time_dep_attrs_ && time_dep_attrs_->set_memento(memento,aspects) ) {
+ aspects.push_back(ecf::Aspect::TIME);
+ return;
+ }
+
+ // ADD_REMOVE_ATTR aspect
+ addTime(memento->attr_);
+}
+
+void Node::set_memento( const NodeDayMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+
+#ifdef DEBUG_MEMENTO
+ std::cout << "Node::set_memento(const NodeDayMemento* memento) " << debugNodePath() << "\n";
+#endif
+
+
+ if (time_dep_attrs_ && time_dep_attrs_->set_memento(memento,aspects) ) {
+ aspects.push_back(ecf::Aspect::DAY);
+ return;
+ }
+
+ // ADD_REMOVE_ATTR aspect
+ addDay(memento->attr_);
+}
+
+void Node::set_memento( const NodeDateMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+
+#ifdef DEBUG_MEMENTO
+ std::cout << "Node::set_memento(const NodeDateMemento* memento) " << debugNodePath() << "\n";
+#endif
+
+ if (time_dep_attrs_ && time_dep_attrs_->set_memento(memento,aspects) ) {
+ aspects.push_back(ecf::Aspect::DATE);
+ return;
+ }
+
+ // ADD_REMOVE_ATTR aspect
+ addDate(memento->attr_);
+}
+
+void Node::set_memento( const NodeCronMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+
+#ifdef DEBUG_MEMENTO
+ std::cout << "Node::set_memento(const NodeCronMemento* memento) " << debugNodePath() << "\n";
+#endif
+
+
+ if (time_dep_attrs_ && time_dep_attrs_->set_memento(memento,aspects) ) {
+ aspects.push_back(ecf::Aspect::CRON);
+ return;
+ }
+
+ // ADD_REMOVE_ATTR aspect
+ addCron(memento->attr_);
+}
+
+void Node::set_memento( const FlagMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+
+#ifdef DEBUG_MEMENTO
+ std::cout << "Node::set_memento(const FlagMemento* memento) " << debugNodePath() << "\n";
+#endif
+ aspects.push_back(ecf::Aspect::FLAG);
+
+ flag_.set_flag( memento->flag_.flag() );
+}
+
+void Node::set_memento( const NodeZombieMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+
+#ifdef DEBUG_MEMENTO
+ std::cout << "Node::set_memento(const NodeZombieMemento* memento) " << debugNodePath() << "\n";
+#endif
+
+ // Zombie attributes should always be via ADD_REMOVE_ATTR
+ // See Node::incremental_changes
+ // Since there is no state to change
+
+ /// remove existing attribute of same type, as duplicate of same type not allowed
+ delete_zombie( memento->attr_.zombie_type());
+ addZombie(memento->attr_);
+}
+
+void Node::set_memento( const NodeVerifyMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+
+#ifdef DEBUG_MEMENTO
+ std::cout << "Node::set_memento(const NodeVerifyMemento* memento) " << debugNodePath() << "\n";
+#endif
+ if (misc_attrs_) {
+ misc_attrs_->verifys_.clear();
+ misc_attrs_->verifys_ = memento->verifys_;
+ return;
+ }
+ misc_attrs_ = new MiscAttrs(this);
+ misc_attrs_->verifys_ = memento->verifys_;
+}
diff --git a/ANode/src/NodeState.hpp b/ANode/src/NodeState.hpp
new file mode 100644
index 0000000..933d3ca
--- /dev/null
+++ b/ANode/src/NodeState.hpp
@@ -0,0 +1,65 @@
+#ifndef NODESTATE_HPP_
+#define NODESTATE_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #9 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "NState.hpp"
+
+//
+// Given a set of nodes, return the the most significant state
+// Depend on the Node::computedState, hence include after Node.hpp
+// This will recurse down ****
+//
+namespace ecf {
+
+template < class T >
+NState::State theComputedNodeState( const std::vector<T>& nodeVec, bool immediate)
+{
+ // std::cout << "theComputedNodeState vec size = " << nodeVec.size() << " immediate = " << immediate << "\n";
+ int unknownCount = 0;
+ int completeCount = 0;
+ int queuedCount = 0;
+ int submittedCount = 0;
+ int activeCount = 0;
+ int abortedCount = 0;
+
+ // We don't know the order, hence we must collate first
+ size_t theVecSize = nodeVec.size();
+ for(size_t n =0; n < theVecSize; n++) {
+ NState::State theState;
+ if (immediate) theState = nodeVec[n]->state();
+ else theState = nodeVec[n]->computedState( Node::HIERARCHICAL );
+
+ // std::cout << "the computed state for " << nodeVec[n]->debugNodePath() << " is " << NState::toString(theState) << "\n";
+
+ switch ( theState ) {
+ case NState::ABORTED: abortedCount++; break;
+ case NState::ACTIVE: activeCount++; break;
+ case NState::SUBMITTED: submittedCount++; break;
+ case NState::QUEUED: queuedCount++; break;
+ case NState::COMPLETE: completeCount++; break;
+ case NState::UNKNOWN: unknownCount++; break;
+ default : assert(false); break;
+ }
+ }
+ if (abortedCount > 0) return NState::ABORTED;
+ if (activeCount > 0) return NState::ACTIVE;
+ if (submittedCount > 0) return NState::SUBMITTED;
+ if (queuedCount > 0) return NState::QUEUED;
+ if (completeCount > 0) return NState::COMPLETE;
+ return NState::UNKNOWN;
+}
+}
+#endif
diff --git a/ANode/src/NodeTreeVisitor.cpp b/ANode/src/NodeTreeVisitor.cpp
new file mode 100644
index 0000000..d69bf88
--- /dev/null
+++ b/ANode/src/NodeTreeVisitor.cpp
@@ -0,0 +1,23 @@
+ //============================================================================
+// Name : Cmd
+// Author : Avi
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+
+#include "NodeTreeVisitor.hpp"
+
+namespace ecf {
+
+NodeTreeVisitor::~NodeTreeVisitor() {}
+
+} // namespace ecf
diff --git a/ANode/src/NodeTreeVisitor.hpp b/ANode/src/NodeTreeVisitor.hpp
new file mode 100644
index 0000000..eeaaedb
--- /dev/null
+++ b/ANode/src/NodeTreeVisitor.hpp
@@ -0,0 +1,40 @@
+#ifndef NODETREEVISITOR_HPP_
+#define NODETREEVISITOR_HPP_
+//============================================================================
+// Name : Cmd
+// Author : Avi
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+class Defs;
+class Suite;
+class Family;
+class Task;
+class NodeContainer;
+
+namespace ecf {
+
+class NodeTreeVisitor {
+public:
+ virtual ~NodeTreeVisitor();
+
+ virtual bool traverseObjectStructureViaVisitors() const { return false;}
+ virtual void visitDefs(Defs*) = 0;
+ virtual void visitSuite(Suite*) = 0;
+ virtual void visitFamily(Family*) = 0;
+ virtual void visitNodeContainer(NodeContainer*) = 0;
+ virtual void visitTask(Task*) = 0;
+};
+
+}
+
+#endif
diff --git a/ANode/src/ResolveExternsVisitor.cpp b/ANode/src/ResolveExternsVisitor.cpp
new file mode 100644
index 0000000..900f38e
--- /dev/null
+++ b/ANode/src/ResolveExternsVisitor.cpp
@@ -0,0 +1,125 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #8 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "ResolveExternsVisitor.hpp"
+#include "ExprAstVisitor.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "ExprAst.hpp"
+#include "Log.hpp"
+#include "Str.hpp"
+
+using namespace std;
+
+namespace ecf {
+
+///////////////////////////////////////////////////////////////////////////////
+// ResolveExternsVisitor: Will traverse node tree hierarchy
+ResolveExternsVisitor::ResolveExternsVisitor(Defs* defs) : defs_(defs) {}
+
+void ResolveExternsVisitor::visitDefs( Defs* d) {
+ BOOST_FOREACH(suite_ptr s, d->suiteVec()) { s->acceptVisitTraversor(*this); }
+}
+
+void ResolveExternsVisitor::visitSuite( Suite* s) { visitNodeContainer(s);}
+void ResolveExternsVisitor::visitFamily( Family* f) { visitNodeContainer(f); }
+
+void ResolveExternsVisitor::visitNodeContainer(NodeContainer* nc){
+
+ setup(nc);
+
+ BOOST_FOREACH(node_ptr t, nc->nodeVec()) {
+ t->acceptVisitTraversor(*this);
+ }
+}
+
+void ResolveExternsVisitor::visitTask( Task* t) { setup(t);}
+
+void ResolveExternsVisitor::setup(Node* n)
+{
+ // Defs passed in to avoid, traversing up the node tree
+ n->auto_add_inlimit_externs(defs_);
+ doSetup(n,n->completeAst());
+ doSetup(n,n->triggerAst());
+}
+
+void ResolveExternsVisitor::doSetup(Node* node,Ast* ast)
+{
+ if ( ast ) {
+ // The complete expression have been parsed and we have created the abstract syntax tree
+ AstResolveExternVisitor astVisitor(node,defs_);
+ ast->accept(astVisitor);
+ }
+}
+
+//======================================================================================
+// AstResolveExternVisitor: Will traverse ASR tree hierarchy
+AstResolveExternVisitor::AstResolveExternVisitor(Node* node,Defs* defs)
+: triggerNode_(node), defs_(defs) {}
+
+AstResolveExternVisitor::~AstResolveExternVisitor() {}
+
+void AstResolveExternVisitor::visitNode(AstNode* astNode)
+{
+ //std::cout << "AstResolveExternVisitor::visitNode " << triggerNode_->debugNodePath() << "\n";
+
+ astNode->setParentNode(triggerNode_);
+
+ // See if can reference the path, on the AstNode, if we cant, it should be added as an extern
+ std::string errorMsg;
+ Node* node = astNode->referencedNode( errorMsg );
+ if ( !node ) {
+ /// Add this path to the extern's. Avoid adding duplicates
+ addExtern(astNode->nodePath());
+ }
+}
+
+void AstResolveExternVisitor::visitVariable(AstVariable* astVar)
+{
+ //std::cout << "AstResolveExternVisitor::visitNode " << triggerNode_->debugNodePath() << "\n";
+
+ astVar->setParentNode(triggerNode_);
+
+ // See if can reference the path, on the AstVariable, if we can't, it should be added as an extern
+ std::string errorMsg;
+ Node* theReferencedNode = astVar->referencedNode( errorMsg );
+ if ( !theReferencedNode ) {
+ addExtern(astVar->nodePath(),astVar->name());
+ return;
+ }
+ LOG_ASSERT(errorMsg.empty(),"");
+
+ // Ok,we found the referenced, node, now see if we can reference the attribute name
+ // Find in order, event, meter, user variable, repeat, generated variable
+ if (theReferencedNode->findExprVariable( astVar->name() ) ) {
+ return;
+ }
+
+ // Can't find name, in event, meter, user variable, repeat, generated variable, add as extern
+ addExtern(astVar->nodePath(),astVar->name());
+}
+
+void AstResolveExternVisitor::addExtern(const std::string& absNodePath, const std::string& var)
+{
+ string ext = absNodePath;
+ if (!var.empty()) {
+ ext += Str::COLON();
+ ext += var;
+ }
+ defs_->add_extern(ext); // stored in a set:
+}
+}
diff --git a/ANode/src/ResolveExternsVisitor.hpp b/ANode/src/ResolveExternsVisitor.hpp
new file mode 100644
index 0000000..cdf7de2
--- /dev/null
+++ b/ANode/src/ResolveExternsVisitor.hpp
@@ -0,0 +1,81 @@
+#ifndef RESOLVE_EXTERNS_VISITOR_HPP_
+#define RESOLVE_EXTERNS_VISITOR_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "NodeTreeVisitor.hpp"
+#include "ExprAstVisitor.hpp"
+#include <string>
+#include <set>
+class Node;
+class Ast;
+
+namespace ecf {
+
+class ResolveExternsVisitor : public NodeTreeVisitor {
+public:
+ ResolveExternsVisitor(Defs*);
+
+ virtual bool traverseObjectStructureViaVisitors() const { return true;}
+ virtual void visitDefs(Defs*);
+ virtual void visitSuite(Suite*);
+ virtual void visitFamily(Family*);
+ virtual void visitNodeContainer(NodeContainer*);
+ virtual void visitTask(Task*);
+
+private:
+ void setup(Node*);
+ void doSetup( Node* node, Ast* ast) ;
+
+ Defs* defs_;
+};
+
+class AstResolveExternVisitor : public ExprAstVisitor {
+public:
+ AstResolveExternVisitor( Node*, Defs*);
+ virtual ~AstResolveExternVisitor();
+
+ virtual void visitTop(AstTop*){}
+ virtual void visitRoot(AstRoot*){}
+ virtual void visitAnd(AstAnd*){}
+ virtual void visitNot(AstNot*){}
+ virtual void visitPlus(AstPlus*){}
+ virtual void visitMinus(AstMinus*){}
+ virtual void visitDivide(AstDivide*){}
+ virtual void visitMultiply(AstMultiply*){}
+ virtual void visitModulo(AstModulo*){}
+ virtual void visitOr(AstOr*){}
+ virtual void visitEqual(AstEqual*){}
+ virtual void visitNotEqual(AstNotEqual*){}
+ virtual void visitLessEqual(AstLessEqual*){}
+ virtual void visitGreaterEqual(AstGreaterEqual*){}
+ virtual void visitGreaterThan(AstGreaterThan*){}
+ virtual void visitLessThan(AstLessThan*){}
+ virtual void visitLeaf(AstLeaf*){}
+ virtual void visitInteger(AstInteger*){}
+ virtual void visitString(AstString*){}
+ virtual void visitNodeState(AstNodeState*){}
+ virtual void visitEventState(AstEventState*){}
+ virtual void visitNode(AstNode*);
+ virtual void visitVariable(AstVariable*);
+
+private:
+ void addExtern(const std::string& absNodePath, const std::string& var = "");
+ Node* triggerNode_;
+ Defs* defs_;
+};
+
+}
+#endif
diff --git a/ANode/src/ServerState.cpp b/ANode/src/ServerState.cpp
new file mode 100644
index 0000000..72b2ed7
--- /dev/null
+++ b/ANode/src/ServerState.cpp
@@ -0,0 +1,467 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #29 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <assert.h>
+#include <iostream>
+#include "ServerState.hpp"
+#include "Str.hpp"
+#include "Log.hpp"
+#include "Host.hpp"
+#include "Ecf.hpp"
+#include "Version.hpp"
+
+using namespace ecf;
+using namespace std;
+
+// When a Defs is loaded into a server:
+// o the jobSubmissionInterval_ is set
+// o the jobGeneration_ is set
+ServerState::ServerState() :
+ state_change_no_(0),
+ variable_state_change_no_(0),
+ server_state_( default_state() ),
+ jobSubmissionInterval_( 60 ),
+ jobGeneration_( true )
+{
+ setup_default_env();
+}
+
+bool ServerState::operator==(const ServerState& rhs) const
+{
+ if ( get_state() != rhs.get_state()) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "ServerState::operator== get_state(" << SState::to_string(get_state()) << ") != rhs.get_state(" << SState::to_string(rhs.get_state()) << ")\n";
+ }
+#endif
+ return false;
+ }
+
+ if ( user_variables_ != rhs.user_variables_) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "ServerState::compare user_variables_ != rhs.user_variables_\n";
+ std::cout << "user_variables_:\n";
+ for(std::vector<Variable>::const_iterator i = user_variables_.begin(); i!=user_variables_.end(); ++i) {
+ std::cout << " " << (*i).name() << " " << (*i).theValue() << "\n";
+ }
+ std::cout << "rhs.user_variables_:\n";
+ for(std::vector<Variable>::const_iterator i = rhs.user_variables_.begin(); i!=rhs.user_variables_.end(); ++i) {
+ std::cout << " " << (*i).name() << " " << (*i).theValue() << "\n";
+ }
+ }
+#endif
+ return false;
+ }
+
+ /// Check pointing, SAVES server variables, since they are visualised by client like ecflowview
+ /// HOWEVER PrintStyle::MIGRATE does not save the server variables, since they should
+ /// not take part in migration. However the testing compares migration files with check point files
+ /// This would always fail. Hence we do not compare server variables.
+
+ return true;
+}
+
+bool ServerState::compare(const ServerState& rhs) const
+{
+ if ( get_state() != rhs.get_state()) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "ServerState::compare get_state(" << SState::to_string(get_state()) << ") != rhs.get_state(" << SState::to_string(rhs.get_state()) << ")\n";
+ }
+#endif
+ return false;
+ }
+
+ if ( user_variables_ != rhs.user_variables_) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "ServerState::compare user_variables_ != rhs.user_variables_\n";
+ std::cout << "user_variables_:\n";
+ for(std::vector<Variable>::const_iterator i = user_variables_.begin(); i!=user_variables_.end(); ++i) {
+ std::cout << " " << (*i).name() << " " << (*i).theValue() << "\n";
+ }
+ std::cout << "rhs.user_variables_:\n";
+ for(std::vector<Variable>::const_iterator i = rhs.user_variables_.begin(); i!=rhs.user_variables_.end(); ++i) {
+ std::cout << " " << (*i).name() << " " << (*i).theValue() << "\n";
+ }
+ }
+#endif
+ return false;
+ }
+
+ if ( server_variables_ != rhs.server_variables_) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "ServerState::compare server_variables_ != rhs.server_variables_\n";
+ std::cout << "server_variables_:\n";
+ for(std::vector<Variable>::const_iterator i = server_variables_.begin(); i!=server_variables_.end(); ++i) {
+ std::cout << " " << (*i).name() << " " << (*i).theValue() << "\n";
+ }
+ std::cout << "rhs.server_variables_:\n";
+ for(std::vector<Variable>::const_iterator i = rhs.server_variables_.begin(); i!=rhs.server_variables_.end(); ++i) {
+ std::cout << " " << (*i).name() << " " << (*i).theValue() << "\n";
+ }
+ }
+#endif
+ return false;
+ }
+ return true;
+}
+
+// server variable can NOT be modified or deleted, only overridden
+void ServerState::add_or_update_server_variables( const NameValueVec& env)
+{
+ // n2 could use map to speed things up.
+ NameValueVec::const_iterator i;
+ NameValueVec::const_iterator theEnd = env.end();
+ for(i = env.begin(); i!=theEnd; ++i) {
+ add_or_update_server_variables((*i).first, (*i).second);
+ }
+}
+void ServerState::add_or_update_server_variables( const std::string& name, const std::string& value)
+{
+ std::vector<Variable>::iterator var_end = server_variables_.end();
+ for(std::vector<Variable>::iterator i = server_variables_.begin(); i!=var_end; ++i) {
+ if ((*i).name() == name) {
+ (*i).set_value( value );
+// std::cout << " Server Variables: Updating " << name << " " << value << "\n";
+ return;
+ }
+ }
+// std::cout << " Server Variables: Adding " << name << " " << value << "\n";
+ server_variables_.push_back( Variable(name, value) );
+}
+
+void ServerState::set_server_variables(const std::vector<Variable>& e)
+{
+ server_variables_ = e;
+}
+
+void ServerState::delete_server_variable( const std::string& var)
+{
+ std::vector<Variable>::iterator var_end = server_variables_.end();
+ for(std::vector<Variable>::iterator i = server_variables_.begin(); i!=var_end; ++i) {
+ if ((*i).name() == var) {
+ server_variables_.erase(i);
+ break;
+ }
+ }
+}
+
+// ================================================================================
+
+void ServerState::add_or_update_user_variables( const NameValueVec& env)
+{
+ // n2 could use map to speed things up.
+ NameValueVec::const_iterator i;
+ NameValueVec::const_iterator theEnd = env.end();
+ for(i = env.begin(); i!=theEnd; ++i) {
+ add_or_update_user_variables((*i).first, (*i).second);
+ }
+}
+
+void ServerState::add_or_update_user_variables( const std::vector<Variable>& env)
+{
+ std::vector<Variable>::const_iterator var_end = env.end();
+ for(std::vector<Variable>::const_iterator i = env.begin(); i!=var_end; ++i) {
+ add_or_update_user_variables( (*i).name(), (*i).theValue());
+ }
+}
+
+void ServerState::add_or_update_user_variables( const std::string& name, const std::string& value)
+{
+ std::vector<Variable>::iterator var_end = user_variables_.end();
+ for(std::vector<Variable>::iterator i = user_variables_.begin(); i!=var_end; ++i) {
+ if ((*i).name() == name) {
+ (*i).set_value( value );
+ variable_state_change_no_ = Ecf::incr_state_change_no();
+// std::cout << " ServerState::add_or_update_user_variables: Updating " << name << " " << value << "\n";
+ return;
+ }
+ }
+
+// std::cout << " ServerState::add_or_update_user_variables: Adding " << name << " " << value << "\n";
+ user_variables_.push_back( Variable(name, value) );
+ variable_state_change_no_ = Ecf::incr_state_change_no();
+}
+
+void ServerState::delete_user_variable( const std::string& var)
+{
+ if (var.empty()) {
+ // delete all user variables
+ user_variables_.clear();
+ variable_state_change_no_ = Ecf::incr_state_change_no();
+ return;
+ }
+
+ std::vector<Variable>::iterator var_end = user_variables_.end();
+ for(std::vector<Variable>::iterator i = user_variables_.begin(); i!=var_end; ++i) {
+ if ((*i).name() == var) {
+ user_variables_.erase(i);
+ variable_state_change_no_ = Ecf::incr_state_change_no();
+ break;
+ }
+ }
+}
+
+const std::string& ServerState::find_user_variable(const std::string& theVarName) const
+{
+ std::vector<Variable>::const_iterator user_var_end = user_variables_.end();
+ for(std::vector<Variable>::const_iterator i = user_variables_.begin(); i!=user_var_end; ++i) {
+ if ((*i).name() == theVarName) {
+ LOG_ASSERT(!(*i).theValue().empty(),"");
+ return (*i).theValue();
+ }
+ }
+ return Str::EMPTY();
+}
+
+const std::string& ServerState::find_variable(const std::string& theVarName) const
+{
+ // SEARCH USER variables FIRST
+ std::vector<Variable>::const_iterator user_var_end = user_variables_.end();
+ for(std::vector<Variable>::const_iterator i = user_variables_.begin(); i!=user_var_end; ++i) {
+ if ((*i).name() == theVarName) {
+// cerr << "FOUND '" << (*i).first << "' '" << (*i).second << "'\n";
+ LOG_ASSERT(!(*i).theValue().empty(),"");
+ return (*i).theValue();
+ }
+ }
+
+ // NOW search server variables
+ std::vector<Variable>::const_iterator ser_var_end = server_variables_.end();
+ for(std::vector<Variable>::const_iterator i = server_variables_.begin(); i!=ser_var_end; ++i) {
+ if ((*i).name() == theVarName) {
+// cerr << "FOUND '" << (*i).first << "' '" << (*i).second << "'\n";
+ LOG_ASSERT(!(*i).theValue().empty(),"");
+ return (*i).theValue();
+ }
+ }
+
+// cerr << "FAILED to FIND '" << theVarName << "'\n";
+ return Str::EMPTY();
+}
+
+const Variable& ServerState::findVariable(const std::string& name) const
+{
+ // SEARCH USER variables FIRST
+ std::vector<Variable>::const_iterator var_end = user_variables_.end();
+ for(std::vector<Variable>::const_iterator i = user_variables_.begin(); i!=var_end; ++i) {
+ if ((*i).name() == name) {
+ LOG_ASSERT(!(*i).theValue().empty(),"");
+ // if ((*i).theValue().empty() ) std::cout << (*i).name() << " has a empty value\n";
+ return (*i);
+ }
+ }
+
+ // NOW search server variables
+ std::vector<Variable>::const_iterator ser_var_end = server_variables_.end();
+ for(std::vector<Variable>::const_iterator i = server_variables_.begin(); i!=ser_var_end; ++i) {
+ if ((*i).name() == name) {
+ LOG_ASSERT(!(*i).theValue().empty(),"");
+ // if ((*i).theValue().empty() ) std::cout << (*i).name() << " has a empty value\n";
+ return (*i);
+ }
+ }
+
+// cerr << "FAILED to FIND '" << theVarName << "'\n";
+ return Variable::EMPTY();
+}
+
+bool ServerState::variable_exists(const std::string& name) const
+{
+ // SEARCH USER variables FIRST
+ std::vector<Variable>::const_iterator var_end = user_variables_.end();
+ for(std::vector<Variable>::const_iterator i = user_variables_.begin(); i!=var_end; ++i) {
+ if ((*i).name() == name) return true;
+ }
+
+ // NOW search server variables
+ std::vector<Variable>::const_iterator ser_var_end = server_variables_.end();
+ for(std::vector<Variable>::const_iterator i = server_variables_.begin(); i!=ser_var_end; ++i) {
+ if ((*i).name() == name) return true;
+ }
+
+ return false;
+}
+
+bool ServerState::variableSubsitution(std::string& cmd) const
+{
+ // scan the command for variables, and substitute
+ // We can also have
+ //
+ // "%<VAR>:<substitute>% i.e if VAR exist use it, else use substitute
+ //
+ // ************************************************************************************************************
+ // Special case handling for user variables, and generated variables, which take precedence over node variables
+ // ************************************************************************************************************
+ //
+ // i.e VAR is defined as BILL
+ // %VAR:fred --f% will either be "BILL" or if VAR is not defined "fred --f"
+ //
+ // Infinite recursion. Its possible to end up with infinite recursion:
+ // edit hello '%hello%' # string like %hello% will cause infinite recursion
+ // edit fred '%bill%'
+ // edit bill '%fred%' # should be 10
+ // To prevent this we will use a simple count
+ char micro = '%';
+ const Variable& micro_var = findVariable(Str::ECF_MICRO());
+ if (!micro_var.empty() && !micro_var.theValue().empty() ) micro = micro_var.theValue()[0];
+
+ bool double_micro_found = false;
+ std::string::size_type pos = 0;
+ int count = 0;
+ while ( 1 ) {
+ // A while loop here is used to:
+ // a/ Allow for multiple substitution on a single line. i.e %ECF_FILES% -I %ECF_INCLUDE%"
+ // b/ Allow for recursive substitution. %fred% -> %bill%--> 10
+
+ size_t firstPercentPos = cmd.find( micro, pos );
+ if ( firstPercentPos == string::npos ) break;
+
+ size_t secondPercentPos = cmd.find( micro, firstPercentPos + 1 );
+ if ( secondPercentPos == string::npos ) break;
+
+ if ( secondPercentPos - firstPercentPos <= 1 ) {
+ // handle %% with no characters in between, skip over
+ // i.e to handle "printf %%02d %HOUR:00%" --> "printf %02d 00" i.e if HOUR not defined
+ pos = secondPercentPos + 1;
+ double_micro_found = true;
+ continue;
+ }
+ else pos = 0;
+
+ string percentVar( cmd.begin() + firstPercentPos+1, cmd.begin() + secondPercentPos );
+
+ // First search user variable (*ONLY* set when doing user edit's the script)
+ // Handle case: cmd = "%fred:bill% and where we have user variable "fred:bill"
+ // Handle case: cmd = "%fred% and where we have user variable "fred"
+ // If we fail to find the variable we return false.
+ // Note: When a variable is found, it can have an empty value which is still valid
+ const Variable& variable = findVariable( percentVar );
+ if (!variable.empty() ) {
+ std::string varValue = variable.theValue();
+ cmd.replace( firstPercentPos, secondPercentPos - firstPercentPos + 1, varValue );
+ }
+ else {
+
+ size_t firstColon = percentVar.find( ':' );
+ if (firstColon != string::npos) {
+
+ string var(percentVar.begin(), percentVar.begin() + firstColon);
+
+ const Variable& variable2 = findVariable( var );
+ if (!variable2.empty() ) {
+ std::string varValue = variable2.theValue();
+ cmd.replace( firstPercentPos, secondPercentPos - firstPercentPos + 1, varValue );
+ }
+ else {
+ string substitute (percentVar.begin()+ firstColon+1, percentVar.end());
+ cmd.replace(firstPercentPos,secondPercentPos-firstPercentPos+1,substitute);
+ }
+ }
+ else {
+ // No Colon, Can't find in user variables, or node variable, hence can't go any further
+ return false;
+ }
+ }
+
+ // Simple Check for infinite recursion
+ if (count > 100) return false;
+ count++;
+ }
+
+ if (double_micro_found) {
+ // replace all double micro with a single micro, this must be a single parse
+ // date +%%Y%%m%%d" ==> date +%Y%m%d
+ // %%%% ==> %% // i.e single parse
+ std::string doubleEcfMicro;
+ doubleEcfMicro += micro;
+ doubleEcfMicro += micro;
+ size_t last_pos = 0;
+ while ( 1 ) {
+ string::size_type ecf_double_micro_pos = cmd.find( doubleEcfMicro , last_pos);
+ if ( ecf_double_micro_pos != std::string::npos ) {
+ cmd.erase( cmd.begin() + ecf_double_micro_pos );
+ last_pos = ecf_double_micro_pos + 1;
+ }
+ else break;
+ }
+ }
+
+ return true;
+}
+
+void ServerState::set_user_variables(const std::vector<Variable>& e)
+{
+ user_variables_ = e;
+ variable_state_change_no_ = Ecf::incr_state_change_no();
+}
+
+void ServerState::set_state(SState::State s) {
+ server_state_ = s;
+ state_change_no_ = Ecf::incr_state_change_no();
+}
+
+
+void ServerState::setup_default_env()
+{
+ // This environment is required for testing in the absence of the server.
+ // When the defs file is begun in the server this environment get *overridden*
+ hostPort_ = std::make_pair(Str::LOCALHOST(),Str::DEFAULT_PORT_NUMBER());
+
+ setup_default_server_variables(server_variables_,Str::DEFAULT_PORT_NUMBER());
+}
+
+void ServerState::setup_default_server_variables(std::vector<Variable>& server_variables, const std::string& port)
+{
+ Host host;
+ server_variables.push_back( Variable(Str::ECF_MICRO(), Ecf::MICRO() )); //Preprocessor character for variable substitution and including files
+ server_variables.push_back( Variable(Str::ECF_HOME(), string(".")) );
+ server_variables.push_back( Variable(string("ECF_JOB_CMD"), Ecf::JOB_CMD() )); //Command to be executed to submit a job
+ server_variables.push_back( Variable(string("ECF_KILL_CMD"), Ecf::KILL_CMD() )); // Command to be executed to kill a job
+ server_variables.push_back( Variable(string("ECF_STATUS_CMD"), Ecf::STATUS_CMD() )); // Command to be executed to kill a job
+ server_variables.push_back( Variable(string("ECF_URL_CMD"), Ecf::URL_CMD() ));
+ server_variables.push_back( Variable(string("ECF_URL_BASE"), Ecf::URL_BASE() ));
+ server_variables.push_back( Variable(string("ECF_URL"), Ecf::URL() ));
+ server_variables.push_back( Variable(string("ECF_LOG"), host.ecf_log_file(port) ));
+ server_variables.push_back( Variable(string("ECF_INTERVAL"), string("60") )); // Check time dependencies and submit any jobs
+ server_variables.push_back( Variable(string("ECF_LISTS"), host.ecf_lists_file(port) ));
+ server_variables.push_back( Variable(string("ECF_CHECK"), host.ecf_checkpt_file(port) ));
+ server_variables.push_back( Variable(string("ECF_CHECKOLD"), host.ecf_backup_checkpt_file(port)));
+ server_variables.push_back( Variable(string("ECF_CHECKINTERVAL"), string("120") )); //The interval in seconds to save check point file
+ server_variables.push_back( Variable(string("ECF_CHECKMODE"), string("CHECK_ON_TIME")) );//The check mode, must be one of NEVER, ON_TIME, ALWAYS
+
+ // Number of times a job should rerun if it aborts. If more than one and
+ // job aborts, the job is automatically re-run. Useful when jobs are run in
+ // an unreliable environments. For example using using commands like ftp(1)
+ // in a job can fail easily, but re-running the job will often work
+ server_variables.push_back( Variable(Str::ECF_TRIES(), string("2")) );
+
+ server_variables.push_back( Variable(string("ECF_VERSION"),Version::raw()) );// server version
+
+ // Needed to setup client environment.
+ // The server sets these variable for use by the client. i.e when creating the jobs
+ // The clients then uses them to communicate with the server.
+ server_variables.push_back( Variable(Str::ECF_PORT(),port) );
+ server_variables.push_back( Variable(Str::ECF_NODE(),Str::LOCALHOST()) );
+}
+
+/// determines why the node is not running.
+void ServerState::why(std::vector<std::string>& theReasonWhy) const
+{
+ if (server_state_ == SState::HALTED) theReasonWhy.push_back("The server is halted");
+ if (server_state_ == SState::SHUTDOWN) theReasonWhy.push_back("The server is shutdown");
+}
diff --git a/ANode/src/ServerState.hpp b/ANode/src/ServerState.hpp
new file mode 100644
index 0000000..d9b95b0
--- /dev/null
+++ b/ANode/src/ServerState.hpp
@@ -0,0 +1,140 @@
+#ifndef SERVER_STATE_HPP_
+#define SERVER_STATE_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #18 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <boost/noncopyable.hpp>
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/string.hpp> // no need to include <string>
+
+#include "SState.hpp"
+#include "NodeFwd.hpp"
+#include "Variable.hpp"
+
+/// This class stores the server state, so that it is accessible by the node tree
+///
+/// The server variables could have been added/deleted or changed, hence these
+/// variables are serialised, also: it has proved useful i.e for
+/// a/ Client to visualise the server environment during a call like -group="get; show state"
+/// b/ Allows the test code to update environment. ie. use ECF_CLIENT
+//// allows us to replace smsinit, smscomplete,etc, with the ECF client exe
+//
+// Note The default state here is RUNNING while in the server the default state is HALTED
+// By choosing RUNNING, it allows the Defs related test, to run without explicitly setting the state
+class ServerState : private boost::noncopyable {
+public:
+ ServerState();
+
+ /// Check pointing, SAVES server variables, since they are visualised by client like ecflowview
+ /// HOWEVER PrintStyle::MIGRATE does not save the server variables, since they should
+ /// not take part in migration. However the testing compares migration files with check point files
+ /// This would always fail. Hence we do not compare server variables.
+ /// This does not compare server variables
+ bool operator==(const ServerState& rhs) const;
+ bool operator!=(const ServerState& rhs) const { return !operator==(rhs);}
+
+ /// This does compare server variables. Used in testing
+ bool compare(const ServerState& rhs) const;
+
+ /// The server variable: are automatically added by the server
+ /// on STARTUP and when a checkpoint file is reloaded.
+ /// The variable are required by Job creation & needed in creation of generated variables
+ /// The variables should NOT be modified.
+ ///
+ /// However user variables can be freely added,deleted and modified
+ /// They will override server variables of the same name
+
+ void add_or_update_server_variables( const NameValueVec& env);
+ void delete_server_variable( const std::string&); // should only be used by test
+ void set_server_variables(const std::vector<Variable>& e);
+ const std::vector<Variable>& server_variables() const { return server_variables_; }
+
+ void add_or_update_user_variables( const NameValueVec& env);
+ void add_or_update_user_variables( const std::vector<Variable>& env);
+ void add_or_update_user_variables( const std::string&, const std::string&);
+ void delete_user_variable( const std::string&);
+
+ void set_user_variables(const std::vector<Variable>& e);
+ const std::vector<Variable>& user_variables() const { return user_variables_; }
+ const std::string& find_user_variable(const std::string& name) const;
+
+ // Search user variables, and then server variables
+ const std::string& find_variable(const std::string& name) const;
+ const Variable& findVariable(const std::string& name) const;
+ bool variable_exists(const std::string& name) const;
+
+ /// find all %VAR% and replaces with variable values, returns false on the
+ /// first variable that can't be found, cmd will be left half processed.
+ /// Will search for ECF_MICRO, if not found assumes % as the micro char
+ bool variableSubsitution(std::string& cmd) const;
+
+ // These functions/data are used to during job generation
+ void jobSubmissionInterval(int s) { jobSubmissionInterval_ = s;}
+ int jobSubmissionInterval() const { return jobSubmissionInterval_;}
+ bool jobGeneration() const { return jobGeneration_;} // testing may disable job generation
+ void jobGeneration(bool f) { jobGeneration_ = f;}
+
+ void set_state(SState::State s);
+ SState::State get_state() const { return server_state_; }
+ static SState::State default_state() { return SState::RUNNING; }
+
+ // set by the server hence no need persist
+ void hostPort( const std::pair<std::string,std::string>& hostPort ) { hostPort_ = hostPort;}
+ std::pair<std::string,std::string> hostPort() const { return hostPort_; }
+
+ /// Currently only SState::State server_state_ recorded
+ unsigned int state_change_no() const { return state_change_no_; }
+ unsigned int variable_state_change_no() const { return variable_state_change_no_; }
+
+ /// determines why the node is not running.
+ void why(std::vector<std::string>& theReasonWhy) const;
+
+ /// Used in test
+ static void setup_default_server_variables(std::vector<Variable>& server_variables, const std::string& port);
+
+private:
+ void setup_default_env();
+
+ void add_or_update_server_variables( const std::string&, const std::string&);
+
+private:
+
+ unsigned int state_change_no_; // *not* persisted, only used on server side
+ unsigned int variable_state_change_no_; // *not* persisted, only used on server side
+
+ SState::State server_state_;
+ std::vector<Variable> server_variables_;
+ std::vector<Variable> user_variables_;
+
+ int jobSubmissionInterval_; // NOT persisted, since set in the server
+ bool jobGeneration_; // NOT persisted, since set in the server
+ std::pair<std::string,std::string> hostPort_; // NOT persisted, set by server hence no need to persist
+
+private:
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/)
+ {
+ ar & server_state_;
+ ar & user_variables_;
+ ar & server_variables_;
+ }
+};
+
+// This should ONLY be added to objects that are *NOT* serialised through a pointer
+BOOST_CLASS_IMPLEMENTATION(ServerState, boost::serialization::object_serializable)
+BOOST_CLASS_TRACKING(ServerState,boost::serialization::track_never);
+
+#endif
diff --git a/ANode/src/Signal.cpp b/ANode/src/Signal.cpp
new file mode 100644
index 0000000..aab1747
--- /dev/null
+++ b/ANode/src/Signal.cpp
@@ -0,0 +1,66 @@
+//============================================================================
+// Name : Signal
+// Author : Avi
+// Revision : $Revision: #8 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "Signal.hpp"
+#include <signal.h>
+#include <iostream>
+
+namespace ecf {
+
+// SIGCHLD : Child status has changed (POSIX)
+// Signal sent to parent process whenever one of its child processes terminates or stops.
+
+Signal::Signal() {}
+
+Signal::~Signal()
+{
+ // Unblock SIGCHLD. This will call the signal-handler in System.cpp,
+ // *IF* we have pending SIGCHLD
+ // This will not return until we have handled all the pending SIGCHLD signal
+ unblock_sigchild();
+
+ // Once the signals are processed, block them until we come in here again
+ // Now block again.
+ block_sigchild();
+}
+
+void Signal::block_sigchild()
+{
+ // Now block again.
+ sigset_t set;
+ sigemptyset( &set );
+ sigaddset( &set, SIGCHLD );
+#ifdef ECFLOW_MT
+ rc = pthread_sigmask(SIG_BLOCK, &set, 0 ); // not tested
+ if (rc != 0) std::cerr << "Signal::~Signal(): pthread_sigmask(SIG_UNBLOCK, &set, 0) returned " << rc << "\n";
+#else
+ sigprocmask( SIG_BLOCK, &set, 0 );
+#endif
+}
+
+void Signal::unblock_sigchild()
+{
+ sigset_t set;
+ sigemptyset( &set );
+ sigaddset( &set, SIGCHLD );
+#ifdef ECFLOW_MT
+ int rc = pthread_sigmask(SIG_UNBLOCK, &set, 0 ); // not tested
+ if (rc != 0) std::cerr << "Signal::~Signal(): pthread_sigmask(SIG_UNBLOCK, &set, 0) returned " << rc << "\n";
+#else
+ sigprocmask( SIG_UNBLOCK, &set, 0 );
+#endif
+}
+
+}
diff --git a/ANode/src/Signal.hpp b/ANode/src/Signal.hpp
new file mode 100644
index 0000000..3ce6263
--- /dev/null
+++ b/ANode/src/Signal.hpp
@@ -0,0 +1,38 @@
+#ifndef SIGNAL_HPP_
+#define SIGNAL_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : During destruction will un-block SIGCHILD and then reblock
+// During job generation we want to avoid being notified of
+// of child process termination.
+// We want to control when child process termination is handled
+// Collaboration: System.hpp
+//============================================================================
+#include <boost/noncopyable.hpp>
+
+namespace ecf {
+
+class Signal : private boost::noncopyable {
+public:
+ Signal();
+
+ /// UNBLOCK SIGCHLD at start of destructor
+ /// BLOCK SIGCHLD and the end of the destructor
+ /// During the gap in between handle process termination
+ ~Signal();
+
+ static void block_sigchild();
+ static void unblock_sigchild();
+};
+}
+#endif
diff --git a/ANode/src/Submittable.cpp b/ANode/src/Submittable.cpp
new file mode 100644
index 0000000..03dcad3
--- /dev/null
+++ b/ANode/src/Submittable.cpp
@@ -0,0 +1,955 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #37 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <assert.h>
+#include <sstream>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include "boost/filesystem/exception.hpp"
+#include <boost/lexical_cast.hpp>
+#include <boost/make_shared.hpp>
+
+#include "Submittable.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "File.hpp"
+#include "Passwd.hpp"
+#include "Stl.hpp"
+#include "Str.hpp"
+#include "Indentor.hpp"
+#include "Log.hpp"
+#include "System.hpp"
+#include "JobsParam.hpp"
+#include "EcfFile.hpp"
+#include "Ecf.hpp"
+#include "DefsDelta.hpp"
+#include "Extract.hpp"
+
+namespace fs = boost::filesystem;
+using namespace ecf;
+using namespace std;
+using namespace boost;
+
+//#define DEBUG_TASK_LOCATION 1
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+// init static
+const std::string& Submittable::DUMMY_JOBS_PASSWORD() { static const std::string DUMMY_JOBS_PASSWORD = "_DJP_"; return DUMMY_JOBS_PASSWORD;}
+const std::string& Submittable::FREE_JOBS_PASSWORD() { static const std::string FREE_JOBS_PASSWORD = "FREE"; return FREE_JOBS_PASSWORD;}
+const std::string& Submittable::DUMMY_PROCESS_OR_REMOTE_ID() { static const std::string DUMMY_PROCESS_OR_REMOTE_ID = "_RID_"; return DUMMY_PROCESS_OR_REMOTE_ID;}
+
+Submittable::~Submittable()
+{
+ delete sub_gen_variables_;
+}
+
+void Submittable::init( const std::string& the_process_or_remote_id)
+{
+ set_state( NState::ACTIVE );
+ set_process_or_remote_id(the_process_or_remote_id);
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Submittable::init\n";
+#endif
+}
+
+void Submittable::complete()
+{
+// cout << "Completed " << debugNodePath() << " at " << suite()->calendar().toString() << "\n";
+ set_state( NState::COMPLETE );
+ flag().clear(ecf::Flag::ZOMBIE);
+
+ /// Should we clear jobsPassword_ & process_id? It can be argued that
+ /// we should keep this. In case it is needed. i.e The job may not really be
+ /// complete. However keeping, this means the memory usage will continue to rise
+ /// Dependent on number of tasks. This can affect network bandwidth as well.
+ /// Hence to reduce network bandwidth we chose to clear the strings
+ clear(); // jobs password, process_id, aborted_reason
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Submittable::complete()\n";
+#endif
+}
+
+void Submittable::aborted(const std::string& reason)
+{
+ // Called during *abnormal* child termination
+ // This will bubble the state, and decrement any limits
+ set_aborted_only(reason);
+}
+
+void Submittable::set_process_or_remote_id(const std::string& id)
+{
+ process_or_remote_id_ = id;
+ set_genvar_ecfrid(process_or_remote_id_);
+ state_change_no_ = Ecf::incr_state_change_no();
+
+#ifdef DEBUG
+ if (tryNo_ == 0 && process_or_remote_id_ != Submittable::DUMMY_PROCESS_OR_REMOTE_ID()) {
+ LogToCout logToCout;
+ LOG(Log::ERR,"Submittable::set_process_or_remote_id: " << absNodePath() << " process_id(" << id << ") tryNo == 0, how can this be ???");
+ }
+#endif
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Submittable::set_process_or_remote_id\n";
+#endif
+}
+
+void Submittable::begin()
+{
+ /// It is *very* important that we reset the passwords. This allows us to detect zombies.
+ tryNo_ = 0; // reset try number
+ clear(); // jobs password, process_id, aborted_reason
+
+ Node::begin(); // see Notes in: Node::begin() about update_generated_variables()
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Submittable::begin()\n";
+#endif
+}
+
+void Submittable::requeue(bool resetRepeats, int clear_suspended_in_child_nodes, bool reset_next_time_slot)
+{
+ /// It is *very* important that we reset the passwords. This allows us to detect zombies.
+ tryNo_ = 0; // reset try number
+ clear(); // jobs password, process_id, aborted_reason
+
+ Node::requeue(resetRepeats,clear_suspended_in_child_nodes,reset_next_time_slot);
+ update_generated_variables();
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Submittable::requeue\n";
+#endif
+}
+
+
+void Submittable::calendarChanged(const ecf::Calendar& c, std::vector<node_ptr>& auto_cancelled_nodes,const ecf::LateAttr* inherited_late)
+{
+ Node::calendarChanged(c,auto_cancelled_nodes,NULL);
+
+ // Late flag should ONLY be set on Submittable
+ check_for_lateness(c,inherited_late);
+}
+
+std::string Submittable::write_state() const
+{
+ // *IMPORTANT* we *CANT* use ';' character, since is used in the parser, when we have
+ // multiple statement on a single line i.e.
+ // task a; task b;
+ std::stringstream ss;
+ if ( !jobsPassword_.empty() && jobsPassword_!= Submittable::DUMMY_JOBS_PASSWORD()) ss << " passwd:" << jobsPassword_;
+ if ( !process_or_remote_id_.empty() ) ss << " rid:" << process_or_remote_id_;
+
+ // The abortedReason_, can contain user generated messages, including \n and ;, hence remove these
+ // as they can mess up the parsing on reload.
+ if ( !abortedReason_.empty() ) {
+ std::string the_abort_reason = abortedReason_;
+ Str::replaceall(the_abort_reason,"\n","\\n");
+ Str::replaceall(the_abort_reason,";"," ");
+ ss << " abort<:" << the_abort_reason << ">abort";
+ }
+ if ( tryNo_ != 0) ss << " try:" << tryNo_;
+ ss << Node::write_state();
+ return ss.str();
+}
+
+void Submittable::read_state(const std::string& line,const std::vector<std::string>& lineTokens)
+{
+ // 0 1 2
+ // task name #
+ for(size_t i = 3; i < lineTokens.size(); i++) {
+ if (lineTokens[i].find("passwd:") != std::string::npos ) {
+ if (!Extract::split_get_second(lineTokens[i],jobsPassword_))
+ throw std::runtime_error( "Submittable::read_state failed for jobs password : " + name());
+ }
+ else if (lineTokens[i].find("rid:") != std::string::npos ) {
+ if (!Extract::split_get_second(lineTokens[i],process_or_remote_id_))
+ throw std::runtime_error( "Submittable::read_state failed for rid : " + name());
+ }
+ else if (lineTokens[i].find("try:") != std::string::npos ) {
+ std::string try_number;
+ if (!Extract::split_get_second(lineTokens[i],try_number))
+ throw std::runtime_error( "Submittable::read_state failed for try number : " + name());
+ tryNo_ = Extract::theInt(try_number,"Submittable::read_state failed for try number");
+ }
+ }
+
+ // extract aborted reason
+ // The line tokens will truncate multiple spaces into a single space chars
+ // Hence use the line to extract the abort reason: This will preserve spaces
+ size_t first_pos = line.find("abort<:");
+ size_t last_pos = line.find(">abort");
+ if (first_pos != std::string::npos) {
+ if ( last_pos != std::string::npos) {
+ abortedReason_ = line.substr(first_pos+7, (last_pos-first_pos-7) );
+ }
+ else {
+ throw std::runtime_error("Submittable::read_state failed for abort reason. Expected abort reason to on single line;");
+ }
+ }
+
+ Node::read_state(line,lineTokens);
+}
+
+
+bool Submittable::operator==(const Submittable& rhs) const
+{
+ if ( jobsPassword_ != rhs.jobsPassword_ ) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Submittable::operator== jobsPassword_(" << jobsPassword_ << ") != rhs.jobsPassword_(" << rhs.jobsPassword_ << ") " << debugNodePath() << "\n";
+ std::cout << "Submittable::operator== state(" << NState::toString(state()) << ") rhs.state(" << NState::toString(rhs.state()) << ") \n";
+ // No point dumping out change numbers, since we don't persist them, hence values will always be zero on client side.
+ }
+#endif
+ return false;
+ }
+
+ if ( process_or_remote_id_ != rhs.process_or_remote_id_ ) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Submittable::operator== process_or_remote_id_(" << process_or_remote_id_ << ") != rhs.process_or_remote_id_(" << rhs.process_or_remote_id_ << ") " << debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+
+ if ( tryNo_ != rhs.tryNo_ ) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Submittable::operator== tryNo_(" << tryNo_ << ") != rhs.tryNo_(" << rhs.tryNo_ << ") " << debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+
+ if ( abortedReason_ != rhs.abortedReason_ ) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Submittable::operator== abortedReason_(" << abortedReason_ << ") != rhs.abortedReason_(" << rhs.abortedReason_ << ") " << debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+
+ return Node::operator==(rhs);
+}
+
+string Submittable::tryNo() const
+{
+ try {
+ return boost::lexical_cast< string >( tryNo_ );
+ }
+ catch ( boost::bad_lexical_cast& e ) {}
+
+ LOG_ASSERT(false,"Submittable::tryNo() corrupt?");
+ return string();
+}
+
+
+EcfFile Submittable::locatedEcfFile() const
+{
+ // Look for scripts file(Task->.ecf | Alias->.usr) in the following order
+ // o/ ECF_SCRIPT Generated VARIABLE absolute path, check if files exists
+ // The variable MUST exist, but the file may not
+ // o/ ECF_FETCH (user variable)
+ // if this variable exist, we need to flag it,
+ // So that that file is obtained from running the command. (Output of popen)
+ // o/ ECF_SCRIPT_CMD (user variable)
+ // if this variable exist, we need to flag it,
+ // So that that file is obtained from running the command. (Output of popen)
+ // o/ ECF_FILES (Typically in the definition file, defines a directory) (backward search)
+ // o/ ECF_HOME (backward search)
+ // where: backward search is root_path = (ECF_FILES | ECF_HOME)
+ // <root-path>/suite/family/family2/task.ecf
+ // <root-path>/family/family2/task.ecf
+ // <root-path>/family2/task.ecf
+ // <root-path>/task.ecf
+ std::string reasonEcfFileNotFound;
+ std::string theAbsNodePath = absNodePath();
+ std::string ecf_home;
+ findParentUserVariableValue( Str::ECF_HOME(), ecf_home);
+
+ /// Update local ECF_SCRIPT variable, ECF_SCRIPT is a generated variable. IT *MUST* exist
+ /// Likewise generated variable like TASK and ECF_NAME as they may occur in ECF_FETCH_CMD/ECF_SCRIPT_CMD
+ update_static_generated_variables(ecf_home,theAbsNodePath);
+
+ const Variable& genvar_ecfscript = get_genvar_ecfscript();
+
+#ifdef DEBUG_TASK_LOCATION
+ std::cout << "Submittable::locatedEcfFile() Submittable " << name() << " searching ECF_SCRIPT = '" << genvar_ecfscript.theValue() << "'\n";
+#endif
+ if ( fs::exists( genvar_ecfscript.theValue() ) ) {
+#ifdef DEBUG_TASK_LOCATION
+ std::cout << "Submittable::locatedEcfFile() Submittable " << name() << " ECF_SCRIPT = '" << genvar_ecfscript.theValue() << "' exists\n";
+#endif
+ return EcfFile( const_cast<Submittable*>(this), genvar_ecfscript.theValue() );
+ }
+ else {
+ std::stringstream ss; ss << " ECF_SCRIPT(" << genvar_ecfscript.theValue() << ") does not exist:\n";
+ reasonEcfFileNotFound += ss.str();
+ }
+
+ // Caution: This is not used in operations or research, equally is has not been tested.
+ std::string ecf_fetch_cmd;
+ findParentVariableValue( Str::ECF_FETCH(), ecf_fetch_cmd );
+ if ( !ecf_fetch_cmd.empty() ) {
+#ifdef DEBUG_TASK_LOCATION
+ std::cout << "Submittable::locatedEcfFile() Submittable " << name() << " ECF_FETCH = '" << ecf_fetch_cmd << "' variable exists\n";
+#endif
+ if (variableSubsitution(ecf_fetch_cmd)) {
+ return EcfFile( const_cast<Submittable*>(this), ecf_fetch_cmd, EcfFile::ECF_FETCH_CMD);
+ }
+ else {
+ std::stringstream ss; ss << " Variable ECF_FETCH(" << ecf_fetch_cmd << ") defined, but variable substitution has failed:\n";
+ reasonEcfFileNotFound += ss.str();
+ throw std::runtime_error( reasonEcfFileNotFound ) ;
+ }
+ }
+ else {
+ reasonEcfFileNotFound += " Variable ECF_FETCH not defined:\n";
+ }
+
+ std::string ecf_script_cmd; // ECFLOW-427
+ findParentVariableValue( "ECF_SCRIPT_CMD", ecf_script_cmd );
+ if ( !ecf_script_cmd.empty() ) {
+#ifdef DEBUG_TASK_LOCATION
+ std::cout << "Submittable::locatedEcfFile() Submittable " << name() << " ECF_SCRIPT_CMD = '" << ecf_script_cmd << "' variable exists\n";
+#endif
+ if (variableSubsitution(ecf_script_cmd)) {
+ return EcfFile( const_cast<Submittable*>(this), ecf_script_cmd, EcfFile::ECF_SCRIPT_CMD);
+ }
+ else {
+ std::stringstream ss; ss << " Variable ECF_SCRIPT_CMD(" << ecf_script_cmd << ") defined, but variable substitution has failed:\n";
+ reasonEcfFileNotFound += ss.str();
+ throw std::runtime_error( reasonEcfFileNotFound ) ;
+ }
+ }
+ else {
+ reasonEcfFileNotFound += " Variable ECF_SCRIPT_CMD not defined:\n";
+ }
+
+
+ std::string ecf_filesDirectory ;
+ if (findParentUserVariableValue( Str::ECF_FILES() , ecf_filesDirectory)) {
+#ifdef DEBUG_TASK_LOCATION
+ std::cout << "Submittable::locatedEcfFile() Submittable " << name() << " searching ECF_FILES = '" << ecf_filesDirectory << "' backwards\n";
+#endif
+ if ( !ecf_filesDirectory.empty() && fs::exists( ecf_filesDirectory ) && fs::is_directory( ecf_filesDirectory ) )
+ {
+ // If File::backwardSearch fails it returns an empty string, i.e failure to locate script (Task/.ecf || Alias/.usr) file
+ std::string searchResult = File::backwardSearch( ecf_filesDirectory, theAbsNodePath, script_extension() );
+ if ( searchResult.empty()) {
+ std::stringstream ss; ss << " Search of directory ECF_FILES(" << ecf_filesDirectory << ") failed:\n";
+ reasonEcfFileNotFound += ss.str();
+ }
+ else {
+ return EcfFile(const_cast<Submittable*>(this), searchResult);
+ }
+ }
+ else {
+ std::stringstream ss; ss << " Directory ECF_FILES(" << ecf_filesDirectory << ") does not exist:\n";
+ reasonEcfFileNotFound += ss.str();
+ }
+ }
+ else {
+ reasonEcfFileNotFound += " Variable ECF_FILES not defined:\n";
+ }
+
+
+#ifdef DEBUG_TASK_LOCATION
+ std::cout << "Submittable::locatedEcfFile() Submittable " << name() << " searching ECF_HOME = '" << ecf_home << "' backwards\n";
+#endif
+ if ( !ecf_home.empty() && fs::exists( ecf_home ) && fs::is_directory( ecf_home ) )
+ {
+ // If File::backwardSearch fails it returns an empty string, i.e failure to locate script (Task/.ecf || Alias/.usr) file
+ std::string searchResult = File::backwardSearch( ecf_home, theAbsNodePath, script_extension() );
+ if ( searchResult.empty()) {
+ std::stringstream ss; ss << " Search of directory ECF_HOME(" << ecf_home << ") failed:\n";
+ reasonEcfFileNotFound += ss.str();
+ }
+ else {
+ return EcfFile(const_cast<Submittable*>(this), searchResult);
+ }
+ }
+ else {
+ std::stringstream ss; ss << " Directory ECF_HOME(" << ecf_home << ") does not exist:\n";
+ reasonEcfFileNotFound += ss.str();
+ }
+
+ // failed to find .ecf file
+ std::stringstream ss;
+ ss << " Script for " << theAbsNodePath << " can not be found:\n" << reasonEcfFileNotFound;
+ throw std::runtime_error( ss.str() ) ;
+}
+
+void Submittable::set_jobs_password(const std::string& p)
+{
+ jobsPassword_ = p;
+ state_change_no_ = Ecf::incr_state_change_no();
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Submittable::set_jobs_password\n";
+#endif
+}
+
+void Submittable::increment_try_no()
+{
+ // EVERY time we SUBMIT a job we must:
+ // o generate a password, and hence updated generated variable ECF_PASS
+ // o increment the try number
+ // This means we also need to regenerate the variables
+ // since ECF_TRYNO , ECF_JOB, ECF_JOBOUT depend on the try number.
+ // ALSO ECF_RID is updated with empty string
+ // o Clear the process/remote id. These will be reset by the child commands
+ // *** This MUST be done before pre-processing as it uses these variables ***
+ tryNo_++;
+ process_or_remote_id_.clear();
+ abortedReason_.clear();
+ jobsPassword_ = Passwd::generate();
+ state_change_no_ = Ecf::incr_state_change_no();
+ update_generated_variables();
+}
+
+void Submittable::clear()
+{
+ abortedReason_.clear(); // reset reason aborted
+ jobsPassword_.clear(); // reset password, it will be regenerated before submission
+ process_or_remote_id_.clear();// reset process id
+ state_change_no_ = Ecf::incr_state_change_no();
+}
+
+bool Submittable::submitJob( JobsParam& jobsParam)
+{
+ increment_try_no();
+
+ return submit_job_only(jobsParam);
+}
+
+bool Submittable::submit_job_only( JobsParam& jobsParam)
+{
+#ifdef DEBUG_JOB_SUBMISSION
+ cerr << "Submittable::submit_job_only for task " << name() << endl;
+#endif
+
+ if (state() == NState::ACTIVE || state() == NState::SUBMITTED ) {
+ std::stringstream ss;
+ ss << "Submittable::submit_job_only: failed: Submittable " << absNodePath() << " is already " << NState::toString(state()) << " : ";
+ jobsParam.errorMsg() += ss.str();
+ flag().set(ecf::Flag::EDIT_FAILED);
+ return false;
+ }
+
+ // If the task is a dummy task, return true
+ std::string theValue;
+ if (findParentUserVariableValue(Str::ECF_DUMMY_TASK(),theValue)) {
+ return true;
+ }
+
+ // state change
+ flag().clear(ecf::Flag::NO_SCRIPT);
+ flag().clear(ecf::Flag::EDIT_FAILED);
+ flag().clear(ecf::Flag::JOBCMD_FAILED);
+ requeue_labels(); // ECFLOW-195, requeue no longer resets labels on tasks, hence we do it at task run time.
+
+ try {
+ // Locate the ecf files corresponding to the jobs.
+ EcfFile ecf_file = locatedEcfFile();
+
+ // Pre-process sms file (i.e expand includes, remove comments,manual) and perform
+ // variable substitution. This will then form the '.job' files.
+ // If the job file already exist it is overridden
+ try {
+ const std::string& job_size = ecf_file.create_job( jobsParam );
+
+ //... make sure ECF_PASS is set on the task, This is substituted in <head.h> file
+ //... and hence must be done before variable substitution in ECF_/JOB file
+ //... This is used by client->server authentication
+ if (createChildProcess(jobsParam)) {
+ set_state(NState::SUBMITTED, false, job_size );
+ return true;
+ }
+
+ // Fall through job submission failed.
+ }
+ catch ( std::exception& e) {
+ flag().set(ecf::Flag::EDIT_FAILED);
+ std::string reason = "Submittable::submit_job_only: Job creation failed for task ";
+ reason += absNodePath();
+ reason += " : \n ";
+ reason += e.what();
+ reason += "\n";
+ jobsParam.errorMsg() += reason;
+ set_aborted_only( reason );
+ return false;
+ }
+ }
+ catch (std::exception& e) {
+
+ flag().set(ecf::Flag::NO_SCRIPT);
+ std::stringstream ss; ss << "Submittable::submit_job_only: Script location failed for task " << absNodePath() << " :\n" << e.what() << "\n";
+ jobsParam.errorMsg() += ss.str();
+ set_aborted_only( e.what() ); // remember jobsParam.errorMsg() is accumulated
+ return false;
+ }
+
+ flag().set(ecf::Flag::JOBCMD_FAILED);
+ std::string reason = " Job creation failed for task ";
+ reason += absNodePath();
+ reason += " could not create child process.";
+ jobsParam.errorMsg() += reason;
+ set_aborted_only( reason );
+ return false;
+}
+
+
+void Submittable::check_job_creation( job_creation_ctrl_ptr jobCtrl)
+{
+ // Typically a valid try number is >=1.
+ // Since check_job_creation is only used for testing/python, we will initialise tryNum to -1
+ // so than when it is incremented it will by a try_no of zero. *zero is an invalid try_no *
+ tryNo_ = -1;
+
+ /// call just before job submission, reset data members, update try_no, and *** generate variable ***
+ increment_try_no();
+
+ if ( !jobCtrl->dir_for_job_creation().empty() ) {
+ /// Override ECF_JOB, can be done by either adding a new user variable of same name
+ /// or the generated variable. We choose generated, since this is automatically reset.
+ /// before a real job submission
+ std::string tmpLocationForJob = jobCtrl->dir_for_job_creation();
+ tmpLocationForJob += absNodePath();
+ tmpLocationForJob += File::JOB_EXTN();
+ tmpLocationForJob += "0"; // try number of zero ( i.e an invalid try number)
+ set_genvar_ecfjob(tmpLocationForJob);
+ }
+
+ JobsParam jobsParam; // create jobs = false, spawn jobs = false
+ if ( submit_job_only(jobsParam) ) {
+ return;
+ }
+
+ std::string errorMsg = jobsParam.getErrorMsg();
+ LOG_ASSERT( !errorMsg.empty(), "failing to submit must raise an error message" );
+
+ jobCtrl->error_msg() += errorMsg;
+ jobCtrl->push_back_failing_submittable( dynamic_pointer_cast<Submittable>(shared_from_this()) );
+}
+
+bool Submittable::run(JobsParam& jobsParam, bool force)
+{
+ if (force || ((state() != NState::SUBMITTED) && (state() != NState::ACTIVE))) {
+
+ if ( jobsParam.createJobs() ) {
+
+ return submitJob(jobsParam);
+ }
+ else {
+ /// This is only for test path. Just return true
+ return true;
+ }
+ }
+ std::stringstream ss;
+ ss << "Submittable::run: Aborted for task " << absNodePath() << " because state is " << NState::toString(state()) << " and force not set\n";
+ jobsParam.errorMsg() += ss.str();
+ return false;
+}
+
+void Submittable::kill(const std::string& zombie_pid)
+{
+ std::string ecf_kill_cmd;
+ if ( zombie_pid.empty() ) {
+ if (state() != NState::ACTIVE && state() != NState::SUBMITTED) {
+ return;
+ }
+
+ // *** Generated variables are *NOT* persisted. ***
+ // *** Hence if we have recovered from a check point file, then they will be empty. ***
+ // *** i.e terminate server with active jobs, restart from saved check_pt file
+ // *** and then try to kill the active job, will get an exception( see below) since
+ // *** Generated variable ECF_RID will be empty.
+ if (!sub_gen_variables_) {
+ // std::cout << "Generated variables empty, regenerating !!!!!\n";
+ update_generated_variables();
+ }
+
+ /// If we are in active state, then ECF_RID must have been setup
+ /// This is typically used in the KILL CMD, make sure its there
+ if (state() == NState::ACTIVE && get_genvar_ecfrid().theValue().empty() ) {
+ std::stringstream ss;
+ ss << "Submittable::kill: Generated variable ECF_RID is empty for task " << absNodePath();
+ throw std::runtime_error( ss.str() );
+ }
+
+ if (!findParentUserVariableValue( Str::ECF_KILL_CMD(), ecf_kill_cmd ) || ecf_kill_cmd.empty() ) {
+ std::stringstream ss;
+ ss << "Submittable::kill: ECF_KILL_CMD not defined, for task " << absNodePath() << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ }
+ else {
+ // Use input
+ if (!findParentUserVariableValue( Str::ECF_KILL_CMD(), ecf_kill_cmd ) || ecf_kill_cmd.empty() ) {
+ std::stringstream ss;
+ ss << "Submittable::kill: ECF_KILL_CMD not defined, for task " << absNodePath() << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+
+ // replace %ECF_RID% with the input args
+ Str::replace(ecf_kill_cmd,"%ECF_RID%", zombie_pid);
+ }
+
+ if (!variableSubsitution(ecf_kill_cmd)) {
+ std::stringstream ss;
+ ss << "Submittable::kill: Variable substitution failed for ECF_KILL_CMD(" << ecf_kill_cmd << ") on task " << absNodePath() << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+
+ // Please note: this is *non blocking* the output of the command(ECF_KILL_CMD) should be written to %ECF_JOB%.kill
+ // The output is accessible via the --file cmd
+ // Done as two separate steps as kill command is not blocking on the server
+// LOG(Log::DBG,"Submittable::kill " << absNodePath() << " " << ecf_kill_cmd );
+ std::string errorMsg;
+ if (!System::instance()->spawn(ecf_kill_cmd,"", errorMsg)) {
+ throw std::runtime_error( errorMsg );
+ }
+ flag().set(ecf::Flag::KILLED);
+}
+
+void Submittable::status()
+{
+ if (state() != NState::ACTIVE && state() != NState::SUBMITTED) {
+ return;
+ }
+
+ // *** Generated variables are *NOT* persisted. ***
+ // *** Hence if we have recovered from a check point file, then they will be empty. ***
+ // *** i.e terminate server with active jobs, restart from saved check_pt file
+ // *** and then try to kill/status the active job, will get an exception(see below) since
+ // *** Generated variable ECF_RID will be empty.
+ if (!sub_gen_variables_) {
+ //std::cout << "Generated variables empty, regenerating !!!!!\n";
+ update_generated_variables();
+ }
+
+ /// If we are in active state, then ECF_RID must have been setup
+ if (state() == NState::ACTIVE && get_genvar_ecfrid().theValue().empty()) {
+ std::stringstream ss;
+ ss << "Submittable::status: Generated variable ECF_RID is empty for task " << absNodePath();
+ throw std::runtime_error( ss.str() );
+ }
+
+ std::string ecf_status_cmd;
+ if (!findParentUserVariableValue( Str::ECF_STATUS_CMD(), ecf_status_cmd ) || ecf_status_cmd.empty() ) {
+ std::stringstream ss;
+ ss << "Submittable::status: ECF_STATUS_CMD not defined, for task " << absNodePath() << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+
+ if (!variableSubsitution(ecf_status_cmd)) {
+ std::stringstream ss;
+ ss << "Submittable::status: Variable substitution failed for ECF_STATUS_CMD(" << ecf_status_cmd << ") on task " << absNodePath() << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+
+ // Please note: this is *non blocking* the output of the command(ECF_STATUS_CMD) should be written to %ECF_JOB%.stat
+ // SPAWN process, attach signal to monitor process. returns true
+ std::string errorMsg;
+ if (!System::instance()->spawn(ecf_status_cmd,"", errorMsg)) {
+ throw std::runtime_error( errorMsg );
+ }
+
+// flag().set(ecf::Flag::STATUS);
+}
+
+
+bool Submittable::createChildProcess(JobsParam& jobsParam)
+{
+#ifdef DEBUG_JOB_SUBMISSION
+ cout << "Submittable::createChildProcess for task " << name() << endl;
+#endif
+ std::string ecf_job_cmd;
+ findParentUserVariableValue( Str::ECF_JOB_CMD(), ecf_job_cmd );
+ if (ecf_job_cmd.empty()) {
+ jobsParam.errorMsg() += "Submittable::createChildProcess: Could not find ECF_JOB_CMD : ";
+ return false;
+ }
+
+ if (!variableSubsitution(ecf_job_cmd)) {
+ jobsParam.errorMsg() += "Submittable::createChildProcess: Variable substitution failed for ECF_JOB_CMD(" + ecf_job_cmd + ") :";
+ return false;
+ }
+
+ // Keep tabs on what was submitted for testing purposes
+ jobsParam.push_back_submittable( this );
+
+ if ( jobsParam.spawnJobs() ) {
+
+ // SPAWN process, attach signal to monitor process. returns true
+ return System::instance()->spawn(ecf_job_cmd,absNodePath(),jobsParam.errorMsg());
+ }
+
+ // Test path ONLY
+ return true;
+}
+
+
+void Submittable::set_aborted_only(const std::string& reason)
+{
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Submittable::set_aborted_only\n";
+#endif
+
+ abortedReason_ = reason;
+ state_change_no_ = Ecf::incr_state_change_no();
+
+ // Do not use "\n" | ';' in abortedReason_, as this can mess up, --migrate output
+ // Which would then affect --load.
+ Str::replace(abortedReason_,"\n","");
+ Str::replace(abortedReason_,";"," ");
+
+ // This will set the state and bubble up the most significant state
+ set_state(NState::ABORTED);
+}
+
+
+void Submittable::update_limits()
+{
+ NState::State task_state = state();
+ std::set<Limit*> limitSet; // ensure local limit have preference over parent
+ if (task_state == NState::COMPLETE) {
+ decrementInLimit(limitSet); // will recurse up
+ }
+ else if (task_state == NState::ABORTED) {
+ decrementInLimit(limitSet); // will recurse up
+ }
+ else if (task_state == NState::SUBMITTED) {
+ incrementInLimit(limitSet); // will recurse up
+ }
+ else if (task_state == NState::ACTIVE) {
+ // *** Don't change limits in this state ***
+ }
+ else {
+ // UNKNOWN, QUEUED
+ // For all other states, this task should NOT be consuming a limit token.
+ // During interactive use a Submittable may get re-queued. In case its consuming
+ // a limit token, we decrement the limit. If the we are NOT consuming
+ // a token, its still *SAFE* to call decrementInLimit
+ decrementInLimit(limitSet); // will recurse up
+ }
+}
+
+// Memento ==========================================================
+void Submittable::incremental_changes(DefsDelta& changes, compound_memento_ptr& comp) const
+{
+#ifdef DEBUG_MEMENTO
+ std::cout << "Submittable::incremental_changes() " << debugNodePath() << "\n";
+#endif
+
+ if (state_change_no_ > changes.client_state_change_no()) {
+ if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
+ comp->add( boost::make_shared<SubmittableMemento>( jobsPassword_,process_or_remote_id_,abortedReason_,tryNo_) );
+ }
+
+ // ** if compound memento has children base class, will add it to DefsDelta
+ Node::incremental_changes(changes,comp);
+}
+
+void Submittable::set_memento(const SubmittableMemento* memento,std::vector<ecf::Aspect::Type>& aspects)
+{
+#ifdef DEBUG_MEMENTO
+ std::cout << "Submittable::set_memento(const SubmittableMemento*) " << debugNodePath() << "\n";
+#endif
+
+ aspects.push_back(ecf::Aspect::SUBMITTABLE);
+
+ jobsPassword_ = memento->jobsPassword_;
+ process_or_remote_id_ = memento->process_or_remote_id_;
+ abortedReason_ = memento->abortedReason_;
+ tryNo_ = memento->tryNo_;
+}
+
+// Generated variables ---------------------------------------------------------------------------------
+
+void Submittable::update_generated_variables() const
+{
+ if (!sub_gen_variables_) sub_gen_variables_ = new SubGenVariables(this);
+ sub_gen_variables_->update_generated_variables();
+ update_repeat_genvar();
+}
+
+void Submittable::update_static_generated_variables(const std::string& ecf_home, const std::string& theAbsNodePath) const
+{
+ if (!sub_gen_variables_) sub_gen_variables_ = new SubGenVariables(this);
+ sub_gen_variables_->update_static_generated_variables(ecf_home,theAbsNodePath);
+}
+
+const Variable& Submittable::findGenVariable(const std::string& name) const
+{
+ // AST can reference generated variables. Currently integer based values
+ // The task names can be integers, other valid option is try_no
+ if (!sub_gen_variables_) update_generated_variables();
+
+ const Variable& gen_var = sub_gen_variables_->findGenVariable(name);
+ if (!gen_var.empty()) return gen_var;
+
+ return Node::findGenVariable(name);
+}
+
+void Submittable::gen_variables(std::vector<Variable>& vec) const
+{
+ if (!sub_gen_variables_) update_generated_variables();
+
+ vec.reserve(vec.size() + 9);
+ sub_gen_variables_->gen_variables(vec);
+ Node::gen_variables(vec);
+}
+
+const Variable& Submittable::get_genvar_ecfrid() const
+{
+ if (!sub_gen_variables_) return Variable::EMPTY();
+ return sub_gen_variables_->genvar_ecfrid();
+}
+
+const Variable& Submittable::get_genvar_ecfscript() const
+{
+ if (!sub_gen_variables_) return Variable::EMPTY();
+ return sub_gen_variables_->genvar_ecfscript();
+}
+
+void Submittable::set_genvar_ecfjob(const std::string& value)
+{
+ if (!sub_gen_variables_) sub_gen_variables_ = new SubGenVariables(this);
+ sub_gen_variables_->set_genvar_ecfjob(value);
+}
+
+void Submittable::set_genvar_ecfrid(const std::string& value)
+{
+ if (!sub_gen_variables_) sub_gen_variables_ = new SubGenVariables(this);
+ sub_gen_variables_->set_genvar_ecfrid(value);
+}
+
+// Generated Variables ================================================================================================
+// The false below is used as a dummy argument to call the Variable constructor that does not
+// Check the variable names. i.e we know they are valid
+SubGenVariables::SubGenVariables(const Submittable* sub)
+: submittable_(sub),
+ genvar_task_("TASK", "", false),
+ genvar_ecfrid_(Str::ECF_RID(), "", false),
+ genvar_ecftryno_(Str::ECF_TRYNO(), "", false),
+ genvar_ecfname_(Str::ECF_NAME(), "", false),
+ genvar_ecfpass_(Str::ECF_PASS(), "", false),
+ genvar_ecfjob_(Str::ECF_JOB(), "", false),
+ genvar_ecfjobout_(Str::ECF_JOBOUT(), "", false),
+ genvar_ecfscript_(Str::ECF_SCRIPT(), "", false) {}
+
+void SubGenVariables::update_generated_variables() const
+{
+ // cache strings that are used in many variables
+ std::string theAbsNodePath = submittable_->absNodePath();
+ std::string ecf_home;
+ submittable_->findParentUserVariableValue(Str::ECF_HOME(), ecf_home);
+ update_static_generated_variables(ecf_home,theAbsNodePath);
+ update_dynamic_generated_variables(ecf_home,theAbsNodePath);
+}
+
+void SubGenVariables::update_static_generated_variables(const std::string& ecf_home,const std::string& theAbsNodePath) const
+{
+ // cache strings that are used in many variables
+ if (submittable_->isAlias() && submittable_->parent())
+ genvar_task_.set_value(submittable_->parent()->name()); // does *not* modify Variable::state_change_no
+ else
+ genvar_task_.set_value(submittable_->name());
+
+ genvar_ecfname_.set_value(theAbsNodePath); // does *not* modify Variable::state_change_no
+
+ genvar_ecfscript_.value_by_ref().reserve( ecf_home.size() + theAbsNodePath.size() + 4 );
+ genvar_ecfscript_.value_by_ref() = ecf_home; // does *not* modify Variable::state_change_no
+ genvar_ecfscript_.value_by_ref() += theAbsNodePath;
+ genvar_ecfscript_.value_by_ref() += submittable_->script_extension();
+}
+
+void SubGenVariables::update_dynamic_generated_variables(const std::string& ecf_home,const std::string& theAbsNodePath) const
+{
+ // cache strings that are used in many variables
+ std::string the_try_no = submittable_->tryNo();
+
+ genvar_ecfrid_.set_value(submittable_->process_or_remote_id_); // does *not* modify Variable::state_change_no
+ genvar_ecftryno_.set_value(the_try_no); // does *not* modify Variable::state_change_no
+ genvar_ecfpass_.set_value(submittable_->jobsPassword_); // does *not* modify Variable::state_change_no
+
+
+ /// The directory associated with ECF_JOB is automatically created if it does not exist.
+ /// This is Done during Job generation. See EcfFile::doCreateJobFile()
+ if (genvar_ecfjob_.value_by_ref().capacity() == 0) {
+ genvar_ecfjob_.value_by_ref().reserve( ecf_home.size() + theAbsNodePath.size() + File::JOB_EXTN().size() + the_try_no.size());
+ }
+ genvar_ecfjob_.value_by_ref() = ecf_home; // does *not* modify Variable::state_change_no
+ genvar_ecfjob_.value_by_ref() += theAbsNodePath;
+ genvar_ecfjob_.value_by_ref() += File::JOB_EXTN();
+ genvar_ecfjob_.value_by_ref() += the_try_no;
+
+
+ /// If ECF_OUT is specified the user must ensure the directory exists, along with directories
+ /// associated with Suites/Families nodes.
+ /// Bottom up. Can be expensive when we have thousands of tasks.
+ std::string ecf_out;
+ submittable_->findParentUserVariableValue(Str::ECF_OUT(), ecf_out);
+
+ if (ecf_out.empty()) {
+ genvar_ecfjobout_.value_by_ref().reserve( ecf_home.size() + theAbsNodePath.size() + 1 + the_try_no.size());
+ genvar_ecfjobout_.value_by_ref() = ecf_home;
+ }
+ else {
+ // For metabuilder, where we use %ECF_HOME% for ECF_OUT
+ char micro = '%';
+ if (ecf_out.find(micro) != std::string::npos) {
+ NameValueMap user_edit_variables;
+ submittable_->variable_substitution(ecf_out,user_edit_variables,micro);
+ }
+ genvar_ecfjobout_.value_by_ref().reserve( ecf_out.size() + theAbsNodePath.size() + 1 + the_try_no.size());
+ genvar_ecfjobout_.value_by_ref() = ecf_out;
+ }
+ genvar_ecfjobout_.value_by_ref() += theAbsNodePath;
+ genvar_ecfjobout_.value_by_ref() += ".";
+ genvar_ecfjobout_.value_by_ref() += the_try_no;
+}
+
+const Variable& SubGenVariables::findGenVariable(const std::string& name) const
+{
+ if (genvar_task_.name() == name) return genvar_task_;
+ if (genvar_ecftryno_.name() == name) return genvar_ecftryno_;
+ if (genvar_ecfjob_.name() == name) return genvar_ecfjob_;
+ if (genvar_ecfscript_.name() == name) return genvar_ecfscript_;
+ if (genvar_ecfjobout_.name() == name) return genvar_ecfjobout_;
+ if (genvar_ecfrid_.name() == name) return genvar_ecfrid_;
+ if (genvar_ecfname_.name() == name) return genvar_ecfname_;
+ if (genvar_ecfpass_.name() == name) return genvar_ecfpass_;
+ return Variable::EMPTY();
+}
+
+void SubGenVariables::gen_variables(std::vector<Variable>& vec) const
+{
+ vec.push_back(genvar_task_);
+ vec.push_back(genvar_ecfjob_);
+ vec.push_back(genvar_ecfscript_);
+ vec.push_back(genvar_ecfjobout_);
+ vec.push_back(genvar_ecftryno_);
+ vec.push_back(genvar_ecfrid_);
+ vec.push_back(genvar_ecfname_);
+ vec.push_back(genvar_ecfpass_);
+}
diff --git a/ANode/src/Submittable.hpp b/ANode/src/Submittable.hpp
new file mode 100644
index 0000000..a0619ec
--- /dev/null
+++ b/ANode/src/Submittable.hpp
@@ -0,0 +1,206 @@
+#ifndef SUBMITTABLE_HPP_
+#define SUBMITTABLE_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #16 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <boost/noncopyable.hpp>
+#include "Node.hpp"
+class EcfFile;
+class SubGenVariables;
+
+class Submittable : public Node {
+protected:
+ Submittable( const std::string& name )
+ : Node(name),
+ jobsPassword_(Submittable::DUMMY_JOBS_PASSWORD()),
+ tryNo_(0),
+ state_change_no_(0),
+ sub_gen_variables_(NULL) {}
+
+ Submittable()
+ : jobsPassword_(Submittable::DUMMY_JOBS_PASSWORD()),
+ tryNo_(0),
+ state_change_no_(0),
+ sub_gen_variables_(NULL) {}
+
+ bool operator==(const Submittable& rhs) const;
+
+public:
+ virtual ~Submittable();
+
+ /// Initialise the task. will set the state to NState::ACTIVE
+ void init(const std::string& processId);
+
+ /// complete the task. Will set the state to NState::COMPLETE
+ /// However if there is a valid Repeat or time dependencies then
+ /// task will be re-queued afterwards
+ void complete();
+
+ /// The late attribute, ONLY applies to the Submittable and not NodeContainer
+ virtual void calendarChanged(const ecf::Calendar&, std::vector<node_ptr>& auto_cancelled_nodes,const ecf::LateAttr* inherited_late);
+
+ /// Overridden to reset the try number
+ /// The tasks job can be invoked multiple times. For each invocation we want to preserve
+ /// the output. The try number is used in SMSJOB/SMSJOBOUT to preserve the output when
+ /// there are multiple runs. re-queue/begin() resets the try Number
+ virtual void begin();
+ virtual void requeue( bool resetRepeats,
+ int clear_suspended_in_child_nodes,
+ bool reset_next_time_slot);
+ virtual bool run(JobsParam& jobsParam, bool force);
+ virtual void kill(const std::string& zombie_pid = "");
+ virtual void status();
+
+ virtual void update_generated_variables() const;
+ virtual const Variable& findGenVariable(const std::string& name) const;
+ virtual void gen_variables(std::vector<Variable>& vec) const;
+
+
+ static const std::string& DUMMY_JOBS_PASSWORD();
+ static const std::string& FREE_JOBS_PASSWORD();
+ static const std::string& DUMMY_PROCESS_OR_REMOTE_ID();
+
+ // returns the corresponding .ecf file.
+ // i.e if the ecf file is missing or empty std::runtime_error is thrown
+ // For dummy tasks, i.e tasks with no .ecf file user should add ECF_DUMMY_TASK variable
+ EcfFile locatedEcfFile() const;
+ virtual const std::string& script_extension() const = 0;
+
+ /// Spawn of a child process. Clear process and remote id before jobs is spawned
+ /// Will increment try no first, and then update generated varaibles
+ bool submitJob( JobsParam& ) ;
+
+ /// generates job file independent of dependencies, resets the try Number
+ virtual void check_job_creation( job_creation_ctrl_ptr jobCtrl);
+
+ /// See Defs.hpp
+ virtual void generate_scripts( const std::map<std::string,std::string>&) const {}
+
+ virtual NState::State computedState(Node::TraverseType) const { return state();}
+
+/// data members accessor's and mutators:
+ /// return the current try number as a string, and int
+ std::string tryNo() const;
+ int try_no() const { return tryNo_;}
+
+ const std::string& jobsPassword() const { return jobsPassword_;}
+
+ /// The remote id (ECF_RID) allows a jobs to be killed when added via a queueing system
+ /// in which case the remote id is really the queueing id.
+ const std::string& process_or_remote_id() const { return process_or_remote_id_;}
+
+ /// Set the task to aborted, providing a reason. Will set the state to NState::ABORTED
+ /// This should only be called in two context's:
+ /// 1/ Called via Child Cmd (AbortCmd) i.e job raised a trap,
+ /// 2/ Abnormal process termination. i.e job killed by signal
+ /// *IMPORTANT* If task try number is less than ECF_TRIES then we should
+ /// resubmit the job. However we *should* not do this immediately here, instead we
+ /// wait of *next* call to resolveDependencies, as that will check if we are *inlimit*
+ void aborted(const std::string& reason);
+ virtual const std::string& abortedReason() const { return abortedReason_;}
+
+// Memento functions:
+ void incremental_changes(DefsDelta&, compound_memento_ptr& comp) const;
+ void set_memento(const SubmittableMemento*,std::vector<ecf::Aspect::Type>& aspects);
+
+ virtual void read_state(const std::string& line,const std::vector<std::string>& lineTokens);
+protected:
+
+ virtual std::string write_state() const;
+ /// call just before job submission, reset data members, update try_no, and generate variable
+ void increment_try_no(); // will increment state_change_no
+
+ /// Submits the job *WITHOUT* incrementing the try number
+ bool submit_job_only( JobsParam& );
+
+ // Overridden from Node to increment/decrement limits
+ virtual void update_limits();
+
+private:
+ friend class ZombieCtrl;
+ friend class AlterCmd;
+
+ void set_jobs_password(const std::string& p);
+
+ void set_process_or_remote_id(const std::string&);
+
+ // Use when we _only_ want to set the state,
+ void set_aborted_only(const std::string& reason);
+
+ bool createChildProcess(JobsParam& jobsParam);
+
+ void clear(); // process_id password and aborted reason
+
+
+ void update_static_generated_variables(const std::string& ecf_home, const std::string& theAbsNodePath) const;
+ const Variable& get_genvar_ecfrid() const;
+ const Variable& get_genvar_ecfscript() const;
+ void set_genvar_ecfjob(const std::string& value);
+ void set_genvar_ecfrid(const std::string& value);
+
+private:
+ std::string jobsPassword_;
+ std::string process_or_remote_id_;
+ std::string abortedReason_;
+ int tryNo_;
+ unsigned int state_change_no_; // *not* persisted, only used on server side
+ mutable SubGenVariables* sub_gen_variables_; // *not* persisted since they can be generated
+ friend class SubGenVariables;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/) {
+ ar & boost::serialization::base_object<Node>(*this); // Serialise base class information
+ ar & jobsPassword_;
+ ar & process_or_remote_id_;
+ ar & abortedReason_;
+ ar & tryNo_;
+ }
+};
+
+// We can have several thousands Submittables. This class helps in avoiding
+// the creation of generated variables until required.
+// This improves client->server down load times by avoiding thousands of string constructions
+class SubGenVariables : private boost::noncopyable {
+public:
+ SubGenVariables(const Submittable*);
+
+ void update_generated_variables() const;
+
+ /// distinguish between the two kinds of generated variables
+ void update_static_generated_variables(const std::string& ecf_home, const std::string& theAbsNodePath) const;
+ void update_dynamic_generated_variables(const std::string& ecf_home,const std::string& theAbsNodePath) const;
+
+ const Variable& findGenVariable(const std::string& name) const;
+ void gen_variables(std::vector<Variable>& vec) const;
+
+ const Variable& genvar_ecfrid() const { return genvar_ecfrid_;}
+ const Variable& genvar_ecfscript() const { return genvar_ecfscript_;}
+
+ void set_genvar_ecfjob(const std::string& value) { genvar_ecfjob_.set_value(value); }
+ void set_genvar_ecfrid(const std::string& value) { genvar_ecfrid_.set_value(value); }
+
+private:
+ const Submittable* submittable_;
+ mutable Variable genvar_task_;
+ mutable Variable genvar_ecfrid_;
+ mutable Variable genvar_ecftryno_;
+ mutable Variable genvar_ecfname_;
+ mutable Variable genvar_ecfpass_;
+ mutable Variable genvar_ecfjob_;
+ mutable Variable genvar_ecfjobout_;
+ mutable Variable genvar_ecfscript_;
+};
+
+#endif
diff --git a/ANode/src/Suite.cpp b/ANode/src/Suite.cpp
new file mode 100644
index 0000000..b575c31
--- /dev/null
+++ b/ANode/src/Suite.cpp
@@ -0,0 +1,767 @@
+//============================================================================
+// Name : NodeTree.cpp
+// Author : Avi
+// Revision : $Revision: #128 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <assert.h>
+#include <sstream>
+#include <boost/lexical_cast.hpp>
+#include <boost/make_shared.hpp>
+
+#include "Suite.hpp"
+#include "Defs.hpp"
+#include "PrintStyle.hpp"
+#include "NodeTreeVisitor.hpp"
+#include "DefsDelta.hpp"
+
+#include "Stl.hpp"
+#include "Str.hpp"
+#include "Ecf.hpp"
+#include "Indentor.hpp"
+#include "ExprAst.hpp"
+#include "Log.hpp"
+#include "CalendarUpdateParams.hpp"
+#include "SuiteChanged.hpp"
+#include "JobsParam.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost::posix_time;
+using namespace boost::gregorian;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+//#define DEBUG_FIND_NODE 1
+
+// Create the generated variable up-front. This allows them to be referenced
+// is abstract syntax tree during the post process call
+
+
+Suite::~Suite()
+{
+// std::cout << "Suite::~Suite() " << debugNodePath() << "\n";
+ if (!Ecf::server()) {
+ notify_delete();
+ }
+ delete suite_gen_variables_;
+}
+
+suite_ptr Suite::create(const std::string& name)
+{
+ return boost::make_shared<Suite>( name );
+}
+
+void Suite::accept(ecf::NodeTreeVisitor& v)
+{
+ SuiteChanged1 changed(this);
+ v.visitSuite(this);
+ NodeContainer::accept(v);
+}
+
+void Suite::acceptVisitTraversor(ecf::NodeTreeVisitor& v)
+{
+ SuiteChanged1 changed(this);
+ v.visitSuite(this);
+}
+
+void Suite::begin()
+{
+ if (false == begun_ ) {
+
+ // begin will change all the states of all child nodes, reset all attributes
+ SuiteChanged1 changed(this);
+
+ // begin can cause thousands of mementos to be created, to avoid this we
+ // update the modify change number.
+ Ecf::incr_modify_change_no();
+
+ begun_ = true;
+ begun_change_no_ = Ecf::incr_state_change_no();
+
+ begin_calendar();
+
+ NodeContainer::begin();
+
+ update_generated_variables();
+ }
+}
+
+void Suite::requeue(
+ bool resetRepeats,
+ int clear_suspended_in_child_nodes,
+ bool reset_next_time_slot)
+{
+ if (false == begun_) {
+ std::stringstream ss; ss << "Suite::requeue: The suite " << name() << " must be 'begun' first\n";
+ throw std::runtime_error( ss.str() ) ;
+ }
+
+ // This is more efficient than: since no locking is required
+ // SuiteChanged changed(boost::dynamic_pointer_cast<Suite>(shared_from_this()));
+ // since no locking is required in SuiteChanged
+ SuiteChanged1 changed(this); //
+
+ // requeue can cause thousands of mementos to be created, to avoid this we
+ // update the modify change number.
+ Ecf::incr_modify_change_no();
+
+ requeue_calendar();
+
+ NodeContainer::requeue(resetRepeats,
+ clear_suspended_in_child_nodes,
+ reset_next_time_slot);
+
+ update_generated_variables();
+}
+
+void Suite::reset_begin() {
+ SuiteChanged1 changed(this);
+ begun_ = false;
+ begun_change_no_ = Ecf::incr_state_change_no();
+}
+
+void Suite::begin_calendar()
+{
+ // Begin the calendar, from the clock attribute _ELSE_
+ // Get the local time, second level resolution, based on the
+ // time zone settings of the computer.
+ if (clockAttr_.get()) {
+ clockAttr_->init_calendar(calendar_); // *IF* AlterCmd was used, wait till Suite is requed
+ clockAttr_->begin_calendar(calendar_);
+ }
+ else {
+ calendar_.begin(Calendar::second_clock_time());
+ }
+}
+
+void Suite::requeue_calendar()
+{
+ // ECFLOW-417
+ // Need special handling for a Suite with hybrid clock and repeat day variable.
+ // Basically on re-queue, we need to update calendar date by the repeat day variable
+ if ( clockAttr_.get() && clockAttr_->hybrid() && repeat().is_repeat_day()) {
+
+ // Get the current time, but with the *existing* date of the suite
+ boost::gregorian::date suite_date = calendar_.suiteTime().date();
+ suite_date += date_duration(repeat().step());
+
+ ptime suiteTime = ptime(suite_date, Calendar::second_clock_time().time_of_day() );
+ calendar_.begin( suiteTime );
+
+ // make sure update variable regenerates all suite variables, i.e like ECF_DATE, etc
+ // Needed since we have changed calendar date
+ if (suite_gen_variables_) suite_gen_variables_->force_update();
+
+ return;
+ }
+
+ // Carry on same as before
+ begin_calendar();
+}
+
+
+void Suite::updateCalendar( const ecf::CalendarUpdateParams & calParams, std::vector<node_ptr>& auto_cancelled_nodes )
+{
+ if (begun_) {
+
+// cout << "Suite::updateCalendar " << debugNodePath() << " serverRunning = " << calParams.serverRunning() << " jobSubInterval = " << to_simple_string(calParams.serverPollPeriod());
+// if ( clockAttr_ ) cout << " clockAttr_->startStopWithServer() = " << clockAttr_->startStopWithServer();
+// cout << "\n";
+
+ /// Some suite can elect to avoid updating the calendar when the server is stopped.
+ /// This allows normal and relative time dependencies to be honoured even
+ /// if the server is started/stopped many times.
+ if ( clockAttr_.get() && clockAttr_->startStopWithServer() && !calParams.serverRunning()) {
+ return;
+ }
+
+ SuiteChanged1 changed(this);
+
+ /// The calendar_ will cache server poll period/job submission interval, as calendar increment for easy access
+ calendar_.update( calParams );
+ calendar_change_no_ = Ecf::state_change_no() + 1; // ** See: collateChanges **
+
+ update_generated_variables();
+
+ calendarChanged(calendar_,auto_cancelled_nodes,get_late());
+ }
+}
+
+bool Suite::resolveDependencies(JobsParam& jobsParam)
+{
+ if (begun_) {
+
+ if (jobsParam.check_for_job_generation_timeout()) return false;
+
+ SuiteChanged1 changed(this);
+ return NodeContainer::resolveDependencies(jobsParam);
+ }
+ return true;
+}
+
+bool Suite::operator==(const Suite& rhs) const
+{
+ if (begun_ != rhs.begun_) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Suite::operator== (begun_(" << begun_ << ") != rhs.begun_(" << rhs.begun_ << ")) " << debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+
+ if ((clockAttr_.get() && !rhs.clockAttr_.get()) || (!clockAttr_.get() && rhs.clockAttr_.get()) ){
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Suite::operator== (clockAttr_ && !rhs.clockAttr_) " << debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ if (clockAttr_.get() && rhs.clockAttr_.get() && !(*clockAttr_ == *rhs.clockAttr_)) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Suite::operator== (clockAttr_ && rhs.clockAttr_ && !(*clockAttr_ == *rhs.clockAttr_)) " << debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+
+ return NodeContainer::operator==(rhs);
+}
+
+std::ostream& Suite::print(std::ostream& os) const
+{
+ Indentor::indent(os) << "suite " << name();
+ if (!PrintStyle::defsStyle()) {
+ std::string st = write_state();
+ if (!st.empty()) os << " #" << st;
+ }
+ os << "\n";
+
+ Node::print(os);
+
+ // make sure clock attribute is written before
+ if (clockAttr_.get()) clockAttr_->print(os);
+ if (!PrintStyle::defsStyle()) {
+ std::string calendar_state = calendar_.write_state();
+ if (!calendar_state.empty()) {
+ Indentor indent;
+ Indentor::indent(os) << "calendar" << calendar_state << "\n";
+ }
+ }
+
+ NodeContainer::print(os);
+ Indentor::indent(os) << "endsuite\n";
+
+ return os;
+}
+
+std::string Suite::write_state() const
+{
+ // *IMPORTANT* we *CANT* use ';' character, since is used in the parser, when we have
+ // multiple statement on a single line i.e.
+ // task a; task b;
+ std::string ret;
+ if (begun_) ret += " begun:1";
+ ret += NodeContainer::write_state();
+ return ret;
+}
+void Suite::read_state(const std::string& line,const std::vector<std::string>& lineTokens) {
+
+ // suite s1 # begun:1 state:queued flag:edit_failed suspended:1
+ if (lineTokens.size() >= 4 && lineTokens[3] == "begun:1") begun_ = true;
+ NodeContainer::read_state(line,lineTokens);
+}
+
+const std::string& Suite::debugType() const { return ecf::Str::SUITE();}
+
+std::ostream& operator<<(std::ostream& os, const Suite& d) { return d.print(os); }
+
+void Suite::addClock( const ClockAttr& c,bool initialize_calendar)
+{
+ if ( clockAttr_.get()) {
+ throw std::runtime_error("Add Clock failed: Suite can only have one clock " + absNodePath());
+ }
+ clockAttr_ = boost::make_shared<ClockAttr>(c);
+ if (initialize_calendar) clockAttr_->init_calendar(calendar_);
+}
+
+void Suite::changeClock( const ClockAttr& c)
+{
+ // When changing the clock, *WAIT* till requeue/begin to init the calendar
+ clockAttr_.reset();
+ addClock( c , false);
+}
+
+void Suite::changeClockType(const std::string& clockType)
+{
+ // ISSUES:
+ // Whenever the user *alters* the clock attributes, it needs to be followed by a re-queue of the suite, because:
+ // o/ if we change from real ->hybrid, then we need to set cron, etc time based nodes to complete
+ // Since we could have running tasks, it is up to user to decide when.
+ // o/ If we change from hybrid ->real, then Node with cron attributes etc, need to be requeued.
+ // o/ Any relative times are no longer valid
+ // o/ Time attributes will be incorrect, and hence may fail/pass incorrectly during dependency evaluation.
+ // o/ Why command may be wrong
+ //
+ //
+ // *IF* the user *forgets* to do this, it can cause spurious errors, hence to *minimise* these
+ // the best we can do is to :
+ // o/ re-sync suite calendar for clock attribute
+ // o/ re-queue all time based attributes, *avoiding*
+ // change of state when switching to hybrid clock (i.e due to day,date,cron time attrs)
+ // This is handled in handle_clock_attribute_change()
+ //
+
+ if (clockType != "hybrid" && clockType != "real") {
+ throw std::runtime_error("Suite::changeClockType: expected clock type to be 'hybrid' or 'real' but found " + clockType);
+ }
+
+ SuiteChanged1 changed(this);
+ if (clockAttr_.get()) {
+ clockAttr_->hybrid( clockType == "hybrid" ); // will update state change_no
+ }
+ else {
+ addClock( ClockAttr( clockType == "hybrid") ); // will update state change_no
+ }
+
+ // re-sync suite calendar for clock attribute, re-queue all time based attributes
+ handle_clock_attribute_change();
+}
+
+void Suite::changeClockDate(const std::string& theDate)
+{
+ // See ISSUES: Suite::changeClockType
+ int dayy,month,year;
+ DateAttr::getDate(theDate,dayy,month,year);
+ if (dayy == 0 || month == 0 || year == 0) throw std::runtime_error("Suite::changeClockDate Invalid clock date:" + theDate );
+
+ // ECFLOW-417
+ // By default the user *IS* expected to requeue afterwards. However in the case where we
+ // have a hybrid clock *AND* repeat day, the calendar date will be updated after the requeue.
+ // This will update calendar by repeat days.
+ // Hence take this into account by decrementing by number of days
+ if ( clockAttr_.get() && clockAttr_->hybrid() && repeat().is_repeat_day()) {
+ boost::gregorian::date theDate( year, month, dayy );
+ theDate -= date_duration(repeat().step());
+ dayy = theDate.day();
+ month = theDate.month();
+ year = theDate.year();
+ }
+
+
+ SuiteChanged1 changed(this);
+ if (clockAttr_.get()) {
+ clockAttr_->date(dayy,month,year); // this will check the date and update state change_no
+ }
+ else {
+ addClock( ClockAttr(dayy,month,year) ); // will update state change_no
+ }
+
+ handle_clock_attribute_change();
+}
+
+void Suite::changeClockGain(const std::string& gain)
+{
+ // See: ISSUES on Suite::changeClockType
+ long theGain = 0;
+ try { theGain = boost::lexical_cast< long >( gain ); }
+ catch ( boost::bad_lexical_cast& ) {
+ throw std::runtime_error( "Suite::changeClockGain: value '" + gain + "' is not convertible to an long, for suite " + name());
+ }
+
+ SuiteChanged1 changed(this);
+ if (!clockAttr_.get()) {
+ addClock( ClockAttr() ); // will update state change_no
+ }
+
+ if (theGain > 0) {
+ clockAttr_->set_gain_in_seconds( theGain, true); // will update state change_no
+ }
+ else {
+ clockAttr_->set_gain_in_seconds( theGain, false); // will update state change_no
+ }
+
+ handle_clock_attribute_change();
+}
+
+void Suite::changeClockSync()
+{
+ // See: ISSUES on Suite::changeClockType
+ SuiteChanged1 changed(this);
+ if (clockAttr_.get()) {
+ clockAttr_->sync(); // clear so that on re-queue we sync with computer, + will update state change_no
+ }
+ else {
+ addClock( ClockAttr() ); // will update state change_no
+ }
+
+ handle_clock_attribute_change();
+}
+
+void Suite::handle_clock_attribute_change()
+{
+ // re-queue time could cause thousands of mementos to be created, to avoid this we
+ // update the modify change number.
+ Ecf::incr_modify_change_no();
+
+ // Since the suite clock attribute has changed, re-sync the suite calendar
+ begin_calendar();
+
+ // re-queue all the time attributes, since clock attribute has changed, avoid changing node state.
+ // Note: when switching to hybrid clock the re-queue of time dependencies will
+ // *not* mark hybrid (day,date,cron) as complete
+ // since these nodes could be in a active/submitted state.
+ NodeContainer::requeue_time_attrs();
+
+ // make sure we regenerate all suite variables, i.e like ECF_DATE, etc
+ if (suite_gen_variables_) suite_gen_variables_->force_update();
+
+ update_generated_variables();
+}
+
+
+bool Suite::checkInvariants(std::string& errorMsg) const
+{
+ if (!calendar_.checkInvariants(errorMsg)) {
+ return false;
+ }
+ if (clockAttr_.get()) {
+ if ( calendar().hybrid() != clockAttr_->hybrid()) {
+ std::stringstream ss;
+ ss << "Suite:" << name() << " Calendar(hybrid(" << calendar().hybrid() << ")) and Clock attribute(hybrid(" << clockAttr_->hybrid() << ")) must be in sync, clock types differs";
+ errorMsg += ss.str();
+ return false;
+ }
+ }
+
+ if (Ecf::server()) {
+ if (state_change_no_ > Ecf::state_change_no() ) {
+ std::stringstream ss;
+ ss << "Suite::checkInvariants: suite_change_no(" << state_change_no_ << ") > Ecf::state_change_no(" << Ecf::state_change_no() << ")\n";
+ errorMsg += ss.str();
+ return false;
+ }
+ if (begun_change_no_ > Ecf::state_change_no() ) {
+ std::stringstream ss;
+ ss << "Suite::checkInvariants: begun_change_no_(" << begun_change_no_ << ") > Ecf::state_change_no(" << Ecf::state_change_no() << ")\n";
+ errorMsg += ss.str();
+ return false;
+ }
+ if (calendar_change_no_ > Ecf::state_change_no() ) {
+ std::stringstream ss;
+ ss << "Suite::checkInvariants: calendar_change_no_(" << calendar_change_no_ << ") > Ecf::state_change_no(" << Ecf::state_change_no() << ")\n";
+ errorMsg += ss.str();
+ return false;
+ }
+ if (modify_change_no_ > Ecf::modify_change_no() ) {
+ std::stringstream ss;
+ ss << "Suite::checkInvariants: modify_change_no_(" << modify_change_no_ << ") > Ecf::modify_change_no(" << Ecf::modify_change_no() << ")\n";
+ errorMsg += ss.str();
+ return false;
+ }
+ }
+ return NodeContainer::checkInvariants(errorMsg);
+}
+
+void Suite::collateChanges(DefsDelta& changes) const
+{
+ /// The suite hold the max state change no, for all its children and attributes
+#ifdef DEBUG_MEMENTO
+ std::cout << "Suite::collateChanges() changes.client_state_change_no("
+ << changes.client_state_change_no() << ") state_change_no("
+ << state_change_no() << ") "
+ << debugNodePath() << "\n";
+#endif
+ // Optimising updates:
+ // Problem:
+ // User has requested 1 second updated in the viewer. We used add SuiteCalendarMemento
+ // when ever there were changes in the suite. However this causes the suite in the
+ // viewer to *refresh* to often.
+ //
+ // Soln 1:
+ // Use:
+ // calendar_change_no_ = Ecf::incr_state_change_no();
+ //
+ // plus only create SuiteCalendarMemento, where the suite changes *AND*
+ // calendar has actually changed.
+ // - This fixes the problem, at the expense of *always* creating a SuiteCalendarMemento
+ // every 60 seconds. Thus adding to network traffic.
+ // - The regression tests will fail, since a change is made in the server,
+ // for which the sync does nothing. *************************************
+ // This could be fixed by creating a SuiteCalendarMemento when calendar changes
+ // However we then go back always creating SuiteCalendarMemento every 60 seconds
+ // even when there are **no other** changes
+ //
+ // Soln 2:
+ // Use:
+ // calendar_change_no_ = Ecf::state_change_no() + 1
+ //
+ // We mimick updating Ecf::state_change_no(), thus we can create memento when required
+ // They should however not be recognised as state change.
+ // + This fixes the problem, and the regression test will also work
+ // This is the solution that has been implemented
+
+ // ********************************************************************
+ // Note: we separate determining incremental changes from the traversal
+ // ********************************************************************
+
+ // *TREAT* All changes to *a* Node, in a single compound_memento_ptr
+ size_t before = changes.size();
+
+ compound_memento_ptr suite_compound_mememto;
+ if (clockAttr_.get() && clockAttr_->state_change_no() > changes.client_state_change_no()) {
+ if (!suite_compound_mememto.get()) suite_compound_mememto = boost::make_shared<CompoundMemento>(absNodePath());
+ suite_compound_mememto->add( boost::make_shared<SuiteClockMemento>( *clockAttr_ ) );
+ }
+ if (begun_change_no_ > changes.client_state_change_no()) {
+ if (!suite_compound_mememto.get()) suite_compound_mememto = boost::make_shared<CompoundMemento>(absNodePath());
+ suite_compound_mememto->add( boost::make_shared<SuiteBeginDeltaMemento>( begun_) );
+ }
+
+ /// Collate NodeContainer and Node changes into *SAME* compound_memento_ptr
+ NodeContainer::incremental_changes(changes, suite_compound_mememto);
+
+ // Traversal, we have finished with this node:
+ // Traverse children : *SEPARATE* compound_memento_ptr created on demand
+ NodeContainer::collateChanges(changes);
+
+ /// *ONLY* create SuiteCalendarMemento, if something changed in the suite.
+ /// Additionally calendar_change_no_ updates should not register as a state change, i.e for tests
+ /// SuiteCalendarMemento is need so that WhyCmd can work on the client side.
+ /// Need to use new compound since the suite may not have change, but it children may have.
+ /// Hence as side affect why command with reference to time will only be accurate
+ /// after some kind of state change. Discussed with Axel, who was happy with this.
+ size_t after = changes.size();
+ if (before != after && calendar_change_no_ > changes.client_state_change_no()) {
+ compound_memento_ptr compound_ptr = boost::make_shared<CompoundMemento>(absNodePath());
+ compound_ptr->add( boost::make_shared<SuiteCalendarMemento>( calendar_ ) );
+ changes.add( compound_ptr );
+ }
+}
+
+void Suite::set_memento( const SuiteClockMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+#ifdef DEBUG_MEMENTO
+ std::cout << "Suite::set_memento( const SuiteClockMemento*) " << debugNodePath() << "\n";
+#endif
+ aspects.push_back(ecf::Aspect::SUITE_CLOCK);
+
+ changeClock(memento->clockAttr_);
+}
+
+void Suite::set_memento( const SuiteBeginDeltaMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+#ifdef DEBUG_MEMENTO
+ std::cout << "Suite::set_memento( const SuiteBeginDeltaMemento* ) " << debugNodePath() << "\n";
+#endif
+ aspects.push_back(ecf::Aspect::SUITE_BEGIN);
+
+ begun_ = memento->begun_;
+}
+
+void Suite::set_memento( const SuiteCalendarMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+#ifdef DEBUG_MEMENTO
+ std::cout << "Suite::set_memento( const SuiteCalendarMemento* ) " << debugNodePath() << "\n";
+#endif
+
+ aspects.push_back(ecf::Aspect::SUITE_CALENDAR);
+
+ // The calendar does *NOT* persist the calendar type (hybrid/real) since we can derive this for clock attribute
+ // Hence make sure calendar/clock are in sync. part of the suite invariants
+ calendar_ = memento->calendar_;
+ if (clockAttr_.get()) {
+ if (clockAttr_->hybrid()) calendar_.set_clock_type(ecf::Calendar::HYBRID);
+ else calendar_.set_clock_type(ecf::Calendar::REAL);
+ }
+}
+
+// generated variables ---------------------------------------------------------------------
+void Suite::update_generated_variables() const
+{
+ // This function is called during:
+ // o begin()
+ // o requeue()
+ // o when calendar changes
+ if (!suite_gen_variables_) suite_gen_variables_ = new SuiteGenVariables(this);
+ suite_gen_variables_->update_generated_variables();
+ update_repeat_genvar();
+}
+
+const Variable& Suite::findGenVariable(const std::string& name) const
+{
+ if (!suite_gen_variables_) update_generated_variables();
+
+ const Variable& gen_var = suite_gen_variables_->findGenVariable(name);
+ if (!gen_var.empty()) return gen_var;
+ return NodeContainer::findGenVariable(name);
+}
+
+void Suite::gen_variables(std::vector<Variable>& vec) const
+{
+ if (!suite_gen_variables_) update_generated_variables();
+
+ vec.reserve(vec.size() + 13);
+ NodeContainer::gen_variables(vec);
+ suite_gen_variables_->gen_variables(vec);
+}
+
+// =======================================================================================
+
+// The false below is used as a dummy argument to call the Variable constructor that does not
+// check the variable names. i.e we know they are valid
+SuiteGenVariables::SuiteGenVariables(const Suite* s)
+: suite_(s),
+ genvar_suite_("SUITE", "", false),
+ genvar_yyyy_("YYYY","", false),
+ genvar_dow_("DOW", "", false),
+ genvar_doy_("DOY", "", false),
+ genvar_date_("DATE", "", false),
+ genvar_day_("DAY", "", false),
+ genvar_dd_("DD", "", false ),
+ genvar_mm_("MM", "", false ),
+ genvar_month_("MONTH", "", false ),
+ genvar_smsdate_("ECF_DATE", "", false ),
+ genvar_clock_("ECF_CLOCK", "", false ),
+ genvar_time_("ECF_TIME", "", false ),
+ force_update_(false){}
+
+void SuiteGenVariables::update_generated_variables() const
+{
+ genvar_suite_.set_value(suite_->name());
+
+ // The calendar_ is only initialised once the suite has begun
+ if (!suite_->begun_) {
+ return;
+ }
+
+ // The code below ASSUMES calendar has been initialised
+ boost::posix_time::time_duration time_of_day = suite_->calendar_.suiteTime().time_of_day();
+
+ //#ifdef DEBUG
+ // using namespace boost::gregorian;
+ // tm t = to_tm(suite_->calendar_.suiteTime()); // to_tm can be a bit of a performance hog
+ //// cerr << "\ntm_year = " << t.tm_year << "\n"; /* year - 1900 */
+ //// cerr << "tm_mon = " << t.tm_mon << "\n"; /* month of year (0 - 11) */
+ //// cerr << "tm_mday = " << t.tm_mday << "\n"; /* day of month (1 - 31) */
+ //// cerr << "tm_wday = " << t.tm_wday << "\n"; /* day of week (Sunday = 0) */
+ //// cerr << "tm_yday = " << t.tm_yday << "\n"; /* day of year (0 - 365) */
+ //// cerr << "tm_hour = " << t.tm_hour << "\n"; /* hours (0 - 23) */
+ //// cerr << "tm_min = " << t.tm_min << "\n"; /* minutes (0 - 59) */
+ //// cerr << "tm_sec = " << t.tm_sec << "\n"; /* seconds (0 - 59) */
+ //
+ // // ***IMPORTANT*** suiteTime is only valid for real clock, note that
+ // // *************** for hybrid the day does not change. hence assertion
+ // // *************** needs to take into account calendar type
+ // if (!suite_->calendar_.hybrid()) {
+ // assert( t.tm_wday == calendar_.day_of_week());
+ // assert( t.tm_mday == calendar_.day_of_month());
+ // assert( t.tm_yday+1 == calendar_.day_of_year());
+ // assert( t.tm_mon+1 == calendar_.month());
+ // }
+ // assert( time_of_day.hours() == t.tm_hour);
+ // assert( time_of_day.minutes() == t.tm_min);
+ // assert( t.tm_year + 1900 == calendar_.year());
+ //#endif
+
+ char smstime[255];
+ sprintf(smstime,"%02d:%02d", time_of_day.hours(),time_of_day.minutes());
+ genvar_time_.set_value( smstime );
+
+ // **********************************************************************
+ // The following generated variable need only be updated if NULL or if day changed
+ // Under: HYBRID the day will never change, hence a one time update
+ // **********************************************************************
+ if (genvar_yyyy_.theValue().empty() || suite_->calendar_.dayChanged() || force_update_) {
+
+ force_update_ = false;
+ genvar_yyyy_.set_value(boost::lexical_cast<std::string>(suite_->calendar_.year()));
+ genvar_dow_.set_value( boost::lexical_cast<std::string>(suite_->calendar_.day_of_week()) );
+ genvar_doy_.set_value( boost::lexical_cast<std::string>(suite_->calendar_.day_of_year()) );
+ //cout << "genvar_yyyy_ = " << genvar_yyyy_->theValue() << "\n";
+ //cout << "genvar_dow_ = " << genvar_dow_->theValue() << "\n";
+ //cout << "genvar_doy_ = " << genvar_doy_->theValue() << "\n";
+
+ char ddmmyyyyBuffer[255];
+ sprintf(ddmmyyyyBuffer,"%02d.%02d.%04d", suite_->calendar_.day_of_month(), suite_->calendar_.month(), suite_->calendar_.year());
+ genvar_date_.set_value( ddmmyyyyBuffer );
+ //cout << "genvar_date_ = " << genvar_date_->theValue() << "\n";
+
+ char *day_name[]= { const_cast<char*>("sunday"), const_cast<char*>("monday"),
+ const_cast<char*>("tuesday"), const_cast<char*>("wednesday"),
+ const_cast<char*>("thursday"), const_cast<char*>("friday"),
+ const_cast<char*>("saturday"), NULL };
+ genvar_day_.set_value( day_name[suite_->calendar_.day_of_week()] );
+ //cout << "genvar_day_ = " << genvar_day_->theValue() << "\n";
+
+ char dd[255];
+ sprintf(dd,"%02d",suite_->calendar_.day_of_month());
+ genvar_dd_.set_value( dd );
+ //cout << "genvar_dd_ = " << genvar_dd_->theValue() << "\n";
+
+ char mm[255];
+ sprintf(mm,"%02d",suite_->calendar_.month());
+ genvar_mm_.set_value( mm );
+ //cout << "genvar_mm_ = " << genvar_mm_->theValue() << "\n";
+
+ char *month_name[]
+ = { const_cast<char*>("january"), const_cast<char*>("february"), const_cast<char*>("march"),
+ const_cast<char*>("april"), const_cast<char*>("may"), const_cast<char*>("june"),
+ const_cast<char*>("july"), const_cast<char*>("august"), const_cast<char*>("september"),
+ const_cast<char*>("october"), const_cast<char*>("november"), const_cast<char*>("december"),
+ NULL } ;
+ genvar_month_.set_value( month_name[suite_->calendar_.month()-1] );
+ //cout << "genvar_month_ = " << genvar_month_->theValue() << "\n";
+
+ char smsdate[255];
+ sprintf(smsdate,"%04d%02d%02d", suite_->calendar_.year(), suite_->calendar_.month() , suite_->calendar_.day_of_month());
+ genvar_smsdate_.set_value( smsdate );
+ //cout << "genvar_smsdate_ = " << genvar_smsdate_->theValue() << "\n";
+
+ char smsclock[255];
+ sprintf(smsclock,"%s:%s:%d:%d", day_name[suite_->calendar_.day_of_week()], month_name[suite_->calendar_.month()-1],suite_->calendar_.day_of_week(),suite_->calendar_.day_of_year());
+ genvar_clock_.set_value( smsclock );
+ //cout << "genvar_clock_ = " << genvar_clock_->theValue() << "\n";
+ }
+}
+
+const Variable& SuiteGenVariables::findGenVariable(const std::string& name) const
+{
+ if (genvar_suite_.name() == name) return genvar_suite_;
+ if (genvar_smsdate_.name() == name) return genvar_smsdate_;
+ if (genvar_yyyy_.name() == name) return genvar_yyyy_;
+ if (genvar_dow_.name() == name) return genvar_dow_;
+ if (genvar_doy_.name() == name) return genvar_doy_;
+ if (genvar_date_.name() == name) return genvar_date_;
+ if (genvar_day_.name() == name) return genvar_day_;
+ if (genvar_dd_.name() == name) return genvar_dd_;
+ if (genvar_mm_.name() == name) return genvar_mm_;
+ if (genvar_month_.name() == name) return genvar_month_;
+ if (genvar_clock_.name() == name) return genvar_clock_;
+ if (genvar_time_.name() == name) return genvar_time_;
+ return Variable::EMPTY();
+}
+
+void SuiteGenVariables::gen_variables(std::vector<Variable>& vec) const
+{
+ vec.push_back(genvar_suite_);
+ vec.push_back(genvar_smsdate_);
+ vec.push_back(genvar_yyyy_);
+ vec.push_back(genvar_dow_);
+ vec.push_back(genvar_doy_);
+ vec.push_back(genvar_date_);
+ vec.push_back(genvar_day_);
+ vec.push_back(genvar_dd_);
+ vec.push_back(genvar_mm_);
+ vec.push_back(genvar_month_);
+ vec.push_back(genvar_clock_);
+ vec.push_back(genvar_time_);
+}
diff --git a/ANode/src/Suite.hpp b/ANode/src/Suite.hpp
new file mode 100644
index 0000000..e210bca
--- /dev/null
+++ b/ANode/src/Suite.hpp
@@ -0,0 +1,178 @@
+#ifndef SUITE_HPP_
+#define SUITE_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #73 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "NodeContainer.hpp"
+#include "Calendar.hpp"
+#include "ClockAttr.hpp"
+class SuiteGenVariables;
+namespace ecf { class CalendarUpdateParams; } // forward declare
+
+
+class Suite : public NodeContainer {
+public:
+ Suite( const std::string& name )
+ : NodeContainer(name),
+ defs_(NULL),
+ begun_(false),
+ state_change_no_(0),
+ modify_change_no_(0),
+ begun_change_no_(0),
+ calendar_change_no_(0),
+ suite_gen_variables_(NULL)
+ {}
+
+ Suite()
+ : defs_(NULL),
+ begun_(false),
+ state_change_no_(0),
+ modify_change_no_(0),
+ begun_change_no_(0),
+ calendar_change_no_(0),
+ suite_gen_variables_(NULL)
+ {}
+
+ virtual ~Suite();
+
+ static suite_ptr create(const std::string& name);
+
+ virtual Suite* suite() const { return const_cast<Suite*>(this); }
+ virtual Defs* defs() const { return defs_;}
+ void set_defs(Defs* d) { defs_ = d;}
+ virtual Suite* isSuite() const { return const_cast<Suite*>(this); }
+ virtual NodeContainer* isNodeContainer() const { return const_cast<Suite*>(this); }
+
+ /// Overridden to take into account begin()
+ virtual bool resolveDependencies(JobsParam& );
+
+ virtual void accept(ecf::NodeTreeVisitor&);
+ virtual void acceptVisitTraversor(ecf::NodeTreeVisitor& v);
+ virtual void begin();
+ virtual void requeue(
+ bool resetRepeats,
+ int clear_suspended_in_child_nodes,
+ bool reset_next_time_slot);
+ bool begun() const { return begun_; }
+ void reset_begin();
+ virtual void update_generated_variables() const;
+
+ virtual const Variable& findGenVariable(const std::string& name) const;
+ virtual void gen_variables(std::vector<Variable>&) const;
+
+ void updateCalendar( const ecf::CalendarUpdateParams &, std::vector<node_ptr>& auto_cancelled_nodes);
+
+ virtual const std::string& debugType() const;
+
+ bool operator==(const Suite& rhs) const;
+ std::ostream& print(std::ostream&) const;
+
+ void addClock( const ClockAttr& , bool initialize_calendar = true); // throw std::run_time if more than one clock is added
+ void changeClock( const ClockAttr& );
+ void changeClockType(const std::string& theType);
+ void changeClockDate(const std::string& theDate);
+ void changeClockGain(const std::string& theIntGain);
+ void changeClockSync();
+
+ /// return the suites calendar
+ const ecf::Calendar& calendar() const { return calendar_;}
+ ecf::Calendar& set_calendar() { return calendar_;}
+ clock_ptr clockAttr() const { return clockAttr_;}
+
+ virtual bool checkInvariants(std::string& errorMsg) const;
+
+ // Memento functions
+ virtual void collateChanges(DefsDelta&) const;
+ void set_memento(const SuiteClockMemento*,std::vector<ecf::Aspect::Type>& aspects );
+ void set_memento(const SuiteBeginDeltaMemento*,std::vector<ecf::Aspect::Type>& aspects );
+ void set_memento(const SuiteCalendarMemento*,std::vector<ecf::Aspect::Type>& aspects );
+ void set_memento(const OrderMemento* m,std::vector<ecf::Aspect::Type>& aspects) { NodeContainer::set_memento(m,aspects); }
+ void set_memento(const ChildrenMemento* m,std::vector<ecf::Aspect::Type>& aspects) { NodeContainer::set_memento(m,aspects); }
+
+ void set_state_change_no( unsigned int x ) { state_change_no_ = x;}
+ unsigned int state_change_no() const { return state_change_no_; }
+ void set_modify_change_no( unsigned int x ) { modify_change_no_ = x;}
+ unsigned int modify_change_no() const { return modify_change_no_; }
+
+ virtual void read_state(const std::string& line,const std::vector<std::string>& lineTokens);
+
+private:
+ void begin_calendar();
+ void requeue_calendar();
+ void handle_clock_attribute_change();
+ virtual std::string write_state() const;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/)
+ {
+ // serialise base class information
+ ar & boost::serialization::base_object<NodeContainer>(*this);
+ ar & begun_;
+ ar & clockAttr_;
+ ar & calendar_;
+
+ // The calendar does not persist the clock type or start stop with server since
+ // that is persisted with the clock attribute
+ if (Archive::is_loading::value) {
+ if (clockAttr_.get()) clockAttr_->init_calendar(calendar_);
+ }
+ }
+
+private:
+ Defs* defs_; // *NOT* persisted, set by parent Defs
+ bool begun_;
+ clock_ptr clockAttr_;
+ ecf::Calendar calendar_; // *Only* persisted since used by the why() on client side
+ unsigned int state_change_no_; // no need to persist
+ unsigned int modify_change_no_; // no need to persist
+ unsigned int begun_change_no_; // no need to persist, record changes to begun_. Needed for SSyncCmd
+ unsigned int calendar_change_no_; // no need to persist,
+ mutable SuiteGenVariables* suite_gen_variables_; // NOT persisted can be generated by calling update_generated_variables()
+ friend class SuiteGenVariables;
+};
+
+std::ostream& operator<<(std::ostream& os, const Suite&);
+
+
+// This class helps in avoiding the creation of generated variables until required.
+// This improves client->server down load times by avoiding thousands of string constructions
+class SuiteGenVariables : private boost::noncopyable {
+public:
+ SuiteGenVariables(const Suite*);
+
+ void force_update() { force_update_ = true;}
+ void update_generated_variables() const;
+ const Variable& findGenVariable(const std::string& name) const;
+ void gen_variables(std::vector<Variable>& vec) const;
+
+private:
+ const Suite* suite_;
+ mutable Variable genvar_suite_; // *NOT* persisted, can be generated by calling update_generated_variables()
+ mutable Variable genvar_yyyy_; // *NOT* persisted, can be generated by calling update_generated_variables()
+ mutable Variable genvar_dow_; // *NOT* persisted, can be generated by calling update_generated_variables()
+ mutable Variable genvar_doy_; // *NOT* persisted, can be generated by calling update_generated_variables()
+ mutable Variable genvar_date_; // *NOT* persisted, can be generated by calling update_generated_variables()
+ mutable Variable genvar_day_; // *NOT* persisted, can be generated by calling update_generated_variables()
+ mutable Variable genvar_dd_; // *NOT* persisted, can be generated by calling update_generated_variables()
+ mutable Variable genvar_mm_; // *NOT* persisted, can be generated by calling update_generated_variables()
+ mutable Variable genvar_month_; // *NOT* persisted, can be generated by calling update_generated_variables()
+ mutable Variable genvar_smsdate_; // *NOT* persisted, can be generated by calling update_generated_variables()
+ mutable Variable genvar_clock_; // *NOT* persisted, can be generated by calling update_generated_variables()
+ mutable Variable genvar_time_; // *NOT* persisted, can be generated by calling update_generated_variables()
+ mutable bool force_update_;
+};
+
+#endif
diff --git a/ANode/src/SuiteChanged.cpp b/ANode/src/SuiteChanged.cpp
new file mode 100644
index 0000000..7f1fc6a
--- /dev/null
+++ b/ANode/src/SuiteChanged.cpp
@@ -0,0 +1,89 @@
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#ifdef DEBUG
+#include <iostream>
+#endif
+
+#include "SuiteChanged.hpp"
+#include "Suite.hpp"
+#include "Ecf.hpp"
+
+namespace ecf {
+
+SuiteChanged::SuiteChanged(suite_ptr s)
+: suite_(s),
+ state_change_no_(Ecf::state_change_no()),
+ modify_change_no_(Ecf::modify_change_no())
+ {}
+
+SuiteChanged::~SuiteChanged()
+{
+ suite_ptr suite = suite_.lock();
+ if (suite.get()) {
+ if ( modify_change_no_ != Ecf::modify_change_no() ) {
+ suite->set_modify_change_no(Ecf::modify_change_no());
+ }
+ if ( state_change_no_ != Ecf::state_change_no() ) {
+ suite->set_state_change_no(Ecf::state_change_no());
+ }
+ }
+}
+
+// ============================================================================
+SuiteChanged0::SuiteChanged0(node_ptr s)
+: node_(s),
+ suite_(s->suite()),
+ state_change_no_(Ecf::state_change_no()),
+ modify_change_no_(Ecf::modify_change_no())
+ {}
+
+SuiteChanged0::~SuiteChanged0()
+{
+ node_ptr node = node_.lock();
+ if (node.get() && suite_) {
+ if ( modify_change_no_ != Ecf::modify_change_no() ) {
+ suite_->set_modify_change_no(Ecf::modify_change_no());
+ //std::cout << "SuiteChanged0::~SuiteChanged0() modify_ changed \n";
+ }
+ if ( state_change_no_ != Ecf::state_change_no() ) {
+ suite_->set_state_change_no(Ecf::state_change_no());
+ //std::cout << "SuiteChanged0::~SuiteChanged0() state changed \n";
+ }
+ }
+}
+
+//================================================================
+
+SuiteChanged1::SuiteChanged1(Suite* s)
+: suite_(s),
+ state_change_no_(Ecf::state_change_no()),
+ modify_change_no_(Ecf::modify_change_no())
+ {}
+
+SuiteChanged1::~SuiteChanged1()
+{
+ if ( modify_change_no_ != Ecf::modify_change_no() ) {
+ suite_->set_modify_change_no(Ecf::modify_change_no());
+ //std::cout << "SuiteChanged1::~SuiteChanged0() modify_ changed \n";
+ }
+ if ( state_change_no_ != Ecf::state_change_no() ) {
+ suite_->set_state_change_no(Ecf::state_change_no());
+ //std::cout << "SuiteChanged1::~SuiteChanged0() modify_ changed \n";
+ }
+}
+
+}
diff --git a/ANode/src/SuiteChanged.hpp b/ANode/src/SuiteChanged.hpp
new file mode 100644
index 0000000..11f50c2
--- /dev/null
+++ b/ANode/src/SuiteChanged.hpp
@@ -0,0 +1,68 @@
+#ifndef SUITE_CHANGED_HPP_
+#define SUITE_CHANGED_HPP_
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <boost/noncopyable.hpp>
+#include "NodeFwd.hpp"
+
+namespace ecf {
+
+// Determine if suite was changed or modified if so, update suite change no
+// This mechanism was used because, when changing some attributes, we can not
+// immediately access the parent suites, to update the change numbers.
+//
+// When given a choice between where to add SuiteChanged, i.e in Node Tree or Commands
+// Generally favour commands, as it will require less maintenance over time.
+//
+// This mechanism was added specifically to support changes over client handles
+// i.e suites are added to handles, hence we need a way to determine which
+// suites (and hence handle) changed, and hence minimise the need for updates.
+
+class SuiteChanged : private boost::noncopyable {
+public:
+ SuiteChanged(suite_ptr s);
+ ~SuiteChanged();
+private:
+ weak_suite_ptr suite_;
+ unsigned int state_change_no_;
+ unsigned int modify_change_no_;
+};
+
+class SuiteChanged0 : private boost::noncopyable {
+public:
+ SuiteChanged0(node_ptr s);
+ ~SuiteChanged0();
+private:
+ weak_node_ptr node_;
+ Suite* suite_; // if node is removed suite pointer is not accessible, hence store first
+ unsigned int state_change_no_;
+ unsigned int modify_change_no_;
+};
+
+
+class SuiteChanged1 : private boost::noncopyable {
+public:
+ SuiteChanged1(Suite* s);
+ ~SuiteChanged1();
+private:
+ Suite* suite_;
+ unsigned int state_change_no_;
+ unsigned int modify_change_no_;
+};
+
+}
+#endif
diff --git a/ANode/src/System.cpp b/ANode/src/System.cpp
new file mode 100644
index 0000000..3894f79
--- /dev/null
+++ b/ANode/src/System.cpp
@@ -0,0 +1,411 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #39 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <assert.h>
+#include <iostream>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <errno.h>
+
+#ifndef O_WRONLY
+#include <fcntl.h>
+#endif
+
+#include "System.hpp"
+#include "Signal.hpp"
+#include "Defs.hpp"
+#include "Submittable.hpp"
+#include "SuiteChanged.hpp"
+#include "Log.hpp"
+
+//#define DEBUG_FORK 1
+//#define DEBUG_CATCH_CHILD 1
+//#define DEBUG_TERMINATED_CHILD 1
+//#define DEBUG_CHILD_ABORT 1
+
+using namespace std;
+
+namespace ecf {
+
+// ===========================================================================
+// Process
+// ===========================================================================
+struct Process {
+public:
+ Process(const std::string& absPath,const std::string& cmdToSpawn, pid_t pid)
+ : absNodePath_(absPath), cmd_(cmdToSpawn),have_status_(0), pid_(pid), status_(0) {}
+
+ std::string absNodePath_; // Path to Task(ECF_JOB_CMD), empty for ECF_KILL_CMD & ECF_STATUS_CMD
+ std::string cmd_; // the command that was spawned
+ sig_atomic_t have_status_;// Nonzero if this process has stopped or terminated. */
+ pid_t pid_; // The process ID of this child.
+ int status_; // The status of this child; 0 if running,
+ // otherwise a status value from waitpid
+};
+std::vector<Process> processVec_;
+
+/* Nonzero means some child's status has changed
+ so look at process_list for the details. */
+volatile int process_status_change_ = 0;
+
+
+// ===========================================================================
+// System
+// ===========================================================================
+System* System::instance_ = NULL;
+
+System* System::instance()
+{
+ if ( instance_ == NULL) {
+
+ // Block SIGCHLD so that we control, when child process termination is handled
+ ecf::Signal::block_sigchild();
+
+ // install signal handler, that will catch Child process termination
+ // The install function can be called asynchronously, and hence deserves
+ // special consideration. Currently we temporarily unblock pending
+ // SIGCHLD signals at the end of Job generation, and then block them again.
+ // During the brief moment between unblock/block we expect
+ // the handler to be called.
+ catchChildProcessTermination();
+
+ instance_ = new System();
+ }
+ return instance_;
+}
+
+void System::destroy()
+{
+ delete instance_;
+ instance_ = NULL;
+}
+
+System::System() {}
+System::~System(){}
+
+bool System::spawn(const std::string& cmdToSpawn,const std::string& absPath,std::string& errorMsg)
+{
+#ifdef DEBUG_FORK
+ std::cout << " System::spawn path(" << absPath << ") cmd(" << cmdToSpawn << ")\n";
+#endif
+
+ int rc = 1; /* Not a zero */
+ int tryi = 1; /* Currently hardcoded */
+
+ for (rc = 1; tryi && rc; tryi--) {
+ rc = sys(cmdToSpawn,absPath,errorMsg);
+ if ( rc ) sleep( 1 ); /* May be 2 many processes */
+ }
+
+ if ( rc ) {
+ std::stringstream ss;
+ ss << "Child process creation failed for command " << cmdToSpawn;
+ if ( !absPath.empty() ) ss << " at path(" << absPath << ")";
+ errorMsg = ss.str();
+#ifdef DEBUG_FORK
+ std::cout << " System::spawn returning false " << endl;
+#endif
+ return false;
+ }
+ return true;
+}
+
+int System::sys(const std::string& cmdToSpawn,const std::string& absPath,std::string& errorMsg)
+{
+#ifdef DEBUG_FORK
+ std::cout << " System::sys path(" << absPath << ") cmd(" << cmdToSpawn << ")\n";
+#endif
+ /**************************************************************************
+ ? Execute the command (cmdToSpawn) and return, DO NOT WAIT for the termination
+ | of the children.
+ | The stdin, stdout and stderr are closed (or redirected to /dev/null)
+ = PID in case of success or 0 in case of errors.
+ ************************************o*************************************/
+ pid_t child_pid;
+ if ( (child_pid = fork()) == 0 ) { /* The child */
+
+ int f;
+ close( 2 );
+ if ( (f = open( "/dev/null", O_WRONLY )) != 2 ) close( f );
+
+ close( 1 );
+ if ( (f = open( "/dev/null", O_WRONLY )) != 1 ) close( f );
+
+ close( 0 );
+ if ( (f = open( "/dev/null", O_RDONLY )) != 0 ) close( f );
+
+ // ==============================================================================
+ // Ideally we should close all open file descriptors in the child process
+ // On Linux: sysconf(_SC_OPEN_MAX); returns 1024
+ // This means making 1024 - 3 system calls
+ // This is especially import for socket descriptors, since if the server goes down
+ // The children/zombies will prevent the server restart on the same port.
+ // i.e the classic Address in use
+ // Its not clear how big a performance issue this, an alternative would be, to only close
+ // open socket file descriptors. But this will require a singleton of some sort
+ // ===============================================================================
+ int fd_limit = sysconf(_SC_OPEN_MAX);
+ for (int i=3; i<fd_limit; i++) close(i);
+
+ execl( "/bin/sh", "sh", "-c", cmdToSpawn.c_str(), (char *)NULL );
+ /*
+ * Maybe the file protection failed (no executable bit set)
+ * or the shell couldn't be found. Look at man execve(2).
+ */
+ _exit( 127 );
+ }
+
+ if ( child_pid == -1 ) {
+ std::stringstream ss;
+ ss << " ECF-PROCESS-SYS: FORK error for " << cmdToSpawn;
+ if (!absPath.empty()) ss << " and task " << absPath;
+ errorMsg = ss.str();
+ return 1;
+ }
+
+ // Store the process pid, so that we can wait for it. ho ho.
+ processVec_.push_back(Process(absPath,cmdToSpawn,child_pid));
+
+#ifdef DEBUG_FORK
+ //LogToCout logToCoutAsWell;
+ LOG( Log::DBG," submit: Path(" << absPath << ") child_pid(" << child_pid << ") cmd(" << cmdToSpawn << ")");
+#endif
+ return 0;
+}
+
+
+static void catch_child(int sig)
+/**************************************************************************
+? Catch the death of the child process
+| This function can be called asynchronously hence it could interfere
+ with the rest of program. Hence this function does not allocate or
+ free memory. We simply store the status, for later processing
+************************************o*************************************/
+{
+#ifdef DEBUG_CATCH_CHILD
+ std::cout << " catch_child (process death) sig = " << sig << endl;
+#endif
+
+ int saved_errno = errno; // save error number since waitpid can change this
+ int status;
+ pid_t child_pid;
+
+ // waitpid returns:
+ // - on success, returns the process ID of the child whose state has changed
+ // - if WNOHANG was specified and one or more child(ren) specified by pid exist,
+ // but have *NOT* yet changed state, then *0* is returned
+ // *** hence we MUST check for 0, other wise we will end up in an infinite loop **
+ // - returns -1 on error
+ while ( (child_pid = waitpid( -1, &status, WNOHANG )) != -1 && child_pid != 0) {
+
+ std::vector<Process>::iterator theEnd = processVec_.end();
+ for(std::vector<Process>::iterator i = processVec_.begin(); i!= theEnd; ++i) {
+ if ((*i).pid_ == child_pid) {
+
+#ifdef DEBUG_CATCH_CHILD
+ std::cout << " catch_child Found pid " << child_pid << endl;
+#endif
+ // Indicate that the status field
+ // has data to look at. We do this only after storing it.
+ (*i).have_status_ = 1;
+
+ // store the status
+ (*i).status_ = status;
+
+ // The program should check this flag from time to time
+ // to see if there is any news in processVec_.
+ process_status_change_++;
+ break;
+ }
+ }
+ }
+
+ // restore error number
+ errno = saved_errno ;
+}
+
+void System::processTerminatedChildren()
+{
+#ifdef DEBUG_TERMINATED_CHILD
+ std::cout << "System::processTerminatedChildren() process_status_change_ = " << process_status_change_
+ << " processVec_.size() = " << processVec_.size() << endl;
+ LogToCout logToCoutAsWell;
+#endif
+ if ( process_status_change_ == 0) {
+ return;
+ }
+
+ // Must be the first thing we do.
+ process_status_change_ = 0;
+
+ std::vector<Process>::iterator i;
+ for(i = processVec_.begin(); i!= processVec_.end(); ++i) {
+
+ if ((*i).have_status_) {
+
+#ifdef DEBUG_TERMINATED_CHILD
+ std::cout << "System::processTerminatedChildren() path(" << (*i).absNodePath_ << ") pid(" << (*i).pid_ << ") has status " << endl;
+#endif
+ // exit status is one of mutually exclusive [ WIFEXITED | WIFSIGNALED | WIFSTOPPED | WIFCONTINUED ]
+ if (WIFEXITED((*i).status_)) {
+
+ // *Normal* termination via exit
+ if ( WEXITSTATUS( (*i).status_ )) {
+ // exit is non zero.
+ std::stringstream ss; ss << " PID(" << (*i).pid_ << ") path(" << (*i).absNodePath_ << ") exited with status " << WEXITSTATUS((*i).status_)<< " [ " << (*i).cmd_ << " ]";
+ died( (*i).absNodePath_, ss.str());
+ }
+ else {
+ // exit(0) child terminated normally
+#ifdef DEBUG_TERMINATED_CHILD
+ LOG( Log::DBG, "PID " << (*i).pid_ << " exited normally [ " << (*i).cmd_ << " ]" );
+#endif
+ }
+
+ // remove the process since it has terminated
+ processVec_.erase(i--);
+ }
+ else if ( WIFSIGNALED( (*i).status_) ) {
+
+ // *abnormal* child process terminated by a signal
+ std::stringstream ss; ss << " ECF-PROCESS-CHILD:PID(" << (*i).pid_ << ") path(" << (*i).absNodePath_ << ") died of signal " << WTERMSIG((*i).status_) << " [ " << (*i).cmd_ << " ]";
+ died( (*i).absNodePath_, ss.str());
+
+ // remove the process since it has terminated
+ processVec_.erase(i--);
+ }
+ else if ( WIFSTOPPED( (*i).status_) ) {
+
+ LOG( Log::WAR, " ECF-PROCESS-CHILD:PID " << (*i).pid_ << " STOPPED? [ " << (*i).absNodePath_ << " ] [ " << (*i).cmd_ << " ]");
+ }
+ else {
+
+ // Can only be WIFCONTINUED. (XSI extension to POSIX)
+ LOG( Log::WAR, " ECF-PROCESS-CHILD:PID " << (*i).pid_ << " CONTINUED? [ " << (*i).absNodePath_ << " ] [ " << (*i).cmd_ << " ]");
+ }
+ }
+ else {
+#ifdef DEBUG_TERMINATED_CHILD
+ LOG( Log::DBG, " ECF-PROCESS-CHILD:stray PID " << (*i).pid_ << " (ignored) [ " << (*i).cmd_ << " ]" );
+#endif
+ }
+ }
+
+#ifdef DEBUG_TERMINATED_CHILD
+ std::cout << "System::processTerminatedChildren() process size = " << processVec_.size() << endl;
+#endif
+}
+
+int System::process() const
+{
+ return static_cast<int>(processVec_.size());
+}
+
+// ============================================================================
+// See: Advanced programming in the UNIX environment: Page 328
+// Note: with sigaction the handle stays installed, until changed
+// this is different to the signal(..) which on some system needs
+// to be reinstalled at start/end of SignalFunction.
+// ============================================================================
+typedef void SignalFunction(int);
+SignalFunction* signal_(int signo, SignalFunction* func)
+{
+ struct sigaction act, oact;
+ act.sa_handler = func;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+ if (signo == SIGALRM) {
+#ifdef SA_INTERRUPT
+ act.sa_flags |= SA_INTERRUPT;
+#endif
+ }
+ else {
+ // We intentionally try to set the SA_RESTART flag for all signals other than SIGALRM
+ // so that any system call interrupted by these other signals in automatically restarted
+#ifdef SA_RESTART
+ act.sa_flags |= SA_RESTART;
+#endif
+ }
+
+ if (sigaction(signo, &act, &oact) < 0)
+ return (SIG_ERR);
+
+ // Return the old handler
+ return oact.sa_handler;
+}
+
+void System::catchChildProcessTermination()
+{
+ // Call our local version (which uses sigaction) rather than the out date signal(..)
+ signal_( SIGCHLD, catch_child );
+}
+
+void System::died( const std::string& absNodePath, const std::string& reason)
+/**************************************************************************
+ ? Process the death of the process. This is most unwanted and implies
+ | that the shell died abnormally.
+ ************************************o*************************************/
+{
+#ifdef DEBUG_CHILD_ABORT
+ std::cout << "System::died path = '" << absNodePath << "'" << endl;
+#endif
+
+ /// always write to log, before returning
+ ecf::log(Log::ERR,reason);
+
+ /// If the Path is empty, then this could be something *OTHER THAN* job submission
+ /// that has failed. i.e kill cmd, or any other command, so don;t assert
+ if ( absNodePath.empty() ) {
+ return;
+ }
+
+ defs_ptr defs = defs_.lock();
+ if ( !defs.get() ) {
+ LOG_ASSERT(defs.get(),"System::died, defs not defined ???");
+ return;
+ }
+
+ node_ptr node = defs->findAbsNode( absNodePath );
+ if ( !node.get() ) {
+#ifdef DEBUG_CHILD_ABORT
+ std::cout << "System::died " << absNodePath << " could not be found in defs \n";
+#endif
+ return;
+ }
+
+ Submittable* submittable = node->isSubmittable();
+ if ( !submittable ) {
+#ifdef DEBUG_CHILD_ABORT
+ std::cout << "System::died " << absNodePath << " path is NOT a Task or Alias \n";
+#endif
+ return;
+ }
+
+ // This function can get called at any time.
+ // AND out of context of any command, hence we must handle case where Suite handles are used.
+ // Otherwise the view will not know about aborted states.
+ // ECFLOW-104 aborted state for a task following an error at submission
+ SuiteChanged1 changed(submittable->suite());
+
+ submittable->flag().set(ecf::Flag::JOBCMD_FAILED);
+
+#ifdef DEBUG_CHILD_ABORT
+ std::cout << "System::died aborting task " << absNodePath << "\n";
+#endif
+ // Set state aborted since the job terminated abnormally, and provide a reason
+ submittable->aborted(reason);
+}
+
+}
diff --git a/ANode/src/System.hpp b/ANode/src/System.hpp
new file mode 100644
index 0000000..a01b830
--- /dev/null
+++ b/ANode/src/System.hpp
@@ -0,0 +1,89 @@
+#ifndef SYSTEM_HPP_
+#define SYSTEM_HPP_
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #18 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Works with class Signal
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <string>
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+
+#include "NodeFwd.hpp"
+
+namespace ecf {
+
+/// Job submission in ECF is a two phase step.
+/// phase 1: Spawn of ECF_JOB_CMD
+/// phase 2: Invocation of ECF_JOB_CMD, this creates the *real* job which communicates with the server
+/// For TEST :ECF_JOB_CMD = "%ECF_JOB% 1> %ECF_JOBOUT% 2>&1
+/// this collapses phase 1 and 2, to a single step
+/// For Operation:ECF_JOB_CMD = ecf_submit %USER% %REMOTE_HOST% %ECFJOB% %ECFJOBOUT%'
+/// This uses ecf_submit,This spawns the process to the different load levellers depending on OS, etc.
+/// and hence involves at least 2 process.
+/// This class handles phase 1, we capture the death of the child process
+/// and hence this class will not in operations handle the death of the real job
+/// created by ecf_submit.
+
+class System : private boost::noncopyable {
+public:
+ static System* instance();
+
+ /// Destroy the singleton. used in test only, to avoid valgrind issues
+ static void destroy();
+
+ /// Let the server set this. Typically only set once, however in test can be many times
+ /// Note:: In test the Defs file in the server can be cleared, i.e. for each new test
+ /// Hence we maintain a weak_ptr to the Defs.
+ void setDefs(const defs_ptr& defs) { defs_ = defs;}
+
+ // return true, if command can be spawned, else false.
+ // For jobs, We can't store reference to Task*, as future functionality like
+ // auto-migrate, etc, means we may end up pointing to garbage.
+ // so instead we will store absNodePath. For other commands this can be empty
+ bool spawn(const std::string& cmdToSpawn,const std::string& absPath,std::string& errorMsg);
+
+ // Handle children that have stopped,aborted or terminated, etc
+ // The signal handler is kept as light as possible, since it is re-entrant.
+ // So Signal handles stores the termination state which handled later
+ // by processTerminatedChildren. Typically when we un-block SIGCHILD
+ void processTerminatedChildren();
+
+ /// returns the number of active process.
+ /// for debug only
+ int process() const;
+
+private:
+ ~System();
+ System();
+
+ /// Install signals that can catch signal from child process termination
+ static void catchChildProcessTermination();
+
+ // When a process terminates abnormally. This function is used to find the
+ // associated task, and set it to the abort state.
+ // Relies on the stored Defs ptr. which was set in the server
+ void died( const std::string& absNodePath, const std::string& reason);
+
+ /// Does the real work of spawning children
+ int sys(const std::string& cmdToSpawn,const std::string& absPath,std::string& errorMsg);
+
+private:
+ weak_defs_ptr defs_; // weak_ptr is an observer of a shared_ptr
+ static System* instance_;
+};
+
+}
+#endif
diff --git a/ANode/src/Task.cpp b/ANode/src/Task.cpp
new file mode 100644
index 0000000..f389aa1
--- /dev/null
+++ b/ANode/src/Task.cpp
@@ -0,0 +1,809 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #204 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <assert.h>
+#include <sstream>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include "boost/filesystem/exception.hpp"
+#include <boost/bind.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/make_shared.hpp>
+
+#include "Task.hpp"
+#include "Defs.hpp"
+#include "PrintStyle.hpp"
+#include "Suite.hpp"
+#include "SuiteChanged.hpp"
+#include "NodeTreeVisitor.hpp"
+#include "File.hpp"
+#include "Stl.hpp"
+#include "Str.hpp"
+#include "Indentor.hpp"
+#include "Log.hpp"
+#include "ExprAst.hpp"
+#include "JobsParam.hpp"
+#include "Ecf.hpp"
+#include "DefsDelta.hpp"
+#include "TaskScriptGenerator.hpp"
+#include "Extract.hpp"
+#include "JobProfiler.hpp"
+
+namespace fs = boost::filesystem;
+using namespace ecf;
+using namespace std;
+using namespace boost;
+
+//#define DEBUG_TASK_LOCATION 1
+
+Task::~Task()
+{
+ if (!Ecf::server()) {
+ notify_delete();
+ }
+}
+
+task_ptr Task::create(const std::string& name)
+{
+ return boost::make_shared<Task>( name );
+}
+
+std::ostream& Task::print(std::ostream& os) const
+{
+ Indentor in;
+ Indentor::indent(os) << "task " << name();
+ if (!PrintStyle::defsStyle()) {
+ std::string st = write_state();
+ if (!st.empty()) os << " #" << st;
+ }
+ os << "\n";
+
+ Node::print(os);
+
+ // Generated variable are not persisted since they are created on demand
+ // There *NO* point in printing them they will always be empty
+
+ // Alias are not printed, but are check point able.
+ if (!PrintStyle::defsStyle()) {
+ Indentor in2;
+ size_t node_vec_size = aliases_.size();
+ for(size_t t = 0; t < node_vec_size; t++) { aliases_[t]->print( os ); }
+ if (node_vec_size != 0) {
+ Indentor in3;
+ Indentor::indent(os) << "endalias\n";
+ }
+ }
+
+ // if ( PrintStyle::defsStyle() ) Indentor::indent(os) << "endtask\n";
+ return os;
+}
+
+std::string Task::write_state() const
+{
+ // *IMPORTANT* we *CANT* use ';' character, since is used in the parser, when we have
+ // multiple statement on a single line i.e.
+ // task a; task b;
+ std::stringstream ss;
+ if (alias_no_ != 0) ss << " alias_no:" << alias_no_;
+ ss << Submittable::write_state();
+ return ss.str();
+}
+
+void Task::read_state(const std::string& line, const std::vector<std::string>& lineTokens) {
+
+ // task t1 # alias_no:0 passwd:_DJP_
+ std::string token;
+ for(size_t i = 3; i < lineTokens.size(); i++) {
+ token.clear();
+ if (lineTokens[i].find("alias_no:") != std::string::npos ) {
+ if (!Extract::split_get_second(lineTokens[i],token)) throw std::runtime_error( "Task::read_state could not read alias_no for task " + name());
+ alias_no_ = Extract::theInt(token,"Task::read_state: invalid alias_no specified : " + line);
+ break;
+ }
+ }
+ Submittable::read_state(line,lineTokens);
+}
+
+std::ostream& operator<<(std::ostream& os, const Task& d) { return d.print(os); }
+
+bool Task::operator==(const Task& rhs) const
+{
+ if (alias_no_ != rhs.alias_no_) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Task::operator== alias_no_(" << alias_no_ << ") != rhs.alias_no_(" << rhs.alias_no_ << ") : " << absNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+
+ size_t vec_size = aliases_.size();
+ if ( vec_size != rhs.aliases_.size()) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Task::operator== aliases_.size() != rhs.aliases_.size() " << absNodePath() << "\n";
+ std::cout << " aliases_.size() = " << vec_size << " rhs.aliases_.size() = " << rhs.aliases_.size() << "\n";
+ }
+#endif
+ return false;
+ }
+
+ for(size_t i =0; i < vec_size; ++i) {
+
+ if ( !( *aliases_[i] == *rhs.aliases_[i] )) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "Task::operator== !( *aliases_[i] == *rhs.aliases_[i] : " << absNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ }
+
+ return Submittable::operator==(rhs);
+}
+
+alias_ptr Task::add_alias(std::vector<std::string>& user_file_contents,const NameValueVec& user_variables,bool create_directory)
+{
+ // Create directory
+ std::string dir_to_create;
+ if (create_directory) {
+
+ if (user_file_contents.empty()) {
+ std::stringstream ss;
+ ss << "Task::add_alias: No .usr file contents specified. Alias creation failed for task " << absNodePath();
+ throw std::runtime_error(ss.str());
+ }
+
+ findParentUserVariableValue( Str::ECF_HOME(), dir_to_create);
+ dir_to_create += absNodePath();
+ if (!File::createDirectories(dir_to_create)) {
+ throw std::runtime_error("Task::add_alias: could not create directory " + dir_to_create);
+ }
+ }
+
+ // create alias
+ std::string alias_name = "alias" + boost::lexical_cast<std::string>(alias_no_);
+ alias_ptr alias = Alias::create( alias_name );
+ alias->set_parent(this);
+
+ // create .usr file
+ if (create_directory) {
+ std::string file_path = dir_to_create + "/" + alias_name + alias->script_extension();
+ std::string error_msg;
+ if (!File::create(file_path,user_file_contents,error_msg)) {
+ std::stringstream ss; ss << "Task::add_alias: could not create .usr file at path(" << file_path <<"): " << error_msg.c_str();
+ throw std::runtime_error(ss.str());
+ }
+ }
+
+ // copy over events, meters, labels
+ BOOST_FOREACH(const Meter& meter, meters()) { alias->addMeter(meter); }
+ BOOST_FOREACH(const Event& event, events()) { alias->addEvent(event); }
+ BOOST_FOREACH(const Label& label, labels()) { alias->addLabel(label); }
+
+ // Add user_variables as variables. Note: to reduce memory we could choose
+ // to only add those variable that have been changed/added. However this
+ // would mean an alias could be affected by changed to an inherited variable.
+ // Hence kept as existing sms functionality
+ //
+ // The variables may be **different** to normal variables in that they may contain a ":" & $
+ // This is **not** allowed in normal variables.
+ // i.e it allows for %A:1%, %A:2%, %A:3%
+ // This is not really recommended but its what the old system supported.
+ // **** Hence add_alias_variable by passes variable name checking ***
+ NameValueVec::const_iterator theEnd = user_variables.end();
+ for(NameValueVec::const_iterator i = user_variables.begin(); i!=theEnd; ++i) {
+ alias->add_alias_variable((*i).first, (*i).second);
+ }
+
+ // increment alias number and store, alias in vector
+ alias_no_++; // Alias number must be set to next valid alias number
+ aliases_.push_back(alias);
+
+ alias_change_no_ = Ecf::incr_state_change_no();
+ add_remove_state_change_no_ = alias_change_no_;
+ return alias;
+}
+
+alias_ptr Task::add_alias_only()
+{
+ std::vector<std::string> empty_user_file_contents;
+ NameValueVec empty_user_variables;
+ return add_alias(empty_user_file_contents,empty_user_variables,false/* don't create directory or .usr file*/);
+}
+
+alias_ptr Task::add_alias(const std::string& name)
+{
+ // Do not update alias_no, since that will be read in
+ alias_ptr alias = Alias::create( name );
+ alias->set_parent(this);
+ aliases_.push_back(alias);
+ return alias;
+}
+
+alias_ptr Task::find_alias(const std::string& name) const
+{
+ size_t vec_size = aliases_.size();
+ for(size_t i = 0; i < vec_size; i++) {
+ if (aliases_[i]->name() == name) {
+ return aliases_[i];
+ }
+ }
+ return alias_ptr();
+}
+
+void Task::reset_alias_number()
+{
+ alias_no_ = 0;
+ alias_change_no_ = Ecf::incr_state_change_no();
+}
+
+node_ptr Task::findImmediateChild(const std::string& name, size_t& child_pos) const
+{
+ child_pos = std::numeric_limits<std::size_t>::max();
+ size_t vec_size = aliases_.size();
+ for(size_t i = 0; i < vec_size; i++) {
+ if (aliases_[i]->name() == name) {
+ child_pos = i;
+ return aliases_[i];
+ }
+ }
+ return node_ptr();
+}
+
+void Task::begin()
+{
+ if (aliases_.empty()) {
+ if (alias_no_ != 0) {
+ reset_alias_number();
+ }
+ }
+
+ Submittable::begin();
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Task::begin()\n";
+#endif
+}
+
+void Task::requeue(
+ bool resetRepeats,
+ int clear_suspended_in_child_nodes,
+ bool reset_next_time_slot)
+{
+ if (aliases_.empty()) {
+ if (alias_no_ != 0) {
+ reset_alias_number();
+ }
+ }
+
+ Submittable::requeue(resetRepeats,
+ clear_suspended_in_child_nodes,
+ reset_next_time_slot);
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "Task::requeue\n";
+#endif
+}
+
+void Task::accept(ecf::NodeTreeVisitor& v)
+{
+ v.visitTask(this);
+}
+
+void Task::acceptVisitTraversor(ecf::NodeTreeVisitor& v)
+{
+ v.visitTask(this);
+}
+
+const std::string& Task::debugType() const { return ecf::Str::TASK();}
+
+void Task::getAllNodes(std::vector<Node*>& vec) const
+{
+ // See notes: getAllSubmittables, about reserve
+ size_t vec_size = aliases_.size();
+ for(size_t i = 0; i < vec_size; i++) {
+ vec.push_back( aliases_[i].get() );
+ }
+}
+
+void Task::immediateChildren(std::vector<node_ptr>& vec) const
+{
+ size_t vec_size = aliases_.size();
+ vec.reserve(vec.size() + vec_size);
+ for(size_t i = 0; i < vec_size; i++) {
+ vec.push_back( boost::dynamic_pointer_cast<Node>(aliases_[i]) );
+ }
+}
+
+void Task::getAllTasks(std::vector<Task*>& vec) const
+{
+ vec.push_back(const_cast<Task*>(this));
+}
+
+void Task::getAllSubmittables(std::vector<Submittable*>& vec) const
+{
+ // *DO NOT reserve here, as it dominate time , for very large defs */
+ // * Previously we had::
+ // vec.reserve(vec.size() + vec_size + 1);
+ // * This took 47 seconds when delete the full defs, i.e when check for active tasks
+
+ vec.push_back(const_cast<Task*>(this));
+ size_t vec_size = aliases_.size();
+ for(size_t i = 0; i < vec_size; i++) {
+ vec.push_back( aliases_[i].get() );
+ }
+}
+
+node_ptr Task::find_node_up_the_tree(const std::string& name) const
+{
+ size_t vec_size = aliases_.size();
+ for(size_t i = 0; i < vec_size; i++) {
+ if (aliases_[i]->name() == name ) {
+ return aliases_[i];
+ }
+ }
+ Node* the_parent = parent();
+ if (the_parent) return the_parent->find_node_up_the_tree(name);
+ return node_ptr();
+}
+
+void Task::get_all_active_submittables(std::vector<Submittable*>& vec) const
+{
+ // See notes: getAllSubmittables, about reserve
+ if (state() == NState::ACTIVE || state() == NState::SUBMITTED) {
+ vec.push_back(const_cast<Task*>(this));
+ }
+ size_t vec_size = aliases_.size();
+ for(size_t i = 0; i < vec_size; i++) {
+ if (aliases_[i]->state() == NState::ACTIVE || aliases_[i]->state() == NState::SUBMITTED) {
+ vec.push_back( aliases_[i].get() );
+ }
+ }
+}
+
+void Task::get_all_tasks(std::vector<task_ptr>& vec) const
+{
+ vec.push_back(boost::dynamic_pointer_cast<Task>(non_const_this()));
+}
+
+void Task::get_all_nodes(std::vector<node_ptr>& nodes) const
+{
+ nodes.push_back( non_const_this() );
+ size_t vec_size = aliases_.size();
+ for(size_t i = 0; i < vec_size; i++) {
+ aliases_[i]->get_all_nodes(nodes);
+ }
+}
+
+void Task::get_all_aliases(std::vector<alias_ptr>& destinationVec) const
+{
+ destinationVec.reserve(destinationVec.size() + aliases_.size());
+ std::copy(aliases_.begin(),aliases_.end(),std::back_inserter(destinationVec));
+}
+
+bool Task::resolveDependencies(JobsParam& jobsParam)
+{
+ if (jobsParam.timed_out_of_job_generation()) return false;
+ JobProfiler profile_me(this,jobsParam,JobProfiler::task_threshold());
+ if (jobsParam.timed_out_of_job_generation()) return false;
+
+
+ // Calling Submittable::resolveDependencies(jobsParam) up front can be expensive.
+ // Due to trigger and complete evaluations. Hence low cost state checks first
+
+ // Do state checking for tasks only. Note: container nodes inherit the most significant state
+ // from the children, hence we can't use the same same algorithm for containers nodes and leaf
+ // nodes like task.
+ NState::State task_state = state();
+ if ( task_state == NState::ACTIVE || task_state == NState::SUBMITTED || task_state == NState::UNKNOWN || task_state == NState::COMPLETE) {
+#ifdef DEBUG_DEPENDENCIES
+ LOG(Log::DBG," Task::resolveDependencies() " << absNodePath() << " HOLDING as task state " << NState::toString(state()) << " is not valid for job submission" );
+#endif
+ return false;
+ }
+ else if (task_state == NState::ABORTED) {
+
+ /// If we have been forcibly aborted by the user. Do not resubmit jobs, until *begin* or *re-queue*. ECFLOW-344
+ if (flag().is_set(ecf::Flag::FORCE_ABORT)) {
+#ifdef DEBUG_DEPENDENCIES
+ LOG(Log::DBG," Task::resolveDependencies() " << absNodePath() << " HOLDING as task state " << NState::toString(state()) << " has been forcibly aborted." );
+#endif
+ return false;
+ }
+
+ /// If we have been killed by the user. Do not resubmit jobs, until *begin* or *re-queue*
+ if (flag().is_set(ecf::Flag::KILLED)) {
+#ifdef DEBUG_DEPENDENCIES
+ LOG(Log::DBG," Task::resolveDependencies() " << absNodePath() << " HOLDING as task state " << NState::toString(state()) << " has been killed." );
+#endif
+ return false;
+ }
+
+ // If the task was aborted, and we have not exceeded ECF_TRIES, then resubmit
+ // otherwise ONLY in state QUEUED can we submit jobs
+ std::string varValue;
+ if (findParentUserVariableValue( Str::ECF_TRIES(), varValue )) {
+ // std::cout << "tryNo_ = " << tryNo_ << " ECF_TRIES = " << varValue << "\n";
+ try {
+ int ecf_tries = boost::lexical_cast< int > (varValue);
+ if ( try_no() >= ecf_tries ) {
+#ifdef DEBUG_DEPENDENCIES
+ LOG(Log::DBG," Task::resolveDependencies() " << absNodePath() << " HOLDING as tryNo_(" << tryNo_ ") >= ECF_TRIES(" << ecf_tries << ") state = " << NState::toString(state()));
+#endif
+ return false;
+ }
+ }
+ catch ( boost::bad_lexical_cast& ) {
+ LOG(Log::ERR,"Variable ECF_TRIES must be convertible to an integer. Can not resubmit job for task:" << absNodePath());
+ return false;
+ }
+ }
+ }
+#ifdef DEBUG
+ else {
+ /// Only one state left
+ assert(task_state == NState::QUEUED);
+ }
+#endif
+
+ /// If we have been forcibly aborted by the user. Do not resubmit jobs, until *begin* or *re-queue*
+ /// This can be set via ALTER, so independent of state.
+ if (flag().is_set(ecf::Flag::FORCE_ABORT)) {
+#ifdef DEBUG_DEPENDENCIES
+ LOG(Log::DBG," Task::resolveDependencies() " << absNodePath() << " HOLDING as task state " << NState::toString(state()) << " has been forcibly aborted." );
+#endif
+ return false;
+ }
+
+
+ if ( ! Node::resolveDependencies(jobsParam) ) {
+
+#ifdef DEBUG_JOB_SUBMISSION
+ LOG(Log::DBG, " Task::resolveDependencies " << absNodePath() << " could not resolve dependencies, may have completed");
+ cout << "Task::resolveDependencies " << absNodePath() << " could not resolve dependencies may have completed" << endl;
+#endif
+ return false;
+ }
+
+ /// By default node tree traversal is top down. hence we only check in limits, at *that* level.
+ /// However *EACH* job submission can *affect* the in limits, hence we *must* check we are in
+ /// limit *up* the node tree. Done last and only in this function (as opposed to Node) as an optimisation
+ if (!check_in_limit_up_node_tree()) {
+#ifdef DEBUG_DEPENDENCIES
+ LOG(Log::DBG," Task::resolveDependencies() " << absNodePath() << " FREE of TRIGGER and inLIMIT");
+#endif
+ return false;
+ }
+
+ // call just before job submission, reset data members, update try_no, and generate variable
+ // *PLACED* outside of submitJob() so that we can configure job generation file ECF_JOB for test/python
+ increment_try_no(); // will increment state_change_no
+
+ if ( jobsParam.createJobs() ) {
+ // The task are ready for job submission.Clear process id and remote id (ECF_RID)
+ // Locate the ecf files corresponding to the task. Pre-process
+ // them(i.e expand includes, remove comments,manual) and perform
+ // variable substitution. This will then form the jobs file.
+ // If the job file already exist it is overridden
+ submit_job_only( jobsParam );
+ }
+ else {
+ // *************************************************************************************
+ // Debug/test path only... Enabled for testing when we don't want to create/spawn jobs
+ // ** Simulate ** job submission as closely as possible. For testing
+ // *************************************************************************************
+ jobsParam.push_back_submittable( this );
+
+ // follow normal life cycle queued->submitted->active. In real life there may be a noticeable
+ // time delay between process creation (via a user command, which could do anything)
+ // and when created process start talking back to the server.
+ // *** Setting state to SUBMITTED will increment any inlimit/Limit via handleStateChange
+ set_state( NState::SUBMITTED );
+
+ // The spawned process will typically call this, via client api. Set task into active state
+ // *** Test path, we take the hit of calling handleStateChange again.
+ init(Submittable::DUMMY_PROCESS_OR_REMOTE_ID());
+ }
+ return true;
+}
+
+void Task::generate_scripts( const std::map<std::string,std::string>& override) const
+{
+ TaskScriptGenerator ecf(this);
+ ecf.generate(override);
+}
+
+node_ptr Task::removeChild(Node* child)
+{
+#ifdef DEBUG
+ assert(child);
+ assert(child->isAlias());
+#endif
+ SuiteChanged1 changed(suite());
+ size_t node_vec_size = aliases_.size();
+ for(size_t t = 0; t < node_vec_size; t++) {
+ if (aliases_[t].get() == child) {
+ child->set_parent(NULL);
+ node_ptr node = boost::dynamic_pointer_cast<Alias>(aliases_[t]);
+ aliases_.erase( aliases_.begin() + t);
+ add_remove_state_change_no_ = Ecf::incr_state_change_no();
+ return node ;
+ }
+ }
+ // Should never happen
+ LOG_ASSERT(false,"Task::removeChild: Could not remove child");
+ return node_ptr();
+}
+
+bool Task::doDeleteChild(Node* child)
+{
+ SuiteChanged1 changed(suite());
+ std::vector<alias_ptr>::iterator the_end = aliases_.end();
+ for(std::vector<alias_ptr>::iterator t = aliases_.begin(); t!=the_end; ++t) {
+ if ( (*t).get() == child) {
+ if (child && child->parent()) child->set_parent(NULL);
+ aliases_.erase(t);
+ add_remove_state_change_no_ = Ecf::incr_state_change_no();
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Task::addChild( node_ptr, size_t)
+{
+ // Only used during PLUG: aliases can't be plugged.
+ LOG_ASSERT(false,"");
+ return false;
+}
+
+bool Task::isAddChildOk( Node*, std::string& errorMsg) const
+{
+ // Only used during PLUG: aliases can't be plugged.
+ errorMsg += "Can not add children to a task node.";
+ return false;
+}
+
+size_t Task::child_position(const Node* child) const
+{
+ size_t vec_size = aliases_.size();
+ for(size_t t = 0; t < vec_size; t++) {
+ if (aliases_[t].get() == child) {
+ return t;
+ }
+ }
+ return std::numeric_limits<std::size_t>::max();
+}
+
+void Task::order(Node* immediateChild, NOrder::Order ord)
+{
+ SuiteChanged1 changed(suite());
+ switch (ord) {
+ case NOrder::TOP: {
+ for(std::vector<alias_ptr>::iterator i = aliases_.begin(); i != aliases_.end(); ++i) {
+ if ((*i).get() == immediateChild) {
+ alias_ptr node = (*i);
+ aliases_.erase(i);
+ aliases_.insert(aliases_.begin(),node);
+ order_state_change_no_ = Ecf::incr_state_change_no();
+ return;
+ }
+ }
+ throw std::runtime_error("Task::order TOP, immediate child not found");
+ }
+ case NOrder::BOTTOM: {
+ for(std::vector<alias_ptr>::iterator i = aliases_.begin(); i != aliases_.end(); ++i) {
+ if ((*i).get() == immediateChild) {
+ alias_ptr node = (*i);
+ aliases_.erase(i);
+ aliases_.push_back(node);
+ order_state_change_no_ = Ecf::incr_state_change_no();
+ return;
+ }
+ }
+ throw std::runtime_error("Task::order BOTTOM, immediate child not found");
+ }
+ case NOrder::ALPHA: {
+ std::sort(aliases_.begin(),aliases_.end(),
+ boost::bind(Str::caseInsLess,
+ boost::bind(&Node::name,_1),
+ boost::bind(&Node::name,_2)));
+ order_state_change_no_ = Ecf::incr_state_change_no();
+ break;
+ }
+ case NOrder::ORDER: {
+ std::sort(aliases_.begin(),aliases_.end(),
+ boost::bind(Str::caseInsGreater,
+ boost::bind(&Node::name,_1),
+ boost::bind(&Node::name,_2)));
+ order_state_change_no_ = Ecf::incr_state_change_no();
+ break;
+ }
+ case NOrder::UP: {
+ for(size_t t = 0; t < aliases_.size();t++) {
+ if ( aliases_[t].get() == immediateChild) {
+ if (t != 0) {
+ alias_ptr node = aliases_[t];
+ aliases_.erase(aliases_.begin()+t);
+ t--;
+ aliases_.insert(aliases_.begin()+t,node);
+ order_state_change_no_ = Ecf::incr_state_change_no();
+ }
+ return;
+ }
+ }
+ throw std::runtime_error("Task::order UP, immediate child not found");
+ }
+ case NOrder::DOWN: {
+ for(size_t t = 0; t < aliases_.size();t++) {
+ if ( aliases_[t].get() == immediateChild) {
+ if (t != aliases_.size()-1) {
+ alias_ptr node = aliases_[t];
+ aliases_.erase(aliases_.begin()+t);
+ t++;
+ aliases_.insert(aliases_.begin()+t,node);
+ order_state_change_no_ = Ecf::incr_state_change_no();
+ }
+ return;
+ }
+ }
+ throw std::runtime_error("Task::order DOWN, immediate child not found");
+ }
+ }
+}
+
+bool Task::checkInvariants(std::string& errorMsg) const
+{
+ if (!Node::checkInvariants(errorMsg)) return false;
+
+ size_t vec_size = aliases_.size();
+ for(size_t t = 0; t < vec_size; t++) {
+ if (aliases_[t]->parent() != this) {
+ std::stringstream ss;
+ ss << "Task::checkInvariants alias(" << aliases_[t]->name() << ") parent() not correct. See task : " << absNodePath();
+ errorMsg += ss.str();
+ return false;
+ }
+ if (!aliases_[t]->checkInvariants(errorMsg)) {
+ return false;
+ }
+ }
+ if ( vec_size > alias_no_ ) {
+ std::stringstream ss;
+ ss << "Task::checkInvariants: alias vector size " << vec_size << " should be less or equal to alias_no_ " << alias_no_ << " for task " << absNodePath() << "\n";
+ errorMsg += ss.str();
+ return false;
+ }
+ return true;
+}
+
+void Task::handleStateChange()
+{
+ /// Increment/decrement limits based on the current state
+ update_limits();
+
+ // Check if a re queue is required, then can eventually change the state, if
+ // repeats, time,today, or cron are involved, hence must be done last
+ // This will recurse up the node tree, causing repeats to increment, at the parent
+ // level and resetting repeats in the children. To mimic nested loops.
+ requeueOrSetMostSignificantStateUpNodeTree();
+}
+
+const std::string& Task::script_extension() const
+{
+ // Migration support, allow user to specify extension. This allows users to use '.sms'
+ // Note: This should be removed in the future since there is performance hit.
+ // searching up the node tree, when most of the time we are using .ecf
+ const std::string& ecf_extn = find_parent_user_variable_value(Str::ECF_EXTN());
+ if (!ecf_extn.empty()) return ecf_extn;
+ return File::ECF_EXTN(); // ".ecf"
+}
+
+void Task::collateChanges(DefsDelta& changes) const
+{
+// std::cout << "Task::collateChanges " << debugNodePath()
+// << " changes.client_state_change_no() = " << changes.client_state_change_no()
+// << " add_remove_state_change_no_ = " << add_remove_state_change_no_
+// << " order_state_change_no_ = " << order_state_change_no_
+// << " alias_change_no_ " << alias_change_no_
+// << "\n";
+
+ /// All changes to Task should be on ONE compound_memento_ptr
+ compound_memento_ptr comp;
+
+ /// There no point doing a OrderMemento if children have been added/delete
+ if (add_remove_state_change_no_ > changes.client_state_change_no()) {
+ if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
+ comp->add( boost::make_shared<AliasChildrenMemento>( aliases_ ) );
+ }
+ else if (order_state_change_no_ > changes.client_state_change_no()) {
+ if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
+ std::vector<std::string> order_vec; order_vec.reserve(aliases_.size());
+ size_t node_vec_size = aliases_.size();
+ for(size_t i =0; i < node_vec_size; i++) order_vec.push_back( aliases_[i]->name());
+ comp->add( boost::make_shared<OrderMemento>( order_vec ) );
+ }
+
+ if (alias_change_no_ > changes.client_state_change_no()) {
+ if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
+ comp->add( boost::make_shared<AliasNumberMemento>( alias_no_ ) );
+ }
+
+ // ** base class will add compound memento into changes.
+ Submittable::incremental_changes(changes, comp);
+
+ // Traversal to children
+ size_t vec_size = aliases_.size();
+ for(size_t t = 0; t < vec_size; t++) { aliases_[t]->collateChanges(changes); }
+}
+
+void Task::set_memento( const OrderMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+#ifdef DEBUG_MEMENTO
+ std::cout << "Task::set_memento( const OrderMemento* ) " << debugNodePath() << "\n";
+#endif
+
+ // Order aliases_ according to memento ordering
+ const std::vector<std::string>& order = memento->order_;
+ if (order.size() != aliases_.size()) {
+ // something gone wrong.
+ std::cout << "Task::set_memento OrderMemento, memento.size() " << order.size() << " Not the same as aliases_size() " << aliases_.size() << "\n";
+ return;
+ }
+
+ std::vector<alias_ptr> vec; vec.reserve(aliases_.size());
+ size_t node_vec_size = aliases_.size();
+ for(size_t i = 0; i < order.size(); i++) {
+ for(size_t t = 0; t < node_vec_size; t++) {
+ if (order[i] == aliases_[t]->name()) {
+ vec.push_back(aliases_[t]);
+ break;
+ }
+ }
+ }
+ if (vec.size() != aliases_.size()) {
+ std::cout << "Task::set_memento(const OrderMemento* memento) could not find all the names\n";
+ return;
+ }
+
+ aspects.push_back(ecf::Aspect::ORDER);
+ aliases_ = vec;
+}
+
+void Task::set_memento( const AliasChildrenMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+#ifdef DEBUG_MEMENTO
+ std::cout << "Task::set_memento( const AliasChildrenMemento* ) " << debugNodePath() << "\n";
+#endif
+
+ aspects.push_back(ecf::Aspect::ADD_REMOVE_NODE);
+ aliases_ = memento->children_;
+
+ // set up alias parent pointers. since they are *NOT* serialised.
+ size_t vec_size = aliases_.size();
+ for(size_t i = 0; i < vec_size; i++) {
+ aliases_[i]->set_parent(this);
+ }
+}
+
+void Task::set_memento( const AliasNumberMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+#ifdef DEBUG_MEMENTO
+ std::cout << "Task::set_memento( const AliasNumberMemento* ) " << debugNodePath() << "\n";
+#endif
+
+ aspects.push_back(ecf::Aspect::ALIAS_NUMBER);
+ alias_no_ = memento->alias_no_;
+}
diff --git a/ANode/src/Task.hpp b/ANode/src/Task.hpp
new file mode 100644
index 0000000..6ccac2f
--- /dev/null
+++ b/ANode/src/Task.hpp
@@ -0,0 +1,172 @@
+#ifndef TASK_HPP_
+#define TASK_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #108 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include "Alias.hpp"
+
+class Task : public Submittable {
+public:
+ Task( const std::string& name )
+ : Submittable(name),
+ order_state_change_no_(0),
+ add_remove_state_change_no_(0),
+ alias_change_no_(0),
+ alias_no_(0)
+ {}
+
+ Task()
+ : order_state_change_no_(0),
+ add_remove_state_change_no_(0),
+ alias_change_no_(0),
+ alias_no_(0)
+ {}
+
+ virtual ~Task();
+
+ static task_ptr create(const std::string& name);
+
+ std::ostream& print(std::ostream&) const;
+ bool operator==(const Task& rhs) const;
+
+ /// Add an alias. The .usr is populated with contents of user_file_contents
+ /// If create_directory is unset we create the alias with creating directory or .usr file
+ alias_ptr add_alias(std::vector<std::string>& user_file_contents,const NameValueVec& user_variables,bool create_directory = true);
+
+ /// Add alias without creating directory & user file
+ alias_ptr add_alias_only();
+
+ /// For Addition of alias via Defs Files
+ alias_ptr add_alias(const std::string& name);
+
+ /// Given a name find the alias.
+ alias_ptr find_alias(const std::string& name) const;
+
+ /// Reset alias number. Used in testing
+ void reset_alias_number();
+
+ /// return list of aliases held by this task
+ const std::vector<alias_ptr>& aliases() { return aliases_; }
+ virtual void immediateChildren(std::vector<node_ptr>&) const;
+
+ /// Overidden from Submittable
+ virtual const std::string& script_extension() const;
+
+ virtual node_ptr find_node_up_the_tree(const std::string& name) const;
+
+ /// Added for consistency, really used to find relative nodes, aliases should never, be in referenced nodes
+ virtual node_ptr find_relative_node(const std::vector<std::string>& pathToNode) { return node_ptr();}
+
+ /// Overridden to reset the try number
+ /// The tasks job can be invoked multiple times. For each invocation we want to preserve
+ /// the output. The try number is used in SMSJOB/SMSJOBOUT to preserve the output when
+ /// there are multiple runs. re-queue/begin() resets the try Number
+ virtual void begin();
+ virtual void requeue( bool resetRepeats,
+ int clear_suspended_in_child_nodes,
+ bool reset_next_time_slot);
+
+ virtual Suite* suite() const { return parent()->suite(); }
+ virtual Defs* defs() const { return (parent()) ? parent()->defs() : NULL;} // exposed to python hence check for NULL first
+ virtual Task* isTask() const { return const_cast<Task*>(this);}
+ virtual Submittable* isSubmittable() const { return const_cast<Task*>(this); }
+
+ virtual void accept(ecf::NodeTreeVisitor&);
+ virtual void acceptVisitTraversor(ecf::NodeTreeVisitor& v);
+
+ virtual void getAllNodes(std::vector<Node*>&) const;
+ virtual void getAllTasks(std::vector<Task*>&) const;
+ virtual void getAllSubmittables(std::vector<Submittable*>&) const;
+ virtual void get_all_active_submittables(std::vector<Submittable*>&) const;
+ virtual void get_all_tasks(std::vector<task_ptr>&) const;
+ virtual void get_all_nodes(std::vector<node_ptr>&) const;
+ virtual void get_all_aliases(std::vector<alias_ptr>&) const;
+
+ virtual const std::string& debugType() const;
+
+ /// submits the jobs of the dependencies resolve
+ virtual bool resolveDependencies(JobsParam& jobsParam);
+
+ virtual node_ptr removeChild( Node* child);
+ virtual bool addChild( node_ptr child,size_t position = std::numeric_limits<std::size_t>::max());
+ virtual bool isAddChildOk( Node* child, std::string& errorMsg) const;
+
+ virtual void order(Node* immediateChild, NOrder::Order);
+ virtual void generate_scripts( const std::map<std::string,std::string>& override) const;
+
+ virtual bool checkInvariants(std::string& errorMsg) const;
+
+ virtual void collateChanges(DefsDelta&) const;
+ void set_memento(const OrderMemento* m,std::vector<ecf::Aspect::Type>& aspects);
+ void set_memento(const AliasChildrenMemento* m,std::vector<ecf::Aspect::Type>& aspects);
+ void set_memento(const AliasNumberMemento* m,std::vector<ecf::Aspect::Type>& aspects);
+ void set_memento(const SubmittableMemento* m,std::vector<ecf::Aspect::Type>& aspects) { Submittable::set_memento(m,aspects); }
+
+ virtual void read_state(const std::string& line,const std::vector<std::string>& lineTokens);
+private:
+ virtual size_t child_position(const Node*) const;
+ virtual std::string write_state() const;
+
+private:
+ /// For use by python interface,
+ std::vector<alias_ptr>::const_iterator alias_begin() const { return aliases_.begin();}
+ std::vector<alias_ptr>::const_iterator alias_end() const { return aliases_.end();}
+ friend void export_Task();
+
+private:
+ // Overridden from Node to increment/decrement limits
+ virtual void handleStateChange();
+ virtual bool doDeleteChild(Node* child);
+
+ // Overridden to locate alias's
+ virtual node_ptr findImmediateChild(const std::string& name, size_t& child_pos) const;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/) {
+ ar & boost::serialization::base_object<Submittable>(*this); // Serialise base class information
+ ar & alias_no_;
+ ar & aliases_;
+
+ // Setup the alias parent pointers. Since they are not serialised
+ // ********************************************************************
+ // WE do not serialise the Alias parent pointer:
+ // WHY: AliasChildrenMenento saves a vector of aliases, had we serialised
+ // the parent, it would also serialise the parent pointer(Task)
+ // i.e the ENTIRE task, and then Task parent, and so on, up the parent hierarchy.
+ // In our case it lead to unregistered class exception when trying to
+ // serialise the Task's parent.
+ // SOLN: WE will not serialise the alias parent pointer. This will be left to
+ // Parent task.
+ // ********************************************************************
+ if (Archive::is_loading::value) {
+ size_t vec_size = aliases_.size();
+ for(size_t i = 0; i < vec_size; i++) {
+ aliases_[i]->set_parent(this);
+ }
+ }
+ }
+
+private:
+ unsigned int order_state_change_no_; // no need to persist
+ unsigned int add_remove_state_change_no_;// no need to persist
+
+ unsigned int alias_change_no_; // no need to persist, for alias number only
+ unsigned int alias_no_;
+ std::vector<alias_ptr> aliases_;
+};
+
+std::ostream& operator<<(std::ostream& os, const Task&);
+
+#endif
diff --git a/ANode/src/TaskScriptGenerator.cpp b/ANode/src/TaskScriptGenerator.cpp
new file mode 100644
index 0000000..0ce852c
--- /dev/null
+++ b/ANode/src/TaskScriptGenerator.cpp
@@ -0,0 +1,263 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #14 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <boost/filesystem.hpp>
+
+#include "TaskScriptGenerator.hpp"
+#include "Task.hpp"
+#include "File.hpp"
+#include "Ecf.hpp"
+#include "Str.hpp"
+
+using namespace std;
+using namespace boost;
+namespace fs = boost::filesystem;
+
+namespace ecf {
+
+TaskScriptGenerator::TaskScriptGenerator(const Task* task)
+: task_(task), is_dummy_task_(false)
+{
+ /// if ECF_DUMMY_TASK specified ignore
+ std::string theValue;
+ is_dummy_task_ = task_->findParentUserVariableValue(Str::ECF_DUMMY_TASK(), theValue);
+ if (is_dummy_task_) return;
+
+ /// if ECF_FILES specified use this before ECF_HOME
+ if (task_->findParentUserVariableValue( Str::ECF_FILES(),ecf_files_)) {
+ // Create any missing directories if ECF_FILES is specified
+ try { fs::create_directories(ecf_files_); }
+ catch ( std::exception& e) {
+ std::stringstream ss;
+ ss << "TaskScriptGenerator: Could not create directories for ECF_FILES " << ecf_files_ << " " << e.what();
+ throw std::runtime_error(ss.str());
+ }
+ }
+
+ /// Find ECF_HOME and ECF_INCLUDE
+ if (!task_->findParentUserVariableValue( Str::ECF_HOME(),ecf_home_)) {
+ std::stringstream ss;
+ ss << "TaskScriptGenerator: Could not generate scripts for task " << task_->absNodePath() << " no ECF_HOME specified\n";
+ throw std::runtime_error(ss.str());
+ }
+ if (!task_->findParentUserVariableValue( Str::ECF_INCLUDE(),ecf_include_)) {
+ std::stringstream ss;
+ ss << "TaskScriptGenerator: Could not generate scripts for task " << task_->absNodePath() << " no ECF_INCLUDE specified\n";
+ throw std::runtime_error(ss.str());
+ }
+
+ // Create any missing directories,
+ try { fs::create_directories(ecf_home_); }
+ catch ( std::exception& e) {
+ std::stringstream ss;
+ ss << "TaskScriptGenerator: Could not create directories for ECF_HOME " << ecf_home_ << " " << e.what();
+ throw std::runtime_error(ss.str());
+ }
+
+ try { fs::create_directories(ecf_include_); }
+ catch ( std::exception& e) {
+ std::stringstream ss;
+ ss << "TaskScriptGenerator: Could not create directories for ECF_INCLUDE " << ecf_include_ << " " << e.what();
+ throw std::runtime_error(ss.str());
+ }
+}
+
+void TaskScriptGenerator::generate(const std::map<std::string,std::string>& override)
+{
+ // Ignore generation for dummy tasks
+ if (is_dummy_task_) return;
+
+ // If ECF_FILES was specified use that in preference to ECF_HOME for the ecf files.
+ std::string root_directory_for_ecf_files;
+ if (!ecf_files_.empty()) root_directory_for_ecf_files = ecf_files_;
+ else root_directory_for_ecf_files = ecf_home_;
+
+ // Note: task_->absNodePath() starts with /.
+ std::string ecf_file_path = root_directory_for_ecf_files + task_->absNodePath() + task_->script_extension();
+ if (fs::exists(ecf_file_path)) {
+ std::cout << "Can not generate. Script file " << ecf_file_path << " already exists\n";
+ return;
+ }
+
+ if (!File::createMissingDirectories(ecf_file_path)) {
+ std::stringstream ss;
+ ss << "TaskScriptGenerator::generate: Could not create missing directories '" << ecf_file_path << "' for task " << task_->absNodePath();
+ throw std::runtime_error(ss.str());
+ }
+
+ // Create file head.h and tail.h in directory ECF_INCLUDE, check to see if they exist first
+ // If the variable ECF_CLIENT_EXE_PATH is specified use it
+ generate_head_file();
+ generate_tail_file();
+
+
+ // Create ECF file with default template or custom file.
+ //cout << "creating ecf file " << ecf_file_path << "\n";
+ std::string contents;
+ std::map<std::string,std::string>::const_iterator it = override.find(task_->absNodePath());
+ if (it == override.end()) {
+ contents = getDefaultTemplateEcfFile();
+ }
+ else {
+ contents = (*it).second;
+ }
+
+ std::string errorMsg;
+ if (!File::create(ecf_file_path,contents,errorMsg)) {
+ std::stringstream ss;
+ ss << "TaskScriptGenerator::generate: Could not create '.ecf' script for task " << task_->absNodePath() << " " << errorMsg;
+ throw std::runtime_error(ss.str());
+ }
+ std::cout << "Generated script file " << ecf_file_path << "\n";
+}
+
+std::string TaskScriptGenerator::getDefaultTemplateEcfFile() const
+{
+ std::string content;
+
+ std::string sleep,var_sleep;
+ if (task_->findParentUserVariableValue("SLEEP",var_sleep)) sleep = "sleep %SLEEP%\n";
+ else sleep = "sleep 1\n";
+
+ std::string client_exe = "%ECF_CLIENT_EXE_PATH:";
+ client_exe += Ecf::CLIENT_NAME();
+ client_exe += "% ";
+
+ content += "%include <head.h>\n";
+ content += "%manual\n";
+ content += "This is the default **generated** ecf script file\n";
+ content += "If the task has events, meters or labels then the associated client\n";
+ content += "to server commands are automatically generated.\n";
+ content += "Will default to sleep for one second in between calls to the events, meters & labels,\n";
+ content += "this can be overridden by adding a variable SLEEP\n";
+ content += "%end\n";
+ content += "\n";
+ content += "%comment\n";
+ content += "#============================================================\n";
+ content += "# Using angle brackets means we look in directory ECF_INCLUDE\n";
+ content += "# and then ECF_HOME\n";
+ content += "#============================================================\n";
+ content += "%end\n";
+ content += "\n";
+ content += "echo do some work\n";
+ BOOST_FOREACH(const Event& e, task_->events()) {
+ content += client_exe + "--event=" + e.name_or_number() + "\n";
+ content += sleep;
+ }
+
+ content += "\n";
+ BOOST_FOREACH(const Meter& m, task_->meters()) {
+ content += "for i in";
+ for(int i = m.min(); i <= m.max(); i = i + 1) {
+ content += " ";
+ content += boost::lexical_cast<std::string>(i);
+ }
+ content += "\n";
+ content += "do\n";
+ content += " " + client_exe + "--meter=" + m.name() + " $i\n";
+ content += " " + sleep;
+ content += "done\n";
+ }
+ content += "\n";
+
+ /// labels require at least 2 arguments,
+ BOOST_FOREACH(const Label& label, task_->labels()) {
+
+ if (!label.new_value().empty()) {
+ content += client_exe + "--label=" + label.name() + " " + label.new_value() + "\n";
+ }
+ else if (!label.value().empty()) {
+ content += client_exe + "--label=" + label.name() + " " + label.value() + "\n";
+ }
+ content += sleep;
+ }
+
+ content += "\n";
+ if (task_->events().empty() && task_->meters().empty()) {
+ content += sleep;
+ }
+ content += "\necho end of job\n";
+ content += "\n%include <tail.h>\n";
+ return content;
+}
+
+void TaskScriptGenerator::generate_head_file() const
+{
+ std::string path = ecf_include_ + "/head.h";
+ if (fs::exists(path)) return;
+
+ std::string client_exe = "%ECF_CLIENT_EXE_PATH:";
+ client_exe += Ecf::CLIENT_NAME();
+ client_exe += "% ";
+
+ std::string contents;
+ contents += "#!/bin/ksh\n";
+ contents += "set -e # stop the shell on first error\n";
+ contents += "set -u # fail when using an undefined variable\n";
+ contents += "set -x # echo script lines as they are executed\n";
+ contents += "\n";
+ contents += "# Defines the variables that are needed for any communication with ECF\n";
+ contents += "export ECF_PORT=%ECF_PORT% # The server port number\n";
+ contents += "export ECF_NODE=%ECF_NODE% # The name of ecf host that issued this task\n";
+ contents += "export ECF_NAME=%ECF_NAME% # The name of this current task\n";
+ contents += "export ECF_PASS=%ECF_PASS% # A unique password\n";
+ contents += "export ECF_TRYNO=%ECF_TRYNO% # Current try number of the task\n";
+ contents += "export ECF_RID=$$\n";
+ contents += "\n";
+ contents += "# Tell ecFlow we have started\n";
+ contents += client_exe + "--init=$$\n";
+ contents += "\n";
+ contents += "# Defined a error handler\n";
+ contents += "ERROR() {\n";
+ contents += " set +e # Clear -e flag, so we don't fail\n";
+ contents += " " + client_exe + "--abort=trap # Notify ecFlow that something went wrong, using 'trap' as the reason\n";
+ contents += " trap 0 # Remove the trap\n";
+ contents += " exit 0 # End the script\n";
+ contents += "}\n";
+ contents += "\n";
+ contents += "# Trap any calls to exit and errors caught by the -e flag\n";
+ contents += "trap ERROR 0\n";
+ contents += "\n";
+ contents += "# Trap any signal that may cause the script to fail\n";
+ contents += "trap '{ echo \"Killed by a signal\"; ERROR ; }' 1 2 3 4 5 6 7 8 10 12 13 15\n";
+
+ std::string errorMsg;
+ if (!File::create(path,contents,errorMsg)) {
+ std::stringstream ss;
+ ss << "TaskScriptGenerator::generate_tail_file: Could not create head.h " << path << " " << errorMsg;
+ throw std::runtime_error(ss.str());
+ }
+}
+
+void TaskScriptGenerator::generate_tail_file() const
+{
+ std::string path = ecf_include_ + "/tail.h";
+ if (fs::exists(path)) return;
+
+ std::string contents = "%ECF_CLIENT_EXE_PATH:";
+ contents += Ecf::CLIENT_NAME();
+ contents +="% --complete # Notify ecFlow of a normal end\n";
+
+ contents += "trap 0 # Remove all traps\n";
+ contents += "exit 0 # End the shell\n";
+
+ std::string errorMsg;
+ if (!File::create(path,contents,errorMsg)) {
+ std::stringstream ss;
+ ss << "TaskScriptGenerator::generate_tail_file: Could not create tail.h " << path << " " << errorMsg;
+ throw std::runtime_error(ss.str());
+ }
+}
+}
diff --git a/ANode/src/TaskScriptGenerator.hpp b/ANode/src/TaskScriptGenerator.hpp
new file mode 100644
index 0000000..abc57dc
--- /dev/null
+++ b/ANode/src/TaskScriptGenerator.hpp
@@ -0,0 +1,46 @@
+#ifndef TASKSCRIPTGENERATOR_HPP_
+#define TASKSCRIPTGENERATOR_HPP_
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <string>
+#include <map>
+#include <boost/noncopyable.hpp>
+class Task;
+
+namespace ecf {
+
+class TaskScriptGenerator : private boost::noncopyable {
+public:
+ TaskScriptGenerator(const Task*);
+
+ void generate(const std::map<std::string,std::string>& override);
+
+private:
+ void generate_head_file() const;
+ void generate_tail_file() const;
+ std::string getDefaultTemplateEcfFile() const;
+
+private:
+ const Task* task_;
+ bool is_dummy_task_;
+ std::string ecf_files_;
+ std::string ecf_home_;
+ std::string ecf_include_;
+};
+
+}
+#endif
diff --git a/ANode/src/TimeDepAttrs.cpp b/ANode/src/TimeDepAttrs.cpp
new file mode 100644
index 0000000..632bcdb
--- /dev/null
+++ b/ANode/src/TimeDepAttrs.cpp
@@ -0,0 +1,872 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #281 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <assert.h>
+#include <boost/foreach.hpp>
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+
+#include "TimeDepAttrs.hpp"
+#include "Str.hpp"
+#include "Log.hpp"
+#include "Ecf.hpp"
+#include "Memento.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+void TimeDepAttrs::begin()
+{
+ // Let time base attributes use, relative duration if applicable
+ // reset requires calendar, to update next time slot, which is used in why command
+ const Calendar& calendar = node_->suite()->calendar();
+ for(size_t i = 0; i < todayVec_.size(); i++) { todayVec_[i].reset(calendar);}
+ for(size_t i = 0; i < timeVec_.size(); i++) { timeVec_[i].reset(calendar);}
+ for(size_t i = 0; i < crons_.size(); i++) { crons_[i].reset(calendar);}
+
+ for(size_t i = 0; i < days_.size(); i++) { days_[i].clearFree(); }
+ for(size_t i = 0; i < dates_.size(); i++) { dates_[i].clearFree(); }
+}
+
+void TimeDepAttrs::requeue(bool reset_next_time_slot) {
+
+ /// If a job takes longer than it slots, then that slot is missed, and next slot is used
+ /// Note we do *NOT* reset for requeue as we want to advance to the next time slot
+ /// *NOTE* Update calendar will *free* time dependencies *even* time series. They rely
+ /// on this function to clear the time dependencies so they *HOLD* the task.
+ const Calendar& calendar = node_->suite()->calendar();
+ for(size_t i = 0; i < todayVec_.size(); i++) { todayVec_[i].requeue(calendar,reset_next_time_slot);}
+ for(size_t i = 0; i < timeVec_.size(); i++) { timeVec_[i].requeue(calendar,reset_next_time_slot);}
+ for(size_t i = 0; i < crons_.size(); i++) { crons_[i].requeue(calendar,reset_next_time_slot);}
+
+ for(size_t i = 0; i < days_.size(); i++) { days_[i].clearFree(); }
+ for(size_t i = 0; i < dates_.size(); i++) { dates_[i].clearFree(); }
+}
+
+void TimeDepAttrs::calendarChanged(const ecf::Calendar& c )
+{
+ // For time/today/cron attributes if the time is free, it *remains* free until re-queued
+ // However if we have day/date dependencies, that do NOT match, then we should *NOT* free
+ // any time/today/cron attributes.
+ //
+ // task t
+ // day Monday
+ // time 10:00
+ //
+ // Hence if we are on Sunday we do *NOT* want to free the time on SUNDAY
+ // (Otherwise we will end up running the task at Monday Midnight
+ // and not Monday at 10.00)
+ //
+ bool have_day = false;
+ bool at_least_one_day_free = false;
+ for(size_t i = 0; i < days_.size(); i++){
+ have_day = true;
+ days_[i].calendarChanged(c);
+ if (!at_least_one_day_free) at_least_one_day_free = days_[i].isFree(c);
+ }
+
+ bool have_date = false;
+ bool at_least_one_date_free = false;
+ for(size_t i = 0; i < dates_.size(); i++) {
+ have_date = true;
+ dates_[i].calendarChanged(c);
+ if (!at_least_one_date_free) at_least_one_date_free = dates_[i].isFree(c);
+ }
+
+ if (have_day || have_date ) {
+ if ( at_least_one_day_free || at_least_one_date_free) {
+ for(size_t i = 0; i < crons_.size(); i++) { crons_[i].calendarChanged(c); }
+ for(size_t i = 0; i < todayVec_.size(); i++) { todayVec_[i].calendarChanged(c); }
+ for(size_t i = 0; i < timeVec_.size(); i++) { timeVec_[i].calendarChanged(c); }
+ }
+ }
+ else {
+ // No Day or Date, If time matches calendarChanged(c) will free time dependencies
+ for(size_t i = 0; i < crons_.size(); i++) { crons_[i].calendarChanged(c); }
+ for(size_t i = 0; i < todayVec_.size(); i++) { todayVec_[i].calendarChanged(c); }
+ for(size_t i = 0; i < timeVec_.size(); i++) { timeVec_[i].calendarChanged(c); }
+ }
+}
+
+void TimeDepAttrs::markHybridTimeDependentsAsComplete()
+{
+ // If hybrid clock and then we may have day/date/cron time dependencies
+ // which mean that node will be stuck in the QUEUED state, i.e since the
+ // date/day does not change with the hybrid clock.
+ // hence Mark these Nodes as complete
+ const Calendar& calendar = node_->suite()->calendar();
+ if (node_->state() != NState::COMPLETE && calendar.hybrid()) {
+ if ( !dates_.empty() || !days_.empty() || !crons_.empty()) {
+
+ int noOfTimeDependencies = 0;
+ if (!dates_.empty()) noOfTimeDependencies++;
+ if (!days_.empty()) noOfTimeDependencies++;
+ if (!crons_.empty()) noOfTimeDependencies++;
+
+ bool oneDateIsFree = false;
+ bool oneDayIsFree = false;
+ bool oneCronIsFree = false;
+
+ for(size_t i=0;i<dates_.size();i++) { if (dates_[i].validForHybrid(calendar)) { if (noOfTimeDependencies == 1) { node_->setStateOnly(NState::QUEUED); return;}oneDateIsFree = true;break;}}
+ for(size_t i=0;i<days_.size();i++) { if (days_[i].validForHybrid(calendar)) { if (noOfTimeDependencies == 1) { node_->setStateOnly(NState::QUEUED); return;}oneDayIsFree = true;break;}}
+ for(size_t i=0;i<crons_.size();i++) { if (crons_[i].validForHybrid(calendar)) { if (noOfTimeDependencies == 1) { node_->setStateOnly(NState::QUEUED); return;}oneCronIsFree = true;break;}}
+
+ if ( oneDateIsFree || oneDayIsFree || oneCronIsFree) {
+ if ( noOfTimeDependencies > 1 ) {
+ // when we have multiple time dependencies they results *MUST* be anded for the node to be free.
+ if (!dates_.empty() && !oneDateIsFree) { node_->setStateOnly(NState::COMPLETE); return;}
+ if (!days_.empty() && !oneDayIsFree) { node_->setStateOnly(NState::COMPLETE); return;}
+ if (!crons_.empty() && !oneCronIsFree) { node_->setStateOnly(NState::COMPLETE); return;}
+
+ // We will only get here, if we have a multiple time dependencies any there is one free in each category
+ node_->setStateOnly(NState::QUEUED);
+ return;
+ }
+ }
+
+ node_->setStateOnly(NState::COMPLETE);
+ }
+ }
+}
+
+void TimeDepAttrs::resetRelativeDuration()
+{
+ for(size_t i = 0; i < crons_.size(); i++) { crons_[i].resetRelativeDuration(); }
+ for(size_t i = 0; i < todayVec_.size(); i++) { todayVec_[i].resetRelativeDuration();}
+ for(size_t i = 0; i < timeVec_.size(); i++) { timeVec_[i].resetRelativeDuration(); }
+}
+
+// #define DEBUG_REQUEUE 1
+bool TimeDepAttrs::testTimeDependenciesForRequeue() const
+{
+ // Check for re-queue required for all time related attributes
+ const Calendar& calendar = node_->suite()->calendar();
+
+#ifdef DEBUG_REQUEUE
+ LogToCout logtocout;
+ LOG(Log::DBG,"TimeDepAttrs::testTimeDependenciesForRequeue() " << node_->debugNodePath() << " calendar " << calendar.toString());
+#endif
+
+
+ // When we have a mixture of cron *with* other time based attributes
+ // The cron *takes* priority. Crons should always return true, for checkForRequeue
+ BOOST_FOREACH(const CronAttr& cron, crons_ ) {
+ if (cron.checkForRequeue(calendar)) { // will always return true
+#ifdef DEBUG_REQUEUE
+ LOG(Log::DBG," TimeDepAttrs::testTimeDependenciesForRequeue() " << node_->debugNodePath() << " for cron");
+#endif
+ return true;
+ }
+ }
+
+
+ if (!timeVec_.empty()) {
+ TimeSlot the_min,the_max; // Needs to handle multiple single slot time attributes
+ BOOST_FOREACH(const ecf::TimeAttr& time, timeVec_) { time.min_max_time_slots(the_min,the_max);}
+ BOOST_FOREACH(const ecf::TimeAttr& time, timeVec_) {
+ if (time.checkForRequeue(calendar,the_min,the_max)) {
+#ifdef DEBUG_REQUEUE
+ LOG(Log::DBG," TimeDepAttrs::testTimeDependenciesForRequeue() " << node_->debugNodePath() << " for time " << time.toString());
+#endif
+ return true;
+ }
+ }
+ }
+
+
+ if (!todayVec_.empty()) {
+ TimeSlot the_min,the_max; // Needs to handle multiple single slot today attributes
+ BOOST_FOREACH(const ecf::TodayAttr& today,todayVec_) { today.min_max_time_slots(the_min,the_max);}
+ BOOST_FOREACH(const ecf::TodayAttr& today,todayVec_) {
+ if (today.checkForRequeue(calendar,the_min,the_max)) {
+#ifdef DEBUG_REQUEUE
+ LOG(Log::DBG," TimeDepAttrs::testTimeDependenciesForRequeue() " << node_->debugNodePath() << " for today " << today.toString());
+#endif
+ return true;;
+ }
+ }
+ }
+
+
+ // **********************************************************************
+ // If we get here there are **NO** time/today/cron dependencies which are free
+ // We now need to determine if this node has a future time dependency which
+ // should re-queue this node
+ // *********************************************************************
+ BOOST_FOREACH(const DateAttr& date, dates_ ) {
+ if (date.checkForRequeue(calendar)) {
+#ifdef DEBUG_REQUEUE
+ LOG(Log::DBG," TimeDepAttrs::testTimeDependenciesForRequeue() " << node_->debugNodePath() << " for date " << date.toString());
+#endif
+ return true;
+ }
+ }
+
+ BOOST_FOREACH(const DayAttr& day, days_ ) {
+ if (day.checkForRequeue(calendar)) {
+#ifdef DEBUG_REQUEUE
+ LOG(Log::DBG," TimeDepAttrs::testTimeDependenciesForRequeue() " << node_->debugNodePath() << " for day " << day.toString());
+#endif
+ return true;
+ }
+ }
+
+#ifdef DEBUG_REQUEUE
+ LOG(Log::DBG," TimeDepAttrs::testTimeDependenciesForRequeue() " << node_->debugNodePath() << " HOLDING ");
+#endif
+ return false;
+}
+
+
+void TimeDepAttrs::miss_next_time_slot()
+{
+ // Note: when we have multiple time dependencies.
+ // We need find valid next time dependency:
+ // time 10:00
+ // time 11:00
+ // time 12:00 14:00 00:30
+ // Also we could have a mix:
+ // time 10:00
+ // today 10:30
+ // time 11:00
+ // time 12:00 14:00 00:30
+
+ // for the moment assume, they have been added sequentially,
+ // hence only first non expired time is updated to miss next time slot
+ for(size_t i=0;i<timeVec_.size();i++) {
+ if (timeVec_[i].time_series().is_valid()) {
+ timeVec_[i].miss_next_time_slot();
+ break;
+ }
+ }
+ for(size_t i=0;i<todayVec_.size();i++){
+ if (todayVec_[i].time_series().is_valid()) {
+ todayVec_[i].miss_next_time_slot();
+ break;
+ }
+ }
+ for(size_t i=0;i<crons_.size();i++) {
+ if (crons_[i].time_series().is_valid()) {
+ crons_[i].miss_next_time_slot();
+ break;
+ }
+ }
+}
+
+
+void TimeDepAttrs::freeHoldingDateDependencies()
+{
+ // Multiple time dependencies of the same type are *ORed*
+ // Multiple time dependencies of different types are *ANDed*
+ //
+ // Hence since we have multiple time dependencies of the same
+ // type here, we need free only one of them
+ const Calendar& calendar = node_->suite()->calendar();
+ for(size_t i=0;i<dates_.size();i++) {
+ if (!dates_[i].isFree(calendar)) {
+ dates_[i].setFree();
+ break;
+ }
+ }
+}
+
+void TimeDepAttrs::freeHoldingTimeDependencies()
+{
+ // Multiple time dependencies of the same type are *ORed*
+ // Multiple time dependencies of different types are *ANDed*
+ //
+ // If we have multiple time dependencies of different types
+ // we need only free one in each category
+ const Calendar& calendar = node_->suite()->calendar();
+ for(size_t i=0;i<timeVec_.size();i++) {
+ if (!timeVec_[i].isFree(calendar)) {
+ timeVec_[i].setFree();
+ timeVec_[i].miss_next_time_slot();
+ break;
+ }
+ }
+ for(size_t i=0;i<todayVec_.size();i++) {
+ if (!todayVec_[i].isFree(calendar)) {
+ todayVec_[i].setFree();
+ todayVec_[i].miss_next_time_slot();
+ break;
+ }
+ }
+ for(size_t i=0;i<days_.size();i++) {
+ if (!days_[i].isFree(calendar)) {
+ days_[i].setFree();
+ break;
+ }
+ }
+ for(size_t i=0;i<crons_.size();i++) {
+ if (!crons_[i].isFree(calendar)) {
+ crons_[i].setFree();
+ crons_[i].miss_next_time_slot();
+ break;
+ }
+ }
+}
+
+
+bool TimeDepAttrs::timeDependenciesFree() const
+{
+ if (!timeVec_.empty() || !todayVec_.empty() || !dates_.empty() || !days_.empty() || !crons_.empty()) {
+
+ int noOfTimeDependencies = 0;
+ if (!timeVec_.empty()) noOfTimeDependencies++;
+ if (!todayVec_.empty()) noOfTimeDependencies++;
+ if (!dates_.empty()) noOfTimeDependencies++;
+ if (!days_.empty()) noOfTimeDependencies++;
+ if (!crons_.empty()) noOfTimeDependencies++;
+
+ bool oneDateIsFree = false;
+ bool oneDayIsFree = false;
+ bool oneTodayIsFree = false;
+ bool oneTimeIsFree = false;
+ bool oneCronIsFree = false;
+
+ const Calendar& calendar = node_->suite()->calendar();
+ for(size_t i=0;i<timeVec_.size();i++) { if (timeVec_[i].isFree(calendar)) {if ( noOfTimeDependencies == 1) return true;oneTimeIsFree = true;break;}}
+ for(size_t i=0;i<crons_.size();i++) { if (crons_[i].isFree(calendar)) {if ( noOfTimeDependencies == 1) return true;oneCronIsFree = true;break;}}
+ for(size_t i=0;i<dates_.size();i++) { if (dates_[i].isFree(calendar)) {if ( noOfTimeDependencies == 1) return true;oneDateIsFree = true;break;}}
+ for(size_t i=0;i<days_.size();i++) { if (days_[i].isFree(calendar)) {if ( noOfTimeDependencies == 1) return true;oneDayIsFree = true;break;}}
+
+ if (!todayVec_.empty()) {
+ // : single Today: (single-time) is free, if calendar time >= today_time
+ // : single Today: (range) is free, if calendar time == (one of the time ranges)
+ // : multi Today : (single | range)is free, if calendar time == (one of the time ranges | tody_time)
+ if (todayVec_.size() == 1 ) {
+ // Single Today Attribute: could be single slot or range
+ if (todayVec_[0].isFree(calendar)) { if ( noOfTimeDependencies == 1) return true;oneTodayIsFree = true;}
+ }
+ else {
+ // Multiple Today Attributes, each could single, or range
+ for(size_t i=0;i<todayVec_.size();i++) {
+ if (todayVec_[i].isFreeMultipleContext(calendar)) {if ( noOfTimeDependencies == 1) return true;oneTodayIsFree = true;break;}
+ }
+ }
+ }
+
+
+ if ( oneDateIsFree || oneDayIsFree || oneTodayIsFree || oneTimeIsFree || oneCronIsFree) {
+ if ( noOfTimeDependencies > 1 ) {
+ // *When* we have multiple time dependencies of *different types* then the results
+ // *MUST* be anded for the node to be free.
+ if (!dates_.empty() && !oneDateIsFree) return false;
+ if (!days_.empty() && !oneDayIsFree) return false;
+ if (!todayVec_.empty() && !oneTodayIsFree) return false;
+ if (!timeVec_.empty() && !oneTimeIsFree) return false;
+ if (!crons_.empty() && !oneCronIsFree) return false;
+
+ // We will only get here, if we have a multiple time dependencies and they are free
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool TimeDepAttrs::time_today_cron_is_free() const
+{
+ if (!timeVec_.empty() || !todayVec_.empty() || !crons_.empty()) {
+
+ int noOfTimeDependencies = 0;
+ if (!timeVec_.empty()) noOfTimeDependencies++;
+ if (!todayVec_.empty()) noOfTimeDependencies++;
+ if (!crons_.empty()) noOfTimeDependencies++;
+
+ bool oneTodayIsFree = false;
+ bool oneTimeIsFree = false;
+ bool oneCronIsFree = false;
+
+ const Calendar& calendar = node_->suite()->calendar();
+ for(size_t i=0;i<timeVec_.size();i++) { if (timeVec_[i].isFree(calendar)) {if ( noOfTimeDependencies == 1) return true;oneTimeIsFree = true;break;}}
+ for(size_t i=0;i<crons_.size();i++) { if (crons_[i].isFree(calendar)) {if ( noOfTimeDependencies == 1) return true;oneCronIsFree = true;break;}}
+
+ if (!todayVec_.empty()) {
+ // : single Today: (single-time) is free, if calendar time >= today_time
+ // : single Today: (range) is free, if calendar time == (one of the time ranges)
+ // : multi Today : (single | range)is free, if calendar time == (one of the time ranges | tody_time)
+ if (todayVec_.size() == 1 ) {
+ // Single Today Attribute: could be single slot or range
+ if (todayVec_[0].isFree(calendar)) { if ( noOfTimeDependencies == 1) return true;oneTodayIsFree = true;}
+ }
+ else {
+ // Multiple Today Attributes, each could single, or range
+ for(size_t i=0;i<todayVec_.size();i++) {
+ if (todayVec_[i].isFreeMultipleContext(calendar)) {if ( noOfTimeDependencies == 1) return true;oneTodayIsFree = true;break;}
+ }
+ }
+ }
+
+
+ if ( oneTodayIsFree || oneTimeIsFree || oneCronIsFree) {
+ if ( noOfTimeDependencies > 1 ) {
+ // *When* we have multiple time dependencies of *different types* then the results
+ // *MUST* be anded for the node to be free.
+ if (!todayVec_.empty() && !oneTodayIsFree) return false;
+ if (!timeVec_.empty() && !oneTimeIsFree) return false;
+ if (!crons_.empty() && !oneCronIsFree) return false;
+
+ // We will only get here, if we have a multiple time dependencies and they are free
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+std::ostream& TimeDepAttrs::print(std::ostream& os) const
+{
+ BOOST_FOREACH(const ecf::TimeAttr& t, timeVec_) { t.print(os); }
+ BOOST_FOREACH(const ecf::TodayAttr& t,todayVec_) { t.print(os); }
+ BOOST_FOREACH(const DateAttr& date, dates_) { date.print(os); }
+ BOOST_FOREACH(const DayAttr& day, days_) { day.print(os); }
+ BOOST_FOREACH(const CronAttr& cron, crons_) { cron.print(os); }
+ return os;
+}
+
+bool TimeDepAttrs::operator==(const TimeDepAttrs& rhs) const
+{
+ if (timeVec_.size() != rhs.timeVec_.size()) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "TimeDepAttrs::operator== (timeVec_.size() != rhs.timeVec_.size()) " << node_->debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ for(unsigned i = 0; i < timeVec_.size(); ++i) {
+ if (!(timeVec_[i] == rhs.timeVec_[i] )) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "TimeDepAttrs::operator== (!(timeVec_[i] == rhs.timeVec_[i] )) " << node_->debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ }
+
+ if (todayVec_.size() != rhs.todayVec_.size()) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "TimeDepAttrs::operator== (todayVec_.size() != rhs.todayVec_.size()) " << node_->debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ for(unsigned i = 0; i < todayVec_.size(); ++i) {
+ if (!(todayVec_[i] == rhs.todayVec_[i] )) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "TimeDepAttrs::operator== (!(todayVec_[i] == rhs.todayVec_[i] )) " << node_->debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ }
+
+ if (dates_.size() != rhs.dates_.size()) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "TimeDepAttrs::operator== (dates_.size() != rhs.dates_.size()) " << node_->debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ for(unsigned i = 0; i < dates_.size(); ++i) {
+ if (!(dates_[i] == rhs.dates_[i]) ) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "TimeDepAttrs::operator== (!(dates_[i] == rhs.dates_[i]) " << node_->debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ }
+
+ if (days_.size() != rhs.days_.size()) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "TimeDepAttrs::operator== (days_.size() != rhs.days_.size()) " << node_->debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ for(unsigned i = 0; i < days_.size(); ++i) {
+ if (!(days_[i] == rhs.days_[i]) ) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "TimeDepAttrs::operator== (!(days_[i] == rhs.days_[i]) " << node_->debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ }
+
+ if (crons_.size() != rhs.crons_.size()) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "TimeDepAttrs::operator== (crons_.size() != rhs.crons_.size()) " << node_->debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ for(unsigned i = 0; i < crons_.size(); ++i) {
+ if (!(crons_[i] == rhs.crons_[i]) ) {
+#ifdef DEBUG
+ if (Ecf::debug_equality()) {
+ std::cout << "TimeDepAttrs::operator== (!(crons_[i] == rhs.crons_[i]) " << node_->debugNodePath() << "\n";
+ }
+#endif
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+//#define DEBUG_WHY 1
+void TimeDepAttrs::why(std::vector<std::string>& vec,const std::string& prefix) const
+{
+#ifdef DEBUG_WHY
+ std::cout << " TimeDepAttrs::why " << node_->debugNodePath() << " checking time dependencies\n";
+#endif
+ // postfix = <attr-type dependent> <next run time > < optional current state>
+ std::string postFix;
+ const Calendar& c = node_->suite()->calendar();
+ for(size_t i = 0; i < days_.size(); i++) { postFix.clear(); if (days_[i].why(c,postFix)) { vec.push_back(prefix + postFix); }}
+ for(size_t i = 0; i < dates_.size(); i++) { postFix.clear(); if (dates_[i].why(c,postFix)) { vec.push_back(prefix + postFix); }}
+ for(size_t i = 0; i < todayVec_.size(); i++){ postFix.clear(); if (todayVec_[i].why(c,postFix)){ vec.push_back(prefix + postFix); }}
+ for(size_t i = 0; i < timeVec_.size(); i++) { postFix.clear(); if (timeVec_[i].why(c,postFix)) { vec.push_back(prefix + postFix); }}
+ for(size_t i = 0; i < crons_.size(); i++) { postFix.clear(); if (crons_[i].why(c,postFix)) { vec.push_back(prefix + postFix); }}
+
+}
+
+bool TimeDepAttrs::checkInvariants(std::string& errorMsg) const
+{
+ if (node_ == NULL) {
+ errorMsg +="TimeDepAttrs::checkInvariants node_ not set";
+ return false;
+ }
+ BOOST_FOREACH(const ecf::TimeAttr& t, timeVec_) { if (!t.checkInvariants(errorMsg)) return false; }
+ BOOST_FOREACH(const ecf::TodayAttr& t,todayVec_) { if (!t.checkInvariants(errorMsg)) return false; }
+ BOOST_FOREACH(const CronAttr& cron, crons_ ) { if (!cron.checkInvariants(errorMsg)) return false; }
+ return true;
+}
+
+
+void TimeDepAttrs::clear()
+{
+ timeVec_.clear();
+ todayVec_.clear();
+ dates_.clear();
+ days_.clear();
+ crons_.clear();
+}
+
+
+void TimeDepAttrs::addTime(const ecf::TimeAttr& t)
+{
+ timeVec_.push_back(t);
+ node_->state_change_no_ = Ecf::incr_state_change_no();
+}
+
+void TimeDepAttrs::addToday(const ecf::TodayAttr& t)
+{
+ todayVec_.push_back(t);
+ node_->state_change_no_ = Ecf::incr_state_change_no();
+}
+
+void TimeDepAttrs::addDate( const DateAttr& d)
+{
+ dates_.push_back( d );
+ node_->state_change_no_ = Ecf::incr_state_change_no();
+}
+
+void TimeDepAttrs::addDay( const DayAttr& d)
+{
+ days_.push_back( d );
+ node_->state_change_no_ = Ecf::incr_state_change_no();
+}
+
+void TimeDepAttrs::addCron( const CronAttr& d)
+{
+ if (d.time().isNULL()) {
+ throw std::runtime_error("TimeDepAttrs::addCron: The cron is in-complete, no time specified");
+ }
+ if (d.time().hasIncrement() && !node_->repeat_.empty()) {
+ std::stringstream ss;
+ ss << "TimeDepAttrs::addCron: Node " << node_->absNodePath() << " already has a repeat. Inappropriate to add two looping structures at the same level\n";
+ throw std::runtime_error(ss.str());
+ }
+ crons_.push_back( d );
+ node_->state_change_no_ = Ecf::incr_state_change_no();
+}
+
+
+void TimeDepAttrs::deleteTime(const std::string& name )
+{
+ if (name.empty()) {
+ timeVec_.clear(); // delete all
+ node_->state_change_no_ = Ecf::incr_state_change_no();
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "TimeDepAttrs::deleteTime\n";
+#endif
+ return;
+ }
+ TimeAttr attr( TimeSeries::create(name) ); // can throw if parse fails
+ delete_time(attr); // can throw if search fails
+}
+void TimeDepAttrs::delete_time( const ecf::TimeAttr& attr )
+{
+ size_t theSize = timeVec_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ // Dont use '==' since that compares additional state like makeFree_
+ if (timeVec_[i].structureEquals(attr)) {
+ timeVec_.erase( timeVec_.begin() + i );
+ node_->state_change_no_ = Ecf::incr_state_change_no();
+
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "TimeDepAttrs::delete_time\n";
+#endif
+ return;
+ }
+ }
+ throw std::runtime_error("TimeDepAttrs::delete_time: Can not find time attribute: ");
+}
+
+
+void TimeDepAttrs::deleteToday(const std::string& name)
+{
+ if (name.empty()) {
+ todayVec_.clear();
+ node_->state_change_no_ = Ecf::incr_state_change_no();
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "TimeDepAttrs::deleteToday\n";
+#endif
+ return;
+ }
+
+ TodayAttr attr( TimeSeries::create(name) ); // can throw if parse fails
+ delete_today(attr); // can throw if search fails
+}
+void TimeDepAttrs::delete_today(const ecf::TodayAttr& attr)
+{
+ size_t theSize = todayVec_.size();
+ for(size_t i = 0; i < theSize; i++) {
+ // Dont use '==' since that compares additional state like makeFree_
+ if (todayVec_[i].structureEquals(attr)) {
+ todayVec_.erase( todayVec_.begin() + i );
+ node_->state_change_no_ = Ecf::incr_state_change_no();
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "TimeDepAttrs::delete_today\n";
+#endif
+ return;
+ }
+ }
+ throw std::runtime_error("TimeDepAttrs::delete_today: Can not find today attribute: " + attr.toString());
+}
+
+void TimeDepAttrs::deleteDate(const std::string& name)
+{
+ if (name.empty()) {
+ dates_.clear();
+ node_->state_change_no_ = Ecf::incr_state_change_no();
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "TimeDepAttrs::deleteDate\n";
+#endif
+ return;
+ }
+
+ DateAttr attr( DateAttr::create(name) ); // can throw if parse fails
+ delete_date(attr); // can throw if search fails
+}
+void TimeDepAttrs::delete_date(const DateAttr& attr)
+{
+ for(size_t i = 0; i < dates_.size(); i++) {
+ // Dont use '==' since that compares additional state like makeFree_
+ if (attr.structureEquals(dates_[i]) ) {
+ dates_.erase( dates_.begin() + i );
+ node_->state_change_no_ = Ecf::incr_state_change_no();
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "TimeDepAttrs::delete_date\n";
+#endif
+ return;
+ }
+ }
+ throw std::runtime_error("TimeDepAttrs::delete_date: Can not find date attribute: " + attr.toString());
+}
+
+
+void TimeDepAttrs::deleteDay(const std::string& name)
+{
+ if (name.empty()) {
+ days_.clear();
+ node_->state_change_no_ = Ecf::incr_state_change_no();
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "TimeDepAttrs::deleteDay\n";
+#endif
+ return;
+ }
+
+ DayAttr attr( DayAttr::create(name) ); // can throw if parse fails.
+ delete_day(attr); // can throw if search fails
+}
+void TimeDepAttrs::delete_day(const DayAttr& attr)
+{
+ for(size_t i = 0; i < days_.size(); i++) {
+ // Dont use '==' since that compares additional state like makeFree_
+ if (attr.structureEquals(days_[i]) ) {
+ days_.erase( days_.begin() + i );
+ node_->state_change_no_ = Ecf::incr_state_change_no();
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "TimeDepAttrs::delete_day\n";
+#endif
+ return;
+ }
+ }
+ throw std::runtime_error("TimeDepAttrs::delete_day: Can not find day attribute: " + attr.toString());
+}
+
+void TimeDepAttrs::deleteCron(const std::string& name)
+{
+ if (name.empty()) {
+ crons_.clear();
+ node_->state_change_no_ = Ecf::incr_state_change_no();
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "TimeDepAttrs::deleteCron\n";
+#endif
+ return;
+ }
+
+ CronAttr attr = CronAttr::create(name); // can throw if parse fails
+ delete_cron(attr); // can throw if search fails
+}
+
+void TimeDepAttrs::delete_cron(const ecf::CronAttr& attr)
+{
+ for(size_t i = 0; i < crons_.size(); i++) {
+ // Dont use '==' since that compares additional state like makeFree_
+ if (attr.structureEquals(crons_[i]) ) {
+ crons_.erase( crons_.begin() + i );
+ node_->state_change_no_ = Ecf::incr_state_change_no();
+#ifdef DEBUG_STATE_CHANGE_NO
+ std::cout << "TimeDepAttrs::deleteCron\n";
+#endif
+ return ;
+ }
+ }
+ throw std::runtime_error("TimeDepAttrs::delete_cron: Can not find cron attribute: " + attr.toString());
+}
+
+// =================================================================================
+
+
+bool TimeDepAttrs::set_memento( const NodeTodayMemento* memento ,std::vector<ecf::Aspect::Type>& aspects) {
+
+#ifdef DEBUG_MEMENTO
+ std::cout << "TimeDepAttrs::set_memento(const NodeTodayMemento* memento) " << node_->debugNodePath() << "\n";
+#endif
+
+ for(size_t i = 0; i < todayVec_.size(); ++i) {
+ // We need to ignore state changes in TodayAttr, (ie we don't use equality operator)
+ // otherwise today will never compare
+ if ( todayVec_[i].structureEquals(memento->attr_) ) {
+ todayVec_[i] = memento->attr_; // need to copy over time series state
+ return true;
+ }
+ }
+ return false;
+}
+
+bool TimeDepAttrs::set_memento( const NodeTimeMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+
+#ifdef DEBUG_MEMENTO
+ std::cout << "TimeDepAttrs::set_memento(const NodeTimeMemento* memento) " << node_->debugNodePath() << "\n";
+#endif
+
+ for(size_t i = 0; i < timeVec_.size(); ++i) {
+ // We need to ignore state changes in TimeAttr, (ie we don't use equality operator)
+ // otherwise time will never compare
+ if ( timeVec_[i].structureEquals(memento->attr_) ) {
+ timeVec_[i] = memento->attr_; // need to copy over time series state
+ return true;
+ }
+ }
+ return false;
+}
+
+bool TimeDepAttrs::set_memento( const NodeCronMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+
+#ifdef DEBUG_MEMENTO
+ std::cout << "TimeDepAttrs::set_memento(const NodeCronMemento* memento) " << node_->debugNodePath() << "\n";
+#endif
+
+ for(size_t i = 0; i < crons_.size(); ++i) {
+ // We need to ignore state changes (ie we don't use equality operator)
+ // otherwise attributes will never compare
+ if ( crons_[i].structureEquals(memento->attr_) ) {
+ crons_[i] = memento->attr_; // need to copy over time series state
+ return true;
+ }
+ }
+ return false;
+}
+
+bool TimeDepAttrs::set_memento( const NodeDayMemento* memento ,std::vector<ecf::Aspect::Type>& aspects) {
+
+#ifdef DEBUG_MEMENTO
+ std::cout << "TimeDepAttrs::set_memento(const NodeDayMemento* memento) " << node_->debugNodePath() << "\n";
+#endif
+
+ for(size_t i = 0; i < days_.size(); ++i) {
+ // We need to ignore state changes (ie we don't use equality operator)
+ // otherwise attributes will never compare
+ if ( days_[i].structureEquals(memento->attr_) ) {
+ if (memento->attr_.isSetFree()) days_[i].setFree();
+ else days_[i].clearFree();
+ return true;
+ }
+ }
+ return false;
+}
+
+bool TimeDepAttrs::set_memento( const NodeDateMemento* memento,std::vector<ecf::Aspect::Type>& aspects ) {
+
+#ifdef DEBUG_MEMENTO
+ std::cout << "TimeDepAttrs::set_memento(const NodeDateMemento* memento) " << node_->debugNodePath() << "\n";
+#endif
+
+ for(size_t i = 0; i < dates_.size(); ++i) {
+ // We need to ignore state changes (ie we don't use equality operator)
+ // otherwise attributes will never compare
+ if ( dates_[i].structureEquals(memento->attr_) ) {
+ if (memento->attr_.isSetFree()) dates_[i].setFree();
+ else dates_[i].clearFree();
+ return true;
+ }
+ }
+ return false;
+}
+
diff --git a/ANode/src/TimeDepAttrs.hpp b/ANode/src/TimeDepAttrs.hpp
new file mode 100644
index 0000000..7c75007
--- /dev/null
+++ b/ANode/src/TimeDepAttrs.hpp
@@ -0,0 +1,149 @@
+#ifndef TIME_DEP_ATTRS_HPP_
+#define TIME_DEP_ATTRS_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #231 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <ostream>
+
+#include <boost/serialization/base_object.hpp>
+#include <boost/serialization/utility.hpp>
+#include <boost/serialization/vector.hpp> // no need to include <vector>
+
+#include "TimeAttr.hpp"
+#include "TodayAttr.hpp"
+#include "DateAttr.hpp"
+#include "DayAttr.hpp"
+#include "CronAttr.hpp"
+#include "NodeFwd.hpp"
+#include "Aspect.hpp"
+
+class TimeDepAttrs {
+public:
+ TimeDepAttrs(Node* node) : node_(node) {}
+ TimeDepAttrs() : node_(NULL) {}
+
+ // needed by node serialisation
+ void set_node(Node* n) { node_ = n; }
+
+ void begin();
+
+ /// If a job takes longer than it slots, then that slot is missed, and next slot is used
+ /// Note we do *NOT* reset for requeue as we want to advance the valid time slots.
+ /// *NOTE* Update calendar will *free* time dependencies *even* time series. They rely
+ /// on this function to clear the time dependencies so they *HOLD* the task.
+ ///
+ /// If we have done an interactive run or complete, *dont* increment next_time_slot_
+ void requeue(bool reset_next_time_slot);
+
+ void miss_next_time_slot();
+ void freeHoldingDateDependencies();
+ void freeHoldingTimeDependencies();
+
+ void calendarChanged(const ecf::Calendar& c);
+
+ // standard functions: ==============================================
+ std::ostream& print(std::ostream&) const;
+ bool operator==(const TimeDepAttrs& rhs) const;
+ bool checkInvariants(std::string& errorMsg) const;
+
+ bool timeDependenciesFree() const;
+ bool time_today_cron_is_free() const; /* used by viewer */
+
+ // Access functions: ======================================================
+ const std::vector<ecf::TimeAttr>& timeVec() const { return timeVec_; }
+ const std::vector<ecf::TodayAttr>& todayVec() const { return todayVec_; }
+ const std::vector<DateAttr>& dates() const { return dates_; }
+ const std::vector<DayAttr>& days() const { return days_; }
+ const std::vector<ecf::CronAttr>& crons() const { return crons_; }
+
+ // Add functions: ===============================================================
+ void addTime( const ecf::TimeAttr& );
+ void addToday( const ecf::TodayAttr& );
+ void addDate( const DateAttr& );
+ void addDay( const DayAttr& );
+ void addCron( const ecf::CronAttr& );
+
+ // Delete functions: can throw std::runtime_error ===================================
+ // if name argument is empty, delete all attributes of that type
+ // Can throw std::runtime_error of the attribute can not be found
+ void deleteTime(const std::string& name );
+ void delete_time( const ecf::TimeAttr& );
+ void deleteToday(const std::string& name);
+ void delete_today(const ecf::TodayAttr&);
+ void deleteDate(const std::string& name);
+ void delete_date(const DateAttr&);
+ void deleteDay(const std::string& name);
+ void delete_day(const DayAttr&);
+ void deleteCron(const std::string& name);
+ void delete_cron(const ecf::CronAttr&);
+
+ // Change functions: ================================================================
+ /// returns true the change was made else false, Can throw std::runtime_error for parse errors
+
+ // mementos functions:
+ /// Collect all the state changes, so that only small subset is returned to client
+ bool set_memento(const NodeTodayMemento* ,std::vector<ecf::Aspect::Type>& aspects);
+ bool set_memento(const NodeTimeMemento* ,std::vector<ecf::Aspect::Type>& aspects);
+ bool set_memento(const NodeDayMemento* ,std::vector<ecf::Aspect::Type>& aspects);
+ bool set_memento(const NodeCronMemento* ,std::vector<ecf::Aspect::Type>& aspects);
+ bool set_memento(const NodeDateMemento* ,std::vector<ecf::Aspect::Type>& aspects);
+
+ void why(std::vector<std::string>& theReasonWhy,const std::string& prefix) const;
+ bool testTimeDependenciesForRequeue() const;
+ void resetRelativeDuration();
+
+
+/// For use by python interface,
+ std::vector<ecf::TimeAttr>::const_iterator time_begin() const { return timeVec_.begin();}
+ std::vector<ecf::TimeAttr>::const_iterator time_end() const { return timeVec_.end();}
+ std::vector<ecf::TodayAttr>::const_iterator today_begin() const { return todayVec_.begin();}
+ std::vector<ecf::TodayAttr>::const_iterator today_end() const { return todayVec_.end();}
+ std::vector<DateAttr>::const_iterator date_begin() const { return dates_.begin();}
+ std::vector<DateAttr>::const_iterator date_end() const { return dates_.end();}
+ std::vector<DayAttr>::const_iterator day_begin() const { return days_.begin();}
+ std::vector<DayAttr>::const_iterator day_end() const { return days_.end();}
+ std::vector<ecf::CronAttr>::const_iterator cron_begin() const { return crons_.begin();}
+ std::vector<ecf::CronAttr>::const_iterator cron_end() const { return crons_.end();}
+
+
+ void clear(); /// Clear *ALL* internal attributes
+
+
+ /// Under the hybrid calendar some time dependent attributes may not be applicable
+ /// i.e if day,date,cron attributes does correspond to 24 hours of today, then we
+ /// need make them as complete.
+ void markHybridTimeDependentsAsComplete();
+
+private:
+ Node* node_; // *NOT* persisted must be set by the parent class
+
+ std::vector<ecf::TimeAttr> timeVec_;
+ std::vector<ecf::TodayAttr> todayVec_;
+ std::vector<DateAttr> dates_;
+ std::vector<DayAttr> days_;
+ std::vector<ecf::CronAttr> crons_;
+
+private:
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/) {
+ ar & timeVec_;
+ ar & todayVec_;
+ ar & dates_;
+ ar & days_;
+ ar & crons_;
+ }
+};
+
+#endif
diff --git a/ANode/test/MyDefsFixture.hpp b/ANode/test/MyDefsFixture.hpp
new file mode 100644
index 0000000..a41c089
--- /dev/null
+++ b/ANode/test/MyDefsFixture.hpp
@@ -0,0 +1,249 @@
+#ifndef MYDEFSFIXTURE_HPP_
+#define MYDEFSFIXTURE_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Description : The structure ONLY used to test the persistence/migration
+// as each new object is created we add it here, to test
+// Serialisation read/write and migration of previous fixtures
+//============================================================================
+#include <boost/lexical_cast.hpp>
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "Alias.hpp"
+#include <algorithm> //for for_each()
+// =======================================================================
+// This struct is used in the node migration tests.
+// If we ever add to this , then update TestMigration.cpp
+// **Ensure** that we keep old fixture.def file, to test that future ecflow
+// versions can migrate old data.
+// =======================================================================
+struct MyDefsFixture {
+
+ MyDefsFixture(const std::string& fileName = "defsfile.txt") : defsfile_()
+ {
+ suite_ptr suite = create_suite();
+
+ // Must be done last
+ defsfile_.addSuite( suite );
+ defsfile_.add_extern("/limits:event");
+ defsfile_.add_extern("/a/b/c:meter");
+ defsfile_.add_extern("/a/b/c/d");
+
+ // add an empty suite. Needed for CHECK_JOB_GEN_ONLY cmd
+ defsfile_.addSuite( Suite::create("EmptySuite" ) );
+
+ // Check expression parse
+ std::string errorMsg, warningMsg;
+ bool result = defsfile_.check(errorMsg,warningMsg);
+ if (!result || !errorMsg.empty()) {
+ std::cout << errorMsg;
+ assert(false);
+ }
+ }
+ ~MyDefsFixture() {}
+
+ const Defs& fixtureDefsFile() const { return defsfile_; }
+
+ void remove_host_depedent_server_variables()
+ {
+ // Allow test data to be used on other platforms
+ defsfile_.set_server().delete_server_variable("ECF_LOG");
+ defsfile_.set_server().delete_server_variable("ECF_CHECK");
+ defsfile_.set_server().delete_server_variable("ECF_CHECKOLD");
+ }
+
+
+ defs_ptr create_defs() const {
+
+ defs_ptr defs = Defs::create();
+
+ defs->addSuite( create_suite() );
+ defs->add_extern("/limits:event");
+ defs->add_extern("/a/b/c:meter");
+ defs->add_extern("/a/b/c/d");
+ defs->set_server().add_or_update_user_variables("MyDefsFixture_user_variable","This is a user variable added to server");
+
+ // add an empty suite. Needed for CHECK_JOB_GEN_ONLY cmd
+ defs->addSuite( Suite::create("EmptySuite" ) );
+
+ // Check expression parse
+ std::string errorMsg, warningMsg;
+ bool result = defs->check(errorMsg,warningMsg);
+ if (!result || !errorMsg.empty()) {
+ std::cout << errorMsg;
+ assert(false);
+ }
+ return defs;
+ }
+
+ Defs defsfile_;
+
+private:
+ suite_ptr create_suite() const {
+ std::string sname = "suiteName";
+ suite_ptr suite = Suite::create( sname );
+
+ ClockAttr clockAttr(false);
+ clockAttr.date(1,1,2009);
+ clockAttr.set_gain_in_seconds(3600);
+ clockAttr.startStopWithServer(true);
+ suite->addClock( clockAttr );
+
+ suite->addAutoCancel( ecf::AutoCancelAttr(2) );
+ suite->addVariable( Variable("VAR","value") );
+ suite->addVariable( Variable("VAR1","\"value\"") );
+ suite->addVariable( Variable("ECF_FETCH","\"smsfetch -F %ECF_FILES% -I %ECF_INCLUDE%\"") );
+
+ suite->add_task( "t1" );
+ suite->add_task( "t2" );
+ task_ptr suiteTask = suite->add_task( "t3" );
+ suiteTask->add_part_trigger( PartExpression("t1 == complete") );
+ suiteTask->add_part_trigger( PartExpression("t2 == complete",false) );
+ suiteTask->add_part_complete( PartExpression("t1 == complete") );
+ suiteTask->add_part_complete( PartExpression("t2 == complete",true) );
+
+ std::vector<ecf::Child::CmdType> child_cmds;
+ child_cmds.push_back(ecf::Child::INIT);
+ child_cmds.push_back(ecf::Child::EVENT);
+ child_cmds.push_back(ecf::Child::METER);
+ child_cmds.push_back(ecf::Child::LABEL);
+ child_cmds.push_back(ecf::Child::WAIT);
+ child_cmds.push_back(ecf::Child::ABORT);
+ child_cmds.push_back(ecf::Child::COMPLETE);
+ suiteTask->addZombie( ZombieAttr(ecf::Child::USER, child_cmds, ecf::User::FOB,10) );
+ suiteTask->addZombie( ZombieAttr(ecf::Child::ECF, child_cmds, ecf::User::FAIL,100) );
+ suiteTask->addZombie( ZombieAttr(ecf::Child::PATH, child_cmds, ecf::User::BLOCK,100) );
+
+
+ task_ptr suiteTask4 = suite->add_task( "t4" );
+ suiteTask4->addZombie( ZombieAttr(ecf::Child::USER, child_cmds, ecf::User::ADOPT,10) );
+ suiteTask4->addZombie( ZombieAttr(ecf::Child::ECF, child_cmds, ecf::User::REMOVE,100) );
+ suiteTask4->addZombie( ZombieAttr(ecf::Child::PATH, child_cmds, ecf::User::BLOCK,100) );
+
+
+ ecf::CronAttr cronAttr;
+ ecf::TimeSlot start( 0, 0 );
+ ecf::TimeSlot finish( 10, 0 );
+ ecf::TimeSlot incr( 0, 5 );
+ std::vector<int> weekdays; for(int i=0;i<7;++i) weekdays.push_back(i);
+ std::vector<int> daysOfMonth;for(int i=1;i<32;++i) daysOfMonth.push_back(i);
+ std::vector<int> months; for(int i=1;i<13;++i) months.push_back(i);
+ cronAttr.addTimeSeries(start,finish,incr);
+ cronAttr.addWeekDays( weekdays );
+ cronAttr.addDaysOfMonth(daysOfMonth);
+ cronAttr.addMonths( months );
+ suite->addCron( cronAttr );
+
+ ecf::LateAttr lateAttr;
+ lateAttr.addSubmitted( ecf::TimeSlot(3,12) );
+ lateAttr.addActive( ecf::TimeSlot(3,12) );
+ lateAttr.addComplete( ecf::TimeSlot(4,12), true);
+
+ std::string suiteLimit = "suiteLimit";
+ suite->addLimit( Limit(suiteLimit,10) );
+
+ std::vector<std::string> stringList; stringList.reserve(3);
+ stringList.push_back("10");
+ stringList.push_back("20");
+ stringList.push_back("30");
+
+ // Add tasks with all the repeat variants
+ task_ptr t5 = suite->add_task( "t5" );
+ t5->addRepeat( RepeatEnumerated("AEnum",stringList));
+
+ task_ptr t6 = suite->add_task( "t6" );
+ t6->addRepeat( RepeatString("aString",stringList));
+
+ task_ptr t7 = suite->add_task( "t7" );
+ t7->addRepeat( RepeatInteger("rep",0,100,1) );
+
+ task_ptr t8 = suite->add_task( "t8" );
+ t8->addRepeat( RepeatDate("YMD",20090916,20090916,1) );
+
+ task_ptr t9 = suite->add_task( "t9" );
+ t9->addRepeat( RepeatDay(2) );
+
+
+ for (int i = 0; i < 3; ++i) {
+ std::string fname = "familyName";
+ std::string tname = "taskName";
+ std::string eventName = "eventName";
+ std::string labelName = "labelName";
+ std::string limitName = "limitName";
+ if ( i != 0 ) {
+ fname += boost::lexical_cast< std::string >( i );
+ tname += boost::lexical_cast< std::string >( i );
+ labelName += boost::lexical_cast< std::string >( i );
+ }
+
+ family_ptr fam = suite->add_family( fname );
+ fam->addDate( DateAttr(0,0,2009) ); // 0 is equivalent to a *
+ fam->addRepeat( RepeatEnumerated("AEnum",stringList));
+ fam->addAutoCancel( ecf::AutoCancelAttr( ecf::TimeSlot(1,0), true));
+ fam->addVariable( Variable("VAR","value") );
+ fam->addTime( ecf::TimeAttr(ecf::TimeSlot(0,0),ecf::TimeSlot(10,1),ecf::TimeSlot(0,1),true) );
+ fam->addLimit( Limit(limitName,20) );
+ fam->addLate( lateAttr );
+
+ task_ptr task = fam->add_task( tname );
+ task->addDate( DateAttr(1,2,2009) );
+ task->addDay( DayAttr(DayAttr::MONDAY) );
+ task->addVariable( Variable("VAR1","\"value\"") );
+ task->addEvent( Event(i) );
+ task->addEvent( Event(i+1, eventName ) );
+ task->addMeter( Meter("myMeter",0,100,100) );
+ task->addLabel( Label(labelName,"\"labelValue\"") );
+ task->addTime( ecf::TimeAttr(ecf::TimeSlot(10,10),true) );
+ task->addToday( ecf::TodayAttr(ecf::TimeSlot(10,12)) );
+ task->addToday( ecf::TodayAttr(ecf::TimeSlot(0,1),ecf::TimeSlot(0,3),ecf::TimeSlot(0,1),true) );
+ task->addDefStatus( DState::COMPLETE );
+ task->addInLimit( InLimit(suiteLimit,"/" + sname ));
+ task->addVerify( VerifyAttr(NState::COMPLETE,3) );
+ task->addLate( lateAttr );
+ if (i == 2) {
+ std::string compExpr = "../familyName" + boost::lexical_cast< std::string >( i-1 );
+ compExpr += "/taskName" + boost::lexical_cast< std::string >( i-1 );
+ compExpr += ":myMeter ge 10";
+ task->add_complete( compExpr );
+
+ std::string expression = "../familyName" + boost::lexical_cast< std::string >( i-1 );
+ expression += "/taskName" + boost::lexical_cast< std::string >( i-1 );
+ expression += " == complete";
+ task->add_trigger( expression );
+ }
+ task->add_alias_only(); //add alias without creating dir & .usr file
+ task->add_alias_only();
+
+
+ // Add a hierarchical family to the first family
+ if (i == 0) {
+ std::string heirFamily = "heir_" + fname;
+ family_ptr hierFam = fam->add_family( heirFamily );
+ hierFam->addVariable( Variable("VAR1","value") );
+ hierFam->addRepeat( RepeatString("aString",stringList));
+
+ task_ptr task1 = hierFam->add_task( tname );
+ task1->addVariable( Variable("VAR1","value") );
+ task1->addEvent( Event(i) );
+ task1->addEvent( Event(i+1, eventName ) );
+ task1->addMeter( Meter("myMeter",0,100,100) );
+ task1->addAutoCancel( ecf::AutoCancelAttr( ecf::TimeSlot(0,1), false));
+ }
+ }
+ return suite;
+ }
+};
+#endif
diff --git a/ANode/test/TestAdd.cpp b/ANode/test/TestAdd.cpp
new file mode 100644
index 0000000..50c4d64
--- /dev/null
+++ b/ANode/test/TestAdd.cpp
@@ -0,0 +1,51 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <iostream>
+#include <stdlib.h>
+
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_add )
+{
+ cout << "ANode:: ...test_add\n";
+
+ defs_ptr defs = Defs::create();
+ task_ptr t1 = Task::create("t1");
+ family_ptr f1 = Family::create("f1");
+ suite_ptr s1 = Suite::create("s1");
+
+ defs->addSuite(s1);
+ s1->addFamily(f1);
+ f1->addTask(t1);
+
+ defs_ptr defs2 = Defs::create();
+ suite_ptr s2 = Suite::create("s2");
+ family_ptr f2 = Family::create("f2");
+
+ // This should all fail since, they are already owned.
+ // Otherwise we end up with two different container owning the same object
+ BOOST_CHECK_THROW( s2->addFamily(f1),std::runtime_error);
+ BOOST_CHECK_THROW( f2->addTask(t1),std::runtime_error);
+ BOOST_CHECK_THROW( defs2->addSuite(s1),std::runtime_error);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ANode/test/TestAlias.cpp b/ANode/test/TestAlias.cpp
new file mode 100644
index 0000000..5a89723
--- /dev/null
+++ b/ANode/test/TestAlias.cpp
@@ -0,0 +1,103 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <iostream>
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "Alias.hpp"
+#include "Str.hpp"
+#include "File.hpp"
+
+namespace fs = boost::filesystem;
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_alias_create )
+{
+ cout << "ANode:: ...test_alias_create\n";
+ std::string ecf_home = File::test_data("ANode/test/data/alias","ANode");
+
+ task_ptr t ;
+ Defs theDefs;
+ {
+ suite_ptr s = theDefs.add_suite("test_alias_create");
+ family_ptr f = s->add_family("f");
+ t = f->add_task("t");
+ t->addMeter(Meter("meter",0,100,100));
+ t->addMeter(Meter("meter1",0,100,100));
+ t->addEvent(Event(1,"event1"));
+ t->addEvent(Event(2,"event2"));
+ t->addLabel(Label("label_name","value"));
+ t->addLabel(Label("label_name1","value"));
+ s->add_variable(Str::ECF_HOME(),ecf_home);
+ }
+
+ // Create .usr file content
+ std::vector<std::string> usr_file_vec;
+ usr_file_vec.push_back("#This is a .usr file.");
+
+ // Create list of variables
+ NameValueVec used_variables;
+ used_variables.push_back( std::make_pair(std::string("a"),std::string("a_value")));
+ used_variables.push_back( std::make_pair(std::string("b"),std::string("b_value")));
+
+ // Finally create the alias.
+ alias_ptr alias = t->add_alias(usr_file_vec,used_variables);
+
+ // Test that default node state is QUEUED
+ BOOST_CHECK_MESSAGE(alias->state() == NState::QUEUED,"Expected initial state of QUEUED");
+
+ // Test that CHILD specific attributes event, meter, labels are copied over from the task.
+ BOOST_CHECK_MESSAGE(alias->meters().size() == 2,"Expected 2 meter to be copied from task but found " << alias->meters().size());
+ BOOST_CHECK_MESSAGE(alias->events().size() == 2,"Expected 2 events to be copied from task but found " << alias->events().size());
+ BOOST_CHECK_MESSAGE(alias->labels().size() == 2,"Expected 2 labels to be copied from task but found " << alias->labels().size());
+
+ // test that user variables passed in got added as Variables
+ BOOST_CHECK_MESSAGE(alias->variables().size() == 2,"Expected 2 variables to be create from input args but found " << alias->variables().size());
+
+ // Test directory creation
+ fs::path dir(ecf_home + "/" + t->absNodePath());
+ BOOST_CHECK_MESSAGE(fs::exists(dir),"Expected directory to be created " + dir.string());
+
+ // Test alias0.usr file creation
+ fs::path usr_file(ecf_home + "/" + t->absNodePath() + "/" + "alias0.usr");
+ BOOST_CHECK_MESSAGE(fs::exists(usr_file),"Expected alias0.usr file to be created " + usr_file.string());
+
+ // Create another alias. This should get created as alias1.usr
+ alias_ptr alias1 = t->add_alias(usr_file_vec,used_variables);
+ fs::path usr_file1(ecf_home + "/" + t->absNodePath() + "/" + "alias1.usr");
+ BOOST_CHECK_MESSAGE(fs::exists(usr_file1),"Expected alias1.usr file to be created " + usr_file1.string());
+
+ // Test Defs::get_all_aliases()
+ std::vector<alias_ptr> alias_vec;
+ theDefs.get_all_aliases(alias_vec);
+ BOOST_CHECK_MESSAGE(alias_vec.size() == 2,"Expected 2 aliases but found " << alias_vec.size());
+
+ // Check alias remove
+ BOOST_FOREACH(alias_ptr al,alias_vec) { al->remove();}
+ alias_vec.clear();
+ theDefs.get_all_aliases(alias_vec);
+ BOOST_CHECK_MESSAGE(alias_vec.empty(),"Expected no aliases but found " << alias_vec.size());
+
+ // Cleanup by removing the created directory
+ fs::remove_all(ecf_home);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ANode/test/TestChangeMgrSingleton.cpp b/ANode/test/TestChangeMgrSingleton.cpp
new file mode 100644
index 0000000..bcafc2c
--- /dev/null
+++ b/ANode/test/TestChangeMgrSingleton.cpp
@@ -0,0 +1,122 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <stdlib.h>
+#include <iostream>
+#include <boost/test/unit_test.hpp>
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "AbstractObserver.hpp"
+
+using namespace std;
+using namespace ecf;
+
+class MyObserver : public AbstractObserver {
+public:
+ MyObserver(Defs* defs) : update_count_(0),defs_(defs),node_(NULL) { defs->attach(this); }
+ MyObserver(Node* node) : update_count_(0),defs_(NULL),node_(node) { node->attach(this); }
+
+ virtual ~MyObserver() {
+ /* std::cout << "~MyObserver()\n"; */
+ if (defs_) defs_->detach(this);
+ if (node_) node_->detach(this);
+ }
+
+ virtual void update(const Node*, const std::vector<ecf::Aspect::Type>&){update_count_++;}
+ virtual void update(const Defs*, const std::vector<ecf::Aspect::Type>&){update_count_++;}
+
+ /// After this call, the node will be deleted, hence observers must *NOT* use the pointers
+ virtual void update_delete(const Node* node) {
+ //std::cout << "update_delete(const Node* node)\n";
+ const_cast<Node*>(node)->detach(this);
+ }
+ virtual void update_delete(const Defs* defs) {
+ //std::cout << "update_delete(const Defs* node)\n";
+ const_cast<Defs*>(defs)->detach(this);
+ }
+
+ int update_count() const { return update_count_;}
+private:
+ int update_count_;
+ Defs* defs_;
+ Node* node_;
+};
+
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_change_mgr_singleton )
+{
+ cout << "ANode:: ...test_change_mgr_singleton\n";
+ {
+ defs_ptr theDefs = Defs::create();
+
+ {
+ // ensure defs pointer out-lives the observer
+ MyObserver defs_obs(theDefs.get());
+
+ std::vector<ecf::Aspect::Type> aspects;
+ theDefs->notify(aspects);
+ theDefs->notify(aspects);
+ theDefs->notify(aspects);
+ theDefs->notify(aspects);
+ theDefs->notify(aspects);
+ BOOST_CHECK_MESSAGE( defs_obs.update_count() == 5,"Expected 5 update");
+ }
+
+ theDefs.reset();
+ }
+
+ {
+ // **** Note using node_ptr can extend the life of the Node, hence we use scoping ***
+ Defs* theDefs = new Defs;
+ std::vector<MyObserver*> obs_vec;
+ {
+ {
+ suite_ptr suite = theDefs->add_suite( "suite1" );
+ family_ptr fam = suite->add_family( "family" );
+ fam->add_task( "t1" );
+ }
+
+ // get all nodes and observer them.
+ std::vector<node_ptr> node_vec; theDefs->get_all_nodes(node_vec);
+
+ // Need to make sure life time of observer is greater than Node tree
+ for(size_t i = 0; i < node_vec.size(); ++i) {
+ obs_vec.push_back( new MyObserver( node_vec[i].get() ) );
+ }
+
+ // Do some updates
+ std::vector<ecf::Aspect::Type> aspects;
+ for(size_t i = 0; i < node_vec.size(); ++i) {
+ node_vec[i]->notify(aspects);
+ node_vec[i]->notify(aspects);
+ }
+ for(size_t i = 0; i < obs_vec.size(); ++i) {
+ BOOST_CHECK_MESSAGE( obs_vec[i]->update_count() == 2,"Expected 2 updates");
+ }
+
+ // delete observers
+ for(size_t i = 0; i < obs_vec.size(); ++i) { delete obs_vec[i]; }
+ }
+
+ // make sure no node_ptr are in scope as they can *delay*
+ // the destructor to the end of the scope, and hence affect this test
+ delete theDefs;
+ }
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ANode/test/TestDefStatus.cpp b/ANode/test/TestDefStatus.cpp
new file mode 100644
index 0000000..91915a6
--- /dev/null
+++ b/ANode/test/TestDefStatus.cpp
@@ -0,0 +1,154 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <iostream>
+#include <stdlib.h>
+
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_defstatus )
+{
+ cout << "ANode:: ...test_defstatus\n";
+
+ // Create a defs file corresponding to:
+ //suite suite1
+ // family f1
+ // task t1
+ // task t2
+ // family f2
+ // task t1
+ // task t2
+ Defs theDefs;
+ suite_ptr suite = theDefs.add_suite( "suite1" );
+ family_ptr f1 = suite->add_family( "f1" );
+ task_ptr t1 = f1->add_task( "t1" );
+ task_ptr t2 = f1->add_task( "t2" );
+
+ family_ptr f2 = suite->add_family( "f2" );
+ task_ptr f2_t1 = f2->add_task( "t1" );
+ task_ptr f2_t2 = f2->add_task( "t2" );
+
+ // Get all nodes and tasks for ease of test
+ vector<Node*> nodes;
+ vector<Task*> tasks;
+ theDefs.getAllNodes(nodes);
+ theDefs.getAllTasks(tasks);
+
+ /// It should be noted that once a suite has begun, it stays begun, however for test purposes we had
+ /// added ability to reset the begin state.
+
+ /// Test 1: with no defstatus. All nodes should be set to NState::QUEUED
+ theDefs.beginAll();
+ BOOST_FOREACH(Node* n,nodes) { BOOST_CHECK_MESSAGE(n->state() == NState::QUEUED,"Expected queued but found " << NState::toString(n->state())); }
+
+ theDefs.requeue();
+ BOOST_FOREACH(Node* n,nodes) { BOOST_CHECK_MESSAGE(n->state() == NState::QUEUED,"Expected queued but found " << NState::toString(n->state())); }
+
+
+ /// Test 2: with defstatus on suite. With complete the status should have been propagated down
+ suite->addDefStatus(DState::COMPLETE);
+ theDefs.reset_begin(); // for test purposes only
+ theDefs.beginAll();
+ BOOST_FOREACH(Node* n,nodes) {
+ BOOST_CHECK_MESSAGE(n->state() == NState::COMPLETE,"Expected complete but found " << NState::toString(n->state()));
+ }
+
+ theDefs.requeue();
+ BOOST_FOREACH(Node* n,nodes) {
+ BOOST_CHECK_MESSAGE(n->state() == NState::COMPLETE,"Expected complete but found " << NState::toString(n->state()));
+ }
+
+ /// Test 3: defstatus of family f1 and f2. The parent node(suite) should reflect status of children
+ /// Also setting defstatus complete on a family should have propagated it downwards to tasks
+ suite->addDefStatus(DState::default_state()); // reset defstatus
+ f1->addDefStatus(DState::COMPLETE);
+ f2->addDefStatus(DState::COMPLETE);
+ theDefs.reset_begin(); // for test purposes only
+ theDefs.beginAll();
+ BOOST_FOREACH(Node* n,nodes) {
+ BOOST_CHECK_MESSAGE(n->state() == NState::COMPLETE,"Expected complete but found " << NState::toString(n->state()));
+ }
+
+ theDefs.requeue();
+ BOOST_FOREACH(Node* n,nodes) {
+ BOOST_CHECK_MESSAGE(n->state() == NState::COMPLETE,"Expected complete but found " << NState::toString(n->state()));
+ }
+
+
+ // Suspend is really a user interaction the real state suould be queued
+ f1->addDefStatus(DState::default_state()); // reset defstatus
+ f2->addDefStatus(DState::default_state()); // reset defstatus
+ suite->addDefStatus(DState::SUSPENDED); // reset defstatus
+ theDefs.reset_begin(); // for test purposes only
+ theDefs.beginAll();
+ BOOST_FOREACH(Node* n,nodes) { BOOST_CHECK_MESSAGE(n->state() == NState::QUEUED,"Expected queued but found " << NState::toString(n->state())); }
+
+ theDefs.requeue();
+ BOOST_FOREACH(Node* n,nodes) { BOOST_CHECK_MESSAGE(n->state() == NState::QUEUED,"Expected queued but found " << NState::toString(n->state())); }
+}
+
+BOOST_AUTO_TEST_CASE( test_ECFLOW_139 )
+{
+ cout << "ANode:: ...test_ECFLOW_139\n";
+
+ // Create a defs file corresponding to:
+ //suite suite1
+ // family f1
+ // task t1; defstatus suspended
+ // task t2; defstatus suspended
+ // family f2
+ // task t1; defstatus suspended
+ // task t2; defstatus suspended
+ Defs theDefs;
+ suite_ptr suite = theDefs.add_suite( "suite1" );
+ family_ptr f1 = suite->add_family( "f1" );
+ task_ptr t1 = f1->add_task( "t1" );
+ task_ptr t2 = f1->add_task( "t2" );
+ t1->addDefStatus(DState::SUSPENDED);
+ t2->addDefStatus(DState::SUSPENDED);
+
+ family_ptr f2 = suite->add_family( "f2" );
+ task_ptr f2_t1 = f2->add_task( "t1" );
+ task_ptr f2_t2 = f2->add_task( "t2" );
+ f2_t1->addDefStatus(DState::SUSPENDED);
+ f2_t2->addDefStatus(DState::SUSPENDED);
+
+ // Get all nodes and tasks for ease of test
+ vector<Task*> tasks;
+ theDefs.getAllTasks(tasks);
+
+ /// It should be noted that once a suite has begun, it stays begun, however for test purposes we had
+ /// added ability to reset the begin state.
+
+ /// Test 1: Check NODE state All nodes should be set to NState::QUEUED
+ theDefs.beginAll();
+ BOOST_FOREACH(Task* n,tasks) { BOOST_CHECK_MESSAGE(n->state() == NState::QUEUED,"Expected queued but found " << NState::toString(n->state())); }
+
+ /// Check: DSTATE
+ BOOST_FOREACH(Task* n,tasks) { BOOST_CHECK_MESSAGE(n->dstate() == DState::SUSPENDED,"Expected suspended but found " << DState::toString(n->dstate())); }
+
+ theDefs.requeue();
+ BOOST_FOREACH(Task* n,tasks) { BOOST_CHECK_MESSAGE(n->state() == NState::QUEUED,"Expected queued but found " << NState::toString(n->state())); }
+ BOOST_FOREACH(Task* n,tasks) { BOOST_CHECK_MESSAGE(n->dstate() == DState::SUSPENDED,"Expected suspended but found " << DState::toString(n->dstate())); }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ANode/test/TestDefs.cpp b/ANode/test/TestDefs.cpp
new file mode 100644
index 0000000..fc99ede
--- /dev/null
+++ b/ANode/test/TestDefs.cpp
@@ -0,0 +1,84 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <iostream>
+#include <stdlib.h>
+
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_defs_absorb )
+{
+ cout << "ANode:: ...test_defs_absorb\n";
+
+ // Create a defs file corresponding to:
+ //suite suite1
+ // family family
+ // task t1
+ // endfamily
+ //endsuite
+ Defs theDefs;
+ {
+ suite_ptr suite = theDefs.add_suite( "suite1" );
+ family_ptr fam = suite->add_family( "family" );
+ fam->add_task( "t1" );
+ }
+ // Then ABSORB a new def
+ //suite suite1-n
+ // family family
+ // task suite1_task1
+ // endfamily
+ //endsuite
+ Defs otherDefs;
+ {
+ for(int i = 0; i < 14; ++i) {
+ suite_ptr suite1 = otherDefs.add_suite( "suite" + boost::lexical_cast<std::string>(i) );
+ family_ptr fam = suite1->add_family( "family" );
+ fam->add_task("suite1_task1");
+ }
+ }
+
+ theDefs.absorb(&otherDefs, true);
+ BOOST_CHECK_MESSAGE(otherDefs.suiteVec().empty(),"absorb failed");
+}
+
+BOOST_AUTO_TEST_CASE( test_defs_absorb_server_user_variables )
+{
+ cout << "ANode:: ...test_defs_absorb_server_user_variables\n";
+
+ Defs theDefs;
+ Defs otherDefs;
+ {
+ otherDefs.set_server().add_or_update_user_variables("VAR1","VAL");
+ otherDefs.set_server().add_or_update_user_variables("VAR2","VAL");
+ otherDefs.set_server().add_or_update_user_variables("VAR3","VAL");
+ otherDefs.add_suite("suite");
+ }
+
+ BOOST_CHECK_MESSAGE(theDefs.server().user_variables().empty(),"Expected no server user variables");
+
+ theDefs.absorb(&otherDefs, true);
+
+ BOOST_CHECK_MESSAGE(otherDefs.suiteVec().empty(),"absorb failed");
+ BOOST_CHECK_MESSAGE(theDefs.suiteVec().size() == 1,"absorb failed");
+ BOOST_CHECK_MESSAGE(theDefs.server().user_variables().size() == 3,"Expected 3 server user variables");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ANode/test/TestEcfFile.cpp b/ANode/test/TestEcfFile.cpp
new file mode 100644
index 0000000..f0d41db
--- /dev/null
+++ b/ANode/test/TestEcfFile.cpp
@@ -0,0 +1,1184 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/test/unit_test.hpp>
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "EcfFile.hpp"
+#include "JobsParam.hpp"
+#include "Jobs.hpp"
+#include "System.hpp"
+#include "File.hpp"
+#include "Str.hpp"
+#include "Ecf.hpp"
+#include "PrintStyle.hpp"
+
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_ecf_file_with_bad_ECF_MICRO )
+{
+ cout << "ANode:: ...test_ecf_file_with_bad_ECF_MICRO\n";
+
+ // Create the defs file corresponding to the text below
+ //suite suite
+ // task t1
+ // ECF_MICRO "" # can not be empty if overridden
+ // task t2
+ // ECF_MICRO "ss" # must be a single char
+ //endsuite
+
+ task_ptr task_t1;
+ task_ptr task_t2;
+ Defs theDefs; {
+ suite_ptr suite = theDefs.add_suite("suite");
+ task_t1 = suite->add_task( "t1" ); task_t1->add_variable("ECF_MICRO","");
+ task_t2 = suite->add_task( "t2" ); task_t2->add_variable("ECF_MICRO","ss");
+ }
+
+ // Check we throw for bad ECF_MICRO chars
+ std::string ecf_file_location;
+ BOOST_REQUIRE_THROW(EcfFile ecfFile(task_t1.get(),ecf_file_location),std::runtime_error);
+ BOOST_REQUIRE_THROW(EcfFile ecfFile(task_t2.get(),ecf_file_location),std::runtime_error);
+}
+
+BOOST_AUTO_TEST_CASE( test_ecf_simple_include_file )
+{
+ // The specific files are specified in ECF_INCLUDE and common files
+ // are specified in ECF_HOME. This test will ensure that if the file common.h
+ // is not found in ECF_INCLUDE we then look at ECF_HOME
+ cout << "ANode:: ...test_ecf_simple_include_file";
+
+ // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode.
+ if (getenv("ECFLOW_CRAY_BATCH")) {
+ cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n";
+ return;
+ }
+ cout << "\n";
+
+ // Create the defs file corresponding to the text below
+ //suite suite
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // task t1
+ //endsuite
+
+ // Create a defs file, where the task name mirrors the ecf files in the given directory
+ task_ptr task_t1 = Task::create( "t1" );
+ suite_ptr suite = Suite::create( "suite" );
+ Defs theDefs; {
+ suite->addVariable( Variable( Str::ECF_INCLUDE(), "$ECF_HOME/includes" ) );
+ suite->addTask( task_t1 );
+ theDefs.addSuite( suite );
+ }
+
+ // Override ECF_HOME. ECF_HOME is as default location for .ecf files, when ECF_INCLUDE not specified
+ // or when file does not exist in ECF_INCLUDE
+ std::string ecf_home = File::test_data("ANode/test/data","ANode");
+ theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(),ecf_home);
+
+ /// begin , will cause creation of generated variables. The generated variables
+ /// are use in client scripts and used to locate the sms files
+ theDefs.beginAll();
+
+ // generate the ecf file;
+ string header = "%include <simple_head.h>\n";
+ string body = "#body\n";
+ string tail = "%include <simple_tail.h>\n";
+ string ecf_file = header;
+ ecf_file += body;
+ ecf_file += tail;
+
+ string ecf_file_location = ecf_home + task_t1->absNodePath() + File::ECF_EXTN();
+ // cout << "file_location = " << ecf_file_location << "\n";
+ BOOST_CHECK_MESSAGE(File::createMissingDirectories(ecf_file_location),"Could not create missing dir\n");
+
+ string errormsg;
+ BOOST_CHECK_MESSAGE(File::create(ecf_file_location, ecf_file, errormsg), errormsg);
+ BOOST_CHECK_MESSAGE(fs::exists(ecf_file_location), "Expected File " << ecf_file_location << " to exist");
+
+ // Create the generated variables
+ task_t1->update_generated_variables();
+
+ /// Now finally the test
+ EcfFile ecfFile(task_t1.get(),ecf_file_location);
+
+ /// Check generation of '.usr' and job files
+ JobsParam jobsParam(true); // spawn_jobs = false
+ try { ecfFile.create_job(jobsParam); }
+ catch ( std::exception& e) { BOOST_CHECK_MESSAGE(false,"Expected job creation to succeed " << e.what());}
+
+ string job_file_location = ecf_home + task_t1->absNodePath() + File::JOB_EXTN() + task_t1->tryNo();
+ BOOST_CHECK_MESSAGE(fs::exists(job_file_location), "Expected File " << job_file_location << " to exist");
+
+ // Open the job file/
+ std::string job_file_contents;
+ BOOST_CHECK_MESSAGE(File::open(job_file_location,job_file_contents),"Could not open job file " << job_file_location);
+
+ std::string expected_job_file_contents = "#head.h\n#body\n#tail.h";
+ BOOST_CHECK_MESSAGE(job_file_contents == expected_job_file_contents ,"Expected\n" <<expected_job_file_contents << "' but found \n" << job_file_contents << "'");
+
+ /// Remove all the generated files
+ boost::filesystem::remove_all( ecf_home + suite->absNodePath() );
+}
+
+BOOST_AUTO_TEST_CASE( test_ECFLOW_495 )
+{
+ // This tests for a regression where, *NOT* all the include file were processed.
+ cout << "ANode:: ...test_ECFLOW_495";
+ if (getenv("ECFLOW_CRAY_BATCH")) {
+ cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n";
+ return;
+ }
+ cout << "\n";
+
+ // Create the defs file corresponding to the text below
+ //suite suite
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // task t1
+ //endsuite
+ Defs theDefs;
+ suite_ptr suite = theDefs.add_suite("suite");
+ suite->addVariable( Variable( Str::ECF_INCLUDE(), "$ECF_HOME/includes" ) );
+ task_ptr task_t1 = suite->add_task("t1");
+
+ // Override ECF_HOME. ECF_HOME is as default location for .ecf files, when ECF_INCLUDE not specified
+ // or when file does not exist in ECF_INCLUDE
+ std::string ecf_home = File::test_data("ANode/test/data","ANode");
+ theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(),ecf_home);
+
+ /// begin , will cause creation of generated variables. The generated variables
+ /// are use in client scripts and used to locate the ecf files
+ theDefs.beginAll();
+
+ // Create the ecf file; *NOTE* <a.h> includes <b.h>
+ string ecf_file = "%include <a.h>\n";
+ ecf_file += "%PAR_EXE:parallel% --gnu --verbose -j $PAR_THR ${run:-0} ::: $(seq %PAR_BEG:0% %PAR_END:50%)\n";
+
+ string ecf_file_location = ecf_home + task_t1->absNodePath() + File::ECF_EXTN();
+ // cout << "file_location = " << ecf_file_location << "\n";
+ BOOST_CHECK_MESSAGE(File::createMissingDirectories(ecf_file_location),"Could not create missing dir\n");
+
+ string errormsg;
+ BOOST_CHECK_MESSAGE(File::create(ecf_file_location, ecf_file, errormsg), errormsg);
+ BOOST_CHECK_MESSAGE(fs::exists(ecf_file_location), "Expected File " << ecf_file_location << " to exist");
+
+ // Create the generated variables
+ task_t1->update_generated_variables();
+
+ /// Now finally the test
+ EcfFile ecfFile(task_t1.get(),ecf_file_location);
+
+ JobsParam jobsParam(true); // spawn_jobs = false
+ try { ecfFile.create_job(jobsParam); }
+ catch ( std::exception& e) { BOOST_CHECK_MESSAGE(false,"Expected job creation to succeed " << e.what());}
+
+ string job_file_location = ecf_home + task_t1->absNodePath() + File::JOB_EXTN() + task_t1->tryNo();
+ BOOST_CHECK_MESSAGE(fs::exists(job_file_location), "Expected File " << job_file_location << " to exist");
+
+ // Open the job file and check job file contents match what we expected
+ std::string job_file_contents;
+ BOOST_CHECK_MESSAGE(File::open(job_file_location,job_file_contents),"Could not open job file " << job_file_location);
+
+ std::string expected_job_file_contents = "#a.h\n#b.h\nparallel --gnu --verbose -j $PAR_THR ${run:-0} ::: $(seq 0 50)";
+ BOOST_CHECK_MESSAGE(job_file_contents == expected_job_file_contents ,"Expected\n'" << expected_job_file_contents << "' but found \n'" << job_file_contents << "'");
+
+ /// Remove all the generated files
+ boost::filesystem::remove_all( ecf_home + suite->absNodePath() );
+}
+
+
+BOOST_AUTO_TEST_CASE( test_ECF_SCRIPT_CMD_ECFLOW_427 )
+{
+ cout << "ANode:: ...test_ECF_SCRIPT_CMD_ECFLOW_427";
+ if (getenv("ECFLOW_CRAY_BATCH")) {
+ cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n";
+ return;
+ }
+ cout << "\n";
+
+ // Create the defs file corresponding to the text below
+ //suite suite
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // task t1
+ //endsuite
+
+ // Create a defs file, where the task name mirrors the ecf files in the given directory
+ task_ptr task_t1 = Task::create( "t1" );
+ suite_ptr suite = Suite::create( "test_ECF_SCRIPT_CMD_ECFLOW_427" );
+ Defs theDefs; {
+ suite->addVariable( Variable( Str::ECF_INCLUDE(), "$ECF_HOME/includes" ) );
+ suite->addTask( task_t1 );
+ theDefs.addSuite( suite );
+ }
+
+ // Override ECF_HOME. ECF_HOME is as default location for .ecf files, when ECF_INCLUDE not specified
+ // or when file does not exist in ECF_INCLUDE
+ std::string ecf_home = File::test_data("ANode/test/data","ANode");
+ theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(),ecf_home);
+
+ /// begin , will cause creation of generated variables. The generated variables
+ /// are use in client scripts and used to locate the sms files
+ theDefs.beginAll();
+
+ // generate the ecf file;
+ string header = "%include <simple_head.h>\n";
+ string body = "#body\n";
+ body += "%manual\nThis is a manual\n%end\n";
+ string tail = "%include <simple_tail.h>\n";
+ string ecf_file = header;
+ ecf_file += body;
+ ecf_file += tail;
+
+ std::string cmd = "cat %ECF_HOME%/%ECF_NAME%.ecf" ;
+ task_t1->add_variable("ECF_SCRIPT_CMD",cmd);
+
+ /// Now finally the test, use this as this will perform variable expansion on ECF_SCRIPT_CMD
+ EcfFile ecfFile = task_t1->locatedEcfFile();
+
+ // *******************************************************************************************************
+ // CREATE the file after locatedEcfFile() otherwise it will just use script as is, and NOT ECF_SCRIPT_CMD
+ // *******************************************************************************************************
+ string ecf_file_location = ecf_home + task_t1->absNodePath() + File::ECF_EXTN();
+ // cout << "file_location = " << ecf_file_location << "\n";
+ BOOST_CHECK_MESSAGE(File::createMissingDirectories(ecf_file_location),"Could not create missing dir\n");
+
+ string errormsg;
+ BOOST_CHECK_MESSAGE(File::create(ecf_file_location, ecf_file, errormsg), errormsg);
+ BOOST_CHECK_MESSAGE(fs::exists(ecf_file_location), "Expected File " << ecf_file_location << " to exist");
+
+ /// Check generation of job files
+ JobsParam jobsParam(true); // spawn_jobs = false
+ {
+ task_t1->update_generated_variables();
+
+ try { ecfFile.create_job(jobsParam); }
+ catch ( std::exception& e) { BOOST_CHECK_MESSAGE(false,"Expected job creation to succeed " << e.what());}
+
+ string job_file_location = ecf_home + task_t1->absNodePath() + File::JOB_EXTN() + task_t1->tryNo();
+ BOOST_CHECK_MESSAGE(fs::exists(job_file_location), "Expected File " << job_file_location << " to exist");
+
+ // Open the job file and check contents
+ std::string job_file_contents;
+ BOOST_CHECK_MESSAGE(File::open(job_file_location,job_file_contents),"Could not open job file " << job_file_location);
+ std::string expected_job_file_contents = "#head.h\n#body\n#tail.h";
+ BOOST_CHECK_MESSAGE(job_file_contents == expected_job_file_contents ,"Expected\n'" <<expected_job_file_contents << "' but found:\n'" << job_file_contents << "'");
+ }
+
+ /// Check manual extraction
+ {
+ std::string manual;
+ try { ecfFile.manual(manual); }
+ catch ( std::exception& e) { BOOST_CHECK_MESSAGE(false,"Expected manual extraction to succeed " << e.what());}
+
+ std::string expected_manual = "This is a manual\n";
+ BOOST_CHECK_MESSAGE(manual == expected_manual ,"Expected:\n'" << expected_manual << "' but found:\n'" << manual << "'");
+ }
+
+ /// Check script
+ {
+ std::string script;
+ try { ecfFile.script(script); }
+ catch ( std::exception& e) { BOOST_CHECK_MESSAGE(false,"Expected script extraction to succeed " << e.what());}
+ BOOST_CHECK_MESSAGE(script == ecf_file ,"Expected:\n'" << ecf_file << "' but found:\n'" << script << "'");
+ }
+
+ /// Remove all the generated files
+ boost::filesystem::remove_all( ecf_home + suite->absNodePath() );
+}
+
+
+BOOST_AUTO_TEST_CASE( test_ecf_include_file )
+{
+ // The specific files are specified in ECF_INCLUDE and common files
+ // are specified in ECF_HOME. This test will ensure that if the file common.h
+ // is not found in ECF_INCLUDE we then look at ECF_HOME
+ cout << "ANode:: ...test_ecf_include_file";
+
+ // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode.
+ if (getenv("ECFLOW_CRAY_BATCH")) {
+ cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n";
+ return;
+ }
+ cout << "\n";
+
+ // SET ECF_HOME
+ std::string ecf_home = File::test_data("ANode/test/data","ANode");
+
+ // Create the defs file corresponding to the text below
+ //suite suite
+ // edit SLEEPTIME 10
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // task t1
+ //endsuite
+
+ // Create a defs file, where the task name mirrors the ecf files in the given directory
+ task_ptr task_t1 = Task::create( "t1" );
+ suite_ptr suite = Suite::create( "suite" );
+ Defs theDefs; {
+ suite->addVariable( Variable( Str::ECF_INCLUDE(), "$ECF_HOME/includes" ) );
+ suite->addVariable( Variable( "SLEEPTIME", "1" ) );
+ suite->addVariable( Variable( "ECF_CLIENT_EXE_PATH", "a/made/up/path" ) );
+ suite->addTask( task_t1 );
+ theDefs.addSuite( suite );
+ }
+
+ // Override ECF_HOME. ECF_HOME is as default location for .ecf files, when ECF_INCLUDE not specified
+ // or when file does not exist in ECF_INCLUDE
+ theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(),ecf_home);
+
+ /// begin , will cause creation of generated variables. The generated variables
+ /// are use in client scripts and used to locate the sms files
+ theDefs.beginAll();
+
+ // generate the ecf file;
+ string header = "%include <head.h>\n\n";
+ string body = "%include <common.h>\n\n";
+ string tail = "%include <tail.h>\n# ===================================";
+ string ecf_file = header;
+ ecf_file += body;
+ ecf_file += tail;
+
+ string ecf_file_location = ecf_home + task_t1->absNodePath() + File::ECF_EXTN();
+ // cout << "file_location = " << ecf_file_location << "\n";
+ BOOST_CHECK_MESSAGE(File::createMissingDirectories(ecf_file_location),"Could not create missing dir\n");
+
+ string errormsg;
+ BOOST_CHECK_MESSAGE(File::create(ecf_file_location, ecf_file, errormsg), errormsg);
+ BOOST_CHECK_MESSAGE(fs::exists(ecf_file_location), "Expected File " << ecf_file_location << " to exist");
+
+ // Create the generated variables
+ task_t1->update_generated_variables();
+
+ /// Now finally the test
+ EcfFile ecfFile(task_t1.get(),ecf_file_location);
+
+ /// Check generation of '.usr' and job files
+ string job_file_location = ecf_home + task_t1->absNodePath() + File::JOB_EXTN() + task_t1->tryNo();
+ JobsParam jobsParam(true); // spawn_jobs = false
+ try { ecfFile.create_job(jobsParam); }
+ catch ( std::exception& e) { BOOST_CHECK_MESSAGE(false,"Expected job creation to succeed " << e.what());}
+ BOOST_CHECK_MESSAGE(fs::exists(job_file_location), "Expected File " << job_file_location << " to exist");
+
+ // Open the job file/
+ std::string job_file_contents;
+ BOOST_CHECK_MESSAGE(File::open(job_file_location,job_file_contents),"Could not open job file " << job_file_location);
+
+ /// Remove all the generated files
+ boost::filesystem::remove_all( ecf_home + suite->absNodePath() );
+}
+
+
+BOOST_AUTO_TEST_CASE( test_ecf_include_multi_paths_ECFLOW_261 )
+{
+ // The specific files are specified in ECF_INCLUDE with multiple paths
+ cout << "ANode:: ...test_ecf_include_multi_paths_ECFLOW_261";
+
+ // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode.
+ if (getenv("ECFLOW_CRAY_BATCH")) {
+ cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n";
+ return;
+ }
+ cout << "\n";
+
+ // SET ECF_HOME
+ std::string ecf_home = File::test_data("ANode/test/data","ANode");
+
+ // Create the defs file corresponding to the text below
+ //suite suite
+ // edit ECF_INCLUDE "$ECF_HOME/empty_include1:$ECF_HOME/empty_include2:$ECF_HOME/includes:$ECF_HOME/includes2"
+ // task t1
+ //endsuite
+
+ // Create a defs file, where the task name mirrors the ecf files in the given directory
+ task_ptr task_t1 = Task::create( "t1" );
+ suite_ptr suite = Suite::create( "suite" );
+ Defs theDefs; {
+ suite->addVariable( Variable( Str::ECF_INCLUDE(), "$ECF_HOME/empty_include1:$ECF_HOME/empty_include2:$ECF_HOME/includes:$ECF_HOME/includes2" ) );
+ suite->addTask( task_t1 );
+ theDefs.addSuite( suite );
+ }
+
+ // Override ECF_HOME. ECF_HOME is as default location for .ecf files, when ECF_INCLUDE not specified
+ // or when file does not exist in ECF_INCLUDE
+ theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(),ecf_home);
+
+ /// begin , will cause creation of generated variables. The generated variables
+ /// are use in client scripts and used to locate the sms files
+ theDefs.beginAll();
+
+ // generate the ecf file;
+ string header = "%include <head.h>\n\n";
+ string body = "%include <fred.h>\n\n"; // this is only defined in ANode/test/data/includes2
+ string tail = "%include <tail.h>\n# ===================================";
+ string ecf_file = header;
+ ecf_file += body;
+ ecf_file += tail;
+
+ string ecf_file_location = ecf_home + task_t1->absNodePath() + File::ECF_EXTN();
+ // cout << "file_location = " << ecf_file_location << "\n";
+ BOOST_CHECK_MESSAGE(File::createMissingDirectories(ecf_file_location),"Could not create missing dir\n");
+
+ string errormsg;
+ BOOST_CHECK_MESSAGE(File::create(ecf_file_location, ecf_file, errormsg), errormsg);
+ BOOST_CHECK_MESSAGE(fs::exists(ecf_file_location), "Expected File " << ecf_file_location << " to exist");
+
+ // Create the generated variables
+ task_t1->update_generated_variables();
+
+ /// Now finally the test
+ EcfFile ecfFile(task_t1.get(),ecf_file_location);
+
+ /// Check generation of job files
+ string job_file_location = ecf_home + task_t1->absNodePath() + File::JOB_EXTN() + task_t1->tryNo();
+ JobsParam jobsParam(true); // spawn_jobs = false
+ try { ecfFile.create_job(jobsParam); }
+ catch ( std::exception& e) { BOOST_CHECK_MESSAGE(false,"Expected job creation to succeed " << e.what());}
+ BOOST_CHECK_MESSAGE(fs::exists(job_file_location), "Expected File " << job_file_location << " to exist");
+
+ // Open the job file
+ std::string job_file_contents;
+ BOOST_CHECK_MESSAGE(File::open(job_file_location,job_file_contents),"Could not open job file " << job_file_location);
+
+ /// Remove all the generated files
+ boost::filesystem::remove_all( ecf_home + suite->absNodePath() );
+}
+
+
+BOOST_AUTO_TEST_CASE( test_ecf_include_ECFLOW_274 )
+{
+ // Test .ecf scripts with includes like %include "../bill.h"
+ // In this case we expect to find bill.h in the same directory as the script
+ cout << "ANode:: ...test_ecf_include_ECFLOW_274";
+
+ // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode.
+ if (getenv("ECFLOW_CRAY_BATCH")) {
+ cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n";
+ return;
+ }
+ cout << "\n";
+
+ // SET ECF_HOME
+ std::string ecf_home = File::test_data("ANode/test/data","ANode");
+
+ // Create the defs file corresponding to the text below
+ //suite suite
+ // edit ECF_INCLUDE "$ECF_HOME/includes"
+ // task t1
+ //endsuite
+
+ // Create a defs file, where the task name mirrors the ecf files in the given directory
+ task_ptr task_t1 = Task::create( "t1" );
+ suite_ptr suite = Suite::create( "suite" );
+ Defs theDefs; {
+ suite->addVariable( Variable( Str::ECF_INCLUDE(), "$ECF_HOME/includes" ) );
+ suite->addTask( task_t1 );
+ theDefs.addSuite( suite );
+ }
+
+ // Override ECF_HOME. ECF_HOME is as default location for .ecf files, when ECF_INCLUDE not specified
+ // or when file does not exist in ECF_INCLUDE
+ theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(),ecf_home);
+
+ /// begin , will cause creation of generated variables. The generated variables
+ /// are use in client scripts and used to locate the sms files
+ theDefs.beginAll();
+
+ // generate the ecf file;
+ string header = "%include <head.h>\n\n";
+ string body = "%include \"./t1.h\"\n\n";
+ string tail = "%include <tail.h>\n# ===================================";
+ string ecf_file = header;
+ ecf_file += body;
+ ecf_file += tail;
+
+ string ecf_file_location = ecf_home + task_t1->absNodePath() + File::ECF_EXTN();
+// cout << "file_location = " << ecf_file_location << "\n";
+ BOOST_CHECK_MESSAGE(File::createMissingDirectories(ecf_file_location),"Could not create missing dir\n");
+
+ string errormsg;
+ BOOST_CHECK_MESSAGE(File::create(ecf_file_location, ecf_file, errormsg), errormsg);
+ BOOST_CHECK_MESSAGE(fs::exists(ecf_file_location), "Expected File " << ecf_file_location << " to exist");
+
+
+ // generate bill.h
+ string header_file = "# in t1.h";
+ string header_file_location = ecf_home + task_t1->absNodePath() + ".h";
+// cout << "file_location = " << header_file_location << "\n";
+ BOOST_CHECK_MESSAGE(File::create(header_file_location, header_file, errormsg), errormsg);
+ BOOST_CHECK_MESSAGE(fs::exists(header_file_location), "Expected File " << header_file_location << " to exist");
+
+
+ // Create the generated variables
+ task_t1->update_generated_variables();
+
+ /// Now finally the test
+ EcfFile ecfFile(task_t1.get(),ecf_file_location);
+
+ /// Check generation of job files
+ string job_file_location = ecf_home + task_t1->absNodePath() + File::JOB_EXTN() + task_t1->tryNo();
+ JobsParam jobsParam(true); // spawn_jobs = false
+ try { ecfFile.create_job(jobsParam); }
+ catch ( std::exception& e) { BOOST_CHECK_MESSAGE(false,"Expected job creation to succeed " << e.what());}
+ BOOST_CHECK_MESSAGE(fs::exists(job_file_location), "Expected File " << job_file_location << " to exist");
+
+ // Open the job file
+ std::string job_file_contents;
+ BOOST_CHECK_MESSAGE(File::open(job_file_location,job_file_contents),"Could not open job file " << job_file_location);
+
+ /// Remove all the generated files
+ boost::filesystem::remove_all( ecf_home + suite->absNodePath() );
+}
+
+
+BOOST_AUTO_TEST_CASE( test_ecf_simple_used_variables )
+{
+ // Test that used variables are as expected
+ // This should PRUNE the generated variables from the used variables list
+ // Additionally it should NOT affect variables like ESUITE but should ignore generated variable SUITE
+ // See File: ANode/test/data/includes/used_variables.h
+ cout << "ANode:: ...test_ecf_simple_used_variables";
+
+ // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode.
+ if (getenv("ECFLOW_CRAY_BATCH")) {
+ cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n";
+ return;
+ }
+ cout << "\n";
+
+
+ // Create the defs file corresponding to the text below
+ //suite suite
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // task t1
+ //endsuite
+
+ // Create a defs file, where the task name mirrors the ecf files in the given directory
+ task_ptr task_t1;
+ suite_ptr suite;
+ Defs theDefs; {
+ suite = theDefs.add_suite("suite");
+ suite->addVariable( Variable( Str::ECF_INCLUDE(), "$ECF_HOME/includes" ) );
+ suite->add_variable("ESUITE","suite");
+ task_t1 = suite->add_family("f1")->add_task( "t1" );
+ }
+
+ // Override ECF_HOME. ECF_HOME is as default location for .ecf files, when ECF_INCLUDE not specified
+ // or when file does not exist in ECF_INCLUDE
+ std::string ecf_home = File::test_data("ANode/test/data","ANode");
+ theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(),ecf_home);
+
+ /// begin , will cause creation of generated variables. The generated variables
+ /// are use in client scripts and used to locate the sms files
+ theDefs.beginAll();
+
+ // generate the ecf file;
+ string ecf_file = "%include <used_variables.h>\n";
+ string ecf_file_location = ecf_home + task_t1->absNodePath() + File::ECF_EXTN();
+ // cout << "file_location = " << ecf_file_location << "\n";
+ BOOST_CHECK_MESSAGE(File::createMissingDirectories(ecf_file_location),"Could not create missing dir\n");
+
+ string errormsg;
+ BOOST_CHECK_MESSAGE(File::create(ecf_file_location, ecf_file, errormsg), errormsg);
+ BOOST_CHECK_MESSAGE(fs::exists(ecf_file_location), "Expected File " << ecf_file_location << " to exist");
+
+ // Create the generated variables
+ task_t1->update_generated_variables();
+
+ /// Now finally the test
+ EcfFile ecfFile(task_t1.get(),ecf_file_location);
+
+ string file_with_used_variables;
+ ecfFile.edit_used_variables(file_with_used_variables);
+ string expected_used_variables = "%comment - ecf user variables\nESUITE = suite\n%end - ecf user variables\n%include <used_variables.h>\n";
+ BOOST_CHECK_MESSAGE(file_with_used_variables==expected_used_variables,"Expected\n" << expected_used_variables << "\nBut found:\n" << file_with_used_variables);
+
+ /// Remove all the generated files
+ boost::filesystem::remove_all( ecf_home + suite->absNodePath() );
+}
+
+BOOST_AUTO_TEST_CASE( test_ecf_simple_used_variables_with_comments )
+{
+ // Test that used variables are as expected
+ // This should PRUNE the generated variables from the used variables list
+ // Additionally it should NOT affect variables like ETASK but should ignore generated variable TASK
+ // See File: ANode/test/data/includes/used_variables_with_comments.h
+ //
+ // This WILL test that when we have user comment and manuals, we can still extract user variables
+ // Those variable defined within comments and manuals that are not defined should be ignored
+ cout << "ANode:: ...test_ecf_simple_used_variables_with_comments";
+
+ // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode.
+ if (getenv("ECFLOW_CRAY_BATCH")) {
+ cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n";
+ return;
+ }
+ cout << "\n";
+
+ // SET ECF_HOME
+ std::string ecf_home = File::test_data("ANode/test/data","ANode");
+
+ // Create the defs file corresponding to the text below
+ //suite suite
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // task t1
+ //endsuite
+
+ // Create a defs file, where the task name mirrors the ecf files in the given directory
+ task_ptr task_t1;
+ suite_ptr suite;
+ Defs theDefs; {
+ suite = theDefs.add_suite("suite");
+ suite->addVariable( Variable( Str::ECF_INCLUDE(), "$ECF_HOME/includes" ) );
+ suite->add_variable("ETASK","suite");
+ suite->add_variable("FRED","fred");
+ task_t1 = suite->add_family("f1")->add_task( "t1" );
+ }
+
+ // Override ECF_HOME. ECF_HOME is as default location for .ecf files, when ECF_INCLUDE not specified
+ // or when file does not exist in ECF_INCLUDE
+ theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(),ecf_home);
+
+ /// begin , will cause creation of generated variables. The generated variables
+ /// are use in client scripts and used to locate the sms files
+ theDefs.beginAll();
+
+ // generate the ecf file;
+ string ecf_file = "%include <used_variables_with_comments.h>\n";
+ string ecf_file_location = ecf_home + task_t1->absNodePath() + File::ECF_EXTN();
+ // cout << "file_location = " << ecf_file_location << "\n";
+ BOOST_CHECK_MESSAGE(File::createMissingDirectories(ecf_file_location),"Could not create missing dir\n");
+
+ string errormsg;
+ BOOST_CHECK_MESSAGE(File::create(ecf_file_location, ecf_file, errormsg), errormsg);
+ BOOST_CHECK_MESSAGE(fs::exists(ecf_file_location), "Expected File " << ecf_file_location << " to exist");
+
+ // Create the generated variables
+ task_t1->update_generated_variables();
+
+ /// Now finally the test
+ EcfFile ecfFile(task_t1.get(),ecf_file_location);
+
+ string file_with_used_variables;
+ ecfFile.edit_used_variables(file_with_used_variables);
+ string expected_used_variables = "%comment - ecf user variables\nETASK = suite\nFRED = fred\n%end - ecf user variables\n%include <used_variables_with_comments.h>\n";
+ BOOST_CHECK_MESSAGE(file_with_used_variables==expected_used_variables,"Expected\n" << expected_used_variables << "\nBut found:\n" << file_with_used_variables);
+
+ /// Remove all the generated files
+ boost::filesystem::remove_all( ecf_home + suite->absNodePath() );
+}
+
+
+BOOST_AUTO_TEST_CASE( test_ecf_simple_used_variables_errors )
+{
+ // Test that used variables are as expected
+ // This is similar to test_ecf_simple_used_variables_with_comments
+ // BUT we DO NOT define variable FRED, hence we expect failure
+ cout << "ANode:: ...test_ecf_simple_used_variables_errors";
+
+ // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode.
+ if (getenv("ECFLOW_CRAY_BATCH")) {
+ cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n";
+ return;
+ }
+ cout << "\n";
+
+
+ // SET ECF_HOME
+ std::string ecf_home = File::test_data("ANode/test/data","ANode");
+
+ // Create the defs file corresponding to the text below
+ //suite suite
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // task t1
+ //endsuite
+
+ // Create a defs file, where the task name mirrors the ecf files in the given directory
+ task_ptr task_t1;
+ suite_ptr suite;
+ Defs theDefs; {
+ suite = theDefs.add_suite("suite");
+ suite->addVariable( Variable( Str::ECF_INCLUDE(), "$ECF_HOME/includes" ) );
+ suite->add_variable("ETASK","suite");
+ task_t1 = suite->add_family("f1")->add_task( "t1" );
+ }
+
+ // Override ECF_HOME. ECF_HOME is as default location for .ecf files, when ECF_INCLUDE not specified
+ // or when file does not exist in ECF_INCLUDE
+ theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(),ecf_home);
+
+ /// begin , will cause creation of generated variables. The generated variables
+ /// are use in client scripts and used to locate the sms files
+ theDefs.beginAll();
+
+ // generate the ecf file;
+ string ecf_file = "%include <used_variables_with_comments.h>\n";
+ string ecf_file_location = ecf_home + task_t1->absNodePath() + File::ECF_EXTN();
+ // cout << "file_location = " << ecf_file_location << "\n";
+ BOOST_CHECK_MESSAGE(File::createMissingDirectories(ecf_file_location),"Could not create missing dir\n");
+
+ string errormsg;
+ BOOST_CHECK_MESSAGE(File::create(ecf_file_location, ecf_file, errormsg), errormsg);
+ BOOST_CHECK_MESSAGE(fs::exists(ecf_file_location), "Expected File " << ecf_file_location << " to exist");
+
+ // Create the generated variables
+ task_t1->update_generated_variables();
+
+ /// Now finally the test
+ EcfFile ecfFile(task_t1.get(),ecf_file_location);
+
+ // Expect a throw since %FRED% is not defined, on the suite, but exists in used_variables_with_comments.h
+ string file_with_used_variables;
+ BOOST_REQUIRE_THROW(ecfFile.edit_used_variables(file_with_used_variables),std::runtime_error);
+
+ /// Remove all the generated files
+ boost::filesystem::remove_all( ecf_home + suite->absNodePath() );
+}
+
+
+BOOST_AUTO_TEST_CASE( test_ecf_file )
+{
+ cout << "ANode:: ...test_ecf_file";
+
+ // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode.
+ if (getenv("ECFLOW_CRAY_BATCH")) {
+ cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n";
+ return;
+ }
+ cout << "\n";
+
+ // SET ECF_HOME
+ std::string ecf_home = File::test_data("ANode/test/data","ANode");
+
+ // Create the defs file corresponding to the text below
+ //# Test the sms file can be found via ECF_SCRIPT
+ //# Note: we have to use relative paths, since these tests are relocatable
+ //#
+ //suite suite
+ // edit SLEEPTIME 10
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // task t1
+ //endsuite
+
+ NameValueMap expected_used_variables;
+ expected_used_variables.insert( std::make_pair(string("VAR1"),string("_val1_")) );
+ expected_used_variables.insert( std::make_pair(string("VAR2"),string("_val2_")) );
+ expected_used_variables.insert( std::make_pair(string("VAR2_fred"),string("<ignored>")) );
+
+ // Create a defs file, where the task name mirrors the sms files in the given directory
+ task_ptr task_t1 = Task::create( "t1" );
+ suite_ptr suite = Suite::create( "suite" );
+ std::pair<std::string,std::string> p;
+ Defs theDefs; {
+ suite->addVariable( Variable( Str::ECF_INCLUDE(), "$ECF_HOME/includes" ) );
+ suite->addVariable( Variable( "SLEEPTIME", "1" ) );
+ suite->addVariable( Variable( "ECF_CLIENT_EXE_PATH", "a/made/up/path" ) );
+ BOOST_FOREACH(p,expected_used_variables) { task_t1->addVariable( Variable( p.first, p.second) );}
+ suite->addTask( task_t1 );
+ theDefs.addSuite( suite );
+ }
+
+
+ // Override ECF_HOME. ECF_HOME is need to locate to the .ecf files
+ theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(),ecf_home);
+
+ /// begin , will cause creation of generated variables. The generated variables
+ /// are use in client scripts and used to locate the sms files
+ theDefs.beginAll();
+
+ // generate the ecf file;
+ string header = "%include <head.h>\n\n";
+ string manual_head = "%manual\n";
+ string manual_body = " manual. The contents of the manual\n";
+ manual_body += " end.\n";
+ string manual_tail = "%end\n\n";
+ string comment_head = "%comment\n";
+ string comment_body = " comment. The contents of the comment\n";
+ comment_body += " end.\n";
+ string comment_tail ="%end\n\n";
+ string ecf_body; {
+ std::pair<std::string,std::string> p;
+ BOOST_FOREACH(p,expected_used_variables) { ecf_body += Ecf::MICRO() + p.first + Ecf::MICRO() + "\n";}
+ ecf_body +="%VAR3:substitute_var%\n";
+ }
+ string tail = "\n%include <tail.h>\n# ===================================";
+
+ string ecf_file = header;
+ ecf_file += manual_head;
+ ecf_file += manual_body;
+ ecf_file += manual_tail;
+ ecf_file += comment_head;
+ ecf_file += comment_body;
+ ecf_file += comment_tail;
+ ecf_file += ecf_body;
+ ecf_file += tail;
+
+ string ecf_file_location = ecf_home + task_t1->absNodePath() + File::ECF_EXTN();
+ // cout << "file_location = " << ecf_file_location << "\n";
+ BOOST_CHECK_MESSAGE(File::createMissingDirectories(ecf_file_location),"Could not create missing dir\n");
+
+ string errormsg;
+ BOOST_CHECK_MESSAGE(File::create(ecf_file_location, ecf_file, errormsg), errormsg);
+ BOOST_CHECK_MESSAGE(fs::exists(ecf_file_location), "Expected File " << ecf_file_location << " to exist");
+
+ // Create the generated variables
+ task_t1->update_generated_variables();
+
+ /// Now finally the test
+ EcfFile ecfFile(task_t1.get(),ecf_file_location);
+
+ /// Test manual extraction
+ /// The manual is manual of all the pre-processed includes
+ /// Test: SUP-762 Lines starting with "manually" are not shown in manual
+ std::string expected_manual = "#This is the manual from the head.h file\n manual. The contents of the manual\n end.\n#This is the manual from the tail.h file\n";
+
+ string theExtractedManual;
+ try { ecfFile.manual(theExtractedManual); }
+ catch (std::exception &e) { BOOST_CHECK_MESSAGE(false,e.what()); }
+ BOOST_CHECK_MESSAGE( theExtractedManual == expected_manual, "Expected \n'" << expected_manual << "' but found \n'" << theExtractedManual << "'");
+
+
+ /// Test script extraction
+ string theExtractedScript;
+ try { ecfFile.script(theExtractedScript); }
+ catch (std::exception &e) { BOOST_CHECK_MESSAGE(false,e.what()); }
+ BOOST_CHECK_MESSAGE( theExtractedScript == ecf_file, "\nExpected\n" << ecf_file
+ << "\nsize = " << ecf_file.size() << " but found-----------------\n"
+ << theExtractedScript << "\nsize = " << theExtractedScript.size() );
+
+
+ /// Test User edit script, this should return all the used variables, between %comment -%end
+ string file_with_used_variables;
+ ecfFile.edit_used_variables(file_with_used_variables);
+ // std::cout << "file_with_used_variables:----------------------------------------------------------------\n" << file_with_used_variables << "\n";
+ BOOST_CHECK_MESSAGE(file_with_used_variables.find("%comment") == 0, "Expected to find variable %comment on the very first line: but found at: " << file_with_used_variables.find("%comment"));
+ BOOST_FOREACH(p,expected_used_variables) {
+ BOOST_CHECK_MESSAGE(file_with_used_variables.find(p.first) != string::npos, "Expected to find variable" << p.first);
+ }
+
+ /// Test extraction of all the used variables
+ std::vector<string> script_lines;
+ Str::split(file_with_used_variables,script_lines,"\n"); // will ignore empty lines, but will do for this case
+ NameValueMap extracted_used_variables;
+ EcfFile::extract_used_variables( extracted_used_variables, script_lines );
+ BOOST_FOREACH(p,expected_used_variables) {
+ BOOST_CHECK_MESSAGE( extracted_used_variables.find(p.first) != extracted_used_variables.end()," expected to find variable " << p.first << " in the extracted variables\n");
+ }
+ // cout << "Expected:----\n"; BOOST_FOREACH(p,expected_used_variables) { cout << p.first << " " << p.second << "\n";}
+ // cout << "Actual:------\n"; BOOST_FOREACH(p,extracted_used_variables) { cout << p.first << " " << p.second << "\n";}
+
+
+ /// Test pre-processing
+ string pre_processed_file;
+ ecfFile.pre_process(pre_processed_file);
+ // cout << "pre_processed_file\n" << pre_processed_file << "\n";
+ BOOST_CHECK_MESSAGE(!pre_processed_file.empty(),"Expected file not to be empty");
+ BOOST_CHECK_MESSAGE(pre_processed_file.find("%include") == string::npos,"Expected all includes to be removed");
+
+ /// Check generation of '.usr' and job files
+ string man_file_location = ecf_home + task_t1->absNodePath() + File::MAN_EXTN();
+ string usr_file_location = ecf_home + task_t1->absNodePath() + File::USR_EXTN();
+ string job_file_location = ecf_home + task_t1->absNodePath() + File::JOB_EXTN() + task_t1->tryNo();
+ JobsParam jobsParam(true); // spawn_jobs = false
+ jobsParam.set_user_edit_variables( extracted_used_variables );
+ jobsParam.set_user_edit_file( script_lines );
+ try { ecfFile.create_job(jobsParam); }
+ catch ( std::exception& e) { BOOST_CHECK_MESSAGE(false,"Expected job creation to succeed " << e.what());}
+ BOOST_CHECK_MESSAGE(fs::exists(usr_file_location), "Expected File " << usr_file_location << " to exist");
+ BOOST_CHECK_MESSAGE(fs::exists(job_file_location), "Expected File " << job_file_location << " to exist");
+
+ // Open the job file/
+ std::string job_file_contents;
+ BOOST_CHECK_MESSAGE(File::open(job_file_location,job_file_contents),"Could not open job file " << job_file_location);
+
+ // Test the contents of the job file.
+// cout << "\n" << job_file_contents << "\n";
+ BOOST_CHECK_MESSAGE(job_file_contents.find("%ECF_PORT%") == string::npos,"Expected variables to be substituted:");
+ BOOST_CHECK_MESSAGE(job_file_contents.find("%ECF_NODE%") == string::npos,"Expected variables to be substituted:");
+ BOOST_CHECK_MESSAGE(job_file_contents.find("%ECF_NAME%") == string::npos,"Expected variables to be substituted:");
+ BOOST_CHECK_MESSAGE(job_file_contents.find("%ECF_PASS%") == string::npos,"Expected variables to be substituted");
+ BOOST_CHECK_MESSAGE(job_file_contents.find("%ECF_TRYNO%") == string::npos,"Expected variables to be substituted");
+ BOOST_CHECK_MESSAGE(job_file_contents.find("%include") == string::npos,"Expected all includes to be expanded");
+ BOOST_CHECK_MESSAGE(job_file_contents.find("%manual") == string::npos,"%manual should have been removed");
+ BOOST_CHECK_MESSAGE(job_file_contents.find("%comment") == string::npos,"%comment should have been removed:");
+ BOOST_CHECK_MESSAGE(job_file_contents.find("%end") == string::npos,"%end should have been removed:");
+ BOOST_CHECK_MESSAGE(job_file_contents.find("%ecfmicro") == string::npos,"%ecfmicro should have been removed:");
+
+
+ /// Remove all the generated files
+ boost::filesystem::remove( man_file_location );
+ boost::filesystem::remove( ecf_file_location );
+ boost::filesystem::remove( usr_file_location );
+ boost::filesystem::remove( job_file_location );
+ boost::filesystem::remove( ecf_home + suite->absNodePath() );
+}
+
+
+BOOST_AUTO_TEST_CASE( test_ecf_file_includenoop )
+{
+ cout << "ANode:: ...test_ecf_file_includenopp";
+
+ // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode.
+ if (getenv("ECFLOW_CRAY_BATCH")) {
+ cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n";
+ return;
+ }
+ cout << "\n";
+
+
+ // This test is used to check that %includenopp are expanded only.
+ // There should be NO variable substitution, or removal of comments/manual
+
+ // SET ECF_HOME
+ std::string ecf_home = File::test_data("ANode/test/data","ANode");
+
+ // Create a defs file, where the task name mirrors the ecf files in the given directory
+ task_ptr task_t1 = Task::create( "t1" );
+ suite_ptr suite = Suite::create( "suite_test_ecf_file_includenopp" );
+ Defs theDefs; {
+ suite->addVariable( Variable( Str::ECF_INCLUDE(), "$ECF_HOME/includes" ) );
+ suite->addVariable( Variable( "SLEEPTIME", "1" ) );
+ suite->addVariable( Variable( "ECF_CLIENT_EXE_PATH", "a/made/up/path" ) );
+ suite->addTask( task_t1 );
+ theDefs.addSuite( suite );
+ }
+ //cout << theDefs << "\n";
+
+ // Override ECF_HOME. ECF_HOME is need to locate to the .ecf files
+ theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(),ecf_home);
+
+ /// begin , will cause creation of generated variables. The generated variables
+ /// are use in client scripts and used to locate the ecf files
+ theDefs.beginAll();
+
+ // generate the ecf file;
+ string header = "%includenopp <head.h>\n";
+ string tail = "%includenopp <tail.h>";
+ string ecf_file = header;
+ ecf_file += tail;
+
+ string ecf_file_location = ecf_home + task_t1->absNodePath() + File::ECF_EXTN();
+ BOOST_CHECK_MESSAGE(File::createMissingDirectories(ecf_file_location),"Could not create missing dir " << ecf_file_location << "\n");
+
+ string errormsg;
+ BOOST_CHECK_MESSAGE(File::create(ecf_file_location, ecf_file, errormsg), errormsg);
+ BOOST_CHECK_MESSAGE(fs::exists(ecf_file_location), "Expected File " << ecf_file_location << " to exist");
+
+ // Create the generated variables. Then EcfFile
+ task_t1->update_generated_variables();
+ EcfFile ecfFile(task_t1.get(),ecf_file_location);
+
+ /// Check generation of job files
+ string man_file_location = ecf_home + task_t1->absNodePath() + File::MAN_EXTN();
+ string job_file_location = ecf_home + task_t1->absNodePath() + File::JOB_EXTN() + task_t1->tryNo();
+ JobsParam jobsParam(true); // spawn_jobs = false
+ try { ecfFile.create_job(jobsParam); }
+ catch ( std::exception& e) { BOOST_CHECK_MESSAGE(false,"Expected job creation to succeed " << e.what());}
+
+ // Open the job file and check the contents
+ BOOST_CHECK_MESSAGE(fs::exists(job_file_location), "Expected job File " << job_file_location << " to exist");
+ std::string job_file_contents;
+ BOOST_CHECK_MESSAGE(File::open(job_file_location,job_file_contents),"Could not open job file " << job_file_location);
+
+ // Test the contents of the job file. We expect includenopp to be expanded
+ // The contents should be left as is: i.e no pre_processing,hence expect to find %manual %comment, %VARIABLES%
+ //cout << "\n" << job_file_contents << "\n";
+ BOOST_CHECK_MESSAGE(job_file_contents.find("%includenopp") == string::npos,"Expected all includes to be removed");
+ BOOST_CHECK_MESSAGE(job_file_contents.find("%ECF_PORT%") != string::npos,"Expected variables as is:");
+ BOOST_CHECK_MESSAGE(job_file_contents.find("%ECF_NODE%") != string::npos,"Expected variables as is:");
+ BOOST_CHECK_MESSAGE(job_file_contents.find("%ECF_NAME%") != string::npos,"Expected variables as is:");
+ BOOST_CHECK_MESSAGE(job_file_contents.find("%ECF_PASS%") != string::npos,"Expected variables as is:");
+ BOOST_CHECK_MESSAGE(job_file_contents.find("%ECF_TRYNO%") != string::npos,"Expected variables as is:");
+ BOOST_CHECK_MESSAGE(job_file_contents.find("%manual") != string::npos,"%manual should exist inside %nopp/%end pair:");
+ BOOST_CHECK_MESSAGE(job_file_contents.find("%comment") != string::npos,"%comment should exist inside %nopp/%end pair:");
+ BOOST_CHECK_MESSAGE(job_file_contents.find("%end") != string::npos,"%end associated with comment and manual should exist:");
+
+
+ // Remove all the generated files
+ boost::filesystem::remove( ecf_file_location );
+ boost::filesystem::remove( man_file_location );
+ boost::filesystem::remove( job_file_location );
+ boost::filesystem::remove( ecf_home + suite->absNodePath() );
+}
+
+
+BOOST_AUTO_TEST_CASE( test_ecf_file_override_ECF_JOB )
+{
+ cout << "ANode:: ...test_ecf_file_override_ECF_JOB";
+
+ // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode.
+ if (getenv("ECFLOW_CRAY_BATCH")) {
+ cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n";
+ return;
+ }
+ cout << "\n";
+
+ // This test is used to check that when user has added a variable ECF_JOB
+ // to specify the location of the job file, we use that, in preference
+ // to generated ECF_JOB for the location of the job file.
+ // Note: The directories to the job file should be created by EcfFile
+
+ // SET ECF_HOME
+ std::string ecf_home = File::test_data("ANode/test/data","ANode");
+ std::string job_file_location = ecf_home + "/a/made/up/path/t1.job";
+
+ // Create a defs file, where the task name mirrors the ecf files in the given directory
+ task_ptr task_t1 = Task::create( "t1" );
+ task_t1->addVariable( Variable( "ECF_JOB", job_file_location ) );
+ suite_ptr suite = Suite::create( "test_ecf_file_override_ECF_JOB" );
+ Defs theDefs; {
+ suite->addVariable( Variable( Str::ECF_INCLUDE(), "$ECF_HOME/includes" ) );
+ suite->addVariable( Variable( "SLEEPTIME", "1" ) );
+ suite->addVariable( Variable( "ECF_CLIENT_EXE_PATH", "a/made/up/path" ) );
+ suite->addTask( task_t1 );
+ theDefs.addSuite( suite );
+ }
+ //cout << theDefs << "\n";
+
+ // Override ECF_HOME. ECF_HOME is need to locate to the .ecf files
+ theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(),ecf_home);
+
+ /// begin , will cause creation of generated variables. The generated variables
+ /// are use in client scripts and used to locate the ecf files
+ theDefs.beginAll();
+
+ // generate the dummy ecf file;
+ string header = "%include <head.h>\n";
+ string tail = "%include <tail.h>";
+ string ecf_file = header;
+ ecf_file += "# ";
+ ecf_file += tail;
+
+ string ecf_file_location = ecf_home + task_t1->absNodePath() + File::ECF_EXTN();
+ BOOST_CHECK_MESSAGE(File::createMissingDirectories(ecf_file_location),"Could not create missing dir " << ecf_file_location << "\n");
+
+ string errormsg;
+ BOOST_CHECK_MESSAGE(File::create(ecf_file_location, ecf_file, errormsg), errormsg);
+ BOOST_CHECK_MESSAGE(fs::exists(ecf_file_location), "Expected File " << ecf_file_location << " to exist");
+
+ // Create the generated variables. Then EcfFile
+ task_t1->update_generated_variables();
+ EcfFile ecfFile(task_t1.get(),ecf_file_location);
+
+ /// Check generation of job files
+ JobsParam jobsParam(true); // spawn_jobs = false
+ try { ecfFile.create_job(jobsParam); }
+ catch ( std::exception& e) { BOOST_CHECK_MESSAGE(false,"Expected job creation to succeed " << e.what());}
+
+ // Open the job file and check the contents
+ BOOST_CHECK_MESSAGE(fs::exists(job_file_location), "Expected job File " << job_file_location << " to exist");
+ std::string job_file_contents;
+ BOOST_CHECK_MESSAGE(File::open(job_file_location,job_file_contents),"Could not open job file " << job_file_location);
+ BOOST_CHECK_MESSAGE( !job_file_contents.empty(),"Job should not be empty");
+
+ // Remove all the generated files
+ boost::filesystem::remove_all( ecf_home + suite->absNodePath() );
+ boost::filesystem::remove_all( ecf_home + "/a" );
+
+ /// Destroy System singleton to avoid valgrind from complaining
+ System::destroy();
+}
+
+BOOST_AUTO_TEST_CASE( test_manual_files )
+{
+ // The specific files are specified in ECF_INCLUDE and common files are specified in ECF_HOME.
+ cout << "ANode:: ...test_manual_files\n";
+
+ // SET ECF_HOME
+ std::string ecf_home = File::test_data("ANode/test/data/SMSHOME","ANode");
+
+
+ // Create the defs file corresponding to the text below
+ //suite suite
+ // edit SLEEPTIME 10
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // family
+ // task t1
+ //endsuite
+
+ // Create a defs file, where the task name mirrors the ecf files in the given directory
+ Defs theDefs;
+ suite_ptr suite = theDefs.add_suite( "suite" );
+ suite->addVariable( Variable( Str::ECF_INCLUDE(), "$ECF_HOME/../includes" ) );
+ family_ptr family = suite->add_family("family");
+ task_ptr task_t1 = family->add_task("t1");
+
+
+ // Override ECF_HOME. ECF_HOME is as default location for .ecf files, when ECF_INCLUDE not specified
+ // or when file does not exist in ECF_INCLUDE
+ theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(),ecf_home);
+
+ /// begin , will cause creation of generated variables. The generated variables
+ /// are use in client scripts and used to locate the sms files
+ theDefs.beginAll();
+
+ // Create the generated variables
+ task_t1->update_generated_variables();
+
+// PrintStyle style(PrintStyle::STATE);
+// std::cout << theDefs << "\n";
+
+ /// Now finally the test
+
+ // Task
+ {
+ std::string manual;
+ EcfFile ecf_file = task_t1->locatedEcfFile(); // will throw std::runtime_error for errors
+ ecf_file.manual(manual); // will throw std::runtime_error for errors
+ BOOST_REQUIRE_MESSAGE(!manual.empty(),"Manual not found");
+ BOOST_CHECK_MESSAGE(manual.find("ECF_MICRO=%") != std::string::npos,"Variable pre-processing failed during manual extraction");
+ BOOST_CHECK_MESSAGE(manual.find("manual-1") != std::string::npos,"Pre-processing of ecfmicro in manuals failed, expected to find string 'manual-1'\n" << manual);
+ BOOST_CHECK_MESSAGE(manual.find("end-1") != std::string::npos,"Pre-processing of ecfmicro in manuals failed, expected to find string 'end-1'\n" << manual);
+ BOOST_CHECK_MESSAGE(manual.find("Test manual files are pre-processed") != std::string::npos,"%include <manual.h> pre-processing failed inside manual->end\n" << manual);
+ }
+
+ {
+ // Family, Check the suite manuals are pre-processed. i.e %includes are expanded
+ // When the node container manual(family or suite) '.man' file, has content but *NO* %manual->%end directives
+ // Just pre-process and return file as is. Since the whole file is a manual.
+ std::string man_file = ecf_home + family->absNodePath() + File::MAN_EXTN();
+ EcfFile ecf_file(family.get(), man_file);
+
+ std::string manual;
+ ecf_file.manual(manual);
+ //cout << manual << "\n";
+ BOOST_CHECK_MESSAGE(!manual.empty(),"Manual not found");
+ BOOST_CHECK_MESSAGE(manual.find("Test manual files are pre-processed") != std::string::npos,"Pre-processing in manual failed");
+ BOOST_CHECK_MESSAGE(manual.find("Special case where there are no manual directives") != std::string::npos,"family manual extraction failed");
+ }
+
+ {
+ // Suite, Check the suite manuals are pre-processed. i.e %includes are expanded
+ std::string man_file = ecf_home + suite->absNodePath() + File::MAN_EXTN();
+ EcfFile ecf_file(suite.get(), man_file);
+
+ std::string manual;
+ ecf_file.manual(manual);
+ // cout << manual << "\n";
+ BOOST_CHECK_MESSAGE(!manual.empty(),"Manual not found");
+ BOOST_CHECK_MESSAGE(manual.find("Test manual files are pre-processed") != std::string::npos,"Pre-processing in manual failed");
+ BOOST_CHECK_MESSAGE(manual.find("suite manual") != std::string::npos,"Suite manual extraction failed");
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ANode/test/TestEnviromentSubstitution.cpp b/ANode/test/TestEnviromentSubstitution.cpp
new file mode 100644
index 0000000..1f1ebaf
--- /dev/null
+++ b/ANode/test/TestEnviromentSubstitution.cpp
@@ -0,0 +1,85 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "Str.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/foreach.hpp>
+#include <string>
+#include <map>
+#include <iostream>
+#include <fstream>
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_environment_substitution )
+{
+ std::cout << "ANode:: ...test_environment_substitution\n";
+
+ Defs defs;
+ Suite* s = NULL;
+ {
+ suite_ptr suite = defs.add_suite( "suite" ); s = suite.get();
+ suite->addVariable(Variable("AVI","avi"));
+
+ std::vector<std::pair<std::string,std::string> > env;
+ env.push_back( std::make_pair(Str::ECF_HOME(), string("/home/smshome")) );
+ env.push_back( std::make_pair(string("FRED"), string("/home/fred")) );
+ env.push_back( std::make_pair(string("BILL"), string("/home/bill")) );
+ env.push_back( std::make_pair(string("JANE"), string("/home/jane")) );
+ defs.set_server().add_or_update_user_variables( env );
+ }
+
+ // See page 31, section 5.1 variable inheritance, of SMS users guide
+ string expected = "/home/smshome";
+ std::string cmd = "$ECF_HOME";
+ BOOST_REQUIRE_MESSAGE(s->variable_dollar_subsitution(cmd)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "$ECF_HOME/include"; expected = "/home/smshome/include";
+ BOOST_REQUIRE_MESSAGE(s->variable_dollar_subsitution(cmd)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "$ECF_HOME$FRED$BILL$JANE"; expected = "/home/smshome/home/fred/home/bill/home/jane";
+ BOOST_REQUIRE_MESSAGE(s->variable_dollar_subsitution(cmd)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+
+ cmd = "$ECF_HOME/$FRED/$BILL/$JANE"; expected = "/home/smshome//home/fred//home/bill//home/jane";
+ BOOST_CHECK_MESSAGE(s->variable_dollar_subsitution(cmd)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%PATH"; expected = "%PATH";
+ BOOST_CHECK_MESSAGE(s->variable_dollar_subsitution(cmd)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "$$"; expected = "$$";
+ BOOST_CHECK_MESSAGE(s->variable_dollar_subsitution(cmd)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "$ERROR$"; expected = "$ERROR$";
+ BOOST_CHECK_MESSAGE(!s->variable_dollar_subsitution(cmd)," substitution expected to fail since ERROR does not exist");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = ""; expected = "";
+ BOOST_CHECK_MESSAGE(s->variable_dollar_subsitution(cmd)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/ANode/test/TestExprParser.cpp b/ANode/test/TestExprParser.cpp
new file mode 100644
index 0000000..a007a16
--- /dev/null
+++ b/ANode/test/TestExprParser.cpp
@@ -0,0 +1,399 @@
+#define BOOST_TEST_MODULE TestNode
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include "ExprParser.hpp"
+#include "ExprAst.hpp"
+#include "Expression.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/foreach.hpp>
+#include <string>
+#include <map>
+#include <iostream>
+#include <fstream>
+using namespace std;
+
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+
+BOOST_AUTO_TEST_CASE( test_expression_parser_basic )
+{
+ std::cout << "ANode:: ...test_expression_parser_basic\n";
+
+ // This must be nicely formatted, i.e. AST is nicely space formatted otherwise it will fail the test
+ // This test ENSURES the the AST matches the expression. (i.e by getting AST to print the expression)
+ // Note: we can use NOT,eq,ne,le,ge, or brackets
+ // we can't use a:event_name ==> a:event_name == set
+ std::vector<std::string> vec;
+ vec.push_back("a == complete");
+ vec.push_back("a != complete");
+ vec.push_back("a:value == 10");
+ vec.push_back("a:value != 10");
+ vec.push_back("a:value >= 10");
+ vec.push_back("a:value <= 10");
+ vec.push_back("a:value > 10");
+ vec.push_back("a:value < 10");
+ vec.push_back("1 == 1");
+ vec.push_back("a:event_name == set");
+ vec.push_back("a:event_name != set");
+ vec.push_back("a:event_name == clear");
+ vec.push_back("a:event_name != clear");
+ vec.push_back("../a/b:eventname == set");
+ vec.push_back("../a/b:eventname == clear");
+ vec.push_back("../a/b:eventname != clear");
+ vec.push_back("../a:event_name >= 10");
+ vec.push_back("a == unknown and b != complete");
+ vec.push_back("a == unknown or b != complete");
+ vec.push_back("a == complete and b == complete or c == complete");
+ vec.push_back("! a == unknown");
+ vec.push_back("/mc/main:YMD <= /mc/main/ref:MC_STOP");
+ vec.push_back("! ../../../prod2diss/operation_is_late:yes == set or ! a == complete");
+ vec.push_back("./a:YMD - ./b:YMD < 5");
+ vec.push_back("./a:YMD + ./b:YMD < 5");
+ vec.push_back("./a:YMD / ./b:YMD < 5");
+ vec.push_back("./a:YMD * ./b:YMD < 5");
+ vec.push_back("./a:YMD % ./b:YMD < 5");
+ vec.push_back("inigroup:YMD == ! 1");
+ vec.push_back("inigroup:YMD == ! 0");
+ vec.push_back("comp == complete and notready == complete"); // ECFLOW-493
+ vec.push_back("comp == complete and not ready == complete");
+ vec.push_back("comp == complete and ! ready == complete"); // we now store the not from the parse, for test comparison
+ vec.push_back("comp == complete and ~ ready == complete");
+
+ for(size_t i = 0; i < vec.size(); i++) {
+
+ PartExpression part(vec[i]);
+ string parseErrorMsg;
+ std::auto_ptr<AstTop> ast = part.parseExpressions( parseErrorMsg );
+ BOOST_REQUIRE_MESSAGE(ast.get(),"Failed to parse\n" << vec[i] << " " << parseErrorMsg);
+
+
+ std::stringstream s2;
+ ast->print_flat(s2);
+ std::string ast_expr = s2.str();
+ BOOST_CHECK_MESSAGE(vec[i]==ast_expr," Failed\n'" << vec[i] << "' != '" << ast_expr << "'" );
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_expression_parser_basic_with_brackets )
+{
+ std::cout << "ANode:: ...test_expression_parser_basic_with_brackets\n";
+
+ // This must be nicely formatted, i.e. AST is nicely space formatted otherwise it will fail the test
+ // This test ENSURES the the AST matches the expression. (i.e by getting AST to print the expression)
+ // Note: we can use NOT,eq,ne,le,ge,
+ // we can't use a:event_name ==> a:event_name == set
+ std::vector<std::string> vec;
+ vec.push_back("((a == complete) and (b == complete))");
+ vec.push_back("(((a == complete) or (b == complete)) and (c == complete))");
+ vec.push_back("((a == complete) and ((b == complete) or (nodepath:eventname == set)))");
+ vec.push_back("((a == complete) and ((b == complete) or ((a == complete) and (b == complete))))");
+ vec.push_back("! ((a == unknown))");
+ vec.push_back("((t:step + 20) >= (t:step1 - 20))");
+ vec.push_back("(((/o/main/12/an/slwet == complete) and ((/o/main/12/an/4dvar/ifstraj:finalwave == set) or (/o/main/12/an/4dvar == complete))) or (/o/main/12/an == complete))");
+ vec.push_back("((obs:YMD <= (main:YMD + 1)) and ((../make/setup == complete) and (obs:YMD <= /o/lag:YMD)))");
+ vec.push_back("(((stage == complete) or (./stage:YMD > ./retrieve:YMD)) and ((./retrieve:YMD - ./load:YMD) < 5))");
+ vec.push_back("((./a:YMD - ./b:YMD) < 5)");
+
+ for(size_t i = 0; i < vec.size(); i++) {
+
+ PartExpression part(vec[i]);
+ string parseErrorMsg;
+ std::auto_ptr<AstTop> ast = part.parseExpressions( parseErrorMsg );
+ BOOST_REQUIRE_MESSAGE(ast.get(),"Failed to parse " << vec[i] << " " << parseErrorMsg);
+
+ std::stringstream s2;
+ ast->print_flat(s2,true/*add_brackets*/);
+ std::string ast_expr = s2.str();
+ BOOST_CHECK_MESSAGE(vec[i]==ast_expr," Failed '" << vec[i] << "' != '" << ast_expr << "'" );
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_parser_good_expressions )
+{
+ std::cout << "ANode:: ...test_parser_good_expressions\n";
+
+ // The map key = trigger expression,
+ // value.first = type of the expected root abstract syntax tree
+ // value.second = result of expected evaluation
+ map<string,std::pair<string,bool> > exprMap;
+
+ exprMap["a:value == 0"] = std::make_pair(AstEqual::stype(),true);
+ exprMap["a:value == 10"] = std::make_pair(AstEqual::stype(),false);
+ exprMap["a:value eq 10"] = std::make_pair(AstEqual::stype(),false);
+ exprMap["a:value != 10"] = std::make_pair(AstNotEqual::stype(),true);
+ exprMap["a:value ne 10"] = std::make_pair(AstNotEqual::stype(),true);
+ exprMap["a:value > 10"] = std::make_pair(AstGreaterThan::stype(),false);
+ exprMap["a:value gt 10"] = std::make_pair(AstGreaterThan::stype(),false);
+ exprMap["a:value >= 10"] = std::make_pair(AstGreaterEqual::stype(),false);
+ exprMap["a:value ge 10"] = std::make_pair(AstGreaterEqual::stype(),false);
+ exprMap["a:value < 10"] = std::make_pair(AstLessThan::stype(),true);
+ exprMap["a:value lt 10"] = std::make_pair(AstLessThan::stype(),true);
+ exprMap["a:value <= 10"] = std::make_pair(AstLessEqual::stype(),true);
+ exprMap["a:value le 10"] = std::make_pair(AstLessEqual::stype(),true);
+
+ exprMap["0 == a:value"] = std::make_pair(AstEqual::stype(),true);
+ exprMap["10 == a:value"] = std::make_pair(AstEqual::stype(),false);
+ exprMap["10 eq a:value"] = std::make_pair(AstEqual::stype(),false);
+ exprMap["10 != a:value"] = std::make_pair(AstNotEqual::stype(),true);
+ exprMap["10 ne a:value"] = std::make_pair(AstNotEqual::stype(),true);
+ exprMap["10 > a:value"] = std::make_pair(AstGreaterThan::stype(),true);
+ exprMap["10 gt a:value"] = std::make_pair(AstGreaterThan::stype(),true);
+ exprMap["10 >= a:value"] = std::make_pair(AstGreaterEqual::stype(),true);
+ exprMap["10 < a:value"] = std::make_pair(AstLessThan::stype(),false);
+ exprMap["10 lt a:value"] = std::make_pair(AstLessThan::stype(),false);
+ exprMap["10 <= a:value"] = std::make_pair(AstLessEqual::stype(),false);
+ exprMap["10 le a:value"] = std::make_pair(AstLessEqual::stype(),false);
+
+ exprMap["a == complete"] = std::make_pair(AstEqual::stype(),false);
+ exprMap["a==complete"] = std::make_pair(AstEqual::stype(),false);
+ exprMap["a eq complete"] = std::make_pair(AstEqual::stype(),false);
+ exprMap["a ne complete"] = std::make_pair(AstNotEqual::stype(),true);
+
+ exprMap["0 eq 1"] = std::make_pair(AstEqual::stype(),false);
+ exprMap["1000 eq 9"] = std::make_pair(AstEqual::stype(),false);
+ exprMap["10 eq 10"] = std::make_pair(AstEqual::stype(),true);
+ exprMap["10 ge 4"] = std::make_pair(AstGreaterEqual::stype(),true);
+ exprMap["10 le 4"] = std::make_pair(AstLessEqual::stype(),false);
+
+ exprMap["0 == 1"] = std::make_pair(AstEqual::stype(),false);
+ exprMap["0 != 1"] = std::make_pair(AstNotEqual::stype(),true);
+ exprMap["0 < 1"] = std::make_pair(AstLessThan::stype(),true);
+ exprMap["10 < 1"] = std::make_pair(AstLessThan::stype(),false);
+ exprMap["1000 == 9"] = std::make_pair(AstEqual::stype(),false);
+ exprMap["10 == 10"] = std::make_pair(AstEqual::stype(),true);
+ exprMap["10 >= 4"] = std::make_pair(AstGreaterEqual::stype(),true);
+ exprMap["10 <= 4"] = std::make_pair(AstLessEqual::stype(),false);
+ exprMap["0 > 1"] = std::make_pair(AstGreaterThan::stype(),false);
+ exprMap["10 > 1"] = std::make_pair(AstGreaterThan::stype(),true);
+
+ exprMap["a:eventname"] = std::make_pair(AstEqual::stype(),false);
+ exprMap["./a/b:eventname"] = std::make_pair(AstEqual::stype(),false);
+ exprMap["/a/b:eventname"] = std::make_pair(AstEqual::stype(),false);
+ exprMap["../a/b:eventname == set"] = std::make_pair(AstEqual::stype(),false);
+ exprMap["../a/b:eventname == clear"] = std::make_pair(AstEqual::stype(),true);
+ exprMap["../a/b:eventname != clear"] = std::make_pair(AstNotEqual::stype(),false);
+ exprMap["a:eventname == set"] = std::make_pair(AstEqual::stype(),false);
+ exprMap["a:eventname != set"] = std::make_pair(AstNotEqual::stype(),true);
+ exprMap["a:eventname == clear"] = std::make_pair(AstEqual::stype(),true);
+
+ exprMap["a:metername >= 100"] = std::make_pair(AstGreaterEqual::stype(),false);
+ exprMap["b:metername le 100"] = std::make_pair(AstLessEqual::stype(),true);
+ exprMap["./b:metername <= 100"] = std::make_pair(AstLessEqual::stype(),true);
+ exprMap["../a/b:metername ge 100"] = std::make_pair(AstGreaterEqual::stype(),false);
+ exprMap["../a/b/c:metername >= 100"] = std::make_pair(AstGreaterEqual::stype(),false);
+
+ exprMap["./a == unknown"] = std::make_pair(AstEqual::stype(),true);
+ exprMap["./a/b != queued"] = std::make_pair(AstNotEqual::stype(),true);
+ exprMap["../a == complete"] = std::make_pair(AstEqual::stype(),false);
+ exprMap["../a/b == aborted"] = std::make_pair(AstEqual::stype(),false);
+ exprMap["../a/b/c != aborted"] = std::make_pair(AstNotEqual::stype(),true);
+
+ exprMap["a eq unknown and b ne complete"] = std::make_pair(AstAnd::stype(),true);
+ exprMap["a eq complete or b eq complete"] = std::make_pair(AstOr::stype(),false);
+ exprMap["a eq complete or b eq unknown"] = std::make_pair(AstOr::stype(),true);
+ exprMap["a eq complete and b eq complete"] = std::make_pair(AstAnd::stype(),false);
+ exprMap["(a eq complete and b == complete)"] = std::make_pair(AstAnd::stype(),false);
+
+ exprMap["a == unknown && b != complete"] = std::make_pair(AstAnd::stype(),true);
+ exprMap["a == complete || b == complete"] = std::make_pair(AstOr::stype(),false);
+ exprMap["a == complete || b == unknown"] = std::make_pair(AstOr::stype(),true);
+ exprMap["a eq complete && b eq complete"] = std::make_pair(AstAnd::stype(),false);
+ exprMap["(a == complete && b == complete)"] = std::make_pair(AstAnd::stype(),false);
+
+ // This should be interpreted as '(a == complete and b == complete) or c == complete'
+ // because 'and' has a higher priority than the 'or'. Hence 'OR' must be at the root.
+ exprMap["a == complete and b == complete or c == complete"] = std::make_pair(AstOr::stype(),false);
+ exprMap["a == complete && b == complete || c == complete"] = std::make_pair(AstOr::stype(),false);
+ exprMap["a == complete and b == complete or c == unknown"] = std::make_pair(AstOr::stype(),true);
+ exprMap["a == complete and (b == complete or c == complete)"] = std::make_pair(AstAnd::stype(),false);
+ exprMap["a == complete or b == complete and c == complete"] = std::make_pair(AstOr::stype(),false);
+ exprMap["((a == complete or b == complete)) and c == complete"] = std::make_pair(AstAnd::stype(),false);
+
+ exprMap["(a != aborted and b == unknown or c != queued)"] = std::make_pair(AstOr::stype(),true);
+ exprMap["(a == complete and b == complete) or nodepath:eventname"] = std::make_pair(AstOr::stype(),false);
+ exprMap["(a == complete and b == complete) or (a == complete and b == complete)"] = std::make_pair(AstOr::stype(),false);
+ exprMap["a == complete and (b == complete or a == complete) and b == complete"] = std::make_pair(AstAnd::stype(),false);
+
+ // Expression that initially fail to parse for the operational suites
+ exprMap["(/skull/consumer/admin/leader:1 and (0 le /skull/consumer/produce1/produce:STEP)) or (not /skull/consumer/admin/leader:1)"] = std::make_pair(AstOr::stype(),true);
+ exprMap["./pdb eq complete and ( not ../../../prod2diss/operation_is_late:yes or ../000/q2diss eq complete)"] = std::make_pair(AstAnd::stype(),false);
+ exprMap["! ../../../prod2diss//operation_is_late:yes"] = std::make_pair(AstNot::stype(),true);
+ exprMap["not ../../../prod2diss//operation_is_late:yes"] = std::make_pair(AstNot::stype(),true);
+ exprMap["not ../../../prod2diss/operation_is_late:yes"] = std::make_pair(AstNot::stype(),true);
+ exprMap["not ../../../prod2diss/operation_is_late:yes or a == complete "] = std::make_pair(AstOr::stype(),true);
+ exprMap["not ../../../prod2diss/operation_is_late:yes or not a == complete "] = std::make_pair(AstOr::stype(),true);
+ exprMap["not ( a == complete )"] = std::make_pair(AstNot::stype(),true);
+ exprMap["not ( a == unknown )"] = std::make_pair(AstNot::stype(),false);
+ exprMap["~ ( a == unknown )"] = std::make_pair(AstNot::stype(),false);
+ exprMap["~ ( a != unknown )"] = std::make_pair(AstNot::stype(),true);
+ exprMap["! ( a == unknown )"] = std::make_pair(AstNot::stype(),false);
+ exprMap["!( a == unknown )"] = std::make_pair(AstNot::stype(),false);
+ exprMap["inigroup:YMD eq ~ 1"] = std::make_pair(AstEqual::stype(),true);
+ exprMap["inigroup:YMD eq ~ 0"] = std::make_pair(AstEqual::stype(),false);
+ exprMap["inigroup:YMD eq ! 0"] = std::make_pair(AstEqual::stype(),false);
+ exprMap["/net/main:YMD le /net/cleanplus1:YMD and 1"] = std::make_pair(AstAnd::stype(),true);
+
+ exprMap["bins/wamabs eq complete and links eq complete"] = std::make_pair(AstAnd::stype(),false);
+ exprMap["/mc/main:YMD le /mc/main/ref:MC_STOP"] = std::make_pair(AstLessEqual::stype(),true);
+ exprMap["/mc//main:YMD le /mc/main//ref:MC_STOP"] = std::make_pair(AstLessEqual::stype(),true);
+ exprMap["( ( /o/main/12/an/slwet eq complete and ( /o/main/12/an/4dvar/ifstraj:finalwave or /o/main/12/an/4dvar eq complete)) or /o/main/12/an eq complete)"] = std::make_pair(AstOr::stype(),false);
+ exprMap["../../sv/getsvs eq complete and ( getae:1 or getae eq complete)"] = std::make_pair(AstAnd::stype(),false);
+ exprMap["( ( /o/lag:YMD gt /sync/o/o/lag:YMD) or ( /o/main:YMD gt /sync/o/o/main:YMD) or 1 eq 0) and /sync/o ne active and /sync/o ne submitted"] = std::make_pair(AstAnd::stype(),false);
+
+
+ exprMap["t:step + 20 le 19"] = std::make_pair(AstLessEqual::stype(),false);
+ exprMap["(t:step + 20) le 19"] = std::make_pair(AstLessEqual::stype(),false);
+ exprMap["t:step + 20 ge 120"] = std::make_pair(AstGreaterEqual::stype(),false);
+ exprMap["t:step - 20 ge 120"] = std::make_pair(AstGreaterEqual::stype(),false);
+ exprMap["t:step + 20 ge t:step1 - 20"] = std::make_pair(AstGreaterEqual::stype(),true);
+ exprMap["(t:step + 20) ge (t:step1 - 20)"] = std::make_pair(AstGreaterEqual::stype(),true);
+
+ // Note: t:step will evaluate to 0, 0 % number == 0, however 20 % 0 is a runtime error, same as divide by zero
+ exprMap["t:step % 20 < 19"] = std::make_pair(AstLessThan::stype(),true);
+ exprMap["t:step % 10 == 0"] = std::make_pair(AstEqual::stype(),true);
+ exprMap["t:step % 20 ge 19"] = std::make_pair(AstGreaterEqual::stype(),false);
+ exprMap["(t:step % 20) ge 19"] = std::make_pair(AstGreaterEqual::stype(),false);
+ exprMap["t:step % 20 ge 120"] = std::make_pair(AstGreaterEqual::stype(),false);
+ exprMap["t:step % 20 ge 120"] = std::make_pair(AstGreaterEqual::stype(),false);
+ exprMap["t:step % 20 ge t:step1 - 20"] = std::make_pair(AstGreaterEqual::stype(),true);
+ exprMap["(t:step % 20) ge (t:step1 - 20)"] = std::make_pair(AstGreaterEqual::stype(),true);
+ exprMap["(t:step % 20) == (t:step1 % 10)"] = std::make_pair(AstEqual::stype(),true);
+
+ exprMap["( obs:YMD le ( main:YMD + 1)) and ../make/setup eq complete and ( obs:YMD le /o/lag:YMD)"] = std::make_pair(AstAnd::stype(),false);
+ exprMap["( stage eq complete or ./stage:YMD gt ./retrieve:YMD) and ( ./retrieve:YMD - ./load:YMD lt 5)"] = std::make_pair(AstAnd::stype(),false);
+ exprMap["./a:YMD - ./b:YMD lt 5"] = std::make_pair(AstLessThan::stype(),true);
+
+ exprMap["comp == complete and notready == complete"] = std::make_pair(AstAnd::stype(),false);
+
+ std::pair<string, std::pair<string,bool> > p;
+ BOOST_FOREACH(p, exprMap ) {
+
+ ExprParser theExprParser(p.first);
+ std::string errorMsg;
+ bool ok = theExprParser.doParse(errorMsg);
+ BOOST_REQUIRE_MESSAGE(ok,errorMsg);
+
+ string expectedRootType = p.second.first;
+ bool expectedEvaluationResult = p.second.second;
+
+ Ast* top = theExprParser.getAst();
+ BOOST_REQUIRE_MESSAGE( top ,"No abstract syntax tree");
+ BOOST_CHECK_MESSAGE( top->left() ,"No root created");
+ BOOST_CHECK_MESSAGE( top->left()->isRoot() ,"First child of top should be a root");
+ BOOST_CHECK_MESSAGE( top->left()->type() == expectedRootType,"expected root type " << expectedRootType << " but found " << top->left()->type());
+ BOOST_CHECK_MESSAGE( expectedEvaluationResult == top->evaluate(),"evaluation not as expected for:\n" << p.first << "\n" << *top);
+
+ std::string error_msg;
+ BOOST_CHECK_MESSAGE( top->check(error_msg),error_msg << ": Check failed for " << *top);
+ }
+}
+
+
+BOOST_AUTO_TEST_CASE( test_trigger_expression_divide_by_zero )
+{
+ std::cout << "ANode:: ...test_trigger_expression_divide_by_zero\n";
+
+ // The map key = trigger expression,
+ // value.first = type of the expected root abstract syntax tree
+ // value.second = result of expected evaluation
+ map<string,std::pair<string,bool> > exprMap;
+
+ // Divide by zero or modulo by zero would lead to run-time crash
+ // However the Ast::evaluate() checks for this, and return zero for the whole expression i.e ./a:YMD % 0 returns 0
+ exprMap["./a:YMD % 0 == 0"] = std::make_pair(AstEqual::stype(),true);
+ exprMap["./a:YMD / 0 == 0"] = std::make_pair(AstEqual::stype(),true);
+
+
+ std::pair<string, std::pair<string,bool> > p;
+ BOOST_FOREACH(p, exprMap ) {
+
+ ExprParser theExprParser(p.first);
+ std::string errorMsg;
+ bool ok = theExprParser.doParse(errorMsg);
+ BOOST_REQUIRE_MESSAGE(ok,errorMsg);
+
+ string expectedRootType = p.second.first;
+ bool expectedEvaluationResult = p.second.second;
+
+ Ast* top = theExprParser.getAst();
+ BOOST_REQUIRE_MESSAGE( top ,"No abstract syntax tree");
+ BOOST_CHECK_MESSAGE( top->left() ,"No root created");
+ BOOST_CHECK_MESSAGE( top->left()->isRoot() ,"First child of top should be a root");
+ BOOST_CHECK_MESSAGE( top->left()->type() == expectedRootType,"expected root type " << expectedRootType << " but found " << top->left()->type());
+ BOOST_CHECK_MESSAGE( expectedEvaluationResult == top->evaluate(),"evaluation not as expected for " << *top);
+
+ // expect check to fail, due to divide/modulo by zero
+ std::string error_msg;
+ BOOST_CHECK_MESSAGE( !top->check(error_msg),error_msg << ": Check failed for " << *top);
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_parser_bad_expressions )
+{
+ std::cout << "ANode:: ...test_parser_bad_expressions\n";
+ vector<string> exprvec;
+ exprvec.push_back("a = complete");
+ exprvec.push_back("a e complete");
+ exprvec.push_back("a=complete");
+ exprvec.push_back("a ! complete");
+ exprvec.push_back("a==complet e");
+ exprvec.push_back("a eq complet e");
+ exprvec.push_back("a::eventname");
+ exprvec.push_back("a:eventname = set");
+ exprvec.push_back("a:eventname == ");
+ exprvec.push_back("a:eventname ! set");
+ exprvec.push_back("a:eventname ! = set");
+ exprvec.push_back("a:eventname %");
+ exprvec.push_back("a:metername 100");
+ exprvec.push_back(". == complete");
+ exprvec.push_back("/ == complete");
+ exprvec.push_back(". == error");
+ exprvec.push_back("./ == error");
+ exprvec.push_back(".a == error");
+ exprvec.push_back(".a == unknown");
+ exprvec.push_back(".a/. == unknown");
+ exprvec.push_back(".. == unknown");
+ exprvec.push_back(".a/b == queued");
+ exprvec.push_back("./a/b/ == active");
+ exprvec.push_back("..a == complete");
+ exprvec.push_back(".../a == complete");
+ exprvec.push_back("../.../a == complete");
+ exprvec.push_back(".. /a == complete");
+ exprvec.push_back("../.. /a == complete");
+ exprvec.push_back("../../.a == complete");
+ exprvec.push_back("..a/b == aborted");
+ exprvec.push_back("..a/b/c == aborted");
+ exprvec.push_back("a == complete and");
+ exprvec.push_back("a %");
+ exprvec.push_back("(a == complete b == complete)");
+ exprvec.push_back("a == complete and b == complete)");
+ exprvec.push_back("(a == complete and b == complete");
+ exprvec.push_back("(a = complete and b = complete or c = complete)");
+ exprvec.push_back("(a erro complete and b == complete) or nodepath:eventname");
+ exprvec.push_back("(a == complete and b == complete or (a == complete and b == complete)");
+ // triggers that dont make sense in the operational suites.
+ exprvec.push_back("../../../legA/fc/pf/01 eq complete eq complete");
+
+ BOOST_FOREACH(const string& expr, exprvec ) {
+
+ //std::cout << "parsing expression " << expr << "\n";
+ ExprParser theExprParser(expr);
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE( !theExprParser.doParse( errorMsg), expr << " expected to fail " );
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/ANode/test/TestExprRepeatDateArithmetic.cpp b/ANode/test/TestExprRepeatDateArithmetic.cpp
new file mode 100644
index 0000000..fa8398c
--- /dev/null
+++ b/ANode/test/TestExprRepeatDateArithmetic.cpp
@@ -0,0 +1,216 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/test/unit_test.hpp>
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_repeat_data_arithmetic )
+{
+ cout << "ANode:: ...test_repeat_data_arithmetic\n" ;
+
+ Defs theDefs;
+ task_ptr t2,t1;
+ {
+ suite_ptr s1 = theDefs.add_suite("s1");
+ t1 = s1->add_task("t1"); t1->addRepeat( RepeatDate("YMD",20090101,20091231,1));
+ t2 = s1->add_task("t2"); t2->add_trigger("t1:YMD ge 20080601");
+ }
+ theDefs.beginAll();
+
+ // Check trigger expressions
+ std::string errorMsg, warningMsg;
+ BOOST_REQUIRE_MESSAGE(theDefs.check(errorMsg,warningMsg),"Expected triggers expressions to parse " << errorMsg);
+
+ // Get the trigger AST
+ Ast* trigger = t2->triggerAst();
+ BOOST_REQUIRE_MESSAGE(trigger,"Expected trigger");
+
+ // check evaluation
+ BOOST_CHECK_MESSAGE(trigger->evaluate(),"Expected trigger to evaluate i.e 20090101 >= 20080601");
+
+ // Check date arithmetic. Basics, end of months
+ t2->changeTrigger("t1:YMD - 1 eq 20081231"); // 20090101 - 1 == 20081231
+ BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic for evaluation");
+
+ t2->changeTrigger("t1:YMD + 1 eq 20090102"); // 20090101 + 1 == 20090102
+ BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic for evaluation");
+}
+
+BOOST_AUTO_TEST_CASE( test_repeat_data_arithmetic_add_to_end_of_month )
+{
+ cout << "ANode:: ...test_repeat_data_arithmetic_add_to_end_of_month\n" ;
+
+ Defs theDefs;
+ task_ptr t2,t1;
+ {
+ suite_ptr s1 = theDefs.add_suite("s1");
+ t1 = s1->add_task("t1"); t1->addRepeat( RepeatDate("YMD",20090101,20091231,1));
+ t2 = s1->add_task("t2"); t2->add_trigger("t1:YMD ge 20080601");
+ }
+ theDefs.beginAll();
+
+ // Check trigger expressions
+ std::string errorMsg, warningMsg;
+ BOOST_REQUIRE_MESSAGE(theDefs.check(errorMsg,warningMsg),"Expected triggers expressions to parse " << errorMsg);
+
+ // Check the end of each month + 1
+ t1->deleteRepeat();
+ t1->addRepeat( RepeatDate("YMD",20090131,20101231,1)); // jan
+ t2->changeTrigger("t1:YMD + 1 eq 20090201"); // 20090131 + 1 == 20090201
+ BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
+
+ t1->deleteRepeat();
+ t1->addRepeat( RepeatDate("YMD",20090228,20101231,1)); // feb
+ t2->changeTrigger("t1:YMD + 1 eq 20090301");
+ BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
+
+ t1->deleteRepeat();
+ t1->addRepeat( RepeatDate("YMD",20090331,20101231,1)); // mar
+ t2->changeTrigger("t1:YMD + 1 eq 20090401");
+ BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
+
+ t1->deleteRepeat();
+ t1->addRepeat( RepeatDate("YMD",20090430,20101231,1)); // apr
+ t2->changeTrigger("t1:YMD + 1 eq 20090501");
+ BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
+
+ t1->deleteRepeat();
+ t1->addRepeat( RepeatDate("YMD",20090531,20101231,1)); // may
+ t2->changeTrigger("t1:YMD + 1 eq 20090601");
+ BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
+
+ t1->deleteRepeat();
+ t1->addRepeat( RepeatDate("YMD",20090630,20101231,1)); // June
+ t2->changeTrigger("t1:YMD + 1 eq 20090701");
+ BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
+
+ t1->deleteRepeat();
+ t1->addRepeat( RepeatDate("YMD",20090731,20101231,1)); // July
+ t2->changeTrigger("t1:YMD + 1 eq 20090801");
+ BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
+
+ t1->deleteRepeat();
+ t1->addRepeat( RepeatDate("YMD",20090831,20101231,1)); // Aug
+ t2->changeTrigger("t1:YMD + 1 eq 20090901");
+ BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
+
+ t1->deleteRepeat();
+ t1->addRepeat( RepeatDate("YMD",20090930,20101231,1)); // Sept
+ t2->changeTrigger("t1:YMD + 1 eq 20091001");
+ BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
+
+ t1->deleteRepeat();
+ t1->addRepeat( RepeatDate("YMD",20091031,20101231,1)); // Oct
+ t2->changeTrigger("t1:YMD + 1 eq 20091101");
+ BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
+
+ t1->deleteRepeat();
+ t1->addRepeat( RepeatDate("YMD",20091130,20101231,1)); // Nov
+ t2->changeTrigger("t1:YMD + 1 eq 20091201");
+ BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
+
+ t1->deleteRepeat();
+ t1->addRepeat( RepeatDate("YMD",20091231,20101231,1)); // Dec
+ t2->changeTrigger("t1:YMD + 1 eq 20100101");
+ BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
+}
+
+
+BOOST_AUTO_TEST_CASE( test_repeat_data_arithmetic_take_from_end_of_month )
+{
+ cout << "ANode:: ...test_repeat_data_arithmetic_take_from_end_of_month\n" ;
+
+ Defs theDefs;
+ task_ptr t2,t1;
+ {
+ suite_ptr s1 = theDefs.add_suite("s1");
+ t1 = s1->add_task("t1"); t1->addRepeat( RepeatDate("YMD",20090101,20091231,1));
+ t2 = s1->add_task("t2"); t2->add_trigger("t1:YMD ge 20080601");
+ }
+ theDefs.beginAll();
+
+ // Check trigger expressions
+ std::string errorMsg, warningMsg;
+ BOOST_REQUIRE_MESSAGE(theDefs.check(errorMsg,warningMsg),"Expected triggers expressions to parse " << errorMsg);
+
+ // Check the end of each month - 1
+ t1->deleteRepeat();
+ t1->addRepeat( RepeatDate("YMD",20090201,20101231,1)); // jan
+ t2->changeTrigger("t1:YMD - 1 eq 20090131");
+ BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
+
+ t1->deleteRepeat();
+ t1->addRepeat( RepeatDate("YMD",20090301,20101231,1)); // feb
+ t2->changeTrigger("t1:YMD - 1 eq 20090228");
+ BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
+
+ t1->deleteRepeat();
+ t1->addRepeat( RepeatDate("YMD",20090401,20101231,1)); // mar
+ t2->changeTrigger("t1:YMD - 1 eq 20090331");
+ BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
+
+ t1->deleteRepeat();
+ t1->addRepeat( RepeatDate("YMD",20090501,20101231,1)); // apr
+ t2->changeTrigger("t1:YMD - 1 eq 20090430");
+ BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
+
+ t1->deleteRepeat();
+ t1->addRepeat( RepeatDate("YMD",20090601,20101231,1)); // may
+ t2->changeTrigger("t1:YMD - 1 eq 20090531");
+ BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
+
+ t1->deleteRepeat();
+ t1->addRepeat( RepeatDate("YMD",20090701,20101231,1)); // June
+ t2->changeTrigger("t1:YMD - 1 eq 20090630");
+ BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
+
+ t1->deleteRepeat();
+ t1->addRepeat( RepeatDate("YMD",20090801,20101231,1)); // July
+ t2->changeTrigger("t1:YMD - 1 eq 20090731");
+ BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
+
+ t1->deleteRepeat();
+ t1->addRepeat( RepeatDate("YMD",20090901,20101231,1)); // Aug
+ t2->changeTrigger("t1:YMD - 1 eq 20090831");
+ BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
+
+ t1->deleteRepeat();
+ t1->addRepeat( RepeatDate("YMD",20091001 ,20101231,1)); // Sept
+ t2->changeTrigger("t1:YMD - 1 eq 20090930");
+ BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
+
+ t1->deleteRepeat();
+ t1->addRepeat( RepeatDate("YMD",20091101 ,20101231,1)); // Oct
+ t2->changeTrigger("t1:YMD - 1 eq 20091031");
+ BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
+
+ t1->deleteRepeat();
+ t1->addRepeat( RepeatDate("YMD",20091201 ,20101231,1)); // Nov
+ t2->changeTrigger("t1:YMD - 1 eq 20091130");
+ BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
+
+ t1->deleteRepeat();
+ t1->addRepeat( RepeatDate("YMD",20100101 ,20101231,1)); // Dec
+ t2->changeTrigger("t1:YMD - 1 eq 20091231");
+ BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ANode/test/TestFindAbsNodePath.cpp b/ANode/test/TestFindAbsNodePath.cpp
new file mode 100644
index 0000000..ec974be
--- /dev/null
+++ b/ANode/test/TestFindAbsNodePath.cpp
@@ -0,0 +1,75 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "Alias.hpp"
+#include "PrintStyle.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <iostream>
+#include <stdlib.h>
+
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_find_abs_node_path )
+{
+ cout << "ANode:: ...test_find_abs_node_path\n";
+
+ size_t no_of_nodes = 0;
+ size_t no_of_alias = 0;
+ Defs theDefs;
+ {
+ for(int s = 0; s < 3; s++) {
+ suite_ptr suite = theDefs.add_suite( "suite" + boost::lexical_cast<std::string>(s)); no_of_nodes++;
+ for(int f = 0; f < 3; f++) {
+ family_ptr fam = suite->add_family( "family" + boost::lexical_cast<std::string>(f)); no_of_nodes++;
+ for(int ff = 0; ff < 3; ff++) {
+ family_ptr hfam = fam->add_family( "family" + boost::lexical_cast<std::string>(ff)); no_of_nodes++;
+ for(int t = 0; t < 3; t++) {
+ task_ptr task = hfam->add_task( "t1" + boost::lexical_cast<std::string>(t)); no_of_nodes++;
+ for(int a = 0; a < 3; a++) {
+ task->add_alias_only(); no_of_nodes++; no_of_alias++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Test Defs::getAllNodes()
+ std::vector<Node*> all_nodes;
+ theDefs.getAllNodes(all_nodes);
+ BOOST_CHECK_MESSAGE(all_nodes.size() == no_of_nodes,"Expected theDefs.getAllNodes() to return " << no_of_nodes << " node, but found " << all_nodes.size());
+
+ // Test Defs::get_all_aliases()
+ std::vector<alias_ptr> alias_vec;
+ theDefs.get_all_aliases(alias_vec);
+ BOOST_CHECK_MESSAGE(alias_vec.size() == no_of_alias,"Expected theDefs.get_all_aliases() to return " << no_of_alias << " node, but found " << alias_vec.size());
+
+ // Test Defs::findAbsNode()
+// PrintStyle::setStyle(PrintStyle::STATE);
+// std::cout << theDefs;
+ for(size_t i= 0; i < all_nodes.size(); i++) {
+ Node* node = all_nodes[i];
+ node_ptr found_node = theDefs.findAbsNode(node->absNodePath());
+ BOOST_CHECK_MESSAGE(found_node.get(),"Could not find node " << node->debugNodePath());
+ BOOST_CHECK_MESSAGE(found_node.get() == node," Expected to find " << node->debugNodePath() << " but found " << found_node->debugNodePath());
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ANode/test/TestFlag.cpp b/ANode/test/TestFlag.cpp
new file mode 100644
index 0000000..fa4cf0f
--- /dev/null
+++ b/ANode/test/TestFlag.cpp
@@ -0,0 +1,75 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <iostream>
+#include <boost/test/unit_test.hpp>
+
+#include "Flag.hpp"
+#include "Str.hpp"
+
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_node_flags )
+{
+ cout << "ANode:: ...test_node_flags\n";
+
+ Flag flag;
+ std::string expected_flags = "force_aborted,user_edit,task_aborted,edit_failed,ecfcmd_failed,no_script,killed,migrated,late,message,by_rule,queue_limit,task_waiting,locked,zombie,no_reque";
+
+ /// Set the flags
+ std::vector<Flag::Type> flag_list = Flag::list();
+ for (size_t i = 0; i < flag_list.size(); ++i) {
+ flag.set( flag_list[i] );
+ BOOST_REQUIRE_MESSAGE(flag.is_set( flag_list[i] ), "Expected flag to be set");
+ }
+ BOOST_REQUIRE_MESSAGE(flag.to_string() == expected_flags, "Expected string '" << expected_flags << "' but found '" << flag.to_string() << "'");
+ for (size_t i = 0; i < flag_list.size(); ++i) {
+ BOOST_REQUIRE_MESSAGE(flag.is_set( flag_list[i] ), "Expected flag to be set");
+ }
+
+ /// clears the flags
+ for (size_t i = 0; i < flag_list.size(); ++i) {
+ flag.clear( flag_list[i] );
+ BOOST_REQUIRE_MESSAGE(!flag.is_set( flag_list[i] ), "Expected flag to be clear");
+ }
+ for (size_t i = 0; i < flag_list.size(); ++i) {
+ BOOST_REQUIRE_MESSAGE(!flag.is_set( flag_list[i] ), "Expected flag to be clear");
+ }
+
+ /// set all flags
+ for (size_t i = 0; i < flag_list.size(); ++i) { flag.set( flag_list[i] );}
+
+ // reset, all flags should be clear
+ flag.reset();
+ for (size_t i = 0; i < flag_list.size(); ++i) {
+ BOOST_REQUIRE_MESSAGE(!flag.is_set( flag_list[i] ), "Expected flag to be clear");
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_node_flags_parsing )
+{
+ cout << "ANode:: ...test_node_flags_parsing\n";
+
+ /// Set the flags
+ Flag flag;
+ std::vector<Flag::Type> flag_list = Flag::list();
+ for (size_t i = 0; i < flag_list.size(); ++i) flag.set( flag_list[i] );
+
+ Flag flag2;
+ flag2.set_flag(flag.to_string());
+ BOOST_REQUIRE_MESSAGE(flag == flag2, "Flags should be equal.\nflag1:" << flag.to_string() << "\nflag2:" << flag2.to_string());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ANode/test/TestHistoryParser.cpp b/ANode/test/TestHistoryParser.cpp
new file mode 100644
index 0000000..ced96f9
--- /dev/null
+++ b/ANode/test/TestHistoryParser.cpp
@@ -0,0 +1,93 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #24 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <string>
+#include <iostream>
+#include <fstream>
+
+#include <boost/test/unit_test.hpp>
+
+#include "Defs.hpp"
+#include "Log.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost;
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+static std::string dump(const std::vector<std::string>& vec)
+{
+ std::stringstream ss;
+ std::copy (vec.begin(), vec.end(), std::ostream_iterator<std::string> (ss, "\n"));
+ return ss.str();
+}
+
+BOOST_AUTO_TEST_CASE( test_defs_history_parser )
+{
+ cout << "ANode:: ...test_defs_history_parser\n";
+
+ {
+ string str1("MSG:[12:03:55 21.8.2013] --shutdown=yes :map");
+ DefsHistoryParser parser;
+ parser.parse(str1);
+
+ std::vector<std::string> expected_messages;
+ expected_messages.push_back("MSG:[12:03:55 21.8.2013] --shutdown=yes :map");
+
+ BOOST_CHECK_MESSAGE(parser.parsed_messages() == expected_messages,"Expected:\n" << dump(expected_messages) << "but found:\n" << dump(parser.parsed_messages()));
+ }
+ {
+ string str1("MSG:[12:03:55 21.8.2013] --shutdown=yes :mapMSG:[12:34:08 21.8.2013] --restart :map");
+ DefsHistoryParser parser;
+ parser.parse(str1);
+
+ std::vector<std::string> expected_messages;
+ expected_messages.push_back("MSG:[12:03:55 21.8.2013] --shutdown=yes :map");
+ expected_messages.push_back("MSG:[12:34:08 21.8.2013] --restart :map");
+ BOOST_CHECK_MESSAGE(parser.parsed_messages() == expected_messages,"Expected:\n" << dump(expected_messages) << "but found:\n" << dump(parser.parsed_messages()));
+ }
+ {
+ string str1("MSG:[12:03:55 21.8.2013] --shutdown=yes :mapMSG:[12:34:08 21.8.2013] --restart :mapMSG:[12:47:22 21.8.2013] --alter add variable SMSNODE 0 / :mapMSG:[13:38:45 21.8.2013] --alter add variable SMSTRYNO 0 / :mapMSG:[13:44:09 21.8.2013] --alter add variable SMSHOME /vol/emos/output / :mapMSG:[15:36:14 21.8.2013] --shutdown=yes :mapMSG:[16:04:26 21.8.2013] --alter add variable SMSNODE 0 / :map");
+ DefsHistoryParser parser;
+ parser.parse(str1);
+
+ std::vector<std::string> expected_messages;
+ expected_messages.push_back("MSG:[12:03:55 21.8.2013] --shutdown=yes :map");
+ expected_messages.push_back("MSG:[12:34:08 21.8.2013] --restart :map");
+ expected_messages.push_back("MSG:[12:47:22 21.8.2013] --alter add variable SMSNODE 0 / :map");
+ expected_messages.push_back("MSG:[13:38:45 21.8.2013] --alter add variable SMSTRYNO 0 / :map");
+ expected_messages.push_back("MSG:[13:44:09 21.8.2013] --alter add variable SMSHOME /vol/emos/output / :map");
+ expected_messages.push_back("MSG:[15:36:14 21.8.2013] --shutdown=yes :map");
+ expected_messages.push_back("MSG:[16:04:26 21.8.2013] --alter add variable SMSNODE 0 / :map");
+ BOOST_CHECK_MESSAGE(parser.parsed_messages() == expected_messages,"Expected:\n" << dump(expected_messages) << "but found:\n" << dump(parser.parsed_messages()));
+ }
+ {
+ string str1("MSG:[12:03:55 21.8.2013] --shutdown=yes :mapLOG:[12:34:08 21.8.2013] --restart :mapERR:[12:47:22 21.8.2013] --alter add variable SMSNODE 0 / :mapWAR:[13:38:45 21.8.2013] --alter add variable SMSTRYNO 0 / :mapDBG:[13:44:09 21.8.2013] --alter add variable SMSHOME /vol/emos/output / :mapOTH:[15:36:14 21.8.2013] --shutdown=yes :mapOTH:[16:04:26 21.8.2013] --alter add variable SMSNODE 0 / :map");
+ DefsHistoryParser parser;
+ parser.parse(str1);
+
+ std::vector<std::string> expected_messages;
+ expected_messages.push_back("MSG:[12:03:55 21.8.2013] --shutdown=yes :map");
+ expected_messages.push_back("LOG:[12:34:08 21.8.2013] --restart :map");
+ expected_messages.push_back("ERR:[12:47:22 21.8.2013] --alter add variable SMSNODE 0 / :map");
+ expected_messages.push_back("WAR:[13:38:45 21.8.2013] --alter add variable SMSTRYNO 0 / :map");
+ expected_messages.push_back("DBG:[13:44:09 21.8.2013] --alter add variable SMSHOME /vol/emos/output / :map");
+ expected_messages.push_back("OTH:[15:36:14 21.8.2013] --shutdown=yes :map");
+ expected_messages.push_back("OTH:[16:04:26 21.8.2013] --alter add variable SMSNODE 0 / :map");
+ BOOST_CHECK_MESSAGE(parser.parsed_messages() == expected_messages,"Expected:\n" << dump(expected_messages) << "but found:\n" << dump(parser.parsed_messages()));
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ANode/test/TestInLimit.cpp b/ANode/test/TestInLimit.cpp
new file mode 100644
index 0000000..3886116
--- /dev/null
+++ b/ANode/test/TestInLimit.cpp
@@ -0,0 +1,76 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #1 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <iostream>
+#include <boost/test/unit_test.hpp>
+
+#include "SerializationTest.hpp"
+#include "InLimit.hpp"
+
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_inlimit_basics )
+{
+ cout << "ANode:: ...test_inlimit_basics \n";
+
+ {
+ InLimit empty;
+ InLimit empty2;
+ BOOST_CHECK_MESSAGE(empty == empty2,"Equality failed");
+
+ InLimit l1("name","path");
+ InLimit l2("name","path");
+ BOOST_CHECK_MESSAGE(l1 == l2,"Equality failed");
+
+ InLimit a("name","path",10);
+ InLimit b("name","path");
+ BOOST_CHECK_MESSAGE(!(a == b),"Equality passed when should fail");
+ }
+
+ InLimit inlim("fred","/path/to/node");
+ {
+ InLimit testCopy = inlim;
+ BOOST_CHECK_MESSAGE(testCopy == inlim,"Copy constructor failed");
+ }
+ {
+ InLimit testCopy;
+ testCopy = inlim;
+ BOOST_CHECK_MESSAGE(testCopy == inlim,"Assignment failed");
+ }
+}
+
+
+// Globals used throughout the test
+static std::string fileName = "test.txt";
+BOOST_AUTO_TEST_CASE( test_InLimit_serialisation )
+{
+ cout << "ANode:: ...test_InLimit_serialisation\n";
+
+ doSaveAndRestore<InLimit>(fileName);
+
+ InLimit saved("limitName","/path/to/some/node",20);
+ save(fileName,saved);
+
+ InLimit restored; restore(fileName,restored);
+ BOOST_CHECK_MESSAGE(saved == restored," save and restored don't match");
+ std::remove(fileName.c_str());
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/ANode/test/TestJobCreator.cpp b/ANode/test/TestJobCreator.cpp
new file mode 100644
index 0000000..cd35c9f
--- /dev/null
+++ b/ANode/test/TestJobCreator.cpp
@@ -0,0 +1,120 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/test/unit_test.hpp>
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "JobsParam.hpp"
+#include "Jobs.hpp"
+#include "System.hpp"
+#include "Str.hpp"
+#include "File.hpp"
+
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_job_creator )
+{
+ cout << "ANode:: ...test_job_creator\n";
+
+ // SET SMSHOME
+ std::string ecf_home = File::test_data("ANode/test/data/SMSHOME","ANode");
+
+ // Create the defs file corresponding to the text below
+ //# Test the sms file can be found via ECF_SCRIPT
+ //# Note: we have to use relative paths, since these tests are relocatable
+ //#
+ //suite suite
+ // edit SLEEPTIME 10
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // family family
+ // task t1
+ // task t2
+ // task t3
+ // endfamily
+ //endsuite
+ //#
+ //# This test suite should force a backwards search since the sms files
+ //# are located in SMSHOME
+ //suite suite1
+ // family family
+ // task suite1_task1
+ // task suite1_task2
+ // task suite1_task3
+ // endfamily
+ //endsuite
+ // Create a defs file, where the task name mirrors the sms files in the given directory
+ Defs theDefs;
+ {
+ suite_ptr suite = Suite::create( "suite" );
+ family_ptr fam = Family::create( "family" );
+ suite->addVariable( Variable( Str::ECF_INCLUDE(), "$ECF_HOME/../includes" ) );
+ suite->addVariable( Variable( "SLEEPTIME", "1" ) );
+ suite->addVariable( Variable( "ECF_CLIENT_EXE_PATH", "a/made/up/path" ) );
+ fam->addTask( Task::create( "t1" ) );
+ fam->addTask( Task::create( "t2" ) );
+ fam->addTask( Task::create( "t3" ) );
+ suite->addFamily( fam );
+ theDefs.addSuite( suite );
+ }
+ {
+ suite_ptr suite1( new Suite( "suite1" ) );
+ family_ptr fam( new Family( "family" ) );
+ fam->addTask( Task::create( "suite1_task1" ) );
+ fam->addTask( Task::create( "suite1_task2" ) );
+ fam->addTask( Task::create( "suite1_task3" ) );
+ suite1->addFamily( fam );
+ theDefs.addSuite( suite1 );
+ }
+// cerr << theDefs << "\n";
+
+ // get all the task, assume non hierarchical families
+ std::vector<Task*> theTasks;
+ theDefs.getAllTasks(theTasks);
+ BOOST_REQUIRE_MESSAGE(theTasks.size() == 6, "Expected 6 tasks but found, " << theTasks.size());
+
+
+ // Override ECF_HOME. ECF_HOME is need to locate to the .ecf files
+ theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(),ecf_home);
+
+
+ /// begin , will cause creation of generated variables. The generated variables
+ /// are use in client scripts and used to locate the ecf files
+ theDefs.beginAll();
+
+ // Test Job creator. The job creation should succeed 3 times only, since
+ // the sms file suite1_task1, suite1_task2,suite1_task3 are empty.
+ JobsParam jobsParam(true/*create jobs*/); // spawn_jobs = false
+ Jobs jobs(&theDefs);
+ jobs.generate(jobsParam);
+ BOOST_REQUIRE_MESSAGE( jobsParam.submitted().size() == 3 , "expected 3 jobs but found " << jobsParam.submitted().size() << "\n" << jobsParam.errorMsg());
+
+ // Expect error message complaining about sms file suite1_task1, suite1_task2,suite1_task3 being empty
+ BOOST_REQUIRE_MESSAGE( !jobsParam.errorMsg().empty(), "expected error message about empty ecf files");
+
+ /// Destroy System singleton to avoid valgrind from complaining
+ System::destroy();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ANode/test/TestJobProfiler.cpp b/ANode/test/TestJobProfiler.cpp
new file mode 100644
index 0000000..f575984
--- /dev/null
+++ b/ANode/test/TestJobProfiler.cpp
@@ -0,0 +1,89 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <iostream>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/test/unit_test.hpp>
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "Str.hpp"
+#include "File.hpp"
+#include "Log.hpp"
+#include "Jobs.hpp"
+#include "JobsParam.hpp"
+#include "System.hpp"
+
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_job_profiler )
+{
+ cout << "ANode:: ...test_job_profiler\n";
+
+ // delete the log file if it exists.
+ std::string log_path = File::test_data("ANode/test/logfile.txt","ANode");
+ fs::remove(log_path);
+ BOOST_CHECK_MESSAGE(!fs::exists( log_path ), "log file " << log_path << " not deleted ");
+
+ // Create a new log, file, we will look in here to see if job profiling is working
+ Log::create(log_path);
+
+
+ // SET ECF_HOME, re-use exist test of directory and scripts
+ Defs theDefs;
+ {
+ suite_ptr suite = theDefs.add_suite("suite");
+ suite->addVariable( Variable( Str::ECF_INCLUDE(), File::test_data("ANode/test/data/includes","ANode") ) );
+ suite->addVariable( Variable( "ECF_HOME", File::test_data("ANode/test/data/SMSHOME","ANode") ) );
+ suite->addVariable( Variable( "SLEEPTIME", "10" ) );
+ family_ptr fam = suite->add_family( "family" );
+ fam->add_task( "t1" );
+ }
+ // cerr << theDefs << "\n";
+
+ // begin , will cause creation of generated variables. The generated variables
+ // are use in client scripts and used to locate the ecf files
+ theDefs.beginAll();
+
+ // By setting submitJobsInterval to -1, we enable the jobs profiling testing
+ // createJobs enables us to ensure job size is profiled
+ // spawn jobs set to false, do not create a separate process to spawn jobs
+ JobsParam jobParam(-1 /*submitJobsInterval*/, true /*createJobs*/, false/* spawn jobs */);
+ Jobs job(&theDefs);
+ bool ok = job.generate( jobParam );
+ BOOST_CHECK_MESSAGE(ok,"generate failed: " << jobParam.getErrorMsg());
+
+ // Check the log file, has the profiling
+ std::string log_file_contents;
+ BOOST_CHECK_MESSAGE(File::open(log_path,log_file_contents), "Could not open log file at " << log_path);
+ BOOST_CHECK_MESSAGE(!log_file_contents.empty(),"log file is is empty ?");
+ BOOST_CHECK_MESSAGE(log_file_contents.find("Exceeds ECF_TASK_THRESHOLD") != std::string::npos, "Exceeds ECF_TASK_THRESHOLD not in profile");
+
+ // Remove the log file. Comment out for debugging
+ fs::remove(log_path);
+
+ // Explicitly destroy log. To keep valgrind happy
+ Log::destroy();
+
+ /// Destroy System singleton to avoid valgrind from complaining
+ System::destroy();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ANode/test/TestLimit.cpp b/ANode/test/TestLimit.cpp
new file mode 100644
index 0000000..7850e44
--- /dev/null
+++ b/ANode/test/TestLimit.cpp
@@ -0,0 +1,184 @@
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #1 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <iostream>
+
+#include <boost/test/unit_test.hpp>
+#include <boost/lexical_cast.hpp>
+#include "SerializationTest.hpp"
+
+#include "Limit.hpp"
+#include "Ecf.hpp"
+
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_limit_basics )
+{
+ cout << "ANode:: ...test_limit_basics \n";
+
+ {
+ Limit empty;
+ Limit empty2;
+ BOOST_CHECK_MESSAGE(empty == empty2,"Equality failed");
+
+ Limit l1("name",2);
+ Limit l2("name",2);
+ BOOST_CHECK_MESSAGE(l1 == l2,"Equality failed");
+
+ Limit l3("name",2);
+ Limit l4("name",4);
+ BOOST_CHECK_MESSAGE(!(l3 == l4),"Equality failed");
+ }
+
+ std::set<std::string> expected_empty_paths;
+ std::set<std::string> expected_paths;
+
+ Limit l1("name",100);
+ for(int i = 1; i < 10; i++) {
+ std::string path = boost::lexical_cast<std::string>(i);
+ expected_paths.insert(path);
+ l1.increment(1,path);
+ BOOST_CHECK_MESSAGE(l1.paths() == expected_paths,"Expected paths not the same at " << i);
+ }
+
+ for(int i = 9; i >= 1; i--) {
+ std::string path = boost::lexical_cast<std::string>(i);
+ l1.decrement(1,path);
+ std::set<std::string>::iterator iter = expected_paths.find(path); expected_paths.erase(iter);
+
+ if (l1.paths() != expected_paths) {
+ std::cout << " Expected:";
+ std::copy (expected_paths.begin(), expected_paths.end(), std::ostream_iterator <std::string> (std::cout, " "));
+ std::cout << " Found:";
+ std::copy (l1.paths().begin(), l1.paths().end(), std::ostream_iterator <std::string> (std::cout, " "));
+ }
+ BOOST_CHECK_MESSAGE(l1.paths() == expected_paths,"Expected paths not the same at " << i);
+ }
+
+ expected_paths.insert("/a/b/c");
+ l1.increment(1,"/a/b/c");
+ BOOST_CHECK_MESSAGE(l1.paths() == expected_paths,"Expected paths not the same");
+
+ l1.decrement(1,"/a/b/c");
+ BOOST_CHECK_MESSAGE(l1.paths() == expected_empty_paths,"Expected paths not the same");
+ BOOST_CHECK_MESSAGE(l1.value() == 0,"Expected value to be 0");
+
+
+ l1.increment(1,"/a/b/c");
+ l1.increment(1,"/a/b/d");
+ BOOST_CHECK_MESSAGE(l1.paths().size() == 2,"Expected 2 paths but found " << l1.paths().size());
+ BOOST_CHECK_MESSAGE(l1.value() == 2,"Expected value to be 2 but found " << l1.value());
+ l1.reset();
+ BOOST_CHECK_MESSAGE(l1.value() == 0,"Expected value to be 0 after reset, but found " << l1.value());
+ BOOST_CHECK_MESSAGE(l1.paths().size() == 0,"Expected 0 paths after reset but found " << l1.paths().size());
+
+ l1.setValue(10);
+ BOOST_CHECK_MESSAGE(l1.value() == 10,"Expected value to be 10, but found " << l1.value());
+ BOOST_CHECK_MESSAGE(l1.paths().size() == 0,"Expected 0 paths after reset but found " << l1.paths().size());
+}
+
+
+BOOST_AUTO_TEST_CASE( test_limit_increment )
+{
+ cout << "ANode:: ...test_limit_increment\n";
+
+ Limit limit("name",10); // Limit of 10
+ limit.increment(1,"path"); // consume 1 token
+
+ BOOST_CHECK_MESSAGE(limit.value() == 1,"Expected increment to consume 1 token but it has consumed " << limit.value());
+ BOOST_CHECK_MESSAGE(limit.paths().size() == 1,"Expected 1 task path but found " << limit.paths().size());
+
+ limit.increment(1,"path"); // Increment with same path, should *NOT* consume a token
+
+ BOOST_CHECK_MESSAGE(limit.value() == 1,"Expected 1 token but it has consumed " << limit.value());
+ BOOST_CHECK_MESSAGE(limit.paths().size() == 1,"Expected 1 task path but found " << limit.paths().size());
+}
+
+BOOST_AUTO_TEST_CASE( test_limit_increment_2 )
+{
+ cout << "ANode:: ...test_limit_increment_2\n";
+
+ Limit limit("name",10); // Limit of 10
+ for(int i = 0; i < 20; i++) {
+ // increment should keep increasing limit value, *EVEN* if over the limit. See ECFLOW-324
+ std::string path = boost::lexical_cast<std::string>(i);
+ limit.increment(1,path);
+ BOOST_CHECK_MESSAGE(limit.value() == i + 1,"Expected limit value of " << i + 1 << " but found " << limit.value());
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_limit_decrement )
+{
+ cout << "ANode:: ...test_limit_decrement\n";
+
+ Ecf::set_server(true); // needed to test state_change_numbers
+
+ Limit limit("name",10); // Limit of 10
+ unsigned int expected_state_change_no = limit.state_change_no();
+
+ limit.increment(1,"path"); expected_state_change_no++; // consume 1 token, should increment state change no
+ BOOST_CHECK_MESSAGE(limit.value() == 1,"Expected limit of value 1 but found " << limit.value());
+ BOOST_CHECK_MESSAGE(limit.paths().size() == 1,"Expected 1 task path but found " << limit.paths().size());
+ BOOST_CHECK_MESSAGE( limit.state_change_no() == expected_state_change_no,"Expected increment to increase state change no, expected " << expected_state_change_no << " but found " << limit.state_change_no());
+
+ // Since 'path_x' is NOT in the list of paths stored by the limit, there should be NO change to state_change_no
+ limit.decrement(1,"path_x");
+ BOOST_CHECK_MESSAGE(limit.value() == 1," decrement of path that does not exist, should not affect the Limit: Expected limit of value 1 but found " << limit.value());
+ BOOST_CHECK_MESSAGE(limit.paths().size() == 1," decrement of path that does not exist, should not affect the Limit : Expected 1 task path but found " << limit.paths().size());
+ BOOST_CHECK_MESSAGE( limit.state_change_no() == expected_state_change_no,"Expected no change in state change no, expected " << expected_state_change_no << " but found " << limit.state_change_no());
+
+ // Multiple decrements should leave Limit of value = 0, and not a negative number
+ limit.decrement(1,"path"); expected_state_change_no++;
+ BOOST_CHECK_MESSAGE( limit.state_change_no() == expected_state_change_no,"Expected decrement to increase state change no, expected " << expected_state_change_no << " but found " << limit.state_change_no());
+
+ // Since we have removed 'path' from the limit expect no further state changes
+ limit.decrement(1,"path");
+ limit.decrement(1,"path");
+ limit.decrement(1,"path");
+ BOOST_CHECK_MESSAGE(limit.value() == 0,"Expected limit of value 0 but found " << limit.value());
+ BOOST_CHECK_MESSAGE(limit.paths().size() == 0,"Expected no task paths but found " << limit.paths().size());
+ BOOST_CHECK_MESSAGE( limit.state_change_no() == expected_state_change_no,"Expected no change to state change no, expected " << expected_state_change_no << " but found " << limit.state_change_no());
+
+ Ecf::set_server(false); // needed to test state_change_numbers
+}
+
+
+// Globals used throughout the test
+static std::string fileName = "testLimit.txt";
+BOOST_AUTO_TEST_CASE( test_LimitDefaultConstructor_serialisation )
+{
+ cout << "ANode:: ...test_LimitDefaultConstructor_serialisation \n";
+
+ doSaveAndRestore<Limit>(fileName);
+}
+
+BOOST_AUTO_TEST_CASE( test_Limit_serialisation )
+{
+ cout << "ANode:: ...test_Limit_serialisation\n";
+ Limit saved1("limitName",100 );
+ doSaveAndRestore(fileName,saved1);
+
+ std::set<std::string> paths; paths.insert("path1"); paths.insert("path2");
+ Limit saved2("limitName",100,10,paths );
+ doSaveAndRestore(fileName,saved2);
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/ANode/test/TestMigration.cpp b/ANode/test/TestMigration.cpp
new file mode 100644
index 0000000..1ff36f7
--- /dev/null
+++ b/ANode/test/TestMigration.cpp
@@ -0,0 +1,113 @@
+#if defined(TEXT_ARCHIVE) || !defined(BINARY_ARCHIVE) && !defined(PORTABLE_BINARY_ARCHIVE) && !defined(EOS_PORTABLE_BINARY_ARCHIVE)
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/test/unit_test.hpp>
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "Alias.hpp"
+#include "Ecf.hpp"
+#include "SerializationTest.hpp"
+#include "MyDefsFixture.hpp"
+#include "File.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::posix_time;
+using namespace boost::gregorian;
+namespace fs = boost::filesystem;
+
+// If you are updating the tests, *MAKE SURE* to check out test/data/migration/* files
+//#define UPDATE_TESTS 1
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+//
+// These test are used for future release. They help to ensure that we have
+// backward compatibility.i.e future release can open file, created by an earlier release
+//
+BOOST_AUTO_TEST_CASE( test_migration_restore_def_con_3_0_1 )
+{
+ cout << "ANode:: ...test_migration_restore_def_con_3_0_1\n";
+
+ std::string file_name = File::test_data("ANode/test/data/migration/default_constructor/","ANode");
+
+ // Create migration data
+ Defs defs;
+ Suite suite;
+ Family family;
+ Task task;
+
+ // Remove host dependent variables from server state, so that we can run on other platforms
+ defs.set_server().delete_server_variable("ECF_LOG");
+ defs.set_server().delete_server_variable("ECF_CHECK");
+ defs.set_server().delete_server_variable("ECF_CHECKOLD");
+
+ // We use .def extension so that we copy over writable files with extension .def to
+ // other platforms during incremental build's
+#ifdef UPDATE_TESTS
+ // remember to check out data
+ doSave(file_name + "Defs.def",defs);
+ doSave(file_name + "Suite.def",suite);
+ doSave(file_name + "Family.def",family);
+ doSave(file_name + "Task.def",task);
+ doSave(file_name + "Limit.def",Limit());
+#else
+ Ecf::set_debug_equality(true);
+ do_restore<Defs>(file_name + "Defs.def",defs);
+ do_restore<Suite>(file_name + "Suite.def",suite);
+ do_restore<Family>(file_name + "Family.def",family);
+ do_restore<Task>(file_name + "Task.def",task);
+ do_restore<Limit>(file_name + "Limit.def",Limit());
+ Ecf::set_debug_equality(false);
+#endif
+}
+
+//#define UPDATE_TESTS 1
+
+BOOST_AUTO_TEST_CASE( test_migration_restore_boost_checkpt_file )
+{
+ cout << "ANode:: ...test_migration_restore_boost_checkpt_file\n";
+
+ std::string file_name = File::test_data("ANode/test/data/migration/fixture/","ANode");
+
+ // Create migration data
+ // This will create a pre-built definition.
+ // If the definition is changed we will need to update this test.
+ // **Keep*** old checkpt test data, to ensure future ecflow versions can be migrated
+ // **Update** here for future boost updates
+ // **IF MyDefsFixture is changed, we need to ensure we can migrate it to future versions
+ MyDefsFixture fixture("boost.checkpt");
+
+ // Allow the test data, to be used on other platforms
+ fixture.remove_host_depedent_server_variables();
+
+#ifdef UPDATE_TESTS
+ // remember to check out data
+ doSave(file_name + "boost.checkpt",fixture.fixtureDefsFile());
+#else
+ Ecf::set_debug_equality(true);
+ do_restore<Defs>(file_name + "boost.checkpt",fixture.fixtureDefsFile());
+ Ecf::set_debug_equality(false);
+#endif
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
+
+#endif
diff --git a/ANode/test/TestMissNextTimeSlot.cpp b/ANode/test/TestMissNextTimeSlot.cpp
new file mode 100644
index 0000000..63c8876
--- /dev/null
+++ b/ANode/test/TestMissNextTimeSlot.cpp
@@ -0,0 +1,114 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #22 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <boost/test/unit_test.hpp>
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Task.hpp"
+
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_miss_next_time_slot )
+{
+ cout << "ANode:: ...test_miss_next_time_slot\n";
+
+ // Start TIME at 9:30
+ // This test is custom. When the user interactively forces a node to the complete state,
+ // But where the user set of time slots. In this case the node should complete and then
+ // requee and miss the next time. If this is repeated, eventually we should reach the
+ // end of the time slot. In which case the node should *not* re-queue and stay complete
+ //
+ // When the node is then re-queued check that the time has been correctly reset.
+
+ // suite s1
+ // task t1
+ // time 10:00
+ // time 11:00
+ // time 12:00
+ // time 13:00
+ // endsuite
+ Defs the_defs;
+ suite_ptr suite = the_defs.add_suite("s1");
+ task_ptr t1 = suite->add_task("t1");
+ t1->addTime( TimeAttr(10,0) );
+ t1->addTime( TimeAttr(11,0) );
+ t1->addTime( TimeAttr(12,0) );
+ t1->addTime( TimeAttr(13,0) );
+ ClockAttr clockAttr(15,12,2010,false);
+ clockAttr.set_gain(9/*hour*/,30/*minutes*/); // *start* at 9:30
+ suite->addClock( clockAttr );
+
+ suite->begin();
+
+ // get all the time attributes
+ const TimeSeries& ts_10 = t1->timeVec()[0].time_series();
+ const TimeSeries& ts_11 = t1->timeVec()[1].time_series();
+ const TimeSeries& ts_12 = t1->timeVec()[2].time_series();
+ const TimeSeries& ts_13 = t1->timeVec()[3].time_series();
+ BOOST_CHECK_MESSAGE( ts_10.is_valid(), "Expected time 10 to be valid since we started at 9:30 ");
+ BOOST_CHECK_MESSAGE( ts_11.is_valid(), "Expected time 11 to be valid since we started at 9:30");
+ BOOST_CHECK_MESSAGE( ts_12.is_valid(), "Expected time 12 to be valid since we started at 9:30");
+ BOOST_CHECK_MESSAGE( ts_13.is_valid(), "Expected time 13 to be valid since we started at 9:30");
+
+ const TimeSlot& time_10 = t1->timeVec()[0].time_series().get_next_time_slot();
+ const TimeSlot& time_11 = t1->timeVec()[1].time_series().get_next_time_slot();
+ const TimeSlot& time_12 = t1->timeVec()[2].time_series().get_next_time_slot();
+ const TimeSlot& time_13 = t1->timeVec()[3].time_series().get_next_time_slot();
+ BOOST_CHECK_MESSAGE( time_10 == TimeSlot(10,0),"Expected next time slot of 10:00 but found " << time_10.toString());
+ BOOST_CHECK_MESSAGE( time_11 == TimeSlot(11,0),"Expected next time slot of 11:00 but found " << time_11.toString());
+ BOOST_CHECK_MESSAGE( time_12 == TimeSlot(12,0),"Expected next time slot of 12:00 but found " << time_12.toString());
+ BOOST_CHECK_MESSAGE( time_13 == TimeSlot(13,0),"Expected next time slot of 13:00 but found " << time_13.toString());
+
+ // before test flags should be clear
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear,before test");
+
+ t1->miss_next_time_slot();
+ BOOST_CHECK_MESSAGE(t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be set,");
+ BOOST_CHECK_MESSAGE( !ts_10.is_valid(), "Expected time 10 to be expired");
+ BOOST_CHECK_MESSAGE( ts_11.is_valid(), "Expected time 11 to be valid since we started at 9:30");
+ BOOST_CHECK_MESSAGE( ts_12.is_valid(), "Expected time 12 to be valid since we started at 9:30");
+ BOOST_CHECK_MESSAGE( ts_13.is_valid(), "Expected time 13 to be valid since we started at 9:30");
+
+ // Calling miss_next_time_slot again, should have *NO* effect, since its only takes affect when NO_REQUE_IF_SINGLE_TIME_DEP is clear
+ t1->miss_next_time_slot();
+ BOOST_CHECK_MESSAGE(t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be set,");
+ BOOST_CHECK_MESSAGE( !ts_10.is_valid(), "Expected time 10 to be expired");
+ BOOST_CHECK_MESSAGE( ts_11.is_valid(), "Expected time 11 to be valid since we started at 9:30");
+ BOOST_CHECK_MESSAGE( ts_12.is_valid(), "Expected time 12 to be valid since we started at 9:30");
+ BOOST_CHECK_MESSAGE( ts_13.is_valid(), "Expected time 13 to be valid since we started at 9:30");
+
+ // Clear the flag and call miss_next_time_slot, this time an additional time slot should have expired
+ t1->flag().clear(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP);
+ t1->miss_next_time_slot();
+ BOOST_CHECK_MESSAGE( !ts_10.is_valid(), "Expected time 10 to be expired");
+ BOOST_CHECK_MESSAGE( !ts_11.is_valid(), "Expected time 11 to be expired");
+ BOOST_CHECK_MESSAGE( ts_12.is_valid(), "Expected time 12 to be valid since we started at 9:30");
+ BOOST_CHECK_MESSAGE( ts_13.is_valid(), "Expected time 13 to be valid since we started at 9:30");
+
+ // call twice more, to expire all time slots
+ t1->flag().clear(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP);
+ t1->miss_next_time_slot();
+ t1->flag().clear(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP);
+ t1->miss_next_time_slot();
+ BOOST_CHECK_MESSAGE( !ts_10.is_valid(), "Expected time 10 to be expired");
+ BOOST_CHECK_MESSAGE( !ts_11.is_valid(), "Expected time 11 to be expired");
+ BOOST_CHECK_MESSAGE( !ts_12.is_valid(), "Expected time 12 to be expired");
+ BOOST_CHECK_MESSAGE( !ts_13.is_valid(), "Expected time 13 to be expired");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ANode/test/TestNodeBeginReque.cpp b/ANode/test/TestNodeBeginReque.cpp
new file mode 100644
index 0000000..ffc5de4
--- /dev/null
+++ b/ANode/test/TestNodeBeginReque.cpp
@@ -0,0 +1,75 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #22 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <boost/test/unit_test.hpp>
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_node_begin_reque_hybrid )
+{
+ cout << "ANode:: ...test_node_begin_reque_hybrid\n";
+
+ // Create a suite with a *HYBRID* clock, and tasks with day,date and cron time attributes
+ defs_ptr the_defs = Defs::create();
+ suite_ptr s1 = the_defs->add_suite( "s1" ) ;
+ s1->addClock( ClockAttr(true) );
+ family_ptr f1 = s1->add_family( "f1" ) ;
+
+ CronAttr cron;
+ std::vector<int> week_days; week_days.push_back(0); week_days.push_back(1);
+ cron.addWeekDays(week_days);
+ cron.add_time_series(10,10,true);
+
+ // For task t1 which has day attribute. For this test to succeed the day must not match today day.
+ // So that under the hybrid clock, its is set to complete
+ boost::gregorian::date todays_date = Calendar::second_clock_time().date();
+ int todays_day_as_number = todays_date.day_of_week().as_number();
+ int tommorrow = todays_day_as_number + 1;
+ if (tommorrow > 6) tommorrow = 0;
+
+ task_ptr t1 = f1->add_task("t1"); t1->addDay( DayAttr( DayAttr::Day_t(tommorrow) ));
+ task_ptr t2 = f1->add_task("t2"); t2->addDate( DateAttr(0,0,2014));
+ task_ptr t3 = f1->add_task("t3"); t3->addCron( cron );
+
+ // begin the suite, Under hybrid clock, nodes with day,date and cron attributes should be marked as complete
+ the_defs->beginAll();
+ BOOST_CHECK_MESSAGE(t1->state() == NState::COMPLETE,"Expected node to be complete");
+ BOOST_CHECK_MESSAGE(t2->state() == NState::COMPLETE,"Expected node to be complete");
+ BOOST_CHECK_MESSAGE(t3->state() == NState::COMPLETE,"Expected node to be complete");
+
+ // Change the node state, so that we can test re-queue
+ t1->set_state(NState::QUEUED);
+ t2->set_state(NState::QUEUED);
+ t3->set_state(NState::QUEUED);
+ BOOST_CHECK_MESSAGE(t1->state() == NState::QUEUED,"Expected node to be QUEUED");
+ BOOST_CHECK_MESSAGE(t2->state() == NState::QUEUED,"Expected node to be QUEUED");
+ BOOST_CHECK_MESSAGE(t3->state() == NState::QUEUED,"Expected node to be QUEUED");
+
+ // Now re-queue all and make sure re-queue also Under hybrid clock, nodes with day,date and cron
+ // attributes should be marked as complete
+ the_defs->requeue();
+ BOOST_CHECK_MESSAGE(t1->state() == NState::COMPLETE,"Expected node to be complete");
+ BOOST_CHECK_MESSAGE(t2->state() == NState::COMPLETE,"Expected node to be complete");
+ BOOST_CHECK_MESSAGE(t3->state() == NState::COMPLETE,"Expected node to be complete");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ANode/test/TestNodeState.cpp b/ANode/test/TestNodeState.cpp
new file mode 100644
index 0000000..5fc9fe2
--- /dev/null
+++ b/ANode/test/TestNodeState.cpp
@@ -0,0 +1,127 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <iostream>
+#include <stdlib.h>
+
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_state_hierarchy )
+{
+ cout << "ANode:: ...test_state_hierarchy\n";
+
+ // Create a defs file corresponding to:
+ //suite s1
+ // family f1
+ // task t1
+ // task t2
+ // task t3
+ // task t4
+ // task t5
+ // endfamily
+ //endsuite
+ Defs theDefs;
+ suite_ptr s1 = theDefs.add_suite( "suite1" );
+ family_ptr f1 = s1->add_family( "family" );
+ task_ptr t1 = f1->add_task( "t1" );
+ task_ptr t2 = f1->add_task( "t2" );
+ task_ptr t3 = f1->add_task( "t3" );
+ task_ptr t4 = f1->add_task( "t4" );
+
+ NState::State result = s1->computedState(Node::IMMEDIATE_CHILDREN);
+ BOOST_REQUIRE_MESSAGE(result == NState::UNKNOWN,"Expected NState::UNKNOWN for suite but found " << NState::toString(result));
+
+ result = f1->computedState(Node::IMMEDIATE_CHILDREN);
+ BOOST_REQUIRE_MESSAGE(result == NState::UNKNOWN,"Expected NState::UNKNOWN for family but found " << NState::toString(result));
+
+ {
+ f1->setStateOnlyHierarchically(NState::QUEUED);
+ result = f1->computedState(Node::IMMEDIATE_CHILDREN);
+ BOOST_REQUIRE_MESSAGE(result == NState::QUEUED,"Expected NState::QUEUED for family but found " << NState::toString(result));
+ }
+
+ {
+ f1->setStateOnlyHierarchically(NState::QUEUED);
+ t1->set_state( NState::ABORTED);
+ result = f1->computedState(Node::IMMEDIATE_CHILDREN);
+ BOOST_REQUIRE_MESSAGE(result == NState::ABORTED,"Expected NState::ABORTED for family but found " << NState::toString(result));
+ }
+
+ {
+ f1->setStateOnlyHierarchically(NState::QUEUED);
+ t2->set_state( NState::SUBMITTED);
+ result = f1->computedState(Node::IMMEDIATE_CHILDREN);
+ BOOST_REQUIRE_MESSAGE(result == NState::SUBMITTED,"Expected NState::SUBMITTED for family but found " << NState::toString(result));
+ }
+
+ {
+ f1->setStateOnlyHierarchically(NState::QUEUED);
+ t3->set_state( NState::ACTIVE);
+ result = f1->computedState(Node::IMMEDIATE_CHILDREN);
+ BOOST_REQUIRE_MESSAGE(result == NState::ACTIVE,"Expected NState::ACTIVE for family but found " << NState::toString(result));
+ }
+
+ {
+ f1->setStateOnlyHierarchically(NState::QUEUED);
+ t3->set_state( NState::ACTIVE);
+ result = f1->computedState(Node::IMMEDIATE_CHILDREN);
+ BOOST_REQUIRE_MESSAGE(result == NState::ACTIVE,"Expected NState::ACTIVE for family but found " << NState::toString(result));
+ }
+
+ {
+ f1->setStateOnlyHierarchically(NState::QUEUED);
+ t1->set_state(NState::COMPLETE);
+ t2->set_state( NState::COMPLETE);
+ t3->set_state( NState::COMPLETE);
+ t4->set_state( NState::COMPLETE);
+ result = f1->computedState(Node::IMMEDIATE_CHILDREN);
+ BOOST_REQUIRE_MESSAGE(result == NState::COMPLETE,"Expected NState::COMPLETE for family but found " << NState::toString(result));
+ }
+
+ {
+ f1->setStateOnlyHierarchically(NState::QUEUED);
+ t1->set_state( NState::COMPLETE);
+ t2->set_state( NState::ACTIVE);
+ t3->set_state( NState::ACTIVE);
+ t4->set_state( NState::QUEUED);
+ result = f1->computedState(Node::IMMEDIATE_CHILDREN);
+ BOOST_REQUIRE_MESSAGE(result == NState::ACTIVE,"Expected NState::ACTIVE for family but found " << NState::toString(result));
+ }
+
+ {
+ f1->setStateOnlyHierarchically(NState::QUEUED);
+ t1->set_state( NState::COMPLETE);
+ t2->set_state( NState::ACTIVE);
+ t3->set_state( NState::ABORTED);
+ t4->set_state( NState::QUEUED);
+ result = f1->computedState(Node::IMMEDIATE_CHILDREN);
+ BOOST_REQUIRE_MESSAGE(result == NState::ABORTED,"Expected NState::ABORTED for family but found " << NState::toString(result));
+ }
+
+ { // ECFLOW-347
+ f1->setStateOnlyHierarchically(NState::UNKNOWN);
+ t1->set_state( NState::COMPLETE);
+ result = f1->computedState(Node::IMMEDIATE_CHILDREN);
+ BOOST_REQUIRE_MESSAGE(result == NState::COMPLETE,"Expected NState::COMPLETE for family but found " << NState::toString(result));
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ANode/test/TestOrder.cpp b/ANode/test/TestOrder.cpp
new file mode 100644
index 0000000..3820ce5
--- /dev/null
+++ b/ANode/test/TestOrder.cpp
@@ -0,0 +1,336 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/test/unit_test.hpp>
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+template <typename T>
+static std::vector<std::string> toStrVec(const std::vector<T>& vec)
+{
+ std::vector<std::string> retVec; retVec.reserve(vec.size());
+ BOOST_FOREACH(T s, vec) { retVec.push_back(s->name()); }
+ return retVec;
+}
+
+std::string toString(const std::vector<std::string>& c)
+{
+ std::stringstream ss;
+ std::copy (c.begin(), c.end(), std::ostream_iterator <std::string> (ss, ", "));
+ return ss.str();
+}
+
+static void test_invariants(Defs& the_defs, int line) {
+ std::string errorMsg;
+ bool passed = the_defs.checkInvariants(errorMsg);
+ BOOST_REQUIRE_MESSAGE( passed,"Invariants failed " << errorMsg << " at line " << line);
+}
+
+
+BOOST_AUTO_TEST_CASE( test_order )
+{
+ cout << "ANode:: ...test_order\n" ;
+ std::vector<std::string> vec; vec.reserve(5);
+ vec.push_back("a");
+ vec.push_back("A");
+ vec.push_back("b");
+ vec.push_back("B");
+ vec.push_back("c");
+ Defs theDefs; {
+ for(size_t s = 0; s < vec.size(); s++) {
+ suite_ptr suite = theDefs.add_suite( vec[s] ) ;
+ for(size_t f = 0; f < vec.size(); f++) {
+ family_ptr fam = suite->add_family( vec[f] ) ;
+ for(size_t t = 0; t < vec.size(); t++) {
+ fam->add_task( vec[t] );
+ }
+ }
+ }
+ }
+
+ std::vector<std::string> alpha;
+ alpha.push_back("a");
+ alpha.push_back("A");
+ alpha.push_back("b");
+ alpha.push_back("B");
+ alpha.push_back("c");
+
+ std::vector<std::string> order;
+ order.push_back("c");
+ order.push_back("B");
+ order.push_back("b");
+ order.push_back("A");
+ order.push_back("a");
+
+ // Test suite ordering ==========================================================================
+ // In init state all suite should be in alpha order
+ theDefs.order(theDefs.findAbsNode("/A").get(), NOrder::ALPHA);
+ test_invariants(theDefs,__LINE__);
+ BOOST_REQUIRE_MESSAGE( toStrVec(theDefs.suiteVec()) == alpha,"NOrder::ALPHA expected " << toString(alpha) << " but found " << toString(toStrVec(theDefs.suiteVec())) );
+
+ // sort in reverse order
+ theDefs.order(theDefs.findAbsNode("/a").get(), NOrder::ORDER);
+ test_invariants(theDefs,__LINE__);
+ BOOST_REQUIRE_MESSAGE( toStrVec(theDefs.suiteVec()) == order,"NOrder::ORDER expected " << toString(order) << " but found " << toString(toStrVec(theDefs.suiteVec())) );
+
+ // Change back to alpha, then move suite 'c' to the top
+ theDefs.order(theDefs.findAbsNode("/A").get(), NOrder::ALPHA);
+ BOOST_REQUIRE_MESSAGE( toStrVec(theDefs.suiteVec()) == alpha,"NOrder::ALPHA expected " << toString(alpha) << " but found " << toString(toStrVec(theDefs.suiteVec())) );
+ test_invariants(theDefs,__LINE__);
+
+ std::vector<std::string> expected;
+ expected.push_back("c");
+ expected.push_back("a");
+ expected.push_back("A");
+ expected.push_back("b");
+ expected.push_back("B");
+ theDefs.order(theDefs.findAbsNode("/c").get(), NOrder::TOP);
+ test_invariants(theDefs,__LINE__);
+ BOOST_REQUIRE_MESSAGE( toStrVec(theDefs.suiteVec()) == expected,"NOrder::TOP expected " << toString(expected) << " but found " << toString(toStrVec(theDefs.suiteVec())) );
+
+ // move suite 'c' back to the bottom
+ theDefs.order(theDefs.findAbsNode("/c").get(), NOrder::BOTTOM);
+ test_invariants(theDefs,__LINE__);
+ BOOST_REQUIRE_MESSAGE( toStrVec(theDefs.suiteVec()) == alpha,"NOrder::BOTTOM order not as expected" );
+
+ // move suite 'a' up one place. Should be no change, since its already at the top
+ theDefs.order(theDefs.findAbsNode("/a").get(), NOrder::UP);
+ test_invariants(theDefs,__LINE__);
+ BOOST_REQUIRE_MESSAGE( toStrVec(theDefs.suiteVec()) == alpha,"NOrder::UP order not as expected" );
+
+ // move suite 'c' down one place. Should be no change, since its already at the bottom
+ theDefs.order(theDefs.findAbsNode("/c").get(), NOrder::DOWN);
+ test_invariants(theDefs,__LINE__);
+ BOOST_REQUIRE_MESSAGE( toStrVec(theDefs.suiteVec()) == alpha,"NOrder::DOWN order not as expected" );
+
+ // Move suite 'a' down by one place
+ expected.clear();
+ expected.push_back("A");
+ expected.push_back("a");
+ expected.push_back("b");
+ expected.push_back("B");
+ expected.push_back("c");
+ theDefs.order(theDefs.findAbsNode("/a").get(), NOrder::DOWN);
+ test_invariants(theDefs,__LINE__);
+ BOOST_REQUIRE_MESSAGE( toStrVec(theDefs.suiteVec()) == expected,"NOrder::DOWN order not as expected" );
+
+ // Move suite 'b' up by one place
+ expected.clear();
+ expected.push_back("A");
+ expected.push_back("b");
+ expected.push_back("a");
+ expected.push_back("B");
+ expected.push_back("c");
+ theDefs.order(theDefs.findAbsNode("/b").get(), NOrder::UP);
+ test_invariants(theDefs,__LINE__);
+ BOOST_REQUIRE_MESSAGE( toStrVec(theDefs.suiteVec()) == expected,"NOrder::UP order not as expected" );
+
+
+ // Test family ordering ==========================================================================
+ // In init state all suite should be in alpha order
+ suite_ptr suite = theDefs.findSuite("a");
+ BOOST_REQUIRE_MESSAGE( suite.get() ,"Expected suite /a to exist " );
+
+ theDefs.order(theDefs.findAbsNode("/a/a").get(), NOrder::ALPHA);
+ test_invariants(theDefs,__LINE__);
+ BOOST_REQUIRE_MESSAGE( toStrVec(suite->nodeVec()) == alpha,"NOrder::ALPHA Init order " << toString(toStrVec(suite->nodeVec())) << " not as expected " << toString(alpha));
+
+ // sort in reverse order
+ std::sort(expected.begin(),expected.end(),std::greater<std::string>());
+ suite->order(theDefs.findAbsNode("/a/a").get(), NOrder::ORDER);
+ test_invariants(theDefs,__LINE__);
+ BOOST_REQUIRE_MESSAGE( toStrVec(suite->nodeVec()) == order,"NOrder::ORDER order " << toString(toStrVec(suite->nodeVec())) << " not as expected " << toString(order));
+
+ // Change back to alpha, then move family 'e' to the top
+ suite->order(theDefs.findAbsNode("/a/a").get(), NOrder::ALPHA);
+ BOOST_REQUIRE_MESSAGE( toStrVec(suite->nodeVec()) == alpha,"NOrder::ALPHA expected " << toString(alpha) << " but found " << toString(toStrVec(suite->nodeVec())) );
+ test_invariants(theDefs,__LINE__);
+ expected.clear();
+ expected.push_back("c");
+ expected.push_back("a");
+ expected.push_back("A");
+ expected.push_back("b");
+ expected.push_back("B");
+ suite->order(theDefs.findAbsNode("/a/c").get(), NOrder::TOP);
+ BOOST_REQUIRE_MESSAGE( toStrVec(suite->nodeVec()) == expected,"NOrder::TOP order " << toString(toStrVec(suite->nodeVec())) << " not as expected " << toString(expected));
+
+ // move family 'c' back to the bottom
+ suite->order(theDefs.findAbsNode("/a/c").get(), NOrder::BOTTOM);
+ test_invariants(theDefs,__LINE__);
+ BOOST_REQUIRE_MESSAGE( toStrVec(suite->nodeVec()) == alpha,"NOrder::BOTTOM order " << toString(toStrVec(suite->nodeVec())) << " not as expected " << toString(alpha));
+
+ // move family 'a' up one place. Should be no change, since its already at the top
+ suite->order(theDefs.findAbsNode("/a/a").get(), NOrder::UP);
+ test_invariants(theDefs,__LINE__);
+ BOOST_REQUIRE_MESSAGE( toStrVec(suite->nodeVec()) == alpha,"NOrder::UP order " << toString(toStrVec(suite->nodeVec())) << " not as expected " << toString(alpha));
+
+ // move family 'c' down one place. Should be no change, since its already at the bottom
+ suite->order(theDefs.findAbsNode("/a/c").get(), NOrder::DOWN);
+ test_invariants(theDefs,__LINE__);
+ BOOST_REQUIRE_MESSAGE( toStrVec(suite->nodeVec()) == alpha,"NOrder::DOWN order " << toString(toStrVec(suite->nodeVec())) << " not as expected " << toString(alpha));
+
+ // Move family 'a' down by one place
+ expected.clear();
+ expected.push_back("A");
+ expected.push_back("a");
+ expected.push_back("b");
+ expected.push_back("B");
+ expected.push_back("c");
+ suite->order(theDefs.findAbsNode("/a/a").get(), NOrder::DOWN);
+ test_invariants(theDefs,__LINE__);
+ BOOST_REQUIRE_MESSAGE( toStrVec(suite->nodeVec()) == expected,"NOrder::DOWN order " << toString(toStrVec(suite->nodeVec())) << " not as expected " << toString(expected));
+
+ // Move family 'b' up by one place
+ suite->order(theDefs.findAbsNode("/a/a").get(), NOrder::ALPHA); // reset
+ test_invariants(theDefs,__LINE__);
+ expected.clear();
+ expected.push_back("a");
+ expected.push_back("b");
+ expected.push_back("A");
+ expected.push_back("B");
+ expected.push_back("c");
+ suite->order(theDefs.findAbsNode("/a/b").get(), NOrder::UP);
+ BOOST_REQUIRE_MESSAGE( toStrVec(suite->nodeVec()) == expected,"NOrder::UP order " << toString(toStrVec(suite->nodeVec())) << " not as expected " << toString(expected));
+
+
+ // Test Task ordering ==========================================================================
+ // In init state all tasks should be in alpha order
+ Family* family = theDefs.findAbsNode("/a/a")->isFamily();
+ BOOST_REQUIRE_MESSAGE( family ,"Expected family /a/a to exist " );
+
+ family->order(theDefs.findAbsNode("/a/a/a").get(), NOrder::ALPHA);
+ test_invariants(theDefs,__LINE__);
+ BOOST_REQUIRE_MESSAGE( toStrVec(family->nodeVec()) == alpha,"NOrder::ALPHA Init state " << toString(toStrVec(family->nodeVec())) << " not as expected " << toString(alpha));
+
+ // sort in reverse order
+ family->order(theDefs.findAbsNode("/a/a/a").get(), NOrder::ORDER);
+ test_invariants(theDefs,__LINE__);
+ BOOST_REQUIRE_MESSAGE( toStrVec(family->nodeVec()) == order,"NOrder::ORDER " << toString(toStrVec(family->nodeVec())) << " not as expected " << toString(order));
+
+ // Change back to alpha, then move task 'c' to the top
+ family->order(theDefs.findAbsNode("/a/a/a").get(), NOrder::ALPHA); // reset
+ expected.clear();
+ expected.push_back("c");
+ expected.push_back("a");
+ expected.push_back("A");
+ expected.push_back("b");
+ expected.push_back("B");
+ family->order(theDefs.findAbsNode("/a/a/c").get(), NOrder::TOP);
+ test_invariants(theDefs,__LINE__);
+ BOOST_REQUIRE_MESSAGE( toStrVec(family->nodeVec()) == expected,"NOrder::TOP order " << toString(toStrVec(family->nodeVec())) << " not as expected " << toString(expected));
+
+ // move task 'c' back to the bottom
+ family->order(theDefs.findAbsNode("/a/a/c").get(), NOrder::BOTTOM);
+ test_invariants(theDefs,__LINE__);
+ BOOST_REQUIRE_MESSAGE( toStrVec(family->nodeVec()) == alpha,"NOrder::BOTTOM order " << toString(toStrVec(family->nodeVec())) << " not as expected " << toString(alpha));
+
+ // move task 'a' up one place. Should be no change, since its already at the top
+ family->order(theDefs.findAbsNode("/a/a/a").get(), NOrder::UP);
+ test_invariants(theDefs,__LINE__);
+ BOOST_REQUIRE_MESSAGE( toStrVec(family->nodeVec()) == alpha,"NOrder::UP order " << toString(toStrVec(family->nodeVec())) << " not as expected " << toString(alpha));
+
+ // move task 'e' down one place. Should be no change, since its already at the bottom
+ family->order(theDefs.findAbsNode("/a/a/c").get(), NOrder::DOWN);
+ test_invariants(theDefs,__LINE__);
+ BOOST_REQUIRE_MESSAGE( toStrVec(family->nodeVec()) == alpha,"NOrder::DOWN order " << toString(toStrVec(family->nodeVec())) << " not as expected " << toString(alpha));
+
+ // Move task 'a' down by one place
+ expected.clear();
+ expected.push_back("A");
+ expected.push_back("a");
+ expected.push_back("b");
+ expected.push_back("B");
+ expected.push_back("c");
+ family->order(theDefs.findAbsNode("/a/a/a").get(), NOrder::DOWN);
+ test_invariants(theDefs,__LINE__);
+ BOOST_REQUIRE_MESSAGE( toStrVec(family->nodeVec()) == expected,"NOrder::DOWN order " << toString(toStrVec(family->nodeVec())) << " not as expected " << toString(expected));
+
+ // Move task 'b' up by one place
+ family->order(theDefs.findAbsNode("/a/a/b").get(), NOrder::DOWN);
+ expected.clear();
+ expected.push_back("A");
+ expected.push_back("a");
+ expected.push_back("B");
+ expected.push_back("b");
+ expected.push_back("c");
+ test_invariants(theDefs,__LINE__);
+ BOOST_REQUIRE_MESSAGE( toStrVec(family->nodeVec()) == expected,"NOrder::UP order " << toString(toStrVec(family->nodeVec())) << " not as expected " << toString(expected));
+}
+
+BOOST_AUTO_TEST_CASE( test_alias_order )
+{
+ cout << "ANode:: ...test_alias_order\n" ;
+ task_ptr task;
+ Defs theDefs; {
+ suite_ptr s = theDefs.add_suite("s");
+ task = s->add_task("t");
+ task->add_alias_only(); // alias0
+ task->add_alias_only(); // alias1
+ task->add_alias_only(); // alias2
+ task->add_alias_only(); // alias3
+ }
+
+ // Test alias ordering ==========================================================================
+ // In init state all suite should be in alpha order
+ alias_ptr alias0 = task->find_alias("alias0");
+ BOOST_REQUIRE_MESSAGE( alias0,"expected to find alias0");
+
+ std::vector<std::string> expected;
+ expected.push_back("alias1");
+ expected.push_back("alias0");
+ expected.push_back("alias2");
+ expected.push_back("alias3");
+ task->order(alias0.get(), NOrder::DOWN);
+ test_invariants(theDefs,__LINE__);
+ BOOST_REQUIRE_MESSAGE( toStrVec(task->aliases()) == expected,"NOrder::DOWN expected " << toString(expected) << " but found " << toString(toStrVec(task->aliases())) );
+
+
+ task->order(alias0.get(), NOrder::ALPHA);
+ test_invariants(theDefs,__LINE__);
+ expected.clear();
+ expected.push_back("alias0");
+ expected.push_back("alias1");
+ expected.push_back("alias2");
+ expected.push_back("alias3");
+ BOOST_REQUIRE_MESSAGE( toStrVec(task->aliases()) == expected,"NOrder::ALPHA expectex " << toString(expected) << " but found " << toString(toStrVec(task->aliases())) );
+
+
+ task->order(task->find_alias("alias3").get(), NOrder::UP);
+ test_invariants(theDefs,__LINE__);
+ expected.clear();
+ expected.push_back("alias0");
+ expected.push_back("alias1");
+ expected.push_back("alias3");
+ expected.push_back("alias2");
+ BOOST_REQUIRE_MESSAGE( toStrVec(task->aliases()) == expected,"NOrder::UP expected " << toString(expected) << " but found " << toString(toStrVec(task->aliases())) );
+
+ // sort in reverse order
+ std::sort(expected.begin(),expected.end(),std::greater<std::string>());
+ task->order(alias0.get(), NOrder::ORDER);
+ test_invariants(theDefs,__LINE__);
+ expected.clear();
+ expected.push_back("alias3");
+ expected.push_back("alias2");
+ expected.push_back("alias1");
+ expected.push_back("alias0");
+ BOOST_REQUIRE_MESSAGE( toStrVec(task->aliases()) == expected,"NOrder::ORDER expected " << toString(expected) << " but found " << toString(toStrVec(task->aliases())) );
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ANode/test/TestPersistence.cpp b/ANode/test/TestPersistence.cpp
new file mode 100644
index 0000000..e162430
--- /dev/null
+++ b/ANode/test/TestPersistence.cpp
@@ -0,0 +1,79 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+
+#include "MyDefsFixture.hpp"
+
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+BOOST_FIXTURE_TEST_SUITE( NodeTestSuite, MyDefsFixture )
+
+// Allow for multiple archives
+static void testPersistence(const Defs& fixtureDefs,ecf::Archive::Type at)
+{
+ std::string check_pt_file = "fixture_defs.check";
+ fixtureDefs.save_as_checkpt(check_pt_file,at);
+
+ Defs restoredDefs;
+ restoredDefs.restore_from_checkpt(check_pt_file,at);
+
+ bool theyCompare = (restoredDefs == fixtureDefs);
+ if (!theyCompare) {
+
+ std::cout << "Dump restored defs\n" << restoredDefs << "\n";
+ std::cout << "Dump fixture defs\n" << fixtureDefs << "\n";
+
+ BOOST_CHECK_MESSAGE(theyCompare,"restored defs file is not same as fixtureDefs defs file");
+ }
+
+ cout << " check pt file_size: " << fs::file_size(check_pt_file) << "\n";
+
+ // Uncomment if you want see what this file looks like
+ fs::remove(check_pt_file);
+}
+
+#if defined(BINARY_ARCHIVE)
+BOOST_AUTO_TEST_CASE( test_node_tree_persistence_binary )
+{
+ cout << left << setw(54) << "ANode:: ...test_node_tree_persistence_binary";
+ BOOST_CHECK_MESSAGE(true,""); // stop boost complaining about no assertions
+ testPersistence(fixtureDefsFile(),ecf::Archive::BINARY);
+}
+#elif defined(PORTABLE_BINARY_ARCHIVE)
+BOOST_AUTO_TEST_CASE( test_node_tree_persistence_portable_binary )
+{
+ cout << left << setw(54) << "ANode:: ...test_node_tree_persistence_portable_binary";
+ BOOST_CHECK_MESSAGE(true,""); // stop boost complaining about no assertions
+ testPersistence(fixtureDefsFile(),ecf::Archive::PORTABLE_BINARY);
+}
+#elif defined(EOS_PORTABLE_BINARY_ARCHIVE)
+BOOST_AUTO_TEST_CASE( test_node_tree_persistence_eos_portable_binary )
+{
+ cout << left << setw(54) << "ANode:: ...test_node_tree_persistence_eos_portable_binary";
+ BOOST_CHECK_MESSAGE(true,""); // stop boost complaining about no assertions
+ testPersistence(fixtureDefsFile(),ecf::Archive::EOS_PORTABLE_BINARY);
+}
+#else
+BOOST_AUTO_TEST_CASE( test_node_tree_persistence_text )
+{
+ cout << left << setw(54) << "ANode:: ...test_node_tree_persistence_text" ;
+ BOOST_CHECK_MESSAGE(true,""); // stop boost complaining about no assertions
+ testPersistence(fixtureDefsFile(),ecf::Archive::TEXT);
+}
+#endif
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ANode/test/TestPreProcessing.cpp b/ANode/test/TestPreProcessing.cpp
new file mode 100644
index 0000000..c102f40
--- /dev/null
+++ b/ANode/test/TestPreProcessing.cpp
@@ -0,0 +1,231 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+#include <set>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/test/unit_test.hpp>
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "File.hpp"
+#include "JobsParam.hpp"
+#include "Str.hpp"
+#include "Ecf.hpp"
+#include "System.hpp"
+
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+void findVariable(std::string& line, std::set<std::string>& variables)
+{
+ // scan for variables
+ // edit SMSFETCH "/home/ma/map/sms/smsfectch -F %ECF_FILES% -I %ECF_INCLUDE%"
+ // We can also have
+ //
+ // "%<VAR>:<substitute>% i.e if VAR exist use it, else use substitute
+ //
+ // i.e VAR is defined as BILL
+ // %VAR:fred --f% will either be "BILL" or if VAR is not defined "fred --f"
+ while ( 1 ) {
+ size_t firstPercentPos = line.find( Ecf::MICRO() );
+ if ( firstPercentPos == string::npos ) break;
+ size_t secondPercentPos = line.find( Ecf::MICRO(), firstPercentPos + 1 );
+ if ( secondPercentPos == string::npos ) break;
+ if ( secondPercentPos - firstPercentPos <= 1 ) break; // handle %% with no characters in between
+
+ string percentVar( line.begin() + firstPercentPos+1, line.begin() + secondPercentPos );
+
+ size_t firstColon = percentVar.find( ':' );
+ if ( firstColon != string::npos ) {
+ string var( percentVar.begin(), percentVar.begin() + firstColon );
+ percentVar = var;
+ }
+
+ // Ignore auto-generated variables
+ if ( percentVar.find("ECF_") == string::npos &&
+ percentVar != "DATE" &&
+ percentVar != "DAY" &&
+ percentVar != "DD" &&
+ percentVar != "DOW" &&
+ percentVar != "DOY" &&
+ percentVar != "MM" &&
+ percentVar != "MONTH" &&
+ percentVar != "YYYY" &&
+ percentVar != "TASK" &&
+ percentVar != "FAMILY" &&
+ percentVar != "FAMILY1" &&
+ percentVar != "SUITE"
+ ) {
+ variables.insert( percentVar );
+ }
+
+ //std::cerr << "line before delete " << line << "\n";
+ line.erase(firstPercentPos, secondPercentPos - firstPercentPos + 1);
+ //std::cerr << "line after delete " << line << "\n";
+ }
+}
+
+void autoDiscoverVariables(const std::string& directory, std::set<std::string>& variables)
+{
+ fs::path full_path( fs::initial_path<fs::path>() );
+ full_path = fs::system_complete( fs::path( directory ) );
+
+ BOOST_CHECK(fs::exists( full_path ));
+ BOOST_CHECK(fs::is_directory( full_path ));
+
+ //std::cout << "\nIn directory: " << full_path.directory_string() << "\n\n";
+ fs::directory_iterator end_iter;
+ for ( fs::directory_iterator dir_itr( full_path ); dir_itr != end_iter; ++dir_itr ) {
+ try {
+ fs::path relPath(directory + "/" + dir_itr->path().filename().string());
+
+ // recurse down directories
+ if ( fs::is_directory(dir_itr->status()) ) {
+ autoDiscoverVariables(relPath.string(),variables);
+ continue;
+ }
+ // std::cout << "......autoDiscoverVariables for file " << relPath.string() << "\n";
+ if (relPath.extension() != ".h") continue; // Only look at .h files
+
+ // open the file, and find variables.
+ std::vector<std::string> lines;
+ if ( File::splitFileIntoLines(relPath.string(), lines) ) {
+ for(size_t i = 0; i < lines.size(); ++i) {
+ findVariable(lines[i], variables);
+ }
+ }
+ }
+ catch ( const std::exception & ex ) {
+ std::cout << "Exception::" << dir_itr->path().filename() << " " << ex.what() << std::endl;
+ }
+ }
+}
+
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+// *Auto* discover the good/bad sms files
+void test_sms_preprocessing(const std::string& directory, bool pass)
+{
+// cerr << " directory = " << directory << "\n";
+
+ // SET ECF_HOME
+ std::string smshome = directory;
+
+ fs::path full_path( fs::initial_path<fs::path>() );
+ full_path = fs::system_complete( fs::path( directory ) );
+ BOOST_CHECK(fs::exists( full_path ));
+ BOOST_CHECK(fs::is_directory( full_path ));
+
+ // Create a defs file, where the task name mirrors the sms files in the given directory
+ Defs theDefs;
+ {
+ suite_ptr suite = theDefs.add_suite("suite");
+ suite->addVariable( Variable( Str::ECF_INCLUDE(), "$ECF_HOME/includes" ) );
+ suite->addVariable( Variable( Str::ECF_OUT(), "$ECF_HOME" ) );
+ suite->addVariable( Variable( "SLEEPTIME", "10" ) );
+ family_ptr fam = suite->add_family( "family" );
+
+ // for operations auto discover the variables used in the header files and give
+ // them a dummy value. This would allow the test to pass when doing
+ // variable substitution. hence if variable substitution fails its likely to be
+ // a bug in autoDiscoverVariables
+ std::set<std::string> discoveredVariables;
+ autoDiscoverVariables(smshome + "/includes", discoveredVariables );
+ BOOST_FOREACH(const string& var, discoveredVariables) {
+// cerr << "autoDiscoverVariables = " << var << "\n";
+ suite->addVariable( Variable( var, "gobblygook" ) );
+ }
+
+ //std::cout << "\nIn directory: " << full_path.directory_string() << "\n\n";
+ fs::directory_iterator end_iter;
+ for (fs::directory_iterator dir_itr( full_path ); dir_itr != end_iter; ++dir_itr) {
+ try {
+ fs::path relPath( directory + "/" + dir_itr->path().filename().string());
+
+ // Ignore directores were only interested in .ecf files.
+ if (fs::is_directory(relPath)) continue;
+ if (File::getExt(relPath.filename().string()) != "ecf" ) continue; // ignore other files
+
+ //std::cout << "......Parsing file " << relPath.string() << "\n";
+ //std::cout << "adding task name " << relPath.leaf() << "\n";
+ fam->add_task( relPath.stem().string() );
+ }
+ catch ( const std::exception & ex ) {
+ std::cout << "Exception " << dir_itr->path().filename() << " " << ex.what() << std::endl;
+ }
+ }
+ //cerr << "The defs\n" << theDefs << "\n";
+ }
+
+ // get all the task
+ std::vector<Task*> theTasks;
+ theDefs.getAllTasks(theTasks);
+
+ // Override ECF_HOME. ECF_HOME is need to locate the ecf files
+ theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(),smshome);
+
+ /// begin , will cause creation of generated variables. The generated variables
+ /// are used in client scripts(sms) and used to locate the sms files
+ theDefs.beginAll();
+
+ // Test Job creator, this will pre-process and perform variable substitution on ecf files
+ BOOST_FOREACH(Task* t, theTasks) {
+
+ //cout << "task " << t->absNodePath() << "\n";
+ JobsParam jobsParam; // create jobs = false, spawn_jobs = false
+ bool ok = t-> submitJob( jobsParam ) ;
+
+ if ( pass ) { // Test expected to pass
+ BOOST_CHECK_MESSAGE(ok,"Failed to create jobs. " << jobsParam.getErrorMsg() );
+ }
+ else { // test expected to fail
+ BOOST_CHECK_MESSAGE(!ok,"Expected failure " << jobsParam.getErrorMsg() );
+ BOOST_CHECK_MESSAGE(!ok,"expected no passes but found " << t->absNodePath() << " passes");
+ // cerr << "\n" << jobsParam.getErrorMsg() << " \n"; // un-comment to ensure correct error message
+ }
+ }
+}
+
+
+BOOST_AUTO_TEST_CASE( test_good_sms )
+{
+ cout << "ANode:: ...test_good_ecf\n";
+
+ std::string path = File::test_data("ANode/test/data/SMSHOME2/good","ANode");
+
+ // All the sms in this directory are expected to pass
+ test_sms_preprocessing(path, true);
+}
+
+BOOST_AUTO_TEST_CASE( test_bad_sms )
+{
+ cout << "ANode:: ...test_bad_ecf\n";
+
+ std::string path = File::test_data("ANode/test/data/SMSHOME2/bad","ANode");
+
+ // All the sms in this directory are expected to fail
+ test_sms_preprocessing(path, false);
+
+ /// Destroy System singleton to avoid valgrind from complaining
+ System::destroy();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ANode/test/TestReplace.cpp b/ANode/test/TestReplace.cpp
new file mode 100644
index 0000000..e1790b7
--- /dev/null
+++ b/ANode/test/TestReplace.cpp
@@ -0,0 +1,575 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/make_shared.hpp>
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "Ecf.hpp"
+
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_replace_add_task )
+{
+ cout << "ANode:: ...test_replace_add_task\n" ;
+ defs_ptr clientDef = Defs::create(); {
+ suite_ptr suite = Suite::create( "suite1" ) ;
+ family_ptr fam = suite->add_family("family" ) ;
+ fam->add_task( "t2" );
+ clientDef->addSuite( suite );
+ }
+
+ // add Child t2 to the server defs
+ Defs serverDefs; {
+ suite_ptr suite = Suite::create( "suite1" ) ;
+ family_ptr fam = suite->add_family("family" ) ;
+ fam->add_task( "t1" );
+ serverDefs.addSuite( suite );
+ }
+
+ Defs expectedDefs; {
+ suite_ptr suite = Suite::create( "suite1" ) ;
+ family_ptr fam = suite->add_family("family" ) ;
+ fam->add_task( "t2" ); // notice we preserve client position, and not server position
+ fam->add_task( "t1" );
+ expectedDefs.addSuite( suite );
+ }
+
+ std::string errorMsg;
+ BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/suite1/family/t2",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
+ BOOST_CHECK_MESSAGE(expectedDefs == serverDefs,"expectedDefs and servers defs should be the same");
+}
+
+BOOST_AUTO_TEST_CASE( test_replace_add_suite )
+{
+ cout << "ANode:: ...test_replace_add_suite\n";
+ // In this test the server defs is *EMPTY* hence we should copy/move over the whole suite
+ // provided the a/ Path to node exists in the client def, b/ create nodes as needed is TRUE
+ Defs expectedDefs; {
+ suite_ptr suite = expectedDefs.add_suite( "suite1" ) ;
+ family_ptr fam = suite->add_family("family" ) ;
+ fam->add_task( "t1" );
+ fam->add_task( "t2" );
+ }
+
+ {
+ // The whole suite should get *MOVED* from clientDef to the *EMPTY* server def. i.e add
+ defs_ptr clientDef = Defs::create(); {
+ suite_ptr suite = clientDef->add_suite( "suite1" ) ;
+ family_ptr fam = suite->add_family("family" ) ;
+ fam->add_task( "t1" );
+ fam->add_task( "t2" );
+ }
+
+ // Server defs is empty
+ Defs serverDefs;
+
+ std::string errorMsg;
+ BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/suite1/family/t2",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
+ BOOST_CHECK_MESSAGE(expectedDefs == serverDefs,"expectedDefs and servers defs should be the same");
+ }
+
+ {
+ // The whole suite should get *MOVED* from clientDef to the *EMPTY* server def. i.e add
+ defs_ptr clientDef = Defs::create(); {
+ suite_ptr suite = clientDef->add_suite( "suite1" ) ;
+ family_ptr fam = suite->add_family("family" ) ;
+ fam->add_task( "t1" );
+ fam->add_task( "t2" );
+ }
+
+ // Server defs is empty
+ Defs serverDefs;
+
+ std::string errorMsg;
+ BOOST_REQUIRE_MESSAGE(serverDefs.replaceChild("/suite1/family",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
+ BOOST_CHECK_MESSAGE(expectedDefs == serverDefs,"expectedDefs and servers defs should be the same");
+ }
+
+ {
+ // The whole suite should get *MOVED* from clientDef to the *EMPTY* server def. i.e add
+ defs_ptr clientDef = Defs::create(); {
+ suite_ptr suite = clientDef->add_suite( "suite1" ) ;
+ family_ptr fam = suite->add_family("family" ) ;
+ fam->add_task( "t1" );
+ fam->add_task( "t2" );
+ }
+
+ // Server defs is empty
+ Defs serverDefs;
+
+ std::string errorMsg;
+ BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/suite1",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
+ BOOST_CHECK_MESSAGE(expectedDefs == serverDefs,"expectedDefs and servers defs should be the same");
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_replace_child )
+{
+ cout << "ANode:: ...test_replace_child\n" ;
+ defs_ptr clientDef = Defs::create(); {
+ suite_ptr suite = Suite::create( "suite1" ) ;
+ family_ptr fam = Family::create( "family" ) ;
+ fam->addTask( Task::create( "t1" ) );
+ suite->addFamily( fam );
+ clientDef->addSuite( suite );
+ }
+ Defs comparisonDef; {
+ suite_ptr suite = Suite::create( "suite1" ) ;
+ family_ptr fam = Family::create( "family" ) ;
+ fam->addTask( Task::create( "t1" ) );
+ suite->addFamily( fam );
+ comparisonDef.addSuite( suite );
+ }
+ BOOST_CHECK_MESSAGE(comparisonDef == *clientDef,"client and comparisonDef should be the same");
+
+ std::string errorMsg;
+ Defs serverDefs;
+ BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/suite1",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
+ BOOST_CHECK_MESSAGE(comparisonDef == serverDefs,"comparisonDef and servers defs should be the same");
+}
+
+BOOST_AUTO_TEST_CASE( test_replace_add_preserves_states )
+{
+ cout << "ANode:: ...test_replace_add_preserves_states\n" ;
+ defs_ptr clientDef = Defs::create(); {
+ suite_ptr suite = clientDef->add_suite( "suite1" ) ;
+ family_ptr fam = suite->add_family("family" ) ;
+ fam->add_task( "t1" );
+ fam->add_task( "t2" );
+ fam->add_task( "t3" );
+ fam->add_task( "t4" );
+ }
+
+ // add Child t4 to the server defs, the states on t1->t3 should be preserved
+ // The abort should be progagated up the node tree
+ family_ptr fam;
+ suite_ptr suite;
+ Defs serverDefs; {
+ suite = serverDefs.add_suite( "suite1" ) ;
+ fam = suite->add_family("family" ) ;
+ task_ptr t1 = fam->add_task( "t1" );
+ task_ptr t2 = fam->add_task( "t2" );
+ task_ptr t3 = fam->add_task( "t3" );
+ serverDefs.beginAll();
+ t1->set_state(NState::COMPLETE);
+ t2->set_state(NState::ABORTED);
+ t3->set_state(NState::ACTIVE);
+ }
+
+ //cout << serverDefs;
+ std::string errorMsg;
+ BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/suite1/family/t4",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
+
+ /// The Nodes t1,t2,t3 may have been replaced hence we must get Nodes again
+ node_ptr st1 = serverDefs.findAbsNode("/suite1/family/t1");
+ node_ptr st2 = serverDefs.findAbsNode("/suite1/family/t2");
+ node_ptr st3 = serverDefs.findAbsNode("/suite1/family/t3");
+ node_ptr st4 = serverDefs.findAbsNode("/suite1/family/t4");
+ BOOST_REQUIRE_MESSAGE(st1,"Expected to find task t1");
+ BOOST_REQUIRE_MESSAGE(st2,"Expected to find task t2");
+ BOOST_REQUIRE_MESSAGE(st3,"Expected to find task t3");
+ BOOST_REQUIRE_MESSAGE(st4,"Expected to find task t4");
+ BOOST_REQUIRE_MESSAGE(st1->state() == NState::COMPLETE," state on task t1 not preserved after replace");
+ BOOST_REQUIRE_MESSAGE(st2->state() == NState::ABORTED," state on task t2 not preserved after replace");
+ BOOST_REQUIRE_MESSAGE(st3->state() == NState::ACTIVE," state on task t3 not preserved after replace");
+ BOOST_REQUIRE_MESSAGE(st4->state() == NState::QUEUED," state on task t4 to be queued");
+ BOOST_REQUIRE_MESSAGE(fam->state() == NState::ABORTED,"Aborted should have propagated to family");
+ BOOST_REQUIRE_MESSAGE(suite->state() == NState::ABORTED,"Aborted should have propagated to suite");
+ BOOST_REQUIRE_MESSAGE(serverDefs.state() == NState::ABORTED,"Aborted should have propagated to Defs");
+}
+
+BOOST_AUTO_TEST_CASE( test_replace_preserves_sibling_states )
+{
+ cout << "ANode:: ...test_replace_preserves_sibling_states\n" ;
+ defs_ptr clientDef = Defs::create(); {
+ suite_ptr suite = Suite::create( "suite1" ) ;
+ family_ptr fam = suite->add_family("family" ) ;
+ fam->add_task( "t4" );
+ clientDef->addSuite( suite );
+ }
+
+ // add Child t4 to the server defs, the states on t1->t4 should be preserved
+ task_ptr t1,t2,t3;
+ Defs serverDefs; {
+ suite_ptr suite = serverDefs.add_suite( "suite1" ) ;
+ family_ptr fam = suite->add_family("family" ) ;
+ t1 = fam->add_task( "t1" ); t1->set_state(NState::COMPLETE);
+ t2 = fam->add_task( "t2" ); t2->set_state(NState::ABORTED);
+ t3 = fam->add_task( "t3" ); t3->set_state(NState::ACTIVE);
+ fam->add_task( "t4" );
+ }
+
+ std::string errorMsg;
+ BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/suite1/family/t4",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
+ BOOST_REQUIRE_MESSAGE(t1->state() == NState::COMPLETE," state on task t1 not preserved after replace");
+ BOOST_REQUIRE_MESSAGE(t2->state() == NState::ABORTED," state on task t2 not preserved after replace");
+ BOOST_REQUIRE_MESSAGE(t3->state() == NState::ACTIVE," state on task t3 not preserved after replace");
+}
+
+BOOST_AUTO_TEST_CASE( test_replace_preserves_begun_status )
+{
+ cout << "ANode:: ...test_replace_preserves_begun_status\n" ;
+ defs_ptr clientDef = Defs::create(); {
+ suite_ptr suite = clientDef->add_suite( "suite1" ) ;
+ family_ptr fam = suite->add_family( "family" ) ;
+ fam->addTask( Task::create( "t1" ) );
+ }
+ Defs comparisonDef; {
+ suite_ptr suite = comparisonDef.add_suite( "suite1" ) ;
+ family_ptr fam = suite->add_family( "family" ) ;
+ fam->addTask( Task::create( "t1" ) );
+ }
+ BOOST_CHECK_MESSAGE(comparisonDef == *clientDef,"client and comparisonDef should be the same");
+ comparisonDef.beginAll();
+
+ defs_ptr serverDefs = Defs::create(); {
+ suite_ptr suite = serverDefs->add_suite( "suite1" ) ;
+ family_ptr fam = suite->add_family( "family" ) ;
+ fam->addTask( Task::create( "t1" ) );
+ }
+ serverDefs->beginAll();
+
+ std::string errorMsg;
+ BOOST_REQUIRE_MESSAGE( serverDefs->replaceChild("/suite1",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
+ BOOST_REQUIRE_MESSAGE( serverDefs->findSuite("suite1"),"Can't find suite1");
+ BOOST_REQUIRE_MESSAGE( serverDefs->findSuite("suite1")->begun(),"Expected replaced suite to preserve begun status");
+ Ecf::set_debug_equality(true); // only has affect in DEBUG build
+ BOOST_CHECK_MESSAGE(comparisonDef == *serverDefs,"comparisonDef and servers defs should be the same");
+ Ecf::set_debug_equality(false);
+}
+
+BOOST_AUTO_TEST_CASE( test_replace_add_node )
+{
+ cout << "ANode:: ...test_replace_add_node\n" ;
+ defs_ptr clientDef = Defs::create(); {
+ suite_ptr suite = Suite::create( "suite1" ) ;
+ family_ptr fam = Family::create( "family" ) ;
+ fam->addTask( Task::create( "t1" ) );
+ suite->addFamily( fam );
+ suite->addTask( Task::create( "t2" ) );
+ clientDef->addSuite( suite );
+ }
+ Defs comparisonDef; {
+ suite_ptr suite = Suite::create( "suite1" ) ;
+ family_ptr fam = Family::create( "family" ) ;
+ fam->addTask( Task::create( "t1" ) );
+ suite->addFamily( fam );
+ suite->addTask( Task::create( "t2" ) );
+ comparisonDef.addSuite( suite );
+ }
+ BOOST_CHECK_MESSAGE(comparisonDef == *clientDef,"client and comparisonDef should be the same");
+
+
+ // Here /suite1/t2 does not exist in the server. Moved from client defs to server
+ Defs serverDefs; {
+ suite_ptr suite = Suite::create( "suite1" ) ;
+ family_ptr fam = Family::create( "family" ) ;
+ fam->addTask( Task::create( "t1" ) );
+ suite->addFamily( fam );
+ serverDefs.addSuite( suite );
+ }
+ std::string errorMsg;
+ BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/suite1/t2",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
+ BOOST_CHECK_MESSAGE(comparisonDef == serverDefs,"comparisonDef and servers defs should be the same");
+}
+
+BOOST_AUTO_TEST_CASE( test_replace_add_hierarchy )
+{
+ cout << "ANode:: ...test_replace_add_hierarchy\n" ;
+ defs_ptr clientDef = Defs::create(); {
+ suite_ptr suite = Suite::create( "suite1" ) ;
+ family_ptr fa = Family::create( "fa" ) ;
+ family_ptr fb = Family::create( "fb" ) ;
+ family_ptr fc = Family::create( "fc" ) ;
+ family_ptr fd = Family::create( "fd" ) ;
+ fa->addFamily( fb );
+ fb->addFamily( fc );
+ fc->addFamily( fd );
+ fd->addTask( Task::create( "t1" ) );
+ suite->addFamily( fa );
+ clientDef->addSuite( suite );
+ }
+ Defs comparisonDef; {
+ suite_ptr suite = Suite::create( "suite1" ) ;
+ family_ptr fa = Family::create( "fa" ) ;
+ family_ptr fb = Family::create( "fb" ) ;
+ family_ptr fc = Family::create( "fc" ) ;
+ family_ptr fd = Family::create( "fd" ) ;
+ fa->addFamily( fb );
+ fb->addFamily( fc );
+ fc->addFamily( fd );
+ fd->addTask( Task::create( "t1" ) );
+ suite->addFamily( fa );
+ comparisonDef.addSuite( suite );
+ }
+ BOOST_CHECK_MESSAGE(comparisonDef == *clientDef,"client and comparisonDef should be the same");
+
+
+ // Here /suite1/fa/fb/fc/fd/t1 does not exist in the server. These should be created.
+ // by adding family "fa" as a child of suite1
+ Defs serverDefs; {
+ suite_ptr suite = Suite::create( "suite1" ) ;
+ serverDefs.addSuite( suite );
+ }
+ std::string errorMsg;
+ BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/suite1/fa/fb/fc/fd/t1",clientDef,true/*create nodes as needed*/, false/*force*/,errorMsg), errorMsg );
+ BOOST_CHECK_MESSAGE(comparisonDef == serverDefs,"comparisonDef and servers defs should be the same");
+}
+
+
+BOOST_AUTO_TEST_CASE( test_replace_order_preserved_for_suite )
+{
+ cout << "ANode:: ...test_replace_order_preserved_for_suite\n" ;
+ // Test that when we replace a suite, its order is preserved,
+ // See ECFLOW-23 - When replacing a node the order is changed.
+ defs_ptr clientDef = Defs::create(); {
+ clientDef->add_suite( "s1" ) ;
+ clientDef->add_suite( "s2" ) ;
+ clientDef->add_suite( "s3" ) ;
+ }
+
+ // Replace suite s1 with another suite s1 check order is preserved
+ Defs serverDefs; {
+ serverDefs.add_suite( "s1" ) ;
+ serverDefs.add_suite( "s2" ) ;
+ serverDefs.add_suite( "s3" ) ;
+ }
+
+ Defs expectedDefs; {
+ expectedDefs.add_suite( "s1" ) ;
+ expectedDefs.add_suite( "s2" ) ;
+ expectedDefs.add_suite( "s3" ) ;
+ }
+
+ std::string errorMsg;
+ BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/s1",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
+ BOOST_CHECK_MESSAGE(expectedDefs == serverDefs,"expectedDefs and servers defs should be the same");
+
+ BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/s2",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
+ BOOST_CHECK_MESSAGE(expectedDefs == serverDefs,"expectedDefs and servers defs should be the same");
+
+ BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/s3",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
+ BOOST_CHECK_MESSAGE(expectedDefs == serverDefs,"expectedDefs and servers defs should be the same");
+}
+
+
+BOOST_AUTO_TEST_CASE( test_replace_order_preserved_for_family )
+{
+ cout << "ANode:: ...test_replace_order_preserved_for_family\n" ;
+ // Test that when we replace a family, its order is preserved,
+ // See ECFLOW-23 - When replacing a node the order is changed.
+ defs_ptr clientDef = Defs::create(); {
+ suite_ptr suite = clientDef->add_suite( "suite1" ) ;
+ suite->add_family("f1" ) ;
+ suite->add_family("f2" ) ;
+ suite->add_family("f3" ) ;
+ }
+
+ // Replace family f1 with another family f1 check order is preserved
+ Defs serverDefs; {
+ suite_ptr suite = serverDefs.add_suite( "suite1" ) ;
+ suite->add_family("f1" ) ;
+ suite->add_family("f2" ) ;
+ suite->add_family("f3" ) ;
+ }
+
+ Defs expectedDefs; {
+ suite_ptr suite = expectedDefs.add_suite( "suite1" ) ;
+ suite->add_family("f1" ) ;
+ suite->add_family("f2" ) ;
+ suite->add_family("f3" ) ;
+ }
+
+ std::string errorMsg;
+ Ecf::set_debug_equality(true); // only has affect in DEBUG build
+ BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/suite1/f1",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
+ BOOST_CHECK_MESSAGE(expectedDefs == serverDefs,"expectedDefs and servers defs should be the same");
+ BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/suite1/f2",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
+ BOOST_CHECK_MESSAGE(expectedDefs == serverDefs,"expectedDefs and servers defs should be the same");
+ BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/suite1/f3",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
+ BOOST_CHECK_MESSAGE(expectedDefs == serverDefs,"expectedDefs and servers defs should be the same");
+ Ecf::set_debug_equality(false);
+}
+
+BOOST_AUTO_TEST_CASE( test_replace_order_preserved_for_task )
+{
+ cout << "ANode:: ...test_replace_order_preserved_for_task\n" ;
+ // Test that when we replace a family, its order is preserved,
+ // See ECFLOW-23 - When replacing a node the order is changed.
+ defs_ptr clientDef = Defs::create(); {
+ suite_ptr suite = clientDef->add_suite( "suite1" ) ;
+ family_ptr f1 = suite->add_family("f1" ) ;
+ f1->add_task("t1");
+ f1->add_task("t2");
+ f1->add_task("t3");
+ }
+
+ // Replace task t1 with another task t1, check order is preserved
+ Defs serverDefs; {
+ suite_ptr suite = serverDefs.add_suite( "suite1" ) ;
+ family_ptr f1 = suite->add_family("f1" ) ;
+ f1->add_task("t1");
+ f1->add_task("t2");
+ f1->add_task("t3");
+ }
+
+ Defs expectedDefs; {
+ suite_ptr suite = expectedDefs.add_suite( "suite1" ) ;
+ family_ptr f1 = suite->add_family("f1" ) ;
+ f1->add_task("t1");
+ f1->add_task("t2");
+ f1->add_task("t3");
+ }
+
+ std::string errorMsg;
+ Ecf::set_debug_equality(true); // only has affect in DEBUG build
+ BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/suite1/f1/t1",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
+ BOOST_CHECK_MESSAGE(expectedDefs == serverDefs,"expectedDefs and servers defs should be the same");
+ BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/suite1/f1/t2",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
+ BOOST_CHECK_MESSAGE(expectedDefs == serverDefs,"expectedDefs and servers defs should be the same");
+ BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/suite1/f1/t3",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
+ BOOST_CHECK_MESSAGE(expectedDefs == serverDefs,"expectedDefs and servers defs should be the same");
+ Ecf::set_debug_equality(false);
+}
+
+BOOST_AUTO_TEST_CASE( test_replace_child_errors )
+{
+ cout << "ANode:: ...test_replace_child_errors\n" ;
+ defs_ptr clientDef = Defs::create(); {
+ suite_ptr suite = Suite::create( "suite1" ) ;
+ family_ptr fam = Family::create( "family" ) ;
+ fam->addTask( Task::create( "t1" ) );
+ suite->addFamily( fam );
+ suite->addTask( Task::create( "t2" ) );
+ clientDef->addSuite( suite );
+ }
+ Defs serverDefs;
+ std::string errorMsg;
+ BOOST_REQUIRE_MESSAGE(!serverDefs.replaceChild("/suite1/i/dont/exist", clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), "Expected failure" );
+}
+
+BOOST_AUTO_TEST_CASE( test_replace_child_errors_2 )
+{
+ cout << "ANode:: ...test_replace_child_errors_2\n" ;
+ defs_ptr clientDef = Defs::create(); {
+ suite_ptr suite = Suite::create( "suite1" ) ;
+ family_ptr fam = Family::create( "family" ) ;
+ fam->addTask( Task::create( "t1" ) );
+ suite->addFamily( fam );
+ suite->addTask( Task::create( "t2" ) );
+ clientDef->addSuite( suite );
+ }
+ Defs serverDefs; {
+ suite_ptr suite = Suite::create( "suite1" ) ;
+ family_ptr fam = Family::create( "family" ) ;
+ fam->addTask( Task::create( "t1" ) );
+ suite->addFamily( fam );
+ serverDefs.addSuite( suite );
+ }
+
+ // because createNodesAsNeeded is false, child adoption should fail since /suite1/t2
+ // does not exist on the server
+ std::string errorMsg;
+ BOOST_REQUIRE_MESSAGE(!serverDefs.replaceChild("/suite1/t2", clientDef , false/*create nodes as needed*/, false, errorMsg), "Expected failure");
+
+ // With flag now set, we will create any missing nodes even if they dont exist in the server
+ errorMsg.clear();
+ BOOST_REQUIRE_MESSAGE(serverDefs.replaceChild("/suite1/t2", clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), "Expected success " << errorMsg );
+}
+
+
+BOOST_AUTO_TEST_CASE( test_replace_child_errors_3 )
+{
+ // test force option
+ cout << "ANode:: ...test_replace_child_errors_3\n" ;
+ defs_ptr clientDef = Defs::create(); {
+ suite_ptr suite = Suite::create( "suite1" ) ;
+ family_ptr fam = Family::create( "family" ) ;
+ fam->addTask( Task::create( "t1" ) );
+ suite->addFamily( fam );
+ suite->addTask( Task::create( "t2" ) );
+ clientDef->addSuite( suite );
+ }
+
+ Defs serverDefs; {
+ suite_ptr suite = Suite::create( "suite1" ) ;
+ family_ptr fam = Family::create( "family" ) ;
+ fam->addTask( Task::create( "t1" ) );
+ suite->addFamily( fam );
+ task_ptr t2 = Task::create( "t2" );
+ suite->addTask( t2 );
+ serverDefs.addSuite( suite );
+
+ t2->set_state( NState::ACTIVE ); // Must be done after parent has been setup
+ }
+ std::string errorMsg;
+ BOOST_REQUIRE_MESSAGE( !serverDefs.replaceChild("/suite1/t2", clientDef, true/*create nodes as needed*/, false/*force*/, errorMsg), "Expected failure since server task t2 is active, and force not used");
+ errorMsg.clear();
+ BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/suite1/t2", clientDef, true/*create nodes as needed*/, true/*force*/, errorMsg), errorMsg);
+}
+
+
+BOOST_AUTO_TEST_CASE( test_replace_add_task_with_bad_trigger )
+{
+ cout << "ANode:: ...test_replace_add_task_with_bad_trigger\n" ;
+ defs_ptr clientDef = Defs::create(); {
+ suite_ptr suite = clientDef->add_suite( "suite1" ) ;
+ family_ptr fam = suite->add_family("family" ) ;
+ task_ptr task = fam->add_task( "t2" );
+ task->add_trigger("txx eq complete");
+ }
+
+ // add Child t2 to the server defs
+ Defs serverDefs; {
+ suite_ptr suite = serverDefs.add_suite( "suite1" ) ;
+ family_ptr fam = suite->add_family("family" ) ;
+ fam->add_task( "t1" );
+ }
+
+ // expect to fail since trigger expression on added task, should not resolve
+ std::string errorMsg;
+ BOOST_REQUIRE_MESSAGE( !serverDefs.replaceChild("/suite1/family/t2",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
+}
+
+BOOST_AUTO_TEST_CASE( test_replace_add_suite_with_bad_triggers )
+{
+ cout << "ANode:: ...test_replace_add_suite_with_bad_triggers\n";
+
+ // The whole suite should get *MOVED* from clientDef to the *EMPTY* server def. i.e add
+ defs_ptr clientDef = Defs::create(); {
+ suite_ptr suite = clientDef->add_suite( "suite1" ) ;
+ family_ptr fam = suite->add_family("family" ) ;
+ fam->add_task( "t1" );
+ fam->add_task( "t2" );
+ task_ptr t3 = fam->add_task("t3");
+ t3->add_trigger("txxxxx eq complete");
+ }
+
+ // Server defs is empty
+ Defs serverDefs;
+
+ // expect failure since trigger expression should not resolve
+ std::string errorMsg;
+ BOOST_REQUIRE_MESSAGE( !serverDefs.replaceChild("/suite1/family/t2",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ANode/test/TestSetState.cpp b/ANode/test/TestSetState.cpp
new file mode 100644
index 0000000..d32bed1
--- /dev/null
+++ b/ANode/test/TestSetState.cpp
@@ -0,0 +1,140 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <iostream>
+#include <stdlib.h>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/test/unit_test.hpp>
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "Jobs.hpp"
+#include "JobsParam.hpp"
+#include "System.hpp"
+
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+static void set_state(node_ptr n,NState::State set,NState::State expected)
+{
+ n->set_state(set);
+ BOOST_REQUIRE_MESSAGE(n->state() == expected,"Expected state " << NState::toString(expected) << " but found " << NState::toString(n->state()) << " for " << n->debugNodePath());
+}
+
+static void test_state(node_ptr n,NState::State expected)
+{
+ BOOST_REQUIRE_MESSAGE(n->state() == expected,"Expected state " << NState::toString(expected) << " but found " << NState::toString(n->state()) << " for " << n->debugNodePath());
+}
+
+BOOST_AUTO_TEST_CASE( test_set_state )
+{
+ cout << "ANode:: ...test_set_state\n";
+ std::vector<NState::State> stateVec = NState::states();
+
+// cout << "Defs setState\n";
+ Defs theDefs;
+ BOOST_FOREACH(NState::State state, stateVec) {
+ theDefs.set_state(state);
+ BOOST_REQUIRE_MESSAGE(theDefs.state() == state,"Expected defs state " << NState::toString(state) << " but found " << NState::toString(theDefs.state()));
+ }
+// theDefs.resume(); // unset the suspended state. Start with default, for next set of test
+ theDefs.set_state(NState::UNKNOWN); // Start with default, for next set of test
+
+
+// cout << "Suite setState\n";
+ suite_ptr s = Suite::create("s");
+ theDefs.addSuite(s);
+ BOOST_FOREACH(NState::State state, stateVec) {
+ set_state(s,state,state); // suite with no children, state should be what was set
+ }
+ s->resume(); // unset the suspended state. Start with default, for next set of test
+ s->set_state(NState::UNKNOWN); // Start with default, for next set of test
+
+
+// cout << "family setState\n";
+ family_ptr f = Family::create("f");
+ s->addFamily(f);
+ BOOST_FOREACH(NState::State state, stateVec) {
+ set_state(f,state,state); // family with no children, state should be what was set
+ }
+ f->resume(); // unset the suspended state. Start with default, for next set of test
+ f->set_state(NState::UNKNOWN); // Start with default, for next set of test
+
+
+// cout << "task setState\n";
+ task_ptr t = Task::create("t");
+ f->addTask(t);
+
+ BOOST_FOREACH(NState::State state, stateVec) {
+ f->setStateOnly(NState::UNKNOWN); // reset family state
+ s->setStateOnly(NState::UNKNOWN); // reset suite state
+ set_state(t,state,state); // task state should be what was set
+
+ test_state(f,state); // family state should be computed state
+ test_state(s,state); // suite state should be computed state
+ }
+
+ /// Everytime we set the state on a nodecontainer, we call handleStateChange
+ /// This by default works out the most significant state of the children
+ /// ie. the computed state. Hence setting the state on Suite/Family is really
+ /// meaningless, since it will always be the computed state.
+}
+
+BOOST_AUTO_TEST_CASE( test_set_aborted )
+{
+ // see ECFLOW-344
+ cout << "ANode:: ...test_set_aborted\n";
+
+ Defs defs;
+ suite_ptr suite = defs.add_suite("s1");
+ task_ptr t1 = suite->add_task("t1");
+ t1->addDefStatus( DState::COMPLETE );
+ defs.beginAll();
+
+ {
+ Jobs jobs(&defs);
+ JobsParam jobsParam;
+ jobs.generate(jobsParam);
+ BOOST_CHECK_MESSAGE( jobsParam.submitted().size() == 0,"No jobs should be submitted when task is complete but found " << jobsParam.submitted().size() << " submitted");
+ }
+
+ t1->setStateOnly(NState::ABORTED,true/*force*/);
+ {
+ Jobs jobs(&defs);
+ JobsParam jobsParam;
+ jobs.generate(jobsParam);
+ BOOST_CHECK_MESSAGE( jobsParam.submitted().size() == 0,"No jobs should be submitted when task is forcibly aborted but found " << jobsParam.submitted().size() << " submitted");
+ }
+
+ t1->requeue(true,0,false);
+
+ t1->set_state(NState::ABORTED); // mimic non forced, i.e like job aborted
+ {
+ Jobs jobs(&defs);
+ JobsParam jobsParam;
+ jobs.generate(jobsParam);
+ BOOST_CHECK_MESSAGE( jobsParam.submitted().size() == 1,"Expected 1 job, when job aborts and ECF_TRIES > 1 but found " << jobsParam.submitted().size() << " submitted");
+ BOOST_CHECK_MESSAGE( t1->try_no() == 1," expected try_no to be 1 but found " << t1->try_no());
+ }
+
+ /// Destroy System singleton to avoid valgrind from complaining
+ System::destroy();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ANode/test/TestSingleExprParse.cpp b/ANode/test/TestSingleExprParse.cpp
new file mode 100644
index 0000000..b223c2b
--- /dev/null
+++ b/ANode/test/TestSingleExprParse.cpp
@@ -0,0 +1,76 @@
+#define BOOST_TEST_MODULE TestSingle
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include "ExprParser.hpp"
+#include "ExprAst.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/foreach.hpp>
+#include <string>
+#include <map>
+#include <iostream>
+#include <fstream>
+using namespace std;
+
+
+// DEBUG AID: to see the expression tree, invert the expected evaluation
+// so that test fail's
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_single_expression )
+{
+ std::cout << "ANode:: ...test_single_expression\n";
+
+ // The map key = trigger expression,
+ // value.first = type of expected root abstract syntax tree
+ // value.second = result of expected evaluation
+ map<string,std::pair<string,bool> > exprMap;
+
+// exprMap["inigroup:YMD eq not 1"] = std::make_pair(AstEqual::stype(),true);
+// exprMap["/net/main:YMD le /net/cleanplus1:YMD and 1"] = std::make_pair(AstAnd::stype(),true);
+// exprMap["!../../../prod2diss//operation_is_late:yes"] = std::make_pair(AstNot::stype(),true);
+// exprMap["../obs:YMD ge ( 19720101 + 6576 - 1)"] = std::make_pair(AstGreaterEqual::stype(),true);
+// exprMap["../obs:YMD ge ( (19720101 + 6576) - (12 + 1) )"] = std::make_pair(AstGreaterEqual::stype(),true);
+
+ exprMap["../timers/end/ymd:YMD >= ./hind:YMD and hind_info == complete and comp == complete and notready == complete"] = std::make_pair(AstAnd::stype(),false);
+// exprMap["comp == complete and ! ready == complete"] = std::make_pair(AstAnd::stype(),false);
+// exprMap["comp == complete and not ready == complete"] = std::make_pair(AstAnd::stype(),false);
+// exprMap["comp == complete and ~ ready == complete"] = std::make_pair(AstAnd::stype(),false);
+
+
+ std::pair<string, std::pair<string,bool> > p;
+ BOOST_FOREACH(p, exprMap ) {
+
+ ExprParser theExprParser(p.first);
+ std::string errorMsg;
+ bool ok = theExprParser.doParse(errorMsg);
+ BOOST_REQUIRE_MESSAGE(ok,errorMsg);
+
+ string expectedRootType = p.second.first;
+ bool expectedEvaluationResult = p.second.second;
+
+ std::stringstream ss;
+
+ Ast* top = theExprParser.getAst();
+ BOOST_REQUIRE_MESSAGE( top ,"No abstract syntax tree");
+ BOOST_REQUIRE_MESSAGE( top->left() ,"No root created");
+ BOOST_REQUIRE_MESSAGE( top->left()->isRoot() ,"First child of top should be a root");
+ BOOST_REQUIRE_MESSAGE( top->left()->type() == expectedRootType,"expected root type " << expectedRootType << " but found " << top->left()->type());
+ top->print_flat(ss);
+ BOOST_REQUIRE_MESSAGE( expectedEvaluationResult == top->evaluate(),"evaluation not as expected for:\n" << p.first << "\n" << ss.str() << "\n" << *top);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/ANode/test/TestSmsLocator.cpp b/ANode/test/TestSmsLocator.cpp
new file mode 100644
index 0000000..389220a
--- /dev/null
+++ b/ANode/test/TestSmsLocator.cpp
@@ -0,0 +1,128 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <iostream>
+#include <stdlib.h>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/test/unit_test.hpp>
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "EcfFile.hpp"
+#include "Str.hpp"
+#include "File.hpp"
+
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_sms_file_locator )
+{
+ cout << "ANode:: ...test_sms_file_locator\n";
+
+ // SET ECF_HOME
+ std::string smshome = File::test_data("ANode/test/data/SMSHOME","ANode");
+
+ // Create a defs file corresponding to:
+ //# Test the sms file can be found via ECF_SCRIPT
+ //#
+ //suite suite
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // edit SLEEPTIME 10
+ // family family
+ // task t1
+ // task t2
+ // task t3
+ // endfamily
+ //endsuite
+ //
+ //#
+ //# This test suite should force a backwards search since the ecf files
+ //# are located in ECF_HOME
+ //suite suite1
+ // family family
+ // task suite1_task1
+ // task suite1_task2
+ // task suite1_task3
+ // endfamily
+ //endsuite
+ //
+ //#
+ //# This suite is used to test command substition with ECF_FETCH command
+ //#
+ //suite suite2
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // edit ECF_FILES $ECF_HOME
+ // family family
+ // edit SMSFETCH "smsfetch -F %ECF_FILES% -I %ECF_INCLUDE%"
+ // task t2
+ // endfamily
+ //endsuite
+ Defs theDefs;
+ {
+ suite_ptr suite = theDefs.add_suite("suite");
+ suite->addVariable( Variable( Str::ECF_INCLUDE(), "$ECF_HOME/includes" ) );
+ suite->addVariable( Variable( "SLEEPTIME", "10" ) );
+ family_ptr fam = suite->add_family( "family" );
+ fam->add_task( "t1" );
+ fam->add_task( "t2" );
+ fam->add_task( "t3" );
+ }
+ {
+ suite_ptr suite = theDefs.add_suite("suite1");
+ family_ptr fam = suite->add_family( "family" );
+ fam->add_task( "suite1_task1" );
+ fam->add_task( "suite1_task2" );
+ fam->add_task( "suite1_task3" );
+ }
+ {
+ suite_ptr suite2 = theDefs.add_suite("suite2");
+ suite2->addVariable( Variable( Str::ECF_INCLUDE(), "$ECF_HOME/includes" ) );
+ suite2->addVariable( Variable( Str::ECF_FILES(), "$ECF_HOME" ) );
+ family_ptr fam = suite2->add_family( "family" );
+ fam->addVariable( Variable( Str::ECF_FETCH(), "smsfetch -F %ECF_FILES% -I %ECF_INCLUDE%" ) );
+ fam->add_task( "t2" );
+ }
+// cerr << theDefs << "\n";
+
+ // get all the task, assume non hierarchical families
+ std::vector<Task*> theTasks;
+ theDefs.getAllTasks(theTasks);
+ BOOST_REQUIRE_MESSAGE(theTasks.size() == 7, "Expected 7 tasks but found, " << theTasks.size());
+
+ // Override ECF_HOME. ECF_HOME is need to locate to the ecf files
+ theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(),smshome);
+
+
+ /// begin , will cause creation of generated variables. The generated variables
+ /// are use in client scripts and used to locate the sms files
+ theDefs.beginAll();
+
+ // Test for ECF_ file location
+ BOOST_FOREACH(Task* t, theTasks) {
+ try {
+ EcfFile ecf_file = t->locatedEcfFile();
+ BOOST_REQUIRE_MESSAGE( ecf_file.valid(), "Could not locate ecf file for task ");
+ }
+ catch (std::exception& e) {
+ BOOST_REQUIRE_MESSAGE(false,"Could not locate ecf file for task " << e.what());
+ }
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ANode/test/TestTaskScriptGenerator.cpp b/ANode/test/TestTaskScriptGenerator.cpp
new file mode 100644
index 0000000..758342c
--- /dev/null
+++ b/ANode/test/TestTaskScriptGenerator.cpp
@@ -0,0 +1,205 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <iostream>
+#include <stdlib.h>
+
+#include "boost/make_shared.hpp"
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/test/unit_test.hpp>
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "EcfFile.hpp"
+#include "Str.hpp"
+#include "File.hpp"
+
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_task_script_generator )
+{
+ cout << "ANode:: ...test_task_script_generator\n";
+
+ // SET ECF_HOME
+ std::string ecf_home = File::test_data("ANode/test/data/TaskScriptGenerator","ANode");
+
+ std::string head = ecf_home + "/head.h";
+ std::string tail = ecf_home + "/tail.h";
+ fs::remove_all(ecf_home);
+ BOOST_REQUIRE_MESSAGE( !fs::exists(head), "Remove of head file failed");
+ BOOST_REQUIRE_MESSAGE( !fs::exists(tail), "Remove of tail file failed");
+
+
+ // Create a defs file corresponding to:
+ //suite suite
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // edit SLEEP 10
+ // task t1
+ // family f1
+ // task t1
+ // task t2
+ // endfamily
+ //endsuite
+ Defs theDefs;
+ {
+ suite_ptr suite = theDefs.add_suite("suite");
+ suite->add_variable( Str::ECF_INCLUDE(),ecf_home );
+ suite->add_variable( Str::ECF_HOME(), ecf_home );
+ suite->add_variable( "SLEEP","10" );
+ task_ptr t1 = suite->add_task("t1");
+ t1->addEvent( Event("event1") );
+ t1->addEvent( Event("event2") );
+ t1->addEvent( Event("event4") );
+ t1->addMeter( Meter("meter1",1,100,90));
+ t1->addMeter( Meter("meter2",1,100,90));
+ t1->addLabel( Label("label","label value"));
+ family_ptr fam = suite->add_family("f1");
+ fam->add_task("t1");
+ fam->add_task("t2");
+// cerr << theDefs << "\n";
+ }
+
+ /// generate the scripts and head.h and tail.h
+ theDefs.generate_scripts();
+
+ /// Test the ecf file were created, by doing job creation
+ /// JobCreationCtrl is used control what node we generate the jobs for:
+ /// Since we have not set the node on it, we force job generation for all tasks
+ job_creation_ctrl_ptr jobCtrl = boost::make_shared<JobCreationCtrl>();
+ theDefs.check_job_creation(jobCtrl);
+ BOOST_REQUIRE_MESSAGE(jobCtrl->get_error_msg().empty(), jobCtrl->get_error_msg());
+ BOOST_REQUIRE_MESSAGE(jobCtrl->fail_submittables().empty(),"Expected no failing tasks");
+
+ /// Additional sanity tests #######################################################
+
+ /// test that header and tail file were created
+ BOOST_REQUIRE_MESSAGE( fs::exists(head), "Head file " << head << " not created");
+ BOOST_REQUIRE_MESSAGE( fs::exists(tail), "Tail file " << tail << " not created");
+
+ // get all the task, assume non hierarchical families
+ std::vector<Task*> theTasks;
+ theDefs.getAllTasks(theTasks);
+
+ /// begin , will cause creation of generated variables. The generated variables
+ /// are use in client scripts and used to locate the sms files
+ theDefs.beginAll();
+
+ // Test for ECF_ file location
+ BOOST_FOREACH(Task* t, theTasks) {
+ try {
+ EcfFile ecf_file = t->locatedEcfFile();
+ BOOST_REQUIRE_MESSAGE( ecf_file.valid(), "Could not locate ecf file for task ");
+ }
+ catch (std::exception& e) {
+ BOOST_REQUIRE_MESSAGE(false,"Could not locate ecf file for task " << e.what());
+ }
+ }
+
+ // Remove the directories that were generated
+ fs::remove_all(ecf_home);
+}
+
+
+BOOST_AUTO_TEST_CASE( test_task_script_generator_with_dummy_tasks )
+{
+ cout << "ANode:: ...test_task_script_generator_with_dummy_tasks\n";
+
+ // SET ECF_HOME
+ std::string ecf_home = File::test_data("ANode/test/data/TaskScriptGenerator","ANode");
+
+ std::string head = ecf_home + "/head.h";
+ std::string tail = ecf_home + "/tail.h";
+ fs::remove_all(ecf_home);
+ BOOST_REQUIRE_MESSAGE( !fs::exists(head), "Remove of head file failed");
+ BOOST_REQUIRE_MESSAGE( !fs::exists(tail), "Remove of tail file failed");
+
+
+ // Create a defs file corresponding to:
+ // suite suite
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // edit ECF_HOME $ECF_HOME/includes
+ // edit SLEEP 10
+ // family f1
+ // task t1
+ // task t2
+ // endfamily
+ // family f2
+ // edit ECF_DUMMY_TASK ''
+ // task t1
+ // task t2
+ // endfamily
+ // endsuite
+ std::vector<task_ptr> tasks_with_scripts,tasks_without_scripts;
+ Defs theDefs;
+ {
+ suite_ptr suite = theDefs.add_suite("suite");
+ suite->add_variable( Str::ECF_INCLUDE(),ecf_home );
+ suite->add_variable( Str::ECF_HOME(), ecf_home );
+ suite->add_variable( "SLEEP","10" );
+ family_ptr f1 = suite->add_family("f1");
+ tasks_with_scripts.push_back(f1->add_task("t1"));
+ family_ptr f2 = suite->add_family("f2");
+ f2->add_variable( "ECF_DUMMY_TASK", "" );
+ tasks_without_scripts.push_back(f2->add_task("t1"));
+ tasks_without_scripts.push_back(f2->add_task("t2"));
+// cout << theDefs << "\n";
+ }
+
+ /// generate the scripts and head.h and tail.h
+ theDefs.generate_scripts();
+
+ /// Test the ecf file were created, by doing job creation
+ /// JobCreationCtrl is used control what node we generate the jobs for:
+ /// Since we have *NOT* set the node on it, we force job generation for all tasks
+ job_creation_ctrl_ptr jobCtrl = boost::make_shared<JobCreationCtrl>();
+ theDefs.check_job_creation(jobCtrl);
+ BOOST_REQUIRE_MESSAGE(jobCtrl->get_error_msg().empty(), jobCtrl->get_error_msg());
+ BOOST_REQUIRE_MESSAGE(jobCtrl->fail_submittables().empty(),"Expected no failing tasks");
+
+ /// Additional sanity tests #######################################################
+
+ /// test that header and tail file were created
+ BOOST_REQUIRE_MESSAGE( fs::exists(head), "Head file " << head << " not created");
+ BOOST_REQUIRE_MESSAGE( fs::exists(tail), "Tail file " << tail << " not created");
+
+ /// begin , will cause creation of generated variables. The generated variables
+ /// are use in client scripts and used to locate the ecf files
+ theDefs.beginAll();
+
+ // Test for script generation
+ BOOST_FOREACH(task_ptr t, tasks_with_scripts) {
+ try {
+ EcfFile ecf_file = t->locatedEcfFile();
+ BOOST_REQUIRE_MESSAGE( ecf_file.valid(), "Could not locate ecf file for task ");
+ }
+ catch (std::exception& e) {
+ BOOST_REQUIRE_MESSAGE(false,"Could not locate ecf file for task " << e.what());
+ }
+ }
+
+ // Test that no scripts are generated when ECF_DUMMY_TASK is used
+ BOOST_FOREACH(task_ptr t, tasks_without_scripts) {
+ BOOST_REQUIRE_THROW(t->locatedEcfFile(),std::runtime_error);
+ }
+
+ // Remove the directories that were generated
+ fs::remove_all(ecf_home);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ANode/test/TestTimeDependencies.cpp b/ANode/test/TestTimeDependencies.cpp
new file mode 100644
index 0000000..7f3c702
--- /dev/null
+++ b/ANode/test/TestTimeDependencies.cpp
@@ -0,0 +1,116 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #14 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <iostream>
+#include <boost/test/unit_test.hpp>
+#include <boost/date_time/posix_time/time_formatters.hpp>
+
+#include "Task.hpp"
+#include "Suite.hpp"
+#include "Defs.hpp"
+#include "Jobs.hpp"
+#include "JobsParam.hpp"
+#include "CalendarUpdateParams.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::posix_time;
+using namespace boost::gregorian;
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_day_time_combination )
+{
+ cout << "ANode:: ...test_day_time_combination\n";
+ // See ECFLOW-337 , this is where the job was being run twice in a week instead of once.
+ // i.e because the day for still free past midnight.
+
+ // Create the suite, starting on a sunday
+ Defs defs;
+ suite_ptr suite = defs.add_suite("s1");
+ boost::posix_time::ptime the_time = boost::posix_time::ptime(date(2015,6,7),time_duration(0,0,0)); //sunday
+ suite->addClock( ClockAttr(the_time) );
+ task_ptr t1 = suite->add_task("t1");
+ t1->addDay( DayAttr(DayAttr::MONDAY) );
+ t1->addTime( ecf::TimeAttr(ecf::TimeSlot(10,0)) );
+
+ defs.beginAll();
+
+ CalendarUpdateParams calUpdateParams( hours(1) );
+ boost::posix_time::ptime expected_time = boost::posix_time::ptime(date(2015,6,8),time_duration(10,0,0)); //Monday & 10
+ //cout << "expected_time = " << expected_time << "\n";
+
+ bool submitted = false;
+ for(int m=1; m < 100; m++) {
+
+ Jobs jobs(&defs);
+ JobsParam jobsParam;
+ jobs.generate(jobsParam);
+
+ if (jobsParam.submitted().size() ) {
+ submitted = true;
+ //cout << "submitted at " << suite->calendar().suiteTime() << "\n";
+
+ BOOST_CHECK_MESSAGE( suite->calendar().suiteTime() == expected_time,"\nExpected to submit at " << expected_time << " only, but also found " << suite->calendar().suiteTime());
+
+ t1->requeue(true/*resetRepeats*/,0/*clear_suspended_in_child_nodes*/,true/*reset_next_time_slot*/);
+ }
+
+ defs.updateCalendar(calUpdateParams);
+ }
+ BOOST_CHECK_MESSAGE( submitted ,"Expected one submission but found none");
+}
+
+BOOST_AUTO_TEST_CASE( test_date_time_combination )
+{
+ // See ECFLOW-337
+ cout << "ANode:: ...test_date_time_combination\n";
+
+ // Create the suite, starting on a sunday
+ Defs defs;
+ suite_ptr suite = defs.add_suite("s1");
+ boost::posix_time::ptime the_time = boost::posix_time::ptime(date(2015,6,7),time_duration(0,0,0)); //sunday
+ suite->addClock( ClockAttr(the_time) );
+ task_ptr t1 = suite->add_task("t1");
+ t1->addDate( DateAttr(8,6,2015) ); // Monday
+ t1->addTime( ecf::TimeAttr(ecf::TimeSlot(10,0)) );
+
+ defs.beginAll();
+
+ CalendarUpdateParams calUpdateParams( hours(1) );
+ boost::posix_time::ptime expected_time = boost::posix_time::ptime(date(2015,6,8),time_duration(10,0,0)); // Monday & 10
+ //cout << "expected_time = " << expected_time << "\n";
+
+ bool submitted = false;
+ for(int m=1; m < 100; m++) {
+
+ Jobs jobs(&defs);
+ JobsParam jobsParam;
+ jobs.generate(jobsParam);
+
+ if (jobsParam.submitted().size() ) {
+ submitted = true;
+ //cout << "submitted at " << suite->calendar().suiteTime() << "\n";
+
+ BOOST_CHECK_MESSAGE( suite->calendar().suiteTime() == expected_time,"\nExpected to submit at " << expected_time << " only, but also found " << suite->calendar().suiteTime());
+ t1->requeue(true/*resetRepeats*/,0/*clear_suspended_in_child_nodes*/,true/*reset_next_time_slot*/);
+ }
+
+ defs.updateCalendar(calUpdateParams);
+ }
+ BOOST_CHECK_MESSAGE( submitted ,"Expected one submission but found none");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ANode/test/TestVariableGeneration.cpp b/ANode/test/TestVariableGeneration.cpp
new file mode 100644
index 0000000..a1d74c1
--- /dev/null
+++ b/ANode/test/TestVariableGeneration.cpp
@@ -0,0 +1,93 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/test/unit_test.hpp>
+#include <iostream>
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "Str.hpp"
+
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+static void findParentVariableValue(task_ptr t, const std::string& name, const std::string& expected)
+{
+ std::string value;
+ BOOST_CHECK_MESSAGE(t->findParentVariableValue(name,value), "Task " << t->debugNodePath() << " could not find variable of name " << name );
+// if (expected.empty()) std::cout << name << " = " << value << "\n";
+ if (!expected.empty())
+ BOOST_CHECK_MESSAGE( value == expected , "From task " << t->debugNodePath() << " for variable " << name << " expected value " << expected << " but found " << value );
+}
+
+BOOST_AUTO_TEST_CASE( test_generated_variables )
+{
+ std::cout << "ANode:: ...test_generated_variables\n";
+
+ task_ptr t;
+
+ Defs defs; {
+
+ suite_ptr suite = defs.add_suite("suite");
+ suite->addRepeat( RepeatInteger("RepeatInteger",10,20,1));
+
+ family_ptr fam = suite->add_family("f" );
+ fam->addRepeat( RepeatDate("YMD",20090101,20091231,1));
+
+ t = fam->add_family("f2")->add_task("t");
+ std::vector<std::string> stringList; stringList.reserve(3);
+ stringList.push_back("AA"); stringList.push_back("BB"); stringList.push_back("CC");
+ t->addRepeat( RepeatEnumerated("AEnum",stringList));
+ }
+
+ // Generate variables, needed since,findParentVariableValue also serach's the generated variables
+ defs.beginAll();
+
+ // Check Submittable generated variables
+ findParentVariableValue(t,"TASK","t");
+ findParentVariableValue(t,Str::ECF_RID(),"");
+ findParentVariableValue(t,Str::ECF_TRYNO(),"0");
+ findParentVariableValue(t,Str::ECF_NAME(),"/suite/f/f2/t");
+ findParentVariableValue(t,Str::ECF_PASS(),"");
+ findParentVariableValue(t,Str::ECF_JOB(),"./suite/f/f2/t.job0");
+ findParentVariableValue(t,Str::ECF_JOBOUT(),"./suite/f/f2/t.0");
+ findParentVariableValue(t,Str::ECF_SCRIPT(),"./suite/f/f2/t.ecf");
+
+ // Check Family generated variables
+ findParentVariableValue(t,"FAMILY","f/f2");
+ findParentVariableValue(t,"FAMILY1","f2");
+
+ // Check Suite generated variables
+ findParentVariableValue(t,"SUITE","suite");
+ findParentVariableValue(t,"YYYY","");
+ findParentVariableValue(t,"DOW","");
+ findParentVariableValue(t,"DOY","");
+ findParentVariableValue(t,"DATE","");
+ findParentVariableValue(t,"DAY","");
+ findParentVariableValue(t,"DD","");
+ findParentVariableValue(t,"MM","");
+ findParentVariableValue(t,"MONTH","");
+ findParentVariableValue(t,"ECF_DATE","");
+ findParentVariableValue(t,"ECF_CLOCK","");
+ findParentVariableValue(t,"ECF_TIME","");
+
+ // Test repeat generated variables
+ findParentVariableValue(t,"AEnum","AA");
+ findParentVariableValue(t,"YMD","20090101");
+ findParentVariableValue(t,"RepeatInteger","10");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ANode/test/TestVariableInheritance.cpp b/ANode/test/TestVariableInheritance.cpp
new file mode 100644
index 0000000..d211a77
--- /dev/null
+++ b/ANode/test/TestVariableInheritance.cpp
@@ -0,0 +1,78 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <map>
+#include <iostream>
+#include <fstream>
+using namespace std;
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+static void findParentVariableValue(task_ptr t, const std::string& name, const std::string& expected)
+{
+ std::string value;
+ BOOST_CHECK_MESSAGE(t->findParentVariableValue(name,value), "Task " << t->debugNodePath() << " could not find variable of name " << name );
+ BOOST_CHECK_MESSAGE( value == expected , "From task " << t->debugNodePath() << " for variable " << name << " expected value " << expected << " but found " << value );
+}
+
+BOOST_AUTO_TEST_CASE( test_variable_inheritance )
+{
+ std::cout << "ANode:: ...test_variable_inheritance\n";
+
+ // See page 31, section 5.1 variable inheritance, of SMS users guide
+ task_ptr t;
+ task_ptr t2 ;
+ task_ptr z;
+
+ Defs defs; {
+ suite_ptr suite = defs.add_suite("suite");
+ suite->addVariable(Variable("TOPLEVEL","10"));
+ suite->addVariable(Variable("MIDDLE","10"));
+ suite->addVariable(Variable("LOWER","10"));
+
+ family_ptr fam = suite->add_family("f" );
+ fam->addVariable( Variable("MIDDLE","20") );
+ t = fam->add_task("t");
+ t->addVariable( Variable("LOWER","abc") );
+ t2 = fam->add_task("t2");
+
+ family_ptr fam2 = suite->add_family("f2" );
+ fam2->addVariable( Variable("TOPLEVEL","40") );
+ z = fam2->add_task("z");
+ }
+
+ // Generate variables, needed since,findParentVariableValue also serach's the generated variables
+ defs.beginAll();
+
+ // See page 31, section 5.1 variable inheritance, of SMS users guide
+ findParentVariableValue(t,"TOPLEVEL","10");
+ findParentVariableValue(t2, "TOPLEVEL","10");
+ findParentVariableValue(z,"TOPLEVEL","40");
+
+ findParentVariableValue(t,"MIDDLE","20");
+ findParentVariableValue(t2, "MIDDLE","20");
+ findParentVariableValue(z,"MIDDLE","10");
+
+ findParentVariableValue(t, "LOWER","abc");
+ findParentVariableValue(t2, "LOWER","10");
+ findParentVariableValue(z, "LOWER","10");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/ANode/test/TestVariableSubstitution.cpp b/ANode/test/TestVariableSubstitution.cpp
new file mode 100644
index 0000000..018e0ef
--- /dev/null
+++ b/ANode/test/TestVariableSubstitution.cpp
@@ -0,0 +1,438 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <string>
+#include <map>
+#include <iostream>
+#include <fstream>
+
+#include <boost/test/unit_test.hpp>
+#include <boost/foreach.hpp>
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "Str.hpp"
+#include "Ecf.hpp"
+#include "Version.hpp"
+
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_variable_substitution )
+{
+ std::cout << "ANode:: ...test_variable_substitution\n";
+
+ Defs defs;
+ suite_ptr s = defs.add_suite("suite");
+ {
+ s->addVariable(Variable("AVI","avi"));
+ s->addVariable(Variable("BAHRA","bahra"));
+ s->addVariable(Variable("LOWER","10"));
+ s->addVariable(Variable("PATH","/fred/bill/joe"));
+ s->addVariable(Variable("EMPTY_VARIABLE",""));
+ s->addVariable(Variable("fred","%bill%"));
+ s->addVariable(Variable("bill","%fred%"));
+ s->addVariable(Variable("hello","%hello%"));
+ s->addVariable(Variable("mary","%jane%"));
+ s->addVariable(Variable("jane","10"));
+ }
+
+
+ // See page 31, section 5.1 variable inheritance, of SMS users guide
+ std::string cmd = "%AVI%-%BAHRA%-%LOWER%-%AVI%";
+ string expected = "avi-bahra-10-avi";
+ BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd),"substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%ECF_VERSION%";
+ expected = Version::raw();
+ BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd),"substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%PATH%"; expected = "/fred/bill/joe";
+ BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "/%AVI%/%BAHRA%/%LOWER%%PATH%"; expected = "/avi/bahra/10/fred/bill/joe";
+ BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%EMPTY_VARIABLE%"; expected = "";
+ BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%mary%"; expected = "10"; // double substitution
+ BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%fred%"; expected = "%fred%"; // infinite substitution
+ BOOST_CHECK_MESSAGE(!s->variableSubsitution(cmd)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%hello%"; expected = "%hello%"; // infinite substitution
+ BOOST_CHECK_MESSAGE(!s->variableSubsitution(cmd)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = Ecf::MICRO(); expected = Ecf::MICRO();
+ BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%PATH"; expected = "%PATH";
+ BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%%"; expected = "%";
+ BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%ERROR%"; expected = "%ERROR%";
+ BOOST_CHECK_MESSAGE(!s->variableSubsitution(cmd)," substitution expected to fail since ERROR does not exist");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = ""; expected = "";
+ BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+
+ // new rules
+ // %<VAR>:substitute %
+ // If we find VAR, then use it, else use substitute
+ cmd = "%AVI:goblly gook%"; expected = "avi";
+ BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%PATH:goblly::: gook%"; expected = "/fred/bill/joe";
+ BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%LOWER:fred% %AVI:fred2%"; expected = "10 avi";
+ BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%LOWER:fred% %AVI:fred2"; expected = "10 %AVI:fred2";
+ BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%EMPTY_VARIABLE::goblly gook%"; expected = "";
+ BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%NULL:goblly gook%"; expected = "goblly gook";
+ BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%NULL::goblly gook%"; expected = ":goblly gook";
+ BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%NULL:%"; expected = "";
+ BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%:%"; expected = "";
+ BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+}
+
+BOOST_AUTO_TEST_CASE( test_variable_substitution_double_micro )
+{
+ std::cout << "ANode:: ...test_variable_substitution_double_micro\n";
+
+ Defs defs;
+ suite_ptr s = defs.add_suite("suite");
+
+ std::string cmd = "%%"; std::string expected = "%";
+ BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%%%"; expected = "%%";
+ BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%%%%"; expected = "%%";
+ BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%%%%%"; expected = "%%%";
+ BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "date +%%Y.%%m.%%d"; expected = "date +%Y.%m.%d";
+ BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd),"substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "printf %%02d %HOUR:00%"; expected = "printf %02d 00";
+ BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd),"substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ s->addVariable(Variable("HOUR","hammer time"));
+ cmd = "printf %%02d %HOUR:00%"; expected = "printf %02d hammer time";
+ BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd),"substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+}
+
+BOOST_AUTO_TEST_CASE( test_user_variable_substitution )
+{
+ std::cout << "ANode:: ...test_user_variable_substitution\n";
+
+ Defs defs;
+ suite_ptr s = defs.add_suite("suite");
+ {
+ s->addVariable(Variable("AVI","avi"));
+ s->addVariable(Variable("BAHRA","bahra"));
+ s->addVariable(Variable("LOWER","10"));
+ s->addVariable(Variable("PATH","/fred/bill/joe"));
+ s->addVariable(Variable("EMPTY_VARIABLE",""));
+ s->addVariable(Variable("fred","%bill%"));
+ s->addVariable(Variable("bill","%fred%"));
+ s->addVariable(Variable("hello","%hello%"));
+ s->addVariable(Variable("mary","%jane%"));
+ s->addVariable(Variable("jane","10"));
+ }
+
+ NameValueMap user_variables;
+ user_variables.insert( std::make_pair(string("AVI"),string("_avi")) );
+ user_variables.insert( std::make_pair(string("BAHRA"),string("_bahra")) );
+ user_variables.insert( std::make_pair(string("LOWER"),string("_10")) );
+ user_variables.insert( std::make_pair(string("PATH"),string("_/fred/bill/joe")) );
+ user_variables.insert( std::make_pair(string("EMPTY_VARIABLE"),string("_")) );
+ user_variables.insert( std::make_pair(string("fred"),string("%bill%")) );
+ user_variables.insert( std::make_pair(string("bill"),string("%fred%")) );
+ user_variables.insert( std::make_pair(string("hello"),string("%hello%")) );
+ user_variables.insert( std::make_pair(string("mary"),string("%jane%")) );
+ user_variables.insert( std::make_pair(string("jane"),string("_10")) );
+
+ // See page 31, section 5.1 variable inheritance, of SMS users guide
+ std::string cmd = "%AVI%-%BAHRA%-%LOWER%-%AVI%"; string expected = "_avi-_bahra-_10-_avi";
+ BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables),"substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%PATH%"; expected = "_/fred/bill/joe";
+ BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "/%AVI%/%BAHRA%/%LOWER%%PATH%"; expected = "/_avi/_bahra/_10_/fred/bill/joe";
+ BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%EMPTY_VARIABLE%"; expected = "_";
+ BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%mary%"; expected = "_10"; // double substitution
+ BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%fred%"; expected = "%fred%"; // infinite substitution
+ BOOST_CHECK_MESSAGE(!s->variable_substitution(cmd,user_variables)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%hello%"; expected = "%hello%"; // infinite substitution
+ BOOST_CHECK_MESSAGE(!s->variable_substitution(cmd,user_variables)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = Ecf::MICRO(); expected = Ecf::MICRO();
+ BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%PATH"; expected = "%PATH";
+ BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+
+ cmd = "%%"; expected = "%";
+ BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%ERROR%"; expected = "%ERROR%";
+ BOOST_CHECK_MESSAGE(!s->variable_substitution(cmd,user_variables)," substitution expected to fail since ERROR does not exist");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = ""; expected = "";
+ BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+
+ // new rules
+ // %<VAR>:substitute %
+ // If we find VAR, then use it, else use substitute
+ cmd = "%AVI:goblly gook%"; expected = "_avi";
+ BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%PATH:goblly::: gook%"; expected = "_/fred/bill/joe";
+ BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%LOWER:fred% %AVI:fred2%"; expected = "_10 _avi";
+ BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%LOWER:fred% %AVI:fred2"; expected = "_10 %AVI:fred2";
+ BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%EMPTY_VARIABLE::goblly gook%"; expected = "_";
+ BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%NULL:goblly gook%"; expected = "goblly gook";
+ BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%NULL::goblly gook%"; expected = ":goblly gook";
+ BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%NULL:%"; expected = "";
+ BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%:%"; expected = "";
+ BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+}
+
+
+BOOST_AUTO_TEST_CASE( test_user_variable_substitution_1 )
+{
+ std::cout << "ANode:: ...test_user_variable_substitution_1\n";
+
+ Defs defs;
+ suite_ptr s = defs.add_suite("suite");
+ s->addVariable(Variable("AVI","avi"));
+
+ NameValueMap user_variables;
+ user_variables.insert( std::make_pair(string("AVI:goblly gook"),string("avtar")) );
+
+ // new rules
+ // %<VAR>:substitute %
+ // If we find VAR, then use it, else use substitute
+ // However when we have user_variables if we find the complete string
+ // in the user variable list, we use user veriable value:
+ // cmd = %FRED:BILL%" and user_variable = "FRED:BILL","Joe90" ===> cmd = "Joe90"
+ std::string cmd = "%AVI:goblly gook%"; std::string expected = "avtar";
+ BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%AVI:goblly%"; expected = "avi";
+ BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%FRED:goblly%"; expected = "goblly";
+ BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+}
+
+
+static std::vector<std::string> required_server_variables()
+{
+ std::vector<std::string> required_server_variables;
+ required_server_variables.push_back( Str::ECF_PORT() );
+ required_server_variables.push_back( std::string("ECF_NODE") );
+
+ required_server_variables.push_back( Str::ECF_HOME() );
+ required_server_variables.push_back( std::string("ECF_LOG") );
+ required_server_variables.push_back( std::string("ECF_CHECK") );
+ required_server_variables.push_back( std::string("ECF_CHECKOLD") );
+
+ // These variable are read in from the environment, but are not exposed
+ // since they only affect the server
+ // ECF_CHECKINTERVAL
+ // ECF_LISTS
+
+ // variables that can be overridden, in the suite definition
+ required_server_variables.push_back( std::string("ECF_JOB_CMD") );
+ required_server_variables.push_back( std::string("ECF_KILL_CMD") );
+ required_server_variables.push_back( std::string("ECF_STATUS_CMD") );
+ required_server_variables.push_back( std::string("ECF_URL_CMD") );
+ required_server_variables.push_back( std::string("ECF_URL_BASE") );
+ required_server_variables.push_back( std::string("ECF_URL") );
+ required_server_variables.push_back( std::string("ECF_MICRO") );
+
+ // Reference variable, these should be read only
+ required_server_variables.push_back( std::string("ECF_PID") ); // server PID
+ required_server_variables.push_back( std::string("ECF_VERSION") );// server version
+ return required_server_variables;
+}
+
+BOOST_AUTO_TEST_CASE( test_server_variable_substitution )
+{
+ std::cout << "ANode:: ...test_server_variable_substitution\n";
+
+ Defs defs;
+ suite_ptr s = defs.add_suite("suite");
+
+ std::vector<std::string> vec = required_server_variables();
+ for(size_t i = 0; i < vec.size(); i++) {
+ if (vec[i] == "ECF_PID") continue; // CANT test since, this is process ID of server
+ std::string value;
+ BOOST_CHECK_MESSAGE(s->findParentVariableValue(vec[i],value),"Could not find Server variable " << vec[i]);
+ BOOST_CHECK_MESSAGE(!value.empty(),"Empty server variable value for " << vec[i]);
+ }
+
+ for(size_t i = 0; i < vec.size(); i++) {
+ if (vec[i] == "ECF_JOB_CMD") continue; // CANT test since it requires %ECF_JOB% and %ECF_JOBOUT%
+ if (vec[i] == "ECF_KILL_CMD") continue; // CANT test since it requires %ECF_PID%
+ if (vec[i] == "ECF_STATUS_CMD") continue; // CANT test since it requires %ECF_RID%
+ if (vec[i] == "ECF_PID") continue; // CANT test since, this is process ID of server
+ std::string cmd = "%";
+ cmd += vec[i];
+ cmd += "%";
+ BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed for " << vec[i] << " : " << cmd);
+ if (vec[i] == "ECF_VERSION") {
+ BOOST_CHECK_MESSAGE( cmd == Version::raw(), "expected '" << Version::raw() << "' but found '" << cmd << "'");
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_generated_variable_substitution_of_ECF_OUT )
+{
+ // test that if ECF_OUT is defined using %, then we perform variable substitution
+ std::cout << "ANode:: ...test_generated_variable_substitution_of_ECF_OUT\n";
+
+ Defs defs;
+ suite_ptr s = defs.add_suite("suite");
+ s->addVariable(Variable("PATH","/fred/bill/joe"));
+ s->addVariable(Variable("ECF_HOME","/ecf_home"));
+ family_ptr f = s->add_family("f");
+ task_ptr t = f->add_task("t");
+ t->addVariable(Variable("ECF_OUT","%PATH%"));
+ family_ptr f1 = s->add_family("f1");
+ f1->addVariable(Variable("PATH2","/fred/bill/joe2"));
+ task_ptr t1 = f1->add_task("t1");
+ t1->addVariable(Variable("ECF_OUT","%PATH2%"));
+
+ // begin_all
+ defs.beginAll();
+ t->update_generated_variables();
+ t1->update_generated_variables();
+
+ // cout << defs;
+
+ string value;
+ value.clear();
+ t->findParentVariableValue(Str::ECF_JOBOUT(),value);
+ BOOST_CHECK_MESSAGE(value == "/fred/bill/joe/suite/f/t.0","ECF_JOBOUT expected /fred/bill/joe/suite/f/t.0, but found " << value);
+
+ value.clear();
+ t1->findParentVariableValue(Str::ECF_JOBOUT(),value);
+ BOOST_CHECK_MESSAGE(value == "/fred/bill/joe2/suite/f1/t1.0","ECF_JOBOUT expected /fred/bill/joe/suite/f/t.0, but found " << value);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/ANode/test/TestVariableSubstitutionDefs.cpp b/ANode/test/TestVariableSubstitutionDefs.cpp
new file mode 100644
index 0000000..4c5a982
--- /dev/null
+++ b/ANode/test/TestVariableSubstitutionDefs.cpp
@@ -0,0 +1,174 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <string>
+#include <map>
+#include <iostream>
+#include <fstream>
+
+#include <boost/test/unit_test.hpp>
+#include <boost/foreach.hpp>
+
+#include "Defs.hpp"
+#include "Str.hpp"
+#include "Version.hpp"
+#include "Ecf.hpp"
+
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_defs_variable_substitution )
+{
+ std::cout << "ANode:: ...test_defs_variable_substitution\n";
+
+ Defs defs;
+ {
+ std::vector<Variable> vec;
+ vec.push_back(Variable("AVI","avi"));
+ vec.push_back(Variable("BAHRA","bahra"));
+ vec.push_back(Variable("LOWER","10"));
+ vec.push_back(Variable("PATH","/fred/bill/joe"));
+ vec.push_back(Variable("fred","%bill%"));
+ vec.push_back(Variable("bill","%fred%"));
+ vec.push_back(Variable("hello","%hello%"));
+ vec.push_back(Variable("mary","%jane%"));
+ vec.push_back(Variable("jane","10"));
+ defs.set_server().add_or_update_user_variables(vec);
+ }
+
+ // See page 31, section 5.1 variable inheritance, of SMS users guide
+ std::string cmd = "%AVI%-%BAHRA%-%LOWER%-%AVI%";
+ string expected = "avi-bahra-10-avi";
+ BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd),"substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%ECF_VERSION%"; expected = Version::raw();
+ BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd),"substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%PATH%"; expected = "/fred/bill/joe";
+ BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "/%AVI%/%BAHRA%/%LOWER%%PATH%"; expected = "/avi/bahra/10/fred/bill/joe";
+ BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%mary%"; expected = "10"; // double substitution
+ BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%fred%"; expected = "%fred%"; // infinite substitution
+ BOOST_CHECK_MESSAGE(!defs.variableSubsitution(cmd)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%hello%"; expected = "%hello%"; // infinite substitution
+ BOOST_CHECK_MESSAGE(!defs.variableSubsitution(cmd)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = Ecf::MICRO(); expected = Ecf::MICRO();
+ BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%PATH"; expected = "%PATH";
+ BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%%"; expected = "%";
+ BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%ERROR%"; expected = "%ERROR%";
+ BOOST_CHECK_MESSAGE(!defs.variableSubsitution(cmd)," substitution expected to fail since ERROR does not exist");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = ""; expected = "";
+ BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+
+ // new rules
+ // %<VAR>:substitute %
+ // If we find VAR, then use it, else use substitute
+ cmd = "%AVI:goblly gook%"; expected = "avi";
+ BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%PATH:goblly::: gook%"; expected = "/fred/bill/joe";
+ BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%LOWER:fred% %AVI:fred2%"; expected = "10 avi";
+ BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%LOWER:fred% %AVI:fred2"; expected = "10 %AVI:fred2";
+ BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%NULL:goblly gook%"; expected = "goblly gook";
+ BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%NULL::goblly gook%"; expected = ":goblly gook";
+ BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%NULL:%"; expected = "";
+ BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%:%"; expected = "";
+ BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed ");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+}
+
+BOOST_AUTO_TEST_CASE( test_defs_variable_substitution_double_micro )
+{
+ std::cout << "ANode:: ...test_defs_variable_substitution_double_micro\n";
+
+ Defs defs;
+
+ std::string cmd = "%%"; std::string expected = "%";
+ BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%%%"; expected = "%%";
+ BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%%%%"; expected = "%%";
+ BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "%%%%%"; expected = "%%%";
+ BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "date +%%Y.%%m.%%d"; expected = "date +%Y.%m.%d";
+ BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd),"substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ cmd = "printf %%02d %HOUR:00%"; expected = "printf %02d 00";
+ BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd),"substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+
+ defs.set_server().add_or_update_user_variables("HOUR","hammer time");
+ cmd = "printf %%02d %HOUR:00%"; expected = "printf %02d hammer time";
+ BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd),"substitution failed");
+ BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ANode/test/TestZombies.cpp b/ANode/test/TestZombies.cpp
new file mode 100644
index 0000000..d5357a9
--- /dev/null
+++ b/ANode/test/TestZombies.cpp
@@ -0,0 +1,81 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <iostream>
+#include <stdlib.h>
+
+#include <boost/test/unit_test.hpp>
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "System.hpp"
+
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_zombies )
+{
+ cout << "ANode:: ...test_zombies\n";
+ Defs theDefs;
+ suite_ptr s = theDefs.add_suite("s");
+ task_ptr t = s->add_family("f")->add_task("t");
+
+ // SANITY
+ {
+ BOOST_REQUIRE_MESSAGE(s->zombies().size() == 0, "Expected 0 zombies but found " << s->zombies().size());
+ BOOST_REQUIRE_MESSAGE(s->findZombie(ecf::Child::USER).empty(), "Expected no zombies");
+ BOOST_REQUIRE_MESSAGE(s->findZombie(ecf::Child::ECF).empty(), "Expected no zombies");
+ BOOST_REQUIRE_MESSAGE(s->findZombie(ecf::Child::PATH).empty(), "Expected no zombies");
+ ZombieAttr attr;
+ BOOST_REQUIRE_MESSAGE(!t->findParentZombie(ecf::Child::PATH,attr) && attr.empty(), "Expected to NOT find PATH zombies on parent");
+ }
+
+ // ADD
+ std::vector<ecf::Child::CmdType> child_cmds;
+ child_cmds.push_back(ecf::Child::INIT);
+ child_cmds.push_back(ecf::Child::EVENT);
+ child_cmds.push_back(ecf::Child::METER);
+ child_cmds.push_back(ecf::Child::LABEL);
+ child_cmds.push_back(ecf::Child::WAIT);
+ child_cmds.push_back(ecf::Child::ABORT);
+ child_cmds.push_back(ecf::Child::COMPLETE);
+ {
+ s->addZombie( ZombieAttr(ecf::Child::USER, child_cmds, ecf::User::FOB,10) );
+ BOOST_REQUIRE_MESSAGE(s->zombies().size() == 1, "Expected 1 zombie but found " << s->zombies().size());
+ s->addZombie( ZombieAttr(ecf::Child::ECF, child_cmds, ecf::User::FAIL,100) );
+ BOOST_REQUIRE_MESSAGE(s->zombies().size() == 2, "Expected 2 zombie but found " << s->zombies().size());
+ s->addZombie( ZombieAttr(ecf::Child::PATH, child_cmds, ecf::User::BLOCK,100) );
+ BOOST_REQUIRE_MESSAGE(s->zombies().size() == 3, "Expected 3 zombie but found " << s->zombies().size());
+ }
+
+ // FIND
+ BOOST_REQUIRE_MESSAGE(!s->findZombie(ecf::Child::USER).empty(), "Expected to find USER zombies");
+ BOOST_REQUIRE_MESSAGE(!s->findZombie(ecf::Child::ECF).empty(), "Expected to find ECF zombies");
+ BOOST_REQUIRE_MESSAGE(!s->findZombie(ecf::Child::PATH).empty(), "Expected to find PATH zombies");
+
+ // FIND on parent
+ {
+ ZombieAttr path_z,ecf_z,user_z;
+ BOOST_REQUIRE_MESSAGE(t->findParentZombie(ecf::Child::PATH,path_z) && !path_z.empty(), "Expected to find PATH zombies on parent");
+ BOOST_REQUIRE_MESSAGE(t->findParentZombie(ecf::Child::ECF,ecf_z) && !ecf_z.empty(), "Expected to find ECF zombies on parent");
+ BOOST_REQUIRE_MESSAGE(t->findParentZombie(ecf::Child::USER,user_z) && !user_z.empty(), "Expected to find USER zombies on parent");
+ }
+
+ /// Destroy System singleton to avoid valgrind from complaining
+ System::destroy();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ANode/test/Test_ECFLOW-195.cpp b/ANode/test/Test_ECFLOW-195.cpp
new file mode 100644
index 0000000..31674cf
--- /dev/null
+++ b/ANode/test/Test_ECFLOW-195.cpp
@@ -0,0 +1,97 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <iostream>
+#include <stdlib.h>
+
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_ECFLOW_195 )
+{
+ cout << "ANode:: ...test_ECFLOW_195 re-queue on task should retain label value\n";
+
+ defs_ptr defs = Defs::create();
+ suite_ptr s1 = defs->add_suite("s1");
+ family_ptr f1 = s1->add_family("f1");
+ task_ptr t1 = f1->add_task("t1");
+
+ s1->addLabel( Label("s1","s1"));
+ f1->addLabel( Label("f1","f1"));
+ t1->addLabel( Label("t1","t1"));
+
+ defs->beginAll();
+
+ // Set the labels, with new values
+ s1->changeLabel("s1","xx");
+ f1->changeLabel("f1","xx");
+ t1->changeLabel("t1","xx");
+
+ { // Check new values have not changed
+ Label s1_label = s1->find_label("s1");
+ BOOST_CHECK_MESSAGE(!s1_label.empty(),"expected to find label 's1'");
+ BOOST_CHECK_MESSAGE(s1_label.new_value() == "xx","expected xx but found " << s1_label.new_value());
+
+ Label f1_label = f1->find_label("f1");
+ BOOST_CHECK_MESSAGE(!f1_label.empty(),"expected to find label 'f1'");
+ BOOST_CHECK_MESSAGE(f1_label.new_value() == "xx","expected xx but found " << f1_label.new_value());
+
+ Label t1_label = t1->find_label("t1");
+ BOOST_CHECK_MESSAGE(!t1_label.empty(),"expected to find label 't1'");
+ BOOST_CHECK_MESSAGE(t1_label.new_value() == "xx","expected xx but found " << t1_label.new_value());
+ }
+
+ // Now requee. the suite and family should be cleared and task label should remain.
+ defs->requeue();
+
+ { // Suite and Family labels should be reset, and task labels should retain their values
+ Label s1_label = s1->find_label("s1");
+ BOOST_CHECK_MESSAGE(!s1_label.empty(),"expected to find label 's1'");
+ BOOST_CHECK_MESSAGE(s1_label.new_value().empty(),"expected empty string for suite label value after re-queue, but found " << s1_label.new_value());
+
+ Label f1_label = f1->find_label("f1");
+ BOOST_CHECK_MESSAGE(!f1_label.empty(),"expected to find label 'f1'");
+ BOOST_CHECK_MESSAGE(f1_label.new_value().empty(),"expected empty string for family label value after re-queue, but found " << f1_label.new_value());
+
+ Label t1_label = t1->find_label("t1");
+ BOOST_CHECK_MESSAGE(!t1_label.empty(),"expected to find label 't1'");
+ BOOST_CHECK_MESSAGE(t1_label.new_value() == "xx","Expected task label to remain unchanged after re-queue but found " << t1_label.new_value());
+ }
+
+ // After explicit re-queue expect new labels to be empty
+ s1->requeue_labels();
+ f1->requeue_labels();
+ t1->requeue_labels();
+ {
+ Label s1_label = s1->find_label("s1");
+ BOOST_CHECK_MESSAGE(!s1_label.empty(),"expected to find label 's1'");
+ BOOST_CHECK_MESSAGE(s1_label.new_value().empty(),"expected empty string for suite label value after explicit re-queue, but found " << s1_label.new_value());
+
+ Label f1_label = f1->find_label("f1");
+ BOOST_CHECK_MESSAGE(!f1_label.empty(),"expected to find label 'f1'");
+ BOOST_CHECK_MESSAGE(f1_label.new_value().empty(),"expected empty string for family label value after explicit re-queue, but found " << f1_label.new_value());
+
+ Label t1_label = t1->find_label("t1");
+ BOOST_CHECK_MESSAGE(!t1_label.empty(),"expected to find label 't1'");
+ BOOST_CHECK_MESSAGE(t1_label.new_value().empty(),"expected empty string for task label value after explicit re-queue, but found " << t1_label.new_value());
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ANode/test/Test_ECFLOW-247.cpp b/ANode/test/Test_ECFLOW-247.cpp
new file mode 100644
index 0000000..f366e31
--- /dev/null
+++ b/ANode/test/Test_ECFLOW-247.cpp
@@ -0,0 +1,102 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "Jobs.hpp"
+#include "JobsParam.hpp"
+#include "PrintStyle.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <iostream>
+#include <stdlib.h>
+
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_ECFLOW_247 )
+{
+ cout << "ANode:: ...test_ECFLOW_247 \n";
+
+ defs_ptr defs = Defs::create();
+ suite_ptr s1 = defs->add_suite("s1");
+ family_ptr f1 = s1->add_family("f1");
+ f1->add_complete("f1/t1 == complete");
+ task_ptr t1 = f1->add_task("t1");
+ task_ptr t2 = f1->add_task("t2");
+ task_ptr t3 = f1->add_task("t3");
+ task_ptr t4 = f1->add_task("t4");
+
+ PrintStyle::setStyle( PrintStyle::MIGRATE);
+ {
+ defs->beginAll();
+ t1->set_state(NState::COMPLETE);
+ //cout << defs;
+
+ t4->set_state(NState::ABORTED);
+ t4->flag().set(ecf::Flag::FORCE_ABORT); // stopped bu user mimic, otherwise it be be queued
+
+ Jobs jobs(defs);
+ JobsParam jobsParam;
+ jobs.generate(jobsParam);
+ //cout << defs;
+
+ BOOST_CHECK_MESSAGE(f1->state() == NState::ABORTED,"The complete for family should not evaluate if child is aborted");
+ }
+ {
+ defs->requeue();
+ t1->set_state(NState::COMPLETE);
+ //cout << defs;
+
+ t4->set_state(NState::ACTIVE);
+
+ Jobs jobs(defs);
+ JobsParam jobsParam;
+ jobs.generate(jobsParam);
+
+ //cout << defs;
+ BOOST_CHECK_MESSAGE(f1->state() == NState::ACTIVE,"The complete for family should not evaluate if child is active");
+ }
+
+ {
+ defs->requeue();
+ t1->set_state(NState::COMPLETE);
+
+ Jobs jobs(defs);
+ JobsParam jobsParam;
+ jobs.generate(jobsParam);
+
+ t4->set_state(NState::SUBMITTED);
+
+ BOOST_CHECK_MESSAGE(f1->state() == NState::SUBMITTED,"The complete for family should not evaluate if child is submitted");
+ //cout << defs;
+ }
+
+ {
+ defs->requeue();
+ t1->set_state(NState::COMPLETE);
+ //cout << defs;
+
+ Jobs jobs(defs);
+ JobsParam jobsParam;
+ jobs.generate(jobsParam);
+
+ BOOST_CHECK_MESSAGE(f1->state() == NState::COMPLETE,"The complete for family should not evaluate if child is submitted");
+ //cout << defs;
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ANode/test/Test_ECFLOW-417.cpp b/ANode/test/Test_ECFLOW-417.cpp
new file mode 100644
index 0000000..eff4d75
--- /dev/null
+++ b/ANode/test/Test_ECFLOW-417.cpp
@@ -0,0 +1,157 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "PrintStyle.hpp"
+#include "CalendarUpdateParams.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/date_time/posix_time/time_formatters.hpp>
+#include <iostream>
+#include <stdlib.h>
+
+using namespace std;
+using namespace ecf;
+using namespace boost::posix_time;
+using namespace boost::gregorian;
+
+BOOST_AUTO_TEST_SUITE( NodeTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_ECFLOW_417_real_clock )
+{
+ // Make sure reque resets calendar according to the clock attribute *FOR* a real clock
+ cout << "ANode:: ...test_ECFLOW_417_real_clock \n";
+
+ defs_ptr defs = Defs::create();
+ suite_ptr s1 = defs->add_suite("s1");
+ s1->addRepeat(RepeatDay(1));
+ s1->addClock( ClockAttr(1,10,2015,false/*real clock*/) );
+ task_ptr t1 = s1->add_task("t1");
+ t1->addTime( ecf::TimeAttr(ecf::TimeSlot(16,0),false) );
+
+ defs->beginAll();
+
+ // ECF_DATE = year/month/day of month
+ {
+ const Variable& ecf_date = s1->findGenVariable("ECF_DATE");
+ BOOST_CHECK_MESSAGE(!ecf_date.empty(),"Did not find ECF_DATE");
+ BOOST_CHECK_MESSAGE(ecf_date.theValue() == "20151001","expected 20151001 but found " << ecf_date.theValue());
+ }
+
+ // now requeue and date should be reset
+ {
+ defs->requeue();
+ const Variable& ecf_date = s1->findGenVariable("ECF_DATE");
+ BOOST_CHECK_MESSAGE(!ecf_date.empty(),"Did not find ECF_DATE");
+ BOOST_CHECK_MESSAGE(ecf_date.theValue() == "20151001","expected 20151001 but found " << ecf_date.theValue());
+ }
+
+ // Now change the clock date to 10.10.2015.
+ {
+ s1->changeClockDate("10.10.2015");
+ const Variable& ecf_date = s1->findGenVariable("ECF_DATE");
+ BOOST_CHECK_MESSAGE(!ecf_date.empty(),"Did not find ECF_DATE");
+ BOOST_CHECK_MESSAGE(ecf_date.theValue() == "20151010","expected 20151010 but found " << ecf_date.theValue());
+ }
+
+ // now requeue
+ {
+ defs->requeue();
+ const Variable& ecf_date = s1->findGenVariable("ECF_DATE");
+ BOOST_CHECK_MESSAGE(!ecf_date.empty(),"Did not find ECF_DATE");
+ BOOST_CHECK_MESSAGE(ecf_date.theValue() == "20151010","expected 20151010 but found " << ecf_date.theValue());
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_ECFLOW_417_hybrid_clock )
+{
+ // ECFLOW-417
+ // For a suite with a hybrid clock *AND* repeat day. requue should update calendar date, by the repeat day interval
+ cout << "ANode:: ...test_ECFLOW_417_hybrid_clock \n";
+
+ defs_ptr defs = Defs::create();
+ suite_ptr s1 = defs->add_suite("s1");
+ s1->addRepeat(RepeatDay(1));
+ s1->addClock( ClockAttr(1,10,2015,true/*hybrid*/) );
+ task_ptr t1 = s1->add_task("t1");
+ t1->addTime( ecf::TimeAttr(ecf::TimeSlot(16,0),false) );
+
+ defs->beginAll();
+
+ // ECF_DATE = year/month/day of month
+ {
+ const Variable& ecf_date = s1->findGenVariable("ECF_DATE");
+ BOOST_CHECK_MESSAGE(!ecf_date.empty(),"Did not find ECF_DATE");
+ BOOST_CHECK_MESSAGE(ecf_date.theValue() == "20151001","expected 20151001 but found " << ecf_date.theValue());
+ }
+
+ // now requeue and date should be incremented
+ {
+ defs->requeue();
+ const Variable& ecf_date = s1->findGenVariable("ECF_DATE");
+ BOOST_CHECK_MESSAGE(!ecf_date.empty(),"Did not find ECF_DATE");
+ BOOST_CHECK_MESSAGE(ecf_date.theValue() == "20151002","expected 20151002 but found " << ecf_date.theValue());
+ }
+
+ // now requeue again and date should be incremented
+ {
+ defs->requeue();
+ const Variable& ecf_date = s1->findGenVariable("ECF_DATE");
+ BOOST_CHECK_MESSAGE(!ecf_date.empty(),"Did not find ECF_DATE");
+ BOOST_CHECK_MESSAGE(ecf_date.theValue() == "20151003","expected 20151003 but found " << ecf_date.theValue());
+ }
+
+
+ // Now change the clock date to 10.10.2015. We expect date to decremented to 09.10.2015,
+ // Since user should always re-queue after changing suite clock attributes.
+ // This will get us back to the original date set by the user.
+ {
+ s1->changeClockDate("10.10.2015");
+ const Variable& ecf_date = s1->findGenVariable("ECF_DATE");
+ BOOST_CHECK_MESSAGE(!ecf_date.empty(),"Did not find ECF_DATE");
+ BOOST_CHECK_MESSAGE(ecf_date.theValue() == "20151009","expected 20151009 but found " << ecf_date.theValue());
+ }
+
+ // now requeue and date should be incremented
+ {
+ defs->requeue();
+ const Variable& ecf_date = s1->findGenVariable("ECF_DATE");
+ BOOST_CHECK_MESSAGE(!ecf_date.empty(),"Did not find ECF_DATE");
+ BOOST_CHECK_MESSAGE(ecf_date.theValue() == "20151010","expected 20151010 but found " << ecf_date.theValue());
+ }
+
+ // Now update calendar for more than 24 hours, and calendar date should *NOT* change for hybrid
+ {
+ boost::posix_time::ptime time_now = s1->calendar().suiteTime();
+ boost::posix_time::time_duration serverPollPeriod = boost::posix_time::time_duration(0,1,0,0);
+ std::string expectedDate = "2015-Oct-10";
+
+ for(int hour=1; hour <= 60; hour++) {
+
+ // Update calendar every hour, for 60 hours
+ time_now += hours(1);
+ CalendarUpdateParams param(time_now, serverPollPeriod, true, /* serverRunning */ false /* forTest */ );
+
+ defs->updateCalendar( param );
+
+ // cout << "hour = " << hour << " timeAfterUpdate " << to_simple_string(s1->calendar().suiteTime()) << "\n";
+
+ std::string actualDate = to_simple_string(s1->calendar().suiteTime().date());
+ BOOST_CHECK_MESSAGE( actualDate == expectedDate,"Expected '" << expectedDate << "' but found " << actualDate << " at hour " << hour);
+ }
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME/suite.man b/ANode/test/data/SMSHOME/suite.man
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/SMSHOME/suite.man
rename to ANode/test/data/SMSHOME/suite.man
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME/suite/family.man b/ANode/test/data/SMSHOME/suite/family.man
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/SMSHOME/suite/family.man
rename to ANode/test/data/SMSHOME/suite/family.man
diff --git a/ANode/test/data/SMSHOME/suite/family/head.h b/ANode/test/data/SMSHOME/suite/family/head.h
new file mode 100644
index 0000000..68c9593
--- /dev/null
+++ b/ANode/test/data/SMSHOME/suite/family/head.h
@@ -0,0 +1,44 @@
+#!/bin/ksh
+
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+set -e # stop the shell on first error
+set -u # fail when using an undefined variable
+set -x # echo script lines as they are executed
+
+# Defines the three variables that are needed for any
+# communication with ECF_
+
+export ECF_PORT=%ECF_PORT% # ECF_ port numner
+export ECF_NODE=%ECF_NODE% # The name ecf server that issued this task
+export ECF_NAME=%ECF_NAME% # The name of this current task
+export ECF_PASS=%ECF_PASS% # A unique password
+export ECF_TRYNO=%ECF_TRYNO% # Current try number of the task
+
+# Tell ECF_ we have stated
+# The ECF_ variable ECF_RID will be set to parameter of smsinit
+# Here we give the current PID.
+
+#smsinit $$
+
+# Defined a error hanlder
+
+ERROR() {
+ set +e # Clear -e flag, so we don't fail
+ #smsabort # Notify ECF_ that something went wrong
+ trap 0 # Remove the trap
+ exit 0 # End the script
+}
+
+# Trap any calls to exit and errors caught by the -e flag
+
+trap ERROR 0
+
+# Trap any signal that may cause the script to fail
+
+trap '{ echo "Killed by a signal"; ERROR ; }' 1 2 3 4 5 6 7 8 10 12 13 15
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME/suite/family/t1.ecf b/ANode/test/data/SMSHOME/suite/family/t1.ecf
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/SMSHOME/suite/family/t1.ecf
rename to ANode/test/data/SMSHOME/suite/family/t1.ecf
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME/suite/family/t2.ecf b/ANode/test/data/SMSHOME/suite/family/t2.ecf
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/SMSHOME/suite/family/t2.ecf
rename to ANode/test/data/SMSHOME/suite/family/t2.ecf
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME/suite/family/t3.ecf b/ANode/test/data/SMSHOME/suite/family/t3.ecf
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/SMSHOME/suite/family/t3.ecf
rename to ANode/test/data/SMSHOME/suite/family/t3.ecf
diff --git a/ANode/test/data/SMSHOME/suite/family/tail.h b/ANode/test/data/SMSHOME/suite/family/tail.h
new file mode 100644
index 0000000..91682fb
--- /dev/null
+++ b/ANode/test/data/SMSHOME/suite/family/tail.h
@@ -0,0 +1,10 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+#smscomplete # Notify SMS of a normal end
+trap 0 # Remove all traps
+exit 0 # End the shell
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME/suite1_task1.ecf b/ANode/test/data/SMSHOME/suite1_task1.ecf
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/SMSHOME/suite1_task1.ecf
rename to ANode/test/data/SMSHOME/suite1_task1.ecf
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME/suite1_task2.ecf b/ANode/test/data/SMSHOME/suite1_task2.ecf
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/SMSHOME/suite1_task2.ecf
rename to ANode/test/data/SMSHOME/suite1_task2.ecf
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME/suite1_task3.ecf b/ANode/test/data/SMSHOME/suite1_task3.ecf
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/SMSHOME/suite1_task3.ecf
rename to ANode/test/data/SMSHOME/suite1_task3.ecf
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/bad/bad.ecf b/ANode/test/data/SMSHOME2/bad/bad.ecf
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/SMSHOME2/bad/bad.ecf
rename to ANode/test/data/SMSHOME2/bad/bad.ecf
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/bad/bad1.ecf b/ANode/test/data/SMSHOME2/bad/bad1.ecf
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/SMSHOME2/bad/bad1.ecf
rename to ANode/test/data/SMSHOME2/bad/bad1.ecf
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/bad/bad10.ecf b/ANode/test/data/SMSHOME2/bad/bad10.ecf
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/SMSHOME2/bad/bad10.ecf
rename to ANode/test/data/SMSHOME2/bad/bad10.ecf
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/bad/bad11.ecf b/ANode/test/data/SMSHOME2/bad/bad11.ecf
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/SMSHOME2/bad/bad11.ecf
rename to ANode/test/data/SMSHOME2/bad/bad11.ecf
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/bad/bad2.ecf b/ANode/test/data/SMSHOME2/bad/bad2.ecf
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/SMSHOME2/bad/bad2.ecf
rename to ANode/test/data/SMSHOME2/bad/bad2.ecf
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/bad/bad3.ecf b/ANode/test/data/SMSHOME2/bad/bad3.ecf
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/SMSHOME2/bad/bad3.ecf
rename to ANode/test/data/SMSHOME2/bad/bad3.ecf
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/bad/bad4.ecf b/ANode/test/data/SMSHOME2/bad/bad4.ecf
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/SMSHOME2/bad/bad4.ecf
rename to ANode/test/data/SMSHOME2/bad/bad4.ecf
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/bad/bad5.ecf b/ANode/test/data/SMSHOME2/bad/bad5.ecf
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/SMSHOME2/bad/bad5.ecf
rename to ANode/test/data/SMSHOME2/bad/bad5.ecf
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/bad/bad6.ecf b/ANode/test/data/SMSHOME2/bad/bad6.ecf
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/SMSHOME2/bad/bad6.ecf
rename to ANode/test/data/SMSHOME2/bad/bad6.ecf
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/bad/bad7.ecf b/ANode/test/data/SMSHOME2/bad/bad7.ecf
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/SMSHOME2/bad/bad7.ecf
rename to ANode/test/data/SMSHOME2/bad/bad7.ecf
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/bad/bad8.ecf b/ANode/test/data/SMSHOME2/bad/bad8.ecf
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/SMSHOME2/bad/bad8.ecf
rename to ANode/test/data/SMSHOME2/bad/bad8.ecf
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/bad/bad9.ecf b/ANode/test/data/SMSHOME2/bad/bad9.ecf
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/SMSHOME2/bad/bad9.ecf
rename to ANode/test/data/SMSHOME2/bad/bad9.ecf
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/bad/bad_ecfmicro.ecf b/ANode/test/data/SMSHOME2/bad/bad_ecfmicro.ecf
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/SMSHOME2/bad/bad_ecfmicro.ecf
rename to ANode/test/data/SMSHOME2/bad/bad_ecfmicro.ecf
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/bad/bad_ecfmicro_1.ecf b/ANode/test/data/SMSHOME2/bad/bad_ecfmicro_1.ecf
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/SMSHOME2/bad/bad_ecfmicro_1.ecf
rename to ANode/test/data/SMSHOME2/bad/bad_ecfmicro_1.ecf
diff --git a/ANode/test/data/SMSHOME2/bad/includes/recursive_head.h b/ANode/test/data/SMSHOME2/bad/includes/recursive_head.h
new file mode 100644
index 0000000..676b8c1
--- /dev/null
+++ b/ANode/test/data/SMSHOME2/bad/includes/recursive_head.h
@@ -0,0 +1,14 @@
+#!/bin/ksh
+
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+#
+# test recursive include
+#
+%include <recursive_head.h>
+
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/.gitignore b/ANode/test/data/SMSHOME2/good/.gitignore
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/SMSHOME2/good/.gitignore
rename to ANode/test/data/SMSHOME2/good/.gitignore
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/ecf_micro_2.ecf b/ANode/test/data/SMSHOME2/good/ecf_micro_2.ecf
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/SMSHOME2/good/ecf_micro_2.ecf
rename to ANode/test/data/SMSHOME2/good/ecf_micro_2.ecf
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/ecfmicro.ecf b/ANode/test/data/SMSHOME2/good/ecfmicro.ecf
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/SMSHOME2/good/ecfmicro.ecf
rename to ANode/test/data/SMSHOME2/good/ecfmicro.ecf
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/good.ecf b/ANode/test/data/SMSHOME2/good/good.ecf
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/SMSHOME2/good/good.ecf
rename to ANode/test/data/SMSHOME2/good/good.ecf
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/good1.ecf b/ANode/test/data/SMSHOME2/good/good1.ecf
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/SMSHOME2/good/good1.ecf
rename to ANode/test/data/SMSHOME2/good/good1.ecf
diff --git a/ANode/test/data/SMSHOME2/good/includes/config.h b/ANode/test/data/SMSHOME2/good/includes/config.h
new file mode 100644
index 0000000..d74ccd7
--- /dev/null
+++ b/ANode/test/data/SMSHOME2/good/includes/config.h
@@ -0,0 +1,1527 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+#=======================================================================
+# config.h
+#=======================================================================
+banner config.h
+
+if [[ "$ARCH" != "linux" ]] ;then
+ typeset -l ARCH
+fi
+
+export SCRATCHDIR=${SCRATCHDIR:-UNDEFINED}
+export ARCH=${ARCH:-sgimips}
+export TMPDIR=${TMPDIR:-UNDEFINED}
+export HOST=${HOST:-`hostname`}
+export NPES=${NPES:-0}
+
+if [[ $ARCH = linux ]] ; then
+ export EMOS_TMPDIR=/var/tmp/tmpdir/%TASK%_%ECF_TRYNO%.$$
+ export TMPDIR=$EMOS_TMPDIR
+ [[ -d $TMPDIR ]] || mkdir -p $TMPDIR
+ export USE_EMOS_TMP="true"
+ cd $TMPDIR
+else
+ EMOS_TMPDIR=""
+fi
+
+if [[ "$TMPDIR" = "UNDEFINED" ]] ; then
+ TMPDIR="$TEMP/NQS_tmpdir.$$" export TMPDIR
+ export USE_EMOS_TMP="true"
+ [[ -d $TMPDIR ]] || mkdir $TMPDIR
+ if [[ $? -ne 0 ]] ; then
+ echo "####### CANNOT CREATE TMPDIR #######" >&2
+ exit 1
+ fi
+fi
+
+PS4="+ "
+
+echo "\
+ This is the config.h file and\n\
+ System variables used were:\n\
+ USER $USER\n\
+ TMPDIR $TMPDIR\n\
+ HOME $HOME\n\
+ HOST $HOST\n\
+ ARCH $ARCH\n\
+ PATH $PATH\n\
+"
+set -xa
+
+#=======================================================================
+# Experiment version and initial data origin (default values)
+#=======================================================================
+
+EXPVER=%VERSION:0001%
+GRIBCLASS=1
+BASEVER=0001
+BASETIME=1996072200
+
+#=======================================================================
+# Software configuration (library cycles etc)
+#=======================================================================
+
+IFSMASTER=ifsMASTER
+#####################################
+IFS_CYCLE=35r3
+#####################################
+
+
+SUITE_TYPE=%SUITE_TYPE:"undef"%
+NEWSTREAM=none
+EMOS_CYCLE=000370
+VIEW_IFS=
+VIEW_IFSAUX=
+VIEW_OBSPROC=
+VIEW_OBSORT=
+VIEW_TOVSCODE=
+VIEW_SSMICODE=
+VIEW_BL=
+VIEW_SSA=
+VIEW_SST=
+VIEW_WAM=
+MAKE_LIBS=yes
+
+GRIB_API_VERSION=1.8.0
+GRIB_API_INCLUDE="-I/usr/local/lib/metaps/lib/grib_api/jasper/include -I/usr/local/lib/metaps/lib/grib_api/$GRIB_API_VERSION/include"
+GRIB_API_LIB="-L/usr/local/lib/metaps/lib/grib_api/jasper/lib -ljasper -L/usr/local/lib/metaps/lib/grib_api/$GRIB_API_VERSION/lib -lgrib_api_f90 -lgrib_api"
+export GRIB_API=/usr/local/lib/metaps/lib/grib_api/$GRIB_API_VERSION/bin # change to fixed version
+export PATH=$GRIB_API:$PATH
+
+#=======================================================================
+# Model configuration
+#=======================================================================
+
+RESOL=799
+LEVELS=91
+GTYPE=l_2
+FCLENGTH=%FCLENGTH:6%
+FCLENGTH0N=$FCLENGTH
+RUN_GFC=no
+
+#=======================================================================
+# Analysis parameters
+#=======================================================================
+
+IFSMODE=early_delivery
+PERIOD=6
+TSTEP=720
+
+if [[ "%STREAM%" = SCDA ]] && [[ %MXUP_TRAJ:3% = 1 ]] ; then
+ RESOLINC_0=255 # HR:255, LR:159
+ TSTEP_INC_0=1800
+else
+ RESOLINC_0=95
+ TSTEP_INC_0=3600
+fi
+
+RESOLINC_1=159 # 255 32r1
+RESOLINC_2=255 # 159 32r1
+TSTEP_INC_1=1800
+TSTEP_INC_2=1800
+
+LFG=.false.
+
+ITER_MIN_0=70
+ITER_MIN_1=50
+ITER_MIN_2=50
+MXUP_TRAJ=%MXUP_TRAJ:3%
+NMINSIMPHY=1
+LINCNMI=false
+LVERIFY_SCREEN=true
+SCRANA=active
+
+RESOLFCE=42
+ITER_FCE=150
+NWRIEVEC=25
+
+OBPATH=ops
+BLACK_DS=ops
+BLACK_MM=ops
+BLACK_EX=ops
+
+LOZONE=true
+LOZONECH=true
+ANEMOM_HT=true
+LISENTRPP=true
+LESUITE=false
+
+OBNLAT=90.00
+OBSLAT=-90.00
+OBWLON=-180.00
+OBELON=180.00
+
+MPLARGS="check=0"
+
+#================================
+# New for 25r3
+
+LINRADEX=true
+LREDUCOB=false
+TSLOTSEC=1800
+UPTRAJ_FCE=0
+LAMV_REASSIGN=false
+
+#================================
+# New for 25r4
+
+BRANCH=""
+BRF=0
+LAIRS=true
+PARALLEL=4
+PROJECTS="none"
+
+#================================
+# New for 26r3
+
+if [[ "%SUITE%" = o || "%SUITE%" = e_* ]] ; then
+ LARCHINCR=true
+else
+ LARCHINCR=false
+fi
+
+#================================
+# New for 28r1
+
+FPOSCLD=%FPOSCLD:false% # should be true for 4dvar, false for 3d_fgat
+PROFILE=%PROFILE:0% # for diagnostic purposes
+LANOBSENS=false
+
+#================================
+# New for 28r2
+#==========================================================
+# Variables configuring testOfAnalysis
+#==========================================================
+LTESTVAR=false
+NTESTVAR=0
+LCVTEST=false
+LTLTEST=false
+LADTEST=false
+LGRTEST=false
+LTESTINC=false # should be set to false and will turn off other testing
+
+#==========================================================
+# New for 28r3
+#==========================================================
+REINIHOUR=%REINIHOUR:0%
+ED_PERIOD=%ED_PERIOD:12%
+ED_ONLY=%ED_ONLY:false%
+REINICLASS=%REINICLASS:od%
+REINI_NOT_ED=%REINI_NOT_ED:false%
+OBSTREAM=%STREAM%
+
+#==========================================================
+# New for 29r1
+#==========================================================
+set -a
+LOBREALTIME=%OBREALTIME:false% ; # false in catchup mode, true in rt
+LCALC_PSBIAS=%CALC_PSBIAS:true%
+LUSE_PSBIAS=%USE_PSBIAS:true%
+INIPSBIAS=%INIPSBIAS:true%
+INIVARBC=%INIVARBC:false%
+
+NTYPE_MODERR=2
+NCOMP_MODERR=1
+LFGMODERR=true
+ALPHAQ=0.3 # 31r2
+NSERR=-1
+LINITCV=true
+LMODERRFC=false
+LBGMODERR=false
+
+LPROPTL=false
+LINTEST=false
+
+SAVINI=false
+
+EPSROTPATH=""
+
+#==========================================================
+# New for 29r2
+#==========================================================
+set -a
+LTWINTRUTH=false
+LTWINEXP=false
+TRUTHEXP="none"
+LCO2=false
+LCO2ANER=false
+INICO2=false
+LERA40_PREODB=false
+Q2CREATE_NEWSTREAM=false
+Q2USE=false
+Q2CHANGELIST=0
+
+# EPS
+NSVET=50
+NITERLET=120
+EPSBASIS=50 # number of tropical singular vectors used in
+ # Gaussian sampling
+EPSBASIST=5 # number of tropical singular vectors used in
+
+ # in order to startup emc suite this might be set to 25
+ # for the first 2 way. Then make_sv would not be used.
+
+EPSEVO_NORMALIZE=true
+ICPEXPVER=%ICPEXPVER:0001%
+EPSGAMMA_TC2INI=1.5
+EPSGAMMA_EVO2INI=1.0 # 1.5 for 29r2
+EPSGAMMA=0.014
+EPSSIMPL=5 # Gaussian sampling for all singular vectors
+#==========================================================
+# New for 29r3
+#==========================================================
+
+LGPINNER=true
+NFRDHP=3
+
+#==========================================================
+# New for 30r1
+#==========================================================
+FILTERRESOL=255
+FILTERFACTOR=5
+FILTEREXPONENT=4
+EC_FILL_NANS=false
+USE_SMT=%USE_SMT:true%
+
+if [[ "%EC_SMT:yes%" = yes ]] ; then
+ USE_SMT=true
+else
+ USE_SMT=false
+fi
+
+#==========================================================
+# New for 30r2
+#==========================================================
+LUSE_RSTBIAS=%USE_RSTBIAS:true%
+ERA_MODE=false
+
+#==========================================================
+# New for 31r1
+#==========================================================
+DOFDBK=true # ie true
+LCALC_RSTBIAS=%CALC_RSTBIAS:false%
+VARBC_PATH=%VARBC_PATH:standard%
+NCS_CONFIG=2 # 31r2
+USE_SMT=%USE_SMT:true%
+LPML=%PRODUCE_EPS_ML:0%
+
+if [[ %EC_SMT:yes% = yes ]] && [[ %USE_SMT:true% = false ]] ; then
+ echo "ECF_ variable EC_SMT and USE_SMT are not compatible"
+ exit 1
+elif [[ %EC_SMT:yes% = no ]] && [[ %USE_SMT:true% = true ]] ; then
+ echo "ECF_ variable EC_SMT and USE_SMT are not compatible"
+ exit 1
+fi
+#==========================================================
+# New for 31r2
+#==========================================================
+LRAIN4D=true
+LNMPHYS=true #32r1
+ENDANENS=0
+ENDANENSODB=0
+
+P4CLIENT=0 #32r1 not used in operations
+
+#==========================================================
+# New for 32r1
+#==========================================================
+LCONSTANT_VARBC=false
+
+#==========================================================
+# New for 32r2
+#==========================================================
+LIASI=true
+
+INIMODISALB=true # if intial data was run with 32r1 or later
+VARBC_ARCHIVE_EVOLVE=false
+
+#==========================================================
+# New for 32r3
+#==========================================================
+LFULL_IASI=%LFULL_IASI:true% # true = use full iasi data and screen: false use screened data
+LGEMS=false # run with gems parameters
+GHGVAR=
+GRGVAR=
+AEROVAR=
+TRACVAR=
+INIGHG=false
+INIGRG=false
+INIAERO=false
+INITRAC=false
+LEVGEN=true # Use van Genuchten hydrology
+INIHTESSEL=true # if starteding from experiment where LEVGEN=true
+LCALC_RSTRHBIAS=%CALC_RSTRHBIAS:true%
+LUSE_RSTRHBIAS=%LUSE_RSTRHBIAS:true%
+LSSMI1D=true
+LSSMIS1D=true
+LAMSRE1D=true
+LTMI1D=true
+LAMSRE1D=true
+ODB_IO_OPENMP=1
+
+#==========================================================
+# New for 33r2
+#==========================================================
+LOBSCOR=false
+
+#==========================================================
+# New for 35r2
+#==========================================================
+
+LECURR=false
+INIECURR=false
+LSCATT_NEUTRAL=false
+D3GGFIELDSSTEND="0"
+LFSOBS=false
+LSEKF=false
+
+#==========================================================
+# New for 35r3
+#==========================================================
+# if EPS or associated then LEMISKF & LWEAK4DVAR=false
+INIOZONE=true
+
+WEAK4D_INTERV=0.0
+LMODERR_PERIODIC=false
+NSPLIT4DWIN=0
+LBALSTRATO=false
+AMSU_LAND=Dynamic_emis
+EMISKF_PATH=standard
+INIEMISKF=true
+INIMODERR=true
+LDUCTDIA=false
+LASCATSM=true
+if [[ %SUITE% = "e_*" ]] ; then LANOBSENS=true; fi
+
+#==========================================================
+# Variables configuring ifs_ctm
+#==========================================================
+LCOUPLO4=false
+CTM_MODEL=mozart
+NFRCOUPLO4=1
+NFRCOUPLO4_FB=1
+LGLOBALGP=true
+LGLOBALSP=true
+MPROCGPG=1
+MPROCSPG=1
+LOUT_SPC=false
+LOUT_FLUX=true
+LOUT_COOR=false
+LIN_GRG=true
+LIN_COOR=false
+LCOUPLO4_CTM=true
+LOUT_GRG=false
+LOUT_CO=false
+LOUT_SO2=false
+LOUT_NOX=false
+LOUT_NO2=false
+LOUT_GO3=false
+LOUT_HCHO=false
+LNOX2NO2=false
+INTERP2D=bilinear
+PARA_SEARCH=global
+IF_MASKED=novalue
+LGRG_CYCLE=true
+LDIFF_GRG=false
+LCONV_GRG=false
+LDIA_GRG=false
+NPROC_CTM=8
+NPROC_CTM_AN=8
+NPROC_DRV=1
+CTM_THREADS=4
+CTM_THREADS_AN=4
+DRV_THREADS=1
+DRV_THREADS_AN=1
+IFS_THREADS_AN=6
+LSTATS=true
+
+#==========================================================
+# Variables configuring Gems
+#==========================================================
+LGEMS=false
+GHGVAR=""
+INIGHG=false
+GRGVAR=""
+INIGRG=false
+AEROVAR=""
+INIAERO=false
+TRACVAR=""
+INITRAC=false
+
+#=======================================================================
+# DR_HOOK
+#=======================================================================
+DR_HOOK=true # 30r1 was false
+DR_HOOK_OPT="none" # 30r1 was "prof"
+DR_HOOK_PROFILE_LIMIT=-10
+DR_HOOK_HASHBITS=15
+DR_HOOK_CATCH_SIGNALS=false
+DR_HOOK_IGNORE_SIGNALS=false
+
+LIBHPM=""
+if [[ $DR_HOOK = true ]] ; then
+ DR_HOOK_OPT=`echo $DR_HOOK_OPT | sed -e 's/\// /g'`
+ if [[ $ARCH = ibm_power4 ]] ; then
+ LIBHPM="-L/usr/pmapi/lib -lpmapi"
+ fi
+fi
+
+#=======================================================================
+# BC project setup for analysis (only those that are different)
+#=======================================================================
+
+if [[ "%STREAM%" = SCDA ]] ; then
+ PERIOD_4D=6 ;
+ WINDOW_LENGTH_4D=%WINDOW_LENGTH_4D:12%
+ WINDOW_OFFSET_4D=%WINDOW_OFFSET_4D:9%
+
+ if [[ %MXUP_TRAJ:3% = 3 ]] ; then
+
+ IFSMODE=4d_inc
+
+ else
+
+ IFSMODE=3d_fgat
+ ITER_MIN=70
+ ITER_MIN_1=0
+ SIMUL_MIN=80
+ SIMUL_MIN_1=0
+ LISENTRPP=false
+ LVERIFY_SCREEN=false
+
+ fi
+else
+ # PERIOD_4D=6 ; # 20040423 should stay 12 by default (for SCDA reinit), then SMS variable is set to 12, this variable is considered for reinit = false (vardata.sms)
+if [[ `echo %FAMILY:NOT_DEF% | cut -d / -f 1` = "main" ]] ; then
+ ## RD behaviour : default is constant 12,
+ ## if SMS variable is changed, task should consider it specifically
+ ## some tasks (vardata, fetcherr) may want this default and not SMS
+ ## variable for REINITIALIZE state
+ PERIOD_4D=12
+ WINDOW_LENGTH_4D=12
+ WINDOW_OFFSET_4D=3
+
+else # SMS variable IS the environment variable for other families
+ PERIOD_4D=%PERIOD_4D:12%
+ WINDOW_LENGTH_4D=%WINDOW_LENGTH_4D:12%
+ WINDOW_OFFSET_4D=%WINDOW_OFFSET_4D:3%
+fi
+fi
+
+#=================================================
+# Simplified Kalman filter parameters
+#=================================================
+
+TSTEP_SV=1200
+RESOLSV=42
+NLANTYPE=6
+NJDSTOP=48
+NITERL=60
+NINNER=30
+NEIGEVO=60
+HESSTYPE=3d
+SVPPFRQ=6
+
+
+################### New for 23r1 #############
+LATE4DSTART=true
+FPOSINC=false
+INICLOUDAN=true
+
+
+#=======================================================================
+# Satellite parameters
+#=======================================================================
+
+LTOVS=.false.
+LATOVS=true
+LAIRS=true # 31r1
+LSSMI=true # 33r1
+LSCAT=.true.
+LGEOS=true
+LRAIN1D=false # 35r2
+LSSMIRAIN=true # 33r2
+LSSMISRAIN=true # 35r3
+LTMIRAIN=true # 35r3
+LAMSRERAIN=true # 33r2
+LPRERAD1C=false
+LREO3=true
+LAEOLUS=false # 31r1
+LSSMIS=true # 31r2
+LAMSRE=true # 31r2
+LMERIS=true # 20080714 until which was false # 33r2
+LTMI=true # 31r2
+LGPSRO=true # 31r2
+
+BIAS_PATH_AMV=none
+BIAS_PATH_REO3=none
+LREO3_BCOR=false
+
+BIASCOLD=yes
+BIASDAYS=14
+BIASMISS=7
+BIAS_ARCHIVE=1
+
+if [[ "%SUITE%" = o || "%SUITE%" = e_* ]] ; then
+ export FDB_NOF_BUFF=4
+ export FDB_BUF_SECT_SIZE=25165824
+elif [[ "%SUITE%" = bc || "%SUITE%" = ebc_* ]] ; then
+ export FDB_NOF_BUFF=3
+ export FDB_BUF_SECT_SIZE=33554432
+else
+ export FDB_NOF_BUFF=4
+ export FDB_BUF_SECT_SIZE=4194304
+fi
+
+# 23r4
+RSTBIAS=true
+
+# 24r2
+ERAFS=false
+
+# SATMON parameters
+SMON_OPT_DIR=""
+SMON_OPT_GEOS=ops
+SMON_OPT_NOAA=ops
+SMON_OPT_DMSP=ops
+SMON_OPT_O3=ops
+SMON_OPT_O3KNMI=ops
+SMON_OPT_O3MSG=ops
+SMON_OPT_TEMP=ops
+SMON_OPT_PWC=ops
+SMON_OPT_AMV=ops
+SMON_OPT_DBAMV=ops # 33r1
+SMON_OPT_AIRS=ops
+SMON_OPT_IASI=ops # 32r3
+SMON_OPT_EARS=ops
+SMON_OPT_PACRARS=ops # 33r1
+SMON_OPT_MERIS=ops # 33r2
+SMON_OPT_SSMIS=ops # 31r2
+SMON_OPT_AMSRE=ops # 31r2
+SMON_OPT_TMI=ops # 31r2
+SMON_OPT_GPSRO=ops # 31r2
+SMON_OPT_SCATT=ops # 35r3
+SMON_OPT_SLMOIST=ops # 35r3
+
+
+SATROOT=/od_archive/data/satmon
+
+#==========================================================
+# Variables configuring Reanalysis
+#==========================================================
+MEANS=true
+MOMENTS=true
+INTEGRALS=true
+INCREMENTS=true
+PLOTS=true
+RSTBIAS_TS=false
+RSTBIAS_SE=true
+ERAPRODUCTS="/era/intprod/data/monitor"
+
+#=======================================================================
+# Coupled wave model parameters
+#=======================================================================
+
+WAVE=yes
+WAM2WAY=yes
+WAMNSTPW=1
+ if [[ "%FSFAMILY%" = @(mc|refc|assim) ]] ; then
+WAMRESOL=global100
+else
+WAMRESOL=global36 # HR global50
+fi
+WAMALT=yes
+WAMSAR=yes
+WAMSARASS=true
+
+if [[ "%FSFAMILY%" = "euroshelf" || $SUITE_TYPE = "law" ]] ; then # law suites
+ WAMNFRE=30 # 36 future 0044
+ WAMNANG=24 # 36 future 0044
+else
+ WAMNFRE=30
+ WAMNANG=24
+fi
+
+date_ers1_wave=1994010100
+
+if [[ $BASETIME -lt $date_ers1_wave || $WAMALT != yes ]] ; then
+ WAMANPARAM_DYN="215/216/220/221/222/223/224/225/226/227/228/229/230/231/232/233/234/235/236/237/238/239/244/245/249"
+else
+ WAMANPARAM_DYN="215/216/217/218/220/221/222/223/224/225/226/227/228/229/230/231/232/233/234/235/236/237/238/239/244/245/246/247/248/249/252/253/254"
+fi
+
+WAMANPARAM_STAT="219"
+WAMANPARAM=$WAMANPARAM_STAT/$WAMANPARAM_DYN
+
+WAMFCPARAM_STAT="219"
+WAMFCPARAM_DYN="215/216/217/218/220/221/222/223/224/225/226/227/228/229/230/231/232/233/234/235/236/237/238/239/244/245/249/252/253/254"
+WAMFCPARAM=$WAMFCPARAM_STAT/$WAMFCPARAM_DYN
+
+INIWAVE=yes
+WAMCOLDLENGTH=240
+WAMSTREAM=0
+# Many of these values are overridden for
+# local area model in law.h
+
+if [[ "%STREAM%" = SCDA ]] ; then
+ WAMSTREAM=1027
+elif [[ "%STREAM%" = DCDA ]] ; then
+ WAMSTREAM=1029
+fi
+
+#=======================================================================
+# Initial data parameters
+#=======================================================================
+
+
+INITIME=%INITIME:2001042900%
+INICLASS=%INICLASS:od%
+INISTREAM=%INISTREAM:da%
+# da : early delivery suite initialised from standard suite
+# dcda : early delivery suite initialised from another delayed cutoff suite
+INITYPE=4v
+INIEXPVER=%INIEXPVER:0001%
+INILEVELS=%INILEVELS:60%
+INISTEP=%INISTEP:0%
+# size of the 4dvar window
+
+# offset from the beginning of the 4V for FC
+INIOFFSET_4D=%INIOFFSET_4D:3%
+# 9 : early delivery suite initialised from standard suite
+# 3 : early delivery suite initialised from another ealry delivery suite
+INITILES=true
+INIRESOL=799 # was 511
+INICI=true
+FORCE_FP=no
+
+if [[ "%FAMILY1:NOT_DEF%" = sv || "%FAMILY1:NOT_DEF%" = m2_12 || "%FAMILY1:NOT_DEF%" = m2_00 || "%FAMILY1:NOT_DEF%" = m1_12 || "%FAMILY1:NOT_DEF%" = m1_00 ]] ; then
+ INITYPE=fc
+# ------- vv
+# INISTEP=12 # for 00,12 UTC forecasts
+# ------- ^^
+ INISTEP=6 # for 06,18 UTC forecasts
+ INISTREAM=dcda
+ INISUFFIX="_sv"
+else
+ INISUFFIX=
+fi
+
+if [[ "$ARCH" != "linux" ]];then
+ typeset -l REINITIALIZE
+fi
+REINITIALIZE=%REINITIALIZE:false%
+REINIEXPVER=%REINIEXPVER:0001%
+REINISTREAM=%REINISTREAM:da%
+REINIPERIOD_4D=%REINIPERIOD_4D:12%
+REINIOFFSET=%REINIOFFSET:12%
+ED_CUTOFF=%ED_CUTOFF:4%
+
+#=================================================
+# PE settings
+#=================================================
+NPES_MKCMA=%MKCMANPES:1%
+NPES_AN=%ANNPES:1%
+NPES_FC=%FCNPES:1%
+NPES_SV=%FCNPES:1%
+#=================================================
+# PREPAN parameters
+#=================================================
+
+OWNER=emos
+AMASTER=/ws/home/ma/emos/amaster/xxxx
+RUN_PARALLEL=true
+
+#=======================================================================
+# Sami's variables + ODB
+#=======================================================================
+
+CONCAT=1
+PMETHOD=2
+FSODB=/emos_backup
+
+ODB_CTX_DEBUG=0
+ODB_MAXHANDLE=5
+ODB_STATIC_LINKING=1
+ODB_UNDEF=2146959359
+ODB_CCMA_CREATE_DIRECT=1
+ODBSAVE_ODBCMP=true #31r2
+ODB_FROM_FB=false
+if [[ "%STREAM%" = SCDA ]] ; then
+ ODBSAVE_CCMA=false
+ ODBSAVE_ECMA=false
+else
+ ODBSAVE_CCMA=true
+ ODBSAVE_ECMA=true
+fi
+ODB_CATCH_SIGNALS=0
+ODB_CCMA_IGNORE_TSLOTS=0
+ODB_CCMA_OBS_RANDOMIZE=0
+ODB_CCMA_WTMETHOD=107
+ODB_ERRTRA=1
+ODB_FLPCHECK=0
+ODB_INTCHECK=0
+ODB_IO_METHOD=4
+ODB_IO_FILESIZE=128
+ODB_PACKING=-1
+ODB_REPRODUCIBLE_SEQNO=4
+ODB_TEST_INDEX_RANGE=0
+ODB_WRITE_EMPTY_FILES=0
+
+MANPATH=""
+#=======================================================================
+# Coupled wave variables
+#=======================================================================
+
+WGRIBIN=yes
+
+#================================
+# New for 19r1, should be put in correct place.
+
+HESS3D=3d
+PPFRQ=12
+LINCNMI=false
+NEIGEVO=60
+#================================
+# New for 24r4
+
+LMAPSOP=false
+MPP_TYPE=1
+if [[ "%STREAM%" = SCDA ]] && [[ %MXUP_TRAJ:3% = 1 ]] ; then
+ LTRAJHR=false
+else
+ LTRAJHR=true
+fi
+
+#================================
+# New for 26r3
+
+LMODERR=false
+
+#=======================================================================
+# Plot control
+#=======================================================================
+
+PLOT_RMS=true
+
+#=======================================================================
+# Standard libraries
+#=======================================================================
+
+SCHOST=%SCHOST%
+SCHOST_BKUP=%SCHOST_BKUP:not_set%
+# storage host
+STHOST=%STHOST:%
+STHOST_BKUP=%STHOST_BKUP%
+WSHOST=%WSHOST%
+
+LIBRESOL=.R64.D64.I32
+ELIB=/usr/local/lib/metaps/lib/${EMOS_CYCLE}
+
+if [[ $ARCH = ibm_power* ]] ; then
+ SLIB=/usr/local/lib
+###########################################
+#temporary setting: A.Hofstadler, 200200821
+ EMOSLIB="-lemos.R64.D64.I32"
+ ECLIB="-L $SLIB "
+ FDBLIB="-L $SLIB -lfdb"
+#temporary setting:
+###########################################
+ EMOSLIB="-L $ELIB $EMOSLIB"
+ OBJECT_MODE=64
+ XLFRTEOPTS=err_recovery=no
+else
+###########################################
+#temporary setting: A.Hofstadler, 200200821
+# EMOSLIB="-lemos.R64.D64.I32"
+ EMOSLIB="-lemos.R32.D64.I32" # or single???
+#temporary setting:
+###########################################
+ SLIB=/usr/local/lib
+ EMOSLIB="-L $ELIB $EMOSLIB"
+fi
+
+emosbin=/home/ma/emos/bin/${EMOS_CYCLE}/$ARCH
+#=======================================================================
+# Singular vector configuration
+# NSVHEM=1 for SVs over NH only
+# 2 " SH only
+# 3 " NH+SH
+#=======================================================================
+
+EPSSVPATH=
+EPSSVROTPATH=
+EPSFCRES=%EPSFCRES:399% # HR 255
+
+# VAREPS 30r2
+EPSFCRES_A=%EPSFCRES_A:399% # HR 255
+EPSFCRES_B=%EPSFCRES_B:255% # HR 255
+EPSFCRES_C=%EPSFCRES_C:255% # HR 255
+
+EPSFCLENGTH_A=%EPSFCLENGTH_A:240%
+EPSFCLENGTH_B=%EPSFCLENGTH_B:144%
+EPSFCLENGTH_C=%EPSFCLENGTH_C:408%
+
+EPSINISTEP_B=%EPSINISTEP_B:216%
+EPSINISTEP_C=%EPSINISTEP_C:360%
+
+EPSFCGTYPE=%EPSFCGTYPE:l_2%
+EPSFCGTYPE_A=%EPSFCGTYPE_A:l_2%
+EPSFCGTYPE_B=%EPSFCGTYPE_B:l_2%
+EPSFCGTYPE_C=%EPSFCGTYPE_C:l_2%
+
+EPSVARHDIF=false
+EPSVARHDIFT=24
+
+EPS_USE_ICP=0
+# /VAREPS
+
+EPSFCLEV=%EPSFCLEV:62% # HR 40
+EPSSVRES=%EPSSVRES:42%
+EPSSVGTYPE=_full
+EPSSVLEV=%EPSSVLEV:62% # HR 40
+EPSMEMBERS=`echo "%ENSEMBLES:50% + 1" | bc`
+EPSNENS=%ENSEMBLES:50%
+EPSEVO=1
+EPSHEM=%EPSHEM:3%
+EPSEVOTIME=48
+
+EPSWAMRESOL=%EPSWAMRESOL:global100%
+EPSWAMNSTPW=%EPSWAMSTPW:1%
+EPSTSTEP=%TSTEP:1800% # HR 2700
+EPSSVTSTEP=%EPSSVTSTEP:900%
+
+if [[ %STREAM% = MAED ]] ; then
+ INIMODISALB=false
+TSTEP=$EPSTSTEP
+fi
+
+EPSTSTEP_SV=900 # HR 1200
+EPSWAMALT=no
+EPSTYPE=%EPSTYPE%
+EPSMEMBER=%MEMBER%
+FCTOTAL=$EPSMEMBERS
+NTOTAL=$EPSNENS
+EPSSVDIAB=%EPSSVDIAB:false%
+EPSSVNUM=%EPSSVNUM:0%
+
+# 28r3
+DELTAHH_TC_TRACKS=12 # 12h lag from previous TC used in targets task
+EPSSV_TOPT=48 # optimization time for the tropical singular vectors
+ # targets
+
+TC_TRACKS_EXPVER=%VERSION:0001% # ???TDB
+
+if [[ %VERSION:0001% = 0020 ]] ; then
+ TC_TRACKS_EXPVER=0001
+fi
+
+OD_PROJ=%OD_PROJ:od%
+
+if [[ "%SUITE%" = emc* ]] && [[ %IS_REAL_TIME:false% = false ]] ; then
+ TC_TRACKS_PATH=/emos/tc/0001
+elif [[ $REINITIALIZE = true ]] ; then
+ TC_TRACKS_PATH=/emos/tc/$REINIEXPVER
+elif [[ %FIRST_DAY% = 1 ]] ; then
+ TC_TRACKS_PATH=/emos/tc/$INIEXPVER
+ TC_TRACKS_EXPVER=0001
+elif [[ ! "$OD_PROJ" = "od" ]] ; then
+# || [[ %IS_REAL_TIME:false% = false ]] ; then
+ ## MC_NO and other MS suites
+ ## and catchup mode running 12 cycle only
+ TC_TRACKS_PATH=/emos/tc/0001
+else
+ TC_TRACKS_PATH=/emos/tc/%VERSION%
+fi
+
+TC_TRACKS_FROM_MARS=true
+TC_TRACKS_CLASS=od
+
+EPSSVTCSUB=%EPSSVTCSUB:0%
+EPSTCBB=%EPSTCBB:1% # use TC tracks to define optimization regions
+EPSSVOP=%EPSSVOP:0% # not required to set sms variable in OD
+EPSSVTC_ORTHONORM=1 # ortho-normalize tropical SVs
+
+RUNHINDCAST=%RUNHINDCAST:0% # 1 for back loop and 0 for realtime
+
+#=======================================================================
+# EFI PATHS:
+#=======================================================================
+EFI_WS_CACHE=/efi_clim/data/cache
+EFI_WS_SCRATCH=/efi_clim/data/scratch
+EFI_ECFS_PATH=ec:/emos/efi_clim
+EFI_HPCF_PATH=/home/ma/emos/data/efi_clim
+#=======================================================================
+# Ocean model configuration
+#=======================================================================
+
+OCVER=h2e2
+ASVER=cy2r3
+
+#=======================================================================
+# Configuration for sensitivity suite
+#=======================================================================
+
+SENSFCRES=255
+SENSFCLEV=60
+SENSADJRES=63
+SENSADJLEV=60
+SENSADJGTYPE=_2
+SENSFCGTYPE=l_2
+SENSADJSTEP=48
+SENSADJTSTEP=600.0
+SENSRUNFC=yes
+INISPQ=no
+
+#new for 25r1
+SENSADJADVEC=euler
+SENSFORCE=false
+SENSDIAB=true
+SENSITER=6
+
+#=======================================================================
+# The disk configuration
+# Look at e-suite configuration below also
+#=======================================================================
+
+if [[ $ARCH = ibm_power* ]] ; then
+ if [[ "%SUITE%" = mc_no ]] ; then
+ TROOT=$STHOST/ms_crit/teps
+ WROOT=$STHOST/ms_crit/teps
+ OROOT=$STHOST/emos_data
+ FDB_ROOT=$STHOST/ms_crit/fdb
+ FDB_IROOT=$STHOST/ms_crit/fdb
+ WAVEEPS_ROOT=$FDB_ROOT
+ WAVEEPS_IROOT=$FDB_IROOT
+ elif [[ "%SUITE%" = e*35r3* || "%SUITE%" = "e_sync" || "%SUITE%" = "emc_no*" ]] ; then
+ TROOT=$STHOST/emos_esuite/emos_data
+ WROOT=$STHOST/emos_esuite/emos_data
+ OROOT=$STHOST/emos_data
+ WBASE=/
+ FDB_ROOT=$STHOST/emos_esuite/ma_fdb
+ FDB_ROOT_BKUP=$STHOST_BKUP/emos_esuite/ma_fdb
+ FDB_IROOT=$STHOST/emos_esuite/ma_fdb
+ WAVEEPS_ROOT=$FDB_ROOT
+ WAVEEPS_IROOT=$FDB_IROOT
+ else
+ TROOT=$STHOST/emos_data
+ WROOT=$STHOST/emos_data
+ OROOT=$STHOST/emos_data
+ FDB_ROOT=$STHOST/ma_fdb
+ FDB_ROOT_BKUP=$STHOST_BKUP/ma_fdb
+ FDB_IROOT=$STHOST/ma_fdb
+ WAVEEPS_ROOT=$STHOST$FDB_ROOT
+ WAVEEPS_IROOT=$STHOST$FDB_IROOT
+ fi
+ if [[ "%FSFAMILY%" = mars ]] ; then
+ WROOT=/od_archive/data
+ fi
+elif [[ $ARCH = linux ]] ; then
+ TROOT=/var/tmp/tmpdir/emos
+ WROOT=/var/tmp/tmpdir/emos
+ OROOT=/var/tmp/tmpdir/emos
+ FDB_ROOT=""
+ FDB_IROOT=""
+else
+ TROOT=/var/tmp/emos
+ WROOT=/var/tmp/emos
+ OROOT=/var/tmp/emos
+ FDB_ROOT=""
+ FDB_IROOT=""
+fi
+
+WBASE=${WROOT}/${EXPVER}
+
+XROOT=/home/ma/emos
+XLIB=$XROOT/lib/${IFS_CYCLE}
+XDATA=$XROOT/data
+XBINS=$XROOT/bin
+XMOD=/cc/rd/module/frt
+XSRC=$XROOT/src
+ODATA=/home/ma/emos/data
+SCRATCH=/ws/scratch/ma/emos
+
+FSROOT=/$USER
+FSOROOT=/emos
+FSFAMILY=""
+FSXDATA=/emos/data
+FSXBINS=/emos/$ARCH/bin
+
+#=======================================================================
+#
+# The following is the configuration filled in by the SMS
+#
+#=======================================================================
+
+#EXPVER=%VERSION% # done further up...
+
+if [[ "%USE_YMD:false%" = true ]] ; then
+ BASETIME=%YMD%%EMOS_BASE%
+else
+ BASETIME=%YYYY%%MM%%DD%%EMOS_BASE%
+fi
+
+FSFAMILY=%FSFAMILY%
+
+ECF_PASS=%ECF_PASS%
+ECF_NODE=%ECF_NODE%
+ECF_NAME=%ECF_NAME%
+ECF_TRYNO=%ECF_TRYNO%
+
+ECF_HOSTFILE=$HOME/.smshostfile
+ECF_PORT=%ECF_PORT%
+ECF_JOBOUT=%ECF_JOBOUT%
+
+
+SUITE=%SUITE%
+FAMILY=%FAMILY:NOT_DEF%
+TASK=%TASK%
+
+DEBUG=0
+DISPLAY=0
+
+# INFORM_EMOS_AUTORESOL=1
+
+#
+# For e-suites only
+#
+if [[ $EXPVER -eq 2 ]] ; then
+ BASEVER=0002
+fi
+
+#Multianalysis
+INIMA="%INIMA:ecmwf%"
+INIMACONS=%INIMACONS:0%
+INIORIG=mars
+MANNCEP=0
+MANMFR=0
+MANDWD=0
+MANUKM=0
+
+INIORIGIN=OFF
+MAORIGINS="CONS"
+MAMISSING="%MAMISSING:%"
+
+if [[ %STREAM% = "MAED" || %STREAM% = MAWV ]] ; then
+ WAMRESOL=global100
+ WAMNFRE=30
+ WAMNANG=24
+ INIOZONE=false
+ LOZONE=false
+ LOZONECH=false
+ RESOL=399
+ LEVELS=62
+
+ for xxx in $INIMA ; do
+ if [[ "$xxx" = ncep ]] ; then
+ MANNCEP=1
+ MAORIGINS="$MAORIGINS KWBC"
+ elif [[ "$xxx" = mfr ]] ; then
+ MANMFR=1
+ MAORIGINS="$MAORIGINS LFPW"
+ elif [[ "$xxx" = ukm ]] ; then
+ MANUKM=1
+ MAORIGINS="$MAORIGINS EGRR"
+ elif [[ "$xxx" = dwd ]] ; then
+ MANDWD=1
+ MAORIGINS="$MAORIGINS EDZW"
+ fi
+ done
+
+
+ # Find WMO centre number. Do this more cleverly
+ if [[ $INIMACONS -eq 1 ]] ; then
+ INIORIGIN=CONS
+ elif [[ $INIMA = mfr ]] ; then
+ INIORIGIN=LFPW
+ elif [[ $INIMA = ncep ]] ; then
+ INIORIGIN=KWBC
+ elif [[ $INIMA = ukm ]] ; then
+ INIORIGIN=EGRR
+ elif [[ $INIMA = dwd ]] ; then
+ INIORIGIN=EDZW
+ fi
+
+fi
+
+#=================================================
+# For mars compute. This will use model number found.
+# If not set, model number will be 255.
+export MARS_COMPUTE_FLAG=0
+
+# User for e-suite plots
+EPLOT_USER=mos
+
+set +a
+
+if [[ %DELTA_DAY% -ne 0 ]] ; then
+ delta=`expr %DELTA_DAY% \* 24`
+ BASETIME=`newdate $BASETIME $delta`
+fi
+
+if [[ $FSFAMILY = "refc" ]] ; then
+ HC_REFDATE=`echo $BASETIME | cut -c 1-8`
+ EPSTYPE=fc
+
+ export HC_REFDATE EPSTYPE
+
+ if [[ %YEAR:0% -ne 0 ]] ; then
+ YEAR=%YEAR:0%
+ YYYY=`echo $BASETIME | cut -c 1-4`
+ MM=`echo $BASETIME | cut -c 5-6`
+ DDHH=`echo $BASETIME | cut -c 7-10`
+ if [[ $MM$DDHH = 0229* ]] ; then
+ BASETIME=`newdate $(( $YEAR$MM$DDHH - 100 )) 24 `
+ else
+ BASETIME=$YEAR$MM$DDHH
+ fi
+ fi
+fi
+
+DELTA_YEAR=%DELTA_YEAR:0%
+YYYY=`echo $BASETIME | cut -c 1-4`
+YYYY=$(( $DELTA_YEAR + $YYYY ))
+if [[ $DELTA_YEAR -ne 0 ]] ; then
+ YYYY=`echo $BASETIME | cut -c 1-4`
+ DELTA_YEAR=%DELTA_YEAR:0%
+ MMDDHH=`echo $BASETIME | cut -c 5-10`
+ YYYY=$(( $DELTA_YEAR + $YYYY ))
+ BASETIME=$YYYY$MMDDHH
+ YMD=$(substring $BASETIME 1 8)
+fi
+
+DELTA_HOUR=%DELTA_HOUR:0%
+if [[ $DELTA_HOUR -ne 0 ]] ; then
+ BASETIME=`newdate $BASETIME $DELTA_HOUR`
+fi
+
+# remove when hpcf gone
+if [[ $HOST = hpc* ]] ; then
+ EMOSLIB="-qextname $EMOSLIB"
+fi
+
+if [[ $ARCH = linux ]] ; then
+ export LINK_C="pgf90 -tp k8-32 -g"
+ export LINK_F="pgf90 -tp k8-32 -g"
+fi
+
+if [[ "%OD_PROJ:od%" = no ]] ; then
+ ### TEPS project
+ EPSHEM=1
+ EPSGAMMA=0.016
+ EPSBASIS=10
+ EPSMEMBERS=21
+ EPSNENS=20
+ GRIBCLASS=113 # from http://www.ecmwf.int/publications/manuals/libraries/gribex/gribClass.html
+fi
+
+#=====================================================================
+# ocean model configuration
+#======================================================================
+export RUNVARFC=%RUNVARFC:0%
+export EPSLEG=%EPSLEG:1%
+if [[ $RUNHINDCAST = 1 ]] ; then
+ # export HC_REFDATE=%YMD%
+ export HC_REFDATE=$((YYYY -(DELTA_YEAR)))`echo $BASETIME | cut -c 5-8`
+
+INIMODISALB=false # if intial data was run with 32r1 or later
+
+#==========================================================
+# Variables configuring inidata
+#==========================================================
+INIPATH="/net/fujitsu/ifs/initial/t95r/ic_19r1_%YMD%"
+INISTREAM=DA
+INITYPE=an
+INISTEP=0
+INISPQ=no
+LFG=.true.
+INIOFFSET=0
+INISCHEME=lslag
+SAVINI=""
+SVRF=no
+IFRF=no
+FORCE_FP=no
+
+INICLASS=`oper_model -b $BASETIME -c`
+INIRESOL=`oper_model -b $BASETIME -r`
+INILEVELS=`oper_model -b $BASETIME -l`
+INIGTYPE=`oper_model -b $BASETIME -t`
+INIEXPVER=`oper_model -b $BASETIME -e`
+INITILES=`oper_model -b $BASETIME -T`
+INICLOUDAN=`oper_model -b $BASETIME -C`
+
+if [[ %RUNHINDCAST:0% = 0 ]] ; then
+ INILEVELS=91
+ INIRESOL=799
+
+if [[ $BASETIME -le %ERA40END:2002073100% ]] ; then
+ INICLASS=e4
+ INILEVELS=60
+ INIEXPVER=0001
+ INITILES=true
+ INICLOUDAN=true
+ INIMODISALB=false
+ EPSGAMMA=0.018
+fi
+
+else # HINDCAST mode
+ INICLASS=ei
+ INILEVELS=60
+
+ if [[ $BASETIME -lt 2008010100 ]] ; then
+ INIEXPVER=0001
+ else
+ INIEXPVER=1112 # temporary while Manuel is changing 1112 to 0001
+ fi
+ EPSGAMMA=0.016 # to be updated according to Martin Leutbecher
+ INIRESOL=255
+ INIMODISALB=true
+ INIHTESSEL=false
+ INITILES=true
+fi
+
+fi
+
+export MARS_CMD='mars'
+
+if [[ %RUNHINDCAST:0% = 1 ]] ; then
+ INIHTESSEL=`oper_model -b $BASETIME -I ${CLASSORIG:="er_ops"} -H`
+fi
+
+### check if MOFC-VarEps is to run
+ sim=`newdate -d -D $BASETIME`
+ real=`date +'%%Y%%m%%d'`
+ real=`newdate -d -D $real`
+ dow=`date +'%%u'`
+ res=$((($sim - $real + $dow) %% 7))
+
+ if [[ $((res)) -lt 0 ]] ; then res=$((res+7)); fi
+
+ RUN_VAREPS=0
+ if [[ $res = 4 ]] ; then # Thursday MOFC
+ RUN_VAREPS=1
+ fi
+ export EPSNLEGS=$((2+$RUN_VAREPS)) # do not refer to sms variables while this changes
+ # 35r2
+ export EPSCOUPL_A=no # 35r2
+ export EPSCOUPLE_A=0 # 35r2
+ CC=`substring $BASETIME 9 10` # later EMOS_BASE
+ export EPSCOUPLE_B=$((CC == 00)) # 35r2
+ export EPSCOUPLE_C=$RUN_VAREPS # 35r2
+
+
+export RUN_VAREPS
+###########
+export OCNINDAT=$(substring $BASETIME 1 8) # 19900101
+
+if [[ $EPSLEG != 1 ]] || [[ $RUNVARFC = 1 ]] ; then
+set -a
+
+
+ENAMELIST=general
+FULL_POS=yes
+LPPL=1
+LPSU=1
+LPPV=0
+LPTH=0
+LPGZ=0
+PPSTEPS="0"
+ERF=408
+FRQRF=-1
+DATE_BRANCH=2005112409
+USEDATE_BRANCH=no
+VIEW=""
+VIEW_HOPE="hope_h2e20"
+OCEPS=no
+OCUSESV=no
+EPSLROT=no
+OCPATM=yes
+OCFCRESOL=255
+OCFCLEVELS=62
+OCFCGTYPE=l_2
+OCFCTSTEP=%TSTEP:1800%.0
+FCCHUNKTOT=1
+NEWSTREAMLIB=none
+SAVLIB=false
+OCEAN_BRANCH="neh_h2e20_enfo"
+OCEAN_CYCLE="h2e20"
+OCIAUFR=2
+if [[ $RUNHINDCAST = 1 ]] ; then
+
+GRIB_API_VERSION=1.7.0
+GRIB_API_INCLUDE="-I/usr/local/lib/metaps/lib/grib_api/jasper/include -I/usr/local/lib/metaps/lib/grib_api/$GRIB_API_VERSION/include"
+GRIB_API_LIB="-L/usr/local/lib/metaps/lib/grib_api/jasper/lib -ljasper -L/usr/local/lib/metaps/lib/grib_api/$GRIB_API_VERSION/lib -lgrib_api_f90 -lgrib_api"
+export GRIB_API=/usr/local/lib/metaps/lib/grib_api/$GRIB_API_VERSION/bin # change to fixed version
+export PATH=$GRIB_API:$PATH
+
+ if [[ $HC_REFDATE -lt 20080605 ]] ; then
+ OCINI="seas_0001_01_NN_${OCNINDAT}_od_02"
+ else
+ OCINI="ocea_0001_01_NN_$(substring $BASETIME 1 8)_od_03"
+ fi
+else
+ OCINI="ocea_0001_01_NN_$(substring $BASETIME 1 8)_od_03"
+fi
+OCNEWREST=false
+OCNMINI="00"
+CLASSORIG=e4_ops
+
+OCRUNCTRLAN=no
+OCRUNCTRLAC=no
+OCRUNCTRLFC=no
+OCRUNASSIMAN=no
+OCRUNASSIMAC=yes
+OCRUNASSIMFC=yes
+MEMBERSTATE=no
+%include <config.oc.h>
+
+ OCINPUT=mars
+ OCSUITE=vareps
+ if [[ -n $OCINI ]] ;then
+ OCINPUT=$(substring $OCINI 1 4)
+ fi
+
+ if [[ $OCINPUT != 'ecfs' ]] ; then
+ OCSTREAM_INI=$OCINPUT
+ if [[ $OCINPUT = 'mars' ]];then
+ OCSTREAM_INI='ocea' # 'seas'
+ fi
+ if [[ $OCINPUT = 'seas' ]];then
+ OCINPUT='mars'
+ fi
+ if [[ $OCINPUT = 'mofc' ]];then
+ OCINPUT='mars'
+ fi
+ OCEXPVER_INI=0001 # $(substring $OCINI 6 9 )
+ OCMETHOD_INI=$(substring $OCINI 11 12 )
+ OCNUMBER_INI=$(substring $OCINI 14 15 )
+ OCDATE_INI=$(substring $OCINI 17 24 )
+ OCCLASS_INI=$(substring $OCINI 26 27 )
+ OCSYST_INI=$(substring $OCINI 29 30 )
+ fi
+
+# For EPS runs only. Change of EPSNORM
+#
+ LASTERA40=%ERA40END:2000070100%
+
+ if [[ $OCEPS = "yes" ]] ; then
+ if [[ $BASETIME -le 2001031400 ]] || [[ $BASETIME -le $LASTERA40 ]] ;
+ then
+ EPSNORM=2.0
+ EPSNORMT=2.0
+ fi
+ EPSTROP=%EPSTROP:$EPSTROP%
+ EPSSVDIAB=%EPSSVDIAB:$EPSSVDIAB%
+ EPSSVNUM=%EPSSVNUM:$EPSSVNUM%
+ fi
+
+#=======================================================================
+# special mofc variables
+#=======================================================================
+
+# pop/web/mofc
+
+MOFC_PROCESS=$WROOT/data/%SUITE%_process
+MOFC_PROCESS=`echo $MOFC_PROCESS | sed -e 's/var\/tmp\/tmpdir\/emos\/data/emos_data/'`
+Y=`echo $BASETIME | cut -c 1-4`
+STREAM=EF
+CLIMYEAR1=$((Y + - %NH_YEARS:18%))
+CLIMYEAR2=$((Y - 1))
+OCUTILS=$XBINS/$STREAM/$EXPVER
+
+export NH_ENSEMBLES=%NH_ENSEMBLES:4%
+export MOFC_PROCESS
+
+if [[ %RUNHINDCAST:0% = 1 ]] ; then
+ MOFCCLIM_VERIF=$WROOT/data/%SUITE%_clim
+ [[ -d $MOFCCLIM_VERIF ]] || mkdir -p $MOFCCLIM_VERIF
+ MOFC_VERIFY=/gpfs1/emos_verify/data/%SUITE%_verify
+ export PATH=$PATH:$HOME/bin/EF/verify
+ [[ -d $MOFC_VERIFY ]] || mkdir -p $MOFC_VERIFY
+
+ INIHTESSEL=`oper_model -b $BASETIME -I ${CLASSORIG:="er_ops"} -H`
+fi
+
+fi
+
+set -a
+
+if [[ %EPSTYPE:cf% = sv ]] ; then
+ INIMODISALB=false
+fi
+
+if [[ "%STREAM%" = EF ]] ; then
+ INIPERIOD_4D=%INIPERIOD_4D:12%
+else
+ INIPERIOD_4D=12
+fi
+
+if [[ "%FSFAMILY:0%" != refc ]] && [[ %RUNHINDCAST:0% != 1 ]] ; then
+ LVARBC=true
+else
+ LVARBC=false
+ INIMODISALB=false # if intial data was run with 32r1 or later
+
+ date4v12h=2000091200
+ # CHANGE date_dcda=2004062900
+ date_dcda=2004062912
+ if [ $BASETIME -ge $date4v12h ] ; then
+ INIPERIOD_4D=12
+ fi
+ if [ $BASETIME -ge $date_dcda ] ; then
+ INIPERIOD_4D=6
+ fi
+fi
+
+inidate=`echo $BASETIME | cut -c 1-8`
+if [ ${inidate} -ge 19971125 ] && [ $INICLASS = od ] && [ $INIPERIOD_4D = 6 ] ; then
+ INIOFFSET_4D=3
+elif [ $INICLASS = ei ] ; then
+ INIOFFSET_4D=9
+elif [ $INICLASS = e4 ] ; then
+ INIOFFSET_4D=3
+elif [ $INIPERIOD_4D = 12 ] ; then
+ if [[ %RUNHINDCAST:0% = 1 ]] || [[ %STREAM:UNDEF% = EF ]] ; then
+ INIOFFSET_4D=9
+ else
+ INIOFFSET_4D=3
+ fi
+elif [ $INIPERIOD_4D = 6 ] ; then
+ INIOFFSET_4D=3
+else
+ INIOFFSET_4D=0
+fi
+
+### SST ###
+CLMSST=no
+PERSST=%PERSST:false%
+FORCE_SST=no
+SSTLEN=%SSTLEN:240%
+SSTINT=%SSTINT:1%
+LOSTIA=%LOSTIA:true% # 33r2
+
+NUMBER=%FCTOTAL:NOT_SET%
+VAR=%VAR:NOT_SET%
+CNUMBER=5
+
+if [[ "%SUITE%" = @(mc*|emc*|mofc*|emofc*|ma|tparc*|dts*) || $SUITE_TYPE = "eps" ]] ; then
+ LWEAK4DVAR=false
+ LEMISKF=false
+ LOZONE=false
+ INIOZONE=false
+ LOZONECH=false
+ LVARBC=false
+else
+ LWEAK4DVAR=true
+ LEMISKF=true
+fi
+
+
+set +a
+
+
diff --git a/ANode/test/data/SMSHOME2/good/includes/config.oc.h b/ANode/test/data/SMSHOME2/good/includes/config.oc.h
new file mode 100644
index 0000000..c9c12ca
--- /dev/null
+++ b/ANode/test/data/SMSHOME2/good/includes/config.oc.h
@@ -0,0 +1,197 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+# EXPVER=et34
+#==========================================================
+# Variables configuring emptyNamelist
+#==========================================================
+ENAMELIST=general
+#
+#==========================================================
+# Variables configuring wsconfig
+#==========================================================
+
+# WSHOST=metis
+# SCRATCH="/scratch/rd/rdx"
+#
+#==========================================================
+# Variables configuring ppgeneral
+#==========================================================
+
+IFSMODE=fc
+#PERIOD=6
+#PERIOD_4D=12
+
+FULL_POS=yes
+LPPL=1
+LPSU=1
+LPML=0
+LPPV=0
+LPTH=0
+LPGZ=0
+#PPFRQ=24
+PPSTEPS="0"
+#BRF=0
+ERF=408
+FRQRF=-1
+#
+#==========================================================
+# Variables configuring Ozone
+#==========================================================
+LOZONE=false
+LOZONECH=false
+#
+#==========================================================
+# Variables configuring clearcase
+#==========================================================
+#PROJECTS="none"
+DATE_BRANCH=2005112409
+USEDATE_BRANCH=no
+VIEW=""
+VIEW_HOPE="hope_h2e20"
+#
+#==========================================================
+# Variables configuring eps_svect
+#==========================================================
+OCEPS=no
+OCUSESV=no
+EPSLROT=no
+EPSNLEGS=%EPSNLEGS:3%
+EPSFCLEV_A=40
+EPSTSTEP_A=1800
+EPSFCLEV_B=40
+EPSTSTEP_B=%TSTEP:2700% # 2700
+EPSFCLEV_C=40
+EPSTSTEP_C=%TSTEP:2700% # 2700
+
+#
+#==========================================================
+# Variables configuring Dr_Hook
+#==========================================================
+#DR_HOOK=true
+#DR_HOOK_OPT="none"
+#DR_HOOK_PROFILE_LIMIT=-10
+#DR_HOOK_HASHBITS=15
+#DR_HOOK_CATCH_SIGNALS=0
+#DR_HOOK_IGNORE_SIGNALS=0
+#
+#==========================================================
+# Variables configuring wavgeneral
+#==========================================================
+#WAVE=yes
+#INIWAVE=yes
+#WAM2WAY=yes
+#WAMALT=no
+#WAMSAR=no
+#WAMSARASS=false
+#WGRIBIN=yes
+#WAMNSTPW=1
+#WAMRESOL=global100
+#WAMCOLDLENGTH=240
+WAMNFRE=%EPSWAMNFRE:25%
+WAMNANG=%EPSWAMNANG:12%
+#WAMFCPARAM="229/230/231/232/220/221/244/233/245"
+#
+#==========================================================
+# Variables configuring compile
+#==========================================================
+OCPATM=yes
+#LD="mpxlf90_r"
+#LDCC="xlc_r"
+#USE=standard
+#USECC=vac_6000
+#PARALLEL=4
+#NATIVE=true
+#F90_DEBUG=0
+#RUN_PARALLEL=true
+#EC_FILL_NANS=false
+#
+#==========================================================
+# Variables configuring system
+#==========================================================
+# ABO all comments
+#FSROOT="/RDX/prepIFS"
+#FSOROOT="/emos"
+#ABO FSXDATA="/ocx/data"
+#ABO FSXBINS="/ocx/$ARCH/bin"
+#ACCOUNT=ecrmoc
+#USER=ocx
+#GROUP=rd
+#FDB_GROUP=ecmwf
+#BASEVER=0001
+#CLASS=rd
+#GRIBCLASS=2
+#NOW=2005112409
+#MEMBERSTATE=no
+#
+#==========================================================
+# Variables configuring submit
+#==========================================================
+#SMS_NAME=ocx-prod
+#
+#==========================================================
+# Variables configuring general
+#==========================================================
+OCFCRESOL=255
+OCFCLEVELS=62
+OCFCGTYPE=l_2
+OCFCTSTEP=%TSTEP:1800%.0
+FCCHUNKTOT=1
+VERSION="fc"
+LESUITE=false
+#
+#==========================================================
+# Variables configuring libraries
+#==========================================================
+# IFS_CYCLE="31r1"
+# Q2USE=true
+# EMOS_CYCLE="000281"
+# Q2CREATE_NEWSTREAM=false
+# NEWSTREAM=none
+NEWSTREAMLIB=none
+# LIBRESOL=".R64.D64.I32"
+SAVLIB=false
+#GETLIB=false
+# MAKE_LIBS=yes
+# Q2CHANGELIST=0
+OCEAN_BRANCH="neh_h2e20_enfo"
+OCEAN_CYCLE="h2e20"
+#
+#==========================================================
+# Variables configuring inidata
+#==========================================================
+#OCNINDAT=$(substring $BASETIME 1 8) # 19900101
+#OCIAUFR=2
+#if [[ $RUNHINDCAST = 1 ]] ; then
+#OCINI="seas_0001_01_NN_${OCNINDAT}_od_02"
+#else
+#OCINI="ocea_0001_01_NN_$(substring $BASETIME 1 8)_od_03"
+## "seas_0001_01_NN_${OCNINDAT}_od_02"
+#fi
+#OCNEWREST=false
+#OCNMINI="00"
+#INIORIG=mars
+#CLASSORIG=e4_ops
+#INISCHEME=lslag
+SVRF=no
+IFRF=no
+#
+#==========================================================
+# Variables configuring ocgeneral
+#==========================================================
+OCRUNCTRLAN=no
+OCRUNCTRLAC=no
+OCRUNCTRLFC=no
+OCRUNASSIMAN=no
+OCRUNASSIMAC=yes
+OCRUNASSIMFC=yes
+#
+MEMBERSTATE=no
+#if [ $RUNVARFC -eq 1 ] ; then
+# OCSUITE=vareps
+#fi
+
diff --git a/ANode/test/data/SMSHOME2/good/includes/endt.h b/ANode/test/data/SMSHOME2/good/includes/endt.h
new file mode 100644
index 0000000..bc9912f
--- /dev/null
+++ b/ANode/test/data/SMSHOME2/good/includes/endt.h
@@ -0,0 +1,13 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+#==========================================================================
+# End task (complete -> SMS)
+# Clean up and exit
+#==========================================================================
+
+smscomplete ; trap 0 ; exit
diff --git a/ANode/test/data/SMSHOME2/good/includes/head.h b/ANode/test/data/SMSHOME2/good/includes/head.h
new file mode 100644
index 0000000..e12e0fe
--- /dev/null
+++ b/ANode/test/data/SMSHOME2/good/includes/head.h
@@ -0,0 +1,43 @@
+#!/bin/ksh
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+set -e # stop the shell on first error
+set -u # fail when using an undefined variable
+set -x # echo script lines as they are executed
+
+# Defines the three variables that are needed for any
+# communication with ECF_
+
+export ECF_PORT=%ECF_PORT% # ECF_ Remote Procedure Call number
+export ECF_NODE=%ECF_NODE% # The name sms that issued this task
+export ECF_NAME=%ECF_NAME% # The name of this current task
+export ECF_PASS=%ECF_PASS% # A unique password
+export ECF_TRYNO=%ECF_TRYNO% # Current try number of the task
+
+# Tell ECF_ we have stated
+# The ECF_ variable ECF_RID will be set to parameter of smsinit
+# Here we give the current PID.
+
+#smsinit $$
+
+# Defined a error hanlder
+
+ERROR() {
+ set +e # Clear -e flag, so we don't fail
+ #smsabort # Notify ECF_ that something went wrong
+ trap 0 # Remove the trap
+ exit 0 # End the script
+}
+
+# Trap any calls to exit and errors caught by the -e flag
+
+trap ERROR 0
+
+# Trap any signal that may cause the script to fail
+
+trap '{ echo "Killed by a signal"; ERROR ; }' 1 2 3 4 5 6 7 8 10 12 13 15
diff --git a/ANode/test/data/SMSHOME2/good/includes/law.h b/ANode/test/data/SMSHOME2/good/includes/law.h
new file mode 100644
index 0000000..a776ede
--- /dev/null
+++ b/ANode/test/data/SMSHOME2/good/includes/law.h
@@ -0,0 +1,43 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+### start of law.h, normally included from config.h ####################
+
+# Override for local area wave model
+if [[ "%FSFAMILY%" = "euroshelf" ]] ; then
+ set -a
+ PPFRQ=6
+ WAMRESOL=medite10
+ WAMANLEN=12
+ WAMFCLEN=120
+ WAMSAR=yes
+ WAMIDELRES=6
+ INIWDEXPVER=%INIWDEXPVER:0001% # expver for wind forcing
+ INIWDCLASS=%INIWDCLASS:od%
+ INIWDSTREAM=DA
+ WGRIBIN=yes
+ gflag=T
+ nsysnb=-1
+ nmetnb=-1
+
+ ALTIMETER=ers2
+ SAR=ers2
+ ERS=`echo $SAR | cut -c4`
+
+ model=medite
+ FSALT=$FSBASE/${ALTIMETER}/alt/$model
+ FSALT_B=$FSBASE/${ALTIMETER}_b/alt/$model
+ FSALT_S=$FSBASE/${ALTIMETER}_s/alt/$model
+ FSSAR=$FSBASE/${SAR}/sar/$model
+ FSSAR_B=$FSBASE/${SAR}_b/sar/$model
+ FSSAR_S=$FSBASE/${SAR}_s/sar/$model
+
+ WAVE_ROOT=$FDB_ROOT
+ WAVE_IROOT=$FDB_IROOT
+
+fi
+# end of law.h #################################
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/qsub.h b/ANode/test/data/SMSHOME2/good/includes/qsub.h
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/qsub.h
rename to ANode/test/data/SMSHOME2/good/includes/qsub.h
diff --git a/ANode/test/data/SMSHOME2/good/includes/rcp.h b/ANode/test/data/SMSHOME2/good/includes/rcp.h
new file mode 100644
index 0000000..3d72f55
--- /dev/null
+++ b/ANode/test/data/SMSHOME2/good/includes/rcp.h
@@ -0,0 +1,41 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+# rcp.h
+
+SMSRCP() {
+ set -x
+ set +e
+ if [[ "${ARCH:=UNDEF}" = hppa || "${ARCH:=UNDEF}" = hpia64 ]] ; then
+ if [[ $PBS_JOBID = NOT_SET ]] ; then
+ rcp %LOGDIR%%SMSNAME%.%SMSTRYNO% \
+ emos@%SMSNODE%:%SMSOUT%%SMSNAME%.%SMSTRYNO%
+ else
+ rm -f %SMSJOBOUT% || : # remove link
+
+ # hardcoded to hanfs2 then mordred to release load on ablamor
+ rcp /var/spool/PBS/spool/${PBS_JOBID}.OU \
+ emos at hanfs2:/hanfs%SMSHOME%%SMSNAME%.%SMSTRYNO% || \
+ rcp /var/spool/PBS/spool/${PBS_JOBID}.OU \
+ emos at mordred:%SMSHOME%%SMSNAME%.%SMSTRYNO% || \
+ rcp /var/spool/PBS/spool/${PBS_JOBID}.OU \
+ emos@%SMSNODE%:%SMSHOME%%SMSNAME%.%SMSTRYNO%
+
+ link_name=`~emos/bin/subs_path.pl -f %SMSOUT% -t $TOPATH -n %SMSJOBOUT%`
+ rm -f $link_name || :
+
+ fi
+ fi
+
+ if [[ ${ARCH:=UNDEF} = ibm_power* ]] ; then
+ rcp %LOGDIR%%SMSNAME%.%SMSTRYNO% %SMSNODE%:%SMSHOME%%SMSNAME%.%SMSTRYNO%
+ fi
+
+}
+typeset -fx SMSRCP
+
+# end of rcp.h
diff --git a/ANode/test/data/SMSHOME2/good/includes/set_traps.h b/ANode/test/data/SMSHOME2/good/includes/set_traps.h
new file mode 100644
index 0000000..5dd0bca
--- /dev/null
+++ b/ANode/test/data/SMSHOME2/good/includes/set_traps.h
@@ -0,0 +1,6 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
diff --git a/ANode/test/data/SMSHOME2/good/includes/setup.h b/ANode/test/data/SMSHOME2/good/includes/setup.h
new file mode 100644
index 0000000..abc1ec6
--- /dev/null
+++ b/ANode/test/data/SMSHOME2/good/includes/setup.h
@@ -0,0 +1,535 @@
+banner setup.h
+#=======================================================================
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+USER=${USER:=$LOGNAME}
+
+set -a
+
+#=======================================================================
+# Get the prompt PS4 to be ok with -u option
+#=======================================================================
+
+typeset -Z2 _h _m _s
+if [[ $ARCH != linux ]] ; then
+SECONDS="$(date '+3600*%%H+60*%%M+%%S')"
+_x=""
+_time='${_x[(_h=(SECONDS/3600)%%24)==(_m=SECONDS/60%%60)==(_s=SECONDS%%60)]}$_h:$_m:$_s'
+PS4="$_time + "
+elif [[ $ARCH = linux ]] ; then
+ set +e
+ LKSH93=`isksh93 && echo "true" || echo "false"`
+ set -e
+ if [[ $ARCH = linux ]] && [[ "$LKSH93" = "true" ]] ; then
+# ksh93 syntax
+ _time='$((_h=(SECONDS/3600)%%24)):$((_m=(SECONDS/60)%%60)):$((_s=SECONDS%%60))'
+ PS4="$_time + "
+ fi
+fi
+
+unset _hh _mm || true
+#=======================================================================
+#
+# Distinguish between OD and RD
+#
+#=======================================================================
+
+STREAM=%STREAM:DA%
+if [[ $STREAM = DA ]] ; then
+ stream=""
+else
+ stream="/${STREAM}"
+fi
+
+ # OD_MODE is set to false (default) for rd, e4 projects
+ # true for od and all od projects
+ OD_MODE=true
+ CLASS=%OD_PROJ:od%
+ OD_PROJ=%OD_PROJ:od%
+
+ #---------------------------------------------------------------------
+ # EMOS specific setup
+ #---------------------------------------------------------------------
+
+ EMOS_YEAR=`substring $BASETIME 1 4`
+ EMOS_MONTH=`substring $BASETIME 5 6`
+ EMOS_DAY=`substring $BASETIME 7 8`
+ EMOS_BASE=`substring $BASETIME 9 10`
+ EMOS_VERSION=$EXPVER
+ EMOS_TIME_STEP_H=%EMOS_TIME_STEP_H%
+ EMOS_STREAM=$STREAM
+
+ if [[ $EXPVER -ne 1 && $EXPVER -ne 2 ]] ; then
+ alias -x gksplot="gksplot -u $EPLOT_USER"
+ alias -x magplot="magplot -u $EPLOT_USER"
+ fi
+
+#=======================================================================
+#
+# Derive the disk variables
+#
+#=======================================================================
+
+export FWROOT=$FSROOT/${EXPVER} # this variable for similar path WITHOUT stream
+export FWBASE=$FSROOT/${EXPVER} # this variable for similar path WITHOUT stream
+
+if [[ %OD_PROJ:od% != od ]] ; then
+ BASE=$TROOT/$CLASS/$EXPVER
+ WORK=$WROOT/$CLASS/$EXPVER
+ LIBS=$BASE/lib
+ BINS=$BASE/bin
+ DATA=$BASE/data
+
+elif [[ $STREAM = MAED ]] ; then
+ TROOT=${TROOT}/${STREAM}
+ WROOT=${WROOT}/${STREAM}
+ FSROOT=${FSROOT}/${STREAM}
+ BASE=$TROOT/$EXPVER
+ WORK=$WROOT/$EXPVER
+ LIBS=$BASE/lib
+ BINS=$BASE/bin
+ DATA=$BASE/data
+
+elif [[ $STREAM = DCDA ]] ; then
+ # TBD TBD TBD ODIR configuration for operational mode
+
+ BASE=$TROOT/$EXPVER
+ LIBS=$BASE/lib
+ BINS=$BASE/bin
+ DATA=$BASE/data
+ TROOT=${TROOT}/${STREAM}
+ BASE=$TROOT/$EXPVER
+ WROOT=${WROOT}/${STREAM}
+ WORK=$WROOT/$EXPVER
+ FSROOT=${FSROOT}/${STREAM}
+ FSODB=${FSODB}/${STREAM}
+
+else
+ BASE=$TROOT/$EXPVER
+ WORK=$WROOT/$EXPVER
+ LIBS=$BASE/lib
+ BINS=$BASE/bin
+ DATA=$BASE/data
+fi
+
+
+if [[ $OD_MODE = true ]] ; then
+ LOGS=%LOGDIR%/$SUITE/$FAMILY
+else
+ LOGS=$TROOT/log/$SUITE/$FAMILY
+fi
+
+if [ "$FSFAMILY" != "" ] ; then
+ PATH=${XBINS}/${ARCH}/${IFS_CYCLE}/${FSFAMILY}:${XBINS}/${ARCH}/${IFS_CYCLE}:${XBINS}/${ARCH}/${IFS_CYCLE}/an:/${BINS}/${FSFAMILY}:${HOME}/bin/${FSFAMILY}:${XBINS}/${IFS_CYCLE}:${XBINS}/an:$PATH:$emosbin:${HOME}/bin/${ARCH}
+ FSFAMILY=/$FSFAMILY
+fi
+
+SUBFSFAMILY=%SUBFSFAMILY:""%
+
+XDIR=$XROOT/bin
+ADIR=$BASE/${BASETIME}${FSFAMILY}$SUBFSFAMILY
+WDIR=$WORK/${BASETIME}${FSFAMILY}$SUBFSFAMILY
+ODIR=$OROOT/0001/${BASETIME}
+
+
+if [[ "$STREAM" = MAED ]] ; then
+ if [[ "$FSFAMILY" = "/fc" ]] ; then
+ if [[ $INIMACONS -eq 1 ]] ; then
+ ADIR="${ADIR}_cons"
+ WDIR="${WDIR}_cons"
+ elif [[ "$INIMA" != "" ]] ; then
+ ADIR="${ADIR}_$INIMA"
+ WDIR="${WDIR}_$INIMA"
+ fi
+ fi
+fi
+
+PATH=$HOME/bin/ppdi:$TMPDIR:$BINS:$BINS/$WAMRESOL:$XROOT/bin/$EMOS_CYCLE:$PATH
+
+if [[ "$FSFAMILY" = /mc ]] && [[ $RUNHINDCAST != 1 ]] ; then
+ EMOS_STREAM=EF
+ STREAM=EF
+fi
+
+#=======================================================================
+#
+# Suite specific fdb settings
+#
+#=======================================================================
+#=======================================================================
+#
+# Derive the FileServer variables
+#
+#=======================================================================
+
+if [[ %OD_PROJ:od% = od ]] ; then
+ FSBASE=${FSROOT}${FSFAMILY}/${EXPVER}
+else
+ FSBASE=${FSROOT}${FSFAMILY}/${CLASS}/${EXPVER}
+fi
+
+FDBASE=$FSBASE
+
+FSHOST=${FSBASE}/${ARCH}
+
+FSLIBS=${FSHOST}/lib
+FSBINS=${FSHOST}/bin
+FSDATA=${FSHOST}/data
+FSODIR=${FSROOT}/0001/$(substring $BASETIME 1 6)/$(substring $BASETIME 7 10)
+
+DHSWAVE=${FSROOT}/${EXPVER}/wave
+
+if [[ "$FSFAMILY" = /euroshelf ]] ; then
+ DHSWAVE=${FSROOT}/${EXPVER}/euroshelf
+fi
+
+if [[ $OD_MODE = true ]] ; then
+ FSDIR=${FSBASE}/${BASETIME}
+ FSLOG=${FSBASE}/log
+
+ DHSTIME=$(substring $BASETIME 1 6)/$(substring $BASETIME 7 10)
+
+ FSBDIR=$FSOROOT/$EXPVER/$DHSTIME
+else
+ FSDIR=$FSROOT/${EXPVER}/${BASETIME}
+ FSLOG=$FSROOT/${EXPVER}/log
+
+ DHSTIME=${BASETIME}
+fi
+FODBDIR=${FSODB}${FSFAMILY}/${EXPVER}${stream}/${BASETIME}
+
+PSDIR=/ws/scratch/ma/emos/ps
+
+#=======================================================================
+# Set variable to run metview macros on a different fs from normal users
+# Please see comments in web.h if you want to change it.
+#
+# On linux cluster we use the default one
+#=======================================================================
+
+
+
+#=======================================================================
+# Model variables that depend on configuration
+#=======================================================================
+
+VPP_MBX_SIZE=1000000
+MBX_SIZE=1000000
+MPP_TYPE=2
+if [[ $ARCH = @(ibm_power*) ]] ; then
+ MBX_SIZE=64000000
+fi
+
+[[ $RESOL = 213 || $RESOL = 319 ]] && NRESOL=160
+[[ $RESOL = 106 || $RESOL = 159 ]] && NRESOL=80
+[[ $RESOL = 511 ]] && NRESOL=256
+[[ $RESOL = 799 ]] && NRESOL=400
+[[ $RESOL = 255 ]] && NRESOL=160
+[[ $RESOL = 399 ]] && NRESOL=200
+
+
+if [[ $ARCH = @(ibm_power*) ]] ; then
+ CC=xlc_r
+ FRT=xlf90
+ FRT77=xlf
+ LD=mpxlf90_r
+ LDCC=xlc_r
+ BUILDWS=true
+ WSUSE=xlf_7112
+ PARALLEL=4
+ NATIVE=true
+ F90_DEBUG=0
+ RUN_PARALLEL=true
+fi
+#==========================================================
+# New for 33r1
+#==========================================================
+
+if [[ $ARCH = ibm_power4 ]] ; then
+ USE=xlf_11102
+elif [[ $ARCH = @(ibm_power6) ]] ; then
+ USE=standard
+fi
+
+if [[ $TASK != exp_setup ]] ; then
+ USE=${USE:-standard}
+
+ if [[ $USE != standard ]] && [[ $ARCH = ibm_power* ]] ; then
+ use $USE
+# addon1=`echo $PATH | cut -d: -f1`
+# addon2=`echo $PATH | cut -d: -f2`
+# REDUCED_PATH=$addon1:$addon2:$REDUCED_PATH
+ fi
+fi
+
+set +a
+
+#=======================================================================
+#
+# Functions to manipulate the variables
+#
+#=======================================================================
+
+NEWADIR() {
+ set -xe
+ if [ $# -lt 1 ] ; then echo $0: error; return 1 ; fi
+ echo $BASE/$(newdate $BASETIME $1)/$(basename $ADIR)
+}
+
+NEWWDIR() {
+ set -xe
+ if [ $# -lt 1 ] ; then echo $0: error; return 1 ; fi
+ # echo $WORK/$(newdate $BASETIME $1)/$(basename $WDIR) # 29r2 TBD
+ echo `echo $WDIR | sed -e "s/$BASETIME/$(newdate $BASETIME $1)/g"`
+}
+
+NEWFSBDIR() {
+ set -x
+ if [ $# -lt 1 ] ; then echo $0: error; return 1 ; fi;
+ XX=`newdate ${BASETIME} $1`;
+ # used to define the location for PS_BIAS file
+ # shall contain DCDA stream within the path _but_ this would mean
+ # modifying FSBDIR variable. However, too many script use already
+ # this variable.
+ echo $FSOROOT/$EXPVER/$(substring $XX 1 6)/$(substring $XX 7 10);
+# ${FSBASE}/$STREAM/$(substring $XX 1 6)/$(substring $XX 7 10)
+}
+
+NEWFDIR() {
+ set -xe
+ if [ $# -lt 1 ] ; then echo $0: error; return 1 ; fi;
+ XX=`newdate ${BASETIME} $1`;
+ echo $FSBASE/$(substring $XX 1 6)/$(substring $XX 7 10)
+}
+
+CHECK_DIR(){
+ if [[ $ARCH = ibm_power* ]] ; then
+ trap '{ echo "Error in function"; exit 1; }' 0 $SMS_SIGNAL_LIST
+ fi
+ set -xeu
+ if [[ ! "$ARCH" = "linux" ]] ; then
+ trap '{ echo "Error in function"; exit 1; }' 0 $SMS_SIGNAL_LIST
+ fi
+ if [[ $# -eq 0 ]]; then
+ return 1
+ fi
+
+ if [[ $ARCH = ibm_power* ]] then
+ (umask 022;pmkdir $1 || exit )
+ else
+ mkdir -p -m 755 $1 || exit
+ fi
+ if [[ ! "$ARCH" = "linux" ]] ; then
+ trap 0
+ fi
+
+ return 0
+}
+
+
+PUT() {
+ set -xe
+ Ecp -o $1 ec:$FSDIR/$1 || return 1
+}
+
+GET() {
+ set -xe
+ Ecp ec:$FSDIR/$1 $1 || return 1
+}
+
+if [[ $OD_MODE = true ]] ; then
+
+ GETSV() {
+ set -xe
+ file=$(basename $2)
+ Ecp ec:$1/$file $2 || return 1
+ }
+
+else
+ GETSV() {
+ set -xe
+ Ecp ec:$1/$2 $2 || return 1
+ }
+
+fi
+
+typeset -fx NEWADIR NEWWDIR NEWFDIR CHECK_DIR PUT GET GETSV NEWFSBDIR
+
+if [[ $ARCH != fujitsu ]] ; then
+ function libselect { echo WARNING - dummy command : libselect $1 ;}
+ typeset -fx libselect
+fi
+
+export OLDADIR=`NEWADIR -$PERIOD`
+export OLDWDIR=`NEWWDIR -$PERIOD`
+export YESTERDIR=`NEWWDIR -24`
+
+#==========================================================================
+# Copy postscript file into a scratch directory;
+#
+# PSFILE [filename [countem [rename]]]
+#
+# Default filename is "ps"
+#
+# countem (set but can contain anything) means that there is more than
+# one file from this task in which case the files are numbered.
+#
+# If only one file is produced it is copied as
+# ${_PSDIR}/${SUITE}${EMOS_BASE}${TASK}.ps
+# otherwise it is copied as
+# ${_PSDIR}/${SUITE}${EMOS_BASE}${TASK}.fileno.ps
+# where fileno is counted automatically
+#
+# If the third parameter is given the naming convention is not followed
+# except that the file numbering is still being done (stupid if there's
+# only one file, but what the hell...)
+#
+# Old file is not saved
+#==========================================================================
+
+PSFILE() {
+ set +exv
+ if [ $# -ge 1 ] ; then _psfile="$1" ; else _psfile="ps" ; fi
+ if [ ! -f $_psfile ] ; then return 1; fi
+ if [ $# -ge 2 ] ; then _fileno=`expr ${_fileno:-0} + 1`; else _fileno=0; fi
+ if [ $# -ge 3 ] ; then _name=$3; else _name=${SUITE}${EMOS_BASE}${TASK}; fi
+
+ if [ ${_fileno} -gt 0 ] ; then
+ /bin/rm -f ${PSDIR}/${_name}.${_fileno}.ps
+ cp $_psfile ${PSDIR}/${_name}.${_fileno}.ps
+ else
+ /bin/rm -f ${PSDIR}/${_name}.ps
+ cp $_psfile ${PSDIR}/${_name}.ps
+ fi
+
+ set -ex
+}
+
+typeset -fx PSFILE
+
+#=======================================================================
+# For FDB we need a different stream. Oh why can they not be the same?
+#=======================================================================
+
+set -a
+[[ $STREAM = DA ]] && { WSTREAM=WV; FDB_STREAM=oper; FDB_WSTREAM=wave; }
+[[ $STREAM = EF ]] && { WSTREAM=WAEF; FDB_STREAM=enfo; FDB_WSTREAM=waef; }
+[[ $STREAM = SCDA ]] && { WSTREAM=SCWV; FDB_STREAM=scda; FDB_WSTREAM=scwv; }
+[[ $STREAM = MAED ]] && { WSTREAM=MAWV; FDB_STREAM=maed; FDB_WSTREAM=mawv; }
+[[ $STREAM = sens ]] && { WSTREAM=sens; FDB_STREAM=sens; FDB_WSTREAM=sens; }
+[[ $STREAM = SCDA ]] && unset FDB_SERVER_HOST || true
+[[ $STREAM = DCDA ]] && { WSTREAM=DCWV ; FDB_STREAM=dcda ; FDB_WSTREAM=dcwv; }
+[[ $STREAM = EFHC ]] && { WSTREAM=EWHC ; FDB_STREAM=efhc ; FDB_WSTREAM=ewhc; } # MC HINDCAST
+[[ $STREAM = ENFH ]] && { WSTREAM=ENWH; FDB_STREAM=enfh ; FDB_WSTREAM=enwh; } # MC HINDCAST
+[[ $STREAM = DAHC ]] && { WSTREAM=WVHC ; FDB_STREAM=dahc ; FDB_WSTREAM=wvhc; } # MC HINDCAST
+
+set +a
+
+#=======================================================================
+# Check for day and date mask
+#=======================================================================
+
+echo checking for date mask
+
+datemask=$(echo '%DATEMASK%' | cut -f1 -d.)
+day=$(substring $BASETIME 7 8)
+weekday=%WEEKDAY:none%
+
+if [[ $weekday != "none" ]] ; then
+ jday=$(newdate -d $BASETIME)
+ jday=$(expr $jday %% 7) || true
+ if [[ $jday -eq 0 ]] ; then
+ dow=monday
+ elif [[ $jday -eq 1 ]] ; then
+ dow=tuesday
+ elif [[ $jday -eq 2 ]] ; then
+ dow=wednesday
+ elif [[ $jday -eq 3 ]] ; then
+ dow=thursday
+ elif [[ $jday -eq 4 ]] ; then
+ dow=friday
+ elif [[ $jday -eq 5 ]] ; then
+ dow=saturday
+ elif [[ $jday -eq 6 ]] ; then
+ dow=sunday
+ fi
+fi
+
+if [[ $datemask != "*" && $day -ne $datemask ]] || [[ $weekday != "none" && $weekday != $dow ]] ; then
+echo job should not run today ... setting it complete
+%include <endt.h>
+fi
+
+#=======================================================================
+#
+# Check the directories
+#
+#=======================================================================
+
+CHECK_DIR $ADIR
+CHECK_DIR $WDIR
+
+if [[ $ARCH = ibm_power* ]];then
+ export PBIO_BUFSIZE=1048576
+fi
+
+#=======================================================================
+#
+# Suite stopper
+#
+#=======================================================================
+
+if [[ %SUITE% = "e_35r3" && $BASETIME = "2012120500" ]] ; then
+ echo "ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR"
+ echo "Suite e_35r3 has been set up to stop now"
+ echo "Operators You can suspend this suite and requeue failed tasks if you like!"
+ echo "ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR"
+ exit 1
+elif [[ %SUITE% = "emc_35r3" && $BASETIME = "2012022600" ]] ; then
+ echo "ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR"
+ echo "Suite emc_35r3 has been set up to stop now"
+ echo "Operators You can suspend this suite and requeue failed tasks if you like!"
+ echo "ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR"
+ exit 1
+fi
+
+#=======================================================================
+# We use an operation only Magics version to be on the safe side.
+# This is of course only on the servers
+#=======================================================================
+MAGICS=%MAGICS:magics_emos%
+
+#=======================================================================
+# We use an operation only Metview version to be on the safe side.
+#=======================================================================
+
+if [[ $ARCH = linux ]] ; then
+ metview_cmd=%METVIEW:metview_emos%
+
+elif [[ $ARCH = ibm_power4 ]] ; then
+ METVIEW_TMPDIR=/home/ma/emos/metview/metview_tmpdir
+ metview_cmd=%METVIEW:/home/ma/emos/metview/MvRun_3.9.3%
+elif [[ $ARCH = ibm_power6 ]] ; then
+ METVIEW_TMPDIR=/home/ma/emos/metview/metview_tmpdir
+ metview_cmd=%METVIEW:/home/ma/emos/metview/MvRun_3.10%
+fi
+
+#=======================================================================
+# We use an operation only metpy version to be on the safe side.
+#=======================================================================
+metpy_cmd=%METPY:metpy_emos%
+
+echo setup complete
+
+# 20040720 add /home/rd/rdx/bin/filter/bufr_filter from hpcd
+#
+%include <law.h>
+
+export LEDFAMILY=%EDFAMILY:false%
+
+banner end setup.h
diff --git a/ANode/test/data/SMSHOME2/good/includes/sms.h b/ANode/test/data/SMSHOME2/good/includes/sms.h
new file mode 100644
index 0000000..3843b43
--- /dev/null
+++ b/ANode/test/data/SMSHOME2/good/includes/sms.h
@@ -0,0 +1,55 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+#==========================================================================
+# Define environment variables and export them.
+#==========================================================================
+
+set -a
+
+ECF_PASS=%ECF_PASS%
+ECF_NODE=%ECF_NODE%
+ECF_NAME=%ECF_NAME%
+ECF_TRYNO=%ECF_TRYNO%
+ECF_RID=$(echo $QSUB_REQID | cut -f1 -d.)
+ECF_HOSTFILE=$HOME/.smshostfile
+ECF_PORT=%ECF_PORT%
+ECF_JOBOUT=%ECF_JOBOUT%
+
+SUITE=%SUITE%
+FAMILY=%FAMILY%
+TASK=%TASK%
+
+DEBUG=0
+DISPLAY=0
+
+#==========================================================================
+# Initialize sms.
+# Trap handling.
+# Modify the ERROR function what to do in case of any error.
+#==========================================================================
+
+#if [[ $ARCH = sgimips && -f /usr/local/ecfs/prodn/.ecfs_k_env ]] ; then
+if [[ -f /usr/local/ecfs/prodn/.ecfs_k_env ]] ; then
+ . /usr/local/ecfs/prodn/.ecfs_k_env
+fi
+
+smsinit $ECF_RID &
+
+ERROR() {
+ smsabort; printenv; trap 0; exit
+}
+
+trap ERROR 0
+trap '{ echo "Killed by a signal"; ERROR ; }' 1 2 3 4 5 6 7 8 10 12 13 15
+
+set -ex
+
+if [[ $ARCH = sgimips && -f /usr/local/ecfs/prodn/.ecfs_k_env ]] ; then
+ . /usr/local/ecfs/prodn/.ecfs_k_env
+fi
+
diff --git a/ANode/test/data/SMSHOME2/good/includes/tail.h b/ANode/test/data/SMSHOME2/good/includes/tail.h
new file mode 100644
index 0000000..91682fb
--- /dev/null
+++ b/ANode/test/data/SMSHOME2/good/includes/tail.h
@@ -0,0 +1,10 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+#smscomplete # Notify SMS of a normal end
+trap 0 # Remove all traps
+exit 0 # End the shell
diff --git a/ANode/test/data/SMSHOME2/good/includes/trap.h b/ANode/test/data/SMSHOME2/good/includes/trap.h
new file mode 100644
index 0000000..edebcf9
--- /dev/null
+++ b/ANode/test/data/SMSHOME2/good/includes/trap.h
@@ -0,0 +1,137 @@
+banner trap.h
+
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+
+#==========================================================================
+# Trap handling and ECF_ initialisation
+#
+# Write into the ERROR function what to do in case of any error.
+#==========================================================================
+
+typeset -l ARCH
+
+if [[ "$ARCH" = hpia64 ]] ; then
+ rcp /home/ma/emos/data/dummy.output emos@%ECF_NODE%:%ECF_JOBOUT% || true
+fi
+
+set -a
+LOADL_STEP_ID=${LOADL_STEP_ID:=NOT_SET}
+QSUB_REQID=${QSUB_REQID:=NOT_SET}
+PBS_JOBID=${PBS_JOBID:=NOT_SET}
+
+if [[ $LOADL_STEP_ID != NOT_SET ]] ; then
+ ECF_RID=$(echo $LOADL_STEP_ID | cut -f1 -d.)
+ ECF_RID=$(substring $ECF_RID 6 8 )
+ ECF_RID=$(echo $LOADL_STEP_ID | cut -f2 -d.)${ECF_RID}
+ JOB_ID=$LOADL_STEP_ID
+elif [[ $QSUB_REQID != NOT_SET ]] ; then
+ ECF_RID=$(echo $QSUB_REQID | cut -f1 -d.)
+ JOB_ID=$QSUB_REQID
+elif [[ $PBS_JOBID != NOT_SET ]] ; then
+ ECF_RID=$(echo $PBS_JOBID | cut -f1 -d.)
+ JOB_ID=$PBS_JOBID
+
+ TOPATH=%TOPATH:/tmp/output%
+ link_name=`~emos/bin/subs_path.pl -f %ECF_OUT% -t $TOPATH -n %ECF_JOBOUT%`
+ mkdir -p `dirname $link_name` || :
+ ln -sf /var/spool/PBS/spool/${PBS_JOBID}.OU $link_name || :
+ rm -f %ECF_JOBOUT% || :
+ ln -sf /var/spool/PBS/spool/${PBS_JOBID}.OU %ECF_JOBOUT%
+else
+ ECF_RID=$$
+ JOB_ID=$ECF_RID
+fi
+
+ECF_PASS=%ECF_PASS%
+ECF_NODE=%ECF_NODE%
+ECF_NAME=%ECF_NAME%
+ECF_TRYNO=%ECF_TRYNO%
+ECF_HOSTFILE=$HOME/.smshostfile
+ECF_JOBOUT=%ECF_JOBOUT%
+
+set +a
+ARCHWDIR=${ARCHWDIR:=""}
+
+SMSCLEAN() {
+ set -x
+ set +e
+ STREAM=${STREAM:=""}
+ if [[ "$STREAM" = @(SEAS|MOFC|OCEA|mnfc|mnfh) ]] ; then
+ if [[ "%TASK%" = logfiles ]] ; then
+ n=0
+ while [[ -d $WDIR ]] ; do
+ # Forked processes could still be around, and 'rm -rf' fails
+ rm -rf $WDIR || true
+ ls -l $WDIR && sleep 2 || true
+ n=$((n+1))
+ [[ $n -gt 5 ]] && break
+ done || true
+ fi
+ fi
+ FSFAMILY=${FSFAMILY:=""}
+ if [[ "$FSFAMILY" = /mars || "%FAMILY1%" = archive ]] ; then
+ cd $TMPDIR
+ n=0
+ while [[ -d ${WDIR}$ECF_NAME ]] ; do
+ # Forked processes could still be around, and 'rm -rf' fails
+ rm -rf ${WDIR}$ECF_NAME || true
+ ls -l ${WDIR}$ECF_NAME && sleep 2 || true
+ n=$((n+1))
+ [[ $n -gt 5 ]] && break
+ done || true
+ fi
+
+ if [[ $ARCH = linux ]] ; then
+ . /usr/local/share/ecmwf/share/.epilog
+ fi
+}
+typeset -fx SMSCLEAN
+
+%include <rcp.h>
+
+ERROR() {
+ set -x
+ set +e
+ wait
+ smsabort
+ trap 0
+ date
+ times
+ echo "environment was:"
+ printenv | sort
+
+ SMSCLEAN
+
+ if [[ $$ARCH != "ibm_power*" ]] ; then
+ SMSRCP || :
+ fi
+ exit 1
+}
+
+if [[ $ARCH == hpia64 ]]; then
+ export SMS_SIGNAL_LIST='1 2 3 4 5 6 7 8 10 12 13 15 24 30 33'
+elif [[ $ARCH == ibm_power* ]]; then
+ export SMS_SIGNAL_LIST='1 2 3 4 5 6 7 8 10 12 13 15 24 30'
+elif [[ $ARCH == linux ]]; then
+ export SMS_SIGNAL_LIST='1 2 3 4 5 6 7 8 13 15 24 31'
+else
+ export SMS_SIGNAL_LIST='1 2 3 4 5 6 7 8 13 15 24 31'
+fi
+
+%include <set_traps.h>
+trap
+set -exu
+
+[[ -d $TMPDIR ]] && cd $TMPDIR
+
+smsinit $ECF_RID &
+smsmsg "#ID ECF_NAME=%ECF_NAME%;ECF_JOBOUT=%ECF_JOBOUT%;ECF_HOME=%ECF_HOME%;JOB_ID=${JOB_ID:-}"
+
+date
+
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/micro_in_comment.ecf b/ANode/test/data/SMSHOME2/good/micro_in_comment.ecf
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/SMSHOME2/good/micro_in_comment.ecf
rename to ANode/test/data/SMSHOME2/good/micro_in_comment.ecf
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/operations.ecf b/ANode/test/data/SMSHOME2/good/operations.ecf
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/SMSHOME2/good/operations.ecf
rename to ANode/test/data/SMSHOME2/good/operations.ecf
diff --git a/ecflow_4_0_7/ANode/test/data/common.h b/ANode/test/data/common.h
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/common.h
rename to ANode/test/data/common.h
diff --git a/ANode/test/data/includes/a.h b/ANode/test/data/includes/a.h
new file mode 100644
index 0000000..3240e1c
--- /dev/null
+++ b/ANode/test/data/includes/a.h
@@ -0,0 +1,2 @@
+#a.h
+%include <b.h>
diff --git a/ANode/test/data/includes/b.h b/ANode/test/data/includes/b.h
new file mode 100644
index 0000000..de98765
--- /dev/null
+++ b/ANode/test/data/includes/b.h
@@ -0,0 +1 @@
+#b.h
diff --git a/ANode/test/data/includes/head.h b/ANode/test/data/includes/head.h
new file mode 100644
index 0000000..0b4d722
--- /dev/null
+++ b/ANode/test/data/includes/head.h
@@ -0,0 +1,65 @@
+#!/bin/ksh
+# ================================== start of head.h ================================
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+%manual
+#This is the manual from the head.h file
+%end
+
+%comment
+#This is the comment from the head.h file
+%end
+
+set -e # stop the shell on first error
+set -u # fail when using an undefined variable
+set -x # echo script lines as they are executed
+
+# Defines the three variables that are needed for any
+# communication with ECF
+
+export ECF_PORT=%ECF_PORT% # ECF_ Remote Procedure Call number
+export ECF_NODE=%ECF_NODE% # The name sms that issued this task
+export ECF_NAME=%ECF_NAME% # The name of this current task
+export ECF_PASS=%ECF_PASS% # A unique password
+export ECF_TRYNO=%ECF_TRYNO% # Current try number of the task
+
+# to debug client communication with the server, enable this environment
+#export ECF_DEBUG_CLIENT=
+
+# Typically we dont set this, however the zombie automated test require this.
+# it allows us to disambiguate a zomie from a real job.
+export ECF_RID=$$
+
+# Tell ECF_ we have stated
+# The ECF_ variable ECF_RID will be set to parameter of smsinit
+# Here we give the current PID.
+
+
+# Defined a error hanlder
+ERROR() {
+ echo "ERROR called"
+ set +e # Clear -e flag, so we don't fail
+ #smsabort # Notify ECF_ that something went wrong
+ %ECF_CLIENT_EXE_PATH:ecflow_client% --abort
+ trap 0 # Remove the trap
+ exit 0 # End the script
+}
+
+# Trap any calls to exit and errors caught by the -e flag
+
+trap ERROR 0
+
+# Trap any signal that may cause the script to fail
+
+trap '{ echo "Killed by a signal"; ERROR ; }' 1 2 3 4 5 6 7 8 10 12 13 15
+
+
+#smsinit $$
+%ECF_CLIENT_EXE_PATH:ecflow_client% --init=$$
+echo $?
+# ================================== end of head.h ================================
diff --git a/ecflow_4_0_7/ANode/test/data/includes/manual.h b/ANode/test/data/includes/manual.h
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/includes/manual.h
rename to ANode/test/data/includes/manual.h
diff --git a/ecflow_4_0_7/ANode/test/data/includes/simple_head.h b/ANode/test/data/includes/simple_head.h
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/includes/simple_head.h
rename to ANode/test/data/includes/simple_head.h
diff --git a/ecflow_4_0_7/ANode/test/data/includes/simple_tail.h b/ANode/test/data/includes/simple_tail.h
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/includes/simple_tail.h
rename to ANode/test/data/includes/simple_tail.h
diff --git a/ANode/test/data/includes/tail.h b/ANode/test/data/includes/tail.h
new file mode 100644
index 0000000..07fa1a7
--- /dev/null
+++ b/ANode/test/data/includes/tail.h
@@ -0,0 +1,19 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+# ================================== start of tail.h ================================
+#smscomplete # Notify ECF of a normal end
+%ECF_CLIENT_EXE_PATH:ecflow_client% --complete
+trap 0 # Remove all traps
+exit 0 # End the shell
+%manual
+#This is the manual from the tail.h file
+%end
+%comment
+#This is the comment from the tail.h file
+%end
+# ================================== end of tail.h ================================
diff --git a/ecflow_4_0_7/ANode/test/data/includes/used_variables.h b/ANode/test/data/includes/used_variables.h
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/includes/used_variables.h
rename to ANode/test/data/includes/used_variables.h
diff --git a/ecflow_4_0_7/ANode/test/data/includes/used_variables_with_comments.h b/ANode/test/data/includes/used_variables_with_comments.h
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/includes/used_variables_with_comments.h
rename to ANode/test/data/includes/used_variables_with_comments.h
diff --git a/ANode/test/data/includes2/fred.h b/ANode/test/data/includes2/fred.h
new file mode 100644
index 0000000..9a1ab42
--- /dev/null
+++ b/ANode/test/data/includes2/fred.h
@@ -0,0 +1,7 @@
+#
+# Used to test inclusion with angle brackets <filename>
+# First look in *ALL* the paths specfied in %ECF_INCLUDE%
+# If file not there then look at ECF_HOME/filename
+#
+# THIS ALLOWS USE TO PUT SPECIFIC FILES IN ECF_INCLUDE
+# AND COMMON FILE IN ECF_HOME
diff --git a/ecflow_4_0_7/ANode/test/data/migration/default_constructor/Defs.def b/ANode/test/data/migration/default_constructor/Defs.def
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/migration/default_constructor/Defs.def
rename to ANode/test/data/migration/default_constructor/Defs.def
diff --git a/ecflow_4_0_7/ANode/test/data/migration/default_constructor/Family.def b/ANode/test/data/migration/default_constructor/Family.def
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/migration/default_constructor/Family.def
rename to ANode/test/data/migration/default_constructor/Family.def
diff --git a/ecflow_4_0_7/ANode/test/data/migration/default_constructor/Limit.def b/ANode/test/data/migration/default_constructor/Limit.def
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/migration/default_constructor/Limit.def
rename to ANode/test/data/migration/default_constructor/Limit.def
diff --git a/ecflow_4_0_7/ANode/test/data/migration/default_constructor/Suite.def b/ANode/test/data/migration/default_constructor/Suite.def
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/migration/default_constructor/Suite.def
rename to ANode/test/data/migration/default_constructor/Suite.def
diff --git a/ecflow_4_0_7/ANode/test/data/migration/default_constructor/Task.def b/ANode/test/data/migration/default_constructor/Task.def
similarity index 100%
rename from ecflow_4_0_7/ANode/test/data/migration/default_constructor/Task.def
rename to ANode/test/data/migration/default_constructor/Task.def
diff --git a/ANode/test/data/migration/fixture/boost.checkpt b/ANode/test/data/migration/fixture/boost.checkpt
new file mode 100644
index 0000000..3aaa477
--- /dev/null
+++ b/ANode/test/data/migration/fixture/boost.checkpt
@@ -0,0 +1,77 @@
+22 serialization::archive 10 0 0 0 0 0 0 2 0 0 0 0 16 0 9 ECF_MICRO 1 % 8 ECF_HOME 1 . 11 ECF_JOB_CMD 30 %ECF_JOB% 1> %ECF_JOBOUT% 2>&1 12 ECF_KILL_CMD 18 kill -15 %ECF_RID% 14 ECF_STATUS_CMD 21 ps --sid %ECF_RID% -f 11 ECF_URL_CMD 63 ${BROWSER:=firefox} -remote 'openURL(%ECF_URL_BASE%/%ECF_URL%)' 12 ECF_URL_BASE 26 https://software.ecmwf.int 7 ECF_URL 24 wiki/display/ECFLOW/Home 12 ECF_INTERVAL 2 60 9 ECF_LISTS 23 eurydice.3141.ecf.lists 17 ECF_CHECKINTERVAL 3 120 13 ECF_CHECKMODE 13 CH [...]
+0 0 0 0 0 9 suiteName 0 0 0 0 0 0 0 0 0 0 0 2 -1 -1 -1 13 1 0
+1 48 0 0 1 1 14 1 0
+2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 10 0 0 0 5 0 0 0 0 0 0 0 0 0 7 0 0 1 2 3 4 5 6 31 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 12 0 1 2 3 4 5 6 7 8 9 10 11 12 0 -1 -1 -1 3 0 3 VAR 5 value 4 VAR1 7 "value" 9 ECF_FETCH 42 "smsfetch -F %ECF_FILES% -I %ECF_INCLUDE%" 0 0 1 1 0 1 25 1 0
+3 10 suiteLimit 10 0 0 0 0 0 0 0 0 0 0 0 0 12 1 0 1 6 1 0
+4 0 0 2 t1 0 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 -1 -1 -1 0 0 0 1 0 0 0 5 _DJP_ 0 0 0 0 0 0 0 1 6
+5 2 t2 0 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 -1 -1 -1 0 0 0 1 0 0 0 5 _DJP_ 0 0 0 0 0 1 6
+6 2 t3 0 0 0 0 0 0 0 2 11 1 0
+7 0 0 2 0 0 0 14 t1 == complete 0 14 t2 == complete 1 0 11
+8 2 0 14 t1 == complete 0 14 t2 == complete 2 0 -1 -1 -1 -1 22 1 0
+9 0 0 3 0 0 0 300 0 0 7 0 0 1 2 3 4 5 6 1 1 100 7 0 0 1 2 3 4 5 6 2 4 100 7 0 0 1 2 3 4 5 6 0 0 0 0 -1 0 0 0 1 0 0 0 5 _DJP_ 0 0 0 0 0 1 6
+10 2 t4 0 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 -1 22
+11 3 0 0 2 300 7 0 0 1 2 3 4 5 6 1 3 100 7 0 0 1 2 3 4 5 6 2 4 100 7 0 0 1 2 3 4 5 6 0 0 -1 0 0 0 1 0 0 0 5 _DJP_ 0 0 0 0 0 1 6
+12 2 t5 0 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 -1 -1 37 16 RepeatEnumerated 1 0
+13 0 0 5 AEnum 0 0 3 0 2 10 2 20 2 30 0 0 0 0 1 0 0 0 5 _DJP_ 0 0 0 0 0 1 6
+14 2 t6 0 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 -1 -1 40 12 RepeatString 1 0
+15 7 aString 3 0 2 10 2 20 2 30 0 0 0 0 1 0 0 0 5 _DJP_ 0 0 0 0 0 1 6
+16 2 t7 0 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 -1 -1 41 13 RepeatInteger 1 0
+17 3 rep 0 100 1 0 0 0 0 1 0 0 0 5 _DJP_ 0 0 0 0 0 1 6
+18 2 t8 0 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 -1 -1 42 10 RepeatDate 1 0
+19 3 YMD 20090916 20090916 1 20090916 0 0 0 1 0 0 0 5 _DJP_ 0 0 0 0 0 1 6
+20 2 t9 0 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 -1 -1 43 9 RepeatDay 1 0
+21 3 day 2 0 0 0 1 0 0 0 5 _DJP_ 0 0 0 0 0 1 7 1 0
+22 10 familyName 0 0 0 0 0 0 0 2 -1 -1 12 1 0
+23 3 12 0 3 12 0 4 12 0 1 0 13
+24 1 0 0 1 0 14
+25 1 0 1 1 0 0 0 10 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 2009 0 0 0 0 0 -1 -1 37
+26 5 AEnum 3 0 2 10 2 20 2 30 0 1 0 3 VAR 5 value 1 1 25
+27 9 limitName 20 0 0 0 0 0 0 2 1 6
+28 8 taskName 0 0 0 0 0 0 0 1 -1 -1 12
+29 3 12 0 3 12 0 4 12 0 1 0 -1 14
+30 1 0 1 1 10 10 0 0 0 1 0 0 1 10 10 0 0 0 0 0 0 0 2 0 0 1 10 12 0 0 0 1 0 0 1 10 12 0 0 0 0 0 0 0 1 1 0 1 0 0 3 0 0 1 0 0 1 0 0 0 0 0 0 0 1 0 1 2 2009 0 1 0 1 0 0 0 21 1 0
+31 0 0 1 0 0 100 0 100 7 myMeter 0 0 2 0 0 0 0 0 1 9 eventName 0 0 1 0 9 labelName 12 "labelValue" 0 22
+32 0 0 1 0 1 3 0 -1 1 0 4 VAR1 7 "value" 0 1 1 0 0 0 10 suiteLimit 10 /suiteName 1 0 5 _DJP_ 0 0 0 2 2 1 0 1 49 1 0
+33 6 alias0 2 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 21
+34 1 0 0 100 0 100 7 myMeter 2 0 0 0 0 0 1 9 eventName 1 0 9 labelName 12 "labelValue" 0 -1 -1 0 0 0 1 0 0 0 5 _DJP_ 0 0 0 49
+35 6 alias1 2 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 21
+36 1 0 0 100 0 100 7 myMeter 2 0 0 0 0 0 1 9 eventName 1 0 9 labelName 12 "labelValue" 0 -1 -1 0 0 0 1 0 0 0 5 _DJP_ 0 0 0 7
+37 15 heir_familyName 0 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 -1 -1 40
+38 7 aString 3 0 2 10 2 20 2 30 0 1 0 4 VAR1 5 value 0 1 0 0 0 1 1 6
+39 8 taskName 0 0 0 0 0 0 0 2 -1 -1 -1 13
+40 0 1 0 0 0 -1 21
+41 1 0 0 100 0 100 7 myMeter 2 0 0 0 0 0 1 9 eventName 0 0 -1 -1 1 0 4 VAR1 5 value 0 1 0 0 0 5 _DJP_ 0 0 0 0 0 1 7
+42 11 familyName1 0 0 0 0 0 0 0 2 -1 -1 12
+43 3 12 0 3 12 0 4 12 0 1 0 13
+44 1 0 0 1 0 14
+45 1 0 1 1 0 0 0 10 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 2009 0 0 0 0 0 -1 -1 37
+46 5 AEnum 3 0 2 10 2 20 2 30 0 1 0 3 VAR 5 value 1 1 25
+47 9 limitName 20 0 0 0 0 0 0 1 1 6
+48 9 taskName1 0 0 0 0 0 0 0 1 -1 -1 12
+49 3 12 0 3 12 0 4 12 0 1 0 -1 14
+50 1 0 1 1 10 10 0 0 0 1 0 0 1 10 10 0 0 0 0 0 0 0 2 0 0 1 10 12 0 0 0 1 0 0 1 10 12 0 0 0 0 0 0 0 1 1 0 1 0 0 3 0 0 1 0 0 1 0 0 0 0 0 0 0 1 0 1 2 2009 0 1 0 1 0 0 0 21
+51 1 0 0 100 0 100 7 myMeter 2 0 0 1 0 0 2 9 eventName 1 0 10 labelName1 12 "labelValue" 0 22
+52 0 0 1 0 1 3 0 -1 1 0 4 VAR1 7 "value" 0 1 1 0 10 suiteLimit 10 /suiteName 1 0 5 _DJP_ 0 0 0 2 2 1 49
+53 6 alias0 2 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 21
+54 1 0 0 100 0 100 7 myMeter 2 0 0 1 0 0 2 9 eventName 1 0 10 labelName1 12 "labelValue" 0 -1 -1 0 0 0 1 0 0 0 5 _DJP_ 0 0 0 49
+55 6 alias1 2 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 21
+56 1 0 0 100 0 100 7 myMeter 2 0 0 1 0 0 2 9 eventName 1 0 10 labelName1 12 "labelValue" 0 -1 -1 0 0 0 1 0 0 0 5 _DJP_ 0 0 0 7
+57 11 familyName2 0 0 0 0 0 0 0 2 -1 -1 12
+58 3 12 0 3 12 0 4 12 0 1 0 13
+59 1 0 0 1 0 14
+60 1 0 1 1 0 0 0 10 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 2009 0 0 0 0 0 -1 -1 37
+61 5 AEnum 3 0 2 10 2 20 2 30 0 1 0 3 VAR 5 value 1 1 25
+62 9 limitName 20 0 0 0 0 0 0 1 1 6
+63 9 taskName2 0 0 0 0 0 0 0 1 11
+64 1 0 38 ../familyName1/taskName1:myMeter ge 10 0 0 11
+65 1 0 36 ../familyName1/taskName1 == complete 0 0 12
+66 3 12 0 3 12 0 4 12 0 1 0 -1 14
+67 1 0 1 1 10 10 0 0 0 1 0 0 1 10 10 0 0 0 0 0 0 0 2 0 0 1 10 12 0 0 0 1 0 0 1 10 12 0 0 0 0 0 0 0 1 1 0 1 0 0 3 0 0 1 0 0 1 0 0 0 0 0 0 0 1 0 1 2 2009 0 1 0 1 0 0 0 21
+68 1 0 0 100 0 100 7 myMeter 2 0 0 2 0 0 3 9 eventName 1 0 10 labelName2 12 "labelValue" 0 22
+69 0 0 1 0 1 3 0 -1 1 0 4 VAR1 7 "value" 0 1 1 0 10 suiteLimit 10 /suiteName 1 0 5 _DJP_ 0 0 0 2 2 1 49
+70 6 alias0 2 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 21
+71 1 0 0 100 0 100 7 myMeter 2 0 0 2 0 0 3 9 eventName 1 0 10 labelName2 12 "labelValue" 0 -1 -1 0 0 0 1 0 0 0 5 _DJP_ 0 0 0 49
+72 6 alias1 2 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 21
+73 1 0 0 100 0 100 7 myMeter 2 0 0 2 0 0 3 9 eventName 1 0 10 labelName2 12 "labelValue" 0 -1 -1 0 0 0 1 0 0 0 5 _DJP_ 0 0 0 0 0 1 51 1 0
+74 0 1 1 3600 1 1 2009 0 0 0 0 8 20160419 0 9 3 12 0 8 20160419 0 9 3 12 0 0 0 0 0 0 0 8 20160419 0 9 3 12 0 8 20160419 0 9 3 12 0 0 0 1 0 0 4
+75 10 EmptySuite 0 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 -1 -1 -1 0 0 0 1 0 0 0 0 1 0 -1 8 20160419 0 9 3 12 0 8 20160419 0 9 3 12 0 0 0 0 0 0 0 8 20160419 0 9 3 12 0 8 20160419 0 9 3 12 0 0 0 1 0 0 0 0 0 0 0
diff --git a/AParser/CMakeLists.txt b/AParser/CMakeLists.txt
new file mode 100644
index 0000000..4b48aa5
--- /dev/null
+++ b/AParser/CMakeLists.txt
@@ -0,0 +1,74 @@
+# Note:
+# If new src or test cpp files are added make sure you touch this file
+#
+
+file( GLOB srcs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp" )
+
+ecbuild_add_library( TARGET libparser
+ NOINSTALL
+ TYPE STATIC
+ SOURCES ${srcs}
+ LIBS node nodeattr core
+ INCLUDES src
+ ../ACore/src
+ ../ANattr/src
+ ../ANode/src
+ )
+
+# ===================================================================
+# Use following to populate list:
+# cd $WK/AParser
+# find test -name \*.cpp | sort
+list( APPEND test_srcs
+ test/PersistHelper.cpp
+ test/TestAutoAddExterns.cpp
+ test/TestDefsStructurePersistAndReload.cpp
+ test/TestMigration.cpp
+ test/TestParser.cpp
+ test/TestVariableParsing.cpp
+)
+ecbuild_add_test( TARGET u_aparser
+ BOOST
+ SOURCES ${test_srcs}
+ LIBS libparser
+ INCLUDES ../ANode/test
+ TEST_DEPENDS u_anode
+ )
+
+
+if (ENABLE_ALL_TESTS)
+ #
+ # Tests parser for a single defs file but with a range of tests
+ #
+ list( APPEND t2_src test/TestSingleDefsFile.cpp test/PersistHelper.cpp )
+ ecbuild_add_test( TARGET perf_aparser
+ BOOST
+ SOURCES ${t2_src}
+ LIBS libparser
+ )
+
+ #
+ # Timer for arbitary defs file,
+ #
+ list( APPEND t3_src test/ParseTimer.cpp test/PersistHelper.cpp )
+ ecbuild_add_test( TARGET perf_aparser_timer
+ ARGS ${CMAKE_CURRENT_SOURCE_DIR}/test/data/single_defs/mega.def
+ SOURCES ${t3_src}
+ LIBS libparser
+ INCLUDES ../ANode/test
+ ${Boost_INCLUDE_DIRS}
+ )
+
+
+ #
+ # Tests parser for a single defs file.
+ #
+ list( APPEND t4_src test/ParseOnly.cpp )
+ ecbuild_add_test( TARGET perf_aparser_only
+ ARGS ${CMAKE_CURRENT_SOURCE_DIR}/test/data/single_defs/mega.def
+ SOURCES ${t4_src}
+ LIBS libparser
+ INCLUDES ../ANode/test
+ ${Boost_INCLUDE_DIRS}
+ )
+endif()
\ No newline at end of file
diff --git a/AParser/Jamfile.jam b/AParser/Jamfile.jam
new file mode 100644
index 0000000..3980f4f
--- /dev/null
+++ b/AParser/Jamfile.jam
@@ -0,0 +1,126 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+#
+# Parser
+#
+project theParser ;
+
+use-project theCore : ../ACore ;
+use-project theNodeAttr : ../ANattr ;
+use-project theNode : ../ANode ;
+
+#
+# Having a library avoid compile objects shared between client and test having
+# differing compilation properties
+#
+lib libparser : [ glob src/*.cpp ]
+ : <include>../ACore/src
+ <include>../ANattr/src
+ <include>../ANode/src
+ <variant>debug:<define>DEBUG
+ <link>static
+ :
+ : <include>../AParser/src
+ ;
+
+#
+# This is *ONLY* required when the define ECFLOW_MT is used,(used by Signal.cpp)
+lib pthread ;
+
+#
+# Tests for parser. Exclude file test/TestSingleDefsFile.cpp, test/ParseOnly.cpp test/ParseTimer.cpp
+# test/TestJobGenPerf.cpp
+#
+exe u_aparser : [ glob test/*.cpp :
+ test/TestSingleDefsFile.cpp
+ test/ParseOnly.cpp test/ParseTimer.cpp
+ test/TestJobGenPerf.cpp
+ ]
+ pthread
+ /theCore//core
+ /theNodeAttr//nodeattr
+ /theNode//node
+ libparser
+ /site-config//boost_system
+ /site-config//boost_serialization
+ /site-config//boost_filesystem
+ /site-config//boost_datetime
+ /site-config//boost_test
+ : <include>../ANode/test
+ <variant>debug:<define>DEBUG
+ ;
+
+#
+# Tests parser for a single defs file.
+#
+exe perf_aparser : test/TestSingleDefsFile.cpp test/PersistHelper.cpp
+ pthread
+ /theCore//core
+ /theNodeAttr//nodeattr
+ /theNode//node
+ libparser
+ /site-config//boost_system
+ /site-config//boost_serialization
+ /site-config//boost_filesystem
+ /site-config//boost_datetime
+ /site-config//boost_test
+ : <include>../ANode/test
+ <variant>debug:<define>DEBUG
+ ;
+
+#
+# Timer for arbitary defs file,
+#
+exe perf_aparser_timer : test/ParseTimer.cpp test/PersistHelper.cpp
+ pthread
+ /theCore//core
+ /theNodeAttr//nodeattr
+ /theNode//node
+ libparser
+ /site-config//boost_system
+ /site-config//boost_serialization
+ /site-config//boost_filesystem
+ /site-config//boost_datetime
+ : <include>../ANode/test
+ <variant>debug:<define>DEBUG
+ ;
+
+#
+# Tests parser for a single defs file.
+#
+exe perf_aparser_only : test/ParseOnly.cpp
+ pthread
+ /theCore//core
+ /theNodeAttr//nodeattr
+ /theNode//node
+ libparser
+ /site-config//boost_system
+ /site-config//boost_serialization
+ /site-config//boost_filesystem
+ /site-config//boost_datetime
+ : <include>../ANode/test
+ <variant>debug:<define>DEBUG
+ ;
+
+#
+# Tests job generation performance, relies on python (Pyext/samples/TestJobGenPerf.py) to setup data
+#
+exe perf_job_gen : test/TestJobGenPerf.cpp
+ pthread
+ /theCore//core
+ /theNodeAttr//nodeattr
+ /theNode//node
+ libparser
+ /site-config//boost_system
+ /site-config//boost_serialization
+ /site-config//boost_filesystem
+ /site-config//boost_datetime
+ : <include>../ANode/test
+ <variant>debug:<define>DEBUG
+ ;
+
\ No newline at end of file
diff --git a/AParser/src/AutoCancelParser.cpp b/AParser/src/AutoCancelParser.cpp
new file mode 100644
index 0000000..33ba735
--- /dev/null
+++ b/AParser/src/AutoCancelParser.cpp
@@ -0,0 +1,55 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #11 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "AutoCancelParser.hpp"
+#include "TimeSeries.hpp"
+#include "Extract.hpp"
+#include "Node.hpp"
+
+using namespace ecf;
+using namespace std;
+
+bool AutoCancelParser::doParse( const std::string& line, std::vector<std::string >& lineTokens )
+{
+ // autocancel +01:00 # cancel one hour after complete
+ // autocancel 01:00 # cancel at 1 am in morning after complete
+ // autocancel 10 # cancel 10 days after complete
+ // autocancel 0 # cancel immediately after complete
+
+ if ( lineTokens.size() < 2 ) throw std::runtime_error( "AutoCancelParser::doParse: Invalid autocancel :" + line );
+ if ( nodeStack().empty() ) throw std::runtime_error("AutoCancelParser::doParse: Could not add autocancel as node stack is empty at line: " + line );
+
+ if (lineTokens[1].find_first_of(':') == string::npos) {
+ // Must be of the form:
+ // autocancel 10 # cancel 10 days after complete
+ // autocancel 0 # cancel immediately after complete
+ int days = Extract::theInt(lineTokens[1],"invalid autocancel " + line) ;
+
+ nodeStack_top()->addAutoCancel( AutoCancelAttr( days ) ) ;
+ }
+ else {
+ // Must be of the form:
+ // autocancel +01:00 # cancel one hour after complete
+ // autocancel 01:00 # cancel at 1 am in morning after complete
+ int hour = 0;
+ int min = 0;
+ bool relative = TimeSeries::getTime(lineTokens[1],hour,min);
+
+ nodeStack_top()->addAutoCancel( AutoCancelAttr( TimeSlot( hour, min), relative ) ) ;
+ }
+ return true;
+}
+
+
diff --git a/AParser/src/AutoCancelParser.hpp b/AParser/src/AutoCancelParser.hpp
new file mode 100644
index 0000000..f413acc
--- /dev/null
+++ b/AParser/src/AutoCancelParser.hpp
@@ -0,0 +1,27 @@
+#ifndef AUTOCANCELPARSER_HPP_
+#define AUTOCANCELPARSER_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "Parser.hpp"
+
+class AutoCancelParser : public Parser {
+public:
+ AutoCancelParser(DefsStructureParser* p) : Parser(p) {}
+ virtual const char* keyword() const { return "autocancel"; }
+ virtual bool doParse(const std::string& line,std::vector<std::string>& lineTokens);
+};
+#endif
diff --git a/AParser/src/CalendarParser.cpp b/AParser/src/CalendarParser.cpp
new file mode 100644
index 0000000..98ec667
--- /dev/null
+++ b/AParser/src/CalendarParser.cpp
@@ -0,0 +1,39 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #21 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <stdexcept>
+
+#include "CalendarParser.hpp"
+#include "Str.hpp"
+#include "Suite.hpp"
+
+using namespace ecf;
+using namespace std;
+
+bool CalendarParser::doParse( const std::string& line, std::vector<std::string >& lineTokens )
+{
+ if ( lineTokens.size() < 2 ) {
+ throw std::runtime_error( "CalendarParser::doParse: Invalid calendar :" + line );
+ }
+ if ( nodeStack().empty() ) {
+ throw std::runtime_error("CalendarParser::doParse: Could not add calendar as node stack is empty at line: " + line );
+ }
+
+ Suite* suite = nodeStack_top()->isSuite();
+ if (!suite) throw std::runtime_error("Calendar can only be added to suites and not " + nodeStack_top()->debugType() );
+ suite->set_calendar().read_state(line,lineTokens);
+
+ return true;
+}
+
diff --git a/AParser/src/CalendarParser.hpp b/AParser/src/CalendarParser.hpp
new file mode 100644
index 0000000..6f4d6ce
--- /dev/null
+++ b/AParser/src/CalendarParser.hpp
@@ -0,0 +1,28 @@
+#ifndef CALENDAR_PARSER_HPP_
+#define CALENDAR_PARSER_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "Parser.hpp"
+
+class CalendarParser : public Parser {
+public:
+ CalendarParser(DefsStructureParser* p) : Parser(p) {}
+ virtual const char* keyword() const { return "calendar"; }
+ virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens);
+};
+
+#endif
diff --git a/AParser/src/ClockParser.cpp b/AParser/src/ClockParser.cpp
new file mode 100644
index 0000000..164dabd
--- /dev/null
+++ b/AParser/src/ClockParser.cpp
@@ -0,0 +1,143 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #22 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <stdexcept>
+
+#include "ClockParser.hpp"
+#include "DateParser.hpp"
+#include "TimeSeries.hpp"
+#include "Extract.hpp"
+#include "Str.hpp"
+#include "Suite.hpp"
+
+using namespace ecf;
+using namespace std;
+
+static void extractTheGain(const std::string& theGainToken, ClockAttr& clockAttr)
+{
+ if ( theGainToken.find(Str::COLON()) != std::string::npos ) {
+ // clock real +01:00
+ // clock real 01:36
+ int hour,min ;
+ bool positiveGain = TimeSeries::getTime(theGainToken,hour,min);
+ clockAttr.set_gain(hour,min,positiveGain);
+ return;
+ }
+
+ long theGain = 0;
+ std::string theGainStr = theGainToken;
+ bool positiveGain = false;
+ if ( theGainStr[0] == '+') {
+ positiveGain = true;
+ theGainStr.erase(theGainStr.begin());
+ }
+ theGain = Extract::theInt(theGainStr,"Invalid clock gain:" + theGainToken);
+ clockAttr.set_gain_in_seconds(theGain,positiveGain);
+}
+
+
+bool ClockParser::doParse( const std::string& line,
+ std::vector<std::string >& lineTokens )
+{
+ // clock hybrid # a comment
+ // clock hybrid
+ // clock real #a comment
+ // clock real 300
+ // clock real +01:00
+ // clock real 20.1.2007
+ // clock real 20.1.2007 +01:00
+
+ // For Testing we allow calendar increment to be change on a per suite basis
+ // -c is optional
+ // clock real 20.1.2007 +01:00
+ // clock hybrid
+
+ // Allow clock to be stopped/started when the server is stopped/started
+ // and hence always honour time dependencies. See Calendar.h for more details
+ // This is optional.( Need to advertise this functionality)
+ // clock real 20.1.2007 +01:00 -s
+ // clock hybrid -s
+ if ( lineTokens.size() < 2 ) {
+ throw std::runtime_error( "ClockParser::doParse: Invalid clock :" + line );
+ }
+ if ( nodeStack().empty() ) {
+ throw std::runtime_error("ClockParser::doParse: Could not add clock as node stack is empty at line: " + line );
+ }
+
+ bool hybrid = true ;
+ if ( lineTokens[1] == "real" ) hybrid = false ;
+ else if ( lineTokens[1] == "hybrid" ) hybrid = true;
+ else throw std::runtime_error( "Invalid clock :" + line );
+
+
+ ClockAttr clockAttr(hybrid);
+
+ if ( lineTokens.size() >= 3 && lineTokens[2][0] != '#' ) {
+ // if third token is not a comment the time must be of the form
+ // clock real 300
+ // clock real +01:00
+ // clock real 20.1.2007
+ // clock real 20.1.2007
+
+ if ( lineTokens[2].find(".") != std::string::npos ) {
+ // clock real 20.1.2007
+
+ // If 0 returned then day,month,year is of form *, and not valid
+ int day,month,year;
+ DateAttr::getDate(lineTokens[2],day,month,year);
+
+ // This will throw std::aout_of_range for an invalid clock date. Note no wild carding allowed.
+ clockAttr.date(day,month,year); // this will check the date
+
+ if ( lineTokens.size() >= 4 && lineTokens[3][0] != '#' ) {
+ // clock real 20.1.2007 +01:00
+ // clock real 20.1.2007 +300
+ // clock real 20.1.2007 350
+ extractTheGain(lineTokens[3], clockAttr);
+ }
+ }
+ else {
+ // clock real 300
+ // clock real +01:00
+ extractTheGain(lineTokens[2], clockAttr);
+ }
+ }
+
+ // Look for the optional -s , i.e start/stop calendar when the server starts/stops
+ // clock real 20.1.2007 +01:00 -s
+ // clock hybrid -s
+ size_t line_token_size = lineTokens.size();
+ for(size_t i = 2; i < line_token_size; i++ ) {
+ if (lineTokens[i] == "-s") {
+ clockAttr.startStopWithServer(true);
+ break;
+ }
+ // Reached the comment, no more valid tokens possible
+ if (lineTokens[i][0] == '#') {
+ // handles comments of the form:
+ // # comment
+ // #comment
+ // since we check the first character
+ break;
+ }
+ }
+
+ Suite* suite = nodeStack_top()->isSuite();
+ if (!suite) throw std::runtime_error("Clock can only be added to suites and not " + nodeStack_top()->debugType() );
+
+ suite->addClock(clockAttr);
+
+ return true;
+}
+
diff --git a/AParser/src/ClockParser.hpp b/AParser/src/ClockParser.hpp
new file mode 100644
index 0000000..0bd3785
--- /dev/null
+++ b/AParser/src/ClockParser.hpp
@@ -0,0 +1,29 @@
+#ifndef CLOCKPARSER_HPP_
+#define CLOCKPARSER_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "Parser.hpp"
+class ClockAttr;
+
+class ClockParser : public Parser {
+public:
+ ClockParser(DefsStructureParser* p) : Parser(p) {}
+ virtual const char* keyword() const { return "clock"; }
+ virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens);
+};
+
+#endif
diff --git a/AParser/src/CronParser.cpp b/AParser/src/CronParser.cpp
new file mode 100644
index 0000000..7aba877
--- /dev/null
+++ b/AParser/src/CronParser.cpp
@@ -0,0 +1,47 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #13 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include "CronParser.hpp"
+#include "Node.hpp"
+#include "DefsStructureParser.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+
+//#define DEBUG_CRON 1
+
+bool CronParser::doParse( const std::string& line, std::vector<std::string >& lineTokens )
+{
+ // cron 23:00 # run every day at 23:00
+ // cron 10:00 20:00 01:00 # run every hour between 10am and 8pm
+ // cron -w 0,1 10:00 # run every sunday and monday at 10am
+ // cron -d 10,11,12 12:00 # run 10th, 11th and 12th of each month at noon
+ // cron -m 1,2,3 12:00 # run on Jan,Feb and March every day at noon.
+ // cron -w 0 -m 5,6,7,8 10:00 20:00 01:00 # run every sunday, between May-Aug, every hour between 10am and 8pm
+ if ( lineTokens.size() < 2 ) throw std::runtime_error( "CronParser::doParse: Invalid cron: " + line );
+
+#ifdef DEBUG_CRON
+ cerr << "CronParser::doParse " << line << "\n";
+#endif
+
+ bool parse_state = (rootParser()->get_file_type() != PrintStyle::DEFS);
+
+ size_t index = 1; // to get over the cron
+ CronAttr cronAttr;
+ CronAttr::parse( cronAttr,lineTokens, index, parse_state);
+
+ nodeStack_top()->addCron( cronAttr );
+ return true;
+}
diff --git a/AParser/src/CronParser.hpp b/AParser/src/CronParser.hpp
new file mode 100644
index 0000000..4eee2f2
--- /dev/null
+++ b/AParser/src/CronParser.hpp
@@ -0,0 +1,30 @@
+#ifndef CRONPARSER_HPP_
+#define CRONPARSER_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "Parser.hpp"
+
+class CronParser : public Parser {
+public:
+ CronParser(DefsStructureParser* p) : Parser(p) {}
+ virtual const char* keyword() const { return "cron"; }
+ virtual bool doParse(const std::string& line,std::vector<std::string>& lineTokens);
+};
+
+#endif
+
+
diff --git a/AParser/src/DateParser.cpp b/AParser/src/DateParser.cpp
new file mode 100644
index 0000000..97fd9f4
--- /dev/null
+++ b/AParser/src/DateParser.cpp
@@ -0,0 +1,51 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #14 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <iostream>
+#include "DefsStructureParser.hpp"
+#include "DateParser.hpp"
+#include "Node.hpp"
+
+using namespace ecf;
+using namespace std;
+
+bool DateParser::doParse( const std::string& line,
+ std::vector<std::string >& lineTokens )
+{
+ // date 15.11.2009 # <value> // with PersistStyle::STATE & MIGRATE
+ // date 15.*.*
+ // date *.1.*
+ if ( lineTokens.size() < 2 ) {
+ throw std::runtime_error( "DateParser::doParse: Invalid date :" + line );
+ }
+
+ if ( nodeStack().empty() ) {
+ throw std::runtime_error("DateParser::doParse: Could not add date as node stack is empty at line: " + line );
+ }
+
+ // DateAttr::create can throw for invalid dates
+ DateAttr date = DateAttr::create( lineTokens[1]) ;
+
+ // state
+ if (lineTokens.size() == 4 && rootParser()->get_file_type() != PrintStyle::DEFS) {
+ if (lineTokens[3] == "free") {
+ date.setFree();
+ }
+ }
+
+ nodeStack_top()->addDate( date );
+
+ return true;
+}
diff --git a/AParser/src/DateParser.hpp b/AParser/src/DateParser.hpp
new file mode 100644
index 0000000..f039e6e
--- /dev/null
+++ b/AParser/src/DateParser.hpp
@@ -0,0 +1,28 @@
+#ifndef DATEPARSER_HPP_
+#define DATEPARSER_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "Parser.hpp"
+
+class DateParser : public Parser {
+public:
+ DateParser(DefsStructureParser* p) : Parser(p) {}
+ virtual const char* keyword() const { return "date"; }
+ virtual bool doParse(const std::string& /*line*/, std::vector<std::string>& lineTokens);
+};
+
+#endif
diff --git a/AParser/src/DayParser.cpp b/AParser/src/DayParser.cpp
new file mode 100644
index 0000000..1f9cd53
--- /dev/null
+++ b/AParser/src/DayParser.cpp
@@ -0,0 +1,46 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #11 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <stdexcept>
+#include "DayParser.hpp"
+#include "DefsStructureParser.hpp"
+#include "Node.hpp"
+
+using namespace std;
+
+bool DayParser::doParse( const std::string& line, std::vector<std::string >& lineTokens )
+{
+ // day monday # free
+ // day tuesday
+ if ( lineTokens.size() < 2 ) {
+ throw std::runtime_error( "DayParser::doParse: Invalid day :" + line );
+ }
+ if ( nodeStack().empty() ) {
+ throw std::runtime_error("DayParser::doParse: Could not add day as node stack is empty at line: " + line );
+ }
+
+ DayAttr day = DayAttr::create( lineTokens[1] );
+
+ // state
+ if (lineTokens.size() == 4 && rootParser()->get_file_type() != PrintStyle::DEFS) {
+ if (lineTokens[3] == "free") {
+ day.setFree();
+ }
+ }
+
+ nodeStack_top()->addDay( day );
+
+ return true;
+}
diff --git a/AParser/src/DayParser.hpp b/AParser/src/DayParser.hpp
new file mode 100644
index 0000000..211183c
--- /dev/null
+++ b/AParser/src/DayParser.hpp
@@ -0,0 +1,27 @@
+#ifndef DAYPARSER_HPP_
+#define DAYPARSER_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #8 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "Parser.hpp"
+
+class DayParser : public Parser {
+public:
+ DayParser(DefsStructureParser* p) : Parser(p) {}
+ virtual const char* keyword() const { return "day"; }
+ virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens);
+};
+#endif
diff --git a/AParser/src/DefsParser.cpp b/AParser/src/DefsParser.cpp
new file mode 100644
index 0000000..aafddce
--- /dev/null
+++ b/AParser/src/DefsParser.cpp
@@ -0,0 +1,425 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #47 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <sstream>
+#include <fstream>
+
+#include "DefsParser.hpp"
+#include "ExternParser.hpp"
+#include "AutoCancelParser.hpp"
+#include "RepeatParser.hpp"
+#include "ClockParser.hpp"
+#include "CalendarParser.hpp"
+#include "VariableParser.hpp"
+#include "InlimitParser.hpp"
+#include "LimitParser.hpp"
+#include "TimeParser.hpp"
+#include "TodayParser.hpp"
+#include "CronParser.hpp"
+#include "MeterParser.hpp"
+#include "DefsStatusParser.hpp"
+#include "EventParser.hpp"
+#include "LabelParser.hpp"
+#include "TriggerParser.hpp"
+#include "DefsStructureParser.hpp"
+#include "DateParser.hpp"
+#include "DayParser.hpp"
+#include "VerifyParser.hpp"
+#include "ZombieAttrParser.hpp"
+#include "LateParser.hpp"
+#include "DefsStateParser.hpp"
+#include "Stl.hpp"
+#include "Str.hpp"
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+
+#include <boost/token_functions.hpp>
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+
+//#define DEBUG_PARSER 1
+
+template<class T>
+ostream& operator<<(ostream& os, const vector<T>& v) {
+ copy(v.begin(), v.end(), ostream_iterator<T>(cout, ","));
+ return os;
+}
+
+
+class TextParser : public Parser {
+public:
+ TextParser(DefsStructureParser* p) : Parser(p) {}
+
+ virtual const char* keyword() const { return "text"; }
+
+ virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens) {
+#ifdef DEBUG
+ assert(*lineTokens.begin() == keyword());
+#endif
+ return true;
+ }
+};
+
+class AliasParser : public Parser {
+public:
+ AliasParser(DefsStructureParser* p, Parser* parentParser) : Parser(p) {
+ reserve_vec(19);
+ addParser( new VariableParser(p) );
+ addParser( new LabelParser(p) );
+ addParser( new MeterParser(p) );
+ addParser( new EventParser(p) );
+ addParser( new TriggerParser(p) );
+ addParser( new InlimitParser(p) );
+ addParser( new LateParser(p) );
+ addParser( new DefsStatusParser(p) );
+ addParser( new CompleteParser(p) );
+ addParser( new TimeParser(p) );
+ addParser( new RepeatParser(p) );
+ addParser( new TodayParser(p) );
+ addParser( new CronParser(p) );
+ addParser( new LimitParser(p) );
+ addParser( new DateParser(p) );
+ addParser( new DayParser(p) );
+ addParser( new AutoCancelParser(p) );
+ addParser( new VerifyParser(p) );
+ addParser( new ZombieAttrParser(p) );
+ }
+
+ virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens) {
+
+ const char* first_token = lineTokens[0].c_str();
+ if (Str::local_strcmp(first_token,keyword()) == 0) {
+
+ if (lineTokens.size() < 2) throw std::runtime_error("Alias name missing.");
+
+ addAlias(line,lineTokens);
+
+ return true;
+ }
+ else if (Str::local_strcmp(first_token,"endalias") == 0) { // required at the end
+ popNode();
+ return true;
+ }
+ return Parser::doParse(line,lineTokens);
+ }
+
+ virtual const char* keyword() const { return "alias"; }
+
+private:
+
+ void addAlias(const std::string& line,std::vector<std::string>& lineTokens) const
+ {
+ // bad test data can mean that last node is not a suite family or task, will fail parse
+ if (nodeStack().empty() ) throw std::runtime_error("Add alias failed empty node stack");
+
+ // alias can only be added to tasks
+ Task* lastAddedTask = nodeStack_top()->isTask();
+ if ( lastAddedTask ) {
+
+ alias_ptr alias = lastAddedTask->add_alias(lineTokens[1]);
+ alias->read_state(line,lineTokens);
+ nodeStack().push( std::make_pair(alias.get(),this) );
+ }
+ else {
+ if ( nodeStack_top()->isAlias() ) {
+
+ // Alias can _only_ be added to tasks pop the top Node to get to the task
+ popNode();
+ addAlias(line, lineTokens );
+ }
+ else throw std::runtime_error("Add alias failed, expected task on node stack");
+ }
+ }
+};
+
+//================================================================================
+
+class TaskParser : public Parser {
+public:
+ TaskParser(DefsStructureParser* p, Parser* parentParser) : Parser(p) {
+ reserve_vec(21);
+ addParser( new VariableParser(p) );
+ addParser( new TriggerParser(p) );
+ addParser( new LabelParser(p) );
+ addParser( new InlimitParser(p) );
+ addParser( new EventParser(p) );
+ addParser( new LateParser(p) );
+ addParser( new MeterParser(p) );
+ addParser( new DefsStatusParser(p) );
+ addParser( new CompleteParser(p) );
+ addParser( new TimeParser(p) );
+ addParser( new RepeatParser(p) );
+ addParser( new TodayParser(p) );
+ addParser( new CronParser(p) );
+ addParser( new LimitParser(p) );
+ addParser( new DateParser(p) );
+ addParser( new DayParser(p) );
+ addParser( new AutoCancelParser(p) );
+ addParser( new VerifyParser(p) );
+ addParser( new ZombieAttrParser(p) );
+ addParser( new AliasParser(p,this) );
+ addParser( new TextParser(p) );
+ }
+
+ virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens) {
+
+ const char* first_token = lineTokens[0].c_str();
+ if (Str::local_strcmp(first_token,keyword()) == 0) {
+
+ if (lineTokens.size() < 2) throw std::runtime_error("Task name missing.");
+
+ // end task is optional, so if we get another task, whilst in a task pop the parser
+ if ( nodeStack_top()->isTask()) {
+ popToContainerNode(); // pop the node stack
+ }
+
+ addTask(line,lineTokens);
+
+ return true;
+ }
+ else if (Str::local_strcmp(first_token,"endtask") == 0) { // optional
+ popToContainerNode();
+ return true;
+ }
+ return Parser::doParse(line,lineTokens);
+ }
+
+ virtual const char* keyword() const { return "task"; }
+
+private:
+
+ void addTask(const std::string& line,std::vector<std::string>& lineTokens) const
+ {
+ // bad test data can mean that last node is not a suite family or task, will fail parse
+ if (nodeStack().empty() ) throw std::runtime_error("Add task failed empty node stack");
+
+ NodeContainer* lastAddedContainer = nodeStack_top()->isNodeContainer();
+ if ( lastAddedContainer ) {
+
+ task_ptr task = Task::create(lineTokens[1]);
+ if (rootParser()->get_file_type() != PrintStyle::DEFS) task->read_state(line,lineTokens);
+ nodeStack().push( std::make_pair(task.get(),this) );
+ lastAddedContainer->addTask( task );
+ }
+ else {
+ if ( nodeStack_top()->isTask() ) {
+
+ // Task can _only_ be added to suite and families.
+ // pop the top Node to get to the Container(suite or family), then call recursively to add task
+ popNode();
+ addTask(line, lineTokens );
+ }
+ }
+ }
+};
+
+//================================================================================
+
+class FamilyParser : public Parser {
+public:
+ FamilyParser(DefsStructureParser* p) : Parser(p)
+ {
+ reserve_vec(21);
+ addParser( new VariableParser(p) );
+ addParser( new TaskParser(p,this) );
+ addParser( new TriggerParser(p) );
+ addParser( new InlimitParser(p) );
+ addParser( new DefsStatusParser(p) );
+ addParser( new LimitParser(p) );
+ addParser( new CompleteParser(p) );
+ addParser( new MeterParser(p) );
+ addParser( new TimeParser(p) );
+ addParser( new LabelParser(p) );
+ addParser( new RepeatParser(p) );
+ addParser( new LateParser(p) );
+ addParser( new EventParser(p) );
+ addParser( new TodayParser(p) );
+ addParser( new CronParser(p) );
+ addParser( new DateParser(p) );
+ addParser( new DayParser(p) );
+ addParser( new AutoCancelParser(p) );
+ addParser( new VerifyParser(p) );
+ addParser( new ZombieAttrParser(p) );
+ addParser( new TextParser(p) );
+ }
+
+ virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens) {
+
+ const char* first_token = lineTokens[0].c_str();
+ if (Str::local_strcmp(first_token,keyword()) == 0) {
+
+ if (lineTokens.size() < 2) throw std::runtime_error("Family name missing.");
+
+ addFamily(line,lineTokens);
+
+ return true;
+ }
+ else if (Str::local_strcmp(first_token,"endfamily") == 0) {
+
+ popFamily();
+ return true;
+ }
+ else if (Str::local_strcmp(first_token,"endtask") == 0) { // optional
+ popNode();
+ return true;
+ }
+ return Parser::doParse(line,lineTokens);
+ }
+
+ virtual const char* keyword() const { return "family"; }
+
+private:
+
+ void addFamily(const std::string& line,const std::vector<std::string>& lineTokens) const
+ {
+ assert( !nodeStack().empty() );
+ Suite* lastAddedSuite = nodeStack_top()->isSuite();
+ if (lastAddedSuite ) {
+
+ family_ptr family = Family::create(lineTokens[1]);
+ if (rootParser()->get_file_type() != PrintStyle::DEFS) family->read_state(line,lineTokens);
+
+ nodeStack().push( std::make_pair(family.get(),this) );
+ lastAddedSuite->addFamily( family );
+ }
+ else {
+ // support hierarchical families
+ Family* lastAddedFamily = nodeStack_top()->isFamily();
+ if ( lastAddedFamily ) {
+
+ family_ptr family = Family::create(lineTokens[1]);
+ if (rootParser()->get_file_type() != PrintStyle::DEFS) family->read_state(line,lineTokens);
+
+ nodeStack().push( std::make_pair(family.get(),this));
+ lastAddedFamily->addFamily( family );
+ }
+ else {
+ Task* lastAddedTask = nodeStack_top()->isTask();
+ if ( lastAddedTask ) {
+ // Pop the node, since tasks don't always have end task
+ popNode();
+ addFamily(line,lineTokens);
+ }
+ }
+ }
+ }
+
+ void popFamily() const
+ {
+ // Compensate for the fact that Task don't have endtask, hence when we pop for a
+ // family, the top should be a suite/family
+ if ( nodeStack_top()->isTask()) {
+ nodeStack().pop(); // pop the task
+ nodeStack().pop(); // pop the family to get to suite/family
+ }
+ else {
+ nodeStack().pop(); // pop the family to get to suite/family
+ }
+ }
+};
+
+//================================================================================
+
+// See ECFLOW-106, and SUP-1198, why we don't allow time,today,date,day ate the suite level.
+class SuiteParser : public Parser {
+public:
+ SuiteParser(DefsStructureParser* p) : Parser(p), started_(false)
+ {
+ reserve_vec(17);
+ addParser( new VariableParser(p) );
+ addParser( new FamilyParser(p) );
+ addParser( new TaskParser(p,this) );
+ addParser( new LimitParser(p) );
+ addParser( new DefsStatusParser(p) );
+ addParser( new ClockParser(p) );
+ addParser( new InlimitParser(p) );
+ addParser( new RepeatParser(p) );
+ addParser( new LateParser(p) );
+ addParser( new CronParser(p) );
+ addParser( new AutoCancelParser(p) );
+ addParser( new VerifyParser(p) );
+ addParser( new ZombieAttrParser(p) );
+ addParser( new EventParser(p) );
+ addParser( new LabelParser(p) );
+ addParser( new CalendarParser(p) );
+ addParser( new MeterParser(p) );
+ }
+
+ virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens) {
+
+ const char* first_token = lineTokens[0].c_str();
+ if (Str::local_strcmp(first_token,keyword()) == 0) {
+
+ if (started_) throw std::runtime_error("Can't have hierarchical suites.");
+ if (lineTokens.size() < 2) throw std::runtime_error("Suite name missing.");
+ started_ = true;
+
+ addSuite(line,lineTokens);
+
+ return true;
+ }
+ else if (Str::local_strcmp(first_token,"endsuite") == 0) {
+
+ if (!started_) {
+ throw std::runtime_error("Misplaced endsuite..");
+ }
+
+ // ... process end suite
+ while ( !nodeStack().empty() ) nodeStack().pop();
+ started_ = false; // since this parser is reused
+ return true;
+ }
+ return Parser::doParse(line,lineTokens);
+ }
+
+ virtual const char* keyword() const { return "suite"; }
+
+private:
+
+ void addSuite(const std::string& line,std::vector<std::string>& lineTokens) const {
+
+ if ( !nodeStack().empty() ) {
+ throw std::runtime_error("SuiteParser::addSuite node stack should be empty");
+ }
+
+ suite_ptr suite = Suite::create(lineTokens[1]);
+ if (rootParser()->get_file_type() != PrintStyle::DEFS) suite->read_state(line,lineTokens);
+
+ nodeStack().push( std::make_pair(suite.get(),this) );
+ defsfile()->addSuite( suite );
+ }
+
+ bool started_;
+};
+
+//================================================================================
+
+DefsParser::DefsParser(DefsStructureParser* p) : Parser(p)
+{
+ reserve_vec(5);
+ addParser( new ExternParser(p) );
+ addParser( new SuiteParser(p) );
+
+ // for defs stat only
+ addParser( new DefsStateParser(p) );
+ addParser( new VariableParser(p,true) );
+ addParser( new HistoryParser(p) );
+}
+
diff --git a/AParser/src/DefsParser.hpp b/AParser/src/DefsParser.hpp
new file mode 100644
index 0000000..42fcc96
--- /dev/null
+++ b/AParser/src/DefsParser.hpp
@@ -0,0 +1,27 @@
+#ifndef DEFSPARSER_HPP_
+#define DEFSPARSER_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "Parser.hpp"
+
+class DefsParser : public Parser {
+public:
+ DefsParser(DefsStructureParser* p);
+ virtual const char* keyword() const { return "DEFS" ;}
+};
+
+#endif
diff --git a/AParser/src/DefsStateParser.cpp b/AParser/src/DefsStateParser.cpp
new file mode 100644
index 0000000..80805a7
--- /dev/null
+++ b/AParser/src/DefsStateParser.cpp
@@ -0,0 +1,42 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "DefsStateParser.hpp"
+#include "Defs.hpp"
+#include "DefsStructureParser.hpp"
+
+using namespace std;
+using namespace boost;
+
+
+bool DefsStateParser::doParse( const std::string& line, std::vector<std::string >& lineTokens )
+{
+// cout << "line = " << line << "\n";
+ if ( lineTokens.size() < 2 ) throw std::runtime_error( "DefsStateParser::doParse Invalid defs_state " + line );
+
+ if (lineTokens[1] == PrintStyle::to_string(PrintStyle::STATE)) rootParser()->set_file_type( PrintStyle::STATE );
+ else if (lineTokens[1] == PrintStyle::to_string(PrintStyle::MIGRATE)) rootParser()->set_file_type( PrintStyle::MIGRATE );
+ else throw std::runtime_error( "DefsStateParser::doParse: file type not specified : " + line );
+
+ defsfile()->read_state(line,lineTokens); // this can throw
+ return true;
+}
+
+bool HistoryParser::doParse( const std::string& line, std::vector<std::string >& lineTokens )
+{
+// cout << "line = " << line << "\n";
+ defsfile()->read_history(line,lineTokens); // this can throw
+ return true;
+}
diff --git a/AParser/src/DefsStateParser.hpp b/AParser/src/DefsStateParser.hpp
new file mode 100644
index 0000000..1cd73dd
--- /dev/null
+++ b/AParser/src/DefsStateParser.hpp
@@ -0,0 +1,35 @@
+#ifndef DEFS_STATE_PARSER_HPP_
+#define DEFS_STATE_PARSER_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #9 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "Parser.hpp"
+
+class DefsStateParser : public Parser {
+public:
+ DefsStateParser(DefsStructureParser* p) : Parser(p){}
+ virtual bool doParse(const std::string& line,std::vector<std::string>& lineTokens);
+ virtual const char* keyword() const { return "defs_state"; }
+};
+
+class HistoryParser : public Parser {
+public:
+ HistoryParser(DefsStructureParser* p) : Parser(p){}
+ virtual bool doParse(const std::string& line,std::vector<std::string>& lineTokens);
+ virtual const char* keyword() const { return "history"; }
+};
+
+#endif
diff --git a/AParser/src/DefsStatusParser.cpp b/AParser/src/DefsStatusParser.cpp
new file mode 100644
index 0000000..b823a2f
--- /dev/null
+++ b/AParser/src/DefsStatusParser.cpp
@@ -0,0 +1,52 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #11 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <sstream>
+#include "DefsStatusParser.hpp"
+#include "DState.hpp"
+#include "Node.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+
+bool DefsStatusParser::doParse(
+ const std::string& line,
+ std::vector<std::string >& lineTokens )
+{
+ if ( lineTokens.size() < 2 ) throw std::runtime_error( "DefsStatusParser::doParse: Invalid defstatus :" + line );
+
+ if ( ! DState::isValid(lineTokens[1]) ) {
+ throw std::runtime_error( "DefsStatusParser::doParse: Invalid defstatus state :" + line );
+ }
+
+ if ( !nodeStack().empty() ) {
+ Node* node = nodeStack_top();
+
+ // Check default status not already defined for this node.
+ std::map< Node*, bool >::const_iterator it = defStatusMap().find( node );
+ if ( it != defStatusMap().end() ) {
+ if ( (*it).second ) {
+ std::stringstream ss;
+ ss << "DefsStatusParser::doParse: " << node->debugType() << " " << node->name() << " already has a default status\n";
+ throw std::runtime_error( ss.str() );
+ }
+ }
+ defStatusMap()[node] = true;
+ node->addDefStatus( DState::toState( lineTokens[1] ) );
+ }
+
+ return true;
+}
diff --git a/AParser/src/DefsStatusParser.hpp b/AParser/src/DefsStatusParser.hpp
new file mode 100644
index 0000000..ca42fae
--- /dev/null
+++ b/AParser/src/DefsStatusParser.hpp
@@ -0,0 +1,28 @@
+#ifndef DEFSSTATUSPARSER_HPP_
+#define DEFSSTATUSPARSER_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "Parser.hpp"
+
+class DefsStatusParser : public Parser {
+public:
+ DefsStatusParser(DefsStructureParser* p) : Parser(p) {}
+ virtual const char* keyword() const { return "defstatus"; }
+ virtual bool doParse(const std::string& line,std::vector<std::string>& lineTokens);
+};
+
+#endif /* DEFSSTATUSPARSER_HPP_ */
diff --git a/AParser/src/DefsStructureParser.cpp b/AParser/src/DefsStructureParser.cpp
new file mode 100644
index 0000000..bbef4cf
--- /dev/null
+++ b/AParser/src/DefsStructureParser.cpp
@@ -0,0 +1,220 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #26 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <sstream>
+
+#include <boost/algorithm/string/trim.hpp>
+#include <boost/tokenizer.hpp>
+#include <boost/token_functions.hpp>
+
+#include "DefsStructureParser.hpp"
+#include "DefsParser.hpp"
+#include "Defs.hpp"
+#include "Version.hpp"
+#include "Str.hpp"
+
+//#define DEBUG_PARSER 1
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+
+/////////////////////////////////////////////////////////////////////////////////////
+DefsStructureParser::DefsStructureParser(Defs* defsfile,const std::string& file_name)
+: defsfile_(defsfile),defsParser_(new DefsParser(this)),
+ infile_(file_name),
+ lineNumber_(0),
+ file_type_(PrintStyle::DEFS)
+{
+}
+
+DefsStructureParser::~DefsStructureParser()
+{
+#ifdef SHOW_PARSER_STATS
+ defsParser_->printStats();
+#endif
+}
+
+bool DefsStructureParser::doParse(std::string& errorMsg,std::string& warningMsg)
+{
+ if (!do_parse_only(errorMsg)) {
+ return false;
+ }
+
+ if (file_type_ == PrintStyle::MIGRATE) {
+ return true;
+ }
+
+ // Now parse the trigger/complete expressions and resolve in-limits
+ return defsfile_->check(errorMsg,warningMsg);
+}
+
+//#define DO_STATS 1
+bool DefsStructureParser::do_parse_only(std::string& errorMsg)
+{
+ if ( !infile_.ok() ) {
+ std::stringstream ss;
+ ss << "Unable to open file! " << infile_.file_name() << "\n\n";
+ ss << Version::description() << "\n";
+ errorMsg = ss.str();
+ return false;
+ }
+
+ std::vector< std::string > lineTokens; lineTokens.reserve(30); // derived from 3199.def & DO_STATS
+ string line; line.reserve(350); // derived from 3199.def & DO_STATS
+#ifdef DO_STATS
+ size_t max_line_size = 0; max_no_of_tokens = 0;
+#endif
+ while ( infile_.good() ) {
+
+ getNextLine( line ); // will increment lineNumer_
+#ifdef DO_STATS
+ max_line_size = std::max(max_line_size,line.size());
+#endif
+
+ lineTokens.clear(); // This is re-used, hence clear up front
+ Str::split(line, lineTokens);
+ if (lineTokens.empty()) continue; // ignore empty lines
+#ifdef DO_STATS
+ max_no_of_tokens = std::max(max_no_of_tokens,lineTokens.size());
+#endif
+
+ // Process each line, according to the parser which is on *top* of the stack
+ // If the *top* of the stack is empty use the DefsParser
+ Parser* theCurrentParser = (nodeStack_.empty()) ? defsParser_.get() : const_cast<Parser*>(nodeStack_.top().second) ;
+ if ( theCurrentParser == NULL ) {
+ std::stringstream ss;
+ ss << "No parser found: Could not parse '" << line << "' around line number " << lineNumber_ << "\n";
+ ss << Version::description() << "\n\n";
+ errorMsg = ss.str();
+ return false;
+ }
+
+ try {
+ // Note: if the chosen parser does not recognise first token then the parent parser has a go at parsing.
+ // If first token begins with '#' it is ignored
+ // cout << "DefsStructureParser::currentParser() = " << theCurrentParser->keyword() << "\n";
+ theCurrentParser->doParse(line,lineTokens);
+ }
+ catch ( std::exception& e) {
+ std::stringstream ss;
+ ss << e.what() << "\n";
+ ss << "Could not parse '" << line << "' around line number " << lineNumber_ << "\n";
+ ss << Version::description() << "\n\n";
+ errorMsg = ss.str();
+ return false;
+ }
+ }
+#ifdef DO_STATS
+ cout << "max line size = " << max_line_size << "\n";
+ cout << "max token size = " << max_no_of_tokens << "\n";
+#endif
+ return true;
+}
+
+void DefsStructureParser::getNextLine(std::string& line)
+{
+ // *ALL* the handling of multiple statements per line are handled in this function
+ // The presence of ';' signals multiple statements per line.
+ if (multi_statements_per_line_vec_.empty()) {
+ infile_.getline(line);
+ lineNumber_++;
+ if (file_type_ == PrintStyle::MIGRATE) {
+ // ignore multiline for migrate, *BECAUSE* *history* for group command uses ';'
+ return;
+ }
+
+
+ if (!line.empty()) {
+
+ // See if there are multi statements per line, ie task a; task b; task b # comment
+ if (line.find(';') != std::string::npos) {
+
+ // ignore lines which have ';' but start with a comment. i.e.
+ // # task a, task b
+ /// calling trim can be very expensive, hence avoid if possible
+ std::string::size_type first_non_space_char_pos = line.find_first_not_of(' ');
+ if (first_non_space_char_pos != std::string::npos && line[first_non_space_char_pos] == '#') {
+ // found leading_comment can ignore this line
+ return;
+ }
+
+
+ // Handle multiple statement with # comment at the end
+ // suite fred; task a; task b; endsuite # suite fred; task a; task b; endsuite
+ // Remove comment at the end, to avoid adding to list of tokens
+ std::string::size_type commentPos = line.find('#');
+ if ( commentPos != std::string::npos) line = line.substr(0,commentPos);
+
+ char_separator<char> sep(";");
+ typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+ tokenizer tokens(line, sep);
+ std::copy(tokens.begin(), tokens.end(), back_inserter(multi_statements_per_line_vec_));
+ assert( !multi_statements_per_line_vec_.empty());
+
+ if ( semiColonInEditVariable() ) {
+ // clear multi_statements_per_line_vec_ since we can't cope with ';' in variable value
+ // hence edit VAR1 'A;B'; edit VAR2 "b;C"
+ // will be treated as one variable and not two
+ // TODO need more sophisticated parsing
+ multi_statements_per_line_vec_.clear();
+ }
+ else {
+ line = *(multi_statements_per_line_vec_.begin());
+ multi_statements_per_line_vec_.erase( multi_statements_per_line_vec_.begin() );
+ }
+ }
+ }
+ }
+ else {
+ line = *(multi_statements_per_line_vec_.begin());
+ multi_statements_per_line_vec_.erase( multi_statements_per_line_vec_.begin() );
+ }
+
+#ifdef DEBUG_PARSER
+ Parser* theParser = currentParser();
+ if ( theParser == NULL) {
+ cout << lineNumber_ << ": '" << line
+ << "' parser( NULL ) node(";
+ }
+ else {
+ cout << lineNumber_ << ": '" << line
+ << "' parser(" << theParser->keyword() << ") ";
+ if (theParser->parent()) cout << " parent_parser(" << theParser->parent()->keyword() << ")";
+ cout << " node(";
+ }
+
+ if (!nodeStack_.empty())
+ cout << nodeStack_top()->debugType() << " : " << nodeStack_top()->name() << ")\n";
+ else
+ cout << "NULL)\n";
+#endif
+}
+
+bool DefsStructureParser::semiColonInEditVariable()
+{
+ if ( multi_statements_per_line_vec_[0].find("edit") != std::string::npos) {
+ // all statements must start with a edit, else we have a semi colon inside variable
+ // edit A fred; edit B bill # valid
+ // edit A 'fred;bill'; edit B 'bill;bill' # Can't cope with this, will be ONE variable !!!!
+ for(size_t i = 0; i < multi_statements_per_line_vec_.size(); i++) {
+ boost::algorithm::trim(multi_statements_per_line_vec_[i]);
+ if (multi_statements_per_line_vec_[i].find("edit") != 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
diff --git a/AParser/src/DefsStructureParser.hpp b/AParser/src/DefsStructureParser.hpp
new file mode 100644
index 0000000..94944bf
--- /dev/null
+++ b/AParser/src/DefsStructureParser.hpp
@@ -0,0 +1,79 @@
+#ifndef DEFS_STRUCTURE_PARSER_HPP_
+#define DEFS_STRUCTURE_PARSER_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #12 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <string>
+#include <stack>
+#include <map>
+#include <vector>
+#include <fstream>
+
+#include "boost/utility.hpp"
+#include "boost/scoped_ptr.hpp"
+
+#include "File_r.hpp"
+#include "PrintStyle.hpp"
+
+class Defs;
+class Node;
+class Parser;
+
+// This class is used to parse the DEFS file.
+class DefsStructureParser : private boost::noncopyable {
+public:
+
+ DefsStructureParser(Defs* defsfile, const std::string& file_name);
+ ~DefsStructureParser();
+
+ /// Parse the definition file, *AND* check expressions and limits
+ /// return true if parse and check are OK, false otherwise
+ /// if false is returned, and error message is also returned
+ bool doParse(std::string& errorMsg,std::string& warningMsg);
+
+ // The file can be of different styles:
+ // DEFS: This is the structure only (default)
+ // STATE: structure + state
+ // MIGRATE: structure + state (No checking, and no externs )
+ void set_file_type(PrintStyle::Type_t t) { file_type_ = t; }
+ PrintStyle::Type_t get_file_type() const { return file_type_; }
+
+protected: // allow test code access
+ bool do_parse_only(std::string& errorMsg);
+
+private:
+
+ std::stack< std::pair<Node*,const Parser*> > nodeStack_; // stack of nodes used in parsing
+ std::map<Node*,bool> defStatusMap_; // check for duplicates
+
+ Defs* defsfile_;
+ boost::scoped_ptr<Parser> defsParser_; // Child parsers will be deleted as well
+ friend class Parser;
+
+ ecf::File_r infile_;
+ int lineNumber_;
+
+ std::vector<std::string> multi_statements_per_line_vec_;
+ PrintStyle::Type_t file_type_;
+
+private:
+ // read in the next line form the defs file
+ void getNextLine(std::string& line);
+ bool semiColonInEditVariable();
+ friend class TriggerCompleteParser;
+};
+
+#endif
diff --git a/AParser/src/EventParser.cpp b/AParser/src/EventParser.cpp
new file mode 100644
index 0000000..f295e4a
--- /dev/null
+++ b/AParser/src/EventParser.cpp
@@ -0,0 +1,75 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #17 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <stdexcept>
+#include <boost/lexical_cast.hpp>
+#include "EventParser.hpp"
+#include "DefsStructureParser.hpp"
+#include "Str.hpp"
+#include "Node.hpp"
+
+using namespace std;
+using namespace ecf;
+
+bool EventParser::doParse( const std::string& line,
+ std::vector<std::string >& lineTokens )
+{
+ if ( lineTokens.size() < 2 ) throw std::runtime_error( "EventParser::doParse: Invalid event : " + line );
+
+ // Events added to suite/family can not be signaled by child command
+ // However alter/force should allow events to set/cleared on Family/suite
+ if ( nodeStack().empty() ) {
+ throw std::runtime_error("EventParser::doParse: Could not add event as node stack is empty at line: " + line );
+ }
+
+
+ // ===============================================================
+ // Don't use -1, to represent that no number was specified, as on
+ // AIX portable binary archive can't cope with this
+ // use std::numeric_limits<int>::max()
+ // THIS HAS TO BE THE SAME AS THE Event() constructor
+ // ================================================================
+ string name;
+ int number = std::numeric_limits<int>::max();
+
+ // Test for numeric, and then casting, is ****faster***** than relying on exception alone
+ if ( lineTokens[1].find_first_of( Str::NUMERIC() ) != std::string::npos ) {
+ try {
+ number = boost::lexical_cast< int >( lineTokens[1] );
+ if ( lineTokens.size() >= 3 && lineTokens[2][0] != '#' ) {
+ name = lineTokens[2];
+ }
+ }
+ catch ( boost::bad_lexical_cast& ) {
+ name = lineTokens[1];
+ }
+ }
+ else {
+ name = lineTokens[1];
+ }
+
+ Event event( number, name );
+
+ // state
+ if (rootParser()->get_file_type() != PrintStyle::DEFS) {
+ if (lineTokens[lineTokens.size()-1] == Event::SET()) {
+ event.set_value(true);
+ }
+ }
+
+ nodeStack_top()->addEvent( event ) ;
+
+ return true;
+}
diff --git a/AParser/src/EventParser.hpp b/AParser/src/EventParser.hpp
new file mode 100644
index 0000000..f4b568b
--- /dev/null
+++ b/AParser/src/EventParser.hpp
@@ -0,0 +1,28 @@
+#ifndef EVENTPARSER_HPP_
+#define EVENTPARSER_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #8 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "Parser.hpp"
+
+class EventParser : public Parser {
+public:
+ EventParser(DefsStructureParser* p) : Parser(p) {}
+ virtual const char* keyword() const { return "event"; }
+ virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens);
+};
+
+#endif
diff --git a/AParser/src/ExternParser.cpp b/AParser/src/ExternParser.cpp
new file mode 100644
index 0000000..f090deb
--- /dev/null
+++ b/AParser/src/ExternParser.cpp
@@ -0,0 +1,48 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "ExternParser.hpp"
+#include "Extract.hpp"
+#include "Defs.hpp"
+
+using namespace std;
+using namespace boost;
+
+bool ExternParser::doParse( const std::string& line,
+ std::vector<std::string >& lineTokens )
+{
+// cout << "line = " << line << "\n";
+ if ( lineTokens.size() < 2 )
+ throw std::runtime_error( "ExternParser::doParse Invalid extern " + line );
+
+ // Guard against
+ // extern # empty extern with a comment
+ // extern #empty extern with a comment
+ if (lineTokens[1][0] == '#') {
+ throw std::runtime_error( "ExternParser::doParse Invalid extern paths." + line );
+ }
+
+ // Expecting:
+ // extern <path>
+ // extern <path>:<attr>
+ // where attr is the name of [ event, meter, repeat, variable, generated variable ]
+ //
+ // We will not split it up:
+
+// cout << "add extern = '" << lineTokens[1] << "'\n";
+ defsfile()->add_extern( lineTokens[1]);
+
+ return true;
+}
diff --git a/AParser/src/ExternParser.hpp b/AParser/src/ExternParser.hpp
new file mode 100644
index 0000000..cfbe7a4
--- /dev/null
+++ b/AParser/src/ExternParser.hpp
@@ -0,0 +1,41 @@
+#ifndef EXTERNPARSER_HPP_
+#define EXTERNPARSER_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #9 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "Parser.hpp"
+//
+// Externs: will typically have a absolute path, however sometimes when
+// suite are generated incrementally relative paths can be added
+// extern a path = a
+// extern /a/b/c path = /a/b/c
+// extern a/b/c path = a/b/c
+// extern /a/b/c:YMD path = /a/b/c variable:YMD (i.e event, meter, variable, repeat, generated variable)
+//
+// Externs are not persisted, why ?:
+// o Externs are un-resolved references to node paths in trigger expressions and inlimits
+// These references could be dynamically generated.
+// o Saves on network bandwidth and checkpoint file size.
+// Hence externs are *ONLY* used on the client side.
+//
+class ExternParser : public Parser {
+public:
+ ExternParser(DefsStructureParser* p) : Parser(p) {}
+ virtual bool doParse(const std::string& line,std::vector<std::string>& lineTokens);
+ virtual const char* keyword() const { return "extern"; }
+};
+
+#endif
diff --git a/AParser/src/InlimitParser.cpp b/AParser/src/InlimitParser.cpp
new file mode 100644
index 0000000..d1c725a
--- /dev/null
+++ b/AParser/src/InlimitParser.cpp
@@ -0,0 +1,45 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "InlimitParser.hpp"
+#include "Extract.hpp"
+#include "Node.hpp"
+
+using namespace std;
+
+bool InlimitParser::doParse(
+ const std::string& line,
+ std::vector<std::string >& lineTokens )
+{
+ if ( lineTokens.size() < 2 )
+ throw std::runtime_error( "InlimitParser::doParse: Invalid inlimit :" + line );
+
+ string path;
+ string limitName;
+ if ( !Extract::pathAndName( lineTokens[1], path, limitName ) ) {
+ throw std::runtime_error( "InlimitParser::doParse: Invalid inlimit : " + line );
+ }
+
+ //extract priority, if third token is not a comment it must be a priority
+ int tokens = Extract::optionalInt( lineTokens, 2, 1, "Invalid in limit : " + line );
+
+ if ( !nodeStack().empty() ) {
+ Node* node = nodeStack_top();
+
+ // cerr << "limitName=" << limitName << " path=" << path << "\n";
+ node->addInLimit( InLimit( limitName, path, tokens ) ) ;
+ }
+ return true;
+}
diff --git a/AParser/src/InlimitParser.hpp b/AParser/src/InlimitParser.hpp
new file mode 100644
index 0000000..204979e
--- /dev/null
+++ b/AParser/src/InlimitParser.hpp
@@ -0,0 +1,28 @@
+#ifndef INLIMITPARSER_HPP_
+#define INLIMITPARSER_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "Parser.hpp"
+
+class InlimitParser : public Parser {
+public:
+ InlimitParser(DefsStructureParser* p) : Parser(p) {}
+ virtual const char* keyword() const { return "inlimit"; }
+ virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens) ;
+};
+
+#endif /* INLIMITPARSER_HPP_ */
diff --git a/AParser/src/LabelParser.cpp b/AParser/src/LabelParser.cpp
new file mode 100644
index 0000000..5b23074
--- /dev/null
+++ b/AParser/src/LabelParser.cpp
@@ -0,0 +1,35 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #14 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "LabelParser.hpp"
+#include "Node.hpp"
+#include "DefsStructureParser.hpp"
+
+using namespace std;
+using namespace ecf;
+
+bool LabelParser::doParse( const std::string& line,
+ std::vector<std::string >& lineTokens )
+{
+ if ( nodeStack().empty() ) {
+ throw std::runtime_error("LabelParser::doParse: Could not add label as node stack is empty at line: " + line );
+ }
+
+ Label label;
+ label.parse(line,lineTokens,rootParser()->get_file_type() != PrintStyle::DEFS);
+ nodeStack_top()->addLabel( label );
+
+ return true;
+}
diff --git a/AParser/src/LabelParser.hpp b/AParser/src/LabelParser.hpp
new file mode 100644
index 0000000..cb308d6
--- /dev/null
+++ b/AParser/src/LabelParser.hpp
@@ -0,0 +1,28 @@
+#ifndef LABELPARSER_HPP_
+#define LABELPARSER_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "Parser.hpp"
+
+class LabelParser : public Parser {
+public:
+ LabelParser(DefsStructureParser* p) : Parser(p) {}
+ virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens);
+ virtual const char* keyword() const { return "label"; }
+};
+
+#endif /* LABELPARSER_HPP_ */
diff --git a/AParser/src/LateParser.cpp b/AParser/src/LateParser.cpp
new file mode 100644
index 0000000..64d587b
--- /dev/null
+++ b/AParser/src/LateParser.cpp
@@ -0,0 +1,44 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #13 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "LateParser.hpp"
+#include "LateAttr.hpp"
+#include "DefsStructureParser.hpp"
+#include "Node.hpp"
+
+using namespace ecf;
+using namespace std;
+
+bool LateParser::doParse( const std::string& line, std::vector<std::string >& lineTokens )
+{
+ if ( lineTokens.size() < 3 ) throw std::runtime_error( "LateParser::doParse: Invalid late :" + line );
+
+ // late -s +00:15 -a 20:00 -c +02:00 #The option can be in any order
+ // 0 1 2 3 4 5 6 7 8 9 10 11 12 13
+ // late -s +00:15 -c +02:00 # not all options are needed
+ // 0 1 2 3 4 5
+
+ LateAttr lateAttr; // lateAttr.isNull() will return true;
+ size_t start_index = 1;
+ LateAttr::parse(lateAttr,line,lineTokens,start_index);
+
+ // state
+ if (rootParser()->get_file_type() != PrintStyle::DEFS && lineTokens[lineTokens.size()-1] == "late") {
+ lateAttr.setLate(true);
+ }
+
+ nodeStack_top()->addLate( lateAttr ) ;
+ return true;
+}
diff --git a/AParser/src/LateParser.hpp b/AParser/src/LateParser.hpp
new file mode 100644
index 0000000..918a245
--- /dev/null
+++ b/AParser/src/LateParser.hpp
@@ -0,0 +1,27 @@
+#ifndef LATEPARSER_HPP_
+#define LATEPARSER_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "Parser.hpp"
+
+class LateParser : public Parser {
+public:
+ LateParser(DefsStructureParser* p) : Parser(p) {}
+ virtual const char* keyword() const { return "late"; }
+ virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens);
+};
+#endif
diff --git a/AParser/src/LimitParser.cpp b/AParser/src/LimitParser.cpp
new file mode 100644
index 0000000..becd85c
--- /dev/null
+++ b/AParser/src/LimitParser.cpp
@@ -0,0 +1,64 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #11 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "LimitParser.hpp"
+#include "Extract.hpp"
+#include "Node.hpp"
+#include "DefsStructureParser.hpp"
+
+using namespace std;
+
+bool LimitParser::doParse(
+ const std::string& line,
+ std::vector<std::string >& lineTokens )
+{
+ // limit name the_limit # value path1 path2
+ if ( lineTokens.size() < 3 )
+ throw std::runtime_error( "LimitParser::doParse: Invalid limit " + line );
+
+ if ( nodeStack().empty() )
+ throw std::runtime_error("LimitParser::doParse: Could not add limit as node stack is empty at line: " + line );
+
+ int limitValue = Extract::theInt( lineTokens[2], "LimitParser::doParse: Invalid limit value: " + line );
+
+ Node* node = nodeStack_top();
+
+ if (rootParser()->get_file_type() != PrintStyle::DEFS) {
+ // state
+ int value = 0;
+ std::set<std::string> paths;
+ bool comment_fnd = false;
+ bool value_processed = false;
+ for(size_t i = 3; i < lineTokens.size(); i++) {
+ if (comment_fnd) {
+ if (!value_processed) {
+ value = Extract::theInt(lineTokens[i],"LimitParser::doParse: Could not extract limit value: " + lineTokens[i]);
+ value_processed = true;
+ }
+ else {
+ paths.insert(lineTokens[i]);
+ }
+ }
+ if (lineTokens[i] == "#") comment_fnd = true;
+ }
+
+ node->addLimit( Limit( lineTokens[1], limitValue, value, paths ) ) ;
+ }
+ else {
+ // structure
+ node->addLimit( Limit( lineTokens[1], limitValue ) ) ;
+ }
+ return true;
+}
diff --git a/AParser/src/LimitParser.hpp b/AParser/src/LimitParser.hpp
new file mode 100644
index 0000000..712fa82
--- /dev/null
+++ b/AParser/src/LimitParser.hpp
@@ -0,0 +1,28 @@
+#ifndef LIMITPARSER_HPP_
+#define LIMITPARSER_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "Parser.hpp"
+
+class LimitParser : public Parser {
+public:
+ LimitParser(DefsStructureParser* p) : Parser(p) {}
+ virtual const char* keyword() const { return "limit"; }
+ virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens);
+};
+
+#endif /* LIMITPARSER_HPP_ */
diff --git a/AParser/src/MeterParser.cpp b/AParser/src/MeterParser.cpp
new file mode 100644
index 0000000..c6bbafa
--- /dev/null
+++ b/AParser/src/MeterParser.cpp
@@ -0,0 +1,54 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #14 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include "MeterParser.hpp"
+#include "Extract.hpp"
+#include "Node.hpp"
+#include "DefsStructureParser.hpp"
+
+using namespace ecf;
+using namespace std;
+
+bool MeterParser::doParse( const std::string& line, std::vector<std::string >& lineTokens )
+{
+ // meter 0 100 100 # value
+ if ( lineTokens.size() < 4 )
+ throw std::runtime_error("MeterParser::doParse: Invalid meter :" + line );
+
+ if ( nodeStack().empty() ) {
+ throw std::runtime_error("MeterParser::doParse: Could not add meter as node stack is empty at line: " + line );
+ }
+
+ int min = Extract::theInt( lineTokens[2], "Invalid meter : " + line );
+ int max = Extract::theInt( lineTokens[3], "Invalid meter : " + line );
+ int colorChange = Extract::optionalInt( lineTokens, 4, 0, "Invalid meter : " + line );
+ Meter meter(lineTokens[1], min, max, colorChange );
+
+ // state
+ if (rootParser()->get_file_type() != PrintStyle::DEFS) {
+ bool comment_fnd = false;
+ for(size_t i = 2; i < lineTokens.size(); i++) {
+ if (comment_fnd) {
+ // token after comment is the value
+ int value = Extract::theInt(lineTokens[i],"MeterParser::doParse, could not extract meter value");
+ meter.set_value(value); // can throw if value not in range
+ }
+ if (lineTokens[i] == "#") comment_fnd = true;
+ }
+ }
+
+ nodeStack_top()->addMeter( meter ) ;
+
+ return true;
+}
diff --git a/AParser/src/MeterParser.hpp b/AParser/src/MeterParser.hpp
new file mode 100644
index 0000000..3b6f25d
--- /dev/null
+++ b/AParser/src/MeterParser.hpp
@@ -0,0 +1,28 @@
+#ifndef METERPARSER_HPP_
+#define METERPARSER_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "Parser.hpp"
+
+class MeterParser : public Parser {
+public:
+ MeterParser(DefsStructureParser* p) : Parser(p) {}
+ virtual const char* keyword() const { return "meter"; }
+ virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens);
+};
+
+#endif /* METERPARSER_HPP_ */
diff --git a/AParser/src/Parser.cpp b/AParser/src/Parser.cpp
new file mode 100644
index 0000000..1c28685
--- /dev/null
+++ b/AParser/src/Parser.cpp
@@ -0,0 +1,167 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #34 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <sstream>
+#include <fstream>
+#include <boost/foreach.hpp>
+
+#include "Parser.hpp"
+#include "DefsStructureParser.hpp"
+#include "Stl.hpp"
+#include "Str.hpp"
+#include "Indentor.hpp"
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+using namespace boost::gregorian;
+
+//#define DEBUG_PARSER 1
+
+template<class T>
+ostream& operator<<(ostream& os, const vector<T>& v) {
+ copy(v.begin(), v.end(), ostream_iterator<T>(cout, ","));
+ return os;
+}
+
+
+
+// ===============================================================================
+
+Parser::Parser( DefsStructureParser* p )
+: parent_(NULL),
+ rootParser_( p )
+#ifdef SHOW_PARSER_STATS
+ ,parserCount_(0)
+#endif
+{}
+
+Parser::~Parser() {
+ DeletePtrs( expectedParsers_ );
+}
+
+bool Parser::doParse(const std::string& line, std::vector<std::string>& lineTokens)
+{
+ const char *first_token = lineTokens[0].c_str();
+ size_t theSize = expectedParsers_.size();
+ for(size_t i = 0; i < theSize; ++i) {
+ Parser* p = expectedParsers_[i];
+
+ if (Str::local_strcmp(first_token,p->keyword()) == 0) {
+
+#ifdef SHOW_PARSER_STATS
+ p->incrementParserCount(); // used for stats
+#endif
+
+ return p->doParse(line,lineTokens);
+ }
+ }
+
+#ifdef DEBUG_PARSER
+ cerr << "Parser::" << keyword() << " token = '" << *lineTokens.begin() << "' did not match parsers(";
+ BOOST_FOREACH(Parser* p, expectedParsers_) { cerr << " " << p->keyword() ; }
+ cerr << ") Trying parent ";
+ if (parent()) cout << "Parser::" << parent()->keyword();
+ cerr << "\n";
+#endif
+
+ // Parent should handle "endfamily", "family" and "endsuite" for hierarchical families
+ if (parent() && ((Str::local_strcmp(first_token,"endfamily") == 0) ||
+ (Str::local_strcmp(first_token,"family") == 0) ||
+ (Str::local_strcmp(first_token,"endsuite") == 0))) {
+ return parent()->doParse(line,lineTokens);
+ }
+
+ // Check if first token is '#' comment character
+ // very first non space character is # comment, hence ignore this line
+ if (*first_token == '#') {
+ // std::cout << "Ignoring line with leading comment : " << line << "\n";
+ return true;
+ }
+
+ // Does not match any parser, or leading comment
+ std::string errorMsg = "Unexpected keyword ";
+ errorMsg += *lineTokens.begin();
+ errorMsg += " found whilst parsing ";
+ errorMsg += keyword();
+ if ( !nodeStack().empty() ) {
+ errorMsg += " ";
+ errorMsg += nodeStack_top()->name();
+ }
+ throw std::runtime_error( errorMsg );
+ return false;
+}
+
+
+Defs* Parser::defsfile() const { return rootParser_->defsfile_ ;}
+std::stack< std::pair<Node*,const Parser*> >& Parser::nodeStack() const { return rootParser_->nodeStack_;}
+Node* Parser::nodeStack_top() const { return rootParser_->nodeStack_.top().first;}
+std::map<Node*,bool>& Parser::defStatusMap() const { return rootParser_->defStatusMap_; }
+
+void Parser::dumpStackTop(const std::string& msg, const std::string& msg2) const
+{
+ std::cout << msg << " '" << msg2 << "' ++++++++++++++++++++++++++++++++++++++++++++++++++\n";
+ if (rootParser_->nodeStack_.empty()) std::cout << "nodeStack_ is EMPTY\n";
+ else std::cout << "TOP = " << rootParser_->nodeStack_.top().first->debugType()
+ << " '" << rootParser_->nodeStack_.top().first->name() << "'\n";
+}
+
+void Parser::addParser(Parser* p)
+{
+ p->parent(this);
+ expectedParsers_.push_back(p);
+}
+
+void Parser::popNode() const { nodeStack().pop();}
+
+
+void Parser::popToContainerNode() const
+{
+ while ( !nodeStack().empty() && !nodeStack_top()->isNodeContainer() ) {
+ nodeStack().pop(); // keep poping till we get to family or suite
+ }
+}
+
+void Parser::dump(const std::vector<std::string>& lineTokens)
+{
+ cout << "tokens:";
+ for(unsigned i=0; i < lineTokens.size(); i++) {
+ cout << " '" << lineTokens[i] << "' ";
+ }
+ cout << "\n";
+}
+
+
+#ifdef SHOW_PARSER_STATS
+void Parser::printStats()
+{
+ Indentor::indent( std::cout ) << "Parser::" << keyword() << "\n";
+ BOOST_FOREACH(Parser* p, expectedParsers_) {
+ Indentor::indent( std::cout ) << p->keyword() << " " << p->parserCount() << "\n";
+ }
+
+ Indentor in;
+ BOOST_FOREACH(Parser* p, expectedParsers_) {
+ if (p->hasChildren()) {
+ p->printStats();
+ }
+ }
+}
+#endif
+
diff --git a/AParser/src/Parser.hpp b/AParser/src/Parser.hpp
new file mode 100644
index 0000000..541a1a1
--- /dev/null
+++ b/AParser/src/Parser.hpp
@@ -0,0 +1,80 @@
+#ifndef PARSER_HPP_
+#define PARSER_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #23 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <string>
+#include <vector>
+#include <stack>
+#include <map>
+
+class DefsStructureParser;
+class Node;
+class Defs;
+
+//#define SHOW_PARSER_STATS 1
+
+class Parser {
+public:
+ Parser(DefsStructureParser* p);
+ virtual ~Parser();
+
+ // if child does not recognise token try the parent
+ virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens);
+ Parser* parent() const { return parent_;}
+ void parent(Parser* p) { parent_ = p;}
+
+ virtual const char* keyword() const = 0;
+
+ DefsStructureParser* rootParser() const { return rootParser_;}
+
+ // convenience function that access DefsStructureParser
+ std::stack< std::pair<Node*,const Parser*> >& nodeStack() const;
+ Node* nodeStack_top() const;
+ std::map<Node*,bool >& defStatusMap() const;
+
+#ifdef SHOW_PARSER_STATS
+ // The following function used in parser stats only
+ void printStats();
+#endif
+
+protected:
+
+ Defs* defsfile() const;
+ void dumpStackTop(const std::string& msg, const std::string& msg2 = "") const;
+ void addParser(Parser* p);
+ void popNode() const;
+ void popToContainerNode() const;
+ static void dump(const std::vector<std::string>& lineTokens);
+ void reserve_vec(int res) { expectedParsers_.reserve(res); }
+
+private:
+
+ bool hasChildren() const { return !expectedParsers_.empty();}
+
+ Parser* parent_;
+ DefsStructureParser* rootParser_;
+ std::vector<Parser*> expectedParsers_;
+
+#ifdef SHOW_PARSER_STATS
+ // The following function used in parser stats only
+ void incrementParserCount() { parserCount_++;}
+ int parserCount() const { return parserCount_;}
+ int parserCount_;
+#endif
+};
+
+#endif
diff --git a/AParser/src/RepeatParser.cpp b/AParser/src/RepeatParser.cpp
new file mode 100644
index 0000000..cb8e519
--- /dev/null
+++ b/AParser/src/RepeatParser.cpp
@@ -0,0 +1,178 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #31 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "RepeatParser.hpp"
+#include "Extract.hpp"
+#include "Str.hpp"
+#include "Node.hpp"
+#include "DefsStructureParser.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+
+
+bool RepeatParser::doParse( const std::string& line,
+ std::vector<std::string >& lineTokens )
+{
+ size_t line_token_size = lineTokens.size();
+ if ( line_token_size < 3 ) throw std::runtime_error( "RepeatParser::doParse: Invalid repeat " + line );
+ if ( nodeStack().empty() ) throw std::runtime_error("RepeatParser::doParse: Could not add repeat as node stack is empty at line: " + line );
+
+ string errorMsg = "Invalid repeat : ";
+ errorMsg += line;
+
+ if ( lineTokens[1] == "date" ) {
+ // repeat date VARIABLE yyyymmdd yyyymmdd [delta]
+ if ( line_token_size < 5 ) throw std::runtime_error( errorMsg );
+
+ string name = lineTokens[2];
+ int startYMD = Extract::ymd( lineTokens[3], errorMsg );
+ int endYMD = Extract::ymd( lineTokens[4], errorMsg );
+ int delta = Extract::optionalInt( lineTokens, 5, 1, errorMsg );
+ RepeatDate rep( name, startYMD, endYMD, delta );
+ int value = 0;
+ if (get_value(lineTokens,value)) rep.set_value(value);
+
+ nodeStack_top()->addRepeat( Repeat( rep ) ) ;
+ }
+ else if ( lineTokens[1] == "enumerated" ) {
+
+ if ( line_token_size < 4 ) throw std::runtime_error( errorMsg );
+
+ // repeat enumerated VARIABLE "first" "second" "last" # comment
+ string name = lineTokens[2];
+ std::vector<std::string> theEnums; theEnums.reserve(line_token_size);
+ for(size_t i = 3; i < line_token_size; i++) {
+ std::string theEnum = lineTokens[i];
+ if (theEnum[0] == '#') break;
+ Str::removeSingleQuotes(theEnum);// remove quotes, they get added back when we persist
+ Str::removeQuotes(theEnum); // remove quotes, they get added back when we persist
+ theEnums.push_back(theEnum);
+ }
+ if ( theEnums.empty() ) throw std::runtime_error( errorMsg );
+
+ RepeatEnumerated rep( name, theEnums) ;
+ int index = 0; // This is *assumed to be the index* and not the value
+ if (get_value(lineTokens,index)) rep.set_value(index);
+
+ nodeStack_top()->addRepeat( Repeat( rep ) ) ;
+ }
+ else if ( lineTokens[1] == "integer" ) {
+ // repeat integer VARIABLE start end [step]
+ if ( line_token_size < 5 ) throw std::runtime_error( errorMsg );
+
+ string name = lineTokens[2];
+ int start = Extract::theInt(lineTokens[3],errorMsg);
+ int end = Extract::theInt(lineTokens[4],errorMsg);
+ int step = Extract::optionalInt(lineTokens,5, 1,errorMsg );
+ RepeatInteger rep( name, start, end, step );
+ int value = 0;
+ if (get_value(lineTokens,value)) rep.set_value(value);
+
+ nodeStack_top()->addRepeat( Repeat( rep ) ) ;
+ }
+ else if ( lineTokens[1] == "day" ) {
+ // repeat day step [ yyyymmdd ] # the step can be positive or negative
+ // *** See RepeatAttr.h ***
+ // *** We will not support end date until there is a clear requirement for this
+ int step = Extract::theInt(lineTokens[2],"Invalid repeat day:");
+
+ // report end date as a parser error
+ if ( line_token_size >= 4 && lineTokens[3][0] != '#') {
+ throw std::runtime_error( "RepeatParser::doParse: repeat day, <end-date> not supported: " + line );
+ }
+ // day has no state
+ nodeStack_top()->addRepeat( Repeat( RepeatDay( step ) ) ) ;
+ }
+ else if ( lineTokens[1] == "string" ) {
+
+ if ( line_token_size < 4 ) throw std::runtime_error( errorMsg );
+
+ string name = lineTokens[2];
+ std::vector<std::string> theEnums; theEnums.reserve(line_token_size);
+ for(size_t i = 3; i < line_token_size; i++) {
+ std::string theEnum = lineTokens[i];
+ if (theEnum[0] == '#') break;
+ Str::removeSingleQuotes(theEnum);// remove quotes, they get added back when we persist
+ Str::removeQuotes(theEnum); // remove quotes, they get added back when we persist
+ theEnums.push_back(theEnum);
+ }
+ if ( theEnums.empty() ) throw std::runtime_error( errorMsg );
+
+ RepeatString rep( name, theEnums) ;
+ int index = 0;
+ if (get_value(lineTokens,index)) rep.set_value(index);
+
+ nodeStack_top()->addRepeat( Repeat( rep ) ) ;
+ }
+ else if ( lineTokens[1] == "month" ) {
+ // repeat month step [ yyyymmdd ] # the step can be positive or negative
+ throw std::runtime_error( "RepeatParser::doParse: repeat month not supported: " + line );
+
+// int endDate = 0;
+// int step = 0;
+// extractDayMonthYear( lineTokens, step, endDate );
+// nodeStack_top()->addRepeat( Repeat( RepeatMonth( step, endDate ) ) );
+ }
+ else if ( lineTokens[1] == "year" ) {
+ // repeat year step [ yyyymmdd ] # the step can be positive or negative
+ throw std::runtime_error( "RepeatParser::doParse: repeat year not supported: " + line );
+// int endDate = 0;
+// int step = 0;
+// extractDayMonthYear( lineTokens, step, endDate );
+// nodeStack_top()->addRepeat( Repeat( RepeatYear( step, endDate ) ) );
+ }
+ else if ( lineTokens[1] == "file" ) {
+ // NOT SUPPORTED
+ }
+ else {
+ throw std::runtime_error( "RepeatParser::doParse: Invalid repeat " + line );
+ }
+ return true;
+}
+
+//void RepeatParser::extractDayMonthYear( const std::vector< std::string >& lineTokens,
+// int& x,
+// int& endDate )
+//{
+// x = Extract::theInt( lineTokens[2], "invalid repeat" );
+// if ( lineTokens.size() >= 4 && lineTokens[3][0] != '#') {
+// std::string errorMsg = "Invalid repeat";
+// endDate = Extract::ymd( lineTokens[3], errorMsg );
+// }
+// if ( ! nodeStack_top()->isSuite() ) {
+// throw std::runtime_error( "RepeatParser::doParse: Invalid repeat day/month/year only valid for suite " );
+// }
+//}
+
+bool RepeatParser::get_value(const std::vector< std::string >& lineTokens, int& value) const
+{
+ // state
+ if (rootParser()->get_file_type() != PrintStyle::DEFS) {
+ // search back for comment
+ // repeat integer VARIABLE start end [step] # value
+ std::string token_after_comment;
+ for(size_t i = lineTokens.size()-1; i > 3; i--) {
+ if (lineTokens[i] == "#") {
+ // token after comment is the value
+ value = Extract::theInt(token_after_comment,"RepeatParser::doParse, could not extract repeat value");
+ return true;
+ }
+ else token_after_comment = lineTokens[i];
+ }
+ }
+ return false;
+}
diff --git a/AParser/src/RepeatParser.hpp b/AParser/src/RepeatParser.hpp
new file mode 100644
index 0000000..1451139
--- /dev/null
+++ b/AParser/src/RepeatParser.hpp
@@ -0,0 +1,33 @@
+#ifndef REPEATPARSER_HPP_
+#define REPEATPARSER_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #8 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "Parser.hpp"
+
+class RepeatParser : public Parser {
+public:
+ RepeatParser(DefsStructureParser* p) : Parser(p) {}
+
+ virtual const char* keyword() const { return "repeat"; }
+ virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens);
+
+private:
+// void extractDayMonthYear(const std::vector<std::string>& lineTokens,int& x, int& endDate);
+ bool get_value(const std::vector< std::string >& lineTokens, int& value) const;
+};
+
+#endif
diff --git a/AParser/src/TimeParser.cpp b/AParser/src/TimeParser.cpp
new file mode 100644
index 0000000..9f5a4c0
--- /dev/null
+++ b/AParser/src/TimeParser.cpp
@@ -0,0 +1,48 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #17 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "TimeParser.hpp"
+#include "TimeSeries.hpp"
+#include "Node.hpp"
+#include "DefsStructureParser.hpp"
+
+
+using namespace ecf;
+using namespace std;
+
+bool TimeParser::doParse( const std::string& line, std::vector<std::string >& lineTokens )
+{
+ if ( lineTokens.size() < 2 )
+ throw std::runtime_error( "TimeParser::doParse: Invalid time :" + line );
+
+ bool parse_state = false;
+ bool isFree = false;
+ if (rootParser()->get_file_type() != PrintStyle::DEFS) {
+ parse_state = true;
+ bool comment_fnd = false;
+ for(size_t i = 2; i < lineTokens.size(); i++) {
+ if (comment_fnd && lineTokens[i] == "free") isFree = true;
+ if (lineTokens[i] == "#") comment_fnd = true;
+ }
+ }
+
+ size_t index = 1;
+ TimeAttr attr( TimeSeries::create(index,lineTokens,parse_state) );
+ if (isFree) attr.setFree();
+
+ nodeStack_top()->addTime( attr );
+ return true;
+}
+
diff --git a/AParser/src/TimeParser.hpp b/AParser/src/TimeParser.hpp
new file mode 100644
index 0000000..769e371
--- /dev/null
+++ b/AParser/src/TimeParser.hpp
@@ -0,0 +1,28 @@
+#ifndef TIMEPARSER_HPP_
+#define TIMEPARSER_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "Parser.hpp"
+
+class TimeParser : public Parser {
+public:
+ TimeParser(DefsStructureParser* p) : Parser(p) {}
+ virtual const char* keyword() const { return "time"; }
+ virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens);
+};
+
+#endif /* TIMEPARSER_HPP_ */
diff --git a/AParser/src/TodayParser.cpp b/AParser/src/TodayParser.cpp
new file mode 100644
index 0000000..5e0af4a
--- /dev/null
+++ b/AParser/src/TodayParser.cpp
@@ -0,0 +1,45 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #13 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "TodayParser.hpp"
+#include "TodayAttr.hpp"
+#include "Node.hpp"
+#include "DefsStructureParser.hpp"
+
+using namespace ecf;
+using namespace std;
+
+bool TodayParser::doParse( const std::string& line, std::vector<std::string >& lineTokens )
+{
+ if ( lineTokens.size() < 2 ) throw std::runtime_error( "TodayParser::doParse: Invalid today :" + line );
+
+ bool parse_state = false;
+ bool isFree = false;
+ if (rootParser()->get_file_type() != PrintStyle::DEFS) {
+ parse_state = true;
+ bool comment_fnd = false;
+ for(size_t i = 2; i < lineTokens.size(); i++) {
+ if (comment_fnd && lineTokens[i] == "free") isFree = true;
+ if (lineTokens[i] == "#") comment_fnd = true;
+ }
+ }
+
+ size_t index = 1;
+ TodayAttr attr( TimeSeries::create(index,lineTokens,parse_state) );
+ if (isFree) attr.setFree();
+
+ nodeStack_top()->addToday( attr );
+ return true;
+}
diff --git a/AParser/src/TodayParser.hpp b/AParser/src/TodayParser.hpp
new file mode 100644
index 0000000..6f97171
--- /dev/null
+++ b/AParser/src/TodayParser.hpp
@@ -0,0 +1,28 @@
+#ifndef TODAYPARSER_HPP_
+#define TODAYPARSER_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "Parser.hpp"
+
+class TodayParser : public Parser {
+public:
+ TodayParser(DefsStructureParser* p) : Parser(p) {}
+ virtual const char* keyword() const { return "today"; }
+ virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens);
+};
+
+#endif
diff --git a/AParser/src/TriggerParser.cpp b/AParser/src/TriggerParser.cpp
new file mode 100644
index 0000000..d17c93f
--- /dev/null
+++ b/AParser/src/TriggerParser.cpp
@@ -0,0 +1,180 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #17 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <stdexcept>
+#include <sstream>
+
+#include "TriggerParser.hpp"
+#include "Str.hpp"
+#include "DefsStructureParser.hpp"
+#include "Node.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+
+
+static bool hasExtension( const std::string& line, const std::vector< std::string >& lineTokens )
+{
+ // cout << "hasExtension = ";
+ if ( line[line.size() - 1] == '\\' ) {
+ // cout << "true\n";
+ return true;
+ }
+ const std::string& lastToken = lineTokens.back();
+ if ( lastToken == "\\" || lastToken[lastToken.size() - 1] == '\\' ) {
+ // cout << "true\n";
+ return true;
+ }
+ // cout << "false\n";
+ return false;
+}
+
+// ===============================================================================
+
+void TriggerCompleteParser::getExpression(
+ const std::string& line,
+ std::vector< std::string >& theLineTokens,
+ std::string& expression,
+ bool& andExp,
+ bool& orExp,
+ bool& isFree) const
+{
+ assert( *theLineTokens.begin() == keyword() );
+ if ( theLineTokens.size() < 2 ) throw std::runtime_error( "Invalid " + std::string(keyword()) + " " + line );
+
+ // trigger -a n == complete
+ // complete -o n == complete
+ if (theLineTokens[1] == "-a") {
+ andExp = true;
+ theLineTokens.erase(theLineTokens.begin() + 1);
+ }
+ else if (theLineTokens[1] == "-o") {
+ orExp = true;
+ theLineTokens.erase(theLineTokens.begin() + 1);
+ }
+
+
+ // Handle continuations, by removing them and adding to expression
+ if ( hasExtension( line, theLineTokens ) ) {
+ /*
+ trigger a == complete and /
+ b == complete
+ */
+ std::vector< std::string > accumalatedTokens = theLineTokens;
+ while ( true ) {
+
+ std::string line2;
+ rootParser()->getNextLine( line2 );
+
+ std::vector< std::string > lineTokens2;
+ Str::split( line2, lineTokens2 );
+
+ std::copy( lineTokens2.begin(), lineTokens2.end(),
+ std::back_inserter( accumalatedTokens ) );
+
+ if ( !hasExtension( line2, lineTokens2 ) ) {
+ break;
+ }
+
+ if ( accumalatedTokens.back() == "\\" ) { // remove continuation
+ accumalatedTokens.pop_back();
+ }
+ }
+
+ size_t accumalated_tokens_size = accumalatedTokens.size();
+ for (size_t i = 1; i < accumalated_tokens_size; i++) {
+ std::string token = accumalatedTokens[i];
+ if ( token[token.size() - 1] == '\\' ) {
+ token.erase( token.begin() + token.size() - 1 );
+ }
+ if ( token.empty() )
+ continue;
+ if ( token.at( 0 ) == '#' )
+ break;
+ if ( i != 1 )
+ expression += " ";
+ expression += token;
+ }
+ }
+ else {
+
+ // lineTokens[0] == "trigger";/ "complete"
+ size_t line_token_size = theLineTokens.size();
+ expression.reserve(line.size());
+ for (size_t i = 1; i < line_token_size; i++) {
+ if ( theLineTokens[i].at( 0 ) == '#' ) break;
+ if ( i != 1 ) expression += " ";
+ expression += theLineTokens[i];
+ }
+
+ // state
+ if (rootParser()->get_file_type() != PrintStyle::DEFS) {
+ bool comment_fnd = false;
+ for(size_t i = 3; i < line_token_size; i++) {
+ if (comment_fnd) {
+ if (theLineTokens[i] == "free") {
+ isFree = true;
+ break;
+ }
+ }
+ if (theLineTokens[i] == "#") comment_fnd = true;
+ }
+ }
+ }
+
+// cout << "expression = '" << expression << "'\n";
+ if ( expression.empty() ) throw std::runtime_error( "Invalid trigger " + line );
+}
+
+
+bool TriggerParser::doParse( const std::string& line, std::vector<std::string >& lineTokens )
+{
+ bool andExp = false;
+ bool orExp = false;
+ bool isFree = false;
+ std::string expression;
+ getExpression( line, lineTokens, expression, andExp , orExp, isFree);
+
+ if ( !nodeStack().empty() ) {
+ Node* node = nodeStack_top();
+ if (!andExp && !orExp) node->add_part_trigger( PartExpression( expression )) ;
+ else if (andExp) node->add_part_trigger( PartExpression( expression, true)) ;
+ else if (orExp) node->add_part_trigger( PartExpression( expression, false)) ;
+ else throw std::runtime_error( "Invalid trigger " + line );
+ if (isFree) node->freeTrigger();
+ }
+
+ return true;
+}
+
+bool CompleteParser::doParse( const std::string& line, std::vector<std::string >& lineTokens )
+{
+ bool andExp = false;
+ bool orExp = false;
+ bool isFree = false;
+ std::string expression;
+ getExpression( line, lineTokens, expression, andExp , orExp, isFree);
+
+ if ( !nodeStack().empty() ) {
+ Node* node = nodeStack_top();
+ if (!andExp && !orExp) node->add_part_complete( PartExpression( expression )) ;
+ else if (andExp) node->add_part_complete( PartExpression( expression, true)) ;
+ else if (orExp) node->add_part_complete( PartExpression( expression, false)) ;
+ else throw std::runtime_error( "Invalid complete trigger " + line );
+ if (isFree) node->freeComplete();
+ }
+ return true;
+}
diff --git a/AParser/src/TriggerParser.hpp b/AParser/src/TriggerParser.hpp
new file mode 100644
index 0000000..cddd911
--- /dev/null
+++ b/AParser/src/TriggerParser.hpp
@@ -0,0 +1,46 @@
+#ifndef TRIGGERPARSER_HPP_
+#define TRIGGERPARSER_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #8 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "Parser.hpp"
+
+class TriggerCompleteParser : public Parser {
+protected:
+ TriggerCompleteParser(DefsStructureParser* p) : Parser(p) {}
+ void getExpression(const std::string& line,
+ std::vector<std::string>& lineTokens,
+ std::string& expression,
+ bool& andExr,
+ bool& orExpr,
+ bool& isFree) const;
+};
+
+class TriggerParser : public TriggerCompleteParser {
+public:
+ TriggerParser(DefsStructureParser* p) : TriggerCompleteParser(p) {}
+ virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens);
+ virtual const char* keyword() const { return "trigger"; }
+};
+
+class CompleteParser : public TriggerCompleteParser {
+public:
+ CompleteParser(DefsStructureParser* p) : TriggerCompleteParser(p) {}
+ virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens) ;
+ virtual const char* keyword() const { return "complete"; }
+};
+
+#endif
diff --git a/AParser/src/VariableParser.cpp b/AParser/src/VariableParser.cpp
new file mode 100644
index 0000000..912ddb1
--- /dev/null
+++ b/AParser/src/VariableParser.cpp
@@ -0,0 +1,103 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #23 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "VariableParser.hpp"
+#include "Node.hpp"
+#include "Str.hpp"
+#include "Defs.hpp"
+
+using namespace ecf;
+using namespace std;
+
+bool VariableParser::doParse(
+ const std::string& line,
+ std::vector<std::string >& lineTokens )
+{
+ // Note: For migrate the defs can have variables
+ Node* node = NULL;
+ if ( nodeStack().empty()) {
+ if (!parsing_defs_) throw std::runtime_error("VariableParser::doParse: Could not add variable, as node stack is empty at line: " + line );
+ }
+ else node = nodeStack_top();
+
+ size_t line_tokens_size = lineTokens.size();
+ if ( line_tokens_size < 3 ) {
+ std::stringstream ss;
+ ss << "VariableParser::doParse: expected at least 3 tokens, found " << line_tokens_size << " on line:" << line << "\n";
+ if (node) ss << "At node: " << node->debugNodePath() << "\n";
+ throw std::runtime_error(ss.str());
+ }
+
+ // There is no need check for '#' comment character in variable name
+ // since the variable constructor will check for this
+ // i.e edit #var value
+ // edit var# value
+
+ // Make sure value does not begin with '#' comment character
+ if ( lineTokens[2][0] == '#') {
+ // edit fred #comment
+ // edit fred #
+ std::stringstream ss;
+ ss << "VariableParser::doParse: Expected value but found comment at line:" << line << "\n";
+ if (node) ss << "At node: " << node->debugNodePath() << "\n";
+ throw std::runtime_error(ss.str());
+ }
+
+
+ // ** For aliases, the variables may be **different** to normal variables in that they may contain a ":" & $
+ // ** This is **not** allowed in normal variables.
+ // ** i.e it allows for %A:1%, %A:2%, %A:3%
+ // ** This is not really recommended but its what the old system supported.
+ // ** Hence the variable construction by-passes variable name checking ***
+
+ // Note:
+ // edit OWNER 'fred' => value = fred
+ // edit OWNER 'fred and "ginger"' => value = fred and "ginger"
+ // edit OWNER "" => value =
+ // edit OWNER '' => value =
+ // edit OWNER '"fred"' => value = "fred" * quotes are preserved *
+ // edit OWNER "'fred'" => value = fred * tick are not preserved *
+ if ( line_tokens_size == 3 ) {
+ // The order of removing double quotes and then single quotes is significant here
+ Str::removeQuotes(lineTokens[2]); // if first *and* last character is "
+ Str::removeSingleQuotes(lineTokens[2]); // if first *and* last character is '
+ if (node) {
+ if (node->isAlias()) node->addVariable( Variable( lineTokens[1], lineTokens[2],false )); // bypass name checking
+ else node->addVariable( Variable( lineTokens[1], lineTokens[2] ));
+ }
+ else defsfile()->set_server().add_or_update_user_variables(lineTokens[1], lineTokens[2]);
+ return true;
+ }
+
+ // i.e
+ // 0 1 2
+ // edit var_name "smsfetch -F %ECF_FILES% -I %ECF_INCLUDE%" #fred
+ std::string value; value.reserve(line.size()-4);
+ for (size_t i = 2; i < line_tokens_size; ++i) {
+ if ( lineTokens[i].at( 0 ) == '#' ) break;
+ if ( i != 2 ) value += " ";
+ value += lineTokens[i];
+ }
+
+ Str::removeQuotes(value);
+ Str::removeSingleQuotes(value);
+ if (node) {
+ if (node->isAlias()) node->addVariable( Variable( lineTokens[1], value, false )); // bypass name checking
+ else node->addVariable( Variable( lineTokens[1], value )) ;
+ }
+ else defsfile()->set_server().add_or_update_user_variables(lineTokens[1], value);
+
+ return true;
+}
diff --git a/AParser/src/VariableParser.hpp b/AParser/src/VariableParser.hpp
new file mode 100644
index 0000000..d57f153
--- /dev/null
+++ b/AParser/src/VariableParser.hpp
@@ -0,0 +1,48 @@
+#ifndef VARIABLEPARSER_HPP_
+#define VARIABLEPARSER_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+// edit fred 'val'
+// edit FRED "smscheck %WSHOST% %EXPVER% %ECF_JOB%"
+//
+// In the old SMS single quotes are used if no interpretation
+// is required and double quotes to allow variable substitution
+// However this is ONLY a requirement for CDP.
+// Note when OLD SMS uses the show command it always outputs with single quotes
+//
+// Do we remove the quotes when we store internally ?
+// i.e if we have :
+// edit YMD '20090901'
+// Then the value '20090901' is not immediately convertible to an integer
+// *************************************************************
+// This is required for evaluation in the abstract syntax tree
+// *************************************************************
+//
+// Hence we will do the following:
+// a/ On parsing always remove quotes ie single or double
+// b/ On serialising always add single quotes
+//============================================================================
+
+#include "Parser.hpp"
+
+class VariableParser : public Parser {
+public:
+ VariableParser(DefsStructureParser* p, bool parsing_defs = false) : Parser(p), parsing_defs_(parsing_defs) {}
+ virtual const char* keyword() const { return "edit"; }
+ virtual bool doParse( const std::string& line, std::vector<std::string >& lineTokens );
+private:
+ bool parsing_defs_;
+};
+
+#endif
diff --git a/AParser/src/VerifyParser.cpp b/AParser/src/VerifyParser.cpp
new file mode 100644
index 0000000..84dda56
--- /dev/null
+++ b/AParser/src/VerifyParser.cpp
@@ -0,0 +1,53 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #11 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "VerifyParser.hpp"
+#include "Node.hpp"
+#include "Extract.hpp"
+
+using namespace ecf;
+using namespace std;
+
+bool VerifyParser::doParse( const std::string& line, std::vector<std::string >& lineTokens )
+{
+ // expect:
+ // verify <state>:int i.e
+ // verify complete:3
+ if ( lineTokens.size() < 2 ) throw std::runtime_error( "VerifyParser::doParse: Invalid verify :" + line );
+
+ if ( !nodeStack().empty() ) {
+ Node* node = nodeStack_top();
+
+ std::string stateInt = lineTokens[1];
+
+ size_t colonPos = stateInt.find_first_of(':');
+ if (colonPos == std::string::npos) throw std::runtime_error( "Invalid verify :" + line );
+
+ std::string state = stateInt.substr(0,colonPos);
+ std::string expected = stateInt.substr(colonPos+1);
+// cout << "state = " << state << "\n";
+// cout << "expected = " << expected << "\n";
+
+ if (!NState::isValid(state)) {
+ throw std::runtime_error( "VerifyParser::doParse: Invalid state :" + line );
+ }
+
+ NState::State theState = NState::toState(state);
+ int theExpectedStateCnt = Extract::theInt(expected,"Invalid verify" );
+
+ node->addVerify( VerifyAttr(theState,theExpectedStateCnt) ) ;
+ }
+ return true;
+}
diff --git a/AParser/src/VerifyParser.hpp b/AParser/src/VerifyParser.hpp
new file mode 100644
index 0000000..127fae6
--- /dev/null
+++ b/AParser/src/VerifyParser.hpp
@@ -0,0 +1,29 @@
+#ifndef VERIFYPARSER_HPP_
+#define VERIFYPARSER_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : A verify attribute parser. Note verify are only used for verification
+// and do not constitute to the structure of a definition file
+//
+//============================================================================
+
+#include "Parser.hpp"
+
+class VerifyParser : public Parser {
+public:
+ VerifyParser(DefsStructureParser* p) : Parser(p) {}
+ virtual const char* keyword() const { return "verify"; }
+ virtual bool doParse( const std::string& line, std::vector<std::string >& lineTokens );
+};
+
+#endif
diff --git a/AParser/src/ZombieAttrParser.cpp b/AParser/src/ZombieAttrParser.cpp
new file mode 100644
index 0000000..901dc65
--- /dev/null
+++ b/AParser/src/ZombieAttrParser.cpp
@@ -0,0 +1,39 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "ZombieAttrParser.hpp"
+#include "Node.hpp"
+
+using namespace ecf;
+using namespace std;
+
+bool ZombieAttrParser::doParse( const std::string& line, std::vector<std::string >& lineTokens )
+{
+ // expect: tokenizer
+ // zombie <zombie_type>: action : child_cmds : lifetime
+ // zombie_type = [ user | ecf | path ] # can only have one
+ // action = [ fob | fail | block | remove | adopt ] # can only have one
+ // child_cmd = [ init, event, meter, label, wait, abort, complete ] # can have mutiple
+ // zombie ecf:fob:: # fob all child commands
+ // zombie ecf:fail:event,meter:200 # fail child command event,meter and block other children
+ if ( lineTokens.size() < 2 ) throw std::runtime_error( "ZombieAttrParser::doParse: Invalid zombie :" + line );
+ if (nodeStack().empty() ) throw std::runtime_error("Add zombie failed empty node stack");
+
+ //cout << "ZombieAttrParser::doParse: " << lineTokens[1] << "\n";
+
+ nodeStack_top()->addZombie( ZombieAttr::create(lineTokens[1]) ) ;
+
+ return true;
+}
diff --git a/AParser/src/ZombieAttrParser.hpp b/AParser/src/ZombieAttrParser.hpp
new file mode 100644
index 0000000..ee40273
--- /dev/null
+++ b/AParser/src/ZombieAttrParser.hpp
@@ -0,0 +1,27 @@
+#ifndef ZOMBIE_ATTR_PARSER_HPP_
+#define ZOMBIE_ATTR_PARSER_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "Parser.hpp"
+
+class ZombieAttrParser : public Parser {
+public:
+ ZombieAttrParser(DefsStructureParser* p) : Parser(p) {}
+ virtual const char* keyword() const { return "zombie"; }
+ virtual bool doParse( const std::string& line, std::vector<std::string >& lineTokens );
+};
+
+#endif
diff --git a/AParser/test/ParseOnly.cpp b/AParser/test/ParseOnly.cpp
new file mode 100644
index 0000000..bdb1036
--- /dev/null
+++ b/AParser/test/ParseOnly.cpp
@@ -0,0 +1,51 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <string>
+#include <iostream>
+#include <fstream>
+
+#include "DefsStructureParser.hpp"
+#include "Defs.hpp"
+#include "PrintStyle.hpp"
+
+using namespace std;
+using namespace ecf;
+
+int main(int argc, char* argv[])
+{
+// cout << "argc = " << argc << "\n";
+// for(int i = 0; i < argc; i++) {
+// cout << "arg " << i << ":" << argv[i] << "\n";
+// }
+
+ if (argc != 2) {
+ cout << "Expect single argument which is path to a defs file\n";
+ return 1;
+ }
+
+ std::string path = argv[1];
+
+ Defs defs;
+ DefsStructureParser checkPtParser( &defs, path);
+ std::string errorMsg,warningMsg;
+ if (!checkPtParser.doParse(errorMsg,warningMsg)) {
+ cout << errorMsg << "\n";
+ cout << warningMsg << "\n";
+ return 1;
+ }
+// PrintStyle::setStyle(PrintStyle::MIGRATE);
+// cout << defs;
+ return 0;
+}
diff --git a/AParser/test/ParseTimer.cpp b/AParser/test/ParseTimer.cpp
new file mode 100644
index 0000000..dfabecc
--- /dev/null
+++ b/AParser/test/ParseTimer.cpp
@@ -0,0 +1,224 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <string>
+#include <iostream>
+#include <fstream>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include "boost/progress.hpp"
+#include <boost/timer.hpp>
+#include "boost/date_time/posix_time/posix_time_types.hpp"
+
+#include "DefsStructureParser.hpp"
+#include "Defs.hpp"
+#include "NodeContainer.hpp"
+#include "Suite.hpp"
+#include "Task.hpp"
+#include "Family.hpp"
+#include "PrintStyle.hpp"
+#include "PersistHelper.hpp"
+#include "JobsParam.hpp"
+#include "Jobs.hpp"
+#include "DurationTimer.hpp"
+#include "Log.hpp"
+#include "System.hpp"
+
+using namespace std;
+using namespace ecf;
+
+// This test is used to find a task given a path of the form:
+// suite/family/task
+// suite/family/family/task
+void test_find_task_using_path( NodeContainer* f,const Defs& defs )
+{
+ if (f != defs.findAbsNode(f->absNodePath()).get() ) cout << "Could not find path " << f->absNodePath() << "\n";
+
+ BOOST_FOREACH(node_ptr t, f->nodeVec()) {
+ if (t.get() != defs.findAbsNode(t->absNodePath()).get()) cout << "Could not find path " << t->absNodePath() << "\n";
+ Family* family = t->isFamily();
+ if (family) {
+ test_find_task_using_path(family, defs);
+ }
+ }
+}
+
+// Create derived class, so that we can time the parse only
+// i.e ignore expression build/checking and limit checking
+class TestDefsStructureParser : public DefsStructureParser {
+public:
+ TestDefsStructureParser(Defs* defsfile, const std::string& file_name) : DefsStructureParser(defsfile,file_name) {}
+ bool do_parse_only(std::string& errorMsg) { return DefsStructureParser::do_parse_only(errorMsg); }
+};
+
+
+int main(int argc, char* argv[])
+{
+// cout << "argc = " << argc << "\n";
+// for(int i = 0; i < argc; i++) {
+// cout << "arg " << i << ":" << argv[i] << "\n";
+// }
+
+ if (argc != 2) {
+ cout << "Expect single argument which is path to a defs file\n";
+ return 1;
+ }
+
+ std::string path = argv[1];
+
+ DurationTimer duration_timer;
+ boost::timer timer; // measures CPU, replace with cpu_timer with boost > 1.51, measures cpu & elapsed
+
+ /// If this is moved below, we get some caching affect, with the persist and reload timing
+ Defs defs;
+ {
+ timer.restart();
+ DefsStructureParser checkPtParser( &defs, path);
+ std::string errorMsg,warningMsg;
+ bool result = checkPtParser.doParse(errorMsg,warningMsg);
+ std::cout << " Parsing Node tree and AST creation time = " << timer.elapsed() << " parse(" << result << ")" << endl;
+ }
+
+ // {
+ // Defs local_defs;
+ // timer.restart();
+ // TestDefsStructureParser checkPtParser( &local_defs, path);
+ // std::string errorMsg;
+ // bool result = checkPtParser.do_parse_only(errorMsg);
+ // std::cout << " Parsing Node tree *only* time = " << timer.elapsed() << " parse(" << result << ")" << endl;
+ // }
+
+
+ // {
+ // timer.restart();
+ // BOOST_FOREACH(suite_ptr s, defs.suiteVec()) { test_find_task_using_path(s.get(),defs); }
+ // cout << " Test all paths can be found. time taken = " << timer.elapsed() << endl;
+ // }
+ //
+ // {
+ // // Test time for persisting to defs file only
+ // std::string tmpFilename = "tmp.def";
+ //
+ // timer.restart();
+ // PrintStyle style(PrintStyle::DEFS);
+ // std::ofstream ofs( tmpFilename.c_str() ); ofs << defs;
+ // cout << " Persist only, time taken = " << timer.elapsed() << endl;
+ //
+ // std::remove(tmpFilename.c_str());
+ // }
+
+ // {
+ // // may need to comment out output for large differences. Will double the time.
+ // timer.restart();
+ // PersistHelper helper;
+ // bool result = helper.test_persist_and_reload(defs);
+ // cout << " Persist and reload(DEFS) and compare, time taken = "
+ // << timer.elapsed() << " file_size(" << helper.file_size() << ") result(" << result << ") msg(" << helper.errorMsg() << ")" << endl;
+ // }
+
+#if defined(BINARY_ARCHIVE)
+ {
+ bool do_compare = false;
+ timer.restart();
+ PersistHelper helper;
+ bool result = helper.test_checkpt_and_reload(defs, do_compare,ecf::Archive::BINARY);
+ cout << " Checkpt(BINARY_ARCHIVE) and reload , time taken = ";
+ cout << timer.elapsed() << " file_size(" << helper.file_size() << ") result(" << result << ") msg(" << helper.errorMsg() << ")" << endl;
+ }
+#elif defined(PORTABLE_BINARY_ARCHIVE)
+ {
+ bool do_compare = false;
+ timer.restart();
+ PersistHelper helper;
+ bool result = helper.test_checkpt_and_reload(defs, do_compare, ecf::Archive::PORTABLE_BINARY);
+ cout << " Checkpt(PORTABLE_BINARY_ARCHIVE) and reload , time taken = ";
+ cout << timer.elapsed() << " file_size(" << helper.file_size() << ") result(" << result << ") msg(" << helper.errorMsg() << ")" << endl;
+ }
+#elif defined(EOS_PORTABLE_BINARY_ARCHIVE)
+ {
+ bool do_compare = false;
+ timer.restart();
+ PersistHelper helper;
+ bool result = helper.test_checkpt_and_reload(defs, do_compare, ecf::Archive::EOS_PORTABLE_BINARY);
+ cout << " Checkpt(EOS_PORTABLE_BINARY_ARCHIVE) and reload , time taken = ";
+ cout << timer.elapsed() << " file_size(" << helper.file_size() << ") result(" << result << ") msg(" << helper.errorMsg() << ")" << endl;
+ }
+#else
+ {
+ bool do_compare = false;
+ timer.restart();
+ PersistHelper helper;
+ bool result = helper.test_checkpt_and_reload(defs, do_compare, ecf::Archive::TEXT);
+ cout << " Checkpt(TEXT_ARCHIVE) and reload , time taken = ";
+ cout << timer.elapsed() << " file_size(" << helper.file_size() << ") result(" << result << ") msg(" << helper.errorMsg() << ")" << endl;
+ }
+// {
+// bool do_compare = false;
+// timer.restart();
+// PersistHelper helper;
+// for(int i = 0; i < 5; i++) {
+// bool result = helper.test_checkpt_and_reload(defs, do_compare, ecf::Archive::TEXT);
+// if (!helper.errorMsg().empty()) cout << " result(" << result << ") msg(" << helper.errorMsg() << ")\n";
+// }
+// cout << " Checkpt(TEXT_ARCHIVE) and reload 5 times: Average time taken = ";
+// cout << timer.elapsed()/5 << " : file_size(" << helper.file_size() << ")\n";
+// }
+#endif
+
+// {
+// // Time how long it takes for job submission. Must call begin on all suites first.
+// timer.restart();
+// defs.beginAll();
+// int count = 10;
+// JobsParam jobsParam; // default is not to create jobs, hence only used in testing
+// Jobs jobs(&defs);
+// for (int i = 0; i < count; i++) {jobs.generate(jobsParam);}
+// cout << " time for " << count << " jobSubmissions:" << timer.elapsed() << "s jobs:" << jobsParam.submitted().size() << endl;
+// }
+//
+// {
+// // Time how long it takes for post process
+// timer.restart();
+// string errorMsg,warningMsg;
+// bool result = defs.check(errorMsg,warningMsg);
+// cout << " time for Defs::check ( inlimit resolution) = " << timer.elapsed() << " result(" << result << ") msg(" << errorMsg << ")" << endl;
+// }
+
+// {
+// // Time how long it takes to delete all nodes/ references. Delete all tasks and then suites/families.
+// timer.restart();
+// std::vector<Task*> tasks;
+// defs.getAllTasks(tasks);
+// BOOST_FOREACH(Task* t, tasks) {
+// if (!defs.deleteChild(t)) cout << "Failed to delete task\n";
+// }
+// tasks.clear(); defs.getAllTasks(tasks);
+// if (!tasks.empty()) cout << "Expected all tasks to be deleted but found " << tasks.size() << "\n";
+//
+// std::vector<suite_ptr> vec = defs.suiteVec(); // make a copy, to avoid invalidating iterators
+// BOOST_FOREACH(suite_ptr s, vec) {
+// std::vector<node_ptr> familyVec = s->nodeVec(); // make a copy, to avoid invalidating iterators
+// BOOST_FOREACH(node_ptr f, familyVec) {
+// if (!defs.deleteChild(f.get())) cout << "Failed to delete family\n";
+// }
+// if (!s->nodeVec().empty()) cout << "Expected all Families to be deleted but found " << s->nodeVec().size() << "\n";
+// if (!defs.deleteChild(s.get())) cout << "Failed to delete suite\n";
+// }
+// if (!defs.suiteVec().empty()) cout << "Expected all Suites to be deleted but found " << defs.suiteVec().size() << "\n";
+//
+// cout << " time for deleting all nodes = " << timer.elapsed() << endl;
+// }
+ cout << " Total elapsed time = " << duration_timer.duration() << " seconds\n";
+}
diff --git a/AParser/test/PersistHelper.cpp b/AParser/test/PersistHelper.cpp
new file mode 100644
index 0000000..5e36bc8
--- /dev/null
+++ b/AParser/test/PersistHelper.cpp
@@ -0,0 +1,237 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <boost/archive/tmpdir.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <iostream>
+#include <fstream>
+
+#include "PersistHelper.hpp"
+#include "DefsStructureParser.hpp"
+#include "PrintStyle.hpp"
+#include "Defs.hpp"
+#include "Ecf.hpp"
+
+namespace fs = boost::filesystem;
+using namespace std;
+using namespace ecf;
+
+bool PersistHelper::test_persist_and_reload( const Defs& theInMemoryDefs, PrintStyle::Type_t file_type_on_disk)
+{
+ // Write parsed file to disk, and reload, then compare defs, they should be the same
+ errorMsg_.clear();
+ file_size_ = 0;
+
+#ifdef DEBUG
+ std::string tmpFilename = "tmp_d.def";
+#else
+ std::string tmpFilename = "tmp.def";
+#endif
+ {
+ // The file MUST be written in the *SAME* form that it was read
+ // Otherwise they will not compare:
+ PrintStyle style(file_type_on_disk);
+ std::ofstream ofs( tmpFilename.c_str() );
+ ofs << theInMemoryDefs;
+ }
+
+ // Reload the file we just persisted and compare with in memory defs
+ Defs savedDef;
+ return reload_from_defs_file(theInMemoryDefs,savedDef,tmpFilename);
+}
+
+
+bool PersistHelper::test_checkpt_and_reload( const Defs& theInMemoryDefs, bool do_compare, ecf::Archive::Type at)
+{
+ errorMsg_.clear();
+ file_size_ = 0;
+
+ // Save in memory defs as a check pt file, then restore and compare
+ Defs reloaded_defs;
+ return reload_from_checkpt_file(theInMemoryDefs,reloaded_defs,do_compare,at);
+}
+
+
+bool PersistHelper::test_state_persist_and_reload_with_checkpt(const Defs& theInMemoryDefs )
+{
+ // Write Defs to disk, and reload, then compare defs relaoded checkpt file, they should be the same
+ errorMsg_.clear();
+ file_size_ = 0;
+
+#ifdef DEBUG
+ std::string tmpFilename = "tmp_d.def";
+#else
+ std::string tmpFilename = "tmp.def";
+#endif
+ {
+ // The file MUST be written in the *SAME* form that it was read
+ // Otherwise they will not compare:
+ PrintStyle style(PrintStyle::MIGRATE); // will save edit history
+ std::ofstream ofs( tmpFilename.c_str() );
+ ofs << theInMemoryDefs;
+ }
+
+ // Reload the file we just persisted and compare with in memory defs
+ Defs reloaded_defs;
+ if (!reload_from_defs_file(theInMemoryDefs,reloaded_defs,tmpFilename)) {
+ return false;
+ }
+
+ // Save in memory defs as a check pt file, then restore and compare
+ Defs reloaded_checkPt_defs;
+ if (!reload_from_checkpt_file(theInMemoryDefs,reloaded_checkPt_defs,true,ecf::Archive::default_archive())) {
+ return false;
+ }
+
+ // Make sure reloading def's file with state is same as the checkpt file
+ Ecf::set_debug_equality(true);
+ bool match = reloaded_defs == reloaded_checkPt_defs;
+ Ecf::set_debug_equality(false);
+
+ if (!match) {
+ std::stringstream ss;
+ ss << "\nPersistHelper::test_state_persist_and_reload_with_checkpt\n";
+ ss << "In reloaded_defs_file and reloaded_checkPt_defs don't match\n";
+ ss << "+++++++++++++ in memory defs ++++++++++++++++++++++++++++\n";
+ PrintStyle style(PrintStyle::MIGRATE); // will save edit history
+ ss << theInMemoryDefs;
+ ss << "+++++++++++++ reloaded_defs ++++++++++++++++++++++++++++\n";
+ ss << reloaded_defs;
+ ss << "++++++++++++++ reloaded_checkPt_defs ++++++++++++++++++++++++++++\n";
+ ss << reloaded_checkPt_defs;
+ errorMsg_ += ss.str();
+ }
+ else {
+ if (compare_edit_history_ && !reloaded_defs.compare_edit_history(reloaded_checkPt_defs)) {
+ std::stringstream ss;
+ ss << "\nPersistHelper::test_state_persist_and_reload_with_checkpt compare_edit_history_\n";
+ ss << "In reloaded_defs_file and reloaded_checkPt_defs edit history don't match\n";
+ ss << "+++++++++++++ in memory defs ++++++++++++++++++++++++++++\n";
+ PrintStyle style(PrintStyle::MIGRATE); // will save edit history
+ ss << theInMemoryDefs;
+ ss << "+++++++++++++ reloaded_defs ++++++++++++++++++++++++++++\n";
+ ss << reloaded_defs;
+ ss << "++++++++++++++ reloaded_checkPt_defs ++++++++++++++++++++++++++++\n";
+ ss << reloaded_checkPt_defs;
+ errorMsg_ += ss.str();
+ }
+ }
+ return errorMsg_.empty();
+}
+
+
+bool PersistHelper::reload_from_defs_file(const Defs& theInMemoryDefs, Defs& reloaded_defs, const std::string& tmpFilename )
+{
+ std::string warningMsg;
+ DefsStructureParser defsParser( &reloaded_defs, tmpFilename );
+ bool theParse = defsParser.doParse(errorMsg_,warningMsg);
+ if (!theParse) {
+ std::stringstream ss;
+ ss << "RE-PARSE failed for " << tmpFilename << "\n";
+ errorMsg_ += ss.str();
+ return false;
+ }
+
+ // Make sure the file we just parsed match's the one we persisted
+ Ecf::set_debug_equality(true);
+ bool match = reloaded_defs == theInMemoryDefs;
+ Ecf::set_debug_equality(false);
+
+ if (!match) {
+ std::stringstream ss;
+ ss << "\nPersistHelper::reload_from_defs_file\n";
+ ss << "In memory and reloaded def's don't match\n";
+ ss << "+++++++++++++ Saved/reloaded_defs ++++++++++++++++++++++++++++\n";
+ PrintStyle style(PrintStyle::STATE);
+ ss << reloaded_defs;
+ ss << "++++++++++++++ In memory def ++++++++++++++++++++++++++++\n";
+ ss << theInMemoryDefs;
+ errorMsg_ += ss.str();
+ }
+ else {
+ if (compare_edit_history_ && !reloaded_defs.compare_edit_history(theInMemoryDefs)) {
+ std::stringstream ss;
+ ss << "\nPersistHelper::reload_from_defs_file compare_edit_history_\n";
+ ss << "In memory and reloaded def's don't match\n";
+ ss << "+++++++++++++ Saved/reloaded_defs ++++++++++++++++++++++++++++\n";
+ PrintStyle style(PrintStyle::MIGRATE);
+ ss << reloaded_defs;
+ ss << "++++++++++++++ In memory def ++++++++++++++++++++++++++++\n";
+ ss << theInMemoryDefs;
+ errorMsg_ += ss.str();
+ }
+ }
+
+ file_size_ = fs::file_size(tmpFilename);
+ std::remove(tmpFilename.c_str());
+ return errorMsg_.empty();
+}
+
+
+bool PersistHelper::reload_from_checkpt_file(const Defs& theInMemoryDefs,
+ Defs& reloaded_defs,
+ bool do_compare ,
+ ecf::Archive::Type at)
+{
+ // make sure edit history is saved
+#ifdef DEBUG
+ std::string tmpCheckPt_file = "tmp.check_debug";
+#else
+ std::string tmpCheckPt_file = "tmp.check";
+#endif
+ theInMemoryDefs.save_as_checkpt(tmpCheckPt_file,at);
+
+ try {
+ // Parse the file we just persisted and load the defs file into memory.
+ reloaded_defs.restore_from_checkpt(tmpCheckPt_file,at);
+
+ if (do_compare ) {
+ // Make sure the checkpoint file file we just parsed match's the one we persisted
+ bool match = reloaded_defs == theInMemoryDefs;
+ if (!match) {
+ std::stringstream ss;
+ ss << "\nPersistHelper::reload_from_checkpt_file\n";
+ ss << "In memory and reloaded def's don't match\n";
+ ss << "+++++++++++++ Saved/reloaded check pt file ++++++++++++++++++++++++++++\n";
+ PrintStyle style(PrintStyle::STATE);
+ ss << reloaded_defs;
+ ss << "++++++++++++++ In memory def ++++++++++++++++++++++++++++\n";
+ ss << theInMemoryDefs;
+ errorMsg_ += ss.str();
+ }
+ else {
+ if (compare_edit_history_ && !reloaded_defs.compare_edit_history(theInMemoryDefs)) {
+ std::stringstream ss;
+ ss << "\nPersistHelper::reload_from_checkpt_file compare_edit_history_\n";
+ ss << "In reloaded_defs_file and reloaded_checkPt_defs edit history don't match\n";
+ ss << "+++++++++++++ Saved/reloaded check pt file ++++++++++++++++++++++++++++\n";
+ PrintStyle style(PrintStyle::MIGRATE);
+ ss << reloaded_defs;
+ ss << "++++++++++++++ theInMemoryDefs ++++++++++++++++++++++++++++\n";
+ ss << theInMemoryDefs;
+ errorMsg_ += ss.str();
+ }
+ }
+ }
+ }
+ catch (std::exception& e) {
+ errorMsg_ = "PersistHelper::reload_from_checkpt_file: " + string(e.what());
+ }
+
+ file_size_ = fs::file_size(tmpCheckPt_file);
+ std::remove(tmpCheckPt_file.c_str());
+
+ return errorMsg_.empty();
+}
diff --git a/AParser/test/PersistHelper.hpp b/AParser/test/PersistHelper.hpp
new file mode 100644
index 0000000..6a20097
--- /dev/null
+++ b/AParser/test/PersistHelper.hpp
@@ -0,0 +1,58 @@
+#ifndef PERSISTHELPER_HPP_
+#define PERSISTHELPER_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+
+#include <boost/noncopyable.hpp>
+#include <string>
+#include "Archive.hpp"
+#include "PrintStyle.hpp"
+class Defs;
+
+/// Given a in memory defs file, this class will write it to disk
+/// and reload the definition file structure and will then make a comparison
+/// to ensure they are the same
+class PersistHelper : private boost::noncopyable {
+public:
+ PersistHelper(bool compare_edit_history = false) : file_size_(0),compare_edit_history_(compare_edit_history) {}
+
+ bool test_persist_and_reload( const Defs& theInMemoryDefs, PrintStyle::Type_t file_type_on_disk);
+ bool test_checkpt_and_reload( const Defs& theInMemoryDefs, bool do_compare = true,ecf::Archive::Type at = ecf::Archive::default_archive());
+ bool test_state_persist_and_reload_with_checkpt( const Defs& theInMemoryDefs );
+ const std::string& errorMsg() const { return errorMsg_;}
+
+ /// returns the file size of the temporary file created by:
+ /// test_persist_and_reload(..) or test_checkpt_and_reload(..)
+ size_t file_size() const { return file_size_;}
+
+private:
+
+ bool reload_from_defs_file( const Defs& theInMemoryDefs, Defs& reloaded_defs, const std::string& filename );
+ bool reload_from_checkpt_file(const Defs& theInMemoryDefs,
+ Defs& reloaded_defs,
+ bool do_compare = true,
+ ecf::Archive::Type at = ecf::Archive::default_archive() );
+
+private:
+
+ std::string errorMsg_;
+ size_t file_size_;
+ bool compare_edit_history_;
+};
+#endif
+
+
+
diff --git a/AParser/test/TestAutoAddExterns.cpp b/AParser/test/TestAutoAddExterns.cpp
new file mode 100644
index 0000000..569bba6
--- /dev/null
+++ b/AParser/test/TestAutoAddExterns.cpp
@@ -0,0 +1,69 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <string>
+#include <iostream>
+#include <fstream>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/timer.hpp>
+#include "boost/date_time/posix_time/posix_time_types.hpp"
+#include <boost/test/unit_test.hpp>
+
+#include "DefsStructureParser.hpp"
+#include "Defs.hpp"
+#include "NodeContainer.hpp"
+#include "Suite.hpp"
+#include "Task.hpp"
+#include "Family.hpp"
+#include "Log.hpp"
+#include "File.hpp"
+
+namespace fs = boost::filesystem;
+using namespace std;
+using namespace ecf;
+using namespace boost::posix_time;
+
+BOOST_AUTO_TEST_SUITE( ParserTestSuite )
+
+// Test that automatic add of externs
+BOOST_AUTO_TEST_CASE( test_auto_add_externs )
+{
+ std::string path = File::test_data("AParser/test/data/single_defs/test_auto_add_extern.def","AParser");
+
+ size_t mega_file_size = fs::file_size(path);
+ cout << "AParser:: ...test_auto_add_externs " << path << " file_size(" << mega_file_size << ")\n";
+
+ Defs defs;
+ DefsStructureParser checkPtParser( &defs, path);
+ std::string errorMsg,warningMsg;
+ BOOST_REQUIRE_MESSAGE(checkPtParser.doParse(errorMsg,warningMsg),errorMsg);
+ BOOST_REQUIRE_MESSAGE(warningMsg.empty(),"Expected no warnings but found:\n" << warningMsg);
+
+ // Check number of extrens read in: Duplicate should be ignore
+ BOOST_REQUIRE_MESSAGE(defs.externs().size() == 9 ,"Expected 9 externs as starting point but found " << defs.externs().size() << "\n");
+
+ // Test auto extern generation. Don't remove existing extern's
+ defs.auto_add_externs(false/* remove_existing_externs_first*/);
+ BOOST_REQUIRE_MESSAGE(defs.externs().size() == 9 ,"Expected 9, auto_add_extern(false) gave: " << defs.externs().size() << "\n" << defs << "\n");
+
+ // By removing the externs read, in we can determine the real number of extern;s from
+ // parsing all the trigger expressions, and inlimit references
+ defs.auto_add_externs(true/* remove_existing_externs_first*/);
+ BOOST_REQUIRE_MESSAGE(defs.externs().size() == 8 ,"Expected 8 externs, since redundant externs removed, auto_add_extern(true) gave: " << defs.externs().size() << "\n"<< defs << "\n");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/AParser/test/TestDefsStructurePersistAndReload.cpp b/AParser/test/TestDefsStructurePersistAndReload.cpp
new file mode 100644
index 0000000..15b6c22
--- /dev/null
+++ b/AParser/test/TestDefsStructurePersistAndReload.cpp
@@ -0,0 +1,96 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <string>
+#include <iostream>
+#include <fstream>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/test/unit_test.hpp>
+#include <boost/foreach.hpp>
+
+#include "PersistHelper.hpp"
+#include "DefsStructureParser.hpp"
+#include "PrintStyle.hpp"
+#include "MyDefsFixture.hpp"
+#include "File.hpp"
+
+namespace fs = boost::filesystem;
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( ParserTestSuite )
+
+//=============================================================================
+// This test case will save the defs file in old style format
+// and the parse it back in. As we add different types to our defs fixture
+// we can automatically check that what we save can be parsed back in.
+// Specifically written to test the parser.
+// Note: Aliases are *NOT* written in the defs file.
+BOOST_AUTO_TEST_CASE( test_defs_structure_persistence_and_reload )
+{
+ cout << "AParser:: ...test_defs_structure_persistence_and_reload\n";
+
+ std::string checkPtFile = File::test_data("AParser/test/generated_defs_file.txt","AParser");
+
+ MyDefsFixture theDefsFixture(checkPtFile);
+
+ PersistHelper helper;
+ BOOST_CHECK_MESSAGE( helper.test_checkpt_and_reload(theDefsFixture.defsfile_), helper.errorMsg());
+
+ // Note: Aliases are *NOT* written in the defs file.
+ // Hence in order for this test to pass, we must delete the alias first & reset task alias_no
+ std::vector<alias_ptr> alias_vec;
+ theDefsFixture.defsfile_.get_all_aliases(alias_vec);
+ BOOST_FOREACH(alias_ptr al,alias_vec) {
+ al->parent()->isTask()->reset_alias_number();
+ al->remove();
+ }
+ BOOST_CHECK_MESSAGE( helper.test_persist_and_reload(theDefsFixture.defsfile_, PrintStyle::DEFS), helper.errorMsg());
+}
+
+
+// This test is used to find a task given a path of the form:
+// suite/family/task
+// suite/family/family/task
+//
+void test_find_task_using_path( NodeContainer* f,const Defs& defs )
+{
+ BOOST_CHECK_MESSAGE(f == defs.findAbsNode(f->absNodePath()).get(), "Could not find path " << f->absNodePath() << "\n");
+
+ BOOST_FOREACH(node_ptr t, f->nodeVec()) {
+ BOOST_CHECK_MESSAGE( t.get() == defs.findAbsNode(t->absNodePath()).get(), "Could not find path " << t->absNodePath() << "\n");
+ Family* family = t->isFamily();
+ if (family) {
+ test_find_task_using_path(family, defs);
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_find_task_using_paths )
+{
+ cout << "AParser:: ...test_find_task_using_paths\n";
+
+ MyDefsFixture theDefsFixture;
+
+ const std::vector<suite_ptr>& suiteVec = theDefsFixture.defsfile_.suiteVec();
+ BOOST_FOREACH(suite_ptr s, suiteVec) {
+ test_find_task_using_path(s.get(),theDefsFixture.defsfile_);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+
diff --git a/AParser/test/TestJobGenPerf.cpp b/AParser/test/TestJobGenPerf.cpp
new file mode 100644
index 0000000..1018544
--- /dev/null
+++ b/AParser/test/TestJobGenPerf.cpp
@@ -0,0 +1,84 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <iostream>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+
+#include "Defs.hpp"
+#include "Str.hpp"
+#include "File.hpp"
+#include "Log.hpp"
+#include "Jobs.hpp"
+#include "JobsParam.hpp"
+#include "DefsStructureParser.hpp"
+#include "JobProfiler.hpp"
+
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+
+// This relies on Pyext/samples/TestJobGenPerf.py to make any defs amenable
+// for this test program.
+//
+// The defs is in /var/tmp/ma0/ECFLOW_TEST/TestJobGenPerf
+//
+int main(int argc, char* argv[])
+{
+ if (argc != 2) {
+ cout << "Expect single argument which is path to a defs file\n";
+ return 1;
+ }
+
+ // delete the log file if it exists.
+ std::string log_path = File::test_data("AParser/test/TestJobGenPerf.log","AParser");
+ fs::remove(log_path);
+
+
+ std::string path = argv[1];
+
+ Defs defs;
+ DefsStructureParser checkPtParser( &defs, path);
+ std::string errorMsg,warningMsg;
+ if (!checkPtParser.doParse(errorMsg,warningMsg)) {
+ cout << errorMsg << "\n";
+ cout << warningMsg << "\n";
+ return 1;
+ }
+
+ // Check number of tasks, if the submitted output below is too low
+ // Then remove, limits,triggers,time,cron so more jobs can be generated.
+ std::vector<Task*> tasks;
+ defs.getAllTasks(tasks);
+ cout << "Tasks = " << tasks.size() << "\n";
+
+ defs.beginAll();
+
+
+ // Create a new log, file, place after begin to avoid queued state
+ Log::create(log_path);
+
+ // This controls the log output when job generation > submitJobsInterval
+ JobProfiler::set_task_threshold(0);
+
+ JobsParam jobParam(20 /*submitJobsInterval*/, true /*createJobs*/, false/* spawn jobs */);
+ Jobs job(&defs);
+ bool ok = job.generate( jobParam );
+ if (!ok) cout << " generate failed: " << jobParam.getErrorMsg();
+ cout << "submitted " << jobParam.submitted().size() << "\n";
+
+ // fs::remove(log_path);
+
+ return 0;
+}
diff --git a/AParser/test/TestMigration.cpp b/AParser/test/TestMigration.cpp
new file mode 100644
index 0000000..c24302c
--- /dev/null
+++ b/AParser/test/TestMigration.cpp
@@ -0,0 +1,429 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name : Request
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <string>
+#include <iostream>
+#include <fstream>
+
+#include <boost/archive/tmpdir.hpp>
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include "boost/progress.hpp"
+
+#include "DefsStructureParser.hpp"
+#include "Defs.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "PrintStyle.hpp"
+#include "PersistHelper.hpp"
+#include "Flag.hpp"
+#include "Memento.hpp"
+#include "MyDefsFixture.hpp"
+
+namespace fs = boost::filesystem;
+using namespace std;
+using namespace ecf;
+
+// ********************************************************************
+// These test are used to check that MIGRATE is equivalent to check pt
+// MIGRATE will be used for migration from old to new release
+// MIGRATE is essentially the defs structure with state.
+// The state is written out as comments
+// It is loaded like a normal Defs, the parser detects MIGRATE
+// and loads the state in.
+//
+// By default persistence/MIGRATE *ONLY* writes the state when it not the default.
+// Hence the defaults should *NOT* change. These test will change the state
+// to a non default value.
+//
+// Write the Defs with state and the compare with in memory defs
+// Write the Defs as check pt an then compare with in memory defs
+// Finally compare the two *RELOADED* defs file.
+// ********************************************************************
+
+BOOST_AUTO_TEST_SUITE( ParserTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_state_parser )
+{
+ cout << "AParser:: ...test_state_parser\n";
+ // **** The persistence will NOT write the defaults, hence we need to change the states
+ // **** to test the persistence
+ PersistHelper helper;
+ std::vector<Flag::Type> flag_list = Flag::list();
+ {
+ Defs defs;
+ BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Empty Defs failed: " << helper.errorMsg());
+ }
+ {
+ Defs defs;
+ suite_ptr suite = defs.add_suite("s1");
+
+ // Change state other the default
+ defs.beginAll();
+ suite->set_state(NState::ABORTED);
+ for (size_t i = 0; i < flag_list.size(); ++i) suite->flag().set( flag_list[i] );
+ suite->suspend();
+ BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs),"Add one suite failed: " << helper.errorMsg());
+ }
+ {
+ Defs defs;
+ suite_ptr suite = defs.add_suite("s1");
+ family_ptr f1 = suite->add_family("f1");
+
+ // Change state other the default
+ f1->set_state(NState::COMPLETE);
+ for (size_t i = 0; i < flag_list.size(); ++i) f1->flag().set( flag_list[i] );
+ f1->suspend();
+ BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs),"Add one family failed: " << helper.errorMsg());
+
+ // Test multiple
+ suite->add_family("f2");
+ suite->add_family("f3");
+ BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs),"Add one family failed: " << helper.errorMsg());
+ }
+ {
+ Defs defs;
+ family_ptr f1 = defs.add_suite("s1")->add_family("f1");
+ task_ptr t1 = f1->add_task("t1");
+
+ for (size_t i = 0; i < flag_list.size(); ++i) t1->flag().set( flag_list[i] );
+ t1->suspend();
+ t1->set_state(NState::COMPLETE);
+
+ // Use memento to modify task state
+ SubmittableMemento memento( "Jobs_password","the_rid","the abort reason with spaces",12);
+ std::vector<ecf::Aspect::Type> aspects;
+ t1->set_memento(&memento,aspects);
+
+ BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Add one task failed: " << helper.errorMsg());
+
+ // Test multiple
+ f1->add_task("t2");
+ f1->add_task("t3");
+ BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Add one task failed: " << helper.errorMsg());
+ }
+ {
+ Defs defs;
+ task_ptr task = defs.add_suite("s1")->add_family("f1")->add_task("t1");
+ alias_ptr t1 = task->add_alias_only();
+ for (size_t i = 0; i < flag_list.size(); ++i) t1->flag().set( flag_list[i] );
+ t1->suspend();
+ t1->set_state(NState::COMPLETE);
+ // Use memento to modify alias state
+ SubmittableMemento memento( "Jobs_password","the_rid","the abort reason with spaces",12);
+ std::vector<ecf::Aspect::Type> aspects;
+ t1->set_memento(&memento,aspects);
+ BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Add one alias failed: " << helper.errorMsg());
+
+ // Test multiple
+ task->add_alias_only();
+ task->add_alias_only();
+ // PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
+ BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Add multiple alias failed: " << helper.errorMsg());
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_state_node_attributes )
+{
+ cout << "AParser:: ...test_state_node_attributes\n";
+ PersistHelper helper;
+ {
+ Defs defs;
+ suite_ptr suite = defs.add_suite("s1");
+ task_ptr task = suite->add_task("t1");
+ ecf::LateAttr lateAttr;
+ lateAttr.addSubmitted( ecf::TimeSlot(3,12) );
+ lateAttr.addActive( ecf::TimeSlot(3,12) );
+ lateAttr.addComplete( ecf::TimeSlot(4,12), true);
+ lateAttr.setLate(true);
+ task->addLate(lateAttr);
+
+ ecf::LateAttr lateAttr1;
+ lateAttr1.addSubmitted( ecf::TimeSlot(3,12) );
+ lateAttr1.addActive( ecf::TimeSlot(3,12) );
+ lateAttr1.addComplete( ecf::TimeSlot(4,12), false);
+ lateAttr1.setLate(true);
+ task_ptr task1 = suite->add_task("t2");
+ task1->addLate(lateAttr1);
+
+// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
+ BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Late state: failed: " << helper.errorMsg());
+ }
+ {
+ Defs defs;
+ task_ptr task = defs.add_suite("s1")->add_task("t1");
+ Meter meter("meter",0,100,100); meter.set_value(10);
+ task->addMeter(meter);
+// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
+ BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Meter state: failed: " << helper.errorMsg());
+ }
+ {
+ Defs defs;
+ task_ptr task = defs.add_suite("s1")->add_task("t1");
+ Event event("event"); event.set_value(true);
+ Event event2(10,"event"); event2.set_value(true);
+ Event event3(10); event3.set_value(true);
+ task->addEvent(event);
+ task->addEvent(event2);
+ task->addEvent(event3);
+// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
+ BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Event state: failed: " << helper.errorMsg());
+ }
+ {
+ {
+ Defs defs;
+ task_ptr task = defs.add_suite("s1")->add_task("t1");
+ Label label("name","value"); label.set_new_value("new value");
+ task->addLabel(label);
+ // PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
+ BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Label state: failed: " << helper.errorMsg());
+ }
+ {
+ Defs defs;
+ suite_ptr suite = defs.add_suite("s1");
+ Label label("name","value"); label.set_new_value("new value");
+ suite->addLabel(label);
+// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
+ BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Label state: failed: " << helper.errorMsg());
+ }
+ {
+ Defs defs;
+ suite_ptr suite = defs.add_suite("s1");
+ Label label("name","value\nvalue");
+ suite->addLabel(label);
+// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
+ BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Label state: failed: " << helper.errorMsg());
+ }
+ {
+ Defs defs;
+ suite_ptr suite = defs.add_suite("s1");
+ Label label("name","value\nvalue"); label.set_new_value("value\nwith\nmany\nnewlines");
+ suite->addLabel(label);
+// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
+ BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Label state: failed: " << helper.errorMsg());
+ }
+ }
+ {
+ Defs defs;
+ suite_ptr suite = defs.add_suite("s1");
+ task_ptr t1 = suite->add_task("t1");
+ task_ptr t2 = suite->add_task("t2");
+ task_ptr t3 = suite->add_task("t3");
+ task_ptr t4 = suite->add_task("t4");
+ Limit limit("limit",10);
+ limit.increment(1,t1->absNodePath());
+ limit.increment(1,t2->absNodePath());
+ limit.increment(1,t3->absNodePath());
+ limit.increment(1,t4->absNodePath());
+ suite->addLimit(limit);
+// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
+ BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Limit state: failed: " << helper.errorMsg());
+ }
+
+ // **** Note InLimit does not have any changeable state
+
+ {
+ Defs defs;
+ suite_ptr suite = defs.add_suite("s1");
+ task_ptr t1 = suite->add_task("t1");
+ task_ptr t2 = suite->add_task("t2");
+ task_ptr t3 = suite->add_task("t3");
+ task_ptr t4 = suite->add_task("t4");
+ task_ptr t5 = suite->add_task("t5");
+ task_ptr t6 = suite->add_task("t6");
+
+ std::vector<std::string> stringList; stringList.reserve(3);
+ stringList.push_back("20130101");
+ stringList.push_back("20130201");
+ stringList.push_back("20130301");
+
+ RepeatEnumerated rep("AEnum",stringList);
+ rep.increment();
+ t1->addRepeat( rep );
+
+ RepeatString rep2("AEnum",stringList);
+ rep2.increment();
+ t2->addRepeat( rep2 );
+
+ RepeatDate rep3("YMD",20090916,20090916,1);
+ rep3.increment();
+ t3->addRepeat( rep3 );
+
+ RepeatInteger rep4("rep",0,100,1);
+ rep4.increment();
+ t4->addRepeat( rep4 );
+ t4->increment_repeat();
+
+ RepeatDay rep5(2);
+ rep5.increment();
+ t5->addRepeat( rep5 );
+
+// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
+ BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Repeat state: failed: " << helper.errorMsg());
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_state_time_attributes )
+{
+ cout << "AParser:: ...test_state_time_attributes\n";
+ PersistHelper helper;
+ {
+ Defs defs;
+ suite_ptr suite = defs.add_suite("s1"); suite->begin();
+ task_ptr task = suite->add_task("t1");
+ TimeAttr time(10,10); time.setFree(); time.miss_next_time_slot();
+ TimeAttr time2(10,10,true); time2.calendarChanged(suite->calendar()); time2.setFree(); time2.miss_next_time_slot();
+ TimeAttr time3(TimeSlot(10,10),TimeSlot(12,10),TimeSlot(0,10),true); time3.calendarChanged(suite->calendar());time3.setFree(); time3.miss_next_time_slot();
+
+ task->addTime(time);
+ task->addTime(time2);
+ task->addTime(time3);
+// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
+ BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Time state: failed: " << helper.errorMsg());
+ }
+ {
+ Defs defs;
+ suite_ptr suite = defs.add_suite("s1"); suite->begin();
+ task_ptr task = suite->add_task("t1");
+ TodayAttr time(10,10); time.setFree(); time.miss_next_time_slot();
+ TodayAttr time2(10,10,true); time2.calendarChanged(suite->calendar()); time2.setFree(); time2.miss_next_time_slot();
+ TodayAttr time3(TimeSlot(10,10),TimeSlot(12,10),TimeSlot(0,10),true); time3.calendarChanged(suite->calendar());time3.setFree(); time3.miss_next_time_slot();
+ task->addToday(time);
+ task->addToday(time2);
+ task->addToday(time3);
+// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
+ BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Today state: failed: " << helper.errorMsg());
+ }
+ {
+ Defs defs;
+ task_ptr task = defs.add_suite("s1")->add_task("t1");
+ DayAttr day;
+ DayAttr day1; day1.setFree();
+ DayAttr day2(DayAttr::FRIDAY); day2.setFree();
+ task->addDay(day);
+ task->addDay(day1);
+ task->addDay(day2);
+// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
+ BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Day state: failed: " << helper.errorMsg());
+ }
+ {
+ Defs defs;
+ task_ptr task = defs.add_suite("s1")->add_task("t1");
+ DateAttr d;
+ DateAttr d1; d1.setFree();
+ DateAttr d2(1,1,2012); d2.setFree();
+ DateAttr d3(0,0,2012); d3.setFree();
+ task->addDate(d);
+ task->addDate(d1);
+ task->addDate(d2);
+ task->addDate(d3);
+// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
+ BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Date state: failed: " << helper.errorMsg());
+ }
+ {
+ Defs defs;
+ suite_ptr suite = defs.add_suite("s1"); suite->begin();
+ task_ptr task = suite->add_task("t1");
+ task_ptr task2 = suite->add_task("t2");
+
+ ecf::CronAttr cronAttr;
+ ecf::TimeSlot start( 0, 0 );
+ ecf::TimeSlot finish( 10, 0 );
+ ecf::TimeSlot incr( 0, 5 );
+ std::vector<int> weekdays; for(int i=0;i<7;++i) weekdays.push_back(i);
+ std::vector<int> daysOfMonth;for(int i=1;i<32;++i) daysOfMonth.push_back(i);
+ std::vector<int> months; for(int i=1;i<13;++i) months.push_back(i);
+ cronAttr.addTimeSeries(start,finish,incr);
+ cronAttr.addWeekDays( weekdays );
+ cronAttr.addDaysOfMonth(daysOfMonth);
+ cronAttr.addMonths( months );
+ cronAttr.setFree();
+ task->addCron(cronAttr);
+
+ // Change TimeSeries state
+ TimeSeries ts(start,finish,incr,true);
+ ts.calendarChanged(suite->calendar());
+ ts.miss_next_time_slot();
+ cronAttr.addTimeSeries(ts);
+ task2->addCron(cronAttr);
+
+// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
+ BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Date state: failed: " << helper.errorMsg());
+ }
+
+ // ZombieAttr do not have any changeable state
+}
+
+BOOST_AUTO_TEST_CASE( test_state_edit_history )
+{
+ cout << "AParser:: ...test_state_edit_history\n";
+ PersistHelper helper(true /* compare edit History */);
+ Defs defs;
+ suite_ptr suite = defs.add_suite("s1");
+ defs.add_edit_history(suite->absNodePath(),"request1 with single spaces");
+ defs.add_edit_history(suite->absNodePath(),"request2 with double spaces");
+ defs.add_edit_history(suite->absNodePath(),"request3_with_no_spaces!|?<>$%^&*()_{}:@<>?");
+ suite_ptr suite2 = defs.add_suite("s2");
+ defs.add_edit_history(suite2->absNodePath(),"request1 with single spaces");
+ defs.add_edit_history(suite2->absNodePath(),"request2 with double spaces");
+ defs.add_edit_history(suite2->absNodePath(),"request3_with_no_spaces!|?<>$%^&*()_{}:@<>?");
+// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
+ BOOST_REQUIRE_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Edit history failed: " << helper.errorMsg());
+}
+
+BOOST_AUTO_TEST_CASE( test_server_state )
+{
+ cout << "AParser:: ...test_server_state\n";
+ PersistHelper helper(true /* compare edit History */);
+ {
+ Defs defs;
+ defs.set_server().set_state(SState::HALTED);
+// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
+ BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Set server state failed " << helper.errorMsg());
+ }
+ {
+ Defs defs;
+ defs.set_server().set_state(SState::RUNNING);
+// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
+ BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Set server state failed " << helper.errorMsg());
+ }
+ {
+ Defs defs;
+ defs.set_server().set_state(SState::SHUTDOWN);
+// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
+ BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Set server state failed " << helper.errorMsg());
+ }
+ {
+ Defs defs;
+ std::vector<Variable> vec;
+ vec.push_back(Variable("name","value1"));
+ vec.push_back(Variable("name2","val with 'spaces' "));
+ vec.push_back(Variable("name3",""));
+ defs.set_server().set_user_variables(vec);
+// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
+ BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Set server variables failed " << helper.errorMsg());
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_state_fixture_defs )
+{
+ cout << "AParser:: ...test_state_fixture_defs\n";
+ PersistHelper helper;
+ MyDefsFixture theDefsFixture;
+ BOOST_REQUIRE_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(theDefsFixture.defsfile_), "Fixture failed: " << helper.errorMsg());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/AParser/test/TestParser.cpp b/AParser/test/TestParser.cpp
new file mode 100644
index 0000000..f3ef508
--- /dev/null
+++ b/AParser/test/TestParser.cpp
@@ -0,0 +1,121 @@
+#define BOOST_TEST_MODULE TestParser
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name : Request
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <string>
+#include <iostream>
+#include <fstream>
+
+#include <boost/archive/tmpdir.hpp>
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include "boost/progress.hpp"
+
+#include "DefsStructureParser.hpp"
+#include "Defs.hpp"
+#include "PrintStyle.hpp"
+#include "PersistHelper.hpp"
+#include "File.hpp"
+
+namespace fs = boost::filesystem;
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( ParserTestSuite )
+
+void test_defs(const std::string& directory, bool pass)
+{
+ fs::path full_path( fs::initial_path<fs::path>() );
+ full_path = fs::system_complete( fs::path( directory ) );
+
+ BOOST_CHECK(fs::exists( full_path ));
+ BOOST_CHECK(fs::is_directory( full_path ));
+
+ //std::cout << "\nIn directory: " << full_path.directory_string() << "\n\n";
+ fs::directory_iterator end_iter;
+ for ( fs::directory_iterator dir_itr( full_path ); dir_itr != end_iter; ++dir_itr )
+ {
+ try
+ {
+ fs::path relPath(directory + "/" + dir_itr->path().filename().string());
+
+ // recurse down directories
+ if ( fs::is_directory(dir_itr->status()) ) {
+ test_defs(relPath.string(),pass);
+ continue;
+ }
+
+ //std::cout << "......Parsing file " << relPath.string() << "\n";
+
+ Defs defs;
+ DefsStructureParser parser( &defs , relPath.string() );
+
+ std::string errorMsg,warningMsg;
+ bool parsedOk = parser.doParse(errorMsg,warningMsg);
+ if (pass) {
+ // Test expected to pass
+ BOOST_CHECK_MESSAGE(parsedOk,"Failed to parse file " << relPath << "\n" << errorMsg);
+
+ if (parsedOk) {
+ // Write parsed file to a temporary file on disk, and reload, then compare defs, should be the same
+ PersistHelper helper;
+ BOOST_CHECK_MESSAGE( helper.test_persist_and_reload(defs,parser.get_file_type()), relPath.string() << " " << helper.errorMsg());
+ BOOST_CHECK_MESSAGE( helper.test_checkpt_and_reload(defs), relPath.string() << " " << helper.errorMsg());
+ }
+ }
+ else {
+ // test expected to fail
+ //std::cout << errorMsg << "\n";
+ BOOST_CHECK_MESSAGE(!parsedOk,"Parse expected to fail for " << relPath << "\n" << errorMsg);
+ }
+ }
+ catch ( const std::exception & ex )
+ {
+ std::cout << dir_itr->path().filename() << " " << ex.what() << std::endl;
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_parsing_for_good_defs )
+{
+ cout << "AParser:: ...test_parsing_for_good_defs\n";
+
+ std::string path = File::test_data("AParser/test/data/good_defs","AParser");
+
+ // All the defs in this directory are expected to pass
+ test_defs(path, true);
+}
+
+BOOST_AUTO_TEST_CASE( test_parsing_for_bad_defs )
+{
+ cout << "AParser:: ...test_parsing_for_bad_defs\n";
+
+ std::string path = File::test_data("AParser/test/data/bad_defs","AParser");
+
+ // All the defs in this directory are expected to fail
+ test_defs(path, false);
+}
+
+BOOST_AUTO_TEST_CASE( test_parsing_for_good_defs_state )
+{
+ cout << "AParser:: ...test_parsing_for_good_defs_state\n";
+
+ std::string path = File::test_data("AParser/test/data/good_defs_state","AParser");
+
+ // All the defs in this directory are expected to pass
+ test_defs(path, true);
+}
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/AParser/test/TestSingleDefsFile.cpp b/AParser/test/TestSingleDefsFile.cpp
new file mode 100644
index 0000000..ab134c8
--- /dev/null
+++ b/AParser/test/TestSingleDefsFile.cpp
@@ -0,0 +1,304 @@
+#define BOOST_TEST_MODULE TestParser
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <string>
+#include <iostream>
+#include <fstream>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include "boost/progress.hpp"
+#include <boost/timer.hpp>
+#include "boost/date_time/posix_time/posix_time_types.hpp"
+#include <boost/test/unit_test.hpp>
+
+#include "DefsStructureParser.hpp"
+#include "Defs.hpp"
+#include "NodeContainer.hpp"
+#include "Suite.hpp"
+#include "Task.hpp"
+#include "Family.hpp"
+#include "PrintStyle.hpp"
+#include "PersistHelper.hpp"
+#include "JobsParam.hpp"
+#include "Jobs.hpp"
+#include "DurationTimer.hpp"
+#include "Log.hpp"
+#include "System.hpp"
+#include "File.hpp"
+
+namespace fs = boost::filesystem;
+using namespace std;
+using namespace ecf;
+using namespace boost::posix_time;
+
+BOOST_AUTO_TEST_SUITE( ParserTestSuite )
+
+// This test is used to find a task given a path of the form:
+// suite/family/task
+// suite/family/family/task
+void test_find_task_using_path( NodeContainer* f,const Defs& defs )
+{
+ BOOST_CHECK_MESSAGE(f == defs.findAbsNode(f->absNodePath()).get(), "Could not find path " << f->absNodePath() << "\n");
+
+ BOOST_FOREACH(node_ptr t, f->nodeVec()) {
+ BOOST_CHECK_MESSAGE(t.get() == defs.findAbsNode(t->absNodePath()).get(), "Could not find path " << t->absNodePath() << "\n");
+ Family* family = t->isFamily();
+ if (family) {
+ test_find_task_using_path(family, defs);
+ }
+ }
+}
+
+// Create derived class, so that we can time the parse only
+// i.e ignore expression build/checking and limit checking
+class TestDefsStructureParser : public DefsStructureParser {
+public:
+ TestDefsStructureParser(Defs* defsfile, const std::string& file_name) : DefsStructureParser(defsfile,file_name) {}
+ bool do_parse_only(std::string& errorMsg) { return DefsStructureParser::do_parse_only(errorMsg); }
+};
+
+BOOST_AUTO_TEST_CASE( test_single_defs )
+{
+ DurationTimer duration_timer;
+
+ std::string path = File::test_data("AParser/test/data/single_defs/mega.def","AParser");
+ size_t mega_file_size = fs::file_size(path);
+ cout << "AParser:: ...test_single_defs " << path << " file_size(" << mega_file_size << ")\n";
+
+ // Time parse/resolve dependencies: This will need to be #defined depending on the platform
+ // Change for file_iterator to plain string halved the time taken to load operation suite
+ boost::timer timer; // measures CPU, replace with cpu_timer with boost > 1.51, measures cpu & elapsed
+#ifdef DEBUG
+#if defined(HPUX) || defined(_AIX)
+ double expectedTimeForParse = 15.0;
+ double expectedTimeForParseOnly = 10.0;
+ double expectedTimeForResolveDependencies = 3.5; // this is time for 10 job submissions
+ double checkExprAndLimits = 1.0;
+ double expectedTimeForFindAllPaths = 7.2;
+ double expectedTimeForDefsPersistOnly = 6 ;
+ double expectedTimeForDefsPersistAndReload = 24;
+ double expectedTimeForCheckPtPersistAndReload = 27;
+#else
+ double expectedTimeForParse = 4.5;
+ double expectedTimeForParseOnly = 2.0;
+ double expectedTimeForResolveDependencies = 0.5 ; // this is time for 10 job submissions
+ double checkExprAndLimits = 0.5;
+ double expectedTimeForFindAllPaths = 1.2;
+ double expectedTimeForDefsPersistOnly = 2 ;
+ double expectedTimeForDefsPersistAndReload = 4.5;
+ double expectedTimeForCheckPtPersistAndReload = 8.0;
+#endif
+#else
+#if defined(HPUX) || defined(_AIX)
+ double expectedTimeForParse = 7.8;
+ double expectedTimeForParseOnly = 5.0;
+ double expectedTimeForResolveDependencies = 3.5; // this is time for 10 job submissions
+ double checkExprAndLimits = 1.0;
+ double expectedTimeForFindAllPaths = 4.5;
+ double expectedTimeForDefsPersistOnly = 3.5 ;
+ double expectedTimeForDefsPersistAndReload = 9.5;
+ double expectedTimeForCheckPtPersistAndReload = 11.5;
+#else
+ double expectedTimeForParse = 1.2;
+ double expectedTimeForParseOnly = 0.6;
+ double expectedTimeForResolveDependencies = 0.2 ; // this is time for 10 job submissions
+ double checkExprAndLimits = 0.1;
+ double expectedTimeForFindAllPaths = 0.58;
+ double expectedTimeForDefsPersistOnly = 0.5 ;
+ double expectedTimeForDefsPersistAndReload = 1.5;
+ double expectedTimeForCheckPtPersistAndReload = 1.6;
+#endif
+#endif
+ // ****************************************************************************************
+ // Please note: that for Parsing: that the predominate time is taken in creating the AST/ and checking
+
+ /// If this is moved below, we get some caching affect, with the persist and reload timing
+ Defs defs;
+ {
+ timer.restart();
+ DefsStructureParser checkPtParser( &defs, path);
+ std::string errorMsg,warningMsg;
+ BOOST_REQUIRE_MESSAGE(checkPtParser.doParse(errorMsg,warningMsg),errorMsg);
+ BOOST_CHECK_MESSAGE(timer.elapsed() < expectedTimeForParse,"Performance regression, expected < " << expectedTimeForParse << " seconds for parse/node tree creation but found " << timer.elapsed());
+ std::cout << " Parsing Node tree and AST creation time = " << timer.elapsed() << " < limit(" << expectedTimeForParse << ")" << endl;
+ }
+
+ {
+ Defs local_defs;
+ timer.restart();
+ TestDefsStructureParser checkPtParser( &local_defs, path);
+ std::string errorMsg;
+ BOOST_REQUIRE_MESSAGE(checkPtParser.do_parse_only(errorMsg),errorMsg);
+ BOOST_CHECK_MESSAGE(timer.elapsed() < expectedTimeForParse,"Performance regression, expected < " << expectedTimeForParseOnly << " seconds for parse/node tree creation but found " << timer.elapsed());
+ std::cout << " Parsing Node tree *only* time = " << timer.elapsed() << " < limit(" << expectedTimeForParseOnly << ")" << endl;
+ }
+
+
+ {
+ timer.restart();
+ BOOST_FOREACH(suite_ptr s, defs.suiteVec()) { test_find_task_using_path(s.get(),defs); }
+ BOOST_CHECK_MESSAGE(timer.elapsed() < expectedTimeForFindAllPaths,"Performance regression, expected < " << expectedTimeForFindAllPaths << " seconds to find all paths, but found " << timer.elapsed());
+ cout << " Test all paths can be found. time taken = " << timer.elapsed() << " < limit(" << expectedTimeForFindAllPaths << ")" << endl;
+ }
+
+ {
+ // Test time for persisting to defs file only
+#ifdef DEBUG
+ std::string tmpFilename = "tmp_d.def";
+#else
+ std::string tmpFilename = "tmp.def";
+#endif
+
+ timer.restart();
+ PrintStyle style(PrintStyle::DEFS);
+ std::ofstream ofs( tmpFilename.c_str() ); ofs << defs;
+ BOOST_CHECK_MESSAGE(timer.elapsed() < expectedTimeForDefsPersistOnly,"Performance regression, expected < " << expectedTimeForDefsPersistOnly << " to persist defs file, but found " << timer.elapsed());
+ cout << " Persist only, time taken = " << timer.elapsed() << " < limit(" << expectedTimeForDefsPersistOnly << ")" << endl;
+
+ std::remove(tmpFilename.c_str());
+ }
+
+ {
+ // may need to comment out output for large differences. Will double the time.
+ timer.restart();
+ PersistHelper helper;
+ BOOST_CHECK_MESSAGE( helper.test_persist_and_reload(defs,PrintStyle::DEFS), helper.errorMsg());
+ BOOST_CHECK_MESSAGE(timer.elapsed() < expectedTimeForDefsPersistAndReload,"Performance regression, expected < " << expectedTimeForDefsPersistAndReload << " seconds to persist and reload, but found " << timer.elapsed());
+ cout << " Persist and reload(DEFS) and compare, time taken = "
+ << timer.elapsed() << " < limit(" << expectedTimeForDefsPersistAndReload << ")"
+ << " file_size(" << helper.file_size() << ")" << endl;
+ }
+ {
+ timer.restart();
+ PersistHelper helper;
+ BOOST_CHECK_MESSAGE( helper.test_persist_and_reload(defs,PrintStyle::STATE), helper.errorMsg());
+ cout << " Persist and reload(STATE) and compare, time taken = " << timer.elapsed()
+ << " file_size(" << helper.file_size() << ")" << endl;
+ }
+ {
+ timer.restart();
+ PersistHelper helper;
+ BOOST_CHECK_MESSAGE( helper.test_persist_and_reload(defs,PrintStyle::MIGRATE), helper.errorMsg());
+ BOOST_CHECK_MESSAGE(timer.elapsed() < expectedTimeForDefsPersistAndReload,"Performance regression, expected < " << expectedTimeForDefsPersistAndReload << " seconds to persist and reload *state*, but found " << timer.elapsed());
+ cout << " Persist and reload(MIGRATE) and compare, time taken = "
+ << timer.elapsed() << " < limit(" << expectedTimeForDefsPersistAndReload << ")"
+ << " file_size(" << helper.file_size() << ")" << endl;
+
+ // each platform will have a slightly different size, since the server environment variables
+ // will be different, i.e host, pid, i.e check point etc, encompasses the host name, which will be different
+ BOOST_CHECK_MESSAGE(helper.file_size() <= 6679000 ,"File size regression expected <= 6679000 but found " << helper.file_size());
+ }
+
+#if defined(BINARY_ARCHIVE)
+ {
+ timer.restart();
+ PersistHelper helper;
+ BOOST_CHECK_MESSAGE( helper.test_checkpt_and_reload(defs,true,ecf::Archive::BINARY), helper.errorMsg());
+ BOOST_CHECK_MESSAGE(timer.elapsed() < expectedTimeForCheckPtPersistAndReload,"Performance regression, expected < " << expectedTimeForCheckPtPersistAndReload << " seconds to persist and reload, but found " << timer.elapsed());
+ cout << " Checkpt(BINARY_ARCHIVE) and reload and compare, time taken = ";
+ cout << timer.elapsed() << " < limit(" << expectedTimeForCheckPtPersistAndReload << ")" << " file_size(" << helper.file_size() << ")" << endl;
+ }
+#elif defined(PORTABLE_BINARY_ARCHIVE)
+ {
+ timer.restart();
+ PersistHelper helper;
+ BOOST_CHECK_MESSAGE( helper.test_checkpt_and_reload(defs,true,ecf::Archive::PORTABLE_BINARY), helper.errorMsg());
+ BOOST_CHECK_MESSAGE(timer.elapsed() < expectedTimeForCheckPtPersistAndReload,"Performance regression, expected < " << expectedTimeForCheckPtPersistAndReload << " seconds to persist and reload, but found " << timer.elapsed());
+ cout << " Checkpt(PORTABLE_BINARY) and reload and compare, time taken = ";
+ cout << timer.elapsed() << " < limit(" << expectedTimeForCheckPtPersistAndReload << ")" << " file_size(" << helper.file_size() << ")" << endl;
+ }
+#elif defined(EOS_PORTABLE_BINARY_ARCHIVE)
+ {
+ timer.restart();
+ PersistHelper helper;
+ BOOST_CHECK_MESSAGE( helper.test_checkpt_and_reload(defs,true,ecf::Archive::EOS_PORTABLE_BINARY), helper.errorMsg());
+ BOOST_CHECK_MESSAGE(timer.elapsed() < expectedTimeForCheckPtPersistAndReload,"Performance regression, expected < " << expectedTimeForCheckPtPersistAndReload << " seconds to persist and reload, but found " << timer.elapsed());
+ cout << " Checkpt(EOS_PORTABLE_BINARY) and reload and compare, time taken = ";
+ cout << timer.elapsed() << " < limit(" << expectedTimeForCheckPtPersistAndReload << ")" << " file_size(" << helper.file_size() << ")" << endl;
+ }
+#else
+ {
+ timer.restart();
+ PersistHelper helper;
+ BOOST_CHECK_MESSAGE( helper.test_checkpt_and_reload(defs,true,ecf::Archive::TEXT), helper.errorMsg());
+ BOOST_CHECK_MESSAGE(timer.elapsed() < expectedTimeForCheckPtPersistAndReload,"Performance regression, expected < " << expectedTimeForCheckPtPersistAndReload << " seconds to persist and reload, but found " << timer.elapsed());
+ cout << " Checkpt(TEXT_ARCHIVE) and reload and compare, time taken = ";
+ cout << timer.elapsed() << " < limit(" << expectedTimeForCheckPtPersistAndReload << ")" << " file_size(" << helper.file_size() << ")" << endl;
+ }
+#endif
+
+ {
+ // Time how long it takes for job submission. Must call begin on all suites first.
+ timer.restart();
+ defs.beginAll();
+ int count = 10;
+ JobsParam jobsParam; // default is *not* to create jobs, and *not* to spawn jobs, hence only used in testing
+ Jobs jobs(&defs);
+ for (int i = 0; i < count; i++) {jobs.generate(jobsParam);}
+ cout << " time for " << count << " jobSubmissions:" << timer.elapsed() << "s jobs:" << jobsParam.submitted().size() << " < limit(" << expectedTimeForResolveDependencies << ")" << endl;
+ BOOST_CHECK_MESSAGE(timer.elapsed() < expectedTimeForResolveDependencies,
+ "jobSubmission Performance regression, expected < " << expectedTimeForResolveDependencies << " seconds for resolving dependencies but found " << timer.elapsed() );
+ }
+
+ {
+ // Time how long it takes for post process
+ timer.restart();
+ string errorMsg,warningMsg;
+ BOOST_CHECK(defs.check(errorMsg,warningMsg));
+ cout << " time for Defs::check ( inlimit resolution) = " << timer.elapsed() << " < limit(" << checkExprAndLimits << ")" << endl;
+ BOOST_CHECK_MESSAGE(timer.elapsed() < checkExprAndLimits,
+ "Defs::check Performance regression, expected < " << checkExprAndLimits << " seconds for resolving dependencies but found " << timer.elapsed() );
+ }
+
+ {
+ // Time how long it takes to delete all nodes/ references. Delete all tasks and then suites/families.
+ timer.restart();
+ std::vector<Task*> tasks;
+ defs.getAllTasks(tasks);
+ BOOST_CHECK_MESSAGE( tasks.size() > 0,"Expected > 0 tasks but found " << tasks.size());
+ BOOST_FOREACH(Task* t, tasks) {
+ BOOST_REQUIRE_MESSAGE(defs.deleteChild(t)," Failed to delete task");
+ }
+ tasks.clear(); defs.getAllTasks(tasks);
+ BOOST_REQUIRE_MESSAGE( tasks.empty(),"Expected all tasks to be deleted but found " << tasks.size());
+
+ std::vector<suite_ptr> vec = defs.suiteVec(); // make a copy, to avoid invalidating iterators
+ BOOST_CHECK_MESSAGE( vec.size() > 0,"Expected > 0 Suites but found " << vec.size());
+ BOOST_FOREACH(suite_ptr s, vec) {
+ std::vector<node_ptr> familyVec = s->nodeVec(); // make a copy, to avoid invalidating iterators
+ BOOST_FOREACH(node_ptr f, familyVec) {
+ BOOST_REQUIRE_MESSAGE(defs.deleteChild(f.get())," Failed to delete family");
+ }
+ BOOST_REQUIRE_MESSAGE( s->nodeVec().empty(),"Expected all Families to be deleted but found " << s->nodeVec().size());
+ BOOST_REQUIRE_MESSAGE(defs.deleteChild(s.get())," Failed to delete suite");
+ }
+ BOOST_REQUIRE_MESSAGE( defs.suiteVec().empty(),"Expected all Suites to be deleted but found " << defs.suiteVec().size());
+
+ cout << " time for deleting all nodes = " << timer.elapsed() << endl;
+ }
+
+ // Explicitly destroy, To keep valgrind happy
+ Log::destroy();
+ System::destroy();
+
+ // cout << "Printing Defs \n";
+ // PrintStyle style(PrintStyle::DEFS);
+ // std::cout << defs;
+ cout << " Total elapsed time = " << duration_timer.duration() << " seconds\n";
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/AParser/test/TestVariableParsing.cpp b/AParser/test/TestVariableParsing.cpp
new file mode 100644
index 0000000..7f6b324
--- /dev/null
+++ b/AParser/test/TestVariableParsing.cpp
@@ -0,0 +1,81 @@
+ //============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <string>
+#include <iostream>
+#include <fstream>
+
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+
+#include "DefsStructureParser.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "File.hpp"
+
+namespace fs = boost::filesystem;
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( ParserTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_single_defs ) {
+
+ cout << "AParser:: ...test_variable \n";
+
+ std::string path = File::test_data("AParser/test/data/good_defs/edit/edit.def","AParser");
+
+ Defs defs;
+ DefsStructureParser checkPtParser( &defs, path );
+ std::string errorMsg,warningMsg;
+ BOOST_REQUIRE_MESSAGE(checkPtParser.doParse(errorMsg,warningMsg),errorMsg);
+
+// suite edit
+// edit ECF_INCLUDE /home/ma/map/sms/example/x # comment line
+// edit ECF_FILES /home/ma/map/sms/example/x #comment line
+// edit EXPVER 'f8na' #
+// edit USER 'ecgems' #comment
+// edit USER2 "ecgems" # comment
+// edit INT1 "10" # comment
+// edit INT2 '11' # comment
+// edit YMD '20091012' # comment
+// family family
+// edit var "smsfetch -F %ECF_FILES% -I %ECF_INCLUDE%" # comment line
+// edit var2 'smsfetch -F %ECF_FILES% -I %ECF_INCLUDE%' #comment line
+// task t2
+// endfamily
+// endsuite
+ suite_ptr editSuite = defs.findSuite("edit");
+ BOOST_REQUIRE_MESSAGE(editSuite,"Could not find the edit suite");
+
+ const Variable& int1 = editSuite->findVariable("INT1");
+ BOOST_REQUIRE_MESSAGE(!int1.empty(),"Could not find variable INT1");
+ BOOST_REQUIRE_MESSAGE(int1.value() == 10,"Expected INT1 to have a value of 10, but found " << int1.value());
+
+ const Variable& int2 = editSuite->findVariable("INT2");
+ BOOST_REQUIRE_MESSAGE(!int2.empty(),"Could not find variable INT2");
+ BOOST_REQUIRE_MESSAGE(int2.value() == 11,"Expected INT2 to have a value of 11, but found " << int2.value());
+
+ const Variable& ymd = editSuite->findVariable("YMD");
+ BOOST_REQUIRE_MESSAGE(!ymd.empty(),"Could not find variable YMD");
+ BOOST_REQUIRE_MESSAGE(ymd.value() == 20091012,"Expected YMD to have a value of 20091012, but found " << ymd.value());
+
+ const Variable& user = editSuite->findVariable("USER");
+ BOOST_REQUIRE_MESSAGE(!user.empty(),"Could not find variable USER");
+ BOOST_REQUIRE_MESSAGE(user.value() == 0,"Expected user to have a value of 0, but found " << user.value());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/clock/clock1.def b/AParser/test/data/bad_defs/clock/clock1.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/clock/clock1.def
rename to AParser/test/data/bad_defs/clock/clock1.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/clock/clock2.def b/AParser/test/data/bad_defs/clock/clock2.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/clock/clock2.def
rename to AParser/test/data/bad_defs/clock/clock2.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/cron/cron1.def b/AParser/test/data/bad_defs/cron/cron1.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/cron/cron1.def
rename to AParser/test/data/bad_defs/cron/cron1.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/cron/cron2.def b/AParser/test/data/bad_defs/cron/cron2.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/cron/cron2.def
rename to AParser/test/data/bad_defs/cron/cron2.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/cron/cron3.def b/AParser/test/data/bad_defs/cron/cron3.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/cron/cron3.def
rename to AParser/test/data/bad_defs/cron/cron3.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/cron/cron4.def b/AParser/test/data/bad_defs/cron/cron4.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/cron/cron4.def
rename to AParser/test/data/bad_defs/cron/cron4.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/cron/cron5.def b/AParser/test/data/bad_defs/cron/cron5.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/cron/cron5.def
rename to AParser/test/data/bad_defs/cron/cron5.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/cron/cron5_1.def b/AParser/test/data/bad_defs/cron/cron5_1.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/cron/cron5_1.def
rename to AParser/test/data/bad_defs/cron/cron5_1.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/cron/cron6.def b/AParser/test/data/bad_defs/cron/cron6.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/cron/cron6.def
rename to AParser/test/data/bad_defs/cron/cron6.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/cron/cron7.def b/AParser/test/data/bad_defs/cron/cron7.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/cron/cron7.def
rename to AParser/test/data/bad_defs/cron/cron7.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/cron/repeat_with_cron.def b/AParser/test/data/bad_defs/cron/repeat_with_cron.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/cron/repeat_with_cron.def
rename to AParser/test/data/bad_defs/cron/repeat_with_cron.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/date/date.def b/AParser/test/data/bad_defs/date/date.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/date/date.def
rename to AParser/test/data/bad_defs/date/date.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/date/date0.def b/AParser/test/data/bad_defs/date/date0.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/date/date0.def
rename to AParser/test/data/bad_defs/date/date0.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/date/date1.def b/AParser/test/data/bad_defs/date/date1.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/date/date1.def
rename to AParser/test/data/bad_defs/date/date1.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/date/date2.def b/AParser/test/data/bad_defs/date/date2.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/date/date2.def
rename to AParser/test/data/bad_defs/date/date2.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/date/date3.def b/AParser/test/data/bad_defs/date/date3.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/date/date3.def
rename to AParser/test/data/bad_defs/date/date3.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/date/date4.def b/AParser/test/data/bad_defs/date/date4.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/date/date4.def
rename to AParser/test/data/bad_defs/date/date4.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/date/date5.def b/AParser/test/data/bad_defs/date/date5.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/date/date5.def
rename to AParser/test/data/bad_defs/date/date5.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/day/day.def b/AParser/test/data/bad_defs/day/day.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/day/day.def
rename to AParser/test/data/bad_defs/day/day.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/defstatus/defstatus.def b/AParser/test/data/bad_defs/defstatus/defstatus.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/defstatus/defstatus.def
rename to AParser/test/data/bad_defs/defstatus/defstatus.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/event/event_1.def b/AParser/test/data/bad_defs/event/event_1.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/event/event_1.def
rename to AParser/test/data/bad_defs/event/event_1.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/event/event_2.def b/AParser/test/data/bad_defs/event/event_2.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/event/event_2.def
rename to AParser/test/data/bad_defs/event/event_2.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/event/event_3.def b/AParser/test/data/bad_defs/event/event_3.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/event/event_3.def
rename to AParser/test/data/bad_defs/event/event_3.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/event/event_4.def b/AParser/test/data/bad_defs/event/event_4.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/event/event_4.def
rename to AParser/test/data/bad_defs/event/event_4.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/event/simple_event.txt b/AParser/test/data/bad_defs/event/simple_event.txt
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/event/simple_event.txt
rename to AParser/test/data/bad_defs/event/simple_event.txt
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/extern/bad.def b/AParser/test/data/bad_defs/extern/bad.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/extern/bad.def
rename to AParser/test/data/bad_defs/extern/bad.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/extern/complete.def b/AParser/test/data/bad_defs/extern/complete.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/extern/complete.def
rename to AParser/test/data/bad_defs/extern/complete.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/extern/trigger1.def b/AParser/test/data/bad_defs/extern/trigger1.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/extern/trigger1.def
rename to AParser/test/data/bad_defs/extern/trigger1.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/extern/trigger2.def b/AParser/test/data/bad_defs/extern/trigger2.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/extern/trigger2.def
rename to AParser/test/data/bad_defs/extern/trigger2.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/family/family.def b/AParser/test/data/bad_defs/family/family.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/family/family.def
rename to AParser/test/data/bad_defs/family/family.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/family/family_1.def b/AParser/test/data/bad_defs/family/family_1.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/family/family_1.def
rename to AParser/test/data/bad_defs/family/family_1.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/family/simple_family.txt b/AParser/test/data/bad_defs/family/simple_family.txt
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/family/simple_family.txt
rename to AParser/test/data/bad_defs/family/simple_family.txt
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/inlimit/limit.def b/AParser/test/data/bad_defs/inlimit/limit.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/inlimit/limit.def
rename to AParser/test/data/bad_defs/inlimit/limit.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/inlimit/limt2.def b/AParser/test/data/bad_defs/inlimit/limt2.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/inlimit/limt2.def
rename to AParser/test/data/bad_defs/inlimit/limt2.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/late/late.def b/AParser/test/data/bad_defs/late/late.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/late/late.def
rename to AParser/test/data/bad_defs/late/late.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/late/late2.def b/AParser/test/data/bad_defs/late/late2.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/late/late2.def
rename to AParser/test/data/bad_defs/late/late2.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/late/late3.def b/AParser/test/data/bad_defs/late/late3.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/late/late3.def
rename to AParser/test/data/bad_defs/late/late3.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/late/late4.def b/AParser/test/data/bad_defs/late/late4.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/late/late4.def
rename to AParser/test/data/bad_defs/late/late4.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/limit/limit.def b/AParser/test/data/bad_defs/limit/limit.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/limit/limit.def
rename to AParser/test/data/bad_defs/limit/limit.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/meter/meter.def b/AParser/test/data/bad_defs/meter/meter.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/meter/meter.def
rename to AParser/test/data/bad_defs/meter/meter.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/meter/meter2.def b/AParser/test/data/bad_defs/meter/meter2.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/meter/meter2.def
rename to AParser/test/data/bad_defs/meter/meter2.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/meter/meter3.def b/AParser/test/data/bad_defs/meter/meter3.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/meter/meter3.def
rename to AParser/test/data/bad_defs/meter/meter3.def
diff --git a/AParser/test/data/bad_defs/repeat/date_missing_name.def b/AParser/test/data/bad_defs/repeat/date_missing_name.def
new file mode 100644
index 0000000..f6ff3ad
--- /dev/null
+++ b/AParser/test/data/bad_defs/repeat/date_missing_name.def
@@ -0,0 +1,3 @@
+suite s1
+ repeat date 20090331 20121212 1
+endsuite
\ No newline at end of file
diff --git a/AParser/test/data/bad_defs/repeat/duplicate_repeats_per_node.def b/AParser/test/data/bad_defs/repeat/duplicate_repeats_per_node.def
new file mode 100644
index 0000000..0e95325
--- /dev/null
+++ b/AParser/test/data/bad_defs/repeat/duplicate_repeats_per_node.def
@@ -0,0 +1,4 @@
+suite s1
+ repeat date YMD 20090331 20121212 1 # status 0
+ repeat date YMD1 20090331 20121212 1 # status 0
+endsuite
\ No newline at end of file
diff --git a/AParser/test/data/bad_defs/repeat/invalid_dates.def b/AParser/test/data/bad_defs/repeat/invalid_dates.def
new file mode 100644
index 0000000..13661d0
--- /dev/null
+++ b/AParser/test/data/bad_defs/repeat/invalid_dates.def
@@ -0,0 +1,3 @@
+suite s1
+ repeat date YMD 20091901 20091501 # should have format yyyymmdd 19 and 15 ar not valid months
+endsuite
\ No newline at end of file
diff --git a/AParser/test/data/bad_defs/repeat/invalid_dates_2.def b/AParser/test/data/bad_defs/repeat/invalid_dates_2.def
new file mode 100644
index 0000000..88668aa
--- /dev/null
+++ b/AParser/test/data/bad_defs/repeat/invalid_dates_2.def
@@ -0,0 +1,3 @@
+suite s1
+ repeat date YMD 20091099 20091501 # should have format yyyymmdd invalid day of month
+endsuite
\ No newline at end of file
diff --git a/AParser/test/data/bad_defs/repeat/repeat_date1.def b/AParser/test/data/bad_defs/repeat/repeat_date1.def
new file mode 100644
index 0000000..0c7f37e
--- /dev/null
+++ b/AParser/test/data/bad_defs/repeat/repeat_date1.def
@@ -0,0 +1,3 @@
+suite s1
+ repeat date YMD 20091001 20090901 1 # start date is > end date, when delta > 0
+endsuite
\ No newline at end of file
diff --git a/AParser/test/data/bad_defs/repeat/repeat_date2.def b/AParser/test/data/bad_defs/repeat/repeat_date2.def
new file mode 100644
index 0000000..9d9211c
--- /dev/null
+++ b/AParser/test/data/bad_defs/repeat/repeat_date2.def
@@ -0,0 +1,3 @@
+suite s1
+repeat date YMD 20090901 20091001 -1 # start date is < end date, when delta < 0
+endsuite
\ No newline at end of file
diff --git a/AParser/test/data/bad_defs/repeat/repeat_date3.def b/AParser/test/data/bad_defs/repeat/repeat_date3.def
new file mode 100644
index 0000000..dc2e4fc
--- /dev/null
+++ b/AParser/test/data/bad_defs/repeat/repeat_date3.def
@@ -0,0 +1,3 @@
+suite s1
+repeat date YMD 20090901 20091010 0 # 0 is an invalid delta
+endsuite
\ No newline at end of file
diff --git a/AParser/test/data/bad_defs/repeat/repeat_integer.def b/AParser/test/data/bad_defs/repeat/repeat_integer.def
new file mode 100644
index 0000000..251d5d5
--- /dev/null
+++ b/AParser/test/data/bad_defs/repeat/repeat_integer.def
@@ -0,0 +1,5 @@
+suite s
+ repeat integer VARIABLE 0 10 2 # comment
+ repeat integer VARIABLE 0 10 # duplicate variable name
+ repeat integer VARIABLE 0 10 # duplicate variable name
+endsuite
\ No newline at end of file
diff --git a/AParser/test/data/bad_defs/repeat/repeat_month.def b/AParser/test/data/bad_defs/repeat/repeat_month.def
new file mode 100644
index 0000000..3849ffe
--- /dev/null
+++ b/AParser/test/data/bad_defs/repeat/repeat_month.def
@@ -0,0 +1,4 @@
+suite s
+ repeat month 2 #111
+endsuite
+
\ No newline at end of file
diff --git a/AParser/test/data/bad_defs/repeat/repeat_with_cron.def b/AParser/test/data/bad_defs/repeat/repeat_with_cron.def
new file mode 100644
index 0000000..ad1c918
--- /dev/null
+++ b/AParser/test/data/bad_defs/repeat/repeat_with_cron.def
@@ -0,0 +1,4 @@
+suite s
+ repeat date YMD 20090331 20121212 1 # status 0
+ cron 10:00 23:00 00:10 # cant have repeat & cron time series at same level
+endsuite
diff --git a/AParser/test/data/bad_defs/repeat/repeat_year.def b/AParser/test/data/bad_defs/repeat/repeat_year.def
new file mode 100644
index 0000000..ffbbc6d
--- /dev/null
+++ b/AParser/test/data/bad_defs/repeat/repeat_year.def
@@ -0,0 +1,3 @@
+suite s
+ repeat year 3 20090331 20121212 1 # status 0
+endsuite
\ No newline at end of file
diff --git a/AParser/test/data/bad_defs/repeat/string_missing_name.def b/AParser/test/data/bad_defs/repeat/string_missing_name.def
new file mode 100644
index 0000000..f28c53d
--- /dev/null
+++ b/AParser/test/data/bad_defs/repeat/string_missing_name.def
@@ -0,0 +1,3 @@
+suite s
+ repeat string
+endsuite
\ No newline at end of file
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/suite/clock.def b/AParser/test/data/bad_defs/suite/clock.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/suite/clock.def
rename to AParser/test/data/bad_defs/suite/clock.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/suite/clock1.def b/AParser/test/data/bad_defs/suite/clock1.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/suite/clock1.def
rename to AParser/test/data/bad_defs/suite/clock1.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/suite/simple_suite.txt b/AParser/test/data/bad_defs/suite/simple_suite.txt
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/suite/simple_suite.txt
rename to AParser/test/data/bad_defs/suite/simple_suite.txt
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/task/simple_task.txt b/AParser/test/data/bad_defs/task/simple_task.txt
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/task/simple_task.txt
rename to AParser/test/data/bad_defs/task/simple_task.txt
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/task/task.def b/AParser/test/data/bad_defs/task/task.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/task/task.def
rename to AParser/test/data/bad_defs/task/task.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/task/task_1.def b/AParser/test/data/bad_defs/task/task_1.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/task/task_1.def
rename to AParser/test/data/bad_defs/task/task_1.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/time/time.def b/AParser/test/data/bad_defs/time/time.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/time/time.def
rename to AParser/test/data/bad_defs/time/time.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/time/time_1.def b/AParser/test/data/bad_defs/time/time_1.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/time/time_1.def
rename to AParser/test/data/bad_defs/time/time_1.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/time/time_2.def b/AParser/test/data/bad_defs/time/time_2.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/time/time_2.def
rename to AParser/test/data/bad_defs/time/time_2.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/time/time_3.def b/AParser/test/data/bad_defs/time/time_3.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/time/time_3.def
rename to AParser/test/data/bad_defs/time/time_3.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/time/time_4.def b/AParser/test/data/bad_defs/time/time_4.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/time/time_4.def
rename to AParser/test/data/bad_defs/time/time_4.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/time/time_5.def b/AParser/test/data/bad_defs/time/time_5.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/time/time_5.def
rename to AParser/test/data/bad_defs/time/time_5.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/time/time_6.def b/AParser/test/data/bad_defs/time/time_6.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/time/time_6.def
rename to AParser/test/data/bad_defs/time/time_6.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/time/time_7.def b/AParser/test/data/bad_defs/time/time_7.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/time/time_7.def
rename to AParser/test/data/bad_defs/time/time_7.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/time/time_8.def b/AParser/test/data/bad_defs/time/time_8.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/time/time_8.def
rename to AParser/test/data/bad_defs/time/time_8.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/today/today.def b/AParser/test/data/bad_defs/today/today.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/today/today.def
rename to AParser/test/data/bad_defs/today/today.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/today/today1.def b/AParser/test/data/bad_defs/today/today1.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/today/today1.def
rename to AParser/test/data/bad_defs/today/today1.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/trigger/bad_trigger2.txt b/AParser/test/data/bad_defs/trigger/bad_trigger2.txt
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/trigger/bad_trigger2.txt
rename to AParser/test/data/bad_defs/trigger/bad_trigger2.txt
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/trigger/bad_trigger3.txt b/AParser/test/data/bad_defs/trigger/bad_trigger3.txt
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/trigger/bad_trigger3.txt
rename to AParser/test/data/bad_defs/trigger/bad_trigger3.txt
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/trigger/bad_trigger4.txt b/AParser/test/data/bad_defs/trigger/bad_trigger4.txt
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/trigger/bad_trigger4.txt
rename to AParser/test/data/bad_defs/trigger/bad_trigger4.txt
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/trigger/bad_trigger5.txt b/AParser/test/data/bad_defs/trigger/bad_trigger5.txt
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/trigger/bad_trigger5.txt
rename to AParser/test/data/bad_defs/trigger/bad_trigger5.txt
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/trigger/complex.def b/AParser/test/data/bad_defs/trigger/complex.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/trigger/complex.def
rename to AParser/test/data/bad_defs/trigger/complex.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/trigger/divide_by_zero.txt b/AParser/test/data/bad_defs/trigger/divide_by_zero.txt
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/trigger/divide_by_zero.txt
rename to AParser/test/data/bad_defs/trigger/divide_by_zero.txt
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/trigger/extern_trigger.def b/AParser/test/data/bad_defs/trigger/extern_trigger.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/trigger/extern_trigger.def
rename to AParser/test/data/bad_defs/trigger/extern_trigger.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/trigger/modulo_by_zero.txt b/AParser/test/data/bad_defs/trigger/modulo_by_zero.txt
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/trigger/modulo_by_zero.txt
rename to AParser/test/data/bad_defs/trigger/modulo_by_zero.txt
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/trigger/simple_trigger_bad_expression.txt b/AParser/test/data/bad_defs/trigger/simple_trigger_bad_expression.txt
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/trigger/simple_trigger_bad_expression.txt
rename to AParser/test/data/bad_defs/trigger/simple_trigger_bad_expression.txt
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/trigger/trigger.txt b/AParser/test/data/bad_defs/trigger/trigger.txt
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/trigger/trigger.txt
rename to AParser/test/data/bad_defs/trigger/trigger.txt
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/trigger/trigger_1.def b/AParser/test/data/bad_defs/trigger/trigger_1.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/trigger/trigger_1.def
rename to AParser/test/data/bad_defs/trigger/trigger_1.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/variable/bad.def b/AParser/test/data/bad_defs/variable/bad.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/variable/bad.def
rename to AParser/test/data/bad_defs/variable/bad.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/variable/bad1.def b/AParser/test/data/bad_defs/variable/bad1.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/variable/bad1.def
rename to AParser/test/data/bad_defs/variable/bad1.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/variable/bad2.def b/AParser/test/data/bad_defs/variable/bad2.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/variable/bad2.def
rename to AParser/test/data/bad_defs/variable/bad2.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/variable/bad3.def b/AParser/test/data/bad_defs/variable/bad3.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/variable/bad3.def
rename to AParser/test/data/bad_defs/variable/bad3.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/variable/bad4.def b/AParser/test/data/bad_defs/variable/bad4.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/variable/bad4.def
rename to AParser/test/data/bad_defs/variable/bad4.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/variable/bad5.def b/AParser/test/data/bad_defs/variable/bad5.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/variable/bad5.def
rename to AParser/test/data/bad_defs/variable/bad5.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/variable/comment.def b/AParser/test/data/bad_defs/variable/comment.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/variable/comment.def
rename to AParser/test/data/bad_defs/variable/comment.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/variable/comment2.def b/AParser/test/data/bad_defs/variable/comment2.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/variable/comment2.def
rename to AParser/test/data/bad_defs/variable/comment2.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/verify/verfiy3.def b/AParser/test/data/bad_defs/verify/verfiy3.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/verify/verfiy3.def
rename to AParser/test/data/bad_defs/verify/verfiy3.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/verify/verify.def b/AParser/test/data/bad_defs/verify/verify.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/verify/verify.def
rename to AParser/test/data/bad_defs/verify/verify.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/verify/verify2.def b/AParser/test/data/bad_defs/verify/verify2.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/verify/verify2.def
rename to AParser/test/data/bad_defs/verify/verify2.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/verify/verify4.def b/AParser/test/data/bad_defs/verify/verify4.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/verify/verify4.def
rename to AParser/test/data/bad_defs/verify/verify4.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/zombie/bad.def b/AParser/test/data/bad_defs/zombie/bad.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/zombie/bad.def
rename to AParser/test/data/bad_defs/zombie/bad.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/zombie/bad2.def b/AParser/test/data/bad_defs/zombie/bad2.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/zombie/bad2.def
rename to AParser/test/data/bad_defs/zombie/bad2.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/zombie/bad3.def b/AParser/test/data/bad_defs/zombie/bad3.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/zombie/bad3.def
rename to AParser/test/data/bad_defs/zombie/bad3.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/zombie/bad4.def b/AParser/test/data/bad_defs/zombie/bad4.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/zombie/bad4.def
rename to AParser/test/data/bad_defs/zombie/bad4.def
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/zombie/bad5.def b/AParser/test/data/bad_defs/zombie/bad5.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/bad_defs/zombie/bad5.def
rename to AParser/test/data/bad_defs/zombie/bad5.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/clock/clock.def b/AParser/test/data/good_defs/clock/clock.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/clock/clock.def
rename to AParser/test/data/good_defs/clock/clock.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/clock/clock1.def b/AParser/test/data/good_defs/clock/clock1.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/clock/clock1.def
rename to AParser/test/data/good_defs/clock/clock1.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/clock/clock2.def b/AParser/test/data/good_defs/clock/clock2.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/clock/clock2.def
rename to AParser/test/data/good_defs/clock/clock2.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/clock/clock3.def b/AParser/test/data/good_defs/clock/clock3.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/clock/clock3.def
rename to AParser/test/data/good_defs/clock/clock3.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/clock/clock4.def b/AParser/test/data/good_defs/clock/clock4.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/clock/clock4.def
rename to AParser/test/data/good_defs/clock/clock4.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/clock/clock5.def b/AParser/test/data/good_defs/clock/clock5.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/clock/clock5.def
rename to AParser/test/data/good_defs/clock/clock5.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/clock/clock6.def b/AParser/test/data/good_defs/clock/clock6.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/clock/clock6.def
rename to AParser/test/data/good_defs/clock/clock6.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/comment/comment.txt b/AParser/test/data/good_defs/comment/comment.txt
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/comment/comment.txt
rename to AParser/test/data/good_defs/comment/comment.txt
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/complete/complete.def b/AParser/test/data/good_defs/complete/complete.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/complete/complete.def
rename to AParser/test/data/good_defs/complete/complete.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/complete/complex.def b/AParser/test/data/good_defs/complete/complex.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/complete/complex.def
rename to AParser/test/data/good_defs/complete/complex.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/cron/cron.def b/AParser/test/data/good_defs/cron/cron.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/cron/cron.def
rename to AParser/test/data/good_defs/cron/cron.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/cron/cron1.def b/AParser/test/data/good_defs/cron/cron1.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/cron/cron1.def
rename to AParser/test/data/good_defs/cron/cron1.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/cron/cron2.def b/AParser/test/data/good_defs/cron/cron2.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/cron/cron2.def
rename to AParser/test/data/good_defs/cron/cron2.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/date/date.def b/AParser/test/data/good_defs/date/date.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/date/date.def
rename to AParser/test/data/good_defs/date/date.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/day/day.def b/AParser/test/data/good_defs/day/day.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/day/day.def
rename to AParser/test/data/good_defs/day/day.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/defstatus/defstatus.txt b/AParser/test/data/good_defs/defstatus/defstatus.txt
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/defstatus/defstatus.txt
rename to AParser/test/data/good_defs/defstatus/defstatus.txt
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/edit/edit.def b/AParser/test/data/good_defs/edit/edit.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/edit/edit.def
rename to AParser/test/data/good_defs/edit/edit.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/event/event_1.def b/AParser/test/data/good_defs/event/event_1.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/event/event_1.def
rename to AParser/test/data/good_defs/event/event_1.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/event/event_2.def b/AParser/test/data/good_defs/event/event_2.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/event/event_2.def
rename to AParser/test/data/good_defs/event/event_2.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/event/family_event.def b/AParser/test/data/good_defs/event/family_event.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/event/family_event.def
rename to AParser/test/data/good_defs/event/family_event.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/event/spaces.def b/AParser/test/data/good_defs/event/spaces.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/event/spaces.def
rename to AParser/test/data/good_defs/event/spaces.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/event/suite_event.def b/AParser/test/data/good_defs/event/suite_event.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/event/suite_event.def
rename to AParser/test/data/good_defs/event/suite_event.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/extern/extern.def b/AParser/test/data/good_defs/extern/extern.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/extern/extern.def
rename to AParser/test/data/good_defs/extern/extern.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/extern/first.def b/AParser/test/data/good_defs/extern/first.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/extern/first.def
rename to AParser/test/data/good_defs/extern/first.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/extern/plain.def b/AParser/test/data/good_defs/extern/plain.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/extern/plain.def
rename to AParser/test/data/good_defs/extern/plain.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/extern/second.def b/AParser/test/data/good_defs/extern/second.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/extern/second.def
rename to AParser/test/data/good_defs/extern/second.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/extern/simple_extern.def b/AParser/test/data/good_defs/extern/simple_extern.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/extern/simple_extern.def
rename to AParser/test/data/good_defs/extern/simple_extern.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/family/hierarchical_family.txt b/AParser/test/data/good_defs/family/hierarchical_family.txt
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/family/hierarchical_family.txt
rename to AParser/test/data/good_defs/family/hierarchical_family.txt
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/family/missingEnds.txt b/AParser/test/data/good_defs/family/missingEnds.txt
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/family/missingEnds.txt
rename to AParser/test/data/good_defs/family/missingEnds.txt
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/family/simple_family.txt b/AParser/test/data/good_defs/family/simple_family.txt
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/family/simple_family.txt
rename to AParser/test/data/good_defs/family/simple_family.txt
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/label/label.txt b/AParser/test/data/good_defs/label/label.txt
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/label/label.txt
rename to AParser/test/data/good_defs/label/label.txt
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/label/multi_line_lables.def b/AParser/test/data/good_defs/label/multi_line_lables.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/label/multi_line_lables.def
rename to AParser/test/data/good_defs/label/multi_line_lables.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/label/spaces.def b/AParser/test/data/good_defs/label/spaces.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/label/spaces.def
rename to AParser/test/data/good_defs/label/spaces.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/late/late.def b/AParser/test/data/good_defs/late/late.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/late/late.def
rename to AParser/test/data/good_defs/late/late.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/lifecycle.txt b/AParser/test/data/good_defs/lifecycle.txt
similarity index 100%
copy from ecflow_4_0_7/AParser/test/data/good_defs/lifecycle.txt
copy to AParser/test/data/good_defs/lifecycle.txt
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/limit/limit.def b/AParser/test/data/good_defs/limit/limit.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/limit/limit.def
rename to AParser/test/data/good_defs/limit/limit.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/limit/limit2.def b/AParser/test/data/good_defs/limit/limit2.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/limit/limit2.def
rename to AParser/test/data/good_defs/limit/limit2.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/meter/negative.def b/AParser/test/data/good_defs/meter/negative.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/meter/negative.def
rename to AParser/test/data/good_defs/meter/negative.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/meter/simple_meter.txt b/AParser/test/data/good_defs/meter/simple_meter.txt
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/meter/simple_meter.txt
rename to AParser/test/data/good_defs/meter/simple_meter.txt
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/meter/spaces.def b/AParser/test/data/good_defs/meter/spaces.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/meter/spaces.def
rename to AParser/test/data/good_defs/meter/spaces.def
diff --git a/AParser/test/data/good_defs/repeat/repeat_date.def b/AParser/test/data/good_defs/repeat/repeat_date.def
new file mode 100644
index 0000000..8de9acc
--- /dev/null
+++ b/AParser/test/data/good_defs/repeat/repeat_date.def
@@ -0,0 +1,10 @@
+suite s1
+ repeat date YMD 20090331 20121212 1 # status 0
+endsuite
+
+suite s2
+ repeat date YMD 20121212 20090331 -1 # status 0
+endsuite
+
+suite s3; repeat date YMD 20090331 20121212 1 # status 0
+endsuite
\ No newline at end of file
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/repeat/repeat_day.def b/AParser/test/data/good_defs/repeat/repeat_day.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/repeat/repeat_day.def
rename to AParser/test/data/good_defs/repeat/repeat_day.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/repeat/repeat_enumerate_quotes.def b/AParser/test/data/good_defs/repeat/repeat_enumerate_quotes.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/repeat/repeat_enumerate_quotes.def
rename to AParser/test/data/good_defs/repeat/repeat_enumerate_quotes.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/repeat/repeat_enumerated.def b/AParser/test/data/good_defs/repeat/repeat_enumerated.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/repeat/repeat_enumerated.def
rename to AParser/test/data/good_defs/repeat/repeat_enumerated.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/repeat/repeat_file.def b/AParser/test/data/good_defs/repeat/repeat_file.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/repeat/repeat_file.def
rename to AParser/test/data/good_defs/repeat/repeat_file.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/repeat/repeat_integer.def b/AParser/test/data/good_defs/repeat/repeat_integer.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/repeat/repeat_integer.def
rename to AParser/test/data/good_defs/repeat/repeat_integer.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/repeat/repeat_integer_1.def b/AParser/test/data/good_defs/repeat/repeat_integer_1.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/repeat/repeat_integer_1.def
rename to AParser/test/data/good_defs/repeat/repeat_integer_1.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/repeat/repeat_integer_2.def b/AParser/test/data/good_defs/repeat/repeat_integer_2.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/repeat/repeat_integer_2.def
rename to AParser/test/data/good_defs/repeat/repeat_integer_2.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/repeat/repeat_string.def b/AParser/test/data/good_defs/repeat/repeat_string.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/repeat/repeat_string.def
rename to AParser/test/data/good_defs/repeat/repeat_string.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/repeat/repeat_string_quotes.def b/AParser/test/data/good_defs/repeat/repeat_string_quotes.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/repeat/repeat_string_quotes.def
rename to AParser/test/data/good_defs/repeat/repeat_string_quotes.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/suite/multi_statements_per_line.def b/AParser/test/data/good_defs/suite/multi_statements_per_line.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/suite/multi_statements_per_line.def
rename to AParser/test/data/good_defs/suite/multi_statements_per_line.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/suite/multi_suite.def b/AParser/test/data/good_defs/suite/multi_suite.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/suite/multi_suite.def
rename to AParser/test/data/good_defs/suite/multi_suite.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/suite/simple_suite.txt b/AParser/test/data/good_defs/suite/simple_suite.txt
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/suite/simple_suite.txt
rename to AParser/test/data/good_defs/suite/simple_suite.txt
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/suite/suite_with_hierarchy.def b/AParser/test/data/good_defs/suite/suite_with_hierarchy.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/suite/suite_with_hierarchy.def
rename to AParser/test/data/good_defs/suite/suite_with_hierarchy.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/suite/suite_with_task.def b/AParser/test/data/good_defs/suite/suite_with_task.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/suite/suite_with_task.def
rename to AParser/test/data/good_defs/suite/suite_with_task.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/task/simple_task.txt b/AParser/test/data/good_defs/task/simple_task.txt
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/task/simple_task.txt
rename to AParser/test/data/good_defs/task/simple_task.txt
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/task/spaces.def b/AParser/test/data/good_defs/task/spaces.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/task/spaces.def
rename to AParser/test/data/good_defs/task/spaces.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/task/task.def b/AParser/test/data/good_defs/task/task.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/task/task.def
rename to AParser/test/data/good_defs/task/task.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/time/time.def b/AParser/test/data/good_defs/time/time.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/time/time.def
rename to AParser/test/data/good_defs/time/time.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/time/time_1.def b/AParser/test/data/good_defs/time/time_1.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/time/time_1.def
rename to AParser/test/data/good_defs/time/time_1.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/time/time_2.def b/AParser/test/data/good_defs/time/time_2.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/time/time_2.def
rename to AParser/test/data/good_defs/time/time_2.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/today/today.def b/AParser/test/data/good_defs/today/today.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/today/today.def
rename to AParser/test/data/good_defs/today/today.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/today/today1.def b/AParser/test/data/good_defs/today/today1.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/today/today1.def
rename to AParser/test/data/good_defs/today/today1.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/trigger/anded_ored.def b/AParser/test/data/good_defs/trigger/anded_ored.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/trigger/anded_ored.def
rename to AParser/test/data/good_defs/trigger/anded_ored.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/trigger/complex_hier.def b/AParser/test/data/good_defs/trigger/complex_hier.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/trigger/complex_hier.def
rename to AParser/test/data/good_defs/trigger/complex_hier.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/trigger/complex_trigger.txt b/AParser/test/data/good_defs/trigger/complex_trigger.txt
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/trigger/complex_trigger.txt
rename to AParser/test/data/good_defs/trigger/complex_trigger.txt
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/trigger/extension.def b/AParser/test/data/good_defs/trigger/extension.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/trigger/extension.def
rename to AParser/test/data/good_defs/trigger/extension.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/trigger/simple_trigger.txt b/AParser/test/data/good_defs/trigger/simple_trigger.txt
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/trigger/simple_trigger.txt
rename to AParser/test/data/good_defs/trigger/simple_trigger.txt
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/trigger/trigger_references.def b/AParser/test/data/good_defs/trigger/trigger_references.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/trigger/trigger_references.def
rename to AParser/test/data/good_defs/trigger/trigger_references.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/variable/alias.def b/AParser/test/data/good_defs/variable/alias.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/variable/alias.def
rename to AParser/test/data/good_defs/variable/alias.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/variable/duplicate.def b/AParser/test/data/good_defs/variable/duplicate.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/variable/duplicate.def
rename to AParser/test/data/good_defs/variable/duplicate.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/variable/variable.txt b/AParser/test/data/good_defs/variable/variable.txt
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/variable/variable.txt
rename to AParser/test/data/good_defs/variable/variable.txt
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/verify/verify.def b/AParser/test/data/good_defs/verify/verify.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/verify/verify.def
rename to AParser/test/data/good_defs/verify/verify.def
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/zombie/zombie.def b/AParser/test/data/good_defs/zombie/zombie.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/zombie/zombie.def
rename to AParser/test/data/good_defs/zombie/zombie.def
diff --git a/AParser/test/data/good_defs_state/defs/defs_state.def b/AParser/test/data/good_defs_state/defs/defs_state.def
new file mode 100644
index 0000000..d18459c
--- /dev/null
+++ b/AParser/test/data/good_defs_state/defs/defs_state.def
@@ -0,0 +1,4 @@
+# 2.0.31
+defs_state STATE state:unknown flag: state_change:17 modify_change:0 server_state:SHUTDOWN
+ edit ECF_MICRO '%'
+ edit ECF_HOME '/var/tmp/ma0/workspace'
diff --git a/AParser/test/data/single_defs/ECFLOW-417.def b/AParser/test/data/single_defs/ECFLOW-417.def
new file mode 100644
index 0000000..6ee2f8b
--- /dev/null
+++ b/AParser/test/data/single_defs/ECFLOW-417.def
@@ -0,0 +1,6 @@
+suite s1
+ repeat day 1
+ clock hybrid
+ task t1
+ time 15:42
+endsuite
\ No newline at end of file
diff --git a/ecflow_4_0_7/AParser/test/data/single_defs/ealadin.def b/AParser/test/data/single_defs/ealadin.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/single_defs/ealadin.def
rename to AParser/test/data/single_defs/ealadin.def
diff --git a/ecflow_4_0_7/AParser/test/data/single_defs/mega.def b/AParser/test/data/single_defs/mega.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/single_defs/mega.def
rename to AParser/test/data/single_defs/mega.def
diff --git a/ecflow_4_0_7/AParser/test/data/single_defs/test_auto_add_extern.def b/AParser/test/data/single_defs/test_auto_add_extern.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/single_defs/test_auto_add_extern.def
rename to AParser/test/data/single_defs/test_auto_add_extern.def
diff --git a/ecflow_4_0_7/AParser/test/data/single_defs/test_complete.def b/AParser/test/data/single_defs/test_complete.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/single_defs/test_complete.def
rename to AParser/test/data/single_defs/test_complete.def
diff --git a/ecflow_4_0_7/AParser/test/data/single_defs/test_repeat.def b/AParser/test/data/single_defs/test_repeat.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/single_defs/test_repeat.def
rename to AParser/test/data/single_defs/test_repeat.def
diff --git a/Base/CMakeLists.txt b/Base/CMakeLists.txt
new file mode 100644
index 0000000..55ff526
--- /dev/null
+++ b/Base/CMakeLists.txt
@@ -0,0 +1,110 @@
+ # =======================================================
+ # to list all sources to build use:
+ # cd $WK/Base
+ # find src -name \*.cpp >> CMakeLists.txt
+ # =======================================================
+ list( APPEND srcs
+ src/ZombieCtrl.cpp
+ src/Stats.cpp
+ src/Client.cpp
+ src/ServerReply.cpp
+ src/stc/DefsCmd.cpp
+ src/stc/PreAllocatedReply.cpp
+ src/stc/SStringVecCmd.cpp
+ src/stc/StcCmd.cpp
+ src/stc/SSuitesCmd.cpp
+ src/stc/SClientHandleCmd.cpp
+ src/stc/SStringCmd.cpp
+ src/stc/ServerToClientCmd.cpp
+ src/stc/SClientHandleSuitesCmd.cpp
+ src/stc/SServerLoadCmd.cpp
+ src/stc/SNodeCmd.cpp
+ src/stc/SStatsCmd.cpp
+ src/stc/SSyncCmd.cpp
+ src/stc/SNewsCmd.cpp
+ src/stc/ErrorCmd.cpp
+ src/stc/GroupSTCCmd.cpp
+ src/stc/ZombieGetCmd.cpp
+ src/ClientToServerRequest.cpp
+ src/Gnuplot.cpp
+ src/WhyCmd.cpp
+ src/ServerToClientResponse.cpp
+ src/cts/CSyncCmd.cpp
+ src/cts/ZombieCmd.cpp
+ src/cts/OrderNodeCmd.cpp
+ src/cts/CheckPtCmd.cpp
+ src/cts/CtsNodeCmd.cpp
+ src/cts/GroupCTSCmd.cpp
+ src/cts/UserCmd.cpp
+ src/cts/ClientHandleCmd.cpp
+ src/cts/PlugCmd.cpp
+ src/cts/ForceCmd.cpp
+ src/cts/LoadDefsCmd.cpp
+ src/cts/CFileCmd.cpp
+ src/cts/ShowCmd.cpp
+ src/cts/CtsCmd.cpp
+ src/cts/TaskApi.cpp
+ src/cts/EditScriptCmd.cpp
+ src/cts/FreeDepCmd.cpp
+ src/cts/PathsCmd.cpp
+ src/cts/EditHistoryMgr.cpp
+ src/cts/LogMessageCmd.cpp
+ src/cts/CtsApi.cpp
+ src/cts/ReplaceNodeCmd.cpp
+ src/cts/RequeueNodeCmd.cpp
+ src/cts/BeginCmd.cpp
+ src/cts/LogCmd.cpp
+ src/cts/AlterCmd.cpp
+ src/cts/TaskCmds.cpp
+ src/cts/CtsCmdRegistry.cpp
+ src/cts/RunNodeCmd.cpp
+ src/cts/ClientToServerCmd.cpp
+ src/cts/ServerVersionCmd.cpp
+)
+
+ecbuild_add_library( TARGET base
+ NOINSTALL
+ TYPE STATIC
+ SOURCES ${srcs}
+ LIBS libparser node nodeattr core
+ INCLUDES src
+ ../ACore/src
+ ../ANattr/src
+ ../ANode/src
+ ../AParser/src
+ ../Base/src
+ ../Base/src/cts
+ ../Base/src/stc
+ )
+
+# This ensures that for debug config, we only link with debug boost libs, for other configs, we link with optimised boost libs
+target_link_libraries(base debug ${Boost_PROGRAM_OPTIONS_LIBRARY_DEBUG} ${Boost_PROGRAM_OPTIONS_LIBRARY_RELEASE})
+
+list( APPEND test_srcs
+ test/TestAlterCmd.cpp
+ test/TestClientHandleCmd.cpp
+ test/TestCmd.cpp
+ test/TestDeleteNodeCmd.cpp
+ test/TestECFLOW-189.cpp
+ test/TestForceCmd.cpp
+ test/TestFreeDepCmd.cpp
+ test/TestLimit.cpp
+ test/TestLogCmd.cpp
+ test/TestMeterCmd.cpp
+ test/TestProgramOptions.cpp
+ test/TestRequest.cpp
+ test/TestRequeueNodeCmd.cpp
+ test/TestResolveDependencies.cpp
+ test/TestSSyncCmd_CH1.cpp
+ test/TestSSyncCmd.cpp
+ test/TestSSyncCmdOrder.cpp
+)
+ecbuild_add_test( TARGET u_base
+ BOOST
+ SOURCES ${test_srcs}
+ LIBS base
+ pthread
+ INCLUDES ../ANode/test
+ TEST_DEPENDS u_aparser
+ )
+
\ No newline at end of file
diff --git a/Base/Jamfile.jam b/Base/Jamfile.jam
new file mode 100644
index 0000000..26c952c
--- /dev/null
+++ b/Base/Jamfile.jam
@@ -0,0 +1,70 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+#
+# Base project
+#
+project theBase ;
+
+
+use-project theCore : ../ACore ;
+use-project theNodeAttr : ../ANattr ;
+use-project theNode : ../ANode ;
+use-project theParser : ../AParser ;
+
+# The <include> means we will automatically add this directory to the include path
+# of any other target that uses this lib
+#
+lib base : [ glob src/*.cpp ] [ glob src/cts/*.cpp ] [ glob src/stc/*.cpp ]
+ : <include>../ACore/src
+ <include>../ANattr/src
+ <include>../AParser/src
+ <include>../ANode/src
+ <include>../Base/src
+ <include>../Base/src/cts
+ <include>../Base/src/stc
+ <link>static
+ <variant>debug:<define>DEBUG
+ <use>/theCore//core
+ <use>/theNodeAttr//nodeattr
+ <use>/theParser//libparser
+ <use>/theNode//node
+ <use>/site-config//boost_system
+ <use>/site-config//boost_serialization
+ <use>/site-config//boost_filesystem
+ <use>/site-config//boost_datetime
+ <use>/site-config//boost_program_options
+ <use>/site-config//boost_test
+ :
+ : <include>../Base/src
+ <include>../Base/src/cts
+ <include>../Base/src/stc
+ ;
+
+#
+# This should be in the site-config.jam file as a project wide requirement
+# however if this is done, it will not link since, lpthread appears twice
+# on the link line
+#
+lib pthread ;
+
+exe u_base : [ glob test/*.cpp ]
+ /theCore//core
+ /theNodeAttr//nodeattr
+ /theNode//node
+ /theParser//libparser
+ base
+ /site-config//boost_system
+ /site-config//boost_serialization
+ /site-config//boost_filesystem
+ /site-config//boost_datetime
+ /site-config//boost_program_options
+ /site-config//boost_test
+ pthread
+ : <include>../ANode/test
+ <variant>debug:<define>DEBUG
+ ;
diff --git a/Base/src/AbstractClientEnv.hpp b/Base/src/AbstractClientEnv.hpp
new file mode 100644
index 0000000..1455be1
--- /dev/null
+++ b/Base/src/AbstractClientEnv.hpp
@@ -0,0 +1,66 @@
+#ifndef ABSTRACT_CLIENT_ENV__HPP_
+#define ABSTRACT_CLIENT_ENV__HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #14 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : This class is used to represent the client environment to the cmds
+//
+// This abstraction ONLY covers aspects that are required, to _CREATE_
+// the client command/request that is to be sent to the server
+// The key theme is that we can define a new client to server command
+// in one place. i.e it allows the functionality, command line arguments,
+// parsing of the arguments, can all be done in the command class itself
+// If the command requires any additional arguments from the client environment
+// they should be added to this class, and the implementation in the derived class
+//============================================================================
+
+#include <boost/noncopyable.hpp>
+#include <string>
+#include <vector>
+
+class AbstractClientEnv : private boost::noncopyable {
+protected:
+ AbstractClientEnv() {}
+public:
+ virtual ~AbstractClientEnv() {}
+
+ /// For all tasks/child based commands we require taskPath and password and optional Remote ID
+ /// When the jobs use a queueing system the remote id (ECF_RID) is used to
+ /// aid killing of jobs.(typically zombies)
+ virtual bool checkTaskPathAndPassword(std::string& errorMsg) const = 0;
+ virtual const std::string& task_path() const = 0;
+ virtual int task_try_no() const = 0;
+ virtual const std::string& jobs_password() const = 0;
+ virtual const std::string& process_or_remote_id() const = 0;
+
+ /// For test allow env variable to be set on defs, i.e. allow us to inject ECF_CLIENT to defs
+ virtual const std::vector<std::pair<std::string,std::string> >& env() const = 0;
+
+ /// Allow ping to set the host:port
+ virtual void set_host_port(const std::string& host, const std::string& port) = 0;
+
+ /// return the current host
+ virtual const std::string& host() const = 0;
+
+ /// returns the port number
+ virtual const std::string& port() const = 0;
+
+ /// debug client, when environment variable ECF_CLIENT_DEBUG is set.
+ virtual bool debug() const = 0 ;
+
+ /// Some commands work on construction. to avoid this under test. Call set_test
+ /// i.e Command like CtsCmd::SERVER_LOAD can be client side only, in which case
+ /// when testing the client interface we want to avoid opening the log file.
+ virtual void set_test() = 0;
+ virtual bool under_test() const = 0;
+};
+#endif
diff --git a/Base/src/AbstractServer.hpp b/Base/src/AbstractServer.hpp
new file mode 100644
index 0000000..6cc5153
--- /dev/null
+++ b/Base/src/AbstractServer.hpp
@@ -0,0 +1,193 @@
+#ifndef ABSTRACTSERVER_HPP_
+#define ABSTRACTSERVER_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #45 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include "Stats.hpp"
+#include "ZombieCtrl.hpp"
+#include "SState.hpp"
+#include "CheckPt.hpp"
+
+class Defs;
+
+/// This class is provided so that the cmd can issue requests to the server
+/// without depending on the server implementation
+///
+class AbstractServer {
+public:
+ virtual ~AbstractServer() {}
+
+ /// returns the current state of the server
+ /// The following table shows the effect of state, on server behaviour:
+ ///
+ /// User Request Task Request Job Scheduling Check-pointing
+ /// RUNNING yes yes yes yes
+ /// SHUTDOWN yes yes no yes
+ /// HALTED yes no no no
+ virtual SState::State state() const = 0;
+
+ /// returns the server host and port number
+ virtual std::pair<std::string,std::string> hostPort() const = 0;
+
+ /// returns the defs held by the server. This should always exist. ECFLOW-182
+ virtual defs_ptr defs() const = 0;
+
+ /// Update the defs help by the server. This allows multiple suites to loaded
+ /// into the server. Note the input defs will be drained of its suites/externs as they
+ /// will get transferred to the server. If the server already has suites of the same
+ /// name, then an error message is created. This can be overridden with the force option
+ virtual void updateDefs(defs_ptr, bool force) = 0;
+
+ /// Remove all suites,externs,client handles, ready for a new start
+ virtual void clear_defs() = 0;
+
+ /// Forces the defs file in the server to be written to disk *IF* no args provided.
+ /// Otherwise updated mode OR check_pt interval OR check pt alarm
+ virtual void checkPtDefs(ecf::CheckPt::Mode m = ecf::CheckPt::UNDEFINED,
+ int check_pt_interval = 0,
+ int check_pt_save_time_alarm = 0) = 0;
+
+ /// Ask the server to restore the defs from the checkpt file. If that fails the back check pt is tried
+ virtual void restore_defs_from_checkpt() = 0;
+
+ /// This function should be called, when the node tree changes state
+ virtual void nodeTreeStateChanged() = 0;
+
+ /// returns true if the server allows task communication
+ /// Task-->server communication is stopped by halted()
+ virtual bool allowTaskCommunication() const = 0;
+
+ /// Stops job scheduling. Check point is enabled. (i,e if we were previously halted)
+ /// However any client request can still communicate with the server
+ /// Does NOT affect check pointing. Since any request can make changes to node tree
+ /// Places server in SHUTDOWN state.
+ /// User Request Task Request Job Scheduling Check-pointing
+ /// RUNNING yes yes yes yes
+ /// SHUTDOWN yes yes no yes
+ /// HALTED yes no no no
+ virtual void shutdown() = 0;
+
+ /// Stop job scheduling *AND* task communication with server. Failed task request are logged
+ /// Hence nodes can be stuck in submitted/active states.
+ /// Task based command will continue attempting, communication with the server for up to 24hrs.
+ ///
+ /// When the server is halted, we do *NOT* do any further check pointing
+ /// In a typical operational scenario where we have a home, and backup servers.
+ /// The checkpoint file is copied to the backup servers periodically (via a task)
+ /// hence we want to preserve the state of the last checkpoint. By prevent any state
+ /// changes to the node tree.
+ ///
+ /// Hence halted(), will completely stop the server. Server will only respond
+ /// to user requests. (tasks requests are blocked)
+ /// Places server in HALTED state.
+ /// User Request Task Request Job Scheduling Check-pointing
+ /// RUNNING yes yes yes yes
+ /// SHUTDOWN yes yes no yes
+ /// HALTED yes no no no
+ virtual void halted() = 0;
+
+ /// Start scheduling tasks and respond to all requests. Check pointing is enabled
+ /// Places server in RUNNING state.
+ /// User Request Task Request Job Scheduling Check-pointing
+ /// RUNNING yes yes yes yes
+ /// SHUTDOWN yes yes no yes
+ /// HALTED yes no no no
+ virtual void restart() = 0;
+
+ /// Ask the server to reload file the hold list of users and their access rights
+ /// The white list file is specified by the environment variable ECF_LISTS
+ /// This allows/disallows user access on the live server
+ /// Return true if file is reloaded ok, else false and error message if:
+ /// a/ File does not exist
+ /// b/ File is empty
+ /// c/ Errors in parsing file
+ /// If errors arise the exist user still stay in affect
+ virtual bool reloadWhiteListFile(std::string& errorMsg) = 0;
+
+ /// There are several kinds of authentifications:
+ /// a/ None
+ /// b/ List mode. ASCII file based on ECF_LISTS is defined. referred as white list file
+ /// c/ Secure mode. binary file based ECF_PASSWD is defined. Referred to as black list file
+ /// At the moment we will only implement options a/ and b/
+ //
+ /// Returns true if the given user has access to the server, false otherwise
+ virtual bool authenticateReadAccess(const std::string& user) = 0;
+
+ /// Returns true if user has matching write access privileges.
+ virtual bool authenticateWriteAccess(const std::string& user ) = 0;
+
+ /// Shutdown the server and let 'user' has have exclusive lock on it.
+ /// If the lock succeeds return true, (This will end up calling the shutdown()
+ /// command on the server). If already locked does nothing and return's false
+ virtual bool lock(const std::string& user) = 0;
+
+ /// Unlock's the server., and restarts job scheduling
+ virtual void unlock() = 0;
+
+ /// Return the user that has exclusive lock, else an empty string
+ virtual const std::string& lockedUser() const = 0;
+
+ /// Return Controller for zombies
+ ZombieCtrl& zombie_ctrl() { return zombie_ctrl_; }
+
+ /// returns the statistical class
+ Stats& stats() { return stats_;}
+
+ /// Call to update the number of request, & returns stats
+ Stats& update_stats() { stats_.update(); return stats_; }
+
+ /// Update for number of requests per second
+ void update_stats(int poll_interval) { stats_.update_stats(poll_interval); }
+
+ // Instead of immediate node tree traversal at the end of child command
+ // we use 'increment_job_generation_count' to defer job generation to server
+ // The server will will check job generation count at poll time.
+ // This approach radically reduces the number of times we traverse the node tree
+ // and hence improves server throughput.
+ void increment_job_generation_count() { job_gen_count_++;}
+ void reset_job_generation_count() { job_gen_count_ = 0; }
+ int get_job_generation_count() const { return job_gen_count_; }
+
+ /// This job generation is special, in that it will time out, job generation time >= next poll.
+ /// This can be called at the end of a *USER* command(force,alter,requeue,etc), hence time_now may be >= next_poll_time
+ /// If this is the case, we will defer job generation
+ virtual void traverse_node_tree_and_job_generate(const boost::posix_time::ptime& time_now,bool user_cmd_context) const = 0;
+
+ /// returns the number of seconds at which we should check time dependencies
+ /// this includes evaluating trigger dependencies and submit the corresponding jobs.
+ /// This is set at 60 seconds. But will vary for debug/test purposes only.
+ /// For Testing the state change queued->submitted->active duration < submitJobsInterval
+ /// If this state change happens at the job submission boundary then
+ /// time series can get a skew.
+ virtual int poll_interval() const = 0;
+
+ /// enable and disable debug output from the server
+ virtual void debug_server_on() = 0;
+ virtual void debug_server_off() = 0;
+ virtual bool debug() const = 0;
+
+protected:
+ AbstractServer() : job_gen_count_(0) {}
+
+private:
+ int job_gen_count_;
+ ZombieCtrl zombie_ctrl_;
+ Stats stats_;
+};
+
+#endif
diff --git a/Base/src/Client.cpp b/Base/src/Client.cpp
new file mode 100644
index 0000000..d412a8a
--- /dev/null
+++ b/Base/src/Client.cpp
@@ -0,0 +1,343 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name : Client
+// Author : Avi
+// Revision : $Revision: #33 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <assert.h>
+
+#include <boost/bind.hpp>
+
+#include "Client.hpp"
+#include "StcCmd.hpp"
+
+//#define DEBUG_CLIENT 1;
+
+#ifdef DEBUG_CLIENT
+#include <boost/date_time/posix_time/time_formatters.hpp> // requires boost date and time lib, for to_simple_string
+#endif
+
+/// The timeout will typically happen when the server has died, but socket is still open
+/// If we do not have a timeout, it will hang indefinitely
+
+/// Constructor starts the asynchronous connect operation.
+Client::Client( boost::asio::io_service& io_service,
+ Cmd_ptr cmd_ptr,
+ const std::string& host,
+ const std::string& port,
+ int timeout
+ )
+: stopped_(false),host_( host ), port_( port ), connection_( io_service ),deadline_(io_service),timeout_(timeout)
+{
+ /// Avoid sending a NULL request to the server
+ if (!cmd_ptr.get()) throw std::runtime_error("Client::Client: No request specified !");
+
+ // The timeout can be set externally for testing, however when its not set the timeout is obtained from the command
+ // Vary the timeout, according to the command, hence loading the definition has longer timeout than ping
+ if (0 == timeout_) {
+ timeout_ = cmd_ptr->timeout();
+ }
+
+#ifdef DEBUG_CLIENT
+ std::cout << " Client::Client() timeout(" << timeout_ << ") " << host_ << ":" << port_ << " "; cmd_ptr->print(std::cout); std::cout << std::endl;
+#endif
+
+ outbound_request_.set_cmd( cmd_ptr );
+
+ // Host name resolution is performed using a resolver, where host and service
+ // names(or ports) are looked up and converted into one or more end points
+ boost::asio::ip::tcp::resolver resolver( io_service );
+ boost::asio::ip::tcp::resolver::query query( host_, port_ );
+ boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve( query );
+
+ // The list of end points obtained could contain both IPv4 and IPv6 end points,
+ // so a program may try each of them until it finds one that works.
+ // This keeps the Client program independent of a specific IP version.
+ start(endpoint_iterator);
+}
+
+Client::~Client() {
+#ifdef DEBUG_CLIENT
+ std::cout << " Client::~Client(): connection_.socket().is_open()=" << connection_.socket().is_open() << std::endl;
+#endif
+}
+
+/// Private ==============================================================================
+
+// This function terminates all the actors to shut down the connection. It
+// may be called by the user of the client class, or by the class itself in
+// response to graceful termination or an unrecoverable error.
+void Client::start(boost::asio::ip::tcp::resolver::iterator endpoint_iter)
+{
+ // Start the connect actor.
+ start_connect(endpoint_iter);
+
+ // Start the deadline actor. You will note that we're not setting any
+ // particular deadline here. Instead, the connect and input actors will
+ // update the deadline prior to each asynchronous operation.
+ deadline_.async_wait(boost::bind(&Client::check_deadline, this));
+}
+
+bool Client::start_connect(boost::asio::ip::tcp::resolver::iterator endpoint_iterator )
+{
+ if ( endpoint_iterator != boost::asio::ip::tcp::resolver::iterator() )
+ {
+#ifdef DEBUG_CLIENT
+ std::cout << " Client::start_connect: Trying " << endpoint_iterator->endpoint() << "..." << std::endl;
+#endif
+
+ // expires_from_now cancels any pending asynchronous waits, and returns the number of asynchronous waits that were cancelled.
+ // If it returns 0 then you were too late and the wait handler has already been executed, or will soon be executed.
+ // If it returns 1 then the wait handler was successfully cancelled.
+
+ // Set a deadline for the connect operation.
+ deadline_.expires_from_now(boost::posix_time::seconds(timeout_));
+
+ boost::asio::ip::tcp::endpoint endpoint = *endpoint_iterator;
+ connection_.socket().async_connect(
+ endpoint,
+ boost::bind(
+ &Client::handle_connect,
+ this,
+ boost::asio::placeholders::error,
+ endpoint_iterator ) );
+ }
+ else {
+ // ran out of end points
+ return false;
+ }
+ return true;
+}
+
+void Client::handle_connect( const boost::system::error_code& e,
+ boost::asio::ip::tcp::resolver::iterator endpoint_iterator )
+{
+#ifdef DEBUG_CLIENT
+ std::cout << " Client::handle_connect stopped_=" << stopped_ << std::endl;
+#endif
+
+ if (stopped_)
+ return;
+
+ // The async_connect() function automatically opens the socket at the start
+ // of the asynchronous operation. If the socket is closed at this time then
+ // the timeout handler must have run first.
+ if (!connection_.socket().is_open())
+ {
+#ifdef DEBUG_CLIENT
+ std::cout << " Client::handle_connect: *Connect timeout*: Trying next end point" << std::endl;
+#endif
+ // Try the next available end point.
+ if (!start_connect( ++endpoint_iterator)) {
+ // Ran out of end points, An error occurred
+ stop();
+ std::stringstream ss;
+ if (e) ss << "Client::handle_connect: Ran out of end points : connection error( " << e.message() << " ) for request( " << outbound_request_ << " ) on " << host_ << ":" << port_;
+ else ss << "Client::handle_connect: Ran out of end points : connection error for request( " << outbound_request_ << " ) on " << host_ << ":" << port_;
+ throw std::runtime_error(ss.str());
+ }
+ }
+ else if (e) {
+
+#ifdef DEBUG_CLIENT
+ std::cout << " Client::handle_connect Connect error: " << e.message() << " . Trying next end point" << std::endl;
+#endif
+
+ // Some kind of error. We need to close the socket used in the previous connection attempt
+ // before starting a new one.
+ connection_.socket().close();
+
+ // Try the next end point.
+ if (!start_connect( ++endpoint_iterator)) {
+ // Ran out of end points. An error occurred.
+ stop();
+ std::stringstream ss; ss << "Client::handle_connect: Ran out of end points: connection error( " << e.message() << " ) for request( " << outbound_request_ << " ) on " << host_ << ":" << port_;
+ throw std::runtime_error(ss.str());
+ }
+ }
+ else {
+#ifdef DEBUG_CLIENT
+ std::cout << " Client::handle_connect **Successfully** established connection to the server: Sending Out bound request = " << outbound_request_ << std::endl;
+#endif
+ // **Successfully** established connection to the server
+ // Start operation to *SEND* a request to the server
+ start_write();
+ }
+}
+
+void Client::start_write()
+{
+ // expires_from_now cancels any pending asynchronous waits, and returns the number of asynchronous waits that were cancelled.
+ // If it returns 0 then you were too late and the wait handler has already been executed, or will soon be executed.
+ // If it returns 1 then the wait handler was successfully cancelled.
+
+ // Set a deadline for the write operation.
+ deadline_.expires_from_now(boost::posix_time::seconds(timeout_));
+
+ connection_.async_write(
+ outbound_request_,
+ boost::bind(
+ &Client::handle_write,
+ this,
+ boost::asio::placeholders::error ) );
+}
+
+void Client::handle_write( const boost::system::error_code& e )
+{
+#ifdef DEBUG_CLIENT
+ std::cout << " Client::handle_write stopped_ = " << stopped_ << std::endl;
+#endif
+ if (stopped_)
+ return;
+
+ if ( !e ) {
+
+#ifdef DEBUG_CLIENT
+ std::cout << " Client::handle_write OK: Check for server reply" << std::endl;
+#endif
+ // Check to see if the server was happy with our request.
+ // If all is OK, the server may choose not to reply(cuts down on network traffic)
+ // In which case handle_read will get a End of File error.
+ start_read();
+ }
+ else {
+
+ // An error occurred.
+ stop();
+
+ std::stringstream ss; ss << "Client::handle_write: error (" << e.message() << " ) for request( " << outbound_request_ << " ) on " << host_ << ":" << port_;
+ throw std::runtime_error(ss.str());
+ }
+
+ // Nothing to do. The socket will be closed automatically when the last
+ // reference to the connection object goes away.
+}
+
+void Client::start_read()
+{
+ // expires_from_now cancels any pending asynchronous waits, and returns the number of asynchronous waits that were cancelled.
+ // If it returns 0 then you were too late and the wait handler has already been executed, or will soon be executed.
+ // If it returns 1 then the wait handler was successfully cancelled.
+
+ // Set a deadline for the read operation.
+ deadline_.expires_from_now(boost::posix_time::seconds(timeout_));
+
+ connection_.async_read(
+ inbound_response_,
+ boost::bind(
+ &Client::handle_read,
+ this,
+ boost::asio::placeholders::error ) );
+}
+
+
+void Client::handle_read( const boost::system::error_code& e )
+{
+#ifdef DEBUG_CLIENT
+ std::cout << " Client::handle_read stopped_ = " << stopped_ << std::endl;
+#endif
+ if (stopped_)
+ return;
+
+ // close socket, & cancel timer.
+ stop();
+
+ if ( !e ) {
+#ifdef DEBUG_CLIENT
+ std::cout << " Client::handle_read OK \n";
+ std::cout << " outbound_request_ = " << outbound_request_ << "\n";
+ std::cout << " inbound_response_ = " << inbound_response_ << "\n";
+#endif
+ /// ***********************************************************
+ /// ClientInvoker will call back, to handle_server_response.
+ /// ***********************************************************
+ // Successfully handled request
+ }
+ else {
+ //
+ // A connection error occurred.
+ // In cases where ( to cut down network traffic), the server does a shutdown/closes
+ // the socket without replying we will get End of File error.
+ //
+ // i.e. client requests a response from the server, and it does not reply(or replies with shutdown/close)
+ //
+
+ // This code will handle a no reply from the server & hence reduce network traffic
+ // Server has shutdown and closed the socket.
+ // See void Server::handle_read(...)
+ if (e.value() == boost::asio::error::eof) {
+ // Treat a *no* reply as OK, so that handle_server_response() returns OK
+#ifdef DEBUG_CLIENT
+ std::cout << " Client::handle_read: No reply from server: Treat as OK" << std::endl;
+#endif
+ inbound_response_.set_cmd( STC_Cmd_ptr(new StcCmd(StcCmd::OK)) );
+ return;
+ }
+
+ std::stringstream ss;
+ ss << "Client::handle_read: connection error( " << e.message() << " ) for request( " << outbound_request_ << " ) on " << host_ << ":" << port_;
+ throw std::runtime_error(ss.str());
+ }
+
+ // Since we are not starting a new operation the io_service will run out of
+ // work to do and the Client will exit.
+}
+
+void Client::stop()
+{
+ stopped_ = true;
+ connection_.socket().close();
+ deadline_.cancel();
+}
+
+/// Handle completion of a write operation.
+/// Handle completion of a read operation.
+bool Client::handle_server_response( ServerReply& server_reply, bool debug ) const
+{
+ if (debug) std::cout << " Client::handle_server_response" << std::endl;
+ server_reply.set_host_port(host_,port_); // client context, needed by some commands, ie. SServerLoadCmd
+ return inbound_response_.handle_server_response(server_reply, outbound_request_.get_cmd(), debug);
+}
+
+void Client::check_deadline()
+{
+#ifdef DEBUG_CLIENT
+ std::cout << " Client::check_deadline stopped_=" << stopped_
+ << " expires(" << to_simple_string(deadline_.expires_at())
+ << ") time now(" << to_simple_string(boost::asio::deadline_timer::traits_type::now()) << ")" << std::endl;
+#endif
+ if (stopped_)
+ return;
+
+ // Check whether the deadline has passed. We compare the deadline against
+ // the current time since a new asynchronous operation may have moved the
+ // deadline before this actor had a chance to run.
+ if (deadline_.expires_at() <= boost::asio::deadline_timer::traits_type::now())
+ {
+#ifdef DEBUG_CLIENT
+ std::cout << " Client::check_deadline timed out" << std::endl;
+#endif
+
+ // The deadline has passed. The socket is closed so that any outstanding
+ // asynchronous operations are cancelled.
+ stop();
+
+ std::stringstream ss;
+ ss << "Client::check_deadline: timed out after " << timeout_ << " seconds for request( " << outbound_request_ << " ) on " << host_ << ":" << port_;
+ throw std::runtime_error(ss.str());
+ }
+
+ // Put the actor back to sleep.
+ deadline_.async_wait(boost::bind(&Client::check_deadline, this));
+}
diff --git a/Base/src/Client.hpp b/Base/src/Client.hpp
new file mode 100644
index 0000000..4aa0d6f
--- /dev/null
+++ b/Base/src/Client.hpp
@@ -0,0 +1,83 @@
+#ifndef CLIENT_HPP_
+#define CLIENT_HPP_
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name : Client
+// Author : Avi
+// Revision : $Revision: #18 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+// Client : Acts as the client part. ( in client/server architecture)
+// Note: The plug command can move a node to another server
+// hence the server itself will NEED to ACT as a client.
+// This is why client lives in Base and not the Client project
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/asio.hpp>
+
+#include "Connection.hpp" // Must come before boost/serialization headers.
+#include "ClientToServerRequest.hpp"
+#include "ServerToClientResponse.hpp"
+
+class Client {
+public:
+ /// Constructor starts the asynchronous connect operation.
+ Client( boost::asio::io_service& io_service, Cmd_ptr cmd_ptr, const std::string& host, const std::string& port , int timout = 0);
+ ~Client();
+
+ /// Client side, get the server response, handles reply from server
+ /// Returns true if all is ok, else false if further client action is required
+ /// will throw std::runtime_error for errors
+ bool handle_server_response( ServerReply&, bool debug ) const;
+
+
+ // support for forward compatibility, by changing boost archive version
+ // By default 0 means, and need to be explicitly enabled. The integer must correspond with
+ // the archive version of the old server. for boost 1.47 this was 9
+ // Chosen to change client side only
+ void allow_new_client_old_server(int f) { connection_.allow_new_client_old_server(f);}
+
+private:
+
+ void start(boost::asio::ip::tcp::resolver::iterator);
+ void stop();
+ void check_deadline();
+
+ bool start_connect(boost::asio::ip::tcp::resolver::iterator);
+ void start_write();
+ void start_read();
+
+ /// Handle completion of a connect operation.
+ void handle_connect( const boost::system::error_code& e,
+ boost::asio::ip::tcp::resolver::iterator endpoint_iterator );
+
+ /// Handle completion of a read operation.
+ void handle_read( const boost::system::error_code& e );
+
+ /// Handle completion of a write operation
+ void handle_write( const boost::system::error_code& e );
+
+private:
+ bool stopped_;
+ std::string host_; /// the servers name
+ std::string port_; /// the port on the server
+ connection connection_; /// The connection to the server.
+ ClientToServerRequest outbound_request_; /// The request we will send to the server
+ ServerToClientResponse inbound_response_; /// The response we get back from the server
+
+ std::string error_msg_;
+ boost::asio::deadline_timer deadline_;
+
+ // connect : timeout_ second
+ // send request : timeout_ second
+ // receive reply : timeout_ second
+ // Default value of 0 means take the timeout from the command
+ int timeout_;
+};
+#endif
diff --git a/Base/src/ClientToServerRequest.cpp b/Base/src/ClientToServerRequest.cpp
new file mode 100644
index 0000000..bc5f1d3
--- /dev/null
+++ b/Base/src/ClientToServerRequest.cpp
@@ -0,0 +1,58 @@
+//============================================================================
+// Name : Request
+// Author : Avi
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <assert.h>
+#include <fstream>
+
+#include "ClientToServerRequest.hpp"
+#include "AbstractServer.hpp"
+
+using namespace std;
+
+STC_Cmd_ptr ClientToServerRequest::handleRequest(AbstractServer* as) const
+{
+ if (cmd_.get()) {
+ return cmd_->handleRequest(as);
+ }
+
+ /// means programming error somewhere
+ std::stringstream ss;
+ ss << "ClientToServerRequest::handleRequest: Can not send a NULL request to the server !";
+ throw std::runtime_error(ss.str());
+}
+
+std::ostream& ClientToServerRequest::print( std::ostream& os ) const {
+ if (cmd_.get()) {
+ return cmd_->print(os);
+ }
+ return os << "NULL request";
+}
+
+bool ClientToServerRequest::operator==(const ClientToServerRequest& rhs) const
+{
+ if (!cmd_.get() && !rhs.cmd_.get()) {
+ return true;
+ }
+ if (cmd_.get() && !rhs.cmd_.get()) {
+ return false;
+ }
+ if (!cmd_.get() && rhs.cmd_.get()) {
+ return false;
+ }
+ return (cmd_->equals(rhs.cmd_.get()));
+}
+
+std::ostream& operator<<( std::ostream& os, const ClientToServerRequest& d ) {
+ return d.print( os );
+}
diff --git a/Base/src/ClientToServerRequest.hpp b/Base/src/ClientToServerRequest.hpp
new file mode 100644
index 0000000..c879173
--- /dev/null
+++ b/Base/src/ClientToServerRequest.hpp
@@ -0,0 +1,67 @@
+#ifndef CLIENT_TO_SERVER_REQUEST_HPP_
+#define CLIENT_TO_SERVER_REQUEST_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #32 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <boost/noncopyable.hpp>
+#include <boost/serialization/tracking.hpp>
+#include "ClientToServerCmd.hpp"
+
+// Base class for client to server requesting.
+// This class is used in the IPC messaging from client to server.
+class ClientToServerRequest : private boost::noncopyable {
+public:
+
+ ClientToServerRequest() {}
+ ClientToServerRequest(const Cmd_ptr& cmd) : cmd_(cmd) { cmd_->setup_user_authentification();}
+ ~ClientToServerRequest() {}
+
+ void set_cmd(const Cmd_ptr& cmd) { cmd_ = cmd; cmd_->setup_user_authentification(); }
+ Cmd_ptr get_cmd() const { return cmd_;}
+
+ /// This is called in the server only, to handle the quest.
+ STC_Cmd_ptr handleRequest(AbstractServer*) const;
+
+ std::ostream& print(std::ostream& os) const;
+
+ bool getRequest() const { return (cmd_.get()) ? cmd_->get_cmd() : false; }
+ bool terminateRequest() const { return (cmd_.get()) ? cmd_->terminate_cmd() : false; }
+ bool groupRequest() const { return (cmd_.get()) ? cmd_->group_cmd() : false; }
+
+ /// Used by boost test, to verify persistence
+ bool operator==(const ClientToServerRequest& rhs) const;
+
+private:
+ Cmd_ptr cmd_;
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/) {
+ ar & cmd_;
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, const ClientToServerRequest& d);
+
+// Do NOT use
+// BOOST_CLASS_IMPLEMENTATION(ClientToServerRequest, boost::serialization::object_serializable)
+// i.e eliminate serialisation overhead at the cost of never being able to increase the version.
+// Since we may need use version ing in the future
+
+// This should ONLY be added to objects that are *NOT* serialised through a pointer
+// Eliminate object tracking (even if serialised through a pointer)
+// at the risk of a programming error creating duplicate objects.
+BOOST_CLASS_TRACKING(ClientToServerRequest,boost::serialization::track_never);
+
+#endif
diff --git a/Base/src/Cmd.hpp b/Base/src/Cmd.hpp
new file mode 100644
index 0000000..765e641
--- /dev/null
+++ b/Base/src/Cmd.hpp
@@ -0,0 +1,27 @@
+#ifndef CMD_HPP_
+#define CMD_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name : Cmd
+// Author : Avi
+// Revision : $Revision: #84 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <boost/shared_ptr.hpp>
+
+class ClientToServerCmd;
+class ServerToClientCmd;
+class ServerReply;
+
+typedef boost::shared_ptr<ClientToServerCmd> Cmd_ptr;
+typedef boost::shared_ptr<ServerToClientCmd> STC_Cmd_ptr;
+
+#endif
diff --git a/Base/src/Connection.hpp b/Base/src/Connection.hpp
new file mode 100644
index 0000000..4a71443
--- /dev/null
+++ b/Base/src/Connection.hpp
@@ -0,0 +1,315 @@
+#ifndef CONNECTION_HPP_
+#define CONNECTION_HPP_
+//============================================================================
+// Name : Connection.cpp
+// Author : Avi
+// Revision : $Revision: #26 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Serves as the connection between client server
+//============================================================================
+
+#if defined(HPUX)
+#include <sys/select.h> // hp-ux uses pselect
+#endif
+
+#include <iomanip>
+#include <string>
+#include <sstream>
+#include <vector>
+
+#include <boost/asio.hpp>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/tuple/tuple.hpp>
+
+#include "Log.hpp"
+#include "Str.hpp"
+#include "Ecf.hpp"
+#include "Serialization.hpp"
+
+#ifdef DEBUG
+//#define DEBUG_CONNECTION 1
+//#define DEBUG_CONNECTION_MEMORY 1
+#endif
+
+/// The connection class provides serialisation primitives on top of a socket.
+/// ISSUES
+/// ======
+/// When the test are run with different configuration
+/// TEXT,BINARY, PORTABLE_BINARY there was _no_ discernible difference in the
+/// run times? I would have expected client->server communication via binary
+/// to be faster. However the definition file we are using are relatively small!
+///
+/// See: ACore/src/boost_archive.hpp for details about serialisation migration issues
+///
+/**
+ * Each message sent using this class consists of:
+ * @li An 8-byte header containing the length of the serialized data in
+ * hexadecimal.
+ * @li The serialized data.
+ */
+class connection {
+public:
+ /// Allow tentative support for new client to talk to old server
+ /// by changing the boost serialisation archive version, hence tentative
+ connection(boost::asio::io_service& io_service)
+ : allow_new_client_old_server_(0),
+ allow_old_client_new_server_(0),
+ socket_(io_service)
+ {
+#ifdef DEBUG_CONNECTION
+ std::cout << "Connection::connection\n";
+#endif
+ }
+
+ ~connection() {
+#ifdef DEBUG_CONNECTION
+ std::cout << "Connection::~connection socket_.is_open() = " << socket_.is_open() << "\n\n";
+#endif
+ }
+
+ /// Get the underlying socket. Used for making a connection or for accepting
+ /// an incoming connection.
+ boost::asio::ip::tcp::socket& socket() {
+ return socket_;
+ }
+
+ // support for forward compatibility, by changing boost archive version, used in client context
+ // See: ACore/src/boost_archive.hpp for details about serialisation migration issues
+ void allow_new_client_old_server(int f) { allow_new_client_old_server_ = f;}
+
+ // support for forward compatibility, by changing boost archive version, used in server context
+ void allow_old_client_new_server(int f) { allow_old_client_new_server_ = f;}
+
+
+ /// Asynchronously write a data structure to the socket.
+ template<typename T, typename Handler>
+ void async_write(const T& t, Handler handler) {
+
+#ifdef DEBUG_CONNECTION
+ std::cout << "Connection::async_write, Serialise the data first so we know how large it is\n";
+#endif
+ // Serialise the data first so we know how large it is.
+ try {
+ ecf::save_as_string(outbound_data_,t);
+
+ if (allow_new_client_old_server_ != 0 && !Ecf::server()) {
+ // Client context, forward compatibility, new client -> old server
+ ecf::boost_archive::replace_version(outbound_data_,allow_new_client_old_server_);
+ }
+
+ // Server context: To allow build of ecflow, i.e old clients 3.0.x, installed on machines hpux,aix,etc
+ // need to communicate to *new* server 4.0.0, new server (boost 1.53:10) ) --> (old_client:boost_1.47:9)
+ // Note: the read below, will have determined the actual archive version used.
+ if (Ecf::server() && allow_old_client_new_server_ != 0 ) {
+ ecf::boost_archive::replace_version(outbound_data_,allow_old_client_new_server_);
+ }
+
+ } catch (const boost::archive::archive_exception& ae ) {
+ // Unable to decode data. Something went wrong, inform the caller.
+ log_archive_error("Connection::async_write, boost::archive::archive_exception ",ae);
+ boost::system::error_code error(boost::asio::error::invalid_argument);
+ socket_.get_io_service().post(boost::bind(handler, error));
+ return;
+ }
+
+#ifdef DEBUG_CONNECTION
+ std::cout << "Connection::async_write Format the header \n";
+#endif
+ // Format the header.
+ std::ostringstream header_stream;
+ header_stream << std::setw(header_length) << std::hex << outbound_data_.size();
+ if (!header_stream || header_stream.str().size() != header_length) {
+ // Something went wrong, inform the caller.
+ log_error("Connection::async_write, could not format header");
+ boost::system::error_code error(boost::asio::error::invalid_argument);
+ socket_.get_io_service().post(boost::bind(handler, error));
+ return;
+ }
+ outbound_header_ = header_stream.str();
+
+
+#ifdef DEBUG_CONNECTION_MEMORY
+ if (Ecf::server()) std::cout << "server::";
+ else std::cout << "client::";
+ std::cout << "async_write outbound_header_.size(" << outbound_header_.size() << ") outbound_data_.size(" << outbound_data_.size() << ")\n";
+#endif
+
+#ifdef DEBUG_CONNECTION
+ std::cout << "Connection::async_write Write the serialized data to the socket. \n";
+#endif
+ // Write the serialized data to the socket. We use "gather-write" to send
+ // both the header and the data in a single write operation.
+ std::vector<boost::asio::const_buffer> buffers; buffers.reserve(2);
+ buffers.push_back(boost::asio::buffer(outbound_header_));
+ buffers.push_back(boost::asio::buffer(outbound_data_));
+ boost::asio::async_write(socket_, buffers, handler);
+
+#ifdef DEBUG_CONNECTION
+ std::cout << "Connection::async_write END \n";
+#endif
+ }
+
+ /// Asynchronously read a data structure from the socket.
+ template<typename T, typename Handler>
+ void async_read(T& t, Handler handler) {
+
+#ifdef DEBUG_CONNECTION
+ std::cout << "Connection::async_read\n";
+#endif
+
+ // Issue a read operation to read exactly the number of bytes in a header.
+ void (connection::*f)(const boost::system::error_code&, T&,boost::tuple<Handler>)
+ = &connection::handle_read_header<T, Handler>;
+
+ boost::asio::async_read(socket_, boost::asio::buffer(inbound_header_),
+ boost::bind(f, this, boost::asio::placeholders::error,
+ boost::ref(t), boost::make_tuple(handler)));
+ }
+
+private:
+ /// Handle a completed read of a message header. The handler is passed using
+ /// a tuple since boost::bind seems to have trouble binding a function object
+ /// created using boost::bind as a parameter.
+ template<typename T, typename Handler>
+ void handle_read_header(const boost::system::error_code& e, T& t,boost::tuple<Handler> handler)
+ {
+ if (e) {
+ boost::get<0>(handler)(e);
+ } else {
+ // Determine the length of the serialized data.
+ std::istringstream is(std::string(inbound_header_, header_length));
+ std::size_t inbound_data_size = 0;
+ if (!(is >> std::hex >> inbound_data_size)) {
+
+ // Header doesn't seem to be valid. Inform the caller.
+ boost::system::error_code error(boost::asio::error::invalid_argument);
+ boost::get<0>(handler)(error);
+ return;
+ }
+
+ // Start an asynchronous call to receive the data.
+ inbound_data_.resize(inbound_data_size);
+ void (connection::*f)(const boost::system::error_code&, T&,boost::tuple<Handler>)
+ = &connection::handle_read_data<T, Handler>;
+
+ boost::asio::async_read(socket_,
+ boost::asio::buffer(inbound_data_), boost::bind(f, this,
+ boost::asio::placeholders::error, boost::ref(t),
+ handler));
+ }
+ }
+
+ /// Handle a completed read of message data.
+ template<typename T, typename Handler>
+ void handle_read_data(const boost::system::error_code& e, T& t, boost::tuple<Handler> handler)
+ {
+ if (e) {
+ boost::get<0>(handler)(e);
+ } else {
+ // Extract the data structure from the data just received.
+ try {
+ std::string archive_data(&inbound_data_[0], inbound_data_.size());
+
+#ifdef DEBUG_CONNECTION_MEMORY
+ if (Ecf::server()) std::cout << "server::";
+ else std::cout << "client::";
+ std::cout << "handle_read_data inbound_data_.size(" << inbound_data_.size() << ")\n";
+#endif
+
+ ecf::restore_from_string(archive_data,t);
+
+ // Server context: To allow build of ecflow, i.e old clients 3.0.x, installed on machines hpux,aix,etc
+ // need to communicate to *new* server 4.0.0, new server (boost 1.53:10) ) --> (old_client:boost_1.47:9)
+ if (Ecf::server() && allow_old_client_new_server_ != 0 ) {
+ // get the actual version used, and *re-use* when replying back to *old* client
+ int archive_version_in_data = ecf::boost_archive::extract_version(archive_data);
+ int current_archive_version = ecf::boost_archive::version();
+ if ( current_archive_version != archive_version_in_data ) {
+ allow_old_client_new_server_ = archive_version_in_data;
+ }
+ else {
+ // compatible, don't bother changing the write format
+ allow_old_client_new_server_ = 0;
+ }
+ }
+ }
+ catch (const boost::archive::archive_exception& ae ) {
+
+ // Log anyway so we know client <--> server incompatible
+ log_archive_error("Connection::handle_read_data, boost::archive::archive_exception ",ae);
+
+ // two context, client code or server, before giving up, try
+ // - Client context, new server -> old client (* assumes old client updated, with this code *)
+ // - Server context, new client -> old server (* assumes old server updated, with this code *)
+ // Match up the boost archive version in the string archive_data with current version
+ std::string archive_data(&inbound_data_[0], inbound_data_.size());
+ int current_archive_version = ecf::boost_archive::version();
+ int archive_version_in_data = ecf::boost_archive::extract_version(archive_data);
+ if (current_archive_version != archive_version_in_data ) {
+ if (ecf::boost_archive::replace_version(archive_data,current_archive_version)) {
+
+ try {
+ ecf::restore_from_string(archive_data,t);
+ // It worked
+ boost::get<0>(handler)(e);
+ return;
+ }
+ catch (...) {} // fall through and return error code
+ }
+ }
+
+ // Unable to decode data.
+ boost::system::error_code error( boost::asio::error::invalid_argument);
+ boost::get<0>(handler)(error);
+ return;
+ }
+ catch (std::exception& ) {
+ log_error("Connection::handle_read_data, Unable to decode data");
+ boost::system::error_code error( boost::asio::error::invalid_argument);
+ boost::get<0>(handler)(error);
+ return;
+ }
+
+ // Inform caller that data has been received ok.
+ boost::get<0>(handler)(e);
+ }
+ }
+
+private:
+
+ void log_error(const char* msg) {
+ const char* in_context = ", in client";
+ if (Ecf::server()) in_context = ", in server";
+ ecf::LogToCout logToCout;
+ LOG(ecf::Log::ERR, msg << in_context);
+ }
+
+ void log_archive_error(const char* msg,const boost::archive::archive_exception& ae) {
+ const char* in_context = ", in client";
+ if (Ecf::server()) in_context = ", in server";
+ ecf::LogToCout logToCout;
+ LOG(ecf::Log::ERR, msg << ae.what() << in_context);
+ }
+
+private:
+ int allow_new_client_old_server_;
+ int allow_old_client_new_server_;
+ boost::asio::ip::tcp::socket socket_;/// The underlying socket.
+ std::string outbound_header_; /// Holds an out-bound header.
+ std::string outbound_data_; /// Holds the out-bound data.
+ enum { header_length = 8 }; /// The size of a fixed length header.
+ char inbound_header_[header_length]; /// Holds an in-bound header.
+ std::vector<char> inbound_data_; /// Holds the in-bound data.
+};
+
+typedef boost::shared_ptr<connection> connection_ptr;
+
+#endif /* CONNECTION_HPP_ */
diff --git a/Base/src/Gnuplot.cpp b/Base/src/Gnuplot.cpp
new file mode 100644
index 0000000..7402f0d
--- /dev/null
+++ b/Base/src/Gnuplot.cpp
@@ -0,0 +1,379 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Encompasses functionality for plotting server load
+//============================================================================
+#include <assert.h>
+#include <vector>
+#include <iostream>
+#include <sstream>
+#include <fstream>
+#include <sys/stat.h> // for chmod
+#include <boost/bind.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+
+#include "Gnuplot.hpp"
+#include "File_r.hpp"
+#include "File.hpp"
+#include "Str.hpp"
+#include "NodePath.hpp"
+#include "Host.hpp"
+
+using namespace std;
+namespace fs = boost::filesystem;
+
+namespace ecf {
+
+Gnuplot::Gnuplot( const std::string& log_file,
+ const std::string& host,
+ const std::string& port,
+ size_t no_of_suites_to_plot
+ )
+: log_file_(log_file), host_(host),port_(port), no_of_suites_to_plot_(no_of_suites_to_plot)
+{
+ if (!fs::exists(log_file)) {
+ std::stringstream ss;
+ ss << "Gnuplot::Gnuplot: The log file " << log_file << " does not exist\n";
+ throw std::runtime_error( ss.str() );
+ }
+
+ std::string path_to_gnuplot = File::which("gnuplot");
+ if ( path_to_gnuplot.empty()) {
+ std::stringstream ss;
+ ss << "Gnuplot::Gnuplot: could not find gnuplot on $PATH.";
+ throw std::runtime_error(ss.str());
+ }
+}
+
+void Gnuplot::show_server_load() const
+{
+ std::string gnuplot_dat_file = host_.prefix_host_and_port(port_,"gnuplot.dat");
+ std::string gnuplot_script_file = host_.prefix_host_and_port(port_,"gnuplot.script");
+
+ // The vector index is the order in which suites are found, this will be used to place the suite in the correct column
+ std::vector<SuiteLoad> suite_vec;
+ std::string gnuplot_file = create_gnuplot_file(suite_vec,gnuplot_dat_file);
+ std::string gnuplot_script = create_gnuplot_script(gnuplot_file,suite_vec,no_of_suites_to_plot_,gnuplot_script_file);
+
+
+ // make the gnuplot_script file executable
+ if ( chmod( gnuplot_script.c_str(), 0755 ) != 0 ) {
+ std::stringstream ss;
+ ss << "Gnuplot::show_server_load: Could not make gnu script file " << gnuplot_script << " executable by using chmod";
+ throw std::runtime_error(ss.str());
+ }
+
+ std::string execute_gnuplot = "gnuplot " + gnuplot_script;
+ ::system(execute_gnuplot.c_str());
+}
+
+
+std::string Gnuplot::create_gnuplot_file(
+ std::vector<SuiteLoad>& suite_vec,
+ const std::string& temp_file ) const
+{
+ /// Will read the log file and create a new file that can be used as input to gnuplot
+ /// We will collate each request/cmd to the server made over a second.
+ /// There are two kinds of commands:
+ /// o User Commands: these start with --
+ /// o Child Command: these start with chd:
+ /// All child commands specify a path and hence suite, whereas for user commands this is optional
+ /// We will trap all use of paths, so that we can show which suites are contributing to the server load
+ /// This will be done for 4 suites
+ ///
+ /// Will convert: FROM:
+ /// XXX:[HH:MM:SS D.M.YYYY] chd:init [+additional information]
+ /// XXX:[HH:MM:SS D.M.YYYY] --begin [+additional information]
+ /// -------------: TO:
+ /// 1 2 3 4 5 6 7 8 9 10
+ /// HH:MM:SS D.M.YYYY request/sec child_request users_requests suite_0 suite_1 suite_2 suite_3 suite_n
+
+ /// The log file can be massive > 50Mb
+ File_r log_file(log_file_);
+ if ( !log_file.ok() ) throw std::runtime_error( "Gnuplot::prepare_for_gnuplot: Could not open log file " + log_file_ );
+
+
+ /// Create a new file that can be used with gnuplot. This has to be column based
+ std::ofstream gnuplot_file( temp_file.c_str() );
+ if ( !gnuplot_file ) {
+ throw std::runtime_error( "Gnuplot::prepare_for_gnuplot: Could not open output file: " + temp_file);
+ }
+
+ gnuplot_file << "#time date total-request child user suite_0 suite_1 suite_2 suite_3 suite_n\n";
+
+ std::vector< std::string > new_time_stamp;
+ std::vector< std::string > old_time_stamp;
+ size_t child_requests_per_second = 0;
+ size_t user_request_per_second = 0;
+ unsigned int plot_data_line_number = 0;
+ string line;
+ while ( log_file.good() ) {
+ log_file.getline( line); // default delimiter is /n
+
+ // The log file format we are interested is :
+ // 0 1 2 3
+ // MSG:[HH:MM:SS D.M.YYYY] chd:fullname [path +additional information]
+ // MSG:[HH:MM:SS D.M.YYYY] --begin [args | path(optional) ] :<user>
+
+ /// We are only interested in Commands (i.e MSG:), and not state changes
+ if (line.empty()) continue;
+ if (line[0] != 'M') continue;
+ std::string::size_type msg_pos = line.find("MSG:");
+ if (msg_pos != 0) continue;
+
+ bool child_cmd = false;
+ bool user_cmd = false;
+ if (line.find(Str::CHILD_CMD()) != std::string::npos) child_cmd = true;
+ else if (line.find(Str::USER_CMD()) != std::string::npos) user_cmd = true;
+ if (!child_cmd && !user_cmd) continue;
+
+ new_time_stamp.clear();
+ {
+ /// MSG:[HH:MM:SS D.M.YYYY] chd:fullname [+additional information] ---> HH:MM:SS D.M.YYYY
+ /// EXTRACT the date
+ string::size_type first_open_bracket = line.find('[');
+ if ( first_open_bracket == std::string::npos) { std::cout << line << "\n"; assert(false); continue;}
+ line.erase(0,first_open_bracket+1);
+
+ string::size_type first_closed_bracket = line.find(']');
+ if ( first_closed_bracket == std::string::npos) { std::cout << line << "\n"; assert(false); continue;}
+ std::string time_stamp = line.substr(0, first_closed_bracket);
+
+ Str::split(time_stamp, new_time_stamp);
+ if (new_time_stamp.size() != 2) continue;
+
+ line.erase(0,first_closed_bracket+1);
+ }
+
+ // Should be just left with " chd:<child command> " or " --<user command>, since we have remove time stamp
+//#ifdef DEBUG
+// std::cout << line << "\n";
+//#endif
+
+ if (old_time_stamp.empty()) {
+ if (child_cmd) child_requests_per_second++;
+ else user_request_per_second++;
+
+ // Extract path if any, to determine the suite most contributing to server load
+ size_t column_index = 0;
+ bool suite_path_found = extract_suite_path(line,child_cmd,suite_vec,column_index);
+ if ( suite_path_found ) assert(suite_vec[column_index].request_per_second_ <= (child_requests_per_second + user_request_per_second) );
+ }
+ else if (old_time_stamp[0] == new_time_stamp[0]) { // HH:MM:SS == HH:MM:SS
+ if (child_cmd) child_requests_per_second++;
+ else user_request_per_second++;
+
+ size_t column_index = 0;
+ bool suite_path_found = extract_suite_path(line,child_cmd,suite_vec,column_index);
+ if ( suite_path_found ) assert(suite_vec[column_index].request_per_second_ <= (child_requests_per_second + user_request_per_second) );
+ }
+ else {
+ /// Start of *NEW* time,
+ /// write the *OLD* time line should contain time date without []
+ /// 1 2 3 4 5 6 7 8 9 10
+ /// HH:MM:SS D.M.YYYY total_request child_request users_requests suite_0 suite_1 suite_2 suite_3 suite_n
+ plot_data_line_number++;
+ gnuplot_file << old_time_stamp[0] << " "
+ << old_time_stamp[1] << " "
+ << (child_requests_per_second + user_request_per_second) << " "
+ << child_requests_per_second << " "
+ << user_request_per_second << " ";
+ for(size_t i = 0; i < suite_vec.size(); i++) { gnuplot_file << suite_vec[i].request_per_second_ << " ";}
+ gnuplot_file << "\n";
+
+
+ // clear request per second
+ child_requests_per_second = 0;
+ user_request_per_second = 0;
+ for(size_t i= 0; i < suite_vec.size();i++) { suite_vec[i].request_per_second_ = 0; }
+
+ // start of *new* time
+ if (child_cmd) child_requests_per_second++;
+ else user_request_per_second++;
+
+ size_t column_index = 0;
+ bool suite_path_found = extract_suite_path(line,child_cmd,suite_vec,column_index);
+ if ( suite_path_found ) assert(suite_vec[column_index].request_per_second_ <= (child_requests_per_second + user_request_per_second) );
+ }
+
+ old_time_stamp = new_time_stamp;
+ }
+
+ if (plot_data_line_number < 3) {
+ throw std::runtime_error( "Gnuplot::prepare_for_gnuplot: Log file empty or not enough data for plot\n");
+ }
+ return temp_file;
+}
+
+std::string Gnuplot::create_gnuplot_script(
+ const std::string& path_to_file,
+ const std::vector<SuiteLoad>& suite_vec,
+ size_t no_of_suites_to_plot,
+ const std::string& script) const
+{
+ /// Create the gnuplot script file for rendering the graph
+ std::ofstream gnuplot_script( script.c_str() );
+ if ( !gnuplot_script ) {
+ throw std::runtime_error( "Gnuplot::create_gnuplot_script: Could not open output file: " + script);
+ }
+
+ gnuplot_script << "set term png\n";
+ gnuplot_script << "set output \"" << host_.name() << "." << port_ << ".png\"\n";
+
+
+ gnuplot_script << "set autoscale # scale axes automatically\n";
+ gnuplot_script << "set xtic auto rotate # set xtics automatically\n";
+ gnuplot_script << "set ytic auto # set ytics automatically\n";
+// gnuplot_script << "set origin 0,0.08 # offset y, so that rotated xtics don't truncate, However cause title to disappear\n";
+ gnuplot_script << "set title \"Server request per second\"\n";
+ gnuplot_script << "set x2label \"time/min\" textcolor lt 3\n";
+ gnuplot_script << "set ylabel \"requests\"\n";
+ gnuplot_script << "set xdata time\n";
+ gnuplot_script << "set grid # show grid\n";
+ gnuplot_script << "set timefmt \"%H:%M:%S %d.%m.%Y\"\n";
+
+ //# LINE COLORS, STYLES
+ //# type 'test' to see the colors and point types available.
+ //# Differs from x11 to postscript
+ //# lt chooses a particular line type: -1=black 1=red 2=grn 3=blue 4=purple 5=aqua 6=brn 7=orange 8=light-brn
+ //# lt must be specified before pt for colored points
+ //# for postscipt -1=normal, 1=grey, 2=dashed, 3=hashed, 4=dot, 5=dot-dash
+ //# lw chooses a line width 1=normal, can use 0.8, 0.3, 1.5, 3, etc.
+ //# ls chooses a line style
+
+ /// 1 2 3 4 5 6 7 8 9 n
+ /// HH:MM:SS D.M.YYYY total_request child_request users_requests suite_0 suite_1 suite_2 suite_3 suite_n
+
+ // determine which suite columns to plot based on server load
+ std::vector<SuiteLoad> suite_vec_copy = suite_vec;
+
+// cout << "sort vector according to load\n";
+ std::sort(suite_vec_copy.begin(),suite_vec_copy.end(),
+ boost::bind(std::greater<int>(),
+ boost::bind(&SuiteLoad::total_request_per_second_, _1),
+ boost::bind(&SuiteLoad::total_request_per_second_, _2)));
+// for(size_t i = 0; i < suite_vec_copy.size(); i++) {
+// cout << " " << suite_vec_copy[i].first << " " << suite_vec_copy[i].second << "\n";
+// }
+
+// cout << "get top loaded suites\n";
+ std::vector<std::string> suites;
+ for(size_t i = 0; i < suite_vec_copy.size() && i < no_of_suites_to_plot; i++) {
+ suites.push_back(suite_vec_copy[i].suite_name_);
+ }
+// std::copy(suites.begin(), suites.end(), std::ostream_iterator <std::string> (std::cout, "\n"));
+
+
+// cout << "now determine which columns the top suites belong to, **THIS** time <int> indicates column\n";
+ std::vector< std::pair<std::string,int> > ordered_suites;
+ for(size_t column = 0; column < suite_vec.size(); column++) {
+ for(size_t j = 0; j < suites.size(); j++) {
+ if (suites[j] == suite_vec[column].suite_name_) {
+ ordered_suites.push_back ( std::make_pair(suites[j], column));
+ }
+ }
+ }
+// for(size_t i = 0; i < ordered_suites.size(); i++) {
+// cout << " " << ordered_suites[i].first << " " << ordered_suites[i].second << "\n";
+// }
+
+
+ gnuplot_script << "plot \""
+ << path_to_file << "\" using 1:4 title \"child\" with lines, \""
+ << path_to_file << "\" using 1:5 title \"user\" with lines, \""
+ << path_to_file << "\" using 1:3 smooth bezier title \"total-load\" with lines lt 3";
+ if (!ordered_suites.empty()) gnuplot_script << ",";
+ else gnuplot_script << "\n";
+ for(size_t i = 0; i < ordered_suites.size(); i++) {
+ gnuplot_script << "\""
+ << path_to_file
+ << "\" using 1:" << (6 + ordered_suites[i].second)
+ << " smooth bezier title \"" << ordered_suites[i].first << "\" with lines";
+ if (i == ordered_suites.size() -1) gnuplot_script << "\n";
+ else gnuplot_script << ",";
+ }
+
+// gnuplot_script << "pause -1 \"Hit any key to continue\"\n\n";
+
+ return script;
+}
+
+
+bool Gnuplot::extract_suite_path(
+ const std::string& line,
+ bool child_cmd,
+ std::vector<SuiteLoad>& suite_vec,
+ size_t& column_index // 0 based
+ )
+{
+ // line should either
+ // chd:<childcommand> path
+ // --<user command) path<optional> :<user>
+ size_t forward_slash = line.find('/');
+ if ( forward_slash != std::string::npos) {
+
+ std::string path;
+ if (child_cmd) {
+
+ // For labels ignore paths in the label part
+ // MSG:[14:55:04 17.10.2013] chd:label progress 'core/nodeattr/nodeAParser' /suite/build/cray/cray_gnu/build_release/test
+ if (line.find("chd:label") != std::string::npos) {
+ size_t last_tick = line.rfind("'");
+ if ( last_tick != std::string::npos ) {
+ size_t the_forward_slash = line.find('/',last_tick);
+ if (the_forward_slash != std::string::npos) {
+ forward_slash = the_forward_slash;
+ }
+ }
+ }
+ path = line.substr(forward_slash);
+ }
+ else {
+ // Ignore the --news command, they dont have a path, hence i.e to ignore line like:
+ // MSG:[09:36:05 22.10.2013] --news=1 36506 6 :ma0 [server handle(36508,7) server(36508,7)
+ // : *Large* scale changes (new handle or suites added/removed) :NEWS]
+ // the /removed was being interpreted as a suite
+ if (line.find("--news") != std::string::npos) return false;
+ }
+
+ // find the space after the path
+ size_t space_pos = line.find(" ",forward_slash);
+ if (space_pos != std::string::npos && space_pos > forward_slash) {
+ path = line.substr(forward_slash,space_pos-forward_slash);
+ }
+
+ if (!path.empty()) {
+
+ std::vector<std::string> theNodeNames; theNodeNames.reserve(4);
+ NodePath::split(path,theNodeNames);
+ if (!theNodeNames.empty()) {
+ for(size_t n = 0; n < suite_vec.size(); n++) {
+ if (suite_vec[n].suite_name_ == theNodeNames[0] ) {
+ suite_vec[n].request_per_second_++;
+ suite_vec[n].total_request_per_second_++;
+ column_index = n;
+ return true;
+ }
+ }
+
+ suite_vec.push_back( SuiteLoad(theNodeNames[0]) );
+ column_index = suite_vec.size() - 1;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
+}
diff --git a/Base/src/Gnuplot.hpp b/Base/src/Gnuplot.hpp
new file mode 100644
index 0000000..a3aa743
--- /dev/null
+++ b/Base/src/Gnuplot.hpp
@@ -0,0 +1,78 @@
+#ifndef GNUPLOT_HPP_
+#define GNUPLOT_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name : Log
+// Author : Avi
+// Revision : $Revision: #2 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <string>
+#include <boost/noncopyable.hpp>
+#include "Host.hpp"
+
+namespace ecf {
+
+class Gnuplot : private boost::noncopyable {
+public:
+
+ Gnuplot( const std::string& log_file,
+ const std::string& host,
+ const std::string& port,
+ size_t no_of_suites_to_plot = 5
+ );
+
+ /// parse the log file and show gnuplot of server load
+ /// Include the suite most contributing to the load
+ /// generates two files
+ /// o <host>.<port>.gnuplot.dat
+ /// o <host>.<port>.gnuplot.script
+ void show_server_load() const;
+
+private:
+ std::string log_file_;
+ Host host_;
+ std::string port_;
+ size_t no_of_suites_to_plot_;
+
+private:
+
+ struct SuiteLoad {
+ SuiteLoad(const std::string& name) : suite_name_(name), request_per_second_(1), total_request_per_second_(1) {}
+
+ std::string suite_name_;
+ size_t request_per_second_;
+ size_t total_request_per_second_;
+ };
+
+ /// Returns that path to file created by this function.
+ /// The create file is to be used by gnuplot to show the server load.
+ /// Can throw exceptions
+ std::string create_gnuplot_file(
+ std::vector<SuiteLoad>& suite_vec,
+ const std::string& input_data) const;
+
+ /// returns the path to the gnuplot script
+ std::string create_gnuplot_script(
+ const std::string& path_to_file,
+ const std::vector<SuiteLoad>& suite_vec,
+ size_t no_of_suites_to_plot,
+ const std::string& script) const;
+
+ static bool extract_suite_path(
+ const std::string& line,
+ bool child_cmd,
+ std::vector<SuiteLoad>& suite_vec,
+ size_t& column_index // 0 based
+ );
+};
+}
+
+#endif
diff --git a/Base/src/ServerReply.cpp b/Base/src/ServerReply.cpp
new file mode 100644
index 0000000..b055ccc
--- /dev/null
+++ b/Base/src/ServerReply.cpp
@@ -0,0 +1,38 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+//#include <iostream>
+#include "ServerReply.hpp"
+
+/// *Note* server_reply_.client_handle_ is kept until the next call to register a new client_handle
+/// The client invoker can be used multiple times, hence keep value of defs, and client handle in server reply
+void ServerReply::clear_for_invoke(bool command_line_interface)
+{
+ //std::cout << "ServerReply::clear_for_invoke\n";
+ cli_ = command_line_interface;
+ in_sync_ = false;
+ full_sync_ = false;
+ news_ = ServerReply::NO_NEWS;
+ block_client_on_home_server_ = false;
+ block_client_server_halted_ = false;
+ block_client_zombie_detected_ = false;
+ host_.clear();
+ port_.clear();
+ error_msg_.clear();
+ str_.clear();
+ zombies_.clear();
+ str_vec_.clear();
+ client_handle_suites_.clear();
+ changed_nodes_.clear();
+}
diff --git a/Base/src/ServerReply.hpp b/Base/src/ServerReply.hpp
new file mode 100644
index 0000000..d7d342f
--- /dev/null
+++ b/Base/src/ServerReply.hpp
@@ -0,0 +1,144 @@
+#ifndef SERVER_REPLY_HPP_
+#define SERVER_REPLY_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #18 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <string>
+#include <vector>
+#include <boost/noncopyable.hpp>
+#include "NodeFwd.hpp"
+#include "Zombie.hpp"
+#include "Stats.hpp"
+
+/// This class is used to hold the replies back from the server
+/// *Note* server_reply_.client_handle_ is kept until the next call to register a new client_handle
+/// The client invoker can be used multiple times, hence keep value of defs, and client handle in server reply
+
+class ServerReply : private boost::noncopyable {
+public:
+ // After ECFLOW-182, NO_DEFS no longer used, however kept, to ensure client/server compatibility
+ // ie. for new client(viewer) must process this from old server, which could return NO_DEFS
+ enum News_t { NO_NEWS, NEWS, DO_FULL_SYNC, NO_DEFS };
+ ServerReply()
+ : cli_(false), in_sync_(false), full_sync_(false), news_(NO_NEWS),
+ block_client_on_home_server_(false),block_client_server_halted_(false),block_client_zombie_detected_(false),
+ client_handle_(0) {}
+
+ /// *Note* server_reply_.client_handle_ is kept until the next call to register a new client_handle
+ /// The client invoker can be used multiple times, hence keep value of defs, and client handle in server reply
+ /// and reset everything else
+ void clear_for_invoke(bool command_line_interface); // true if calling from command line
+
+ /// task based replies
+ bool block_client_on_home_server() const { return block_client_on_home_server_;}
+ void set_block_client_on_home_server() { block_client_on_home_server_ = true;}
+
+ bool block_client_server_halted() const { return block_client_server_halted_;}
+ void set_block_client_server_halted() { block_client_server_halted_ = true;}
+
+ bool block_client_zombie_detected() const { return block_client_zombie_detected_;}
+ void set_block_client_zombie_detected() { block_client_zombie_detected_ = true;}
+
+ void set_host_port(const std::string& host, const std::string& port) { host_ = host; port_ = port;}
+ const std::string& host() const { return host_;}
+ const std::string& port() const { return port_;}
+
+ bool client_request_failed() const { return !error_msg_.empty(); }
+ void set_error_msg(const std::string& e) { error_msg_ = e;}
+ const std::string& error_msg() const { return error_msg_; }
+ std::string& get_error_msg() { return error_msg_; }
+
+ const std::vector<Zombie>& zombies() const { return zombies_; }
+ void set_zombies( const std::vector<Zombie>& z) { zombies_ = z;}
+
+ /// For uses with the suites cmd, or any other command that needs a vector of strings form server
+ const std::vector<std::string>& get_string_vec() const { return str_vec_; }
+ void set_string_vec( const std::vector<std::string>& z) { str_vec_ = z;}
+
+ const std::vector<std::pair<unsigned int, std::vector<std::string> > >& get_client_handle_suites() const { return client_handle_suites_; }
+ void set_client_handle_suites(const std::vector<std::pair<unsigned int, std::vector<std::string> > >& s) { client_handle_suites_ = s; }
+
+ /// Only valid when the client requested the CFileCmd or log file from the server
+ /// Other times this will be empty.
+ const std::string& get_string() const { return str_; }
+ void set_string( const std::string& f) { str_ = f;}
+
+ /// Only valid when Stats command called.
+ const Stats& stats() const { return stats_; }
+ void set_stats( const Stats& s) { stats_ = s;}
+
+ /// Return true if client is using Command Level Interface. Set via clear_for_invoke()
+ bool cli() const { return cli_; }
+
+ /// Only valid after a call to sync()
+ /// in_sync() should be called after call to sync() Returns true if client defs is now in_sync with server
+ bool in_sync() const { return in_sync_;}
+ void set_sync(bool b) { in_sync_ = b;}
+
+ /// The SSyncCmd will set if we have a full sync(ie retrieved full node tree from server) or incremental sync
+ bool full_sync() const { return full_sync_; }
+ void set_full_sync(bool f) { full_sync_ = f; }
+
+ /// Only valid after a call to news()
+ /// return true if the server has changed
+ News_t get_news() const { return news_; }
+ void set_news(News_t n) { news_ = n;}
+
+
+ /// Only valid when the client requested the defs node tree from the server
+ /// The defs *WILL* be retained until the next call to get the server defs
+ /// **Hence is NOT reset in clear_for_invoke()
+ defs_ptr client_defs() const { return client_defs_; }
+ void set_client_defs(defs_ptr d) { client_defs_ = d;}
+
+ /// Only valid when the client requested the node from the server
+ /// The node *WILL* be retained until the next call to get the node
+ /// **Hence is NOT reset in clear_for_invoke()
+ node_ptr client_node() const { return client_node_; }
+ void set_client_node(node_ptr d) { client_node_ = d;}
+
+ /// A client handle of value 0 is not valid. Created in the server
+ /// We should keep a reference to the client handle, for use with client handle commands
+ /// **Hence is NOT reset in clear_for_invoke()
+ void set_client_handle(int handle) { client_handle_ = handle;}
+ int client_handle() const { return client_handle_;}
+
+ // During incremental sync, record list of changed nodes, used by python api
+ std::vector<std::string>& changed_nodes() { return changed_nodes_; }
+
+private:
+ friend class SSyncCmd;
+ bool cli_;
+ bool in_sync_; // clear at the start of invoke
+ bool full_sync_; // clear at the start of invoke
+ News_t news_; // clear at the start of invoke
+ bool block_client_on_home_server_; // clear at the start of invoke
+ bool block_client_server_halted_; // clear at the start of invoke
+ bool block_client_zombie_detected_; // clear at the start of invoke
+ std::string host_; // clear at the start of invoke
+ std::string port_; // clear at the start of invoke
+ std::string str_; // clear at the start of invoke
+ std::string error_msg_; // clear at the start of invoke
+ std::vector<Zombie> zombies_; // clear at the start of invoke
+ std::vector<std::string> str_vec_; // clear at the start of invoke
+ std::vector<std::string> changed_nodes_;// clear at the start of invoke
+ std::vector<std::pair<unsigned int, std::vector<std::string> > > client_handle_suites_; // clear at the start of invoke
+ Stats stats_; // Used for test only, ideally need to clear
+
+ int client_handle_; // set locally when suites are registered, and kept for reference
+ defs_ptr client_defs_; // server reply stored as the client side defs, kept locally
+ node_ptr client_node_; // server reply stored as the client side node, kept locally
+};
+#endif
diff --git a/Base/src/ServerToClientResponse.cpp b/Base/src/ServerToClientResponse.cpp
new file mode 100644
index 0000000..9c945f9
--- /dev/null
+++ b/Base/src/ServerToClientResponse.cpp
@@ -0,0 +1,70 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #13 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <assert.h>
+#include <fstream>
+#include <sstream>
+#include <stdexcept>
+
+#include "ServerToClientResponse.hpp"
+#include "ClientToServerRequest.hpp" // for throw
+#include "AbstractServer.hpp"
+
+using namespace std;
+using namespace ecf;
+
+bool ServerToClientResponse::handle_server_response( ServerReply& r, Cmd_ptr cts_cmd, bool debug ) const
+{
+ /// Called in client context: see ClientInvoker
+ if (stc_cmd_.get()) {
+ return stc_cmd_->handle_server_response(r,cts_cmd,debug);
+ }
+
+ /// ClientToServerRequest::handleRequest returned a NULL pointer stc_cmd_.
+ std::stringstream ss;
+ ss << "ServerToClientResponse::handle_server_response: ";
+ if (cts_cmd.get()) {
+ ss << "Client request ";
+ cts_cmd->print(ss);
+ ss << " failed. ";
+ }
+ ss << "Server replied with a NULL message\n";
+ throw std::runtime_error(ss.str());
+}
+
+std::ostream& ServerToClientResponse::print( std::ostream& os ) const
+{
+ if (stc_cmd_.get()) {
+ return stc_cmd_->print(os);
+ }
+ return os << "NULL ServerToClientResponse";
+}
+
+bool ServerToClientResponse::operator==(const ServerToClientResponse& rhs) const
+{
+ if (!stc_cmd_.get() && !rhs.stc_cmd_.get()) {
+ return true;
+ }
+ if (stc_cmd_.get() && !rhs.stc_cmd_.get()) {
+ return false;
+ }
+ if (!stc_cmd_.get() && rhs.stc_cmd_.get()) {
+ return false;
+ }
+ return (stc_cmd_->equals(rhs.stc_cmd_.get()));
+}
+
+std::ostream& operator<<( std::ostream& os, const ServerToClientResponse& d ) {
+ return d.print( os );
+}
diff --git a/Base/src/ServerToClientResponse.hpp b/Base/src/ServerToClientResponse.hpp
new file mode 100644
index 0000000..8f3b2fc
--- /dev/null
+++ b/Base/src/ServerToClientResponse.hpp
@@ -0,0 +1,62 @@
+#ifndef SERVERTOCLIENTREQUEST_HPP_
+#define SERVERTOCLIENTREQUEST_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #30 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <boost/noncopyable.hpp>
+#include <boost/serialization/tracking.hpp>
+#include "ServerToClientCmd.hpp"
+
+// Base class for server to client requesting. This class is used in the IPC messaging between
+// server and client
+class ServerToClientResponse : private boost::noncopyable {
+public:
+ ServerToClientResponse() {}
+ ServerToClientResponse(const STC_Cmd_ptr& cmd) : stc_cmd_(cmd) {}
+ ~ServerToClientResponse() {}
+
+ STC_Cmd_ptr get_cmd() const { return stc_cmd_; }
+ void set_cmd(const STC_Cmd_ptr& cmd) { stc_cmd_ = cmd;}
+
+ std::ostream& print(std::ostream& os) const;
+
+ /// Handle the response from the server. On the client side
+ /// return true IF and ONLY IF client response was ok, if further client action required return false
+ bool handle_server_response( ServerReply&, Cmd_ptr cts_cmd, bool debug ) const;
+
+ /// Used by boost test, to verify persistence
+ bool operator==(const ServerToClientResponse& rhs) const;
+
+private:
+ STC_Cmd_ptr stc_cmd_;
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /*version*/) {
+ ar & stc_cmd_;
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, const ServerToClientResponse& d);
+
+// Do NOT use
+// BOOST_CLASS_IMPLEMENTATION(ecf::ServerToClientResponse, boost::serialization::object_serializable)
+// i.e eliminate serialisation overhead at the cost of never being able to increase the version.
+// Since we may need use version ing in the future
+
+// This should ONLY be added to objects that are *NOT* serialised through a pointer
+// Eliminate object tracking (even if serialised through a pointer)
+// at the risk of a programming error creating duplicate objects.
+BOOST_CLASS_TRACKING(ServerToClientResponse,boost::serialization::track_never);
+
+#endif
diff --git a/Base/src/Stats.cpp b/Base/src/Stats.cpp
new file mode 100644
index 0000000..53781c5
--- /dev/null
+++ b/Base/src/Stats.cpp
@@ -0,0 +1,333 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #35 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <iostream>
+#include <sstream>
+#include <iomanip>
+#include <string>
+#include "Stats.hpp"
+#include "SState.hpp"
+
+using namespace std;
+
+Stats::Stats() :
+
+ status_(0),
+ request_count_(0),
+ job_sub_interval_(0),
+ checkpt_interval_(0),
+ checkpt_save_time_alarm_(0),
+ checkpt_mode_(ecf::CheckPt::UNDEFINED),
+ no_of_suites_(0),
+
+ checkpt_(0),
+ restore_defs_from_checkpt_(0),
+
+ server_version_(0),
+ restart_server_(0),
+ shutdown_server_(0),
+ halt_server_(0),
+ reload_white_list_file_(0),
+ ping_(0),
+ debug_server_on_(0),
+ debug_server_off_(0),
+ get_defs_(0),
+ sync_(0),
+ news_(0),
+
+ node_job_gen_(0),
+ node_check_job_gen_only_(0),
+ node_delete_(0),
+ node_suspend_(0),
+ node_resume_(0),
+ node_kill_(0),
+ node_status_(0),
+ node_edit_history_(0),
+
+ log_cmd_(0),
+ log_msg_cmd_(0),
+ begin_cmd_(0),
+
+ task_init_(0),
+ task_complete_(0),
+ task_wait_(0),
+ task_abort_(0),
+ task_event_(0),
+ task_meter_(0),
+ task_label_(0),
+
+ zombie_fob_(0),
+ zombie_fail_(0),
+ zombie_adopt_(0),
+ zombie_remove_(0),
+ zombie_get_(0),
+ zombie_block_(0),
+ zombie_kill_(0),
+
+ requeue_node_(0),
+ order_node_(0),
+ run_node_(0),
+ load_defs_(0),
+ replace_(0),
+ force_(0),
+ free_dep_(0),
+ suites_(0),
+ edit_script_(0),
+
+ alter_cmd_(0),
+ ch_cmd_(0),
+ file_ecf_(0),
+ file_job_(0),
+ file_jobout_(0),
+ file_cmdout_(0),
+ file_manual_(0),
+
+ plug_(0),
+ move_(0),
+ group_cmd_(0),
+ server_load_cmd_(0),
+ stats_(0),
+ check_(0)
+{
+}
+
+void Stats::update_stats(int poll_interval)
+{
+ // Called at poll time, ie just before node tree traversal
+ request_vec_.push_back( std::make_pair(request_count_,poll_interval) );
+ request_count_ = 0;
+ request_stats_.clear();
+
+ // To stop excessive memory usage , we will only store, request per poll period, for 1 hour
+ if (request_vec_.size() > 60) {
+ request_vec_.pop_front();
+ }
+}
+
+void Stats::update_for_serialisation()
+{
+ /// This *ONLY* compute the data when this function is called
+ /// >>> Hence the server load is only valid for last hour <<<
+ no_of_suites_ = 0;
+ if (request_vec_.empty()) return;
+
+ std::stringstream ss;
+ int count = 0;
+ int request = 0;
+ int seconds = 0;
+ std::deque<std::pair<int,int> >::reverse_iterator rend = request_vec_.rend();
+ for(std::deque<std::pair<int,int> >::reverse_iterator i = request_vec_.rbegin(); i != rend; ++i) {
+ count++;
+ request += (*i).first;
+ seconds += (*i).second;
+ double request_per_second = (double)request/seconds;
+
+ if (count == 1) {
+ ss << setiosflags(ios::fixed) << setprecision(2) << request_per_second;
+ }
+ else if (count == 5) {
+ ss << " " << request_per_second;
+ }
+ else if (count == 15) {
+ ss << " " << request_per_second;
+ }
+ else if (count == 30) {
+ ss << " " << request_per_second ;
+ }
+ else if (count == 60) {
+ ss << " " << request_per_second;
+ }
+ }
+ request_stats_ = ss.str();
+}
+
+void Stats::reset()
+{
+ checkpt_ = 0;
+ restore_defs_from_checkpt_ = 0;
+
+ server_version_ = 0;
+ restart_server_ = 0;
+ shutdown_server_ = 0;
+ halt_server_ = 0;
+ reload_white_list_file_ = 0;
+ ping_ = 0;
+ debug_server_on_ = 0;
+ debug_server_off_ = 0;
+ get_defs_ = 0;
+ sync_ = 0;
+ news_ = 0;
+
+ node_job_gen_ = 0;
+ node_check_job_gen_only_ = 0;
+ node_delete_ = 0;
+ node_suspend_ = 0;
+ node_resume_ = 0;
+ node_kill_ = 0;
+ node_status_ = 0;
+ node_edit_history_ = 0;
+
+ log_cmd_ = 0;
+ log_msg_cmd_ = 0;
+ begin_cmd_ = 0;
+
+ task_init_ = 0;
+ task_complete_ = 0;
+ task_wait_ = 0;
+ task_abort_ = 0;
+ task_event_ = 0;
+ task_meter_ = 0;
+ task_label_ = 0;
+
+ zombie_fob_ = 0;
+ zombie_fail_ = 0;
+ zombie_adopt_ = 0;
+ zombie_remove_ = 0;
+ zombie_get_ = 0;
+ zombie_block_ = 0;
+ zombie_kill_ = 0;
+
+ requeue_node_ = 0;
+ order_node_ = 0;
+ run_node_ = 0;
+ load_defs_ = 0;
+ replace_ = 0;
+ force_ = 0;
+ free_dep_ = 0;
+ suites_ = 0;
+ edit_script_ = 0;
+
+ alter_cmd_ = 0;
+ ch_cmd_ = 0;
+ file_ecf_ = 0;
+ file_job_ = 0;
+ file_jobout_ = 0;
+ file_cmdout_ = 0;
+ file_manual_ = 0;
+
+ plug_ = 0;
+ move_ = 0;
+ group_cmd_ = 0;
+ server_load_cmd_ = 0;
+ stats_ = 0;
+ check_ = 0;
+}
+
+static string show_checkpt_mode(ecf::CheckPt::Mode m){
+ switch (m) {
+ case ecf::CheckPt::NEVER: return "CHECK_NEVER"; break;
+ case ecf::CheckPt::ON_TIME: return "CHECK_ON_TIME"; break;
+ case ecf::CheckPt::ALWAYS: return "CHECK_ON_ALWAYS"; break;
+ case ecf::CheckPt::UNDEFINED: return "UNDEFINED"; break;
+ }
+ return std::string();
+}
+
+void Stats::show(std::ostream& os) const
+{
+ int width = 35;
+ os << "Server statistics\n";
+ os << left << setw(width) << " Version " << version_ << "\n";
+ os << left << setw(width) << " Status " << SState::to_string(status_) << "\n";
+ os << left << setw(width) << " Host " << host_ << "\n";
+ os << left << setw(width) << " Port " << port_ << "\n";
+ os << left << setw(width) << " Up since " << up_since_ << "\n";
+ os << left << setw(width) << " Job sub' interval " << job_sub_interval_ << "s\n";
+ os << left << setw(width) << " ECF_HOME " << ECF_HOME_ << "\n";
+ os << left << setw(width) << " ECF_LOG " << ECF_LOG_ << "\n";
+ os << left << setw(width) << " ECF_CHECK " << ECF_CHECK_ << "\n";
+ os << left << setw(width) << " Check pt interval " << checkpt_interval_ << "s\n";
+ os << left << setw(width) << " Check pt mode " << show_checkpt_mode(checkpt_mode_) << "\n";
+ os << left << setw(width) << " Check pt save time alarm " << checkpt_save_time_alarm_ << "s\n";
+ os << left << setw(width) << " Number of Suites " << no_of_suites_ << "\n";
+ os << left << setw(width) << " Request's per 1,5,15,30,60 min " << request_stats_ << "\n";
+
+ if (checkpt_ || restore_defs_from_checkpt_ || server_version_ || restart_server_ || shutdown_server_ || halt_server_ ||
+ ping_ || debug_server_on_ || debug_server_off_ || get_defs_ || sync_ || news_) os << "\n";
+ if (!locked_by_user_.empty()) os << left << setw(width) << " Locked by user " << locked_by_user_ << "\n";
+ if (checkpt_ != 0) os << left << setw(width) << " Check points " << checkpt_ << "\n";
+ if (restore_defs_from_checkpt_ != 0) os << left << setw(width) << " Restore from Check point " << restore_defs_from_checkpt_ << "\n";
+ if (restart_server_ != 0) os << left << setw(width) << " Restart server " << restart_server_ << "\n";
+ if (shutdown_server_ != 0) os << left << setw(width) << " Shutdown server " << shutdown_server_ << "\n";
+ if (halt_server_ != 0) os << left << setw(width) << " Halt server " << halt_server_ << "\n";
+ if (ping_ != 0) os << left << setw(width) << " Ping " << ping_ << "\n";
+ if (debug_server_on_ != 0) os << left << setw(width) << " debug server on " << debug_server_on_ << "\n";
+ if (debug_server_off_ != 0) os << left << setw(width) << " debug server off " << debug_server_off_ << "\n";
+ if (get_defs_ != 0) os << left << setw(width) << " Get full definition " << get_defs_ << "\n";
+ if (server_version_ != 0) os << left << setw(width) << " Server version " << server_version_ << "\n";
+ if (sync_ != 0) os << left << setw(width) << " Sync " << sync_ << "\n";
+ if (news_ != 0) os << left << setw(width) << " News " << news_ << "\n";
+
+ if (task_init_ || task_complete_ || task_wait_ || task_abort_ || task_event_ || task_meter_ || task_label_) os << "\n";
+ if (task_init_ != 0) os << left << setw(width) << " Task init " << task_init_ << "\n";
+ if (task_complete_ != 0) os << left << setw(width) << " Task complete " << task_complete_ << "\n";
+ if (task_wait_ != 0) os << left << setw(width) << " Task wait " << task_wait_ << "\n";
+ if (task_abort_ != 0) os << left << setw(width) << " Task abort " << task_abort_ << "\n";
+ if (task_event_ != 0) os << left << setw(width) << " Task event " << task_event_ << "\n";
+ if (task_meter_ != 0) os << left << setw(width) << " Task meter " << task_meter_ << "\n";
+ if (task_label_ != 0) os << left << setw(width) << " Task label " << task_label_ << "\n";
+
+ if (zombie_fob_ || zombie_fail_ || zombie_adopt_ || zombie_remove_ || zombie_get_ || zombie_block_ || zombie_kill_) os << "\n";
+ if (zombie_fob_ != 0) os << left << setw(width) << " Zombie fob " << zombie_fob_ << "\n";
+ if (zombie_fail_ != 0) os << left << setw(width) << " Zombie fail " << zombie_fail_ << "\n";
+ if (zombie_adopt_ != 0) os << left << setw(width) << " Zombie adopt " << zombie_adopt_ << "\n";
+ if (zombie_remove_ != 0) os << left << setw(width) << " Zombie remove " << zombie_remove_ << "\n";
+ if (zombie_get_ != 0) os << left << setw(width) << " Zombie get " << zombie_get_ << "\n";
+ if (zombie_block_ != 0) os << left << setw(width) << " Zombie block " << zombie_block_ << "\n";
+ if (zombie_kill_ != 0) os << left << setw(width) << " Zombie kill " << zombie_kill_ << "\n";
+
+ if (load_defs_ || begin_cmd_ || requeue_node_ || node_job_gen_ || node_check_job_gen_only_ || node_delete_ || node_suspend_ ||
+ node_resume_ || node_kill_ || node_status_ || node_edit_history_ || log_cmd_ || log_msg_cmd_ || order_node_ || run_node_ || replace_ ||
+ force_ || free_dep_ || suites_ || edit_script_ || alter_cmd_ || ch_cmd_ || plug_ || move_ || group_cmd_ ||
+ reload_white_list_file_ || server_load_cmd_ || stats_ || check_
+ ) os << "\n";
+ if (load_defs_ != 0) os << left << setw(width) << " Load definition " << load_defs_ << "\n";
+ if (begin_cmd_ != 0) os << left << setw(width) << " Begin " << begin_cmd_ << "\n";
+ if (requeue_node_ != 0) os << left << setw(width) << " Requeue " << requeue_node_ << "\n";
+ if (node_job_gen_ != 0) os << left << setw(width) << " Job generation " << node_job_gen_ << "\n";
+ if (node_check_job_gen_only_ != 0) os << left << setw(width) << " Check Job generation " << node_check_job_gen_only_ << "\n";
+ if (node_delete_ != 0) os << left << setw(width) << " Node delete " << node_delete_ << "\n";
+ if (node_suspend_ != 0) os << left << setw(width) << " Node suspend " << node_suspend_ << "\n";
+ if (node_resume_ != 0) os << left << setw(width) << " Node resume " << node_resume_ << "\n";
+ if (node_kill_ != 0) os << left << setw(width) << " Node kill " << node_kill_ << "\n";
+ if (node_status_ != 0) os << left << setw(width) << " Node status " << node_status_ << "\n";
+ if (node_edit_history_ != 0) os << left << setw(width) << " Node edit history " << node_edit_history_ << "\n";
+ if (log_cmd_ != 0) os << left << setw(width) << " Log cmd " << log_cmd_ << "\n";
+ if (log_msg_cmd_ != 0) os << left << setw(width) << " Log message " << log_msg_cmd_ << "\n";
+ if (order_node_ != 0) os << left << setw(width) << " Order " << order_node_ << "\n";
+ if (run_node_ != 0) os << left << setw(width) << " Run " << run_node_ << "\n";
+ if (replace_ != 0) os << left << setw(width) << " Replace " << replace_ << "\n";
+ if (force_ != 0) os << left << setw(width) << " Force " << force_ << "\n";
+ if (free_dep_ != 0) os << left << setw(width) << " Free dependencies " << free_dep_ << "\n";
+ if (suites_ != 0) os << left << setw(width) << " Suites " << suites_ << "\n";
+ if (edit_script_ != 0) os << left << setw(width) << " Edit script " << edit_script_ << "\n";
+ if (alter_cmd_ != 0) os << left << setw(width) << " Alter " << alter_cmd_ << "\n";
+ if (ch_cmd_ != 0) os << left << setw(width) << " Client handle " << ch_cmd_ << "\n";
+ if (plug_ != 0) os << left << setw(width) << " Plug " << plug_ << "\n";
+ if (move_ != 0) os << left << setw(width) << " Move " << move_ << "\n";
+ if (group_cmd_ != 0) os << left << setw(width) << " Group " << group_cmd_ << "\n";
+ if (server_load_cmd_ != 0) os << left << setw(width) << " Server load cmd " << server_load_cmd_ << "\n";
+ if (stats_ != 0) os << left << setw(width) << " stats cmd " << stats_ << "\n";
+ if (check_ != 0) os << left << setw(width) << " checks " << check_ << "\n";
+ if (reload_white_list_file_ != 0) os << left << setw(width) << " Reload white list file " << reload_white_list_file_ << "\n";
+
+ if (file_ecf_ || file_job_ || file_jobout_ || file_manual_ || file_cmdout_) os << "\n";
+ if (file_ecf_ != 0) os << left << setw(width) << " File ECF " << file_ecf_ << "\n";
+ if (file_job_ != 0) os << left << setw(width) << " File job " << file_job_ << "\n";
+ if (file_jobout_ != 0) os << left << setw(width) << " File Job out " << file_jobout_ << "\n";
+ if (file_cmdout_ != 0) os << left << setw(width) << " File Cmd out " << file_cmdout_ << "\n";
+ if (file_manual_ != 0) os << left << setw(width) << " File manual " << file_manual_ << "\n";
+ os << flush;
+}
diff --git a/Base/src/Stats.hpp b/Base/src/Stats.hpp
new file mode 100644
index 0000000..f9187e1
--- /dev/null
+++ b/Base/src/Stats.hpp
@@ -0,0 +1,216 @@
+#ifndef STATS_HPP_
+#define STATS_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #31 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <boost/serialization/serialization.hpp>
+#include <deque>
+#include <iostream>
+#include <sstream>
+#include "CheckPt.hpp"
+
+/// This class is used to store all statistical data about all the
+/// commands processed by the server. Uses default copy constructor
+struct Stats {
+
+ Stats();
+ void show(std::ostream& os = std::cout) const;
+
+ void update() { request_count_++; }
+ void update_stats(int poll_interval);
+ void update_for_serialisation();
+ void reset();
+
+ int status_; // 0 HALTED, 1 SHUTDOWN, 2 RUNNING
+ std::string locked_by_user_;
+ std::string host_;
+ std::string port_;
+ std::string up_since_;
+ std::string version_;
+ std::string request_stats_;
+ std::string ECF_HOME_;
+ std::string ECF_CHECK_;
+ std::string ECF_LOG_;
+
+ int request_count_;
+ int job_sub_interval_;
+ int checkpt_interval_;
+ int checkpt_save_time_alarm_;
+ ecf::CheckPt::Mode checkpt_mode_;
+ int no_of_suites_;
+
+ unsigned int checkpt_;
+ unsigned int restore_defs_from_checkpt_;
+
+ unsigned int server_version_;
+ unsigned int restart_server_;
+ unsigned int shutdown_server_;
+ unsigned int halt_server_;
+ unsigned int reload_white_list_file_;
+ unsigned int ping_;
+ unsigned int debug_server_on_;
+ unsigned int debug_server_off_;
+ unsigned int get_defs_;
+ unsigned int sync_;
+ unsigned int news_;
+
+ unsigned int node_job_gen_;
+ unsigned int node_check_job_gen_only_;
+ unsigned int node_delete_;
+ unsigned int node_suspend_;
+ unsigned int node_resume_;
+ unsigned int node_kill_;
+ unsigned int node_status_;
+ unsigned int node_edit_history_;
+
+ unsigned int log_cmd_;
+ unsigned int log_msg_cmd_;
+ unsigned int begin_cmd_;
+
+ unsigned int task_init_;
+ unsigned int task_complete_;
+ unsigned int task_wait_;
+ unsigned int task_abort_;
+ unsigned int task_event_;
+ unsigned int task_meter_;
+ unsigned int task_label_;
+
+ unsigned int zombie_fob_;
+ unsigned int zombie_fail_;
+ unsigned int zombie_adopt_;
+ unsigned int zombie_remove_;
+ unsigned int zombie_get_;
+ unsigned int zombie_block_;
+ unsigned int zombie_kill_;
+
+ unsigned int requeue_node_;
+ unsigned int order_node_;
+ unsigned int run_node_;
+ unsigned int load_defs_;
+ unsigned int replace_;
+ unsigned int force_;
+ unsigned int free_dep_;
+ unsigned int suites_;
+ unsigned int edit_script_;
+
+ unsigned int alter_cmd_;
+ unsigned int ch_cmd_;
+ unsigned int file_ecf_;
+ unsigned int file_job_;
+ unsigned int file_jobout_;
+ unsigned int file_cmdout_;
+ unsigned int file_manual_;
+
+ unsigned int plug_;
+ unsigned int move_;
+ unsigned int group_cmd_;
+ unsigned int server_load_cmd_;
+ unsigned int stats_;
+ unsigned int check_;
+
+private:
+
+ std::deque< std::pair<int,int> > request_vec_; // pair.first = number of requests, pair.second = poll interval
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+
+ ar & status_;
+ ar & locked_by_user_;
+ ar & host_;
+ ar & port_;
+ ar & up_since_;
+ ar & version_;
+ ar & job_sub_interval_;
+ ar & checkpt_interval_;
+ ar & checkpt_save_time_alarm_;
+ ar & checkpt_mode_;
+ ar & no_of_suites_;
+ ar & request_stats_;
+ ar & ECF_HOME_;
+ ar & ECF_CHECK_;
+ ar & ECF_LOG_;
+
+ ar & checkpt_;
+
+ ar & server_version_;
+ ar & restart_server_;
+ ar & shutdown_server_;
+ ar & halt_server_;
+ ar & reload_white_list_file_;
+ ar & ping_;
+ ar & debug_server_on_;
+ ar & debug_server_off_;
+
+ ar & get_defs_;
+ ar & sync_;
+ ar & news_;
+
+ ar & node_job_gen_;
+ ar & node_check_job_gen_only_;
+ ar & node_delete_;
+ ar & node_suspend_;
+ ar & node_resume_;
+ ar & node_kill_;
+ ar & node_status_;
+ ar & node_edit_history_;
+
+ ar & log_cmd_;
+ ar & log_msg_cmd_;
+ ar & begin_cmd_;
+
+ ar & task_init_;
+ ar & task_complete_;
+ ar & task_wait_;
+ ar & task_abort_;
+ ar & task_event_;
+ ar & task_meter_;
+ ar & task_label_;
+
+ ar & zombie_fob_;
+ ar & zombie_fail_;
+ ar & zombie_adopt_;
+ ar & zombie_remove_;
+ ar & zombie_get_;
+ ar & zombie_block_;
+ ar & zombie_kill_;
+
+ ar & requeue_node_;
+ ar & order_node_;
+ ar & run_node_;
+ ar & load_defs_;
+ ar & replace_;
+ ar & force_;
+ ar & free_dep_;
+ ar & suites_;
+ ar & edit_script_;
+
+ ar & alter_cmd_;
+ ar & ch_cmd_;
+ ar & file_ecf_;
+ ar & file_job_;
+ ar & file_jobout_;
+ ar & file_cmdout_;
+ ar & file_manual_;
+
+ ar & plug_;
+ ar & move_;
+ ar & group_cmd_;
+ ar & server_load_cmd_;
+ ar & stats_;
+ ar & check_;
+ }
+};
+#endif
diff --git a/Base/src/WhyCmd.cpp b/Base/src/WhyCmd.cpp
new file mode 100644
index 0000000..547f7f4
--- /dev/null
+++ b/Base/src/WhyCmd.cpp
@@ -0,0 +1,58 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Client side command only.
+// Placed in this category, since the server does not need to link
+// with it.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/foreach.hpp>
+#include "WhyCmd.hpp"
+#include "Defs.hpp"
+#include "Node.hpp"
+
+WhyCmd::WhyCmd(defs_ptr defs, const std::string& absNodePath)
+: defs_(defs)
+{
+ if (!defs_.get()) {
+ throw std::runtime_error("WhyCmd: The definition parameter is empty");
+ }
+
+ if (! absNodePath.empty() ) {
+ node_ = defs_->findAbsNode(absNodePath);
+ if ( ! node_.get() ) {
+ std::string errorMsg = "WhyCmd: The node path parameter '";
+ errorMsg += absNodePath;
+ errorMsg += "' can not be found.";
+ throw std::runtime_error(errorMsg);
+ }
+ }
+}
+
+std::string WhyCmd::why() const
+{
+ std::vector<std::string> theReasonWhy;
+ if (node_.get()) {
+ node_->bottom_up_why(theReasonWhy);
+ }
+ else {
+ defs_->top_down_why(theReasonWhy);
+ }
+
+ // Don't add /n on very last item
+ std::string reason;
+ for(size_t i = 0; i < theReasonWhy.size(); ++i) {
+ reason += theReasonWhy[i];
+ if (i != theReasonWhy.size()-1) reason += "\n";
+ }
+ return reason;
+}
+
diff --git a/Base/src/WhyCmd.hpp b/Base/src/WhyCmd.hpp
new file mode 100644
index 0000000..d85e214
--- /dev/null
+++ b/Base/src/WhyCmd.hpp
@@ -0,0 +1,37 @@
+#ifndef WHY_CMD_HPP_
+#define WHY_CMD_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Client side command only.
+// Placed in this category, since the server does not need to link
+// with it.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <string>
+#include <boost/noncopyable.hpp>
+#include "NodeFwd.hpp"
+
+class WhyCmd : private boost::noncopyable {
+public:
+ WhyCmd(defs_ptr defs, const std::string& absNodePath);
+
+ /// Why the node is not running
+ /// Return a '/n' separated string which lists the reasons why
+ /// the provided node is not active.
+ std::string why() const;
+
+private:
+ defs_ptr defs_;
+ node_ptr node_;
+};
+
+#endif
diff --git a/Base/src/ZombieCtrl.cpp b/Base/src/ZombieCtrl.cpp
new file mode 100644
index 0000000..18361d3
--- /dev/null
+++ b/Base/src/ZombieCtrl.cpp
@@ -0,0 +1,772 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #41 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : manages the zombies
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include "ZombieCtrl.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Submittable.hpp"
+#include "ClientToServerCmd.hpp"
+#include "AbstractServer.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost::posix_time;
+
+//#define DEBUG_ZOMBIE 1
+
+/// Zombie creation:
+/// *** ECF *** Zombies is created with: process(node path, password, pid/rid , try_no) ***
+/// *** PATH *** Zombies is created with: process(node path, password, pid/rid , try_no) ***
+/// *** USER *** Zombies is created with: TASK(node path, password, pid/rid , try_no) ***
+///
+/// There are several places where we hold path,password,pid/rid,etc
+/// Task Cmd/
+/// Node Tree Process(n) USER Zombie PATH/ECF Zombie
+/// Path same as node tree same as process
+/// password same as node tree same as process
+/// pid/rid same as node tree same as process
+/// try no same as node tree same as process
+/// ^ |
+/// | ----adopt-----------
+///
+/// Zombie Finding:
+/// For a given Task, we could have multiple zombie process, i.e. with different password/process id
+/// We can't assume that there is only one zombie process. Hence search/zombie matching
+/// should involve matching with password/process id first and then resort to path matching
+///
+/// Note: Only the init child command is required pass the process id. The other child command may
+// or may *not* provide this. In the test scenario we do.
+static bool match(const Zombie& z, const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password);
+
+
+bool ZombieCtrl::handle_path_zombie(
+ AbstractServer* as,
+ const TaskCmd* task_cmd, // The child command
+ std::string& action_taken,
+ STC_Cmd_ptr& theReply // Reply varies according to User Action
+)
+{
+#ifdef DEBUG_ZOMBIE
+ std::cout << " ZombieCtrl::handle_path_zombie:";
+#endif
+ const std::string& path_to_task = task_cmd->path_to_node();
+ const std::string& jobs_password = task_cmd->jobs_password();
+ const std::string& process_or_remote_id = task_cmd->process_or_remote_id();
+
+
+ /// *** The ZombieAttr may have added/ deleted via AlterCmd. This allows for dynamic changes
+ /// *no* task, find the closest Zombie attribute up the Node tree, ie attribute could be on family/suite even though task has been deleted
+ /// If none found we resort to default behaviour
+ node_ptr closest_matching_node = as->defs()->find_closest_matching_node(path_to_task);
+#ifdef DEBUG_ZOMBIE
+ if (closest_matching_node.get()) std::cout << " closest node found: ";
+#endif
+
+
+#ifdef DEBUG_ZOMBIE
+ std::cout << " Searching for match over " << zombies_.size() << " zombies :";
+#endif
+ Zombie& theExistingZombie = find_zombie(path_to_task, process_or_remote_id, jobs_password );
+ if(!theExistingZombie.empty() ) {
+ // When NULL is passed for task, we change existing zombie to be of type PATH
+ return handle_existing_zombie(theExistingZombie,NULL/*task*/,closest_matching_node,task_cmd,action_taken,theReply);
+ }
+
+ /// Create a zombie,
+ /// *** PATH *** Zombies is created with: process path, process password, and process id/rid , process try_no ***
+#ifdef DEBUG_ZOMBIE
+ std::cout << " No matching zombie fnd: Creating Path Zombie: ";
+#endif
+
+ ZombieAttr attr = ZombieAttr::get_default_attr(Child::PATH);
+ if (closest_matching_node.get()) {
+ closest_matching_node->findParentZombie(Child::PATH, attr ); // Override default from node tree
+ }
+
+ Zombie new_zombie(Child::PATH,task_cmd->child_type(),attr,path_to_task,jobs_password,process_or_remote_id,task_cmd->try_no());
+ zombies_.push_back( new_zombie );
+
+ /// The user action may end deleting the zombie just added. Depends on ZombieAttribute settings
+ return handle_user_actions(new_zombie,NULL /*task*/,task_cmd,action_taken,theReply);
+}
+
+
+bool ZombieCtrl::handle_zombie(
+ Submittable* task, // This NULL for path zombies
+ const TaskCmd* task_cmd, // The child command
+ std::string& action_taken,
+ STC_Cmd_ptr& theReply // Reply varies according to User Action
+)
+{
+#ifdef DEBUG_ZOMBIE
+ std::cout << " ZombieCtrl::handle_zombie:";
+#endif
+ const std::string& path_to_task = task_cmd->path_to_node();
+ const std::string& jobs_password = task_cmd->jobs_password();
+ const std::string& process_or_remote_id = task_cmd->process_or_remote_id();
+
+ Zombie& theExistingZombie = find_zombie(path_to_task, process_or_remote_id, jobs_password );
+ if(!theExistingZombie.empty() ) {
+ return handle_existing_zombie(theExistingZombie,task,node_ptr(),task_cmd,action_taken,theReply);
+ }
+
+ /// Create Zombie:
+ /// *** ECF *** Zombies is created with: process path, process password, and process id/rid , process try_no ***
+ Child::ZombieType zombie_type = Child::ECF;
+ ZombieAttr attr = ZombieAttr::get_default_attr( zombie_type );
+
+ /// Look for any Zombie attribute up node tree, use this to construct & configure zombie
+ task->findParentZombie(zombie_type, attr );
+
+ /// Handle corner case ,where we have two jobs with different process id, but same password
+ /// Can happen if jobs is started externally, or via test, occasionally
+ ecf::Child::CmdType child_type = task_cmd->child_type();
+ if (child_type == Child::INIT && task->state() == NState::ACTIVE) {
+
+ /// Find zombie by path only, and remove it. Re-added again below. With updated, data<<<<
+#ifdef DEBUG_ZOMBIE
+ cout << " >TASK already active:< ";
+#endif
+ size_t zombieVecSize = zombies_.size();
+ for(size_t i = 0 ; i < zombieVecSize; i++) {
+ if (zombies_[i].path_to_task() == path_to_task) {
+ zombie_type = zombies_[i].type(); // recover the original zombie type
+ zombies_.erase( zombies_.begin() + i);
+#ifdef DEBUG_ZOMBIE
+ cout << " Removing: ";
+#endif
+ break;
+ }
+ }
+ }
+
+
+#ifdef DEBUG_ZOMBIE
+ std::cout << " Creating ECF Zombie:";
+#endif
+ Zombie new_zombie(zombie_type,child_type,attr,path_to_task,jobs_password,process_or_remote_id,task_cmd->try_no());
+ zombies_.push_back( new_zombie );
+
+ /// Mark task as zombie for xcdp
+ task->flag().set(ecf::Flag::ZOMBIE);
+
+ return handle_user_actions(new_zombie,task,task_cmd,action_taken,theReply);
+}
+
+bool ZombieCtrl::handle_existing_zombie(
+ Zombie& theExistingZombie, // The server already knows about the zombie
+ Submittable* task, // This NULL for path zombies
+ node_ptr closest_matching_node, // only defined for path zombies
+ const TaskCmd* task_cmd, // The child command
+ std::string& action_taken, // User action taken
+ STC_Cmd_ptr& theReply // Reply varies according to User Action
+)
+{
+#ifdef DEBUG_ZOMBIE
+ std::cout << " handle_existing_zombie: Updating child_type: ";
+#endif
+ // If we have no task, then change the zombie type to PATH
+ if (!task) {
+#ifdef DEBUG_ZOMBIE
+ std::cout << " : updating zombie type to PATH: ";
+#endif
+ theExistingZombie.set_type( ecf::Child::PATH );
+ }
+
+ /// *** The ZombieAttr may have added/ deleted via AlterCmd. This allows for dynamic changes
+ ZombieAttr attr = ZombieAttr::get_default_attr(theExistingZombie.type());
+ if (closest_matching_node.get()) {
+#ifdef DEBUG_ZOMBIE
+ cout << " Attr found for path zombie(" << attr.toString() << "): ";
+#endif
+ closest_matching_node->findParentZombie(theExistingZombie.type(), attr ); // Override default from node tree
+ }
+
+ if (task && task->findParentZombie(theExistingZombie.type(), attr )) { // Override default from node tree
+#ifdef DEBUG_ZOMBIE
+ cout << " Attr found(" << attr.toString() << "): ";
+#endif
+ }
+ theExistingZombie.set_attr( attr ); // Update attribute stored on the zombie
+ theExistingZombie.set_last_child_cmd( task_cmd->child_type() );// The zombie stores the last child command.
+ theExistingZombie.increment_calls(); // record how times server handled with zombie
+
+
+ /// Update the process id, if it is empty on the existing zombie
+ /// *** NOTE**** can not update process id from task, as that could be an ID from a different JOB,
+ /// ************ Hence zombie matching resorts to path and password matching
+ const std::string& process_or_remote_id = task_cmd->process_or_remote_id();
+ if (theExistingZombie.process_or_remote_id().empty() && !process_or_remote_id.empty()) {
+#ifdef DEBUG_ZOMBIE
+ std::cout << "Updating process id(" << process_or_remote_id << "): ";
+#endif
+ theExistingZombie.set_process_or_remote_id( process_or_remote_id );
+ }
+
+ return handle_user_actions(theExistingZombie,task,task_cmd,action_taken,theReply);
+}
+
+bool ZombieCtrl::handle_user_actions(
+ Zombie& theZombie, // Existing or one we just created
+ Submittable* task, // This is NULL for path zombies
+ const TaskCmd* task_cmd, // The child command
+ std::string& action_taken,// User action taken
+ STC_Cmd_ptr& theReply // Reply varies according to User Action
+)
+{
+ const std::string& path_to_task = task_cmd->path_to_node();
+ const std::string& process_password = task_cmd->jobs_password();
+ const std::string& process_or_remote_id = task_cmd->process_or_remote_id();
+
+ if (theZombie.manual_user_action()) action_taken = "manual-";
+ else action_taken = "automatic-";
+
+ // *ADOPT* If zombie is set to adopt, copy over password and carry on as >NORMAL< , i.e. we return true
+ if ( task && theZombie.adopt()) {
+
+ action_taken += "adopt";
+ /// Zombie was marked to adopt. password copied over, and zombie removed
+ /// *MUST* use the password of the process, and *NOT* the zombie
+ /// Since next time process communicates, it will be *WITH* the process password
+ task->set_jobs_password( process_password );
+ task->set_process_or_remote_id( process_or_remote_id );
+
+ /// Remove the zombie, as its been adopted
+ /// matching by password/process id may fail, hence remove by path
+ bool remove_ok = remove(path_to_task, process_or_remote_id, process_password );
+ if (!remove_ok) {
+ (void) remove_by_path(path_to_task);
+ }
+
+ /// Clear the zombie flag
+ task->flag().clear(ecf::Flag::ZOMBIE);
+
+#ifdef DEBUG_ZOMBIE
+ std::cout << " >>>ADOPT<<< then remove(" << remove_ok <<") ";
+ if (!remove_ok) std::cout << " >>>ERROR<<<< Remove failed ";
+ std::cout << " zombies_.size(" << zombies_.size() << ")\n";
+#endif
+ return true;
+ }
+
+ // *FOB*
+ if (theZombie.fob()) {
+ /// Means return as if everything is OK. hence ClientInvoker will *NOT* block, and job can continue.
+ action_taken += "fob";
+
+ /// On the child COMPLETE/ABORT cmd, remove the zombie:
+ /// *****************************************************************************************
+ /// Since we are returning false, The Task Cmd complete/abort **wont** be able to remove the zombie
+ /// i.e since we want job to continue, *WITHOUT* invoking the dohandeRequest
+ /// *****************************************************************************************
+ if (task_cmd->child_type() == Child::COMPLETE || task_cmd->child_type() == Child::ABORT ) {
+
+ bool remove_ok = remove(path_to_task, process_or_remote_id, process_password );
+ if (!remove_ok) {
+ (void)remove_by_path(path_to_task);
+ }
+
+ /// Clear the zombie flag
+ if (task) task->flag().clear(ecf::Flag::ZOMBIE);
+
+#ifdef DEBUG_ZOMBIE
+ std::cout << " child == COMPLETE remove zombie ";
+ if (!remove_ok) std::cout << " >>>ERROR<<<< Remove failed ";
+#endif
+ }
+
+#ifdef DEBUG_ZOMBIE
+ std::cout << " >>>FOB<<< zombies_.size(" << zombies_.size() << ")\n";
+#endif
+ theReply = PreAllocatedReply::ok_cmd();
+ return false;
+ }
+
+ // *FAIL* Ask ClientInvoker *NOT* to block, *fail* with an error.
+ if (theZombie.fail()) {
+#ifdef DEBUG_ZOMBIE
+ std::cout << " >>>FAIL<<< zombies_.size(" << zombies_.size() << ")\n";
+#endif
+ action_taken += "fail";
+ theReply = PreAllocatedReply::error_cmd("[ authentication failed ] Request set to FAIL via zombie setting");
+ return false;
+ }
+
+ // *KILL* Typically kill is immediate(i.e. via ZombieCmd), However this could have been set via ZombieAttribute
+ if (theZombie.kill()) {
+ // when a task a script is killed(i,e with kill -15), it will typically be trapped
+ // This will then typically call abort. We have a choice:
+ // a/ If we remove the zombie, the action taken will be lost, when the abort arises, hence default action is block
+ // b/ Change the action type to be fob, so that the abort does not block
+ // c/ Continue killing until process terminate. Up to use to remove zombies
+ // Opted for option b/ however we do *NOT* change action type, we just fob
+ if (task) {
+ if (!task->flag().is_set(ecf::Flag::KILLED)) {
+
+ action_taken += "kill & fob";
+
+ // Kill the task, separate process, will typically send kill -15 to script.
+ task->kill(theZombie.process_or_remote_id());
+ }
+ else {
+ action_taken += "kill(already killed, fobing instead)";
+ }
+ }
+ else {
+ action_taken += "kill(no task, fobing instead)";
+ }
+#ifdef DEBUG_ZOMBIE
+ std::cout << " >>>KILL<<< zombies_.size(" << zombies_.size() << ")\n";
+#endif
+ theReply = PreAllocatedReply::ok_cmd(); // do not block the script, fob
+ return false;
+ }
+
+ // *REMOVE* Typically Removal is immediate(i.e. via ZombieCmd), However this could have been set via ZombieAttribute
+ if (theZombie.remove()) {
+ /// Ask ClientInvoker to continue blocking, Zombie may re-appear
+ action_taken += "remove";
+ bool remove_ok = remove(path_to_task, process_or_remote_id, process_password);
+ if (!remove_ok) (void)remove_by_path(path_to_task);
+
+#ifdef DEBUG_ZOMBIE
+ std::cout << " >>>REMOVE<<< zombies_.size(" << zombies_.size() << ") : BLOCKING ";
+ if (!remove_ok) std::cout << " >>>ERROR<<<< Remove failed ";
+#endif
+ theReply = PreAllocatedReply::block_client_zombie_cmd();
+ return false;
+ }
+
+ // *DEFAULT*:
+ // Label,event,meter : fob
+ // init,complete,abort,wait: block
+ if (task_cmd->child_type() == Child::LABEL ||
+ task_cmd->child_type() == Child::EVENT ||
+ task_cmd->child_type() == Child::METER) {
+
+ /// Means return as if everything is OK. hence ClientInvoker will *NOT* block, and job can continue.
+#ifdef DEBUG_ZOMBIE
+ std::cout << ": FOB\n";
+#endif
+ action_taken += "fob";
+ theReply = PreAllocatedReply::ok_cmd();
+ return false;
+ }
+
+#ifdef DEBUG_ZOMBIE
+ std::cout << ": BLOCKING\n";
+#endif
+ // i.e it will make several attempts , and then start contacting servers in the hosts file.
+ action_taken += "block";
+ theReply = PreAllocatedReply::block_client_zombie_cmd();
+ return false;
+}
+
+
+void ZombieCtrl::do_add_user_zombies(const std::vector<Submittable*>& tasks)
+{
+ size_t taskVecSize = tasks.size();
+ for(size_t i = 0; i < taskVecSize; i++) {
+ Submittable* t = tasks[i];
+ if (t->state() == NState::ACTIVE || t->state() == NState::SUBMITTED) {
+
+ Zombie& theExistingZombie = find( t );
+ if (theExistingZombie.empty() ) {
+
+#ifdef DEBUG_ZOMBIE
+ std::cout << " ZombieCtrl::do_add_user_zombies " << t->absNodePath() << " " << t->process_or_remote_id() << " " << t->jobsPassword() << "\n";
+#endif
+
+ ZombieAttr attr = ZombieAttr::get_default_attr(Child::USER); // get the default USER zombie attribute
+ t->findParentZombie(Child::USER, attr ); // Override default from the node tree
+
+ zombies_.push_back(Zombie(Child::USER,Child::INIT,attr,t->absNodePath(),t->jobsPassword(),t->process_or_remote_id(),t->try_no()));
+
+ /// Mark task as zombie for xcdp
+ t->flag().set(ecf::Flag::ZOMBIE);
+ }
+ }
+ }
+}
+
+void ZombieCtrl::add_user_zombies( node_ptr node)
+{
+ if (!node.get()) return;
+ std::vector<Submittable*> tasks;
+ node->get_all_active_submittables(tasks);
+ do_add_user_zombies(tasks);
+}
+
+void ZombieCtrl::add_user_zombies( suite_ptr suite)
+{
+ if (!suite.get()) return;
+ std::vector<Submittable*> tasks;
+ suite->get_all_active_submittables(tasks);
+ do_add_user_zombies(tasks);
+}
+
+void ZombieCtrl::add_user_zombies( defs_ptr defs)
+{
+ if (!defs.get()) return;
+ std::vector<Submittable*> tasks;
+ defs->get_all_active_submittables(tasks);
+ do_add_user_zombies(tasks);
+}
+
+/// Returns the list of zombies, **updated** with seconds since creation
+void ZombieCtrl::get( std::vector< Zombie >& ret) {
+
+ boost::posix_time::ptime time_now = Calendar::second_clock_time();
+
+ size_t zombieVecSize = zombies_.size(); ret.reserve(zombieVecSize);
+ for(size_t i = 0 ; i < zombieVecSize; i++) {
+
+ time_duration duration = time_now - zombies_[i].creation_time();
+ zombies_[i].set_duration( duration.total_seconds() );
+
+ ret.push_back(zombies_[i]);
+ }
+}
+
+void ZombieCtrl::remove_stale_zombies( const boost::posix_time::ptime& time_now )
+{
+ for(std::vector<Zombie>::iterator i = zombies_.begin(); i != zombies_.end(); ++i) {
+ time_duration duration = time_now - (*i).creation_time();
+ if ( duration.total_seconds() > (*i).allowed_age()) {
+#ifdef DEBUG_ZOMBIE
+ std::cout << " ZombieCtrl::remove_stale_zombies " << (*i) << "\n";
+#endif
+ zombies_.erase(i--);
+ }
+ }
+}
+
+void ZombieCtrl::fob( const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password) {
+
+ Zombie& theExistingZombie = find_zombie(path_to_task, process_or_remote_id, password );
+ if( theExistingZombie.empty() ) return;
+ theExistingZombie.set_fob();
+}
+
+void ZombieCtrl::fobCli( const std::string& path_to_task, Submittable* task) {
+
+ if (task) {
+ /// Try to determine the real zombie. (not 100% precise) by comparing its password with zombie
+ /// If zombie password does *NOT* match then this is the real zombie.
+ size_t zombieVecSize = zombies_.size();
+ for(size_t i = 0 ; i < zombieVecSize; i++) {
+ if (zombies_[i].path_to_task() == path_to_task && zombies_[i].jobs_password() != task->jobsPassword()) {
+ zombies_[i].set_fob();
+ return;
+ }
+ }
+ for(size_t i = 0 ; i < zombieVecSize; i++) {
+ if (zombies_[i].path_to_task() == path_to_task && zombies_[i].process_or_remote_id() != task->process_or_remote_id()) {
+ zombies_[i].set_fob();
+ return;
+ }
+ }
+ }
+
+ /// The best we can do
+ Zombie& theExistingZombie = find_by_path( path_to_task );
+ if ( theExistingZombie.empty() ) return;
+ theExistingZombie.set_fob();
+}
+
+void ZombieCtrl::fail(const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password) {
+
+ Zombie& theExistingZombie = find_zombie(path_to_task, process_or_remote_id, password );
+ if( theExistingZombie.empty() ) return;
+ theExistingZombie.set_fail();
+}
+
+void ZombieCtrl::failCli( const std::string& path_to_task, Submittable* task) {
+
+ if (task) {
+ /// Try to determine the real zombie. (not 100% precise) by comparing its password with zombie
+ /// If zombie password does *NOT* match then this is the real zombie.
+ size_t zombieVecSize = zombies_.size();
+ for(size_t i = 0 ; i < zombieVecSize; i++) {
+ if (zombies_[i].path_to_task() == path_to_task && zombies_[i].jobs_password() != task->jobsPassword()) {
+ zombies_[i].set_fail();
+ return;
+ }
+ }
+ for(size_t i = 0 ; i < zombieVecSize; i++) {
+ if (zombies_[i].path_to_task() == path_to_task && zombies_[i].process_or_remote_id() != task->process_or_remote_id()) {
+ zombies_[i].set_fail();
+ return;
+ }
+ }
+ }
+
+ /// The best we can do
+ Zombie& theExistingZombie = find_by_path( path_to_task );
+ if ( theExistingZombie.empty() ) return;
+ theExistingZombie.set_fail();
+}
+
+void ZombieCtrl::adopt( const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password ) {
+
+ Zombie& theExistingZombie = find_zombie(path_to_task, process_or_remote_id, password );
+ if ( theExistingZombie.empty() ) return;
+ theExistingZombie.set_adopt();
+}
+
+void ZombieCtrl::adoptCli( const std::string& path_to_task, Submittable* task) {
+
+ if (!task) {
+ throw std::runtime_error("ZombieCtrl::adoptCli: Can't adopt zombie, there is no corresponding task!");
+ }
+
+ /// Try to determine the real zombie. (not 100% precise) by comparing its password with zombie
+ /// If zombie password does *NOT* match then this is the real zombie.
+ size_t zombieVecSize = zombies_.size();
+ for(size_t i = 0 ; i < zombieVecSize; i++) {
+ if (zombies_[i].path_to_task() == path_to_task && zombies_[i].jobs_password() != task->jobsPassword()) {
+ zombies_[i].set_adopt();
+ return;
+ }
+ }
+
+ /// ***************************************************************************************
+ /// IMPORTANT: We should *NEVER* adopt a zombie, when the process id are different
+ /// This can end up, with two process running, Will mess up job output, as well as corruption caused
+ /// but running the same job twice. Better to kill both and re-queue.
+ /// Note: PBS can create two process, i.e same password, different PID's
+ /// ***************************************************************************************
+ for(size_t i = 0 ; i < zombieVecSize; i++) {
+ if (zombies_[i].path_to_task() == path_to_task && zombies_[i].process_or_remote_id() != task->process_or_remote_id()) {
+ std::stringstream ss;
+ ss << "ZombieCtrl::adoptCli: Can *not* adopt zombies, where process id are different. Task("
+ << task->process_or_remote_id() << ") zombie(" << zombies_[i].process_or_remote_id()
+ << "). Please kill both process, and re-queue";
+ throw std::runtime_error(ss.str());
+ }
+ }
+}
+
+void ZombieCtrl::block( const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password ) {
+
+ Zombie& theExistingZombie = find_zombie(path_to_task, process_or_remote_id, password );
+ if ( theExistingZombie.empty() ) return;
+ theExistingZombie.set_block();
+}
+
+void ZombieCtrl::blockCli( const std::string& path_to_task, Submittable* task) {
+
+ if (!task) {
+ throw std::runtime_error("ZombieCtrl::blockCli: Can't block zombie, there is no corresponding task for path " + path_to_task );
+ }
+ else {
+ /// Try to determine the real zombie. (not 100% precise) by comparing its password with zombie
+ /// If zombie password does *NOT* match then this is the real zombie.
+ size_t zombieVecSize = zombies_.size();
+ for(size_t i = 0 ; i < zombieVecSize; i++) {
+ if (zombies_[i].path_to_task() == path_to_task && zombies_[i].jobs_password() != task->jobsPassword()) {
+ zombies_[i].set_block();
+ return;
+ }
+ }
+ }
+}
+
+void ZombieCtrl::kill( const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password ) {
+
+ Zombie& theExistingZombie = find_zombie(path_to_task, process_or_remote_id, password );
+ if ( theExistingZombie.empty() ) return;
+ theExistingZombie.set_kill();
+}
+
+void ZombieCtrl::killCli( const std::string& path_to_task, Submittable* task) {
+
+ if (!task) {
+ throw std::runtime_error("ZombieCtrl::killCli: Can't kill zombie, there is no corresponding task for path " + path_to_task );
+ }
+
+ /// Try to determine the real zombie. (not 100% precise) by comparing its password with zombie
+ /// If zombie password does *NOT* match then this is the real zombie.
+ size_t zombieVecSize = zombies_.size();
+ for(size_t i = 0 ; i < zombieVecSize; i++) {
+ if (zombies_[i].path_to_task() == path_to_task && zombies_[i].jobs_password() != task->jobsPassword()) {
+ task->kill(zombies_[i].process_or_remote_id());
+ zombies_[i].set_kill();
+ return;
+ }
+ }
+ for(size_t i = 0 ; i < zombieVecSize; i++) {
+ if ( zombies_[i].path_to_task() == path_to_task && zombies_[i].process_or_remote_id() != task->process_or_remote_id()) {
+ task->kill(zombies_[i].process_or_remote_id());
+ zombies_[i].set_kill();
+ return ;
+ }
+ }
+ /// The best we can do
+ Zombie& theExistingZombie = find_by_path( path_to_task );
+ if ( theExistingZombie.empty() ) {
+ throw std::runtime_error("ZombieCtrl::killCli: Can't kill, could not locate zombie(and hence pid) for path: " + path_to_task );
+ }
+ task->kill(theExistingZombie.process_or_remote_id());
+ theExistingZombie.set_kill();
+ remove_by_path(path_to_task);
+}
+
+/// Called by the child commands, ie complete and abort
+/// Hence remove zombie with matching password/process id ?
+bool ZombieCtrl::remove( Submittable* t)
+{
+ if (t) {
+ return remove(t->absNodePath(), t->process_or_remote_id(), t->jobsPassword() );
+ }
+ return false;
+}
+
+bool ZombieCtrl::remove( const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password ) {
+
+ /// Note: Its possible for two separate jobs to have the same password. (submit 1, submit 2) before job1 active, password overridden by submit 2
+ /// Hence remove needs to at least match process_id
+ size_t zombieVecSize = zombies_.size();
+ for(size_t i = 0 ; i < zombieVecSize; i++) {
+ if (match(zombies_[i],path_to_task,process_or_remote_id,password)) {
+//#ifdef DEBUG_ZOMBIE
+// std::cout << " ZombieCtrl::remove " << zombies_[i] << " \n";
+//#endif
+ zombies_.erase( zombies_.begin() + i);
+ return true;
+ }
+ }
+ return false;
+}
+
+void ZombieCtrl::removeCli( const std::string& path_to_task, Submittable* task) {
+
+ if (task) {
+ /// Try to determine the real zombie. (not 100% precise) by comparing its password with zombie
+ /// If zombie password does *NOT* match then this is the real zombie.
+ size_t zombieVecSize = zombies_.size();
+ for(size_t i = 0 ; i < zombieVecSize; i++) {
+ if ( zombies_[i].path_to_task() == path_to_task && zombies_[i].jobs_password() != task->jobsPassword()) {
+#ifdef DEBUG_ZOMBIE
+ std::cout << " ZombieCtrl::removeCli " << zombies_[i] << " \n";
+#endif
+ zombies_.erase( zombies_.begin() + i);
+ return ;
+ }
+ }
+ for(size_t i = 0 ; i < zombieVecSize; i++) {
+ if ( zombies_[i].path_to_task() == path_to_task && zombies_[i].process_or_remote_id() != task->process_or_remote_id()) {
+#ifdef DEBUG_ZOMBIE
+ std::cout << " ZombieCtrl::removeCli " << zombies_[i] << " \n";
+#endif
+ zombies_.erase( zombies_.begin() + i);
+ return ;
+ }
+ }
+ }
+
+ /// The best we can do
+ (void)remove_by_path(path_to_task);
+}
+
+bool ZombieCtrl::remove_by_path(const std::string& path_to_task)
+{
+ size_t zombieVecSize = zombies_.size();
+ for(size_t i = 0 ; i < zombieVecSize; i++) {
+ if ( zombies_[i].path_to_task() == path_to_task) {
+#ifdef DEBUG_ZOMBIE
+ std::cout << " ZombieCtrl::remove_by_path : " << zombies_[i] << " \n";
+#endif
+ zombies_.erase( zombies_.begin() + i);
+ return true;
+ }
+ }
+ return false;
+}
+
+/// Query
+const Zombie& ZombieCtrl::find(const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password) const
+{
+ size_t zombieVecSize = zombies_.size();
+ for(size_t i = 0 ; i < zombieVecSize; i++) {
+ if (match(zombies_[i],path_to_task,process_or_remote_id,password)) {
+ return zombies_[i];
+ }
+ }
+ return Zombie::EMPTY();
+}
+
+//================= private ===================================================================
+
+Zombie& ZombieCtrl::find(Submittable* task)
+{
+ if (task) return find_zombie(task->absNodePath(),task->process_or_remote_id(),task->jobsPassword());
+ return Zombie::EMPTY_();
+}
+
+const Zombie& ZombieCtrl::find(Submittable* task) const
+{
+ if (task) return find(task->absNodePath(),task->process_or_remote_id(),task->jobsPassword());
+ return Zombie::EMPTY();
+}
+
+Zombie& ZombieCtrl::find_zombie(const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password)
+{
+ size_t zombieVecSize = zombies_.size();
+ for(size_t i = 0 ; i < zombieVecSize; i++) {
+ if (match(zombies_[i],path_to_task,process_or_remote_id,password)) {
+ return zombies_[i];
+ }
+ }
+ return find_by_path(path_to_task);
+}
+
+
+bool match(const Zombie& z, const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password)
+{
+ /// Process/remote id only created when task becomes active.
+ if (z.path_to_task() == path_to_task) {
+ if (process_or_remote_id.empty() || z.process_or_remote_id().empty()) {
+ if (z.jobs_password() == password) {
+ return true;
+ }
+ }
+ else if ( z.process_or_remote_id() == process_or_remote_id ) {
+ return true;
+ }
+ }
+ return false;
+}
+
+Zombie& ZombieCtrl::find_by_path(const std::string& path_to_task)
+{
+ size_t zombieVecSize = zombies_.size();
+ for(size_t i = 0 ; i < zombieVecSize; i++) {
+ if (zombies_[i].path_to_task() == path_to_task) {
+ return zombies_[i];
+ }
+ }
+ return Zombie::EMPTY_();
+}
+
+const Zombie& ZombieCtrl::find_by_path_only(const std::string& path_to_task) const
+{
+ size_t zombieVecSize = zombies_.size();
+ for(size_t i = 0 ; i < zombieVecSize; i++) {
+ if (zombies_[i].path_to_task() == path_to_task) {
+ return zombies_[i];
+ }
+ }
+ return Zombie::EMPTY();
+}
diff --git a/Base/src/ZombieCtrl.hpp b/Base/src/ZombieCtrl.hpp
new file mode 100644
index 0000000..dc0697c
--- /dev/null
+++ b/Base/src/ZombieCtrl.hpp
@@ -0,0 +1,143 @@
+#ifndef ZOMBIE_CTRL_HPP_
+#define ZOMBIE_CTRL_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #23 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : manages the zombies
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <string>
+#include <vector>
+#include <boost/noncopyable.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include "Zombie.hpp"
+#include "NodeFwd.hpp"
+#include "Cmd.hpp"
+class TaskCmd;
+class AbstractServer;
+
+/// All zombies are auto deleted after a period of time. See Zombie::allowed_age()
+class ZombieCtrl : private boost::noncopyable {
+public:
+ ZombieCtrl() {}
+
+ /// Handle the zombie, and return back to the client
+ bool handle_zombie(
+ Submittable*, // Must be NON NULL
+ const TaskCmd* task_cmd, // The child command
+ std::string& action_taken,// action taken
+ STC_Cmd_ptr& theReply // Reply varies according to User Action
+ );
+
+ bool handle_path_zombie(
+ AbstractServer* as, // Find closest matching node
+ const TaskCmd* task_cmd, // The child command
+ std::string& action_taken,// action taken
+ STC_Cmd_ptr& theReply // Reply varies according to User Action
+ );
+
+
+ /// Find all *Tasks* beneath the input Node, that are in active or submitted states
+ /// We deliberately ignore aliases (This was requested by Axel)
+ /// Then add as 'USER' zombies. This should be called when commands like, delete, requeue,
+ /// run, are using the force option, and will create zombies.
+ void add_user_zombies(node_ptr);
+ void add_user_zombies(suite_ptr);
+ void add_user_zombies(defs_ptr);
+
+ /// Returns the list of zombies, **updated** with seconds since creation
+ /// To avoid sending attr to client, we copy over its setting, if in effect
+ void get(std::vector<Zombie>&) ;
+
+
+ /// remove all zombies, older than their allowed age
+ /// Server typically checks every 60 seconds
+ void remove_stale_zombies(const boost::posix_time::ptime& time_now);
+
+
+ /// Will ask the child command to terminate, *without* the child command raising any errors
+ /// Since we can have many child commands(init,event,meter, label,complete) in a job
+ /// This fob must stay around, since we don't know how long the job will last for.
+ /// Will override, fail,recover,remove
+ /// For Command Line Interface only the task_path is provided. Just have to make do.
+ void fob(const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password);
+ void fobCli(const std::string& path_to_task, Submittable*);
+
+
+ /// Similar to a fob, But will ask the child command to terminate, with an error.
+ /// Typically this will raise a trap in the job file, and hence raise an abort
+ /// However the abort will also be a zombie, and will also be auto-terminated
+ /// Hence the job file must be careful to use 'set -e' to avoid infinite recursion
+ /// Since we can have many child commands(init,event,meter, label,complete) in a job
+ /// This fob must stay around, since we don't know how long the job will last for.
+ /// Will override, fob,recover,remove
+ /// For Command Line Interface only the task_path is provided. Just have to make do.
+ void fail( const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password);
+ void failCli(const std::string& path_to_task, Submittable*);
+
+
+ /// Find the task node, corresponding to the zombie, and copy over
+ /// the password. Then remove the zombie. Next time the child commands
+ /// communicate with the server, all will be ok
+ /// Will override, fail,fob,remove
+ /// For Command Line Interface only the task_path is provided. Just have to make do.
+ void adopt(const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password);
+ void adoptCli(const std::string& path_to_task, Submittable*);
+ void block(const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password);
+ void blockCli(const std::string& path_to_task, Submittable*);
+ void kill(const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password);
+ void killCli(const std::string& path_to_task, Submittable*);
+
+
+ /// Remove the zombie corresponding to the Task path. Should only be one
+ /// Since we can have many child commands(init,event,meter, label,complete) in a job
+ /// the zombies may get re-added, should we rember this.
+ /// If path not found does nothing.
+ /// For Command Line Interface only the task_path is provided. Just have to make do.
+ bool remove(Submittable*);
+ bool remove(const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password);
+ void removeCli(const std::string& path_to_task, Submittable*);
+
+ /// Query
+ const Zombie& find(const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password) const;
+ const Zombie& find_by_path_only(const std::string& path_to_task) const;
+
+private:
+
+ bool handle_existing_zombie(
+ Zombie &, // The server already knows about the zombie
+ Submittable*, // This NULL for path zombies
+ node_ptr closest_matching_node, // only set for path zombies
+ const TaskCmd* task_cmd, // The child command
+ std::string& action_taken,// User action taken
+ STC_Cmd_ptr& theReply // Reply varies according to User Action
+ );
+
+ bool handle_user_actions(
+ Zombie &, // The server already knows about the zombie
+ Submittable*, // This NULL for path zombies
+ const TaskCmd* task_cmd, // The child command
+ std::string& action_taken,// User action taken
+ STC_Cmd_ptr& theReply // Reply varies according to User Action
+ );
+
+ Zombie& find_zombie(const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password);
+ Zombie& find(Submittable*);
+ const Zombie& find(Submittable*) const;
+ void do_add_user_zombies(const std::vector<Submittable*>& tasks);
+ Zombie& find_by_path(const std::string& path_to_task);
+
+ bool remove_by_path(const std::string& path_to_task);
+private:
+ std::vector<Zombie> zombies_;
+};
+#endif
diff --git a/Base/src/cts/AlterCmd.cpp b/Base/src/cts/AlterCmd.cpp
new file mode 100644
index 0000000..a846cd3
--- /dev/null
+++ b/Base/src/cts/AlterCmd.cpp
@@ -0,0 +1,1030 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #62 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <boost/lexical_cast.hpp>
+
+#include "ClientToServerCmd.hpp"
+#include "AbstractServer.hpp"
+#include "AbstractClientEnv.hpp"
+#include "CtsApi.hpp"
+#include "Defs.hpp"
+#include "Task.hpp"
+#include "Str.hpp"
+#include "ExprAst.hpp"
+#include "SuiteChanged.hpp"
+#include "Log.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+namespace po = boost::program_options;
+
+static std::string dump_args(const std::vector<std::string>& options, const std::vector<std::string>& paths )
+{
+ std::string the_args;
+ for(size_t i = 0; i < options.size(); i++) {
+ the_args += options[i];
+ the_args += " ";
+ }
+ for(size_t i = 0; i < paths.size(); i++) {
+ the_args += paths[i];
+ the_args += " ";
+ }
+ return the_args;
+}
+
+static AlterCmd::Delete_attr_type deleteAttrType(const std::string& s)
+{
+ if (s == "variable") return AlterCmd::DEL_VARIABLE;
+ if (s == "time") return AlterCmd::DEL_TIME;
+ if (s == "today") return AlterCmd::DEL_TODAY;
+ if (s == "date") return AlterCmd::DEL_DATE;
+ if (s == "day") return AlterCmd::DEL_DAY;
+ if (s == "cron") return AlterCmd::DEL_CRON;
+ if (s == "event") return AlterCmd::DEL_EVENT;
+ if (s == "meter") return AlterCmd::DEL_METER;
+ if (s == "label") return AlterCmd::DEL_LABEL;
+ if (s == "trigger") return AlterCmd::DEL_TRIGGER;
+ if (s == "complete") return AlterCmd::DEL_COMPLETE;
+ if (s == "repeat") return AlterCmd::DEL_REPEAT;
+ if (s == "limit") return AlterCmd::DEL_LIMIT;
+ if (s == "limit_path") return AlterCmd::DEL_LIMIT_PATH;
+ if (s == "inlimit") return AlterCmd::DEL_INLIMIT;
+ if (s == "zombie") return AlterCmd::DEL_ZOMBIE;
+ if (s == "late") return AlterCmd::DEL_LATE;
+ return AlterCmd::DELETE_ATTR_ND;
+}
+static std::string to_string(AlterCmd::Delete_attr_type d)
+{
+ switch (d) {
+ case AlterCmd::DEL_VARIABLE: return "variable"; break;
+ case AlterCmd::DEL_TIME: return "time"; break;
+ case AlterCmd::DEL_TODAY: return "today"; break;
+ case AlterCmd::DEL_DATE: return "date"; break;
+ case AlterCmd::DEL_DAY: return "day"; break;
+ case AlterCmd::DEL_CRON: return "cron"; break;
+ case AlterCmd::DEL_EVENT: return "event"; break;
+ case AlterCmd::DEL_METER: return "meter"; break;
+ case AlterCmd::DEL_LABEL: return "label"; break;
+ case AlterCmd::DEL_TRIGGER: return "trigger"; break;
+ case AlterCmd::DEL_COMPLETE: return "complete"; break;
+ case AlterCmd::DEL_REPEAT: return "repeat"; break;
+ case AlterCmd::DEL_LIMIT: return "limit"; break;
+ case AlterCmd::DEL_LIMIT_PATH:return "limit_path"; break;
+ case AlterCmd::DEL_INLIMIT: return "inlimit"; break;
+ case AlterCmd::DEL_ZOMBIE: return "zombie"; break;
+ case AlterCmd::DEL_LATE: return "late"; break;
+ case AlterCmd::DELETE_ATTR_ND: break;
+ default: break;
+ }
+ return string();
+}
+static void validDeleteAttr(std::vector<std::string>& vec)
+{
+ vec.reserve(17);
+ vec.push_back("variable");
+ vec.push_back("time");
+ vec.push_back("today");
+ vec.push_back("date");
+ vec.push_back("day");
+ vec.push_back("cron");
+ vec.push_back("event");
+ vec.push_back("meter");
+ vec.push_back("label");
+ vec.push_back("trigger");
+ vec.push_back("complete");
+ vec.push_back("repeat");
+ vec.push_back("limit");
+ vec.push_back("limit_path");
+ vec.push_back("inlimit");
+ vec.push_back("zombie");
+ vec.push_back("late");
+}
+
+
+static AlterCmd::Add_attr_type addAttrType(const std::string& s)
+{
+ if (s == "time") return AlterCmd::ADD_TIME;
+ if (s == "today") return AlterCmd::ADD_TODAY;
+ if (s == "date") return AlterCmd::ADD_DATE;
+ if (s == "day") return AlterCmd::ADD_DAY;
+ if (s == "zombie") return AlterCmd::ADD_ZOMBIE;
+ if (s == "variable") return AlterCmd::ADD_VARIABLE;
+ if (s == "late") return AlterCmd::ADD_LATE;
+ return AlterCmd::ADD_ATTR_ND;
+}
+static std::string to_string(AlterCmd::Add_attr_type a) {
+ switch (a) {
+ case AlterCmd::ADD_TIME: return "time;"; break;
+ case AlterCmd::ADD_TODAY: return "today"; break;
+ case AlterCmd::ADD_DATE: return "date"; break;
+ case AlterCmd::ADD_DAY: return "day"; break;
+ case AlterCmd::ADD_ZOMBIE: return "zombie"; break;
+ case AlterCmd::ADD_VARIABLE:return "variable"; break;
+ case AlterCmd::ADD_LATE: return "late"; break;
+ case AlterCmd::ADD_ATTR_ND: break;
+ }
+ return string();
+}
+static void validAddAttr(std::vector<std::string>& vec)
+{
+ vec.reserve(7);
+ vec.push_back("time");
+ vec.push_back("today");
+ vec.push_back("date");
+ vec.push_back("day");
+ vec.push_back("zombie");
+ vec.push_back("variable");
+ vec.push_back("late");
+}
+
+
+static AlterCmd::Change_attr_type changeAttrType(const std::string& s)
+{
+ if (s == "variable") return AlterCmd::VARIABLE;
+ if (s == "clock_type") return AlterCmd::CLOCK_TYPE;
+ if (s == "clock_date") return AlterCmd::CLOCK_DATE;
+ if (s == "clock_gain") return AlterCmd::CLOCK_GAIN;
+ if (s == "clock_sync") return AlterCmd::CLOCK_SYNC;
+ if (s == "event") return AlterCmd::EVENT;
+ if (s == "meter") return AlterCmd::METER;
+ if (s == "label") return AlterCmd::LABEL;
+ if (s == "trigger") return AlterCmd::TRIGGER;
+ if (s == "complete") return AlterCmd::COMPLETE;
+ if (s == "repeat") return AlterCmd::REPEAT;
+ if (s == "limit_max") return AlterCmd::LIMIT_MAX;
+ if (s == "limit_value") return AlterCmd::LIMIT_VAL;
+ if (s == "defstatus") return AlterCmd::DEFSTATUS;
+ if (s == "late") return AlterCmd::LATE;
+ return AlterCmd::CHANGE_ATTR_ND;
+}
+static std::string to_string(AlterCmd::Change_attr_type c)
+{
+ switch (c) {
+ case AlterCmd::VARIABLE: return "variable"; break;
+ case AlterCmd::CLOCK_TYPE: return "clock_type"; break;
+ case AlterCmd::CLOCK_DATE: return "clock_date"; break;
+ case AlterCmd::CLOCK_GAIN: return "clock_gain"; break;
+ case AlterCmd::CLOCK_SYNC: return "clock_sync"; break;
+ case AlterCmd::EVENT: return "event"; break;
+ case AlterCmd::METER: return "meter"; break;
+ case AlterCmd::LABEL: return "label"; break;
+ case AlterCmd::TRIGGER: return "trigger"; break;
+ case AlterCmd::COMPLETE: return "complete"; break;
+ case AlterCmd::REPEAT: return "repeat"; break;
+ case AlterCmd::LIMIT_MAX: return "limit_max"; break;
+ case AlterCmd::LIMIT_VAL: return "limit_value"; break;
+ case AlterCmd::DEFSTATUS: return "defstatus"; break;
+ case AlterCmd::LATE: return "late"; break;
+ case AlterCmd::CHANGE_ATTR_ND: break;
+ default: break;
+ }
+ return string();
+}
+static void validChangeAttr(std::vector<std::string>& vec)
+{
+ vec.reserve(16);
+ vec.push_back("variable");
+ vec.push_back("clock_type");
+ vec.push_back("clock_gain");
+ vec.push_back("clock_date");
+ vec.push_back("clock_sync");
+ vec.push_back("event");
+ vec.push_back("meter");
+ vec.push_back("label");
+ vec.push_back("trigger");
+ vec.push_back("complete");
+ vec.push_back("repeat");
+ vec.push_back("limit_max");
+ vec.push_back("limit_value");
+ vec.push_back("defstatus");
+ vec.push_back("free_password");
+ vec.push_back("late");
+}
+
+//=======================================================================================
+
+bool AlterCmd::equals(ClientToServerCmd* rhs) const
+{
+ AlterCmd* the_rhs = dynamic_cast<AlterCmd*>(rhs);
+ if (!the_rhs) return false;
+ if ( paths_ != the_rhs->paths()) { return false; }
+ if ( name_ != the_rhs->name()) { return false; }
+ if ( value_ != the_rhs->value()) { return false; }
+ if ( del_attr_type_ != the_rhs->delete_attr_type()) { return false; }
+ if ( change_attr_type_ != the_rhs->change_attr_type()) { return false; }
+ if ( add_attr_type_ != the_rhs->add_attr_type()) { return false; }
+ if ( flag_type_ != the_rhs->flag_type()) { return false; }
+ if ( flag_ != the_rhs->flag()) { return false; }
+ return UserCmd::equals(rhs);
+}
+
+std::ostream& AlterCmd::print(std::ostream& os) const
+{
+ return my_print(os,paths_);
+}
+
+std::ostream& AlterCmd::print(std::ostream& os, const std::string& path) const
+{
+ std::vector<std::string> paths(1,path);
+ return my_print(os,paths);
+}
+
+std::ostream& AlterCmd::my_print(std::ostream& os, const std::vector<std::string>& paths) const
+{
+ std::string alter_type,attr_type;
+ if (del_attr_type_ != AlterCmd::DELETE_ATTR_ND) {
+ alter_type = "delete";
+ attr_type = to_string(del_attr_type_);
+ }
+ else if (change_attr_type_ != AlterCmd::CHANGE_ATTR_ND) {
+ alter_type = "change";
+ attr_type = to_string(change_attr_type_);
+ }
+ else if (add_attr_type_ != AlterCmd::ADD_ATTR_ND) {
+ alter_type = "add";
+ attr_type = to_string(add_attr_type_);
+ }
+ else if (flag_type_ != Flag::NOT_SET) {
+ if (flag_) alter_type = "set_flag";
+ else alter_type = "clear_flag";
+ attr_type = Flag::enum_to_string(flag_type_);
+ }
+ return user_cmd(os,CtsApi::to_string(CtsApi::alter(paths,alter_type,attr_type,name_,value_)));
+}
+
+STC_Cmd_ptr AlterCmd::alter_server_state(AbstractServer* as) const
+{
+ if ( del_attr_type_ == AlterCmd::DEL_VARIABLE) {
+ as->defs()->set_server().delete_user_variable(name_);
+ }
+ else if ( change_attr_type_ == AlterCmd::VARIABLE || add_attr_type_ == AlterCmd::ADD_VARIABLE) {
+
+ // ECFLOW-380: ECF_NODE, ECF_PORT, ECF_PID, ECF_VERSION, ECF_LISTS
+ if (name_ == Str::ECF_NODE() || name_ == Str::ECF_PORT() || name_ == "ECF_PID" || name_ == "ECF_VERSION" || name_ == "ECF_LISTS" ) {
+ std::stringstream ss; ss << "AlterCmd:: Can not add or change read only server variable " << name_;
+ throw std::runtime_error(ss.str());
+ }
+ as->defs()->set_server().add_or_update_user_variables(name_,value_);
+ }
+
+ // Update defs flag state
+ if (flag_type_ != Flag::NOT_SET) {
+ if (flag_) as->defs()->flag().set(flag_type_);
+ else as->defs()->flag().clear(flag_type_);
+ }
+
+ return doJobSubmission( as );
+}
+
+
+STC_Cmd_ptr AlterCmd::doHandleRequest(AbstractServer* as) const
+{
+ as->update_stats().alter_cmd_++;
+
+ std::stringstream ss;
+ size_t vec_size = paths_.size();
+ for(size_t i= 0; i < vec_size; i++) {
+
+ /// For root node user means to change server state
+ if (paths_[i] == "/") {
+ return alter_server_state(as);
+ }
+
+ node_ptr node = find_node_for_edit_no_throw(as,paths_[i]);
+ if (!node.get()) {
+ ss << "AlterCmd: Could not find node at path " << paths_[i] << "\n";
+ LOG(Log::ERR,"AlterCmd: Failed: Could not find node at path " << paths_[i]);
+ continue;
+ }
+
+ SuiteChanged0 changed(node);
+ try {
+ switch (del_attr_type_) {
+ case AlterCmd::DEL_VARIABLE: node->deleteVariable(name_); break;
+ case AlterCmd::DEL_TIME: node->deleteTime(name_); break;
+ case AlterCmd::DEL_TODAY: node->deleteToday(name_); break;
+ case AlterCmd::DEL_DATE: node->deleteDate(name_); break;
+ case AlterCmd::DEL_DAY: node->deleteDay(name_);break;
+ case AlterCmd::DEL_CRON: node->deleteCron(name_);break;
+ case AlterCmd::DEL_EVENT: node->deleteEvent(name_);break;
+ case AlterCmd::DEL_METER: node->deleteMeter(name_); break;
+ case AlterCmd::DEL_LABEL: node->deleteLabel(name_); break;
+ case AlterCmd::DEL_TRIGGER: node->deleteTrigger(); break;
+ case AlterCmd::DEL_COMPLETE: node->deleteComplete(); break;
+ case AlterCmd::DEL_REPEAT: node->deleteRepeat(); break;
+ case AlterCmd::DEL_LIMIT: node->deleteLimit(name_);break;
+ case AlterCmd::DEL_LIMIT_PATH:node->delete_limit_path(name_,value_);break;
+ case AlterCmd::DEL_INLIMIT: node->deleteInlimit(name_); break;
+ case AlterCmd::DEL_ZOMBIE: node->deleteZombie(name_); break;
+ case AlterCmd::DEL_LATE: node->deleteLate(); break;
+ case AlterCmd::DELETE_ATTR_ND: break;
+ default: break;
+ }
+ }
+ catch ( std::exception& e) {
+ ss << "Alter (delete) failed for " << paths_[i] << " : " << e.what() << "\n";
+ }
+
+ try {
+ switch (change_attr_type_) {
+ case AlterCmd::VARIABLE: node->changeVariable(name_,value_); break;
+ case AlterCmd::CLOCK_TYPE: node->suite()->changeClockType(name_); break; // node must be a suite, value must [hybrid|real| virtual]
+ case AlterCmd::CLOCK_DATE: node->suite()->changeClockDate(name_); break; // Expecting day.month.year: node must be a suite, value must [hybrid|real| virtual]
+ case AlterCmd::CLOCK_GAIN: node->suite()->changeClockGain(name_); break; // node must be a suite, value must be int
+ case AlterCmd::CLOCK_SYNC: node->suite()->changeClockSync(); break; // node must be a suite, sync clock with computer
+ case AlterCmd::EVENT: node->changeEvent(name_,value_);break; // if value is empty just set, [1|0] or name [set | clear]
+ case AlterCmd::METER: node->changeMeter(name_,value_); break;
+ case AlterCmd::LABEL: node->changeLabel(name_,value_); break;
+ case AlterCmd::TRIGGER: node->changeTrigger(name_); break; // expression must parse
+ case AlterCmd::COMPLETE: node->changeComplete(name_); break; // expression must parse
+ case AlterCmd::REPEAT: node->changeRepeat(name_); break; //
+ case AlterCmd::LIMIT_MAX: node->changeLimitMax(name_,value_);break; // value must be convertible to int
+ case AlterCmd::LIMIT_VAL: node->changeLimitValue(name_,value_); break; // value < limit max, & value must be convertible to an int
+ case AlterCmd::DEFSTATUS: node->changeDefstatus(name_); break; // must be a valid state
+ case AlterCmd::LATE: node->changeLate(LateAttr::create(name_)); break; // must be a valid late
+ case AlterCmd::CHANGE_ATTR_ND: break;
+ default: break;
+ }
+ }
+ catch ( std::exception& e) {
+ ss << "Alter (change) failed for " << paths_[i] << " : " << e.what() << "\n";
+ }
+
+ try {
+ switch (add_attr_type_) {
+ case AlterCmd::ADD_TIME: node->addTime( TimeSeries::create(name_ ) ); break;
+ case AlterCmd::ADD_TODAY: node->addToday( TimeSeries::create(name_) ); break;
+ case AlterCmd::ADD_DATE: node->addDate( DateAttr::create(name_) ); break;
+ case AlterCmd::ADD_DAY: node->addDay( DayAttr::create(name_) ); break;
+ case AlterCmd::ADD_ZOMBIE: node->addZombie( ZombieAttr::create(name_) ); break;
+ case AlterCmd::ADD_VARIABLE:node->add_variable( name_, value_); break;
+ case AlterCmd::ADD_LATE: node->addLate( LateAttr::create(name_)); break;
+ case AlterCmd::ADD_ATTR_ND: break;
+ }
+ }
+ catch ( std::exception& e) {
+ ss << "Alter (add) failed for " << paths_[i] << ": Could not parse " << name_ << " : " << e.what() << "\n";
+ }
+
+ // Change flags
+ if (flag_type_ != Flag::NOT_SET) {
+ if (flag_) node->flag().set(flag_type_);
+ else node->flag().clear(flag_type_);
+ }
+ }
+
+ std::string error_msg = ss.str();
+ if (!error_msg.empty()) {
+ throw std::runtime_error( error_msg ) ;
+ }
+
+ return doJobSubmission( as );
+}
+
+const char* AlterCmd::arg() { return CtsApi::alterArg();}
+const char* AlterCmd::desc() {
+ /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+ return "Alter the node according to the options.\n"
+ "To add/delete/change server variables use '/' for the path.\n"
+ " arg1 = [ delete | change | add | set_flag | clear_flag]\n"
+ " one option must be specified\n"
+ " arg2 = For delete:\n"
+ " [ variable | time | today | date | day | cron | event | meter | late |\n"
+ " label | trigger | complete | repeat | limit | inlimit | limit_path | zombie ]\n"
+ " For change:\n"
+ " [ variable | clock_type | clock_gain | clock_date | clock_sync | event | meter | label |\n"
+ " trigger | complete | repeat | limit_max | limit_value | defstatus | late ]\n"
+ " *NOTE* If the clock is changed, then the suite will need to be re-queued in order for\n"
+ " the change to take effect fully.\n"
+ " For add:\n"
+ " [ variable | time | today | date | day | zombie | late ]\n"
+ " For set_flag and clear_flag:\n"
+ " [ force_aborted | user_edit | task_aborted | edit_failed |\n"
+ " ecfcmd_failed | no_script | killed | migrated | late |\n"
+ " message | complete | queue_limit | task_waiting | locked | zombie ]\n"
+ " arg3 = name/value\n"
+ " when changing, attributes like variable,meter,event,label,limits,late\n"
+ " we expect arguments to be quoted\n"
+ " arg4 = new_value\n"
+ " specifies the new value only used for 'change'\n"
+ " values with spaces must be quoted\n"
+ " arg5 = paths : At lease one path required. The paths must start with a leading '/' character\n\n"
+ ;
+}
+
+void AlterCmd::addOption(boost::program_options::options_description& desc) const {
+ desc.add_options()( AlterCmd::arg(),po::value< vector<string> >()->multitoken(), AlterCmd::desc() );
+}
+void AlterCmd::create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* ac) const
+{
+ vector<string> args = vm[ arg() ].as< vector<string> >();
+
+ if (ac->debug()) dumpVecArgs(AlterCmd::arg(),args);
+
+ std::vector<std::string> options,paths;
+ split_args_to_options_and_paths(args,options,paths); // relative order is still preserved
+ if (paths.empty()) {
+ std::stringstream ss;
+ ss << "AlterCmd: No paths specified. Paths must begin with a leading '/' character\n" << dump_args(options,paths) << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ if (options.empty()) {
+ std::stringstream ss;
+ ss << "AlterCmd: Invalid argument list:\n" << dump_args(options,paths) << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ if (options.size() < 2 ) {
+ std::stringstream ss;
+ ss << "Alter: At least three arguments expected. Found " << args.size() << "\n" << dump_args(options,paths) << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+
+ // arg[0] should one of [ add | delete | change | set_flag | clear_flag ]
+ std::string alterType = options[0];
+
+ if ( alterType == "add") {
+
+ createAdd(cmd,options,paths);
+ return;
+ }
+ else if ( alterType == "change") {
+
+ createChange(cmd,options,paths);
+ return;
+ }
+ else if ( alterType == "delete") {
+
+ createDelete(cmd,options,paths);
+ return;
+ }
+ else if ( alterType == "set_flag") {
+
+ create_flag(cmd,options,paths, true /*set */);
+ return;
+ }
+ else if ( alterType == "clear_flag") {
+
+ create_flag(cmd,options,paths, false /*clear */);
+ return;
+ }
+
+ std::stringstream ss;
+ ss << "Alter: The first argument must be one of [ change | delete | add | set_flag | clear_flag ] but found '"
+ << alterType << "'\n" << dump_args(options,paths) << "\n";
+ throw std::runtime_error( ss.str() );
+}
+
+void AlterCmd::createAdd( Cmd_ptr& cmd, std::vector<std::string>& options, std::vector<std::string>& paths ) const
+{
+ // options[0] - add
+ // options[1] - [ time | date | day | zombie | variable ]
+ // options[2] - [ time_string | date_string | day_string | zombie_string | variable_name ]
+ // options[3] - variable_value
+ std::stringstream ss;
+
+ AlterCmd::Add_attr_type theAttrType = addAttrType(options[1]);
+ if (theAttrType == AlterCmd::ADD_ATTR_ND) {
+ ss << "AlterCmd: add: The second argument must be one of [ ";
+ std::vector<std::string> valid;
+ validAddAttr(valid);
+ for(size_t i = 0; i < valid.size(); ++i) {
+ if (i != 0) ss << " | ";
+ ss << valid[i];
+ }
+ ss << "] but found " << options[1] << "\n" << AlterCmd::desc();
+ throw std::runtime_error( ss.str() );
+ }
+
+ if (options.size() < 3 ) {
+ ss << "AlterCmd: add: At least four arguments expected. Found " << (options.size() + paths.size()) << "\n" << dump_args(options,paths) << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+
+ // **** parse and check format, expect this argument to be single or double tick quoted ****
+ // **** for time,date,day or zombie
+ std::string name = options[2];
+ std::string value;
+ try {
+ switch (theAttrType) {
+ case AlterCmd::ADD_TIME: (void) TimeSeries::create(name); break;
+ case AlterCmd::ADD_TODAY: (void) TimeSeries::create(name); break;
+ case AlterCmd::ADD_DATE: (void) DateAttr::create(name); break;
+ case AlterCmd::ADD_DAY: (void) DayAttr::create(name); break;
+ case AlterCmd::ADD_ZOMBIE:(void) ZombieAttr::create(name); break;
+ case AlterCmd::ADD_LATE: (void) LateAttr::create(name); break;
+ case AlterCmd::ADD_VARIABLE: {
+ if (options.size() == 3 && paths.size() > 1) {
+ // variable value may be a path, hence it will be in the paths parameter
+ options.push_back(paths[0] );
+ paths.erase( paths.begin() );
+ }
+ if (options.size() < 4 ) {
+ ss << "AlterCmd: add: Expected 'add variable <name> <value> <paths>. Not enough arguments\n" << dump_args(options,paths) << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ value = options[3];
+
+ // Create a Variable to check valid names
+ Variable check(name,value);
+ break;
+ }
+ case AlterCmd::ADD_ATTR_ND:break;
+ }
+ }
+ catch ( std::exception& e) {
+ ss << "AlterCmd: add: Could not parse " << name << ". Error: " << e.what()
+ << "\n for time,today and date the new value should be a quoted string "
+ << "\n for add expected: --alter add variable <name> <value> <paths>\n" << dump_args(options,paths) << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+
+ cmd = Cmd_ptr( new AlterCmd(paths,theAttrType, name, value) );
+}
+
+
+void AlterCmd::createDelete( Cmd_ptr& cmd, const std::vector<std::string>& options, const std::vector<std::string>& paths) const
+{
+ // options[0] = delete
+ // options[1] = variable | time | today | date | day | cron | event | meter | label | trigger | complete | repeat | limit | limit_path | inlimit | zombie |late
+ // options[2] = name ( of object to be delete ) optional
+ // options[3] = limit_path (optional *ONLY* applicable for limit_path, specifies the path to be deleted
+ AlterCmd::Delete_attr_type theAttrType = deleteAttrType(options[1]);
+ if (theAttrType == AlterCmd::DELETE_ATTR_ND) {
+ std::stringstream ss;
+ ss << "Alter: delete: The second argument must be one of [ ";
+ std::vector<std::string> valid;
+ validDeleteAttr(valid);
+ for(size_t i = 0; i < valid.size(); ++i) {
+ if (i != 0) ss << " | ";
+ ss << valid[i];
+ }
+ ss << "] but found " << options[1] << "\n" << AlterCmd::desc();
+ throw std::runtime_error( ss.str() );
+ }
+
+ // Generally an empty third argument means delete all attributes, otherwise delete the specific one.
+ std::string name;
+ if (options.size() >= 3 ) name = options[2];
+
+ // Deleting the limit path requires an additional arg
+ std::string path_value;
+
+ // if specified make sure its parses
+ try {
+ switch (theAttrType) {
+ case AlterCmd::DEL_VARIABLE: {
+ if (!name.empty()) Variable check(name,""); // Create a Variable to check valid names
+ break;
+ }
+ case AlterCmd::DEL_TIME: {
+ if (!name.empty()) (void) TimeSeries::create(name) ; // will throw if not valid
+ break;
+ }
+ case AlterCmd::DEL_TODAY: {
+ if (!name.empty()) (void) TimeSeries::create(name) ; // will throw if not valid
+ break;
+ }
+ case AlterCmd::DEL_DATE: {
+ if (!name.empty()) (void) DateAttr::create(name); // will throw if not valid
+ break;
+ }
+ case AlterCmd::DEL_DAY: {
+ if (!name.empty()) (void)DayAttr::create(name); // will throw if not valid
+ break;
+ }
+ case AlterCmd::DEL_CRON:{
+ if (!name.empty()) {
+ CronAttr parsedCron = CronAttr::create(name); // will throw if not valid
+
+ // additional check since parsing is very forgiving. if parsed string is same as default
+ // then no cron was specified.
+ CronAttr emptyCron;
+ if ( emptyCron.structureEquals(parsedCron)) {
+ throw std::runtime_error("Delete cron Attribute failed. Check cron " + name);
+ }
+ }
+ break;
+ }
+ case AlterCmd::DEL_EVENT: {
+ if (!name.empty()) {
+ Event check(name); // will throw if not valid
+ }
+ break;
+ }
+ case AlterCmd::DEL_METER: {
+ if (!name.empty()) Meter check(name,0,100); // will throw if not valid
+ break;
+ }
+ case AlterCmd::DEL_LABEL: {
+ if (!name.empty()) Label check(name,"value"); // will throw if not valid
+ break;
+ }
+ case AlterCmd::DEL_TRIGGER: break; // there can only be one trigger per node, so we delete by path
+ case AlterCmd::DEL_COMPLETE: break; // there can only be one complete per node, so we delete by path
+ case AlterCmd::DEL_REPEAT: break; // there can only be one repeat per node, so we delete by path
+ case AlterCmd::DEL_LATE: break; // there can only be one late per node, so we delete by path
+ case AlterCmd::DEL_LIMIT: {
+ if (!name.empty()) Limit check(name,10); // will throw if not valid
+ break;
+ }
+ case AlterCmd::DEL_INLIMIT: {
+ if (!name.empty()) InLimit check(name); // will throw if not valid
+ break;
+ }
+ case AlterCmd::DEL_ZOMBIE: {
+ if (!Child::valid_zombie_type(name)) {
+ throw std::runtime_error("Delete Zombie Attribute failed. Expected one of [ ecf | path | user ] but found " + name);
+ }
+ break;
+ }
+ case AlterCmd::DEL_LIMIT_PATH: {
+ if (name.empty()) {
+ std::stringstream ss;
+ ss << "Delete limit_path failed. No limit name provided. Expected 5 args: delete limit_path <limit_name> <path-to-limit> <path_to_node>\n";
+ ss << dump_args(options,paths) << "\n";
+ throw std::runtime_error(ss.str());
+ }
+
+ std::vector<std::string> altered_path = paths;
+ if (options.size() == 4) {
+ // User has provide a limit path which does not start with '/'. Go with flow
+ path_value = options[3];
+ }
+ else {
+ // Since we have a limit path(i.e begins with'/') it will appear in the paths, as the first path
+ if (paths.size() <= 1) {
+ std::stringstream ss;
+ ss << "Delete limit_path failed: No path to limit provided. Expected 5 args: delete limit_path <limit_name> <path-to-limit> <path_to_node>\n"
+ << dump_args(options,paths) << "\n";
+ throw std::runtime_error(ss.str());
+ }
+ path_value = paths[0];
+
+ // Change paths to remove the limit path.
+ altered_path.erase(altered_path.begin());
+ }
+ cmd = Cmd_ptr( new AlterCmd(altered_path,theAttrType, name, path_value ) );
+ return;
+ }
+ case AlterCmd::DELETE_ATTR_ND: break;
+ }
+ }
+ catch ( std::exception& e) {
+ std::stringstream ss;
+ ss << "AlterCmd: delete: Could not parse " << name << ". Error: " << e.what()
+ << "\n for time,today and date the new value should be a quoted string\n" << dump_args(options,paths) << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+
+ cmd = Cmd_ptr( new AlterCmd(paths,theAttrType, name, path_value ) );
+}
+
+void AlterCmd::createChange( Cmd_ptr& cmd, std::vector<std::string>& options, std::vector<std::string>& paths) const
+{
+ // options[0] = change
+ // options[1] = variable | clock_type | clock_gain | clock_date | clock_sync | event | meter | label | trigger | complete | repeat | limit_max | limit_value | defstatus | late ]
+ // options[2] = name
+ // options[3] = value
+
+ std::stringstream ss;
+
+ AlterCmd::Change_attr_type theAttrType = changeAttrType(options[1]);
+ if (theAttrType == AlterCmd::CHANGE_ATTR_ND) {
+ ss << "AlterCmd: change: The third argument(" << options[1] << ") must be one of [ ";
+ std::vector<std::string> valid;
+ validChangeAttr(valid);
+ for(size_t i = 0; i < valid.size(); ++i) {
+ if (i != 0) ss << " | ";
+ ss << valid[i];
+ }
+ ss << "]\n" << AlterCmd::desc();
+ throw std::runtime_error( ss.str() );
+ }
+
+ std::string name, value;
+ switch (theAttrType) {
+ case AlterCmd::VARIABLE: {
+ if (options.size() == 3 && paths.size() > 1) {
+ // The variable value may be a path, and hence it will be paths and not options parameter
+ options.push_back(paths[0]);
+ paths.erase(paths.begin()); // remove first path, since it has been added to options
+ }
+ if (options.size() != 4 ) {
+ ss << "AlterCmd: change: expected 5 args : change variable <variable_name> <new_value> <path_to_node>";
+ ss << " but found only " << (options.size() + paths.size()) << " arguments. The value should be quoted if there are spaces\n";
+ ss << dump_args(options,paths) << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ name = options[2];
+ value = options[3];
+ break;}
+
+ case AlterCmd::CLOCK_TYPE: {
+ if (options.size() != 3) {
+ ss << "AlterCmd: change: expected at least four args i.e. change clock_type [ hybrid | real ] <path_to_suite>";
+ ss << " but found only " << (options.size() + paths.size()) << " arguments\n"
+ << dump_args(options,paths) << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ name = options[2];
+ if (name != "hybrid" && name != "real") {
+ ss << "AlterCmd: change clock_type: expected third argument to be one of [ hybrid | real ]";
+ ss << " but found " << name << "\n" << dump_args(options,paths) << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ break;}
+
+ case AlterCmd::CLOCK_DATE: {
+ if (options.size() != 3) {
+ ss << "AlterCmd: change clock_date : expected at least four args : change clock_date day.month.year <path_to_suite>";
+ ss << " but found only " << (options.size() + paths.size()) << " arguments\n" << dump_args(options,paths) << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ name = options[2];
+
+ // Check date is in correct format:
+ try {
+ int day,month,year;
+ DateAttr::getDate(name,day,month,year);
+ DateAttr::checkDate(day,month,year,false /* for clocks we don't allow wild carding */);
+ }
+ catch ( std::exception& e) {
+ ss << "AlterCmd:change clock_date " << name << " is not valid. " << e.what();
+ throw std::runtime_error( ss.str() );
+ }
+ break;}
+
+ case AlterCmd::CLOCK_GAIN: {
+ if (options.size() != 3) {
+ ss << "AlterCmd: change clock_gain : expected four args i.e. change clock_gain <int> <path_to_suite> ";
+ ss << " but found " << (options.size() + paths.size()) << " arguments. The actual gain must be convertible to an integer\n";
+ ss << dump_args(options,paths) << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ name = options[2];
+ try { boost::lexical_cast< int >( name ); }
+ catch ( boost::bad_lexical_cast& ) {
+ ss << "AlterCmd: " << options[0] << " " << options[1] << " " << options[2] << " " << paths[0];
+ ss << " expected '" << name << "' to be convertible to an integer\n";
+ ss << dump_args(options,paths) << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ break; }
+
+ case AlterCmd::CLOCK_SYNC: {
+ if (options.size() != 2) {
+ ss << "AlterCmd: change clock_sync : expected three args i.e. change clock_sync <path_to_suite> ";
+ ss << " but found " << (options.size() + paths.size()) << " arguments.\n";
+ ss << dump_args(options,paths) << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ break; }
+
+ case AlterCmd::EVENT: {
+ if (options.size() != 3 && options.size() != 4) {
+ ss << "AlterCmd: Change event : expected four/five args: change event <name_or_number> <[set | clear | <nothing>]> <path_to_node>";
+ ss << " but found only " << (options.size() + paths.size()) << " arguments\n";
+ ss << dump_args(options,paths) << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ name = options[2];
+ if ( options.size() == 4) {
+ value = options[3];
+ if (value != Event::SET() && value != Event::CLEAR()) {
+ ss << "AlterCmd: Change event : expected four/five args: change event <name_or_number> <[set | clear | <nothing>]> <path_to_node>";
+ ss << " but found only " << (options.size() + paths.size()) << " arguments\n";
+ ss << dump_args(options,paths) << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ }
+ // The name could be an integer
+ try { boost::lexical_cast< int >( name ); }
+ catch ( boost::bad_lexical_cast& ) {
+ // name is not an integer, check name is valid
+ Event check_name(name); // will throw if name is not valid
+ }
+ break; }
+
+ case AlterCmd::METER: {
+ if (options.size() != 4) {
+ ss << "AlterCmd: change: expected five args: change meter meter_name meter_value <path_to_node>";
+ ss << " but found only " << (options.size() + paths.size()) << " arguments. The meter value must be convertible to an integer\n";
+ ss << dump_args(options,paths) << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ name = options[2];
+ Meter check(name,0,100); // Check meter name , by creating a meter
+
+ value = options[3];
+ try { boost::lexical_cast< int >( value );}
+ catch ( boost::bad_lexical_cast& ) {
+ ss << "AlterCmd: " << options[0] << " " << options[1] << " " << options[2] << " " << options[3] << " " << paths[0]
+ << " expected " << value << " to be convertible to an integer\n";
+ throw std::runtime_error( ss.str() );
+ }
+
+ break; }
+
+
+ case AlterCmd::LABEL: {
+
+ if (options.size() == 3 && paths.size() == 1) {
+ // ECFLOW-648 allow label value to be empty
+ // HOWEVER , we can not cope multiple paths, and setting value to empty.
+ // since empty quotes are removed by boost program options, hence if we have a lavel value which is path, and multiple paths
+ value.clear();
+ }
+ else {
+ // ECFLOW-480 take into account label values that is a path, add ing quotes around the value does not help:
+ // Note boost program options will remove the quotes around the value
+ // hence its difficult to say what is an option and what is a path.
+ // However since we expect 4(change,label,<label_name>,<label_value>) options, work around the problem
+ if (options.size() == 3 && paths.size() > 1) {
+ options.push_back(paths[0]);
+ paths.erase(paths.begin()); // remove first path, since it has been added to options
+ }
+ if (options.size() != 4) {
+ ss << "AlterCmd: change label expected at least five args : change label <label_name> <label_value> <path_to_node> ";
+ ss << " but found " << (options.size() + paths.size()) << " arguments. the label value should be quoted\n";
+ ss << dump_args(options,paths) << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ value = options[3];
+ }
+ name = options[2];
+
+ Label check(name,value); // Check name , by creating
+ break; }
+
+ case AlterCmd::LATE: {
+ if (options.size() != 3) {
+ ss << "AlterCmd: change: expected three args: change late \"late -s +00:15 -a 20:00 -c +02:00\" <path_to_node>";
+ ss << " but found only " << (options.size() + paths.size()) << " arguments\n";
+ ss << dump_args(options,paths) << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ name = options[2];
+ (void) LateAttr::create(name); // Check we can create the late
+ break; }
+
+ case AlterCmd::TRIGGER: {
+ // ECFLOW-137, if the expression contains a leading '/' and *no* spaces,
+ // then it will get treated as a path and not an option
+ // i.e change trigger 'expression' <path_to_node>
+ // change trigger "/suite/task:a" /path/to/a/node
+ // Note boost program options will remove the quotes around the expression
+ // hence its difficult to say what is an option and what is a path.
+ // However since we expect 3 options, work around the problem
+ if (options.size() == 2 && paths.size() == 2) {
+ options.push_back(paths[0]);
+ paths.erase(paths.begin()); // remove first path, since it has been added to options
+ }
+ if (options.size() != 3) {
+ ss << "AlterCmd: change: expected four args : change trigger 'expression' <path_to_node>";
+ ss << " but found " << (options.size() + paths.size()) << " arguments. The trigger expression must be quoted\n";
+ ss << dump_args(options,paths) << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ name = options[2];
+
+ // Parse the expression
+ PartExpression exp(name);
+ string parseErrorMsg;
+ std::auto_ptr<AstTop> ast = exp.parseExpressions( parseErrorMsg );
+ if (!ast.get()) {
+ ss << "AlterCmd: change trigger: Failed to parse expression '" << name << "'. " << parseErrorMsg << "\n";
+ ss << dump_args(options,paths) << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ break; }
+
+ case AlterCmd::COMPLETE: {
+ if (options.size() == 2 && paths.size() == 2) {
+ options.push_back(paths[0]);
+ paths.erase(paths.begin()); // remove first path, since it has been added to options
+ }
+ if (options.size() != 3) {
+ ss << "AlterCmd: change complete: expected four args: change complete 'expression' <path_to_node> ";
+ ss << " but found " << (options.size() + paths.size()) << " arguments. The expression must be quoted\n";
+ ss << dump_args(options,paths) << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ name = options[2];
+
+ // Parse the expression
+ PartExpression exp(name);
+ string parseErrorMsg;
+ std::auto_ptr<AstTop> ast = exp.parseExpressions( parseErrorMsg );
+ if (!ast.get()) {
+ ss << "AlterCmd: change complete: Failed to parse expression '" << name << "'. " << parseErrorMsg << "\n";
+ ss << dump_args(options,paths) << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ break;}
+
+ case AlterCmd::REPEAT: {
+ // *NOTE* a Node can only have *ONE* repeat, hence no need to provide name
+ if (options.size() != 3) {
+ ss << "AlterCmd: change repeat: expected four arg's : change repeat [ integer | string ] <path_to_node>";
+ ss << " but found only " << (options.size() + paths.size()) << " arguments.\n";
+ ss << dump_args(options,paths) << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ name = options[2];
+ break; }
+
+ case AlterCmd::LIMIT_MAX: {
+ if (options.size() != 4) {
+ ss << "AlterCmd: change: limit_max: : expected five arguments : change limit_max <limit_name> <int> <path_to_node>";
+ ss << " but found " << (options.size() + paths.size()) << " arguments.\n";
+ ss << dump_args(options,paths) << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ name = options[2];
+ value = options[3];
+ int limit = 0;
+ try { limit = boost::lexical_cast< int >( value );}
+ catch ( boost::bad_lexical_cast& ) {
+ ss << "AlterCmd: change: limit-max: " << options[0] << " " << options[1] << " " << options[2] << " " << options[3] << " " << paths[0]
+ << " expected " << value << " to be convertible to an integer\n";
+ throw std::runtime_error( ss.str() );
+ }
+ Limit check(name,limit); // Check name , by creating
+ break; }
+
+ case AlterCmd::LIMIT_VAL: {
+ if (options.size() != 4) {
+ ss << "AlterCmd: change: limit-value: expected five arguments : change limit_value <limit_name> <int> <path_to_node>";
+ ss << " but found " << (options.size() + paths.size()) << " arguments.\n";
+ ss << dump_args(options,paths) << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ name = options[2];
+ value = options[3];
+ try { boost::lexical_cast< int >( value );}
+ catch ( boost::bad_lexical_cast& ) {
+ ss << "AlterCmd: change: limit_value: " << options[0] << " " << options[1] << " " << options[2] << " " << options[3] << " " << paths[0]
+ << " expected " << value << " to be convertible to an integer\n";
+ ss << dump_args(options,paths) << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ Limit check(name,10); // Check name, by creating
+ break;}
+
+ case AlterCmd::DEFSTATUS: {
+ if (options.size() != 3) {
+ ss << "AlterCmd: change defstatus expected four args : change defstatus [ queued | complete | unknown | aborted | suspended ] <path_to_node>";
+ ss << " but found " << (options.size() + paths.size()) << " arguments.\n";
+ ss << dump_args(options,paths) << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ name = options[2];
+ if (!DState::isValid(name)) {
+ ss << "AlterCmd: " << options[0] << " " << options[1] << " " << options[2] << " " << paths[0]
+ << "an expected " << name << " to be a valid state, i.e one of [ queued | complete | unknown | aborted | suspended ]\n";
+ throw std::runtime_error( ss.str() );
+ }
+ break; }
+
+ case AlterCmd::CHANGE_ATTR_ND: break;
+ default: break;
+ }
+
+ cmd = Cmd_ptr( new AlterCmd(paths,theAttrType, name, value ) );
+}
+
+void AlterCmd::create_flag( Cmd_ptr& cmd, const std::vector<std::string>& options, const std::vector<std::string>& paths, bool flag) const
+{
+ // options[0] = set_flag | clear_flag
+ // options[1] = [ force_aborted | user_edit | task_aborted | edit_failed | ecfcmd_failed | no_script | killed | migrated | late | message | complete | queue_limit | task_waiting | locked | zombie ]
+
+ Flag::Type theFlagType = Flag::string_to_flag_type(options[1]);
+ if (theFlagType == Flag::NOT_SET) {
+ std::stringstream ss;
+ ss << "AlterCmd: set/clear_flag: The second argument(" << options[1] << ") must be one of [ ";
+ std::vector<std::string> valid;
+ Flag::valid_flag_type(valid);
+ for(size_t i = 0; i < valid.size(); ++i) { if (i != 0) ss << " | "; ss << valid[i]; }
+ ss << "]\n" << AlterCmd::desc();
+ throw std::runtime_error( ss.str() );
+ }
+
+ cmd = Cmd_ptr( new AlterCmd(paths,theFlagType, flag ) );
+}
+
+std::ostream& operator<<(std::ostream& os, const AlterCmd& c) { return c.print(os); }
diff --git a/Base/src/cts/BeginCmd.cpp b/Base/src/cts/BeginCmd.cpp
new file mode 100644
index 0000000..09992ec
--- /dev/null
+++ b/Base/src/cts/BeginCmd.cpp
@@ -0,0 +1,177 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #23 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include "ClientToServerCmd.hpp"
+#include "AbstractServer.hpp"
+#include "CtsApi.hpp"
+#include "AbstractClientEnv.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Str.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+namespace po = boost::program_options;
+
+
+BeginCmd::BeginCmd(const std::string& suiteName, bool force)
+: suiteName_(suiteName), force_(force)
+{
+ // The begin command actually requires the suite name without the lead '/'
+ // i.e if we provide /suite --> change to suite
+ if (!suiteName_.empty() && suiteName_[0] == '/') {
+ suiteName_.erase(0,1); // delete first character
+ }
+}
+
+std::ostream& BeginCmd::print(std::ostream& os) const
+{
+ return user_cmd(os,CtsApi::begin(suiteName_,force_));
+}
+
+bool BeginCmd::equals(ClientToServerCmd* rhs) const
+{
+ BeginCmd* the_rhs = dynamic_cast< BeginCmd* > ( rhs );
+ if ( !the_rhs ) return false;
+ if (suiteName_ != the_rhs->suiteName()) return false;
+ if (force_ != the_rhs->force()) return false;
+ return UserCmd::equals(rhs);
+}
+
+STC_Cmd_ptr BeginCmd::doHandleRequest(AbstractServer* as) const
+{
+ as->update_stats().begin_cmd_++;
+ defs_ptr defs = as->defs();
+
+ // If no suite name begin all suites, else begin the the specific suite
+ if ( suiteName_.empty()) {
+
+ const std::vector<suite_ptr>& suiteVec = defs->suiteVec();
+ size_t theSuiteVecSize = suiteVec.size();
+ if (!force_) {
+ for(size_t s = 0; s < theSuiteVecSize; s++) {
+ /// check_suite_can_begin will throw if suite can't begin
+ defs->check_suite_can_begin(suiteVec[s]);
+ }
+ }
+ else {
+ for(size_t s = 0; s < theSuiteVecSize; s++) {
+ as->zombie_ctrl().add_user_zombies(suiteVec[s]);
+ }
+
+ // Force should *only* be used for test
+ defs->reset_begin();
+ }
+
+ defs->beginAll();
+ }
+ else {
+
+ suite_ptr suite = defs->findSuite(suiteName_);
+ if (!suite.get()) {
+ std::stringstream ss;
+ ss << "BeginCmd::doHandleRequest: Begin failed as suite '" << suiteName_ << "' is not loaded.\n";
+ throw std::runtime_error( ss.str() );
+ }
+
+ /// check_suite_can_begin will throw if suite can't begin
+ if (!force_) defs->check_suite_can_begin(suite);
+ else {
+ as->zombie_ctrl().add_user_zombies(suite);
+
+ // Force should *only* be used for test
+ suite->reset_begin();
+ }
+
+
+ defs->beginSuite(suite);
+ }
+
+ // After begin do the first Job submission. This will kick of those
+ // jobs that have no dependencies, or relative time of +00:00
+ return doJobSubmission(as);
+}
+
+const char* BeginCmd::arg() { return CtsApi::beginArg();}
+const char* BeginCmd::desc() {
+ /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+ return
+ "Begin playing the definition in the server.\n"
+ "Expects zero or a single quoted string.\n"
+ " arg1 = suite-name | Nothing | force\n"
+ " play the chosen suite, if no arg specified, play all suites, in the definition\n"
+ " force means reset the begin status on the suites and bypass checks.\n"
+ " This is only required if suite-name is provide as the first argument\n"
+ " Using force can cause the creation of zombies\n"
+ "Usage:\n"
+ "--begin # will begin all suites\n"
+ "--begin=\"--force\" # reset and then begin all suites, bypassing any checks. Note: string must be quoted\n"
+ "--begin=\"mySuite\" # begin playing suite of name 'mySuite'\n"
+ "--begin=\"mySuite --force\" # reset and begin playing suite 'mySuite', bypass check"
+ ;
+}
+
+void BeginCmd::addOption(boost::program_options::options_description& desc) const
+{
+ // allow options like
+ // client --begin=suitename // begin <suitename>
+ // client --begin // means begin all suites
+ desc.add_options()( BeginCmd::arg(),po::value< string >()->implicit_value( string("") ), BeginCmd::desc() );
+}
+void BeginCmd::create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* ace ) const
+{
+ std::string beginArg = vm[ arg() ].as< std::string > ();
+
+ if (ace->debug()) {
+ cout << " BeginCmd::create arg = " << beginArg << "\n";
+ }
+
+ std::string suiteName;
+ bool force = false;
+
+ if (!beginArg.empty()) {
+ std::vector< std::string > lineTokens;
+ Str::split(beginArg,lineTokens);
+ if (lineTokens.size() == 1) {
+ if (lineTokens[0] == "--force") force = true;
+ else suiteName = lineTokens[0];
+ }
+ else if (lineTokens.size() == 2) {
+ suiteName = lineTokens[0];
+ if (lineTokens[1] != "--force") {
+ std::stringstream ss;
+ ss << "BeginCmd: Expected second argument to be '--force' but found " << lineTokens[1] << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ force = true;
+ }
+ else {
+ std::stringstream ss;
+ ss << "BeginCmd: Expect zero, one or 2 arguments, but found " << lineTokens.size() << " arguments\n" << BeginCmd::desc() << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ }
+
+ if (ace->debug()) {
+ std::cout << " BeginCmd::create suiteName = " << suiteName << "\n";
+ std::cout << " BeginCmd::create force = " << force << "\n";
+ }
+
+ cmd = Cmd_ptr(new BeginCmd( suiteName, force ));
+}
+
+std::ostream& operator<<(std::ostream& os, const BeginCmd& c) { return c.print(os); }
diff --git a/Base/src/cts/CFileCmd.cpp b/Base/src/cts/CFileCmd.cpp
new file mode 100644
index 0000000..36ab13f
--- /dev/null
+++ b/Base/src/cts/CFileCmd.cpp
@@ -0,0 +1,309 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #42 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <sstream>
+#include "boost/filesystem/operations.hpp"
+#include <boost/lexical_cast.hpp>
+
+#include "ClientToServerCmd.hpp"
+#include "AbstractServer.hpp"
+#include "AbstractClientEnv.hpp"
+#include "File.hpp"
+#include "CtsApi.hpp"
+#include "Defs.hpp"
+#include "Task.hpp"
+#include "EcfFile.hpp"
+#include "Str.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+namespace po = boost::program_options;
+namespace fs = boost::filesystem;
+
+CFileCmd::CFileCmd(const std::string& pathToNode, const std::string& file_type, const std::string& input_max_lines)
+: file_(ECF), pathToNode_(pathToNode), max_lines_(File::MAX_LINES())
+{
+ // std::cout << "CFileCmd::CFileCmd the_max_lines " << the_max_lines << "\n";
+
+ if (file_type == "script") file_ = CFileCmd::ECF;
+ else if (file_type == "job") file_ = CFileCmd::JOB;
+ else if (file_type == "jobout") file_ = CFileCmd::JOBOUT;
+ else if (file_type == "manual") file_ = CFileCmd::MANUAL;
+ else if (file_type == "kill") file_ = CFileCmd::KILL;
+ else if (file_type == "stat") file_ = CFileCmd::STAT;
+ else {
+ std::stringstream ss;
+ ss << "CFileCmd::CFileCmd: Unrecognised file type " << file_type << " expected one of [script | job | jobout | manual | kill | stat] \n";
+ throw std::runtime_error( ss.str() );
+ }
+
+ if (!input_max_lines.empty()){
+ try {
+ // Note: max_lines_ if type size_t, hence we cast to int to check for negative numbers
+ int the_max_lines = boost::lexical_cast<int>( input_max_lines );
+ if (the_max_lines <= 0) the_max_lines = File::MAX_LINES();
+ max_lines_ = the_max_lines;
+ }
+ catch ( boost::bad_lexical_cast& e) {
+ std::stringstream ss;
+ ss << "CFileCmd::CFileCmd: The third argument(" << input_max_lines << ") must be convertible to an integer\n";
+ throw std::runtime_error(ss.str());
+ }
+ }
+}
+
+
+std::vector<CFileCmd::File_t> CFileCmd::fileTypesVec()
+{
+ std::vector<CFileCmd::File_t> vec; vec.reserve(5);
+ vec.push_back(CFileCmd::ECF);
+ vec.push_back(CFileCmd::JOB);
+ vec.push_back(CFileCmd::JOBOUT);
+ vec.push_back(CFileCmd::MANUAL);
+ vec.push_back(CFileCmd::KILL);
+ vec.push_back(CFileCmd::STAT);
+ return vec;
+}
+
+std::string CFileCmd::toString(CFileCmd::File_t ft)
+{
+ switch (ft) {
+ case CFileCmd::ECF: return "script"; break;
+ case CFileCmd::MANUAL: return "manual"; break;
+ case CFileCmd::JOB: return "job"; break;
+ case CFileCmd::JOBOUT: return "jobout"; break;
+ case CFileCmd::KILL: return "kill"; break;
+ case CFileCmd::STAT: return "stat"; break;
+ default : break;
+ }
+ return "script";
+}
+
+bool CFileCmd::equals(ClientToServerCmd* rhs) const
+{
+ CFileCmd* the_rhs = dynamic_cast<CFileCmd*>(rhs);
+ if (!the_rhs) return false;
+ if ( file_ != the_rhs->fileType()) { return false; }
+ if ( max_lines_ != the_rhs->max_lines()) { return false; }
+ if ( pathToNode_ != the_rhs->pathToNode()) { return false; }
+ return UserCmd::equals(rhs);
+}
+
+std::ostream& CFileCmd::print(std::ostream& os) const
+{
+ return user_cmd(os,CtsApi::to_string(CtsApi::file(pathToNode_,toString(file_),boost::lexical_cast<std::string>(max_lines_))));
+}
+
+STC_Cmd_ptr CFileCmd::doHandleRequest(AbstractServer* as) const
+{
+ // cout << "CFileCmd::doHandleRequest " << toString(file_) << " =======================================\n";
+ switch (file_) {
+ case CFileCmd::ECF: as->update_stats().file_ecf_++; break;
+ case CFileCmd::MANUAL: as->update_stats().file_manual_++; break;
+ case CFileCmd::JOB: as->update_stats().file_job_++; break;
+ case CFileCmd::JOBOUT: as->update_stats().file_jobout_++; break;
+ case CFileCmd::KILL: as->update_stats().file_cmdout_++; break;
+ case CFileCmd::STAT: as->update_stats().file_cmdout_++; break;
+ }
+
+ node_ptr node = find_node(as,pathToNode_); // will throw if defs not defined, or node not found
+
+ std::string fileContents;
+ Submittable* submittable = node->isSubmittable();
+ if ( submittable ) {
+
+ switch (file_) {
+ case CFileCmd::ECF: {
+ EcfFile ecf_file = submittable->locatedEcfFile(); // will throw std::runtime_error for errors
+ ecf_file.script(fileContents); // will throw std::runtime_error for errors
+ break;}
+
+ case CFileCmd::MANUAL: {
+ EcfFile ecf_file = submittable->locatedEcfFile(); // will throw std::runtime_error for errors
+ ecf_file.manual(fileContents); // will throw std::runtime_error for errors
+ break;}
+
+ case CFileCmd::JOB: {
+ std::string ecf_job_file;
+ submittable->findParentVariableValue(Str::ECF_JOB(), ecf_job_file);
+ if (!File::open(ecf_job_file,fileContents)) {
+ std::stringstream ss;
+ ss << "CFileCmd::doHandleRequest: Failed to open the job file('" << ecf_job_file << "') for task " << pathToNode_;
+ throw std::runtime_error( ss.str() ) ;
+ }
+ break;}
+
+ case CFileCmd::JOBOUT: {
+
+ // ECF_JOBOUT is either constructed from ECF_OUT *OR* ECF_HOME/ECF_NAME.ECF_TRYNO
+ // See: Submittable.cpp: SubGenVariables::update_generated_variables()
+ //
+ // Typically if ECF_OUT is specified, we should only look at that location
+ // however SMS also looked at the alternate location (and RD relied on this ECFLOW-177 )
+
+ const Variable& ecf_jobout_gen_var = submittable->findGenVariable(Str::ECF_JOBOUT());
+ if (!File::open(ecf_jobout_gen_var.theValue(),fileContents)) {
+
+ // If that fails as a backup, look under ECF_HOME/ECF_NAME.ECF_TRYNO, ECFLOW-177 preserve old SMS behaviour
+ std::string backup_jobout;
+ submittable->findParentUserVariableValue(Str::ECF_HOME(), backup_jobout);
+ backup_jobout += submittable->absNodePath();
+ backup_jobout += ".";
+ backup_jobout += submittable->tryNo();
+
+ if ( backup_jobout != ecf_jobout_gen_var.theValue()) {
+ // Implies ECF_OUT was specified, hence *ALSO* look in ECF_HOME/ECF_NAME.ECF_TRYNO
+ if (!File::open(backup_jobout,fileContents)) {
+ std::stringstream ss;
+ ss << "CFileCmd::doHandleRequest: Failed to open the job-out(ECF_JOBOUT=ECF_OUT/ECF_NAME.ECF_TRYNO) file('"
+ << ecf_jobout_gen_var.theValue() << "') *AND* at location (ECF_JOBOUT=ECF_HOME/ECF_NAME.ECF_TRYNO)('"
+ << backup_jobout << "') for task " << pathToNode_;
+ throw std::runtime_error( ss.str() ) ;
+ }
+ }
+ else {
+ // ECF_OUT *not* specified implies ECF_JOBOUT = ECF_HOME/ECF_NAME.ECF_TRYNO
+ std::stringstream ss;
+ ss << "CFileCmd::doHandleRequest: Failed to open the job-out(ECF_JOBOUT=ECF_HOME/ECF_NAME.ECF_TRYNO) file('"
+ << ecf_jobout_gen_var.theValue() << "') for task " << pathToNode_;
+ throw std::runtime_error( ss.str() ) ;
+ }
+ }
+
+ break; }
+
+ case CFileCmd::KILL: {
+ std::string ecf_job_file;
+ submittable->findParentVariableValue(Str::ECF_JOB(), ecf_job_file);
+ std::string file = ecf_job_file + ".kill";
+ if (!File::open(file,fileContents)) {
+ std::stringstream ss;
+ ss << "CFileCmd::doHandleRequest: Failed to open the kill output file('" << file << "') for task " << pathToNode_;
+ throw std::runtime_error( ss.str() ) ;
+ }
+ break; }
+
+ case CFileCmd::STAT: {
+ std::string ecf_job_file;
+ submittable->findParentVariableValue(Str::ECF_JOB(), ecf_job_file);
+ std::string file = ecf_job_file + ".stat";
+ if (!File::open(file,fileContents)) {
+ std::stringstream ss;
+ ss << "CFileCmd::doHandleRequest: Failed to open the status output file('" << file << "') for task " << pathToNode_;
+ throw std::runtime_error( ss.str() ) ;
+ }
+ break; }
+
+ default : assert(false); break;
+ }
+ }
+ else {
+
+ if (file_ == CFileCmd::MANUAL) {
+ // The only valid option for Suite or Family is Manual
+
+ // First look for .man files in ECF_FILES and then ECF_HOME
+ std::string ecf_files;
+ node->findParentUserVariableValue( Str::ECF_FILES(), ecf_files);
+ if ( !ecf_files.empty() && fs::exists( ecf_files ) && fs::is_directory( ecf_files ) ) {
+
+ std::string manFile = File::backwardSearch( ecf_files, node->absNodePath(), File::MAN_EXTN());
+ if (!manFile.empty()) {
+ EcfFile the_file(node.get(), manFile);
+ the_file.manual(fileContents); // pre-process & extract manual: will throw std::runtime_error for errors
+ }
+ }
+
+ if ( fileContents.empty() ) {
+ // Try under ECF_HOME
+ std::string ecf_home;
+ node->findParentUserVariableValue( Str::ECF_HOME(), ecf_home);
+ if ( !ecf_home.empty() && fs::exists( ecf_home ) && fs::is_directory( ecf_home ) ) {
+
+ std::string manFile = File::backwardSearch( ecf_home, node->absNodePath(), File::MAN_EXTN());
+ EcfFile the_file(node.get(), manFile);
+ the_file.manual(fileContents); // pre-process & extract manual: will throw std::runtime_error for errors
+ }
+ else {
+ std::string errorMsg = "Failed to find the manual for Suite/Family "; errorMsg += pathToNode_;
+ errorMsg += " ECF_HOME directory does not exist and/or ECF_FILES not defined or directory does not exist.";
+ throw std::runtime_error( errorMsg ) ;
+ }
+ }
+ }
+ else {
+ std::stringstream ss; ss << "Option " << CFileCmd::toString(file_) << " is only valid for tasks. ";
+ throw std::runtime_error( ss.str() ) ;
+ }
+ }
+
+ /// The file could get very large, hence truncate at the start
+ if (Str::truncate_at_start(fileContents, max_lines_)) {
+ std::stringstream ss;
+ ss << "\n# >>>>>>>> File truncated down to " << max_lines_ << ". Truncated from the end of the file <<<<<<<<<\n";
+ fileContents += ss.str();
+ }
+
+ return PreAllocatedReply::string_cmd(fileContents);
+}
+
+const char* CFileCmd::arg() { return CtsApi::fileArg();}
+const char* CFileCmd::desc() {
+ /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+ return "Return the chosen file. Select from [ script<default> | job | jobout | manual | kill | stat ]\n"
+ "By default will return the script.\n"
+ " arg1 = path to node\n"
+ " arg2 = (optional) [ script<default> | job | jobout | manual | kill | stat ]\n"
+ " kill will attempt to return output of ECF_KILL_CMD, i.e the file %ECF_JOB%.kill\n"
+ " stat will attempt to return output of ECF_STATUS_CMD, i.e the file %ECF_JOB%.stat\n"
+ " arg3 = (optional) max_lines = 10000 <default>"
+ ;
+}
+
+void CFileCmd::addOption(boost::program_options::options_description& desc) const {
+ desc.add_options()( CFileCmd::arg(),po::value< vector<string> >()->multitoken(), CFileCmd::desc() );
+}
+void CFileCmd::create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* ac) const
+{
+ vector<string> args = vm[ arg() ].as< vector<string> >();
+
+ if (ac->debug()) dumpVecArgs(CFileCmd::arg(),args);
+
+ if (args.size() < 1 ) {
+ std::stringstream ss;
+ ss << "CFileCmd: At least one arguments expected for File. Found " << args.size() << "\n" << CFileCmd::desc() << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+
+ std::string pathToNode = args[0];
+
+ std::string file_type = "script";
+ if (args.size() >= 2) {
+ file_type = args[1];
+ }
+
+ std::string max_lines;
+ if (args.size() == 3) {
+ max_lines = args[2];
+ }
+
+ cmd = Cmd_ptr( new CFileCmd(pathToNode, file_type, max_lines) );
+}
+
+std::ostream& operator<<(std::ostream& os, const CFileCmd& c) { return c.print(os); }
+
diff --git a/Base/src/cts/CSyncCmd.cpp b/Base/src/cts/CSyncCmd.cpp
new file mode 100644
index 0000000..353b62b
--- /dev/null
+++ b/Base/src/cts/CSyncCmd.cpp
@@ -0,0 +1,160 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #22 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include "ClientToServerCmd.hpp"
+#include "AbstractServer.hpp"
+#include "AbstractClientEnv.hpp"
+#include "CtsApi.hpp"
+#include "Defs.hpp"
+#include "Log.hpp"
+#include "Ecf.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+namespace po = boost::program_options;
+
+std::ostream& CSyncCmd::print(std::ostream& os) const
+{
+ /// Note: Be careful how the *debug* output is interpreted, since the:
+ /// client_handle_ > 0 state/modify numbers will be for a set of registered suites,
+ /// client_handle_ == 0 state/modify numbers is global i.e. for all suites.
+ std::stringstream ss;
+ if (api_ == CSyncCmd::NEWS) {
+ ss << CtsApi::to_string(CtsApi::news(client_handle_,client_state_change_no_,client_modify_change_no_));
+ return user_cmd(os,ss.str());
+ }
+
+ if (api_ == CSyncCmd::SYNC) {
+ ss << CtsApi::to_string(CtsApi::sync(client_handle_,client_state_change_no_,client_modify_change_no_));
+ return user_cmd(os,ss.str());
+ }
+
+ ss << CtsApi::sync_full(client_handle_);
+ return user_cmd(os,ss.str());
+}
+
+bool CSyncCmd::equals(ClientToServerCmd* rhs) const
+{
+ CSyncCmd* the_rhs = dynamic_cast< CSyncCmd* > ( rhs );
+ if ( !the_rhs ) return false;
+ if (api_ != the_rhs->api()) return false;
+ if (client_handle_ != the_rhs->client_handle()) return false;
+ if (client_state_change_no_ != the_rhs->client_state_change_no()) return false;
+ if (client_modify_change_no_ != the_rhs->client_modify_change_no()) return false;
+ return UserCmd::equals(rhs);
+}
+
+const char* CSyncCmd::theArg() const
+{
+ if (api_ == CSyncCmd::NEWS) return CtsApi::newsArg();
+ if (api_ == CSyncCmd::SYNC) return CtsApi::syncArg();
+ return CtsApi::sync_full_arg();
+}
+
+int CSyncCmd::timeout() const
+{
+ if (api_ == CSyncCmd::SYNC || api_ == CSyncCmd::SYNC_FULL) {
+ return time_out_for_load_sync_and_get();
+ }
+ return 20; // CSyncCmd::NEWS
+}
+
+void CSyncCmd::do_log(AbstractServer* as) const
+{
+ if (api_ == CSyncCmd::NEWS) {
+
+ /// Log without adding a new line, to the log file
+ /// The SNewsCmd will append additional debug and then add new line
+ std::stringstream ss;
+ print(ss); // Populate the stream with command details:
+ bool ok = log_no_newline(Log::MSG,ss.str()); // log command without adding newline
+ if (!ok && as->defs()) {
+ // problems writing to log file, warn user ECFLOW-536
+ as->defs()->flag().set(ecf::Flag::LATE);
+ }
+ return;
+ }
+
+ ClientToServerCmd::do_log(as);
+}
+
+STC_Cmd_ptr CSyncCmd::doHandleRequest(AbstractServer* as) const
+{
+ // If no defs not loaded, SSyncCmd and SNewsCmd do nothing. This is a valid state, hence don't error for this request
+ if (api_ == CSyncCmd::NEWS) {
+ as->update_stats().news_++;
+ return PreAllocatedReply::news_cmd(client_handle_, client_state_change_no_, client_modify_change_no_,as);
+ }
+ if (api_ == CSyncCmd::SYNC) {
+ as->update_stats().sync_++;
+ return PreAllocatedReply::sync_cmd(client_handle_, client_state_change_no_, client_modify_change_no_,as);
+ }
+ as->update_stats().sync_++;
+ return PreAllocatedReply::sync_full_cmd(client_handle_,as);
+}
+
+void CSyncCmd::addOption(boost::program_options::options_description& desc) const
+{
+ if (api_ == CSyncCmd::NEWS) {
+ desc.add_options()(CtsApi::newsArg(),po::value< vector<unsigned int> >()->multitoken(),
+ "Returns true if state of server definition changed.\n"
+ "*Important* for use with c++/python interface only.\n"
+ "Requires Given a client handle, change and modify number determine if server changed since last call\n"
+ "This relies on user calling sync after news to update the locally stored modify and change numbers.\n"
+ "These numbers are then used in the next call to news."
+ );
+ return;
+ }
+
+ if (api_ == CSyncCmd::SYNC) {
+ desc.add_options()(CtsApi::syncArg(),po::value< vector<unsigned int> >()->multitoken(),
+ "Incrementally synchronise the local definition with the one in the server.\n"
+ "*Important* for use with c++/python interface only.\n"
+ "Preference should be given to this method as only the changes are returned.\n"
+ "This reduces the network bandwidth required to keep in sync with the server\n"
+ "Requires a client handle, change and modify number, to get the incremental changes from server.\n"
+ "The change in server state is then and merged with the client definition."
+ );
+ return;
+ }
+
+ desc.add_options()(CtsApi::sync_full_arg(),po::value< unsigned int >(),
+ "Returns the full definition from the server.\n"
+ "*Important* for use with c++/python interface only.\n"
+ "Requires a client_handle. The returned definition is stored on the client."
+ );
+}
+
+void CSyncCmd::create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* ac ) const
+{
+ if (ac->debug()) cout << " CSyncCmd::create api = '" << api_ << "'.\n";
+
+ if (api_ == CSyncCmd::NEWS || api_ == CSyncCmd::SYNC){
+ vector<unsigned int> args = vm[ theArg() ].as< vector<unsigned int> >();
+ if (args.size() != 3) throw std::runtime_error("CSyncCmd::create(SYNC/NEWS) expects 3 integer arguments, Client handle, state change number, and modify change number");
+ unsigned int client_handle = args[0];
+ unsigned int state_change_no = args[1];
+ unsigned int modify_change_no = args[2];
+ cmd = Cmd_ptr(new CSyncCmd( api_,client_handle,state_change_no,modify_change_no));
+ return;
+ }
+
+ unsigned int client_handle = vm[ theArg() ].as< unsigned int >();
+ cmd = Cmd_ptr(new CSyncCmd(client_handle)); // FULL_SYNC
+}
+
+std::ostream& operator<<(std::ostream& os, const CSyncCmd& c) { return c.print(os); }
diff --git a/Base/src/cts/CheckPtCmd.cpp b/Base/src/cts/CheckPtCmd.cpp
new file mode 100644
index 0000000..2f18f93
--- /dev/null
+++ b/Base/src/cts/CheckPtCmd.cpp
@@ -0,0 +1,203 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/lexical_cast.hpp>
+
+#include "ClientToServerCmd.hpp"
+#include "AbstractServer.hpp"
+#include "AbstractClientEnv.hpp"
+#include "CtsApi.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+namespace po = boost::program_options;
+
+std::ostream& CheckPtCmd::print(std::ostream& os) const
+{
+ return user_cmd(os,CtsApi::checkPtDefs(mode_,check_pt_interval_,check_pt_save_time_alarm_));
+}
+
+bool CheckPtCmd::equals(ClientToServerCmd* rhs) const
+{
+ CheckPtCmd* the_rhs = dynamic_cast< CheckPtCmd* > ( rhs );
+ if ( !the_rhs ) return false;
+ if (mode_ != the_rhs->mode()) return false;
+ if (check_pt_interval_ != the_rhs->check_pt_interval()) return false;
+ if (check_pt_save_time_alarm_ != the_rhs->check_pt_save_time_alarm()) return false;
+ return UserCmd::equals(rhs);
+}
+
+bool CheckPtCmd::isWrite() const
+{
+ // TODO: if save to takes to long, the the late flag is set. Even when command is read only ?
+ if (mode_ != ecf::CheckPt::UNDEFINED) return true;
+ if (check_pt_interval_ != 0) return true;
+ if (check_pt_save_time_alarm_ != 0) return true;
+ return false;
+}
+
+const char* CheckPtCmd::theArg() const
+{
+ return CtsApi::checkPtDefsArg();
+}
+
+STC_Cmd_ptr CheckPtCmd::doHandleRequest(AbstractServer* as) const
+{
+ // Placed here rather than in server. Since we want to record explicit request to check pt
+ // The update_stats() is used to record the number of requests per second, hence we do not
+ // want to skew this, and hence we ignore implicit request's via signal handling,
+ // or when server terminates( does implicit check pt also)
+ as->update_stats().checkpt_++;
+ as->checkPtDefs(mode_,check_pt_interval_,check_pt_save_time_alarm_);
+ return PreAllocatedReply::ok_cmd();
+}
+
+static const char* arg_desc()
+{
+ /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+ return
+ "Forces the definition file in the server to be written to disk *or* allow mode,\n"
+ "interval and alarm to be changed.\n"
+ "Whenever the check pt file is written to disk, it is measured.\n"
+ "If the time to save to disk is greater than the default of 30 seconds,\n"
+ "then an alarm is raised. This can be seen in the GUI as a late flag on the server.\n"
+ "Once the late flag has been set it will need to manually cleared in the GUI\n"
+ "or by using --alter functionality\n"
+ "Note excessive save times can interfere with job scheduling.\n"
+ "The alarm threshold can be changed. See below.\n"
+ " arg1 = (optional) mode [ never | on_time | on_time:<integer> | always | <integer>]\n"
+ " never : Never check point the definition in the server\n"
+ " on_time : Turn on automatic check pointing at interval stored on server\n"
+ " on_time<integer> : Turn on automatic check point, with the specified interval in seconds\n"
+ " alarm<integer> : Modify the alarm notification time for check pt saving to disk\n"
+ " always : Check point at any change in node tree, *NOT* recommended for large definitions\n"
+ " <integer> : This specifies the interval in seconds when server should automatically check pt.\n"
+ " This will only take effect of mode is on_time/CHECK_ON_TIME\n"
+ " Should ideally be a value greater than 60 seconds, default is 120 seconds\n"
+ "Usage:\n"
+ " --check_pt\n"
+ " Immediately check point the definition held in the server\n"
+ " --check_pt=never\n"
+ " Switch off check pointing\n"
+ " --check_pt=on_time\n"
+ " Start automatic check pointing at the interval stored in the server\n"
+ " --check_pt=180\n"
+ " Change the check pt interval to 180 seconds\n"
+ " --check_pt=on_time:90\n"
+ " Change mode and interval, to automatic check pointing every 90 seconds\n"
+ " --check_pt=alarm:35\n"
+ " Change the alarm time for check pt saves. i.e if saving the check pt takes longer than 35 seconds\n"
+ " set the late flag on the server."
+ ;
+}
+
+void CheckPtCmd::addOption(boost::program_options::options_description& desc) const
+{
+ desc.add_options()(CtsApi::checkPtDefsArg(),po::value< string >()->implicit_value( string("") ),arg_desc());
+}
+
+static int parse_check_pt_interval( const std::string& the_arg)
+{
+ int check_pt_interval = 0;
+ try { check_pt_interval = boost::lexical_cast<int>(the_arg); }
+ catch (...) {
+ std::stringstream ss;
+ ss << "check_pt: Illegal argument(" << the_arg << "), expected [ never | on_time | on_time:<integer> | always | <integer>]\n" << arg_desc();
+ throw std::runtime_error(ss.str());
+ }
+ if (check_pt_interval <= 0) {
+ std::stringstream ss;
+ ss << "check_pt: interval(" << check_pt_interval << ") must be greater than zero :\n" << arg_desc();
+ throw std::runtime_error(ss.str());
+ }
+ return check_pt_interval;
+}
+
+static int parse_check_pt_alarm_time( const std::string& the_arg, int colon_pos)
+{
+ std::string alarm_time = the_arg.substr(colon_pos+1);
+
+ int check_pt_alarm_time = 0;
+ try { check_pt_alarm_time = boost::lexical_cast<int>(alarm_time); }
+ catch (...) {
+ std::stringstream ss;
+ ss << "check_pt: Illegal argument(" << the_arg << "), expected [ never | on_time | on_time:<integer> | alarm::integer> | always | <integer>]\n" << arg_desc();
+ throw std::runtime_error(ss.str());
+ }
+ if (check_pt_alarm_time <= 0) {
+ std::stringstream ss;
+ ss << "check_pt: alarm time(" << check_pt_alarm_time << ") must be greater than zero :\n" << arg_desc();
+ throw std::runtime_error(ss.str());
+ }
+ return check_pt_alarm_time;
+}
+
+
+void CheckPtCmd::create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* ace ) const
+{
+ if (ace->debug()) cout << "CheckPtCmd::create\n";
+
+ std::string the_arg = vm[ theArg() ].as< std::string > ();
+
+ if (ace->debug()) cout << " CheckPtCmd::create arg = " << the_arg << "\n";
+
+ ecf::CheckPt::Mode m = ecf::CheckPt::UNDEFINED;
+ int check_pt_interval = 0;
+ int check_pt_save_time_alarm = 0;
+
+ if (!the_arg.empty()) {
+ size_t colon_pos = the_arg.find(":");
+ if (colon_pos != std::string::npos) {
+ // could be mode:interval or alarm:integer
+ if (the_arg.find("alarm") != std::string::npos) {
+ check_pt_save_time_alarm = parse_check_pt_alarm_time(the_arg,colon_pos);
+ }
+ else {
+ std::string mode = the_arg.substr(0,colon_pos);
+ std::string interval = the_arg.substr(colon_pos+1);
+
+ if (mode == "never") m = ecf::CheckPt::NEVER;
+ else if (mode == "on_time") m = ecf::CheckPt::ON_TIME;
+ else if (mode == "always") m = ecf::CheckPt::ALWAYS;
+ else {
+ std::stringstream ss;
+ ss << "check_pt: Illegal argument(" << the_arg << "), expected [ never | on_time | on_time:<integer> | alarm:<integer> | always | <integer>]\n" << arg_desc();
+ throw std::runtime_error(ss.str());
+ }
+ check_pt_interval = parse_check_pt_interval(interval);
+ }
+ }
+ else {
+ if (the_arg == "never") m = ecf::CheckPt::NEVER;
+ else if (the_arg == "on_time") m = ecf::CheckPt::ON_TIME;
+ else if (the_arg == "always") m = ecf::CheckPt::ALWAYS;
+ else {
+ check_pt_interval = parse_check_pt_interval(the_arg);
+ }
+ }
+ }
+
+ // testing client interface
+ if (ace->under_test()) return;
+
+ if (ace->debug()) cout << " CheckPtCmd::create mode = " << m << " check_pt_interval = " << check_pt_interval << "\n";
+
+ cmd = Cmd_ptr(new CheckPtCmd(m,check_pt_interval,check_pt_save_time_alarm));
+}
+
+std::ostream& operator<<(std::ostream& os, const CheckPtCmd& c) { return c.print(os); }
diff --git a/Base/src/cts/ClientHandleCmd.cpp b/Base/src/cts/ClientHandleCmd.cpp
new file mode 100644
index 0000000..d646b38
--- /dev/null
+++ b/Base/src/cts/ClientHandleCmd.cpp
@@ -0,0 +1,331 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #31 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/lexical_cast.hpp>
+
+#include "ClientToServerCmd.hpp"
+#include "AbstractServer.hpp"
+#include "AbstractClientEnv.hpp"
+#include "CtsApi.hpp"
+#include "Defs.hpp"
+#include "Log.hpp"
+#include "Ecf.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+namespace po = boost::program_options;
+
+/// *****************************************************************************
+/// Note: The Client Handle commands, change the server,
+/// However the changes cant really be considered as incremental
+/// Hence for all handle command, we will do a FULL SYNC
+/// Relying on the modify_change_no is to CRUDE, as it affects all handles
+/// Instead we will use a simple flag to indicate that a FULL sync is required
+/// *****************************************************************************
+
+std::ostream& ClientHandleCmd::print(std::ostream& os) const
+{
+ switch (api_) {
+ case ClientHandleCmd::REGISTER: return user_cmd(os,CtsApi::to_string(CtsApi::ch_register(auto_add_new_suites_,suites_))); break;
+ case ClientHandleCmd::DROP: return user_cmd(os,CtsApi::ch_drop(client_handle_)); break;
+ case ClientHandleCmd::DROP_USER:{
+ if (drop_user_.empty()) return user_cmd(os,CtsApi::ch_drop_user(user()));
+ return user_cmd(os,CtsApi::ch_drop_user(drop_user_));
+ break;
+ }
+ case ClientHandleCmd::ADD: return user_cmd(os,CtsApi::to_string(CtsApi::ch_add(client_handle_,suites_))); break;
+ case ClientHandleCmd::REMOVE: return user_cmd(os,CtsApi::to_string(CtsApi::ch_remove(client_handle_,suites_))); break;
+ case ClientHandleCmd::AUTO_ADD: return user_cmd(os,CtsApi::to_string(CtsApi::ch_auto_add(client_handle_,auto_add_new_suites_))); break;
+ case ClientHandleCmd::SUITES: return user_cmd(os,CtsApi::ch_suites()); break;
+ default: assert(false); break;
+ }
+ return os;
+}
+
+bool ClientHandleCmd::equals(ClientToServerCmd* rhs) const
+{
+ ClientHandleCmd* the_rhs = dynamic_cast< ClientHandleCmd* > ( rhs );
+ if ( !the_rhs ) return false;
+ if (api_ != the_rhs->api()) return false;
+ if (drop_user_ != the_rhs->drop_user()) return false;
+ return UserCmd::equals(rhs);
+}
+
+const char* ClientHandleCmd::theArg() const
+{
+ switch (api_) {
+ case ClientHandleCmd::REGISTER: return CtsApi::ch_register_arg(); break;
+ case ClientHandleCmd::DROP: return CtsApi::ch_drop_arg(); break;
+ case ClientHandleCmd::DROP_USER: return CtsApi::ch_drop_user_arg(); break;
+ case ClientHandleCmd::ADD: return CtsApi::ch_add_arg(); break;
+ case ClientHandleCmd::REMOVE: return CtsApi::ch_remove_arg(); break;
+ case ClientHandleCmd::AUTO_ADD: return CtsApi::ch_auto_add_arg(); break;
+ case ClientHandleCmd::SUITES: return CtsApi::ch_suites_arg(); break;
+ }
+ assert(false);
+ return NULL;
+}
+
+STC_Cmd_ptr ClientHandleCmd::doHandleRequest(AbstractServer* as) const
+{
+ as->update_stats().ch_cmd_++;
+
+ switch (api_) {
+ case ClientHandleCmd::REGISTER: {
+
+ unsigned int client_handle = as->defs()->client_suite_mgr().create_client_suite(auto_add_new_suites_,suites_,user());
+//#ifdef DEBUG
+// LOG(Log::DBG,as->defs()->client_suite_mgr().dump_max_change_no());
+//#endif
+ // return the handle to the client
+ return PreAllocatedReply::client_handle_cmd(client_handle) ;
+ }
+
+ case ClientHandleCmd::DROP: {
+ as->defs()->client_suite_mgr().remove_client_suite(client_handle_); // will throw if handle not found
+
+ // return the 0 handle to the client. The client stores the handle locally. Reset to zero.
+ return PreAllocatedReply::client_handle_cmd(0) ;
+ }
+
+ case ClientHandleCmd::DROP_USER: {
+ // will throw if no users handles dropped
+ if (drop_user_.empty()) as->defs()->client_suite_mgr().remove_client_suites(user());
+ else as->defs()->client_suite_mgr().remove_client_suites(drop_user_);
+
+ if (drop_user_.empty() || drop_user_ == user()) {
+ // return the 0 handle to the client. The client stores the handle locally. Reset to zero.
+ return PreAllocatedReply::client_handle_cmd(0) ;
+ }
+ break;
+ }
+
+ case ClientHandleCmd::ADD: {
+ as->defs()->client_suite_mgr().add_suites(client_handle_,suites_); // will throw if handle not found
+ break;
+ }
+
+ case ClientHandleCmd::REMOVE: {
+ as->defs()->client_suite_mgr().remove_suites(client_handle_,suites_); // will throw if handle not found
+ break;
+ }
+
+ case ClientHandleCmd::AUTO_ADD: {
+ as->defs()->client_suite_mgr().auto_add_new_suites(client_handle_,auto_add_new_suites_); // will throw if handle not found
+ break;
+ }
+
+ case ClientHandleCmd::SUITES: {
+ return PreAllocatedReply::client_handle_suites_cmd(as) ;
+ break;
+ }
+
+ default: assert(false); break;
+
+ }
+ return PreAllocatedReply::ok_cmd();
+}
+
+void ClientHandleCmd::addOption(boost::program_options::options_description& desc) const
+{
+ switch (api_) {
+ case ClientHandleCmd::REGISTER:{
+ desc.add_options()(CtsApi::ch_register_arg(), po::value< vector<string> >()->multitoken(),
+ "Register interest in a set of suites.\n"
+ "If a definition has lots of suites, but the client. is only interested in a small subset,\n"
+ "Then using this command can reduce network bandwidth and synchronisation will be quicker.\n"
+ "This command will create a client handle, which must be used for any other changes.\n"
+ "The newly created handle can be shown with the --suites command\n"
+ "Deleted suites will stay registered, and must be explicitly removed/dropped.\n"
+ "Note: Suites can be registered before they are loaded into the server\n"
+ "This option affects news() and sync() commands\n"
+ " arg1 = true | false # true means add new suites to my list, when they are created\n"
+ " arg2 = names # should be a list of suite names, names not in the definition are ignored\n"
+ "Usage:\n"
+ " --ch_register=true s1 s2 s3 # register interest in suites s1,s2,s3 and any new suites\n"
+ " --ch_register=false s1 s2 s3 # register interest in suites s1,s2,s3 only\n"
+ " --ch_register=false # register handle, suites will be added later on\n"
+ "To list all suites and handles use --suites"
+ );
+ break;
+ }
+
+ case ClientHandleCmd::DROP:{
+ desc.add_options()(CtsApi::ch_drop_arg(), po::value< int >(),
+ "Drop/de-register the client handle.\n"
+ "Un-used handle should be dropped otherwise they will stay, in the server.\n"
+ " arg1 = handle(integer) # The handle must be an integer that is > 0\n"
+ "Usage:\n"
+ " --ch_drop=10 # drop the client handle 10\n"
+ "An error is returned if the handle had not previously been registered\n"
+ "The handle stored on the local client is set to zero\n"
+ "To list all suites and handles use --suites"
+ );
+ break;
+ }
+
+ case ClientHandleCmd::DROP_USER:{
+ desc.add_options()(CtsApi::ch_drop_user_arg(), po::value<std::string >()->implicit_value( string("")),
+ "Drop/de-register all handles associated with the given user.\n"
+ "If no user provided will drop for current user. Client must ensure un-used handle are dropped\n"
+ "otherwise they will stay, in the server.\n"
+ " arg1 = user # The user to be drooped, if left empty drop current user \n"
+ "Usage:\n"
+ " --ch_drop_user=ma0 # drop all handles associated with user ma0\n"
+ " --ch_drop_user # drop all handles associated with current user\n"
+ "An error is returned if no registered handles\n"
+ "To list all suites and handles use --suites"
+ );
+ break;
+ }
+
+ case ClientHandleCmd::ADD:{
+ desc.add_options()( CtsApi::ch_add_arg(), po::value< vector<string> >()->multitoken(),
+ "Add a set of suites, to an existing handle.\n"
+ " arg1 = handle(integer) # The handle must be an integer that is > 0\n"
+ " arg2 = names # should be a list of suite names, names not in the definition are ignored\n"
+ "Usage:\n"
+ " --ch_add=10 s2 s3 s4 # add suites s2 s3,s4 to handle 10\n"
+ "An error is returned if the handle had not previously been registered\n"
+ "The handle is created with --ch_register command\n"
+ "To list all suites and handles use --suites"
+ );
+ break;
+ }
+
+ case ClientHandleCmd::REMOVE:{
+ desc.add_options()( CtsApi::ch_remove_arg(), po::value< vector<string> >()->multitoken(),
+ "Remove a set of suites, from an existing handle.\n"
+ " arg1 = handle(integer) # The handle must be an integer that is > 0\n"
+ " arg2 = names # should be a list of suite names, names not in the definition are ignored\n"
+ "Usage:\n"
+ " --ch_rem=10 s2 s3 s4 # remove suites s2 s3,s4 from handle 10\n"
+ "The handle is created with --ch_register command\n"
+ "To list all suites and handles use --suites"
+ );
+ break;
+ }
+
+ case ClientHandleCmd::AUTO_ADD: {
+ desc.add_options()( CtsApi::ch_auto_add_arg(), po::value< vector<string> >()->multitoken(),
+ "Change an existing handle so that new suites can be added automatically.\n"
+ " arg1 = handle(integer) # The handle must be an integer that is > 0\n"
+ " arg2 = true | false # true means add new suites to my list, when they are created\n"
+ "Usage:\n"
+ " --ch_auto_add=10 true # modify handle 10 so that new suites, get added automatically to it\n"
+ " --ch_auto_add=10 false # modify handle 10 so that no new suites are added\n"
+ "The handle is created with --ch_register command\n"
+ "To list all suites and handles use --suites"
+ );
+ break;
+ }
+
+ case ClientHandleCmd::SUITES:{
+ desc.add_options()(CtsApi::ch_suites_arg(),
+ "Shows all the client handles, and the suites they reference"
+ );
+ break;
+ }
+ default: assert(false); break;
+ }
+}
+
+void ClientHandleCmd::create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* ac ) const
+{
+ if (ac->debug()) cout << " ClientHandleCmd::create api = '" << api_ << "'.\n";
+
+ switch (api_) {
+
+ case ClientHandleCmd::REGISTER: {
+ vector<string> args = vm[ theArg() ].as< vector<string> >();
+ // args can be empty, otherwise first arg must be bool, true or false, subsequent args represent suite names
+ bool auto_add_new_suites = false;
+ std::vector<std::string> suite_names; suite_names.reserve( args.size() );
+ if (!args.empty()) {
+ if (args[0] == "true") auto_add_new_suites = true;
+ else if (args[0] == "false") auto_add_new_suites = false;
+ else throw std::runtime_error("ClientHandleCmd::create: First argument should be true | false. See help");
+ for(size_t i = 1; i < args.size(); i++) { suite_names.push_back( args[i] ); }
+ }
+ cmd = Cmd_ptr(new ClientHandleCmd( suite_names, auto_add_new_suites ));
+ break;
+ }
+
+ case ClientHandleCmd::DROP: {
+ int client_handle = vm[ theArg() ].as< int >();
+ if ( 0 == client_handle) throw std::runtime_error("ClientHandleCmd::create: handles must have a value > 0");
+ cmd = Cmd_ptr(new ClientHandleCmd( client_handle ));
+ break;
+ }
+
+ case ClientHandleCmd::DROP_USER: {
+ std::string the_user_to_drop = vm[ theArg() ].as< std::string >();
+ cmd = Cmd_ptr(new ClientHandleCmd( the_user_to_drop ));
+ break;
+ }
+
+ case ClientHandleCmd::ADD: {
+ vector<string> args = vm[ theArg() ].as< vector<string> >();
+ if (args.size() < 2) throw std::runtime_error("To few arguments. First arg should be a integer handle, then a list of suite names. See help");
+ int client_handle = 0;
+ try { client_handle = boost::lexical_cast<int>( args[0]); }
+ catch (std::exception& ) { throw std::runtime_error("The first argument must be an integer. See help"); }
+ if (0 == client_handle) throw std::runtime_error("ClientHandleCmd::create: handles must have a value > 0");
+ std::vector<std::string> suite_names; suite_names.reserve( args.size() );
+ for(size_t i = 1; i < args.size(); i++) { suite_names.push_back( args[i] ); }
+ cmd = Cmd_ptr(new ClientHandleCmd(client_handle, suite_names, ClientHandleCmd::ADD ));
+ break;
+ }
+
+ case ClientHandleCmd::REMOVE: {
+ vector<string> args = vm[ theArg() ].as< vector<string> >();
+ if (args.size() < 2) throw std::runtime_error("To few arguments. First arg should be a integer handle, then a list of suite names. See help");
+ int client_handle = 0;
+ try { client_handle = boost::lexical_cast<int>( args[0]); }
+ catch (std::exception& ) { throw std::runtime_error("ClientHandleCmd::create: The first argument must be an integer. See help"); }
+ if ( 0 == client_handle ) throw std::runtime_error("ClientHandleCmd::create: handles must have a value > 0");
+ std::vector<std::string> suite_names; suite_names.reserve( args.size() );
+ for(size_t i = 1; i < args.size(); i++) { suite_names.push_back( args[i] ); }
+ cmd = Cmd_ptr(new ClientHandleCmd(client_handle, suite_names, ClientHandleCmd::REMOVE ));
+ break;
+ }
+
+ case ClientHandleCmd::AUTO_ADD: {
+ vector<string> args = vm[ theArg() ].as< vector<string> >();
+ if (args.size() != 2) throw std::runtime_error("Two argument expected. First arg should be a integer handle, second should be true or false. See help");
+ int client_handle = 0;
+ try { client_handle = boost::lexical_cast<int>( args[0]); }
+ catch (std::exception& ) { throw std::runtime_error("ClientHandleCmd::create: The first argument must be an integer. See help"); }
+ if ( 0 == client_handle ) throw std::runtime_error("ClientHandleCmd::create: handles must have a value > 0");
+ bool auto_add_new_suites = false;
+ if (args[1] == "true") auto_add_new_suites = true;
+ else if (args[1] == "false") auto_add_new_suites = false;
+ else throw std::runtime_error("ClientHandleCmd::create: First argument should be true | false. See help");
+ cmd = Cmd_ptr(new ClientHandleCmd(client_handle, auto_add_new_suites ));
+ break;
+ }
+
+ case ClientHandleCmd::SUITES: {
+ cmd = Cmd_ptr(new ClientHandleCmd( ClientHandleCmd::SUITES ));
+ break;
+ }
+
+ default: assert(false); break;
+ }
+}
+
+std::ostream& operator<<(std::ostream& os, const ClientHandleCmd& c) { return c.print(os); }
diff --git a/Base/src/cts/ClientToServerCmd.cpp b/Base/src/cts/ClientToServerCmd.cpp
new file mode 100644
index 0000000..e11aa8a
--- /dev/null
+++ b/Base/src/cts/ClientToServerCmd.cpp
@@ -0,0 +1,206 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #67 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <iostream>
+#include <sstream>
+
+#include "ClientToServerCmd.hpp"
+#include "ServerToClientCmd.hpp"
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "Alias.hpp"
+
+#include "JobsParam.hpp"
+#include "Jobs.hpp"
+#include "AbstractServer.hpp"
+#include "Log.hpp"
+#include "Str.hpp"
+#include "CmdContext.hpp"
+#include "EditHistoryMgr.hpp"
+
+using namespace std;
+using namespace boost;
+using namespace ecf;
+
+//#define DEBUG_INVARIANTS 1
+
+ClientToServerCmd::~ClientToServerCmd(){}
+
+STC_Cmd_ptr ClientToServerCmd::handleRequest(AbstractServer* as) const
+{
+ // Allow creating of new time stamp, when *not* in a command. i.e during node tree traversal in server
+ CmdContext cmdContext;
+
+ // Create the log time stamp once for a given request
+ if (Log::instance()) Log::instance()->cache_time_stamp();
+
+ // LOG the command, *BEFORE* invoking it. (i.e in case server hangs/crashes)
+ // Allow override in the rare cases, where we want to output additional debug
+ // If logging fails set late flag to warn users, ECFLOW-536
+ do_log(as);
+
+#ifdef DEBUG_INVARIANTS
+ LOG_ASSERT( as->defs() , "ClientToServerCmd::handleRequest: Start: No defs? ");
+ std::string errmsg;
+ if (!as->defs()->checkInvariants(errmsg)) {
+ LOG(Log::ERR,"ClientToServerCmd::handleRequest: PreCondition: Failed invariant checking:" << errmsg);
+ }
+#endif
+
+
+ STC_Cmd_ptr halted;
+ if (! authenticate(as,halted)) {
+ assert (halted.get());
+ return halted;
+ }
+
+ // mark edited nodes, with edit history. relies on doHandleRequest to populate edit_history_nodes_/paths
+ // hence must at the same scope level
+ EditHistoryMgr edit_history_mgr(this,as);
+
+ // Handle the request, and return the reply back to the client
+ STC_Cmd_ptr server_to_client_ptr = doHandleRequest(as);
+ if ( isWrite() && server_to_client_ptr->ok()) {
+
+ // This can end up, check pointing the defs file
+ as->nodeTreeStateChanged();
+ }
+
+#ifdef DEBUG_INVARIANTS
+ LOG_ASSERT( as->defs() , "ClientToServerCmd::handleRequest: End: No defs? ");
+ std::string errmsg;
+ if (!as->defs()->checkInvariants(errmsg)) {
+ LOG(Log::ERR,"ClientToServerCmd::handleRequest: PostCondition: Failed invariant checking:" << errmsg);
+ }
+#endif
+
+ return server_to_client_ptr;
+}
+
+void ClientToServerCmd::do_log(AbstractServer* as) const
+{
+ std::stringstream ss;
+ print(ss); // Populate the stream with command details:
+ if (!log(Log::MSG,ss.str())) { // will automatically add end of line
+ // problems writing to log file, warn users, ECFLOW-536
+ if (as->defs()) {
+ as->defs()->flag().set(ecf::Flag::LATE);
+ }
+ }
+}
+
+STC_Cmd_ptr ClientToServerCmd::doJobSubmission(AbstractServer* as)
+{
+ // This function could be called at the end of *USER* command that can change state.
+ //
+ // We could have other tasks/jobs dependent on the state change. i.e end of time series
+ // This will traverse the node tree and resolve dependencies and may force
+ // Other jobs to be generated, due to the state change.
+ // However *** errors in job submission ***, should *NOT* typically abort the command.
+ // Since we will typically just set task to aborted state
+
+ // This job generation will timeout if job generation takes longer than next poll time.
+ as->traverse_node_tree_and_job_generate(Calendar::second_clock_time(), true /* user cmd context */);
+
+ return PreAllocatedReply::ok_cmd();
+}
+
+node_ptr ClientToServerCmd::find_node(AbstractServer* as, const std::string& absNodepath) const
+{
+ node_ptr theNode = as->defs()->findAbsNode(absNodepath);
+ if ( !theNode.get() ) {
+
+ std::stringstream ss;
+ print(ss);
+
+ std::string errorMsg = "Can not find node at path '";
+ errorMsg += absNodepath;
+ errorMsg += "' ";
+ errorMsg += ss.str();
+ errorMsg += " failed";
+ throw std::runtime_error( errorMsg) ;
+ }
+ return theNode;
+}
+
+
+void ClientToServerCmd::dumpVecArgs(const char* argOption, const std::vector<std::string>& args) {
+ cout << " " << argOption;
+ for(size_t i= 0; i < args.size(); i++) { cout << " args[" << i << "]='" << args[i] << "'";} cout << "\n";
+}
+
+node_ptr ClientToServerCmd::find_node_for_edit(AbstractServer* as, const std::string& absNodepath) const
+{
+ node_ptr theNode = find_node(as, absNodepath);
+ add_node_for_edit_history(theNode);
+ return theNode;
+}
+
+node_ptr ClientToServerCmd::find_node_for_edit_no_throw(AbstractServer* as, const std::string& absNodepath) const
+{
+ node_ptr theNode = as->defs()->findAbsNode(absNodepath);
+ add_node_for_edit_history(theNode);
+ return theNode;
+}
+
+void ClientToServerCmd::add_node_for_edit_history(AbstractServer* as,const std::string& absNodepath) const
+{
+ add_node_for_edit_history(as->defs()->findAbsNode(absNodepath));
+}
+
+void ClientToServerCmd::add_node_for_edit_history(node_ptr the_node) const
+{
+ if (the_node.get()) edit_history_nodes_.push_back(the_node);
+}
+
+void ClientToServerCmd::add_node_path_for_edit_history(const std::string& absNodepath) const
+{
+ edit_history_node_paths_.push_back(absNodepath);
+}
+
+BOOST_CLASS_EXPORT_IMPLEMENT(ServerVersionCmd)
+BOOST_CLASS_EXPORT_IMPLEMENT(CtsCmd)
+BOOST_CLASS_EXPORT_IMPLEMENT(CSyncCmd)
+BOOST_CLASS_EXPORT_IMPLEMENT(ClientHandleCmd)
+BOOST_CLASS_EXPORT_IMPLEMENT(CtsNodeCmd)
+BOOST_CLASS_EXPORT_IMPLEMENT(PathsCmd)
+BOOST_CLASS_EXPORT_IMPLEMENT(CheckPtCmd)
+BOOST_CLASS_EXPORT_IMPLEMENT(LoadDefsCmd)
+BOOST_CLASS_EXPORT_IMPLEMENT(LogCmd)
+BOOST_CLASS_EXPORT_IMPLEMENT(LogMessageCmd)
+BOOST_CLASS_EXPORT_IMPLEMENT(BeginCmd)
+BOOST_CLASS_EXPORT_IMPLEMENT(ZombieCmd)
+BOOST_CLASS_EXPORT_IMPLEMENT(InitCmd)
+BOOST_CLASS_EXPORT_IMPLEMENT(EventCmd)
+BOOST_CLASS_EXPORT_IMPLEMENT(MeterCmd)
+BOOST_CLASS_EXPORT_IMPLEMENT(LabelCmd)
+BOOST_CLASS_EXPORT_IMPLEMENT(AbortCmd)
+BOOST_CLASS_EXPORT_IMPLEMENT(CtsWaitCmd)
+BOOST_CLASS_EXPORT_IMPLEMENT(CompleteCmd)
+BOOST_CLASS_EXPORT_IMPLEMENT(RequeueNodeCmd)
+BOOST_CLASS_EXPORT_IMPLEMENT(OrderNodeCmd)
+BOOST_CLASS_EXPORT_IMPLEMENT(RunNodeCmd)
+BOOST_CLASS_EXPORT_IMPLEMENT(ReplaceNodeCmd)
+BOOST_CLASS_EXPORT_IMPLEMENT(ForceCmd)
+BOOST_CLASS_EXPORT_IMPLEMENT(FreeDepCmd)
+BOOST_CLASS_EXPORT_IMPLEMENT(CFileCmd)
+BOOST_CLASS_EXPORT_IMPLEMENT(EditScriptCmd)
+BOOST_CLASS_EXPORT_IMPLEMENT(PlugCmd)
+BOOST_CLASS_EXPORT_IMPLEMENT(AlterCmd)
+BOOST_CLASS_EXPORT_IMPLEMENT(MoveCmd)
+BOOST_CLASS_EXPORT_IMPLEMENT(GroupCTSCmd)
+BOOST_CLASS_EXPORT_IMPLEMENT(ShowCmd)
diff --git a/Base/src/cts/ClientToServerCmd.hpp b/Base/src/cts/ClientToServerCmd.hpp
new file mode 100644
index 0000000..bf5412a
--- /dev/null
+++ b/Base/src/cts/ClientToServerCmd.hpp
@@ -0,0 +1,1847 @@
+#ifndef CLIENT_TO_SERVER_CMD_HPP_
+#define CLIENT_TO_SERVER_CMD_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name : Cmd
+// Author : Avi
+// Revision : $Revision: #143 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <string>
+#include <vector>
+
+#include <boost/program_options.hpp>
+#include <boost/serialization/base_object.hpp> // base class serialization
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/assume_abstract.hpp>
+#include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/export.hpp> // explicit code for exports (place last) , needed for BOOST_CLASS_EXPORT
+
+#include "PrintStyle.hpp"
+#include "Cmd.hpp"
+#include "NodeFwd.hpp"
+#include "NOrder.hpp"
+#include "Zombie.hpp"
+#include "Flag.hpp"
+#include "Child.hpp"
+#include "CheckPt.hpp"
+#include "PreAllocatedReply.hpp"
+
+#if defined(_AIX) && !defined(DEBUG)
+// Required for MoveCmd for release mode of v11.1 compiler
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#endif
+
+class AbstractServer;
+class AbstractClientEnv;
+
+///////////////////////////////////////////////////////////////////////////////////
+// Client->Server cmd's
+///////////////////////////////////////////////////////////////////////////////////
+class ClientToServerCmd {
+public:
+ virtual ~ClientToServerCmd();
+
+ /// The second print is for use by EditHistoryMgr when we have commands that take multiple paths
+ /// The EditHistoryMgr records what command was applied to each node. However when logging the
+ /// the command we do not want logs all the paths, for each node.(performance bottleneck
+ /// when dealing with thousands of paths)
+ virtual std::ostream& print(std::ostream& os) const = 0;
+ virtual std::ostream& print(std::ostream& os, const std::string& path) const { return print(os); }
+
+ virtual bool equals(ClientToServerCmd* rhs) const = 0;
+
+ /// Called by the _server_ to service the client depending on the Command
+ /// The server will pass itself down via the AbstractServer
+ /// The returned Server to Client command is sent back to the client
+ /// Uses template pattern, it first authenticates request and then calls
+ /// doHandleRequest. This function can throw exceptions. std::runtime_error
+ STC_Cmd_ptr handleRequest(AbstractServer*) const;
+
+ /// Returns true if handleRequest is testable. Only used in TEST
+ virtual bool handleRequestIsTestable() const { return true ;}
+
+ /// How long in seconds the client to attempt to send request and get a reply back
+ /// before the request fails. This timeout affects the wait for the outward request
+ /// and inward reply.
+ ///
+ /// The timeout feature allow the client to fail gracefully in the case
+ /// where the server has died/crashed. The timeout will ensure the socket is closed.
+ /// allowing the server to be restarted without getting the address is use error.
+ ///
+ /// NOTE: We also have a timeout in ClientInvoker/ClientEnvironment, *that* is different,
+ /// as that applies to CHILD/task commands, and control how long we continue
+ /// to iterate over the hosts files
+ virtual int timeout() const { return 60; }
+
+ /// A command can be read only command or write only command
+ /// A read only command will not change the state of the suites in the server
+ /// A write only command can modify the state of suite in the server
+ /// Used by the server for authentication since only write only users are allowed to edit.
+ virtual bool isWrite() const { return false; /* returning false means read only */ }
+
+ /// This Must be called for client->server commands.As this is required
+ /// for authentication. *However* task based commands have their own authentication
+ /// mechanism, and don't need setup_user_authentification().
+ virtual void setup_user_authentification() = 0;
+
+ /// Allow control over connection to different servers/hosts if the main server is down
+ /// i.e for a getCmd, we do not want to wait 24 hours, trying all the servers
+ /// However for Task based commands like , init,abort,event, meter,complete we
+ /// want this behaviour as it can alter Node tree state and thus affect dependent nodes
+ virtual bool connect_to_different_servers() const { return false; }
+
+ /// The show occurs on the client side
+ virtual PrintStyle::Type_t show_style() const { return PrintStyle::NOTHING;}
+
+ // Other commands
+ virtual bool get_cmd() const { return false; }
+ virtual bool task_cmd() const { return false; }
+ virtual bool terminate_cmd() const { return false; }
+ virtual bool group_cmd() const { return false; }
+ virtual bool ping_cmd() const { return false;}
+ virtual bool why_cmd( std::string& ) const { return false;}
+ virtual bool show_cmd() const { return false ;}
+ virtual bool delete_all_cmd() const { return false ;}
+
+ // CLIENT side Parse and command construction, create can throw std::runtime_error for errors
+ virtual const char* theArg() const = 0; // used for argument parsing
+ virtual void addOption(boost::program_options::options_description& desc) const = 0;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv) const = 0;
+protected:
+ ClientToServerCmd() {}
+
+ /// called by handleRequest, part of the template pattern
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const = 0;
+
+ /// return true if authentication succeeds, false and STC_Cmd_ptr to return otherwise
+ /// This function is called from doHandleRequest and hence is called
+ /// from within the server. The default implementation will get the current
+ /// user and authenticate with reference to the white list file
+ virtual bool authenticate(AbstractServer*, STC_Cmd_ptr&) const = 0;
+
+ /// Log the command. Must typically be done before call doHandleRequest(), in case of crash/exception
+ /// In rare case allow override. (i.e for additional debug)
+ /// called by handleRequest, part of the template pattern
+ /// If logging fails set late flag to warn users ECFLOW-536
+ virtual void do_log(AbstractServer*) const;
+
+ /// Some commands which cause a change in state, should force an immediate job submission.
+ /// Providing the server is *NOT* shutdown
+ static STC_Cmd_ptr doJobSubmission(AbstractServer* as);
+
+ static void dumpVecArgs(const char* argOption, const std::vector<std::string>& args);
+
+ /// Find the node otherwise throw std:::runtime_error
+ node_ptr find_node(AbstractServer* as, const std::string& absNodepath) const;
+
+ /// Find The node for edit, otherwise throw std:::runtime_error
+ /// Will add the node edit history collection
+ node_ptr find_node_for_edit(AbstractServer* as, const std::string& absNodepath) const;
+
+ /// Find The node for edit, otherwise return a NULL pointer
+ /// Will add the node edit history collection
+ node_ptr find_node_for_edit_no_throw(AbstractServer* as, const std::string& absNodepath) const;
+
+ /// finds the associated node and adds to edit history nodes
+ void add_node_for_edit_history(AbstractServer* as, const std::string& absNodepath) const;
+ void add_node_for_edit_history(node_ptr) const;
+ void add_node_path_for_edit_history(const std::string& absNodepath) const;
+
+private:
+ friend class GroupCTSCmd;
+ friend class EditHistoryMgr;
+ mutable std::vector<weak_node_ptr> edit_history_nodes_; // NOT persisted
+ mutable std::vector<std::string> edit_history_node_paths_; // NOT persisted, used when deleting
+
+private:
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive &ar, const unsigned int /*version*/) {}
+};
+BOOST_SERIALIZATION_ASSUME_ABSTRACT(ClientToServerCmd)
+
+//=================================================================================
+// Task Commands
+// ================================================================================
+class TaskCmd : public ClientToServerCmd {
+protected:
+ TaskCmd( const std::string& pathToSubmittable,
+ const std::string& jobsPassword,
+ const std::string& process_or_remote_id,
+ int try_no)
+ : submittable_(0),path_to_submittable_(pathToSubmittable),
+ jobs_password_(jobsPassword),process_or_remote_id_(process_or_remote_id), try_no_(try_no){}
+ TaskCmd() : submittable_(0),try_no_(0) {}
+public:
+
+ virtual bool isWrite() const { return true; }
+ virtual int timeout() const { return 190; } // ECFLOW-157 80 -> 190
+
+ const std::string& path_to_node() const { return path_to_submittable_;}
+ const std::string& jobs_password() const { return jobs_password_;}
+ const std::string& process_or_remote_id() const { return process_or_remote_id_;}
+ int try_no() const { return try_no_;}
+ virtual ecf::Child::CmdType child_type() const = 0;
+
+ virtual bool equals(ClientToServerCmd*) const;
+ virtual bool task_cmd() const { return true; }
+ virtual bool connect_to_different_servers() const { return true; }
+
+protected:
+ /// Overridden to do nothing since Task based commands don't need _user_
+ /// based authentification
+ virtual void setup_user_authentification(){}
+ virtual bool authenticate(AbstractServer*, STC_Cmd_ptr&) const; /// Task have their own mechanism,can throw std::runtime_error
+ Submittable* get_submittable(AbstractServer* as) const ; // can throw std::runtime_error
+
+protected:
+ mutable Submittable* submittable_; // stored during authentication and re-used handle request, not persisted, server side only
+
+private:
+ std::string path_to_submittable_;
+ std::string jobs_password_;
+ std::string process_or_remote_id_;
+ int try_no_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< ClientToServerCmd >( *this );
+ ar & path_to_submittable_;
+ ar & jobs_password_;
+ ar & process_or_remote_id_;
+ ar & try_no_;
+ }
+};
+
+class InitCmd : public TaskCmd {
+public:
+ InitCmd(const std::string& pathToTask,
+ const std::string& jobsPassword,
+ const std::string& process_or_remote_id,
+ int try_no )
+ : TaskCmd(pathToTask,jobsPassword,process_or_remote_id,try_no) {}
+
+ InitCmd() : TaskCmd() {}
+
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ClientToServerCmd*) const;
+
+ virtual const char* theArg() const { return arg();}
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+private:
+ static const char* arg(); // used for argument parsing
+ static const char* desc(); // The description of the argument as provided to user
+
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+ virtual ecf::Child::CmdType child_type() const { return ecf::Child::INIT; }
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< TaskCmd >( *this );
+ }
+};
+
+class CompleteCmd : public TaskCmd {
+public:
+ CompleteCmd(const std::string& pathToTask,
+ const std::string& jobsPassword,
+ const std::string& process_or_remote_id = "",
+ int try_no = 1)
+ : TaskCmd(pathToTask,jobsPassword,process_or_remote_id,try_no) {}
+ CompleteCmd() : TaskCmd() {}
+
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ClientToServerCmd*) const;
+
+ virtual const char* theArg() const { return arg();}
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+private:
+ static const char* arg(); // used for argument parsing
+ static const char* desc(); // The description of the argument as provided to user
+
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+ virtual ecf::Child::CmdType child_type() const { return ecf::Child::COMPLETE; }
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< TaskCmd >( *this );
+ }
+};
+
+/// A child command that evaluates a expression. If the expression is false.
+/// Then client invoker will block.
+class CtsWaitCmd : public TaskCmd {
+public:
+ CtsWaitCmd(const std::string& pathToTask,
+ const std::string& jobsPassword,
+ const std::string& process_or_remote_id,
+ int try_no,
+ const std::string& expression);
+ CtsWaitCmd() : TaskCmd() {}
+
+ const std::string& expression() const { return expression_;}
+
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ClientToServerCmd*) const;
+
+ virtual const char* theArg() const { return arg();}
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+private:
+
+ static const char* arg(); // used for argument parsing
+ static const char* desc(); // The description of the argument as provided to user
+
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+ virtual ecf::Child::CmdType child_type() const { return ecf::Child::WAIT; }
+
+ std::string expression_;
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< TaskCmd >( *this );
+ ar & expression_;
+ }
+};
+
+class AbortCmd : public TaskCmd {
+public:
+ AbortCmd(const std::string& pathToTask,
+ const std::string& jobsPassword,
+ const std::string& process_or_remote_id,
+ int try_no = 1,
+ const std::string& reason = "");
+ AbortCmd() : TaskCmd() {}
+
+ const std::string& reason() const {return reason_; }
+
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ClientToServerCmd*) const;
+
+ virtual const char* theArg() const { return arg();}
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+private:
+ static const char* arg(); // used for argument parsing
+ static const char* desc(); // The description of the argument as provided to user
+
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+ virtual ecf::Child::CmdType child_type() const { return ecf::Child::ABORT; }
+
+ std::string reason_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< TaskCmd >( *this );
+ ar & reason_;
+ }
+};
+
+class EventCmd : public TaskCmd {
+public:
+ EventCmd(const std::string& pathToTask,
+ const std::string& jobsPassword,
+ const std::string& process_or_remote_id,
+ int try_no,
+ const std::string& eventName )
+ : TaskCmd(pathToTask,jobsPassword,process_or_remote_id,try_no), name_(eventName) {}
+ EventCmd() : TaskCmd() {}
+
+ const std::string& name() const { return name_; }
+
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ClientToServerCmd*) const;
+
+ virtual const char* theArg() const { return arg();}
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+private:
+ static const char* arg(); // used for argument parsing
+ static const char* desc(); // The description of the argument as provided to user
+
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+ virtual ecf::Child::CmdType child_type() const { return ecf::Child::EVENT; }
+
+private:
+ std::string name_; // the events name
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< TaskCmd >( *this );
+ ar & name_;
+ }
+};
+
+class MeterCmd : public TaskCmd {
+public:
+ MeterCmd(const std::string& pathToTask,
+ const std::string& jobsPassword,
+ const std::string& process_or_remote_id,
+ int try_no,
+ const std::string& meterName,
+ int meterValue)
+ : TaskCmd(pathToTask,jobsPassword,process_or_remote_id,try_no), name_(meterName), value_(meterValue) {}
+ MeterCmd() : TaskCmd(), value_(0) {}
+
+ const std::string& name() const { return name_; }
+ int value() const { return value_; }
+
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ClientToServerCmd*) const;
+
+ virtual const char* theArg() const { return arg();}
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+private:
+ static const char* arg(); // used for argument parsing
+ static const char* desc(); // The description of the argument as provided to user
+
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+ virtual ecf::Child::CmdType child_type() const { return ecf::Child::METER; }
+
+private:
+ std::string name_; // the meters name
+ int value_; // the meters value
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< TaskCmd >( *this );
+ ar & name_;
+ ar & value_;
+ }
+};
+
+class LabelCmd : public TaskCmd {
+public:
+ LabelCmd(const std::string& pathToTask,
+ const std::string& jobsPassword,
+ const std::string& process_or_remote_id,
+ int try_no,
+ const std::string& name,
+ const std::string& label)
+ : TaskCmd(pathToTask,jobsPassword,process_or_remote_id,try_no), name_(name), label_(label) {}
+ LabelCmd() : TaskCmd() {}
+
+ const std::string& name() const { return name_; }
+ const std::string& label() const { return label_;}
+
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ClientToServerCmd*) const;
+
+ virtual const char* theArg() const { return arg();}
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+private:
+ static const char* arg(); // used for argument parsing
+ static const char* desc(); // The description of the argument as provided to user
+
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+ virtual ecf::Child::CmdType child_type() const { return ecf::Child::LABEL; }
+
+private:
+ std::string name_; // the label name
+ std::string label_; // a single label, or multi-line label
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< TaskCmd >( *this );
+ ar & name_;
+ ar & label_;
+ }
+};
+
+//=================================================================================
+// User Commands
+// ================================================================================
+class UserCmd : public ClientToServerCmd {
+public:
+ UserCmd(){}
+
+ const std::string& user() const { return user_;}
+ virtual void setup_user_authentification();
+
+protected:
+
+ virtual bool equals(ClientToServerCmd*) const;
+ virtual bool authenticate(AbstractServer*, STC_Cmd_ptr&) const;
+
+ /// Prompt the user for confirmation: If user responds with no, will exit client
+ static void prompt_for_confirmation(const std::string& prompt);
+
+ /// All user commands will be pre_fixed with "--" and post_fixed with :user.
+ std::ostream& user_cmd(std::ostream& os, const std::string& the_cmd) const;
+
+ static int time_out_for_load_sync_and_get();
+
+ // The order is preserved during the split. Paths assumed to start with '/' char
+ static void split_args_to_options_and_paths(
+ const std::vector<std::string>& args,
+ std::vector<std::string>& options,
+ std::vector<std::string>& paths);
+
+private:
+ std::string user_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< ClientToServerCmd >( *this );
+ ar & user_;
+ }
+};
+
+
+// ========================================================================
+// This Command should NEVER be changed
+// This will allow new client to ask OLD server about its version
+// ========================================================================
+class ServerVersionCmd : public UserCmd {
+public:
+ ServerVersionCmd(){}
+
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ClientToServerCmd*) const;
+ virtual const char* theArg() const;
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+private:
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< UserCmd >( *this );
+ }
+};
+
+
+// This command is used to encapsulate all commands that are
+// simple signals to the server. This helps to cut down on the
+// number of global symbols used by boost serialisation.
+// =========================================================================
+// *** IMPORTANT ***: If any of these commands in the future need arguments,
+// *** then ensure to place a DUMMY enum in its place.
+// *** This will allow a *newer* development client to still send message to a older server.
+// *** i.e like terminating the server
+// *** IMPORTANT: For any new commands, must be added to the end.
+// *** - STATS_RESET was introduced in release 4.0.5
+// =========================================================================
+class CtsCmd : public UserCmd {
+public:
+ enum Api { NO_CMD, RESTORE_DEFS_FROM_CHECKPT,
+ RESTART_SERVER, SHUTDOWN_SERVER, HALT_SERVER, TERMINATE_SERVER,
+ RELOAD_WHITE_LIST_FILE,
+ FORCE_DEP_EVAL,
+ PING, GET_ZOMBIES, STATS, SUITES,
+ DEBUG_SERVER_ON, DEBUG_SERVER_OFF,
+ SERVER_LOAD, STATS_RESET
+ };
+
+ CtsCmd(Api a) : api_(a) {}
+ CtsCmd() : api_(NO_CMD) {}
+
+ Api api() const { return api_;}
+
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ClientToServerCmd*) const;
+
+ virtual bool isWrite() const;
+ virtual bool terminate_cmd() const { return api_ == TERMINATE_SERVER; }
+ virtual bool ping_cmd() const { return api_ == PING; }
+ virtual int timeout() const;
+
+ virtual bool handleRequestIsTestable() const;
+
+ virtual const char* theArg() const;
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+private:
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+
+ Api api_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< UserCmd >( *this );
+ ar & api_;
+ }
+};
+
+class CheckPtCmd : public UserCmd {
+public:
+ CheckPtCmd(ecf::CheckPt::Mode m, int interval,int checkpt_save_time_alarm)
+ : mode_(m), check_pt_interval_(interval),check_pt_save_time_alarm_(checkpt_save_time_alarm) {}
+ CheckPtCmd() : mode_(ecf::CheckPt::UNDEFINED), check_pt_interval_(0),check_pt_save_time_alarm_(0) {}
+
+ ecf::CheckPt::Mode mode() const { return mode_;}
+ int check_pt_interval() const { return check_pt_interval_;}
+ int check_pt_save_time_alarm() const { return check_pt_save_time_alarm_;}
+
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ClientToServerCmd*) const;
+ virtual bool isWrite() const;
+ virtual const char* theArg() const;
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+private:
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+
+ ecf::CheckPt::Mode mode_;
+ int check_pt_interval_;
+ int check_pt_save_time_alarm_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< UserCmd >( *this );
+ ar & mode_;
+ ar & check_pt_interval_;
+ ar & check_pt_save_time_alarm_;
+ }
+};
+
+
+// Client---(CSyncCmd::SYNC_FULL)---->Server-----(SSyncCmd)--->client:
+// Client---(CSyncCmd::SYNC)--------->Server-----(SSyncCmd)--->client:
+// Client---(CSyncCmd::NEWS)--------->Server-----(SNewsCmd)--->client:
+class CSyncCmd : public UserCmd {
+public:
+ enum Api { NEWS, SYNC , SYNC_FULL};
+
+ CSyncCmd(Api a, unsigned int client_handle,unsigned int client_state_change_no, unsigned int client_modify_change_no)
+ : api_(a),
+ client_handle_(client_handle),
+ client_state_change_no_(client_state_change_no),
+ client_modify_change_no_(client_modify_change_no) {}
+ CSyncCmd(unsigned int client_handle)
+ : api_(SYNC_FULL),
+ client_handle_(client_handle),
+ client_state_change_no_(0),
+ client_modify_change_no_(0) {}
+ CSyncCmd()
+ : api_(SYNC),
+ client_handle_(0),
+ client_state_change_no_(0),
+ client_modify_change_no_(0) {}
+
+ Api api() const { return api_;}
+ int client_state_change_no() const { return client_state_change_no_;}
+ int client_modify_change_no() const { return client_modify_change_no_;}
+ int client_handle() const { return client_handle_;}
+
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ClientToServerCmd*) const;
+ virtual int timeout() const;
+
+ virtual const char* theArg() const;
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+private:
+
+ /// Custom handling of command logging to add additional debug on same line
+ /// makes it easier to debug errors in syncing.
+ virtual void do_log(AbstractServer*) const;
+
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+
+ Api api_;
+ int client_handle_;
+ int client_state_change_no_;
+ int client_modify_change_no_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< UserCmd >( *this );
+ ar & api_;
+ ar & client_handle_;
+ ar & client_state_change_no_;
+ ar & client_modify_change_no_;
+ }
+};
+
+class ClientHandleCmd : public UserCmd {
+public:
+ enum Api { REGISTER, DROP, DROP_USER, ADD, REMOVE, AUTO_ADD , SUITES };
+
+ ClientHandleCmd(Api api = AUTO_ADD)
+ : api_(api),
+ client_handle_(0),
+ auto_add_new_suites_(false) {}
+
+ ClientHandleCmd(const std::vector<std::string>& suites, bool add_add_new_suites)
+ : api_(REGISTER),
+ client_handle_(0),
+ auto_add_new_suites_(add_add_new_suites),
+ suites_(suites) {}
+
+ ClientHandleCmd(int client_handle)
+ : api_(DROP),
+ client_handle_(client_handle),
+ auto_add_new_suites_(false) {}
+
+ ClientHandleCmd(const std::string& drop_user)
+ : api_(DROP_USER),
+ client_handle_(0),
+ auto_add_new_suites_(false),
+ drop_user_(drop_user){}
+
+ ClientHandleCmd(int client_handle, const std::vector<std::string>& suites, Api api)
+ : api_(api), // Must be ADD or REMOVE
+ client_handle_(client_handle),
+ auto_add_new_suites_(false),
+ suites_(suites){}
+
+ ClientHandleCmd(int client_handle, bool add_add_new_suites)
+ : api_(AUTO_ADD),
+ client_handle_(client_handle),
+ auto_add_new_suites_(add_add_new_suites) {}
+
+ Api api() const { return api_;}
+ const std::string& drop_user() const { return drop_user_;}
+
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ClientToServerCmd*) const;
+
+ virtual const char* theArg() const;
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+private:
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+
+ Api api_;
+ int client_handle_;
+ bool auto_add_new_suites_;
+ std::string drop_user_;
+ std::vector<std::string> suites_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< UserCmd >( *this );
+ ar & api_;
+ ar & client_handle_;
+ ar & auto_add_new_suites_;
+ ar & drop_user_;
+ ar & suites_;
+ }
+};
+
+// Collection of commands, that all take a abs node path as their only arg
+// Reduce number of global symbols caused by boost serialisation
+// Previously they were all separate commands
+//
+// Client---(CtsNodeCmd(GET))---->Server-----(DefsCmd | SNodeCmd )--->client:
+// When doHandleRequest is called in the server it will return DefsCmd
+// The DefsCmd is used to transport the node tree hierarchy to/from the server
+//
+// CHECK_JOB_GEN_ONLY command will traverse hierarchically from the given node path
+// and force generation of jobs. (i.e independently of dependencies).
+// This is used in *testing* only, so that we can compare/test/verify
+// job generation with the old version.
+// if absNodepath is empty we will generate jobs for all tasks
+class CtsNodeCmd : public UserCmd {
+public:
+ enum Api { NO_CMD, JOB_GEN, CHECK_JOB_GEN_ONLY, GET, WHY, GET_STATE, MIGRATE };
+ CtsNodeCmd(Api a, const std::string& absNodePath) : api_(a),absNodePath_(absNodePath) {}
+ CtsNodeCmd(Api a) : api_(a) { assert(a != NO_CMD); }
+ CtsNodeCmd() : api_(NO_CMD) {}
+
+ Api api() const { return api_;}
+ const std::string& absNodePath() const { return absNodePath_;}
+
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ClientToServerCmd*) const;
+
+ virtual PrintStyle::Type_t show_style() const;
+
+ virtual int timeout() const;
+ virtual bool isWrite() const;
+ virtual bool handleRequestIsTestable() const { return !terminate_cmd();}
+ virtual bool why_cmd( std::string& nodePath) const;
+ virtual bool get_cmd() const { return api_ == GET; }
+
+ virtual const char* theArg() const;
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+private:
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+
+private:
+ Api api_;
+ std::string absNodePath_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< UserCmd >( *this );
+ ar & api_;
+ ar & absNodePath_;
+ }
+};
+
+// DELETE If paths_ empty will delete all suites (beware) else will delete the chosen nodes.
+class PathsCmd : public UserCmd {
+public:
+ enum Api { NO_CMD, DELETE, SUSPEND, RESUME, KILL, STATUS, CHECK, EDIT_HISTORY };
+
+ PathsCmd(Api api,const std::vector<std::string>& paths, bool force = false)
+ : api_(api),force_(force),paths_(paths){}
+ PathsCmd(Api api,const std::string& absNodePath, bool force = false);
+ PathsCmd(Api api)
+ : api_(api), force_(false) { assert(api != NO_CMD); }
+ PathsCmd()
+ : api_(NO_CMD),force_(false) {}
+
+ Api api() const { return api_; }
+ const std::vector<std::string>& paths() const { return paths_;}
+ bool force() const { return force_;}
+
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual std::ostream& print(std::ostream& os, const std::string& path) const;
+
+ virtual bool equals(ClientToServerCmd*) const;
+ virtual bool isWrite() const;
+ virtual bool delete_all_cmd() const;
+
+ virtual const char* theArg() const;
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+private:
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+
+ std::ostream& my_print(std::ostream& os, const std::vector<std::string>& paths) const;
+
+private:
+ Api api_;
+ bool force_;
+ std::vector<std::string> paths_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< UserCmd >( *this );
+ ar & api_;
+ ar & force_;
+ ar & paths_;
+ }
+};
+
+
+/// The LogCmd is paired with SStringCmd
+/// Client---(LogCmd)---->Server-----(SStringCmd)--->client:
+/// When doHandleRequest is called in the server it will return SStringCmd
+/// The SStringCmd is used to transport the log file contents to the client
+class LogCmd : public UserCmd {
+public:
+ enum LogApi { GET, CLEAR, FLUSH, NEW , PATH};
+ LogCmd(LogApi a, int get_last_n_lines = 0); // for zero we take default from log. Avoid adding dependency on log.hpp
+ LogCmd(const std::string& path); // NEW
+ LogCmd();
+
+ LogApi api() const { return api_;}
+ int get_last_n_lines() const { return get_last_n_lines_;}
+ const std::string& new_path() const { return new_path_;}
+
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ClientToServerCmd*) const;
+
+ virtual bool isWrite() const;
+ virtual const char* theArg() const { return arg();}
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+private:
+ static const char* arg(); // used for argument parsing
+ static const char* desc(); // The description of the argument as provided to user
+
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+
+ LogApi api_;
+ int get_last_n_lines_; // default to 100 -> ECFLOW-174
+ std::string new_path_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< UserCmd >( *this );
+ ar & api_;
+ ar & get_last_n_lines_;
+ ar & new_path_;
+ }
+};
+
+/// Simply writes the message to the log file
+class LogMessageCmd : public UserCmd {
+public:
+ LogMessageCmd(const std::string& msg) : msg_(msg) {}
+ LogMessageCmd() {}
+
+ const std::string& msg() const { return msg_;}
+
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ClientToServerCmd*) const;
+
+ virtual const char* theArg() const { return arg();}
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+private:
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+ static const char* arg(); // used for argument parsing
+ static const char* desc(); // The description of the argument as provided to user
+
+ std::string msg_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< UserCmd >( *this );
+ ar & msg_;
+ }
+};
+
+
+// class Begin: if suiteName is empty we will begin all suites
+class BeginCmd : public UserCmd {
+public:
+ BeginCmd(const std::string& suiteName, bool force = false);
+ BeginCmd() : force_(false) {}
+
+ const std::string& suiteName() const { return suiteName_;}
+ bool force() const { return force_;}
+
+ virtual int timeout() const { return 80; }
+
+ virtual bool isWrite() const { return true; }
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ClientToServerCmd*) const;
+
+ virtual const char* theArg() const { return arg();}
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+private:
+ static const char* arg(); // used for argument parsing
+ static const char* desc(); // The description of the argument as provided to user
+
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+
+ std::string suiteName_;
+ bool force_; // reset begin status on suites & bypass checks, can create zombies, used in test only
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< UserCmd >( *this );
+ ar & suiteName_;
+ ar & force_;
+ }
+};
+
+class ZombieCmd : public UserCmd {
+public:
+ ZombieCmd(ecf::User::Action uc, const std::string& path, const std::string& process_id, const std::string& password)
+ : user_action_(uc), path_(path), process_id_(process_id), password_(password) {}
+ ZombieCmd(ecf::User::Action uc = ecf::User::BLOCK) : user_action_(uc) {}
+
+ const std::string& path_to_task() const { return path_;}
+ const std::string& process_or_remote_id() const { return process_id_;}
+ const std::string& password() const { return password_;}
+
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ClientToServerCmd*) const;
+
+ virtual const char* theArg() const;
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+private:
+
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+
+ ecf::User::Action user_action_;
+ std::string path_;
+ std::string process_id_;
+ std::string password_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< UserCmd >( *this );
+ ar & user_action_;
+ ar & path_;
+ ar & process_id_;
+ ar & password_;
+ }
+};
+
+class RequeueNodeCmd : public UserCmd {
+public:
+ enum Option { NO_OPTION, ABORT, FORCE };
+
+ RequeueNodeCmd(const std::vector<std::string>& paths, Option op = NO_OPTION)
+ : paths_(paths), option_(op) {}
+
+ RequeueNodeCmd(const std::string& absNodepath, Option op = NO_OPTION)
+ : paths_(std::vector<std::string>(1,absNodepath)), option_(op) {}
+
+ RequeueNodeCmd() : option_(NO_OPTION) {}
+
+ const std::vector<std::string>& paths() const { return paths_;}
+ Option option() const { return option_;}
+
+ virtual bool isWrite() const { return true; }
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual std::ostream& print(std::ostream& os, const std::string& path) const;
+ virtual bool equals(ClientToServerCmd*) const;
+
+ virtual const char* theArg() const { return arg();}
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+private:
+ static const char* arg(); // used for argument parsing
+ static const char* desc(); // The description of the argument as provided to user
+
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+
+private:
+ mutable std::vector<std::string> paths_; // mutable to allow swap to clear & reclaim memory, as soon as possible
+ Option option_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< UserCmd >( *this );
+ ar & paths_;
+ ar & option_;
+ }
+};
+
+class OrderNodeCmd : public UserCmd {
+public:
+ OrderNodeCmd(const std::string& absNodepath, NOrder::Order op)
+ : absNodepath_(absNodepath), option_(op) {}
+ OrderNodeCmd() : option_(NOrder::TOP) {}
+
+ const std::string& absNodepath() const { return absNodepath_;}
+ NOrder::Order option() const { return option_;}
+
+ virtual bool isWrite() const { return true; }
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ClientToServerCmd*) const;
+
+ virtual const char* theArg() const { return arg();}
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+private:
+ static const char* arg(); // used for argument parsing
+ static const char* desc(); // The description of the argument as provided to user
+
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+
+ std::string absNodepath_;
+ NOrder::Order option_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< UserCmd >( *this );
+ ar & absNodepath_;
+ ar & option_;
+ }
+};
+
+
+// The absNodepath must be provided
+class RunNodeCmd : public UserCmd {
+public:
+ RunNodeCmd(const std::string& absNodepath, bool force, bool test = false)
+ : paths_(std::vector<std::string>(1,absNodepath)), force_(force), test_(test) {}
+
+ RunNodeCmd(const std::vector<std::string>& paths, bool force, bool test = false)
+ : paths_(paths), force_(force), test_(test) {}
+
+ RunNodeCmd() : force_(false), test_(false) {}
+
+ const std::vector<std::string>& paths() const { return paths_;}
+ bool force() const { return force_;}
+
+ virtual bool isWrite() const { return true; }
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual std::ostream& print(std::ostream& os, const std::string& path) const;
+ virtual bool equals(ClientToServerCmd*) const;
+
+ virtual const char* theArg() const { return arg();}
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+private:
+ static const char* arg(); // used for argument parsing
+ static const char* desc(); // The description of the argument as provided to user
+
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+
+private:
+ std::vector<std::string> paths_;
+ bool force_;
+ bool test_; // only for test, hence we don't serialise this
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< UserCmd >( *this );
+ ar & paths_;
+ ar & force_;
+ }
+};
+
+
+// Does Nothing in the server, however allows client code to display the
+// returned Defs in different showStyles
+// This class has no need for persistence, i.e client side only
+class ShowCmd : public UserCmd {
+public:
+ ShowCmd(PrintStyle::Type_t s = PrintStyle::DEFS) : style_(s) {}
+
+ // returns the showStyle
+ virtual bool show_cmd() const { return true ;}
+ virtual PrintStyle::Type_t show_style() const { return style_;}
+
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ClientToServerCmd*) const;
+
+ virtual const char* theArg() const { return arg();}
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+private:
+ static const char* arg(); // used for argument parsing
+ static const char* desc(); // The description of the argument as provided to user
+
+ // The Show Cmd is processed on the client side,
+ // Likewise the doHandleRequest does nothing,
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+
+ PrintStyle::Type_t style_;
+
+ // Persistence is still required since show command can be *USED* in a *GROUP* command
+ // However its ONLY used on the client side, hence no need to serialise data members
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< UserCmd >( *this );
+ }
+};
+
+// Will *load* the suites, into the server.
+// Additionally the server will try to resolve extern's. The extern are references
+// to Node, events, meters, limits, variables defined on another suite.
+class LoadDefsCmd : public UserCmd {
+public:
+ LoadDefsCmd(const std::string& defs_filename, bool force = false);
+
+ LoadDefsCmd(const defs_ptr& defs, bool force = false)
+ : force_(force), defs_(defs) {}
+
+ LoadDefsCmd() : force_(false) {}
+
+ // Uses by equals only
+ const defs_ptr& theDefs() const { return defs_; }
+
+ virtual bool isWrite() const { return true; }
+ virtual int timeout() const { return time_out_for_load_sync_and_get(); }
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ClientToServerCmd*) const;
+
+ virtual const char* theArg() const { return arg();}
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+ static Cmd_ptr create(const std::string& defs_filename, bool force, bool check_only, AbstractClientEnv* clientEnv);
+
+private:
+ static const char* arg(); // used for argument parsing
+ static const char* desc(); // The description of the command as provided to user
+
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+
+ bool force_;
+ defs_ptr defs_;
+ std::string defs_filename_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< UserCmd >( *this );
+ ar & force_;
+ ar & defs_;
+ ar & defs_filename_;
+ }
+};
+
+class ReplaceNodeCmd : public UserCmd {
+public:
+ ReplaceNodeCmd(const std::string& node_path, bool createNodesAsNeeded, defs_ptr defs, bool force );
+ ReplaceNodeCmd(const std::string& node_path, bool createNodesAsNeeded, const std::string& path_to_defs, bool force );
+ ReplaceNodeCmd() : createNodesAsNeeded_(false), force_(false) {}
+
+ defs_ptr theDefs() const { return clientDefs_; }
+ const std::string& pathToNode() const { return pathToNode_; }
+ const std::string& path_to_defs() const { return path_to_defs_;}
+ bool createNodesAsNeeded() const { return createNodesAsNeeded_;}
+ bool force() const { return force_;}
+
+ virtual bool isWrite() const { return true; }
+ virtual int timeout() const { return 300; }
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ClientToServerCmd*) const;
+
+ virtual const char* theArg() const { return arg();}
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+private:
+ static const char* arg(); // used for argument parsing
+ static const char* desc(); // The description of the argument as provided to user
+
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+
+ bool createNodesAsNeeded_;
+ bool force_;
+ std::string pathToNode_;
+ std::string path_to_defs_; // Can be empty if defs loaded in memory via python api
+ defs_ptr clientDefs_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< UserCmd >( *this );
+ ar & createNodesAsNeeded_;
+ ar & force_;
+ ar & pathToNode_;
+ ar & path_to_defs_;
+ ar & clientDefs_;
+ }
+};
+
+// Set the state on the affected node ONLY.
+// If recursive is used set the state, on node and _ALL_ nodes _beneath
+// setRepeatToLastValue set, only make sense when used with recursive.
+// stateOrEvent, string is one of:
+// < unknown | suspended | complete | queued | submitted | active | aborted | clear | set >
+class ForceCmd : public UserCmd {
+public:
+ ForceCmd(const std::vector<std::string>& paths,
+ const std::string& stateOrEvent,
+ bool recursive,
+ bool setRepeatToLastValue)
+ : paths_(paths), stateOrEvent_(stateOrEvent),
+ recursive_(recursive), setRepeatToLastValue_(setRepeatToLastValue) {}
+ ForceCmd(const std::string& path,
+ const std::string& stateOrEvent,
+ bool recursive,
+ bool setRepeatToLastValue)
+ : paths_(std::vector<std::string>(1,path)), stateOrEvent_(stateOrEvent),
+ recursive_(recursive), setRepeatToLastValue_(setRepeatToLastValue) {}
+ ForceCmd() : recursive_(false), setRepeatToLastValue_(false) {}
+
+ // Uses by equals only
+ const std::vector<std::string> paths() const { return paths_; }
+ const std::string& stateOrEvent() const { return stateOrEvent_;}
+ bool recursive() const { return recursive_;}
+ bool setRepeatToLastValue() const { return setRepeatToLastValue_;}
+
+ virtual bool isWrite() const { return true; }
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual std::ostream& print(std::ostream& os, const std::string& path) const;
+ virtual bool equals(ClientToServerCmd*) const;
+
+ virtual const char* theArg() const { return arg();}
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+private:
+ static const char* arg(); // used for argument parsing
+ static const char* desc(); // The description of the argument as provided to user
+
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+
+private:
+ std::vector<std::string> paths_;
+ std::string stateOrEvent_;
+ bool recursive_;
+ bool setRepeatToLastValue_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< UserCmd >( *this );
+ ar & paths_;
+ ar & stateOrEvent_;
+ ar & recursive_;
+ ar & setRepeatToLastValue_;
+ }
+};
+
+// Free Dependencies
+class FreeDepCmd : public UserCmd {
+public:
+ FreeDepCmd(const std::vector<std::string>& paths,
+ bool trigger = true,
+ bool all = false, // day, date, time, today, trigger, cron
+ bool date = false,
+ bool time = false // includes time, day, date, today, cron
+ )
+ : paths_(paths), trigger_(trigger), all_(all), date_(date), time_(time) {}
+
+ FreeDepCmd(const std::string& path,
+ bool trigger = true,
+ bool all = false, // day, date, time, today, trigger, cron
+ bool date = false,
+ bool time = false // includes time, day, date, today, cron
+ )
+ : paths_(std::vector<std::string>(1,path)), trigger_(trigger), all_(all), date_(date), time_(time) {}
+
+ FreeDepCmd() : trigger_(true), all_(false), date_(false), time_(false){}
+
+ // Uses by equals only
+ const std::vector<std::string>& paths() const { return paths_; }
+ bool trigger() const { return trigger_;}
+ bool all() const { return all_;}
+ bool date() const { return date_;}
+ bool time() const { return time_;}
+
+ virtual bool isWrite() const { return true; }
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual std::ostream& print(std::ostream& os, const std::string& path) const;
+ virtual bool equals(ClientToServerCmd*) const;
+
+ virtual const char* theArg() const { return arg();}
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+private:
+ static const char* arg(); // used for argument parsing
+ static const char* desc(); // The description of the argument as provided to user
+
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+
+private:
+ std::vector<std::string> paths_;
+ bool trigger_;
+ bool all_;
+ bool date_;
+ bool time_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< UserCmd >( *this );
+ ar & paths_;
+ ar & trigger_;
+ ar & all_;
+ ar & date_;
+ ar & time_;
+ }
+};
+
+class AlterCmd : public UserCmd {
+public:
+ enum Delete_attr_type { DEL_VARIABLE, DEL_TIME, DEL_TODAY, DEL_DATE, DEL_DAY,
+ DEL_CRON, DEL_EVENT, DEL_METER, DEL_LABEL,
+ DEL_TRIGGER, DEL_COMPLETE, DEL_REPEAT, DEL_LIMIT, DEL_LIMIT_PATH,
+ DEL_INLIMIT, DEL_ZOMBIE, DELETE_ATTR_ND, DEL_LATE };
+
+ enum Change_attr_type { VARIABLE, CLOCK_TYPE, CLOCK_DATE, CLOCK_GAIN, EVENT, METER, LABEL,
+ TRIGGER, COMPLETE, REPEAT, LIMIT_MAX, LIMIT_VAL, DEFSTATUS, CHANGE_ATTR_ND, CLOCK_SYNC, LATE };
+
+ enum Add_attr_type { ADD_TIME, ADD_TODAY, ADD_DATE, ADD_DAY, ADD_ZOMBIE, ADD_VARIABLE, ADD_ATTR_ND, ADD_LATE };
+
+ AlterCmd(const std::string& path, Add_attr_type attr, const std::string& name, const std::string& value = "" )
+ : paths_(std::vector<std::string>(1,path)), name_(name), value_(value), add_attr_type_(attr),
+ del_attr_type_(DELETE_ATTR_ND), change_attr_type_(CHANGE_ATTR_ND),flag_type_(ecf::Flag::NOT_SET), flag_(false) {}
+ AlterCmd(const std::vector<std::string>& paths, Add_attr_type attr, const std::string& name, const std::string& value = "" )
+ : paths_(paths), name_(name), value_(value), add_attr_type_(attr),
+ del_attr_type_(DELETE_ATTR_ND), change_attr_type_(CHANGE_ATTR_ND),flag_type_(ecf::Flag::NOT_SET), flag_(false) {}
+
+ AlterCmd(const std::string& path, Delete_attr_type del, const std::string& name = "" , const std::string& value = "")
+ : paths_(std::vector<std::string>(1,path)), name_(name), value_(value), add_attr_type_(ADD_ATTR_ND),
+ del_attr_type_(del), change_attr_type_(CHANGE_ATTR_ND),flag_type_(ecf::Flag::NOT_SET), flag_(false) {}
+ AlterCmd(const std::vector<std::string>& paths, Delete_attr_type del, const std::string& name = "" , const std::string& value = "")
+ : paths_(paths), name_(name), value_(value), add_attr_type_(ADD_ATTR_ND),
+ del_attr_type_(del), change_attr_type_(CHANGE_ATTR_ND),flag_type_(ecf::Flag::NOT_SET), flag_(false) {}
+
+ AlterCmd(const std::string& path, Change_attr_type attr, const std::string& name, const std::string& value = "")
+ : paths_(std::vector<std::string>(1,path)), name_(name), value_(value), add_attr_type_(ADD_ATTR_ND),
+ del_attr_type_(DELETE_ATTR_ND), change_attr_type_(attr),flag_type_(ecf::Flag::NOT_SET), flag_(false) {}
+ AlterCmd(const std::vector<std::string>& paths, Change_attr_type attr, const std::string& name, const std::string& value = "")
+ : paths_(paths), name_(name), value_(value), add_attr_type_(ADD_ATTR_ND),
+ del_attr_type_(DELETE_ATTR_ND), change_attr_type_(attr),flag_type_(ecf::Flag::NOT_SET), flag_(false) {}
+
+ AlterCmd(const std::string& path, ecf::Flag::Type ft, bool flag)
+ : paths_(std::vector<std::string>(1,path)), add_attr_type_(ADD_ATTR_ND),
+ del_attr_type_(DELETE_ATTR_ND), change_attr_type_(CHANGE_ATTR_ND),flag_type_(ft), flag_(flag) {}
+ AlterCmd(const std::vector<std::string>& paths, ecf::Flag::Type ft, bool flag)
+ : paths_(paths), add_attr_type_(ADD_ATTR_ND),
+ del_attr_type_(DELETE_ATTR_ND), change_attr_type_(CHANGE_ATTR_ND),flag_type_(ft), flag_(flag) {}
+
+ AlterCmd()
+ : add_attr_type_(ADD_ATTR_ND), del_attr_type_(DELETE_ATTR_ND),
+ change_attr_type_(CHANGE_ATTR_ND),flag_type_(ecf::Flag::NOT_SET), flag_(false) {}
+
+ // Uses by equals only
+ const std::vector<std::string>& paths() const { return paths_; }
+ const std::string& name() const { return name_; }
+ const std::string& value() const { return value_; }
+ Delete_attr_type delete_attr_type() const { return del_attr_type_;}
+ Change_attr_type change_attr_type() const { return change_attr_type_;}
+ Add_attr_type add_attr_type() const { return add_attr_type_;}
+ ecf::Flag::Type flag_type() const { return flag_type_;}
+ bool flag() const { return flag_;}
+
+ virtual bool isWrite() const { return true; }
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual std::ostream& print(std::ostream& os, const std::string& path) const;
+ virtual bool equals(ClientToServerCmd*) const;
+
+ virtual const char* theArg() const { return arg();}
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+private:
+ static const char* arg(); // used for argument parsing
+ static const char* desc(); // The description of the argument as provided to user
+
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+ STC_Cmd_ptr alter_server_state(AbstractServer*) const;
+
+ void createAdd( Cmd_ptr& cmd, std::vector<std::string>& options, std::vector<std::string>& paths) const;
+ void createDelete( Cmd_ptr& cmd, const std::vector<std::string>& options, const std::vector<std::string>& paths) const;
+ void createChange( Cmd_ptr& cmd, std::vector<std::string>& options, std::vector<std::string>& paths) const;
+ void create_flag( Cmd_ptr& cmd, const std::vector<std::string>& options, const std::vector<std::string>& paths, bool flag) const;
+
+ std::ostream& my_print(std::ostream& os, const std::vector<std::string>& paths) const;
+
+private:
+ std::vector<std::string> paths_;
+ std::string name_;
+ std::string value_;
+ Add_attr_type add_attr_type_;
+ Delete_attr_type del_attr_type_;
+ Change_attr_type change_attr_type_;
+ ecf::Flag::Type flag_type_;
+ bool flag_; // true means set false means clear
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< UserCmd >( *this );
+ ar & paths_;
+ ar & name_;
+ ar & value_;
+ ar & add_attr_type_;
+ ar & del_attr_type_;
+ ar & change_attr_type_;
+ ar & flag_type_;
+ ar & flag_;
+ }
+};
+
+//================================================================================
+// Paired with SStringCmd
+// Client---(CFileCmd)---->Server-----(SStringCmd)--->client:
+//================================================================================
+class CFileCmd : public UserCmd {
+public:
+ enum File_t { ECF, JOB, JOBOUT, MANUAL, KILL, STAT };
+ CFileCmd(const std::string& pathToNode, File_t file, size_t max_lines)
+ : file_(file), pathToNode_(pathToNode), max_lines_(max_lines) {}
+ CFileCmd(const std::string& pathToNode, const std::string& file_type, const std::string& max_lines);
+
+ CFileCmd() : file_(ECF),max_lines_(0) {}
+
+ // Uses by equals only
+ const std::string& pathToNode() const { return pathToNode_; }
+ File_t fileType() const { return file_;}
+ size_t max_lines() const { return max_lines_;}
+
+ static std::vector<CFileCmd::File_t> fileTypesVec();
+ static std::string toString(File_t);
+
+ virtual bool handleRequestIsTestable() const { return false ;}
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ClientToServerCmd*) const;
+
+ virtual const char* theArg() const { return arg();}
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+private:
+ static const char* arg(); // used for argument parsing
+ static const char* desc(); // The description of the argument as provided to user
+
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+
+ File_t file_;
+ std::string pathToNode_;
+ size_t max_lines_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< UserCmd >( *this );
+ ar & file_;
+ ar & pathToNode_;
+ ar & max_lines_;
+ }
+};
+
+//================================================================================
+// Paired with SStringCmd
+// Client---(EditScriptCmd)---->Server-----(SStringCmd)--->client:
+//================================================================================
+class EditScriptCmd : public UserCmd {
+public:
+ enum EditType { EDIT, PREPROCESS, SUBMIT, PREPROCESS_USER_FILE, SUBMIT_USER_FILE };
+ EditScriptCmd(const std::string& path_to_node,EditType et) // EDIT or PREPROCESS
+ : edit_type_(et), path_to_node_(path_to_node),
+ alias_(false),run_(false)
+ {}
+
+ EditScriptCmd(const std::string& path_to_node, const NameValueVec& user_variables)
+ : edit_type_(SUBMIT), path_to_node_(path_to_node), user_variables_(user_variables),
+ alias_(false),run_(false)
+ {}
+
+ EditScriptCmd(const std::string& path_to_node, const std::vector<std::string>& user_file_contents)
+ : edit_type_(PREPROCESS_USER_FILE), path_to_node_(path_to_node), user_file_contents_(user_file_contents),
+ alias_(false),run_(false)
+ {}
+
+ EditScriptCmd( const std::string& path_to_node,
+ const NameValueVec& user_variables,
+ const std::vector<std::string>& user_file_contents,
+ bool create_alias,
+ bool run_alias
+ )
+ : edit_type_(SUBMIT_USER_FILE), path_to_node_(path_to_node), user_file_contents_(user_file_contents),user_variables_(user_variables),
+ alias_(create_alias),run_(run_alias)
+ {}
+
+ EditScriptCmd() : edit_type_(EDIT),alias_(false),run_(false) {}
+
+ // Uses by equals only
+ const std::string& path_to_node() const { return path_to_node_; }
+ EditType edit_type() const { return edit_type_;}
+ bool alias() const { return alias_;}
+ bool run() const { return run_;}
+
+ virtual bool handleRequestIsTestable() const { return false ;}
+ virtual bool isWrite() const;
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ClientToServerCmd*) const;
+
+ virtual const char* theArg() const { return arg();}
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+private:
+ static const char* arg(); // used for argument parsing
+ static const char* desc(); // The description of the argument as provided to user
+
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+
+ EditType edit_type_;
+ std::string path_to_node_;
+ mutable std::vector<std::string> user_file_contents_;
+ NameValueVec user_variables_;
+ bool alias_;
+ bool run_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< UserCmd >( *this );
+ ar & edit_type_;
+ ar & path_to_node_;
+ ar & user_file_contents_;
+ ar & user_variables_;
+ ar & alias_;
+ ar & run_;
+ }
+};
+
+class PlugCmd : public UserCmd {
+public:
+ PlugCmd(const std::string& source, const std::string& dest) : source_(source), dest_(dest) {}
+ PlugCmd() {}
+
+ // Uses by equals only
+ const std::string& source() const { return source_; }
+ const std::string& dest() const { return dest_; }
+
+ virtual int timeout() const { return 120; }
+ virtual bool handleRequestIsTestable() const { return false ;}
+ virtual bool isWrite() const { return true; }
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ClientToServerCmd*) const;
+
+ virtual const char* theArg() const { return arg();}
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+private:
+ static const char* arg(); // used for argument parsing
+ static const char* desc(); // The description of the argument as provided to user
+
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+
+private:
+ std::string source_;
+ std::string dest_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< UserCmd >( *this );
+ ar & source_;
+ ar & dest_;
+ }
+};
+
+class MoveCmd : public UserCmd {
+public:
+ MoveCmd(const std::pair<std::string,std::string>& host_port, Node* src, const std::string& dest);
+ MoveCmd();
+ virtual ~MoveCmd();
+
+ Node* source() const;
+ const std::string& dest() const { return dest_; }
+
+ virtual bool handleRequestIsTestable() const { return false ;}
+ virtual bool isWrite() const { return true; }
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ClientToServerCmd*) const;
+
+ virtual const char* theArg() const { return arg();}
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+private:
+ static const char* arg(); // used for argument parsing
+ static const char* desc(); // The description of the argument as provided to user
+
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+
+ bool check_source() const;
+
+private:
+ mutable Suite* sourceSuite_; // only one is set, gets round un-registered class exception
+ mutable Family* sourceFamily_;// only one is set, gets round un-registered class exception
+ mutable Task* sourceTask_; // only one is set, gets round un-registered class exception
+ std::string src_host_;
+ std::string src_port_;
+ std::string src_path_;
+ std::string dest_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< UserCmd >( *this );
+ ar & sourceSuite_; // only one is serialised
+ ar & sourceFamily_; // only one is serialised
+ ar & sourceTask_; // only one is serialised
+ ar & src_host_;
+ ar & src_port_;
+ ar & src_path_;
+ ar & dest_;
+ }
+};
+
+// The group command allows a series of commands to be be executed:
+//
+// Client---(GroupCTSCmd)---->Server-----(GroupSTCCmd | StcCmd(OK) | Error )--->client:
+//
+// If client->server contains GetDefs cmd and log file commands, then a group
+// command will be created for returning to the client
+//
+// If group command contains multiple [ CtsNodeCmd(GET) | LogCmd --get ] commands then
+// all the results are returned back to the client, HOWEVER when client calls
+// Cmd::defs() | Cmd::get_string() only the first data is returned.
+//
+class GroupCTSCmd : public UserCmd {
+public:
+ GroupCTSCmd(const std::string& list_of_commands,AbstractClientEnv* clientEnv);
+ GroupCTSCmd(){}
+
+ virtual bool isWrite() const;
+ virtual PrintStyle::Type_t show_style() const;
+ virtual bool get_cmd() const;
+ virtual bool task_cmd() const;
+ virtual bool terminate_cmd() const;
+ virtual bool why_cmd( std::string& ) const;
+ virtual bool group_cmd() const { return true; }
+
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ClientToServerCmd*) const;
+
+ void addChild(Cmd_ptr childCmd);
+ const std::vector<Cmd_ptr>& cmdVec() const { return cmdVec_;}
+
+ virtual const char* theArg() const { return arg();}
+ virtual void addOption(boost::program_options::options_description& desc) const;
+ virtual void create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+private:
+ static const char* arg(); // used for argument parsing
+ static const char* desc(); // The description of the argument as provided to user
+
+ virtual void setup_user_authentification();
+ virtual bool authenticate(AbstractServer*, STC_Cmd_ptr&) const;
+ virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
+
+ std::vector<Cmd_ptr> cmdVec_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< UserCmd >( *this );
+ ar & cmdVec_;
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, const ServerVersionCmd&);
+std::ostream& operator<<(std::ostream& os, const CtsCmd&);
+std::ostream& operator<<(std::ostream& os, const CtsNodeCmd&);
+std::ostream& operator<<(std::ostream& os, const PathsCmd&);
+std::ostream& operator<<(std::ostream& os, const CheckPtCmd&);
+std::ostream& operator<<(std::ostream& os, const LoadDefsCmd&);
+std::ostream& operator<<(std::ostream& os, const LogCmd&);
+std::ostream& operator<<(std::ostream& os, const LogMessageCmd&);
+std::ostream& operator<<(std::ostream& os, const BeginCmd&);
+std::ostream& operator<<(std::ostream& os, const ZombieCmd&);
+std::ostream& operator<<(std::ostream& os, const InitCmd&);
+std::ostream& operator<<(std::ostream& os, const EventCmd&);
+std::ostream& operator<<(std::ostream& os, const MeterCmd&);
+std::ostream& operator<<(std::ostream& os, const LabelCmd&);
+std::ostream& operator<<(std::ostream& os, const CompleteCmd&);
+std::ostream& operator<<(std::ostream& os, const CtsWaitCmd&);
+std::ostream& operator<<(std::ostream& os, const AbortCmd&);
+std::ostream& operator<<(std::ostream& os, const RequeueNodeCmd&);
+std::ostream& operator<<(std::ostream& os, const OrderNodeCmd&);
+std::ostream& operator<<(std::ostream& os, const RunNodeCmd&);
+std::ostream& operator<<(std::ostream& os, const ReplaceNodeCmd&);
+std::ostream& operator<<(std::ostream& os, const ForceCmd&);
+std::ostream& operator<<(std::ostream& os, const FreeDepCmd&);
+std::ostream& operator<<(std::ostream& os, const CFileCmd&);
+std::ostream& operator<<(std::ostream& os, const PlugCmd&);
+std::ostream& operator<<(std::ostream& os, const AlterCmd&);
+std::ostream& operator<<(std::ostream& os, const MoveCmd&);
+std::ostream& operator<<(std::ostream& os, const GroupCTSCmd&);
+
+BOOST_CLASS_EXPORT_KEY(ServerVersionCmd)
+BOOST_CLASS_EXPORT_KEY(CtsCmd)
+BOOST_CLASS_EXPORT_KEY(CSyncCmd)
+BOOST_CLASS_EXPORT_KEY(ClientHandleCmd)
+BOOST_CLASS_EXPORT_KEY(CtsNodeCmd)
+BOOST_CLASS_EXPORT_KEY(PathsCmd)
+BOOST_CLASS_EXPORT_KEY(CheckPtCmd)
+BOOST_CLASS_EXPORT_KEY(LoadDefsCmd)
+BOOST_CLASS_EXPORT_KEY(LogCmd)
+BOOST_CLASS_EXPORT_KEY(LogMessageCmd)
+BOOST_CLASS_EXPORT_KEY(BeginCmd)
+BOOST_CLASS_EXPORT_KEY(ZombieCmd)
+BOOST_CLASS_EXPORT_KEY(InitCmd)
+BOOST_CLASS_EXPORT_KEY(EventCmd)
+BOOST_CLASS_EXPORT_KEY(MeterCmd)
+BOOST_CLASS_EXPORT_KEY(LabelCmd)
+BOOST_CLASS_EXPORT_KEY(AbortCmd)
+BOOST_CLASS_EXPORT_KEY(CtsWaitCmd)
+BOOST_CLASS_EXPORT_KEY(CompleteCmd)
+BOOST_CLASS_EXPORT_KEY(RequeueNodeCmd)
+BOOST_CLASS_EXPORT_KEY(OrderNodeCmd)
+BOOST_CLASS_EXPORT_KEY(RunNodeCmd)
+BOOST_CLASS_EXPORT_KEY(ReplaceNodeCmd)
+BOOST_CLASS_EXPORT_KEY(ForceCmd)
+BOOST_CLASS_EXPORT_KEY(FreeDepCmd)
+BOOST_CLASS_EXPORT_KEY(CFileCmd)
+BOOST_CLASS_EXPORT_KEY(EditScriptCmd)
+BOOST_CLASS_EXPORT_KEY(PlugCmd)
+BOOST_CLASS_EXPORT_KEY(AlterCmd)
+BOOST_CLASS_EXPORT_KEY(MoveCmd)
+BOOST_CLASS_EXPORT_KEY(GroupCTSCmd)
+BOOST_CLASS_EXPORT_KEY(ShowCmd)
+#endif
diff --git a/Base/src/cts/CtsApi.cpp b/Base/src/cts/CtsApi.cpp
new file mode 100644
index 0000000..5dbf1c2
--- /dev/null
+++ b/Base/src/cts/CtsApi.cpp
@@ -0,0 +1,710 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #76 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : (C)lient (t)o (s)erver API
+//============================================================================
+
+#include <sstream>
+#include <boost/algorithm/string/trim.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include "CtsApi.hpp"
+
+std::string CtsApi::to_string(const std::vector<std::string>& vec) {
+ std::string ret;
+ for(size_t i = 0; i < vec.size(); i++) { ret += vec[i]; ret += " "; }
+ return ret;
+}
+
+std::string CtsApi::server_version() { return std::string("--server_version");}
+const char* CtsApi::server_version_arg() { return "server_version"; }
+
+std::string CtsApi::get(const std::string& absNodePath) {
+ std::string ret = "--get";
+ if (!absNodePath.empty()) {
+ ret += "=";
+ ret += absNodePath;
+ }
+ return ret;
+}
+const char* CtsApi::getArg() { return "get"; }
+
+std::string CtsApi::get_state(const std::string& absNodePath) {
+ std::string ret = "--get_state";
+ if (!absNodePath.empty()) {
+ ret += "=";
+ ret += absNodePath;
+ }
+ return ret;
+}
+const char* CtsApi::get_state_arg() { return "get_state"; }
+
+std::string CtsApi::migrate(const std::string& absNodePath) {
+ std::string ret = "--migrate";
+ if (!absNodePath.empty()) {
+ ret += "=";
+ ret += absNodePath;
+ }
+ return ret;
+}
+const char* CtsApi::migrate_arg() { return "migrate"; }
+
+std::string CtsApi::stats() { return "--stats"; }
+const char* CtsApi::statsArg() { return "stats"; }
+
+std::string CtsApi::stats_reset() { return "--stats_reset"; }
+const char* CtsApi::stats_reset_arg() { return "stats_reset"; }
+
+
+std::string CtsApi::suites() { return "--suites"; }
+const char* CtsApi::suitesArg() { return "suites"; }
+
+std::vector<std::string> CtsApi::ch_register( bool auto_add_new_suites , const std::vector<std::string>& suites )
+{
+ std::vector<std::string> retVec; retVec.reserve(suites.size() +1);
+ std::string ret = "--ch_register=";
+ if ( auto_add_new_suites ) ret += "true";
+ else ret += "false";
+ retVec.push_back(ret);
+ for(size_t i = 0; i < suites.size(); i++) { retVec.push_back(suites[i]);}
+ return retVec;
+}
+const char* CtsApi::ch_register_arg() { return "ch_register"; }
+
+std::string CtsApi::ch_suites() { return "--ch_suites";}
+const char* CtsApi::ch_suites_arg() { return "ch_suites"; }
+
+std::string CtsApi::ch_drop(int client_handle)
+{
+ std::string ret = "--ch_drop=";
+ ret += boost::lexical_cast<std::string>(client_handle);
+ return ret;
+}
+const char* CtsApi::ch_drop_arg() { return "ch_drop"; }
+
+std::string CtsApi::ch_drop_user(const std::string& user)
+{
+ std::string ret = "--ch_drop_user";
+ if (!user.empty()) {
+ ret += "=";
+ ret += user;
+ }
+ return ret;
+}
+const char* CtsApi::ch_drop_user_arg() { return "ch_drop_user"; }
+
+std::vector<std::string> CtsApi::ch_add( int client_handle, const std::vector<std::string>& suites )
+{
+ std::vector<std::string> retVec; retVec.reserve(suites.size() +1);
+ std::string ret = "--ch_add=";
+ ret += boost::lexical_cast<std::string>(client_handle);
+ retVec.push_back(ret);
+ for(size_t i = 0; i < suites.size(); i++) { retVec.push_back(suites[i]);}
+ return retVec;
+}
+const char* CtsApi::ch_add_arg() { return "ch_add"; }
+
+std::vector<std::string> CtsApi::ch_remove( int client_handle, const std::vector<std::string>& suites )
+{
+ std::vector<std::string> retVec; retVec.reserve(suites.size() +1);
+ std::string ret = "--ch_rem=";
+ ret += boost::lexical_cast<std::string>(client_handle);
+ retVec.push_back(ret);
+ for(size_t i = 0; i < suites.size(); i++) { retVec.push_back(suites[i]); }
+ return retVec;
+}
+const char* CtsApi::ch_remove_arg() { return "ch_rem"; }
+
+std::vector<std::string> CtsApi::ch_auto_add( int client_handle, bool auto_add_new_suites )
+{
+ std::vector<std::string> retVec; retVec.reserve(2);
+ std::string ret = "--ch_auto_add=";
+ ret += boost::lexical_cast<std::string>(client_handle);
+ retVec.push_back(ret);
+ if ( auto_add_new_suites ) retVec.push_back("true");
+ else retVec.push_back("false");
+ return retVec;
+}
+const char* CtsApi::ch_auto_add_arg() { return "ch_auto_add"; }
+
+
+std::vector<std::string> CtsApi::sync(unsigned int client_handle,unsigned int state_change_no, unsigned int modify_change_no )
+{
+ std::vector<std::string> retVec; retVec.reserve(3);
+ std::string ret = "--sync=";
+ ret += boost::lexical_cast<std::string>( client_handle );
+ retVec.push_back(ret);
+ retVec.push_back(boost::lexical_cast<std::string>( state_change_no ));
+ retVec.push_back(boost::lexical_cast<std::string>( modify_change_no ));
+ return retVec;
+}
+const char* CtsApi::syncArg() { return "sync"; }
+
+std::string CtsApi::sync_full(unsigned int client_handle) {
+ std::string ret = "--sync_full=";
+ ret += boost::lexical_cast<std::string>( client_handle );
+ return ret;
+}
+const char* CtsApi::sync_full_arg() { return "sync_full";}
+
+std::vector<std::string> CtsApi::news(unsigned int client_handle, unsigned int state_change_no, unsigned int modify_change_no )
+{
+ std::vector<std::string> retVec; retVec.reserve(3);
+ std::string ret = "--news=";
+ ret += boost::lexical_cast<std::string>( client_handle );
+ retVec.push_back(ret);
+ retVec.push_back(boost::lexical_cast<std::string>( state_change_no ));
+ retVec.push_back(boost::lexical_cast<std::string>( modify_change_no ));
+ return retVec;
+}
+const char* CtsApi::newsArg() { return "news"; }
+
+std::vector<std::string> CtsApi::loadDefs(const std::string& filePath, bool force, bool check_only) {
+
+ std::string ret = "--load="; ret += filePath;
+
+ std::vector<std::string> retVec; retVec.reserve(3);
+ retVec.push_back(ret);
+ if (force) retVec.push_back("force");
+ if (check_only) retVec.push_back("check_only");
+ return retVec;
+}
+const char* CtsApi::loadDefsArg() { return "load"; }
+
+std::string CtsApi::restartServer() { return "--restart";}
+const char* CtsApi::restartServerArg() { return "restart";}
+
+std::string CtsApi::haltServer(bool auto_confirm) { return (auto_confirm) ? "--halt=yes" : "--halt"; }
+const char* CtsApi::haltServerArg() { return "halt"; }
+
+std::string CtsApi::shutdownServer(bool auto_confirm) { return (auto_confirm) ? "--shutdown=yes" : "--shutdown"; }
+const char* CtsApi::shutdownServerArg() { return "shutdown"; }
+
+std::string CtsApi::terminateServer(bool auto_confirm) { return (auto_confirm) ? "--terminate=yes" : "--terminate";}
+const char* CtsApi::terminateServerArg() { return "terminate";}
+
+std::string CtsApi::pingServer() { return "--ping"; }
+const char* CtsApi::pingServerArg() { return "ping"; }
+
+std::string CtsApi::server_load(const std::string& path_to_log_file)
+{
+ std::string ret = "--server_load";
+ if (!path_to_log_file.empty()) {
+ ret += "=";
+ ret += path_to_log_file;
+ }
+ return ret;
+}
+const char* CtsApi::server_load_arg() { return "server_load"; }
+
+
+std::string CtsApi::debug_server_on() { return "--debug_server_on"; }
+const char* CtsApi::debug_server_on_arg() { return "debug_server_on"; }
+std::string CtsApi::debug_server_off() { return "--debug_server_off"; }
+const char* CtsApi::debug_server_off_arg() { return "debug_server_off"; }
+
+
+std::string CtsApi::begin(const std::string& suiteName, bool force) {
+
+ // *both* are optional
+ std::string ret = "--begin";
+ if (suiteName.empty() && !force) {
+ return ret;
+ }
+ if (!suiteName.empty()) {
+ ret += "=";
+ ret += suiteName;
+ }
+ if (force) {
+ if (suiteName.empty()) {
+ ret += "=--force";
+ }
+ else {
+ ret += " --force"; // note the space separator
+ }
+ }
+ return ret;
+}
+const char* CtsApi::beginArg() { return "begin"; }
+
+
+std::string CtsApi::checkJobGenOnly(const std::string& absNodePath)
+{
+ std::string ret = "--checkJobGenOnly";
+ if (!absNodePath.empty()) {
+ ret += "=";
+ ret += absNodePath;
+ }
+ return ret;
+}
+const char* CtsApi::checkJobGenOnlyArg() { return "checkJobGenOnly";}
+
+
+std::string CtsApi::job_gen(const std::string& absNodePath)
+{
+ std::string ret = "--job_gen";
+ if (!absNodePath.empty()) {
+ ret += "=";
+ ret += absNodePath;
+ }
+ return ret;
+}
+const char* CtsApi::job_genArg() { return "job_gen";}
+
+
+std::vector<std::string> CtsApi::check(const std::vector<std::string>& paths)
+{
+ std::vector<std::string> retVec; retVec.reserve(2 + paths.size());
+ retVec.push_back("--check");
+ if (paths.empty()) retVec.push_back("_all_");
+ std::copy(paths.begin(),paths.end(),std::back_inserter(retVec));
+ return retVec;
+}
+std::vector<std::string> CtsApi::check(const std::string& path)
+{
+ if (path.empty()) {
+ return CtsApi::check(std::vector<std::string>());
+ }
+ return CtsApi::check(std::vector<std::string>(1,path));
+}
+const char* CtsApi::check_arg() { return "check";}
+
+std::vector<std::string> CtsApi::delete_node(const std::vector<std::string>& paths, bool force, bool auto_confirm )
+{
+ std::vector<std::string> retVec; retVec.reserve(4 + paths.size());
+ retVec.push_back("--delete");
+ if (paths.empty()) {
+ retVec.push_back("_all_");
+ }
+ if (force) {
+ retVec.push_back("force");
+ }
+ if (auto_confirm) { // By default delete prompts
+ retVec.push_back("yes"); // yes means we don't prompt, and have automatically confirmed the delete
+ }
+ std::copy(paths.begin(),paths.end(),std::back_inserter(retVec));
+ return retVec;
+}
+std::vector<std::string> CtsApi::delete_node(const std::string& absNodePath, bool force, bool auto_confirm )
+{
+ if (absNodePath.empty()) return CtsApi::delete_node(std::vector<std::string>(),force,auto_confirm);
+ return CtsApi::delete_node(std::vector<std::string>(1,absNodePath),force,auto_confirm);
+}
+const char* CtsApi::delete_node_arg() { return "delete";}
+
+
+std::vector<std::string> CtsApi::suspend(const std::vector<std::string>& paths)
+{
+ std::vector<std::string> retVec; retVec.reserve(1 + paths.size());
+ retVec.push_back("--suspend");
+ std::copy(paths.begin(),paths.end(),std::back_inserter(retVec));
+ return retVec;
+}
+std::vector<std::string> CtsApi::suspend(const std::string& path)
+{
+ return CtsApi::suspend(std::vector<std::string>(1,path));
+}
+const char* CtsApi::suspend_arg() { return "suspend";}
+
+
+std::vector<std::string> CtsApi::resume(const std::vector<std::string>& paths)
+{
+ std::vector<std::string> retVec; retVec.reserve(1 + paths.size());
+ retVec.push_back("--resume");
+ std::copy(paths.begin(),paths.end(),std::back_inserter(retVec));
+ return retVec;
+}
+std::vector<std::string> CtsApi::resume(const std::string& path)
+{
+ return CtsApi::resume(std::vector<std::string>(1,path));
+}
+const char* CtsApi::resume_arg() { return "resume";}
+
+
+std::vector<std::string> CtsApi::kill(const std::vector<std::string>& paths)
+{
+ std::vector<std::string> retVec; retVec.reserve(1 + paths.size());
+ retVec.push_back("--kill");
+ std::copy(paths.begin(),paths.end(),std::back_inserter(retVec));
+ return retVec;
+}
+std::vector<std::string> CtsApi::kill(const std::string& path)
+{
+ return CtsApi::kill(std::vector<std::string>(1,path));
+}
+const char* CtsApi::kill_arg() { return "kill";}
+
+
+std::vector<std::string> CtsApi::status(const std::vector<std::string>& paths)
+{
+ std::vector<std::string> retVec; retVec.reserve(1 + paths.size());
+ retVec.push_back("--status");
+ std::copy(paths.begin(),paths.end(),std::back_inserter(retVec));
+ return retVec;
+}
+std::vector<std::string> CtsApi::status(const std::string& path)
+{
+ return CtsApi::status(std::vector<std::string>(1,path));
+}
+const char* CtsApi::statusArg() { return "status";}
+
+
+std::vector<std::string> CtsApi::edit_history(const std::vector<std::string>& paths)
+{
+ std::vector<std::string> retVec; retVec.reserve(1 + paths.size());
+ retVec.push_back("--edit_history");
+ std::copy(paths.begin(),paths.end(),std::back_inserter(retVec));
+ return retVec;
+}
+std::vector<std::string> CtsApi::edit_history(const std::string& path)
+{
+ return CtsApi::edit_history(std::vector<std::string>(1,path));
+}
+const char* CtsApi::edit_history_arg() { return "edit_history";}
+
+
+std::string CtsApi::why(const std::string& absNodePath)
+{
+ if ( absNodePath.empty()) return "--why";
+ std::string ret = "--why=";
+ ret += absNodePath;
+ return ret;
+}
+const char* CtsApi::whyArg() { return "why";}
+
+std::string CtsApi::zombieGet() { return "--zombie_get"; }
+const char* CtsApi::zombieGetArg() { return "zombie_get"; }
+
+std::vector<std::string> CtsApi::zombieFob(const std::string& task_path,const std::string& process_id, const std::string& password)
+{
+ std::vector<std::string> retVec; retVec.reserve(3);
+ std::string ret = "--zombie_fob="; ret += task_path;
+ retVec.push_back(ret);
+ retVec.push_back(process_id); // Note: order is important, even if empty
+ retVec.push_back(password); // Note: order is important, even if empty
+ return retVec;
+}
+std::string CtsApi::zombieFobCli(const std::string& path) { std::string ret = "--zombie_fob="; ret += path; return ret;}
+const char* CtsApi::zombieFobArg() { return "zombie_fob";}
+
+std::vector<std::string> CtsApi::zombieFail(const std::string& task_path,const std::string& process_id, const std::string& password)
+{
+ std::vector<std::string> retVec; retVec.reserve(3);
+ std::string ret = "--zombie_fail="; ret += task_path;
+ retVec.push_back(ret);
+ retVec.push_back(process_id); // Note: order is important, even if empty
+ retVec.push_back(password); // Note: order is important, even if empty
+ return retVec;
+}
+std::string CtsApi::zombieFailCli(const std::string& path) { std::string ret = "--zombie_fail="; ret += path; return ret;}
+const char* CtsApi::zombieFailArg() { return "zombie_fail";}
+
+std::vector<std::string> CtsApi::zombieAdopt(const std::string& task_path,const std::string& process_id, const std::string& password)
+{
+ std::vector<std::string> retVec; retVec.reserve(3);
+ std::string ret = "--zombie_adopt="; ret += task_path;
+ retVec.push_back(ret);
+ retVec.push_back(process_id); // Note: order is important, even if empty
+ retVec.push_back(password); // Note: order is important, even if empty
+ return retVec;
+}
+std::string CtsApi::zombieAdoptCli(const std::string& path) { std::string ret = "--zombie_adopt="; ret += path; return ret;}
+const char* CtsApi::zombieAdoptArg() { return "zombie_adopt";}
+
+std::vector<std::string> CtsApi::zombieRemove(const std::string& task_path,const std::string& process_id, const std::string& password)
+{
+ std::vector<std::string> retVec; retVec.reserve(3);
+ std::string ret = "--zombie_remove="; ret += task_path;
+ retVec.push_back(ret);
+ retVec.push_back(process_id); // Note: order is important, even if empty
+ retVec.push_back(password); // Note: order is important, even if empty
+ return retVec;
+}
+std::string CtsApi::zombieRemoveCli(const std::string& path) { std::string ret = "--zombie_remove="; ret += path; return ret;}
+const char* CtsApi::zombieRemoveArg() { return "zombie_remove";}
+
+std::vector<std::string> CtsApi::zombieBlock(const std::string& task_path,const std::string& process_id, const std::string& password)
+{
+ std::vector<std::string> retVec; retVec.reserve(3);
+ std::string ret = "--zombie_block="; ret += task_path;
+ retVec.push_back(ret);
+ retVec.push_back(process_id); // Note: order is important, even if empty
+ retVec.push_back(password); // Note: order is important, even if empty
+ return retVec;
+}
+std::string CtsApi::zombieBlockCli(const std::string& path) { std::string ret = "--zombie_block="; ret += path; return ret;}
+const char* CtsApi::zombieBlockArg() { return "zombie_block";}
+
+
+std::vector<std::string> CtsApi::zombieKill(const std::string& task_path,const std::string& process_id, const std::string& password)
+{
+ std::vector<std::string> retVec; retVec.reserve(3);
+ std::string ret = "--zombie_kill="; ret += task_path;
+ retVec.push_back(ret);
+ retVec.push_back(process_id); // Note: order is important, even if empty
+ retVec.push_back(password); // Note: order is important, even if empty
+ return retVec;
+}
+std::string CtsApi::zombieKillCli(const std::string& path) { std::string ret = "--zombie_kill="; ret += path; return ret;}
+const char* CtsApi::zombieKillArg() { return "zombie_kill";}
+
+
+std::vector<std::string> CtsApi::requeue(const std::vector<std::string>& paths, const std::string& option)
+{
+ std::vector<std::string> retVec; retVec.reserve(2 + paths.size());
+ retVec.push_back("--requeue");
+ if (!option.empty()) retVec.push_back(option);
+ std::copy(paths.begin(),paths.end(),std::back_inserter(retVec));
+ return retVec;
+}
+std::vector<std::string> CtsApi::requeue(const std::string& absNodePath, const std::string& option)
+{
+ return CtsApi::requeue(std::vector<std::string>(1,absNodePath),option);
+}
+const char* CtsApi::requeueArg() { return "requeue"; }
+
+std::vector<std::string> CtsApi::run(const std::vector<std::string>& paths, bool force)
+{
+ std::vector<std::string> retVec; retVec.reserve(paths.size()+2);
+ retVec.push_back("--run");
+ if (force) retVec.push_back("force");
+ std::copy(paths.begin(),paths.end(),std::back_inserter(retVec));
+ return retVec;
+}
+std::vector<std::string> CtsApi::run(const std::string& absNodePath, bool force)
+{
+ return CtsApi::run(std::vector<std::string>(1,absNodePath),force);
+}
+const char* CtsApi::runArg() { return "run"; }
+
+
+std::vector<std::string> CtsApi::order(const std::string& absNodePath,const std::string& orderType)
+{
+ std::vector<std::string> retVec; retVec.reserve(2);
+ std::string ret = "--order="; ret += absNodePath;
+ retVec.push_back(ret);
+ retVec.push_back(orderType);
+ return retVec;
+}
+const char* CtsApi::orderArg() { return "order"; }
+
+
+std::vector<std::string> CtsApi::replace( const std::string& absNodePath,
+ const std::string& path_to_client_defs,
+ bool create_parents_as_required,
+ bool force)
+{
+ std::vector<std::string> retVec; retVec.reserve(3);
+
+ std::string ret = "--replace="; ret += absNodePath;
+ retVec.push_back(ret);
+ retVec.push_back(path_to_client_defs);
+ if (create_parents_as_required) retVec.push_back("parent");
+ if (force) retVec.push_back("force");
+
+ return retVec;
+}
+const char* CtsApi::replace_arg() { return "replace"; }
+
+
+std::string CtsApi::checkPtDefs(ecf::CheckPt::Mode m, int check_pt_interval, int check_pt_save_time_alarm)
+{
+ std::string ret = "--check_pt";
+ if (m != ecf::CheckPt::UNDEFINED || check_pt_interval != 0 || check_pt_save_time_alarm != 0) ret += "=";
+
+ switch (m) {
+ case ecf::CheckPt::NEVER: ret += "never"; break;
+ case ecf::CheckPt::ON_TIME: ret += "on_time"; break;
+ case ecf::CheckPt::ALWAYS: ret += "always"; break;
+ case ecf::CheckPt::UNDEFINED: break; // leave empty
+ default: assert(false); break;
+ }
+
+ if (check_pt_interval != 0) {
+ if (m != ecf::CheckPt::UNDEFINED) ret += ":";
+ ret += boost::lexical_cast<std::string>(check_pt_interval);
+ }
+ else {
+ if (m == ecf::CheckPt::UNDEFINED && check_pt_save_time_alarm != 0) {
+ ret += "alarm:";
+ ret += boost::lexical_cast<std::string>(check_pt_save_time_alarm);
+ }
+ }
+ return ret;
+}
+const char* CtsApi::checkPtDefsArg() { return "check_pt"; }
+
+std::string CtsApi::restoreDefsFromCheckPt() { return "--restore_from_checkpt"; }
+const char* CtsApi::restoreDefsFromCheckPtArg(){ return "restore_from_checkpt"; }
+
+
+std::string CtsApi::logMsg(const std::string& theMsgToLog) {
+ std::string ret = "--msg=";
+ ret += theMsgToLog;
+ return ret;
+}
+const char* CtsApi::logMsgArg() { return "msg"; }
+
+
+std::vector<std::string> CtsApi::force( const std::vector<std::string>& paths,
+ const std::string& state_or_event,
+ bool recursive,
+ bool set_repeats_to_last_value)
+{
+ std::vector<std::string> retVec; retVec.reserve(paths.size() + 3);
+
+ std::string ret = "--force="; ret += state_or_event;
+ retVec.push_back(ret);
+ if (recursive) retVec.push_back("recursive");
+ if (set_repeats_to_last_value) retVec.push_back("full");
+ std::copy(paths.begin(),paths.end(),std::back_inserter(retVec));
+ return retVec;
+}
+
+std::vector<std::string> CtsApi::force( const std::string& path,
+ const std::string& state_or_event,
+ bool recursive,
+ bool set_repeats_to_last_value)
+{
+ return CtsApi::force(std::vector<std::string>(1,path),state_or_event,recursive,set_repeats_to_last_value);
+}
+const char* CtsApi::forceArg() { return "force"; }
+
+
+std::vector<std::string> CtsApi::freeDep(const std::vector<std::string>& paths,bool trigger, bool all, bool date, bool time) {
+
+ std::vector<std::string> retVec; retVec.reserve(paths.size() + 4);
+
+ retVec.push_back("--free-dep");
+ if (all) retVec.push_back("all");
+ else {
+ if (trigger) retVec.push_back("trigger");
+ if (date) retVec.push_back("date");
+ if (time) retVec.push_back("time");
+ }
+ std::copy(paths.begin(),paths.end(),std::back_inserter(retVec));
+ return retVec;
+}
+std::vector<std::string> CtsApi::freeDep(const std::string& path,bool trigger, bool all, bool date, bool time) {
+
+ return CtsApi::freeDep(std::vector<std::string>(1,path),trigger,all,date,time);
+}
+const char* CtsApi::freeDepArg() { return "free-dep"; }
+
+
+std::vector<std::string> CtsApi::file(const std::string& absNodePath, const std::string& fileType, const std::string& max_lines)
+{
+ std::vector<std::string> retVec; retVec.reserve(3);
+ std::string ret = "--file="; ret += absNodePath;
+ retVec.push_back(ret);
+ retVec.push_back(fileType);
+ retVec.push_back(max_lines);
+ return retVec;
+}
+const char* CtsApi::fileArg() { return "file"; }
+
+
+std::vector<std::string> CtsApi::plug(const std::string& sourcePath, const std::string& destPath)
+{
+ std::vector<std::string> retVec; retVec.reserve(2);
+
+ std::string ret = "--plug="; ret += sourcePath;
+ retVec.push_back(ret);
+ retVec.push_back(destPath);
+
+ return retVec;
+}
+const char* CtsApi::plugArg() { return "plug"; }
+
+std::vector<std::string> CtsApi::alter(
+ const std::vector<std::string>& paths,
+ const std::string& alterType,
+ const std::string& attrType,
+ const std::string& name,
+ const std::string& value)
+{
+ std::vector<std::string> retVec; retVec.reserve(5 + paths.size());
+
+ retVec.push_back("--alter");
+ retVec.push_back(alterType);
+ retVec.push_back(attrType);
+ if ( !name.empty() ) retVec.push_back(name);
+ if ( !value.empty() ) retVec.push_back(value);
+ std::copy(paths.begin(),paths.end(),std::back_inserter(retVec));
+ return retVec;
+}
+std::vector<std::string> CtsApi::alter(
+ const std::string& path,
+ const std::string& alterType,
+ const std::string& attrType,
+ const std::string& name,
+ const std::string& value)
+{
+ return CtsApi::alter(std::vector<std::string>(1,path),alterType,attrType,name,value);
+}
+const char* CtsApi::alterArg() { return "alter"; }
+
+
+std::string CtsApi::reloadwsfile() { return "--reloadwsfile"; }
+const char* CtsApi::reloadwsfileArg() { return "reloadwsfile"; }
+
+std::string CtsApi::group(const std::string& cmds) {
+ std::string ret = "--group=";
+ ret += cmds;
+ return ret;
+}
+const char* CtsApi::groupArg() { return "group"; }
+
+std::vector<std::string> CtsApi::getLog(int lastLine) {
+ std::vector<std::string> retVec; retVec.reserve(2);
+ retVec.push_back("--log=get");
+ if (lastLine != 0) {
+ std::stringstream ss; ss << lastLine;
+ retVec.push_back(ss.str());
+ }
+ return retVec;
+}
+std::vector<std::string> CtsApi::new_log(const std::string& new_path) {
+ std::vector<std::string> retVec; retVec.reserve(2);
+ retVec.push_back("--log=new");
+ if (!new_path.empty()) retVec.push_back(new_path);
+ return retVec;
+}
+std::string CtsApi::clearLog() { return "--log=clear"; }
+std::string CtsApi::flushLog() { return "--log=flush"; }
+std::string CtsApi::get_log_path() { return "--log=path"; }
+
+
+std::string CtsApi::forceDependencyEval() { return "--force-dep-eval";}
+const char* CtsApi::forceDependencyEvalArg() { return "force-dep-eval";}
+
+
+std::vector<std::string> CtsApi::edit_script(
+ const std::string& path_to_task,
+ const std::string& edit_type,
+ const std::string& path_to_script,
+ bool create_alias,
+ bool run
+ )
+{
+ std::vector<std::string> retVec;
+ std::string ret = "--edit_script=";
+ ret += path_to_task;
+ retVec.push_back(ret);
+ retVec.push_back(edit_type);
+ if (!path_to_script.empty()) retVec.push_back(path_to_script);
+ if (create_alias) retVec.push_back("create_alias");
+ if (!run) retVec.push_back("no_run");
+ return retVec;
+}
+const char* CtsApi::edit_script_arg() { return "edit_script";}
+
diff --git a/Base/src/cts/CtsApi.hpp b/Base/src/cts/CtsApi.hpp
new file mode 100644
index 0000000..a3ef970
--- /dev/null
+++ b/Base/src/cts/CtsApi.hpp
@@ -0,0 +1,216 @@
+#ifndef CTS_API_HPP_
+#define CTS_API_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #74 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : (C)lient (t)o (s)erver API
+//============================================================================
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include <string>
+#include <vector>
+#include "NodeFwd.hpp"
+#include "CheckPt.hpp"
+
+// The two variant api must correspond i.e '--get' and 'get' since this is used by boost program options
+// *************************************************************************************
+// Note:: if the api requires multiple parameters it must return a std::vector<std::string>
+// ***************************************************************************************
+class CtsApi : private boost::noncopyable {
+public:
+ static std::string to_string(const std::vector<std::string>& );
+
+ static std::string server_version();
+
+ // For python
+ static defs_ptr load( defs_ptr defs) { return defs;}
+ static std::vector<std::string> loadDefs(const std::string& filePath,bool force,bool check_only);
+ static std::string get(const std::string& absNodePath = "");
+ static std::string get_state(const std::string& absNodePath = "");
+ static std::string migrate(const std::string& absNodePath = "");
+ static std::vector<std::string> sync(unsigned int client_handle, unsigned int state_change_no, unsigned int modify_change_no );
+ static std::string sync_full(unsigned int client_handle);
+ static std::vector<std::string> news(unsigned int client_handle, unsigned int state_change_no, unsigned int modify_change_no );
+
+ static std::vector<std::string> ch_register( bool auto_add_new_suites, const std::vector<std::string>& suites);
+ static std::string ch_suites();
+ static std::string ch_drop(int client_handle);
+ static std::string ch_drop_user(const std::string& user);
+ static std::vector<std::string> ch_add(int client_handle, const std::vector<std::string>& suites);
+ static std::vector<std::string> ch_remove(int client_handle, const std::vector<std::string>& suites);
+ static std::vector<std::string> ch_auto_add(int client_handle, bool auto_add_new_suites);
+ static std::string suites(); // returns list if all suites, and client handles.
+
+ static std::string restartServer();
+ static std::string haltServer(bool auto_confirm = true);
+ static std::string shutdownServer(bool auto_confirm = true);
+ static std::string terminateServer(bool auto_confirm = true);
+ static std::string pingServer();
+ static std::string server_load(const std::string& path_to_log_file);
+ static std::string debug_server_on();
+ static std::string debug_server_off();
+
+ // odd one out, take multi-args but expects string
+ static std::string begin(const std::string& suiteName = "", bool force = false); // no suite begins all suites
+
+ static std::string job_gen(const std::string& absNodePath = "");
+ static std::string checkJobGenOnly(const std::string& absNodePath = "");
+
+ static std::vector<std::string> check(const std::string& absNodePath = "");
+ static std::vector<std::string> check(const std::vector<std::string>& paths);
+ static std::vector<std::string> delete_node(const std::vector<std::string>& paths, bool force = false, bool auto_confirm = true); // no paths specified ,delete all suites, for test
+ static std::vector<std::string> delete_node(const std::string& absNodePath = "", bool force = false, bool auto_confirm = true); // no node specified ,delete all suites, for test
+ static std::vector<std::string> suspend(const std::string& absNodePath);
+ static std::vector<std::string> suspend(const std::vector<std::string>& paths);
+ static std::vector<std::string> resume(const std::string& absNodePath);
+ static std::vector<std::string> resume(const std::vector<std::string>& paths);
+ static std::vector<std::string> kill(const std::string& absNodePath);
+ static std::vector<std::string> kill(const std::vector<std::string>& paths);
+ static std::vector<std::string> status(const std::string& absNodePath);
+ static std::vector<std::string> status(const std::vector<std::string>& paths);
+ static std::vector<std::string> edit_history(const std::vector<std::string>& paths);
+ static std::vector<std::string> edit_history(const std::string& absNodePath);
+
+ static std::string why(const std::string& absNodePath);
+ static std::string zombieGet();
+ static std::vector<std::string> zombieFob(const std::string& task_path,const std::string& process_id, const std::string& password);
+ static std::vector<std::string> zombieFail(const std::string& task_path,const std::string& process_id, const std::string& password);
+ static std::vector<std::string> zombieAdopt(const std::string& task_path,const std::string& process_id, const std::string& password);
+ static std::vector<std::string> zombieRemove(const std::string& task_path,const std::string& process_id, const std::string& password);
+ static std::vector<std::string> zombieBlock(const std::string& task_path,const std::string& process_id, const std::string& password);
+ static std::vector<std::string> zombieKill(const std::string& task_path,const std::string& process_id, const std::string& password);
+ static std::string zombieFobCli(const std::string& task_path);
+ static std::string zombieFailCli(const std::string& task_path);
+ static std::string zombieAdoptCli(const std::string& task_path);
+ static std::string zombieRemoveCli(const std::string& task_path);
+ static std::string zombieBlockCli(const std::string& task_path);
+ static std::string zombieKillCli(const std::string& task_path);
+
+ static std::vector<std::string> replace( const std::string& absNodePath,
+ const std::string& path_to_client_defs,
+ bool create_parents_as_required = true,
+ bool force = false);
+ static std::vector<std::string> requeue(const std::vector<std::string>& paths, const std::string& option/* [ "" | "force" | "abort" ] */);
+ static std::vector<std::string> requeue(const std::string& absNodePath, const std::string& option/* [ "" | "force" | "abort" ] */);
+ static std::vector<std::string> run(const std::vector<std::string>& paths,bool force = false);
+ static std::vector<std::string> run(const std::string& absNodePath,bool force = false);
+ static std::vector<std::string> order(const std::string& absNodePath,const std::string& orderType);
+
+ static std::string checkPtDefs(ecf::CheckPt::Mode m = ecf::CheckPt::UNDEFINED, int check_pt_interval = 0, int check_pt_save_time_alarm = 0);
+ static std::string restoreDefsFromCheckPt();
+
+ static std::vector<std::string> force(const std::vector<std::string>& paths,const std::string& state_or_event,bool recursive = false,bool set_repeats_to_last_value = false);
+ static std::vector<std::string> force(const std::string& path,const std::string& state_or_event,bool recursive = false,bool set_repeats_to_last_value = false);
+
+ static std::vector<std::string> freeDep(const std::vector<std::string>& paths,bool trigger = true, bool all = false, bool date = false, bool time = false);
+ static std::vector<std::string> freeDep(const std::string& absNodePath,bool trigger = true, bool all = false, bool date = false, bool time = false);
+
+ static std::vector<std::string> file(const std::string& absNodePath, const std::string& fileType, const std::string& max_lines);
+ static std::vector<std::string> plug(const std::string& sourcePath, const std::string& destPath);
+
+ static std::vector<std::string> alter(const std::string& path,
+ const std::string& alterType, /* one of [ 'add' | 'change' | 'delete' | 'set_flag' | 'clear_flag' ] */
+ const std::string& attrType,
+ const std::string& name = "",
+ const std::string& value = "");
+ static std::vector<std::string> alter(const std::vector<std::string>& paths,
+ const std::string& alterType, /* one of [ 'add' | 'change' | 'delete' | 'set_flag' | 'clear_flag' ] */
+ const std::string& attrType,
+ const std::string& name = "",
+ const std::string& value = "");
+
+ static std::string reloadwsfile();
+
+ // "expect string of the form "shutdown; get" must be ';' separated
+ static std::string group(const std::string& cmds);
+
+ static std::string logMsg(const std::string& theMsgToLog);
+ static std::vector<std::string> getLog(int lastLines = 0);
+ static std::vector<std::string> new_log(const std::string& new_path);
+ static std::string get_log_path();
+ static std::string clearLog();
+ static std::string flushLog();
+ static std::string forceDependencyEval();
+
+ static std::string stats();
+ static std::string stats_reset();
+ static std::vector<std::string> edit_script(const std::string& path_to_task,
+ const std::string& edit_type,
+ const std::string& path_to_script = "",
+ bool create_alias = false,
+ bool run = true);
+
+ // Only to be used in Cmd
+ static const char* server_version_arg();
+ static const char* statsArg();
+ static const char* stats_reset_arg();
+ static const char* suitesArg();
+ static const char* ch_register_arg();
+ static const char* ch_drop_arg();
+ static const char* ch_suites_arg();
+ static const char* ch_drop_user_arg();
+ static const char* ch_add_arg();
+ static const char* ch_remove_arg();
+ static const char* ch_auto_add_arg();
+
+ static const char* terminateServerArg();
+ static const char* restartServerArg();
+ static const char* haltServerArg();
+ static const char* shutdownServerArg();
+ static const char* pingServerArg();
+ static const char* server_load_arg();
+ static const char* debug_server_on_arg();
+ static const char* debug_server_off_arg();
+
+ static const char* getArg();
+ static const char* get_state_arg();
+ static const char* migrate_arg();
+ static const char* syncArg();
+ static const char* sync_full_arg();
+ static const char* newsArg();
+ static const char* loadDefsArg();
+ static const char* beginArg();
+ static const char* job_genArg();
+ static const char* check_arg();
+ static const char* checkJobGenOnlyArg();
+ static const char* delete_node_arg();
+ static const char* suspend_arg();
+ static const char* resume_arg();
+ static const char* kill_arg();
+ static const char* statusArg();
+ static const char* edit_history_arg();
+ static const char* whyArg();
+ static const char* zombieGetArg();
+ static const char* zombieFobArg();
+ static const char* zombieFailArg();
+ static const char* zombieAdoptArg();
+ static const char* zombieRemoveArg();
+ static const char* zombieBlockArg();
+ static const char* zombieKillArg();
+ static const char* replace_arg();
+ static const char* requeueArg();
+ static const char* runArg();
+ static const char* orderArg();
+ static const char* checkPtDefsArg();
+ static const char* restoreDefsFromCheckPtArg();
+ static const char* logMsgArg();
+ static const char* forceArg();
+ static const char* freeDepArg();
+ static const char* fileArg();
+ static const char* plugArg();
+ static const char* reloadwsfileArg();
+ static const char* groupArg();
+ static const char* forceDependencyEvalArg();
+ static const char* alterArg();
+ static const char* edit_script_arg();
+};
+#endif
diff --git a/Base/src/cts/CtsCmd.cpp b/Base/src/cts/CtsCmd.cpp
new file mode 100644
index 0000000..e879fc2
--- /dev/null
+++ b/Base/src/cts/CtsCmd.cpp
@@ -0,0 +1,409 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #81 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/lexical_cast.hpp>
+
+#include "ClientToServerCmd.hpp"
+#include "AbstractServer.hpp"
+#include "AbstractClientEnv.hpp"
+#include "CtsApi.hpp"
+#include "Jobs.hpp"
+#include "JobsParam.hpp"
+#include "Defs.hpp"
+#include "Log.hpp"
+#include "Ecf.hpp"
+#include "Gnuplot.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+namespace po = boost::program_options;
+
+// *IMPORTANT*: STATS_RESET was introduced in release 4.0.5
+
+std::ostream& CtsCmd::print(std::ostream& os) const
+{
+ switch (api_) {
+ case CtsCmd::GET_ZOMBIES: return user_cmd(os,CtsApi::zombieGet()); break;
+ case CtsCmd::RESTORE_DEFS_FROM_CHECKPT: return user_cmd(os,CtsApi::restoreDefsFromCheckPt()); break;
+ case CtsCmd::RESTART_SERVER: return user_cmd(os,CtsApi::restartServer()); break;
+ case CtsCmd::SHUTDOWN_SERVER: return user_cmd(os,CtsApi::shutdownServer()); break;
+ case CtsCmd::HALT_SERVER: return user_cmd(os,CtsApi::haltServer()); break;
+ case CtsCmd::TERMINATE_SERVER: return user_cmd(os,CtsApi::terminateServer()); break;
+ case CtsCmd::RELOAD_WHITE_LIST_FILE: return user_cmd(os,CtsApi::reloadwsfile()); break;
+ case CtsCmd::FORCE_DEP_EVAL: return user_cmd(os,CtsApi::forceDependencyEval()); break;
+ case CtsCmd::PING: return user_cmd(os,CtsApi::pingServer()); break;
+ case CtsCmd::STATS: return user_cmd(os,CtsApi::stats()); break;
+ case CtsCmd::STATS_RESET: return user_cmd(os,CtsApi::stats_reset()); break;
+ case CtsCmd::SUITES: return user_cmd(os,CtsApi::suites()); break;
+ case CtsCmd::DEBUG_SERVER_ON: return user_cmd(os,CtsApi::debug_server_on()); break;
+ case CtsCmd::DEBUG_SERVER_OFF: return user_cmd(os,CtsApi::debug_server_off()); break;
+ case CtsCmd::SERVER_LOAD: return user_cmd(os,CtsApi::server_load("")); break;
+ case CtsCmd::NO_CMD: assert(false); break;
+ default: assert(false); break;
+ }
+ return os;
+}
+
+bool CtsCmd::equals(ClientToServerCmd* rhs) const
+{
+ CtsCmd* the_rhs = dynamic_cast< CtsCmd* > ( rhs );
+ if ( !the_rhs ) return false;
+ if (api_ != the_rhs->api()) return false;
+ return UserCmd::equals(rhs);
+}
+
+bool CtsCmd::isWrite() const
+{
+ switch (api_) {
+ case CtsCmd::GET_ZOMBIES: return false; break; // read only
+ case CtsCmd::RESTORE_DEFS_FROM_CHECKPT: return true; break; // requires write privilege
+ case CtsCmd::RESTART_SERVER: return true; break; // requires write privilege
+ case CtsCmd::SHUTDOWN_SERVER: return true; break; // requires write privilege
+ case CtsCmd::HALT_SERVER: return true; break; // requires write privilege
+ case CtsCmd::TERMINATE_SERVER: return true; break; // requires write privilege
+ case CtsCmd::RELOAD_WHITE_LIST_FILE:return true; break; // requires write privilege
+ case CtsCmd::FORCE_DEP_EVAL: return true; break; // requires write privilege
+ case CtsCmd::PING: return false; break; // read only
+ case CtsCmd::STATS: return false; break; // read only
+ case CtsCmd::STATS_RESET: return true; break; // requires write privilege
+ case CtsCmd::SUITES: return false; break; // read only
+ case CtsCmd::DEBUG_SERVER_ON: return false; break; // read only
+ case CtsCmd::DEBUG_SERVER_OFF: return false; break; // read only
+ case CtsCmd::SERVER_LOAD: return false; break; // read only
+ case CtsCmd::NO_CMD: assert(false); break;
+ default: assert(false); break;
+ }
+ assert(false);
+ return false;
+}
+
+int CtsCmd::timeout() const
+{
+ if (api_ == CtsCmd::PING) return 10;
+ return ClientToServerCmd::timeout();
+}
+
+const char* CtsCmd::theArg() const
+{
+ switch (api_) {
+ case CtsCmd::GET_ZOMBIES: return CtsApi::zombieGetArg(); break;
+ case CtsCmd::RESTORE_DEFS_FROM_CHECKPT: return CtsApi::restoreDefsFromCheckPtArg(); break;
+ case CtsCmd::RESTART_SERVER: return CtsApi::restartServerArg(); break;
+ case CtsCmd::SHUTDOWN_SERVER: return CtsApi::shutdownServerArg(); break;
+ case CtsCmd::HALT_SERVER: return CtsApi::haltServerArg(); break;
+ case CtsCmd::TERMINATE_SERVER: return CtsApi::terminateServerArg(); break;
+ case CtsCmd::RELOAD_WHITE_LIST_FILE:return CtsApi::reloadwsfileArg(); break;
+ case CtsCmd::FORCE_DEP_EVAL: return CtsApi::forceDependencyEvalArg(); break;
+ case CtsCmd::PING: return CtsApi::pingServerArg(); break;
+ case CtsCmd::STATS: return CtsApi::statsArg(); break;
+ case CtsCmd::STATS_RESET: return CtsApi::stats_reset_arg(); break;
+ case CtsCmd::SUITES: return CtsApi::suitesArg(); break;
+ case CtsCmd::DEBUG_SERVER_ON: return CtsApi::debug_server_on_arg(); break;
+ case CtsCmd::DEBUG_SERVER_OFF: return CtsApi::debug_server_off_arg(); break;
+ case CtsCmd::SERVER_LOAD: return CtsApi::server_load_arg(); break;
+ case CtsCmd::NO_CMD: assert(false); break;
+ default: assert(false); break;
+ }
+ assert(false);
+ return NULL;
+}
+
+STC_Cmd_ptr CtsCmd::doHandleRequest(AbstractServer* as) const
+{
+ switch (api_) {
+ case CtsCmd::GET_ZOMBIES: {
+ as->update_stats().zombie_get_++;
+ return PreAllocatedReply::zombie_get_cmd( as );
+ }
+
+ case CtsCmd::RESTORE_DEFS_FROM_CHECKPT: {
+ as->update_stats().restore_defs_from_checkpt_++;
+ as->restore_defs_from_checkpt(); // this can throw, i.e. if server not halted, or defs has suites, etc
+ break;
+ }
+
+ case CtsCmd::RESTART_SERVER: {
+ as->update_stats().restart_server_++;
+ as->restart();
+ return doJobSubmission( as );
+ }
+ case CtsCmd::SHUTDOWN_SERVER: as->update_stats().shutdown_server_++; as->shutdown(); break;
+ case CtsCmd::HALT_SERVER: as->update_stats().halt_server_++; as->halted(); break;
+ case CtsCmd::TERMINATE_SERVER: as->checkPtDefs(); break;
+ case CtsCmd::RELOAD_WHITE_LIST_FILE: {
+ as->update_stats().reload_white_list_file_++;
+ std::string errorMsg;
+ if (!as->reloadWhiteListFile(errorMsg)) {
+ throw std::runtime_error( errorMsg ) ;
+ }
+ break;
+ }
+ case CtsCmd::FORCE_DEP_EVAL: {
+ // The Default JobsParam does *not* allow Job creation, & hence => does not submit jobs
+ // The default does *not* allow job spawning
+ Jobs jobs(as->defs());
+ JobsParam jobsParam; // create jobs = false, spawn_jobs = false
+ if (!jobs.generate(jobsParam)) throw std::runtime_error( jobsParam.getErrorMsg() ) ;
+ break;
+ }
+ case CtsCmd::PING: as->update_stats().ping_++; break;
+ case CtsCmd::STATS: as->update_stats().stats_++; return PreAllocatedReply::stats_cmd( as ); break;
+ case CtsCmd::STATS_RESET: as->update_stats().reset(); break; // we could have done as->update_stats().stats_++, to honor reset, we dont
+ case CtsCmd::SUITES: as->update_stats().suites_++; return PreAllocatedReply::suites_cmd( as ); break;
+ case CtsCmd::DEBUG_SERVER_ON: as->update_stats().debug_server_on_++; as->debug_server_on(); break;
+ case CtsCmd::DEBUG_SERVER_OFF: as->update_stats().debug_server_off_++; as->debug_server_off(); break;
+ case CtsCmd::SERVER_LOAD: { as->update_stats().server_load_cmd_++;
+ if (Log::instance()) {
+ return PreAllocatedReply::server_load_cmd( Log::instance()->path() );
+ }
+ break;
+ }
+ case CtsCmd::NO_CMD: assert(false); break;
+ default: assert(false); break;
+ }
+
+ return PreAllocatedReply::ok_cmd();
+}
+
+static const char* server_load_desc() {
+ /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+ return
+ "Generates gnuplot files that show the server load graphically.\n"
+ "This is done by parsing the log file. If no log file is provided,\n"
+ "then the log file path is obtained from the server. If the returned\n"
+ "log file path is not accessible an error is returned\n"
+ "This command produces a three files in the CWD.\n"
+ " o <host>.<port>.gnuplot.dat\n"
+ " o <host>.<port>.gnuplot.script\n"
+ " o <host>.<port>.png\n\n"
+ "The generated script can be manually changed, to see different rendering\n"
+ "effects. i.e. just run 'gnuplot <host>.<port>.gnuplot.script'\n\n"
+ " arg1 = <optional> path to log file\n\n"
+ "If the path to log file is known, it is *preferable* to use this,\n"
+ "rather than requesting the log path from the server.\n\n"
+ "Usage:\n"
+ " --server_load=/path/to_log_file # Parses log and generate gnuplot files\n"
+ " --server_load # Log file path is requested from server\n"
+ " # which is then used to generate gnuplot files\n"
+ " # *AVOID* if log file path is accessible\n\n"
+ "Now use any png viewer to see the output i.e\n\n"
+ "> display <host>.<port>.png\n"
+ "> feh <host>.<port>.png\n"
+ "> eog <host>.<port>.png\n"
+ "> xdg-open <host>.<port>.png\n"
+ "> w3m <host>.<port>.png\n"
+ ;
+}
+
+void CtsCmd::addOption(boost::program_options::options_description& desc) const
+{
+ switch (api_) {
+ case CtsCmd::GET_ZOMBIES:{
+ desc.add_options()(CtsApi::zombieGetArg(),
+ "Returns the list of zombies from the server.\n"
+ "Results reported to standard output."
+ );
+ break;
+ }
+ case CtsCmd::RESTORE_DEFS_FROM_CHECKPT:{
+ desc.add_options()(CtsApi::restoreDefsFromCheckPtArg(),
+ "Ask the server to load the definition from an check pt file.\n"
+ "The server must be halted and the definition in the server must be deleted\n"
+ "first, otherwise an error is returned"
+ );
+ break;
+ }
+ case CtsCmd::RESTART_SERVER:{
+ desc.add_options()( CtsApi::restartServerArg(),
+ "Start job scheduling, communication with jobs, and respond to all requests.\n"
+ "The following table shows server behaviour in the different states.\n"
+ "|----------------------------------------------------------------------------------|\n"
+ "| Server State | User Request | Task Request |Job Scheduling | Auto-Check-pointing |\n"
+ "|--------------|--------------|--------------|---------------|---------------------|\n"
+ "| RUNNING | yes | yes | yes | yes |\n"
+ "| SHUTDOWN | yes | yes | no | yes |\n"
+ "| HALTED | yes | no | no | no |\n"
+ "|--------------|--------------|--------------|---------------|---------------------|"
+ );
+ break;
+ }
+ case CtsCmd::SHUTDOWN_SERVER: {
+ desc.add_options()( CtsApi::shutdownServerArg(),po::value< string >()->implicit_value( string("") ),
+ "Stop server from scheduling new jobs.\n"
+ " arg1 = yes(optional) # use to bypass confirmation prompt,i.e\n"
+ " --shutdown=yes\n"
+ "The following table shows server behaviour in the different states.\n"
+ "|----------------------------------------------------------------------------------|\n"
+ "| Server State | User Request | Task Request |Job Scheduling | Auto-Check-pointing |\n"
+ "|--------------|--------------|--------------|---------------|---------------------|\n"
+ "| RUNNING | yes | yes | yes | yes |\n"
+ "| SHUTDOWN | yes | yes | no | yes |\n"
+ "| HALTED | yes | no | no | no |\n"
+ "|--------------|--------------|--------------|---------------|---------------------|"
+ );
+ break;
+ }
+ case CtsCmd::HALT_SERVER: {
+ desc.add_options()( CtsApi::haltServerArg(),po::value< string >()->implicit_value( string("") ),
+ "Stop server communication with jobs, and new job scheduling.\n"
+ "Also stops automatic check pointing\n"
+ " arg1 = yes(optional) # use to bypass confirmation prompt,i.e.\n"
+ " --halt=yes\n"
+ "The following table shows server behaviour in the different states.\n"
+ "|----------------------------------------------------------------------------------|\n"
+ "| Server State | User Request | Task Request |Job Scheduling | Auto-Check-pointing |\n"
+ "|--------------|--------------|--------------|---------------|---------------------|\n"
+ "| RUNNING | yes | yes | yes | yes |\n"
+ "| SHUTDOWN | yes | yes | no | yes |\n"
+ "| HALTED | yes | no | no | no |\n"
+ "|--------------|--------------|--------------|---------------|---------------------|"
+ );
+ break;
+ }
+ case CtsCmd::TERMINATE_SERVER:{
+ desc.add_options()( CtsApi::terminateServerArg(),po::value< string >()->implicit_value( string("") ),
+ "Terminate the server.\n"
+ " arg1 = yes(optional) # use to bypass confirmation prompt.i.e\n"
+ " --terminate=yes"
+ );
+ break;
+ }
+ case CtsCmd::RELOAD_WHITE_LIST_FILE:{
+ desc.add_options()( CtsApi::reloadwsfileArg(),
+ "Reload the white list file.\n"
+ "The white list file is used to authenticate 'user' commands.\n"
+ "File path is specified by ECF_LISTS environment, read by the server on startup.\n"
+ "If ECF_LISTS is not specified, then by default it will open <host>.<port>.ecf.lists\n"
+ "On startup, if the file is not present or is present but is empty (i.e just contains the version number)\n"
+ "then all users have read/write access\n"
+ "However on reload it will raises an error if file does not exist, or fails to parse\n"
+ "Expected format for this file is:\n\n"
+ "# comment\n"
+ "4.4.14 # version number, this must be present, even if no users specified\n\n"
+ "# Users with read/write access\n"
+ "user1 # comment\n"
+ "user2 # comment\n\n"
+ "* # use this form if you want all users to have read/write access\n\n"
+ "# Users with read access, must have - before user name\n"
+ "-user3 # comment\n"
+ "-user4\n\n"
+ "-* # use this form if you want all users to have read access"
+ );
+ break;
+ }
+ case CtsCmd::FORCE_DEP_EVAL:{
+ desc.add_options()( CtsApi::forceDependencyEvalArg(),
+ "Force dependency evaluation. Used for DEBUG only."
+ );
+ break;
+ }
+ case CtsCmd::PING:{
+ desc.add_options()( CtsApi::pingServerArg(),
+ "Check if server is running on given host/port. Result reported to standard output.\n"
+ "Usage:\n"
+ " --ping --host=mach --port=3144 # Check if server alive on host mach & port 3144\n"
+ " --ping --host=fred # Check if server alive on host fred and port ECF_PORT,\n"
+ " # otherwise default port of 3141\n"
+ " --ping # Check if server alive by using environment variables\n"
+ " # ECF_NODE and ECF_PORT\n"
+ "If ECF_NODE not defined uses 'localhost', if ECF_PORT not defined assumes 3141"
+ );
+ break;
+ }
+ case CtsCmd::STATS:{
+ desc.add_options()( CtsApi::statsArg(),
+ "Returns the server statistics."
+ );
+ break;
+ }
+ case CtsCmd::STATS_RESET:{
+ desc.add_options()( CtsApi::stats_reset_arg(),
+ "Resets the server statistics."
+ );
+ break;
+ }
+ case CtsCmd::SUITES:{
+ desc.add_options()( CtsApi::suitesArg(),
+ "Returns the list of suites, in the order defined in the server."
+ );
+ break;
+ }
+ case CtsCmd::DEBUG_SERVER_ON: {
+ desc.add_options()( CtsApi::debug_server_on_arg(),
+ "Enables debug output from the server"
+ );
+ break;
+ }
+ case CtsCmd::DEBUG_SERVER_OFF: {
+ desc.add_options()( CtsApi::debug_server_off_arg(),
+ "Disables debug output from the server"
+ );
+ break;
+ }
+ case CtsCmd::SERVER_LOAD: {
+ desc.add_options()( CtsApi::server_load_arg(),po::value< std::string >()->implicit_value( string("") ), server_load_desc() );
+ break;
+ }
+ case CtsCmd::NO_CMD: assert(false); break;
+ default: assert(false); break;
+ }
+}
+
+bool CtsCmd::handleRequestIsTestable() const {
+ if (api_ == CtsCmd::TERMINATE_SERVER) return false;
+ if (api_ == CtsCmd::RESTORE_DEFS_FROM_CHECKPT) return false;
+ return true;
+}
+
+void CtsCmd::create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* ac ) const
+{
+ if (ac->debug()) cout << " CtsCmd::create api = '" << api_ << "'.\n";
+
+ assert( api_ != CtsCmd::NO_CMD);
+
+ if (api_ == CtsCmd::HALT_SERVER || api_ == CtsCmd::SHUTDOWN_SERVER || api_ == CtsCmd::TERMINATE_SERVER) {
+
+ std::string do_prompt = vm[ theArg() ].as< std::string > ();
+ if (do_prompt.empty()) {
+ if (api_ == CtsCmd::HALT_SERVER) prompt_for_confirmation("Are you sure you want to halt the server ? ");
+ else if (api_ == CtsCmd::SHUTDOWN_SERVER) prompt_for_confirmation("Are you sure you want to shut down the server ? ");
+ else prompt_for_confirmation("Are you sure you want to terminate the server ? ");
+ }
+ else if ( do_prompt != "yes" )
+ throw std::runtime_error("Halt, shutdown and terminate expected 'yes' as the only argument to bypass the confirmation prompt");
+ }
+ else if ( api_ == CtsCmd::SERVER_LOAD) {
+
+ std::string log_file = vm[ theArg() ].as< std::string > ();
+ if (ac->debug()) std::cout << " CtsCmd::create CtsCmd::SERVER_LOAD " << log_file << "\n";
+
+ if (!log_file.empty()) {
+
+ // testing client interface
+ if (ac->under_test()) return;
+
+ // No need to call server. Parse the log file to create gnu_plot file.
+ Gnuplot gnuplot(log_file,ac->host(),ac->port() );
+ gnuplot.show_server_load();
+
+ return; // Don't create command, since with log file, it is client specific only
+ }
+ }
+ cmd = Cmd_ptr(new CtsCmd( api_ ));
+}
+
+std::ostream& operator<<(std::ostream& os, const CtsCmd& c) { return c.print(os); }
diff --git a/Base/src/cts/CtsCmdRegistry.cpp b/Base/src/cts/CtsCmdRegistry.cpp
new file mode 100644
index 0000000..1950391
--- /dev/null
+++ b/Base/src/cts/CtsCmdRegistry.cpp
@@ -0,0 +1,145 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #52 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/make_shared.hpp>
+#include "CtsCmdRegistry.hpp"
+#include "ClientToServerCmd.hpp"
+#include "AbstractClientEnv.hpp"
+namespace po = boost::program_options;
+
+
+CtsCmdRegistry::CtsCmdRegistry(bool addGroupCmd)
+{
+ // If a new client to server command is added. Make sure to add it here.
+ // Could have used static initialisation' but this is less problematic.
+
+ /// The order dictates how the --help is shown *BUT* Since we traverse this list.
+ /// Place the command which require the fastest response first.
+ vec_.reserve(70);
+
+ vec_.push_back( boost::make_shared<CSyncCmd>(CSyncCmd::NEWS,0,0,0));
+ vec_.push_back( boost::make_shared<CSyncCmd>(CSyncCmd::SYNC,0,0,0));
+ vec_.push_back( boost::make_shared<CSyncCmd>(0)); // SYNC_FULL
+ vec_.push_back( boost::make_shared<CtsNodeCmd>(CtsNodeCmd::GET));
+ vec_.push_back( boost::make_shared<CtsNodeCmd>(CtsNodeCmd::GET_STATE));
+ vec_.push_back( boost::make_shared<CtsNodeCmd>(CtsNodeCmd::MIGRATE));
+ vec_.push_back( boost::make_shared<CheckPtCmd>());
+ vec_.push_back( boost::make_shared<CtsCmd>(CtsCmd::PING));
+ vec_.push_back( boost::make_shared<CtsCmd>(CtsCmd::RESTORE_DEFS_FROM_CHECKPT));
+ vec_.push_back( boost::make_shared<CtsCmd>(CtsCmd::RESTART_SERVER));
+ vec_.push_back( boost::make_shared<CtsCmd>(CtsCmd::HALT_SERVER));
+ vec_.push_back( boost::make_shared<CtsCmd>(CtsCmd::SHUTDOWN_SERVER));
+ vec_.push_back( boost::make_shared<CtsCmd>(CtsCmd::TERMINATE_SERVER));
+ vec_.push_back( boost::make_shared<CtsCmd>(CtsCmd::RELOAD_WHITE_LIST_FILE));
+ vec_.push_back( boost::make_shared<CtsCmd>(CtsCmd::FORCE_DEP_EVAL));
+ vec_.push_back( boost::make_shared<CtsCmd>(CtsCmd::STATS));
+ vec_.push_back( boost::make_shared<CtsCmd>(CtsCmd::STATS_RESET));
+ vec_.push_back( boost::make_shared<CtsCmd>(CtsCmd::DEBUG_SERVER_ON));
+ vec_.push_back( boost::make_shared<CtsCmd>(CtsCmd::DEBUG_SERVER_OFF));
+ vec_.push_back( boost::make_shared<CtsCmd>(CtsCmd::SERVER_LOAD));
+ vec_.push_back( boost::make_shared<CtsNodeCmd>(CtsNodeCmd::JOB_GEN));
+ vec_.push_back( boost::make_shared<CtsNodeCmd>(CtsNodeCmd::CHECK_JOB_GEN_ONLY));
+ vec_.push_back( boost::make_shared<PathsCmd>(PathsCmd::DELETE));
+ vec_.push_back( boost::make_shared<PathsCmd>(PathsCmd::SUSPEND));
+ vec_.push_back( boost::make_shared<PathsCmd>(PathsCmd::RESUME));
+ vec_.push_back( boost::make_shared<PathsCmd>(PathsCmd::KILL));
+ vec_.push_back( boost::make_shared<PathsCmd>(PathsCmd::STATUS));
+ vec_.push_back( boost::make_shared<PathsCmd>(PathsCmd::CHECK));
+ vec_.push_back( boost::make_shared<PathsCmd>(PathsCmd::EDIT_HISTORY));
+ vec_.push_back( boost::make_shared<ZombieCmd>(ecf::User::FOB));
+ vec_.push_back( boost::make_shared<ZombieCmd>(ecf::User::FAIL));
+ vec_.push_back( boost::make_shared<ZombieCmd>(ecf::User::ADOPT));
+ vec_.push_back( boost::make_shared<ZombieCmd>(ecf::User::BLOCK));
+ vec_.push_back( boost::make_shared<ZombieCmd>(ecf::User::REMOVE));
+ vec_.push_back( boost::make_shared<ZombieCmd>(ecf::User::KILL));
+ vec_.push_back( boost::make_shared<CtsCmd>(CtsCmd::GET_ZOMBIES));
+ vec_.push_back( boost::make_shared<CtsCmd>(CtsCmd::SUITES));
+ vec_.push_back( boost::make_shared<ClientHandleCmd>(ClientHandleCmd::REGISTER));
+ vec_.push_back( boost::make_shared<ClientHandleCmd>(ClientHandleCmd::DROP));
+ vec_.push_back( boost::make_shared<ClientHandleCmd>(ClientHandleCmd::DROP_USER));
+ vec_.push_back( boost::make_shared<ClientHandleCmd>(ClientHandleCmd::ADD));
+ vec_.push_back( boost::make_shared<ClientHandleCmd>(ClientHandleCmd::REMOVE));
+ vec_.push_back( boost::make_shared<ClientHandleCmd>(ClientHandleCmd::AUTO_ADD));
+ vec_.push_back( boost::make_shared<ClientHandleCmd>(ClientHandleCmd::SUITES));
+ vec_.push_back( boost::make_shared<LogCmd>());
+ vec_.push_back( boost::make_shared<ServerVersionCmd>());
+ vec_.push_back( boost::make_shared<LogMessageCmd>());
+ vec_.push_back( boost::make_shared<BeginCmd>());
+ vec_.push_back( boost::make_shared<InitCmd>());
+ vec_.push_back( boost::make_shared<CompleteCmd>());
+ vec_.push_back( boost::make_shared<AbortCmd>());
+ vec_.push_back( boost::make_shared<CtsWaitCmd>());
+ vec_.push_back( boost::make_shared<EventCmd>());
+ vec_.push_back( boost::make_shared<MeterCmd>());
+ vec_.push_back( boost::make_shared<LabelCmd>());
+ vec_.push_back( boost::make_shared<RequeueNodeCmd>());
+ vec_.push_back( boost::make_shared<OrderNodeCmd>());
+ vec_.push_back( boost::make_shared<RunNodeCmd>());
+ vec_.push_back( boost::make_shared<ForceCmd>());
+ vec_.push_back( boost::make_shared<FreeDepCmd>());
+ vec_.push_back( boost::make_shared<LoadDefsCmd>());
+ vec_.push_back( boost::make_shared<ReplaceNodeCmd>());
+ vec_.push_back( boost::make_shared<CFileCmd>());
+ vec_.push_back( boost::make_shared<EditScriptCmd>());
+ vec_.push_back( boost::make_shared<AlterCmd>());
+ vec_.push_back( boost::make_shared<PlugCmd>());
+ // Note: we deliberately do not add MoveCmd, as it should not appear in the public api
+ // It is created on the fly by the PlugCmd
+
+ /// Command that can *ONLY* be used in a group command
+ vec_.push_back( boost::make_shared<CtsNodeCmd>(CtsNodeCmd::WHY));
+ vec_.push_back( boost::make_shared<ShowCmd>());
+ if (addGroupCmd) vec_.push_back( boost::make_shared<GroupCTSCmd>());
+}
+
+bool CtsCmdRegistry::parse(Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const
+{
+ size_t vec_size = vec_.size();
+ for(size_t i = 0; i < vec_size; i++) {
+
+ if ( vm.count( vec_[i]->theArg() ) ) {
+
+ if (clientEnv->debug()) std::cout << " CtsCmdRegistry::parse matched with registered command " << vec_[i]->theArg() << "\n";
+
+ vec_[i]->create(cmd,vm,clientEnv);
+ return true;
+ }
+ }
+ return false;
+}
+
+void CtsCmdRegistry::addAllOptions(boost::program_options::options_description& desc) const
+{
+ addCmdOptions(desc);
+ addHelpOption(desc);
+}
+
+void CtsCmdRegistry::addCmdOptions(boost::program_options::options_description& desc) const
+{
+ size_t vec_size = vec_.size();
+ for(size_t i = 0; i < vec_size; i++) {
+ vec_[i]->addOption(desc);
+ }
+}
+
+void CtsCmdRegistry::addHelpOption(boost::program_options::options_description& desc) const
+{
+ /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+ desc.add_options() ("help,h",po::value< std::string >()->implicit_value( std::string("") ), "Produce help message");
+ desc.add_options() ("version,v", "Show ecflow client version number, and version of the boost library used" );
+ desc.add_options() ("debug,d",
+ "Dump out client environment settings for debug\n"
+ "Set environment variable ECF_DEBUG_CLIENT for additional debug" );
+}
diff --git a/Base/src/cts/CtsCmdRegistry.hpp b/Base/src/cts/CtsCmdRegistry.hpp
new file mode 100644
index 0000000..d52f818
--- /dev/null
+++ b/Base/src/cts/CtsCmdRegistry.hpp
@@ -0,0 +1,56 @@
+#ifndef CTS_CMD_REGISTRY_HPP_
+#define CTS_CMD_REGISTRY_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Registration of all the client to server commands
+// This allows us to parse the arg associated with
+// commands in this category. The idea being to keep
+// new commands functionality in one place.
+// Any new client to server commands that are created
+// must be added to this class.
+//============================================================================
+
+#include <boost/noncopyable.hpp>
+#include <boost/program_options.hpp>
+#include <vector>
+#include "Cmd.hpp"
+
+class AbstractClientEnv;
+
+class CtsCmdRegistry : private boost::noncopyable {
+public:
+ CtsCmdRegistry(bool addGroupCmd = true );
+
+ /// These option describe the arguments for each of the commands
+ /// They also can be presented to the user via --help option.
+ void addAllOptions(boost::program_options::options_description& desc) const;
+ void addCmdOptions(boost::program_options::options_description& desc) const;
+
+ /// Parse arguments given in 'vm' and use that to create a command
+ /// that will be sent to the server. Will throw std::runtime_error for errors
+ /// Returns true if command line argument specified via 'vm', matches one of the
+ /// registered command.
+ /// *** This allows us to distinguish between where we match with a registered
+ /// *** command, but do *NOT* set Cmd_ptr, ie since its a client specific command
+ /// *** i.e there is no need to send it to the server
+ bool parse( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const;
+
+private:
+ std::vector<Cmd_ptr > vec_;
+
+ void addHelpOption(boost::program_options::options_description& desc) const;
+};
+
+#endif
diff --git a/Base/src/cts/CtsNodeCmd.cpp b/Base/src/cts/CtsNodeCmd.cpp
new file mode 100644
index 0000000..e5d3e59
--- /dev/null
+++ b/Base/src/cts/CtsNodeCmd.cpp
@@ -0,0 +1,338 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #70 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/make_shared.hpp>
+
+#include "ClientToServerCmd.hpp"
+#include "AbstractServer.hpp"
+#include "AbstractClientEnv.hpp"
+#include "CtsApi.hpp"
+#include "Defs.hpp"
+#include "Task.hpp"
+#include "JobCreationCtrl.hpp"
+#include "Ecf.hpp"
+#include "Jobs.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+namespace po = boost::program_options;
+
+bool CtsNodeCmd::why_cmd( std::string& nodePath) const
+{
+ if (api_ == CtsNodeCmd::WHY) {
+ nodePath = absNodePath_;
+ return true;
+ }
+ return false;
+}
+
+std::ostream& CtsNodeCmd::print(std::ostream& os) const
+{
+ switch (api_) {
+ case CtsNodeCmd::GET: {
+ std::stringstream ss;
+ ss << CtsApi::get(absNodePath_);
+#ifdef DEBUG
+ if (Ecf::server()) ss << " [server(" << Ecf::state_change_no() << " " << Ecf::modify_change_no() << ")]";
+#endif
+ return user_cmd(os,ss.str());
+ }
+ case CtsNodeCmd::GET_STATE: return user_cmd(os,CtsApi::get_state(absNodePath_)); break;
+ case CtsNodeCmd::MIGRATE: return user_cmd(os,CtsApi::migrate(absNodePath_)); break;
+ case CtsNodeCmd::JOB_GEN: return user_cmd(os,CtsApi::job_gen(absNodePath_)); break;
+ case CtsNodeCmd::CHECK_JOB_GEN_ONLY: return user_cmd(os,CtsApi::checkJobGenOnly(absNodePath_)); break;
+ case CtsNodeCmd::WHY: return user_cmd(os,CtsApi::why(absNodePath_)); break;
+ case CtsNodeCmd::NO_CMD: break;
+ default: throw std::runtime_error("CtsNodeCmd::print: Unrecognised command");break;
+ }
+ return os;
+}
+
+bool CtsNodeCmd::equals(ClientToServerCmd* rhs) const
+{
+ CtsNodeCmd* the_rhs = dynamic_cast< CtsNodeCmd* > ( rhs );
+ if ( !the_rhs ) return false;
+ if (api_ != the_rhs->api()) return false;
+ if (absNodePath_ != the_rhs->absNodePath()) return false;
+ return UserCmd::equals(rhs);
+}
+
+bool CtsNodeCmd::isWrite() const
+{
+ switch (api_) {
+ case CtsNodeCmd::GET: return false; break; // read only
+ case CtsNodeCmd::GET_STATE: return false; break; // read only
+ case CtsNodeCmd::MIGRATE: return false; break; // read only
+ case CtsNodeCmd::JOB_GEN: return true; break; // requires write privilege
+ case CtsNodeCmd::CHECK_JOB_GEN_ONLY:return false; break; // read only
+ case CtsNodeCmd::WHY: return false; break; // read only
+ case CtsNodeCmd::NO_CMD: break;
+ default: throw std::runtime_error("CtsNodeCmd::isWrite: Unrecognised command");break;
+ }
+ assert(false);
+ return false;
+}
+
+const char* CtsNodeCmd::theArg() const
+{
+ switch (api_) {
+ case CtsNodeCmd::GET: return CtsApi::getArg(); break;
+ case CtsNodeCmd::GET_STATE: return CtsApi::get_state_arg(); break;
+ case CtsNodeCmd::MIGRATE: return CtsApi::migrate_arg(); break;
+ case CtsNodeCmd::JOB_GEN: return CtsApi::job_genArg(); break;
+ case CtsNodeCmd::CHECK_JOB_GEN_ONLY: return CtsApi::checkJobGenOnlyArg(); break;
+ case CtsNodeCmd::WHY: return CtsApi::whyArg(); break;
+ case CtsNodeCmd::NO_CMD: break;
+ default: throw std::runtime_error("CtsNodeCmd::theArg: Unrecognised command");break;
+ }
+ assert(false);
+ return NULL;
+}
+
+PrintStyle::Type_t CtsNodeCmd::show_style() const
+{
+ if (api_ == CtsNodeCmd::GET) return PrintStyle::DEFS;
+ else if (api_ == CtsNodeCmd::GET_STATE) return PrintStyle::STATE;
+ else if (api_ == CtsNodeCmd::MIGRATE) return PrintStyle::MIGRATE;
+ return ClientToServerCmd::show_style();
+}
+
+
+int CtsNodeCmd::timeout() const
+{
+ if (api_ == CtsNodeCmd::GET) {
+ return time_out_for_load_sync_and_get();
+ }
+ return ClientToServerCmd::timeout();
+}
+
+STC_Cmd_ptr CtsNodeCmd::doHandleRequest(AbstractServer* as) const
+{
+ switch (api_) {
+
+ case CtsNodeCmd::GET:
+ case CtsNodeCmd::MIGRATE:
+ case CtsNodeCmd::GET_STATE: {
+ // The client will configure the output display
+ as->update_stats().get_defs_++;
+ if ( absNodePath_.empty() ) {
+ // with migrate we need to get edit history.
+ return PreAllocatedReply::defs_cmd(as,(api_ == MIGRATE));
+ }
+ // however request for a particular node, thats not there, treated as an error
+ node_ptr theNodeToReturn = find_node(as,absNodePath_);
+ return PreAllocatedReply::node_cmd(as,theNodeToReturn);
+ }
+
+ case CtsNodeCmd::CHECK_JOB_GEN_ONLY: {
+ as->update_stats().node_check_job_gen_only_++;
+ job_creation_ctrl_ptr jobCtrl = boost::make_shared<JobCreationCtrl>();
+ jobCtrl->set_node_path(absNodePath_);
+ as->defs()->check_job_creation(jobCtrl);
+ if (! jobCtrl->get_error_msg().empty() ) {
+ throw std::runtime_error( jobCtrl->get_error_msg() ) ;
+ }
+ break;
+ }
+
+ case CtsNodeCmd::JOB_GEN: {
+ as->update_stats().node_job_gen_++;
+
+ if (as->state() == SState::RUNNING) {
+
+ if ( absNodePath_.empty() ) {
+ // If no path specified do a full job generation over all suites
+ return doJobSubmission( as );
+ }
+
+ // Generate jobs for the given node, downwards
+ node_ptr theNode = find_node_for_edit(as,absNodePath_);
+ Jobs jobs(theNode.get());
+ jobs.generate();
+ }
+ break;
+ }
+
+ case CtsNodeCmd::WHY: {
+ /// Why is actually invoked on client side.
+ /// Added as a command because:
+ /// o documentation
+ /// o allows use with group command, without any other changes
+ break;
+ }
+
+ case CtsNodeCmd::NO_CMD:
+ default: throw std::runtime_error("CtsNodeCmd::doHandleRequest: Unrecognised command");break;
+ }
+
+ return PreAllocatedReply::ok_cmd();
+}
+
+static const char* job_gen_only_desc() {
+ return
+ "Test hierarchical Job generation only, for chosen Node.\n"
+ "The jobs are generated independent of the dependencies\n"
+ "This will generate the jobs *only*, i.e. no job submission. Used for checking job generation only\n"
+ " arg = node path | arg = NULL\n"
+ " If no node path specified generates for all Tasks in the definition. For Test only"
+ ;
+}
+
+static const char* job_gen_desc() { // dependency_dependent_job_submission
+ return
+ "Job submission for chosen Node *based* on dependencies.\n"
+ "The server traverses the node tree every 60 seconds, and if the dependencies are free\n"
+ "does job generation and submission. Sometimes the user may free time/date dependencies\n"
+ "to avoid waiting for the server poll, this commands allows early job generation\n"
+ " arg = node path | arg = NULL\n"
+ " If no node path specified generates for full definition."
+ ;
+}
+
+static const char* why_desc() {
+ return
+ "Show the reason why a node is not running.\n"
+ "Can only be used with the group command. The group command must include a \n"
+ "'get' command(i.e returns the server defs)\n"
+ "The why command take a optional string argument representing a node path\n"
+ "Will return reason why the node is holding and for all its children.\n"
+ "If no arguments supplied will report on all nodes\n"
+ " arg = node path | arg = NULL\n"
+ "Usage:\n"
+ " --group=\"get; why\" # returns why for all holding nodes\n"
+ " --group=\"get; why=/suite/family\" # returns why for a specific node"
+ ;
+}
+
+static const char* get_desc() {
+ return
+ "Get the suite definition or node tree in form that is re-parse able\n"
+ "Get all suite node tree's from the server and write to standard out.\n"
+ "The output is parse-able, and can be used to re-load the definition\n"
+ " arg = NULL | arg = node path\n"
+ "Usage:\n"
+ " --get # gets the definition from the server,and writes to standard out\n"
+ " --get=/s1 # gets the suite from the server,and writes to standard out"
+ ;
+}
+
+static const char* get_state_desc() {
+ return
+ "Get state data. For the whole suite definition or individual nodes.\n"
+ "This will include event, meter, node state, trigger and time state.\n"
+ "The output is written to standard out.\n"
+ " arg = NULL | arg = node path\n"
+ "Usage:\n"
+ " --get_state # gets the definition from the server,and writes to standard out\n"
+ " --get_state=/s1 # gets the suite from the server,and writes to standard out"
+ ;
+}
+
+const char* migrate_desc() {
+ return "Used to print state of the definition returned from the server to standard output.\n"
+ "The node state is shown in the comments.\n"
+ "This format allows the definition to be migrated to future version of ecflow.\n"
+ "The output includes edit history but excludes externs.\n"
+ "When the definition is reloaded *NO* checking is done.\n"
+ "\n"
+ "The following shows a summary of the features associated with each choice:\n"
+ " --get --get_state --migrate\n"
+ "Auto generate externs Yes Yes No\n"
+ "Checking on reload Yes Yes No\n"
+ "Edit History No No Yes\n"
+ "Show trigger AST No Yes No\n"
+ "\n\n"
+ "Migration is required when the release number changes:\n"
+ " <release-number>.<major>.<minor>\n"
+ " 6.1.7 -> 7.0.0\n"
+ "as the checkpoint files are not compatible.\n\n"
+ "To actually migrate to a newer version of ecflow, follow these steps:\n\n"
+ " Steps for Old server:\n"
+ " o shutdown\n"
+ " # ecflow_client --shutdown\n"
+ " o suspend all suites\n"
+ " # CL=\"ecflow_client --port=32222 --host=vsms1\"\n"
+ " # for s in $($CL --suites); do $CL --suspend=/$s; done\n"
+ " o wait for active/submitted tasks to complete\n"
+ " o halt the server\n"
+ " # ecflow_client --halt=yes\n"
+ " o Use --migrate to dump state and structure to a file\n"
+ " # ecflow_client --migrate > all_suites.def\n"
+ " o terminate server *or* leave server running but start new server on different machine\n"
+ " to avoid port number clash.\n"
+ " o remove checkpt and backup checkpt files, to prevent new server from loading them\n"
+ " *Only* applicable if starting new server on same machine\n\n"
+ " Steps for New server:\n"
+ " o start server\n"
+ " o load the migration file\n"
+ " # ecflow_client --load=all_suites.def\n"
+ " o set server running:\n"
+ " # ecflow_client --restart\n"
+ " o resume suspended suites\n"
+ " # CL=\"ecflow_client --port=32222 --host=vsms1\"\n"
+ " # for s in $($CL --suites); do $CL --resume=/$s; done\n\n"
+ "Usage:\n"
+ " --migrate # show all suites\n"
+ " --migrate=/s1 # show state for suite s1\n"
+ ;
+}
+
+
+void CtsNodeCmd::addOption(boost::program_options::options_description& desc) const
+{
+ switch (api_) {
+ case CtsNodeCmd::GET:{
+ desc.add_options()(CtsApi::getArg(),po::value< string >()->implicit_value(string()),get_desc());
+ break;
+ }
+ case CtsNodeCmd::GET_STATE:{
+ desc.add_options()(CtsApi::get_state_arg(),po::value< string >()->implicit_value(string()),get_state_desc());
+ break;
+ }
+ case CtsNodeCmd::MIGRATE:{
+ desc.add_options()(CtsApi::migrate_arg(),po::value< string >()->implicit_value(string()),migrate_desc());
+ break;
+ }
+ case CtsNodeCmd::JOB_GEN:{
+ desc.add_options()( CtsApi::job_genArg(), po::value< string >()->implicit_value(string()), job_gen_desc() );
+ break;
+ }
+ case CtsNodeCmd::CHECK_JOB_GEN_ONLY:{
+ desc.add_options()( CtsApi::checkJobGenOnlyArg(), po::value< string >()->implicit_value(string()), job_gen_only_desc() );
+ break;
+ }
+ case CtsNodeCmd::WHY: {
+ desc.add_options()( CtsApi::whyArg(), po::value< string >()->implicit_value(string()),why_desc());
+ break;
+ }
+ case CtsNodeCmd::NO_CMD: assert(false); break;
+ default: assert(false); break;
+ }
+}
+
+void CtsNodeCmd::create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* ac ) const
+{
+ assert( api_ != CtsNodeCmd::NO_CMD);
+
+ if (ac->debug()) cout << " CtsNodeCmd::create = '" << theArg() << "'.\n";
+
+ std::string absNodePath = vm[ theArg() ].as< std::string > ();
+
+ cmd = Cmd_ptr(new CtsNodeCmd( api_ , absNodePath));
+}
+
+std::ostream& operator<<(std::ostream& os, const CtsNodeCmd& c) { return c.print(os); }
diff --git a/Base/src/cts/EditHistoryMgr.cpp b/Base/src/cts/EditHistoryMgr.cpp
new file mode 100644
index 0000000..81b6724
--- /dev/null
+++ b/Base/src/cts/EditHistoryMgr.cpp
@@ -0,0 +1,120 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #72 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include "EditHistoryMgr.hpp"
+#include "ClientToServerCmd.hpp"
+#include "AbstractServer.hpp"
+#include "Defs.hpp"
+#include "Log.hpp"
+#include "Node.hpp"
+#include "SuiteChanged.hpp"
+#include "Ecf.hpp"
+#include "Str.hpp"
+
+using namespace std;
+using namespace boost;
+using namespace ecf;
+
+EditHistoryMgr::EditHistoryMgr(const ClientToServerCmd* c,AbstractServer* a)
+: cts_cmd_(c),
+ as_(a),
+ state_change_no_(Ecf::state_change_no()),
+ modify_change_no_(Ecf::modify_change_no())
+{
+ assert(cts_cmd_->edit_history_nodes_.empty());
+ assert(cts_cmd_->edit_history_node_paths_.empty());
+}
+
+EditHistoryMgr::~EditHistoryMgr()
+{
+ // check if state changed
+ if (state_change_no_ != Ecf::state_change_no() || modify_change_no_ != Ecf::modify_change_no()) {
+
+ // Ignore child commands for edit history, where only interested in user commands
+ if (!cts_cmd_->task_cmd() && as_->defs()) {
+
+ // *ONLY* record edit history to commands that change the data model
+ // Otherwise we will end up making a data model change for read only commands
+ // If there has been a change in defs state then the command must return true from isWrite
+ if (cts_cmd_->isWrite()) {
+ if (cts_cmd_->edit_history_nodes_.empty() && cts_cmd_->edit_history_node_paths_.empty()) {
+
+ as_->defs()->flag().set(Flag::MESSAGE);
+ add_edit_history(Str::ROOT_PATH());
+ }
+ else {
+ // edit_history_node_paths_ is only populated by the delete command
+ size_t the_size = cts_cmd_->edit_history_node_paths_.size();
+ if (the_size != 0) as_->defs()->flag().set(Flag::MESSAGE);
+ for(size_t i = 0; i < the_size; i++) {
+ add_delete_edit_history(cts_cmd_->edit_history_node_paths_[i]);
+ }
+
+ the_size = cts_cmd_->edit_history_nodes_.size();
+ for(size_t i = 0; i < the_size; i++) {
+ node_ptr edited_node = cts_cmd_->edit_history_nodes_[i].lock();
+ if (edited_node.get()) {
+ // Setting the flag will make a state change. But its OK command allows it.
+ SuiteChanged0 suiteChanged(edited_node);
+ edited_node->flag().set(Flag::MESSAGE); // trap state change in suite for sync
+ add_edit_history(edited_node->absNodePath());
+ }
+ }
+ }
+ }
+ else {
+ // Read only command, that is making data model changes, oops ?
+ // TODO, Can happen when check pt command set late flag, even though its read only command.
+ // i.e when saving takes more the 30 seconds
+ std::stringstream ss;
+ cts_cmd_->print(ss);
+ cout << "cmd " << ss.str() << " should return true from isWrite() ******************\n";
+ cout << "Read only command is making data changes to defs ?????\n";
+ cout << "Ecf::state_change_no() " << Ecf::state_change_no() << " Ecf::modify_change_no() " << Ecf::modify_change_no() << "\n";
+ cout << "state_change_no_ " << state_change_no_ << " modify_change_no_ " << modify_change_no_ << "\n";
+ cout.flush();
+ }
+ }
+ }
+
+ // Clear edit history nodes;
+ cts_cmd_->edit_history_nodes_.clear();
+ cts_cmd_->edit_history_node_paths_.clear();
+}
+
+void EditHistoryMgr::add_edit_history(const std::string& path) const
+{
+ // Note: if the cts_cmd_, had thousands of paths, calling cts_cmd_->print(ss); will append those paths to the
+ // output, HUGE performance bottle neck, Since we are recording what command was applied to each node
+ // we ONLY need the single path.
+ //
+ // The old code hacked around this issue by doing vector<string>().swap(paths_);in handleRequest()
+ // This caused its own set of problems. JIRA 434
+ // See: Client/bin/gcc-4.8/release/perf_test_large_defs
+
+ // record all the user edits to the node. Reuse the time stamp cache created in handleRequest()
+ std::stringstream ss;
+ ss << "MSG:";
+ if (Log::instance()) ss << Log::instance()->get_cached_time_stamp();
+ cts_cmd_->print(ss,path); // custom print
+ as_->defs()->add_edit_history(path,ss.str());
+}
+
+void EditHistoryMgr::add_delete_edit_history(const std::string& path) const
+{
+ // History is added to Str::ROOT_PATH(), but the path must show deleted node path
+ std::stringstream ss;
+ ss << "MSG:";
+ if (Log::instance()) ss << Log::instance()->get_cached_time_stamp();
+ cts_cmd_->print(ss,path); // custom print
+ as_->defs()->add_edit_history(Str::ROOT_PATH(),ss.str());
+}
diff --git a/Base/src/cts/EditHistoryMgr.hpp b/Base/src/cts/EditHistoryMgr.hpp
new file mode 100644
index 0000000..dd355c4
--- /dev/null
+++ b/Base/src/cts/EditHistoryMgr.hpp
@@ -0,0 +1,42 @@
+#ifndef EDIT_HISTORY_MGR_HPP_
+#define EDIT_HISTORY_MGR_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #72 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// This class manages the edit history, for the commands.
+// It determines if there was a state change, if there was, it adds edit
+// history to the stored nodes.
+// Additionally we check that if there was an edit then the command must
+// return ClientToServerCmd::isWrite() true.
+//============================================================================
+#include <boost/noncopyable.hpp>
+#include <string>
+
+class ClientToServerCmd;
+class AbstractServer;
+
+class EditHistoryMgr : private boost::noncopyable {
+public:
+ EditHistoryMgr(const ClientToServerCmd*,AbstractServer*);
+ ~EditHistoryMgr();
+
+private:
+ void add_edit_history(const std::string& path) const;
+ void add_delete_edit_history(const std::string& path) const;
+
+private:
+ const ClientToServerCmd* cts_cmd_;
+ AbstractServer* as_;
+ mutable unsigned int state_change_no_; // detect state change in defs
+ mutable unsigned int modify_change_no_; // detect state change in defs
+};
+#endif
diff --git a/Base/src/cts/EditScriptCmd.cpp b/Base/src/cts/EditScriptCmd.cpp
new file mode 100644
index 0000000..9d7b53b
--- /dev/null
+++ b/Base/src/cts/EditScriptCmd.cpp
@@ -0,0 +1,400 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #37 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "boost/filesystem/operations.hpp"
+
+#include "ClientToServerCmd.hpp"
+#include "AbstractServer.hpp"
+#include "AbstractClientEnv.hpp"
+#include "File.hpp"
+#include "CtsApi.hpp"
+#include "Defs.hpp"
+#include "Task.hpp"
+#include "Alias.hpp"
+#include "Suite.hpp"
+#include "EcfFile.hpp"
+#include "JobsParam.hpp"
+#include "SuiteChanged.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+namespace po = boost::program_options;
+namespace fs = boost::filesystem;
+
+bool EditScriptCmd::equals(ClientToServerCmd* rhs) const
+{
+ EditScriptCmd* the_rhs = dynamic_cast<EditScriptCmd*>(rhs);
+ if (!the_rhs) return false;
+ if ( path_to_node_ != the_rhs->path_to_node()) { return false; }
+ if ( edit_type_ != the_rhs->edit_type()) { return false; }
+ if ( alias_ != the_rhs->alias()) { return false; }
+ if ( run_ != the_rhs->run()) { return false; }
+ return UserCmd::equals(rhs);
+}
+
+static std::string to_string(EditScriptCmd::EditType et) {
+ switch (et) {
+ case EditScriptCmd::EDIT: return "edit"; break;
+ case EditScriptCmd::PREPROCESS: return "pre_process"; break;
+ case EditScriptCmd::SUBMIT: return "submit"; break;
+ case EditScriptCmd::PREPROCESS_USER_FILE:return "pre_process_file"; break;
+ case EditScriptCmd::SUBMIT_USER_FILE: return "submit_file"; break;
+ default : assert(false); break;
+ }
+ return "edit";
+}
+static std::vector<std::string> valid_edit_types() {
+ std::vector<std::string> edit_types; edit_types.reserve(5);
+ edit_types.push_back("edit");
+ edit_types.push_back("pre_process");
+ edit_types.push_back("submit");
+ edit_types.push_back("pre_process_file");
+ edit_types.push_back("submit_file");
+ return edit_types;
+}
+
+
+std::ostream& EditScriptCmd::print(std::ostream& os) const
+{
+ return user_cmd(os,CtsApi::to_string(CtsApi::edit_script(path_to_node_,to_string(edit_type()),"",alias_,run_)));
+}
+
+bool EditScriptCmd::isWrite() const
+{
+ switch (edit_type_) {
+ case EditScriptCmd::EDIT: return false; break;
+ case EditScriptCmd::PREPROCESS: return false; break;
+ case EditScriptCmd::PREPROCESS_USER_FILE:return false; break;
+ case EditScriptCmd::SUBMIT: return true; break;
+ case EditScriptCmd::SUBMIT_USER_FILE: return true; break;
+ default : assert(false); break;
+ }
+ return false;
+}
+
+
+STC_Cmd_ptr EditScriptCmd::doHandleRequest(AbstractServer* as) const
+{
+ as->update_stats().edit_script_++;
+
+ node_ptr node = find_node_for_edit(as,path_to_node_); // will throw if defs not defined, or node not found
+ Submittable* submittable = node->isSubmittable();
+ if (!submittable) throw std::runtime_error( "EditScriptCmd failed. Can not locate task or alias at path " + path_to_node_ ) ;
+
+ /// record any changes made to suite. Needed for incremental updates
+ SuiteChanged0 changed(node);
+
+ switch (edit_type_) {
+ case EditScriptCmd::EDIT: {
+
+ /// Find all the used variable in the script, i.e 'ecf file'
+ EcfFile ecf_file = submittable->locatedEcfFile(); // will throw std::runtime_error for errors
+
+ /// This will throw std::runtime_error for parse errors
+ /// Returns the script with the used variables added at the front of the file
+ // **********************************************************************
+ // Custom handling of dynamic variables, i.e ECF_TRYNO, ECF_PASS and
+ // any variable that embeds a try number, i.e. ECF_JOB, ECF_JOBOUT
+ // This is required since the try number is *always* incremented *before* job submission,
+ // hence the value extracted from the job file will not be accurate, hence we exclude it.
+ // This way at job submission we use the latest/correct value, which is in-sync with JOB OUTPUT
+ // Note: Otherwise the job output will not be in sync
+ //
+ // Custom handling of ECF_PORT,ECF_NODE,ECF_NAME do not show these variables, these veriables
+ // including ECF_PASS appear in the script. If the user accidentally edits them,
+ // Child communication with the server will be broken. Hence not shown
+ //
+ // This special handling is done in: EcfFile::get_used_variables
+ // **********************************************************************
+ std::string ret_file_contents;
+ ecf_file.edit_used_variables(ret_file_contents);
+ return PreAllocatedReply::string_cmd(ret_file_contents);
+ }
+
+
+ case EditScriptCmd::PREPROCESS: {
+
+ /// PRE_PROCESS the ecf file accessible by the server
+ EcfFile ecf_file = submittable->locatedEcfFile(); // will throw std::runtime_error for errors
+
+ /// This function can throw std::runtime error if pre_processing fails
+ /// This *WILL* also include the used variables
+ std::string ret_file_contents ;
+ ecf_file.pre_process(ret_file_contents);
+ return PreAllocatedReply::string_cmd(ret_file_contents);
+ }
+
+
+ case EditScriptCmd::PREPROCESS_USER_FILE: {
+
+ /// The file contents('user_file_contents_') here could have been edited by the user on the client side.
+ EcfFile ecf_file = submittable->locatedEcfFile(); // will throw std::runtime_error for errors
+
+ /// This function can throw std::runtime error if pre_processing fails
+ std::string ret_file_contents ;
+ ecf_file.pre_process(user_file_contents_,ret_file_contents);
+ vector<string>().swap(user_file_contents_); // clear user_file_contents_ and minimise its capacity
+ return PreAllocatedReply::string_cmd(ret_file_contents);
+ }
+
+
+ case EditScriptCmd::SUBMIT: {
+
+ if (submittable->state() == NState::ACTIVE || submittable->state() == NState::SUBMITTED ) {
+ std::stringstream ss;
+ ss << "Node " << path_to_node_ << " is already " << NState::toString(submittable->state()) << " : ";
+ throw std::runtime_error("EditScriptCmd:: failed for submit: " + ss.str() );
+ }
+
+ /// Using the User edited variables, generate the job using the ECF/USR file accessible from the server
+ /// Convert from vector to map
+ NameValueMap user_variables_map;
+ for(size_t i = 0; i < user_variables_.size(); i++) {
+ user_variables_map.insert( std::make_pair(user_variables_[i].first, user_variables_[i].second ));
+ }
+
+ /// Do job submission, but creating .usr file first
+ /// This will *NOT* timeout, unlike server Job generation
+ JobsParam jobsParam(as->poll_interval(),true /* create jobs */); // spawn_jobs = true
+ jobsParam.set_user_edit_variables( user_variables_map );
+
+ // Custom handling of dynamic variables, i.e ECF_TRYNO, ECF_PASS and
+ // any variable that embeds a try number, i.e. ECF_JOB, ECF_JOBOUT
+ // This is required since the try number is *always* incremented *before* job submission,
+ // hence the value extracted from the job file will *not* be accurate, hence we exclude it form user variables
+ if (!submittable->submitJob(jobsParam)) {
+ throw std::runtime_error("EditScriptCmd:: failed for submit: " + jobsParam.getErrorMsg());
+ }
+ submittable->flag().set(ecf::Flag::USER_EDIT);
+ break; }
+
+
+ case EditScriptCmd::SUBMIT_USER_FILE: {
+ /// The file contents('user_file_contents_') here could have been edited by the user on the client side. ECF_HOME
+ /// If the selected node is an Alias, Just submit it. Since aliases can *NOT* have other aliases as children
+ if (!alias_ || submittable->isAlias()) {
+ if (submittable->state() == NState::ACTIVE || submittable->state() == NState::SUBMITTED ) {
+ std::stringstream ss;
+ ss << "Node " << path_to_node_ << " is already " << NState::toString(submittable->state()) << " : ";
+ throw std::runtime_error("EditScriptCmd:: failed for submit: " + ss.str() );
+ }
+
+ /// Convert from vector to map
+ NameValueMap user_variables_map;
+ for(size_t i = 0; i < user_variables_.size(); i++) {
+ user_variables_map.insert( std::make_pair(user_variables_[i].first, user_variables_[i].second ));
+ }
+
+ /// Do job submission, *USING* the user supplied file , will create .usr file
+ /// This will *NOT* timeout, unlike server Job generation
+ JobsParam jobsParam(as->poll_interval(),true /* create jobs */); // spawn_jobs = true
+ jobsParam.set_user_edit_variables( user_variables_map );
+ jobsParam.set_user_edit_file( user_file_contents_);
+
+ if (!submittable->submitJob(jobsParam)) {
+ vector<string>().swap(user_file_contents_); // clear user_file_contents_ and minimise its capacity
+ throw std::runtime_error("EditScriptCmd::SUBMIT_USER_FILE: failed : " + jobsParam.getErrorMsg());
+ }
+ submittable->flag().set(ecf::Flag::USER_EDIT);
+ }
+ else {
+ // CREATE a Child Alias. The create alias and parent it to the Task., and choose to run or not.
+ Task* task = submittable->isTask();
+ if (!task) {
+ vector<string>().swap(user_file_contents_); // clear user_file_contents_ and minimise its capacity
+ throw std::runtime_error("EditScriptCmd::SUBMIT_USER_FILE: Aliases can only be created for a task. Selected path is a Alias. Please select a Task path");
+ }
+ alias_ptr alias = task->add_alias(user_file_contents_,user_variables_);
+
+ if (run_) {
+ /// This will *NOT* timeout, unlike server Job generation
+ JobsParam jobsParam(as->poll_interval(),true /* create jobs */); // spawn jobs = true
+ if (!alias->submitJob(jobsParam)) {
+ vector<string>().swap(user_file_contents_); // clear user_file_contents_ and minimise its capacity
+ throw std::runtime_error("EditScriptCmd::SUBMIT_USER_FILE: failed for Alias : " + jobsParam.getErrorMsg());
+ }
+ alias->flag().set(ecf::Flag::USER_EDIT);
+ }
+ }
+ break; }
+
+ default : assert(false); break;
+ }
+
+
+ // Clear up memory allocated *ASAP*
+ // When dealing with several thousands strings, this makes a *HUGE* difference
+ vector<string>().swap(user_file_contents_); // clear user_file_contents_ and minimise its capacity
+
+ return PreAllocatedReply::ok_cmd();
+}
+
+const char* EditScriptCmd::arg() { return CtsApi::edit_script_arg();}
+const char* EditScriptCmd::desc() {
+ /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+ return "Allows user to edit, pre-process and submit the script.\n"
+ " arg1 = path to task # The path to the task/alias\n"
+ " arg2 = [ edit | pre_process | submit | pre_process_file | submit_file ]\n"
+ " edit : will return the script file to standard out. The script will\n"
+ " include used variables enclosed between %comment/%end at the\n"
+ " start of the file\n"
+ " pre_process: Will return the script file to standard out.The script will\n"
+ " include used variables enclosed between %comment/%end at the\n"
+ " start of the file and with all %include expanded\n"
+ " submit: Will extract the used variables from the supplied file, i.e \n"
+ " between the %comment/%end and use these them to generate the\n"
+ " job using the ecf file accessible from the server\n"
+ " pre_process_file: Will pre process the user supplied file\n"
+ " submit_file: Like submit, but the supplied file, is submitted by the server\n"
+ " The last 2 options allow complete freedom to debug the script file\n"
+ " arg3 = [ path_to_script_file ]\n"
+ " needed for option [ pre_process_file | submit_file ]\n"
+ " arg4 = create_alias (optional) default value is false, for use with 'submit_file' option\n"
+ " arg5 = no_run (optional) default value is false, i.e immediately run the alias\n"
+ " is no_run is specified the alias in only created\n"
+ "Usage:\n"
+ "--edit_script=/path/to/task edit > script_file\n"
+ " server returns script with the used variables to standard out\n"
+ " The user can choose to edit this file\n"
+ "--edit_script=/path/to/task pre_process > pre_processed_script_file\n"
+ " server will pre process the ecf file accessible from the server\n"
+ " (i.e expand all %includes) and return the file to standard out\n"
+ "--edit_script=/path/to/task submit script_file\n"
+ " Will extract the used variables in the 'script_file' and will uses these\n"
+ " variables during variable substitution of the ecf file accessible by the\n"
+ " server. This is then submitted as a job\n"
+ "--edit_script=/path/to/task pre_process_file file_to_pre_process\n"
+ " The server will pre-process the user supplied file and return the contents\n"
+ " to standard out\n"
+ "--edit_script=/path/to/task submit_file file_to_submit\n"
+ " Will extract the used variables in the 'file_to_submit' and will uses these\n"
+ " variables during variable substitution, the file is then submitted for job\n"
+ " generation by the server\n"
+ "--edit_script=/path/to/task submit_file file_to_submit create_alias\n"
+ " Like the the previous example but will create and run as an alias"
+ ;
+}
+
+void EditScriptCmd::addOption(boost::program_options::options_description& desc) const {
+ desc.add_options()( EditScriptCmd::arg(),po::value< vector<string> >()->multitoken(), EditScriptCmd::desc() );
+}
+
+void EditScriptCmd::create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* ac) const
+{
+ vector<string> args = vm[ arg() ].as< vector<string> >();
+
+ if (ac->debug()) dumpVecArgs(EditScriptCmd::arg(),args);
+
+ std::stringstream ss;
+ if (args.size() < 2) {
+ ss << "EditScriptCmd:At least 2 arguments required:\n" << EditScriptCmd::desc();
+ throw std::runtime_error(ss.str());
+ }
+
+ string path_to_task = args[0];
+ string edit_type_str = args[1];
+ EditScriptCmd::EditType edit_type = EditScriptCmd::EDIT;
+
+ /// Check edit_type is valid
+ bool ok = false;
+ std::vector<std::string> edit_types = valid_edit_types();
+ for(size_t i = 0; i < edit_types.size(); i++) {
+ if (edit_type_str == edit_types[i]) {
+ if (edit_type_str == "edit") edit_type = EditScriptCmd::EDIT;
+ else if (edit_type_str == "pre_process") edit_type = EditScriptCmd::PREPROCESS;
+ else if (edit_type_str == "submit") edit_type = EditScriptCmd::SUBMIT;
+ else if (edit_type_str == "pre_process_file") edit_type = EditScriptCmd::PREPROCESS_USER_FILE;
+ else if (edit_type_str == "submit_file") edit_type = EditScriptCmd::SUBMIT_USER_FILE;
+ else { assert(false); }
+ ok = true; break;
+ }
+ }
+
+ if (!ok) {
+ ss << "The second argument(" << args[1] << ") to edit_script must be one of [ ";
+ for(size_t i = 0; i < edit_types.size(); ++i) { if (i != 0) ss << " | "; ss << edit_types[i];}
+ ss << "]\n" << EditScriptCmd::desc();
+ throw std::runtime_error( ss.str() );
+ }
+
+ if (args.size() == 2) {
+ if (edit_type == EditScriptCmd::EDIT || edit_type == EditScriptCmd::PREPROCESS) {
+ cmd = Cmd_ptr( new EditScriptCmd( path_to_task, edit_type) );
+ return;
+ }
+ else {
+ ss << "When two arguments specified, the second argument must be one of [ edit | pre_process ]\n" << EditScriptCmd::desc();
+ throw ss.str();
+ }
+ }
+
+ bool create_alias = false; // for use with "submit_file" option only
+ bool run_alias = true; // for use with "submit_file" option only
+ for(size_t i = 0; i < args.size(); i++) {
+ if (i > 2 && args[i] == "create_alias") create_alias = true;
+ if (i > 2 && args[i] == "no_run") run_alias = false;
+ }
+ if ( ( create_alias || !run_alias) && edit_type != EditScriptCmd::SUBMIT_USER_FILE ) {
+ ss << "The create_alias option is only valid when the second argument is 'submit_file' \n" << EditScriptCmd::desc();
+ throw ss.str();
+ }
+
+
+ if (args.size() >= 3 && args.size() <= 5) {
+ string path_to_script = args[2];
+ std::vector<std::string> script_lines;
+
+ if (!fs::exists(path_to_script)) {
+ ss << "The script file specified '" << path_to_script << "' does not exist\n";
+ throw std::runtime_error(ss.str());
+ }
+ if (!File::splitFileIntoLines(path_to_script, script_lines)) {
+ ss << "Could not open script file " << path_to_script;
+ throw std::runtime_error(ss.str());
+ }
+
+ if (edit_type == EditScriptCmd::SUBMIT || EditScriptCmd::SUBMIT_USER_FILE) {
+ // extract the Used variables from the script file
+ NameValueMap used_variables_as_map;
+ EcfFile::extract_used_variables(used_variables_as_map,script_lines);
+
+ // Convert MAP to Vec
+ NameValueVec used_variables_as_vec;
+ std::pair<std::string, std::string> pair;
+ BOOST_FOREACH(pair, used_variables_as_map) { used_variables_as_vec.push_back( std::make_pair(pair.first,pair.second) ); }
+
+ if (edit_type == EditScriptCmd::SUBMIT) {
+ cmd = Cmd_ptr( new EditScriptCmd( path_to_task, used_variables_as_vec ) ); //SUMBIT
+ return;
+ }
+
+ cmd = Cmd_ptr( new EditScriptCmd( path_to_task, used_variables_as_vec, script_lines, create_alias, run_alias ) ); // SUBMIT_USER_FILE
+ return;
+ }
+ else if (edit_type == EditScriptCmd::PREPROCESS_USER_FILE ) {
+
+ cmd = Cmd_ptr( new EditScriptCmd( path_to_task, script_lines ) );
+ return;
+ }
+ }
+
+ ss << "Wrong number of arguments specified\n" << EditScriptCmd::desc();
+ throw std::runtime_error(ss.str());
+}
+
+std::ostream& operator<<(std::ostream& os, const EditScriptCmd& c) { return c.print(os); }
diff --git a/Base/src/cts/ForceCmd.cpp b/Base/src/cts/ForceCmd.cpp
new file mode 100644
index 0000000..4fe8851
--- /dev/null
+++ b/Base/src/cts/ForceCmd.cpp
@@ -0,0 +1,258 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #36 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include "ClientToServerCmd.hpp"
+#include "AbstractServer.hpp"
+#include "AbstractClientEnv.hpp"
+#include "CtsApi.hpp"
+#include "Defs.hpp"
+#include "Node.hpp"
+#include "Str.hpp"
+#include "SuiteChanged.hpp"
+#include "Extract.hpp"
+#include "Log.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+namespace po = boost::program_options;
+
+// ===================================================================================
+
+bool ForceCmd::equals(ClientToServerCmd* rhs) const
+{
+ ForceCmd* the_rhs = dynamic_cast<ForceCmd*>(rhs);
+ if (!the_rhs) return false;
+ if ( paths_ != the_rhs->paths()) { return false;}
+ if ( stateOrEvent_ != the_rhs->stateOrEvent()) { return false; }
+ if ( recursive_ != the_rhs->recursive()) { return false; }
+ if ( setRepeatToLastValue_ != the_rhs->setRepeatToLastValue()) { return false; }
+ return UserCmd::equals(rhs);
+}
+
+std::ostream& ForceCmd::print(std::ostream& os) const
+{
+ return user_cmd(os,CtsApi::to_string(CtsApi::force(paths_,stateOrEvent_,recursive_,setRepeatToLastValue_)));
+}
+
+std::ostream& ForceCmd::print(std::ostream& os, const std::string& path) const
+{
+ std::vector<std::string> paths(1,path);
+ return user_cmd(os,CtsApi::to_string(CtsApi::force(paths,stateOrEvent_,recursive_,setRepeatToLastValue_)));
+}
+
+STC_Cmd_ptr ForceCmd::doHandleRequest(AbstractServer* as) const
+{
+ as->update_stats().force_++;
+
+ assert(isWrite()); // isWrite used in handleRequest() to control check pointing
+
+ bool is_event_state = Event::isValidState(stateOrEvent_);
+ bool is_node_state = NState::isValid(stateOrEvent_);
+ if (!is_node_state && !is_event_state) {
+ std::stringstream ss;
+ ss << "ForceCmd: failed. Invalid node state or event " << stateOrEvent_ << " expected one of "
+ << "[ unknown | complete | queued | submitted | active | aborted | clear | set]";
+ throw std::runtime_error( ss.str() ) ;
+ }
+
+ std::stringstream error_ss;
+ size_t vec_size = paths_.size();
+ for(size_t i = 0; i < vec_size; i++) {
+
+ string the_path = paths_[i];
+ string the_event;
+ if ( is_event_state ) {
+ Extract::pathAndName(paths_[i],the_path, the_event);
+ if ( the_path.empty() || the_event.empty() ) {
+ std::stringstream ss;
+ ss << "ForceCmd: When 'set' or 'clear' is specified the path needs to include name of the event i.e --force=/path/to_task:event_name set";
+ std::string error_msg = ss.str();
+ ecf::log(Log::ERR, error_msg);
+ error_ss << error_msg << "\n";
+ continue;
+ }
+ }
+
+ node_ptr node = find_node_for_edit_no_throw(as,the_path);
+ if (!node.get()) {
+ std::stringstream ss;
+ ss << "ForceCmd: Could not find node at path " << the_path;
+ std::string error_msg = ss.str();
+ ecf::log(Log::ERR, error_msg);
+ error_ss << error_msg << "\n";
+ continue;
+ }
+ SuiteChanged0 changed(node); // Cater for suites in handles
+
+ if (is_node_state) {
+ /// We want this to have side effects. i.e bubble up state and re-queue if complete and has repeat's
+ /// **** However if state is SET to complete, we want to MISS the next time slot.
+ /// **** we need to mark the time dependency as *expired*, otherwise, it will be automatically reset to QUEUED state
+ NState::State new_state = NState::toState(stateOrEvent_);
+ if (new_state == NState::COMPLETE) {
+ node->miss_next_time_slot();
+ }
+
+ if (recursive_) node->set_state_hierarchically( new_state, true /* force */ );
+ else node->set_state( new_state, true /* force */ );
+ }
+ else {
+ // The recursive option is *NOT* applicable to events, hence ignore. According to Axel !!!!
+ if ( stateOrEvent_ == Event::SET() ) {
+ if (!node->set_event(the_event)) {
+ std::stringstream ss;
+ ss << "ForceCmd: force set: failed for node(" << node->absNodePath() << ") can not find event(" << the_event << ")";
+ std::string error_msg = ss.str();
+ ecf::log(Log::ERR, error_msg);
+ error_ss << error_msg << "\n";
+ continue;
+ }
+ }
+ else if ( stateOrEvent_ == Event::CLEAR() ) {
+ if (!node->clear_event(the_event)) {
+ std::stringstream ss;
+ ss << "ForceCmd: force clear: failed for node(" << node->absNodePath() << ") can not find event(" << the_event << ")";
+ std::string error_msg = ss.str();
+ ecf::log(Log::ERR, error_msg);
+ error_ss << error_msg << "\n";
+ continue;
+ }
+ }
+ else throw std::runtime_error("ForceCmd: Invalid parameter") ;
+ }
+
+ if ( recursive_ && setRepeatToLastValue_) {
+ node->setRepeatToLastValueHierarchically();
+ }
+ }
+
+ std::string error_msg = error_ss.str();
+ if (!error_msg.empty()) {
+ throw std::runtime_error( error_msg ) ;
+ }
+
+ /// Change of state, do immediate job generation
+ return doJobSubmission( as );
+}
+
+const char* ForceCmd::arg() { return CtsApi::forceArg();}
+const char* ForceCmd::desc() {
+ /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+ return
+ "Force a node to a given state, or set its event.\n"
+ "When a task is set to complete, it may be automatically re-queued if it has\n"
+ "multiple future time dependencies. However each time we force a complete it will\n"
+ "expire any time based attribute on that node. When the last time based attribute\n"
+ "expires, the node will stay in a complete state.\n"
+ "This behaviour allow Repeat values to be incremented interactively.\n"
+ "A repeat attribute is incremented when all the child nodes are complete\n"
+ "in this case the child nodes are automatically re-queued.\n"
+ " arg1 = [ unknown | complete | queued | submitted | active | aborted | clear | set ]\n"
+ " arg2 = (optional) recursive\n"
+ " Applies state to node and recursively to all its children\n"
+ " arg3 = (optional) full\n"
+ " Set repeat variables to last value, only works in conjunction\n"
+ " with recursive option\n"
+ " arg4 = path_to_node or path_to_node:<event>: paths must begin with '/'\n"
+ "Usage:\n"
+ " --force=complete /suite/t1 /suite/t2 # Set task t1 & t2 to complete\n"
+ " --force=clear /suite/task:ev # Clear the event 'ev' on task /suite/task\n"
+ " --force=complete recursive /suite/f1 # Recursively set complete all children of /suite/f1\n"
+ "Effect:\n"
+ " Consider the effect of forcing complete when the current time is at 09:00\n"
+ " suite s1\n"
+ " task t1; time 12:00 # will complete straight away\n"
+ " task t2; time 10:00 13:00 01:00 # will complete on fourth attempt\n\n"
+ " --force=complete /s1/t1 /s1/t2\n"
+ " When we have a time range(i.e as shown with task t2), it is re-queued and the\n"
+ " next time slot is incremented for each complete, until it expires, and the task completes.\n"
+ " Use the Why command, to show next run time (i.e. next time slot)"
+ ;
+}
+
+void ForceCmd::addOption(boost::program_options::options_description& desc) const {
+ desc.add_options()( ForceCmd::arg(),po::value< vector<string> >()->multitoken(), ForceCmd::desc() );
+}
+void ForceCmd::create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* ac) const
+{
+ vector<string> args = vm[ arg() ].as< vector<string> >();
+
+ if (ac->debug()) dumpVecArgs(ForceCmd::arg(),args);
+
+ if (args.size() < 2 ) {
+ std::stringstream ss;
+ ss << "ForceCmd: At least two arguments expected for Force. Found " << args.size() << "\n"
+ << ForceCmd::desc() << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+
+ std::vector<std::string> options,paths;
+ split_args_to_options_and_paths(args,options,paths); // relative order is still preserved
+ if (paths.empty()) {
+ std::stringstream ss;
+ ss << "ForceCmd: No paths specified. Paths must begin with a leading '/' character\n" << ForceCmd::desc() << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ if (options.empty()) {
+ std::stringstream ss;
+ ss << "ForceCmd: Invalid argument list. Expected of:\n"
+ << "[ unknown | complete | queued | submitted | active | aborted | clear | set]\n" << ForceCmd::desc() << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+
+ bool is_valid_state = false;
+ bool is_valid_event_state = false;
+ bool setRepeatToLastValue = false;
+ bool recursive = false;
+ std::string stateOrEvent;
+ size_t vec_size = options.size();
+ for(size_t i = 0; i < vec_size; i++) {
+ if (Str::caseInsCompare(options[i],"recursive")) recursive = true;
+ else if (Str::caseInsCompare( options[i],"full")) setRepeatToLastValue = true;
+ else if (NState::isValid(options[i])) { is_valid_state = true; stateOrEvent = options[i];}
+ else if (Event::isValidState(options[i])) { is_valid_event_state = true; stateOrEvent = options[i];}
+ else {
+ std::stringstream ss; ss << "ForceCmd: Invalid argument \n" << ForceCmd::desc() << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ }
+
+ if (!is_valid_state && !is_valid_event_state) {
+ std::stringstream ss;
+ ss << "ForceCmd: Invalid node state or event expected one of:\n"
+ << "[ unknown | complete | queued | submitted | active | aborted | clear | set]\n";
+ throw std::runtime_error( ss.str() );
+ }
+
+ if ( is_valid_event_state ) {
+ // When set or clear used the path needs to include the name of the event:
+ size_t vec_size = paths.size();
+ for(size_t i = 0; i < vec_size; i++) {
+ string the_event,the_path;
+ Extract::pathAndName(paths[i],the_path, the_event);
+ if ( the_path.empty() || the_event.empty() ) {
+ std::stringstream ss;
+ ss << "ForceCmd: When 'set' or 'clear' is specified the path needs to include name of the event i.e\n";
+ ss << " --force=/path/to_task:event_name set\n";
+ throw std::runtime_error( ss.str() );
+ }
+ }
+ }
+ cmd = Cmd_ptr( new ForceCmd(paths, stateOrEvent, recursive, setRepeatToLastValue ) );
+}
+
+std::ostream& operator<<(std::ostream& os, const ForceCmd& c) { return c.print(os); }
diff --git a/Base/src/cts/FreeDepCmd.cpp b/Base/src/cts/FreeDepCmd.cpp
new file mode 100644
index 0000000..fdb5567
--- /dev/null
+++ b/Base/src/cts/FreeDepCmd.cpp
@@ -0,0 +1,156 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #28 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include "ClientToServerCmd.hpp"
+#include "AbstractServer.hpp"
+#include "AbstractClientEnv.hpp"
+#include "CtsApi.hpp"
+#include "Defs.hpp"
+#include "Node.hpp"
+#include "SuiteChanged.hpp"
+#include "Log.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+namespace po = boost::program_options;
+
+//=======================================================================================
+
+bool FreeDepCmd::equals(ClientToServerCmd* rhs) const
+{
+ FreeDepCmd* the_rhs = dynamic_cast<FreeDepCmd*>(rhs);
+ if (!the_rhs) return false;
+ if ( paths_ != the_rhs->paths()) { return false;}
+ if ( all_ != the_rhs->all()) { return false; }
+ if ( trigger_ != the_rhs->trigger()) { return false; }
+ if ( date_ != the_rhs->date()) { return false; }
+ if ( time_ != the_rhs->time()) { return false; }
+ return UserCmd::equals(rhs);
+}
+
+std::ostream& FreeDepCmd::print(std::ostream& os) const
+{
+ return user_cmd(os,CtsApi::to_string(CtsApi::freeDep(paths_,trigger_,all_,date_,time_)));
+}
+
+std::ostream& FreeDepCmd::print(std::ostream& os, const std::string& path) const
+{
+ std::vector<std::string> paths(1,path);
+ return user_cmd(os,CtsApi::to_string(CtsApi::freeDep(paths,trigger_,all_,date_,time_)));
+}
+
+STC_Cmd_ptr FreeDepCmd::doHandleRequest(AbstractServer* as) const
+{
+ as->update_stats().free_dep_++;
+
+ std::stringstream ss;
+ size_t vec_size = paths_.size();
+ for(size_t i = 0; i < vec_size; i++) {
+
+ node_ptr node = find_node_for_edit_no_throw(as,paths_[i]);
+ if (!node.get()) {
+ ss << "FreeDepCmd: Could not find node at path " << paths_[i] << "\n";
+ LOG(Log::ERR,"FreeDepCmd: Could not find node at path " << paths_[i]);
+ continue;
+ }
+
+ SuiteChanged0 changed(node);
+ if (all_) {
+ node->freeTrigger();
+ node->freeHoldingDateDependencies();
+ node->freeHoldingTimeDependencies();
+ }
+ else {
+ if (trigger_) node->freeTrigger();
+ if (date_) node->freeHoldingDateDependencies();
+ if (time_) node->freeHoldingTimeDependencies();
+ }
+ }
+
+ std::string error_msg = ss.str();
+ if (!error_msg.empty()) {
+ throw std::runtime_error( error_msg ) ;
+ }
+
+ return doJobSubmission( as );
+}
+
+const char* FreeDepCmd::arg() { return CtsApi::freeDepArg();}
+const char* FreeDepCmd::desc() {
+ return
+ "Free dependencies for a node. Defaults to triggers\n"
+ "After freeing the time related dependencies (i.e time,today,cron)\n"
+ "the next time slot will be missed.\n"
+ " arg1 = (optional) trigger\n"
+ " arg2 = (optional) all\n"
+ " Free trigger, date and all time dependencies\n"
+ " arg3 = (optional) date\n"
+ " Free date dependencies\n"
+ " arg4 = (optional) time\n"
+ " Free all time dependencies i.e time, day, today, cron\n"
+ " arg5 = List of paths. At least one required. Must start with a leading '/'\n"
+ "Usage:\n"
+ " --free-dep=/s1/t1 /s2/t2 # free trigger dependencies for task's t1,t2\n"
+ " --free-dep=all /s1/f1/t1 # free all dependencies of /s1/f1/t1\n"
+ " --free-dep=date /s1/f1 # free holding date dependencies of /s1/f1"
+ ;
+}
+
+void FreeDepCmd::addOption(boost::program_options::options_description& desc) const {
+ desc.add_options()( FreeDepCmd::arg(),po::value< vector<string> >()->multitoken(), FreeDepCmd::desc() );
+}
+void FreeDepCmd::create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* ac) const
+{
+ vector<string> args = vm[ arg() ].as< vector<string> >();
+
+ if (ac->debug()) dumpVecArgs(FreeDepCmd::arg(),args);
+
+ if (args.size() < 1 ) {
+ std::stringstream ss;
+ ss << "FreeDepCmd: At least one arguments expected for Free dependencies. Found " << args.size() << "\n" << FreeDepCmd::desc() << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+
+ std::vector<std::string> options,paths;
+ split_args_to_options_and_paths(args,options,paths); // relative order is still preserved
+ if (paths.empty()) {
+ std::stringstream ss;
+ ss << "FreeDepCmd: No paths specified. Paths must begin with a leading '/' character\n" << FreeDepCmd::desc() << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+
+ bool trigger = options.empty(); // If no options default to freeing trigger dependencies
+ bool all = false;
+ bool date = false;
+ bool time = false;
+ size_t vec_size = options.size();
+ for(size_t i = 0; i < vec_size; i++) {
+ if (options[i] == "trigger") trigger = true;
+ else if ( options[i] == "all") all = true;
+ else if ( options[i] == "date") date = true;
+ else if ( options[i] == "time") time = true;
+ else {
+ std::stringstream ss;
+ ss << "FreeDepCmd: Invalid argument(" << options[i] << ")\n" << FreeDepCmd::desc() << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ }
+ assert(trigger || all || date || time); // at least one must be true
+ cmd = Cmd_ptr( new FreeDepCmd(paths, trigger, all, date , time) );
+}
+
+std::ostream& operator<<(std::ostream& os, const FreeDepCmd& c) { return c.print(os); }
diff --git a/Base/src/cts/GroupCTSCmd.cpp b/Base/src/cts/GroupCTSCmd.cpp
new file mode 100644
index 0000000..1305ce8
--- /dev/null
+++ b/Base/src/cts/GroupCTSCmd.cpp
@@ -0,0 +1,301 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #29 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <iostream>
+#include <boost/foreach.hpp>
+#include <boost/algorithm/string/trim.hpp>
+#include <boost/make_shared.hpp>
+
+#include "ClientToServerCmd.hpp"
+#include "GroupSTCCmd.hpp"
+#include "AbstractServer.hpp"
+#include "AbstractClientEnv.hpp"
+#include "Str.hpp"
+#include "CtsApi.hpp"
+#include "CtsCmdRegistry.hpp"
+#include "ArgvCreator.hpp"
+#include "Log.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+namespace po = boost::program_options;
+
+//#define DEBUG_GROUP_CMD 1
+
+//======================================================================================
+
+GroupCTSCmd::GroupCTSCmd(const std::string& cmdSeries,AbstractClientEnv* clientEnv)
+{
+ std::vector<std::string> individualCmdVec;
+ Str::split(cmdSeries,individualCmdVec,";");
+ if ( individualCmdVec.empty()) throw std::runtime_error("GroupCTSCmd::GroupCTSCmd: Please provide a list of ';' separated commands\n" );
+ if (clientEnv->debug()){
+ for(size_t i=0; i < individualCmdVec.size(); i++) { cout << " CHILD COMMAND = " << individualCmdVec[i] << "\n";}
+ }
+
+
+ // Create a list of allowable commands for a group. i.e excludes help, group
+ po::options_description desc( "Allowed group options" );
+ CtsCmdRegistry cmdRegistry( false /* don't add group option */);
+ cmdRegistry.addCmdOptions(desc);
+
+
+ for(size_t i=0; i < individualCmdVec.size(); i++){
+ // massage the commands so that, we add -- at the start of each command.
+ // This is required by the boost program options.
+ std::string aCmd = individualCmdVec[i];
+ boost::algorithm::trim(aCmd);
+
+ std::string subCmd;
+ if (aCmd.find("--") == std::string::npos) subCmd = "--";
+ subCmd += aCmd;
+
+ // Each sub command can have, many args
+ std::vector<std::string> subCmdArgs;
+ Str::split(subCmd,subCmdArgs);
+
+ // The first will be the command, then the args. However from boost 1.59
+ // we must use --cmd=value, instead of --cmd value
+ if (!subCmdArgs.empty() && subCmdArgs.size() > 1 && subCmdArgs[0].find("=") == std::string::npos) {
+ subCmdArgs[0] += "=";
+ subCmdArgs[0] += subCmdArgs[1];
+ subCmdArgs.erase( subCmdArgs.begin() + 1); // remove, since we have added to first
+ }
+
+ /// Hack because we *can't* create program option with vector of strings, which can be empty
+ /// Hence if command is just show, add a dummy arg.
+ //if (aCmd == "show") subCmdArgs.push_back("<dummy_arg>");
+
+ std::vector<std::string> theArgs; theArgs.push_back("ClientInvoker");
+ std::copy( subCmdArgs.begin(), subCmdArgs.end(), std::back_inserter(theArgs));
+
+ // Create a Argv array from a vector of strings
+ ArgvCreator argvCreator(theArgs);
+
+ if (clientEnv->debug()) {
+ cout << " PROCESSING COMMAND = '" << subCmd << "' argc(" << argvCreator.argc() << ")";
+ cout << argvCreator.toString() << "\n";
+ }
+
+ // Treat each sub command separately
+ boost::program_options::variables_map group_vm;
+ po::store( po::parse_command_line( argvCreator.argc(), argvCreator.argv(), desc ), group_vm );
+ po::notify( group_vm );
+
+ Cmd_ptr childCmd;
+ cmdRegistry.parse( childCmd,group_vm,clientEnv);
+ addChild( childCmd );
+ }
+}
+
+
+bool GroupCTSCmd::isWrite() const
+{
+ BOOST_FOREACH(Cmd_ptr subCmd, cmdVec_) { if (subCmd->isWrite()) return true; }
+ return false;
+}
+
+bool GroupCTSCmd::get_cmd() const
+{
+ BOOST_FOREACH(Cmd_ptr subCmd, cmdVec_) { if (subCmd->get_cmd()) return true; }
+ return false;
+}
+
+PrintStyle::Type_t GroupCTSCmd::show_style() const
+{
+ // Only return non default style( PrintStyle::NOTHING ) if sub command
+ // contains a show cmd
+ BOOST_FOREACH(Cmd_ptr subCmd, cmdVec_) {
+ if ( subCmd->show_cmd() ) return subCmd->show_style();
+ }
+ return PrintStyle::NOTHING;
+}
+
+bool GroupCTSCmd::task_cmd() const
+{
+ BOOST_FOREACH(Cmd_ptr subCmd, cmdVec_) { if (subCmd->task_cmd()) return true; }
+ return false;
+}
+
+bool GroupCTSCmd::terminate_cmd() const
+{
+ BOOST_FOREACH(Cmd_ptr subCmd, cmdVec_) { if (subCmd->terminate_cmd()) return true; }
+ return false;
+}
+
+bool GroupCTSCmd::why_cmd( std::string& nodePath) const
+{
+ BOOST_FOREACH(Cmd_ptr subCmd, cmdVec_) { if (subCmd->why_cmd(nodePath)) return true; }
+ return false;
+}
+
+std::ostream& GroupCTSCmd::print(std::ostream& os) const
+{
+ std::stringstream ss;
+ size_t the_size = cmdVec_.size();
+ for(size_t i = 0; i < the_size; i++) {
+ cmdVec_[i]->print(ss);
+ ss <<"; ";
+ }
+ return user_cmd(os,CtsApi::group(ss.str()));
+}
+
+bool GroupCTSCmd::equals(ClientToServerCmd* rhs) const
+{
+ GroupCTSCmd* the_rhs = dynamic_cast< GroupCTSCmd* > ( rhs );
+ if ( !the_rhs ) return false;
+
+ const std::vector<Cmd_ptr>& rhsCmdVec = the_rhs->cmdVec();
+ if (cmdVec_.size() != rhsCmdVec.size()) return false;
+
+ for(size_t i = 0; i < cmdVec_.size(); i++) {
+ if ( !cmdVec_[i]->equals( rhsCmdVec[i].get() ) ) {
+ return false;
+ }
+ }
+
+ return UserCmd::equals(rhs);
+}
+
+void GroupCTSCmd::addChild(Cmd_ptr childCmd)
+{
+ assert(childCmd.get()); // Dont add NULL children
+ cmdVec_.push_back(childCmd);
+}
+
+void GroupCTSCmd::setup_user_authentification()
+{
+ UserCmd::setup_user_authentification();
+ for(size_t i = 0; i < cmdVec_.size(); i++) {
+ cmdVec_[i]->setup_user_authentification();
+ }
+}
+
+bool GroupCTSCmd::authenticate(AbstractServer* as, STC_Cmd_ptr& errorMsg) const
+{
+ // Can only run Group cmd if all child commands authenticate
+ size_t cmd_vec_size = cmdVec_.size();
+ for(size_t i = 0; i < cmd_vec_size; i++) {
+ if (!cmdVec_[i]->authenticate(as,errorMsg)) {
+
+ // Log authentication failure:
+ std::stringstream ss;
+ ss << "GroupCTSCmd::authenticate failed: for ";
+ cmdVec_[i]->print(ss);
+ ss << errorMsg;
+ log(Log::ERR,ss.str()); // will automatically add end of line
+
+#ifdef DEBUG_GROUP_CMD
+ std::cout << "GroupCTSCmd::authenticate failed for "; cmdVec_[i]->print(std::cout); std::cout << errorMsg << "\n";
+#endif
+ return false;
+ }
+ }
+ return true;
+}
+
+STC_Cmd_ptr GroupCTSCmd::doHandleRequest(AbstractServer* as) const
+{
+#ifdef DEBUG_GROUP_CMD
+ std::cout << "GroupCTSCmd::doHandleRequest cmdVec_.size() = " << cmdVec_.size() << "\n";
+#endif
+
+ as->update_stats().group_cmd_++;
+
+ boost::shared_ptr<GroupSTCCmd> theReturnedGroupCmd = boost::make_shared<GroupSTCCmd>();
+
+ // For the command to succeed all children MUST succeed
+ size_t cmd_vec_size = cmdVec_.size();
+ for(size_t i = 0; i < cmd_vec_size; i++) {
+#ifdef DEBUG_GROUP_CMD
+ std::cout << " GroupCTSCmd::doHandleRequest calling "; cmdVec_[i]->print(std::cout); // std::cout << "\n";
+#endif
+
+ STC_Cmd_ptr theReturnCmd = cmdVec_[i]->doHandleRequest(as);
+
+#ifdef DEBUG_GROUP_CMD
+ std::cout << " return Cmd = "; theReturnCmd->print(std::cout); std::cout << "\n";
+#endif
+
+ if ( !theReturnCmd->ok() ) {
+ return theReturnCmd; // The Error Command
+ }
+
+ if ( !theReturnCmd->get_string().empty() ) {
+#ifdef DEBUG_GROUP_CMD
+ std::cout << " GroupCTSCmd::doHandleRequest returning Cmd = "; theReturnCmd->print(std::cout); std::cout << " to client\n";
+#endif
+ theReturnedGroupCmd->addChild( theReturnCmd );
+ continue;
+ }
+
+ if ( theReturnCmd->hasDefs() ) {
+#ifdef DEBUG_GROUP_CMD
+ std::cout << " GroupCTSCmd::doHandleRequest returning Cmd = "; theReturnCmd->print(std::cout); std::cout << " to client\n";
+#endif
+ theReturnedGroupCmd->addChild( theReturnCmd );
+ continue;
+ }
+
+ if ( theReturnCmd->hasNode() ) {
+#ifdef DEBUG_GROUP_CMD
+ std::cout << " GroupCTSCmd::doHandleRequest returning Cmd = "; theReturnCmd->print(std::cout); std::cout << " to client\n";
+#endif
+ theReturnedGroupCmd->addChild( theReturnCmd );
+ }
+ }
+
+ if ( theReturnedGroupCmd->cmdVec().empty() ) {
+ // Nothing to return, i.e. no Defs, Node or Log file
+ return PreAllocatedReply::ok_cmd();
+ }
+
+ return theReturnedGroupCmd ;
+}
+
+const char* GroupCTSCmd::arg() { return CtsApi::groupArg() ;}
+const char* GroupCTSCmd::desc() {
+ return
+ "Allows a series of ';' separated commands to be grouped and executed as one.\n"
+ "Some commands like halt, shutdown and terminate will prompt the user. To bypass the prompt\n"
+ "provide 'yes' as an additional parameter. See example below.\n"
+ " arg = string\n"
+ "Usage:\n"
+ " --group=\"halt=yes; reloadwsfile; restart;\"\n"
+ " # halt server,bypass the confirmation prompt,\n"
+ " # reload white list file, restart server\n"
+ " --group=\"get; show\" # get server defs, and write to standard output\n"
+ " --group=\"get=/s1; show state\" # get suite 's1', and write state to standard output"
+ ;
+}
+
+void GroupCTSCmd::addOption(boost::program_options::options_description& desc) const {
+ desc.add_options()( GroupCTSCmd::arg(), po::value< string >(), GroupCTSCmd::desc() );
+}
+
+void GroupCTSCmd::create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const
+{
+ if (clientEnv->debug()) cout << " " << arg() << ": Group Cmd '" << vm[ arg() ].as< std::string > () << "'\n";
+
+ // Parse and split commands and then parse individually. Assumes commands are separated by ';'
+ std::string cmdSeries = vm[GroupCTSCmd::arg()].as< std::string > ();
+
+ cmd = Cmd_ptr( new GroupCTSCmd(cmdSeries,clientEnv) );
+}
+
+std::ostream& operator<<(std::ostream& os, const GroupCTSCmd& c) { return c.print(os); }
diff --git a/Base/src/cts/LoadDefsCmd.cpp b/Base/src/cts/LoadDefsCmd.cpp
new file mode 100644
index 0000000..39e73d1
--- /dev/null
+++ b/Base/src/cts/LoadDefsCmd.cpp
@@ -0,0 +1,154 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #43 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <boost/make_shared.hpp>
+#include "ClientToServerCmd.hpp"
+#include "AbstractServer.hpp"
+#include "AbstractClientEnv.hpp"
+#include "Str.hpp"
+#include "CtsApi.hpp"
+#include "Defs.hpp"
+#include "Log.hpp"
+#include "DefsStructureParser.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+namespace po = boost::program_options;
+
+LoadDefsCmd::LoadDefsCmd(const std::string& defs_filename, bool force)
+: force_(force), defs_(Defs::create()), defs_filename_(defs_filename)
+{
+ if (defs_filename_.empty()) {
+ std::stringstream ss;
+ ss << "LoadDefsCmd::LoadDefsCmd: The pathname to the definition file must be provided\n" << LoadDefsCmd::desc();
+ throw std::runtime_error(ss.str());
+ }
+
+ // At the end of the parse check the trigger/complete expressions and resolve in-limits
+ DefsStructureParser checkPtParser( defs_.get(), defs_filename_ );
+ std::string errMsg, warningMsg;
+ if ( checkPtParser.doParse( errMsg , warningMsg) ) {
+ // Dump out the in memory Node tree
+ // std::cout << defs_.get();
+
+ // Out put any warning to standard output
+ cout << warningMsg;
+ }
+ else {
+ std::stringstream ss; ss << "\nLoadDefsCmd::LoadDefsCmd. Failed to parse file " << defs_filename_ << "\n";
+ ss << errMsg;
+ throw std::runtime_error( ss.str() );
+ }
+}
+
+bool LoadDefsCmd::equals(ClientToServerCmd* rhs) const
+{
+ LoadDefsCmd* the_rhs = dynamic_cast<LoadDefsCmd*>(rhs);
+ if (!the_rhs) return false;
+
+ if (!UserCmd::equals(rhs)) return false;
+
+ if (defs_ == NULL && the_rhs->theDefs() == NULL) return true;
+ if (defs_ == NULL && the_rhs->theDefs() != NULL) return false;
+ if (defs_ != NULL && the_rhs->theDefs() == NULL) return false;
+
+ return (*defs_ == *(the_rhs->theDefs()));
+}
+
+STC_Cmd_ptr LoadDefsCmd::doHandleRequest(AbstractServer* as) const
+{
+ as->update_stats().load_defs_++;
+
+ assert(isWrite()); // isWrite used in handleRequest() to control check pointing
+ if (defs_) {
+
+ // After the updateDefs, defs_ will be left with NO suites.
+ // Can't really used defs_ after this point
+ // *NOTE* Externs are not persisted. Hence calling check() will report
+ // all errors, references are not resolved.
+ as->updateDefs(defs_,force_);
+ }
+
+ return PreAllocatedReply::ok_cmd();
+}
+
+std::ostream& LoadDefsCmd::print(std::ostream& os) const
+{
+ /// If defs_filename_ is empty, the Defs was a in memory defs.
+ if (defs_filename_.empty()) {
+ return user_cmd(os,CtsApi::to_string(CtsApi::loadDefs("<in-memory-defs>",force_,false/*check_only*/)));
+ }
+ return user_cmd(os,CtsApi::to_string(CtsApi::loadDefs(defs_filename_,force_,false/*check_only*/)));
+}
+
+const char* LoadDefsCmd::arg() { return CtsApi::loadDefsArg();}
+const char* LoadDefsCmd::desc() {
+ return "Check and load definition file into server.\n"
+ "The loaded definition will be checked for valid trigger and complete expressions,\n"
+ "additionally in-limit references to limits will be validated.\n"
+ "If the server already has the 'suites' of the same name, then a error message is issued.\n"
+ "The suite's can be overwritten if the force option is used.\n"
+ "To just check the definition and not send to server, use 'check_only'\n"
+ " arg1 = path to the definition file\n"
+ " arg2 = (optional) [ force | check_only ] # default = false for both\n"
+ "Usage:\n"
+ "--load=/my/home/exotic.def # will error if suites of same name exists\n"
+ "--load=/my/home/exotic.def force # overwrite suite's of same name\n"
+ "--load=/my/home/exotic.def check_only # Just check, don't send to server"
+ ;
+}
+
+void LoadDefsCmd::addOption(boost::program_options::options_description& desc) const{
+ desc.add_options()( LoadDefsCmd::arg(), po::value< vector<string> >()->multitoken(), LoadDefsCmd:: desc() );
+}
+
+void LoadDefsCmd::create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const
+{
+ vector<string> args = vm[ arg() ].as< vector<string> >();
+ if (clientEnv->debug()) dumpVecArgs(LoadDefsCmd::arg(),args);
+
+ bool check_only = false;
+ bool force = false;
+ std::string defs_filename;
+ for(size_t i = 0; i < args.size(); i++) {
+ if (args[i] == "force") force = true;
+ else if (args[i] == "check_only") check_only = true;
+ else defs_filename = args[i];
+ }
+ if (clientEnv->debug()) cout << " LoadDefsCmd::create: Defs file '" << defs_filename << "'.\n";
+
+ cmd = LoadDefsCmd::create(defs_filename,force, check_only,clientEnv );
+}
+
+Cmd_ptr LoadDefsCmd::create(const std::string& defs_filename, bool force, bool check_only, AbstractClientEnv* clientEnv)
+{
+ // The constructor can throw if parsing of defs_filename fail's
+ boost::shared_ptr<LoadDefsCmd> load_cmd = boost::make_shared<LoadDefsCmd>(defs_filename,force);
+
+ // Don't send to server if checking, i.e cmd not set
+ if (check_only) return Cmd_ptr();
+
+ // For test allow the server environment to be changed, i.e. allow us to inject ECF_CLIENT
+ // The server will also update the env on the defs, server will override client env, where they clash
+ load_cmd->theDefs()->set_server().add_or_update_user_variables( clientEnv->env() );
+
+ return load_cmd;
+}
+
+
+std::ostream& operator<<(std::ostream& os, const LoadDefsCmd& c) { return c.print(os); }
diff --git a/Base/src/cts/LogCmd.cpp b/Base/src/cts/LogCmd.cpp
new file mode 100644
index 0000000..a7f8f96
--- /dev/null
+++ b/Base/src/cts/LogCmd.cpp
@@ -0,0 +1,258 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #30 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include "boost/filesystem/path.hpp"
+#include "boost/filesystem/operations.hpp"
+
+#include <boost/algorithm/string/trim.hpp>
+
+#include "ClientToServerCmd.hpp"
+#include "AbstractServer.hpp"
+#include "AbstractClientEnv.hpp"
+#include "Log.hpp"
+#include "CtsApi.hpp"
+#include "Str.hpp"
+#include "Defs.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+namespace po = boost::program_options;
+namespace fs = boost::filesystem;
+
+
+LogCmd::LogCmd(LogApi a, int get_last_n_lines)
+: api_(a), get_last_n_lines_(get_last_n_lines)
+{
+ if (get_last_n_lines_ == 0) get_last_n_lines_ = Log::get_last_n_lines_default();
+}
+
+
+LogCmd::LogCmd()
+: api_(LogCmd::GET),get_last_n_lines_(Log::get_last_n_lines_default()) {}
+
+
+LogCmd::LogCmd(const std::string& path)
+: api_(NEW),get_last_n_lines_(Log::get_last_n_lines_default()),new_path_(path)
+{
+ // ECFLOW-154, If path to new log file is specified, it should only be checked by the server,
+ // as that could be on a different machine.
+ // ECFLOW-174, Never get the full log, as this can make server consume to much memory
+ // default taken from get_last_n_lines_default
+ // ECFLOW-377, should remove leading/trailing spaces from path
+ boost::algorithm::trim(new_path_);
+}
+
+std::ostream& LogCmd::print(std::ostream& os) const
+{
+ switch (api_) {
+ case LogCmd::GET: return user_cmd(os,CtsApi::to_string(CtsApi::getLog(get_last_n_lines_))); break;
+ case LogCmd::CLEAR: return user_cmd(os,CtsApi::clearLog()); break;
+ case LogCmd::FLUSH: return user_cmd(os,CtsApi::flushLog()); break;
+ case LogCmd::NEW: return user_cmd(os,CtsApi::to_string(CtsApi::new_log(new_path_))); break;
+ case LogCmd::PATH: return user_cmd(os,CtsApi::get_log_path()); break;
+ default : throw std::runtime_error( "LogCmd::print: Unrecognised log api command,") ;
+ }
+ return os;
+}
+
+bool LogCmd::equals(ClientToServerCmd* rhs) const
+{
+ LogCmd* the_rhs = dynamic_cast< LogCmd* > ( rhs );
+ if ( !the_rhs ) return false;
+ if (api_ != the_rhs->api()) return false;
+ if (get_last_n_lines_ != the_rhs->get_last_n_lines()) return false;
+ if (new_path_ != the_rhs->new_path()) return false;
+ return UserCmd::equals(rhs);
+}
+
+// changed for release 4.1.0
+bool LogCmd::isWrite() const
+{
+ switch (api_) {
+ case LogCmd::GET: return false; break;
+ case LogCmd::CLEAR: return false; break;
+ case LogCmd::FLUSH: return false; break;
+ case LogCmd::NEW: return true; break;
+ case LogCmd::PATH: return false; break;
+ default : throw std::runtime_error( "LogCmd::isWrite: Unrecognised log api command,") ;
+ }
+ return false;
+}
+
+STC_Cmd_ptr LogCmd::doHandleRequest(AbstractServer* as) const
+{
+ as->update_stats().log_cmd_++;
+
+ if (Log::instance()) {
+ switch (api_) {
+ case LogCmd::GET: return PreAllocatedReply::string_cmd( Log::instance()->contents(get_last_n_lines_) ); break;
+ case LogCmd::CLEAR: Log::instance()->clear(); break;
+ case LogCmd::FLUSH: Log::instance()->flush(); break;
+ case LogCmd::NEW: {
+ if (!new_path_.empty()) {
+ Log::instance()->new_path(new_path_); // will throw for errors
+
+ // *NOTE* calling --log=new <path> should be treated the *SAME* as editing ECF_LOG in the GUI
+ // This is done adding it as a *USER* variable. This overloads the server variables
+ // It also allows us to see the change in GUI. Note: Defs/server_variables are not synced
+ // ECFLOW-376
+ as->defs()->set_server().add_or_update_user_variables(Str::ECF_LOG(),Log::instance()->path());
+ }
+ else {
+ // User could have overridden ECF_LOG variable
+ // *FIRST* look at user variables, then look at *server* variables.
+ std::string log_file_name = as->defs()->server().find_variable(Str::ECF_LOG());
+
+ // ECFLOW-377 should remove leading/trailing spaces from path
+ boost::algorithm::trim(log_file_name);
+
+ Log::instance()->new_path(log_file_name); // will throw for errors
+ }
+
+ as->stats().ECF_LOG_ = Log::instance()->path(); // do NOT update number of requests
+ break;
+ }
+ case LogCmd::PATH: return PreAllocatedReply::string_cmd( Log::instance()->path() ); break;
+ default : throw std::runtime_error( "Unrecognised log api command,") ;
+ }
+ }
+ return PreAllocatedReply::ok_cmd();
+}
+
+const char* LogCmd::arg() { return "log";}
+const char* LogCmd::desc() {
+ return "Get,clear,flush or create a new log file.\n"
+ "The user must ensure that a valid path is specified.\n"
+ "Specifying '--log=get' with a large number of lines from the server,\n"
+ "can consume a lot of **memory**. The log file can be a very large file,\n"
+ "hence we use a default of 100 lines, optionally the number of lines can be specified.\n"
+ " arg1 = [ get | clear | flush | new | path ]\n"
+ " get - Outputs the log file to standard out.\n"
+ " defaults to return the last 100 lines\n"
+ " The second argument can specify how many lines to return\n"
+ " clear - Clear the log file of its contents.\n"
+ " flush - Flush and close the log file. (only temporary) next time\n"
+ " server writes to log, it will be opened again. Hence it best\n"
+ " to halt the server first\n"
+ " new - Flush and close the existing log file, and start using the\n"
+ " the path defined for ECF_LOG. By changing this variable\n"
+ " a new log file path can be used\n"
+ " Alternatively an explicit path can also be provided\n"
+ " in which case ECF_LOG is also updated\n"
+ " path - Returns the path name to the existing log file\n"
+ " arg2 = [ new_path | optional last n lines ]\n"
+ " if get specified can specify lines to get. Value must be convertible to an integer\n"
+ " Otherwise if arg1 is 'new' then the second argument must be a path\n"
+ "Usage:\n"
+ " --log=get # Write the last 100 lines of the log file to standard out\n"
+ " --log=get 200 # Write the last 200 lines of the log file to standard out\n"
+ " --log=clear # Clear the log file. The log is now empty\n"
+ " --log=flush # Flush and close log file, next request will re-open log file\n"
+ " --log=new /path/to/new/log/file # Close and flush log file, and create a new log file, updates ECF_LOG\n"
+ " --log=new # Close and flush log file, and create a new log file using ECF_LOG variable"
+ ;
+}
+
+void LogCmd::addOption(boost::program_options::options_description& desc) const {
+ desc.add_options()( LogCmd::arg(), po::value< vector<string> >()->multitoken(), LogCmd::desc() );
+}
+
+void LogCmd::create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* ac) const
+{
+ vector<string> args = vm[ arg() ].as< vector<string> >();
+
+ if (ac->debug()) dumpVecArgs(LogCmd::arg(),args);
+
+ if (!args.empty() && args[0] == "get") {
+
+ if ( args.size() != 1 && args.size() != 2) {
+ std::stringstream ss;
+ ss << "LogCmd: Please use '--log==get 100' to get the log file contents from the server\n";
+ ss << "optionally an integer can be provide to specify the last number of lines\n";
+ throw std::runtime_error( ss.str() );
+ }
+
+ if (args.size() == 1 ) {
+ // This will retrieve Log::get_last_n_lines_default() lines from the log file.
+ cmd = Cmd_ptr( new LogCmd( LogCmd::GET , Log::get_last_n_lines_default() ) );
+ return;
+ }
+
+ int value = Log::get_last_n_lines_default();
+ if (args.size() == 2) {
+ try { value = boost::lexical_cast<int>(args[1]); }
+ catch (boost::bad_lexical_cast& e) {
+ throw std::runtime_error( "LogCmd: Second argument must be a integer, i.e. --log get 100\n" );
+ }
+ }
+
+ cmd = Cmd_ptr( new LogCmd( LogCmd::GET, value ) );
+ return ;
+ }
+
+ if (!args.empty() && args[0] == "clear") {
+
+ if (args.size() != 1 ) {
+ std::stringstream ss;
+ ss << "LogCmd: Too many arguments. Please use " << CtsApi::clearLog() << " to clear the log file\n";
+ throw std::runtime_error( ss.str() );
+ }
+ cmd = Cmd_ptr( new LogCmd( LogCmd::CLEAR ) );
+ return;
+ }
+ if (!args.empty() && args[0] == "flush") {
+
+ if (args.size() != 1 ) {
+ std::stringstream ss;
+ ss << "LogCmd: Too many arguments. Please use " << CtsApi::flushLog() << " to flush the log file\n";
+ throw std::runtime_error( ss.str() );
+ }
+ cmd = Cmd_ptr( new LogCmd( LogCmd::FLUSH ) );
+ return;
+ }
+ if (!args.empty() && args[0] == "path") {
+
+ if (args.size() != 1 ) {
+ std::stringstream ss;
+ ss << "LogCmd: Too many arguments. Please use " << CtsApi::get_log_path() << " to get the log file path\n";
+ throw std::runtime_error( ss.str() );
+ }
+ cmd = Cmd_ptr( new LogCmd( LogCmd::PATH ) );
+ return;
+ }
+
+ if (!args.empty() && args[0] == "new") {
+
+ if (args.size() > 2 ) {
+ std::stringstream ss;
+ ss << "LogCmd: Too many arguments. Expected --log=new OR --log=new /path/to/newlog/file\n";
+ throw std::runtime_error( ss.str() );
+ }
+ std::string path;
+ if ( args.size() == 2 ) {
+ path = args[1];
+ }
+ cmd = Cmd_ptr( new LogCmd( path ) );
+ return;
+ }
+
+ std::stringstream ss;
+ ss << "LogCmd: The arguments have not been specified correctly\n" << LogCmd::desc();
+ throw std::runtime_error( ss.str() );
+}
+
+std::ostream& operator<<(std::ostream& os, const LogCmd& c) { return c.print(os); }
diff --git a/Base/src/cts/LogMessageCmd.cpp b/Base/src/cts/LogMessageCmd.cpp
new file mode 100644
index 0000000..00425a4
--- /dev/null
+++ b/Base/src/cts/LogMessageCmd.cpp
@@ -0,0 +1,72 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #14 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <iostream>
+
+#include "ClientToServerCmd.hpp"
+#include "AbstractServer.hpp"
+#include "AbstractClientEnv.hpp"
+#include "Log.hpp"
+#include "Stats.hpp"
+#include "CtsApi.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+namespace po = boost::program_options;
+
+std::ostream& LogMessageCmd::print(std::ostream& os) const
+{
+ return user_cmd(os,CtsApi::logMsg(msg_));
+}
+
+bool LogMessageCmd::equals(ClientToServerCmd* rhs) const
+{
+ LogMessageCmd* the_rhs = dynamic_cast< LogMessageCmd* > ( rhs );
+ if ( !the_rhs ) return false;
+ if (msg_ != the_rhs->msg()) return false;
+ return UserCmd::equals(rhs);
+}
+
+STC_Cmd_ptr LogMessageCmd::doHandleRequest(AbstractServer* as) const
+{
+ // ***** No need to log message here, already done via print, in base ****
+ as->update_stats().log_msg_cmd_++;
+ return PreAllocatedReply::ok_cmd();
+}
+
+const char* LogMessageCmd::arg() { return CtsApi::logMsgArg();}
+const char* LogMessageCmd::desc() {
+ return
+ "Writes the input string to the log file.\n"
+ " arg1 = string\n"
+ "Usage:\n"
+ " --msg=\"place me in the log file\""
+ ;
+}
+
+void LogMessageCmd::addOption(boost::program_options::options_description& desc) const {
+ desc.add_options()( LogMessageCmd::arg(), po::value< string >(), LogMessageCmd::desc() );
+}
+
+void LogMessageCmd::create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* ace) const
+{
+ string msg = vm[ arg() ].as< string >();
+ if (ace->debug()) { cout << " LogMessageCmd::create arg = " << msg << "\n";}
+ cmd = Cmd_ptr( new LogMessageCmd( msg ) );
+}
+
+std::ostream& operator<<(std::ostream& os, const LogMessageCmd& c) { return c.print(os); }
diff --git a/Base/src/cts/OrderNodeCmd.cpp b/Base/src/cts/OrderNodeCmd.cpp
new file mode 100644
index 0000000..f4bf593
--- /dev/null
+++ b/Base/src/cts/OrderNodeCmd.cpp
@@ -0,0 +1,110 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #21 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include "ClientToServerCmd.hpp"
+#include "AbstractServer.hpp"
+#include "AbstractClientEnv.hpp"
+#include "CtsApi.hpp"
+#include "Defs.hpp"
+#include "Task.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+namespace po = boost::program_options;
+
+bool OrderNodeCmd::equals(ClientToServerCmd* rhs) const
+{
+ OrderNodeCmd* the_rhs = dynamic_cast< OrderNodeCmd* > ( rhs );
+ if ( !the_rhs ) return false;
+ if (absNodepath_ != the_rhs->absNodepath()) return false;
+ if (option_ != the_rhs->option()) return false;
+ return UserCmd::equals(rhs);
+}
+
+std::ostream& OrderNodeCmd::print(std::ostream& os) const
+{
+ return user_cmd(os,CtsApi::to_string(CtsApi::order(absNodepath_,NOrder::toString(option_))));
+}
+
+STC_Cmd_ptr OrderNodeCmd::doHandleRequest(AbstractServer* as) const
+{
+ assert(isWrite()); // isWrite used in handleRequest() to control check pointing
+
+ as->update_stats().order_node_++;
+
+ node_ptr theNode = find_node_for_edit(as,absNodepath_);
+
+ Node* theParent = theNode->parent();
+ if ( theParent ) theParent->order(theNode.get(), option_);
+ else as->defs()->order(theNode.get(), option_);
+
+ return doJobSubmission( as );
+}
+
+const char* OrderNodeCmd::arg() { return CtsApi::orderArg();}
+const char* OrderNodeCmd::desc() {
+ return
+ "Re-orders the nodes held by the server\n"
+ " arg1 = node path\n"
+ " arg2 = [ top | bottom | alpha | order | up | down ]\n"
+ "It should be noted that in the absence of triggers and time/date dependencies,\n"
+ "the tasks are submitted in order.\n"
+ "This changes the order and hence affects the submission order::\n\n"
+ " o top raises the node within its parent, so that it is first\n"
+ " o bottom lowers the node within its parent, so that it is last\n"
+ " o alpha Arranges for all the peers of selected note to be sorted alphabetically (case-insensitive)\n"
+ " o order Arranges for all the peers of selected note to be sorted in reverse alphabet(case-insensitive)\n"
+ " o up Moves the selected node up one place amongst its peers\n"
+ " o down Moves the selected node down one place amongst its peers\n\n"
+ "This command can fail because:\n"
+ "- The node path does not exist in the server\n"
+ "- The order_type is not does not match one of arg2\n"
+ "Usage:\n"
+ " --order=/suite/f1 top # move node f1 to the top"
+ ;
+}
+
+void OrderNodeCmd::addOption(boost::program_options::options_description& desc) const{
+ desc.add_options()( OrderNodeCmd::arg(), po::value< vector<string> >()->multitoken(), OrderNodeCmd::desc() );
+}
+void OrderNodeCmd::create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* ac) const
+{
+ vector<string> args = vm[ OrderNodeCmd::arg() ].as< vector<string> >();
+
+ if (ac->debug()) dumpVecArgs(OrderNodeCmd::arg(),args);
+
+ if (args.size() != 2 ) {
+ std::stringstream ss;
+ ss << "OrderNodeCmd: Two arguments expected. Please specify one of:\n";
+ ss << OrderNodeCmd::arg() << " pathToNode top\n";
+ ss << OrderNodeCmd::arg() << " pathToNode bottom\n";
+ ss << OrderNodeCmd::arg() << " pathToNode alpha\n";
+ ss << OrderNodeCmd::arg() << " pathToNode order\n";
+ ss << OrderNodeCmd::arg() << " pathToNode up\n";
+ ss << OrderNodeCmd::arg() << " pathToNode down\n";
+ throw std::runtime_error( ss.str() );
+ }
+
+ if (!NOrder::isValid(args[1])) {
+ throw std::runtime_error( "OrderNodeCmd: Invalid second option: please specify one of [ top, bottom, alpha, order, up, down ]\n");
+ }
+
+ cmd = Cmd_ptr(new OrderNodeCmd( args[0],NOrder::toOrder(args[1])));
+}
+
+std::ostream& operator<<(std::ostream& os, const OrderNodeCmd& c) { return c.print(os); }
+
diff --git a/Base/src/cts/PathsCmd.cpp b/Base/src/cts/PathsCmd.cpp
new file mode 100644
index 0000000..aaad254
--- /dev/null
+++ b/Base/src/cts/PathsCmd.cpp
@@ -0,0 +1,514 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #16 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <algorithm>
+#include <boost/make_shared.hpp>
+
+#include "ClientToServerCmd.hpp"
+#include "AbstractServer.hpp"
+#include "AbstractClientEnv.hpp"
+#include "CtsApi.hpp"
+#include "Defs.hpp"
+#include "Task.hpp"
+#include "Suite.hpp"
+#include "SuiteChanged.hpp"
+#include "Ecf.hpp"
+#include "Log.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+namespace po = boost::program_options;
+
+// forward declare static functions
+static void check_for_active_or_submitted_tasks(AbstractServer* as,node_ptr theNodeToDelete);
+
+
+PathsCmd::PathsCmd(Api api,const std::string& absNodePath, bool force)
+: api_(api),force_(force)
+{
+ if (!absNodePath.empty()) paths_.push_back(absNodePath);
+}
+
+std::ostream& PathsCmd::print(std::ostream& os) const
+{
+ return my_print(os,paths_);
+}
+
+std::ostream& PathsCmd::print(std::ostream& os, const std::string& path) const
+{
+ std::vector<std::string> paths(1,path);
+ return my_print(os,paths);
+}
+
+std::ostream& PathsCmd::my_print(std::ostream& os,const std::vector<std::string>& paths) const
+{
+ switch (api_) {
+ case PathsCmd::DELETE: return user_cmd(os,CtsApi::to_string(CtsApi::delete_node(paths,force_))); break;
+ case PathsCmd::SUSPEND: return user_cmd(os,CtsApi::to_string(CtsApi::suspend(paths))); break;
+ case PathsCmd::RESUME: return user_cmd(os,CtsApi::to_string(CtsApi::resume(paths))); break;
+ case PathsCmd::KILL: return user_cmd(os,CtsApi::to_string(CtsApi::kill(paths))); break;
+ case PathsCmd::STATUS: return user_cmd(os,CtsApi::to_string(CtsApi::status(paths))); break;
+ case PathsCmd::CHECK: return user_cmd(os,CtsApi::to_string(CtsApi::check(paths))); break;
+ case PathsCmd::EDIT_HISTORY: return user_cmd(os,CtsApi::to_string(CtsApi::edit_history(paths))); break;
+ case PathsCmd::NO_CMD: break;
+ default: assert(false);break;
+ }
+ return os;
+}
+
+bool PathsCmd::equals(ClientToServerCmd* rhs) const
+{
+ PathsCmd* the_rhs = dynamic_cast< PathsCmd* > ( rhs );
+ if ( !the_rhs ) return false;
+ if (api_ != the_rhs->api()) return false;
+ if (paths_ != the_rhs->paths()) return false;
+ if (force_ != the_rhs->force()) return false;
+ return UserCmd::equals(rhs);
+}
+
+bool PathsCmd::isWrite() const
+{
+ switch (api_) {
+ case PathsCmd::DELETE: return true; break; // requires write privilege
+ case PathsCmd::SUSPEND: return true; break; // requires write privilege
+ case PathsCmd::RESUME: return true; break; // requires write privilege
+ case PathsCmd::KILL: return true; break; // requires write privilege
+ case PathsCmd::STATUS: return false; break; // read only
+ case PathsCmd::CHECK: return false; break; // read only
+ case PathsCmd::EDIT_HISTORY: return false; break; // read only
+ case PathsCmd::NO_CMD: break;
+ default: break;
+ }
+ assert(false);
+ return false;
+}
+
+const char* PathsCmd::theArg() const
+{
+ switch (api_) {
+ case PathsCmd::DELETE: return CtsApi::delete_node_arg(); break;
+ case PathsCmd::SUSPEND: return CtsApi::suspend_arg(); break;
+ case PathsCmd::RESUME: return CtsApi::resume_arg(); break;
+ case PathsCmd::KILL: return CtsApi::kill_arg(); break;
+ case PathsCmd::STATUS: return CtsApi::statusArg(); break;
+ case PathsCmd::CHECK: return CtsApi::check_arg(); break;
+ case PathsCmd::EDIT_HISTORY: return CtsApi::edit_history_arg(); break;
+ case PathsCmd::NO_CMD: break;
+ default: break;
+ }
+ assert(false);
+ return NULL;
+}
+
+bool PathsCmd::delete_all_cmd() const
+{
+ if (api_ == PathsCmd::DELETE && paths_.empty()) {
+ return true;
+ }
+ return false ;
+}
+
+STC_Cmd_ptr PathsCmd::doHandleRequest(AbstractServer* as) const
+{
+ std::stringstream ss;
+ switch (api_) {
+
+ case PathsCmd::CHECK: {
+ as->update_stats().check_++;
+
+ if ( paths_.empty() ) {
+ // check all the defs,
+ std::string error_msg,warning_msg;
+ if (!as->defs()->check(error_msg,warning_msg)) {
+ error_msg += "\n";
+ error_msg += warning_msg;
+ return PreAllocatedReply::string_cmd(error_msg);
+ }
+ return PreAllocatedReply::string_cmd(warning_msg); // can be empty
+ }
+ else {
+ std::string acc_warning_msg;
+ size_t vec_size = paths_.size();
+ for(size_t i = 0; i < vec_size; i++) {
+
+ node_ptr theNodeToCheck = as->defs()->findAbsNode(paths_[i]);
+ if (!theNodeToCheck.get()) {
+ ss << "PathsCmd:Check: Could not find node at path '" << paths_[i] << "'\n";
+ LOG(Log::ERR,"Check: Could not find node at path " << paths_[i]);
+ continue;
+ }
+
+ std::string error_msg,warning_msg;
+ if (!theNodeToCheck->check(error_msg,warning_msg)) {
+ error_msg += "\n";
+ error_msg += warning_msg;
+ return PreAllocatedReply::string_cmd(error_msg);
+ }
+ acc_warning_msg += warning_msg;
+ }
+ std::string paths_not_fnd_error_msg = ss.str();
+ if (!paths_not_fnd_error_msg.empty()) throw std::runtime_error( paths_not_fnd_error_msg );
+ return PreAllocatedReply::string_cmd(acc_warning_msg);
+ }
+ break;
+ }
+
+ case PathsCmd::DELETE: {
+ as->update_stats().node_delete_++;
+
+ if ( paths_.empty() ) {
+ if (!force_) check_for_active_or_submitted_tasks(as,node_ptr());
+ else as->zombie_ctrl().add_user_zombies(as->defs());
+ as->clear_defs();
+ }
+ else {
+
+ size_t vec_size = paths_.size();
+ for(size_t i = 0; i < vec_size; i++) {
+
+ node_ptr theNodeToDelete = as->defs()->findAbsNode(paths_[i]);
+ if (!theNodeToDelete.get()) {
+ ss << "PathsCmd:Delete: Could not find node at path '" << paths_[i] << "'\n";
+ LOG(Log::ERR,"Delete: Could not find node at path " << paths_[i]);
+ continue;
+ }
+ // since node is to be deleted, we need to record the paths.
+ add_node_path_for_edit_history(paths_[i]);
+
+ if (!force_) check_for_active_or_submitted_tasks(as,theNodeToDelete);
+ else as->zombie_ctrl().add_user_zombies(theNodeToDelete);
+
+ if (!as->defs()->deleteChild( theNodeToDelete.get() )) {
+ std::string errorMsg = "Delete: Can not delete node " + theNodeToDelete->debugNodePath();
+ throw std::runtime_error( errorMsg ) ;
+ }
+ }
+ }
+ break;
+ }
+
+ case PathsCmd::SUSPEND: {
+ as->update_stats().node_suspend_++;
+ size_t vec_size = paths_.size();
+ for(size_t i = 0; i < vec_size; i++) {
+ node_ptr theNode = find_node_for_edit_no_throw(as,paths_[i]);
+ if (!theNode.get()) {
+ ss << "PathsCmd:Suspend: Could not find node at path '" << paths_[i] << "'\n";
+ LOG(Log::ERR,"Suspend: Could not find node at path " << paths_[i]);
+ continue;
+ }
+ SuiteChanged0 changed(theNode);
+ theNode->suspend();
+ }
+ break;
+ }
+
+ case PathsCmd::RESUME: {
+
+ // At the end of resume, we need to traverse node tree, and do job submission
+ as->update_stats().node_resume_++;
+ size_t vec_size = paths_.size();
+ for(size_t i = 0; i < vec_size; i++) {
+ node_ptr theNode = find_node_for_edit_no_throw(as,paths_[i]);
+ if (!theNode.get()) {
+ ss << "PathsCmd:Resume: Could not find node at path '" << paths_[i] << "'\n";
+ LOG(Log::ERR,"Resume: Could not find path " << paths_[i]);
+ continue;
+ }
+ SuiteChanged0 changed(theNode);
+ theNode->resume();
+ as->increment_job_generation_count(); // in case we throw below
+ }
+ break;
+ }
+
+ case PathsCmd::KILL: {
+ as->update_stats().node_kill_++;
+ size_t vec_size = paths_.size();
+ for(size_t i = 0; i < vec_size; i++) {
+ node_ptr theNode = find_node_for_edit_no_throw(as,paths_[i]);
+ if (!theNode.get()) {
+ ss << "PathsCmd:Kill: Could not find node at path '" << paths_[i] << "'\n";
+ LOG(Log::ERR,"Kill: Could not find node at path " << paths_[i]);
+ continue;
+ }
+ SuiteChanged0 changed(theNode);
+ theNode->kill(); // this can throw std::runtime_error
+ }
+ break;
+ }
+
+ case PathsCmd::STATUS: {
+ as->update_stats().node_status_++;
+ size_t vec_size = paths_.size();
+ for(size_t i = 0; i < vec_size; i++) {
+ node_ptr theNode = find_node_for_edit_no_throw(as,paths_[i]);
+ if (!theNode.get()) {
+ ss << "PathsCmd:Status: Could not find node at path '" << paths_[i] << "'\n";
+ LOG(Log::ERR,"Status: Could not find node at path " << paths_[i]);
+ continue;
+ }
+ if (!theNode->suite()->begun()) {
+ std::stringstream ss;
+ ss << "Status failed. For " << paths_[i] << " The suite " << theNode->suite()->name() << " must be 'begun' first\n";
+ throw std::runtime_error( ss.str() ) ;
+ }
+ SuiteChanged0 changed(theNode);
+ theNode->status(); // this can throw std::runtime_error
+ }
+ break;
+ }
+
+ case PathsCmd::EDIT_HISTORY: {
+ as->update_stats().node_edit_history_++;
+ if (paths_.empty()) throw std::runtime_error( "No paths specified for edit history") ;
+ // Only first path used
+ const std::deque<std::string>& edit_history = as->defs()->get_edit_history(paths_[0]);
+ std::vector<std::string> vec; vec.reserve(edit_history.size());
+ std::copy(edit_history.begin(),edit_history.end(),std::back_inserter(vec));
+ return PreAllocatedReply::string_vec_cmd(vec);
+ }
+
+ case PathsCmd::NO_CMD: assert(false); break;
+
+ default: assert(false); break;
+ }
+
+ std::string error_msg = ss.str();
+ if (!error_msg.empty()) {
+ throw std::runtime_error( error_msg ) ;
+ }
+
+ if ( PathsCmd::RESUME == api_) {
+ // After resume we need to do job submission.
+ return doJobSubmission(as);
+ }
+
+ return PreAllocatedReply::ok_cmd();
+}
+
+static void check_for_active_or_submitted_tasks(AbstractServer* as,node_ptr theNodeToDelete)
+{
+ vector<Task*> taskVec;
+ if ( theNodeToDelete.get() ) {
+ theNodeToDelete->getAllTasks(taskVec);
+ }
+ else {
+ as->defs()->getAllTasks(taskVec);
+ }
+
+ vector<Task*> activeVec,submittedVec;
+ BOOST_FOREACH(Task* t, taskVec) {
+ if (t->state() == NState::ACTIVE) activeVec.push_back(t);
+ if (t->state() == NState::SUBMITTED) submittedVec.push_back(t);
+ }
+ if (!activeVec.empty() || !submittedVec.empty()) {
+ std::stringstream ss;
+ if (theNodeToDelete.get()) ss << "Can not delete node " << theNodeToDelete->debugNodePath() << "\n";
+ else ss << "Can not delete all nodes.\n";
+ if (!activeVec.empty() ) {
+ ss << " There are " << activeVec.size() << " active tasks. First : " << activeVec.front()->absNodePath() << "\n";
+ }
+ if (!submittedVec.empty() ) {
+ ss << " There are " << submittedVec.size() << " submitted tasks. First : " << submittedVec.front()->absNodePath() << "\n";
+ }
+ ss << "Please use the 'force' option to bypass this check, at the expense of creating zombies\n";
+ throw std::runtime_error( ss.str() ) ;
+ }
+}
+
+static const char* delete_node_desc() {
+ return
+ "Deletes the specified node(s) or _ALL_ existing definitions( i.e delete all suites) in the server.\n"
+ " arg1 = [ force | yes ](optional) # Use this parameter to bypass checks, i.e. for active or submitted tasks\n"
+ " arg2 = yes(optional) # Use 'yes' to bypass the confirmation prompt\n"
+ " arg3 = node paths | _all_ # _all_ means delete all suites\n"
+ " # node paths must start with a leading '/'\n"
+ "Usage:\n"
+ " --delete=_all_ # Delete all suites in server. Use with care.\n"
+ " --delete=/suite/f1/t1 # Delete node at /suite/f1/t1. This will prompt\n"
+ " --delete=force /suite/f1/t1 # Delete node at /suite/f1/t1 even if active or submitted\n"
+ " --delete=force yes /s1 /s2 # Delete suites s1,s2 even if active or submitted, bypassing prompt"
+ ;
+}
+
+static const char* get_check_desc() {
+ return
+ "Checks the expression and limits in the server. Will also check trigger references.\n"
+ "Trigger expressions that reference paths that don't exist, will be reported as errors.\n"
+ "(Note: On the client side unresolved paths in trigger expressions must\n"
+ "have an associated 'extern' specified)\n"
+ " arg = [ _all_ | list of node paths ]\n"
+ "Usage:\n"
+ " --check=_all_ # Checks the whole suite\n"
+ " --check=/s1 /s2/f1/t1 # Check suite /s1 and task t1"
+ ;
+}
+
+static const char* get_kill_desc() {
+ return
+ "Kills the job associated with the node.\n"
+ "If a family or suite is selected, will kill hierarchically.\n"
+ "Kill uses the ECF_KILL_CMD variable. After variable substitution it is invoked as a command.\n"
+ "The command should be written in such a way that the output is written to %ECF_JOB%.kill\n"
+ "as this allow the --file command to report the output: .e.e.\n"
+ " /home/ma/emos/bin/ecfkill %USER% %HOST% %ECF_RID% %ECF_JOB% > %ECF_JOB%.kill 2>&1::\n"
+ "Usage::\n"
+ " --kill=/s1/f1/t1 /s1/f2/t2 # kill the jobs for tasks t1 and t2\n"
+ " --file=/s1/f1/t1 kill # write to standard out the '.kill' file for task /s1/f1/t1"
+ ;
+}
+const char* get_status_desc(){
+ return
+ "Shows the status of a job associated with a task.\n"
+ "If a family or suite is selected, will invoke status command hierarchically.\n"
+ "Status uses the ECF_STATUS_CMD variable. After variable substitution it is invoked as a command.\n"
+ "The command should be written in such a way that the output is written to %ECF_JOB%.stat\n"
+ "This will allow the output of status command to be shown by the --file command\n"
+ "i.e /home/ma/emos/bin/ecfstatus %USER% %HOST% %ECF_RID% %ECF_JOB% > %ECF_JOB%.stat 2>&1::\n"
+ "Usage::\n"
+ " --status=/s1/f1/t1 /s1/f2/t2\n"
+ " --file=/s1/f1/t1 stat # write to standard out the '.stat' file"
+ ;
+}
+const char* get_edit_history_desc(){
+ return
+ "Returns the edit history associated with a Node.\n"
+ "Usage::\n"
+ " --edit_history=/s1/f1/t1\n"
+ ;
+}
+const char* suspend_desc(){
+ return
+ "Suspend the given node. This prevents job generation for the given node, or any child node.\n"
+ "Usage::\n"
+ " --suspend=/s1/f1/t1 # suspend task s1/f1/t1\n"
+ " --suspend=/s1 /s2 # suspend suites /s1 and /s2\n"
+ ;
+}
+const char* resume_desc(){
+ return
+ "Resume the given node. This allows job generation for the given node, or any child node.\n"
+ "Usage::\n"
+ " --resume=/s1/f1/t1 # resume task s1/f1/t1\n"
+ " --resume=/s1 /s2 # resume suites /s1 and /s2\n"
+ ;
+}
+
+void PathsCmd::addOption(boost::program_options::options_description& desc) const
+{
+ switch (api_) {
+ case PathsCmd::CHECK:{
+ desc.add_options()(CtsApi::check_arg(),po::value< vector<string> >()->multitoken(),get_check_desc());
+ break;
+ }
+ case PathsCmd::DELETE:{
+ desc.add_options()( CtsApi::delete_node_arg(), po::value< vector<string> >()->multitoken(), delete_node_desc() );
+ break;
+ }
+ case PathsCmd::SUSPEND:{
+ desc.add_options()( CtsApi::suspend_arg(), po::value< vector<string> >()->multitoken(),suspend_desc());
+ break;
+ }
+ case PathsCmd::RESUME: {
+ desc.add_options()( CtsApi::resume_arg(), po::value< vector<string> >()->multitoken(),resume_desc());
+ break;
+ }
+ case PathsCmd::KILL: {
+ desc.add_options()( CtsApi::kill_arg(), po::value< vector<string> >()->multitoken(),get_kill_desc());
+ break;
+ }
+ case PathsCmd::STATUS: {
+ desc.add_options()( CtsApi::statusArg(), po::value< vector<string> >()->multitoken(), get_status_desc());
+ break;
+ }
+ case PathsCmd::EDIT_HISTORY: {
+ desc.add_options()( CtsApi::edit_history_arg(), po::value< vector<string> >()->multitoken(), get_edit_history_desc());
+ break;
+ }
+ case PathsCmd::NO_CMD: assert(false); break;
+ default: assert(false); break;
+ }
+}
+
+void PathsCmd::create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* ac ) const
+{
+ assert( api_ != PathsCmd::NO_CMD);
+
+ vector<string> args = vm[ theArg() ].as< vector<string> >();
+ if (ac->debug()) dumpVecArgs( theArg(), args);
+
+ std::vector<std::string> options,paths;
+ split_args_to_options_and_paths(args,options,paths); // relative order is still preserved
+
+ bool force = false;
+ if (api_ == PathsCmd::DELETE) {
+ bool all = false;
+ bool do_prompt = true;
+ size_t vec_size = options.size();
+ for(size_t i = 0; i < vec_size; i++) {
+ if (args[i] == "_all_") all = true;
+ if (args[i] == "force") force = true;
+ if (args[i] == "yes") do_prompt = false;
+ }
+
+ if (!all && paths.empty()) {
+ std::stringstream ss;
+ ss << "Delete: No paths specified. Paths must begin with a leading '/' character\n";
+ throw std::runtime_error( ss.str() );
+ }
+
+ if (do_prompt) {
+ std::string confirm;
+ if (paths.empty()) confirm = "Are you sure you want to delete all the suites ? ";
+ else {
+ confirm = "Are you sure want to delete nodes at paths:\n";
+ size_t vec_size = paths.size();
+ for(size_t i = 0; i < vec_size; i++) {
+ confirm += " " + paths[i];
+ if ( i == vec_size -1) confirm += " ? ";
+ else confirm += "\n";
+ }
+ }
+ prompt_for_confirmation(confirm);
+ }
+ }
+ else if (api_ == PathsCmd::CHECK) {
+
+ bool all = false;
+ size_t vec_size = options.size();
+ for(size_t i = 0; i < vec_size; i++) {
+ if (args[i] == "_all_") all = true;
+ }
+ if (!all && paths.empty()) {
+ std::stringstream ss;
+ ss << "Check: Please specify '_all_' or a list of paths. Paths must begin with a leading '/' character\n";
+ throw std::runtime_error( ss.str() );
+ }
+ }
+ else {
+ if (paths.empty()) {
+ std::stringstream ss;
+ ss << theArg() << ": No paths specified. Paths must begin with a leading '/' character\n";
+ throw std::runtime_error( ss.str() );
+ }
+ }
+
+ cmd = Cmd_ptr(new PathsCmd( api_ , paths, force));
+}
+
+std::ostream& operator<<(std::ostream& os, const PathsCmd& c) { return c.print(os); }
diff --git a/Base/src/cts/PlugCmd.cpp b/Base/src/cts/PlugCmd.cpp
new file mode 100644
index 0000000..f088708
--- /dev/null
+++ b/Base/src/cts/PlugCmd.cpp
@@ -0,0 +1,392 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #32 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/make_shared.hpp>
+
+#include "ClientToServerCmd.hpp"
+#include "AbstractServer.hpp"
+#include "AbstractClientEnv.hpp"
+#include "Str.hpp"
+#include "CtsApi.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Task.hpp"
+#include "Family.hpp"
+#include "NodePath.hpp"
+#include "Client.hpp"
+#include "SuiteChanged.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+namespace po = boost::program_options;
+
+//=======================================================================================
+
+bool PlugCmd::equals(ClientToServerCmd* rhs) const
+{
+ PlugCmd* the_rhs = dynamic_cast<PlugCmd*>(rhs);
+ if (!the_rhs) return false;
+ if ( source_ != the_rhs->source()) { return false; }
+ if ( dest_ != the_rhs->dest()) { return false; }
+ return UserCmd::equals(rhs);
+}
+
+std::ostream& PlugCmd::print(std::ostream& os) const
+{
+ return user_cmd(os,CtsApi::to_string(CtsApi::plug(source_,dest_)));
+}
+
+/// Class to manage locking: Only unlock if acquired the lock,
+class Lock {
+public:
+ Lock(const std::string& user, AbstractServer* as) : as_(as) { ok_ = as->lock(user); }
+ ~Lock() { if (ok_) as_->unlock(); }
+ bool ok() const { return ok_;}
+private:
+ bool ok_;
+ AbstractServer* as_;
+};
+
+STC_Cmd_ptr PlugCmd::doHandleRequest(AbstractServer* as) const
+{
+ as->update_stats().plug_++;
+
+ Lock lock(user(),as);
+ if (!lock.ok()) {
+ std::string errorMsg = "Plug command failed. User "; errorMsg += as->lockedUser();
+ errorMsg += " already has an exclusive lock";
+ throw std::runtime_error( errorMsg ) ;
+ }
+
+ node_ptr sourceNode = as->defs()->findAbsNode(source_);
+ if (!sourceNode.get()) throw std::runtime_error( "Plug command failed. Could not find source path " + source_ ) ;
+
+ // Moving a node which is active, or submitted, will lead to zombie's. hence prevent
+ if (sourceNode->state() == NState::ACTIVE || sourceNode->state() == NState::SUBMITTED) {
+ std::string errorMsg = "Plug command failed. The source node "; errorMsg += source_;
+ errorMsg += " is ";
+ errorMsg += NState::toString(sourceNode->state());
+ throw std::runtime_error( errorMsg ) ;
+ }
+
+ if (sourceNode->isAlias()) {
+ std::string errorMsg = "Plug command failed. The source node "; errorMsg += source_;
+ errorMsg += " is a Alias. Alias can not be moved";
+ throw std::runtime_error( errorMsg ) ;
+ }
+
+
+ // Check to see if dest node is on the same server
+ std::string host,port,destPath;
+ node_ptr destNode = as->defs()->findAbsNode(dest_);
+ if (!destNode.get()) {
+
+ // Dest could still be on the same server. Extract host and port
+ // expect: host:port/suite/family/node
+ if (!NodePath::extractHostPort(dest_,host,port)) {
+ std::string errorMsg = "Plug command failed. The destination path "; errorMsg += dest_;
+ errorMsg += " does not exist on server, and could not extract host/port from the destination path";
+ throw std::runtime_error( errorMsg ) ;
+ }
+
+ // Remove the host:port from the path
+ destPath = NodePath::removeHostPortFromPath(dest_);
+
+ std::pair<std::string,std::string> hostPortPair = as->hostPort();
+ if ( hostPortPair.first == host && hostPortPair.second == port) {
+
+ // Matches local server, try to find dest node again.
+ destNode = as->defs()->findAbsNode(destPath);
+ if (!destNode) {
+ std::string errorMsg = "Plug command failed. The destination path "; errorMsg += dest_;
+ errorMsg += " does not exist on server "; errorMsg += hostPortPair.first;
+ throw std::runtime_error( errorMsg ) ;
+ }
+ }
+ // dest_ is on another server.
+ }
+
+ if (!destNode.get()) {
+
+ // Since host/port does not match local server, move source node to remote server
+ try {
+ if (destPath.empty()) {
+ // Note destPath can be empty, when moving a suite
+ if (!sourceNode->isSuite()) {
+ throw std::runtime_error( "Destination path can only be empty when moving a whole suite to a new server" ) ;
+ }
+ }
+
+ {
+ // Server is acting like a client, Send MoveCmd to another server
+ // The source should end up being copied, when sent to remote server
+ boost::asio::io_service io_service;
+ Client theClient( io_service, Cmd_ptr( new MoveCmd(as->hostPort(),sourceNode.get(), destPath) ), host, port );
+ io_service.run();
+
+ ServerReply server_reply;
+ theClient.handle_server_response( server_reply, false /* debug */ );
+ if (server_reply.client_request_failed()) {
+ throw std::runtime_error( server_reply.error_msg() ) ;
+ }
+ }
+
+ // The move command was ok, remove the source node, and delete its memory
+ sourceNode->remove();
+
+ // Updated defs state
+ as->defs()->set_most_significant_state();
+
+ return PreAllocatedReply::ok_cmd();
+ }
+ catch (std::exception& e) {
+ std::stringstream ss; ss << "MoveCmd Failed for " << host << ":" << port << " " << e.what() << "\n";
+ throw std::runtime_error( ss.str() ) ;
+ }
+ }
+
+ // source and destination on same defs file
+
+ // If the destination is task, replace with its parent
+
+ Node* theDestNode = destNode.get();
+ if (theDestNode->isTask()) theDestNode = theDestNode->parent();
+
+ // Before we do remove the source node, check its ok to add it as a child
+ std::string errorMsg;
+ if (!theDestNode->isAddChildOk(sourceNode.get(),errorMsg) ) {
+ throw std::runtime_error( "Plug command failed. " + errorMsg ) ;
+ }
+
+ if (!theDestNode->addChild( sourceNode->remove() ) ) {
+ // This should never fail !!!! else we have lost/ and leaked source node !!!!
+ throw std::runtime_error("Fatal error plug command failed.") ;
+ }
+
+ add_node_for_edit_history(destNode);
+
+ // Updated defs state
+ as->defs()->set_most_significant_state();
+
+ return PreAllocatedReply::ok_cmd();
+}
+
+const char* PlugCmd::arg() { return CtsApi::plugArg();}
+const char* PlugCmd::desc() {
+ return
+ "Plug command is used to move nodes.\n"
+ "The destination node can be on another server In which case the destination\n"
+ "path should be of the form '<host>:<port>/suite/family/task\n"
+ " arg1 = path to source node\n"
+ " arg2 = path to the destination node\n"
+ "This command can fail because:\n"
+ "- Source node is in a 'active' or 'submitted' state\n"
+ "- Another user already has an lock\n"
+ "- source/destination paths do not exist on the corresponding servers\n"
+ "- If the destination node path is empty, i.e. only host:port is specified,\n"
+ " then the source node must correspond to a suite.\n"
+ "- If the source node is added as a child, then its name must be unique\n"
+ " amongst its peers\n"
+ "Usage:\n"
+ " --plug=/suite macX:3141 # move the suite to ecFlow server on host(macX) and port(3141)"
+ ;
+}
+
+void PlugCmd::addOption(boost::program_options::options_description& desc) const {
+ desc.add_options()( PlugCmd::arg(),po::value< vector<string> >()->multitoken(), PlugCmd::desc() );
+}
+
+void PlugCmd::create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* ace) const
+{
+ vector<string> args = vm[ arg() ].as< vector<string> >();
+
+ if (ace->debug()) dumpVecArgs(PlugCmd::arg(),args);
+
+ if (args.size() != 2 ) {
+ std::stringstream ss;
+ ss << "PlugCmd: Two arguments are expected, found " << args.size() << "\n" << PlugCmd::desc() << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+
+ std::string sourceNode = args[0];
+ std::string destNode = args[1];
+
+ cmd = Cmd_ptr( new PlugCmd(sourceNode, destNode) );
+}
+
+// ===================================================================================
+
+MoveCmd::MoveCmd(const std::pair<std::string,std::string>& host_port, Node* src, const std::string& dest)
+ : sourceSuite_(src->isSuite()),
+ sourceFamily_(src->isFamily()),
+ sourceTask_(src->isTask()),
+ src_host_(host_port.first),
+ src_port_(host_port.second),
+ src_path_(src->absNodePath()),
+ dest_(dest) {}
+
+MoveCmd::MoveCmd()
+: sourceSuite_(NULL),
+ sourceFamily_(NULL),
+ sourceTask_(NULL) {}
+
+MoveCmd::~MoveCmd(){}
+
+bool MoveCmd::equals(ClientToServerCmd* rhs) const
+{
+ MoveCmd* the_rhs = dynamic_cast<MoveCmd*>(rhs);
+ if (!the_rhs) return false;
+ if (dest_ != the_rhs->dest()) { return false; }
+
+ Node* theSource = source();
+ if (theSource == NULL && the_rhs->source()) { return false; }
+ if (theSource && the_rhs->source() == NULL) { return false; }
+ if (theSource == NULL && the_rhs->source() == NULL) { return true; }
+ if (theSource->absNodePath() != the_rhs->source()->absNodePath()) { return false; }
+ return UserCmd::equals(rhs);
+}
+
+std::ostream& MoveCmd::print(std::ostream& os) const
+{
+ std::stringstream ss;
+ ss << "Plug(Move) source(" << src_host_ << ":" << src_port_ << ":" << src_path_ << ") destination(" << dest_ << ")";
+ return user_cmd(os,ss.str());
+}
+
+Node* MoveCmd::source() const
+{
+ if ( sourceSuite_ ) return sourceSuite_ ;
+ if ( sourceFamily_ ) return sourceFamily_;
+ if ( sourceTask_ ) return sourceTask_;
+ return NULL;
+}
+
+bool MoveCmd::check_source() const
+{
+ if ( sourceSuite_ || sourceFamily_ || sourceTask_ ) return true ;
+ return false;
+}
+
+STC_Cmd_ptr MoveCmd::doHandleRequest(AbstractServer* as) const
+{
+ Lock lock(user(),as);
+ if (!lock.ok()) {
+ std::string errorMsg = "Plug(Move) command failed. User "; errorMsg += as->lockedUser();
+ errorMsg += " already has an exclusive lock";
+ throw std::runtime_error( errorMsg);
+ }
+
+ if (!check_source()) {
+ throw std::runtime_error("Plug(Move) command failed. No source specified");
+ }
+
+ // destNode can be NULL when we are moving a suite
+ node_ptr destNode;
+ if (!dest_.empty()) {
+
+ if (!as->defs()) throw std::runtime_error( "No definition in server");
+
+ destNode = as->defs()->findAbsNode(dest_);
+ if (!destNode.get()) {
+ std::string errorMsg = "Plug(Move) command failed. The destination path "; errorMsg += dest_;
+ errorMsg += " does not exist on server";
+ throw std::runtime_error( errorMsg);
+ }
+ }
+ else {
+ if (!source()->isSuite()) {
+ throw std::runtime_error("::Destination path can only be empty when moving a whole suite to a new server");
+ }
+ }
+
+ if (destNode.get()) {
+
+ // The destNode containing suite may be in a handle
+ SuiteChanged0 suiteChanged(destNode);
+
+ // If the destination is task, replace with its parent
+ Node* thedestNode = destNode.get();
+ if (thedestNode->isTask()) thedestNode = thedestNode->parent();
+
+ // check its ok to add
+ std::string errorMsg;
+ if (!thedestNode->isAddChildOk(source(),errorMsg) ) {
+ std::string msg = "Plug(Move) command failed. "; msg += errorMsg;
+ throw std::runtime_error( msg) ;
+ }
+
+ // pass ownership
+ if (!thedestNode->addChild( node_ptr( source() ) )) {
+ // This should never fail !!!! else we have lost/ and leaked source node !!!!
+ throw std::runtime_error("Fatal error plug(move) command failed.") ;
+ }
+
+ add_node_for_edit_history(destNode);
+ }
+ else {
+
+ if (!sourceSuite_) throw std::runtime_error("Source node was expected to be a suite");
+
+ suite_ptr the_source_suite(sourceSuite_); // pass ownership to suite_ptr
+
+ // The sourceSuite may be in a handle or pre-registered suite
+ SuiteChanged suiteChanged(the_source_suite);
+
+ if (!as->defs()) {
+ defs_ptr newDefs = Defs::create();
+ newDefs->addSuite( the_source_suite );
+ as->updateDefs( newDefs, true /*force*/ ); // force is mute, since we adding a new defs in the server
+ }
+ else {
+
+ if (as->defs()->findSuite(the_source_suite->name())) {
+ std::stringstream ss; ss << "Suite of name " << the_source_suite->name() << " already exists\n";
+ throw std::runtime_error( ss.str() );
+ }
+
+ as->defs()->addSuite( the_source_suite ) ;
+ }
+
+ /// A bit of hack, since need a way of getting a node_ptr from a Node*
+ add_node_for_edit_history(as,the_source_suite->absNodePath());
+ }
+
+ // Updated defs state
+ if (as->defs()) as->defs()->set_most_significant_state();
+
+ // Ownership for sourceSuite_ has been passed on.
+ sourceSuite_ = NULL;
+ sourceFamily_ = NULL;
+ sourceTask_ = NULL;
+
+ return PreAllocatedReply::ok_cmd();
+}
+
+const char* MoveCmd::arg() { return "move";}
+const char* MoveCmd::desc() { return "The move command is an internal cmd, Called by the plug cmd. Does not appear on public api.";}
+
+void MoveCmd::addOption(boost::program_options::options_description& desc) const {
+ desc.add_options()( MoveCmd::arg(),po::value< vector<string> >()->multitoken(), MoveCmd::desc() );
+}
+
+void MoveCmd::create(Cmd_ptr&, boost::program_options::variables_map&, AbstractClientEnv* ) const
+{
+ assert(false);
+}
+
+std::ostream& operator<<(std::ostream& os, const PlugCmd& c) { return c.print(os); }
+std::ostream& operator<<(std::ostream& os, const MoveCmd& c) { return c.print(os); }
diff --git a/Base/src/cts/ReplaceNodeCmd.cpp b/Base/src/cts/ReplaceNodeCmd.cpp
new file mode 100644
index 0000000..dcfb6d4
--- /dev/null
+++ b/Base/src/cts/ReplaceNodeCmd.cpp
@@ -0,0 +1,203 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #37 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <boost/make_shared.hpp>
+
+#include "ClientToServerCmd.hpp"
+#include "AbstractServer.hpp"
+#include "AbstractClientEnv.hpp"
+#include "CtsApi.hpp"
+#include "Defs.hpp"
+#include "DefsStructureParser.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+namespace po = boost::program_options;
+
+ReplaceNodeCmd::ReplaceNodeCmd(const std::string& node_path, bool createNodesAsNeeded, defs_ptr defs, bool force )
+: createNodesAsNeeded_(createNodesAsNeeded), force_(force), pathToNode_(node_path), clientDefs_(defs)
+{
+ if (!clientDefs_.get()) {
+ throw std::runtime_error( "ReplaceNodeCmd::ReplaceNodeCmd: client definition is empty" );
+ }
+
+ // Client defs has been created in memory.
+ // warn about naff expression and unresolved in-limit references to Limit's
+ std::string errMsg, warningMsg;
+ if (!clientDefs_->check(errMsg, warningMsg)) {
+ throw std::runtime_error(errMsg);
+ }
+
+ // Make sure pathToNode exists in the client defs
+ node_ptr nodeToReplace = clientDefs_->findAbsNode( node_path );
+ if (! nodeToReplace.get() ) {
+ std::stringstream ss;
+ ss << "ReplaceNodeCmd::ReplaceNodeCmd: Can not replace child since path " << node_path;
+ ss << " does not exist in the client definition ";
+ throw std::runtime_error( ss.str() );
+ }
+
+ // Out put any warning's to standard output
+ cout << warningMsg;
+}
+
+ReplaceNodeCmd::ReplaceNodeCmd(const std::string& node_path, bool createNodesAsNeeded, const std::string& path_to_defs, bool force )
+: createNodesAsNeeded_(createNodesAsNeeded),
+ force_(force),
+ pathToNode_(node_path),
+ path_to_defs_(path_to_defs),
+ clientDefs_(Defs::create())
+{
+ // Parse the file and load the defs file into memory.
+ DefsStructureParser checkPtParser( clientDefs_.get(), path_to_defs );
+ std::string errMsg, warningMsg;
+ if ( ! checkPtParser.doParse( errMsg , warningMsg) ) {
+ std::stringstream ss;
+ ss << "ReplaceNodeCmd::ReplaceNodeCmd: Could not parse file " << path_to_defs << " : " << errMsg;
+ throw std::runtime_error( ss.str() );
+ }
+
+ // Make sure pathToNode exists in the client defs
+ node_ptr nodeToReplace = clientDefs_->findAbsNode( node_path );
+ if (! nodeToReplace.get() ) {
+ std::stringstream ss;
+ ss << "ReplaceNodeCmd::ReplaceNodeCmd: Can not replace child since path " << node_path;
+ ss << ", does not exist in the client definition " << path_to_defs;
+ throw std::runtime_error( ss.str() );
+ }
+
+ // Out put any warning's to standard output
+ cout << warningMsg;
+}
+
+bool ReplaceNodeCmd::equals(ClientToServerCmd* rhs) const
+{
+ ReplaceNodeCmd* the_rhs = dynamic_cast<ReplaceNodeCmd*>(rhs);
+ if (!the_rhs) return false;
+
+ if (!UserCmd::equals(rhs)) return false;
+
+ if (createNodesAsNeeded_ != the_rhs->createNodesAsNeeded()) { return false; }
+ if (force_ != the_rhs->force()) return false;
+ if (pathToNode_ != the_rhs->pathToNode()) return false;
+ if (path_to_defs_ != the_rhs->path_to_defs()) return false;
+
+ if (clientDefs_ == NULL && the_rhs->theDefs() == NULL) return true;
+ if (clientDefs_ == NULL && the_rhs->theDefs() != NULL) return false;
+ if (clientDefs_ != NULL && the_rhs->theDefs() == NULL) return false;
+
+ return (*clientDefs_ == *(the_rhs->theDefs()));
+}
+
+STC_Cmd_ptr ReplaceNodeCmd::doHandleRequest(AbstractServer* as) const
+{
+ as->update_stats().replace_++;
+
+ assert(isWrite()); // isWrite used in handleRequest() to control check pointing
+ if (clientDefs_) {
+
+ if (as->defs().get() == clientDefs_.get()) {
+ /// Typically will only happen with test environment
+ throw std::runtime_error("ReplaceNodeCmd::doHandleRequest: The definition in the server is the same as the client provided definition??");
+ }
+
+ if (force_) {
+ as->zombie_ctrl().add_user_zombies( as->defs()->findAbsNode( pathToNode_ ) );
+ }
+
+ std::string errorMsg;
+ if (!as->defs()->replaceChild(pathToNode_, clientDefs_, createNodesAsNeeded_, force_, errorMsg)) {
+ throw std::runtime_error(errorMsg);
+ }
+
+ add_node_for_edit_history(as,pathToNode_);
+ }
+ return doJobSubmission( as );
+}
+
+std::ostream& ReplaceNodeCmd::print(std::ostream& os) const
+{
+ std::string path_to_client_defs = path_to_defs_;
+ if (path_to_client_defs.empty()) path_to_client_defs = "<empty>"; // defs must have bee loaded in memory via python api
+ return user_cmd(os,CtsApi::to_string(CtsApi::replace(pathToNode_,path_to_client_defs,createNodesAsNeeded_,force_)));
+}
+
+const char* ReplaceNodeCmd::arg() { return CtsApi::replace_arg();}
+const char* ReplaceNodeCmd::desc() {
+ /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+ return
+ "Replaces a node in the server, with the given path\n"
+ "Can also be used to add nodes in the server\n"
+ " arg1 = path to node\n"
+ " must exist in the client defs(arg2). This is also the node we want to\n"
+ " replace in the server\n"
+ " arg2 = path to client definition file\n"
+ " provides the definition of the new node\n"
+ " arg3 = (optional) [ parent | false ] (default = parent)\n"
+ " create parent families or suite as needed, when arg1 does not\n"
+ " exist in the server\n"
+ " arg4 = (optional) force (default = false) \n"
+ " Force the replacement even if it causes zombies to be created\n"
+ "Replace can fail if:\n"
+ "- The node path(arg1) does not exist in the provided client definition(arg2)\n"
+ "- The client definition(arg2) must be free of errors\n"
+ "- If the third argument is not provided, then node path(arg1) must exist in the server\n"
+ "- Nodes to be replaced are in active/submitted state, in which case arg4(force) can be used\n\n"
+ "After replace is done, we check trigger expressions. These are reported to standard output.\n"
+ "It is up to the user to correct invalid trigger expressions, otherwise the tasks will *not* run.\n"
+ "Please note, you can use --check to check trigger expression and limits in the server.\n"
+ "For more information use --help check.\n\n"
+ "Usage:\n"
+ " --replace=/suite/f1/t1 /tmp/client.def parent # Add/replace node tree /suite/f1/t1\n"
+ " --replace=/suite/f1/t1 /tmp/client.def false force # replace t1 even if its active or submitted";
+}
+
+void ReplaceNodeCmd::addOption(boost::program_options::options_description& desc) const {
+ desc.add_options()( ReplaceNodeCmd::arg(),po::value< vector<string> >()->multitoken(), ReplaceNodeCmd::desc() );
+}
+void ReplaceNodeCmd::create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const
+{
+ vector<string> args = vm[ arg() ].as< vector<string> >();
+
+ if (clientEnv->debug()) dumpVecArgs(ReplaceNodeCmd::arg(),args);
+
+ if (args.size() < 2 ) {
+ std::stringstream ss;
+ ss << "ReplaceNodeCmd: At least two arguments expected, found " << args.size()
+ << " Please specify <path-to-Node> <defs files> parent(optional) force(optional), i.e\n"
+ << "--" << arg() << "=/suite/fa/t AdefsFile.def parent force\n";
+ throw std::runtime_error( ss.str() );
+ }
+
+ std::string pathToNode = args[0];
+ std::string pathToDefsFile = args[1];
+ bool createNodesAsNeeded = true; // parent arg
+ bool force = false;
+ if ( args.size() == 3 && args[2] == "false") createNodesAsNeeded = false;
+ if ( args.size() == 4 && args[3] == "force") force = true;
+
+ /// If path to file does not parse, we will throw an exception
+ ReplaceNodeCmd* replace_cmd = new ReplaceNodeCmd(pathToNode,createNodesAsNeeded, pathToDefsFile , force);
+
+ // For test allow the defs environment to changed, i.e. allow us to inject ECF_CLIENT
+ replace_cmd->theDefs()->set_server().add_or_update_user_variables( clientEnv->env() );
+
+ cmd = Cmd_ptr( replace_cmd );
+}
+
+std::ostream& operator<<(std::ostream& os, const ReplaceNodeCmd& c) { return c.print(os); }
diff --git a/Base/src/cts/RequeueNodeCmd.cpp b/Base/src/cts/RequeueNodeCmd.cpp
new file mode 100644
index 0000000..ffb12bd
--- /dev/null
+++ b/Base/src/cts/RequeueNodeCmd.cpp
@@ -0,0 +1,236 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #32 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include "ClientToServerCmd.hpp"
+#include "AbstractServer.hpp"
+#include "AbstractClientEnv.hpp"
+#include "CtsApi.hpp"
+#include "Defs.hpp"
+#include "Task.hpp"
+#include "SuiteChanged.hpp"
+#include "Log.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+namespace po = boost::program_options;
+
+
+bool RequeueNodeCmd::equals(ClientToServerCmd* rhs) const
+{
+ RequeueNodeCmd* the_rhs = dynamic_cast< RequeueNodeCmd* > ( rhs );
+ if ( !the_rhs ) return false;
+ if (paths_ != the_rhs->paths()) return false;
+ if (option_ != the_rhs->option()) return false;
+ return UserCmd::equals(rhs);
+}
+
+static std::string to_string(RequeueNodeCmd::Option option) {
+ switch (option) {
+ case RequeueNodeCmd::NO_OPTION: return string();
+ case RequeueNodeCmd::FORCE: return "force";
+ case RequeueNodeCmd::ABORT: return "abort";
+ default: assert(false); break;
+ }
+ return string();
+}
+
+std::ostream& RequeueNodeCmd::print(std::ostream& os) const
+{
+ return user_cmd(os,CtsApi::to_string(CtsApi::requeue(paths_,to_string(option_))));
+}
+
+std::ostream& RequeueNodeCmd::print(std::ostream& os, const std::string& path) const
+{
+ std::vector<std::string> paths(1,path);
+ return user_cmd(os,CtsApi::to_string(CtsApi::requeue(paths,to_string(option_))));
+}
+
+STC_Cmd_ptr RequeueNodeCmd::doHandleRequest(AbstractServer* as) const
+{
+ as->update_stats().requeue_node_++;
+ assert(isWrite()); // isWrite used in handleRequest() to control check pointing
+
+ // This is *only* incremented for child nodes. Hence we only clear suspended for child nodes.
+ int clear_suspended_in_child_nodes = 0;
+
+ std::stringstream ss;
+ size_t vec_size = paths_.size();
+ for(size_t i = 0; i < vec_size; i++) {
+
+ node_ptr theNodeToRequeue = find_node_for_edit_no_throw(as,paths_[i]);
+ if (!theNodeToRequeue.get()) {
+ ss << "RequeueNodeCmd: Could not find node at path " << paths_[i] << "\n";
+ LOG(Log::ERR,"RequeueNodeCmd: Could not find node at path " << paths_[i]);
+ continue;
+ }
+
+ if (!theNodeToRequeue->suite()->begun()) {
+ std::stringstream ss;
+ ss << "RequeueNodeCmd::doHandleRequest: For node " << paths_[i] << ". The suite " << theNodeToRequeue->suite()->name() << " must be 'begun' first\n";
+ throw std::runtime_error( ss.str() ) ;
+ }
+
+ SuiteChanged0 changed(theNodeToRequeue);
+
+ if (option_ == RequeueNodeCmd::ABORT) {
+ // ONLY Re-queue the aborted tasks
+ std::vector<Task*> taskVec;
+ theNodeToRequeue->getAllTasks(taskVec);
+ for(size_t i=0; i < taskVec.size(); i++) {
+ if (taskVec[i]->state() == NState::ABORTED) {
+ taskVec[i]->requeue( true /* reset repeats */,
+ clear_suspended_in_child_nodes,
+ true /* reset_next_time_slot */);
+ taskVec[i]->set_most_significant_state_up_node_tree(); // Must in loop and not outside ECFLOW-428
+ }
+ }
+
+ // Call handleStateChange on parent, to avoid requeue same node again.
+ Node* parent = theNodeToRequeue->parent();
+ if (parent) parent->handleStateChange(); // ECFLOW-359
+ }
+ else if ( option_ == RequeueNodeCmd::NO_OPTION) {
+ // ONLY Re-queue if there no tasks in submitted or active states
+ std::vector<Task*> taskVec;
+ theNodeToRequeue->getAllTasks(taskVec);
+ for(size_t i=0; i < taskVec.size(); i++) {
+ if (taskVec[i]->state() == NState::SUBMITTED || taskVec[i]->state() == NState::ACTIVE) {
+ return PreAllocatedReply::ok_cmd();
+ }
+ }
+
+ // The NO_REQUE_IF_SINGLE_TIME_DEP is typically cleared at the *end* requeue, however there are cases
+ // where we need to reset it *BEFORE* re-queue. Since it is tied to missing the next time slot
+ // i.e take this case:
+ // time 10:00 15:00 00:30
+ // If we force complete, we set NO_REQUE_IF_SINGLE_TIME_DEP, which is used to advance next valid time slot
+ // (i.e no reset), however when we reach the *end* time i.e 15:00
+ // calling force complete now leaves node in a complete state and with NO_REQUE_IF_SINGLE_TIME_DEP set.
+ // Therefore *any* *MANUAL* re-queue afterward will NOT reset the next valid time slot.
+ // To overcome this manual re-queue will always clear NO_REQUE_IF_SINGLE_TIME_DEP and hence reset next valid time slot
+ theNodeToRequeue->requeue( true /* reset repeats */,
+ clear_suspended_in_child_nodes,
+ true /* reset_next_time_slot */ );
+
+
+ theNodeToRequeue->set_most_significant_state_up_node_tree();
+
+ // Call handleStateChange on parent, to avoid requeue same node again.
+ Node* parent = theNodeToRequeue->parent();
+ if (parent) parent->handleStateChange(); // ECFLOW-359
+ }
+ else if ( option_ == RequeueNodeCmd::FORCE) {
+
+ as->zombie_ctrl().add_user_zombies(theNodeToRequeue);
+
+ // Please note: that if any tasks under theNodeToRequeue are in
+ // active or submitted states, then we will have created zombie jobs
+ // The GUI: that calls this command should call a separate request
+ // the returns the active/submitted tasks first. This can then be
+ // presented to the user, who can elect to kill them if required.
+ theNodeToRequeue->requeue( true /* reset repeats */,
+ clear_suspended_in_child_nodes,
+ true /* reset_next_time_slot */ );
+
+ theNodeToRequeue->set_most_significant_state_up_node_tree();
+
+ // Call handleStateChange on parent, to avoid requeue same node again.
+ Node* parent = theNodeToRequeue->parent();
+ if (parent) parent->handleStateChange(); // ECFLOW-359
+ }
+ }
+
+ std::string error_msg = ss.str();
+ if (!error_msg.empty()) {
+ throw std::runtime_error( error_msg ) ;
+ }
+
+ // Do an immediate job submission, so that any re-queued tasks are submitted
+ return doJobSubmission(as);
+}
+
+const char* RequeueNodeCmd::arg() { return CtsApi::requeueArg();}
+const char* RequeueNodeCmd::desc() {
+ return
+ "Re queues the specified node(s)\n"
+ " If any child of the specified node(s) is in a suspended state, this state is cleared\n"
+ " arg1 = (optional) [ abort | force ]\n"
+ " abort = re-queue only aborted tasks below node\n"
+ " force = Force the re-queueing even if there are nodes that are active or submitted\n"
+ " <null> = Checks if any tasks are in submitted or active states below the node\n"
+ " if so does nothing. Otherwise re-queues the node.\n"
+ " arg2 = list of node paths. The node paths must begin with a leading '/' character\n\n"
+ "Usage:\n"
+ " --requeue=abort /suite/f1 # re-queue all aborted children of /suite/f1\n"
+ " --requeue=force /suite/f1 # forcibly re-queue /suite/f1 and all its children.May cause zombies.\n"
+ " --requeue=/s1/f1/t1 /s1/t2 # Re-queue node '/suite/f1/t1' and '/s1/t2'"
+ ;
+}
+
+void RequeueNodeCmd::addOption(boost::program_options::options_description& desc) const{
+ desc.add_options()( RequeueNodeCmd::arg(), po::value< vector<string> >()->multitoken(), RequeueNodeCmd::desc() );
+}
+void RequeueNodeCmd::create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* ac) const
+{
+ vector<string> args = vm[ RequeueNodeCmd::arg() ].as< vector<string> >();
+
+ if (ac->debug()) dumpVecArgs(RequeueNodeCmd::arg(),args);
+
+ if (args.size() < 1 ) {
+ std::stringstream ss;
+ ss << "RequeueNodeCmd: At least 1 argument(path to node) expected. Please specify one of:\n";
+ ss << RequeueNodeCmd::arg() << " pathToNode\n";
+ ss << RequeueNodeCmd::arg() << " abort pathToNode\n";
+ ss << RequeueNodeCmd::arg() << " force pathToNode\n";
+ throw std::runtime_error( ss.str() );
+ }
+
+ std::vector<std::string> options,paths;
+ split_args_to_options_and_paths(args,options,paths); // relative order is still preserved
+ if (paths.empty()) {
+ std::stringstream ss;
+ ss << "RequeueNodeCmd: No paths specified. At least one path expected. Paths must begin with a leading '/' character\n" << RequeueNodeCmd::desc() << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+
+ RequeueNodeCmd::Option option = RequeueNodeCmd::NO_OPTION;
+ size_t vec_size = options.size();
+ for(size_t i = 0; i < vec_size; i++) {
+ if (options[i] == "abort") {
+ option = RequeueNodeCmd::ABORT;
+ if (ac->debug()) cout << " ABORT selected\n";
+ }
+ else if (options[i] == "force") {
+ option = RequeueNodeCmd::FORCE;
+ if (ac->debug()) cout << " FORCE selected\n";
+ }
+ else {
+ std::stringstream ss;
+ ss << "RequeueNodeCmd: RequeueNodeCmd: Expected : [force | abort ] paths.\n" << RequeueNodeCmd::desc() << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ }
+ if (options.size() > 1) {
+ std::stringstream ss;
+ ss << "RequeueNodeCmd: Expected only a single option i.e [ force | abort ]\n" << RequeueNodeCmd::desc() << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+
+ cmd = Cmd_ptr(new RequeueNodeCmd(paths,option));
+}
+
+std::ostream& operator<<(std::ostream& os, const RequeueNodeCmd& c) { return c.print(os); }
diff --git a/Base/src/cts/RunNodeCmd.cpp b/Base/src/cts/RunNodeCmd.cpp
new file mode 100644
index 0000000..ea8412d
--- /dev/null
+++ b/Base/src/cts/RunNodeCmd.cpp
@@ -0,0 +1,173 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #34 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include "ClientToServerCmd.hpp"
+#include "AbstractServer.hpp"
+#include "AbstractClientEnv.hpp"
+#include "Str.hpp"
+#include "CtsApi.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "JobsParam.hpp"
+#include "SuiteChanged.hpp"
+#include "Log.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+namespace po = boost::program_options;
+
+bool RunNodeCmd::equals(ClientToServerCmd* rhs) const
+{
+ RunNodeCmd* the_rhs = dynamic_cast< RunNodeCmd* > ( rhs );
+ if ( !the_rhs ) return false;
+ if (paths_ != the_rhs->paths()) return false;
+ if (force_ != the_rhs->force()) return false;
+ return UserCmd::equals(rhs);
+}
+
+std::ostream& RunNodeCmd::print(std::ostream& os) const
+{
+ return user_cmd(os,CtsApi::to_string(CtsApi::run(paths_,force_)));
+}
+
+std::ostream& RunNodeCmd::print(std::ostream& os, const std::string& path) const
+{
+ std::vector<std::string> paths(1,path);
+ return user_cmd(os,CtsApi::to_string(CtsApi::run(paths,force_)));
+}
+
+
+STC_Cmd_ptr RunNodeCmd::doHandleRequest(AbstractServer* as) const
+{
+ as->update_stats().run_node_++;
+
+ assert(isWrite()); // isWrite used in handleRequest() to control check pointing
+
+ std::stringstream ss;
+ size_t vec_size = paths_.size();
+ for(size_t i = 0; i < vec_size; i++) {
+ node_ptr node = find_node_for_edit_no_throw(as,paths_[i]);
+ if (!node.get()) {
+ ss << "RunNodeCmd: Could not find node at path " << paths_[i] << "\n";
+ LOG(Log::ERR,"RunNodeCmd: Could not find node at path " << paths_[i]);
+ continue;
+ }
+
+ if (!node->suite()->begun()) {
+ std::stringstream ss;
+ ss << "RunNodeCmd failed: For " << paths_[i] << ". The suite " << node->suite()->name() << " must be 'begun' first\n";
+ throw std::runtime_error( ss.str() ) ;
+ }
+
+ SuiteChanged0 changed(node);
+
+ // Please note: that if any tasks under theNode are in
+ // active or submitted states, then we will have created zombies jobs
+ // The GUI: that calls this command should call a separate request
+ // the returns the active/submitted tasks first. This can then be
+ // presented to the user, who can elect to kill them if required.
+ bool createJobs = true;
+ if (test_) createJobs = false;
+
+ /// This will *NOT* timeout, unlike server Job generation
+ JobsParam jobsParam(as->poll_interval(), createJobs ); // default here is to spawn jobs , spawn jobs = true
+ // At the task level, if create jobs is false, we will not spawn jobs
+#ifdef DEBUG_JOB_SUBMISSION
+ jobsParam.logDebugMessage(" from RunNodeCmd::doHandleRequest");
+#endif
+
+ if (force_) as->zombie_ctrl().add_user_zombies(node);
+
+ // Avoid re-running the task again on the same time slot
+ node->miss_next_time_slot();
+
+ if (!node->run(jobsParam, force_)) {
+ LOG(Log::ERR,"RunNodeCmd: Failed for " << paths_[i] << " : " << jobsParam.getErrorMsg());
+ }
+ }
+
+ std::string error_msg = ss.str();
+ if (!error_msg.empty()) {
+ throw std::runtime_error( error_msg ) ;
+ }
+
+ return PreAllocatedReply::ok_cmd();
+}
+
+const char* RunNodeCmd::arg() { return CtsApi::runArg();}
+const char* RunNodeCmd::desc() {
+ return "Ignore triggers, limits, time or date dependencies, just run the Task.\n"
+ "When a job completes, it may be automatically re-queued if it has a cron\n"
+ "or multiple time dependencies. If we have multiple time based attributes,\n"
+ "then each run, will expire the time.\n"
+ "When we run before the time, we want to avoid re-running the task then\n"
+ "a flag is set, so that it is not automatically re-queued.\n"
+ "A repeat attribute is incremented when all the child nodes are complete\n"
+ "in this case the child nodes are automatically re-queued.\n"
+ "Hence this command can be aid, in allowing a Repeat attribute to be incremented\n"
+ " arg1 = (optional)force\n"
+ " Forcibly run, even if there are nodes that are active or submitted\n"
+ " This can result in zombie creation\n"
+ " arg2 = node path(s). The paths must begin with a leading '/' character.\n"
+ " If the path is /suite/family will recursively run all tasks\n"
+ " When providing multiple paths avoid running the same task twice\n"
+ "Example:\n"
+ " --run=/suite/t1 # run task t1\n"
+ "Effect:\n"
+ " task t1; time 12:00 # will complete if run manually\n"
+ " task t2; time 10:00 13:00 01:00 # will run 4 times before completing\n"
+ " When we have a time range(i.e as shown with task t2), then next time slot\n"
+ " is incremented for each run, until it expires, and the task completes.\n"
+ " Use the Why command, to show next run time (i.e. next time slot)"
+ ;
+}
+
+void RunNodeCmd::addOption(boost::program_options::options_description& desc) const{
+ desc.add_options()( RunNodeCmd::arg(), po::value< vector<string> >()->multitoken(), RunNodeCmd::desc() );
+}
+void RunNodeCmd::create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* ace) const
+{
+ vector<string> args = vm[ RunNodeCmd::arg() ].as< vector<string> >();
+
+ if (ace->debug()) dumpVecArgs(RunNodeCmd::arg(),args);
+
+ std::vector<std::string> options,paths;
+ split_args_to_options_and_paths(args,options,paths); // relative order is still preserved
+ if (paths.empty()) {
+ std::stringstream ss;
+ ss << "RunNodeCmd: No paths specified. Paths must begin with a leading '/' character\n" << RunNodeCmd::desc() << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+
+ bool force = false;
+ if (!options.empty()) {
+ if (options.size() != 1) {
+ std::stringstream ss;
+ ss << "RunNodeCmd: Invalid arguments. Expected a single optional 'force'\n" << RunNodeCmd::desc() << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ if (options[0].find("force") != std::string::npos) force = true;
+ else {
+ std::stringstream ss;
+ ss << "RunNodeCmd: Expected force <path(s)>\n" << RunNodeCmd::desc() << "\n";
+ throw std::runtime_error( ss.str() );
+ }
+ }
+ cmd = Cmd_ptr(new RunNodeCmd(paths,force));
+}
+
+std::ostream& operator<<(std::ostream& os, const RunNodeCmd& c) { return c.print(os); }
diff --git a/Base/src/cts/ServerVersionCmd.cpp b/Base/src/cts/ServerVersionCmd.cpp
new file mode 100644
index 0000000..c2e7ba0
--- /dev/null
+++ b/Base/src/cts/ServerVersionCmd.cpp
@@ -0,0 +1,80 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #8 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : returns the server version.
+// This command should not be changed
+// It will allow new clients to ask OLD server their version numbers
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "ClientToServerCmd.hpp"
+#include "AbstractServer.hpp"
+#include "AbstractClientEnv.hpp"
+#include "CtsApi.hpp"
+#include "Version.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+namespace po = boost::program_options;
+
+std::ostream& ServerVersionCmd::print(std::ostream& os) const
+{
+ return user_cmd(os,CtsApi::server_version());
+}
+
+bool ServerVersionCmd::equals(ClientToServerCmd* rhs) const
+{
+ ServerVersionCmd* the_rhs = dynamic_cast< ServerVersionCmd* > ( rhs );
+ if ( !the_rhs ) return false;
+ return UserCmd::equals(rhs);
+}
+
+const char* ServerVersionCmd::theArg() const
+{
+ return CtsApi::server_version_arg();
+}
+
+STC_Cmd_ptr ServerVersionCmd::doHandleRequest(AbstractServer* as) const
+{
+ as->update_stats().server_version_++;
+ return PreAllocatedReply::string_cmd(Version::raw());
+}
+
+static const char* arg_desc()
+{
+ /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+ return
+ "Returns the version number of the server\n"
+ "Usage:\n"
+ " --server_version\n"
+ " Writes the version to standard output\n"
+ ;
+}
+
+void ServerVersionCmd::addOption(boost::program_options::options_description& desc) const
+{
+ desc.add_options()(CtsApi::server_version_arg(),arg_desc());
+}
+
+void ServerVersionCmd::create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* ace ) const
+{
+ if (ace->debug()) cout << " ServerVersionCmd::create\n";
+
+ // testing client interface
+ if (ace->under_test()) return;
+
+ cmd = Cmd_ptr(new ServerVersionCmd());
+}
+
+std::ostream& operator<<(std::ostream& os, const ServerVersionCmd& c) { return c.print(os); }
diff --git a/Base/src/cts/ShowCmd.cpp b/Base/src/cts/ShowCmd.cpp
new file mode 100644
index 0000000..398a245
--- /dev/null
+++ b/Base/src/cts/ShowCmd.cpp
@@ -0,0 +1,104 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #20 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <iostream>
+#include "ClientToServerCmd.hpp"
+#include "AbstractServer.hpp"
+#include "Str.hpp"
+#include "CtsApi.hpp"
+#include "AbstractClientEnv.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+namespace po = boost::program_options;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool ShowCmd::equals(ClientToServerCmd* rhs) const
+{
+ return (dynamic_cast<ShowCmd*>(rhs)) ? UserCmd::equals(rhs) : false;
+}
+
+std::ostream& ShowCmd::print(std::ostream& os) const
+{
+ return user_cmd(os,"show");
+}
+
+STC_Cmd_ptr ShowCmd::doHandleRequest(AbstractServer* as) const
+{
+ /// Should never get called since, show command is only called on client side.
+ return PreAllocatedReply::ok_cmd();
+}
+
+const char* ShowCmd::arg() { return "show";}
+const char* ShowCmd::desc() {
+ return "Used to print state of the definition returned from the server to standard output.\n"
+ "This command can *only* be used in a group command, and will only work if it is\n"
+ "preceded with a get command. See examples below.\n"
+ " arg1 = [ defs | state | migrate ] \n"
+ "The output of show has several options: i.e\n"
+ " o no arguments: With no arguments, print the definition structure to standard output\n"
+ " Extern's are automatically added, allowing the output to be reloaded into the server\n"
+ " i.e --group=\"get ; show\"\n"
+ " o state:\n"
+ " This will output definition structure along with all the state information.\n"
+ " This will include the trigger expressions, abstract syntax tree as comments.\n"
+ " Excludes the edit history\n"
+ " o migrate:\n"
+ " This will output definition structure along with all the state information.\n"
+ " The node state is shown in the comments.\n"
+ " This format allows the definition to be migrated to future version of ecflow.\n"
+ " The output includes edit history but excludes externs.\n"
+ " When the definition is reloaded *NO* checking is done.\n"
+ "\n"
+ "The following shows a summary of the features associated with each choice\n"
+ " DEFS STATE MIGRATE\n"
+ "Auto generate externs Yes Yes No\n"
+ "Checking on reload Yes Yes No\n"
+ "Edit History No No Yes\n"
+ "trigger AST No Yes No\n"
+ "\n"
+ "Usage:\n"
+ " --group=\"get ; show\"\n"
+ " --group=\"get ; show defs\" # same as the previous example\n"
+ " --group=\"get ; show state\" # Show all state for the node tree\n"
+ " --group=\"get ; show migrate\" # Shows state and allows migration\n"
+ " --group=\"get=/s1; show\" # show state for the node only\n"
+ " --group=\"get=/s1; show state\""
+ ;
+}
+
+void ShowCmd::addOption(boost::program_options::options_description& desc) const {
+ desc.add_options()( ShowCmd::arg(), po::value< string >()->implicit_value(string()), ShowCmd::desc() );
+}
+void ShowCmd::create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* ac ) const
+{
+ std::string show_state = vm[ ShowCmd::arg() ].as< std::string > ();
+
+ if (ac->debug()) cout << " ShowCmd::create api = '" << show_state << "'.\n";
+
+ PrintStyle::Type_t style = PrintStyle::DEFS;
+ if (!show_state.empty()) {
+ if (show_state == "state") style = PrintStyle::STATE;
+ else if (show_state == "migrate" ) style = PrintStyle::MIGRATE;
+ else if (show_state == "defs" ) style = PrintStyle::DEFS;
+ else throw std::runtime_error("ShowCmd::create invalid show option expected one of [ defs | state | migrate ] but found " + show_state);
+ }
+ cmd = Cmd_ptr( new ShowCmd( style ) );
+}
+
+std::ostream& operator<<(std::ostream& os, const ShowCmd& c) { return c.print(os); }
diff --git a/Base/src/cts/TaskApi.cpp b/Base/src/cts/TaskApi.cpp
new file mode 100644
index 0000000..66f97cd
--- /dev/null
+++ b/Base/src/cts/TaskApi.cpp
@@ -0,0 +1,80 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <boost/algorithm/string/trim.hpp>
+#include "TaskApi.hpp"
+
+std::string TaskApi::init(const std::string& process_id)
+{
+ std::string ret = "--init=";
+ ret += process_id;
+ return ret;
+}
+const char* TaskApi::initArg() { return "init"; }
+
+
+std::string TaskApi::abort(const std::string& reason)
+{
+ if (reason.empty()) return "--abort";
+ std::string ret = "--abort=";
+ ret += reason;
+ return ret;
+}
+const char* TaskApi::abortArg() { return "abort"; }
+
+
+std::string TaskApi::event(const std::string& eventName) {
+ std::string ret = "--event=";
+ ret += eventName;
+ return ret;
+}
+const char* TaskApi::eventArg() { return "event"; }
+
+
+std::vector<std::string> TaskApi::meter(const std::string& meterName,const std::string& new_meter_value)
+{
+ std::vector<std::string> retVec; retVec.reserve(2);
+ std::string ret = "--meter=";ret += meterName;
+ retVec.push_back(ret);
+ retVec.push_back(new_meter_value);
+ return retVec;
+}
+const char* TaskApi::meterArg() { return "meter"; }
+
+
+std::vector<std::string> TaskApi::label(const std::string& label_name, const std::vector<std::string>& labels )
+{
+ std::vector<std::string> retVec; retVec.reserve(labels.size() +1);
+ std::string ret = "--label=";
+ ret += label_name;
+ retVec.push_back(ret);
+ for(size_t i = 0; i < labels.size(); i++) { retVec.push_back(labels[i]);}
+ return retVec;
+}
+const char* TaskApi::labelArg() { return "label"; }
+
+
+std::string TaskApi::complete() { return "--complete"; }
+const char* TaskApi::completeArg() { return "complete"; }
+
+
+std::string TaskApi::wait(const std::string& expression)
+{
+ std::string ret = "--wait=";
+ ret += expression;
+ return ret;
+}
+const char* TaskApi::waitArg() { return "wait"; }
+
+
diff --git a/Base/src/cts/TaskApi.hpp b/Base/src/cts/TaskApi.hpp
new file mode 100644
index 0000000..12c7503
--- /dev/null
+++ b/Base/src/cts/TaskApi.hpp
@@ -0,0 +1,43 @@
+#ifndef TASK_API_HPP_
+#define TASK_API_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Task api. i.e the child commands, typically called from the jobs files
+// The two variant api must correspond i.e '--get' and 'get'
+// since this is used by boost program options
+//============================================================================
+#include <boost/noncopyable.hpp>
+#include <string>
+#include <vector>
+
+class TaskApi : private boost::noncopyable {
+public:
+ /// Used to construct arguments, for argc,argv
+ static std::string init(const std::string& process_id);
+ static std::string abort(const std::string& reason = "");
+ static std::string event(const std::string& eventName);
+ static std::vector<std::string> meter(const std::string& meterName,const std::string& metervalue);
+ static std::vector<std::string> label(const std::string& label_name, const std::vector<std::string>& labels );
+ static std::string complete();
+ static std::string wait(const std::string& expression);
+
+ // Only to be used in Cmd
+ static const char* initArg();
+ static const char* abortArg();
+ static const char* eventArg();
+ static const char* meterArg();
+ static const char* labelArg();
+ static const char* completeArg();
+ static const char* waitArg();
+};
+#endif
diff --git a/Base/src/cts/TaskCmds.cpp b/Base/src/cts/TaskCmds.cpp
new file mode 100644
index 0000000..9e79a39
--- /dev/null
+++ b/Base/src/cts/TaskCmds.cpp
@@ -0,0 +1,923 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #91 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include "ClientToServerCmd.hpp"
+#include "AbstractServer.hpp"
+#include "AbstractClientEnv.hpp"
+#include "TaskApi.hpp"
+#include "ExprAst.hpp"
+#include "ExprAstVisitor.hpp"
+
+#include "Defs.hpp"
+#include "Task.hpp"
+#include "SuiteChanged.hpp"
+#include "Log.hpp"
+#include "Str.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+namespace po = boost::program_options;
+
+//#define DEBUG_ZOMBIE 1
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+bool TaskCmd::equals(ClientToServerCmd* rhs) const
+{
+ TaskCmd* the_rhs = dynamic_cast<TaskCmd*>(rhs);
+ if (!the_rhs) return false;
+ if (path_to_submittable_ != the_rhs->path_to_node()) return false;
+ if (jobs_password_ != the_rhs->jobs_password()) return false;
+ if (process_or_remote_id_ != the_rhs->process_or_remote_id()) return false;
+ if (try_no_ != the_rhs->try_no()) return false;
+
+ // avoid calling base equals, as task cmd's don't use User(user_) variables.
+ return true;
+}
+
+// **********************************************************************************
+// IMPORTANT: In the current SMS/ECF only the init child command, passes the
+// process_or_remote_id_, for *ALL* other child commands this is empty.
+// The Automated tests get round this via setting ECF_RID in the header/tail job includes
+// However since this may not be in .sms/.ecf files, we can not rely on it
+// Hence we need to be able to handle *EMPTY* process_or_remote_id_ for child commands
+// ************************************************************************************
+bool TaskCmd::authenticate(AbstractServer* as, STC_Cmd_ptr& theReply) const
+{
+#ifdef DEBUG_ZOMBIE
+ std::cout << " TaskCmd::authenticate " << Child::to_string(child_type());
+ std::cout << " " << path_to_submittable_ << " " << process_or_remote_id_ << " " << jobs_password_ << " " << try_no_;
+ const Zombie& zombie = as->zombie_ctrl().find(path_to_submittable_,process_or_remote_id_,jobs_password_);
+ if (!zombie.empty()) std::cout << " " << zombie;
+ else {
+ const Zombie& zombie = as->zombie_ctrl().find_by_path_only(path_to_submittable_);
+ if (!zombie.empty()) std::cout << " find_by_path_only: " << zombie;
+ }
+#endif
+ /// ***************************************************************************
+ /// Task based cmd have their own authentication mechanism, hence we
+ /// Don't need to call the base class authenticate
+ /// **************************************************************************
+
+ if (!as->allowTaskCommunication()) {
+ // This is not an Error, hence we don't throw exception
+ theReply = PreAllocatedReply::block_client_server_halted_cmd();
+ return false;
+ }
+
+ submittable_ = get_submittable(as);
+ if (!submittable_) {
+#ifdef DEBUG_ZOMBIE
+ std::cout << ": PATH Zombie\n";
+#endif
+ // Create path zombie, if not already created:
+ std::string action_taken;
+ (void)as->zombie_ctrl().handle_path_zombie(as,this,action_taken,theReply);
+
+ // distinguish output by using *path*
+ std::stringstream ss; ss << " zombie(*path*) : " << process_or_remote_id_ << " : " << jobs_password_ << " : action taken(" << action_taken << ")";
+ log(Log::ERR,ss.str());
+ return false;
+ }
+
+ // If the CMD *WAS* created with Submittable::DUMMY_JOBS_PASSWORD then we were testing
+ // This will be copied from client to server, hence we want to avoid same check in the
+ // server. when handleRequest is called()
+ // DO NOT place #ifdef DEBUG otherwise test will start failing for the release build
+ if ( jobs_password_ == Submittable::DUMMY_JOBS_PASSWORD()) {
+ return true;
+ }
+
+ SuiteChanged1 changed(submittable_->suite());
+
+ /// Check if User wants to explicitly bypass password checking
+ /// This can be done via AlterCmd by adding a variable on the task, ECF_PASS with value Submittable::FREE_JOBS_PASSWORD
+ /// Note: this *does not* look for the variable up the node tree, only on the task.
+ std::string ecf_pass_value;
+ if (submittable_->findVariableValue(Str::ECF_PASS(), ecf_pass_value)) {
+
+ if ( ecf_pass_value == Submittable::FREE_JOBS_PASSWORD()) {
+ submittable_->flag().clear(ecf::Flag::ZOMBIE);
+ return true;
+ }
+ }
+
+ /// Handle corner case ,where we have two jobs with different process id, but same password
+ /// Can happen if jobs is started externally,
+ /// or via test(i.e submit 1,submit 2(force)) before job1 active its password is overridden
+ bool submittable_allready_aborted = false;
+ bool submittable_allready_active = false;
+ bool submittable_allready_complete = false;
+ bool password_missmatch = false;
+ bool pid_missmatch = false;
+
+ if ( submittable_->jobsPassword() != jobs_password_) {
+#ifdef DEBUG_ZOMBIE
+ std::cout << ": submittable pass(" << submittable_->jobsPassword() << ") != jobs_password_(" << jobs_password_ << ")";
+#endif
+ password_missmatch = true;
+ }
+
+ /// *** See Note above: Not all child commands pass a process_id. ***
+ /// *** Hence this test for zombies is ONLY valid if process sets the process_or_remote_id_ ****
+ /// *** User should really set ECF_RID in the scripts
+ if (!submittable_->process_or_remote_id().empty() && !process_or_remote_id_.empty() && submittable_->process_or_remote_id() != process_or_remote_id_) {
+#ifdef DEBUG_ZOMBIE
+ std::cout << ":task pid(" << submittable_->process_or_remote_id() << ") != process pid(" << process_or_remote_id_ << ")";
+#endif
+ pid_missmatch = true;
+ }
+
+ if ((child_type() == Child::INIT) && (submittable_->state() == NState::ACTIVE)) {
+#ifdef DEBUG_ZOMBIE
+ std::cout << ":(child_type() == Child::INIT) && submittable_->state() == NState::ACTIVE)";
+#endif
+
+ // If ECF_NONSTRICT_ZOMBIES be more forgiving
+ if (!password_missmatch && !pid_missmatch ) {
+ if (submittable_->user_variable_exists("ECF_NONSTRICT_ZOMBIES")) {
+ std::stringstream ss; ss << " zombie(ECF_NONSTRICT_ZOMBIES) : " << path_to_submittable_ << " : already active : action taken( fob )";
+ log(Log::WAR, ss.str() );
+ theReply = PreAllocatedReply::ok_cmd();
+ return false;
+ }
+ }
+
+ submittable_allready_active = true;
+ }
+
+ if ( submittable_->state() == NState::COMPLETE) {
+#ifdef DEBUG_ZOMBIE
+ std::cout << ": submittable_->state() == NState::COMPLETE)";
+#endif
+
+ // If ECF_NONSTRICT_ZOMBIES be more forgiving
+ if (child_type() == Child::COMPLETE) {
+ if (submittable_->user_variable_exists("ECF_NONSTRICT_ZOMBIES")) {
+ std::stringstream ss; ss << " zombie(ECF_NONSTRICT_ZOMBIES) : " << path_to_submittable_ ;
+ if (password_missmatch) ss << " : password miss-match[ task:"<< submittable_->jobsPassword()<<" child:" << jobs_password_ << " ]";
+ if (pid_missmatch) ss << " : pid miss-match[ task:"<< submittable_->process_or_remote_id()<<" child:" << process_or_remote_id_ << " ]";
+ ss << " : already complete : action taken( fob )";
+ log(Log::WAR, ss.str() );
+ theReply = PreAllocatedReply::ok_cmd();
+ return false;
+ }
+ }
+
+ // If Task state is complete, and we receive **any** child command then it is a zombie
+ submittable_allready_complete = true;
+ }
+
+ if ( submittable_->state() == NState::ABORTED) {
+#ifdef DEBUG_ZOMBIE
+ std::cout << ": submittable_->state() == NState::ABORTED)";
+#endif
+
+ // If ECF_NONSTRICT_ZOMBIES be more forgiving
+ if (child_type() == Child::ABORT) {
+ if (submittable_->user_variable_exists("ECF_NONSTRICT_ZOMBIES")) {
+ std::stringstream ss; ss << " zombie(ECF_NONSTRICT_ZOMBIES) : " << path_to_submittable_ ;
+ if (password_missmatch) ss << " : password miss-match[ task:"<< submittable_->jobsPassword() << " child:" << jobs_password_ << " ]";
+ if (pid_missmatch) ss << " : pid miss-match[ task:"<< submittable_->process_or_remote_id() << " child:" << process_or_remote_id_ << " ]";
+ ss << " : already aborted : action taken( fob )";
+ log(Log::WAR, ss.str() );
+ theReply = PreAllocatedReply::ok_cmd();
+ return false;
+ }
+ }
+
+ // If Task state is aborted, and we receive **any** child command then it is a zombie
+ submittable_allready_aborted = true;
+ }
+
+#ifdef DEBUG_ZOMBIE
+ std::cout << "\n";
+#endif
+
+ if (password_missmatch || pid_missmatch || submittable_allready_active || submittable_allready_complete || submittable_allready_aborted){
+ /// If the task has adopted we return true, and carry on as normal
+ std::string action_taken;
+ if (!as->zombie_ctrl().handle_zombie(submittable_,this,action_taken,theReply)) {
+
+ // LOG failure: Include type of zombie.
+ // ** NOTE **: the zombie may have been removed by user actions. i.e if fob and child cmd is abort | complete, etc
+ std::stringstream ss; ss << " zombie";
+ const Zombie& theZombie = as->zombie_ctrl().find(path_to_submittable_, process_or_remote_id_, jobs_password_ );
+ if (!theZombie.empty() ) ss << "(" << theZombie.type_str() << ")";
+
+ ss << " : " << path_to_submittable_ << " : " << process_or_remote_id_ << " : " << jobs_password_;
+ if (submittable_allready_active) ss << " : already active";
+ if (submittable_allready_complete) ss << " : already complete";
+ if (submittable_allready_aborted) ss << " : already aborted";
+ if (password_missmatch) ss << " : password miss-match[ task:"<< submittable_->jobsPassword()<<" child:" << jobs_password_ << " ]";
+ if (pid_missmatch) ss << " : pid miss-match[ task:"<< submittable_->process_or_remote_id()<<" child:" << process_or_remote_id_ << " ]";
+ ss << " : action taken(" << action_taken << ")";
+ log(Log::ERR,ss.str());
+ return false;
+ }
+ }
+ return true;
+}
+
+Submittable* TaskCmd::get_submittable(AbstractServer* as) const
+{
+ node_ptr node = as->defs()->findAbsNode(path_to_submittable_);
+ if (!node.get()) {
+ return NULL;
+ }
+
+ return node->isSubmittable();
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+std::ostream& InitCmd::print(std::ostream& os) const
+{
+ return os << Str::CHILD_CMD() << "init " << path_to_node();
+}
+
+bool InitCmd::equals(ClientToServerCmd* rhs) const
+{
+ InitCmd* the_rhs = dynamic_cast<InitCmd*>(rhs);
+ if (!the_rhs) return false;
+ return TaskCmd::equals(rhs);
+}
+
+STC_Cmd_ptr InitCmd::doHandleRequest(AbstractServer* as) const
+{
+ as->update_stats().task_init_++;
+
+ { // update suite change numbers before job submission. submittable_ setup during authentication
+ SuiteChanged1 changed(submittable_->suite());
+ submittable_->init(process_or_remote_id()); // will set task->set_state(NState::ACTIVE);
+ }
+
+ // Do job submission in case any triggers dependent on NState::ACTIVE
+ as->increment_job_generation_count();
+ return PreAllocatedReply::ok_cmd();
+}
+
+const char* InitCmd::arg() { return TaskApi::initArg();}
+const char* InitCmd::desc() {
+ return
+ "Mark task as started(active). For use in the '.ecf' script file *only*\n"
+ "Hence the context is supplied via environment variables.\n"
+ " arg = process_or_remote_id. The process id of the job or remote_id\n"
+ " Using remote id allows the jobs to be killed\n\n"
+ "If this child command is a zombie, then the default action will be to *block*.\n"
+ "The default can be overridden by using zombie attributes.\n"
+ "Otherwise the blocking period is defined by ECF_TIMEOUT.\n\n"
+ "Usage:\n"
+ " ecflow_client --init=$$"
+ ;
+}
+
+void InitCmd::addOption(boost::program_options::options_description& desc) const{
+ desc.add_options()( InitCmd::arg(), po::value< string >(), InitCmd::desc() );
+}
+
+void InitCmd::create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const
+{
+ std::string process_or_remote_id = vm[ arg() ].as< std::string > ();
+
+ if (clientEnv->debug())
+ cout << " InitCmd::create " << InitCmd::arg()
+ << " clientEnv->task_path(" << clientEnv->task_path()
+ << ") clientEnv->jobs_password(" << clientEnv->jobs_password()
+ << ") clientEnv->process_or_remote_id(" << clientEnv->process_or_remote_id()
+ << ") clientEnv->task_try_no(" << clientEnv->task_try_no()
+ << ") process_or_remote_id(" << process_or_remote_id
+ << ") clientEnv->under_test(" << clientEnv->under_test()
+ << ")\n";
+
+ std::string errorMsg;
+ if ( !clientEnv->checkTaskPathAndPassword(errorMsg) ) {
+ throw std::runtime_error( "InitCmd: " + errorMsg );
+ }
+
+ /// if ECF_RID is specified then it *MUST* be the same as input argument
+ /// On cca we ECF_RID can be specified under test, and therefore fail this check, hence we use clientEnv->under_test()
+ if (!clientEnv->under_test() && !clientEnv->process_or_remote_id().empty() && clientEnv->process_or_remote_id() != process_or_remote_id) {
+ std::stringstream ss;
+ ss << "remote id(" << process_or_remote_id << ") passed as an argument, not the same the client environment ECF_RID(" << clientEnv->process_or_remote_id() << ")";
+ throw std::runtime_error(ss.str());
+ }
+
+ cmd = Cmd_ptr( new InitCmd( clientEnv->task_path(),
+ clientEnv->jobs_password(),
+ process_or_remote_id,
+ clientEnv->task_try_no()
+ )
+ );
+}
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+std::ostream& CompleteCmd::print(std::ostream& os) const
+{
+ return os << Str::CHILD_CMD() << "complete " << path_to_node();
+}
+
+bool CompleteCmd::equals(ClientToServerCmd* rhs) const
+{
+ CompleteCmd* the_rhs = dynamic_cast<CompleteCmd*>(rhs);
+ if (!the_rhs) return false;
+ return TaskCmd::equals(rhs);
+}
+
+STC_Cmd_ptr CompleteCmd::doHandleRequest(AbstractServer* as) const
+{
+ as->update_stats().task_complete_++;
+
+ {
+ /// If there is an associated zombie, remove from the list. Must match,
+ /// Do this before task->complete(), since that clears password & process id
+ /// remove(..) uses password/ process id to match the right zombie
+ as->zombie_ctrl().remove( submittable_ );
+
+ // update suite change numbers before job submission, submittable_ setup during authentication
+ SuiteChanged1 changed(submittable_->suite());
+ submittable_->complete(); // will set task->set_state(NState::COMPLETE);
+ }
+
+ // Do job submission in case any triggers dependent on NState::COMPLETE
+ as->increment_job_generation_count();
+ return PreAllocatedReply::ok_cmd();
+}
+
+const char* CompleteCmd::arg() { return TaskApi::completeArg();}
+const char* CompleteCmd::desc()
+{
+ return
+ "Mark task as complete. For use in the '.ecf' script file *only*\n"
+ "Hence the context is supplied via environment variables\n\n"
+ "If this child command is a zombie, then the default action will be to *block*.\n"
+ "The default can be overridden by using zombie attributes.\n"
+ "Otherwise the blocking period is defined by ECF_TIMEOUT.\n\n"
+ "Usage:\n"
+ " ecflow_client --complete"
+ ;
+}
+
+void CompleteCmd::addOption(boost::program_options::options_description& desc) const {
+ desc.add_options()( CompleteCmd::arg(), CompleteCmd::desc() );
+}
+void CompleteCmd::create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const
+{
+ if (clientEnv->debug())
+ cout << " CompleteCmd::create " << CompleteCmd::arg()
+ << " task_path(" << clientEnv->task_path()
+ << ") password(" << clientEnv->jobs_password()
+ << ") remote_id(" << clientEnv->process_or_remote_id()
+ << ") try_no(" << clientEnv->task_try_no()
+ << ")\n";
+
+
+ std::string errorMsg;
+ if ( !clientEnv->checkTaskPathAndPassword(errorMsg) ) {
+ throw std::runtime_error( "CompleteCmd: " + errorMsg );
+ }
+
+ cmd = Cmd_ptr( new CompleteCmd( clientEnv->task_path(),
+ clientEnv->jobs_password(),
+ clientEnv->process_or_remote_id(),
+ clientEnv->task_try_no()) );
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+CtsWaitCmd::CtsWaitCmd(const std::string& pathToTask,
+ const std::string& jobsPassword,
+ const std::string& process_or_remote_id,
+ int try_no,
+ const std::string& expression)
+ : TaskCmd(pathToTask,jobsPassword,process_or_remote_id,try_no), expression_(expression)
+{
+ // Parse expression to make sure its valid
+ PartExpression exp(expression);
+ string parseErrorMsg;
+ std::auto_ptr<AstTop> ast = exp.parseExpressions( parseErrorMsg );
+ if (!ast.get()) {
+
+ assert( !parseErrorMsg.empty() );
+ std::stringstream ss; ss << "CtsWaitCmd: Failed to parse expression '" << expression << "'. " << parseErrorMsg;
+ throw std::runtime_error( ss.str() );
+ }
+}
+
+std::ostream& CtsWaitCmd::print(std::ostream& os) const
+{
+ return os << Str::CHILD_CMD() << "wait " << expression_ << " " << path_to_node();
+}
+
+bool CtsWaitCmd::equals(ClientToServerCmd* rhs) const
+{
+ CtsWaitCmd* the_rhs = dynamic_cast< CtsWaitCmd* > ( rhs );
+ if ( !the_rhs ) return false;
+ if (expression_ != the_rhs->expression()) return false;
+ return TaskCmd::equals(rhs);
+}
+
+STC_Cmd_ptr CtsWaitCmd::doHandleRequest(AbstractServer* as) const
+{
+ as->update_stats().task_wait_++;
+
+ SuiteChanged1 changed(submittable_->suite());
+
+ // Parse the expression
+ PartExpression exp(expression_);
+ string parseErrorMsg;
+ std::auto_ptr<AstTop> ast = exp.parseExpressions( parseErrorMsg );
+ if (!ast.get()) {
+ // should NOT really, since client did check
+ std::stringstream ss; ss << "CtsWaitCmd: Failed to parse expression '" << expression_ << "'. " << parseErrorMsg;
+ throw std::runtime_error( ss.str() ) ;
+ }
+
+ // The complete expression have been parsed and we have created the abstract syntax tree
+ // We now need CHECK the AST for path nodes, event and meter. repeats,etc.
+ // *** This will also set the Node pointers ***
+ AstResolveVisitor astVisitor(submittable_);
+ ast->accept(astVisitor);
+
+ // If the expression references paths that don't exist throw an error
+ // This be captured in the ecf script, which should then abort the task
+ // Otherwise we will end up blocking indefinitely
+ if ( !astVisitor.errorMsg().empty() ) {
+ std::stringstream ss;
+ ss << "CtsWaitCmd: AST node tree references failed for " << expression_;
+ ss << " at " << submittable_->debugNodePath() << " : " << astVisitor.errorMsg();
+ throw std::runtime_error( ss.str() ) ;
+ }
+
+ // Evaluate the expression
+ if ( ast->evaluate() ) {
+
+ submittable_->flag().clear(ecf::Flag::WAIT);
+
+ // expression evaluates, return OK
+ return PreAllocatedReply::ok_cmd();
+ }
+
+ submittable_->flag().set(ecf::Flag::WAIT);
+
+ // Block/wait while expression is false
+ return PreAllocatedReply::block_client_on_home_server_cmd();
+}
+
+const char* CtsWaitCmd::arg() { return TaskApi::waitArg();}
+const char* CtsWaitCmd::desc() {
+ return
+ "Evaluates an expression, and block while the expression is false.\n"
+ "For use in the '.ecf' file *only*, hence the context is supplied via environment variables\n"
+ " arg1 = string(expression)\n"
+ "Usage:\n"
+ " ecflow_client --wait=\"/suite/taskx == complete\""
+ ;
+}
+
+void CtsWaitCmd::addOption(boost::program_options::options_description& desc) const {
+ desc.add_options()( CtsWaitCmd::arg(), po::value< string >(), CtsWaitCmd::desc() );
+}
+void CtsWaitCmd::create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const
+{
+ std::string expression = vm[ arg() ].as< std::string > ();
+
+ if (clientEnv->debug())
+ cout << " CtsWaitCmd::create " << CtsWaitCmd::arg()
+ << " task_path(" << clientEnv->task_path()
+ << ") password(" << clientEnv->jobs_password()
+ << ") remote_id(" << clientEnv->process_or_remote_id()
+ << ") try_no(" << clientEnv->task_try_no()
+ << ") expression(" << expression << ")\n";
+
+ std::string errorMsg;
+ if ( !clientEnv->checkTaskPathAndPassword(errorMsg) ) {
+ throw std::runtime_error( "CtsWaitCmd: " + errorMsg );
+ }
+
+ cmd = Cmd_ptr( new CtsWaitCmd( clientEnv->task_path(),
+ clientEnv->jobs_password(),
+ clientEnv->process_or_remote_id(),
+ clientEnv->task_try_no(),
+ expression) );
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+AbortCmd::AbortCmd(const std::string& pathToTask,
+ const std::string& jobsPassword,
+ const std::string& process_or_remote_id,
+ int try_no,
+ const std::string& reason)
+:TaskCmd(pathToTask,jobsPassword,process_or_remote_id,try_no), reason_(reason)
+{
+ if (!reason_.empty()) {
+ // Do not use "\n" | ';' in abortedReason_, as this can mess up, --migrate output
+ // Which would then affect --load.
+ Str::replace(reason_,"\n","");
+ Str::replace(reason_,";"," ");
+ }
+}
+
+std::ostream& AbortCmd::print(std::ostream& os) const
+{
+ return os << Str::CHILD_CMD() << "abort " << path_to_node() << " " << reason_;
+}
+
+bool AbortCmd::equals(ClientToServerCmd* rhs) const
+{
+ AbortCmd* the_rhs = dynamic_cast<AbortCmd*>(rhs);
+ if (!the_rhs) return false;
+ if (reason_ != the_rhs->reason()) return false;
+ return TaskCmd::equals(rhs);
+}
+
+STC_Cmd_ptr AbortCmd::doHandleRequest(AbstractServer* as) const
+{
+ as->update_stats().task_abort_++;
+
+ assert(isWrite()); // isWrite used in handleRequest() to control check pointing
+
+ {
+ /// If there is an associated zombie, remove from the list
+ as->zombie_ctrl().remove( submittable_ );
+
+ // update suite change numbers before job submission, submittable_ setup during authentication
+ SuiteChanged1 changed(submittable_->suite());
+
+ string theReason = reason_;
+ if ( theReason.empty() ) theReason = "Trap raised in job file";
+
+ submittable_->aborted(theReason); // will set task->set_state(NState::ABORTED);
+ }
+
+ // Do job submission in case any triggers dependent on NState::ABORTED
+ // If task try number is less than ECF_TRIES we attempt to re-submit the job.(ie if still in limit)
+ as->increment_job_generation_count();
+ return PreAllocatedReply::ok_cmd();
+}
+
+const char* AbortCmd::arg() { return TaskApi::abortArg();}
+const char* AbortCmd::desc() {
+ return
+ "Mark task as aborted. For use in the '.ecf' script file *only*\n"
+ "Hence the context is supplied via environment variables\n"
+ " arg1 = (optional) string(reason)\n"
+ " Optionally provide a reason why the abort was raised\n\n"
+ "If this child command is a zombie, then the default action will be to *block*.\n"
+ "The default can be overridden by using zombie attributes.\n"
+ "Otherwise the blocking period is defined by ECF_TIMEOUT.\n\n"
+ "Usage:\n"
+ " ecflow_client --abort=reasonX"
+ ;
+}
+
+void AbortCmd::addOption(boost::program_options::options_description& desc) const{
+ desc.add_options()( AbortCmd::arg(), po::value< string >()->implicit_value(string()), AbortCmd::desc() );
+}
+void AbortCmd::create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const
+{
+ std::string reason = vm[ arg() ].as< std::string > ();
+
+ if (clientEnv->debug())
+ cout << " AbortCmd::create " << AbortCmd::arg()
+ << " task_path(" << clientEnv->task_path()
+ << ") password(" << clientEnv->jobs_password()
+ << ") remote_id(" << clientEnv->process_or_remote_id()
+ << ") try_no(" << clientEnv->task_try_no()
+ << ") reason(" << reason << ")\n";
+
+
+ std::string errorMsg;
+ if ( !clientEnv->checkTaskPathAndPassword(errorMsg) ) {
+ throw std::runtime_error( "AbortCmd: " + errorMsg );
+ }
+
+ cmd = Cmd_ptr(new AbortCmd( clientEnv->task_path(),
+ clientEnv->jobs_password(),
+ clientEnv->process_or_remote_id(),
+ clientEnv->task_try_no(),
+ reason));
+}
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool EventCmd::equals(ClientToServerCmd* rhs) const
+{
+ EventCmd* the_rhs = dynamic_cast<EventCmd*>(rhs);
+ if (!the_rhs) return false;
+ if (name_ != the_rhs->name()) return false;
+ return TaskCmd::equals(rhs);
+}
+
+std::ostream& EventCmd::print(std::ostream& os) const
+{
+ return os << Str::CHILD_CMD() << "event " << name_ << " " << path_to_node();
+}
+
+STC_Cmd_ptr EventCmd::doHandleRequest(AbstractServer* as) const
+{
+ as->update_stats().task_event_++;
+
+ { // update suite change numbers before job submission, task_ setup during authentication
+ SuiteChanged1 changed(submittable_->suite());
+
+ // The name could either be "string" or an integer either way it should be unique
+ if (!submittable_->set_event(name_,true)) {
+ std::string ss; ss = "Event request failed as event '"; ss += name_; ss += "' does not exist on task "; ss += path_to_node();
+ ecf::log(Log::ERR,ss);
+ return PreAllocatedReply::ok_cmd();
+ }
+ }
+
+ // Do job submission in case any triggers dependent on events
+ as->increment_job_generation_count();
+ return PreAllocatedReply::ok_cmd();
+}
+
+const char* EventCmd::arg() { return TaskApi::eventArg();}
+const char* EventCmd::desc() {
+ return
+ "Change event. For use in the '.ecf' script file *only*\n"
+ "Hence the context is supplied via environment variables\n"
+ " arg1(string | int) = event-name\n\n"
+ "If this child command is a zombie, then the default action will be to *fob*,\n"
+ "i.e allow the ecflow client command to complete without an error\n"
+ "The default can be overridden by using zombie attributes.\n\n"
+ "Usage:\n"
+ " ecflow_client --event=ev"
+ ;
+}
+
+void EventCmd::addOption(boost::program_options::options_description& desc) const {
+ desc.add_options()( EventCmd::arg(), po::value< string >(), EventCmd::desc() );
+}
+void EventCmd::create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const
+{
+ std::string event = vm[ arg() ].as< std::string > ();
+
+ if (clientEnv->debug())
+ cout << " EventCmd::create " << EventCmd::arg()
+ << " task_path(" << clientEnv->task_path()
+ << ") password(" << clientEnv->jobs_password()
+ << ") remote_id(" << clientEnv->process_or_remote_id()
+ << ") try_no(" << clientEnv->task_try_no()
+ << ") event(" << event << ")\n";
+
+
+ std::string errorMsg;
+ if ( !clientEnv->checkTaskPathAndPassword(errorMsg) ) {
+ throw std::runtime_error( "EventCmd: " + errorMsg );
+ }
+
+ cmd = Cmd_ptr(new EventCmd( clientEnv->task_path(),
+ clientEnv->jobs_password(),
+ clientEnv->process_or_remote_id(),
+ clientEnv->task_try_no(),
+ event ));
+}
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool MeterCmd::equals(ClientToServerCmd* rhs) const
+{
+ MeterCmd* the_rhs = dynamic_cast<MeterCmd*>(rhs);
+ if (!the_rhs) return false;
+ if (name_ != the_rhs->name()) return false;
+ if (value_ != the_rhs->value()) return false;
+ return TaskCmd::equals(rhs);
+}
+
+std::ostream& MeterCmd::print(std::ostream& os) const
+{
+ return os << Str::CHILD_CMD() << "meter " << name_ << " " << value_ << " " << path_to_node();
+}
+
+STC_Cmd_ptr MeterCmd::doHandleRequest(AbstractServer* as) const
+{
+ as->update_stats().task_meter_++;
+
+ { // Added scope for SuiteChanged1 changed: i.e update suite change numbers before job submission
+ // submittable_ setup during authentication
+ SuiteChanged1 changed(submittable_->suite());
+
+ /// Allow meter to set any valid value that is in range because:
+ /// - When we have a network failure, and restoration. The meter tasks, will come in random, order.
+ /// - When task is executed without a requee the meter value will less than maximum
+ ///
+ /// This has *IMPLICATION*, if the meter is used in a trigger, using a equality
+ /// operator, then the trigger will always hold. hence suite designers need to
+ /// aware of this.
+ try {
+
+ Meter& the_meter = submittable_->find_meter(name_);
+ if (the_meter.empty()) {
+ LOG(Log::ERR,"MeterCmd::doHandleRequest: failed as meter '" << name_ << "' does not exist on task " << path_to_node());
+ return PreAllocatedReply::ok_cmd();
+ }
+
+ /// Invalid meter values(out or range) will raise exceptions.
+ /// Just ignore the request rather than failing client cmd
+ the_meter.set_value(value_);
+ }
+ catch (std::exception& e) {
+ LOG(Log::ERR,"MeterCmd::doHandleRequest: failed for task " << path_to_node() << ". " << e.what());
+ return PreAllocatedReply::ok_cmd();
+ }
+ }
+
+ // Do job submission in case any triggers dependent on meters
+ as->increment_job_generation_count();
+ return PreAllocatedReply::ok_cmd();
+}
+
+const char* MeterCmd::arg() { return TaskApi::meterArg();}
+const char* MeterCmd::desc() {
+ return
+ "Change meter. For use in the '.ecf' script file *only*\n"
+ "Hence the context is supplied via environment variables\n"
+ " arg1(string) = meter-name\n"
+ " arg2(int) = the new meter value\n\n"
+ "If this child command is a zombie, then the default action will be to *fob*,\n"
+ "i.e allow the ecflow client command to complete without an error\n"
+ "The default can be overridden by using zombie attributes.\n\n"
+ "Usage:\n"
+ " ecflow_client --meter=my_meter 20"
+ ;
+}
+
+void MeterCmd::addOption(boost::program_options::options_description& desc) const {
+ desc.add_options()( MeterCmd::arg(), po::value< vector<string> >()->multitoken(), MeterCmd::desc() );
+}
+void MeterCmd::create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const
+{
+ vector<string> args = vm[ arg() ].as< vector<string> >();
+
+ if (clientEnv->debug()) {
+ dumpVecArgs(MeterCmd::arg(),args);
+ cout << " MeterCmd::create " << MeterCmd::arg()
+ << " task_path(" << clientEnv->task_path()
+ << ") password(" << clientEnv->jobs_password()
+ << ") remote_id(" << clientEnv->process_or_remote_id()
+ << ") try_no(" << clientEnv->task_try_no()
+ << ")\n";
+ }
+
+ if (args.size() != 2 ) {
+ std::stringstream ss;
+ ss << "MeterCmd: Two arguments expected, found " << args.size()
+ << " Please specify <meter-name> <meter-value>, ie --meter=name 100\n";
+ throw std::runtime_error( ss.str() );
+ }
+
+ int value = 0;
+ try {
+ std::string strVal = args[1];
+ value = boost::lexical_cast<int>(strVal);
+ }
+ catch (boost::bad_lexical_cast& e) {
+ throw std::runtime_error( "MeterCmd: Second argument must be a integer, i.e. --meter=name 100\n" );
+ }
+
+ std::string errorMsg;
+ if ( !clientEnv->checkTaskPathAndPassword(errorMsg) ) {
+ throw std::runtime_error( "MeterCmd: " + errorMsg );
+ }
+
+ cmd = Cmd_ptr(new MeterCmd( clientEnv->task_path(),
+ clientEnv->jobs_password(),
+ clientEnv->process_or_remote_id(),
+ clientEnv->task_try_no(),
+ args[0],
+ value ));
+}
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool LabelCmd::equals(ClientToServerCmd* rhs) const
+{
+ LabelCmd* the_rhs = dynamic_cast<LabelCmd*>(rhs);
+ if (!the_rhs) return false;
+ if (name_ != the_rhs->name()) return false;
+ if (label_ != the_rhs->label()) return false;
+ return TaskCmd::equals(rhs);
+}
+
+std::ostream& LabelCmd::print(std::ostream& os) const
+{
+ return os << Str::CHILD_CMD() << "label " << name_ << " '" << label_ << "' " << path_to_node();
+}
+
+STC_Cmd_ptr LabelCmd::doHandleRequest(AbstractServer* as) const
+{
+ as->update_stats().task_label_++;
+
+ assert(isWrite()); // isWrite used in handleRequest() to control check pointing
+
+ // submittable_ setup during authentication
+ if (submittable_->findLabel(name_)) {
+
+ SuiteChanged1 changed(submittable_->suite());
+ submittable_->changeLabel(name_,label_);
+ }
+ // else {
+ // // ECFLOW-175, avoid filling up log file. Can get thousands of these messages, especially form MARS
+ // std::string ss;
+ // ss = "Label request failed as label '"; ss += name_; ss += "' does not exist on task "; ss += path_to_node();
+ // ecf::log(Log::ERR,ss);
+ //}
+
+ // Note: reclaiming memory for label_ earlier make *no* difference to performance of server
+
+ return PreAllocatedReply::ok_cmd();
+}
+
+const char* LabelCmd::arg() { return TaskApi::labelArg();}
+const char* LabelCmd::desc() {
+ return
+ "Change Label. For use in the '.ecf' script file *only*\n"
+ "Hence the context is supplied via environment variables\n"
+ " arg1 = label-name\n"
+ " arg2 = The new label value\n"
+ " The labels values can be single or multi-line(space separated quoted strings)\n\n"
+ "If this child command is a zombie, then the default action will be to *fob*,\n"
+ "i.e allow the ecflow client command to complete without an error\n"
+ "The default can be overridden by using zombie attributes.\n\n"
+ "Usage:\n"
+ " ecflow_client --label=progressed merlin"
+ ;
+}
+
+void LabelCmd::addOption(boost::program_options::options_description& desc) const {
+ desc.add_options()( LabelCmd::arg(), po::value< vector<string> >()->multitoken(), LabelCmd::desc() );
+}
+void LabelCmd::create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* clientEnv ) const
+{
+ vector<string> args = vm[ arg() ].as< vector<string> >();
+
+ if (clientEnv->debug()) {
+ dumpVecArgs(LabelCmd::arg(),args);
+ cout << " LabelCmd::create " << LabelCmd::arg()
+ << " task_path(" << clientEnv->task_path()
+ << ") password(" << clientEnv->jobs_password()
+ << ") remote_id(" << clientEnv->process_or_remote_id()
+ << ") try_no(" << clientEnv->task_try_no()
+ << ")\n";
+ }
+
+ if (args.size() < 2 ) {
+ std::stringstream ss;
+ ss << "LabelCmd: At least 2 arguments expected. Please specify <label-name> <string1> <string2>\n";
+ throw std::runtime_error( ss.str() );
+ }
+
+ std::string labelName = args[0];
+ args.erase(args.begin()); // remove name from vector of strings
+ std::string labelValue;
+ for(size_t i =0; i < args.size(); i++) {
+ if (i != 0) labelValue += " ";
+ labelValue += args[i];
+ }
+
+ std::string errorMsg;
+ if ( !clientEnv->checkTaskPathAndPassword(errorMsg) ) {
+ throw std::runtime_error( "LabelCmd: " + errorMsg );
+ }
+
+ cmd = Cmd_ptr(new LabelCmd( clientEnv->task_path(),
+ clientEnv->jobs_password(),
+ clientEnv->process_or_remote_id(),
+ clientEnv->task_try_no(),
+ labelName,
+ labelValue));
+}
+
+std::ostream& operator<<(std::ostream& os, const InitCmd& c) { return c.print(os); }
+std::ostream& operator<<(std::ostream& os, const EventCmd& c) { return c.print(os); }
+std::ostream& operator<<(std::ostream& os, const MeterCmd& c) { return c.print(os); }
+std::ostream& operator<<(std::ostream& os, const LabelCmd& c) { return c.print(os); }
+std::ostream& operator<<(std::ostream& os, const AbortCmd& c) { return c.print(os); }
+std::ostream& operator<<(std::ostream& os, const CompleteCmd& c) { return c.print(os); }
+std::ostream& operator<<(std::ostream& os, const CtsWaitCmd& c) { return c.print(os); }
diff --git a/Base/src/cts/UserCmd.cpp b/Base/src/cts/UserCmd.cpp
new file mode 100644
index 0000000..4137893
--- /dev/null
+++ b/Base/src/cts/UserCmd.cpp
@@ -0,0 +1,154 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #65 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <iostream>
+#include <sstream>
+#include <fstream>
+
+#include <pwd.h> /* getpwuid */
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h> /* tolower */
+#include <string.h> // for strerror()
+#include <errno.h> // for errno()
+
+#include "ClientToServerCmd.hpp"
+
+#include "AbstractServer.hpp"
+#include "Log.hpp"
+#include "Str.hpp"
+
+using namespace std;
+using namespace boost;
+using namespace ecf;
+
+bool UserCmd::equals(ClientToServerCmd* rhs) const
+{
+ UserCmd* the_rhs = dynamic_cast< UserCmd* > ( rhs );
+ if ( !the_rhs ) return false;
+ return user_ == the_rhs->user();
+}
+
+bool UserCmd::authenticate(AbstractServer* as, STC_Cmd_ptr& ) const
+{
+ // The user should NOT be empty. Rather than asserting and killing the server, fail authentication
+ // ECFLOW-577 and ECFLOW-512. When user_ empty ??
+ if (!user_.empty() && as->authenticateReadAccess(user_)) {
+
+ // Does this user command require write access
+ if ( isWrite() ) {
+ // command requires write access. Check user has write access
+ if ( as->authenticateWriteAccess(user_) ) {
+ return true;
+ }
+ std::string msg = "[ authentication failed ] User ";
+ msg += user_;
+ msg += " has no *write* access. Please see your administrator.";
+ throw std::runtime_error( msg );
+ }
+ else {
+ // read request, and we have read access
+ return true;
+ }
+ }
+
+ std::string msg = "[ authentication failed ] User '";
+ msg += user_;
+ msg += "' is not allowed any access.";
+ throw std::runtime_error( msg );
+
+ return false;
+}
+
+void UserCmd::setup_user_authentification()
+{
+ // Minimise system calls by using static.
+ static std::string the_user_name;
+ if (the_user_name.empty()) {
+
+ // Get the uid of the running process and use it to get a record from /etc/passwd */
+ // getuid() can not fail, but getpwuid can fail.
+ errno = 0;
+ uid_t real_user_id_of_process = getuid();
+ struct passwd * thePassWord = getpwuid ( real_user_id_of_process );
+ if (thePassWord == 0 ) {
+ if ( errno != 0) {
+ std::string theError = strerror(errno);
+ throw std::runtime_error("UserCmd::setup_user_authentification: could not determine user name. Because: " + theError);
+ }
+
+ std::stringstream ss;
+ ss << "UserCmd::setup_user_authentification: could not determine user name for uid " << real_user_id_of_process;
+ throw std::runtime_error(ss.str());
+ }
+
+ the_user_name = thePassWord->pw_name; // equivalent to the login name
+ if ( the_user_name.empty() ) {
+ throw std::runtime_error("UserCmd::setup_user_authentification: could not determine user name. Because: thePassWord->pw_name is empty");
+ }
+ }
+
+ user_ = the_user_name;
+ assert(!user_.empty());
+}
+
+void UserCmd::prompt_for_confirmation(const std::string& prompt)
+{
+ cout << prompt;
+ char reply[256];
+ cin.getline (reply,256);
+ if (reply[0] != 'y' && reply[0] != 'Y') {
+ exit(1);
+ }
+}
+
+std::ostream& UserCmd::user_cmd(std::ostream& os, const std::string& the_cmd) const
+{
+ return os << the_cmd << " :" << user_;
+}
+
+//#define DEBUG_ME 1
+
+void UserCmd::split_args_to_options_and_paths(
+ const std::vector<std::string>& args,
+ std::vector<std::string>& options,
+ std::vector<std::string>& paths)
+{
+ // ** ECFLOW-137 **, if the trigger expression have a leading '/' then it gets parsed into the paths
+ // vector and not options
+ // This is because boost program options does *NOT* seem to preserve the leading quotes around the
+ // trigger/complete expression, i.e "/suite/t2 == complete" is read as /suite/t2 == complete
+ // However in paths we do expect to see any spaces
+
+ size_t vec_size = args.size();
+ for(size_t i = 0; i < vec_size; i++) {
+ if (args[i].empty()) continue;
+ if (args[i][0] == '/' && args[i].find(" ") == std::string::npos) {
+ paths.push_back(args[i]);
+ }
+ else {
+ options.push_back(args[i]);
+ }
+ }
+
+#ifdef DEBUG_ME
+ std::cout << "split_args_to_options_and_paths\n";
+ for(size_t i = 0; i < args.size(); ++i) { std::cout << "args[" << i << "]=" <<args[i] << "\n"; }
+ for(size_t i = 0; i < options.size(); ++i) { std::cout << "options[" << i << "]=" << options[i] << "\n"; }
+ for(size_t i = 0; i < paths.size(); ++i) { std::cout << "paths[" << i << "]=" << paths[i] << "\n"; }
+#endif
+}
+
+int UserCmd::time_out_for_load_sync_and_get() { return 600; }
+
diff --git a/Base/src/cts/ZombieCmd.cpp b/Base/src/cts/ZombieCmd.cpp
new file mode 100644
index 0000000..8aaa1b7
--- /dev/null
+++ b/Base/src/cts/ZombieCmd.cpp
@@ -0,0 +1,232 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #24 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include "ClientToServerCmd.hpp"
+#include "AbstractServer.hpp"
+#include "CtsApi.hpp"
+#include "AbstractClientEnv.hpp"
+#include "Defs.hpp"
+#include "Task.hpp"
+#include "Str.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+namespace po = boost::program_options;
+
+std::ostream& ZombieCmd::print(std::ostream& os) const
+{
+ switch (user_action_) {
+ case User::FOB: return user_cmd(os,CtsApi::to_string(CtsApi::zombieFob(path_,process_id_,password_))); break;
+ case User::FAIL: return user_cmd(os,CtsApi::to_string(CtsApi::zombieFail(path_,process_id_,password_))); break;
+ case User::ADOPT: return user_cmd(os,CtsApi::to_string(CtsApi::zombieAdopt(path_,process_id_,password_))); break;
+ case User::REMOVE: return user_cmd(os,CtsApi::to_string(CtsApi::zombieRemove(path_,process_id_,password_))); break;
+ case User::BLOCK: return user_cmd(os,CtsApi::to_string(CtsApi::zombieBlock(path_,process_id_,password_))); break;
+ case User::KILL: return user_cmd(os,CtsApi::to_string(CtsApi::zombieKill(path_,process_id_,password_))); break;
+ default: break;
+ }
+ return os;
+}
+
+bool ZombieCmd::equals(ClientToServerCmd* rhs) const
+{
+ ZombieCmd* the_rhs = dynamic_cast< ZombieCmd* > ( rhs );
+ if ( !the_rhs ) return false;
+ if (path_ != the_rhs->path_to_task()) return false;
+ if (process_id_ != the_rhs->process_or_remote_id()) return false;
+ if (password_ != the_rhs->password()) return false;
+ return UserCmd::equals(rhs);
+}
+
+STC_Cmd_ptr ZombieCmd::doHandleRequest(AbstractServer* as) const
+{
+ // To uniquely identify a zombie we need path to task and remote_id, This information
+ // is available from the zombie class via get command. However we do not want to
+ // expose the password.
+ // Hence the Command level interface will make do with just the path to the task.
+ // The first zombie whose corresponding task where password does *NOT* match is acted upon
+ Task* task = NULL;
+ if ( process_id_.empty() && password_.empty()) {
+ node_ptr node = as->defs()->findAbsNode(path_);
+ if (node.get()) task = node->isTask();
+ }
+
+ switch (user_action_) {
+
+ case User::FOB: {
+ as->update_stats().zombie_fob_++;
+ if ( process_id_.empty() && password_.empty()) as->zombie_ctrl().fobCli(path_,task);
+ else as->zombie_ctrl().fob(path_,process_id_,password_);
+ break;
+ }
+
+ case User::FAIL: {
+ as->update_stats().zombie_fail_++;
+ if ( process_id_.empty() && password_.empty()) as->zombie_ctrl().failCli(path_,task);
+ else as->zombie_ctrl().fail(path_,process_id_,password_);
+ break;
+ }
+
+ case User::ADOPT: {
+ as->update_stats().zombie_adopt_++;
+ if ( process_id_.empty() && password_.empty()) as->zombie_ctrl().adoptCli(path_,task);
+ else as->zombie_ctrl().adopt(path_,process_id_,password_);
+ break;
+ }
+
+ case User::REMOVE: {
+ as->update_stats().zombie_remove_++;
+ if ( process_id_.empty() && password_.empty()) as->zombie_ctrl().removeCli(path_,task);
+ else as->zombie_ctrl().remove(path_,process_id_,password_);
+ break;
+ }
+
+ case User::BLOCK: {
+ as->update_stats().zombie_block_++;
+ if ( process_id_.empty() && password_.empty()) as->zombie_ctrl().blockCli(path_,task);
+ else as->zombie_ctrl().block(path_,process_id_,password_);
+ break;
+ }
+
+ case User::KILL: {
+ as->update_stats().zombie_kill_++;
+ if ( process_id_.empty() && password_.empty()) as->zombie_ctrl().killCli(path_,task);
+ else as->zombie_ctrl().kill(path_,process_id_,password_);
+ break;
+ }
+ }
+
+ return PreAllocatedReply::ok_cmd();
+}
+
+const char* ZombieCmd::theArg() const {
+
+ switch (user_action_) {
+ case User::FOB: return CtsApi::zombieFobArg(); break;
+ case User::FAIL: return CtsApi::zombieFailArg(); break;
+ case User::ADOPT: return CtsApi::zombieAdoptArg(); break;
+ case User::REMOVE: return CtsApi::zombieRemoveArg(); break;
+ case User::BLOCK: return CtsApi::zombieBlockArg(); break;
+ case User::KILL: return CtsApi::zombieKillArg(); break;
+ default: break;
+ }
+ assert(false);
+ return NULL;
+}
+
+void ZombieCmd::addOption(boost::program_options::options_description& desc) const
+{
+ switch (user_action_) {
+
+ case User::FOB: {
+ desc.add_options()( CtsApi::zombieFobArg(), po::value< vector<string> >()->multitoken(),
+ "Locates the task in the zombie list, and sets to fob.\n"
+ "Next time the child commands (init,event,meter,label,abort,complete) communicate\n"
+ "with the server, they will complete successfully (but without updating the node tree)\n"
+ "allowing the job to finish.\n"
+ "The server zombie is automatically deleted after 1 hour\n"
+ " arg = path to task\n"
+ " --zombie_fob=/path/to/task"
+ );
+ break;
+ }
+ case User::FAIL: {
+ desc.add_options()( CtsApi::zombieFailArg(), po::value< vector<string> >()->multitoken(),
+ "Locates the task in the zombie list, and sets to fail.\n"
+ "Next time the child commands (init,event,meter,label,abort,complete) communicate\n"
+ "with the server, they will be set to fail. Depending on the job setup this may\n"
+ "force a abort, the abort will also fail.\n"
+ "Hence job structure should use 'set -e' in the error trapping functions to prevent\n"
+ "infinite recursion. The server zombie is automatically deleted after 1 hour\n"
+ " arg = path to task\n"
+ " --zombie_fail=/path/to/task"
+ );
+ break;
+ }
+ case User::ADOPT: {
+ desc.add_options()( CtsApi::zombieAdoptArg(), po::value< vector<string> >()->multitoken(),
+ "Locates the task in the zombie list, and sets to adopt.\n"
+ "Next time the child commands (init,event,meter,label,abort,complete) communicate\n"
+ "with the server, the password on the zombie is adopted by the task.\n"
+ "The zombie is then deleted.\n"
+ " arg = path to task\n"
+ " --zombie_adopt=/path/to/task"
+ );
+ break;
+ }
+ case User::REMOVE: {
+ desc.add_options()( CtsApi::zombieRemoveArg(), po::value< vector<string> >()->multitoken(),
+ "Locates the task in the zombie list, and removes it.\n"
+ "Since a job typically has many child commands(i.e init, complete, event, meter, label)\n"
+ "the zombie may reappear\n"
+ " arg = path to task\n"
+ " --zombie_remove=/path/to/task"
+ );
+ break;
+ }
+ case User::BLOCK: {
+ desc.add_options()( CtsApi::zombieBlockArg(), po::value< vector<string> >()->multitoken(),
+ "Locates the task in the zombie list, and blocks it.\n"
+ "This is default behaviour of the child commands(init,event,meter,label,abort,complete)\n"
+ "when the server can not match the passwords. Each child commands will continue\n"
+ "attempting to connect to the server for 24 hours, and will then return an error.\n"
+ "The connection timeout can be configured with environment ECF_TIMEOUT\n"
+ " arg = path to task\n"
+ " --zombie_block=/path/to/task"
+ );
+ break;
+ }
+ case User::KILL: {
+ desc.add_options()( CtsApi::zombieKillArg(), po::value< vector<string> >()->multitoken(),
+ "Locates the task in the zombie list, and kills the associated job.\n"
+ "The kill is done using ECF_KILL_CMD, but using the process_id from the zombie\n"
+ "The job is allowed to continue until the kill is received\n"
+ "Can only kill zombies that have an associated Task, hence path zombies\n"
+ "must be killed manually.\n"
+ " arg = path to task\n"
+ " --zombie_kill=/path/to/task"
+ );
+ break;
+ }
+ default: assert(false); break;
+ }
+}
+
+void ZombieCmd::create( Cmd_ptr& cmd,
+ boost::program_options::variables_map& vm,
+ AbstractClientEnv* ace ) const
+{
+ vector<string> args = vm[ theArg() ].as< vector<string> >();
+ if (ace->debug()) dumpVecArgs( theArg(), args);
+
+ // For Command Line Interface only the task_path is provided. Just have to make do.
+ // arg1 = task_path
+ // arg2 = process_or_remote_id ( empty for CLI)
+ // arg3 = password ( empty for CLI)
+ std::string path;
+ std::string process_or_remote_id;
+ std::string password;
+ for(size_t i = 0; i < args.size(); i++) {
+ if (i == 0 ) path = args[i];
+ if (i == 1 ) process_or_remote_id = args[i];
+ if (i == 2 ) password = args[i];
+ }
+ if (path.empty()) {
+ throw std::runtime_error("ZombieCmd::create: expects at least one argument. path to task");
+ }
+
+ cmd = Cmd_ptr(new ZombieCmd(user_action_, path, process_or_remote_id, password ));
+}
+
+std::ostream& operator<<(std::ostream& os, const ZombieCmd& c) { return c.print(os); }
diff --git a/Base/src/stc/DefsCmd.cpp b/Base/src/stc/DefsCmd.cpp
new file mode 100644
index 0000000..fb81db7
--- /dev/null
+++ b/Base/src/stc/DefsCmd.cpp
@@ -0,0 +1,99 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name : Cmd
+// Author : Avi
+// Revision : $Revision: #27 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <iostream>
+
+#include "DefsCmd.hpp"
+#include "ClientToServerCmd.hpp"
+#include "Defs.hpp"
+#include "Ecf.hpp"
+#include "AbstractServer.hpp"
+#include "PrintStyle.hpp"
+
+using namespace std;
+using namespace boost;
+
+//=====================================================================================
+// The defs command returns the full definition back to the client
+
+DefsCmd::DefsCmd(AbstractServer* as,bool save_edit_history)
+{
+ init(as,save_edit_history);
+}
+
+void DefsCmd::init(AbstractServer* as,bool save_edit_history)
+{
+ defs_ = as->defs();
+ /// Return the current value of the state change no. So the that
+ /// the next call to get the SSYncCmd , we need only return what's changed
+ defs_->set_state_change_no( Ecf::state_change_no() );
+ defs_->set_modify_change_no( Ecf::modify_change_no() );
+ defs_->save_edit_history(save_edit_history);
+}
+
+bool DefsCmd::equals(ServerToClientCmd* rhs) const
+{
+ DefsCmd* the_rhs = dynamic_cast<DefsCmd*>(rhs);
+ if (!the_rhs) return false;
+ if (!ServerToClientCmd::equals(rhs)) return false;
+
+ if (defs_ == NULL && the_rhs->defs() == NULL) return true;
+ if (defs_ == NULL && the_rhs->defs() != NULL) return false;
+ if (defs_ != NULL && the_rhs->defs() == NULL) return false;
+ return (*defs_ == *(the_rhs->defs()));
+}
+
+std::ostream& DefsCmd::print(std::ostream& os) const
+{
+ os << "cmd:DefsCmd [ defs ]";
+ return os;
+}
+
+// Called in client
+bool DefsCmd::handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const
+{
+ if (debug) std::cout << " DefsCmd::handle_server_response show_state = " << PrintStyle::to_string(cts_cmd->show_style()) << "\n";
+
+ // If we asked for the defs node tree from the server, then this is what we should have got back.
+ // ** Keep existing defs in memory, until a new one is requested. This allows clients
+ // ** to continue using this defs, in between other api calls, until a new defs is requested.
+
+ if ( !defs_.get() ) {
+ std::stringstream ss;
+ ss << "DefsCmd::handle_server_response: Error Node tree could not be retrieved from server. Request "; cts_cmd->print(ss); ss << " failed.\n";
+ throw std::runtime_error(ss.str());
+ }
+
+ if (server_reply.cli() && !cts_cmd->group_cmd()) {
+ /// This Could be part of a group command, hence ONLY show defs if NOT group command
+ PrintStyle style(cts_cmd->show_style());
+
+ if (cts_cmd->show_style() != PrintStyle::MIGRATE) {
+ /// Auto generate externs, before writing to standard out. This can be expensive since
+ /// All the trigger references need to to be resolved. & AST need to be created first
+ /// The old spirit based parsing, horrendously, slow. Can't use Spirit QI, till IBM pull support it
+ defs_->auto_add_externs();
+ }
+ std::cout << *defs_;
+ }
+ else {
+ server_reply.set_sync( true ); // always in sync when getting the full defs
+ server_reply.set_full_sync( true ); // Done a full sync, as opposed to incremental
+ server_reply.set_client_defs( defs_ );
+ }
+ return true;
+}
+
+
+std::ostream& operator<<(std::ostream& os, const DefsCmd& c) { return c.print(os); }
diff --git a/Base/src/stc/DefsCmd.hpp b/Base/src/stc/DefsCmd.hpp
new file mode 100644
index 0000000..9a28534
--- /dev/null
+++ b/Base/src/stc/DefsCmd.hpp
@@ -0,0 +1,52 @@
+#ifndef DEFS_CMD_HPP_
+#define DEFS_CMD_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #14 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "ServerToClientCmd.hpp"
+class AbstractServer;
+
+//================================================================================
+// Paired with CtsNodeCmd(GET)
+// Client---CtsNodeCmd(GET)---->Server-----(DefsCmd | SNodeCmd)--->client:
+//================================================================================
+class DefsCmd : public ServerToClientCmd {
+public:
+ DefsCmd(AbstractServer* as, bool save_edit_history = false);
+ DefsCmd() {}
+
+ void init(AbstractServer* as, bool save_edit_history);
+
+ defs_ptr defs() const { return defs_; }
+
+ virtual bool hasDefs() const { return defs_.get() != NULL; }
+ virtual bool handle_server_response( ServerReply&, Cmd_ptr cts_cmd, bool debug ) const;
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ServerToClientCmd*) const;
+
+private:
+ defs_ptr defs_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< ServerToClientCmd >( *this );
+ ar & defs_;
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, const DefsCmd&);
+
+#endif
diff --git a/Base/src/stc/ErrorCmd.cpp b/Base/src/stc/ErrorCmd.cpp
new file mode 100644
index 0000000..bc93688
--- /dev/null
+++ b/Base/src/stc/ErrorCmd.cpp
@@ -0,0 +1,63 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #13 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <iostream>
+#include "ErrorCmd.hpp"
+#include "ClientToServerCmd.hpp"
+#include "Log.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+
+ErrorCmd::ErrorCmd(const std::string& errorMsg)
+{
+ init(errorMsg);
+}
+
+void ErrorCmd::init( const std::string& errorMsg)
+{
+//#ifdef DEBUG
+// std::cout << ErrorCmd::init " << errorMsg << "\n";
+// LogToCout toCoutAsWell;
+//#endif
+
+ LOG_ASSERT(!errorMsg.empty(),"");
+ error_msg_ = errorMsg;
+
+ // Log the error, Remove any "/n" as the log file will add this automatically
+ size_t pos = error_msg_.rfind("\n");
+ if (pos != string::npos) error_msg_.erase(error_msg_.begin() + pos);
+ ecf::log(Log::ERR,error_msg_); // will automatically add end of line
+}
+
+std::ostream& ErrorCmd::print(std::ostream& os) const { return os << "cmd:Error [ " << error_msg_ << " ]";}
+
+bool ErrorCmd::equals(ServerToClientCmd* rhs) const
+{
+ return (dynamic_cast<ErrorCmd*>(rhs)) ? ServerToClientCmd::equals(rhs) : false;
+}
+
+bool ErrorCmd::handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const
+{
+ if (debug) std::cout << " ErrorCmd::handle_server_response " << error_msg_ << "\n";
+
+ std::stringstream ss;
+ ss << "Error: request( "; cts_cmd->print(ss); ss << " ) failed! Server replied with: '" << error_msg_ << "'\n";
+ server_reply.set_error_msg(ss.str());
+ return false;
+}
+
+std::ostream& operator<<(std::ostream& os, const ErrorCmd& c) { return c.print(os); }
+
diff --git a/Base/src/stc/ErrorCmd.hpp b/Base/src/stc/ErrorCmd.hpp
new file mode 100644
index 0000000..ea8ce1a
--- /dev/null
+++ b/Base/src/stc/ErrorCmd.hpp
@@ -0,0 +1,45 @@
+#ifndef ERROR_CMD_HPP_
+#define ERROR_CMD_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include "ServerToClientCmd.hpp"
+
+class ErrorCmd : public ServerToClientCmd {
+public:
+ ErrorCmd(const std::string& errorMsg);
+ ErrorCmd() : ServerToClientCmd() {}
+
+ void init( const std::string& errorMsg);
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ServerToClientCmd*) const;
+ virtual bool handle_server_response( ServerReply&, Cmd_ptr cts_cmd, bool debug ) const;
+
+ virtual std::string error() const { return error_msg_;} /// Used by test
+ virtual bool ok() const { return false; } /// Used by group command
+
+private:
+ std::string error_msg_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< ServerToClientCmd >( *this );
+ ar & error_msg_;
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, const ErrorCmd&);
+
+#endif
diff --git a/Base/src/stc/GroupSTCCmd.cpp b/Base/src/stc/GroupSTCCmd.cpp
new file mode 100644
index 0000000..589f06d
--- /dev/null
+++ b/Base/src/stc/GroupSTCCmd.cpp
@@ -0,0 +1,124 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #18 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <boost/foreach.hpp>
+#include "GroupSTCCmd.hpp"
+#include "ClientToServerCmd.hpp"
+#include "Str.hpp"
+#include "Defs.hpp"
+#include "Log.hpp"
+#include "PrintStyle.hpp"
+#include "WhyCmd.hpp"
+#include "Task.hpp"
+#include "Family.hpp"
+#include "Suite.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+
+std::ostream& GroupSTCCmd::print(std::ostream& os) const
+{
+ return os << "cmd:GroupSTCCmd";
+}
+
+bool GroupSTCCmd::equals(ServerToClientCmd* rhs) const
+{
+ GroupSTCCmd* the_rhs = dynamic_cast< GroupSTCCmd* > ( rhs );
+ if ( !the_rhs ) return false;
+
+ const std::vector<STC_Cmd_ptr>& rhsCmdVec = the_rhs->cmdVec();
+ if (cmdVec_.size() != rhsCmdVec.size()) return false;
+
+ for(size_t i = 0; i < cmdVec_.size(); i++) {
+ if ( !cmdVec_[i]->equals( rhsCmdVec[i].get() ) ) {
+ return false;
+ }
+ }
+
+ return ServerToClientCmd::equals(rhs);
+}
+
+bool GroupSTCCmd::handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const
+{
+ if (debug) std::cout << " GroupSTCCmd::handle_server_response\n";
+
+ BOOST_FOREACH(STC_Cmd_ptr subCmd, cmdVec_) {
+ (void)subCmd->handle_server_response(server_reply, cts_cmd, debug);
+ }
+
+ /// This assumes the DefsCmd::handle_server_response() | SNodeCmd::handle_server_response has been called
+ /// this will populate ServerReply with the defs/node returned from the server
+ defs_ptr defs = server_reply.client_defs();
+ node_ptr node = server_reply.client_node();
+
+ if ( cts_cmd->get_cmd() && (defs.get() || node.get())) {
+ if (debug) std::cout << " GroupSTCCmd::handle_server_response *get* was called\n";
+
+ /// client --group="get; show" # where get will call DefsCmd will return defs, from the server
+ /// client --group="get; show state" # where get will call DefsCmd will return defs, from the server
+ /// client --group="get /s1; show state" # where get will call DefsCmd will return defs, from the server
+
+ // Print out the data that was received from server. as a part of get request.
+ // The server can not do a show, it MUST be done at the Client side
+ // The show request is only valid if the out bound request to the server
+ PrintStyle::Type_t style = cts_cmd->show_style();
+ if ( style != PrintStyle::NOTHING ) {
+ if (debug) std::cout << " GroupSTCCmd::handle_server_response *show* was called " << PrintStyle::to_string(style) << "\n";
+ PrintStyle::setStyle(style);
+ if (defs.get()) {
+
+ /// Auto generate externs, before writing to standard out. This can be expensive since
+ /// All the trigger references need to to be resolved. & AST need to be created first
+ /// The old spirit based parsing is horrendously, slow. Can't use Spirit QI, till IBM support it
+ if (cts_cmd->show_style() != PrintStyle::MIGRATE) {
+ defs->auto_add_externs();
+ }
+
+ std::cout << *defs.get();
+ }
+ else {
+ if (node.get()) {
+ Suite* suite = node->isSuite();
+ if (suite) std::cout << *suite << "\n";
+ Family* fam = node->isFamily();
+ if (fam) std::cout << *fam << "\n";
+ Task* task = node->isTask();
+ if (task) std::cout << *task << "\n";
+ }
+ }
+ }
+ }
+
+ std::string nodePath;
+ if (cts_cmd->why_cmd(nodePath) && defs.get()) {
+ if (debug) std::cout << " GroupSTCCmd::handle_server_response *why* was called\n";
+
+ /// client --group="get; why" # where get will call DefsCmd will return defs, from the server
+ /// client --group="get; why <path>" # where get will call DefsCmd will return defs, from the server
+ WhyCmd cmd(defs, nodePath);
+ std::cout << cmd.why() << "\n";
+ }
+
+ return true;
+}
+
+void GroupSTCCmd::addChild(STC_Cmd_ptr childCmd)
+{
+ LOG_ASSERT(childCmd.get(),""); // Dont add NULL children
+ cmdVec_.push_back(childCmd);
+}
+
+std::ostream& operator<<(std::ostream& os, const GroupSTCCmd& c) { return c.print(os); }
diff --git a/Base/src/stc/GroupSTCCmd.hpp b/Base/src/stc/GroupSTCCmd.hpp
new file mode 100644
index 0000000..7ceb2b9
--- /dev/null
+++ b/Base/src/stc/GroupSTCCmd.hpp
@@ -0,0 +1,44 @@
+#ifndef GROUP_STC_CMD_HPP_
+#define GROUP_STC_CMD_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #8 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "ServerToClientCmd.hpp"
+
+class GroupSTCCmd : public ServerToClientCmd {
+public:
+ GroupSTCCmd() : ServerToClientCmd() {}
+
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ServerToClientCmd*) const;
+ virtual bool handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const;
+
+ void addChild(STC_Cmd_ptr childCmd);
+ const std::vector<STC_Cmd_ptr>& cmdVec() const { return cmdVec_;}
+
+private:
+ std::vector<STC_Cmd_ptr> cmdVec_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< ServerToClientCmd >( *this );
+ ar & cmdVec_;
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, const GroupSTCCmd&);
+
+#endif
diff --git a/Base/src/stc/PreAllocatedReply.cpp b/Base/src/stc/PreAllocatedReply.cpp
new file mode 100644
index 0000000..edff028
--- /dev/null
+++ b/Base/src/stc/PreAllocatedReply.cpp
@@ -0,0 +1,201 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #24 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "PreAllocatedReply.hpp"
+
+#include "StcCmd.hpp"
+#include "DefsCmd.hpp"
+#include "SNodeCmd.hpp"
+#include "SStringCmd.hpp"
+#include "SStringVecCmd.hpp"
+#include "SServerLoadCmd.hpp"
+#include "GroupSTCCmd.hpp"
+#include "ErrorCmd.hpp"
+#include "SNewsCmd.hpp"
+#include "SSyncCmd.hpp"
+#include "SStatsCmd.hpp"
+#include "SSuitesCmd.hpp"
+#include "SClientHandleCmd.hpp"
+#include "SClientHandleSuitesCmd.hpp"
+#include "ZombieGetCmd.hpp"
+
+STC_Cmd_ptr PreAllocatedReply::stc_cmd_ = STC_Cmd_ptr( new StcCmd() );
+STC_Cmd_ptr PreAllocatedReply::defs_cmd_ = STC_Cmd_ptr( new DefsCmd() );
+STC_Cmd_ptr PreAllocatedReply::node_cmd_ = STC_Cmd_ptr( new SNodeCmd() );
+STC_Cmd_ptr PreAllocatedReply::stats_cmd_ = STC_Cmd_ptr( new SStatsCmd() );
+STC_Cmd_ptr PreAllocatedReply::suites_cmd_ = STC_Cmd_ptr( new SSuitesCmd() );
+STC_Cmd_ptr PreAllocatedReply::zombie_get_cmd_ = STC_Cmd_ptr( new ZombieGetCmd() );
+STC_Cmd_ptr PreAllocatedReply::error_cmd_ = STC_Cmd_ptr( new ErrorCmd() );
+STC_Cmd_ptr PreAllocatedReply::client_handle_cmd_ = STC_Cmd_ptr( new SClientHandleCmd() );
+STC_Cmd_ptr PreAllocatedReply::client_handle_suites_cmd_ = STC_Cmd_ptr( new SClientHandleSuitesCmd() );
+STC_Cmd_ptr PreAllocatedReply::string_cmd_ = STC_Cmd_ptr( new SStringCmd() );
+STC_Cmd_ptr PreAllocatedReply::string_vec_cmd_ = STC_Cmd_ptr( new SStringVecCmd() );
+STC_Cmd_ptr PreAllocatedReply::server_load_cmd_ = STC_Cmd_ptr( new SServerLoadCmd() );
+STC_Cmd_ptr PreAllocatedReply::news_cmd_ = STC_Cmd_ptr( new SNewsCmd() );
+STC_Cmd_ptr PreAllocatedReply::sync_cmd_ = STC_Cmd_ptr( new SSyncCmd() );
+
+STC_Cmd_ptr PreAllocatedReply::ok_cmd()
+{
+ StcCmd* cmd = dynamic_cast<StcCmd*>(stc_cmd_.get());
+ cmd->init(StcCmd::OK);
+ return stc_cmd_;
+}
+STC_Cmd_ptr PreAllocatedReply::block_client_server_halted_cmd()
+{
+ StcCmd* cmd = dynamic_cast<StcCmd*>(stc_cmd_.get());
+ cmd->init(StcCmd::BLOCK_CLIENT_SERVER_HALTED);
+ return stc_cmd_;
+}
+STC_Cmd_ptr PreAllocatedReply::block_client_on_home_server_cmd()
+{
+ StcCmd* cmd = dynamic_cast<StcCmd*>(stc_cmd_.get());
+ cmd->init(StcCmd::BLOCK_CLIENT_ON_HOME_SERVER);
+ return stc_cmd_;
+}
+STC_Cmd_ptr PreAllocatedReply::block_client_zombie_cmd()
+{
+ StcCmd* cmd = dynamic_cast<StcCmd*>(stc_cmd_.get());
+ cmd->init(StcCmd::BLOCK_CLIENT_ZOMBIE);
+ return stc_cmd_;
+}
+
+STC_Cmd_ptr PreAllocatedReply::defs_cmd(AbstractServer* as,bool save_edit_history)
+{
+ DefsCmd* cmd = dynamic_cast<DefsCmd*>(defs_cmd_.get());
+ cmd->init(as,save_edit_history);
+ return defs_cmd_;
+}
+
+STC_Cmd_ptr PreAllocatedReply::node_cmd(AbstractServer* as,node_ptr node)
+{
+ SNodeCmd* cmd = dynamic_cast<SNodeCmd*>(node_cmd_.get());
+ cmd->init(as,node);
+ return node_cmd_;
+}
+
+STC_Cmd_ptr PreAllocatedReply::stats_cmd(AbstractServer* as)
+{
+ SStatsCmd* cmd = dynamic_cast<SStatsCmd*>(stats_cmd_.get());
+ cmd->init(as);
+ return stats_cmd_;
+}
+
+STC_Cmd_ptr PreAllocatedReply::suites_cmd(AbstractServer* as)
+{
+ SSuitesCmd* cmd = dynamic_cast<SSuitesCmd*>(suites_cmd_.get());
+ cmd->init(as);
+ return suites_cmd_;
+}
+
+STC_Cmd_ptr PreAllocatedReply::zombie_get_cmd(AbstractServer* as)
+{
+ ZombieGetCmd* cmd = dynamic_cast<ZombieGetCmd*>(zombie_get_cmd_.get());
+ cmd->init(as);
+ return zombie_get_cmd_;
+}
+
+STC_Cmd_ptr PreAllocatedReply::error_cmd(const std::string& error_msg)
+{
+ ErrorCmd* cmd = dynamic_cast<ErrorCmd*>(error_cmd_.get());
+ cmd->init(error_msg);
+ return error_cmd_;
+}
+
+STC_Cmd_ptr PreAllocatedReply::client_handle_cmd(int handle)
+{
+ SClientHandleCmd* cmd = dynamic_cast<SClientHandleCmd*>(client_handle_cmd_.get());
+ cmd->init(handle);
+ return client_handle_cmd_;
+}
+
+STC_Cmd_ptr PreAllocatedReply::client_handle_suites_cmd(AbstractServer* as)
+{
+ SClientHandleSuitesCmd* cmd = dynamic_cast<SClientHandleSuitesCmd*>(client_handle_suites_cmd_.get());
+ cmd->init(as);
+ return client_handle_suites_cmd_;
+}
+
+STC_Cmd_ptr PreAllocatedReply::string_cmd(const std::string& any_string)
+{
+ SStringCmd* cmd = dynamic_cast<SStringCmd*>(string_cmd_.get());
+ cmd->init(any_string);
+ return string_cmd_;
+}
+
+STC_Cmd_ptr PreAllocatedReply::string_vec_cmd(const std::vector<std::string>& vec)
+{
+ SStringVecCmd* cmd = dynamic_cast<SStringVecCmd*>(string_vec_cmd_.get());
+ cmd->init(vec);
+ return string_vec_cmd_;
+}
+
+STC_Cmd_ptr PreAllocatedReply::server_load_cmd(const std::string& log_file_path)
+{
+ SServerLoadCmd* cmd = dynamic_cast<SServerLoadCmd*>(server_load_cmd_.get());
+ cmd->init(log_file_path);
+ return server_load_cmd_;
+}
+
+STC_Cmd_ptr PreAllocatedReply::news_cmd(unsigned int client_handle,
+ unsigned int client_state_change_no,
+ unsigned int client_modify_change_no,
+ AbstractServer* as)
+{
+ SNewsCmd* cmd = dynamic_cast<SNewsCmd*>(news_cmd_.get());
+ cmd->init(client_handle,client_state_change_no,client_modify_change_no,as);
+ return news_cmd_;
+}
+
+STC_Cmd_ptr PreAllocatedReply::sync_cmd(unsigned int client_handle,
+ unsigned int client_state_change_no,
+ unsigned int client_modify_change_no,
+ AbstractServer* as)
+{
+ SSyncCmd* cmd = dynamic_cast<SSyncCmd*>(sync_cmd_.get());
+ cmd->init(client_handle,client_state_change_no,client_modify_change_no,false,as);
+ return sync_cmd_;
+}
+
+STC_Cmd_ptr PreAllocatedReply::sync_full_cmd(unsigned int client_handle,AbstractServer* as)
+{
+ SSyncCmd* cmd = dynamic_cast<SSyncCmd*>(sync_cmd_.get()); // can reuse the same command
+ cmd->init(client_handle,0,0,true,as);
+ return sync_cmd_;
+}
+
+// ==============================================================================
+// Serialisation export
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "boost_archive.hpp"
+
+#include <boost/serialization/export.hpp> // explicit code for exports (place last) , needed for BOOST_CLASS_EXPORT
+BOOST_CLASS_EXPORT(DefsCmd)
+BOOST_CLASS_EXPORT(SNodeCmd)
+BOOST_CLASS_EXPORT(SStringCmd)
+BOOST_CLASS_EXPORT(SStringVecCmd)
+BOOST_CLASS_EXPORT(SServerLoadCmd)
+BOOST_CLASS_EXPORT(GroupSTCCmd)
+BOOST_CLASS_EXPORT(ErrorCmd)
+BOOST_CLASS_EXPORT(StcCmd)
+BOOST_CLASS_EXPORT(SSyncCmd)
+BOOST_CLASS_EXPORT(SNewsCmd)
+BOOST_CLASS_EXPORT(SStatsCmd)
+BOOST_CLASS_EXPORT(SSuitesCmd)
+BOOST_CLASS_EXPORT(SClientHandleCmd)
+BOOST_CLASS_EXPORT(SClientHandleSuitesCmd)
+BOOST_CLASS_EXPORT(ZombieGetCmd)
diff --git a/Base/src/stc/PreAllocatedReply.hpp b/Base/src/stc/PreAllocatedReply.hpp
new file mode 100644
index 0000000..b2df2c3
--- /dev/null
+++ b/Base/src/stc/PreAllocatedReply.hpp
@@ -0,0 +1,71 @@
+#ifndef PRE_ALLOCATED_REPLY_HPP_
+#define PRE_ALLOCATED_REPLY_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #22 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <string>
+#include <boost/noncopyable.hpp>
+#include "Cmd.hpp"
+#include "NodeFwd.hpp"
+class AbstractServer;
+
+// class PreAllocatedReply:
+// This class pre allocates the replies back to the client
+// This will help to reduce memory fragmentation.
+// Since the commands are re-used those commands with state,
+// should be cleared first
+class PreAllocatedReply : private boost::noncopyable {
+public:
+ static STC_Cmd_ptr ok_cmd();
+ static STC_Cmd_ptr block_client_server_halted_cmd();
+ static STC_Cmd_ptr block_client_on_home_server_cmd();
+ static STC_Cmd_ptr block_client_zombie_cmd();
+
+ static STC_Cmd_ptr defs_cmd(AbstractServer*, bool save_edit_history);
+ static STC_Cmd_ptr node_cmd(AbstractServer*,node_ptr);
+ static STC_Cmd_ptr stats_cmd(AbstractServer*);
+ static STC_Cmd_ptr suites_cmd(AbstractServer*);
+ static STC_Cmd_ptr zombie_get_cmd(AbstractServer*);
+ static STC_Cmd_ptr error_cmd(const std::string& error_msg);
+ static STC_Cmd_ptr client_handle_cmd(int handle);
+ static STC_Cmd_ptr client_handle_suites_cmd(AbstractServer*);
+ static STC_Cmd_ptr string_cmd(const std::string& any_string);
+ static STC_Cmd_ptr string_vec_cmd(const std::vector<std::string>&);
+ static STC_Cmd_ptr server_load_cmd(const std::string& any_string);
+ static STC_Cmd_ptr news_cmd(unsigned int client_handle,
+ unsigned int client_state_change_no,
+ unsigned int client_modify_change_no, AbstractServer* as);
+ static STC_Cmd_ptr sync_cmd(unsigned int client_handle,
+ unsigned int client_state_change_no,
+ unsigned int client_modify_change_no, AbstractServer* as);
+ static STC_Cmd_ptr sync_full_cmd(unsigned int client_handle,AbstractServer* as);
+private:
+
+ static STC_Cmd_ptr stc_cmd_;
+ static STC_Cmd_ptr defs_cmd_;
+ static STC_Cmd_ptr node_cmd_;
+ static STC_Cmd_ptr stats_cmd_;
+ static STC_Cmd_ptr suites_cmd_;
+ static STC_Cmd_ptr zombie_get_cmd_;
+ static STC_Cmd_ptr error_cmd_;
+ static STC_Cmd_ptr client_handle_cmd_;
+ static STC_Cmd_ptr client_handle_suites_cmd_;
+ static STC_Cmd_ptr string_cmd_;
+ static STC_Cmd_ptr string_vec_cmd_;
+ static STC_Cmd_ptr server_load_cmd_;
+ static STC_Cmd_ptr news_cmd_;
+ static STC_Cmd_ptr sync_cmd_;
+};
+
+#endif
diff --git a/Base/src/stc/SClientHandleCmd.cpp b/Base/src/stc/SClientHandleCmd.cpp
new file mode 100644
index 0000000..76a196c
--- /dev/null
+++ b/Base/src/stc/SClientHandleCmd.cpp
@@ -0,0 +1,34 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <iostream>
+#include "SClientHandleCmd.hpp"
+
+using namespace ecf;
+using namespace std;
+
+bool SClientHandleCmd::equals(ServerToClientCmd* rhs) const
+{
+ return (dynamic_cast<SClientHandleCmd*>(rhs)) ? ServerToClientCmd::equals(rhs) : false;
+}
+
+bool SClientHandleCmd::handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const
+{
+ if (debug) cout << " SClientHandleCmd::handle_server_response handle_ = " << handle_ << "\n";
+ server_reply.set_client_handle( handle_ );
+ return true;
+}
+
+std::ostream& operator<<(std::ostream& os, const SClientHandleCmd& c) { return c.print(os); }
diff --git a/Base/src/stc/SClientHandleCmd.hpp b/Base/src/stc/SClientHandleCmd.hpp
new file mode 100644
index 0000000..10ba403
--- /dev/null
+++ b/Base/src/stc/SClientHandleCmd.hpp
@@ -0,0 +1,42 @@
+#ifndef SCLIENT_HANDLE_CMD_HPP_
+#define SCLIENT_HANDLE_CMD_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include "ServerToClientCmd.hpp"
+
+class SClientHandleCmd : public ServerToClientCmd {
+public:
+ SClientHandleCmd(int handle) : handle_(handle) {}
+ SClientHandleCmd() : ServerToClientCmd() , handle_(0) {}
+
+ void init(int handle) { handle_ = handle; }
+ virtual std::ostream& print(std::ostream& os) const { return os << "cmd:SClientHandleCmd [ " << handle_ << " ]";}
+ virtual bool equals(ServerToClientCmd*) const;
+ virtual bool handle_server_response( ServerReply&, Cmd_ptr cts_cmd, bool debug ) const;
+
+private:
+ int handle_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< ServerToClientCmd >( *this );
+ ar & handle_;
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, const SClientHandleCmd&);
+
+#endif
diff --git a/Base/src/stc/SClientHandleSuitesCmd.cpp b/Base/src/stc/SClientHandleSuitesCmd.cpp
new file mode 100644
index 0000000..55c393e
--- /dev/null
+++ b/Base/src/stc/SClientHandleSuitesCmd.cpp
@@ -0,0 +1,118 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #12 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include "SClientHandleSuitesCmd.hpp"
+#include "AbstractServer.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "ClientSuiteMgr.hpp"
+#include "ClientToServerCmd.hpp"
+
+using namespace std;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+SClientHandleSuitesCmd::SClientHandleSuitesCmd(AbstractServer* as )
+{
+ init(as);
+}
+
+void SClientHandleSuitesCmd::init(AbstractServer* as)
+{
+ // This command can be re-used hence clear existing data members
+ users_.clear();
+ client_handles_.clear();
+
+ ClientSuiteMgr& client_suite_mgr = as->defs()->client_suite_mgr();
+ const std::vector<ecf::ClientSuites>& clientSuites = client_suite_mgr.clientSuites();
+
+ size_t client_suites_size = clientSuites.size();
+ client_handles_.reserve(client_suites_size);
+ for(size_t c = 0; c < client_suites_size; c++) {
+
+ // The handle suites are already ordered same as Defs suites
+ std::vector<std::string> suite_names;
+ clientSuites[c].suites( suite_names );
+
+ client_handles_.push_back( std::make_pair(clientSuites[c].handle(), suite_names) );
+
+ // Create user, and his list of handles
+ bool fnd_user = false;
+ for(size_t u = 0; u < users_.size(); u++) {
+ if (users_[u].first == clientSuites[c].user()) {
+ users_[u].second.push_back(clientSuites[c].handle());
+ fnd_user = true;
+ break;
+ }
+ }
+ if (!fnd_user) {
+ std::vector<unsigned int> handles; handles.push_back(clientSuites[c].handle());
+ users_.push_back( std::make_pair(clientSuites[c].user(),handles) );
+ }
+ }
+}
+
+bool SClientHandleSuitesCmd::equals(ServerToClientCmd* rhs) const
+{
+ SClientHandleSuitesCmd* the_rhs = dynamic_cast<SClientHandleSuitesCmd*>(rhs);
+ if (!the_rhs) return false;
+ return ServerToClientCmd::equals(rhs);
+}
+
+std::ostream& SClientHandleSuitesCmd::print(std::ostream& os) const
+{
+ os << "cmd:SClientHandleSuitesCmd ";
+ return os;
+}
+
+bool SClientHandleSuitesCmd::handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const
+{
+ if (debug) std::cout << " SClientHandleSuitesCmd::handle_server_response\n";
+
+ if (server_reply.cli() && !cts_cmd->group_cmd()) {
+ /// This Could be part of a group command, hence ONLY if NOT group command
+
+ // print out:
+ // user handle suites
+ // user1 1 s1 s2 s3
+ // 2 s1 s2
+ // user2 1 s1 s2 s3
+ // 2 s1 s2
+ for(size_t u = 0; u < users_.size(); u++) {
+ if (u == 0) {
+ cout << "\n";
+ cout << left << setw(10) << "User" << setw(6) << "handle" << " suites\n";
+ }
+ cout << left << setw(10) << users_[u].first;
+ for(size_t h = 0; h < users_[u].second.size(); h++) {
+ unsigned int handle = users_[u].second[h];
+ for( size_t c = 0; c < client_handles_.size(); c++) {
+ if (handle == client_handles_[c].first) {
+ if (h != 0) cout << " "; // 10 spaces to align handles
+ cout << right << setw(6) << handle << " ";
+ const std::vector<std::string>& suites = client_handles_[c].second;
+ for(size_t i = 0; i < suites.size(); i++) { cout << suites[i] << " "; }
+ cout << "\n";
+ }
+ }
+ }
+ }
+ }
+ else {
+ server_reply.set_client_handle_suites(client_handles_);
+ }
+ return true;
+}
+
+std::ostream& operator<<(std::ostream& os, const SClientHandleSuitesCmd& c) { return c.print(os); }
diff --git a/Base/src/stc/SClientHandleSuitesCmd.hpp b/Base/src/stc/SClientHandleSuitesCmd.hpp
new file mode 100644
index 0000000..c61a77d
--- /dev/null
+++ b/Base/src/stc/SClientHandleSuitesCmd.hpp
@@ -0,0 +1,47 @@
+#ifndef SCLIENT_HANDLE_SUITES_CMD_HPP_
+#define SCLIENT_HANDLE_SUITES_CMD_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "ServerToClientCmd.hpp"
+class AbstractServer;
+
+//================================================================================
+class SClientHandleSuitesCmd : public ServerToClientCmd {
+public:
+ SClientHandleSuitesCmd(AbstractServer* as );
+ SClientHandleSuitesCmd() : ServerToClientCmd() {}
+
+ void init(AbstractServer* as);
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ServerToClientCmd*) const;
+ virtual bool handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const;
+
+private:
+ std::vector<std::pair<std::string, std::vector<unsigned int> > > users_; // users , list of handles
+ std::vector<std::pair<unsigned int, std::vector<std::string> > > client_handles_; // handle, list of suites
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< ServerToClientCmd >( *this );
+ ar & users_;
+ ar & client_handles_;
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, const SClientHandleSuitesCmd&);
+
+#endif
diff --git a/Base/src/stc/SNewsCmd.cpp b/Base/src/stc/SNewsCmd.cpp
new file mode 100644
index 0000000..855a68f
--- /dev/null
+++ b/Base/src/stc/SNewsCmd.cpp
@@ -0,0 +1,262 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #31 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <iostream>
+#include "SNewsCmd.hpp"
+#include "Defs.hpp"
+#include "Ecf.hpp"
+#include "AbstractServer.hpp"
+#include "Log.hpp"
+
+using namespace std;
+using namespace ecf;
+
+/// Custom handling of command logging so that we can add additional debug.
+/// Rely's on CSyncCmd not adding newline when logging the command
+#define DEBUG_NEWS 1
+
+
+SNewsCmd::SNewsCmd( unsigned int client_handle,
+ unsigned int client_state_change_no,
+ unsigned int client_modify_change_no,
+ AbstractServer* as)
+: news_(ServerReply::NO_NEWS)
+{
+ init(client_handle,client_state_change_no,client_modify_change_no,as);
+}
+
+/// Called in the server
+void SNewsCmd::init(
+ unsigned int client_handle, // a reference to a set of suites used by client
+ unsigned int client_state_change_no,
+ unsigned int client_modify_change_no, AbstractServer* as)
+{
+ news_ = ServerReply::NO_NEWS;
+
+ // After ECFLOW-182 server will always have a defs, hence we should never return ServerReply::NO_DEFS
+ // However keep as an enum, to allow new client(ecflowview) deal with reply from old server
+ // defs_ptr server_defs = as->defs();
+ // if ( ! server_defs.get() ) {
+ //
+ // news_ = ServerReply::NO_DEFS;
+ //#if DEBUG_NEWS
+ // log_append(" [:NO_DEFS]");
+ //#else
+ // log_append("");
+ //#endif
+ // return;
+ // }
+
+
+ // =====================================================================================
+ // The code to determine changes here must also relate to SSyncCmd
+ // ======================================================================================
+
+ if (client_handle == 0) {
+
+ // Here Ecf::modify_change_no() and Ecf::state_change_no() represent the max change numbers over *all* the suites
+
+ /// *** The client_modify_change_no and client_state_change_no should always be trailing the server
+ /// *** i.e the value should be less or equal to server. However if::
+ /// *** o/ Server **dies** we can get the case, where client numbers are greater than server numbers.
+ /// *** o/ Server changes number overflows, since it unsigned, and re-start's with 0
+ /// *** When no handle are involved, we can get by with a full sync
+ /// *** Note: whenever the server starts, the state and modify numbers start from zero
+ if ( (client_modify_change_no > Ecf::modify_change_no()) || (client_state_change_no > Ecf::state_change_no())) {
+
+ news_ = ServerReply::DO_FULL_SYNC;
+
+#if DEBUG_NEWS
+ std::stringstream ss;
+ ss << " [server(" << Ecf::state_change_no() << "," << Ecf::modify_change_no() << ") : client no > server no ! :DO_FULL_SYNC]";
+ log_append(ss.str());
+#else
+ log_append("");
+#endif
+ return;
+ }
+
+ if ( client_modify_change_no < Ecf::modify_change_no()) {
+
+ news_ = ServerReply::NEWS;
+
+#if DEBUG_NEWS
+ std::stringstream ss;
+ ss << " [server(" << Ecf::state_change_no() << "," << Ecf::modify_change_no() << ") : *Large* scale changes :NEWS]";
+ log_append(ss.str());
+#else
+ log_append("");
+#endif
+ return;
+ }
+
+ if ( client_state_change_no < Ecf::state_change_no() ) {
+
+ news_ = ServerReply::NEWS;
+
+#if DEBUG_NEWS
+ std::stringstream ss;
+ ss << " [server(" << Ecf::state_change_no() << "," << Ecf::modify_change_no() << ") : *Small* scale changes :NEWS]";
+ log_append( ss.str());
+#else
+ log_append("");
+#endif
+ return;
+ }
+
+
+#if DEBUG_NEWS
+ log_append(" [:NO_NEWS]");
+#else
+ log_append("");
+#endif
+ return;
+ }
+
+ // =============================================================================================
+ // Handle used: Determine the max modify and state change no, for suites in our handle
+ // =============================================================================================
+
+ /// *** If we can't find the handle, then it may be that the server died ?
+ /// *** It is up to the client to do a full sync *including* re-registering suites
+ ClientSuiteMgr& client_suite_mgr = as->defs()->client_suite_mgr();
+ if ( ! client_suite_mgr.valid_handle(client_handle)) {
+
+ news_ = ServerReply::DO_FULL_SYNC;
+
+#if DEBUG_NEWS
+ std::stringstream ss;
+ ss << " [server(" << Ecf::state_change_no() << "," << Ecf::modify_change_no() << ") : Can not find handle(" << client_handle << ") :DO_FULL_SYNC]";
+ log_append(ss.str());
+#else
+ log_append("");
+#endif
+
+ return;
+ }
+
+ /// *** The client_modify_change_no and client_state_change_no should always be trailing the server
+ /// *** i.e the value should be less or equal to server. However if
+ /// *** o/ Server **dies** we can get the case, where client numbers are greater than server numbers.
+ /// *** o/ Server changes number overflows, since it unsigned, and re-start's with 0
+ /// *** we can get the case, where client numbers are greater than server numbers and also the
+ /// *** handle will not exist in the server,
+ /// *** It is up to the client to do a full sync *including* re-registering suites
+ /// *** Note: whenever the server starts, the state and modify numbers start from zero
+ unsigned int max_client_handle_modify_change_no = 0;
+ unsigned int max_client_handle_state_change_no = 0;
+ client_suite_mgr.max_change_no( client_handle,max_client_handle_state_change_no,max_client_handle_modify_change_no);
+
+ if ((client_modify_change_no > max_client_handle_modify_change_no) || (client_state_change_no > max_client_handle_state_change_no)) {
+
+ news_ = ServerReply::DO_FULL_SYNC;
+
+#if DEBUG_NEWS
+ std::stringstream ss;
+ ss << " [server handle(" << max_client_handle_state_change_no << ","
+ << max_client_handle_modify_change_no << ") server(" << Ecf::state_change_no() << "," << Ecf::modify_change_no()
+ << ") : client no > server no ! :DO_FULL_SYNC]";
+ log_append(ss.str());
+#else
+ log_append("");
+#endif
+
+ return;
+ }
+
+ /// Changes where user adds a new handle/auto adds/removes require a full update, but only for changed handle
+ if (client_suite_mgr.handle_changed( client_handle )) {
+
+ news_ = ServerReply::NEWS;
+
+#if DEBUG_NEWS
+ std::stringstream ss;
+ ss << " [server handle(" << max_client_handle_state_change_no << ","
+ << max_client_handle_modify_change_no << ") server(" << Ecf::state_change_no() << "," << Ecf::modify_change_no()
+ << ") : *Large* scale changes (new handle or suites added or removed) :NEWS]";
+ log_append(ss.str());
+#else
+ log_append("");
+#endif
+
+ return;
+ }
+
+ // The client handle represents a subset of the suites.
+ if ( client_modify_change_no < max_client_handle_modify_change_no) {
+
+ news_ = ServerReply::NEWS;
+
+#if DEBUG_NEWS
+ std::stringstream ss;
+ ss << " [server handle(" << max_client_handle_state_change_no << ","
+ << max_client_handle_modify_change_no << ") server(" << Ecf::state_change_no() << "," << Ecf::modify_change_no()
+ << ") : *Large* scale changes :NEWS]";
+ log_append( ss.str());
+#else
+ log_append("");
+#endif
+
+ return;
+ }
+
+ // This should also reflect changes made just to the defs(state/suspended) and also the server state
+ if ( client_state_change_no < max_client_handle_state_change_no ) {
+
+ news_ = ServerReply::NEWS;
+
+#if DEBUG_NEWS
+ std::stringstream ss;
+ ss << " [server handle(" << max_client_handle_state_change_no << ","
+ << max_client_handle_modify_change_no << ") server(" << Ecf::state_change_no() << "," << Ecf::modify_change_no()
+ << ") : *Small* scale changes :NEWS]";
+ log_append(ss.str());
+#else
+ log_append("");
+#endif
+
+ return;
+ }
+
+#if DEBUG_NEWS
+ log_append(" [:NO_NEWS]");
+#else
+ log_append("");
+#endif
+}
+
+
+/// Called in the client
+bool SNewsCmd::handle_server_response( ServerReply& server_reply, Cmd_ptr /*cts_cmd*/, bool debug ) const
+{
+ if (debug) std::cout << " SNewsCmd::handle_server_response news_ = " << news_ << "\n";
+ server_reply.set_news( news_);
+ return true;
+}
+
+bool SNewsCmd::equals(ServerToClientCmd* rhs) const
+{
+ SNewsCmd* the_rhs = dynamic_cast<SNewsCmd*>(rhs);
+ if (!the_rhs) return false;
+ if (news_ != the_rhs->news()) return false;
+ return ServerToClientCmd::equals(rhs);
+}
+
+std::ostream& SNewsCmd::print(std::ostream& os) const
+{
+ os << "cmd:SNewsCmd [ " << news_ << " ] ";
+ return os;
+}
+
+std::ostream& operator<<(std::ostream& os, const SNewsCmd& c) { return c.print(os); }
diff --git a/Base/src/stc/SNewsCmd.hpp b/Base/src/stc/SNewsCmd.hpp
new file mode 100644
index 0000000..b60c5e7
--- /dev/null
+++ b/Base/src/stc/SNewsCmd.hpp
@@ -0,0 +1,63 @@
+#ifndef SNEWS_CMD_HPP_
+#define SNEWS_CMD_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #9 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : class SNewsCmd: Used to determine any change in the server
+//
+// The *client_state_change_no* was passed from the client to the server
+// The *client_modify_change_no* was passed from the client to the server
+//
+// The code here needs to coordinate with SSyncCmd
+//
+// Paired with CtsCmd(NEWS)
+// Client---CtsCmd(NEWS)---->Server-----(SNewsCmd)--->client:
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "ServerToClientCmd.hpp"
+
+class SNewsCmd : public ServerToClientCmd {
+public:
+ // The constructor is *called* in the server.
+ SNewsCmd(unsigned int client_handle, // a reference to a set of suites used by client
+ unsigned int client_state_change_no,
+ unsigned int client_modify_change_no,
+ AbstractServer* as);
+ SNewsCmd() : ServerToClientCmd(), news_(ServerReply::NO_NEWS) {}
+
+ void init(unsigned int client_handle, // a reference to a set of suites used by client
+ unsigned int client_state_change_no,
+ unsigned int client_modify_change_no,
+ AbstractServer* as);
+
+ ServerReply::News_t news() const { return news_;} // used by equals only
+ bool get_news() const { return ( news_ != ServerReply::NO_NEWS); }
+
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ServerToClientCmd*) const;
+ virtual bool handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const;
+
+private:
+ // After ECFLOW-182, ServerReply::NO_DEFS no longer used, however kept, to ensure client/server compatibility
+ // ie. for new client(viewer) must process this from old server, which could return NO_DEFS
+ ServerReply::News_t news_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< ServerToClientCmd >( *this );
+ ar & news_;
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, const SNewsCmd&);
+#endif
diff --git a/Base/src/stc/SNodeCmd.cpp b/Base/src/stc/SNodeCmd.cpp
new file mode 100644
index 0000000..403e772
--- /dev/null
+++ b/Base/src/stc/SNodeCmd.cpp
@@ -0,0 +1,144 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name : Cmd
+// Author : Avi
+// Revision : $Revision: #11 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <iostream>
+
+#include "SNodeCmd.hpp"
+#include "ClientToServerCmd.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "Alias.hpp"
+#include "AbstractServer.hpp"
+#include "PrintStyle.hpp"
+
+using namespace std;
+using namespace boost;
+
+//=====================================================================================
+// This command returns the requested node back to the client
+// Note: In the case where defs has not been loaded, it can be NULL
+
+SNodeCmd::SNodeCmd(AbstractServer* as,node_ptr node)
+{
+ init(as,node);
+}
+
+void SNodeCmd::init(AbstractServer* as, node_ptr node)
+{
+ suite_.reset();
+ family_.reset();
+ task_.reset();
+ alias_.reset();
+
+ if (node.get()) {
+ if (node->isSuite()) {
+ suite_ = boost::dynamic_pointer_cast<Suite>(node);
+ }
+ else if (node->isFamily()) {
+ family_ = boost::dynamic_pointer_cast<Family>(node);
+ }
+ else if (node->isTask()) {
+ task_ = boost::dynamic_pointer_cast<Task>(node);
+ }
+ else if (node->isAlias()) {
+ alias_ = boost::dynamic_pointer_cast<Alias>(node);
+ }
+ }
+}
+
+node_ptr SNodeCmd::get_node_ptr() const
+{
+ if (suite_.get()) {
+ return boost::dynamic_pointer_cast<Node>(suite_);
+ }
+ else if (family_.get()) {
+ return boost::dynamic_pointer_cast<Node>(family_);
+ }
+ else if (task_.get()) {
+ return boost::dynamic_pointer_cast<Node>(task_);
+ }
+ else if (alias_.get()) {
+ return boost::dynamic_pointer_cast<Node>(alias_);
+ }
+ return node_ptr();
+}
+
+bool SNodeCmd::equals(ServerToClientCmd* rhs) const
+{
+ SNodeCmd* the_rhs = dynamic_cast<SNodeCmd*>(rhs);
+ if (!the_rhs) return false;
+ if (!ServerToClientCmd::equals(rhs)) return false;
+ return true;
+}
+
+std::ostream& SNodeCmd::print(std::ostream& os) const
+{
+ os << "cmd:SNodeCmd [ ";
+ node_ptr node = get_node_ptr();
+ if (node.get()) os << node->absNodePath();
+ else os << "node == NULL";
+ os << " ]";
+ return os;
+}
+
+// Called in client
+bool SNodeCmd::handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const
+{
+ if (debug) std::cout << " SNodeCmd::handle_server_response\n";
+
+ node_ptr node = get_node_ptr();
+ if ( !node.get() ) {
+ std::stringstream ss;
+ ss << "SNodeCmd::handle_server_response: Error Node could not be retrieved from server. Request "; cts_cmd->print(ss); ss << " failed.\n";
+ throw std::runtime_error(ss.str());
+ }
+
+
+ if (server_reply.cli() && !cts_cmd->group_cmd()) {
+ /// This Could be part of a group command, hence ONLY show Node if NOT group command
+ PrintStyle style(cts_cmd->show_style());
+
+ Suite* suite = node->isSuite();
+ if (suite) {
+ if (cts_cmd->show_style() != PrintStyle::MIGRATE) {
+ /// Auto generate externs, before writing to standard out. This can be expensive since
+ /// All the trigger references need to to be resolved. & AST need to be created first
+ /// The old spirit based parsing, horrendously, slow. Can't use Spirit QI, till IBM pull support it
+ ///
+ /// We need a fabricate a defs to show the externs, used by the suite
+ Defs defs;
+ defs.addSuite(boost::dynamic_pointer_cast<Suite>( node ));
+ defs.auto_add_externs();
+ std::cout << defs;
+ return true;
+ }
+ std::cout << *suite << "\n";
+ return true;
+ }
+ Family* fam = node->isFamily();
+ if (fam) std::cout << *fam << "\n";
+ Task* task = node->isTask();
+ if (task) std::cout << *task << "\n";
+ Alias* alias = node->isAlias();
+ if (alias) std::cout << *alias << "\n";
+ }
+ else {
+ server_reply.set_client_node( node );
+ }
+ return true;
+}
+
+std::ostream& operator<<(std::ostream& os, const SNodeCmd& c) { return c.print(os); }
diff --git a/Base/src/stc/SNodeCmd.hpp b/Base/src/stc/SNodeCmd.hpp
new file mode 100644
index 0000000..b96a6f9
--- /dev/null
+++ b/Base/src/stc/SNodeCmd.hpp
@@ -0,0 +1,58 @@
+#ifndef SNODE_CMD_HPP_
+#define SNODE_CMD_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "ServerToClientCmd.hpp"
+class AbstractServer;
+
+//================================================================================
+// Paired with CtsNodeCmd(Get)
+// Client---CtsNodeCmd(GET)---->Server-----(SNodeCmd | SNodeCmd)--->client:
+//================================================================================
+class SNodeCmd : public ServerToClientCmd {
+public:
+ SNodeCmd(AbstractServer* as,node_ptr node);
+ SNodeCmd() {}
+
+ void init(AbstractServer* as, node_ptr node);
+
+ virtual bool handle_server_response( ServerReply&, Cmd_ptr cts_cmd, bool debug ) const;
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ServerToClientCmd*) const;
+ virtual bool hasNode() const { return true; } /// used by group command
+
+private:
+ node_ptr get_node_ptr() const;
+
+ suite_ptr suite_;
+ family_ptr family_;
+ task_ptr task_;
+ alias_ptr alias_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< ServerToClientCmd >( *this );
+ ar & suite_;
+ ar & family_;
+ ar & task_;
+ ar & alias_;
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, const SNodeCmd&);
+
+#endif
diff --git a/Base/src/stc/SServerLoadCmd.cpp b/Base/src/stc/SServerLoadCmd.cpp
new file mode 100644
index 0000000..41743a0
--- /dev/null
+++ b/Base/src/stc/SServerLoadCmd.cpp
@@ -0,0 +1,46 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <iostream>
+#include "SServerLoadCmd.hpp"
+#include "Gnuplot.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+
+bool SServerLoadCmd::equals(ServerToClientCmd* rhs) const
+{
+ SServerLoadCmd* the_rhs = dynamic_cast<SServerLoadCmd*>(rhs);
+ if (!the_rhs) return false;
+ if (log_file_path_ != the_rhs->log_file_path()) return false;
+ return ServerToClientCmd::equals(rhs);
+}
+
+std::ostream& SServerLoadCmd::print(std::ostream& os) const
+{
+ os << "cmd:SServerLoadCmd [ " << log_file_path_ << " ]";
+ return os;
+}
+
+bool SServerLoadCmd::handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const
+{
+ if (debug) cout << " SServerLoadCmd::handle_server_response log_file_path = " << log_file_path() << "\n";
+ Gnuplot gnuplot(log_file_path(), server_reply.host(), server_reply.port());
+ gnuplot.show_server_load();
+ return true;
+}
+
+std::ostream& operator<<(std::ostream& os, const SServerLoadCmd& c) { return c.print(os); }
diff --git a/Base/src/stc/SServerLoadCmd.hpp b/Base/src/stc/SServerLoadCmd.hpp
new file mode 100644
index 0000000..b264211
--- /dev/null
+++ b/Base/src/stc/SServerLoadCmd.hpp
@@ -0,0 +1,48 @@
+#ifndef SSERVER_LOAD_CMD_HPP_
+#define SSERVER_LOAD_CMD_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "ServerToClientCmd.hpp"
+
+///================================================================================
+/// Paired with CtsCmd::SERVER_LOAD
+/// Client---(CtsCmd::SERVER_LOAD)---->Server-----(SServerLoadCmd)--->client:
+///================================================================================
+class SServerLoadCmd : public ServerToClientCmd {
+public:
+ SServerLoadCmd(const std::string& log_file_path) : log_file_path_(log_file_path) {}
+ SServerLoadCmd() : ServerToClientCmd() {}
+
+ void init(const std::string& s) { log_file_path_ = s;}
+ const std::string& log_file_path() const { return log_file_path_; }
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ServerToClientCmd*) const;
+ virtual bool handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const;
+
+private:
+ std::string log_file_path_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< ServerToClientCmd >( *this );
+ ar & log_file_path_;
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, const SServerLoadCmd&);
+
+#endif
diff --git a/Base/src/stc/SStatsCmd.cpp b/Base/src/stc/SStatsCmd.cpp
new file mode 100644
index 0000000..fd5c99b
--- /dev/null
+++ b/Base/src/stc/SStatsCmd.cpp
@@ -0,0 +1,57 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #11 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "SStatsCmd.hpp"
+#include "AbstractServer.hpp"
+#include "Defs.hpp"
+
+using namespace std;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+SStatsCmd::SStatsCmd(AbstractServer* as )
+{
+ init(as);
+}
+
+void SStatsCmd::init(AbstractServer* as)
+{
+ as->stats().update_for_serialisation();
+ stats_ = as->stats();
+ stats_.no_of_suites_ = as->defs()->suiteVec().size();
+}
+
+bool SStatsCmd::equals(ServerToClientCmd* rhs) const
+{
+ SStatsCmd* the_rhs = dynamic_cast<SStatsCmd*>(rhs);
+ if (!the_rhs) return false;
+ return ServerToClientCmd::equals(rhs);
+}
+
+std::ostream& SStatsCmd::print(std::ostream& os) const
+{
+ os << "cmd:SStatsCmd ";
+ return os;
+}
+
+bool SStatsCmd::handle_server_response( ServerReply& server_reply, Cmd_ptr /*cts_cmd*/, bool debug ) const
+{
+ if (debug) std::cout << " SStatsCmd::handle_server_response\n";
+ if (server_reply.cli()) stats_.show();
+ else server_reply.set_stats( stats_ );
+ return true;
+}
+
+std::ostream& operator<<(std::ostream& os, const SStatsCmd& c) { return c.print(os); }
diff --git a/Base/src/stc/SStatsCmd.hpp b/Base/src/stc/SStatsCmd.hpp
new file mode 100644
index 0000000..6818e9b
--- /dev/null
+++ b/Base/src/stc/SStatsCmd.hpp
@@ -0,0 +1,50 @@
+#ifndef SSTATS_CMD_HPP_
+#define SSTATS_CMD_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #8 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "ServerToClientCmd.hpp"
+#include "Stats.hpp"
+class AbstractServer;
+
+//================================================================================
+// Paired with CtsCmd(STATS)
+// Client---(CtsCmd(STATS))---->Server-----(SStatsCmd)--->client:
+//================================================================================
+class SStatsCmd : public ServerToClientCmd {
+public:
+ SStatsCmd(AbstractServer* as );
+ SStatsCmd() : ServerToClientCmd() {}
+
+ void init(AbstractServer* as);
+
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ServerToClientCmd*) const;
+ virtual bool handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const;
+
+private:
+ Stats stats_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< ServerToClientCmd >( *this );
+ ar & stats_;
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, const SStatsCmd&);
+
+#endif
diff --git a/Base/src/stc/SStringCmd.cpp b/Base/src/stc/SStringCmd.cpp
new file mode 100644
index 0000000..785bdc1
--- /dev/null
+++ b/Base/src/stc/SStringCmd.cpp
@@ -0,0 +1,46 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <iostream>
+#include "SStringCmd.hpp"
+
+using namespace std;
+using namespace boost;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool SStringCmd::equals(ServerToClientCmd* rhs) const
+{
+ SStringCmd* the_rhs = dynamic_cast<SStringCmd*>(rhs);
+ if (!the_rhs) return false;
+ if (str_ != the_rhs->get_string()) return false;
+ return ServerToClientCmd::equals(rhs);
+}
+
+std::ostream& SStringCmd::print(std::ostream& os) const
+{
+ os << "cmd:SStringCmd ";
+ return os;
+}
+
+bool SStringCmd::handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const
+{
+ if (debug) cout << " SStringCmd::handle_server_response str.size()= " << str_.size() << "\n";
+ if (server_reply.cli()) std::cout << str_ << "\n";
+ else server_reply.set_string( str_ );
+ return true;
+}
+
+std::ostream& operator<<(std::ostream& os, const SStringCmd& c) { return c.print(os); }
diff --git a/Base/src/stc/SStringCmd.hpp b/Base/src/stc/SStringCmd.hpp
new file mode 100644
index 0000000..852baa3
--- /dev/null
+++ b/Base/src/stc/SStringCmd.hpp
@@ -0,0 +1,54 @@
+#ifndef SSTRING_CMD_HPP_
+#define SSTRING_CMD_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "ServerToClientCmd.hpp"
+
+///================================================================================
+/// Paired with CFileCmd
+/// Client---(CFileCmd)---->Server-----(SStringCmd)--->client:
+/// Only valid when the clients request a CFileCmd *OR* Log file
+/// Other times this will be empty.
+/// CFileCmd:: The file Contents(script,job,jobout,manual)
+/// Can be potentially very large
+/// LogCmd: The log file Can be potentially very large
+/// Only really valid if the out bound request was a LogCmd(LogCmd::GET)
+///================================================================================
+class SStringCmd : public ServerToClientCmd {
+public:
+ SStringCmd(const std::string& s) : str_(s) {}
+ SStringCmd() : ServerToClientCmd() {}
+
+ void init(const std::string& s) { str_ = s;}
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ServerToClientCmd*) const;
+ virtual const std::string& get_string() const { return str_;} // used by group command
+ virtual bool handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const;
+
+private:
+ std::string str_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< ServerToClientCmd >( *this );
+ ar & str_;
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, const SStringCmd&);
+
+#endif
diff --git a/Base/src/stc/SStringVecCmd.cpp b/Base/src/stc/SStringVecCmd.cpp
new file mode 100644
index 0000000..2471b11
--- /dev/null
+++ b/Base/src/stc/SStringVecCmd.cpp
@@ -0,0 +1,50 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <iostream>
+#include "SStringVecCmd.hpp"
+
+using namespace std;
+using namespace boost;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool SStringVecCmd::equals(ServerToClientCmd* rhs) const
+{
+ SStringVecCmd* the_rhs = dynamic_cast<SStringVecCmd*>(rhs);
+ if (!the_rhs) return false;
+ if (vec_ != the_rhs->get_string_vec()) return false;
+ return ServerToClientCmd::equals(rhs);
+}
+
+std::ostream& SStringVecCmd::print(std::ostream& os) const
+{
+ os << "cmd:SStringVecCmd ";
+ return os;
+}
+
+bool SStringVecCmd::handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const
+{
+ if (debug) cout << " SStringVecCmd::handle_server_response str.size()= " << vec_.size() << "\n";
+ if (server_reply.cli()) {
+ for(size_t i = 0; i < vec_.size(); i++) {
+ std::cout << vec_[i] << "\n";
+ }
+ }
+ else server_reply.set_string_vec( vec_ );
+ return true;
+}
+
+std::ostream& operator<<(std::ostream& os, const SStringVecCmd& c) { return c.print(os); }
diff --git a/Base/src/stc/SStringVecCmd.hpp b/Base/src/stc/SStringVecCmd.hpp
new file mode 100644
index 0000000..b33963f
--- /dev/null
+++ b/Base/src/stc/SStringVecCmd.hpp
@@ -0,0 +1,46 @@
+#ifndef SSTRING_VEC_CMD_HPP_
+#define SSTRING_VEC_CMD_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "ServerToClientCmd.hpp"
+
+///================================================================================
+class SStringVecCmd : public ServerToClientCmd {
+public:
+ SStringVecCmd(const std::vector<std::string>& s) : vec_(s) {}
+ SStringVecCmd() : ServerToClientCmd() {}
+
+ void init(const std::vector<std::string>& s) { vec_ = s;}
+ const std::vector<std::string>& get_string_vec() const { return vec_;}
+
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ServerToClientCmd*) const;
+ virtual bool handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const;
+
+private:
+ std::vector<std::string> vec_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< ServerToClientCmd >( *this );
+ ar & vec_;
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, const SStringVecCmd&);
+
+#endif
diff --git a/Base/src/stc/SSuitesCmd.cpp b/Base/src/stc/SSuitesCmd.cpp
new file mode 100644
index 0000000..c12f8c7
--- /dev/null
+++ b/Base/src/stc/SSuitesCmd.cpp
@@ -0,0 +1,86 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #13 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "SSuitesCmd.hpp"
+#include "AbstractServer.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "ClientSuiteMgr.hpp"
+#include "ClientToServerCmd.hpp"
+
+using namespace std;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+SSuitesCmd::SSuitesCmd(AbstractServer* as )
+{
+ init(as);
+}
+
+void SSuitesCmd::init(AbstractServer* as)
+{
+ // This command can be re-used hence clear existing data members
+ suites_.clear();
+
+ const std::vector<suite_ptr>& suiteVec = as->defs()->suiteVec();
+ size_t suite_vec_size = suiteVec.size();
+ suites_.reserve(suite_vec_size);
+ for(size_t i = 0; i < suite_vec_size; i++) {
+ suites_.push_back( suiteVec[i]->name() );
+ }
+}
+
+bool SSuitesCmd::equals(ServerToClientCmd* rhs) const
+{
+ SSuitesCmd* the_rhs = dynamic_cast<SSuitesCmd*>(rhs);
+ if (!the_rhs) return false;
+ return ServerToClientCmd::equals(rhs);
+}
+
+std::ostream& SSuitesCmd::print(std::ostream& os) const
+{
+ os << "cmd:SSuitesCmd ";
+ return os;
+}
+
+bool SSuitesCmd::handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const
+{
+ if (debug) std::cout << " SSuitesCmd::handle_server_response\n";
+
+ if (server_reply.cli() && !cts_cmd->group_cmd()) {
+ /// This Could be part of a group command, hence ONLY if NOT group command
+
+ if (suites_.empty()) {
+ cout << "No suites\n";
+ }
+
+ int newline_at = 4;
+ size_t the_size = suites_.size();
+ for(size_t i = 0; i < the_size; i++) {
+ cout << left << setw(20) << suites_[i];
+ if (i != 0 && (i % newline_at) == 0) {
+ cout << "\n";
+ newline_at += 5;
+ }
+ }
+ cout << "\n";
+ }
+ else {
+ server_reply.set_string_vec(suites_);
+ }
+ return true;
+}
+
+std::ostream& operator<<(std::ostream& os, const SSuitesCmd& c) { return c.print(os); }
diff --git a/Base/src/stc/SSuitesCmd.hpp b/Base/src/stc/SSuitesCmd.hpp
new file mode 100644
index 0000000..edf72e2
--- /dev/null
+++ b/Base/src/stc/SSuitesCmd.hpp
@@ -0,0 +1,48 @@
+#ifndef SSUITES_CMD_HPP_
+#define SSUITES_CMD_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #8 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "ServerToClientCmd.hpp"
+class AbstractServer;
+
+//================================================================================
+// Paired with CtsCmd(SUITES)
+// Client---(CtsCmd(SUITES))---->Server-----(SSuitesCmd)--->client:
+//================================================================================
+class SSuitesCmd : public ServerToClientCmd {
+public:
+ SSuitesCmd(AbstractServer* as );
+ SSuitesCmd() : ServerToClientCmd() {}
+
+ void init(AbstractServer* as);
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ServerToClientCmd*) const;
+ virtual bool handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const;
+
+private:
+ std::vector<std::string> suites_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< ServerToClientCmd >( *this );
+ ar & suites_;
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, const SSuitesCmd&);
+
+#endif
diff --git a/Base/src/stc/SSyncCmd.cpp b/Base/src/stc/SSyncCmd.cpp
new file mode 100644
index 0000000..96ee05d
--- /dev/null
+++ b/Base/src/stc/SSyncCmd.cpp
@@ -0,0 +1,466 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #55 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <iostream>
+
+#include "SSyncCmd.hpp"
+#include "Defs.hpp"
+#include "Ecf.hpp"
+#include "Log.hpp"
+#include "AbstractServer.hpp"
+#include "boost_archive.hpp" // collates boost archive includes
+
+using namespace std;
+using namespace boost;
+
+// =====================================================================================================
+//#define DEBUG_SERVER_SYNC 1
+//#define DEBUG_CLIENT_SYNC 1
+
+// ===========================================================================================
+// CACHE: the deserialization costs, so that if multiple clients request the full defs
+// we can improve the performance, by only performing that once for each state change.
+std::string FullServerDefsCache::full_server_defs_as_string_ = "";
+unsigned int FullServerDefsCache::state_change_no_ = 0;
+unsigned int FullServerDefsCache::modify_change_no_= 0;
+
+void FullServerDefsCache::update_cache_if_state_changed(defs_ptr defs)
+{
+ // See if there was a state change *OR* if cache is empty
+ if (state_change_no_ != Ecf::state_change_no() ||
+ modify_change_no_ != Ecf::modify_change_no() ||
+ full_server_defs_as_string_.empty()
+ )
+ {
+ try {
+#ifdef DEBUG_SERVER_SYNC
+ cout << ": *updating* cache";
+#endif
+ // Update cache
+ std::ostringstream archive_stream;
+
+#if defined(BINARY_ARCHIVE)
+ boost::archive::binary_oarchive archive( archive_stream );
+ archive << defs;
+ full_server_defs_as_string_ = archive_stream.str();
+ // std::cout << "async_write BINARY " << outbound_data_ << "\n";
+
+#elif defined(PORTABLE_BINARY_ARCHIVE)
+ portable_binary_oarchive archive( archive_stream );
+ archive << defs;
+ full_server_defs_as_string_ = archive_stream.str();
+ // std::cout << "async_write PORTABLE_BINARY " << outbound_data_ << "\n";
+
+#elif defined(EOS_PORTABLE_BINARY_ARCHIVE)
+ eos::portable_oarchive archive( archive_stream );
+ archive << defs;
+ full_server_defs_as_string_ = archive_stream.str();
+ // std::cout << "async_write EOS_PORTABLE_BINARY " << outbound_data_ << "\n";
+#else
+ boost::archive::text_oarchive archive( archive_stream );
+ archive << defs;
+ full_server_defs_as_string_ = archive_stream.str();
+ // std::cout << "async_write TEXT " << outbound_data_ << "\n";
+#endif
+ }
+ catch (const boost::archive::archive_exception& ae ) {
+ // Unable to decode data. Something went wrong, inform the caller.
+ ecf::LogToCout logToCout;
+ LOG(ecf::Log::ERR,"FullServerDefsCache::update_cache_if_state_changed boost::archive::archive_exception " << ae.what());
+ throw;
+ }
+
+ state_change_no_ = Ecf::state_change_no();
+ modify_change_no_ = Ecf::modify_change_no();
+ }
+#ifdef DEBUG_SERVER_SYNC
+ else {
+ cout << ": *cache* up to date";
+ }
+#endif
+}
+
+defs_ptr FullServerDefsCache::restore_defs_from_string(const std::string& archive_data)
+{
+#ifdef DEBUG_CLIENT_SYNC
+ cout << ": FullServerDefsCache::restore_defs_from_string: archive_data.size(" << archive_data.size() << ")";
+#endif
+ defs_ptr defs;
+ try {
+ std::istringstream archive_stream(archive_data);
+
+#if defined(BINARY_ARCHIVE)
+ // std::cout << "handle_read_data Archive BINARY\n";
+ boost::archive::binary_iarchive archive( archive_stream );
+ archive >> defs;
+
+#elif defined(PORTABLE_BINARY_ARCHIVE)
+ // std::cout << "handle_read_data Archive PORTABLE_BINARY\n";
+ portable_binary_iarchive archive( archive_stream );
+ archive >> defs;
+
+#elif defined(EOS_PORTABLE_BINARY_ARCHIVE)
+ // std::cout << "handle_read_data Archive EOS_PORTABLE_BINARY\n";
+ eos::portable_iarchive archive( archive_stream );
+ archive >> defs;
+
+#else
+ // std::cout << "handle_read_data Archive TEXT\n";
+ boost::archive::text_iarchive archive( archive_stream );
+ archive >> defs;
+#endif
+ } catch (const boost::archive::archive_exception& ae ) {
+ // Unable to decode data.
+ ecf::LogToCout logToCout;
+ LOG(ecf::Log::ERR,"FullServerDefsCache::restore_defs_from_string: boost::archive::archive_exception " << ae.what());
+ throw;
+ } catch (std::exception& e) {
+ // Unable to decode data.
+ ecf::LogToCout logToCout;
+ LOG(ecf::Log::ERR,"FullServerDefsCache::restore_defs_from_string " << e.what());
+ throw;
+ }
+
+#ifdef DEBUG_CLIENT_SYNC
+ if (defs.get()) cout << ": valid defs";
+ else cout << ": *empty* defs?";
+#endif
+ return defs;
+}
+
+defs_ptr FullServerDefsCache::restore_defs_from_string()
+{
+ // Used in Test when no client/server
+ return restore_defs_from_string(full_server_defs_as_string_);
+}
+
+
+SSyncCmd::SSyncCmd(
+ unsigned int client_handle,
+ unsigned int client_state_change_no,
+ unsigned int client_modify_change_no,
+ AbstractServer* as
+)
+: full_defs_(false),no_defs_(false),
+ incremental_changes_(client_state_change_no)
+{
+ init(client_handle, client_state_change_no, client_modify_change_no, false, as);
+}
+
+void SSyncCmd::reset_data_members(unsigned int client_state_change_no)
+{
+ full_defs_ = false;
+ no_defs_ = false;
+ incremental_changes_.init(client_state_change_no); // persisted, used for returning INCREMENTAL changes
+ server_defs_ = defs_ptr(); // persisted, used for returning FULL definition
+ full_server_defs_as_string_.clear(); // semi-persisted, i.e on load & not on saving
+}
+
+void SSyncCmd::init(
+ unsigned int client_handle, // a reference to a set of suites used by client
+ unsigned int client_state_change_no,
+ unsigned int client_modify_change_no,
+ bool do_full_sync,
+ AbstractServer* as
+)
+{
+ // ********************************************************
+ // This is called in the server
+ // ********************************************************
+#ifdef DEBUG_SERVER_SYNC
+ cout << "SSyncCmd::init: client(" << client_state_change_no << "," << client_modify_change_no << ") server(" << Ecf::state_change_no() << "," << Ecf::modify_change_no() << ")";
+#endif
+
+ // Reset all data members since this command can be re-used
+ reset_data_members(client_state_change_no);
+
+ // After ECFLOW-182 server will always have a defs, hence we should never return ServerReply::NO_DEFS
+ // We have kept no_defs_ to allow compatibility. To allow new client(ecflowview) deal with reply from old server
+ // Hence from release >= 4.0.7 no_defs_ will always be false
+ // if ( ! as->defs().get() ) {
+ //#ifdef DEBUG_SERVER_SYNC
+ // cout << ": *NO* defs\n";
+ //#endif
+ // no_defs_ = true;
+ // return;
+ // }
+
+ // explicit request
+ if (do_full_sync) {
+#ifdef DEBUG_SERVER_SYNC
+ cout << ": *Flag do_full_sync set* ";
+#endif
+ full_sync(client_handle,as);
+ return;
+ }
+
+ if (client_handle == 0) {
+#ifdef DEBUG_SERVER_SYNC
+ cout << ": No *handle* ";
+#endif
+
+ /// *** The client_modify_change_no and client_state_change_no should always be trailing the server
+ /// *** i.e the value should be less or equal to server. However if the server **dies** we can
+ /// *** get the case, where client numbers are greater than server numbers.
+ /// *** When no handle are involved, we get by with a full sync
+ /// *** Note: whenever the server starts, the state and modify numbers start from zero
+ if ( client_modify_change_no > Ecf::modify_change_no() || client_state_change_no > Ecf::state_change_no()) {
+#ifdef DEBUG_SERVER_SYNC
+ cout << ": client modify no > server modify no: Server died/restored? ";
+#endif
+ full_sync(client_handle,as);
+ return;
+ }
+
+ if ( client_modify_change_no < Ecf::modify_change_no()) {
+#ifdef DEBUG_SERVER_SYNC
+ cout << ": *Large* scale changes: modify numbers not in sync ";
+#endif
+ full_sync(client_handle,as);
+ return;
+ }
+
+ // small scale changes. Collate changes over *defs* and all suites.
+ // Suite stores the maximum state change, over *all* its children, this is used by client handle mechanism
+ // and here to avoid traversing down the hierarchy.
+ // ******** We must trap all child changes under the suite. See class SuiteChanged
+ // ******** otherwise some attribute sync's will be missed
+ as->defs()->collateChanges(client_handle,incremental_changes_);
+ incremental_changes_.set_server_state_change_no(Ecf::state_change_no());
+ incremental_changes_.set_server_modify_change_no(Ecf::modify_change_no());
+#ifdef DEBUG_SERVER_SYNC
+ if (incremental_changes_.size()) cout << ":*small* scale changes: no of changes(" << incremental_changes_.size() << ")\n";
+ else cout << ": *No changes*\n";
+#endif
+ return;
+ }
+
+
+ //==========================================================================================
+ // Handle used
+ //==========================================================================================
+ ClientSuiteMgr& client_suite_mgr = as->defs()->client_suite_mgr();
+#ifdef DEBUG_SERVER_SYNC
+ cout << ": *handle* used " << client_handle << " : ";
+ std::vector<string> suites; client_suite_mgr.suites(client_handle,suites);
+ BOOST_FOREACH(const std::string& name, suites) { std::cout << name << " "; }
+#endif
+
+ /// *** The client_modify_change_no and client_state_change_no should always be trailing the server
+ /// *** i.e the value should be less or equal to server. However if the server **dies** we can
+ /// *** get the case, where client numbers are greater than server numbers. In this case we do a full sync
+ /// *** It is up to the client to catch the exception. and do a full sync *including* re-registering suites
+ /// *** Note: whenever the server starts, the state and modify numbers start from zero
+ unsigned int max_client_handle_modify_change_no = 0;
+ unsigned int max_client_handle_state_change_no = 0;
+ client_suite_mgr.max_change_no( client_handle, max_client_handle_state_change_no,max_client_handle_modify_change_no);
+#ifdef DEBUG_SERVER_SYNC
+ cout << ": server_handle(" << max_client_handle_state_change_no << "," << max_client_handle_modify_change_no << ")";
+#endif
+
+
+ if (client_modify_change_no > max_client_handle_modify_change_no || client_state_change_no > max_client_handle_state_change_no) {
+#ifdef DEBUG_SERVER_SYNC
+ cout << ": client no > server no: Server died/restored?";
+#endif
+ full_sync(client_handle,as);
+ return;
+ }
+
+ if ( client_modify_change_no < max_client_handle_modify_change_no) {
+#ifdef DEBUG_SERVER_SYNC
+ cout << ": *Large* scale changes : modify numbers not in sync";
+#endif
+ full_sync(client_handle,as);
+ return;
+ }
+
+ if (client_suite_mgr.handle_changed( client_handle )) {
+ // *Large* scale handle changes, i.e. created handle/ added or removed suites
+#ifdef DEBUG_SERVER_SYNC
+ cout << ": *Large* scale changes: added/removed suites to handle";
+#endif
+ full_sync(client_handle,as);
+ return;
+ }
+
+ // small scale changes
+ as->defs()->collateChanges(client_handle,incremental_changes_);
+ incremental_changes_.set_server_state_change_no(max_client_handle_state_change_no);
+ incremental_changes_.set_server_modify_change_no(max_client_handle_modify_change_no);
+#ifdef DEBUG_SERVER_SYNC
+ if (incremental_changes_.size()) cout << ": *small* scale changes: no of changes(" << incremental_changes_.size() << ")\n";
+ else cout << ": *No changes*\n";
+#endif
+}
+
+
+void SSyncCmd::full_sync(unsigned int client_handle, AbstractServer* as)
+{
+ if ( 0 == client_handle ) {
+ // Have already checked for no defs.
+ as->defs()->set_state_change_no( Ecf::state_change_no() );
+ as->defs()->set_modify_change_no( Ecf::modify_change_no() );
+
+ FullServerDefsCache::update_cache_if_state_changed(as->defs());
+ full_defs_ = true;
+#ifdef DEBUG_SERVER_SYNC
+ cout << ": *no handle* returning FULL defs(*cached* string, size(" << FullServerDefsCache::full_server_defs_as_string_.size() << "))" << endl;
+#endif
+ return;
+ }
+
+
+#ifdef DEBUG_SERVER_SYNC
+ cout << ": returning handle based FULL defs";
+#endif
+ // Only return the defs state and suites that the client has registered in the client handle
+ // *HOWEVER* if the client has registered *ALL* the suites, just return the server defs
+ // *with* the updated change numbers
+ //
+ // *OTHERWISE* this compute the **maximum** state and modify change numbers over
+ // the suites managed by the client handle and then set it on the newly created defs file.
+ // **** It also takes special precaution *NOT* to change Ecf::state_change_no() and Ecf::modify_change_no()
+ // **** so that we avoid changing max modify no for suites not in our handle
+ // **** Will clear the handle_changed flag
+ //
+ // **** Although we create a new defs, we use the same suites. This presents
+ // **** a problem with the suites defs() pointer. To avoid corrupting the server defs
+ // **** we set the suite defs ptr to the the real server defs.
+ // **** --> The defs serialisation will setup the suite defs pointers. <---
+ // **** An alternative would be to clone the entire suites, since this can have
+ // **** hundreds of tasks. It would be very expensive.
+ // **** This means that server_defs_ will fail invarint_checking before serialisation
+ defs_ptr the_server_defs = as->defs()->client_suite_mgr().create_defs( client_handle, as->defs() );
+ if ( the_server_defs.get() == as->defs().get()) {
+ FullServerDefsCache::update_cache_if_state_changed(as->defs());
+ full_defs_ = true;
+#ifdef DEBUG_SERVER_SYNC
+ cout << ": The handle has *ALL* the suites: return the FULL defs(*cached* string, size(" << FullServerDefsCache::full_server_defs_as_string_.size() << "))";
+#endif
+ }
+ else {
+ server_defs_ = the_server_defs;
+ }
+
+#ifdef DEBUG_SERVER_SYNC
+ if (server_defs_) cout << ": no of suites(" << server_defs_->suiteVec().size() << ")" << endl;
+ else cout << ": NULL defs!" << endl;
+#endif
+}
+
+bool SSyncCmd::equals(ServerToClientCmd* rhs) const
+{
+ SSyncCmd* the_rhs = dynamic_cast<SSyncCmd*>(rhs);
+ if (!the_rhs) return false;
+ return ServerToClientCmd::equals(rhs);
+}
+
+std::ostream& SSyncCmd::print(std::ostream& os) const
+{
+ os << "cmd:SSyncCmd";
+ return os;
+}
+
+bool SSyncCmd::handle_server_response( ServerReply& server_reply, Cmd_ptr /*cts_cmd*/, bool debug ) const
+{
+ // Update server_reply.client_defs_, with the changes returned from the server
+ do_sync( server_reply, debug );
+
+ return true;
+}
+
+bool SSyncCmd::do_sync( ServerReply& server_reply, bool debug) const
+{
+ // ****************************************************
+ // On the client side
+ // ****************************************************
+ if (no_defs_) {
+#ifdef DEBUG_CLIENT_SYNC
+ std::cout << "SSyncCmd::do_sync: No defs in the server. Reset client caches\n";
+#endif
+ if (debug) std::cout << " SSyncCmd::do_sync:: No defs in the server. Reset client caches\n";
+ server_reply.client_handle_ = 0;
+ server_reply.client_defs_ = defs_ptr();
+ server_reply.client_node_ = node_ptr();
+ server_reply.set_sync( true );
+ server_reply.set_full_sync( true );
+ return true;
+ }
+
+ if (server_defs_.get()) {
+ // *FULL* sync
+ // to keep pace with the state changes. Passed back later on, get further changes
+ // If non zero handle will contain suites specified in the client handle, including their max change numbers
+ server_reply.client_defs_ = server_defs_;
+ server_reply.set_sync( true );
+ server_reply.set_full_sync( true );
+ if (debug) cout << " SSyncCmd::do_sync::*FULL sync*, client side state/modify numbers(" << server_defs_->state_change_no() << "," << server_defs_->modify_change_no() << ")\n";
+#ifdef DEBUG_CLIENT_SYNC
+ cout << "SSyncCmd::do_sync: defs *FULL sync*, client side state/modify numbers(" << server_defs_->state_change_no() << "," << server_defs_->modify_change_no() << ")\n";
+#endif
+ return true;
+ }
+
+ if (full_defs_) {
+ if (full_server_defs_as_string_.empty()) {
+ // TEST path.(i.e no client server): re-use static string
+#ifdef DEBUG_CLIENT_SYNC
+ cout << "SSyncCmd::do_sync: TEST PATH: *FULL CACHE sync* : using static cache";
+#endif
+ server_reply.client_defs_ = FullServerDefsCache::restore_defs_from_string();
+ }
+ else {
+#ifdef DEBUG_CLIENT_SYNC
+ cout << "SSyncCmd::do_sync: *FULL CACHE sync* : using cache returned from server: cache_size(" << full_server_defs_as_string_.size() << ")";
+#endif
+ server_reply.client_defs_ = FullServerDefsCache::restore_defs_from_string(full_server_defs_as_string_);
+ }
+ server_reply.set_sync( true );
+ server_reply.set_full_sync( true );
+ if (debug) cout << " SSyncCmd::do_sync::*FULL CACHE sync*, client side state/modify numbers(" << server_reply.client_defs_->state_change_no() << "," << server_reply.client_defs_->modify_change_no() << ")\n";
+#ifdef DEBUG_CLIENT_SYNC
+ cout << ": client side state/modify numbers(" << server_reply.client_defs_->state_change_no() << "," << server_reply.client_defs_->modify_change_no() << ")\n";
+#endif
+ return true;
+ }
+
+ // Can only sync, *if* we have definition on the client side
+ if (server_reply.client_defs_.get() ) {
+ // *INCREMENTAL* sync
+ // Apply mementos to the client side defs, to bring in sync with server defs
+ // If *no* server loaded, then no changes applied
+ // Returns true if are any memento's, i.e. server changed.
+ server_reply.set_full_sync( false );
+ bool changes_made_to_client = incremental_changes_.incremental_sync(server_reply.client_defs_,server_reply.changed_nodes());
+ server_reply.set_sync( changes_made_to_client );
+
+ if (debug) cout << " SSyncCmd::do_sync::*INCREMENTAL sync*, client side state/modify numbers("
+ << incremental_changes_.get_server_state_change_no() << ","
+ << incremental_changes_.get_server_modify_change_no() << ") changes_made_to_client("
+ << changes_made_to_client << ")\n";
+
+#ifdef DEBUG_CLIENT_SYNC
+ cout << "SSyncCmd::do_sync::*INCREMENTAL sync*, client side state/modify numbers("
+ << incremental_changes_.get_server_state_change_no() << ","
+ << incremental_changes_.get_server_modify_change_no() << ") changes_made_to_client("
+ << changes_made_to_client << "), changed_node_paths("
+ << server_reply.changed_nodes().size() << ")\n";
+#endif
+ return changes_made_to_client;
+ }
+ return false;
+}
+
+std::ostream& operator<<(std::ostream& os, const SSyncCmd& c) { return c.print(os); }
diff --git a/Base/src/stc/SSyncCmd.hpp b/Base/src/stc/SSyncCmd.hpp
new file mode 100644
index 0000000..8fe35c0
--- /dev/null
+++ b/Base/src/stc/SSyncCmd.hpp
@@ -0,0 +1,160 @@
+#ifndef SSYNC_CMD_HPP_
+#define SSYNC_CMD_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #25 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/noncopyable.hpp>
+
+#include "ServerToClientCmd.hpp"
+#include "DefsDelta.hpp"
+
+//================================================================================
+// Cache the de-serialisation cost, in the *SERVER* when returning the FULL definition
+// When there are no state changes, we can just return the cache string for other clients
+// Thereby saving time in the server and client for de-serialisation.
+// Here we are trading memory for speed:
+//
+// Current for each client request we have:
+// client1: --------------> get---------------> Server
+// serialise---------<----de-serialize
+//
+// client2: --------------> get---------------> Server
+// serialise---------<----de-serialize
+//
+// client3: --------------> get---------------> Server
+// serialise---------<----de-serialize
+//
+// By caching the de-serialisation process, we can speed up the downloads.
+// However whenever there is a state change we need to update the cache
+//
+// client1: --------------> get---------------> Server
+// serialise------<----de-serialisation
+//
+// client2: --------------> get---------------> Server
+// serialise---------<----return cache
+//
+// client3: --------------> get---------------> Server
+// serialise---------<----return cache
+//================================================================================
+class FullServerDefsCache : private boost::noncopyable {
+public:
+ // Server side
+ static void update_cache_if_state_changed(defs_ptr defs);
+
+ // Client side
+ static defs_ptr restore_defs_from_string(const std::string&);
+ static defs_ptr restore_defs_from_string(); // used in test
+
+private:
+ friend class SSyncCmd;
+
+ FullServerDefsCache();
+ ~FullServerDefsCache();
+ static std::string full_server_defs_as_string_;
+ static unsigned int state_change_no_; // detect state change in defs across clients
+ static unsigned int modify_change_no_; // detect state change in defs across clients
+};
+
+//================================================================================
+// class SSyncCmd: Used to transfer changes made in the server to the client
+// The client can then apply the changes to the client side defs.
+//
+// *** This class should be used in conjunction with the news command.
+// *** i.e The news command is used to test for server changes. This command
+// *** will then get those changes and merge them with client side defs, bringing
+// *** client and server defs in sync.
+//
+// The *client_state_change_no* was passed from the client to the server
+// The *client_modify_change_no* was passed from the client to the server
+//
+// This class make use of FullServerDefsCache as a performance optimisation.
+//================================================================================
+class SSyncCmd : public ServerToClientCmd {
+public:
+ // The constructor is *called* in the server.
+ // This will collate the incremental changes made so far relative to the client_state_change_no.
+ // For large scale change we use client_modify_change_no this will require a full update
+ // *THIS* constructor is used for *TEST* only
+ SSyncCmd(unsigned int client_handle, // a reference to a set of suites used by client
+ unsigned int client_state_change_no,
+ unsigned int client_modify_change_no,
+ AbstractServer* as);
+
+ SSyncCmd() : ServerToClientCmd(), full_defs_(false), no_defs_(false), incremental_changes_(0) {}
+
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ServerToClientCmd*) const;
+
+ // Client side functions:
+ virtual bool handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const;
+
+ /// do_sync() is invoked on the *client side*, Can throw std::runtime_error
+ /// Either does a *FULL* or *INCREMENTAL sync depending on the
+ /// changes in the server. Returns true if client defs changed.
+ bool do_sync( ServerReply& server_reply, bool debug = false) const;
+
+private:
+
+ friend class PreAllocatedReply;
+ void init(unsigned int client_handle, // a reference to a set of suites used by client
+ unsigned int client_state_change_no,
+ unsigned int client_modify_change_no,
+ bool full_sync,
+ AbstractServer* as);
+
+ /// For use when doing a full sync
+ void init(unsigned int client_handle,AbstractServer* as);
+
+ void reset_data_members(unsigned int client_state_change_no);
+ void full_sync(unsigned int client_handle,AbstractServer* as);
+
+private:
+
+ bool full_defs_;
+ bool no_defs_;
+ DefsDelta incremental_changes_;
+ defs_ptr server_defs_; // for returning a subset of the suites
+ std::string full_server_defs_as_string_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< ServerToClientCmd >( *this );
+ ar & no_defs_; // inform user defs does not exist.
+ ar & full_defs_; // returning full defs as a string
+ ar & incremental_changes_; // state changes, small scale changes
+
+ /// When the server_defs_ was created the def's pointer on the suites was reset back to real server defs
+ /// This is not correct for server_defs_, since we use the *same* suites
+ /// **** This is OK since by default the Defs serialisation will fix up the suite's def's pointers ***
+ /// The alternative is to clone all the suites, which is very expensive
+ ar & server_defs_; // large scale changes, if non zero handle, a small subset of the suites
+
+ // when full_defs_ is set server_defs_ will be empty.
+ if (Archive::is_saving::value) {
+ // Avoid copying the string. As this could be very large > 60MB
+ if (full_defs_) {
+ ar & FullServerDefsCache::full_server_defs_as_string_;
+ }
+ else ar & full_server_defs_as_string_;
+ }
+ else {
+ ar & full_server_defs_as_string_;
+ }
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, const SSyncCmd&);
+
+#endif
diff --git a/Base/src/stc/ServerToClientCmd.cpp b/Base/src/stc/ServerToClientCmd.cpp
new file mode 100644
index 0000000..9663700
--- /dev/null
+++ b/Base/src/stc/ServerToClientCmd.cpp
@@ -0,0 +1,26 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #16 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "ServerToClientCmd.hpp"
+#include "Str.hpp"
+
+using namespace ecf;
+
+ServerToClientCmd::~ServerToClientCmd() {}
+
+const std::string& ServerToClientCmd::get_string() const
+{
+ return Str::EMPTY();
+}
diff --git a/Base/src/stc/ServerToClientCmd.hpp b/Base/src/stc/ServerToClientCmd.hpp
new file mode 100644
index 0000000..46fcce8
--- /dev/null
+++ b/Base/src/stc/ServerToClientCmd.hpp
@@ -0,0 +1,62 @@
+#ifndef SERVER_TO_CLIENT_CMD_HPP_
+#define SERVER_TO_CLIENT_CMD_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #19 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <string>
+#include <vector>
+
+#include <boost/serialization/base_object.hpp> // base class serialization
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/assume_abstract.hpp>
+#include <boost/serialization/shared_ptr.hpp>
+
+#include "Cmd.hpp"
+#include "NodeFwd.hpp"
+#include "ServerReply.hpp"
+class AbstractServer;
+
+//================================================================================
+// Start of Server->client
+//================================================================================
+class ServerToClientCmd {
+public:
+ virtual ~ServerToClientCmd();
+
+ virtual std::ostream& print(std::ostream& os) const = 0;
+ virtual bool equals(ServerToClientCmd*) const { return true;}
+
+ virtual const std::string& get_string() const; /// Used by group command, can return any string, including file contents
+ virtual bool ok() const { return true;} /// Used by group command
+ virtual bool hasDefs() const { return false; } /// used by group command
+ virtual bool hasNode() const { return false; } /// used by group command
+ virtual std::string error() const { return std::string();} /// Used by test
+ virtual bool isOkCmd() const { return false; } /// Used by server, to not respond back, client assumes OK
+
+ // Called in client, if any data to be returned , the set on class ServerReply
+ // Cmd_ptr cts_cmd can used for additional context.
+ // return true, if client should exit, returns false, if further work required, ie blocking, errors, etc
+ virtual bool handle_server_response( ServerReply&, Cmd_ptr cts_cmd, bool debug ) const = 0;
+
+protected:
+ ServerToClientCmd(){}
+private:
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive &ar, const unsigned int /*version*/) {}
+};
+BOOST_SERIALIZATION_ASSUME_ABSTRACT(ServerToClientCmd)
+
+#endif
diff --git a/Base/src/stc/StcCmd.cpp b/Base/src/stc/StcCmd.cpp
new file mode 100644
index 0000000..685b695
--- /dev/null
+++ b/Base/src/stc/StcCmd.cpp
@@ -0,0 +1,69 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name : Cmd
+// Author : Avi
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <iostream>
+#include "StcCmd.hpp"
+
+std::ostream& StcCmd::print(std::ostream& os) const
+{
+ switch (api_) {
+ case StcCmd::OK: return os << "cmd:Ok"; break;
+ case StcCmd::BLOCK_CLIENT_SERVER_HALTED: return os << "cmd:Server_halted"; break;
+ case StcCmd::BLOCK_CLIENT_ON_HOME_SERVER: return os << "cmd:Wait"; break;
+ case StcCmd::BLOCK_CLIENT_ZOMBIE: return os << "cmd:Zombie"; break;
+ default: assert(false); break;
+ }
+ assert(false); // unknown command
+ return os << "cmd:Unknown??";
+}
+
+// Client context
+bool StcCmd::handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const
+{
+ bool ret = false;
+ switch (api_) {
+ case StcCmd::OK: {
+ if (debug) std::cout << " StcCmd::handle_server_response OK\n";
+ ret = true;
+ break;
+ }
+ case StcCmd::BLOCK_CLIENT_SERVER_HALTED: {
+ if (debug) std::cout << " StcCmd::handle_server_response BLOCK_CLIENT_SERVER_HALTED\n";
+ server_reply.set_block_client_server_halted(); // requires further work, by ClientInvoker
+ break;
+ }
+ case StcCmd::BLOCK_CLIENT_ON_HOME_SERVER: {
+ if (debug) std::cout << " StcCmd::handle_server_response BLOCK_CLIENT_ON_HOME_SERVER\n";
+ server_reply.set_block_client_on_home_server(); // requires further work, by ClientInvoker
+ break;
+ }
+ case StcCmd::BLOCK_CLIENT_ZOMBIE: {
+ if (debug) std::cout << " StcCmd::handle_server_response BLOCK_CLIENT_ZOMBIE\n";
+ server_reply.set_block_client_zombie_detected(); // requires further work, by ClientInvoker
+ break;
+ }
+ default: assert(false); break;
+ }
+ return ret;
+}
+
+bool StcCmd::equals(ServerToClientCmd* rhs) const
+{
+ StcCmd* the_rhs = dynamic_cast<StcCmd*>(rhs);
+ if (!the_rhs) return false;
+ if (api_ != the_rhs->api()) return false;
+ return ServerToClientCmd::equals(rhs);
+}
+
+std::ostream& operator<<(std::ostream& os, const StcCmd& c) { return c.print(os); }
diff --git a/Base/src/stc/StcCmd.hpp b/Base/src/stc/StcCmd.hpp
new file mode 100644
index 0000000..9e85bd9
--- /dev/null
+++ b/Base/src/stc/StcCmd.hpp
@@ -0,0 +1,57 @@
+#ifndef STC_CMD_HPP_
+#define STC_CMD_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #8 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "ServerToClientCmd.hpp"
+
+// Command that are simple replies to the client.
+// Originally we had separate commands. However this lead
+// TOC overflow on the AIX. Hence in order to minimise global
+// symbols due to use of boost serialisation, will use a single command
+class StcCmd : public ServerToClientCmd {
+public:
+ enum Api { OK,
+ BLOCK_CLIENT_SERVER_HALTED,
+ BLOCK_CLIENT_ON_HOME_SERVER,
+ BLOCK_CLIENT_ZOMBIE
+ };
+ StcCmd(Api a) : api_(a) {}
+ StcCmd() : api_(OK) {}
+
+ void init(Api a) { api_ = a;}
+ Api api() const { return api_;}
+
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ServerToClientCmd*) const;
+ virtual bool handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const;
+
+ /// Other legitimate ServerToClientCmd commands also return ok() as true
+ /// Hence must still have isOkCmd()
+ virtual bool ok() const { return api_ == OK; } // used by group command
+ virtual bool isOkCmd() const { return api_ == OK; } // Used if no reply back from server
+
+private:
+ Api api_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< ServerToClientCmd >( *this );
+ ar & api_;
+ }
+};
+std::ostream& operator<<(std::ostream& os, const StcCmd&);
+#endif
diff --git a/Base/src/stc/ZombieGetCmd.cpp b/Base/src/stc/ZombieGetCmd.cpp
new file mode 100644
index 0000000..ec7f8be
--- /dev/null
+++ b/Base/src/stc/ZombieGetCmd.cpp
@@ -0,0 +1,66 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #11 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <iostream>
+#include "ZombieGetCmd.hpp"
+#include "AbstractServer.hpp"
+
+using namespace std;
+using namespace boost;
+
+ZombieGetCmd::ZombieGetCmd(AbstractServer* as)
+{
+ init(as);
+}
+
+// called in the server
+void ZombieGetCmd::init(AbstractServer* as)
+{
+ zombies_.clear();
+ as->zombie_ctrl().get(zombies_);
+}
+
+bool ZombieGetCmd::equals(ServerToClientCmd* rhs) const
+{
+ ZombieGetCmd* the_rhs = dynamic_cast<ZombieGetCmd*>(rhs);
+ if (!the_rhs) return false;
+ return ServerToClientCmd::equals(rhs);
+}
+
+std::ostream& ZombieGetCmd::print(std::ostream& os) const
+{
+ os << "cmd:ZombieGetCmd [ " << zombies_.size() << " ]";
+ return os;
+}
+
+// Called in client
+bool ZombieGetCmd::handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const
+{
+ if (debug) {
+ std::cout << " ZombieGetCmd::handle_server_response zombies.size() = " << zombies_.size() << "\n";
+ }
+
+ if (server_reply.cli()) {
+ std::cout << Zombie::pretty_print(zombies_);
+ }
+ else {
+ if (debug) {
+ std::cout << Zombie::pretty_print(zombies_);
+ }
+ server_reply.set_zombies( zombies_);
+ }
+ return true;
+}
+
+std::ostream& operator<<(std::ostream& os, const ZombieGetCmd& c) { return c.print(os); }
diff --git a/Base/src/stc/ZombieGetCmd.hpp b/Base/src/stc/ZombieGetCmd.hpp
new file mode 100644
index 0000000..01fabee
--- /dev/null
+++ b/Base/src/stc/ZombieGetCmd.hpp
@@ -0,0 +1,49 @@
+#ifndef ZOMBIE_GET_CMD_HPP_
+#define ZOMBIE_GET_CMD_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "ServerToClientCmd.hpp"
+#include "Zombie.hpp"
+class AbstractServer;
+
+//================================================================================
+// Paired with CtsCmd(GET_ZOMBIES)
+// Client---CtsCmd(GET_ZOMBIES)---->Server-----(ZombieGetCmd)--->client:
+//================================================================================
+class ZombieGetCmd : public ServerToClientCmd {
+public:
+ ZombieGetCmd(AbstractServer*);
+ ZombieGetCmd() : ServerToClientCmd() {}
+
+ void init(AbstractServer*);
+ virtual bool handle_server_response( ServerReply&, Cmd_ptr cts_cmd, bool debug ) const;
+ virtual std::ostream& print(std::ostream& os) const;
+ virtual bool equals(ServerToClientCmd*) const;
+
+private:
+ std::vector<Zombie> zombies_;
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize( Archive & ar, const unsigned int /*version*/ ) {
+ ar & boost::serialization::base_object< ServerToClientCmd >( *this );
+ ar & zombies_;
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, const ZombieGetCmd&);
+
+#endif
diff --git a/Base/test/MockServer.hpp b/Base/test/MockServer.hpp
new file mode 100644
index 0000000..a74faaa
--- /dev/null
+++ b/Base/test/MockServer.hpp
@@ -0,0 +1,98 @@
+#ifndef MOCK_SERVER_HPP_
+#define MOCK_SERVER_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #26 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <assert.h>
+#include "Defs.hpp"
+#include "SuiteChanged.hpp"
+#include "AbstractServer.hpp"
+#include "JobsParam.hpp"
+#include "Jobs.hpp"
+#include "Log.hpp"
+#include "Ecf.hpp" // In server we increment modify and state change numbers,
+
+/// Act as stand in for a server since Request require at least a AbstractServer
+class MockServer : public AbstractServer {
+public:
+ // For the MockServer don't delete the Defs. since we past in a fixture defs
+ struct null_deleter {
+ void operator()(void const *) const{}
+ };
+
+ // Only in server side do we increment state/modify numbers, controlled by: Ecf::set_server(true)
+ MockServer(Defs* defs) : defs_(defs_ptr(defs,MockServer::null_deleter())) { Ecf::set_server(true); }
+ MockServer(defs_ptr defs) : defs_(defs) { Ecf::set_server(true); }
+ ~MockServer() { Ecf::set_server(false); }
+
+ virtual SState::State state() const { return SState::RUNNING;}
+ virtual std::pair<std::string,std::string> hostPort() const { assert(defs_.get()); return defs_->server().hostPort(); }
+ virtual defs_ptr defs() const { return defs_;}
+ virtual void updateDefs(defs_ptr d, bool force) { assert(defs_.get()); defs_->absorb(d.get(),force); }
+ virtual void clear_defs() { if (defs_.get()) defs_->clear(); } // dont delete since we pass in Fixture defs. Otherwise it will crash
+ virtual void checkPtDefs(ecf::CheckPt::Mode m = ecf::CheckPt::UNDEFINED,
+ int check_pt_interval = 0,
+ int check_pt_save_time_alarm = 0) {}
+ virtual void restore_defs_from_checkpt() {}
+ virtual void nodeTreeStateChanged() {}
+ virtual bool allowTaskCommunication() const { return true;}
+ virtual void shutdown() {}
+ virtual void halted() {}
+ virtual void restart() {}
+ virtual bool reloadWhiteListFile(std::string&) { return true;}
+ virtual bool authenticateReadAccess(const std::string& ) { return true;}
+ virtual bool authenticateWriteAccess(const std::string& ) { return true;}
+ virtual bool lock(const std::string& user) {
+ if (userWhoHasLock_.empty()) {
+ userWhoHasLock_ = user;
+ shutdown();
+ return true;
+ }
+ return false;
+ }
+ virtual void unlock() { userWhoHasLock_.clear(); restart(); }
+ virtual const std::string& lockedUser() const { return userWhoHasLock_;}
+ virtual void traverse_node_tree_and_job_generate(const boost::posix_time::ptime& time_now,bool user_cmd_context) const {
+ if (state() == SState::RUNNING && defs_.get()) {
+ JobsParam jobsParam(poll_interval(), false /* as->allow_job_creation_during_tree_walk() */ );
+ Jobs jobs(defs_);
+ if (!jobs.generate(jobsParam)) ecf::log(ecf::Log::ERR,jobsParam.getErrorMsg()); // will automatically add end of line
+ }
+ }
+ virtual int poll_interval() const { return 60; }
+ virtual void debug_server_on(){}
+ virtual void debug_server_off(){}
+ virtual bool debug() const { return true; }
+
+private:
+ defs_ptr defs_;
+ std::string userWhoHasLock_;
+};
+
+/// This class is used to create a Mock Server, so that we can make direct
+/// data model changes without using commands.
+/// In particular it will:
+/// o Ecf::set_server(true): This controls incrementing of state/modify change numbers
+/// which should *only* be done on the server side
+/// o Update Suite state/modify change number
+class MockSuiteChangedServer : private boost::noncopyable {
+public:
+ MockSuiteChangedServer(suite_ptr suite) : suiteChanged_(suite) { Ecf::set_server(true);}
+ ~MockSuiteChangedServer() { Ecf::set_server(false); }
+private:
+ ecf::SuiteChanged suiteChanged_;
+};
+#endif
+
diff --git a/Base/test/TestAlterCmd.cpp b/Base/test/TestAlterCmd.cpp
new file mode 100644
index 0000000..94eb6db
--- /dev/null
+++ b/Base/test/TestAlterCmd.cpp
@@ -0,0 +1,827 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #48 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <boost/test/unit_test.hpp>
+
+#include "ClientToServerCmd.hpp"
+#include "ServerToClientCmd.hpp"
+#include "MyDefsFixture.hpp"
+#include "TestHelper.hpp"
+#include "Str.hpp"
+#include "System.hpp"
+
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( BaseTestSuite )
+
+class TestStateChanged {
+public:
+ TestStateChanged(suite_ptr s)
+ : suite_(s),
+ initial_suite_state_change_no_(s->state_change_no()),
+ initial_suite_modify_change_no_(s->modify_change_no()) { Ecf::set_server(true);}
+
+ ~TestStateChanged() {
+ Ecf::set_server(false);
+ BOOST_CHECK_MESSAGE(suite_->state_change_no() != initial_suite_state_change_no_ ||
+ suite_->modify_change_no() != initial_suite_modify_change_no_,
+ "Suite " << suite_->name() << " has no change in attributes. Forget to increment change no?"
+ << " suite_->state_change_no(" << suite_->state_change_no()<< ")-"
+ << "-initial_suite_state_change_no_(" << initial_suite_state_change_no_ << ") "
+ << " suite_->modify_change_no(" << suite_->modify_change_no() << ")-"
+ << "-initial_suite_modify_change_no_(" << initial_suite_modify_change_no_ << ")"
+ );
+ }
+private:
+ suite_ptr suite_;
+ unsigned int initial_suite_state_change_no_;
+ unsigned int initial_suite_modify_change_no_;
+};
+
+
+class TestDefsStateChanged {
+public:
+ TestDefsStateChanged(Defs* s)
+ : defs_(s),
+ initial_state_change_no_(s->defs_only_max_state_change_no()) {}
+
+ ~TestDefsStateChanged() {
+ Ecf::set_server(false);
+ BOOST_CHECK_MESSAGE(defs_->defs_only_max_state_change_no() != initial_state_change_no_,
+ "Defs has no change in attributes. Forget to increment change no?"
+ );
+ }
+private:
+ Defs* defs_;
+ unsigned int initial_state_change_no_;
+};
+
+
+BOOST_AUTO_TEST_CASE( test_alter_cmd_for_clock_type_hybrid )
+{
+ cout << "Base:: ...test_alter_cmd_for_clock_type_hybrid\n";
+
+ // In this test the suite has NO Clock attribute. It should get added automatically
+ // when a new clock is added, we should sync with the computer clock
+ Defs defs;
+ suite_ptr s = Suite::create("suite");
+ defs.addSuite( s );
+
+ BOOST_CHECK_MESSAGE( !s->clockAttr(), "Expected no clock");
+ std::string error_msg;
+ BOOST_CHECK_MESSAGE(defs.checkInvariants(error_msg),"checkInvariants failed " << error_msg);
+
+ { // Change clock type =====================================================================================================
+ defs.beginAll();
+ TestStateChanged changed(s);
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::CLOCK_TYPE,"hybrid","")));
+ clock_ptr v = s->clockAttr();
+ BOOST_CHECK_MESSAGE( v && v->hybrid() , "expected clock to be added and be hybrid");
+
+ // Altering the suite clock attributes, should force suite calendar to align to todays date and time
+ boost::posix_time::ptime date_now = Calendar::second_clock_time();
+ int day_of_month = date_now.date().day();
+ int month = date_now.date().month();
+ int year = date_now.date().year();
+ BOOST_CHECK_MESSAGE( s->calendar().day_of_month() == day_of_month, "Calendar should be updated after re-queue/begin. Expected " << day_of_month << " but found " << s->calendar().day_of_month());
+ BOOST_CHECK_MESSAGE( s->calendar().month() == month, "Calendar should be updated after re-queue/begin. Expected " << month << " but found " << s->calendar().month());
+ BOOST_CHECK_MESSAGE( s->calendar().year() == year, "Calendar should be updated after re-queued/begin");
+ BOOST_CHECK_MESSAGE(defs.checkInvariants(error_msg),"checkInvariants failed " << error_msg);
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_alter_cmd_for_clock_type_real )
+{
+ cout << "Base:: ...test_alter_cmd_for_clock_type_real\n";
+
+ // In this test the suite has NO Clock attribute. It should get added automatically
+ // when a new clock is added, we should sync with the computer clock
+ Defs defs;
+ suite_ptr s = defs.add_suite("suite");
+
+ BOOST_CHECK_MESSAGE( !s->clockAttr(), "Expected no clock");
+ std::string error_msg; BOOST_CHECK_MESSAGE(defs.checkInvariants(error_msg),"checkInvariants failed " << error_msg);
+
+ { // Change clock type =====================================================================================================
+ defs.beginAll();
+ TestStateChanged changed(s);
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::CLOCK_TYPE,"real","")));
+ clock_ptr v = s->clockAttr();
+ BOOST_CHECK_MESSAGE( v && !v->hybrid() , "expected clock to be added and be real");
+
+ // Altering the suite clock attributes, should force suite calendar to align to todays date and time
+ boost::posix_time::ptime date_now = Calendar::second_clock_time();
+ int day_of_month = date_now.date().day();
+ int month = date_now.date().month();
+ int year = date_now.date().year();
+ BOOST_CHECK_MESSAGE( s->calendar().day_of_month() == day_of_month, "Calendar should be updated after re-queue/begin. Expected " << day_of_month << " but found " << s->calendar().day_of_month());
+ BOOST_CHECK_MESSAGE( s->calendar().month() == month, "Calendar should be updated after re-queue/begin. Expected " << month << " but found " << s->calendar().month());
+ BOOST_CHECK_MESSAGE( s->calendar().year() == year, "Calendar should be updated after re-queued/begin");
+ BOOST_CHECK_MESSAGE(defs.checkInvariants(error_msg),"checkInvariants failed " << error_msg);
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_alter_cmd_for_clock_sync )
+{
+ cout << "Base:: ...test_alter_cmd_for_clock_sync\n";
+
+ // Add a suite with a hybrid clock set to the past, on switch to real time, should have todays date
+ // Since the clock exists on the suite, with another date, we must explicitly sync with computer
+ // alternatively user can change clock date and clock gain to align with computer
+ Defs defs;
+ suite_ptr s = defs.add_suite("suite");
+ ClockAttr clockAttr(true); // add hybrid clock
+ clockAttr.date(1,1,2009);
+ s->addClock( clockAttr );
+
+ BOOST_REQUIRE_MESSAGE( s->clockAttr(), "Expected clock");
+ BOOST_REQUIRE_MESSAGE( s->clockAttr()->hybrid(), "Expected hybrid clock");
+ std::string error_msg; BOOST_CHECK_MESSAGE(defs.checkInvariants(error_msg),"checkInvariants failed " << error_msg);
+
+ { // Change clock type =====================================================================================================
+ defs.beginAll();
+ TestStateChanged changed(s);
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::CLOCK_TYPE,"real","")));
+ clock_ptr v = s->clockAttr();
+ BOOST_CHECK_MESSAGE( v && !v->hybrid() , "expected clock to be added and be real");
+
+ // When we reque, the date should be unchanged
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new RequeueNodeCmd("/" + s->name())));
+ BOOST_CHECK_MESSAGE( s->calendar().day_of_month() == 1, "Calendar should be updated after re-queue/begin. Expected day of month " << 1 << " but found " << s->calendar().day_of_month());
+ BOOST_CHECK_MESSAGE( s->calendar().month() == 1, "Calendar should be updated after re-queue/begin. Expected month " << 1 << " but found " << s->calendar().month());
+ BOOST_CHECK_MESSAGE( s->calendar().year() == 2009, "Calendar should be updated after re-queued/begin, Expected year " << 2009 << " but found " << s->calendar().year());
+ BOOST_CHECK_MESSAGE(defs.checkInvariants(error_msg),"checkInvariants failed " << error_msg);
+
+ // After a clk sync, data should match computer
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::CLOCK_SYNC,"","")));
+
+ boost::posix_time::ptime date_now = Calendar::second_clock_time();
+ int day_of_month = date_now.date().day();
+ int month = date_now.date().month();
+ int year = date_now.date().year();
+ BOOST_CHECK_MESSAGE( s->calendar().day_of_month() == day_of_month, "Calendar should be updated after re-queue/begin. Expected " << day_of_month << " but found " << s->calendar().day_of_month());
+ BOOST_CHECK_MESSAGE( s->calendar().month() == month, "Calendar should be updated after re-queue/begin. Expected " << month << " but found " << s->calendar().month());
+ BOOST_CHECK_MESSAGE( s->calendar().year() == year, "Calendar should be updated after re-queued/begin");
+ BOOST_CHECK_MESSAGE(defs.checkInvariants(error_msg),"checkInvariants failed " << error_msg);
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_alter_cmd_for_clock_date )
+{
+ cout << "Base:: ...test_alter_cmd_for_clock_date\n";
+
+ // In this test the suite has NO Clock attribute. It should get added automatically
+ Defs defs;
+ suite_ptr s = defs.add_suite("suite");
+ BOOST_CHECK_MESSAGE( !s->clockAttr(), "Expected no clock");
+ std::string error_msg; BOOST_CHECK_MESSAGE(defs.checkInvariants(error_msg),"checkInvariants failed " << error_msg);
+
+ // Change clock date =====================================================================================================
+ TestStateChanged changed(s);
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::CLOCK_DATE,"12.12.2012","")));
+ clock_ptr v = s->clockAttr();
+ BOOST_CHECK_MESSAGE( v.get(), "expected clock to be added");
+
+ // Check that calendar is updated by the Alter
+ {
+ BOOST_CHECK_MESSAGE( s->calendar().day_of_month() == 12, "Calendar should be updated");
+ BOOST_CHECK_MESSAGE( s->calendar().month() == 12, "Calendar should be updated");
+ BOOST_CHECK_MESSAGE( s->calendar().year() == 2012, "Calendar should be updated");
+
+ defs.beginAll();
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new RequeueNodeCmd(s->absNodePath())));
+ BOOST_CHECK_MESSAGE( s->calendar().day_of_month() == 12, "Calendar should be updated after re-queued");
+ BOOST_CHECK_MESSAGE( s->calendar().month() == 12, "Calendar should be updated after re-queued");
+ BOOST_CHECK_MESSAGE( s->calendar().year() == 2012, "Calendar should be updated after re-queued");
+
+ // Now re sync with the computers clock, the suite calendar should align to todays date and time
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::CLOCK_SYNC,"","")));
+
+ boost::posix_time::ptime date_now = Calendar::second_clock_time();
+ int day_of_month = date_now.date().day();
+ int month = date_now.date().month();
+ int year = date_now.date().year();
+ BOOST_CHECK_MESSAGE( s->calendar().day_of_month() == day_of_month, "Calendar should be updated after re-queue/begin. Expected " << day_of_month << " but found " << s->calendar().day_of_month());
+ BOOST_CHECK_MESSAGE( s->calendar().month() == month, "Calendar should be updated after re-queue/begin. Expected " << month << " but found " << s->calendar().month());
+ BOOST_CHECK_MESSAGE( s->calendar().year() == year, "Calendar should be updated after re-queued/begin");
+ BOOST_CHECK_MESSAGE(defs.checkInvariants(error_msg),"checkInvariants failed " << error_msg);
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_alter_cmd_for_clock_gain )
+{
+ cout << "Base:: ...test_alter_cmd_for_clock_gain\n";
+
+ // In this test the suite has NO Clock attribute. It should get added automatically
+ Defs defs;
+ std::string suitename = "suite";
+ suite_ptr s = defs.add_suite(suitename);
+ BOOST_CHECK_MESSAGE( !s->clockAttr(), "Expected no clock");
+ std::string error_msg; BOOST_CHECK_MESSAGE(defs.checkInvariants(error_msg),"checkInvariants failed " << error_msg);
+
+ { // Change clock gain =====================================================================================================
+ TestStateChanged changed(s);
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(suitename,AlterCmd::CLOCK_GAIN,"86400",""))); // add 24 hours in seconds
+ clock_ptr v = s->clockAttr();
+ BOOST_CHECK_MESSAGE( v.get(), "expected clock to be added");
+ BOOST_CHECK_MESSAGE( v && v->gain() == 86400 , "expected clock gain to be 86400 but found " << v->gain());
+
+ // Check that calendar is updated by the alter
+ {
+ // add one day, to current date, to simulate a gain of 24 hours
+ boost::posix_time::ptime date_now = Calendar::second_clock_time();
+ boost::gregorian::date newDate = date_now.date();
+ boost::gregorian::date_duration one_day(1);
+ newDate += one_day;
+ int day_of_month = newDate.day();
+ int month = newDate.month();
+ int year = newDate.year();
+ BOOST_CHECK_MESSAGE( s->calendar().day_of_month() == day_of_month, "Calendar should be updated after alter. Expected " << day_of_month << " but found " << s->calendar().day_of_month());
+ BOOST_CHECK_MESSAGE( s->calendar().month() == month, "Calendar should be updated after alter. Expected " << month << " but found " << s->calendar().month());
+ BOOST_CHECK_MESSAGE( s->calendar().year() == year, "Calendar should be updated after alter");
+
+ // This should init calendar with todays date + 86400 seconds. i.e +1 day.
+ defs.beginAll();
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new RequeueNodeCmd("/" + suitename)));
+ BOOST_CHECK_MESSAGE( s->calendar().day_of_month() == day_of_month, "Calendar should be updated after re-queue/begin. Expected " << day_of_month << " but found " << s->calendar().day_of_month());
+ BOOST_CHECK_MESSAGE( s->calendar().month() == month, "Calendar should be updated after re-queue/begin. Expected " << month << " but found " << s->calendar().month());
+ BOOST_CHECK_MESSAGE( s->calendar().year() == year, "Calendar should be updated after re-queued/begin");
+
+ // Now re sync with the computers clock,When we reque, the suite calendar should align to todays date and time
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::CLOCK_SYNC,"","")));
+ day_of_month = date_now.date().day();
+ month = date_now.date().month();
+ year = date_now.date().year();
+ BOOST_CHECK_MESSAGE( s->calendar().day_of_month() == day_of_month, "Calendar should be updated after re-queue/begin. Expected " << day_of_month << " but found " << s->calendar().day_of_month());
+ BOOST_CHECK_MESSAGE( s->calendar().month() == month, "Calendar should be updated after re-queue/begin. Expected " << month << " but found " << s->calendar().month());
+ BOOST_CHECK_MESSAGE( s->calendar().year() == year, "Calendar should be updated after re-queued/begin");
+ BOOST_CHECK_MESSAGE(defs.checkInvariants(error_msg),"checkInvariants failed " << error_msg);
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_alter_cmd )
+{
+ cout << "Base:: ...test_alter_cmd\n";
+
+ Defs defs;
+ suite_ptr s = defs.add_suite("suite");
+ task_ptr task = s->add_task("t1");
+ {
+ ClockAttr clockAttr(false); // real clock
+ clockAttr.date(1,1,2009);
+ clockAttr.set_gain_in_seconds(3600);
+ clockAttr.startStopWithServer(true);
+ s->addClock( clockAttr );
+ s->addDefStatus(DState::SUSPENDED); // avoid AlterCmd from job submission
+ }
+
+ std::string error_msg; BOOST_CHECK_MESSAGE(defs.checkInvariants(error_msg),"checkInvariants failed " << error_msg);
+
+ { // Change server state. This will cause Flag::MESSAGE to be set on the defs
+ TestDefsStateChanged chenged(&defs);
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd("/",AlterCmd::ADD_VARIABLE,"_fred_","value")));
+ BOOST_CHECK_MESSAGE( defs.server().find_variable("_fred_") == "value" , "expected to find value");
+
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd("/",AlterCmd::VARIABLE,"_fred_","_value_")));
+ BOOST_CHECK_MESSAGE( defs.server().find_variable("_fred_") == "_value_" , "expected to find _value_");
+
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd("/",AlterCmd::DEL_VARIABLE,"_fred_")));
+ BOOST_CHECK_MESSAGE( defs.server().find_variable("_fred_") == "" , "expected to find empty string");
+
+ BOOST_CHECK_MESSAGE( defs.get_edit_history("/").size() == 3,
+ "expected edit_history of 3 to be added but found " << defs.get_edit_history("/").size());
+
+ {
+ // test set and clear flags of the definition
+ // Note: we can not really test Flag::Message clear, since that act of clearing, sets the message
+ std::vector<Flag::Type> flag_list = Flag::list();
+ for(size_t i =0; i < flag_list.size(); ++i) {
+ // When any user command(including setting flags) invoked, we set Flag::MESSAGE on the defs.
+ // Hence setting flag Flag::MESSAGE has no effect. Likewise clearing has no affect since it get set
+ if ( flag_list[i] == Flag::MESSAGE) continue;
+
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd("/",flag_list[i],true)));
+ BOOST_CHECK_MESSAGE( defs.flag().is_set(flag_list[i]), "Expected flag " << flag_list[i] << " to be set ");
+
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd("/",flag_list[i],false)));
+ BOOST_CHECK_MESSAGE( ! defs.flag().is_set(flag_list[i]), "Expected flag " << flag_list[i] << " to be clear ");
+ }
+ }
+ }
+
+ { // Change clock type =====================================================================================================
+ defs.beginAll();
+ BOOST_CHECK_MESSAGE( s->calendar().hybrid() == false, "expected calendar to be real after begin");
+ BOOST_CHECK_MESSAGE( s->calendar().hybrid() == s->clockAttr()->hybrid(), "Calendar and Clock attribute must be in sync after begin");
+
+ TestStateChanged changed(s);
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::CLOCK_TYPE,"hybrid","")));
+ clock_ptr v = s->clockAttr();
+ BOOST_CHECK_MESSAGE( v && v->hybrid() , "expected clock to be hybrid");
+ BOOST_CHECK_MESSAGE( defs.get_edit_history(s->absNodePath()).size() == 1,
+ "expected edit_history of 1 to be added but found " << defs.get_edit_history(s->absNodePath()).size());
+
+ // Check that calendar is in sync with clock attribute after the alter
+ {
+ BOOST_CHECK_MESSAGE( s->calendar().hybrid() == s->clockAttr()->hybrid(), "Calendar and Clock attribute must be in sync after alter");
+ BOOST_CHECK_MESSAGE( s->calendar().hybrid() == true, "expected calendar to be re-initialised to be hybrid after alter");
+ }
+
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::CLOCK_TYPE,"real","")));
+ BOOST_CHECK_MESSAGE( v && !v->hybrid() , "expected clock to be real");
+ BOOST_CHECK_MESSAGE( defs.get_edit_history(s->absNodePath()).size() == 2,
+ "expected edit_history of 2 to be added but found " << defs.get_edit_history(s->absNodePath()).size());
+
+ // Check that calendar is in sync with clock attribute after the alter
+ {
+ BOOST_CHECK_MESSAGE( s->calendar().hybrid() == s->clockAttr()->hybrid(), "Calendar and Clock attribute must be in sync after alter");
+ BOOST_CHECK_MESSAGE( s->calendar().hybrid() == false, "expected calendar to be re-initialised to be real after alter");
+ }
+ }
+
+ { // Change clock date =====================================================================================================
+ TestStateChanged changed(s);
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::CLOCK_DATE,"12.12.2012","")));
+ clock_ptr v = s->clockAttr();
+ BOOST_CHECK_MESSAGE( (v->day() == 12 && v->month() == 12 && v->year() == 2012) , "expected clock date to be 12.12.2012 but found " << v->toString());
+ BOOST_CHECK_MESSAGE( defs.get_edit_history(s->absNodePath()).size() == 3,
+ "expected edit_history of 3 to be added but found " << defs.get_edit_history(s->absNodePath()).size());
+
+ // Check that calendar is updated after alter
+ {
+ BOOST_CHECK_MESSAGE( s->calendar().day_of_month() == 12, "Calendar should be updated after re-queued");
+ BOOST_CHECK_MESSAGE( s->calendar().month() == 12, "Calendar should be updated after re-queued");
+ BOOST_CHECK_MESSAGE( s->calendar().year() == 2012, "Calendar should be updated after re-queued");
+ }
+ }
+
+ { // Change clock gain =====================================================================================================
+ TestStateChanged changed(s);
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::CLOCK_GAIN,"86400",""))); // add 24 hours in seconds
+ clock_ptr v = s->clockAttr();
+ BOOST_CHECK_MESSAGE( v && v->gain() == 86400 , "expected clock gain to be 3333 but found " << v->gain());
+ BOOST_CHECK_MESSAGE( defs.get_edit_history(s->absNodePath()).size() == 4,
+ "expected edit_history of 4 to be added but found " << defs.get_edit_history(s->absNodePath()).size());
+
+ // Check that calendar is updated after the alter
+ {
+ BOOST_CHECK_MESSAGE( s->calendar().day_of_month() == 13, "Calendar should be updated after re-queued");
+ BOOST_CHECK_MESSAGE( s->calendar().month() == 12, "Calendar should be updated after re-queued");
+ BOOST_CHECK_MESSAGE( s->calendar().year() == 2012, "Calendar should be updated after re-queued");
+ }
+ }
+
+ // test add, the deleting of a specific attribute
+ {
+ TestStateChanged changed(s);
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_DATE,"12.12.2010")));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_DAY,"sunday")));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_TIME,"23:00")));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_TODAY,"23:00")));
+ BOOST_CHECK_MESSAGE( task->dates().size() == 1, "expected 1 date to be added but found " << s->dates().size());
+ BOOST_CHECK_MESSAGE( task->days().size() == 1, "expected 1 day to be added but found " << s->days().size());
+ BOOST_CHECK_MESSAGE( task->timeVec().size() == 1, "expected 1 time to be added but found " << s->timeVec().size());
+ BOOST_CHECK_MESSAGE( task->todayVec().size() == 1, "expected 1 today attr, to be added but found " << s->todayVec().size());
+ BOOST_CHECK_MESSAGE( defs.get_edit_history(task->absNodePath()).size() == 4, "expected edit_history of 4 to be added but found " << defs.get_edit_history(task->absNodePath()).size());
+ }
+ {
+ TestStateChanged changed(s);
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::DEL_DATE,"12.12.2010")));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::DEL_DAY,"sunday")));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::DEL_TIME,"23:00")));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::DEL_TODAY,"23:00")));
+ BOOST_CHECK_MESSAGE( task->dates().size() == 0, "expected 0 dates, but found " << s->dates().size());
+ BOOST_CHECK_MESSAGE( task->days().size() == 0, "expected 0 day but found " << s->days().size());
+ BOOST_CHECK_MESSAGE( task->timeVec().size() == 0, "expected 0 time but found " << s->timeVec().size());
+ BOOST_CHECK_MESSAGE( task->todayVec().size() == 0, "expected 0 today but found " << s->todayVec().size());
+ BOOST_CHECK_MESSAGE( defs.get_edit_history(task->absNodePath()).size() == 8, "expected edit_history of 8 to be added but found " << defs.get_edit_history(task->absNodePath()).size());
+ }
+
+ { // test delete all
+ TestStateChanged changed(s);
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_DATE,"12.12.2010")));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_DATE,"12.*.2010")));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_DATE,"8.*.2010")));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_DAY,"sunday")));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_DAY,"monday")));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_DAY,"tuesday")));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_TIME,"09:00")));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_TIME,"22:00")));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_TIME,"23:00")));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_TODAY,"02:00")));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_TODAY,"03:00")));
+ BOOST_CHECK_MESSAGE( defs.get_edit_history(task->absNodePath()).size() == 19, "expected edit_history of 19 to be added but found " << defs.get_edit_history(task->absNodePath()).size());
+
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::DEL_DATE)));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::DEL_DAY)));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::DEL_TIME)));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::DEL_TODAY)));
+ BOOST_CHECK_MESSAGE( task->dates().size() == 0, "expected 0 dates, but found " << s->dates().size());
+ BOOST_CHECK_MESSAGE( task->days().size() == 0, "expected 0 day but found " << s->days().size());
+ BOOST_CHECK_MESSAGE( task->timeVec().size() == 0, "expected 0 time but found " << s->timeVec().size());
+ BOOST_CHECK_MESSAGE( task->todayVec().size() == 0, "expected 0 today but found " << s->todayVec().size());
+
+ /// Edit history should be truncated to max of 20
+ BOOST_CHECK_MESSAGE( defs.get_edit_history(task->absNodePath()).size() == 20, "expected edit_history to be truncated to 20, but found " << defs.get_edit_history(task->absNodePath()).size());
+ }
+
+ { // test add variables
+ TestStateChanged changed(s);
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::ADD_VARIABLE,"FRED1","_val_")));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::ADD_VARIABLE,"FRED2","_val_")));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::ADD_VARIABLE,"FRED3","_val_")));
+ BOOST_CHECK_MESSAGE( s->variables().size() == 3, "expected 3 variable but found " << s->variables().size());
+
+ // test delete variables
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_VARIABLE,"FRED1")));
+ BOOST_CHECK_MESSAGE( s->variables().size() == 2, "expected 2 variable but found " << s->variables().size());
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_VARIABLE)));
+ BOOST_CHECK_MESSAGE( s->variables().size() == 0, "expected 0 variable but found " << s->variables().size());
+
+ // test change variable
+ s->add_variable("FRED1","BILL");
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::VARIABLE,"FRED1","BILL1")));
+ const Variable& v = s->findVariable("FRED1");
+ BOOST_CHECK_MESSAGE( !v.empty() && v.theValue() == "BILL1", "expected to find variable FRED1, with value BILL1");
+ }
+
+ { // test add event
+ TestStateChanged changed(s);
+ s->addEvent( Event(1,"event1") );
+ s->addEvent( Event(2,"event2") );
+ s->addEvent( Event(3,"event3") );
+ BOOST_CHECK_MESSAGE( s->events().size() == 3, "expected 3 but found " << s->events().size());
+
+ // test delete event
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_EVENT,"event1")));
+ BOOST_CHECK_MESSAGE( s->events().size() == 2, "expected 2 but found " << s->events().size());
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_EVENT)));
+ BOOST_CHECK_MESSAGE( s->events().size() == 0, "expected 0 but found " << s->events().size());
+
+ // test change event
+ s->addEvent( Event(1,"event1") );
+ s->addEvent( Event(2,"event2") );
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::EVENT,"event1",Event::SET())));
+ {const Event& v = s->findEventByNameOrNumber("event1");
+ BOOST_CHECK_MESSAGE( v.value() == 1, "expected to find event with value set");}
+
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::EVENT,"event1",Event::CLEAR())));
+ {const Event& v = s->findEventByNameOrNumber("event1");
+ BOOST_CHECK_MESSAGE( !v.empty() && v.value() == 0, "expected to find event with value cleared");}
+
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::EVENT,"event1","")));
+ {const Event& v = s->findEventByNameOrNumber("event1");
+ BOOST_CHECK_MESSAGE( v.value() == 1, "expected to find event with value set");}
+ }
+
+ { // test add meter
+ TestStateChanged changed(s);
+ s->addMeter( Meter("meter",0,100,100) );
+ s->addMeter( Meter("meter1",0,100,100) );
+ s->addMeter( Meter("meter2",0,100,100) );
+ BOOST_CHECK_MESSAGE( s->meters().size() == 3, "expected 3 but found " << s->meters().size());
+
+ // test delete meter
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_METER,"meter")));
+ BOOST_CHECK_MESSAGE( s->meters().size() == 2, "expected 2 but found " << s->meters().size());
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_METER)));
+ BOOST_CHECK_MESSAGE( s->meters().size() == 0, "expected 0 but found " << s->meters().size());
+
+ // test change meter value
+ s->addMeter( Meter("meter",0,100,100) );
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::METER,"meter","10")));
+ const Meter& v = s->findMeter("meter");
+ BOOST_CHECK_MESSAGE( v.value() == 10, "expected to find meter with value 10");
+ }
+
+ { // test add label
+ TestStateChanged changed(s);
+ s->addLabel( Label("label","labelValue") );
+ s->addLabel( Label("label1","\"labelValue\"") );
+ s->addLabel( Label("label2","\"labelValue\"") );
+ BOOST_CHECK_MESSAGE( s->labels().size() == 3, "expected 3 but found " << s->labels().size());
+
+ // test delete label
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_LABEL,"label")));
+ BOOST_CHECK_MESSAGE( s->labels().size() == 2, "expected 2 but found " << s->labels().size());
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_LABEL)));
+ BOOST_CHECK_MESSAGE( s->labels().size() == 0, "expected 0 but found " << s->labels().size());
+
+ // test change label value
+ s->addLabel( Label("label","labelValue") );
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::LABEL,"label","--fred--")));
+ std::string label_value;
+ BOOST_CHECK_MESSAGE(s->getLabelNewValue("label",label_value ),"Expected to find label");
+ BOOST_CHECK_MESSAGE( label_value == "--fred--", "expected to find label with value --fred--");
+
+ // change label to be empty, ECFLOW-648
+ label_value.clear();
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::LABEL,"label","")));
+ BOOST_CHECK_MESSAGE(s->getLabelNewValue("label",label_value ),"Expected to find label");
+ BOOST_CHECK_MESSAGE( label_value.empty(), "expected to find label with empty value");
+ }
+
+ { // test add Trigger
+ TestStateChanged changed(s);
+ s->add_trigger( "t1 == complete");
+ BOOST_CHECK_MESSAGE( s->get_trigger(), "expected trigger to be added");
+
+ // test delete trigger
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_TRIGGER)));
+ BOOST_CHECK_MESSAGE( !s->get_trigger(), "expected trigger to be deleted");
+
+ // test change trigger expression
+ s->add_trigger( "t1 == complete" );
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::TRIGGER,"x == complete","")));
+ BOOST_CHECK_MESSAGE( s->triggerExpression() == "trigger x == complete", "expected trigger to be changed found " << s->triggerExpression());
+ }
+
+ { // test add complete expression
+ TestStateChanged changed(s);
+ s->add_complete( "t1 == complete" );
+ BOOST_CHECK_MESSAGE( s->get_complete(), "expected complete to be added");
+
+ // test delete complete
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_COMPLETE)));
+ BOOST_CHECK_MESSAGE( !s->get_complete(), "expected complete to be deleted");
+
+ // test change complete expression
+ s->add_complete( "t1 == complete" );
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::COMPLETE,"x == complete","")));
+ BOOST_CHECK_MESSAGE( s->completeExpression() == "complete x == complete", "expected complete expression to be changed found " << s->completeExpression() );
+ }
+
+ { // test add limit
+ TestStateChanged changed(s);
+ s->addLimit( Limit("limit",10) );
+ s->addLimit( Limit("limit1",10) );
+ s->addLimit( Limit("limit2",10) );
+ BOOST_CHECK_MESSAGE( s->limits().size() == 3, "expected 3 but found " << s->limits().size());
+
+ // test delete limit
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_LIMIT,"limit2")));
+ BOOST_CHECK_MESSAGE( s->limits().size() == 2, "expected 2 but found " << s->limits().size());
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_LIMIT)));
+ BOOST_CHECK_MESSAGE( s->limits().size() == 0, "expected 0 but found " << s->limits().size());
+
+ // test change limit max value
+ s->addLimit( Limit("limit",10) );
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::LIMIT_MAX,"limit","90")));
+ limit_ptr v = s->find_limit("limit");
+ BOOST_CHECK_MESSAGE( v.get() && v->theLimit() == 90, "expected to find limit with max value of 90");
+
+ // test change limit value
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::LIMIT_VAL,"limit","33")));
+ BOOST_CHECK_MESSAGE( v.get() && v->value() == 33, "expected to find limit with value of 33");
+
+ // Test delete limit path
+ std::set<std::string> paths; paths.insert("made_up_path");
+ Limit limit_path("limit_name",10);
+ limit_path.set_paths(paths);
+
+ s->addLimit( limit_path );
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_LIMIT_PATH,"limit_name","made_up_path")));
+ limit_ptr lm = s->find_limit("limit_name");
+ BOOST_CHECK_MESSAGE( lm.get() && lm->paths().empty(), "Expected no paths but found " << lm->paths().size());
+ }
+
+ { // test add repeat
+ TestStateChanged changed(s);
+ s->addRepeat( RepeatDate("YMD",20090916,20090930,1));
+ BOOST_CHECK_MESSAGE( !s->repeat().empty(), "expected repeat to be added");
+
+ // test delete repeat
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_REPEAT)));
+ BOOST_CHECK_MESSAGE( s->repeat().empty(), "expected repeat to be deleted");
+
+ // test change repeat value
+ s->addRepeat( RepeatDate("YMD",20090916,20090930,1));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::REPEAT,"20090917","")));
+ BOOST_CHECK_MESSAGE( s->repeat().valueAsString() == "20090917", "expected 20090917 but found " << s->repeat().valueAsString());
+ }
+ {
+ TestStateChanged changed(s);
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_REPEAT))); // delete previous repeat
+
+ std::vector<std::string> stringList; stringList.reserve(3);
+ stringList.push_back("a");
+ stringList.push_back("b");
+ stringList.push_back("c");
+
+ s->addRepeat( RepeatEnumerated("AEnum",stringList));
+ BOOST_CHECK_MESSAGE( !s->repeat().empty(), "expected repeat to be added");
+
+ // test delete repeat
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_REPEAT)));
+ BOOST_CHECK_MESSAGE( s->repeat().empty(), "expected repeat to be deleted");
+
+ // test change repeat value
+ s->addRepeat( RepeatEnumerated("AEnum",stringList));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::REPEAT,"1","")));
+ BOOST_CHECK_MESSAGE( s->repeat().valueAsString() == "b", "expected 'b' but found " << s->repeat().valueAsString());
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::REPEAT,"c","")));
+ BOOST_CHECK_MESSAGE( s->repeat().valueAsString() == "c", "expected 'c' but found " << s->repeat().valueAsString());
+ }
+ {
+ TestStateChanged changed(s);
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_REPEAT))); // delete previous repeat
+
+ std::vector<std::string> stringList; stringList.reserve(3);
+ stringList.push_back("a");
+ stringList.push_back("b");
+ stringList.push_back("c");
+
+ s->addRepeat( RepeatString("RepeatString",stringList));
+ BOOST_CHECK_MESSAGE( !s->repeat().empty(), "expected repeat to be added");
+
+ // test delete repeat
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_REPEAT)));
+ BOOST_CHECK_MESSAGE( s->repeat().empty(), "expected repeat to be deleted");
+
+ // test change repeat value
+ s->addRepeat( RepeatString("RepeatString",stringList));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::REPEAT,"1","")));
+ BOOST_CHECK_MESSAGE( s->repeat().valueAsString() == "b", "expected 'b' but found " << s->repeat().valueAsString());
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::REPEAT,"c","")));
+ BOOST_CHECK_MESSAGE( s->repeat().valueAsString() == "c", "expected 'c' but found " << s->repeat().valueAsString());
+ }
+
+ {
+ TestStateChanged changed(s);
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_REPEAT))); // delete previous repeat
+
+ std::vector<std::string> stringList; stringList.reserve(3);
+ stringList.push_back("a");
+ stringList.push_back("b");
+ stringList.push_back("c");
+
+ s->addRepeat( RepeatInteger("rep",0,100,1));
+ BOOST_CHECK_MESSAGE( !s->repeat().empty(), "expected repeat to be added");
+
+ // test delete repeat
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_REPEAT)));
+ BOOST_CHECK_MESSAGE( s->repeat().empty(), "expected repeat to be deleted");
+
+ // test change repeat value
+ s->addRepeat( RepeatInteger("rep",0,100,1));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::REPEAT,"22","")));
+ BOOST_CHECK_MESSAGE( s->repeat().valueAsString() == "22", "expected '22' but found " << s->repeat().valueAsString());
+ }
+
+ { // add cron
+ TestStateChanged changed(s);
+ ecf::CronAttr cronAttr;
+ ecf::TimeSlot start( 0, 0 );
+ ecf::TimeSlot finish( 10, 0 );
+ ecf::TimeSlot incr( 0, 5 );
+ std::vector<int> weekdays; for(int i=0;i<7;++i) weekdays.push_back(i);
+ std::vector<int> daysOfMonth;for(int i=1;i<32;++i) daysOfMonth.push_back(i);
+ std::vector<int> months; for(int i=1;i<13;++i) months.push_back(i);
+ cronAttr.addTimeSeries(start,finish,incr);
+ cronAttr.addWeekDays( weekdays );
+ cronAttr.addDaysOfMonth(daysOfMonth);
+ cronAttr.addMonths( months );
+ task->addCron( cronAttr );
+
+ BOOST_CHECK_MESSAGE( task->crons().size() == 1, "expected cron to be added");
+
+ // test delete cron
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::DEL_CRON)));
+ BOOST_CHECK_MESSAGE( task->crons().size() == 0, "expected cron to be delete");
+ }
+
+ { // test suite changed
+ TestStateChanged changed(s);
+
+ // test add zombie
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::ADD_ZOMBIE,"user:fob:init:300")));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::ADD_ZOMBIE,"path:fob:init:300")));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::ADD_ZOMBIE,"ecf:fob:init:300")));
+ BOOST_CHECK_MESSAGE( s->zombies().size() == 3, "expected 3 but found " << s->zombies().size());
+
+ // test delete zombie
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_ZOMBIE,"ecf")));
+ BOOST_CHECK_MESSAGE( s->zombies().size() == 2, "expected 2 but found " << s->zombies().size());
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_ZOMBIE,"path")));
+ BOOST_CHECK_MESSAGE( s->zombies().size() == 1, "expected 1 but found " << s->zombies().size());
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_ZOMBIE,"user")));
+ BOOST_CHECK_MESSAGE( s->zombies().size() == 0, "expected 0 but found " << s->zombies().size());
+ }
+
+ { // free password
+ TestStateChanged changed(s);
+ std::string returnedValue;
+ BOOST_CHECK_MESSAGE( !task->findVariableValue(Str::ECF_PASS(),returnedValue), "Expected no variable of name ECF_PASS");
+
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_VARIABLE,Str::ECF_PASS(),Submittable::FREE_JOBS_PASSWORD())));
+
+ BOOST_CHECK_MESSAGE( task->findVariableValue(Str::ECF_PASS(),returnedValue), "Expected to find variable ECF_PASS on the task");
+ BOOST_CHECK_MESSAGE( returnedValue == Submittable::FREE_JOBS_PASSWORD(), "Expected variable value of name " << Submittable::FREE_JOBS_PASSWORD() << " but found " << returnedValue);
+ }
+
+ {
+ // test set and clear flags
+ // Note: we can not really test Flag::Message clear, since that act of clearing, sets the message
+ std::vector<Flag::Type> flag_list = Flag::list();
+ for(size_t i =0; i < flag_list.size(); ++i) {
+ // When any user command(including setting flags) invoked, we set Flag::MESSAGE on the defs.
+ // Hence setting flag Flag::MESSAGE has no effect. Likewise clearing has no affect since it get set
+ if ( flag_list[i] == Flag::MESSAGE) continue;
+
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),flag_list[i],true)));
+ BOOST_CHECK_MESSAGE( s->flag().is_set(flag_list[i]), "Expected flag " << flag_list[i] << " to be set ");
+
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),flag_list[i],false)));
+ BOOST_CHECK_MESSAGE( ! s->flag().is_set(flag_list[i]), "Expected flag " << flag_list[i] << " to be clear ");
+ }
+ }
+
+ BOOST_CHECK_MESSAGE( defs.get_edit_history(s->absNodePath()).size() == 20, "expected edit_history to be truncated to 20, but found " << defs.get_edit_history(s->absNodePath()).size());
+
+ { // Change suite def status =====================================================================================================
+ TestStateChanged changed(s);
+ std::vector<std::string> dstates = DState::allStates();
+ for(size_t i = 0; i < dstates.size(); i++) {
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEFSTATUS,dstates[i])));
+ }
+ // reset back to suspended
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEFSTATUS,"suspended")));
+ }
+
+ // ================================ LATE ==================================================================
+ { // test add late
+ TestStateChanged changed(s);
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::ADD_LATE,"late -s 10:10 -a 23:10 -c +23:10")));
+ BOOST_CHECK_MESSAGE( s->get_late(), "expected late to be added");
+
+ // test change late
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::LATE,"late -s 10:10")));
+ BOOST_CHECK_MESSAGE( s->get_late() && s->get_late()->toString() == "late -s +10:10", "expected 'late -s 10:10' but found " << s->get_late()->toString());
+
+ // test delete variable
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_LATE)));
+ BOOST_CHECK_MESSAGE( !s->get_late(), "expected late to be deleted");
+ }
+ {
+ TestStateChanged changed(s);
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::ADD_LATE,"-s 10:10 -a 23:10 -c +23:10")));
+ BOOST_CHECK_MESSAGE( s->get_late(), "expected late to be added");
+
+ // test change late
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::LATE,"-s 10:10 -a 12:00")));
+ BOOST_CHECK_MESSAGE( s->get_late() && s->get_late()->toString() == "late -s +10:10 -a 12:00", "expected 'late -s +10:10 -a 12:00' but found " << s->get_late()->toString());
+
+ // test delete variable
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_LATE)));
+ BOOST_CHECK_MESSAGE( !s->get_late(), "expected late to be deleted");
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_alter_cmd_errors )
+{
+ cout << "Base:: ...test_alter_cmd_errors\n";
+
+ Defs defs;
+ suite_ptr s = defs.add_suite("suite");
+ s->add_task("t1");
+
+ { // test add variables
+ TestStateChanged changed(s);
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::ADD_VARIABLE,"FRED1","_val_")));
+ BOOST_CHECK_MESSAGE( s->variables().size() == 1, "expected 1 variable but found " << s->variables().size());
+
+ // test delete variables, with a non existent path
+ TestHelper::invokeFailureRequest(&defs,Cmd_ptr( new AlterCmd("/idont/exist",AlterCmd::DEL_VARIABLE,"FRED1")));
+
+ // ECFLOW-380 test change read only server variables,ECF_NODE, ECF_PORT, ECF_PID, ECF_VERSION, ECF_LISTS
+ TestHelper::invokeFailureRequest(&defs,Cmd_ptr( new AlterCmd("/",AlterCmd::ADD_VARIABLE,"ECF_NODE","a")));
+ TestHelper::invokeFailureRequest(&defs,Cmd_ptr( new AlterCmd("/",AlterCmd::ADD_VARIABLE,"ECF_PORT","a")));
+ TestHelper::invokeFailureRequest(&defs,Cmd_ptr( new AlterCmd("/",AlterCmd::ADD_VARIABLE,"ECF_PID","a")));
+ TestHelper::invokeFailureRequest(&defs,Cmd_ptr( new AlterCmd("/",AlterCmd::ADD_VARIABLE,"ECF_VERSION","a")));
+ TestHelper::invokeFailureRequest(&defs,Cmd_ptr( new AlterCmd("/",AlterCmd::ADD_VARIABLE,"ECF_LISTS","a")));
+
+ TestHelper::invokeFailureRequest(&defs,Cmd_ptr( new AlterCmd("/",AlterCmd::VARIABLE,"ECF_NODE","a")));
+ TestHelper::invokeFailureRequest(&defs,Cmd_ptr( new AlterCmd("/",AlterCmd::VARIABLE,"ECF_PORT","a")));
+ TestHelper::invokeFailureRequest(&defs,Cmd_ptr( new AlterCmd("/",AlterCmd::VARIABLE,"ECF_PID","a")));
+ TestHelper::invokeFailureRequest(&defs,Cmd_ptr( new AlterCmd("/",AlterCmd::VARIABLE,"ECF_VERSION","a")));
+ TestHelper::invokeFailureRequest(&defs,Cmd_ptr( new AlterCmd("/",AlterCmd::VARIABLE,"ECF_LISTS","a")));
+ }
+
+ /// Destroy singleton's to avoid valgrind from complaining
+ System::destroy();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Base/test/TestClientHandleCmd.cpp b/Base/test/TestClientHandleCmd.cpp
new file mode 100644
index 0000000..faffdc2
--- /dev/null
+++ b/Base/test/TestClientHandleCmd.cpp
@@ -0,0 +1,260 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #12 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <boost/test/unit_test.hpp>
+
+#include "ClientToServerCmd.hpp"
+#include "ServerToClientCmd.hpp"
+#include "TestHelper.hpp"
+#include "Suite.hpp"
+
+using namespace std;
+using namespace ecf;
+
+// The client handle commands do not change state & modify change number, hence need to bypass these checks
+static bool bypass_state_modify_change_check = false;
+
+BOOST_AUTO_TEST_SUITE( BaseTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_client_handle_cmd_empty_server )
+{
+ cout << "Base:: ...test_client_handle_cmd_empty_server\n";
+
+ std::vector<std::string> suite_names; suite_names.reserve(5);
+ for(int i=0; i < 5; i++) suite_names.push_back( "s" + boost::lexical_cast<std::string>(i) );
+
+ defs_ptr new_defs = Defs::create();
+
+ // Register new handle on an EMPTY server. register the suite
+ for(size_t j = 0; j < suite_names.size(); j++) {
+ std::vector<std::string> names; names.push_back(suite_names[j]);
+ TestHelper::invokeRequest(new_defs.get(),Cmd_ptr( new ClientHandleCmd(names,false)),bypass_state_modify_change_check);
+ }
+
+ // We should have 5 handle, 1,2,3,4,5
+
+ //std::cout << " expect failure when dropping(DROP_USER) on handle that does not exist, handle 6" << endl;
+ TestHelper::invokeFailureRequest(new_defs.get(),Cmd_ptr( new ClientHandleCmd(6)));
+
+ //std::cout << " expect failure for auto add,on handle that does not exist, handle 6" << endl;
+ TestHelper::invokeFailureRequest(new_defs.get(),Cmd_ptr( new ClientHandleCmd(6,true /* auto add */)));
+
+ //std::cout << " expect failure for ADD,on handle that does not exist, handle 6" << endl;
+ TestHelper::invokeFailureRequest(new_defs.get(),Cmd_ptr( new ClientHandleCmd(6,suite_names,ClientHandleCmd::ADD)));
+
+ //std::cout << " expect failure for REMOVE, on handle that does not exist, handle 6" << endl;
+ TestHelper::invokeFailureRequest(new_defs.get(),Cmd_ptr( new ClientHandleCmd(6,suite_names,ClientHandleCmd::REMOVE)));
+
+ for(int handle=1; handle < 6; handle++) {
+
+ //std::cout << " expect success for dropping handle " << handle << endl;
+ TestHelper::invokeRequest(new_defs.get(),Cmd_ptr( new ClientHandleCmd(handle)),bypass_state_modify_change_check);
+
+ //std::cout << " expect failure for auto add,on handle that does not exist, handle " << handle << endl;
+ TestHelper::invokeFailureRequest(new_defs.get(),Cmd_ptr( new ClientHandleCmd(6,true /* auto add */)));
+
+ //std::cout << " expect failure for ADD,on handle that does not exist, handle " << handle <<endl;
+ TestHelper::invokeFailureRequest(new_defs.get(),Cmd_ptr( new ClientHandleCmd(6,suite_names,ClientHandleCmd::ADD)));
+
+ //std::cout << " expect failure for REMOVE, on handle that does not exist, handle " << handle << "\n" << endl;
+ TestHelper::invokeFailureRequest(new_defs.get(),Cmd_ptr( new ClientHandleCmd(6,suite_names,ClientHandleCmd::REMOVE)));
+ }
+}
+
+
+BOOST_AUTO_TEST_CASE( test_client_handle_cmd_register_and_drop )
+{
+ cout << "Base:: ...test_client_handle_cmd_register_and_drop\n";
+
+ std::vector<std::string> suite_names; suite_names.reserve(6);
+ for(int i=0; i < 5; i++) suite_names.push_back( "s" + boost::lexical_cast<std::string>(i) );
+
+ Defs defs;
+ for(size_t j = 0; j < suite_names.size(); j++) defs.addSuite( Suite::create(suite_names[j]) );
+
+ // Register new handle
+ for(size_t j = 0; j < suite_names.size(); j++) {
+ std::vector<std::string> names; names.push_back(suite_names[j]);
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new ClientHandleCmd(names,false)),bypass_state_modify_change_check);
+ BOOST_CHECK_MESSAGE(defs.client_suite_mgr().clientSuites().size() == j+1,"Expected " << j+1 << " Client suites but found " << defs.client_suite_mgr().clientSuites().size());
+ }
+
+ // Drop the handles. take a copy, since we about to delete clientSuites
+ std::vector<ecf::ClientSuites> clientSuites = defs.client_suite_mgr().clientSuites();
+ for(size_t k =0; k< clientSuites.size(); k++) {
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new ClientHandleCmd( clientSuites[k].handle() )),bypass_state_modify_change_check);
+ }
+ BOOST_CHECK_MESSAGE(defs.client_suite_mgr().clientSuites().empty(),"Expected no client handles, but found " << defs.client_suite_mgr().clientSuites().size());
+}
+
+
+BOOST_AUTO_TEST_CASE( test_client_handle_cmd_auto_add )
+{
+ cout << "Base:: ...test_client_handle_cmd_auto_add\n";
+
+ std::vector<std::string> suite_names; suite_names.reserve(6);
+ for(int i=0; i < 5; i++) suite_names.push_back( "s" + boost::lexical_cast<std::string>(i) );
+
+ Defs defs;
+ for(size_t j = 0; j < suite_names.size(); j++) defs.addSuite( Suite::create(suite_names[j]) );
+
+ // Register new handle, with no suites, but with auto add new suites
+ std::vector<std::string> names;
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new ClientHandleCmd(names,false/* auto_add */)),bypass_state_modify_change_check);
+ BOOST_CHECK_MESSAGE(defs.client_suite_mgr().clientSuites().size() == 1,"Expected 1 Client suites but found " << defs.client_suite_mgr().clientSuites().size());
+ BOOST_CHECK_MESSAGE(defs.client_suite_mgr().clientSuites().front().auto_add_new_suites() == false,"Expected auto add to be disabled");
+
+ // Now enable auto add
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new ClientHandleCmd(defs.client_suite_mgr().clientSuites().front().handle(),true /* auto add */)),bypass_state_modify_change_check);
+ BOOST_CHECK_MESSAGE(defs.client_suite_mgr().clientSuites().front().auto_add_new_suites(),"Expected auto add to be enabled");
+
+ // now add new suite, they should get added to the new client handles
+ names.clear();
+ for(int i=5; i < 10; i++) names.push_back( "s" + boost::lexical_cast<std::string>(i) );
+ for(size_t j = 0; j < names.size(); j++) defs.addSuite( Suite::create(names[j]) );
+
+ std::vector<ecf::ClientSuites> clientSuites = defs.client_suite_mgr().clientSuites();
+ std::vector<std::string> handle_suites;
+ clientSuites[0].suites(handle_suites);
+ BOOST_CHECK_MESSAGE(handle_suites == names ,"Expected suites to be automatically added to our handle");
+
+ // Delete the suite s5,s6,s7,s8,s9
+ for(int i=5; i < 10; i++) {
+ suite_ptr suite = defs.findSuite("s" + boost::lexical_cast<std::string>(i));
+ BOOST_CHECK_MESSAGE(suite.get(),"Failed to find suite s" << i);
+ suite->remove();
+ }
+
+ { // Even when suites have been removed, we still keep registered suite
+ // These have to be explicitly deleted by the user
+ std::vector<ecf::ClientSuites> clientSuites = defs.client_suite_mgr().clientSuites();
+ std::vector<std::string> handle_suites;
+ clientSuites[0].suites(handle_suites);
+ BOOST_CHECK_MESSAGE(handle_suites.size() == 5,"Expected handle to have 5 suites but found" << handle_suites.size());
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_client_handle_cmd_add_remove )
+{
+ cout << "Base:: ...test_client_handle_cmd_add_remove\n";
+
+ std::vector<std::string> suite_names; suite_names.reserve(6);
+ for(int i=0; i < 5; i++) suite_names.push_back( "s" + boost::lexical_cast<std::string>(i) );
+
+ defs_ptr defs = Defs::create();
+ for(size_t j = 0; j < suite_names.size(); j++) defs->addSuite( Suite::create(suite_names[j]) );
+ std::vector<std::string> empty_vec;
+
+ // Register new handle, with no suites,
+ {
+ TestHelper::invokeRequest(defs.get(),Cmd_ptr( new ClientHandleCmd(empty_vec,false)),bypass_state_modify_change_check);
+ BOOST_CHECK_MESSAGE(defs->client_suite_mgr().clientSuites().size() == 1,"Expected 1 Client suites but found " << defs->client_suite_mgr().clientSuites().size());
+ BOOST_CHECK_MESSAGE(!defs->client_suite_mgr().handle_changed(1),"Expected No handle change, when no real suites added");
+
+ defs_ptr created_defs = defs->client_suite_mgr().create_defs(1,defs); // clear the handle change
+ BOOST_CHECK_MESSAGE(created_defs,"Expected defs to be created");
+ BOOST_CHECK_MESSAGE(created_defs->suiteVec().empty(),"Expected no suites");
+ BOOST_CHECK_MESSAGE(!defs->client_suite_mgr().handle_changed(1),"Expected handle changed to be cleared after create_defs()");
+ }
+
+ // Now add suites to the existing handle, then check they match.
+ std::vector<std::string> handle_suites;
+ {
+ TestHelper::invokeRequest(defs.get(),Cmd_ptr( new ClientHandleCmd(defs->client_suite_mgr().clientSuites().front().handle(),suite_names,ClientHandleCmd::ADD)),bypass_state_modify_change_check);
+ defs->client_suite_mgr().clientSuites().front().suites(handle_suites);
+ BOOST_CHECK_MESSAGE(handle_suites == suite_names ,"Expected suites to be added to our handle");
+ BOOST_CHECK_MESSAGE(defs->client_suite_mgr().handle_changed(1),"Expected handle changed when adding new suites to our handle");
+
+ defs_ptr created_defs = defs->client_suite_mgr().create_defs(1,defs); // clear the handle change
+ BOOST_CHECK_MESSAGE(created_defs,"Expected defs to be created");
+ BOOST_CHECK_MESSAGE(created_defs.get() == defs.get(),"When *ALL* suites registered, the returned defs should be the same");
+ BOOST_CHECK_MESSAGE(created_defs->suiteVec().size() == suite_names.size(),"Not all suites created");
+ }
+
+ // Now remove the suites from the handle
+ {
+ TestHelper::invokeRequest(defs.get(),Cmd_ptr( new ClientHandleCmd(defs->client_suite_mgr().clientSuites().front().handle(),suite_names,ClientHandleCmd::REMOVE)),bypass_state_modify_change_check);
+ handle_suites.clear();
+ defs->client_suite_mgr().clientSuites().front().suites(handle_suites);
+ BOOST_CHECK_MESSAGE(handle_suites == empty_vec ,"Expected no suites in our handle but found " << handle_suites.size());
+ BOOST_CHECK_MESSAGE(defs->client_suite_mgr().handle_changed(1),"Expected handle changed when adding new removing suites");
+
+ defs_ptr created_defs = defs->client_suite_mgr().create_defs(1,defs); // clear the handle change
+ BOOST_CHECK_MESSAGE(created_defs,"Expected defs to be created");
+ BOOST_CHECK_MESSAGE(created_defs->suiteVec().empty(),"Expected no suites");
+ BOOST_CHECK_MESSAGE(!defs->client_suite_mgr().handle_changed(1),"Expected handle changed to be cleared after create_defs()");
+ }
+}
+
+static bool check_ordering(Defs& defs)
+{
+ // make sure order of suites in handles is the same as server order
+ const std::vector<suite_ptr>& suite_vec = defs.suiteVec();
+ std::vector<std::string> suite_names;
+ for(size_t i = 0; i < suite_vec.size(); i++) suite_names.push_back(suite_vec[i]->name());
+
+ // Drop the handles. take a copy, since we about to delete clientSuites
+ std::vector<ecf::ClientSuites> clientSuites = defs.client_suite_mgr().clientSuites();
+ for(size_t k =0; k< clientSuites.size(); k++) {
+ std::vector<std::string> names; names.reserve(6);
+ clientSuites[k].suites(names);
+ if (names != suite_names) return false;
+ }
+ return true;
+}
+
+BOOST_AUTO_TEST_CASE( test_client_handle_suite_ordering )
+{
+ cout << "Base:: ...test_client_handle_suite_ordering\n";
+ // ensure order of suites in a handle is the same as server suites
+
+ std::vector<std::string> suite_names; suite_names.reserve(6);
+ for(int i=0; i < 5; i++) suite_names.push_back( "s" + boost::lexical_cast<std::string>(i) );
+
+ Defs defs;
+ for(size_t j = 0; j < suite_names.size(); j++) defs.addSuite( Suite::create(suite_names[j]) );
+
+ // Register 3 new handle
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new ClientHandleCmd(suite_names,true)),bypass_state_modify_change_check);
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new ClientHandleCmd(suite_names,true)),bypass_state_modify_change_check);
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new ClientHandleCmd(suite_names,true)),bypass_state_modify_change_check);
+ BOOST_CHECK_MESSAGE(defs.client_suite_mgr().clientSuites().size() == 3,"Expected 3 Client suites but found " << defs.client_suite_mgr().clientSuites().size());
+
+ // After registration make sure ordering is the same
+ BOOST_CHECK_MESSAGE(check_ordering(defs),"Ordering not preserved after registration of handles");
+
+
+ // Check ordering after OrderNodeCmd
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new OrderNodeCmd("/s0",NOrder::DOWN)));
+ BOOST_CHECK_MESSAGE(check_ordering(defs),"Ordering not preserved after NOrder::DOWN");
+
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new OrderNodeCmd("/s0",NOrder::UP)));
+ BOOST_CHECK_MESSAGE(check_ordering(defs),"Ordering not preserved after NOrder::UP");
+
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new OrderNodeCmd("/s0",NOrder::BOTTOM)));
+ BOOST_CHECK_MESSAGE(check_ordering(defs),"Ordering not preserved after NOrder::BOTTOM");
+
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new OrderNodeCmd("/s0",NOrder::TOP)));
+ BOOST_CHECK_MESSAGE(check_ordering(defs),"Ordering not preserved after NOrder::TOP");
+
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new OrderNodeCmd("/s0",NOrder::ALPHA)));
+ BOOST_CHECK_MESSAGE(check_ordering(defs),"Ordering not preserved after NOrder::ALPHA");
+
+
+ // check ordering after adding new suites, notice we auto add new suites to all our handles
+ defs.add_suite("sxx");
+ BOOST_CHECK_MESSAGE(check_ordering(defs),"Ordering not preserved after adding a new suite");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Base/test/TestCmd.cpp b/Base/test/TestCmd.cpp
new file mode 100644
index 0000000..1108cea
--- /dev/null
+++ b/Base/test/TestCmd.cpp
@@ -0,0 +1,109 @@
+ //============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #23 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <boost/test/unit_test.hpp>
+#include <boost/foreach.hpp>
+#include <string>
+#include <iostream>
+#include <fstream>
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "TestHelper.hpp"
+#include "System.hpp"
+#include "Str.hpp"
+
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( BaseTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_simple_cmd )
+{
+ cout << "Base:: ...test_simple_cmd\n";
+ // Create the defs file. Note that the default ECF_TRIES = 3
+ // suite suite
+ // family f
+ // task t1
+ // task t2
+ // endfamily
+ // endsuite
+ Defs defs;
+ string suite_f_t1 = "suite/f/t1";
+ std::string suitename = "suite";
+ family_ptr f = Family::create("f");
+ task_ptr t1 = Task::create("t1");
+ task_ptr t2 = Task::create("t2");
+ suite_ptr s = Suite::create(suitename);
+ {
+ f->addTask( t1 );
+ f->addTask( t2 );
+ s->addFamily(f);
+ defs.addSuite( s );
+ }
+
+ // ***********************************************************************
+ // Create a request to begin suite
+ // make sure chosen suite can begin to resolve dependencies.
+ // beginning the suite will:
+ // 1/ set all children to the QUEUED state
+ // 2/ Begin job submission, and hence changes state to ACTIVE for submitted jobs
+ {
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new BeginCmd(suitename,false)));
+ BOOST_CHECK_MESSAGE( s->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(s->state()));
+ BOOST_CHECK_MESSAGE( f->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f->state()));
+ BOOST_CHECK_MESSAGE( t1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(t1->state()));
+ BOOST_CHECK_MESSAGE( t2->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(t2->state()));
+ }
+
+
+ // ***********************************************************************
+ // Create a request to abort Node: suite1/f/t1, Since the default ECF_TRIES is > 0, the aborted tasks
+ // should be re-submitted, until the task try number > ECF_TRIES
+ {
+ std::string varValue;
+ if (t1->findParentUserVariableValue( Str::ECF_TRIES(), varValue )) {
+ int ecf_tries = boost::lexical_cast< int > (varValue);
+ while (1) {
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AbortCmd(suite_f_t1,Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1)));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new CtsCmd( CtsCmd::FORCE_DEP_EVAL)));
+ BOOST_CHECK_MESSAGE( t1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(t1->state()));
+ BOOST_CHECK_MESSAGE( f->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f->state()));
+ BOOST_CHECK_MESSAGE( s->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(s->state()));
+ //std::cout << "tryNo = " << t1->try_no() << " ECF_TRIES = " << ecf_tries << "\n";
+ if ( t1->try_no() == ecf_tries) break;
+ }
+
+ /// Since we have exceeded the try number, abort should mean abort
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new AbortCmd(suite_f_t1,Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1)));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new CtsCmd( CtsCmd::FORCE_DEP_EVAL)),false);
+ BOOST_CHECK_MESSAGE( t1->state() == NState::ABORTED, "expected state NState::ABORTED, but found to be " << NState::toString(t1->state()));
+ BOOST_CHECK_MESSAGE( f->state() == NState::ABORTED, "expected state NState::ABORTED, but found to be " << NState::toString(f->state()));
+ BOOST_CHECK_MESSAGE( s->state() == NState::ABORTED, "expected state NState::ABORTED, but found to be " << NState::toString(s->state()));
+ }
+ }
+
+ {
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE( defs.checkInvariants(errorMsg), errorMsg);
+ }
+
+ /// Destroy System singleton to avoid valgrind from complaining
+ System::destroy();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/Base/test/TestDeleteNodeCmd.cpp b/Base/test/TestDeleteNodeCmd.cpp
new file mode 100644
index 0000000..59fc5fb
--- /dev/null
+++ b/Base/test/TestDeleteNodeCmd.cpp
@@ -0,0 +1,198 @@
+//============================================================================
+// Name : Request
+// Author : Avi
+// Revision : $Revision: #16 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+
+#include "ClientToServerCmd.hpp"
+#include "ServerToClientCmd.hpp"
+#include "MyDefsFixture.hpp"
+#include "TestHelper.hpp"
+#include "DefsStructureParser.hpp"
+#include "DurationTimer.hpp"
+#include "Str.hpp"
+
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( BaseTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_delete_node_cmd )
+{
+ cout << "Base:: ...test_delete_node_cmd\n";
+
+ MyDefsFixture fixtureDef;
+ MockServer mockServer(&fixtureDef.defsfile_);
+
+ // IMPORTANT: ******************************************************************************
+ // If the PathsCmd is given a EMPTY list of paths, it will delete *EVERYTHING*
+ // *****************************************************************************************
+
+ // Delete all Aliases
+ {
+ std::vector<alias_ptr> vec;
+ fixtureDef.defsfile_.get_all_aliases(vec);
+ BOOST_CHECK_MESSAGE( vec.size() > 0,"Expected > 0 aliases but found " << vec.size());
+
+ std::vector<std::string> paths; paths.reserve(vec.size());
+ BOOST_FOREACH(alias_ptr t, vec) { paths.push_back(t->absNodePath()); }
+
+ size_t edit_history_size_before = fixtureDef.defsfile_.get_edit_history(Str::ROOT_PATH()).size();
+ BOOST_CHECK_MESSAGE( !paths.empty(),"Expected paths to be specified, *OTHERWISE* we delete all nodes");
+ PathsCmd cmd(PathsCmd::DELETE,paths);
+ cmd.setup_user_authentification();
+ STC_Cmd_ptr returnCmd = cmd.handleRequest( &mockServer );
+ BOOST_CHECK_MESSAGE(returnCmd->ok(),"Failed to delete aliases");
+ {
+ // ECFLOW-434
+ const std::deque<std::string>& edit_history = fixtureDef.defsfile_.get_edit_history(Str::ROOT_PATH());
+ size_t edit_history_size_after = edit_history_size_before + paths.size();
+ if ( edit_history_size_after > Defs::max_edit_history_size_per_node())
+ edit_history_size_after = Defs::max_edit_history_size_per_node();
+ BOOST_CHECK_MESSAGE( edit_history.size() == edit_history_size_after, "Expected " << edit_history_size_after << " edit history but found " << edit_history.size());
+ }
+
+ std::vector<alias_ptr> afterDeleteVec;
+ fixtureDef.defsfile_.get_all_aliases(afterDeleteVec);
+ BOOST_REQUIRE_MESSAGE( afterDeleteVec.empty(),"Expected all aliases to be deleted but found " << afterDeleteVec.size());
+ }
+
+ // Delete all tasks
+ {
+ std::vector<Task*> vec;
+ fixtureDef.defsfile_.getAllTasks(vec);
+ BOOST_CHECK_MESSAGE( vec.size() > 0,"Expected > 0 tasks but found " << vec.size());
+
+ std::vector<std::string> paths; paths.reserve(vec.size());
+ BOOST_FOREACH(Task* t, vec) { paths.push_back(t->absNodePath()); }
+
+ BOOST_CHECK_MESSAGE( !paths.empty(),"Expected paths to be specified, *OTHERWISE* we delete all nodes");
+ size_t edit_history_size_before = fixtureDef.defsfile_.get_edit_history(Str::ROOT_PATH()).size();
+ PathsCmd cmd(PathsCmd::DELETE,paths);
+ cmd.setup_user_authentification();
+ STC_Cmd_ptr returnCmd = cmd.handleRequest( &mockServer );
+ BOOST_CHECK_MESSAGE(returnCmd->ok(),"Failed to delete tasks");
+ {
+ const std::deque<std::string>& edit_history = fixtureDef.defsfile_.get_edit_history(Str::ROOT_PATH());
+ size_t edit_history_size_after = edit_history_size_before + paths.size();
+ if ( edit_history_size_after > Defs::max_edit_history_size_per_node())
+ edit_history_size_after = Defs::max_edit_history_size_per_node();
+ BOOST_CHECK_MESSAGE( edit_history.size() == edit_history_size_after, "Expected " << edit_history_size_after << " edit history but found " << edit_history.size());
+ }
+
+
+ std::vector<Task*> afterDeleteVec;
+ fixtureDef.defsfile_.getAllTasks(afterDeleteVec);
+ BOOST_REQUIRE_MESSAGE( afterDeleteVec.empty(),"Expected all tasks to be deleted but found " << afterDeleteVec.size());
+ }
+
+ // Delete all Families
+ {
+ // DONT use getAllFamilies as this will return hierarchical families
+ // we don't want to delete families twice
+ // std::vector<Family*> vec;
+ // fixtureDef.defsfile_.getAllFamilies(vec);
+ }
+
+ // Delete all Suites
+ {
+ std::vector<suite_ptr> vec = fixtureDef.defsfile_.suiteVec();
+ BOOST_CHECK_MESSAGE( vec.size() > 0,"Expected > 0 Suites but found " << vec.size());
+ BOOST_FOREACH(suite_ptr s, vec) {
+ {
+ // Delete all Families
+ // *********************************************************************************************
+ // **EXPLICITLY** check for empty paths otherwise we can end up deleting ALL suites accidentally
+ // if PathsCmd is given an empty list, we will delete all nodes including the suites
+ // *********************************************************************************************
+ std::vector<family_ptr> familyVec = s->familyVec();
+ // DONT USE:
+ // BOOST_FOREACH(family_ptr f, s->familyVec()) {
+ // As with this will invalidate the iterators.
+ std::vector<std::string> paths; paths.reserve(vec.size());
+ BOOST_FOREACH(family_ptr f, familyVec) { paths.push_back(f->absNodePath()); }
+
+ if (!paths.empty()) {
+ size_t edit_history_size_before = fixtureDef.defsfile_.get_edit_history(Str::ROOT_PATH()).size();
+ PathsCmd cmd(PathsCmd::DELETE,paths);
+ cmd.setup_user_authentification();
+ STC_Cmd_ptr returnCmd = cmd.handleRequest( &mockServer );
+ BOOST_CHECK_MESSAGE(returnCmd->ok(),"Failed to delete families");
+ BOOST_REQUIRE_MESSAGE( s->familyVec().empty(),"Expected all Families to be deleted but found " << s->familyVec().size());
+ {
+ const std::deque<std::string>& edit_history = fixtureDef.defsfile_.get_edit_history(Str::ROOT_PATH());
+ size_t edit_history_size_after = edit_history_size_before + paths.size();
+ if ( edit_history_size_after > Defs::max_edit_history_size_per_node())
+ edit_history_size_after = Defs::max_edit_history_size_per_node();
+ BOOST_CHECK_MESSAGE( edit_history.size() == edit_history_size_after, "Expected " << edit_history_size_after << " edit history but found " << edit_history.size());
+ }
+ }
+ }
+
+ // delete the suite
+ size_t edit_history_size_before = fixtureDef.defsfile_.get_edit_history(Str::ROOT_PATH()).size();
+ std::string absNodePath = s->absNodePath();
+ PathsCmd cmd(PathsCmd::DELETE,absNodePath);
+ cmd.setup_user_authentification();
+ STC_Cmd_ptr returnCmd = cmd.handleRequest( &mockServer );
+ BOOST_CHECK_MESSAGE(returnCmd->ok(),"Failed to delete suite at path " << absNodePath);
+ {
+ const std::deque<std::string>& edit_history = fixtureDef.defsfile_.get_edit_history(Str::ROOT_PATH());
+ size_t edit_history_size_after = edit_history_size_before + 1;
+ if ( edit_history_size_after > Defs::max_edit_history_size_per_node())
+ edit_history_size_after = Defs::max_edit_history_size_per_node();
+ BOOST_CHECK_MESSAGE( edit_history.size() == edit_history_size_after, "Expected " << edit_history_size_after << " edit history but found " << edit_history.size());
+ }
+ }
+
+ BOOST_REQUIRE_MESSAGE( fixtureDef.defsfile_.suiteVec().empty(),"Expected all Suites to be deleted but found " << fixtureDef.defsfile_.suiteVec().size());
+ }
+}
+
+// Will break for valgrind hence commented out
+//BOOST_AUTO_TEST_CASE( test_delete_cmd_for_defs )
+//{
+// std::string path_to_very_large_defs_file = "/var/tmp/ma0/BIG_DEFS/3199.def";
+// cout << "Base:: ...test_delete_cmd_for_defs " << path_to_very_large_defs_file;
+//
+// // Ok will only run locally, so don't fail, for other platforms
+// if (!fs::exists(path_to_very_large_defs_file)) cout << " ... missing test\n";
+// else {
+// Defs defs;
+// {
+// DurationTimer duration_timer;
+// DefsStructureParser checkPtParser( &defs, path_to_very_large_defs_file);
+// std::string errorMsg,warningMsg;
+// BOOST_REQUIRE_MESSAGE(checkPtParser.doParse(errorMsg,warningMsg),"failed to parse 3199.def");
+// cout << " ...Loading took " << duration_timer.duration();
+// BOOST_CHECK_MESSAGE( duration_timer.duration() < 20,"Loading defs "
+// << path_to_very_large_defs_file << " took " << duration_timer.duration() << " Expected to take < 20 seconds");
+// }
+//
+// DurationTimer duration_timer;
+// MockServer mockServer(&defs);
+// PathsCmd cmd(PathsCmd::DELETE,"",true);
+// cmd.setup_user_authentification();
+// STC_Cmd_ptr returnCmd = cmd.handleRequest( &mockServer );
+// BOOST_CHECK_MESSAGE(returnCmd->ok(),"Failed to delete defs");
+// cout << " ...Deleting took " << duration_timer.duration() << "\n";
+// BOOST_CHECK_MESSAGE( duration_timer.duration() < 2,"Deleting defs "
+// << path_to_very_large_defs_file << " took " << duration_timer.duration() << " Expected to take < 2 seconds");
+// }
+//}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/Base/test/TestECFLOW-189.cpp b/Base/test/TestECFLOW-189.cpp
new file mode 100644
index 0000000..ef2650c
--- /dev/null
+++ b/Base/test/TestECFLOW-189.cpp
@@ -0,0 +1,85 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #23 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <boost/test/unit_test.hpp>
+
+#include "ClientToServerCmd.hpp"
+#include "ServerToClientCmd.hpp"
+#include "MyDefsFixture.hpp"
+#include "MockServer.hpp"
+#include "TestHelper.hpp"
+#include "System.hpp"
+#include "PrintStyle.hpp"
+#include "Defs.hpp"
+
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( BaseTestSuite )
+
+static defs_ptr create_defs()
+{
+ // suite s1
+ // family f1
+ // trigger f2 == complete
+ // task t1
+ // task t2
+ // endfamily
+ // family f2
+ // task t1
+ // task t2
+ // endfamily
+ // endsuite
+ defs_ptr theDefs = Defs::create();
+ suite_ptr suite = theDefs->add_suite( "s1" ) ;
+ family_ptr f1 = suite->add_family( "f1" ) ;
+ family_ptr f2 = suite->add_family( "f2" ) ;
+ f1->add_trigger("f2 == complete");
+ f1->add_task("t1");
+ f1->add_task("t2");
+ f2->add_task("t1");
+ f2->add_task("t2");
+
+ return theDefs;
+}
+
+BOOST_AUTO_TEST_CASE( test_ECFLOW_189 )
+{
+ cout << "Base:: ...test_ECFLOW_189\n";
+ defs_ptr the_defs = create_defs();
+ the_defs->beginAll();
+ node_ptr s1 = the_defs->findAbsNode("/s1");
+ node_ptr f1 = the_defs->findAbsNode("/s1/f1");
+ node_ptr t1 = the_defs->findAbsNode("/s1/f1/t1");
+ node_ptr t2 = the_defs->findAbsNode("/s1/f1/t2");
+
+ TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new PathsCmd(PathsCmd::SUSPEND, t1->absNodePath())));
+ TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new PathsCmd(PathsCmd::SUSPEND, t2->absNodePath())));
+
+ TestHelper::test_state(t1,DState::SUSPENDED);
+ TestHelper::test_state(t2,DState::SUSPENDED);
+
+ // Now resume /s1/f1/t1 and /s1/f1/t2
+ TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new PathsCmd(PathsCmd::RESUME, t1->absNodePath())));
+
+ // We expect state to be queued since the trigger on /s1/f1 should prevent jobs from running
+ // If we find submitted or aborted(i.e it was free to run, but could not generate the jobs), then its an error
+ TestHelper::test_state(t1,NState::QUEUED);
+ TestHelper::test_state(t2,NState::QUEUED);
+
+ /// Destroy System singleton to avoid valgrind from complaining
+ System::destroy();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Base/test/TestForceCmd.cpp b/Base/test/TestForceCmd.cpp
new file mode 100644
index 0000000..661df05
--- /dev/null
+++ b/Base/test/TestForceCmd.cpp
@@ -0,0 +1,920 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #23 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <boost/test/unit_test.hpp>
+
+#include "ClientToServerCmd.hpp"
+#include "ServerToClientCmd.hpp"
+#include "MyDefsFixture.hpp"
+#include "MockServer.hpp"
+#include "TestHelper.hpp"
+#include "System.hpp"
+#include "PrintStyle.hpp"
+
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( BaseTestSuite )
+
+static defs_ptr create_defs()
+{
+ defs_ptr theDefs = Defs::create();
+ suite_ptr suite = theDefs->add_suite( "s1" ) ;
+ family_ptr f1 = suite->add_family( "f1" ) ;
+ task_ptr t1 = f1->add_task("t1");
+ t1->addTime( TimeAttr(10,30));
+ t1->add_alias_only();
+ task_ptr t2 = f1->add_task("t2");
+ t2->add_alias_only();
+ return theDefs;
+}
+
+BOOST_AUTO_TEST_CASE( test_force_cmd )
+{
+ cout << "Base:: ...test_force_cmd\n";
+ defs_ptr the_defs = create_defs();
+ the_defs->beginAll();
+ node_ptr s1 = the_defs->findAbsNode("/s1");
+ node_ptr f1 = the_defs->findAbsNode("/s1/f1");
+ node_ptr t1 = the_defs->findAbsNode("/s1/f1/t1");
+ node_ptr t2 = the_defs->findAbsNode("/s1/f1/t2");
+
+ TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",true /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(t1,NState::COMPLETE);
+ BOOST_CHECK_MESSAGE(t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be set");
+ BOOST_CHECK_MESSAGE(!f1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be NOT set");
+ BOOST_CHECK_MESSAGE(!s1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be NOT set");
+
+ TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new ForceCmd(t2->absNodePath(),"complete",true /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(t2,NState::COMPLETE);
+ BOOST_CHECK_MESSAGE(!t2->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be NOT set since there are NO time depedencies");
+ BOOST_CHECK_MESSAGE(!f1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be NOT set");
+ BOOST_CHECK_MESSAGE(!s1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be NOT set");
+
+
+ TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new ForceCmd(s1->absNodePath(),"complete",true /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(s1,NState::COMPLETE);
+ TestHelper::test_state(f1,NState::COMPLETE);
+ TestHelper::test_state(t1,NState::COMPLETE);
+
+ int clear_suspended_in_child_nodes = 0;
+ s1->requeue(true,clear_suspended_in_child_nodes,false);
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear after requeue");
+ BOOST_CHECK_MESSAGE(!t2->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear after requeue");
+ BOOST_CHECK_MESSAGE(!f1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear after requeue");
+ BOOST_CHECK_MESSAGE(!s1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear after requeue");
+
+ node_ptr alias = the_defs->findAbsNode("/s1/f1/t1/alias0");
+ TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new ForceCmd(alias->absNodePath(),"complete",true /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(alias,NState::COMPLETE);
+}
+
+
+static void doForce(MockServer& mockServer,
+ Node* node,
+ const std::string& stateOrEvent,
+ const std::vector<Node*>& nodes)
+{
+ ForceCmd cmd(node->absNodePath(), stateOrEvent, true /*recursive */, true /* set Repeat to last value */);
+ cmd.setup_user_authentification();
+ STC_Cmd_ptr returnCmd = cmd.handleRequest( &mockServer );
+ BOOST_REQUIRE_MESSAGE(returnCmd->ok(),"Failed to force for node " << node->debugNodePath());
+
+ for(size_t i = 0; i < nodes.size(); i++) {
+ if (NState::isValid(stateOrEvent)) {
+ NState::State state = NState::toState(stateOrEvent);
+
+ // Force Cmd recursive does **NOT** apply to aliases.
+ if (nodes[i]->isAlias()) {
+ // The alias should still be in default QUEUED state
+ BOOST_CHECK_MESSAGE( nodes[i]->state() == NState::QUEUED, "Expected state NState::QUEUED for alias but found " << NState::toString(nodes[i]->state()) << " for alias " << nodes[i]->debugNodePath());
+ }
+ else {
+ BOOST_CHECK_MESSAGE( nodes[i]->state() == state, "Expected state " << NState::toString(state) << " but found " << NState::toString(nodes[i]->state()) << " for node " << nodes[i]->debugNodePath());
+ }
+ }
+ else BOOST_CHECK_MESSAGE(false, "oops");
+
+ if (!(nodes[i]->repeat().empty())) {
+ BOOST_CHECK_MESSAGE( !nodes[i]->repeat().valid(), "Expected repeat to be set to last value. ie in valid");
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_force_cmd_recursive )
+{
+ cout << "Base:: ...test_force_cmd_recursive\n";
+
+ defs_ptr the_defs = create_defs();
+ node_ptr suite = the_defs->findAbsNode("/s1");
+ std::vector<Node*> nodes;
+ suite->getAllNodes(nodes);
+
+ MockServer mockServer(the_defs);
+ std::vector< std::string > all_states = NState::allStates();
+ BOOST_FOREACH(const std::string& state, all_states) {
+ doForce(mockServer,suite.get(),state,nodes);
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_force_cmd_bubbles_up_state_changes )
+{
+ cout << "Base:: ...test_force_cmd_bubbles_up_state_changes\n";
+
+ defs_ptr the_defs = create_defs();
+ std::vector<Node*> nodes;
+ std::vector<Task*> tasks;
+ the_defs->getAllNodes(nodes);
+ the_defs->getAllTasks(tasks);
+ node_ptr suite = the_defs->findAbsNode("/s1");
+
+ MockServer mockServer(the_defs);
+
+ std::vector< std::string > all_states = NState::allStates();
+ BOOST_FOREACH(const std::string& state, all_states) {
+
+ // cout << "Setting all tasks to state " << state << "\n";
+ BOOST_FOREACH(Task* task, tasks) {
+ ForceCmd cmd(task->absNodePath(), state, false /*recursive */, false /* set Repeat to last value */);
+ cmd.setup_user_authentification();
+ STC_Cmd_ptr returnCmd = cmd.handleRequest( &mockServer );
+ BOOST_REQUIRE_MESSAGE(returnCmd->ok(),"Failed to force for node " << task->debugNodePath());
+ }
+
+ // Check that state change set on task has bubbled up to the suite.
+ // Since the state has been set on *all* tasks
+ // cout << "Suite state = " << NState::toString(suite->state()) << "\n";
+ NState::State expected_state = NState::toState(state);
+ BOOST_CHECK_MESSAGE( suite->state() == expected_state, "Expected state " << NState::toString(expected_state) << " but found " << NState::toString(suite->state()) << " for suite " << suite->debugNodePath());
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_force_cmd_alias_does_not_bubble_up_state_changes )
+{
+ cout << "Base:: ...test_force_cmd_alias_does_not_bubble_up_state_changes\n";
+
+ defs_ptr the_defs = create_defs();
+ std::vector<Node*> nodes;
+ std::vector<alias_ptr> aliases;
+ the_defs->getAllNodes(nodes);
+ the_defs->get_all_aliases(aliases);
+ node_ptr suite = the_defs->findAbsNode("/s1");
+
+ // initialize by setting all nodes to state QUEUED
+ BOOST_FOREACH(Node* n, nodes) { n->set_state(NState::QUEUED); }
+
+ MockServer mockServer(the_defs);
+ std::vector< std::string > all_states = NState::allStates();
+ BOOST_FOREACH(const std::string& state, all_states) {
+
+ BOOST_FOREACH(alias_ptr alias, aliases) {
+ ForceCmd cmd(alias->absNodePath(), state, false /*recursive */, false /* set Repeat to last value */);
+ cmd.setup_user_authentification();
+ STC_Cmd_ptr returnCmd = cmd.handleRequest( &mockServer );
+ BOOST_REQUIRE_MESSAGE(returnCmd->ok(),"Failed to force for alias " << alias->debugNodePath());
+ }
+
+ // Check that state change set on alias has *NOT* bubbled up to the suite.
+ BOOST_CHECK_MESSAGE( suite->state() == NState::QUEUED, "Expected suite to have state QUEUED but found " << NState::toString(suite->state()));
+ }
+}
+
+
+BOOST_AUTO_TEST_CASE( test_force_events )
+{
+ cout << "Base:: ...test_force_events\n";
+
+ MyDefsFixture fixtureDef;
+ MockServer mockServer(&fixtureDef.defsfile_);
+
+ node_ptr suite = fixtureDef.fixtureDefsFile().findAbsNode("/suiteName");
+ BOOST_REQUIRE_MESSAGE( suite.get(), "Could not find suite");
+ std::vector<Node*> nodes;
+ suite->getAllNodes(nodes);
+
+ /// Set and clear events
+ BOOST_FOREACH(Node* node, nodes) {
+ BOOST_FOREACH(const Event& e, node->events()) {
+ std::string path = node->absNodePath() + ":" + e.name_or_number();
+ ForceCmd cmd(path, Event::SET(), false /*recursive */, false /* set Repeat to last value */);
+ cmd.setup_user_authentification();
+ STC_Cmd_ptr returnCmd = cmd.handleRequest( &mockServer );
+ BOOST_REQUIRE_MESSAGE(returnCmd->ok(),"Failed to force event for node " << node->debugNodePath());
+ }
+ BOOST_FOREACH(const Event& e, node->events()) {
+ BOOST_CHECK_MESSAGE(e.value(), "Event not set as expected for node " << node->debugNodePath());
+ }
+ }
+ BOOST_FOREACH(Node* node, nodes) {
+ BOOST_FOREACH(const Event& e, node->events()) {
+ std::string path = node->absNodePath() + ":" + e.name_or_number();
+ ForceCmd cmd(path, Event::CLEAR(), false /*recursive */, false /* set Repeat to last value */);
+ cmd.setup_user_authentification();
+ STC_Cmd_ptr returnCmd = cmd.handleRequest( &mockServer );
+ BOOST_REQUIRE_MESSAGE(returnCmd->ok(),"Failed to force event for node " << node->debugNodePath());
+ }
+ BOOST_FOREACH(const Event& e, node->events()) {
+ BOOST_CHECK_MESSAGE(!e.value(), "Event not cleared as expected for node " << node->debugNodePath());
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_force_events_errors )
+{
+ cout << "Base:: ...test_force_events_errors\n";
+
+ MyDefsFixture fixtureDef;
+ MockServer mockServer(&fixtureDef.defsfile_);
+
+ node_ptr suite = fixtureDef.fixtureDefsFile().findAbsNode("/suiteName");
+ BOOST_REQUIRE_MESSAGE( suite.get(), "Could not find suite");
+ std::vector<Node*> nodes;
+ suite->getAllNodes(nodes);
+
+ /// Make a path that does not exist
+ BOOST_FOREACH(Node* node, nodes) {
+ BOOST_FOREACH(const Event& e, node->events()) {
+ std::string path = node->absNodePath() + "/path/doesnot/exist" + ":" + e.name_or_number();
+ ForceCmd cmd(path, Event::SET(), false /*recursive */, false /* set Repeat to last value */);
+ cmd.setup_user_authentification();
+ BOOST_REQUIRE_THROW(cmd.handleRequest( &mockServer ) , std::runtime_error);
+ }
+ }
+ BOOST_FOREACH(Node* node, nodes) {
+ BOOST_FOREACH(const Event& e, node->events()) {
+ std::string path = node->absNodePath() + "/path/doesnot/exist" + ":" + e.name_or_number();
+ ForceCmd cmd(path, Event::CLEAR(), false /*recursive */, false /* set Repeat to last value */);
+ cmd.setup_user_authentification();
+ BOOST_REQUIRE_THROW(cmd.handleRequest( &mockServer ) , std::runtime_error);
+ }
+ }
+
+ /// Make path that does not contain a event
+ BOOST_FOREACH(Node* node, nodes) {
+ if (node->events().empty()) {
+ std::string path = node->absNodePath() ;
+ ForceCmd cmd(path, Event::SET(), false /*recursive */, false /* set Repeat to last value */);
+ cmd.setup_user_authentification();
+ BOOST_REQUIRE_THROW(cmd.handleRequest( &mockServer ) , std::runtime_error);
+ }
+ }
+ BOOST_FOREACH(Node* node, nodes) {
+ if (node->events().empty()) {
+ std::string path = node->absNodePath();
+ ForceCmd cmd(path, Event::CLEAR(), false /*recursive */, false /* set Repeat to last value */);
+ cmd.setup_user_authentification();
+ BOOST_REQUIRE_THROW(cmd.handleRequest( &mockServer ) , std::runtime_error);
+ }
+ }
+
+ /// Make a event that does not exist
+ BOOST_FOREACH(Node* node, nodes) {
+ BOOST_FOREACH(const Event& e, node->events()) {
+ std::string path = node->absNodePath() + ":" + e.name_or_number() + "made_up";
+ ForceCmd cmd(path, Event::SET(), false /*recursive */, false /* set Repeat to last value */);
+ cmd.setup_user_authentification();
+ BOOST_REQUIRE_THROW(cmd.handleRequest( &mockServer ) , std::runtime_error);
+ }
+ }
+ BOOST_FOREACH(Node* node, nodes) {
+ BOOST_FOREACH(const Event& e, node->events()) {
+ std::string path = node->absNodePath() + ":" + e.name_or_number() + "made_up";
+ ForceCmd cmd(path, Event::CLEAR(), false /*recursive */, false /* set Repeat to last value */);
+ cmd.setup_user_authentification();
+ BOOST_REQUIRE_THROW(cmd.handleRequest( &mockServer ) , std::runtime_error);
+ }
+ }
+}
+
+
+BOOST_AUTO_TEST_CASE( test_force_interactive )
+{
+ // This test is custom. When the user interactively forces a node to the
+ // complete state, and that node has pending time activities. The default
+ // behaviour, is the node is re-queued again, and hence the propagation up the
+ // node tree does not happen. This is test checks that the node does *not* exhibit
+ // this functionality. What we want is that task is set to complete, without
+ // forcing a re-queue, this is then propagated up the node tree. Which forces the
+ // family to complete, and hence update the repeat variable.
+ cout << "Base:: ...test_force_interactive\n";
+
+ // suite s1
+ // family daily
+ // repeat date YMD 20101215 20101217 1
+ // task t1
+ // time 11:30
+ // endfamily
+ // endsuite
+ // make sure time is set *before* 11:30, so that time dependency holds the task
+ defs_ptr the_defs = Defs::create();
+ suite_ptr suite = Suite::create( "s1" ) ;
+ ClockAttr clockAttr(15,12,2010,false);
+ clockAttr.set_gain(1/*hour*/,0/*minutes*/);
+ suite->addClock( clockAttr );
+ family_ptr f1 = Family::create( "daily" ) ;
+ f1->addRepeat( RepeatDate("date", 20101215, 20101217) );
+ task_ptr t1 = Task::create("t1" );
+ t1->addTime( ecf::TimeAttr(ecf::TimeSlot(11,30)) );
+ f1->addTask( t1 );
+ suite->addFamily( f1 );
+ the_defs->addSuite( suite );
+
+ // before test flags should be clear
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear,before test");
+ BOOST_CHECK_MESSAGE(!f1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, before test");
+ BOOST_CHECK_MESSAGE(!suite->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, before test");
+
+ /// begin the suite
+ TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new BeginCmd("s1",false)));
+ TestHelper::test_state(t1,NState::QUEUED);
+ BOOST_REQUIRE_MESSAGE(f1->repeat().value() == 20101215,"Repeat value expected is 20101215 but found " << f1->repeat().value());
+
+
+ // Force the task t1 to complete state.
+ // Since task t1 is complete, the family 'daily' should complete.
+ // This will cause the repeat to take the next value anf forcing a requeue
+ TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(t1,NState::QUEUED);
+ BOOST_REQUIRE_MESSAGE(f1->repeat().value() == 20101216,"Repeat value expected is 20101216 but found " << f1->repeat().value());
+
+ // Reque should mean flag was cleared + on suite should never get set, since flag is stopped at repeat
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, since task was REQUED");
+ BOOST_CHECK_MESSAGE(!f1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, since family was REQUED");
+ BOOST_CHECK_MESSAGE(!suite->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, since repeat should stop flag propagation up node tree");
+
+ // Force the task t1 to complete again
+ TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(t1,NState::QUEUED);
+ BOOST_REQUIRE_MESSAGE(f1->repeat().value() == 20101217,"Repeat value expected is 20101217 but found " << f1->repeat().value());
+
+ // Do for the last time,
+ TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(t1,NState::COMPLETE);
+ TestHelper::test_state(f1,NState::COMPLETE);
+ TestHelper::test_state(suite,NState::COMPLETE);
+
+ // Since we completed, without a requeue, we should expect flag to stay set.
+ BOOST_CHECK_MESSAGE(t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be set, since there was no reque");
+
+ // Flag propagation should stop at the repeat
+ BOOST_CHECK_MESSAGE(!suite->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP *NOT* to be set");
+}
+
+BOOST_AUTO_TEST_CASE( test_force_interactive_next_time_slot )
+{
+ // This test is custom. When the user interactively forces a node to the complete state,
+ // But where the user has a single time slot. We should stay complete and NOT requee
+ //
+ cout << "Base:: ...test_force_interactive_next_time_slot\n";
+
+ // suite s1
+ // task t1
+ // time 10:00
+ // endsuite
+ // make sure time is set *before* 10:00, so that time dependency holds the task
+ Defs the_defs;
+ suite_ptr suite = the_defs.add_suite("s1");
+ task_ptr t1 = suite->add_task("t1");
+ t1->addTime( TimeAttr(10,0) );
+ ClockAttr clockAttr(15,12,2010,false);
+ clockAttr.set_gain(9/*hour*/,30/*minutes*/); // start at 09:30
+ suite->addClock( clockAttr );
+
+ // before test flags should be clear
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear,before test");
+
+ /// begin the suite
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new BeginCmd("s1",false)));
+ TestHelper::test_state(t1,NState::QUEUED);
+// PrintStyle::setStyle(PrintStyle::STATE);
+// cout << the_defs << "\n";
+
+ // since we started at 09:30 the next time slot should be 10:00
+ const TimeSlot& next_time_slot = t1->timeVec().back().time_series().get_next_time_slot();
+ BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(10,0),"Expected next time slot of 10:00 but found " << next_time_slot.toString());
+
+ // Force the task t1 to complete state. Since we had ONLY a SINGLE time dependency we should stay complete
+ // It should also advance the next time slot
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(t1,NState::COMPLETE);
+ BOOST_CHECK_MESSAGE( !t1->timeVec().back().time_series().is_valid(),"Expected 10:00 time slot to have expired");
+ BOOST_CHECK_MESSAGE( t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be set");
+
+ // call again should, should be do difference
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(t1,NState::COMPLETE);
+ BOOST_CHECK_MESSAGE( !t1->timeVec().back().time_series().is_valid(),"Expected 10:00 time slot to have expired");
+ BOOST_CHECK_MESSAGE( t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be set");
+
+ /// we will now Re-queue, Since the time is still 09:30, we expect next_time slot to be 10:00
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new RequeueNodeCmd(t1->absNodePath())));
+ TestHelper::test_state(t1,NState::QUEUED);
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear");
+ BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(10,0),"After Re-queue, Expected next time slot of 10:00 but found " << next_time_slot.toString());
+}
+
+
+BOOST_AUTO_TEST_CASE( test_force_interactive_next_time_slot_1 )
+{
+ // Start TIME at 9:30
+ // This test is custom. When the user interactively forces a node to the complete state,
+ // But where the user set of time slots. In this case the node should complete and then
+ // requee and miss the next time. If this is repeated, eventually we should reach the
+ // end of the time slot. In which case the node should *not* re-queue and stay complete
+ //
+ // When the node is then re-queued check that the time has been correctly reset.
+ cout << "Base:: ...test_force_interactive_next_time_slot_1\n";
+
+ // suite s1
+ // task t1
+ // time 10:00
+ // time 11:00
+ // time 12:00
+ // time 13:00
+ // endsuite
+ Defs the_defs;
+ suite_ptr suite = the_defs.add_suite("s1");
+ task_ptr t1 = suite->add_task("t1");
+ t1->addTime( TimeAttr(10,0) );
+ t1->addTime( TimeAttr(11,0) );
+ t1->addTime( TimeAttr(12,0) );
+ t1->addTime( TimeAttr(13,0) );
+ ClockAttr clockAttr(15,12,2010,false);
+ clockAttr.set_gain(9/*hour*/,30/*minutes*/); // *start* at 9:30
+ suite->addClock( clockAttr );
+
+ // before test flags should be clear
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear,before test");
+
+ /// begin the suite
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new BeginCmd("s1",false)));
+ TestHelper::test_state(t1,NState::QUEUED);
+// PrintStyle::setStyle(PrintStyle::STATE);
+// cout << the_defs << "\n";
+
+ // get all the time attributes
+ const TimeSeries& ts_10 = t1->timeVec()[0].time_series();
+ const TimeSeries& ts_11 = t1->timeVec()[1].time_series();
+ const TimeSeries& ts_12 = t1->timeVec()[2].time_series();
+ const TimeSeries& ts_13 = t1->timeVec()[3].time_series();
+ BOOST_CHECK_MESSAGE( ts_10.is_valid(), "Expected time 10 to be valid since we started at 9:30 ");
+ BOOST_CHECK_MESSAGE( ts_11.is_valid(), "Expected time 11 to be valid since we started at 9:30");
+ BOOST_CHECK_MESSAGE( ts_12.is_valid(), "Expected time 12 to be valid since we started at 9:30");
+ BOOST_CHECK_MESSAGE( ts_13.is_valid(), "Expected time 13 to be valid since we started at 9:30");
+
+ const TimeSlot& time_10 = t1->timeVec()[0].time_series().get_next_time_slot();
+ const TimeSlot& time_11 = t1->timeVec()[1].time_series().get_next_time_slot();
+ const TimeSlot& time_12 = t1->timeVec()[2].time_series().get_next_time_slot();
+ const TimeSlot& time_13 = t1->timeVec()[3].time_series().get_next_time_slot();
+ BOOST_CHECK_MESSAGE( time_10 == TimeSlot(10,0),"Expected next time slot of 10:00 but found " << time_10.toString());
+ BOOST_CHECK_MESSAGE( time_11 == TimeSlot(11,0),"Expected next time slot of 11:00 but found " << time_11.toString());
+ BOOST_CHECK_MESSAGE( time_12 == TimeSlot(12,0),"Expected next time slot of 12:00 but found " << time_12.toString());
+ BOOST_CHECK_MESSAGE( time_13 == TimeSlot(13,0),"Expected next time slot of 13:00 but found " << time_13.toString());
+
+
+ // Force the task t1 to complete state. Since we have a future time dependency, we should get re-queued again
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(t1,NState::QUEUED);
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear");
+ BOOST_CHECK_MESSAGE( !ts_10.is_valid(), "Expected time 10 to be expired ");
+ BOOST_CHECK_MESSAGE( ts_11.is_valid(), "Expected time 11 to be valid.");
+ BOOST_CHECK_MESSAGE( ts_12.is_valid(), "Expected time 12 to be valid");
+ BOOST_CHECK_MESSAGE( ts_13.is_valid(), "Expected time 13 to be valid");
+
+ // Repeat
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(t1,NState::QUEUED);
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear");
+ BOOST_CHECK_MESSAGE( !ts_10.is_valid(), "Expected time 10 to be expired due to force cmd");
+ BOOST_CHECK_MESSAGE( !ts_11.is_valid(), "Expected time 11 to be expired due to force cmd");
+ BOOST_CHECK_MESSAGE( ts_12.is_valid(), "Expected time 12 to be valid");
+ BOOST_CHECK_MESSAGE( ts_13.is_valid(), "Expected time 13 to be valid");
+
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(t1,NState::QUEUED);
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear");
+ BOOST_CHECK_MESSAGE( !ts_10.is_valid(), "Expected time 10 to be expired due to force cmd");
+ BOOST_CHECK_MESSAGE( !ts_11.is_valid(), "Expected time 11 to be expired due to force cmd");
+ BOOST_CHECK_MESSAGE( !ts_12.is_valid(), "Expected time 12 to be expired due to force cmd");
+ BOOST_CHECK_MESSAGE( ts_13.is_valid(), "Expected time 13 to be valid");
+
+
+ // Repeat *last* time, since all times have expired, we expect task to stay complete.
+ // Addtionally since we have *not* re-queued the flag NO_REQUE_IF_SINGLE_TIME_DEP should have remained set
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(t1,NState::COMPLETE);
+ BOOST_CHECK_MESSAGE( t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be set");
+ BOOST_CHECK_MESSAGE( !ts_10.is_valid(), "Expected time 10 to be expired since we started clock at 10:30 ");
+ BOOST_CHECK_MESSAGE( !ts_11.is_valid(), "Expected time 11 to be expired due to force cmd");
+ BOOST_CHECK_MESSAGE( !ts_12.is_valid(), "Expected time 12 to be expired due to force cmd");
+ BOOST_CHECK_MESSAGE( !ts_13.is_valid(), "Expected time 13 to be expired due to force cmd");
+
+ /// we will now Re-queue, Since the time is still 10:30, we expect valid from 11:00 and not 10:00
+ /// We should also have cleared NO_REQUE_IF_SINGLE_TIME_DEP
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new RequeueNodeCmd(t1->absNodePath())));
+ TestHelper::test_state(t1,NState::QUEUED);
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear");
+ BOOST_CHECK_MESSAGE( ts_10.is_valid(), "Expected time 10 to be in valid since we started clock at 9:30 ");
+ BOOST_CHECK_MESSAGE( ts_11.is_valid(), "Expected time 11 to be valid");
+ BOOST_CHECK_MESSAGE( ts_12.is_valid(), "Expected time 12 to be valid");
+ BOOST_CHECK_MESSAGE( ts_13.is_valid(), "Expected time 13 to be valid");
+}
+
+BOOST_AUTO_TEST_CASE( test_force_interactive_next_time_slot_2 )
+{
+ // Start TIME at 9:30
+ // This test is custom. When the user interactively forces a node to the complete state,
+ // But where the user has a time range. In this case the node should complete and then
+ // requee and miss the next time slot. If this is repeated, eventually we should reach the
+ // end of the time slot. In which case the node should *not* reque and stay complete
+ //
+ // When the node is then requeed check that the next time slot has been correctly reset.
+ cout << "Base:: ...test_force_interactive_next_time_slot_2\n";
+
+ // suite s1
+ // task t1
+ // time 10:00 14:00 01:00
+ // endsuite
+ Defs the_defs;
+ suite_ptr suite = the_defs.add_suite("s1");
+ task_ptr t1 = suite->add_task("t1");
+ t1->addTime( TimeAttr(TimeSlot(10,0),TimeSlot(14,0),TimeSlot(1,0)) );
+ ClockAttr clockAttr(15,12,2010,false);
+ clockAttr.set_gain(9/*hour*/,30/*minutes*/); // start at 99:30
+ suite->addClock( clockAttr );
+
+ // before test flags should be clear
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear,before test");
+
+ /// begin the suite
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new BeginCmd("s1",false)));
+ TestHelper::test_state(t1,NState::QUEUED);
+// PrintStyle::setStyle(PrintStyle::STATE);
+// cout << the_defs << "\n";
+
+ // since we started at 09:30 the next time slot should be 10:00
+ const TimeSlot& next_time_slot = t1->timeVec().back().time_series().get_next_time_slot();
+ BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(10,0),"Expected next time slot of 10:00 but found " << next_time_slot.toString());
+
+ // Force the task t1 to complete state. Since we have a future time dependency, we should get re-queued again
+ // It should also advance the next time slot
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(t1,NState::QUEUED);
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, after a requeue");
+ BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(11,0),"Expected next time slot of 11:00 but found " << next_time_slot.toString());
+
+ // Repeat, to make sure next_time_slot is advanced
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(t1,NState::QUEUED);
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, after a requeue");
+ BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(12,0),"Expected next time slot of 12:00 but found " << next_time_slot.toString());
+
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(t1,NState::QUEUED);
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, after a requeue");
+ BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(13,0),"Expected next time slot of 13:00 but found " << next_time_slot.toString());
+
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(t1,NState::QUEUED);
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, after a requeue");
+ BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(14,0),"Expected next time slot of 14:00 but found " << next_time_slot.toString());
+
+ // Repeat, ** THIS time we have *exceeded* the time range, it should no longer requeue, and should stay complete
+ // Additionally since there is no reque we expect NO_REQUE_IF_SINGLE_TIME_DEP to remain set
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(t1,NState::COMPLETE);
+ BOOST_CHECK_MESSAGE(t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be set");
+ BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(15,0),"Expected next time slot of 15:00 but found " << next_time_slot.toString());
+
+ /// we will now Re-queue, Since the time is still 10:30, we expect next_time slot to be 11:00 and not 10:00
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new RequeueNodeCmd(t1->absNodePath())));
+ TestHelper::test_state(t1,NState::QUEUED);
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear");
+ BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(10,0),"After Re-queue, Expected next time slot of 10:00 but found " << next_time_slot.toString());
+}
+
+
+BOOST_AUTO_TEST_CASE( test_force_interactive_next_time_slot_3 )
+{
+ // Start TIME at 10:30
+ // This test is custom. When the user interactively forces a node to the complete state,
+ // But where the user set of time slots. In this case the node should complete and then
+ // requee and miss the next time. If this is repeated, eventually we should reach the
+ // end of the time slot. In which case the node should *not* re-queue and stay complete
+ //
+ // When the node is then re-queued check that the time has been correctly reset.
+ cout << "Base:: ...test_force_interactive_next_time_slot_3\n";
+
+ // suite s1
+ // task t1
+ // time 10:00
+ // time 11:00
+ // time 12:00
+ // time 13:00
+ // endsuite
+ Defs the_defs;
+ suite_ptr suite = the_defs.add_suite("s1");
+ task_ptr t1 = suite->add_task("t1");
+ t1->addTime( TimeAttr(10,0) );
+ t1->addTime( TimeAttr(11,0) );
+ t1->addTime( TimeAttr(12,0) );
+ t1->addTime( TimeAttr(13,0) );
+ ClockAttr clockAttr(15,12,2010,false);
+ clockAttr.set_gain(10/*hour*/,30/*minutes*/); // *start* at 10:30
+ suite->addClock( clockAttr );
+
+ // before test flags should be clear
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear,before test");
+
+ /// begin the suite
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new BeginCmd("s1",false)));
+ TestHelper::test_state(t1,NState::QUEUED);
+// PrintStyle::setStyle(PrintStyle::STATE);
+// cout << the_defs << "\n";
+
+ // get all the time attributes
+ const TimeSeries& ts_10 = t1->timeVec()[0].time_series();
+ const TimeSeries& ts_11 = t1->timeVec()[1].time_series();
+ const TimeSeries& ts_12 = t1->timeVec()[2].time_series();
+ const TimeSeries& ts_13 = t1->timeVec()[3].time_series();
+ BOOST_CHECK_MESSAGE( !ts_10.is_valid(), "Expected time 10 to be in-valid since we started clock at 10:30 ");
+ BOOST_CHECK_MESSAGE( ts_11.is_valid(), "Expected time 11 to be valid since we started at 10:30");
+ BOOST_CHECK_MESSAGE( ts_12.is_valid(), "Expected time 12 to be valid since we started at 10:30");
+ BOOST_CHECK_MESSAGE( ts_13.is_valid(), "Expected time 13 to be valid since we started at 10:30");
+
+ const TimeSlot& time_10 = t1->timeVec()[0].time_series().get_next_time_slot();
+ const TimeSlot& time_11 = t1->timeVec()[1].time_series().get_next_time_slot();
+ const TimeSlot& time_12 = t1->timeVec()[2].time_series().get_next_time_slot();
+ const TimeSlot& time_13 = t1->timeVec()[3].time_series().get_next_time_slot();
+ BOOST_CHECK_MESSAGE( time_10 == TimeSlot(10,0),"Expected next time slot of 10:00 but found " << time_10.toString());
+ BOOST_CHECK_MESSAGE( time_11 == TimeSlot(11,0),"Expected next time slot of 11:00 but found " << time_11.toString());
+ BOOST_CHECK_MESSAGE( time_12 == TimeSlot(12,0),"Expected next time slot of 12:00 but found " << time_12.toString());
+ BOOST_CHECK_MESSAGE( time_13 == TimeSlot(13,0),"Expected next time slot of 13:00 but found " << time_13.toString());
+
+
+ // Force the task t1 to complete state. Since we have a future time dependency, we should get re-queued again
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(t1,NState::QUEUED);
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear");
+ BOOST_CHECK_MESSAGE( !ts_10.is_valid(), "Expected time 10 to be expired since we started clock at 10:30 ");
+ BOOST_CHECK_MESSAGE( !ts_11.is_valid(), "Expected time 11 to be expired, since we just completed.");
+ BOOST_CHECK_MESSAGE( ts_12.is_valid(), "Expected time 12 to be valid");
+ BOOST_CHECK_MESSAGE( ts_13.is_valid(), "Expected time 13 to be valid");
+
+ // Repeat
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(t1,NState::QUEUED);
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear");
+ BOOST_CHECK_MESSAGE( !ts_10.is_valid(), "Expected time 10 to be expired since we started clock at 10:30 ");
+ BOOST_CHECK_MESSAGE( !ts_11.is_valid(), "Expected time 11 to be expired due to force cmd");
+ BOOST_CHECK_MESSAGE( !ts_12.is_valid(), "Expected time 12 to be expired due to force cmd");
+ BOOST_CHECK_MESSAGE( ts_13.is_valid(), "Expected time 13 to be valid");
+
+ // Repeat *last* time, since all times have expired, we expect task to complete.
+ // Addtionally since we have *not* re-queued the flag NO_REQUE_IF_SINGLE_TIME_DEP should have remained set
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(t1,NState::COMPLETE);
+ BOOST_CHECK_MESSAGE( t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be set");
+ BOOST_CHECK_MESSAGE( !ts_10.is_valid(), "Expected time 10 to be expired since we started clock at 10:30 ");
+ BOOST_CHECK_MESSAGE( !ts_11.is_valid(), "Expected time 11 to be expired due to force cmd");
+ BOOST_CHECK_MESSAGE( !ts_12.is_valid(), "Expected time 12 to be expired due to force cmd");
+ BOOST_CHECK_MESSAGE( !ts_13.is_valid(), "Expected time 13 to be expired due to force cmd");
+
+ /// we will now Re-queue, Since the time is still 10:30, we expect valid from 11:00 and not 10:00
+ /// We should also have cleared NO_REQUE_IF_SINGLE_TIME_DEP
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new RequeueNodeCmd(t1->absNodePath())));
+ TestHelper::test_state(t1,NState::QUEUED);
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear");
+ BOOST_CHECK_MESSAGE( !ts_10.is_valid(), "Expected time 10 to be in valid since we started clock at 10:30 ");
+ BOOST_CHECK_MESSAGE( ts_11.is_valid(), "Expected time 11 to be valid");
+ BOOST_CHECK_MESSAGE( ts_12.is_valid(), "Expected time 12 to be valid");
+ BOOST_CHECK_MESSAGE( ts_13.is_valid(), "Expected time 13 to be valid");
+}
+
+
+BOOST_AUTO_TEST_CASE( test_force_interactive_next_time_slot_4 )
+{
+ // This test is custom. When the user interactively forces a node to the complete state,
+ // But where the user has a time range. In this case the node should complete and then
+ // requee and miss the next time slot. If this is repeated, eventually we should reach the
+ // end of the time slot. In which case the node should *not* reque and stay complete
+ //
+ // When the node is then requeed check that the next time slot has been correctly reset.
+ cout << "Base:: ...test_force_interactive_next_time_slot_4\n";
+
+ // suite s1
+ // task t1
+ // time 10:00 14:00 01:00
+ // endsuite
+ Defs the_defs;
+ suite_ptr suite = the_defs.add_suite("s1");
+ task_ptr t1 = suite->add_task("t1");
+ t1->addTime( TimeAttr(TimeSlot(10,0),TimeSlot(14,0),TimeSlot(1,0)) );
+ ClockAttr clockAttr(15,12,2010,false);
+ clockAttr.set_gain(10/*hour*/,30/*minutes*/); // start at 10:30
+ suite->addClock( clockAttr );
+
+ // before test flags should be clear
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear,before test");
+
+ /// begin the suite
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new BeginCmd("s1",false)));
+ TestHelper::test_state(t1,NState::QUEUED);
+// PrintStyle::setStyle(PrintStyle::STATE);
+// cout << the_defs << "\n";
+
+ // since we started at 10:30 the next time slot should be 11:00
+ const TimeSlot& next_time_slot = t1->timeVec().back().time_series().get_next_time_slot();
+ BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(11,0),"Expected next time slot of 11:00 but found " << next_time_slot.toString());
+
+ // Force the task t1 to complete state. Since we have a future time dependency, we should get re-queued again
+ // It should also advance the next time slot
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(t1,NState::QUEUED);
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, after a requeue");
+ BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(12,0),"Expected next time slot of 12:00 but found " << next_time_slot.toString());
+
+ // Repeat, to make sure next_time_slot is advanced
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(t1,NState::QUEUED);
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, after a requeue");
+ BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(13,0),"Expected next time slot of 13:00 but found " << next_time_slot.toString());
+
+ // Repeat, to make sure next_time_slot is advanced
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(t1,NState::QUEUED);
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, after a requeue");
+ BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(14,0),"Expected next time slot of 14:00 but found " << next_time_slot.toString());
+
+ // Repeat, ** THIS time we have *exceeded* the time range, it should no longer requeue, and should stay complete
+ // Additionally since there is no reque we expect NO_REQUE_IF_SINGLE_TIME_DEP to remain set
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(t1,NState::COMPLETE);
+ BOOST_CHECK_MESSAGE(t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be set");
+ BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(15,0),"Expected next time slot of 15:00 but found " << next_time_slot.toString());
+
+ /// we will now Re-queue, Since the time is still 10:30, we expect next_time slot to be 11:00 and not 10:00
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new RequeueNodeCmd(t1->absNodePath())));
+ TestHelper::test_state(t1,NState::QUEUED);
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear");
+ BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(11,0),"After Re-queue, Expected next time slot of 11:00 but found " << next_time_slot.toString());
+}
+
+
+BOOST_AUTO_TEST_CASE( test_force_interactive_next_time_slot_for_cron )
+{
+ // This test is custom. When the user interactively forces a node to the complete state,
+ // But where the user has a time range. In this case the node should complete and then
+ // requee and miss the next time slot. If this is repeated, eventually we should reach the
+ // end of the time slot.
+ //
+ // When the node is then requeed check that the next time slot has been correctly reset.
+ cout << "Base:: ...test_force_interactive_next_time_slot_for_cron\n";
+
+ // suite s1
+ // task t1
+ // cron 10:00 13:00 01:00
+ // endsuite
+ Defs the_defs;
+ suite_ptr suite = the_defs.add_suite("s1");
+ ClockAttr clockAttr(15,12,2010,false);
+ clockAttr.set_gain(9/*hour*/,30/*minutes*/); // start at 09:30
+ suite->addClock( clockAttr );
+
+ task_ptr t1 = suite->add_task("t1");
+ ecf::CronAttr cronAttr;
+ cronAttr.addTimeSeries(TimeSlot(10,0),TimeSlot(13,0),TimeSlot(1,0));
+ t1->addCron(cronAttr);
+
+ // before test flags should be clear
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear,before test");
+
+ /// begin the suite
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new BeginCmd("s1",false)));
+ TestHelper::test_state(t1,NState::QUEUED);
+// PrintStyle::setStyle(PrintStyle::STATE);
+// cout << the_defs << "\n";
+
+ // since we started at 09:30 the next time slot should be 10:00
+ const TimeSlot& next_time_slot = t1->crons().back().time_series().get_next_time_slot();
+ BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(10,0),"Expected next time slot of 10:00 but found " << next_time_slot.toString());
+
+ // Force the task t1 to complete state. Since we have a future time dependency, we should get re-queued again
+ // It should also advance the next time slot
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(t1,NState::QUEUED);
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, after a requeue");
+ BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(11,0),"Expected next time slot of 11:00 but found " << next_time_slot.toString());
+
+ // Repeat, to make sure next_time_slot is advanced
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(t1,NState::QUEUED);
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, after a requeue");
+ BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(12,0),"Expected next time slot of 12:00 but found " << next_time_slot.toString());
+
+ // Repeat, to make sure next_time_slot is advanced
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(t1,NState::QUEUED);
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, after a requeue");
+ BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(13,0),"Expected next time slot of 13:00 but found " << next_time_slot.toString());
+
+ // Repeat, ** THIS time we have *exceeded* the time range, However the cron *ALWAYS* re-queues
+ // Additionally since there is no reque we expect NO_REQUE_IF_SINGLE_TIME_DEP to remain set
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(t1,NState::QUEUED);
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, after a requeue");
+ BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(14,0),"Expected next time slot of 14:00 but found " << next_time_slot.toString());
+
+ /// we will now Re-queue, Since the time is still 09:30, we expect next_time slot to be 10:00 and not 14:00
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new RequeueNodeCmd(t1->absNodePath())));
+ TestHelper::test_state(t1,NState::QUEUED);
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear");
+ BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(10,0),"After Re-queue, Expected next time slot of 10:00 but found " << next_time_slot.toString());
+}
+
+
+BOOST_AUTO_TEST_CASE( test_force_interactive_next_time_slot_for_cron_on_family )
+{
+ // This test is custom. When the user interactively forces a node to the complete state,
+ // But where the user has a time range. In this case the node should complete and then
+ // requee and miss the next time slot. If this is repeated, eventually we should reach the
+ // end of the time slot.
+ //
+ // When the node is then requeed check that the next time slot has been correctly reset.
+ cout << "Base:: ...test_force_interactive_next_time_slot_for_cron_on_family\n";
+
+ // suite s1
+ // family
+ // cron 10:00 13:00 01:00
+ // task t1
+ // time 11:00
+ // task t2
+ // time 12:00
+ // endsuite
+ Defs the_defs;
+ suite_ptr suite = the_defs.add_suite("s1");
+ ClockAttr clockAttr(15,12,2010,false);
+ clockAttr.set_gain(9/*hour*/,30/*minutes*/); // start at 09:30
+ suite->addClock( clockAttr );
+
+ family_ptr f1 = suite->add_family("f1");
+ ecf::CronAttr cronAttr;
+ cronAttr.addTimeSeries(TimeSlot(10,0),TimeSlot(13,0),TimeSlot(1,0));
+ f1->addCron(cronAttr);
+
+ task_ptr t1 = f1->add_task("t1");
+ t1->addTime( TimeAttr(11,0) );
+
+ task_ptr t2 = f1->add_task("t2");
+ t2->addTime( TimeAttr(12,0) );
+
+ // before test flags should be clear
+ BOOST_CHECK_MESSAGE(!f1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear,before test");
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear,before test");
+ BOOST_CHECK_MESSAGE(!t2->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear,before test");
+
+ /// begin the suite
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new BeginCmd("s1",false)));
+ TestHelper::test_state(t1,NState::QUEUED);
+ TestHelper::test_state(t2,NState::QUEUED);
+// PrintStyle::setStyle(PrintStyle::STATE);
+// cout << the_defs << "\n";
+
+ // since we started at 09:30 the next time slot should be 11:00
+ const TimeSlot& t1_next_time_slot = t1->timeVec().back().time_series().get_next_time_slot();
+ const TimeSlot& t2_next_time_slot = t2->timeVec().back().time_series().get_next_time_slot();
+ BOOST_CHECK_MESSAGE( t1_next_time_slot == TimeSlot(11,0),"Expected next time slot of 11:00 but found " << t1_next_time_slot.toString());
+ BOOST_CHECK_MESSAGE( t2_next_time_slot == TimeSlot(12,0),"Expected next time slot of 12:00 but found " << t2_next_time_slot.toString());
+
+ // Force the task t1 & t2 to complete state. Since we only have a single time dependency it should expire
+ // It should also advance the next time slot
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(t1,NState::COMPLETE);
+ TestHelper::test_state(t2,NState::QUEUED);
+ BOOST_CHECK_MESSAGE( ! t1->timeVec().back().time_series().is_valid(),"Expected 11:00 time slot to be expired ");
+
+ // Forcing t2 to complete as well should, end up requeueing t1,t2 due to parent cron
+ TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t2->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(t1,NState::QUEUED);
+ TestHelper::test_state(t2,NState::QUEUED);
+ BOOST_CHECK_MESSAGE( t1->timeVec().back().time_series().is_valid(),"Expected 11:00 time slot to be valid ");
+ BOOST_CHECK_MESSAGE( t2->timeVec().back().time_series().is_valid(),"Expected 12:00 time slot to be valid ");
+ BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear");
+ BOOST_CHECK_MESSAGE(!t2->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear");
+
+ /// Destroy System singleton to avoid valgrind from complaining
+ System::destroy();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Base/test/TestFreeDepCmd.cpp b/Base/test/TestFreeDepCmd.cpp
new file mode 100644
index 0000000..c29b1f3
--- /dev/null
+++ b/Base/test/TestFreeDepCmd.cpp
@@ -0,0 +1,304 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #22 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+
+#include <boost/test/unit_test.hpp>
+
+#include "ClientToServerCmd.hpp"
+#include "ServerToClientCmd.hpp"
+#include "Suite.hpp"
+#include "Task.hpp"
+#include "Family.hpp"
+#include "Defs.hpp"
+#include "ExprAst.hpp"
+#include "MockServer.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+
+BOOST_AUTO_TEST_SUITE( BaseTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_free_dep_cmd )
+{
+ cout << "Base:: ...test_free_dep_cmd\n";
+
+ // Create a test and add the date and time dependencies
+ ptime theLocalTime(date(2011,Nov,4), time_duration(9,30,0));
+ ptime time_plus_hour = theLocalTime + hours(1);
+ ptime time_plus_2_hour = theLocalTime + hours(2);
+ date todaysDate = theLocalTime.date();
+ date tomorrows_date = todaysDate + date_duration(1);
+ date tomorrows_date_1 = todaysDate + date_duration(2);
+
+ // Get tomorrow as a day so that isFree fails.
+ tm day_1 = to_tm(tomorrows_date);
+ tm day_2 = to_tm(tomorrows_date_1);
+
+ suite_ptr suite;
+ task_ptr task;
+ Defs theDefs; {
+ suite = theDefs.add_suite( "test_time" );
+ ClockAttr clockAttr(theLocalTime,false/*false means use real clock*/);
+ suite->addClock( clockAttr );
+
+ family_ptr fam = suite->add_family( "family" );
+ task = fam->add_task( "t" );
+ task->addTime( ecf::TimeAttr( TimeSlot(time_plus_hour.time_of_day()) ) );
+ task->addTime( ecf::TimeAttr( TimeSlot(time_plus_2_hour.time_of_day()) ) );
+ task->addTime( ecf::TimeAttr( ecf::TimeSlot(1,1), ecf::TimeSlot(1,3), ecf::TimeSlot(0,1),
+ true /*relative to suite start*/
+ ));
+ task->addToday( ecf::TodayAttr( TimeSlot(time_plus_hour.time_of_day()) ) );
+ task->addToday( ecf::TodayAttr( TimeSlot(time_plus_2_hour.time_of_day()) ) );
+ task->addDate( DateAttr(tomorrows_date.day(),tomorrows_date.month(),tomorrows_date.year()) );
+ task->addDate( DateAttr(tomorrows_date_1.day(),tomorrows_date_1.month(),tomorrows_date_1.year()) );
+ task->addDay( DayAttr(static_cast<DayAttr::Day_t>(day_1.tm_wday) ));
+ task->addDay( DayAttr(static_cast<DayAttr::Day_t>(day_2.tm_wday) ));
+ task->add_trigger( "t2 == complete" );
+
+ CronAttr cronAttr;
+ cronAttr.addTimeSeries( ecf::TimeSlot(time_plus_hour.time_of_day()),
+ ecf::TimeSlot(time_plus_2_hour.time_of_day()),
+ ecf::TimeSlot(0,1) );
+ task->addCron( cronAttr );
+
+ fam->add_task( "t2" );
+ // cout << theDefs << "\n";
+ }
+ std::vector<task_ptr> vec;
+ theDefs.get_all_tasks(vec);
+ BOOST_REQUIRE_MESSAGE(vec.size() == 2,"Error in number of tasks");
+
+ // This will initialise the calendar from the Clock attribute
+ theDefs.beginAll();
+
+ // First all trigger should fail to evaluate AND all dependencies should NOT be free
+ BOOST_REQUIRE_MESSAGE(task->triggerAst(),"Expected trigger abstract syntax tree for task " << task->absNodePath());
+ BOOST_REQUIRE_MESSAGE(!task->triggerAst()->evaluate(),"Trigger should not evaluate");
+
+ const Calendar& cal = suite->calendar();
+ BOOST_FOREACH(const ecf::TimeAttr& attr, task->timeVec()) {
+ BOOST_CHECK_MESSAGE(!attr.isFree(cal)," Time should not be free");
+ }
+ BOOST_FOREACH(const ecf::TodayAttr& attr, task->todayVec()) {
+ BOOST_CHECK_MESSAGE(!attr.isFree(cal)," Today should not be free");
+ }
+ BOOST_FOREACH(const ecf::CronAttr& attr, task->crons()) {
+ BOOST_CHECK_MESSAGE(!attr.isFree(cal)," Cron should not be free");
+ }
+ BOOST_FOREACH(const DateAttr& attr, task->dates()) {
+ BOOST_CHECK_MESSAGE(!attr.isFree(cal)," Date should not be free");
+ }
+ BOOST_FOREACH(const DayAttr& attr, task->days()) {
+ BOOST_CHECK_MESSAGE(!attr.isFree(cal),"Day should not be free");
+ }
+
+
+ // Invoke the FreeDepCmd
+ MockServer mockServer(&theDefs);
+
+ FreeDepCmd cmd(task->absNodePath(),true/*trigger*/,true/* all */);
+ cmd.setup_user_authentification();
+ STC_Cmd_ptr returnCmd = cmd.handleRequest( &mockServer );
+ BOOST_REQUIRE_MESSAGE(returnCmd->ok(),"Failed to for FreeDepCmd");
+
+
+ // Dependencies should now all be free now.
+ BOOST_REQUIRE_MESSAGE(task->get_trigger()->isFree(),"Trigger should evaluate");
+ bool at_least_one_free = false;
+ BOOST_FOREACH(const ecf::TimeAttr& attr, task->timeVec()) {
+ if (attr.isFree(cal)) { at_least_one_free = true; break;}
+ }
+ BOOST_CHECK_MESSAGE(at_least_one_free,"At least one Time should be free");
+
+ at_least_one_free = false;
+ BOOST_FOREACH(const ecf::TodayAttr& attr, task->todayVec()) {
+ if (attr.isFree(cal)) { at_least_one_free = true; break;}
+ }
+ BOOST_CHECK_MESSAGE(at_least_one_free,"At least one Today should be free");
+
+ at_least_one_free = false;
+ BOOST_FOREACH(const ecf::CronAttr& attr, task->crons()) {
+ if (attr.isFree(cal)) { at_least_one_free = true; break;}
+ }
+ BOOST_CHECK_MESSAGE(at_least_one_free,"At least one Cron should be free");
+
+ at_least_one_free = false;
+ BOOST_FOREACH(const DateAttr& attr, task->dates()) {
+ if (attr.isFree(cal)) { at_least_one_free = true; break;}
+ }
+ BOOST_CHECK_MESSAGE(at_least_one_free,"At least one Date should be free");
+
+ at_least_one_free = false;
+ BOOST_FOREACH(const DayAttr& attr, task->days()) {
+ if (attr.isFree(cal)) { at_least_one_free = true; break;}
+ }
+ BOOST_CHECK_MESSAGE(at_least_one_free,"At least one Day should be free");
+}
+
+BOOST_AUTO_TEST_CASE( test_free_dep_cmd_single_time_slot )
+{
+ cout << "Base:: ...test_free_dep_cmd_single_time_slot\n";
+
+ // We add a time dependency *AFTER* the suite/calendar time
+ // This checks that we DO NOT re-queue a task with a future time dependency
+ // when a time dependency has been freed
+ ptime theLocalTime(date(2011,Nov,4), time_duration(9,30,0));
+ ptime time_plus_2minute = theLocalTime + minutes(2);
+
+ suite_ptr suite;
+ task_ptr task;
+ Defs theDefs; {
+ suite = theDefs.add_suite( "test_time" );
+ ClockAttr clockAttr(theLocalTime,false/*false means use real clock*/);
+ suite->addClock( clockAttr );
+ task = suite->add_task( "t" );
+ task->addTime( ecf::TimeAttr( TimeSlot(time_plus_2minute.time_of_day()) ) );
+ }
+
+ // This will initialise the calendar from the Clock attribute
+ theDefs.beginAll();
+
+ // expect task to be holding at 9:30
+ const Calendar& cal = suite->calendar();
+ BOOST_FOREACH(const ecf::TimeAttr& attr, task->timeVec()) {
+ BOOST_CHECK_MESSAGE(!attr.isFree(cal)," Time should not be free");
+ }
+
+ // Invoke the FreeDepCmd
+ MockServer mockServer(&theDefs);
+ FreeDepCmd cmd(task->absNodePath(),true/*trigger*/,true/* all */);
+ cmd.setup_user_authentification();
+ STC_Cmd_ptr returnCmd = cmd.handleRequest( &mockServer );
+ BOOST_REQUIRE_MESSAGE(returnCmd->ok(),"Failed to for FreeDepCmd");
+
+ // expect task to be free
+ bool at_least_one_free = false;
+ BOOST_FOREACH(const ecf::TimeAttr& attr, task->timeVec()) {
+ if (attr.isFree(cal)) { at_least_one_free = true; break;}
+ }
+ BOOST_CHECK_MESSAGE(at_least_one_free,"At least one Time should be free");
+
+ // The crux of the test. Should not requeue.
+ BOOST_CHECK_MESSAGE(task->state() == NState::ACTIVE,"Free dependency should have done an immediate job submission. Expected active state");
+ task->complete();
+ BOOST_CHECK_MESSAGE(task->state() == NState::COMPLETE,"Expected Complete but found " << NState::toString(task->state()) << ", free dependency should avoid re-queue for a future single time dependency.");
+}
+
+BOOST_AUTO_TEST_CASE( test_free_dep_cmd_with_time_series )
+{
+ cout << "Base:: ...test_free_dep_cmd_with_time_series\n";
+
+ // We start the suite *IN BETWEEN* a time series, and the force free dependency
+ // This checks that we DO NOT re-queue a task with a future time dependency
+ // when a time dependency has been freed
+ ptime theLocalTime(date(2011,Nov,4), time_duration(9,29,0));
+ suite_ptr suite;
+ task_ptr task;
+ Defs theDefs; {
+ suite = theDefs.add_suite( "test_time" );
+ ClockAttr clockAttr(theLocalTime,false/*false means use real clock*/);
+ suite->addClock( clockAttr );
+ task = suite->add_task( "t" );
+ task->addTime( ecf::TimeAttr( ecf::TimeSlot(9,28), ecf::TimeSlot(9,30), ecf::TimeSlot(0,2),
+ false /*relative to suite start*/
+ ));
+ }
+
+ // This will initialise the calendar from the Clock attribute
+ theDefs.beginAll();
+
+ // expect task to be holding, at 9:29
+ const Calendar& cal = suite->calendar();
+ BOOST_FOREACH(const ecf::TimeAttr& attr, task->timeVec()) {
+ BOOST_CHECK_MESSAGE(!attr.isFree(cal)," Time should not be free");
+ }
+
+ // Invoke the FreeDepCmd
+ MockServer mockServer(&theDefs);
+ FreeDepCmd cmd(task->absNodePath(),true/*trigger*/,true/* all */);
+ cmd.setup_user_authentification();
+ STC_Cmd_ptr returnCmd = cmd.handleRequest( &mockServer );
+ BOOST_REQUIRE_MESSAGE(returnCmd->ok(),"Failed to for FreeDepCmd");
+
+ // expect task to be free
+ bool at_least_one_free = false;
+ BOOST_FOREACH(const ecf::TimeAttr& attr, task->timeVec()) {
+ if (attr.isFree(cal)) { at_least_one_free = true; break;}
+ }
+ BOOST_CHECK_MESSAGE(at_least_one_free,"At least one Time should be free");
+
+ // The crux of the test. Should not requeue, as we should have advanced the time slot beyond the END point
+ // i.e FreeDepCmd will advance the time slot, beyond end time
+ BOOST_CHECK_MESSAGE(task->state() == NState::ACTIVE,"Free dependency should have done an immediate job submission. Expected active state");
+ task->complete();
+ BOOST_CHECK_MESSAGE(task->state() == NState::COMPLETE,"Expected Complete but found " << NState::toString(task->state()) << ", free dependency should avoid re-queue for a future single time dependency.");
+}
+
+BOOST_AUTO_TEST_CASE( test_free_dep_cmd_with_time_series_2 )
+{
+ cout << "Base:: ...test_free_dep_cmd_with_time_series_2\n";
+
+ // We start the suite *IN BETWEEN* a time series, and the force free dependency
+ // This time we have a larger range, and *SHOULD* re-queue, even if we miss a time slot
+ ptime theLocalTime(date(2011,Nov,4), time_duration(9,29,0));
+ suite_ptr suite;
+ task_ptr task;
+ Defs theDefs; {
+ suite = theDefs.add_suite( "test_time" );
+ ClockAttr clockAttr(theLocalTime,false/*false means use real clock*/);
+ suite->addClock( clockAttr );
+ task = suite->add_task( "t" );
+ task->addTime( ecf::TimeAttr( ecf::TimeSlot(9,28), ecf::TimeSlot(9,34), ecf::TimeSlot(0,2),
+ false /*relative to suite start*/
+ ));
+ }
+
+ // This will initialise the calendar from the Clock attribute
+ // Will initialise nextTimeSlot=09:30
+ theDefs.beginAll();
+
+ // expect task to be holding, at 9:29
+ const Calendar& cal = suite->calendar();
+ BOOST_FOREACH(const ecf::TimeAttr& attr, task->timeVec()) {
+ BOOST_CHECK_MESSAGE(!attr.isFree(cal)," Time should not be free");
+ }
+
+ // Invoke the FreeDepCmd. This will update next nextTimeSlot to 09:32
+ MockServer mockServer(&theDefs);
+ FreeDepCmd cmd(task->absNodePath(),true/*trigger*/,true/* all */);
+ cmd.setup_user_authentification();
+ STC_Cmd_ptr returnCmd = cmd.handleRequest( &mockServer );
+ BOOST_REQUIRE_MESSAGE(returnCmd->ok(),"Failed to for FreeDepCmd");
+
+ // expect task to be free
+ bool at_least_one_free = false;
+ BOOST_FOREACH(const ecf::TimeAttr& attr, task->timeVec()) {
+ if (attr.isFree(cal)) { at_least_one_free = true; break;}
+ }
+ BOOST_CHECK_MESSAGE(at_least_one_free,"At least one Time should be free");
+
+ // The crux of the test. Even if we advance the time slot we should *STILL* be in range
+ BOOST_CHECK_MESSAGE(task->state() == NState::ACTIVE,"Free dependency should have done an immediate job submission. Expected active state");
+ task->complete();
+ BOOST_CHECK_MESSAGE(task->state() == NState::QUEUED,"Expected QUEUED but found " << NState::toString(task->state()) << ", free dependency should avoid re-queue for a future single time dependency.");
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Base/test/TestHelper.hpp b/Base/test/TestHelper.hpp
new file mode 100644
index 0000000..1061cdd
--- /dev/null
+++ b/Base/test/TestHelper.hpp
@@ -0,0 +1,90 @@
+#ifndef TESTHELPER_HPP_
+#define TESTHELPER_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #33 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <boost/test/test_tools.hpp>
+
+#include "ClientToServerCmd.hpp"
+#include "ServerToClientCmd.hpp"
+#include "ClientToServerRequest.hpp"
+#include "MockServer.hpp"
+#include "Node.hpp"
+
+// defines statics utility functions used by more than one test
+class TestHelper {
+public:
+ static void invokeRequest( Defs* defs, Cmd_ptr theCmd, bool check_change_numbers = true ) {
+
+ // Check that state change happens
+ unsigned int state_change_no = Ecf::state_change_no();
+ unsigned int modify_change_no = Ecf::modify_change_no();
+
+ // Setup command for invocation
+ ClientToServerRequest cmd_request;
+ cmd_request.set_cmd( theCmd );
+ // std::cout << cmd_request << "\n";
+
+ MockServer server(defs);
+ STC_Cmd_ptr result = cmd_request.handleRequest(&server);
+ BOOST_CHECK_MESSAGE( result, "ClientToServerRequest " << cmd_request << " returned NULL\n");
+ BOOST_CHECK_MESSAGE( result->error().empty(), cmd_request << " " << result->error());
+ if (check_change_numbers) {
+ BOOST_CHECK_MESSAGE( state_change_no != Ecf::state_change_no() || modify_change_no != Ecf::modify_change_no(),
+ "State & modify change numbers unaltered by command " << cmd_request);
+
+ // Some tests(TestSSyncCmd_CH1.cpp), create defs where invariants like change numbers are deliberately different
+ std::string error_msg;
+ BOOST_CHECK_MESSAGE(defs->checkInvariants(error_msg),"invokeRequest checkInvariants failed " << error_msg << " for cmd " << cmd_request );
+ }
+ }
+
+ static void invokeFailureRequest( Defs* defs, Cmd_ptr theCmd ) {
+
+ ClientToServerRequest cmd_request;
+ cmd_request.set_cmd( theCmd );
+
+ MockServer server(defs);
+
+ // We expect this to fail
+ BOOST_CHECK_THROW(cmd_request.handleRequest(&server), std::runtime_error );
+ }
+
+ static void invokeFailureRequest(MockServer& server, Cmd_ptr theCmd ) {
+
+ ClientToServerRequest cmd_request;
+ cmd_request.set_cmd( theCmd );
+
+ BOOST_CHECK_THROW(cmd_request.handleRequest(&server), std::runtime_error );
+
+// STC_Cmd_ptr result = cmd_request.handleRequest(&server);
+// BOOST_CHECK_MESSAGE( !result->ok(), "ClientToServerRequest " << cmd_request << " was expected to fail \n");
+ }
+
+ static void test_state(node_ptr n,NState::State expected)
+ {
+ BOOST_REQUIRE_MESSAGE(n->state() == expected,"Expected state " << NState::toString(expected) << " but found " << NState::toString(n->state()) << " for " << n->debugNodePath());
+ }
+
+ static void test_state(node_ptr n,DState::State expected)
+ {
+ BOOST_REQUIRE_MESSAGE(n->dstate() == expected,"Expected state " << DState::toString(expected) << " but found " << DState::toString(n->dstate()) << " for " << n->debugNodePath());
+ }
+
+private:
+ TestHelper() {}
+};
+#endif /* TESTHELPER_HPP_ */
+
diff --git a/Base/test/TestLimit.cpp b/Base/test/TestLimit.cpp
new file mode 100644
index 0000000..4a80f99
--- /dev/null
+++ b/Base/test/TestLimit.cpp
@@ -0,0 +1,669 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #32 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <string>
+#include <iostream>
+#include <fstream>
+
+#include <boost/test/unit_test.hpp>
+#include <boost/foreach.hpp>
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "TestHelper.hpp"
+#include "JobsParam.hpp"
+#include "Jobs.hpp"
+#include "System.hpp"
+
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( BaseTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_add_limit )
+{
+ cout << "Base:: ...test_add_limit\n";
+ suite_ptr suite = Suite::create("suite");
+ suite->addLimit(Limit("fast",1)) ; // " Adding limit first time should be ok");
+ BOOST_REQUIRE_THROW(suite->addLimit(Limit("fast",1)), std::runtime_error); //" Adding same limit second time should fail");
+
+ suite->addInLimit(InLimit("fast","/suite")); //" Adding in-limit first time should be ok");
+ BOOST_REQUIRE_THROW(suite->addInLimit(InLimit("fast","/suite")), std::runtime_error); // " Adding in-limit second time should fail");
+}
+
+BOOST_AUTO_TEST_CASE( test_limit_increment )
+{
+ cout << "Base:: ...test_limit_increment\n";
+
+ // Test than when a job is submitted multiple times, it should only consume 1 token
+ //
+ // Create the defs file
+ // suite suite
+ // limit fast 10
+ // family f
+ // inlimit /suite:fast
+ // task t1
+ // endfamily
+ // endsuite
+ Defs defs;
+ std::string limitName = "fast";
+ std::string pathToLimit = "/suite";
+ std::string suitename = "suite";
+ suite_ptr s = defs.add_suite(suitename);
+ family_ptr f = s->add_family("f");
+ task_ptr t1 = f->add_task("t1");
+ {
+ f->addInLimit(InLimit(limitName,pathToLimit));
+ s->addLimit(Limit(limitName,10));
+ }
+ // cerr << defs << "\n";
+
+
+ {
+ // Resolve dependencies:: BEFORE calling beginCmd, should be a NO OP
+ JobsParam jobsParam; // create jobs = false, spawn jobs = false
+ Jobs jobs(&defs);
+ BOOST_CHECK_MESSAGE( jobs.generate(jobsParam),jobsParam.getErrorMsg());
+ BOOST_CHECK_MESSAGE( jobsParam.submitted().size() == 0, "Expected 0 tasks to submit but found " << jobsParam.submitted().size());
+ }
+
+ {
+ // Create a request to begin suite
+ // make sure chosen suite can begin to resolve dependencies.
+ // beginning the suite will:
+ // 1/ set all children to the QUEUED state
+ // 2/ Begin job submission, and hence changes state to ACTIVE for submitted jobs
+ //
+ // Resolve dependencies. Only one task should be submitted due to Limit
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new BeginCmd(suitename)));
+ BOOST_CHECK_MESSAGE( s->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(s->state()));
+ BOOST_CHECK_MESSAGE( f->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f->state()));
+ BOOST_CHECK_MESSAGE( t1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(t1->state()));
+ }
+
+ {
+ // Resolve dependencies. No task should submit since we have reached the limit
+ JobsParam jobsParam; // create jobs = false, spawn jobs = false
+ Jobs jobs(&defs);
+ BOOST_CHECK_MESSAGE( jobs.generate(jobsParam),jobsParam.getErrorMsg());
+ BOOST_CHECK_MESSAGE( jobsParam.submitted().size() == 0, "Expected 0 task to submit but found " << jobsParam.submitted().size());
+ }
+
+ {
+ // Try resubmitting the an active task, it should still only consume 1 token in the limit
+ BOOST_CHECK_MESSAGE( t1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(t1->state()));
+
+ // Hack the state, to allow job to re- resubmitted
+ t1->setStateOnly(NState::QUEUED);
+
+ JobsParam jobsParam; // create jobs = false, spawn jobs = false
+ Jobs jobs(&defs);
+ BOOST_CHECK_MESSAGE( jobs.generate(jobsParam),jobsParam.getErrorMsg());
+ BOOST_CHECK_MESSAGE( jobsParam.submitted().size() == 1, "Expected 1 task to submit but found " << jobsParam.submitted().size());
+
+ // Limit should still have only consumed one token
+ limit_ptr limit = s->find_limit(limitName);
+ BOOST_CHECK_MESSAGE( limit.get(), "Limit not found");
+ BOOST_CHECK_MESSAGE( limit->value() == 1, "Expected limit of value 1, but found " << limit->value());
+ BOOST_CHECK_MESSAGE( limit->paths().size() == 1, "Expected Only 1 task path in limit but found " << limit->paths().size());
+ }
+}
+
+
+//===============================================================================
+// This TEST is used to test limit and inLimit.
+// Both examples taken from the documentation
+BOOST_AUTO_TEST_CASE( test_limit )
+{
+ cout << "Base:: ...test_limit\n";
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Create the defs file
+ // suite suite
+ // limit fast 1
+ // family f
+ // inlimit /suite:fast
+ // task t1
+ // task t2
+ // endfamily
+ // endsuite
+ Defs defs;
+ std::string limitName = "fast";
+ std::string pathToLimit = "/suite";
+ std::string suitename = "suite";
+ family_ptr f = Family::create("f");
+ task_ptr t1 = Task::create("t1");
+ task_ptr t2 = Task::create("t2");
+ suite_ptr s = Suite::create(suitename);
+ {
+ f->addTask( t1 );
+ f->addTask( t2);
+ f->addInLimit(InLimit(limitName,pathToLimit));
+
+ s->addFamily(f);
+ s->addLimit(Limit(limitName,1));
+
+ defs.addSuite( s );
+ }
+ // cerr << defs << "\n";
+
+
+ //*******************************************************************************
+ // Resolve dependencies:: BEFORE calling beginCmd, should be a NO OP
+ {
+ JobsParam jobsParam; // create jobs = false, spawn jobs = false
+ Jobs jobs(&defs);
+ BOOST_CHECK_MESSAGE( jobs.generate(jobsParam),jobsParam.getErrorMsg());
+ BOOST_CHECK_MESSAGE( jobsParam.submitted().size() == 0, "Expected 0 tasks to submit but found " << jobsParam.submitted().size());
+ }
+
+ // ***********************************************************************
+ // Create a request to begin suite
+ // make sure chosen suite can begin to resolve dependencies.
+ // beginning the suite will:
+ // 1/ set all children to the QUEUED state
+ // 2/ Begin job submission, and hence changes state to ACTIVE for submitted jobs
+ //
+ // Resolve dependencies. Only one task should be submitted due to Limit
+ //
+ {
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new BeginCmd(suitename)));
+ BOOST_CHECK_MESSAGE( s->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(s->state()));
+ BOOST_CHECK_MESSAGE( f->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f->state()));
+ BOOST_CHECK_MESSAGE( t1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(t1->state()));
+ BOOST_CHECK_MESSAGE( t2->state() == NState::QUEUED, "expected state NState::QUEUED, but found to be " << NState::toString(t2->state()));
+ }
+
+ //*******************************************************************************
+ // Resolve dependencies. No task should submit since we have reached the limit
+ {
+ JobsParam jobsParam; // create jobs = false, spawn jobs = false
+ Jobs jobs(&defs);
+ BOOST_CHECK_MESSAGE( jobs.generate(jobsParam),jobsParam.getErrorMsg());
+ BOOST_CHECK_MESSAGE( jobsParam.submitted().size() == 0, "Expected 0 task to submit but found " << jobsParam.submitted().size());
+ }
+
+ {
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE( defs.checkInvariants(errorMsg), errorMsg);
+ }
+}
+
+
+BOOST_AUTO_TEST_CASE( test_limit1 )
+{
+ cout << "Base:: ...test_limit1\n";
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Create the defs file
+ // suite suite
+ // limit disk 50
+ // family f
+ // inlimit /suite:disk 20
+ // task t1
+ // task t2
+ // task t3
+ // endfamily
+ // endsuite
+ //
+ // Test that only 2 Tasks can run
+ Defs defs;
+ std::string limitName = "disk";
+ std::string pathToLimit = "/suite";
+ std::string suitename = "suite";
+ family_ptr f = Family::create("f");
+ task_ptr t1 = Task::create("t1");
+ task_ptr t2 = Task::create("t2");
+ task_ptr t3 = Task::create("t3");
+ suite_ptr s = Suite::create(suitename);
+ {
+ f->addTask( t1 );
+ f->addTask( t2 );
+ f->addTask( t3 );
+ f->addInLimit(InLimit(limitName,pathToLimit,20));
+
+ s->addFamily(f);
+ s->addLimit(Limit(limitName,50));
+
+ defs.addSuite( s );
+ }
+ // cerr << defs << "\n";
+
+ //*******************************************************************************
+ // Resolve dependencies:: BEFORE calling beginCmd, should be a NO OP
+ {
+ JobsParam jobsParam; // create jobs = false, spawn jobs = false
+ Jobs jobs(&defs);
+ BOOST_CHECK_MESSAGE( jobs.generate(jobsParam),jobsParam.getErrorMsg());
+ BOOST_CHECK_MESSAGE( jobsParam.submitted().size() == 0, "Expected 0 tasks to submit but found " << jobsParam.submitted().size());
+ }
+
+ // ***********************************************************************
+ // Create a request to begin suite
+ // make sure chosen suite can begin to resolve dependencies.
+ // beginning the suite will:
+ // 1/ set all children to the QUEUED state
+ // 2/ Begin job submission, and hence changes state to ACTIVE for submitted jobs
+ //
+ // Resolve dependencies. Only TWO task should be active due to Limit
+ {
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new BeginCmd(suitename)));
+ BOOST_CHECK_MESSAGE( s->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(s->state()));
+ BOOST_CHECK_MESSAGE( f->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f->state()));
+ BOOST_CHECK_MESSAGE( t1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(t1->state()));
+ BOOST_CHECK_MESSAGE( t2->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(t2->state()));
+ BOOST_CHECK_MESSAGE( t3->state() == NState::QUEUED, "expected state NState::QUEUED, but found to be " << NState::toString(t3->state()));
+ }
+
+ //*******************************************************************************
+ // Resolve dependencies. No task should submit since we have reached the limit
+ {
+ JobsParam jobsParam; // create jobs = false, spawn jobs = false
+ Jobs jobs(&defs);
+ BOOST_CHECK_MESSAGE( jobs.generate(jobsParam),jobsParam.getErrorMsg());
+ BOOST_CHECK_MESSAGE( jobsParam.submitted().size() == 0, "Expected 0 task to submit but found " << jobsParam.submitted().size());
+ if (jobsParam.submitted().size() != 0 ) {
+ BOOST_FOREACH(Submittable* t, jobsParam.submitted()) { cerr << "Submittable " << t->absNodePath() << "\n";}
+ }
+ }
+
+ {
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE( defs.checkInvariants(errorMsg), errorMsg);
+ }
+}
+
+
+BOOST_AUTO_TEST_CASE( test_limit_references_after_delete )
+{
+ /// In-limit have a reference to a limit. This limit can be on another node. If that node is deleted
+ /// The limits are also deleted, hence we need to ensure in-limit reference to limits that are being
+ /// deleted are cleared. Currently we use shared_ptr to achieve this
+ cout << "Base:: ...test_limit_references_after_delete\n";
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Create the defs file
+ // suite suiteLimits # the limit we want delete
+ // limit limit1 1
+ // limit limit2 1
+ // limit limit3 1
+ // endsuite
+ //
+ // suite suite
+ // family f
+ // inlimit /suiteLimits:limit1 # check limits references cleared after suiteLimits is deleted
+ // task t1
+ // endfamily
+ // family f1
+ // inlimit /suiteLimits:limit2
+ // task t1
+ // endfamily
+ // family f2
+ // inlimit /suiteLimits:limit3
+ // task t1
+ // endfamily
+ // endsuite
+ //
+ // In this test case we will delete the suiteLimits, and then test to ensure the the in-limits
+ // in suite have been reset.
+ Defs defs;
+ {
+ suite_ptr suite = Suite::create("suiteLimits" );
+ suite->addLimit(Limit("limit1",1));
+ suite->addLimit(Limit("limit2",1));
+ suite->addLimit(Limit("limit3",1));
+ defs.addSuite( suite );
+ }
+
+ InLimit in_limit1("limit1","/suiteLimits");
+ InLimit in_limit2("limit2","/suiteLimits");
+ InLimit in_limit3("limit3","/suiteLimits");
+ {
+ suite_ptr suite = Suite::create("suite");
+
+ family_ptr fam = Family::create("f");
+ fam->addTask( Task::create("t1") );
+ fam->addInLimit(in_limit1);
+ suite->addFamily(fam);
+
+ family_ptr fam2 = Family::create("f1");
+ fam2->addTask( Task::create("t1") );
+ fam2->addInLimit(in_limit2);
+ suite->addFamily(fam2);
+
+ family_ptr fam3 = Family::create("f2");
+ fam3->addTask( Task::create("t1") );
+ fam3->addInLimit(in_limit3);
+ suite->addFamily(fam3);
+
+ defs.addSuite( suite );
+ }
+
+
+ // First check that in-limit reference have been setup
+ node_ptr f = defs.findAbsNode("/suite/f");
+ node_ptr f1 = defs.findAbsNode("/suite/f1");
+ node_ptr f2 = defs.findAbsNode("/suite/f2");
+ BOOST_REQUIRE_MESSAGE( f.get() && f1.get() && f2.get(), "Failed to find family than contain the inlimits");
+
+
+ BOOST_REQUIRE_MESSAGE( f->findInLimitByNameAndPath(in_limit1) &&
+ f1->findInLimitByNameAndPath(in_limit2) &&
+ f2->findInLimitByNameAndPath(in_limit3) , "Failed to find in-limits on the families" << defs);
+
+ // Now check they all reference the limits
+ BOOST_REQUIRE_MESSAGE( f->findLimitViaInLimit(in_limit1), "Inlimit does not reference its limit. Post process failed ?");
+ BOOST_REQUIRE_MESSAGE( f1->findLimitViaInLimit(in_limit2), "Inlimit does not reference its limit. Post process failed ?");
+ BOOST_REQUIRE_MESSAGE( f2->findLimitViaInLimit(in_limit3), "Inlimit does not reference its limit. Post process failed ?");
+
+ // Ok Now delete suiteLimits, as this is where the limits reside
+ // *** It is extremely important that shared_ptr for '/suiteLimit' is in its own
+ // *** scope, otherwise it will keep the 'suite' live, and NOT delete the limits
+ {
+ node_ptr suiteLimits = defs.findAbsNode("/suiteLimits");
+ BOOST_REQUIRE_MESSAGE( suiteLimits.get(), "Could not find the suite we want to delete?");
+ BOOST_REQUIRE_MESSAGE( defs.deleteChild(suiteLimits.get()), "Deletion failed?");
+ BOOST_REQUIRE_MESSAGE( !defs.findAbsNode("/suiteLimits").get(), "Deletion failed?");
+ }
+
+ BOOST_REQUIRE_MESSAGE( !f->findLimitViaInLimit(in_limit1), "In-limit still references limit that has been deleted?");
+ BOOST_REQUIRE_MESSAGE( !f1->findLimitViaInLimit(in_limit2), "In-limit still references limit that has been deleted?");
+ BOOST_REQUIRE_MESSAGE( !f2->findLimitViaInLimit(in_limit3), "In-limit still references limit that has been deleted?");
+}
+
+BOOST_AUTO_TEST_CASE( test_limits_after_force_cmd )
+{
+ cout << "Base:: ...test_limits_after_force_cmd\n";
+
+ // Create the following defs
+ // suite s1
+ // limit A 10
+ // family f1
+ // inlimit A
+ // task t1
+ // task t2
+ // family f2
+ // inlimit A
+ // task t1
+ // task t2
+
+ // When all the tasks are running/submitted state, limit A should have consumed 4 tokens
+ // However if we how force family f2 to be complete, then the limit should be reset back to 2 tokens.
+ // Repeating for family f1, should result with a Limit with no tokens
+ Defs defs;
+ suite_ptr s1 = defs.add_suite("s1");
+ s1->addLimit(Limit("A",10));
+ family_ptr f1 = s1->add_family("f1");
+ f1->addInLimit( InLimit("A","/s1"));
+ task_ptr f1_t1 = f1->add_task("t1");
+ task_ptr f1_t2 = f1->add_task("t2");
+ family_ptr f2 = s1->add_family("f2");
+ f2->addInLimit( InLimit("A","/s1"));
+ task_ptr f2_t1 = f2->add_task("t1");
+ task_ptr f2_t2 = f2->add_task("t2");
+ //cout << defs;
+
+ // Create a request to begin suite
+ // make sure chosen suite can begin to resolve dependencies.
+ // beginning the suite will:
+ // 1/ set all children to the QUEUED state
+ // 2/ Begin job submission, and hence changes state to ACTIVE for submitted jobs
+ //
+ // Resolve dependencies. All tasks are within the limit and hence should start
+ {
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new BeginCmd("/s1")));
+ BOOST_CHECK_MESSAGE( s1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(s1->state()));
+ BOOST_CHECK_MESSAGE( f1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1->state()));
+ BOOST_CHECK_MESSAGE( f1_t1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1_t1->state()));
+ BOOST_CHECK_MESSAGE( f1_t2->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1_t2->state()));
+ BOOST_CHECK_MESSAGE( f2->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f2->state()));
+ BOOST_CHECK_MESSAGE( f2_t1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f2_t1->state()));
+ BOOST_CHECK_MESSAGE( f2_t2->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f2_t2->state()));
+
+ limit_ptr the_limit = s1->find_limit("A");
+ BOOST_CHECK_MESSAGE( the_limit, "Could not find limit");
+ BOOST_CHECK_MESSAGE( the_limit->value() == 4,"Expected limit value to be 4 but found " << the_limit->value());
+ }
+
+ {
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new ForceCmd(f2->absNodePath(),"complete",true /*recursive */, false /* set Repeat to last value */)));
+
+ BOOST_CHECK_MESSAGE( s1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(s1->state()));
+ BOOST_CHECK_MESSAGE( f1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1->state()));
+ BOOST_CHECK_MESSAGE( f1_t1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1_t1->state()));
+ BOOST_CHECK_MESSAGE( f1_t2->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1_t2->state()));
+ BOOST_CHECK_MESSAGE( f2->state() == NState::COMPLETE, "expected state NState::COMPLETE, but found to be " << NState::toString(f2->state()));
+ BOOST_CHECK_MESSAGE( f2_t1->state() == NState::COMPLETE, "expected state NState::COMPLETE, but found to be " << NState::toString(f2_t1->state()));
+ BOOST_CHECK_MESSAGE( f2_t2->state() == NState::COMPLETE, "expected state NState::COMPLETE, but found to be " << NState::toString(f2_t2->state()));
+
+ limit_ptr the_limit = s1->find_limit("A");
+ BOOST_CHECK_MESSAGE( the_limit, "Could not find limit");
+ BOOST_CHECK_MESSAGE( the_limit->value() == 2,"Expected limit value to be 2 but found " << the_limit->value());
+ }
+
+ {
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new ForceCmd(f1->absNodePath(),"complete",true /*recursive */, false /* set Repeat to last value */)));
+
+ BOOST_CHECK_MESSAGE( s1->state() == NState::COMPLETE, "expected state NState::ACTIVE, but found to be " << NState::toString(s1->state()));
+ BOOST_CHECK_MESSAGE( f1->state() == NState::COMPLETE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1->state()));
+ BOOST_CHECK_MESSAGE( f1_t1->state() == NState::COMPLETE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1_t1->state()));
+ BOOST_CHECK_MESSAGE( f1_t2->state() == NState::COMPLETE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1_t2->state()));
+ BOOST_CHECK_MESSAGE( f2->state() == NState::COMPLETE, "expected state NState::COMPLETE, but found to be " << NState::toString(f2->state()));
+ BOOST_CHECK_MESSAGE( f2_t1->state() == NState::COMPLETE, "expected state NState::COMPLETE, but found to be " << NState::toString(f2_t1->state()));
+ BOOST_CHECK_MESSAGE( f2_t2->state() == NState::COMPLETE, "expected state NState::COMPLETE, but found to be " << NState::toString(f2_t2->state()));
+
+ limit_ptr the_limit = s1->find_limit("A");
+ BOOST_CHECK_MESSAGE( the_limit, "Could not find limit");
+ BOOST_CHECK_MESSAGE( the_limit->value() == 0,"Expected limit value to be 0 but found " << the_limit->value());
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_limits_after_requeue_family_ECFLOW_196 )
+{
+ cout << "Base:: ...test_limits_after_requeue_family_ECFLOW_196\n";
+
+ // This test is used to ensure that, requeue causes node to release tokens held by the Limits
+
+ // Create the following defs
+ // suite s1
+ // limit A 10
+ // family f1
+ // inlimit A
+ // task t1
+ // task t2
+ // family f2
+ // inlimit A
+ // task t1
+ // task t2
+
+ // When all the tasks are running/submitted state, limit A should have consumed 4 tokens
+ // However if we how force family f2 to be requeud, then the limit should be reset back to 2 tokens.
+ Defs defs;
+ suite_ptr s1 = defs.add_suite("s1");
+ s1->addLimit(Limit("A",10));
+ family_ptr f1 = s1->add_family("f1");
+ f1->addInLimit( InLimit("A","/s1"));
+ task_ptr f1_t1 = f1->add_task("t1");
+ task_ptr f1_t2 = f1->add_task("t2");
+ family_ptr f2 = s1->add_family("f2");
+ f2->addInLimit( InLimit("A","/s1"));
+ task_ptr f2_t1 = f2->add_task("t1");
+ task_ptr f2_t2 = f2->add_task("t2");
+ //cout << defs;
+
+
+ // Create a request to begin suite
+ // make sure chosen suite can begin to resolve dependencies.
+ // beginning the suite will:
+ // 1/ set all children to the QUEUED state
+ // 2/ Begin job submission, and hence changes state to ACTIVE for submitted jobs
+ //
+ // Resolve dependencies. All tasks are within the limit and hence should start
+ int expected_limit_value = 4;
+ limit_ptr the_limit = s1->find_limit("A");
+ BOOST_CHECK_MESSAGE( the_limit, "Could not find limit");
+ {
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new BeginCmd("/s1")));
+ BOOST_CHECK_MESSAGE( s1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(s1->state()));
+ BOOST_CHECK_MESSAGE( f1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1->state()));
+ BOOST_CHECK_MESSAGE( f1_t1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1_t1->state()));
+ BOOST_CHECK_MESSAGE( f1_t2->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1_t2->state()));
+ BOOST_CHECK_MESSAGE( f2->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f2->state()));
+ BOOST_CHECK_MESSAGE( f2_t1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f2_t1->state()));
+ BOOST_CHECK_MESSAGE( f2_t2->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f2_t2->state()));
+
+ BOOST_CHECK_MESSAGE( the_limit->value() == expected_limit_value,"Expected limit value to be 4 but found " << the_limit->value());
+ }
+
+ {
+ expected_limit_value = 2;
+ // We now want to re-queue node f2, and check to see that limit tokens are released after the re-queue
+ // However, the Mock server, will call resolve dependencies after re-queue command , and place nodes *back* into active
+ // state, to *STOP* this, we will add a trigger, so that the dependencies will not resolve, and hence nodes stay queued
+ f2->add_trigger("1 == 0");
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new RequeueNodeCmd(f2->absNodePath(),RequeueNodeCmd::FORCE)));
+
+ BOOST_CHECK_MESSAGE( s1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(s1->state()));
+ BOOST_CHECK_MESSAGE( f1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1->state()));
+ BOOST_CHECK_MESSAGE( f1_t1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1_t1->state()));
+ BOOST_CHECK_MESSAGE( f1_t2->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1_t2->state()));
+ BOOST_CHECK_MESSAGE( f2->state() == NState::QUEUED, "expected state NState::QUEUED, but found to be " << NState::toString(f2->state()));
+ BOOST_CHECK_MESSAGE( f2_t1->state() == NState::QUEUED, "expected state NState::QUEUED, but found to be " << NState::toString(f2_t1->state()));
+ BOOST_CHECK_MESSAGE( f2_t2->state() == NState::QUEUED, "expected state NState::QUEUED, but found to be " << NState::toString(f2_t2->state()));
+
+ BOOST_CHECK_MESSAGE( the_limit->value() == expected_limit_value,"Expected limit value to be 2 but found " << the_limit->value());
+ }
+
+ {
+ expected_limit_value = 0;
+ // We now want to re-queue node f1, and check to see that limit tokens are released after the re-queue
+ // However, the Mock server, will call resolve dependencies after re-queue command , and place nodes *back* into active
+ // state, to *STOP* this, we will add a trigger, so that the dependencies will not resolve, and hence nodes stay queued
+ f1->add_trigger("1 == 0");
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new RequeueNodeCmd(f1->absNodePath(),RequeueNodeCmd::FORCE)));
+
+ BOOST_CHECK_MESSAGE( s1->state() == NState::QUEUED, "expected state NState::ACTIVE, but found to be " << NState::toString(s1->state()));
+ BOOST_CHECK_MESSAGE( f1->state() == NState::QUEUED, "expected state NState::ACTIVE, but found to be " << NState::toString(f1->state()));
+ BOOST_CHECK_MESSAGE( f1_t1->state() == NState::QUEUED, "expected state NState::ACTIVE, but found to be " << NState::toString(f1_t1->state()));
+ BOOST_CHECK_MESSAGE( f1_t2->state() == NState::QUEUED, "expected state NState::ACTIVE, but found to be " << NState::toString(f1_t2->state()));
+ BOOST_CHECK_MESSAGE( f2->state() == NState::QUEUED, "expected state NState::QUEUED, but found to be " << NState::toString(f2->state()));
+ BOOST_CHECK_MESSAGE( f2_t1->state() == NState::QUEUED, "expected state NState::QUEUED, but found to be " << NState::toString(f2_t1->state()));
+ BOOST_CHECK_MESSAGE( f2_t2->state() == NState::QUEUED, "expected state NState::QUEUED, but found to be " << NState::toString(f2_t2->state()));
+
+ BOOST_CHECK_MESSAGE( the_limit->value() == expected_limit_value,"Expected limit value to be 0 but found " << the_limit->value());
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_limits_after_requeue_task_ECFLOW_196 )
+{
+ cout << "Base:: ...test_limits_after_requeue_task_ECFLOW_196\n";
+
+ // This test is used to ensure that, requeue causes node to release tokens held by the Limits
+
+ // Create the following def, i.e using internal and external limits
+ // suite s0
+ // limit X 5
+ // suite s1
+ // limit A 10
+ // limit B 5
+ // family f1
+ // inlimit A
+ // inlimit B
+ // inlimit X /s0/
+ // task t1
+ // task t2
+ // family f2
+ // inlimit A
+ // inlimit B
+ // inlimit X /s0/
+ // task t1
+ // task t2
+
+ // When all the tasks are running/submitted state, limit A should have consumed 4 tokens
+ // However if we how force task to reque, then the token should be released
+ Defs defs;
+ suite_ptr s0 = defs.add_suite("s0");
+ s0->addLimit(Limit("X",10));
+
+ suite_ptr s1 = defs.add_suite("s1");
+ s1->addLimit(Limit("A",10));
+ s1->addLimit(Limit("B",5));
+ family_ptr f1 = s1->add_family("f1");
+ f1->addInLimit( InLimit("A","/s1"));
+ f1->addInLimit( InLimit("B","/s1"));
+ f1->addInLimit( InLimit("X","/s0"));
+ task_ptr f1_t1 = f1->add_task("t1");
+ task_ptr f1_t2 = f1->add_task("t2");
+ family_ptr f2 = s1->add_family("f2");
+ f2->addInLimit( InLimit("A","/s1"));
+ f2->addInLimit( InLimit("B","/s1"));
+ f2->addInLimit( InLimit("X","/s0"));
+ task_ptr f2_t1 = f2->add_task("t1");
+ task_ptr f2_t2 = f2->add_task("t2");
+
+ std::vector<task_ptr> tasks;
+ tasks.push_back(f1_t1); tasks.push_back(f1_t2);
+ tasks.push_back(f2_t1); tasks.push_back(f2_t2);
+ //cout << defs;
+
+ limit_ptr the_A_limit = s1->find_limit("A");
+ limit_ptr the_B_limit = s1->find_limit("B");
+ limit_ptr the_X_limit = s0->find_limit("X");
+ BOOST_CHECK_MESSAGE( the_A_limit && the_B_limit && the_X_limit, "Could not find limits");
+
+ // Create a request to begin suite
+ // make sure chosen suite can begin to resolve dependencies.
+ // beginning the suite will:
+ // 1/ set all children to the QUEUED state
+ // 2/ Begin job submission, and hence changes state to ACTIVE for submitted jobs
+ //
+ // Resolve dependencies. All tasks are within the limit and hence should start
+ int expected_limit_value = 4;
+ {
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new BeginCmd("/s1")));
+ BOOST_CHECK_MESSAGE( s1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(s1->state()));
+ BOOST_CHECK_MESSAGE( f1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1->state()));
+ BOOST_CHECK_MESSAGE( f1_t1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1_t1->state()));
+ BOOST_CHECK_MESSAGE( f1_t2->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1_t2->state()));
+ BOOST_CHECK_MESSAGE( f2->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f2->state()));
+ BOOST_CHECK_MESSAGE( f2_t1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f2_t1->state()));
+ BOOST_CHECK_MESSAGE( f2_t2->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f2_t2->state()));
+
+ BOOST_CHECK_MESSAGE( the_A_limit->value() == expected_limit_value,"Expected limit value to be " << expected_limit_value << " but found " << the_A_limit->value());
+ BOOST_CHECK_MESSAGE( the_B_limit->value() == expected_limit_value,"Expected limit value to be " << expected_limit_value << " but found " << the_B_limit->value());
+ BOOST_CHECK_MESSAGE( the_X_limit->value() == expected_limit_value,"Expected limit value to be " << expected_limit_value << " but found " << the_X_limit->value());
+ }
+
+ {
+ // We now want to re-queue node tasks, and check to see that limit tokens are released after the re-queue
+ // However, the Mock server, will call resolve dependencies after re-queue command , and place nodes *back* into active
+ // state, to *STOP* this, we will add a trigger, so that the dependencies will not resolve, and hence nodes stay queued
+ f1->add_trigger("1 == 0");
+ f2->add_trigger("1 == 0");
+
+ for(size_t i =0; i < tasks.size(); i++) {
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new RequeueNodeCmd(tasks[i]->absNodePath(),RequeueNodeCmd::FORCE)));
+ expected_limit_value--;
+ BOOST_CHECK_MESSAGE( the_A_limit->value() == expected_limit_value,"Expected limit value " << expected_limit_value << " but found " << the_A_limit->value());
+ BOOST_CHECK_MESSAGE( the_B_limit->value() == expected_limit_value,"Expected limit value " << expected_limit_value << " but found " << the_B_limit->value());
+ BOOST_CHECK_MESSAGE( the_X_limit->value() == expected_limit_value,"Expected limit value " << expected_limit_value << " but found " << the_X_limit->value());
+ }
+ }
+
+ /// Destroy System singleton to avoid valgrind from complaining
+ System::destroy();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Base/test/TestLogCmd.cpp b/Base/test/TestLogCmd.cpp
new file mode 100644
index 0000000..b9e143e
--- /dev/null
+++ b/Base/test/TestLogCmd.cpp
@@ -0,0 +1,95 @@
+ //============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #9 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include "ClientToServerCmd.hpp"
+#include "TestHelper.hpp"
+#include "Defs.hpp"
+#include "Log.hpp"
+#include "File.hpp"
+#include "Str.hpp"
+
+using namespace boost;
+namespace fs = boost::filesystem;
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( BaseTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_log_cmd )
+{
+ cout << "Base:: ...test_log_cmd\n";
+
+ {
+ LogCmd log_cmd;
+ BOOST_REQUIRE_MESSAGE(log_cmd.api() == LogCmd::GET," expected GET as the default");
+ BOOST_REQUIRE_MESSAGE(log_cmd.new_path() == "","expected empty path but found " << log_cmd.new_path());
+ }
+
+ {
+ LogCmd log_cmd("/a/path");
+ BOOST_REQUIRE_MESSAGE(log_cmd.api() == LogCmd::NEW," expected NEW as the default api when path provided");
+ BOOST_REQUIRE_MESSAGE(log_cmd.new_path() == "/a/path","expected 'a/path' but found " << log_cmd.new_path());
+ }
+
+ // ECFLOW-377
+ {
+ LogCmd log_cmd("/a/path ");
+ BOOST_CHECK_MESSAGE(log_cmd.new_path() == "/a/path","expected '/a/path' but found '" << log_cmd.new_path() << "'");
+ }
+ {
+ LogCmd log_cmd(" /a/path");
+ BOOST_CHECK_MESSAGE(log_cmd.new_path() == "/a/path","expected '/a/path' but found '" << log_cmd.new_path() << "'");
+ }
+ {
+ LogCmd log_cmd(" /a/path ");
+ BOOST_CHECK_MESSAGE(log_cmd.new_path() == "/a/path","expected '/a/path' but found '" << log_cmd.new_path() << "'");
+ }
+
+ // Create a new log file, equivalent --log=new .../Base/test/new_logfile.txt
+ // LogCmd::doHandleRequest needs log file to have been created first
+ std::string old_log_file = File::test_data("Base/test/old_logfile.txt","Base");
+ Log::instance()->create(old_log_file);
+
+ std::string new_log_file = File::test_data("Base/test/new_logfile.txt ","Base"); // ECFLOW-377 note extra space at the end
+ std::string expected_new_log_file = File::test_data("Base/test/new_logfile.txt","Base"); // space removed
+
+ // ECFLOW-376 --log=new <path> should be treated same as changing ECF_LOG from the gui. i.e added as a user variable. hence visible in GUI
+ Defs defs;
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new LogCmd(new_log_file)), false /* check_change_numbers */);
+ BOOST_CHECK_MESSAGE( defs.server().find_variable("ECF_LOG") == expected_new_log_file , "expected to find ECF_LOG with value '" << expected_new_log_file << "' but found '" << defs.server().find_variable("ECF_LOG") << "'");
+ BOOST_CHECK_MESSAGE( defs.server().find_user_variable("ECF_LOG") == expected_new_log_file , "expected to find ECF_LOG in the *USER* variables '" << expected_new_log_file << "' but found '" << defs.server().find_user_variable("ECF_LOG") << "'");
+ BOOST_CHECK_MESSAGE( Log::instance()->path() == expected_new_log_file , "expected to find ECF_LOG with value '" << expected_new_log_file << "' but found '" << defs.server().find_variable("ECF_LOG") << "'");
+
+
+ // Update ECF_LOG to have a *SPACE* at the end. ECFLOW-377
+ defs.set_server().add_or_update_user_variables(Str::ECF_LOG(),new_log_file);
+ BOOST_CHECK_MESSAGE( defs.server().find_variable("ECF_LOG") == new_log_file , "expected to find ECF_LOG with value '" << new_log_file << "' but found '" << defs.server().find_variable("ECF_LOG") << "'");
+
+
+ // INVOKE log command where we update log file from ECF_LOG, equivalent --log=new
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new LogCmd(LogCmd::NEW)), false /* check_change_numbers */);
+ BOOST_CHECK_MESSAGE( Log::instance()->path() == expected_new_log_file , "expected to find Log::instance()->path() with value '" << expected_new_log_file << "' but found '" << defs.server().find_variable("ECF_LOG") << "'");
+
+ // tidy up
+ Log::instance()->destroy();
+ fs::remove(old_log_file); // remove generated log file
+ fs::remove(expected_new_log_file); // remove generated log file
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/Base/test/TestMeterCmd.cpp b/Base/test/TestMeterCmd.cpp
new file mode 100644
index 0000000..534dd07
--- /dev/null
+++ b/Base/test/TestMeterCmd.cpp
@@ -0,0 +1,96 @@
+ //============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #9 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <boost/test/unit_test.hpp>
+#include <boost/foreach.hpp>
+#include <string>
+#include <iostream>
+#include <fstream>
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "TestHelper.hpp"
+#include "System.hpp"
+
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( BaseTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_meter_cmd )
+{
+ cout << "Base:: ...test_meter_cmd\n";
+ // Create the defs file.
+ // suite suite
+ // family f
+ // task t1
+ // meter m 0 100 100
+ // endfamily
+ // endsuite
+ Defs defs;
+ string suite_f_t1 = "suite/f/t1";
+ task_ptr t1 = Task::create("t1");
+ std::string meter_name = "m";
+ {
+ t1->addMeter( Meter(meter_name,0,100,100));
+ suite_ptr s = Suite::create("suite");
+ family_ptr f = Family::create("f");
+ f->addTask( t1 );
+ s->addFamily(f);
+ defs.addSuite( s );
+ }
+
+ // Meter which doesn't exist should be silently ignore
+ int meter_value = 10;
+ TestHelper::invokeRequest(&defs,
+ Cmd_ptr( new MeterCmd(suite_f_t1,
+ Submittable::DUMMY_JOBS_PASSWORD(),
+ Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),
+ 1,"FRED",meter_value)),
+ false /* expect change number not to change */
+ );
+
+ /// Test setting meter value
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new MeterCmd(suite_f_t1,Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1,meter_name,meter_value)));
+ const Meter& the_meter = t1->findMeter(meter_name);
+ BOOST_CHECK_MESSAGE( !the_meter.empty(), "Meter not found");
+ BOOST_CHECK_MESSAGE( the_meter.value() == meter_value, "Expected meter value " << meter_value << " but found " << the_meter.value());
+
+
+ /// Set a meter value less than the current value.
+ meter_value = 9;
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new MeterCmd(suite_f_t1,Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1,meter_name,meter_value)));
+ BOOST_CHECK_MESSAGE( the_meter.value() == meter_value, "Expected meter value " << meter_value << " but found " << the_meter.value());
+
+ /// Set a meter value greater than max meter, this should be ignored
+ /// Avoid failing task, if meter, value is out of range. Just log a warning message
+ meter_value = 2000;
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new MeterCmd(suite_f_t1,Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1,meter_name,meter_value))
+ ,false /* expect change number not to change */);
+ BOOST_CHECK_MESSAGE( the_meter.value() == 9, "Expected meter value 9 but found " << the_meter.value());
+
+
+ /// Set to valid value
+ meter_value = 20;
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new MeterCmd(suite_f_t1,Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1,meter_name,meter_value)));
+ BOOST_CHECK_MESSAGE( the_meter.value() == meter_value, "Expected meter value " << meter_value << " but found " << the_meter.value());
+
+ /// Destroy System singleton to avoid valgrind from complaining
+ System::destroy();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/Base/test/TestProgramOptions.cpp b/Base/test/TestProgramOptions.cpp
new file mode 100644
index 0000000..91aa99c
--- /dev/null
+++ b/Base/test/TestProgramOptions.cpp
@@ -0,0 +1,160 @@
+ //============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #9 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <string>
+#include <iostream>
+#include <fstream>
+
+#include <boost/test/unit_test.hpp>
+#include <boost/foreach.hpp>
+#include <boost/program_options.hpp>
+
+using namespace std;
+namespace po = boost::program_options;
+
+BOOST_AUTO_TEST_SUITE( BaseTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_program_options_implicit_value )
+{
+ cout << "Base:: ...test_program_options_implicit_value\n";
+
+ // Declare the supported options.
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help", "produce help message")
+ ("arg1", po::value<string>()->implicit_value( string("") ), "optional arg1 description") ;
+
+ {
+ char* argv[] = {
+ const_cast<char*>("test_program_options_implicit_value"),
+ const_cast<char*>("--help"),
+ const_cast<char*>("--arg1")
+ };
+
+ po::variables_map vm;
+ po::store(po::parse_command_line(3, argv, desc), vm); // populate variable map
+ po::notify(vm); // raise any errors
+
+ BOOST_CHECK_MESSAGE(vm.count("help"), "Expected help");
+ BOOST_CHECK_MESSAGE(vm.count("arg1"), "Expected arg1");
+ BOOST_CHECK_MESSAGE(vm["arg1"].as<string>() == "", "Expected arg1 to be empty");
+ }
+// {
+// // This test fails on boost 1.59, can't cope --arg1 10, only --arg1=10 *******
+// // See: ECFLOW-509 and https://svn.boost.org/trac/boost/ticket/11893
+// char* argv[] = {
+// const_cast<char*>("test_program_options_implicit_value"),
+// const_cast<char*>("--arg1"),
+// const_cast<char*>("10")
+// };
+//
+// po::variables_map vm;
+//// po::store(po::parse_command_line(3, argv, desc,
+//// po::command_line_style::unix_style ^ po::command_line_style::allow_short ^
+//// po::command_line_style::long_allow_adjacent |
+//// po::command_line_style::short_allow_adjacent |
+//// po::command_line_style::allow_long_disguise
+//// ), vm);
+//
+// po::store(po::command_line_parser(3,argv).options(desc).style(
+// po::command_line_style::long_allow_next |
+// po::command_line_style::allow_long_disguise |
+// po::command_line_style::long_allow_adjacent).run(),
+// vm);
+// po::notify(vm);
+//
+// BOOST_CHECK_MESSAGE(vm.count("arg1"), "Expected arg1");
+// BOOST_CHECK_MESSAGE(vm["arg1"].as<string>() == "10", "Expected arg1 with value of 10 but found '" << vm["arg1"].as<string>() << "'");
+// }
+
+ {
+ char* argv[] = {
+ const_cast<char*>("test_program_options_implicit_value"),
+ const_cast<char*>("--arg1=11")
+ };
+
+ po::variables_map vm;
+ po::store(po::parse_command_line(2, argv, desc), vm);
+ po::notify(vm);
+
+ BOOST_CHECK_MESSAGE(vm.count("arg1"), "Expected arg1");
+ BOOST_CHECK_MESSAGE(vm["arg1"].as<string>() == "11", "Expected arg1 with value of 11 but found " << vm["arg1"].as<string>());
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_program_options_multitoken )
+{
+ cout << "Base:: ...test_program_options_multitoken\n";
+
+ // Declare the supported options.
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help", "produce help message")
+ ("arg1", po::value< vector<string> >()->multitoken(), "arg1 description") ;
+
+ char* argv[] = {
+ const_cast<char*>("test_program_options_multitoken"),
+ const_cast<char*>("--help"),
+ const_cast<char*>("--arg1"),
+ const_cast<char*>("a"),
+ const_cast<char*>("b")
+ };
+
+ po::variables_map vm;
+ po::store(po::parse_command_line(5, argv, desc), vm);
+ po::notify(vm);
+
+ BOOST_CHECK_MESSAGE(vm.count("help"), "Expected help");
+ BOOST_CHECK_MESSAGE(vm.count("arg1"), "Expected arg1");
+
+ std::vector<string> expected; expected.push_back("a"); expected.push_back("b");
+ BOOST_CHECK_MESSAGE(vm["arg1"].as< vector<string> >() == expected, "multi-token not as expected");
+}
+
+BOOST_AUTO_TEST_CASE( test_program_options_multitoken_with_negative_values )
+{
+ cout << "Base:: ...test_program_options_multitoken_with_negative_values\n";
+
+ // Declare the supported options.
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help", "produce help message")
+ ("arg1", po::value< vector<string> >()->multitoken(), "arg1 description") ;
+
+ char* argv[] = {
+ const_cast<char*>("test_program_options_multitoken_1"),
+ const_cast<char*>("--help"),
+ const_cast<char*>("--arg1"),
+ const_cast<char*>("-1"),
+ const_cast<char*>("-w")
+ };
+
+ // --alter delete cron -w 0,1 10:00 /s1 # -w treated as option
+ // --alter=/s1 change meter name -1 # -1 treated as option
+ // Note: negative numbers get treated as options: i.e trying to change meter value to a negative number
+ // To avoid negative numbers from being treated as option use, we need to change command line style:
+ // po::command_line_style::unix_style ^ po::command_line_style::allow_short
+
+ po::variables_map vm;
+ po::store(po::parse_command_line(5, argv, desc,po::command_line_style::unix_style ^ po::command_line_style::allow_short), vm);
+ po::notify(vm);
+
+ BOOST_CHECK_MESSAGE(vm.count("help"), "Expected help");
+ BOOST_CHECK_MESSAGE(vm.count("arg1"), "Expected arg1");
+
+ std::vector<string> expected; expected.push_back("-1"); expected.push_back("-w");
+ BOOST_CHECK_MESSAGE(vm["arg1"].as< vector<string> >() == expected, "multi-token not as expected");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Base/test/TestRequest.cpp b/Base/test/TestRequest.cpp
new file mode 100644
index 0000000..32fa3fc
--- /dev/null
+++ b/Base/test/TestRequest.cpp
@@ -0,0 +1,316 @@
+//============================================================================
+// Name : Request
+// Author : Avi
+// Revision : $Revision: #128 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include "boost/make_shared.hpp"
+
+#include "MyDefsFixture.hpp"
+#include "ServerToClientResponse.hpp"
+#include "TestHelper.hpp"
+#include "SerializationTest.hpp"
+#include "DefsCmd.hpp"
+#include "SNodeCmd.hpp"
+#include "ErrorCmd.hpp"
+#include "StcCmd.hpp"
+#include "SStringCmd.hpp"
+#include "SServerLoadCmd.hpp"
+#include "GroupSTCCmd.hpp"
+#include "SSyncCmd.hpp"
+#include "SNewsCmd.hpp"
+#include "System.hpp"
+
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+
+BOOST_FIXTURE_TEST_SUITE( BaseTestSuite, MyDefsFixture )
+
+// Can't delete the fixture defs, hence use a NULL deleter to avoid freeing memory twice.
+// Required since DefsCmd and LoadDefsCmd requires a shared_ptr.
+struct null_deleter { void operator()(void const *) const{} };
+
+
+static void populateCmdVec(std::vector<Cmd_ptr>& cmd_vec, std::vector<STC_Cmd_ptr>& stc_cmd_vec, MockServer* mock_server)
+{
+ std::vector<std::string> suite_names; suite_names.push_back("suiteName");
+ MyDefsFixture fixture;
+ defs_ptr client_defs = fixture.create_defs();
+
+ // Client --> Server commands
+ // make sure begin cmd is first. As this will init calendar. + other commands rely on it
+ // i.e RequeueNodeCmd assumes calendar has been initialized
+ cmd_vec.push_back( Cmd_ptr( new ShowCmd()));
+ cmd_vec.push_back( Cmd_ptr( new ServerVersionCmd()));
+ cmd_vec.push_back( Cmd_ptr( new BeginCmd("suiteName"))); // must be first
+ cmd_vec.push_back( Cmd_ptr( new BeginCmd("EmptySuite"))); // must be first
+ cmd_vec.push_back( Cmd_ptr( new ReplaceNodeCmd("suiteName",false,client_defs, true)));
+ cmd_vec.push_back( Cmd_ptr( new LoadDefsCmd(mock_server->defs(),true/*force*/)));
+ cmd_vec.push_back( Cmd_ptr( new LogMessageCmd("LogMessageCmd")) );
+ cmd_vec.push_back( Cmd_ptr( new LogCmd(LogCmd::CLEAR))); // server replies back OK/Error Cmd
+ cmd_vec.push_back( Cmd_ptr( new LogCmd(LogCmd::GET))); // server replies back OK/Error | SStringCmd
+ cmd_vec.push_back( Cmd_ptr( new LogCmd(LogCmd::PATH))); // server replies back Error |SStringCmd
+ cmd_vec.push_back( Cmd_ptr( new CtsCmd(CtsCmd::RESTORE_DEFS_FROM_CHECKPT)));
+ cmd_vec.push_back( Cmd_ptr( new CheckPtCmd()));
+ cmd_vec.push_back( Cmd_ptr( new CtsCmd(CtsCmd::PING)));
+ cmd_vec.push_back( Cmd_ptr( new CtsCmd(CtsCmd::DEBUG_SERVER_ON)));
+ cmd_vec.push_back( Cmd_ptr( new CtsCmd(CtsCmd::DEBUG_SERVER_OFF)));
+ cmd_vec.push_back( Cmd_ptr( new CtsCmd(CtsCmd::RESTART_SERVER)));
+ cmd_vec.push_back( Cmd_ptr( new CtsCmd(CtsCmd::SHUTDOWN_SERVER)));
+ cmd_vec.push_back( Cmd_ptr( new CtsCmd(CtsCmd::HALT_SERVER)));
+ cmd_vec.push_back( Cmd_ptr( new CtsCmd(CtsCmd::TERMINATE_SERVER)));
+ cmd_vec.push_back( Cmd_ptr( new CtsCmd(CtsCmd::RELOAD_WHITE_LIST_FILE)));
+ cmd_vec.push_back( Cmd_ptr( new CtsCmd(CtsCmd::FORCE_DEP_EVAL)));
+ cmd_vec.push_back( Cmd_ptr( new CtsCmd(CtsCmd::STATS)));
+ cmd_vec.push_back( Cmd_ptr( new CtsCmd(CtsCmd::STATS_RESET)));
+ cmd_vec.push_back( Cmd_ptr( new CtsCmd(CtsCmd::SUITES)));
+ cmd_vec.push_back( Cmd_ptr( new CSyncCmd(CSyncCmd::NEWS,0,0,0)));
+ cmd_vec.push_back( Cmd_ptr( new CSyncCmd(CSyncCmd::SYNC,0,0,0)));
+ cmd_vec.push_back( Cmd_ptr( new CSyncCmd(0))); // SYNC_FULL
+ cmd_vec.push_back( Cmd_ptr( new RequeueNodeCmd("/suiteName",RequeueNodeCmd::NO_OPTION)));
+ cmd_vec.push_back( Cmd_ptr( new OrderNodeCmd("/suiteName",NOrder::ALPHA)));
+ cmd_vec.push_back( Cmd_ptr( new RunNodeCmd("/suiteName", true/* force for test */, true /* for test */)));
+ cmd_vec.push_back( Cmd_ptr( new PathsCmd(PathsCmd::SUSPEND,"EmptySuite")));
+ cmd_vec.push_back( Cmd_ptr( new PathsCmd(PathsCmd::RESUME,"EmptySuite")));
+ cmd_vec.push_back( Cmd_ptr( new PathsCmd(PathsCmd::KILL,"EmptySuite")));
+ cmd_vec.push_back( Cmd_ptr( new PathsCmd(PathsCmd::STATUS,"EmptySuite")));
+ cmd_vec.push_back( Cmd_ptr( new PathsCmd(PathsCmd::CHECK,"/suiteName")));
+ cmd_vec.push_back( Cmd_ptr( new PathsCmd(PathsCmd::CHECK,""))); // check the full defs
+ cmd_vec.push_back( Cmd_ptr( new PathsCmd(PathsCmd::EDIT_HISTORY,"/suiteName"))); // check the full defs
+ cmd_vec.push_back( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::WHY,"/suiteName")));
+ cmd_vec.push_back( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::GET,"/suiteName")));
+ cmd_vec.push_back( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::GET_STATE,"/suiteName")));
+ cmd_vec.push_back( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::MIGRATE,"/suiteName")));
+ cmd_vec.push_back( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::CHECK_JOB_GEN_ONLY,"EmptySuite"))); // will *reset* begin
+ cmd_vec.push_back( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::GET,""))); // return the full defs
+ cmd_vec.push_back( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::GET_STATE,"")));
+ cmd_vec.push_back( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::MIGRATE,"")));
+ cmd_vec.push_back( Cmd_ptr( new ZombieCmd(ecf::User::FOB,"suiteName/familyName/taskName",Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),Submittable::DUMMY_JOBS_PASSWORD())));
+ cmd_vec.push_back( Cmd_ptr( new ZombieCmd(ecf::User::FAIL,"suiteName/familyName/taskName",Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),Submittable::DUMMY_JOBS_PASSWORD())));
+ cmd_vec.push_back( Cmd_ptr( new ZombieCmd(ecf::User::ADOPT,"suiteName/familyName/taskName",Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),Submittable::DUMMY_JOBS_PASSWORD())));
+ cmd_vec.push_back( Cmd_ptr( new ZombieCmd(ecf::User::REMOVE,"suiteName/familyName/taskName",Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),Submittable::DUMMY_JOBS_PASSWORD())));
+ cmd_vec.push_back( Cmd_ptr( new ZombieCmd(ecf::User::KILL,"suiteName/familyName/taskName",Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),Submittable::DUMMY_JOBS_PASSWORD())));
+ cmd_vec.push_back( Cmd_ptr( new ClientHandleCmd(suite_names,true))); // register
+ cmd_vec.push_back( Cmd_ptr( new ClientHandleCmd(1,suite_names,ClientHandleCmd::ADD))); // add
+ cmd_vec.push_back( Cmd_ptr( new ClientHandleCmd(1,suite_names,ClientHandleCmd::REMOVE))); // remove
+ cmd_vec.push_back( Cmd_ptr( new ClientHandleCmd(1, true))); // auto_add new suites
+ cmd_vec.push_back( Cmd_ptr( new ClientHandleCmd(1))); // de-register/drop
+ cmd_vec.push_back( Cmd_ptr( new InitCmd("suiteName/familyName/taskName",Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1)));
+ cmd_vec.push_back( Cmd_ptr( new EventCmd("suiteName/familyName/taskName",Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1,"eventName")));
+ cmd_vec.push_back( Cmd_ptr( new MeterCmd("suiteName/familyName/heir_familyName/taskName",Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1,"myMeter",100)));
+ cmd_vec.push_back( Cmd_ptr( new CompleteCmd("suiteName/familyName/taskName",Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1)));
+ cmd_vec.push_back( Cmd_ptr( new AbortCmd("suiteName/familyName/taskName",Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1)));
+ cmd_vec.push_back( Cmd_ptr( new CtsWaitCmd("suiteName/familyName/taskName",Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1,"1 eq 1")));
+ cmd_vec.push_back( Cmd_ptr( new LabelCmd("suiteName/familyName/taskName",Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1,"labelName","label value")));
+ cmd_vec.push_back( Cmd_ptr( new ForceCmd("/suiteName","complete",true,true)));
+ cmd_vec.push_back( Cmd_ptr( new FreeDepCmd("/suiteName")));
+ cmd_vec.push_back( Cmd_ptr( new CFileCmd("/suiteName",CFileCmd::ECF, 10)));
+ cmd_vec.push_back( Cmd_ptr( new CFileCmd("/suiteName",CFileCmd::JOB,100)));
+ cmd_vec.push_back( Cmd_ptr( new CFileCmd("/suiteName",CFileCmd::JOBOUT,100)));
+ cmd_vec.push_back( Cmd_ptr( new CFileCmd("/suiteName",CFileCmd::MANUAL,100)));
+ cmd_vec.push_back( Cmd_ptr( new EditScriptCmd()));
+ cmd_vec.push_back( Cmd_ptr( new AlterCmd("/suiteName/t1",AlterCmd::ADD_DATE,"12.*.*")));
+ cmd_vec.push_back( Cmd_ptr( new AlterCmd("/suiteName/t1",AlterCmd::ADD_DAY,"sunday")));
+ cmd_vec.push_back( Cmd_ptr( new AlterCmd("/suiteName/t1",AlterCmd::ADD_TIME,"+12:00")));
+ cmd_vec.push_back( Cmd_ptr( new AlterCmd("/suiteName/t1",AlterCmd::ADD_TIME,"+10:00 20:00 00:30")));
+ cmd_vec.push_back( Cmd_ptr( new AlterCmd("/suiteName/t1",AlterCmd::ADD_TODAY,"10:00 20:00 00:30")));
+ cmd_vec.push_back( Cmd_ptr( new PlugCmd()));
+
+ boost::shared_ptr<GroupCTSCmd> theGroupCmd = boost::make_shared<GroupCTSCmd>();
+ theGroupCmd->addChild( Cmd_ptr( new BeginCmd("suiteName")) );
+ theGroupCmd->addChild( Cmd_ptr( new BeginCmd("EmptySuite")) );
+ theGroupCmd->addChild( Cmd_ptr( new ServerVersionCmd()) );
+ theGroupCmd->addChild( Cmd_ptr( new CtsCmd(CtsCmd::PING)) );
+ theGroupCmd->addChild( Cmd_ptr( new CtsCmd(CtsCmd::RESTART_SERVER)) );
+ theGroupCmd->addChild( Cmd_ptr( new CtsCmd(CtsCmd::SHUTDOWN_SERVER)) );
+ theGroupCmd->addChild( Cmd_ptr( new CtsCmd(CtsCmd::HALT_SERVER)) );
+ theGroupCmd->addChild( Cmd_ptr( new CtsCmd(CtsCmd::TERMINATE_SERVER)) );
+ theGroupCmd->addChild( Cmd_ptr( new CtsCmd(CtsCmd::RELOAD_WHITE_LIST_FILE)) );
+ theGroupCmd->addChild( Cmd_ptr( new CtsCmd(CtsCmd::SERVER_LOAD)) );
+ theGroupCmd->addChild( Cmd_ptr( new PathsCmd(PathsCmd::SUSPEND,"EmptySuite")) );
+ theGroupCmd->addChild( Cmd_ptr( new PathsCmd(PathsCmd::RESUME,"EmptySuite")) );
+ theGroupCmd->addChild( Cmd_ptr( new PathsCmd(PathsCmd::KILL,"EmptySuite")) );
+ theGroupCmd->addChild( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::GET,"EmptySuite")) );
+ theGroupCmd->addChild( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::GET_STATE,"EmptySuite")) );
+ theGroupCmd->addChild( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::MIGRATE,"EmptySuite")) );
+ theGroupCmd->addChild( Cmd_ptr( new ShowCmd()));
+ theGroupCmd->addChild( Cmd_ptr( new ZombieCmd(ecf::User::FOB,"suiteName/familyName/taskName",Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),Submittable::DUMMY_JOBS_PASSWORD())));
+ theGroupCmd->addChild( Cmd_ptr( new ZombieCmd(ecf::User::FAIL,"suiteName/familyName/taskName",Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),Submittable::DUMMY_JOBS_PASSWORD())));
+ theGroupCmd->addChild( Cmd_ptr( new ZombieCmd(ecf::User::ADOPT,"suiteName/familyName/taskName",Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),Submittable::DUMMY_JOBS_PASSWORD())));
+ theGroupCmd->addChild( Cmd_ptr( new ZombieCmd(ecf::User::REMOVE,"suiteName/familyName/taskName",Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),Submittable::DUMMY_JOBS_PASSWORD())));
+ theGroupCmd->addChild( Cmd_ptr( new RequeueNodeCmd("/suiteName",RequeueNodeCmd::NO_OPTION)) );
+ theGroupCmd->addChild( Cmd_ptr( new OrderNodeCmd("/suiteName",NOrder::ALPHA)) );
+ theGroupCmd->addChild( Cmd_ptr( new RunNodeCmd("/suiteName",true/*force for test*/, true /* for test */)) );
+ theGroupCmd->addChild( Cmd_ptr( new InitCmd("suiteName/familyName/taskName",Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1)) );
+ theGroupCmd->addChild( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::CHECK_JOB_GEN_ONLY,"EmptySuite")) ); // will *reset* begin
+ theGroupCmd->addChild( Cmd_ptr( new EventCmd("suiteName/familyName/taskName",Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1,"eventName")) );
+ theGroupCmd->addChild( Cmd_ptr( new MeterCmd("suiteName/familyName/heir_familyName/taskName",Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1,"myMeter",100)) );
+ theGroupCmd->addChild( Cmd_ptr( new CompleteCmd("suiteName/familyName/taskName",Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1)) );
+ theGroupCmd->addChild( Cmd_ptr( new AbortCmd("suiteName/familyName/taskName",Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1)) );
+ theGroupCmd->addChild( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::GET)) );
+ theGroupCmd->addChild( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::GET_STATE)) );
+ theGroupCmd->addChild( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::MIGRATE)) );
+ theGroupCmd->addChild( Cmd_ptr( new CtsCmd(CtsCmd::FORCE_DEP_EVAL)) ); // will force deletion of any Node which has autocomplete
+ theGroupCmd->addChild( Cmd_ptr( new LoadDefsCmd(mock_server->defs(), true/*force*/)) );
+ theGroupCmd->addChild( Cmd_ptr( new LogCmd(LogCmd::GET)) );
+ theGroupCmd->addChild( Cmd_ptr( new LogCmd(LogCmd::CLEAR)) );
+ theGroupCmd->addChild( Cmd_ptr( new LogMessageCmd("LogMessageCmd")) );
+ theGroupCmd->addChild( Cmd_ptr( new ForceCmd("/suiteName","complete",true,true)) );
+ theGroupCmd->addChild( Cmd_ptr( new FreeDepCmd("/suiteName",false,true)) );
+
+ BOOST_CHECK_MESSAGE(theGroupCmd->isWrite(),"Expected isWrite() to return true");
+ BOOST_CHECK_MESSAGE(theGroupCmd->get_cmd(),"Expected get_cmd() to return true");
+ BOOST_CHECK_MESSAGE(theGroupCmd->task_cmd(),"Expected task_cmd() to return true");
+ BOOST_CHECK_MESSAGE(theGroupCmd->terminate_cmd(),"Expected terminate_cmd() to return true");
+ BOOST_CHECK_MESSAGE(theGroupCmd->group_cmd(),"Expected group_cmd() to return true");
+ cmd_vec.push_back( theGroupCmd );
+
+
+ // Server --> Client commands
+ stc_cmd_vec.push_back( STC_Cmd_ptr( new ErrorCmd("The error")));
+ stc_cmd_vec.push_back( STC_Cmd_ptr( new StcCmd(StcCmd::OK)));
+ stc_cmd_vec.push_back( STC_Cmd_ptr( new StcCmd(StcCmd::BLOCK_CLIENT_SERVER_HALTED)));
+ stc_cmd_vec.push_back( STC_Cmd_ptr( new StcCmd(StcCmd::BLOCK_CLIENT_ON_HOME_SERVER)));
+ stc_cmd_vec.push_back( STC_Cmd_ptr( new SStringCmd("Dummy contents")));
+ stc_cmd_vec.push_back( STC_Cmd_ptr( new SServerLoadCmd("/path/to/log_file")));
+ stc_cmd_vec.push_back( STC_Cmd_ptr( new SSyncCmd(0,0,0,mock_server )));
+ stc_cmd_vec.push_back( STC_Cmd_ptr( new SNewsCmd(0,0,0,mock_server)));
+ stc_cmd_vec.push_back( STC_Cmd_ptr( new DefsCmd(mock_server)));
+ stc_cmd_vec.push_back( STC_Cmd_ptr( new SNodeCmd(mock_server,node_ptr()) ));
+
+ boost::shared_ptr<GroupSTCCmd> theSTCGroupCmd = boost::make_shared<GroupSTCCmd>() ;
+ theSTCGroupCmd->addChild( STC_Cmd_ptr( new ErrorCmd()) );
+ theSTCGroupCmd->addChild( STC_Cmd_ptr( new StcCmd(StcCmd::OK)) );
+ theSTCGroupCmd->addChild( STC_Cmd_ptr( new StcCmd(StcCmd::BLOCK_CLIENT_SERVER_HALTED)) );
+ theSTCGroupCmd->addChild( STC_Cmd_ptr( new StcCmd(StcCmd::BLOCK_CLIENT_ON_HOME_SERVER)) );
+ theSTCGroupCmd->addChild( STC_Cmd_ptr( new SStringCmd()) );
+ theSTCGroupCmd->addChild( STC_Cmd_ptr( new SServerLoadCmd()) );
+ theSTCGroupCmd->addChild( STC_Cmd_ptr( new DefsCmd(mock_server)));
+ theSTCGroupCmd->addChild( STC_Cmd_ptr( new SNodeCmd(mock_server,node_ptr())));
+ stc_cmd_vec.push_back( theSTCGroupCmd );
+}
+
+static void test_persistence(const Defs& theFixtureDefs )
+{
+ Defs* fixtureDefs = const_cast<Defs*>(&theFixtureDefs);
+ MockServer mockServer(fixtureDefs); // creates shared ptr with a NULL deleter
+
+ std::vector<Cmd_ptr> cmd_vec;
+ std::vector<STC_Cmd_ptr> stc_cmd_vec;
+ populateCmdVec(cmd_vec, stc_cmd_vec, &mockServer);
+
+ int getRequest = 0;
+ int terminateRequest = 0;
+ int groupRequest = 0;
+ BOOST_FOREACH(const Cmd_ptr& theCmd, cmd_vec) {
+
+ // std::cout << "TheCmd "; theCmd->print(std::cout); std::cout << "\n";
+ if (theCmd->connect_to_different_servers()) {
+ BOOST_CHECK_MESSAGE(theCmd->task_cmd(),"Currently only tasks commands, are allowed to connect to different servers");
+ }
+
+ const ClientToServerRequest cmd_request(theCmd); // MUST be const to avoid AIX compiler warning
+ {
+ if (theCmd.get()->handleRequestIsTestable()) {
+ // test handleRequest while were at it.
+ // Avoid TERMINATE_SERVER cmd as this will prematurely cause an exit, wont appear as an error
+ // cerr << "cmd_request = " << cmd_request << "\n";
+ try {
+ STC_Cmd_ptr ok_or_error_cmd = cmd_request.handleRequest(&mockServer);
+ if (ok_or_error_cmd) {
+ // Commands like ErrorCmd, OkCmd don't return a cmd_ptr from handleRequest
+ // those that do, check OkCmd returned, else if ErrorCmd show the error
+ BOOST_CHECK_MESSAGE(ok_or_error_cmd->ok(),"Request '" << cmd_request << "' returned " << ok_or_error_cmd->error());
+ }
+ }
+ catch (std::exception& e ) {
+ BOOST_CHECK_MESSAGE(false,"Unexpected exception : " << e.what() << " : " << cmd_request ) ;
+ }
+ }
+ }
+
+ BOOST_REQUIRE_NO_THROW(ecf::save("request.txt",cmd_request));
+
+ ClientToServerRequest restoredRequest;
+ BOOST_REQUIRE_NO_THROW(ecf::restore("request.txt", restoredRequest));
+ BOOST_REQUIRE_MESSAGE(restoredRequest == cmd_request, "restoredRequest " << restoredRequest << " cmd_request " << cmd_request);
+
+ if (restoredRequest.getRequest()) getRequest++;
+ if (restoredRequest.terminateRequest()) terminateRequest++;
+ if (restoredRequest.groupRequest()) groupRequest++;
+ fs::remove("request.txt");
+ }
+
+ BOOST_CHECK_MESSAGE(getRequest ==3," expected 3 get Request but found " << getRequest );
+ BOOST_CHECK_MESSAGE(terminateRequest ==2," expected 2 terminate Request but found " << terminateRequest );
+ BOOST_CHECK_MESSAGE(groupRequest ==1," expected 1 group Request but found " << groupRequest );
+
+
+ BOOST_FOREACH(const STC_Cmd_ptr& theCmd, stc_cmd_vec) {
+// std::cout << "TheCmd "; theCmd->print(std::cout); std::cout << "\n";
+
+ const ServerToClientResponse cmd_request(theCmd); // MUST be const to avoid AIX compiler warning
+ BOOST_REQUIRE_NO_THROW(ecf::save("request.txt",cmd_request));
+
+ ServerToClientResponse restoredRequest;
+ BOOST_REQUIRE_NO_THROW(ecf::restore("request.txt", restoredRequest));
+ BOOST_REQUIRE_MESSAGE(restoredRequest == cmd_request, "restoredRequest " << restoredRequest << " cmd_request " << cmd_request);
+ fs::remove("request.txt");
+ }
+}
+
+#if defined(BINARY_ARCHIVE)
+BOOST_AUTO_TEST_CASE( test_all_request_persistence_binary )
+{
+ cout << "Base:: ...test_all_request_persistence_binary\n";
+ test_persistence( fixtureDefsFile());
+}
+#elif defined(PORTABLE_BINARY_ARCHIVE)
+BOOST_AUTO_TEST_CASE( test_all_request_persistence_portable_binary )
+{
+ cout << "Base:: ...test_all_request_persistence_portable_binary\n";
+ test_persistence( fixtureDefsFile() );
+}
+#elif defined(EOS_PORTABLE_BINARY_ARCHIVE)
+BOOST_AUTO_TEST_CASE( test_all_request_persistence_eos_portable_binary )
+{
+ cout << "Base:: ...test_all_request_persistence_eos_portable_binary\n";
+ test_persistence( fixtureDefsFile() );
+}
+#else
+BOOST_AUTO_TEST_CASE( test_all_request_persistence_text )
+{
+ cout << "Base:: ...test_all_request_persistence_text\n";
+ test_persistence( fixtureDefsFile());
+}
+#endif
+
+BOOST_AUTO_TEST_CASE( test_request_authenticate )
+{
+ cout << "Base:: ...test_request_authenticate\n";
+
+ // the path "suiteName0/familyName0/taskName0" must exist in the defsfile_ fixture
+ Cmd_ptr cmd_ptr(new InitCmd("suiteName/familyName/taskName",Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1));
+
+ // The invokeRequest will return check if the path and password exist in the Node tree
+ TestHelper::invokeRequest(&defsfile_, cmd_ptr);
+
+ /// Destroy System singleton to avoid valgrind from complaining
+ System::destroy();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/Base/test/TestRequeueNodeCmd.cpp b/Base/test/TestRequeueNodeCmd.cpp
new file mode 100644
index 0000000..e8540cc
--- /dev/null
+++ b/Base/test/TestRequeueNodeCmd.cpp
@@ -0,0 +1,248 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #22 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <boost/test/unit_test.hpp>
+
+#include "ClientToServerCmd.hpp"
+#include "TestHelper.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( BaseTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_requeue_with_suspend )
+{
+ cout << "Base:: ...test_requeue_with_suspend\n";
+
+ defs_ptr the_defs = Defs::create();
+ suite_ptr s1 = the_defs->add_suite( "s1" ) ;
+ family_ptr f1 = s1->add_family( "f1" ) ;
+ task_ptr t1 = f1->add_task("t1");
+ task_ptr t2 = f1->add_task("t2");
+ task_ptr t3 = f1->add_task("t3");
+ t3->addDefStatus(DState::SUSPENDED);
+
+ the_defs->beginAll();
+
+ // After begin/requeue we must honour defs status
+ BOOST_CHECK_MESSAGE(t3->isSuspended(),"Expected node to be suspended");
+
+ // Suspend all nodes
+ TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new PathsCmd(PathsCmd::SUSPEND,s1->absNodePath())));
+ TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new PathsCmd(PathsCmd::SUSPEND,f1->absNodePath())));
+ TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new PathsCmd(PathsCmd::SUSPEND,t1->absNodePath())));
+ TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new PathsCmd(PathsCmd::SUSPEND,t2->absNodePath())));
+ BOOST_CHECK_MESSAGE(s1->isSuspended(),"Expected node to be suspended");
+ BOOST_CHECK_MESSAGE(f1->isSuspended(),"Expected node to be suspended");
+ BOOST_CHECK_MESSAGE(t1->isSuspended(),"Expected node to be suspended");
+ BOOST_CHECK_MESSAGE(t2->isSuspended(),"Expected node to be suspended");
+
+ // Re-queue of the nodes, that are suspended, they should *stay* suspended
+ TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new RequeueNodeCmd(t1->absNodePath())));
+ BOOST_CHECK_MESSAGE(t1->isSuspended(),"Expected node to stay suspended");
+
+ // Now re-queue the top level suite, this is suspended.
+ // This should stay suspended *BUT* child nodes which are suspend should be cleared
+ TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new RequeueNodeCmd(s1->absNodePath())));
+ BOOST_CHECK_MESSAGE(s1->isSuspended(),"Suite should stay suspend");
+ BOOST_CHECK_MESSAGE(!f1->isSuspended(),"Expected child nodes to be un-suspended");
+ BOOST_CHECK_MESSAGE(!t1->isSuspended(),"Expected child nodes to be un-suspended");
+ BOOST_CHECK_MESSAGE(!t2->isSuspended(),"Expected child nodes to be un-suspended");
+ BOOST_CHECK_MESSAGE(t3->isSuspended(), "Requeue must honour def status");
+}
+
+BOOST_AUTO_TEST_CASE( test_requeue_family_clears_children_SUP_909 )
+{
+ cout << "Base:: ...test_requeue_family_clears_children_SUP_909\n";
+
+ // suite s1
+ // family f1
+ // task t1
+ // time 23:30
+ // endFamily
+ // endsuite
+ // make sure time is set *before* 23:30, so that time dependency holds the task
+
+ defs_ptr the_defs = Defs::create();
+ suite_ptr suite = the_defs->add_suite( "s1" ) ;
+ ClockAttr clockAttr(15,12,2010,false);
+ clockAttr.set_gain(9/*hour*/,30/*minutes*/); // start at 09:30
+ suite->addClock( clockAttr );
+
+ family_ptr f1 = suite->add_family( "f1" ) ;
+ task_ptr t1 = f1->add_task("t1");
+ t1->addTime( TimeAttr(23,30));
+
+ const TimeSeries& theTime = t1->timeVec().back().time_series();
+
+ the_defs->beginAll();
+
+ BOOST_CHECK_MESSAGE(theTime.is_valid(), "Expected time to be holding");
+ TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",true /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(t1,NState::COMPLETE);
+ BOOST_CHECK_MESSAGE( !theTime.is_valid(), "Expected time to have expired");
+ BOOST_CHECK_MESSAGE( t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be set");
+
+ // Now reque the family, this should clear the time, so that it now holding again
+ TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new RequeueNodeCmd(f1->absNodePath())));
+ TestHelper::test_state(f1,NState::QUEUED);
+ TestHelper::test_state(t1,NState::QUEUED);
+ BOOST_CHECK_MESSAGE( theTime.is_valid(), "Expected time to be reset");
+ BOOST_CHECK_MESSAGE( !t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear");
+}
+
+BOOST_AUTO_TEST_CASE( test_repeat_based_requeue_clears_children )
+{
+ cout << "Base:: ...test_repeat_based_requeue_clears_children\n";
+
+ // suite s1
+ // repeat day 1
+ // family f1
+ // task t1
+ // time 23:30
+ // endfamily
+ // endsuite
+ // make sure time is set *before* 23:30, so that time dependency holds the task
+
+ defs_ptr the_defs = Defs::create();
+ suite_ptr suite = the_defs->add_suite( "s1" ) ;
+ ClockAttr clockAttr(15,12,2010,false);
+ clockAttr.set_gain(9/*hour*/,30/*minutes*/); // start at 09:30
+ suite->addClock( clockAttr );
+
+ suite->addRepeat( RepeatDay(1) );
+
+ family_ptr f1 = suite->add_family( "f1" ) ;
+ task_ptr t1 = f1->add_task("t1");
+ t1->addTime( TimeAttr(23,30));
+
+ const TimeSeries& theTime = t1->timeVec().back().time_series();
+
+ the_defs->beginAll();
+
+ BOOST_CHECK_MESSAGE(theTime.is_valid(), "Expected time to be holding");
+
+ // Forcing task t1 to complete, should cause the top, level repeat to REQEUE
+ TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",true /*recursive */, false /* set Repeat to last value */)));
+
+ TestHelper::test_state(t1,NState::QUEUED);
+ BOOST_CHECK_MESSAGE( theTime.is_valid(), "Expected time to be holding");
+ BOOST_CHECK_MESSAGE( !t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear");
+}
+
+BOOST_AUTO_TEST_CASE( test_ecflow_359 )
+{
+ cout << "Base:: ...test_ECFLOW-359\n";
+
+ // suite s1
+ // family f1
+ // repeat date YMD 20090916 20090928
+ // family parent
+ // task dummy
+ // time 16:00
+ // endfamily
+ // task complete
+ // defstatus complete
+
+ // set defstatus complete /s1/f1/parent/dummy
+ // requeue s1/f1/parent
+ // f1 gets set complete through status inheritance
+ // YMD is not increment at the moment...
+
+ defs_ptr the_defs = Defs::create();
+ suite_ptr suite = the_defs->add_suite( "s1" ) ;
+ family_ptr f1 = suite->add_family("f1");
+ f1->addRepeat( RepeatDate("YMD",20090916,20090928,1) );
+
+ family_ptr parent = f1->add_family( "parent" ) ;
+ task_ptr dummy = parent->add_task("dummy");
+ dummy->addTime( TimeAttr(16,0));
+
+ task_ptr complete = f1->add_task("complete");
+ complete->addDefStatus( DState::COMPLETE);
+
+// PrintStyle::setStyle(PrintStyle::STATE);
+// cout << the_defs;
+
+ the_defs->beginAll();
+
+// cout << "----->set defstatus complete /s1/f1/parent/dummy\n";
+ BOOST_CHECK_MESSAGE( dummy->defStatus() == DState::QUEUED, "Expected dstate to be queued but found " << DState::toString( dummy->dstate()));
+ TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new AlterCmd(dummy->absNodePath(),AlterCmd::DEFSTATUS,"complete")));
+ BOOST_CHECK_MESSAGE( dummy->defStatus() == DState::COMPLETE, "Expected dstate to be complete but found " << DState::toString( dummy->dstate()));
+// cout << the_defs;
+
+// cout << "----->requeue parent since all children are now complete, we expect the repeat on the f1 to increment\n";
+ BOOST_CHECK_MESSAGE( f1->repeat().value() == 20090916, "Expected repeat value of 20090916 but found " << f1->repeat().value());
+ TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new RequeueNodeCmd(parent->absNodePath())));
+ BOOST_CHECK_MESSAGE( f1->repeat().value() == 20090917, "Expected repeat value of 20090917 but found " << f1->repeat().value());
+// cout << the_defs;
+
+// cout << "----->requeue again\n";
+ TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new RequeueNodeCmd(parent->absNodePath())));
+ BOOST_CHECK_MESSAGE( f1->repeat().value() == 20090918, "Expected repeat value of 20090918 but found " << f1->repeat().value());
+// cout << the_defs;
+}
+
+
+BOOST_AUTO_TEST_CASE( test_ecflow_428 )
+{
+ cout << "Base:: ...test_ECFLOW-428\n";
+ // suite s1
+ // family f1
+ // family f2
+ // task t1
+ // task t2
+
+ // Set t1 to aborted, then call reque aborted on suite s1
+ // This should result ALL nodes to be in a queued state
+
+ defs_ptr the_defs = Defs::create();
+ suite_ptr suite = the_defs->add_suite( "s1" ) ;
+ suite->addDefStatus(DState::SUSPENDED);
+ family_ptr f1 = suite->add_family("f1");
+ family_ptr f2 = f1->add_family("f1");
+ task_ptr t1 = f2->add_task("t1");
+ task_ptr t2 = f2->add_task("t2");
+
+// PrintStyle::setStyle(PrintStyle::STATE);
+// cout << the_defs;
+
+ the_defs->beginAll();
+
+ // set t1 to aborted state
+ TestHelper::invokeRequest(the_defs.get(),
+ Cmd_ptr( new ForceCmd(t1->absNodePath(), "aborted", false /*recursive */, false /* set Repeat to last value */)));
+ TestHelper::test_state(t1,NState::ABORTED);
+ TestHelper::test_state(t2,NState::QUEUED);
+ TestHelper::test_state(f1,NState::ABORTED);
+ TestHelper::test_state(f2,NState::ABORTED);
+ TestHelper::test_state(suite,NState::ABORTED);
+
+ // Now reque aborted tasks for suite
+ TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new RequeueNodeCmd(suite->absNodePath(), RequeueNodeCmd::ABORT)));
+
+ // *Suite* should now be queued
+ TestHelper::test_state(suite,NState::QUEUED);
+ TestHelper::test_state(f1,NState::QUEUED);
+ TestHelper::test_state(f2,NState::QUEUED);
+ TestHelper::test_state(t1,NState::QUEUED);
+ TestHelper::test_state(t2,NState::QUEUED);
+}
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Base/test/TestResolveDependencies.cpp b/Base/test/TestResolveDependencies.cpp
new file mode 100644
index 0000000..f42fb9e
--- /dev/null
+++ b/Base/test/TestResolveDependencies.cpp
@@ -0,0 +1,277 @@
+#define BOOST_TEST_MODULE TestBase
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #37 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <iostream>
+#include <fstream>
+
+#include <boost/test/unit_test.hpp>
+#include <boost/foreach.hpp>
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "ExprAst.hpp"
+#include "TestHelper.hpp"
+#include "JobsParam.hpp"
+#include "Jobs.hpp"
+#include "System.hpp"
+
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( BaseTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_resolve_dependencies )
+{
+ cout << "Base:: ...test_resolve_dependencies\n";
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Create the defs file
+ // suite suite
+ // family f
+ // task t
+ // meter step 0 240 120
+ // task tt
+ // complete t:step ge 120
+ // trigger t == complete
+ // endfamily
+ // endsuite
+ Defs defs;
+ std::string metername = "step";
+ std::string suitename = "suite";
+ std::string familyname = "f";
+ {
+ suite_ptr suite = defs.add_suite( suitename );
+ family_ptr fam = suite->add_family( familyname );
+
+ task_ptr task = fam->add_task( "t" );
+ task->addMeter( Meter(metername,0,240,120) );
+
+ task_ptr task_tt = fam->add_task( "tt" );
+ task_tt->add_complete( "t:step ge 120");
+ task_tt->add_trigger( "t == complete" );
+
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE( defs.checkInvariants(errorMsg), errorMsg);
+ }
+
+
+ // Ensure initial state is unknown
+ string suite_f_t = "/suite/f/t";
+ string suite_f_tt = "/suite/f/tt";
+ node_ptr node_t = defs.findAbsNode(suite_f_t);
+ node_ptr node_tt = defs.findAbsNode(suite_f_tt);
+ suite_ptr suite = defs.findSuite(suitename);
+ family_ptr fam = suite->findFamily(familyname);
+ BOOST_CHECK_MESSAGE( suite->state() == NState::UNKNOWN, "expected state NState::UNKNOWN, but found to be " << NState::toString(suite->state()));
+ BOOST_CHECK_MESSAGE( node_t->state() == NState::UNKNOWN, "expected state NState::UNKNOWN, but found to be " << NState::toString(node_t->state()));
+ BOOST_CHECK_MESSAGE( node_tt->state() == NState::UNKNOWN, "expected state NState::UNKNOWN, but found to be " << NState::toString(node_tt->state()));
+ BOOST_CHECK_MESSAGE( fam->state() == NState::UNKNOWN, "expected state NState::UNKNOWN, but found to be " << NState::toString(fam->state()));
+
+
+ // ***********************************************************************
+ // Create a request to begin suite
+ // make sure chosen suite can begin to resolve dependencies.
+ // beginning the suite will :
+ // 1/ set all children to the QUEUED state
+ // 2/ Begin job submission, and hence changes state to ACTIVE for submitted jobs
+ {
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new BeginCmd(suitename)));
+ BOOST_CHECK_MESSAGE( suite->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(suite->state()));
+ BOOST_CHECK_MESSAGE( fam->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(fam->state()));
+ BOOST_CHECK_MESSAGE( node_t->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(node_t->state()));
+ BOOST_CHECK_MESSAGE( node_tt->state() == NState::QUEUED, "expected state NState::QUEUED, but found to be " << NState::toString(node_tt->state()));
+ }
+
+ //*******************************************************************************
+ // Resolve dependencies.
+ // task t
+ // meter step 0 240 120 EXPECTED to be sumbitted
+ //
+ // task tt
+ // complete t:step ge 120 Expected to HOLD, since we ain't done nothing yet
+ // trigger t == complete
+ {
+ JobsParam jobsParam; // create jobs = false, spawn jobs = false
+ Jobs jobs(&defs);
+ BOOST_CHECK_MESSAGE( jobs.generate(jobsParam),jobsParam.getErrorMsg());
+ BOOST_CHECK_MESSAGE( jobsParam.submitted().size() == 0, "Expected 0 task to submit but found " << jobsParam.submitted().size());
+ BOOST_CHECK_MESSAGE( node_t->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(node_t->state()));
+ BOOST_CHECK_MESSAGE( node_tt->state() == NState::QUEUED,"expected state NState::QUEUED, but found to be " << NState::toString(node_tt->state()));
+ }
+
+ //**********************************************************************
+ // Create a request to set the Meter node t. This should force node tt
+ // to complete immediately
+ {
+ int meterValue = 120;
+ TestHelper::invokeRequest(&defs, Cmd_ptr( new MeterCmd(suite_f_t,Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1,metername,meterValue)));
+ TestHelper::invokeRequest(&defs, Cmd_ptr( new CtsCmd( CtsCmd::FORCE_DEP_EVAL)));
+ const Meter& theMeter = node_t->findMeter(metername);
+ BOOST_CHECK_MESSAGE( !theMeter.empty(), "Could not find the meter ");
+ BOOST_CHECK_MESSAGE( theMeter.value() == meterValue , "Meter value not set");
+
+ BOOST_CHECK_MESSAGE( node_t->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(node_t->state()));
+ BOOST_CHECK_MESSAGE( node_tt->state() == NState::COMPLETE,"expected state NState::COMPLETE, but found to be " << NState::toString(node_tt->state()));
+
+ }
+
+ {
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE( defs.checkInvariants(errorMsg), errorMsg);
+ }
+
+ /// Destroy System singleton to avoid valgrind from complaining
+ System::destroy();
+}
+
+BOOST_AUTO_TEST_CASE( test_trigger_after_delete )
+{
+ cout << "Base:: ...test_trigger_after_delete\n";
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Create the defs file
+ // suite suite1 # the limit we want delete
+ // family f
+ // task t0
+ // defstatus complete
+ // task t1
+ // event event
+ // task t2
+ // meter meter 0 100 100
+ // task t3
+ // edit user_var 1
+ // task t4
+ // repeat integer repeat_var 0 10 2
+ // endfamily
+ // endsuite
+ // suite suite2
+ // family f
+ // task t0
+ // trigger /suite1/f/t0 == complete
+ // task t1
+ // trigger /suite1/f/t1:event == set
+ // task t2
+ // trigger /suite1/f/t2:meter == 10
+ // task t3
+ // trigger /suite1/f/t2:user_var == 1
+ // task t4
+ // trigger /suite1/f/t2:repeat_var == 2
+ // endfamily
+ // endsuite
+ //
+ // In this test case all triggers in suite2 will evalate true, we then delete suite1 and
+ // all the triggers should evaluate false; This is used to test the shared ptr in
+ // the expression, which hold the reference nodes. When the reference nodes are deleted
+ // then the expression should not evaluate
+ Defs defs;
+ {
+ suite_ptr suite = Suite::create("suite1" );
+ family_ptr f = Family::create("f" );
+ task_ptr t0 = Task::create("t0" );
+ task_ptr t1 = Task::create("t1" );
+ task_ptr t2 = Task::create("t2" );
+ task_ptr t3 = Task::create("t3" );
+ task_ptr t4 = Task::create("t4" );
+ t0->addDefStatus(DState::COMPLETE);
+ t1->addEvent(Event(0,"event"));
+ t2->addMeter(Meter("meter",0,100,100));
+ t3->addVariable(Variable("user_var","1"));
+ t4->addRepeat(RepeatInteger("repeat_var",0,10,2));
+
+ f->addTask(t0);
+ f->addTask(t1);
+ f->addTask(t2);
+ f->addTask(t3);
+ f->addTask(t4);
+ suite->addFamily(f);
+ defs.addSuite( suite );
+ }
+ {
+ suite_ptr suite = Suite::create("suite2" );
+ family_ptr f = Family::create("f" );
+ task_ptr t0 = Task::create("t0" );
+ task_ptr t1 = Task::create("t1" );
+ task_ptr t2 = Task::create("t2" );
+ task_ptr t3 = Task::create("t3" );
+ task_ptr t4 = Task::create("t4" );
+ t0->add_trigger("/suite1/f/t0 == complete");
+ t1->add_trigger("/suite1/f/t1:event == set");
+ t2->add_trigger("/suite1/f/t2:meter == 10");
+ t3->add_trigger("/suite1/f/t3:user_var == 1");
+ t4->add_trigger("/suite1/f/t4:repeat_var == 2");
+
+ f->addTask(t0);
+ f->addTask(t1);
+ f->addTask(t2);
+ f->addTask(t3);
+ f->addTask(t4);
+ suite->addFamily(f);
+ defs.addSuite( suite );
+ }
+
+ // begin. This will reset all attributes
+ defs.beginAll();
+
+ // setup attrbutes in suite1 so that evalaution will succeed in suite 2
+ // *** this must be in its own scope otherwise the shared_ptr will keep the node alive
+ {
+ node_ptr t1 = defs.findAbsNode("/suite1/f/t1"); t1->changeEvent("event","set");
+ node_ptr t2 = defs.findAbsNode("/suite1/f/t2"); t2->changeMeter("meter",10);
+ node_ptr t4 = defs.findAbsNode("/suite1/f/t4"); t4->changeRepeat("2");
+ // cout << defs;
+ }
+
+ // evalate the triggers in suite2
+ {
+ node_ptr suite2 = defs.findAbsNode("/suite2");
+ std::vector<task_ptr> suite2_tasks;
+ suite2->get_all_tasks(suite2_tasks);
+ BOOST_REQUIRE_MESSAGE(suite2_tasks.size() == 5, "Expected 5 tasks on suite2 but found " << suite2_tasks.size());
+
+ for(size_t i = 0; i < suite2_tasks.size(); i++) {
+ BOOST_REQUIRE_MESSAGE( suite2_tasks[i]->triggerAst()->evaluate(), "Expected task " << suite2_tasks[i]->absNodePath() << " to evaluate");
+ }
+ }
+
+
+ // Ok Now delete suite1,
+ // *** It is extremely important that shared_ptr for '/suite1' is in its own
+ // *** scope, otherwise it will keep the 'suite' live, and NOT delete the limits
+ {
+ node_ptr suite1 = defs.findAbsNode("/suite1");
+ BOOST_REQUIRE_MESSAGE( suite1.get(), "Could not find the suite we want to delete?");
+ BOOST_REQUIRE_MESSAGE( defs.deleteChild(suite1.get()), "Deletion failed?");
+ BOOST_REQUIRE_MESSAGE( !defs.findAbsNode("/suite1").get(), "Deletion failed?");
+ }
+
+ // revaluate the triggers in suite2. This should fail, since we have delete suite1
+ {
+ node_ptr suite2 = defs.findAbsNode("/suite2");
+ std::vector<task_ptr> suite2_tasks;
+ suite2->get_all_tasks(suite2_tasks);
+ BOOST_REQUIRE_MESSAGE(suite2_tasks.size() == 5, "Expected 5 tasks on suite2 but found " << suite2_tasks.size());
+
+ for(size_t i = 0; i < suite2_tasks.size(); i++) {
+ BOOST_REQUIRE_MESSAGE( !suite2_tasks[i]->triggerAst()->evaluate(), "Expected task " << suite2_tasks[i]->absNodePath() << " to fail evaluation");
+ }
+ }
+
+ /// Destroy System singleton to avoid valgrind from complaining
+ System::destroy();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/Base/test/TestSSyncCmd.cpp b/Base/test/TestSSyncCmd.cpp
new file mode 100644
index 0000000..cd3ca12
--- /dev/null
+++ b/Base/test/TestSSyncCmd.cpp
@@ -0,0 +1,379 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #40 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <boost/test/unit_test.hpp>
+#include <boost/function.hpp>
+
+#include "ClientToServerCmd.hpp"
+#include "ServerToClientCmd.hpp"
+#include "MyDefsFixture.hpp"
+#include "MockServer.hpp"
+#include "TestHelper.hpp"
+#include "SSyncCmd.hpp"
+#include "SNewsCmd.hpp"
+#include "Ecf.hpp"
+#include "NodeFwd.hpp"
+#include "SuiteChanged.hpp"
+#include "CalendarUpdateParams.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+
+
+BOOST_AUTO_TEST_SUITE( BaseTestSuite )
+
+/// define a function which returns nothing, and takes a defs_ptr parameter
+typedef boost::function<void (defs_ptr)> defs_change_cmd;
+
+/// Re-use the same test scaffold to modify and then resync, by passing
+/// in a function that will modify the defs
+static void test_sync_scaffold(
+ defs_change_cmd the_defs_change_command,
+ const std::string& test_name,
+ bool full_sync = false,
+ bool start_with_begin = false)
+{
+ MyDefsFixture clientFixture;
+ MyDefsFixture serverFixture;
+ defs_ptr server_defs = serverFixture.create_defs();
+ if ( start_with_begin ) server_defs->beginAll();
+ server_defs->set_server().set_state( SState::HALTED); // if defs default state is RUNNING, whereas for server it is HALTED
+
+ ServerReply server_reply;
+ defs_ptr client_defs = clientFixture.create_defs();
+ if ( start_with_begin ) client_defs->beginAll();
+ client_defs->set_server().set_state( SState::HALTED); // if defs default state is RUNNING, whereas for server it is HALTED
+ server_reply.set_client_defs( client_defs );
+
+
+ Ecf::set_debug_equality(true); // only has affect in DEBUG build
+ BOOST_CHECK_MESSAGE( *server_defs == *server_reply.client_defs(),"Test:" << test_name << ": Starting point client and server defs should be the same");
+ Ecf::set_debug_equality(false);
+
+ // Get change number before any changes
+ unsigned int client_state_change_no = Ecf::state_change_no();
+ unsigned int client_modify_change_no = Ecf::modify_change_no();
+
+ // make some change to the server
+ {
+ Ecf::set_server(true);
+
+ the_defs_change_command(server_defs);
+
+ std::string error_msg;
+ BOOST_REQUIRE_MESSAGE( server_defs->checkInvariants(error_msg),"Test:" << test_name << ": Invariants failed: " << error_msg);
+ BOOST_REQUIRE_MESSAGE( !(*server_reply.client_defs() == *server_defs),"Test:" << test_name << ": Expected client and server defs to differ\n" << *server_reply.client_defs() << "\n" << "server defs = " << *server_defs);
+ Ecf::set_server(false);
+ }
+
+ MockServer mock_server(server_defs);
+ unsigned int client_handle = 0;
+ SNewsCmd news_cmd(client_handle, client_state_change_no, client_modify_change_no, &mock_server );
+ SSyncCmd cmd(client_handle, client_state_change_no, client_modify_change_no, &mock_server );
+
+ std::string error_msg;
+ BOOST_REQUIRE_MESSAGE( server_defs->checkInvariants(error_msg),"Test:" << test_name << ": Invariants failed: " << error_msg);
+ BOOST_CHECK_MESSAGE( news_cmd.get_news(), "Test:" << test_name << ": Expected server to change");
+ BOOST_CHECK_MESSAGE( cmd.do_sync( server_reply ),"Test:" << test_name << ": Expected server to change");
+ BOOST_CHECK_MESSAGE( server_reply.in_sync(), "Test:" << test_name << ": Expected server to change");
+ BOOST_CHECK_MESSAGE( server_reply.full_sync() == full_sync,"Test:" << test_name << ": Expected sync not as expected");
+
+ error_msg.clear();
+ BOOST_REQUIRE_MESSAGE( server_reply.client_defs()->checkInvariants(error_msg),"Test:" << test_name << ": Invariants failed: " << error_msg);
+
+ Ecf::set_debug_equality(true);
+ BOOST_CHECK_MESSAGE( *server_defs == *server_reply.client_defs(),"Test:" << test_name << ": Server and client should be same after sync" );
+ Ecf::set_debug_equality(false);
+}
+
+// The modifiers
+void delete_some_attributes(defs_ptr defs)
+{
+ std::vector<Task*> tasks;
+ defs->getAllTasks(tasks);
+ BOOST_FOREACH(Task* task, tasks) {
+
+ SuiteChanged1 changed(task->suite());
+
+ /// Take a copy, of the objects we want to delete. since there are returned by reference
+ std::vector<Event> events = task->events();
+ std::vector<Meter> meters = task->meters();
+ std::vector<Label> labels = task->labels();
+
+ BOOST_FOREACH(const Event& e, events) { task->deleteEvent( e.name_or_number() );}
+ BOOST_FOREACH(const Meter& m, meters) { task->deleteMeter( m.name() ); }
+ BOOST_FOREACH(const Label& l, labels) { task->deleteLabel( l.name() ); }
+
+ BOOST_REQUIRE_MESSAGE( task->events().empty(),"Expected all events to be deleted");
+ BOOST_REQUIRE_MESSAGE( task->meters().empty(),"Expected all meters to be deleted");
+ BOOST_REQUIRE_MESSAGE( task->labels().empty(),"Expected all labels to be deleted");
+ }
+}
+
+void add_some_attributes(defs_ptr defs) {
+ std::vector<task_ptr> tasks;
+ defs->get_all_tasks(tasks);
+ BOOST_FOREACH(task_ptr task, tasks) { SuiteChanged1 changed(task->suite()); task->addDay( DayAttr(DayAttr::TUESDAY) );}
+}
+
+void begin(defs_ptr defs) { defs->beginAll();} // reset all attributes
+
+void add_alias(defs_ptr defs) {
+
+ std::vector<task_ptr> tasks;
+ defs->get_all_tasks(tasks);
+ BOOST_REQUIRE_MESSAGE( !tasks.empty(), "Expected at least one task");
+
+ SuiteChanged1 changed(tasks[0]->suite());
+ tasks[0]->add_alias_only();
+}
+
+void remove_all_aliases(defs_ptr defs) {
+
+ std::vector<alias_ptr> aliases;
+ defs->get_all_aliases(aliases);
+ BOOST_REQUIRE_MESSAGE( !aliases.empty(), "Expected at least one alias");
+
+ BOOST_FOREACH(alias_ptr alias, aliases) {
+ TestHelper::invokeRequest(defs.get(),Cmd_ptr( new PathsCmd(PathsCmd::DELETE,alias->absNodePath())));
+ }
+
+ aliases.clear();
+ defs->get_all_aliases(aliases);
+ BOOST_REQUIRE_MESSAGE( aliases.empty(), "Expected at no alias");
+}
+
+void remove_all_tasks(defs_ptr defs) {
+
+ // Remove tasks should force a incremental sync
+ std::vector<task_ptr> tasks;
+ defs->get_all_tasks(tasks);
+ BOOST_FOREACH(task_ptr task, tasks) { SuiteChanged1 changed(task->suite()); task->remove() ;}
+
+ tasks.clear();
+ defs->get_all_tasks(tasks);
+ BOOST_REQUIRE_MESSAGE( tasks.empty(), "Failed to delete tasks");
+}
+
+void remove_a_family(defs_ptr defs) {
+
+ // Remove tasks should force a incremental sync
+ std::vector<Family*> vec;
+ defs->getAllFamilies(vec);
+ size_t family_size = vec.size();
+ BOOST_REQUIRE_MESSAGE( !vec.empty(), "Expected at least one family");
+ if (!vec.empty()) {
+ SuiteChanged1 changed(vec[0]->suite());
+ vec[0]->remove();
+ }
+
+ vec.clear();
+ defs->getAllFamilies(vec);
+ BOOST_REQUIRE_MESSAGE( vec.size() < family_size, "Failed to delete family");
+}
+
+
+void change_clock_gain(defs_ptr defs) {
+ BOOST_FOREACH(suite_ptr suite, defs->suiteVec()) {
+ if (suite->clockAttr().get()) {
+ SuiteChanged changed(suite);
+ suite->changeClockGain("100001");
+ }
+ }
+}
+void change_clock_type_to_real(defs_ptr defs) {
+
+ BOOST_FOREACH(suite_ptr suite, defs->suiteVec()) {
+ if (suite->clockAttr().get()) {
+ SuiteChanged changed(suite);
+ suite->changeClockType("real");
+ }
+ }
+}
+void change_clock_type_to_hybrid(defs_ptr defs) {
+
+ BOOST_FOREACH(suite_ptr suite, defs->suiteVec()) {
+ if (suite->clockAttr().get()) {
+ SuiteChanged changed(suite);
+ suite->changeClockType("hybrid");
+ }
+ }
+}
+void change_clock_date(defs_ptr defs) {
+
+ BOOST_FOREACH(suite_ptr suite, defs->suiteVec()) {
+ if (suite->clockAttr().get()) {
+ SuiteChanged changed(suite);
+ suite->changeClockDate("1.1.2001");
+ }
+ }
+}
+void change_clock_sync(defs_ptr defs) {
+
+ BOOST_FOREACH(suite_ptr suite, defs->suiteVec()) {
+ if (suite->clockAttr().get()) {
+ SuiteChanged changed(suite);
+ suite->changeClockSync();
+ }
+ }
+}
+
+
+/// This has been split into two functions, as changing both together could mask an error
+/// i.e found bug where we forgot to update state_change number when changing the limit
+/// max value, however because we had, changed value as well it got masked.
+void change_limit_max(defs_ptr defs) {
+
+ BOOST_FOREACH(suite_ptr s, defs->suiteVec()) {
+ std::vector<limit_ptr> theLimits = s->limits();
+ BOOST_FOREACH(limit_ptr l, theLimits) {
+ //std::cout << "found " << l->toString() << "\n";
+ TestHelper::invokeRequest(defs.get(),Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::LIMIT_MAX,l->name(),"90")));
+ limit_ptr v = s->find_limit(l->name());
+ BOOST_CHECK_MESSAGE( v.get() && v->theLimit() == 90, "expected to find limit with max value of 90");
+ }
+ }
+}
+void change_limit_value(defs_ptr defs) {
+
+ BOOST_FOREACH(suite_ptr s, defs->suiteVec()) {
+ std::vector<limit_ptr> theLimits = s->limits();
+ BOOST_FOREACH(limit_ptr l, theLimits) {
+ TestHelper::invokeRequest(defs.get(),Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::LIMIT_VAL,l->name(),"33")));
+ limit_ptr v = s->find_limit(l->name());
+ BOOST_CHECK_MESSAGE( v.get() && v->value() == 33, "expected to find limit with value of 33");
+ }
+ }
+}
+
+
+void update_repeat(defs_ptr defs) {
+
+ std::vector<Node*> nodes;
+ defs->getAllNodes(nodes);
+
+ BOOST_FOREACH(Node* n, nodes) {
+ if (!n->repeat().empty()) {
+ SuiteChanged1 changed(n->suite());
+ n->increment_repeat();
+ }
+ }
+}
+
+void update_calendar(defs_ptr defs) {
+
+ // The calendar is *only* updated if the suite have been begun. Hence make sure this test scaffold
+ // starts the test, with all the suites in a begun state
+ CalendarUpdateParams p( Calendar::second_clock_time(), minutes(1), true /* server running */, false/* for Test*/ );
+ defs->updateCalendar(p);
+
+ // Currently updating the calendar, does not cause change, Hence force a change
+ BOOST_FOREACH(suite_ptr suite, defs->suiteVec()) {
+ SuiteChanged changed(suite);
+ suite->add_variable("name","value");
+ }
+
+ // Note: In the real server, persisting that calendar, the clock type is not persisted.
+ // i.e when we have hybrid calendar, when restored on the client side it will be 'real' clock since
+ // that is the default now. This is not correct and will fail invariant checking.
+ // however the memento should reset clock type on the calenadar form the clok attribute.
+}
+
+
+void delete_suite(defs_ptr defs) {
+ std::vector<suite_ptr> vec = defs->suiteVec();
+ BOOST_REQUIRE_MESSAGE(!vec.empty(),"Expected suites");
+ vec[0]->remove();
+}
+
+void set_server_state_shutdown(defs_ptr defs) {
+ defs->set_server().set_state( SState::SHUTDOWN );
+}
+void set_server_state_running(defs_ptr defs) {
+ defs->set_server().set_state( SState::RUNNING );
+}
+
+void add_server_variable(defs_ptr defs) {
+ TestHelper::invokeRequest(defs.get(),Cmd_ptr( new AlterCmd("/",AlterCmd::ADD_VARIABLE,"_fred_","value")));
+}
+void change_server_variable(defs_ptr defs) {
+ // Because the scaffold create client/server defs each time.
+ // To test change/delete variables we modify the default set
+ TestHelper::invokeRequest(defs.get(),Cmd_ptr( new AlterCmd("/",AlterCmd::VARIABLE,"ECF_TRIES","4")));
+}
+void delete_server_variable(defs_ptr defs) {
+ // Because the scaffold create client/server defs each time.
+ // To test change/delete variables we modify the default set
+ // ***NOTE*** we can not delete server variables like ECF_TRIES, can only change them
+ // However we can delete user variables added to the server
+ TestHelper::invokeRequest(defs.get(),Cmd_ptr( new AlterCmd("/",AlterCmd::DEL_VARIABLE,"MyDefsFixture_user_variable")));
+}
+
+void reorder_suites(defs_ptr defs) {
+ std::vector<suite_ptr> suiteVec = defs->suiteVec();
+ BOOST_REQUIRE_MESSAGE(!suiteVec.empty(),"Expected suites");
+ std::string path = "/" + suiteVec[0]->name();
+ TestHelper::invokeRequest(defs.get(),Cmd_ptr( new OrderNodeCmd(path,NOrder::ALPHA)));
+}
+
+void set_defs_flag(defs_ptr defs) {
+ defs->flag().set(ecf::Flag::MESSAGE);
+}
+
+void set_defs_state(defs_ptr defs) {
+ defs->set_state(NState::ABORTED);
+}
+
+BOOST_AUTO_TEST_CASE( test_ssync_cmd )
+{
+ // To DEBUG: enable the defines in Memento.hpp
+ cout << "Base:: ...test_ssync_cmd\n";
+ test_sync_scaffold(update_repeat,"update_repeat");
+ test_sync_scaffold(delete_some_attributes,"delete_some_attributes");
+ test_sync_scaffold(add_some_attributes,"add_some_attributes");
+ test_sync_scaffold(begin,"begin",true /* expect full_sync */);
+ test_sync_scaffold(add_alias,"add_alias");
+ test_sync_scaffold(remove_all_aliases,"remove_all_aliases");
+ test_sync_scaffold(remove_all_tasks,"remove_all_tasks");
+ test_sync_scaffold(remove_a_family,"remove_a_family");
+ test_sync_scaffold(change_clock_gain,"change_clock_gain", true /* expect full_sync */);
+ test_sync_scaffold(change_clock_type_to_real,"change_clock_type_to_real", true /* expect full_sync */);
+ test_sync_scaffold(change_clock_type_to_hybrid,"change_clock_type_to_hybrid", true /* expect full_sync */);
+ test_sync_scaffold(change_clock_date,"change_clock_date", true /* expect full_sync */);
+ test_sync_scaffold(change_clock_sync,"change_clock_sync", true /* expect full_sync */);
+ test_sync_scaffold(update_calendar,"update_calendar", false/* expect full_sync */, true /* start test with begin */ );
+ test_sync_scaffold(change_limit_max,"change_limit_max");
+ test_sync_scaffold(change_limit_value,"change_limit_value");
+ test_sync_scaffold(delete_suite,"delete_suite", true /* expect full_sync */);
+
+ // Test Changes in Defs
+ // The default server state is HALTED, hence setting to halted will not show a change
+ test_sync_scaffold(set_server_state_shutdown,"set_server_state_shutdown");
+ test_sync_scaffold(set_server_state_running,"set_server_state_running");
+
+ test_sync_scaffold(add_server_variable,"add_server_variable");
+ test_sync_scaffold(change_server_variable,"change_server_variable");
+ test_sync_scaffold(delete_server_variable,"delete_server_variable");
+
+ test_sync_scaffold(reorder_suites,"reorder_suites");
+
+ test_sync_scaffold(set_defs_flag,"set_defs_flag");
+ test_sync_scaffold(set_defs_state,"set_defs_state");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+
diff --git a/Base/test/TestSSyncCmdOrder.cpp b/Base/test/TestSSyncCmdOrder.cpp
new file mode 100644
index 0000000..8e5290e
--- /dev/null
+++ b/Base/test/TestSSyncCmdOrder.cpp
@@ -0,0 +1,231 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <boost/test/unit_test.hpp>
+#include <boost/function.hpp>
+
+#include "ClientToServerCmd.hpp"
+#include "ServerToClientCmd.hpp"
+#include "MyDefsFixture.hpp"
+#include "MockServer.hpp"
+#include "TestHelper.hpp"
+#include "SSyncCmd.hpp"
+#include "Ecf.hpp"
+#include "NodeFwd.hpp"
+#include "SuiteChanged.hpp"
+#include "System.hpp"
+
+using namespace std;
+using namespace ecf;
+
+// The client handle commands do not change state & modify change number, hence need to bypass these checks
+static bool bypass_state_modify_change_check = false;
+
+BOOST_AUTO_TEST_SUITE( BaseTestSuite )
+
+/// define a function which returns nothing, and takes a defs_ptr parameter
+typedef boost::function<void (defs_ptr)> defs_change_cmd;
+
+template <typename T>
+static std::vector<std::string> toStrVec(const std::vector<T>& vec)
+{
+ std::vector<std::string> retVec; retVec.reserve(vec.size());
+ BOOST_FOREACH(T s, vec) { retVec.push_back(s->name()); }
+ return retVec;
+}
+
+static std::string toString(const std::vector<std::string>& c)
+{
+ std::stringstream ss;
+ std::copy (c.begin(), c.end(), std::ostream_iterator <std::string> (ss, ", "));
+ return ss.str();
+}
+
+static std::vector<std::string> vector_abcd() {
+ std::vector<std::string> names; names.reserve(4);
+ names.push_back("a"); names.push_back("b"); names.push_back("c"); names.push_back("d");
+ return names;
+}
+static std::vector<std::string> vector_dcba() {
+ std::vector<std::string> names; names.reserve(4);
+ names.push_back("d"); names.push_back("c"); names.push_back("b"); names.push_back("a");
+ return names;
+}
+
+static defs_ptr create_defs()
+{
+ std::vector<std::string> names = vector_dcba();
+ defs_ptr defs = Defs::create();
+ for(size_t j = 0; j <names.size(); j++) {
+ suite_ptr s = defs->add_suite( names[j] );
+ if ( 0 == j) { // only add family to first suite
+ for(size_t k = 0; k <names.size(); k++) {
+ family_ptr f = s->add_family(names[k]);
+ for(size_t l = 0; l <names.size(); l++) {
+ task_ptr t = f->add_task(names[l]);
+// t->add_alias_only(); // alias0
+// t->add_alias_only(); // alias1
+// t->add_alias_only(); // alias2
+ }
+ }
+ }
+ }
+ return defs;
+}
+
+
+/// Re-use the same test scaffold to modify and then resync, by passing in a function that will modify the defs
+static void test_sync_scaffold( defs_change_cmd the_defs_change_command,
+ unsigned int test_equality, /*0 means test equality, any other number test size*/
+ bool full_sync, unsigned int client_handle)
+{
+ defs_ptr server_defs = create_defs();
+ ServerReply server_reply;
+ server_reply.set_client_defs( create_defs() );
+
+
+ Ecf::set_debug_equality(true); // only has affect in DEBUG build
+ BOOST_CHECK_MESSAGE( *server_defs == *server_reply.client_defs(), "Starting point client and server defs should be the same");
+ Ecf::set_debug_equality(false);
+
+ // Get change number before any changes
+ Ecf::set_state_change_no(0);
+ Ecf::set_modify_change_no(0);
+ unsigned int client_state_change_no = Ecf::state_change_no();
+ unsigned int client_modify_change_no = Ecf::modify_change_no();
+
+ // make some change to the server
+ {
+ Ecf::set_server(true);
+
+ the_defs_change_command(server_defs);
+ std::string errorMsg;
+ BOOST_REQUIRE_MESSAGE( server_defs->checkInvariants(errorMsg),"Invariants failed " << errorMsg);
+ BOOST_REQUIRE_MESSAGE( !(*server_reply.client_defs() == *server_defs), "Expected client and server defs to differ " << *server_reply.client_defs() << "\n" << "server defs = " << *server_defs);
+ Ecf::set_server(false);
+ }
+
+// cout << "test_sync_scaffold AFTER Command before SYNC: Server:\n" << *server_defs << "\n";
+// cout << "test_sync_scaffold AFTER Command before SYNC: Client:\n" << *server_reply.client_defs() << "\n";
+
+ MockServer mock_server(server_defs);
+ SSyncCmd cmd(client_handle, client_state_change_no, client_modify_change_no, &mock_server );
+ string error_msg;BOOST_REQUIRE_MESSAGE(mock_server.defs()->checkInvariants(error_msg), error_msg);
+ BOOST_CHECK_MESSAGE( cmd.do_sync( server_reply ), "Expected server to change");
+ BOOST_CHECK_MESSAGE( server_reply.in_sync(), "Expected to be in sync");
+ BOOST_CHECK_MESSAGE( server_reply.full_sync() == full_sync, "Expected full sync");
+
+ if (0 == test_equality) {
+ Ecf::set_debug_equality(true);
+ BOOST_CHECK_MESSAGE( *server_defs == *server_reply.client_defs(), "Server and client should be same after sync" );
+ Ecf::set_debug_equality(false);
+ }
+ else {
+ BOOST_CHECK_MESSAGE( server_reply.client_defs()->suiteVec().size() == test_equality, "Expected suite of size " << test_equality << " but found " << server_reply.client_defs()->suiteVec().size());
+ }
+}
+
+static void reorder_suites(defs_ptr theDefs) {
+
+ TestHelper::invokeRequest(theDefs.get(),Cmd_ptr( new OrderNodeCmd("/a",NOrder::ALPHA)));
+ BOOST_REQUIRE_MESSAGE( toStrVec(theDefs->suiteVec()) == vector_abcd(),"NOrder::ALPHA expected " << toString(vector_abcd())<< " but found: " << toString(toStrVec(theDefs->suiteVec())));
+}
+
+static void reorder_family(defs_ptr theDefs) {
+// std::cout << "reorder_family\n" << *theDefs << "\n";
+
+ TestHelper::invokeRequest(theDefs.get(),Cmd_ptr( new OrderNodeCmd("/d/d",NOrder::ALPHA)));
+
+ std::vector<Family*> families;
+ theDefs->findSuite("d")->getAllFamilies(families);
+ BOOST_REQUIRE_MESSAGE( toStrVec(families) == vector_abcd(),"NOrder::ALPHA expected " << toString(vector_abcd())<< " but found: " << toString(toStrVec(families)));
+}
+
+static void reorder_task(defs_ptr theDefs) {
+ //std::cout << "reorder_task\n" << *theDefs << "\n";
+
+ TestHelper::invokeRequest(theDefs.get(),Cmd_ptr( new OrderNodeCmd("/d/d/d",NOrder::ALPHA)));
+
+ std::vector<Task*> tasks;
+ theDefs->findAbsNode("/d/d")->getAllTasks(tasks);
+ BOOST_REQUIRE_MESSAGE( toStrVec(tasks) == vector_abcd(),"NOrder::ALPHA expected " << toString(vector_abcd())<< " but found: " << toString(toStrVec(tasks)));
+}
+
+//static void reorder_alias(defs_ptr theDefs) {
+// //std::cout << "reorder_task\n" << *theDefs << "\n";
+//
+// TestHelper::invokeRequest(theDefs.get(),Cmd_ptr( new OrderNodeCmd("/d/d/d/alias0",NOrder::ALPHA)));
+//
+// std::vector<alias_ptr> aliases;
+// theDefs->findAbsNode("/d/d/d")->get_all_aliases(aliases);
+// BOOST_REQUIRE_MESSAGE( toStrVec(aliases) == vector_abcd(),"NOrder::ALPHA expected " << toString(vector_abcd())<< " but found: " << toString(toStrVec(tasks)));
+//}
+
+
+static void reorder_suites_using_handles(defs_ptr theDefs) {
+
+ // *** NOTE ****: Whenever we register a handle, we get a *FULL* sync
+
+ // create client handle which references all the suites
+ // It should be noted that invokeRequest, uses a MockServer, which set/unsets
+ // Hence after this call Ecf::server_ is false. Hence we need to ensure that following
+ // commands/ DM function set Ecf::server_ to true.
+ std::vector<std::string> suite_names = vector_abcd();
+ TestHelper::invokeRequest(theDefs.get(),Cmd_ptr( new ClientHandleCmd(suite_names,false)),bypass_state_modify_change_check);
+ BOOST_CHECK_MESSAGE(theDefs->client_suite_mgr().clientSuites().size() == 1,"Expected 1 Client suites but found " << theDefs->client_suite_mgr().clientSuites().size());
+
+ TestHelper::invokeRequest(theDefs.get(),Cmd_ptr( new OrderNodeCmd("/a",NOrder::ALPHA)));
+ BOOST_REQUIRE_MESSAGE( toStrVec(theDefs->suiteVec()) == vector_abcd(),"NOrder::ALPHA expected " << toString(vector_abcd())<< " but found: " << toString(toStrVec(theDefs->suiteVec())));
+}
+
+static void reorder_family_using_handles(defs_ptr theDefs) {
+
+ // *** NOTE ****: Whenever we register a handle, we get a *FULL* sync
+
+ // create client handle which references all the suites
+ // It should be noted that invokeRequest, uses a MockServer, which set/unsets
+ // Hence after this call Ecf::server_ is false. Hence we need to ensure that following
+ // commands/ DM function set Ecf::server_ to true.
+ std::vector<std::string> suite_names ; suite_names.push_back("d"); // clinet handle for suite 'd' ONLY
+ TestHelper::invokeRequest(theDefs.get(),Cmd_ptr( new ClientHandleCmd(suite_names,false)),bypass_state_modify_change_check);
+ BOOST_CHECK_MESSAGE(theDefs->client_suite_mgr().clientSuites().size() == 1,"Expected 1 Client suites but found " << theDefs->client_suite_mgr().clientSuites().size());
+
+ /// Don't call, data model function directly, since Ecf::server_ is false. *here*
+ /// The suite should stay the same, only suite d's family should change
+ TestHelper::invokeRequest(theDefs.get(),Cmd_ptr( new OrderNodeCmd("/d/d",NOrder::ALPHA)));
+ BOOST_REQUIRE_MESSAGE( toStrVec(theDefs->suiteVec()) == vector_dcba(),"expected " << toString(vector_dcba())<< " but found: " << toString(toStrVec(theDefs->suiteVec())));
+
+ suite_ptr suite_a = theDefs->findSuite("d");
+ std::vector<Family*> families; suite_a->getAllFamilies(families);
+ BOOST_REQUIRE_MESSAGE( toStrVec(families) == vector_abcd(),"NOrder::ALPHA expected " << toString(vector_abcd())<< " but found: " << toString(toStrVec(families)));
+}
+
+
+BOOST_AUTO_TEST_CASE( test_ssync_cmd_test_order )
+{
+ cout << "Base:: ...test_ssync_cmd_test_order\n";
+ test_sync_scaffold(reorder_suites, 0 /* test equality */, false /* expect full_sync */, 0);
+ test_sync_scaffold(reorder_family, 0 /* test equality */, false /* expect full_sync */, 0);
+ test_sync_scaffold(reorder_task, 0 /* test equality */, false /* expect full_sync */, 0);
+// test_sync_scaffold(reorder_alias, 0 /* test equality */, false /* expect full_sync */, 0);
+
+ test_sync_scaffold(reorder_suites_using_handles, 0 /* test equality */, true /* expect full_sync */, 1 /* client handle */);
+ test_sync_scaffold(reorder_family_using_handles, 1 /* test size */, true /* expect full_sync */, 1 /* client handle */);
+
+ /// Keep valgrind happy
+ System::destroy();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/Base/test/TestSSyncCmd_CH1.cpp b/Base/test/TestSSyncCmd_CH1.cpp
new file mode 100644
index 0000000..da7e5e0
--- /dev/null
+++ b/Base/test/TestSSyncCmd_CH1.cpp
@@ -0,0 +1,674 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #18 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <boost/test/unit_test.hpp>
+#include <boost/function.hpp>
+
+#include "ClientToServerCmd.hpp"
+#include "ServerToClientCmd.hpp"
+#include "MyDefsFixture.hpp"
+#include "MockServer.hpp"
+#include "TestHelper.hpp"
+#include "SSyncCmd.hpp"
+#include "SNewsCmd.hpp"
+#include "Ecf.hpp"
+#include "NodeFwd.hpp"
+#include "SuiteChanged.hpp"
+
+using namespace std;
+using namespace ecf;
+
+/// This test, is used to check sync with the client handles.
+/// The client handles will register interest in a set of suites
+/// When calling sync, check will only receive notification on our
+/// our suites
+// In particular when a set of suites are registered to a handle
+// and we add/delete/check point/order the server passes back to the client
+// the a *new* defs with all the suites corresponding to the handle
+// There is a complication however, the suite are not copied/cloned
+// This causes a problem, since if we create a new defs, and add
+// the suites, the suite defs pointer is *NOW* corrupted, as it will point
+// to the new defs. This is not an issue in real apps, since searisation
+// fixes up these ptrs.
+
+// The client handle commands do not change state & modify change number, hence need to bypass these checks
+static bool bypass_state_modify_change_check = false;
+
+BOOST_AUTO_TEST_SUITE( BaseTestSuite )
+
+static defs_ptr create_client_defs(defs_ptr defs)
+{
+ for(size_t j = 0; j < 5; j++) {
+ suite_ptr suite = defs->add_suite( "s" + boost::lexical_cast<std::string>(j) );
+ family_ptr f = suite->add_family("f");
+ f->add_task("t");
+ if (j == 0) {
+ suite->addLimit( Limit("suiteLimit",10) );
+ suite->addRepeat( RepeatDate("YMD",20090916,20090916,1) );
+ }
+ }
+ return defs;
+}
+
+static defs_ptr create_server_defs()
+{
+ defs_ptr defs = Defs::create();
+
+ // Create server defs, with a port other than default.
+ // This allows additional testing. i.e server variables
+ std::vector<Variable> server_variables;
+ ServerState::setup_default_server_variables(server_variables,"4000");
+ defs->set_server().set_server_variables(server_variables);
+
+ // ensure client/server start out the same
+ return create_client_defs(defs);
+}
+
+/// define a function which returns nothing, and takes a defs_ptr parameter
+typedef boost::function<bool (defs_ptr)> defs_change_cmd;
+
+/// Re-use the same test scaffold to modify and then resync, by passing
+/// in a function that will modify the defs
+void test_sync_scaffold( defs_change_cmd the_defs_change_command, const std::string& test_name, bool full_sync = false)
+{
+ // Create the defs
+ defs_ptr server_defs = create_server_defs();
+ ServerReply server_reply;
+ server_reply.set_client_defs( create_client_defs(Defs::create()) );
+
+ Ecf::set_debug_equality(true); // only has affect in DEBUG build
+ BOOST_CHECK_MESSAGE( *server_defs == *server_reply.client_defs(),
+ test_name << ": Starting point client and server defs should be the same : "
+ << "SERVER\n" << server_defs
+ << "CLIENT\n" << server_reply.client_defs());
+ Ecf::set_debug_equality(false);
+
+ // set handle and change numbers, before any changes
+ Ecf::set_state_change_no(0);
+ Ecf::set_modify_change_no(0);
+ unsigned int client_state_change_no = Ecf::state_change_no();
+ unsigned int client_modify_change_no = Ecf::modify_change_no();
+ unsigned int client_handle = 0;
+
+ bool expected_change;
+
+ // make some change to the server
+ {
+ /// create client handle which references suites s0 and s4, in the server defs
+ /// Registering suites should change handle_changed boolean
+ std::vector<std::string> suite_names; suite_names.push_back("s0"); suite_names.push_back("s4");
+ TestHelper::invokeRequest(server_defs.get(),Cmd_ptr( new ClientHandleCmd(suite_names,false)),bypass_state_modify_change_check);
+
+ BOOST_CHECK_MESSAGE(server_defs->client_suite_mgr().clientSuites().size() == 1,test_name << ": Expected 1 Client suites but found " <<server_defs->client_suite_mgr().clientSuites().size());
+ client_handle = server_defs->client_suite_mgr().clientSuites().front().handle();
+ BOOST_CHECK_MESSAGE( client_handle == 1,"" );
+
+ /// Check that handle_changed set, required for syncing, i.e needed for full sync , without change state/modify numbers
+ BOOST_CHECK_MESSAGE(server_defs->client_suite_mgr().handle_changed(client_handle) == true,"Expected handle_changed to be set when suites are registered ");
+
+ /// called create Defs should clear the flag. make sure server state, is synced
+ defs_ptr the_client_defs = server_defs->client_suite_mgr().create_defs(client_handle,server_defs);
+ BOOST_CHECK_MESSAGE(the_client_defs->suiteVec().size() == 2 ,test_name << ": Expected 2 suites");
+ BOOST_CHECK_MESSAGE(server_defs->client_suite_mgr().handle_changed(client_handle) == false,test_name << ": Expected handle_changed to be cleared after create_defs()");
+ Ecf::set_debug_equality(true);
+ BOOST_CHECK_MESSAGE( server_defs->server().compare(the_client_defs->server() ), test_name << ": Server state does not match");
+ Ecf::set_debug_equality(false);
+
+ Ecf::set_server(true);
+ expected_change = the_defs_change_command(server_defs);
+ std::string error_msg;
+ BOOST_REQUIRE_MESSAGE( server_defs->checkInvariants(error_msg) , test_name << ": Invariants failed: " << error_msg);
+ Ecf::set_server(false);
+
+ /// Call create defs again, after change in server defs, check server state is synced
+ the_client_defs = server_defs->client_suite_mgr().create_defs(client_handle,server_defs);
+ Ecf::set_debug_equality(true);
+ BOOST_CHECK_MESSAGE( server_defs->server().compare(the_client_defs->server() ), test_name << ": Server state does not match");
+ Ecf::set_debug_equality(false);
+ }
+
+ MockServer mock_server(server_defs);
+ SNewsCmd news_cmd(client_handle, client_state_change_no, client_modify_change_no, &mock_server );
+ SSyncCmd cmd(client_handle, client_state_change_no, client_modify_change_no, &mock_server );
+
+ if ( expected_change ) {
+ BOOST_CHECK_MESSAGE( news_cmd.get_news(), test_name << " : get_news : Expected server to change");
+ BOOST_CHECK_MESSAGE( cmd.do_sync( server_reply ), test_name << " : do_sync : Expected server to change");
+ BOOST_CHECK_MESSAGE( server_reply.in_sync(), test_name << " : in_sync : Expected client server to be in sync");
+ BOOST_CHECK_MESSAGE( server_reply.full_sync() == full_sync,test_name << ": Expected sync not as expected. client: " << server_reply.full_sync() << " full_sync: " << full_sync);
+ BOOST_CHECK_MESSAGE( server_defs->state() == server_reply.client_defs()->state(),test_name << ": Expected server State(" << NState::toString(server_defs->state()) << ") to be same as client state(" << NState::toString(server_reply.client_defs()->state()) << ")");
+ if (full_sync) {
+ Ecf::set_debug_equality(true);
+ BOOST_CHECK_MESSAGE( server_defs->server().compare(server_reply.client_defs()->server()),test_name << ": Server state does not match");
+ Ecf::set_debug_equality(false);
+ }
+ else {
+ }
+
+ // * Note we expect client defs to fail invariant checking when doing a full sync with handles
+ // * Under real server this should be ok since, we fix up the defs ptr, during serialisation
+
+ // * note. We can't really compare server and client defs, since when we sync with
+ // * with handles, we only return a sub set of the suites, in our handle
+
+ // DO a sync again. hence we should expect no changes
+ server_reply.clear_for_invoke(false);
+ Ecf::set_server(true);
+ /* server side */ SNewsCmd news_cmd1(client_handle, server_reply.client_defs()->state_change_no(), server_reply.client_defs()->modify_change_no(), &mock_server );
+ /* server side */ SSyncCmd cmd1(client_handle, server_reply.client_defs()->state_change_no(), server_reply.client_defs()->modify_change_no(), &mock_server );
+ Ecf::set_server(false);
+ /* client side */ BOOST_CHECK_MESSAGE( !news_cmd1.get_news(), test_name << ": Expected no changes to client, we should be in sync");
+ /* client side */ BOOST_CHECK_MESSAGE( !cmd1.do_sync( server_reply ), test_name << ": Expected no changes to client, we should be in sync");
+ }
+ else {
+
+ BOOST_CHECK_MESSAGE( !news_cmd.get_news(), test_name << ": Expected no change");
+ BOOST_CHECK_MESSAGE( !cmd.do_sync( server_reply ), test_name << ": Expected no change");
+ BOOST_CHECK_MESSAGE( !server_reply.in_sync(), test_name << ": Expected no change");
+ BOOST_CHECK_MESSAGE( !(*server_defs == *server_reply.client_defs()), test_name << ": Server and client defs expected to differ" );
+ }
+}
+
+
+static bool set_server_state_shutdown(defs_ptr defs) {
+ defs->set_server().set_state( SState::SHUTDOWN );
+ return true; // expect changes
+}
+static bool set_server_state_running(defs_ptr defs) {
+ defs->set_server().set_state( SState::RUNNING );
+ return true; // expect changes
+}
+
+static bool change_suites_s3_outside_of_handle(defs_ptr defs)
+{
+ /// Make a state change to suites s3, in the server. This is *not* in the client handle
+ /// Note: we do *NOT* make a state change as this will be propagated to the defs, and hence will be synced
+ /// We *NEED* MockSuiteChangedServer, so that change is propagated to the suite.
+ MockSuiteChangedServer mockServer(defs->findSuite("s3")); // Increment suite state/modify change number
+ defs->findSuite("s3")->suspend(); // small scale state change
+ return false; // expect no changes
+}
+
+static bool change_suites_s3_outside_of_handle_add_variable(defs_ptr defs)
+{
+ /// make a state change to suites s3, in the server. This is *not* in the client handle
+ /// We *NEED* MockSuiteChangedServer, so that change is propagated to the suite.
+ MockSuiteChangedServer mockServer(defs->findSuite("s3")); // Increment suite state/modify change number
+ defs->findSuite("s3")->add_variable("Var","value"); // small scale state change
+ return false; // expect no changes in sync
+}
+
+static bool add_task_to_suite_s3(defs_ptr defs)
+{
+ /// make a modify change to suites s3, in the server. This is *not* in the client handle
+ MockSuiteChangedServer mockServer(defs->findSuite("s3")); // Increment suite state/modify change number
+ defs->findSuite("s3")->addTask( Task::create("s3_task")); // small scale change
+ return false; // expect no changes, since suite s3 not in handle
+}
+
+static bool delete_task_on_suite_s3(defs_ptr defs)
+{
+ /// make a modify change to suites s3, in the server. This is *not* in the client handle
+ MockSuiteChangedServer mockServer(defs->findSuite("s3")); // Increment suite state/modify change number
+ defs->findAbsNode("/s3/f/t")->remove(); // small scale change
+ return false; // expect no changes, since suite s3 not in handle
+}
+static bool delete_family_on_suite_s3(defs_ptr defs)
+{
+ /// make a modify change to suites s3, in the server. This is *not* in the client handle
+ MockSuiteChangedServer mockServer(defs->findSuite("s3")); // Increment suite state/modify change number
+ defs->findAbsNode("/s3/f")->remove(); // small scale change
+ return false; // expect no changes, since suite s3 not in handle
+}
+
+static bool change_state_of_s4(defs_ptr defs)
+{
+ /// Ok now make state change to s4, which **is** in the handle
+ /// We need MockSuiteChangedServer, so that change is propagated to the suite.
+ MockSuiteChangedServer mockServer(defs->findSuite("s4")); // Increment suite state/modify change number
+ defs->findSuite("s4")->set_state(NState::SUBMITTED); // small scale change
+ return true; // expect changes
+}
+
+static bool add_variable_to_suite_s4(defs_ptr defs)
+{
+ /// Ok now make state change to s4, which **is** in the handle
+ /// We need MockSuiteChangedServer, so that change is propagated to the suite.
+ MockSuiteChangedServer mockServer(defs->findSuite("s4")); // Increment suite state/modify change number
+ defs->findSuite("s4")->add_variable("Var","value"); // small scale state change
+ return true; // expect changes
+}
+
+static bool add_server_user_variables(defs_ptr defs)
+{
+ // Change server. This is outside of any suites
+ std::vector<Variable> user_variables;
+ user_variables.push_back(Variable("a","b"));
+ user_variables.push_back(Variable("c","d"));
+ defs->set_server().set_user_variables(user_variables);
+ return true; // expect change
+}
+
+static bool add_task_to_suite_s4(defs_ptr defs)
+{
+ /// Ok now make modify change to s4, which **is** in the handle
+ MockSuiteChangedServer mockServer(defs->findSuite("s4")); // Increment suite state/modify change number
+ defs->findSuite("s4")->addTask( Task::create("s4_task")); // small scale change
+ return true; // expect changes
+}
+
+static bool delete_task_on_suite_s4(defs_ptr defs)
+{
+ /// Ok now make modify change to s4, which **is** in the handle
+ MockSuiteChangedServer mockServer(defs->findSuite("s4")); // Increment suite state/modify change number
+ defs->findAbsNode("/s4/f/t")->remove(); // small scale change
+ return true; // expect changes, since suite s4 is in handle
+}
+
+static bool delete_family_on_suite_s4(defs_ptr defs)
+{
+ /// Ok now make modify change to s4, which **is** in the handle
+ MockSuiteChangedServer mockServer(defs->findSuite("s4")); // Increment suite state/modify change number
+ defs->findAbsNode("/s4/f")->remove(); // small scale change
+ return true; // expect changes, since suite s4 is in handle
+}
+
+static bool change_order_of_s4_top(defs_ptr defs) {
+ /// Ok make modify change to s4, which **is** in the handle
+ suite_ptr s4 = defs->findSuite("s4");
+ MockSuiteChangedServer mockServer(s4); // Increment suite state/modify change number
+ defs->order(s4.get(),NOrder::TOP) ; // small scale scale change
+ return true;
+}
+
+static bool change_order_of_s4_bottom(defs_ptr defs) {
+ /// Ok make modify change to s4, which **is** in the handle
+ suite_ptr s4 = defs->findSuite("s4");
+ MockSuiteChangedServer mockServer(s4); // Increment suite state/modify change number
+ defs->order(s4.get(),NOrder::BOTTOM) ; // small scale change
+ return true;
+}
+
+static bool delete_suite_s4(defs_ptr defs)
+{
+ /// Ok now make delete s4 which, which **is** in the handle
+ MockSuiteChangedServer mockServer(defs->findSuite("s4")); // Increment suite state/modify change number
+ defs->findSuite("s4")->remove(); // large scale change
+ return true; // expect changes
+}
+
+static bool set_defs_state(defs_ptr defs)
+{
+ defs->set_state( NState::ABORTED ); // changes the defs state
+ return true; // expect changes
+}
+
+static bool set_defs_state_2(defs_ptr defs)
+{
+ defs->set_state( NState::ABORTED ); // changes the defs state
+ return delete_suite_s4( defs ); // large scale change
+}
+
+static bool add_server_variable(defs_ptr defs) {
+ // Change defs server state. small scale change
+ TestHelper::invokeRequest(defs.get(),Cmd_ptr( new AlterCmd("/",AlterCmd::ADD_VARIABLE,"_fred_","value")));
+ return true;
+}
+
+static bool change_server_variable(defs_ptr defs) {
+ // Because the scaffold create client/server defs each time.
+ // To test change/delete variables we modify the default set
+ TestHelper::invokeRequest(defs.get(),Cmd_ptr( new AlterCmd("/",AlterCmd::VARIABLE,"ECF_TRIES","4")));
+ return true;
+}
+
+// ===============================================================================
+// The modifiers, do this for suite s0 which is in a handle
+// ===============================================================================
+static bool s0_delete_some_attributes(defs_ptr defs) {
+
+ /// Ok now make state change to s4, which **is** in the handle
+ /// We need MockSuiteChangedServer, so that change is propagated to the suite.
+ suite_ptr suite = defs->findSuite("s0");
+ BOOST_REQUIRE_MESSAGE( suite,"Could not find suite");
+ MockSuiteChangedServer mockServer(suite); // Increment suite state/modify change number
+
+ std::vector<Task*> tasks;
+ suite->getAllTasks(tasks);
+ BOOST_REQUIRE_MESSAGE( !tasks.empty(), "Expected at least one task");
+
+ BOOST_FOREACH(Task* task, tasks) {
+ SuiteChanged1 changed(task->suite());
+ task->addMeter(Meter("meter",0,100));
+ }
+ return true;
+}
+
+static bool s0_add_some_attributes(defs_ptr defs) {
+ suite_ptr suite = defs->findSuite("s0");
+ BOOST_REQUIRE_MESSAGE( suite,"Could not find suite");
+ MockSuiteChangedServer mockServer(suite); // Increment suite state/modify change number
+
+ std::vector<task_ptr> tasks;
+ suite->get_all_tasks(tasks);
+ BOOST_REQUIRE_MESSAGE( !tasks.empty(), "Expected at least one task");
+
+ BOOST_FOREACH(task_ptr task, tasks) { SuiteChanged1 changed(suite.get()); task->addDay( DayAttr(DayAttr::TUESDAY) );}
+ return true;
+}
+
+static bool s0_begin(defs_ptr defs) {
+ suite_ptr suite = defs->findSuite("s0");
+ BOOST_REQUIRE_MESSAGE( suite,"Could not find suite");
+ MockSuiteChangedServer mockServer(suite); // Increment suite state/modify change number
+
+ suite->begin();
+ return true;
+}
+
+static bool s0_add_alias(defs_ptr defs) {
+ suite_ptr suite = defs->findSuite("s0");
+ BOOST_REQUIRE_MESSAGE( suite,"Could not find suite");
+ MockSuiteChangedServer mockServer(suite); // Increment suite state/modify change number
+
+ std::vector<task_ptr> tasks;
+ suite->get_all_tasks(tasks);
+ BOOST_REQUIRE_MESSAGE( !tasks.empty(), "Expected at least one task");
+
+ SuiteChanged1 changed(tasks[0]->suite());
+ tasks[0]->add_alias_only();
+ return true;
+}
+
+static bool s0_remove_all_tasks(defs_ptr defs) {
+ suite_ptr suite = defs->findSuite("s0");
+ BOOST_REQUIRE_MESSAGE( suite,"Could not find suite");
+ MockSuiteChangedServer mockServer(suite); // Increment suite state/modify change number
+
+
+ // Remove tasks should force a incremental sync
+ std::vector<task_ptr> tasks;
+ suite->get_all_tasks(tasks);
+ BOOST_REQUIRE_MESSAGE( !tasks.empty(), "Expected at least one task");
+ BOOST_FOREACH(task_ptr task, tasks) { SuiteChanged1 changed(task->suite()); task->remove() ;}
+
+ tasks.clear();
+ suite->get_all_tasks(tasks);
+ BOOST_REQUIRE_MESSAGE( tasks.empty(), "Failed to delete tasks");
+ return true;
+}
+
+static bool s0_remove_a_family(defs_ptr defs) {
+ suite_ptr suite = defs->findSuite("s0");
+ BOOST_REQUIRE_MESSAGE( suite,"Could not find suite");
+ MockSuiteChangedServer mockServer(suite); // Increment suite state/modify change number
+
+ std::vector<Family*> vec;
+ suite->getAllFamilies(vec);
+ size_t family_size = vec.size();
+ BOOST_REQUIRE_MESSAGE( !vec.empty(), "Expected at least one family");
+ if (!vec.empty()) {
+ SuiteChanged1 changed(vec[0]->suite());
+ vec[0]->remove();
+ }
+
+ vec.clear();
+ suite->getAllFamilies(vec);
+ BOOST_REQUIRE_MESSAGE( vec.size() < family_size, "Failed to delete family");
+ return true;
+}
+
+
+static bool s0_change_clock_gain(defs_ptr defs) {
+ suite_ptr suite = defs->findSuite("s0");
+ BOOST_REQUIRE_MESSAGE( suite,"Could not find suite");
+ MockSuiteChangedServer mockServer(suite); // Increment suite state/modify change number
+
+ suite->changeClockGain("100001");
+ return true;
+}
+
+static bool s0_change_clock_type_to_real(defs_ptr defs) {
+ suite_ptr suite = defs->findSuite("s0");
+ BOOST_REQUIRE_MESSAGE( suite,"Could not find suite");
+ MockSuiteChangedServer mockServer(suite); // Increment suite state/modify change number
+
+ suite->changeClockType("hybrid");
+ return true;
+}
+
+static bool s0_change_clock_date(defs_ptr defs) {
+ suite_ptr suite = defs->findSuite("s0");
+ BOOST_REQUIRE_MESSAGE( suite,"Could not find suite");
+
+ suite->changeClockDate("1.1.2001");
+ return true;
+}
+
+static bool s0_change_clock_sync(defs_ptr defs) {
+ suite_ptr suite = defs->findSuite("s0");
+ BOOST_REQUIRE_MESSAGE( suite,"Could not find suite");
+ MockSuiteChangedServer mockServer(suite); // Increment suite state/modify change number
+
+ suite->changeClockSync();
+ return true;
+}
+
+/// This has been split into two functions, as changing both together could mask an error
+/// i.e found bug where we forgot to update state_change number when changing the limit
+/// max value, however because we had, changed value as well it got masked.
+static bool s0_change_limit_max(defs_ptr defs) {
+ suite_ptr suite = defs->findSuite("s0");
+ BOOST_REQUIRE_MESSAGE( suite,"Could not find suite");
+ // Note: we ONLY* need MockSuiteChangedServer, when we make changes via functions and not commands
+
+ std::vector<limit_ptr> theLimits = suite->limits();
+ BOOST_REQUIRE_MESSAGE( !theLimits.empty(),"The limit are empty on suite s0 " << defs);
+ BOOST_FOREACH(limit_ptr l, theLimits) {
+ //std::cout << "found " << l->toString() << "\n";
+ TestHelper::invokeRequest(defs.get(),Cmd_ptr( new AlterCmd(suite->absNodePath(),AlterCmd::LIMIT_MAX,l->name(),"90")));
+ limit_ptr v = suite->find_limit(l->name());
+ BOOST_CHECK_MESSAGE( v.get() && v->theLimit() == 90, "expected to find limit with max value of 90");
+ }
+ return true;
+}
+
+static bool s0_change_limit_value(defs_ptr defs) {
+ suite_ptr suite = defs->findSuite("s0");
+ BOOST_REQUIRE_MESSAGE( suite,"Could not find suite");
+ // Note: we ONLY* need MockSuiteChangedServer, when we make changes via functions and not commands
+
+ std::vector<limit_ptr> theLimits = suite->limits();
+ BOOST_FOREACH(limit_ptr l, theLimits) {
+ TestHelper::invokeRequest(defs.get(),Cmd_ptr( new AlterCmd(suite->absNodePath(),AlterCmd::LIMIT_VAL,l->name(),"33")));
+ limit_ptr v = suite->find_limit(l->name());
+ BOOST_CHECK_MESSAGE( v.get() && v->value() == 33, "expected to find limit with value of 33");
+ }
+ return true;
+}
+
+static bool s0_update_repeat(defs_ptr defs) {
+
+ suite_ptr suite = defs->findSuite("s0");
+ BOOST_REQUIRE_MESSAGE( suite,"Could not find suite");
+ MockSuiteChangedServer mockServer(suite); // Increment suite state/modify change number
+
+
+ SuiteChanged1 changed(suite.get());
+ suite->increment_repeat();
+ return true;
+}
+
+// ===============================================
+
+BOOST_AUTO_TEST_CASE( test_ssync_using_handle )
+{
+ cout << "Base:: ...test_ssync_using_handle\n";
+
+ // =======================================================================================
+ // Note: where we update Suite::modify_change_no() we should *EXPECT* a full sync
+ // =======================================================================================
+
+ // test_sync_scaffold will created 5 suites s0,s1,s2,s3,s4,s5 and add suites s0 & s4 to a handle
+ // The following test will perform changes in/out of handles
+
+ { // Change defs state in the presence of handles. These should sync regardless of handles
+ // The default server state is HALTED, hence setting to halted will not show a change
+ test_sync_scaffold(set_server_state_shutdown,"set_server_state_shutdown");
+ test_sync_scaffold(set_server_state_running,"set_server_state_running");
+
+ test_sync_scaffold(add_server_variable,"add_server_variable");
+ test_sync_scaffold(change_server_variable,"change_server_variable");
+
+ test_sync_scaffold(set_defs_state,"set_defs_state");
+ test_sync_scaffold(set_defs_state_2,"set_defs_state_2",true /* expect a full sync */);
+ }
+
+ test_sync_scaffold(change_suites_s3_outside_of_handle,"change_suites_s3_outside_of_handle");
+ test_sync_scaffold(change_suites_s3_outside_of_handle_add_variable,"change_suites_s3_outside_of_handle_add_variable");
+ test_sync_scaffold(add_task_to_suite_s3,"add_task_to_suite_s3");
+ test_sync_scaffold(delete_task_on_suite_s3,"delete_task_on_suite_s3");
+ test_sync_scaffold(delete_family_on_suite_s3,"delete_family_on_suite_s3");
+
+ test_sync_scaffold(change_order_of_s4_top,"change_order_of_s4_top"); // change order is an incremental sync
+ test_sync_scaffold(change_order_of_s4_bottom,"change_order_of_s4_bottom"); // change order is an incremental sync
+
+ test_sync_scaffold(change_state_of_s4,"change_state_of_s4");
+ test_sync_scaffold(add_variable_to_suite_s4,"add_variable_to_suite_s4");
+ test_sync_scaffold(add_server_user_variables,"add_server_user_variables");
+ test_sync_scaffold(add_task_to_suite_s4,"add_task_to_suite_s4");
+ test_sync_scaffold(delete_task_on_suite_s4,"delete_task_on_suite_s4");
+ test_sync_scaffold(delete_family_on_suite_s4,"delete_family_on_suite_s4");
+ test_sync_scaffold(delete_suite_s4,"delete_suite_s4", true /* expect a full sync */);
+
+
+ test_sync_scaffold(s0_delete_some_attributes,"s0_delete_some_attributes");
+ test_sync_scaffold(s0_add_some_attributes,"s0_add_some_attributes");
+ test_sync_scaffold(s0_add_alias,"s0_add_alias");
+ test_sync_scaffold(s0_update_repeat,"s0_update_repeat");
+ test_sync_scaffold(s0_change_limit_max,"s0_change_limit_max");
+ test_sync_scaffold(s0_change_limit_value,"s0_change_limit_value");
+ test_sync_scaffold(s0_begin,"s0_begin", true/* expect a full sync */);
+
+ test_sync_scaffold(s0_remove_all_tasks,"s0_remove_all_tasks" );
+ test_sync_scaffold(s0_remove_a_family,"s0_remove_a_family");
+
+ test_sync_scaffold(s0_change_clock_gain,"s0_change_clock_gain", true/* expect a full sync */);
+ test_sync_scaffold(s0_change_clock_type_to_real,"s0_change_clock_type_to_real", true/* expect a full sync */);
+ test_sync_scaffold(s0_change_clock_date,"s0_change_clock_date", true/* expect a full sync */);
+ test_sync_scaffold(s0_change_clock_sync,"s0_change_clock_sync", true/* expect a full sync */);
+}
+
+
+
+static defs_ptr create_the_server_defs()
+{
+ defs_ptr defs = create_server_defs();
+ std::vector<suite_ptr> suite_vec = defs->suiteVec();
+ for(size_t j = 0; j < suite_vec.size(); j++) {
+ suite_vec[j]->set_state_change_no(j);
+ suite_vec[j]->set_modify_change_no(j);
+ }
+ return defs;
+}
+
+BOOST_AUTO_TEST_CASE( test_ssync_full_sync_using_handle )
+{
+ /// This test checks that when user has registered with all the suites.
+ /// Syncing should use the global change numbers
+ /// **ADDITIONALLY* the newsCmd must reflect this.
+ /// This is handled in ClientSuites::create_defs, in that we *MUST* update the
+ /// local change numbers to be the same as the global change numbers
+ /// This is important since the NewsCmd must be in *SYNC* with SYNCCmd
+
+ cout << "Base:: ...test_ssync_full_sync_using_handle\n";
+ // Create the server defs with some changes, in state & modify numbers
+ defs_ptr server_defs = create_the_server_defs();
+
+ // Create Client defs, without any changes
+ ServerReply server_reply;
+ server_reply.set_client_defs( create_client_defs(Defs::create()) );
+
+ // Server & client should be the same, since we ignore change numbers in the comparison
+ Ecf::set_debug_equality(true); // only has affect in DEBUG build
+ BOOST_CHECK_MESSAGE( *server_defs == *server_reply.client_defs(), "Starting point client and server defs should be the same"
+ << "SERVER\n" << server_defs
+ << "CLIENT\n" << server_reply.client_defs());
+ Ecf::set_debug_equality(false);
+
+ /// register interest in **ALL** the suites
+ std::vector<std::string> suite_names;
+ suite_names.push_back("s0");
+ suite_names.push_back("s1");
+ suite_names.push_back("s2");
+ suite_names.push_back("s3");
+ suite_names.push_back("s4");
+ TestHelper::invokeRequest(server_defs.get(),Cmd_ptr( new ClientHandleCmd(suite_names,false)),bypass_state_modify_change_check);
+
+ /// make sure handle created.
+ BOOST_CHECK_MESSAGE(server_defs->client_suite_mgr().clientSuites().size() == 1,"Expected 1 Client suites but found " <<server_defs->client_suite_mgr().clientSuites().size());
+ unsigned int client_handle = server_defs->client_suite_mgr().clientSuites().front().handle();
+ BOOST_CHECK_MESSAGE( client_handle == 1,"" );
+
+ // make sure server suites have different state/modify numbers from the client
+ {
+ unsigned int server_state_change_no = 0;
+ unsigned int server_modify_change_no = 0;
+ server_defs->client_suite_mgr().max_change_no(client_handle,server_state_change_no, server_modify_change_no);
+ BOOST_CHECK_MESSAGE(server_state_change_no == 4,"" );
+ BOOST_CHECK_MESSAGE(server_modify_change_no == 4,"" );
+
+ // *MAKE* sure global change numbers are different to handle suite change numbers
+ // This is the key part of this test.
+ // Since syncing should transfer these change numbers to the client
+ Ecf::set_state_change_no(server_state_change_no+10);
+ Ecf::set_modify_change_no(server_modify_change_no+20);
+ }
+
+ // Now sync from server
+ Ecf::set_server(true);
+ MockServer mock_server(server_defs);
+ /* server side */ SNewsCmd news_cmd(client_handle, server_reply.client_defs()->state_change_no(), server_reply.client_defs()->modify_change_no(), &mock_server );
+ /* server side */ SSyncCmd cmd(client_handle, server_reply.client_defs()->state_change_no(), server_reply.client_defs()->modify_change_no(), &mock_server );
+ Ecf::set_server(false);
+
+ // make sure SSyncCmd updated the server change numbers, to use global change numbers
+ unsigned int server_state_change_no = 0;
+ unsigned int server_modify_change_no = 0;
+ {
+ server_defs->client_suite_mgr().max_change_no(client_handle,server_state_change_no, server_modify_change_no);
+ BOOST_CHECK_MESSAGE(server_state_change_no == 14,"" );
+ BOOST_CHECK_MESSAGE(server_modify_change_no == 24,"" );
+ }
+
+ // SYNC the client, via do_sync( this should transfer change numbers to the client )
+ BOOST_CHECK_MESSAGE( news_cmd.get_news(), "Expected server to change");
+ BOOST_CHECK_MESSAGE( cmd.do_sync( server_reply ), "Expected server to change");
+ BOOST_CHECK_MESSAGE( server_reply.in_sync(), "Expected server to change");
+ BOOST_CHECK_MESSAGE( server_defs->state() == server_reply.client_defs()->state(),"Expected server State(" << NState::toString(server_defs->state()) << ") to be same as client state(" << NState::toString(server_reply.client_defs()->state()) << ")");
+
+ // After do_sync client and server change number should be in sync
+ BOOST_CHECK_MESSAGE(server_reply.client_defs()->state_change_no() == server_state_change_no,"Expected " << server_reply.client_defs()->state_change_no() << " state change number but found " << server_state_change_no);
+ BOOST_CHECK_MESSAGE(server_reply.client_defs()->modify_change_no() == server_modify_change_no,"Expected " << server_reply.client_defs()->modify_change_no() << " modify change number but found " << server_modify_change_no);
+
+ // Do final sync, there should not be ANY changes
+ Ecf::set_server(true);
+ /* server side */ SNewsCmd news_cmd1(client_handle, server_reply.client_defs()->state_change_no(), server_reply.client_defs()->modify_change_no(), &mock_server );
+ /* server side */ SSyncCmd cmd1(client_handle, server_reply.client_defs()->state_change_no(), server_reply.client_defs()->modify_change_no(), &mock_server );
+ Ecf::set_server(false);
+ /* client side */ BOOST_CHECK_MESSAGE( !news_cmd1.get_news(), "Expected no changes to client, we should be in sync");
+ /* client side */ BOOST_CHECK_MESSAGE( !cmd1.do_sync( server_reply ), "Expected no changes to client, we should be in sync");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/CMAKE_failed_tests.txt b/CMAKE_failed_tests.txt
similarity index 100%
rename from ecflow_4_0_7/CMAKE_failed_tests.txt
rename to CMAKE_failed_tests.txt
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..60f23d7
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,285 @@
+############################################################################################
+# cmake options:
+#
+# -DCMAKE_BUILD_TYPE=Debug|RelWithDebInfo|Release|Production
+# -DCMAKE_INSTALL_PREFIX=/path/to/install
+#
+# -DCMAKE_MODULE_PATH=/path/to/ecbuild/cmake
+#
+# -DCMAKE_C_COMPILER=gcc
+# -DCMAKE_CXX_COMPILER=g++
+#
+# -DCMAKE_PREFIX_PATH=/path/to/jasper:/path/to/any/package/out/of/place
+# -DBUILD_SHARED_LIBS=OFF
+# =========================================================================================
+# Usage instructions:
+#
+# cd $WK
+# release=$(cat VERSION.cmake | grep 'set( ECFLOW_RELEASE' | awk '{print $3}'| sed 's/["]//g')
+# major=$(cat VERSION.cmake | grep 'set( ECFLOW_MAJOR' | awk '{print $3}'| sed 's/["]//g')
+# minor=$(cat VERSION.cmake | grep 'set( ECFLOW_MINOR' | awk '{print $3}'| sed 's/["]//g')
+#
+##############################################################################
+
+cmake_minimum_required( VERSION 2.8.11 FATAL_ERROR )
+
+# ===========================================================================
+# Change the default if NO CMAKE_BUILD_TYPE specified
+if (NOT DEFINED CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE Release CACHE STRING "Build Configuration type" FORCE)
+endif()
+
+
+project( ecflow CXX )
+
+set( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../ecbuild/cmake")
+# message( STATUS "CMAKE_MODULE_PATH : ${CMAKE_MODULE_PATH}")
+
+include( ecbuild_system )
+
+ecbuild_requires_macro_version( 1.6 )
+
+
+###############################################################################
+# local project
+
+ecbuild_declare_project()
+
+# =========================================================================================
+# VERSION
+# Get the ecflow version specified in 'VERSION.cmake'. This is only accessible after ecbuild_declare_project()
+# The ecflow version config is done in ACore directory
+# =========================================================================================
+
+message( STATUS "CMAKE_INSTALL_PREFIX : ${CMAKE_INSTALL_PREFIX}" )
+message( STATUS "ECFLOW_RELEASE : ${ECFLOW_RELEASE}" )
+message( STATUS "ECFLOW_MAJOR : ${ECFLOW_MAJOR}" )
+message( STATUS "ECFLOW_MINOR : ${ECFLOW_MINOR}" )
+message( STATUS "ECFLOW_VERSION : ${ECFLOW_VERSION_STR}" )
+
+# =========================================================================================
+# Options , be aware of caching, when modifying on the command line.
+# Ideally start fresh or remove cache CmakeCache.txt in build dir
+# =========================================================================================
+option( ENABLE_PYTHON "enable python interface" ON )
+option( ENABLE_UI "Build ecFlowUI" ON )
+option( ENABLE_GUI "Build ecflowview" ON )
+option( ENABLE_ALL_TESTS "This includes performance/migration/regression tests" OFF )
+option( ENABLE_UI_BACKTRACE "Print a UI debug backtrace" OFF )
+
+
+
+# =========================================================================================
+# Qt for ecFlowUI.
+# Algorithm: we test for Qt5 - if it's there, then use it; otherwise look for Qt4.
+# if we don't find that, then we cannot build ecFlowUI.
+# =========================================================================================
+
+if(ENABLE_UI)
+
+ ecbuild_info("ecFlowUI is enabled - searching for Qt5; if not found, will try Qt4")
+
+ find_package(Qt5Widgets 5.0.0)
+ find_package(Qt5Gui 5.0.0)
+ find_package(Qt5Network 5.0.0)
+
+ if (Qt5Widgets_FOUND AND Qt5Gui_FOUND AND Qt5Network_FOUND)
+ ecbuild_info("Qt5 version ${Qt5Widgets_VERSION_STRING} was found")
+ set(ECFLOW_QT_INCLUDE_DIR ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Gui_INCLUDE_DIR} ${Qt5Network_INCLUDE_DIR})
+ set(ECFLOW_QT_LIBRARIES ${Qt5Widgets_LIBRARIES} ${Qt5Gui_LIBRARIES} ${Qt5Network_LIBRARIES})
+ set(ECFLOW_QT5 1)
+ add_definitions(-DECFLOW_QT5)
+ else()
+ ecbuild_info("Could not find all required Qt5 packages - searching for Qt4")
+
+ find_package(Qt4 4.8.0 REQUIRED QtCore QtGui QtNetwork)
+ if(QT_FOUND)
+ ecbuild_info("Found Qt 4, please ignore any warnings about Qt5 components that were not found.")
+ else()
+ ecbuild_critical("Qt5 and Qt4 not found - one of these is required for ecFlowUI; or use -DENABLE_UI=OFF")
+ endif()
+ endif()
+
+ set(ECFLOW_QT 1)
+ add_definitions(-DQT_NO_KEYWORDS) # We need to disable keywords because there is a problem in using Qt and boost together.
+
+endif()
+
+
+
+# sanity check - cannot set ENABLE_UI_BACKTRACE if UI is OFF
+if(ENABLE_UI_BACKTRACE AND (NOT ENABLE_UI))
+ message(WARNING "Cannot ENABLE_UI_BACKTRACE if UI is not enabled")
+ set(ENABLE_UI_BACKTRACE OFF)
+endif()
+
+# sanity check - cannot set UI_BACKTRACE_EMAIL_ADDRESSES if UI and ENABLE_UI_BACKTRACE are OFF
+if(UI_BACKTRACE_EMAIL_ADDRESSES AND (NOT ENABLE_UI))
+ message(WARNING "Cannot set UI_BACKTRACE_EMAIL_ADDRESSES if UI is not enabled")
+ set(UI_BACKTRACE_EMAIL_ADDRESSES)
+endif()
+
+
+message( STATUS "ENABLE_PYTHON : ${ENABLE_PYTHON}" )
+message( STATUS "ENABLE_GUI : ${ENABLE_GUI}" )
+message( STATUS "ENABLE_UI : ${ENABLE_UI}" )
+message( STATUS "ENABLE_ALL_TESTS : ${ENABLE_ALL_TESTS}" )
+
+if (ENABLE_UI)
+ message( STATUS "ENABLE_UI_BACKTRACE : ${ENABLE_UI_BACKTRACE}" )
+ if(UI_BACKTRACE_EMAIL_ADDRESSES)
+ message( STATUS "UI_BACKTRACE_EMAIL_ADDRESSES : ${UI_BACKTRACE_EMAIL_ADDRESSES}" )
+ endif()
+endif()
+
+# ======================================================================================
+# GUI requires X11 and Motif
+# ======================================================================================
+
+if(ENABLE_GUI)
+ find_package( X11 )
+# if ( X11_FOUND )
+# debug_var( X11_INCLUDE_DIR )
+# debug_var( X11_LIBRARIES )
+# debug_var( X11_Xt_INCLUDE_PATH )
+# debug_var( X11_Xt_LIB )
+# debug_var( X11_Xpm_INCLUDE_PATH )
+# debug_var( X11_Xpm_LIB )
+# endif()
+
+ find_package( Motif )
+# if ( MOTIF_FOUND )
+# debug_var( MOTIF_INCLUDE_DIR )
+# debug_var( MOTIF_LIBRARIES )
+# endif()
+endif()
+
+# =========================================================================================
+# Boost
+# =========================================================================================
+
+ecbuild_add_extra_search_paths( boost ) # also respects BOOST_ROOT
+
+# Ecflow test require statics libs for boost < 1.59, otherwise get double free error.
+# To use static boost python ensure that Boost_USE_STATIC_LIBS is set on.
+# See: http://www.cmake.org/cmake/help/v3.0/module/FindBoost.html
+set(Boost_USE_STATIC_LIBS ON)
+set(Boost_USE_MULTITHREADED ON)
+set(Boost_NO_SYSTEM_PATHS ON)
+set(Boost_DETAILED_FAILURE_MSG ON)
+#set(Boost_DEBUG ON)
+
+find_package( Boost 1.53.0 REQUIRED COMPONENTS python serialization system thread unit_test_framework test_exec_monitor filesystem program_options date_time regex)
+
+# Available boost lib should be referenced as:
+#
+# ${Boost_SYSTEM_LIBRARY}
+# ${Boost_SERIALIZATION_LIBRARY}
+# ${Boost_THREAD_LIBRARY}
+# ${Boost_FILESYSTEM_LIBRARY}
+# ${Boost_PROGRAM_OPTIONS_LIBRARY}
+# ${Boost_DATE_TIME_LIBRARY}
+#
+# ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}
+# ${Boost_TEST_EXEC_MONITOR_LIBRARY}
+
+
+#message( STATUS "Boost_LIBRARIES : ${Boost_LIBRARIES}" )
+
+
+
+# =========================================================================================
+# Qt
+# =========================================================================================
+
+
+
+# =========================================================================================
+# debug
+# =========================================================================================
+
+if( CMAKE_BUILD_TYPE MATCHES "[Dd][Ee][Bb][Uu][Gg]" )
+
+ message( STATUS "INFO: DEBUG BUILD" )
+
+ # Tell C/C++ that we're doing a debug build
+ add_definitions( -DDEBUG )
+
+endif()
+
+# =========================================================================================
+# build source code
+# =========================================================================================
+
+add_subdirectory( ACore )
+add_subdirectory( ANattr )
+add_subdirectory( ANode )
+add_subdirectory( AParser )
+add_subdirectory( Base )
+add_subdirectory( Client )
+add_subdirectory( CSim )
+add_subdirectory( Server )
+add_subdirectory( Test )
+
+if (ENABLE_PYTHON)
+ ecbuild_find_python( VERSION 2.7 REQUIRED )
+ #debug_var(PYTHON_LIBRARIES)
+ #debug_var(PYTHON_INCLUDE_DIR)
+ add_subdirectory( Pyext )
+endif()
+
+if(ENABLE_UI)
+ add_subdirectory( Viewer )
+ add_subdirectory( share )
+endif()
+
+if( ENABLE_GUI AND X11_FOUND AND MOTIF_FOUND )
+ add_subdirectory( view )
+endif()
+
+# =========================================================================================
+# tar ball, by default ecbuild will tar everything apart from hard wired directory called 'build'
+# hence we can tell it, what directories not to pack
+# =========================================================================================
+
+ecbuild_dont_pack( DIRS
+ ACore/doc ANattr/doc ANode/doc Client/doc Pyext/doc Server/doc
+ ecbuild
+ SCRATCH
+ CUSTOMER
+ build_scripts/nightly build_scripts/test_bench
+ Doc/func_spec Doc/misc Doc/New_viewer Doc/newsletter Doc/online Doc/presentations Doc/tac
+)
+
+
+# =========================================================================================
+# install scripts
+# =========================================================================================
+
+install( FILES
+ ${CMAKE_SOURCE_DIR}/tools/ecflow_logsvr.pl
+ ${CMAKE_SOURCE_DIR}/tools/ecflow_logsvr.sh
+ ${CMAKE_SOURCE_DIR}/tools/ecflow_start.sh
+ ${CMAKE_SOURCE_DIR}/tools/ecflow_stop.sh
+ ${CMAKE_SOURCE_DIR}/tools/noconnect.sh
+ ${CMAKE_SOURCE_DIR}/Pyext/migrate/ecflow_migrate.py
+ DESTINATION bin
+ PERMISSIONS OWNER_READ GROUP_READ WORLD_READ OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE
+)
+
+# install documentation
+install (FILES
+ ${CMAKE_SOURCE_DIR}/Doc/user-manual/client_options.docx
+ DESTINATION doc/ecflow
+ PERMISSIONS OWNER_READ GROUP_READ WORLD_READ OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE
+)
+
+# =========================================================================================
+# final
+# =========================================================================================
+
+# prepares a tar.gz of your sources and/or binaries
+ecbuild_install_project( NAME ecFlow )
+
+# print the summary of the configuration
+ecbuild_print_summary()
diff --git a/ecflow_4_0_7/COPYING b/COPYING
similarity index 100%
rename from ecflow_4_0_7/COPYING
rename to COPYING
diff --git a/CSim/CMakeLists.txt b/CSim/CMakeLists.txt
new file mode 100644
index 0000000..8e50557
--- /dev/null
+++ b/CSim/CMakeLists.txt
@@ -0,0 +1,53 @@
+list( APPEND srcs
+ src/Analyser.cpp
+ src/AstAnalyserVisitor.cpp
+ src/DefsAnalyserVisitor.cpp
+ src/FlatAnalyserVisitor.cpp
+ src/Simulator.cpp
+ src/SimulatorVisitor.cpp
+)
+ecbuild_add_library( TARGET libsimu
+ NOINSTALL
+ TYPE STATIC
+ SOURCES ${srcs}
+ LIBS libparser node nodeattr core
+ INCLUDES src
+ ../ACore/src
+ ../ANattr/src
+ ../ANode/src
+ ../AParser/src
+ ../Base/src
+ )
+
+
+list( APPEND test_srcs
+ test/TestMeter.cpp
+ test/TestTime.cpp
+ test/TestUtil.cpp
+ test/TestSimulator.cpp
+ test/TestAutoCancel.cpp
+ test/TestRepeat.cpp
+ test/TestToday.cpp
+ test/TestAnalysis.cpp
+)
+ecbuild_add_test( TARGET c_csim
+ BOOST
+ SOURCES ${test_srcs}
+ LIBS libsimu
+ pthread
+ INCLUDES ../ANode/test
+ TEST_DEPENDS u_base
+ )
+
+if (ENABLE_ALL_TESTS)
+
+ ecbuild_add_test( TARGET c_csim_single
+ BOOST
+ SOURCES test/TestSingleSimulator.cpp test/TestUtil.cpp
+ LIBS libsimu
+ pthread
+ INCLUDES ../ANode/test
+ TEST_DEPENDS u_base
+ )
+endif()
+
\ No newline at end of file
diff --git a/CSim/jamfile.jam b/CSim/jamfile.jam
new file mode 100644
index 0000000..27e40ca
--- /dev/null
+++ b/CSim/jamfile.jam
@@ -0,0 +1,95 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+#
+# Simulator. Standalone exe that can:
+# 1/ Check structure of the definition file
+# 2/ Simulate the definition
+# allow checking for dead locks, etc
+project theSimulator ;
+
+#
+# IMPORTANT: Simulator *MUST* not link with server or any of its source code
+#
+use-project theCore : ../ACore ;
+use-project theNodeAttr : ../ANattr ;
+use-project theNode : ../ANode ;
+use-project theParser : ../AParser ;
+use-project theBase : ../Base ;
+
+lib pthread ;
+
+#
+# Split into library, so that testing can use library, and hence same compiler option
+#
+# The <include> means we will automatically add this directory to the include path
+# of any other target that uses this lib
+#
+lib libsimu : [ glob src/*.cpp ]
+ : <include>../ACore/src
+ <include>../ANattr/src
+ <include>../ANode/src
+ <include>../AParser/src
+ <include>../Base/src
+ <variant>debug:<define>DEBUG
+ <link>static
+ <use>/theCore//core
+ <use>/theNodeAttr//nodeattr
+ <use>/theNode//node
+ <use>/theBase//base
+ <use>/theParser//libparser
+ <use>/site-config//boost_system
+ <use>/site-config//boost_serialization
+ <use>/site-config//boost_filesystem
+ <use>/site-config//boost_program_options
+ <use>/site-config//boost_datetime
+ :
+ : <include>../CSim/src
+ ;
+
+
+#
+# Test for simulator
+# IMPORTANT: server *MUST* not link with client or include any of the client code
+#
+exe c_csim : [ glob test/*.cpp : test/TestSingleSimulator.cpp ]
+ pthread
+ /theCore//core
+ /theNodeAttr//nodeattr
+ /theNode//node
+ /theParser//libparser
+ /theBase//base
+ libsimu
+ /site-config//boost_system
+ /site-config//boost_serialization
+ /site-config//boost_filesystem
+ /site-config//boost_datetime
+ /site-config//boost_program_options
+ /site-config//boost_test
+ : <variant>debug:<define>DEBUG
+ ;
+
+#
+# Test for single simulator. Use for developing the tests
+# IMPORTANT: server *MUST* not link with client or include any of the client code
+#
+exe c_csim_single : [ glob test/TestSingleSimulator.cpp test/TestUtil.cpp ]
+ pthread
+ /theCore//core
+ /theNodeAttr//nodeattr
+ /theNode//node
+ /theParser//libparser
+ /theBase//base
+ libsimu
+ /site-config//boost_system
+ /site-config//boost_serialization
+ /site-config//boost_filesystem
+ /site-config//boost_datetime
+ /site-config//boost_program_options
+ /site-config//boost_test
+ : <variant>debug:<define>DEBUG
+ ;
diff --git a/CSim/src/Analyser.cpp b/CSim/src/Analyser.cpp
new file mode 100644
index 0000000..244a565
--- /dev/null
+++ b/CSim/src/Analyser.cpp
@@ -0,0 +1,57 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "Analyser.hpp"
+#include "DefsAnalyserVisitor.hpp"
+#include "FlatAnalyserVisitor.hpp"
+#include "Defs.hpp"
+#include "File.hpp"
+#include <iostream>
+#include <fstream>
+
+using namespace std;
+
+namespace ecf {
+
+Analyser::Analyser() {}
+
+void Analyser::run(Defs& theDefs)
+{
+ // Run flat analysis
+ {
+ FlatAnalyserVisitor visitor;
+ theDefs.acceptVisitTraversor(visitor);
+
+ std::string fileName = "defs.flat";
+
+ std::ofstream file(fileName.c_str());
+ file << visitor.report();
+ }
+
+ // run depth first analysis
+ {
+ DefsAnalyserVisitor visitor;
+ theDefs.acceptVisitTraversor(visitor);
+
+ std::string fileName = "defs.depth";
+
+ std::ofstream file(fileName.c_str(),ios::out);
+ file << visitor.report();
+ file.close();
+ }
+}
+
+}
+
diff --git a/CSim/src/Analyser.hpp b/CSim/src/Analyser.hpp
new file mode 100644
index 0000000..4f4d02c
--- /dev/null
+++ b/CSim/src/Analyser.hpp
@@ -0,0 +1,31 @@
+#ifndef ANALYSER_HPP_
+#define ANALYSER_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+class Defs;
+
+namespace ecf {
+
+class Analyser {
+public:
+ Analyser();
+
+ static void run(Defs& theDefs);
+};
+
+}
+#endif
diff --git a/CSim/src/AstAnalyserVisitor.cpp b/CSim/src/AstAnalyserVisitor.cpp
new file mode 100644
index 0000000..ea72164
--- /dev/null
+++ b/CSim/src/AstAnalyserVisitor.cpp
@@ -0,0 +1,58 @@
+ //============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "AstAnalyserVisitor.hpp"
+#include "ExprAst.hpp"
+#include "Defs.hpp"
+
+using namespace std;
+
+namespace ecf {
+
+AstAnalyserVisitor::AstAnalyserVisitor() {}
+AstAnalyserVisitor::~AstAnalyserVisitor() {}
+
+void AstAnalyserVisitor::visitTop(AstTop*) {}
+void AstAnalyserVisitor::visitRoot(AstRoot*) {}
+void AstAnalyserVisitor::visitAnd(AstAnd*) {}
+void AstAnalyserVisitor::visitNot(AstNot*) {}
+void AstAnalyserVisitor::visitPlus(AstPlus*) {}
+void AstAnalyserVisitor::visitMinus(AstMinus*) {}
+void AstAnalyserVisitor::visitDivide(AstDivide*) {}
+void AstAnalyserVisitor::visitMultiply(AstMultiply*) {}
+void AstAnalyserVisitor::visitModulo(AstModulo*) {}
+void AstAnalyserVisitor::visitOr(AstOr*) {}
+void AstAnalyserVisitor::visitEqual(AstEqual*) {}
+void AstAnalyserVisitor::visitNotEqual(AstNotEqual*) {}
+void AstAnalyserVisitor::visitLessEqual(AstLessEqual*) {}
+void AstAnalyserVisitor::visitGreaterEqual(AstGreaterEqual*) {}
+void AstAnalyserVisitor::visitGreaterThan(AstGreaterThan*) {}
+void AstAnalyserVisitor::visitLessThan(AstLessThan*) {}
+void AstAnalyserVisitor::visitLeaf(AstLeaf*) {}
+void AstAnalyserVisitor::visitInteger(AstInteger*) {}
+void AstAnalyserVisitor::visitString(AstString*) {}
+void AstAnalyserVisitor::visitNodeState(AstNodeState*) {}
+void AstAnalyserVisitor::visitEventState(AstEventState*) {}
+
+void AstAnalyserVisitor::visitNode(AstNode* astNode)
+{
+ Node* refNode = astNode->referencedNode();
+ if ( refNode ) dependentNodes_.insert( refNode);
+ else dependentNodePaths_.insert(astNode->nodePath());
+}
+
+void AstAnalyserVisitor::visitVariable(AstVariable* astVar){}
+
+}
diff --git a/CSim/src/AstAnalyserVisitor.hpp b/CSim/src/AstAnalyserVisitor.hpp
new file mode 100644
index 0000000..2a09933
--- /dev/null
+++ b/CSim/src/AstAnalyserVisitor.hpp
@@ -0,0 +1,64 @@
+#ifndef ASTANALYSERVISITOR_HPP_
+#define ASTANALYSERVISITOR_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "ExprAstVisitor.hpp"
+#include <iostream>
+#include <sstream>
+#include <set>
+class Node;
+
+namespace ecf {
+
+class AstAnalyserVisitor : public ExprAstVisitor {
+public:
+ AstAnalyserVisitor();
+ virtual ~AstAnalyserVisitor();
+
+ const std::set<Node*>& dependentNodes() const { return dependentNodes_;}
+ const std::set<std::string>& dependentNodePaths() const { return dependentNodePaths_;}
+
+ virtual void visitTop(AstTop*);
+ virtual void visitRoot(AstRoot*);
+ virtual void visitAnd(AstAnd*);
+ virtual void visitNot(AstNot*);
+ virtual void visitPlus(AstPlus*);
+ virtual void visitMinus(AstMinus*);
+ virtual void visitDivide(AstDivide*);
+ virtual void visitMultiply(AstMultiply*);
+ virtual void visitModulo(AstModulo*);
+ virtual void visitOr(AstOr*);
+ virtual void visitEqual(AstEqual*);
+ virtual void visitNotEqual(AstNotEqual*);
+ virtual void visitLessEqual(AstLessEqual*);
+ virtual void visitGreaterEqual(AstGreaterEqual*);
+ virtual void visitGreaterThan(AstGreaterThan*);
+ virtual void visitLessThan(AstLessThan*);
+ virtual void visitLeaf(AstLeaf*);
+ virtual void visitInteger(AstInteger*);
+ virtual void visitString(AstString*);
+ virtual void visitNodeState(AstNodeState*);
+ virtual void visitEventState(AstEventState*);
+ virtual void visitNode(AstNode*);
+ virtual void visitVariable(AstVariable*);
+
+private:
+ std::set<Node*> dependentNodes_;
+ std::set<std::string> dependentNodePaths_;
+};
+}
+#endif
diff --git a/CSim/src/DefsAnalyserVisitor.cpp b/CSim/src/DefsAnalyserVisitor.cpp
new file mode 100644
index 0000000..3399cb8
--- /dev/null
+++ b/CSim/src/DefsAnalyserVisitor.cpp
@@ -0,0 +1,167 @@
+ //============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "DefsAnalyserVisitor.hpp"
+#include "AstAnalyserVisitor.hpp"
+#include "ExprAst.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "Indentor.hpp"
+#include "Str.hpp"
+
+using namespace std;
+
+namespace ecf {
+
+///////////////////////////////////////////////////////////////////////////////
+DefsAnalyserVisitor::DefsAnalyserVisitor() {}
+
+void DefsAnalyserVisitor::visitDefs( Defs* d) {
+ BOOST_FOREACH(suite_ptr s, d->suiteVec()) { s->acceptVisitTraversor(*this); }
+}
+
+void DefsAnalyserVisitor::visitSuite( Suite* s) { visitNodeContainer(s);}
+void DefsAnalyserVisitor::visitFamily( Family* f) { visitNodeContainer(f);}
+
+void DefsAnalyserVisitor::visitNodeContainer(NodeContainer* nc)
+{
+ std::set<Node*> dependentNodes;
+ analyse(nc,dependentNodes);
+
+ BOOST_FOREACH(node_ptr t, nc->nodeVec()) { t->acceptVisitTraversor(*this);}
+}
+
+void DefsAnalyserVisitor::visitTask( Task* t)
+{
+ std::set<Node*> dependentNodes;
+ analyse(t,dependentNodes);
+}
+
+void DefsAnalyserVisitor::analyse(Node* node,std::set<Node*>& dependentNodes, bool dependent)
+{
+ // ***************************************************************
+ // Do a depth first search to find the root cause of the blockage
+ // ***************************************************************
+//#ifdef DEBUG
+// if (dependent) {
+// ss_ << "DefsAnalyserVisitor::analyse " << node->debugType() << Str::COLON() << node->absNodePath();
+// ss_ << " state(" << NState::toString(node->state()) << ")\n";
+// }
+//#endif
+ if (analysedNodes_.find(node) != analysedNodes_.end()) return;
+ analysedNodes_.insert( node );
+ if (node->state() == NState::COMPLETE ) return;
+
+ if (node->state() == NState::QUEUED) {
+ std::vector<std::string> theReasonWhy;
+ node->why(theReasonWhy);
+ for(size_t i = 0; i < theReasonWhy.size(); ++i) {
+ Indentor::indent(ss_) << "Reason: " << theReasonWhy[i] << "\n";
+ }
+ }
+
+
+ /// Note a complete expression that does not evaluate, does *NOT* hold the node
+ /// It merly sets node to complete.
+ if ( node->completeAst() && !node->evaluateComplete()) {
+ // Follow nodes referenced in the complete expressions
+ analyseExpressions(node,dependentNodes,false,dependent);
+
+ // follow child nodes
+ NodeContainer* nc = dynamic_cast<NodeContainer*>(node);
+ if (nc) {
+ BOOST_FOREACH(node_ptr t, nc->nodeVec()) { t->acceptVisitTraversor(*this);}
+ }
+ }
+
+
+ if ( node->triggerAst() && !node->evaluateTrigger() ) {
+ // Follow nodes referenced in the trigger expressions
+ analyseExpressions(node,dependentNodes,true,dependent);
+
+ // follow child nodes
+ NodeContainer* nc = dynamic_cast<NodeContainer*>(node);
+ if (nc) {
+ BOOST_FOREACH(node_ptr t, nc->nodeVec()) { t->acceptVisitTraversor(*this);}
+ }
+ }
+}
+
+void DefsAnalyserVisitor::analyseExpressions(Node* node,std::set<Node*>& dependentNodes, bool trigger, bool dependent)
+{
+ Indentor in; Indentor::indent(ss_);
+ if ( dependent ) ss_ << "DEPENDENT ";
+ if (trigger) {
+ ss_ << node->debugNodePath() << " holding on trigger expression '" << node->triggerExpression() << "'\n";
+ }
+ else {
+ ss_ << node->debugNodePath() << " holding on complete expression '" << node->completeExpression() << "'\n";
+ }
+
+
+ AstAnalyserVisitor astVisitor;
+ if ( trigger ) {
+ node->triggerAst()->accept(astVisitor);
+ ss_ << *node->triggerAst();
+ }
+ else {
+ node->completeAst()->accept(astVisitor);
+ ss_ << *node->completeAst();
+ }
+
+ // Warn about NULL node references in the trigger expressions
+ BOOST_FOREACH(const string& nodePath, astVisitor.dependentNodePaths()) {
+ Indentor in; Indentor::indent(ss_) << "'" << nodePath << "' is not defined in the expression\n";
+ }
+
+ // **** NOTE: Currently for COMPLETE expression will only follow trigger expressions
+ BOOST_FOREACH(Node* triggerNode, astVisitor.dependentNodes()) {
+
+
+ Indentor in; Indentor::indent(ss_) << "EXPRESSION NODE " << triggerNode->debugNodePath();
+ ss_ << " state(" << NState::toString(triggerNode->state()) << ")";
+ if (triggerNode->triggerAst()) ss_ << " trigger(evaluation = " << triggerNode->evaluateTrigger() << "))";
+ if (analysedNodes_.find(triggerNode) != analysedNodes_.end()) ss_ << " analysed ";
+ if (dependentNodes.find(triggerNode) != dependentNodes.end()) ss_ << " ** ";
+ ss_ << "\n";
+
+ if ( dependentNodes.find(triggerNode) != dependentNodes.end()) {
+ // possible deadlock make sure
+ if (triggerNode->triggerAst()) {
+ AstAnalyserVisitor visitor;
+ triggerNode->triggerAst()->accept(visitor);
+
+// cerr << "Node = " << node->absNodePath() << "\n";
+// cerr << "triggerNode = " << triggerNode->absNodePath() << "\n";
+// BOOST_FOREACH(Node* n,visitor.dependentNodes() ) {
+// cerr << "triggerNode Node dependents = " << n->absNodePath() << "\n";
+// }
+
+ if (visitor.dependentNodes().find(node) != visitor.dependentNodes().end()) {
+ Indentor in; Indentor::indent(ss_) << "Deadlock detected between:\n";
+ Indentor in2; Indentor::indent(ss_) << node->debugNodePath() << "\n";
+ Indentor::indent(ss_) << triggerNode->debugNodePath() << "\n";
+ }
+ }
+ continue;
+ }
+ dependentNodes.insert( triggerNode );
+ analyse(triggerNode,dependentNodes,true);
+ }
+}
+
+}
diff --git a/CSim/src/DefsAnalyserVisitor.hpp b/CSim/src/DefsAnalyserVisitor.hpp
new file mode 100644
index 0000000..dad1c5c
--- /dev/null
+++ b/CSim/src/DefsAnalyserVisitor.hpp
@@ -0,0 +1,47 @@
+#ifndef DEFSANALYSERVISITOR_HPP_
+#define DEFSANALYSERVISITOR_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "NodeTreeVisitor.hpp"
+#include <sstream>
+#include <set>
+#include <vector>
+class Node;
+
+namespace ecf {
+
+class DefsAnalyserVisitor : public NodeTreeVisitor {
+public:
+ DefsAnalyserVisitor();
+ std::string report() const { return ss_.str();}
+
+ virtual bool traverseObjectStructureViaVisitors() const { return true;}
+ virtual void visitDefs(Defs*);
+ virtual void visitSuite(Suite*);
+ virtual void visitFamily(Family*);
+ virtual void visitNodeContainer(NodeContainer*);
+ virtual void visitTask(Task*);
+
+private:
+ void analyse(Node* n,std::set<Node*>& dependentNodes, bool dependent = false);
+ void analyseExpressions(Node* node,std::set<Node*>& dependentNodes, bool trigger, bool dependent);
+
+ std::stringstream ss_;
+ std::set<Node*> analysedNodes_; // The node we analysed
+};
+}
+#endif
diff --git a/CSim/src/FlatAnalyserVisitor.cpp b/CSim/src/FlatAnalyserVisitor.cpp
new file mode 100644
index 0000000..c366f5c
--- /dev/null
+++ b/CSim/src/FlatAnalyserVisitor.cpp
@@ -0,0 +1,111 @@
+ //============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "FlatAnalyserVisitor.hpp"
+#include "AstAnalyserVisitor.hpp"
+#include "ExprAst.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "Indentor.hpp"
+#include "Str.hpp"
+
+using namespace std;
+
+namespace ecf {
+
+///////////////////////////////////////////////////////////////////////////////
+FlatAnalyserVisitor::FlatAnalyserVisitor() {}
+
+void FlatAnalyserVisitor::visitDefs( Defs* d) {
+ BOOST_FOREACH(suite_ptr s, d->suiteVec()) { s->acceptVisitTraversor(*this); }
+}
+
+void FlatAnalyserVisitor::visitSuite( Suite* s) { visitNodeContainer(s);}
+void FlatAnalyserVisitor::visitFamily( Family* f) { visitNodeContainer(f);}
+
+void FlatAnalyserVisitor::visitNodeContainer(NodeContainer* nc)
+{
+ if (nc->state() == NState::COMPLETE ) return;
+
+ Indentor in;
+ bool traverseChildren = analyse(nc);
+
+ // Dont bother traversing children if parent is holding on trigger/complete expression
+ if (traverseChildren) {
+ BOOST_FOREACH(node_ptr t, nc->nodeVec()) { t->acceptVisitTraversor(*this);}
+ }
+}
+
+void FlatAnalyserVisitor::visitTask( Task* t)
+{
+ Indentor in;
+ analyse(t);
+}
+
+bool FlatAnalyserVisitor::analyse(Node* node)
+{
+ bool traverseChildren = true;
+
+ Indentor::indent(ss_) << node->debugType() << Str::COLON() << node->name() << " state(" << NState::toString(node->state()) << ")";
+ if (node->state() != NState::COMPLETE ) {
+
+ if (node->repeat().isInfinite()) {
+ ss_ << " may **NEVER** complete due to " << node->repeat().toString();
+ }
+ ss_ << "\n";
+
+ if (node->state() == NState::QUEUED) {
+ std::vector<std::string> theReasonWhy;
+ node->why(theReasonWhy);
+ for(size_t i = 0; i < theReasonWhy.size(); ++i) {
+ Indentor::indent(ss_) << "Reason: " << theReasonWhy[i] << "\n";
+ }
+ }
+
+ /// Note a complete expression that does not evaluate, does *NOT* hold the node
+ /// It merly sets node to complete.
+ if ( node->completeAst() && !node->evaluateComplete()) {
+ Indentor::indent(ss_) << "holding on complete expression '" << node->completeExpression() << "'\n";
+
+ AstAnalyserVisitor astVisitor;
+ node->completeAst()->accept(astVisitor);
+ BOOST_FOREACH(const string& nodePath, astVisitor.dependentNodePaths()) {
+ Indentor in; Indentor::indent(ss_) << "'" << nodePath << "' is not defined in the expression\n";
+ }
+ ss_ << *node->completeAst();
+
+ traverseChildren = false;
+ }
+
+ if ( node->triggerAst() && !node->evaluateTrigger() ) {
+ Indentor::indent(ss_) << "holding on trigger expression '" << node->triggerExpression() << "'\n";
+
+ AstAnalyserVisitor astVisitor;
+ node->triggerAst()->accept(astVisitor);
+ BOOST_FOREACH(const string& nodePath, astVisitor.dependentNodePaths()) {
+ Indentor in; Indentor::indent(ss_) << "'" << nodePath << "' is not defined in the expression\n";
+ }
+ ss_ << *node->triggerAst();
+
+ traverseChildren = false;
+ }
+ }
+ ss_ << "\n";
+ return traverseChildren;
+}
+
+}
diff --git a/CSim/src/FlatAnalyserVisitor.hpp b/CSim/src/FlatAnalyserVisitor.hpp
new file mode 100644
index 0000000..f35a935
--- /dev/null
+++ b/CSim/src/FlatAnalyserVisitor.hpp
@@ -0,0 +1,43 @@
+#ifndef FLATANALYSERVISITOR_HPP_
+#define FLATANALYSERVISITOR_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "NodeTreeVisitor.hpp"
+#include <sstream>
+class Node;
+
+namespace ecf {
+
+class FlatAnalyserVisitor : public NodeTreeVisitor {
+public:
+ FlatAnalyserVisitor();
+ std::string report() const { return ss_.str();}
+
+ virtual bool traverseObjectStructureViaVisitors() const { return true;}
+ virtual void visitDefs(Defs*);
+ virtual void visitSuite(Suite*);
+ virtual void visitFamily(Family*);
+ virtual void visitNodeContainer(NodeContainer*);
+ virtual void visitTask(Task*);
+
+private:
+ bool analyse(Node* n);
+ std::stringstream ss_;
+};
+
+}
+#endif
diff --git a/CSim/src/Simulator.cpp b/CSim/src/Simulator.cpp
new file mode 100644
index 0000000..aade656
--- /dev/null
+++ b/CSim/src/Simulator.cpp
@@ -0,0 +1,360 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/lexical_cast.hpp>
+#include <boost/date_time/posix_time/time_formatters.hpp> // requires boost date and time lib
+
+#include "Simulator.hpp"
+#include "Analyser.hpp"
+#include "SimulatorVisitor.hpp"
+#include "DefsStructureParser.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "Log.hpp"
+#include "JobsParam.hpp"
+#include "Jobs.hpp"
+#include "CalendarUpdateParams.hpp"
+#include "CmdContext.hpp"
+
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+//#define DEBUG_LONG_RUNNING_SUITES 1
+
+namespace ecf {
+
+/// Class that allows multiple log files.
+class LogDestroyer {
+public:
+ LogDestroyer() {}
+ ~LogDestroyer() { Log::destroy(); }
+};
+
+Simulator::Simulator(const boost::posix_time::time_duration& period)
+: max_simulation_period_(period),
+ truncateLongRepeatsTo_(0),
+ level_(0),
+ foundCrons_(false)
+{
+#ifdef DEBUG_LONG_RUNNING_SUITES
+ std::cout << "Simulator::Simulator max_simulation_period_ " << to_simple_string(max_simulation_period_) << endl;
+#endif
+}
+
+bool Simulator::run(Defs& theDefs, const std::string& defs_filename, std::string& errorMsg, bool do_checks) const
+{
+ CmdContext cmd_context;
+
+#ifdef DEBUG_LONG_RUNNING_SUITES
+ std::cout << "Simulator::run " << defs_filename << endl;
+#endif
+ // ****:NOTE:******
+ // ** This simulator relies on the defs checking to set event and meter usedInTrigger()
+ // ** to speed up simulator. However this is done in AstResolveVisitor.
+ // ** Which is called during checking:
+ // ** By default checking in done when reading a defs file from disk:
+ // ** However many test create Defs on the fly. These may not do_checks.
+ // ** Hence we do it here, since it is simulator specific.
+ if (do_checks) {
+ std::string warningMsg;
+ if (!theDefs.check(errorMsg,warningMsg)) {
+ return false;
+ }
+ }
+
+
+ // Allow new log to be created each time, by destroying the old log.
+ LogDestroyer destroyLog;
+
+ // Initialise the Log file, and destroy when done. This
+ // allows new log file to be created named after the definition file
+ std::string logFileName = defs_filename + ".log";
+ fs::remove(logFileName);
+ Log::create(logFileName);
+ //cout << "defs_filename " << defs_filename << "\n";
+ //cout << "***** after Log::create(logFileName)\n";
+
+ // Do the following:
+ // o call begin() for each suite
+ // o determine calendar increment. If no time dependencies use an hour increment
+ // o determine max simulation period. ie looks at size of repeats
+ // o If multiple suites and some suites have no tasks, mark them as complete, these may have server limits
+ // o If no tasks at all, no point in simulating
+ // **** Need a better mechanism of handling long repeats, the old way of changing repeat
+ // **** attributes is not acceptable.(i.e user could save in python after simulation
+ // **** and there defs would be corrupted
+ SimulatorVisitor simiVisitor(truncateLongRepeatsTo_ /* NOT USED */);
+ theDefs.acceptVisitTraversor(simiVisitor);
+ foundCrons_ = simiVisitor.foundCrons();
+
+ if (!simiVisitor.foundTasks()) {
+ errorMsg += "The defs file ";
+ errorMsg += defs_filename;
+ errorMsg += " has no tasks, can not simulate\n";
+ return false;
+ }
+
+ // Let visitor determine calendar increment. i.e if no time dependencies we will use 1 hour increment
+ // Default max_simulation_period_ is 1 year, however some operation suites run for many years
+ // Analyse the repeats to determine max simulation period
+ time_duration calendarIncrement = simiVisitor.calendarIncrement();
+ boost::posix_time::time_duration max_simulation_period = simiVisitor.maxSimulationPeriod();
+ if ( max_simulation_period > max_simulation_period_) max_simulation_period_ = max_simulation_period;
+
+#ifdef DEBUG_LONG_RUNNING_SUITES
+ cout << defs_filename << " time dependency = " << simiVisitor.hasTimeDependencies()
+ << " max_simulation_period_=" << to_simple_string(max_simulation_period_)
+ << " calendarIncrement=" << to_simple_string(calendarIncrement)
+ << endl;
+#endif
+
+ CalendarUpdateParams calUpdateParams( calendarIncrement );
+
+ // Start simulation ...
+ boost::posix_time::time_duration duration(0,0,0,0);
+ while (1) {
+
+// cout << "duration = " << to_simple_string(duration) << endl;
+
+ // Resolve dependencies and submit jobs
+ if (!doJobSubmission(theDefs,errorMsg)) return false;
+
+ // Determine termination criteria. If all suite complete, exit,
+ // Let simulation termination take autocancel into account. i.e we extend simulation even though
+ // suite may have completed, to allow autocancel to take effect.
+ // Hence if a suite has complete, but has autocancel we continue simulation
+ // Note: should also handle case of autocancel which remove all suites
+ size_t completeSuiteCnt = 0;
+ int hasAutoCancel = 0;
+ BOOST_FOREACH(suite_ptr s, theDefs.suiteVec()) {
+ if (s->state() == NState::COMPLETE) completeSuiteCnt++;
+ if (s->hasAutoCancel()) hasAutoCancel++;
+ }
+ if ( (theDefs.suiteVec().size() == completeSuiteCnt) && (hasAutoCancel == 0)) {
+ LOG(Log::MSG, "Simulation complete in " << to_simple_string(duration) );
+
+ if ( !theDefs.checkInvariants(errorMsg) ) break;
+
+ // Run verification on the completed suite
+ return theDefs.verification(errorMsg);
+ }
+
+ // crons run for ever. To terminate, we rely on test to have Verify attributes
+ // The verify attributes should *only* be on the task. (i.e task auto-reques
+ // hance parent is never complete, and hence no point in having verify attributes
+ if (foundCrons_) {
+ std::string msg;
+ if (theDefs.verification(msg)) {
+ return true;
+ }
+ }
+
+ // if simulation runs to long bomb out., then Analyse the defs,
+ // to determine why the simulation would not complete
+ if (abortSimulation(simiVisitor, duration, errorMsg) ) {
+
+ if ( !theDefs.checkInvariants(errorMsg) ) break;
+
+ if ( (theDefs.suiteVec().size() == completeSuiteCnt) && (hasAutoCancel != 0)) {
+ errorMsg += "All suites have completed, but autocancel has not taken effect?\n";
+ }
+
+ if (foundCrons_) {
+ std::string msg;
+ if (!theDefs.verification(msg)) {
+ errorMsg += msg;
+ errorMsg += "\n";
+ }
+ }
+
+ Analyser analyser;
+ analyser.run(theDefs);
+ errorMsg += "Please see files .flat and .depth for analysis\n";
+
+ PrintStyle::setStyle(PrintStyle::MIGRATE);
+ std::stringstream ss;
+ ss << theDefs;
+ errorMsg += ss.str();
+ return false;
+ }
+
+ // Increment calendar.
+ theDefs.updateCalendar( calUpdateParams );
+ duration += calendarIncrement;
+ }
+
+ return false;
+}
+
+
+bool Simulator::run(const std::string& theDefsFile,std::string& errorMsg) const
+{
+#ifdef DEBUG_LONG_RUNNING_SUITES
+ cout << "Simulator::run parsing file " << theDefsFile << endl;
+#endif
+
+ Defs theDefs;
+ DefsStructureParser checkPtParser( &theDefs , theDefsFile );
+ std::string warningMsg;
+ if (!checkPtParser.doParse(errorMsg,warningMsg)) return false;
+
+ return run(theDefs,theDefsFile,errorMsg, false /* don't do check, allready done */);
+}
+
+//---------------------------------------------------------------------------------------
+
+bool Simulator::abortSimulation( const SimulatorVisitor& simiVisitor,
+ const boost::posix_time::time_duration& duration,
+ std::string& errorMsg) const
+{
+#ifdef DEBUG_LONG_RUNNING_SUITES
+ cout << " duration = " << to_simple_string(duration)
+ << " max_simulation_period_=" << to_simple_string(max_simulation_period_)
+ << "\n";
+#endif
+ if (duration > max_simulation_period_) {
+
+ errorMsg = "\nTimed out after ";
+ errorMsg += to_simple_string(max_simulation_period_);
+ errorMsg += " hours of simulation.\n";
+
+ if (!simiVisitor.hasTimeDependencies()) errorMsg += "The definition has no time dependencies.\n";
+ return true;
+ }
+
+ return false;
+}
+
+
+bool Simulator::doJobSubmission(Defs& theDefs, std::string& errorMsg) const
+{
+ // For the simulation we ensure job submission takes less than 2 seconds
+ int submitJobsInterval = 10;
+
+ // Resolve dependencies and submit jobs
+ JobsParam jobsParam(submitJobsInterval, false /*create jobs*/); // spawn jobs *will* be set to false
+ Jobs jobs(&theDefs);
+ if (!jobs.generate(jobsParam)) {
+ ecf::log(Log::ERR, jobsParam.getErrorMsg());
+ assert(false);
+ return false;
+ }
+
+//#ifdef DEBUG_LONG_RUNNING_SUITES
+// cout << "Simulator::doJobSubmission jobsParam.submitted().size() " << jobsParam.submitted().size() << " level = " << level_ << endl;
+//#endif
+ level_++;
+
+ // For those jobs that were submitted, Simulate client by going
+ // through the task events and meters and updating them and then
+ // re-checking for job submission. Finally mark task as complete
+ // This is important as there may be other task dependent on this.
+ BOOST_FOREACH(Submittable* t, jobsParam.submitted()) {
+
+#ifdef DEBUG_LONG_RUNNING_SUITES
+ // If task repeating themselves, determine what is causing this:
+ std::map<Task*,int>::iterator i = taskIntMap_.find(t);
+ if (i == taskIntMap_.end()) taskIntMap_.insert( std::make_pair(t,1));
+ else {
+ (*i).second++;
+ // Find top most node that has a repeat, check if its incrementing:
+ Node* nodeWithRepeat = NULL;
+ Node* theParent = t->parent();
+ while (theParent) {
+ if (!theParent->repeat().empty()) nodeWithRepeat = theParent;
+ theParent = theParent->parent();
+ }
+ //cout << t->suite()->calendar().toString();
+ if ( nodeWithRepeat) {
+ cout << " level " << level_ << " submitted task " << t->debugNodePath() << " count = " << (*i).second
+ << " HAS parent Repeating node " << nodeWithRepeat->debugNodePath()
+ << " " << nodeWithRepeat->repeat().dump() << endl;
+ }
+ else { // cound be a cron
+ cout << " level " << level_ << " submitted task " << t->debugNodePath() << " count = " << (*i).second << endl;
+ }
+ }
+#endif
+
+ // If the task has any event used in the trigger expressions, then update event.
+ BOOST_FOREACH(Event& event, t->ref_events()) {
+
+ if (event.usedInTrigger()) { // event used in triger/complete expression
+ event.set_value(true);
+ if (!doJobSubmission(theDefs,errorMsg)) {
+ level_--;
+ return false;
+ }
+ }
+ else {
+ // warn about events not used in any trigger or complete expressions
+// cout << "submitted task " << t->debugNodePath() << " UN-USED event " << event.toString() << "\n";
+ }
+ }
+
+ // if the task has any meters used in trigger expressions, then increment meters
+ BOOST_FOREACH(Meter& meter, t->ref_meters()) {
+
+ if (meter.usedInTrigger()) { // meter used in trigger/complete expression
+ while (meter.value() < meter.max()) {
+ meter.set_value(meter.value()+1);
+ if (!doJobSubmission(theDefs,errorMsg)) {
+ level_--;
+ return false;
+ }
+ }
+ }
+ else {
+ // Meters that are not used in trigger are usually used to indicate progress.
+ meter.set_value(meter.max());
+ }
+ }
+
+ // any state change should be followed with a job submission
+ t->complete(); // Finally mark task as complete
+
+ // crons run for ever. To terminate, we rely on test to have Verify attributes
+ if (foundCrons_) {
+ std::string msg;
+ t->verification(msg);
+ if (msg.empty()) {
+ return true;
+ }
+ }
+
+#ifdef DEBUG_LONG_RUNNING_SUITES
+ cout << t->debugNodePath() << " completes at " << t->suite()->calendar().toString() << " level " << level_ << endl;
+#endif
+ if (!doJobSubmission(theDefs,errorMsg)) {
+ level_--;
+ return false;
+ }
+ }
+
+ level_--;
+ return true;
+}
+
+}
diff --git a/CSim/src/Simulator.hpp b/CSim/src/Simulator.hpp
new file mode 100644
index 0000000..1093f2a
--- /dev/null
+++ b/CSim/src/Simulator.hpp
@@ -0,0 +1,61 @@
+#ifndef SIMULATOR_HPP_
+#define SIMULATOR_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <boost/noncopyable.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <string>
+#include <map>
+class Defs;
+class Task;
+namespace ecf { class SimulatorVisitor;}
+
+namespace ecf {
+
+/// This class is used to simulate a definition file. This is use full
+/// because:
+// a/ Save time over involving server and asking client to play definition file
+// b/ Tells you of any parser errors in the definition file
+// c/ Tells you about any deadlocks, ie if suite does not complete
+// d/ Will simulate for both real and hybrid clocks
+// e/ Simulation will by default run for a year.
+class Simulator : private boost::noncopyable {
+public:
+ // default to run simulation for 1 year, or until suites complete if there are time dependencies 8784 = 366 X 24
+ // Otherwise will simulate for 24 hours
+ Simulator(const boost::posix_time::time_duration& period = boost::posix_time::time_duration(8784,0,0,0));
+
+ /// Some definition file will run forever. **NOT USED ***, kept for reference. Need a better mechanism
+ void truncateLongRepeats(int truncateTo) { truncateLongRepeatsTo_ = truncateTo ;}
+
+ /// return true if all ok else returns false;
+ bool run(Defs&, const std::string& defs_filename, std::string& errorMsg, bool do_checks = true) const;
+ bool run(const std::string& theDefsFile, std::string& errorMsg) const;
+
+private:
+
+ bool abortSimulation(const ecf::SimulatorVisitor&, const boost::posix_time::time_duration& duration,std::string& message) const;
+ bool doJobSubmission(Defs&, std::string& errorMsg) const;
+
+ mutable boost::posix_time::time_duration max_simulation_period_;
+ mutable std::map<Task*,int> taskIntMap_;
+ int truncateLongRepeatsTo_;
+ mutable int level_;
+ mutable bool foundCrons_;
+};
+}
+#endif /* SIMULATOR_HPP_ */
diff --git a/CSim/src/SimulatorVisitor.cpp b/CSim/src/SimulatorVisitor.cpp
new file mode 100644
index 0000000..858a982
--- /dev/null
+++ b/CSim/src/SimulatorVisitor.cpp
@@ -0,0 +1,148 @@
+ //============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <iostream>
+#include "SimulatorVisitor.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "Indentor.hpp"
+
+using namespace std;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+
+//#define DEBUG_VISITOR 1
+
+namespace ecf {
+
+///////////////////////////////////////////////////////////////////////////////
+SimulatorVisitor::SimulatorVisitor(int /* truncateRepeats */)
+: /* truncateRepeats_(truncateRepeats), */
+ foundTasks_(false),
+ foundCrons_(false),
+ hasTimeDependencies_(false),
+ max_length_(0),
+ ci_(hours(1))
+ {}
+
+void SimulatorVisitor::visitDefs( Defs* d) {
+ BOOST_FOREACH(suite_ptr s, d->suiteVec()) { s->acceptVisitTraversor(*this); }
+}
+
+void SimulatorVisitor::visitSuite( Suite* s) {
+
+#ifdef DEBUG_VISITOR
+ cout << "SimulatorVisitor::visitSuite " << s->debugNodePath() << "\n";
+#endif
+
+ /// begin , will cause creation of generated variables. The generated variables
+ /// are use in client scripts and used to locate the sms files.
+ s->begin();
+
+ // IF the suite has no task (i.e could consist of just limits, set suite to complete
+ // Since we rely on it for termination of tests
+ // make setting NState::COMPLETE is after begin(), which will set Node into the queued state
+ std::vector<Task*> theTasks;
+ s->getAllTasks(theTasks);
+ if (theTasks.empty()) {
+ s->set_state(NState::COMPLETE);
+ return;
+ }
+ foundTasks_ = true;
+
+ // Found time dependencies use calendar increment of one minute
+ if (s->hasTimeDependencies()) {
+ hasTimeDependencies_ = true;
+ ci_ = minutes(1);
+ }
+
+ // If suite has repeat day attribute( a infinite repeat), it will run forever, hence disable this for simulation purposes
+ /// reset will clear the invalid flag., when doing a real job submission.
+ /// *** this must be placed after begin() since begin() will reset all attributes() *****
+ if (s->ref_repeat().makeInfiniteInValid()) {
+ cout << "Disabling '" << s->repeat().dump() << "' attribute of " << s->debugNodePath() << ". This will allow simulation to complete earlier.\n";
+ }
+
+ if (!s->crons().empty()) {
+ foundCrons_ = true;
+ //cout << "Found crons on Suite\n";
+ }
+
+ visitNodeContainer(s);
+}
+
+void SimulatorVisitor::visitFamily( Family* f) { visitNodeContainer(f);}
+
+void SimulatorVisitor::visitNodeContainer(NodeContainer* nc)
+{
+ if (!nc->crons().empty()) {
+ foundCrons_ = true;
+ cout << "Found crons on NodeContainer\n";
+ }
+
+// analyse(nc);
+ BOOST_FOREACH(node_ptr t, nc->nodeVec()) { t->acceptVisitTraversor(*this);}
+}
+
+void SimulatorVisitor::visitTask( Task* t )
+{
+ if (!t->crons().empty()) {
+ foundCrons_ = true;
+ // cout << "Found crons on task\n";
+ }
+// analyse(t);
+}
+
+boost::posix_time::time_duration SimulatorVisitor::maxSimulationPeriod() const
+{
+ if ( hasTimeDependencies_) return hours(max_length_);
+ return hours(24);
+}
+
+/// Commented out, since we need to find a better mechanism of truncating long repeats
+/// without change repeat structure/attributes. (i.e need a simulation mode, with a max length
+/// that is ignored in the server.
+//void SimulatorVisitor::analyse(Node* node)
+//{
+// if (!node->repeat().empty()) {
+// int lengthInDays = node->repeat().length();
+//
+//#ifdef DEBUG_VISITOR
+// cout << "SimulatorVisitor::analyse " << node->debugNodePath() << " " << node->repeat().dump() << " length = " << lengthInDays << "\n";
+//#endif
+//
+// // **************************************************************************
+// // ****** CAUTION: Truncate make a change to defs structure. Use with care
+// // **************************************************************************
+// if (truncateRepeats_ != 0 && lengthInDays > truncateRepeats_) {
+// node->repeat_.truncate(truncateRepeats_);
+// lengthInDays = node->repeat().length();
+// }
+//
+// lengthInDays *= 24; // convert to hours Day of month value
+//
+// if ( lengthInDays > max_length_) {
+// max_length_ = lengthInDays;
+//
+//#ifdef DEBUG_VISITOR
+// cout << "max_length_ = " << max_length_ << " hours \n";
+//#endif
+// }
+// }
+//}
+
+}
diff --git a/CSim/src/SimulatorVisitor.hpp b/CSim/src/SimulatorVisitor.hpp
new file mode 100644
index 0000000..3ec2829
--- /dev/null
+++ b/CSim/src/SimulatorVisitor.hpp
@@ -0,0 +1,73 @@
+#ifndef SIMULATORVISITOR_HPP_
+#define SIMULATORVISITOR_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "NodeTreeVisitor.hpp"
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <iostream>
+#include <sstream>
+#include <set>
+#include <vector>
+class Node;
+
+namespace ecf {
+
+class SimulatorVisitor : public NodeTreeVisitor {
+public:
+ SimulatorVisitor(int truncateRepeats);
+
+ /// If the definition file has suites with no tasks, ie they could have server limits
+ /// then for simulation purposes(i.e when all suites complete we terminate simulation)
+ /// mark these as complete. Must be done *AFTER* beginAll() which sets all nodes to queued state
+ bool foundTasks() const { return foundTasks_;}
+
+ /// Crons run for ever. Detect them so that we can abort early
+ bool foundCrons() const { return foundCrons_;}
+
+ /// returns true if defs has time,date,today, date time based attributes
+ bool hasTimeDependencies() const { return hasTimeDependencies_;}
+
+ /// Determine the max simulation period in hours. We will default to a years 8784 = 366 X 24
+ /// However by going through and looking at the repeats, we can get a better idea
+ boost::posix_time::time_duration maxSimulationPeriod() const;
+
+ // default calendar increment is one minute, however if we have no time dependencies,
+ // then simulation can be speeded up, ie by using hour increment
+ const boost::posix_time::time_duration& calendarIncrement() const { return ci_;}
+
+ virtual bool traverseObjectStructureViaVisitors() const { return true;}
+ virtual void visitDefs(Defs*);
+ virtual void visitSuite(Suite*);
+ virtual void visitFamily(Family*);
+ virtual void visitNodeContainer(NodeContainer*);
+ virtual void visitTask(Task*);
+
+private:
+ /// Commented out since, we need to find a way of truncating lon repeats
+ /// without changing repeat structure.
+// void analyse(Node* node);
+// int truncateRepeats_; // allow for simulation to complete earlier. ***NOT USED, kept for reference *****
+
+ bool foundTasks_;
+ bool foundCrons_;
+ bool hasTimeDependencies_;
+ int max_length_;
+ boost::posix_time::time_duration ci_;
+};
+
+}
+#endif
diff --git a/CSim/test/TestAnalysis.cpp b/CSim/test/TestAnalysis.cpp
new file mode 100644
index 0000000..7019550
--- /dev/null
+++ b/CSim/test/TestAnalysis.cpp
@@ -0,0 +1,82 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+
+#include "Simulator.hpp"
+
+#include "File.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "TestUtil.hpp"
+#include "System.hpp"
+
+using namespace std;
+using namespace ecf;
+
+
+BOOST_AUTO_TEST_SUITE( SimulatorTestSuite )
+
+/// Use this class to test single simulation of definition file that we want to add
+/// to Test Simulator. This is a separate exe
+
+BOOST_AUTO_TEST_CASE( test_analysys )
+{
+ cout << "Simulator:: ...test_analysys\n";
+ //suite suite
+ // family family
+ // task t1
+ // trigger t2 == complete
+ // task t2
+ // trigger t1 == complete
+ // endfamily
+ //endsuite
+
+ // This simulation is expected to fail, since we have a deadlock/ race condition
+ // It will prodice a defs.depth and defs.flat files. Make sure to remove them
+ Defs theDefs;
+ {
+ suite_ptr suite = theDefs.add_suite("test_analysys");
+ family_ptr fam = suite->add_family("family");
+
+ task_ptr task1 = fam->add_task("t1");
+ task1->add_trigger( "t2 == complete" );
+
+ task_ptr task2 = fam->add_task("t2");
+ task2->add_trigger( "t1 == complete" );
+
+ // cout << theDefs << "\n";
+ }
+
+ Simulator simulator;
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE(!simulator.run(theDefs, TestUtil::testDataLocation("test_analysys.def") , errorMsg),errorMsg);
+
+ // cout << theDefs << "\n";
+ boost::filesystem::remove("defs.depth");
+ boost::filesystem::remove("defs.flat");
+
+ /// Destroy singleton's to avoid valgrind from complaining
+ System::destroy();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/CSim/test/TestAutoCancel.cpp b/CSim/test/TestAutoCancel.cpp
new file mode 100644
index 0000000..5f60f2b
--- /dev/null
+++ b/CSim/test/TestAutoCancel.cpp
@@ -0,0 +1,304 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include "Simulator.hpp"
+#include "File.hpp"
+#include "Log.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "TestUtil.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include "boost/progress.hpp"
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+
+using namespace std;
+using namespace ecf;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+
+namespace fs = boost::filesystem;
+
+/// Simulate definition files that are created on then fly. This us to validate
+/// Defs file, to check for correctness
+
+BOOST_AUTO_TEST_SUITE( SimulatorTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_autocancel_ast_node_reset )
+{
+ cout << "Simulator:: ...test_autocancel_ast_node_reset\n";
+
+ // ****: Since we have no time dependencies the simulator calendar increment
+ // ****: is in hours. Hence autocancel at hour resolution
+ Defs theDefs;
+ {
+ ClockAttr clockAttr(true);
+ clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
+ suite_ptr suite = theDefs.add_suite("s1");
+ suite->addClock( clockAttr );
+
+ family_ptr fam = suite->add_family("family");
+ task_ptr task = fam->add_task("t");
+ task->add_trigger( "/s2/family/t == complete" );
+
+ task_ptr task2 = fam->add_task("t2");
+ task2->add_trigger( "/s3/family/t == complete" );
+ task2->add_complete( "/s2/family == complete" );
+
+ task_ptr task3 = fam->add_task("t3");
+ task3->add_trigger( "/s3 == complete" );
+ task3->add_complete( "/s2 == complete");
+ // cout << theDefs << "\n";
+ }
+ {
+ ClockAttr clockAttr(true);
+ clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
+
+ suite_ptr suite = theDefs.add_suite("s2");
+ suite->addClock( clockAttr );
+ suite->addAutoCancel( ecf::AutoCancelAttr( ecf::TimeSlot(1,0), false));
+
+ family_ptr fam = suite->add_family("family");
+ fam->add_task("t");
+ }
+ {
+ ClockAttr clockAttr(true);
+ clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
+ suite_ptr suite = theDefs.add_suite("s3");
+ suite->addClock( clockAttr );
+ suite->addAutoCancel( ecf::AutoCancelAttr( ecf::TimeSlot(1,0), false));
+
+ family_ptr fam = suite->add_family("family");
+ fam->add_task("t");
+ }
+
+ // Check number of AST nodes. The AST should be created on the fly
+ std::set<Node*> theSet;
+ theDefs.getAllAstNodes(theSet);
+ BOOST_CHECK_MESSAGE(theSet.size() == 5,"Expected to have 5 AST nodes in trigger/complete expressions but found " << theSet.size());
+
+ // Run the simulator
+ Simulator simulator;
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE(simulator.run(theDefs,TestUtil::testDataLocation("test_autocancel_ast_node_reset.def"), errorMsg),errorMsg);
+
+ // Auto cancel should delete suite s2 and s3, leaving one suite i.e s1
+ BOOST_CHECK_MESSAGE(theDefs.suiteVec().size() == 1,"Expected to have 1 suites but found " << theDefs.suiteVec().size());
+
+ // The references to nodes in suites s2, s3 should have been cleared in suite s1
+ {
+ std::set<Node*> theSet;
+ theDefs.getAllAstNodes(theSet);
+ BOOST_CHECK_MESSAGE(theSet.empty(),"Expected to have 0 AST nodes in trigger/complete expressions but found " << theSet.size());
+ }
+}
+
+
+BOOST_AUTO_TEST_CASE( test_autocancel_suite )
+{
+ cout << "Simulator:: ...test_autocancel_suite\n";
+
+ // ****: Since we have no time dependencies the simulator calendar increment
+ // ****: is in hours. Hence autocancel at hour resolution
+ Defs theDefs;
+ {
+ ClockAttr clockAttr(true);
+ clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
+ suite_ptr suite = theDefs.add_suite("test_autocancel_10_hours_relative");
+ suite->addClock( clockAttr );
+ suite->addAutoCancel( ecf::AutoCancelAttr( ecf::TimeSlot(10,0), true));
+ family_ptr fam = suite->add_family("family");
+ fam->add_task("t");
+ }
+ {
+ ClockAttr clockAttr(true);
+ clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
+ suite_ptr suite = theDefs.add_suite("test_autocancel_1_hours_real");
+ suite->addClock( clockAttr );
+ suite->addAutoCancel( ecf::AutoCancelAttr( ecf::TimeSlot(1,0), false));
+ family_ptr fam = suite->add_family("family");
+ fam->add_task("t");
+ }
+ {
+ ClockAttr clockAttr(true);
+ clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
+ suite_ptr suite = theDefs.add_suite("test_autocancel_1_day_relative");
+ suite->addClock( clockAttr );
+ suite->addAutoCancel( ecf::AutoCancelAttr(1) );
+ family_ptr fam = suite->add_family("family");
+ fam->add_task("t");
+ // cout << theDefs << "\n";
+ }
+
+ Simulator simulator;
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE(simulator.run(theDefs, TestUtil::testDataLocation("test_autocancel_suite.def"), errorMsg),errorMsg);
+
+ // make sure autocancel deletes the suite.
+ BOOST_CHECK_MESSAGE(theDefs.suiteVec().size() == 0,"Expected to have 0 suites but found " << theDefs.suiteVec().size());
+}
+
+BOOST_AUTO_TEST_CASE( test_autocancel_family_and_task )
+{
+ cout << "Simulator:: ...test_autocancel_family_and_task\n";
+
+ // ****: Since we have no time dependencies the simulator calendar increment
+ // ****: is in hours. Hence autocancel at hour resolution
+ Defs theDefs;
+ {
+ ClockAttr clockAttr(true);
+ clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
+ suite_ptr suite = theDefs.add_suite("test_autocancel_9_10_hours_relative");
+ suite->addClock( clockAttr );
+
+ family_ptr fam = suite->add_family("family");
+ fam->addAutoCancel( ecf::AutoCancelAttr( ecf::TimeSlot(10,0), true));
+
+ task_ptr task = fam->add_task("t");
+ task->addAutoCancel( ecf::AutoCancelAttr( ecf::TimeSlot(9,0), true));
+
+ // cout << theDefs << "\n";
+ }
+ {
+ ClockAttr clockAttr(true);
+ clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
+ suite_ptr suite = theDefs.add_suite("test_autocancel_1_2_hours_real");
+ suite->addClock( clockAttr );
+
+ family_ptr fam = suite->add_family("family");
+ fam->addAutoCancel( ecf::AutoCancelAttr( ecf::TimeSlot(2,0), false));
+
+ task_ptr task = fam->add_task("t");
+ task->addAutoCancel( ecf::AutoCancelAttr( ecf::TimeSlot(1,0), false));
+ }
+ {
+ ClockAttr clockAttr(true);
+ clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
+ suite_ptr suite = theDefs.add_suite("test_autocancel_1_2_day_relative");
+ suite->addClock( clockAttr );
+
+ family_ptr fam = suite->add_family("family");
+ fam->addAutoCancel( ecf::AutoCancelAttr(2) );
+
+ task_ptr task = fam->add_task("t");
+ task->addAutoCancel( ecf::AutoCancelAttr(1) );
+ // cout << theDefs << "\n";
+ }
+
+ Simulator simulator;
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE(simulator.run(theDefs,TestUtil::testDataLocation("test_autocancel_family_and_task.def"), errorMsg),errorMsg);
+
+ // make sure autocancel deletes the families.
+ std::vector<Family*> famVec;
+ theDefs.getAllFamilies(famVec);
+ BOOST_CHECK_MESSAGE(famVec.size() == 0,"Expected to have 0 families but found " << famVec.size());
+}
+
+BOOST_AUTO_TEST_CASE( test_autocancel_task )
+{
+ cout << "Simulator:: ...test_autocancel_task\n";
+
+ // ****: Since we have no time dependencies the simulator calendar increment
+ // ****: is in hours. Hence autocancel at hour resolution
+ Defs theDefs;
+ {
+ ClockAttr clockAttr(true);
+ clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
+ suite_ptr suite = theDefs.add_suite("test_autocancel_10_hours_relative");
+ suite->addClock( clockAttr );
+
+ family_ptr fam = suite->add_family("family");
+ task_ptr task = fam->add_task("t");
+ task->addAutoCancel( ecf::AutoCancelAttr( ecf::TimeSlot(10,0), true));
+ }
+ {
+ ClockAttr clockAttr(true);
+ clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
+ suite_ptr suite = theDefs.add_suite("test_autocancel_1_hours_real");
+ suite->addClock( clockAttr );
+ family_ptr fam = suite->add_family("family");
+ task_ptr task = fam->add_task("t");
+ task->addAutoCancel( ecf::AutoCancelAttr( ecf::TimeSlot(1,0), false));
+ }
+ {
+ ClockAttr clockAttr(true);
+ clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
+ suite_ptr suite = theDefs.add_suite("test_autocancel_1_day_relative");
+ suite->addClock( clockAttr );
+
+ family_ptr fam = suite->add_family("family");
+ task_ptr task = fam->add_task("t");
+ task->addAutoCancel( ecf::AutoCancelAttr(1) );
+ // cout << theDefs << "\n";
+ }
+
+ Simulator simulator;
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE(simulator.run(theDefs,TestUtil::testDataLocation("test_autocancel_task.def"), errorMsg),errorMsg);
+
+ // make sure autocancel deletes the tasks and leaves families intact.
+ std::vector<task_ptr> task_vec;
+ theDefs.get_all_tasks(task_vec);
+
+ std::vector<Family*> famVec;
+ theDefs.getAllFamilies(famVec);
+
+ BOOST_CHECK_MESSAGE(famVec.size() == 3,"Expected to have 3 families but found " << famVec.size());
+ BOOST_CHECK_MESSAGE(task_vec.size() == 0,"Expected to have 0 tasks but found " << task_vec.size());
+}
+
+BOOST_AUTO_TEST_CASE( test_two_autocancel_in_hierarchy )
+{
+ cout << "Simulator:: ...test_two_autocancel_in_hierarchy\n"; // ECFLOW-556
+
+ // ****: Since we have no time dependencies the simulator calendar increment
+ // ****: is in hours. Hence autocancel at hour resolution
+ Defs theDefs;
+ {
+ ClockAttr clockAttr(true);
+ clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
+ suite_ptr suite = theDefs.add_suite("test_two_autocancel_in_hierarchy");
+ suite->addClock( clockAttr );
+
+ family_ptr fam = suite->add_family("family");
+ fam->addAutoCancel( ecf::AutoCancelAttr( ecf::TimeSlot(1,0), true));
+ task_ptr task = fam->add_task("t");
+ task->addAutoCancel( ecf::AutoCancelAttr( ecf::TimeSlot(1,0), true));
+ }
+
+ Simulator simulator;
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE(simulator.run(theDefs,TestUtil::testDataLocation("test_two_autocancel_in_hierarchy.def"), errorMsg),errorMsg);
+
+ std::vector<task_ptr> task_vec;
+ theDefs.get_all_tasks(task_vec);
+
+ std::vector<Family*> famVec;
+ theDefs.getAllFamilies(famVec);
+
+ BOOST_CHECK_MESSAGE(famVec.size() == 0,"Expected to have 0 families but found " << famVec.size());
+ BOOST_CHECK_MESSAGE(task_vec.size() == 0,"Expected to have 0 tasks but found " << task_vec.size());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/CSim/test/TestMeter.cpp b/CSim/test/TestMeter.cpp
new file mode 100644
index 0000000..0c2687a
--- /dev/null
+++ b/CSim/test/TestMeter.cpp
@@ -0,0 +1,108 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include "Simulator.hpp"
+#include "File.hpp"
+#include "Log.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "TestUtil.hpp"
+#include "System.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include "boost/progress.hpp"
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+
+using namespace std;
+using namespace ecf;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+
+namespace fs = boost::filesystem;
+
+/// Simulate definition files that are created on then fly. This us to validate
+/// Defs file, to check for correctness
+
+BOOST_AUTO_TEST_SUITE( SimulatorTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_meter )
+{
+ cout << "Simulator:: ...test_meter\n";
+
+ //suite suite
+ // clock real <todays date>
+ // family family
+ // task fc
+ // meter hour 0 240
+ // task half
+ // trigger fc:hour >= 120
+ // endfamily
+ //endsuite
+
+ // Initialise clock with todays date then create a time attribute + minutes
+ // such that the task should only run once, in the next minute
+ boost::posix_time::ptime theLocalTime = Calendar::second_clock_time();
+
+ Defs theDefs;
+ {
+ ClockAttr clockAttr(theLocalTime );
+ suite_ptr suite = theDefs.add_suite("test_meter");
+ suite->addClock( clockAttr );
+ suite->addVerify( VerifyAttr(NState::COMPLETE,1) );
+
+ family_ptr fam = suite->add_family("family");
+ fam->addVerify( VerifyAttr(NState::COMPLETE,1) );
+
+ task_ptr fc = fam->add_task("fc");
+ fc->addMeter( Meter("hour",0,240,240) );
+ fc->addVerify( VerifyAttr(NState::COMPLETE,1) );
+
+ task_ptr half = fam->add_task("half");
+ half->add_trigger( "fc:hour >= 120" );
+ half->addVerify( VerifyAttr(NState::COMPLETE,1) );
+// cout << theDefs << "\n";
+ }
+
+ Simulator simulator;
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE(simulator.run(theDefs,TestUtil::testDataLocation("test_meter.def"), errorMsg),errorMsg);
+
+ // The simulator will set all the meter values, so final value must be the max value.
+ bool found_task = false;
+ std::vector<Task*> theServerTasks;
+ theDefs.getAllTasks(theServerTasks);
+ BOOST_FOREACH(Task* t, theServerTasks) {
+ if (t->name() == "fc") {
+ found_task = true;
+ const std::vector<Meter>& meters = t->meters();
+ BOOST_REQUIRE_MESSAGE(meters.size() == 1,"Expected one meter but found " << meters.size());
+ BOOST_CHECK_MESSAGE(meters[0].value() == meters[0].max(),"Expected meter to have value of " << meters[0].max() << " but found " << meters[0].value() );
+ }
+ }
+ BOOST_REQUIRE_MESSAGE(found_task ,"Failed to find task fc ");
+
+ /// Destroy System singleton to avoid valgrind from complaining
+ System::destroy();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/CSim/test/TestRepeat.cpp b/CSim/test/TestRepeat.cpp
new file mode 100644
index 0000000..8e825ae
--- /dev/null
+++ b/CSim/test/TestRepeat.cpp
@@ -0,0 +1,448 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include "Simulator.hpp"
+#include "File.hpp"
+#include "Log.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "TestUtil.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include "boost/progress.hpp"
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+
+using namespace std;
+using namespace ecf;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+
+namespace fs = boost::filesystem;
+
+/// Simulate definition files that are created on then fly. This us to validate
+/// Defs file, to check for correctness
+
+BOOST_AUTO_TEST_SUITE( SimulatorTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_repeat_integer )
+{
+ cout << "Simulator:: ...test_repeat_integer\n";
+
+ //suite suite
+ // repeat integer VAR 0 1 1 # run at 0, 1 2 times
+ // edit SLEEPTIME 1
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // family family
+ // repeat integer VAR 0 1 1 # run at 0, 1 2 times
+ // task t<n>
+ // ....
+ // endfamily
+ //endsuite
+
+ // Each task/job should be run *4* times, according to the repeats
+ // Mimics nested loops
+ Defs theDefs;
+ {
+ suite_ptr suite = theDefs.add_suite("suite");
+ suite->addRepeat( RepeatInteger("VAR",0,1,1)); // repeat contents 2 times
+ suite->addVerify( VerifyAttr(NState::COMPLETE,2) );
+ family_ptr fam = suite->add_family( "family" );
+ fam->addRepeat( RepeatInteger("VAR",0,1,1)); // repeat contents 2 times
+ fam->addVerify( VerifyAttr(NState::COMPLETE,4) ); // verify family repeats 2 times
+ int taskSize = 2;
+ for(int i=0; i < taskSize; i++) {
+ task_ptr t = fam->add_task( "t" + boost::lexical_cast<std::string>(i) );
+ t->addVerify( VerifyAttr(NState::COMPLETE,4) ); // Each task should run 4 times
+ }
+ // cout << theDefs << "\n";
+ }
+
+ Simulator simulator;
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE(simulator.run(theDefs,TestUtil::testDataLocation("test_repeat_integer.def"),errorMsg),errorMsg);
+// cout << theDefs << "\n";
+}
+
+BOOST_AUTO_TEST_CASE( test_repeat_integer_relative )
+{
+ cout << "Simulator:: ...test_repeat_integer_relative\n";
+
+ //suite suite
+ // repeat integer VAR 0 1 1 # run at 0, 1 2 times
+ // edit SLEEPTIME 1
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // family family
+ // repeat integer VAR 0 1 1 # run at 0, 1 2 times
+ // task t1
+ // time +0;02
+ // endfamily
+ //endsuite
+
+ // Each task/job should be run *4* times relative to Node times, according to the repeats
+ // Mimics nested loops
+ Defs theDefs;
+ {
+ ClockAttr clockAttr(true/*false means use hybrid clock*/);
+ clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
+ suite_ptr suite = theDefs.add_suite("test_repeat_integer_relative");
+ suite->addClock( clockAttr );
+ suite->addRepeat( RepeatInteger("VAR",0,1,1)); // repeat contents 2 times
+ suite->addVerify( VerifyAttr(NState::COMPLETE,2) );
+
+ family_ptr fam = suite->add_family( "family" );
+ fam->addRepeat( RepeatInteger("VAR",0,1,1)); // repeat contents 2 times
+ fam->addVerify( VerifyAttr(NState::COMPLETE,4) );
+
+ task_ptr t = fam->add_task("t1");
+ t->addTime( ecf::TimeAttr( TimeSlot(0,2), true /*relative*/ ) );
+ t->addVerify( VerifyAttr(NState::COMPLETE,4) ); // Each task should run 4 times
+
+// cout << theDefs << "\n";
+ }
+
+ Simulator simulator;
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE(simulator.run(theDefs,TestUtil::testDataLocation("test_repeat_integer_relative.def"),errorMsg),errorMsg);
+// cout << theDefs << "\n";
+}
+
+
+BOOST_AUTO_TEST_CASE( test_repeat_date )
+{
+ cout << "Simulator:: ...test_repeat_date\n";
+ //suite suite
+ // clock real <fixed date + time>
+ // family family
+ // repeat date YMD 20091001 20091015 1 # yyyymmdd
+ // task t
+ // time 10:00
+ // endfamily
+ //endsuite
+
+ // Each task should be run 15 times, ie every day at 10.00 am from 1st Oct->15 October 15 times
+ Defs theDefs;
+ {
+ ClockAttr clockAttr;
+ clockAttr.date(1,10,2009);
+ suite_ptr suite = theDefs.add_suite("test_repeat_date");
+ suite->addVerify( VerifyAttr(NState::COMPLETE,1) );
+ suite->addClock( clockAttr );
+
+ family_ptr fam = suite->add_family( "family" );
+ fam->addRepeat( RepeatDate("YMD",20091001,20091015,1)); // repeat contents 15 times
+ fam->addVerify( VerifyAttr(NState::COMPLETE,15) );
+
+ task_ptr task = fam->add_task("t");
+ task->addTime( ecf::TimeAttr( TimeSlot(10,0) ) );
+ task->addVerify( VerifyAttr(NState::COMPLETE,15) ); // task should complete 15 times
+
+// cout << theDefs << "\n";
+ }
+
+ Simulator simulator;
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE(simulator.run(theDefs, TestUtil::testDataLocation("test_repeat_date.def"), errorMsg),errorMsg);
+}
+
+BOOST_AUTO_TEST_CASE( test_repeat_date_2 )
+{
+ cout << "Simulator:: ...test_repeat_date_2\n";
+ //suite suite
+ // clock real <fixed date + time>
+ // family family
+ // repeat date YMD 20091015 20091001 -1
+ // task t
+ // time 10:00
+ // endfamily
+ //endsuite
+
+ // Each task should be run 15 times, ie every day at 10.00 am
+ Defs theDefs;
+ {
+ ClockAttr clockAttr;
+ clockAttr.date(1,10,2015);
+ suite_ptr suite = theDefs.add_suite("test_repeat_date");
+ suite->addVerify( VerifyAttr(NState::COMPLETE,1) );
+ suite->addClock( clockAttr );
+
+ family_ptr fam = suite->add_family( "family" );
+ fam->addRepeat( RepeatDate("YMD",20091015,20091001,-1)); // repeat contents 15 times
+ fam->addVerify( VerifyAttr(NState::COMPLETE,15) );
+
+ task_ptr task = fam->add_task("t");
+ task->addTime( ecf::TimeAttr( TimeSlot(10,0) ) );
+ task->addVerify( VerifyAttr(NState::COMPLETE,15) ); // task should complete 15 times
+
+// cout << theDefs << "\n";
+ }
+
+ Simulator simulator;
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE(simulator.run(theDefs, TestUtil::testDataLocation("test_repeat_date.def"), errorMsg),errorMsg);
+}
+
+BOOST_AUTO_TEST_CASE( test_repeat_date_for_loop )
+{
+ cout << "Simulator:: ...test_repeat_date_for_loop\n";
+
+ //suite suite
+ // clock real <todays date>
+ // repeat date YMD 20091001 20091005 1 # yyyymmdd
+ // family family
+ // repeat date YMD 20091001 20091005 1 # yyyymmdd
+ // task t
+ // time 10:00
+ // endfamily
+ //endsuite
+
+ // Each task should be run 5 * 5= 25 times, ie every day from from 1st Oct -> 5 Oct 5*5 times
+ Defs theDefs;
+ {
+ suite_ptr suite = theDefs.add_suite("test_repeat_date_for_loop");
+ suite->addRepeat( RepeatDate("YMD",20091001,20091005,1)); // repeat contents 5 times
+ suite->addVerify( VerifyAttr(NState::COMPLETE,5) );
+
+ // start at specific time other wise time dependent checks will not verify
+ ClockAttr clockAttr;
+ clockAttr.date(1,10,2009);
+ suite->addClock( clockAttr );
+
+ family_ptr fam = suite->add_family( "family" );
+ fam->addRepeat( RepeatDate("YMD",20091001,20091005,1)); // repeat contents 5 times
+ fam->addVerify( VerifyAttr(NState::COMPLETE,25) );
+
+ task_ptr task = fam->add_task("t");
+ task->addTime( ecf::TimeAttr( TimeSlot(10,0) ) );
+ task->addVerify( VerifyAttr(NState::COMPLETE,25) ); // task should complete 25 times
+
+// cout << theDefs << "\n";
+ }
+
+ Simulator simulator;
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE(simulator.run(theDefs, TestUtil::testDataLocation("test_repeat_date_for_loop.def"), errorMsg),errorMsg);
+}
+
+
+BOOST_AUTO_TEST_CASE( test_repeat_date_for_loop2 )
+{
+ cout << "Simulator:: ...test_repeat_date_for_loop2\n";
+
+ //suite suite
+ // clock real <todays date>
+ // repeat date YMD 20091001 20091005 1 # yyyymmdd
+ // family family
+ // repeat date YMD 20091001 20091005 1 # yyyymmdd
+ // task t
+ // time 10:00
+ // time 11:00
+ // endfamily
+ //endsuite
+
+ // Each task should be run 5 * 5 * 2 = 50 times, ie every day from from 1st Oct -> 5 Oct 5*5 times * 2 time slots
+ Defs theDefs;
+ {
+ // start at specific time other wise time dependent checks will not verify
+ suite_ptr suite = theDefs.add_suite("test_repeat_date_for_loop2");
+ suite->addRepeat( RepeatDate("YMD",20091001,20091005,1)); // repeat contents 5 times
+ suite->addVerify( VerifyAttr(NState::COMPLETE,5) );
+
+ ClockAttr clockAttr;
+ clockAttr.date(1,10,2009);
+ suite->addClock( clockAttr );
+
+ family_ptr fam = suite->add_family( "family" );
+ fam->addRepeat( RepeatDate("YMD",20091001,20091005,1)); // repeat contents 5 times
+ fam->addVerify( VerifyAttr(NState::COMPLETE,25) );
+
+ task_ptr task = fam->add_task("t");
+ task->addTime( ecf::TimeAttr( TimeSlot(10,0) ) );
+ task->addTime( ecf::TimeAttr( TimeSlot(11,0) ) );
+ task->addVerify( VerifyAttr(NState::COMPLETE,50) ); // task should complete 50 times
+
+ // cout << theDefs << "\n";
+ }
+
+ Simulator simulator;
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE(simulator.run(theDefs, TestUtil::testDataLocation("test_repeat_date_for_loop2.def"), errorMsg),errorMsg);
+}
+
+
+BOOST_AUTO_TEST_CASE( test_repeat_with_cron )
+{
+ cout << "Simulator:: ...test_repeat_with_cron\n";
+// suite s
+// clock real <today date>
+// family f
+// repeat date YMD 20091001 20091004 1 # yyyymmdd
+// family plot
+// complete plot/finish == complete
+//
+// task finish
+// trigger 1 == 0 # stops task from running
+// complete checkdata::done or checkdata == complete
+//
+// task checkdata
+// event done
+// cron <today date> + 2 minutes # cron that run forever
+// endfamily
+// endfamily
+// endsuite
+
+ Defs theDefs;
+ {
+ boost::posix_time::ptime theLocalTime = Calendar::second_clock_time();
+ boost::posix_time::ptime time_plus_2_minute = theLocalTime + minutes(2);
+ ClockAttr clockAttr(theLocalTime, false/* real clock*/);
+
+ suite_ptr suite = theDefs.add_suite("test_repeat_with_cron");
+ suite->addClock( clockAttr );
+
+ family_ptr f = suite->add_family( "f" );
+ f->addRepeat( RepeatDate("YMD",20091001,20091004,1)); // repeat contents 4 times
+ f->addVerify( VerifyAttr(NState::COMPLETE,4) );
+
+ family_ptr family_plot = f->add_family( "plot" );
+ family_plot->add_complete( "plot/finish == complete");
+ family_plot->addVerify( VerifyAttr(NState::COMPLETE,4) );
+
+
+ task_ptr task_finish = family_plot->add_task("finish");
+ task_finish->add_trigger( "1 == 0");
+ task_finish->add_complete( "checkdata:done or checkdata == complete" );
+ task_finish->addVerify( VerifyAttr(NState::COMPLETE,8) );
+
+ task_ptr task_checkdata = family_plot->add_task("checkdata");
+ task_checkdata->addEvent( Event(1,"done"));
+
+ CronAttr cronAttr;
+ cronAttr.addTimeSeries( ecf::TimeSlot(time_plus_2_minute.time_of_day()) );
+ task_checkdata->addCron( cronAttr );
+ task_checkdata->addVerify( VerifyAttr(NState::COMPLETE,8) );
+
+// cout << theDefs << "\n";
+ }
+
+ Simulator simulator;
+ std::string errorMsg;
+ BOOST_REQUIRE_MESSAGE(simulator.run(theDefs, TestUtil::testDataLocation("test_repeat_with_cron.def"), errorMsg),errorMsg);
+}
+
+BOOST_AUTO_TEST_CASE( test_repeat_enumerated )
+{
+ cout << "Simulator:: ...test_repeat_enumerated\n";
+ //suite suite
+ // family family
+ // repeat enumerated ENUM "hello" "there" "bill" # run 3 times
+ // task t1
+ // endfamily
+ //endsuite
+
+ // Each task/job should be run 3 according to the repeats
+ Defs theDefs;
+ {
+ suite_ptr suite = theDefs.add_suite("test_repeat_enumerated");
+
+ std::vector<std::string> theEnums;
+ theEnums.push_back("hello"); // index 0
+ theEnums.push_back("there"); // index 1
+ theEnums.push_back("bill"); // index 2
+
+ family_ptr fam = suite->add_family( "family" );
+ fam->addRepeat( RepeatEnumerated("ENUM",theEnums)); // repeat contents 3 times
+ fam->addVerify( VerifyAttr(NState::COMPLETE,3) );
+
+ task_ptr task = fam->add_task("t1");
+ task->addVerify( VerifyAttr(NState::COMPLETE,3) );
+
+ // cout << theDefs << "\n";
+ }
+
+ Simulator simulator;
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE(simulator.run(theDefs,TestUtil::testDataLocation("test_repeat_enumerated.def"), errorMsg),errorMsg);
+ // cout << theDefs << "\n";
+
+
+ std::vector<Task*> theServerTasks;
+ theDefs.getAllTasks(theServerTasks);
+ BOOST_FOREACH(Task* t, theServerTasks) {
+ // verify repeat has the last value
+ Family* family = dynamic_cast<Family*>(t->parent());
+ const Repeat& repeat = family->findRepeat("ENUM");
+ BOOST_REQUIRE_MESSAGE(!repeat.empty(),"Expected to find repeat on family " << family->absNodePath() );
+ BOOST_REQUIRE_MESSAGE(!repeat.valid(),"Expected invalid repeat");
+ BOOST_REQUIRE_MESSAGE(repeat.value() == 3,"Expected to find repeat with value 3 but found " << repeat.value() );
+ BOOST_REQUIRE_MESSAGE(repeat.last_valid_value() == 2,"Expected to find repeat with last valid value 2 but found " << repeat.last_valid_value() );
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_repeat_string )
+{
+ cout << "Simulator:: ...test_repeat_string\n";
+ //suite suite
+ // family family
+ // repeat string STRING "hello" "there" # run 2 times
+ // task t1
+ // endfamily
+ //endsuite
+
+ // Each task/job should be run 3 according to the repeats
+ Defs theDefs;
+ {
+ suite_ptr suite = theDefs.add_suite("test_repeat_string");
+
+ std::vector<std::string> theStrings;
+ theStrings.push_back("hello"); // index 0
+ theStrings.push_back("there"); // index 1
+
+ family_ptr fam = suite->add_family( "family" );
+ fam->addRepeat( RepeatString("STRING",theStrings)); // repeat contents 2 times
+ fam->addVerify( VerifyAttr(NState::COMPLETE,2) );
+
+ task_ptr task = fam->add_task("t1");
+ task->addVerify( VerifyAttr(NState::COMPLETE,2) );
+
+ // cout << theDefs << "\n";
+ }
+
+ Simulator simulator;
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE(simulator.run(theDefs, TestUtil::testDataLocation("test_repeat_string.def"), errorMsg),errorMsg);
+ // cout << theDefs << "\n";
+
+ std::vector<Task*> theServerTasks;
+ theDefs.getAllTasks(theServerTasks);
+ BOOST_FOREACH(Task* t, theServerTasks) {
+ // verify repeat has the last value
+ Family* family = dynamic_cast<Family*>(t->parent());
+ const Repeat& repeat = family->findRepeat("STRING");
+ BOOST_REQUIRE_MESSAGE(!repeat.empty(),"Expected to find repeat on family " << family->absNodePath() );
+ BOOST_REQUIRE_MESSAGE(!repeat.valid(),"Expected invalid repeat");
+ BOOST_REQUIRE_MESSAGE(repeat.value() == 2,"Expected to find repeat with value 2 but found " << repeat.value() );
+ BOOST_REQUIRE_MESSAGE(repeat.last_valid_value() == 1,"Expected to find repeat with last valid value 1 but found " << repeat.last_valid_value() );
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/CSim/test/TestSimulator.cpp b/CSim/test/TestSimulator.cpp
new file mode 100644
index 0000000..cf4e95f
--- /dev/null
+++ b/CSim/test/TestSimulator.cpp
@@ -0,0 +1,135 @@
+#define BOOST_TEST_MODULE TestSimulator
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #11 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <string>
+#include <iostream>
+#include <fstream>
+
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include "boost/progress.hpp"
+
+#include "System.hpp"
+#include "Simulator.hpp"
+#include "File.hpp"
+#include "LogVerification.hpp"
+
+namespace fs = boost::filesystem;
+
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( SimulatorTestSuite )
+
+void simulate(const std::string& directory, bool pass)
+{
+ fs::path full_path( fs::initial_path<fs::path>() );
+ full_path = fs::system_complete( fs::path( directory ) );
+
+ BOOST_CHECK(fs::exists( full_path ));
+ BOOST_CHECK(fs::is_directory( full_path ));
+
+ //std::cout << "\nIn directory: " << full_path.directory_string() << "\n\n";
+ fs::directory_iterator end_iter;
+ for ( fs::directory_iterator dir_itr( full_path ); dir_itr != end_iter; ++dir_itr ) {
+
+ try {
+ fs::path relPath(directory + "/" + dir_itr->path().filename().string());
+
+ // recurse down directories
+ if ( is_directory(dir_itr->status()) ) {
+ simulate(relPath.string(),pass);
+ continue;
+ }
+
+ // Only simulate file with .def file extension, i.e. ignore log files.
+// cout << "path = " << relPath << "\n";
+ if (File::getExt(relPath.filename().string()) != "def" && File::getExt(relPath.filename().string()) != "got") continue;
+
+// std::cout << "...............Simulating file " << relPath.string() << "\n";
+ Simulator simulator;
+ std::string errorMsg;
+ bool simPass = simulator.run(relPath.string(), errorMsg);
+ if (pass) {
+ // Test expected to pass
+ BOOST_CHECK_MESSAGE(simPass,"Simulator expected to pass for " << relPath << "\n" << errorMsg);
+
+ // Compare/ create log files
+ if (simPass) {
+ std::string logFileName = relPath.string() + ".log";
+ std::string goldenFileName = relPath.string() + ".glog";
+ BOOST_CHECK_MESSAGE(fs::exists(logFileName),"Log file " << logFileName << " should have been created");
+ if (fs::exists(goldenFileName) ) {
+
+ ofstream my_file(goldenFileName.c_str());
+ if (!my_file.good()) {
+ // read able file
+// cout << "file " << goldenFileName << " is readable \n";
+ std::string errorMessage;
+ BOOST_CHECK_MESSAGE(LogVerification::compareNodeStates(logFileName,goldenFileName,errorMessage),
+ "Log file comparison failed for " << relPath.string() << "\n" << errorMessage);
+ }
+ else {
+ // writable file, overwrite
+// cout << "Golden file " << goldenFileName << " is writeable, overwriting\n";
+ fs::remove(goldenFileName);
+ fs::copy_file(logFileName,goldenFileName);
+ }
+ }
+ else {
+ // Create golden log file so that it can be compared next time
+ // fs::copy_file(logFileName,goldenFileName);
+ }
+ }
+ }
+ else {
+ // test expected to fail
+ BOOST_CHECK_MESSAGE(!simPass,"Simulator expected to fail for " << relPath << "\n" << errorMsg);
+ }
+ }
+ catch ( const std::exception & ex )
+ {
+ std::cout << dir_itr->path().filename() << " " << ex.what() << std::endl;
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_simulate_good_defs )
+{
+ cout << "Simulator:: ...test_simulate_good_defs\n";
+
+ std::string path = File::test_data("CSim/test/data/good_defs","CSim");
+
+ // All the defs in this directory are expected to pass
+ simulate(path, true);
+}
+
+BOOST_AUTO_TEST_CASE( test_simulate_bad_defs )
+{
+ cout << "Simulator:: ...test_simulate_bad_defs\n";
+
+ std::string path = File::test_data("CSim/test/data/bad_defs","CSim");
+
+ // All the defs in this directory are expected to fail
+ simulate(path, false);
+
+ /// Destroy System singleton to avoid valgrind from complaining
+ System::destroy();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/CSim/test/TestSingleSimulator.cpp b/CSim/test/TestSingleSimulator.cpp
new file mode 100644
index 0000000..cab24cb
--- /dev/null
+++ b/CSim/test/TestSingleSimulator.cpp
@@ -0,0 +1,107 @@
+#define BOOST_TEST_MODULE TestSingleSimulator
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/// Use this class to test single simulation of definition file that we want to add
+/// to Test Simulator. This is a separate exe
+//============================================================================
+#include "Simulator.hpp"
+
+#include "File.hpp"
+#include "Log.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "TestUtil.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include "boost/progress.hpp"
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+
+using namespace std;
+using namespace ecf;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( SimulatorTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_repeat_date_for_loop2 )
+{
+ cout << "Simulator:: ...test_repeat_date_for_loop2\n";
+
+ //suite suite
+ // clock real <todays date>
+ // repeat date YMD 20091001 20091005 1 # yyyymmdd
+ // family family
+ // repeat date YMD 20091001 20091005 1 # yyyymmdd
+ // task t
+ // time 10:00
+ // time 11:00
+ // endfamily
+ //endsuite
+
+ // Each task should be run 5 * 5 * 2 = 50 times, ie every day from from 1st Oct -> 5 Oct 5*5 times * 2 time slots
+ Defs theDefs;
+ {
+ // start at specific time other wise time dependent checks will not verify
+ suite_ptr suite = theDefs.add_suite("test_repeat_date_for_loop2");
+ suite->addRepeat( RepeatDate("YMD",20091001,20091005,1)); // repeat contents 5 times
+ suite->addVerify( VerifyAttr(NState::COMPLETE,5) );
+
+ ClockAttr clockAttr;
+ clockAttr.date(1,10,2009);
+ suite->addClock( clockAttr );
+
+ family_ptr fam = suite->add_family( "family" );
+ fam->addRepeat( RepeatDate("YMD",20091001,20091005,1)); // repeat contents 5 times
+ fam->addVerify( VerifyAttr(NState::COMPLETE,25) );
+
+ task_ptr task = fam->add_task("t");
+ task->addTime( ecf::TimeAttr( TimeSlot(10,0) ) );
+ task->addTime( ecf::TimeAttr( TimeSlot(11,0) ) );
+ task->addVerify( VerifyAttr(NState::COMPLETE,50) ); // task should complete 50 times
+
+ // cout << theDefs << "\n";
+ }
+
+ Simulator simulator;
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE(simulator.run(theDefs, TestUtil::testDataLocation("test_repeat_date_for_loop2.def"), errorMsg),errorMsg);
+}
+
+
+//BOOST_AUTO_TEST_CASE( test_single_from_file )
+//{
+// cout << "Simulator:: ...test_single_from_file\n";
+//
+////std::string path = File::test_data("CSim/test/data/good_defs/operations/loop.def","CSim");
+// std::string path = File::test_data("CSim/test/data/good_defs/ECFLOW-130/radarlvl2.def","CSim");
+//
+// Simulator simulator;
+// std::string errorMsg;
+// bool passed = simulator.run(path, errorMsg);
+//
+// BOOST_REQUIRE_MESSAGE(passed, path << " failed simulation \n" << errorMsg);
+//}
+
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/CSim/test/TestTime.cpp b/CSim/test/TestTime.cpp
new file mode 100644
index 0000000..b38f161
--- /dev/null
+++ b/CSim/test/TestTime.cpp
@@ -0,0 +1,380 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include "Simulator.hpp"
+#include "File.hpp"
+#include "Log.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "TestUtil.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include "boost/progress.hpp"
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+
+using namespace std;
+using namespace ecf;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+
+namespace fs = boost::filesystem;
+
+/// Simulate definition files that are created on then fly. This allows us to create
+/// tests with todays date/time this speeds up the testr, we can also validate
+/// Defs file, to check for correctness
+
+BOOST_AUTO_TEST_SUITE( SimulatorTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_time )
+{
+ cout << "Simulator:: ...test_time\n";
+
+ //# Note: we have to use relative paths, since these tests are relocatable
+ //suite suite
+ // clock real <todays date>
+ // family family
+ // task t1
+ // time <start>
+ // endfamily
+ //endsuite
+
+ // Initialise clock with todays date then create a time attribute + minutes
+ // such that the task should only run once, in the next minute
+ boost::posix_time::ptime theLocalTime = Calendar::second_clock_time();
+ boost::posix_time::ptime time_plus_minute = theLocalTime + minutes(1);
+
+ Defs theDefs;
+ {
+ suite_ptr suite = theDefs.add_suite("test_time");
+ ClockAttr clockAttr(theLocalTime,false/*false means use real clock*/);
+ suite->addClock( clockAttr );
+
+ family_ptr fam = suite->add_family( "family" );
+ task_ptr task = fam->add_task("t");
+ task->addTime( ecf::TimeAttr( TimeSlot(time_plus_minute.time_of_day()) ) );
+ task->addVerify( VerifyAttr(NState::COMPLETE,1) ); // expect task to complete 1 time
+
+ // cout << theDefs << "\n";
+ }
+
+ Simulator simulator;
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE(simulator.run(theDefs, TestUtil::testDataLocation("test_time.def"), errorMsg),errorMsg);
+}
+
+BOOST_AUTO_TEST_CASE( test_time_series )
+{
+ cout << "Simulator:: ...test_time_series\n";
+
+ //suite suite
+ // clock real <sunday>
+ // family family
+ // task t1
+ // time 00:30 23:59 04:00 # should run 6 times 00:30 4:30 8:30 12:30 16:30 20:30
+ // endfamily
+ //endsuite
+
+ // Initialise real clock on a Moday, such that task should _only_ run
+ // on Monday since we are using a hybrid clock
+ Defs theDefs;
+ {
+ ClockAttr clockAttr(true/*false means use hybrid clock*/);
+ clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
+ suite_ptr suite = theDefs.add_suite("test_time_series");
+ suite->addClock( clockAttr );
+
+ family_ptr fam = suite->add_family( "family" );
+ task_ptr task = fam->add_task("t");
+ TimeSeries timeSeries(TimeSlot(00,30), TimeSlot(23,59), TimeSlot(4,0), false/* relative */);
+
+ task->addTime( TimeAttr( timeSeries ));
+ task->addVerify( VerifyAttr(NState::COMPLETE,6) ); // expect task to complete 6 times
+
+ // cout << theDefs << "\n";
+ }
+
+ Simulator simulator;
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE(simulator.run(theDefs, TestUtil::testDataLocation("test_time_series.def"), errorMsg),errorMsg);
+}
+
+BOOST_AUTO_TEST_CASE( test_time_and_date )
+{
+ cout << "Simulator:: ...test_time_and_date\n";
+
+ //# Note: we have to use relative paths, since these tests are relocatable
+ //suite suite
+ // clock real <todays date>
+ // family family
+ // task t1
+ // date <today date>
+ // time <start>
+ // endfamily
+ //endsuite
+
+
+ Defs theDefs;
+ {
+ // Initialise clock with todays date then create a time attribute + minutes
+ // such that the task should only run once, in the next minute
+ boost::posix_time::ptime theLocalTime = Calendar::second_clock_time();
+ boost::gregorian::date todaysDate = theLocalTime.date();
+ boost::posix_time::ptime time_plus_minute = theLocalTime + minutes(1);
+
+ ClockAttr clockAttr(theLocalTime,false/*false means use real clock*/);
+ suite_ptr suite = theDefs.add_suite("test_time_and_date");
+ suite->addClock( clockAttr );
+
+ family_ptr fam = suite->add_family( "family" );
+ task_ptr task = fam->add_task("t");
+ task->addDate( DateAttr(todaysDate.day(),todaysDate.month(),todaysDate.year()) );
+ task->addTime( ecf::TimeAttr( TimeSlot(time_plus_minute.time_of_day()) ) );
+ task->addVerify( VerifyAttr(NState::COMPLETE,1) ); // expect task to complete 1 time
+
+ // cout << theDefs << "\n";
+ }
+
+ Simulator simulator;
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE(simulator.run(theDefs, TestUtil::testDataLocation("test_time_and_date.def"), errorMsg),errorMsg);
+}
+
+BOOST_AUTO_TEST_CASE( test_time_and_tomorrows_date )
+{
+ cout << "Simulator:: ...test_time_and_tomorrows_date\n";
+
+ //# Note: we have to use relative paths, since these tests are relocatable
+ //suite suite
+ // clock real <tomorrows date>
+ // family family
+ // task t1
+ // date <tomorrows date>
+ // time <start>
+ // endfamily
+ //endsuite
+
+
+ Defs theDefs;
+ {
+ // Initialise clock with todays date then create a time attribute + minutes
+ // such that the task should only run once, in the next minute
+ boost::posix_time::ptime theLocalTime = Calendar::second_clock_time();
+ boost::gregorian::date tomorrows_date = theLocalTime.date();
+ tomorrows_date += days(1);
+ boost::posix_time::ptime time_plus_minute = theLocalTime + minutes(1);
+
+ ClockAttr clockAttr(theLocalTime,false/*false means use real clock*/);
+ suite_ptr suite = theDefs.add_suite("test_time_and_tomorrows_date");
+ suite->addClock( clockAttr );
+
+ family_ptr fam = suite->add_family( "family" );
+ task_ptr task = fam->add_task("t");
+ task->addDate( DateAttr(tomorrows_date.day(),tomorrows_date.month(),tomorrows_date.year()) );
+ task->addTime( ecf::TimeAttr( TimeSlot(time_plus_minute.time_of_day()) ) );
+ task->addVerify( VerifyAttr(NState::COMPLETE,1) ); // expect task to complete 1 time
+
+ // cout << theDefs << "\n";
+ }
+
+ Simulator simulator;
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE(simulator.run(theDefs, TestUtil::testDataLocation("test_time_and_tomorrows_date.def"), errorMsg),errorMsg);
+}
+
+
+BOOST_AUTO_TEST_CASE( test_multiple_times_and_dates )
+{
+ cout << "Simulator:: ...test_multiple_times_and_dates\n";
+
+ //# Note: we have to use relative paths, since these tests are relocatable
+ //suite suite
+ // clock real <todays date>
+ // family family
+ // repeat integer 0 1 1 # repeat twice
+ // task t1
+ // date <today date>
+ // date <tomrrows date>
+ // time <start>
+ // time <start>
+ // endfamily
+ //endsuite
+ Defs theDefs;
+ {
+ // Initialise clock with todays date then create a time attribute + minutes
+ // Note: we don't use:
+ // boost::posix_time::ptime theLocalTime = Calendar::second_clock_time();
+ // because if run at late we can end up with illegal for the hour, ie. > 24
+
+ boost::gregorian::date todaysDate(2009,2,10);
+ ptime theLocalTime(todaysDate, hours(3));
+ boost::gregorian::date tomarrows_date = todaysDate + date_duration(1);
+ boost::posix_time::time_duration td_plus_minute = theLocalTime.time_of_day() + minutes(1);
+ boost::posix_time::time_duration td_plus_hour = theLocalTime.time_of_day() + hours(1);
+
+ ClockAttr clockAttr(theLocalTime,false/*false means use real clock*/);
+ suite_ptr suite = theDefs.add_suite("test_multiple_times_and_dates");
+ suite->addClock( clockAttr );
+
+
+ family_ptr fam = suite->add_family( "family" );
+ //fam->addRepeat( RepeatInteger("rep",0,1,1) );
+ task_ptr task = fam->add_task("t");
+ task->addDate( DateAttr(todaysDate.day(),todaysDate.month(),todaysDate.year()) );
+ task->addDate( DateAttr(tomarrows_date.day(),tomarrows_date.month(),tomarrows_date.year()) );
+ task->addTime( TimeAttr( TimeSlot(td_plus_minute) ));
+ task->addTime( TimeAttr( TimeSlot(td_plus_hour) ));
+ task->addVerify( VerifyAttr(NState::COMPLETE,4) ); // expect task to complete 4 time
+
+ // cout << theDefs << "\n";
+ }
+
+ Simulator simulator;
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE(simulator.run(theDefs,TestUtil::testDataLocation("test_multiple_times_and_dates.def"), errorMsg),errorMsg);
+}
+
+BOOST_AUTO_TEST_CASE( test_multiple_times_and_dates_hybrid )
+{
+ cout << "Simulator:: ...test_multiple_times_and_dates_hybrid\n";
+
+ //# Note: we have to use relative paths, since these tests are relocatable
+ //suite suite
+ // clock hybrid <todays date>
+ // family family
+ // task t1
+ // date <today date>
+ // date <tomrrows date>
+ // time <start>
+ // time <start>
+ // endfamily
+ //endsuite
+ Defs theDefs;
+ {
+ // Initialise clock with todays date then create a time attribute + minutes
+ // such that the task should only run once, in the next minute
+ boost::posix_time::ptime theLocalTime = boost::posix_time::ptime(date(2012,2,22),time_duration(10,20,0));
+ boost::gregorian::date todaysDate = theLocalTime.date();
+ boost::gregorian::date tomorrows_date = todaysDate + date_duration(1);
+ boost::posix_time::time_duration td_plus_minute = theLocalTime.time_of_day() + minutes(1);
+ boost::posix_time::time_duration td_plus_10_minute = theLocalTime.time_of_day() + minutes(10);
+
+ suite_ptr suite = theDefs.add_suite("test_multiple_times_and_dates_hybrid");
+ suite->addClock( ClockAttr(theLocalTime,true) ); // true means use hybrid clock
+
+ family_ptr fam = suite->add_family("family");
+ task_ptr task = fam->add_task("t");
+ task->addDate( DateAttr(todaysDate.day(),todaysDate.month(),todaysDate.year()) );
+ task->addDate( DateAttr(tomorrows_date.day(),tomorrows_date.month(),tomorrows_date.year()) );
+ task->addTime( TimeAttr( TimeSlot(td_plus_minute) ));
+ task->addTime( TimeAttr( TimeSlot(td_plus_10_minute) ));
+ task->addVerify( VerifyAttr(NState::COMPLETE,2) ); // expect task to complete 2 time
+ //cout << theDefs << "\n";
+ }
+
+ Simulator simulator;
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE(simulator.run(theDefs, TestUtil::testDataLocation("test_multiple_times_and_dates_hybrid.def"), errorMsg),errorMsg);
+}
+
+BOOST_AUTO_TEST_CASE( test_multiple_times_and_days )
+{
+ cout << "Simulator:: ...test_multiple_times_and_days\n";
+
+ //suite suite
+ // clock real <sunday>
+ // family family
+ // rep integer 0 1 1 # repeat twice
+ // task t1
+ // day monday
+ // day tuesday
+ // time <start>
+ // time <start>
+ // endfamily
+ //endsuite
+
+ // Initialise real clock on a sunday, such that task should run on Monday & tuesday twice
+ Defs theDefs;
+ {
+ ClockAttr clockAttr(false/*false means use real clock*/);
+ clockAttr.date(11,10,2009); // 11 October 2009 was a sunday
+ suite_ptr suite = theDefs.add_suite("test_multiple_times_and_days");
+ suite->addClock( clockAttr );
+
+ family_ptr fam = suite->add_family("family");
+ //fam->addRepeat( RepeatInteger("rep",0,1,1) );
+ task_ptr task = fam->add_task("t");
+ task->addDay( DayAttr(DayAttr::MONDAY) );
+ task->addDay( DayAttr(DayAttr::TUESDAY) );
+ task->addTime( TimeAttr( TimeSlot(10,0) ));
+ task->addTime( TimeAttr( TimeSlot(20,0) ));
+ task->addVerify( VerifyAttr(NState::COMPLETE,4) ); // expect task to complete 4 time
+
+ // cout << theDefs << "\n";
+ }
+
+ Simulator simulator;
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE(simulator.run(theDefs, TestUtil::testDataLocation("test_multiple_times_and_days.def"), errorMsg),errorMsg);
+}
+
+BOOST_AUTO_TEST_CASE( test_multiple_times_and_days_hybrid )
+{
+ cout << "Simulator:: ...test_multiple_times_and_days_hybrid\n";
+
+ //suite suite
+ // clock real <sunday>
+ // family family
+ // task t1
+ // day monday
+ // day tuesday
+ // time <start>
+ // time <start>
+ // endfamily
+ //endsuite
+
+ // Initialise real clock on a Monday, such that task should _only_ run
+ // on Monday since we are using a hybrid clock
+ Defs theDefs;
+ {
+ ClockAttr clockAttr(true/*false means use hybrid clock*/);
+ clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
+ suite_ptr suite = theDefs.add_suite("test_multiple_times_and_days_hybrid");
+ suite->addClock( clockAttr );
+
+ family_ptr fam = suite->add_family("family");
+ task_ptr task = fam->add_task("t");
+ task->addDay( DayAttr(DayAttr::MONDAY) );
+ task->addDay( DayAttr(DayAttr::TUESDAY) );
+ task->addTime( TimeAttr( TimeSlot(10,0) ));
+ task->addTime( TimeAttr( TimeSlot(11,0) ));
+ task->addTime( TimeAttr( TimeSlot(20,0) ));
+ task->addVerify( VerifyAttr(NState::COMPLETE,3) ); // expect task to complete 3 times
+
+ // cout << theDefs << "\n";
+ }
+
+ Simulator simulator;
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE(simulator.run(theDefs, TestUtil::testDataLocation("test_multiple_times_and_days_hybrid.def"), errorMsg),errorMsg);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/CSim/test/TestToday.cpp b/CSim/test/TestToday.cpp
new file mode 100644
index 0000000..f1a1133
--- /dev/null
+++ b/CSim/test/TestToday.cpp
@@ -0,0 +1,158 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include "Simulator.hpp"
+#include "File.hpp"
+#include "Log.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "TestUtil.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include "boost/progress.hpp"
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+
+using namespace std;
+using namespace ecf;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+
+namespace fs = boost::filesystem;
+
+/// Simulate definition files that are created on then fly. This allows us to create
+/// tests with todays date/time this speeds up the testr, we can also validate
+/// Defs file, to check for correctness
+
+BOOST_AUTO_TEST_SUITE( SimulatorTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_today )
+{
+ cout << "Simulator:: ...test_today\n";
+
+ //suite suite
+ // clock real <fixed date>
+ // family family
+ // task t1
+ // today <start> # +1 minute
+ // today <start> # +2 minute
+ // endfamily
+ //endsuite
+ Defs theDefs;
+ {
+ // Initialise clock then create a today attribute + minutes
+ // such that the task should only run once, in the next minute
+ ptime theLocalTime = boost::posix_time::ptime(date(2010,6,21),time_duration(1,2,0));
+ boost::posix_time::ptime time_plus_minute = theLocalTime + minutes(1);
+ boost::posix_time::ptime time_plus_10_minute = theLocalTime + minutes(10);
+
+ suite_ptr suite = theDefs.add_suite( "test_today" );
+ ClockAttr clockAttr(theLocalTime,false/*false means use real clock*/);
+ suite->addClock( clockAttr );
+
+ family_ptr fam = suite->add_family( "family" );
+ task_ptr task = fam->add_task( "t" );
+ task->addToday( ecf::TodayAttr( TimeSlot(time_plus_minute.time_of_day()) ) );
+ task->addToday( ecf::TodayAttr( TimeSlot(time_plus_10_minute.time_of_day()) ) );
+ task->addVerify( VerifyAttr(NState::COMPLETE,2) ); // expect task to complete 2 time
+ // cout << theDefs << "\n";
+ }
+
+ Simulator simulator;
+ std::string errorMsg;
+ bool result = simulator.run(theDefs, TestUtil::testDataLocation("test_today.def"), errorMsg);
+
+ BOOST_CHECK_MESSAGE(result,errorMsg);
+}
+
+BOOST_AUTO_TEST_CASE( test_today_time_series )
+{
+ cout << "Simulator:: ...test_today_time_series\n";
+
+ //suite suite
+ // clock real <monday>
+ // family family
+ // task t1
+ // today 00:30 18:59 04:00 # should run 5 times 00:30 4:30 8:30 12:30 16:30
+ // endfamily
+ //endsuite
+
+ Defs theDefs;
+ {
+ suite_ptr suite = theDefs.add_suite( "test_today_time_series" );
+ ClockAttr clockAttr(true/*false means use hybrid clock*/);
+ clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
+ suite->addClock( clockAttr );
+
+ family_ptr fam = suite->add_family( "family" );
+ task_ptr task = fam->add_task( "t" );
+ TimeSeries timeSeries(TimeSlot(00,30), TimeSlot(18,59), TimeSlot(4,0), false/* relative */);
+
+ task->addToday( TodayAttr( timeSeries ));
+ task->addVerify( VerifyAttr(NState::COMPLETE,5) );
+ // cout << theDefs << "\n";
+ }
+
+ Simulator simulator;
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE(simulator.run(theDefs, TestUtil::testDataLocation("test_today_time_series.def") , errorMsg),errorMsg);
+}
+
+BOOST_AUTO_TEST_CASE( test_today_time_and_date )
+{
+ cout << "Simulator:: ...test_today_time_and_date\n";
+
+ //suite suite
+ // clock real <todays date>
+ // family family
+ // task t1
+ // date <today date>
+ // time <start>
+ // today <start>
+ // endfamily
+ //endsuite
+ Defs theDefs;
+ {
+ // Task will only run if all time dependencies are satisfied
+ boost::posix_time::ptime theLocalTime = Calendar::second_clock_time();
+ boost::gregorian::date todaysDate = theLocalTime.date();
+ boost::posix_time::ptime time_plus_minute = theLocalTime + minutes(1);
+
+ suite_ptr suite = theDefs.add_suite( "test_today_time_and_date" );
+ ClockAttr clockAttr(theLocalTime,false/*false means use real clock*/);
+ suite->addClock( clockAttr );
+
+ family_ptr fam = suite->add_family( "family" );
+ task_ptr task = fam->add_task( "t" );
+ task->addDate( DateAttr(todaysDate.day(),todaysDate.month(),todaysDate.year()) );
+ task->addTime( ecf::TimeAttr( TimeSlot(time_plus_minute.time_of_day()) ) );
+ task->addToday( ecf::TodayAttr( TimeSlot(time_plus_minute.time_of_day()) ) );
+
+ task->addVerify( VerifyAttr(NState::COMPLETE,1) );
+ // cout << theDefs << "\n";
+ }
+
+ Simulator simulator;
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE(simulator.run(theDefs,TestUtil::testDataLocation("test_today_time_and_date.def"),errorMsg),errorMsg);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/CSim/test/TestUtil.cpp b/CSim/test/TestUtil.cpp
new file mode 100644
index 0000000..a6c22ef
--- /dev/null
+++ b/CSim/test/TestUtil.cpp
@@ -0,0 +1,28 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include "TestUtil.hpp"
+#include "File.hpp"
+
+using namespace std;
+using namespace ecf;
+
+std::string TestUtil::testDataLocation( const std::string& defsFile)
+{
+ std::string testData = File::test_data("CSim/test/data","CSim");
+
+ testData += "/";
+ testData += defsFile;
+ return testData;
+}
diff --git a/CSim/test/TestUtil.hpp b/CSim/test/TestUtil.hpp
new file mode 100644
index 0000000..a94793e
--- /dev/null
+++ b/CSim/test/TestUtil.hpp
@@ -0,0 +1,36 @@
+#ifndef TESTUTIL_HPP_
+#define TESTUTIL_HPP_
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <boost/noncopyable.hpp>
+#include <string>
+#include <map>
+#include "Defs.hpp"
+
+// This class provides a test harness for running defs file in a client server environment
+// To avoid Address in use errors, we can have client/server use a different port number
+// This is more important when doing instrumentation in HP-UX, as that can take a long time.
+//
+class TestUtil : private boost::noncopyable {
+public:
+
+
+ /// Returns the location of the defs file, such thats it in the test data area
+ static std::string testDataLocation( const std::string& defsFile);
+
+};
+#endif /* TESTUTIL_HPP_ */
diff --git a/ecflow_4_0_7/CSim/test/data/bad_defs/today.def b/CSim/test/data/bad_defs/today.def
similarity index 100%
rename from ecflow_4_0_7/CSim/test/data/bad_defs/today.def
rename to CSim/test/data/bad_defs/today.def
diff --git a/ecflow_4_0_7/CSim/test/data/bad_defs/xde.def b/CSim/test/data/bad_defs/xde.def
similarity index 100%
rename from ecflow_4_0_7/CSim/test/data/bad_defs/xde.def
rename to CSim/test/data/bad_defs/xde.def
diff --git a/CSim/test/data/bad_defs/xde.def.log b/CSim/test/data/bad_defs/xde.def.log
new file mode 100644
index 0000000..772b223
--- /dev/null
+++ b/CSim/test/data/bad_defs/xde.def.log
@@ -0,0 +1,5 @@
+LOG:[12:27:20 12.5.2016] queued: /dfo
+LOG:[12:27:20 12.5.2016] complete: /dfo
+LOG:[12:27:20 12.5.2016] complete: /
+LOG:[12:27:20 12.5.2016] queued: /dfi
+LOG:[12:27:20 12.5.2016] complete: /dfi
diff --git a/ecflow_4_0_7/CSim/test/data/good_defs/ECFLOW-130/radarlvl2.def b/CSim/test/data/good_defs/ECFLOW-130/radarlvl2.def
similarity index 100%
rename from ecflow_4_0_7/CSim/test/data/good_defs/ECFLOW-130/radarlvl2.def
rename to CSim/test/data/good_defs/ECFLOW-130/radarlvl2.def
diff --git a/CSim/test/data/good_defs/ECFLOW-130/radarlvl2.def.log b/CSim/test/data/good_defs/ECFLOW-130/radarlvl2.def.log
new file mode 100644
index 0000000..e13d22e
--- /dev/null
+++ b/CSim/test/data/good_defs/ECFLOW-130/radarlvl2.def.log
@@ -0,0 +1,3131 @@
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2_cleanup
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_ref2grb
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_reflectivity_mosaic
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] queued: /radarlvl2
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] active: /radarlvl2
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] active: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_canrad
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod/jradar_level2
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2/prod
+LOG:[12:27:19 12.5.2016] complete: /radarlvl2
+LOG:[12:27:19 12.5.2016] complete: /
+MSG:[12:27:19 12.5.2016] Simulation complete in 23:55:00
diff --git a/ecflow_4_0_7/CSim/test/data/good_defs/SingleDefsTest/test.def b/CSim/test/data/good_defs/SingleDefsTest/test.def
similarity index 100%
copy from ecflow_4_0_7/CSim/test/data/good_defs/SingleDefsTest/test.def
copy to CSim/test/data/good_defs/SingleDefsTest/test.def
diff --git a/CSim/test/data/good_defs/SingleDefsTest/test.def.glog b/CSim/test/data/good_defs/SingleDefsTest/test.def.glog
new file mode 100644
index 0000000..33e7bbf
--- /dev/null
+++ b/CSim/test/data/good_defs/SingleDefsTest/test.def.glog
@@ -0,0 +1,42 @@
+LOG:[15:45:48 22.2.2011] queued: /suite
+LOG:[15:45:48 22.2.2011] queued: /suite/family
+LOG:[15:45:48 22.2.2011] queued: /suite/family/t
+LOG:[15:45:48 22.2.2011] submitted: /suite/family/t
+LOG:[15:45:48 22.2.2011] submitted: /suite/family
+LOG:[15:45:48 22.2.2011] submitted: /suite
+LOG:[15:45:48 22.2.2011] submitted: /
+LOG:[15:45:48 22.2.2011] active: /suite/family/t
+LOG:[15:45:48 22.2.2011] active: /suite/family
+LOG:[15:45:48 22.2.2011] active: /suite
+LOG:[15:45:48 22.2.2011] active: /
+LOG:[15:45:48 22.2.2011] complete: /suite/family/t
+LOG:[15:45:48 22.2.2011] queued: /suite/family/t
+LOG:[15:45:48 22.2.2011] queued: /suite/family
+LOG:[15:45:48 22.2.2011] queued: /suite
+LOG:[15:45:48 22.2.2011] queued: /
+LOG:[15:45:48 22.2.2011] submitted: /suite/family/t
+LOG:[15:45:48 22.2.2011] submitted: /suite/family
+LOG:[15:45:48 22.2.2011] submitted: /suite
+LOG:[15:45:48 22.2.2011] submitted: /
+LOG:[15:45:48 22.2.2011] active: /suite/family/t
+LOG:[15:45:48 22.2.2011] active: /suite/family
+LOG:[15:45:48 22.2.2011] active: /suite
+LOG:[15:45:48 22.2.2011] active: /
+LOG:[15:45:48 22.2.2011] complete: /suite/family/t
+LOG:[15:45:48 22.2.2011] queued: /suite/family/t
+LOG:[15:45:48 22.2.2011] queued: /suite/family
+LOG:[15:45:48 22.2.2011] queued: /suite
+LOG:[15:45:48 22.2.2011] queued: /
+LOG:[15:45:48 22.2.2011] submitted: /suite/family/t
+LOG:[15:45:48 22.2.2011] submitted: /suite/family
+LOG:[15:45:48 22.2.2011] submitted: /suite
+LOG:[15:45:48 22.2.2011] submitted: /
+LOG:[15:45:48 22.2.2011] active: /suite/family/t
+LOG:[15:45:48 22.2.2011] active: /suite/family
+LOG:[15:45:48 22.2.2011] active: /suite
+LOG:[15:45:48 22.2.2011] active: /
+LOG:[15:45:48 22.2.2011] complete: /suite/family/t
+LOG:[15:45:48 22.2.2011] complete: /suite/family
+LOG:[15:45:48 22.2.2011] complete: /suite
+LOG:[15:45:48 22.2.2011] complete: /
+MSG:[15:45:48 22.2.2011] Simulation complete in 00:03:00
diff --git a/CSim/test/data/good_defs/SingleDefsTest/test.def.log b/CSim/test/data/good_defs/SingleDefsTest/test.def.log
new file mode 100644
index 0000000..1252b74
--- /dev/null
+++ b/CSim/test/data/good_defs/SingleDefsTest/test.def.log
@@ -0,0 +1,42 @@
+LOG:[12:27:19 12.5.2016] queued: /suite
+LOG:[12:27:19 12.5.2016] queued: /suite/family
+LOG:[12:27:19 12.5.2016] queued: /suite/family/t
+LOG:[12:27:19 12.5.2016] submitted: /suite/family/t
+LOG:[12:27:19 12.5.2016] submitted: /suite/family
+LOG:[12:27:19 12.5.2016] submitted: /suite
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /suite/family/t
+LOG:[12:27:19 12.5.2016] active: /suite/family
+LOG:[12:27:19 12.5.2016] active: /suite
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /suite/family/t
+LOG:[12:27:19 12.5.2016] queued: /suite/family/t
+LOG:[12:27:19 12.5.2016] queued: /suite/family
+LOG:[12:27:19 12.5.2016] queued: /suite
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /suite/family/t
+LOG:[12:27:19 12.5.2016] submitted: /suite/family
+LOG:[12:27:19 12.5.2016] submitted: /suite
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /suite/family/t
+LOG:[12:27:19 12.5.2016] active: /suite/family
+LOG:[12:27:19 12.5.2016] active: /suite
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /suite/family/t
+LOG:[12:27:19 12.5.2016] queued: /suite/family/t
+LOG:[12:27:19 12.5.2016] queued: /suite/family
+LOG:[12:27:19 12.5.2016] queued: /suite
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /suite/family/t
+LOG:[12:27:19 12.5.2016] submitted: /suite/family
+LOG:[12:27:19 12.5.2016] submitted: /suite
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /suite/family/t
+LOG:[12:27:19 12.5.2016] active: /suite/family
+LOG:[12:27:19 12.5.2016] active: /suite
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /suite/family/t
+LOG:[12:27:19 12.5.2016] complete: /suite/family
+LOG:[12:27:19 12.5.2016] complete: /suite
+LOG:[12:27:19 12.5.2016] complete: /
+MSG:[12:27:19 12.5.2016] Simulation complete in 00:03:00
diff --git a/ecflow_4_0_7/CSim/test/data/good_defs/cron/cron.def b/CSim/test/data/good_defs/cron/cron.def
similarity index 100%
rename from ecflow_4_0_7/CSim/test/data/good_defs/cron/cron.def
rename to CSim/test/data/good_defs/cron/cron.def
diff --git a/CSim/test/data/good_defs/cron/cron.def.log b/CSim/test/data/good_defs/cron/cron.def.log
new file mode 100644
index 0000000..0c12d35
--- /dev/null
+++ b/CSim/test/data/good_defs/cron/cron.def.log
@@ -0,0 +1,146 @@
+LOG:[12:25:36 12.5.2016] queued: /cron
+LOG:[12:25:36 12.5.2016] queued: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] queued: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] submitted: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] submitted: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] submitted: /cron
+LOG:[12:25:36 12.5.2016] submitted: /
+LOG:[12:25:36 12.5.2016] active: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] active: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] active: /cron
+LOG:[12:25:36 12.5.2016] active: /
+LOG:[12:25:36 12.5.2016] complete: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] queued: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] queued: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] queued: /cron
+LOG:[12:25:36 12.5.2016] queued: /
+LOG:[12:25:36 12.5.2016] submitted: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] submitted: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] submitted: /cron
+LOG:[12:25:36 12.5.2016] submitted: /
+LOG:[12:25:36 12.5.2016] active: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] active: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] active: /cron
+LOG:[12:25:36 12.5.2016] active: /
+LOG:[12:25:36 12.5.2016] complete: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] queued: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] queued: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] queued: /cron
+LOG:[12:25:36 12.5.2016] queued: /
+LOG:[12:25:36 12.5.2016] submitted: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] submitted: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] submitted: /cron
+LOG:[12:25:36 12.5.2016] submitted: /
+LOG:[12:25:36 12.5.2016] active: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] active: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] active: /cron
+LOG:[12:25:36 12.5.2016] active: /
+LOG:[12:25:36 12.5.2016] complete: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] queued: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] queued: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] queued: /cron
+LOG:[12:25:36 12.5.2016] queued: /
+LOG:[12:25:36 12.5.2016] submitted: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] submitted: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] submitted: /cron
+LOG:[12:25:36 12.5.2016] submitted: /
+LOG:[12:25:36 12.5.2016] active: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] active: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] active: /cron
+LOG:[12:25:36 12.5.2016] active: /
+LOG:[12:25:36 12.5.2016] complete: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] queued: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] queued: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] queued: /cron
+LOG:[12:25:36 12.5.2016] queued: /
+LOG:[12:25:36 12.5.2016] submitted: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] submitted: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] submitted: /cron
+LOG:[12:25:36 12.5.2016] submitted: /
+LOG:[12:25:36 12.5.2016] active: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] active: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] active: /cron
+LOG:[12:25:36 12.5.2016] active: /
+LOG:[12:25:36 12.5.2016] complete: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] queued: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] queued: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] queued: /cron
+LOG:[12:25:36 12.5.2016] queued: /
+LOG:[12:25:36 12.5.2016] submitted: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] submitted: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] submitted: /cron
+LOG:[12:25:36 12.5.2016] submitted: /
+LOG:[12:25:36 12.5.2016] active: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] active: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] active: /cron
+LOG:[12:25:36 12.5.2016] active: /
+LOG:[12:25:36 12.5.2016] complete: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] queued: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] queued: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] queued: /cron
+LOG:[12:25:36 12.5.2016] queued: /
+LOG:[12:25:36 12.5.2016] submitted: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] submitted: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] submitted: /cron
+LOG:[12:25:36 12.5.2016] submitted: /
+LOG:[12:25:36 12.5.2016] active: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] active: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] active: /cron
+LOG:[12:25:36 12.5.2016] active: /
+LOG:[12:25:36 12.5.2016] complete: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] queued: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] queued: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] queued: /cron
+LOG:[12:25:36 12.5.2016] queued: /
+LOG:[12:25:36 12.5.2016] submitted: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] submitted: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] submitted: /cron
+LOG:[12:25:36 12.5.2016] submitted: /
+LOG:[12:25:36 12.5.2016] active: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] active: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] active: /cron
+LOG:[12:25:36 12.5.2016] active: /
+LOG:[12:25:36 12.5.2016] complete: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] queued: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] queued: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] queued: /cron
+LOG:[12:25:36 12.5.2016] queued: /
+LOG:[12:25:36 12.5.2016] submitted: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] submitted: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] submitted: /cron
+LOG:[12:25:36 12.5.2016] submitted: /
+LOG:[12:25:36 12.5.2016] active: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] active: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] active: /cron
+LOG:[12:25:36 12.5.2016] active: /
+LOG:[12:25:36 12.5.2016] complete: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] queued: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] queued: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] queued: /cron
+LOG:[12:25:36 12.5.2016] queued: /
+LOG:[12:25:36 12.5.2016] submitted: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] submitted: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] submitted: /cron
+LOG:[12:25:36 12.5.2016] submitted: /
+LOG:[12:25:36 12.5.2016] active: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] active: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] active: /cron
+LOG:[12:25:36 12.5.2016] active: /
+LOG:[12:25:36 12.5.2016] complete: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] queued: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] queued: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] queued: /cron
+LOG:[12:25:36 12.5.2016] queued: /
+LOG:[12:25:36 12.5.2016] submitted: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] submitted: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] submitted: /cron
+LOG:[12:25:36 12.5.2016] submitted: /
+LOG:[12:25:36 12.5.2016] active: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] active: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] active: /cron
+LOG:[12:25:36 12.5.2016] active: /
+LOG:[12:25:36 12.5.2016] complete: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] queued: /cron/cronFamily/t
+LOG:[12:25:36 12.5.2016] queued: /cron/cronFamily
+LOG:[12:25:36 12.5.2016] queued: /cron
+LOG:[12:25:36 12.5.2016] queued: /
diff --git a/ecflow_4_0_7/CSim/test/data/good_defs/cron/cron2.def b/CSim/test/data/good_defs/cron/cron2.def
similarity index 100%
rename from ecflow_4_0_7/CSim/test/data/good_defs/cron/cron2.def
rename to CSim/test/data/good_defs/cron/cron2.def
diff --git a/CSim/test/data/good_defs/cron/cron2.def.log b/CSim/test/data/good_defs/cron/cron2.def.log
new file mode 100644
index 0000000..f2b808c
--- /dev/null
+++ b/CSim/test/data/good_defs/cron/cron2.def.log
@@ -0,0 +1,55 @@
+LOG:[12:25:36 12.5.2016] queued: /cron2
+LOG:[12:25:36 12.5.2016] queued: /cron2/cronFamily
+LOG:[12:25:36 12.5.2016] queued: /cron2/cronFamily/t
+LOG:[12:25:36 12.5.2016] submitted: /cron2/cronFamily/t
+LOG:[12:25:36 12.5.2016] submitted: /cron2/cronFamily
+LOG:[12:25:36 12.5.2016] submitted: /cron2
+LOG:[12:25:36 12.5.2016] submitted: /
+LOG:[12:25:36 12.5.2016] active: /cron2/cronFamily/t
+LOG:[12:25:36 12.5.2016] active: /cron2/cronFamily
+LOG:[12:25:36 12.5.2016] active: /cron2
+LOG:[12:25:36 12.5.2016] active: /
+LOG:[12:25:36 12.5.2016] complete: /cron2/cronFamily/t
+LOG:[12:25:36 12.5.2016] queued: /cron2/cronFamily/t
+LOG:[12:25:36 12.5.2016] queued: /cron2/cronFamily
+LOG:[12:25:36 12.5.2016] queued: /cron2
+LOG:[12:25:36 12.5.2016] queued: /
+LOG:[12:25:36 12.5.2016] submitted: /cron2/cronFamily/t
+LOG:[12:25:36 12.5.2016] submitted: /cron2/cronFamily
+LOG:[12:25:36 12.5.2016] submitted: /cron2
+LOG:[12:25:36 12.5.2016] submitted: /
+LOG:[12:25:36 12.5.2016] active: /cron2/cronFamily/t
+LOG:[12:25:36 12.5.2016] active: /cron2/cronFamily
+LOG:[12:25:36 12.5.2016] active: /cron2
+LOG:[12:25:36 12.5.2016] active: /
+LOG:[12:25:36 12.5.2016] complete: /cron2/cronFamily/t
+LOG:[12:25:36 12.5.2016] queued: /cron2/cronFamily/t
+LOG:[12:25:36 12.5.2016] queued: /cron2/cronFamily
+LOG:[12:25:36 12.5.2016] queued: /cron2
+LOG:[12:25:36 12.5.2016] queued: /
+LOG:[12:25:36 12.5.2016] submitted: /cron2/cronFamily/t
+LOG:[12:25:36 12.5.2016] submitted: /cron2/cronFamily
+LOG:[12:25:36 12.5.2016] submitted: /cron2
+LOG:[12:25:36 12.5.2016] submitted: /
+LOG:[12:25:36 12.5.2016] active: /cron2/cronFamily/t
+LOG:[12:25:36 12.5.2016] active: /cron2/cronFamily
+LOG:[12:25:36 12.5.2016] active: /cron2
+LOG:[12:25:36 12.5.2016] active: /
+LOG:[12:25:36 12.5.2016] complete: /cron2/cronFamily/t
+LOG:[12:25:36 12.5.2016] queued: /cron2/cronFamily/t
+LOG:[12:25:36 12.5.2016] queued: /cron2/cronFamily
+LOG:[12:25:36 12.5.2016] queued: /cron2
+LOG:[12:25:36 12.5.2016] queued: /
+LOG:[12:25:36 12.5.2016] submitted: /cron2/cronFamily/t
+LOG:[12:25:36 12.5.2016] submitted: /cron2/cronFamily
+LOG:[12:25:36 12.5.2016] submitted: /cron2
+LOG:[12:25:36 12.5.2016] submitted: /
+LOG:[12:25:36 12.5.2016] active: /cron2/cronFamily/t
+LOG:[12:25:36 12.5.2016] active: /cron2/cronFamily
+LOG:[12:25:36 12.5.2016] active: /cron2
+LOG:[12:25:36 12.5.2016] active: /
+LOG:[12:25:36 12.5.2016] complete: /cron2/cronFamily/t
+LOG:[12:25:36 12.5.2016] queued: /cron2/cronFamily/t
+LOG:[12:25:36 12.5.2016] queued: /cron2/cronFamily
+LOG:[12:25:36 12.5.2016] queued: /cron2
+LOG:[12:25:36 12.5.2016] queued: /
diff --git a/ecflow_4_0_7/CSim/test/data/good_defs/cron/cron3.def b/CSim/test/data/good_defs/cron/cron3.def
similarity index 100%
rename from ecflow_4_0_7/CSim/test/data/good_defs/cron/cron3.def
rename to CSim/test/data/good_defs/cron/cron3.def
diff --git a/CSim/test/data/good_defs/cron/cron3.def.log b/CSim/test/data/good_defs/cron/cron3.def.log
new file mode 100644
index 0000000..795db58
--- /dev/null
+++ b/CSim/test/data/good_defs/cron/cron3.def.log
@@ -0,0 +1,81 @@
+LOG:[12:27:01 12.5.2016] queued: /cron3
+LOG:[12:27:01 12.5.2016] queued: /cron3/cronFamily
+LOG:[12:27:01 12.5.2016] queued: /cron3/cronFamily/t
+LOG:[12:27:01 12.5.2016] submitted: /cron3/cronFamily/t
+LOG:[12:27:01 12.5.2016] submitted: /cron3/cronFamily
+LOG:[12:27:01 12.5.2016] submitted: /cron3
+LOG:[12:27:01 12.5.2016] submitted: /
+LOG:[12:27:01 12.5.2016] active: /cron3/cronFamily/t
+LOG:[12:27:01 12.5.2016] active: /cron3/cronFamily
+LOG:[12:27:01 12.5.2016] active: /cron3
+LOG:[12:27:01 12.5.2016] active: /
+LOG:[12:27:01 12.5.2016] complete: /cron3/cronFamily/t
+LOG:[12:27:01 12.5.2016] queued: /cron3/cronFamily/t
+LOG:[12:27:01 12.5.2016] queued: /cron3/cronFamily
+LOG:[12:27:01 12.5.2016] queued: /cron3
+LOG:[12:27:01 12.5.2016] queued: /
+LOG:[12:27:01 12.5.2016] submitted: /cron3/cronFamily/t
+LOG:[12:27:01 12.5.2016] submitted: /cron3/cronFamily
+LOG:[12:27:01 12.5.2016] submitted: /cron3
+LOG:[12:27:01 12.5.2016] submitted: /
+LOG:[12:27:01 12.5.2016] active: /cron3/cronFamily/t
+LOG:[12:27:01 12.5.2016] active: /cron3/cronFamily
+LOG:[12:27:01 12.5.2016] active: /cron3
+LOG:[12:27:01 12.5.2016] active: /
+LOG:[12:27:01 12.5.2016] complete: /cron3/cronFamily/t
+LOG:[12:27:01 12.5.2016] queued: /cron3/cronFamily/t
+LOG:[12:27:01 12.5.2016] queued: /cron3/cronFamily
+LOG:[12:27:01 12.5.2016] queued: /cron3
+LOG:[12:27:01 12.5.2016] queued: /
+LOG:[12:27:01 12.5.2016] submitted: /cron3/cronFamily/t
+LOG:[12:27:01 12.5.2016] submitted: /cron3/cronFamily
+LOG:[12:27:01 12.5.2016] submitted: /cron3
+LOG:[12:27:01 12.5.2016] submitted: /
+LOG:[12:27:01 12.5.2016] active: /cron3/cronFamily/t
+LOG:[12:27:01 12.5.2016] active: /cron3/cronFamily
+LOG:[12:27:01 12.5.2016] active: /cron3
+LOG:[12:27:01 12.5.2016] active: /
+LOG:[12:27:01 12.5.2016] complete: /cron3/cronFamily/t
+LOG:[12:27:01 12.5.2016] queued: /cron3/cronFamily/t
+LOG:[12:27:01 12.5.2016] queued: /cron3/cronFamily
+LOG:[12:27:01 12.5.2016] queued: /cron3
+LOG:[12:27:01 12.5.2016] queued: /
+LOG:[12:27:01 12.5.2016] submitted: /cron3/cronFamily/t
+LOG:[12:27:01 12.5.2016] submitted: /cron3/cronFamily
+LOG:[12:27:01 12.5.2016] submitted: /cron3
+LOG:[12:27:01 12.5.2016] submitted: /
+LOG:[12:27:01 12.5.2016] active: /cron3/cronFamily/t
+LOG:[12:27:01 12.5.2016] active: /cron3/cronFamily
+LOG:[12:27:01 12.5.2016] active: /cron3
+LOG:[12:27:01 12.5.2016] active: /
+LOG:[12:27:01 12.5.2016] complete: /cron3/cronFamily/t
+LOG:[12:27:01 12.5.2016] queued: /cron3/cronFamily/t
+LOG:[12:27:01 12.5.2016] queued: /cron3/cronFamily
+LOG:[12:27:01 12.5.2016] queued: /cron3
+LOG:[12:27:01 12.5.2016] queued: /
+LOG:[12:27:01 12.5.2016] submitted: /cron3/cronFamily/t
+LOG:[12:27:01 12.5.2016] submitted: /cron3/cronFamily
+LOG:[12:27:01 12.5.2016] submitted: /cron3
+LOG:[12:27:01 12.5.2016] submitted: /
+LOG:[12:27:01 12.5.2016] active: /cron3/cronFamily/t
+LOG:[12:27:01 12.5.2016] active: /cron3/cronFamily
+LOG:[12:27:01 12.5.2016] active: /cron3
+LOG:[12:27:01 12.5.2016] active: /
+LOG:[12:27:01 12.5.2016] complete: /cron3/cronFamily/t
+LOG:[12:27:01 12.5.2016] queued: /cron3/cronFamily/t
+LOG:[12:27:01 12.5.2016] queued: /cron3/cronFamily
+LOG:[12:27:01 12.5.2016] queued: /cron3
+LOG:[12:27:01 12.5.2016] queued: /
+LOG:[12:27:01 12.5.2016] submitted: /cron3/cronFamily/t
+LOG:[12:27:01 12.5.2016] submitted: /cron3/cronFamily
+LOG:[12:27:01 12.5.2016] submitted: /cron3
+LOG:[12:27:01 12.5.2016] submitted: /
+LOG:[12:27:01 12.5.2016] active: /cron3/cronFamily/t
+LOG:[12:27:01 12.5.2016] active: /cron3/cronFamily
+LOG:[12:27:01 12.5.2016] active: /cron3
+LOG:[12:27:01 12.5.2016] active: /
+LOG:[12:27:01 12.5.2016] complete: /cron3/cronFamily/t
+LOG:[12:27:01 12.5.2016] queued: /cron3/cronFamily/t
+LOG:[12:27:01 12.5.2016] queued: /cron3/cronFamily
+LOG:[12:27:01 12.5.2016] queued: /cron3
+LOG:[12:27:01 12.5.2016] queued: /
diff --git a/ecflow_4_0_7/CSim/test/data/good_defs/cron/cron4.def b/CSim/test/data/good_defs/cron/cron4.def
similarity index 100%
rename from ecflow_4_0_7/CSim/test/data/good_defs/cron/cron4.def
rename to CSim/test/data/good_defs/cron/cron4.def
diff --git a/CSim/test/data/good_defs/cron/cron4.def.log b/CSim/test/data/good_defs/cron/cron4.def.log
new file mode 100644
index 0000000..f86822f
--- /dev/null
+++ b/CSim/test/data/good_defs/cron/cron4.def.log
@@ -0,0 +1,809 @@
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] submitted: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] submitted: /cron4
+LOG:[12:27:03 12.5.2016] submitted: /
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] active: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] active: /cron4
+LOG:[12:27:03 12.5.2016] active: /
+LOG:[12:27:03 12.5.2016] complete: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily/t
+LOG:[12:27:03 12.5.2016] queued: /cron4/cronFamily
+LOG:[12:27:03 12.5.2016] queued: /cron4
+LOG:[12:27:03 12.5.2016] queued: /
diff --git a/ecflow_4_0_7/CSim/test/data/good_defs/cron/cron5.def b/CSim/test/data/good_defs/cron/cron5.def
similarity index 100%
rename from ecflow_4_0_7/CSim/test/data/good_defs/cron/cron5.def
rename to CSim/test/data/good_defs/cron/cron5.def
diff --git a/CSim/test/data/good_defs/cron/cron5.def.log b/CSim/test/data/good_defs/cron/cron5.def.log
new file mode 100644
index 0000000..4bda3b0
--- /dev/null
+++ b/CSim/test/data/good_defs/cron/cron5.def.log
@@ -0,0 +1,107 @@
+LOG:[12:26:55 12.5.2016] queued: /cron5
+LOG:[12:26:55 12.5.2016] queued: /cron5/cronFamily
+LOG:[12:26:55 12.5.2016] queued: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] submitted: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] submitted: /cron5/cronFamily
+LOG:[12:26:55 12.5.2016] submitted: /cron5
+LOG:[12:26:55 12.5.2016] submitted: /
+LOG:[12:26:55 12.5.2016] active: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] active: /cron5/cronFamily
+LOG:[12:26:55 12.5.2016] active: /cron5
+LOG:[12:26:55 12.5.2016] active: /
+LOG:[12:26:55 12.5.2016] complete: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] queued: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] queued: /cron5/cronFamily
+LOG:[12:26:55 12.5.2016] queued: /cron5
+LOG:[12:26:55 12.5.2016] queued: /
+LOG:[12:26:55 12.5.2016] submitted: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] submitted: /cron5/cronFamily
+LOG:[12:26:55 12.5.2016] submitted: /cron5
+LOG:[12:26:55 12.5.2016] submitted: /
+LOG:[12:26:55 12.5.2016] active: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] active: /cron5/cronFamily
+LOG:[12:26:55 12.5.2016] active: /cron5
+LOG:[12:26:55 12.5.2016] active: /
+LOG:[12:26:55 12.5.2016] complete: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] queued: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] queued: /cron5/cronFamily
+LOG:[12:26:55 12.5.2016] queued: /cron5
+LOG:[12:26:55 12.5.2016] queued: /
+LOG:[12:26:55 12.5.2016] submitted: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] submitted: /cron5/cronFamily
+LOG:[12:26:55 12.5.2016] submitted: /cron5
+LOG:[12:26:55 12.5.2016] submitted: /
+LOG:[12:26:55 12.5.2016] active: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] active: /cron5/cronFamily
+LOG:[12:26:55 12.5.2016] active: /cron5
+LOG:[12:26:55 12.5.2016] active: /
+LOG:[12:26:55 12.5.2016] complete: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] queued: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] queued: /cron5/cronFamily
+LOG:[12:26:55 12.5.2016] queued: /cron5
+LOG:[12:26:55 12.5.2016] queued: /
+LOG:[12:26:55 12.5.2016] submitted: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] submitted: /cron5/cronFamily
+LOG:[12:26:55 12.5.2016] submitted: /cron5
+LOG:[12:26:55 12.5.2016] submitted: /
+LOG:[12:26:55 12.5.2016] active: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] active: /cron5/cronFamily
+LOG:[12:26:55 12.5.2016] active: /cron5
+LOG:[12:26:55 12.5.2016] active: /
+LOG:[12:26:55 12.5.2016] complete: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] queued: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] queued: /cron5/cronFamily
+LOG:[12:26:55 12.5.2016] queued: /cron5
+LOG:[12:26:55 12.5.2016] queued: /
+LOG:[12:26:55 12.5.2016] submitted: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] submitted: /cron5/cronFamily
+LOG:[12:26:55 12.5.2016] submitted: /cron5
+LOG:[12:26:55 12.5.2016] submitted: /
+LOG:[12:26:55 12.5.2016] active: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] active: /cron5/cronFamily
+LOG:[12:26:55 12.5.2016] active: /cron5
+LOG:[12:26:55 12.5.2016] active: /
+LOG:[12:26:55 12.5.2016] complete: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] queued: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] queued: /cron5/cronFamily
+LOG:[12:26:55 12.5.2016] queued: /cron5
+LOG:[12:26:55 12.5.2016] queued: /
+LOG:[12:26:55 12.5.2016] submitted: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] submitted: /cron5/cronFamily
+LOG:[12:26:55 12.5.2016] submitted: /cron5
+LOG:[12:26:55 12.5.2016] submitted: /
+LOG:[12:26:55 12.5.2016] active: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] active: /cron5/cronFamily
+LOG:[12:26:55 12.5.2016] active: /cron5
+LOG:[12:26:55 12.5.2016] active: /
+LOG:[12:26:55 12.5.2016] complete: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] queued: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] queued: /cron5/cronFamily
+LOG:[12:26:55 12.5.2016] queued: /cron5
+LOG:[12:26:55 12.5.2016] queued: /
+LOG:[12:26:55 12.5.2016] submitted: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] submitted: /cron5/cronFamily
+LOG:[12:26:55 12.5.2016] submitted: /cron5
+LOG:[12:26:55 12.5.2016] submitted: /
+LOG:[12:26:55 12.5.2016] active: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] active: /cron5/cronFamily
+LOG:[12:26:55 12.5.2016] active: /cron5
+LOG:[12:26:55 12.5.2016] active: /
+LOG:[12:26:55 12.5.2016] complete: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] queued: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] queued: /cron5/cronFamily
+LOG:[12:26:55 12.5.2016] queued: /cron5
+LOG:[12:26:55 12.5.2016] queued: /
+LOG:[12:26:55 12.5.2016] submitted: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] submitted: /cron5/cronFamily
+LOG:[12:26:55 12.5.2016] submitted: /cron5
+LOG:[12:26:55 12.5.2016] submitted: /
+LOG:[12:26:55 12.5.2016] active: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] active: /cron5/cronFamily
+LOG:[12:26:55 12.5.2016] active: /cron5
+LOG:[12:26:55 12.5.2016] active: /
+LOG:[12:26:55 12.5.2016] complete: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] queued: /cron5/cronFamily/t
+LOG:[12:26:55 12.5.2016] queued: /cron5/cronFamily
+LOG:[12:26:55 12.5.2016] queued: /cron5
+LOG:[12:26:55 12.5.2016] queued: /
diff --git a/ecflow_4_0_7/CSim/test/data/good_defs/cron/cron6.def b/CSim/test/data/good_defs/cron/cron6.def
similarity index 100%
rename from ecflow_4_0_7/CSim/test/data/good_defs/cron/cron6.def
rename to CSim/test/data/good_defs/cron/cron6.def
diff --git a/CSim/test/data/good_defs/cron/cron6.def.log b/CSim/test/data/good_defs/cron/cron6.def.log
new file mode 100644
index 0000000..640be5b
--- /dev/null
+++ b/CSim/test/data/good_defs/cron/cron6.def.log
@@ -0,0 +1,55 @@
+LOG:[12:27:10 12.5.2016] queued: /cron6
+LOG:[12:27:10 12.5.2016] queued: /cron6/cronFamily
+LOG:[12:27:10 12.5.2016] queued: /cron6/cronFamily/t
+LOG:[12:27:10 12.5.2016] submitted: /cron6/cronFamily/t
+LOG:[12:27:10 12.5.2016] submitted: /cron6/cronFamily
+LOG:[12:27:10 12.5.2016] submitted: /cron6
+LOG:[12:27:10 12.5.2016] submitted: /
+LOG:[12:27:10 12.5.2016] active: /cron6/cronFamily/t
+LOG:[12:27:10 12.5.2016] active: /cron6/cronFamily
+LOG:[12:27:10 12.5.2016] active: /cron6
+LOG:[12:27:10 12.5.2016] active: /
+LOG:[12:27:10 12.5.2016] complete: /cron6/cronFamily/t
+LOG:[12:27:10 12.5.2016] queued: /cron6/cronFamily/t
+LOG:[12:27:10 12.5.2016] queued: /cron6/cronFamily
+LOG:[12:27:10 12.5.2016] queued: /cron6
+LOG:[12:27:10 12.5.2016] queued: /
+LOG:[12:27:10 12.5.2016] submitted: /cron6/cronFamily/t
+LOG:[12:27:10 12.5.2016] submitted: /cron6/cronFamily
+LOG:[12:27:10 12.5.2016] submitted: /cron6
+LOG:[12:27:10 12.5.2016] submitted: /
+LOG:[12:27:10 12.5.2016] active: /cron6/cronFamily/t
+LOG:[12:27:10 12.5.2016] active: /cron6/cronFamily
+LOG:[12:27:10 12.5.2016] active: /cron6
+LOG:[12:27:10 12.5.2016] active: /
+LOG:[12:27:10 12.5.2016] complete: /cron6/cronFamily/t
+LOG:[12:27:10 12.5.2016] queued: /cron6/cronFamily/t
+LOG:[12:27:10 12.5.2016] queued: /cron6/cronFamily
+LOG:[12:27:10 12.5.2016] queued: /cron6
+LOG:[12:27:10 12.5.2016] queued: /
+LOG:[12:27:10 12.5.2016] submitted: /cron6/cronFamily/t
+LOG:[12:27:10 12.5.2016] submitted: /cron6/cronFamily
+LOG:[12:27:10 12.5.2016] submitted: /cron6
+LOG:[12:27:10 12.5.2016] submitted: /
+LOG:[12:27:10 12.5.2016] active: /cron6/cronFamily/t
+LOG:[12:27:10 12.5.2016] active: /cron6/cronFamily
+LOG:[12:27:10 12.5.2016] active: /cron6
+LOG:[12:27:10 12.5.2016] active: /
+LOG:[12:27:10 12.5.2016] complete: /cron6/cronFamily/t
+LOG:[12:27:10 12.5.2016] queued: /cron6/cronFamily/t
+LOG:[12:27:10 12.5.2016] queued: /cron6/cronFamily
+LOG:[12:27:10 12.5.2016] queued: /cron6
+LOG:[12:27:10 12.5.2016] queued: /
+LOG:[12:27:10 12.5.2016] submitted: /cron6/cronFamily/t
+LOG:[12:27:10 12.5.2016] submitted: /cron6/cronFamily
+LOG:[12:27:10 12.5.2016] submitted: /cron6
+LOG:[12:27:10 12.5.2016] submitted: /
+LOG:[12:27:10 12.5.2016] active: /cron6/cronFamily/t
+LOG:[12:27:10 12.5.2016] active: /cron6/cronFamily
+LOG:[12:27:10 12.5.2016] active: /cron6
+LOG:[12:27:10 12.5.2016] active: /
+LOG:[12:27:10 12.5.2016] complete: /cron6/cronFamily/t
+LOG:[12:27:10 12.5.2016] queued: /cron6/cronFamily/t
+LOG:[12:27:10 12.5.2016] queued: /cron6/cronFamily
+LOG:[12:27:10 12.5.2016] queued: /cron6
+LOG:[12:27:10 12.5.2016] queued: /
diff --git a/ecflow_4_0_7/CSim/test/data/good_defs/cron/cron7.def b/CSim/test/data/good_defs/cron/cron7.def
similarity index 100%
rename from ecflow_4_0_7/CSim/test/data/good_defs/cron/cron7.def
rename to CSim/test/data/good_defs/cron/cron7.def
diff --git a/CSim/test/data/good_defs/cron/cron7.def.log b/CSim/test/data/good_defs/cron/cron7.def.log
new file mode 100644
index 0000000..12ade0a
--- /dev/null
+++ b/CSim/test/data/good_defs/cron/cron7.def.log
@@ -0,0 +1,4735 @@
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] submitted: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] submitted: /cron7
+LOG:[12:25:37 12.5.2016] submitted: /
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] active: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] active: /cron7
+LOG:[12:25:37 12.5.2016] active: /
+LOG:[12:25:37 12.5.2016] complete: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily/t
+LOG:[12:25:37 12.5.2016] queued: /cron7/cronFamily
+LOG:[12:25:37 12.5.2016] queued: /cron7
+LOG:[12:25:37 12.5.2016] queued: /
diff --git a/ecflow_4_0_7/CSim/test/data/good_defs/day/day.def b/CSim/test/data/good_defs/day/day.def
similarity index 100%
rename from ecflow_4_0_7/CSim/test/data/good_defs/day/day.def
rename to CSim/test/data/good_defs/day/day.def
diff --git a/CSim/test/data/good_defs/day/day.def.log b/CSim/test/data/good_defs/day/day.def.log
new file mode 100644
index 0000000..547ec64
--- /dev/null
+++ b/CSim/test/data/good_defs/day/day.def.log
@@ -0,0 +1,29 @@
+LOG:[12:27:19 12.5.2016] queued: /suite
+LOG:[12:27:19 12.5.2016] queued: /suite/family
+LOG:[12:27:19 12.5.2016] queued: /suite/family/y
+LOG:[12:27:19 12.5.2016] queued: /suite/family/x
+LOG:[12:27:19 12.5.2016] submitted: /suite/family/y
+LOG:[12:27:19 12.5.2016] submitted: /suite/family
+LOG:[12:27:19 12.5.2016] submitted: /suite
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /suite/family/y
+LOG:[12:27:19 12.5.2016] active: /suite/family
+LOG:[12:27:19 12.5.2016] active: /suite
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /suite/family/y
+LOG:[12:27:19 12.5.2016] queued: /suite/family
+LOG:[12:27:19 12.5.2016] queued: /suite
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /suite/family/x
+LOG:[12:27:19 12.5.2016] submitted: /suite/family
+LOG:[12:27:19 12.5.2016] submitted: /suite
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /suite/family/x
+LOG:[12:27:19 12.5.2016] active: /suite/family
+LOG:[12:27:19 12.5.2016] active: /suite
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /suite/family/x
+LOG:[12:27:19 12.5.2016] complete: /suite/family
+LOG:[12:27:19 12.5.2016] complete: /suite
+LOG:[12:27:19 12.5.2016] complete: /
+MSG:[12:27:19 12.5.2016] Simulation complete in 25:00:00
diff --git a/ecflow_4_0_7/CSim/test/data/good_defs/day/hybrid_day.def b/CSim/test/data/good_defs/day/hybrid_day.def
similarity index 100%
rename from ecflow_4_0_7/CSim/test/data/good_defs/day/hybrid_day.def
rename to CSim/test/data/good_defs/day/hybrid_day.def
diff --git a/CSim/test/data/good_defs/day/hybrid_day.def.log b/CSim/test/data/good_defs/day/hybrid_day.def.log
new file mode 100644
index 0000000..20a890d
--- /dev/null
+++ b/CSim/test/data/good_defs/day/hybrid_day.def.log
@@ -0,0 +1,18 @@
+LOG:[12:27:19 12.5.2016] queued: /suite
+LOG:[12:27:19 12.5.2016] queued: /suite/family
+LOG:[12:27:19 12.5.2016] queued: /suite/family/y
+LOG:[12:27:19 12.5.2016] queued: /suite/family/x
+LOG:[12:27:19 12.5.2016] complete: /suite/family/x
+LOG:[12:27:19 12.5.2016] submitted: /suite/family/y
+LOG:[12:27:19 12.5.2016] submitted: /suite/family
+LOG:[12:27:19 12.5.2016] submitted: /suite
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /suite/family/y
+LOG:[12:27:19 12.5.2016] active: /suite/family
+LOG:[12:27:19 12.5.2016] active: /suite
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /suite/family/y
+LOG:[12:27:19 12.5.2016] complete: /suite/family
+LOG:[12:27:19 12.5.2016] complete: /suite
+LOG:[12:27:19 12.5.2016] complete: /
+MSG:[12:27:19 12.5.2016] Simulation complete in 00:00:00
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/lifecycle.txt b/CSim/test/data/good_defs/misc/liefcycle.def
similarity index 100%
rename from ecflow_4_0_7/AParser/test/data/good_defs/lifecycle.txt
rename to CSim/test/data/good_defs/misc/liefcycle.def
diff --git a/CSim/test/data/good_defs/misc/liefcycle.def.log b/CSim/test/data/good_defs/misc/liefcycle.def.log
new file mode 100644
index 0000000..ad05fee
--- /dev/null
+++ b/CSim/test/data/good_defs/misc/liefcycle.def.log
@@ -0,0 +1,44 @@
+LOG:[12:27:19 12.5.2016] queued: /suite1
+LOG:[12:27:19 12.5.2016] queued: /suite1/family1
+LOG:[12:27:19 12.5.2016] queued: /suite1/family1/a
+LOG:[12:27:19 12.5.2016] queued: /suite1/family1/b
+LOG:[12:27:19 12.5.2016] queued: /suite1/family2
+LOG:[12:27:19 12.5.2016] queued: /suite1/family2/aa
+LOG:[12:27:19 12.5.2016] queued: /suite1/family2/bb
+LOG:[12:27:19 12.5.2016] submitted: /suite1/family1/a
+LOG:[12:27:19 12.5.2016] submitted: /suite1/family1
+LOG:[12:27:19 12.5.2016] submitted: /suite1
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /suite1/family1/a
+LOG:[12:27:19 12.5.2016] active: /suite1/family1
+LOG:[12:27:19 12.5.2016] active: /suite1
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /suite1/family2/bb
+LOG:[12:27:19 12.5.2016] submitted: /suite1/family2
+LOG:[12:27:19 12.5.2016] active: /suite1/family2/bb
+LOG:[12:27:19 12.5.2016] active: /suite1/family2
+LOG:[12:27:19 12.5.2016] complete: /suite1/family2/bb
+LOG:[12:27:19 12.5.2016] queued: /suite1/family2
+LOG:[12:27:19 12.5.2016] submitted: /suite1/family2/aa
+LOG:[12:27:19 12.5.2016] submitted: /suite1/family2
+LOG:[12:27:19 12.5.2016] active: /suite1/family2/aa
+LOG:[12:27:19 12.5.2016] active: /suite1/family2
+LOG:[12:27:19 12.5.2016] complete: /suite1/family2/aa
+LOG:[12:27:19 12.5.2016] complete: /suite1/family2
+LOG:[12:27:19 12.5.2016] complete: /suite1/family1/a
+LOG:[12:27:19 12.5.2016] queued: /suite1/family1
+LOG:[12:27:19 12.5.2016] queued: /suite1
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /suite1/family1/b
+LOG:[12:27:19 12.5.2016] submitted: /suite1/family1
+LOG:[12:27:19 12.5.2016] submitted: /suite1
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /suite1/family1/b
+LOG:[12:27:19 12.5.2016] active: /suite1/family1
+LOG:[12:27:19 12.5.2016] active: /suite1
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /suite1/family1/b
+LOG:[12:27:19 12.5.2016] complete: /suite1/family1
+LOG:[12:27:19 12.5.2016] complete: /suite1
+LOG:[12:27:19 12.5.2016] complete: /
+MSG:[12:27:19 12.5.2016] Simulation complete in 00:00:00
diff --git a/ecflow_4_0_7/CSim/test/data/good_defs/SingleDefsTest/test.def b/CSim/test/data/good_defs/misc/time.def
similarity index 100%
rename from ecflow_4_0_7/CSim/test/data/good_defs/SingleDefsTest/test.def
rename to CSim/test/data/good_defs/misc/time.def
diff --git a/CSim/test/data/good_defs/misc/time.def.log b/CSim/test/data/good_defs/misc/time.def.log
new file mode 100644
index 0000000..1252b74
--- /dev/null
+++ b/CSim/test/data/good_defs/misc/time.def.log
@@ -0,0 +1,42 @@
+LOG:[12:27:19 12.5.2016] queued: /suite
+LOG:[12:27:19 12.5.2016] queued: /suite/family
+LOG:[12:27:19 12.5.2016] queued: /suite/family/t
+LOG:[12:27:19 12.5.2016] submitted: /suite/family/t
+LOG:[12:27:19 12.5.2016] submitted: /suite/family
+LOG:[12:27:19 12.5.2016] submitted: /suite
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /suite/family/t
+LOG:[12:27:19 12.5.2016] active: /suite/family
+LOG:[12:27:19 12.5.2016] active: /suite
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /suite/family/t
+LOG:[12:27:19 12.5.2016] queued: /suite/family/t
+LOG:[12:27:19 12.5.2016] queued: /suite/family
+LOG:[12:27:19 12.5.2016] queued: /suite
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /suite/family/t
+LOG:[12:27:19 12.5.2016] submitted: /suite/family
+LOG:[12:27:19 12.5.2016] submitted: /suite
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /suite/family/t
+LOG:[12:27:19 12.5.2016] active: /suite/family
+LOG:[12:27:19 12.5.2016] active: /suite
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /suite/family/t
+LOG:[12:27:19 12.5.2016] queued: /suite/family/t
+LOG:[12:27:19 12.5.2016] queued: /suite/family
+LOG:[12:27:19 12.5.2016] queued: /suite
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /suite/family/t
+LOG:[12:27:19 12.5.2016] submitted: /suite/family
+LOG:[12:27:19 12.5.2016] submitted: /suite
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /suite/family/t
+LOG:[12:27:19 12.5.2016] active: /suite/family
+LOG:[12:27:19 12.5.2016] active: /suite
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /suite/family/t
+LOG:[12:27:19 12.5.2016] complete: /suite/family
+LOG:[12:27:19 12.5.2016] complete: /suite
+LOG:[12:27:19 12.5.2016] complete: /
+MSG:[12:27:19 12.5.2016] Simulation complete in 00:03:00
diff --git a/CSim/test/data/good_defs/operations/loop.def b/CSim/test/data/good_defs/operations/loop.def
new file mode 100644
index 0000000..1f7b287
--- /dev/null
+++ b/CSim/test/data/good_defs/operations/loop.def
@@ -0,0 +1,24 @@
+# This file was taken from one of operational suites
+
+suite limits
+ defstatus complete
+ clock hybrid 0 # 01.07.2009 14:47
+ limit metis 6
+endsuite
+
+suite admin
+ #defstatus suspended
+ clock hybrid 22.12.2005 # run at midnight to ensure test is deterministice
+ inlimit /limits:metis
+
+ family daily
+ repeat date YMD 20070115 20070118 1 # run 4 times
+ verify complete:4
+ family check
+ verify complete:4 # make sure it actually ran 4 times
+ task rcp
+ time 00:00 23:59 00:10 # Note: finish minute (59) is not a multiple of the increment 10, last time is 23:50
+ verify complete:576 # 576 = 24(hours) * 6( completions per hour) * 4 times
+ endfamily
+ endfamily
+endsuite
\ No newline at end of file
diff --git a/CSim/test/data/good_defs/operations/loop.def.log b/CSim/test/data/good_defs/operations/loop.def.log
new file mode 100644
index 0000000..054f7b6
--- /dev/null
+++ b/CSim/test/data/good_defs/operations/loop.def.log
@@ -0,0 +1,9230 @@
+LOG:[12:27:14 12.5.2016] complete: /limits
+LOG:[12:27:14 12.5.2016] complete: /limits
+LOG:[12:27:14 12.5.2016] complete: /limits
+LOG:[12:27:14 12.5.2016] complete: /
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check
+LOG:[12:27:14 12.5.2016] complete: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check
+LOG:[12:27:14 12.5.2016] complete: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check
+LOG:[12:27:14 12.5.2016] complete: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] queued: /admin/daily/check
+LOG:[12:27:14 12.5.2016] queued: /admin/daily
+LOG:[12:27:14 12.5.2016] queued: /admin
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily/check
+LOG:[12:27:14 12.5.2016] submitted: /admin/daily
+LOG:[12:27:14 12.5.2016] submitted: /admin
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] active: /admin/daily/check
+LOG:[12:27:14 12.5.2016] active: /admin/daily
+LOG:[12:27:14 12.5.2016] active: /admin
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check/rcp
+LOG:[12:27:14 12.5.2016] complete: /admin/daily/check
+LOG:[12:27:14 12.5.2016] complete: /admin/daily
+LOG:[12:27:14 12.5.2016] complete: /admin
+LOG:[12:27:14 12.5.2016] complete: /
+MSG:[12:27:14 12.5.2016] Simulation complete in 95:50:00
diff --git a/CSim/test/data/good_defs/operations/mars.def b/CSim/test/data/good_defs/operations/mars.def
new file mode 100644
index 0000000..3acfa68
--- /dev/null
+++ b/CSim/test/data/good_defs/operations/mars.def
@@ -0,0 +1,10 @@
+suite mars
+ clock hybrid 01.07.2009
+ family archive
+ repeat integer fred 1 1
+ task grib
+ verify complete:6 # 00:30 4:30 8:30 12:30 16:30 20:30
+ time 00:30 23:59 04:00 #
+ endfamily
+endsuite
+
\ No newline at end of file
diff --git a/CSim/test/data/good_defs/operations/mars.def.log b/CSim/test/data/good_defs/operations/mars.def.log
new file mode 100644
index 0000000..0de3f88
--- /dev/null
+++ b/CSim/test/data/good_defs/operations/mars.def.log
@@ -0,0 +1,81 @@
+LOG:[12:27:19 12.5.2016] queued: /mars
+LOG:[12:27:19 12.5.2016] queued: /mars/archive
+LOG:[12:27:19 12.5.2016] queued: /mars/archive/grib
+LOG:[12:27:19 12.5.2016] submitted: /mars/archive/grib
+LOG:[12:27:19 12.5.2016] submitted: /mars/archive
+LOG:[12:27:19 12.5.2016] submitted: /mars
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /mars/archive/grib
+LOG:[12:27:19 12.5.2016] active: /mars/archive
+LOG:[12:27:19 12.5.2016] active: /mars
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /mars/archive/grib
+LOG:[12:27:19 12.5.2016] queued: /mars/archive/grib
+LOG:[12:27:19 12.5.2016] queued: /mars/archive
+LOG:[12:27:19 12.5.2016] queued: /mars
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /mars/archive/grib
+LOG:[12:27:19 12.5.2016] submitted: /mars/archive
+LOG:[12:27:19 12.5.2016] submitted: /mars
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /mars/archive/grib
+LOG:[12:27:19 12.5.2016] active: /mars/archive
+LOG:[12:27:19 12.5.2016] active: /mars
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /mars/archive/grib
+LOG:[12:27:19 12.5.2016] queued: /mars/archive/grib
+LOG:[12:27:19 12.5.2016] queued: /mars/archive
+LOG:[12:27:19 12.5.2016] queued: /mars
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /mars/archive/grib
+LOG:[12:27:19 12.5.2016] submitted: /mars/archive
+LOG:[12:27:19 12.5.2016] submitted: /mars
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /mars/archive/grib
+LOG:[12:27:19 12.5.2016] active: /mars/archive
+LOG:[12:27:19 12.5.2016] active: /mars
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /mars/archive/grib
+LOG:[12:27:19 12.5.2016] queued: /mars/archive/grib
+LOG:[12:27:19 12.5.2016] queued: /mars/archive
+LOG:[12:27:19 12.5.2016] queued: /mars
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /mars/archive/grib
+LOG:[12:27:19 12.5.2016] submitted: /mars/archive
+LOG:[12:27:19 12.5.2016] submitted: /mars
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /mars/archive/grib
+LOG:[12:27:19 12.5.2016] active: /mars/archive
+LOG:[12:27:19 12.5.2016] active: /mars
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /mars/archive/grib
+LOG:[12:27:19 12.5.2016] queued: /mars/archive/grib
+LOG:[12:27:19 12.5.2016] queued: /mars/archive
+LOG:[12:27:19 12.5.2016] queued: /mars
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /mars/archive/grib
+LOG:[12:27:19 12.5.2016] submitted: /mars/archive
+LOG:[12:27:19 12.5.2016] submitted: /mars
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /mars/archive/grib
+LOG:[12:27:19 12.5.2016] active: /mars/archive
+LOG:[12:27:19 12.5.2016] active: /mars
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /mars/archive/grib
+LOG:[12:27:19 12.5.2016] queued: /mars/archive/grib
+LOG:[12:27:19 12.5.2016] queued: /mars/archive
+LOG:[12:27:19 12.5.2016] queued: /mars
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /mars/archive/grib
+LOG:[12:27:19 12.5.2016] submitted: /mars/archive
+LOG:[12:27:19 12.5.2016] submitted: /mars
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /mars/archive/grib
+LOG:[12:27:19 12.5.2016] active: /mars/archive
+LOG:[12:27:19 12.5.2016] active: /mars
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /mars/archive/grib
+LOG:[12:27:19 12.5.2016] complete: /mars/archive
+LOG:[12:27:19 12.5.2016] complete: /mars
+LOG:[12:27:19 12.5.2016] complete: /
+MSG:[12:27:19 12.5.2016] Simulation complete in 20:30:00
diff --git a/CSim/test/data/good_defs/operations/naw.def b/CSim/test/data/good_defs/operations/naw.def
new file mode 100644
index 0000000..06d556b
--- /dev/null
+++ b/CSim/test/data/good_defs/operations/naw.def
@@ -0,0 +1,208 @@
+#============================================================
+suite weather
+ clock hybrid -3542400 # 29.08.2009 16:54
+ # repeat day 1 # status 0 ************** DISABLED SO THAT SUITE CAN COMPLETE *****************
+ edit SMSTRIES '2'
+ edit SMSCMD 'smssubmit.x %SMSJOB% hades rdx'
+ edit SMSHOME '/vol/rdx_dir/mars_stats/sms'
+ edit SMSINCLUDE '/vol/rdx_dir/mars_stats/sms/include'
+ edit SMSFILES '/vol/rdx_dir/mars_stats/sms/weather'
+ edit SMSSTATUSCMD 'smscheck %SCHOST% %EXPVER% %SMSJOB%'
+ edit ACCOUNT 'ecrmna'
+ edit OWNER 'naw'
+ edit EXPVER 'weather'
+ edit LOGDIR '/scratch/rd/rdx'
+ edit USER 'rdx'
+ edit QUEUE 'normal'
+ edit ECFS 'no'
+ family naw
+ family general
+ # time 06:00
+ task metgrams
+ defstatus complete
+ task equipot
+ defstatus complete
+ endfamily
+ family tephi
+ edit WSHOST 'linux_cluster'
+ edit SMSKILL '/home/rd/rdx/bin/smskill %USER% %WSHOST% %SMSRID% %SMSJOB%'
+ edit SMSCMD '/home/rd/rdx/bin/smssubmit.x %SMSJOB% %WSHOST% %USER%'
+ edit HOUR '00'
+ # time 05:35
+ task rd_tephi
+ defstatus complete
+ edit TDATE '2000110500'
+ edit EXPVER 'e4mb'
+ task tephi
+ endfamily
+ family main
+ edit WSHOST 'linux_cluster'
+ edit SCHOST 'c1a'
+ edit CPUTIME '30000'
+ edit MEM '800'
+ edit SMSLOGPORT '9314'
+ edit SMSLOGHOST 'c1a-batch'
+ edit SMSKILL '/home/rd/rdx/bin/smskill %USER% %WSHOST% %SMSRID% %SMSJOB%'
+ edit SMSCMD '/home/rd/rdx/bin/smssubmit.x.nils %SMSJOB% %WSHOST% %USER%'
+ edit LOGDIR '/vol/explog/outputs'
+ family scm_quick
+ edit LONG 'no'
+ edit START12 'no'
+ task getmars_scm
+ edit SMSKILL '/home/rd/rdx/bin/smskill %USER% %SCHOST% %SMSRID% %SMSJOB%'
+ edit SMSCMD '/home/rd/rdx/bin/smssubmit.x %SMSJOB% %SCHOST% %USER%'
+ edit LOGDIR '/c1a/rdx_dir/log'
+ # time 05:20
+ task getdata_scm
+ trigger getmars_scm eq complete
+ edit CLASS 'np'
+ edit NPES '8'
+ edit MEM '800'
+ edit SMSKILL '/home/rd/rdx/bin/smskill %USER% %SCHOST% %SMSRID% %SMSJOB%'
+ edit SMSCMD '/home/rd/rdx/bin/smssubmit.x %SMSJOB% %SCHOST% %USER%'
+ edit LOGDIR '/c1a/rdx_dir/log'
+ task benson
+ trigger getdata_scm eq complete
+ edit QUEUE 'normal'
+ task chilbolton
+ trigger getdata_scm eq complete
+ task husbos
+ trigger getdata_scm eq complete
+ task belvoir_castle
+ trigger getdata_scm eq complete
+ task york
+ trigger getdata_scm eq complete
+ task welshpool
+ trigger getdata_scm eq complete
+ edit QUEUE 'normal'
+ task newmarket
+ trigger getdata_scm eq complete
+ endfamily
+ family scm
+ edit LONG 'yes'
+ edit START12 'no'
+ task getmars_scm
+ edit SMSKILL '/home/rd/rdx/bin/smskill %USER% %SCHOST% %SMSRID% %SMSJOB%'
+ edit SMSCMD '/home/rd/rdx/bin/smssubmit.x %SMSJOB% %SCHOST% %USER%'
+ edit LOGDIR '/c1a/rdx_dir/log'
+ # time 06:45
+ task getdata_scm
+ trigger getmars_scm eq complete
+ edit CLASS 'np'
+ edit NPES '8'
+ edit MEM '800'
+ edit SMSKILL '/home/rd/rdx/bin/smskill %USER% %SCHOST% %SMSRID% %SMSJOB%'
+ edit SMSCMD '/home/rd/rdx/bin/smssubmit.x %SMSJOB% %SCHOST% %USER%'
+ edit LOGDIR '/c1a/rdx_dir/log'
+ edit SMSPASS 'FREE'
+ task benson
+ trigger getdata_scm eq complete
+ edit SMSPASS 'FREE'
+ task chilbolton
+ trigger getdata_scm eq complete
+ task husbos
+ trigger getdata_scm eq complete
+ edit SMSPASS 'FREE'
+ task belvoir_castle
+ trigger getdata_scm eq complete
+ task york
+ trigger getdata_scm eq complete
+ task welshpool
+ trigger getdata_scm eq complete
+ edit SMSPASS 'FREE'
+ task newmarket
+ trigger getdata_scm eq complete
+ task cabauw
+ trigger getdata_scm eq complete
+ task arm_sgp
+ trigger getdata_scm eq complete
+ task vocals0850W
+ defstatus complete
+ trigger getdata_scm eq complete
+ task vocals0750W
+ defstatus complete
+ trigger getdata_scm eq complete
+ task web
+ trigger benson eq complete and chilbolton eq complete and husbos eq complete and belvoir_castle eq complete and york eq complete and welshpool eq complete and newmarket eq complete and cabauw eq complete and arm_sgp eq complete and vocals0850W eq complete and vocals0750W eq complete
+ endfamily
+ endfamily
+ endfamily
+endsuite
+suite weather12
+ clock hybrid -9244800 # 14.06.2009 16:54
+ # repeat day 1 # status 0 ************** DISABLED SO THAT SUITE CAN COMPLETE *****************
+ edit SMSTRIES '2'
+ edit SMSCMD 'smssubmit.x %SMSJOB% hades rdx'
+ edit SMSHOME '/vol/rdx_dir/mars_stats/sms'
+ edit SMSINCLUDE '/vol/rdx_dir/mars_stats/sms/include'
+ edit SMSFILES '/vol/rdx_dir/mars_stats/sms/weather'
+ edit SMSSTATUSCMD 'smscheck %SCHOST% %EXPVER% %SMSJOB%'
+ edit ACCOUNT 'ecrmna'
+ edit OWNER 'naw'
+ edit EXPVER 'weather'
+ edit LOGDIR '/scratch/rd/rdx'
+ edit USER 'rdx'
+ edit QUEUE 'normal'
+ edit ECFS 'no'
+ family naw
+ family main
+ edit WSHOST 'linux_cluster'
+ edit SCHOST 'c1a'
+ edit CPUTIME '30000'
+ edit MEM '800'
+ edit SMSLOGPORT '9314'
+ edit SMSLOGHOST 'c1a-batch'
+ edit SMSKILL '/home/rd/rdx/bin/smskill %USER% %WSHOST% %SMSRID% %SMSJOB%'
+ edit SMSCMD '/home/rd/rdx/bin/smssubmit.x.nils %SMSJOB% %WSHOST% %USER%'
+ edit LOGDIR '/vol/explog/outputs'
+ family scm
+ edit LONG 'yes'
+ edit START12 'yes'
+ task getmars_scm
+ edit SMSKILL '/home/rd/rdx/bin/smskill %USER% %SCHOST% %SMSRID% %SMSJOB%'
+ edit SMSCMD '/home/rd/rdx/bin/smssubmit.x %SMSJOB% %SCHOST% %USER%'
+ edit LOGDIR '/c1a/rdx_dir/log'
+ edit SMSPASS 'FREE'
+ # time 17:45
+ task getdata_scm
+ trigger getmars_scm eq complete
+ edit CLASS 'np'
+ edit NPES '8'
+ edit MEM '800'
+ edit SMSKILL '/home/rd/rdx/bin/smskill %USER% %SCHOST% %SMSRID% %SMSJOB%'
+ edit SMSCMD '/home/rd/rdx/bin/smssubmit.x %SMSJOB% %SCHOST% %USER%'
+ edit LOGDIR '/c1a/rdx_dir/log'
+ task benson
+ trigger getdata_scm eq complete
+ task chilbolton
+ trigger getdata_scm eq complete
+ task husbos
+ trigger getdata_scm eq complete
+ task belvoir_castle
+ trigger getdata_scm eq complete
+ task york
+ trigger getdata_scm eq complete
+ task welshpool
+ trigger getdata_scm eq complete
+ task newmarket
+ trigger getdata_scm eq complete
+ task cabauw
+ defstatus complete
+ trigger getdata_scm eq complete
+ edit SMSPASS 'FREE'
+ task arm_sgp
+ defstatus complete
+ trigger getdata_scm eq complete
+ task vocals0850W
+ defstatus complete
+ trigger getdata_scm eq complete
+ task vocals0750W
+ defstatus complete
+ trigger getdata_scm eq complete
+ task web
+ trigger benson eq complete and chilbolton eq complete and husbos eq complete and belvoir_castle eq complete and york eq complete and welshpool eq complete and newmarket eq complete and cabauw eq complete and arm_sgp eq complete and vocals0750W eq complete and vocals0850W eq complete
+ endfamily
+ endfamily
+ endfamily
+endsuite
+#============================================================
diff --git a/CSim/test/data/good_defs/operations/naw.def.log b/CSim/test/data/good_defs/operations/naw.def.log
new file mode 100644
index 0000000..39a4d42
--- /dev/null
+++ b/CSim/test/data/good_defs/operations/naw.def.log
@@ -0,0 +1,270 @@
+LOG:[12:27:18 12.5.2016] queued: /weather
+LOG:[12:27:18 12.5.2016] queued: /weather/naw
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/general
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/general/metgrams
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/general/equipot
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/general
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/tephi
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/tephi/rd_tephi
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/tephi/tephi
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main/scm_quick
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main/scm_quick/getmars_scm
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main/scm_quick/getdata_scm
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main/scm_quick/benson
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main/scm_quick/chilbolton
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main/scm_quick/husbos
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main/scm_quick/belvoir_castle
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main/scm_quick/york
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main/scm_quick/welshpool
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main/scm_quick/newmarket
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main/scm
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main/scm/getmars_scm
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main/scm/getdata_scm
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main/scm/benson
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main/scm/chilbolton
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main/scm/husbos
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main/scm/belvoir_castle
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main/scm/york
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main/scm/welshpool
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main/scm/newmarket
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main/scm/cabauw
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main/scm/arm_sgp
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/main/scm/vocals0850W
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/main/scm/vocals0750W
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main/scm/web
+LOG:[12:27:18 12.5.2016] queued: /weather12
+LOG:[12:27:18 12.5.2016] queued: /weather12/naw
+LOG:[12:27:18 12.5.2016] queued: /weather12/naw/main
+LOG:[12:27:18 12.5.2016] queued: /weather12/naw/main/scm
+LOG:[12:27:18 12.5.2016] queued: /weather12/naw/main/scm/getmars_scm
+LOG:[12:27:18 12.5.2016] queued: /weather12/naw/main/scm/getdata_scm
+LOG:[12:27:18 12.5.2016] queued: /weather12/naw/main/scm/benson
+LOG:[12:27:18 12.5.2016] queued: /weather12/naw/main/scm/chilbolton
+LOG:[12:27:18 12.5.2016] queued: /weather12/naw/main/scm/husbos
+LOG:[12:27:18 12.5.2016] queued: /weather12/naw/main/scm/belvoir_castle
+LOG:[12:27:18 12.5.2016] queued: /weather12/naw/main/scm/york
+LOG:[12:27:18 12.5.2016] queued: /weather12/naw/main/scm/welshpool
+LOG:[12:27:18 12.5.2016] queued: /weather12/naw/main/scm/newmarket
+LOG:[12:27:18 12.5.2016] complete: /weather12/naw/main/scm/cabauw
+LOG:[12:27:18 12.5.2016] complete: /weather12/naw/main/scm/arm_sgp
+LOG:[12:27:18 12.5.2016] complete: /weather12/naw/main/scm/vocals0850W
+LOG:[12:27:18 12.5.2016] complete: /weather12/naw/main/scm/vocals0750W
+LOG:[12:27:18 12.5.2016] queued: /weather12/naw/main/scm/web
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/tephi/tephi
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/tephi
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw
+LOG:[12:27:18 12.5.2016] submitted: /weather
+LOG:[12:27:18 12.5.2016] submitted: /
+LOG:[12:27:18 12.5.2016] active: /weather/naw/tephi/tephi
+LOG:[12:27:18 12.5.2016] active: /weather/naw/tephi
+LOG:[12:27:18 12.5.2016] active: /weather/naw
+LOG:[12:27:18 12.5.2016] active: /weather
+LOG:[12:27:18 12.5.2016] active: /
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main/scm_quick/getmars_scm
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main/scm_quick
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main/scm_quick/getmars_scm
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main/scm_quick
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main/scm/getmars_scm
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main/scm
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main/scm/getmars_scm
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main/scm
+LOG:[12:27:18 12.5.2016] submitted: /weather12/naw/main/scm/getmars_scm
+LOG:[12:27:18 12.5.2016] submitted: /weather12/naw/main/scm
+LOG:[12:27:18 12.5.2016] submitted: /weather12/naw/main
+LOG:[12:27:18 12.5.2016] submitted: /weather12/naw
+LOG:[12:27:18 12.5.2016] submitted: /weather12
+LOG:[12:27:18 12.5.2016] active: /weather12/naw/main/scm/getmars_scm
+LOG:[12:27:18 12.5.2016] active: /weather12/naw/main/scm
+LOG:[12:27:18 12.5.2016] active: /weather12/naw/main
+LOG:[12:27:18 12.5.2016] active: /weather12/naw
+LOG:[12:27:18 12.5.2016] active: /weather12
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/tephi/tephi
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/tephi
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/main/scm_quick/getmars_scm
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main/scm_quick
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main/scm_quick/getdata_scm
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main/scm_quick
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main/scm_quick/getdata_scm
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main/scm_quick
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/main/scm_quick/getdata_scm
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main/scm_quick
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main/scm_quick/benson
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main/scm_quick
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main/scm_quick/benson
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main/scm_quick
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main/scm_quick/chilbolton
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main/scm_quick/chilbolton
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main/scm_quick/husbos
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main/scm_quick/husbos
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main/scm_quick/belvoir_castle
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main/scm_quick/belvoir_castle
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main/scm_quick/york
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main/scm_quick/york
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main/scm_quick/welshpool
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main/scm_quick/welshpool
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main/scm_quick/newmarket
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main/scm_quick/newmarket
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/main/scm_quick/benson
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/main/scm_quick/chilbolton
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/main/scm_quick/husbos
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/main/scm_quick/belvoir_castle
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/main/scm_quick/york
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/main/scm_quick/welshpool
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/main/scm_quick/newmarket
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/main/scm_quick
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/main/scm/getmars_scm
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main/scm
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main
+LOG:[12:27:18 12.5.2016] queued: /weather/naw
+LOG:[12:27:18 12.5.2016] queued: /weather
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main/scm/getdata_scm
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main/scm
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw
+LOG:[12:27:18 12.5.2016] submitted: /weather
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main/scm/getdata_scm
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main/scm
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main
+LOG:[12:27:18 12.5.2016] active: /weather/naw
+LOG:[12:27:18 12.5.2016] active: /weather
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/main/scm/getdata_scm
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main/scm
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main
+LOG:[12:27:18 12.5.2016] queued: /weather/naw
+LOG:[12:27:18 12.5.2016] queued: /weather
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main/scm/benson
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main/scm
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw
+LOG:[12:27:18 12.5.2016] submitted: /weather
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main/scm/benson
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main/scm
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main
+LOG:[12:27:18 12.5.2016] active: /weather/naw
+LOG:[12:27:18 12.5.2016] active: /weather
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main/scm/chilbolton
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main/scm/chilbolton
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main/scm/husbos
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main/scm/husbos
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main/scm/belvoir_castle
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main/scm/belvoir_castle
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main/scm/york
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main/scm/york
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main/scm/welshpool
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main/scm/welshpool
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main/scm/newmarket
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main/scm/newmarket
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main/scm/cabauw
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main/scm/cabauw
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main/scm/arm_sgp
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main/scm/arm_sgp
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/main/scm/benson
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/main/scm/chilbolton
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/main/scm/husbos
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/main/scm/belvoir_castle
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/main/scm/york
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/main/scm/welshpool
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/main/scm/newmarket
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/main/scm/cabauw
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/main/scm/arm_sgp
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main/scm
+LOG:[12:27:18 12.5.2016] queued: /weather/naw/main
+LOG:[12:27:18 12.5.2016] queued: /weather/naw
+LOG:[12:27:18 12.5.2016] queued: /weather
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main/scm/web
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main/scm
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw/main
+LOG:[12:27:18 12.5.2016] submitted: /weather/naw
+LOG:[12:27:18 12.5.2016] submitted: /weather
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main/scm/web
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main/scm
+LOG:[12:27:18 12.5.2016] active: /weather/naw/main
+LOG:[12:27:18 12.5.2016] active: /weather/naw
+LOG:[12:27:18 12.5.2016] active: /weather
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/main/scm/web
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/main/scm
+LOG:[12:27:18 12.5.2016] complete: /weather/naw/main
+LOG:[12:27:18 12.5.2016] complete: /weather/naw
+LOG:[12:27:18 12.5.2016] complete: /weather
+LOG:[12:27:18 12.5.2016] complete: /weather12/naw/main/scm/getmars_scm
+LOG:[12:27:18 12.5.2016] queued: /weather12/naw/main/scm
+LOG:[12:27:18 12.5.2016] queued: /weather12/naw/main
+LOG:[12:27:18 12.5.2016] queued: /weather12/naw
+LOG:[12:27:18 12.5.2016] queued: /weather12
+LOG:[12:27:18 12.5.2016] queued: /
+LOG:[12:27:18 12.5.2016] submitted: /weather12/naw/main/scm/getdata_scm
+LOG:[12:27:18 12.5.2016] submitted: /weather12/naw/main/scm
+LOG:[12:27:18 12.5.2016] submitted: /weather12/naw/main
+LOG:[12:27:18 12.5.2016] submitted: /weather12/naw
+LOG:[12:27:18 12.5.2016] submitted: /weather12
+LOG:[12:27:18 12.5.2016] submitted: /
+LOG:[12:27:18 12.5.2016] active: /weather12/naw/main/scm/getdata_scm
+LOG:[12:27:18 12.5.2016] active: /weather12/naw/main/scm
+LOG:[12:27:18 12.5.2016] active: /weather12/naw/main
+LOG:[12:27:18 12.5.2016] active: /weather12/naw
+LOG:[12:27:18 12.5.2016] active: /weather12
+LOG:[12:27:18 12.5.2016] active: /
+LOG:[12:27:18 12.5.2016] complete: /weather12/naw/main/scm/getdata_scm
+LOG:[12:27:18 12.5.2016] queued: /weather12/naw/main/scm
+LOG:[12:27:18 12.5.2016] queued: /weather12/naw/main
+LOG:[12:27:18 12.5.2016] queued: /weather12/naw
+LOG:[12:27:18 12.5.2016] queued: /weather12
+LOG:[12:27:18 12.5.2016] queued: /
+LOG:[12:27:18 12.5.2016] submitted: /weather12/naw/main/scm/benson
+LOG:[12:27:18 12.5.2016] submitted: /weather12/naw/main/scm
+LOG:[12:27:18 12.5.2016] submitted: /weather12/naw/main
+LOG:[12:27:18 12.5.2016] submitted: /weather12/naw
+LOG:[12:27:18 12.5.2016] submitted: /weather12
+LOG:[12:27:18 12.5.2016] submitted: /
+LOG:[12:27:18 12.5.2016] active: /weather12/naw/main/scm/benson
+LOG:[12:27:18 12.5.2016] active: /weather12/naw/main/scm
+LOG:[12:27:18 12.5.2016] active: /weather12/naw/main
+LOG:[12:27:18 12.5.2016] active: /weather12/naw
+LOG:[12:27:18 12.5.2016] active: /weather12
+LOG:[12:27:18 12.5.2016] active: /
+LOG:[12:27:18 12.5.2016] submitted: /weather12/naw/main/scm/chilbolton
+LOG:[12:27:18 12.5.2016] active: /weather12/naw/main/scm/chilbolton
+LOG:[12:27:18 12.5.2016] submitted: /weather12/naw/main/scm/husbos
+LOG:[12:27:18 12.5.2016] active: /weather12/naw/main/scm/husbos
+LOG:[12:27:18 12.5.2016] submitted: /weather12/naw/main/scm/belvoir_castle
+LOG:[12:27:18 12.5.2016] active: /weather12/naw/main/scm/belvoir_castle
+LOG:[12:27:18 12.5.2016] submitted: /weather12/naw/main/scm/york
+LOG:[12:27:18 12.5.2016] active: /weather12/naw/main/scm/york
+LOG:[12:27:18 12.5.2016] submitted: /weather12/naw/main/scm/welshpool
+LOG:[12:27:18 12.5.2016] active: /weather12/naw/main/scm/welshpool
+LOG:[12:27:18 12.5.2016] submitted: /weather12/naw/main/scm/newmarket
+LOG:[12:27:18 12.5.2016] active: /weather12/naw/main/scm/newmarket
+LOG:[12:27:18 12.5.2016] complete: /weather12/naw/main/scm/benson
+LOG:[12:27:18 12.5.2016] complete: /weather12/naw/main/scm/chilbolton
+LOG:[12:27:18 12.5.2016] complete: /weather12/naw/main/scm/husbos
+LOG:[12:27:18 12.5.2016] complete: /weather12/naw/main/scm/belvoir_castle
+LOG:[12:27:18 12.5.2016] complete: /weather12/naw/main/scm/york
+LOG:[12:27:18 12.5.2016] complete: /weather12/naw/main/scm/welshpool
+LOG:[12:27:18 12.5.2016] complete: /weather12/naw/main/scm/newmarket
+LOG:[12:27:18 12.5.2016] queued: /weather12/naw/main/scm
+LOG:[12:27:18 12.5.2016] queued: /weather12/naw/main
+LOG:[12:27:18 12.5.2016] queued: /weather12/naw
+LOG:[12:27:18 12.5.2016] queued: /weather12
+LOG:[12:27:18 12.5.2016] queued: /
+LOG:[12:27:18 12.5.2016] submitted: /weather12/naw/main/scm/web
+LOG:[12:27:18 12.5.2016] submitted: /weather12/naw/main/scm
+LOG:[12:27:18 12.5.2016] submitted: /weather12/naw/main
+LOG:[12:27:18 12.5.2016] submitted: /weather12/naw
+LOG:[12:27:18 12.5.2016] submitted: /weather12
+LOG:[12:27:18 12.5.2016] submitted: /
+LOG:[12:27:18 12.5.2016] active: /weather12/naw/main/scm/web
+LOG:[12:27:18 12.5.2016] active: /weather12/naw/main/scm
+LOG:[12:27:18 12.5.2016] active: /weather12/naw/main
+LOG:[12:27:18 12.5.2016] active: /weather12/naw
+LOG:[12:27:18 12.5.2016] active: /weather12
+LOG:[12:27:18 12.5.2016] active: /
+LOG:[12:27:18 12.5.2016] complete: /weather12/naw/main/scm/web
+LOG:[12:27:18 12.5.2016] complete: /weather12/naw/main/scm
+LOG:[12:27:18 12.5.2016] complete: /weather12/naw/main
+LOG:[12:27:18 12.5.2016] complete: /weather12/naw
+LOG:[12:27:18 12.5.2016] complete: /weather12
+LOG:[12:27:18 12.5.2016] complete: /
+MSG:[12:27:18 12.5.2016] Simulation complete in 00:00:00
diff --git a/CSim/test/data/good_defs/operations/xbe.def b/CSim/test/data/good_defs/operations/xbe.def
new file mode 100644
index 0000000..d61516c
--- /dev/null
+++ b/CSim/test/data/good_defs/operations/xbe.def
@@ -0,0 +1,9134 @@
+#============================================================
+extern an
+extern an
+extern fc
+extern fc
+extern eps_sv
+extern eps_sv
+extern eps_fc
+extern eps_fc
+extern oceatm
+extern oceatm
+extern oce
+extern oce
+extern fpos
+extern fpos
+extern sens
+extern sens
+extern wam
+extern wam
+extern oc
+extern oc
+extern climplot
+extern climplot
+extern coup
+extern coup
+extern an
+extern an
+extern fc
+extern fc
+extern eps_sv
+extern eps_sv
+extern eps_fc
+extern eps_fc
+extern oceatm
+extern oceatm
+extern oce
+extern oce
+extern fpos
+extern fpos
+extern sens
+extern sens
+extern wam
+extern wam
+extern oc
+extern oc
+extern climplot
+extern climplot
+extern coup
+extern coup
+suite cu9
+ clock hybrid 0 # 27.11.2008 16:54
+ family a01d
+ edit SMSTRIES '1'
+ edit SMSFILES '/vol/msverify/sms/cu9/a01d'
+ edit SMSINCLUDE '/vol/msverify/sms/cu9/a01d/include'
+ edit SMSHOME '/vol/msverify/sms'
+ edit SMSOUT '/vol/msverify/sms'
+ edit SMSLOGPORT '9314'
+ edit SMSLOGHOST 'hpce-batch'
+ edit FSFAMILY ''
+ edit DELTA_DAY '0'
+ edit HOUR ''
+ edit MEMBER '0'
+ edit NPROCA '1'
+ edit NPROCB '1'
+ edit THREADS '1'
+ edit BRANCH ''
+ edit PROJECTS 'none'
+ edit PARALLEL '4'
+ edit DEBUG '0'
+ edit PROFILE '0'
+ edit DISPLAY 'define_your_own:0.0'
+ edit QUEUE 'normal'
+ edit SCHOST 'hpce'
+ edit WSHOST 'ecgate'
+ edit LOGHOST 'linux_cluster'
+ edit EXPVER 'a01d'
+ edit OWNER 'cu9'
+ edit USER 'xbe'
+ edit ACCOUNT 'betro3'
+ edit YMD '2008021112'
+ edit SECS '43200'
+ edit SMSCMD 'smssubmit.x %SMSJOB% %SCHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %SCHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %SCHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/hpce/rdx_dir/msx'
+ family make
+ edit YMD '2008021112'
+ edit HOUR ''
+ edit FSFAMILY 'make'
+ task setup
+ edit QUEUE 'normal'
+ family libs
+ defstatus complete
+ trigger setup eq complete
+ edit CCSUBDIR '.'
+ task p4setup_ifs
+ edit SMSTRIES '2'
+ task p4diff_ifs
+ trigger p4setup_ifs eq complete
+ family compile
+ trigger p4setup_ifs eq complete
+ family ifsaux
+ defstatus complete
+ task libifsaux
+ endfamily
+ family surf
+ defstatus complete
+ trigger ifsaux eq complete
+ task libsurf
+ endfamily
+ family trans
+ defstatus complete
+ trigger ifsaux eq complete
+ task libtrans
+ endfamily
+ family ifs
+ defstatus complete
+ trigger ( ifsaux eq complete or ifsaux eq unknown) and ( trans eq complete or trans eq unknown) and ( surf eq complete or surf eq unknown)
+ task libifs
+ endfamily
+ family wam
+ defstatus complete
+ trigger ifsaux eq complete
+ task libwam
+ endfamily
+ family odb
+ defstatus complete
+ family compiler
+ task libodbsqlcompiler
+ endfamily
+ family databases
+ trigger compiler eq complete
+ family CCMA
+ task libCCMA
+ endfamily
+ family ECMA
+ task libECMA
+ endfamily
+ endfamily
+ family corelibs
+ trigger ../ifsaux eq complete
+ family odb
+ task libodb
+ endfamily
+ family odbdummy
+ trigger odb/libodb eq complete
+ task libodbdummy
+ endfamily
+ family odbmain
+ trigger odb/libodb eq complete and odbdummy/libodbdummy eq complete and ../../ifs eq complete
+ task libodbmain
+ endfamily
+ family odbport
+ trigger odb/libodb eq complete and odbdummy/libodbdummy eq complete and odbmain/libodbmain eq complete and ../../ifs eq complete
+ task libodbport
+ endfamily
+ endfamily
+ endfamily
+ family ssa
+ defstatus complete
+ trigger ifsaux eq complete and ifs eq complete and odb/corelibs/odb/libodb eq complete
+ task libssa
+ endfamily
+ family obstat
+ defstatus complete
+ trigger ifsaux eq complete and odb/corelibs/odb/libodb eq complete
+ task libobstat
+ endfamily
+ family bl
+ defstatus complete
+ trigger ifsaux eq complete
+ task libbl95
+ endfamily
+ family scat
+ defstatus complete
+ trigger ifsaux eq complete
+ task libscat
+ endfamily
+ family satrad
+ defstatus complete
+ trigger ifsaux eq complete
+ task libsatrad
+ endfamily
+ family aeolus
+ defstatus complete
+ trigger ifsaux eq complete
+ task libaeolus
+ endfamily
+ family prepdata
+ defstatus complete
+ trigger ( ifsaux eq complete or ifsaux eq unknown) and ( trans eq complete or trans eq unknown) and ( ifs eq complete or ifs eq unknown)
+ task libprepdata
+ endfamily
+ endfamily
+ endfamily
+ task links
+ trigger ( setup eq complete or setup eq unknown) and ( libs eq complete or libs eq unknown)
+ edit QUEUE 'normal'
+ task logfiles
+ trigger ( links eq complete or links eq unknown)
+ edit SMSCMD 'smssubmit.x %SMSJOB% %SCHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %SCHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %SCHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/hpce/rdx_dir/msx'
+ endfamily
+ family eps_varfc
+ limit SC 6
+ limit PIC 6
+ edit STREAM 'ENFO'
+ edit FSFAMILY 'mc'
+ edit HOUR ''
+ edit SMSCMD 'smssubmit.x %SMSJOB% %SCHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %SCHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %SCHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/hpce/rdx_dir/msx'
+ family make
+ trigger ../make eq complete
+ edit YMD '2008021112'
+ edit HOUR '12'
+ task setup
+ edit QUEUE 'normal'
+ family bins
+ trigger ../../make/links eq complete and ./setup eq complete
+ task ifs
+ task wamabs
+ edit QUEUE 'normal'
+ task mc_tools
+ task prepdata
+ task ma_tools
+ defstatus complete
+ endfamily
+ family const
+ task datalinks
+ trigger ../setup eq complete
+ task wconstA
+ trigger ../bins/wamabs eq complete
+ edit WAMRESOL 'global100'
+ edit WAMNFRE '30'
+ edit WAMNANG '24'
+ task wconstB
+ trigger ./wconstA eq complete
+ edit WAMRESOL 'global100'
+ edit WAMNFRE '25'
+ edit WAMNANG '12'
+ task wconstC
+ trigger ./wconstB eq complete
+ edit WAMRESOL 'global300'
+ edit WAMNFRE '25'
+ edit WAMNANG '12'
+ task getsst
+ defstatus complete
+ trigger ../setup eq complete and ../../main/fc/inigroup/getini eq complete
+ endfamily
+ task logfiles
+ trigger bins eq complete and const eq complete
+ edit SMSCMD 'smssubmit.x %SMSJOB% %SCHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %SCHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %SCHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/hpce/rdx_dir/msx'
+ endfamily
+ family main
+ family sv
+ defstatus complete
+ repeat string YMD "2008021112" # status 0
+ edit EPSTYPE 'sv'
+ edit EPSSVTCSUB '1'
+ edit EPSSVOP '1'
+ task getini
+ trigger ../../make/const/datalinks eq complete
+ edit QUEUE 'normal'
+ edit INISTREAM 'DCDA'
+ edit INISTEP '6'
+ edit INITYPE 'fc'
+ edit PRIORITY '40'
+ task inidata_sv
+ trigger ../../make/bins/ifs eq complete and getini eq complete
+ edit QUEUE 'parallel'
+ edit NPES '16'
+ edit THREADS '4'
+ edit MEM '960'
+ edit CPUTIME '1000'
+ task svnh
+ trigger inidata_sv eq complete
+ edit FCLENGTH '48'
+ edit MEMBER '0'
+ edit EPSTROP '0'
+ edit EPSHEM '1'
+ edit MEM '960'
+ edit NPES '16'
+ edit THREADS '2'
+ edit CPUTIME '6000'
+ edit QUEUE 'normal'
+ task svsh
+ trigger inidata_sv eq complete
+ edit FCLENGTH '48'
+ edit MEMBER '0'
+ edit EPSTROP '0'
+ edit EPSHEM '2'
+ edit MEM '960'
+ edit NPES '16'
+ edit THREADS '2'
+ edit CPUTIME '6000'
+ edit QUEUE 'normal'
+ task targets
+ trigger ../../make/bins/mc_tools eq complete
+ task subspace
+ trigger svnh eq complete and svsh eq complete and targets eq complete
+ task sv1
+ trigger targets eq complete and subspace eq complete
+ edit FCLENGTH '48'
+ edit MEMBER '1'
+ edit EPSTROP '1'
+ edit MEM '960'
+ edit NPES '16'
+ edit THREADS '2'
+ edit CPUTIME '6000'
+ edit QUEUE 'normal'
+ task sv2
+ trigger targets eq complete and subspace eq complete
+ edit FCLENGTH '48'
+ edit MEMBER '2'
+ edit EPSTROP '1'
+ edit MEM '960'
+ edit NPES '16'
+ edit THREADS '2'
+ edit CPUTIME '6000'
+ edit QUEUE 'normal'
+ task sv3
+ trigger targets eq complete and subspace eq complete
+ edit FCLENGTH '48'
+ edit MEMBER '3'
+ edit EPSTROP '1'
+ edit MEM '960'
+ edit NPES '16'
+ edit THREADS '2'
+ edit CPUTIME '6000'
+ edit QUEUE 'normal'
+ task sv4
+ trigger targets eq complete and subspace eq complete
+ edit FCLENGTH '48'
+ edit MEMBER '4'
+ edit EPSTROP '1'
+ edit MEM '960'
+ edit NPES '16'
+ edit THREADS '2'
+ edit CPUTIME '6000'
+ edit QUEUE 'normal'
+ task sv5
+ trigger targets eq complete and subspace eq complete
+ edit FCLENGTH '48'
+ edit MEMBER '5'
+ edit EPSTROP '1'
+ edit MEM '960'
+ edit NPES '16'
+ edit THREADS '2'
+ edit CPUTIME '6000'
+ edit QUEUE 'normal'
+ task sv6
+ trigger targets eq complete and subspace eq complete
+ edit FCLENGTH '48'
+ edit MEMBER '6'
+ edit EPSTROP '1'
+ edit MEM '960'
+ edit NPES '16'
+ edit THREADS '2'
+ edit CPUTIME '6000'
+ edit QUEUE 'normal'
+ task svnhevo
+ trigger svnh eq complete
+ edit FCLENGTH '48'
+ edit EPSHEM '1'
+ edit MEM '960'
+ edit NPES '16'
+ edit THREADS '2'
+ edit CPUTIME '6000'
+ edit QUEUE 'normal'
+ task svshevo
+ trigger svsh eq complete
+ edit FCLENGTH '48'
+ edit EPSHEM '2'
+ edit MEM '960'
+ edit NPES '16'
+ edit THREADS '2'
+ edit CPUTIME '6000'
+ edit QUEUE 'normal'
+ task svsave
+ trigger svnh eq complete and svsh eq complete and sv1 eq complete and sv2 eq complete and sv3 eq complete and sv4 eq complete and sv5 eq complete and sv6 eq complete and svnhevo eq complete and svshevo eq complete
+ task logfiles
+ trigger svsave eq complete
+ edit SMSCMD 'smssubmit.x %SMSJOB% %SCHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %SCHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %SCHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/hpce/rdx_dir/msx'
+ endfamily
+ family fc
+ family inigroup
+ repeat string YMD "2008021112" # status 1
+ trigger ( ../sv:YMD gt inigroup:YMD or ../sv eq complete) and ( inigroup:YMD lt ( ensemble:YMD + 2))
+ complete ( inigroup:YMD eq ~ 1)
+ task getini
+ trigger ../../../make/setup eq complete
+ edit QUEUE 'normal'
+ edit INISTREAM 'DA'
+ edit INISTEP '0'
+ edit INITYPE '4v'
+ edit PRIORITY '40'
+ task inidata
+ trigger ../../../make/bins/ifs eq complete and getini eq complete and ../../../make/const/getsst eq complete
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit QUEUE 'parallel'
+ edit NPES '16'
+ edit THREADS '4'
+ edit MEM '960'
+ edit CPUTIME '1000'
+ task wavini
+ trigger ../../../make/const/wconstA eq complete
+ edit QUEUE 'normal'
+ edit PRIORITY '40'
+ edit MEM '900'
+ edit NPES '1'
+ edit THREADS '1'
+ edit CPUTIME '8000'
+ task wcold
+ defstatus complete
+ trigger inidata eq complete and wavini eq complete
+ edit QUEUE 'normal'
+ edit MEM '900'
+ edit NPES '8'
+ edit THREADS '1'
+ edit CPUTIME '3000'
+ task wavfcdata
+ trigger ./wcold eq complete and ../../../make eq complete and wavini eq complete
+ task getsvs
+ trigger ../../../make/bins/mc_tools eq complete
+ edit EPSTROP '1'
+ task getae
+ trigger ./getini eq complete and ./getsvs eq complete
+ event 1
+ task rot
+ trigger ./inidata eq complete and ./getae eq complete and ../../../make/bins/mc_tools eq complete
+ edit EPSTROP '1'
+ task geticp
+ defstatus complete
+ trigger getini eq complete
+ family pert_ic
+ inlimit PIC
+ trigger geticp eq complete and rot eq complete and ./inidata eq complete and ../../../make/bins/mc_tools eq complete
+ edit EPSTROP '1'
+ edit EPSFCLEV '62'
+ edit EPSFCRES '399'
+ family 000
+ edit MEMBER '0'
+ task pertinic
+ endfamily
+ family 001
+ edit MEMBER '1'
+ task pertinic
+ endfamily
+ family 002
+ edit MEMBER '2'
+ task pertinic
+ endfamily
+ family 003
+ edit MEMBER '3'
+ task pertinic
+ endfamily
+ family 004
+ edit MEMBER '4'
+ task pertinic
+ endfamily
+ family 005
+ edit MEMBER '5'
+ task pertinic
+ endfamily
+ family 006
+ edit MEMBER '6'
+ task pertinic
+ endfamily
+ family 007
+ edit MEMBER '7'
+ task pertinic
+ endfamily
+ family 008
+ edit MEMBER '8'
+ task pertinic
+ endfamily
+ family 009
+ edit MEMBER '9'
+ task pertinic
+ endfamily
+ family 010
+ edit MEMBER '10'
+ task pertinic
+ endfamily
+ family 011
+ edit MEMBER '11'
+ task pertinic
+ endfamily
+ family 012
+ edit MEMBER '12'
+ task pertinic
+ endfamily
+ family 013
+ edit MEMBER '13'
+ task pertinic
+ endfamily
+ family 014
+ edit MEMBER '14'
+ task pertinic
+ endfamily
+ family 015
+ edit MEMBER '15'
+ task pertinic
+ endfamily
+ family 016
+ edit MEMBER '16'
+ task pertinic
+ endfamily
+ family 017
+ edit MEMBER '17'
+ task pertinic
+ endfamily
+ family 018
+ edit MEMBER '18'
+ task pertinic
+ endfamily
+ family 019
+ edit MEMBER '19'
+ task pertinic
+ endfamily
+ family 020
+ edit MEMBER '20'
+ task pertinic
+ endfamily
+ family 021
+ edit MEMBER '21'
+ task pertinic
+ endfamily
+ family 022
+ edit MEMBER '22'
+ task pertinic
+ endfamily
+ family 023
+ edit MEMBER '23'
+ task pertinic
+ endfamily
+ family 024
+ edit MEMBER '24'
+ task pertinic
+ endfamily
+ family 025
+ edit MEMBER '25'
+ task pertinic
+ endfamily
+ family 026
+ edit MEMBER '26'
+ task pertinic
+ endfamily
+ family 027
+ edit MEMBER '27'
+ task pertinic
+ endfamily
+ family 028
+ edit MEMBER '28'
+ task pertinic
+ endfamily
+ family 029
+ edit MEMBER '29'
+ task pertinic
+ endfamily
+ family 030
+ edit MEMBER '30'
+ task pertinic
+ endfamily
+ family 031
+ edit MEMBER '31'
+ task pertinic
+ endfamily
+ family 032
+ edit MEMBER '32'
+ task pertinic
+ endfamily
+ family 033
+ edit MEMBER '33'
+ task pertinic
+ endfamily
+ family 034
+ edit MEMBER '34'
+ task pertinic
+ endfamily
+ family 035
+ edit MEMBER '35'
+ task pertinic
+ endfamily
+ family 036
+ edit MEMBER '36'
+ task pertinic
+ endfamily
+ family 037
+ edit MEMBER '37'
+ task pertinic
+ endfamily
+ family 038
+ edit MEMBER '38'
+ task pertinic
+ endfamily
+ family 039
+ edit MEMBER '39'
+ task pertinic
+ endfamily
+ family 040
+ edit MEMBER '40'
+ task pertinic
+ endfamily
+ family 041
+ edit MEMBER '41'
+ task pertinic
+ endfamily
+ family 042
+ edit MEMBER '42'
+ task pertinic
+ endfamily
+ family 043
+ edit MEMBER '43'
+ task pertinic
+ endfamily
+ family 044
+ edit MEMBER '44'
+ task pertinic
+ endfamily
+ family 045
+ edit MEMBER '45'
+ task pertinic
+ endfamily
+ family 046
+ edit MEMBER '46'
+ task pertinic
+ endfamily
+ family 047
+ edit MEMBER '47'
+ task pertinic
+ endfamily
+ family 048
+ edit MEMBER '48'
+ task pertinic
+ endfamily
+ family 049
+ edit MEMBER '49'
+ task pertinic
+ endfamily
+ family 050
+ edit MEMBER '50'
+ task pertinic
+ endfamily
+ endfamily
+ task cp_pert
+ trigger pert_ic eq complete
+ task logfiles
+ trigger wavfcdata eq complete and wavini eq complete and inidata eq complete and pert_ic eq complete and cp_pert eq complete and rot eq complete
+ edit SMSCMD 'smssubmit.x %SMSJOB% %SCHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %SCHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %SCHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/hpce/rdx_dir/msx'
+ endfamily
+ family ensemble
+ inlimit SC
+ repeat string YMD "2008021112" # status 1
+ trigger ( ( inigroup:YMD gt ensemble:YMD) or ( inigroup eq complete)) and ( ensemble:YMD eq lag:YMD)
+ complete ( ensemble:YMD eq ~ 1)
+ edit RUNVARFC '1'
+ edit HC_REFDATE '0'
+ family cv
+ defstatus complete
+ trigger ( ../inigroup:YMD gt ../ensemble:YMD) or ( ../inigroup/pert_ic/000 eq complete)
+ edit EPSTYPE 'cv'
+ family control_1
+ edit SUBFSFAMILY '/cv001'
+ edit EPSMEMBER '1'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task getiniLeg
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit PRIORITY '40'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit CPUTIME '2700'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '216'
+ edit TSTEP '1800'
+ meter step 0 216 216
+ endfamily
+ family control_2
+ edit SUBFSFAMILY '/cv002'
+ edit EPSMEMBER '2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ task intHtoLB
+ trigger ./getiniLeg eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ task modeleps
+ trigger ./intHtoLB eq complete
+ edit MEM '960'
+ edit NPES '16'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit CPUTIME 'INF'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '216'
+ edit TSTEP '2700'
+ meter step 0 216 216
+ endfamily
+ endfamily
+ family cf
+ edit EPSTYPE 'cf'
+ family control
+ trigger ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/000 eq complete)
+ edit SUBFSFAMILY '/cf000'
+ edit EPSMEMBER '0'
+ family legA
+ edit EPSCOUPLE '0'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ edit EPSLEG '2'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an0'
+ edit FCGROUP 'fc0'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ edit EPSLEG '3'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit EPSFCLENGTH_B '0'
+ edit EPSINISTEP_B '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ endfamily
+ family pf
+ edit EPSTYPE 'pf'
+ family 001
+ trigger ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/001 eq complete))
+ edit SUBFSFAMILY '/001'
+ edit EPSMEMBER '1'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an1'
+ edit FCGROUP 'fc0'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '1'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '1'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an1'
+ edit FCGROUP 'fc0'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '1'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '1'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '1'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an1'
+ edit FCGROUP 'fc0'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '1'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '1'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 002
+ trigger ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/002 eq complete))
+ edit SUBFSFAMILY '/002'
+ edit EPSMEMBER '2'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an2'
+ edit FCGROUP 'fc0'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '2'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '2'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an2'
+ edit FCGROUP 'fc0'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '2'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '2'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '2'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an2'
+ edit FCGROUP 'fc0'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '2'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '2'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 003
+ trigger ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/003 eq complete))
+ edit SUBFSFAMILY '/003'
+ edit EPSMEMBER '3'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an3'
+ edit FCGROUP 'fc0'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '3'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '3'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an3'
+ edit FCGROUP 'fc0'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '3'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '3'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '3'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an3'
+ edit FCGROUP 'fc0'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '3'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '3'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 004
+ trigger ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/004 eq complete))
+ edit SUBFSFAMILY '/004'
+ edit EPSMEMBER '4'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an4'
+ edit FCGROUP 'fc0'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '4'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '4'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an4'
+ edit FCGROUP 'fc0'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '4'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '4'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '4'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an4'
+ edit FCGROUP 'fc0'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '4'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '4'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 005
+ trigger ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/005 eq complete))
+ edit SUBFSFAMILY '/005'
+ edit EPSMEMBER '5'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an0'
+ edit FCGROUP 'fc1'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '5'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '5'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an0'
+ edit FCGROUP 'fc1'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '5'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '5'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '5'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an0'
+ edit FCGROUP 'fc1'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '5'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '5'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 006
+ trigger ( ./001/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/006 eq complete))
+ edit SUBFSFAMILY '/006'
+ edit EPSMEMBER '6'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an1'
+ edit FCGROUP 'fc1'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '6'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '6'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an1'
+ edit FCGROUP 'fc1'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '6'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '6'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '6'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an1'
+ edit FCGROUP 'fc1'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '6'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '6'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 007
+ trigger ( ./002/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/007 eq complete))
+ edit SUBFSFAMILY '/007'
+ edit EPSMEMBER '7'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an2'
+ edit FCGROUP 'fc1'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '7'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '7'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an2'
+ edit FCGROUP 'fc1'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '7'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '7'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '7'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an2'
+ edit FCGROUP 'fc1'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '7'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '7'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 008
+ trigger ( ./003/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/008 eq complete))
+ edit SUBFSFAMILY '/008'
+ edit EPSMEMBER '8'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an3'
+ edit FCGROUP 'fc1'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '8'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '8'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an3'
+ edit FCGROUP 'fc1'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '8'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '8'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '8'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an3'
+ edit FCGROUP 'fc1'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '8'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '8'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 009
+ trigger ( ./004/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/009 eq complete))
+ edit SUBFSFAMILY '/009'
+ edit EPSMEMBER '9'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an4'
+ edit FCGROUP 'fc1'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '9'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '9'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an4'
+ edit FCGROUP 'fc1'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '9'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '9'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '9'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an4'
+ edit FCGROUP 'fc1'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '9'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '9'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 010
+ trigger ( ./005/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/010 eq complete))
+ edit SUBFSFAMILY '/010'
+ edit EPSMEMBER '10'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an0'
+ edit FCGROUP 'fc2'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '10'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '10'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an0'
+ edit FCGROUP 'fc2'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '10'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '10'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '10'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an0'
+ edit FCGROUP 'fc2'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '10'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '10'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 011
+ trigger ( ./006/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/011 eq complete))
+ edit SUBFSFAMILY '/011'
+ edit EPSMEMBER '11'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an1'
+ edit FCGROUP 'fc2'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '11'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '11'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an1'
+ edit FCGROUP 'fc2'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '11'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '11'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '11'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an1'
+ edit FCGROUP 'fc2'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '11'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '11'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 012
+ trigger ( ./007/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/012 eq complete))
+ edit SUBFSFAMILY '/012'
+ edit EPSMEMBER '12'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an2'
+ edit FCGROUP 'fc2'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '12'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '12'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an2'
+ edit FCGROUP 'fc2'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '12'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '12'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '12'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an2'
+ edit FCGROUP 'fc2'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '12'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '12'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 013
+ trigger ( ./008/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/013 eq complete))
+ edit SUBFSFAMILY '/013'
+ edit EPSMEMBER '13'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an3'
+ edit FCGROUP 'fc2'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '13'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '13'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an3'
+ edit FCGROUP 'fc2'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '13'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '13'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '13'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an3'
+ edit FCGROUP 'fc2'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '13'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '13'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 014
+ trigger ( ./009/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/014 eq complete))
+ edit SUBFSFAMILY '/014'
+ edit EPSMEMBER '14'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an4'
+ edit FCGROUP 'fc2'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '14'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '14'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an4'
+ edit FCGROUP 'fc2'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '14'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '14'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '14'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an4'
+ edit FCGROUP 'fc2'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '14'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '14'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 015
+ trigger ( ./010/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/015 eq complete))
+ edit SUBFSFAMILY '/015'
+ edit EPSMEMBER '15'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an0'
+ edit FCGROUP 'fc3'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '15'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '15'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an0'
+ edit FCGROUP 'fc3'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '15'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '15'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '15'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an0'
+ edit FCGROUP 'fc3'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '15'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '15'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 016
+ trigger ( ./011/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/016 eq complete))
+ edit SUBFSFAMILY '/016'
+ edit EPSMEMBER '16'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an1'
+ edit FCGROUP 'fc3'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '16'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '16'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an1'
+ edit FCGROUP 'fc3'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '16'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '16'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '16'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an1'
+ edit FCGROUP 'fc3'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '16'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '16'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 017
+ trigger ( ./012/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/017 eq complete))
+ edit SUBFSFAMILY '/017'
+ edit EPSMEMBER '17'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an2'
+ edit FCGROUP 'fc3'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '17'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '17'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an2'
+ edit FCGROUP 'fc3'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '17'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '17'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '17'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an2'
+ edit FCGROUP 'fc3'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '17'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '17'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 018
+ trigger ( ./013/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/018 eq complete))
+ edit SUBFSFAMILY '/018'
+ edit EPSMEMBER '18'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an3'
+ edit FCGROUP 'fc3'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '18'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '18'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an3'
+ edit FCGROUP 'fc3'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '18'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '18'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '18'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an3'
+ edit FCGROUP 'fc3'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '18'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '18'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 019
+ trigger ( ./014/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/019 eq complete))
+ edit SUBFSFAMILY '/019'
+ edit EPSMEMBER '19'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an4'
+ edit FCGROUP 'fc3'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '19'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '19'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an4'
+ edit FCGROUP 'fc3'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '19'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '19'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '19'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an4'
+ edit FCGROUP 'fc3'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '19'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '19'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 020
+ trigger ( ./015/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/020 eq complete))
+ edit SUBFSFAMILY '/020'
+ edit EPSMEMBER '20'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an0'
+ edit FCGROUP 'fc4'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '20'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '20'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an0'
+ edit FCGROUP 'fc4'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '20'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '20'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '20'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an0'
+ edit FCGROUP 'fc4'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '20'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '20'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 021
+ trigger ( ./016/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/021 eq complete))
+ edit SUBFSFAMILY '/021'
+ edit EPSMEMBER '21'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an1'
+ edit FCGROUP 'fc4'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '21'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '21'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an1'
+ edit FCGROUP 'fc4'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '21'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '21'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '21'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an1'
+ edit FCGROUP 'fc4'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '21'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '21'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 022
+ trigger ( ./017/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/022 eq complete))
+ edit SUBFSFAMILY '/022'
+ edit EPSMEMBER '22'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an2'
+ edit FCGROUP 'fc4'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '22'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '22'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an2'
+ edit FCGROUP 'fc4'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '22'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '22'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '22'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an2'
+ edit FCGROUP 'fc4'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '22'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '22'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 023
+ trigger ( ./018/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/023 eq complete))
+ edit SUBFSFAMILY '/023'
+ edit EPSMEMBER '23'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an3'
+ edit FCGROUP 'fc4'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '23'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '23'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an3'
+ edit FCGROUP 'fc4'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '23'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '23'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '23'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an3'
+ edit FCGROUP 'fc4'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '23'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '23'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 024
+ trigger ( ./019/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/024 eq complete))
+ edit SUBFSFAMILY '/024'
+ edit EPSMEMBER '24'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an4'
+ edit FCGROUP 'fc4'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '24'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '24'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an4'
+ edit FCGROUP 'fc4'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '24'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '24'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '24'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an4'
+ edit FCGROUP 'fc4'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '24'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '24'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 025
+ trigger ( ./020/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/025 eq complete))
+ edit SUBFSFAMILY '/025'
+ edit EPSMEMBER '25'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an0'
+ edit FCGROUP 'fc5'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '25'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '25'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an0'
+ edit FCGROUP 'fc5'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '25'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '25'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '25'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an0'
+ edit FCGROUP 'fc5'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '25'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '25'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 026
+ trigger ( ./021/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/026 eq complete))
+ edit SUBFSFAMILY '/026'
+ edit EPSMEMBER '26'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an1'
+ edit FCGROUP 'fc5'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '26'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '26'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an1'
+ edit FCGROUP 'fc5'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '26'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '26'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '26'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an1'
+ edit FCGROUP 'fc5'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '26'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '26'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 027
+ trigger ( ./022/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/027 eq complete))
+ edit SUBFSFAMILY '/027'
+ edit EPSMEMBER '27'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an2'
+ edit FCGROUP 'fc5'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '27'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '27'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an2'
+ edit FCGROUP 'fc5'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '27'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '27'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '27'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an2'
+ edit FCGROUP 'fc5'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '27'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '27'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 028
+ trigger ( ./023/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/028 eq complete))
+ edit SUBFSFAMILY '/028'
+ edit EPSMEMBER '28'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an3'
+ edit FCGROUP 'fc5'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '28'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '28'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an3'
+ edit FCGROUP 'fc5'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '28'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '28'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '28'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an3'
+ edit FCGROUP 'fc5'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '28'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '28'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 029
+ trigger ( ./024/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/029 eq complete))
+ edit SUBFSFAMILY '/029'
+ edit EPSMEMBER '29'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an4'
+ edit FCGROUP 'fc5'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '29'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '29'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an4'
+ edit FCGROUP 'fc5'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '29'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '29'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '29'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an4'
+ edit FCGROUP 'fc5'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '29'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '29'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 030
+ trigger ( ./025/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/030 eq complete))
+ edit SUBFSFAMILY '/030'
+ edit EPSMEMBER '30'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an0'
+ edit FCGROUP 'fc6'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '30'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '30'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an0'
+ edit FCGROUP 'fc6'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '30'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '30'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '30'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an0'
+ edit FCGROUP 'fc6'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '30'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '30'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 031
+ trigger ( ./026/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/031 eq complete))
+ edit SUBFSFAMILY '/031'
+ edit EPSMEMBER '31'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an1'
+ edit FCGROUP 'fc6'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '31'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '31'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an1'
+ edit FCGROUP 'fc6'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '31'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '31'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '31'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an1'
+ edit FCGROUP 'fc6'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '31'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '31'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 032
+ trigger ( ./027/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/032 eq complete))
+ edit SUBFSFAMILY '/032'
+ edit EPSMEMBER '32'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an2'
+ edit FCGROUP 'fc6'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '32'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '32'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an2'
+ edit FCGROUP 'fc6'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '32'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '32'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '32'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an2'
+ edit FCGROUP 'fc6'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '32'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '32'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 033
+ trigger ( ./028/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/033 eq complete))
+ edit SUBFSFAMILY '/033'
+ edit EPSMEMBER '33'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an3'
+ edit FCGROUP 'fc6'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '33'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '33'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an3'
+ edit FCGROUP 'fc6'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '33'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '33'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '33'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an3'
+ edit FCGROUP 'fc6'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '33'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '33'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 034
+ trigger ( ./029/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/034 eq complete))
+ edit SUBFSFAMILY '/034'
+ edit EPSMEMBER '34'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an4'
+ edit FCGROUP 'fc6'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '34'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '34'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an4'
+ edit FCGROUP 'fc6'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '34'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '34'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '34'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an4'
+ edit FCGROUP 'fc6'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '34'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '34'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 035
+ trigger ( ./030/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/035 eq complete))
+ edit SUBFSFAMILY '/035'
+ edit EPSMEMBER '35'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an0'
+ edit FCGROUP 'fc7'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '35'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '35'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an0'
+ edit FCGROUP 'fc7'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '35'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '35'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '35'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an0'
+ edit FCGROUP 'fc7'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '35'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '35'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 036
+ trigger ( ./031/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/036 eq complete))
+ edit SUBFSFAMILY '/036'
+ edit EPSMEMBER '36'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an1'
+ edit FCGROUP 'fc7'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '36'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '36'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an1'
+ edit FCGROUP 'fc7'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '36'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '36'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '36'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an1'
+ edit FCGROUP 'fc7'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '36'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '36'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 037
+ trigger ( ./032/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/037 eq complete))
+ edit SUBFSFAMILY '/037'
+ edit EPSMEMBER '37'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an2'
+ edit FCGROUP 'fc7'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '37'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '37'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an2'
+ edit FCGROUP 'fc7'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '37'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '37'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '37'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an2'
+ edit FCGROUP 'fc7'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '37'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '37'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 038
+ trigger ( ./033/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/038 eq complete))
+ edit SUBFSFAMILY '/038'
+ edit EPSMEMBER '38'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an3'
+ edit FCGROUP 'fc7'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '38'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '38'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an3'
+ edit FCGROUP 'fc7'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '38'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '38'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '38'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an3'
+ edit FCGROUP 'fc7'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '38'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '38'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 039
+ trigger ( ./034/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/039 eq complete))
+ edit SUBFSFAMILY '/039'
+ edit EPSMEMBER '39'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an4'
+ edit FCGROUP 'fc7'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '39'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '39'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an4'
+ edit FCGROUP 'fc7'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '39'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '39'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '39'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an4'
+ edit FCGROUP 'fc7'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '39'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '39'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 040
+ trigger ( ./035/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/040 eq complete))
+ edit SUBFSFAMILY '/040'
+ edit EPSMEMBER '40'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an0'
+ edit FCGROUP 'fc8'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '40'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '40'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an0'
+ edit FCGROUP 'fc8'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '40'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '40'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '40'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an0'
+ edit FCGROUP 'fc8'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '40'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '40'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 041
+ trigger ( ./036/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/041 eq complete))
+ edit SUBFSFAMILY '/041'
+ edit EPSMEMBER '41'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an1'
+ edit FCGROUP 'fc8'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '41'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '41'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an1'
+ edit FCGROUP 'fc8'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '41'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '41'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '41'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an1'
+ edit FCGROUP 'fc8'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '41'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '41'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 042
+ trigger ( ./037/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/042 eq complete))
+ edit SUBFSFAMILY '/042'
+ edit EPSMEMBER '42'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an2'
+ edit FCGROUP 'fc8'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '42'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '42'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an2'
+ edit FCGROUP 'fc8'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '42'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '42'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '42'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an2'
+ edit FCGROUP 'fc8'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '42'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '42'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 043
+ trigger ( ./038/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/043 eq complete))
+ edit SUBFSFAMILY '/043'
+ edit EPSMEMBER '43'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an3'
+ edit FCGROUP 'fc8'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '43'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '43'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an3'
+ edit FCGROUP 'fc8'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '43'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '43'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '43'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an3'
+ edit FCGROUP 'fc8'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '43'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '43'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 044
+ trigger ( ./039/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/044 eq complete))
+ edit SUBFSFAMILY '/044'
+ edit EPSMEMBER '44'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an4'
+ edit FCGROUP 'fc8'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '44'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '44'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an4'
+ edit FCGROUP 'fc8'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '44'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '44'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '44'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an4'
+ edit FCGROUP 'fc8'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '44'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '44'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 045
+ trigger ( ./040/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/045 eq complete))
+ edit SUBFSFAMILY '/045'
+ edit EPSMEMBER '45'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an0'
+ edit FCGROUP 'fc9'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '45'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '45'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an0'
+ edit FCGROUP 'fc9'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '45'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '45'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '45'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an0'
+ edit FCGROUP 'fc9'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '45'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '45'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 046
+ trigger ( ./041/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/046 eq complete))
+ edit SUBFSFAMILY '/046'
+ edit EPSMEMBER '46'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an1'
+ edit FCGROUP 'fc9'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '46'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '46'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an1'
+ edit FCGROUP 'fc9'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '46'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '46'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '46'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an1'
+ edit FCGROUP 'fc9'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '46'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '46'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 047
+ trigger ( ./042/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/047 eq complete))
+ edit SUBFSFAMILY '/047'
+ edit EPSMEMBER '47'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an2'
+ edit FCGROUP 'fc9'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '47'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '47'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an2'
+ edit FCGROUP 'fc9'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '47'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '47'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '47'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an2'
+ edit FCGROUP 'fc9'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '47'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '47'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 048
+ trigger ( ./043/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/048 eq complete))
+ edit SUBFSFAMILY '/048'
+ edit EPSMEMBER '48'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an3'
+ edit FCGROUP 'fc9'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '48'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '48'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an3'
+ edit FCGROUP 'fc9'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '48'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '48'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '48'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an3'
+ edit FCGROUP 'fc9'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '48'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '48'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 049
+ trigger ( ./044/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/049 eq complete))
+ edit SUBFSFAMILY '/049'
+ edit EPSMEMBER '49'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an4'
+ edit FCGROUP 'fc9'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '49'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '49'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an4'
+ edit FCGROUP 'fc9'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '49'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '49'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '49'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an4'
+ edit FCGROUP 'fc9'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '49'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '49'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ family 050
+ trigger ( ./045/legB/modeleps eq complete) and ( ( ../../inigroup:YMD gt ../../ensemble:YMD) or ( ../../inigroup/pert_ic/050 eq complete))
+ edit SUBFSFAMILY '/050'
+ edit EPSMEMBER '50'
+ family legA
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an0'
+ edit FCGROUP 'fc10'
+ task getiniLeg
+ edit PRIORITY '40'
+ edit EPSMEMBER '50'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ task modeleps
+ trigger ./getiniLeg eq complete
+ edit MEM '960'
+ edit NPES '24'
+ edit CPUTIME '25000'
+ edit THREADS '4'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '1'
+ edit EPSMEMBER '50'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '240'
+ edit EPSINISTEP_PREVIOUS '0'
+ edit FCLENGTH '240'
+ edit TSTEP '1800'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '30'
+ edit EPSWAMNANG '24'
+ edit EPSWAMNSTPW '1'
+ meter step 0 240 240
+ endfamily
+ family legB
+ trigger legA eq complete
+ complete ( 2 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an0'
+ edit FCGROUP 'fc10'
+ task getvarepsdata
+ edit EPSLEG '2'
+ edit PRIORITY '40'
+ edit EPSMEMBER '50'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '399'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ complete ( 2 gt 1)
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSMEMBER '50'
+ edit EPSINISTEP '216'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ complete ( 2 gt 1)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '2'
+ edit EPSMEMBER '50'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '216'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global100'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ edit EPSFCLENGTH_A '240'
+ meter step 0 0 0
+ endfamily
+ family legC
+ trigger legB eq complete
+ complete ( 3 gt 1)
+ edit EPSCOUPLE '0'
+ edit OCGROUP 'an0'
+ edit FCGROUP 'fc10'
+ task getvarepsdata
+ edit EPSLEG '3'
+ edit PRIORITY '40'
+ edit EPSMEMBER '50'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '255'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ task intHtoL
+ trigger ./getvarepsdata eq complete
+ edit QUEUE 'parallel'
+ edit NPES '8'
+ edit THREADS '2'
+ edit MEM '1599'
+ edit CPUTIME '200'
+ edit EPSINISTEP '168'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit FCLENGTH '0'
+ task modeleps
+ trigger ( intHtoL eq complete)
+ edit MEM '960'
+ edit NPES '16'
+ edit CPUTIME '4000'
+ edit THREADS '2'
+ edit STACK '550'
+ edit QUEUE 'normal'
+ edit EPSNLEGS '1'
+ edit EPSLEG '3'
+ edit EPSMEMBER '50'
+ edit EPSFCRES '95'
+ edit EPSFCLEV '62'
+ edit EPSFCGTYPE 'l_2'
+ edit EPSINISTEP '0'
+ edit EPSINISTEP_PREVIOUS '168'
+ edit FCLENGTH '0'
+ edit TSTEP '2700'
+ edit EPSWAMRESOL 'global300'
+ edit EPSWAMNFRE '25'
+ edit EPSWAMNANG '12'
+ edit EPSWAMNSTPW '1'
+ meter step 0 0 0
+ endfamily
+ endfamily
+ endfamily
+ task logfiles
+ trigger cv eq complete and cf eq complete and pf eq complete
+ edit SMSCMD 'smssubmit.x %SMSJOB% %SCHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %SCHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %SCHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/hpce/rdx_dir/msx'
+ endfamily
+ family lag
+ repeat string YMD "2008021112" # status 3
+ trigger ( ( ensemble:YMD ge lag:YMD) or ( ensemble eq complete or ensemble eq unknown)) and ( ( inigroup:YMD gt lag:YMD) or ( inigroup eq complete or inigroup eq unknown))
+ complete ( lag:YMD eq ~ 1)
+ family archive
+ edit SMSTRIES '1'
+ edit MEM_ARCH '400'
+ edit CPUTIME_ARCH '10000'
+ edit PRIORITY '45'
+ edit FCLENGTH '240'
+ family cv
+ defstatus complete
+ trigger cf eq complete
+ edit ARCHTYPE 'cv'
+ family arch000
+ trigger ( ( ../../../ensemble:YMD eq ../../../lag:YMD) and ( ../../../ensemble/cv eq complete)) or ( ../../../ensemble:YMD gt ../../../lag:YMD)
+ edit EPSCHUNKS '5'
+ edit EPSARCHGRP '0'
+ family arch
+ task ml
+ event fdb
+ task pl
+ trigger ( ml eq complete or ml eq unknown)
+ event fdb
+ task sfc
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown)
+ event fdb
+ task pt
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown)
+ event fdb
+ task pv
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown) and ( pt eq complete or pt eq unknown)
+ event fdb
+ task hl
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown) and ( pt eq complete or pt eq unknown) and ( pv eq complete or pv eq unknown)
+ event fdb
+ endfamily
+ task cleanmc
+ trigger arch eq complete
+ endfamily
+ endfamily
+ family cf
+ edit ARCHTYPE 'cf'
+ family arch000
+ trigger ( ( ../../../ensemble:YMD eq ../../../lag:YMD) and ( ../../../ensemble/cf eq complete)) or ( ../../../ensemble:YMD gt ../../../lag:YMD)
+ edit EPSCHUNKS '5'
+ edit EPSARCHGRP '0'
+ family arch
+ task ml
+ event fdb
+ task pl
+ trigger ( ml eq complete or ml eq unknown)
+ event fdb
+ task sfc
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown)
+ event fdb
+ task pt
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown)
+ event fdb
+ task pv
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown) and ( pt eq complete or pt eq unknown)
+ event fdb
+ task hl
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown) and ( pt eq complete or pt eq unknown) and ( pv eq complete or pv eq unknown)
+ event fdb
+ task wm_sfc_arc
+ trigger sfc eq complete
+ complete ( ( 240 ge 768 and 1 ne 1) or ( 240 lt 768))
+ edit RUNVARFC '1'
+ task wm_ua_arc
+ trigger wm_sfc_arc eq complete
+ complete ( ( 240 ge 768 and 1 ne 1) or ( 240 lt 768))
+ edit RUNVARFC '1'
+ endfamily
+ task cleanmc
+ trigger arch eq complete
+ endfamily
+ endfamily
+ family pf
+ trigger cf eq complete and cv eq complete
+ edit ARCHTYPE 'pf'
+ family arch001
+ trigger ( ../../../ensemble:YMD gt ../../../lag:YMD or ( ../../../ensemble/pf/001 eq complete and ../../../ensemble/pf/002 eq complete and ../../../ensemble/pf/003 eq complete and ../../../ensemble/pf/004 eq complete and ../../../ensemble/pf/005 eq complete))
+ edit EPSCHUNKS '5'
+ edit EPSARCHGRP '1'
+ family arch
+ task ml
+ event fdb
+ task pl
+ trigger ( ml eq complete or ml eq unknown)
+ event fdb
+ task sfc
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown)
+ event fdb
+ task pt
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown)
+ event fdb
+ task pv
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown) and ( pt eq complete or pt eq unknown)
+ event fdb
+ task hl
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown) and ( pt eq complete or pt eq unknown) and ( pv eq complete or pv eq unknown)
+ event fdb
+ task wm_sfc_arc
+ trigger sfc eq complete
+ complete ( ( 240 ge 768 and 1 ne 1) or ( 240 lt 768))
+ edit RUNVARFC '1'
+ task wm_ua_arc
+ trigger wm_sfc_arc eq complete
+ complete ( ( 240 ge 768 and 1 ne 1) or ( 240 lt 768))
+ edit RUNVARFC '1'
+ endfamily
+ task cleanmc
+ trigger arch eq complete
+ endfamily
+ family arch002
+ trigger arch001 eq complete and ( ../../../ensemble:YMD gt ../../../lag:YMD or ( ../../../ensemble/pf/006 eq complete and ../../../ensemble/pf/007 eq complete and ../../../ensemble/pf/008 eq complete and ../../../ensemble/pf/009 eq complete and ../../../ensemble/pf/010 eq complete))
+ edit EPSCHUNKS '5'
+ edit EPSARCHGRP '2'
+ family arch
+ task ml
+ event fdb
+ task pl
+ trigger ( ml eq complete or ml eq unknown)
+ event fdb
+ task sfc
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown)
+ event fdb
+ task pt
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown)
+ event fdb
+ task pv
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown) and ( pt eq complete or pt eq unknown)
+ event fdb
+ task hl
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown) and ( pt eq complete or pt eq unknown) and ( pv eq complete or pv eq unknown)
+ event fdb
+ task wm_sfc_arc
+ trigger sfc eq complete
+ complete ( ( 240 ge 768 and 1 ne 1) or ( 240 lt 768))
+ edit RUNVARFC '1'
+ task wm_ua_arc
+ trigger wm_sfc_arc eq complete
+ complete ( ( 240 ge 768 and 1 ne 1) or ( 240 lt 768))
+ edit RUNVARFC '1'
+ endfamily
+ task cleanmc
+ trigger arch eq complete
+ endfamily
+ family arch003
+ trigger arch002 eq complete and ( ../../../ensemble:YMD gt ../../../lag:YMD or ( ../../../ensemble/pf/011 eq complete and ../../../ensemble/pf/012 eq complete and ../../../ensemble/pf/013 eq complete and ../../../ensemble/pf/014 eq complete and ../../../ensemble/pf/015 eq complete))
+ edit EPSCHUNKS '5'
+ edit EPSARCHGRP '3'
+ family arch
+ task ml
+ event fdb
+ task pl
+ trigger ( ml eq complete or ml eq unknown)
+ event fdb
+ task sfc
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown)
+ event fdb
+ task pt
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown)
+ event fdb
+ task pv
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown) and ( pt eq complete or pt eq unknown)
+ event fdb
+ task hl
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown) and ( pt eq complete or pt eq unknown) and ( pv eq complete or pv eq unknown)
+ event fdb
+ task wm_sfc_arc
+ trigger sfc eq complete
+ complete ( ( 240 ge 768 and 1 ne 1) or ( 240 lt 768))
+ edit RUNVARFC '1'
+ task wm_ua_arc
+ trigger wm_sfc_arc eq complete
+ complete ( ( 240 ge 768 and 1 ne 1) or ( 240 lt 768))
+ edit RUNVARFC '1'
+ endfamily
+ task cleanmc
+ trigger arch eq complete
+ endfamily
+ family arch004
+ trigger arch003 eq complete and ( ../../../ensemble:YMD gt ../../../lag:YMD or ( ../../../ensemble/pf/016 eq complete and ../../../ensemble/pf/017 eq complete and ../../../ensemble/pf/018 eq complete and ../../../ensemble/pf/019 eq complete and ../../../ensemble/pf/020 eq complete))
+ edit EPSCHUNKS '5'
+ edit EPSARCHGRP '4'
+ family arch
+ task ml
+ event fdb
+ task pl
+ trigger ( ml eq complete or ml eq unknown)
+ event fdb
+ task sfc
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown)
+ event fdb
+ task pt
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown)
+ event fdb
+ task pv
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown) and ( pt eq complete or pt eq unknown)
+ event fdb
+ task hl
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown) and ( pt eq complete or pt eq unknown) and ( pv eq complete or pv eq unknown)
+ event fdb
+ task wm_sfc_arc
+ trigger sfc eq complete
+ complete ( ( 240 ge 768 and 1 ne 1) or ( 240 lt 768))
+ edit RUNVARFC '1'
+ task wm_ua_arc
+ trigger wm_sfc_arc eq complete
+ complete ( ( 240 ge 768 and 1 ne 1) or ( 240 lt 768))
+ edit RUNVARFC '1'
+ endfamily
+ task cleanmc
+ trigger arch eq complete
+ endfamily
+ family arch005
+ trigger arch004 eq complete and ( ../../../ensemble:YMD gt ../../../lag:YMD or ( ../../../ensemble/pf/021 eq complete and ../../../ensemble/pf/022 eq complete and ../../../ensemble/pf/023 eq complete and ../../../ensemble/pf/024 eq complete and ../../../ensemble/pf/025 eq complete))
+ edit EPSCHUNKS '5'
+ edit EPSARCHGRP '5'
+ family arch
+ task ml
+ event fdb
+ task pl
+ trigger ( ml eq complete or ml eq unknown)
+ event fdb
+ task sfc
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown)
+ event fdb
+ task pt
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown)
+ event fdb
+ task pv
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown) and ( pt eq complete or pt eq unknown)
+ event fdb
+ task hl
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown) and ( pt eq complete or pt eq unknown) and ( pv eq complete or pv eq unknown)
+ event fdb
+ task wm_sfc_arc
+ trigger sfc eq complete
+ complete ( ( 240 ge 768 and 1 ne 1) or ( 240 lt 768))
+ edit RUNVARFC '1'
+ task wm_ua_arc
+ trigger wm_sfc_arc eq complete
+ complete ( ( 240 ge 768 and 1 ne 1) or ( 240 lt 768))
+ edit RUNVARFC '1'
+ endfamily
+ task cleanmc
+ trigger arch eq complete
+ endfamily
+ family arch006
+ trigger arch005 eq complete and ( ../../../ensemble:YMD gt ../../../lag:YMD or ( ../../../ensemble/pf/026 eq complete and ../../../ensemble/pf/027 eq complete and ../../../ensemble/pf/028 eq complete and ../../../ensemble/pf/029 eq complete and ../../../ensemble/pf/030 eq complete))
+ edit EPSCHUNKS '5'
+ edit EPSARCHGRP '6'
+ family arch
+ task ml
+ event fdb
+ task pl
+ trigger ( ml eq complete or ml eq unknown)
+ event fdb
+ task sfc
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown)
+ event fdb
+ task pt
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown)
+ event fdb
+ task pv
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown) and ( pt eq complete or pt eq unknown)
+ event fdb
+ task hl
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown) and ( pt eq complete or pt eq unknown) and ( pv eq complete or pv eq unknown)
+ event fdb
+ task wm_sfc_arc
+ trigger sfc eq complete
+ complete ( ( 240 ge 768 and 1 ne 1) or ( 240 lt 768))
+ edit RUNVARFC '1'
+ task wm_ua_arc
+ trigger wm_sfc_arc eq complete
+ complete ( ( 240 ge 768 and 1 ne 1) or ( 240 lt 768))
+ edit RUNVARFC '1'
+ endfamily
+ task cleanmc
+ trigger arch eq complete
+ endfamily
+ family arch007
+ trigger arch006 eq complete and ( ../../../ensemble:YMD gt ../../../lag:YMD or ( ../../../ensemble/pf/031 eq complete and ../../../ensemble/pf/032 eq complete and ../../../ensemble/pf/033 eq complete and ../../../ensemble/pf/034 eq complete and ../../../ensemble/pf/035 eq complete))
+ edit EPSCHUNKS '5'
+ edit EPSARCHGRP '7'
+ family arch
+ task ml
+ event fdb
+ task pl
+ trigger ( ml eq complete or ml eq unknown)
+ event fdb
+ task sfc
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown)
+ event fdb
+ task pt
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown)
+ event fdb
+ task pv
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown) and ( pt eq complete or pt eq unknown)
+ event fdb
+ task hl
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown) and ( pt eq complete or pt eq unknown) and ( pv eq complete or pv eq unknown)
+ event fdb
+ task wm_sfc_arc
+ trigger sfc eq complete
+ complete ( ( 240 ge 768 and 1 ne 1) or ( 240 lt 768))
+ edit RUNVARFC '1'
+ task wm_ua_arc
+ trigger wm_sfc_arc eq complete
+ complete ( ( 240 ge 768 and 1 ne 1) or ( 240 lt 768))
+ edit RUNVARFC '1'
+ endfamily
+ task cleanmc
+ trigger arch eq complete
+ endfamily
+ family arch008
+ trigger arch007 eq complete and ( ../../../ensemble:YMD gt ../../../lag:YMD or ( ../../../ensemble/pf/036 eq complete and ../../../ensemble/pf/037 eq complete and ../../../ensemble/pf/038 eq complete and ../../../ensemble/pf/039 eq complete and ../../../ensemble/pf/040 eq complete))
+ edit EPSCHUNKS '5'
+ edit EPSARCHGRP '8'
+ family arch
+ task ml
+ event fdb
+ task pl
+ trigger ( ml eq complete or ml eq unknown)
+ event fdb
+ task sfc
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown)
+ event fdb
+ task pt
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown)
+ event fdb
+ task pv
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown) and ( pt eq complete or pt eq unknown)
+ event fdb
+ task hl
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown) and ( pt eq complete or pt eq unknown) and ( pv eq complete or pv eq unknown)
+ event fdb
+ task wm_sfc_arc
+ trigger sfc eq complete
+ complete ( ( 240 ge 768 and 1 ne 1) or ( 240 lt 768))
+ edit RUNVARFC '1'
+ task wm_ua_arc
+ trigger wm_sfc_arc eq complete
+ complete ( ( 240 ge 768 and 1 ne 1) or ( 240 lt 768))
+ edit RUNVARFC '1'
+ endfamily
+ task cleanmc
+ trigger arch eq complete
+ endfamily
+ family arch009
+ trigger arch008 eq complete and ( ../../../ensemble:YMD gt ../../../lag:YMD or ( ../../../ensemble/pf/041 eq complete and ../../../ensemble/pf/042 eq complete and ../../../ensemble/pf/043 eq complete and ../../../ensemble/pf/044 eq complete and ../../../ensemble/pf/045 eq complete))
+ edit EPSCHUNKS '5'
+ edit EPSARCHGRP '9'
+ family arch
+ task ml
+ event fdb
+ task pl
+ trigger ( ml eq complete or ml eq unknown)
+ event fdb
+ task sfc
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown)
+ event fdb
+ task pt
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown)
+ event fdb
+ task pv
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown) and ( pt eq complete or pt eq unknown)
+ event fdb
+ task hl
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown) and ( pt eq complete or pt eq unknown) and ( pv eq complete or pv eq unknown)
+ event fdb
+ task wm_sfc_arc
+ trigger sfc eq complete
+ complete ( ( 240 ge 768 and 1 ne 1) or ( 240 lt 768))
+ edit RUNVARFC '1'
+ task wm_ua_arc
+ trigger wm_sfc_arc eq complete
+ complete ( ( 240 ge 768 and 1 ne 1) or ( 240 lt 768))
+ edit RUNVARFC '1'
+ endfamily
+ task cleanmc
+ trigger arch eq complete
+ endfamily
+ family arch010
+ trigger arch009 eq complete and ( ../../../ensemble:YMD gt ../../../lag:YMD or ( ../../../ensemble/pf/046 eq complete and ../../../ensemble/pf/047 eq complete and ../../../ensemble/pf/048 eq complete and ../../../ensemble/pf/049 eq complete and ../../../ensemble/pf/050 eq complete))
+ edit EPSCHUNKS '5'
+ edit EPSARCHGRP '10'
+ family arch
+ task ml
+ event fdb
+ task pl
+ trigger ( ml eq complete or ml eq unknown)
+ event fdb
+ task sfc
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown)
+ event fdb
+ task pt
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown)
+ event fdb
+ task pv
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown) and ( pt eq complete or pt eq unknown)
+ event fdb
+ task hl
+ defstatus complete
+ trigger ( ml eq complete or ml eq unknown) and ( pl eq complete or pl eq unknown) and ( sfc eq complete or sfc eq unknown) and ( pt eq complete or pt eq unknown) and ( pv eq complete or pv eq unknown)
+ event fdb
+ task wm_sfc_arc
+ trigger sfc eq complete
+ complete ( ( 240 ge 768 and 1 ne 1) or ( 240 lt 768))
+ edit RUNVARFC '1'
+ task wm_ua_arc
+ trigger wm_sfc_arc eq complete
+ complete ( ( 240 ge 768 and 1 ne 1) or ( 240 lt 768))
+ edit RUNVARFC '1'
+ endfamily
+ task cleanmc
+ trigger arch eq complete
+ endfamily
+ endfamily
+ family icp
+ trigger ./pf eq complete
+ edit ARCHTYPE 'icp'
+ task ml
+ event fdb
+ task cleanmc
+ trigger ml eq complete
+ endfamily
+ endfamily
+ task flush
+ trigger archive/pf eq complete and archive/cf eq complete and archive/cv eq complete and archive/icp eq complete
+ edit SMSCMD 'smssubmit.x %SMSJOB% %WSHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %WSHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %WSHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/vol/msexplog/outputs'
+ edit QUEUE 'expsms'
+ family ecfs
+ task save
+ endfamily
+ family plot
+ family prob
+ edit SMSCMD 'smssubmit.x %SMSJOB% %WSHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %WSHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %WSHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/vol/msexplog/outputs'
+ edit QUEUE 'expsms'
+ task plumea
+ defstatus complete
+ task pb
+ defstatus complete
+ trigger ../../prob eq complete
+ endfamily
+ endfamily
+ family prob
+ defstatus complete
+ task rain
+ task temp
+ task wind
+ endfamily
+ task cleanvarfc
+ trigger archive eq complete and flush eq complete and ecfs eq complete and plot eq complete and prob eq complete
+ task logfiles
+ trigger cleanvarfc eq complete
+ edit SMSCMD 'smssubmit.x %SMSJOB% %SCHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %SCHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %SCHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/hpce/rdx_dir/msx'
+ endfamily
+ endfamily
+ endfamily
+ endfamily
+ task wipefdb
+ trigger ( an eq complete or an eq unknown) and ( fc eq complete or fc eq unknown) and ( eps_sv eq complete or eps_sv eq unknown) and ( eps_fc eq complete or eps_fc eq unknown) and ( eps_varfc eq complete or eps_varfc eq unknown) and ( oceatm eq complete or oceatm eq unknown) and ( oce eq complete or oce eq unknown) and ( fpos eq complete or fpos eq unknown) and ( sens eq complete or sens eq unknown) and ( wam eq complete or wam eq unknown) and ( oc eq complete or oc eq u [...]
+ edit YMD '2008021112'
+ edit HOUR ''
+ edit FSFAMILY 'cancel'
+ task cancel
+ trigger ( an eq complete or an eq unknown) and ( fc eq complete or fc eq unknown) and ( eps_sv eq complete or eps_sv eq unknown) and ( eps_fc eq complete or eps_fc eq unknown) and ( eps_varfc eq complete or eps_varfc eq unknown) and ( oceatm eq complete or oceatm eq unknown) and ( oce eq complete or oce eq unknown) and ( fpos eq complete or fpos eq unknown) and ( sens eq complete or sens eq unknown) and ( wam eq complete or wam eq unknown) and ( oc eq complete or oc eq u [...]
+ edit YMD '2008021112'
+ edit HOUR ''
+ edit FSFAMILY 'cancel'
+ edit SMSCMD 'smssubmit.x %SMSJOB% %WSHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %WSHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %WSHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/vol/msexplog/outputs'
+ edit QUEUE 'expsms'
+ endfamily
+endsuite
+#============================================================
diff --git a/CSim/test/data/good_defs/operations/xbe.def.log b/CSim/test/data/good_defs/operations/xbe.def.log
new file mode 100644
index 0000000..f0fba19
--- /dev/null
+++ b/CSim/test/data/good_defs/operations/xbe.def.log
@@ -0,0 +1,2149 @@
+LOG:[12:27:19 12.5.2016] queued: /cu9
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/setup
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/libs/p4setup_ifs
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/libs/p4diff_ifs
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/libs/compile
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/ifsaux
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/libs/compile/ifsaux/libifsaux
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/ifsaux
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/ifsaux/libifsaux
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/surf
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/libs/compile/surf/libsurf
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/surf
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/surf/libsurf
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/trans
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/libs/compile/trans/libtrans
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/trans
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/trans/libtrans
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/ifs
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/libs/compile/ifs/libifs
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/ifs
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/ifs/libifs
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/wam
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/libs/compile/wam/libwam
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/wam
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/wam/libwam
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/libs/compile/odb/compiler
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/libs/compile/odb/compiler/libodbsqlcompiler
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/libs/compile/odb/databases
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/libs/compile/odb/databases/CCMA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/libs/compile/odb/databases/CCMA/libCCMA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/libs/compile/odb/databases/ECMA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/libs/compile/odb/databases/ECMA/libECMA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/libs/compile/odb/corelibs
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/libs/compile/odb/corelibs/odb
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/libs/compile/odb/corelibs/odb/libodb
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/libs/compile/odb/corelibs/odbdummy
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/libs/compile/odb/corelibs/odbdummy/libodbdummy
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/libs/compile/odb/corelibs/odbmain
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/libs/compile/odb/corelibs/odbmain/libodbmain
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/libs/compile/odb/corelibs/odbport
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/libs/compile/odb/corelibs/odbport/libodbport
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/compiler
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/compiler/libodbsqlcompiler
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/databases
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/databases/CCMA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/databases/CCMA/libCCMA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/databases/ECMA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/databases/ECMA/libECMA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/corelibs
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/corelibs/odb
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/corelibs/odb/libodb
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/corelibs/odbdummy
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/corelibs/odbdummy/libodbdummy
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/corelibs/odbmain
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/corelibs/odbmain/libodbmain
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/corelibs/odbport
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/corelibs/odbport/libodbport
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/ssa
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/libs/compile/ssa/libssa
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/ssa
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/ssa/libssa
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/obstat
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/libs/compile/obstat/libobstat
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/obstat
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/obstat/libobstat
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/bl
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/libs/compile/bl/libbl95
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/bl
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/bl/libbl95
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/scat
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/libs/compile/scat/libscat
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/scat
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/scat/libscat
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/satrad
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/libs/compile/satrad/libsatrad
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/satrad
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/satrad/libsatrad
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/aeolus
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/libs/compile/aeolus/libaeolus
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/aeolus
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/aeolus/libaeolus
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/prepdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/libs/compile/prepdata/libprepdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/prepdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/prepdata/libprepdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/p4setup_ifs
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/p4diff_ifs
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/ifsaux
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/ifsaux/libifsaux
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/surf
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/surf/libsurf
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/trans
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/trans/libtrans
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/ifs
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/ifs/libifs
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/wam
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/wam/libwam
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/compiler
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/compiler/libodbsqlcompiler
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/databases
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/databases/CCMA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/databases/CCMA/libCCMA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/databases/ECMA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/databases/ECMA/libECMA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/corelibs
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/corelibs/odb
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/corelibs/odb/libodb
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/corelibs/odbdummy
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/corelibs/odbdummy/libodbdummy
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/corelibs/odbmain
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/corelibs/odbmain/libodbmain
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/corelibs/odbport
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/odb/corelibs/odbport/libodbport
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/ssa
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/ssa/libssa
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/obstat
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/obstat/libobstat
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/bl
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/bl/libbl95
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/scat
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/scat/libscat
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/satrad
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/satrad/libsatrad
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/aeolus
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/aeolus/libaeolus
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/prepdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/libs/compile/prepdata/libprepdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/links
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make/logfiles
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/make
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/make/setup
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/make/bins
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/make/bins/ifs
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/make/bins/wamabs
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/make/bins/mc_tools
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/make/bins/prepdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/make/bins/ma_tools
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/make/const
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/make/const/datalinks
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/make/const/wconstA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/make/const/wconstB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/make/const/wconstC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/make/const/getsst
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/make/logfiles
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/sv
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/sv/getini
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/sv/inidata_sv
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/sv/svnh
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/sv/svsh
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/sv/targets
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/sv/subspace
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/sv/sv1
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/sv/sv2
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/sv/sv3
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/sv/sv4
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/sv/sv5
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/sv/sv6
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/sv/svnhevo
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/sv/svshevo
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/sv/svsave
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/sv/logfiles
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/sv
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/sv/getini
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/sv/inidata_sv
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/sv/svnh
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/sv/svsh
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/sv/targets
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/sv/subspace
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/sv/sv1
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/sv/sv2
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/sv/sv3
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/sv/sv4
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/sv/sv5
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/sv/sv6
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/sv/svnhevo
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/sv/svshevo
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/sv/svsave
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/sv/logfiles
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/getini
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/inidata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/wavini
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/wcold
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/wavfcdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/getsvs
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/getae
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/rot
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/geticp
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/000
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/000/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/001
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/001/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/002
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/002/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/003
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/003/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/004
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/004/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/005
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/005/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/006
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/006/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/007
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/007/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/008
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/008/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/009
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/009/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/010
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/010/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/011
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/011/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/012
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/012/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/013
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/013/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/014
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/014/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/015
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/015/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/016
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/016/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/017
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/017/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/018
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/018/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/019
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/019/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/020
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/020/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/021
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/021/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/022
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/022/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/023
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/023/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/024
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/024/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/025
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/025/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/026
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/026/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/027
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/027/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/028
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/028/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/029
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/029/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/030
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/030/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/031
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/031/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/032
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/032/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/033
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/033/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/034
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/034/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/035
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/035/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/036
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/036/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/037
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/037/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/038
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/038/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/039
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/039/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/040
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/040/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/041
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/041/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/042
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/042/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/043
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/043/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/044
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/044/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/045
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/045/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/046
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/046/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/047
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/047/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/048
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/048/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/049
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/049/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/050
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/050/pertinic
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/cp_pert
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/inigroup/logfiles
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/cv
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/cv/control_1
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/cv/control_1/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/cv/control_1/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/cv/control_2
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/cv/control_2/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/cv/control_2/intHtoLB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/cv/control_2/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/cv
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/cv/control_1
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/cv/control_1/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/cv/control_1/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/cv/control_2
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/cv/control_2/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/cv/control_2/intHtoLB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/cv/control_2/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/cf
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/cf/control
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/cf/control/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/cf/control/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/cf/control/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/cf/control/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/cf/control/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/cf/control/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/cf/control/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/cf/control/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/cf/control/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/cf/control/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/cf/control/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/001
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/001/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/001/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/001/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/001/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/001/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/001/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/001/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/001/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/001/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/001/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/001/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/002
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/002/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/002/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/002/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/002/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/002/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/002/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/002/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/002/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/002/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/002/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/002/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/003
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/003/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/003/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/003/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/003/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/003/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/003/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/003/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/003/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/003/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/003/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/003/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/004
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/004/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/004/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/004/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/004/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/004/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/004/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/004/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/004/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/004/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/004/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/004/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/005
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/005/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/005/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/005/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/005/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/005/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/005/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/005/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/005/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/005/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/005/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/005/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/006
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/006/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/006/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/006/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/006/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/006/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/006/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/006/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/006/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/006/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/006/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/006/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/007
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/007/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/007/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/007/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/007/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/007/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/007/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/007/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/007/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/007/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/007/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/007/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/008
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/008/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/008/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/008/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/008/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/008/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/008/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/008/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/008/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/008/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/008/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/008/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/009
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/009/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/009/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/009/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/009/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/009/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/009/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/009/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/009/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/009/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/009/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/009/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/010
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/010/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/010/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/010/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/010/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/010/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/010/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/010/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/010/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/010/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/010/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/010/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/011
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/011/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/011/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/011/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/011/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/011/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/011/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/011/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/011/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/011/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/011/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/011/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/012
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/012/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/012/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/012/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/012/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/012/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/012/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/012/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/012/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/012/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/012/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/012/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/013
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/013/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/013/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/013/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/013/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/013/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/013/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/013/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/013/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/013/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/013/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/013/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/014
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/014/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/014/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/014/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/014/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/014/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/014/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/014/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/014/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/014/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/014/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/014/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/015
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/015/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/015/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/015/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/015/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/015/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/015/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/015/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/015/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/015/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/015/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/015/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/016
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/016/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/016/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/016/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/016/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/016/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/016/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/016/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/016/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/016/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/016/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/016/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/017
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/017/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/017/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/017/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/017/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/017/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/017/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/017/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/017/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/017/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/017/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/017/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/018
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/018/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/018/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/018/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/018/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/018/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/018/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/018/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/018/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/018/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/018/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/018/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/019
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/019/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/019/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/019/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/019/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/019/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/019/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/019/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/019/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/019/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/019/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/019/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/020
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/020/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/020/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/020/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/020/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/020/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/020/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/020/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/020/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/020/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/020/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/020/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/021
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/021/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/021/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/021/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/021/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/021/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/021/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/021/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/021/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/021/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/021/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/021/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/022
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/022/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/022/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/022/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/022/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/022/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/022/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/022/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/022/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/022/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/022/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/022/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/023
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/023/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/023/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/023/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/023/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/023/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/023/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/023/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/023/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/023/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/023/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/023/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/024
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/024/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/024/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/024/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/024/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/024/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/024/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/024/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/024/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/024/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/024/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/024/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/025
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/025/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/025/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/025/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/025/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/025/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/025/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/025/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/025/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/025/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/025/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/025/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/026
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/026/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/026/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/026/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/026/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/026/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/026/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/026/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/026/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/026/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/026/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/026/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/027
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/027/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/027/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/027/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/027/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/027/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/027/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/027/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/027/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/027/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/027/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/027/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/028
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/028/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/028/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/028/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/028/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/028/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/028/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/028/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/028/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/028/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/028/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/028/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/029
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/029/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/029/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/029/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/029/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/029/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/029/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/029/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/029/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/029/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/029/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/029/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/030
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/030/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/030/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/030/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/030/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/030/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/030/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/030/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/030/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/030/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/030/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/030/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/031
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/031/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/031/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/031/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/031/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/031/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/031/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/031/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/031/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/031/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/031/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/031/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/032
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/032/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/032/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/032/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/032/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/032/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/032/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/032/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/032/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/032/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/032/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/032/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/033
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/033/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/033/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/033/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/033/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/033/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/033/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/033/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/033/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/033/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/033/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/033/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/034
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/034/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/034/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/034/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/034/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/034/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/034/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/034/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/034/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/034/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/034/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/034/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/035
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/035/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/035/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/035/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/035/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/035/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/035/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/035/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/035/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/035/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/035/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/035/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/036
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/036/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/036/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/036/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/036/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/036/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/036/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/036/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/036/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/036/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/036/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/036/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/037
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/037/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/037/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/037/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/037/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/037/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/037/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/037/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/037/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/037/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/037/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/037/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/038
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/038/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/038/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/038/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/038/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/038/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/038/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/038/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/038/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/038/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/038/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/038/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/039
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/039/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/039/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/039/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/039/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/039/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/039/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/039/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/039/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/039/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/039/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/039/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/040
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/040/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/040/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/040/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/040/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/040/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/040/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/040/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/040/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/040/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/040/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/040/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/041
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/041/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/041/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/041/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/041/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/041/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/041/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/041/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/041/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/041/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/041/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/041/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/042
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/042/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/042/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/042/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/042/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/042/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/042/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/042/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/042/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/042/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/042/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/042/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/043
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/043/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/043/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/043/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/043/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/043/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/043/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/043/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/043/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/043/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/043/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/043/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/044
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/044/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/044/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/044/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/044/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/044/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/044/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/044/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/044/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/044/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/044/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/044/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/045
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/045/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/045/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/045/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/045/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/045/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/045/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/045/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/045/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/045/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/045/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/045/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/046
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/046/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/046/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/046/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/046/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/046/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/046/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/046/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/046/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/046/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/046/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/046/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/047
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/047/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/047/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/047/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/047/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/047/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/047/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/047/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/047/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/047/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/047/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/047/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/048
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/048/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/048/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/048/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/048/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/048/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/048/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/048/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/048/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/048/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/048/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/048/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/049
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/049/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/049/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/049/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/049/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/049/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/049/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/049/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/049/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/049/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/049/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/049/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/050
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/050/legA
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/050/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/050/legA/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/050/legB
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/050/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/050/legB/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/050/legB/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/050/legC
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/050/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/050/legC/intHtoL
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/050/legC/modeleps
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/ensemble/logfiles
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cv
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/cv/arch000
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/cv/arch000/arch
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/cv/arch000/arch/ml
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/cv/arch000/arch/pl
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/cv/arch000/arch/sfc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cv/arch000/arch/pt
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cv/arch000/arch/pv
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cv/arch000/arch/hl
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/cv/arch000/cleanmc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cv
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cv/arch000
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cv/arch000/arch
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cv/arch000/arch/ml
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cv/arch000/arch/pl
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cv/arch000/arch/sfc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cv/arch000/arch/pt
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cv/arch000/arch/pv
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cv/arch000/arch/hl
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cv/arch000/cleanmc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/cf
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/cf/arch000
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/cf/arch000/arch
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/cf/arch000/arch/ml
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/cf/arch000/arch/pl
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/cf/arch000/arch/sfc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cf/arch000/arch/pt
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cf/arch000/arch/pv
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cf/arch000/arch/hl
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/cf/arch000/arch/wm_sfc_arc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/cf/arch000/arch/wm_ua_arc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/cf/arch000/cleanmc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch001
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch001/arch
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch001/arch/ml
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch001/arch/pl
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch001/arch/sfc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch001/arch/pt
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch001/arch/pv
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch001/arch/hl
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch001/arch/wm_sfc_arc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch001/arch/wm_ua_arc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch001/cleanmc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch002
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch002/arch
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch002/arch/ml
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch002/arch/pl
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch002/arch/sfc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch002/arch/pt
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch002/arch/pv
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch002/arch/hl
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch002/arch/wm_sfc_arc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch002/arch/wm_ua_arc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch002/cleanmc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch003
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch003/arch
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch003/arch/ml
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch003/arch/pl
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch003/arch/sfc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch003/arch/pt
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch003/arch/pv
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch003/arch/hl
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch003/arch/wm_sfc_arc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch003/arch/wm_ua_arc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch003/cleanmc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch004
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch004/arch
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch004/arch/ml
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch004/arch/pl
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch004/arch/sfc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch004/arch/pt
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch004/arch/pv
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch004/arch/hl
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch004/arch/wm_sfc_arc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch004/arch/wm_ua_arc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch004/cleanmc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch005
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch005/arch
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch005/arch/ml
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch005/arch/pl
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch005/arch/sfc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch005/arch/pt
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch005/arch/pv
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch005/arch/hl
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch005/arch/wm_sfc_arc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch005/arch/wm_ua_arc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch005/cleanmc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch006
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch006/arch
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch006/arch/ml
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch006/arch/pl
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch006/arch/sfc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch006/arch/pt
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch006/arch/pv
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch006/arch/hl
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch006/arch/wm_sfc_arc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch006/arch/wm_ua_arc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch006/cleanmc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch007
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch007/arch
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch007/arch/ml
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch007/arch/pl
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch007/arch/sfc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch007/arch/pt
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch007/arch/pv
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch007/arch/hl
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch007/arch/wm_sfc_arc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch007/arch/wm_ua_arc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch007/cleanmc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch008
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch008/arch
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch008/arch/ml
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch008/arch/pl
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch008/arch/sfc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch008/arch/pt
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch008/arch/pv
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch008/arch/hl
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch008/arch/wm_sfc_arc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch008/arch/wm_ua_arc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch008/cleanmc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch009
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch009/arch
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch009/arch/ml
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch009/arch/pl
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch009/arch/sfc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch009/arch/pt
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch009/arch/pv
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch009/arch/hl
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch009/arch/wm_sfc_arc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch009/arch/wm_ua_arc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch009/cleanmc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch010
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch010/arch
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch010/arch/ml
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch010/arch/pl
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch010/arch/sfc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch010/arch/pt
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch010/arch/pv
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch010/arch/hl
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch010/arch/wm_sfc_arc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch010/arch/wm_ua_arc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch010/cleanmc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/icp
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/icp/ml
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/archive/icp/cleanmc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/flush
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/ecfs
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/ecfs/save
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/plot
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/plot/prob
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/plot/prob/plumea
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/plot/prob/pb
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/plot/prob
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/plot
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/prob
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/prob/rain
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/prob/temp
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/prob/wind
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/prob
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/prob/rain
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/prob/temp
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/prob/wind
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/cleanvarfc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/main/fc/lag/logfiles
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/wipefdb
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/cancel
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d/make/setup
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d/make
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d
+LOG:[12:27:19 12.5.2016] submitted: /cu9
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d/make/setup
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d/make
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d
+LOG:[12:27:19 12.5.2016] active: /cu9
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/getini
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/inidata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/wavini
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/wcold
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/wavfcdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/getsvs
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/getae
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/rot
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/geticp
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/000
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/000/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/001
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/001/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/002
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/002/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/003
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/003/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/004
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/004/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/005
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/005/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/006
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/006/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/007
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/007/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/008
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/008/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/009
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/009/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/010
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/010/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/011
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/011/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/012
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/012/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/013
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/013/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/014
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/014/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/015
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/015/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/016
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/016/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/017
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/017/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/018
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/018/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/019
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/019/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/020
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/020/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/021
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/021/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/022
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/022/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/023
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/023/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/024
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/024/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/025
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/025/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/026
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/026/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/027
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/027/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/028
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/028/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/029
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/029/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/030
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/030/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/031
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/031/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/032
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/032/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/033
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/033/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/034
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/034/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/035
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/035/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/036
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/036/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/037
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/037/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/038
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/038/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/039
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/039/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/040
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/040/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/041
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/041/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/042
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/042/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/043
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/043/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/044
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/044/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/045
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/045/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/046
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/046/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/047
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/047/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/048
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/048/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/049
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/049/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/050
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/pert_ic/050/pertinic
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/cp_pert
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/inigroup/logfiles
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/cv
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/cv/control_1
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/cv/control_1/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/cv/control_1/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/cv/control_2
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/cv/control_2/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/cv/control_2/intHtoLB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/cv/control_2/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/cf
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/cf/control
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/cf/control/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/cf/control/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/cf/control/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/cf/control/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/cf/control/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/cf/control/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/cf/control/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/cf/control/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/cf/control/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/cf/control/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/cf/control/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/001
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/001/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/001/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/001/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/001/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/001/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/001/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/001/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/001/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/001/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/001/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/001/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/002
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/002/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/002/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/002/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/002/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/002/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/002/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/002/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/002/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/002/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/002/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/002/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/003
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/003/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/003/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/003/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/003/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/003/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/003/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/003/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/003/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/003/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/003/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/003/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/004
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/004/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/004/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/004/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/004/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/004/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/004/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/004/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/004/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/004/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/004/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/004/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/005
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/005/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/005/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/005/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/005/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/005/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/005/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/005/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/005/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/005/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/005/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/005/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/006
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/006/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/006/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/006/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/006/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/006/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/006/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/006/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/006/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/006/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/006/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/006/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/007
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/007/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/007/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/007/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/007/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/007/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/007/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/007/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/007/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/007/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/007/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/007/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/008
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/008/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/008/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/008/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/008/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/008/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/008/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/008/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/008/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/008/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/008/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/008/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/009
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/009/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/009/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/009/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/009/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/009/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/009/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/009/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/009/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/009/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/009/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/009/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/010
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/010/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/010/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/010/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/010/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/010/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/010/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/010/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/010/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/010/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/010/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/010/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/011
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/011/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/011/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/011/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/011/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/011/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/011/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/011/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/011/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/011/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/011/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/011/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/012
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/012/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/012/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/012/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/012/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/012/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/012/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/012/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/012/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/012/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/012/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/012/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/013
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/013/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/013/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/013/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/013/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/013/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/013/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/013/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/013/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/013/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/013/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/013/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/014
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/014/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/014/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/014/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/014/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/014/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/014/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/014/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/014/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/014/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/014/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/014/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/015
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/015/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/015/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/015/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/015/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/015/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/015/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/015/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/015/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/015/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/015/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/015/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/016
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/016/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/016/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/016/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/016/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/016/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/016/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/016/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/016/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/016/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/016/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/016/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/017
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/017/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/017/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/017/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/017/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/017/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/017/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/017/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/017/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/017/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/017/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/017/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/018
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/018/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/018/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/018/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/018/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/018/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/018/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/018/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/018/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/018/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/018/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/018/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/019
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/019/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/019/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/019/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/019/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/019/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/019/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/019/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/019/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/019/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/019/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/019/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/020
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/020/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/020/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/020/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/020/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/020/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/020/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/020/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/020/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/020/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/020/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/020/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/021
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/021/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/021/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/021/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/021/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/021/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/021/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/021/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/021/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/021/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/021/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/021/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/022
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/022/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/022/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/022/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/022/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/022/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/022/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/022/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/022/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/022/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/022/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/022/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/023
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/023/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/023/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/023/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/023/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/023/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/023/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/023/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/023/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/023/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/023/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/023/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/024
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/024/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/024/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/024/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/024/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/024/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/024/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/024/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/024/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/024/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/024/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/024/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/025
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/025/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/025/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/025/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/025/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/025/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/025/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/025/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/025/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/025/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/025/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/025/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/026
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/026/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/026/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/026/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/026/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/026/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/026/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/026/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/026/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/026/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/026/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/026/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/027
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/027/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/027/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/027/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/027/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/027/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/027/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/027/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/027/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/027/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/027/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/027/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/028
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/028/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/028/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/028/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/028/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/028/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/028/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/028/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/028/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/028/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/028/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/028/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/029
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/029/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/029/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/029/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/029/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/029/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/029/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/029/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/029/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/029/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/029/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/029/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/030
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/030/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/030/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/030/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/030/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/030/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/030/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/030/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/030/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/030/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/030/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/030/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/031
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/031/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/031/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/031/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/031/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/031/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/031/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/031/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/031/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/031/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/031/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/031/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/032
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/032/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/032/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/032/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/032/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/032/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/032/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/032/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/032/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/032/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/032/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/032/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/033
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/033/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/033/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/033/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/033/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/033/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/033/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/033/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/033/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/033/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/033/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/033/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/034
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/034/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/034/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/034/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/034/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/034/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/034/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/034/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/034/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/034/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/034/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/034/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/035
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/035/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/035/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/035/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/035/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/035/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/035/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/035/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/035/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/035/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/035/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/035/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/036
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/036/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/036/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/036/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/036/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/036/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/036/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/036/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/036/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/036/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/036/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/036/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/037
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/037/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/037/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/037/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/037/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/037/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/037/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/037/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/037/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/037/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/037/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/037/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/038
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/038/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/038/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/038/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/038/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/038/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/038/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/038/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/038/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/038/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/038/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/038/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/039
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/039/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/039/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/039/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/039/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/039/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/039/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/039/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/039/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/039/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/039/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/039/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/040
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/040/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/040/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/040/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/040/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/040/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/040/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/040/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/040/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/040/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/040/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/040/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/041
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/041/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/041/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/041/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/041/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/041/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/041/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/041/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/041/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/041/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/041/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/041/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/042
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/042/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/042/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/042/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/042/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/042/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/042/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/042/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/042/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/042/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/042/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/042/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/043
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/043/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/043/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/043/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/043/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/043/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/043/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/043/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/043/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/043/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/043/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/043/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/044
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/044/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/044/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/044/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/044/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/044/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/044/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/044/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/044/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/044/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/044/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/044/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/045
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/045/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/045/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/045/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/045/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/045/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/045/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/045/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/045/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/045/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/045/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/045/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/046
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/046/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/046/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/046/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/046/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/046/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/046/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/046/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/046/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/046/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/046/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/046/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/047
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/047/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/047/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/047/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/047/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/047/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/047/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/047/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/047/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/047/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/047/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/047/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/048
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/048/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/048/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/048/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/048/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/048/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/048/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/048/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/048/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/048/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/048/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/048/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/049
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/049/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/049/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/049/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/049/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/049/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/049/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/049/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/049/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/049/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/049/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/049/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/050
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/050/legA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/050/legA/getiniLeg
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/050/legA/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/050/legB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/050/legB/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/050/legB/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/050/legB/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/050/legC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/050/legC/getvarepsdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/050/legC/intHtoL
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/pf/050/legC/modeleps
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/ensemble/logfiles
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cv
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cv/arch000
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cv/arch000/arch
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cv/arch000/arch/ml
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cv/arch000/arch/pl
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cv/arch000/arch/sfc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cv/arch000/arch/pt
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cv/arch000/arch/pv
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cv/arch000/arch/hl
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cv/arch000/cleanmc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cf
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cf/arch000
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cf/arch000/arch
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cf/arch000/arch/ml
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cf/arch000/arch/pl
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cf/arch000/arch/sfc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cf/arch000/arch/pt
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cf/arch000/arch/pv
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cf/arch000/arch/hl
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cf/arch000/arch/wm_sfc_arc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cf/arch000/arch/wm_ua_arc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/cf/arch000/cleanmc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch001
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch001/arch
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch001/arch/ml
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch001/arch/pl
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch001/arch/sfc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch001/arch/pt
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch001/arch/pv
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch001/arch/hl
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch001/arch/wm_sfc_arc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch001/arch/wm_ua_arc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch001/cleanmc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch002
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch002/arch
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch002/arch/ml
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch002/arch/pl
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch002/arch/sfc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch002/arch/pt
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch002/arch/pv
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch002/arch/hl
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch002/arch/wm_sfc_arc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch002/arch/wm_ua_arc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch002/cleanmc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch003
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch003/arch
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch003/arch/ml
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch003/arch/pl
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch003/arch/sfc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch003/arch/pt
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch003/arch/pv
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch003/arch/hl
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch003/arch/wm_sfc_arc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch003/arch/wm_ua_arc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch003/cleanmc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch004
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch004/arch
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch004/arch/ml
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch004/arch/pl
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch004/arch/sfc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch004/arch/pt
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch004/arch/pv
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch004/arch/hl
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch004/arch/wm_sfc_arc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch004/arch/wm_ua_arc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch004/cleanmc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch005
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch005/arch
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch005/arch/ml
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch005/arch/pl
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch005/arch/sfc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch005/arch/pt
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch005/arch/pv
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch005/arch/hl
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch005/arch/wm_sfc_arc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch005/arch/wm_ua_arc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch005/cleanmc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch006
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch006/arch
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch006/arch/ml
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch006/arch/pl
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch006/arch/sfc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch006/arch/pt
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch006/arch/pv
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch006/arch/hl
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch006/arch/wm_sfc_arc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch006/arch/wm_ua_arc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch006/cleanmc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch007
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch007/arch
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch007/arch/ml
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch007/arch/pl
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch007/arch/sfc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch007/arch/pt
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch007/arch/pv
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch007/arch/hl
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch007/arch/wm_sfc_arc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch007/arch/wm_ua_arc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch007/cleanmc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch008
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch008/arch
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch008/arch/ml
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch008/arch/pl
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch008/arch/sfc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch008/arch/pt
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch008/arch/pv
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch008/arch/hl
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch008/arch/wm_sfc_arc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch008/arch/wm_ua_arc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch008/cleanmc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch009
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch009/arch
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch009/arch/ml
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch009/arch/pl
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch009/arch/sfc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch009/arch/pt
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch009/arch/pv
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch009/arch/hl
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch009/arch/wm_sfc_arc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch009/arch/wm_ua_arc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch009/cleanmc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch010
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch010/arch
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch010/arch/ml
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch010/arch/pl
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch010/arch/sfc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch010/arch/pt
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch010/arch/pv
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch010/arch/hl
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch010/arch/wm_sfc_arc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch010/arch/wm_ua_arc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/pf/arch010/cleanmc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/icp
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/icp/ml
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/archive/icp/cleanmc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/flush
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/ecfs
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/ecfs/save
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/plot
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/plot/prob
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/plot/prob/plumea
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/plot/prob/pb
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/prob
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/prob/rain
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/prob/temp
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/prob/wind
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/cleanvarfc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc/lag/logfiles
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main/fc
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/main
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/setup
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d
+LOG:[12:27:19 12.5.2016] queued: /cu9
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d/make/links
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d/make
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d
+LOG:[12:27:19 12.5.2016] submitted: /cu9
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d/make/links
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d/make
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d
+LOG:[12:27:19 12.5.2016] active: /cu9
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/links
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/make
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d
+LOG:[12:27:19 12.5.2016] queued: /cu9
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d/make/logfiles
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d/make
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d
+LOG:[12:27:19 12.5.2016] submitted: /cu9
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d/make/logfiles
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d/make
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d
+LOG:[12:27:19 12.5.2016] active: /cu9
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make/logfiles
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/make
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d
+LOG:[12:27:19 12.5.2016] queued: /cu9
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d/eps_varfc/make/setup
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d/eps_varfc/make
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d/eps_varfc
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d
+LOG:[12:27:19 12.5.2016] submitted: /cu9
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d/eps_varfc/make/setup
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d/eps_varfc/make
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d/eps_varfc
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d
+LOG:[12:27:19 12.5.2016] active: /cu9
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/make/setup
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/make
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d
+LOG:[12:27:19 12.5.2016] queued: /cu9
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d/eps_varfc/make/bins/ifs
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d/eps_varfc/make/bins
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d/eps_varfc/make
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d/eps_varfc
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d
+LOG:[12:27:19 12.5.2016] submitted: /cu9
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d/eps_varfc/make/bins/ifs
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d/eps_varfc/make/bins
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d/eps_varfc/make
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d/eps_varfc
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d
+LOG:[12:27:19 12.5.2016] active: /cu9
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d/eps_varfc/make/bins/wamabs
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d/eps_varfc/make/bins/wamabs
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d/eps_varfc/make/bins/mc_tools
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d/eps_varfc/make/bins/mc_tools
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d/eps_varfc/make/bins/prepdata
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d/eps_varfc/make/bins/prepdata
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d/eps_varfc/make/const/datalinks
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d/eps_varfc/make/const
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d/eps_varfc/make/const/datalinks
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d/eps_varfc/make/const
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/make/bins/ifs
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/make/bins/wamabs
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d/eps_varfc/make/const/wconstA
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d/eps_varfc/make/const/wconstA
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/make/const/wconstA
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d/eps_varfc/make/const/wconstB
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d/eps_varfc/make/const/wconstB
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/make/const/wconstB
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d/eps_varfc/make/const/wconstC
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d/eps_varfc/make/const/wconstC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/make/const/wconstC
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/make/bins/mc_tools
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/make/bins/prepdata
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/make/bins
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/make/const/datalinks
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/make/const
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc/make
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d/eps_varfc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d
+LOG:[12:27:19 12.5.2016] queued: /cu9
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d/eps_varfc/make/logfiles
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d/eps_varfc/make
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d/eps_varfc
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d
+LOG:[12:27:19 12.5.2016] submitted: /cu9
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d/eps_varfc/make/logfiles
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d/eps_varfc/make
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d/eps_varfc
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d
+LOG:[12:27:19 12.5.2016] active: /cu9
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/make/logfiles
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc/make
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/eps_varfc
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d
+LOG:[12:27:19 12.5.2016] queued: /cu9
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d/wipefdb
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d
+LOG:[12:27:19 12.5.2016] submitted: /cu9
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d/wipefdb
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d
+LOG:[12:27:19 12.5.2016] active: /cu9
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/wipefdb
+LOG:[12:27:19 12.5.2016] queued: /cu9/a01d
+LOG:[12:27:19 12.5.2016] queued: /cu9
+LOG:[12:27:19 12.5.2016] queued: /
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d/cancel
+LOG:[12:27:19 12.5.2016] submitted: /cu9/a01d
+LOG:[12:27:19 12.5.2016] submitted: /cu9
+LOG:[12:27:19 12.5.2016] submitted: /
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d/cancel
+LOG:[12:27:19 12.5.2016] active: /cu9/a01d
+LOG:[12:27:19 12.5.2016] active: /cu9
+LOG:[12:27:19 12.5.2016] active: /
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d/cancel
+LOG:[12:27:19 12.5.2016] complete: /cu9/a01d
+LOG:[12:27:19 12.5.2016] complete: /cu9
+LOG:[12:27:19 12.5.2016] complete: /
+MSG:[12:27:19 12.5.2016] Simulation complete in 00:00:00
diff --git a/CSim/test/data/good_defs/operations/xde.def.glog b/CSim/test/data/good_defs/operations/xde.def.glog
new file mode 100644
index 0000000..ce4bd3a
--- /dev/null
+++ b/CSim/test/data/good_defs/operations/xde.def.glog
@@ -0,0 +1,4 @@
+DBG:[14:20:32 3.11.2009] state change /dfo unknown --> queued duration_(00:00:00) initTime_(2009-Nov-03 14:20:32) suiteTime_(2009-Nov-03 14:20:32)
+DBG:[14:20:32 3.11.2009] state change /dfo queued --> complete duration_(00:00:00) initTime_(2009-Nov-03 14:20:32) suiteTime_(2009-Nov-03 14:20:32)
+DBG:[14:20:32 3.11.2009] state change /dfi unknown --> queued duration_(00:00:00) initTime_(2009-Nov-03 14:20:32) suiteTime_(2009-Nov-03 14:20:32)
+DBG:[14:20:32 3.11.2009] state change /dfi queued --> complete duration_(00:00:00) initTime_(2009-Nov-03 14:20:32) suiteTime_(2009-Nov-03 14:20:32)
diff --git a/CSim/test/data/good_defs/operations/xfi.def b/CSim/test/data/good_defs/operations/xfi.def
new file mode 100644
index 0000000..5fb4645
--- /dev/null
+++ b/CSim/test/data/good_defs/operations/xfi.def
@@ -0,0 +1,265 @@
+#============================================================
+suite trunk_test
+ clock hybrid 0 # 18.03.2008 16:54
+ edit USER 'fim'
+ edit SMSINCLUDE '/scratch/ms/fi/fim/hm_home/trunk_test/lib/sms'
+ edit SMSFILES '/scratch/ms/fi/fim/hm_home/trunk_test/lib/sms'
+ edit EXP 'trunk_test'
+ edit ARGS ''
+ edit ENVT ''
+ edit YMD ''
+ edit HH '0'
+ edit Env_system '/home/ms/fi/fim/hm_home/trunk_test/Env_system'
+ edit TARGETNODE '%SMSHOST%'
+ edit HM_REV '/home/ms/dk/nhz/harmonie_release/trunk'
+ edit R_HOST ''
+ edit SRC_DIR ''
+ edit ENSMBR '-1'
+ edit SMSTRIES '1'
+ edit SMSJOBOUT '/hpce/ms_dir/ms/fi/fim/HARMONIE%SMSNAME%.%SMSTRYNO%'
+ edit SMSCMD 'perl -S Submit.pl -o %SMSJOBOUT% %SMSJOB% >> mSMS.log 2>&1'
+ edit SKIPifDONE '0'
+ task InitRun
+ family Build
+ trigger ( InitRun eq complete)
+ task Build_pack
+ family Utilities
+ task Make_gl
+ task Make_monitor
+ task Make_oulan
+ task Make_gl_ecgate
+ endfamily
+ task Archive_log
+ endfamily
+endsuite
+suite test_def
+ clock hybrid 0 # 09.10.2009 16:54
+ edit USER 'sniemela'
+ edit SMSINCLUDE '/usr/people/sms/usr_def/hirlam/test_def/scripts'
+ edit SMSFILES '/usr/people/sms/usr_def/hirlam/test_def/scripts'
+ edit EXP 'test_def'
+ edit ARGS ''
+ edit ENVT ''
+ edit YMD ''
+ edit HH '0'
+ edit Env_system '/home/users/sniemela/Harmonie/hm_home/test_def/Env_system'
+ edit TARGETNODE '%SMSHOST%'
+ edit HM_REV '/operative/hirlam/home/Harmonie/33h1'
+ edit R_HOST ''
+ edit SRC_DIR ''
+ edit PP ''
+ edit ENSMBR '-1'
+ edit SMSTRIES '1'
+ edit HM_WD '/home/users/sniemela/Harmonie/hm_home/test_def'
+ edit DTGBEG '2008090100'
+ edit DTGEND '2008090100'
+ edit _mSMS_DocURL ''
+ edit SMSJOBOUT '/home/sms/tmp/%SMSNAME%.%SMSTRYNO%'
+ edit SMSCMD 'ssh %SMSHOST% -l %USER% ". /etc/profile;bsub "< %SMSJOB% 1>%SMSJOBOUT% 2>&1 &'
+ edit SKIPifDONE '0'
+ edit KONE_VALINTA 'jumbo'
+ task Ping_HPC
+ edit SMSHOST 'sms.fmi.fi'
+ edit SMSCMD 'sh< %SMSJOB% 1>%SMSJOBOUT% 2>&1 &'
+ label HOST ""
+ task Prepare_SMS
+ trigger ( Ping_HPC eq complete)
+ edit SMSHOST 'sms.fmi.fi'
+ edit SMSCMD 'sh< %SMSJOB% 1>%SMSJOBOUT% 2>&1 &'
+ task InitRun
+ trigger ( Ping_HPC eq complete) and ( Prepare_SMS eq complete)
+ family Build
+ trigger ( InitRun eq complete)
+ task Build_pack
+ family Utilities
+ task Make_gl
+ task Make_monitor
+ task Make_oulan
+ endfamily
+ task Archive_log
+ trigger ( Build_pack eq complete and Utilities eq complete)
+ endfamily
+ family MARS
+ trigger ( InitRun eq complete)
+ task Empty
+ endfamily
+ family MakeCycleInput
+ repeat date YMD 20080901 20080901 1 # status 0
+ trigger ( Build eq complete and ( MakeCycleInput:YMD lt ( Postprocessing:YMD + 3)))
+ family Hour
+ repeat integer HH 0 23 24 # status 0
+ trigger ( ../InitRun eq complete)
+ complete ( ( ( ../MakeCycleInput:YMD le 20080901) and ( Hour:HH lt 00)) or ( ( ../MakeCycleInput:YMD ge 20080901) and ( Hour:HH)))
+ task Prepare_cycle
+ family Climate
+ trigger ( Prepare_cycle eq complete)
+ task Empty
+ endfamily
+ family Boundaries
+ trigger ( Climate eq complete)
+ task Boundary_strategy
+ family LBC0
+ task hir2aro
+ trigger ( ../Boundary_strategy eq complete)
+ endfamily
+ family LBC1
+ task hir2aro
+ trigger ( ../Boundary_strategy eq complete)
+ endfamily
+ family LBC2
+ task hir2aro
+ trigger ( ../Boundary_strategy eq complete)
+ endfamily
+ family LBC3
+ task hir2aro
+ trigger ( ../Boundary_strategy eq complete)
+ endfamily
+ family LBC4
+ task hir2aro
+ trigger ( ../Boundary_strategy eq complete)
+ endfamily
+ family LBC5
+ task hir2aro
+ trigger ( ../Boundary_strategy eq complete)
+ endfamily
+ family LBC6
+ task hir2aro
+ trigger ( ../Boundary_strategy eq complete)
+ endfamily
+ endfamily
+ family Observations
+ trigger ( Climate eq complete and ../../MARS eq complete)
+ task Empty
+ endfamily
+ task Archive_log
+ trigger ( Boundaries eq complete and Observations eq complete)
+ endfamily
+ endfamily
+ family Date
+ repeat date YMD 20080901 20080901 1 # status 0
+ trigger ( Build eq complete)
+ family Hour
+ repeat integer HH 0 23 24 # status 0
+ complete ( ( ( ../Date:YMD le 20080901) and ( Hour:HH lt 00)) or ( ( ../Date:YMD ge 20080901) and ( Hour:HH gt 00)))
+ family Cycle
+ trigger ( ( ../../MakeCycleInput eq complete) or ( ../../MakeCycleInput:YMD gt ../../Date:YMD) or ( ( ../../MakeCycleInput:YMD eq ../../Date:YMD) and ( ../../MakeCycleInput/Hour:HH gt ../Hour:HH)) or ( ( ../../MakeCycleInput:YMD eq ../../Date:YMD) and ( ../../MakeCycleInput/Hour:HH eq ../Hour:HH)))
+ family StartData
+ trigger ( ( ../../../MakeCycleInput eq complete) or ( ../../../MakeCycleInput:YMD gt ../../../Date:YMD) or ( ( ../../../MakeCycleInput:YMD eq ../../../Date:YMD) and ( ../../../MakeCycleInput/Hour:HH gt ../../Hour:HH)) or ( ( ../../../MakeCycleInput:YMD eq ../../../Date:YMD) and ( ../../../MakeCycleInput/Hour:HH eq ../../Hour:HH) and ( ../../../MakeCycleInput/Hour/Boundaries/LBC0 eq complete)))
+ task Prep_ini_surfex
+ task FirstGuess
+ endfamily
+ family Analysis
+ trigger ( StartData eq complete and ( ( ../../../MakeCycleInput eq complete) or ( ../../../MakeCycleInput:YMD gt ../../../Date:YMD) or ( ( ../../../MakeCycleInput:YMD eq ../../../Date:YMD) and ( ../../../MakeCycleInput/Hour:HH gt ../../Hour:HH)) or ( ( ../../../MakeCycleInput:YMD eq ../../../Date:YMD) and ( ../../../MakeCycleInput/Hour:HH eq ../../Hour:HH) and ( ../../../MakeCycleInput/Hour/Observations eq complete))))
+ family AnSFC
+ task Empty
+ endfamily
+ family AnUA
+ task Empty
+ endfamily
+ endfamily
+ family Forecasting
+ trigger ( ( StartData eq complete and Analysis eq complete) and ( ( ../../../MakeCycleInput eq complete) or ( ../../../MakeCycleInput:YMD gt ../../../Date:YMD) or ( ( ../../../MakeCycleInput:YMD eq ../../../Date:YMD) and ( ../../../MakeCycleInput/Hour:HH gt ../../Hour:HH)) or ( ( ../../../MakeCycleInput:YMD eq ../../../Date:YMD) and ( ../../../MakeCycleInput/Hour:HH eq ../../Hour:HH) and ( ../../../MakeCycleInput/Hour/Boundaries eq complete))))
+ task Forecast
+ task Archive_fc
+ trigger ( Forecast eq complete)
+ endfamily
+ endfamily
+ task Archive_log
+ trigger ( Cycle eq complete)
+ task LogProgress
+ trigger ( Cycle eq complete)
+ endfamily
+ endfamily
+ family Postprocessing
+ repeat date YMD 20080901 20080901 1 # status 0
+ trigger ( Build eq complete)
+ family Hour
+ repeat integer HH 0 23 24 # status 0
+ trigger ( ( ../Date eq complete) or ( ../Date:YMD gt ../Postprocessing:YMD) or ( ( ../Date:YMD eq ../Postprocessing:YMD) and ( ../Date/Hour:HH gt Hour:HH)))
+ complete ( ( ( ../Postprocessing:YMD le 20080901) and ( Hour:HH lt 00)) or ( ( ../Postprocessing:YMD ge 20080901) and ( Hour:HH gt 00)))
+ family Extract4ver
+ family fldextr0
+ task Run_fldver
+ endfamily
+ family fldextr1
+ task Run_fldver
+ endfamily
+ family fldextr2
+ task Run_fldver
+ endfamily
+ family fldextr3
+ task Run_fldver
+ endfamily
+ family fldextr4
+ task Run_fldver
+ endfamily
+ family fldextr5
+ task Run_fldver
+ endfamily
+ family fldextr6
+ task Run_fldver
+ endfamily
+ endfamily
+ task Gather_extract
+ trigger ( Extract4ver eq complete)
+ family Postp_family
+ family Postp0
+ task Postpp
+ endfamily
+ family Postp1
+ task Postpp
+ endfamily
+ family Postp2
+ task Postpp
+ endfamily
+ family Postp3
+ task Postpp
+ endfamily
+ family Postp4
+ task Postpp
+ endfamily
+ family Postp5
+ task Postpp
+ endfamily
+ family Postp6
+ task Postpp
+ endfamily
+ endfamily
+ family Grib_family
+ trigger ( Postp_family eq complete)
+ family Grib0
+ task Makegrib
+ endfamily
+ family Grib1
+ task Makegrib
+ endfamily
+ family Grib2
+ task Makegrib
+ endfamily
+ family Grib3
+ task Makegrib
+ endfamily
+ family Grib4
+ task Makegrib
+ endfamily
+ family Grib5
+ task Makegrib
+ endfamily
+ family Grib6
+ task Makegrib
+ endfamily
+ endfamily
+ task Cleancycle
+ trigger ( Postp_family eq complete and Gather_extract eq complete and Grib_family eq complete)
+ family ECMWF
+ task Empty
+ endfamily
+ task Archive_log
+ trigger ( ECMWF eq complete and Cleancycle eq complete)
+ task LogProgress
+ trigger ( ECMWF eq complete and Cleancycle eq complete)
+ edit PP 'PP'
+ endfamily
+ endfamily
+endsuite
+#============================================================
diff --git a/CSim/test/data/good_defs/operations/xfi.def.log b/CSim/test/data/good_defs/operations/xfi.def.log
new file mode 100644
index 0000000..fc20b7c
--- /dev/null
+++ b/CSim/test/data/good_defs/operations/xfi.def.log
@@ -0,0 +1,609 @@
+LOG:[12:27:18 12.5.2016] queued: /trunk_test
+LOG:[12:27:18 12.5.2016] queued: /trunk_test/InitRun
+LOG:[12:27:18 12.5.2016] queued: /trunk_test/Build
+LOG:[12:27:18 12.5.2016] queued: /trunk_test/Build/Build_pack
+LOG:[12:27:18 12.5.2016] queued: /trunk_test/Build/Utilities
+LOG:[12:27:18 12.5.2016] queued: /trunk_test/Build/Utilities/Make_gl
+LOG:[12:27:18 12.5.2016] queued: /trunk_test/Build/Utilities/Make_monitor
+LOG:[12:27:18 12.5.2016] queued: /trunk_test/Build/Utilities/Make_oulan
+LOG:[12:27:18 12.5.2016] queued: /trunk_test/Build/Utilities/Make_gl_ecgate
+LOG:[12:27:18 12.5.2016] queued: /trunk_test/Build/Archive_log
+LOG:[12:27:18 12.5.2016] queued: /test_def
+LOG:[12:27:18 12.5.2016] queued: /test_def/Ping_HPC
+LOG:[12:27:18 12.5.2016] queued: /test_def/Prepare_SMS
+LOG:[12:27:18 12.5.2016] queued: /test_def/InitRun
+LOG:[12:27:18 12.5.2016] queued: /test_def/Build
+LOG:[12:27:18 12.5.2016] queued: /test_def/Build/Build_pack
+LOG:[12:27:18 12.5.2016] queued: /test_def/Build/Utilities
+LOG:[12:27:18 12.5.2016] queued: /test_def/Build/Utilities/Make_gl
+LOG:[12:27:18 12.5.2016] queued: /test_def/Build/Utilities/Make_monitor
+LOG:[12:27:18 12.5.2016] queued: /test_def/Build/Utilities/Make_oulan
+LOG:[12:27:18 12.5.2016] queued: /test_def/Build/Archive_log
+LOG:[12:27:18 12.5.2016] queued: /test_def/MARS
+LOG:[12:27:18 12.5.2016] queued: /test_def/MARS/Empty
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput/Hour
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput/Hour/Prepare_cycle
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput/Hour/Climate
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput/Hour/Climate/Empty
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput/Hour/Boundaries
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput/Hour/Boundaries/Boundary_strategy
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput/Hour/Boundaries/LBC0
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput/Hour/Boundaries/LBC0/hir2aro
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput/Hour/Boundaries/LBC1
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput/Hour/Boundaries/LBC1/hir2aro
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput/Hour/Boundaries/LBC2
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput/Hour/Boundaries/LBC2/hir2aro
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput/Hour/Boundaries/LBC3
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput/Hour/Boundaries/LBC3/hir2aro
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput/Hour/Boundaries/LBC4
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput/Hour/Boundaries/LBC4/hir2aro
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput/Hour/Boundaries/LBC5
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput/Hour/Boundaries/LBC5/hir2aro
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput/Hour/Boundaries/LBC6
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput/Hour/Boundaries/LBC6/hir2aro
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput/Hour/Observations
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput/Hour/Observations/Empty
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput/Hour/Archive_log
+LOG:[12:27:18 12.5.2016] queued: /test_def/Date
+LOG:[12:27:18 12.5.2016] queued: /test_def/Date/Hour
+LOG:[12:27:18 12.5.2016] queued: /test_def/Date/Hour/Cycle
+LOG:[12:27:18 12.5.2016] queued: /test_def/Date/Hour/Cycle/StartData
+LOG:[12:27:18 12.5.2016] queued: /test_def/Date/Hour/Cycle/StartData/Prep_ini_surfex
+LOG:[12:27:18 12.5.2016] queued: /test_def/Date/Hour/Cycle/StartData/FirstGuess
+LOG:[12:27:18 12.5.2016] queued: /test_def/Date/Hour/Cycle/Analysis
+LOG:[12:27:18 12.5.2016] queued: /test_def/Date/Hour/Cycle/Analysis/AnSFC
+LOG:[12:27:18 12.5.2016] queued: /test_def/Date/Hour/Cycle/Analysis/AnSFC/Empty
+LOG:[12:27:18 12.5.2016] queued: /test_def/Date/Hour/Cycle/Analysis/AnUA
+LOG:[12:27:18 12.5.2016] queued: /test_def/Date/Hour/Cycle/Analysis/AnUA/Empty
+LOG:[12:27:18 12.5.2016] queued: /test_def/Date/Hour/Cycle/Forecasting
+LOG:[12:27:18 12.5.2016] queued: /test_def/Date/Hour/Cycle/Forecasting/Forecast
+LOG:[12:27:18 12.5.2016] queued: /test_def/Date/Hour/Cycle/Forecasting/Archive_fc
+LOG:[12:27:18 12.5.2016] queued: /test_def/Date/Hour/Archive_log
+LOG:[12:27:18 12.5.2016] queued: /test_def/Date/Hour/LogProgress
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Extract4ver
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Extract4ver/fldextr0
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Extract4ver/fldextr0/Run_fldver
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Extract4ver/fldextr1
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Extract4ver/fldextr1/Run_fldver
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Extract4ver/fldextr2
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Extract4ver/fldextr2/Run_fldver
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Extract4ver/fldextr3
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Extract4ver/fldextr3/Run_fldver
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Extract4ver/fldextr4
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Extract4ver/fldextr4/Run_fldver
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Extract4ver/fldextr5
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Extract4ver/fldextr5/Run_fldver
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Extract4ver/fldextr6
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Extract4ver/fldextr6/Run_fldver
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Gather_extract
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Postp_family
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Postp_family/Postp0
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Postp_family/Postp0/Postpp
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Postp_family/Postp1
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Postp_family/Postp1/Postpp
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Postp_family/Postp2
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Postp_family/Postp2/Postpp
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Postp_family/Postp3
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Postp_family/Postp3/Postpp
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Postp_family/Postp4
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Postp_family/Postp4/Postpp
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Postp_family/Postp5
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Postp_family/Postp5/Postpp
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Postp_family/Postp6
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Postp_family/Postp6/Postpp
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Grib_family
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Grib_family/Grib0
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Grib_family/Grib0/Makegrib
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Grib_family/Grib1
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Grib_family/Grib1/Makegrib
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Grib_family/Grib2
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Grib_family/Grib2/Makegrib
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Grib_family/Grib3
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Grib_family/Grib3/Makegrib
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Grib_family/Grib4
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Grib_family/Grib4/Makegrib
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Grib_family/Grib5
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Grib_family/Grib5/Makegrib
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Grib_family/Grib6
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Grib_family/Grib6/Makegrib
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Cleancycle
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/ECMWF
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/ECMWF/Empty
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/Archive_log
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour/LogProgress
+LOG:[12:27:18 12.5.2016] submitted: /trunk_test/InitRun
+LOG:[12:27:18 12.5.2016] submitted: /trunk_test
+LOG:[12:27:18 12.5.2016] submitted: /
+LOG:[12:27:18 12.5.2016] active: /trunk_test/InitRun
+LOG:[12:27:18 12.5.2016] active: /trunk_test
+LOG:[12:27:18 12.5.2016] active: /
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Ping_HPC
+LOG:[12:27:18 12.5.2016] submitted: /test_def
+LOG:[12:27:18 12.5.2016] active: /test_def/Ping_HPC
+LOG:[12:27:18 12.5.2016] active: /test_def
+LOG:[12:27:18 12.5.2016] complete: /trunk_test/InitRun
+LOG:[12:27:18 12.5.2016] queued: /trunk_test
+LOG:[12:27:18 12.5.2016] submitted: /trunk_test/Build/Build_pack
+LOG:[12:27:18 12.5.2016] submitted: /trunk_test/Build
+LOG:[12:27:18 12.5.2016] submitted: /trunk_test
+LOG:[12:27:18 12.5.2016] active: /trunk_test/Build/Build_pack
+LOG:[12:27:18 12.5.2016] active: /trunk_test/Build
+LOG:[12:27:18 12.5.2016] active: /trunk_test
+LOG:[12:27:18 12.5.2016] submitted: /trunk_test/Build/Utilities/Make_gl
+LOG:[12:27:18 12.5.2016] submitted: /trunk_test/Build/Utilities
+LOG:[12:27:18 12.5.2016] active: /trunk_test/Build/Utilities/Make_gl
+LOG:[12:27:18 12.5.2016] active: /trunk_test/Build/Utilities
+LOG:[12:27:18 12.5.2016] submitted: /trunk_test/Build/Utilities/Make_monitor
+LOG:[12:27:18 12.5.2016] active: /trunk_test/Build/Utilities/Make_monitor
+LOG:[12:27:18 12.5.2016] submitted: /trunk_test/Build/Utilities/Make_oulan
+LOG:[12:27:18 12.5.2016] active: /trunk_test/Build/Utilities/Make_oulan
+LOG:[12:27:18 12.5.2016] submitted: /trunk_test/Build/Utilities/Make_gl_ecgate
+LOG:[12:27:18 12.5.2016] active: /trunk_test/Build/Utilities/Make_gl_ecgate
+LOG:[12:27:18 12.5.2016] submitted: /trunk_test/Build/Archive_log
+LOG:[12:27:18 12.5.2016] active: /trunk_test/Build/Archive_log
+LOG:[12:27:18 12.5.2016] complete: /trunk_test/Build/Build_pack
+LOG:[12:27:18 12.5.2016] complete: /trunk_test/Build/Utilities/Make_gl
+LOG:[12:27:18 12.5.2016] complete: /trunk_test/Build/Utilities/Make_monitor
+LOG:[12:27:18 12.5.2016] complete: /trunk_test/Build/Utilities/Make_oulan
+LOG:[12:27:18 12.5.2016] complete: /trunk_test/Build/Utilities/Make_gl_ecgate
+LOG:[12:27:18 12.5.2016] complete: /trunk_test/Build/Utilities
+LOG:[12:27:18 12.5.2016] complete: /trunk_test/Build/Archive_log
+LOG:[12:27:18 12.5.2016] complete: /trunk_test/Build
+LOG:[12:27:18 12.5.2016] complete: /trunk_test
+LOG:[12:27:18 12.5.2016] complete: /test_def/Ping_HPC
+LOG:[12:27:18 12.5.2016] queued: /test_def
+LOG:[12:27:18 12.5.2016] queued: /
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Prepare_SMS
+LOG:[12:27:18 12.5.2016] submitted: /test_def
+LOG:[12:27:18 12.5.2016] submitted: /
+LOG:[12:27:18 12.5.2016] active: /test_def/Prepare_SMS
+LOG:[12:27:18 12.5.2016] active: /test_def
+LOG:[12:27:18 12.5.2016] active: /
+LOG:[12:27:18 12.5.2016] complete: /test_def/Prepare_SMS
+LOG:[12:27:18 12.5.2016] queued: /test_def
+LOG:[12:27:18 12.5.2016] queued: /
+LOG:[12:27:18 12.5.2016] submitted: /test_def/InitRun
+LOG:[12:27:18 12.5.2016] submitted: /test_def
+LOG:[12:27:18 12.5.2016] submitted: /
+LOG:[12:27:18 12.5.2016] active: /test_def/InitRun
+LOG:[12:27:18 12.5.2016] active: /test_def
+LOG:[12:27:18 12.5.2016] active: /
+LOG:[12:27:18 12.5.2016] complete: /test_def/InitRun
+LOG:[12:27:18 12.5.2016] queued: /test_def
+LOG:[12:27:18 12.5.2016] queued: /
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Build/Build_pack
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Build
+LOG:[12:27:18 12.5.2016] submitted: /test_def
+LOG:[12:27:18 12.5.2016] submitted: /
+LOG:[12:27:18 12.5.2016] active: /test_def/Build/Build_pack
+LOG:[12:27:18 12.5.2016] active: /test_def/Build
+LOG:[12:27:18 12.5.2016] active: /test_def
+LOG:[12:27:18 12.5.2016] active: /
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Build/Utilities/Make_gl
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Build/Utilities
+LOG:[12:27:18 12.5.2016] active: /test_def/Build/Utilities/Make_gl
+LOG:[12:27:18 12.5.2016] active: /test_def/Build/Utilities
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Build/Utilities/Make_monitor
+LOG:[12:27:18 12.5.2016] active: /test_def/Build/Utilities/Make_monitor
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Build/Utilities/Make_oulan
+LOG:[12:27:18 12.5.2016] active: /test_def/Build/Utilities/Make_oulan
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MARS/Empty
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MARS
+LOG:[12:27:18 12.5.2016] active: /test_def/MARS/Empty
+LOG:[12:27:18 12.5.2016] active: /test_def/MARS
+LOG:[12:27:18 12.5.2016] complete: /test_def/Build/Build_pack
+LOG:[12:27:18 12.5.2016] complete: /test_def/Build/Utilities/Make_gl
+LOG:[12:27:18 12.5.2016] complete: /test_def/Build/Utilities/Make_monitor
+LOG:[12:27:18 12.5.2016] complete: /test_def/Build/Utilities/Make_oulan
+LOG:[12:27:18 12.5.2016] complete: /test_def/Build/Utilities
+LOG:[12:27:18 12.5.2016] queued: /test_def/Build
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Build/Archive_log
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Build
+LOG:[12:27:18 12.5.2016] active: /test_def/Build/Archive_log
+LOG:[12:27:18 12.5.2016] active: /test_def/Build
+LOG:[12:27:18 12.5.2016] complete: /test_def/Build/Archive_log
+LOG:[12:27:18 12.5.2016] complete: /test_def/Build
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput/Hour/Prepare_cycle
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput/Hour
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput/Hour/Prepare_cycle
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput/Hour
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput
+LOG:[12:27:18 12.5.2016] complete: /test_def/MakeCycleInput/Hour/Prepare_cycle
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput/Hour
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput/Hour/Climate/Empty
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput/Hour/Climate
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput/Hour
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput/Hour/Climate/Empty
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput/Hour/Climate
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput/Hour
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput
+LOG:[12:27:18 12.5.2016] complete: /test_def/MakeCycleInput/Hour/Climate/Empty
+LOG:[12:27:18 12.5.2016] complete: /test_def/MakeCycleInput/Hour/Climate
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput/Hour
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput/Hour/Boundaries/Boundary_strategy
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput/Hour/Boundaries
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput/Hour
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput/Hour/Boundaries/Boundary_strategy
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput/Hour/Boundaries
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput/Hour
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput
+LOG:[12:27:18 12.5.2016] complete: /test_def/MakeCycleInput/Hour/Boundaries/Boundary_strategy
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput/Hour/Boundaries
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput/Hour
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput/Hour/Boundaries/LBC0/hir2aro
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput/Hour/Boundaries/LBC0
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput/Hour/Boundaries
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput/Hour
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput/Hour/Boundaries/LBC0/hir2aro
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput/Hour/Boundaries/LBC0
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput/Hour/Boundaries
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput/Hour
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput/Hour/Boundaries/LBC1/hir2aro
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput/Hour/Boundaries/LBC1
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput/Hour/Boundaries/LBC1/hir2aro
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput/Hour/Boundaries/LBC1
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput/Hour/Boundaries/LBC2/hir2aro
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput/Hour/Boundaries/LBC2
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput/Hour/Boundaries/LBC2/hir2aro
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput/Hour/Boundaries/LBC2
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput/Hour/Boundaries/LBC3/hir2aro
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput/Hour/Boundaries/LBC3
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput/Hour/Boundaries/LBC3/hir2aro
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput/Hour/Boundaries/LBC3
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput/Hour/Boundaries/LBC4/hir2aro
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput/Hour/Boundaries/LBC4
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput/Hour/Boundaries/LBC4/hir2aro
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput/Hour/Boundaries/LBC4
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput/Hour/Boundaries/LBC5/hir2aro
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput/Hour/Boundaries/LBC5
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput/Hour/Boundaries/LBC5/hir2aro
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput/Hour/Boundaries/LBC5
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput/Hour/Boundaries/LBC6/hir2aro
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput/Hour/Boundaries/LBC6
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput/Hour/Boundaries/LBC6/hir2aro
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput/Hour/Boundaries/LBC6
+LOG:[12:27:18 12.5.2016] complete: /test_def/MakeCycleInput/Hour/Boundaries/LBC0/hir2aro
+LOG:[12:27:18 12.5.2016] complete: /test_def/MakeCycleInput/Hour/Boundaries/LBC0
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Date/Hour/Cycle/StartData/Prep_ini_surfex
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Date/Hour/Cycle/StartData
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Date/Hour/Cycle
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Date/Hour
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Date
+LOG:[12:27:18 12.5.2016] active: /test_def/Date/Hour/Cycle/StartData/Prep_ini_surfex
+LOG:[12:27:18 12.5.2016] active: /test_def/Date/Hour/Cycle/StartData
+LOG:[12:27:18 12.5.2016] active: /test_def/Date/Hour/Cycle
+LOG:[12:27:18 12.5.2016] active: /test_def/Date/Hour
+LOG:[12:27:18 12.5.2016] active: /test_def/Date
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Date/Hour/Cycle/StartData/FirstGuess
+LOG:[12:27:18 12.5.2016] active: /test_def/Date/Hour/Cycle/StartData/FirstGuess
+LOG:[12:27:18 12.5.2016] complete: /test_def/Date/Hour/Cycle/StartData/Prep_ini_surfex
+LOG:[12:27:18 12.5.2016] complete: /test_def/Date/Hour/Cycle/StartData/FirstGuess
+LOG:[12:27:18 12.5.2016] complete: /test_def/Date/Hour/Cycle/StartData
+LOG:[12:27:18 12.5.2016] queued: /test_def/Date/Hour/Cycle
+LOG:[12:27:18 12.5.2016] queued: /test_def/Date/Hour
+LOG:[12:27:18 12.5.2016] queued: /test_def/Date
+LOG:[12:27:18 12.5.2016] complete: /test_def/MakeCycleInput/Hour/Boundaries/LBC1/hir2aro
+LOG:[12:27:18 12.5.2016] complete: /test_def/MakeCycleInput/Hour/Boundaries/LBC1
+LOG:[12:27:18 12.5.2016] complete: /test_def/MakeCycleInput/Hour/Boundaries/LBC2/hir2aro
+LOG:[12:27:18 12.5.2016] complete: /test_def/MakeCycleInput/Hour/Boundaries/LBC2
+LOG:[12:27:18 12.5.2016] complete: /test_def/MakeCycleInput/Hour/Boundaries/LBC3/hir2aro
+LOG:[12:27:18 12.5.2016] complete: /test_def/MakeCycleInput/Hour/Boundaries/LBC3
+LOG:[12:27:18 12.5.2016] complete: /test_def/MakeCycleInput/Hour/Boundaries/LBC4/hir2aro
+LOG:[12:27:18 12.5.2016] complete: /test_def/MakeCycleInput/Hour/Boundaries/LBC4
+LOG:[12:27:18 12.5.2016] complete: /test_def/MakeCycleInput/Hour/Boundaries/LBC5/hir2aro
+LOG:[12:27:18 12.5.2016] complete: /test_def/MakeCycleInput/Hour/Boundaries/LBC5
+LOG:[12:27:18 12.5.2016] complete: /test_def/MakeCycleInput/Hour/Boundaries/LBC6/hir2aro
+LOG:[12:27:18 12.5.2016] complete: /test_def/MakeCycleInput/Hour/Boundaries/LBC6
+LOG:[12:27:18 12.5.2016] complete: /test_def/MakeCycleInput/Hour/Boundaries
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput/Hour
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput
+LOG:[12:27:18 12.5.2016] complete: /test_def/MARS/Empty
+LOG:[12:27:18 12.5.2016] complete: /test_def/MARS
+LOG:[12:27:18 12.5.2016] queued: /test_def
+LOG:[12:27:18 12.5.2016] queued: /
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput/Hour/Observations/Empty
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput/Hour/Observations
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput/Hour
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput
+LOG:[12:27:18 12.5.2016] submitted: /test_def
+LOG:[12:27:18 12.5.2016] submitted: /
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput/Hour/Observations/Empty
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput/Hour/Observations
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput/Hour
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput
+LOG:[12:27:18 12.5.2016] active: /test_def
+LOG:[12:27:18 12.5.2016] active: /
+LOG:[12:27:18 12.5.2016] complete: /test_def/MakeCycleInput/Hour/Observations/Empty
+LOG:[12:27:18 12.5.2016] complete: /test_def/MakeCycleInput/Hour/Observations
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput/Hour
+LOG:[12:27:18 12.5.2016] queued: /test_def/MakeCycleInput
+LOG:[12:27:18 12.5.2016] queued: /test_def
+LOG:[12:27:18 12.5.2016] queued: /
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput/Hour/Archive_log
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput/Hour
+LOG:[12:27:18 12.5.2016] submitted: /test_def/MakeCycleInput
+LOG:[12:27:18 12.5.2016] submitted: /test_def
+LOG:[12:27:18 12.5.2016] submitted: /
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput/Hour/Archive_log
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput/Hour
+LOG:[12:27:18 12.5.2016] active: /test_def/MakeCycleInput
+LOG:[12:27:18 12.5.2016] active: /test_def
+LOG:[12:27:18 12.5.2016] active: /
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Date/Hour/Cycle/Analysis/AnSFC/Empty
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Date/Hour/Cycle/Analysis/AnSFC
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Date/Hour/Cycle/Analysis
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Date/Hour/Cycle
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Date/Hour
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Date
+LOG:[12:27:18 12.5.2016] active: /test_def/Date/Hour/Cycle/Analysis/AnSFC/Empty
+LOG:[12:27:18 12.5.2016] active: /test_def/Date/Hour/Cycle/Analysis/AnSFC
+LOG:[12:27:18 12.5.2016] active: /test_def/Date/Hour/Cycle/Analysis
+LOG:[12:27:18 12.5.2016] active: /test_def/Date/Hour/Cycle
+LOG:[12:27:18 12.5.2016] active: /test_def/Date/Hour
+LOG:[12:27:18 12.5.2016] active: /test_def/Date
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Date/Hour/Cycle/Analysis/AnUA/Empty
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Date/Hour/Cycle/Analysis/AnUA
+LOG:[12:27:18 12.5.2016] active: /test_def/Date/Hour/Cycle/Analysis/AnUA/Empty
+LOG:[12:27:18 12.5.2016] active: /test_def/Date/Hour/Cycle/Analysis/AnUA
+LOG:[12:27:18 12.5.2016] complete: /test_def/MakeCycleInput/Hour/Archive_log
+LOG:[12:27:18 12.5.2016] complete: /test_def/MakeCycleInput/Hour
+LOG:[12:27:18 12.5.2016] complete: /test_def/MakeCycleInput
+LOG:[12:27:18 12.5.2016] complete: /test_def/Date/Hour/Cycle/Analysis/AnSFC/Empty
+LOG:[12:27:18 12.5.2016] complete: /test_def/Date/Hour/Cycle/Analysis/AnSFC
+LOG:[12:27:18 12.5.2016] complete: /test_def/Date/Hour/Cycle/Analysis/AnUA/Empty
+LOG:[12:27:18 12.5.2016] complete: /test_def/Date/Hour/Cycle/Analysis/AnUA
+LOG:[12:27:18 12.5.2016] complete: /test_def/Date/Hour/Cycle/Analysis
+LOG:[12:27:18 12.5.2016] queued: /test_def/Date/Hour/Cycle
+LOG:[12:27:18 12.5.2016] queued: /test_def/Date/Hour
+LOG:[12:27:18 12.5.2016] queued: /test_def/Date
+LOG:[12:27:18 12.5.2016] queued: /test_def
+LOG:[12:27:18 12.5.2016] queued: /
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Date/Hour/Cycle/Forecasting/Forecast
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Date/Hour/Cycle/Forecasting
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Date/Hour/Cycle
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Date/Hour
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Date
+LOG:[12:27:18 12.5.2016] submitted: /test_def
+LOG:[12:27:18 12.5.2016] submitted: /
+LOG:[12:27:18 12.5.2016] active: /test_def/Date/Hour/Cycle/Forecasting/Forecast
+LOG:[12:27:18 12.5.2016] active: /test_def/Date/Hour/Cycle/Forecasting
+LOG:[12:27:18 12.5.2016] active: /test_def/Date/Hour/Cycle
+LOG:[12:27:18 12.5.2016] active: /test_def/Date/Hour
+LOG:[12:27:18 12.5.2016] active: /test_def/Date
+LOG:[12:27:18 12.5.2016] active: /test_def
+LOG:[12:27:18 12.5.2016] active: /
+LOG:[12:27:18 12.5.2016] complete: /test_def/Date/Hour/Cycle/Forecasting/Forecast
+LOG:[12:27:18 12.5.2016] queued: /test_def/Date/Hour/Cycle/Forecasting
+LOG:[12:27:18 12.5.2016] queued: /test_def/Date/Hour/Cycle
+LOG:[12:27:18 12.5.2016] queued: /test_def/Date/Hour
+LOG:[12:27:18 12.5.2016] queued: /test_def/Date
+LOG:[12:27:18 12.5.2016] queued: /test_def
+LOG:[12:27:18 12.5.2016] queued: /
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Date/Hour/Cycle/Forecasting/Archive_fc
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Date/Hour/Cycle/Forecasting
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Date/Hour/Cycle
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Date/Hour
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Date
+LOG:[12:27:18 12.5.2016] submitted: /test_def
+LOG:[12:27:18 12.5.2016] submitted: /
+LOG:[12:27:18 12.5.2016] active: /test_def/Date/Hour/Cycle/Forecasting/Archive_fc
+LOG:[12:27:18 12.5.2016] active: /test_def/Date/Hour/Cycle/Forecasting
+LOG:[12:27:18 12.5.2016] active: /test_def/Date/Hour/Cycle
+LOG:[12:27:18 12.5.2016] active: /test_def/Date/Hour
+LOG:[12:27:18 12.5.2016] active: /test_def/Date
+LOG:[12:27:18 12.5.2016] active: /test_def
+LOG:[12:27:18 12.5.2016] active: /
+LOG:[12:27:18 12.5.2016] complete: /test_def/Date/Hour/Cycle/Forecasting/Archive_fc
+LOG:[12:27:18 12.5.2016] complete: /test_def/Date/Hour/Cycle/Forecasting
+LOG:[12:27:18 12.5.2016] complete: /test_def/Date/Hour/Cycle
+LOG:[12:27:18 12.5.2016] queued: /test_def/Date/Hour
+LOG:[12:27:18 12.5.2016] queued: /test_def/Date
+LOG:[12:27:18 12.5.2016] queued: /test_def
+LOG:[12:27:18 12.5.2016] queued: /
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Date/Hour/Archive_log
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Date/Hour
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Date
+LOG:[12:27:18 12.5.2016] submitted: /test_def
+LOG:[12:27:18 12.5.2016] submitted: /
+LOG:[12:27:18 12.5.2016] active: /test_def/Date/Hour/Archive_log
+LOG:[12:27:18 12.5.2016] active: /test_def/Date/Hour
+LOG:[12:27:18 12.5.2016] active: /test_def/Date
+LOG:[12:27:18 12.5.2016] active: /test_def
+LOG:[12:27:18 12.5.2016] active: /
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Date/Hour/LogProgress
+LOG:[12:27:18 12.5.2016] active: /test_def/Date/Hour/LogProgress
+LOG:[12:27:18 12.5.2016] complete: /test_def/Date/Hour/Archive_log
+LOG:[12:27:18 12.5.2016] complete: /test_def/Date/Hour/LogProgress
+LOG:[12:27:18 12.5.2016] complete: /test_def/Date/Hour
+LOG:[12:27:18 12.5.2016] complete: /test_def/Date
+LOG:[12:27:18 12.5.2016] queued: /test_def
+LOG:[12:27:18 12.5.2016] queued: /
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Extract4ver/fldextr0/Run_fldver
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Extract4ver/fldextr0
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Extract4ver
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing
+LOG:[12:27:18 12.5.2016] submitted: /test_def
+LOG:[12:27:18 12.5.2016] submitted: /
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Extract4ver/fldextr0/Run_fldver
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Extract4ver/fldextr0
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Extract4ver
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing
+LOG:[12:27:18 12.5.2016] active: /test_def
+LOG:[12:27:18 12.5.2016] active: /
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Extract4ver/fldextr1/Run_fldver
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Extract4ver/fldextr1
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Extract4ver/fldextr1/Run_fldver
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Extract4ver/fldextr1
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Extract4ver/fldextr2/Run_fldver
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Extract4ver/fldextr2
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Extract4ver/fldextr2/Run_fldver
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Extract4ver/fldextr2
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Extract4ver/fldextr3/Run_fldver
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Extract4ver/fldextr3
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Extract4ver/fldextr3/Run_fldver
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Extract4ver/fldextr3
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Extract4ver/fldextr4/Run_fldver
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Extract4ver/fldextr4
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Extract4ver/fldextr4/Run_fldver
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Extract4ver/fldextr4
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Extract4ver/fldextr5/Run_fldver
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Extract4ver/fldextr5
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Extract4ver/fldextr5/Run_fldver
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Extract4ver/fldextr5
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Extract4ver/fldextr6/Run_fldver
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Extract4ver/fldextr6
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Extract4ver/fldextr6/Run_fldver
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Extract4ver/fldextr6
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Postp_family/Postp0/Postpp
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Postp_family/Postp0
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Postp_family
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Postp_family/Postp0/Postpp
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Postp_family/Postp0
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Postp_family
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Postp_family/Postp1/Postpp
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Postp_family/Postp1
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Postp_family/Postp1/Postpp
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Postp_family/Postp1
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Postp_family/Postp2/Postpp
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Postp_family/Postp2
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Postp_family/Postp2/Postpp
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Postp_family/Postp2
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Postp_family/Postp3/Postpp
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Postp_family/Postp3
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Postp_family/Postp3/Postpp
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Postp_family/Postp3
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Postp_family/Postp4/Postpp
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Postp_family/Postp4
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Postp_family/Postp4/Postpp
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Postp_family/Postp4
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Postp_family/Postp5/Postpp
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Postp_family/Postp5
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Postp_family/Postp5/Postpp
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Postp_family/Postp5
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Postp_family/Postp6/Postpp
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Postp_family/Postp6
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Postp_family/Postp6/Postpp
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Postp_family/Postp6
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/ECMWF/Empty
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/ECMWF
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/ECMWF/Empty
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/ECMWF
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Extract4ver/fldextr0/Run_fldver
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Extract4ver/fldextr0
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Extract4ver/fldextr1/Run_fldver
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Extract4ver/fldextr1
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Extract4ver/fldextr2/Run_fldver
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Extract4ver/fldextr2
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Extract4ver/fldextr3/Run_fldver
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Extract4ver/fldextr3
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Extract4ver/fldextr4/Run_fldver
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Extract4ver/fldextr4
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Extract4ver/fldextr5/Run_fldver
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Extract4ver/fldextr5
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Extract4ver/fldextr6/Run_fldver
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Extract4ver/fldextr6
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Extract4ver
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Gather_extract
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Gather_extract
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Gather_extract
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Postp_family/Postp0/Postpp
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Postp_family/Postp0
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Postp_family/Postp1/Postpp
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Postp_family/Postp1
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Postp_family/Postp2/Postpp
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Postp_family/Postp2
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Postp_family/Postp3/Postpp
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Postp_family/Postp3
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Postp_family/Postp4/Postpp
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Postp_family/Postp4
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Postp_family/Postp5/Postpp
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Postp_family/Postp5
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Postp_family/Postp6/Postpp
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Postp_family/Postp6
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Postp_family
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Grib_family/Grib0/Makegrib
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Grib_family/Grib0
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Grib_family
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Grib_family/Grib0/Makegrib
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Grib_family/Grib0
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Grib_family
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Grib_family/Grib1/Makegrib
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Grib_family/Grib1
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Grib_family/Grib1/Makegrib
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Grib_family/Grib1
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Grib_family/Grib2/Makegrib
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Grib_family/Grib2
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Grib_family/Grib2/Makegrib
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Grib_family/Grib2
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Grib_family/Grib3/Makegrib
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Grib_family/Grib3
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Grib_family/Grib3/Makegrib
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Grib_family/Grib3
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Grib_family/Grib4/Makegrib
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Grib_family/Grib4
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Grib_family/Grib4/Makegrib
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Grib_family/Grib4
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Grib_family/Grib5/Makegrib
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Grib_family/Grib5
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Grib_family/Grib5/Makegrib
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Grib_family/Grib5
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Grib_family/Grib6/Makegrib
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Grib_family/Grib6
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Grib_family/Grib6/Makegrib
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Grib_family/Grib6
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Grib_family/Grib0/Makegrib
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Grib_family/Grib0
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Grib_family/Grib1/Makegrib
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Grib_family/Grib1
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Grib_family/Grib2/Makegrib
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Grib_family/Grib2
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Grib_family/Grib3/Makegrib
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Grib_family/Grib3
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Grib_family/Grib4/Makegrib
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Grib_family/Grib4
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Grib_family/Grib5/Makegrib
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Grib_family/Grib5
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Grib_family/Grib6/Makegrib
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Grib_family/Grib6
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Grib_family
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Cleancycle
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Cleancycle
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Cleancycle
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/ECMWF/Empty
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/ECMWF
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing/Hour
+LOG:[12:27:18 12.5.2016] queued: /test_def/Postprocessing
+LOG:[12:27:18 12.5.2016] queued: /test_def
+LOG:[12:27:18 12.5.2016] queued: /
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/Archive_log
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing
+LOG:[12:27:18 12.5.2016] submitted: /test_def
+LOG:[12:27:18 12.5.2016] submitted: /
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/Archive_log
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing
+LOG:[12:27:18 12.5.2016] active: /test_def
+LOG:[12:27:18 12.5.2016] active: /
+LOG:[12:27:18 12.5.2016] submitted: /test_def/Postprocessing/Hour/LogProgress
+LOG:[12:27:18 12.5.2016] active: /test_def/Postprocessing/Hour/LogProgress
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/Archive_log
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour/LogProgress
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing/Hour
+LOG:[12:27:18 12.5.2016] complete: /test_def/Postprocessing
+LOG:[12:27:18 12.5.2016] complete: /test_def
+LOG:[12:27:18 12.5.2016] complete: /
+MSG:[12:27:18 12.5.2016] Simulation complete in 00:00:00
diff --git a/CSim/test/data/good_defs/operations/xpt.def b/CSim/test/data/good_defs/operations/xpt.def
new file mode 100644
index 0000000..1947ede
--- /dev/null
+++ b/CSim/test/data/good_defs/operations/xpt.def
@@ -0,0 +1,2562 @@
+#============================================================
+extern an
+extern an
+extern fc
+extern fc
+extern eps_sv
+extern eps_sv
+extern eps_fc
+extern eps_fc
+extern eps_varfc
+extern eps_varfc
+extern oceatm
+extern oceatm
+extern oce
+extern oce
+extern fpos
+extern fpos
+extern sens
+extern sens
+extern wam
+extern wam
+extern oc
+extern oc
+extern climplot
+extern climplot
+extern an
+extern an
+extern fc
+extern fc
+extern eps_sv
+extern eps_sv
+extern eps_fc
+extern eps_fc
+extern eps_varfc
+extern eps_varfc
+extern oceatm
+extern oceatm
+extern oce
+extern oce
+extern fpos
+extern fpos
+extern sens
+extern sens
+extern wam
+extern wam
+extern oc
+extern oc
+extern climplot
+extern climplot
+suite ptb
+ clock hybrid 0 # 03.11.2008 16:55
+ family a020
+ edit SMSTRIES '1'
+ edit SMSFILES '/vol/msverify/sms/ptb/a020'
+ edit SMSINCLUDE '/vol/msverify/sms/ptb/a020/include'
+ edit SMSHOME '/vol/msverify/sms'
+ edit SMSOUT '/vol/msverify/sms'
+ edit SMSLOGPORT '9314'
+ edit SMSLOGHOST 'hpce-batch'
+ edit FSFAMILY ''
+ edit DELTA_DAY '0'
+ edit HOUR ''
+ edit MEMBER '0'
+ edit NPROCA '1'
+ edit NPROCB '1'
+ edit THREADS '1'
+ edit BRANCH ''
+ edit PARALLEL '4'
+ edit DEBUG '0'
+ edit PROFILE '0'
+ edit DISPLAY 'define_your_own:0.0'
+ edit QUEUE 'normal'
+ edit SCHOST 'hpce'
+ edit WSHOST 'ecgate'
+ edit LOGHOST 'ecgate'
+ edit EXPVER 'a020'
+ edit OWNER 'ptb'
+ edit USER 'xpt'
+ edit ACCOUNT 'ptearth'
+ edit YMD '19900101'
+ edit SECS '0'
+ edit SMSCMD 'smssubmit.x %SMSJOB% %SCHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %SCHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %SCHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/hpce/rdx_dir/msx'
+ family make
+ edit YMD '19900101'
+ edit HOUR '00'
+ edit FSFAMILY 'make'
+ task setup
+ edit QUEUE 'normal'
+ family libs
+ defstatus complete
+ trigger setup eq complete
+ edit CCSUBDIR '.'
+ task p4setup_ifs
+ edit SMSTRIES '2'
+ task p4diff_ifs
+ trigger p4setup_ifs eq complete
+ family compile
+ trigger p4setup_ifs eq complete
+ family ifsaux
+ defstatus complete
+ task libifsaux
+ endfamily
+ family surf
+ defstatus complete
+ trigger ifsaux eq complete
+ task libsurf
+ endfamily
+ family trans
+ defstatus complete
+ trigger ifsaux eq complete
+ task libtrans
+ endfamily
+ family ifs
+ defstatus complete
+ trigger ( ifsaux eq complete or ifsaux eq unknown) and ( trans eq complete or trans eq unknown) and ( surf eq complete or surf eq unknown)
+ task libifs
+ endfamily
+ family wam
+ defstatus complete
+ trigger ifsaux eq complete
+ task libwam
+ endfamily
+ family odb
+ defstatus complete
+ family compiler
+ task libodbsqlcompiler
+ endfamily
+ family databases
+ trigger compiler eq complete
+ family CCMA
+ task libCCMA
+ endfamily
+ family ECMA
+ task libECMA
+ endfamily
+ endfamily
+ family corelibs
+ trigger ../ifsaux eq complete
+ family odb
+ task libodb
+ endfamily
+ family odbdummy
+ trigger odb/libodb eq complete
+ task libodbdummy
+ endfamily
+ family odbmain
+ trigger odb/libodb eq complete and odbdummy/libodbdummy eq complete and ../../ifs eq complete
+ task libodbmain
+ endfamily
+ family odbport
+ trigger odb/libodb eq complete and odbdummy/libodbdummy eq complete and odbmain/libodbmain eq complete and ../../ifs eq complete
+ task libodbport
+ endfamily
+ endfamily
+ endfamily
+ family ssa
+ defstatus complete
+ trigger ifsaux eq complete and ifs eq complete and odb/corelibs/odb/libodb eq complete
+ task libssa
+ endfamily
+ family obstat
+ defstatus complete
+ trigger ifsaux eq complete and odb/corelibs/odb/libodb eq complete
+ task libobstat
+ endfamily
+ family bl
+ defstatus complete
+ trigger ifsaux eq complete
+ task libbl95
+ endfamily
+ family scat
+ defstatus complete
+ trigger ifsaux eq complete
+ task libscat
+ endfamily
+ family satrad
+ defstatus complete
+ trigger ifsaux eq complete
+ task libsatrad
+ endfamily
+ family aeolus
+ defstatus complete
+ trigger ifsaux eq complete
+ task libaeolus
+ endfamily
+ family prepdata
+ defstatus complete
+ trigger ( ifsaux eq complete or ifsaux eq unknown) and ( trans eq complete or trans eq unknown) and ( ifs eq complete or ifs eq unknown)
+ task libprepdata
+ endfamily
+ endfamily
+ endfamily
+ task links
+ trigger ( setup eq complete or setup eq unknown) and ( libs eq complete or libs eq unknown)
+ edit QUEUE 'normal'
+ task logfiles
+ trigger ( links eq complete or links eq unknown)
+ edit SMSCMD 'smssubmit.x %SMSJOB% %SCHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %SCHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %SCHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/hpce/rdx_dir/msx'
+ endfamily
+ family coup
+ edit VERSION 'a020'
+ edit STREAM 'MMSF'
+ edit EPSTYPE 'fc'
+ edit EMOS_BASE '00'
+ edit DATEMASK '*.*.*'
+ edit FIRST_DAY '0'
+ edit YMD '19690101'
+ edit USE_YMD 'true'
+ edit FCCHUNK '1'
+ edit OCESUITE '0'
+ edit ORIGIN 'ECMF'
+ edit SMSTRIES '1'
+ edit DELTA_DAY '0'
+ edit USER_PRIORITY '50'
+ edit PRIORITY '50'
+ edit EMOS_TYPE 'fc'
+ edit EMOS_TIME_STEP_H '0000'
+ edit EMOS_STREAM 'DA'
+ edit FSFAMILY 'coup'
+ edit FCNPES '1'
+ edit MEMBER '0'
+ edit COUP 'true'
+ edit RUNBACK '0'
+ edit OCASSIMTOTAL '3'
+ edit OCCONTROLTOTAL '1'
+ edit OCNEWPERTORDER 'yes'
+ edit SMSCMD 'smssubmit.x %SMSJOB% %SCHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %SCHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %SCHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/hpce/rdx_dir/msx'
+ edit HOUR '00'
+ edit CHUNK '0'
+ edit RUNCOUPLE '0'
+ edit FCLENGTH '0'
+ edit FCGROUP 'fc0'
+ edit OCGROUP 'an0'
+ edit OCTOTAL '3'
+ edit FCTOTAL '1'
+ edit OCSUITENO '1'
+ edit CFCTOTDONE '0'
+ edit FCTOTDONE '0'
+ edit CFCEXTOTDONE '0'
+ edit FCEXTOTDONE '0'
+ family limits
+ defstatus complete
+ limit mars 1
+ limit cpmodel 1
+ limit fdbclean 1
+ limit ws 1
+ limit PIC 6
+ endfamily
+ family make
+ trigger /ptb/a020/make eq complete
+ task setup
+ task links
+ trigger setup eq complete
+ task datalinks
+ trigger links eq complete
+ task ocsetup
+ trigger datalinks eq complete
+ task libsoc
+ trigger ./ocsetup eq complete
+ task oclinks
+ trigger ./libsoc eq complete
+ task prepdata
+ trigger oclinks eq complete
+ task mc_tools
+ trigger prepdata eq complete
+ task sc_tools
+ trigger mc_tools eq complete
+ task tools
+ defstatus complete
+ trigger oclinks eq complete
+ edit SMSCMD 'smssubmit.x %SMSJOB% %WSHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %WSHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %WSHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/vol/msexplog/outputs'
+ edit QUEUE 'expsms'
+ task octools
+ defstatus complete
+ trigger tools eq complete
+ edit SMSCMD 'smssubmit.x %SMSJOB% %WSHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %WSHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %WSHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/vol/msexplog/outputs'
+ edit QUEUE 'expsms'
+ task build_seasplot
+ defstatus complete
+ trigger octools eq complete
+ edit SMSCMD 'smssubmit.x %SMSJOB% %WSHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %WSHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %WSHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/vol/msexplog/outputs'
+ edit QUEUE 'expsms'
+ family couple
+ trigger mc_tools eq complete
+ task ifs
+ trigger ../oclinks eq complete
+ task oasis
+ task wamabs
+ endfamily
+ family const
+ task wconst
+ trigger ../couple eq complete
+ endfamily
+ family control
+ defstatus complete
+ trigger const eq complete
+ edit FSFAMILY 'control'
+ task ocean
+ trigger ../libsoc eq complete
+ task forcing
+ trigger ocean eq complete
+ task getcouple
+ defstatus complete
+ trigger forcing eq complete
+ edit RUNCOUPLE '1'
+ edit FCGROUP 'fc0'
+ endfamily
+ family assim
+ trigger control eq complete and const eq complete
+ edit FSFAMILY 'assim'
+ task ocean
+ trigger ../libsoc eq complete
+ task forcing
+ trigger ocean eq complete
+ task getcouple
+ trigger forcing eq complete
+ edit RUNCOUPLE '1'
+ edit FCGROUP 'fc0'
+ endfamily
+ task logfiles
+ trigger setup eq complete and links eq complete and datalinks eq complete and ocsetup eq complete and libsoc eq complete and oclinks eq complete and tools eq complete and sc_tools eq complete and octools eq complete and build_seasplot eq complete and couple eq complete and const eq complete and control eq complete and assim eq complete
+ edit SMSCMD 'smssubmit.x %SMSJOB% %SCHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %SCHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %SCHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/hpce/rdx_dir/msx'
+ edit LOGTASK 'make'
+ endfamily
+ family fcdate
+ trigger make eq complete
+ family main
+ repeat enumerated YMD "19690101" "19690102" # status 19690102
+ edit LOGTASK 'fcdate/main'
+ family control0
+ defstatus complete
+ edit FSFAMILY 'control'
+ edit OCTOTAL '1'
+ edit OCGROUP 'an0'
+ edit FCTOTAL '1'
+ edit RUNCOUPLE '1'
+ edit FCLENGTH '24'
+ edit SUBFSFAMILY '_an0_fc0'
+ edit FCGROUP 'fc0'
+ task getini
+ task inidata
+ trigger getini eq complete
+ edit NPES '12'
+ edit ININPES '12'
+ edit MEM '900'
+ edit THREADS '2'
+ edit CPUTIME '1000'
+ task oceini
+ family eps_sv
+ defstatus complete
+ edit MOFCSV 'true'
+ family svevo
+ edit DELTA_DAY '-2'
+ task getini
+ edit PRIORITY '40'
+ task inidata
+ trigger getini eq complete
+ edit NPES '12'
+ edit ININPES '12'
+ edit MEM '900'
+ edit THREADS '2'
+ edit CPUTIME '1000'
+ task svnh
+ trigger inidata eq complete
+ edit FCLENGTH '48'
+ edit EPSSVDIAB '0'
+ edit EPSTROP '0'
+ edit MEMBER '0'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ task svsh
+ trigger inidata eq complete
+ edit FCLENGTH '48'
+ edit EPSSVDIAB '0'
+ edit EPSTROP '0'
+ edit MEMBER '0'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ endfamily
+ family svini
+ edit DELTA_DAY '0'
+ task getini
+ trigger ../svevo eq complete
+ edit PRIORITY '40'
+ task inidata
+ trigger getini eq complete
+ edit NPES '12'
+ edit ININPES '12'
+ edit MEM '900'
+ edit THREADS '2'
+ edit CPUTIME '1000'
+ task svnh
+ trigger inidata eq complete
+ edit FCLENGTH '48'
+ edit EPSSVDIAB '0'
+ edit EPSTROP '0'
+ edit MEMBER '0'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ task svsh
+ trigger inidata eq complete
+ edit FCLENGTH '48'
+ edit EPSSVDIAB '0'
+ edit EPSTROP '0'
+ edit MEMBER '0'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ task targets
+ trigger svsh eq complete
+ edit FCLENGTH '48'
+ task subspace
+ trigger svnh eq complete and svsh eq complete and targets eq complete
+ edit FCLENGTH '48'
+ task sv1
+ trigger targets eq complete and subspace eq complete
+ edit FCLENGTH '48'
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ edit MEMBER '1'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ task sv2
+ trigger targets eq complete and subspace eq complete
+ edit FCLENGTH '48'
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ edit MEMBER '2'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ task sv3
+ trigger sv1 eq complete and targets eq complete
+ edit FCLENGTH '48'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ edit MEMBER '3'
+ task sv4
+ trigger sv2 eq complete and targets eq complete
+ edit FCLENGTH '48'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ edit MEMBER '4'
+ task sv5
+ trigger sv3 eq complete and targets eq complete and subspace eq complete
+ edit FCLENGTH '48'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ edit MEMBER '5'
+ task sv6
+ trigger sv4 eq complete and targets eq complete and subspace eq complete
+ edit FCLENGTH '48'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ edit MEMBER '6'
+ endfamily
+ endfamily
+ family eps_pert
+ task getae
+ defstatus complete
+ trigger ../eps_sv eq complete
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ task getsvs
+ defstatus complete
+ trigger getae eq complete
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ task ocrot
+ defstatus complete
+ trigger getsvs eq complete
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ task geticp
+ trigger ../getini eq complete
+ family pert_ic
+ inlimit /ptb/a020/coup/limits:PIC
+ trigger geticp eq complete and ocrot eq complete and ../inidata eq complete
+ edit EPSTROP '0'
+ family 000
+ edit MEMBER '0'
+ task pertinic
+ endfamily
+ family 001
+ edit MEMBER '1'
+ task pertinic
+ endfamily
+ family 002
+ edit MEMBER '2'
+ task pertinic
+ endfamily
+ family 003
+ edit MEMBER '3'
+ task pertinic
+ endfamily
+ family 004
+ edit MEMBER '4'
+ task pertinic
+ endfamily
+ family 005
+ edit MEMBER '5'
+ task pertinic
+ endfamily
+ family 006
+ edit MEMBER '6'
+ task pertinic
+ endfamily
+ family 007
+ edit MEMBER '7'
+ task pertinic
+ endfamily
+ family 008
+ edit MEMBER '8'
+ task pertinic
+ endfamily
+ family 009
+ edit MEMBER '9'
+ task pertinic
+ endfamily
+ family 010
+ edit MEMBER '10'
+ task pertinic
+ endfamily
+ family 011
+ edit MEMBER '11'
+ task pertinic
+ endfamily
+ family 012
+ edit MEMBER '12'
+ task pertinic
+ endfamily
+ family 013
+ edit MEMBER '13'
+ task pertinic
+ endfamily
+ family 014
+ edit MEMBER '14'
+ task pertinic
+ endfamily
+ family 015
+ edit MEMBER '15'
+ task pertinic
+ endfamily
+ family 016
+ edit MEMBER '16'
+ task pertinic
+ endfamily
+ family 017
+ edit MEMBER '17'
+ task pertinic
+ endfamily
+ family 018
+ edit MEMBER '18'
+ task pertinic
+ endfamily
+ family 019
+ edit MEMBER '19'
+ task pertinic
+ endfamily
+ family 020
+ edit MEMBER '20'
+ task pertinic
+ endfamily
+ family 021
+ edit MEMBER '21'
+ task pertinic
+ endfamily
+ family 022
+ edit MEMBER '22'
+ task pertinic
+ endfamily
+ family 023
+ edit MEMBER '23'
+ task pertinic
+ endfamily
+ family 024
+ edit MEMBER '24'
+ task pertinic
+ endfamily
+ family 025
+ edit MEMBER '25'
+ task pertinic
+ endfamily
+ family 026
+ edit MEMBER '26'
+ task pertinic
+ endfamily
+ family 027
+ edit MEMBER '27'
+ task pertinic
+ endfamily
+ family 028
+ edit MEMBER '28'
+ task pertinic
+ endfamily
+ family 029
+ edit MEMBER '29'
+ task pertinic
+ endfamily
+ family 030
+ edit MEMBER '30'
+ task pertinic
+ endfamily
+ family 031
+ edit MEMBER '31'
+ task pertinic
+ endfamily
+ family 032
+ edit MEMBER '32'
+ task pertinic
+ endfamily
+ family 033
+ edit MEMBER '33'
+ task pertinic
+ endfamily
+ family 034
+ edit MEMBER '34'
+ task pertinic
+ endfamily
+ family 035
+ edit MEMBER '35'
+ task pertinic
+ endfamily
+ family 036
+ edit MEMBER '36'
+ task pertinic
+ endfamily
+ family 037
+ edit MEMBER '37'
+ task pertinic
+ endfamily
+ family 038
+ edit MEMBER '38'
+ task pertinic
+ endfamily
+ family 039
+ edit MEMBER '39'
+ task pertinic
+ endfamily
+ family 040
+ edit MEMBER '40'
+ task pertinic
+ endfamily
+ family 041
+ edit MEMBER '41'
+ task pertinic
+ endfamily
+ family 042
+ edit MEMBER '42'
+ task pertinic
+ endfamily
+ family 043
+ edit MEMBER '43'
+ task pertinic
+ endfamily
+ family 044
+ edit MEMBER '44'
+ task pertinic
+ endfamily
+ family 045
+ edit MEMBER '45'
+ task pertinic
+ endfamily
+ family 046
+ edit MEMBER '46'
+ task pertinic
+ endfamily
+ family 047
+ edit MEMBER '47'
+ task pertinic
+ endfamily
+ family 048
+ edit MEMBER '48'
+ task pertinic
+ endfamily
+ family 049
+ edit MEMBER '49'
+ task pertinic
+ endfamily
+ family 050
+ edit MEMBER '50'
+ task pertinic
+ endfamily
+ endfamily
+ endfamily
+ task ocwavini
+ edit SMSTRIES '2'
+ edit MEM '300'
+ edit NPES '1'
+ edit CPUTIME '400'
+ task ocwcold
+ defstatus complete
+ trigger inidata eq complete and ocwavini eq complete and eps_pert eq complete
+ edit MEM '800'
+ edit NPES '1'
+ edit THREADS '8'
+ edit CPUTIME '2000'
+ task ocwavfcdata
+ trigger ./ocwcold eq complete and ocwavini eq complete
+ family fc0
+ edit OCFCPERT '0'
+ edit FCGROUP 'fc0'
+ edit SUBFSFAMILY '_an0_fc0'
+ task iniocean
+ trigger ( ../oceini eq complete and ( ../getini eq active or ../getini eq complete))
+ task iniatmos
+ trigger ( /ptb/a020/coup/fcdate/main/control0/inidata eq complete and /ptb/a020/coup/fcdate/main/control0/ocwavfcdata eq complete and /ptb/a020/coup/fcdate/main/control0/eps_pert eq complete)
+ edit FCCHUNK '1'
+ task cpmodel1
+ inlimit /ptb/a020/coup/limits:cpmodel
+ trigger ( iniocean eq complete and iniatmos eq complete and /ptb/a020/coup/fcdate/main/control0/inidata eq complete and /ptb/a020/coup/fcdate/main/control0/ocwavfcdata eq complete and /ptb/a020/coup/fcdate/main/control0/eps_pert eq complete)
+ edit FCCHUNKSUB '1'
+ edit MEM '1300'
+ edit NPES '1'
+ edit THREADS '8'
+ edit EC_SMT 'yes'
+ edit CPUTIME '360000'
+ meter step -1 24 24
+ task extrafields
+ trigger cpmodel1 eq complete
+ task mm_sfc
+ trigger extrafields eq complete
+ task mm_ua
+ trigger mm_sfc eq complete
+ endfamily
+ endfamily
+ family assim0
+ edit FSFAMILY 'assim'
+ edit OCGROUP 'an0'
+ edit FCTOTAL '1'
+ edit RUNCOUPLE '1'
+ edit FCLENGTH '24'
+ edit SUBFSFAMILY '_an0_fc0'
+ edit FCGROUP 'fc0'
+ task getini
+ task inidata
+ trigger getini eq complete
+ edit NPES '12'
+ edit ININPES '12'
+ edit MEM '900'
+ edit THREADS '2'
+ edit CPUTIME '1000'
+ task oceini
+ family eps_sv
+ defstatus complete
+ edit MOFCSV 'true'
+ family svevo
+ edit DELTA_DAY '-2'
+ task getini
+ edit PRIORITY '40'
+ task inidata
+ trigger getini eq complete
+ edit NPES '12'
+ edit ININPES '12'
+ edit MEM '900'
+ edit THREADS '2'
+ edit CPUTIME '1000'
+ task svnh
+ trigger inidata eq complete
+ edit FCLENGTH '48'
+ edit EPSSVDIAB '0'
+ edit EPSTROP '0'
+ edit MEMBER '0'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ task svsh
+ trigger inidata eq complete
+ edit FCLENGTH '48'
+ edit EPSSVDIAB '0'
+ edit EPSTROP '0'
+ edit MEMBER '0'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ endfamily
+ family svini
+ edit DELTA_DAY '0'
+ task getini
+ trigger ../svevo eq complete
+ edit PRIORITY '40'
+ task inidata
+ trigger getini eq complete
+ edit NPES '12'
+ edit ININPES '12'
+ edit MEM '900'
+ edit THREADS '2'
+ edit CPUTIME '1000'
+ task svnh
+ trigger inidata eq complete
+ edit FCLENGTH '48'
+ edit EPSSVDIAB '0'
+ edit EPSTROP '0'
+ edit MEMBER '0'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ task svsh
+ trigger inidata eq complete
+ edit FCLENGTH '48'
+ edit EPSSVDIAB '0'
+ edit EPSTROP '0'
+ edit MEMBER '0'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ task targets
+ trigger svsh eq complete
+ edit FCLENGTH '48'
+ task subspace
+ trigger svnh eq complete and svsh eq complete and targets eq complete
+ edit FCLENGTH '48'
+ task sv1
+ trigger targets eq complete and subspace eq complete
+ edit FCLENGTH '48'
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ edit MEMBER '1'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ task sv2
+ trigger targets eq complete and subspace eq complete
+ edit FCLENGTH '48'
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ edit MEMBER '2'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ task sv3
+ trigger sv1 eq complete and targets eq complete
+ edit FCLENGTH '48'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ edit MEMBER '3'
+ task sv4
+ trigger sv2 eq complete and targets eq complete
+ edit FCLENGTH '48'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ edit MEMBER '4'
+ task sv5
+ trigger sv3 eq complete and targets eq complete and subspace eq complete
+ edit FCLENGTH '48'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ edit MEMBER '5'
+ task sv6
+ trigger sv4 eq complete and targets eq complete and subspace eq complete
+ edit FCLENGTH '48'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ edit MEMBER '6'
+ endfamily
+ endfamily
+ family eps_pert
+ task getae
+ defstatus complete
+ trigger ../eps_sv eq complete
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ task getsvs
+ defstatus complete
+ trigger getae eq complete
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ task ocrot
+ defstatus complete
+ trigger getsvs eq complete
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ task geticp
+ trigger ../getini eq complete
+ family pert_ic
+ inlimit /ptb/a020/coup/limits:PIC
+ trigger geticp eq complete and ocrot eq complete and ../inidata eq complete
+ edit EPSTROP '0'
+ family 000
+ edit MEMBER '0'
+ task pertinic
+ endfamily
+ family 001
+ edit MEMBER '1'
+ task pertinic
+ endfamily
+ family 002
+ edit MEMBER '2'
+ task pertinic
+ endfamily
+ family 003
+ edit MEMBER '3'
+ task pertinic
+ endfamily
+ family 004
+ edit MEMBER '4'
+ task pertinic
+ endfamily
+ family 005
+ edit MEMBER '5'
+ task pertinic
+ endfamily
+ family 006
+ edit MEMBER '6'
+ task pertinic
+ endfamily
+ family 007
+ edit MEMBER '7'
+ task pertinic
+ endfamily
+ family 008
+ edit MEMBER '8'
+ task pertinic
+ endfamily
+ family 009
+ edit MEMBER '9'
+ task pertinic
+ endfamily
+ family 010
+ edit MEMBER '10'
+ task pertinic
+ endfamily
+ family 011
+ edit MEMBER '11'
+ task pertinic
+ endfamily
+ family 012
+ edit MEMBER '12'
+ task pertinic
+ endfamily
+ family 013
+ edit MEMBER '13'
+ task pertinic
+ endfamily
+ family 014
+ edit MEMBER '14'
+ task pertinic
+ endfamily
+ family 015
+ edit MEMBER '15'
+ task pertinic
+ endfamily
+ family 016
+ edit MEMBER '16'
+ task pertinic
+ endfamily
+ family 017
+ edit MEMBER '17'
+ task pertinic
+ endfamily
+ family 018
+ edit MEMBER '18'
+ task pertinic
+ endfamily
+ family 019
+ edit MEMBER '19'
+ task pertinic
+ endfamily
+ family 020
+ edit MEMBER '20'
+ task pertinic
+ endfamily
+ family 021
+ edit MEMBER '21'
+ task pertinic
+ endfamily
+ family 022
+ edit MEMBER '22'
+ task pertinic
+ endfamily
+ family 023
+ edit MEMBER '23'
+ task pertinic
+ endfamily
+ family 024
+ edit MEMBER '24'
+ task pertinic
+ endfamily
+ family 025
+ edit MEMBER '25'
+ task pertinic
+ endfamily
+ family 026
+ edit MEMBER '26'
+ task pertinic
+ endfamily
+ family 027
+ edit MEMBER '27'
+ task pertinic
+ endfamily
+ family 028
+ edit MEMBER '28'
+ task pertinic
+ endfamily
+ family 029
+ edit MEMBER '29'
+ task pertinic
+ endfamily
+ family 030
+ edit MEMBER '30'
+ task pertinic
+ endfamily
+ family 031
+ edit MEMBER '31'
+ task pertinic
+ endfamily
+ family 032
+ edit MEMBER '32'
+ task pertinic
+ endfamily
+ family 033
+ edit MEMBER '33'
+ task pertinic
+ endfamily
+ family 034
+ edit MEMBER '34'
+ task pertinic
+ endfamily
+ family 035
+ edit MEMBER '35'
+ task pertinic
+ endfamily
+ family 036
+ edit MEMBER '36'
+ task pertinic
+ endfamily
+ family 037
+ edit MEMBER '37'
+ task pertinic
+ endfamily
+ family 038
+ edit MEMBER '38'
+ task pertinic
+ endfamily
+ family 039
+ edit MEMBER '39'
+ task pertinic
+ endfamily
+ family 040
+ edit MEMBER '40'
+ task pertinic
+ endfamily
+ family 041
+ edit MEMBER '41'
+ task pertinic
+ endfamily
+ family 042
+ edit MEMBER '42'
+ task pertinic
+ endfamily
+ family 043
+ edit MEMBER '43'
+ task pertinic
+ endfamily
+ family 044
+ edit MEMBER '44'
+ task pertinic
+ endfamily
+ family 045
+ edit MEMBER '45'
+ task pertinic
+ endfamily
+ family 046
+ edit MEMBER '46'
+ task pertinic
+ endfamily
+ family 047
+ edit MEMBER '47'
+ task pertinic
+ endfamily
+ family 048
+ edit MEMBER '48'
+ task pertinic
+ endfamily
+ family 049
+ edit MEMBER '49'
+ task pertinic
+ endfamily
+ family 050
+ edit MEMBER '50'
+ task pertinic
+ endfamily
+ endfamily
+ endfamily
+ task ocwavini
+ edit SMSTRIES '2'
+ edit MEM '300'
+ edit NPES '1'
+ edit CPUTIME '400'
+ task ocwcold
+ defstatus complete
+ trigger inidata eq complete and ocwavini eq complete and eps_pert eq complete
+ edit MEM '800'
+ edit NPES '1'
+ edit THREADS '8'
+ edit CPUTIME '2000'
+ task ocwavfcdata
+ trigger ./ocwcold eq complete and ocwavini eq complete
+ family fc0
+ edit OCFCPERT '0'
+ edit FCGROUP 'fc0'
+ edit SUBFSFAMILY '_an0_fc0'
+ task iniocean
+ trigger ( ../oceini eq complete and ( ../getini eq active or ../getini eq complete))
+ task iniatmos
+ trigger ( /ptb/a020/coup/fcdate/main/assim0/inidata eq complete and /ptb/a020/coup/fcdate/main/assim0/ocwavfcdata eq complete and /ptb/a020/coup/fcdate/main/assim0/eps_pert eq complete)
+ edit FCCHUNK '1'
+ task cpmodel1
+ inlimit /ptb/a020/coup/limits:cpmodel
+ trigger ( iniocean eq complete and iniatmos eq complete and /ptb/a020/coup/fcdate/main/assim0/inidata eq complete and /ptb/a020/coup/fcdate/main/assim0/ocwavfcdata eq complete and /ptb/a020/coup/fcdate/main/assim0/eps_pert eq complete)
+ edit FCCHUNKSUB '1'
+ edit MEM '1300'
+ edit NPES '1'
+ edit THREADS '8'
+ edit EC_SMT 'yes'
+ edit CPUTIME '360000'
+ meter step -1 24 24
+ task extrafields
+ trigger cpmodel1 eq complete
+ task mm_sfc
+ trigger extrafields eq complete
+ task mm_ua
+ trigger mm_sfc eq complete
+ endfamily
+ endfamily
+ family assim1
+ edit FSFAMILY 'assim'
+ edit OCGROUP 'an1'
+ edit FCTOTAL '1'
+ edit RUNCOUPLE '1'
+ edit FCLENGTH '24'
+ edit SUBFSFAMILY '_an1_fc1'
+ edit FCGROUP 'fc1'
+ task getini
+ defstatus complete
+ task inidata
+ defstatus complete
+ trigger getini eq complete
+ edit NPES '12'
+ edit ININPES '12'
+ edit MEM '900'
+ edit THREADS '2'
+ edit CPUTIME '1000'
+ task oceini
+ family eps_sv
+ defstatus complete
+ edit MOFCSV 'true'
+ family svevo
+ edit DELTA_DAY '-2'
+ task getini
+ edit PRIORITY '40'
+ task inidata
+ trigger getini eq complete
+ edit NPES '12'
+ edit ININPES '12'
+ edit MEM '900'
+ edit THREADS '2'
+ edit CPUTIME '1000'
+ task svnh
+ trigger inidata eq complete
+ edit FCLENGTH '48'
+ edit EPSSVDIAB '0'
+ edit EPSTROP '0'
+ edit MEMBER '0'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ task svsh
+ trigger inidata eq complete
+ edit FCLENGTH '48'
+ edit EPSSVDIAB '0'
+ edit EPSTROP '0'
+ edit MEMBER '0'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ endfamily
+ family svini
+ edit DELTA_DAY '0'
+ task getini
+ trigger ../svevo eq complete
+ edit PRIORITY '40'
+ task inidata
+ trigger getini eq complete
+ edit NPES '12'
+ edit ININPES '12'
+ edit MEM '900'
+ edit THREADS '2'
+ edit CPUTIME '1000'
+ task svnh
+ trigger inidata eq complete
+ edit FCLENGTH '48'
+ edit EPSSVDIAB '0'
+ edit EPSTROP '0'
+ edit MEMBER '0'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ task svsh
+ trigger inidata eq complete
+ edit FCLENGTH '48'
+ edit EPSSVDIAB '0'
+ edit EPSTROP '0'
+ edit MEMBER '0'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ task targets
+ trigger svsh eq complete
+ edit FCLENGTH '48'
+ task subspace
+ trigger svnh eq complete and svsh eq complete and targets eq complete
+ edit FCLENGTH '48'
+ task sv1
+ trigger targets eq complete and subspace eq complete
+ edit FCLENGTH '48'
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ edit MEMBER '1'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ task sv2
+ trigger targets eq complete and subspace eq complete
+ edit FCLENGTH '48'
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ edit MEMBER '2'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ task sv3
+ trigger sv1 eq complete and targets eq complete
+ edit FCLENGTH '48'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ edit MEMBER '3'
+ task sv4
+ trigger sv2 eq complete and targets eq complete
+ edit FCLENGTH '48'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ edit MEMBER '4'
+ task sv5
+ trigger sv3 eq complete and targets eq complete and subspace eq complete
+ edit FCLENGTH '48'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ edit MEMBER '5'
+ task sv6
+ trigger sv4 eq complete and targets eq complete and subspace eq complete
+ edit FCLENGTH '48'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ edit MEMBER '6'
+ endfamily
+ endfamily
+ family eps_pert
+ defstatus complete
+ task getae
+ defstatus complete
+ trigger ../eps_sv eq complete
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ task getsvs
+ defstatus complete
+ trigger getae eq complete
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ task ocrot
+ defstatus complete
+ trigger getsvs eq complete
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ task geticp
+ trigger ../getini eq complete
+ family pert_ic
+ inlimit /ptb/a020/coup/limits:PIC
+ trigger geticp eq complete and ocrot eq complete and ../inidata eq complete
+ edit EPSTROP '0'
+ family 000
+ edit MEMBER '0'
+ task pertinic
+ endfamily
+ family 001
+ edit MEMBER '1'
+ task pertinic
+ endfamily
+ family 002
+ edit MEMBER '2'
+ task pertinic
+ endfamily
+ family 003
+ edit MEMBER '3'
+ task pertinic
+ endfamily
+ family 004
+ edit MEMBER '4'
+ task pertinic
+ endfamily
+ family 005
+ edit MEMBER '5'
+ task pertinic
+ endfamily
+ family 006
+ edit MEMBER '6'
+ task pertinic
+ endfamily
+ family 007
+ edit MEMBER '7'
+ task pertinic
+ endfamily
+ family 008
+ edit MEMBER '8'
+ task pertinic
+ endfamily
+ family 009
+ edit MEMBER '9'
+ task pertinic
+ endfamily
+ family 010
+ edit MEMBER '10'
+ task pertinic
+ endfamily
+ family 011
+ edit MEMBER '11'
+ task pertinic
+ endfamily
+ family 012
+ edit MEMBER '12'
+ task pertinic
+ endfamily
+ family 013
+ edit MEMBER '13'
+ task pertinic
+ endfamily
+ family 014
+ edit MEMBER '14'
+ task pertinic
+ endfamily
+ family 015
+ edit MEMBER '15'
+ task pertinic
+ endfamily
+ family 016
+ edit MEMBER '16'
+ task pertinic
+ endfamily
+ family 017
+ edit MEMBER '17'
+ task pertinic
+ endfamily
+ family 018
+ edit MEMBER '18'
+ task pertinic
+ endfamily
+ family 019
+ edit MEMBER '19'
+ task pertinic
+ endfamily
+ family 020
+ edit MEMBER '20'
+ task pertinic
+ endfamily
+ family 021
+ edit MEMBER '21'
+ task pertinic
+ endfamily
+ family 022
+ edit MEMBER '22'
+ task pertinic
+ endfamily
+ family 023
+ edit MEMBER '23'
+ task pertinic
+ endfamily
+ family 024
+ edit MEMBER '24'
+ task pertinic
+ endfamily
+ family 025
+ edit MEMBER '25'
+ task pertinic
+ endfamily
+ family 026
+ edit MEMBER '26'
+ task pertinic
+ endfamily
+ family 027
+ edit MEMBER '27'
+ task pertinic
+ endfamily
+ family 028
+ edit MEMBER '28'
+ task pertinic
+ endfamily
+ family 029
+ edit MEMBER '29'
+ task pertinic
+ endfamily
+ family 030
+ edit MEMBER '30'
+ task pertinic
+ endfamily
+ family 031
+ edit MEMBER '31'
+ task pertinic
+ endfamily
+ family 032
+ edit MEMBER '32'
+ task pertinic
+ endfamily
+ family 033
+ edit MEMBER '33'
+ task pertinic
+ endfamily
+ family 034
+ edit MEMBER '34'
+ task pertinic
+ endfamily
+ family 035
+ edit MEMBER '35'
+ task pertinic
+ endfamily
+ family 036
+ edit MEMBER '36'
+ task pertinic
+ endfamily
+ family 037
+ edit MEMBER '37'
+ task pertinic
+ endfamily
+ family 038
+ edit MEMBER '38'
+ task pertinic
+ endfamily
+ family 039
+ edit MEMBER '39'
+ task pertinic
+ endfamily
+ family 040
+ edit MEMBER '40'
+ task pertinic
+ endfamily
+ family 041
+ edit MEMBER '41'
+ task pertinic
+ endfamily
+ family 042
+ edit MEMBER '42'
+ task pertinic
+ endfamily
+ family 043
+ edit MEMBER '43'
+ task pertinic
+ endfamily
+ family 044
+ edit MEMBER '44'
+ task pertinic
+ endfamily
+ family 045
+ edit MEMBER '45'
+ task pertinic
+ endfamily
+ family 046
+ edit MEMBER '46'
+ task pertinic
+ endfamily
+ family 047
+ edit MEMBER '47'
+ task pertinic
+ endfamily
+ family 048
+ edit MEMBER '48'
+ task pertinic
+ endfamily
+ family 049
+ edit MEMBER '49'
+ task pertinic
+ endfamily
+ family 050
+ edit MEMBER '50'
+ task pertinic
+ endfamily
+ endfamily
+ endfamily
+ task ocwavini
+ defstatus complete
+ edit SMSTRIES '2'
+ edit MEM '300'
+ edit NPES '1'
+ edit CPUTIME '400'
+ task ocwcold
+ defstatus complete
+ trigger inidata eq complete and ocwavini eq complete and eps_pert eq complete
+ edit MEM '800'
+ edit NPES '1'
+ edit THREADS '8'
+ edit CPUTIME '2000'
+ task ocwavfcdata
+ defstatus complete
+ trigger ./ocwcold eq complete and ocwavini eq complete
+ family fc1
+ edit OCFCPERT '1'
+ edit FCGROUP 'fc1'
+ edit SUBFSFAMILY '_an1_fc1'
+ task iniocean
+ trigger ( ../oceini eq complete and ( ../getini eq active or ../getini eq complete))
+ task iniatmos
+ trigger ( /ptb/a020/coup/fcdate/main/assim0/inidata eq complete and /ptb/a020/coup/fcdate/main/assim0/ocwavfcdata eq complete and /ptb/a020/coup/fcdate/main/assim0/eps_pert eq complete)
+ edit FCCHUNK '1'
+ task cpmodel1
+ inlimit /ptb/a020/coup/limits:cpmodel
+ trigger ( iniocean eq complete and iniatmos eq complete and /ptb/a020/coup/fcdate/main/assim0/inidata eq complete and /ptb/a020/coup/fcdate/main/assim0/ocwavfcdata eq complete and /ptb/a020/coup/fcdate/main/assim0/eps_pert eq complete)
+ edit FCCHUNKSUB '1'
+ edit MEM '1300'
+ edit NPES '1'
+ edit THREADS '8'
+ edit EC_SMT 'yes'
+ edit CPUTIME '360000'
+ meter step -1 24 24
+ task extrafields
+ trigger cpmodel1 eq complete
+ task mm_sfc
+ trigger extrafields eq complete
+ task mm_ua
+ trigger mm_sfc eq complete
+ endfamily
+ endfamily
+ family assim2
+ edit FSFAMILY 'assim'
+ edit OCGROUP 'an2'
+ edit FCTOTAL '1'
+ edit RUNCOUPLE '1'
+ edit FCLENGTH '24'
+ edit SUBFSFAMILY '_an2_fc2'
+ edit FCGROUP 'fc2'
+ task getini
+ defstatus complete
+ task inidata
+ defstatus complete
+ trigger getini eq complete
+ edit NPES '12'
+ edit ININPES '12'
+ edit MEM '900'
+ edit THREADS '2'
+ edit CPUTIME '1000'
+ task oceini
+ family eps_sv
+ defstatus complete
+ edit MOFCSV 'true'
+ family svevo
+ edit DELTA_DAY '-2'
+ task getini
+ edit PRIORITY '40'
+ task inidata
+ trigger getini eq complete
+ edit NPES '12'
+ edit ININPES '12'
+ edit MEM '900'
+ edit THREADS '2'
+ edit CPUTIME '1000'
+ task svnh
+ trigger inidata eq complete
+ edit FCLENGTH '48'
+ edit EPSSVDIAB '0'
+ edit EPSTROP '0'
+ edit MEMBER '0'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ task svsh
+ trigger inidata eq complete
+ edit FCLENGTH '48'
+ edit EPSSVDIAB '0'
+ edit EPSTROP '0'
+ edit MEMBER '0'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ endfamily
+ family svini
+ edit DELTA_DAY '0'
+ task getini
+ trigger ../svevo eq complete
+ edit PRIORITY '40'
+ task inidata
+ trigger getini eq complete
+ edit NPES '12'
+ edit ININPES '12'
+ edit MEM '900'
+ edit THREADS '2'
+ edit CPUTIME '1000'
+ task svnh
+ trigger inidata eq complete
+ edit FCLENGTH '48'
+ edit EPSSVDIAB '0'
+ edit EPSTROP '0'
+ edit MEMBER '0'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ task svsh
+ trigger inidata eq complete
+ edit FCLENGTH '48'
+ edit EPSSVDIAB '0'
+ edit EPSTROP '0'
+ edit MEMBER '0'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ task targets
+ trigger svsh eq complete
+ edit FCLENGTH '48'
+ task subspace
+ trigger svnh eq complete and svsh eq complete and targets eq complete
+ edit FCLENGTH '48'
+ task sv1
+ trigger targets eq complete and subspace eq complete
+ edit FCLENGTH '48'
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ edit MEMBER '1'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ task sv2
+ trigger targets eq complete and subspace eq complete
+ edit FCLENGTH '48'
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ edit MEMBER '2'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ task sv3
+ trigger sv1 eq complete and targets eq complete
+ edit FCLENGTH '48'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ edit MEMBER '3'
+ task sv4
+ trigger sv2 eq complete and targets eq complete
+ edit FCLENGTH '48'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ edit MEMBER '4'
+ task sv5
+ trigger sv3 eq complete and targets eq complete and subspace eq complete
+ edit FCLENGTH '48'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ edit MEMBER '5'
+ task sv6
+ trigger sv4 eq complete and targets eq complete and subspace eq complete
+ edit FCLENGTH '48'
+ edit MEM '1600'
+ edit NPES '8'
+ edit THREADS '4'
+ edit CPUTIME '16000'
+ edit EC_SMT 'no'
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ edit MEMBER '6'
+ endfamily
+ endfamily
+ family eps_pert
+ defstatus complete
+ task getae
+ defstatus complete
+ trigger ../eps_sv eq complete
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ task getsvs
+ defstatus complete
+ trigger getae eq complete
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ task ocrot
+ defstatus complete
+ trigger getsvs eq complete
+ edit EPSSVDIAB 'true'
+ edit EPSTROP '1'
+ task geticp
+ trigger ../getini eq complete
+ family pert_ic
+ inlimit /ptb/a020/coup/limits:PIC
+ trigger geticp eq complete and ocrot eq complete and ../inidata eq complete
+ edit EPSTROP '0'
+ family 000
+ edit MEMBER '0'
+ task pertinic
+ endfamily
+ family 001
+ edit MEMBER '1'
+ task pertinic
+ endfamily
+ family 002
+ edit MEMBER '2'
+ task pertinic
+ endfamily
+ family 003
+ edit MEMBER '3'
+ task pertinic
+ endfamily
+ family 004
+ edit MEMBER '4'
+ task pertinic
+ endfamily
+ family 005
+ edit MEMBER '5'
+ task pertinic
+ endfamily
+ family 006
+ edit MEMBER '6'
+ task pertinic
+ endfamily
+ family 007
+ edit MEMBER '7'
+ task pertinic
+ endfamily
+ family 008
+ edit MEMBER '8'
+ task pertinic
+ endfamily
+ family 009
+ edit MEMBER '9'
+ task pertinic
+ endfamily
+ family 010
+ edit MEMBER '10'
+ task pertinic
+ endfamily
+ family 011
+ edit MEMBER '11'
+ task pertinic
+ endfamily
+ family 012
+ edit MEMBER '12'
+ task pertinic
+ endfamily
+ family 013
+ edit MEMBER '13'
+ task pertinic
+ endfamily
+ family 014
+ edit MEMBER '14'
+ task pertinic
+ endfamily
+ family 015
+ edit MEMBER '15'
+ task pertinic
+ endfamily
+ family 016
+ edit MEMBER '16'
+ task pertinic
+ endfamily
+ family 017
+ edit MEMBER '17'
+ task pertinic
+ endfamily
+ family 018
+ edit MEMBER '18'
+ task pertinic
+ endfamily
+ family 019
+ edit MEMBER '19'
+ task pertinic
+ endfamily
+ family 020
+ edit MEMBER '20'
+ task pertinic
+ endfamily
+ family 021
+ edit MEMBER '21'
+ task pertinic
+ endfamily
+ family 022
+ edit MEMBER '22'
+ task pertinic
+ endfamily
+ family 023
+ edit MEMBER '23'
+ task pertinic
+ endfamily
+ family 024
+ edit MEMBER '24'
+ task pertinic
+ endfamily
+ family 025
+ edit MEMBER '25'
+ task pertinic
+ endfamily
+ family 026
+ edit MEMBER '26'
+ task pertinic
+ endfamily
+ family 027
+ edit MEMBER '27'
+ task pertinic
+ endfamily
+ family 028
+ edit MEMBER '28'
+ task pertinic
+ endfamily
+ family 029
+ edit MEMBER '29'
+ task pertinic
+ endfamily
+ family 030
+ edit MEMBER '30'
+ task pertinic
+ endfamily
+ family 031
+ edit MEMBER '31'
+ task pertinic
+ endfamily
+ family 032
+ edit MEMBER '32'
+ task pertinic
+ endfamily
+ family 033
+ edit MEMBER '33'
+ task pertinic
+ endfamily
+ family 034
+ edit MEMBER '34'
+ task pertinic
+ endfamily
+ family 035
+ edit MEMBER '35'
+ task pertinic
+ endfamily
+ family 036
+ edit MEMBER '36'
+ task pertinic
+ endfamily
+ family 037
+ edit MEMBER '37'
+ task pertinic
+ endfamily
+ family 038
+ edit MEMBER '38'
+ task pertinic
+ endfamily
+ family 039
+ edit MEMBER '39'
+ task pertinic
+ endfamily
+ family 040
+ edit MEMBER '40'
+ task pertinic
+ endfamily
+ family 041
+ edit MEMBER '41'
+ task pertinic
+ endfamily
+ family 042
+ edit MEMBER '42'
+ task pertinic
+ endfamily
+ family 043
+ edit MEMBER '43'
+ task pertinic
+ endfamily
+ family 044
+ edit MEMBER '44'
+ task pertinic
+ endfamily
+ family 045
+ edit MEMBER '45'
+ task pertinic
+ endfamily
+ family 046
+ edit MEMBER '46'
+ task pertinic
+ endfamily
+ family 047
+ edit MEMBER '47'
+ task pertinic
+ endfamily
+ family 048
+ edit MEMBER '48'
+ task pertinic
+ endfamily
+ family 049
+ edit MEMBER '49'
+ task pertinic
+ endfamily
+ family 050
+ edit MEMBER '50'
+ task pertinic
+ endfamily
+ endfamily
+ endfamily
+ task ocwavini
+ defstatus complete
+ edit SMSTRIES '2'
+ edit MEM '300'
+ edit NPES '1'
+ edit CPUTIME '400'
+ task ocwcold
+ defstatus complete
+ trigger inidata eq complete and ocwavini eq complete and eps_pert eq complete
+ edit MEM '800'
+ edit NPES '1'
+ edit THREADS '8'
+ edit CPUTIME '2000'
+ task ocwavfcdata
+ defstatus complete
+ trigger ./ocwcold eq complete and ocwavini eq complete
+ family fc2
+ edit OCFCPERT '2'
+ edit FCGROUP 'fc2'
+ edit SUBFSFAMILY '_an2_fc2'
+ task iniocean
+ trigger ( ../oceini eq complete and ( ../getini eq active or ../getini eq complete))
+ task iniatmos
+ trigger ( /ptb/a020/coup/fcdate/main/assim0/inidata eq complete and /ptb/a020/coup/fcdate/main/assim0/ocwavfcdata eq complete and /ptb/a020/coup/fcdate/main/assim0/eps_pert eq complete)
+ edit FCCHUNK '1'
+ task cpmodel1
+ inlimit /ptb/a020/coup/limits:cpmodel
+ trigger ( iniocean eq complete and iniatmos eq complete and /ptb/a020/coup/fcdate/main/assim0/inidata eq complete and /ptb/a020/coup/fcdate/main/assim0/ocwavfcdata eq complete and /ptb/a020/coup/fcdate/main/assim0/eps_pert eq complete)
+ edit FCCHUNKSUB '1'
+ edit MEM '1300'
+ edit NPES '1'
+ edit THREADS '8'
+ edit EC_SMT 'yes'
+ edit CPUTIME '360000'
+ meter step -1 24 24
+ task extrafields
+ trigger cpmodel1 eq complete
+ task mm_sfc
+ trigger extrafields eq complete
+ task mm_ua
+ trigger mm_sfc eq complete
+ endfamily
+ endfamily
+ task logfiles
+ trigger control0 eq complete and assim0 eq complete and assim1 eq complete and assim2 eq complete
+ edit SMSCMD 'smssubmit.x %SMSJOB% %SCHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %SCHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %SCHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/hpce/rdx_dir/msx'
+ edit MOVE_TO_ECFS 'no'
+ endfamily
+ family lag
+ repeat enumerated YMD "19690101" "19690102" # status 19690102
+ edit LOGTASK 'fcdate/lag'
+ family control0
+ defstatus complete
+ edit FSFAMILY 'control'
+ edit OCTOTAL '1'
+ edit OCGROUP 'an0'
+ edit FCTOTAL '1'
+ edit RUNCOUPLE '1'
+ edit FCLENGTH '24'
+ edit FCGROUP 'fc0'
+ edit RUNFC '0'
+ family archive
+ inlimit /ptb/a020/coup/limits:mars
+ edit OCNEWPERTORDER 'yes'
+ edit FCGROUP 'fc0'
+ edit FCCHUNK '1'
+ task preparcoup
+ trigger ( /ptb/a020/coup/fcdate/main:YMD gt /ptb/a020/coup/fcdate/lag:YMD) or ( /ptb/a020/coup/fcdate/main:YMD eq /ptb/a020/coup/fcdate/lag:YMD and ( ( /ptb/a020/coup/fcdate/main/control0/fc0 eq complete)))
+ task arcfc
+ trigger preparcoup eq complete
+ event fdb
+ label files ""
+ task sfc_arc
+ trigger preparcoup eq complete
+ event fdb
+ label files ""
+ task ua_arc
+ trigger preparcoup eq complete
+ event fdb
+ label files ""
+ task mm_sfc_arc
+ trigger preparcoup eq complete
+ event fdb
+ label files ""
+ task mm_ua_arc
+ trigger preparcoup eq complete
+ event fdb
+ label files ""
+ endfamily
+ family restarts
+ trigger archive eq complete
+ edit FCCHUNKSUB '1'
+ family fc0
+ edit OCFCPERT '0'
+ edit FCGROUP 'fc0'
+ task saverestarts
+ endfamily
+ endfamily
+ task ocflush
+ trigger archive eq complete and restarts eq complete
+ family process
+ family fc0
+ trigger ( /ptb/a020/coup/fcdate/main:YMD gt /ptb/a020/coup/fcdate/lag:YMD) or ( /ptb/a020/coup/fcdate/main:YMD eq /ptb/a020/coup/fcdate/lag:YMD and /ptb/a020/coup/fcdate/main/control0/fc0 eq complete)
+ edit OCFCPERT '0'
+ edit FCGROUP 'fc0'
+ task nino_oc
+ edit SMSCMD 'smssubmit.x %SMSJOB% %WSHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %WSHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %WSHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/vol/msexplog/outputs'
+ edit QUEUE 'expsms'
+ task nino_daily
+ trigger nino_oc eq complete
+ edit SMSCMD 'smssubmit.x %SMSJOB% %WSHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %WSHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %WSHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/vol/msexplog/outputs'
+ edit QUEUE 'expsms'
+ task nino_atmos
+ trigger nino_daily eq complete
+ edit SMSCMD 'smssubmit.x %SMSJOB% %WSHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %WSHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %WSHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/vol/msexplog/outputs'
+ edit QUEUE 'expsms'
+ task tcyc
+ trigger ../../archive eq complete
+ edit SMSCMD 'smssubmit.x %SMSJOB% %WSHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %WSHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %WSHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/vol/msexplog/outputs'
+ edit QUEUE 'expsms'
+ endfamily
+ endfamily
+ endfamily
+ family assim0
+ edit FSFAMILY 'assim'
+ edit OCGROUP 'an0'
+ edit FCTOTAL '1'
+ edit RUNCOUPLE '1'
+ edit FCLENGTH '24'
+ edit FCGROUP 'fc0'
+ edit RUNFC '0'
+ family archive
+ inlimit /ptb/a020/coup/limits:mars
+ edit OCNEWPERTORDER 'yes'
+ edit FCGROUP 'fc0'
+ edit FCCHUNK '1'
+ task preparcoup
+ trigger ( /ptb/a020/coup/fcdate/main:YMD gt /ptb/a020/coup/fcdate/lag:YMD) or ( /ptb/a020/coup/fcdate/main:YMD eq /ptb/a020/coup/fcdate/lag:YMD and ( ( /ptb/a020/coup/fcdate/main/assim0/fc0 eq complete)))
+ task arcfc
+ trigger preparcoup eq complete
+ event fdb
+ label files ""
+ task sfc_arc
+ trigger preparcoup eq complete
+ event fdb
+ label files ""
+ task ua_arc
+ trigger preparcoup eq complete
+ event fdb
+ label files ""
+ task mm_sfc_arc
+ trigger preparcoup eq complete
+ event fdb
+ label files ""
+ task mm_ua_arc
+ trigger preparcoup eq complete
+ event fdb
+ label files ""
+ endfamily
+ family restarts
+ trigger archive eq complete
+ edit FCCHUNKSUB '1'
+ family fc0
+ edit OCFCPERT '0'
+ edit FCGROUP 'fc0'
+ task saverestarts
+ endfamily
+ endfamily
+ task ocflush
+ trigger archive eq complete and restarts eq complete
+ family process
+ family fc0
+ trigger ( /ptb/a020/coup/fcdate/main:YMD gt /ptb/a020/coup/fcdate/lag:YMD) or ( /ptb/a020/coup/fcdate/main:YMD eq /ptb/a020/coup/fcdate/lag:YMD and /ptb/a020/coup/fcdate/main/assim0/fc0 eq complete)
+ edit OCFCPERT '0'
+ edit FCGROUP 'fc0'
+ task nino_oc
+ edit SMSCMD 'smssubmit.x %SMSJOB% %WSHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %WSHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %WSHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/vol/msexplog/outputs'
+ edit QUEUE 'expsms'
+ task nino_daily
+ trigger nino_oc eq complete
+ edit SMSCMD 'smssubmit.x %SMSJOB% %WSHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %WSHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %WSHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/vol/msexplog/outputs'
+ edit QUEUE 'expsms'
+ task nino_atmos
+ trigger nino_daily eq complete
+ edit SMSCMD 'smssubmit.x %SMSJOB% %WSHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %WSHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %WSHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/vol/msexplog/outputs'
+ edit QUEUE 'expsms'
+ task tcyc
+ trigger ../../archive eq complete
+ edit SMSCMD 'smssubmit.x %SMSJOB% %WSHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %WSHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %WSHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/vol/msexplog/outputs'
+ edit QUEUE 'expsms'
+ endfamily
+ endfamily
+ endfamily
+ family assim1
+ edit FSFAMILY 'assim'
+ edit OCGROUP 'an1'
+ edit FCTOTAL '1'
+ edit RUNCOUPLE '1'
+ edit FCLENGTH '24'
+ edit FCGROUP 'fc1'
+ edit RUNFC '0'
+ family archive
+ inlimit /ptb/a020/coup/limits:mars
+ edit OCNEWPERTORDER 'yes'
+ edit FCGROUP 'fc1'
+ edit FCCHUNK '1'
+ task preparcoup
+ trigger ( /ptb/a020/coup/fcdate/main:YMD gt /ptb/a020/coup/fcdate/lag:YMD) or ( /ptb/a020/coup/fcdate/main:YMD eq /ptb/a020/coup/fcdate/lag:YMD and ( ( /ptb/a020/coup/fcdate/main/assim1/fc1 eq complete)))
+ task arcfc
+ trigger preparcoup eq complete
+ event fdb
+ label files ""
+ task sfc_arc
+ trigger preparcoup eq complete
+ event fdb
+ label files ""
+ task ua_arc
+ trigger preparcoup eq complete
+ event fdb
+ label files ""
+ task mm_sfc_arc
+ trigger preparcoup eq complete
+ event fdb
+ label files ""
+ task mm_ua_arc
+ trigger preparcoup eq complete
+ event fdb
+ label files ""
+ endfamily
+ family restarts
+ trigger archive eq complete
+ edit FCCHUNKSUB '1'
+ family fc1
+ edit OCFCPERT '1'
+ edit FCGROUP 'fc1'
+ task saverestarts
+ endfamily
+ endfamily
+ task ocflush
+ trigger archive eq complete and restarts eq complete
+ family process
+ family fc1
+ trigger ( /ptb/a020/coup/fcdate/main:YMD gt /ptb/a020/coup/fcdate/lag:YMD) or ( /ptb/a020/coup/fcdate/main:YMD eq /ptb/a020/coup/fcdate/lag:YMD and /ptb/a020/coup/fcdate/main/assim1/fc1 eq complete)
+ edit OCFCPERT '1'
+ edit FCGROUP 'fc1'
+ task nino_oc
+ edit SMSCMD 'smssubmit.x %SMSJOB% %WSHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %WSHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %WSHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/vol/msexplog/outputs'
+ edit QUEUE 'expsms'
+ task nino_daily
+ trigger nino_oc eq complete
+ edit SMSCMD 'smssubmit.x %SMSJOB% %WSHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %WSHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %WSHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/vol/msexplog/outputs'
+ edit QUEUE 'expsms'
+ task nino_atmos
+ trigger nino_daily eq complete
+ edit SMSCMD 'smssubmit.x %SMSJOB% %WSHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %WSHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %WSHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/vol/msexplog/outputs'
+ edit QUEUE 'expsms'
+ task tcyc
+ trigger ../../archive eq complete
+ edit SMSCMD 'smssubmit.x %SMSJOB% %WSHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %WSHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %WSHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/vol/msexplog/outputs'
+ edit QUEUE 'expsms'
+ endfamily
+ endfamily
+ endfamily
+ family assim2
+ edit FSFAMILY 'assim'
+ edit OCGROUP 'an2'
+ edit FCTOTAL '1'
+ edit RUNCOUPLE '1'
+ edit FCLENGTH '24'
+ edit FCGROUP 'fc2'
+ edit RUNFC '0'
+ family archive
+ inlimit /ptb/a020/coup/limits:mars
+ edit OCNEWPERTORDER 'yes'
+ edit FCGROUP 'fc2'
+ edit FCCHUNK '1'
+ task preparcoup
+ trigger ( /ptb/a020/coup/fcdate/main:YMD gt /ptb/a020/coup/fcdate/lag:YMD) or ( /ptb/a020/coup/fcdate/main:YMD eq /ptb/a020/coup/fcdate/lag:YMD and ( ( /ptb/a020/coup/fcdate/main/assim2/fc2 eq complete)))
+ task arcfc
+ trigger preparcoup eq complete
+ event fdb
+ label files ""
+ task sfc_arc
+ trigger preparcoup eq complete
+ event fdb
+ label files ""
+ task ua_arc
+ trigger preparcoup eq complete
+ event fdb
+ label files ""
+ task mm_sfc_arc
+ trigger preparcoup eq complete
+ event fdb
+ label files ""
+ task mm_ua_arc
+ trigger preparcoup eq complete
+ event fdb
+ label files ""
+ endfamily
+ family restarts
+ trigger archive eq complete
+ edit FCCHUNKSUB '1'
+ family fc2
+ edit OCFCPERT '2'
+ edit FCGROUP 'fc2'
+ task saverestarts
+ endfamily
+ endfamily
+ task ocflush
+ trigger archive eq complete and restarts eq complete
+ family process
+ family fc2
+ trigger ( /ptb/a020/coup/fcdate/main:YMD gt /ptb/a020/coup/fcdate/lag:YMD) or ( /ptb/a020/coup/fcdate/main:YMD eq /ptb/a020/coup/fcdate/lag:YMD and /ptb/a020/coup/fcdate/main/assim2/fc2 eq complete)
+ edit OCFCPERT '2'
+ edit FCGROUP 'fc2'
+ task nino_oc
+ edit SMSCMD 'smssubmit.x %SMSJOB% %WSHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %WSHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %WSHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/vol/msexplog/outputs'
+ edit QUEUE 'expsms'
+ task nino_daily
+ trigger nino_oc eq complete
+ edit SMSCMD 'smssubmit.x %SMSJOB% %WSHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %WSHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %WSHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/vol/msexplog/outputs'
+ edit QUEUE 'expsms'
+ task nino_atmos
+ trigger nino_daily eq complete
+ edit SMSCMD 'smssubmit.x %SMSJOB% %WSHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %WSHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %WSHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/vol/msexplog/outputs'
+ edit QUEUE 'expsms'
+ task tcyc
+ trigger ../../archive eq complete
+ edit SMSCMD 'smssubmit.x %SMSJOB% %WSHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %WSHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %WSHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/vol/msexplog/outputs'
+ edit QUEUE 'expsms'
+ endfamily
+ endfamily
+ endfamily
+ task logfiles
+ trigger control0 eq complete and assim0 eq complete and assim1 eq complete and assim2 eq complete
+ edit SMSCMD 'smssubmit.x %SMSJOB% %SCHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %SCHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %SCHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/hpce/rdx_dir/msx'
+ edit MOVE_TO_ECFS 'no'
+ endfamily
+ family clean
+ repeat enumerated YMD "19690101" "19690102" # status 19690102
+ edit LOGTASK 'fcdate/clean'
+ family control0
+ defstatus complete
+ edit FSFAMILY 'control'
+ edit OCTOTAL '1'
+ edit OCGROUP 'an0'
+ edit RUNCOUPLE '1'
+ edit FCTOTAL '1'
+ edit FCTOT '1'
+ family fc0
+ edit OCFCPERT '0'
+ edit FCGROUP 'fc0'
+ edit FCCHUNK '1'
+ task saveoce
+ trigger ( ( ( /ptb/a020/coup/fcdate/lag:YMD gt /ptb/a020/coup/fcdate/clean:YMD) or ( /ptb/a020/coup/fcdate/lag:YMD eq /ptb/a020/coup/fcdate/clean:YMD and ( /ptb/a020/coup/fcdate/lag/control0 eq complete) and ( /ptb/a020/coup/fcdate/main/control0 eq complete))))
+ task occleanfdb
+ inlimit /ptb/a020/coup/limits:fdbclean
+ trigger saveoce eq complete
+ edit ICPDATA '1'
+ task occleanfdbicp
+ inlimit /ptb/a020/coup/limits:fdbclean
+ trigger occleanfdb eq complete
+ task occleandirs
+ trigger occleanfdb eq complete and occleanfdbicp eq complete
+ endfamily
+ endfamily
+ family assim0
+ edit FSFAMILY 'assim'
+ edit OCGROUP 'an0'
+ edit RUNCOUPLE '1'
+ edit FCTOTAL '1'
+ edit FCTOT '3'
+ family fc0
+ edit OCFCPERT '0'
+ edit FCGROUP 'fc0'
+ edit FCCHUNK '1'
+ task saveoce
+ trigger ( ( ( /ptb/a020/coup/fcdate/lag:YMD gt /ptb/a020/coup/fcdate/clean:YMD) or ( /ptb/a020/coup/fcdate/lag:YMD eq /ptb/a020/coup/fcdate/clean:YMD and ( /ptb/a020/coup/fcdate/lag/assim0 eq complete) and ( /ptb/a020/coup/fcdate/main/assim0 eq complete))))
+ task occleanfdb
+ inlimit /ptb/a020/coup/limits:fdbclean
+ trigger saveoce eq complete
+ edit ICPDATA '1'
+ task occleanfdbicp
+ inlimit /ptb/a020/coup/limits:fdbclean
+ trigger occleanfdb eq complete and ../../assim1 eq complete and ../../assim2 eq complete
+ task occleandirs
+ trigger occleanfdb eq complete and ../../assim1 eq complete and ../../assim2 eq complete and occleanfdbicp eq complete
+ endfamily
+ endfamily
+ family assim1
+ edit FSFAMILY 'assim'
+ edit OCGROUP 'an1'
+ edit RUNCOUPLE '1'
+ edit FCTOTAL '1'
+ edit FCTOT '3'
+ family fc1
+ edit OCFCPERT '1'
+ edit FCGROUP 'fc1'
+ edit FCCHUNK '1'
+ task saveoce
+ trigger ( ( ( /ptb/a020/coup/fcdate/lag:YMD gt /ptb/a020/coup/fcdate/clean:YMD) or ( /ptb/a020/coup/fcdate/lag:YMD eq /ptb/a020/coup/fcdate/clean:YMD and ( /ptb/a020/coup/fcdate/lag/assim1 eq complete) and ( /ptb/a020/coup/fcdate/main/assim1 eq complete))))
+ task occleanfdb
+ inlimit /ptb/a020/coup/limits:fdbclean
+ trigger saveoce eq complete
+ edit ICPDATA '1'
+ task occleanfdbicp
+ defstatus complete
+ inlimit /ptb/a020/coup/limits:fdbclean
+ trigger occleanfdb eq complete
+ task occleandirs
+ trigger occleanfdb eq complete and occleanfdbicp eq complete
+ endfamily
+ endfamily
+ family assim2
+ edit FSFAMILY 'assim'
+ edit OCGROUP 'an2'
+ edit RUNCOUPLE '1'
+ edit FCTOTAL '1'
+ edit FCTOT '3'
+ family fc2
+ edit OCFCPERT '2'
+ edit FCGROUP 'fc2'
+ edit FCCHUNK '1'
+ task saveoce
+ trigger ( ( ( /ptb/a020/coup/fcdate/lag:YMD gt /ptb/a020/coup/fcdate/clean:YMD) or ( /ptb/a020/coup/fcdate/lag:YMD eq /ptb/a020/coup/fcdate/clean:YMD and ( /ptb/a020/coup/fcdate/lag/assim2 eq complete) and ( /ptb/a020/coup/fcdate/main/assim2 eq complete))))
+ task occleanfdb
+ inlimit /ptb/a020/coup/limits:fdbclean
+ trigger saveoce eq complete
+ edit ICPDATA '1'
+ task occleanfdbicp
+ defstatus complete
+ inlimit /ptb/a020/coup/limits:fdbclean
+ trigger occleanfdb eq complete
+ task occleandirs
+ trigger occleanfdb eq complete and occleanfdbicp eq complete
+ endfamily
+ endfamily
+ task logfiles
+ trigger control0 eq complete and assim0 eq complete and assim1 eq complete and assim2 eq complete
+ edit SMSCMD 'smssubmit.x %SMSJOB% %SCHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %SCHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %SCHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/hpce/rdx_dir/msx'
+ edit MOVE_TO_ECFS 'no'
+ endfamily
+ endfamily
+ endfamily
+ task wipefdb
+ trigger ( an eq complete or an eq unknown) and ( fc eq complete or fc eq unknown) and ( eps_sv eq complete or eps_sv eq unknown) and ( eps_fc eq complete or eps_fc eq unknown) and ( eps_varfc eq complete or eps_varfc eq unknown) and ( oceatm eq complete or oceatm eq unknown) and ( oce eq complete or oce eq unknown) and ( fpos eq complete or fpos eq unknown) and ( sens eq complete or sens eq unknown) and ( wam eq complete or wam eq unknown) and ( oc eq complete or oc eq u [...]
+ edit YMD '19900101'
+ edit HOUR '00'
+ edit FSFAMILY 'cancel'
+ task cancel
+ trigger ( an eq complete or an eq unknown) and ( fc eq complete or fc eq unknown) and ( eps_sv eq complete or eps_sv eq unknown) and ( eps_fc eq complete or eps_fc eq unknown) and ( eps_varfc eq complete or eps_varfc eq unknown) and ( oceatm eq complete or oceatm eq unknown) and ( oce eq complete or oce eq unknown) and ( fpos eq complete or fpos eq unknown) and ( sens eq complete or sens eq unknown) and ( wam eq complete or wam eq unknown) and ( oc eq complete or oc eq u [...]
+ edit YMD '19900101'
+ edit HOUR '00'
+ edit FSFAMILY 'cancel'
+ edit SMSCMD 'smssubmit.x %SMSJOB% %WSHOST% %USER%'
+ edit SMSKILL 'smskill %USER% %WSHOST% %SMSRID% %SMSJOB%'
+ edit SMSSTATUSCMD 'smscheck %WSHOST% %EXPVER% %SMSJOB%'
+ edit LOGDIR '/vol/msexplog/outputs'
+ edit QUEUE 'expsms'
+ endfamily
+endsuite
+#============================================================
diff --git a/CSim/test/data/good_defs/operations/xpt.def.log b/CSim/test/data/good_defs/operations/xpt.def.log
new file mode 100644
index 0000000..28b5b29
--- /dev/null
+++ b/CSim/test/data/good_defs/operations/xpt.def.log
@@ -0,0 +1,4946 @@
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/setup
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/libs/p4setup_ifs
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/libs/p4diff_ifs
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/libs/compile
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/ifsaux
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/libs/compile/ifsaux/libifsaux
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/ifsaux
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/ifsaux/libifsaux
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/surf
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/libs/compile/surf/libsurf
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/surf
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/surf/libsurf
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/trans
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/libs/compile/trans/libtrans
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/trans
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/trans/libtrans
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/ifs
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/libs/compile/ifs/libifs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/ifs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/ifs/libifs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/wam
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/libs/compile/wam/libwam
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/wam
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/wam/libwam
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/libs/compile/odb/compiler
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/libs/compile/odb/compiler/libodbsqlcompiler
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/libs/compile/odb/databases
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/libs/compile/odb/databases/CCMA
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/libs/compile/odb/databases/CCMA/libCCMA
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/libs/compile/odb/databases/ECMA
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/libs/compile/odb/databases/ECMA/libECMA
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/libs/compile/odb/corelibs
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/libs/compile/odb/corelibs/odb
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/libs/compile/odb/corelibs/odb/libodb
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/libs/compile/odb/corelibs/odbdummy
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/libs/compile/odb/corelibs/odbdummy/libodbdummy
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/libs/compile/odb/corelibs/odbmain
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/libs/compile/odb/corelibs/odbmain/libodbmain
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/libs/compile/odb/corelibs/odbport
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/libs/compile/odb/corelibs/odbport/libodbport
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/compiler
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/compiler/libodbsqlcompiler
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/databases
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/databases/CCMA
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/databases/CCMA/libCCMA
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/databases/ECMA
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/databases/ECMA/libECMA
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/corelibs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/corelibs/odb
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/corelibs/odb/libodb
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/corelibs/odbdummy
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/corelibs/odbdummy/libodbdummy
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/corelibs/odbmain
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/corelibs/odbmain/libodbmain
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/corelibs/odbport
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/corelibs/odbport/libodbport
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/ssa
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/libs/compile/ssa/libssa
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/ssa
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/ssa/libssa
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/obstat
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/libs/compile/obstat/libobstat
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/obstat
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/obstat/libobstat
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/bl
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/libs/compile/bl/libbl95
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/bl
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/bl/libbl95
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/scat
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/libs/compile/scat/libscat
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/scat
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/scat/libscat
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/satrad
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/libs/compile/satrad/libsatrad
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/satrad
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/satrad/libsatrad
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/aeolus
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/libs/compile/aeolus/libaeolus
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/aeolus
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/aeolus/libaeolus
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/prepdata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/libs/compile/prepdata/libprepdata
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/prepdata
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/prepdata/libprepdata
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/p4setup_ifs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/p4diff_ifs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/ifsaux
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/ifsaux/libifsaux
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/surf
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/surf/libsurf
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/trans
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/trans/libtrans
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/ifs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/ifs/libifs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/wam
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/wam/libwam
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/compiler
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/compiler/libodbsqlcompiler
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/databases
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/databases/CCMA
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/databases/CCMA/libCCMA
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/databases/ECMA
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/databases/ECMA/libECMA
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/corelibs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/corelibs/odb
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/corelibs/odb/libodb
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/corelibs/odbdummy
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/corelibs/odbdummy/libodbdummy
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/corelibs/odbmain
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/corelibs/odbmain/libodbmain
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/corelibs/odbport
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/odb/corelibs/odbport/libodbport
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/ssa
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/ssa/libssa
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/obstat
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/obstat/libobstat
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/bl
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/bl/libbl95
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/scat
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/scat/libscat
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/satrad
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/satrad/libsatrad
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/aeolus
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/aeolus/libaeolus
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/prepdata
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/libs/compile/prepdata/libprepdata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/links
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make/logfiles
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/limits
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/limits
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make/setup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make/links
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make/datalinks
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make/ocsetup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make/libsoc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make/oclinks
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make/prepdata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make/mc_tools
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make/sc_tools
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/make/tools
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/make/octools
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/make/build_seasplot
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make/couple
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make/couple/ifs
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make/couple/oasis
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make/couple/wamabs
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make/const
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make/const/wconst
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/make/control
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make/control/ocean
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make/control/forcing
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/make/control/getcouple
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/make/control
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/make/control/ocean
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/make/control/forcing
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/make/control/getcouple
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make/assim
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make/assim/ocean
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make/assim/forcing
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make/assim/getcouple
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make/logfiles
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/getini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/inidata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/oceini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svevo
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svevo/getini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svevo/inidata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svevo/svnh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svevo/svsh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/getini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/inidata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/svnh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/svsh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/targets
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/subspace
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv3
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv4
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv5
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv6
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svevo
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svevo/getini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svevo/inidata
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svevo/svnh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svevo/svsh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/getini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/inidata
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/svnh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/svsh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/targets
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/subspace
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv2
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv3
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv4
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv5
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv6
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/getae
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/getsvs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/ocrot
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/geticp
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/000
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/000/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/001
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/001/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/002
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/002/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/003
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/003/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/004
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/004/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/005
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/005/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/006
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/006/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/007
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/007/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/008
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/008/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/009
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/009/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/010
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/010/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/011
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/011/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/012
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/012/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/013
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/013/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/014
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/014/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/015
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/015/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/016
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/016/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/017
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/017/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/018
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/018/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/019
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/019/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/020
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/020/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/021
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/021/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/022
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/022/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/023
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/023/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/024
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/024/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/025
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/025/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/026
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/026/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/027
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/027/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/028
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/028/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/029
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/029/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/030
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/030/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/031
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/031/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/032
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/032/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/033
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/033/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/034
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/034/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/035
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/035/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/036
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/036/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/037
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/037/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/038
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/038/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/039
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/039/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/040
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/040/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/041
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/041/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/042
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/042/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/043
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/043/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/044
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/044/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/045
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/045/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/046
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/046/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/047
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/047/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/048
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/048/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/049
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/049/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/050
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/050/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/ocwavini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/ocwcold
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/ocwavfcdata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/fc0/iniocean
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/fc0/iniatmos
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/fc0/cpmodel1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/fc0/extrafields
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/fc0/mm_sfc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/fc0/mm_ua
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/getini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/inidata
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/oceini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svevo
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svevo/getini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svevo/inidata
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svevo/svnh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svevo/svsh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/getini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/inidata
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/svnh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/svsh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/targets
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/subspace
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv2
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv3
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv4
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv5
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv6
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/getae
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/getsvs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/ocrot
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/geticp
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/000
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/000/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/001
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/001/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/002
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/002/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/003
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/003/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/004
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/004/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/005
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/005/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/006
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/006/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/007
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/007/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/008
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/008/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/009
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/009/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/010
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/010/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/011
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/011/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/012
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/012/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/013
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/013/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/014
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/014/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/015
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/015/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/016
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/016/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/017
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/017/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/018
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/018/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/019
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/019/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/020
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/020/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/021
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/021/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/022
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/022/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/023
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/023/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/024
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/024/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/025
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/025/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/026
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/026/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/027
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/027/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/028
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/028/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/029
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/029/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/030
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/030/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/031
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/031/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/032
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/032/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/033
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/033/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/034
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/034/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/035
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/035/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/036
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/036/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/037
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/037/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/038
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/038/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/039
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/039/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/040
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/040/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/041
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/041/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/042
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/042/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/043
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/043/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/044
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/044/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/045
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/045/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/046
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/046/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/047
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/047/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/048
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/048/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/049
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/049/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/050
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/050/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/ocwavini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/ocwcold
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/ocwavfcdata
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/fc0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/fc0/iniocean
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/fc0/iniatmos
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/fc0/cpmodel1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/fc0/extrafields
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/fc0/mm_sfc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/fc0/mm_ua
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/getini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/inidata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/oceini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svevo
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svevo/getini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svevo/inidata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svevo/svnh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svevo/svsh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/getini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/inidata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/svnh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/svsh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/targets
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/subspace
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/sv1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/sv2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/sv3
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/sv4
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/sv5
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/sv6
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svevo
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svevo/getini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svevo/inidata
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svevo/svnh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svevo/svsh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/getini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/inidata
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/svnh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/svsh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/targets
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/subspace
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/sv1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/sv2
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/sv3
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/sv4
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/sv5
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/sv6
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/getae
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/getsvs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/ocrot
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/geticp
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/000
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/000/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/001
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/001/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/002
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/002/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/003
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/003/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/004
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/004/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/005
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/005/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/006
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/006/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/007
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/007/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/008
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/008/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/009
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/009/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/010
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/010/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/011
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/011/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/012
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/012/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/013
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/013/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/014
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/014/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/015
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/015/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/016
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/016/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/017
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/017/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/018
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/018/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/019
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/019/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/020
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/020/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/021
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/021/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/022
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/022/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/023
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/023/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/024
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/024/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/025
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/025/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/026
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/026/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/027
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/027/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/028
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/028/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/029
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/029/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/030
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/030/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/031
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/031/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/032
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/032/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/033
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/033/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/034
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/034/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/035
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/035/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/036
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/036/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/037
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/037/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/038
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/038/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/039
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/039/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/040
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/040/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/041
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/041/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/042
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/042/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/043
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/043/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/044
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/044/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/045
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/045/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/046
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/046/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/047
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/047/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/048
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/048/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/049
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/049/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/050
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/050/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/ocwavini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/ocwcold
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/ocwavfcdata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/fc0/iniocean
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/fc0/iniatmos
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/fc0/cpmodel1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/fc0/extrafields
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/fc0/mm_sfc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/fc0/mm_ua
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/getini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/inidata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/oceini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svevo
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svevo/getini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svevo/inidata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svevo/svnh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svevo/svsh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/getini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/inidata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/svnh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/svsh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/targets
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/subspace
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/sv1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/sv2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/sv3
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/sv4
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/sv5
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/sv6
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svevo
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svevo/getini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svevo/inidata
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svevo/svnh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svevo/svsh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/getini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/inidata
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/svnh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/svsh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/targets
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/subspace
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/sv1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/sv2
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/sv3
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/sv4
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/sv5
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/sv6
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/getae
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/getsvs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/ocrot
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/geticp
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/000
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/000/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/001
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/001/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/002
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/002/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/003
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/003/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/004
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/004/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/005
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/005/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/006
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/006/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/007
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/007/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/008
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/008/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/009
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/009/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/010
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/010/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/011
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/011/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/012
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/012/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/013
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/013/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/014
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/014/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/015
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/015/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/016
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/016/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/017
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/017/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/018
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/018/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/019
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/019/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/020
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/020/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/021
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/021/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/022
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/022/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/023
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/023/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/024
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/024/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/025
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/025/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/026
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/026/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/027
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/027/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/028
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/028/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/029
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/029/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/030
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/030/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/031
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/031/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/032
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/032/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/033
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/033/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/034
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/034/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/035
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/035/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/036
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/036/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/037
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/037/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/038
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/038/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/039
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/039/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/040
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/040/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/041
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/041/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/042
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/042/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/043
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/043/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/044
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/044/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/045
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/045/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/046
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/046/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/047
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/047/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/048
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/048/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/049
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/049/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/050
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/050/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/getae
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/getsvs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/ocrot
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/geticp
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/000
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/000/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/001
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/001/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/002
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/002/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/003
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/003/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/004
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/004/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/005
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/005/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/006
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/006/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/007
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/007/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/008
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/008/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/009
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/009/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/010
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/010/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/011
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/011/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/012
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/012/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/013
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/013/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/014
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/014/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/015
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/015/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/016
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/016/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/017
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/017/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/018
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/018/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/019
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/019/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/020
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/020/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/021
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/021/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/022
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/022/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/023
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/023/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/024
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/024/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/025
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/025/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/026
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/026/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/027
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/027/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/028
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/028/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/029
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/029/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/030
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/030/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/031
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/031/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/032
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/032/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/033
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/033/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/034
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/034/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/035
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/035/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/036
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/036/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/037
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/037/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/038
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/038/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/039
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/039/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/040
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/040/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/041
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/041/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/042
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/042/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/043
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/043/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/044
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/044/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/045
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/045/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/046
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/046/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/047
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/047/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/048
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/048/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/049
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/049/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/050
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/050/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/ocwavini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/ocwcold
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/ocwavfcdata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/fc1/iniocean
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/fc1/iniatmos
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/fc1/cpmodel1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/fc1/extrafields
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/fc1/mm_sfc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/fc1/mm_ua
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/getini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/inidata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/oceini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svevo
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svevo/getini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svevo/inidata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svevo/svnh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svevo/svsh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/getini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/inidata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/svnh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/svsh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/targets
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/subspace
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/sv1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/sv2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/sv3
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/sv4
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/sv5
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/sv6
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svevo
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svevo/getini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svevo/inidata
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svevo/svnh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svevo/svsh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/getini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/inidata
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/svnh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/svsh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/targets
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/subspace
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/sv1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/sv2
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/sv3
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/sv4
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/sv5
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/sv6
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/getae
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/getsvs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/ocrot
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/geticp
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/000
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/000/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/001
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/001/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/002
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/002/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/003
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/003/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/004
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/004/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/005
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/005/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/006
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/006/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/007
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/007/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/008
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/008/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/009
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/009/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/010
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/010/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/011
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/011/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/012
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/012/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/013
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/013/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/014
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/014/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/015
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/015/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/016
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/016/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/017
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/017/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/018
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/018/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/019
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/019/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/020
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/020/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/021
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/021/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/022
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/022/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/023
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/023/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/024
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/024/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/025
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/025/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/026
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/026/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/027
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/027/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/028
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/028/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/029
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/029/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/030
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/030/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/031
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/031/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/032
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/032/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/033
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/033/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/034
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/034/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/035
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/035/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/036
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/036/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/037
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/037/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/038
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/038/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/039
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/039/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/040
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/040/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/041
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/041/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/042
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/042/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/043
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/043/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/044
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/044/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/045
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/045/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/046
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/046/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/047
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/047/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/048
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/048/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/049
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/049/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/050
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/050/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/getae
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/getsvs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/ocrot
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/geticp
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/000
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/000/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/001
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/001/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/002
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/002/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/003
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/003/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/004
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/004/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/005
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/005/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/006
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/006/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/007
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/007/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/008
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/008/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/009
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/009/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/010
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/010/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/011
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/011/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/012
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/012/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/013
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/013/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/014
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/014/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/015
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/015/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/016
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/016/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/017
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/017/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/018
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/018/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/019
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/019/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/020
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/020/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/021
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/021/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/022
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/022/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/023
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/023/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/024
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/024/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/025
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/025/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/026
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/026/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/027
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/027/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/028
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/028/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/029
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/029/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/030
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/030/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/031
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/031/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/032
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/032/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/033
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/033/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/034
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/034/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/035
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/035/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/036
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/036/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/037
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/037/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/038
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/038/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/039
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/039/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/040
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/040/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/041
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/041/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/042
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/042/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/043
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/043/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/044
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/044/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/045
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/045/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/046
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/046/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/047
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/047/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/048
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/048/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/049
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/049/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/050
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/050/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/ocwavini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/ocwcold
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/ocwavfcdata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/fc2/iniocean
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/fc2/iniatmos
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/fc2/cpmodel1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/fc2/extrafields
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/fc2/mm_sfc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/fc2/mm_ua
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/logfiles
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/archive
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/archive/preparcoup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/archive/arcfc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/archive/sfc_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/archive/ua_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/archive/mm_sfc_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/archive/mm_ua_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/restarts
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/restarts/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/restarts/fc0/saverestarts
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/ocflush
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/process
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/process/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/process/fc0/nino_oc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/process/fc0/nino_daily
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/process/fc0/nino_atmos
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/process/fc0/tcyc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/archive/preparcoup
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/archive/arcfc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/archive/sfc_arc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/archive/ua_arc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/archive/mm_sfc_arc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/archive/mm_ua_arc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/restarts
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/restarts/fc0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/restarts/fc0/saverestarts
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/ocflush
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/process
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/process/fc0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/process/fc0/nino_oc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/process/fc0/nino_daily
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/process/fc0/nino_atmos
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/process/fc0/tcyc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/archive/preparcoup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/archive/arcfc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/archive/sfc_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/archive/ua_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/archive/mm_sfc_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/archive/mm_ua_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/restarts
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/restarts/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/restarts/fc0/saverestarts
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/ocflush
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/process
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/process/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/nino_oc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/nino_daily
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/nino_atmos
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/tcyc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/archive/preparcoup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/archive/arcfc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/archive/sfc_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/archive/ua_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/archive/mm_sfc_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/archive/mm_ua_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/restarts
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/restarts/fc1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/restarts/fc1/saverestarts
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/ocflush
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/process
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/process/fc1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/nino_oc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/nino_daily
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/nino_atmos
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/tcyc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/archive/preparcoup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/archive/arcfc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/archive/sfc_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/archive/ua_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/archive/mm_sfc_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/archive/mm_ua_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/restarts
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/restarts/fc2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/restarts/fc2/saverestarts
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/ocflush
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/process
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/process/fc2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/nino_oc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/nino_daily
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/nino_atmos
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/tcyc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/logfiles
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/control0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/control0/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/control0/fc0/saveoce
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/control0/fc0/occleanfdb
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/control0/fc0/occleanfdbicp
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/control0/fc0/occleandirs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/control0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/control0/fc0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/control0/fc0/saveoce
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/control0/fc0/occleanfdb
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/control0/fc0/occleanfdbicp
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/control0/fc0/occleandirs
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim0/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim0/fc0/saveoce
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim0/fc0/occleanfdb
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim0/fc0/occleanfdbicp
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim0/fc0/occleandirs
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim1/fc1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim1/fc1/saveoce
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim1/fc1/occleanfdb
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim1/fc1/occleanfdbicp
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim1/fc1/occleandirs
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim2/fc2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim2/fc2/saveoce
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim2/fc2/occleanfdb
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim2/fc2/occleanfdbicp
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim2/fc2/occleandirs
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/logfiles
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/wipefdb
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/cancel
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/make/setup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/make
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/make/setup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/make
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/setup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/make/links
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/make
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/make/links
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/make
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/links
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/make
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/make/logfiles
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/make
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/make/logfiles
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/make
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make/logfiles
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/make
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make/setup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make/setup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/make/setup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make/links
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make/links
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/make/links
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make/datalinks
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make/datalinks
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/make/datalinks
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make/ocsetup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make/ocsetup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/make/ocsetup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make/libsoc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make/libsoc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/make/libsoc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make/oclinks
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make/oclinks
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/make/oclinks
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make/prepdata
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make/prepdata
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/make/prepdata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make/mc_tools
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make/mc_tools
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/make/mc_tools
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make/sc_tools
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make/sc_tools
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make/couple/ifs
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make/couple
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make/couple/ifs
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make/couple
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make/couple/oasis
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make/couple/oasis
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make/couple/wamabs
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make/couple/wamabs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/make/sc_tools
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/make/couple/ifs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/make/couple/oasis
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/make/couple/wamabs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/make/couple
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make/const/wconst
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make/const
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make/const/wconst
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make/const
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/make/const/wconst
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/make/const
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make/assim/ocean
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make/assim
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make/assim/ocean
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make/assim
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/make/assim/ocean
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make/assim
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make/assim/forcing
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make/assim
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make/assim/forcing
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make/assim
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/make/assim/forcing
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make/assim
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make/assim/getcouple
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make/assim
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make/assim/getcouple
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make/assim
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/make/assim/getcouple
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/make/assim
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make/logfiles
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make/logfiles
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/make/logfiles
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/make
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/getini
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/getini
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/oceini
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/oceini
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/ocwavini
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/ocwavini
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1/oceini
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1/oceini
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2/oceini
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2/oceini
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/getini
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/inidata
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/inidata
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/geticp
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/geticp
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/inidata
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/geticp
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/000/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/000
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/000/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/000
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/001/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/001
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/001/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/001
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/002/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/002
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/002/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/002
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/003/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/003
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/003/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/003
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/004/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/004
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/004/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/004
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/005/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/005
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/005/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/005
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/000/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/000
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/006/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/006
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/006/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/006
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/006/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/006
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/007/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/007
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/007/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/007
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/007/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/007
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/008/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/008
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/008/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/008
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/008/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/008
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/009/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/009
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/009/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/009
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/009/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/009
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/010/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/010
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/010/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/010
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/010/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/010
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/011/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/011
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/011/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/011
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/011/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/011
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/012/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/012
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/012/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/012
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/012/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/012
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/013/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/013
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/013/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/013
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/013/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/013
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/014/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/014
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/014/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/014
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/014/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/014
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/015/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/015
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/015/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/015
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/015/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/015
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/016/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/016
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/016/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/016
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/016/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/016
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/017/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/017
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/017/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/017
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/017/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/017
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/018/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/018
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/018/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/018
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/018/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/018
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/019/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/019
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/019/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/019
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/019/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/019
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/020/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/020
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/020/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/020
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/020/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/020
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/021/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/021
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/021/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/021
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/021/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/021
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/022/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/022
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/022/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/022
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/022/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/022
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/023/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/023
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/023/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/023
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/023/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/023
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/024/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/024
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/024/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/024
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/024/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/024
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/025/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/025
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/025/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/025
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/025/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/025
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/026/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/026
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/026/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/026
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/026/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/026
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/027/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/027
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/027/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/027
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/027/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/027
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/028/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/028
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/028/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/028
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/028/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/028
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/029/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/029
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/029/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/029
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/029/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/029
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/030/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/030
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/030/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/030
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/030/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/030
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/031/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/031
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/031/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/031
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/031/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/031
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/032/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/032
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/032/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/032
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/032/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/032
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/033/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/033
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/033/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/033
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/033/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/033
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/034/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/034
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/034/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/034
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/034/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/034
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/035/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/035
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/035/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/035
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/035/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/035
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/036/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/036
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/036/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/036
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/036/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/036
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/037/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/037
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/037/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/037
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/037/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/037
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/038/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/038
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/038/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/038
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/038/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/038
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/039/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/039
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/039/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/039
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/039/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/039
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/040/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/040
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/040/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/040
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/040/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/040
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/041/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/041
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/041/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/041
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/041/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/041
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/042/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/042
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/042/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/042
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/042/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/042
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/043/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/043
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/043/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/043
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/043/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/043
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/044/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/044
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/044/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/044
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/044/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/044
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/045/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/045
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/045/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/045
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/045/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/045
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/046/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/046
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/046/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/046
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/046/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/046
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/047/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/047
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/047/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/047
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/047/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/047
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/048/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/048
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/048/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/048
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/048/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/048
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/049/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/049
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/049/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/049
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/049/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/049
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/050/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/050
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/050/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/050
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/050/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/050
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/001/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/001
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/002/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/002
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/003/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/003
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/004/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/004
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/005/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/005
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/oceini
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/fc0/iniocean
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/fc0/iniocean
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/fc0/iniocean
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/ocwavini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/ocwavfcdata
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/ocwavfcdata
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/ocwavfcdata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/fc0/iniatmos
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/fc0/iniatmos
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1/fc1/iniatmos
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1/fc1/iniatmos
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2/fc2/iniatmos
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2/fc2/iniatmos
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/fc0/iniatmos
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/fc0/cpmodel1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/fc0/cpmodel1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/fc0/cpmodel1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/fc0/extrafields
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/fc0/extrafields
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/fc0/extrafields
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/fc0/mm_sfc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/fc0/mm_sfc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/fc0/mm_sfc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/fc0/mm_ua
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/fc0/mm_ua
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/fc0/mm_ua
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/archive/preparcoup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/archive/preparcoup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/nino_oc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/process/fc0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/process
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/nino_oc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/process/fc0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/process
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/archive/preparcoup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/archive/arcfc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/archive/arcfc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/archive/arcfc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/archive/sfc_arc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/archive/sfc_arc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/archive/sfc_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/archive/ua_arc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/archive/ua_arc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/archive/ua_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/archive/mm_sfc_arc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/archive/mm_sfc_arc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/archive/mm_sfc_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/archive/mm_ua_arc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/archive/mm_ua_arc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/archive/mm_ua_arc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/restarts/fc0/saverestarts
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/restarts/fc0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/restarts
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/restarts/fc0/saverestarts
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/restarts/fc0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/restarts
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/tcyc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/tcyc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/restarts/fc0/saverestarts
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/restarts/fc0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/restarts
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/ocflush
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/ocflush
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/ocflush
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/tcyc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/nino_oc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/process/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/process
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/nino_daily
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/process/fc0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/process
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/nino_daily
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/process/fc0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/process
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/nino_daily
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/process/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/process
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/nino_atmos
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/process/fc0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/process
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/nino_atmos
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/process/fc0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/process
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/nino_atmos
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/process/fc0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/process
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim0/fc0/saveoce
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim0/fc0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim0/fc0/saveoce
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim0/fc0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim0/fc0/saveoce
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim0/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim0/fc0/occleanfdb
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim0/fc0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim0/fc0/occleanfdb
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim0/fc0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim0/fc0/occleanfdb
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim0/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/fc1/iniatmos
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/fc2/iniatmos
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/oceini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1/fc1/iniocean
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1/fc1/iniocean
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/fc1/iniocean
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1/fc1/cpmodel1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1/fc1/cpmodel1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/fc1/cpmodel1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1/fc1/extrafields
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1/fc1/extrafields
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/fc1/extrafields
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1/fc1/mm_sfc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1/fc1/mm_sfc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/fc1/mm_sfc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1/fc1/mm_ua
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1/fc1/mm_ua
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/fc1/mm_ua
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/archive/preparcoup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/archive/preparcoup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/nino_oc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/process/fc1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/process
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/nino_oc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/process/fc1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/process
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/archive/preparcoup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/archive/arcfc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/archive/arcfc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/archive/arcfc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/archive/sfc_arc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/archive/sfc_arc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/archive/sfc_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/archive/ua_arc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/archive/ua_arc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/archive/ua_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/archive/mm_sfc_arc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/archive/mm_sfc_arc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/archive/mm_sfc_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/archive/mm_ua_arc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/archive/mm_ua_arc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/archive/mm_ua_arc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/restarts/fc1/saverestarts
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/restarts/fc1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/restarts
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/restarts/fc1/saverestarts
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/restarts/fc1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/restarts
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/tcyc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/tcyc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/restarts/fc1/saverestarts
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/restarts/fc1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/restarts
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/ocflush
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/ocflush
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/ocflush
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/tcyc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/nino_oc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/process/fc1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/process
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/nino_daily
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/process/fc1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/process
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/nino_daily
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/process/fc1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/process
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/nino_daily
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/process/fc1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/process
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/nino_atmos
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/process/fc1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/process
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/nino_atmos
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/process/fc1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/process
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/nino_atmos
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/process/fc1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/process
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim1/fc1/saveoce
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim1/fc1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim1/fc1/saveoce
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim1/fc1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim1/fc1/saveoce
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim1/fc1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim1/fc1/occleanfdb
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim1/fc1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim1/fc1/occleanfdb
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim1/fc1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim1/fc1/occleanfdb
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim1/fc1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim1/fc1/occleandirs
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim1/fc1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim1/fc1/occleandirs
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim1/fc1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim1/fc1/occleandirs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim1/fc1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/oceini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2/fc2/iniocean
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2/fc2/iniocean
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/fc2/iniocean
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2/fc2/cpmodel1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2/fc2/cpmodel1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/fc2/cpmodel1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2/fc2/extrafields
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2/fc2/extrafields
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/fc2/extrafields
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2/fc2/mm_sfc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2/fc2/mm_sfc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/fc2/mm_sfc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2/fc2/mm_ua
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2/fc2/mm_ua
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/fc2/mm_ua
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/logfiles
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/logfiles
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/archive/preparcoup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/archive/preparcoup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/nino_oc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/process/fc2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/process
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/nino_oc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/process/fc2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/process
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/logfiles
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/getini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/inidata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/oceini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svevo
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svevo/getini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svevo/inidata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svevo/svnh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svevo/svsh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/getini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/inidata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/svnh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/svsh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/targets
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/subspace
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv3
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv4
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv5
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv6
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svevo
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svevo/getini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svevo/inidata
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svevo/svnh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svevo/svsh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/getini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/inidata
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/svnh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/svsh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/targets
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/subspace
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv2
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv3
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv4
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv5
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv6
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/getae
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/getsvs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/ocrot
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/geticp
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/000
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/000/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/001
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/001/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/002
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/002/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/003
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/003/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/004
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/004/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/005
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/005/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/006
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/006/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/007
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/007/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/008
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/008/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/009
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/009/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/010
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/010/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/011
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/011/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/012
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/012/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/013
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/013/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/014
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/014/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/015
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/015/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/016
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/016/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/017
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/017/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/018
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/018/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/019
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/019/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/020
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/020/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/021
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/021/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/022
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/022/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/023
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/023/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/024
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/024/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/025
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/025/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/026
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/026/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/027
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/027/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/028
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/028/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/029
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/029/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/030
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/030/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/031
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/031/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/032
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/032/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/033
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/033/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/034
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/034/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/035
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/035/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/036
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/036/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/037
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/037/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/038
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/038/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/039
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/039/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/040
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/040/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/041
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/041/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/042
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/042/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/043
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/043/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/044
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/044/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/045
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/045/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/046
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/046/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/047
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/047/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/048
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/048/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/049
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/049/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/050
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/050/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/ocwavini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/ocwcold
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/ocwavfcdata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/fc0/iniocean
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/fc0/iniatmos
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/fc0/cpmodel1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/fc0/extrafields
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/fc0/mm_sfc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/control0/fc0/mm_ua
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/getini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/inidata
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/oceini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svevo
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svevo/getini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svevo/inidata
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svevo/svnh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svevo/svsh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/getini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/inidata
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/svnh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/svsh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/targets
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/subspace
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv2
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv3
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv4
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv5
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_sv/svini/sv6
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/getae
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/getsvs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/ocrot
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/geticp
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/000
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/000/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/001
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/001/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/002
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/002/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/003
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/003/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/004
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/004/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/005
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/005/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/006
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/006/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/007
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/007/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/008
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/008/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/009
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/009/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/010
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/010/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/011
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/011/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/012
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/012/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/013
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/013/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/014
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/014/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/015
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/015/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/016
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/016/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/017
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/017/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/018
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/018/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/019
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/019/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/020
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/020/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/021
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/021/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/022
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/022/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/023
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/023/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/024
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/024/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/025
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/025/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/026
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/026/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/027
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/027/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/028
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/028/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/029
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/029/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/030
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/030/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/031
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/031/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/032
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/032/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/033
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/033/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/034
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/034/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/035
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/035/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/036
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/036/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/037
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/037/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/038
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/038/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/039
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/039/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/040
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/040/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/041
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/041/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/042
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/042/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/043
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/043/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/044
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/044/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/045
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/045/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/046
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/046/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/047
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/047/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/048
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/048/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/049
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/049/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/050
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/eps_pert/pert_ic/050/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/ocwavini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/ocwcold
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/ocwavfcdata
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/fc0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/fc0/iniocean
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/fc0/iniatmos
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/fc0/cpmodel1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/fc0/extrafields
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/fc0/mm_sfc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/control0/fc0/mm_ua
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/getini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/inidata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/oceini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svevo
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svevo/getini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svevo/inidata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svevo/svnh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svevo/svsh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/getini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/inidata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/svnh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/svsh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/targets
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/subspace
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/sv1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/sv2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/sv3
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/sv4
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/sv5
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/sv6
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svevo
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svevo/getini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svevo/inidata
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svevo/svnh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svevo/svsh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/getini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/inidata
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/svnh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/svsh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/targets
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/subspace
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/sv1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/sv2
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/sv3
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/sv4
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/sv5
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_sv/svini/sv6
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/getae
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/getsvs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/ocrot
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/geticp
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/000
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/000/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/001
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/001/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/002
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/002/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/003
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/003/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/004
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/004/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/005
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/005/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/006
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/006/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/007
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/007/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/008
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/008/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/009
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/009/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/010
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/010/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/011
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/011/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/012
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/012/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/013
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/013/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/014
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/014/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/015
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/015/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/016
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/016/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/017
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/017/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/018
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/018/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/019
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/019/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/020
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/020/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/021
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/021/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/022
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/022/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/023
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/023/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/024
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/024/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/025
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/025/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/026
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/026/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/027
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/027/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/028
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/028/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/029
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/029/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/030
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/030/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/031
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/031/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/032
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/032/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/033
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/033/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/034
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/034/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/035
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/035/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/036
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/036/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/037
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/037/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/038
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/038/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/039
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/039/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/040
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/040/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/041
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/041/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/042
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/042/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/043
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/043/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/044
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/044/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/045
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/045/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/046
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/046/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/047
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/047/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/048
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/048/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/049
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/049/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/050
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/050/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/ocwavini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/ocwcold
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/ocwavfcdata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/fc0/iniocean
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/fc0/iniatmos
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/fc0/cpmodel1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/fc0/extrafields
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/fc0/mm_sfc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/fc0/mm_ua
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/getini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/inidata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/oceini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svevo
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svevo/getini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svevo/inidata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svevo/svnh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svevo/svsh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/getini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/inidata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/svnh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/svsh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/targets
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/subspace
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/sv1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/sv2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/sv3
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/sv4
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/sv5
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/sv6
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svevo
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svevo/getini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svevo/inidata
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svevo/svnh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svevo/svsh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/getini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/inidata
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/svnh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/svsh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/targets
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/subspace
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/sv1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/sv2
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/sv3
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/sv4
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/sv5
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_sv/svini/sv6
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/getae
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/getsvs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/ocrot
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/geticp
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/000
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/000/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/001
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/001/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/002
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/002/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/003
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/003/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/004
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/004/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/005
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/005/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/006
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/006/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/007
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/007/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/008
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/008/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/009
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/009/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/010
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/010/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/011
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/011/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/012
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/012/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/013
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/013/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/014
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/014/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/015
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/015/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/016
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/016/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/017
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/017/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/018
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/018/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/019
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/019/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/020
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/020/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/021
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/021/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/022
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/022/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/023
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/023/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/024
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/024/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/025
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/025/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/026
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/026/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/027
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/027/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/028
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/028/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/029
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/029/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/030
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/030/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/031
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/031/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/032
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/032/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/033
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/033/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/034
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/034/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/035
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/035/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/036
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/036/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/037
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/037/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/038
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/038/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/039
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/039/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/040
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/040/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/041
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/041/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/042
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/042/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/043
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/043/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/044
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/044/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/045
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/045/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/046
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/046/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/047
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/047/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/048
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/048/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/049
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/049/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/050
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/050/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/getae
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/getsvs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/ocrot
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/geticp
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/000
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/000/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/001
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/001/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/002
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/002/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/003
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/003/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/004
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/004/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/005
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/005/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/006
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/006/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/007
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/007/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/008
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/008/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/009
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/009/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/010
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/010/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/011
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/011/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/012
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/012/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/013
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/013/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/014
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/014/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/015
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/015/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/016
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/016/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/017
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/017/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/018
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/018/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/019
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/019/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/020
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/020/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/021
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/021/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/022
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/022/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/023
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/023/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/024
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/024/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/025
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/025/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/026
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/026/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/027
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/027/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/028
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/028/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/029
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/029/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/030
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/030/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/031
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/031/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/032
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/032/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/033
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/033/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/034
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/034/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/035
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/035/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/036
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/036/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/037
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/037/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/038
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/038/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/039
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/039/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/040
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/040/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/041
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/041/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/042
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/042/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/043
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/043/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/044
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/044/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/045
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/045/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/046
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/046/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/047
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/047/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/048
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/048/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/049
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/049/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/050
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/eps_pert/pert_ic/050/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/ocwavini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/ocwcold
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/ocwavfcdata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/fc1/iniocean
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/fc1/iniatmos
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/fc1/cpmodel1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/fc1/extrafields
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/fc1/mm_sfc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/fc1/mm_ua
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/getini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/inidata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/oceini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svevo
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svevo/getini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svevo/inidata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svevo/svnh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svevo/svsh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/getini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/inidata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/svnh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/svsh
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/targets
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/subspace
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/sv1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/sv2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/sv3
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/sv4
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/sv5
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/sv6
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svevo
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svevo/getini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svevo/inidata
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svevo/svnh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svevo/svsh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/getini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/inidata
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/svnh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/svsh
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/targets
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/subspace
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/sv1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/sv2
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/sv3
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/sv4
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/sv5
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_sv/svini/sv6
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/getae
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/getsvs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/ocrot
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/geticp
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/000
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/000/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/001
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/001/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/002
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/002/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/003
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/003/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/004
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/004/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/005
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/005/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/006
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/006/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/007
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/007/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/008
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/008/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/009
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/009/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/010
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/010/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/011
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/011/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/012
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/012/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/013
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/013/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/014
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/014/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/015
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/015/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/016
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/016/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/017
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/017/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/018
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/018/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/019
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/019/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/020
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/020/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/021
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/021/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/022
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/022/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/023
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/023/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/024
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/024/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/025
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/025/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/026
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/026/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/027
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/027/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/028
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/028/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/029
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/029/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/030
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/030/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/031
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/031/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/032
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/032/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/033
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/033/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/034
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/034/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/035
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/035/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/036
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/036/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/037
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/037/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/038
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/038/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/039
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/039/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/040
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/040/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/041
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/041/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/042
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/042/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/043
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/043/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/044
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/044/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/045
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/045/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/046
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/046/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/047
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/047/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/048
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/048/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/049
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/049/pertinic
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/050
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/050/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/getae
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/getsvs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/ocrot
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/geticp
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/000
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/000/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/001
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/001/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/002
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/002/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/003
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/003/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/004
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/004/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/005
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/005/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/006
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/006/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/007
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/007/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/008
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/008/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/009
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/009/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/010
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/010/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/011
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/011/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/012
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/012/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/013
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/013/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/014
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/014/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/015
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/015/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/016
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/016/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/017
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/017/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/018
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/018/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/019
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/019/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/020
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/020/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/021
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/021/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/022
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/022/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/023
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/023/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/024
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/024/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/025
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/025/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/026
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/026/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/027
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/027/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/028
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/028/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/029
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/029/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/030
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/030/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/031
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/031/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/032
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/032/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/033
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/033/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/034
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/034/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/035
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/035/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/036
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/036/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/037
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/037/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/038
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/038/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/039
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/039/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/040
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/040/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/041
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/041/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/042
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/042/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/043
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/043/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/044
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/044/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/045
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/045/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/046
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/046/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/047
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/047/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/048
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/048/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/049
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/049/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/050
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/eps_pert/pert_ic/050/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/ocwavini
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/ocwcold
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/ocwavfcdata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/fc2/iniocean
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/fc2/iniatmos
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/fc2/cpmodel1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/fc2/extrafields
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/fc2/mm_sfc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/fc2/mm_ua
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/logfiles
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/getini
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/getini
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/oceini
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/oceini
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/ocwavini
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/ocwavini
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1/oceini
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1/oceini
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2/oceini
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2/oceini
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/getini
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/inidata
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/inidata
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/geticp
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/geticp
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/inidata
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/geticp
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/eps_pert
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/000/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/000
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/000/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/000
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/001/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/001
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/001/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/001
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/002/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/002
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/002/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/002
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/003/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/003
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/003/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/003
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/004/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/004
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/004/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/004
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/005/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/005
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/005/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/005
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/000/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/000
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/006/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/006
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/006/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/006
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/006/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/006
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/007/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/007
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/007/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/007
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/007/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/007
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/008/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/008
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/008/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/008
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/008/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/008
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/009/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/009
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/009/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/009
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/009/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/009
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/010/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/010
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/010/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/010
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/010/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/010
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/011/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/011
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/011/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/011
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/011/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/011
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/012/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/012
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/012/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/012
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/012/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/012
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/013/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/013
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/013/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/013
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/013/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/013
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/014/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/014
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/014/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/014
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/014/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/014
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/015/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/015
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/015/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/015
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/015/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/015
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/016/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/016
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/016/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/016
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/016/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/016
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/017/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/017
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/017/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/017
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/017/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/017
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/018/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/018
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/018/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/018
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/018/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/018
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/019/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/019
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/019/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/019
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/019/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/019
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/020/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/020
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/020/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/020
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/020/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/020
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/021/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/021
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/021/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/021
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/021/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/021
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/022/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/022
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/022/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/022
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/022/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/022
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/023/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/023
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/023/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/023
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/023/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/023
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/024/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/024
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/024/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/024
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/024/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/024
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/025/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/025
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/025/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/025
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/025/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/025
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/026/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/026
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/026/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/026
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/026/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/026
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/027/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/027
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/027/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/027
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/027/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/027
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/028/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/028
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/028/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/028
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/028/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/028
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/029/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/029
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/029/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/029
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/029/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/029
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/030/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/030
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/030/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/030
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/030/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/030
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/031/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/031
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/031/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/031
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/031/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/031
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/032/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/032
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/032/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/032
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/032/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/032
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/033/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/033
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/033/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/033
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/033/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/033
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/034/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/034
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/034/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/034
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/034/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/034
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/035/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/035
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/035/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/035
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/035/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/035
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/036/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/036
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/036/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/036
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/036/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/036
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/037/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/037
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/037/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/037
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/037/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/037
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/038/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/038
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/038/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/038
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/038/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/038
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/039/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/039
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/039/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/039
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/039/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/039
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/040/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/040
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/040/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/040
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/040/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/040
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/041/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/041
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/041/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/041
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/041/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/041
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/042/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/042
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/042/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/042
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/042/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/042
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/043/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/043
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/043/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/043
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/043/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/043
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/044/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/044
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/044/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/044
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/044/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/044
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/045/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/045
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/045/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/045
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/045/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/045
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/046/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/046
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/046/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/046
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/046/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/046
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/047/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/047
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/047/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/047
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/047/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/047
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/048/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/048
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/048/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/048
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/048/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/048
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/049/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/049
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/049/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/049
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/049/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/049
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/050/pertinic
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/050
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/050/pertinic
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/050
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/050/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/050
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/001/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/001
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/002/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/002
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/003/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/003
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/004/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/004
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/005/pertinic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic/005
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert/pert_ic
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/eps_pert
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/oceini
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/fc0/iniocean
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/fc0/iniocean
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/fc0/iniocean
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/ocwavini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/ocwavfcdata
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/ocwavfcdata
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/ocwavfcdata
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/fc0/iniatmos
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/fc0/iniatmos
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1/fc1/iniatmos
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1/fc1/iniatmos
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2/fc2/iniatmos
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2/fc2/iniatmos
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/fc0/iniatmos
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/fc0/cpmodel1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/fc0/cpmodel1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/fc0/cpmodel1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/fc0/extrafields
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/fc0/extrafields
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/fc0/extrafields
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/fc0/mm_sfc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/fc0/mm_sfc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/fc0/mm_sfc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/fc0/mm_ua
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/fc0/mm_ua
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/fc0/mm_ua
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0/fc0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/fc1/iniatmos
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/fc2/iniatmos
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/oceini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1/fc1/iniocean
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1/fc1/iniocean
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/fc1/iniocean
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1/fc1/cpmodel1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1/fc1/cpmodel1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/fc1/cpmodel1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1/fc1/extrafields
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1/fc1/extrafields
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/fc1/extrafields
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1/fc1/mm_sfc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1/fc1/mm_sfc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/fc1/mm_sfc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1/fc1/mm_ua
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1/fc1/mm_ua
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/fc1/mm_ua
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1/fc1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/oceini
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2/fc2/iniocean
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2/fc2/iniocean
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/fc2/iniocean
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2/fc2/cpmodel1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2/fc2/cpmodel1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/fc2/cpmodel1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2/fc2/extrafields
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2/fc2/extrafields
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/fc2/extrafields
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2/fc2/mm_sfc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2/fc2/mm_sfc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/fc2/mm_sfc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2/fc2/mm_ua
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2/fc2/mm_ua
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/fc2/mm_ua
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2/fc2
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/assim2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main/logfiles
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main/logfiles
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main/logfiles
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/main
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/archive/preparcoup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/archive/arcfc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/archive/arcfc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/archive/arcfc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/archive/sfc_arc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/archive/sfc_arc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/archive/sfc_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/archive/ua_arc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/archive/ua_arc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/archive/ua_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/archive/mm_sfc_arc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/archive/mm_sfc_arc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/archive/mm_sfc_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/archive/mm_ua_arc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/archive/mm_ua_arc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/archive/mm_ua_arc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/restarts/fc2/saverestarts
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/restarts/fc2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/restarts
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/restarts/fc2/saverestarts
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/restarts/fc2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/restarts
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/tcyc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/tcyc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/restarts/fc2/saverestarts
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/restarts/fc2
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/restarts
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/ocflush
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/ocflush
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/ocflush
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/tcyc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/nino_oc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/process/fc2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/process
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/nino_daily
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/process/fc2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/process
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/nino_daily
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/process/fc2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/process
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/nino_daily
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/process/fc2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/process
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/nino_atmos
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/process/fc2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/process
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/nino_atmos
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/process/fc2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/process
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/nino_atmos
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/process/fc2
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/process
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/logfiles
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/logfiles
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim2/fc2/saveoce
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim2/fc2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim2/fc2/saveoce
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim2/fc2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/logfiles
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/archive
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/archive/preparcoup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/archive/arcfc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/archive/sfc_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/archive/ua_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/archive/mm_sfc_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/archive/mm_ua_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/restarts
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/restarts/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/restarts/fc0/saverestarts
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/ocflush
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/process
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/process/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/process/fc0/nino_oc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/process/fc0/nino_daily
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/process/fc0/nino_atmos
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/control0/process/fc0/tcyc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/archive/preparcoup
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/archive/arcfc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/archive/sfc_arc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/archive/ua_arc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/archive/mm_sfc_arc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/archive/mm_ua_arc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/restarts
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/restarts/fc0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/restarts/fc0/saverestarts
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/ocflush
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/process
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/process/fc0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/process/fc0/nino_oc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/process/fc0/nino_daily
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/process/fc0/nino_atmos
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/control0/process/fc0/tcyc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/archive/preparcoup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/archive/arcfc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/archive/sfc_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/archive/ua_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/archive/mm_sfc_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/archive/mm_ua_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/restarts
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/restarts/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/restarts/fc0/saverestarts
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/ocflush
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/process
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/process/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/nino_oc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/nino_daily
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/nino_atmos
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/tcyc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/archive/preparcoup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/archive/arcfc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/archive/sfc_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/archive/ua_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/archive/mm_sfc_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/archive/mm_ua_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/restarts
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/restarts/fc1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/restarts/fc1/saverestarts
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/ocflush
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/process
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/process/fc1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/nino_oc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/nino_daily
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/nino_atmos
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/tcyc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/archive/preparcoup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/archive/arcfc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/archive/sfc_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/archive/ua_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/archive/mm_sfc_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/archive/mm_ua_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/restarts
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/restarts/fc2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/restarts/fc2/saverestarts
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/ocflush
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/process
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/process/fc2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/nino_oc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/nino_daily
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/nino_atmos
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/tcyc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/logfiles
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/archive/preparcoup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/archive/preparcoup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/nino_oc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/process/fc0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/process
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/nino_oc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/process/fc0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/process
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/nino_oc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/process/fc1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/process
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/nino_oc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/process/fc1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/process
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/nino_oc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/process/fc2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/process
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/nino_oc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/process/fc2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/process
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/archive/preparcoup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/archive/arcfc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/archive/arcfc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/archive/arcfc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/archive/sfc_arc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/archive/sfc_arc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/archive/sfc_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/archive/ua_arc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/archive/ua_arc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/archive/ua_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/archive/mm_sfc_arc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/archive/mm_sfc_arc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/archive/mm_sfc_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/archive/mm_ua_arc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/archive/mm_ua_arc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/archive/mm_ua_arc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/restarts/fc0/saverestarts
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/restarts/fc0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/restarts
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/restarts/fc0/saverestarts
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/restarts/fc0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/restarts
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/tcyc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/tcyc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/archive/preparcoup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/archive/preparcoup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/restarts/fc0/saverestarts
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/restarts/fc0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/restarts
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/ocflush
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/ocflush
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/ocflush
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/tcyc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/archive/preparcoup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/archive/arcfc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/archive/arcfc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/archive/arcfc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/archive/sfc_arc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/archive/sfc_arc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/archive/sfc_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/archive/ua_arc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/archive/ua_arc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/archive/ua_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/archive/mm_sfc_arc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/archive/mm_sfc_arc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/archive/mm_sfc_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/archive/mm_ua_arc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/archive/mm_ua_arc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/archive/mm_ua_arc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/restarts/fc1/saverestarts
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/restarts/fc1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/restarts
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/restarts/fc1/saverestarts
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/restarts/fc1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/restarts
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/tcyc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/tcyc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/archive/preparcoup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/archive/preparcoup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/restarts/fc1/saverestarts
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/restarts/fc1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/restarts
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/ocflush
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/ocflush
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/ocflush
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/tcyc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/archive/preparcoup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/archive/arcfc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/archive/arcfc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/archive/arcfc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/archive/sfc_arc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/archive/sfc_arc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/archive/sfc_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/archive/ua_arc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/archive/ua_arc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/archive/ua_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/archive/mm_sfc_arc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/archive/mm_sfc_arc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/archive/mm_sfc_arc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/archive/mm_ua_arc
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/archive/mm_ua_arc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/archive/mm_ua_arc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/archive
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/restarts/fc2/saverestarts
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/restarts/fc2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/restarts
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/restarts/fc2/saverestarts
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/restarts/fc2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/restarts
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/tcyc
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/tcyc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/restarts/fc2/saverestarts
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/restarts/fc2
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/restarts
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/ocflush
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/ocflush
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/ocflush
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/tcyc
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/nino_oc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/process/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/process
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/nino_daily
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/process/fc0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/process
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/nino_daily
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/process/fc0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/process
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/nino_daily
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/process/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0/process
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/nino_atmos
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/process/fc0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0/process
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/nino_atmos
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/process/fc0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0/process
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/process/fc0/nino_atmos
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/process/fc0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0/process
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/nino_oc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/process/fc1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/process
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/nino_daily
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/process/fc1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/process
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/nino_daily
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/process/fc1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/process
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/nino_daily
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/process/fc1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1/process
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/nino_atmos
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/process/fc1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1/process
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/nino_atmos
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/process/fc1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1/process
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/process/fc1/nino_atmos
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/process/fc1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1/process
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/nino_oc
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/process/fc2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/process
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/nino_daily
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/process/fc2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/process
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/nino_daily
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/process/fc2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/process
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/nino_daily
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/process/fc2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2/process
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag/assim2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/nino_atmos
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/process/fc2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2/process
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/assim2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/nino_atmos
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/process/fc2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2/process
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/assim2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/process/fc2/nino_atmos
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/process/fc2
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2/process
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/assim2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag/logfiles
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag/logfiles
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag/logfiles
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/lag
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim2/fc2/saveoce
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim2/fc2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim2/fc2/occleanfdb
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim2/fc2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim2/fc2/occleanfdb
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim2/fc2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim2/fc2/occleanfdb
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim2/fc2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim2/fc2/occleandirs
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim2/fc2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim2/fc2/occleandirs
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim2/fc2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim2/fc2/occleandirs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim2/fc2
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim0/fc0/occleanfdbicp
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim0/fc0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim0/fc0/occleanfdbicp
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim0/fc0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim0/fc0/occleanfdbicp
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim0/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim0/fc0/occleandirs
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim0/fc0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim0/fc0/occleandirs
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim0/fc0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim0/fc0/occleandirs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim0/fc0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/logfiles
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/logfiles
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/logfiles
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/control0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/control0/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/control0/fc0/saveoce
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/control0/fc0/occleanfdb
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/control0/fc0/occleanfdbicp
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/control0/fc0/occleandirs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/control0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/control0/fc0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/control0/fc0/saveoce
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/control0/fc0/occleanfdb
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/control0/fc0/occleanfdbicp
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/control0/fc0/occleandirs
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim0/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim0/fc0/saveoce
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim0/fc0/occleanfdb
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim0/fc0/occleanfdbicp
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim0/fc0/occleandirs
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim1/fc1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim1/fc1/saveoce
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim1/fc1/occleanfdb
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim1/fc1/occleanfdbicp
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim1/fc1/occleandirs
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim2/fc2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim2/fc2/saveoce
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim2/fc2/occleanfdb
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim2/fc2/occleanfdbicp
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim2/fc2/occleandirs
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/logfiles
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim0/fc0/saveoce
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim0/fc0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim0/fc0/saveoce
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim0/fc0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim1/fc1/saveoce
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim1/fc1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim1/fc1/saveoce
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim1/fc1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim2/fc2/saveoce
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim2/fc2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim2/fc2/saveoce
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim2/fc2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim2
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim0/fc0/saveoce
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim0/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim0/fc0/occleanfdb
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim0/fc0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim0/fc0/occleanfdb
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim0/fc0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim0/fc0/occleanfdb
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim0/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim1/fc1/saveoce
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim1/fc1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim1/fc1/occleanfdb
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim1/fc1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim1/fc1/occleanfdb
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim1/fc1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim1/fc1/occleanfdb
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim1/fc1
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim1/fc1/occleandirs
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim1/fc1
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim1/fc1/occleandirs
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim1/fc1
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim1/fc1/occleandirs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim1/fc1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim1
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim2/fc2/saveoce
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim2/fc2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim2/fc2/occleanfdb
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim2/fc2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim2/fc2/occleanfdb
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim2/fc2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim2/fc2/occleanfdb
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim2/fc2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim2/fc2/occleandirs
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim2/fc2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim2
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim2/fc2/occleandirs
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim2/fc2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim2
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim2/fc2/occleandirs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim2/fc2
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim2
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim0/fc0/occleanfdbicp
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim0/fc0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim0/fc0/occleanfdbicp
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim0/fc0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim0/fc0/occleanfdbicp
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim0/fc0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean/assim0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim0/fc0/occleandirs
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim0/fc0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/assim0
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim0/fc0/occleandirs
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim0/fc0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/assim0
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim0/fc0/occleandirs
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim0/fc0
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/assim0
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean/logfiles
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean/logfiles
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean/logfiles
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate/clean
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup/fcdate
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/coup
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/wipefdb
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/wipefdb
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/wipefdb
+LOG:[12:27:16 12.5.2016] queued: /ptb/a020
+LOG:[12:27:16 12.5.2016] queued: /ptb
+LOG:[12:27:16 12.5.2016] queued: /
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020/cancel
+LOG:[12:27:16 12.5.2016] submitted: /ptb/a020
+LOG:[12:27:16 12.5.2016] submitted: /ptb
+LOG:[12:27:16 12.5.2016] submitted: /
+LOG:[12:27:16 12.5.2016] active: /ptb/a020/cancel
+LOG:[12:27:16 12.5.2016] active: /ptb/a020
+LOG:[12:27:16 12.5.2016] active: /ptb
+LOG:[12:27:16 12.5.2016] active: /
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020/cancel
+LOG:[12:27:16 12.5.2016] complete: /ptb/a020
+LOG:[12:27:16 12.5.2016] complete: /ptb
+LOG:[12:27:16 12.5.2016] complete: /
+MSG:[12:27:16 12.5.2016] Simulation complete in 00:00:00
diff --git a/ecflow_4_0_7/CSim/test/data/good_defs/today/today.def b/CSim/test/data/good_defs/today/today.def
similarity index 100%
rename from ecflow_4_0_7/CSim/test/data/good_defs/today/today.def
rename to CSim/test/data/good_defs/today/today.def
diff --git a/CSim/test/data/good_defs/today/today.def.log b/CSim/test/data/good_defs/today/today.def.log
new file mode 100644
index 0000000..453f233
--- /dev/null
+++ b/CSim/test/data/good_defs/today/today.def.log
@@ -0,0 +1,12 @@
+LOG:[12:27:14 12.5.2016] queued: /suiteName
+LOG:[12:27:14 12.5.2016] queued: /suiteName/t1
+LOG:[12:27:14 12.5.2016] submitted: /suiteName/t1
+LOG:[12:27:14 12.5.2016] submitted: /suiteName
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /suiteName/t1
+LOG:[12:27:14 12.5.2016] active: /suiteName
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /suiteName/t1
+LOG:[12:27:14 12.5.2016] complete: /suiteName
+LOG:[12:27:14 12.5.2016] complete: /
+MSG:[12:27:14 12.5.2016] Simulation complete in 15:00:00
diff --git a/ecflow_4_0_7/CSim/test/data/good_defs/today/today2.def b/CSim/test/data/good_defs/today/today2.def
similarity index 100%
rename from ecflow_4_0_7/CSim/test/data/good_defs/today/today2.def
rename to CSim/test/data/good_defs/today/today2.def
diff --git a/CSim/test/data/good_defs/today/today2.def.log b/CSim/test/data/good_defs/today/today2.def.log
new file mode 100644
index 0000000..3bb2d88
--- /dev/null
+++ b/CSim/test/data/good_defs/today/today2.def.log
@@ -0,0 +1,66 @@
+LOG:[12:27:14 12.5.2016] queued: /s1
+LOG:[12:27:14 12.5.2016] queued: /s1/t1
+LOG:[12:27:14 12.5.2016] queued: /s1/t2
+LOG:[12:27:14 12.5.2016] submitted: /s1/t2
+LOG:[12:27:14 12.5.2016] submitted: /s1
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /s1/t2
+LOG:[12:27:14 12.5.2016] active: /s1
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /s1/t2
+LOG:[12:27:14 12.5.2016] queued: /s1/t2
+LOG:[12:27:14 12.5.2016] queued: /s1
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /s1/t2
+LOG:[12:27:14 12.5.2016] submitted: /s1
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /s1/t2
+LOG:[12:27:14 12.5.2016] active: /s1
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /s1/t2
+LOG:[12:27:14 12.5.2016] queued: /s1/t2
+LOG:[12:27:14 12.5.2016] queued: /s1
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /s1/t2
+LOG:[12:27:14 12.5.2016] submitted: /s1
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /s1/t2
+LOG:[12:27:14 12.5.2016] active: /s1
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /s1/t2
+LOG:[12:27:14 12.5.2016] queued: /s1/t2
+LOG:[12:27:14 12.5.2016] queued: /s1
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /s1/t2
+LOG:[12:27:14 12.5.2016] submitted: /s1
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /s1/t2
+LOG:[12:27:14 12.5.2016] active: /s1
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /s1/t2
+LOG:[12:27:14 12.5.2016] queued: /s1/t2
+LOG:[12:27:14 12.5.2016] queued: /s1
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /s1/t2
+LOG:[12:27:14 12.5.2016] submitted: /s1
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /s1/t2
+LOG:[12:27:14 12.5.2016] active: /s1
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /s1/t2
+LOG:[12:27:14 12.5.2016] queued: /s1/t2
+LOG:[12:27:14 12.5.2016] queued: /s1
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /s1/t1
+LOG:[12:27:14 12.5.2016] submitted: /s1
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /s1/t1
+LOG:[12:27:14 12.5.2016] active: /s1
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] submitted: /s1/t2
+LOG:[12:27:14 12.5.2016] active: /s1/t2
+LOG:[12:27:14 12.5.2016] complete: /s1/t1
+LOG:[12:27:14 12.5.2016] complete: /s1/t2
+LOG:[12:27:14 12.5.2016] complete: /s1
+LOG:[12:27:14 12.5.2016] complete: /
+MSG:[12:27:14 12.5.2016] Simulation complete in 20:00:00
diff --git a/ecflow_4_0_7/CSim/test/data/good_defs/today/today_range.def b/CSim/test/data/good_defs/today/today_range.def
similarity index 100%
rename from ecflow_4_0_7/CSim/test/data/good_defs/today/today_range.def
rename to CSim/test/data/good_defs/today/today_range.def
diff --git a/CSim/test/data/good_defs/today/today_range.def.log b/CSim/test/data/good_defs/today/today_range.def.log
new file mode 100644
index 0000000..1dc4960
--- /dev/null
+++ b/CSim/test/data/good_defs/today/today_range.def.log
@@ -0,0 +1,62 @@
+LOG:[12:27:14 12.5.2016] queued: /suiteName
+LOG:[12:27:14 12.5.2016] queued: /suiteName/t1
+LOG:[12:27:14 12.5.2016] queued: /suiteName/t2
+LOG:[12:27:14 12.5.2016] queued: /suiteName/t3
+LOG:[12:27:14 12.5.2016] submitted: /suiteName/t3
+LOG:[12:27:14 12.5.2016] submitted: /suiteName
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /suiteName/t3
+LOG:[12:27:14 12.5.2016] active: /suiteName
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] complete: /suiteName/t3
+LOG:[12:27:14 12.5.2016] queued: /suiteName/t3
+LOG:[12:27:14 12.5.2016] queued: /suiteName
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /suiteName/t1
+LOG:[12:27:14 12.5.2016] submitted: /suiteName
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /suiteName/t1
+LOG:[12:27:14 12.5.2016] active: /suiteName
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] submitted: /suiteName/t2
+LOG:[12:27:14 12.5.2016] active: /suiteName/t2
+LOG:[12:27:14 12.5.2016] submitted: /suiteName/t3
+LOG:[12:27:14 12.5.2016] active: /suiteName/t3
+LOG:[12:27:14 12.5.2016] complete: /suiteName/t1
+LOG:[12:27:14 12.5.2016] queued: /suiteName/t1
+LOG:[12:27:14 12.5.2016] complete: /suiteName/t2
+LOG:[12:27:14 12.5.2016] queued: /suiteName/t2
+LOG:[12:27:14 12.5.2016] complete: /suiteName/t3
+LOG:[12:27:14 12.5.2016] queued: /suiteName/t3
+LOG:[12:27:14 12.5.2016] queued: /suiteName
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /suiteName/t2
+LOG:[12:27:14 12.5.2016] submitted: /suiteName
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /suiteName/t2
+LOG:[12:27:14 12.5.2016] active: /suiteName
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] submitted: /suiteName/t3
+LOG:[12:27:14 12.5.2016] active: /suiteName/t3
+LOG:[12:27:14 12.5.2016] complete: /suiteName/t2
+LOG:[12:27:14 12.5.2016] queued: /suiteName/t2
+LOG:[12:27:14 12.5.2016] complete: /suiteName/t3
+LOG:[12:27:14 12.5.2016] queued: /suiteName/t3
+LOG:[12:27:14 12.5.2016] queued: /suiteName
+LOG:[12:27:14 12.5.2016] queued: /
+LOG:[12:27:14 12.5.2016] submitted: /suiteName/t1
+LOG:[12:27:14 12.5.2016] submitted: /suiteName
+LOG:[12:27:14 12.5.2016] submitted: /
+LOG:[12:27:14 12.5.2016] active: /suiteName/t1
+LOG:[12:27:14 12.5.2016] active: /suiteName
+LOG:[12:27:14 12.5.2016] active: /
+LOG:[12:27:14 12.5.2016] submitted: /suiteName/t2
+LOG:[12:27:14 12.5.2016] active: /suiteName/t2
+LOG:[12:27:14 12.5.2016] submitted: /suiteName/t3
+LOG:[12:27:14 12.5.2016] active: /suiteName/t3
+LOG:[12:27:14 12.5.2016] complete: /suiteName/t1
+LOG:[12:27:14 12.5.2016] complete: /suiteName/t2
+LOG:[12:27:14 12.5.2016] complete: /suiteName/t3
+LOG:[12:27:14 12.5.2016] complete: /suiteName
+LOG:[12:27:14 12.5.2016] complete: /
+MSG:[12:27:14 12.5.2016] Simulation complete in 11:00:00
diff --git a/CSim/test/data/test_analysys.def.log b/CSim/test/data/test_analysys.def.log
new file mode 100644
index 0000000..ffea4f5
--- /dev/null
+++ b/CSim/test/data/test_analysys.def.log
@@ -0,0 +1,4 @@
+LOG:[12:27:29 12.5.2016] queued: /test_analysys
+LOG:[12:27:29 12.5.2016] queued: /test_analysys/family
+LOG:[12:27:29 12.5.2016] queued: /test_analysys/family/t1
+LOG:[12:27:29 12.5.2016] queued: /test_analysys/family/t2
diff --git a/CSim/test/data/test_autocancel_ast_node_reset.def.log b/CSim/test/data/test_autocancel_ast_node_reset.def.log
new file mode 100644
index 0000000..5c22553
--- /dev/null
+++ b/CSim/test/data/test_autocancel_ast_node_reset.def.log
@@ -0,0 +1,46 @@
+LOG:[12:27:20 12.5.2016] queued: /s1
+LOG:[12:27:20 12.5.2016] queued: /s1/family
+LOG:[12:27:20 12.5.2016] queued: /s1/family/t
+LOG:[12:27:20 12.5.2016] queued: /s1/family/t2
+LOG:[12:27:20 12.5.2016] queued: /s1/family/t3
+LOG:[12:27:20 12.5.2016] queued: /s2
+LOG:[12:27:20 12.5.2016] queued: /s2/family
+LOG:[12:27:20 12.5.2016] queued: /s2/family/t
+LOG:[12:27:20 12.5.2016] queued: /s3
+LOG:[12:27:20 12.5.2016] queued: /s3/family
+LOG:[12:27:20 12.5.2016] queued: /s3/family/t
+LOG:[12:27:20 12.5.2016] submitted: /s2/family/t
+LOG:[12:27:20 12.5.2016] submitted: /s2/family
+LOG:[12:27:20 12.5.2016] submitted: /s2
+LOG:[12:27:20 12.5.2016] submitted: /
+LOG:[12:27:20 12.5.2016] active: /s2/family/t
+LOG:[12:27:20 12.5.2016] active: /s2/family
+LOG:[12:27:20 12.5.2016] active: /s2
+LOG:[12:27:20 12.5.2016] active: /
+LOG:[12:27:20 12.5.2016] submitted: /s3/family/t
+LOG:[12:27:20 12.5.2016] submitted: /s3/family
+LOG:[12:27:20 12.5.2016] submitted: /s3
+LOG:[12:27:20 12.5.2016] active: /s3/family/t
+LOG:[12:27:20 12.5.2016] active: /s3/family
+LOG:[12:27:20 12.5.2016] active: /s3
+LOG:[12:27:20 12.5.2016] complete: /s2/family/t
+LOG:[12:27:20 12.5.2016] complete: /s2/family
+LOG:[12:27:20 12.5.2016] complete: /s2
+LOG:[12:27:20 12.5.2016] submitted: /s1/family/t
+LOG:[12:27:20 12.5.2016] submitted: /s1/family
+LOG:[12:27:20 12.5.2016] submitted: /s1
+LOG:[12:27:20 12.5.2016] active: /s1/family/t
+LOG:[12:27:20 12.5.2016] active: /s1/family
+LOG:[12:27:20 12.5.2016] active: /s1
+LOG:[12:27:20 12.5.2016] complete: /s1/family/t2
+LOG:[12:27:20 12.5.2016] complete: /s1/family/t3
+LOG:[12:27:20 12.5.2016] complete: /s1/family/t
+LOG:[12:27:20 12.5.2016] complete: /s1/family
+LOG:[12:27:20 12.5.2016] complete: /s1
+LOG:[12:27:20 12.5.2016] complete: /s3/family/t
+LOG:[12:27:20 12.5.2016] complete: /s3/family
+LOG:[12:27:20 12.5.2016] complete: /s3
+LOG:[12:27:20 12.5.2016] complete: /
+MSG:[12:27:20 12.5.2016] autocancel SUITE:/s2
+MSG:[12:27:20 12.5.2016] autocancel SUITE:/s3
+MSG:[12:27:20 12.5.2016] Simulation complete in 01:00:00
diff --git a/CSim/test/data/test_autocancel_family_and_task.def.log b/CSim/test/data/test_autocancel_family_and_task.def.log
new file mode 100644
index 0000000..da86abd
--- /dev/null
+++ b/CSim/test/data/test_autocancel_family_and_task.def.log
@@ -0,0 +1,46 @@
+LOG:[12:27:20 12.5.2016] queued: /test_autocancel_9_10_hours_relative
+LOG:[12:27:20 12.5.2016] queued: /test_autocancel_9_10_hours_relative/family
+LOG:[12:27:20 12.5.2016] queued: /test_autocancel_9_10_hours_relative/family/t
+LOG:[12:27:20 12.5.2016] queued: /test_autocancel_1_2_hours_real
+LOG:[12:27:20 12.5.2016] queued: /test_autocancel_1_2_hours_real/family
+LOG:[12:27:20 12.5.2016] queued: /test_autocancel_1_2_hours_real/family/t
+LOG:[12:27:20 12.5.2016] queued: /test_autocancel_1_2_day_relative
+LOG:[12:27:20 12.5.2016] queued: /test_autocancel_1_2_day_relative/family
+LOG:[12:27:20 12.5.2016] queued: /test_autocancel_1_2_day_relative/family/t
+LOG:[12:27:20 12.5.2016] submitted: /test_autocancel_9_10_hours_relative/family/t
+LOG:[12:27:20 12.5.2016] submitted: /test_autocancel_9_10_hours_relative/family
+LOG:[12:27:20 12.5.2016] submitted: /test_autocancel_9_10_hours_relative
+LOG:[12:27:20 12.5.2016] submitted: /
+LOG:[12:27:20 12.5.2016] active: /test_autocancel_9_10_hours_relative/family/t
+LOG:[12:27:20 12.5.2016] active: /test_autocancel_9_10_hours_relative/family
+LOG:[12:27:20 12.5.2016] active: /test_autocancel_9_10_hours_relative
+LOG:[12:27:20 12.5.2016] active: /
+LOG:[12:27:20 12.5.2016] submitted: /test_autocancel_1_2_hours_real/family/t
+LOG:[12:27:20 12.5.2016] submitted: /test_autocancel_1_2_hours_real/family
+LOG:[12:27:20 12.5.2016] submitted: /test_autocancel_1_2_hours_real
+LOG:[12:27:20 12.5.2016] active: /test_autocancel_1_2_hours_real/family/t
+LOG:[12:27:20 12.5.2016] active: /test_autocancel_1_2_hours_real/family
+LOG:[12:27:20 12.5.2016] active: /test_autocancel_1_2_hours_real
+LOG:[12:27:20 12.5.2016] submitted: /test_autocancel_1_2_day_relative/family/t
+LOG:[12:27:20 12.5.2016] submitted: /test_autocancel_1_2_day_relative/family
+LOG:[12:27:20 12.5.2016] submitted: /test_autocancel_1_2_day_relative
+LOG:[12:27:20 12.5.2016] active: /test_autocancel_1_2_day_relative/family/t
+LOG:[12:27:20 12.5.2016] active: /test_autocancel_1_2_day_relative/family
+LOG:[12:27:20 12.5.2016] active: /test_autocancel_1_2_day_relative
+LOG:[12:27:20 12.5.2016] complete: /test_autocancel_9_10_hours_relative/family/t
+LOG:[12:27:20 12.5.2016] complete: /test_autocancel_9_10_hours_relative/family
+LOG:[12:27:20 12.5.2016] complete: /test_autocancel_9_10_hours_relative
+LOG:[12:27:20 12.5.2016] complete: /test_autocancel_1_2_hours_real/family/t
+LOG:[12:27:20 12.5.2016] complete: /test_autocancel_1_2_hours_real/family
+LOG:[12:27:20 12.5.2016] complete: /test_autocancel_1_2_hours_real
+LOG:[12:27:20 12.5.2016] complete: /test_autocancel_1_2_day_relative/family/t
+LOG:[12:27:20 12.5.2016] complete: /test_autocancel_1_2_day_relative/family
+LOG:[12:27:20 12.5.2016] complete: /test_autocancel_1_2_day_relative
+LOG:[12:27:20 12.5.2016] complete: /
+MSG:[12:27:20 12.5.2016] autocancel TASK:/test_autocancel_1_2_hours_real/family/t
+MSG:[12:27:20 12.5.2016] autocancel FAMILY:/test_autocancel_1_2_hours_real/family
+MSG:[12:27:20 12.5.2016] autocancel TASK:/test_autocancel_9_10_hours_relative/family/t
+MSG:[12:27:20 12.5.2016] autocancel FAMILY:/test_autocancel_9_10_hours_relative/family
+MSG:[12:27:20 12.5.2016] autocancel TASK:/test_autocancel_1_2_day_relative/family/t
+MSG:[12:27:20 12.5.2016] autocancel FAMILY:/test_autocancel_1_2_day_relative/family
+MSG:[12:27:20 12.5.2016] Simulation complete in 48:00:00
diff --git a/CSim/test/data/test_autocancel_suite.def.log b/CSim/test/data/test_autocancel_suite.def.log
new file mode 100644
index 0000000..f246c0c
--- /dev/null
+++ b/CSim/test/data/test_autocancel_suite.def.log
@@ -0,0 +1,43 @@
+LOG:[12:27:20 12.5.2016] queued: /test_autocancel_10_hours_relative
+LOG:[12:27:20 12.5.2016] queued: /test_autocancel_10_hours_relative/family
+LOG:[12:27:20 12.5.2016] queued: /test_autocancel_10_hours_relative/family/t
+LOG:[12:27:20 12.5.2016] queued: /test_autocancel_1_hours_real
+LOG:[12:27:20 12.5.2016] queued: /test_autocancel_1_hours_real/family
+LOG:[12:27:20 12.5.2016] queued: /test_autocancel_1_hours_real/family/t
+LOG:[12:27:20 12.5.2016] queued: /test_autocancel_1_day_relative
+LOG:[12:27:20 12.5.2016] queued: /test_autocancel_1_day_relative/family
+LOG:[12:27:20 12.5.2016] queued: /test_autocancel_1_day_relative/family/t
+LOG:[12:27:20 12.5.2016] submitted: /test_autocancel_10_hours_relative/family/t
+LOG:[12:27:20 12.5.2016] submitted: /test_autocancel_10_hours_relative/family
+LOG:[12:27:20 12.5.2016] submitted: /test_autocancel_10_hours_relative
+LOG:[12:27:20 12.5.2016] submitted: /
+LOG:[12:27:20 12.5.2016] active: /test_autocancel_10_hours_relative/family/t
+LOG:[12:27:20 12.5.2016] active: /test_autocancel_10_hours_relative/family
+LOG:[12:27:20 12.5.2016] active: /test_autocancel_10_hours_relative
+LOG:[12:27:20 12.5.2016] active: /
+LOG:[12:27:20 12.5.2016] submitted: /test_autocancel_1_hours_real/family/t
+LOG:[12:27:20 12.5.2016] submitted: /test_autocancel_1_hours_real/family
+LOG:[12:27:20 12.5.2016] submitted: /test_autocancel_1_hours_real
+LOG:[12:27:20 12.5.2016] active: /test_autocancel_1_hours_real/family/t
+LOG:[12:27:20 12.5.2016] active: /test_autocancel_1_hours_real/family
+LOG:[12:27:20 12.5.2016] active: /test_autocancel_1_hours_real
+LOG:[12:27:20 12.5.2016] submitted: /test_autocancel_1_day_relative/family/t
+LOG:[12:27:20 12.5.2016] submitted: /test_autocancel_1_day_relative/family
+LOG:[12:27:20 12.5.2016] submitted: /test_autocancel_1_day_relative
+LOG:[12:27:20 12.5.2016] active: /test_autocancel_1_day_relative/family/t
+LOG:[12:27:20 12.5.2016] active: /test_autocancel_1_day_relative/family
+LOG:[12:27:20 12.5.2016] active: /test_autocancel_1_day_relative
+LOG:[12:27:20 12.5.2016] complete: /test_autocancel_10_hours_relative/family/t
+LOG:[12:27:20 12.5.2016] complete: /test_autocancel_10_hours_relative/family
+LOG:[12:27:20 12.5.2016] complete: /test_autocancel_10_hours_relative
+LOG:[12:27:20 12.5.2016] complete: /test_autocancel_1_hours_real/family/t
+LOG:[12:27:20 12.5.2016] complete: /test_autocancel_1_hours_real/family
+LOG:[12:27:20 12.5.2016] complete: /test_autocancel_1_hours_real
+LOG:[12:27:20 12.5.2016] complete: /test_autocancel_1_day_relative/family/t
+LOG:[12:27:20 12.5.2016] complete: /test_autocancel_1_day_relative/family
+LOG:[12:27:20 12.5.2016] complete: /test_autocancel_1_day_relative
+LOG:[12:27:20 12.5.2016] complete: /
+MSG:[12:27:20 12.5.2016] autocancel SUITE:/test_autocancel_1_hours_real
+MSG:[12:27:20 12.5.2016] autocancel SUITE:/test_autocancel_10_hours_relative
+MSG:[12:27:20 12.5.2016] autocancel SUITE:/test_autocancel_1_day_relative
+MSG:[12:27:20 12.5.2016] Simulation complete in 24:00:00
diff --git a/CSim/test/data/test_autocancel_task.def.log b/CSim/test/data/test_autocancel_task.def.log
new file mode 100644
index 0000000..75a13ce
--- /dev/null
+++ b/CSim/test/data/test_autocancel_task.def.log
@@ -0,0 +1,43 @@
+LOG:[12:27:20 12.5.2016] queued: /test_autocancel_10_hours_relative
+LOG:[12:27:20 12.5.2016] queued: /test_autocancel_10_hours_relative/family
+LOG:[12:27:20 12.5.2016] queued: /test_autocancel_10_hours_relative/family/t
+LOG:[12:27:20 12.5.2016] queued: /test_autocancel_1_hours_real
+LOG:[12:27:20 12.5.2016] queued: /test_autocancel_1_hours_real/family
+LOG:[12:27:20 12.5.2016] queued: /test_autocancel_1_hours_real/family/t
+LOG:[12:27:20 12.5.2016] queued: /test_autocancel_1_day_relative
+LOG:[12:27:20 12.5.2016] queued: /test_autocancel_1_day_relative/family
+LOG:[12:27:20 12.5.2016] queued: /test_autocancel_1_day_relative/family/t
+LOG:[12:27:20 12.5.2016] submitted: /test_autocancel_10_hours_relative/family/t
+LOG:[12:27:20 12.5.2016] submitted: /test_autocancel_10_hours_relative/family
+LOG:[12:27:20 12.5.2016] submitted: /test_autocancel_10_hours_relative
+LOG:[12:27:20 12.5.2016] submitted: /
+LOG:[12:27:20 12.5.2016] active: /test_autocancel_10_hours_relative/family/t
+LOG:[12:27:20 12.5.2016] active: /test_autocancel_10_hours_relative/family
+LOG:[12:27:20 12.5.2016] active: /test_autocancel_10_hours_relative
+LOG:[12:27:20 12.5.2016] active: /
+LOG:[12:27:20 12.5.2016] submitted: /test_autocancel_1_hours_real/family/t
+LOG:[12:27:20 12.5.2016] submitted: /test_autocancel_1_hours_real/family
+LOG:[12:27:20 12.5.2016] submitted: /test_autocancel_1_hours_real
+LOG:[12:27:20 12.5.2016] active: /test_autocancel_1_hours_real/family/t
+LOG:[12:27:20 12.5.2016] active: /test_autocancel_1_hours_real/family
+LOG:[12:27:20 12.5.2016] active: /test_autocancel_1_hours_real
+LOG:[12:27:20 12.5.2016] submitted: /test_autocancel_1_day_relative/family/t
+LOG:[12:27:20 12.5.2016] submitted: /test_autocancel_1_day_relative/family
+LOG:[12:27:20 12.5.2016] submitted: /test_autocancel_1_day_relative
+LOG:[12:27:20 12.5.2016] active: /test_autocancel_1_day_relative/family/t
+LOG:[12:27:20 12.5.2016] active: /test_autocancel_1_day_relative/family
+LOG:[12:27:20 12.5.2016] active: /test_autocancel_1_day_relative
+LOG:[12:27:20 12.5.2016] complete: /test_autocancel_10_hours_relative/family/t
+LOG:[12:27:20 12.5.2016] complete: /test_autocancel_10_hours_relative/family
+LOG:[12:27:20 12.5.2016] complete: /test_autocancel_10_hours_relative
+LOG:[12:27:20 12.5.2016] complete: /test_autocancel_1_hours_real/family/t
+LOG:[12:27:20 12.5.2016] complete: /test_autocancel_1_hours_real/family
+LOG:[12:27:20 12.5.2016] complete: /test_autocancel_1_hours_real
+LOG:[12:27:20 12.5.2016] complete: /test_autocancel_1_day_relative/family/t
+LOG:[12:27:20 12.5.2016] complete: /test_autocancel_1_day_relative/family
+LOG:[12:27:20 12.5.2016] complete: /test_autocancel_1_day_relative
+LOG:[12:27:20 12.5.2016] complete: /
+MSG:[12:27:20 12.5.2016] autocancel TASK:/test_autocancel_1_hours_real/family/t
+MSG:[12:27:20 12.5.2016] autocancel TASK:/test_autocancel_10_hours_relative/family/t
+MSG:[12:27:20 12.5.2016] autocancel TASK:/test_autocancel_1_day_relative/family/t
+MSG:[12:27:20 12.5.2016] Simulation complete in 24:00:00
diff --git a/CSim/test/data/test_autocancel_task_1.def.log b/CSim/test/data/test_autocancel_task_1.def.log
new file mode 100644
index 0000000..abf5bac
--- /dev/null
+++ b/CSim/test/data/test_autocancel_task_1.def.log
@@ -0,0 +1,16 @@
+LOG:[11:16:30 24.2.2016] queued: /test_autocancel_task_1
+LOG:[11:16:30 24.2.2016] queued: /test_autocancel_task_1/family
+LOG:[11:16:30 24.2.2016] queued: /test_autocancel_task_1/family/t
+LOG:[11:16:30 24.2.2016] submitted: /test_autocancel_task_1/family/t
+LOG:[11:16:30 24.2.2016] submitted: /test_autocancel_task_1/family
+LOG:[11:16:30 24.2.2016] submitted: /test_autocancel_task_1
+LOG:[11:16:30 24.2.2016] submitted: /
+LOG:[11:16:30 24.2.2016] active: /test_autocancel_task_1/family/t
+LOG:[11:16:30 24.2.2016] active: /test_autocancel_task_1/family
+LOG:[11:16:30 24.2.2016] active: /test_autocancel_task_1
+LOG:[11:16:30 24.2.2016] active: /
+LOG:[11:16:30 24.2.2016] complete: /test_autocancel_task_1/family/t
+LOG:[11:16:30 24.2.2016] complete: /test_autocancel_task_1/family
+LOG:[11:16:30 24.2.2016] complete: /test_autocancel_task_1
+LOG:[11:16:30 24.2.2016] complete: /
+MSG:[11:16:30 24.2.2016] autocancel FAMILY:/test_autocancel_task_1/family
diff --git a/CSim/test/data/test_meter.def.log b/CSim/test/data/test_meter.def.log
new file mode 100644
index 0000000..b27048b
--- /dev/null
+++ b/CSim/test/data/test_meter.def.log
@@ -0,0 +1,20 @@
+LOG:[12:25:35 12.5.2016] queued: /test_meter
+LOG:[12:25:35 12.5.2016] queued: /test_meter/family
+LOG:[12:25:35 12.5.2016] queued: /test_meter/family/fc
+LOG:[12:25:35 12.5.2016] queued: /test_meter/family/half
+LOG:[12:25:35 12.5.2016] submitted: /test_meter/family/fc
+LOG:[12:25:35 12.5.2016] submitted: /test_meter/family
+LOG:[12:25:35 12.5.2016] submitted: /test_meter
+LOG:[12:25:35 12.5.2016] submitted: /
+LOG:[12:25:35 12.5.2016] active: /test_meter/family/fc
+LOG:[12:25:35 12.5.2016] active: /test_meter/family
+LOG:[12:25:35 12.5.2016] active: /test_meter
+LOG:[12:25:35 12.5.2016] active: /
+LOG:[12:25:35 12.5.2016] submitted: /test_meter/family/half
+LOG:[12:25:35 12.5.2016] active: /test_meter/family/half
+LOG:[12:25:35 12.5.2016] complete: /test_meter/family/half
+LOG:[12:25:35 12.5.2016] complete: /test_meter/family/fc
+LOG:[12:25:35 12.5.2016] complete: /test_meter/family
+LOG:[12:25:35 12.5.2016] complete: /test_meter
+LOG:[12:25:35 12.5.2016] complete: /
+MSG:[12:25:35 12.5.2016] Simulation complete in 00:00:00
diff --git a/CSim/test/data/test_multiple_times_and_dates.def.log b/CSim/test/data/test_multiple_times_and_dates.def.log
new file mode 100644
index 0000000..6c85203
--- /dev/null
+++ b/CSim/test/data/test_multiple_times_and_dates.def.log
@@ -0,0 +1,55 @@
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_dates
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_dates/family
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_dates/family/t
+LOG:[12:25:35 12.5.2016] submitted: /test_multiple_times_and_dates/family/t
+LOG:[12:25:35 12.5.2016] submitted: /test_multiple_times_and_dates/family
+LOG:[12:25:35 12.5.2016] submitted: /test_multiple_times_and_dates
+LOG:[12:25:35 12.5.2016] submitted: /
+LOG:[12:25:35 12.5.2016] active: /test_multiple_times_and_dates/family/t
+LOG:[12:25:35 12.5.2016] active: /test_multiple_times_and_dates/family
+LOG:[12:25:35 12.5.2016] active: /test_multiple_times_and_dates
+LOG:[12:25:35 12.5.2016] active: /
+LOG:[12:25:35 12.5.2016] complete: /test_multiple_times_and_dates/family/t
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_dates/family/t
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_dates/family
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_dates
+LOG:[12:25:35 12.5.2016] queued: /
+LOG:[12:25:35 12.5.2016] submitted: /test_multiple_times_and_dates/family/t
+LOG:[12:25:35 12.5.2016] submitted: /test_multiple_times_and_dates/family
+LOG:[12:25:35 12.5.2016] submitted: /test_multiple_times_and_dates
+LOG:[12:25:35 12.5.2016] submitted: /
+LOG:[12:25:35 12.5.2016] active: /test_multiple_times_and_dates/family/t
+LOG:[12:25:35 12.5.2016] active: /test_multiple_times_and_dates/family
+LOG:[12:25:35 12.5.2016] active: /test_multiple_times_and_dates
+LOG:[12:25:35 12.5.2016] active: /
+LOG:[12:25:35 12.5.2016] complete: /test_multiple_times_and_dates/family/t
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_dates/family/t
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_dates/family
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_dates
+LOG:[12:25:35 12.5.2016] queued: /
+LOG:[12:25:35 12.5.2016] submitted: /test_multiple_times_and_dates/family/t
+LOG:[12:25:35 12.5.2016] submitted: /test_multiple_times_and_dates/family
+LOG:[12:25:35 12.5.2016] submitted: /test_multiple_times_and_dates
+LOG:[12:25:35 12.5.2016] submitted: /
+LOG:[12:25:35 12.5.2016] active: /test_multiple_times_and_dates/family/t
+LOG:[12:25:35 12.5.2016] active: /test_multiple_times_and_dates/family
+LOG:[12:25:35 12.5.2016] active: /test_multiple_times_and_dates
+LOG:[12:25:35 12.5.2016] active: /
+LOG:[12:25:35 12.5.2016] complete: /test_multiple_times_and_dates/family/t
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_dates/family/t
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_dates/family
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_dates
+LOG:[12:25:35 12.5.2016] queued: /
+LOG:[12:25:35 12.5.2016] submitted: /test_multiple_times_and_dates/family/t
+LOG:[12:25:35 12.5.2016] submitted: /test_multiple_times_and_dates/family
+LOG:[12:25:35 12.5.2016] submitted: /test_multiple_times_and_dates
+LOG:[12:25:35 12.5.2016] submitted: /
+LOG:[12:25:35 12.5.2016] active: /test_multiple_times_and_dates/family/t
+LOG:[12:25:35 12.5.2016] active: /test_multiple_times_and_dates/family
+LOG:[12:25:35 12.5.2016] active: /test_multiple_times_and_dates
+LOG:[12:25:35 12.5.2016] active: /
+LOG:[12:25:35 12.5.2016] complete: /test_multiple_times_and_dates/family/t
+LOG:[12:25:35 12.5.2016] complete: /test_multiple_times_and_dates/family
+LOG:[12:25:35 12.5.2016] complete: /test_multiple_times_and_dates
+LOG:[12:25:35 12.5.2016] complete: /
+MSG:[12:25:35 12.5.2016] Simulation complete in 25:00:00
diff --git a/CSim/test/data/test_multiple_times_and_dates_hybrid.def.log b/CSim/test/data/test_multiple_times_and_dates_hybrid.def.log
new file mode 100644
index 0000000..1466f91
--- /dev/null
+++ b/CSim/test/data/test_multiple_times_and_dates_hybrid.def.log
@@ -0,0 +1,31 @@
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_dates_hybrid
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_dates_hybrid/family
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_dates_hybrid/family/t
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_dates_hybrid/family/t
+LOG:[12:25:35 12.5.2016] submitted: /test_multiple_times_and_dates_hybrid/family/t
+LOG:[12:25:35 12.5.2016] submitted: /test_multiple_times_and_dates_hybrid/family
+LOG:[12:25:35 12.5.2016] submitted: /test_multiple_times_and_dates_hybrid
+LOG:[12:25:35 12.5.2016] submitted: /
+LOG:[12:25:35 12.5.2016] active: /test_multiple_times_and_dates_hybrid/family/t
+LOG:[12:25:35 12.5.2016] active: /test_multiple_times_and_dates_hybrid/family
+LOG:[12:25:35 12.5.2016] active: /test_multiple_times_and_dates_hybrid
+LOG:[12:25:35 12.5.2016] active: /
+LOG:[12:25:35 12.5.2016] complete: /test_multiple_times_and_dates_hybrid/family/t
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_dates_hybrid/family/t
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_dates_hybrid/family/t
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_dates_hybrid/family
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_dates_hybrid
+LOG:[12:25:35 12.5.2016] queued: /
+LOG:[12:25:35 12.5.2016] submitted: /test_multiple_times_and_dates_hybrid/family/t
+LOG:[12:25:35 12.5.2016] submitted: /test_multiple_times_and_dates_hybrid/family
+LOG:[12:25:35 12.5.2016] submitted: /test_multiple_times_and_dates_hybrid
+LOG:[12:25:35 12.5.2016] submitted: /
+LOG:[12:25:35 12.5.2016] active: /test_multiple_times_and_dates_hybrid/family/t
+LOG:[12:25:35 12.5.2016] active: /test_multiple_times_and_dates_hybrid/family
+LOG:[12:25:35 12.5.2016] active: /test_multiple_times_and_dates_hybrid
+LOG:[12:25:35 12.5.2016] active: /
+LOG:[12:25:35 12.5.2016] complete: /test_multiple_times_and_dates_hybrid/family/t
+LOG:[12:25:35 12.5.2016] complete: /test_multiple_times_and_dates_hybrid/family
+LOG:[12:25:35 12.5.2016] complete: /test_multiple_times_and_dates_hybrid
+LOG:[12:25:35 12.5.2016] complete: /
+MSG:[12:25:35 12.5.2016] Simulation complete in 00:10:00
diff --git a/CSim/test/data/test_multiple_times_and_days.def.log b/CSim/test/data/test_multiple_times_and_days.def.log
new file mode 100644
index 0000000..f847342
--- /dev/null
+++ b/CSim/test/data/test_multiple_times_and_days.def.log
@@ -0,0 +1,55 @@
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_days
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_days/family
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_days/family/t
+LOG:[12:25:35 12.5.2016] submitted: /test_multiple_times_and_days/family/t
+LOG:[12:25:35 12.5.2016] submitted: /test_multiple_times_and_days/family
+LOG:[12:25:35 12.5.2016] submitted: /test_multiple_times_and_days
+LOG:[12:25:35 12.5.2016] submitted: /
+LOG:[12:25:35 12.5.2016] active: /test_multiple_times_and_days/family/t
+LOG:[12:25:35 12.5.2016] active: /test_multiple_times_and_days/family
+LOG:[12:25:35 12.5.2016] active: /test_multiple_times_and_days
+LOG:[12:25:35 12.5.2016] active: /
+LOG:[12:25:35 12.5.2016] complete: /test_multiple_times_and_days/family/t
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_days/family/t
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_days/family
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_days
+LOG:[12:25:35 12.5.2016] queued: /
+LOG:[12:25:35 12.5.2016] submitted: /test_multiple_times_and_days/family/t
+LOG:[12:25:35 12.5.2016] submitted: /test_multiple_times_and_days/family
+LOG:[12:25:35 12.5.2016] submitted: /test_multiple_times_and_days
+LOG:[12:25:35 12.5.2016] submitted: /
+LOG:[12:25:35 12.5.2016] active: /test_multiple_times_and_days/family/t
+LOG:[12:25:35 12.5.2016] active: /test_multiple_times_and_days/family
+LOG:[12:25:35 12.5.2016] active: /test_multiple_times_and_days
+LOG:[12:25:35 12.5.2016] active: /
+LOG:[12:25:35 12.5.2016] complete: /test_multiple_times_and_days/family/t
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_days/family/t
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_days/family
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_days
+LOG:[12:25:35 12.5.2016] queued: /
+LOG:[12:25:35 12.5.2016] submitted: /test_multiple_times_and_days/family/t
+LOG:[12:25:35 12.5.2016] submitted: /test_multiple_times_and_days/family
+LOG:[12:25:35 12.5.2016] submitted: /test_multiple_times_and_days
+LOG:[12:25:35 12.5.2016] submitted: /
+LOG:[12:25:35 12.5.2016] active: /test_multiple_times_and_days/family/t
+LOG:[12:25:35 12.5.2016] active: /test_multiple_times_and_days/family
+LOG:[12:25:35 12.5.2016] active: /test_multiple_times_and_days
+LOG:[12:25:35 12.5.2016] active: /
+LOG:[12:25:35 12.5.2016] complete: /test_multiple_times_and_days/family/t
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_days/family/t
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_days/family
+LOG:[12:25:35 12.5.2016] queued: /test_multiple_times_and_days
+LOG:[12:25:35 12.5.2016] queued: /
+LOG:[12:25:35 12.5.2016] submitted: /test_multiple_times_and_days/family/t
+LOG:[12:25:35 12.5.2016] submitted: /test_multiple_times_and_days/family
+LOG:[12:25:35 12.5.2016] submitted: /test_multiple_times_and_days
+LOG:[12:25:35 12.5.2016] submitted: /
+LOG:[12:25:35 12.5.2016] active: /test_multiple_times_and_days/family/t
+LOG:[12:25:35 12.5.2016] active: /test_multiple_times_and_days/family
+LOG:[12:25:35 12.5.2016] active: /test_multiple_times_and_days
+LOG:[12:25:35 12.5.2016] active: /
+LOG:[12:25:35 12.5.2016] complete: /test_multiple_times_and_days/family/t
+LOG:[12:25:35 12.5.2016] complete: /test_multiple_times_and_days/family
+LOG:[12:25:35 12.5.2016] complete: /test_multiple_times_and_days
+LOG:[12:25:35 12.5.2016] complete: /
+MSG:[12:25:35 12.5.2016] Simulation complete in 68:00:00
diff --git a/CSim/test/data/test_multiple_times_and_days_hybrid.def.log b/CSim/test/data/test_multiple_times_and_days_hybrid.def.log
new file mode 100644
index 0000000..06592d7
--- /dev/null
+++ b/CSim/test/data/test_multiple_times_and_days_hybrid.def.log
@@ -0,0 +1,45 @@
+LOG:[12:25:36 12.5.2016] queued: /test_multiple_times_and_days_hybrid
+LOG:[12:25:36 12.5.2016] queued: /test_multiple_times_and_days_hybrid/family
+LOG:[12:25:36 12.5.2016] queued: /test_multiple_times_and_days_hybrid/family/t
+LOG:[12:25:36 12.5.2016] queued: /test_multiple_times_and_days_hybrid/family/t
+LOG:[12:25:36 12.5.2016] submitted: /test_multiple_times_and_days_hybrid/family/t
+LOG:[12:25:36 12.5.2016] submitted: /test_multiple_times_and_days_hybrid/family
+LOG:[12:25:36 12.5.2016] submitted: /test_multiple_times_and_days_hybrid
+LOG:[12:25:36 12.5.2016] submitted: /
+LOG:[12:25:36 12.5.2016] active: /test_multiple_times_and_days_hybrid/family/t
+LOG:[12:25:36 12.5.2016] active: /test_multiple_times_and_days_hybrid/family
+LOG:[12:25:36 12.5.2016] active: /test_multiple_times_and_days_hybrid
+LOG:[12:25:36 12.5.2016] active: /
+LOG:[12:25:36 12.5.2016] complete: /test_multiple_times_and_days_hybrid/family/t
+LOG:[12:25:36 12.5.2016] queued: /test_multiple_times_and_days_hybrid/family/t
+LOG:[12:25:36 12.5.2016] queued: /test_multiple_times_and_days_hybrid/family/t
+LOG:[12:25:36 12.5.2016] queued: /test_multiple_times_and_days_hybrid/family
+LOG:[12:25:36 12.5.2016] queued: /test_multiple_times_and_days_hybrid
+LOG:[12:25:36 12.5.2016] queued: /
+LOG:[12:25:36 12.5.2016] submitted: /test_multiple_times_and_days_hybrid/family/t
+LOG:[12:25:36 12.5.2016] submitted: /test_multiple_times_and_days_hybrid/family
+LOG:[12:25:36 12.5.2016] submitted: /test_multiple_times_and_days_hybrid
+LOG:[12:25:36 12.5.2016] submitted: /
+LOG:[12:25:36 12.5.2016] active: /test_multiple_times_and_days_hybrid/family/t
+LOG:[12:25:36 12.5.2016] active: /test_multiple_times_and_days_hybrid/family
+LOG:[12:25:36 12.5.2016] active: /test_multiple_times_and_days_hybrid
+LOG:[12:25:36 12.5.2016] active: /
+LOG:[12:25:36 12.5.2016] complete: /test_multiple_times_and_days_hybrid/family/t
+LOG:[12:25:36 12.5.2016] queued: /test_multiple_times_and_days_hybrid/family/t
+LOG:[12:25:36 12.5.2016] queued: /test_multiple_times_and_days_hybrid/family/t
+LOG:[12:25:36 12.5.2016] queued: /test_multiple_times_and_days_hybrid/family
+LOG:[12:25:36 12.5.2016] queued: /test_multiple_times_and_days_hybrid
+LOG:[12:25:36 12.5.2016] queued: /
+LOG:[12:25:36 12.5.2016] submitted: /test_multiple_times_and_days_hybrid/family/t
+LOG:[12:25:36 12.5.2016] submitted: /test_multiple_times_and_days_hybrid/family
+LOG:[12:25:36 12.5.2016] submitted: /test_multiple_times_and_days_hybrid
+LOG:[12:25:36 12.5.2016] submitted: /
+LOG:[12:25:36 12.5.2016] active: /test_multiple_times_and_days_hybrid/family/t
+LOG:[12:25:36 12.5.2016] active: /test_multiple_times_and_days_hybrid/family
+LOG:[12:25:36 12.5.2016] active: /test_multiple_times_and_days_hybrid
+LOG:[12:25:36 12.5.2016] active: /
+LOG:[12:25:36 12.5.2016] complete: /test_multiple_times_and_days_hybrid/family/t
+LOG:[12:25:36 12.5.2016] complete: /test_multiple_times_and_days_hybrid/family
+LOG:[12:25:36 12.5.2016] complete: /test_multiple_times_and_days_hybrid
+LOG:[12:25:36 12.5.2016] complete: /
+MSG:[12:25:36 12.5.2016] Simulation complete in 20:00:00
diff --git a/CSim/test/data/test_repeat_date.def.log b/CSim/test/data/test_repeat_date.def.log
new file mode 100644
index 0000000..f05e2e0
--- /dev/null
+++ b/CSim/test/data/test_repeat_date.def.log
@@ -0,0 +1,212 @@
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date
+LOG:[12:27:21 12.5.2016] submitted: /
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date
+LOG:[12:27:21 12.5.2016] active: /
+LOG:[12:27:21 12.5.2016] complete: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] complete: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date
+LOG:[12:27:21 12.5.2016] queued: /
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date
+LOG:[12:27:21 12.5.2016] submitted: /
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date
+LOG:[12:27:21 12.5.2016] active: /
+LOG:[12:27:21 12.5.2016] complete: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] complete: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date
+LOG:[12:27:21 12.5.2016] queued: /
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date
+LOG:[12:27:21 12.5.2016] submitted: /
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date
+LOG:[12:27:21 12.5.2016] active: /
+LOG:[12:27:21 12.5.2016] complete: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] complete: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date
+LOG:[12:27:21 12.5.2016] queued: /
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date
+LOG:[12:27:21 12.5.2016] submitted: /
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date
+LOG:[12:27:21 12.5.2016] active: /
+LOG:[12:27:21 12.5.2016] complete: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] complete: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date
+LOG:[12:27:21 12.5.2016] queued: /
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date
+LOG:[12:27:21 12.5.2016] submitted: /
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date
+LOG:[12:27:21 12.5.2016] active: /
+LOG:[12:27:21 12.5.2016] complete: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] complete: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date
+LOG:[12:27:21 12.5.2016] queued: /
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date
+LOG:[12:27:21 12.5.2016] submitted: /
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date
+LOG:[12:27:21 12.5.2016] active: /
+LOG:[12:27:21 12.5.2016] complete: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] complete: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date
+LOG:[12:27:21 12.5.2016] queued: /
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date
+LOG:[12:27:21 12.5.2016] submitted: /
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date
+LOG:[12:27:21 12.5.2016] active: /
+LOG:[12:27:21 12.5.2016] complete: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] complete: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date
+LOG:[12:27:21 12.5.2016] queued: /
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date
+LOG:[12:27:21 12.5.2016] submitted: /
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date
+LOG:[12:27:21 12.5.2016] active: /
+LOG:[12:27:21 12.5.2016] complete: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] complete: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date
+LOG:[12:27:21 12.5.2016] queued: /
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date
+LOG:[12:27:21 12.5.2016] submitted: /
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date
+LOG:[12:27:21 12.5.2016] active: /
+LOG:[12:27:21 12.5.2016] complete: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] complete: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date
+LOG:[12:27:21 12.5.2016] queued: /
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date
+LOG:[12:27:21 12.5.2016] submitted: /
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date
+LOG:[12:27:21 12.5.2016] active: /
+LOG:[12:27:21 12.5.2016] complete: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] complete: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date
+LOG:[12:27:21 12.5.2016] queued: /
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date
+LOG:[12:27:21 12.5.2016] submitted: /
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date
+LOG:[12:27:21 12.5.2016] active: /
+LOG:[12:27:21 12.5.2016] complete: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] complete: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date
+LOG:[12:27:21 12.5.2016] queued: /
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date
+LOG:[12:27:21 12.5.2016] submitted: /
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date
+LOG:[12:27:21 12.5.2016] active: /
+LOG:[12:27:21 12.5.2016] complete: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] complete: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date
+LOG:[12:27:21 12.5.2016] queued: /
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date
+LOG:[12:27:21 12.5.2016] submitted: /
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date
+LOG:[12:27:21 12.5.2016] active: /
+LOG:[12:27:21 12.5.2016] complete: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] complete: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date
+LOG:[12:27:21 12.5.2016] queued: /
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date
+LOG:[12:27:21 12.5.2016] submitted: /
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date
+LOG:[12:27:21 12.5.2016] active: /
+LOG:[12:27:21 12.5.2016] complete: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] complete: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] queued: /test_repeat_date
+LOG:[12:27:21 12.5.2016] queued: /
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] submitted: /test_repeat_date
+LOG:[12:27:21 12.5.2016] submitted: /
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] active: /test_repeat_date
+LOG:[12:27:21 12.5.2016] active: /
+LOG:[12:27:21 12.5.2016] complete: /test_repeat_date/family/t
+LOG:[12:27:21 12.5.2016] complete: /test_repeat_date/family
+LOG:[12:27:21 12.5.2016] complete: /test_repeat_date
+LOG:[12:27:21 12.5.2016] complete: /
+MSG:[12:27:21 12.5.2016] Simulation complete in 346:00:00
diff --git a/CSim/test/data/test_repeat_date_for_loop.def.log b/CSim/test/data/test_repeat_date_for_loop.def.log
new file mode 100644
index 0000000..d3ccb60
--- /dev/null
+++ b/CSim/test/data/test_repeat_date_for_loop.def.log
@@ -0,0 +1,356 @@
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] submitted: /
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] active: /
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] queued: /
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] submitted: /
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] active: /
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] queued: /
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] submitted: /
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] active: /
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] queued: /
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] submitted: /
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] active: /
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] queued: /
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] submitted: /
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] active: /
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] queued: /
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] submitted: /
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] active: /
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] queued: /
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] submitted: /
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] active: /
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] queued: /
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] submitted: /
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] active: /
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] queued: /
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] submitted: /
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] active: /
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] queued: /
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] submitted: /
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] active: /
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] queued: /
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] submitted: /
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] active: /
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] queued: /
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] submitted: /
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] active: /
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] queued: /
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] submitted: /
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] active: /
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] queued: /
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] submitted: /
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] active: /
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] queued: /
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] submitted: /
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] active: /
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] queued: /
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] submitted: /
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] active: /
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] queued: /
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] submitted: /
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] active: /
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] queued: /
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] submitted: /
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] active: /
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] queued: /
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] submitted: /
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] active: /
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] queued: /
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] submitted: /
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] active: /
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] queued: /
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] submitted: /
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] active: /
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] queued: /
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] submitted: /
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] active: /
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] queued: /
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] submitted: /
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] active: /
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] queued: /
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] submitted: /
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] active: /
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] queued: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] queued: /
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] submitted: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] submitted: /
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] active: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] active: /
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family/t
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop/family
+LOG:[12:27:23 12.5.2016] complete: /test_repeat_date_for_loop
+LOG:[12:27:23 12.5.2016] complete: /
+MSG:[12:27:23 12.5.2016] Simulation complete in 530:00:00
diff --git a/CSim/test/data/test_repeat_date_for_loop2.def.log b/CSim/test/data/test_repeat_date_for_loop2.def.log
new file mode 100644
index 0000000..fbc8d26
--- /dev/null
+++ b/CSim/test/data/test_repeat_date_for_loop2.def.log
@@ -0,0 +1,681 @@
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] queued: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] queued: /
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] submitted: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] submitted: /
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] active: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] active: /
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family/t
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2/family
+LOG:[12:27:25 12.5.2016] complete: /test_repeat_date_for_loop2
+LOG:[12:27:25 12.5.2016] complete: /
+MSG:[12:27:25 12.5.2016] Simulation complete in 535:00:00
diff --git a/CSim/test/data/test_repeat_enumerated.def.log b/CSim/test/data/test_repeat_enumerated.def.log
new file mode 100644
index 0000000..898ab42
--- /dev/null
+++ b/CSim/test/data/test_repeat_enumerated.def.log
@@ -0,0 +1,44 @@
+LOG:[12:27:29 12.5.2016] queued: /test_repeat_enumerated
+LOG:[12:27:29 12.5.2016] queued: /test_repeat_enumerated/family
+LOG:[12:27:29 12.5.2016] queued: /test_repeat_enumerated/family/t1
+LOG:[12:27:29 12.5.2016] submitted: /test_repeat_enumerated/family/t1
+LOG:[12:27:29 12.5.2016] submitted: /test_repeat_enumerated/family
+LOG:[12:27:29 12.5.2016] submitted: /test_repeat_enumerated
+LOG:[12:27:29 12.5.2016] submitted: /
+LOG:[12:27:29 12.5.2016] active: /test_repeat_enumerated/family/t1
+LOG:[12:27:29 12.5.2016] active: /test_repeat_enumerated/family
+LOG:[12:27:29 12.5.2016] active: /test_repeat_enumerated
+LOG:[12:27:29 12.5.2016] active: /
+LOG:[12:27:29 12.5.2016] complete: /test_repeat_enumerated/family/t1
+LOG:[12:27:29 12.5.2016] complete: /test_repeat_enumerated/family
+LOG:[12:27:29 12.5.2016] queued: /test_repeat_enumerated/family
+LOG:[12:27:29 12.5.2016] queued: /test_repeat_enumerated/family/t1
+LOG:[12:27:29 12.5.2016] queued: /test_repeat_enumerated
+LOG:[12:27:29 12.5.2016] queued: /
+LOG:[12:27:29 12.5.2016] submitted: /test_repeat_enumerated/family/t1
+LOG:[12:27:29 12.5.2016] submitted: /test_repeat_enumerated/family
+LOG:[12:27:29 12.5.2016] submitted: /test_repeat_enumerated
+LOG:[12:27:29 12.5.2016] submitted: /
+LOG:[12:27:29 12.5.2016] active: /test_repeat_enumerated/family/t1
+LOG:[12:27:29 12.5.2016] active: /test_repeat_enumerated/family
+LOG:[12:27:29 12.5.2016] active: /test_repeat_enumerated
+LOG:[12:27:29 12.5.2016] active: /
+LOG:[12:27:29 12.5.2016] complete: /test_repeat_enumerated/family/t1
+LOG:[12:27:29 12.5.2016] complete: /test_repeat_enumerated/family
+LOG:[12:27:29 12.5.2016] queued: /test_repeat_enumerated/family
+LOG:[12:27:29 12.5.2016] queued: /test_repeat_enumerated/family/t1
+LOG:[12:27:29 12.5.2016] queued: /test_repeat_enumerated
+LOG:[12:27:29 12.5.2016] queued: /
+LOG:[12:27:29 12.5.2016] submitted: /test_repeat_enumerated/family/t1
+LOG:[12:27:29 12.5.2016] submitted: /test_repeat_enumerated/family
+LOG:[12:27:29 12.5.2016] submitted: /test_repeat_enumerated
+LOG:[12:27:29 12.5.2016] submitted: /
+LOG:[12:27:29 12.5.2016] active: /test_repeat_enumerated/family/t1
+LOG:[12:27:29 12.5.2016] active: /test_repeat_enumerated/family
+LOG:[12:27:29 12.5.2016] active: /test_repeat_enumerated
+LOG:[12:27:29 12.5.2016] active: /
+LOG:[12:27:29 12.5.2016] complete: /test_repeat_enumerated/family/t1
+LOG:[12:27:29 12.5.2016] complete: /test_repeat_enumerated/family
+LOG:[12:27:29 12.5.2016] complete: /test_repeat_enumerated
+LOG:[12:27:29 12.5.2016] complete: /
+MSG:[12:27:29 12.5.2016] Simulation complete in 00:00:00
diff --git a/CSim/test/data/test_repeat_integer.def.log b/CSim/test/data/test_repeat_integer.def.log
new file mode 100644
index 0000000..50b8a21
--- /dev/null
+++ b/CSim/test/data/test_repeat_integer.def.log
@@ -0,0 +1,75 @@
+LOG:[12:27:20 12.5.2016] queued: /suite
+LOG:[12:27:20 12.5.2016] queued: /suite/family
+LOG:[12:27:20 12.5.2016] queued: /suite/family/t0
+LOG:[12:27:20 12.5.2016] queued: /suite/family/t1
+LOG:[12:27:20 12.5.2016] submitted: /suite/family/t0
+LOG:[12:27:20 12.5.2016] submitted: /suite/family
+LOG:[12:27:20 12.5.2016] submitted: /suite
+LOG:[12:27:20 12.5.2016] submitted: /
+LOG:[12:27:20 12.5.2016] active: /suite/family/t0
+LOG:[12:27:20 12.5.2016] active: /suite/family
+LOG:[12:27:20 12.5.2016] active: /suite
+LOG:[12:27:20 12.5.2016] active: /
+LOG:[12:27:20 12.5.2016] submitted: /suite/family/t1
+LOG:[12:27:20 12.5.2016] active: /suite/family/t1
+LOG:[12:27:20 12.5.2016] complete: /suite/family/t0
+LOG:[12:27:20 12.5.2016] complete: /suite/family/t1
+LOG:[12:27:20 12.5.2016] complete: /suite/family
+LOG:[12:27:20 12.5.2016] queued: /suite/family
+LOG:[12:27:20 12.5.2016] queued: /suite/family/t0
+LOG:[12:27:20 12.5.2016] queued: /suite/family/t1
+LOG:[12:27:20 12.5.2016] queued: /suite
+LOG:[12:27:20 12.5.2016] queued: /
+LOG:[12:27:20 12.5.2016] submitted: /suite/family/t0
+LOG:[12:27:20 12.5.2016] submitted: /suite/family
+LOG:[12:27:20 12.5.2016] submitted: /suite
+LOG:[12:27:20 12.5.2016] submitted: /
+LOG:[12:27:20 12.5.2016] active: /suite/family/t0
+LOG:[12:27:20 12.5.2016] active: /suite/family
+LOG:[12:27:20 12.5.2016] active: /suite
+LOG:[12:27:20 12.5.2016] active: /
+LOG:[12:27:20 12.5.2016] submitted: /suite/family/t1
+LOG:[12:27:20 12.5.2016] active: /suite/family/t1
+LOG:[12:27:20 12.5.2016] complete: /suite/family/t0
+LOG:[12:27:20 12.5.2016] complete: /suite/family/t1
+LOG:[12:27:20 12.5.2016] complete: /suite/family
+LOG:[12:27:20 12.5.2016] complete: /suite
+LOG:[12:27:20 12.5.2016] queued: /suite
+LOG:[12:27:20 12.5.2016] queued: /suite/family
+LOG:[12:27:20 12.5.2016] queued: /suite/family/t0
+LOG:[12:27:20 12.5.2016] queued: /suite/family/t1
+LOG:[12:27:20 12.5.2016] queued: /
+LOG:[12:27:20 12.5.2016] submitted: /suite/family/t0
+LOG:[12:27:20 12.5.2016] submitted: /suite/family
+LOG:[12:27:20 12.5.2016] submitted: /suite
+LOG:[12:27:20 12.5.2016] submitted: /
+LOG:[12:27:20 12.5.2016] active: /suite/family/t0
+LOG:[12:27:20 12.5.2016] active: /suite/family
+LOG:[12:27:20 12.5.2016] active: /suite
+LOG:[12:27:20 12.5.2016] active: /
+LOG:[12:27:20 12.5.2016] submitted: /suite/family/t1
+LOG:[12:27:20 12.5.2016] active: /suite/family/t1
+LOG:[12:27:20 12.5.2016] complete: /suite/family/t0
+LOG:[12:27:20 12.5.2016] complete: /suite/family/t1
+LOG:[12:27:20 12.5.2016] complete: /suite/family
+LOG:[12:27:20 12.5.2016] queued: /suite/family
+LOG:[12:27:20 12.5.2016] queued: /suite/family/t0
+LOG:[12:27:20 12.5.2016] queued: /suite/family/t1
+LOG:[12:27:20 12.5.2016] queued: /suite
+LOG:[12:27:20 12.5.2016] queued: /
+LOG:[12:27:20 12.5.2016] submitted: /suite/family/t0
+LOG:[12:27:20 12.5.2016] submitted: /suite/family
+LOG:[12:27:20 12.5.2016] submitted: /suite
+LOG:[12:27:20 12.5.2016] submitted: /
+LOG:[12:27:20 12.5.2016] active: /suite/family/t0
+LOG:[12:27:20 12.5.2016] active: /suite/family
+LOG:[12:27:20 12.5.2016] active: /suite
+LOG:[12:27:20 12.5.2016] active: /
+LOG:[12:27:20 12.5.2016] submitted: /suite/family/t1
+LOG:[12:27:20 12.5.2016] active: /suite/family/t1
+LOG:[12:27:20 12.5.2016] complete: /suite/family/t0
+LOG:[12:27:20 12.5.2016] complete: /suite/family/t1
+LOG:[12:27:20 12.5.2016] complete: /suite/family
+LOG:[12:27:20 12.5.2016] complete: /suite
+LOG:[12:27:20 12.5.2016] complete: /
+MSG:[12:27:20 12.5.2016] Simulation complete in 00:00:00
diff --git a/CSim/test/data/test_repeat_integer_relative.def.log b/CSim/test/data/test_repeat_integer_relative.def.log
new file mode 100644
index 0000000..70f931b
--- /dev/null
+++ b/CSim/test/data/test_repeat_integer_relative.def.log
@@ -0,0 +1,59 @@
+LOG:[12:27:20 12.5.2016] queued: /test_repeat_integer_relative
+LOG:[12:27:20 12.5.2016] queued: /test_repeat_integer_relative/family
+LOG:[12:27:20 12.5.2016] queued: /test_repeat_integer_relative/family/t1
+LOG:[12:27:20 12.5.2016] submitted: /test_repeat_integer_relative/family/t1
+LOG:[12:27:20 12.5.2016] submitted: /test_repeat_integer_relative/family
+LOG:[12:27:20 12.5.2016] submitted: /test_repeat_integer_relative
+LOG:[12:27:20 12.5.2016] submitted: /
+LOG:[12:27:20 12.5.2016] active: /test_repeat_integer_relative/family/t1
+LOG:[12:27:20 12.5.2016] active: /test_repeat_integer_relative/family
+LOG:[12:27:20 12.5.2016] active: /test_repeat_integer_relative
+LOG:[12:27:20 12.5.2016] active: /
+LOG:[12:27:20 12.5.2016] complete: /test_repeat_integer_relative/family/t1
+LOG:[12:27:20 12.5.2016] complete: /test_repeat_integer_relative/family
+LOG:[12:27:20 12.5.2016] queued: /test_repeat_integer_relative/family
+LOG:[12:27:20 12.5.2016] queued: /test_repeat_integer_relative/family/t1
+LOG:[12:27:20 12.5.2016] queued: /test_repeat_integer_relative
+LOG:[12:27:20 12.5.2016] queued: /
+LOG:[12:27:20 12.5.2016] submitted: /test_repeat_integer_relative/family/t1
+LOG:[12:27:20 12.5.2016] submitted: /test_repeat_integer_relative/family
+LOG:[12:27:20 12.5.2016] submitted: /test_repeat_integer_relative
+LOG:[12:27:20 12.5.2016] submitted: /
+LOG:[12:27:20 12.5.2016] active: /test_repeat_integer_relative/family/t1
+LOG:[12:27:20 12.5.2016] active: /test_repeat_integer_relative/family
+LOG:[12:27:20 12.5.2016] active: /test_repeat_integer_relative
+LOG:[12:27:20 12.5.2016] active: /
+LOG:[12:27:20 12.5.2016] complete: /test_repeat_integer_relative/family/t1
+LOG:[12:27:20 12.5.2016] complete: /test_repeat_integer_relative/family
+LOG:[12:27:20 12.5.2016] complete: /test_repeat_integer_relative
+LOG:[12:27:20 12.5.2016] queued: /test_repeat_integer_relative
+LOG:[12:27:20 12.5.2016] queued: /test_repeat_integer_relative/family
+LOG:[12:27:20 12.5.2016] queued: /test_repeat_integer_relative/family/t1
+LOG:[12:27:20 12.5.2016] queued: /
+LOG:[12:27:20 12.5.2016] submitted: /test_repeat_integer_relative/family/t1
+LOG:[12:27:20 12.5.2016] submitted: /test_repeat_integer_relative/family
+LOG:[12:27:20 12.5.2016] submitted: /test_repeat_integer_relative
+LOG:[12:27:20 12.5.2016] submitted: /
+LOG:[12:27:20 12.5.2016] active: /test_repeat_integer_relative/family/t1
+LOG:[12:27:20 12.5.2016] active: /test_repeat_integer_relative/family
+LOG:[12:27:20 12.5.2016] active: /test_repeat_integer_relative
+LOG:[12:27:20 12.5.2016] active: /
+LOG:[12:27:20 12.5.2016] complete: /test_repeat_integer_relative/family/t1
+LOG:[12:27:20 12.5.2016] complete: /test_repeat_integer_relative/family
+LOG:[12:27:20 12.5.2016] queued: /test_repeat_integer_relative/family
+LOG:[12:27:20 12.5.2016] queued: /test_repeat_integer_relative/family/t1
+LOG:[12:27:20 12.5.2016] queued: /test_repeat_integer_relative
+LOG:[12:27:20 12.5.2016] queued: /
+LOG:[12:27:20 12.5.2016] submitted: /test_repeat_integer_relative/family/t1
+LOG:[12:27:20 12.5.2016] submitted: /test_repeat_integer_relative/family
+LOG:[12:27:20 12.5.2016] submitted: /test_repeat_integer_relative
+LOG:[12:27:20 12.5.2016] submitted: /
+LOG:[12:27:20 12.5.2016] active: /test_repeat_integer_relative/family/t1
+LOG:[12:27:20 12.5.2016] active: /test_repeat_integer_relative/family
+LOG:[12:27:20 12.5.2016] active: /test_repeat_integer_relative
+LOG:[12:27:20 12.5.2016] active: /
+LOG:[12:27:20 12.5.2016] complete: /test_repeat_integer_relative/family/t1
+LOG:[12:27:20 12.5.2016] complete: /test_repeat_integer_relative/family
+LOG:[12:27:20 12.5.2016] complete: /test_repeat_integer_relative
+LOG:[12:27:20 12.5.2016] complete: /
+MSG:[12:27:20 12.5.2016] Simulation complete in 00:08:00
diff --git a/CSim/test/data/test_repeat_string.def.log b/CSim/test/data/test_repeat_string.def.log
new file mode 100644
index 0000000..99550a2
--- /dev/null
+++ b/CSim/test/data/test_repeat_string.def.log
@@ -0,0 +1,30 @@
+LOG:[12:27:29 12.5.2016] queued: /test_repeat_string
+LOG:[12:27:29 12.5.2016] queued: /test_repeat_string/family
+LOG:[12:27:29 12.5.2016] queued: /test_repeat_string/family/t1
+LOG:[12:27:29 12.5.2016] submitted: /test_repeat_string/family/t1
+LOG:[12:27:29 12.5.2016] submitted: /test_repeat_string/family
+LOG:[12:27:29 12.5.2016] submitted: /test_repeat_string
+LOG:[12:27:29 12.5.2016] submitted: /
+LOG:[12:27:29 12.5.2016] active: /test_repeat_string/family/t1
+LOG:[12:27:29 12.5.2016] active: /test_repeat_string/family
+LOG:[12:27:29 12.5.2016] active: /test_repeat_string
+LOG:[12:27:29 12.5.2016] active: /
+LOG:[12:27:29 12.5.2016] complete: /test_repeat_string/family/t1
+LOG:[12:27:29 12.5.2016] complete: /test_repeat_string/family
+LOG:[12:27:29 12.5.2016] queued: /test_repeat_string/family
+LOG:[12:27:29 12.5.2016] queued: /test_repeat_string/family/t1
+LOG:[12:27:29 12.5.2016] queued: /test_repeat_string
+LOG:[12:27:29 12.5.2016] queued: /
+LOG:[12:27:29 12.5.2016] submitted: /test_repeat_string/family/t1
+LOG:[12:27:29 12.5.2016] submitted: /test_repeat_string/family
+LOG:[12:27:29 12.5.2016] submitted: /test_repeat_string
+LOG:[12:27:29 12.5.2016] submitted: /
+LOG:[12:27:29 12.5.2016] active: /test_repeat_string/family/t1
+LOG:[12:27:29 12.5.2016] active: /test_repeat_string/family
+LOG:[12:27:29 12.5.2016] active: /test_repeat_string
+LOG:[12:27:29 12.5.2016] active: /
+LOG:[12:27:29 12.5.2016] complete: /test_repeat_string/family/t1
+LOG:[12:27:29 12.5.2016] complete: /test_repeat_string/family
+LOG:[12:27:29 12.5.2016] complete: /test_repeat_string
+LOG:[12:27:29 12.5.2016] complete: /
+MSG:[12:27:29 12.5.2016] Simulation complete in 00:00:00
diff --git a/CSim/test/data/test_repeat_with_cron.def.log b/CSim/test/data/test_repeat_with_cron.def.log
new file mode 100644
index 0000000..3e9a515
--- /dev/null
+++ b/CSim/test/data/test_repeat_with_cron.def.log
@@ -0,0 +1,104 @@
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron/f
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron/f/plot
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron/f/plot/finish
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron/f/plot/checkdata
+LOG:[12:27:28 12.5.2016] submitted: /test_repeat_with_cron/f/plot/checkdata
+LOG:[12:27:28 12.5.2016] submitted: /test_repeat_with_cron/f/plot
+LOG:[12:27:28 12.5.2016] submitted: /test_repeat_with_cron/f
+LOG:[12:27:28 12.5.2016] submitted: /test_repeat_with_cron
+LOG:[12:27:28 12.5.2016] submitted: /
+LOG:[12:27:28 12.5.2016] active: /test_repeat_with_cron/f/plot/checkdata
+LOG:[12:27:28 12.5.2016] active: /test_repeat_with_cron/f/plot
+LOG:[12:27:28 12.5.2016] active: /test_repeat_with_cron/f
+LOG:[12:27:28 12.5.2016] active: /test_repeat_with_cron
+LOG:[12:27:28 12.5.2016] active: /
+LOG:[12:27:28 12.5.2016] complete: /test_repeat_with_cron/f/plot/finish
+LOG:[12:27:28 12.5.2016] complete: /test_repeat_with_cron/f/plot/checkdata
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron/f/plot/checkdata
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron/f/plot
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron/f
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron
+LOG:[12:27:28 12.5.2016] queued: /
+LOG:[12:27:28 12.5.2016] complete: /test_repeat_with_cron/f/plot
+LOG:[12:27:28 12.5.2016] complete: /test_repeat_with_cron/f/plot/finish
+LOG:[12:27:28 12.5.2016] complete: /test_repeat_with_cron/f/plot/checkdata
+LOG:[12:27:28 12.5.2016] complete: /test_repeat_with_cron/f
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron/f
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron/f/plot
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron/f/plot/finish
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron/f/plot/checkdata
+LOG:[12:27:28 12.5.2016] submitted: /test_repeat_with_cron/f/plot/checkdata
+LOG:[12:27:28 12.5.2016] submitted: /test_repeat_with_cron/f/plot
+LOG:[12:27:28 12.5.2016] submitted: /test_repeat_with_cron/f
+LOG:[12:27:28 12.5.2016] submitted: /test_repeat_with_cron
+LOG:[12:27:28 12.5.2016] submitted: /
+LOG:[12:27:28 12.5.2016] active: /test_repeat_with_cron/f/plot/checkdata
+LOG:[12:27:28 12.5.2016] active: /test_repeat_with_cron/f/plot
+LOG:[12:27:28 12.5.2016] active: /test_repeat_with_cron/f
+LOG:[12:27:28 12.5.2016] active: /test_repeat_with_cron
+LOG:[12:27:28 12.5.2016] active: /
+LOG:[12:27:28 12.5.2016] complete: /test_repeat_with_cron/f/plot/finish
+LOG:[12:27:28 12.5.2016] complete: /test_repeat_with_cron/f/plot/checkdata
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron/f/plot/checkdata
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron/f/plot
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron/f
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron
+LOG:[12:27:28 12.5.2016] queued: /
+LOG:[12:27:28 12.5.2016] complete: /test_repeat_with_cron/f/plot
+LOG:[12:27:28 12.5.2016] complete: /test_repeat_with_cron/f/plot/finish
+LOG:[12:27:28 12.5.2016] complete: /test_repeat_with_cron/f/plot/checkdata
+LOG:[12:27:28 12.5.2016] complete: /test_repeat_with_cron/f
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron/f
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron/f/plot
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron/f/plot/finish
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron/f/plot/checkdata
+LOG:[12:27:28 12.5.2016] submitted: /test_repeat_with_cron/f/plot/checkdata
+LOG:[12:27:28 12.5.2016] submitted: /test_repeat_with_cron/f/plot
+LOG:[12:27:28 12.5.2016] submitted: /test_repeat_with_cron/f
+LOG:[12:27:28 12.5.2016] submitted: /test_repeat_with_cron
+LOG:[12:27:28 12.5.2016] submitted: /
+LOG:[12:27:28 12.5.2016] active: /test_repeat_with_cron/f/plot/checkdata
+LOG:[12:27:28 12.5.2016] active: /test_repeat_with_cron/f/plot
+LOG:[12:27:28 12.5.2016] active: /test_repeat_with_cron/f
+LOG:[12:27:28 12.5.2016] active: /test_repeat_with_cron
+LOG:[12:27:28 12.5.2016] active: /
+LOG:[12:27:28 12.5.2016] complete: /test_repeat_with_cron/f/plot/finish
+LOG:[12:27:28 12.5.2016] complete: /test_repeat_with_cron/f/plot/checkdata
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron/f/plot/checkdata
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron/f/plot
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron/f
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron
+LOG:[12:27:28 12.5.2016] queued: /
+LOG:[12:27:28 12.5.2016] complete: /test_repeat_with_cron/f/plot
+LOG:[12:27:28 12.5.2016] complete: /test_repeat_with_cron/f/plot/finish
+LOG:[12:27:28 12.5.2016] complete: /test_repeat_with_cron/f/plot/checkdata
+LOG:[12:27:28 12.5.2016] complete: /test_repeat_with_cron/f
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron/f
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron/f/plot
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron/f/plot/finish
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron/f/plot/checkdata
+LOG:[12:27:28 12.5.2016] submitted: /test_repeat_with_cron/f/plot/checkdata
+LOG:[12:27:28 12.5.2016] submitted: /test_repeat_with_cron/f/plot
+LOG:[12:27:28 12.5.2016] submitted: /test_repeat_with_cron/f
+LOG:[12:27:28 12.5.2016] submitted: /test_repeat_with_cron
+LOG:[12:27:28 12.5.2016] submitted: /
+LOG:[12:27:28 12.5.2016] active: /test_repeat_with_cron/f/plot/checkdata
+LOG:[12:27:28 12.5.2016] active: /test_repeat_with_cron/f/plot
+LOG:[12:27:28 12.5.2016] active: /test_repeat_with_cron/f
+LOG:[12:27:28 12.5.2016] active: /test_repeat_with_cron
+LOG:[12:27:28 12.5.2016] active: /
+LOG:[12:27:28 12.5.2016] complete: /test_repeat_with_cron/f/plot/finish
+LOG:[12:27:28 12.5.2016] complete: /test_repeat_with_cron/f/plot/checkdata
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron/f/plot/checkdata
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron/f/plot
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron/f
+LOG:[12:27:28 12.5.2016] queued: /test_repeat_with_cron
+LOG:[12:27:28 12.5.2016] queued: /
+LOG:[12:27:28 12.5.2016] complete: /test_repeat_with_cron/f/plot
+LOG:[12:27:28 12.5.2016] complete: /test_repeat_with_cron/f/plot/finish
+LOG:[12:27:28 12.5.2016] complete: /test_repeat_with_cron/f/plot/checkdata
+LOG:[12:27:28 12.5.2016] complete: /test_repeat_with_cron/f
+LOG:[12:27:28 12.5.2016] complete: /test_repeat_with_cron
+LOG:[12:27:28 12.5.2016] complete: /
+MSG:[12:27:28 12.5.2016] Simulation complete in 72:02:00
diff --git a/CSim/test/data/test_time.def.log b/CSim/test/data/test_time.def.log
new file mode 100644
index 0000000..fef3fc0
--- /dev/null
+++ b/CSim/test/data/test_time.def.log
@@ -0,0 +1,16 @@
+LOG:[12:25:35 12.5.2016] queued: /test_time
+LOG:[12:25:35 12.5.2016] queued: /test_time/family
+LOG:[12:25:35 12.5.2016] queued: /test_time/family/t
+LOG:[12:25:35 12.5.2016] submitted: /test_time/family/t
+LOG:[12:25:35 12.5.2016] submitted: /test_time/family
+LOG:[12:25:35 12.5.2016] submitted: /test_time
+LOG:[12:25:35 12.5.2016] submitted: /
+LOG:[12:25:35 12.5.2016] active: /test_time/family/t
+LOG:[12:25:35 12.5.2016] active: /test_time/family
+LOG:[12:25:35 12.5.2016] active: /test_time
+LOG:[12:25:35 12.5.2016] active: /
+LOG:[12:25:35 12.5.2016] complete: /test_time/family/t
+LOG:[12:25:35 12.5.2016] complete: /test_time/family
+LOG:[12:25:35 12.5.2016] complete: /test_time
+LOG:[12:25:35 12.5.2016] complete: /
+MSG:[12:25:35 12.5.2016] Simulation complete in 00:01:00
diff --git a/CSim/test/data/test_time_and_date.def.log b/CSim/test/data/test_time_and_date.def.log
new file mode 100644
index 0000000..f9e01e0
--- /dev/null
+++ b/CSim/test/data/test_time_and_date.def.log
@@ -0,0 +1,16 @@
+LOG:[12:25:35 12.5.2016] queued: /test_time_and_date
+LOG:[12:25:35 12.5.2016] queued: /test_time_and_date/family
+LOG:[12:25:35 12.5.2016] queued: /test_time_and_date/family/t
+LOG:[12:25:35 12.5.2016] submitted: /test_time_and_date/family/t
+LOG:[12:25:35 12.5.2016] submitted: /test_time_and_date/family
+LOG:[12:25:35 12.5.2016] submitted: /test_time_and_date
+LOG:[12:25:35 12.5.2016] submitted: /
+LOG:[12:25:35 12.5.2016] active: /test_time_and_date/family/t
+LOG:[12:25:35 12.5.2016] active: /test_time_and_date/family
+LOG:[12:25:35 12.5.2016] active: /test_time_and_date
+LOG:[12:25:35 12.5.2016] active: /
+LOG:[12:25:35 12.5.2016] complete: /test_time_and_date/family/t
+LOG:[12:25:35 12.5.2016] complete: /test_time_and_date/family
+LOG:[12:25:35 12.5.2016] complete: /test_time_and_date
+LOG:[12:25:35 12.5.2016] complete: /
+MSG:[12:25:35 12.5.2016] Simulation complete in 00:01:00
diff --git a/CSim/test/data/test_time_and_tomorrows_date.def.log b/CSim/test/data/test_time_and_tomorrows_date.def.log
new file mode 100644
index 0000000..f7cd26c
--- /dev/null
+++ b/CSim/test/data/test_time_and_tomorrows_date.def.log
@@ -0,0 +1,16 @@
+LOG:[12:25:35 12.5.2016] queued: /test_time_and_tomorrows_date
+LOG:[12:25:35 12.5.2016] queued: /test_time_and_tomorrows_date/family
+LOG:[12:25:35 12.5.2016] queued: /test_time_and_tomorrows_date/family/t
+LOG:[12:25:35 12.5.2016] submitted: /test_time_and_tomorrows_date/family/t
+LOG:[12:25:35 12.5.2016] submitted: /test_time_and_tomorrows_date/family
+LOG:[12:25:35 12.5.2016] submitted: /test_time_and_tomorrows_date
+LOG:[12:25:35 12.5.2016] submitted: /
+LOG:[12:25:35 12.5.2016] active: /test_time_and_tomorrows_date/family/t
+LOG:[12:25:35 12.5.2016] active: /test_time_and_tomorrows_date/family
+LOG:[12:25:35 12.5.2016] active: /test_time_and_tomorrows_date
+LOG:[12:25:35 12.5.2016] active: /
+LOG:[12:25:35 12.5.2016] complete: /test_time_and_tomorrows_date/family/t
+LOG:[12:25:35 12.5.2016] complete: /test_time_and_tomorrows_date/family
+LOG:[12:25:35 12.5.2016] complete: /test_time_and_tomorrows_date
+LOG:[12:25:35 12.5.2016] complete: /
+MSG:[12:25:35 12.5.2016] Simulation complete in 24:01:00
diff --git a/CSim/test/data/test_time_series.def.log b/CSim/test/data/test_time_series.def.log
new file mode 100644
index 0000000..8ed8fbc
--- /dev/null
+++ b/CSim/test/data/test_time_series.def.log
@@ -0,0 +1,81 @@
+LOG:[12:25:35 12.5.2016] queued: /test_time_series
+LOG:[12:25:35 12.5.2016] queued: /test_time_series/family
+LOG:[12:25:35 12.5.2016] queued: /test_time_series/family/t
+LOG:[12:25:35 12.5.2016] submitted: /test_time_series/family/t
+LOG:[12:25:35 12.5.2016] submitted: /test_time_series/family
+LOG:[12:25:35 12.5.2016] submitted: /test_time_series
+LOG:[12:25:35 12.5.2016] submitted: /
+LOG:[12:25:35 12.5.2016] active: /test_time_series/family/t
+LOG:[12:25:35 12.5.2016] active: /test_time_series/family
+LOG:[12:25:35 12.5.2016] active: /test_time_series
+LOG:[12:25:35 12.5.2016] active: /
+LOG:[12:25:35 12.5.2016] complete: /test_time_series/family/t
+LOG:[12:25:35 12.5.2016] queued: /test_time_series/family/t
+LOG:[12:25:35 12.5.2016] queued: /test_time_series/family
+LOG:[12:25:35 12.5.2016] queued: /test_time_series
+LOG:[12:25:35 12.5.2016] queued: /
+LOG:[12:25:35 12.5.2016] submitted: /test_time_series/family/t
+LOG:[12:25:35 12.5.2016] submitted: /test_time_series/family
+LOG:[12:25:35 12.5.2016] submitted: /test_time_series
+LOG:[12:25:35 12.5.2016] submitted: /
+LOG:[12:25:35 12.5.2016] active: /test_time_series/family/t
+LOG:[12:25:35 12.5.2016] active: /test_time_series/family
+LOG:[12:25:35 12.5.2016] active: /test_time_series
+LOG:[12:25:35 12.5.2016] active: /
+LOG:[12:25:35 12.5.2016] complete: /test_time_series/family/t
+LOG:[12:25:35 12.5.2016] queued: /test_time_series/family/t
+LOG:[12:25:35 12.5.2016] queued: /test_time_series/family
+LOG:[12:25:35 12.5.2016] queued: /test_time_series
+LOG:[12:25:35 12.5.2016] queued: /
+LOG:[12:25:35 12.5.2016] submitted: /test_time_series/family/t
+LOG:[12:25:35 12.5.2016] submitted: /test_time_series/family
+LOG:[12:25:35 12.5.2016] submitted: /test_time_series
+LOG:[12:25:35 12.5.2016] submitted: /
+LOG:[12:25:35 12.5.2016] active: /test_time_series/family/t
+LOG:[12:25:35 12.5.2016] active: /test_time_series/family
+LOG:[12:25:35 12.5.2016] active: /test_time_series
+LOG:[12:25:35 12.5.2016] active: /
+LOG:[12:25:35 12.5.2016] complete: /test_time_series/family/t
+LOG:[12:25:35 12.5.2016] queued: /test_time_series/family/t
+LOG:[12:25:35 12.5.2016] queued: /test_time_series/family
+LOG:[12:25:35 12.5.2016] queued: /test_time_series
+LOG:[12:25:35 12.5.2016] queued: /
+LOG:[12:25:35 12.5.2016] submitted: /test_time_series/family/t
+LOG:[12:25:35 12.5.2016] submitted: /test_time_series/family
+LOG:[12:25:35 12.5.2016] submitted: /test_time_series
+LOG:[12:25:35 12.5.2016] submitted: /
+LOG:[12:25:35 12.5.2016] active: /test_time_series/family/t
+LOG:[12:25:35 12.5.2016] active: /test_time_series/family
+LOG:[12:25:35 12.5.2016] active: /test_time_series
+LOG:[12:25:35 12.5.2016] active: /
+LOG:[12:25:35 12.5.2016] complete: /test_time_series/family/t
+LOG:[12:25:35 12.5.2016] queued: /test_time_series/family/t
+LOG:[12:25:35 12.5.2016] queued: /test_time_series/family
+LOG:[12:25:35 12.5.2016] queued: /test_time_series
+LOG:[12:25:35 12.5.2016] queued: /
+LOG:[12:25:35 12.5.2016] submitted: /test_time_series/family/t
+LOG:[12:25:35 12.5.2016] submitted: /test_time_series/family
+LOG:[12:25:35 12.5.2016] submitted: /test_time_series
+LOG:[12:25:35 12.5.2016] submitted: /
+LOG:[12:25:35 12.5.2016] active: /test_time_series/family/t
+LOG:[12:25:35 12.5.2016] active: /test_time_series/family
+LOG:[12:25:35 12.5.2016] active: /test_time_series
+LOG:[12:25:35 12.5.2016] active: /
+LOG:[12:25:35 12.5.2016] complete: /test_time_series/family/t
+LOG:[12:25:35 12.5.2016] queued: /test_time_series/family/t
+LOG:[12:25:35 12.5.2016] queued: /test_time_series/family
+LOG:[12:25:35 12.5.2016] queued: /test_time_series
+LOG:[12:25:35 12.5.2016] queued: /
+LOG:[12:25:35 12.5.2016] submitted: /test_time_series/family/t
+LOG:[12:25:35 12.5.2016] submitted: /test_time_series/family
+LOG:[12:25:35 12.5.2016] submitted: /test_time_series
+LOG:[12:25:35 12.5.2016] submitted: /
+LOG:[12:25:35 12.5.2016] active: /test_time_series/family/t
+LOG:[12:25:35 12.5.2016] active: /test_time_series/family
+LOG:[12:25:35 12.5.2016] active: /test_time_series
+LOG:[12:25:35 12.5.2016] active: /
+LOG:[12:25:35 12.5.2016] complete: /test_time_series/family/t
+LOG:[12:25:35 12.5.2016] complete: /test_time_series/family
+LOG:[12:25:35 12.5.2016] complete: /test_time_series
+LOG:[12:25:35 12.5.2016] complete: /
+MSG:[12:25:35 12.5.2016] Simulation complete in 20:30:00
diff --git a/CSim/test/data/test_today.def.log b/CSim/test/data/test_today.def.log
new file mode 100644
index 0000000..1e3250a
--- /dev/null
+++ b/CSim/test/data/test_today.def.log
@@ -0,0 +1,29 @@
+LOG:[12:27:29 12.5.2016] queued: /test_today
+LOG:[12:27:29 12.5.2016] queued: /test_today/family
+LOG:[12:27:29 12.5.2016] queued: /test_today/family/t
+LOG:[12:27:29 12.5.2016] submitted: /test_today/family/t
+LOG:[12:27:29 12.5.2016] submitted: /test_today/family
+LOG:[12:27:29 12.5.2016] submitted: /test_today
+LOG:[12:27:29 12.5.2016] submitted: /
+LOG:[12:27:29 12.5.2016] active: /test_today/family/t
+LOG:[12:27:29 12.5.2016] active: /test_today/family
+LOG:[12:27:29 12.5.2016] active: /test_today
+LOG:[12:27:29 12.5.2016] active: /
+LOG:[12:27:29 12.5.2016] complete: /test_today/family/t
+LOG:[12:27:29 12.5.2016] queued: /test_today/family/t
+LOG:[12:27:29 12.5.2016] queued: /test_today/family
+LOG:[12:27:29 12.5.2016] queued: /test_today
+LOG:[12:27:29 12.5.2016] queued: /
+LOG:[12:27:29 12.5.2016] submitted: /test_today/family/t
+LOG:[12:27:29 12.5.2016] submitted: /test_today/family
+LOG:[12:27:29 12.5.2016] submitted: /test_today
+LOG:[12:27:29 12.5.2016] submitted: /
+LOG:[12:27:29 12.5.2016] active: /test_today/family/t
+LOG:[12:27:29 12.5.2016] active: /test_today/family
+LOG:[12:27:29 12.5.2016] active: /test_today
+LOG:[12:27:29 12.5.2016] active: /
+LOG:[12:27:29 12.5.2016] complete: /test_today/family/t
+LOG:[12:27:29 12.5.2016] complete: /test_today/family
+LOG:[12:27:29 12.5.2016] complete: /test_today
+LOG:[12:27:29 12.5.2016] complete: /
+MSG:[12:27:29 12.5.2016] Simulation complete in 00:10:00
diff --git a/CSim/test/data/test_today_time_and_date.def.log b/CSim/test/data/test_today_time_and_date.def.log
new file mode 100644
index 0000000..e7c727e
--- /dev/null
+++ b/CSim/test/data/test_today_time_and_date.def.log
@@ -0,0 +1,16 @@
+LOG:[12:27:29 12.5.2016] queued: /test_today_time_and_date
+LOG:[12:27:29 12.5.2016] queued: /test_today_time_and_date/family
+LOG:[12:27:29 12.5.2016] queued: /test_today_time_and_date/family/t
+LOG:[12:27:29 12.5.2016] submitted: /test_today_time_and_date/family/t
+LOG:[12:27:29 12.5.2016] submitted: /test_today_time_and_date/family
+LOG:[12:27:29 12.5.2016] submitted: /test_today_time_and_date
+LOG:[12:27:29 12.5.2016] submitted: /
+LOG:[12:27:29 12.5.2016] active: /test_today_time_and_date/family/t
+LOG:[12:27:29 12.5.2016] active: /test_today_time_and_date/family
+LOG:[12:27:29 12.5.2016] active: /test_today_time_and_date
+LOG:[12:27:29 12.5.2016] active: /
+LOG:[12:27:29 12.5.2016] complete: /test_today_time_and_date/family/t
+LOG:[12:27:29 12.5.2016] complete: /test_today_time_and_date/family
+LOG:[12:27:29 12.5.2016] complete: /test_today_time_and_date
+LOG:[12:27:29 12.5.2016] complete: /
+MSG:[12:27:29 12.5.2016] Simulation complete in 00:01:00
diff --git a/CSim/test/data/test_today_time_series.def.log b/CSim/test/data/test_today_time_series.def.log
new file mode 100644
index 0000000..b942ce6
--- /dev/null
+++ b/CSim/test/data/test_today_time_series.def.log
@@ -0,0 +1,68 @@
+LOG:[12:27:29 12.5.2016] queued: /test_today_time_series
+LOG:[12:27:29 12.5.2016] queued: /test_today_time_series/family
+LOG:[12:27:29 12.5.2016] queued: /test_today_time_series/family/t
+LOG:[12:27:29 12.5.2016] submitted: /test_today_time_series/family/t
+LOG:[12:27:29 12.5.2016] submitted: /test_today_time_series/family
+LOG:[12:27:29 12.5.2016] submitted: /test_today_time_series
+LOG:[12:27:29 12.5.2016] submitted: /
+LOG:[12:27:29 12.5.2016] active: /test_today_time_series/family/t
+LOG:[12:27:29 12.5.2016] active: /test_today_time_series/family
+LOG:[12:27:29 12.5.2016] active: /test_today_time_series
+LOG:[12:27:29 12.5.2016] active: /
+LOG:[12:27:29 12.5.2016] complete: /test_today_time_series/family/t
+LOG:[12:27:29 12.5.2016] queued: /test_today_time_series/family/t
+LOG:[12:27:29 12.5.2016] queued: /test_today_time_series/family
+LOG:[12:27:29 12.5.2016] queued: /test_today_time_series
+LOG:[12:27:29 12.5.2016] queued: /
+LOG:[12:27:29 12.5.2016] submitted: /test_today_time_series/family/t
+LOG:[12:27:29 12.5.2016] submitted: /test_today_time_series/family
+LOG:[12:27:29 12.5.2016] submitted: /test_today_time_series
+LOG:[12:27:29 12.5.2016] submitted: /
+LOG:[12:27:29 12.5.2016] active: /test_today_time_series/family/t
+LOG:[12:27:29 12.5.2016] active: /test_today_time_series/family
+LOG:[12:27:29 12.5.2016] active: /test_today_time_series
+LOG:[12:27:29 12.5.2016] active: /
+LOG:[12:27:29 12.5.2016] complete: /test_today_time_series/family/t
+LOG:[12:27:29 12.5.2016] queued: /test_today_time_series/family/t
+LOG:[12:27:29 12.5.2016] queued: /test_today_time_series/family
+LOG:[12:27:29 12.5.2016] queued: /test_today_time_series
+LOG:[12:27:29 12.5.2016] queued: /
+LOG:[12:27:29 12.5.2016] submitted: /test_today_time_series/family/t
+LOG:[12:27:29 12.5.2016] submitted: /test_today_time_series/family
+LOG:[12:27:29 12.5.2016] submitted: /test_today_time_series
+LOG:[12:27:29 12.5.2016] submitted: /
+LOG:[12:27:29 12.5.2016] active: /test_today_time_series/family/t
+LOG:[12:27:29 12.5.2016] active: /test_today_time_series/family
+LOG:[12:27:29 12.5.2016] active: /test_today_time_series
+LOG:[12:27:29 12.5.2016] active: /
+LOG:[12:27:29 12.5.2016] complete: /test_today_time_series/family/t
+LOG:[12:27:29 12.5.2016] queued: /test_today_time_series/family/t
+LOG:[12:27:29 12.5.2016] queued: /test_today_time_series/family
+LOG:[12:27:29 12.5.2016] queued: /test_today_time_series
+LOG:[12:27:29 12.5.2016] queued: /
+LOG:[12:27:29 12.5.2016] submitted: /test_today_time_series/family/t
+LOG:[12:27:29 12.5.2016] submitted: /test_today_time_series/family
+LOG:[12:27:29 12.5.2016] submitted: /test_today_time_series
+LOG:[12:27:29 12.5.2016] submitted: /
+LOG:[12:27:29 12.5.2016] active: /test_today_time_series/family/t
+LOG:[12:27:29 12.5.2016] active: /test_today_time_series/family
+LOG:[12:27:29 12.5.2016] active: /test_today_time_series
+LOG:[12:27:29 12.5.2016] active: /
+LOG:[12:27:29 12.5.2016] complete: /test_today_time_series/family/t
+LOG:[12:27:29 12.5.2016] queued: /test_today_time_series/family/t
+LOG:[12:27:29 12.5.2016] queued: /test_today_time_series/family
+LOG:[12:27:29 12.5.2016] queued: /test_today_time_series
+LOG:[12:27:29 12.5.2016] queued: /
+LOG:[12:27:29 12.5.2016] submitted: /test_today_time_series/family/t
+LOG:[12:27:29 12.5.2016] submitted: /test_today_time_series/family
+LOG:[12:27:29 12.5.2016] submitted: /test_today_time_series
+LOG:[12:27:29 12.5.2016] submitted: /
+LOG:[12:27:29 12.5.2016] active: /test_today_time_series/family/t
+LOG:[12:27:29 12.5.2016] active: /test_today_time_series/family
+LOG:[12:27:29 12.5.2016] active: /test_today_time_series
+LOG:[12:27:29 12.5.2016] active: /
+LOG:[12:27:29 12.5.2016] complete: /test_today_time_series/family/t
+LOG:[12:27:29 12.5.2016] complete: /test_today_time_series/family
+LOG:[12:27:29 12.5.2016] complete: /test_today_time_series
+LOG:[12:27:29 12.5.2016] complete: /
+MSG:[12:27:29 12.5.2016] Simulation complete in 16:30:00
diff --git a/CSim/test/data/test_two_autocancel_in_hierarchy.def.log b/CSim/test/data/test_two_autocancel_in_hierarchy.def.log
new file mode 100644
index 0000000..c0179d3
--- /dev/null
+++ b/CSim/test/data/test_two_autocancel_in_hierarchy.def.log
@@ -0,0 +1,17 @@
+LOG:[12:27:20 12.5.2016] queued: /test_two_autocancel_in_hierarchy
+LOG:[12:27:20 12.5.2016] queued: /test_two_autocancel_in_hierarchy/family
+LOG:[12:27:20 12.5.2016] queued: /test_two_autocancel_in_hierarchy/family/t
+LOG:[12:27:20 12.5.2016] submitted: /test_two_autocancel_in_hierarchy/family/t
+LOG:[12:27:20 12.5.2016] submitted: /test_two_autocancel_in_hierarchy/family
+LOG:[12:27:20 12.5.2016] submitted: /test_two_autocancel_in_hierarchy
+LOG:[12:27:20 12.5.2016] submitted: /
+LOG:[12:27:20 12.5.2016] active: /test_two_autocancel_in_hierarchy/family/t
+LOG:[12:27:20 12.5.2016] active: /test_two_autocancel_in_hierarchy/family
+LOG:[12:27:20 12.5.2016] active: /test_two_autocancel_in_hierarchy
+LOG:[12:27:20 12.5.2016] active: /
+LOG:[12:27:20 12.5.2016] complete: /test_two_autocancel_in_hierarchy/family/t
+LOG:[12:27:20 12.5.2016] complete: /test_two_autocancel_in_hierarchy/family
+LOG:[12:27:20 12.5.2016] complete: /test_two_autocancel_in_hierarchy
+LOG:[12:27:20 12.5.2016] complete: /
+MSG:[12:27:20 12.5.2016] autocancel FAMILY:/test_two_autocancel_in_hierarchy/family
+MSG:[12:27:20 12.5.2016] Simulation complete in 01:00:00
diff --git a/ecflow_4_0_7/Client/.gitignore b/Client/.gitignore
similarity index 100%
rename from ecflow_4_0_7/Client/.gitignore
rename to Client/.gitignore
diff --git a/Client/CMakeLists.txt b/Client/CMakeLists.txt
new file mode 100644
index 0000000..b677dca
--- /dev/null
+++ b/Client/CMakeLists.txt
@@ -0,0 +1,129 @@
+ # =======================================================
+ # LIB
+ # to list all sources to build use:
+ # cd $WK/Base
+ # find src -name \*.cpp --print
+ # =======================================================
+
+ # Excludes src/ClientMain.cpp
+list( APPEND srcs
+ src/Rtt.cpp
+ src/ClientEnvironment.cpp
+ src/ClientInvoker.cpp
+ src/Rtt.cpp
+ src/ClientOptions.cpp
+ src/UrlCmd.cpp
+)
+ecbuild_add_library( TARGET libclient
+ NOINSTALL
+ TYPE STATIC
+ SOURCES ${srcs}
+ LIBS base libparser node nodeattr core
+ pthread
+ INCLUDES src
+ ../ACore/src
+ ../ANattr/src
+ ../ANode/src
+ ../AParser/src
+ ../Base/src
+ ../Base/src/cts
+ ../Base/src/stc
+ )
+
+# ========================================================================
+# EXE ecflow_client
+ecbuild_add_executable( TARGET ecflow_client
+ SOURCES src/ClientMain.cpp
+ LIBS libclient
+ INCLUDES ${Boost_INCLUDE_DIRS}
+ )
+
+# Override default behaviour that add RPATHS during install
+# The only thing that seem to work is set INSTALL_RPATH to ""
+# Using SKIP_BUILD_RPATH,BUILD_WITH_INSTALL_RPATH,INSTALL_RPATH_USE_LINK_PATH
+# had no effect
+#
+SET_TARGET_PROPERTIES(ecflow_client PROPERTIES
+ INSTALL_RPATH ""
+ )
+
+# use, i.e. don't skip the full RPATH for the build tree
+#SET(CMAKE_SKIP_BUILD_RPATH FALSE)
+
+# when building, don't use the install RPATH already
+# (but later on when installing)
+#SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
+
+# the RPATH to be used when installing
+#SET(CMAKE_INSTALL_RPATH "")
+
+# don't add the automatically determined parts of the RPATH
+# which point to directories outside the build tree to the install RPATH
+#SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)
+
+
+# ================================================================================
+# TEST
+# Use following to populate list:
+# cd $WK/Client
+# find test -name \*.cpp | sort
+list( APPEND test_srcs
+ test/SCPort.cpp
+ test/TestCheckPtDefsCmd.cpp
+ test/TestClientEnvironment.cpp
+ test/TestClientInterface.cpp
+ test/TestClientInvoker.cpp
+ test/TestClientTimeout.cpp
+ test/TestGroupCmd.cpp
+ test/TestJobGenOnly.cpp
+ test/TestLifeCycle.cpp
+ test/TestLoadDefsCmd.cpp
+ test/TestPlugCmd.cpp
+ test/TestRtt.cpp
+ test/TestServer.cpp
+ test/TestServerAndLifeCycle.cpp
+ test/TestServerLoad.cpp
+ test/TestSignalSIGTERM.cpp
+ test/TestUrlCmd.cpp
+ test/TestWhiteListFile.cpp
+)
+ecbuild_add_test( TARGET s_client
+ BOOST
+ SOURCES ${test_srcs}
+ LIBS libclient
+ INCLUDES ../ANode/test
+ ../Base/test
+ TEST_DEPENDS u_base
+ )
+
+
+if (ENABLE_ALL_TESTS)
+ #
+ # Simple stand alone test
+ #
+ ecbuild_add_test( TARGET perf_test_large_defs
+ BOOST
+ SOURCES test/TestSinglePerf.cpp test/SCPort.cpp
+ LIBS libclient
+ INCLUDES ../ANode/test
+ ../Base/test
+ TEST_DEPENDS u_base
+ )
+
+ #
+ # test migration
+ #
+ ecbuild_add_test( TARGET m_test_migration
+ BOOST
+ SOURCES test/TestMigration.cpp test/SCPort.cpp
+ LIBS libclient
+ INCLUDES ../ANode/test
+ ../Base/test
+ TEST_DEPENDS u_base
+ )
+endif()
+
+# ===================================================================
+# install
+# ===================================================================
+install (TARGETS ecflow_client DESTINATION bin)
diff --git a/Client/Jamfile.jam b/Client/Jamfile.jam
new file mode 100644
index 0000000..3f45bab
--- /dev/null
+++ b/Client/Jamfile.jam
@@ -0,0 +1,137 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+#
+# Client
+#
+project theClient ;
+
+use-project theCore : ../ACore ;
+use-project theNodeAttr : ../ANattr ;
+use-project theNode : ../ANode ;
+use-project theParser : ../AParser ;
+use-project theBase : ../Base ;
+
+#
+# This should be in the site-config.jam file as a project wide requirement
+# however if this is done, it will not link since, lpthread appears twice
+# on the link line
+#
+lib pthread ;
+
+#
+# define DEBUG_CLIENT for additional debug
+#
+# Having a library avoid compile objects shared between client and test having
+# differing compilation properties
+#
+# Exclude ClientMain.cpp from the library.
+#
+# The <include> means we will automatically add this directory to the include path
+# of any other target that uses this lib
+#
+lib libclient : [ glob src/*.cpp : src/*Main.cpp ]
+ : <include>../ACore/src
+ <include>../ANattr/src
+ <include>../ANode/src
+ <include>../Base/src
+ <include>../AParser/src
+ <include>../Client/src
+ <variant>debug:<define>DEBUG
+ <link>static
+ <use>/theCore//core
+ <use>/theNode//node
+ <use>/theParser//libparser
+ <use>/theBase//base
+ <use>/site-config//boost_system
+ <use>/site-config//boost_serialization
+ <use>/site-config//boost_filesystem
+ <use>/site-config//boost_program_options
+ <use>/site-config//boost_datetime
+ :
+ : <include>../Client/src
+ ;
+
+#
+# client. This Just pulls in src/ClientMain.cpp
+#
+exe ecflow_client : [ glob src/*Main.cpp ]
+ /theCore//core
+ /theNodeAttr//nodeattr
+ /theNode//node
+ /theParser//libparser
+ /theBase//base
+ libclient
+ /site-config//boost_system
+ /site-config//boost_serialization
+ /site-config//boost_filesystem
+ /site-config//boost_program_options
+ /site-config//boost_datetime
+ pthread
+ : <variant>debug:<define>DEBUG
+ ;
+
+#
+# Tests for client. All test source code, by pulling in libclient we avoid
+# linking with ClientMain.cpp
+#
+exe s_client : [ glob test/*.cpp : test/TestSinglePerf.cpp test/TestMigration.cpp ]
+ pthread
+ /theCore//core
+ /theNodeAttr//nodeattr
+ /theNode//node
+ /theParser//libparser
+ /theBase//base
+ libclient
+ /site-config//boost_system
+ /site-config//boost_serialization
+ /site-config//boost_filesystem
+ /site-config//boost_program_options
+ /site-config//boost_datetime
+ /site-config//boost_test
+ : <include>../ANode/test
+ <include>../Base/test
+ <variant>debug:<define>DEBUG
+ ;
+
+exe perf_test_large_defs : [ glob test/TestSinglePerf.cpp ] [ glob test/SCPort.cpp ]
+ /theCore//core
+ /theNodeAttr//nodeattr
+ /theNode//node
+ /theParser//libparser
+ /theBase//base
+ libclient
+ pthread
+ /site-config//boost_system
+ /site-config//boost_serialization
+ /site-config//boost_filesystem
+ /site-config//boost_program_options
+ /site-config//boost_datetime
+ /site-config//boost_test
+ : <include>../ANode/test
+ <include>../Base/test
+ <variant>debug:<define>DEBUG
+ ;
+
+exe m_test_migration : [ glob test/TestMigration.cpp ] [ glob test/SCPort.cpp ]
+ /theCore//core
+ /theNodeAttr//nodeattr
+ /theNode//node
+ /theParser//libparser
+ /theBase//base
+ libclient
+ pthread
+ /site-config//boost_system
+ /site-config//boost_serialization
+ /site-config//boost_filesystem
+ /site-config//boost_program_options
+ /site-config//boost_datetime
+ /site-config//boost_test
+ : <include>../ANode/test
+ <include>../Base/test
+ <variant>debug:<define>DEBUG
+ ;
\ No newline at end of file
diff --git a/ecflow_4_0_7/Client/ecf_hostsfile b/Client/ecf_hostsfile
similarity index 100%
rename from ecflow_4_0_7/Client/ecf_hostsfile
rename to Client/ecf_hostsfile
diff --git a/Client/src/ClientEnvironment.cpp b/Client/src/ClientEnvironment.cpp
new file mode 100644
index 0000000..d6c8564
--- /dev/null
+++ b/Client/src/ClientEnvironment.cpp
@@ -0,0 +1,394 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name : ClientEnvironment
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <iostream>
+#include <fstream>
+#include <iterator>
+#include <stdlib.h> // for getenv()
+
+#include "boost/foreach.hpp"
+
+#include "ClientEnvironment.hpp"
+#include "ClientToServerCmd.hpp"
+#include "File.hpp"
+#include "Str.hpp"
+#include "Ecf.hpp"
+#include "boost_archive.hpp"
+#include "TimeStamp.hpp"
+#include "Version.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+
+// Provide upper and lower bounds for timeouts
+/// The timeout is used control for how long we continue to iterate over the hosts
+/// attempting to connect to the servers.
+#ifdef DEBUG
+#define MAX_TIMEOUT 120 // Max time in seconds for client to deliver message
+#define MIN_TIMEOUT 5 // Some reasonable value
+#else
+#define MAX_TIMEOUT 24*3600 // We don't try forever, only 24 hours
+#define MIN_TIMEOUT 10*60 // Some reasonable value
+#endif
+
+//#define DEBUG_ENVIRONMENT 1
+
+template<class T>
+ostream& operator<<(ostream& os, const vector<T>& v)
+{
+ copy(v.begin(), v.end(), ostream_iterator<T>(cout, "\n"));
+ return os;
+}
+
+
+ClientEnvironment::ClientEnvironment()
+: AbstractClientEnv(),
+ task_try_num_(1),timeout_(MAX_TIMEOUT),connect_timeout_(0),
+ denied_(false),no_ecf_(false), debug_(false),under_test_(false),
+ host_file_read_(false),
+ host_vec_index_(0),
+ allow_new_client_old_server_(0)
+{
+ init();
+}
+
+// test constructor
+ClientEnvironment::ClientEnvironment(const std::string& hostFile, const std::string& host, const std::string& port)
+: AbstractClientEnv(),
+ task_try_num_(1),timeout_(MAX_TIMEOUT),connect_timeout_(0),
+ denied_(false),no_ecf_(false), debug_(false),under_test_(false),
+ host_file_read_(false),
+ host_vec_index_(0),
+ allow_new_client_old_server_(0)
+{
+ init();
+
+ /// The host file passed in takes *precedence* over ECF_HOSTFILE environment variable read in init()
+ host_file_ = hostFile;
+
+ /// Override config, and environment.
+ if (!host.empty()) {
+ host_vec_.clear();
+ host_vec_.push_back(std::make_pair(host,port));
+ }
+}
+
+void ClientEnvironment::init()
+{
+ read_environment_variables();
+#ifdef DEBUG_ENVIRONMENT
+ std::cout << toString() << std::endl;
+#endif
+
+ // If no host specified default to local host and default port number
+ if (host_vec_.empty())
+ host_vec_.push_back(std::make_pair(Str::LOCALHOST(),Str::DEFAULT_PORT_NUMBER()));
+
+ // Program option are read in last, and will override any previous setting
+ // However program option are delayed until later. See notes in header
+ if (debug_) std::cout << toString() << "\n";
+}
+
+bool ClientEnvironment::get_next_host(std::string& errorMsg)
+{
+ if (debug_) cout << "ClientEnvironment::get_next_host() host_file_read_ = " << host_file_read_ << " host_file_ = " << host_file_ << "\n";
+ if (!host_file_read_ && !host_file_.empty()) {
+
+ if (!parseHostsFile(errorMsg)) {
+ return false;
+ }
+ host_file_read_ = true;
+ // SKIP OVER THE FIRST HOST, hence both paths need to increment host_vec_index_
+ }
+
+ host_vec_index_++;
+ if (host_vec_index_ >= static_cast<int>(host_vec_.size())) {
+ host_vec_index_ = 0;
+ }
+
+ return true;
+}
+
+// AbstractClientEnv functions: ============================================================================
+const std::string& ClientEnvironment::host() const
+{
+#ifdef DEBUG_ENVIRONMENT
+// cout << "ClientEnvironment::host() host_vec_index_ = " << host_vec_index_
+// << " host_vec_[host_vec_index_] = " << host_vec_[host_vec_index_] << "\n";
+#endif
+ assert( host_vec_index_ >=0 && host_vec_index_ < static_cast<int>(host_vec_.size()));
+ return host_vec_[host_vec_index_].first;
+}
+
+const std::string& ClientEnvironment::port() const
+{
+ assert( host_vec_index_ >=0 && host_vec_index_ < static_cast<int>(host_vec_.size()));
+ return host_vec_[host_vec_index_].second;
+}
+
+void ClientEnvironment::set_host_port(const std::string& the_host, const std::string& the_port)
+{
+ if (the_host.empty()) throw std::runtime_error("ClientEnvironment::set_host_port: Empty host specified ?");
+ if (the_port.empty()) throw std::runtime_error("ClientEnvironment::set_host_port: Empty port specified ?");
+ try { boost::lexical_cast<int>(the_port); }
+ catch ( boost::bad_lexical_cast& e) {
+ throw std::runtime_error("ClientEnvironment::set_host_port: Invalid port number " + the_port);
+ }
+
+ // Override default
+ host_vec_.clear();
+
+ // make sure there only one host:port in host_vec_
+ host_vec_.push_back(std::make_pair(the_host,the_port));
+
+ // Make sure we don't look in hosts file.
+ // When there is only one host:port in host_vec_, calling get_next_host() will always return host_vec_[0]
+ host_file_read_ = true;
+
+ // Update 'int allow_new_client_old_server_' *IF* ECF_ALLOW_NEW_CLIENT_OLD_SERVER set, and matches input host/port
+ update_allow_new_client_old_server(the_host,the_port);
+}
+
+bool ClientEnvironment::checkTaskPathAndPassword(std::string& errorMsg) const
+{
+ if ( task_path_.empty() ) {
+ errorMsg = "No task path specified for ECF_NAME \n";
+ return false;
+ }
+ if ( jobs_password_.empty() ) {
+ errorMsg = "No jobs password specified for ECF_PASS \n";
+ return false;
+ }
+ return true;
+}
+
+std::string ClientEnvironment::toString() const
+{
+ std::stringstream ss;
+ ss << TimeStamp::now() << Version::description() << "\n";
+ if (host_vec_.empty()) ss << " ECF_NODE =\n ";
+ else {
+ ss << " ECF_NODE : host_vec_index_ = " << host_vec_index_ << " host_vec_.size() = " << host_vec_.size() << "\n";
+ std::pair<std::string,std::string> i;
+ BOOST_FOREACH(i, host_vec_) { ss << " " << i.first << Str::COLON() << i.second << "\n";}
+ }
+ ss << " ECF_NAME = " << task_path_ << "\n";
+ ss << " ECF_PASS = " << jobs_password_ << "\n";
+ ss << " ECF_RID = " << remote_id_ << "\n";
+ ss << " ECF_TRYNO = " << task_try_num_ << "\n";
+ ss << " ECF_HOSTFILE = " << host_file_ << "\n";
+ ss << " ECF_TIMEOUT = " << timeout_ << "\n";
+ ss << " ECF_CONNECT_TIMEOUT = " << connect_timeout_ << "\n";
+ ss << " ECF_DENIED = " << denied_ << "\n";
+ assert( host_vec_index_ >=0 && host_vec_index_ < static_cast<int>(host_vec_.size()));
+ if (host_vec_.empty()) ss << " ECF_PORT = \n";
+ else ss << " ECF_PORT = " << host_vec_[host_vec_index_].second << "\n";
+ ss << " NO_ECF = " << no_ecf_ << "\n";
+ for(size_t i = 0; i < env_.size(); i++) {
+ ss << " " << env_[i].first << " = " << env_[i].second << "\n";
+ }
+ ss << " ECF_ALLOW_NEW_CLIENT_OLD_SERVER = " << env_ecf_new_client_old_server_ << "\n";
+ ss << " allow_new_client_old_server_ = " << allow_new_client_old_server_ << "\n";
+
+ ss << " ECF_DEBUG_CLIENT = " << debug_ << "\n";
+ return ss.str();
+}
+
+std::string ClientEnvironment::hostSpecified()
+{
+ char* theEnv = getenv(Str::ECF_NODE().c_str());
+ if (theEnv) {
+ return std::string(theEnv);
+ }
+ return std::string();
+}
+
+std::string ClientEnvironment::portSpecified()
+{
+ char* theEnv = getenv(Str::ECF_PORT().c_str());
+ if (theEnv) {
+ return std::string(theEnv);
+ }
+ return Str::DEFAULT_PORT_NUMBER();
+}
+
+
+void ClientEnvironment::read_environment_variables()
+{
+#ifdef DEBUG_ENVIRONMENT
+ std::cout << "ClientEnvironment::read_environment_variables()\n";
+#endif
+
+ if (getenv(Str::ECF_NAME().c_str())) task_path_ = getenv(Str::ECF_NAME().c_str());
+ if (getenv(Str::ECF_PASS().c_str())) jobs_password_ = getenv(Str::ECF_PASS().c_str());
+ if (getenv(Str::ECF_TRYNO().c_str())) task_try_num_ = atoi(getenv(Str::ECF_TRYNO().c_str()));
+ if (getenv("ECF_HOSTFILE")) host_file_ = getenv("ECF_HOSTFILE");
+ if (getenv(Str::ECF_RID().c_str())) remote_id_ = getenv(Str::ECF_RID().c_str());
+
+ if (getenv("ECF_TIMEOUT")) timeout_ = atoi(getenv("ECF_TIMEOUT")); // host file timeout
+ if( timeout_ > MAX_TIMEOUT ) timeout_ = MAX_TIMEOUT;
+ if( timeout_ < MIN_TIMEOUT ) timeout_ = MIN_TIMEOUT;
+
+ if (getenv("ECF_CONNECT_TIMEOUT")) connect_timeout_ = atoi(getenv("ECF_CONNECT_TIMEOUT")); // for test only
+
+ if (getenv("ECF_DENIED")) denied_ = true;
+ if (getenv("NO_ECF")) no_ecf_ = true;
+ if (getenv("ECF_DEBUG_CLIENT")) debug_ = true;
+
+ char *debug_level = getenv("ECF_DEBUG_LEVEL");
+ if (debug_level) {
+ try { Ecf::set_debug_level(boost::lexical_cast<unsigned int>(debug_level)); }
+ catch (...) { throw std::runtime_error("The environment variable ECF_DEBUG_LEVEL must be an unsigned integer."); }
+ }
+
+ /// Override the config settings *IF* any
+ std::string port = Str::DEFAULT_PORT_NUMBER();
+ std::string host = Str::LOCALHOST();
+ if (!host_vec_.empty()) {
+ host = host_vec_[0].first; // first entry is the config host
+ port = host_vec_[0].second; // first entry is the config port
+ }
+
+ if (getenv(Str::ECF_PORT().c_str())) {
+ port = getenv(Str::ECF_PORT().c_str());
+ host_vec_.clear(); // remove config settings, net effect is overriding
+ host_vec_.push_back(std::make_pair(host,port));
+ }
+
+ // Add the ECF_NODE host into list of hosts. Make sure its first in host_vec_
+ // as we want environment setting to take priority.
+ string env_host = hostSpecified();
+ if (!env_host.empty()) {
+ host = env_host;
+ host_vec_.clear(); // remove previous setting if any
+ host_vec_.push_back(std::make_pair(host,port));
+ }
+
+ if (getenv("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")) {
+ env_ecf_new_client_old_server_ = getenv("ECF_ALLOW_NEW_CLIENT_OLD_SERVER");
+ update_allow_new_client_old_server(host,port);
+ }
+}
+
+
+static std::string ecf_allow_new_client_old_server_error_msg(const std::string& env)
+{
+ int current_archive_version = ecf::boost_archive::version();
+ int previous_archive_version = current_archive_version -1;
+ std::stringstream ss;
+ ss << "\nFound environment variable ECF_ALLOW_NEW_CLIENT_OLD_SERVER=" << env << "\n";
+ ss << "ECF_ALLOW_NEW_CLIENT_OLD_SERVER must have one of the formats:\n";
+ ss << " ECF_ALLOW_NEW_CLIENT_OLD_SERVER=<int>\n";
+ ss << " ECF_ALLOW_NEW_CLIENT_OLD_SERVER=<host>:<port>:<int>,<host>:<port>:<int>,<host>:<port>:<int>\n";
+ ss << "Where <int> represents the archive version of the server. i.e the old server\n";
+ ss << "i.e. export ECF_ALLOW_NEW_CLIENT_OLD_SERVER=" << previous_archive_version << "\n";
+ ss << "or export ECF_ALLOW_NEW_CLIENT_OLD_SERVER=host1:3142:" << previous_archive_version << ",localhost:3142:" << previous_archive_version << "\n";
+ ss << "Please ensure host/port of the server you want connect too, is on the list";
+ return ss.str();
+}
+
+void ClientEnvironment::update_allow_new_client_old_server(const std::string& host, const std::string& port)
+{
+ // If we update host/port via command line, we need to update this again.
+ // cout << "ClientEnvironment::update_allow_new_client_old_server: host:" << host << " port:" << port << " env=" << env_ecf_new_client_old_server_ << "\n";
+
+ // In the viewer context, we can have multiple clients, some where client <-> server is compatible , others which are not:
+ // To allow for this, we expect following syntax:
+ // option 1/ export ECF_ALLOW_NEW_CLIENT_OLD_SERVER=<int>
+ // option 2/ export ECF_ALLOW_NEW_CLIENT_OLD_SERVER=<host>:<port>:<int>,<host>:<port>:<int>,<host>:<port>:<int>
+ // Where <int> represents the archive version of the server. i.e the old server.
+ // Only if the host/port matches in in our list do we update allow_new_client_old_server_
+ //
+ if (!env_ecf_new_client_old_server_.empty()) {
+ try {
+ // option 1:
+ allow_new_client_old_server_ = boost::lexical_cast<int>(env_ecf_new_client_old_server_);
+ }
+ catch (...) {
+ // cout << "option 2: Match the archive referring to *this* host/port specified.\n";
+ std::vector<std::string> list;
+ Str::split(env_ecf_new_client_old_server_,list,",");
+ if (list.empty()) throw std::runtime_error(ecf_allow_new_client_old_server_error_msg(env_ecf_new_client_old_server_));
+ // Find our host/port in the list:
+ for(size_t i = 0; i < list.size(); ++i) {
+ std::vector<std::string> host_port_archive;
+ Str::split( list[i], host_port_archive, ":");
+ if (host_port_archive.size() == 3) {
+ // cout << host_port_archive[0] << ":" << host_port_archive[1] << ":" << host_port_archive[2] << "\n";
+ if (host_port_archive[0] == host && host_port_archive[1] == port) {
+ try { allow_new_client_old_server_ = boost::lexical_cast<int>(host_port_archive[2]); break;}
+ catch (...) { throw std::runtime_error(ecf_allow_new_client_old_server_error_msg(env_ecf_new_client_old_server_));}
+ }
+ }
+ else { throw std::runtime_error(ecf_allow_new_client_old_server_error_msg(env_ecf_new_client_old_server_));}
+ }
+ }
+ }
+}
+
+
+bool ClientEnvironment::parseHostsFile(std::string& errorMsg)
+{
+ std::vector<std::string> lines;
+ if (!File::splitFileIntoLines(host_file_,lines,true /*IGNORE EMPTY LINES*/)) {
+ std::stringstream ss; ss << "ClientEnvironment:: Could not open the hosts file " << host_file_;
+ errorMsg += ss.str();
+ return false;
+ }
+
+ // The Home server and port should be at index 0.
+ std::string job_supplied_port = Str::DEFAULT_PORT_NUMBER();
+ if ( !host_vec_.empty() ) job_supplied_port = host_vec_[0].second;
+
+ // Each line should have the format: We only read in the first token.
+ // host # comment
+ // host:port # another comment
+ // If no port is specified we default to port read in from the environment
+ // if that was not specified we default to Str::DEFAULT_PORT_NUMBER()
+ std::vector<std::string>::iterator theEnd = lines.end();
+ for(std::vector<std::string>::iterator i = lines.begin(); i!= theEnd; ++i) {
+
+ std::vector< std::string > tokens;
+ Str::split((*i),tokens);
+ if (tokens.empty()) continue;
+ if (tokens[0][0] == '#') {
+// std::cout << "Ignoring line:'" << *i << "'\n";
+ continue;
+ }
+
+ std::string theBackupHost;
+ std::string thePort;
+
+ size_t colonPos = tokens[0].find_first_of(':');
+ if (colonPos == string::npos) {
+ // When the port is *NOT* specified, we must use the job supplied port.
+ // i.e. the one read in from the environment
+ theBackupHost = tokens[0];
+ thePort = job_supplied_port;
+// std::cout << "Host = " << theBackupHost << " Port is " << thePort << "\n";
+ }
+ else {
+ theBackupHost = tokens[0].substr(0,colonPos);
+ thePort = tokens[0].substr(colonPos+1);
+// std::cout << "Host = " << theBackupHost << " Port is specified " << thePort << "\n";
+ }
+
+ // std::cout << "Host = " << theBackupHost << " " << thePort << "\n";
+ host_vec_.push_back(std::make_pair(theBackupHost,thePort));
+ }
+
+ return true;
+}
diff --git a/Client/src/ClientEnvironment.hpp b/Client/src/ClientEnvironment.hpp
new file mode 100644
index 0000000..536d121
--- /dev/null
+++ b/Client/src/ClientEnvironment.hpp
@@ -0,0 +1,150 @@
+#ifndef CLIENT_ENVIRONMENT_HPP_
+#define CLIENT_ENVIRONMENT_HPP_
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name : ClientEnvironment
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "AbstractClientEnv.hpp"
+
+class ClientEnvironment : public AbstractClientEnv {
+public:
+ /// The constructor will load the environment
+ ClientEnvironment();
+
+ /// This constructor is only used in Test environment, as it allow the host file to be set
+ ClientEnvironment(const std::string& hostFile, const std::string& host = "", const std::string& port = "");
+
+ /// Forward compatibility allow new client to talk to old server
+ /// Only applies when return value is non zero, in which case, it will return
+ /// the boost archive version of the old server
+ /// For the command line this is read from ECF_ALLOW_NEW_CLIENT_OLD_SERVER
+ int allow_new_client_old_server() const { return allow_new_client_old_server_;}
+ void allow_new_client_old_server(int boost_archive_version) { allow_new_client_old_server_ = boost_archive_version;}
+
+ /// This controls for how long child commands continue trying to connect to Server before failing.
+ /// Maximum time in seconds for client to deliver message to server/servers. This is
+ /// typically 24 hours in a real environment. It is this long to allow operators to
+ /// recover from any crashes.
+ /// for the CHILD/task commands *ONLY*
+ /// Can be overriden by changing environment variable ECF_TIMEOUT
+ long max_child_cmd_timeout() const { return timeout_; }
+
+ /// Allow pur python jobs to override the ECF_TIMEOUT
+ void set_child_cmd_timeout(unsigned int t) { timeout_ = t; }
+
+ /// The timeout feature allow the client to fail gracefully in the case
+ /// where the server has died/crashed. The timeout will ensure the socket is closed.
+ /// allowing the server to be restarted without getting the address is use error.
+ /// Set the timeout for each client->server communication:
+ // connect : timeout_ second
+ // send request : timeout_ second
+ // receive reply : timeout_ second
+ // default is 0 second, which means take the timeout from the command/request
+ // The default can be overridden with ECF_CONNECT_TIMEOUT.
+ // This is useful when running valgrind --tool=callgrind which leads to
+ // massive slow down and disconnection from the client, when the server is still
+ // running.
+ // used for **test only**
+ int connect_timeout() const { return connect_timeout_;}
+
+ /// When called will demand load the ecf host file, and read the hosts.
+ /// Will then iterate over the host, when the end is reached will start over
+ /// If host can not be opened or errors occur returns false;
+ bool get_next_host(std::string& errorMsg);
+
+ /// If server denies client communication and this flag is set, exit with an error
+ /// Avoids 24hr hour connection attempt to server. Aids zombie control.
+ bool denied() const { return denied_;}
+
+ /// if NO_ECF is set then abort client immediately. Client should return success
+ /// useful when we want to test jobs stand-alone
+ bool no_ecf() const { return no_ecf_;}
+
+ /// for debug
+ std::string toString() const;
+
+ /// Return contents of ECF_NODE environment variable, Otherwise an EMPTY string
+ static std::string hostSpecified();
+
+ /// Returns of ECF_PORT,environment variable, otherwise returns Str::DEFAULT_PORT_NUMBER
+ static std::string portSpecified();
+
+ // Set the rid. Only needed to override in regression test, to avoid interference
+ // May be need a better name, is really the process id of running job.
+ // Needs to be the same value as supplied to child command init
+ void set_remote_id(const std::string& rid) { remote_id_ = rid; }
+
+// AbstractClientEnv functions:
+ virtual bool checkTaskPathAndPassword(std::string& errorMsg) const;
+ virtual const std::string& task_path() const { return task_path_; }
+ virtual int task_try_no() const { return task_try_num_; }
+ virtual const std::string& jobs_password() const { return jobs_password_ ;}
+ virtual const std::string& process_or_remote_id() const { return remote_id_; }
+ virtual void set_host_port(const std::string& host, const std::string& port);
+ virtual const std::string& host() const;
+ virtual const std::string& port() const;
+ virtual const std::vector<std::pair<std::string,std::string> >& env() const { return env_;}
+ virtual bool debug() const { return debug_;} //enabled if ECF_DEBUG_CLIENT set
+ virtual void set_test() { under_test_ = true; }
+ virtual bool under_test() const { return under_test_; }
+
+private:
+
+ std::string task_path_; // ECF_NAME = /aSuit/aFam/aTask
+ std::string jobs_password_; // ECF_PASS jobs password
+ std::string remote_id_; // ECF_RID process id of running job
+ int task_try_num_; // ECF_TRYNO. The task try number. The number of times we should submitted a job, if it is aborted
+ std::string host_file_; // ECF_HOSTFILE. File that lists the backup hosts, port numbers must match
+ long timeout_; // ECF_TIMEOUT. Host file iteration time out
+ int connect_timeout_; // default 0, ECF_CONNECT_TIMEOUT, connection timeout
+ bool denied_; // ECF_DENIED. If set ECF denies access, client will exit with failure")
+ bool no_ecf_; // NO_ECF. if defined then abort cmd immediately. useful when test jobs stand-alone
+
+ bool debug_; // For live debug, enabled by env variable ECF_CLIENT_DEBUG
+ bool under_test_; // Used in testing client interface
+ std::vector<std::pair<std::string,std::string> > env_; // For test allow env variable to be set on defs
+
+ bool host_file_read_; // to ensure we read host file only once
+ std::vector<std::pair<std::string, std::string> > host_vec_; // The list of host:port pairs
+ int host_vec_index_; // index into host_vec;
+ int allow_new_client_old_server_; // the boost archive version of old server, allow new client--> old server communication
+ std::string env_ecf_new_client_old_server_;
+
+ /// The option read from the command line.
+ friend class ClientOptions;
+
+ // Allow testing to override the task path set in the environment. In this constructor
+ friend class ClientInvoker;
+
+private:
+
+ void init();
+
+ void read_environment_variables(); /// Get the standard environment variables
+
+ void update_allow_new_client_old_server(const std::string& host, const std::string& port);
+
+ void taskPath(const std::string& s) { task_path_ = s;}
+ void set_jobs_password(const std::string& s) { jobs_password_ = s;}
+ void set_connect_timeout(int t) { connect_timeout_ = t;}
+
+ // Allow testing to add or update the environment in the Defs file
+ // Each pair is ( variable name, variable value )
+ void setEnv( const std::vector<std::pair<std::string,std::string> >& e) { env_= e;}
+
+ bool parseHostsFile(std::string& errorMsg);
+};
+
+#endif
diff --git a/Client/src/ClientInvoker.cpp b/Client/src/ClientInvoker.cpp
new file mode 100644
index 0000000..56f0df0
--- /dev/null
+++ b/Client/src/ClientInvoker.cpp
@@ -0,0 +1,1315 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <iostream>
+#include <iterator>
+#include <boost/date_time/posix_time/time_formatters.hpp> // requires boost date and time lib
+
+#include "ClientInvoker.hpp"
+#include "Client.hpp"
+#include "ClientEnvironment.hpp"
+#include "ClientOptions.hpp"
+#include "Defs.hpp"
+#include "ArgvCreator.hpp"
+#include "Str.hpp"
+#include "ClientToServerCmd.hpp"
+#include "Rtt.hpp"
+#include "Ecf.hpp"
+#include "DurationTimer.hpp"
+#include "TimeStamp.hpp"
+#include "Log.hpp"
+
+#ifdef DEBUG
+
+#if defined(HPUX) || defined(_AIX)
+#define RETRY_CONNECTION_PERIOD 2
+#define NEXT_HOST_POLL_PERIOD 2
+#else
+#define RETRY_CONNECTION_PERIOD 1
+#define NEXT_HOST_POLL_PERIOD 1
+#endif
+
+#else
+#define RETRY_CONNECTION_PERIOD 10
+#define NEXT_HOST_POLL_PERIOD 30
+#endif
+
+using namespace std;
+using namespace ecf;
+using namespace boost::posix_time;
+
+// ==================================================================================
+// class ClientInvoker
+ClientInvoker::ClientInvoker()
+: on_error_throw_exception_(true), cli_(false), test_(false),testInterface_(false),
+ connection_attempts_(2),retry_connection_period_(RETRY_CONNECTION_PERIOD),child_task_try_no_(0)
+{
+ if (clientEnv_.debug()) cout << TimeStamp::now() << "ClientInvoker::ClientInvoker(): 1=================start=================\n";
+}
+
+ClientInvoker::ClientInvoker(const std::string& host_port)
+: on_error_throw_exception_(true), cli_(false), test_(false),testInterface_(false),
+ connection_attempts_(2),retry_connection_period_(RETRY_CONNECTION_PERIOD),child_task_try_no_(0)
+{
+ if (clientEnv_.debug()) cout << TimeStamp::now() << "ClientInvoker::ClientInvoker(): 2=================start=================\n";
+ // assume format <host>:<port>
+ size_t colonPos = host_port.find_first_of(':');
+ if (colonPos == string::npos) throw std::runtime_error("ClientInvoker::ClientInvoker: expected <host>:<port> : no ':' found in " + host_port);
+ std::string host = host_port.substr(0,colonPos);
+ std::string port = host_port.substr(colonPos+1);
+ set_host_port(host,port);
+}
+
+ClientInvoker::ClientInvoker(const std::string& host, const std::string& port)
+: on_error_throw_exception_(true), cli_(false), test_(false),testInterface_(false),
+ connection_attempts_(2),retry_connection_period_(RETRY_CONNECTION_PERIOD)
+{
+ if (clientEnv_.debug()) cout << TimeStamp::now() << "ClientInvoker::ClientInvoker(): 3=================start=================\n";
+ set_host_port(host,port);
+}
+
+ClientInvoker::ClientInvoker(const std::string& host, int port)
+: on_error_throw_exception_(true), cli_(false), test_(false),testInterface_(false),
+ connection_attempts_(2),retry_connection_period_(RETRY_CONNECTION_PERIOD)
+{
+ if (clientEnv_.debug()) cout << TimeStamp::now() << "ClientInvoker::ClientInvoker(): 4=================start=================\n";
+ set_host_port(host, boost::lexical_cast<std::string>(port));
+}
+
+void ClientInvoker::set_host_port(const std::string& host, const std::string& port)
+{
+ // Allow host and port to be overridden.
+ // o Override environment setting
+ // o For child commands will override opening of ecf_hosts file
+ clientEnv_.set_host_port(host,port);
+}
+
+const std::string& ClientInvoker::host() const
+{
+ return clientEnv_.host();
+}
+const std::string& ClientInvoker::port() const
+{
+ return clientEnv_.port();
+}
+
+void ClientInvoker::allow_new_client_old_server(int archive_version_of_old_server)
+{
+ clientEnv_.allow_new_client_old_server(archive_version_of_old_server);
+}
+
+int ClientInvoker::allow_new_client_old_server() const
+{
+ return clientEnv_.allow_new_client_old_server();
+}
+
+void ClientInvoker::taskPath(const std::string& s) {
+ assert(!s.empty());
+ test_ = true;
+ clientEnv_.taskPath(s);
+}
+void ClientInvoker::set_jobs_password(const std::string& djp)
+{
+ test_ = true;
+ clientEnv_.set_jobs_password(djp);
+}
+
+void ClientInvoker::setEnv( const std::vector<std::pair<std::string,std::string> >& e) {
+ assert(!e.empty());
+ test_ = true;
+ clientEnv_.setEnv(e); // For test allow env variable to be set on defs
+}
+
+void ClientInvoker::testInterface() {
+ testInterface_ = true;
+ clientEnv_.set_test();
+}
+
+const std::string& ClientInvoker::process_or_remote_id() const
+{
+ return clientEnv_.process_or_remote_id();
+}
+
+void ClientInvoker::enable_logging(const std::string& log_file_name)
+{
+ Rtt::create(log_file_name);
+}
+
+void ClientInvoker::disable_logging()
+{
+ Rtt::destroy();
+}
+
+void ClientInvoker::set_connect_timeout(int t)
+{
+ clientEnv_.set_connect_timeout(t);
+}
+
+void ClientInvoker::set_connection_attempts( unsigned int attempts)
+{
+ connection_attempts_ = attempts;
+ if ( connection_attempts_ < 1 ) connection_attempts_ = 1;
+}
+
+int ClientInvoker::invoke(int argc, char* argv[]) const
+{
+ // Allow request to logged & allow logging of round trip time, Hence must be placed *before* RoundTripRecorder
+ RequestLogger request_logger(this);
+
+ // initialise start_time_ and rtt_,
+ RoundTripRecorder round_trip_recorder(this);
+
+ /// If NO_ECF set then abort immediately. returning success. Useful in testing jobs stand-alone.
+ if (clientEnv_.no_ecf()) { cout << "NO_ECF\n"; return 0; } // success
+
+ // Clear error message. For test. Don't keep previous error.
+ // i.e If next test passes when it shouldn't the wrong message is output
+ server_reply_.get_error_msg().clear();
+
+ Cmd_ptr cts_cmd;
+ try {
+ // read in program option, and construct the client to server commands from them.
+ // This will extract host/port from the environment/ args
+ // This will throw std::runtime_error for invalid arguments or options
+ cts_cmd = args_.parse(argc,argv,&clientEnv_);
+
+ // For --help and --debug, --load defs check_only no command is created
+ // When testInterface avoid writing to standard out.
+ if (!cts_cmd.get()) {
+ if (!testInterface_ && clientEnv_.debug()) {
+ cout << "args: "; for ( int x=0; x< argc; x++) cout << argv[x] << " "; cout << "\n";
+ }
+ return 0;
+ }
+ }
+ catch ( std::exception& e ) {
+ stringstream ss;
+ if (argc == 1) {
+ ss << Ecf::CLIENT_NAME() << ": No options specified\n";
+ ss << "Usage: " << Ecf::CLIENT_NAME() << " [OPTION]...\n";
+ ss << "Try '" << Ecf::CLIENT_NAME() << " --help' for list of options\n";
+ }
+ else {
+ ss << Ecf::CLIENT_NAME() << ": Caught exception whilst parsing arguments:\n" << e.what() << "\n";
+ ss << "args: "; for ( int x=0; x< argc; x++) ss << argv[x] << " "; ss << "\n";
+ }
+ server_reply_.set_error_msg(ss.str());
+ if (on_error_throw_exception_) throw std::runtime_error(server_reply_.error_msg());
+ return 1;
+ }
+ catch ( ... ) {
+ server_reply_.set_error_msg("ecflow:ClientInvoker: caught exception: Parsing arguments: unknown type!\n");
+ if (on_error_throw_exception_) throw std::runtime_error(server_reply_.error_msg());
+ return 1;
+ }
+
+ // Under debug we display round trip time for each request
+ request_logger.set_cts_cmd(cts_cmd);
+
+ int res = do_invoke_cmd( cts_cmd );
+ if (res == 1 && on_error_throw_exception_) throw std::runtime_error(server_reply_.error_msg());
+ return res;
+}
+
+int ClientInvoker::invoke( const std::string& arg ) const
+{
+ int argc = 2;
+ char* argv[] = { const_cast<char*>("ClientInvoker"), const_cast<char*>(arg.c_str()) };
+ return invoke(argc,argv);
+}
+
+int ClientInvoker::invoke( const std::vector<std::string>& args ) const
+{
+ std::vector<std::string> theArgs;
+ theArgs.push_back("ClientInvoker");
+ std::copy( args.begin(), args.end(), std::back_inserter(theArgs) );
+ ArgvCreator argvCreator( theArgs );
+ return invoke(argvCreator.argc(),argvCreator.argv());
+}
+
+int ClientInvoker::invoke(Cmd_ptr cts_cmd) const
+{
+ // assumes clients of Cmd_ptr constructor has caught exceptions
+
+ // Allow request to be logged & allow logging of round trip time, Hence must be placed *before* RoundTripRecorder
+ RequestLogger request_logger(this);
+
+ // initialise start_time_ and rtt_,
+ RoundTripRecorder round_trip_recorder(this);
+
+ // allow display of round trip time for each request
+ request_logger.set_cts_cmd(cts_cmd);
+
+ int res = do_invoke_cmd( cts_cmd );
+ if (res == 1 && on_error_throw_exception_) throw std::runtime_error(server_reply_.error_msg());
+ return res;
+}
+
+
+int ClientInvoker::do_invoke_cmd(Cmd_ptr cts_cmd) const
+{
+ if (clientEnv_.debug()) cout << "\n" << TimeStamp::now() << "ClientInvoker::do_invoke_cmd : on_error_throw_exception_(" << on_error_throw_exception_ << ")" << std::endl;
+ if (clientEnv_.no_ecf()) { cout << "NO_ECF\n"; return 0;} // success If NO_ECF set then abort immediately. returning success. Useful in testing jobs stand-alone.
+ if (testInterface_) return 0; // The testInterface_ flag allows testing of client interface, parsing of args, without needing to contact server
+ assert(!clientEnv_.host().empty()); // make sure host is NOT empty.
+
+ /// retry_connection_period_ specifies the time to wait, before retrying to connect to server.
+ /// Added to get round glitches in the network.
+ /// However for ping() always default to 1 second. This avoids 10 second wait in release mode.
+ /// We do this both for the CLI(command level interface) and python api
+ unsigned int retry_connection_period = retry_connection_period_;
+ if (cts_cmd->ping_cmd()) retry_connection_period = 1;
+
+ try {
+ /// report this message at least once. So client has a clue what's going on
+ bool report_block_client_on_home_server = false;
+ bool report_block_client_server_halted = false;
+ bool report_block_client_zombie_detected = false;
+
+ // We do not want to loop over the sms host list indefinitely hence we use a timer.
+ // The time out period is supplied via ClientEnvironment
+ bool never_polled = true; // don't wait for the first host only subsequent ones
+
+ while ( true ) {
+
+ // for each host try connecting several times. To compensate for network glitches.
+ int no_of_tries = connection_attempts_;
+ while ( no_of_tries > 0 ) {
+ try {
+ if (clientEnv_.debug()) { cout << TimeStamp::now() << "ClientInvoker: >>> About to invoke "; cts_cmd->print(cout); cout << " on " << client_env_host_port() << " : retry_connection_period(" << retry_connection_period << ") no_of_tries(" << no_of_tries << ") cmd_connect_timeout(" << cts_cmd->timeout() << ") ECF_CONNECT_TIMEOUT(" << clientEnv_.connect_timeout() << ")<<<" << endl;}
+
+ /// *** Each call to io_service.run(); is a *REQUEST* to the server ***
+ /// *** Hence we *MUST* clear the server_reply before each call *******
+ /// *** Found during zombie test. i.e when blocking, we were responding to previous, reply, since server_reply was not being reset
+ /// *Note* server_reply_.client_handle_ is kept until the next call to register a new client_handle
+ /// The client invoker can be used multiple times, hence keep value of defs, and client handle in server reply
+ /// However this is only done, if we are not using the Command Level Interface(cli)
+ server_reply_.clear_for_invoke(cli_);
+
+ boost::asio::io_service io_service;
+ Client theClient( io_service, cts_cmd , clientEnv_.host(), clientEnv_.port(), clientEnv_.connect_timeout() );
+ if (clientEnv_.allow_new_client_old_server() != 0) theClient.allow_new_client_old_server(clientEnv_.allow_new_client_old_server());
+ io_service.run();
+ if (clientEnv_.debug()) cout << TimeStamp::now() << "ClientInvoker: >>> After: io_service.run() <<<" << endl;;
+
+ /// Let see how the server responded if at all.
+ try {
+ /// will return false if further action required
+ if (theClient.handle_server_response( server_reply_, clientEnv_.debug() )) {
+ // The normal response. RoundTriprecorder will record in rtt_
+
+ // If the command was a delete_all command, reset client_handle
+ if (cts_cmd->delete_all_cmd()) {
+ ClientInvoker* non_const_this = const_cast<ClientInvoker*>(this);
+ non_const_this->reset();
+ }
+ return 0; // the normal exit path
+ }
+ }
+ catch (std::exception& e) {
+ server_reply_.set_error_msg( e.what() );
+ return 1;
+ }
+
+ if ( server_reply_.block_client_on_home_server()) {
+ // Valid reply from server. Typically waiting on a expression
+ // Ok _Block_ on _current_ server, and continue waiting, until server reply is ok
+ if (!report_block_client_on_home_server || clientEnv_.debug()) { cout << TimeStamp::now() << "ecflow:ClientInvoker: "; cts_cmd->print(cout); cout << " : " << client_env_host_port() << " : WAITING on home server, continue waiting\n";report_block_client_on_home_server = true;}
+ no_of_tries++;
+ }
+ else if (server_reply_.block_client_server_halted()) {
+ // Valid reply from server.
+ // fall through try again, then try other hosts
+ if (!report_block_client_server_halted || clientEnv_.debug()){ cout << TimeStamp::now() << "ecflow:ClientInvoker: "; cts_cmd->print(cout); cout << " : " << client_env_host_port() << " : blocking : server is HALTED, continue waiting\n";report_block_client_server_halted = true;}
+ }
+ else if (server_reply_.block_client_zombie_detected()) {
+ // Valid reply from server.
+ // fall through try again, then try other hosts
+ if (!report_block_client_zombie_detected || clientEnv_.debug()){ cout << TimeStamp::now() << "ecflow:ClientInvoker: "; cts_cmd->print(cout); cout << " : " << client_env_host_port() << " : blocking : zombie detected, continue waiting\n";report_block_client_zombie_detected = true;}
+ }
+ else if (server_reply_.client_request_failed()) {
+ // Valid reply from server
+ // This error is ONLY valid if we got a real reply from the server
+ // as opposed to some kind of connection errors. For connections errors
+ // we fall through and try again.
+ if (clientEnv_.debug()) {cout << TimeStamp::now() << "ecflow:ClientInvoker:"; cts_cmd->print(cout); cout << " failed : " << client_env_host_port() << " : " << server_reply_.error_msg() << "\n";}
+ return 1;
+ }
+ else {
+ std::cout << TimeStamp::now() << "ecflow:ClientInvoker: missed response? for request "; cts_cmd->print(cout); std::cout << " oops" << endl;
+ }
+ }
+ catch (std::exception& e) {
+ // *Some kind of connection error*: fall through and try again. Avoid this message when pinging, i.e to see if server is alive.
+ if (clientEnv_.debug()) { cerr << TimeStamp::now() << "ecflow:ClientInvoker: Connection error: (" << e.what() << ")" << endl; }
+ if (!cts_cmd->ping_cmd()) {
+ cerr << TimeStamp::now() << "ecflow:ClientInvoker: Connection error: (" << e.what() << ")" << endl;
+ }
+ }
+
+ // Wait a bit before trying to connect again, but only if no_of_tries > 0
+ no_of_tries--;
+ if (no_of_tries > 0) sleep( retry_connection_period );
+ }
+
+ // Don't bother with other hosts when:
+ // 1/ Testing
+ // 2/ ping-ing
+ // 3/ ECF_DENIED has been set
+ // 4/ Dealing with non tasks based request
+ if (!cts_cmd->connect_to_different_servers() || test_ || cts_cmd->ping_cmd() || clientEnv_.denied() ) {
+ std::stringstream ss;
+ ss << TimeStamp::now() << "Request( "; cts_cmd->print(ss) << " )";
+ if (clientEnv_.denied()) ss << " ECF_DENIED ";
+ ss << ", Failed to connect to " << client_env_host_port()
+ << ". After " << connection_attempts_ << " attempts. Is the server running ?\n";
+ // Only print client environment if not pinging
+ if (!cts_cmd->ping_cmd()) ss << "Client environment:\n" << clientEnv_.toString() << endl;
+ server_reply_.set_error_msg(ss.str());
+ return 1;
+ }
+
+ boost::posix_time::time_duration duration = microsec_clock::universal_time() - start_time_;
+ if (clientEnv_.debug()) { cout << "ClientInvoker: Time duration = " << duration.total_seconds() << " clientEnv_.max_child_cmd_timeout() = " << clientEnv_.max_child_cmd_timeout() << endl;}
+
+ if ( duration.total_seconds() >= clientEnv_.max_child_cmd_timeout() ) {
+ std::stringstream ss; ss << TimeStamp::now() << "ecflow:ClientInvoker: Timed out after " << clientEnv_.max_child_cmd_timeout() << " seconds : for " << client_env_host_port() << "\n";
+ std::string msg = ss.str();
+ cout << msg;
+ server_reply_.set_error_msg(msg);
+ return 1;
+ }
+
+ // The host is not playing ball, try the next host, will *restart* with home server, if end reached
+ // *get_next_host* *only* returns false if host exists, and parsing it fails
+ std::string current_host_port = client_env_host_port();
+
+ std::string local_error_msg;
+ if (!clientEnv_.get_next_host(local_error_msg)) {
+ /// Instead of exiting, Just spit out a warning
+ cout << TimeStamp::now() << "ecflow:ClientInvoker: "; cts_cmd->print(cout); cout << " get next host failed because: " << local_error_msg << endl;
+ }
+
+ cout << TimeStamp::now() << "ecflow:ClientInvoker: "; cts_cmd->print(cout); cout << " current host(" << current_host_port << ") trying next host(" << client_env_host_port() << ")" << endl;
+
+ if( never_polled ) never_polled = false; // To avoid the first wait
+ else sleep(NEXT_HOST_POLL_PERIOD);
+ }
+ }
+ catch ( std::exception& e ) {
+ stringstream ss; ss << TimeStamp::now() << "ecflow:ClientInvoker: caught exception: " << e.what() << "\n";
+ server_reply_.set_error_msg(ss.str());
+ }
+ catch ( ... ) {
+ stringstream ss; ss << TimeStamp::now() << "ecflow:ClientInvoker: Caught Exception of unknown type!\n";
+ server_reply_.set_error_msg(ss.str());
+ }
+ return 1;
+}
+
+
+void ClientInvoker::reset()
+{
+ server_reply_.set_client_defs( defs_ptr() );
+ server_reply_.set_client_node( node_ptr() );
+ server_reply_.set_client_handle( 0 );
+}
+
+//=====================================================================================
+// By using the command directly, it is a lot faster than using argc/argv
+// preserve old method to test api/command level interface.
+
+int ClientInvoker::getDefs() const
+{
+ if (testInterface_) return invoke(CtsApi::get());
+ return invoke( Cmd_ptr( new CtsNodeCmd( CtsNodeCmd::GET) ) );
+}
+
+int ClientInvoker::loadDefs(
+ const std::string& filePath,
+ bool force, /* true means overwrite suite of same name */
+ bool check_only /* true means don't send to server, just check only */
+) const
+{
+ if (testInterface_) return invoke(CtsApi::loadDefs(filePath,force,check_only));
+ Cmd_ptr cmd = LoadDefsCmd::create(filePath,force,check_only,&clientEnv_);
+ if (cmd) return invoke(cmd); // If check_only cmd will be empty
+ return 0;
+}
+
+int ClientInvoker::sync(defs_ptr& client_defs) const
+{
+ if (client_defs.get()) {
+ server_reply_.set_client_defs( client_defs );
+ if (testInterface_) return invoke(CtsApi::sync(server_reply_.client_handle(), client_defs->state_change_no(), client_defs->modify_change_no()));
+ return invoke( Cmd_ptr( new CSyncCmd(CSyncCmd::SYNC,server_reply_.client_handle(), client_defs->state_change_no(), client_defs->modify_change_no() ) ) );
+ }
+
+ if (testInterface_) return invoke(CtsApi::get());
+ int res = invoke( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::GET)));
+ if (res == 0) {
+ client_defs = server_reply_.client_defs(); // update change number
+ }
+ return res;
+}
+
+int ClientInvoker::sync_local() const
+{
+ defs_ptr defs = server_reply_.client_defs();
+
+ if (defs.get()) {
+
+ // Prevent infinite loops in change observers.
+ // This can be removed when we do the new ecflowview. TODO
+ if ( defs->in_notification()) {
+ std::cout << "ecflow:ClientInvoker::sync_local() called in the middle of notification. Ignoring..... \n";
+ return 0;
+ }
+
+ if (testInterface_) return invoke(CtsApi::sync(server_reply_.client_handle(),defs->state_change_no(), defs->modify_change_no()));
+ return invoke( Cmd_ptr( new CSyncCmd(CSyncCmd::SYNC,server_reply_.client_handle(), defs->state_change_no(), defs->modify_change_no() ) ) );
+ }
+ // If we have a handle return the defs, with the registered suites, else returns the full defs
+ if (testInterface_) return invoke(CtsApi::sync_full(server_reply_.client_handle()));
+ return invoke( Cmd_ptr( new CSyncCmd(server_reply_.client_handle()) ) );
+}
+
+int ClientInvoker::news(defs_ptr& client_defs) const
+{
+ if (client_defs.get()) {
+ if (testInterface_) return invoke(CtsApi::news(server_reply_.client_handle(),client_defs->state_change_no(), client_defs->modify_change_no()));
+ return invoke( Cmd_ptr( new CSyncCmd(CSyncCmd::NEWS,server_reply_.client_handle(), client_defs->state_change_no(), client_defs->modify_change_no() ) ) );
+ }
+ server_reply_.set_error_msg("The client definition is empty.");
+ if (on_error_throw_exception_) throw std::runtime_error(server_reply_.error_msg());
+ return 1;
+}
+
+int ClientInvoker::news_local() const
+{
+ defs_ptr defs = server_reply_.client_defs();
+ if (defs.get()) {
+ if (testInterface_) return invoke(CtsApi::news(server_reply_.client_handle(), defs->state_change_no(), defs->modify_change_no()));
+ return invoke( Cmd_ptr( new CSyncCmd(CSyncCmd::NEWS,server_reply_.client_handle(), defs->state_change_no(), defs->modify_change_no() ) ) );
+ }
+
+ // There is no local defs, i.e first time call, The default client handle should be 0.
+ // go with defaults for state and modify change numbers
+ // User is expected to call sync_local(), which will update local defs.
+ if (testInterface_) return invoke(CtsApi::news(server_reply_.client_handle(), 0, 0));
+ return invoke( Cmd_ptr( new CSyncCmd(CSyncCmd::NEWS,server_reply_.client_handle(), 0, 0 ) ) );
+}
+//=====================================================================================
+int ClientInvoker::restartServer() const
+{
+ if (testInterface_) return invoke(CtsApi::restartServer());
+ return invoke(Cmd_ptr(new CtsCmd(CtsCmd::RESTART_SERVER)));
+}
+int ClientInvoker::haltServer() const
+{
+ if (testInterface_) return invoke(CtsApi::haltServer(true/*auto_confirm*/));
+ return invoke(Cmd_ptr(new CtsCmd(CtsCmd::HALT_SERVER)));
+}
+int ClientInvoker::pingServer() const
+{
+ if (testInterface_) return invoke( CtsApi::pingServer());
+ return invoke(Cmd_ptr(new CtsCmd(CtsCmd::PING)));
+}
+int ClientInvoker::shutdownServer() const
+{
+ if (testInterface_) return invoke(CtsApi::shutdownServer(true/*auto_confirm*/));
+ return invoke(Cmd_ptr(new CtsCmd(CtsCmd::SHUTDOWN_SERVER)));
+}
+int ClientInvoker::terminateServer() const
+{
+ if (testInterface_) return invoke(CtsApi::terminateServer(true/*auto_confirm*/));
+ return invoke(Cmd_ptr(new CtsCmd(CtsCmd::TERMINATE_SERVER)));
+}
+int ClientInvoker::stats() const
+{
+ if (testInterface_) return invoke(CtsApi::stats());
+ return invoke(Cmd_ptr(new CtsCmd(CtsCmd::STATS)));
+}
+int ClientInvoker::stats_reset() const
+{
+ if (testInterface_) return invoke(CtsApi::stats_reset());
+ return invoke(Cmd_ptr(new CtsCmd(CtsCmd::STATS_RESET)));
+}
+int ClientInvoker::suites() const
+{
+ if (testInterface_) return invoke(CtsApi::suites());
+ return invoke(Cmd_ptr(new CtsCmd(CtsCmd::SUITES)));
+}
+int ClientInvoker::server_version() const
+{
+ if (testInterface_) return invoke(CtsApi::server_version());
+ return invoke(Cmd_ptr(new ServerVersionCmd()) );
+}
+int ClientInvoker::debug_server_on() const
+{
+ if (testInterface_) return invoke(CtsApi::debug_server_on());
+ return invoke(Cmd_ptr(new CtsCmd(CtsCmd::DEBUG_SERVER_ON)));
+}
+int ClientInvoker::debug_server_off() const
+{
+ if (testInterface_) return invoke(CtsApi::debug_server_off());
+ return invoke(Cmd_ptr(new CtsCmd(CtsCmd::DEBUG_SERVER_OFF)));
+}
+
+//=====================================================================================
+
+int ClientInvoker::ch_register( bool auto_add_new_suites,const std::vector<std::string>& suites ) const
+{
+ if (testInterface_) return invoke(CtsApi::ch_register(auto_add_new_suites, suites));
+ return invoke(Cmd_ptr(new ClientHandleCmd(suites, auto_add_new_suites)) );
+}
+int ClientInvoker::ch_suites() const
+{
+ if (testInterface_) return invoke(CtsApi::ch_suites());
+ return invoke(Cmd_ptr(new ClientHandleCmd(ClientHandleCmd::SUITES)) );
+}
+int ClientInvoker::ch_drop( int client_handle ) const
+{
+ if (testInterface_) return invoke(CtsApi::ch_drop(client_handle));
+ return invoke(Cmd_ptr(new ClientHandleCmd(client_handle)) );
+}
+int ClientInvoker::ch_drop_user( const std::string& user) const
+{
+ if (testInterface_) return invoke(CtsApi::ch_drop_user(user));
+ return invoke(Cmd_ptr(new ClientHandleCmd(user)) );
+}
+int ClientInvoker::ch_add( int client_handle, const std::vector<std::string>& suites ) const
+{
+ if (testInterface_) return invoke(CtsApi::ch_add(client_handle, suites));
+ return invoke(Cmd_ptr(new ClientHandleCmd(client_handle, suites, ClientHandleCmd::ADD)) );
+}
+int ClientInvoker::ch_remove( int client_handle, const std::vector<std::string>& suites ) const
+{
+ if (testInterface_) return invoke(CtsApi::ch_remove(client_handle, suites));
+ return invoke(Cmd_ptr(new ClientHandleCmd(client_handle, suites, ClientHandleCmd::REMOVE)) );
+}
+int ClientInvoker::ch_auto_add( int client_handle, bool auto_add_new_suites ) const
+{
+ if (testInterface_) return invoke(CtsApi::ch_auto_add(client_handle, auto_add_new_suites));
+ return invoke(Cmd_ptr(new ClientHandleCmd(client_handle,auto_add_new_suites)) );
+}
+int ClientInvoker::ch1_drop() const
+{
+ if (0 == server_reply_.client_handle()) return 0;
+ if (testInterface_) return invoke(CtsApi::ch_drop(server_reply_.client_handle()));
+ return invoke(Cmd_ptr(new ClientHandleCmd(server_reply_.client_handle())) );
+}
+int ClientInvoker::ch1_add( const std::vector<std::string>& suites ) const
+{
+ if (testInterface_) return invoke(CtsApi::ch_add(server_reply_.client_handle(), suites));
+ return invoke(Cmd_ptr(new ClientHandleCmd(server_reply_.client_handle(), suites, ClientHandleCmd::ADD)) );
+}
+int ClientInvoker::ch1_remove( const std::vector<std::string>& suites ) const
+{
+ if (testInterface_) return invoke(CtsApi::ch_remove(server_reply_.client_handle(), suites));
+ return invoke(Cmd_ptr(new ClientHandleCmd(server_reply_.client_handle(), suites, ClientHandleCmd::REMOVE)) );
+}
+int ClientInvoker::ch1_auto_add( bool auto_add_new_suites ) const
+{
+ if (testInterface_) return invoke(CtsApi::ch_auto_add(server_reply_.client_handle(), auto_add_new_suites));
+ return invoke(Cmd_ptr(new ClientHandleCmd(server_reply_.client_handle(),auto_add_new_suites)) );
+}
+
+// ======================================================================================================
+
+int ClientInvoker::begin( const std::string& suiteName, bool force ) const
+{
+ if (testInterface_) return invoke(CtsApi::begin(suiteName, force));
+ return invoke(Cmd_ptr(new BeginCmd(suiteName, force )) );
+}
+int ClientInvoker::begin_all_suites( bool force ) const
+{
+ if (testInterface_) return invoke(CtsApi::begin("", force));
+ return invoke(Cmd_ptr(new BeginCmd("", force )) );
+}
+// ======================================================================================================
+
+int ClientInvoker::zombieGet() const
+{
+ if (testInterface_) return invoke(CtsApi::zombieGet());
+ return invoke(Cmd_ptr(new CtsCmd(CtsCmd::GET_ZOMBIES)));
+}
+int ClientInvoker::zombieFob( const Zombie& z ) const
+{
+ if (testInterface_) return invoke(CtsApi::zombieFob(z.path_to_task(), z.process_or_remote_id(), z.jobs_password()));
+ return invoke(Cmd_ptr(new ZombieCmd(User::FOB, z.path_to_task(), z.process_or_remote_id(), z.jobs_password() )));
+}
+int ClientInvoker::zombieFail( const Zombie& z ) const
+{
+ if (testInterface_) return invoke(CtsApi::zombieFail(z.path_to_task(), z.process_or_remote_id(), z.jobs_password()));
+ return invoke(Cmd_ptr(new ZombieCmd(User::FAIL, z.path_to_task(), z.process_or_remote_id(), z.jobs_password() )));
+}
+int ClientInvoker::zombieAdopt( const Zombie& z ) const
+{
+ if (testInterface_) return invoke(CtsApi::zombieAdopt(z.path_to_task(), z.process_or_remote_id(), z.jobs_password()));
+ return invoke(Cmd_ptr(new ZombieCmd(User::ADOPT, z.path_to_task(), z.process_or_remote_id(), z.jobs_password() )));
+}
+int ClientInvoker::zombieBlock( const Zombie& z ) const
+{
+ if (testInterface_) return invoke(CtsApi::zombieBlock(z.path_to_task(), z.process_or_remote_id(), z.jobs_password()));
+ return invoke(Cmd_ptr(new ZombieCmd(User::BLOCK, z.path_to_task(), z.process_or_remote_id(), z.jobs_password() )));
+}
+int ClientInvoker::zombieRemove( const Zombie& z ) const
+{
+ if (testInterface_) return invoke(CtsApi::zombieRemove(z.path_to_task(), z.process_or_remote_id(), z.jobs_password()));
+ return invoke(Cmd_ptr(new ZombieCmd(User::REMOVE, z.path_to_task(), z.process_or_remote_id(), z.jobs_password() )));
+}
+int ClientInvoker::zombieKill( const Zombie& z ) const
+{
+ if (testInterface_) return invoke(CtsApi::zombieKill(z.path_to_task(), z.process_or_remote_id(), z.jobs_password()));
+ return invoke(Cmd_ptr(new ZombieCmd(User::KILL, z.path_to_task(), z.process_or_remote_id(), z.jobs_password() )));
+}
+int ClientInvoker::zombieFobCli( const std::string& absNodePath ) const
+{
+ if (testInterface_) return invoke(CtsApi::zombieFobCli(absNodePath));
+ return invoke(Cmd_ptr(new ZombieCmd(User::FOB, absNodePath,"","")));
+}
+int ClientInvoker::zombieFailCli( const std::string& absNodePath ) const
+{
+ if (testInterface_) return invoke(CtsApi::zombieFailCli(absNodePath));
+ return invoke(Cmd_ptr(new ZombieCmd(User::FAIL, absNodePath,"","" )));
+}
+int ClientInvoker::zombieAdoptCli( const std::string& absNodePath ) const
+{
+ if (testInterface_) return invoke(CtsApi::zombieAdoptCli(absNodePath));
+ return invoke(Cmd_ptr(new ZombieCmd(User::ADOPT, absNodePath,"","" )));
+}
+int ClientInvoker::zombieBlockCli( const std::string& absNodePath ) const
+{
+ if (testInterface_) return invoke(CtsApi::zombieBlockCli(absNodePath));
+ return invoke(Cmd_ptr(new ZombieCmd(User::BLOCK, absNodePath,"","" )));
+}
+int ClientInvoker::zombieRemoveCli( const std::string& absNodePath ) const
+{
+ if (testInterface_) return invoke(CtsApi::zombieRemoveCli(absNodePath));
+ return invoke(Cmd_ptr(new ZombieCmd(User::REMOVE, absNodePath,"","" )));
+}
+int ClientInvoker::zombieKillCli( const std::string& absNodePath ) const
+{
+ if (testInterface_) return invoke(CtsApi::zombieKillCli(absNodePath));
+ return invoke(Cmd_ptr(new ZombieCmd(User::KILL, absNodePath,"","" )));
+}
+
+// ======================================================================================================
+
+int ClientInvoker::job_gen( const std::string& absNodePath ) const
+{
+ if (testInterface_) return invoke(CtsApi::job_gen(absNodePath));
+ return invoke(Cmd_ptr(new CtsNodeCmd( CtsNodeCmd::JOB_GEN, absNodePath)));
+}
+
+int ClientInvoker::edit_history( const std::string& path ) const
+{
+ if (testInterface_) return invoke(CtsApi::edit_history(path));
+ return invoke(Cmd_ptr(new PathsCmd( PathsCmd::EDIT_HISTORY, path)));
+}
+int ClientInvoker::kill( const std::vector<std::string>& paths ) const
+{
+ if (testInterface_) return invoke(CtsApi::kill(paths));
+ return invoke(Cmd_ptr(new PathsCmd( PathsCmd::KILL, paths)));
+}
+int ClientInvoker::kill( const std::string& absNodePath ) const
+{
+ if (testInterface_) return invoke(CtsApi::kill(absNodePath));
+ return invoke(Cmd_ptr(new PathsCmd( PathsCmd::KILL, absNodePath)));
+}
+int ClientInvoker::status( const std::vector<std::string>& paths ) const
+{
+ if (testInterface_) return invoke(CtsApi::status(paths));
+ return invoke(Cmd_ptr(new PathsCmd( PathsCmd::STATUS, paths)));
+}
+int ClientInvoker::status( const std::string& absNodePath ) const
+{
+ if (testInterface_) return invoke(CtsApi::status(absNodePath));
+ return invoke(Cmd_ptr(new PathsCmd( PathsCmd::STATUS, absNodePath)));
+}
+int ClientInvoker::suspend( const std::vector<std::string>& paths ) const
+{
+ if (testInterface_) return invoke(CtsApi::suspend(paths));
+ return invoke(Cmd_ptr(new PathsCmd( PathsCmd::SUSPEND, paths)));
+}
+int ClientInvoker::suspend( const std::string& absNodePath ) const
+{
+ if (testInterface_) return invoke(CtsApi::suspend(absNodePath));
+ return invoke(Cmd_ptr(new PathsCmd( PathsCmd::SUSPEND, absNodePath)));
+}
+int ClientInvoker::resume( const std::vector<std::string>& paths ) const
+{
+ if (testInterface_) return invoke(CtsApi::resume(paths));
+ return invoke(Cmd_ptr(new PathsCmd( PathsCmd::RESUME, paths)));
+}
+int ClientInvoker::resume( const std::string& absNodePath ) const
+{
+ if (testInterface_) return invoke(CtsApi::resume(absNodePath));
+ return invoke(Cmd_ptr(new PathsCmd( PathsCmd::RESUME, absNodePath)));
+}
+int ClientInvoker::check( const std::vector<std::string>& paths ) const
+{
+ if (testInterface_) return invoke(CtsApi::check(paths));
+ return invoke(Cmd_ptr(new PathsCmd( PathsCmd::CHECK, paths)));
+}
+int ClientInvoker::check( const std::string& absNodePath ) const
+{
+ if (testInterface_) return invoke(CtsApi::check(absNodePath));
+ return invoke(Cmd_ptr(new PathsCmd( PathsCmd::CHECK, absNodePath)));
+}
+int ClientInvoker::delete_nodes( const std::vector<std::string>& paths, bool force ) const
+{
+ if (testInterface_) return invoke(CtsApi::delete_node(paths, force, true/*auto_confirm*/));
+ return invoke(Cmd_ptr(new PathsCmd( PathsCmd::DELETE, paths,force)));
+}
+int ClientInvoker::delete_node( const std::string& absNodePath, bool force ) const
+{
+ if (testInterface_) return invoke(CtsApi::delete_node(absNodePath, force, true/*auto_confirm*/));
+ return invoke(Cmd_ptr(new PathsCmd( PathsCmd::DELETE, absNodePath,force)));
+}
+int ClientInvoker::delete_all( bool force) const
+{
+ if (testInterface_) return invoke(CtsApi::delete_node(std::vector<std::string>(),force));
+ return invoke(Cmd_ptr(new PathsCmd( PathsCmd::DELETE, std::vector<std::string>(),force)));
+}
+
+// ======================================================================================================
+
+int ClientInvoker::replace( const std::string& absNodePath, const std::string& path_to_client_defs,
+ bool create_parents_as_required, bool force) const
+{
+ if (testInterface_) return invoke(CtsApi::replace(absNodePath, path_to_client_defs, create_parents_as_required, force));
+
+ /// *Note* server_reply_.client_handle_ is kept until the next call to register_client_handle
+ /// The client invoker can be used multiple times, hence keep value of defs, and client handle in server reply
+ server_reply_.clear_for_invoke(cli_);
+
+ /// Handle command constructors that can throw
+ Cmd_ptr cts_cmd;
+ try {
+
+ ReplaceNodeCmd* replace_cmd = new ReplaceNodeCmd( absNodePath, create_parents_as_required, path_to_client_defs, force);
+
+ // For test allow the defs environment to changed, i.e. allow us to inject ECF_CLIENT ???
+ replace_cmd->theDefs()->set_server().add_or_update_user_variables( clientEnv_.env() );
+
+ cts_cmd = Cmd_ptr( replace_cmd );
+ }
+ catch (std::exception& e ){
+ std::stringstream ss; ss << "ecflow:ClientInvoker::replace(" << absNodePath << "," << path_to_client_defs << ", ...) failed: " << e.what();
+ server_reply_.set_error_msg( ss.str() );
+ if (on_error_throw_exception_) throw std::runtime_error( server_reply_.error_msg() );
+ return 1;
+ }
+
+ return invoke( cts_cmd );
+}
+
+int ClientInvoker::replace_1(const std::string& absNodePath, defs_ptr client_defs, bool create_parents_as_required, bool force) const
+{
+ /// *Note* server_reply_.client_handle_ is kept until the next call to register_client_handle
+ /// The client invoker can be used multiple times, hence keep value of defs, and client handle in server reply
+ server_reply_.clear_for_invoke(cli_);
+
+ /// Handle command constructors that can throw
+ Cmd_ptr cts_cmd;
+ try {
+ cts_cmd = Cmd_ptr( new ReplaceNodeCmd( absNodePath, create_parents_as_required, client_defs, force) );
+ }
+ catch (std::exception& e ){
+ std::stringstream ss; ss << "ecflow:ClientInvoker::replace_1(" << absNodePath << " ...) failed: " << e.what();
+ server_reply_.set_error_msg( ss.str() );
+ if (on_error_throw_exception_) throw std::runtime_error( server_reply_.error_msg() );
+ return 1;
+ }
+
+ return invoke( cts_cmd );
+}
+
+int ClientInvoker::requeue( const std::vector<std::string>& paths, const std::string& option ) const
+{
+ if (testInterface_) return invoke(CtsApi::requeue(paths, option));
+
+ RequeueNodeCmd::Option the_option = RequeueNodeCmd::NO_OPTION;
+ if (!option.empty()) {
+ if (option == "abort") the_option = RequeueNodeCmd::ABORT;
+ else if (option == "force") the_option = RequeueNodeCmd::FORCE;
+ else {
+ server_reply_.set_error_msg("ecflow:ClientInvoker::requeue: Expected option = [ force | abort ]");
+ if (on_error_throw_exception_) {
+ throw std::runtime_error(server_reply_.error_msg());
+ }
+ return 1;
+ }
+ }
+ return invoke(Cmd_ptr(new RequeueNodeCmd(paths, the_option)));
+}
+int ClientInvoker::requeue( const std::string& absNodePath, const std::string& option) const
+{
+ if (testInterface_) return invoke(CtsApi::requeue(absNodePath, option));
+
+ RequeueNodeCmd::Option the_option = RequeueNodeCmd::NO_OPTION;
+ if (!option.empty()) {
+ if (option == "abort") the_option = RequeueNodeCmd::ABORT;
+ else if (option == "force") the_option = RequeueNodeCmd::FORCE;
+ else {
+ server_reply_.set_error_msg("ecflow:ClientInvoker::requeue: Expected option = [ force | abort ]");
+ if (on_error_throw_exception_) throw std::runtime_error(server_reply_.error_msg());
+ return 1;
+ }
+ }
+ return invoke(Cmd_ptr(new RequeueNodeCmd(absNodePath, the_option)));
+}
+
+int ClientInvoker::run( const std::vector<std::string>& paths, bool force ) const
+{
+ if (testInterface_) return invoke(CtsApi::run(paths, force));
+ return invoke(Cmd_ptr(new RunNodeCmd(paths, force)));
+}
+int ClientInvoker::run( const std::string& absNodePath, bool force ) const
+{
+ if (testInterface_) return invoke(CtsApi::run(absNodePath, force));
+ return invoke(Cmd_ptr(new RunNodeCmd(absNodePath, force)));
+}
+int ClientInvoker::order( const std::string& absNodePath, const std::string& order ) const
+{
+ if (testInterface_) return invoke(CtsApi::order(absNodePath, order));
+
+ if (!NOrder::isValid(order)) {
+ server_reply_.set_error_msg("ecflow:ClientInvoker::order: please specify one of [ top, bottom, alpha, order, up, down ]\n");
+ if (on_error_throw_exception_) throw std::runtime_error(server_reply_.error_msg());
+ return 1;
+ }
+ return invoke(Cmd_ptr(new OrderNodeCmd(absNodePath, NOrder::toOrder(order))));
+}
+int ClientInvoker::order(const std::string& absNodePath,NOrder::Order order) const
+{
+ return invoke(Cmd_ptr(new OrderNodeCmd(absNodePath, order)));
+}
+
+// ======================================================================================================
+
+int ClientInvoker::checkPtDefs(ecf::CheckPt::Mode m,int check_pt_interval,int check_pt_save_time_alarm) const
+{
+ if (testInterface_) return invoke(CtsApi::checkPtDefs(m, check_pt_interval, check_pt_save_time_alarm));
+ return invoke(Cmd_ptr(new CheckPtCmd(m,check_pt_interval,check_pt_save_time_alarm)));
+}
+int ClientInvoker::restoreDefsFromCheckPt() const
+{
+ if (testInterface_) return invoke(CtsApi::restoreDefsFromCheckPt());
+ return invoke(Cmd_ptr(new CtsCmd( CtsCmd::RESTORE_DEFS_FROM_CHECKPT )));
+}
+
+int ClientInvoker::force( const std::string& absNodePath, const std::string& state_or_event,bool recursive, bool set_repeats_to_last_value ) const
+{
+ if (testInterface_) return invoke(CtsApi::force(absNodePath, state_or_event, recursive, set_repeats_to_last_value));
+ return invoke(Cmd_ptr(new ForceCmd(absNodePath, state_or_event, recursive, set_repeats_to_last_value )));
+}
+int ClientInvoker::force( const std::vector<std::string>& paths, const std::string& state_or_event,bool recursive, bool set_repeats_to_last_value) const
+{
+ if (testInterface_) return invoke(CtsApi::force(paths, state_or_event, recursive, set_repeats_to_last_value));
+ return invoke(Cmd_ptr(new ForceCmd(paths, state_or_event, recursive, set_repeats_to_last_value )));
+}
+
+int ClientInvoker::freeDep( const std::vector<std::string>& paths, bool trigger,bool all, bool date, bool the_time ) const
+{
+ if (testInterface_) return invoke(CtsApi::freeDep(paths, trigger, all, date, the_time));
+ return invoke(Cmd_ptr(new FreeDepCmd(paths, trigger, all, date , the_time)));
+}
+int ClientInvoker::freeDep( const std::string& absNodePath, bool trigger, bool all,bool date, bool the_time ) const
+{
+ if (testInterface_) return invoke(CtsApi::freeDep(absNodePath, trigger, all, date, the_time));
+ return invoke(Cmd_ptr(new FreeDepCmd(absNodePath, trigger, all, date , the_time)));
+}
+
+int ClientInvoker::file( const std::string& absNodePath, const std::string& fileType, const std::string& max_lines ) const
+{
+ if (testInterface_) return invoke(CtsApi::file(absNodePath, fileType, max_lines));
+
+ /// Handle command constructors that can throw
+ Cmd_ptr cts_cmd;
+ try {
+ cts_cmd = Cmd_ptr( new CFileCmd(absNodePath, fileType, max_lines));
+ }
+ catch (std::exception& e ){
+ std::stringstream ss; ss << "ecflow:ClientInvoker::file(" << absNodePath << "," << fileType << "," << max_lines << ") failed:\n" << e.what();
+ server_reply_.set_error_msg( ss.str() );
+ if (on_error_throw_exception_) {
+ throw std::runtime_error( server_reply_.error_msg() );
+ }
+ return 1;
+ }
+
+ return invoke( cts_cmd );
+}
+
+int ClientInvoker::plug( const std::string& sourcePath, const std::string& destPath ) const
+{
+ if (testInterface_) return invoke(CtsApi::plug(sourcePath, destPath));
+ return invoke(Cmd_ptr(new PlugCmd(sourcePath, destPath)));
+}
+
+// ======================================================================================================
+
+int ClientInvoker::reloadwsfile() const
+{
+ if (testInterface_) return invoke(CtsApi::reloadwsfile());
+ return invoke(Cmd_ptr(new CtsCmd( CtsCmd::RELOAD_WHITE_LIST_FILE )));
+}
+int ClientInvoker::group( const std::string& groupRequest ) const
+{
+ if (testInterface_) return invoke(CtsApi::group(groupRequest));
+ return invoke(Cmd_ptr(new GroupCTSCmd(groupRequest,&clientEnv_)));
+}
+
+int ClientInvoker::logMsg( const std::string& msg ) const
+{
+ if (testInterface_) return invoke(CtsApi::logMsg(msg));
+ return invoke(Cmd_ptr(new LogMessageCmd( msg )));
+}
+int ClientInvoker::new_log( const std::string& new_path) const
+{
+ if (testInterface_) return invoke(CtsApi::new_log(new_path));
+
+ /// Handle command constructors that can throw
+ Cmd_ptr cts_cmd;
+ try {
+ cts_cmd = Cmd_ptr(new LogCmd( new_path ));
+ }
+ catch (std::exception& e ){
+ server_reply_.set_error_msg( e.what() );
+ if (on_error_throw_exception_) throw std::runtime_error( server_reply_.error_msg() );
+ return 1;
+ }
+ return invoke(cts_cmd);
+}
+int ClientInvoker::getLog( int lastLines) const
+{
+ if (lastLines == 0) lastLines = Log::get_last_n_lines_default();
+ if (testInterface_) return invoke(CtsApi::getLog(lastLines));
+ return invoke(Cmd_ptr(new LogCmd( LogCmd::GET, lastLines )));
+}
+int ClientInvoker::clearLog() const
+{
+ if (testInterface_) return invoke(CtsApi::clearLog());
+ return invoke(Cmd_ptr(new LogCmd( LogCmd::CLEAR )));
+}
+int ClientInvoker::flushLog() const
+{
+ if (testInterface_) return invoke(CtsApi::flushLog());
+ return invoke(Cmd_ptr(new LogCmd( LogCmd::FLUSH )));
+}
+int ClientInvoker::get_log_path() const
+{
+ if (testInterface_) return invoke(CtsApi::get_log_path());
+ return invoke(Cmd_ptr(new LogCmd( LogCmd::PATH )));
+}
+
+int ClientInvoker::forceDependencyEval() const
+{
+ return invoke(CtsApi::forceDependencyEval());
+}
+
+// ======================================================================================================
+
+int ClientInvoker::edit_script_edit(const std::string& path_to_task)
+{
+ return invoke(Cmd_ptr( new EditScriptCmd( path_to_task, EditScriptCmd::EDIT) ) );
+}
+
+int ClientInvoker::edit_script_preprocess(const std::string& path_to_task)
+{
+ return invoke(Cmd_ptr( new EditScriptCmd( path_to_task, EditScriptCmd::PREPROCESS) ) );
+}
+
+int ClientInvoker::edit_script_preprocess(const std::string& path_to_task,const std::vector<std::string>& file_contents)
+{
+ return invoke(Cmd_ptr( new EditScriptCmd( path_to_task,file_contents) ) );
+}
+
+int ClientInvoker::edit_script_submit(const std::string& path_to_task,const NameValueVec& used_variables)
+{
+ return invoke(Cmd_ptr( new EditScriptCmd( path_to_task,used_variables) ) );
+}
+
+int ClientInvoker::edit_script_submit(
+ const std::string& path_to_task,
+ const NameValueVec& used_variables,
+ const std::vector<std::string>& file_contents,
+ bool create_alias,
+ bool run_alias)
+{
+ return invoke(Cmd_ptr( new EditScriptCmd( path_to_task,used_variables,file_contents,create_alias,run_alias) ) );
+}
+
+std::string ClientInvoker::client_env_host_port() const
+{
+ std::string host_port = clientEnv_.host();
+ host_port += Str::COLON();
+ host_port += clientEnv_.port();
+ return host_port;
+}
+
+std::string ClientInvoker::find_free_port(int seed_port_number, bool debug)
+{
+ // Ping failed, We need to distinguish between:
+ // a/ Server does not exist : <FREE> port
+ // b/ Address in use : <BUSY> port on existing server
+ // Using server_version() but then get error messages
+ // ******** Until this is done we can't implement port hopping **********
+
+ if (debug) cout << " ClientInvoker::find_free_port: starting with port " << seed_port_number << "\n";
+ int the_port = seed_port_number;
+ std::string free_port;
+ ClientInvoker client;
+ client.set_retry_connection_period(1); // avoid long wait
+ client.set_connection_attempts(1); // avoid long wait
+ while (1) {
+ free_port = boost::lexical_cast<std::string>(the_port);
+ try {
+ if (debug) cout << " Trying to connect to server on '" << Str::LOCALHOST() << ":" << free_port << "'\n";
+ client.set_host_port(Str::LOCALHOST(),free_port);
+ client.pingServer();
+ if (debug) cout << " Connected to server on port " << free_port << " trying next port\n";
+ the_port++;
+ }
+ catch ( std::runtime_error& e) {
+ std::string error_msg = e.what();
+ if (debug) cout << " " << e.what();
+ if (error_msg.find("authentication failed") != std::string::npos) {
+ if (debug) cout << " Could not connect, due to authentication failure, hence port " << the_port << " is used,trying next port\n";
+ the_port++;
+ continue;
+ }
+ else {
+ if (debug) cout << " Found free port " << free_port << "\n";
+ break;
+ }
+ }
+ }
+ return free_port;
+}
+
+bool ClientInvoker::wait_for_server_reply(int time_out) const
+{
+ DurationTimer timer;
+ while(1) {
+ sleep(2);
+
+ if (on_error_throw_exception_) {
+ try {
+ pingServer(); // will throw exception
+ return true; // no exception, server lives
+ }
+ catch( ... ) {}
+ }
+ else {
+ if (pingServer() == 0) {
+ return true; // ping OK,
+ }
+ }
+ if (timer.duration() > time_out) {
+ return false;
+ }
+ }
+ return false;
+}
+
+bool ClientInvoker::wait_for_server_death(int time_out) const
+{
+ DurationTimer timer;
+ while(1) {
+
+ if (on_error_throw_exception_) {
+ try {
+ pingServer(); // will throw exception
+ }
+ catch( ... ) {
+ // server died
+ return true;
+ }
+ }
+ else {
+ if (pingServer() == 1) {
+ return true; // ping failed, server has died,
+ }
+ }
+ if (timer.duration() > time_out) {
+ return false; // server still lives
+ }
+
+ // Ping ok, server lives, continue pinging, until timeout
+ sleep(2);
+ }
+ return false;
+}
+
+
+int ClientInvoker::load_in_memory_defs( const defs_ptr& clientDefs, bool force) const
+{
+ /// *Note* server_reply_.client_handle_ is kept until the next call to register_client_handle
+ /// The client invoker can be used multiple times, hence keep value of defs, and client handle in server reply
+ server_reply_.clear_for_invoke(cli_);
+
+ if ( !clientDefs.get() ) {
+ server_reply_.set_error_msg("The client definition is empty.");
+ if (on_error_throw_exception_) throw std::runtime_error(server_reply_.error_msg());
+ return 1;
+ }
+
+ // Client defs has been created in memory.
+ // warn about naff expression and unresolved in-limit references to Limit's
+ // Don't allow defs to be loaded into server, with trigger parser errors.
+ std::string warningMsg;
+ if (!clientDefs->check(server_reply_.get_error_msg(), warningMsg)) {
+ if (on_error_throw_exception_) throw std::runtime_error(server_reply_.error_msg());
+ return 1;
+ }
+
+ return invoke( Cmd_ptr( new LoadDefsCmd( clientDefs, force /*force overwrite suite of same name*/) ) );
+}
+
+
+// ==========================================================================
+// Python child support
+// ==========================================================================
+void ClientInvoker::set_child_path(const std::string& path)
+{
+ child_task_path_ = path;
+}
+void ClientInvoker::set_child_password(const std::string& pass)
+{
+ child_task_password_ = pass;
+}
+void ClientInvoker::set_child_pid(const std::string& pid)
+{
+ child_task_pid_ = pid;
+}
+void ClientInvoker::set_child_try_no(unsigned int try_no)
+{
+ child_task_try_no_ = try_no;
+}
+void ClientInvoker::set_child_timeout(unsigned int seconds )
+{
+ clientEnv_.set_child_cmd_timeout(seconds);
+}
+
+
+void ClientInvoker::check_child_parameters() const
+{
+ if (clientEnv_.debug()) {
+ std::cout << " child_task_path_ = '" << child_task_path_ << "'\n";
+ std::cout << " child_task_password_ = '" << child_task_password_ << "'\n";
+ std::cout << " child_task_pid_ = '" << child_task_pid_ << "'\n";
+ std::cout << " child_task_try_no_ = " << child_task_try_no_ << "\n";
+ }
+ if (child_task_path_.empty()) throw std::runtime_error("Child Path not set");
+ if (child_task_password_.empty()) throw std::runtime_error("Child password not set");
+ if (child_task_pid_.empty()) throw std::runtime_error("Child pid not set");
+ if (child_task_try_no_ == 0) throw std::runtime_error("Child try_no not set");
+}
+
+void ClientInvoker::child_init()
+{
+ check_child_parameters();
+ on_error_throw_exception_ = true; // for python always throw exception
+ invoke( Cmd_ptr( new InitCmd(child_task_path_, child_task_password_, child_task_pid_, child_task_try_no_ ) ) );
+}
+
+void ClientInvoker::child_abort(const std::string& reason )
+{
+ check_child_parameters();
+ on_error_throw_exception_ = true; // for python always throw exception
+ invoke( Cmd_ptr( new AbortCmd(child_task_path_, child_task_password_, child_task_pid_, child_task_try_no_,reason ) ) );
+}
+
+void ClientInvoker::child_event(const std::string& event_name_or_number)
+{
+ check_child_parameters();
+ on_error_throw_exception_ = true; // for python always throw exception
+ invoke( Cmd_ptr( new EventCmd(child_task_path_, child_task_password_, child_task_pid_, child_task_try_no_,event_name_or_number ) ) );
+}
+
+void ClientInvoker::child_meter(const std::string& meter_name, int meter_value)
+{
+ if (meter_name.empty()) throw std::runtime_error("Meter name not set");
+ check_child_parameters();
+ on_error_throw_exception_ = true; // for python always throw exception
+ invoke( Cmd_ptr( new MeterCmd(child_task_path_, child_task_password_, child_task_pid_, child_task_try_no_,meter_name,meter_value ) ) );
+}
+
+void ClientInvoker::child_label(const std::string& label_name, const std::string& label_value)
+{
+ if (label_name.empty()) throw std::runtime_error("Label name not set");
+ check_child_parameters();
+ on_error_throw_exception_ = true; // for python always throw exception
+ invoke( Cmd_ptr( new LabelCmd(child_task_path_, child_task_password_, child_task_pid_, child_task_try_no_,label_name,label_value ) ) );
+}
+
+void ClientInvoker::child_wait(const std::string& expression)
+{
+ check_child_parameters();
+ on_error_throw_exception_ = true; // for python always throw exception
+ invoke( Cmd_ptr( new CtsWaitCmd(child_task_path_, child_task_password_, child_task_pid_, child_task_try_no_, expression ) ) );
+}
+
+void ClientInvoker::child_complete()
+{
+ check_child_parameters();
+ on_error_throw_exception_ = true; // for python always throw exception
+ invoke( Cmd_ptr( new CompleteCmd(child_task_path_, child_task_password_, child_task_pid_, child_task_try_no_ ) ) );
+}
+
+// ==========================================================================
+// class RequestLogger:
+// ==========================================================================
+RequestLogger::RequestLogger(const ClientInvoker* ci) : ci_(ci){}
+RequestLogger::~RequestLogger() {
+
+ // *assumes* destructor of RoundTripRecorder was invoked first, to allow recording of the time rtt_
+ if (cmd_.get()) {
+ if (ci_->clientEnv_.debug() && ci_->server_reply_.error_msg().empty()) {
+ cout << TimeStamp::now() << "ClientInvoker "; cmd_->print(cout); cout << " SUCCEDED " << to_simple_string(ci_->rtt_) << "\n";
+ }
+
+ if (Rtt::instance()) {
+ std::stringstream ss;
+ ss << ci_->client_env_host_port() << " ";
+ cmd_->print(ss);
+ ss << " " << Rtt::tag() << to_simple_string(ci_->rtt_); // Note: endl added rtt(..)
+ ss << " : " << ci_->server_reply_.error_msg();
+ rtt(ss.str());
+ }
+
+ if (ci_->cli_ && cmd_->ping_cmd() && ci_->server_reply_.error_msg().empty()) {
+ cout << "ping server(" << ci_->client_env_host_port() << ") succeeded in " << to_simple_string(ci_->rtt_) << " ~" << ci_->rtt_.total_milliseconds() << " milliseconds\n";
+ }
+ }
+}
+
+// ==========================================================================
+// class RoundTripRecorder:
+// ==========================================================================
+RoundTripRecorder::RoundTripRecorder(const ClientInvoker* ci)
+: ci_(ci)
+{
+ // get the current time from the clock -- one second resolution
+ ci_->start_time_ = microsec_clock::universal_time();
+ ci_->rtt_ = boost::posix_time::time_duration();
+}
+
+RoundTripRecorder::~RoundTripRecorder() {
+ ci_->rtt_ = microsec_clock::universal_time() - ci_->start_time_;
+}
diff --git a/Client/src/ClientInvoker.hpp b/Client/src/ClientInvoker.hpp
new file mode 100644
index 0000000..4de7468
--- /dev/null
+++ b/Client/src/ClientInvoker.hpp
@@ -0,0 +1,365 @@
+#ifndef CLIENT_INVOKER_HPP_
+#define CLIENT_INVOKER_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include "boost/date_time/posix_time/posix_time_types.hpp"
+
+#include "ClientEnvironment.hpp"
+#include "ClientOptions.hpp"
+#include "Cmd.hpp"
+#include "CtsApi.hpp"
+#include "TaskApi.hpp"
+#include "NodeFwd.hpp"
+#include "ServerReply.hpp"
+#include "Zombie.hpp"
+#include "NOrder.hpp"
+
+/// Invokes the client depending on the arguments
+/// This has been separated from main, to allow us to invoke the client
+/// from a test suite.
+/// Important: We can make *many* calls with the same ClientInvoker.
+/// This is more efficient than creating a ClientInvoker for each request
+class ClientInvoker : private boost::noncopyable {
+public:
+ /// Will create the *ClientEnvironment* once on construction
+ /// By default will throw exception std::runtime_error for errors
+ ClientInvoker();
+ ClientInvoker(const std::string& host_port);
+ ClientInvoker(const std::string& host, const std::string& port);
+ ClientInvoker(const std::string& host, int port);
+
+ /// if throw_exception_on_error = false, then
+ /// invoke() will return 0 for success and 1 for error.
+ /// The error message can be retrieved from errorMsg()
+ /// if throw_exception_on_error = true,
+ /// then invoke() for errors will throw std::runtime_error
+ /// will still return 0 for success.
+ void set_throw_on_error(bool f) { on_error_throw_exception_ = f;}
+
+ /// Return the time it takes to contact server and get a reply.
+ const boost::posix_time::time_duration& round_trip_time() const { return rtt_;}
+
+ /// Configure to using command line interface
+ /// This affect commands like ping, log & file, so that, output is written to standard out
+ void set_cli(bool f) { cli_ = f; }
+
+ /// This will override the environment setting.
+ /// In particular setting host explicitly will avoid cycling through server list,
+ /// if connection fails. hence will bomb out earlier
+ /// If applied to child command's will continue attempting this host/port until timeout
+ void set_host_port(const std::string& h, const std::string& p);
+ const std::string& host() const;
+ const std::string& port() const;
+
+ /// Whenever there is a connections failure we wait a number of seconds
+ /// before trying again. ( i.e. to get round glitches in the network.)
+ /// For the ping command this is set as 1 second
+ /// This wait between connection attempts can be configured here.
+ /// i.e for the GUI & python interface this can be reduced to increase responsiveness.
+ /// Default: In debug this period in set to 1 second and in release mode 10 seconds
+ void set_retry_connection_period(unsigned int period) { retry_connection_period_ = period; }
+
+ /// Set the number of times to connect to server, in case of failure
+ /// The period between connection attempts is handled by set_retry_connection_period
+ /// i.e for the GUI & python interface this can be reduced to increase responsiveness.
+ /// Default value is set as 2. Setting a value less than 1 is ignored, will default to 1 in this case
+ void set_connection_attempts( unsigned int attempts);
+
+ /// returns 1 on error and 0 on success. The errorMsg can be accessed via errorMsg()
+ /// Will attempt to connect to the server a number of times. If this fails it will
+ /// try the next server, and so on until a timeout period is reached.
+ int invoke( int argc, char* argv[]) const;
+
+ // support for forward compatibility, by changing boost archive version
+ // Chosen to change client side only
+ void allow_new_client_old_server(int archive_version_of_old_server);
+ int allow_new_client_old_server() const;
+
+ /// If testing, overwrite the task path set in the environment, required for
+ /// testing the task based commands.
+ /// By allowing environment to be changed, we allow smsinit,smscomplete, etc to be replaced
+ /// with ECF_CLIENT path executable
+ /// The following functions are only used for testing purposes.
+ /// Override task paths,env' & job creation at begin time
+ void taskPath(const std::string& s);
+ void set_jobs_password(const std::string&);
+ void setEnv( const std::vector<std::pair<std::string,std::string> >& e);
+ void testInterface(); // allow cmd construction to be aware thats it under test
+ const std::string& process_or_remote_id() const;
+
+ /// record each request its arguments and the round trip time to and from server
+ /// If the file can not opened for create/append then an runtime error exception is thrown
+ void enable_logging(const std::string& log_file_name);
+ void disable_logging();
+
+ /// The timeout feature allow the client to fail gracefully in the case
+ /// where the server has died/crashed. The timeout will ensure the socket is closed.
+ /// allowing the server to be restarted without getting the address is use error.
+ /// Set the timeout for each client->server communication:
+ // connect : timeout_ second
+ // send request : timeout_ second
+ // receive reply : timeout_ second
+ // default is 0 second, which means take the timeout from the command/request
+ // used for test only
+ void set_connect_timeout(int t);
+
+ /// ServerReply Holds the reply from the server
+ void reset(); // will clear local client definition and handle
+ const ServerReply& server_reply() const { return server_reply_;}
+ defs_ptr defs() const { return server_reply_.client_defs(); }
+ const std::string& get_string() const { return server_reply_.get_string(); }
+ bool in_sync() const { return server_reply_.in_sync();}
+ bool get_news() const { return (server_reply_.get_news() != ServerReply::NO_NEWS); }
+ int client_handle() const { return server_reply_.client_handle(); }
+
+ /// If invoke returns 1, the error message can be retrieved with this function
+ const std::string& errorMsg() const { return server_reply_.error_msg();}
+
+ // ***************************************************************************
+ // Task/child based api. Only added here for test.
+ // Relies on environment for the other args
+ int initTask(const std::string& process_id)const
+ { return invoke(TaskApi::init(process_id)); }
+ int abortTask(const std::string& reason_why = "") const
+ { return invoke(TaskApi::abort(reason_why)); }
+ int eventTask(const std::string& eventName) const
+ { return invoke(TaskApi::event(eventName)); }
+ int meterTask(const std::string& meterName, const std::string& new_meter_value) const
+ { return invoke(TaskApi::meter(meterName,new_meter_value)); }
+ int labelTask(const std::string& labelName, const std::vector<std::string>& labels) const
+ { return invoke(TaskApi::label(labelName,labels)); }
+ int waitTask(const std::string& on_expression) const
+ { return invoke(TaskApi::wait(on_expression)); }
+ int completeTask() const
+ { return invoke(TaskApi::complete()); }
+
+ // Support for python child commands, and python jobs
+ void set_child_path(const std::string& path);
+ void set_child_password(const std::string& pass);
+ void set_child_pid(const std::string& pid);
+ void set_child_try_no(unsigned int try_no);
+ void set_child_timeout(unsigned int seconds ); // ECF_TIMEOUT default is 24 hours allow python jobs to override
+ void child_init();
+ void child_abort(const std::string& reason = "");
+ void child_event(const std::string& event_name_or_number);
+ void child_meter(const std::string& meter_name, int meter_value);
+ void child_label(const std::string& label_name, const std::string& label_value);
+ void child_wait(const std::string& on_expression);
+ void child_complete();
+
+ // ********************************************************************************
+ // The client api. Mirrors CtsApi on the whole
+ int getDefs() const;
+ int loadDefs(const std::string& filePath,
+ bool force = false, /* true means overwrite suite of same name */
+ bool check_only = false /* true means don't send to server, just check only */
+ ) const;
+ int load( const defs_ptr& defs, bool force = false /*true means overwrite suite of same name*/) const
+ { return load_in_memory_defs(defs,force); }
+ int sync(defs_ptr& client_defs) const;
+ int sync_local() const;
+ int news(defs_ptr& client_defs) const;
+ int news_local() const;
+
+ // find free port on local host. Not 100% accurate, use in test
+ static std::string find_free_port(int seed_port_number, bool debug = false);
+
+ bool wait_for_server_reply(int time_out = 60) const; // wait for server reply, returning false means timed out.
+ bool wait_for_server_death(int time_out = 60) const; // wait for server reply, returning true means server died,false means timed out.
+ int restartServer() const;
+ int haltServer() const;
+ int shutdownServer() const ;
+ int terminateServer() const;
+ int pingServer() const;
+ int server_load(const std::string& path_to_log_file = "") const { return invoke(CtsApi::server_load(path_to_log_file)); }
+ int debug_server_on() const;
+ int debug_server_off() const;
+ int stats() const;
+ int stats_reset() const;
+ int server_version() const;
+
+ int suites() const;
+ int ch_register( bool auto_add_new_suites, const std::vector<std::string>& suites) const;
+ int ch_suites() const;
+ int ch_drop(int client_handle) const;
+ int ch_drop_user(const std::string& user = "") const;
+ int ch_add(int client_handle, const std::vector<std::string>& suites) const;
+ int ch_remove(int client_handle, const std::vector<std::string>& suites) const;
+ int ch_auto_add(int client_handle, bool auto_add_new_suites) const;
+ int ch1_drop() const;
+ int ch1_add(const std::vector<std::string>& suites) const;
+ int ch1_remove(const std::vector<std::string>& suites) const;
+ int ch1_auto_add(bool auto_add_new_suites) const;
+
+ int begin(const std::string& suiteName,bool force = false) const;
+ int begin_all_suites(bool force = false) const;
+
+ int zombieGet() const;
+ int zombieFob(const Zombie& z) const;
+ int zombieFail(const Zombie& z) const;
+ int zombieAdopt(const Zombie& z) const;
+ int zombieBlock(const Zombie& z) const;
+ int zombieRemove(const Zombie& z) const;
+ int zombieKill(const Zombie& z) const;
+ int zombieFobCli(const std::string& absNodePath) const;
+ int zombieFailCli(const std::string& absNodePath) const;
+ int zombieAdoptCli(const std::string& absNodePath) const;
+ int zombieBlockCli(const std::string& absNodePath) const;
+ int zombieRemoveCli(const std::string& absNodePath) const;
+ int zombieKillCli(const std::string& absNodePath) const;
+
+ int job_gen(const std::string& absNodePath) const;
+
+ int edit_history(const std::string& path) const;
+ int kill(const std::vector<std::string>& paths) const;
+ int kill(const std::string& absNodePath) const;
+ int status(const std::vector<std::string>& paths) const;
+ int status(const std::string& absNodePath) const;
+ int suspend(const std::vector<std::string>& paths) const;
+ int suspend(const std::string& absNodePath) const;
+ int resume(const std::vector<std::string>& paths) const;
+ int resume(const std::string& absNodePath) const;
+ int check(const std::vector<std::string>& paths) const;
+ int check(const std::string& absNodePath) const;
+ int delete_nodes(const std::vector<std::string>& paths,bool force = false) const;
+ int delete_node(const std::string& absNodePath,bool force = false) const;
+ int delete_all(bool force = false) const;
+
+ int replace( const std::string& absNodePath, const std::string& path_to_client_defs,
+ bool create_parents_as_required = true, bool force = false) const;
+ int replace_1( const std::string& absNodePath, defs_ptr client_defs, bool create_parents_as_required = true, bool force = false) const;
+
+ int requeue(const std::vector<std::string>& paths,const std::string& option = "") const;
+ int requeue(const std::string& absNodePath,const std::string& option = "") const;
+ int run(const std::vector<std::string>& paths,bool force = false) const;
+ int run(const std::string& absNodePath,bool force = false) const;
+ int order(const std::string& absNodePath,const std::string& order) const; // slow
+ int order(const std::string& absNodePath,NOrder::Order) const; // fast
+
+ int checkPtDefs(ecf::CheckPt::Mode m = ecf::CheckPt::UNDEFINED, int check_pt_interval = 0, int check_pt_save_time_alarm = 0) const;
+ int restoreDefsFromCheckPt() const;
+
+ int force(const std::string& absNodePath,const std::string& state_or_event,bool recursive = false,bool set_repeats_to_last_value = false) const;
+ int force(const std::vector<std::string>& paths,const std::string& state_or_event,bool recursive = false,bool set_repeats_to_last_value = false) const;
+
+ int freeDep(const std::vector<std::string>& paths,bool trigger = true, bool all = false, bool date = false, bool time = false) const;
+ int freeDep(const std::string& absNodePath,bool trigger = true, bool all = false, bool date = false, bool time = false) const;
+
+ int file(const std::string& absNodePath, const std::string& fileType, const std::string& max_lines = "10000") const;
+
+ int plug(const std::string& sourcePath, const std::string& destPath) const;
+
+ int alter(const std::vector<std::string>& paths,
+ const std::string& alterType, /* one of [ add | change | delete | set_flag | clear_flag ] */
+ const std::string& attrType,
+ const std::string& name = "",
+ const std::string& value = "") const { return invoke(CtsApi::alter(paths,alterType,attrType,name,value)); }
+ int alter(const std::string& path,
+ const std::string& alterType, /* one of [ add | change | delete | set_flag | clear_flag ] */
+ const std::string& attrType,
+ const std::string& name = "",
+ const std::string& value = "") const { return invoke(CtsApi::alter(path,alterType,attrType,name,value)); }
+
+ int reloadwsfile() const;
+ int group(const std::string& groupRequest) const;
+
+ int logMsg(const std::string& msg) const;
+ int new_log(const std::string& new_path = "") const;
+ int getLog(int lastLines = 0) const;
+ int clearLog() const;
+ int flushLog() const;
+ int get_log_path() const;
+
+ int forceDependencyEval() const;
+
+ /// The first is for use by CLI(Commend level interface), the other are for ecFlowview/Python
+ int edit_script( const std::string& path_to_task,
+ const std::string& edit_type,
+ const std::string& path_to_script = "",
+ bool create_alias = false,
+ bool run = true)
+ {return invoke(CtsApi::edit_script(path_to_task,edit_type,path_to_script,create_alias,run));}
+ int edit_script_edit(const std::string& path_to_task); // ecFlowview EDIT
+ int edit_script_preprocess(const std::string& path_to_task); // ecFlowview PRE_PROCESS
+ int edit_script_submit(const std::string& path_to_task,const NameValueVec& used_variables ); // ecFlowview SUBMIT
+ int edit_script_preprocess(const std::string& path_to_task,const std::vector<std::string>& file_contents); // ecFlowview PRE_PROCESS USER File
+ int edit_script_submit(const std::string& path_to_task,
+ const NameValueVec& used_variables,
+ const std::vector<std::string>& file_contents,
+ bool alias = false,
+ bool run = true); // ecFlowview SUBMIT_FILE
+
+private:
+ /// returns 1 on error and 0 on success. The errorMsg can be accessed via errorMsg()
+ int invoke( const std::string& arg ) const;
+ int invoke( const std::vector<std::string>& args ) const;
+ int invoke(Cmd_ptr) const; // assumes clients of Cmd_ptr constructor has caught exceptions
+
+ int do_invoke_cmd(Cmd_ptr) const;
+ int load_in_memory_defs( const defs_ptr& clientDefs, bool force) const; /// For clients that want to load a in memory definition into the server.
+ std::string client_env_host_port() const;
+ void check_child_parameters() const;
+
+private:
+ friend class RoundTripRecorder;
+ friend class RequestLogger;
+private:
+ bool on_error_throw_exception_;
+ bool cli_; // Command Line Interface. Controls whether output written to standard out
+ bool test_; // used in testing only
+ bool testInterface_; // used in testing only
+ unsigned int connection_attempts_; // No of attempts to establish connection with the server
+ unsigned int retry_connection_period_; // No of seconds to wait before trying to connect in case of failure.
+
+ std::string child_task_path_; // support for python child commands
+ std::string child_task_password_; // support for python child commands
+ std::string child_task_pid_; // support for python child commands
+ int child_task_try_no_; // support for python child commands
+
+ mutable boost::posix_time::time_duration rtt_;// record latency for each cmd.
+ mutable boost::posix_time::ptime start_time_; // Used for time out and measuring latency
+ mutable ClientEnvironment clientEnv_; // Will read the environment *once* on construction. Must be before Client options
+ mutable ClientOptions args_; // Used for argument parsing & creating client request
+ mutable ServerReply server_reply_; // stores the local defs, client_handle, & all server replies
+
+ /// For use by python interface,
+ std::vector<std::string>::const_iterator changed_node_paths_begin() const { return server_reply_.changed_nodes().begin();}
+ std::vector<std::string>::const_iterator changed_node_paths_end() const { return server_reply_.changed_nodes().end();}
+ friend void export_Client();
+};
+
+// Allow logging and debug output of request round trip times
+class RequestLogger : private boost::noncopyable {
+public:
+ RequestLogger(const ClientInvoker* ci);
+ ~RequestLogger();
+ void set_cts_cmd(Cmd_ptr cmd) { cmd_ = cmd;}
+private:
+ const ClientInvoker* ci_;
+ Cmd_ptr cmd_;
+};
+
+class RoundTripRecorder : private boost::noncopyable {
+public:
+ RoundTripRecorder(const ClientInvoker* ci);
+ ~RoundTripRecorder();
+private:
+ const ClientInvoker* ci_;
+};
+
+#endif
diff --git a/Client/src/ClientMain.cpp b/Client/src/ClientMain.cpp
new file mode 100644
index 0000000..4c4b286
--- /dev/null
+++ b/Client/src/ClientMain.cpp
@@ -0,0 +1,32 @@
+//============================================================================
+// Name : ClientMain
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include "ClientInvoker.hpp"
+#include <iostream>
+
+int main( int argc, char* argv[] ) {
+
+ /// By default, error condition will throw exception.
+ try {
+ ClientInvoker client;
+ client.set_cli(true); // output log and file commands to standard out
+ (void) client.invoke(argc,argv);
+ }
+ catch (std::exception& e ) {
+ std::cerr << e.what() << std::endl;
+ return 1;
+ }
+ return 0;
+}
diff --git a/Client/src/ClientOptions.cpp b/Client/src/ClientOptions.cpp
new file mode 100644
index 0000000..0825cc5
--- /dev/null
+++ b/Client/src/ClientOptions.cpp
@@ -0,0 +1,329 @@
+//============================================================================
+// Name : ClientOptions
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Delegates argument parsing to the registered commands
+//============================================================================
+#include <boost/lexical_cast.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/bind.hpp>
+#include <iostream>
+#include <iomanip>
+
+#include "ClientOptions.hpp"
+#include "ClientEnvironment.hpp"
+#include "Version.hpp"
+#include "Str.hpp"
+#include "Ecf.hpp"
+#include "Child.hpp"
+#include "TaskApi.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost;
+namespace po = boost::program_options;
+
+static const char* client_env_description();
+static const char* client_task_env_description();
+
+
+ClientOptions::ClientOptions()
+{
+ // This could have been moved to parse(). However since the same ClienttInvoker can be
+ // be used for multiple commands. We have separated out the parts the need only be done once.
+ // hence improving the performance:
+ std::string title_help = "Client options, ";
+ title_help += Version::description();
+ title_help += " ";
+ desc_ = new po::options_description( title_help , po::options_description::m_default_line_length + 80 );
+
+ // This will iterate over all the registered client to server commands and
+ // Each command will add to the option description, its required arguments
+ cmdRegistry_.addAllOptions(*desc_);
+
+ // Allow the host,port and rid to be overridden by the command line
+ // This allows the jobs, which make other calls to ecflow_client from interfering with each other
+ desc_->add_options()("rid",po::value< string >()->implicit_value( string("") ),
+ "rid: If specified will override the environment variable ECF_RID, Can only be used for child commands");
+ desc_->add_options()("port",po::value< string >()->implicit_value( string("") ),
+ "port: If specified will override the environment variable ECF_PORT and default port number of 3141");
+ desc_->add_options()("host",po::value< string >()->implicit_value( string("") ),
+ "host: If specified will override the environment variable ECF_NODE and default host, localhost");
+}
+
+ClientOptions::~ClientOptions()
+{
+ delete desc_;
+}
+
+Cmd_ptr ClientOptions::parse(int argc, char* argv[],ClientEnvironment* env) const
+{
+ if (env->debug()) {
+ cout << " ClientOptions::parse argc=" << argc;
+ for(int i = 0; i < argc; i++) { cout << " arg" << i << "=" << argv[i];}
+ cout << "\n";
+ std::cout << " help column width = " << po::options_description::m_default_line_length + 80 << "\n";
+ }
+
+ // parse arguments into 'vm'.
+ // --alter delete cron -w 0,1 10:00 /s1 # -w treated as option
+ // --alter=/s1 change meter name -1 # -1 treated as option
+ // Note: negative numbers get treated as options: i.e trying to change meter value to a negative number
+ // To avoid negative numbers from being treated as option use, we need to change command line style:
+ // po::command_line_style::unix_style ^ po::command_line_style::allow_short
+ boost::program_options::variables_map vm;
+ po::store( po::parse_command_line( argc, argv, *desc_ ,po::command_line_style::unix_style ^ po::command_line_style::allow_short), vm );
+ po::notify( vm );
+
+
+ // Check to see if host or port, specified. This will override the environment variables
+ std::string host,port;
+ if ( vm.count( "port" ) ) {
+ port = vm[ "port" ].as< std::string > ();
+ if (env->debug()) std::cout << " port " << port << " overridden at the command line\n";
+ try { boost::lexical_cast< int >( port );}
+ catch ( boost::bad_lexical_cast& e ) {
+ std::stringstream ss; ss << "ClientOptions::parse: The specified port(" << port << ") must be convertible to an integer";
+ throw std::runtime_error( ss.str() );
+ }
+ }
+ if ( vm.count( "host" ) ) {
+ host = vm[ "host" ].as< std::string > ();
+ if (env->debug()) std::cout << " host " << host << " overridden at the command line\n";
+ }
+ if (!host.empty() || !port.empty()) {
+ if (host.empty()) host = env->hostSpecified(); // get the environment variable ECF_NODE
+ if (port.empty()) port = env->portSpecified(); // get the environment variable ECF_PORT
+ if (host.empty()) host = Str::LOCALHOST(); // if ECF_NODE not specified default to localhost
+ if (port.empty()) port = Str::DEFAULT_PORT_NUMBER(); // if ECF_PORT not specified use default
+ env->set_host_port(host,port);
+ }
+ if ( vm.count( "rid" ) ) {
+ std::string rid = vm[ "rid" ].as< std::string > ();
+ if (env->debug()) std::cout << " rid " << rid << " overridden at the command line\n";
+ env->set_remote_id(rid);
+ }
+
+ // Defer the parsing of the command , to the command. This allows
+ // all cmd functionality to be centralised with the command
+ // This can throw std::runtime_error if arg's don't parse
+ Cmd_ptr client_request;
+ if ( ! cmdRegistry_.parse( client_request, vm, env) ) {
+
+ // The arguments did *NOT* match with any of the registered command.
+ // Hence if arguments don't match help, debug or version its an error
+ // Note: we did *NOT* check for a NULL client_request since *NOT* all
+ // request need to create it. Some commands are client specific.
+ // For example:
+ // --server_load // this is sent to server
+ // --server_load=<path> // no command returned, command executed by client
+ if ( vm.count( "help" ) ) {
+ string help_cmd = vm[ "help" ].as< std::string > ();
+ show_help(help_cmd);
+ return client_request;
+ }
+
+ if ( vm.count( "debug" ) ) {
+ cout << env->toString() << "\n";
+ return client_request;
+ }
+
+ if ( vm.count( "version" ) ) {
+ cout << Version::description() << "\n";
+ exit(0);
+ }
+
+ std::stringstream ss;
+ ss << "ClientOptions::parse: Arguments did not match any commands.\n";
+ ss << " argc=" << argc << "\n"; for(int i = 0; i < argc; i++) { ss << " arg" << i << "=" << argv[i];}
+ ss << "\nUse --help to see all the available commands\n";
+ throw std::runtime_error(ss.str());
+ }
+
+ return client_request;
+}
+
+void ClientOptions::show_help(const std::string & help_cmd) const
+{
+ // WARNING: This assumes that there are no user/child commands with name 'summary','all','child','user'
+ if (help_cmd.empty()) {
+
+ cout << "\nClient/server based work flow package:\n\n";
+ cout << Version::description() << "\n\n";
+ cout << Ecf::CLIENT_NAME() << " provides the command line interface, for interacting with the server:\n";
+
+ cout << "Try:\n\n";
+ cout << " " << Ecf::CLIENT_NAME() << " --help=all # List all commands, verbosely\n";
+ cout << " " << Ecf::CLIENT_NAME() << " --help=summary # One line summary of all commands\n";
+ cout << " " << Ecf::CLIENT_NAME() << " --help=child # One line summary of child commands\n";
+ cout << " " << Ecf::CLIENT_NAME() << " --help=user # One line summary of user command\n";
+ cout << " " << Ecf::CLIENT_NAME() << " --help=<cmd> # Detailed help on each command\n\n";
+
+ show_all_commands("Commands:");
+ }
+ else {
+ if (help_cmd == "all") cout << *desc_ << "\n";
+ else if (help_cmd == "summary") show_cmd_summary("\nEcflow client commands:\n");
+ else if (help_cmd == "child") show_cmd_summary("\nEcflow child client commands:\n","child");
+ else if (help_cmd == "user") show_cmd_summary("\nEcflow user client commands:\n","user");
+ else {
+ // Help on individual command
+ const po::option_description* od = desc_->find_nothrow(help_cmd,
+ true, /*approx, will find nearest match*/
+ false, /*long_ignore_case = false*/
+ false /*short_ignore_case = false*/
+ );
+// cout << "long_name = " << od.long_name() << "\n";
+// cout << "format_name = " << od.format_name() << "\n";
+// cout << "format_parameter = " << od.format_parameter() << "\n";
+ if (od) {
+ cout << "\n";
+ cout << od->long_name() << "\n";
+ for(size_t i =0; i< od->long_name().size(); i++) cout << "-";
+ cout << "\n\n";
+ cout << od->description() << "\n\n";
+ cout << client_env_description();
+ if ( od->long_name() == TaskApi::initArg() ||
+ od->long_name() == TaskApi::completeArg() ||
+ od->long_name() == TaskApi::abortArg() ||
+ od->long_name() == TaskApi::waitArg() ||
+ od->long_name() == TaskApi::eventArg() ||
+ od->long_name() == TaskApi::labelArg() ||
+ od->long_name() == TaskApi::meterArg()) {
+ cout << "\n";
+ cout << client_task_env_description();
+ }
+ }
+ else {
+ show_all_commands("No matching command found, please choose from:");
+ }
+ }
+ }
+}
+
+void ClientOptions::show_all_commands(const char* title) const
+{
+ cout << title << "\n";
+ // take a copy, since we need to sort
+ std::vector< boost::shared_ptr<po::option_description> > options = desc_->options();
+
+ // sort using long_name
+ std::sort(options.begin(),options.end(),
+ boost::bind(std::less<std::string>(),
+ boost::bind(&po::option_description::long_name,_1),
+ boost::bind(&po::option_description::long_name,_2)));
+
+ size_t vec_size = options.size();
+ size_t max_width = 0;
+ for(size_t i = 0; i < vec_size; i++) { max_width = std::max(max_width,options[i]->long_name().size()); }
+ max_width += 1;
+ for(size_t i = 0; i < vec_size; i++) {
+ if (i == 0 || i % 5 == 0) cout << "\n ";
+ cout << left << std::setw(max_width) << options[i]->long_name();
+ }
+ cout << "\n";
+}
+
+void ClientOptions::show_cmd_summary(const char *title,const std::string& user_or_child) const
+{
+ assert(user_or_child.empty() || user_or_child == "child" || user_or_child == "user");
+ cout << title << "\n";
+
+ // take a copy, since we need to sort
+ std::vector< boost::shared_ptr<po::option_description> > options = desc_->options();
+
+ // sort using long_name
+ std::sort(options.begin(),options.end(),
+ boost::bind(std::less<std::string>(),
+ boost::bind(&po::option_description::long_name,_1),
+ boost::bind(&po::option_description::long_name,_2)));
+
+ size_t vec_size = options.size();
+ size_t max_width = 0;
+ for(size_t i = 0; i < vec_size; i++) { max_width = std::max(max_width,options[i]->long_name().size()); }
+ max_width += 1;
+ for(size_t i = 0; i < vec_size; i++) {
+
+ if (user_or_child == "child" && Child::valid_child_cmd(options[i]->long_name())) {
+ std::vector< std::string > lines;
+ Str::split(options[i]->description(),lines,"\n");
+ if (!lines.empty()) {
+ cout << " " << left << std::setw(max_width) << options[i]->long_name() << " ";
+ cout << "child ";
+ cout << lines[0] << "\n";
+ }
+ }
+ else if (user_or_child == "user" && !Child::valid_child_cmd(options[i]->long_name())) {
+ std::vector< std::string > lines;
+ Str::split(options[i]->description(),lines,"\n");
+ if (!lines.empty()) {
+ cout << " " << left << std::setw(max_width) << options[i]->long_name() << " ";
+ cout << "user ";
+ cout << lines[0] << "\n";
+ }
+ }
+ else if (user_or_child .empty()) {
+ std::vector< std::string > lines;
+ Str::split(options[i]->description(),lines,"\n");
+ if (!lines.empty()) {
+ cout << " " << left << std::setw(max_width) << options[i]->long_name() << " ";
+ if (Child::valid_child_cmd(options[i]->long_name())) cout << "child ";
+ else cout << "user ";
+ cout << lines[0] << "\n";
+ }
+ }
+ }
+ cout << "\n";
+}
+
+const char* client_env_description() {
+ return
+ "The client reads in the following environment variables. These are read by user and child command\n\n"
+ "|----------|----------|------------|-------------------------------------------------------------------|\n"
+ "| Name | Type | Required | Description |\n"
+ "|----------|----------|------------|-------------------------------------------------------------------|\n"
+ "| ECF_NODE | <string> | Mandatory* | The host name of the main server. defaults to 'localhost' |\n"
+ "| ECF_PORT | <int> | Mandatory* | The TCP/IP port to call on the server. Must be unique to a server |\n"
+ "|----------|----------|------------|-------------------------------------------------------------------|\n\n"
+ "* The host and port must be specified in order for the client to communicate with the server, this can \n"
+ " be done by setting ECF_NODE, ECF_PORT or by specifying --host=<host> --port=<int> on the command line\n"
+ ;
+}
+
+const char* client_task_env_description()
+{
+ return
+ "The following environment variables are specific to child commands.\n"
+ "The scripts should export the mandatory variables. Typically defined in the head/tail includes files\n\n"
+ "|--------------|----------|-----------|---------------------------------------------------------------|\n"
+ "| Name | Type | Required | Description |\n"
+ "|--------------|----------|-----------|---------------------------------------------------------------|\n"
+ "| ECF_NAME | <string> | Mandatory | Full path name to the task |\n"
+ "| ECF_PASS | <string> | Mandatory | The jobs password, allocated by server, then used by server to|\n"
+ "| | | | authenticate client request |\n"
+ "| ECF_TRYNO | <int> | Mandatory | The number of times the job has run. This is allocated by the |\n"
+ "| | | | server, and used in job/output file name generation. |\n"
+ "| ECF_RID | <string> | Mandatory | The process identifier. Helps zombies identification and |\n"
+ "| | | | automated killing of running jobs |\n"
+ "| ECF_TIMEOUT | <int> | optional | Max time in *seconds* for client to deliver message to main |\n"
+ "| | | | server. The default is 24 hours |\n"
+ "| ECF_HOSTFILE | <string> | optional | File that lists alternate hosts to try, if connection to main |\n"
+ "| | | | host fails |\n"
+ "| ECF_DENIED | <any> | optional | Provides a way for child to exit with an error, if server |\n"
+ "| | | | denies connection. Avoids 24hr wait. Note: when you have |\n"
+ "| | | | hundreds of tasks, using this approach requires a lot of |\n"
+ "| | | | manual intervention to determine job status |\n"
+ "| NO_ECF | <any> | optional | If set exit's ecflow_client immediately with success. This |\n"
+ "| | | | allows the scripts to be tested independent of the server |\n"
+ "|--------------|----------|-----------|---------------------------------------------------------------|\n"
+ ;
+}
+
diff --git a/Client/src/ClientOptions.hpp b/Client/src/ClientOptions.hpp
new file mode 100644
index 0000000..2d98eb6
--- /dev/null
+++ b/Client/src/ClientOptions.hpp
@@ -0,0 +1,50 @@
+#ifndef CLIENTOPTIONS_HPP_
+#define CLIENTOPTIONS_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name : ClientOptions
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Will parse the client argument line, and construct a command
+// that will be sent to the server.
+//
+// The environment must be read in before the program options. The program options
+// will construct the commands, some of which require the environment
+// We could have just done this as last part of constructor. However we need a
+// separation between reading the environment and reading the option for:
+// a/ testing purposes. i.e as this allows us to inject/override the task path
+// read in from the environment.
+// b/ override host and port number.
+// will throw std::runtime_error for invalid arguments
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/noncopyable.hpp>
+#include "CtsCmdRegistry.hpp"
+class ClientEnvironment;
+
+class ClientOptions : private boost::noncopyable {
+public:
+ /// Will create command register, & ask each cmd to describe their arguments
+ ClientOptions();
+ ~ClientOptions();
+
+ /// parse the arguments and create the client request that is to be sent
+ /// to the server. Will throw std::runtime_error if invalid arguments specified
+ Cmd_ptr parse(int argc, char* argv[], ClientEnvironment*) const;
+
+private:
+
+ void show_help(const std::string& help_cmd) const;
+ void show_all_commands(const char* title) const;
+ void show_cmd_summary(const char* title, const std::string& user_or_child = "") const;
+
+ CtsCmdRegistry cmdRegistry_;
+ boost::program_options::options_description* desc_;
+};
+#endif
diff --git a/Client/src/Rtt.cpp b/Client/src/Rtt.cpp
new file mode 100644
index 0000000..2133a74
--- /dev/null
+++ b/Client/src/Rtt.cpp
@@ -0,0 +1,180 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Simple singleton implementation of log
+//============================================================================
+#include <assert.h>
+#include <vector>
+#include <iostream>
+#include <boost/lexical_cast.hpp>
+#include <boost/foreach.hpp>
+#include "boost/date_time/posix_time/posix_time.hpp" //include all types plus i/o
+
+#include "Rtt.hpp"
+#include "File.hpp"
+#include "Str.hpp"
+#include "Indentor.hpp"
+
+using namespace std;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+
+namespace ecf {
+
+Rtt* Rtt::instance_ = NULL;
+
+void Rtt::create(const std::string& filename)
+{
+ if ( instance_ == NULL) {
+ instance_ = new Rtt(filename);
+ }
+}
+
+void Rtt::destroy()
+{
+ delete instance_;
+ instance_ = NULL;
+}
+
+
+Rtt::Rtt(const std::string& filename)
+: file_(filename.c_str(), ios::out | ios::app)
+{
+ if (!file_.is_open()) {
+ std::cerr << "Rtt::Rtt Could not open file '" << filename << "'\n";
+ std::runtime_error("Rtt::Rtt: Could not open file " + filename);
+ }
+}
+
+Rtt::~Rtt(){}
+
+void Rtt::log(const std::string& message)
+{
+ file_ << message << endl;
+}
+
+void rtt(const std::string& message)
+{
+ if (Rtt::instance()) {
+ Rtt::instance()->log(message);
+ }
+}
+
+std::string Rtt::analyis(const std::string& filename)
+{
+ std::vector<std::string> lines;
+ if (!File::splitFileIntoLines(filename,lines)) {
+ std::cout << "Rtt::analyis: could not open file " << filename << "\n";
+ return string();
+ }
+
+ // Typical format
+ // localhost:3141 --ping :ma0 rtt:00:00:00.001082
+ // localhost:3141 --log=new Test/data/ECF_HOME/test_wait_cmd/test_wait_cmd.def_log :ma0 rtt:00:00:00.000930
+ // localhost:3141 --zombie_get :ma0 rtt:00:00:00.003982
+
+ /// Extract the command name and time, and add to map, to compute averages, min,max & standard deviation
+ map<string,vector<time_duration> > cmd_time_map;
+ size_t max_cmd_size = 0;
+ for(size_t i = 0; i < lines.size(); i++) {
+
+ if (lines[i].empty()) continue;
+// cout << i << ":" << lines[i] << " ";
+ string::size_type dash = lines[i].find("--");
+ string::size_type rtt_pos = lines[i].find(Rtt::tag());
+ if (dash == std::string::npos) continue;
+ if (rtt_pos == std::string::npos) continue;
+
+
+ int cmd_length = 0;
+ string::size_type equals = lines[i].find("=",dash);
+ string::size_type space = lines[i].find(" ",dash);
+ if (equals != std::string::npos) cmd_length = equals;
+ else if (space != std::string::npos) cmd_length = space;
+ string cmd = lines[i].substr(0,cmd_length);
+ max_cmd_size = std::max(max_cmd_size,cmd.size());
+
+ string time = lines[i].substr(rtt_pos+4);
+ time_duration td(duration_from_string(time));
+// cout << " cmd:(" << cmd << ") time(" << to_simple_string(td) << ")\n";
+
+ map<string,vector<time_duration> >::iterator cmd_iterator = cmd_time_map.find(cmd);
+ if ( cmd_iterator == cmd_time_map.end()) {
+ vector<time_duration> vec;
+ vec.push_back(td);
+ std::pair<string, vector<time_duration> > p = std::make_pair(cmd,vec);
+ cmd_time_map.insert( p );
+ }
+ else {
+ (*cmd_iterator).second.push_back(td);
+ }
+ }
+
+ time_duration total(0,0,0,0);
+ int total_requests = 0;
+
+ // Create title
+ std::stringstream ss;
+ ss << left << setw(max_cmd_size+1) << "Command" << right << setw(5) << "count" << setw(9) << "min" << setw(9) << "average" << setw(9) << "max" << setw(9) << right << "std\n";
+ std::pair<string, vector<time_duration> > p;
+ BOOST_FOREACH(p, cmd_time_map) {
+
+ time_duration average_td(0,0,0,0);
+ time_duration min(24,59,59,0);
+ time_duration max(0,0,0,0);
+ for(size_t i = 0; i < p.second.size(); i++) {
+ average_td += p.second[i];
+ total_requests++;
+ total += p.second[i];
+ min = std::min(min,p.second[i]);
+ max = std::max(max,p.second[i]);
+ }
+
+ ss << left << setw(max_cmd_size+1) << p.first << setw(5) << right << p.second.size();
+ if (p.second.empty()) {
+ ss << setw(9) << right << p.second[0].total_microseconds() << " ? ";
+ }
+ else if ( p.second.size() == 1) {
+ ss << setw(9) << right << p.second[0].total_microseconds();
+ }
+ else {
+ int average = average_td.total_microseconds()/p.second.size();
+
+// bool debug = false;
+// if (p.first == "begin") debug = true;
+
+ // compute standard deviation
+ unsigned int total_diff_from_avg = 0;
+ for(size_t i = 0; i < p.second.size(); i++) {
+ int diff = p.second[i].total_microseconds() - average;
+ int diff_squared = diff * diff;
+ total_diff_from_avg += diff_squared;
+// if (debug) cout << "diff: " << diff << " diff_squared: " << diff_squared << " total_diff_from_avg: " << total_diff_from_avg << "\n";
+ }
+
+ double avg = total_diff_from_avg/p.second.size();
+ int stdd = (int)sqrt(avg);
+// if (debug) cout << "avg: " << avg << " stdd: " << stdd << "\n";
+
+ ss << setw(9) << right << min.total_microseconds() ;
+ ss << setw(9) << right << average;
+ ss << setw(9) << right << max.total_microseconds();
+ ss << setw(9) << right << stdd;
+ }
+ ss << "\n";
+ }
+ ss << "\ntotal round trip time " << to_simple_string(total) << " for " << total_requests << " requests\n";
+ return ss.str();
+}
+
+}
+
diff --git a/Client/src/Rtt.hpp b/Client/src/Rtt.hpp
new file mode 100644
index 0000000..a9b6ead
--- /dev/null
+++ b/Client/src/Rtt.hpp
@@ -0,0 +1,62 @@
+#ifndef RTT_HPP_
+#define RTT_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name : Rtt
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Simple client based singleton for recording round trip times
+// of all client based command
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <string>
+#include <fstream>
+#include <sstream>
+#include <boost/noncopyable.hpp>
+#include <boost/lambda/lambda.hpp>
+
+namespace ecf {
+
+class Rtt : private boost::noncopyable {
+public:
+ static void create(const std::string& filename);
+ static void destroy();
+ static Rtt* instance() { return instance_;}
+
+ void log(const std::string& message);
+
+ /// Open the file, and create average times for all client invoker round trip times
+ static std::string analyis(const std::string& filename);
+
+ /// Used in output and parsing, when computing averages
+ static const char* tag() { return "rtt:";}
+
+private:
+ ~Rtt();
+ Rtt(const std::string& filename);
+ static Rtt* instance_;
+ mutable std::ofstream file_;
+};
+
+void rtt(const std::string& message);
+
+// allow user to do the following:
+// RTT("this is " << path << " ok ");
+//
+// helper, see STRINGIZE() macro
+template <typename Functor>
+std::string stringize_rtt(Functor const & f) {
+ std::ostringstream out;
+ f(out);
+ return out.str();
+}
+#define STRINGIZE_RTT(EXPRESSION) (ecf::stringize_rtt(boost::lambda::_1 << EXPRESSION))
+#define RTT(EXPRESSION) ecf::rtt(STRINGIZE_RTT(EXPRESSION))
+}
+#endif
diff --git a/Client/src/UrlCmd.cpp b/Client/src/UrlCmd.cpp
new file mode 100644
index 0000000..83c4171
--- /dev/null
+++ b/Client/src/UrlCmd.cpp
@@ -0,0 +1,66 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Client side command only.
+// Placed in this category, since the server does not need to link
+// with it.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/foreach.hpp>
+#include "UrlCmd.hpp"
+#include "Defs.hpp"
+#include "Node.hpp"
+
+UrlCmd::UrlCmd(defs_ptr defs, const std::string& absNodePath)
+: defs_(defs),node_(NULL)
+{
+ if (!defs_.get()) {
+ throw std::runtime_error("UrlCmd: The definition parameter is empty");
+ }
+
+ if (absNodePath.empty()) {
+ throw std::runtime_error("UrlCmd: The node path parameter is empty");
+ }
+
+ node_ = defs_->findAbsNode(absNodePath).get();
+ if ( !node_ ) {
+ std::string errorMsg = "UrlCmd: The node path parameter '";
+ errorMsg += absNodePath;
+ errorMsg += "' can not be found.";
+ throw std::runtime_error(errorMsg);
+ }
+}
+
+std::string UrlCmd::getUrl() const
+{
+ std::string url;
+ node_->findParentUserVariableValue("ECF_URL_CMD", url);
+ if (url.empty()) {
+ std::string errorMsg = "UrlCmd: Could not find variable ECF_URL_CMD from node ";
+ errorMsg += node_->absNodePath();
+ throw std::runtime_error(errorMsg);
+ }
+
+ if (!node_->variableSubsitution(url)) {
+ std::string errorMsg = "UrlCmd:: Variable substitution failed for ";
+ errorMsg += url;
+ throw std::runtime_error(errorMsg);
+ }
+ return url;
+}
+
+void UrlCmd::execute() const
+{
+ // invoke as a system command, we don't use System::instance()
+ // since this is on the client side. hence no need manage the spawned process
+ system(getUrl().c_str());
+}
+
diff --git a/Client/src/UrlCmd.hpp b/Client/src/UrlCmd.hpp
new file mode 100644
index 0000000..35a406c
--- /dev/null
+++ b/Client/src/UrlCmd.hpp
@@ -0,0 +1,40 @@
+#ifndef URL_CMD_HPP_
+#define URL_CMD_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Version : Beta version for test use only
+// Revision : $Revision$
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Client side command only.
+// Placed in this category, since the server does not need to link
+// with it.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <string>
+#include <boost/noncopyable.hpp>
+#include "NodeFwd.hpp"
+
+class UrlCmd : private boost::noncopyable {
+public:
+ /// Will throw std::runtime_error if defs or node path is not correct
+ UrlCmd(defs_ptr defs, const std::string& absNodePath );
+
+ /// Will throw std::runtime_error if url can not be formed
+ std::string getUrl() const;
+
+ /// Execute the url command
+ void execute() const;
+
+private:
+ defs_ptr defs_;
+ Node* node_;
+};
+
+#endif
diff --git a/Client/test/InvokeServer.hpp b/Client/test/InvokeServer.hpp
new file mode 100644
index 0000000..619a13c
--- /dev/null
+++ b/Client/test/InvokeServer.hpp
@@ -0,0 +1,157 @@
+#ifndef INVOKESERVER_HPP_
+#define INVOKESERVER_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #32 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <iostream>
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include <boost/noncopyable.hpp>
+
+#include "TestHelper.hpp"
+#include "ClientInvoker.hpp"
+#include "Str.hpp"
+#include "File.hpp"
+#include "EcfPortLock.hpp"
+#include "Host.hpp"
+
+class InvokeServer : private boost::noncopyable {
+public:
+ InvokeServer(const std::string& msg,
+ const std::string& port = ecf::Str::DEFAULT_PORT_NUMBER(),
+ bool disable_job_generation = false,
+ bool remove_checkpt_file_before_server_start = true,
+ bool remove_checkpt_file_after_server_exit = true
+ ) : port_(port),
+ host_(ClientEnvironment::hostSpecified()),
+ remove_checkpt_file_after_server_exit_(remove_checkpt_file_after_server_exit)
+ {
+ if (host_.empty()) {
+ if(!msg.empty()) std::cout << msg << " port(" << port_ << ")" << std::endl;
+
+ doStart(port_,disable_job_generation,remove_checkpt_file_before_server_start);
+ }
+ else {
+ // Start of test, clear any existing defs on remote/localhost server
+ // Assuming this has been started on input port
+ std::string test_name = msg;
+ test_name += " on ";
+ test_name += host_;
+ test_name += ecf::Str::COLON();
+ test_name += port_;
+
+ std::cout << test_name << std::endl;
+
+ ClientInvoker theClient(host_,port_);
+ theClient.logMsg( test_name );
+ BOOST_REQUIRE_MESSAGE( theClient.delete_all() == 0,CtsApi::to_string(CtsApi::delete_node()) << " failed should return 0. Should Delete ALL existing defs in the server\n" << theClient.errorMsg());
+ }
+ }
+
+ InvokeServer(const std::string& port,
+ bool stop_ambiguaty,
+ bool disable_job_generation = false,
+ bool remove_checkpt_file_before_server_start = true,
+ bool remove_checkpt_file_after_server_exit = true
+ ) : port_(port),
+ remove_checkpt_file_after_server_exit_(remove_checkpt_file_after_server_exit)
+ {
+ // host_ is empty.
+ doStart(port_,disable_job_generation,remove_checkpt_file_before_server_start);
+ }
+
+ ~InvokeServer() {
+ // This will also remove the generated files.
+ // Will only terminate local server, host_ is *EMPTY* for local server, using two constructors above
+ if (host_.empty()) {
+ doEnd(ecf::Str::LOCALHOST(), port_, remove_checkpt_file_after_server_exit_);
+ }
+ }
+
+ const std::string& port() const { return port_; }
+ const std::string& host() const { if (host_.empty()) return ecf::Str::LOCALHOST(); return host_; }
+
+ std::string ecf_log_file() const { return host_name_.ecf_log_file(port_);}
+ std::string ecf_checkpt_file() const { return host_name_.ecf_checkpt_file(port_); }
+ std::string ecf_backup_checkpt_file() const { return host_name_.ecf_backup_checkpt_file(port_); }
+
+
+ static void doStart(const std::string& port,bool disable_job_generation = false, bool remove_checkpt_file_before_server_start = true)
+ {
+ /// Remove check pt and backup check pt file, else server will load it & remove log file
+ ecf::Host h;
+ if (remove_checkpt_file_before_server_start) {
+ boost::filesystem::remove(h.ecf_checkpt_file(port));
+ boost::filesystem::remove(h.ecf_backup_checkpt_file(port));
+ }
+ boost::filesystem::remove(h.ecf_log_file(port));
+
+ // start the server in the background
+ std::string theServerInvokePath = ecf::File::find_ecf_server_path();
+ BOOST_REQUIRE_MESSAGE(!theServerInvokePath.empty(),"InvokeServer::doStart: The server program could not be found");
+ BOOST_REQUIRE_MESSAGE(boost::filesystem::exists(theServerInvokePath),"InvokeServer::doStart: server exe does not exist at:" << theServerInvokePath);
+
+ // Create a port file. To avoid creating multiple servers on the same port number
+ ecf::EcfPortLock::create( port );
+
+ // Make sure server starts in the background to avoid hanging test
+ theServerInvokePath += " --port=" + port;
+ if (disable_job_generation) {
+ theServerInvokePath += " --dis_job_gen";
+ }
+ theServerInvokePath += " &";
+
+ //std::cout << "InvokeServer::doStart port = " << port << " server path = " << theServerInvokePath << "\n";
+ (void)system( theServerInvokePath.c_str() );
+
+ // Allow time for server process to kick in.
+ ClientInvoker theClient(ecf::Str::LOCALHOST(),port);
+ BOOST_REQUIRE_MESSAGE(theClient.wait_for_server_reply(),"InvokeServer::doStart: Server failed to start after 60 second on " << ecf::Str::LOCALHOST() << ":" << port);
+ }
+
+
+ static void doEnd( const std::string& host, const std::string& port, bool remove_checkpt_file_after_server_exit )
+ {
+ // std::cout << "*****InvokeServer::doEnd Closing server on " << host << ecf::Str::COLON() << port << "\n";
+ {
+ ClientInvoker theClient(host,port);
+ BOOST_REQUIRE_NO_THROW( theClient.terminateServer() );
+ BOOST_REQUIRE_MESSAGE( theClient.wait_for_server_death(),"Failed to terminate server after 60 seconds\n");
+ }
+
+ // remove port file. This prevented multiple different process from opening servers with same port number
+ ecf::EcfPortLock::remove( port );
+
+ // Remove generated file comment for debug
+ ecf::Host h;
+ boost::filesystem::remove(h.ecf_log_file(port));
+ BOOST_CHECK_MESSAGE(!boost::filesystem::exists(h.ecf_log_file(port)), "log file " << h.ecf_log_file(port) << " not deleted\n");
+
+ if (remove_checkpt_file_after_server_exit) {
+ boost::filesystem::remove(h.ecf_checkpt_file(port));
+ boost::filesystem::remove(h.ecf_backup_checkpt_file(port));
+ BOOST_CHECK_MESSAGE(!boost::filesystem::exists(h.ecf_checkpt_file(port)), "file " << h.ecf_checkpt_file(port) << " not deleted\n");
+ BOOST_CHECK_MESSAGE(!boost::filesystem::exists(h.ecf_backup_checkpt_file(port)), "file " << h.ecf_backup_checkpt_file(port) << " not deleted\n");
+ }
+ }
+
+private:
+ InvokeServer(const InvokeServer&);
+ std::string port_;
+ std::string host_;
+ ecf::Host host_name_;
+ bool remove_checkpt_file_after_server_exit_;
+};
+
+#endif
diff --git a/Client/test/SCPort.cpp b/Client/test/SCPort.cpp
new file mode 100644
index 0000000..e97c8b0
--- /dev/null
+++ b/Client/test/SCPort.cpp
@@ -0,0 +1,63 @@
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #8 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <iostream>
+#include "SCPort.hpp"
+#include "EcfPortLock.hpp"
+#include "ClientInvoker.hpp"
+
+namespace ecf {
+
+// init the globals. Note we dont use 3141, so that in the case where we already
+// have a remote/local server started external to the test, it does not clash
+// Also debug and release version use different port numbers to avoid clashes, if both tests run at same time
+
+#ifdef DEBUG
+int SCPort::thePort_ = 3161;
+#else
+int SCPort::thePort_ = 3142;
+#endif
+
+std::string SCPort::next()
+{
+ std::string host;
+ char* ecf_host = getenv("ECF_NODE");
+ if ( ecf_host ) host = ecf_host;
+ if ( host == "localhost" ) {
+
+ std::string port;
+ char* ecf_port = getenv("ECF_PORT");
+ if ( ecf_port ) port = ecf_port;
+ if (!port.empty()) {
+
+ //std::cout << "SCPort::next() ECF_NODE(" << host << ") ECF_PORT(" << port << ")\n";
+ return port;
+ }
+ }
+
+ return next_only();
+}
+
+std::string SCPort::next_only()
+{
+ // Use a combination of local lock file, and pinging the server
+ while (!EcfPortLock::is_free(thePort_)) thePort_++;
+
+ // std::cout << "SCPort::next() = " << thePort << "\n";
+ return ClientInvoker::find_free_port(thePort_);
+}
+
+}
diff --git a/Client/test/SCPort.hpp b/Client/test/SCPort.hpp
new file mode 100644
index 0000000..ab0f160
--- /dev/null
+++ b/Client/test/SCPort.hpp
@@ -0,0 +1,44 @@
+#ifndef PORT_HPP_
+#define PORT_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <string>
+
+namespace ecf {
+
+// If two different process/servers both try to use the same port number, you
+// get an "Address in use" error, even if one the process is dead. This is
+// because the kernel does not immediately release the resource and there is
+// time out period. To get round this we will start the new server/client
+// and use a different port number.
+
+class SCPort {
+public:
+ /// Check ECF_HOST and ECF_PORT first, otherwise calls next_only
+ static std::string next();
+
+ /// make sure we have a unique port, each time next_only() is called;
+ static std::string next_only();
+
+private:
+ SCPort();
+ ~SCPort();
+
+ static int thePort_;
+};
+}
+
+#endif
diff --git a/Client/test/TestCheckPtDefsCmd.cpp b/Client/test/TestCheckPtDefsCmd.cpp
new file mode 100644
index 0000000..f40cef5
--- /dev/null
+++ b/Client/test/TestCheckPtDefsCmd.cpp
@@ -0,0 +1,237 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #29 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <string>
+#include <fstream>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/test/unit_test.hpp>
+
+#include "ClientInvoker.hpp"
+#include "ClientEnvironment.hpp"
+#include "InvokeServer.hpp"
+#include "SCPort.hpp"
+#include "Str.hpp"
+#include "File.hpp"
+
+namespace fs = boost::filesystem;
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( ClientTestSuite )
+
+// ************************************************************************************
+// Note: If you make edits to node tree, they will have no effect until the server is rebuilt
+// ************************************************************************************
+BOOST_AUTO_TEST_CASE( test_check_pt_defs_cmd )
+{
+ // This will remove check pt and backup file before server start, to avoid the server from loading previous test data
+ InvokeServer invokeServer("Client:: ...test_check_pt_defs_cmd",SCPort::next());
+
+ ClientInvoker theClient(invokeServer.host(),invokeServer.port());
+ BOOST_REQUIRE_MESSAGE( theClient.restartServer() == 0,CtsApi::restartServer() << " should return 0 server not started, or connection refused\n" << theClient.errorMsg());
+
+ std::string path = File::test_data("Client/test/data/lifecycle.txt","Client");
+
+ BOOST_REQUIRE_MESSAGE(theClient.loadDefs(path) == 0,"load defs failed \n" << theClient.errorMsg());
+
+ // First time. Should create a ecf_checkpt_file, but _no_ backup file
+ BOOST_REQUIRE_MESSAGE(theClient.checkPtDefs() == 0,CtsApi::checkPtDefs() << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(fs::exists(invokeServer.ecf_checkpt_file()),CtsApi::checkPtDefs() << " failed file(" << invokeServer.ecf_checkpt_file() << ") not saved");
+ BOOST_REQUIRE_MESSAGE(fs::file_size(invokeServer.ecf_checkpt_file()) !=0,"Expected check point file(" << invokeServer.ecf_checkpt_file() << "), to have file size > 0");
+ if (ClientEnvironment::hostSpecified().empty()) {
+ // This check only valid if server was invoked locally. Ignore for remote servers
+ BOOST_REQUIRE_MESSAGE(!fs::exists(invokeServer.ecf_backup_checkpt_file()), "Backup check point file(" << invokeServer.ecf_backup_checkpt_file() << ")should not exist,for very first time.");
+ }
+
+ // Save checkpoint file again. This should create a backup file, we should have ecf_checkpt_file and ecf_backup_checkpt_file
+ BOOST_REQUIRE_MESSAGE(theClient.checkPtDefs() == 0,CtsApi::checkPtDefs() << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(fs::exists(invokeServer.ecf_checkpt_file()),CtsApi::checkPtDefs() << " failed No check pt file(" << invokeServer.ecf_checkpt_file() << ") saved");
+ BOOST_REQUIRE_MESSAGE(fs::file_size(invokeServer.ecf_checkpt_file()) !=0,"Expected check point file(" << invokeServer.ecf_checkpt_file() << ") to have file size > 0 ");
+ BOOST_REQUIRE_MESSAGE(fs::exists(invokeServer.ecf_backup_checkpt_file()), "Backup check point file(" << invokeServer.ecf_backup_checkpt_file() << ") not created");
+ BOOST_REQUIRE_MESSAGE(fs::file_size(invokeServer.ecf_backup_checkpt_file()) !=0,"Expected backup check point file(" << invokeServer.ecf_backup_checkpt_file() << "), to have file size > 0");
+
+ // Check the defaults for mode , interval and alarm time before making any changes
+ BOOST_REQUIRE_MESSAGE(theClient.stats() == 0,CtsApi::stats() << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_mode_ == ecf::CheckPt::ON_TIME, " Expected default check pt mode to be ON_TIME");
+ BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_interval_ == CheckPt::default_interval(), " Expected default check pt interval of " << CheckPt::default_interval() << " but found " << theClient.server_reply().stats().checkpt_interval_);
+ BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_save_time_alarm_ == CheckPt::default_save_time_alarm(), " Expected default check pt alarm time of " << CheckPt::default_save_time_alarm() << " but found " << theClient.server_reply().stats().checkpt_save_time_alarm_);
+
+
+ // Test change of check_pt interval and mode and alarm
+ BOOST_REQUIRE_MESSAGE(theClient.checkPtDefs(ecf::CheckPt::NEVER) == 0,CtsApi::checkPtDefs(ecf::CheckPt::NEVER) << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.stats() == 0,CtsApi::stats() << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_mode_ == ecf::CheckPt::NEVER, " Expected check pt mode of NEVER");
+
+ BOOST_REQUIRE_MESSAGE(theClient.checkPtDefs(ecf::CheckPt::ON_TIME) == 0,CtsApi::checkPtDefs(ecf::CheckPt::ON_TIME) << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.stats() == 0,CtsApi::stats() << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_mode_ == ecf::CheckPt::ON_TIME, " Expected check pt mode of ON_TIME");
+
+ BOOST_REQUIRE_MESSAGE(theClient.checkPtDefs(ecf::CheckPt::ALWAYS) == 0,CtsApi::checkPtDefs(ecf::CheckPt::ALWAYS) << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.stats() == 0,CtsApi::stats() << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_mode_ == ecf::CheckPt::ALWAYS, " Expected check pt mode of ALWAYS");
+
+ BOOST_REQUIRE_MESSAGE(theClient.checkPtDefs(ecf::CheckPt::ON_TIME,30) == 0,CtsApi::checkPtDefs(ecf::CheckPt::ON_TIME,30) << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.stats() == 0,CtsApi::stats() << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_mode_ == ecf::CheckPt::ON_TIME, " Expected check pt mode of ON_TIME");
+ BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_interval_ == 30, " Expected check pt interval of 30 but found " << theClient.server_reply().stats().checkpt_interval_);
+
+ BOOST_REQUIRE_MESSAGE(theClient.checkPtDefs(ecf::CheckPt::UNDEFINED,56) == 0,CtsApi::checkPtDefs(ecf::CheckPt::UNDEFINED,56) << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.stats() == 0,CtsApi::stats() << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_mode_ == ecf::CheckPt::ON_TIME, " Expected check pt mode of ON_TIME");
+ BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_interval_ == 56, " Expected check pt interval of 56 but found " << theClient.server_reply().stats().checkpt_interval_);
+
+ // Mode and interval should remain unchanged only the alarm time should be changed
+ BOOST_REQUIRE_MESSAGE(theClient.checkPtDefs(ecf::CheckPt::UNDEFINED,0,10) == 0,CtsApi::checkPtDefs(ecf::CheckPt::UNDEFINED,0,10) << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.stats() == 0,CtsApi::stats() << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_mode_ == ecf::CheckPt::ON_TIME, " Expected check pt mode of ON_TIME");
+ BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_interval_ == 56, " Expected check pt interval of 56 but found " << theClient.server_reply().stats().checkpt_interval_);
+ BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_save_time_alarm_ == 10, " Expected check pt alarm time of 10 but found " << theClient.server_reply().stats().checkpt_save_time_alarm_);
+
+ // restore default check pointing for test that follow.
+ BOOST_REQUIRE_MESSAGE(theClient.checkPtDefs(ecf::CheckPt::ON_TIME,CheckPt::default_interval()) == 0,CtsApi::checkPtDefs(ecf::CheckPt::ON_TIME) << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.checkPtDefs(ecf::CheckPt::UNDEFINED,0,CheckPt::default_save_time_alarm()) == 0,CtsApi::checkPtDefs(ecf::CheckPt::ON_TIME) << " failed should return 0\n" << theClient.errorMsg());
+
+ // check defaults were set
+ BOOST_REQUIRE_MESSAGE(theClient.stats() == 0,CtsApi::stats() << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_mode_ == ecf::CheckPt::ON_TIME, " Expected default check pt mode to be ON_TIME");
+ BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_interval_ == CheckPt::default_interval(), " Expected default check pt interval of " << CheckPt::default_interval() << " but found " << theClient.server_reply().stats().checkpt_interval_);
+ BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_save_time_alarm_ == CheckPt::default_save_time_alarm(), " Expected default check pt alarm time of " << CheckPt::default_save_time_alarm() << " but found " << theClient.server_reply().stats().checkpt_save_time_alarm_);
+}
+
+
+BOOST_AUTO_TEST_CASE( test_restore_from_check_pt )
+{
+ InvokeServer invokeServer("Client:: ...test_restore_from_check_pt",SCPort::next());
+
+ defs_ptr the_defs = Defs::create();
+ the_defs->add_suite("s0");
+ the_defs->add_suite("s1");
+ the_defs->add_suite("s2");
+ the_defs->add_suite("s3");
+ the_defs->add_suite("s4");
+
+ ClientInvoker theClient(invokeServer.host(),invokeServer.port());
+ BOOST_REQUIRE_MESSAGE(theClient.load(the_defs) == 0,"load defs failed \n" << theClient.errorMsg());
+
+ size_t expected_no_of_suites = 5;
+ for(int i = 0; i < 5; i++) {
+ BOOST_REQUIRE_MESSAGE(theClient.checkPtDefs() == 0,CtsApi::checkPtDefs() << " failed should return 0\n" << theClient.errorMsg());
+
+ BOOST_REQUIRE_MESSAGE( theClient.delete_all() == 0,"Expected delete all nodes to succeed\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.haltServer() == 0,"Expected halt server to succeed\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.restoreDefsFromCheckPt() == 0,"Expected restoreDefsFromCheckPt succeed\n");
+ BOOST_REQUIRE_MESSAGE( theClient.getDefs() == 0, "Expected getDefs() to succeed, i.e expected empty defs\n");
+ BOOST_REQUIRE_MESSAGE( theClient.defs()->suiteVec().size() == expected_no_of_suites, "Expected " << expected_no_of_suites << " suites, after restoreDefsFromCheckPt but found " << theClient.defs()->suiteVec().size() << "\n");
+
+ std::string suite = "/s" + boost::lexical_cast<std::string>(i);
+ BOOST_REQUIRE_MESSAGE( theClient.delete_node(suite) == 0,"Expected delete single suite to succeed\n" << theClient.errorMsg());
+ expected_no_of_suites--;
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_restore_from_check_pt_using_new_server )
+{
+ // This test relies on a NEW server invocation. Hence if ECF_NODE/remote server is used
+ // the test will will invalid. hence ignore.
+ if (!ClientEnvironment::hostSpecified().empty()) {
+ cout << "Client:: ...test_restore_from_check_pt_using_new_server: ignoring test when ECF_NODE specified\n";
+ return;
+ }
+
+ std::string port = SCPort::next();
+ {
+ // Start a new server. However make sure that on server exist we not delete check pt files
+ InvokeServer invokeServer("Client:: ...test_restore_from_check_pt_using_new_server",
+ port,
+ false, /* bool disable_job_generation = false */
+ true, /* bool remove_checkpt_file_before_server_start = true */
+ false /* bool remove_checkpt_file_after_server_exit = true */
+ );
+
+ defs_ptr the_defs = Defs::create();
+ the_defs->add_suite("s0");
+ the_defs->add_suite("s1");
+ the_defs->add_suite("s2");
+ the_defs->add_suite("s3");
+ the_defs->add_suite("s4");
+
+ ClientInvoker theClient(invokeServer.host(),invokeServer.port());
+ BOOST_REQUIRE_MESSAGE( theClient.load(the_defs) == 0,"load defs failed \n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.checkPtDefs() == 0,CtsApi::checkPtDefs() << " failed should\n" << theClient.errorMsg());
+ }
+
+ // start a new server, using same port. Make sure on start, we do not delete any checkpt files on start up
+ // server should load check pt file on start up
+ InvokeServer invokeServer("", /* for debug use -new server- as msg */
+ port,
+ false, /* bool disable_job_generation = false */
+ false, /* bool remove_checkpt_file_before_server_start = true */
+ true /* bool remove_checkpt_file_after_server_exit = true */
+ );
+
+ ClientInvoker theClient(invokeServer.host(),invokeServer.port());
+ BOOST_REQUIRE_MESSAGE( theClient.sync_local() == 0, "Expected sync_local() to succeed \n");
+ BOOST_REQUIRE_MESSAGE( theClient.defs(), "Expected sync_local() to succeed defs is empty\n");
+ BOOST_REQUIRE_MESSAGE( theClient.defs()->suiteVec().size() == 5, "Expected 5 suites, after restoreDefsFromCheckPt but found " << theClient.defs()->suiteVec().size() << "\n");
+}
+
+BOOST_AUTO_TEST_CASE( test_check_pt_edit_history )
+{
+ // This test relies on a NEW server invocation. Hence if ECF_NODE/remote server is used
+ // the test will will invalid. hence ignore.
+ if (!ClientEnvironment::hostSpecified().empty()) {
+ cout << "Client:: ...test_check_pt_edit_history: ignoring test when ECF_NODE specified\n";
+ return;
+ }
+
+ // This will remove check pt and backup file before server start, to avoid the server from loading previous test data
+ InvokeServer invokeServer("Client:: ...test_check_pt_edit_history",SCPort::next());
+
+ ClientInvoker theClient(invokeServer.host(),invokeServer.port());
+ BOOST_REQUIRE_MESSAGE(theClient.edit_history(Str::ROOT_PATH()) == 0,CtsApi::to_string(CtsApi::edit_history(Str::ROOT_PATH())) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.server_reply().get_string_vec().size() == 0,"Expected edit history of size 0 after server start, but found " << theClient.server_reply().get_string_vec().size());
+
+
+ // make 5 edits
+ BOOST_REQUIRE_MESSAGE( theClient.restartServer() == 0,CtsApi::restartServer() << " should return 0 server not started, or connection refused\n" << theClient.errorMsg());
+ std::string path = File::test_data("Client/test/data/lifecycle.txt","Client");
+ BOOST_REQUIRE_MESSAGE(theClient.loadDefs(path) == 0,"load defs failed \n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.shutdownServer() == 0,CtsApi::shutdownServer() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.haltServer() == 0,CtsApi::haltServer() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.restartServer() == 0,CtsApi::restartServer() << " should return 0\n" << theClient.errorMsg());
+
+ // make sure edit history updated
+ BOOST_REQUIRE_MESSAGE(theClient.edit_history(Str::ROOT_PATH()) == 0,CtsApi::to_string(CtsApi::edit_history(Str::ROOT_PATH())) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.server_reply().get_string_vec().size() == 5,"Expected edit history of size 5, but found " << theClient.server_reply().get_string_vec().size());
+
+ // make sure edit history was *NOT* serialized, It is only serialized when check pointing
+ BOOST_REQUIRE_MESSAGE(theClient.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.defs()->get_edit_history(Str::ROOT_PATH()).size() == 0,"Expected edit history of size 0, but found " << theClient.defs()->get_edit_history(Str::ROOT_PATH()).size());
+
+ // This should write the edit history
+ BOOST_REQUIRE_MESSAGE(theClient.checkPtDefs(ecf::CheckPt::ALWAYS) == 0,CtsApi::checkPtDefs(ecf::CheckPt::ALWAYS) << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(fs::exists(invokeServer.ecf_checkpt_file()),CtsApi::checkPtDefs() << " failed No check pt file(" << invokeServer.ecf_checkpt_file() << ") saved");
+ BOOST_REQUIRE_MESSAGE(fs::file_size(invokeServer.ecf_checkpt_file()) !=0,"Expected check point file(" << invokeServer.ecf_checkpt_file() << ") to have file size > 0 ");
+
+
+ // Create a defs file from the check pt file & check edit history
+ Defs defs;
+ defs.restore_from_checkpt(invokeServer.ecf_checkpt_file()); // make a data model change
+ BOOST_REQUIRE_MESSAGE(defs.get_edit_history(Str::ROOT_PATH()).size() == 5,"Expected edit history of size 5, but found " << defs.get_edit_history(Str::ROOT_PATH()).size());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/Client/test/TestClientEnvironment.cpp b/Client/test/TestClientEnvironment.cpp
new file mode 100644
index 0000000..4e1da3a
--- /dev/null
+++ b/Client/test/TestClientEnvironment.cpp
@@ -0,0 +1,256 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #9 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <iostream>
+#include <vector>
+#include <string>
+
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+
+#include "ClientEnvironment.hpp"
+#include "Str.hpp"
+#include "File.hpp"
+
+namespace fs = boost::filesystem;
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( ClientTestSuite )
+
+// **************************************************************************************
+// test the client environment:
+// In particular test host file parsing
+// **************************************************************************************
+BOOST_AUTO_TEST_CASE( test_client_environment_host_file_parsing )
+{
+ std::cout << "Client:: ...test_client_environment_host_file_parsing" << endl;
+
+ std::string good_host_file = File::test_data("Client/test/data/good_hostfile","Client");
+
+ // local host should be implicitly added to internal host list
+ std::vector<std::string> expectedHost;
+ expectedHost.push_back(Str::LOCALHOST());
+ expectedHost.push_back("host1");
+ expectedHost.push_back("host2");
+ expectedHost.push_back("host3");
+ expectedHost.push_back("host4");
+ expectedHost.push_back("host5");
+ expectedHost.push_back("host6");
+
+
+ ClientEnvironment client_env( good_host_file );
+// cout << "client_env " << client_env.toString() << "\n";
+ std::string home_host = client_env.host();
+ std::string host;
+// cout << "client_env home host " << client_env.host() << " job supplied port " << client_env.port() << "\n";
+ size_t count = 0;
+ BOOST_CHECK_MESSAGE( home_host == expectedHost[count], "Expected home host " << expectedHost[count] << " but found " << home_host);
+
+ bool home_host_fnd = false;
+ while (home_host != host) {
+ // Cycle through the host until we reach the home host
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE( client_env.get_next_host(errorMsg), errorMsg);
+// cout << "client_env host " << client_env.host() << " port " << client_env.port() << "\n";
+ host = client_env.host();
+ count++;
+ if (host == home_host) {
+ home_host_fnd = true ;
+ count = 0;
+ }
+ BOOST_REQUIRE_MESSAGE( count < expectedHost.size(), "Test file out of date");
+ BOOST_CHECK_MESSAGE( host == expectedHost[count], "Expected host " << expectedHost[count] << " but found " << host);
+ }
+ BOOST_CHECK_MESSAGE( home_host_fnd, "Cycling through host file, should lead to home host");
+}
+
+BOOST_AUTO_TEST_CASE( test_client_environment_host_file_defaults )
+{
+ std::cout << "Client:: ...test_client_environment_host_file_defaults" << endl;
+
+ // When the HOST file does *NOT* indicate the port, it should be taken
+ // from the config/environment.
+ // In file good_hostfile, host3 and host5 do not specify a port, hence
+ // this port is assumed to be the job supplied port, that was read from
+ // config or environment. To test this correctly we need to specify a port
+ // other than the default
+
+ std::string good_host_file = File::test_data("Client/test/data/good_hostfile","Client");
+
+
+ // local host should be implicitly added to internal host list
+ std::vector<std::pair<std::string,std::string> > expectedHost;
+ expectedHost.push_back( make_pair(Str::LOCALHOST(), string("5111")) ); // here 5111 is job supplied port
+ expectedHost.push_back( make_pair(string("host1"), string("3142")) );
+ expectedHost.push_back( make_pair(string("host2"), string("3141")) );
+ expectedHost.push_back( make_pair(string("host3"), string("5111")) ); // not specified in host file, hence expect 5111
+ expectedHost.push_back( make_pair(string("host4"), string("4001")) );
+ expectedHost.push_back( make_pair(string("host5"), string("5111")) ); // not specified in host file, hence expect 5111
+ expectedHost.push_back( make_pair(string("host6"), string("4081")) );
+
+ // Create the ClientEnvironment overriding the config & environment. To specify host and port
+ ClientEnvironment client_env( good_host_file , Str::LOCALHOST(),"5111");
+// cout << "client_env " << client_env.toString() << "\n";
+ std::string home_host = client_env.host();
+ std::string home_port = client_env.port();
+ BOOST_CHECK_MESSAGE( Str::LOCALHOST() == home_host && "5111" == home_port,"host host & port not as expected");
+
+ std::string host;
+// cout << "client_env home host " << client_env.host() << " job supplied port " << client_env.port() << "\n";
+ size_t count = 0;
+ bool home_host_fnd = false;
+ while (home_host != host) {
+ // Cycle through the host until we reach the home host
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE( client_env.get_next_host(errorMsg), errorMsg);
+// cout << "client_env host " << client_env.host() << " port " << client_env.port() << "\n";
+ host = client_env.host();
+ std::string port = client_env.port();
+ count++;
+ if (host == home_host) {
+ BOOST_CHECK_MESSAGE( count-1 == 6, "Expected 6 hosts in host file"); // ignore last increment of count, hence -1
+ home_host_fnd = true ;
+ count = 0;
+ }
+ BOOST_REQUIRE_MESSAGE( count < expectedHost.size(), "Test file out of date");
+ BOOST_CHECK_MESSAGE( host == expectedHost[count].first, "Expected host " << expectedHost[count].first << " but found " << host);
+ BOOST_CHECK_MESSAGE( port == expectedHost[count].second, "Expected port " << expectedHost[count].second << " but found " << port);
+ }
+ BOOST_CHECK_MESSAGE( home_host_fnd, "Cycling through host file, should lead to home host");
+}
+
+
+BOOST_AUTO_TEST_CASE( test_client_environment_empty_host_file )
+{
+ std::cout << "Client:: ...test_client_environment_empty_host_file" << endl;
+
+ std::string empty_host_file = File::test_data("Client/test/data/empty_hostfile","Client");
+
+ std::string errormsg;
+ BOOST_CHECK_MESSAGE(File::create(empty_host_file,"",errormsg), "Failed to create empty host file " << errormsg);
+
+ ClientEnvironment client_env( empty_host_file );
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE( client_env.get_next_host(errorMsg),errorMsg);
+ BOOST_CHECK_MESSAGE( client_env.get_next_host(errorMsg),errorMsg);
+
+ fs::remove(empty_host_file);
+}
+
+
+BOOST_AUTO_TEST_CASE( test_client_environment_errors )
+{
+ if (getenv("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")) {
+ cout << "Client:: ...test_client_environment_errors-ECF_ALLOW_NEW_CLIENT_OLD_SERVER: ignoring test when ECF_ALLOW_NEW_CLIENT_OLD_SERVER specified\n";
+ return;
+ }
+ if (getenv("ECF_PORT")) {
+ cout << "Client:: ...test_client_environment_errors-ECF_ALLOW_NEW_CLIENT_OLD_SERVER: ignoring test when ECF_PORT specified\n";
+ return;
+ }
+
+ std::cout << "Client:: ...test_client_environment_errors-ECF_ALLOW_NEW_CLIENT_OLD_SERVER" << endl;
+ {
+ char* put = const_cast<char*>("ECF_ALLOW_NEW_CLIENT_OLD_SERVER=xx");
+ BOOST_CHECK_MESSAGE(putenv(put) == 0,"putenv failed for " << put);
+ BOOST_CHECK_THROW(ClientEnvironment client_env, std::runtime_error );
+ putenv(const_cast<char*>("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")); // remove from env, otherwise valgrind complains
+ }
+
+ {
+ // ONLY run this test if enviroment variable ECF_PORT not defined
+ std::string env = "ECF_ALLOW_NEW_CLIENT_OLD_SERVER=";
+ env += Str::LOCALHOST(); env += ":"; env += Str::DEFAULT_PORT_NUMBER(); env += ":xx";
+ BOOST_CHECK_MESSAGE(putenv(const_cast<char*>(env.c_str())) == 0,"putenv failed for " << env);
+ BOOST_CHECK_THROW(ClientEnvironment client_env, std::runtime_error );
+ putenv(const_cast<char*>("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")); // remove from env, otherwise valgrind complains
+ }
+ {
+ std::string env = "ECF_ALLOW_NEW_CLIENT_OLD_SERVER=";
+ env += Str::LOCALHOST(); env += ":"; env += Str::DEFAULT_PORT_NUMBER(); env += "xx";
+ BOOST_CHECK_MESSAGE(putenv(const_cast<char*>(env.c_str())) == 0,"putenv failed for " << env);
+ BOOST_CHECK_THROW(ClientEnvironment client_env, std::runtime_error );
+ putenv(const_cast<char*>("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")); // remove from env, otherwise valgrind complains
+ }
+ {
+ std::string env = "ECF_ALLOW_NEW_CLIENT_OLD_SERVER=";
+ env += Str::LOCALHOST(); env += Str::DEFAULT_PORT_NUMBER(); env += "12";
+ BOOST_CHECK_MESSAGE(putenv(const_cast<char*>(env.c_str())) == 0,"putenv failed for " << env);
+ BOOST_CHECK_THROW(ClientEnvironment client_env, std::runtime_error );
+ putenv(const_cast<char*>("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")); // remove from env, otherwise valgrind complains
+ }
+ {
+ std::stringstream ss;
+ ss << "ECF_ALLOW_NEW_CLIENT_OLD_SERVER=fred:2222:0,bill:333:2222," << Str::LOCALHOST() << ":" << Str::DEFAULT_PORT_NUMBER() << ":xx";
+ std::string env = ss.str();
+ BOOST_CHECK_MESSAGE(putenv(const_cast<char*>(env.c_str())) == 0,"putenv failed for " << env);
+ BOOST_CHECK_THROW(ClientEnvironment client_env, std::runtime_error );
+ putenv(const_cast<char*>("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")); // remove from env, otherwise valgrind complains
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_client_environment )
+{
+ if (getenv("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")) {
+ cout << "Client:: ...test_client_environment-ECF_ALLOW_NEW_CLIENT_OLD_SERVER: ignoring test when ECF_ALLOW_NEW_CLIENT_OLD_SERVER specified\n";
+ return;
+ }
+ if (getenv("ECF_PORT")) {
+ cout << "Client:: ...test_client_environment-ECF_ALLOW_NEW_CLIENT_OLD_SERVER: ignoring test when ECF_PORT specified\n";
+ return;
+ }
+
+ std::cout << "Client:: ...test_client_environment-ECF_ALLOW_NEW_CLIENT_OLD_SERVER" << endl;
+ {
+ std::string env = "ECF_ALLOW_NEW_CLIENT_OLD_SERVER=";
+ env += Str::LOCALHOST(); env += ":"; env += Str::DEFAULT_PORT_NUMBER(); env += ":11";
+ BOOST_CHECK_MESSAGE(putenv(const_cast<char*>(env.c_str())) == 0,"putenv failed for " << env);
+ ClientEnvironment client_env;
+ BOOST_CHECK_MESSAGE(client_env.allow_new_client_old_server()==11,"Expected 11 but found " << client_env.allow_new_client_old_server() << " for env " << env);
+ putenv(const_cast<char*>("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")); // remove from env, otherwise valgrind complains
+ }
+ {
+ std::stringstream ss;
+ ss << "ECF_ALLOW_NEW_CLIENT_OLD_SERVER=fred:2222:0,bill:333:2222," << Str::LOCALHOST() << ":" << Str::DEFAULT_PORT_NUMBER() << ":" << 33;
+ std::string env = ss.str();
+ BOOST_CHECK_MESSAGE(putenv(const_cast<char*>(env.c_str())) == 0,"putenv failed for " << env);
+ ClientEnvironment client_env;
+ BOOST_CHECK_MESSAGE(client_env.allow_new_client_old_server()==33,"Expected 33 but found " << client_env.allow_new_client_old_server() << " for env " << env);
+ putenv(const_cast<char*>("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")); // remove from env, otherwise valgrind complains
+ }
+ {
+ // Create a valid ECF_ALLOW_NEW_CLIENT_OLD_SERVER list where there is no match with our host/port.
+ // hence allow_new_client_old_server should remain zero
+ std::stringstream ss;
+ ss << "ECF_ALLOW_NEW_CLIENT_OLD_SERVER=fred:2222:0,bill:333:2222,bill:333:2222,bill:333:2222,bill:333:2222,bill:333:2222";
+ std::string env = ss.str();
+ BOOST_CHECK_MESSAGE(putenv(const_cast<char*>(env.c_str())) == 0,"putenv failed for " << env);
+ ClientEnvironment client_env;
+ BOOST_CHECK_MESSAGE(client_env.allow_new_client_old_server()==0,"Should remain unchanged but found " << client_env.allow_new_client_old_server());
+ putenv(const_cast<char*>("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")); // remove from env, otherwise valgrind complains
+ }
+ {
+ char* put = const_cast<char*>("ECF_ALLOW_NEW_CLIENT_OLD_SERVER=10");
+ BOOST_CHECK_MESSAGE(putenv(put) == 0,"putenv failed for " << put);
+ ClientEnvironment client_env;
+ BOOST_CHECK_MESSAGE(client_env.allow_new_client_old_server()==10,"expcted 10 but found " << client_env.allow_new_client_old_server());
+ putenv(const_cast<char*>("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")); // remove from env, otherwise valgrind complains
+ }
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/Client/test/TestClientInterface.cpp b/Client/test/TestClientInterface.cpp
new file mode 100644
index 0000000..6d0e593
--- /dev/null
+++ b/Client/test/TestClientInterface.cpp
@@ -0,0 +1,564 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #75 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <fstream>
+#include <iostream>
+
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/foreach.hpp>
+
+#include "ClientInvoker.hpp"
+#include "ClientToServerCmd.hpp"
+#include "ClientEnvironment.hpp"
+#include "NState.hpp"
+#include "Defs.hpp"
+#include "Task.hpp"
+#include "Suite.hpp"
+#include "Child.hpp"
+#include "File.hpp"
+#include "Flag.hpp"
+
+namespace fs = boost::filesystem;
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( ClientTestSuite )
+
+// **************************************************************************************
+// test the interface, this will create the cmd without actually submitting to the server
+// This will test argument parsing.
+// **************************************************************************************
+BOOST_AUTO_TEST_CASE( test_client_interface )
+{
+ std::cout << "Client:: ...test_client_interface" << endl;
+
+ ClientInvoker theClient ;
+ theClient.testInterface(); // stops submission to server
+ std::vector<std::string> paths; paths.push_back("/s1"); paths.push_back("/s2");
+
+ BOOST_REQUIRE_MESSAGE( theClient.delete_all() == 0,CtsApi::to_string(CtsApi::delete_node()) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.shutdownServer() == 0,CtsApi::shutdownServer() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.haltServer() == 0,CtsApi::haltServer() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.restartServer() == 0,CtsApi::restartServer() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.terminateServer() == 0,CtsApi::terminateServer() << " should return 0\n" << theClient.errorMsg());
+
+ BOOST_REQUIRE_MESSAGE( theClient.server_version() == 0,CtsApi::server_version() << " should return 0\n" << theClient.errorMsg());
+
+ {
+ defs_ptr dummy_defs = Defs::create();
+ BOOST_REQUIRE_MESSAGE( theClient.sync(dummy_defs) == 0, std::string(CtsApi::syncArg()) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.news(dummy_defs) == 0, std::string(CtsApi::newsArg()) << " should return 0\n" << theClient.errorMsg());
+ }
+
+ BOOST_REQUIRE_MESSAGE( theClient.server_load("/path/to_log/file") == 0,CtsApi::server_load("/path/to_log/file") << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.server_load() == 0,CtsApi::server_load("") << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.pingServer() == 0,CtsApi::pingServer() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.debug_server_on() == 0,CtsApi::debug_server_on() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.debug_server_off() == 0,CtsApi::debug_server_off() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.stats() == 0,CtsApi::stats() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.stats_reset() == 0,CtsApi::stats_reset() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.suites() == 0,CtsApi::suites() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.getDefs() == 0,CtsApi::get() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.begin("/suite") == 0,CtsApi::begin("/suite") << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.begin("/suite",true) == 0,CtsApi::begin("/suite",true) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.begin("/suite",false) == 0,CtsApi::begin("/suite",false) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.begin_all_suites() == 0,CtsApi::begin() << " should return 0\n" << theClient.errorMsg());
+
+
+ Zombie z(Child::USER,ecf::Child::INIT,ZombieAttr::get_default_attr(Child::USER),"path_to_task","DUMMY_JOBS_PASSWORD", "DUMMY_PROCESS_OR_REMOTE_ID",1);
+ BOOST_REQUIRE_MESSAGE( theClient.zombieGet() == 0,CtsApi::zombieGet() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.zombieFob(z) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.zombieFail(z) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.zombieAdopt(z) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.zombieBlock(z) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.zombieRemove(z) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.zombieKill(z) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.zombieFobCli("path_to_task") == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.zombieFailCli("path_to_task") == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.zombieAdoptCli("path_to_task") == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.zombieBlockCli("path_to_task") == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.zombieRemoveCli("path_to_task") == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.zombieKillCli("path_to_task") == 0, " should return 0\n" << theClient.errorMsg());
+
+ BOOST_REQUIRE_MESSAGE( theClient.job_gen("") == 0,CtsApi::job_gen("") << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.job_gen("/s") == 0,CtsApi::job_gen("/s") << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.check("") == 0,CtsApi::to_string(CtsApi::check("")) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.check("/s") == 0,CtsApi::to_string(CtsApi::check("/s")) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.check(paths) == 0,CtsApi::to_string(CtsApi::check(paths)) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.kill("/s") == 0,CtsApi::to_string(CtsApi::kill("/s")) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.kill(paths) == 0,CtsApi::to_string(CtsApi::kill(paths)) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.status("/s") == 0,CtsApi::to_string(CtsApi::status("/s")) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.status(paths) == 0,CtsApi::to_string(CtsApi::status(paths)) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.suspend("/s") == 0,CtsApi::to_string(CtsApi::suspend("/s"))<< " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.suspend(paths) == 0,CtsApi::to_string(CtsApi::suspend(paths))<< " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.resume("/s") == 0,CtsApi::to_string(CtsApi::resume("/s")) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.resume(paths) == 0,CtsApi::to_string(CtsApi::resume(paths)) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.edit_history("/s") == 0,CtsApi::to_string(CtsApi::edit_history("/s")) << " should return 0\n" << theClient.errorMsg());
+
+ // empty string should be same as delete all
+ BOOST_REQUIRE_MESSAGE( theClient.delete_node("") == 0,CtsApi::to_string(CtsApi::delete_node()) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.delete_node("/s") == 0,CtsApi::to_string(CtsApi::delete_node("/s")) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.delete_node("/s",true) == 0,CtsApi::to_string(CtsApi::delete_node("/s",true)) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.delete_node("/s",false) == 0,CtsApi::to_string(CtsApi::delete_node("/s",false)) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.delete_nodes(paths,false) == 0,CtsApi::to_string(CtsApi::delete_node(paths,false)) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.delete_nodes(paths,true) == 0,CtsApi::to_string(CtsApi::delete_node(paths,false)) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.delete_all() == 0,CtsApi::to_string(CtsApi::delete_node()) << " should return 0\n" << theClient.errorMsg());
+
+ BOOST_REQUIRE_MESSAGE( theClient.requeue("/s","") == 0, CtsApi::to_string(CtsApi::requeue("/s","")) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.requeue("/s","force") == 0, CtsApi::to_string(CtsApi::requeue("/s","force")) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.requeue("/s","abort") == 0, CtsApi::to_string(CtsApi::requeue("/s","abort")) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.requeue(paths,"") == 0, CtsApi::to_string(CtsApi::requeue(paths,"")) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.requeue(paths,"force") == 0,CtsApi::to_string(CtsApi::requeue(paths,"force")) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.requeue(paths,"abort") == 0,CtsApi::to_string(CtsApi::requeue(paths,"abort")) << " should return 0\n" << theClient.errorMsg());
+
+
+ BOOST_REQUIRE_MESSAGE( theClient.run("/s") == 0,CtsApi::to_string(CtsApi::run("/s")) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.run("/s",true) == 0,CtsApi::to_string(CtsApi::run("/s",true)) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.run(paths) == 0,CtsApi::to_string(CtsApi::run(paths)) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.run(paths,true) == 0,CtsApi::to_string(CtsApi::run(paths,true)) << " should return 0\n" << theClient.errorMsg());
+
+
+ std::string path = File::test_data("Client/test/data/lifecycle.txt","Client");
+ BOOST_REQUIRE_MESSAGE( theClient.loadDefs(path) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.loadDefs(path,true/*force*/) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.loadDefs(path,true/*force*/,true/*check_only*/) == 0, "should return 0\n" << theClient.errorMsg());
+
+ BOOST_REQUIRE_MESSAGE( theClient.replace("/suite1",path) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.replace("/suite1",path,true) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.replace("/suite1",path,true, true) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.replace("/suite1",path,false, true) == 0, " should return 0\n" << theClient.errorMsg());
+
+ BOOST_REQUIRE_MESSAGE( theClient.order("/s","top") == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.order("/s","bottom") == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.order("/s","alpha") == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.order("/s","order") == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.order("/s","up") == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.order("/s","down") == 0, " should return 0\n" << theClient.errorMsg());
+
+ BOOST_REQUIRE_MESSAGE( theClient.checkPtDefs() == 0,CtsApi::checkPtDefs() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.checkPtDefs(ecf::CheckPt::NEVER) == 0," should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.checkPtDefs(ecf::CheckPt::ON_TIME) == 0," should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.checkPtDefs(ecf::CheckPt::ON_TIME,180) == 0," should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.checkPtDefs(ecf::CheckPt::ALWAYS) == 0," should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.checkPtDefs(ecf::CheckPt::UNDEFINED) == 0," should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.checkPtDefs(ecf::CheckPt::UNDEFINED,0,35) == 0," should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.restoreDefsFromCheckPt() == 0,CtsApi::restoreDefsFromCheckPt() << " should return 0\n" << theClient.errorMsg());
+
+ std::vector<std::string> event_paths; event_paths.push_back("/s1:e"); event_paths.push_back("/s2/f1/t1:e");
+ BOOST_REQUIRE_MESSAGE( theClient.force(event_paths[0],"set") == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.force(event_paths[1],"clear") == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.force(event_paths,"set") == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.force(event_paths,"clear") == 0," should return 0\n" << theClient.errorMsg());
+ std::vector<std::string> validStates = NState::allStates(); // HPUX barfs if use NState::allStates() directly
+ BOOST_FOREACH(const string& state, validStates) {
+ BOOST_REQUIRE_MESSAGE( theClient.force("/s",state,true,true) == 0, "force " << state << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.force(paths,state,true,true) == 0, "force " << state << " should return 0\n" << theClient.errorMsg());
+ }
+
+ BOOST_REQUIRE_MESSAGE( theClient.freeDep("/s") == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.freeDep("/s",true,true,true,true) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.freeDep("/s",true) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.freeDep("/s",false,true) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.freeDep("/s",false,false,true) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.freeDep("/s",false,false,false,true) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.freeDep(paths) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.freeDep(paths,true,true,true,true) == 0, " should return 0\n" << theClient.errorMsg());
+
+ std::vector<CFileCmd::File_t> fileTypesVec = CFileCmd::fileTypesVec();
+ for(size_t i = 0; i < fileTypesVec.size(); i++) {
+ BOOST_REQUIRE_MESSAGE( theClient.file("/s",CFileCmd::toString(fileTypesVec[i]),string("100")) == 0, " should return 0\n" << theClient.errorMsg());
+ }
+
+ BOOST_REQUIRE_MESSAGE( theClient.plug("/source","/dest") == 0, " should return 0\n" << theClient.errorMsg());
+
+ {
+ BOOST_REQUIRE_MESSAGE( theClient.getLog(10) == 0," should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.clearLog() == 0, CtsApi::clearLog() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.flushLog() == 0, CtsApi::flushLog() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.get_log_path() == 0, CtsApi::get_log_path() << " should return 0\n" << theClient.errorMsg());
+
+ std::string new_log_path = File::test_data("Client/test/data/new_log.log","Client");
+ BOOST_REQUIRE_MESSAGE( theClient.new_log(new_log_path) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.new_log("") == 0, " should return 0\n" << theClient.errorMsg());
+ }
+
+ BOOST_REQUIRE_MESSAGE( theClient.reloadwsfile() == 0,CtsApi::reloadwsfile() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.forceDependencyEval() == 0, CtsApi::forceDependencyEval() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.group("shutdown yes;halt yes;restart") == 0,"--group should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.group("shutdown=yes;halt=yes;restart") == 0,"--group should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.group("get ; show") == 0,"--group should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.group("get ; show state") == 0,"--group should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.group("get ; show defs") == 0,"--group should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.group("get ; show migrate") == 0,"--group should return 0\n" << theClient.errorMsg());
+
+
+ {
+ std::string path_to_script = "dummy_ecf_file" + File::ECF_EXTN();
+ std::string contents = "%comment\n"
+ "VAR = fred\n"
+ "%end\n"
+ "# rest of the ecf file\n";
+ std::string error_msg;
+ BOOST_CHECK_MESSAGE(File::create(path_to_script,contents,error_msg),error_msg);
+
+ std::vector<std::string> file_contents;
+ NameValueVec used_variables;
+ BOOST_REQUIRE_MESSAGE( theClient.edit_script_edit("/s") == 0,"--edit_script_edit should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.edit_script_preprocess("/s") == 0,"--edit_script_preprocess should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.edit_script_preprocess("/s",file_contents) == 0,"--edit_script_preprocess should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.edit_script_submit("/s",used_variables) == 0,"--edit_script_submit should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.edit_script_submit("/s",used_variables,file_contents) == 0,"--edit_script_submit should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.edit_script_submit("/s",used_variables,file_contents,true/*alias*/) == 0,"--edit_script_submit should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.edit_script_submit("/s",used_variables,file_contents,true/*alias*/,true/*run*/) == 0,"--edit_script_submit should return 0\n" << theClient.errorMsg());
+
+ BOOST_REQUIRE_MESSAGE( theClient.edit_script("/s","edit") == 0,"--edit_script should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.edit_script("/s","pre_process") == 0,"--edit_script should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.edit_script("/s","submit",path_to_script) == 0,"--edit_script should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.edit_script("/s","submit_file",path_to_script) == 0,"--edit_script should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.edit_script("/s","submit_file",path_to_script,true) == 0,"--edit_script should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.edit_script("/s","submit_file",path_to_script,false) == 0,"--edit_script should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.edit_script("/s","submit_file",path_to_script,false,true) == 0,"--edit_script should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.edit_script("/s","submit_file",path_to_script,false,false) == 0,"--edit_script should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.edit_script("/s","pre_process_file",path_to_script) == 0,"--edit_script should return 0\n" << theClient.errorMsg());
+ fs::remove(path_to_script);
+ }
+
+ {
+ std::vector<std::string> suites; suites.push_back("a"); suites.push_back("b");
+ BOOST_REQUIRE_MESSAGE( theClient.ch_register(true,suites) == 0,"--ch_register \n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.ch_register(false,suites) == 0,"--ch_register \n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.ch_suites() == 0,"--ch_suites should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.ch_drop(1) == 0,"--ch_drop should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.ch_drop_user("user") == 0,"--ch_drop_user should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.ch_add(1,suites) == 0,"--ch_add \n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.ch_remove(1,suites) == 0,"--ch_remove \n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.ch_auto_add(1,true) == 0,"--ch_auto_add \n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.ch_auto_add(1,false) == 0,"--ch_auto_add \n" << theClient.errorMsg());
+ // need test interface that allows client handle to set on ClinetInvoker
+// BOOST_REQUIRE_MESSAGE( theClient.ch1_drop() == 0,"--ch1_drop \n" << theClient.errorMsg());
+// BOOST_REQUIRE_MESSAGE( theClient.ch1_add(suites) == 0,"--ch1_add \n" << theClient.errorMsg());
+// BOOST_REQUIRE_MESSAGE( theClient.ch1_remove(suites) == 0,"--ch1_remove \n" << theClient.errorMsg());
+// BOOST_REQUIRE_MESSAGE( theClient.ch1_auto_add(true) == 0,"--ch1_auto_add \n" << theClient.errorMsg());
+// BOOST_REQUIRE_MESSAGE( theClient.ch1_auto_add(false) == 0,"--ch1_auto_add \n" << theClient.errorMsg());
+ }
+
+ {
+ defs_ptr theDefs = Defs::create();
+ theDefs->addSuite( Suite::create("s1") );
+ BOOST_REQUIRE_MESSAGE( theClient.load( theDefs ) == 0,"-- load should return 0\n" << theClient.errorMsg());
+ }
+
+ /// test alter
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","zombie","ecf:fob::10") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","zombie","ecf:fob::") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","zombie","user:fob::10") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","zombie","path:fob::10") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","zombie","path:fob::") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","zombie","ecf:fob:init,event,meter,label,wait,complete,abort:10") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","zombie","ecf:fob:init,event,meter,label,wait,complete:10") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","zombie","ecf:fail:init,event,meter,label,wait,complete:10000") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","zombie","ecf:adopt:init,event,meter,label,wait,complete:23") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","zombie","ecf:remove:init,event,meter,label,wait,complete:0") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","zombie","ecf:block:init,event,meter,label,wait,complete:") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","zombie","ecf:kill:init,event,meter,label,wait,complete:103333333") == 0,"--alter should return 0\n" << theClient.errorMsg());
+
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","time","+12:00") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","time","+10:00 20:00 00:30") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","today","12:00") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","today","10:00 20:00 00:30") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","date","12.12.2009") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","date","*.12.2009") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","date","*.*.2009") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","date","*.*.*") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","variable","name","value") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","variable","name","/value/with/path") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/", "add","variable","name","value") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/", "add","variable","name","/value/with/path") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","late","late -s +00:15 -a 20:00 -c +02:00") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","late","late -a 20:00 -c +02:00 -s +00:15") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","late","late -c +02:00 -a 20:00 -s +00:15") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","late","late -s 00:02 -c +00:05") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","late","late -s 00:01 -a 14:30 -c +00:01") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","late","-s +00:15 -a 20:00 -c +02:00") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","late","-a 20:00 -c +02:00 -s +00:15") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","late","-c +02:00 -a 20:00 -s +00:15") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","late","-s 00:02 -c +00:05") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","late","-s 00:01 -a 14:30 -c +00:01") == 0,"--alter should return 0\n" << theClient.errorMsg());
+
+ std::vector<std::string> validDays = DayAttr::allDays(); // HPUX barfs if use DayAttr::allDays() directly in BOOST_FOREACH
+ BOOST_FOREACH(const string& day, validDays) {
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","day",day) == 0,"--alter should return 0\n" << theClient.errorMsg());
+ }
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/", "delete","variable","varName") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","variable","varName") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","variable","/var/with/path") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","variable") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","time") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","time","+12:00") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","time","+10:00 20:00 00:30") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","today") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","today","12:00") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","today","10:00 20:00 00:30") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","date") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","date","12.12.2009") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","date","*.12.2009") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","date","*.*.2009") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","date","*.*.*") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","day","sunday") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","day") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","23:00") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","10:00 20:00 01:00") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","-w 0,1 10:00") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","-d 10,11,12 12:00") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","-w 0 -m 5,6,7,8 10:00 20:00 01:00") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","event","name") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","event","1") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","event") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","meter","name") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","meter") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","trigger") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","complete") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","repeat") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","limit","name") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","limit_path","limit_name","path") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","limit_path","limit_name","/path/with/slash") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","inlimit","name") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","zombie","user") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","zombie","ecf") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","zombie","path") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","late") == 0,"--alter should return 0\n" << theClient.errorMsg());
+
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","variable","name","newValue") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","variable","name","/new/value/with/path") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_type","hybrid") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_type","real") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_date","12.6.2013") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_gain","20") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_sync") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","event","22","set") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","event","33","clear") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","event","4") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","event","name","set") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","event","name","clear") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","event","name") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","meter","name","20") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","meter","name","-1") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","label","name","newValue") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","label","name","/value/with/path/ECFLOW-480") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","label","name","") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","trigger","(t:step + 20) ge (t:step1 - 20)") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","trigger","/suite/fred == complete") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","trigger","/suite/fred:event") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","complete","not ( a == complete )") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","complete","/trigger/with/leading/slash == aborted") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","complete","/trigger/with/leading/slash:event") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","repeat","1") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","repeat","blue") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","limit_max","limit_name","12") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","limit_value","limit_name","12") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","late","late -s +00:15 -a 20:00 -c +02:00") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","late","late -s 00:02 -c +00:05") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","late","late -s 00:01 -a 14:30 -c +00:01") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","late","-s +00:15 -a 20:00 -c +02:00") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","late","-a 20:00 -c +02:00 -s +00:15") == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","late","-c +02:00 -a 20:00 -s +00:15") == 0,"--alter should return 0\n" << theClient.errorMsg());
+
+
+ std::vector<std::string> dstates = DState::allStates();
+ for(size_t i = 0; i < dstates.size(); i++) {
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","defstatus",dstates[i]) == 0,"--alter should return 0\n" << theClient.errorMsg());
+ }
+
+ std::vector<std::string> flag_types;
+ Flag::valid_flag_type(flag_types);
+ for(size_t i = 0; i < flag_types.size(); i++) {
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","set_flag",flag_types[i]) == 0,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","clear_flag",flag_types[i]) == 0,"--alter should return 0\n" << theClient.errorMsg());
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_client_interface_for_fail )
+{
+ std::cout << "Client:: ...test_client_interface_for_fail" << endl;
+
+ ClientInvoker theClient ;
+ theClient.testInterface(); // stops submission to server
+ theClient.set_throw_on_error(false);
+
+ std::vector<std::string> paths; paths.push_back("/s1"); paths.push_back("/s2");
+
+ /// test alter
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","time","") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","time","012:00") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","time","1200") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","time","fred") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","time","+10:0020:00 00:30") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","time","+10:00 2000 00:30") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","time","+1000 20:00 00:30") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","time","+10:00 20:00 0030") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","time","any old rubbish") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","today","+10:0020:00 00:30") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","today","+10:00 2000 00:30") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","today","+1000 20:00 00:30") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","today","+10:00 20:00 0030") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","today","any old rubbish") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","today","") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","date","") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","date","0.12.2009") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","date","12.0.2009") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","date","12.12.g") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","date","*..2009") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","date","12..2009") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","date","12.12.") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","date","fred") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","date","any old rubbish") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","day","frenday") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","day","") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","day","opps ") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","variable","na me","value") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/", "add","variable","na me","value") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/", "add","variable","","value") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","late","") == 1,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","late","late") == 1,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","late","late -s") == 1,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","late","late -a") == 1,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","late","late -c") == 1,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","late","late -s +00:15 -a") == 1,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","late","late -s +00:15 -a 20:00 -c") == 1,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","late","-s") == 1,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","late","-a") == 1,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","late","-c") == 1,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","late","-s +00:15 -a") == 1,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","late","-s +00:15 -a 20:00 -c") == 1,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","late","-c +02:000 -a 20:00 -s +00:15") == 1,"--alter should return 0\n" << theClient.errorMsg());
+
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/", "delete","vari able","varName") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","v ariable","varName") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","time","012:00") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","time","1200") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","time","fred") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","time","+10:0020:00 00:30") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","time","+10:00 2000 00:30") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","time","+1000 20:00 00:30") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","time","+10:00 20:00 0030") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","time","any old rubbish") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","today","+10:0020:00 00:30") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","today","+10:00 2000 00:30") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","today","+1000 20:00 00:30") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","today","+10:00 20:00 0030") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","today","any old rubbish") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","date","0.12.2009") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","date","12.0.2009") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","date","12.12.g") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","date","*..2009") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","date","12..2009") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","date","12.12.") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","date","fred") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","date","any old rubbish") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","day","su nday") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","day","fryday") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","any old rubbish") == 1,"Expected fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","2300") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","1000 20:00 01:00") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","-w 0,1 1000'") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","-w 1000") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","-d 10,11,12 1200") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","-d 10,11,12") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","-d 1200") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","-w 0 -m 5,6,7,8 10:00 20:00 01:000") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","-w 0 -m 5,6,7,8 10:00 20:00 0100") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","-w -m 20:00 01:00") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","-w 0 -m 5,6,7,8 1000 20:00 01:00") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","-w 20 -m 5,6,7,8 10:00 20:00 01:00") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","-w 0 -m 5,6,7,8,24 10:00 20:00 01:00") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","event","name df") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","event","22 56 ") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","meter","na me") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","limit"," name") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","inlimit","na me") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","vari able","name","newValue") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","","name","/new/value/with/path") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_type","") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_type","hyb rid") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_type","hybrid ") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_type","ybrid") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_type","re al") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_type","rreal") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_date","*.6.2013") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_date","12.0.2013") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_date","any old rubbish") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_date","") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_gain","string") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_gain","") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_gain","fred") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","event","name","fr ed") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","event","na me") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","meter","name","") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","meter","na me","20") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","meter","name","-") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","label","na me","newValue") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","trigger","t:step + 20) ge (t:step1 - 20)") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","complete","not a == complete )") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","limit_max","limit_ name","12") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","limit_value","limit_ name","12") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","defstatus","complete-34") == 1,"--alter expected to fail\n" << theClient.errorMsg());
+
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","late","") == 1,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","late","late") == 1,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","late","late -s") == 1,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","late","late -a") == 1,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","late","late -c") == 1,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","late","-s +00:15 -a") == 1,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","late","-s +00:15 -a 20:00 -c") == 1,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","late","-s +00:15 -a") == 1,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","late","-s +00:15 -a 20:00 -c") == 1,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","late","-s +00:152") == 1,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","late","-c +00:152") == 1,"--alter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","late","-a +00:152") == 1,"--alter should return 0\n" << theClient.errorMsg());
+}
+
+
+BOOST_AUTO_TEST_CASE( test_client_task_interface )
+{
+ std::cout << "Client:: ...test_client_task_interface" << endl;
+
+ ClientInvoker theClient ;
+ theClient.testInterface(); // stops submission to server
+ theClient.taskPath("/a/made/up/path");
+ theClient.set_jobs_password( Submittable::DUMMY_JOBS_PASSWORD() );
+
+ BOOST_REQUIRE_MESSAGE( theClient.initTask(Submittable::DUMMY_PROCESS_OR_REMOTE_ID()) == 0,"--init should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.abortTask("reason for abort") == 0,"--abort should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.eventTask("event_name") == 0,"--event should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.meterTask("meter_name","20") == 0,"--meter should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.waitTask("a == complete") == 0,"--wait should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.completeTask() == 0,"--complete should return 0\n" << theClient.errorMsg());
+ std::vector<std::string> labels; labels.push_back("test_client_task_interface");
+ BOOST_REQUIRE_MESSAGE( theClient.labelTask("label_name",labels) == 0,"--label should return 0\n" << theClient.errorMsg());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/Client/test/TestClientInvoker.cpp b/Client/test/TestClientInvoker.cpp
new file mode 100644
index 0000000..feb9e8f
--- /dev/null
+++ b/Client/test/TestClientInvoker.cpp
@@ -0,0 +1,63 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #9 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <iostream>
+#include <vector>
+#include <string>
+
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+
+#include "ClientInvoker.hpp"
+#include "Str.hpp"
+#include "File.hpp"
+
+namespace fs = boost::filesystem;
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( ClientTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_client_invoker )
+{
+ if (getenv("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")) {
+ cout << "Client:: ...test_client_invoker: ignoring test when ECF_ALLOW_NEW_CLIENT_OLD_SERVER specified\n";
+ return;
+ }
+
+ std::cout << "Client:: ...test_client_invoker" << endl;
+ {
+ char* put = const_cast<char*>("ECF_ALLOW_NEW_CLIENT_OLD_SERVER=10");
+ BOOST_CHECK_MESSAGE(putenv(put) == 0,"putenv failed for " << put);
+ ClientInvoker invoker;
+ BOOST_CHECK_MESSAGE(invoker.allow_new_client_old_server()==10,"Expected 10 but found " << invoker.allow_new_client_old_server() << " for env " << put);
+ putenv(const_cast<char*>("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")); // remove from env, otherwise valgrind complains
+ }
+ {
+ std::stringstream ss;
+ ss << "ECF_ALLOW_NEW_CLIENT_OLD_SERVER=fred:2222:12,bill:3333:2222,bill4:6666:1313";
+ std::string env = ss.str();
+ BOOST_CHECK_MESSAGE(putenv(const_cast<char*>(env.c_str())) == 0,"putenv failed for " << env);
+ ClientInvoker invoker("bill","3333");
+ BOOST_CHECK_MESSAGE(invoker.allow_new_client_old_server()==2222,"Expected 2222 but found " << invoker.allow_new_client_old_server() << " for env " << env);
+
+ invoker.set_host_port("bill4","6666");
+ BOOST_CHECK_MESSAGE(invoker.allow_new_client_old_server()==1313,"Expected 1313 but found " << invoker.allow_new_client_old_server() << " for env " << env);
+ putenv(const_cast<char*>("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")); // remove from env, otherwise valgrind complains, + *COULD* affect other tests
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/Client/test/TestClientTimeout.cpp b/Client/test/TestClientTimeout.cpp
new file mode 100644
index 0000000..e9838de
--- /dev/null
+++ b/Client/test/TestClientTimeout.cpp
@@ -0,0 +1,77 @@
+////============================================================================
+//// Name :
+//// Author : Avi
+//// Revision : $Revision: #5 $
+////
+//// Copyright 2009-2016 ECMWF.
+//// This software is licensed under the terms of the Apache Licence version 2.0
+//// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+//// In applying this licence, ECMWF does not waive the privileges and immunities
+//// granted to it by virtue of its status as an intergovernmental organisation
+//// nor does it submit to any jurisdiction.
+////
+//// Description :
+////============================================================================
+//#include <string>
+//#include <fstream>
+//
+//#include "boost/filesystem/operations.hpp"
+//#include "boost/filesystem/path.hpp"
+//#include <boost/test/unit_test.hpp>
+//
+//#include "ClientInvoker.hpp"
+//#include "ClientEnvironment.hpp"
+//#include "InvokeServer.hpp"
+//#include "SCPort.hpp"
+//#include "Str.hpp"
+//
+//namespace fs = boost::filesystem;
+//using namespace std;
+//using namespace ecf;
+//
+//BOOST_AUTO_TEST_SUITE( ClientTestSuite )
+//
+//// ************************************************************************************
+//// Note: If you make edits to node tree, they will have no effect until the server is rebuilt
+//// ************************************************************************************
+//
+///// This test will check the timeoout feature of the Client
+///// The timeout feature allow the client to fail gracefully in the case
+///// where the server has died/crashed. The timeout will ensure the scoket is closed.
+///// allowing the server to be restarted withou getting the address is use error.
+//BOOST_AUTO_TEST_CASE( test_client_timeout )
+//{
+// // This will remove check pt and backup file before server start, to avoid the server from loading previous test data
+// InvokeServer invokeServer("Client:: ...test_client_timeout",SCPort::next());
+//
+// // The timeout is configured to vary according the the client request
+// // however we can override for testing.
+// // Here we set a timeout for 1 second, then attempt to load a very large definition into the server.
+// // Note: the timeout of 1 second means we have 1 second for each communication, hence:
+// // connect : 1 second
+// // send request : 1 second
+// // receive reply : 1 second
+// ClientInvoker theClient(invokeServer.host(),invokeServer.port());
+// theClient.set_timeout(1);
+//
+// std::string path = File::test_data("AParser/test/data/single_defs/mega.def","AParser");
+// BOOST_REQUIRE_THROW(theClient.loadDefs(path),std::runtime_error); // Expected load defs to fail with a timeout of 1 second\n
+//
+// /// Now see what timeout value we succeed with
+// bool loaded_defs = false;
+// for(int i = 2; i < 10; ++i) {
+// theClient.set_timeout(i);
+// try {
+// cout << "Trying with timeout of " << i << " seconds\n";
+// theClient.loadDefs(path);
+// cout << " loaded mega defs with a timeout of " << i << " seconds\n";
+// loaded_defs = true;
+// break;
+// }
+// catch (...) {}
+// }
+// BOOST_REQUIRE_MESSAGE(loaded_defs,"Expected load of defs to succeed\n");
+//}
+//
+//BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/Client/test/TestGroupCmd.cpp b/Client/test/TestGroupCmd.cpp
new file mode 100644
index 0000000..6e47e31
--- /dev/null
+++ b/Client/test/TestGroupCmd.cpp
@@ -0,0 +1,219 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #37 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <fstream>
+
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+
+#include "ClientInvoker.hpp"
+#include "ClientEnvironment.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "File.hpp"
+#include "PrintStyle.hpp"
+#include "InvokeServer.hpp"
+#include "SCPort.hpp"
+
+namespace fs = boost::filesystem;
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( ClientTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_group_cmd )
+{
+ // The previous test's has created/destroyed a server process
+ // If two different process both try to use the same port number, you
+ // get an "Address in use" error, even if one the process is dead. This is
+ // because the kernel does not immediately release the resource and there is
+ // time out period. To get round this we will start the new server/client
+ // and use a different port number. the default is 3141
+
+ // This will remove check pt and backup file before server start, to avoid the server from loading previous test data
+ InvokeServer invokeServer("Client:: ...test_group_cmd",SCPort::next());
+
+ ClientInvoker theClient(invokeServer.host(),invokeServer.port());
+ BOOST_REQUIRE_MESSAGE( theClient.group("shutdown yes;halt yes;restart") == 0,"--group should return 0\n" << theClient.errorMsg());
+}
+
+BOOST_AUTO_TEST_CASE( test_client_group_lifecyle )
+{
+ /// *** This test is the same as in file TestServerAndLifeCyle.cpp only this time
+ /// *** we use the group command where ever possible
+ // This will remove check pt and backup file before server start, to avoid the server from loading previous test data
+
+ // ** NOTE: We disable job generation in the server **/
+ InvokeServer invokeServer("Client:: ...test_client_group_lifecyle",SCPort::next(),true /*disable job generation in server*/);
+
+ ClientInvoker theClient(invokeServer.host(),invokeServer.port());
+
+ {
+ // restart server, load lifecycle, and get the defs tree from the server
+ std::string groupRequest ="--restart; load=";
+ groupRequest += File::test_data("Client/test/data/lifecycle.txt","Client");
+ groupRequest += "; get";
+
+ BOOST_REQUIRE_MESSAGE( theClient.group(groupRequest) == 0,"Group request " << CtsApi::group(groupRequest) << " failed should return 0\n" << theClient.errorMsg());
+ defs_ptr serverDefs = theClient.defs();
+ BOOST_REQUIRE_MESSAGE( serverDefs.get(),"Server returned a NULL defs");
+ BOOST_REQUIRE_MESSAGE( serverDefs->suiteVec().size() >= 1," no suite ?");
+ }
+
+ // Now go through and simulate client request to change Node tree state.
+ // This is **highly** dependent on lifecycle.txt
+ // suite suite1
+ // family family1
+ // task a
+ // event 1 myEvent
+ // meter myMeter 0 100
+ // task b
+ // trigger a == complete
+ // endfamily
+ // family family2
+ // task aa
+ // trigger ../family1/a:myMeter >= 20 and ../family1/a:myEvent
+ // task bb
+ // trigger ../family1/a:myMeter >= 50 || ../family1/a:myEvent
+ // endfamily
+ // endsuite
+ string suite1_family1_a = "suite1/family1/a";
+ string suite1_family1_b = "suite1/family1/b";
+ string suite1_family2_aa = "suite1/family2/aa";
+ string suite1_family2_bb = "suite1/family2/bb";
+
+
+ // ***********************************************************************
+ // Create a request to initialise Node: suite1/family1/a
+ // Create a request to set the event on Node suite1/family1/a
+ // This should place suite1_family2_bb immediately into submitted state
+ // Since we at least one node in ACTIVE, suite should be in ACTIVE state
+ {
+ theClient.taskPath(suite1_family1_a);
+ theClient.set_jobs_password(Submittable::DUMMY_JOBS_PASSWORD());
+
+ // make sure to use same ECF_RID if its specified
+ std::string remote_id= "process_or_remote_id";
+ if (!theClient.process_or_remote_id().empty()) remote_id = theClient.process_or_remote_id();
+ std::string groupRequest ="begin=suite1; init=";
+ groupRequest += remote_id;
+ groupRequest += "; event=myEvent; force-dep-eval; get";
+
+ BOOST_REQUIRE_MESSAGE(theClient.group(groupRequest) == 0,"Group request " << groupRequest << " failed should return 0\n" << theClient.errorMsg());
+
+ defs_ptr serverDefs = theClient.defs();
+ // PrintStyle style(PrintStyle::STATE);
+ // cerr << *serverDefs.get() << "\n";
+ BOOST_REQUIRE_MESSAGE( serverDefs.get(),"get command failed to get node tree from server");
+
+ node_ptr node = serverDefs->findAbsNode(suite1_family1_a);
+ BOOST_REQUIRE_MESSAGE( node->state() == NState::ACTIVE, "Node expected NState::ACTIVE, but found to be " << NState::toString(node->state()));
+ node_ptr nodeb = serverDefs->findAbsNode(suite1_family2_bb);
+ BOOST_REQUIRE_MESSAGE( nodeb->state() == NState::ACTIVE, "Node expected NState::ACTIVE, but found to be " << NState::toString(nodeb->state()));
+ }
+
+
+ //**********************************************************************
+ // Create a request to set the Meter on Node suite1/family1/a
+ // This should force suite1_family2_aa immediately into submitted state
+ // This should force suite1_family2_bb immediately into submitted state
+ {
+ theClient.taskPath(suite1_family1_a);
+ std::string groupRequest ="meter=myMeter 100; force-dep-eval; get";
+ BOOST_REQUIRE_MESSAGE( theClient.group(groupRequest) == 0,"Group request " << CtsApi::group(groupRequest) << " failed should return 0\n" << theClient.errorMsg());
+
+ defs_ptr serverDefs = theClient.defs();
+ BOOST_REQUIRE_MESSAGE( serverDefs.get(),"get command failed to get node tree from server");
+
+ node_ptr nodeaa = serverDefs->findAbsNode(suite1_family2_aa);
+ BOOST_REQUIRE_MESSAGE( nodeaa->state() == NState::ACTIVE, "Node expected NState::ACTIVE, but found to be " << NState::toString(nodeaa->state()));
+
+ node_ptr nodebb = serverDefs->findAbsNode(suite1_family2_bb);
+ BOOST_REQUIRE_MESSAGE( nodebb->state() == NState::ACTIVE, "Node expected NState::ACTIVE, but found to be " << NState::toString(nodebb->state()));
+ }
+
+ //**********************************************************************
+ // Create a request to complete task suite1/family1/a
+ // This should force suite1_family1_b to complete
+ // Resolve dependencies
+ // We could either wait 60 second or
+ // added a custom command that will force dependency evaluation
+ {
+ theClient.taskPath(suite1_family1_a);
+ std::string groupRequest ="complete;force-dep-eval;get";
+ BOOST_REQUIRE_MESSAGE( theClient.group(groupRequest) == 0,"Group request " << CtsApi::group(groupRequest) << " failed should return 0\n" << theClient.errorMsg());
+
+ defs_ptr serverDefs = theClient.defs();
+ BOOST_REQUIRE_MESSAGE( serverDefs.get(),"get command failed to get node tree from server");
+
+ node_ptr node = serverDefs->findAbsNode(suite1_family1_b);
+ BOOST_REQUIRE_MESSAGE( node->state() == NState::ACTIVE, "Expected NState::ACTIVE, but found " << NState::toString(node->state()));
+ }
+
+ //********************************************************************************
+ // Complete the remaining tasks. Should really call init first, but what the eck.
+ //
+ // Get the node tree back from the server, and check its node state
+ // All node state should be complete. + check meter/event value was set properly
+
+ {
+ theClient.taskPath(suite1_family1_b);
+ BOOST_REQUIRE_MESSAGE(theClient.completeTask() == 0,TaskApi::complete() << " failed should return 0\n" << theClient.errorMsg());
+
+ theClient.taskPath(suite1_family2_aa);
+ BOOST_REQUIRE_MESSAGE(theClient.completeTask() == 0,TaskApi::complete() << " failed should return 0\n" << theClient.errorMsg());
+
+ theClient.taskPath(suite1_family2_bb);
+ std::string groupRequest ="complete;force-dep-eval;get";
+ BOOST_REQUIRE_MESSAGE( theClient.group(groupRequest) == 0,"Group request " << CtsApi::group(groupRequest) << " failed should return 0\n" << theClient.errorMsg());
+
+
+ defs_ptr serverDefs = theClient.defs();
+ BOOST_REQUIRE_MESSAGE( serverDefs.get(),"get command failed to get node tree from server");
+
+ std::string metername = "myMeter";
+ int meterValue = 100;
+ node_ptr node = serverDefs->findAbsNode(suite1_family1_a);
+ const Meter& theMeter = node->findMeter(metername);
+ BOOST_REQUIRE_MESSAGE( !theMeter.empty(), "Could not find the meter");
+ BOOST_REQUIRE_MESSAGE( theMeter.value() == meterValue , "Expected meter value " << meterValue << " but found " << theMeter.value());
+ {
+ std::string errorMsg; BOOST_REQUIRE_MESSAGE( serverDefs->checkInvariants(errorMsg), errorMsg);
+ }
+
+ std::string eventname = "myEvent";
+ const Event& theEvent = node->findEventByNameOrNumber(eventname);
+ BOOST_REQUIRE_MESSAGE( !theEvent.empty(), "Could not find the event myEvent");
+ BOOST_REQUIRE_MESSAGE( theEvent.value(), "The event was not set");
+
+ const std::vector<suite_ptr>& suiteVec = serverDefs->suiteVec();
+ suite_ptr suite = suiteVec.back();
+ BOOST_REQUIRE_MESSAGE( suite->state() == NState::COMPLETE,
+ "Suite expected NState::COMPLETE, but found to be " << NState::toString(suite->state()));
+ }
+
+ {
+ // Check that a log file was created, by asking the server for it.
+ BOOST_REQUIRE_MESSAGE( theClient.getLog() == 0, "get log failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(!theClient.get_string().empty(),"The log file returned from the server is empty!!");
+
+ // Clear the log
+ BOOST_REQUIRE_MESSAGE( theClient.clearLog() == 0,CtsApi::clearLog() << " failed should return 0\n" << theClient.errorMsg());
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/Client/test/TestJobGenOnly.cpp b/Client/test/TestJobGenOnly.cpp
new file mode 100644
index 0000000..0db9827
--- /dev/null
+++ b/Client/test/TestJobGenOnly.cpp
@@ -0,0 +1,96 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #40 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <iostream>
+#include <fstream>
+
+#include "boost/make_shared.hpp"
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/test/unit_test.hpp>
+#include <boost/foreach.hpp>
+#include <boost/timer.hpp>
+
+#include "Defs.hpp"
+#include "DefsStructureParser.hpp"
+#include "NodeAttr.hpp"
+#include "Suite.hpp"
+#include "Task.hpp"
+#include "Str.hpp"
+#include "File.hpp"
+#include "ExprAst.hpp"
+#include "TestHelper.hpp"
+#include "JobCreationCtrl.hpp"
+
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( ClientTestSuite )
+
+// Tests the Job generation against the OLD sms
+BOOST_AUTO_TEST_CASE( test_jobgenonly )
+{
+ cout << "Client:: ...test_jobgenonly" << endl;
+
+ // Define paths to ECF_HOME and location of the defs file
+
+ std::string defsFile = File::test_data("Client/test/data/jobgenonly.def","Client");
+ std::string ecf_home = File::test_data("Client/test/data/ECF_HOME","Client");
+
+ /// Remove existing job file if any.
+ /// Job file location may NOT be same as ecf file.
+ /// The default Job location is defined by generated variable ECF_JOB
+ /// ECF_JOB = ECF_HOME/<abs node path>.job<try_no>.
+ std::vector<std::string> generatedFiles; generatedFiles.reserve(5);
+ std::string t1_job = ecf_home + "/suite/family/t1.job0"; generatedFiles.push_back(t1_job);
+ std::string t2_job = ecf_home + "/suite/family/t2.job0"; generatedFiles.push_back(t2_job);
+ std::string t3_job = ecf_home + "/suite/family/t3.job0"; generatedFiles.push_back(t3_job);
+
+ // See EcfFile.cpp: To enable generation of man files, for test. i.e DEBUG_MAN_FILE
+#ifdef DEBUG_MAN_FILE
+ std::string t1_man = ecf_home + "/suite/family/t1.man"; generatedFiles.push_back(t1_man);
+ std::string t3_man = ecf_home + "/suite/family/t3.man"; generatedFiles.push_back(t3_man);
+#endif
+ BOOST_FOREACH(const std::string& s, generatedFiles ) { fs::remove(s); }
+ BOOST_FOREACH(const std::string& s, generatedFiles ) { BOOST_REQUIRE_MESSAGE(!fs::exists(s),"Could not delete file " << s); }
+
+
+ // Load the defs file 'jobgenonly.def'
+ Defs theDefs;
+ DefsStructureParser checkPtParser( &theDefs, defsFile );
+ std::string errorMsg,warningMsg;
+ BOOST_REQUIRE_MESSAGE(checkPtParser.doParse(errorMsg,warningMsg),errorMsg);
+
+ // Override ECF_HOME. ECF_HOME is needed to locate to the .ecf files
+ theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(),ecf_home);
+
+ // provide definition of ECF_CLIENT. This should replace smsinit, smscomplete, smsevent,etc
+ // with path to the ecf client
+ std::string clientPath = File::find_ecf_client_path();
+ BOOST_REQUIRE_MESSAGE( !clientPath.empty(), "Could not find path to client executable");
+ theDefs.set_server().add_or_update_user_variables("ECF_CLIENT",clientPath);
+
+ // JobCreationCtrl is used control what node we generate the jobs for:
+ // Since we have not set the node on it, we force job generation for all tasks
+ job_creation_ctrl_ptr jobCtrl = boost::make_shared<JobCreationCtrl>();
+ theDefs.check_job_creation(jobCtrl);
+ BOOST_REQUIRE_MESSAGE(jobCtrl->get_error_msg().empty(), jobCtrl->get_error_msg());
+ BOOST_REQUIRE_MESSAGE(jobCtrl->fail_submittables().empty(),"Expected no failing tasks");
+
+ // Check if jobs file were generated.
+ BOOST_FOREACH(const std::string& s, generatedFiles ) { BOOST_REQUIRE_MESSAGE(fs::exists(s),"File " << s << " should have been created"); }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Client/test/TestLifeCycle.cpp b/Client/test/TestLifeCycle.cpp
new file mode 100644
index 0000000..817f1fc
--- /dev/null
+++ b/Client/test/TestLifeCycle.cpp
@@ -0,0 +1,216 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #50 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <iostream>
+#include <fstream>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include "boost/progress.hpp"
+#include <boost/test/unit_test.hpp>
+
+#include "DefsStructureParser.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "TestHelper.hpp"
+#include "JobsParam.hpp"
+#include "Jobs.hpp"
+#include "File.hpp"
+
+namespace fs = boost::filesystem;
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( ClientTestSuite)
+
+BOOST_AUTO_TEST_CASE( test_node_tree_lifecycle )
+{
+ cout << "Client:: ...test_node_tree_lifecycle" << endl;
+
+ std::string path = File::test_data("Client/test/data/lifecycle.txt","Client");
+
+ Defs defs;
+ DefsStructureParser checkPtParser( &defs, path );
+ std::string errorMsg,warningMsg;
+ bool parse = checkPtParser.doParse(errorMsg,warningMsg);
+ if (!parse) std::cerr << errorMsg;
+ BOOST_CHECK(parse);
+
+ // Now go through and simulate client request to change Node tree state.
+ // This is **highly** dependent on lifecycle.txt
+// suite suite1
+// family family1
+// task a
+// event 1 myEvent
+// meter myMeter 0 100
+// task b
+// trigger a == complete
+// endfamily
+// family family2
+// task aa
+// trigger ../family1/a:myMeter >= 20 and ../family1/a:myEvent
+// task bb
+// trigger ../family1/a:myMeter >= 50 || ../family1/a:myEvent
+// endfamily
+// endsuite
+
+ // get the suite, before we do anything initial state should be UNKNOWN
+ const std::vector<suite_ptr>& suiteVec = defs.suiteVec();
+ suite_ptr suite = suiteVec.back();
+ BOOST_CHECK_MESSAGE( suite->state() == NState::UNKNOWN," Initial suite state should be NState::UNKNOWN");
+
+ string suite1_family1_a = "suite1/family1/a";
+ string suite1_family1_b = "suite1/family1/b";
+ string suite1_family2_aa = "suite1/family2/aa";
+ string suite1_family2_bb = "suite1/family2/bb";
+
+
+ // Pick the suite that is allowed to resolve dependencies
+ // The suite must be loaded and be in state UNKNOWN or COMPLETE
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new BeginCmd("suite1")));
+
+
+ // ***********************************************************************
+ // Create a request to initialise Node: suite1/family1/a
+ {
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new InitCmd(suite1_family1_a,Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1)));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new CtsCmd( CtsCmd::FORCE_DEP_EVAL)),false);
+
+ node_ptr node = defs.findAbsNode(suite1_family1_a);
+ BOOST_CHECK_MESSAGE( node, "Could not find node");
+ BOOST_CHECK_MESSAGE( node->state() == NState::ACTIVE, "Init request should place node in NState::ACTIVE");
+ BOOST_CHECK_MESSAGE( suite->state() == NState::ACTIVE, "Suite should be in NState::ACTIVE after init cmd");
+ std::string errorMsg; BOOST_CHECK_MESSAGE( defs.checkInvariants(errorMsg),errorMsg);
+ }
+
+ //**********************************************************************
+ // Create a request to set the event on Node suite1/family1/a
+ // This should force suite1_family2_bb immediately into submitted/active state
+ {
+ std::string eventname = "myEvent";
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new EventCmd(suite1_family1_a,Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1,eventname)));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new CtsCmd( CtsCmd::FORCE_DEP_EVAL)));
+ node_ptr node = defs.findAbsNode(suite1_family1_a);
+
+ const Event& theEvent = node->findEventByNameOrNumber(eventname);
+ BOOST_CHECK_MESSAGE( !theEvent.empty(), "Could not find the event myEvent");
+ BOOST_CHECK_MESSAGE( theEvent.value(), "The event was not set");
+ std::string errorMsg; BOOST_CHECK_MESSAGE( defs.checkInvariants(errorMsg),errorMsg);
+
+ // cerr << "Defs " << defs << "\n";
+ BOOST_CHECK_MESSAGE( node->state() == NState::ACTIVE, "State should be NState::ACTIVE but found to be " << NState::toString(node->state()));
+ BOOST_CHECK_MESSAGE( suite->state() == NState::ACTIVE, "Suite should be in NState::ACTIVE but found to be " << NState::toString(suite->state()));
+
+ node_ptr nodebb = defs.findAbsNode(suite1_family2_bb);
+ BOOST_CHECK_MESSAGE( nodebb->state() == NState::ACTIVE, "State should be NState::ACTIVE but found to be " << NState::toString(nodebb->state()));
+ }
+
+ //*******************************************************************************
+ // Resolve dependencies. After previous event suite1_family2_bb should have
+ // been put into ACTIVE state.
+ // ** Tests trigger/AST OR functionality **
+ // Since we at least one node in active, suite should
+ // be in avtive state
+ {
+ JobsParam jobsParam; // create jobs = false, spawn jobs = false
+ Jobs jobs(&defs);
+ BOOST_CHECK_MESSAGE(jobs.generate(jobsParam),jobsParam.getErrorMsg());
+ BOOST_FOREACH(Submittable* t, jobsParam.submitted() ) {
+ BOOST_CHECK_MESSAGE( t->state() == NState::SUBMITTED, "jobSubmission should change Node state");
+ }
+
+ {
+ node_ptr node = defs.findAbsNode(suite1_family1_a);
+ BOOST_CHECK_MESSAGE( node->state() == NState::ACTIVE, "resolve dependencies should change Node state here");
+ }
+ node_ptr node = defs.findAbsNode(suite1_family2_bb);
+ BOOST_CHECK_MESSAGE( node, "Could Not find Node " << suite1_family2_bb );
+ BOOST_CHECK_MESSAGE( node->state() == NState::ACTIVE, "resolve dependencies should change Node state");
+ BOOST_CHECK_MESSAGE( suite->state() == NState::ACTIVE, "Suite expected NState::ACTIVE, but found to be " << NState::toString(suite->state()));
+ std::string errorMsg; BOOST_CHECK_MESSAGE( defs.checkInvariants(errorMsg),errorMsg);
+ }
+
+ //**********************************************************************
+ // Create a request to set the Meter on Node suite1/family1/a
+ // This should immediately change suite1_family2_aa into submitted state
+ {
+ std::string metername = "myMeter";
+ int meterValue = 100;
+ TestHelper::invokeRequest(&defs, Cmd_ptr( new MeterCmd(suite1_family1_a,Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1,metername,meterValue)));
+ TestHelper::invokeRequest(&defs, Cmd_ptr( new CtsCmd( CtsCmd::FORCE_DEP_EVAL)));
+
+ node_ptr node = defs.findAbsNode(suite1_family1_a);
+ BOOST_CHECK_MESSAGE( node->state() == NState::ACTIVE,
+ "Expected Node '" << node->absNodePath() << "' to be NState::ACTIVE, but found " << NState::toString(node->state()) << "\n");
+ BOOST_CHECK_MESSAGE( suite->state() == NState::ACTIVE,
+ "Suite expected NState::ACTIVE, but found to be " << NState::toString(suite->state()));
+
+ const Meter& theMeter = node->findMeter(metername);
+ BOOST_CHECK_MESSAGE( !theMeter.empty(), "Could not find the meter");
+ BOOST_CHECK_MESSAGE( theMeter.value() == meterValue , "Meter value not set");
+ std::string errorMsg; BOOST_REQUIRE_MESSAGE( defs.checkInvariants(errorMsg), errorMsg);
+
+ node_ptr nodeaa = defs.findAbsNode(suite1_family2_aa);
+ BOOST_CHECK_MESSAGE( nodeaa, "Could Not find Node " << suite1_family2_aa );
+ BOOST_CHECK_MESSAGE( nodeaa->state() == NState::ACTIVE, "resolve dependencies should change Node state");
+ }
+
+ //**********************************************************************
+ // Create a request to complete task suite1/family1/a
+ // A is complete, which means evaluation dependencies should force:
+ // suite1/family1/b :->to be submitted.
+ // since the complete command does an immediate job submission afterwards
+ {
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new CompleteCmd(suite1_family1_a,Submittable::DUMMY_JOBS_PASSWORD())));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new CtsCmd( CtsCmd::FORCE_DEP_EVAL)));
+
+ node_ptr node = defs.findAbsNode(suite1_family1_a);
+ BOOST_CHECK_MESSAGE( node, "Could not find node");
+ BOOST_CHECK_MESSAGE( node->state() == NState::COMPLETE, "Complete request should place node in NState::COMPLETE");
+ BOOST_CHECK_MESSAGE( suite->state() == NState::ACTIVE, "Expected NState::ACTIVE, but found to be " << NState::toString(suite->state()));
+
+
+ node_ptr nodeb = defs.findAbsNode(suite1_family1_b);
+ BOOST_CHECK_MESSAGE( nodeb, "Could not find node");
+ BOOST_CHECK_MESSAGE( nodeb->state() == NState::ACTIVE, "Expected NState::ACTIVE, but found to be " << NState::toString(nodeb->state()));
+
+ std::string errorMsg; BOOST_CHECK_MESSAGE( defs.checkInvariants(errorMsg),errorMsg);
+ }
+
+ //*******************************************************************************
+ // Job submission, should not send any jobs for submission.
+ // This will evaluate dependencies( ie day,date, trigger ast)
+ {
+ JobsParam jobsParam; // create jobs = false, spawn jobs = false
+ Jobs jobs(&defs);
+ BOOST_CHECK_MESSAGE( jobs.generate(jobsParam),jobsParam.getErrorMsg());
+ BOOST_CHECK_MESSAGE( jobsParam.submitted().size() == 0, "Expected 0 task to submit but found " << jobsParam.submitted().size());
+ }
+
+ //********************************************************************************
+ // Complete the remaining tasks
+ {
+ TestHelper::invokeRequest(&defs , Cmd_ptr( new CompleteCmd("suite1/family1/b",Submittable::DUMMY_JOBS_PASSWORD())));
+ TestHelper::invokeRequest(&defs , Cmd_ptr( new CompleteCmd(suite1_family2_aa,Submittable::DUMMY_JOBS_PASSWORD())));
+ TestHelper::invokeRequest(&defs , Cmd_ptr( new CompleteCmd(suite1_family2_bb,Submittable::DUMMY_JOBS_PASSWORD())));
+
+ BOOST_CHECK_MESSAGE( suite->state() == NState::COMPLETE, "Suite should be in NState::COMPLETE state");
+ std::string errorMsg; BOOST_CHECK_MESSAGE( defs.checkInvariants(errorMsg),errorMsg);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/Client/test/TestLoadDefsCmd.cpp b/Client/test/TestLoadDefsCmd.cpp
new file mode 100644
index 0000000..751234a
--- /dev/null
+++ b/Client/test/TestLoadDefsCmd.cpp
@@ -0,0 +1,158 @@
+//============================================================================
+// Name : Request
+// Author : Avi
+// Revision : $Revision: #42 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <string>
+#include <iostream>
+#include <fstream>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/test/unit_test.hpp>
+
+#include "DefsStructureParser.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "ClientToServerCmd.hpp"
+#include "ServerToClientCmd.hpp"
+#include "MockServer.hpp"
+#include "InvokeServer.hpp"
+#include "SCPort.hpp"
+#include "System.hpp"
+
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( ClientTestSuite )
+
+//=============================================================================
+// This test the LoadDefsCmd. This command will merge/absorb a defs file
+// Since we are merging 2 files. It will give us an opportunity to resolve
+// the extern node paths in the trigger expressions.
+//
+// ********************************************************************
+// In the real server, we dont store, externs
+// *******************************************************************
+BOOST_AUTO_TEST_CASE( test_load_defs_cmd_handleRequest )
+{
+ cout << "Client:: ...test_load_defs_cmd_handleRequest"<< endl;
+
+ std::string firstDef = File::test_data("Client/test/data/first.def","Client");
+
+ // Load the FIRST file with a set of unresolved extrens
+ defs_ptr firstDefs = Defs::create();
+ {
+ DefsStructureParser checkPtParser( firstDefs.get(), firstDef );
+ std::string errorMsg,warningMsg;
+ bool parse = checkPtParser.doParse(errorMsg,warningMsg);
+ BOOST_CHECK_MESSAGE(parse,"Parse failed. " << errorMsg);
+ }
+ size_t noOfSuites = firstDefs->suiteVec().size();
+ size_t noOfExterns = firstDefs->externs().size();
+
+
+ // load the SECOND file, which should resolve the externs
+ std::string secondDef = File::test_data("Client/test/data/second.def","Client");
+ Defs secondDefs;
+ {
+ DefsStructureParser checkPtParser( &secondDefs , secondDef);
+ std::string errorMsg,warningMsg;
+ bool parse = checkPtParser.doParse(errorMsg,warningMsg);
+ BOOST_CHECK_MESSAGE(parse,"Parse failed. " << errorMsg);
+ }
+ noOfSuites += secondDefs.suiteVec().size();
+ noOfExterns += secondDefs.externs().size();
+
+
+ // Create a LoadDefsCmd. This capable of merging defs files and resolving externs
+ LoadDefsCmd cmd(firstDefs);
+ cmd.setup_user_authentification();
+
+ // Calling handelRequest will absorb the first defs into second including externs & server user variables
+ // AND resolve any references to node paths in the trigger expressions
+ // Test that the merge was OK as well
+ MockServer mockServer(&secondDefs);
+ STC_Cmd_ptr requestStatus = cmd.handleRequest(&mockServer);
+ BOOST_CHECK_MESSAGE( requestStatus, "Handle Request " << cmd << " returned NULL\n");
+ BOOST_CHECK_MESSAGE( requestStatus->error().empty(), requestStatus->error());
+ BOOST_CHECK_MESSAGE( secondDefs.suiteVec().size() == noOfSuites,"Merge failed to add suites");
+ BOOST_CHECK_MESSAGE( secondDefs.externs().size() == noOfExterns,"Merge failed to add externs");
+ BOOST_CHECK_MESSAGE( firstDefs->suiteVec().size() == 0, "Merge failed to remove suites");
+
+
+ // Modify the Defs file to add a task/trigger that references the undefined
+ // extern path defined in file 'first.def' This should fail.
+ task_ptr task = Task::create( "AMadeUpName");
+ task->add_trigger( "/a/b/c/d/e/f/g/h/j == complete");
+ secondDefs.suiteVec().back()->familyVec().back()->addTask(task);
+
+ // we just added an expression, re-parse to create AST
+ // This should also attempt to resolve the extern node path /a/b/c/d/e/f/g/h/j
+ // The suite 'a' should exist. But the full path is non existent
+ // hence we expect the PARSE to fail.
+ std::string errormsg,warningMsg;
+ BOOST_CHECK_MESSAGE(!secondDefs.check(errormsg,warningMsg),errormsg);
+}
+
+BOOST_AUTO_TEST_CASE( test_load_defs_check_only )
+{
+ /// Test that when check only is called the definition is NOT loaded
+ InvokeServer invokeServer("Client:: ...test_load_defs_check_only",SCPort::next());
+
+ std::string path = File::test_data("Client/test/data/lifecycle.txt","Client");
+
+ // Do not load the defs do a check only
+ ClientInvoker theClient(invokeServer.host(),invokeServer.port());
+ BOOST_REQUIRE_MESSAGE( theClient.loadDefs(path,false,true/* check only*/) == 0,"Expected load to succeed\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.sync_local() == 0,"Expected sync to succeed\n" << theClient.errorMsg());
+
+ // Note: when running with ECF_NODE=localhost the defs may exist, but the number of suites should be empty
+ BOOST_REQUIRE_MESSAGE( !theClient.defs() || theClient.defs()->suiteVec().empty(),"Expected no defs, since nothing should have been loaded\n" << theClient.errorMsg());
+
+ // provide path to definition that should fail to parse
+ std::string path_bad_def = File::test_data("Client/test/data/bad.def","Client");
+ BOOST_REQUIRE_THROW( theClient.loadDefs(path_bad_def,false,true/* check only*/),std::runtime_error);
+}
+
+BOOST_AUTO_TEST_CASE( test_load_defs )
+{
+ /// Test that loading a defs a second time, with the same suite, throws a errors
+ /// unless the -force option is used.
+ InvokeServer invokeServer("Client:: ...test_load_defs",SCPort::next());
+
+ // create a defs with a single suite 's1'
+ defs_ptr theDefs = Defs::create();
+ {
+ suite_ptr suite = Suite::create("s1");
+ theDefs->addSuite( suite );
+ }
+
+ // Load the defs into the server
+ ClientInvoker theClient(invokeServer.host(),invokeServer.port());
+ theClient.set_throw_on_error(false);
+ BOOST_REQUIRE_MESSAGE( theClient.load(theDefs) == 0,"Expected load to succeed\n" << theClient.errorMsg());
+
+ // load the defs again. This should fail. as it stops accidental overwrites
+ BOOST_REQUIRE_MESSAGE( theClient.load(theDefs) == 1,"Expected load to fail\n" << theClient.errorMsg());
+
+ // Try again but with force
+ BOOST_REQUIRE_MESSAGE( theClient.load(theDefs,true /*force*/) == 0,"Expected load to succeed\n" << theClient.errorMsg());
+
+ /// Destroy singleton's to avoid valgrind from complaining
+ System::destroy();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Client/test/TestMigration.cpp b/Client/test/TestMigration.cpp
new file mode 100644
index 0000000..31b62e3
--- /dev/null
+++ b/Client/test/TestMigration.cpp
@@ -0,0 +1,119 @@
+#define BOOST_TEST_MODULE TestMigration
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #11 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <fstream>
+
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/timer.hpp>
+
+#include "ClientInvoker.hpp"
+#include "ClientEnvironment.hpp"
+#include "File.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Task.hpp"
+#include "TestHelper.hpp"
+#include "InvokeServer.hpp"
+#include "SCPort.hpp"
+#include "Str.hpp"
+#include "Host.hpp"
+#include "Rtt.hpp"
+#include "DurationTimer.hpp"
+
+namespace fs = boost::filesystem;
+using namespace std;
+using namespace ecf;
+
+/**
+* Make available program's arguments to all tests, recieving
+* this fixture.
+*/
+struct ArgsFixture {
+ ArgsFixture(): argc(boost::unit_test::framework::master_test_suite().argc),
+ argv(boost::unit_test::framework::master_test_suite().argv){}
+ int argc;
+ char **argv;
+};
+
+BOOST_AUTO_TEST_SUITE( ClientTestSuite )
+
+// ************************************************************************************
+// Note: If you make edits to node tree, they will have no effect until the server is rebuilt
+// ************************************************************************************
+
+void do_test_migration(
+ ClientInvoker& theClient,
+ const std::string& host,
+ const std::string& port,
+ const std::string& directory,
+ int & error_cnt
+)
+{
+ fs::path full_path( fs::initial_path<fs::path>() );
+ full_path = fs::system_complete( fs::path( directory ) );
+
+ BOOST_CHECK(fs::exists( full_path ));
+ BOOST_CHECK(fs::is_directory( full_path ));
+
+ //std::cout << "\nIn directory: " << full_path.directory_string() << "\n\n";
+ fs::directory_iterator end_iter;
+ for ( fs::directory_iterator dir_itr( full_path ); dir_itr != end_iter; ++dir_itr ) {
+ try {
+ fs::path relPath(directory + "/" + dir_itr->path().filename().string());
+
+ // recurse down directories
+ if ( is_directory(dir_itr->status()) ) {
+ do_test_migration(theClient,host,port,relPath.string(),error_cnt);
+ continue;
+ }
+
+ cout << relPath.string() << " : file size " << fs::file_size(relPath) << "\n\n";
+ if ( fs::file_size(relPath) > 0) {
+ try {
+ theClient.loadDefs(relPath.string());
+ theClient.delete_all(true);
+ }
+ catch ( std::exception& e) {
+ error_cnt++;
+ BOOST_CHECK_MESSAGE(false,theClient.errorMsg() << " : " << e.what());
+ }
+ }
+ }
+ catch ( const std::exception & ex ) {
+ std::cout << dir_itr->path().filename() << " " << ex.what() << std::endl;
+ }
+ }
+}
+
+
+BOOST_FIXTURE_TEST_CASE( test_migration,ArgsFixture )
+{
+ if (argc == 2 && fs::exists(argv[1])) {
+ /// This will remove checkpt and backup , to avoid server from loading it. (i.e from previous test)
+ InvokeServer invokeServer("Client:: ...test_migration:",SCPort::next());
+
+ ClientInvoker theClient(invokeServer.host(), invokeServer.port());
+ int error_cnt = 0;
+ do_test_migration(theClient,invokeServer.host(), invokeServer.port(),argv[1],error_cnt);
+ BOOST_REQUIRE_MESSAGE( error_cnt == 0, "Migration test failed " << error_cnt << " times " );
+ }
+ else {
+ std::cout << "Ignoring test, since directory '/var/tmp/ma0/ECFLOW_TEST/migration' not found\n";
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Client/test/TestPlugCmd.cpp b/Client/test/TestPlugCmd.cpp
new file mode 100644
index 0000000..b1523f0
--- /dev/null
+++ b/Client/test/TestPlugCmd.cpp
@@ -0,0 +1,321 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #34 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <boost/test/unit_test.hpp>
+#include <iostream>
+#include <fstream>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include "boost/progress.hpp"
+
+#include "DefsStructureParser.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "TestHelper.hpp"
+#include "MockServer.hpp"
+
+#include "ClientInvoker.hpp"
+#include "InvokeServer.hpp"
+#include "SCPort.hpp"
+#include "File.hpp"
+
+namespace fs = boost::filesystem;
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( ClientTestSuite)
+
+BOOST_AUTO_TEST_CASE( test_plug_cmd )
+{
+ cout << "Client:: ...test_plug_cmd" << endl;
+
+ std::string path = File::test_data("Client/test/data/lifecycle.txt","Client");
+
+ Defs defs;
+ DefsStructureParser checkPtParser( &defs , path );
+ std::string errorMsg,warningMsg;
+ bool parse = checkPtParser.doParse(errorMsg,warningMsg);
+ if (!parse) std::cerr << errorMsg;
+ BOOST_CHECK(parse);
+
+// suite suite1
+// family family1
+// task a
+// event 1 myEvent
+// meter myMeter 0 100
+// task b
+// trigger a == complete
+// endfamily
+// family family2
+// task aa
+// trigger ../family1/a:myMeter >= 20 and ../family1/a:myEvent
+// task bb
+// trigger ../family1/a:myMeter >= 50 || ../family1/a:myEvent
+// endfamily
+// endsuite
+
+ /// Test failure modes, MockServer defaults to localhost:3141
+ // test source node that does not exist, fails
+ TestHelper::invokeFailureRequest(&defs, Cmd_ptr( new PlugCmd("I/dont/exist/on/the server", "suite1/family2") ));
+
+ // test dest node that does not exist, fails
+ TestHelper::invokeFailureRequest(&defs, Cmd_ptr( new PlugCmd("suite1/family1/a", "i/dont/exist/on/server") ));
+
+ // test source node same as dest node, fails
+ TestHelper::invokeFailureRequest(&defs, Cmd_ptr( new PlugCmd("suite1/family1/a", "suite1/family1/a") ));
+
+ // test dest node that matches local server host and port, but where path does not exist, fails
+ TestHelper::invokeFailureRequest(&defs, Cmd_ptr( new PlugCmd("suite1/family1/a", "//localhost:3141/i/dont/exist/on/local_server") ));
+
+ // Lock server as another user. Invoke a valid request that should fail, due to a lock
+ MockServer server(&defs);
+ BOOST_REQUIRE_MESSAGE(server.lock("A user"),"Lock expected to succeed");
+ TestHelper::invokeFailureRequest(server,Cmd_ptr( new PlugCmd("suite1/family1/a", "suite1/family2")));
+
+
+ { // Move the TASKS: on family1 --> family2
+ // Note: if on the destination node we select a task 'suite1/family2/aa', then node is moved to its parent
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new PlugCmd("suite1/family1/a", "suite1/family2")));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new PlugCmd("suite1/family1/b", "//localhost:3141/suite1/family2/aa")));
+
+ node_ptr node = defs.findAbsNode("suite1/family1");
+ BOOST_REQUIRE_MESSAGE( node.get() && node->isFamily(), "Could not find suite1/family1");
+ BOOST_REQUIRE_MESSAGE( node->isFamily()->taskVec().size() == 0, "Failed to move task to other family");
+
+ node_ptr node2 = defs.findAbsNode("suite1/family2");
+ BOOST_REQUIRE_MESSAGE( node2.get() && node->isFamily(), "Could not find suite1/family2");
+ BOOST_REQUIRE_MESSAGE( node2->isFamily()->taskVec().size() == 4, "family2 two should have 4 tasks");
+ }
+
+ { // Move FAMILIES: Add a new suite and move family1 and family2 to it.
+ defs.addSuite( Suite::create("suite2") );
+
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new PlugCmd("suite1/family1", "suite2")));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new PlugCmd("suite1/family2", "suite2")));
+
+ node_ptr suite1 = defs.findAbsNode("suite1");
+ BOOST_REQUIRE_MESSAGE( suite1.get() && suite1->isSuite(), "Could not find suite1");
+ BOOST_REQUIRE_MESSAGE( suite1->isSuite()->familyVec().size() == 0, "Expected suite1 to have '0' families as they should have been moved to suite2");
+
+ node_ptr suite2 = defs.findAbsNode("suite2");
+ BOOST_REQUIRE_MESSAGE( suite2.get() && suite2->isSuite(), "Could not find suite2");
+ BOOST_REQUIRE_MESSAGE( suite2->isSuite()->familyVec().size() == 2, "Expected suite2 to have '2' families");
+ }
+}
+
+
+BOOST_AUTO_TEST_CASE( test_plug_cmd_with_handles )
+{
+ cout << "Client:: ...test_plug_cmd_with_handles" << endl;
+
+ std::string path = File::test_data("Client/test/data/lifecycle.txt","Client");
+
+ Defs defs;
+ DefsStructureParser checkPtParser( &defs , path );
+ std::string errorMsg,warningMsg;
+ bool parse = checkPtParser.doParse(errorMsg,warningMsg);
+ if (!parse) std::cerr << errorMsg;
+ BOOST_CHECK(parse);
+
+// suite suite1
+// family family1
+// task a
+// event 1 myEvent
+// meter myMeter 0 100
+// task b
+// trigger a == complete
+// endfamily
+// family family2
+// task aa
+// trigger ../family1/a:myMeter >= 20 and ../family1/a:myEvent
+// task bb
+// trigger ../family1/a:myMeter >= 50 || ../family1/a:myEvent
+// endfamily
+// endsuite
+
+ /// create client handle which references suites suite in the server defs
+ std::vector<std::string> suite_names; suite_names.push_back("suite"); suite_names.push_back("suite2");
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new ClientHandleCmd(suite_names,false)),false /* bypass_state_modify_change_check */);
+
+
+ { // Move the TASKS: on family1 --> family2
+ // Note: if on the destination node we select a task 'suite1/family2/aa', then node is moved to its parent
+ Suite* suite = defs.findAbsNode("suite1")->isSuite();
+ unsigned int state_change_no = suite->state_change_no();
+ unsigned int modify_change_no = suite->modify_change_no();
+
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new PlugCmd("suite1/family1/a", "suite1/family2")));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new PlugCmd("suite1/family1/b", "//localhost:3141/suite1/family2/aa")));
+
+ BOOST_CHECK_MESSAGE(state_change_no != suite->state_change_no() || modify_change_no != suite->modify_change_no(),
+ "state and modify change numbers unaltered by plug command when using handles");
+ }
+
+ { // Move FAMILIES: Add a new suite and move family1 and family2 to it.
+ suite_ptr suite2 = defs.add_suite("suite2");
+ unsigned int state_change_no = suite2->state_change_no();
+ unsigned int modify_change_no = suite2->modify_change_no();
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new PlugCmd("suite1/family1", "suite2")));
+ TestHelper::invokeRequest(&defs,Cmd_ptr( new PlugCmd("suite1/family2", "suite2")));
+ BOOST_CHECK_MESSAGE(state_change_no != suite2->state_change_no() || modify_change_no != suite2->modify_change_no(),
+ "state and modify change numbers unaltered by plug command when using handles");
+ }
+}
+
+static void test_plug_on_multiple_server(
+ const std::string& host1, const std::string& port1,
+ const std::string& host2, const std::string& port2
+)
+{
+ std::cout << " on host1("<< host1 << ":" << port1 << ") host2(" << host2 << ":" << port2 << ")" << endl;
+ ClientInvoker server1Client(host1,port1); server1Client.set_throw_on_error(false);
+ ClientInvoker server2Client(host2,port2); server2Client.set_throw_on_error(false);
+
+ //std::cout << " restartServer the FIRST and SECOND servers" << endl;
+ BOOST_REQUIRE_MESSAGE( server1Client.restartServer() == 0,CtsApi::restartServer() << " should return 0 server not started, or connection refused\n" << server1Client.errorMsg());
+ BOOST_REQUIRE_MESSAGE( server2Client.restartServer() == 0,CtsApi::restartServer() << " should return 0 server not started, or connection refused\n" << server2Client.errorMsg());
+
+ //std::cout << " LOAD the defs into FIRST server(" << host1 << ":" << port1 << ") There is NO DEFS in the second server." << endl;
+ std::string path = File::test_data("Client/test/data/lifecycle.txt","Client");
+ BOOST_REQUIRE_MESSAGE( server1Client.loadDefs(path) == 0,"load defs failed \n" << server1Client.errorMsg());
+
+
+ //cout << " Test the ERROR conditions in MoveCmd" << endl;
+ std::string sourcePath = "/suite1";
+ std::string secondServerHostPort = "//localhost:" + port2; // The destination path must encode the host:port path to the second server
+
+ std::string destPath = secondServerHostPort + "/A/made/up/dest/path/that/does/not/exist/on/server2";
+ //cout << " Plug/Move from server1(" << host1 << ":" << port1 << ") to destination server " << destPath << endl;
+ int theResult = server1Client.plug(sourcePath,destPath);
+ BOOST_REQUIRE_MESSAGE( theResult == 1,CtsApi::plugArg() << "Expected to fail since no defs in server 2\n");
+ // std::cout << "Error message = " << server1Client.errorMsg() << "\n";
+
+ //cout << " *** Load Defs into SECOND server ***, ie both servers have the same definitions" << endl;
+ BOOST_REQUIRE_MESSAGE( server2Client.loadDefs(path) == 0,"load defs failed \n" << server2Client.errorMsg());
+
+
+ destPath = secondServerHostPort + "/suite1";
+ theResult = server1Client.plug(sourcePath,destPath);
+ // cout << "server1Client.errorMsg() = " << server1Client.errorMsg() << "\n";
+ BOOST_REQUIRE_MESSAGE( theResult == 1,CtsApi::plugArg() << " Expected to fail, since 'suite1' already exists in the server \n");
+
+ destPath = secondServerHostPort + "/suite1/family1";
+ theResult = server1Client.plug(sourcePath,destPath);
+ // cout << "server1Client.errorMsg() = " << server1Client.errorMsg() << "\n";
+ BOOST_REQUIRE_MESSAGE( theResult == 1,CtsApi::plugArg() << " Expected to fail, since can't move a suite into a family\n");
+
+ destPath = secondServerHostPort + "/suite1";
+ theResult = server1Client.plug("/suite1/family1",destPath);
+ // cout << "server1Client.errorMsg() = " << server1Client.errorMsg() << "\n";
+ BOOST_REQUIRE_MESSAGE( theResult == 1,CtsApi::plugArg() << " Expected to fail, Destination already has a family1 \n");
+
+ destPath = secondServerHostPort + "/A/made/up/dest/path/that/does/not/exist/on/server2";
+ theResult = server1Client.plug(sourcePath,destPath);
+ // cout << "server1Client.errorMsg() = " << server1Client.errorMsg() << "\n";
+ BOOST_REQUIRE_MESSAGE( theResult == 1,CtsApi::plugArg() << " Expected to fail, since destination path does not exist\n");
+
+ destPath = secondServerHostPort;
+ theResult = server1Client.plug("/suite1/family1",destPath);
+ // cout << "server1Client.errorMsg() = " << server1Client.errorMsg() << "\n";
+ BOOST_REQUIRE_MESSAGE( theResult == 1,CtsApi::plugArg() << " Expected to fail,since source path must be a suite, if the destination path name is empty\n");
+
+
+ // ==========================================================================================
+ // Test Plug command works
+ // ==========================================================================================
+
+ // Completely remove the 'suite1' file in the second server
+ BOOST_REQUIRE_MESSAGE( server2Client.delete_node(sourcePath) == 0,CtsApi::to_string(CtsApi::delete_node(sourcePath)) << " failed \n" << server2Client.errorMsg());
+ BOOST_REQUIRE_MESSAGE( server2Client.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << server2Client.errorMsg());
+ BOOST_REQUIRE_MESSAGE( server2Client.defs().get(),"Server returned a NULL defs");
+ BOOST_REQUIRE_MESSAGE( server2Client.defs()->suiteVec().size() == 0," Expected server2 to have zero suite");
+
+ // Move the suite FROM the FIRST server TO the SECOND server and check that it worked
+ destPath = secondServerHostPort;
+ theResult = server1Client.plug(sourcePath,destPath);
+ BOOST_REQUIRE_MESSAGE( theResult == 0,CtsApi::plugArg() << " failed \n" << server1Client.errorMsg());
+
+ BOOST_REQUIRE_MESSAGE( server1Client.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << server1Client.errorMsg());
+ BOOST_REQUIRE_MESSAGE( server1Client.defs().get(),"Server returned a NULL defs");
+ BOOST_REQUIRE_MESSAGE( server1Client.defs()->suiteVec().size() == 0," Expected server1 to have no suites");
+
+ BOOST_REQUIRE_MESSAGE( server2Client.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << server2Client.errorMsg());
+ BOOST_REQUIRE_MESSAGE( server2Client.defs().get(),"Server returned a NULL defs");
+ BOOST_REQUIRE_MESSAGE( server2Client.defs()->suiteVec().size() == 1," Expected server2 to have one suite");
+
+
+ // ==========================================================================
+ // Do it again, but with no defs file in second server. reload defs into server1
+ BOOST_REQUIRE_MESSAGE(server1Client.delete_all() == 0,CtsApi::to_string(CtsApi::delete_node()) << " failed \n" << server1Client.errorMsg());
+ BOOST_REQUIRE_MESSAGE(server2Client.delete_all() == 0,CtsApi::to_string(CtsApi::delete_node()) << " failed \n" << server2Client.errorMsg());
+ BOOST_REQUIRE_MESSAGE(server1Client.loadDefs(path) == 0,"load defs failed \n" << server1Client.errorMsg());
+
+ destPath = secondServerHostPort;
+ theResult = server1Client.plug(sourcePath,destPath);
+ BOOST_REQUIRE_MESSAGE( theResult == 0,CtsApi::plugArg() << " failed \n" << server1Client.errorMsg());
+
+ BOOST_REQUIRE_MESSAGE(server1Client.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << server1Client.errorMsg());
+ BOOST_REQUIRE_MESSAGE( server1Client.defs().get(),"Server returned a NULL defs");
+ BOOST_REQUIRE_MESSAGE( server1Client.defs()->suiteVec().size() == 0," Expected server1 to have no suites");
+
+ BOOST_REQUIRE_MESSAGE(server2Client.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << server2Client.errorMsg());
+ BOOST_REQUIRE_MESSAGE( server2Client.defs().get(),"Server returned a NULL defs");
+ BOOST_REQUIRE_MESSAGE( server2Client.defs()->suiteVec().size() == 1," Expected server2 to have one suite");
+}
+
+BOOST_AUTO_TEST_CASE( test_server_plug_cmd )
+{
+ if (ClientEnvironment::hostSpecified().empty()) {
+
+ cout << "Client:: ...test_server_plug_cmd";
+
+ // Invoke two servers. *which* will both terminate at the end of this scope
+ // This will remove check pt and backup file before server start, to avoid the server from loading previous test data
+ InvokeServer invokeServer1("",SCPort::next());
+ InvokeServer invokeServer2("",SCPort::next());
+
+ test_plug_on_multiple_server(invokeServer1.host(), invokeServer1.port(),
+ invokeServer2.host(), invokeServer2.port());
+ }
+ else {
+
+ // Plug is broken for new->old servers, where boost serialsation version number changes.
+ if (getenv("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")) {
+ cout << "Client:: ...test_server_plug_cmd: ignoring test when ECF_ALLOW_NEW_CLIENT_OLD_SERVER specified" << endl;
+ return;
+ }
+
+ cout << "Client:: ...test_server_plug_cmd";
+
+ // Remote server all ready running, start one more additional server
+ {
+ // remove any suites on the remote server. Since this test requires it.
+ ClientInvoker theClient(ClientEnvironment::hostSpecified(),ClientEnvironment::portSpecified());
+ BOOST_REQUIRE_MESSAGE( theClient.delete_all() == 0,CtsApi::to_string(CtsApi::delete_node()) << " failed should return 0. Should Delete ALL existing defs in the server\n" << theClient.errorMsg());
+ }
+
+ // Start additional local server, special constructor. need false flag, to avoid ambiguity, with the other constructor.
+ std::string port2 = SCPort::next_only();
+ InvokeServer invokeServer2(port2,false);
+
+ test_plug_on_multiple_server(ClientEnvironment::hostSpecified(), ClientEnvironment::portSpecified(),
+ Str::LOCALHOST(), port2);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/Client/test/TestRtt.cpp b/Client/test/TestRtt.cpp
new file mode 100644
index 0000000..7cca3de
--- /dev/null
+++ b/Client/test/TestRtt.cpp
@@ -0,0 +1,53 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <iostream>
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/timer.hpp>
+
+#include "Rtt.hpp"
+#include "File.hpp"
+
+namespace fs = boost::filesystem;
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( ClientTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_client_invoker_round_trip_times )
+{
+ cout << "Client:: ...test_client_invoker_round_trip_times" << endl;
+
+ std::string root_path = File::test_data("Client/test/data/","Client");
+
+ /// Open file rtt.dat and compute average round trip times
+ std::string result = Rtt::analyis( root_path + "rtt.dat");
+ //cout << result << "\n";
+
+ /// generated a file with results
+ std::string errorMsg;
+ string generated_file = root_path + "rtt_analysis.dat";
+ BOOST_CHECK_MESSAGE(File::create(generated_file, result,errorMsg),errorMsg);
+
+ /// Compare with a reference file
+ std::vector<std::string> ignoreVec; errorMsg.clear();
+ std::string diffs = File::diff(generated_file, root_path + "ref_analysis.dat", ignoreVec, errorMsg );
+ BOOST_CHECK_MESSAGE(diffs.empty(),diffs << "\n" << errorMsg);
+
+ if (diffs.empty()) boost::filesystem::remove(generated_file);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Client/test/TestServer.cpp b/Client/test/TestServer.cpp
new file mode 100644
index 0000000..4ff49f0
--- /dev/null
+++ b/Client/test/TestServer.cpp
@@ -0,0 +1,318 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #45 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <fstream>
+
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/timer.hpp>
+#include <boost/date_time/posix_time/time_formatters.hpp> // requires boost date and time lib, for to_simple_string
+
+#include "ClientInvoker.hpp"
+#include "ClientEnvironment.hpp"
+#include "File.hpp"
+#include "TestHelper.hpp"
+#include "InvokeServer.hpp"
+#include "SCPort.hpp"
+#include "Str.hpp"
+#include "DurationTimer.hpp"
+#include "Host.hpp"
+#include "Version.hpp"
+
+namespace fs = boost::filesystem;
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( ClientTestSuite )
+
+// ************************************************************************************
+// Note: If you make edits to node tree, they will have no effect until the server is rebuilt
+//
+// Note: To test HPUX->Linux, invoke serve on (Linux/HPUX) and the client cmds on other system
+// On the client side set ECF_NODE to machine name. To allow further testing if ECF_NODE
+// is specified then *don't* shutdown the server
+// ************************************************************************************
+
+BOOST_AUTO_TEST_CASE( test_server_version )
+{
+ /// This will remove checkpt and backup , to avoid server from loading it. (i.e from previous test)
+ InvokeServer invokeServer("Client:: ...test_server_version:",SCPort::next());
+
+ ClientInvoker theClient(invokeServer.host(), invokeServer.port());
+ BOOST_REQUIRE_MESSAGE(theClient.server_version() == 0,"server version\n" << theClient.errorMsg());
+ if (ClientEnvironment::hostSpecified().empty()) {
+ // This check only valid if server was invoked locally. Ignore for remote servers
+ BOOST_REQUIRE_MESSAGE(theClient.get_string() == Version::raw(),"Expected client version(" << Version::raw() << ") to match server version(" << theClient.get_string() << ")");
+ }
+ else {
+ // remote server, version may be different
+ BOOST_WARN_MESSAGE(theClient.get_string() == Version::raw(),"Client version(" << Version::raw() << ") does not match server version(" << theClient.get_string() << ")");
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_server_state_changes )
+{
+ /// This will remove checkpt and backup , to avoid server from loading it. (i.e from previous test)
+ InvokeServer invokeServer("Client:: ...test_server_state_changes:",SCPort::next());
+
+ std::string path = File::test_data("Client/test/data/lifecycle.txt","Client");
+
+ ClientInvoker theClient(invokeServer.host(), invokeServer.port());
+ BOOST_REQUIRE_MESSAGE(theClient.loadDefs(path) == 0,"load defs failed \n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << theClient.errorMsg());
+ if (ClientEnvironment::hostSpecified().empty()) {
+ // server started locally
+ BOOST_REQUIRE_MESSAGE(theClient.defs()->server().get_state() == SState::HALTED,"Expected INITIAL server state HALTED but found " << SState::to_string(theClient.defs()->server().get_state()));
+ }
+
+ BOOST_REQUIRE_MESSAGE(theClient.shutdownServer() == 0,CtsApi::shutdownServer() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.defs()->server().get_state() == SState::SHUTDOWN,"Expected server state SHUTDOWN but found " << SState::to_string(theClient.defs()->server().get_state()));
+
+ BOOST_REQUIRE_MESSAGE(theClient.haltServer() == 0,CtsApi::haltServer() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.defs()->server().get_state() == SState::HALTED,"Expected server state HALTED but found " << SState::to_string(theClient.defs()->server().get_state()));
+
+ BOOST_REQUIRE_MESSAGE(theClient.restartServer() == 0,CtsApi::restartServer() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.defs()->server().get_state() == SState::RUNNING,"Expected server state RUNNING but found " << SState::to_string(theClient.defs()->server().get_state()));
+
+ /// Repeat test using sync_local() to test incremental changes of server
+ BOOST_REQUIRE_MESSAGE(theClient.shutdownServer() == 0,CtsApi::shutdownServer() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.sync_local() == 0," failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.defs()->server().get_state() == SState::SHUTDOWN,"Expected server state SHUTDOWN but found " << SState::to_string(theClient.defs()->server().get_state()));
+
+ BOOST_REQUIRE_MESSAGE(theClient.haltServer() == 0,CtsApi::haltServer() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.sync_local() == 0," failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.defs()->server().get_state() == SState::HALTED,"Expected server state HALTED but found " << SState::to_string(theClient.defs()->server().get_state()));
+
+ BOOST_REQUIRE_MESSAGE(theClient.restartServer() == 0,CtsApi::restartServer() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.sync_local() == 0," failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.defs()->server().get_state() == SState::RUNNING,"Expected server state RUNNING but found " << SState::to_string(theClient.defs()->server().get_state()));
+
+ if (ClientEnvironment::hostSpecified().empty()) {
+ // This check only valid if server was invoked locally. Ignore for remote servers
+
+ // make sure edit history updated
+ BOOST_REQUIRE_MESSAGE(theClient.edit_history(Str::ROOT_PATH()) == 0,CtsApi::to_string(CtsApi::edit_history(Str::ROOT_PATH())) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.server_reply().get_string_vec().size() == 7,"Expected edit history of size 7, but found " << theClient.server_reply().get_string_vec().size());
+
+ // make sure edit history was *NOT* serialized, It is only serialized when check pointing
+ BOOST_REQUIRE_MESSAGE(theClient.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.defs()->get_edit_history(Str::ROOT_PATH()).size() == 0,"Expected edit history of size 0, but found " << theClient.defs()->get_edit_history(Str::ROOT_PATH()).size());
+ }
+}
+
+
+BOOST_AUTO_TEST_CASE( test_server_stress_test )
+{
+ /// This will remove checkpt and backup , to avoid server from loading it. (i.e from previous test)
+ InvokeServer invokeServer("Client:: ...test_server_stress_test:",SCPort::next());
+
+ std::string path = File::test_data("Client/test/data/lifecycle.txt","Client");
+
+ boost::timer boost_timer; // measures CPU, replace with cpu_timer with boost > 1.51, measures cpu & elapsed
+ DurationTimer duration_timer;
+ ClientInvoker theClient(invokeServer.host(), invokeServer.port());
+ int load = 125;
+ for(int i = 0; i < load; i++) {
+
+ BOOST_REQUIRE_MESSAGE(theClient.delete_all() == 0,CtsApi::to_string(CtsApi::delete_node()) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.loadDefs(path) == 0,"load defs failed \n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.shutdownServer() == 0,CtsApi::shutdownServer() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.haltServer() == 0,CtsApi::haltServer() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.restartServer() == 0,CtsApi::restartServer() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.restartServer() == 0,CtsApi::restartServer() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.checkPtDefs() == 0,CtsApi::checkPtDefs() << " failed should return 0\n" << theClient.errorMsg());
+
+ BOOST_REQUIRE_MESSAGE(theClient.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.defs().get(),"Server returned a NULL defs");
+ BOOST_REQUIRE_MESSAGE( theClient.defs()->suiteVec().size() >= 1," no suite ?");
+ }
+ cout << " Server handled " << load * 8
+ << " requests in boost_timer(" << boost_timer.elapsed()
+ << ") DurationTimer(" << to_simple_string(duration_timer.elapsed())
+ << ")" << endl;
+}
+
+
+BOOST_AUTO_TEST_CASE( test_server_group_stress_test )
+{
+ /// This is exactly the same test as above, but uses the group command
+ /// This should be faster as the network traffic should be a lot less
+ InvokeServer invokeServer("Client:: ...test_server_group_stress_test:",SCPort::next());
+
+ std::string path = File::test_data("Client/test/data/lifecycle.txt","Client");
+
+ boost::timer boost_timer; // measures CPU, replace with cpu_timer with boost > 1.51, measures cpu & elapsed
+ DurationTimer duration_timer;
+ ClientInvoker theClient(invokeServer.host(), invokeServer.port());
+
+ std::string groupRequest = CtsApi::to_string(CtsApi::delete_node());
+ groupRequest += ";";
+ groupRequest += CtsApi::to_string(CtsApi::loadDefs(path,true/*force*/,false /*check_only*/));
+ groupRequest += ";";
+ groupRequest += CtsApi::shutdownServer();
+ groupRequest += ";";
+ groupRequest += CtsApi::haltServer();
+ groupRequest += ";";
+ groupRequest += CtsApi::restartServer();
+ groupRequest += ";";
+ groupRequest += CtsApi::restartServer();
+ groupRequest += ";";
+ groupRequest += CtsApi::checkPtDefs();
+ groupRequest += ";";
+ groupRequest += CtsApi::get();
+
+ //cout << "groupRequest = " << groupRequest << "\n";
+
+ int load = 125;
+ for(int i = 0; i < load; i++) {
+ BOOST_REQUIRE_MESSAGE( theClient.group(groupRequest) == 0,"Group request " << CtsApi::group(groupRequest) << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.defs().get(),"Server returned a NULL defs");
+ BOOST_REQUIRE_MESSAGE( theClient.defs()->suiteVec().size() >= 1," no suite ?");
+ }
+ cout << " Server handled " << load * 8
+ << " commands using " << load << " group requests in boost_timer(" << boost_timer.elapsed()
+ << ") DurationTimer(" << to_simple_string(duration_timer.elapsed())
+ << ")" << endl;
+}
+
+BOOST_AUTO_TEST_CASE( test_server_stress_test_2 )
+{
+ /// More extensive stress test, using as many user based command as possible.
+ ///
+ /// This will remove checkpt and backup , to avoid server from loading it. (i.e from previous test)
+ InvokeServer invokeServer("Client:: ...test_server_stress_test_2:",SCPort::next());
+
+ std::string path = File::test_data("Client/test/data/lifecycle.txt","Client");
+
+ Zombie z(Child::USER,ecf::Child::INIT,ZombieAttr::get_default_attr(Child::USER),"path_to_task","DUMMY_JOBS_PASSWORD", "DUMMY_PROCESS_OR_REMOTE_ID",1);
+ std::vector<std::string> suites; suites.push_back("suite1"); suites.push_back("made_up_suite");
+
+ std::vector<std::string> nodes_to_delete;
+ nodes_to_delete.push_back("/suite1/family2/aa"); // these should exist in lifecycle.txt
+ nodes_to_delete.push_back("/suite1/family2/bb");
+
+#if defined(HPUX)
+ int load = 10; // On non linux systems use different load otherwise it takes to long
+#elif defined(_AIX)
+ int load = 65; // On non linux systems use different load otherwise it takes to long
+#else
+ int load = 136;
+#endif
+
+ boost::timer boost_timer; // measures CPU, replace with cpu_timer with boost > 1.51, measures cpu & elapsed
+ DurationTimer duration_timer;
+ ClientInvoker theClient(invokeServer.host(), invokeServer.port());
+ theClient.set_throw_on_error(false);
+ for(int i = 0; i < load; i++) {
+
+ BOOST_REQUIRE_MESSAGE( theClient.pingServer() == 0, " ping should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.delete_all() == 0,CtsApi::to_string(CtsApi::delete_node()) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.loadDefs(path) == 0,"load defs failed \n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.shutdownServer() == 0,CtsApi::shutdownServer() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.haltServer() == 0,CtsApi::haltServer() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.restartServer() == 0,CtsApi::restartServer() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.news_local() == 0, " new local failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.sync_local() == 0, "failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.stats() == 0,CtsApi::stats() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.suites() == 0,CtsApi::suites() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.server_version() == 0,CtsApi::server_version() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.debug_server_off() == 0,CtsApi::debug_server_off() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.check("/suite1") == 0,"check should return 0\n" << theClient.errorMsg()); //13
+
+ BOOST_REQUIRE_MESSAGE( theClient.logMsg("start") == 0,"log msg should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.get_log_path() == 0,"get_log_path should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.getLog(1) == 0,"get_log last line should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.flushLog() == 0,"flushLog should return 0\n" << theClient.errorMsg());
+
+ BOOST_REQUIRE_MESSAGE( theClient.force("/suite1","unknown",true) == 0,"check should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.force("/suite1","complete",true) == 0,"check should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.force("/suite1","submitted",true) == 0,"check should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.force("/suite1","active",true) == 0,"check should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.force("/suite1","aborted",true) == 0,"check should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.force("/suite1","queued",true) == 0,"check should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.force("/suite1/family1/a:myEvent","set") == 0,"check should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.force("/suite1/family1/a:myEvent","clear") == 0,"check should return 0\n" << theClient.errorMsg());
+
+ BOOST_REQUIRE_MESSAGE( theClient.zombieGet() == 0,CtsApi::zombieGet() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.zombieFob(z) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.zombieFail(z) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.zombieAdopt(z) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.zombieBlock(z) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.zombieRemove(z) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.zombieKill(z) == 0, " should return 0\n" << theClient.errorMsg()); //19
+
+ BOOST_REQUIRE_MESSAGE( theClient.suspend("/suite1") == 0,CtsApi::to_string(CtsApi::suspend("/suite1"))<< " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.resume("/suite1") == 0,CtsApi::to_string(CtsApi::resume("/suite1")) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.edit_history("/suite1") == 0,CtsApi::to_string(CtsApi::edit_history("/suite1")) << " should return 0\n" << theClient.errorMsg());
+
+ BOOST_REQUIRE_MESSAGE( theClient.replace("/suite1",path) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.replace("/suite1",path,true) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.replace("/suite1",path,true, true) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.replace("/suite1",path,false, true) == 0, " should return 0\n" << theClient.errorMsg()); //26
+
+ BOOST_REQUIRE_MESSAGE( theClient.checkPtDefs() == 0,CtsApi::checkPtDefs() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.checkPtDefs(ecf::CheckPt::NEVER) == 0," should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.checkPtDefs(ecf::CheckPt::ALWAYS) == 0," should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.checkPtDefs(ecf::CheckPt::ON_TIME,180) == 0," should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.checkPtDefs(ecf::CheckPt::ON_TIME) == 0," should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.checkPtDefs(ecf::CheckPt::UNDEFINED) == 0," should return 0\n" << theClient.errorMsg()); //32
+ BOOST_REQUIRE_MESSAGE( theClient.checkPtDefs(ecf::CheckPt::ON_TIME,CheckPt::default_interval()) == 0," should return 0\n" << theClient.errorMsg());
+
+ BOOST_REQUIRE_MESSAGE( theClient.freeDep("/suite1") == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.freeDep("/suite1",true,true,true,true) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.freeDep("/suite1",true) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.freeDep("/suite1",false,true) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.freeDep("/suite1",false,false,true) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.freeDep("/suite1",false,false,false,true) == 0, " should return 0\n" << theClient.errorMsg()); //38
+
+ BOOST_REQUIRE_MESSAGE( theClient.ch_register(true,suites) == 0,"--ch_register \n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.ch_suites() == 0,"--ch_suites should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.ch_add(1,suites) == 0,"--ch_add \n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.ch_remove(1,suites) == 0,"--ch_remove \n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.ch_auto_add(1,true) == 0,"--ch_auto_add \n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.ch_auto_add(1,false) == 0,"--ch_auto_add \n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.ch_drop(1) == 0,"--ch_drop should return 0\n" << theClient.errorMsg()); //45
+
+ BOOST_REQUIRE_MESSAGE( theClient.ch_register(true,suites) == 0,"--ch_register \n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.ch1_add(suites) == 0,"--ch1_add \n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.ch1_auto_add(true) == 0,"--ch1_auto_add \n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.ch1_auto_add(false) == 0,"--ch1_auto_add \n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.ch1_remove(suites) == 0,"--ch1_remove \n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.ch1_drop() == 0,"--ch1_drop \n" << theClient.errorMsg()); //51
+
+ BOOST_REQUIRE_MESSAGE( theClient.order("/suite1","top") == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.order("/suite1","bottom") == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.order("/suite1","alpha") == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.order("/suite1",NOrder::ORDER) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.order("/suite1",NOrder::UP) == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.order("/suite1",NOrder::DOWN) == 0, " should return 0\n" << theClient.errorMsg()); //57
+
+ BOOST_REQUIRE_MESSAGE( theClient.delete_node("/suite1/family1/a") == 0, " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.delete_nodes(nodes_to_delete) == 0, " should return 0\n" << theClient.errorMsg());
+
+ BOOST_REQUIRE_MESSAGE( theClient.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << theClient.errorMsg()); //60
+ BOOST_REQUIRE_MESSAGE( theClient.defs().get(),"Server returned a NULL defs");
+ BOOST_REQUIRE_MESSAGE( theClient.defs()->suiteVec().size() >= 1," no suite ?");
+ }
+ cout << " Server handled " << load * 74
+ << " requests in boost_timer(" << boost_timer.elapsed()
+ << ") DurationTimer(" << to_simple_string(duration_timer.elapsed())
+ << ")" << endl;
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Client/test/TestServerAndLifeCycle.cpp b/Client/test/TestServerAndLifeCycle.cpp
new file mode 100644
index 0000000..9de0450
--- /dev/null
+++ b/Client/test/TestServerAndLifeCycle.cpp
@@ -0,0 +1,247 @@
+#define BOOST_TEST_MODULE TestClient
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #54 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <fstream>
+
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+
+#include "ClientInvoker.hpp"
+#include "ClientEnvironment.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "File.hpp"
+#include "PrintStyle.hpp"
+#include "WhiteListFile.hpp"
+#include "InvokeServer.hpp"
+#include "SCPort.hpp"
+#include "Str.hpp"
+#include "System.hpp" // kill singleton for valgrind
+
+namespace fs = boost::filesystem;
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( ClientTestSuite )
+
+// ************************************************************************************
+// Note: If you make edits to node tree, they will have no effect until the server is rebuilt
+//
+// Note: To test HPUX->Linux, invoke serve on (Linux/HPUX) and the client cmds on other system
+// On the client side set ECF_NODE to machine name. To allow further testing if ECF_NODE
+// is specified then *don't* shutdown the server
+// ************************************************************************************
+
+BOOST_AUTO_TEST_CASE( test_client_lifecyle )
+{
+ // *******************************************************************************************
+ // This test will *ONLY* work when testing with new server invocation, since it relies
+ // on disabling job generation. Hence ignore test if ECF_NODE has been defined
+ // *******************************************************************************************
+ std::string host = ClientEnvironment::hostSpecified();
+ if (!host.empty()) {
+ // Server allready started, since we cant disable job generation ignore this test
+ std::cout << "Client:: ...test_client_lifecycle, ignoring test when ECF_NODE specified..." << endl;
+ return;
+ }
+
+ // This will remove check pt and backup file before server start, to avoid the server from loading previous test data
+ // ** NOTE: We disable job generation in the server **/
+ InvokeServer invokeServer("Client:: ...test_client_lifecycle",SCPort::next(),true /*disable job generation in server*/);
+
+ ClientInvoker theClient(invokeServer.host(),invokeServer.port());
+ BOOST_REQUIRE_MESSAGE( theClient.restartServer() == 0,CtsApi::restartServer() << " should return 0 server not started, or connection refused\n" << theClient.errorMsg());
+
+ // load the defs into the server
+ {
+ std::string path = File::test_data("Client/test/data/lifecycle.txt","Client");
+ BOOST_REQUIRE_MESSAGE(theClient.delete_all() == 0,CtsApi::to_string(CtsApi::delete_node()) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.loadDefs(path) == 0, "Load defs failed \n" << theClient.errorMsg());
+ }
+ {
+ BOOST_REQUIRE_MESSAGE(theClient.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << theClient.errorMsg());
+ defs_ptr serverDefs = theClient.defs();
+ BOOST_REQUIRE_MESSAGE( serverDefs.get(),"Server returned a NULL defs");
+ BOOST_REQUIRE_MESSAGE( serverDefs->suiteVec().size() >= 1," no suite ?");
+ }
+
+
+ // Now go through and simulate client request to change Node tree state.
+ // This is **highly** dependent on lifecycle.txt
+ // suite suite1
+ // family family1
+ // task a
+ // event 1 myEvent
+ // meter myMeter 0 100
+ // task b
+ // trigger a == complete
+ // endfamily
+ // family family2
+ // task aa
+ // trigger ../family1/a:myMeter >= 20 and ../family1/a:myEvent
+ // task bb
+ // trigger ../family1/a:myMeter >= 50 || ../family1/a:myEvent
+ // endfamily
+ // endsuite
+
+ string suite1_family1_a = "suite1/family1/a";
+ string suite1_family1_b = "suite1/family1/b";
+ string suite1_family2_aa = "suite1/family2/aa";
+ string suite1_family2_bb = "suite1/family2/bb";
+
+ {
+ // Begin will set all states to queued and then start job submission placing
+ // any submiited jobs into the active state. Note server setup has disabled job generation
+ BOOST_REQUIRE_MESSAGE(theClient.begin("suite1") == 0,CtsApi::begin("suite1") << " failed should return 0\n" << theClient.errorMsg());
+
+ BOOST_REQUIRE_MESSAGE(theClient.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << theClient.errorMsg());
+ defs_ptr serverDefs = theClient.defs();
+ node_ptr node = serverDefs->findAbsNode(suite1_family1_a);
+ BOOST_REQUIRE_MESSAGE( node->state() == NState::ACTIVE, "Node expected NState::ACTIVE, but found to be " << NState::toString(node->state()));
+ }
+
+ //**********************************************************************
+ // Create a request to set the event on Node suite1/family1/a
+ // This should place suite1_family2_bb immediately into submitted state
+ // Since we at least one node in submitted, suite should be in SUBMITTED state
+ {
+ theClient.taskPath(suite1_family1_a);
+ theClient.set_jobs_password(Submittable::DUMMY_JOBS_PASSWORD());
+ BOOST_REQUIRE_MESSAGE(theClient.eventTask("myEvent") == 0,TaskApi::event("myEvent") << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.forceDependencyEval() == 0,CtsApi::forceDependencyEval() << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << theClient.errorMsg());
+ defs_ptr serverDefs = theClient.defs();
+ // PrintStyle style(PrintStyle::STATE);
+ // cerr << *serverDefs.get() << "\n";
+ BOOST_REQUIRE_MESSAGE( serverDefs.get(),"get command failed to get node tree from server");
+
+ node_ptr node = serverDefs->findAbsNode(suite1_family1_a);
+ BOOST_REQUIRE_MESSAGE( node->state() == NState::ACTIVE, "Node expected NState::ACTIVE, but found to be " << NState::toString(node->state()));
+ node_ptr nodeb = serverDefs->findAbsNode(suite1_family2_bb);
+ BOOST_REQUIRE_MESSAGE( nodeb->state() == NState::ACTIVE, "Node expected NState::ACTIVE, but found to be " << NState::toString(nodeb->state()));
+ }
+
+
+ //**********************************************************************
+ // Create a request to set the Meter on Node suite1/family1/a
+ // This should force suite1_family2_aa immediately into submitted state
+ // This should force suite1_family2_bb immediately into submitted state
+ {
+ theClient.taskPath(suite1_family1_a);
+ {
+ char* argv[] = { const_cast<char*>("ClientInvoker"),
+ const_cast<char*>("--meter=myMeter"),
+ const_cast<char*>("100")
+ };
+ BOOST_REQUIRE_MESSAGE(theClient.invoke(3,argv) == 0," should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.forceDependencyEval() == 0,CtsApi::forceDependencyEval() << " failed should return 0\n" << theClient.errorMsg());
+ }
+
+ BOOST_REQUIRE_MESSAGE(theClient.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << theClient.errorMsg());
+ defs_ptr serverDefs = theClient.defs();
+ BOOST_REQUIRE_MESSAGE( serverDefs.get(),"get command failed to get node tree from server");
+
+ node_ptr nodeaa = serverDefs->findAbsNode(suite1_family2_aa);
+ BOOST_REQUIRE_MESSAGE( nodeaa->state() == NState::ACTIVE, "Node expected NState::ACTIVE, but found to be " << NState::toString(nodeaa->state()));
+
+ node_ptr nodebb = serverDefs->findAbsNode(suite1_family2_bb);
+ BOOST_REQUIRE_MESSAGE( nodebb->state() == NState::ACTIVE, "Node expected NState::ACTIVE, but found to be " << NState::toString(nodebb->state()));
+ }
+
+ //**********************************************************************
+ // Create a request to complete task suite1/family1/a
+ // This should force suite1_family1_b to complete
+ {
+ theClient.taskPath(suite1_family1_a);
+ BOOST_REQUIRE_MESSAGE(theClient.completeTask() == 0,TaskApi::complete() << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.forceDependencyEval() == 0,CtsApi::forceDependencyEval() << " failed should return 0\n" << theClient.errorMsg());
+
+ // Resolve dependencies
+ // We could either wait 60 second or
+ // added a custom command that will force dependency evaluation
+ BOOST_REQUIRE_MESSAGE( theClient.forceDependencyEval() == 0,"--force-dep-eval failed should return 0\n" << theClient.errorMsg());
+
+ BOOST_REQUIRE_MESSAGE(theClient.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << theClient.errorMsg());
+ defs_ptr serverDefs = theClient.defs();
+ BOOST_REQUIRE_MESSAGE( serverDefs.get(),"get command failed to get node tree from server");
+
+ node_ptr node = serverDefs->findAbsNode(suite1_family1_b);
+ BOOST_REQUIRE_MESSAGE( node->state() == NState::ACTIVE, "Expected NState::ACTIVE, but found " << NState::toString(node->state()));
+ }
+
+ //********************************************************************************
+ // Complete the remaining tasks. Should really call init first, but what the eck.
+ {
+ theClient.taskPath(suite1_family1_b);
+ BOOST_REQUIRE_MESSAGE(theClient.completeTask() == 0,TaskApi::complete() << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.forceDependencyEval() == 0,CtsApi::forceDependencyEval() << " failed should return 0\n" << theClient.errorMsg());
+
+ theClient.taskPath(suite1_family2_aa);
+ BOOST_REQUIRE_MESSAGE(theClient.completeTask() == 0,TaskApi::complete() << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.forceDependencyEval() == 0,CtsApi::forceDependencyEval() << " failed should return 0\n" << theClient.errorMsg());
+
+ theClient.taskPath(suite1_family2_bb);
+ BOOST_REQUIRE_MESSAGE(theClient.completeTask() == 0,TaskApi::complete() << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.forceDependencyEval() == 0,CtsApi::forceDependencyEval() << " failed should return 0\n" << theClient.errorMsg());
+ }
+
+ {
+ // Get the node tree back from the server, and check its node state
+ // All node state should be complete. + check meter/event value was set properly
+ BOOST_REQUIRE_MESSAGE(theClient.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << theClient.errorMsg());
+
+ defs_ptr serverDefs = theClient.defs();
+ BOOST_REQUIRE_MESSAGE( serverDefs.get(),"get command failed to get node tree from server");
+
+ std::string metername = "myMeter";
+ int meterValue = 100;
+ node_ptr node = serverDefs->findAbsNode(suite1_family1_a);
+ const Meter& theMeter = node->findMeter(metername);
+ BOOST_REQUIRE_MESSAGE( !theMeter.empty(), "Could not find the meter");
+ BOOST_REQUIRE_MESSAGE( theMeter.value() == meterValue , "Expected meter value " << meterValue << " but found " << theMeter.value());
+ {
+ std::string errorMsg; BOOST_REQUIRE_MESSAGE( serverDefs->checkInvariants(errorMsg), errorMsg);
+ }
+
+ std::string eventname = "myEvent";
+ const Event& theEvent = node->findEventByNameOrNumber(eventname);
+ BOOST_REQUIRE_MESSAGE( !theEvent.empty(), "Could not find the event myEvent");
+ BOOST_REQUIRE_MESSAGE( theEvent.value(), "The event was not set");
+
+ const std::vector<suite_ptr>& suiteVec = serverDefs->suiteVec();
+ suite_ptr suite = suiteVec.back();
+ BOOST_REQUIRE_MESSAGE( suite->state() == NState::COMPLETE,
+ "Suite expected NState::COMPLETE, but found to be " << NState::toString(suite->state()));
+ }
+
+ {
+ // Check that a log file was created, by asking the server for it.
+ BOOST_REQUIRE_MESSAGE( theClient.getLog() == 0, "get log failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(!theClient.get_string().empty(),"The log file returned from the server is empty!!");
+
+ // Clear the log
+ BOOST_REQUIRE_MESSAGE(theClient.flushLog() == 0,CtsApi::flushLog() << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.clearLog() == 0,CtsApi::clearLog() << " failed should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.delete_all() == 0,CtsApi::to_string(CtsApi::delete_node()) << " should return 0\n" << theClient.errorMsg());
+ }
+
+ /// Destroy singleton's to avoid valgrind from complaining
+ System::destroy();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/Client/test/TestServerLoad.cpp b/Client/test/TestServerLoad.cpp
new file mode 100644
index 0000000..2ce9d75
--- /dev/null
+++ b/Client/test/TestServerLoad.cpp
@@ -0,0 +1,103 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #29 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <string>
+#include <fstream>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/test/unit_test.hpp>
+
+#include "ClientInvoker.hpp"
+#include "InvokeServer.hpp"
+#include "SCPort.hpp"
+#include "Str.hpp"
+#include "File.hpp"
+
+namespace fs = boost::filesystem;
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( ClientTestSuite )
+
+BOOST_AUTO_TEST_CASE( test_server_load )
+{
+ // Check if gnuplot is found on the path, on the RPM machines gnuplot not always installed
+ std::string path_to_gnuplot = File::which("gnuplot");
+ if ( path_to_gnuplot.empty()) {
+ cout << "Client:: ...test_server_load -----> gnuplot not found on $PATH *IGNORING* test\n";
+ return;
+ }
+
+ // This will remove check pt and backup file before server start, to avoid the server from loading previous test data
+ InvokeServer invokeServer("Client:: ...test_server_load",SCPort::next());
+
+ ClientInvoker theClient(invokeServer.host(),invokeServer.port());
+
+ // add some text in log file, need at least 4 different time-stamps for plotting
+ int load = 2;
+ for(int i = 0; i < load; i++) {
+ BOOST_REQUIRE_MESSAGE(theClient.delete_all() == 0,CtsApi::to_string(CtsApi::delete_node()) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.shutdownServer() == 0,CtsApi::shutdownServer() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.haltServer() == 0,CtsApi::haltServer() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.restartServer() == 0,CtsApi::restartServer() << " should return 0\n" << theClient.errorMsg());
+ }
+ sleep(1); // need a time gap
+ for(int i = 0; i < load; i++) {
+ BOOST_REQUIRE_MESSAGE(theClient.delete_all() == 0,CtsApi::to_string(CtsApi::delete_node()) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.shutdownServer() == 0,CtsApi::shutdownServer() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.haltServer() == 0,CtsApi::haltServer() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.restartServer() == 0,CtsApi::restartServer() << " should return 0\n" << theClient.errorMsg());
+ }
+ sleep(1); // need a time gap
+ for(int i = 0; i < load; i++) {
+ BOOST_REQUIRE_MESSAGE(theClient.delete_all() == 0,CtsApi::to_string(CtsApi::delete_node()) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.shutdownServer() == 0,CtsApi::shutdownServer() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.haltServer() == 0,CtsApi::haltServer() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.restartServer() == 0,CtsApi::restartServer() << " should return 0\n" << theClient.errorMsg());
+ }
+ sleep(1); // need a time gap
+ for(int i = 0; i < load; i++) {
+ BOOST_REQUIRE_MESSAGE(theClient.delete_all() == 0,CtsApi::to_string(CtsApi::delete_node()) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.shutdownServer() == 0,CtsApi::shutdownServer() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.haltServer() == 0,CtsApi::haltServer() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE(theClient.restartServer() == 0,CtsApi::restartServer() << " should return 0\n" << theClient.errorMsg());
+ }
+
+ // Now generate gnuplot files.
+ BOOST_REQUIRE_MESSAGE( theClient.server_load() == 0,CtsApi::server_load_arg() << " should return 0 server not started, or connection refused\n" << theClient.errorMsg());
+
+ // Check files were created
+ Host the_host(invokeServer.host());
+ std::string gnuplot_dat_file = the_host.prefix_host_and_port(invokeServer.port(),"gnuplot.dat");
+ std::string gnuplot_script_file = the_host.prefix_host_and_port(invokeServer.port(),"gnuplot.script");
+ std::string gnuplot_png_file = the_host.prefix_host_and_port(invokeServer.port(),"png");
+
+
+ BOOST_REQUIRE_MESSAGE(fs::exists(gnuplot_dat_file),CtsApi::server_load_arg() << " failed file(" << gnuplot_dat_file << ") not generated");
+ BOOST_REQUIRE_MESSAGE(fs::exists(gnuplot_script_file),CtsApi::server_load_arg() << " failed file(" << gnuplot_script_file << ") not generated");
+ BOOST_REQUIRE_MESSAGE(fs::exists(gnuplot_png_file),CtsApi::server_load_arg() << " failed file(" << gnuplot_png_file << ") not generated");
+
+ BOOST_REQUIRE_MESSAGE(fs::file_size(gnuplot_dat_file) !=0,"Expected file(" << gnuplot_dat_file << ") to have file size > 0 ");
+ BOOST_REQUIRE_MESSAGE(fs::file_size(gnuplot_script_file) !=0,"Expected file(" << gnuplot_script_file << ") to have file size > 0 ");
+ BOOST_REQUIRE_MESSAGE(fs::file_size(gnuplot_png_file) !=0,"Expected file(" << gnuplot_png_file << ") to have file size > 0 ");
+
+ // remove generated gnuplot files.
+ fs::remove( gnuplot_dat_file );
+ fs::remove( gnuplot_script_file );
+ fs::remove( gnuplot_png_file );
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/Client/test/TestSignalSIGTERM.cpp b/Client/test/TestSignalSIGTERM.cpp
new file mode 100644
index 0000000..453c40a
--- /dev/null
+++ b/Client/test/TestSignalSIGTERM.cpp
@@ -0,0 +1,82 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <string>
+#include <fstream>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/test/unit_test.hpp>
+
+#include "ClientInvoker.hpp"
+#include "ClientEnvironment.hpp"
+#include "InvokeServer.hpp"
+#include "SCPort.hpp"
+#include "Str.hpp"
+
+namespace fs = boost::filesystem;
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( ClientTestSuite )
+
+// ************************************************************************************
+// Note: If you make edits to node tree, they will have no effect until the server is rebuilt
+//
+// This test will send a signal SIGTERM, i.e (via kill -15 pid) and check to ensure
+// that a check point file is saved.
+// ************************************************************************************
+BOOST_AUTO_TEST_CASE( test_signal_SIGTERM )
+{
+ // This will remove check pt and backup file before server start, to avoid the server from loading previous test data
+ InvokeServer invokeServer("Client:: ...test_signal_SIGTERM",SCPort::next());
+
+ ClientInvoker theClient(invokeServer.host(),invokeServer.port());
+ BOOST_REQUIRE_MESSAGE( theClient.restartServer() == 0,CtsApi::restartServer() << " should return 0 server not started, or connection refused\n" << theClient.errorMsg());
+
+ std::string path = File::test_data("Client/test/data/lifecycle.txt","Client");
+ BOOST_REQUIRE_MESSAGE(theClient.loadDefs(path) == 0,"load defs failed \n" << theClient.errorMsg());
+
+ // Get the definition
+ BOOST_REQUIRE_MESSAGE(theClient.sync_local() == 0, "Sync local failed\n" << theClient.errorMsg());
+
+ // Get the process id of the server
+ const std::string& ecf_pid = theClient.defs()->server().find_variable("ECF_PID");
+ BOOST_REQUIRE_MESSAGE(!ecf_pid.empty(),"ECF_PID not set in the server");
+
+ // Send a SIGTERM to the server and ensure that a check point file is created
+ std::string sigterm = "kill -15 " + ecf_pid ;
+ system(sigterm.c_str());
+ sleep(2); // allow time for system call
+
+ // We expect a check point file to be save to disk, but *no* backup
+ BOOST_REQUIRE_MESSAGE(fs::exists(invokeServer.ecf_checkpt_file()),CtsApi::checkPtDefs() << " failed file(" << invokeServer.ecf_checkpt_file() << ") not saved");
+ BOOST_REQUIRE_MESSAGE(fs::file_size(invokeServer.ecf_checkpt_file()) !=0,"Expected check point file(" << invokeServer.ecf_checkpt_file() << "), to have file size > 0");
+ if (ClientEnvironment::hostSpecified().empty()) {
+ // This check only valid if server was invoked locally. Ignore for remote servers
+ BOOST_REQUIRE_MESSAGE(!fs::exists(invokeServer.ecf_backup_checkpt_file()), "Backup check point file(" << invokeServer.ecf_backup_checkpt_file() << ")should not exist,for very first time.");
+ }
+
+ // Send a SIGTERM again. This time we expect the backup check point file to be created.
+ system(sigterm.c_str());
+ sleep(2); // allow time for system call
+
+ BOOST_REQUIRE_MESSAGE(fs::exists(invokeServer.ecf_checkpt_file()),CtsApi::checkPtDefs() << " failed No check pt file(" << invokeServer.ecf_checkpt_file() << ") saved");
+ BOOST_REQUIRE_MESSAGE(fs::file_size(invokeServer.ecf_checkpt_file()) !=0,"Expected check point file(" << invokeServer.ecf_checkpt_file() << ") to have file size > 0 ");
+ BOOST_REQUIRE_MESSAGE(fs::exists(invokeServer.ecf_backup_checkpt_file()), "Expected backup check point file(" << invokeServer.ecf_backup_checkpt_file() << ") to be created");
+ BOOST_REQUIRE_MESSAGE(fs::file_size(invokeServer.ecf_backup_checkpt_file()) !=0,"Expected backup check point file(" << invokeServer.ecf_backup_checkpt_file() << "), to have file size > 0");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/Client/test/TestSinglePerf.cpp b/Client/test/TestSinglePerf.cpp
new file mode 100644
index 0000000..0d1fc9b
--- /dev/null
+++ b/Client/test/TestSinglePerf.cpp
@@ -0,0 +1,271 @@
+#define BOOST_TEST_MODULE TestSingle
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #11 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <fstream>
+
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/timer.hpp>
+
+#include "ClientInvoker.hpp"
+#include "ClientEnvironment.hpp"
+#include "File.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Task.hpp"
+#include "TestHelper.hpp"
+#include "InvokeServer.hpp"
+#include "SCPort.hpp"
+#include "Str.hpp"
+#include "Host.hpp"
+#include "Rtt.hpp"
+#include "DurationTimer.hpp"
+
+namespace fs = boost::filesystem;
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( ClientTestSuite )
+
+// ************************************************************************************
+// Note: If you make edits to node tree, they will have no effect until the server is rebuilt
+// ************************************************************************************
+
+static void sync_and_news_local(ClientInvoker& theClient)
+{
+ {
+ cout << " news_local() : ";
+ DurationTimer duration_timer;
+ theClient.news_local();
+ cout << (double)duration_timer.elapsed().total_milliseconds()/(double)1000;
+ }
+ {
+ cout << " sync_local() : ";
+ DurationTimer duration_timer;
+ theClient.sync_local();
+ cout << (double)duration_timer.elapsed().total_milliseconds()/(double)1000 << endl;
+ }
+}
+
+void time_load_and_downloads(
+ ClientInvoker& theClient,
+ const std::string& host,
+ const std::string& port,
+ const std::string& directory
+)
+{
+ fs::path full_path( fs::initial_path<fs::path>() );
+ full_path = fs::system_complete( fs::path( directory ) );
+
+ BOOST_CHECK(fs::exists( full_path ));
+ BOOST_CHECK(fs::is_directory( full_path ));
+
+ int count = 10;
+
+ //std::cout << "\nIn directory: " << full_path.directory_string() << "\n\n";
+ fs::directory_iterator end_iter;
+ for ( fs::directory_iterator dir_itr( full_path ); dir_itr != end_iter; ++dir_itr )
+ {
+ try
+ {
+ fs::path relPath(directory + "/" + dir_itr->path().filename().string());
+
+ // recurse down directories
+ if ( is_directory(dir_itr->status()) ) {
+ time_load_and_downloads(theClient,host,port,relPath.string());
+ continue;
+ }
+
+ cout << "\n" << relPath.string() << " : file size " << fs::file_size(relPath) << endl;
+ {
+ DurationTimer duration_timer;
+ BOOST_REQUIRE_MESSAGE(theClient.loadDefs(relPath.string()) == 0,"load defs failed \n" << theClient.errorMsg());
+ cout << " Load: " << duration_timer.elapsed().total_milliseconds() << "ms" << endl;
+ }
+ {
+ DurationTimer duration_timer;
+ BOOST_REQUIRE_MESSAGE(theClient.begin_all_suites() == 0,"begin failed \n" << theClient.errorMsg());
+ cout << " Begin: " << duration_timer.elapsed().total_milliseconds() << "ms" << endl;
+ }
+ {
+ cout << " Download(Sync): "; cout.flush();
+ for(int i = 0; i < count; i++) {
+ DurationTimer duration_timer;
+ theClient.sync_local();
+ int seconds = duration_timer.elapsed().total_milliseconds();
+ cout << seconds << " ";
+ }
+ cout << ":(milli-seconds) sync_local() with the same Client. First call updates cache." << endl;
+ }
+ {
+ // On construction of Defs, hence should be slightly faster
+ cout << " Download(Sync-FULL): "; cout.flush();
+ double total = 0;
+ for(int i = 0; i < count; i++) {
+ ClientInvoker client(host,port);
+ DurationTimer duration_timer;
+ client.sync_local();
+ int seconds = duration_timer.elapsed().total_milliseconds();
+ cout << seconds << " ";
+ total += seconds;
+ }
+ cout << ": Avg:" << (double)(total)/((double)count*1000) << "(sec) : sync_local() with *different* clients. Uses Cache" << endl;
+ }
+ {
+ // This should more expensive on second call, due to destruction of
+ // defs(on theClient) from previous calls
+ cout << " Download(FULL): "; cout.flush();
+ double total = 0;
+ for(int i = 0; i < count; i++) {
+ DurationTimer duration_timer;
+ theClient.getDefs();
+ int seconds = duration_timer.elapsed().total_milliseconds();
+ cout << seconds << " ";
+ total += seconds;
+ }
+ cout << ": Avg:" << (double)(total)/((double)count*1000) << "(sec) : get_defs() from same client" << endl;
+ }
+ {
+ std::vector<task_ptr> all_tasks;
+ theClient.defs()->get_all_tasks(all_tasks);
+ std::vector<std::string> paths;paths.reserve(all_tasks.size());
+ for(size_t i = 0; i < all_tasks.size(); i++) {
+ paths.push_back(all_tasks[i]->absNodePath());
+ if (i == 6000) break; // > 9000 really slows down, could be logging ??
+ }
+ {
+ cout << " Suspend " << paths.size() << " tasks : "; cout.flush();
+ DurationTimer duration_timer;
+ theClient.suspend(paths);
+ cout << (double)duration_timer.elapsed().total_milliseconds()/(double)1000;
+ }
+ sync_and_news_local(theClient);
+ {
+ cout << " Resume " << paths.size() << " tasks : "; cout.flush();
+ DurationTimer duration_timer;
+ theClient.resume(paths);
+ cout << (double)duration_timer.elapsed().total_milliseconds()/(double)1000;
+ }
+ sync_and_news_local(theClient);
+ {
+ cout << " force " << paths.size() << " tasks : "; cout.flush();
+ DurationTimer duration_timer;
+ theClient.force(paths,"complete");
+ cout << (double)duration_timer.elapsed().total_milliseconds()/(double)1000;
+ }
+ sync_and_news_local(theClient);
+ }
+ {
+ // This should more expensive on second call, due to destruction of
+ // defs(on theClient) from previous calls
+ cout << " Check pt: "; cout.flush();
+ double total = 0;
+ for(int i = 0; i < count; i++) {
+ DurationTimer duration_timer;
+ theClient.checkPtDefs();
+ int seconds = duration_timer.elapsed().total_milliseconds();
+ cout << seconds << " "; cout.flush();
+ total += seconds;
+ }
+ cout << ": Avg:" << (double)(total)/((double)count*1000) << "ms" << endl;
+ }
+ {
+ DurationTimer duration_timer;
+ BOOST_REQUIRE_MESSAGE(theClient.delete_all(true) == 0,"delete all defs failed \n" << theClient.errorMsg());
+ cout << " Delete: " << duration_timer.elapsed().total_milliseconds() << "ms" << endl;
+ }
+ }
+ catch ( const std::exception & ex ) {
+ std::cout << dir_itr->path().filename() << " " << ex.what() << std::endl;
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_perf_for_large_defs )
+{
+ if (fs::exists("/var/tmp/ma0/BIG_DEFS")) {
+ /// This will remove checkpt and backup , to avoid server from loading it. (i.e from previous test)
+ InvokeServer invokeServer("Client:: ...test_perf_for_large_defs:",SCPort::next());
+
+ ClientInvoker theClient(invokeServer.host(), invokeServer.port());
+ time_load_and_downloads(theClient,invokeServer.host(), invokeServer.port(),"/var/tmp/ma0/BIG_DEFS");
+ }
+ else {
+ std::cout << "Ingoring test, since directory /var/tmp/ma0/BIG_DEFS does not exist";
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+// Sept 2015, desktop
+
+//^Ceurydice{/var/tmp/ma0/workspace/ecflow}:191 --> Client/bin/gcc-4.8/release/perf_test_large_defs
+//Running 1 test case...
+//Client:: ...test_perf_for_large_defs: port(3146)
+//
+///var/tmp/ma0/BIG_DEFS/od.def : file size 11081032
+//Warning: TASK /lbc/perle/local/perle has a inlimit ../process:excl :The referenced FAMILY '/lbc/perle/process' does not define the limit excl
+//
+// Load: 1364ms
+// Begin: 239ms
+// Download(Sync): 791 4 0 0 0 0 0 0 0 0 :(milli-seconds) sync_local() with the same Client. First call updates cache.
+// Download(Sync-FULL): 451 453 456 455 457 456 456 457 456 455 : Avg:0.4552(sec) : sync_local() with *different* clients. Uses Cache
+// Download(FULL): 802 813 835 855 880 891 900 910 923 934 : Avg:0.8743(sec) : get_defs() from same client
+// Suspend 6001 tasks : 0.027 news_local() : 0 sync_local() : 0.075
+// Resume 6001 tasks : 0.027 news_local() : 0 sync_local() : 0.053
+// force 6001 tasks : 0.073 news_local() : 0 sync_local() : 0.108
+// Check pt: 334 334 339 338 338 338 339 338 338 338 : Avg:0.3374ms
+// Delete: 98ms
+//
+///var/tmp/ma0/BIG_DEFS/vsms2.31415.def : file size 153539843
+// Load: 8720ms
+// Begin: 591ms
+// Download(Sync): 5323 0 0 0 0 0 0 0 0 0 :(milli-seconds) sync_local() with the same Client. First call updates cache.
+// Download(Sync-FULL): 3208 3181 3181 3193 3199 3197 3200 3209 3199 3202 : Avg:3.1969(sec) : sync_local() with *different* clients. Uses Cache
+// Download(FULL): 5456 5911 5916 5995 6315 6458 6696 6658 6811 6903 : Avg:6.3119(sec) : get_defs() from same client
+// Suspend 6001 tasks : 0.045 news_local() : 0 sync_local() : 0.113
+// Resume 6001 tasks : 0.044 news_local() : 0 sync_local() : 0.081
+// force 6001 tasks : 0.076 news_local() : 0 sync_local() : 0.12
+// Check pt: 2327 2342 2341 2343 2351 2340 2344 2350 2346 2376 : Avg:2.346ms
+// Delete: 1486ms
+//
+///var/tmp/ma0/BIG_DEFS/3199.def : file size 59631577
+// Load: 5290ms
+// Begin: 1577ms
+// Download(Sync): 3797 23 0 0 0 0 0 0 0 0 :(milli-seconds) sync_local() with the same Client. First call updates cache.
+// Download(Sync-FULL): 2157 2170 2153 2337 2446 2156 2565 2223 2165 2163 : Avg:2.2535(sec) : sync_local() with *different* clients. Uses Cache
+// Download(FULL): 3841 4143 4018 4473 4336 4406 4813 4856 5029 4508 : Avg:4.4423(sec) : get_defs() from same client
+// Suspend 6001 tasks : 0.061 news_local() : 0 sync_local() : 0.095
+// Resume 6001 tasks : 0.046 news_local() : 0 sync_local() : 0.066
+// force 6001 tasks : 0.126 news_local() : 0 sync_local() : 0.239
+// Check pt: 1616 1614 1606 1603 1604 1606 1602 1602 1603 1600 : Avg:1.6056ms
+// Delete: 991ms
+//
+///var/tmp/ma0/BIG_DEFS/mega.def : file size 6723372
+// Load: 835ms
+// Begin: 117ms
+// Download(Sync): 552 1 0 0 0 0 0 0 0 0 :(milli-seconds) sync_local() with the same Client. First call updates cache.
+// Download(Sync-FULL): 280 281 277 283 280 284 279 283 279 283 : Avg:0.2809(sec) : sync_local() with *different* clients. Uses Cache
+// Download(FULL): 547 556 564 577 585 588 599 602 609 610 : Avg:0.5837(sec) : get_defs() from same client
+// Suspend 6001 tasks : 0.035 news_local() : 0 sync_local() : 0.085
+// Resume 6001 tasks : 0.031 news_local() : 0 sync_local() : 0.06
+// force 6001 tasks : 0.104 news_local() : 0 sync_local() : 0.553
+// Check pt: 255 250 242 242 243 242 242 244 244 241 : Avg:0.2445ms
+// Delete: 105ms
+//
+//*** No errors detected
+//eurydice{/var/tmp/ma0/workspace/ecflow}:192 -->
+
diff --git a/Client/test/TestUrlCmd.cpp b/Client/test/TestUrlCmd.cpp
new file mode 100644
index 0000000..7c19efc
--- /dev/null
+++ b/Client/test/TestUrlCmd.cpp
@@ -0,0 +1,65 @@
+//============================================================================
+// Name : Request
+// Author : Avi
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <string>
+#include <iostream>
+#include <fstream>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/test/unit_test.hpp>
+
+#include "DefsStructureParser.hpp"
+#include "Defs.hpp"
+#include "UrlCmd.hpp"
+#include "File.hpp"
+
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( ClientTestSuite )
+
+//=============================================================================
+// This will test the UrlCmd.
+BOOST_AUTO_TEST_CASE( test_url_cmd )
+{
+ cout << "Client:: ...test_url_cmd" << endl;
+
+ std::string path = File::test_data("Client/test/data/lifecycle.txt","Client");
+
+ defs_ptr defs = Defs::create();
+
+ DefsStructureParser checkPtParser( defs.get(), path );
+ std::string errorMsg,warningMsg;
+ bool parse = checkPtParser.doParse(errorMsg,warningMsg);
+ BOOST_CHECK_MESSAGE(parse,errorMsg);
+
+ // Check error conditions
+ BOOST_REQUIRE_THROW(UrlCmd(defs,"a made up name"), std::runtime_error );
+ BOOST_REQUIRE_THROW(UrlCmd(defs_ptr(),"/suite1/family1/a"), std::runtime_error );
+
+ // The Url command relies on variable substitution, hence we must ensure that
+ // generated variables are created.
+ defs->beginAll();
+
+ UrlCmd urlCmd(defs,"/suite1/family1/a");
+ std::string expected = "${BROWSER:=firefox} -remote 'openURL(http://www.ecmwf.int/publications/manuals/sms)'";
+ std::string actual = urlCmd.getUrl();
+ BOOST_CHECK_MESSAGE( expected == actual,"Expected '" << expected << "' but found " << actual);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+
diff --git a/Client/test/TestWhiteListFile.cpp b/Client/test/TestWhiteListFile.cpp
new file mode 100644
index 0000000..8480bb6
--- /dev/null
+++ b/Client/test/TestWhiteListFile.cpp
@@ -0,0 +1,93 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <boost/test/unit_test.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+
+#include "ClientInvoker.hpp"
+#include "ClientEnvironment.hpp"
+#include "WhiteListFile.hpp"
+#include "InvokeServer.hpp"
+#include "SCPort.hpp"
+#include "Str.hpp"
+
+namespace fs = boost::filesystem;
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( ClientTestSuite )
+
+// ************************************************************************************
+// Note: If you make edits to node tree, they will have no effect until the server is rebuilt
+//
+// Note: To test HPUX->Linux, invoke serve on (Linux/HPUX) and the client cmds on other system
+// On the client side set ECF_NODE to machine name. To allow further testing if ECF_NODE
+// is specified then *don't* shutdown the server
+// ************************************************************************************
+
+BOOST_AUTO_TEST_CASE( test_loading_of_white_list_file )
+{
+ Host the_host;
+ std::string port = SCPort::next();
+ std::string host = ClientEnvironment::hostSpecified();
+ if (host.empty()) {
+
+ // make sure NO whitelist file is present before the server is started.
+ // This allows any user to send requests to the server
+ // Only do this locally, as white list file on remote machine may not be accessible
+ fs::remove(the_host.ecf_lists_file(port));
+ }
+
+ // This will remove check pt and backup file before server start, to avoid the server from loading previous test data
+ InvokeServer invokeServer("Client:: ...test_loading_of_white_list_file",port);
+
+ ClientInvoker theClient(invokeServer.host(),invokeServer.port());
+ BOOST_REQUIRE_MESSAGE( theClient.delete_all() == 0,CtsApi::to_string(CtsApi::delete_node()) << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.shutdownServer() == 0,CtsApi::shutdownServer() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.haltServer() == 0,CtsApi::haltServer() << " should return 0\n" << theClient.errorMsg());
+ BOOST_REQUIRE_MESSAGE( theClient.restartServer() == 0,CtsApi::restartServer() << " should return 0\n" << theClient.errorMsg());
+
+ // OK now test white list file functionality, but only if server was invoked locally
+ if ( host.empty() ) {
+
+ // The white list file should not exist, hence reload white list SHOULD fail.
+ // i.e because we deleted it earlier
+ BOOST_REQUIRE_THROW( theClient.reloadwsfile(), std::runtime_error);
+
+ // Create a valid white list file; For the FIRST time:
+ // **** IMPORTANT: if we had reloaded a white list file where the user has read access
+ // **************: _FIRST_ it will not be possible reload white file with write access, afterwards
+ // **************: since subsequent RELOAD command itself will require write access
+ std::string errorMsg;
+ BOOST_REQUIRE_MESSAGE(WhiteListFile::createWithWriteAccess(the_host.ecf_lists_file(port),errorMsg),errorMsg);
+
+ // Reload should pass, as its the _first_ time
+ BOOST_REQUIRE_MESSAGE( theClient.reloadwsfile() == 0, CtsApi::reloadwsfile() << " should return 0\n" << theClient.errorMsg());
+
+ // Invoking a client request that requires write access, should pass
+ BOOST_CHECK_MESSAGE( theClient.shutdownServer() == 0,"should return 0\n" << theClient.errorMsg());
+
+ // Invoking a client request that requires read access, should also pass
+ BOOST_CHECK_MESSAGE( theClient.getDefs() == 0,"should return 0\n" << theClient.errorMsg());
+ BOOST_CHECK_MESSAGE( theClient.sync_local() == 0,"should return 0\n" << theClient.errorMsg());
+ BOOST_CHECK_MESSAGE( theClient.news_local() == 0,"should return 0\n" << theClient.errorMsg());
+
+ // Remove the white list file. Comment out for debug
+ fs::remove(the_host.ecf_lists_file(port));
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/ecflow_4_0_7/Client/test/data/ECF_HOME/includes/head.h b/Client/test/data/ECF_HOME/includes/head.h
similarity index 100%
rename from ecflow_4_0_7/Client/test/data/ECF_HOME/includes/head.h
rename to Client/test/data/ECF_HOME/includes/head.h
diff --git a/ecflow_4_0_7/Client/test/data/ECF_HOME/includes/tail.h b/Client/test/data/ECF_HOME/includes/tail.h
similarity index 100%
rename from ecflow_4_0_7/Client/test/data/ECF_HOME/includes/tail.h
rename to Client/test/data/ECF_HOME/includes/tail.h
diff --git a/ecflow_4_0_7/Client/test/data/ECF_HOME/suite/family/head.h b/Client/test/data/ECF_HOME/suite/family/head.h
similarity index 100%
rename from ecflow_4_0_7/Client/test/data/ECF_HOME/suite/family/head.h
rename to Client/test/data/ECF_HOME/suite/family/head.h
diff --git a/ecflow_4_0_7/Client/test/data/ECF_HOME/suite/family/t1.ecf b/Client/test/data/ECF_HOME/suite/family/t1.ecf
similarity index 100%
rename from ecflow_4_0_7/Client/test/data/ECF_HOME/suite/family/t1.ecf
rename to Client/test/data/ECF_HOME/suite/family/t1.ecf
diff --git a/ecflow_4_0_7/Client/test/data/ECF_HOME/suite/family/t2.ecf b/Client/test/data/ECF_HOME/suite/family/t2.ecf
similarity index 100%
rename from ecflow_4_0_7/Client/test/data/ECF_HOME/suite/family/t2.ecf
rename to Client/test/data/ECF_HOME/suite/family/t2.ecf
diff --git a/ecflow_4_0_7/Client/test/data/ECF_HOME/suite/family/t3.ecf b/Client/test/data/ECF_HOME/suite/family/t3.ecf
similarity index 100%
rename from ecflow_4_0_7/Client/test/data/ECF_HOME/suite/family/t3.ecf
rename to Client/test/data/ECF_HOME/suite/family/t3.ecf
diff --git a/ecflow_4_0_7/Client/test/data/ECF_HOME/suite/family/tail.h b/Client/test/data/ECF_HOME/suite/family/tail.h
similarity index 100%
rename from ecflow_4_0_7/Client/test/data/ECF_HOME/suite/family/tail.h
rename to Client/test/data/ECF_HOME/suite/family/tail.h
diff --git a/ecflow_4_0_7/Client/test/data/bad.def b/Client/test/data/bad.def
similarity index 100%
rename from ecflow_4_0_7/Client/test/data/bad.def
rename to Client/test/data/bad.def
diff --git a/ecflow_4_0_7/Client/test/data/first.def b/Client/test/data/first.def
similarity index 100%
rename from ecflow_4_0_7/Client/test/data/first.def
rename to Client/test/data/first.def
diff --git a/ecflow_4_0_7/Client/test/data/good_hostfile b/Client/test/data/good_hostfile
similarity index 100%
rename from ecflow_4_0_7/Client/test/data/good_hostfile
rename to Client/test/data/good_hostfile
diff --git a/ecflow_4_0_7/Client/test/data/jobgenonly.def b/Client/test/data/jobgenonly.def
similarity index 100%
rename from ecflow_4_0_7/Client/test/data/jobgenonly.def
rename to Client/test/data/jobgenonly.def
diff --git a/ecflow_4_0_7/Client/test/data/lifecycle.txt b/Client/test/data/lifecycle.txt
similarity index 100%
rename from ecflow_4_0_7/Client/test/data/lifecycle.txt
rename to Client/test/data/lifecycle.txt
diff --git a/Client/test/data/ref_analysis.dat b/Client/test/data/ref_analysis.dat
new file mode 100644
index 0000000..e75eea0
--- /dev/null
+++ b/Client/test/data/ref_analysis.dat
@@ -0,0 +1,33 @@
+Command count min average max std
+localhost:3141 --begin 49 562 1530 6932 1146
+localhost:3141 --ch_add 1 514
+localhost:3141 --ch_drop 8 472 491 513 12
+localhost:3141 --ch_register 9 503 533 578 22
+localhost:3141 --ch_rem 1 511
+localhost:3141 --ch_suites 11 486 538 601 37
+localhost:3141 --check_pt 3 689 854 1161 216
+localhost:3141 --delete 56 516 756 1000 133
+localhost:3141 --file 25 575 875 1013 94
+localhost:3141 --force 4 544 554 572 10
+localhost:3141 --get 83 889 2256 3926 519
+localhost:3141 --halt 1 691
+localhost:3141 --kill 2 1051 1062 1073 11
+localhost:3141 --load 50 1462 2566 7291 1103
+localhost:3141 --log 98 510 733 950 106
+localhost:3141 --news 60 481 982 1537 196
+localhost:3141 --order 33 502 549 795 82
+localhost:3141 --ping 1 1594
+localhost:3141 --requeue 1 2281
+localhost:3141 --restart 50 483 676 2204 246
+localhost:3141 --restore_from_checkpt 3 716 888 1208 226
+localhost:3141 --resume 1 2183
+localhost:3141 --shutdown 1 680
+localhost:3141 --stats 1 989
+localhost:3141 --suites 2 492 622 752 130
+localhost:3141 --suspend 2 511 517 524 6
+localhost:3141 --sync 103 520 1610 4363 671
+localhost:3141 --sync_full 25 1155 2085 6717 1152
+localhost:3141 --terminate 1 1247
+localhost:3141 --zombie_get 68 484 729 917 105
+
+total round trip time 00:00:00.942435 for 753 requests
diff --git a/Client/test/data/rtt.dat b/Client/test/data/rtt.dat
new file mode 100644
index 0000000..5aebe16
--- /dev/null
+++ b/Client/test/data/rtt.dat
@@ -0,0 +1,753 @@
+localhost:3141 --ping :ma0 rtt:00:00:00.001594
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000818
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_repeat_integer/test_repeat_integer.def_log :ma0 rtt:00:00:00.000851
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000761
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000780
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_repeat_integer/test_repeat_integer.def :ma0 rtt:00:00:00.002748
+localhost:3141 --restart :ma0 rtt:00:00:00.000755
+localhost:3141 --begin=test_repeat_integer :ma0 rtt:00:00:00.002220
+localhost:3141 --get :ma0 rtt:00:00:00.002406
+localhost:3141 --news=0 140 1 :ma0 rtt:00:00:00.001107
+localhost:3141 --sync=0 140 1 :ma0 rtt:00:00:00.002342
+localhost:3141 --get :ma0 rtt:00:00:00.002121
+localhost:3141 --news=0 271 2 :ma0 rtt:00:00:00.001044
+localhost:3141 --sync=0 140 1 :ma0 rtt:00:00:00.002141
+localhost:3141 --get :ma0 rtt:00:00:00.001929
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000723
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000725
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_repeat_date/test_repeat_date.def_log :ma0 rtt:00:00:00.000769
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000772
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000823
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_repeat_date/test_repeat_date.def :ma0 rtt:00:00:00.002388
+localhost:3141 --restart :ma0 rtt:00:00:00.000733
+localhost:3141 --begin=test_repeat_date :ma0 rtt:00:00:00.002114
+localhost:3141 --get :ma0 rtt:00:00:00.002349
+localhost:3141 --news=0 451 6 :ma0 rtt:00:00:00.000838
+localhost:3141 --sync=0 451 6 :ma0 rtt:00:00:00.001649
+localhost:3141 --get :ma0 rtt:00:00:00.001388
+localhost:3141 --news=0 591 6 :ma0 rtt:00:00:00.001537
+localhost:3141 --sync=0 591 6 :ma0 rtt:00:00:00.002285
+localhost:3141 --get :ma0 rtt:00:00:00.002288
+localhost:3141 --news=0 661 6 :ma0 rtt:00:00:00.001085
+localhost:3141 --sync=0 661 6 :ma0 rtt:00:00:00.002283
+localhost:3141 --get :ma0 rtt:00:00:00.002007
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000829
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000724
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_repeat_enumerator/test_repeat_enumerator.def_log :ma0 rtt:00:00:00.000778
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000785
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000823
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_repeat_enumerator/test_repeat_enumerator.def :ma0 rtt:00:00:00.002341
+localhost:3141 --restart :ma0 rtt:00:00:00.000717
+localhost:3141 --begin=test_repeat_enumerator :ma0 rtt:00:00:00.001677
+localhost:3141 --get :ma0 rtt:00:00:00.002288
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000807
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000725
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_repeat_defstatus/test_repeat_defstatus.def_log :ma0 rtt:00:00:00.000795
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000744
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000811
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_repeat_defstatus/test_repeat_defstatus.def :ma0 rtt:00:00:00.002400
+localhost:3141 --restart :ma0 rtt:00:00:00.000700
+localhost:3141 --begin=test_repeat_defstatus :ma0 rtt:00:00:00.000835
+localhost:3141 --get :ma0 rtt:00:00:00.002359
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000810
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000707
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_handle/test_handle.def_log :ma0 rtt:00:00:00.000799
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000787
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000807
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_handle/test_handle.def :ma0 rtt:00:00:00.004505
+localhost:3141 --restart :ma0 rtt:00:00:00.000501
+localhost:3141 --begin :ma0 rtt:00:00:00.000770
+localhost:3141 --ch_register=false s0 s1 s2 :ma0 rtt:00:00:00.000555
+localhost:3141 --sync_full=1 :ma0 rtt:00:00:00.001948
+localhost:3141 --ch_suites :ma0 rtt:00:00:00.000586
+localhost:3141 --ch_drop=1 :ma0 rtt:00:00:00.000495
+localhost:3141 --ch_suites :ma0 rtt:00:00:00.000486
+localhost:3141 --ch_register=false s0 s1 s2 :ma0 rtt:00:00:00.000532
+localhost:3141 --sync=1 1006 32 :ma0 rtt:00:00:00.001916
+localhost:3141 --ch_add=1 s3 s4 :ma0 rtt:00:00:00.000514
+localhost:3141 --ch_suites :ma0 rtt:00:00:00.000564
+localhost:3141 --sync=1 1006 32 :ma0 rtt:00:00:00.002695
+localhost:3141 --ch_rem=1 s3 s4 :ma0 rtt:00:00:00.000511
+localhost:3141 --ch_suites :ma0 rtt:00:00:00.000552
+localhost:3141 --sync=1 1006 34 :ma0 rtt:00:00:00.001899
+localhost:3141 --ch_drop=1 :ma0 rtt:00:00:00.000486
+localhost:3141 --ch_suites :ma0 rtt:00:00:00.000503
+localhost:3141 --ch_register=false s0 s1 s2 :ma0 rtt:00:00:00.000506
+localhost:3141 --ch_register=false s3 s4 :ma0 rtt:00:00:00.000537
+localhost:3141 --ch_suites :ma0 rtt:00:00:00.000549
+localhost:3141 --ch_drop=1 :ma0 rtt:00:00:00.000502
+localhost:3141 --ch_drop=2 :ma0 rtt:00:00:00.000472
+localhost:3141 --ch_suites :ma0 rtt:00:00:00.000498
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000561
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000552
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_handle_sync/test_handle_sync.def_log :ma0 rtt:00:00:00.000546
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000528
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000582
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_handle_sync/test_handle_sync.def :ma0 rtt:00:00:00.003888
+localhost:3141 --restart :ma0 rtt:00:00:00.000484
+localhost:3141 --begin :ma0 rtt:00:00:00.000720
+localhost:3141 --ch_register=false s0 s1 s2 :ma0 rtt:00:00:00.000540
+localhost:3141 --news=1 0 0 :ma0 rtt:00:00:00.000496
+localhost:3141 --sync_full=1 :ma0 rtt:00:00:00.001951
+localhost:3141 --suspend /s3 :ma0 rtt:00:00:00.000524
+localhost:3141 --news=1 1126 54 :ma0 rtt:00:00:00.000481
+localhost:3141 --force=complete /s3 :ma0 rtt:00:00:00.000553
+localhost:3141 --news=1 1126 54 :ma0 rtt:00:00:00.000481
+localhost:3141 --sync=1 1126 54 :ma0 rtt:00:00:00.000631
+localhost:3141 --force=complete /s0 :ma0 rtt:00:00:00.000549
+localhost:3141 --news=1 1136 54 :ma0 rtt:00:00:00.000493
+localhost:3141 --sync=1 1136 54 :ma0 rtt:00:00:00.000898
+localhost:3141 --ch_drop=1 :ma0 rtt:00:00:00.000498
+localhost:3141 --ch_register=false s0 s1 s2 :ma0 rtt:00:00:00.000515
+localhost:3141 --news=1 1146 54 :ma0 rtt:00:00:00.000499
+localhost:3141 --sync=1 1146 54 :ma0 rtt:00:00:00.001963
+localhost:3141 --force=complete /s1 :ma0 rtt:00:00:00.000544
+localhost:3141 --sync=1 1146 54 :ma0 rtt:00:00:00.000894
+localhost:3141 --order=/s0 alpha :ma0 rtt:00:00:00.000539
+localhost:3141 --sync=1 1155 54 :ma0 rtt:00:00:00.000874
+localhost:3141 --ch_drop=1 :ma0 rtt:00:00:00.000481
+localhost:3141 --suites :ma0 rtt:00:00:00.000492
+localhost:3141 --ch_register=false s0 s1 s2 :ma0 rtt:00:00:00.000503
+localhost:3141 --news=1 1157 54 :ma0 rtt:00:00:00.000496
+localhost:3141 --sync=1 1157 54 :ma0 rtt:00:00:00.001895
+localhost:3141 --force=unknown /s1 :ma0 rtt:00:00:00.000572
+localhost:3141 --sync=1 1157 54 :ma0 rtt:00:00:00.000892
+localhost:3141 --delete force yes /s2 :ma0 rtt:00:00:00.000524
+localhost:3141 --news=1 1166 54 :ma0 rtt:00:00:00.000482
+localhost:3141 --sync=1 1166 54 :ma0 rtt:00:00:00.001520
+localhost:3141 --ch_suites :ma0 rtt:00:00:00.000601
+localhost:3141 --ch_drop=1 :ma0 rtt:00:00:00.000513
+localhost:3141 --ch_suites :ma0 rtt:00:00:00.000490
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000495
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000484
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_handle_sync/test_handle_sync.def_log :ma0 rtt:00:00:00.000544
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000523
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000557
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_handle_sync/test_handle_sync.def :ma0 rtt:00:00:00.002196
+localhost:3141 --restart :ma0 rtt:00:00:00.000498
+localhost:3141 --begin :ma0 rtt:00:00:00.000596
+localhost:3141 --ch_register=false s0 s1 s2 :ma0 rtt:00:00:00.000534
+localhost:3141 --ch_suites :ma0 rtt:00:00:00.000550
+localhost:3141 --sync_full=1 :ma0 rtt:00:00:00.001931
+localhost:3141 --delete yes /s0 :ma0 rtt:00:00:00.000535
+localhost:3141 --delete yes /s1 :ma0 rtt:00:00:00.000519
+localhost:3141 --delete yes /s2 :ma0 rtt:00:00:00.000516
+localhost:3141 --sync=1 1224 69 :ma0 rtt:00:00:00.000834
+localhost:3141 --ch_suites :ma0 rtt:00:00:00.000541
+localhost:3141 --load=<in-memory-defs> :ma0 rtt:00:00:00.001792
+localhost:3141 --sync=1 1230 72 :ma0 rtt:00:00:00.001890
+localhost:3141 --ch_drop=1 :ma0 rtt:00:00:00.000481
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000486
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000485
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_reque/test_reque.def_log :ma0 rtt:00:00:00.000535
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000516
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000546
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_reque/test_reque.def :ma0 rtt:00:00:00.001593
+localhost:3141 --restart :ma0 rtt:00:00:00.000496
+localhost:3141 --begin=test_reque :ma0 rtt:00:00:00.001472
+localhost:3141 --get :ma0 rtt:00:00:00.002323
+localhost:3141 --news=0 1412 83 :ma0 rtt:00:00:00.000997
+localhost:3141 --sync=0 1412 83 :ma0 rtt:00:00:00.002161
+localhost:3141 --get :ma0 rtt:00:00:00.002035
+localhost:3141 --news=0 1520 83 :ma0 rtt:00:00:00.001032
+localhost:3141 --sync=0 1520 83 :ma0 rtt:00:00:00.002325
+localhost:3141 --get :ma0 rtt:00:00:00.002004
+localhost:3141 --requeue /test_reque :ma0 rtt:00:00:00.002281
+localhost:3141 --get :ma0 rtt:00:00:00.002302
+localhost:3141 --news=0 1714 85 :ma0 rtt:00:00:00.000983
+localhost:3141 --sync=0 1714 85 :ma0 rtt:00:00:00.002194
+localhost:3141 --get :ma0 rtt:00:00:00.002009
+localhost:3141 --news=0 1822 85 :ma0 rtt:00:00:00.001008
+localhost:3141 --sync=0 1822 85 :ma0 rtt:00:00:00.002332
+localhost:3141 --get :ma0 rtt:00:00:00.002077
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000764
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000729
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_kill_cmd/test_kill_cmd.def_log :ma0 rtt:00:00:00.000776
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000759
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000807
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_kill_cmd/test_kill_cmd.def :ma0 rtt:00:00:00.001838
+localhost:3141 --restart :ma0 rtt:00:00:00.000500
+localhost:3141 --begin=test_kill_task :ma0 rtt:00:00:00.001078
+localhost:3141 --sync_full=0 :ma0 rtt:00:00:00.001403
+localhost:3141 --sync=0 1884 89 :ma0 rtt:00:00:00.002116
+localhost:3141 --kill /test_kill_task/family/t0 :ma0 rtt:00:00:00.001073
+localhost:3141 --sync=0 1897 89 :ma0 rtt:00:00:00.001359
+localhost:3141 --sync=0 1899 89 :ma0 rtt:00:00:00.002039
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000814
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000712
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_kill_cmd/test_kill_cmd.def_log :ma0 rtt:00:00:00.000781
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000753
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000854
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_kill_cmd/test_kill_cmd.def :ma0 rtt:00:00:00.002131
+localhost:3141 --restart :ma0 rtt:00:00:00.000726
+localhost:3141 --begin=test_kill_suite :ma0 rtt:00:00:00.001499
+localhost:3141 --sync_full=0 :ma0 rtt:00:00:00.001974
+localhost:3141 --sync=0 1944 93 :ma0 rtt:00:00:00.002119
+localhost:3141 --kill /test_kill_suite :ma0 rtt:00:00:00.001051
+localhost:3141 --sync=0 1957 93 :ma0 rtt:00:00:00.001405
+localhost:3141 --sync=0 1959 93 :ma0 rtt:00:00:00.002062
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000766
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000713
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_change_order/test_change_order.def_log :ma0 rtt:00:00:00.000826
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000836
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000820
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_change_order/test_change_order.def :ma0 rtt:00:00:00.005046
+localhost:3141 --restart :ma0 rtt:00:00:00.000489
+localhost:3141 --begin :ma0 rtt:00:00:00.000771
+localhost:3141 --sync_full=0 :ma0 rtt:00:00:00.004407
+localhost:3141 --order=/a order :ma0 rtt:00:00:00.000540
+localhost:3141 --sync=0 2163 103 :ma0 rtt:00:00:00.000903
+localhost:3141 --order=/a alpha :ma0 rtt:00:00:00.000509
+localhost:3141 --sync=0 2165 103 :ma0 rtt:00:00:00.000844
+localhost:3141 --order=/a bottom :ma0 rtt:00:00:00.000504
+localhost:3141 --sync=0 2167 103 :ma0 rtt:00:00:00.000845
+localhost:3141 --order=/a alpha :ma0 rtt:00:00:00.000531
+localhost:3141 --order=/a down :ma0 rtt:00:00:00.000502
+localhost:3141 --sync=0 2169 103 :ma0 rtt:00:00:00.000857
+localhost:3141 --order=/a alpha :ma0 rtt:00:00:00.000515
+localhost:3141 --order=/c up :ma0 rtt:00:00:00.000506
+localhost:3141 --sync=0 2173 103 :ma0 rtt:00:00:00.001106
+localhost:3141 --order=/a/a order :ma0 rtt:00:00:00.000532
+localhost:3141 --sync=0 2177 103 :ma0 rtt:00:00:00.000849
+localhost:3141 --order=/a/a alpha :ma0 rtt:00:00:00.000506
+localhost:3141 --sync=0 2179 103 :ma0 rtt:00:00:00.000846
+localhost:3141 --order=/a/a bottom :ma0 rtt:00:00:00.000532
+localhost:3141 --sync=0 2181 103 :ma0 rtt:00:00:00.000841
+localhost:3141 --order=/a/a alpha :ma0 rtt:00:00:00.000505
+localhost:3141 --order=/a/a down :ma0 rtt:00:00:00.000524
+localhost:3141 --sync=0 2183 103 :ma0 rtt:00:00:00.000927
+localhost:3141 --order=/a/a alpha :ma0 rtt:00:00:00.000513
+localhost:3141 --order=/a/c up :ma0 rtt:00:00:00.000508
+localhost:3141 --sync=0 2187 103 :ma0 rtt:00:00:00.000918
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000506
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000497
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_change_order/test_change_order.def_log :ma0 rtt:00:00:00.000545
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000529
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000592
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_change_order/test_change_order.def :ma0 rtt:00:00:00.007291
+localhost:3141 --restart :ma0 rtt:00:00:00.000501
+localhost:3141 --begin :ma0 rtt:00:00:00.000935
+localhost:3141 --sync_full=0 :ma0 rtt:00:00:00.006717
+localhost:3141 --ch_register=false a b c :ma0 rtt:00:00:00.000578
+localhost:3141 --sync=1 2514 119 :ma0 rtt:00:00:00.004363
+localhost:3141 --sync=1 2514 117 :ma0 rtt:00:00:00.000520
+localhost:3141 --order=/a order :ma0 rtt:00:00:00.000537
+localhost:3141 --sync=1 2514 117 :ma0 rtt:00:00:00.000907
+localhost:3141 --order=/a alpha :ma0 rtt:00:00:00.000514
+localhost:3141 --sync=1 2516 117 :ma0 rtt:00:00:00.000870
+localhost:3141 --order=/a bottom :ma0 rtt:00:00:00.000521
+localhost:3141 --sync=1 2518 117 :ma0 rtt:00:00:00.000848
+localhost:3141 --order=/a alpha :ma0 rtt:00:00:00.000525
+localhost:3141 --order=/a down :ma0 rtt:00:00:00.000503
+localhost:3141 --sync=1 2520 117 :ma0 rtt:00:00:00.000867
+localhost:3141 --order=/a alpha :ma0 rtt:00:00:00.000524
+localhost:3141 --order=/c up :ma0 rtt:00:00:00.000522
+localhost:3141 --sync=1 2524 117 :ma0 rtt:00:00:00.001098
+localhost:3141 --order=/a/a order :ma0 rtt:00:00:00.000514
+localhost:3141 --sync=1 2528 117 :ma0 rtt:00:00:00.000847
+localhost:3141 --order=/a/a alpha :ma0 rtt:00:00:00.000520
+localhost:3141 --sync=1 2530 117 :ma0 rtt:00:00:00.000846
+localhost:3141 --order=/a/a bottom :ma0 rtt:00:00:00.000519
+localhost:3141 --sync=1 2532 117 :ma0 rtt:00:00:00.000880
+localhost:3141 --order=/a/a alpha :ma0 rtt:00:00:00.000519
+localhost:3141 --order=/a/a down :ma0 rtt:00:00:00.000505
+localhost:3141 --sync=1 2534 117 :ma0 rtt:00:00:00.000862
+localhost:3141 --order=/a/a alpha :ma0 rtt:00:00:00.000505
+localhost:3141 --order=/a/c up :ma0 rtt:00:00:00.000552
+localhost:3141 --sync=1 2538 117 :ma0 rtt:00:00:00.000916
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000514
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000550
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_limit/test_limit.def_log :ma0 rtt:00:00:00.000533
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000516
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000589
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_limit/test_limit.def :ma0 rtt:00:00:00.002230
+localhost:3141 --restart :ma0 rtt:00:00:00.000503
+localhost:3141 --begin=test_limit :ma0 rtt:00:00:00.002060
+localhost:3141 --get :ma0 rtt:00:00:00.003202
+localhost:3141 --news=0 2768 123 :ma0 rtt:00:00:00.001038
+localhost:3141 --sync=0 2768 123 :ma0 rtt:00:00:00.001993
+localhost:3141 --get :ma0 rtt:00:00:00.002829
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000853
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000725
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_today_single_slot/test_today_single_slot.def_log :ma0 rtt:00:00:00.000794
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000746
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000819
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_today_single_slot/test_today_single_slot.def :ma0 rtt:00:00:00.002144
+localhost:3141 --restart :ma0 rtt:00:00:00.000716
+localhost:3141 --begin=test_today_single_slot :ma0 rtt:00:00:00.001863
+localhost:3141 --get :ma0 rtt:00:00:00.002164
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000783
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000722
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_today_relative_time_series/test_today_relative_time_series.def_log :ma0 rtt:00:00:00.000785
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000753
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000806
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_today_relative_time_series/test_today_relative_time_series.def :ma0 rtt:00:00:00.002235
+localhost:3141 --restart :ma0 rtt:00:00:00.000733
+localhost:3141 --begin=test_today_relative_time_series :ma0 rtt:00:00:00.000786
+localhost:3141 --get :ma0 rtt:00:00:00.002183
+localhost:3141 --news=0 2942 131 :ma0 rtt:00:00:00.001012
+localhost:3141 --sync=0 2942 131 :ma0 rtt:00:00:00.001338
+localhost:3141 --get :ma0 rtt:00:00:00.001887
+localhost:3141 --news=0 2943 131 :ma0 rtt:00:00:00.001040
+localhost:3141 --sync=0 2943 131 :ma0 rtt:00:00:00.001342
+localhost:3141 --get :ma0 rtt:00:00:00.001948
+localhost:3141 --news=0 2944 131 :ma0 rtt:00:00:00.000995
+localhost:3141 --sync=0 2944 131 :ma0 rtt:00:00:00.001923
+localhost:3141 --get :ma0 rtt:00:00:00.001860
+localhost:3141 --news=0 2990 131 :ma0 rtt:00:00:00.001043
+localhost:3141 --sync=0 2990 131 :ma0 rtt:00:00:00.001330
+localhost:3141 --get :ma0 rtt:00:00:00.001863
+localhost:3141 --news=0 2991 131 :ma0 rtt:00:00:00.001036
+localhost:3141 --sync=0 2991 131 :ma0 rtt:00:00:00.001339
+localhost:3141 --get :ma0 rtt:00:00:00.001856
+localhost:3141 --news=0 2992 131 :ma0 rtt:00:00:00.000989
+localhost:3141 --sync=0 2992 131 :ma0 rtt:00:00:00.001931
+localhost:3141 --get :ma0 rtt:00:00:00.001831
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000780
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000763
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_today_real_time_series/test_today_real_time_series.def_log :ma0 rtt:00:00:00.000823
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000767
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000849
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_today_real_time_series/test_today_real_time_series.def :ma0 rtt:00:00:00.002284
+localhost:3141 --restart :ma0 rtt:00:00:00.000712
+localhost:3141 --begin=test_today_real_time_series :ma0 rtt:00:00:00.000800
+localhost:3141 --get :ma0 rtt:00:00:00.002248
+localhost:3141 --news=0 3104 135 :ma0 rtt:00:00:00.001324
+localhost:3141 --news=0 3104 135 :ma0 rtt:00:00:00.001037
+localhost:3141 --news=0 3104 135 :ma0 rtt:00:00:00.001011
+localhost:3141 --sync=0 3104 135 :ma0 rtt:00:00:00.001937
+localhost:3141 --get :ma0 rtt:00:00:00.001925
+localhost:3141 --news=0 3149 135 :ma0 rtt:00:00:00.001022
+localhost:3141 --news=0 3149 135 :ma0 rtt:00:00:00.001019
+localhost:3141 --news=0 3149 135 :ma0 rtt:00:00:00.001017
+localhost:3141 --sync=0 3149 135 :ma0 rtt:00:00:00.002064
+localhost:3141 --get :ma0 rtt:00:00:00.001955
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000796
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000889
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_events/test_events.def_log :ma0 rtt:00:00:00.000794
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000782
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000808
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_events/test_events.def :ma0 rtt:00:00:00.003309
+localhost:3141 --restart :ma0 rtt:00:00:00.000500
+localhost:3141 --begin=test_events :ma0 rtt:00:00:00.002266
+localhost:3141 --get :ma0 rtt:00:00:00.002928
+localhost:3141 --news=0 3298 139 :ma0 rtt:00:00:00.001039
+localhost:3141 --sync=0 3298 139 :ma0 rtt:00:00:00.001313
+localhost:3141 --get :ma0 rtt:00:00:00.002571
+localhost:3141 --news=0 3301 139 :ma0 rtt:00:00:00.001035
+localhost:3141 --sync=0 3301 139 :ma0 rtt:00:00:00.001922
+localhost:3141 --get :ma0 rtt:00:00:00.002557
+localhost:3141 --news=0 3324 139 :ma0 rtt:00:00:00.001105
+localhost:3141 --sync=0 3324 139 :ma0 rtt:00:00:00.002705
+localhost:3141 --get :ma0 rtt:00:00:00.002523
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000732
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000742
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_complete/test_complete.def_log :ma0 rtt:00:00:00.000784
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000786
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000815
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_complete/test_complete.def :ma0 rtt:00:00:00.003330
+localhost:3141 --restart :ma0 rtt:00:00:00.000719
+localhost:3141 --begin=test_complete :ma0 rtt:00:00:00.002345
+localhost:3141 --get :ma0 rtt:00:00:00.002671
+localhost:3141 --news=0 3507 143 :ma0 rtt:00:00:00.001112
+localhost:3141 --sync=0 3507 143 :ma0 rtt:00:00:00.002612
+localhost:3141 --get :ma0 rtt:00:00:00.002276
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000744
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_complete_does_not_hold/test_complete_does_not_hold.def_log :ma0 rtt:00:00:00.000826
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000745
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000821
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_complete_does_not_hold/test_complete_does_not_hold.def :ma0 rtt:00:00:00.002355
+localhost:3141 --restart :ma0 rtt:00:00:00.000716
+localhost:3141 --begin=test_complete_does_not_hold :ma0 rtt:00:00:00.001561
+localhost:3141 --get :ma0 rtt:00:00:00.002340
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_complete_with_empty_family/test_complete_with_empty_family.def_log :ma0 rtt:00:00:00.000878
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000783
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000886
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_complete_with_empty_family/test_complete_with_empty_family.def :ma0 rtt:00:00:00.002763
+localhost:3141 --restart :ma0 rtt:00:00:00.000707
+localhost:3141 --begin=test_complete_with_empty_family :ma0 rtt:00:00:00.002443
+localhost:3141 --get :ma0 rtt:00:00:00.002457
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000884
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_abort_cmd/test_abort_cmd.def_log :ma0 rtt:00:00:00.000796
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000749
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000965
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_abort_cmd/test_abort_cmd.def :ma0 rtt:00:00:00.002040
+localhost:3141 --restart :ma0 rtt:00:00:00.000804
+localhost:3141 --begin=test_abort_cmd :ma0 rtt:00:00:00.001465
+localhost:3141 --get :ma0 rtt:00:00:00.002093
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000760
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000722
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_shutdown/test_shutdown.def_log :ma0 rtt:00:00:00.000799
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000758
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000807
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_shutdown/test_shutdown.def :ma0 rtt:00:00:00.002494
+localhost:3141 --restart :ma0 rtt:00:00:00.000726
+localhost:3141 --begin=test_shutdown :ma0 rtt:00:00:00.000824
+localhost:3141 --shutdown=yes :ma0 rtt:00:00:00.000680
+localhost:3141 --sync_full=0 :ma0 rtt:00:00:00.002101
+localhost:3141 --sync=0 3969 159 :ma0 rtt:00:00:00.001582
+localhost:3141 --sync=0 3970 159 :ma0 rtt:00:00:00.001078
+localhost:3141 --sync=0 3970 159 :ma0 rtt:00:00:00.001101
+localhost:3141 --sync=0 3970 159 :ma0 rtt:00:00:00.001619
+localhost:3141 --restart :ma0 rtt:00:00:00.002204
+localhost:3141 --get :ma0 rtt:00:00:00.002526
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000805
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000721
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_suspend_node/test_suspend_node.def_log :ma0 rtt:00:00:00.000795
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000748
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000812
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_suspend_node/test_suspend_node.def :ma0 rtt:00:00:00.002633
+localhost:3141 --restart :ma0 rtt:00:00:00.000505
+localhost:3141 --begin=test_suspend_node :ma0 rtt:00:00:00.000566
+localhost:3141 --suspend /test_suspend_node/family :ma0 rtt:00:00:00.000511
+localhost:3141 --sync_full=0 :ma0 rtt:00:00:00.001683
+localhost:3141 --sync=0 4077 163 :ma0 rtt:00:00:00.001114
+localhost:3141 --sync=0 4077 163 :ma0 rtt:00:00:00.001066
+localhost:3141 --sync=0 4077 163 :ma0 rtt:00:00:00.002114
+localhost:3141 --sync=0 4098 163 :ma0 rtt:00:00:00.001920
+localhost:3141 --sync=0 4107 163 :ma0 rtt:00:00:00.001134
+localhost:3141 --sync=0 4107 163 :ma0 rtt:00:00:00.002167
+localhost:3141 --resume /test_suspend_node/family :ma0 rtt:00:00:00.002183
+localhost:3141 --get :ma0 rtt:00:00:00.002853
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000768
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000723
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_cron_time_series/test_cron_time_series.def_log :ma0 rtt:00:00:00.000786
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000759
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000851
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_cron_time_series/test_cron_time_series.def :ma0 rtt:00:00:00.002216
+localhost:3141 --restart :ma0 rtt:00:00:00.000736
+localhost:3141 --begin=test_cron_time_series :ma0 rtt:00:00:00.000794
+localhost:3141 --get :ma0 rtt:00:00:00.002235
+localhost:3141 --news=0 4258 167 :ma0 rtt:00:00:00.001067
+localhost:3141 --news=0 4258 167 :ma0 rtt:00:00:00.001010
+localhost:3141 --sync=0 4258 167 :ma0 rtt:00:00:00.001992
+localhost:3141 --get :ma0 rtt:00:00:00.001889
+localhost:3141 --news=0 4303 167 :ma0 rtt:00:00:00.001011
+localhost:3141 --news=0 4303 167 :ma0 rtt:00:00:00.001005
+localhost:3141 --sync=0 4303 167 :ma0 rtt:00:00:00.001989
+localhost:3141 --get :ma0 rtt:00:00:00.001898
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000748
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000703
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_file_cmd/test_file_cmd.def_log :ma0 rtt:00:00:00.000767
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000755
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000857
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_file_cmd/test_file_cmd.def :ma0 rtt:00:00:00.002238
+localhost:3141 --restart :ma0 rtt:00:00:00.000722
+localhost:3141 --begin=test_file_cmd :ma0 rtt:00:00:00.002131
+localhost:3141 --get :ma0 rtt:00:00:00.001859
+localhost:3141 --file=/test_file_cmd script 10000 :ma0 rtt:00:00:00.000734
+localhost:3141 --file=/test_file_cmd job 10000 :ma0 rtt:00:00:00.000575
+localhost:3141 --file=/test_file_cmd jobout 10000 :ma0 rtt:00:00:00.000808
+localhost:3141 --file=/test_file_cmd manual 10000 :ma0 rtt:00:00:00.000954
+localhost:3141 --file=/test_file_cmd kill 10000 :ma0 rtt:00:00:00.000872
+localhost:3141 --file=/test_file_cmd stat 10000 :ma0 rtt:00:00:00.000810
+localhost:3141 --file=/test_file_cmd/family script 10000 :ma0 rtt:00:00:00.000926
+localhost:3141 --file=/test_file_cmd/family job 10000 :ma0 rtt:00:00:00.000939
+localhost:3141 --file=/test_file_cmd/family jobout 10000 :ma0 rtt:00:00:00.000952
+localhost:3141 --file=/test_file_cmd/family manual 10000 :ma0 rtt:00:00:00.000865
+localhost:3141 --file=/test_file_cmd/family kill 10000 :ma0 rtt:00:00:00.000794
+localhost:3141 --file=/test_file_cmd/family stat 10000 :ma0 rtt:00:00:00.000895
+localhost:3141 --file=/test_file_cmd/family/t0 script 10000 :ma0 rtt:00:00:00.000787
+localhost:3141 --file=/test_file_cmd/family/t0 job 10000 :ma0 rtt:00:00:00.000948
+localhost:3141 --file=/test_file_cmd/family/t0 jobout 10000 :ma0 rtt:00:00:00.000908
+localhost:3141 --file=/test_file_cmd/family/t0 manual 10000 :ma0 rtt:00:00:00.000993
+localhost:3141 --file=/test_file_cmd/family/t0 kill 10000 :ma0 rtt:00:00:00.000818
+localhost:3141 --file=/test_file_cmd/family/t0 stat 10000 :ma0 rtt:00:00:00.000896
+localhost:3141 --file=/test_file_cmd/family/t1 script 10000 :ma0 rtt:00:00:00.000827
+localhost:3141 --file=/test_file_cmd/family/t1 job 10000 :ma0 rtt:00:00:00.000830
+localhost:3141 --file=/test_file_cmd/family/t1 jobout 10000 :ma0 rtt:00:00:00.000950
+localhost:3141 --file=/test_file_cmd/family/t1 manual 10000 :ma0 rtt:00:00:00.001013
+localhost:3141 --file=/test_file_cmd/family/t1 kill 10000 :ma0 rtt:00:00:00.000931
+localhost:3141 --file=/test_file_cmd/family/t1 stat 10000 :ma0 rtt:00:00:00.000987
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000917
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000856
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_triggers_and_meters/test_triggers_and_meters.def_log :ma0 rtt:00:00:00.000870
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000825
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.001000
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_triggers_and_meters/test_triggers_and_meters.def :ma0 rtt:00:00:00.006511
+localhost:3141 --restart :ma0 rtt:00:00:00.000536
+localhost:3141 --begin=test_triggers_and_meters :ma0 rtt:00:00:00.006932
+localhost:3141 --get :ma0 rtt:00:00:00.003926
+localhost:3141 --news=0 4594 175 :ma0 rtt:00:00:00.001023
+localhost:3141 --sync=0 4594 175 :ma0 rtt:00:00:00.002577
+localhost:3141 --get :ma0 rtt:00:00:00.003520
+localhost:3141 --news=0 4660 175 :ma0 rtt:00:00:00.001043
+localhost:3141 --sync=0 4660 175 :ma0 rtt:00:00:00.002591
+localhost:3141 --get :ma0 rtt:00:00:00.003536
+localhost:3141 --news=0 4726 175 :ma0 rtt:00:00:00.001038
+localhost:3141 --sync=0 4726 175 :ma0 rtt:00:00:00.002202
+localhost:3141 --get :ma0 rtt:00:00:00.003526
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000790
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000756
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_why_day/test_why_day.def_log :ma0 rtt:00:00:00.000783
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000750
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000879
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_why_day/test_why_day.def :ma0 rtt:00:00:00.002096
+localhost:3141 --restart :ma0 rtt:00:00:00.000718
+localhost:3141 --begin=test_why_day :ma0 rtt:00:00:00.000780
+localhost:3141 --sync_full=0 :ma0 rtt:00:00:00.001765
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000916
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_why_date/test_why_date.def_log :ma0 rtt:00:00:00.000793
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000765
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000889
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_why_date/test_why_date.def :ma0 rtt:00:00:00.002029
+localhost:3141 --restart :ma0 rtt:00:00:00.000697
+localhost:3141 --begin=test_why_date :ma0 rtt:00:00:00.000787
+localhost:3141 --sync_full=0 :ma0 rtt:00:00:00.001839
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_why_time/test_why_time.def_log :ma0 rtt:00:00:00.000800
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000802
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000797
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_why_time/test_why_time.def :ma0 rtt:00:00:00.002091
+localhost:3141 --restart :ma0 rtt:00:00:00.000718
+localhost:3141 --begin=test_why_time :ma0 rtt:00:00:00.000778
+localhost:3141 --sync_full=0 :ma0 rtt:00:00:00.001753
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_why_today/test_why_today.def_log :ma0 rtt:00:00:00.000764
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000746
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000775
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_why_today/test_why_today.def :ma0 rtt:00:00:00.002027
+localhost:3141 --restart :ma0 rtt:00:00:00.000718
+localhost:3141 --begin=test_why_today :ma0 rtt:00:00:00.000798
+localhost:3141 --sync_full=0 :ma0 rtt:00:00:00.001773
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_why_cron/test_why_cron.def_log :ma0 rtt:00:00:00.000815
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000785
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000944
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_why_cron/test_why_cron.def :ma0 rtt:00:00:00.002163
+localhost:3141 --restart :ma0 rtt:00:00:00.000714
+localhost:3141 --begin=test_why_cron :ma0 rtt:00:00:00.000853
+localhost:3141 --sync_full=0 :ma0 rtt:00:00:00.001839
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_why_limit/test_why_limit.def_log :ma0 rtt:00:00:00.000950
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000764
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000550
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_why_limit/test_why_limit.def :ma0 rtt:00:00:00.001851
+localhost:3141 --restart :ma0 rtt:00:00:00.000491
+localhost:3141 --begin=test_why_limit :ma0 rtt:00:00:00.001091
+localhost:3141 --sync_full=0 :ma0 rtt:00:00:00.001767
+localhost:3141 --get :ma0 rtt:00:00:00.001970
+localhost:3141 --get :ma0 rtt:00:00:00.002742
+localhost:3141 --get :ma0 rtt:00:00:00.002792
+localhost:3141 --get :ma0 rtt:00:00:00.002725
+localhost:3141 --get :ma0 rtt:00:00:00.002751
+localhost:3141 --get :ma0 rtt:00:00:00.002718
+localhost:3141 --get :ma0 rtt:00:00:00.002756
+localhost:3141 --get :ma0 rtt:00:00:00.002724
+localhost:3141 --get :ma0 rtt:00:00:00.002835
+localhost:3141 --get :ma0 rtt:00:00:00.002715
+localhost:3141 --get :ma0 rtt:00:00:00.002782
+localhost:3141 --get :ma0 rtt:00:00:00.002761
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_why_trigger/test_why_trigger.def_log :ma0 rtt:00:00:00.000829
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000767
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000850
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_why_trigger/test_why_trigger.def :ma0 rtt:00:00:00.002027
+localhost:3141 --restart :ma0 rtt:00:00:00.000734
+localhost:3141 --begin=test_why_trigger :ma0 rtt:00:00:00.000829
+localhost:3141 --sync_full=0 :ma0 rtt:00:00:00.001716
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_why_meter/test_why_meter.def_log :ma0 rtt:00:00:00.000784
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000739
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000789
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_why_meter/test_why_meter.def :ma0 rtt:00:00:00.002763
+localhost:3141 --restart :ma0 rtt:00:00:00.000854
+localhost:3141 --begin=test_why_meter :ma0 rtt:00:00:00.001467
+localhost:3141 --sync_full=0 :ma0 rtt:00:00:00.001438
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_why_event/test_why_event.def_log :ma0 rtt:00:00:00.000560
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000515
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000541
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_why_event/test_why_event.def :ma0 rtt:00:00:00.002027
+localhost:3141 --restart :ma0 rtt:00:00:00.000488
+localhost:3141 --begin=test_why_event :ma0 rtt:00:00:00.001042
+localhost:3141 --sync_full=0 :ma0 rtt:00:00:00.001318
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_why_user_var/test_why_user_var.def_log :ma0 rtt:00:00:00.000566
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000522
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000556
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_why_user_var/test_why_user_var.def :ma0 rtt:00:00:00.001786
+localhost:3141 --restart :ma0 rtt:00:00:00.000488
+localhost:3141 --begin=test_why_user_var :ma0 rtt:00:00:00.000972
+localhost:3141 --sync_full=0 :ma0 rtt:00:00:00.001155
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_why_gen_var/test_why_gen_var.def_log :ma0 rtt:00:00:00.000547
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000512
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000536
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_why_gen_var/test_why_gen_var.def :ma0 rtt:00:00:00.001831
+localhost:3141 --restart :ma0 rtt:00:00:00.000486
+localhost:3141 --begin=test_why_gen_var :ma0 rtt:00:00:00.001012
+localhost:3141 --sync_full=0 :ma0 rtt:00:00:00.001184
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_why_repeat/test_why_repeat.def_log :ma0 rtt:00:00:00.000596
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000511
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000536
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_why_repeat/test_why_repeat.def :ma0 rtt:00:00:00.002163
+localhost:3141 --restart :ma0 rtt:00:00:00.000504
+localhost:3141 --begin=test_why_repeat :ma0 rtt:00:00:00.001293
+localhost:3141 --sync_full=0 :ma0 rtt:00:00:00.001210
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000557
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_time_single_slot/test_time_single_slot.def_log :ma0 rtt:00:00:00.000519
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000510
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000535
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_time_single_slot/test_time_single_slot.def :ma0 rtt:00:00:00.001462
+localhost:3141 --restart :ma0 rtt:00:00:00.000483
+localhost:3141 --begin=test_time_single_slot :ma0 rtt:00:00:00.000562
+localhost:3141 --get :ma0 rtt:00:00:00.002240
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000812
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000747
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_time_multiple_single_slot/test_time_multiple_single_slot.def_log :ma0 rtt:00:00:00.000792
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000779
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000847
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_time_multiple_single_slot/test_time_multiple_single_slot.def :ma0 rtt:00:00:00.002199
+localhost:3141 --restart :ma0 rtt:00:00:00.000729
+localhost:3141 --begin=test_time_multiple_single_slot :ma0 rtt:00:00:00.000829
+localhost:3141 --get :ma0 rtt:00:00:00.002265
+localhost:3141 --news=0 5429 231 :ma0 rtt:00:00:00.001035
+localhost:3141 --news=0 5429 231 :ma0 rtt:00:00:00.001046
+localhost:3141 --news=0 5429 231 :ma0 rtt:00:00:00.001050
+localhost:3141 --sync=0 5429 231 :ma0 rtt:00:00:00.002064
+localhost:3141 --get :ma0 rtt:00:00:00.001902
+localhost:3141 --news=0 5476 231 :ma0 rtt:00:00:00.001045
+localhost:3141 --news=0 5476 231 :ma0 rtt:00:00:00.001037
+localhost:3141 --news=0 5476 231 :ma0 rtt:00:00:00.001031
+localhost:3141 --sync=0 5476 231 :ma0 rtt:00:00:00.001942
+localhost:3141 --get :ma0 rtt:00:00:00.001908
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000767
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000727
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_time_relative_time_series/test_time_relative_time_series.def_log :ma0 rtt:00:00:00.000803
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000751
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000812
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_time_relative_time_series/test_time_relative_time_series.def :ma0 rtt:00:00:00.002174
+localhost:3141 --restart :ma0 rtt:00:00:00.000747
+localhost:3141 --begin=test_time_relative_time_series :ma0 rtt:00:00:00.000923
+localhost:3141 --get :ma0 rtt:00:00:00.002217
+localhost:3141 --news=0 5586 235 :ma0 rtt:00:00:00.001040
+localhost:3141 --sync=0 5586 235 :ma0 rtt:00:00:00.001332
+localhost:3141 --get :ma0 rtt:00:00:00.001847
+localhost:3141 --news=0 5587 235 :ma0 rtt:00:00:00.001036
+localhost:3141 --sync=0 5587 235 :ma0 rtt:00:00:00.001330
+localhost:3141 --get :ma0 rtt:00:00:00.001862
+localhost:3141 --news=0 5588 235 :ma0 rtt:00:00:00.001030
+localhost:3141 --sync=0 5588 235 :ma0 rtt:00:00:00.001907
+localhost:3141 --get :ma0 rtt:00:00:00.001864
+localhost:3141 --news=0 5634 235 :ma0 rtt:00:00:00.001043
+localhost:3141 --sync=0 5634 235 :ma0 rtt:00:00:00.001330
+localhost:3141 --get :ma0 rtt:00:00:00.001869
+localhost:3141 --news=0 5635 235 :ma0 rtt:00:00:00.001084
+localhost:3141 --sync=0 5635 235 :ma0 rtt:00:00:00.001336
+localhost:3141 --get :ma0 rtt:00:00:00.001866
+localhost:3141 --news=0 5636 235 :ma0 rtt:00:00:00.001042
+localhost:3141 --sync=0 5636 235 :ma0 rtt:00:00:00.001944
+localhost:3141 --get :ma0 rtt:00:00:00.001866
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000753
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000728
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_time_real_series/test_time_real_series.def_log :ma0 rtt:00:00:00.000776
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000767
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000843
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_time_real_series/test_time_real_series.def :ma0 rtt:00:00:00.002184
+localhost:3141 --restart :ma0 rtt:00:00:00.000749
+localhost:3141 --begin=test_time_real_series :ma0 rtt:00:00:00.000790
+localhost:3141 --get :ma0 rtt:00:00:00.001729
+localhost:3141 --news=0 5746 239 :ma0 rtt:00:00:00.001022
+localhost:3141 --news=0 5746 239 :ma0 rtt:00:00:00.001054
+localhost:3141 --news=0 5746 239 :ma0 rtt:00:00:00.001027
+localhost:3141 --sync=0 5746 239 :ma0 rtt:00:00:00.001934
+localhost:3141 --get :ma0 rtt:00:00:00.001898
+localhost:3141 --news=0 5791 239 :ma0 rtt:00:00:00.001034
+localhost:3141 --news=0 5791 239 :ma0 rtt:00:00:00.001043
+localhost:3141 --news=0 5791 239 :ma0 rtt:00:00:00.001034
+localhost:3141 --sync=0 5791 239 :ma0 rtt:00:00:00.001973
+localhost:3141 --get :ma0 rtt:00:00:00.001872
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000810
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000747
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_late/test_late.def_log :ma0 rtt:00:00:00.000780
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000768
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000834
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_late/test_late.def :ma0 rtt:00:00:00.001888
+localhost:3141 --restart :ma0 rtt:00:00:00.000714
+localhost:3141 --begin=test_late :ma0 rtt:00:00:00.001453
+localhost:3141 --get :ma0 rtt:00:00:00.001910
+localhost:3141 --news=0 5868 243 :ma0 rtt:00:00:00.001042
+localhost:3141 --sync=0 5868 243 :ma0 rtt:00:00:00.001371
+localhost:3141 --get :ma0 rtt:00:00:00.001607
+localhost:3141 --news=0 5870 243 :ma0 rtt:00:00:00.001032
+localhost:3141 --sync=0 5870 243 :ma0 rtt:00:00:00.001619
+localhost:3141 --get :ma0 rtt:00:00:00.001537
+localhost:3141 --sync_full=0 :ma0 rtt:00:00:00.001516
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000770
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000741
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_server_job_submission/test_server_job_submission.def_log :ma0 rtt:00:00:00.000797
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000762
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000810
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_server_job_submission/test_server_job_submission.def :ma0 rtt:00:00:00.002509
+localhost:3141 --restart :ma0 rtt:00:00:00.000717
+localhost:3141 --begin=test_server_job_submission :ma0 rtt:00:00:00.002936
+localhost:3141 --get :ma0 rtt:00:00:00.002446
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000778
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000705
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_restore_defs_from_check_pt/test_restore_defs_from_check_pt.def_log :ma0 rtt:00:00:00.000782
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000763
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000826
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_restore_defs_from_check_pt/test_restore_defs_from_check_pt.def :ma0 rtt:00:00:00.001965
+localhost:3141 --restart :ma0 rtt:00:00:00.000718
+localhost:3141 --begin=test_restore_defs_from_check_pt :ma0 rtt:00:00:00.001473
+localhost:3141 --get :ma0 rtt:00:00:00.001889
+localhost:3141 --check_pt=never :ma0 rtt:00:00:00.000714
+localhost:3141 --get :ma0 rtt:00:00:00.001421
+localhost:3141 --check_pt :ma0 rtt:00:00:00.001161
+localhost:3141 --restore_from_checkpt :ma0 rtt:00:00:00.000741
+localhost:3141 --halt=yes :ma0 rtt:00:00:00.000691
+localhost:3141 --restore_from_checkpt :ma0 rtt:00:00:00.000716
+localhost:3141 --delete _all_ yes :ma0 rtt:00:00:00.000851
+localhost:3141 --get :ma0 rtt:00:00:00.000889
+localhost:3141 --restore_from_checkpt :ma0 rtt:00:00:00.001208
+localhost:3141 --get :ma0 rtt:00:00:00.001442
+localhost:3141 --check_pt=on_time:120 :ma0 rtt:00:00:00.000689
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000737
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000723
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_wait_cmd/test_wait_cmd.def_log :ma0 rtt:00:00:00.000797
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000765
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000770
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_wait_cmd/test_wait_cmd.def :ma0 rtt:00:00:00.002531
+localhost:3141 --restart :ma0 rtt:00:00:00.000509
+localhost:3141 --begin=test_wait_cmd :ma0 rtt:00:00:00.002830
+localhost:3141 --get :ma0 rtt:00:00:00.002840
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000860
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_wait_cmd_parse_fail/test_wait_cmd_parse_fail.def_log :ma0 rtt:00:00:00.000800
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000767
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000847
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_wait_cmd_parse_fail/test_wait_cmd_parse_fail.def :ma0 rtt:00:00:00.002834
+localhost:3141 --restart :ma0 rtt:00:00:00.000726
+localhost:3141 --begin=test_wait_cmd_parse_fail :ma0 rtt:00:00:00.004206
+localhost:3141 --sync_full=0 :ma0 rtt:00:00:00.002854
+localhost:3141 --sync=0 6337 261 :ma0 rtt:00:00:00.002927
+localhost:3141 --sync=0 6408 261 :ma0 rtt:00:00:00.002610
+localhost:3141 --sync=0 6438 261 :ma0 rtt:00:00:00.000789
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_wait_cmd_non_existant_paths/test_wait_cmd_non_existant_paths.def_log :ma0 rtt:00:00:00.000822
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000759
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000844
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_wait_cmd_non_existant_paths/test_wait_cmd_non_existant_paths.def :ma0 rtt:00:00:00.002826
+localhost:3141 --restart :ma0 rtt:00:00:00.000727
+localhost:3141 --begin=test_wait_cmd_non_existant_paths :ma0 rtt:00:00:00.004255
+localhost:3141 --sync_full=0 :ma0 rtt:00:00:00.002858
+localhost:3141 --sync=0 6541 265 :ma0 rtt:00:00:00.002904
+localhost:3141 --sync=0 6584 265 :ma0 rtt:00:00:00.002972
+localhost:3141 --sync=0 6648 265 :ma0 rtt:00:00:00.000773
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000767
+localhost:3141 --log=new Test/data/ECF_HOME_debug/test_alias/test_alias.def_log :ma0 rtt:00:00:00.000773
+localhost:3141 --log=clear :ma0 rtt:00:00:00.000775
+localhost:3141 --delete _all_ force yes :ma0 rtt:00:00:00.000824
+localhost:3141 --load=Test/data/ECF_HOME_debug/test_alias/test_alias.def :ma0 rtt:00:00:00.001962
+localhost:3141 --restart :ma0 rtt:00:00:00.000772
+localhost:3141 --begin=test_alias :ma0 rtt:00:00:00.001498
+localhost:3141 --get :ma0 rtt:00:00:00.001978
+localhost:3141 --file=/test_alias/task_a script 10000 :ma0 rtt:00:00:00.000870
+localhost:3141 --sync_full=0 :ma0 rtt:00:00:00.002039
+localhost:3141 --sync=0 6723 269 :ma0 rtt:00:00:00.001990
+localhost:3141 --sync=0 6744 269 :ma0 rtt:00:00:00.002100
+localhost:3141 --order=/test_alias/task_a/alias0 down :ma0 rtt:00:00:00.000795
+localhost:3141 --sync=0 6750 269 :ma0 rtt:00:00:00.001277
+localhost:3141 --order=/test_alias/task_a/alias0 up :ma0 rtt:00:00:00.000739
+localhost:3141 --sync=0 6752 269 :ma0 rtt:00:00:00.001272
+localhost:3141 --order=/test_alias/task_a/alias0 order :ma0 rtt:00:00:00.000768
+localhost:3141 --sync=0 6754 269 :ma0 rtt:00:00:00.001300
+localhost:3141 --order=/test_alias/task_a/alias0 alpha :ma0 rtt:00:00:00.000769
+localhost:3141 --sync=0 6756 269 :ma0 rtt:00:00:00.001274
+localhost:3141 --delete yes /test_alias/task_a/alias0 :ma0 rtt:00:00:00.000748
+localhost:3141 --delete yes /test_alias/task_a/alias1 :ma0 rtt:00:00:00.000741
+localhost:3141 --sync=0 6758 269 :ma0 rtt:00:00:00.001274
+localhost:3141 --zombie_get :ma0 rtt:00:00:00.000768
+localhost:3141 --suites :ma0 rtt:00:00:00.000752
+localhost:3141 --stats :ma0 rtt:00:00:00.000989
+localhost:3141 --terminate=yes :ma0 rtt:00:00:00.001247
diff --git a/ecflow_4_0_7/Client/test/data/second.def b/Client/test/data/second.def
similarity index 100%
rename from ecflow_4_0_7/Client/test/data/second.def
rename to Client/test/data/second.def
diff --git a/Doc/.pydevproject b/Doc/.pydevproject
new file mode 100644
index 0000000..a9cca03
--- /dev/null
+++ b/Doc/.pydevproject
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?eclipse-pydev version="1.0"?>
+
+<pydev_project>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
+</pydev_project>
diff --git a/ecflow_4_0_7/Doc/user-manual/client_options.docx b/Doc/user-manual/client_options.docx
similarity index 100%
rename from ecflow_4_0_7/Doc/user-manual/client_options.docx
rename to Doc/user-manual/client_options.docx
diff --git a/Doc/user-manual/user_manual.docx b/Doc/user-manual/user_manual.docx
new file mode 100644
index 0000000..789c28d
Binary files /dev/null and b/Doc/user-manual/user_manual.docx differ
diff --git a/ecflow_4_0_7/Doc/user-manual/user_manual.pdf b/Doc/user-manual/user_manual.pdf
similarity index 100%
rename from ecflow_4_0_7/Doc/user-manual/user_manual.pdf
rename to Doc/user-manual/user_manual.pdf
diff --git a/Jamroot.jam b/Jamroot.jam
new file mode 100644
index 0000000..baed659
--- /dev/null
+++ b/Jamroot.jam
@@ -0,0 +1,187 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+#
+# To clean all the sub projects just use: bjam --clean
+#
+path-constant TOP : . ; # After that, the TOP variable can be used in every Jamfile.
+
+build-project ACore ;
+build-project ANattr ;
+build-project ANode ;
+build-project AParser ;
+build-project Base ;
+build-project Client ;
+build-project CSim ;
+build-project Server ;
+build-project Test ;
+
+# The gui is not built on HPUX and IBM(power6) platforms
+import os ;
+ARCH = [ os.environ ARCH ] ;
+ARCH default = UNDEF ; # if arch not defined set as UNDEF, otherwise if $(ARCH) will be true
+build_gui = linux cray other_gui_arch ;
+# echo "ARCH = $(ARCH)" ;
+if $(ARCH) in $(build_gui) {
+ build-project view ;
+}
+
+# Some user do no want python: They must define ECF_NO_PYTHON
+NO_PYTHON = [ os.environ ECF_NO_PYTHON ] ;
+#echo "NO_PYTHON = $(NO_PYTHON)" ;
+if ! $(NO_PYTHON) {
+ # echo "building python" ;
+ build-project Pyext ;
+}
+
+# ==================== INSTALL ==========================================================
+
+local dest_dir = [ os.environ ECFLOW_DESTDIR ] ;
+dest_dir default = "" ;
+constant ECFLOW_DESTDIR : $(dest_dir) ;
+
+local ECFLOW_VERSION = [ SHELL "cd $(TOP); ./version.sh" ] ;
+local install_dir = [ os.environ ECFLOW_INSTALL_DIR ] ;
+install_dir default = "/usr/local/apps/ecflow/$(ECFLOW_VERSION)" ;
+constant ECFLOW_INSTALL_DIR : $(install_dir) ;
+
+local python_install_dir = [ os.environ ECFLOW_PYTHON_INSTALL_DIR ] ;
+python_install_dir default = $(install_dir)/lib/python2.7/site-packages/ecflow ;
+constant ECFLOW_PYTHON_INSTALL_DIR : $(python_install_dir) ;
+
+# Used for ecflowview files
+constant ECFLOW_SHARED_DIR : $(ECFLOW_DESTDIR)$(ECFLOW_INSTALL_DIR)/share/ecflow ;
+
+#echo "ECFLOW_VERSION = '$(ECFLOW_VERSION)'" ;
+#echo "ECFLOW_DESTDIR = '$(ECFLOW_DESTDIR)'" ;
+#echo "ECFLOW_INSTALL_DIR = '$(ECFLOW_INSTALL_DIR)'" ;
+#echo "ECFLOW_PYTHON_INSTALL_DIR = '$(ECFLOW_PYTHON_INSTALL_DIR)'" ;
+#echo "ECFLOW_SHARED_DIR = '$(ECFLOW_SHARED_DIR)'" ;
+
+#
+# Allow the installation directory be be defined externally, by the environment variable ECFLOW_INSTALL_DIR
+#
+# However we want this to be explicit, as we dont need it on a day to day basis.
+# Usage:
+# bjam install variant=release
+#
+# to install the debug version
+# bjam install | bjam install variant=debug
+#
+# To preview the installation witout actaully doing it:
+# bjam install variant=release -d2 -n
+#
+# Note: if you find that the install has started to create directories
+# of name install-server,install-client,,install-py
+# Then *ensure* you have set the environment variables ECFLOW_INSTALL_DIR,
+#
+# Note: Not all system have XLib, hence install ecFlowview manually by using:
+# bjam -d2 install-viewer
+#
+# Make sure for ECMWF that ECFLOW_INSTALL_DIR leaf directory encompasses version number
+# that ties up with $WK/VERSION.cmake
+#
+
+# Do no call this on the command line, prefer bjam install-all || install-viewer
+# If this is called in isolation ldd will show the referenced shared lib as missing
+install install-view
+ : view//ecflowview
+ : <location>$(ECFLOW_DESTDIR)/$(ECFLOW_INSTALL_DIR)/bin
+ <dll-path>$(ECFLOW_INSTALL_DIR)/lib
+ ;
+
+
+# Some linux RPM have requirements that 64 bit libs must be under lib64
+# See http://software.ecmwf.int/issues/browse/ECFLOW-30, 64-bit Linux platforms expect libraries to go to the $PREFIX/lib64 directory, not $PREFIX/lib
+#
+install install-view64
+ : view//ecflowview
+ : <location>$(ECFLOW_DESTDIR)/$(ECFLOW_INSTALL_DIR)/bin
+ <dll-path>$(ECFLOW_INSTALL_DIR)/lib64
+ ;
+
+install install-view-files
+ : [ glob view/servers ]
+ [ glob view/src/ecflowview.menu ]
+ : <location>$(ECFLOW_SHARED_DIR)
+ ;
+
+install install-server
+ : Server//ecflow_server
+ : <location>$(ECFLOW_DESTDIR)/$(ECFLOW_INSTALL_DIR)/bin
+ ;
+
+install install-client
+ : Client//ecflow_client
+ : <location>$(ECFLOW_DESTDIR)/$(ECFLOW_INSTALL_DIR)/bin
+ ;
+
+install install-tools
+ : [ glob tools/*.sh ]
+ [ glob tools/*.pl ]
+ : <location>$(ECFLOW_DESTDIR)/$(ECFLOW_INSTALL_DIR)/bin
+ ;
+
+install install-doc
+ : [ glob Doc/user-manual/*.docx ]
+ [ glob Doc/user-manual/*.pdf ]
+ : <location>$(ECFLOW_DESTDIR)/$(ECFLOW_INSTALL_DIR)/doc/ecflow
+ ;
+
+# Fix bugs associated with the output of old version of ecflow_client --migrate
+install install-migrate
+ : [ glob Pyext/migrate/ecflow_migrate.py ]
+ : <location>$(ECFLOW_DESTDIR)/$(ECFLOW_INSTALL_DIR)/bin
+ ;
+
+# ===============================================================================================
+
+# Use this for a non-python install
+alias install-base :
+ install-server
+ install-client
+ install-tools
+ install-doc
+ install-migrate
+ ;
+alias install :
+ install-base
+ Pyext//install-py
+ Pyext//install-py1
+ ;
+alias install-viewer :
+ install-view
+ install-view-files
+ ;
+alias install-viewer64 :
+ install-view64
+ install-view-files
+ ;
+alias install-all :
+ install
+ install-viewer
+ ;
+alias install-all64 :
+ install
+ install-viewer64
+ ;
+
+# make install explicit, otherwise we end installing for all calls to bjam
+explicit install-server ;
+explicit install-client ;
+explicit install-tools ;
+explicit install-view ;
+explicit install-viewer ;
+explicit install-view64 ;
+explicit install-viewer64 ;
+explicit install-view-files ;
+explicit install-doc ;
+explicit install-migrate ;
+explicit install ;
+explicit install-base ;
+explicit install-all ;
+explicit install-all64 ;
diff --git a/ecflow_4_0_7/LICENSE b/LICENSE
similarity index 100%
rename from ecflow_4_0_7/LICENSE
rename to LICENSE
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..738bf95
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,71 @@
+Apache [ecflow]
+ Copyright [2009-2012] The Apache Software Foundation
+
+ This product includes software developed at
+ The Apache Software Foundation (http://www.apache.org/).
+
+
+
+Boost Software License - Version 1.0 - August 17th, 2003
+========================================================
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+
+
+The MIT License (MIT) - EOS-Portable-library
+============================================
+Copyright (c) 2012 EOS GmbH
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+LazyTextEdit
+================================================
+LazyTextEdit is a Qt based text editor that lazily loads data from disk when
+necessary.
+
+It tries to keep memory usage as low as possible and only stores chunks of data
+that have been modified. Its APIs resembles that of QText(Edit|Document|Cursor).
+It supports basic formatting options using TextSections and SyntaxHighlighter.
+
+LazyTextEdit is licensed under the Apache 2.0 license.
+
+Some of the source code was modified for inclusion in ecFlowUI.
+
diff --git a/Pyext/.gitignore b/Pyext/.gitignore
new file mode 100644
index 0000000..2ed7e98
--- /dev/null
+++ b/Pyext/.gitignore
@@ -0,0 +1,3 @@
+/build
+/setup.py
+/timestamp
diff --git a/Pyext/.pydevproject b/Pyext/.pydevproject
new file mode 100644
index 0000000..a9cca03
--- /dev/null
+++ b/Pyext/.pydevproject
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?eclipse-pydev version="1.0"?>
+
+<pydev_project>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
+</pydev_project>
diff --git a/Pyext/CMakeLists.txt b/Pyext/CMakeLists.txt
new file mode 100644
index 0000000..c91cc01
--- /dev/null
+++ b/Pyext/CMakeLists.txt
@@ -0,0 +1,181 @@
+### ecflow python bindings
+# NOTES:
+#
+# To see the python link line: Do python-config --ldflags, i.e
+# > /usr/local/apps/python/2.7.8-01/bin/python-config --ldflags
+# > -lpthread -ldl -lutil -lm -lpython2.7 -Xlinker -export-dynamic
+#
+# However on cct we get:
+# > /usr/local/apps/python/2.7.5-01/bin/python-config --ldflags
+# > -L/usr/local/apps/python/2.7.5-01/lib/python2.7/config -lpthread -ldl -lutil -lm -lpython2.7 -Xlinker -export-dynamic
+#
+# cct is correct as it has the "-L" but on other machines we rely on /usr/lib/libpython2.7.so.1.0 being there!
+# lxop-test does not have /usr/lib/libpython2.7.so.1.0 so ecbuild fails
+#
+#
+
+file( GLOB srcs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp" "src/*.hpp" )
+
+# =====================================================================
+# local includes
+include_directories(
+ ../ACore/src
+ ../ANattr/src
+ ../ANode/src
+ ../AParser/src
+ ../Base/src
+ ../Base/src/cts
+ ../Base/src/stc
+ ../Client/src
+ ../CSim/src
+ )
+
+# =====================================================================
+# INCLUDES here is for external includes
+ecbuild_add_library( TARGET ecflow
+ TYPE MODULE
+ SOURCES ${srcs}
+ CONDITION PYTHONLIBS_FOUND
+ LIBS libclient libsimu base libparser node nodeattr core
+ ${PYTHON_LIBRARIES}
+ INCLUDES
+ ${Boost_INCLUDE_DIRS}
+ ${PYTHON_INCLUDE_DIRS}
+ )
+
+# This ensures that for debug config, we only link with debug boost libs, for other configs, we link with optimised boost libs
+if ( PYTHONLIBS_FOUND )
+ target_link_libraries(ecflow debug ${Boost_PYTHON_LIBRARY_DEBUG} )
+ target_link_libraries(ecflow optimized ${Boost_PYTHON_LIBRARY_RELEASE} )
+endif()
+
+#
+# Override default behaviour that add RPATHS during install
+# The only thing that seem to work is set INSTALL_RPATH to ""
+# Using SKIP_BUILD_RPATH,BUILD_WITH_INSTALL_RPATH,INSTALL_RPATH_USE_LINK_PATH
+# had no effect
+#
+# by default cmake add prefix 'lib', we don't want this hence disable
+set_target_properties(ecflow PROPERTIES
+ PREFIX ""
+ INSTALL_RPATH ""
+ )
+
+# =====================================================================
+# tests
+
+ecbuild_add_test( TARGET py_u_TestMigrate
+ TYPE PYTHON
+ ARGS ${CMAKE_CURRENT_SOURCE_DIR}/migrate/py_u_TestMigrate.py
+ ENVIRONMENT "PYTHONPATH=${CMAKE_BINARY_DIR}/lib" )
+
+list( APPEND u_tests
+ py_u_TestAddDelete
+ py_u_TestAddDeleteFunc
+ py_u_TestAddNodeFunc
+ py_u_TestDefs
+ py_u_TestDefsCheck
+ py_u_TestDerivable
+ py_u_TestEcf
+ py_u_TestError
+ py_u_TestFind
+ py_u_TestFlag
+ py_u_TestGetAllTasks
+ py_u_TestJobGeneration
+ py_u_TestParent
+ py_u_TestRepeatArithmetic
+ py_u_TestSimulator
+ py_u_TestTraversal
+ py_u_TestUserManual
+ py_u_TestWith
+)
+foreach( test ${u_tests} )
+
+ ecbuild_add_test( TARGET ${test}
+ TYPE PYTHON
+ ARGS ${CMAKE_CURRENT_SOURCE_DIR}/test/${test}.py
+ ENVIRONMENT "PYTHONPATH=${CMAKE_BINARY_DIR}/lib"
+ TEST_DEPENDS u_base
+ )
+endforeach()
+
+
+if ( ENABLE_ALL_TESTS)
+ list( APPEND s_tests
+ py_s_TestClientApi
+ py_s_TestPythonChildApi
+ )
+
+ foreach( test ${s_tests} )
+
+ ecbuild_add_test( TARGET ${test}
+ TYPE PYTHON
+ ARGS ${CMAKE_CURRENT_SOURCE_DIR}/test/${test}.py
+ ENVIRONMENT "PYTHONPATH=${CMAKE_BINARY_DIR}/lib"
+ TEST_DEPENDS u_base
+ )
+ endforeach()
+
+ set_property(TEST py_s_TestClientApi APPEND PROPERTY DEPENDS s_test)
+ set_property(TEST py_s_TestPythonChildApi APPEND PROPERTY DEPENDS py_s_TestClientApi)
+endif()
+
+
+# ==========================================================================
+# install
+# -DCMAKE_PYTHON_INSTALL_TYPE = [ local | setup ]
+# local : this will install to $INSTALL_PREFIX/$release.$major.$minor/lib/python2.7/site-packages/ecflow/
+# setup : experimental only,python way of installing
+#
+# -DCMAKE_PYTHON_INSTALL_PREFIX should *only* used when using python setup.py (CMAKE_PYTHON_INSTALL_TYPE=setup)
+# *AND* for testing python install to local directory
+# ==========================================================================
+
+# CMAKE_PYTHON_INSTALL_TYPE = [ local | setup | not defined ]
+
+if( CMAKE_PYTHON_INSTALL_TYPE MATCHES "local" OR NOT DEFINED CMAKE_PYTHON_INSTALL_TYPE )
+
+ message(STATUS "python install *LOCAL* +++ lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages/ecflow +++++++")
+ set(PYTHON_SITE "lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages" )
+ set(PYTHON_DEST "${PYTHON_SITE}/ecflow" )
+
+ install( TARGETS ecflow DESTINATION ${PYTHON_DEST}
+ RENAME ecflow.so
+ )
+ install( FILES ecflow/__init__.py DESTINATION ${PYTHON_DEST} )
+
+else()
+ message( STATUS "python found, CMAKE_PYTHON_INSTALL_TYPE=${CMAKE_PYTHON_INSTALL_TYPE}")
+
+ # -------------------------------------------------------------------------------------
+ # Install using setup.py
+ # See: http://bloerg.net/2012/11/10/cmake-and-distutils.html
+ # -------------------------------------------------------------------------------------
+ message(STATUS "python install using *setup.py* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
+ message(STATUS "CMAKE_CURRENT_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}")
+ message(STATUS "CMAKE_BINARY_DIR=${CMAKE_BINARY_DIR}")
+ message(STATUS "CMAKE_PYTHON_INSTALL_PREFIX : ${CMAKE_PYTHON_INSTALL_PREFIX}" )
+
+ set(SETUP_PY_IN "${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in")
+ set(SETUP_PY "${CMAKE_CURRENT_SOURCE_DIR}/setup.py")
+ set(DEPS "${CMAKE_CURRENT_SOURCE_DIR}/ecflow/__init__.py")
+ set(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/timestamp")
+
+ configure_file(${SETUP_PY_IN} ${SETUP_PY} )
+
+ add_custom_command(OUTPUT ${OUTPUT}
+ COMMAND ${PYTHON} ${SETUP_PY} build
+ COMMAND ${CMAKE_COMMAND} -E touch ${OUTPUT}
+ DEPENDS ${DEPS})
+ add_custom_target(target ALL DEPENDS ${OUTPUT})
+
+
+ install(CODE "execute_process(COMMAND ${PYTHON} ${SETUP_PY} build_ext)")
+
+ if( DEFINED CMAKE_PYTHON_INSTALL_PREFIX )
+ message(STATUS "custom/*test* python install prefix defined CMAKE_PYTHON_INSTALL_PREFIX=${CMAKE_PYTHON_INSTALL_PREFIX}")
+ install(CODE "execute_process(COMMAND ${PYTHON} ${SETUP_PY} install -f --prefix=${CMAKE_PYTHON_INSTALL_PREFIX})")
+ else()
+ install(CODE "execute_process(COMMAND ${PYTHON} ${SETUP_PY} install)")
+ endif()
+endif()
diff --git a/Pyext/ecflow/__init__.py b/Pyext/ecflow/__init__.py
new file mode 100755
index 0000000..5ff5c6b
--- /dev/null
+++ b/Pyext/ecflow/__init__.py
@@ -0,0 +1,18 @@
+from ecflow import *
+
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+"""
+The ecFlow python module
+"""
+
+# http://stackoverflow.com/questions/13040646/how-do-i-create-documentation-with-pydoc
diff --git a/Pyext/jamfile.jam b/Pyext/jamfile.jam
new file mode 100755
index 0000000..4371ed2
--- /dev/null
+++ b/Pyext/jamfile.jam
@@ -0,0 +1,206 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+# =============================================================================
+# This jam file, allows for creation of ecflow python extension module, where
+# we have a STATIC link to boost python
+# ===============================================================================
+
+# ===============================================================================
+# Error to watch out for:
+# error: No best alternative for /python_for_extensions
+# next alternative: required properties: <python>2.7 <target-os>linux
+# matched
+# next alternative: required properties: <python>2.7 <target-os>linux
+# matched
+#
+# Please check if you have more than one 'using python' in configuration files.
+# Please check site-config.jam, user-config.jam and project-config.jam and
+# remove duplicated 'using python'
+#
+# When installing BOOST-python libs, make sure to call module load python *FIRST*
+# Otherwise it will pick the python specified in project-config.jam, which make not be correct
+#
+# ===============================================================================
+
+#
+# jamfile for installing, building exposing c++ library to python.
+# and for testing embedded python
+#
+# Use of <dll-path> should force a relink. But this *ONLY* works for executables
+# and *NOT* shared libraries. The HACKY work around is use <dll-path> when
+# building the extension. Hence this requires that ECFLOW_INSTALL_DIR
+# is correctly set during build time. Yuk.
+#
+project thePyext ;
+
+use-project theCore : ../ACore ;
+use-project theNodeAttr : ../ANattr ;
+use-project theNode : ../ANode ;
+use-project theParser : ../AParser ;
+use-project theBase : ../Base ;
+use-project theClient : ../Client ;
+use-project theSimulator : ../CSim ;
+
+# Make the definition of the python-extension rule available
+import python ;
+
+if ! [ python.configured ]
+{
+ # ECHO "notice: no Python configured in user-config.jam" ;
+ # ECHO "notice: will use default configuration" ;
+ # We will typically place this in user-congig/site-config.jam
+ #using python
+ # : # version
+ # : # cmd-or-prefix
+ # : # includes
+ # : # libraries
+ # : # condition
+ # ;
+ using python ;
+}
+
+# Specify the path to the Boost project. If you move this project,
+# adjust this path to refer to the Boost root directory.
+import os ;
+local BOOST_ROOT = [ os.environ BOOST_ROOT ] ;
+use-project boost
+ : $(BOOST_ROOT) ;
+
+
+# ======================== libs ============================================
+# HPUX: ADD standard libs. They don't get added by default ?
+# Also on HPUX the shared libs appears reversed, and don't appear
+# in the order specified weird ?
+# Notice the use of <library> to add additional library on the link line
+# but only for HPUX/acc toolset
+# <ALL>: It appears the pthread lib is automatically added. i.e >lib pthread ;
+#
+
+lib std_v2 ;
+lib stream ;
+lib Csup ;
+lib unwind ;
+lib m ;
+alias hpux_std_libs : std_v2 stream Csup unwind m ;
+
+# ========================================================================
+# Extension: Declare a Python extension called ecflow.
+# ========================================================================
+python-extension ecflow : [ glob src/*.cpp ]
+ /theCore//core
+ /theNodeAttr//nodeattr
+ /theNode//node
+ /theParser//libparser
+ /theBase//base
+ /theClient//libclient
+ /theSimulator//libsimu
+ /site-config//boost_system
+ /site-config//boost_serialization
+ /site-config//boost_filesystem
+ /site-config//boost_program_options
+ /site-config//boost_datetime
+ /site-config//boost_python_static
+ : <variant>debug:<define>DEBUG
+ <toolset>acc:<library>hpux_std_libs
+ ;
+
+# ========================================================================
+# Documentation:
+# ========================================================================
+# Place the shared library 'ecflow' into the ecflow/ directory.
+# - *REQUIRED* for sphinx-build. Documentation generation See Doc/online/conf.py
+# We use this as first place to look for c++ extension
+# - avoids hard wired dependency on compiler path
+# - Picks up latest changes
+install ecflow/ : ecflow ;
+
+
+# ========================================================================
+# INSTALLATION:
+# ========================================================================
+# - install __init__.py file.
+# - This install is referenced in JamRoot.jam
+install install-py1
+ : [ glob ecflow/*.py ]
+ : <location>$(ECFLOW_DESTDIR)/$(ECFLOW_PYTHON_INSTALL_DIR)
+ ;
+
+# - <dll-path> for install Left in, in case its fixed in the future.
+# - This install is referenced in JamRoot.jam
+# - <install-dependencies>on will also install boost_python shared lib and add repath to it.
+install install-py
+ : ecflow
+ : <install-type>PYTHON_EXTENSION
+ <install-type>SHARED_LIB
+ <location>$(ECFLOW_DESTDIR)$(ECFLOW_PYTHON_INSTALL_DIR)
+ ;
+
+# make install explicit, otherwise we end installing for all calls to bjam
+explicit install-py1 ;
+explicit install-py ;
+
+
+# ========================================================================
+# TESTING: unit-tests and test for python fragments in online tutorial
+# ========================================================================
+import testing ;
+
+# A little "rule" (function) to clean up the syntax of declaring tests
+# of these extension modules.
+local rule run-test ( test-name : sources + )
+{
+ testing.make-test run-pyd : $(sources) : : $(test-name) ;
+}
+
+#
+# Declare test targets;
+# Note cant run TestWith until all plarforms support with statement, i.e python 2.6 or greater
+#
+run-test TestClientApi : ecflow [ glob test/py_s_TestClientApi.py ] ;
+run-test TestPythonChildApi : ecflow [ glob test/py_s_TestPythonChildApi.py ] ;
+run-test TestDefs : ecflow [ glob test/py_u_TestDefs.py ] ;
+run-test TestError : ecflow [ glob test/py_u_TestError.py ] ;
+run-test TestTraversal : ecflow [ glob test/py_u_TestTraversal.py ] ;
+run-test TestDefsCheck : ecflow [ glob test/py_u_TestDefsCheck.py ] ;
+run-test TestSimulator : ecflow [ glob test/py_u_TestSimulator.py ] ;
+run-test TestAddDelete : ecflow [ glob test/py_u_TestAddDelete.py ] ;
+run-test TestAddDeleteError : ecflow [ glob test/py_u_TestAddDeleteError.py ] ;
+run-test TestAddDeleteFunc : ecflow [ glob test/py_u_TestAddDeleteFunc.py ] ;
+run-test TestAddNodeFunc : ecflow [ glob test/py_u_TestAddNodeFunc.py ] ;
+run-test TestParent : ecflow [ glob test/py_u_TestParent.py ] ;
+run-test TestUserManual : ecflow [ glob test/py_u_TestUserManual.py ] ;
+run-test TestJobGeneration : ecflow [ glob test/py_u_TestJobGeneration.py ] ;
+run-test TestGetAllTasks : ecflow [ glob test/py_u_TestGetAllTasks.py ] ;
+run-test TestDerivable : ecflow [ glob test/py_u_TestDerivable.py ] ;
+run-test TestWith : ecflow [ glob test/py_u_TestWith.py ] ;
+run-test TestFind : ecflow [ glob test/py_u_TestFind.py ] ;
+run-test TestMigrate : ecflow [ glob migrate/py_u_TestMigrate.py ] ;
+run-test TestRepeatArithmetic : ecflow [ glob test/py_u_TestRepeatArithmetic.py ] ;
+run-test TestGeneratedVariable : ecflow [ glob test/py_u_TestGeneratedVariable.py ] ;
+run-test TestEcf : ecflow [ glob test/py_u_TestEcf.py ] ;
+run-test TestFlag : ecflow [ glob test/py_u_TestFlag.py ] ;
+
+# A target that runs all the tests.
+# Note test_embed & test_embed_ecf commented out since we dont use this functionality
+alias test-all
+ : TestUserManual TestJobGeneration TestDefs TestError TestTraversal TestDefsCheck
+ TestSimulator TestAddDelete TestAddDeleteError TestAddDeleteFunc TestAddNodeFunc TestParent TestGetAllTasks
+ TestDerivable TestMigrate TestRepeatArithmetic TestWith TestFind TestGeneratedVariable TestEcf
+ TestClientApi TestPythonChildApi TestFlag
+ # test_embed test_embed_ecf
+ ;
+
+# Only run tests when explicitly requested
+explicit test-all
+ TestUserManual TestJobGeneration TestDefs TestError TestTraversal TestDefsCheck
+ TestSimulator TestAddDelete TestAddDeleteError TestAddDeleteFunc TestAddNodeFunc TestParent TestGetAllTasks
+ TestDerivable TestMigrate TestRepeatArithmetic TestWith TestFind TestGeneratedVariable TestEcf
+ TestClientApi TestPythonChildApi TestFlag
+ # test_embed test_embed_ecf
+ ;
+
\ No newline at end of file
diff --git a/ecflow_4_0_7/Pyext/migrate/abort_and_label_bug.def b/Pyext/migrate/abort_and_label_bug.def
similarity index 100%
rename from ecflow_4_0_7/Pyext/migrate/abort_and_label_bug.def
rename to Pyext/migrate/abort_and_label_bug.def
diff --git a/ecflow_4_0_7/Pyext/migrate/aborted_reason_bug.def b/Pyext/migrate/aborted_reason_bug.def
similarity index 100%
rename from ecflow_4_0_7/Pyext/migrate/aborted_reason_bug.def
rename to Pyext/migrate/aborted_reason_bug.def
diff --git a/Pyext/migrate/ecflow_migrate.py b/Pyext/migrate/ecflow_migrate.py
new file mode 100644
index 0000000..5dff9ad
--- /dev/null
+++ b/Pyext/migrate/ecflow_migrate.py
@@ -0,0 +1,416 @@
+#!/usr/bin/env python2.7
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+import os # for getenv
+import shutil # used to remove directory tree
+#import argparse # requires python 2.7
+import getopt, sys # for argument parsing
+
+class Migrator(object):
+ def __init__(self, list_of_input_lines):
+ self.list_of_input_lines = list_of_input_lines
+ self.list_of_output_lines = []
+
+ def _migration_hook(self,default_version_number):
+ """Derived suite should override this function to perform the migration
+ """
+ return False;
+
+ def output_lines(self):
+ return self.list_of_output_lines
+
+ def migrate(self, default_version_number):
+ """Template/skeleton function, which will call the hooks
+ """
+ version = self.version_number_as_integer(default_version_number)
+ if version >= default_version_number:
+ self.list_of_output_lines = self.list_of_input_lines
+ return False
+
+ self.list_of_output_lines = []
+ migrated = self._migration_hook(default_version_number)
+ if migrated :
+ self.list_of_input_lines = self.list_of_output_lines # preserve this migration
+ print "Applying " + type(self).__name__
+ else:
+ self.list_of_output_lines = self.list_of_input_lines
+ return migrated
+
+ def version_number_as_integer(self,default_version):
+ """Determine the version number used in ecflow_client --migrate
+ This should be in the very first line
+ # 3.1.8
+ """
+ if len(self.list_of_input_lines) > 0:
+ tokens = self.list_of_input_lines[0].split()
+ if len(tokens) > 1:
+ # print tokens
+ version = (int)(tokens[1].replace(".",""))
+ # print "******************* found version " + str(version)
+ return version;
+ return default_version
+
+
+class MigrateForTaskAbort(Migrator):
+ """Fix bug where the task abort states(i.e a string) will contain new lines and hence
+ spill over the next line, and affecting the parser. This will move the abort string
+ into the same line, and remove the interleaving new lines
+ """
+ def __init__(self, list_of_input_lines):
+ Migrator.__init__(self, list_of_input_lines)
+
+ def _migration_hook(self,default_version_number):
+ """
+ The correct format is: where abort state is on the same line
+ task task # passwd:jxX0gIbR abort<: reason for abort >abort:
+ ensure_start_abort_and_end_abort_on_sameline
+ """
+ migrated = False
+ start_line_append = ""
+ for line in self.list_of_input_lines:
+ # process line
+ end_abort_pos = line.find(">abort")
+ task_pos = line.find("task")
+ if task_pos != -1:
+ start_abort_pos = line.find("abort<:")
+ if start_abort_pos != -1 and end_abort_pos != -1:
+ # start and end found on same line. This is the correct format
+ start_line_append = ""
+
+ if start_abort_pos != -1 and end_abort_pos == -1:
+ # print "start abort found with no end abort"
+ start_line_append = line
+ start_line_append = start_line_append.rstrip('\n')
+ start_line_append += " "
+ migrated = True
+ continue
+
+ if len(start_line_append) > 0:
+ start_line_append += line
+ if end_abort_pos != -1:
+ self.list_of_output_lines.append(start_line_append) # preserve'\n' for this case
+ # print start_line_append
+ start_line_append = "";
+ else:
+ start_line_append = start_line_append.rstrip('\n')
+ start_line_append += " "
+
+ continue;
+
+ self.list_of_output_lines.append(line)
+
+ return migrated
+
+
+class MigrateForLabel(Migrator):
+ """Fix bug where label value has new lines, and hence spills over to next line
+ This will remove place newline back onto the same line
+ """
+ def __init__(self, list_of_input_lines):
+ Migrator.__init__(self, list_of_input_lines)
+
+ def _migration_hook(self,default_version_number):
+ """
+ The correct format is where label in on the same line
+ label name "value" # "new value"
+ However if the value or new value has new line it can mess up the parsing
+ label info "have you? set START_LOBSVR=1 in the task, once, to launch the logserver,
+ setup ssh login
+ created remote /tmp/map/cray"
+ """
+ #count = 0;
+ no_of_label_quotes = 0
+ migrated = False
+ start_line_append = ""
+ for line in self.list_of_input_lines:
+ #count = count + 1
+ #print str(count) + ": " + line
+ #if count == 383119:
+ # print "debug mee"
+ if len(start_line_append) > 0:
+ no_of_label_quotes += line.count('"')
+ start_line_append += line
+ if no_of_label_quotes % 2 == 0:
+ # even number of quotes
+ self.list_of_output_lines.append(start_line_append) # preserve last '\n'
+ start_line_append = ""
+ no_of_label_quotes = 0
+ else:
+ start_line_append = start_line_append.rstrip('\n')
+ continue
+ else:
+
+ # process line
+ tokens = line.split()
+ if len(tokens) >0 and tokens[0] == "label":
+ no_of_label_quotes = line.count('"')
+ if no_of_label_quotes % 2 != 0 :
+ start_line_append = line
+ start_line_append = start_line_append.rstrip('\n')
+ migrated = True
+ continue
+
+ self.list_of_output_lines.append(line)
+
+ return migrated
+
+class MigrateForVariable(Migrator):
+ """Fix bug where variable value has new lines, and hence spills over to next line
+ This will remove place newline back onto the same line
+ """
+ def __init__(self, list_of_input_lines):
+ Migrator.__init__(self, list_of_input_lines)
+
+ def _migration_hook(self,default_version_number):
+ """
+ The correct format is where variable in on the same line
+ edit EMOS_TYPE ' family prod_wparam
+ endfamily
+'
+ """
+ #count = 0;
+ no_of_label_quotes = 0
+ migrated = False
+ start_line_append = ""
+ for line in self.list_of_input_lines:
+ #count = count + 1
+ #print str(count) + ": " + line
+ #if count == 383119:
+ # print "debug mee"
+ if len(start_line_append) > 0:
+ no_of_label_quotes += line.count("'")
+ start_line_append += line
+ if no_of_label_quotes % 2 == 0:
+ # even number of quotes
+ self.list_of_output_lines.append(start_line_append) # preserve last '\n'
+ start_line_append = ""
+ no_of_label_quotes = 0
+ else:
+ start_line_append = start_line_append.rstrip('\n')
+ continue
+ else:
+
+ # process line, avoid ECF_URL_CMD as that could by error have uneven number of "'' i.e
+ # edit ECF_URL_CMD '${BROWSER:=firefox} -remote 'openURL(%URL%'
+ # hence we use
+ # if no_of_label_quotes == 1:
+ # instead of
+ # if no_of_label_quotes % 2 == 0:
+ tokens = line.split()
+ if len(tokens) >= 3 and tokens[0] == "edit":
+ no_of_label_quotes = line.count("'")
+ if no_of_label_quotes == 1:
+ start_line_append = line
+ start_line_append = start_line_append.rstrip('\n')
+ migrated = True
+ continue
+
+ self.list_of_output_lines.append(line)
+
+ return migrated
+
+
+class MigrateForHistory(Migrator):
+ """Fix bug where history spans multiple lines.
+ See File: history_bug.def
+ """
+ def __init__(self, list_of_input_lines):
+ Migrator.__init__(self, list_of_input_lines)
+
+ def _migration_hook(self,default_version_number):
+ """
+ The history should all be on one line
+ defs_state MIGRATE state>:queued flag:message state_change:1500811 modify_change:48
+ edit ECF_LOG '/vol/emos_nc/output/ecflow/vali.21801.ecf.log'
+ edit SMSNAME '0'
+ history /s2s_devel/ecmf/back MSG:[15:53:06 21.10.2014] --replace=/s2s_devel/ecmf/back s2s_devel.def parent :emos
+ history /s2s_devel/ecmf/enfh MSG:[13:45:53 12.11.2014] -alter change label last_run 20140929
+ 20141002
+ 20141016
+ 20141023 /s2s_devel/ecmf/enfh/ :emos MSG:[14:05:53 14.11.2014] --requeue force /s2s_devel/ecmf/enfh :emos
+ history /s2s_devel/ecmf/enfh/back MSG:[13:38:30 11.11.2014] --alter change event doIt set /s2s_devel/ecmf/enfh/back :emos
+ suite limits # begun:1 state:complete flag:message suspended:1
+ endsuite
+ """
+ migrated = False
+ history_started = False
+ for line in self.list_of_input_lines:
+ # process line
+ tokens = line.split()
+ if len(tokens) >= 2 and tokens[0] == "suite":
+ history_started = False
+
+ if not history_started and len(tokens) >= 2 and tokens[0] == "history":
+ history_started = True
+
+ if history_started:
+ # append to previous line
+ if len(tokens) >= 1 and tokens[0] != "history":
+ # get last line of output lines, string the new line and append
+ self.list_of_output_lines[-1] = self.list_of_output_lines[-1].rstrip()
+ self.list_of_output_lines[-1] = self.list_of_output_lines[-1] + line
+ migrated = True
+ continue;
+
+ self.list_of_output_lines.append(line)
+
+ return migrated
+
+
+def do_migrate(defs_file):
+
+ migration_count = 0
+ fileName, fileExtension = os.path.splitext(defs_file)
+ output_file_name = fileName + ".mig";
+
+ input_file_object = open(defs_file,'r')
+ output_file_object = open(output_file_name,'w')
+ try:
+ list_of_input_lines = input_file_object.readlines() # preserves new lines, we want this
+
+ list_of_output_lines = []
+ abort_migrator = MigrateForTaskAbort(list_of_input_lines)
+ if abort_migrator.migrate(401):
+ migration_count += 1
+ # did migration, update input lines for next migration
+ list_of_input_lines = abort_migrator.output_lines()
+ list_of_output_lines = abort_migrator.output_lines()
+
+
+ label_migrator = MigrateForLabel(list_of_input_lines)
+ if label_migrator.migrate(319):
+ migration_count += 1
+ # did migration, update input lines for next migration
+ list_of_input_lines = label_migrator.output_lines()
+ list_of_output_lines = label_migrator.output_lines()
+
+
+ variable_migrator = MigrateForVariable(list_of_input_lines)
+ if variable_migrator.migrate(401):
+ migration_count += 1
+ # did migration, update input lines for next migration
+ list_of_input_lines = variable_migrator.output_lines()
+ list_of_output_lines = variable_migrator.output_lines()
+
+
+ variable_migrator = MigrateForHistory(list_of_input_lines)
+ if variable_migrator.migrate(406):
+ migration_count += 1
+ # did migration, update input lines for next migration
+ list_of_input_lines = variable_migrator.output_lines()
+ list_of_output_lines = variable_migrator.output_lines()
+
+ output_file_object.writelines(list_of_output_lines)
+ finally:
+ input_file_object.close()
+ output_file_object.close()
+
+ return migration_count
+
+def usage():
+ DESC = """\nThis python file is used to *FIX* migration bugs, when migrating from one release of ecflow to another.
+
+ Migration may be required when the release number changes:
+ <release-number>.<major>.<minor>
+ 6.1.7 -> 7.0.0
+ as the checkpoint files *may* not be compatible.
+
+ This can be *checked* before hand. By attempting to load the check pt into the new server.
+ On the old server run:
+ ecflow_client --check_pt # this will write out a checkpt file
+ Now copy this file to a separate directory, and start the *new* server using the same port number
+ If no errors are reported, you do not need to migrate.
+ If loading the checkpt file into the new server fails for any reason then
+ then please follow these steps.
+
+ Steps for Old server:
+ o shutdown
+ # ecflow_client --shutdown
+ o suspend all suites
+ # CL="ecflow_client --port=32222 --host=vsms1"
+ # for s in $($CL --suites); do $CL --suspend=/$s; done
+ o wait for active/submitted tasks to complete
+ o halt the server
+ # ecflow_client --halt=yes
+ o Use --migrate to dump state and structure to a file
+ # ecflow_client --migrate > all_suites.def
+ o terminate server *or* leave server running but start new server on different machine
+ to avoid port number clash.
+ o remove checkpt and backup checkpt files, to prevent new server from loading them
+ *Only* applicable if starting new server on same machine
+ o Run this script
+ python ecflow_migrate.py -d all_suites.def
+ This will fix any issues associated with reloading this defs into the new server.
+ It write a file called 'all_suites.mig', which we will need to load into the new server.
+ See below.
+
+ Steps for New server:
+ o start server
+ o load the migration file
+ # ecflow_client --load all_suites.mig
+ o set server running:
+ # ecflow_client --restart
+ o resume suspended suites
+ # CL="ecflow_client --port=32222 --host=vsms1"
+ # for s in $($CL --suites); do $CL --resume=/$s; done
+
+
+ There could be bugs with *old* "ecflow_client --migrate > all_suites.def"
+ This file, will fix any bugs associated --migrate, so that the subsequent
+ load with *new* client (ecflow_client --load all_suites.mig) will work
+
+ Usage:
+ python ecflow_migrate.py --defs_file <filename>
+ python ecflow_migrate.py --d <filename>
+ python ecflow_migrate.py --defs_file all_suites.def
+
+ The fixed definition is written as filename.mig, i.e. all_suites.mig
+ """
+ return DESC;
+
+
+if __name__ == "__main__":
+
+# PARSER = argparse.ArgumentParser(description=usage(),
+# formatter_class=argparse.RawDescriptionHelpFormatter)
+# PARSER.add_argument('defs_file', help="The definition file to *fix* for migration")
+# ARGS = PARSER.parse_args()
+# ARGS.defs_file = os.path.expandvars(ARGS.defs_file) # expand references to any environment variables
+# print ARGS
+# do_migrate( ARGS.defs_file )
+
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "hd", ["help", "defs_file="])
+ except getopt.GetoptError as err:
+ # print help information and exit:
+ print(err) # will print something like "option -a not recognised"
+ print usage()
+ sys.exit(2)
+
+ defs_file = None
+ for o, a in opts:
+ if o in ("-h", "--help"):
+ print usage()
+ sys.exit()
+ elif o in ("-d", "--defs_file"):
+ defs_file = a
+ else:
+ assert False, "un-handled option"
+
+ if defs_file == None:
+ print "Please enter path to the defs file i.e ecflow_migrate --d ./defs_file.def"
+ sys.exit(1)
+
+ defs_file = os.path.expandvars(defs_file); # expand references to any environment variables
+ do_migrate( defs_file )
diff --git a/ecflow_4_0_7/Pyext/migrate/history_bug.def b/Pyext/migrate/history_bug.def
similarity index 100%
rename from ecflow_4_0_7/Pyext/migrate/history_bug.def
rename to Pyext/migrate/history_bug.def
diff --git a/ecflow_4_0_7/Pyext/migrate/label_bug.def b/Pyext/migrate/label_bug.def
similarity index 100%
rename from ecflow_4_0_7/Pyext/migrate/label_bug.def
rename to Pyext/migrate/label_bug.def
diff --git a/ecflow_4_0_7/Pyext/migrate/no_migration.def b/Pyext/migrate/no_migration.def
similarity index 100%
rename from ecflow_4_0_7/Pyext/migrate/no_migration.def
rename to Pyext/migrate/no_migration.def
diff --git a/Pyext/migrate/py_u_TestMigrate.py b/Pyext/migrate/py_u_TestMigrate.py
new file mode 100644
index 0000000..5133a8b
--- /dev/null
+++ b/Pyext/migrate/py_u_TestMigrate.py
@@ -0,0 +1,192 @@
+
+import os
+import ecflow_migrate
+import unittest
+import filecmp
+
+def get_parent_dir(file_path):
+ return os.path.dirname(file_path)
+
+def get_root_source_dir():
+ cwd = os.getcwd()
+ #print "get_root_source_dir from: " + cwd
+ while (1):
+ # Get to directory that has ecflow
+ head, tail = os.path.split(cwd)
+ #print " head:" + head
+ #print " tail:" + tail
+ if tail.find("ecflow") != -1 :
+
+ # bjam, already at the source directory
+ if os.path.exists(cwd + "/VERSION.cmake"):
+ print " Found VERSION.cmake in " + cwd
+ return cwd
+
+ if tail != "Pyext" and tail != "migrate":
+ # in cmake, we may be in the build directory, hence we need to determine source directory
+ file = cwd + "/CTestTestfile.cmake"
+ #print " searching for " + file
+ if os.path.exists(file):
+ # determine path by looking into this file:
+ for line in open(file):
+ ## Source directory: /tmp/ma0/workspace/ecflow/ACore
+ if line.find("Source directory"):
+ tokens = line.split()
+ if len(tokens) == 4:
+ #print " returning root_source_dir:", tokens[3]
+ return tokens[3]
+ raise RuntimeError("ERROR could not find Source directory in CTestTestfile.cmake")
+ else:
+ raise RuntimeError("ERROR could not find file CTestTestfile.cmake in " + cwd)
+
+ cwd = head
+ return cwd
+
+
+
+# These tests the migration for ecflow < 318 to ecflow 318
+#
+# In ecflow_client --migrate, we can get abort reason to span multiple line, hence messing up load
+#
+class TestMigrate318(unittest.TestCase):
+ def setUp(self):
+ # perform setup actions if any
+ self.workspace_dir = get_root_source_dir()
+ #print "setup : " + self.workspace_dir
+
+ def tearDown(self):
+ # Perform clean -up actions if any
+ pass
+
+ def locate(self,file):
+ return self.workspace_dir + "/Pyext/" + file
+
+ def testMigrateVersionNumber(self):
+ list_of_defs_lines =[ "# 3.1.2"]
+
+ mig = ecflow_migrate.Migrator(list_of_defs_lines)
+ self.assertEqual(mig.version_number_as_integer(0), 312,"expected version 3.1.2")
+
+ list_of_defs_lines =[ "# "]
+ mig = ecflow_migrate.Migrator(list_of_defs_lines)
+ self.assertEqual(mig.version_number_as_integer(10), 10,"Expected 10, since valid version not provided")
+
+ def test_no_migration(self):
+ migration_count = ecflow_migrate.do_migrate(self.locate("migrate/no_migration.def"))
+ self.assertEqual(migration_count,0,"Expected no migration")
+ self.assertTrue(filecmp.cmp(self.locate("migrate/no_migration.def"),self.locate("migrate/no_migration.mig")))
+ # remove the generated file
+ try: os.remove(self.locate("migrate/no_migration.mig"))
+ except: pass
+
+# ==============================================================================================
+ # Test for abort bug
+
+ def test_normal_abort_case(self):
+ list_of_defs_lines = [ "# 3.1.2", "task task abort<: aa >abort\n" ]
+ abort_migrator = ecflow_migrate.MigrateForTaskAbort(list_of_defs_lines)
+ abort_migrator.migrate(318)
+
+ expected_output_lines = ["# 3.1.2", "task task abort<: aa >abort\n"]
+ self.assertEqual(abort_migrator.output_lines(),expected_output_lines)
+
+ def test_task_abort_reason_bug_simple(self):
+ list_of_defs_lines = ["# 3.1.2", "task task abort<: aa\n",">abort\n" ]
+ abort_migrator = ecflow_migrate.MigrateForTaskAbort(list_of_defs_lines)
+ abort_migrator.migrate(318)
+
+ expected_output_lines = ["# 3.1.2","task task abort<: aa >abort\n"]
+ self.assertEqual(abort_migrator.output_lines(),expected_output_lines)
+
+ def test_task_abort_reason_bug(self):
+ # In ecflow_client --migrate, we can get abort reason to span multiple line, hence messing up load
+ list_of_defs_lines = ["# 3.1.2","task task # passwd:jxX0gIbR abort<: Script for /suite/family/task can not be found:\n",
+ "line2\n", "line3\n",">abort try:2 state:aborted dur:02:19:57 flag:task_aborted,no_script\n" ]
+
+ abort_migrator = ecflow_migrate.MigrateForTaskAbort(list_of_defs_lines)
+ abort_migrator.migrate(318)
+
+ expected_output_lines = ["# 3.1.2","task task # passwd:jxX0gIbR abort<: Script for /suite/family/task can not be found: line2 line3 >abort try:2 state:aborted dur:02:19:57 flag:task_aborted,no_script\n"]
+ self.assertEqual(abort_migrator.output_lines(),expected_output_lines)
+
+ def test_migrate_abort_file(self):
+ migration_count = ecflow_migrate.do_migrate(self.locate("migrate/aborted_reason_bug.def"))
+ self.assertEqual(migration_count,1,"Expected defs file to be migrated")
+
+ # remove the generated file
+ try: os.remove(self.locate("migrate/aborted_reason_bug.mig"))
+ except: pass
+
+# ===============================================================================================
+
+ def test_normal_label(self):
+ list_of_defs_lines = ["# 3.1.2","label name \"value\"\n" ]
+
+ migrator = ecflow_migrate.MigrateForLabel(list_of_defs_lines)
+ migrator.migrate(319)
+
+ expected_output_lines = ["# 3.1.2","label name \"value\"\n" ]
+ self.assertEqual(migrator.output_lines(),expected_output_lines)
+
+ def test_label_over_multiple_lines(self):
+ list_of_defs_lines = ["# 3.1.2","label name \"value1\n", "value2\n", "value3\"\n" ]
+
+ migrator = ecflow_migrate.MigrateForLabel(list_of_defs_lines)
+ migrator.migrate(319)
+
+ expected_output_lines = ["# 3.1.2","label name \"value1value2value3\"\n" ]
+ self.assertEqual(migrator.output_lines(),expected_output_lines)
+
+ def test_label_over_multiple_lines_with_state(self):
+ list_of_defs_lines = ["# 3.1.2","label name \"value1\n", "value2\n", "value3\" # \"value4\n", "value5\"\n" ]
+
+ migrator = ecflow_migrate.MigrateForLabel(list_of_defs_lines)
+ migrator.migrate(319)
+
+ expected_output_lines = ["# 3.1.2","label name \"value1value2value3\" # \"value4value5\"\n" ]
+ self.assertEqual(migrator.output_lines(),expected_output_lines)
+
+
+ def test_migrate_label_file(self):
+ migration_count = ecflow_migrate.do_migrate(self.locate("migrate/label_bug.def"))
+ self.assertEqual(migration_count,1,"Expected defs file to be migrated")
+
+ # remove the generated file
+ try: os.remove(self.locate("migrate/label_bug.mig"))
+ except: pass
+
+ def test_migrate_variable_file(self):
+ migration_count = ecflow_migrate.do_migrate(self.locate("migrate/variable_bug.def"))
+ self.assertEqual(migration_count,1,"Expected defs file to be migrated")
+
+ # remove the generated file
+ try: os.remove(self.locate("migrate/variable_bug.mig"))
+ except: pass
+
+# ====================================================================================================
+# test both together
+
+ def test_migrate_abort_and_label(self):
+ migration_count = ecflow_migrate.do_migrate(self.locate("migrate/abort_and_label_bug.def"))
+ self.assertEqual(migration_count,2,"Expected 2 migrations, one for abort and one for label")
+
+ # remove the generated file
+ try: os.remove(self.locate("migrate/abort_and_label_bug.mig"))
+ except: pass
+
+#====================================================================================================
+#test history
+
+ def test_migrate_history(self):
+ print "test_migrate_history"
+ migration_count = ecflow_migrate.do_migrate(self.locate("migrate/history_bug.def"))
+ self.assertEqual(migration_count,1,"Expected 1 migrations,for history")
+
+ # remove the generated file
+ try: os.remove(self.locate("migrate/history_bug.mig"))
+ except: pass
+
+#run the tests
+if __name__ == '__main__':
+ #print "Current working directory: " + os.getcwd()
+ unittest.main()
\ No newline at end of file
diff --git a/ecflow_4_0_7/Pyext/migrate/variable_bug.def b/Pyext/migrate/variable_bug.def
similarity index 100%
rename from ecflow_4_0_7/Pyext/migrate/variable_bug.def
rename to Pyext/migrate/variable_bug.def
diff --git a/Pyext/samples/ListVariables.py b/Pyext/samples/ListVariables.py
new file mode 100755
index 0000000..53b0efa
--- /dev/null
+++ b/Pyext/samples/ListVariables.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python2.7
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+import ecflow
+import argparse # for argument parsing
+
+if __name__ == "__main__":
+
+ DESC = """Will list variables for any node
+ Usage:
+ Example1: List all the server variables
+ ListVariables.py --host cca --port 4141 --path /
+
+ Example2: List the variables for the given node
+ ListVariables.py --host cca --port 4141 --path /path/to/node
+ """
+ PARSER = argparse.ArgumentParser(description=DESC,
+ formatter_class=argparse.RawDescriptionHelpFormatter)
+ PARSER.add_argument('--host', default="localhost",
+ help="The name of the host machine, defaults to 'localhost'")
+ PARSER.add_argument('--port', default="3141",
+ help="The port on the host, defaults to 3141")
+ PARSER.add_argument('--path', default="/",
+ help="The path to the node. i.e /suite/family/task")
+ ARGS = PARSER.parse_args()
+ #print ARGS
+
+ # ===========================================================================
+ CL = ecflow.Client(ARGS.host, ARGS.port)
+ try:
+ CL.ping()
+
+ # get the incremental changes, and merge with defs stored on the Client
+ CL.sync_local()
+
+ # check to see if definition exists in the server
+ defs = CL.get_defs()
+ if defs == None :
+ print "No definition found, exiting..."
+ exit(0)
+
+ # print defs;
+ if ARGS.path == "/":
+ for var in defs.server_variables: print "edit " + var.name() + " '" + var.value() + "'"
+ for var in defs.user_variables: print "edit " + var.name() + " '" + var.value() + "'"
+ else:
+ node = defs.find_abs_node(ARGS.path)
+ if node == None:
+ print "No node found at path " + ARGS.path
+ else:
+ for var in node.variables: print "edit " + var.name() + " '" + var.value() + "'"
+
+ except RuntimeError, ex:
+ print "Error: " + str(ex)
+ print "Check host and port number are correct."
diff --git a/Pyext/samples/TestBench.py b/Pyext/samples/TestBench.py
new file mode 100644
index 0000000..fc04b1c
--- /dev/null
+++ b/Pyext/samples/TestBench.py
@@ -0,0 +1,204 @@
+#!/usr/bin/env python2.7
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+# =============================================================================
+# Code for testing *any* definition
+# Since any ad hoc definition will reference local directories in the
+# ECF_ variables, we need to remove them and inject our own.
+#
+# This script is re-runnable, and hence will delete suites in the server
+# matching those in the input definition. Hence it is best to use this
+# script with a *test* server to avoid accidentally deleting existing suites
+# of the same name.
+# =============================================================================
+import ecflow
+import os # for getenv
+import shutil # used to remove directory tree
+import argparse # for argument parsing
+
+def delete_variables_affecting_job_generation(node):
+ """delete customer related ECF variables, these will point to directories
+ that don't exist. Its ok we will regenerate our own local ones"""
+ var = node.find_variable("ECF_HOME")
+ if not var.empty() :
+ node.delete_variable("ECF_HOME")
+ var = node.find_variable("ECF_FILES")
+ if not var.empty() :
+ node.delete_variable("ECF_FILES")
+ var = node.find_variable("ECF_INCLUDE")
+ if not var.empty() :
+ node.delete_variable("ECF_INCLUDE")
+ var = node.find_variable("ECF_JOB_CMD")
+ if not var.empty() :
+ node.delete_variable("ECF_JOB_CMD")
+ var = node.find_variable("ECF_KILL_CMD")
+ if not var.empty() :
+ node.delete_variable("ECF_KILL_CMD")
+ var = node.find_variable("ECF_STATUS_CMD")
+ if not var.empty() :
+ node.delete_variable("ECF_STATUS_CMD")
+ var = node.find_variable("ECF_OUT")
+ if not var.empty() :
+ node.delete_variable("ECF_OUT")
+
+def traverse_container(node_container):
+ """Recursively traverse definition node hierarchy and delete
+ the variables that affect job generation.
+ """
+ delete_variables_affecting_job_generation(node_container)
+ for node in node_container.nodes:
+ delete_variables_affecting_job_generation(node)
+ if not isinstance(node, ecflow.Task):
+ traverse_container(node)
+
+if __name__ == "__main__":
+
+ DESC = """Will allow any definition to be loaded and played on the server
+ This is done by:
+ o Remove existing ECF_ variables that affect job generation.
+ i.e variables that refer to customer specific directories are removed
+ o Allows ECF_HOME to specified, defaults to ./CUSTOMER/ECF_HOME
+ o Generates the scripts(.ecf files) automatically based on the definition.
+ i.e if a task has events,meters,labels then the client request for these are
+ automatically injected in the generated .ecf script files
+ o Will clear out existing data both on disk and on the server to allow
+ multiple re-runs of this script. ** If this is an issue please use
+ a test server **
+ o All suites are put into a suspended state. This allows the GUI to resume them
+ o The server is restarted and suites are begun
+ This programs assumes that ecflow module is accessible.
+ """
+ PARSER = argparse.ArgumentParser(description=DESC,
+ formatter_class=argparse.RawDescriptionHelpFormatter)
+ PARSER.add_argument('defs_file',
+ help="The definition file")
+ PARSER.add_argument('--host', default="localhost",
+ help="The name of the host machine, defaults to 'localhost'")
+ PARSER.add_argument('--port', default="3141",
+ help="The port on the host, defaults to 3141")
+ PARSER.add_argument('--path', default="/",
+ help="replace only the node path in the suite")
+ PARSER.add_argument('--ecf_home', default=os.getcwd() + "/CUSTOMER/ECF_HOME",
+ help="Directory to be used for generated scripts(ECF_HOME), defaults to ./CUSTOMER/ECF_HOME")
+ PARSER.add_argument('--verbose', nargs='?', default=False, const=True, type=bool,
+ help="Show verbose output")
+ ARGS = PARSER.parse_args()
+ ARGS.defs_file = os.path.expandvars(ARGS.defs_file) # expand references to any environment variables
+ print ARGS
+
+ # If running on local work space, use /Pyext/test/data/CUSTOMER/ECF_HOME as ecf_home
+ if not ARGS.ecf_home:
+ if os.getenv("WK") == None:
+ print "No ecf_home specified. Please specify a writable directory"
+ exit(1)
+ ARGS.ecf_home = os.getenv("WK") + "/Pyext/test/data/CUSTOMER/ECF_HOME"
+ if ARGS.verbose:
+ print "Workspace is defined"
+ print "using /Client/bin/gcc\-4.8/debug/ecflow_client"
+
+ if ARGS.verbose:
+ print "Using ECF_HOME=" + ARGS.ecf_home
+
+ if ARGS.verbose:
+ print "\nloading the definition from the input arguments(" + ARGS.defs_file + ")\n"
+ try:
+ DEFS = ecflow.Defs(ARGS.defs_file)
+ except RuntimeError, ex:
+ print " ecflow.Defs(" + ARGS.defs_file + ") failed:\n" + str(ex)
+ exit(1)
+
+ if ARGS.verbose:
+ print "remove test data associated with the DEFS, so we start fresh, Allows rerun"
+ for suite in DEFS.suites:
+ dir_to_remove = ARGS.ecf_home + suite.get_abs_node_path()
+ if ARGS.verbose:
+ print " Deleting directory: " + dir_to_remove + "\n"
+ shutil.rmtree(dir_to_remove, True)
+
+ if ARGS.verbose:
+ print "remove remote reference to ECF_HOME and ECF_INCLUDE, since we inject or own\n"
+ for suite in DEFS.suites:
+ traverse_container(suite)
+
+ if ARGS.verbose:
+ print "add variables required for script generation, for all suites\n"
+ DEFS.add_variable("ECF_HOME", ARGS.ecf_home)
+ if os.getenv("WK") != None:
+ debug_path = os.getenv("WK") + "/Client/bin/gcc-4.8/debug/ecflow_client"
+ release_path = os.getenv("WK") + "/Client/bin/gcc-4.8/debug/ecflow_client"
+ if os.path.exists( debug_path ):
+ DEFS.add_variable("ECF_CLIENT_EXE_PATH", debug_path )
+ else:
+ if os.path.exists( release_path ):
+ DEFS.add_variable("ECF_CLIENT_EXE_PATH", release_path )
+
+ DEFS.add_variable("SLEEP", "10") # not strictly required since default is 1 second
+ DEFS.add_variable("ECF_INCLUDE", ARGS.ecf_home + "/includes")
+
+
+ if ARGS.verbose:
+ print "Place all suites into suspended state, so they can be started by the GUI\n"
+ for suite in DEFS.suites:
+ suite.add_defstatus(ecflow.DState.suspended)
+
+ # ecflow.PrintStyle.set_style(ecflow.Style.STATE)
+ if ARGS.verbose:
+ print DEFS
+
+ if ARGS.verbose:
+ print "Generating script files(.ecf) from the definition"
+ DEFS.generate_scripts()
+
+ if ARGS.verbose:
+ print "\nchecking script file generation, pre-processing & variable substitution\n"
+ JOB_CTRL = ecflow.JobCreationCtrl()
+ DEFS.check_job_creation(JOB_CTRL)
+ assert len(JOB_CTRL.get_error_msg()) == 0, JOB_CTRL.get_error_msg()
+
+ # ===========================================================================
+ CL = ecflow.Client(ARGS.host, ARGS.port)
+ try:
+ if ARGS.verbose:
+ print "check server " + ARGS.host + ":" + ARGS.port + " is running"
+ CL.ping()
+
+ if ARGS.verbose:
+ print "Server is already running. re-start the server"
+ CL.restart_server()
+
+ if ARGS.verbose:
+ print "Remove suites associated with this DEFS, allows rerun *******************************************"
+ for suite in DEFS.suites:
+ try:
+ CL.delete(suite.get_abs_node_path(), True)
+ except RuntimeError, ex:
+ pass # For first run this will fail, hence ignore
+
+ if ARGS.verbose:
+ print "Load the definition into " + ARGS.host + ":" + ARGS.port
+ if ARGS.path == "/":
+ CL.load(DEFS)
+ else:
+ CL.replace(ARGS.path, DEFS)
+
+ if ARGS.verbose:
+ print "Begin all suites. They should be suspended."
+ print "Loaded suites:"
+ for suite in DEFS.suites:
+ CL.begin_suite(suite.name())
+ print " " + suite.name()
+ print "into server " + ARGS.host \
+ + ":" + ARGS.port + ", please view the playable suites in the GUI"
+ except RuntimeError, ex:
+ print "Error: " + str(ex)
diff --git a/Pyext/samples/TestJobGenPerf.py b/Pyext/samples/TestJobGenPerf.py
new file mode 100644
index 0000000..412eaba
--- /dev/null
+++ b/Pyext/samples/TestJobGenPerf.py
@@ -0,0 +1,155 @@
+#!/usr/bin/env python2.7
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+# =============================================================================
+# Code for testing *any* definition
+# Since any ad hoc definition will reference local directories in the
+# ECF_ variables, we need to remove them and inject our own.
+#
+# This test was created aid the performance testing of job generation
+# It is tied to AParser/test/TestJobGenPerf.cpp
+# =============================================================================
+import ecflow
+import os # for getenv
+import shutil # used to remove directory tree
+import argparse # for argument parsing
+
+def delete_variables_affecting_job_generation(node):
+ """delete customer related ECF variables, these will point to directories
+ that don't exist. Its ok we will regenerate our own local ones"""
+ var = node.find_variable("ECF_HOME")
+ if not var.empty() :
+ node.delete_variable("ECF_HOME")
+ var = node.find_variable("ECF_FILES")
+ if not var.empty() :
+ node.delete_variable("ECF_FILES")
+ var = node.find_variable("ECF_INCLUDE")
+ if not var.empty() :
+ node.delete_variable("ECF_INCLUDE")
+ var = node.find_variable("ECF_JOB_CMD")
+ if not var.empty() :
+ node.delete_variable("ECF_JOB_CMD")
+ var = node.find_variable("ECF_KILL_CMD")
+ if not var.empty() :
+ node.delete_variable("ECF_KILL_CMD")
+ var = node.find_variable("ECF_STATUS_CMD")
+ if not var.empty() :
+ node.delete_variable("ECF_STATUS_CMD")
+ var = node.find_variable("ECF_OUT")
+ if not var.empty() :
+ node.delete_variable("ECF_OUT")
+
+def traverse_container(node_container):
+ """Recursively traverse definition node hierarchy and delete
+ the variables that affect job generation.
+ """
+ delete_variables_affecting_job_generation(node_container)
+ for node in node_container.nodes:
+ delete_variables_affecting_job_generation(node)
+ if not isinstance(node, ecflow.Task):
+ traverse_container(node)
+
+if __name__ == "__main__":
+
+ DESC = """Will allow any definition to be loaded and played on the server
+ This is done by:
+ o Remove existing ECF_ variables that affect job generation.
+ i.e variables that refer to customer specific directories are removed
+ o Allows ECF_HOME to specified, defaults to ./CUSTOMER/ECF_HOME
+ o Generates the scripts(.ecf files) automatically based on the definition.
+ i.e if a task has events,meters,labels then the client request for these are
+ automatically injected in the generated .ecf script files
+ o Will clear out existing data both on disk and on the server to allow
+ multiple re-runs of this script. ** If this is an issue please use
+ a test server **
+ This programs assumes that ecflow module is accessible.
+ """
+ PARSER = argparse.ArgumentParser(description=DESC,
+ formatter_class=argparse.RawDescriptionHelpFormatter)
+ PARSER.add_argument('defs_file',
+ help="The definition file")
+ PARSER.add_argument('--ecf_home', default="/var/tmp/ma0/ECFLOW_TEST/TestJobGenPerf/ECF_HOME",
+ help="Directory to be used for generated scripts(ECF_HOME), defaults to /var/tmp/ma0/ECFLOW_TEST/TestJobGenPerf/ECF_HOME")
+ PARSER.add_argument('--verbose', nargs='?', default=False, const=True, type=bool,
+ help="Show verbose output")
+ ARGS = PARSER.parse_args()
+ ARGS.defs_file = os.path.expandvars(ARGS.defs_file) # expand references to any environment variables
+ print ARGS
+
+ # If running on local work space, use /Pyext/test/data/CUSTOMER/ECF_HOME as ecf_home
+ if not ARGS.ecf_home:
+ if os.getenv("WK") == None:
+ print "No ecf_home specified. Please specify a writable directory"
+ exit(1)
+ ARGS.ecf_home = "/var/tmp/ma0/ECFLOW_TEST/TestJobGenPerf/ECF_HOME"
+ if ARGS.verbose:
+ print "Workspace is defined"
+ print "using /Client/bin/gcc\-4.5/debug/ecflow_client"
+
+ print "Using ECF_HOME=" + ARGS.ecf_home
+ print "removing directory " + ARGS.ecf_home
+ try:
+ shutil.rmtree(ARGS.ecf_home)
+ except:
+ pass
+
+ if not os.path.exists(ARGS.ecf_home):
+ print ARGS.ecf_home + " directory does not exist, creating"
+ os.makedirs(ARGS.ecf_home)
+
+ print "\nloading the definition from the input arguments(" + ARGS.defs_file + ")\n"
+
+ try:
+ DEFS = ecflow.Defs(ARGS.defs_file)
+ except RuntimeError, ex:
+ print " ecflow.Defs(" + ARGS.defs_file + ") failed:\n" + str(ex)
+ exit(1)
+
+ if ARGS.verbose:
+ print "remove test data associated with the DEFS, so we start fresh, Allows rerun"
+ for suite in DEFS.suites:
+ dir_to_remove = ARGS.ecf_home + suite.get_abs_node_path()
+ if ARGS.verbose:
+ print " Deleting directory: " + dir_to_remove + "\n"
+ shutil.rmtree(dir_to_remove, True)
+
+ if ARGS.verbose:
+ print "remove remote reference to ECF_HOME and ECF_INCLUDE, since we inject or own\n"
+ for suite in DEFS.suites:
+ print "add variables required for script generation, for all suites\n"
+ traverse_container(suite)
+
+ suite.add_variable("ECF_HOME", ARGS.ecf_home)
+ suite.add_variable("ECF_INCLUDE", ARGS.ecf_home + "/includes")
+ suite.add_variable("ECF_CLIENT_EXE_PATH", os.getenv("WK") + "/Client/bin/gcc\-4.8/debug/ecflow_client")
+ suite.add_variable("SLEEP", "10") # not strictly required since default is 1 second
+
+
+
+ # ecflow.PrintStyle.set_style(ecflow.Style.STATE)
+ #if ARGS.verbose:
+ #print DEFS
+ DEFS.generate_scripts()
+
+ if ARGS.verbose:
+ print "\nchecking script file generation, pre-processing & variable substitution\n"
+ JOB_CTRL = ecflow.JobCreationCtrl()
+ DEFS.check_job_creation(JOB_CTRL)
+ assert len(JOB_CTRL.get_error_msg()) == 0, JOB_CTRL.get_error_msg()
+
+
+ newDefs = ARGS.ecf_home + "/../" + os.path.basename(ARGS.defs_file)
+ print "Saving modified defs as " + newDefs
+ DEFS.save_as_defs(newDefs)
+
diff --git a/Pyext/samples/TestServerGetDefs.py b/Pyext/samples/TestServerGetDefs.py
new file mode 100644
index 0000000..d92ea70
--- /dev/null
+++ b/Pyext/samples/TestServerGetDefs.py
@@ -0,0 +1,59 @@
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+# This test is a simple client that, repeatedly calls gets defs
+# This is used to stress test the server to determine how many defs
+# can be called before the server gets overloaded
+
+import datetime
+import time, sys
+from ecflow import Client
+
+def main(ci,inc = 2):
+ while True:
+ start_time = datetime.datetime.now()
+ try:
+ ci.get_server_defs()
+ except RuntimeError, e :
+ print "Error:" + str(e)
+
+ print "get_server_defs took: " + str(datetime.datetime.now() - start_time)
+ time.sleep(inc)
+
+if __name__ == "__main__":
+
+ numargs = len(sys.argv) - 1
+ #print "numargs = " + str(numargs)
+ #i = 0;
+ #while i < len(sys.argv):
+ #print "arg " + str(i) + ": " + sys.argv[i]
+ #i = i + 1
+
+ if numargs > 3:
+ print "usage: " + sys.argv[0] + " host port seconds_delay"
+ sys.exit(1)
+
+ port = "3142"
+ host = "localhost"
+ inc = 1
+ if numargs >= 1: host = sys.argv[1];
+ if numargs >= 2: port = sys.argv[2]
+ if numargs >= 3: inc = int(sys.argv[3])
+
+ #print "host(" + host + ") port(" + port + ") delay between get_server_defs(" + str(inc) +")"
+
+ ci = Client(host,port)
+ ci.ping()
+
+ main(ci,inc)
+
\ No newline at end of file
diff --git a/Pyext/samples/check_modules.py b/Pyext/samples/check_modules.py
new file mode 100755
index 0000000..1e3fb5d
--- /dev/null
+++ b/Pyext/samples/check_modules.py
@@ -0,0 +1,88 @@
+#!/usr/bin/env python2.7
+import argparse
+import re
+if __name__ == "__main__":
+ DESC = """Will check module are correct:
+ Usage:
+ ./check_modules.py --m "module load git module swap PrgEnv-cray PrgEnv-gnu " --f module_list_file
+ ./check_modules.py --m "module swap PrgEnv-cray PrgEnv-gnu" --f module_list_file
+ ./check_modules.py --m "module unload grib_api" --f module_list_file
+ """
+ PARSER = argparse.ArgumentParser(description=DESC,formatter_class=argparse.RawDescriptionHelpFormatter)
+ PARSER.add_argument('--m',help="The module command of some sort")
+ PARSER.add_argument('--f',help="Path to a file that is the output of module list")
+ PARSER.add_argument('--remote_host',help="remote host")
+ ARGS = PARSER.parse_args()
+ #print ARGS
+
+ delimter = "module"
+ module_cmds = [delimter+e for e in ARGS.m.split(delimter) if e != ""]
+ #print module_cmds
+
+ module_actions = ("load","add","rm","unload","swap","switch")
+ for mod in module_cmds:
+ module_cmd = mod.split()
+ #print ">>",module_cmd,"<<"
+ if len(module_cmd) < 3 and module_cmd[0] != "module":
+ print "Error: Module command ",module_cmds[0]," is not correctly formed, first string must be module"
+ exit(1)
+ if not module_cmd[1] in module_actions:
+ print "Error: Module command ",module_cmd," is not correctly formed, second arg must be one of add,load,rm,unload,switch,swap"
+ exit(1)
+
+ # open file,for list of modules,
+ # Currently Loaded Modulefiles:
+ # 1) version/3.2.10(default) 7) ecfs/2.2.1-rc2(new:prodn:default)
+ # 2) verbose/true(default) 8) metview/4.6.4(default)
+ # 3) mode/64(default) 9) ecaccess/4.0.2(default)
+ # 4) gnu/4.8.1(default) 10) fftw/3.3.4(default)
+ # 5) python/2.7.8-01(default) 11) emos/437(default)
+ # 6) sms/4.4.14(default) 12) ecmwf/1.0(default)
+
+ module_list = list()
+ module_list_file = open(ARGS.f)
+ try:
+ for line in module_list_file:
+ #print line
+ line = line.rstrip()
+ if line.find("Currently Loaded") == 0: continue;
+ tokens = re.split(r'\s|\d+\)',line)
+ while '' in tokens:
+ tokens.remove('')
+ #print tokens
+ for tok in tokens:
+ module_list.append(tok)
+ finally:
+ module_list_file.close()
+ #print module_list
+
+ for mod in module_cmds:
+ module_cmd = mod.split()
+ #print ">>",module_cmd,"<<"
+ if module_cmd[1] == "load" or module_cmd[1] == "add":
+ if not any(module_cmd[2] in s for s in module_list):
+ if ARGS.remote_host =="sappa" or ARGS.remote_host =="sappb":
+ if module_cmd[2] == "git": continue # ignore, uses system git
+ print "Error: package",module_cmd[2],"not found in the module list"
+ exit(1)
+ if module_cmd[1] == "swap" or module_cmd[1] == "switch":
+ # swap could be
+ # module swap PrgEnv-cray PrgEnv-gnu
+ # module swap cdt/15.06
+ expected_package = module_cmd[-1] # get last element
+ if not any(module_cmd[-1] in s for s in module_list):
+ print "Error: package",module_cmd[-1],"not found in the module list"
+ exit(1)
+ if module_cmd[1] == "unload" or module_cmd[1] == "rm":
+ if any(module_cmd[2] in s for s in module_list):
+ print "Error:",mod,"found in the module list"
+ exit(1)
+
+#
+# module list > module_list_file 2>&1 && less module_list_file
+# FAIL:
+# ./check_modules.py --m "module unload emos" --f module_list_file
+# ./check_modules.py --m "module load python module load xxx" --f module_list_file
+# PASS:
+# ./check_modules.py --m "module load python module swap fftw/3.3.1 fftw/3.3.4" --f module_list_file
+# ./check_modules.py --m "module load python module swap sms/4.4.14" --f module_list_file --remote_host sappa
diff --git a/Pyext/samples/cray.py b/Pyext/samples/cray.py
new file mode 100755
index 0000000..99ac7cb
--- /dev/null
+++ b/Pyext/samples/cray.py
@@ -0,0 +1,2175 @@
+#!/usr/bin/env python
+# -*- coding= UTF-8 -*-
+from __future__ import with_statement
+import sys, os, pwd, getopt
+sys.path.append('/home/ma/emos/def/o/def')
+import inc_emos as ic
+from ecf import *
+import ecf
+from inc_emos import Family, Task, Variables, Time, Meter, Event, Label, Late
+import sms2ecf
+
+# ecf.USE_TRIGGER = 0 # DEBUG MODE: do not load triggers
+
+def get_username():
+ return pwd.getpwuid( os.getuid() )[ 0 ]
+def get_uid():
+ return pwd.getpwnam(get_username()).pw_uid
+
+def create_wrapper(name, content):
+ print "#MSG: creating file %s/" % wdir + name
+ wrapper = open(wdir + "/%s" % name, 'w')
+ print >>wrapper, content
+ wrapper.close()
+##############################################
+
+# ic.SUBM = "/home/ma/emos/bin/smssubmit.cray"
+# ic.KILL = "/home/ma/emos/bin/smssubmit.cray"
+# ic.STAT = "/home/ma/emos/bin/smssubmit.cray"
+# sms2ecf.subm = "/home/ma/emos/bin/smssubmit.cray"
+# sms2ecf.kill = "/home/ma/emos/bin/smssubmit.cray"
+# sms2ecf.stat = "/home/ma/emos/bin/smssubmit.cray"
+
+def create_task():
+ ### PRODUCER/CONSUMER TASK
+ produce = '''#!/bin/ksh
+%manual
+ start - check - stop logsvr
+%end
+%include <qsub.h>
+%include <trap.h>
+
+step=%BEG:0%
+while [ $step -le %FIN:48% ]; do
+ if [[ %PRODUCE:1% = yes ]]; then
+ xevent p
+ elif [[ %CALL_WAITER:0% != 0 ]]; then
+case %ECF_PROG:0% in
+0) smswait %TRIGGER:1==1%;;
+*) ecflow_client --wait "%TRIGGER:1==1%";;
+esac
+ fi
+
+ if [[ %CONSUME:no% = yes ]]; then
+ xevent c
+ fi
+
+ xmeter step $step
+ step=$((step + %BY:1%))
+done
+
+%include <endt.h>
+'''
+ create_wrapper("produce.sms", produce)
+
+ create_wrapper("consume.sms", produce)
+ ### PURE PYTHON
+
+ head = """import os, time, signal
+import ecflow
+
+print "PYTHONPATH====================================================="
+print os.environ['PYTHONPATH'].split(os.pathsep)
+
+class Client(object):
+ ''' communication with the ecflow server. This will automatically call
+ the child command init()/complete(), for job start/finish. It will also
+ handle exceptions and signals, by calling the abort child command.
+ *ONLY* one instance of this class, should be used. Otherwise zombies will be created.
+ '''
+ def __init__(self):
+ print "Creating Client"
+ self.ci = ecflow.Client()
+ self.ci.set_host_port("$ECF_NODE$","$ECF_PORT$")
+ self.ci.set_child_pid(os.getpid())
+ self.ci.set_child_path("$ECF_NAME$")
+ self.ci.set_child_password("$ECF_PASS$")
+ self.ci.set_child_try_no($ECF_TRYNO$)
+
+ print "Only wait 20 seconds, if the server cannot be contacted (note default is 24 hours) before failing"
+ self.ci.set_child_timeout(20)
+
+ # Abort the task for the following signals
+ signal.signal(signal.SIGINT, self.signal_handler)
+ signal.signal(signal.SIGHUP, self.signal_handler)
+ signal.signal(signal.SIGQUIT, self.signal_handler)
+ signal.signal(signal.SIGILL, self.signal_handler)
+ signal.signal(signal.SIGTRAP, self.signal_handler)
+ signal.signal(signal.SIGIOT, self.signal_handler)
+ signal.signal(signal.SIGBUS, self.signal_handler)
+ signal.signal(signal.SIGFPE, self.signal_handler)
+ signal.signal(signal.SIGUSR1, self.signal_handler)
+ signal.signal(signal.SIGUSR2, self.signal_handler)
+ signal.signal(signal.SIGPIPE, self.signal_handler)
+ signal.signal(signal.SIGTERM, self.signal_handler)
+ signal.signal(signal.SIGXCPU, self.signal_handler)
+ signal.signal(signal.SIGPWR, self.signal_handler)
+
+ def signal_handler(self,signum, frame):
+ print 'Aborting: Signal handler called with signal ', signum
+ self.ci.child_abort("Signal handler called with signal " + str(signum));
+
+ def __enter__(self):
+ self.ci.child_init()
+ return self.ci
+
+ def __exit__(self,ex_type,value,tb):
+ print "Client:__exit__: ex_type:" + str(ex_type) + " value:" + str(value) + "\\\n" + str(tb)
+ if ex_type != None:
+ self.ci.child_abort("Aborted with exception type " + str(ex_type) + ":" + str(value))
+ return False
+ self.ci.child_complete()
+ return False
+"""
+ body = """#!/usr/bin/env python
+$include <head.py>
+
+if __name__ == "__main__":
+# This will also handle call to sys.exit(), i.e Client.__exit__ will still be called.
+ with Client() as ci:
+ # *******************************************************************************
+ # This is where the main work is done.
+ # *******************************************************************************
+ for i in range(1,100):
+ ci.child_meter('step',i)
+ ci.child_label('info', "value_" + str(i))
+ time.sleep(1)
+
+ ci.child_event('1')
+ print "Finished event,meter and label child commands"
+
+$manual
+ This is the manual section. Instead of calling python from the ECF_JOB_CMD we could alternatively place,
+ #!/bin/env/python
+ on the first line of this file.
+$end
+
+$comment
+ Note: We do not need a include a tail.py, the head.py does it all.
+$end
+
+"""
+ create_wrapper("head.py", head)
+ create_wrapper("pure_python.sms", body)
+ ### PYTHON TASK
+ content = """$include <python_header.h>
+# header files are located in the same directory as wrapper (quotes)
+for step in range(0,101):
+ print step
+ xmeter("step", step)
+else:
+ print 'the loop is over'
+xevent("1")
+xlabel("info", "news from pure python world")
+
+$include <python_endt.h>
+"""
+ create_wrapper("python.sms", content)
+
+ content = """#!/usr/bin/env python
+import os
+import sys
+import signal
+
+ECF_PORT=$ECF_PORT:0$
+XECF="/usr/local/apps/ecflow/current/bin/ecflow_client ";
+# --port=$ECF_PORT:0$ --host=$ECF_NODE:0$ ";
+def SigHandler(signum, frame):
+ print "caught signal " + signum
+ xabort()
+ sys.exit(0);
+ return
+
+print ECF_PORT
+# set -eux ?
+# trap 0 ?
+# time stamp per executed line
+
+import atexit
+early_exit = True
+ at atexit.register
+def goodbye():
+ if early_exit:
+ print "too early"
+ xabort()
+ else:
+ xcomplete()
+
+# TIME_STAMP
+# http://shop.oreilly.com/product/9780596007973.do # recipie p436
+import syslog, time
+
+class FunctionFileLikeWrapper():
+ def __init__(self, func): self.func = func
+ def write(self, msg): self.func(msg)
+ def flush(self): pass
+
+class TimeStamper(object):
+ msg_format = "[%y%m%d %H:%M:%S]", time.gmtime, "%s: %s"
+ msg_format = "+ %H:%M:%S", time.gmtime, "%s %s"
+
+ def __call__(self, msg):
+ tfmt, tfun, gfmt = self.msg_format
+ return "%s %s\\\n" % (time.strftime(tfmt, tfun()), msg)
+
+class TeeFileLikeWrapper():
+ def __init__(self, *files): self.files = files
+ def write(self, msg):
+ for f in self.files: f.write(timestamp(msg.strip()))
+
+class FlushingWrapper:
+ def __init__(self, *files): self.files = files
+ def write(self, msg):
+ for f in self.files:
+ f.write(timestamp(msg))
+ # f.write(timestamp(msg.strip()))
+ f.flush()
+
+def logto(*files):
+ # sys.stdout = TeeFileLikeWrapper(*files)
+ sys.stdout = FlushingWrapper(*files)
+
+syslogger = syslog.syslog
+syslogfile = FunctionFileLikeWrapper(syslogger)
+timestamp = TimeStamper()
+logto(sys.stdout, syslogfile, open("log.tmp", "w"))
+# end time stamp
+
+if ECF_PORT > 0:
+ os.environ['ECF_PORT'] = "$ECF_PORT:0$"
+ os.environ['ECF_NAME'] = "$ECF_NAME:0$"
+ os.environ['ECF_NODE'] = "$ECF_NODE:0$"
+ os.environ['ECF_PASS'] = "$ECF_PASS:0$"
+
+ def xinit():
+ os.system(XECF + " --init=" + str(os.getpid()))
+ print "init"
+ def xabort():
+ os.system(XECF + " --abort")
+ def xcomplete():
+ os.system(XECF + " --complete")
+ def xmeter(name, step):
+ os.system(XECF + " --meter=" + name + " " + str(step))
+ def xevent(name):
+ os.system(XECF + " --event=" + name)
+ def xlabel(name, msg):
+ os.system(XECF + " --label=" + name + " '%s'" % msg)
+else:
+ os.environ['SMS_PROG'] = "$SMS_PROG:0$"
+ os.environ['SMSNAME'] = "$SMSNAME:0$"
+ os.environ['SMSNODE'] = "$SMSNODE:0$"
+ os.environ['SMSPASS'] = "$SMSPASS:0$"
+
+ def xinit():
+ os.system('smsinit ' + str(os.getpid()))
+ def xabort():
+ os.system('smsabort')
+ def xcomplete():
+ os.system('smscomplete')
+ def xmeter(name, step):
+ os.system("smsmeter " + name + " " + str(step))
+ def xevent(name):
+ os.system("smsevent " + name)
+ def xlabel(name, msg):
+ os.system("smslabel " + name + " '%s'" % msg)
+
+signal.signal (signal.SIGHUP, SigHandler)
+signal.signal (signal.SIGINT, SigHandler)
+signal.signal (signal.SIGQUIT, SigHandler)
+signal.signal (signal.SIGILL, SigHandler)
+signal.signal (signal.SIGTRAP, SigHandler)
+signal.signal (signal.SIGIOT, SigHandler)
+signal.signal (signal.SIGBUS, SigHandler)
+signal.signal (signal.SIGFPE, SigHandler)
+
+"""
+ create_wrapper("python_header.h", content)
+
+ content = """# os.system('smscomplete')
+early_exit = False
+# xcomplete() # managed with atexit
+# os.system('/usr/local/apps/sms/bin/ecflow/bin/ecf_client --complete')
+"""
+ create_wrapper("python_endt.h", content)
+
+ ### PERL TASK
+ create_wrapper("perl.sms", """#!/usr/bin/perl -w
+^include <perl_header.h>
+# header files are located in the same directory as wrapper (quotes)
+print "Pure perl SMS task";
+for ( my $step=1; $step <= 100 ; $step++ ) {
+ print "this is the number $step\\\n";
+ xmeter("step", $step);
+}
+xevent("1");
+
+xlabel("info", "news from pure perl world");
+^include <perl_endt.h>
+""")
+ # create_wrapper("perl.sms", content)
+
+ source = """use strict;
+
+my $xmeter = "smsmeter"; my $arg_m = "";
+my $xlabel = "smslabel"; my $arg_l = "";
+my $xevent = "smsevent"; my $arg_e = "";
+my $xcomplete = "smscomplete"; my $arg_c = "";
+my $xabort = "smsabort";
+
+if (^ECF_PORT:0^ != 0) {
+$ENV{'ECF_PORT'} = "^ECF_PORT:0^" ; # ecFlow port number
+$ENV{'ECF_NODE'} = "^ECF_NODE:0^" ; # ecFlow host
+$ENV{'ECF_NAME'} = "^ECF_NAME:0^" ; # task path into the suite
+$ENV{'ECF_PASS'} = "^ECF_PASS:0^" ; # password for the job
+$ENV{'ECF_TRYNO'} = "^ECF_TRYNO:0^" ; # job occurence number
+my $client = "/usr/local/apps/ecflow/current/bin/ecflow_client";
+$xmeter = $client; $arg_m = "--meter";
+$xlabel = $client; $arg_l = "--label";
+$xevent = $client; $arg_e = "--event";
+$xcomplete = $client; $arg_c = "--complete";
+$xabort = $client;
+
+system($client, "--init", "$$");
+} else {
+ $ENV{'SMS_PROG'} = "^SMS_PROG:0^" ; # SMS Program Number
+ $ENV{'SMSNODE'} = "^SMSNODE:0^" ; # SMS host
+ $ENV{'SMSNAME'} = "^SMSNAME:0^" ; # task path into the suite
+ $ENV{'SMSPASS'} = "^SMSPASS:0^" ; # password for the job occurence
+ $ENV{'SMSTRYNO'} = "^SMSTRYNO:0^" ; # job occurence number
+}
+
+sub xmeter($$){ my ($name, $step) = @_;
+ system($xmeter, $arg_m, $name, $step); }
+sub xevent($){ my ($name) = @_;
+ system($xevent, $arg_e, $name); }
+sub xlabel($$){ my ($name, $msg) = @_;
+ system($xlabel, $arg_l, $name, $msg); }
+sub xabort(){ system($xabort); }
+sub xcomplete(){ system($xcomplete, $arg_c, "$$"); }
+
+print "start";
+eval '
+"""
+ create_wrapper("perl_header.h", source)
+
+ source="""';
+if ($@){
+ print "caught signal: $@\n";
+ xabort();
+ exit;
+ }
+print "the job is now complete\n";
+xcomplete();
+exit;"""
+ create_wrapper("perl_endt.h", source)
+
+ ### LOGER TASK
+ content = """#!/bin/ksh
+%manual
+ start - check - stop logsvr
+%end
+%include <qsub.h>
+%include <trap.h>
+SLEEP=%SLEEP:0%
+KIND=%KIND:start%
+type rsh && RSH=rsh || RSH=ssh
+
+case $HOST in
+c2a*) rhost=c2a;;
+c2b*) rhost=c2b;;
+xxcct*) rhost=cctdtn1 ; RSH=ssh;;
+cct*) rhost=cct-log ; RSH=ssh;;
+cca*) rhost=cca-log ; RSH=ssh ;;
+xxcca*) rhost=cca-il2 ; RSH=ssh ;;
+xxccb*) rhost=ccb-il2 ; RSH=ssh ;;
+ccb*) rhost=ccb-log ; RSH=ssh ;;
+esac
+
+case $KIND in
+start)
+
+ps -elf | grep logsvr | grep -v grep | grep $USER && \\\
+ps -elf | grep logsvr | grep $USER | grep -v grep | \\\
+awk '{print $1}' | xargs kill -9
+
+case $ARCH in
+cray)
+ case $HOST in
+ cct*) logsvr=/usr/local/apps/sms/bin/logsvr.sh
+ # /usr/local/apps/emos/bin/logsvr.sh
+ # $RSH $rhost
+ nohup $logsvr > /tmp/emos_logsvr.tmp 2>&1 &
+ rhost=cct # start on both nodes cctdtn1 + cct (Avi serial jobs)
+ trap 0; xcomplete; exit 0
+ ;;
+ cca*|ccb*) logsvr=/usr/local/apps/emos/bin/logsvr.sh;;
+ *) exit 1;;
+ esac
+
+ $RSH $rhost nohup $logsvr > /tmp/emos_logsvr.tmp 2>&1 &
+;;
+ibm*) $RSH $rhost nohup $HOME/bin/boot/logsvr.sh > /tmp/emos_logsvr.tmp 2>&1 &
+;;
+*) nohup logsvr.sh > /tmp/emos_logsvr.tmp 2>&1 &
+;;
+esac
+xlabel info "logserver is started"
+
+;;
+stop)
+pid=$($RSH $rhost ps -elf | grep logsvr | grep $USER | grep -v grep | awk '{print $1}' )
+kill -9 $pid
+xlabel info "logserver is stoped"
+;;
+
+ping)
+case $ARCH in
+cray) ps -elf | grep logsvr | grep $USER # grep -v grep || exit 1
+ xlabel info "???"
+ trap 0; xcomplete; exit 0
+;;
+*) $RSH $rhost ps -elf | grep logsvr | grep -v grep | grep $USER || exit 1
+;;
+esac
+
+xlabel info "$($RSH $rhost ps -elf | grep logsvr | grep -v grep | grep $USER)"
+;;
+esac
+
+%include <endt.h>
+"""
+ create_wrapper("logsvr.sms", content)
+
+ ### task
+ content = """#!/bin/ksh
+%manual
+manual - this task is automatically created by cray.py
+%end
+%include <qsub.h>
+if [[ $ARCH = hp* ]]; then export PATH=/usr/local/bin:$PATH; fi
+if [[ $HOST = lxop* ]]; then export PATH=/usr/local/apps/ecflow/current:/usr/local/apps/sms/bin:$PATH; fi
+%include <trap.h>
+SLEEP=%SLEEP:0%
+echo OK
+
+case %ECF_PORT:0% in
+0) base=900000; LOGPORT=%LOGPORT:0%;;
+*) base=1000; LOGPORT=%LOGPORT:0%;;
+esac
+base=1000
+
+case $HOST in
+cc*)xlabel info $(printenv | grep -E '(SUBMIT_|EC_)') ;;
+*) xlabel info OK
+esac
+
+printenv | sort
+xevent 1
+step=0
+while (( $step <= 12 )); do
+ xmeter step $step
+ ((step = step + 1))
+ sleep $SLEEP
+done
+%include <endt.h>
+"""
+ create_wrapper("test.sms", content)
+
+ content = """#!/bin/ksh
+%manual
+manual - this task is automatically created by cray.py
+
+expected to run in real-time mode only
+
+%end
+#include <qsub.h>
+#include <step1.h>
+%include <trap.h>
+
+KIND=%KIND:when%
+NOW=$(date +%%H%%M)
+
+case $KIND in
+when) TIME=0;
+for when in $(echo %WHENS:0%); do
+ if [[ $((NOW - when)) -le 1 ]]; then break; fi
+ TIME=$when
+done
+for when in $(echo %WHENS:0%); do
+ if [[ $when -le $NOW ]] then xmeter time $when; sleep %SLEEP:5%; fi
+ done;;
+time) TIME=%TIME:0%
+
+main=/sapp/run/ext
+case $TIME in
+1350) path=$main/DC1/00;;
+0120) path=$main/DC1/12;;
+0205) path=$main/DC1/18;;
+1405) path=$main/DC1/06;;
+1605) path=$main/DA1/12;;
+2205) path=$main/DA1/18;;
+0405) path=$main/DA1/00;;
+1005) path=$main/DA1/06;;
+*) xabort;;
+esac
+
+case %ECF_PORT:0% in
+0) login="set SMS_PROG %SMS_PROG:0%; login %SMSNODE:0% $USER 1"
+ cdp -c "$login; force -r complete $path";;
+*) ecflow_client --force=complete recursive $path;;
+esac
+
+;;
+esac
+%include <endt.h>
+#include <step2.h>
+"""
+
+ create_wrapper("sapp.sms", content)
+
+ content = """
+%manual
+manual - this task is automatically created by cray.py
+
+expected to run in real-time mode only
+%end
+#include <qsub.h>
+#include <step1.h>
+%include <trap.h>
+
+if [[ $USER == map ]]; then
+cd /tmp/map/work/p4/metapps/suites/o/def
+make etest | grep -v Node::addVariable:
+make teste | grep -v Node::addVariable:
+
+TEST="" make oe edae lawe lbce rd mce mofce
+TEST= "" make e eeda elbc elaw
+
+fi
+
+cd /home/ma/emos/def/o/def
+# make etest| grep -v Node::addVariable:
+# make teste| grep -v Node::addVariable:
+
+TEST="" make oe edae lawe lbce rd mce mofce| grep -v Node::addVariable:
+TEST="" make e eeda elbc elaw | grep -v Node::addVariable:
+
+make doc
+make covtest
+make cov| grep -v Node::addVariable:
+
+# e o rd
+
+%include <endt.h>
+#include <step2.h>
+"""
+ create_wrapper("maker.sms", content)
+
+ content = """#!/bin/ksh
+%manual
+manual - this task is automatically created by cray.py
+expected to run in real-time mode only
+%end
+#include <qsub.h>
+#include <step1.h>
+%include <trap.h>
+
+KIND=%KIND:when%
+NOW=$(date +%%H%%M)
+
+YMD=%YMD:20010101%
+BASETIME=%YMD:20010101%%EMOS_BASE:00%
+BASE=%EMOS_BASE:00%
+STREAM=%STREAM:elda%
+MEMBER_FROM=%MEMBER_FROM:%
+MEMBER=%MEMBER:%
+EXPVER_FROM=%EXPVER_FROM:9093%
+EXPVER=%EXPVER:9963%
+
+case $HOST in
+c2*) FDB_ROOT=%STHOST:/s2o1%/ma_fdb;;
+cc*) FDB_ROOT=%STHOST:/sc1%/tcwork/emos/ma_fdb;;
+*) exit 1;;
+esac
+
+cd $FDB_ROOT
+mkdir fix
+cd fix
+scp emos@%SCHOST_BKUP:cca:$FDB_ROOT/:od:$STREAM:g:$EXPVER_FROM:$YMD::/:${EMOS_BASE}00:$MEMBER_FROM:*: .
+
+cat > rules.txt <<EOF
+set expver="$EXPVER";
+write;
+EOF
+
+for f in $(ls :${EMOS_BASE}00:$MEMBER_FROM:*:); do
+ grib_filter -o $f.0001 rules.txt $f
+done
+
+echo "mkdir -p test; for f in $(ls :${EMOS_BASE}00:$MEMBER_FROM:*:); do FDB_ROOT=$(pwd)/test grib2fdb $f; done"
+echo "mv test/*$STREAM:*/* $FDB_ROOT/:od:$STREAM:g:$EXPVER:$YMD::/."
+done
+
+case $KIND in
+VERSION) echo;;
+MEMBER) echo;;
+*) xabort;;
+esac
+
+;;
+esac
+%include <endt.h>
+#include <step2.h>
+"""
+
+ create_wrapper("safety.sms", content)
+
+def create_de():
+ try: os.stat(wdir + "/de")
+ except: os.mkdir(wdir + "/de")
+ task = open(wdir + "/de/setup.ecf", 'w')
+ print >>task, '''#!/bin/ksh
+%include <head.h>
+%ecfmicro ~
+~includenopp <scripts/setup.run>
+~ecfmicro %
+%include <tail.h>
+'''
+
+ task = open(wdir + "/de/model.ecf", 'w')
+ print >>task, '''#!/bin/ksh
+# QSUB -lh %THREADS:1%
+# QSUB -lPv %NPES:1%
+# @ tasks_per_node = 64
+%include <head.h>
+%ecfmicro ~
+~includenopp <scripts/model.run>
+~ecfmicro %
+%include <tail.h>
+'''
+
+ logdir = "/s2o2/emos_dir"
+ return Family("de").add(
+ Defcomplete(),
+ Repeat("YMD", 20100101, 20121212),
+ Variables(ECF_EXTN= ".ecf",
+ ACCOUNT= "oesu",
+ SCHOST= "cca",
+ ECF_LOGHOST= "cca",
+ ECF_OUT= logdir,
+ LOGDIR= logdir,
+ QUEUE= "ns",
+ TURTLES= 1000*'I LIKE ',
+ ),
+ Task("setup"),
+ Task("obs").add(Trigger("setup==complete")),
+ Task("namelist").add(Trigger("obs==complete")),
+ Task("model").add(
+ Variables(NPES= 1,
+ THREADS= 1,
+ QUEUE= "np",),
+ Trigger("namelist==complete")),
+ Task("postproc").add(Trigger("model==complete")),
+ )
+
+def create_smhi():
+ submit = open(wdir + "/smhi_run.sh", 'w')
+ print >>submit, '''#!/bin/ksh
+set -eux
+ECF_NAME=$1
+ECF_PASS=$2
+ECF_JOB=$3
+ECF_JOBOUT=$4
+ECF_NODE=$5
+ECF_PORT=$6
+export ECF_NAME ECF_PASS ECF_NODE ECF_PORT ECF_JOB ECF_JOBOUT
+echo "#MSG: START USER SCRIPT"
+. $ECF_JOB # >> $ECF_JOBOUT 2>&1
+'''
+
+ man = open(wdir + "/smhi_man.h", 'w')
+ print >> man, '''
+an example for include manual page
+'''
+ man.close()
+
+ shell = open(wdir + "/smhi.sh", 'w')
+ print >> shell, '''#!/bin/ksh
+set -eux
+# use ecflow ||
+export PATH=/usr/local/apps/ecflow/current/bin:$PATH
+export SIGNAL_LIST='1 2 3 4 5 6 7 8 13 15 24 31'
+ecflow_client --init=$$
+
+ERROR() {
+ ecflow_client --abort # raison:trap
+ echo "#WAR: TRAPPING ERROR"
+ trap 0
+ uname -a; date; times
+ sleep 0
+ exit 0
+}
+trap ERROR 0 $SIGNAL_LIST
+
+ecflow_client --event=1
+ecflow_client --meter=step 10
+
+echo "simulates an error"; exit 1
+echo "simulates an early exit: expect this to be trapped and reflected as error"
+exit 0 # test bubbling up an error through ssh
+
+'''
+ wrapper = open(wdir + "/smhi_v.sms", 'w')
+ print >>wrapper, '''
+%manual
+ example of minimalist script: only variables, wrapper is added at submission time
+%end
+#SET ECF_NAME=%ECF_NAME%
+#SET ECF_NODE=%ECF_NODE%
+#SET ECF_PORT=%ECF_PORT%
+#SET ECF_PASS=%ECF_PASS%
+#SET ECF_JOB=%ECF_JOB%
+#SET ECF_JOBOUT=%ECF_JOBOUT%
+#SET ECF_TRYNO=%ECF_TRYNO%
+#SET SCRIPT_PATH=%SCRIPT_PATH%
+#SET SCRIPT_NAME=%SCRIPT_NAME%
+'''
+
+ submit = open(wdir + "/smhisubmit.sh", 'w')
+ print >>submit, '''#!/bin/ksh
+set -eux
+ECF_JOB=$1
+grep "#SET " $ECF_JOB | sed -e "s:#SET ::" > $ECF_JOB.set
+grep "#SET " $ECF_JOB > $ECF_JOB.var
+. $ECF_JOB.set
+echo "#!/bin/ksh" > $ECF_JOB
+cat $ECF_JOB.set $ECF_JOB.var >> $ECF_JOB
+cat >> $ECF_JOB <<\@@
+set -eux
+export ECF_NAME ECF_PASS ECF_NODE ECF_PORT
+export PATH=/usr/local/apps/ecflow/current/bin:$PATH
+export SIGNAL_LIST='1 2 3 4 5 6 7 8 13 15 24 31'
+ERROR() {
+ ecflow_client --abort trap
+ echo "#WAR: TRAPPING ERROR"
+ trap 0
+ uname -a; date; times
+ exit 1
+}
+trap ERROR 0 $SIGNAL_LIST
+
+if [[ ${USE_SSH_SUB:=0} == 1 ]]; then
+ssh $SCHOST mkdir -p $(dirname $ECF_JOBOUT)
+ssh $SCHOST -R$ECF_PORT:$ECF_NODE:$ECF_PORT ''' + wdir + '''/smhi_run.sh \
+ $ECF_NAME $ECF_PASS $SCRIPT_PATH/$SCRIPT_NAME $ECF_JOBOUT $ECF_NODE $ECF_PORT
+echo "#MSG: ssh exits with $?"
+else
+ecflow_client --init=$$
+
+i=0
+while [[ $i -lt ${STEPS:=1} ]]; do
+ ecflow_client --meter=step $i
+ ((i=i+1))
+done
+
+ecflow_client --event=1
+
+fi
+
+wait
+trap 0
+ecflow_client --complete
+uname -a; date; times
+exit 0
+@@
+
+chmod 755 $ECF_JOB
+$ECF_JOB > $ECF_JOBOUT 2>&1 &
+
+'''
+
+ os.system("chmod 755 " + wdir + "/smhisubmit.sh")
+ wrapper = open(wdir + "/smhi.sms", 'w')
+ os.system("chmod 755 " + wdir + "/smhi_run.sh")
+ cmd = "ln -sf %s/test.sms " % wdir + wdir + "/"
+ os.system(cmd + "a.sms")
+ os.system(cmd + "a1.sms")
+ os.system(cmd + "a11.sms")
+ print "##cmd", cmd
+
+ print >> wrapper, '''#!/bin/ksh
+%manual
+%include <smhi_man.h>
+%end
+set -eux
+# use ecflow ||
+export PATH=/usr/local/apps/ecflow/current/bin:$PATH
+export SIGNAL_LIST='1 2 3 4 5 6 7 8 13 15 24 31'
+ECF_NAME=%ECF_NAME%
+ECF_PASS=%ECF_PASS%
+ECF_NODE=%ECF_NODE%
+ECF_PORT=%ECF_PORT%
+export ECF_NAME ECF_PASS ECF_NODE ECF_PORT
+
+ERROR() {
+ ecflow_client --abort # raise:trap
+ echo "#WAR: TRAPPING ERROR"
+ trap 0
+ uname -a; date; times; sleep 0
+ exit 1
+}
+
+SLEEP=%SLEEP:0%
+trap ERROR 0 $SIGNAL_LIST
+
+if [[ %USE_SSH_SUB:0% == 1 ]]; then
+ssh %SCHOST% mkdir -p $(dirname %ECF_JOBOUT%)
+ssh %SCHOST% -R%ECF_PORT%:%ECF_NODE%:%ECF_PORT% ''' + wdir + '''/smhi_run.sh \
+ %ECF_NAME% %ECF_PASS% %SCRIPT_PATH%/%SCRIPT_NAME% %ECF_JOBOUT% %ECF_NODE% %ECF_PORT%
+ echo "#MSG: ssh exits with $?"
+else
+ecflow_client --init=$$
+
+i=0
+while [[ $i -lt ${STEPS:=1} ]]; do
+ ecflow_client --meter=step $i
+ ((i=i+1))
+done
+
+ecflow_client --event=1
+
+fi
+
+wait
+trap 0
+ecflow_client --complete
+uname -a; date; times
+exit 0
+'''
+
+def dummy(): return Task("test")
+
+def logsvr(kind): return Task("logsvr").add(
+ Label("man", "kind may be start, stop, ping"),
+ Label("info", ""),
+ Variables(KIND= kind))
+
+def limits():
+ return (Family("Test").add(Defcomplete(),
+ Label("info", "test find reg exp, case sens"),
+ Task("Ecmwf"),
+ Task("ECMWF"),
+ Task("ecmwf"),
+ Task("ecm")),
+ Family("limits").add(
+ Defcomplete(),
+ Limit("lim", 10),
+ Limit("test", 10),
+ Limit("hpc", 10),
+ Limit("cca", 10),
+ Limit("ccb", 10),
+ # Limit("cct", 10),
+ # Limit("c2a", 10),
+ # Limit("c2b", 10),
+ Inlimit(ic.psel() + "/limits:lim")))
+
+def repeat():
+ return Family("repeat").add(
+ Defcomplete(),
+ Family("int").add(
+ Repeat("YMD", 21000101, 21001212, 1, "integer"),
+ dummy()),
+ Family("date").add(
+ Repeat("YMD", 21000101, 21001212, 1, "date"),
+ dummy()),
+ Family("string").add(
+ Repeat("YMD", ["1", "2", "3", "4", "5"], kind="string"),
+ dummy()),
+ Family("enum").add(
+ Repeat("YMD", "1 2 3 4 5".split(), kind="enum"),
+ dummy()),
+ )
+
+
+def fam_ui():
+ return Family("ui").add(
+ Defcomplete(),
+ repeat(),
+
+ Variables(VAR= 1),
+
+ Family("limit").add(Limit("mutex", 1),
+ InLimit("limit:mutex"),
+ Defstatus("complete"),
+ dummy()),
+
+ Family("autocancel").add(AutoCancel("+01:00"),
+ dummy()),
+
+ dummy().add(Meter("step", -1, 100),
+ Event(1),
+ Label("info", ""),
+ Late("-s 00:10 -c 01:00"),
+ ),
+
+ Family("complete").add(Complete("test:1"),
+ Trigger("test==complete")),
+
+ Task("time").add(Time("10:00"),
+ Today("11:00"),
+ Cron("12:00 13:00 00:05"),
+ ),
+ Task("date").add(Date("01.*.*"),)
+ )
+
+def smhi():
+ return Family("smhi").add(
+ Defcomplete(),
+
+ Variables(ECF_FILES= wdir,
+ QUEUE= "none",
+ LOGDIR= jdir, # "/vol/lxop_emos_nc/output",
+ MANPATH= "%ECF_SCRIPT%",
+ ECF_JOB_CMD= "%ECF_JOB% > %ECF_JOBOUT% 2>&1",
+ ECF_HOME= jdir, # "/tmp/smhi",
+ ECF_INCLUDE= wdir,),
+
+ acq(),
+
+ Family("ex1").add(Cron("00:00 23:59 00:03"),
+ Task("scan").add(Label("info", "one min"),
+ Event("1")),
+ Task("proc").add(Label("info", "one min"),
+ Trigger("scan:1"),
+ Complete("scan eq complete and not scan:1"))),
+ Family("ex2").add(
+ Task("scan").add(Label("info", "one min"),
+ Cron("00:00 23:59 00:03"),
+ Event("1")),
+ Family("consume").add(
+ Label("info", "event is set by scan task"),
+ Event("1"),
+ Cron("00:00 23:59 00:05"),
+ Trigger("consume:1"),
+ Task("proc1").add(Trigger("1==0", Complete("1==1"))),
+ Task("proc2").add(Trigger("1==0", Complete("1==1"))),
+ )),
+ Family("name").add(
+ Variables(ECF_JOB_CMD= SUBMIT,
+ ECF_KILL_CMD= KILL,
+ ECF_STATUS_CMD= STATUS,
+ ECF_CHECK_CMD= CHECK,
+ # ECF_EXTN= ".sms",
+ ACCOUNT= "UNSET",
+ ECF_INCLUDE= idir,
+ ECF_HOME= jdir,
+ ECF_FILES= wdir,
+ TOPATH= udir + "/logs",
+ SLEEP= 1,
+ SCHOST= "ibis",
+ ECF_TRIES= 1,),
+ Task("a").add(Meter("step", -1, 100), Event("1")),
+ Task("a1").add(Meter("step", -1, 100), Event("1")),
+ Task("a11").add(Meter("step", -1, 100), Event("1")),
+ ),
+
+ Family("ssh").add(
+ Variables(USE_SSH_SUB= 1,
+ SCRIPT_PATH= wdir,
+ SCRIPT_NAME= "smhi.sh"),
+ smhi_unit("ibis", "ibis", "none", jdir),
+ smhi_unit("pikachu", "pikachu", "none", jdir),
+ ),
+
+ Family("alter").add(
+ Variables(USE_SSH_SUB= 1,
+ ECF_JOB_CMD= "/home/ma/map/course/cray/smhisubmit.sh %ECF_JOB%",
+ SCRIPT_PATH= wdir,
+ SCRIPT_NAME= "smhi.sh"),
+ smhi_unit_alter("ibis", "ibis", "none", jdir),
+ smhi_unit_alter("pikachu", "pikachu", "none", jdir),
+ )
+ )
+
+def acq():
+ name = "acq_ex"
+
+ fam = Family(name).add(
+ Defcomplete(),
+ Family("times").add(
+ dummy().add(
+ Time("10:00 20:00 00:30"))),
+ Complete(name + "/data eq complete"),
+ Task("data").add(
+ Event("ready"),
+ Trigger("rt/wait:data"),
+ ),
+ Family("rt").add(
+ Complete("data:ready"),
+ Task("wait").add(
+ Event("data"),
+ # Cron("10:00 12:00 00:05")
+ )),
+ Task("late").add(
+ Time("11:00"),
+ Trigger("not data:ready")))
+ return fam
+
+
+HCRAY="cct"
+
+SUBMIT=ic.SUBM + " %USER% %SCHOST% %ECF_JOB% %ECF_JOBOUT% submit"
+GSUB=SUBMIT.replace("%SCHOST%", "%SCHOST% %ECF_RID%")
+KILL=GSUB.replace(" submit", " kill")
+STATUS=GSUB.replace(" submit", " status")
+CHECK=STATUS
+
+
+def unit(name, schost, queue, rdir, account="", leaf=True, add=None):
+ return Family(name).add(
+ If(account != "",
+ Variables(ACCOUNT= account)),
+ Variables(QUEUE= queue,
+ SCHOST= schost,
+ ECF_OUT= rdir,
+ LOGDIR= rdir,),
+ If (leaf, Task("test").add(
+ add,
+ Event(1),
+ Meter("step", -1, 120, 100),
+ Label("info", "nop"))))
+
+def smhi_nit(name, schost, queue, rdir, account=""):
+ return Family(name).add(
+ If(account != "", Variables(ACCOUNT= account)),
+ Variables(QUEUE= queue,
+ SCHOST= schost,
+ ECF_OUT= rdir,
+ LOGDIR= rdir,),
+ Task("smhi").add(
+ Event(1),
+ Meter("step", -1, 120, 100),
+ Label("info", "nop")))
+
+def smhi_unit(name, schost, queue, rdir, account=""): return None
+
+def smhi_unit_alter(name, schost, queue, rdir, account=""):
+ return Family(name).add(
+ If(account != "", Variables(ACCOUNT= account)),
+ Variables(QUEUE= queue,
+ SCHOST= schost,
+ ECF_OUT= rdir,
+ LOGDIR= rdir,),
+ Task("smhi_v").add(
+ Event(1),
+ Meter("step", -1, 120, 100),
+ Label("info", "nop")))
+
+def turkey_main(day, path):
+ def runs(num, time):
+ return Family('run%d' % num).add(
+ Trigger(path + '/deps/%s eq complete' % time),
+
+ Family('feed_meb').add(
+ Task('strip_message'),
+
+ Task('insert_meb').add(
+ Trigger('strip_message eq complete'),
+ ),
+ ),
+ Family('feed_reb').add(
+ Task('decode_synop').add(
+ Trigger('../feed_meb/insert_meb eq complete'),
+ ),
+ Task('decode_temp').add(
+ Trigger('../feed_reb/decode_synop eq complete'),
+ ),
+ Task('decode_ship').add(
+ Trigger('../feed_reb/decode_temp eq complete'),
+ ),
+ Task('decode_metar').add(
+ Trigger('../feed_reb/decode_ship eq complete'),
+ ),
+ ),
+ Family('rdb').add(
+ Task('rdb_synop').add(
+ Trigger('../feed_reb/decode_synop eq complete'),
+ ),
+ Task('rdb_temp').add(
+ Trigger('../feed_reb/decode_temp eq complete'),
+ ),
+ Task('rdb_ship').add(
+ Trigger('../feed_reb/decode_ship eq complete'),
+ ),
+ Task('rdb_metar').add(
+ Trigger('../feed_reb/decode_metar eq complete'),
+ ),
+ ),
+ ),
+
+ def task_trigger(name, condition):
+ return Task(name).add(Trigger(condition))
+
+ def echos():
+ echo = {
+ "cleandb" : "0131",
+ "cleanerrdb": "0136",
+ "silmeb": "0141",
+ "silreb": "0146",
+ "run1": "0221",
+ "run2": "0421",
+ "run3":"0621",
+ "run4": '0821',
+ 'run5': '1021',
+ 'run6': '1321',
+ 'run7': '1421',
+ 'run8': '1621',
+ 'run9': '1821',
+ 'run10': '2121',
+ 'eksikveritamamla': '2201',
+ 'uydutsm': '0201',
+ 'model_all_gunluk_tsm': '0131',
+ 'radar_lokasyon_tip_tsm': '0501',
+ 'retObsAndFtp_for_00': '0231',
+ 'retObsAndFtp_for_18': '0241',
+ 'retObsAndFtp_for_12': '1541',
+ 'retObsAndFtp_for_06': '1101',
+ 'retObsAndFtp_for_06gungeri': '0801',
+ 'uydureport': '1655',
+ 'radarreport': '0701',
+ 'backuplog': '2301',
+ 'cleanup': '2316'
+ }
+ out = []
+
+ for key in sorted(echo, key=echo.get, reverse=False): # order by value
+ # for key in sorted(echo.keys()): # order by key
+ out.append(task_trigger("echo_%s" % key,
+ path + "/deps/%s" % echo[key] + " eq complete"))
+ return out
+
+ return Family('main').add(
+ Trigger('deps/0000 eq complete'),
+
+ Family('clean').add(
+ task_trigger('cleandb',
+ path + '/deps/0130 eq complete'),
+
+ Task('clean_errdb').add(
+ Trigger(path + '/deps/0135 eq complete'),
+ ),
+ Task('silmeb').add(
+ Trigger(path + '/deps/0140 eq complete'),
+ ),
+ Task('silreb').add(
+ Trigger(path + '/deps/0145 eq complete'),
+ ),
+ ),
+ runs(1, "0220"),
+ runs(2, "0420"),
+ runs(3, "0620"),
+ runs(4, "0820"),
+ runs(5, "1020"),
+ runs(6, "1320"),
+ runs(7, "1420"),
+ runs(8, "1620"),
+ runs(9, "1820"),
+ runs(10, "2120"),
+ Family('model').add(
+ Task('eksikveritamamla').add(
+ Trigger(path + '/deps/2200 eq complete'),
+ ),
+ ),
+ Family('tsmarc').add(
+ Task('uydu_tsm').add(
+ Trigger(path + '/deps/0200 eq complete'),
+ ),
+ Task('model_all_gunluk_tsm').add(
+ Trigger(path + '/deps/0130 eq complete'),
+ ),
+ Task('radar_lokasyon_tip_tsm').add(
+ Trigger(path + '/deps/0500 eq complete'),
+ ),
+ ),
+ Family('ftpsenddata').add(
+ Task('retObsAndFtp_for_00').add(
+ Trigger(path + '/deps/0230 eq complete'),
+ ),
+ Task('retObsAndFtp_for_18').add(
+ Trigger(path + '/deps/0240 eq complete'),
+ ),
+ Task('retObsAndFtp_for_12').add(
+ Trigger(path + '/deps/1540 eq complete'),
+ ),
+ Task('retObsAndFtp_for_06').add(
+ Trigger(path + '/deps/1100 eq complete'),
+ ),
+ Task('retObsAndFtp_for_06gungeri').add(
+ Trigger(path + '/deps/0800 eq complete'),
+ ),
+ Task('uydu_report').add(
+ Trigger(path + '/deps/1654 eq complete'),
+ ),
+ Task('radar_report').add(
+ Trigger(path + '/deps/0700 eq complete'),
+ ),
+ ),
+ Family('cleanup').add(
+ Task('backuplog').add(
+ Trigger(path + '/deps/2300 eq complete'),
+ ),
+ Task('cleanup').add(
+ Trigger(path + '/deps/2315 eq complete'),
+ ),
+ ),
+ Family('echo').add(
+ Variables(
+ ECF_FILES= '/pp1/bin/dpp_sms/echo',),
+
+ echos(),
+ ))
+
+
+def turkey_deps(num):
+ def item(hhmm):
+ return Family(hhmm).add(
+ Complete("./%s/compl eq complete and " % hhmm +
+ './%s/dummy eq queued' % hhmm),
+
+ Task('dummy').add(
+ Cron('-w %d' % num + ' ' + hhmm[:2] + ":" + hhmm[-2:]),
+ ),
+ Task('compl').add(
+ Complete("dummy eq active or " +
+ "dummy eq submitted or " +
+ 'dummy eq complete'),
+ Trigger('1 eq 0'),
+ ),
+ )
+
+ items = [ "0000",
+"0130",
+"0135",
+"0140",
+"0145",
+"0220",
+"0420",
+"0620",
+"0820",
+"1020",
+"1320",
+"1420",
+"1620",
+"1820",
+"2120",
+"2200",
+"0200",
+"0500",
+"0230",
+"0240",
+"1540",
+"1100",
+"0800",
+"1654",
+"0700",
+"2300",
+"2315",
+"0131",
+"0136",
+"0141",
+"0146",
+"0221",
+"0421",
+"0621",
+"0821",
+"1021",
+"1321",
+"1421",
+"1621",
+"1821",
+"2121",
+"2201",
+"0201",
+"0501",
+"0231",
+"0241",
+"1541",
+"1101",
+"0801",
+"1655",
+"0701",
+"2301",
+"2316", ]
+ def loop_items():
+ out = []
+ for hhmm in items:
+ out.append(item(hhmm))
+ return out
+
+ return Family('deps').add(
+ Variables(
+ ECF_FILES= '/pp1/bin/dpp_sms/haftalik',),
+ loop_items())
+
+def turkey_loop(suite_name):
+ out = []
+ days = [ "Pazartesi", "Sali", "Carsamba", "Persembe", "Cuma", "Cumartesi", "Pazar"]
+ days = [ "mon", "tue", "wed", "thu", "fri", "sat", "sun"]
+ start = 20120723; end=20301231 # beware addition below does not consider start as a date
+ path = "/%s/weekly/" % suite_name
+
+ for num in xrange(7):
+ out.append(Family(days[num]).add(
+ Repeat(kind='date', name='YMD',
+ start= start + num, end=end, step=7),
+ turkey_deps(1),
+ turkey_main(days[num], path=path + days[num]),))
+ return out
+
+def turkey(suite_name):
+ return Family('weekly').add(
+ Label("repeat", "run one family per week day"),
+ Label("time_trigger", "replace time dependencies with trigger"),
+ Label("aborted", "one aborted task requests being fixed within one week"),
+ Defcomplete(),
+ turkey_loop(suite_name),)
+
+##########################################################################
+## PURE
+
+class Languages(object):
+ def __init__(self): pass
+ def task(self): return None
+ def scripts(self): pass
+
+class Python(Languages):
+ def task(self):
+ return (
+ Task("pure_python").add(
+ Variables(ECF_MICRO= "$",
+ ECF_INCLUDE= wdir,
+ SCHOST= "localhost",
+ ECF_JOB_CMD= "use ecflow; $ECF_JOB$ > $ECF_JOBOUT$ 2>&1 &"),
+ Event("1"),
+ Label("info", ""),
+ Meter("step", -1, 100),
+ # Defstatus("complete"),
+ ),
+
+ Task("python").add(
+ Variables(ECF_MICRO= "$",
+ ECF_INCLUDE= wdir,
+ SCHOST= "localhost",
+ ECF_JOB_CMD= "$ECF_JOB$ > $ECF_JOBOUT$ 2>&1 &"),
+ Event("1"),
+ Label("info", ""),
+ Meter("step", -1, 100),
+ # Defstatus("complete"),
+ ), )
+
+class Perl(object):
+ def task(self):
+ return Task("perl").add(
+ Label("todo", "time-stamp PS4, set eux, exit 0 1,"),
+ Variables(ECF_MICRO= "^",
+ ECF_INCLUDE= wdir,
+ SCHOST= "localhost",
+ ECF_JOB_CMD= "^ECF_JOB^ > ^ECF_JOBOUT^ 2>&1 &"),
+ Event("1"),
+ Label("info", ""),
+ Meter("step", -1, 100),
+ # Defstatus("complete"),
+ )
+
+class Ruby(object):
+ def task(self):
+ return Task("ruby").add(
+ Label("todo", "time-stamp PS4, set eux, exit 0 1,"),
+ Variables(ECF_MICRO= "^",
+ ECF_INCLUDE= wdir,
+ SCHOST= "localhost",
+ ECF_JOB_CMD= "^ECF_JOB^ > ^ECF_JOBOUT^ 2>&1 &"),
+ Event("1"),
+ Label("info", ""),
+ Meter("step", -1, 100),
+ Defstatus("complete"),
+ )
+
+ def scripts(self):
+ head = """#!/usr/bin/env ruby"""
+ tail = """ """
+ body = """ """
+ create_wrapper("head.rb", head)
+ create_wrapper("tail.rb", tail)
+ create_wrapper("ruby.sms", body)
+
+ruby = Ruby()
+perl = Perl()
+pyth = Python()
+
+WDIR= "/scratch/ma/map/sms"
+HLOG= "/home/ma/map/logs"
+
+hosts = {"lxb" : { "COMPILER": "gcc-4.3", # linux64
+ "SCHOST": "lxb",
+ "QUEUE_EPILOG": "serial",
+ "LOGDIR": HLOG, "ECF_OUT": HLOG,
+ "QUEUE": "serial",
+ "WDIR": WDIR, },
+ "ibis" : { "COMPILER": "gcc",
+ "SCHOST": "ibis",
+ "WDIR": WDIR, },
+ "lxop" : { "COMPILER": "gcc-4.3",
+ "SCHOST": "lxop",
+ "QUEUE": "test",
+ "QUEUE_EPILOG": "test",
+ "LOGDIR": HLOG, "ECF_OUT": HLOG,
+ "COMPILE_DIR": "/gpfs/lxop/emos_data/sms",
+ "WDIR": "/gpfs/lxop/emos_data/sms",
+ },
+ "opensuse103": { "COMPILER": "gcc-4.5",
+ "SCHOST": "opensuse103",
+ "LOGDIR": HLOG, "ECF_OUT": HLOG,
+ "WDIR": WDIR, },
+ "opensuse113": { "COMPILER": "gcc-4.5",
+ "SCHOST": "opensuse113",
+ "LOGDIR": HLOG, "ECF_OUT": HLOG,
+ "WDIR": WDIR, },
+ "opensuse131": { "COMPILER": "gcc-4.8",
+ "SCHOST": "opensuse131",
+ "LOGDIR": HLOG, "ECF_OUT": HLOG,
+ "WDIR": WDIR, },
+ "ecgb": { "COMPILER": "gcc-4.4.7", # redhat
+ "QUEUE": "normal",
+ "QUEUE_EPILOG": "normal",
+ "SCHOST": "ecgb",
+ "LOGDIR": HLOG, "ECF_OUT": HLOG,
+ "WDIR": WDIR, },
+ "lxc": { "COMPILER": "gcc-4.4.7", # redhat
+ "QUEUE": "normal",
+ "QUEUE_EPILOG": "normal",
+ "SCHOST": "lxc",
+ "LOGDIR": HLOG, "ECF_OUT": HLOG,
+ "WDIR": WDIR, },
+ "cct": { "COMPILER": "gcc",
+ "QUEUE_EPILOG": "ns",
+ "SCHOST": "cct",
+ "LOGDIR": HLOG, "ECF_OUT": HLOG,
+ "COMPILE_DIR": "/home/ma/map/sms",
+ "WDIR": "/home/ma/map/sms", },
+ "cca": { "COMPILER": "gcc",
+ "QUEUE_EPILOG": "ns",
+ "SCHOST": "cca",
+ "LOGDIR": HLOG, "ECF_OUT": HLOG,
+ "WDIR": "/home/ma/map/sms", },
+ "ccb": { "COMPILER": "gcc",
+ "QUEUE_EPILOG": "ns",
+ "SCHOST": "ccb",
+ "LOGDIR": HLOG, "ECF_OUT": HLOG,
+ "WDIR": "/home/ma/map/sms",
+ "COMPILE_DIR": "/home/ma/map/sms",
+ }, }
+
+class Compile(object):
+
+ def __init__(self):
+ pass
+
+ def compile(self, host=None, add=None, but=None):
+ version = "4.4.15"
+ if host is None: dest = hosts.keys()
+ else: dest = (host, )
+ out = []
+ for host in sorted(dest):
+ if not but: pass
+ elif host == but or host in but: continue
+ out.append(Family(host).add(
+ add,
+ Variables(hosts[host]),
+ Variables(ECF_FILES= wdir,
+ VERSION= version,
+ ECF_INCLUDE= idir, ),
+ Task("get"),
+ Task("make").add(Trigger(["get"])),
+ Task("install").add(Defcomplete(),
+ Trigger(["make"])),
+ Task("testit").add(Event("cdp"),
+ Event("sms"),
+ Event("child"),
+ Event("xcdp"),
+ Trigger(["make"])),
+ Task("child").add(Defcomplete(),
+ Variables(SMS_VERSION= "4.4.15",),
+ Label("info", ""),
+ Event("1"),
+ Meter("step", -1, 100)),
+ ))
+ return out
+
+ def main(self):
+ self.create_tasks()
+ return Family("sms").add(Family("compile").add(
+ Defstatus("suspended"),
+ # onws("localhost"),
+ Variables(SCHOST= "localhost"),
+ Task("prepare"),
+ self.compile("ibis", add=Trigger("prepare==complete")),
+ Family("remote").add(Trigger("prepare==complete"),
+ self.compile(but="ibis"),)))
+
+ def wrap(self, content):
+ return '''#!/bin/ksh
+# generated by cray.py
+%%manual
+ start - check - stop logsvr
+%%end
+%%include <qsub.h>
+%%include <step1.h>
+%%include <trap.h>
+%s
+%%include <endt.h>
+%%include <step2.h>''' % content
+
+ def create_tasks(self):
+ source = "%SOURCE_DIR:/tmp/map/work/git/sms%"
+ compil = "%COMPILE_DIR:/scratch/ma/map/sms/$ARCH/%/%SCHOST:$HOST%"
+ task = self.wrap("cd %s/sms; make clean; cd ../; tar -czf sms.tgz sms; " % source)
+ create_wrapper("prepare.sms", task)
+
+ task = self.wrap("comp=%s; " % compil +
+ "mkdir -p $comp; cd $comp; scp ibis:%s/sms.tgz .;" % source +
+'''rm -rf sms.tar sms || :
+gzip -d sms.tgz; tar -xf sms.tar''')
+ create_wrapper("get.sms", task)
+
+ task = self.wrap("comp=%s;" % compil +
+ '''cd $comp/sms;
+if [[ $ARCH == cray ]]; then
+module switch PrgEnv-cray PrgEnv-intel
+export CRAYPE_LINK_TYPE=dynamic
+fi
+make %TARGET:linux%''')
+ create_wrapper("make.sms", task)
+
+ task = self.wrap("comp=%s;" % compil +
+ '''cd $comp/sms; make tester;
+mkdir -p %SMSHOME:/tmp/$USER%
+SMS_PROG=900001 sms &
+sleep 10
+xevent sms
+SMS_PROG=900001 smsping localhost || :
+./cdp/cdp -c 'set SMS_PROG 900001; login $HOST $USER 1; terminate -y; exit 0'
+xevent cdp
+DISPLAY=ibis:0.0 ./xcdp/xcdp &
+xevent xcdp
+ln -sf ./cdp/child smsevent
+./smsevent child
+rm -f smsevent''')
+ create_wrapper("testit.sms", task)
+
+ task = self.wrap("xevent 1; xlabel info test; xmeter step 0; xmeter step 100;")
+ create_wrapper("child.sms", task)
+
+##########################################################################
+## BARBER
+
+def call_barber_passerby():
+ # family passby
+ # limit to one at a time entering the
+ # shop to check if there is room to
+ # stay in there
+ return Task("passby").add(
+ Cron("00:00 23:59 00:01"),
+ # this one is regular
+ Variables(ID= 0),
+ Inlimit("limit:passby"))
+ # other frequent passers by can be added here
+# called by client generator task
+
+def call_barber_client(id):
+ return Family(id).add(
+ # to be called by passby to create a new client
+ Task("cut").add(
+ Inlimit("../limit:barbers")),
+ # there may be many barbers in the shop
+ # but one cashier only
+ Task("pay").add(
+ Trigger("./cut == complete"),
+ Inlimit("../limit:barbers"),
+ Inlimit("../limit:cashiers")),
+ Task("leave").add(
+ Trigger("cut==complete and pay==complete"),
+ If(id % 2 == 0,
+ Defcomplete(),
+ Autocancel( "0" ))))
+
+# main definition
+def call_barber_shop():
+ return Family("shop").add(
+ Defstatus("suspended"),
+ Variables(NB_CHAIRS= 4),
+
+ Family("limit").add(
+ Defcomplete(),
+ Limit("passby", 1),
+ Limit("barbers", 1),
+ Limit("cashiers", 1)),
+
+ call_barber_passerby(),)
+
+##########################################################################
+## dinner
+total_number = 5
+life_expectency = 100
+def requeued():
+ return Repeat("iter", 1, life_expectency, kind= "integer")
+ # possibility to requeue the task without duration limit
+ # provided 02:00 is below the task duration:
+ # cron 00:00 23:59 02:00
+
+def triggered(ref, tor=None, tand=None):
+ trg = ""
+ tr2 = ""
+ if tand: trg = " and %s" % tand
+ if tor: tr2 = " or %s" % tor
+ return Trigger("(%s != active and %s != submitted and %s != aborted"
+ % (ref, ref, ref) + trg + ")" + tr2)
+
+def philosopher(id, s1, s2, version):
+ return Family("%d" % id).add(
+ Task("eat").add(
+ Inlimit("../limit:"+str(s1)),
+ Inlimit("../limit:"+str(s2)),
+ Event("release")),
+ If( version == "normal",
+ # eat task a3ttribute
+ # TBD triggered("think")
+ ( requeued(),
+
+ Task("think").add(
+ requeued(),
+ triggered( "eat", tor="eat:release or eat==complete")))),
+ If( version == "simple",
+ (Task("release").add(
+ Trigger("eat:release or eat==complete"),),
+ requeued())))
+
+def call_dinner():
+ out = Family("dinner").add(
+ Variables(SLEEP= 10),
+ Defstatus("suspended"),
+ )
+ for version in "simple normal".split():
+ # Xcdp would fold parent family when limits change
+ # we prefer to store them in a dedicated family then
+ lim = Family("limit").add(
+ Defcomplete(),)
+# for num 1 $total_number do num 1 $total_number do
+# $total_number do num 1 $total_number do
+ num = 1
+ while num <= total_number:
+ lim.add(Limit(str(num), 1))
+ num += 1; # endfor
+ ver = Family(version).add(lim)
+ out.add(ver)
+# for num 1 $total_number do num 1 $total_number do
+# $total_number do num 1 $total_number do
+ num = 1
+ while num <= total_number:
+ stick1 = num
+ stick2 = 1 + ((num) % total_number)
+ ver.add(philosopher( num, stick1, stick2, version))
+ num += 1; # endfor
+ return out
+
+##########################################################################
+## CONSUMER
+# /home/ma/map/course/course2011/src/consumer.py
+beg = 0
+fin = 48
+by = 3
+
+def not_consumer(): return Variables(CONSUME= "no")
+
+def not_producer(): return Variables(PRODUCE= "no")
+
+def ev():return (Event("p"), Event("c"))
+
+def call_task(name, start, stop, inc):
+ meter = None
+ if start != stop:
+ meter = Meter( "step", -1, int(stop))
+
+ return Task(name).add(
+ ev(),
+ Variables(BEG= start,
+ FIN= stop,
+ BY= inc),
+ meter)
+
+def call_consumer(SELECTION):
+ # defstatus suspended # avoid early start
+ def consume1(leap = 1, leap_nb = 3):
+ out = []
+ while leap <= leap_nb:
+ leap_beg = beg + by * (leap - 1)
+ leap_by = by * leap_nb
+ out.append(Family("%d" % leap).add(
+ call_task( "consume", "'%STEP%'", "'%STEP%'", leap_by).add(
+ Repeat("STEP", leap_beg, fin, leap_by, kind="integer"),
+ # same trigger as consume0
+ # Trigger("(%s and (consume:STEP le %s1/produce:STEP)) or " % (lead, prod) +
+ # "(not %s and (consume:STEP le %s0/produce:step))" % (lead, prod))
+ Trigger("(consume:STEP le %s1/produce:STEP)" % prod),
+ )))
+ leap += 1;
+ return out
+
+ def consume2(idx, fin):
+ out = []
+ while idx <= fin:
+ out.append(Family("%03d" % idx).add(
+ call_task( "consume", idx, idx, by).add(
+ Variables(STEP= idx),
+ # Same trigger as consume0
+ # Trigger("(%s and (consume:STEP le %s1/produce:STEP)) or " % (lead, prod) +
+ # "(not %s and (consume:STEP le %s0/produce:step))" % (lead, prod))))
+ Trigger("consume:STEP le %s1/produce:STEP" % prod),
+ )))
+ idx += by
+ return out
+
+ lead = "/%s/consumer/admin/leader:1" % SELECTION
+ prod = "/%s/consumer/produce" % SELECTION
+ if 1: return Family("consumer").add(Defcomplete()) # FIXME
+ return Family("consumer").add(
+ Defcomplete(),
+
+ Variables(SLEEP= 10,
+ PRODUCE= "no",
+ CONSUME= "no"),
+
+ Family("limit").add(
+ Defcomplete(),
+ Limit("consume", 7),),
+
+ Family("admin").add(
+ # set manually with Xcdp or alter the event 1 so
+ # that producer 1 becomes leader
+ # default is producer0 leads
+ Task("leader").add(
+ Event("1"),
+ Defcomplete())),
+ # text this task is dummy task not designed to run
+
+ # default : task does both :
+ Variables(PRODUCE= "yes",
+ CONSUME= "yes"),
+ # this task will do both, ie serial
+
+ call_task( "produce", beg, fin, by).add(
+ Label("info", "do both at once"),),
+ # this will loop inside the task, reporting
+ # its processed step as a meter indication
+
+ Family("produce0").add(
+ not_consumer(),
+ call_task( "produce", beg, fin, by )),
+ # here, choice is to push a new task for each step
+
+ Family("produce1").add(
+ not_consumer(),
+ call_task( "produce", '%STEP%', "%STEP%", by ).add(
+ Repeat("STEP", beg, fin, by , kind="integer"), )),
+ # PRB edit FIN '$((%STEP% + %BY%))'
+
+ Family("consume").add(
+ not_producer(),
+ Inlimit("limit:consume"),
+ Variables(CALL_WAITER= 1,
+ # $step will be interpreted in the job!
+ TRIGGER= "../produce:step -gt consume:$step or ../produce eq complete"),
+ call_task( "consume", beg, fin, by ).add(
+ )),
+
+ Family("consume0or1").add(
+ not_producer(),
+ Inlimit("limit:consume"),
+ call_task( "consume", "%STEP%", "%STEP%", by, ),
+ Repeat( "STEP", beg, fin, by, kind="integer"),
+ Trigger("(%s and (consume0or1:STEP le %s1/produce:STEP)) or "
+ % (lead, prod) +
+ "(not %s and (consume0or1:STEP le %s0/produce:step))"
+ % (lead, prod))),
+
+ Family("consume1").add(
+ not_producer(),
+ Inlimit("limit:consume"),
+ consume1()),
+
+ Family("consume2").add(
+ # loop is "exploded"
+ # consume limit may be changed manually with Xcdp
+ # to reduce or increase the load
+ Inlimit("limit:consume"),
+ not_producer(),
+ consume2(beg, fin)))
+
+##########################################################################
+class Cray(ic.SeedOD):
+ def __init__(self):
+ super(Cray, self).__init__()
+
+ def setup(self, node):
+ account= "UNSET"
+ global user, host
+ if user == "emos" or host in ("ode", "eode", "ecf"):
+ rdir = "/vol/lxop_emos_nc/output"
+ user= "emos"
+ account= "oesu"
+ else: pass
+ self.defs.add_extern("/o/main:YMD")
+
+ node.add(
+ Clock("real"),
+ Defstatus("suspended"),
+ Label("info", "test,logsvr tasks generated by cray.py"),
+ Event("1"),
+ Meter("step", -1, 100),
+ Repeat(kind="day", step=1),
+ limits(),
+
+ Variables(ECF_JOB_CMD= SUBMIT,
+ ECF_KILL_CMD= KILL,
+ ECF_STATUS_CMD= STATUS,
+ ECF_CHECK_CMD= CHECK,
+ # ECF_EXTN= ".sms",
+ ACCOUNT= "UNSET",
+ SCHOST= "localhost",
+ ECF_INCLUDE= idir,
+ ECF_HOME= jdir,
+ ECF_FILES= wdir,
+ QUEUE= "ns", USER= user, LOGDIR= "/tmp",
+ TOPATH= udir + "/logs",
+ SLEEP= 1, # x120
+ ECF_TRIES= 1,),
+
+ Family("looper").add(Time("09:00"),
+ Variables(SCHOST= "ibis"),
+ dummy()), # .add(Defcomplete())),
+
+ create_de(),
+
+ smhi(),
+
+ Compile().main(),
+
+ Task("dummy").add(Time("16:00"),
+ Variables(SCHOST= "localhost",
+ FAMILY= "unset",
+ FAMILY1= "unset"),
+ Time("17:00"),),
+
+ fam_ui(),
+
+ # turkey(ic.selection()),
+
+ sapp(),
+
+ Family("maker").add(maker(),),
+
+ call_consumer(ic.selection()).add(
+ Label("repeat", "repeat may be attached to a family, or a task, to facilitate requeue or not"),
+ Label("event", "event may be set by the task itself, by a user, by a third party job"),
+ Label("trigger", "can be on the task-family node, or inside a task (wait)"),
+ Label("deadlock", "produce0/produce complete with step=-1"),
+ Label("latency", "between task wrapper creation, and new file visible from the server"),
+ Label("ZZZ", "icon when the job is waiting the trigger condition"),
+ Variables(QUEUE= "ns", USER= user, LOGDIR= "/tmp",
+ SCHOST="localhost"),),
+
+ call_barber_shop().add(Defstatus("complete"),),
+
+ call_dinner().add(Defstatus("complete"),),
+
+ pyth.task(),
+
+ perl.task(),
+
+ ruby.task(),
+
+ Family("blacklist").add(
+ Event("cca"),
+ Event("ccb"),
+ Event("hps"),
+
+ Defstatus("complete")) )
+
+ msg = "have you? setup ssh login, created remote directory"
+ msg += ", set START_LOGSVR=1 (edit task), once, to launch the logserver"
+ if "eod" in host: user = "emos"
+ print "#MSG: host, user", host, user
+
+ node = node.family("submit").add(
+ unit("jonas", "ibis", "no", "/tmp/$USER/jobs", add=(Today("07:00"),
+ Today("21:00"))),
+ Variables(USER= user,
+ ACCOUNT= account), #
+
+ # Time("09:00"),
+
+ self.arg4(),
+ self.burst(),
+ # self.arg3(),
+ # self.prb(),
+
+ )
+
+ def burst(self):
+ sub = "/home/ma/emos/bin/smssubmit "
+ out = []
+ for num in xrange(0, 10):
+ out.append(Family("%03d" % num).add(Task("test")))
+
+ return Family("arg3").add(
+ Defstatus("complete"),
+ Variables(SCHOST= "cca-b"),
+ out
+ )
+
+ def arg3(self):
+ sub = "/home/ma/emos/bin/smssubmit "
+ return Family("arg3").add(
+ Defstatus("complete"),
+
+ self.submits(),
+
+ Variables(ECF_JOB_CMD= sub +"%USER% %SCHOST% %ECF_JOB%",
+ ECF_KILL_CMD= sub + "%USER% %SCHOST% %ECF_JOB% kill",
+ ECF_STATUS_CMD= sub + "%USER% %SCHOST% %ECF_JOB% status",
+ ),
+ )
+
+ def arg4(self):
+ return Family("arg4").add(self.submits())
+
+ def prb(self):
+ sub = "/home/ma/emos/bin/smssubmit "
+ return Family("prb").add(
+ Defstatus("complete"),
+ self.submits(),
+ Label("info", "simulate prb at submission with % remaining"),
+ Variables(ECF_JOB_CMD= sub +"%USER% %SCHOST% %ECF_JOB% %STTHOST%%ECF_JOBOUT%",
+ ECF_KILL_CMD= sub + "%USER% %SCHOST% %ECF_JOB% %STTHOST%%ECF_JOBOUT% kill",
+ ECF_STATUS_CMD= sub + "%USER% %SCHOST% %ECF_JOB% %STTHOST%%ECF_JOBOUT% status",
+ ), )
+
+ def submits(self):
+ global host, user
+ def parallel(pes=1, thr=1, hyp="no"):
+ return Family("p%d_%d_%s" %(pes, thr, hyp)).add(
+ Variables(NPES=pes, THREADS=thr,
+ HYPER=hyp),
+ Task("test").add(Label("info", ""),
+ Meter("step", -1, 120),
+ Event(1)))
+ ct1logs= "/sc1/tcwork/emos/logs"
+ # ct1logs = '/home/ma/%s/logs' % user
+ if ecflow: base = 1000
+ else: base = 900000
+ base = 1000
+ if "eod" in host: user = "emos"
+
+ out = [
+
+ unit("cray", HCRAY, "ns", ct1logs, leaf=False).add(
+ unit("ccp", "cca-login1", "ns", ct1logs).add(
+ Complete(ic.psel() + "/blacklist:cca"),),
+ unit("cca", "cca-login1", "ns", ct1logs).add(
+ logsvr("ping"),
+ Complete(ic.psel() + "/blacklist:cca"),),
+ unit("ccb", "ccb-login1", "ns", ct1logs).add(
+ logsvr("ping"), ),
+ Family("parallel_a").add(
+ # Defcomplete(), ###
+ Complete(ic.psel() + "/blacklist:cca"),
+ Variables(SCHOST= "cca",
+ QUEUE= "os",
+ LOGHOST= "cca-il2",
+ ECF_OUT= ct1logs,
+ LOGDIR= ct1logs,),
+ parallel(1, 1),
+ parallel(1, 24),
+ parallel(2, 12),
+ parallel(2, 24),
+ parallel(2, 15),
+
+ parallel(1, 2, "yes"),
+ parallel(2, 24, "yes"),
+ parallel(24, 2, "yes"),
+ parallel(10, 5, "yes"),),
+
+ Family("parallel_b").add(
+ Complete(ic.psel() + "/blacklist:ccb"),
+ Variables(SCHOST= "ccb",
+ QUEUE= "os",
+ LOGHOST= "ccb-il2",
+ ECF_OUT= ct1logs,
+ LOGDIR= ct1logs,),
+ parallel(1, 1),
+ parallel(1, 24),
+ parallel(2, 12),
+ parallel(2, 24),
+ parallel(2, 15),
+
+ parallel(1, 2, "yes"),
+ parallel(2, 24, "yes"),
+ parallel(24, 2, "yes"),
+ parallel(10, 5, "yes"),),
+
+ If(user == "emos",
+ Variables(LOGHOST= HCRAY,
+ LOGPORT= base + get_uid()),
+ Variables(LOGHOST= HCRAY,
+ LOGPORT= base + get_uid())),
+ )
+ ]
+
+ lxop_out = "/vol/lxop_emos_nc/output"
+ if user == "emos" or host in ("ode", "eode", "ecf"):
+ ic.SUBM = "/home/ma/emos/bin/trimurtu"
+ sms2ecf.subm = "/home/ma/emos/bin/trimurti"
+
+ out += (
+ Variables(LOGPORT= 9316),
+ unit("cca", "cca", "ns", "/sc1/tcwork/emos_dir", "oesu").add(
+ Variables(STHOST= "/c1",
+ LOGHOST= "cca"),
+ logsvr("ping"),
+ Complete(ic.psel() + "/blacklist:cca"),),
+
+ unit("ecgb", "ecgb", "emos", "/vol/emos_nc/output"),
+ unit("lxc", "lxc", "emos", "/vol/emos_nc/output"),
+ unit("lxab", "lxab", "serial", "/vol/emos_nc/output"),
+ unit("lxop", "lxop", "emos", lxop_out
+ ).add(Variables(ECF_OUT= lxop_out,
+ ECF_LOGHOST= "lxop",
+ ECF_LOGPORT= 9316,
+ LOGDIR= lxop_out, )),
+ unit("sappa", "sappa", "serial", "/vol/emos_nc/output"),
+ unit("sappb", "sappb", "serial", "/vol/emos_nc/output"),
+ unit("opensuse131", "opensuse131", "serial", "/vol/emos_nc/output"),
+ Family("hps").add(
+ Complete(ic.psel() + "/blacklist:hps"),
+ unit("acq", "acq", "emos", "/tmp/emos"),
+ unit("pp1", "pp1", "emos", "/tmp/emos"),
+ unit("pp2", "pp2", "emos", "/tmp/emos"),
+ unit("pp3", "pp3", "emos", "/tmp/emos"),
+ unit("pp4", "pp4", "emos", "/tmp/emos"),
+ unit("bilbo", "bilbo", "emos", "/tmp/emos"),
+ unit("hallas", "hallas", "emos", "/tmp/emos"),
+ # unit("itanium", "itanium", "emos", "/tmp/emos"),),
+ unit("localhost", "localhost", "ns", "/tmp/emos/logs"),
+ unit("ibis", "ibis", "ns", "/tmp/emos/logs"),
+ ))
+ else:
+ rdir = "/tmp"
+ out += (unit("localhost", "localhost", "ns", "/tmp/%s/logs" % user),
+ unit("lxab", "lxab", "serial", udir + "/logs"),
+ unit("lxop", "lxop", "emos", udir + "/logs"),
+ unit("ecgb", "ecgb", "ns", udir + "/logs"),
+ unit("lxc", "lxc", "ns", udir + "/logs"), )
+ return out
+
+def maker():
+ return Task("maker").add(
+ Variables(ECF_FILES= wdir,
+ ECF_INCLUDE= "/home/ma/emos/def/o/include",
+ WSHOST= "ibis",
+ USER= "emos",
+ SCHOST= "ibis",
+ ECF_OUT= "/vol/lxop_emos_nc/output",), )
+
+def usage():
+ print '''cray.py -h -u [user] -n [node] -s [suite-name] \
+ -e: ecflow'''
+
+if __name__ == "__main__":
+ global user, udir, ecflow, host
+ suites = { "cray": Cray,
+ "test": Cray,
+ }
+ # suite = "test"; node = "eode"
+ # argv = cli_proc.process(suites, selection=suite, host=node)
+ user = get_username()
+ try: host = sys.argv[-1]
+ except: host= "localhost"
+ ecflow = False
+ ecflow = True
+ suite = None
+ user = get_username()
+ opts, args = getopt.getopt(
+ sys.argv[1:], "hp:u:es:n:p:",
+ ["help", "port", "user", "ecflow", "suite", "node", "path"])
+ print "#MSG: opts, args", opts, args
+
+ output = None
+ verbose = False
+ for o, a in opts:
+ if o in ("-n", "--node"): host = a
+ elif o in ("-h", "--help"): usage(); sys.exit()
+ elif o in ("-s", "--suite"): suite = a
+ elif o in ("-p", "--path"): path = a
+ elif o in ("-e", "--ecflow"): ecflow = True
+ elif o in ("-u", "--user"):
+ user = a
+ elif o in ("-p", "--port"):
+ port = a
+ else: print "#ERR: what?", o, a; assert False, "unhandled option"
+
+ import cli_proc
+
+ if suite is None:
+ cli_proc.ip.SELECTION = user
+ elif '/' in suite:
+ sel = suite
+ if '/' == suite[0]: sel = sel[1:]
+ if '/' in sel: sel, family = sel.split('/', 1)
+ cli_proc.ip.SELECTION = sel
+ else: cli_proc.ip.SELECTION = suite
+
+ if ecflow and host not in ("ode", "map", "pikachu"):
+ ic.ecf.ECF_MODE = "ecflow"
+ else:
+ import sms2ecf
+ sms2ecf.ECF_MODE = "sms"
+ ic.ecf.ECF_MODE = "sms"
+
+ print "#MSG: ecflow/sms: ", ic.ecf.ECF_MODE
+ global wdir, rdir, fdef, jdir
+
+ ########### SETTINGS ################
+ udir = pwd.getpwnam(user).pw_dir
+ wdir = udir + "/course/cray"
+ rdir = "/sc1/tcwork/emos/logs"
+ fdef = wdir + "/cray.def"
+ jdir = "/tmp/%s/cray" % user
+ ddef = udir + "/course/cray"
+ fdef = ddef + "/cray.def"
+ idir = "/home/ma/emos/def/cray/include"
+ if user == "map" or host in ["map", ]:
+ wdir = "/home/ma/map/course/cray"
+ elif user == "emos" or host in ["ode", "od3", "eode"]:
+ jdir="/vol/lxop_emos_nc/output"
+ rdir="/vol/lxop_emos_nc/output"
+ udir="/vol/lxop_emos_nc/output"
+
+ print "##", host, suite
+ argv = cli_proc.process(suites, selection=suite, host=host, proc=False)
+ try: os.makedirs(wdir)
+ except: pass # one line on purpose
+ try: os.makedirs(jdir)
+ except: pass
+
+ create_task()
+ create_smhi()
diff --git a/Pyext/samples/def2def.py b/Pyext/samples/def2def.py
new file mode 100755
index 0000000..0f269fe
--- /dev/null
+++ b/Pyext/samples/def2def.py
@@ -0,0 +1,274 @@
+#!/usr/bin/env python
+# This software is provided under the ECMWF standard software license agreement.
+import sys
+try: import ecflow
+except:
+ sys.path.append("/usr/local/apps/ecflow/current/lib/python2.7/site-packages/ecflow")
+ import ecflow
+import ecflow as ec
+import sys
+""" a simple program to convert an expanded definition file to
+py script using ecf.py"""
+
+class Indent:
+ """This class manages indentation, for use with context manager
+ It is used to correctly indent the definition node tree hierarchy
+ """
+ _pos = 0
+ _step = 3
+ def __init__(self):
+ Indent._pos += Indent._step
+ def __del__(self):
+ Indent._pos -= Indent._step
+ @classmethod
+ def indent(cls, loc=''):
+ for i in range(Indent._pos):
+ if loc is None:
+ print ' '
+ elif type(loc) == str:
+ loc += ' '
+ else:
+ loc.write(' ')
+ if type(loc) == str:
+ return loc
+
+def adds(line=0):
+ if line is None:
+ return ""
+
+ return Indent.indent() + line + "\n"
+
+def add(line, echo=0):
+ if line is None:
+ return
+ elif echo:
+ print Indent.indent() + line
+ else:
+ return Indent.indent() + line + "\n"
+
+class DefFormat(object):
+ def __init__(self, defs):
+ self.defs = defs
+
+ def process_attr(self, node, end=False):
+ res = ""
+ ind = Indent()
+ defstatus = node.get_defstatus()
+ if defstatus:
+ if defstatus != ec.DState.queued:
+ res += add("Defstatus('%s')," % defstatus)
+
+ item = node.get_autocancel()
+ if item:
+ line = "%s" % item
+ line = line.replace("autocancel ", "")
+ res += add("Autocancel('%s')," % line)
+
+ item = node.get_repeat()
+ if not item.empty():
+ line = "%s" % item
+ full = line.split()
+ kind = full[1]
+ name = full[2]
+ try:
+ beg = full[3]
+ try: end = full[4]
+ except: end = beg
+ if "#" in end: end = beg
+ except: beg = 1; end = 1
+ by = 1
+ if len(full) == 6: by = full[5]
+
+ if kind in ("integer", "date"):
+ res += add(
+ "Repeat(kind='%s', name='%s', start=%s, end=%s, step=%s),"
+ % ( kind, name, beg, end, by))
+ elif kind in ("day", ):
+ res += add(
+ "Repeat(kind='%s', name='%s', step=%s),"
+ % ( kind, name, by))
+ elif kind in ("string", "enumerated"):
+ line = "%s" % item
+ line = line.replace("repeat %s %s" % (kind, name), "")
+ line.replace('"', '')
+ res += add("Repeat(kind='%s', name='%s', start=%s)," % (
+ kind, name, line.split()))
+ # FIXME string enum
+
+ item = node.get_late()
+ if item:
+ line = "%s" % item
+ line = line.replace("late ", "")
+ res += add("Late('%s')," % line)
+
+ item = node.get_complete()
+ if item: res += add("Complete('%s')," % item)
+
+ item = node.get_trigger()
+ if item:
+ res += add("Trigger('%s')," % item)
+
+ for item in node.meters:
+ line = "%s" % item
+ dummy, name, beg, end, thr = line.split(" ")
+ res += add("Meter('%s', %s, %s, %s)," % (name, beg, end, thr))
+
+ for item in node.events:
+ line = "%s" % item
+ line = line.replace("event ", "").strip()
+ res += add("Event('%s')," % line)
+
+ for item in node.labels:
+ res += add("Label('%s', '%s')," % (item.name(), item.value()))
+
+ for item in node.limits:
+ val = item.value()
+ if val == "0" or val == 0:
+ val = "1"
+ res += add("Limit('%s', %d)," % (
+ item.name(), int(val)))
+
+ for item in node.inlimits:
+ line = "%s" % item
+ line = line.replace("inlimit ", "")
+ res += add("InLimit('%s')," % line)
+
+ for item in node.times:
+ line = "%s" % item
+ line = line.replace("time ", "")
+ res += add("Time('%s')," % line)
+
+ for item in node.todays:
+ line = "%s" % item
+ line = line.replace("today ", "")
+ res += add("Today('%s')," % line)
+
+ for item in node.dates:
+ line = "%s" % item
+ line = line.replace("date ", "")
+ res += add("Date('%s')," % line)
+
+ for item in node.days:
+ line = "%s" % item
+ line = line.replace("day ", "")
+
+ res += add("Day('%s')," % item)
+ for item in node.crons:
+ line = "%s" % item
+ line = line.replace("cron ", "")
+ res += add("Cron('%s')," % line)
+
+ var = "Variables("
+ vind = Indent()
+ num = 0
+ for item in node.variables:
+ sep="'"
+ if sep in item.value(): sep="\""
+ var += ind.indent("\n") + item.name() + \
+ "= %s%s%s," % (sep, item.value(), sep)
+ num += 1
+ del vind
+ if num: res += add(var + "),")
+
+ del ind
+ if len(res) == 0:
+ return None
+ return res
+
+ def process(self, node=None, inc=0):
+ STREAM = 1
+ if node is None:
+ num = 0
+ print "# ecf.ECF_MODE = 'sms'"
+ print "suites = []"
+ for suite in self.defs.suites:
+ if STREAM: print "suite%d = Suite('%s').add(" % (num, suite.name())
+ else: print "s = Suite('%s')"% (suite.name()) + "; suites.append(s);"
+ self.process(suite)
+ print ")"
+ num += 1
+ if num > 1:
+ if 0: raise BaseException("no more than one suite at a time")
+ print "### WARNING: more than one suite defined"
+
+ elif isinstance(node, ec.Suite):
+ if not STREAM: print "s.add(\n"
+ add( self.process_attr(node),1 )
+ if STREAM: ind = Indent()
+ for kid in node.nodes: self.process(kid)
+ if STREAM: del ind
+
+ elif isinstance(node, ec.Family):
+ many = ""; one = ""; post = "" # circumvent limitation to 255 items
+ if inc % 200 == 0:
+ one += "("; post = "),"
+ if inc > 200: many = "),"
+ if STREAM:
+ add( many + one + "Family('%s').add(" % node.name(), 1)
+ res = self.process_attr(node)
+ else:
+ print ")\ncur = Family('%s')" % node.name()
+ print "fam.add(cur); fam = cur; fam.add("
+ res = self.process_attr(node)
+
+ if STREAM:
+ if res is not None:
+ print Indent.indent(res)
+ ind = Indent()
+ num = 0
+ for kid in node.nodes: self.process(kid, num) ; num += 1
+ if STREAM:
+ del ind
+ add( Indent.indent(post + "), # endfamily %s" % node.name()), 1 )
+ print "# ", num
+ elif isinstance(node, ec.Task):
+ res = self.process_attr(node)
+ if res is None:
+ add( "Task('%s')," % node.name(), 1)
+ else: add( "Task('%s').add(\n" % node.name() +
+ "%s%s)," % (res, Indent.indent()), 1)
+
+ def main(self):
+ self.header()
+ self.process()
+ self.footer()
+
+ def header(self):
+ print """#!/usr/bin/env python
+# NOTICE: this file was originally created with def2def.py
+import sys
+# sys.path.append('../o/def')
+# sys.path.append('.')
+sys.path.append('/home/ma/emos/def/o/def')
+from ecf import *
+import ecf as ecf
+# import inc_emos as ie
+"""
+
+ def footer(self):
+ print """
+if __name__ == '__main__':
+ defs = Defs()
+ defs.add(suite0);
+ defs.auto_add_externs(True)
+ if 0:
+ import cli_proc, ecf
+ cli_proc.process(ie.Seed(defs), compare=False)
+ else:
+ port = 1500 + int(get_uid()) # when started with ecflow_start.sh # ECMWF
+
+ if 0: # test job creation
+ job_ctrl = ecflow.JobCreationCtrl()
+ defs.check_job_creation(job_ctrl)
+
+ print "loading on localhost@%s" % port
+ client = ecf.Client("localhost", port)
+ client.replace("/%s" % suite0.name(), defs)
+"""
+if __name__ == '__main__':
+ filename = sys.argv[1]
+ defs = ec.Defs(filename)
+ defs.auto_add_externs(True)
+ if 0: print defs
+ DefFormat(defs).main()
+
diff --git a/Pyext/samples/ecf.py b/Pyext/samples/ecf.py
new file mode 100755
index 0000000..2ec00b2
--- /dev/null
+++ b/Pyext/samples/ecf.py
@@ -0,0 +1,1045 @@
+#!/usr/bin/env python
+# This software is provided under the ECMWF standard software license agreement.
+""" a layer over raw ecflow api
+
+use 'export ECF_DEBUG_LEVEL=10' to remove warning message related to
+variables overwrite
+
+"""
+
+import pwd, os, unittest
+try:
+ from ecflow import TimeSlot
+ from ecflow import JobCreationCtrl as JobCreationCtrl
+ from ecflow import ChildCmdType
+ from ecflow import ZombieType, ZombieAttr, ZombieUserActionType
+except: print "# ecf.py cannot import few types"
+
+import ecflow
+ecflow.Ecf.set_debug_level(3)
+
+DEBUG = 0
+# DECORATE = "ONLY_TRIGGER"
+# DECORATE = "NO_TRIGGER"
+# DECORATE = "ONLY_EVENT"
+# DECORATE = "NO_ATTRIBUTE"
+DECORATE = "ALL"
+
+USE_TIME = True
+USE_LATE = False
+USE_TRIGGER = True
+USE_LIMIT = True
+
+if DECORATE == "NO_TRIGGER":
+ USE_TRIGGER = False
+ USE_LIMIT = True
+ USE_EVENT = True
+elif DECORATE == "ONLY_TRIGGER":
+ USE_TRIGGER = True
+ USE_LIMIT = False
+ USE_EVENT = False
+elif DECORATE == "NO_ATTRIBUTE":
+ USE_TRIGGER = False
+ USE_LIMIT = False
+ USE_EVENT = False
+elif DECORATE == "ONLY_EVENT":
+ USE_TRIGGER = False
+ USE_LIMIT = False
+ USE_EVENT = True
+elif DECORATE == "ALL":
+ USE_TRIGGER = True
+ USE_LIMIT = True
+ USE_EVENT = True
+else: raise BaseException
+
+def get_username():
+ return pwd.getpwuid( os.getuid() )[ 0 ]
+def get_uid():
+ return pwd.getpwnam(get_username()).pw_uid
+
+def translate(name, value=None):
+ """ Translate from sms to ecflow """
+ import sms2ecf, sys
+ def is_sms():
+ if sys.argv[-1] in ( # "localhost"
+ "sms", "od3", "ode","pikachu","ibis","map", "od", "od2", ):
+ sms2ecf.ECF_MODE = "sms"
+ return True
+ return sms2ecf.ECF_MODE == "sms"
+ if is_sms():
+ sms2ecf.ECF_MODE = "sms"
+ return sms2ecf.translate(name, value)
+ return name, value
+
+class State:
+ """ this class aims at affording a user the possibility to add Triggers as
+ t1 = Task("t1")
+ Task("ts").add(Trigger(t1 == COMPLETE))
+
+ SUBMITTED, ACTIVE, SUSPENDED, ABORTED, QUEUED, COMPLETE, UNKNOWN
+ are instance of this class.
+ """
+
+ def __init__(self, state):
+ """ store the status """
+ self.state = str(state)
+
+ def __str__(self):
+ """ translate into string """
+ return "%s" % self.state
+
+ def __eq__(self, arg):
+ """ when == is used, we should care about task name starting with 0-9"""
+ if type(arg) == str:
+ add = ""
+ if type(arg[0]) == int:
+ add = "./"
+ return add + arg + " == " + self.state
+ elif isinstance(arg, ecflow.Node):
+ return arg.get_abs_node_path() + " == " + self.state
+ return False
+
+ def __ne__(self, arg):
+ """ aka != """
+ if type(arg) == str:
+ add = ""
+ if type(arg[0]) == int:
+ add = "./"
+ return add + arg + " != " + self.state
+ elif isinstance(arg, ecflow.Node):
+ return arg.get_abs_node_path() + " != " + self.state
+ return False
+
+ def value(self):
+ """ return state """
+ return self.state
+
+ def eval(self, node):
+ """ return state """
+ return self.state == node.get_state()
+
+
+
+SUBMITTED = State("submitted")
+ACTIVE = State("active")
+SUSPENDED = State("suspended")
+ABORTED = State("aborted")
+QUEUED = State("queued")
+COMPLETE = State("complete")
+UNKNOWN = State("unknown")
+
+class Attribute(object):
+ """ generic attribute to be attached to a node"""
+ def add_to(self, node):
+ """ use polymorphism to attach attribute to a node"""
+ pass
+
+class Variable(Attribute, ecflow.Variable):
+ """ filter variables to be attached to a node, may alter its name SMS-ECF"""
+ def add_to(self, node):
+ """ add_variable"""
+ keyt, valt = translate(self.name(), self.value())
+ if "/tc1/emos_es" in valt: raise BaseException # FIXME
+ node.add_variable(keyt, valt)
+
+class Label(Attribute, ecflow.Label):
+ """ wrap around label"""
+ def add_to(self, node):
+ """ add_label"""
+ node.add_label(self)
+
+class Meter(Attribute, ecflow.Meter):
+ """ wrap around meter"""
+ def add_to(self, node):
+ """ add_meter"""
+ node.add_meter(self)
+
+class Event(Attribute, ecflow.Event):
+ """ wrap around event"""
+ def add_to(self, node):
+ """ add_event"""
+ node.add_event(self)
+
+class InLimit(Attribute):
+ """ a class to host a path for a limit
+ silently ignore if USE_LIMIT is False,
+ (in debug mode) """
+
+ def __init__(self, fullpath):
+ self.data = None
+ if USE_LIMIT:
+ try: path, name = fullpath.split(":")
+ except: name = fullpath; path = ""
+ if name is None: raise BaseException
+ self.data = ecflow.InLimit(name, path)
+ self.path_ = path
+ self.name_ = name
+
+ def add_to(self, node):
+ """ add_inlimit"""
+ if USE_LIMIT and self.data is None: raise BaseException
+ if USE_LIMIT and self.data is not None:
+ node.add_inlimit(self.data)
+
+ def value(self):
+ """ get limit fullpath-name """
+ return self.path_ + ":" + self.name_
+
+ def name(self):
+ """ get limit name """
+ return self.name_
+
+class Inlimit(InLimit):
+ def __init__(self, fullpath):
+ super(Inlimit, self).__init__(fullpath)
+
+class Trigger(Attribute):
+ """ add trigger (string, list of task names, or directly
+ expression and: and'ed (True) or or'ed (False) unk: add or
+ [name]==unknown for RD
+ """
+ def __init__(self, expr, unk=False, anded=True):
+ self.expr = None
+ if expr is None:
+ return
+ if expr == "":
+ return
+ if type(expr) == str:
+ # self.expr = ecflow.Expression(expr)
+ self.expr = expr
+ return
+ if type(expr) == tuple:
+ prep = list(expr)
+ expr = prep
+
+ if type(expr) == list:
+ for index, name in enumerate(expr):
+ if name == None:
+ continue
+ pre = ""
+
+ if type(name) in (Node, Task, Family, Suite):
+ fullname = name.fullname()
+ name = fullname
+ elif type(name) in (ecflow.Task, ecflow.Family):
+ name = name.name()
+ else: pass
+
+ if name[0].isdigit(): pre = "./" # "0123456789":
+
+ if ':' in name:
+ item = pre + name
+ else:
+ item = pre + "%s == complete" % name
+ if unk: item += " or %s%s==unknown" % (pre, name)
+ else: pass
+
+ if item is None: self.expr = None
+ elif index == 0 or self.expr is None:
+ self.expr = item
+ elif item is None: return
+ else: self.expr += " and %s" % item
+
+ elif type(expr) in (ecflow.Expression,
+ ecflow.PartExpression):
+ self.expr = ecflow.Expression(str(item))
+ else:
+ print type(expr)
+ raise Exception("what? trigger?")
+
+ def add_to(self, node):
+ if not USE_TRIGGER:
+ return
+ if self.expr is None:
+ return
+ if node.get_trigger() is None:
+ node.add_trigger(self.expr)
+ else: node.add_part_trigger(ecflow.PartExpression(self.expr, True))
+
+class TriggerAnd(Trigger):
+ def __init__(self, expr, unk=False, anded=True):
+ self.expr = expr
+ if (not ":" in expr and
+ not " eq " in expr and
+ not "==" in expr):
+ self.expr += " eq complete"
+ def add_to(self, node):
+ node.add_part_trigger(ecflow.PartExpression(self.expr, True))
+
+class TriggerImpossible(Trigger):
+ """ attribute to be added to node when it is not expected to run
+ any task"""
+
+ def __init__(self):
+ """ add an 'impossible trigger', for a task not to run """
+ super(TriggerImpossible, self).__init__("1==0")
+
+class TriggerAlways(Trigger):
+ """ attribute to be added to node when it is not expected to run
+ any task"""
+
+ def __init__(self):
+ """ add an 'impossible trigger', for a task not to run """
+ super(TriggerAlways, self).__init__("1==1")
+
+class Complete(Trigger):
+ """ class to host complete expression, added later to a node"""
+ def __init__(self, expression, unk=False, anded=False):
+ super(Complete, self).__init__(expression, unk, anded)
+
+ def add_to(self, node):
+ if USE_TRIGGER and self.expr is not None:
+ node.add_complete(self.expr)
+
+class Clock(Attribute):
+ """ wrapper to add clock """
+ def __init__(self, arg):
+ if type(arg) == str:
+ hybrid = "hybrid" in arg
+ hhh, mmm, sss = [0, 0, 0]
+ try:
+ hhh, mmm, sss = arg.split(':')
+ self.data = ecflow.Clock(hhh, mmm, sss, hybrid)
+ except:
+ self.data = ecflow.Clock(hybrid)
+ else: self.data = ecflow.Clock(arg)
+
+ def add_to(self, node):
+ if type(node) != Suite:
+ print "WAR: clock can only be attached to suite node, "
+ print "WAR: clock is ignored"
+ return
+ node.add_clock(self.data)
+
+class AutoCancel(Attribute):
+ """ wrapper to add time """
+ def __init__(self, arg):
+ if type(arg) == str:
+ hhh, mmm = arg.split(':')
+ rel = '+' in arg
+ self.data = ecflow.Autocancel(int(hhh), int(mmm), rel)
+ else: self.data = ecflow.Autocancel(arg)
+
+ def add_to(self, node):
+ node.add_autocancel(self.data)
+
+class Time(Attribute):
+ """ wrapper to add time """
+ def __init__(self, arg):
+ self.data = arg
+
+ def add_to(self, node):
+ if USE_TIME and self.data is not None:
+ node.add_time(self.data)
+
+class Today(Time):
+ """ wrapper to add time """
+ def __init__(self, arg):
+ self.data = arg
+
+ def add_to(self, node):
+ if USE_TIME and self.data is not None:
+ node.add_today(self.data)
+
+class Cron(Time):
+ """ wrapper to add time """
+ def __init__(self, bes, wdays=None, days=None, months=None):
+ self.data = ecflow.Cron()
+
+ if not ("-w" in bes or "-m" in bes or "-d" in bes):
+ self.data.set_time_series(bes);
+ return
+
+ import argparse
+ parser = argparse.ArgumentParser()
+ parser.add_argument("-w", nargs='?', default=0, help= "weekdays")
+ parser.add_argument("-d", nargs='?', default=0, help= "days")
+ parser.add_argument("-m", nargs='?', default=0, help= "months")
+ parser.add_argument("arg", type=str, help= "begin end step")
+ parsed = parser.parse_args(bes.split())
+
+ if parsed.w:
+ self.data.set_week_days([int(x) for x in parsed.w.split(',')])
+ if parsed.d:
+ self.data.set_week_days([int(x) for x in parsed.d.split(',')])
+ if parsed.m:
+ self.data.set_months([int(x) for x in parsed.m.split(',')])
+ self.data.set_time_series(parsed.arg)
+
+ def add_to(self, node):
+ if USE_TIME and self.data is not None:
+ node.add_cron(self.data)
+ else: print "#WAR: ignoring: %s" % self.data
+
+class Date(Time):
+ """ wrapper to add date """
+
+ def __init__(self, arg, mask=False):
+ super(Date, self).__init__(arg)
+ self.mask = mask
+
+ def add_to(self, node):
+ if USE_TIME and self.data is not None:
+ ### ??? FIX, emos avoids dates, datasvc would not
+ if self.mask:
+ node.add_variable("DATEMASK", self.data)
+ else:
+ ddd, mmm, yyy = self.data.split('.')
+ if ddd == '*': ddd = 0
+ if mmm == '*': mmm = 0
+ if yyy == '*': yyy = 0
+
+ node.add_date(int(ddd), int(mmm), int(yyy))
+ # node.add_date(self.data)
+
+class Day(Date):
+ """ wrapper to add day """
+ def add_to(self, node):
+ if USE_TIME and self.data is not None:
+ if isinstance(self.data, str):
+ days = { "monday": ecflow.Days.monday,
+ "sunday": ecflow.Days.sunday,
+ "tuesday": ecflow.Days.tuesday,
+ "wednesday": ecflow.Days.wednesday,
+ "thursday": ecflow.Days.thursday,
+ "saturday": ecflow.Days.saturday,
+ "friday": ecflow.Days.friday, }
+ # node.add_date(self.data) ### FIX
+ node.add_variable("WEEKDAY", self.data)
+ node.add_day(ecflow.Days(days[self.data]))
+ else: node.add_day(ecflow.Days(self.data))
+
+class Defcomplete(Attribute):
+ """ wrapper to add defstatus complete """
+ def __init__(self):
+ pass
+
+ def add_to(self, node):
+ node.defstatus("complete")
+
+class Defstatus(Defcomplete):
+ """ add defstatus attribute"""
+ def __init__(self, kind):
+ if type(kind) == str:
+ kinds = {"suspended": ecflow.DState.suspended,
+ "aborted": ecflow.DState.aborted,
+ "complete": ecflow.DState.complete,
+ "active": ecflow.DState.active,
+ "submitted": ecflow.DState.submitted,
+ "unknown": ecflow.DState.unknown,
+ "queued": ecflow.DState.queued,
+ }
+ self.data = kinds[kind]
+ else: self.data = kind
+
+ def add_to(self, node):
+ node.add_defstatus(self.data)
+
+class DefcompleteIf(Defcomplete):
+ """ wrapper to add conditional defstatus complete
+ just change name to make it explicit
+ """
+ def __init__(self, arg=True):
+ # super(DefcompleteIf, self).__init__()
+ self.data = arg
+
+ def add_to(self, node):
+ if self.data:
+ node.defstatus("complete")
+ # else: node.defstatus("queued") # in comment to prevent
+ # overwrite when using multiple defcomplete
+
+class Limit(Attribute):
+ """ wrapper to add limit """
+
+ # name = None; size = 1
+
+ def __init__(self, name=None, size=1):
+ self.name = name
+ self.size = size
+
+ def add_to(self, node):
+ if USE_LIMIT and self.name is not None:
+ if type(self.name) is dict:
+ for name, size in self.name.items():
+ node.add_limit(name, size)
+ else: node.add_limit(self.name, self.size)
+
+class Late(Attribute):
+ """ wrapper around late, to be add'ed to families and tasks """
+
+ def __init__(self, arg):
+ self.data = None
+ if not USE_LATE:
+ if DEBUG: print "#MSG: late is disabled"
+ return
+ sub = False
+ act = False
+ com = False
+ rel = False
+ self.data = ecflow.Late()
+ for item in arg.split(" "):
+ if item == "-s":
+ sub = True
+ elif item == "-c":
+ com = True
+ elif item == "-a":
+ act = True
+ else:
+ hour, mins = item.split(":")
+ rel = "+" in hour
+ if "+" in hour: hour= hour[1:]
+ if sub:
+ self._add_sub(hour, mins)
+ elif com:
+ self._add_com(hour, mins, rel)
+ elif act:
+ self._add_act(hour, mins)
+ sub = False
+ act = False
+ com = False
+
+ def _add_sub(self, hour, mins):
+ """ submitted"""
+ self.data.submitted(ecflow.TimeSlot(int(hour), int(mins)))
+
+ def _add_com(self, hour, mins, rel):
+ """ complete"""
+ self.data.complete(ecflow.TimeSlot(int(hour), int(mins)), rel)
+
+ def _add_act(self, hour, mins):
+ """ active"""
+ self.data.active(ecflow.TimeSlot(int(hour), int(mins)))
+
+ def add_to(self, node):
+ if USE_LATE and self.data is not None:
+ node.add_late(self.data)
+
+class Variables(Attribute):
+ """ dedicated class to enable variable addition with different
+ syntax """
+
+ def _set_tvar(self, key, val):
+ """ facilitate to load a ecflow suite to SMS, translating
+ variable names"""
+ keyt, valt = translate(str(key), str(val))
+ if self.data is None:
+ self.data = Variable(keyt, valt)
+ else:
+ next = self.next
+ self.next = Variables(keyt, valt, next)
+
+ def __init__(self, __a=None, __b=None, __next=None, *args, **kwargs):
+ self.data = None
+ self.next = __next
+
+ if len(args) > 0:
+ if type(args) == list:
+ for item in args.iteritems():
+ self._set_tvar(item.name(), item.value())
+ elif type(args) == tuple:
+ for key, val in args.items():
+ self._set_tvar(key, val)
+ else: raise BaseException()
+ if len(kwargs) > 0:
+ for key, val in kwargs.items():
+ self._set_tvar(key, val)
+ if type(__a) == dict:
+ for key, val in __a.items():
+ self._set_tvar(key, val)
+ elif type(__a) == tuple: raise BaseException()
+ # for key, val in __a.items(): self._set_tvar(key, val)
+ elif type(__a) == list: raise BaseException()
+ elif type(__a) == Variable: self.data = __a
+ elif __a is not None and __b is not None:
+ self._set_tvar(__a, __b)
+ elif __a is None and __b is None: pass
+ else: raise BaseException(__a, __b, __next, args, kwargs)
+
+ def add_to(self, node):
+ if self.data is not None:
+ node.add_variable(self.data)
+ edit = "%s" % self.data
+ try: # FIXME Christian's request
+ if "ECF_JOB_CMD" in edit:
+ if "%WSHOST%" in edit:
+ node.add_label("infopcmd", "WSHOST")
+ elif "%SCHOST%" in edit:
+ node.add_label("infopcmd", "SCHOST")
+ elif "%HOST%" in edit:
+ node.add_label("infopcmd", "HOST")
+ else:
+ node.add_label("infopcmd", edit)
+ elif "edit WSHOST " in edit:
+ node.add_label("infopws", edit.replace("edit WSHOST ", ""))
+ elif "edit SCHOST " in edit:
+ node.add_label("infopsc", edit.replace("edit SCHOST ", ""))
+ elif "edit HOST " in edit:
+ node.add_label("infophs", edit.replace("edit HOST ", ""))
+ except: pass
+ if self.next is not None:
+ self.next.add_to(node)
+
+ def add(self, what): raise baseException(what.fullname())
+
+class Limits(Attribute):
+ """ dedicated class to enable limits addition with different syntax """
+
+ def _set_tvar(self, key, val):
+ """ append limits """
+ if self.data is None:
+ self.data = ecflow.Limit(key, val)
+ else:
+ next = self.next
+ self.next = Limits(key, val, next)
+
+ def __init__(self, __a=None, __b=None, __next=None, *args, **kwargs):
+ self.data = None
+ self.next = __next
+
+ if len(args) > 0:
+ if type(args) == list:
+ for item in args.iteritems():
+ self._set_tvar(item.name(), item.value())
+ elif type(args) == tuple:
+ for key, val in args.items():
+ self._set_tvar(key, val)
+ elif len(kwargs) > 0:
+ for key, val in kwargs.items():
+ self._set_tvar(key, val)
+ elif type(__a) == dict:
+ for key in sorted(__a.iterkeys()):
+ self._set_tvar(key, __a[key])
+
+ if __a is not None and __b is not None:
+ self._set_tvar(__a, __b)
+
+ def add_to(self, node):
+ if self.data is not None:
+ node.add_limit(self.data)
+ if self.next is not None:
+ self.next.add_to(node)
+
+class Repeat(Attribute):
+ def __init__(self, name="YMD", start=20120101, end=21010101, step=1, kind="date"):
+ if kind == "date":
+ # print "# repeat", start, end, step, name, kind
+ self.data = ecflow.RepeatDate(name, int(start), int(end),
+ int(step))
+ elif "int" in kind:
+ self.data = ecflow.RepeatInteger(name, int(start), int(end), int(step))
+ elif kind == "string":
+ self.data = ecflow.RepeatString(name, start)
+ elif "enum" in kind:
+ self.data = ecflow.RepeatEnumerated(name, start)
+ elif kind == "day":
+ self.data = ecflow.RepeatDay(step)
+ else: self.data = None
+
+ def add_to(self, node):
+ if self.data is not None:
+ node.add_repeat(self.data)
+
+def If(test=True, then=None, otow=None):
+ """ enable Task("t1").add(If(test= (1==1),
+ then= Variables(ONE=1),
+ otow= Variables(TWO=2)))
+ appreciate that both branches are evaluated, using this If class
+ ie there is no 'dead code' as it is with python language 'if' structure
+
+ using If to distinguish od/rd mode request that both users share
+ the variables (parameter.py) and ecf.py
+
+ otow: on the other way?
+ """
+ if test:
+ return then
+ return otow
+
+class Root(object): # from where Suite and Node derive
+ """ generic tree node """
+
+ def __str__(self):
+ if isinstance(self, ecflow.Node):
+ return self.fullname()
+ return str(self)
+
+ def __eq__(self, node):
+ if isinstance(self, ecflow.Node):
+ return "%s == " % self.fullname() + str(node)
+ return False
+
+ def __ne__(self, node):
+ if isinstance(self, ecflow.Node):
+ return "%s != " % self.fullname() + str(node)
+ return False
+
+ def __and__(self, node):
+ if isinstance(self, ecflow.Node):
+ return "%s and " % self.fullname() + str(node)
+ return False
+
+ def __or__(self, node):
+ if isinstance(self, ecflow.Node):
+ return "%s or " % self.fullname() + str(node)
+ return False
+
+ def fullname(self):
+ """ simple syntax """
+ if isinstance(self, ecflow.Node):
+ return self.get_abs_node_path()
+ return str(self)
+
+ def repeat(self, name="YMD", start=20120101, end=20321212, step=1,
+ kind="date"):
+ """ add repeat attribute"""
+ if kind == "date":
+ self.add_repeat(ecflow.RepeatDate(name, int(start), int(end),
+ int(step)))
+ elif kind == "integer":
+ self.add_repeat(ecflow.RepeatInteger(name, int(start), int(end), int(step)))
+ elif kind == "string":
+ self.add_repeat(ecflow.RepeatString(name, start))
+ elif kind == "enumerated":
+ self.add_repeat(ecflow.RepeatEnumerated(name, start))
+ elif kind == "day":
+ self.add_repeat(ecflow.RepeatDay(step))
+ else: raise BaseException
+ return self
+
+ def defstatus(self, kind):
+ """ add defstatus attribute"""
+ status = kind
+ if type(kind) == str:
+ kinds = {"suspended": ecflow.DState.suspended,
+ "aborted": ecflow.DState.aborted,
+ "complete": ecflow.DState.complete,
+ "active": ecflow.DState.active,
+ "submitted": ecflow.DState.submitted,
+ "unknown": ecflow.DState.unknown,
+ "queued": ecflow.DState.queued,
+ }
+ status = kinds[kind]
+ self.add_defstatus(status)
+ return self
+
+ def add(self, item=None, *args):
+ """ add a task, a family or an attribute """
+ if DEBUG: print self.fullname(), item, args
+
+ if item is not None:
+ if type(item) == tuple:
+ for val in item:
+ self.add(val)
+ elif type(item) == list:
+ for val in item:
+ self.add(val)
+ else:
+ if DEBUG:
+ if type(item) in (Task, Family):
+ print item.fullname()
+ try: item.add_to(self)
+ except Exception, exc:
+ print item
+ raise BaseException("not yet", self, type(item), exc)
+
+ if len(args) > 0:
+ if type(args) == tuple:
+ for val in args:
+ self.add(val)
+ elif type(args) == list:
+ for val in args:
+ self.add(val)
+ else: raise BaseException()
+
+ if not isinstance(self, ecflow.Node): raise BaseException(
+ "you don't want that")
+
+ return self
+
+ def limit(self, name, size):
+ """ add limit attribute"""
+ if name is None: raise BaseException
+ self.add_limit(name, size)
+ return self
+
+ def inlimit(self, full_path):
+ """ add inlimit attribute"""
+ if not USE_LIMIT:
+ return self
+
+ path, name = full_path.split(":")
+ if name is None: raise BaseException()
+ if path is None: raise BaseException()
+
+ self.add_inlimit(name, path)
+ return self
+
+class Node(Root): # from where Task and Family derive
+ """ Node class is shared by family and task """
+
+ def add_limits(self, __a = None, __b = None, **kwargs):
+ """ add limit dependency"""
+ if isinstance(__a, basestring):
+ self.add_limit(__a, __b)
+ elif isinstance(__a, dict):
+ assert __b is None
+ for key, val in __a.items():
+ self.add_limit(key, val)
+ for key, val in kwargs.items():
+ self.add_limit(key, val)
+ return self
+
+ def meter(self, name, start, end, threshold=None):
+ """ add meter attribute"""
+ if threshold == None:
+ threshold = end
+ self.add_meter(name, start, end, threshold)
+ return self
+
+ def label(self, name, default=""):
+ """ add label attribute"""
+ self.add_label(name, default)
+ return self
+
+ def event(self, name=1):
+ """ add event attribute"""
+ if USE_EVENT:
+ self.add_event(name)
+ return self
+
+ def cron(self, time, dom=False, wdays=False, month=False):
+ """ wrapper for add_cron """
+ cron = ecflow.Cron()
+ cron.set_time_series(time)
+ if wdays is not False:
+ cron.set_week_days(wdays)
+ if month is not False:
+ cron.set_months(month)
+ if dom is not False:
+ cron.set_day_of_month(dom)
+
+ self.add_cron(cron)
+ return self
+
+ def today(self, hhmm):
+ """ wrapper around time """
+ self.time(hhmm)
+ return self # ???
+
+ def time(self, hhmm):
+ """ wrapper around time, None argument is silently ignored """
+ if hhmm is not None:
+ self.add_time(hhmm)
+ return self
+
+ def trigger(self, arg):
+ """ add trigger attribute"""
+ if USE_TRIGGER and arg is not None:
+ self.add_trigger(arg)
+ return self
+
+ def trigger_and(self, arg):
+ """ append to existing trigger"""
+ if USE_TRIGGER and arg is not None:
+ self.add_part_trigger(ecflow.PartExpression(arg, True))
+ return self
+
+ def trigger_or(self, arg):
+ """ append to existing trigger"""
+ if USE_TRIGGER and arg is not None:
+ self.add_part_trigger(ecflow.PartExpression(arg, False))
+ return self
+
+ def complete(self, arg):
+ """ add complete attribute"""
+ if USE_TRIGGER and arg is not None:
+ self.add_complete(arg)
+ return self
+
+ def complete_and(self, arg):
+ """ append to existing complete"""
+ if USE_TRIGGER and arg is not None:
+ self.add_part_complete(ecflow.PartExpression(arg, True))
+ return self
+
+ def complete_or(self, arg):
+ """ append to existing complete"""
+ if USE_TRIGGER and arg is not None:
+ self.add_part_complete(ecflow.PartExpression(arg, False))
+ return self
+
+ def up(self):
+ """ get parent, one level up"""
+ return self.get_parent()
+
+class Defs(ecflow.Defs):
+ """ wrapper for the definition """
+ def add(self, suite):
+ """ add suite """
+ self.add_suite(suite)
+ return suite
+
+ def suite(self, name):
+ """ add suite providing its name """
+ suite = Suite(name)
+ self.add(suite)
+ return suite
+
+class Client(ecflow.Client):
+ """ wrapper around client """
+ def __init__(self, host="localhost", port="31415"):
+ if "@" in host:
+ host, port = host.split("@")
+ # super(Client, self).__init__(host, int(port))
+ super(Client, self).__init__()
+ self.set_host_port(host, int(port))
+ else:
+ super(Client, self).__init__()
+ self.set_host_port(host, int(port))
+ # super(Client, self).__init__(host, "%s" % port)
+ self.host = host
+ self.port = port
+
+ def __str__(self):
+ return "ecflow client %s@%s v%s" % (self.host, self.port,
+ self.version())
+
+class Suite(ecflow.Suite, Root):
+ """ wrapper for a suite """
+
+ def family(self, name):
+ """ add family """
+ fam = Family(name)
+ self.add_family(fam)
+ return fam
+
+ def task(self, name):
+ """ add family """
+ tsk = Task(name)
+ self.add_task(tsk)
+ return tsk
+
+ # def __enter__(self): return self
+ # def __exit__(self, *args): pass
+
+class Family(ecflow.Family, Node, Attribute):
+ """ wrapper around family """
+
+ def family(self, name):
+ """ add a family """
+ fam = Family(name)
+ self.add_family(fam)
+ return fam
+
+ def task(self, name):
+ """ add a task """
+ tsk = Task(name)
+ self.add_task(tsk)
+ return tsk
+
+ def add_to(self, node):
+ node.add_family(self)
+
+ # def __enter__(self): return self
+ # def __exit__(self, *args): pass
+
+class Task(ecflow.Task, Node, Attribute):
+ """ wrapper around task """
+
+ def __setattr__(self, key, val):
+ # assert key.isupper()
+ if key.isupper():
+ key, val = translate(key, val)
+ self.add_variable(key, val)
+
+ def add_to(self, node):
+ # self.add_label("infop", "def")
+ node.add_task(self)
+
+ def add_family(self, node): raise BaseException()
+
+def display(defs, fname=None):
+ """ print defs"""
+ if fname is None:
+ pass # print defs
+ else:
+ fop = open(fname, "w")
+ print >> fop, defs
+
+
+class TestEcf(unittest.TestCase):
+ """ a test case """
+ def test_xxx(self):
+ """ a test """
+
+ suite = Suite ("a_suite")
+ suite.defstatus("suspended")
+
+ fam = Family("a_family")
+ tsk = Task("a_task")
+
+ ft2 = Task("a_fam")
+ ft2.add_to(fam)
+
+ tsk.VAR = "VALUE" # edit VAR "VALUE"
+ tsk.add(Late("-s 00:05 -c 01:00"))
+
+ fam.add(tsk,
+
+ (Task("1"), Task("2")),
+ [Task("11"), Task("12")],
+ Task("111"), Task("211"),
+
+ Task("t2").add(Trigger(tsk == COMPLETE),
+ Time("01:00")) )
+
+ fam.add(Task("t3").add(
+ If(test= (1==1),
+ then=Variables(ADD_ONE=1),
+ otow=Variables(ADD_TWO=1)),
+
+ If(test= (1==0),
+ then=Variables(ADD_ONE=0),
+ otow=Variables(ADD_TWO=0)),
+ Trigger(tsk != ABORTED),
+ Complete(tsk == COMPLETE))) # longer
+
+ fam.add(
+ Task("2t"),
+ Task("t4").add(
+ Trigger(tsk.name() != COMPLETE)),
+ Late("-s 00:05 -c 01:00"),
+ Variables(VAR="VALUE"),
+ Task("t5").add(Trigger(["t4", "t3", "t2"])),
+ Task("t6").add(Trigger("2t" == COMPLETE)),
+ Task("t7").add(Trigger("2t eq complete")),
+ )
+
+ tsk.add(Limit("a_limit", 10),
+ InLimit("a_task:a_limit"),
+ Meter("step", -1, 100),
+ Label("info", "none"),
+ Event(1),
+ Event("a"),
+ Defcomplete())
+
+ tsk.add(Variables({"A": "a", "B": "b"}))
+ tsk.add(Variables(D="d", E="e"))
+ tsk.add(Variables("C", "c"))
+ suite.add(fam)
+
+ fam.family("another").add(DefcompleteIf(True))
+
+ defs = Defs()
+ defs.add(suite)
+ another = defs.suite("another")
+ another.defstatus("suspended")
+ another.task("tn")
+ afam = another.family("another_fam")
+ afam.task("t2n")
+
+ display(defs, fname="test_ecf.tmp")
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Pyext/samples/printdefs.py b/Pyext/samples/printdefs.py
new file mode 100644
index 0000000..ace3608
--- /dev/null
+++ b/Pyext/samples/printdefs.py
@@ -0,0 +1,178 @@
+#!/usr/bin/env python2.7
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+import ecflow
+import argparse # for argument parsing
+
+class Indentor:
+ """This class manages indentation,
+ It is used to correctly indent the definition node tree hierarchy
+ """
+ _index = 0
+ def __init__(self):
+ Indentor._index += 1
+ def __del__(self):
+ Indentor._index -= 1
+ @classmethod
+ def indent(cls):
+ for i in range(Indentor._index):
+ print ' ',
+
+class DefsTraverser:
+ """Traverse the ecflow.Defs definition and writes to standard out.
+
+ Ecflow has the following hierarchy::
+ Task --> Submittable -->Node
+ Family --> NodeContainer -->Node
+ Suite --> NodeContainer -->Node
+
+ This demonstrates that all nodes in the node tree and all attributes are accessible.
+ Additionally the state data is also accessible. This class will write state data as
+ comments. If the definition was returned from the server, it allows access to latest
+ snapshot of the state data held in the server.
+ """
+ def __init__(self,defs):
+ assert (isinstance(defs,ecflow.Defs)),"Expected ecflow.Defs as first argument"
+ self.__defs = defs
+
+ def do_print(self):
+ for extern in self.__defs.externs:
+ self.__println("extern " + extern)
+ for suite in self.__defs.suites:
+ self.__print("suite ")
+ self.__print_node(suite)
+ clock = suite.get_clock()
+ if clock:
+ indent = Indentor()
+ self.__println(str(clock))
+ del indent
+ self.__print_nc(suite)
+ self.__println("endsuite")
+
+ def __print_nc(self,node_container):
+ indent = Indentor()
+ for node in node_container.nodes:
+ if isinstance(node, ecflow.Task):
+ self.__print("task ")
+ self.__print_node(node)
+ self.__print_alias(node)
+ else:
+ self.__print("family ")
+ self.__print_node(node)
+ self.__print_nc(node)
+ self.__println("endfamily")
+ del indent
+
+ def __print_alias(self,task):
+ indent = Indentor()
+ for alias in task.nodes:
+ self.__print("alias ")
+ self.__print_node(alias)
+ self.__println("endalias")
+ del indent
+
+ def __print_node(self,node):
+ print node.name() + " # state:" + str(node.get_state())
+
+ indent = Indentor()
+ defStatus = node.get_defstatus()
+ if defStatus != ecflow.DState.queued:
+ self.__println("defstatus " + str(defStatus))
+
+ autocancel = node.get_autocancel()
+ if autocancel: self.__println(str(autocancel))
+
+ repeat = node.get_repeat()
+ if not repeat.empty(): self.__println(str(repeat) + " # value: " + str(repeat.value()))
+
+ late = node.get_late()
+ if late: self.__println(str(late) + " # is_late: " + str(late.is_late()))
+
+ complete_expr = node.get_complete()
+ if complete_expr:
+ for part_expr in complete_expr.parts:
+ trig = "complete "
+ if part_expr.and_expr(): trig = trig + "-a "
+ if part_expr.or_expr(): trig = trig + "-o "
+ self.__print(trig)
+ print part_expr.get_expression()
+ trigger_expr = node.get_trigger()
+ if trigger_expr:
+ for part_expr in trigger_expr.parts:
+ trig = "trigger "
+ if part_expr.and_expr(): trig = trig + "-a "
+ if part_expr.or_expr(): trig = trig + "-o "
+ self.__print(trig)
+ print part_expr.get_expression()
+
+ for var in node.variables: self.__println("edit " + var.name() + " '" + var.value() + "'")
+ for meter in node.meters: self.__println(str(meter) + " # value: " + str(meter.value()))
+ for event in node.events: self.__println(str(event) + " # value: " + str(event.value()))
+ for label in node.labels: self.__println(str(label) + " # value: " + label.new_value())
+ for limit in node.limits: self.__println(str(limit) + " # value: " + str(limit.value()))
+ for inlimit in node.inlimits: self.__println(str(inlimit))
+ for the_time in node.times: self.__println(str(the_time))
+ for today in node.todays: self.__println(str(today))
+ for date in node.dates: self.__println(str(date))
+ for day in node.days: self.__println(str(day))
+ for cron in node.crons: self.__println(str(cron))
+ for verify in node.verifies: self.__println(str(verify))
+ for zombie in node.zombies: self.__println(str(zombie))
+
+ del indent
+
+ def __print(self,the_string):
+ Indentor.indent()
+ print the_string,
+
+ def __println(self,the_string):
+ Indentor.indent()
+ print the_string
+
+if __name__ == "__main__":
+
+ DESC = """Will list all the nodes and attributes in the definition
+ Usage:
+ Example1: List all the states
+ printdefs.py --host cca --port 4141
+ """
+ PARSER = argparse.ArgumentParser(description=DESC,
+ formatter_class=argparse.RawDescriptionHelpFormatter)
+ PARSER.add_argument('--host', default="localhost",
+ help="The name of the host machine, defaults to 'localhost'")
+ PARSER.add_argument('--port', default="3141",
+ help="The port on the host, defaults to 3141")
+ ARGS = PARSER.parse_args()
+ #print ARGS
+
+ # ===========================================================================
+ CL = ecflow.Client(ARGS.host, ARGS.port)
+ try:
+ CL.ping()
+
+ # get the incremental changes, and merge with defs stored on the Client
+ CL.sync_local()
+
+ # check to see if definition exists in the server
+ defs = CL.get_defs()
+ if defs == None :
+ print "No definition found, exiting..."
+ exit(0)
+
+ # print defs;
+ defs_traverser = DefsTraverser(defs)
+ defs_traverser.do_print()
+
+ except RuntimeError, ex:
+ print "Error: " + str(ex)
+ print "Check host and port number are correct."
diff --git a/Pyext/samples/resume.py b/Pyext/samples/resume.py
new file mode 100644
index 0000000..987e659
--- /dev/null
+++ b/Pyext/samples/resume.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python2.7
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+import ecflow
+import argparse # for argument parsing
+
+if __name__ == "__main__":
+
+ DESC = """Will resume any suspended 'node' who name matches input
+ Usage:
+ Example1: resume all suspended node whose name matches 'fred' for suite grib_api
+ resume.py --host cca --port 4141 --suite grib_api --name fred
+ """
+ PARSER = argparse.ArgumentParser(description=DESC,
+ formatter_class=argparse.RawDescriptionHelpFormatter)
+ PARSER.add_argument('--host', default="localhost",
+ help="The name of the host machine, defaults to 'localhost'")
+ PARSER.add_argument('--port', default="3141",
+ help="The port on the host, defaults to 3141")
+ PARSER.add_argument('--suite',
+ help="The name of the suite")
+ PARSER.add_argument('--name', default="install",
+ help="The name of the node")
+ ARGS = PARSER.parse_args()
+ print ARGS
+
+ # ===========================================================================
+ CL = ecflow.Client(ARGS.host, ARGS.port)
+ try:
+ CL.ping()
+
+ # get the incremental changes, and merge with defs stored on the Client
+ CL.sync_local()
+
+ # check to see if definition exists in the server
+ defs = CL.get_defs()
+ if defs == None :
+ print "No definition found, exiting..."
+ exit(0)
+
+ paths_list = []
+ node_vec = defs.get_all_nodes()
+ for node in node_vec:
+ if node.name() != ARGS.name: continue
+ if node.get_dstate() != ecflow.DState.suspended: continue
+
+ path = node.get_abs_node_path()
+ paths = path.split('/')
+ if paths[1] == ARGS.suite:
+ paths_list.append(path)
+
+ if len(paths_list) > 0:
+ CL.resume(paths_list)
+
+# # requires ecflow >= 4.0.8
+# suite = defs.find_suite(ARGS.suite)
+# if suite != None:
+# paths_list = []
+# node_vec = suite.get_all_nodes()
+# for node in node_vec:
+# if node.name() == ARGS.name and node.get_dstate() == DState.SUSPENDED:
+# paths_list.append(node.get_abs_node_path())
+#
+# print paths_list
+# if len(paths_list) > 0:
+# CL.resume(paths_list)
+
+ except RuntimeError, ex:
+ print "Error: " + str(ex)
+ print "Check host and port number are correct."
diff --git a/Pyext/samples/sms2ecf.py b/Pyext/samples/sms2ecf.py
new file mode 100755
index 0000000..51948d3
--- /dev/null
+++ b/Pyext/samples/sms2ecf.py
@@ -0,0 +1,193 @@
+#!/usr/bin/env python
+""" one module to store needed function to translate SMS-ECFLOW suites """
+import sys
+ECF_MODE = "ecflow" # "sms"
+
+# RAW_MODE:
+# False: translate *_CMD (submit, kill, status) variables values for %ECF_ + number args
+# True: just translate the name, and %ECF_, not arguments number
+
+RAW_MODE = False
+# ECF_MODE = "sms"
+CDP = "/usr/local/apps/sms/bin/cdp"
+subm = "/home/ma/emos/bin/trimurti"
+kill = subm
+stat = subm
+
+DICT_SMS_ECF = {
+ 'SMSNAME': 'ECF_NAME',
+ 'SMSNODE': 'ECF_NODE',
+ 'SMSPASS': 'ECF_PASS',
+ 'SMS_PROG': 'ECF_PORT',
+ 'SMSFILES': 'ECF_FILES',
+ 'SMSINCLUDE': 'ECF_INCLUDE',
+ 'SMSTRIES': 'ECF_TRIES',
+ 'SMSTRYNO': 'ECF_TRYNO',
+ 'SMSTRIE': 'ECF_TRIE',
+ 'SMSHOME': 'ECF_HOME',
+ 'SMSRID': 'ECF_RID',
+ 'SMSJOB': 'ECF_JOB',
+ 'SMSJOBOUT': 'ECF_JOBOUT',
+ 'SMSOUT': 'ECF_OUT',
+ 'SMSCHECKOLD': 'ECF_CHECKOLD',
+ 'SMSCHECK': 'ECF_CHECK',
+ 'SMSLOG': 'ECF_LOG',
+ 'SMSLIST': 'ECF_LIST',
+ 'SMSPASSWD': 'ECF_PASSWD',
+ 'SMSSERVER': 'ECF_SERVER',
+ 'SMSMICRO': 'ECF_MICRO',
+ 'SMSPID': 'ECF_PID',
+ 'SMSHOST': 'ECF_HOST',
+ 'SMSDATE': 'ECF_DATE',
+ 'SMSURL': 'ECF_URL',
+ 'SMSURLBASE': 'ECF_URLBASE',
+ 'SMSCMD': 'ECF_JOB_CMD',
+ 'SMSKILL': 'ECF_KILL_CMD',
+ 'SMSSTATUSCMD': 'ECF_STATUS_CMD',
+ 'SMSJOBCHECK': 'ECF_CHECK_CMD',
+ 'SMSURLCMD': 'ECF_URL_CMD',
+ 'SMSWEBACCES': 'ECF_WEBACCES',
+ 'SMS_VER': 'ECF_VER',
+ 'SMS_VERSION': 'ECF_VERSION',
+ 'SMSLOGHOST': 'ECF_LOGHOST',
+ 'SMSLOGPORT': 'ECF_LOGPORT',
+ 'SMSLOGTIMEOUT': 'ECF_LOGTIMEOUT',
+}
+
+DICT_ECF_SMS = dict((v, k) for k, v in DICT_SMS_ECF.iteritems())
+
+def translate(name, value=None):
+ """ find and replace submit, kill and status command, according to
+ sms/ecflow mode """
+ value2 = value
+ transl = name
+ smssubmit = "trimurti"
+ ecfsubmit = "/home/ma/emos/bin/ecflow_submit"
+
+ def add_ext(name, value):
+ if "_v2" in value: rc = " %ECF_JOB% %SCHOST% %USER%"
+ elif "kill" in value or "stat" in value:
+ if "WSHOST" in value: rc = RIDCLWS
+ else: rc = RIDCL
+ # if "submit" in value:
+ # if "WSHOST" in value: rc = JOBCLWS
+ # else: rc = JOBCL
+ elif "WSHOST" in value: rc = JOBCLWS
+ else: rc = JOBCL
+
+ if name in ('ECF_JOB_CMD', 'SMSCMD'):
+ rc = SUBCMD + " " + rc
+ elif name in ('ECF_KILL_CMD', 'SMSKILL'):
+ if "submit" in KILLCMD:
+ rc = KILLCMD + " %s kill" % rc
+ else: rc = KILLCMD + " %s " % rc
+ elif name in ('ECF_STATUS_CMD', 'SMSSTATUS',
+ 'ECF_CHECK_CMD', 'SMSJOBCHECK'):
+ if "submit" in STATCMD:
+ rc = STATCMD + " %s status" % rc
+ else: rc = STATCMD + " %s" % rc
+ return rc
+
+ if ECF_MODE == "ecflow" and name in DICT_SMS_ECF.keys():
+ if name in ('SMSCMD', 'SMSKILL', 'SMSSTATUSCMD', 'SMSHOME'):
+ value2 = value.replace('SMS', 'ECF_')
+ value = value2.replace(smssubmit, ecfsubmit)
+ elif name in ('ECF_JOB_CMD', 'ECF_KILL_CMD', 'ECF_STATUS_CMD'):
+ value2 = value.replace('SMS', 'ECF_')
+ value = value2.replace(smssubmit, ecfsubmit)
+ transl = DICT_SMS_ECF[name]
+
+ elif ECF_MODE == "sms" and name in DICT_ECF_SMS.keys():
+ if name in ('ECF_CMD_CMD', 'ECF_KILL_CMD', 'ECF_STATUS_CMD'):
+ value2 = value.replace('ECF_', 'SMS')
+ transl = DICT_ECF_SMS[name]
+
+ else: pass
+
+ if ECF_MODE == "sms" and RAW_MODE:
+ value2 = value.replace("ECF_", "SMS")
+ return transl, value2
+
+ elif ECF_MODE == "sms" and "CMD" in name and not "submit" in value:
+ if name in ('ECF_JOB_CMD'): name = "SMSCMD"
+ elif name in ('ECF_KILL_CMD'): name = "SMSKILL"
+ elif name in ('ECF_STATUS_CMD'): name = "SMSSTATUS"
+ value2 = value.replace("ECF_", "SMS")
+ value = value2
+
+ elif ECF_MODE == "sms":
+ SUBCMD = subm
+ KILLCMD = kill
+ STATCMD = stat
+
+ JOBCL = ' %USER% %SCHOST% %SMSJOB% %SMSJOBOUT%'
+ RIDCL = ' %USER% %SCHOST% %SMSRID% %SMSJOB% %SMSJOBOUT%'
+ STATL = ' %USER% %SCHOST% %SMSRID% %SMSJOB%'
+ STATLWS = ' %USER% %WSHOST% %SMSRID% %SMSJOB%'
+
+ JOBCLWS = JOBCL.replace("%SC", "%WS")
+ RIDCLWS = RIDCL.replace("%SC", "%WS") # .replace("HOST%", "HOST% %SMSRID%")
+ if name in ('ECF_JOB_CMD', 'SMSCMD'):
+ value2 = add_ext(name, value)
+ elif name in ('ECF_KILL_CMD', 'SMSKILL'):
+ if "submit" in KILLCMD:
+ value2 = KILLCMD + add_ext(value, value) + " kill"
+ else: value2 = KILLCMD + add_ext(value, value)
+ elif name in ('ECF_STATUS_CMD', 'SMSSTATUS',
+ 'ECF_CHECK_CMD', 'SMSJOBCHECK'):
+ if "submit" in STATCMD:
+ value2 = STATCMD + add_ext(value, value) + " status"
+ else: value2 = STATCMD + add_ext(value, value)
+ return transl, value2
+ return transl, value
+
+
+def get(name, host="localhost", port=314159):
+ import os, pwd
+ os.getlogin = lambda: pwd.getpwuid(os.getuid())[0]
+ user = os.getlogin()
+ cmd = "setenv -i HOME USER; set SMS_PROG %d; login %s %s 1; status > /dev/null ; get; show > %s; " % (port, host, user, name)
+ os.system("cdp -c '%s'" % cmd)
+
+def ignore(): pass
+
+ignored = ( "action", "owner", "text", "migrate", "automigrate", "autorestore")
+def sms2ecf(orig, dest):
+ import re
+ fop = open(dest, 'w')
+ with open(orig, 'r') as source:
+ try:
+ for line in source:
+ for key in ignored:
+ if " %s " % key in line:
+ continue
+ print >> fop, line
+ except:
+ print "oops"
+
+def load(name, host="localhost", port=31415):
+ import ecflow as ec
+ client = ec.Client(host, port)
+ try:
+ client.load(name)
+ except:
+ client.replace("/", name)
+
+if __name__ == "__main__":
+ import sys
+ try:
+ sms = sys.argv[1]
+ prog = sys.argv[2]
+ ecf = sys.argv[3]
+ port = sys.argv[4]
+ except:
+ sms = "localhost"
+ prog = 314159
+ ecf = "localhost"
+ port = 31415
+
+ before = "from_sms.exp"
+ become = "prep_ecf.exp"
+ get(name=before)
+ sms2ecf(orig=before, dest=become)
+ load(name=become)
diff --git a/Pyext/script.py b/Pyext/script.py
new file mode 100644
index 0000000..b7b5591
--- /dev/null
+++ b/Pyext/script.py
@@ -0,0 +1,11 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+#
+#
+print 'Hello World !'
+number = 42
diff --git a/Pyext/setup.py.in b/Pyext/setup.py.in
new file mode 100755
index 0000000..0cb1e85
--- /dev/null
+++ b/Pyext/setup.py.in
@@ -0,0 +1,137 @@
+#!/usr/bin/env python
+from distutils.core import setup, Extension
+import os
+import sys
+import glob
+
+# ========================================================================
+# Usage:
+# cd $WK; cd ecbuild/release/; sh -x ../../cmake.sh release; make ; make install
+# calling 'sh -x ../../cmake.sh release' will generate setup.py from setup.py.in
+# Issues:
+# Can not test cmake install, since it will always install to
+# /usr/local/apps/python/current/lib/python2.7/site-packages/ecflow
+#
+# To test install manually, we can:
+# cd $WK/Pyext
+# rm -rf build/ # for a clean build
+# python setup.py build_ext
+# python setup.py install --home=~
+#
+# See: http://docs.python.org/2/distutils/apiref.html?highlight=extension#distutils.core.Extension
+#
+# ========================================================================
+# AIX: On AIX we need custom compile and link flags:
+# The final link line is wrong: xlC_r xlc_r ,
+# /usr/local/lpp/vacpp11109/usr/vacpp/bin/.orig/xlC_r: 1501-228 (W) input file xlc_r not found
+#
+# Removing the duplicated xlc_r, We then get a little further,
+# ld: 0711-317 ERROR: Undefined symbol: .main
+# Using -bnoquiet
+# .main [12] ER PR crt0_64.s(/lib/crt0_64.o)
+# 00000070 .text R_RBR [34] .__start
+# This is because it is missing -G (generate dynamic library)
+# When we manually add -G, we sucessfully link(ecflow.so)
+#
+# Both of these can be fixed, by overriding the Link line with:
+# export LDSHARED="xlC_r -G -Wl,-bI:/usr/local/apps/python/2.7.2-01/lib/python2.7/config/python.exp"
+#
+# To find out what python is going to use:
+# python -c "from distutils import sysconfig; print sysconfig.get_config_vars('LDSHARED')[0]"
+# On AIX, it does not use this value ?
+#
+# See python issue 18235 _sysconfigdata.py wrong on AIX installations
+# ==========================================================================
+
+# ==========================================================================
+# Permissions: The permission of congfigured file are wrong: 2 choices
+# o Make sure origin file, has the right permissions
+# o Copy file to different directory, and change the permissions
+# since file(COPY) does rename files
+# configure_file(setup.py.in ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/setup.py)
+# now copy the temporary into the final destination, setting the permissions
+# file(COPY ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/setup.py
+# DESTINATION ${CMAKE_BINARY_DIR}
+# FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ
+# GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
+# ============================================================================
+
+#=============================================================================
+# define the directories to search for include files
+# to get this to work, you will need to include the path
+# to your boost installation and ecflow includes
+boost_root=os.getenv("BOOST_ROOT")
+include_dirs = [ "@CMAKE_CURRENT_SOURCE_DIR@/../ACore/src",
+ "@CMAKE_CURRENT_SOURCE_DIR@/../ANattr/src",
+ "@CMAKE_CURRENT_SOURCE_DIR@/../ANode/src",
+ "@CMAKE_CURRENT_SOURCE_DIR@/../AParser/src",
+ "@CMAKE_CURRENT_SOURCE_DIR@/../Base/src",
+ "@CMAKE_CURRENT_SOURCE_DIR@/../Base/src/cts",
+ "@CMAKE_CURRENT_SOURCE_DIR@/../Base/src/stc",
+ "@CMAKE_CURRENT_SOURCE_DIR@/../CSim/src",
+ "@CMAKE_CURRENT_SOURCE_DIR@/../Client/src",
+ "@CMAKE_CURRENT_SOURCE_DIR@/src",
+ boost_root,
+ ]
+
+# define the library directories to include any extra libraries that may be needed.
+# Give preference to release libs
+boost_lib_dir = boost_root + "/stage/lib/"
+library_dirs = ['@CMAKE_BINARY_DIR@/ACore',
+ '@CMAKE_BINARY_DIR@/ANattr/',
+ '@CMAKE_BINARY_DIR@/ANode/',
+ '@CMAKE_BINARY_DIR@/AParser/',
+ '@CMAKE_BINARY_DIR@/Base/',
+ '@CMAKE_BINARY_DIR@/CSim/',
+ '@CMAKE_BINARY_DIR@/Client/',
+ boost_lib_dir
+ ]
+
+# define the libraries to link with this includes the boost lib
+libraries = [ 'core' , 'nodeattr', 'node', 'libparser', 'base', 'libsimu', 'libclient',
+ 'boost_system-mt',
+ 'boost_serialization-mt',
+ 'boost_filesystem-mt',
+ 'boost_program_options-mt',
+ 'boost_date_time-mt',
+ 'boost_python-mt' ]
+
+# Using gcc-4.8 with boost 1.53 on linux requires these flags
+extra_compile_args = ['-ftemplate-depth-512', '-Wno-unused-local-typedefs' ]
+extra_link_args = []
+
+# extra compile flags needed for AIX only
+# Note setup.py will add -q64 -qcpluscmt -DNDEBUG automatically
+# Note: two extra_compile_args, debug and release, use the debug for testing and faster compiles
+if sys.platform.startswith("aix"):
+ extra_compile_args = [ '-qsuppress=1540-0198', '-O3', '-qstrict', '-qfuncsect', '-qeh', '-qrtti' ]
+ #extra_compile_args = [ '-qsuppress=1540-0198', '-qNOOPTimize', '-qnoinline', '-qfullpath', '-qfuncsect', '-qeh', '-qrtti' ]
+ extra_link_args= [ '-lpthread', '-ldl', '-bbigtoc' ] # '-G', '-noipath',
+
+
+# create the extension and add it to the python distribution
+# o glob.glob(os.path.join('src', '*.cpp'))
+# This expand the list of cpp files that need to be compiled
+#
+# The configuation below installs to:
+# o /usr/local/apps/python/current/lib/python2.7/site-packages/ecflow
+# when, "python setup.py install" is used:
+# lib/python2.7/site-packages/ecflow/ecflow.so
+# __init__.py
+setup( name='ecflow',
+ version='@ECFLOW_VERSION@',
+ author = 'ECMWF',
+ description = """ecflow Python interface""",
+ packages = [ 'ecflow' ],
+ package_dir={'ecflow': '@CMAKE_CURRENT_SOURCE_DIR@/ecflow'},
+ ext_modules=[ Extension(
+ 'ecflow.ecflow',
+ glob.glob(os.path.join('@CMAKE_CURRENT_SOURCE_DIR@/src', '*.cpp')),
+ include_dirs=include_dirs,
+ library_dirs=library_dirs,
+ libraries=libraries,
+ extra_compile_args=extra_compile_args,
+ extra_link_args=extra_link_args
+ )
+ ],
+ )
diff --git a/Pyext/src/BoostPythonUtil.cpp b/Pyext/src/BoostPythonUtil.cpp
new file mode 100644
index 0000000..43d891e
--- /dev/null
+++ b/Pyext/src/BoostPythonUtil.cpp
@@ -0,0 +1,56 @@
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "BoostPythonUtil.hpp"
+
+void BoostPythonUtil::list_to_int_vec(const boost::python::list& list, std::vector<int>& int_vec)
+{
+ int the_list_size = len(list);
+ int_vec.reserve(the_list_size);
+ for (int i = 0; i < the_list_size; ++i) {
+ int_vec.push_back(boost::python::extract<int>(list[i]));
+ }
+}
+
+void BoostPythonUtil::list_to_str_vec(const boost::python::list& list, std::vector<std::string>& vec)
+{
+ int the_list_size = len(list);
+ vec.reserve(the_list_size);
+ for (int i = 0; i < the_list_size; ++i) {
+ vec.push_back(boost::python::extract<std::string>(list[i]));
+ }
+}
+
+void BoostPythonUtil::dict_to_str_vec(const boost::python::dict& dict, std::vector<std::pair<std::string,std::string> >& str_pair_vec)
+{
+ boost::python::list keys = dict.keys();
+ const int no_of_keys = len(keys);
+ str_pair_vec.reserve(no_of_keys);
+
+ for(int i = 0; i < no_of_keys; ++i) {
+
+ boost::python::object curArg = dict[keys[i]];
+ if(curArg) {
+ std::string first = boost::python::extract<std::string>(keys[i]);
+ std::string second = boost::python::extract<std::string>(dict[keys[i]]);
+ str_pair_vec.push_back( std::make_pair(first,second));
+// std::cout << "BoostPythonUtil::dict_to_str_vec " << first << " " << second << "\n";
+ }
+ }
+
+}
+
diff --git a/Pyext/src/BoostPythonUtil.hpp b/Pyext/src/BoostPythonUtil.hpp
new file mode 100644
index 0000000..625a53e
--- /dev/null
+++ b/Pyext/src/BoostPythonUtil.hpp
@@ -0,0 +1,37 @@
+#ifndef BOOST_PYTHON_UTIL_HPP_
+#define BOOST_PYTHON_UTIL_HPP_
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <boost/noncopyable.hpp>
+#include <boost/python.hpp>
+#include <vector>
+#include <string>
+
+// See: http://wiki.python.org/moin/boost.python/HowTo#boost.function_objects
+
+class BoostPythonUtil : private boost::noncopyable {
+public:
+
+ /// Convert python list to a vector of integers. raises a type error if integer extraction fails
+ static void list_to_int_vec(const boost::python::list& list, std::vector<int>& int_vec);
+ static void list_to_str_vec(const boost::python::list& list, std::vector<std::string>& int_vec);
+ static void dict_to_str_vec(const boost::python::dict& dict, std::vector<std::pair<std::string,std::string> >& str_pair);
+
+};
+
+#endif
diff --git a/Pyext/src/ClientDoc.cpp b/Pyext/src/ClientDoc.cpp
new file mode 100644
index 0000000..a62fd89
--- /dev/null
+++ b/Pyext/src/ClientDoc.cpp
@@ -0,0 +1,1419 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #89 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "ClientDoc.hpp"
+
+const char* ClientDoc::class_client(){
+ return
+ "Class client provides an interface to communicate with the :term:`ecflow_server`.::\n\n"
+ " Client(\n"
+ " string host, # The server name. Can not be empty.\n"
+ " string port # The port on the server, must be unique to the server\n"
+ " )\n\n"
+ " Client(\n"
+ " string host, # The server name. Can not be empty.\n"
+ " int port # The port on the server, must be unique to the server\n"
+ " )\n\n"
+ " Client(\n"
+ " string host_port, # Expect's <host>:<port>\n"
+ " )\n\n"
+ "The client reads in the following environment variables.\n"
+ "For child commands,(i.e these are commands called in the .ecf/jobs files), these variables are used.\n"
+ "For the python interface these environment variable are not really applicable but documented for completeness:\n\n"
+ "* ECF_NAME <string> : Full path name to the task\n"
+ "* ECF_PASS <string> : The jobs password, allocated by server, then used by server to authenticate client request\n"
+ "* ECF_TRYNO <int> : The number of times to start a job if it aborts\n"
+ "* ECF_TIMEOUT <int> : Max time in seconds for client to deliver message to main server\n"
+ "* ECF_HOSTFILE<string> : File that lists alternate hosts to try, if connection to main host fails\n"
+ "* ECF_DENIED <any> : Provides a way for child to exit with an error, if server denies connection.\n"
+ " Avoids 24hr wait. Note: when you have hundreds of tasks, using this approach\n"
+ " requires a lot of manual intervention to determine job status\n"
+ "* NO_ECF <any> : If set exit's immediately with success. Used to test jobs without communicating with server\n\n"
+ "The following environment variables are used by the python interface and child commands\n\n"
+ "* ECF_NODE <string> : The host name of the main server. defaults to 'localhost'\n"
+ "* ECF_PORT <int> : The TCP/IP port to call on the server. Must be unique to a server\n\n"
+ "The ECF_NODE and ECF_PORT can be overridden by using the Constructor or set_host_port() member function.\n"
+ "For optimal usage it is best to reuse the same Client rather than recreating for each client server interaction\n"
+ "By default the Client interface will throw exceptions for error's.\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client(\"localhost:3150\") # for errors will throw RuntimeError\n"
+ " ci.terminate_server()\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n\n"
+ ;
+}
+
+const char* ClientDoc::set_host_port(){
+ return
+ "Override the default(localhost and port 3141) and environment setting(ECF_NODE and ECF_PORT)\n"
+ "and set it explicitly::\n\n"
+ " set_host_port(\n"
+ " string host, # The server name. Can not be empty.\n"
+ " string port # The port on the server, must be unique to the server\n"
+ " )\n\n"
+ " set_host_port(\n"
+ " string host, # The server name. Can not be empty.\n"
+ " int port # The port on the server, must be unique to the server\n"
+ " )\n\n"
+ " set_host_port(\n"
+ " string host_port, # Expect's <host>:<port>\n"
+ " )\n\n"
+ "Exceptions:\n\n"
+ "- Raise a RuntimeError if the host or port is empty\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client();\n"
+ " ci.set_host_port(\"localhost\",\"3150\")\n"
+ " ci.set_host_port(\"avi\",3150)\n"
+ " ci.set_host_port(\"avi:3150\")\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n\n"
+ ;
+}
+
+const char* ClientDoc::set_retry_connection_period() {
+ return
+ "Set the sleep period between connection attempts\n\n"
+ "Whenever there is a connection failure we wait a number of seconds before trying again.\n"
+ "i.e. to get round glitches in the network.\n"
+ "For the ping command this is hard wired as 1 second.\n"
+ "This wait between connection attempts can be configured here.\n"
+ "i.e This could be reduced to increase responsiveness.\n"
+ "Default: In debug this period is 1 second and in release mode 10 seconds::\n\n"
+ " set_retry_connection_period(\n"
+ " int period # must be an integer >= 0\n"
+ " )\n\n"
+ "Exceptions:\n\n"
+ "- None\n"
+ "\nUsage::\n\n"
+ " ci = Client()\n"
+ " ci.set_connection_attempts(3) # make 3 attempts for server connection\n"
+ " ci.set_retry_connection_period(1) # wait 1 second between each attempt\n"
+ ;
+}
+
+const char* ClientDoc::set_connection_attempts() {
+ return
+ "Set the number of times to connect to :term:`ecflow_server`, in case of connection failures\n\n"
+ "The period between connection attempts is handled by Client.set_retry_connection_period().\n"
+ "If the network is unreliable the connection attempts can be be increased, likewise\n"
+ "when the network is stable this number could be reduced to one.\n"
+ "This can increase responsiveness and reduce latency.\n"
+ "Default value is set as 2.\n"
+ "Setting a value less than one is ignored, will default to 1 in this case::\n\n"
+ " set_connection_attempts(\n"
+ " int attempts # must be an integer >= 1\n"
+ " )\n"
+ "\nExceptions:\n\n"
+ "- None\n"
+ "\nUsage::\n\n"
+ " ci = Client()\n"
+ " ci.set_connection_attempts(3) # make 3 attempts for server connection\n"
+ " ci.set_retry_connection_period(1) # wait 1 second between each attempt\n"
+ ;
+}
+
+const char* ClientDoc::get_defs(){
+ return
+ "Returns the :term:`suite definition` stored on the Client.\n\n"
+ "Use :py:class:`ecflow.Client.sync_local()` to retrieve the definition from the server first.\n"
+ "The definition is *retained* in memory until the next call to sync_local().\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.sync_local() # get the definition from the server and store on 'ci'\n"
+ " print ci.get_defs() # print out definition stored in the client\n"
+ " print ci.get_defs() # print again, this shows that defs is retained on ci\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::get_log()
+{
+ return
+ "Request the :term:`ecflow_server` to return the log file contents as a string\n\n"
+ "Use with caution as the returned string could be several megabytes.\n"
+ "Only enabled in the debug build of ECF.\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " print ci.get_log() # get the log file from the server\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::new_log()
+{
+ return
+ "Request the :term:`ecflow_server` to use the path provided, as the new log file\n\n"
+ "The old log file is released.\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.new_log('/path/log.log') # use '/path/log,log' as the new log file\n"
+ " # To keep track of log file Can change ECF_LOG\n"
+ " ci.alter('\','change','variable','ECF_LOG','/new/path.log')\n"
+ " ci.new_log()\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::clear_log()
+{
+ return
+ "Request the :term:`ecflow_server` to clear log file.\n"
+ "Log file will be empty after this call.\n\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.clear_log() # log file is now empty\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::flush_log()
+{
+ return
+ "Request the :term:`ecflow_server` to flush and then close log file\n\n"
+ "It is best that the server is :term:`shutdown` first, as log file will be reopened\n"
+ "whenever a command wishes to log any changes.\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.flush_log() # Log can now opened by external program\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::log_msg()
+{
+ return
+ "Request the :term:`ecflow_server` writes a string message to the log file.\n\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.log_msg(\"A message\") # Write message to log file\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::restart_server() {
+ return
+ "Restart the :term:`ecflow_server`\n\n"
+ "Start job scheduling, communication with jobs, and respond to all requests.\n"
+ "See :term:`server states`\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.retstart_server()\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+const char* ClientDoc::halt_server() {
+ return
+ "Halt the :term:`ecflow_server`\n\n"
+ "Stop server communication with jobs, and new job scheduling, and stops check pointing.\n"
+ "See :term:`server states`\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.halt_server()\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+const char* ClientDoc::shutdown_server() {
+ return
+ "Shut down the :term:`ecflow_server`\n\n"
+ "Stop server from scheduling new jobs.\n"
+ "See :term:`server states`\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.shutdown_server()\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::terminate_server() {
+ return "Terminate the :term:`ecflow_server`::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.terminate_server()\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::wait_for_server_reply() {
+ return "Wait for a response from the :term:`ecflow_server`::\n\n"
+ " void wait_for_server_reply(\n"
+ " int time_out : (default = 60) \n"
+ " )\n\n"
+ "This is used to check if server has started. Typically for tests.\n"
+ "Returns true if server(ping) replies before time out, otherwise false\n"
+ "\nUsage::\n\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " if ci.wait_for_server_reply(30):\n"
+ " print 'Server is alive'\n"
+ " else:\n"
+ " print 'Timed out after 30 second wait for server response.?'\n"
+ ;
+}
+
+const char* ClientDoc::load_defs(){
+ return
+ "Load a :term:`suite definition` given by the file_path argument into the :term:`ecflow_server`::\n\n"
+ " void load(\n"
+ " string file_path : path name to the definition file\n"
+ " [(bool)force=False] : If true overwrite suite of same name\n"
+ " )\n\n"
+ "By default throws a RuntimeError exception for errors.\n"
+ "If force is not used and :term:`suite` of the same name already exists in the server,\n"
+ "then a error is thrown\n"
+ "\nUsage::\n\n"
+ " defs_file = \"Hello.def\" \n"
+ " defs = Defs()\n"
+ " suite = def.add_suite(\"s1\")\n"
+ " family = suite.add_family(\"f1\")\n"
+ " for i in [ \"_1\", \"_2\", \"_3\" ]:\n"
+ " family.add_task( \"t\" + i )\n"
+ " defs.save_as_defs(defs_file) # write out in memory defs into the file 'Hello.def'\n"
+ " ...\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.load(defs_file) # open and parse defs file, and load into server.\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::load(){
+ return
+ "Load a in memory :term:`suite definition` into the :term:`ecflow_server`::\n\n"
+ " void load(\n"
+ " Defs defs : A in memory definition\n"
+ " [(bool)force=False] : for true overwrite suite of same name\n"
+ " )\n\n"
+ "If force is not used and :term:`suite` already exists in the server, then a error is thrown.\n"
+ "\nUsage::\n\n"
+ " defs = Defs(\"hello.def\")\n"
+ " suite = defs.add_suite(\"s1\")\n"
+ " family = suite.add_family(\"f1\")\n"
+ " for i in [ \"_1\", \"_2\", \"_3\" ]: \n"
+ " family.add_task( Task( \"t\" + i) )\n"
+ " ...\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.load(defs) # Load in memory defs, into the server\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::get_server_defs() {
+ return
+ "Get all suite Node tree's from the :term:`ecflow_server`.\n\n"
+ "The definition is *retained* in memory until the next call to get_server_defs().\n"
+ "This is important since get_server_defs() could return several megabytes of data.\n"
+ "Hence we only want to call it once, and then access it locally with get_defs().\n"
+ "If you need to access the server definition in a loop use :py:class:`ecflow.Client.sync_local` instead\n"
+ "since this is capable of returning incremental changes, and thus considerably\n"
+ "reducing the network load.\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.get_server_defs() # get the definition from the server and store on 'ci'\n"
+ " print ci.get_defs() # print out definition stored in the client\n"
+ " print ci.get_defs() # print again, this shows that defs is retained on ci\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::sync() {
+ return
+ "Requests that :term:`ecflow_server` returns the full definition or incremental change made and applies them to the client Defs\n\n"
+ "When there is a very large definition, calling :py:class:`ecflow.Client.get_server_defs` each time can be *very* expensive\n"
+ "both in terms of memory, speed, and network bandwidth. The alternative is to call \n"
+ "this function, which will get the incremental changes, and apply them local client :term:`suite definition`\n"
+ "effectively synchronising the client and server Defs.\n"
+ "If the period of time between two sync() calls is too long, then the full server definition\n"
+ "is returned and assigned to the client Defs.\n"
+ "We can determine if the changes were applied by calling in_sync() after the call to sync_local()::\n\n"
+ " void sync_local(); # The very first call, will get the full Defs.\n"
+ "\n"
+ "Exceptions:\n\n"
+ "- raise a RuntimeError if the delta change can not be applied.\n"
+ "- this could happen if the client Defs bears no resemblance to server Defs\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.sync_local() # Very first call gets the full Defs\n"
+ " client_defs = ci.get_defs() # End user access to the returned Defs\n"
+ " ... after a period of time\n"
+ " ci.sync_local() # Subsequent calls to sync_local() users the local Defs to sync incrementally\n"
+ " if ci.in_sync(): # returns true server changed and changes applied to client\n"
+ " print 'Client is now in sync with server'\n"
+ " client_defs = ci.get_defs() # End user access to the returned Defs\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ "\n"
+ "Calling sync_local() is considerably faster than calling get_server_defs() for large Definitions"
+ ;
+}
+
+const char* ClientDoc::in_sync() {
+ return
+ "Returns true if the definition on the client is in sync with the :term:`ecflow_server`\n\n"
+ "Calling in_sync() is **only** valid after a call to sync_local().\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.sync_local() # very first call gets the full Defs\n"
+ " client_defs = ci.get_defs() # End user access to the returned Defs\n"
+ " ... after a period of time\n"
+ " ci.sync_local() # Subsequent calls to sync_local() users the local Defs to sync incrementally\n"
+ " if ci.in_sync(): # returns true changed and changes applied to client\n"
+ " print 'Client is now in sync with server'\n"
+ " client_defs = ci.get_defs() # End user access to the returned Defs\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::news() {
+ return
+ "Query the :term:`ecflow_server` to detect any changes.\n\n"
+ "This returns a simple bool, if there has been changes, the user should call :py:class:`ecflow.Client.sync_local`.\n"
+ "This will bring the client in sync with changes in the server. If sync_local() is not called\n"
+ "then calling news_local() will always return true.\n"
+ "news_local() uses the definition stored on the client::\n\n"
+ " bool news_local()\n"
+ "\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " if ci.news_local(): # has the server changed\n"
+ " print 'Server Changed' # server changed bring client in sync with server\n"
+ " ci.sync_local() # get the full definition from the server if first time\n"
+ " # otherwise apply incremental changes to Client definition,\n"
+ " # bringing it in sync with the server definition\n"
+ " print ci.get_defs() # print the synchronised definition. Should be same as server\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::changed_node_paths() {
+ return
+ "After a call to sync_local() we can access the list of nodes that changed\n\n"
+ "The returned list consists of node paths. *IF* the list is empty assume that\n"
+ "whole definition changed. This should be expected after the first call to sync_local()\n"
+ "since that always retrieves the full definition from the server::\n\n"
+ " void changed_node_paths()\n"
+ "\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " if ci.news_local(): # has the server changed\n"
+ " print 'Server Changed' # server changed bring client in sync with server\n"
+ " ci.sync_local() # get the full definition from the server if first time\n"
+ " # otherwise apply incremental changes to Client definition,\n"
+ " # bringing it in sync with the server definition\n"
+ " defs = ci.get_defs() # get the updated/synchronised definition\n"
+ " for path in ci.changed_node_paths:\n"
+ " print path\n"
+ " if path == '/': # path '/' represent change to server node/defs\n"
+ " print 'defs changed' # defs state change or user variables changed\n"
+ " else:\n"
+ " node = defs.find_abs_node(path)\n"
+ "\n"
+ " # if changed_node_paths is empty, then assume entire definition changed\n"
+ " print defs # print the synchronised definition. Should be same as server\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+
+const char* ClientDoc::checkpt(){
+ return
+ "Request the :term:`ecflow_server` :term:`check point` s the definition held in the server immediately\n\n"
+ "This effectively saves the definition held in the server to disk,\n"
+ "in a platform independent manner. This is the default when no arguments are specified.\n"
+ "The saved file will include node state, passwords, etc.\n"
+ "The default file name is <host>.<port>.ecf.check and is saved in ECF_HOME directory.\n"
+ "The :term:`check point` file name can be overridden via ECF_CHECK server environment variable.\n"
+ "The back up :term:`check point` file name can be overridden via ECF_CHECKOLD server environment variable::\n\n"
+ " void checkpt(\n"
+ " [(CheckPt::Mode)mode=CheckPt.UNDEFINED]\n"
+ " : Must be one of [ NEVER, ON_TIME, ALWAYS, UNDEFINED ]\n"
+ " NEVER : Never check point the definition in the server\n"
+ " ON_TIME: Turn on automatic check pointing at interval stored on server\n"
+ " or with interval specified as the second argument\n"
+ " ALWAYS: Check point at any change in node tree, *NOT* recommended for large definitions\n"
+ " UNDEFINED:The default, which allows for immediate check pointing, or alarm setting\n"
+ " [(int)interval=120] : This specifies the interval in seconds when server should automatically check pt.\n"
+ " This will only take effect if mode is on_time/CHECK_ON_TIME\n"
+ " Should ideally be a value greater than 60 seconds, default is 120 seconds\n"
+ " [(int)alarm=30] : Specifies check pt save alarm time. If saving the check pt takes longer than\n"
+ " the alarm time, then the late flag is set on the server.\n"
+ " This flag will need to be cleared manually.\n"
+ " )\n\n"
+ "Note: When the time taken to save the check pt is excessive, it can interfere with job scheduling.\n\n"
+ "It may be an indication of the following:\n\n"
+ "* slow disk\n"
+ "* file system full\n"
+ "* The definition is very large and needs to split\n\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.checkpt() # Save the definition held in the server to disk\n"
+ " ci.checkpt(CheckPt.NEVER) # Switch off check pointing\n"
+ " ci.checkpt(CheckPt.ON_TIME) # Start automatic check pointing at the interval stored in the server\n"
+ " ci.checkpt(CheckPt.ON_TIME,180) # Start automatic check pointing every 180 seconds\n"
+ " ci.checkpt(CheckPt.ALWAYS) # Check point at any state change in node tree. *not* recommended for large defs\n"
+ " ci.checkpt(CheckPt.UNDEFINED,0,35) # Change check point save time alarm to 35 seconds\n"
+ " # With these arguments mode and interval remain unchanged\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+
+const char* ClientDoc::restore_from_checkpt() {
+ return
+ "Request the :term:`ecflow_server` loads the :term:`check point` file from disk\n\n"
+ "The server will first try to open file at ECF_HOME/ECF_CHECK if that fails it will\n"
+ "then try path ECF_HOME/ECF_CHECKOLD.\n"
+ "An error is returned if the server has not been :term:`halted` or contains a :term:`suite definition`\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.halt_server() # server must be halted, otherwise restore_from_checkpt will throw\n"
+ " ci.restore_from_checkpt() # restore the definition from the check point file\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+
+const char* ClientDoc::reload_wl_file(){
+ return
+ "Request that the :term:`ecflow_server` reload the white list file.\n\n"
+ "The white list file if present, can be used to control who has read/write\n"
+ "access to the :term:`ecflow_server`::\n\n"
+ " void reload_wl_file()\n\n"
+ "Usage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.reload_wl_file()\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::run(){
+ return
+ "Immediately run the jobs associated with the input :term:`node`.\n\n"
+ "Ignore :term:`trigger` s, :term:`limit` s, :term:`suspended`, :term:`time` or :term:`date` dependencies,\n"
+ "just run the :term:`task`.\n"
+ "When a job completes, it may be automatically re-queued if it has\n"
+ "multiple time :term:`dependencies`. In the specific case where a :term:`task` has a SINGLE\n"
+ "time dependency and we want to avoid re running the :term:`task` then\n"
+ "a flag is set so that it is not automatically re-queued when set to :term:`complete`.\n"
+ "The flag is applied up the :term:`node` hierarchy until we reach a node with a :term:`repeat`\n"
+ "or :term:`cron` attribute. This behaviour allow :term:`repeat` values to be incremented interactively.\n"
+ "A :term:`repeat` attribute is incremented when all the child nodes are :term:`complete`\n"
+ "in this case the child nodes are automatically re-queued\n::\n\n"
+ " void run(\n"
+ " string absolute_node_path : Path name to node. If the path is suite/family will recursively\n"
+ " run all child tasks\n"
+ " [(bool)force=False] : If true, run even if there are nodes that are active or submitted.\n"
+ " )\n"
+ " void run(\n"
+ " list paths : List of paths. If the path is suite/family will recursively run all child tasks\n"
+ " [(bool)force=False] : If true, run even if there are nodes that are active or submitted.\n"
+ " )\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.run('/s1') # run all tasks under suite /s1\n"
+ "\n"
+ " path_list = ['/s1/f1/t1','/s2/f1/t2']\n"
+ " ci.run(path_list) # run all tasks specified in the paths\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ "\nEffect::\n\n"
+ " Lets see the effect of run command on the following defs::\n\n"
+ " suite s1\n"
+ " task t1; time 10:00 # will complete straight away\n"
+ " task t2; time 10:00 13:00 01:00 # will re-queue 3 times and complete on fourth run\n\n"
+ "In the last case (task t2) after each run the next time slot is incremented.\n"
+ "This can be seen by calling the Why command."
+ ;
+}
+
+const char* ClientDoc::requeue(){
+
+ return
+ "Re queues the specified :term:`node` (s)::\n\n"
+ " void requeue(\n"
+ " list paths : A list of paths. Node paths must begin with a leading '/' character\n"
+ " [(str)option=''] : option = ('' | 'abort' | 'force')\n"
+ " '' : empty string, the default, re-queue the node\n"
+ " abort: means re-queue only aborted tasks below node\n"
+ " force: means re-queueing even if there are nodes that are active or submitted\n"
+ " )\n"
+ " void requeue(\n"
+ " string absolute_node_path : Path name to node\n"
+ " [(string)option=''] : option = ('' | 'abort' | 'force')\n"
+ " )\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.requeue('/s1','abort') # re-queue aborted tasks below suite /s1\n"
+ "\n"
+ " path_list = ['/s1/f1/t1','/s2/f1/t2']\n"
+ " ci.requeue(path_list)\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::free_trigger_dep(){
+ return
+ "Free :term:`trigger` :term:`dependencies` for a :term:`node`::\n\n"
+ " void free_trigger_dep(\n"
+ " string absolute_node_path : Path name to node\n"
+ " )\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.free_trigger_dep('/s1')\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::free_date_dep(){
+ return
+ "Free :term:`date` :term:`dependencies` for a :term:`node`::\n\n"
+ " void free_date_dep(\n"
+ " string absolute_node_path : Path name to node\n"
+ " )\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.free_date_dep('/s1')\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::free_time_dep(){
+ return
+ "Free all time :term:`dependencies`. i.e :term:`time`, :term:`day`, :term:`today`, :term:`cron`::\n\n"
+ " void free_time_dep(\n"
+ " string absolute_node_path : Path name to node\n"
+ " )\n\n"
+ "After freeing the time related dependencies (i.e time,today,cron)\n"
+ "the next time slot will be missed.\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.free_time_dep('/s1')\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::free_all_dep(){
+ return
+ "Free all :term:`trigger`, :term:`date` and all time(:term:`day`, :term:`today`, :term:`cron`,etc) :term:`dependencies`::\n\n"
+ " void free_all_dep(\n"
+ " string absolute_node_path : Path name to node\n"
+ " )\n\n"
+ "After freeing the time related dependencies (i.e time,today,cron)\n"
+ "the next time slot will be missed.\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.free_all_dep('/s1')\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::ping(){
+ return
+ "Checks if the :term:`ecflow_server` is running::\n\n"
+ " void ping()\n\n"
+ "The default behaviour is to check on host 'localhost' and port 3141\n"
+ "It should be noted that any Client function will fail if the server is\n"
+ "is not running. Hence ping() is not strictly required. However its main\n"
+ "distinction from other Client function is that it is quite fast.\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client(\"localhost\",\"3150\")\n"
+ " ci.ping()\n"
+ " print \"------- Server already running------\"\n"
+ " do_something_with_server(ci)\n"
+ " except RuntimeError, e:\n"
+ " print \"------- Server *NOT* running------\" + str(e)\n"
+ ;
+}
+
+const char* ClientDoc::stats(){
+ return
+ "Prints the :term:`ecflow_server` statistics to standard out::\n\n"
+ " void stats()\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.stats()\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::stats_reset(){
+ return
+ "Resets the statistical data in the server::\n\n"
+ " void stats_reset()\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.stats_reset()\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::suites(){
+ return
+ "Returns a list strings representing the :term:`suite` names.\n\n"
+ " list(string) suites()\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " suites = ci.suites()\n"
+ " print suites\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::ch_register() {
+ return
+ "Register interest in a set of :term:`suite` s.\n\n"
+ "If a definition has lots of suites, but the client is only interested in a small subset.\n"
+ "Then using this command can reduce network bandwidth and synchronisation will be quicker.\n"
+ "This command will create a client handle. This handle is held locally on the :py:class:`ecflow.Client`, and\n"
+ "can be used implicitly by ch_drop(),ch_add(),ch_remove() and ch_auto_add().\n"
+ "Registering a client handle affects the news() and sync() commands::\n\n"
+ " void ch_register(\n"
+ " bool auto_add_new_suites : true means add new suites to my list, when they are created\n"
+ " list suite_names : should be a list of suite names, names not in the definition are ignored\n"
+ " )\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client()\n"
+ " suite_names = [ 's1', 's2', 's3' ]\n"
+ " ci.ch_register(True,suite_names) # register interest in suites s1,s2,s3 and any new suites\n"
+ " ci.ch_register(False,suite_names) # register interest in suites s1,s2,s3 only\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n\n"
+ "The client 'ci' will hold locally the client handle. Since we have made multiple calls to register\n"
+ "a handle, the variable 'ci' will hold the handle for the last call only.\n"
+ "The handle associated with the suite can be manually retrieved::\n\n"
+ " try:\n"
+ " ci = Client()\n"
+ " suite_names = [ 's1', 's2', 's3' ]\n"
+ " ci.ch_register(True,suite_names) # register interest in suites s1,s2,s3 and any new suites\n"
+ " client_handle = ci.ch_handle()\n # get the handle associated with last call to ch_register\n"
+ " ci.ch_drop( client_handle ) # de-register the handle\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n\n"
+ ;
+}
+
+const char* ClientDoc::ch_suites() {
+ return
+ "Writes to standard out the list of registered handles and the suites they reference.\n\n";
+}
+
+const char* ClientDoc::ch_drop(){
+ return
+ "Drop/de-register the client handle.\n\n"
+ "Client must ensure un-used handle are dropped otherwise they will stay, in the :term:`ecflow_server`::\n\n"
+ " void ch_drop(\n"
+ " int client_handle : The handle must be an integer that is > 0\n"
+ " )\n"
+ " void ch_drop() : Uses the local handle stored on the client, from last call to ch_register()\n\n"
+ "Exception:\n\n"
+ "- RunTimeError thrown if handle has not been previously registered\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " suites = [ 's1', 's2' ]\n"
+ " ci.ch_register(False, suites)\n"
+ " while( 1 ):\n"
+ " # get incremental changes to suites s1 & s2, uses data stored on ci/defs\n"
+ " ci.sync_local() # will only retrieve data for suites s1 & s2\n"
+ " update(ci.get_defs())\n"
+ " finally:\n"
+ " ci.ch_drop()\n"
+ ;
+}
+
+const char* ClientDoc::ch_drop_user(){
+ return
+ "Drop/de-register all handles associated with user.\n\n"
+ "Client must ensure un-used handle are dropped otherwise they will stay, in the :term:`ecflow_server`::\n\n"
+ " void ch_drop_user(\n"
+ " string user # If empty string will drop current user\n"
+ " )\n\n"
+ "Exception:\n\n"
+ "- RunTimeError thrown if handle has not been previously registered\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " suites = [ 's1', 's2' ]\n"
+ " ci.ch_register(False, suites)\n"
+ " while( 1 ):\n"
+ " # get incremental changes to suites s1 & s2, uses data stored on ci/defs\n"
+ " ci.sync_local() # will only retrieve data for suites s1 & s2\n"
+ " update(ci.get_defs())\n"
+ " finally:\n"
+ " ci.ch_drop_user(\"\") # drop all handles associated with current user\n\n"
+ ;
+}
+
+const char* ClientDoc::ch_add() {
+ return
+ "Add a set of suites, to an existing handle::\n\n"
+ " integer ch_add(\n"
+ " integer handle : the handle obtained after ch_register\n"
+ " list suite_names : list of strings representing suite names\n"
+ " )\n"
+ " integer ch_add(\n"
+ " list suite_names : list of strings representing suite names\n"
+ " )\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " suite_names = []\n"
+ " ci.ch_register(True,suite_names) # register interest in any new suites\n"
+ " suite_names = [ 's1', 's2' ]\n"
+ " ci.ch_add(suite_names) # add suites s1,s2 to the last added handle\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n\n"
+ ;
+}
+
+const char* ClientDoc::ch_remove() {
+ return
+ "Remove a set of suites, from an existing handle::\n\n"
+ " integer ch_remove(\n"
+ " integer handle : the handle obtained after ch_register\n"
+ " list suite_names : list of strings representing suite names\n"
+ " )\n"
+ " integer ch_remove(\n"
+ " list suite_names : list of strings representing suite names\n"
+ " )\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " suite_names = [ 's1', 's2' , 's3']\n"
+ " ci.ch_register(True,suite_names) # register interest in suites s1,s2,s3 and any new suites\n"
+ " suite_names = [ 's1' ]\n"
+ " ci.ch_remove( suite_names ) # remove suites s1 from the last added handle\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n\n"
+ ;
+}
+
+const char* ClientDoc::ch_auto_add() {
+ return
+ "Change an existing handle so that new suites can be added automatically::\n\n"
+ " void ch_auto_add(\n"
+ " integer handle, : the handle obtained after ch_register\n"
+ " bool auto_add_new_suite : automatically add new suites, this handle when they are created\n"
+ " )\n"
+ " void ch_auto_add(\n"
+ " bool auto_add_new_suite : automatically add new suites using handle on the client\n"
+ " )\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " suite_names = [ 's1', 's2' , 's3']\n"
+ " ci.ch_register(True,suite_names) # register interest in suites s1,s2,s3 and any new suites\n"
+ " ci.ch_auto_add( False ) # disable adding newly created suites to my handle\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n\n"
+ ;
+}
+
+const char* ClientDoc::get_file(){
+ return
+ "File command can be used to request the various file types associated with a :term:`node`\n\n"
+ "This command defaults to returning a max of 10000 lines. This can be changed::\n\n"
+ " string get_file(\n"
+ " string absolute_node_path : Path name to node\n"
+ " [(string)file_type='script'] : file_type = [ script<default> | job | jobout | manual | kill | stat ]\n"
+ " [(string)max_lines=\"10000\"] : The number of lines in the file to return\n"
+ " )\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " for file in [ 'script', 'job', 'jobout', 'manual', 'kill', 'stat' ]:\n"
+ " print ci.get_file('/suite/f1/t1',file) # make a request to the server\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::plug(){
+ return
+ "Plug command is used to move :term:`node` s\n\n"
+ "The destination node can be on another :term:`ecflow_server`.\n"
+ "In which case the destination path should be of the form '//<host>:<port>/suite/family/task::\n\n"
+ " void plug(\n"
+ " string source_absolute_node_path : Path name to source node\n"
+ " string destination_absolute_node_path : Path name to destination node. Note if only\n"
+ " '//host:port' is specified the whole suite can be moved\n"
+ " )\n\n"
+ "By default throws a RuntimeError exception for errors.\n\n"
+ "Exceptions can be raised because:\n\n"
+ "- Source :term:`node` is in a :term:`active` or :term:`submitted` state.\n"
+ "- Another user already has an lock.\n"
+ "- source/destination paths do not exist on the corresponding servers\n"
+ "- If the destination node path is empty, i.e. only host:port is specified,\n"
+ " then the source :term:`node` must correspond to a :term:`suite`.\n"
+ "- If the source node is added as a child, then its name must be unique\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.plug('/suite','host3:3141')\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::alter(){
+ return
+ "Alter command is used to change the attributes of a node::\n\n"
+ " void alter(\n"
+ " (list | string ) paths(s) : A single or list of paths. Path name to the node whose attributes are to be changed\n"
+ " string alter_type : This must be one of [ 'add' | 'change' | 'delete' | 'set_flag' | 'clear_flag' ]\n"
+ " string attr_type : This varies according to the 'alter_type'. valid strings are:\n"
+ " add : [ variable,time,today,date,day,zombie,late]\n"
+ " delete : [ variable,time,today,date,day,cron,event,meter,label,trigger,complete,repeat,limit,inlimit,limit_path,zombie,late]\n"
+ " change : [ variable,clock-type,clock-gain,event,meter,label,trigger,complete,repeat,limit-max,limit-value,late]\n"
+ " set_flag and clear_flag:\n"
+ " [ force_aborted | user_edit | task_aborted | edit_failed | ecfcmd_failed | no_script | killed | \n"
+ " migrated | late | message | complete | queue_limit | task_waiting | locked | zombie ]\n"
+ " string name : used to locate the attribute, when multiple attributes of the same type,\n"
+ " optional for some.i.e. when changing, attributes like variable,meter,event,label,limits\n"
+ " string value : Only used when 'changing' a attribute. provides a new value\n"
+ " )\n\n"
+ "Exceptions can be raised because:\n\n"
+ "- absolute_node_path does not exist.\n"
+ "- parsing fails\n"
+ "\n"
+ "The following describes the parameters in more detail::\n\n"
+ " add variable variable_name variable_value\n"
+ " add time format # when format is +hh:mm | hh:mm | hh:mm(start) hh:mm(finish) hh:mm(increment)\n"
+ " add today format # when format is +hh:mm | hh:mm | hh:mm(start) hh:mm(finish) hh:mm(increment)\n"
+ " add date format # when format dd.mm.yyyy, can use '*' to indicate any day,month, or year\n"
+ " add day format # when format is one of [ sunday,monday,tuesday,wednesday,friday,saturday ]\n"
+ " add zombie format # when format is one of <zombie-type>:<child>:<server-action>|<client-action>:<zombie-lifetime>\n"
+ " # <zombie-type> := [ user | ecf | path ]\n"
+ " # <child> := [ init, event, meter, label, wait, abort, complete ]\n"
+ " # <server-action> := [ adopt | delete ]\n"
+ " # <client-action> := [ fob | fail | block(default) ]\n"
+ " # <zombie-lifetime>:= lifetime of zombie in the server\n"
+ " # example\n"
+ " # add zombie :label:fob:0 # fob all child label request, & remove zombie as soon as possible\n"
+ "\n"
+ " delete variable name # if name is empty will delete -all- variables on the node\n"
+ " delete time name # To delete a specific time, enter the time in same format as show above,\n"
+ " # or as specified in the defs file\n"
+ " # an empty name will delete all time attributes on the node\n"
+ " delete today name # To delete a specific today attribute, enter in same format as show above,\n"
+ " # or as specified in the defs file.\n"
+ " # an empty name will delete all today attributes on the node\n"
+ " delete date name # To delete a specific date attribute, enter in same format as show above,\n"
+ " # or as specified in the defs file\n"
+ " # an empty name will delete all date attributes on the node\n"
+ " delete day name # To delete a specific day attribute, enter in same format as show above,\n"
+ " # or as specified in the defs file\n"
+ " # an empty name will delete all day attributes on the node\n"
+ " delete cron name # To delete a specific cron attribute, enter in same as specified in the defs file\n"
+ " # an empty name will delete all cron attributes on the node\n"
+ " delete event name # To delete a specific event, enter name or number\n"
+ " # an empty name will delete all events on the node\n"
+ " delete meter name # To delete a specific meter , enter the meter name\n"
+ " # an empty name will delete all meter on the node \n"
+ " delete label name # To delete a specific label , enter the label name\n"
+ " # an empty name will delete all labels on the node\n"
+ " delete limit name # To delete a specific limit , enter the limit name\n"
+ " # an empty name will delete all limits on the node\n"
+ " delete inlimit name # To delete a specific inlimit , enter the inlimit name\n"
+ " # an empty name will delete all inlimits on the node\n"
+ " delete limit_path limit_name limit_path # To delete a specific limit path\n"
+ " delete trigger # A node can only have one trigger expression, hence the name is not required\n"
+ " delete complete # A node can only have one complete expression, hence the name is not required\n"
+ " delete repeat # A node can only have one repeat, hence the name is not required\n"
+ "\n"
+ " change variable name value # Find the specified variable, and set the new value.\n"
+ " change clock_type name # The name must be one of 'hybrid' or 'real'.\n"
+ " change clock_gain name # The gain must be convertible to an integer.\n"
+ " change clock_sync name # Sync suite calendar with the computer.\n"
+ " change event name(optional ) # if no name specified the event is set, otherwise name must be 'set' or 'clear'\n"
+ " change meter name value # The meter value must be convertible to an integer, and between meter min-max range.\n"
+ " change label name value # sets the label\n"
+ " change trigger name # The name must be expression. returns an error if the expression does not parse\n"
+ " change complete name # The name must be expression. returns an error if the expression does not parse\n"
+ " change limit_max name value # Sets the max value of the limit. The value must be convertible to an integer\n"
+ " change limit_value name value # Sets the consumed tokens to value.The value must be convertible to an integer\n"
+ " change repeat value # If the repeat is a date, then the value must be a valid YMD ( ie. yyyymmdd)\n"
+ " # and be convertible to an integer, additionally the value must be in range\n"
+ " # of the repeat start and end dates. Like wise for repeat integer. For repeat\n"
+ " # string and enum, the name must either be an integer, that is a valid index or\n"
+ " # if it is a string, it must correspond to one of enum's or strings list\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.alter('/suite','change','trigger','b2 == complete')\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::force_state(){
+
+ return
+ "Force a node(s) to a given state\n\n"
+ "When a :term:`task` is set to :term:`complete`, it may be automatically re-queued if it has\n"
+ "multiple time :term:`dependencies`. In the specific case where a task has a single\n"
+ "time dependency and we want to interactively set it to :term:`complete`\n"
+ "a flag is set so that it is not automatically re-queued when set to complete.\n"
+ "The flag is applied up the node hierarchy until reach a node with a :term:`repeat`\n"
+ "or :term:`cron` attribute. This behaviour allow :term:`repeat` values to be incremented interactively.\n"
+ "A :term:`repeat` attribute is incremented when all the child nodes are :term:`complete`\n"
+ "in this case the child nodes are automatically re-queued\n::\n\n"
+ " void force_state(\n"
+ " string absolute_node_path: Path name to node. The path must begin with a leading '/'\n"
+ " State::State state : [ unknown | complete | queued | submitted | active | aborted ]\n"
+ " )\n"
+ " void force_state(\n"
+ " list paths : A list of absolute node paths. The paths must begin with a leading '/'\n"
+ " State::State state : [ unknown | complete | queued | submitted | active | aborted ]\n"
+ " )\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " # force a single node to complete\n"
+ " ci.force_state('/s1/f1',State.complete)\n"
+ "\n"
+ " # force a list of nodes to complete\n"
+ " paths = [ '/s1/t1', '/s1/t2', '/s1/f1/t1' ]\n"
+ " ci.force_state(paths,State.complete)\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ "\nEffect::\n\n"
+ " Lets see the effect of forcing complete on the following defs::\n\n"
+ " suite s1\n"
+ " task t1; time 10:00 # will complete straight away\n"
+ " task t2; time 10:00 13:00 01:00 # will re-queue 3 times and complete on fourth \n\n"
+ "In the last case (task t2) after each force complete, the next time slot is incremented.\n"
+ "This can be seen by calling the Why command."
+
+ ;
+}
+
+const char* ClientDoc::force_state_recursive(){
+
+ return
+ "Force node(s) to a given state recursively::\n\n"
+ " void force_state_recursive(\n"
+ " string absolute_node_path: Path name to node.The paths must begin with a leading '/'\n"
+ " State::State state : [ unknown | complete | queued | submitted | active | aborted ]\n"
+ " )\n"
+ " void force_state_recursive(\n"
+ " list paths : A list of absolute node paths.The paths must begin with a leading '/'\n"
+ " State::State state : [ unknown | complete | queued | submitted | active | aborted ]\n"
+ " )\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.force_state_recursive('/s1/f1',State.complete)\n"
+ "\n"
+ " # recursively force a list of nodes to complete\n"
+ " paths = [ '/s1', '/s2', '/s1/f1/t1' ]\n"
+ " ci.force_state_recursive(paths,State.complete)\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::force_event(){
+
+ return
+ "Set or clear a :term:`event`::\n\n"
+ " void force_event(\n"
+ " string absolute_node_path:event: Path name to node: < event name | number>\n"
+ " The paths must begin with a leading '/'\n"
+ " string signal : [ set | clear ]\n"
+ " )\n"
+ " void force_event(\n"
+ " list paths : A list of absolute node paths. Each path must include a event name\n"
+ " The paths must begin with a leading '/'\n"
+ " string signal : [ set | clear ]\n"
+ " )\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.force_event('/s1/f1:event_name','set')\n"
+ "\n"
+ " # Set or clear a event for a list of events\n"
+ " paths = [ '/s1/t1:ev1', '/s2/t2:ev2' ]\n"
+ " ci.force_event(paths,State.complete)\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::replace(){
+ return
+ "Replaces a :term:`node` in a :term:`suite definition` with the given path. The definition is in the :term:`ecflow_server`::\n\n"
+ " void replace(\n"
+ " string absolute_node_path: Path name to node in the client defs.\n"
+ " This is also the node we want to replace in the server.\n"
+ " string client_defs_file : File path to defs files, that provides the definition of the new node\n"
+ " [(bool)parent=False] : create parent families or suite as needed,\n"
+ " when absolute_node_path does not exist in the server\n"
+ " [(bool)force=False] : check for zombies, if force = true, bypass checks\n"
+ " )\n"
+ "\n"
+ " void replace(\n"
+ " string absolute_node_path: Path name to node in the client defs.\n"
+ " This is also the node we want to replace in the server.\n"
+ " Defs client_defs : In memory client definition that provides the definition of the new node\n"
+ " [(bool)parent=False] : create parent families or suite as needed,\n"
+ " when absolute_node_path does not exist in the server\n"
+ " [(bool)force=False] : check for zombies, force = true, bypass checks\n"
+ " )\n"
+ "\n"
+ "Exceptions can be raised because:\n\n"
+ "- The absolute_node_path does not exist in the provided definition\n"
+ "- The provided client definition must be free of errors\n"
+ "- If the third argument is not provided, then the absolute_node_path must exist in the server defs\n"
+ "- replace will fail, if child task nodes are in :term:`active` / :term:`submitted` state\n\n"
+ "After replace is done, we check trigger expressions. These are reported to standard output.\n"
+ "It is up to the user to correct invalid trigger expressions, otherwise the tasks will *not* run.\n"
+ "Please note, you can use check() to check trigger expression and limits in the server.\n\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.replace('/s1/f1','/tmp/defs.def')\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ "\n"
+ " try:\n"
+ " ci.replace('/s1',client_defs) # replace suite 's1' in the server, with 's1' in the client_defs\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::kill(){
+ return
+ "Kills the job associated with the :term:`node`.::\n\n"
+ " void kill(\n"
+ " list paths: List of paths. Paths must begin with a leading '/' character\n"
+ " )\n"
+ " void kill(\n"
+ " string absolute_node_path: Path name to node to kill.\n"
+ " )\n"
+ "\n"
+ "If a :term:`family` or :term:`suite` is selected, will kill hierarchically.\n"
+ "Kill uses the ECF_KILL_CMD variable. After :term:`variable substitution` it is invoked as a command.\n"
+ "The ECF_KILL_CMD variable should be written in such a way that the output is written to %ECF_JOB%.kill, i.e::\n\n"
+ " kill -15 %ECF_RID% > %ECF_JOB%.kill 2>&1\n"
+ " /home/ma/emos/bin/ecfkill %USER% %HOST% %ECF_RID% %ECF_JOB% > %ECF_JOB%.kill 2>&1\n\n"
+ "\n"
+ "Exceptions can be raised because:\n\n"
+ "- The absolute_node_path does not exist in the server\n"
+ "- ECF_KILL_CMD variable is not defined\n"
+ "- :term:`variable substitution` fails\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.kill('/s1/f1')\n"
+ " time.sleep(2)\n"
+ " print ci.file('/s1/t1','kill') # request kill output\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::status(){
+ return
+ "Shows the status of a job associated with a :term:`task` ::\n\n"
+ " void status(\n"
+ " list paths: List of paths. Paths must begin with a leading '/' character\n"
+ " )\n"
+ " void status(\n"
+ " string absolute_node_path\n"
+ " )\n\n"
+ "If a :term:`family` or :term:`suite` is selected, will invoke status command hierarchically.\n"
+ "Status uses the ECF_STATUS_CMD variable. After :term:`variable substitution` it is invoked as a command.\n"
+ "The command should be written in such a way that the output is written to %ECF_JOB%.stat, i.e::\n\n"
+ " /home/ma/emos/bin/ecfstatus %USER% %HOST% %ECF_RID% %ECF_JOB% > %ECF_JOB%.stat 2>&1\n\n"
+ "Exceptions can be raised because:\n\n"
+ "- The absolute_node_path does not exist in the server\n"
+ "- ECF_STATUS_CMD variable is not defined\n"
+ "- :term:`variable substitution` fails\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.status('/s1/t1')\n"
+ " time.sleep(2)\n"
+ " print ci.file('/s1/t1','stats') # request status output\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::order(){
+ return
+ "Re-orders the :term:`node` s in the :term:`suite definition` held by the :term:`ecflow_server`\n\n"
+ "It should be noted that in the absence of :term:`dependencies`,\n"
+ "the order in which :term:`task` s are :term:`submitted`, depends on the order in the definition.\n"
+ "This changes the order and hence affects the submission order::\n\n"
+ " void order(\n"
+ " string absolute_node_path: Path name to node.\n"
+ " string order_type : Must be one of [ top | bottom | alpha | order | up | down ]\n"
+ " )\n"
+ " o top raises the node within its parent, so that it is first\n"
+ " o bottom lowers the node within its parent, so that it is last\n"
+ " o alpha Arranges for all the peers of selected note to be sorted alphabetically\n"
+ " o order Arranges for all the peers of selected note to be sorted in reverse alphabet\n"
+ " o up Moves the selected node up one place amongst its peers\n"
+ " o down Moves the selected node down one place amongst its peers\n\n"
+ "Exceptions can be raised because:\n\n"
+ "- The absolute_node_path does not exist in the server\n"
+ "- The order_type is not the right type\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.order('/s1/f1','top')\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::group(){
+ return
+ "Allows a series of commands to be executed in the :term:`ecflow_server`::\n\n"
+ " void group(\n"
+ " string cmds : a list of ';' separated commands \n"
+ " )\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.group('get; show')\n"
+ " ci.group('get; show state') # show node states and trigger abstract syntax trees\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::begin_suite(){
+ return
+ "Begin playing the chosen :term:`suite` s in the :term:`ecflow_server`\n"
+ "Note: using the force option may cause :term:`zombie` s::\n\n"
+ " void begin_suite\n"
+ " string suite_name : begin playing the given suite\n"
+ " [(bool)force=False] : bypass the checks\n"
+ " )\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.begin_suite('/suite1') # begin playing suite '/suite1'\n"
+ " ci.begin_suite('/suite1',True) # begin playing suite '/suite1' bypass any checks"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::begin_all(){
+ return
+ "Begin playing all the :term:`suite` s in the :term:`ecflow_server`\n"
+ "Note: using the force option may cause :term:`zombie` s::\n\n"
+ " void begin_all_suites(\n"
+ " [(bool)force=False] : bypass the checks\n"
+ " )\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.begin_all_suites() # begin playing all the suites\n"
+ " ci.begin_all_suites(True) # begin playing all the suites, by passing checks\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::suspend(){
+ return
+ "Suspend :term:`job creation` / generation for the given :term:`node`::\n\n"
+ " void suspend(\n"
+ " list paths: List of paths. Paths must begin with a leading '/' character\n"
+ " )\n"
+ " void suspend(\n"
+ " string absolute_node_path: Path name to node to suspend.\n"
+ " )\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.suspend('/s1/f1/task1')\n"
+ " paths = ['/s1/f1/t1','/s2/f1/t2']\n"
+ " ci.suspend(paths)\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::resume(){
+ return
+ "Resume :term:`job creation` / generation for the given :term:`node`::\n\n"
+ " void resume(\n"
+ " list paths: List of paths. Paths must begin with a leading '/' character\n"
+ " )\n"
+ " void resume(\n"
+ " string absolute_node_path: Path name to node to resume.\n"
+ " )\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.resume('/s1/f1/task1')\n"
+ " paths = ['/s1/f1/t1','/s2/f1/t2']\n"
+ " ci.resume(paths)\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::job_gen(){
+ return
+ "Job submission for chosen Node *based* on :term:`dependencies`\n"
+ "The :term:`ecflow_server` traverses the :term:`node` tree every 60 seconds, and if the dependencies are free\n"
+ "does :term:`job creation` and submission. Sometimes the user may free time/date dependencies\n"
+ "to avoid waiting for the server poll, this commands allows early job generation::\n\n"
+ " void job_generation(\n"
+ " string absolute_node_path: Path name for job generation to start from\n"
+ " )\n"
+ " If empty string specified generates for full definition.\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.job_generation('/s1') # generate jobs for suite '/s1 \n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::delete_node(){
+ return
+ "Delete the :term:`node` (s) specified.\n\n"
+ "If a node is :term:`submitted` or :term:`active`, then a Exception will be raised.\n"
+ "To force the deletion at the expense of :term:`zombie` creation, then set\n"
+ "the force parameter to true::\n\n"
+ " void delete(\n"
+ " list paths : List of paths.\n"
+ " [(bool)force=False] : If true delete even if in 'active' or 'submitted' states\n"
+ " Which risks creating zombies.\n"
+ " )\n"
+ " void delete(\n"
+ " string absolute_node_path: Path name of node to delete.\n"
+ " [(bool)force=False] : If true delete even if in 'active' or 'submitted' states\n"
+ " )\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.delete('/s1/f1/task1')\n"
+ "\n"
+ " paths = ['/s1/f1/t1','/s2/f1/t2']\n"
+ " ci.delete(paths) # delete all tasks specified in the paths\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* ClientDoc::delete_all(){
+ return
+ "Delete all the :term:`node` s held in the :term:`ecflow_server`.\n\n"
+ "The :term:`suite definition` in the server will be empty, after this call. **Use with care**\n"
+ "If a node is :term:`submitted` or :term:`active`, then a Exception will be raised.\n"
+ "To force the deletion at the expense of :term:`zombie` creation, then set\n"
+ "the force parameter to true::\n\n"
+ " void delete_all(\n"
+ " [(bool)force=False] : If true delete even if in 'active' or 'submitted' states\n"
+ " Which risks creating zombies.\n"
+ " )\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.delete_all()\n"
+ " ci.get_server_defs()\n"
+ " except RuntimeError, e:\n"
+ " print str(e); # expect failure since all nodes deleted"
+ ;
+}
+
+const char* ClientDoc::check()
+{
+ return
+ "Check :term:`trigger` and :term:`complete expression` s and :term:`limit` s\n\n"
+ "The :term:`ecflow_server` does not store :term:`extern` s. Hence all unresolved references\n"
+ "are reported as errors.\n"
+ "Returns a non empty string for any errors or warning::\n\n"
+ " string check(\n"
+ " list paths # List of paths.\n"
+ " )\n"
+ " string check(\n"
+ " string absolute_node_path\n"
+ " )\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " print ci.check('/suite1')\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
diff --git a/Pyext/src/ClientDoc.hpp b/Pyext/src/ClientDoc.hpp
new file mode 100644
index 0000000..724f58e
--- /dev/null
+++ b/Pyext/src/ClientDoc.hpp
@@ -0,0 +1,92 @@
+#ifndef CLIENT_DOC_HPP_
+#define CLIENT_DOC_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #32 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/noncopyable.hpp>
+
+// ===========================================================================
+// IMPORTANT: These appear as python doc strings.
+// Additionally they are auto documented using sphinx-poco
+// Hence the doc strings use reStructuredText markup.
+// ===========================================================================
+class ClientDoc : private boost::noncopyable {
+public:
+ static const char* class_client();
+ static const char* set_host_port();
+ static const char* set_retry_connection_period();
+ static const char* set_connection_attempts();
+ static const char* get_defs();
+
+ static const char* get_log();
+ static const char* new_log();
+ static const char* clear_log();
+ static const char* flush_log();
+ static const char* log_msg();
+ static const char* restart_server();
+ static const char* halt_server();
+ static const char* shutdown_server();
+ static const char* terminate_server();
+ static const char* wait_for_server_reply();
+ static const char* load_defs();
+ static const char* load();
+ static const char* get_server_defs();
+ static const char* sync();
+ static const char* in_sync();
+ static const char* news();
+ static const char* changed_node_paths();
+ static const char* checkpt();
+ static const char* restore_from_checkpt();
+ static const char* reload_wl_file();
+ static const char* run();
+ static const char* requeue();
+ static const char* free_date_dep();
+ static const char* free_trigger_dep();
+ static const char* free_time_dep();
+ static const char* free_all_dep();
+ static const char* ping();
+ static const char* stats();
+ static const char* stats_reset();
+ static const char* suites();
+ static const char* ch_register();
+ static const char* ch_suites();
+ static const char* ch_drop();
+ static const char* ch_drop_user();
+ static const char* ch_add();
+ static const char* ch_remove();
+ static const char* ch_auto_add();
+ static const char* get_file();
+ static const char* plug();
+ static const char* alter();
+ static const char* force_state();
+ static const char* force_state_recursive();
+ static const char* force_event();
+ static const char* replace();
+ static const char* kill();
+ static const char* check();
+ static const char* status();
+ static const char* order();
+ static const char* group();
+ static const char* begin_suite();
+ static const char* begin_all();
+ static const char* suspend();
+ static const char* resume();
+ static const char* job_gen();
+ static const char* delete_node();
+ static const char* delete_all();
+
+private:
+ ClientDoc(){}
+};
+#endif
diff --git a/Pyext/src/DefsDoc.cpp b/Pyext/src/DefsDoc.cpp
new file mode 100644
index 0000000..873471b
--- /dev/null
+++ b/Pyext/src/DefsDoc.cpp
@@ -0,0 +1,800 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #73 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : This class is used as a helper class
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "DefsDoc.hpp"
+
+const char* DefsDoc::abs_node_path_doc()
+{
+ return "returns a string which holds the path to the node\n\n";
+}
+
+const char* DefsDoc::part_expression_doc()
+{
+ return
+ "PartExpression holds part of a :term:`trigger` or :term:`complete expression`.\n\n"
+ "Expressions can contain references to :term:`event`, :term:`meter` s, user variables,\n"
+ ":term:`repeat` variables and generated variables. The part expression allows us\n"
+ "to split a large trigger or complete expression into smaller ones\n"
+ "\nConstructor::\n\n"
+ " PartExpression(exp )\n"
+ " string exp: This represents the *first* expression\n\n"
+ " PartExpression(exp, bool and_expr)\n"
+ " string exp: This represents the expression\n"
+ " bool and_exp: If true the expression is to be anded, with a previously added expression\n"
+ " If false the expression is to be 'ored', with a previously added expression\n"
+ "\nUsage:\n"
+ "To add simple expression this class can be by-passed, i.e. can use::\n\n"
+ " task = Task('t1')\n"
+ " task.add_trigger( 't2 == active' )\n"
+ " task.add_complete( 't2 == complete' )\n\n"
+ "To add large triggers and complete expression::\n\n"
+ " exp1 = PartExpression('t1 == complete')\n # a simple expression can be added as a string\n"
+ " ....\n"
+ " task2.add_part_trigger( PartExpression(\"t1 == complete or t4 == complete\") ) \n"
+ " task2.add_part_trigger( PartExpression(\"t5 == active\",True) ) # anded with first expression\n"
+ " task2.add_part_trigger( PartExpression(\"t7 == active\",False) ) # or'ed with last expression added\n\n"
+ "The trigger for task2 is equivalent to\n"
+ "'t1 == complete or t4 == complete and t5 == active or t7 == active'"
+ ;
+}
+
+const char* DefsDoc::expression_doc()
+{
+ return
+ "Expression holds :term:`trigger` or :term:`complete expression`.\n\n"
+ "Expressions can contain references to events, meters, user variables,repeat variables and generated variables.\n"
+ "Expressions hold a list of part expressions. This allows us to split a large trigger or complete\n"
+ "expression into smaller ones.\n"
+ "\nConstructor::\n\n"
+ " Expression( expression )\n"
+ " string expression : This typically represents the complete expression\n"
+ " however part expression can still be added\n"
+ " Expression( part )\n"
+ " PartExpression part: The first part expression should have no 'and/or' set\n"
+ "\nUsage:\n"
+ "To add simple expression this class can be by passed, i.e. can use::\n\n"
+ " task = Task('t1')\n"
+ " task.add_trigger( 't2 == active' )\n"
+ " task.add_complete( 't2 == complete' )\n"
+ "\n"
+ " task = Task('t2')\n"
+ " task.add_trigger( 't1 == active' )\n"
+ " task.add_part_trigger( 't3 == active', True)\n\n"
+ "To store and add large expressions use a Expression with PartExpression::\n\n"
+ " big_expr = Expression( PartExpression(\"t1 == complete or t4 == complete\") )\n"
+ " big_expr.add( PartExpression(\"t5 == active\",True) )\n"
+ " big_expr.add( PartExpression(\"t7 == active\",False) )\n"
+ " task.add_trigger( big_expr)\n\n"
+ "In the example above the trigger for task is equivalent to\n"
+ "'t1 == complete or t4 == complete and t5 == active or t7 == active'\n\n"
+ "::\n\n"
+ " big_expr2 = Expression('t0 == complete'))\n"
+ " big_expr2.add( PartExpression(\"t1 == complete or t4 == complete\",True) )\n"
+ " big_expr2.add( PartExpression(\"t5 == active\",False) )\n"
+ " task2.add_trigger( big_expr2)\n\n"
+ "Here the trigger for task2 is equivalent to\n"
+ "'t0 == complete and t1 == complete or t4 == complete or t5 == active'"
+ ;
+}
+
+const char* DefsDoc::add_trigger_doc()
+{
+ return
+ "Add a :term:`trigger` or :term:`complete expression`.\n\n"
+ "This defines a dependency for a :term:`node`.\n"
+ "There can only be one :term:`trigger` or :term:`complete expression` dependency per node.\n"
+ "A :term:`node` with a trigger can only be activated when the trigger has expired.\n"
+ "A trigger holds a node as long as the expression returns false.\n"
+ "\nException:\n\n"
+ "- Will throw RuntimeError if multiple trigger or complete expression are added\n"
+ "- Will throw RuntimeError if first expression is added as 'AND' or 'OR' expression\n"
+ " Like wise second and subsequent expression must have 'AND' or 'OR' booleans set\n"
+ "\nUsage:\n\n"
+ "Note we can not make multiple add_trigger(..) calls on the same :term:`task`!\n"
+ "to add a simple trigger::\n\n"
+ " task1.add_trigger( \"t2 == active\" )\n"
+ " task2.add_trigger( \"t1 == complete or t4 == complete\" )\n"
+ " task3.add_trigger( \"t5 == active\" )\n"
+ "\n"
+ "Long expression can be broken up using add_part_trigger::\n\n"
+ " task2.add_part_trigger( \"t1 == complete or t4 == complete\")\n"
+ " task2.add_part_trigger( \"t5 == active\",True) # True means AND\n"
+ " task2.add_part_trigger( \"t7 == active\",False) # False means OR\n\n"
+ "The trigger for task2 is equivalent to:\n"
+ "'t1 == complete or t4 == complete and t5 == active or t7 == active'"
+ ;
+}
+
+const char* DefsDoc::add_variable_doc()
+{
+ return
+ "Adds a name value :term:`variable`.\n\n"
+ "This defines a variable for use in :term:`variable substitution` in a :term:`ecf script` file.\n"
+ "There can be any number of variables. The variables are names inside a pair of\n"
+ "'%' characters in an :term:`ecf script`. The name are case sensitive.\n"
+ "Special character in the value, must be placed inside single quotes if misinterpretation\n"
+ "is to be avoided.\n"
+ "The value of the variable replaces the variable name in the :term:`ecf script` at :term:`job creation` time.\n"
+ "The variable names for any given node must be unique. If duplicates are added then the\n"
+ "the last value added is kept.\n"
+ "\nException:\n\n"
+ "- Writes warning to standard output, if a duplicate variable name is added\n"
+ "\nUsage::\n\n"
+ " task.add_variable( Variable(\"ECF_HOME\",\"/tmp/\"))\n"
+ " task.add_variable( \"TMPDIR\",\"/tmp/\")\n"
+ " task.add_variable( \"COUNT\",2)\n"
+ " a_dict = { \"name\":\"value\", \"name2\":\"value2\", \"name3\":\"value3\" }\n"
+ " task.add_variable(a_dict)\n"
+ ;
+}
+
+const char* DefsDoc::add_label_doc()
+{
+ return
+ "Adds a :term:`label` to a :term:`node`.\n\n"
+ "Labels can be updated from the jobs files, via :term:`child command`\n"
+ "\nException:\n\n"
+ "- Throws RuntimeError if a duplicate label name is added\n"
+ "\nUsage::\n\n"
+ " task.add_label( Label(\"TEA\",\"/me/\"))\n"
+ " task.add_label( \"Joe\",\"/me/\")\n\n"
+ "The corresponding child command in the .ecf script file might be::\n"
+ " ecflow_client --label=TEA time\n"
+ " ecflow_client --label=Joe ninety\n"
+ ;
+}
+
+const char* DefsDoc::add_limit_doc()
+{
+ return
+ "Adds a :term:`limit` to a :term:`node` for simple load management.\n\n"
+ "Multiple limits can be added, however the limit name must be unique.\n"
+ "For a node to be in a limit, a :term:`inlimit` must be used.\n"
+ "\nException:\n\n"
+ "- Throws RuntimeError if a duplicate limit name is added\n"
+ "\nUsage::\n\n"
+ " family.add_limit( Limit(\"load\",12) )\n"
+ " family.add_limit( \"load\",12 )\n"
+ ;
+}
+
+const char* DefsDoc::add_inlimit_doc()
+{
+ return
+ "Adds a :term:`inlimit` to a :term:`node`.\n\n"
+ "InLimit reference a :term:`limit`/:py:class:`ecflow.Limit`. Duplicate InLimits are not allowed\n"
+ "\nException:\n\n"
+ "- Throws RuntimeError if a duplicate is added\n"
+ "\nUsage::\n\n"
+ " task2.add_inlimit( InLimit(\"limitName\",\"/s1/f1\",2) )\n"
+ " task2.add_inlimit( \"limitName\",\"/s1/f1\",2 )\n"
+ ;
+}
+
+const char* DefsDoc::suite_doc()
+{
+ return
+ "A :term:`suite` is a collection of Families,Tasks,Variables, :term:`repeat` and :term:`clock` definitions\n\n"
+ "Suite is the only node that can be started using the begin API.\n"
+ "There are two ways of adding a suite, see example below and :py:class:`ecflow.Defs.add_suite`\n"
+ "\nConstructor::\n\n"
+ " Suite(name)\n"
+ " string name : The Suite name. name must consist of alpha numeric characters or\n"
+ " underscore or dot. The first character can not be a dot, as this\n"
+ " will interfere with trigger expressions. Case is significant\n"
+ "\nException:\n\n"
+ "- Throws a RuntimeError if the name is not valid\n"
+ "- Throws a RuntimeError if duplicate suite names added\n"
+ "\nUsage::\n\n"
+ " defs = Defs(\"new.def\") # create a defs\n"
+ " suite = Suite(\"suite_1\") # create a suite\n"
+ " defs.add_suite(suite) # add suite to definition\n"
+ " suite2 = defs.add_suite(\"s2\") # create a suite and add it to the defs\n"
+ ;
+}
+
+const char* DefsDoc::family_doc()
+{
+ return
+ "Create a :term:`family` :term:`node`.A Family node lives inside a :term:`suite` or another :term:`family`\n\n"
+ "A family is used to collect :term:`task` s together or to group other families.\n"
+ "Typically you place tasks that are related to each other inside the same family\n"
+ "analogous to the way you create directories to contain related files.\n"
+ "There are two ways of adding a family, see example below.\n"
+ "\nConstructor::\n\n"
+ " Family(name)\n"
+ " string name : The Family name. name must consist of alpha numeric characters or\n"
+ " underscore or dot. The first character can not be dot, as this\n"
+ " will interfere with trigger expressions. Case is significant\n"
+ "\nException:\n\n"
+ "- Throws a RuntimeError if the name is not valid\n"
+ "- Throws a RuntimeError if a duplicate family is added\n"
+ "\nUsage::\n\n"
+ " suite = Suite(\"suite_1\") # create a suite\n"
+ " family = Family(\"family_1\") # create a family\n"
+ " suite.add_family(family) # add created family to a suite\n"
+ " f2 = suite.add_family(\"f2\") # create a family r2 and add to suite\n"
+ ;
+}
+
+const char* DefsDoc::task_doc()
+{
+ return
+ "Creates a :term:`task` :term:`node`.Task is a child of a :term:`suite` or :term:`family` node.\n\n"
+ "Multiple Tasks can be added, however the task names must be unique for a given parent.\n"
+ "Note case is significant. Only Tasks can be submitted. A job inside a Task :term:`ecf script` (i.e .ecf file)\n"
+ "should generally be re-entrant since a Task may be automatically submitted more than once if it aborts.\n"
+ "There are two ways of adding a task, see example below\n"
+ "\nConstructor::\n\n"
+ " Task(name)\n"
+ " string name : The Task name.Name must consist of alpha numeric characters or\n"
+ " underscore or dot. First character can not be a dot.\n"
+ " Case is significant\n"
+ "\nException:\n\n"
+ "- Throws a RuntimeError if the name is not valid\n"
+ "- Throws a RuntimeError if a duplicate Task is added\n"
+ "\nUsage::\n\n"
+ " task = Task(\"t1\") # create a task\n"
+ " family.add_task(task) # add to the family\n"
+ " t2 = family.add_task(\"t2\") # create a task t2 and add to the family\n\n"
+ ;
+}
+
+const char* DefsDoc::alias_doc()
+{
+ return
+ "A Aliases is create by the GUI or via edit_script command\n\n"
+ "Aliases provide a mechanism to edit/test task scripts without effecting the suite\n"
+ "The Aliases parent is always a Task.Multiple Alias can be added\n"
+ ;
+}
+
+const char* DefsDoc::add_suite_doc()
+{
+ return
+ "Add a :term:`suite` :term:`node`. See :py:class:`ecflow.Suite`\n\n"
+ "Only one suite should be added for ease of maintenance. If a new suite is added\n"
+ "which matches the name of an existing suite, then an exception is thrown.\n"
+ "\nException:\n\n"
+ "- Throws RuntimeError is the suite name is not valid\n"
+ "- Throws RuntimeError if duplicate suite is added\n"
+ "\nUsage::\n\n"
+ " Defs defs(\"file.def\" # create a defs)\n"
+ " suite = Suite(\"suite\") # create a Suite \n"
+ " defs.add_suite(suite) # add suite to defs\n"
+ " s2 = defs.add_suite(\"s2\") # create a suite and add to defs\n"
+ ;
+}
+
+const char* DefsDoc::add_extern_doc()
+{
+ return
+ ":term:`extern` refer to nodes that have not yet been defined typically due to cross suite :term:`dependencies`\n\n"
+ ":term:`trigger` and :term:`complete expression` s may refer to paths, and variables in other suites, that have not been\n"
+ "loaded yet. The references to node paths and variable must exist, or exist as externs\n"
+ "Externs can be added manually or automatically.\n\n"
+ "Manual Method::\n\n"
+ " void add_extern(string nodePath )\n"
+ "\nUsage::\n\n"
+ " defs = Defs(\"file.def\")\n"
+ " ....\n"
+ " defs.add_extern('/temp/bill:event_name')\n"
+ " defs.add_extern('/temp/bill:meter_name')\n"
+ " defs.add_extern('/temp/bill:repeat_name')\n"
+ " defs.add_extern('/temp/bill:edit_name')\n"
+ " defs.add_extern('/temp/bill')\n"
+ "\n"
+ "Automatic Method:\n"
+ " This will scan all trigger and complete expressions, looking for paths and variables\n"
+ " that have not been defined. The added benefit of this approach is that duplicates will not\n"
+ " be added. It is the user's responsibility to check that extern's are eventually defined\n"
+ " otherwise trigger expression will not evaluate correctly\n\n"
+ "::\n\n"
+ " void auto_add_externs(bool remove_existing_externs_first )\n"
+ "\nUsage::\n\n"
+ " defs = Defs(\"file.def\")\n"
+ " ...\n"
+ " defs.auto_add_externs(True) # remove existing extern first.\n"
+ ;
+}
+
+
+const char* DefsDoc::node_doc()
+{
+ return
+ "A Node class is the abstract base class for Suite, Family and Task\n\n"
+ "Every Node instance has a name, and a path relative to a suite"
+ ;
+}
+
+const char* DefsDoc::node_container_doc()
+{
+ return
+ "NodeContainer is the abstract base class for a Suite and Family\n\n"
+ "A NodeContainer can have Families and Tasks as children"
+ ;
+}
+
+const char* DefsDoc::submittable_doc()
+{
+ return
+ "Submittable is the abstract base class for a Task and Alias\n\n"
+ "It provides a process id, password and try number"
+ ;
+}
+
+const char* DefsDoc::add_family_doc()
+{
+ return
+ "Add a :term:`family`. See :py:class:`ecflow.Family`.\n\n"
+ "Multiple families can be added. However family names must be unique.\n"
+ "for a given parent. Families can be hierarchical.\n"
+ "\nException:\n\n"
+ "- Throws RuntimeError if a duplicate is added\n"
+ "\nUsage::\n\n"
+ " suite = Suite(\"suite\") # create a suite\n"
+ " f1 = Family(\"f1\") # create a family\n"
+ " suite.add_family(f1) # add family to suite\n"
+ " f2 = suite.add_family(\"f2\") # create a family and add to suite\n"
+ ;
+}
+
+const char* DefsDoc::add_task_doc()
+{
+ return
+ "Add a :term:`task`. See :py:class:`ecflow.Task`\n\n"
+ "Multiple Tasks can be added. However Task names must be unique,\n"
+ "for a given parent. Task can be added to Familiy's or Suites.\n"
+ "\nException:\n\n"
+ "- Throws RuntimeError if a duplicate is added\n"
+ "\nUsage::\n\n"
+ " f1 = Family(\"f1\") # create a family\n"
+ " t1 = Task(\"t1\") # create a task\n"
+ " f1.add_task(t1) # add task to family\n"
+ " t2 = f1.add_task(\"t2\") # create task 't2' and add to family"
+ ;
+}
+
+
+const char* DefsDoc::add_definition_doc()
+{
+ return
+ "The Defs class holds the :term:`suite definition` structure.\n\n"
+ "It contains all the suites and hence acts like the root for suite node tree hierarchy.\n"
+ "The definition can be kept as python code, alternatively it can be saved as a flat\n"
+ "ASCII definition file.\n"
+ "If a definition is read in from disk, it will by default, check the :term:`trigger` expressions.\n"
+ "If however the definition is created in python, then checking should be done explicitly.\n"
+ "The Defs class take one argument which represents the file name\n\n"
+ "Example::\n\n"
+ " defs = Defs() # create an empty defs\n"
+ " suite = defs.add_suite(\"s1\")\n"
+ " family = suite.add_family(\"f1\")\n"
+ " for i in [ \"_1\", \"_2\", \"_3\" ]: family.add_task( \"t\" + i )\n"
+ " defs.save_as_defs('filename.def') # save defs into file\n"
+ "\n"
+ "Create a Defs from an existing file on disk.\n"
+ "\n"
+ " defs = Defs('filename.def') # Will open and parse the file and create the Definition\n"
+ " print defs\n"
+ ;
+}
+
+const char* DefsDoc::add_event_doc()
+{
+ return
+ "Add a :term:`event`. See :py:class:`ecflow.Event`\n"
+ "Events can be referenced in :term:`trigger` and :term:`complete expression` s\n\n"
+ "\nException:\n\n"
+ "- Throws RuntimeError if a duplicate is added\n"
+ "\nUsage::\n\n"
+ " t1 = Task(\"t1\")\n"
+ " t1.add_event( Event(10) )\n"
+ " t1.add_event( Event(11,\"Eventname\") )\n"
+ " t1.add_event( 12 )\n"
+ " t1.add_event( 13, \"name\")\n"
+ " t1.add_event(\"flag\")\n\n"
+ "To reference in a trigger::\n\n"
+ " t2 = Task(\"t2\")\n"
+ " t2.add_trigger('t1:flag == set')\n"
+ ;
+}
+
+const char* DefsDoc::add_meter_doc()
+{
+ return
+ "Add a :term:`meter`. See :py:class:`ecflow.Meter`\n"
+ "Meters can be referenced in :term:`trigger` and :term:`complete expression` s\n\n"
+ "\nException:\n\n"
+ "- Throws RuntimeError if a duplicate is added\n"
+ "\nUsage::\n\n"
+ " t1 = Task(\"t1\")\n"
+ " t1.add_meter( Meter(\"metername\",0,100,50) )\n"
+ " t1.add_meter( \"meter\",0,200)\n\n"
+ "To reference in a trigger::\n\n"
+ " t2 = Task(\"t2\")\n"
+ " t2.add_trigger('t1:meter >= 10')\n"
+ ;
+}
+
+const char* DefsDoc::add_date_doc()
+{
+ return
+ "Add a :term:`date` time dependency\n\n"
+ "A value of zero for day,month,year means every day, every month, every year\n"
+ "\nException:\n\n"
+ "- Throws RuntimeError if an invalid date is added\n"
+ "\nUsage::\n\n"
+ " t1 = Task(\"t1\")\n"
+ " t1.add_date( Date(1,1,2010) ) # day,month,year\n"
+ " t1.add_date( 2,1,2010) # day,month,year\n"
+ " t1.add_date( 1,0,0) # day,month,year, the first of each month for every year\n"
+ ;
+}
+
+const char* DefsDoc::add_day_doc()
+{
+ return
+ "Add a :term:`day` time dependency\n\n"
+ "\nUsage::\n\n"
+ " t1 = Task(\"t1\")\n"
+ " t1.add_day( Day(Days.sunday) ) \n"
+ " t1.add_day( Days.monday)\n"
+ " t1.add_day( \"tuesday\")\n"
+ ;
+}
+
+const char* DefsDoc::add_today_doc()
+{
+ return
+ "Add a :term:`today` time dependency\n\n"
+ "\nUsage::\n\n"
+ " t1 = Task(\"t1\")\n"
+ " t1.add_today( \"00:30\" )\n"
+ " t1.add_today( \"+00:30\" )\n"
+ " t1.add_today( \"+00:30 20:00 01:00\" )\n"
+ " t1.add_today( Today( 0,10 )) # hour,min,relative =false\n"
+ " t1.add_today( Today( 0,12,True )) # hour,min,relative\n"
+ " t1.add_today( Today(TimeSlot(20,20),False))\n"
+ " t1.add_today( 0,1 )) # hour,min,relative=false\n"
+ " t1.add_today( 0,3,False )) # hour,min,relative=false\n"
+ " start = TimeSlot(0,0)\n"
+ " finish = TimeSlot(23,0)\n"
+ " incr = TimeSlot(0,30)\n"
+ " ts = TimeSeries( start, finish, incr, True)\n"
+ " task2.add_today( Today(ts) )\n"
+ ;
+}
+
+const char* DefsDoc::add_time_doc()
+{
+ return
+ "Add a :term:`time` dependency\n\n"
+ "\nUsage::\n\n"
+ " t1 = Task(\"t1\")\n"
+ " t1.add_time( \"00:30\" )\n"
+ " t1.add_time( \"+00:30\" )\n"
+ " t1.add_time( \"+00:30 20:00 01:00\" )\n"
+ " t1.add_time( Time( 0,10 )) # hour,min,relative =false\n"
+ " t1.add_time( Time( 0,12,True )) # hour,min,relative\n"
+ " t1.add_time( Time(TimeSlot(20,20),False))\n"
+ " t1.add_time( 0,1 )) # hour,min,relative=false\n"
+ " t1.add_time( 0,3,False )) # hour,min,relative=false\n"
+ " start = TimeSlot(0,0)\n"
+ " finish = TimeSlot(23,0)\n"
+ " incr = TimeSlot(0,30)\n"
+ " ts = TimeSeries( start, finish, incr, True)\n"
+ " task2.add_time( Time(ts) )\n"
+ ;
+}
+
+const char* DefsDoc::add_cron_doc()
+{
+ return
+ "Add a :term:`cron` time dependency\n\n"
+ "\nUsage::\n\n"
+ " start = TimeSlot(0,0)\n"
+ " finish = TimeSlot(23,0)\n"
+ " incr = TimeSlot(0,30)\n"
+ " time_series = TimeSeries( start, finish, incr, True)\n"
+ " cron = Cron()\n"
+ " cron.set_week_days( [0,1,2,3,4,5,6] )\n"
+ " cron.set_days_of_month( [1,2,3,4,5,6] )\n"
+ " cron.set_months( [1,2,3,4,5,6] )\n"
+ " cron.set_time_series( time_series )\n"
+ " t1 = Task(\"t1\")\n"
+ " t1.add_cron( cron )\n"
+ ;
+}
+
+const char* DefsDoc::add_late_doc()
+{
+ return
+ "Add a :term:`late` attribute\n\n"
+ "\nException:\n\n"
+ "- Throws a RuntimeError if more than one late is added\n"
+ "\nUsage::\n\n"
+ " late = Late()\n"
+ " late.submitted( 20,10 ) # hour,minute\n"
+ " late.active( 20,10 ) # hour,minute\n"
+ " late.complete( 20,10,True) # hour,minute,relative\n"
+ " t1 = Task(\"t1\")\n"
+ " t1.add_late( late )\n"
+ ;
+}
+
+const char* DefsDoc::add_autocancel_doc()
+{
+ return
+ "Add a :term:`autocancel` attribute.\n\n"
+ "This will delete the node on completion. The deletion may be delayed by\n"
+ "an amount of time in hours and minutes or expressed as days\n"
+ "Node deletion is not immediate. The nodes are checked once a minute\n"
+ "and expired auto cancel nodes are deleted\n"
+ "A node may only have one auto cancel attribute\n"
+ "\nException:\n\n"
+ "- Throws a RuntimeError if more than one auto cancel is added\n"
+ "\nUsage::\n\n"
+ " t1 = Task('t1')\n"
+ " t1.add_autocancel( Autocancel(20,10,False) ) # hour,min, relative\n"
+ " t2 = Task('t2')\n"
+ " t2.add_autocancel( 3 ) # 3 days \n"
+ " t3 = Task('t3')\n"
+ " t3.add_autocancel( 20,10,True ) # hour,minutes,relative \n"
+ " t4 = Task('t4')\n"
+ " t4.add_autocancel( TimeSlot(20,10),True ) # hour,minutes,relative \n"
+ ;
+}
+
+const char* DefsDoc::add_verify_doc()
+{
+ return
+ "Add a Verify attribute.\n\n"
+ "For DEBUG/test used to assert that a particular state was reached."
+ ;
+}
+
+const char* DefsDoc::add_repeat_date_doc()
+{
+ return
+ "Add a RepeatDate attribute.\n\n"
+ "A node can only have one repeat\n"
+ "\nException:\n\n"
+ "- Throws a RuntimeError if more than one repeat is added\n"
+ "\nUsage::\n\n"
+ " t1 = Task('t1')\n"
+ " t1.add_repeat( RepeatDate(\"testDate\",20100111,20100115) )\n"
+ ;
+}
+
+const char* DefsDoc::add_repeat_integer_doc()
+{
+ return
+ "Add a RepeatInteger attribute.\n\n"
+ "A node can only have one :term:`repeat`\n"
+ "\nException:\n\n"
+ "- Throws a RuntimeError if more than one repeat is added\n"
+ "\nUsage::\n\n"
+ " t1 = Task('t1')\n"
+ " t1.add_repeat( RepeatInteger(\"testInteger\",0,100,2) )\n"
+ ;
+}
+
+const char* DefsDoc::add_repeat_string_doc()
+{
+ return
+ "Add a RepeatString attribute.\n\n"
+ "A node can only have one :term:`repeat`\n"
+ "\nException:\n\n"
+ "- Throws a RuntimeError if more than one repeat is added\n"
+ "\nUsage::\n\n"
+ " t1 = Task('t1')\n"
+ " t1.add_repeat( RepeatString(\"test_string\",['a', 'b', 'c' ] ) )\n"
+ ;
+}
+
+const char* DefsDoc::add_repeat_enumerated_doc()
+{
+ return
+ "Add a RepeatEnumerated attribute.\n\n"
+ "A node can only have one :term:`repeat`\n"
+ "\nException:\n\n"
+ "- Throws a RuntimeError if more than one repeat is added\n"
+ "\nUsage::\n\n"
+ " t1 = Task('t1')\n"
+ " t1.add_repeat( RepeatEnumerated(\"test_string\", ['red', 'green', 'blue' ] ) )\n"
+ ;
+}
+
+const char* DefsDoc::add_repeat_day_doc()
+{
+ return
+ "Add a RepeatDay attribute.\n\n"
+ "A node can only have one :term:`repeat`\n"
+ "\nException:\n\n"
+ "- Throws a RuntimeError if more than one repeat is added\n"
+ ;
+}
+
+const char* DefsDoc::add_defstatus_doc()
+{
+ return
+ "Set the default status( :term:`defstatus` ) of node at begin or re queue\n\n"
+ "A :term:`defstatus` is useful in preventing suites from running automatically\n"
+ "once begun, or in setting Task's complete so they can be run selectively\n"
+ "\nUsage::\n\n"
+ " t1 = Task('t1')\n"
+ " t1.add_defstatus( DState.suspended )\n"
+ ;
+}
+
+const char* DefsDoc::jobgenctrl_doc()
+{
+ return
+ "The class JobCreationCtrl is used in :term:`job creation` checking\n\n"
+ "Constructor::\n\n"
+ " JobCreationCtrl()\n\n"
+ "\nUsage::\n\n"
+ " defs = Defs('my.def') # specify the definition we want to check, load into memory\n"
+ " job_ctrl = JobCreationCtrl()\n"
+ " job_ctrl.set_node_path('/suite/to_check') # will hierarchically check job creation under this node\n"
+ " defs.check_job_creation(job_ctrl) # job files generated to ECF_JOB\n"
+ " print job_ctrl.get_error_msg() # report any errors in job generation\n"
+ "\n"
+ " job_ctrl = JobCreationCtrl() # no set_node_path() hence check job creation for all tasks\n"
+ " job_ctrl.set_dir_for_job_creation(tmp) # generate jobs file under this directory\n"
+ " defs.check_job_creation(job_ctrl)\n"
+ " print job_ctrl.get_error_msg()\n"
+ "\n"
+ " job_ctrl = JobCreationCtrl() # no set_node_path() hence check job creation for all tasks\n"
+ " job_ctrl.generate_temp_dir() # automatically generate directory for job file\n"
+ " defs.check_job_creation(job_ctrl)\n"
+ " print job_ctrl.get_error_msg()\n"
+ ;
+}
+
+const char* DefsDoc::check_job_creation_doc()
+{
+ return
+ "Check :term:`job creation` .\n\n"
+ "Will check the following:\n\n"
+ "- :term:`ecf script` files and includes files can be located\n"
+ "- recursive includes\n"
+ "- manual and comments :term:`pre-processing`\n"
+ "- :term:`variable substitution`\n\n"
+ "Some :term:`task` s are dummy tasks have no associated :term:`ecf script` file.\n"
+ "To disable error message for these tasks please add a variable called ECF_DUMMY_TASK to them.\n"
+ "Checking is done in conjunction with the class :py:class:`ecflow.JobCreationCtrl`.\n"
+ "If no node path is set on class JobCreationCtrl then all tasks are checked.\n"
+ "In the case where we want to check all tasks, use the convenience function that take no arguments.\n"
+ "\nUsage::\n\n"
+ " defs = Defs('my.def') # specify the defs we want to check, load into memory\n"
+ " ...\n"
+ " print defs.check_job_creation() # Check job generation for all tasks\n"
+ " ...\n"
+ " job_ctrl = JobCreationCtrl()\n"
+ " defs.check_job_creation(job_ctrl) # Check job generation for all tasks, same as above\n"
+ " print job_ctrl.get_error_msg()\n"
+ " ...\n"
+ " job_ctrl = JobCreationCtrl()\n"
+ " job_ctrl.set_node_path('/suite/to_check') # will hierarchically check job creation under this node\n"
+ " defs.check_job_creation(job_ctrl) # job files generated to ECF_JOB\n"
+ " print job_ctrl.get_error_msg()\n"
+ " ...\n"
+ " job_ctrl = JobCreationCtrl() # no set_node_path() hence check job creation for all tasks\n"
+ " job_ctrl.set_dir_for_job_creation(tmp) # generate jobs file under this directory\n"
+ " defs.check_job_creation(job_ctrl)\n"
+ " print job_ctrl.get_error_msg()\n"
+ " ...\n"
+ " job_ctrl = JobCreationCtrl() # no set_node_path() hence check job creation for all tasks\n"
+ " job_ctrl.generate_temp_dir() # automatically generate directory for job file\n"
+ " defs.check_job_creation(job_ctrl)\n"
+ " print job_ctrl.get_error_msg()\n"
+ ;
+}
+
+const char* DefsDoc::generate_scripts_doc()
+{
+ return
+ "Automatically generate template :term:`ecf script` s for this definition\n"
+ "Will automatically add :term:`child command` s for :term:`event`, :term:`meter` and :term:`label` s.\n"
+ "This allows the definition to be refined with out worrying about the scripts.\n"
+ "However it should be noted that, this will create a lot of *duplicated* script contents\n"
+ "i.e in the absence of :term:`event` s, :term:`meter` s and :term:`label` s, most of generated :term:`ecf script` files will\n"
+ "be the same. Hence should only be used an aid to debugging the definition.\n"
+ "It uses the contents of the definition to parameterise what gets\n"
+ "generated, and the location of the files. Will throw Exceptions for errors.\n"
+ "\nRequires:\n\n"
+ "- ECF_HOME: specified and accessible for all Tasks, otherwise RuntimeError is raised\n"
+ "- ECF_INCLUDE: specifies location for head.h and tail.h includes, will use angle brackets,\n"
+ " i.e %include <head.h>, if the head.h and tail.h already exist they are used otherwise\n"
+ " they are generated\n"
+ "\nOptional:\n\n"
+ "- ECF_FILES: If specified, then scripts are generated under this directory otherwise ECF_HOME is used.\n"
+ " The missing directories are automatically created.\n"
+ "- ECF_CLIENT_EXE_PATH: if specified child command will use this, otherwise will use ecflow_client\n"
+ " and assume this accessible on the path.\n"
+ "- ECF_DUMMY_TASK: Will not generated scripts for this task.\n"
+ "- SLEEP: Uses this variable to delay time between calls to child commands, if not specified uses delay of one second\n\n"
+ "\nUsage::\n\n"
+ " defs = ecflow.Defs()\n"
+ " suite = defs.add_suite('s1')\n"
+ " suite.add_variable(\"ECF_HOME\",\"/user/var/home\")\n"
+ " suite.add_variable(\"ECF_INCLUDE\",\"/user/var/home/includes\")\n"
+ " for i in range(1,7) :\n"
+ " fam = suite.add_family(\"f\" + str(i))\n"
+ " for t in ( \"a\", \"b\", \"c\", \"d\", \"e\" ) :\n"
+ " fam.add_task(t);\n"
+ " defs.generate_scripts() # generate '.ecf' and head.h/tail.h if required\n"
+ ;
+}
+
+const char* DefsDoc::check()
+{
+ return
+ "Check :term:`trigger` and :term:`complete expression` s and :term:`limit` s\n\n"
+ "* Client Side: The client side can specify externs. Hence all node path references\n"
+ " in :term:`trigger` expressions, and :term:`inlimit` references to :term:`limit` s, that are\n"
+ " unresolved and which do *not* appear in :term:`extern` s are reported as errors\n"
+ "* Server Side: The server does not store externs. Hence all unresolved references\n"
+ " are reported as errors\n\n"
+ "Returns a non empty string for any errors or warning\n"
+ "\nUsage::\n\n"
+ " # Client side\n"
+ " defs = Defs('my.def') # Load my.def from disk\n"
+ " ....\n"
+ " print defs.check() # do the check\n"
+ "\n"
+ " # Server Side\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " print ci.check('/suite')\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
+
+const char* DefsDoc::simulate()
+{
+ return
+ "Simulates a :term:`suite definition` for 1 year:\n\n"
+ "Will disable infinite repeats at the suite level. i.e repeat day\n"
+ "This allows simulation to progress faster.\n"
+ "By default will run simulation for a year. If the simulation does not complete\n"
+ "creates .flat and .depth files. This provides clues as to the state of the definition\n"
+ "at the end of the simulation\n"
+ "\nUsage::\n\n"
+ " defs = Defs('my.def') # specify the defs we want to simulate\n"
+ " ....\n"
+ " theResults = defs.simulate()\n"
+ " print theResults\n"
+ ;
+}
+
+
+const char* DefsDoc::get_server_state()
+{
+ return
+ "Returns the :term:`ecflow_server` state: See :term:`server states`\n\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
+ " ci.shutdown_server()\n"
+ " ci.sync_local()\n"
+ " assert ci.get_defs().get_server_state() == SState.SHUTDOWN, \"Expected server to be shutdown\"\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n"
+ ;
+}
diff --git a/Pyext/src/DefsDoc.hpp b/Pyext/src/DefsDoc.hpp
new file mode 100644
index 0000000..56dc881
--- /dev/null
+++ b/Pyext/src/DefsDoc.hpp
@@ -0,0 +1,71 @@
+#ifndef DEFS_DOC_HPP_
+#define DEFS_DOC_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #18 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/noncopyable.hpp>
+
+// ===========================================================================
+// IMPORTANT: These appear as python doc strings.
+// Additionally they are auto documented using sphinx-poco
+// Hence the doc strings use reStructuredText markup.
+// ===========================================================================
+class DefsDoc : private boost::noncopyable {
+public:
+ static const char* abs_node_path_doc();
+ static const char* part_expression_doc();
+ static const char* expression_doc();
+ static const char* add_trigger_doc();
+ static const char* add_variable_doc();
+ static const char* add_label_doc();
+ static const char* add_limit_doc();
+ static const char* add_inlimit_doc();
+ static const char* node_doc();
+ static const char* node_container_doc();
+ static const char* submittable_doc();
+ static const char* task_doc();
+ static const char* alias_doc();
+ static const char* family_doc();
+ static const char* add_suite_doc();
+ static const char* add_extern_doc();
+ static const char* add_family_doc();
+ static const char* add_task_doc();
+ static const char* suite_doc();
+ static const char* add_definition_doc();
+ static const char* add_event_doc();
+ static const char* add_meter_doc();
+ static const char* add_date_doc();
+ static const char* add_day_doc();
+ static const char* add_today_doc();
+ static const char* add_time_doc();
+ static const char* add_cron_doc();
+ static const char* add_late_doc();
+ static const char* add_autocancel_doc();
+ static const char* add_verify_doc();
+ static const char* add_repeat_date_doc();
+ static const char* add_repeat_integer_doc();
+ static const char* add_repeat_string_doc();
+ static const char* add_repeat_enumerated_doc();
+ static const char* add_repeat_day_doc();
+ static const char* add_defstatus_doc();
+ static const char* jobgenctrl_doc();
+ static const char* check_job_creation_doc();
+ static const char* generate_scripts_doc();
+ static const char* check();
+ static const char* simulate();
+ static const char* get_server_state();
+private:
+ DefsDoc(){}
+};
+#endif
diff --git a/Pyext/src/EcfExt.cpp b/Pyext/src/EcfExt.cpp
new file mode 100644
index 0000000..263710b
--- /dev/null
+++ b/Pyext/src/EcfExt.cpp
@@ -0,0 +1,45 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #17 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/python.hpp>
+#include <boost/python/docstring_options.hpp>
+using namespace boost::python;
+
+void export_Core();
+void export_NodeAttr();
+void export_Node();
+void export_Task();
+void export_SuiteAndFamily();
+void export_Defs();
+void export_Client();
+
+// See: http://wiki.python.org/moin/boost.python/HowTo#boost.function_objects
+BOOST_PYTHON_MODULE(ecflow)
+{
+ boost::python::docstring_options doc_options(
+ true, // show the docstrings from here
+ true, // show Python signatures.
+ false // Don't mention the C++ method signatures in the generated docstrings
+ );
+ scope().attr("__doc__") =
+ "The ecflow module provides the python bindings/api for creating definition structure and communicating with the server.";
+
+ export_Core();
+ export_NodeAttr();
+ export_Node();
+ export_Task();
+ export_SuiteAndFamily();
+ export_Defs();
+ export_Client();
+}
diff --git a/Pyext/src/ExportClient.cpp b/Pyext/src/ExportClient.cpp
new file mode 100644
index 0000000..4a6964a
--- /dev/null
+++ b/Pyext/src/ExportClient.cpp
@@ -0,0 +1,336 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #85 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/python.hpp>
+#include <boost/noncopyable.hpp>
+
+#include "ClientInvoker.hpp"
+#include "Defs.hpp"
+#include "ClientDoc.hpp"
+#include "WhyCmd.hpp"
+#include "UrlCmd.hpp"
+#include "NState.hpp"
+#include "Version.hpp"
+#include "BoostPythonUtil.hpp"
+
+using namespace boost::python;
+using namespace std;
+namespace bp = boost::python;
+
+// See: http://wiki.python.org/moin/boost.python/HowTo#boost.function_objects
+
+void set_host_port(ClientInvoker* self, const std::string& host,int port) {self->set_host_port(host,boost::lexical_cast<std::string>(port));}
+void set_host_port_1(ClientInvoker* self, const std::string& host_port){
+ // assume format <host>:<port>
+ size_t colonPos = host_port.find_first_of(':');
+ if (colonPos == string::npos) throw std::runtime_error("set_host_port: expected <host>:<port> : no ':' found in " + host_port);
+ std::string host = host_port.substr(0,colonPos);
+ std::string port = host_port.substr(colonPos+1);
+ self->set_host_port(host,port);
+}
+
+
+std::string version(ClientInvoker* self) { return ecf::Version::raw();}
+std::string server_version(ClientInvoker* self) { self->server_version(); return self->get_string();}
+
+const std::string& get_log(ClientInvoker* self) { self->getLog(); return self->get_string();}
+
+const std::string& get_file(ClientInvoker* self,
+ const std::string& absNodePath,
+ const std::string& file_type = "script",
+ const std::string& max_lines = "10000")
+{ self->file(absNodePath,file_type,max_lines); return self->get_string(); }
+
+const std::string& get_file_1(ClientInvoker* self,
+ const std::string& absNodePath,
+ const std::string& file_type = "script" )
+{ self->file(absNodePath,file_type,"10000"); return self->get_string(); }
+
+
+/// Set the CLI to enable output to standard out
+class CliSetter {
+public:
+ CliSetter(ClientInvoker* self) : _self(self) { self->set_cli(true); }
+ ~CliSetter() { _self->set_cli(false);}
+private:
+ ClientInvoker* _self;
+};
+void stats(ClientInvoker* self) { CliSetter setter(self); self->stats(); }
+void stats_reset(ClientInvoker* self) { self->stats_reset(); }
+boost::python::list suites(ClientInvoker* self) {
+ self->suites();
+ const std::vector<std::string> the_suites = self->server_reply().get_string_vec();
+ boost::python::list list;
+ size_t the_size = the_suites.size();
+ for(size_t i = 0; i < the_size; i++) list.append( the_suites[i] );
+ return list;
+}
+
+bool news_local(ClientInvoker* self) { self->news_local(); return self->get_news(); }
+
+void free_trigger_dep(ClientInvoker* self, const std::string& path) { self->freeDep(path,true /*trigger*/,false/*all*/,false/*date*/,false/*time*/); }
+void free_date_dep(ClientInvoker* self, const std::string& path) { self->freeDep(path,false/*trigger*/,false/*all*/,true /*date*/,false/*time*/); }
+void free_time_dep(ClientInvoker* self, const std::string& path) { self->freeDep(path,false/*trigger*/,false/*all*/,false/*date*/,true /*time*/); }
+void free_all_dep(ClientInvoker* self, const std::string& path) { self->freeDep(path,false/*trigger*/,true /*all*/,false/*date*/,false/*time*/); }
+void free_trigger_dep1(ClientInvoker* self,const boost::python::list& list) { std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths);self->freeDep(paths,true /*trigger*/,false/*all*/,false/*date*/,false/*time*/); }
+void free_date_dep1(ClientInvoker* self, const boost::python::list& list) { std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths);self->freeDep(paths,false/*trigger*/,false/*all*/,true /*date*/,false/*time*/); }
+void free_time_dep1(ClientInvoker* self, const boost::python::list& list) { std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths);self->freeDep(paths,false/*trigger*/,false/*all*/,false/*date*/,true /*time*/); }
+void free_all_dep1(ClientInvoker* self, const boost::python::list& list) { std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths);self->freeDep(paths,false/*trigger*/,true /*all*/,false/*date*/,false/*time*/); }
+
+void force_state(ClientInvoker* self, const std::string& path, NState::State state) { self->force(path,NState::toString(state),false);}
+void force_states(ClientInvoker* self, const boost::python::list& list, NState::State state){ std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths);self->force(paths,NState::toString(state),false);}
+void force_state_recursive(ClientInvoker* self, const std::string& path, NState::State state) { self->force(path,NState::toString(state),true);}
+void force_states_recursive(ClientInvoker* self,const boost::python::list& list,NState::State state){ std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths);self->force(paths,NState::toString(state),true);}
+void force_event(ClientInvoker* self, const std::string& path, const std::string& set_or_clear) { self->force(path,set_or_clear);}
+void force_events(ClientInvoker* self,const boost::python::list& list,const std::string& set_or_clear) { std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths);self->force(paths,set_or_clear);}
+
+void run(ClientInvoker* self, const std::string& path, bool force) { self->run(path,force);}
+void runs(ClientInvoker* self,const boost::python::list& list, bool force) { std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths); self->run(paths,force);}
+void requeue(ClientInvoker* self,std::string path, const std::string& option) { self->requeue(path,option);}
+void requeues(ClientInvoker* self,const boost::python::list& list, const std::string& option) { std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths);self->requeue(paths,option);}
+void suspend(ClientInvoker* self, const std::string& path) { self->suspend(path);}
+void suspends(ClientInvoker* self,const boost::python::list& list) { std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths);self->suspend(paths);}
+void resume(ClientInvoker* self, const std::string& path) { self->resume(path);}
+void resumes(ClientInvoker* self,const boost::python::list& list) { std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths);self->resume(paths);}
+void status(ClientInvoker* self, const std::string& path) { self->status(path);}
+void statuss(ClientInvoker* self,const boost::python::list& list) { std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths);self->status(paths);}
+void do_kill(ClientInvoker* self, const std::string& path) { self->kill(path);}
+void do_kills(ClientInvoker* self,const boost::python::list& list) { std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths);self->kill(paths);}
+const std::string& check(ClientInvoker* self, const std::string& node_path) { self->check(node_path); return self->get_string(); }
+const std::string& checks(ClientInvoker* self, const boost::python::list& list) { std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths);self->check(paths); return self->get_string(); }
+
+void delete_node(ClientInvoker* self,const boost::python::list& list, bool force) { std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths);self->delete_nodes(paths,force);}
+
+void ch_suites(ClientInvoker* self){ CliSetter cli(self);self->ch_suites();}
+void ch_register(ClientInvoker* self,bool auto_add_new_suites,const boost::python::list& list)
+{std::vector<std::string> suites;BoostPythonUtil::list_to_str_vec(list,suites); self->ch_register(auto_add_new_suites,suites);}
+
+void ch_add(ClientInvoker* self,int client_handle,const boost::python::list& list)
+{std::vector<std::string> suites;BoostPythonUtil::list_to_str_vec(list,suites); self->ch_add(client_handle,suites);}
+void ch1_add(ClientInvoker* self,const boost::python::list& list)
+{std::vector<std::string> suites;BoostPythonUtil::list_to_str_vec(list,suites); self->ch1_add(suites);}
+
+void ch_remove(ClientInvoker* self,int client_handle,const boost::python::list& list)
+{std::vector<std::string> suites;BoostPythonUtil::list_to_str_vec(list,suites); self->ch_remove(client_handle,suites);}
+void ch1_remove(ClientInvoker* self,const boost::python::list& list)
+{std::vector<std::string> suites;BoostPythonUtil::list_to_str_vec(list,suites); self->ch1_remove(suites);}
+
+/// Need to provide override since the boolean argument is optional.
+/// This saves on client python code, on having to specify the optional arg
+void replace_1(ClientInvoker* self,const std::string& absNodePath, defs_ptr client_defs) { self->replace_1(absNodePath,client_defs);}
+void replace_2(ClientInvoker* self,const std::string& absNodePath, const std::string& path_to_client_defs) { self->replace(absNodePath,path_to_client_defs);}
+
+void order(ClientInvoker* self,const std::string& absNodePath,const std::string& the_order){ self->order(absNodePath,the_order);}
+
+void alters(ClientInvoker* self,
+ const boost::python::list& list,
+ const std::string& alterType, /* one of [ add | change | delete | set_flag | clear_flag ] */
+ const std::string& attrType,
+ const std::string& name = "",
+ const std::string& value = "") { std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths);self->check(paths);self->alter(paths,alterType,attrType,name,value); }
+void alter(ClientInvoker* self,
+ const std::string& path,
+ const std::string& alterType, /* one of [ add | change | delete | set_flag | clear_flag ] */
+ const std::string& attrType,
+ const std::string& name = "",
+ const std::string& value = "") { self->alter(path,alterType,attrType,name,value); }
+
+void set_child_pid(ClientInvoker* self,int pid) { self->set_child_pid( boost::lexical_cast<std::string>(pid)); }
+
+
+void export_Client()
+{
+ class_<ClientInvoker, boost::noncopyable >("Client",ClientDoc::class_client())
+ .def( init<std::string>() /* host:port */)
+ .def( init<std::string,std::string>() /* host, port */)
+ .def( init<std::string,int>() /* host, port(int) */)
+ .def("version", &version, "Returns the current client version")
+ .def("server_version", &server_version, "Returns the server version, can throw for old servers, that did not implement this request.")
+ .def("set_host_port", &ClientInvoker::set_host_port, ClientDoc::set_host_port())
+ .def("set_host_port", &set_host_port )
+ .def("set_host_port", &set_host_port_1 )
+ .def("get_host", &ClientInvoker::host, return_value_policy<copy_const_reference>(), "Return the host, assume set_host_port() has been set, otherwise return localhost" )
+ .def("get_port", &ClientInvoker::port, return_value_policy<copy_const_reference>(), "Return the port, assume set_host_port() has been set. otherwise returns 3141" )
+ .def("set_retry_connection_period",&ClientInvoker::set_retry_connection_period, ClientDoc::set_retry_connection_period())
+ .def("set_connection_attempts",&ClientInvoker::set_connection_attempts, ClientDoc::set_connection_attempts())
+ .def("get_defs", &ClientInvoker::defs, ClientDoc::get_defs())
+ .def("in_sync", &ClientInvoker::in_sync, ClientDoc::in_sync())
+#ifdef DEBUG
+ .def("get_log" , &get_log, return_value_policy<copy_const_reference>(),ClientDoc::get_log())
+#endif
+ .def("new_log", &ClientInvoker::new_log, (bp::arg("path")=""),ClientDoc::new_log())
+ .def("clear_log", &ClientInvoker::clearLog, ClientDoc::clear_log())
+ .def("flush_log", &ClientInvoker::flushLog, ClientDoc::flush_log())
+ .def("log_msg", &ClientInvoker::logMsg, ClientDoc::log_msg())
+ .def("restart_server", &ClientInvoker::restartServer, ClientDoc::restart_server())
+ .def("halt_server", &ClientInvoker::haltServer, ClientDoc::halt_server())
+ .def("shutdown_server", &ClientInvoker::shutdownServer, ClientDoc::shutdown_server())
+ .def("terminate_server", &ClientInvoker::terminateServer, ClientDoc::terminate_server())
+ .def("wait_for_server_reply",&ClientInvoker::wait_for_server_reply,(bp::arg("time_out")=60), ClientDoc::wait_for_server_reply())
+ .def("load" , &ClientInvoker::loadDefs,(bp::arg("path_to_defs"), bp::arg("force")=false,bp::arg("check_only")=false),ClientDoc::load_defs())
+ .def("load" , &ClientInvoker::load,(bp::arg("defs"), bp::arg("force")=false),ClientDoc::load())
+ .def("get_server_defs", &ClientInvoker::getDefs, ClientDoc::get_server_defs())
+ .def("sync_local", &ClientInvoker::sync_local, ClientDoc::sync())
+ .def("news_local", &news_local, ClientDoc::news())
+ .add_property("changed_node_paths",boost::python::range( &ClientInvoker::changed_node_paths_begin, &ClientInvoker::changed_node_paths_end),ClientDoc::changed_node_paths())
+ .def("suites" , &suites, ClientDoc::suites())
+ .def("ch_register", &ch_register, ClientDoc::ch_register())
+ .def("ch_suites", &ch_suites, ClientDoc::ch_suites())
+ .def("ch_handle", &ClientInvoker::client_handle, ClientDoc::ch_register())
+ .def("ch_drop", &ClientInvoker::ch_drop, ClientDoc::ch_drop())
+ .def("ch_drop", &ClientInvoker::ch1_drop)
+ .def("ch_drop_user", &ClientInvoker::ch_drop_user, ClientDoc::ch_drop_user())
+ .def("ch_add", &ch_add, ClientDoc::ch_add())
+ .def("ch_add", &ch1_add )
+ .def("ch_remove", &ch_remove, ClientDoc::ch_remove())
+ .def("ch_remove", &ch1_remove)
+ .def("ch_auto_add", &ClientInvoker::ch_auto_add, ClientDoc::ch_auto_add())
+ .def("ch_auto_add", &ClientInvoker::ch1_auto_add)
+ .def("checkpt", &ClientInvoker::checkPtDefs, (bp::arg("mode")=ecf::CheckPt::UNDEFINED, bp::arg("check_pt_interval")=0,bp::arg("check_pt_save_alarm_time")=0), ClientDoc::checkpt())
+ .def("restore_from_checkpt",&ClientInvoker::restoreDefsFromCheckPt,ClientDoc::restore_from_checkpt())
+ .def("reload_wl_file" , &ClientInvoker::reloadwsfile, ClientDoc::reload_wl_file())
+ .def("requeue" , &requeue, (bp::arg("abs_node_path"), bp::arg("option")=""), ClientDoc::requeue())
+ .def("requeue" , &requeues, (bp::arg("paths"), bp::arg("option")="") )
+ .def("free_trigger_dep", &free_trigger_dep, ClientDoc::free_trigger_dep())
+ .def("free_trigger_dep", &free_trigger_dep1 )
+ .def("free_date_dep", &free_date_dep, ClientDoc::free_date_dep())
+ .def("free_date_dep", &free_date_dep1 )
+ .def("free_time_dep", &free_time_dep, ClientDoc::free_time_dep())
+ .def("free_time_dep", &free_time_dep1)
+ .def("free_all_dep", &free_all_dep, ClientDoc::free_all_dep())
+ .def("free_all_dep", &free_all_dep1)
+ .def("ping" , &ClientInvoker::pingServer, ClientDoc::ping())
+ .def("stats" , &stats, ClientDoc::stats())
+ .def("stats_reset" , &stats_reset, ClientDoc::stats_reset())
+ .def("get_file" , &get_file, return_value_policy<copy_const_reference>(), ClientDoc::get_file())
+ .def("get_file" , &get_file_1, return_value_policy<copy_const_reference>())
+ .def("plug" , &ClientInvoker::plug, ClientDoc::plug())
+ .def("alter" , &alters,(bp::arg("paths"),bp::arg("alter_type"),bp::arg("attribute_type"),bp::arg("name")="",bp::arg("value")=""), ClientDoc::alter())
+ .def("alter" , &alter,(bp::arg("abs_node_path"),bp::arg("alter_type"),bp::arg("attribute_type"),bp::arg("name")="",bp::arg("value")=""))
+ .def("force_event" , &force_event, ClientDoc::force_event())
+ .def("force_event" , &force_events)
+ .def("force_state" , &force_state, ClientDoc::force_state())
+ .def("force_state" , &force_states)
+ .def("force_state_recursive",&force_state_recursive, ClientDoc::force_state_recursive())
+ .def("force_state_recursive",&force_states_recursive)
+ .def("replace" , &ClientInvoker::replace, ClientDoc::replace())
+ .def("replace" , &ClientInvoker::replace_1)
+ .def("replace" , &replace_1 )
+ .def("replace" , &replace_2 )
+ .def("order" , &order, ClientDoc::order())
+ .def("group" , &ClientInvoker::group, ClientDoc::group())
+ .def("begin_suite" , &ClientInvoker::begin, (bp::arg("suite_name"),bp::arg("force")=false), ClientDoc::begin_suite())
+ .def("begin_all_suites", &ClientInvoker::begin_all_suites,(bp::arg("force")=false), ClientDoc::begin_all())
+ .def("job_generation", &ClientInvoker::job_gen, ClientDoc::job_gen())
+ .def("run" , &run, ClientDoc::run())
+ .def("run" , &runs)
+ .def("check" , &check, return_value_policy<copy_const_reference>(), ClientDoc::check())
+ .def("check" , &checks, return_value_policy<copy_const_reference>())
+ .def("kill" , &do_kill, ClientDoc::kill())
+ .def("kill" , &do_kills)
+ .def("status" , &status, ClientDoc::status())
+ .def("status" , &statuss)
+ .def("suspend" , &suspend, ClientDoc::suspend())
+ .def("suspend" , &suspends)
+ .def("resume" , &resume, ClientDoc::resume())
+ .def("resume" , &resumes)
+ .def("delete" , &ClientInvoker::delete_node, (bp::arg("abs_node_path"),bp::arg("force")=false), ClientDoc::delete_node())
+ .def("delete" , &delete_node, (bp::arg("paths"),bp::arg("force")=false))
+ .def("delete_all", &ClientInvoker::delete_all, (bp::arg("force")=false), ClientDoc::delete_all())
+ .def("debug_server_on", &ClientInvoker::debug_server_on, "Enable server debug, Will dump to standard out on server host.")
+ .def("debug_server_off", &ClientInvoker::debug_server_off, "Disable server debug")
+
+ .def("zombie_fob", &ClientInvoker::zombieFobCli )
+ .def("zombie_fail", &ClientInvoker::zombieFailCli )
+ .def("zombie_adopt", &ClientInvoker::zombieAdoptCli )
+ .def("zombie_block", &ClientInvoker::zombieBlockCli )
+ .def("zombie_remove", &ClientInvoker::zombieRemoveCli )
+ .def("zombie_kill", &ClientInvoker::zombieKillCli )
+
+ .def("set_child_path", &ClientInvoker::set_child_path , "Set the path to the task, obtained from server using %ECF_NAME%")
+ .def("set_child_password", &ClientInvoker::set_child_password,"Set the password, needed for authentication, provided by the server using %ECF_PASS%")
+ .def("set_child_pid", &ClientInvoker::set_child_pid, "Set the process id of this job" )
+ .def("set_child_pid", &set_child_pid, "Set the process id of this job" )
+ .def("set_child_try_no", &ClientInvoker::set_child_try_no, "Set the try no, i.e the number of times this job has run, obtained from the server, using %ECF_TRYNO%")
+ .def("set_child_timeout", &ClientInvoker::set_child_timeout, "Set timeout if child can not connect to server, default is 24 hours. The input is required to be in seconds")
+ .def("child_init", &ClientInvoker::child_init, "Child command,notify server job has started")
+ .def("child_abort", &ClientInvoker::child_abort, (bp::arg("reason")=""), "Child command,notify server job has aborted, can provide an optional reason")
+ .def("child_event", &ClientInvoker::child_event, "Child command,notify server event occurred, requires the event name")
+ .def("child_meter", &ClientInvoker::child_meter, "Child command,notify server meter changed, requires meter name and value")
+ .def("child_label", &ClientInvoker::child_label, "Child command,notify server label changed, requires label name, and new value")
+ .def("child_wait", &ClientInvoker::child_wait, "Child command,wait for expression to come true")
+ .def("child_complete", &ClientInvoker::child_complete,"Child command,notify server job has complete")
+ ;
+
+ class_<WhyCmd, boost::noncopyable >( "WhyCmd",
+ "The why command reports, the reason why a node is not running.\n\n"
+ "It needs the definition structure and the path to node\n"
+ "\nConstructor::\n\n"
+ " WhyCmd(defs, node_path)\n"
+ " defs_ptr defs : pointer to a definition structure\n"
+ " string node_path : The node path\n\n"
+ "\nExceptions:\n\n"
+ "- raises RuntimeError if the definition is empty\n"
+ "- raises RuntimeError if the node path is empty\n"
+ "- raises RuntimeError if the node path can not be found in the definition\n"
+ "\nUsage::\n\n"
+ " try:\n"
+ " ci = Client()\n"
+ " ci.sync_local()\n"
+ " ask = WhyCmd(ci.get_defs(),'/suite/family')\n"
+ " print ask.why()\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n\n"
+ ,
+ init<defs_ptr,std::string >()
+ )
+ .def("why", &WhyCmd::why, "returns a '/n' separated string, with reasons why node is not running")
+ ;
+
+ class_<UrlCmd, boost::noncopyable >( "UrlCmd",
+ "Executes a command ECF_URL_CMD to display a url.\n\n"
+ "It needs the definition structure and the path to node.\n"
+ "\nConstructor::\n\n"
+ " UrlCmd(defs, node_path)\n"
+ " defs_ptr defs : pointer to a definition structure\n"
+ " string node_path : The node path.\n\n"
+ "\nExceptions\n\n"
+ "- raises RuntimeError if the definition is empty\n"
+ "- raises RuntimeError if the node path is empty\n"
+ "- raises RuntimeError if the node path can not be found in the definition\n"
+ "- raises RuntimeError if ECF_URL_CMD not defined or if variable substitution fails\n"
+ "\nUsage:\n"
+ "Lets assume that the server has the following definition::\n\n"
+ " suite s\n"
+ " edit ECF_URL_CMD \"${BROWSER:=firefox} -remote 'openURL(%ECF_URL_BASE%/%ECF_URL%)'\"\n"
+ " edit ECF_URL_BASE \"http://www.ecmwf.int\"\n"
+ " family f\n"
+ " task t1\n"
+ " edit ECF_URL \"publications/manuals/ecflow\"\n"
+ " task t2\n"
+ " edit ECF_URL index.html\n\n"
+ "::\n\n"
+ " try:\n"
+ " ci = Client()\n"
+ " ci.sync_local()\n"
+ " url = UrlCmd(ci.get_defs(),'/suite/family/task')\n"
+ " print url.execute()\n"
+ " except RuntimeError, e:\n"
+ " print str(e)\n\n"
+ ,
+ init<defs_ptr,std::string >()
+ )
+ .def("execute", &UrlCmd::execute, "Displays url in the chosen browser")
+ ;
+}
diff --git a/Pyext/src/ExportCore.cpp b/Pyext/src/ExportCore.cpp
new file mode 100644
index 0000000..4175041
--- /dev/null
+++ b/Pyext/src/ExportCore.cpp
@@ -0,0 +1,246 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #33 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/python.hpp>
+#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
+#include <boost/noncopyable.hpp>
+#include "PrintStyle.hpp"
+#include "DState.hpp"
+#include "SState.hpp"
+#include "File.hpp"
+#include "TimeSlot.hpp"
+#include "TimeSeries.hpp"
+#include "CheckPt.hpp"
+#include "Ecf.hpp"
+
+// See: http://wiki.python.org/moin/boost.python/HowTo#boost.function_objects
+template<class K, class T>
+ struct pair_to_tuple {
+ typedef pair_to_tuple<K,T> converter;
+ typedef std::pair<K,T> ctype;
+
+ static PyObject* convert(ctype const& v) {
+ using namespace boost::python;
+ return incref(make_tuple(v.first,v.second).ptr());
+ }
+ static void register_to_python() {
+ boost::python::to_python_converter<ctype,converter>();
+ }
+};
+
+using namespace boost::python;
+using namespace std;
+using namespace ecf;
+
+bool debug_build()
+{
+#ifdef NDEBUG
+ return false;
+#else
+ return true;
+#endif
+}
+
+void export_Core()
+{
+ // For use in test only
+ def("debug_build",debug_build);
+
+ class_<File, boost::noncopyable >("File", "Utility class, Used in test only.")
+ .def("find_server", &File::find_ecf_server_path, "Provides pathname to the server") .staticmethod("find_server")
+ .def("find_client", &File::find_ecf_client_path, "Provides pathname to the client") .staticmethod("find_client")
+ ;
+
+ enum_<PrintStyle::Type_t>("Style",
+ "Style is used to control printing output for the definition\n\n"
+ "- DEFS: This style outputs the definition file in a format that is parse-able.\n"
+ " and can be re-loaded back into the server.\n"
+ " Externs are automatically added.\n"
+ " This excludes the edit history.\n"
+ "- STATE: The output includes additional state information for debug\n"
+ " This excludes the edit history\n"
+ "- MIGRATE: Output includes structure and state, allow migration to future ecflow versions\n"
+ " This includes edit history. If file is reloaded no checking is done\n\n"
+ "The following shows a summary of the features associated with each choice\n"
+ "\n"
+ " ===================== ==== ===== =======\n"
+ " Functionality DEFS STATE MIGRATE\n"
+ " ===================== ==== ===== =======\n"
+ " Auto generate externs Yes Yes No\n"
+ " Checking on reload Yes Yes No\n"
+ " Edit History No No Yes\n"
+ " Show trigger AST No Yes No\n"
+ " ===================== ==== ===== =======\n"
+ )
+ .value("NOTHING", PrintStyle::NOTHING)
+ .value("DEFS", PrintStyle::DEFS)
+ .value("STATE", PrintStyle::STATE)
+ .value("MIGRATE", PrintStyle::MIGRATE)
+ ;
+
+ enum_<CheckPt::Mode>("CheckPt",
+ "CheckPt is enum that is used to control check pointing in the :term:`ecflow_server`\n\n"
+ "- NEVER : Switches of check pointing\n"
+ "- ON_TIME: :term:`check point` file is saved periodically, specified by checkPtInterval. This is the default.\n"
+ "- ALWAYS : :term:`check point` file is saved after any state change, *not* recommended for large definitions\n"
+ "- UNDEFINED : None of the the above, used to provide default argument\n"
+ )
+ .value("NEVER", CheckPt::NEVER)
+ .value("ON_TIME",CheckPt::ON_TIME)
+ .value("ALWAYS", CheckPt::ALWAYS)
+ .value("UNDEFINED", CheckPt::UNDEFINED)
+ ;
+
+
+ class_<PrintStyle, boost::noncopyable >("PrintStyle",
+ "Singleton used to control the print Style.\n\n"
+ "\nUsage::\n\n"
+ " style = PrintStyle.get_style()\n"
+ ,
+ no_init)
+ .def("get_style", &PrintStyle::getStyle,"Returns the style, static method")
+ .staticmethod("get_style")
+ .def("set_style", &PrintStyle::setStyle,"Set the style, static method")
+ .staticmethod("set_style")
+ ;
+
+ class_<Ecf, boost::noncopyable >("Ecf",
+ "Singleton used to control ecf debugging\n\n",
+ no_init)
+ .def("debug_equality", &Ecf::debug_equality,"Returns true if debugging of equality is enabled")
+ .staticmethod("debug_equality")
+ .def("set_debug_equality", &Ecf::set_debug_equality,"Set debugging for equality")
+ .staticmethod("set_debug_equality")
+ .def("debug_level", &Ecf::debug_level,"Returns integer showing debug level. debug_level > 0 will disable some warning messages")
+ .staticmethod("debug_level")
+ .def("set_debug_level", &Ecf::set_debug_level,"Set debug level. debug_level > 0 will disable some warning messages")
+ .staticmethod("set_debug_level")
+ ;
+
+ enum_<NState::State>("State",
+ "Each :term:`node` can have a status, which reflects the life cycle of a node.\n\n"
+ "It varies as follows:\n\n"
+ "- When the definition file is loaded into the :term:`ecflow_server` the :term:`task` status is :term:`unknown`\n"
+ "- After begin command the :term:`task` s are either :term:`queued`, :term:`complete`, :term:`aborted` or :term:`suspended` ,\n"
+ " a suspended task means that the task is really :term:`queued` but it must be resumed by\n"
+ " the user first before it can be :term:`submitted`. See :py:class:`ecflow.DState`\n"
+ "- Once the :term:`dependencies` are resolved a task is submitted and placed into the :term:`submitted` state,\n"
+ " however if the submission fails, the task is placed in a :term:`aborted` state.\n"
+ "- On a successful submission the task is placed into the :term:`active` state\n"
+ "- Before a job ends, it may send other message to the server such as:\n"
+ " Set an :term:`event`, Change a :term:`meter`, Change a :term:`label`, send a message to log file\n\n"
+ "Jobs end by becoming either :term:`complete` or :term:`aborted`"
+ )
+ .value("unknown", NState::UNKNOWN)
+ .value("complete", NState::COMPLETE)
+ .value("queued", NState::QUEUED)
+ .value("aborted", NState::ABORTED)
+ .value("submitted",NState::SUBMITTED)
+ .value("active", NState::ACTIVE)
+ ;
+
+ enum_<DState::State>("DState",
+ "A DState is like a ecflow.State, except for the addition of SUSPENDED\n\n"
+ "Suspended stops job generation, and hence is an attribute of a Node.\n"
+ "DState can be used for setting the default state of node when it is\n"
+ "begun or re queued. DState is used for defining :term:`defstatus`. See :py:class:`ecflow.Node.add_defstatus`\n"
+ "The default state of a :term:`node` is :term:`queued`.\n"
+ "\nUsage::\n\n"
+ " task = ecflow.Task('t1')\n"
+ " task.add_defstatus(ecflow.DState.complete)"
+ )
+ .value("unknown", DState::UNKNOWN)
+ .value("complete", DState::COMPLETE)
+ .value("queued", DState::QUEUED)
+ .value("aborted", DState::ABORTED)
+ .value("submitted",DState::SUBMITTED)
+ .value("suspended",DState::SUSPENDED)
+ .value("active", DState::ACTIVE)
+ ;
+
+ enum_<SState::State>("SState",
+ "A SState holds the :term:`ecflow_server` state\n\n"
+ "See :term:`server states`"
+ )
+ .value("HALTED", SState::HALTED)
+ .value("SHUTDOWN", SState::SHUTDOWN)
+ .value("RUNNING", SState::RUNNING)
+ ;
+
+
+ class_<TimeSlot>("TimeSlot",
+ "Represents a time slot.\n\n"
+ "It is typically used as an argument to a TimeSeries or\n"
+ "other time dependent attributes of a node.\n"
+ "\n"
+ "\nConstructor::\n\n"
+ " TimeSlot(hour,min)\n"
+ " int hour: represent an hour:\n"
+ " int minute: represents a minute:\n"
+ "\nUsage::\n\n"
+ " ts = TimeSlot(10,11)\n"
+ ,
+ init<int,int>()
+ )
+ .def("__str__", &TimeSlot::toString) // __str__
+ .def(self == self ) // __eq__
+ .def("hour", &TimeSlot::hour) // return int
+ .def("minute", &TimeSlot::minute) // return int
+ .def("empty", &TimeSlot::isNULL) // return bool
+ ;
+
+ // single slot, | start, finish, incr, bool relative to suite start
+ class_<TimeSeries>("TimeSeries",
+ "A TimeSeries can hold a single time slot or a series.\n\n"
+ "Time series can be created relative to the :term:`suite` start or start of a repeating node.\n"
+ "A Time series can be used as argument to the :py:class:`ecflow.Time`, py:class:`ecflow.Today` and py:class:`ecflow.Cron` attributes of a node.\n"
+ "If a time the job takes to complete is longer than the interval, a 'slot' is missed\n"
+ "e.g time 10:00 20:00 01:00, if the 10.00 run takes more than an hour the 11.00 is missed\n\n"
+ "\nConstructor::\n\n"
+ " TimeSeries(single,relative_to_suite_start)\n"
+ " TimeSlot single : A single point in a 24 clock \n"
+ " optional bool relative_to_suite_start : depend on suite begin time or\n"
+ " start of repeating node. Default is false\n"
+ "\n"
+ " TimeSeries(hour,minute,relative_to_suite_start)\n"
+ " int hour : hour in 24 clock \n"
+ " int minute : minute < 59 \n"
+ " bool relative_to_suite_start<optional> : depend on suite begin time or\n"
+ " start of repeating node. Default is false\n"
+ "\n"
+ " TimeSeries(start,finish,increment,relative_to_suite_start)\n"
+ " start TimeSlot : The start time \n"
+ " finish TimeSlot : The finish time, when used in a series. This must greater than the start.\n"
+ " increment TimeSlot : The increment. This must be less that difference between start and finish\n"
+ " bool relative_to_suite_start<optional> : The time is relative suite start, or start of repeating node.\n"
+ " The default is false\n"
+ "\nExceptions:\n\n"
+ "- Raises IndexError when an invalid time series is specified\n"
+ "\nUsage::\n\n"
+ " time_series = TimeSeries(TimeSlot(10,11),False)\n" ,
+ init<TimeSlot, optional<bool> >())
+ .def( init<int,int,optional<bool> >())
+ .def( init<TimeSlot,TimeSlot,TimeSlot,optional<bool> >())
+ .def("__str__", &TimeSeries::toString) // __str__
+ .def(self == self ) // __eq__
+ .def("has_increment", &TimeSeries::hasIncrement,"distinguish between a single time slot and a series. returns true for a series") // false if single time slot
+ .def("start", &TimeSeries::start , return_value_policy<copy_const_reference>(),"returns the start time") // returns a time slot
+ .def("finish", &TimeSeries::finish, return_value_policy<copy_const_reference>(),"returns the finish time if time series specified, else returns a NULL time slot") // returns a time slot
+ .def("incr", &TimeSeries::incr, return_value_policy<copy_const_reference>()," returns the increment time if time series specified, else returns a NULL time slot") // returns a time slot
+ .def("relative", &TimeSeries::relative,"returns a boolean where true means that the time series is relative")
+ ;
+
+ using namespace boost::python;
+ pair_to_tuple<std::string,std::string>::register_to_python();
+}
diff --git a/Pyext/src/ExportDefs.cpp b/Pyext/src/ExportDefs.cpp
new file mode 100644
index 0000000..91f43c4
--- /dev/null
+++ b/Pyext/src/ExportDefs.cpp
@@ -0,0 +1,189 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #93 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/python.hpp>
+#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/make_shared.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/noncopyable.hpp>
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "PrintStyle.hpp"
+#include "File.hpp"
+#include "DefsStructureParser.hpp"
+#include "JobCreationCtrl.hpp"
+#include "Simulator.hpp"
+#include "BoostPythonUtil.hpp"
+
+#include "DefsDoc.hpp"
+
+using namespace ecf;
+using namespace boost::python;
+using namespace std;
+namespace bp = boost::python;
+
+// See: http://wiki.python.org/moin/boost.python/HowTo#boost.function_objects
+
+void save_as_defs(const Defs& theDefs, const std::string& filename, PrintStyle::Type_t the_style_enum)
+{
+ PrintStyle style(the_style_enum);
+ std::stringstream ss; ss << theDefs;
+
+ std::string file_creation_error_msg;
+ if (!File::create(filename,ss.str(),file_creation_error_msg)) {
+ std::string error = "save_as_defs failed: ";
+ error += file_creation_error_msg;
+ throw std::runtime_error(error);
+ }
+}
+
+void save_as_defs_1(const Defs& theDefs, const std::string& filename)
+{
+ save_as_defs(theDefs,filename,PrintStyle::DEFS);
+}
+
+static defs_ptr create_defs(const std::string& file_name)
+{
+ defs_ptr defs = Defs::create();
+
+ DefsStructureParser checkPtParser( defs.get(), file_name );
+ std::string errorMsg,warningMsg;
+ if (!checkPtParser.doParse(errorMsg,warningMsg)) {
+ throw std::runtime_error(errorMsg);
+ }
+ if (!warningMsg.empty()) std::cerr << warningMsg;
+ return defs;
+}
+
+std::string check_defs(defs_ptr defs)
+{
+ std::string error_msg;
+ std::string warning_msg;
+ if (defs.get() && !defs->check(error_msg,warning_msg)) {
+ error_msg += "\n";
+ error_msg += warning_msg;
+ return error_msg;
+ }
+ return warning_msg;
+}
+
+void save_as_checkpt(defs_ptr defs, const std::string& file_name)
+{
+ defs->save_as_checkpt(file_name); // use default ARCHIVE
+}
+
+void restore_from_checkpt(defs_ptr defs, const std::string& file_name)
+{
+ defs->restore_from_checkpt(file_name); // use default ARCHIVE
+}
+
+std::string simulate(defs_ptr defs)
+{
+ if (defs.get()) {
+ // name output file after name of the first suite
+ std::string defs_filename = "pyext.def";
+ if (!defs->suiteVec().empty()) {
+ defs_filename = (*defs->suiteVec().begin())->name() + ".def";
+ }
+
+ Simulator simulator;
+ std::string errorMsg;
+ if (!simulator.run(*defs, defs_filename, errorMsg)) {
+ return errorMsg;
+ }
+ }
+ return string();
+}
+
+SState::State get_server_state(defs_ptr self) { return self->server().get_state(); }
+
+/// Since we don't pass in a child pos, the nodes are added to the end
+void add_suite(defs_ptr self,suite_ptr s){ self->addSuite(s); }
+
+std::vector<task_ptr> get_all_tasks(defs_ptr self){ std::vector<task_ptr> tasks; self->get_all_tasks(tasks); return tasks; }
+std::vector<node_ptr> get_all_nodes(defs_ptr self){ std::vector<node_ptr> nodes; self->get_all_nodes(nodes); return nodes; }
+
+// Context management, Only used to provide indentation
+defs_ptr defs_enter(defs_ptr self) { return self;}
+bool defs_exit(defs_ptr self,const boost::python::object& type,const boost::python::object& value,const boost::python::object& traceback){return false;}
+
+std::string check_job_creation(defs_ptr defs)
+{
+ job_creation_ctrl_ptr jobCtrl = boost::make_shared<JobCreationCtrl>();
+ defs->check_job_creation(jobCtrl);
+ return jobCtrl->get_error_msg();
+}
+
+// Add server user variables
+defs_ptr add_variable(defs_ptr self,const std::string& name, const std::string& value) {
+ self->set_server().add_or_update_user_variables(name,value); return self;}
+defs_ptr add_variable_int(defs_ptr self,const std::string& name, int value) {
+ self->set_server().add_or_update_user_variables(name, boost::lexical_cast<std::string>(value)); return self;}
+defs_ptr add_variable_var(defs_ptr self,const Variable& var) {
+ self->set_server().add_or_update_user_variables(var.name(),var.theValue()); return self;}
+defs_ptr add_variable_dict(defs_ptr self,const boost::python::dict& dict) {
+ std::vector<std::pair<std::string,std::string> > vec;
+ BoostPythonUtil::dict_to_str_vec(dict,vec);
+ std::vector<std::pair<std::string,std::string> >::iterator i;
+ std::vector<std::pair<std::string,std::string> >::iterator vec_end = vec.end();
+ for(i = vec.begin(); i != vec_end; ++i) {
+ self->set_server().add_or_update_user_variables((*i).first,(*i).second);
+ }
+ return self;
+}
+void delete_variable(defs_ptr self,const std::string& name) { self->set_server().delete_user_variable(name);}
+
+
+void export_Defs()
+{
+ class_<Defs, boost::noncopyable, defs_ptr >( "Defs", DefsDoc::add_definition_doc() ,init<>("Create a empty Defs"))
+ .def("__init__",make_constructor(&create_defs), DefsDoc::add_definition_doc())
+ .def(self == self ) // __eq__
+ .def("__str__", &Defs::toString) // __str__
+ .def("__enter__", &defs_enter) // allow with statement, hence indentation support
+ .def("__exit__", &defs_exit) // allow with statement, hence indentation support
+ .def("add_suite", &add_suite, DefsDoc::add_suite_doc())
+ .def("add_suite", &Defs::add_suite )
+ .def("add_extern", &Defs::add_extern, DefsDoc::add_extern_doc())
+ .def("auto_add_externs", &Defs::auto_add_externs, DefsDoc::add_extern_doc())
+ .def("add_variable", &add_variable, DefsDoc::add_variable_doc())
+ .def("add_variable", &add_variable_int)
+ .def("add_variable", &add_variable_var)
+ .def("add_variable", &add_variable_dict)
+ .def("delete_variable", &delete_variable,"An empty string will delete all user variables")
+ .def("find_suite", &Defs::findSuite,"Given a name, find the corresponding :term:`suite`")
+ .def("find_abs_node", &Defs::findAbsNode,"Given a path, find the the :term:`node`")
+ .def("get_all_nodes", &get_all_nodes,"Returns all the :term:`node` s in the definition")
+ .def("get_all_tasks", &get_all_tasks,"Returns all the :term:`task` nodes")
+ .def("has_time_dependencies", &Defs::hasTimeDependencies,"returns True if the :term:`suite definition` has any time :term:`dependencies`")
+ .def("save_as_checkpt", &save_as_checkpt, "Save the in memory :term:`suite definition` as a :term:`check point` file. This includes all node state.")
+ .def("restore_from_checkpt", &restore_from_checkpt, "Restore the :term:`suite definition` from a :term:`check point` file stored on disk")
+ .def("save_as_defs", &save_as_defs, "Save the in memory :term:`suite definition` into a file. The file name must be passed as an argument\n\n")
+ .def("save_as_defs", &save_as_defs_1, "Save the in memory :term:`suite definition` into a file. The file name must be passed as an argument\n\n")
+ .def("check", &check_defs, DefsDoc::check())
+ .def("simulate", &simulate, DefsDoc::simulate())
+ .def("check_job_creation", &check_job_creation, DefsDoc::check_job_creation_doc() )
+ .def("check_job_creation", &Defs::check_job_creation)
+ .def("generate_scripts", &Defs::generate_scripts, DefsDoc::generate_scripts_doc() )
+ .def("get_state", &Defs::state )
+ .def("get_server_state", &get_server_state, DefsDoc::get_server_state() )
+ .add_property("suites", boost::python::range( &Defs::suite_begin, &Defs::suite_end),"Returns a list of :term:`suite` s")
+ .add_property("externs", boost::python::range( &Defs::extern_begin, &Defs::extern_end),"Returns a list of :term:`extern` s" )
+ .add_property("user_variables", boost::python::range( &Defs::user_variables_begin, &Defs::user_variables_end),"Returns a list of user defined :term:`variable` s" )
+ .add_property("server_variables", boost::python::range( &Defs::server_variables_begin, &Defs::server_variables_end),"Returns a list of server :term:`variable` s" )
+ ;
+}
diff --git a/Pyext/src/ExportNode.cpp b/Pyext/src/ExportNode.cpp
new file mode 100644
index 0000000..8f9fb54
--- /dev/null
+++ b/Pyext/src/ExportNode.cpp
@@ -0,0 +1,341 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #85 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/python.hpp>
+#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/make_shared.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/noncopyable.hpp>
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Task.hpp"
+#include "Expression.hpp"
+#include "JobCreationCtrl.hpp"
+#include "BoostPythonUtil.hpp"
+
+#include "DefsDoc.hpp"
+#include "NodeAttrDoc.hpp"
+
+using namespace ecf;
+using namespace boost::python;
+using namespace std;
+namespace bp = boost::python;
+
+// See: http://wiki.python.org/moin/boost.python/HowTo#boost.function_objects
+
+Defs* get_defs(node_ptr self) { return self->defs(); }
+
+node_ptr add_variable(node_ptr self,const std::string& name, const std::string& value) { self->add_variable(name,value); return self;}
+node_ptr add_variable_int(node_ptr self,const std::string& name, int value) { self->add_variable_int(name,value); return self;}
+node_ptr add_variable_var(node_ptr self,const Variable& var) { self->addVariable(var); return self;}
+node_ptr add_variable_dict(node_ptr self,const boost::python::dict& dict) {
+ std::vector<std::pair<std::string,std::string> > vec;
+ BoostPythonUtil::dict_to_str_vec(dict,vec);
+ std::vector<std::pair<std::string,std::string> >::iterator i;
+ std::vector<std::pair<std::string,std::string> >::iterator vec_end = vec.end();
+ for(i = vec.begin(); i != vec_end; ++i) {
+ self->add_variable((*i).first,(*i).second);
+ }
+ return self;
+}
+
+node_ptr add_event(node_ptr self,const Event& e) { self->addEvent(e); return self; }
+node_ptr add_event_1(node_ptr self,int number) { self->addEvent(Event(number)); return self; }
+node_ptr add_event_2(node_ptr self,int number,const std::string& name) { self->addEvent(Event(number,name)); return self; }
+node_ptr add_event_3(node_ptr self,const std::string& name) { self->addEvent(Event(name)); return self; }
+
+node_ptr add_meter(node_ptr self,const Meter& m) { self->addMeter(m); return self;}
+node_ptr add_meter_1(node_ptr self,const std::string& meter_name, int min,int max, int color_change) { self->addMeter(Meter(meter_name,min,max,color_change)); return self;}
+node_ptr add_meter_2(node_ptr self,const std::string& meter_name, int min,int max) { self->addMeter(Meter(meter_name,min,max));return self; }
+
+node_ptr add_label(node_ptr self,const std::string& name, const std::string& value) { self->addLabel(Label(name,value)); return self; }
+node_ptr add_label_1(node_ptr self,const Label& label) { self->addLabel(label); return self; }
+node_ptr add_limit(node_ptr self,const std::string& name, int limit) { self->addLimit(Limit(name,limit)); return self;}
+node_ptr add_limit_1(node_ptr self,const Limit& limit) { self->addLimit(limit); return self;}
+node_ptr add_in_limit(node_ptr self,const std::string& name,const std::string& pathToNode,int tokens) { self->addInLimit(InLimit(name,pathToNode,tokens)); return self;}
+node_ptr add_in_limit_1(node_ptr self,const InLimit& inlimit) { self->addInLimit(inlimit); return self;}
+node_ptr add_time(node_ptr self,int hour, int minute) { self->addTime(ecf::TimeAttr(hour,minute));return self; }
+node_ptr add_time_1(node_ptr self,int hour, int minute, bool relative) { self->addTime(ecf::TimeAttr(hour,minute,relative)); return self;}
+node_ptr add_time_2(node_ptr self,const std::string& ts) { self->addTime(ecf::TimeAttr(TimeSeries::create(ts)));return self;}
+node_ptr add_time_3(node_ptr self,const ecf::TimeAttr& ts) { self->addTime(ts);return self;}
+node_ptr add_today(node_ptr self,int hour, int minute) { self->addToday(ecf::TodayAttr(hour,minute)); return self;}
+node_ptr add_today_1(node_ptr self,int hour, int minute, bool relative) { self->addToday(ecf::TodayAttr(hour,minute,relative)); return self;}
+node_ptr add_today_2(node_ptr self,const std::string& ts) { self->addToday(ecf::TodayAttr(TimeSeries::create(ts)));return self;}
+node_ptr add_today_3(node_ptr self,const ecf::TodayAttr& ts) { self->addToday(ts);return self;}
+node_ptr add_date(node_ptr self,int day, int month, int year) { self->addDate(DateAttr(day,month,year)); return self;}
+node_ptr add_date_1(node_ptr self,const DateAttr& d) { self->addDate(d); return self;}
+node_ptr add_day(node_ptr self,DayAttr::Day_t day ) { self->addDay(DayAttr(day)); return self;}
+node_ptr add_day_1(node_ptr self,const std::string& day ) { self->addDay(DayAttr(DayAttr::getDay(day))); return self;}
+node_ptr add_day_2(node_ptr self,const DayAttr& day ) { self->addDay(day); return self;}
+node_ptr add_autocancel(node_ptr self,int days ) { self->addAutoCancel(ecf::AutoCancelAttr(days)); return self;}
+node_ptr add_autocancel_1(node_ptr self,int hour, int min,bool relative) { self->addAutoCancel(ecf::AutoCancelAttr(hour,min,relative)); return self;}
+node_ptr add_autocancel_2(node_ptr self,const TimeSlot& ts,bool relative){ self->addAutoCancel(ecf::AutoCancelAttr(ts,relative)); return self;}
+node_ptr add_autocancel_3(node_ptr self, const ecf::AutoCancelAttr& attr){ self->addAutoCancel(attr); return self;}
+node_ptr add_zombie(node_ptr self, const ZombieAttr& attr){ self->addZombie(attr); return self;}
+
+node_ptr add_cron(node_ptr self,const ecf::CronAttr& attr) { self->addCron(attr); return self; }
+node_ptr add_late(node_ptr self,const ecf::LateAttr& attr) { self->addLate(attr); return self; }
+std::string get_state_change_time(node_ptr self,const std::string& format)
+{
+ if (format == "iso_extended") return to_iso_extended_string(self->state_change_time());
+ else if (format == "iso") return to_iso_string(self->state_change_time());
+ return to_simple_string(self->state_change_time());
+}
+
+node_ptr add_defstatus(node_ptr self,DState::State s) { self->addDefStatus(s); return self; }
+node_ptr add_repeat_date(node_ptr self,const RepeatDate& d) { self->addRepeat(d); return self; }
+node_ptr add_repeat_integer(node_ptr self,const RepeatInteger& d) { self->addRepeat(d); return self; }
+node_ptr add_repeat_string(node_ptr self,const RepeatString& d) { self->addRepeat(d); return self; }
+node_ptr add_repeat_enum(node_ptr self,const RepeatEnumerated& d) { self->addRepeat(d); return self; }
+node_ptr add_repeat_day(node_ptr self,const RepeatDay& d) { self->addRepeat(d); return self; }
+node_ptr add_trigger(node_ptr self,const std::string& expr) { self->add_trigger(expr); return self; }
+node_ptr add_trigger_expr(node_ptr self,const Expression& expr) { self->add_trigger_expr(expr); return self; }
+node_ptr add_complete(node_ptr self,const std::string& expr) { self->add_complete(expr); return self; }
+node_ptr add_complete_expr(node_ptr self,const Expression& expr) { self->add_complete_expr(expr); return self; }
+node_ptr add_part_trigger(node_ptr self,const PartExpression& expr) { self->add_part_trigger(PartExpression(expr)); return self; }
+node_ptr add_part_trigger_1(node_ptr self,const std::string& expression) { self->add_part_trigger(PartExpression(expression)); return self;}
+node_ptr add_part_trigger_2(node_ptr self,const std::string& expression, bool and_expr) { self->add_part_trigger(PartExpression(expression,and_expr)); return self;}
+node_ptr add_part_complete(node_ptr self,const PartExpression& expr) { self->add_part_complete(PartExpression(expr)); return self; }
+node_ptr add_part_complete_1(node_ptr self,const std::string& expression) { self->add_part_complete(PartExpression(expression)); return self;}
+node_ptr add_part_complete_2(node_ptr self,const std::string& expression, bool and_expr){ self->add_part_complete(PartExpression(expression,and_expr)); return self;}
+bool evaluate_trigger(node_ptr self) { Ast* t = self->triggerAst(); if (t) return t->evaluate();return false;}
+bool evaluate_complete(node_ptr self) { Ast* t = self->completeAst(); if (t) return t->evaluate();return false;}
+
+static job_creation_ctrl_ptr makeJobCreationCtrl() { return boost::make_shared<JobCreationCtrl>();}
+
+std::vector<node_ptr> get_all_nodes(node_ptr self){ std::vector<node_ptr> nodes; self->get_all_nodes(nodes); return nodes; }
+
+void export_Node()
+{
+ enum_<Flag::Type>("FlagType",
+ "Flags store state associated with a node\n\n"
+ "FORCE_ABORT - Node* do not run when try_no > ECF_TRIES, and task aborted by user\n"
+ "USER_EDIT - task\n"
+ "TASK_ABORTED - task*\n"
+ "EDIT_FAILED - task*\n"
+ "JOBCMD_FAILED - task*\n"
+ "NO_SCRIPT - task*\n"
+ "KILLED - task* do not run when try_no > ECF_TRIES, and task killed by user\n"
+ "MIGRATED - Node\n"
+ "LATE - Node attribute, Task is late, or Defs checkpt takes to long\n"
+ "MESSAGE - Node\n"
+ "BYRULE - Node*, set if node is set to complete by complete trigger expression\n"
+ "QUEUELIMIT - Node\n"
+ "WAIT - task* \n"
+ "LOCKED - Server\n"
+ "ZOMBIE - task*\n"
+ "NO_REQUE - task\n"
+ "NOT_SET\n"
+ )
+ .value("force_abort", Flag::FORCE_ABORT)
+ .value("user_edit", Flag::USER_EDIT)
+ .value("task_aborted", Flag::TASK_ABORTED)
+ .value("edit_failed", Flag::EDIT_FAILED)
+ .value("jobcmd_failed",Flag::JOBCMD_FAILED)
+ .value("no_script", Flag::NO_SCRIPT)
+ .value("killed", Flag::KILLED)
+ .value("migrated", Flag::MIGRATED)
+ .value("late", Flag::LATE)
+ .value("message", Flag::MESSAGE)
+ .value("byrule", Flag::BYRULE)
+ .value("queuelimit", Flag::QUEUELIMIT)
+ .value("wait", Flag::WAIT)
+ .value("locked", Flag::LOCKED)
+ .value("zombie", Flag::ZOMBIE)
+ .value("no_reque", Flag::NO_REQUE_IF_SINGLE_TIME_DEP)
+ .value("not_set", Flag::NOT_SET)
+ ;
+
+ class_<Flag>("Flag",
+ "Represents additional state associated with a Node.\n\n"
+ ,
+ init<>()
+ )
+ .def("__str__", &Flag::to_string) // __str__
+ .def(self == self ) // __eq__
+ .def("is_set", &Flag::is_set,"Queries if a given flag is set")
+ .def("set", &Flag::set, "Sets the given flag. Used in test only")
+ .def("clear", &Flag::clear, "Clear the given flag. Used in test only")
+ .def("reset", &Flag::reset, "Clears all flags. Used in test only")
+ .def("list", &Flag::list, "Returns the list of all flag types. returns FlagTypeVec. Used in test only").staticmethod("list")
+ .def("type_to_string",&Flag::enum_to_string, "Convert type to a string. Used in test only").staticmethod("type_to_string")
+ ;
+
+ class_<std::vector<Flag::Type> >("FlagTypeVec", "Hold a list of flag types")
+ .def(vector_indexing_suite<std::vector<Flag::Type> , true >()) ;
+
+
+
+ class_<JobCreationCtrl, boost::noncopyable, job_creation_ctrl_ptr >("JobCreationCtrl", DefsDoc::jobgenctrl_doc())
+ .def("__init__",make_constructor(makeJobCreationCtrl), DefsDoc::jobgenctrl_doc())
+ .def("set_node_path", &JobCreationCtrl::set_node_path, "The node we want to check job creation for. If no node specified check all tasks")
+ .def("set_dir_for_job_creation", &JobCreationCtrl::set_dir_for_job_creation, "Specify directory, for job creation")
+ .def("get_dir_for_job_creation", &JobCreationCtrl::dir_for_job_creation, return_value_policy<copy_const_reference>(), "Returns the directory set for job creation")
+ .def("generate_temp_dir", &JobCreationCtrl::generate_temp_dir, "Automatically generated temporary directory for job creation. Directory written to stdout for information")
+ .def("get_error_msg", &JobCreationCtrl::get_error_msg, return_value_policy<copy_const_reference>(),"Returns an error message generated during checking of job creation")
+ ;
+
+ // mimic PartExpression(const std::string& expression )
+ // mimic PartExpression(const std::string& expression, bool andExpr /* true means AND , false means OR */ )
+ // Use to adding large trigger and complete expressions
+ class_<PartExpression>("PartExpression",DefsDoc::part_expression_doc(), init<std::string>())
+ .def(init<std::string,bool>())
+ .def(self == self ) // __eq__
+ .def("get_expression", &PartExpression::expression, return_value_policy<copy_const_reference>(), "returns the part expression as a string")
+ .def("and_expr", &PartExpression::andExpr)
+ .def("or_expr", &PartExpression::orExpr)
+ ;
+
+ class_<Expression, boost::shared_ptr<Expression> >("Expression",DefsDoc::expression_doc(), init<std::string>() )
+ .def(init<PartExpression>())
+ .def(self == self ) // __eq__
+ .def("__str__", &Expression::expression) // __str__
+ .def("get_expression", &Expression::expression, "returns the complete expression as a string")
+ .def("add", &Expression::add,"Add a part expression, the second and subsequent part expressions must have 'and/or' set")
+ .add_property("parts", boost::python::range( &Expression::part_begin, &Expression::part_end),"Returns a list of PartExpression's" )
+ ;
+
+ // Turn off proxies by passing true as the NoProxy template parameter.
+ // shared_ptrs don't need proxies because calls on one a copy of the
+ // shared_ptr will affect all of them (duh!).
+ class_<std::vector<node_ptr> >("NodeVec", "Hold a list of Nodes (i.e :term:`suite`, :term:`family` or :term:`task` s)")
+ .def(vector_indexing_suite<std::vector<node_ptr> , true >()) ;
+
+ // Note: we have have not added __setattr__, as it seems to interfere with
+ // classes derived from Node. i.e calling self.fred = bill in the derived class
+ // expects self to be of type Node.
+ class_<Node, boost::noncopyable, node_ptr >("Node", DefsDoc::node_doc(), no_init)
+ .def("name",&Node::name, return_value_policy<copy_const_reference>() )
+ .def("add_trigger", &add_trigger, DefsDoc::add_trigger_doc())
+ .def("add_trigger", &add_trigger_expr)
+ .def("add_complete", &add_complete, DefsDoc::add_trigger_doc())
+ .def("add_complete", &add_complete_expr)
+ .def("add_part_trigger" ,&add_part_trigger, DefsDoc::add_trigger_doc())
+ .def("add_part_trigger" ,&add_part_trigger_1 )
+ .def("add_part_trigger" ,&add_part_trigger_2 )
+ .def("add_part_complete",&add_part_complete, DefsDoc::add_trigger_doc())
+ .def("add_part_complete",&add_part_complete_1 )
+ .def("add_part_complete",&add_part_complete_2 )
+ .def("evaluate_trigger", &evaluate_trigger ,"evaluate trigger expression")
+ .def("evaluate_complete",&evaluate_complete ,"evaluate complete expression")
+ .def("add_variable", &add_variable, DefsDoc::add_variable_doc())
+ .def("add_variable", &add_variable_int)
+ .def("add_variable", &add_variable_var)
+ .def("add_variable", &add_variable_dict)
+ .def("add_label", &add_label, DefsDoc::add_label_doc())
+ .def("add_label", &add_label_1)
+ .def("add_limit", &add_limit, DefsDoc::add_limit_doc())
+ .def("add_limit", &add_limit_1)
+ .def("add_inlimit", &add_in_limit,(bp::arg("limit_name"),bp::arg("path_to_node_containing_limit")="",bp::arg("tokens")=1),DefsDoc::add_inlimit_doc())
+ .def("add_inlimit", &add_in_limit_1)
+ .def("add_event", &add_event, DefsDoc::add_event_doc())
+ .def("add_event", &add_event_1)
+ .def("add_event", &add_event_2)
+ .def("add_event", &add_event_3)
+ .def("add_meter", &add_meter, DefsDoc::add_meter_doc())
+ .def("add_meter", add_meter_1)
+ .def("add_meter", add_meter_2)
+ .def("add_date", &add_date, DefsDoc::add_date_doc() )
+ .def("add_date", &add_date_1)
+ .def("add_day", &add_day, DefsDoc::add_day_doc())
+ .def("add_day", &add_day_1)
+ .def("add_day", &add_day_2)
+ .def("add_today", &add_today, DefsDoc::add_today_doc())
+ .def("add_today", &add_today_1)
+ .def("add_today", &add_today_2)
+ .def("add_today", &add_today_3)
+ .def("add_time", &add_time, DefsDoc::add_time_doc())
+ .def("add_time", &add_time_1 )
+ .def("add_time", &add_time_2 )
+ .def("add_time", &add_time_3 )
+ .def("add_cron", &add_cron, DefsDoc::add_cron_doc())
+ .def("add_late", &add_late, DefsDoc::add_late_doc())
+ .def("add_autocancel", &add_autocancel, DefsDoc::add_autocancel_doc())
+ .def("add_autocancel", &add_autocancel_1)
+ .def("add_autocancel", &add_autocancel_2)
+ .def("add_autocancel", &add_autocancel_3)
+ .def("add_verify", &Node::addVerify, DefsDoc::add_verify_doc())
+ .def("add_repeat", &add_repeat_date, DefsDoc::add_repeat_date_doc())
+ .def("add_repeat", &add_repeat_integer, DefsDoc::add_repeat_integer_doc())
+ .def("add_repeat", &add_repeat_string, DefsDoc::add_repeat_string_doc())
+ .def("add_repeat", &add_repeat_enum, DefsDoc::add_repeat_enumerated_doc() )
+ .def("add_repeat", &add_repeat_day, DefsDoc::add_repeat_day_doc() )
+ .def("add_defstatus", &add_defstatus, DefsDoc::add_defstatus_doc())
+ .def("add_zombie", &add_zombie, NodeAttrDoc::zombie_doc())
+ .def("delete_variable", &Node::deleteVariable )
+ .def("delete_event", &Node::deleteEvent )
+ .def("delete_meter", &Node::deleteMeter )
+ .def("delete_label", &Node::deleteLabel )
+ .def("delete_trigger", &Node::deleteTrigger )
+ .def("delete_complete", &Node::deleteComplete )
+ .def("delete_repeat", &Node::deleteRepeat )
+ .def("delete_limit", &Node::deleteLimit )
+ .def("delete_inlimit", &Node::deleteInlimit )
+ .def("delete_time", &Node::deleteTime )
+ .def("delete_time", &Node::delete_time )
+ .def("delete_today", &Node::deleteToday )
+ .def("delete_today", &Node::delete_today )
+ .def("delete_date", &Node::deleteDate )
+ .def("delete_date", &Node::delete_date )
+ .def("delete_day", &Node::deleteDay )
+ .def("delete_day", &Node::delete_day )
+ .def("delete_cron", &Node::deleteCron )
+ .def("delete_cron", &Node::delete_cron )
+ .def("delete_zombie", &Node::deleteZombie )
+ .def("delete_zombie", &Node::delete_zombie )
+ .def("change_trigger", &Node::changeTrigger )
+ .def("change_complete", &Node::changeComplete )
+ .def("get_abs_node_path", &Node::absNodePath, DefsDoc::abs_node_path_doc())
+ .def("has_time_dependencies", &Node::hasTimeDependencies)
+ .def("update_generated_variables", &Node::update_generated_variables)
+ .def("get_generated_variables", &Node::gen_variables, "returns a list of generated variables. Use ecflow.VariableList as return argument")
+ .def("is_suspended", &Node::isSuspended, "Returns true if the :term:`node` is in a :term:`suspended` state")
+ .def("find_variable", &Node::findVariable, return_value_policy<copy_const_reference>(), "Find user variable on the node only. Returns a object")
+ .def("find_parent_variable",&Node::find_parent_variable,return_value_policy<copy_const_reference>(), "Find user variable variable up the parent hierarchy. Returns a object")
+ .def("find_meter", &Node::findMeter, return_value_policy<copy_const_reference>(), "Find the :term:`meter` on the node only. Returns a object")
+ .def("find_event", &Node::findEventByNameOrNumber,return_value_policy<copy_const_reference>(), "Find the :term:`event` on the node only. Returns a object")
+ .def("find_label", &Node::find_label, return_value_policy<copy_const_reference>(), "Find the :term:`label` on the node only. Returns a object")
+ .def("find_limit", &Node::find_limit , "Find the :term:`limit` on the node only. returns a limit ptr" )
+ .def("find_node_up_the_tree",&Node::find_node_up_the_tree , "Search immediate node, then up the node hierarchy" )
+ .def("get_state", &Node::state , "Returns the state of the node. This excludes the suspended state")
+ .def("get_state_change_time",&get_state_change_time, (bp::arg("format")="iso_extended"), "Returns the time of the last state change as a string. Default format is iso_extended, (iso_extended, iso, simple)")
+ .def("get_dstate", &Node::dstate, "Returns the state of node. This will include suspended state")
+ .def("get_defstatus", &Node::defStatus )
+ .def("get_repeat", &Node::repeat, return_value_policy<copy_const_reference>() )
+ .def("get_late", &Node::get_late,return_internal_reference<>() )
+ .def("get_autocancel", &Node::get_autocancel, return_internal_reference<>())
+ .def("get_trigger", &Node::get_trigger, return_internal_reference<>() )
+ .def("get_complete", &Node::get_complete, return_internal_reference<>() )
+ .def("get_defs", get_defs, return_internal_reference<>() )
+ .def("get_parent", &Node::parent, return_internal_reference<>() )
+ .def("get_all_nodes", &get_all_nodes,"Returns all the child nodes")
+ .def("get_flag", &Node::get_flag,return_value_policy<copy_const_reference>(),"Return additional state associated with a node.")
+ .add_property("meters", boost::python::range( &Node::meter_begin, &Node::meter_end) , "Returns a list of :term:`meter` s")
+ .add_property("events", boost::python::range( &Node::event_begin, &Node::event_end) , "Returns a list of :term:`event` s")
+ .add_property("variables", boost::python::range( &Node::variable_begin, &Node::variable_end),"Returns a list of user defined :term:`variable` s" )
+ .add_property("labels", boost::python::range( &Node::label_begin, &Node::label_end) , "Returns a list of :term:`label` s")
+ .add_property("limits", boost::python::range( &Node::limit_begin, &Node::limit_end), "Returns a list of :term:`limit` s" )
+ .add_property("inlimits", boost::python::range( &Node::inlimit_begin, &Node::inlimit_end), "Returns a list of :term:`inlimit` s" )
+ .add_property("verifies", boost::python::range( &Node::verify_begin, &Node::verify_end), "Returns a list of Verify's" )
+ .add_property("times", boost::python::range( &Node::time_begin, &Node::time_end), "Returns a list of :term:`time` s" )
+ .add_property("todays", boost::python::range( &Node::today_begin, &Node::today_end), "Returns a list of :term:`today` s" )
+ .add_property("dates", boost::python::range( &Node::date_begin, &Node::date_end), "Returns a list of :term:`date` s" )
+ .add_property("days", boost::python::range( &Node::day_begin, &Node::day_end), "Returns a list of :term:`day` s")
+ .add_property("crons", boost::python::range( &Node::cron_begin, &Node::cron_end), "Returns a list of :term:`cron` s" )
+ .add_property("zombies", boost::python::range( &Node::zombie_begin, &Node::zombie_end), "Returns a list of :term:`zombie` s" )
+ ;
+}
diff --git a/Pyext/src/ExportNodeAttr.cpp b/Pyext/src/ExportNodeAttr.cpp
new file mode 100644
index 0000000..f0aa0bc
--- /dev/null
+++ b/Pyext/src/ExportNodeAttr.cpp
@@ -0,0 +1,415 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #53 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/python.hpp>
+#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
+#include <boost/make_shared.hpp>
+
+#include "NodeAttr.hpp"
+#include "Limit.hpp"
+#include "InLimit.hpp"
+#include "Variable.hpp"
+#include "ClockAttr.hpp"
+#include "CronAttr.hpp"
+#include "DateAttr.hpp"
+#include "DayAttr.hpp"
+#include "LateAttr.hpp"
+#include "RepeatAttr.hpp"
+#include "TimeAttr.hpp"
+#include "TodayAttr.hpp"
+#include "VerifyAttr.hpp"
+#include "AutoCancelAttr.hpp"
+#include "ZombieAttr.hpp"
+#include "NodeAttrDoc.hpp"
+#include "BoostPythonUtil.hpp"
+
+using namespace ecf;
+using namespace boost::python;
+using namespace std;
+namespace bp = boost::python;
+
+// See: http://wiki.python.org/moin/boost.python/HowTo#boost.function_objects
+
+void add_time_series_3(CronAttr* self,const std::string& ts) { self->addTimeSeries(TimeSeries::create(ts));}
+
+void set_week_days(CronAttr* cron,const boost::python::list& list)
+{
+ std::vector<int> int_vec;
+ BoostPythonUtil::list_to_int_vec(list,int_vec);
+ cron->addWeekDays(int_vec);
+}
+
+void set_days_of_month(CronAttr* cron,const boost::python::list& list)
+{
+ std::vector<int> int_vec;
+ BoostPythonUtil::list_to_int_vec(list,int_vec);
+ cron->addDaysOfMonth(int_vec);
+}
+
+void set_months(CronAttr* cron,const boost::python::list& list)
+{
+ std::vector<int> int_vec;
+ BoostPythonUtil::list_to_int_vec(list,int_vec);
+ cron->addMonths(int_vec);
+}
+
+// Create as shared because: we want to pass a Python list as part of the constructor,
+// *AND* the only way make_constructor works is with a pointer.
+// The Node::add function seem to cope with this, some boost python magic,must do a conversion
+// from shared_ptr to pass by reference
+static boost::shared_ptr<RepeatEnumerated> create_RepeatEnumerated(const std::string& name, const boost::python::list& list)
+{
+ std::vector<std::string> vec;
+ BoostPythonUtil::list_to_str_vec(list,vec);
+ return boost::make_shared<RepeatEnumerated>( name,vec );
+}
+static boost::shared_ptr<RepeatString> create_RepeatString(const std::string& name, const boost::python::list& list)
+{
+ std::vector<std::string> vec;
+ BoostPythonUtil::list_to_str_vec(list,vec);
+ return boost::make_shared<RepeatString>( name,vec );
+}
+
+static boost::shared_ptr<ZombieAttr> create_ZombieAttr(
+ Child::ZombieType zt,const boost::python::list& list,User::Action uc,int life_time_in_server)
+{
+ std::vector<Child::CmdType> vec;
+ int the_list_size = len(list);
+ vec.reserve(the_list_size);
+ for (int i = 0; i < the_list_size; ++i) {
+ vec.push_back(boost::python::extract<Child::CmdType>(list[i]));
+ }
+ return boost::make_shared<ZombieAttr>(zt,vec,uc,life_time_in_server );
+}
+
+static boost::shared_ptr<ZombieAttr> create_ZombieAttr1(
+ Child::ZombieType zt,const boost::python::list& list,User::Action uc)
+{
+ std::vector<Child::CmdType> vec;
+ int the_list_size = len(list);
+ vec.reserve(the_list_size);
+ for (int i = 0; i < the_list_size; ++i) {
+ vec.push_back(boost::python::extract<Child::CmdType>(list[i]));
+ }
+ return boost::make_shared<ZombieAttr>(zt,vec,uc);
+}
+
+
+static boost::python::list wrap_set_of_strings(Limit* limit)
+{
+ boost::python::list list;
+ const std::set<std::string>& paths = limit->paths();
+ BOOST_FOREACH(std::string path, paths) {
+ list.append(path);
+ }
+ return list;
+}
+
+void export_NodeAttr()
+{
+ enum_<Child::ZombieType>("ZombieType", NodeAttrDoc::zombie_type_doc())
+ .value("ecf", Child::ECF)
+ .value("user", Child::USER)
+ .value("path", Child::PATH)
+ ;
+
+ enum_<User::Action>("ZombieUserActionType",NodeAttrDoc::zombie_user_action_type_doc())
+ .value("fob", User::FOB)
+ .value("fail", User::FAIL)
+ .value("remove", User::REMOVE)
+ .value("adopt", User::ADOPT)
+ .value("block", User::BLOCK)
+ .value("kill", User::KILL)
+ ;
+
+ enum_<Child::CmdType>("ChildCmdType",NodeAttrDoc::child_cmd_type_doc())
+ .value("init", Child::INIT)
+ .value("event", Child::EVENT)
+ .value("meter", Child::METER)
+ .value("label", Child::LABEL)
+ .value("wait", Child::WAIT)
+ .value("abort", Child::ABORT)
+ .value("complete",Child::COMPLETE)
+ ;
+
+ // ZombieAttr(ecf::Child::ZombieType t, const std::vector<ecf::Child::CmdType>& c, ecf::User::Action a, int zombie_lifetime);
+ class_<ZombieAttr>("ZombieAttr",NodeAttrDoc::zombie_doc())
+ .def("__init__",make_constructor(&create_ZombieAttr) )
+ .def("__init__",make_constructor(&create_ZombieAttr1) )
+ .def("__str__", &ZombieAttr::toString) // __str__
+ .def(self == self ) // __eq__
+ .def("empty", &ZombieAttr::empty, "Return true if the attribute is empty")
+ .def("zombie_type", &ZombieAttr::zombie_type, "Returns the :term:`zombie type`")
+ .def("user_action", &ZombieAttr::action, "The automated action to invoke, when zombies arise")
+ .def("zombie_lifetime",&ZombieAttr::zombie_lifetime,"Returns the lifetime in seconds of :term:`zombie` in the server")
+ .add_property( "child_cmds",boost::python::range(&ZombieAttr::child_begin,&ZombieAttr::child_end),"The list of child commands. If empty action applies to all child cmds")
+ ;
+
+ class_<Variable>("Variable",NodeAttrDoc::variable_doc(),init<std::string, std::string>())
+ .def("__str__", &Variable::toString) // __str__
+ .def(self == self ) // __eq__
+ .def("name", &Variable::name, return_value_policy<copy_const_reference>(), "Return the variable name as string")
+ .def("value", &Variable::theValue, return_value_policy<copy_const_reference>(), "Return the variable value as a string")
+ .def("empty", &Variable::empty, "Return true if the variable is empty. Used when returning a Null variable, from a find")
+ ;
+
+ // We need to return pass a list of Variable as arguments, to retrieve the generated variables
+ class_<std::vector<Variable> >("VariableList", "Hold a list of Variables")
+ .def(vector_indexing_suite<std::vector<Variable> >()) ;
+
+
+ class_<Label>("Label",NodeAttrDoc::label_doc(),init<std::string, std::string>())
+ .def(self == self ) // __eq__
+ .def("__str__", &Label::toString) // __str__
+ .def("name", &Label::name, return_value_policy<copy_const_reference>(), "Return the :term:`label` name as string")
+ .def("value", &Label::value, return_value_policy<copy_const_reference>(), "Return the original :term:`label` value as string")
+ .def("new_value", &Label::new_value, return_value_policy<copy_const_reference>(), "Return the new label value as string")
+ .def("empty", &Label::empty, "Return true if the Label is empty. Used when returning a NULL Label, from a find")
+ ;
+
+ // This will not work, because paths_begin
+ //.add_property("node_paths", boost::python::range(&Limit::paths_begin,&Limit::paths_begin),"List of nodes(paths) that have consumed a limit")
+
+ class_<Limit, boost::shared_ptr<Limit> >("Limit",NodeAttrDoc::limit_doc(),init<std::string, int>())
+ .def(self == self ) // __eq__
+ .def("__str__", &Limit::toString) // __str__
+ .def("name", &Limit::name, return_value_policy<copy_const_reference>(), "Return the :term:`limit` name as string")
+ .def("value", &Limit::value, "The :term:`limit` token value as an integer")
+ .def("limit", &Limit::theLimit, "The max value of the :term:`limit` as an integer")
+ .def("increment",&Limit::increment, "used for test only")
+ .def("decrement",&Limit::decrement, "used for test only")
+ .def("node_paths",&wrap_set_of_strings,"List of nodes(paths) that have consumed a limit")
+ ;
+
+ class_<InLimit>("InLimit",NodeAttrDoc::inlimit_doc(),init<std::string, std::string, optional<int> >())
+ .def( init<std::string,std::string> () )
+ .def( init<std::string> () )
+ .def(self == self ) // __eq__
+ .def("__str__", &InLimit::toString) // __str__
+ .def("name", &InLimit::name, return_value_policy<copy_const_reference>(), "Return the :term:`inlimit` name as string")
+ .def("path_to_node",&InLimit::pathToNode, return_value_policy<copy_const_reference>(), "Path to the node that holds the limit, can be empty")
+ .def("tokens", &InLimit::tokens, "The number of token to consume from the Limit")
+ ;
+
+ class_<Event>("Event",NodeAttrDoc::event_doc(), init<int, optional<std::string> >())
+ .def( init<std::string> () )
+ .def(self == self ) // __eq__
+ .def("__str__", &Event::toString) // __str__
+ .def("name", &Event::name, return_value_policy<copy_const_reference>(), "Return the Events name as string. If number supplied name may be empty.")
+ .def("number", &Event::number, "Return events number as a integer. if not specified return max integer value")
+ .def("value", &Event::value, "Return events current value")
+ .def("empty", &Event::empty, "Return true if the Event is empty. Used when returning a NULL Event, from a find")
+ ;
+
+ class_<Meter>("Meter",NodeAttrDoc::meter_doc(),init<std::string,int,int,optional<int> >())
+ .def(self == self ) // __eq__
+ .def("__str__", &Meter::toString) // __str__
+ .def("name", &Meter::name, return_value_policy<copy_const_reference>(), "Return the Meters name as string")
+ .def("min", &Meter::min, "Return the Meters minimum value")
+ .def("max", &Meter::max, "Return the Meters maximum value")
+ .def("value", &Meter::value, "Return meters current value")
+ .def("color_change",&Meter::colorChange, "returns the color change")
+ .def("empty", &Meter::empty, "Return true if the Meter is empty. Used when returning a NULL Meter, from a find")
+ ;
+
+ class_<DateAttr>("Date",NodeAttrDoc::date_doc() ,init<int,int,int>()) // day,month,year
+ .def(self == self ) // __eq__
+ .def("__str__", &DateAttr::toString) // __str__
+ .def("day", &DateAttr::day, "Return the day. The range is 0-31, 0 means its wild-carded")
+ .def("month", &DateAttr::month, "Return the month. The range is 0-12, 0 means its wild-carded")
+ .def("year", &DateAttr::year, "Return the year, 0 means its wild-carded")
+ ;
+
+ enum_<DayAttr::Day_t>("Days",NodeAttrDoc::days_enum_doc())
+ .value("sunday", DayAttr::SUNDAY)
+ .value("monday", DayAttr::MONDAY)
+ .value("tuesday", DayAttr::TUESDAY)
+ .value("wednesday",DayAttr::WEDNESDAY)
+ .value("thursday", DayAttr::THURSDAY)
+ .value("friday", DayAttr::FRIDAY)
+ .value("saturday", DayAttr::SATURDAY);
+
+ class_<DayAttr>("Day",NodeAttrDoc::day_doc(),init<DayAttr::Day_t>() )
+ .def(self == self ) // __eq__
+ .def("__str__", &DayAttr::toString) // __str__
+ .def("day", &DayAttr::day, "Return the day as enumerator")
+ ;
+
+ class_<TimeAttr>("Time",NodeAttrDoc::time_doc() ,init<TimeSlot, optional<bool> >())
+ .def( init<int,int,optional<bool> >()) // hour, minute, relative
+ .def( init<TimeSeries>())
+ .def( init<TimeSlot,TimeSlot,TimeSlot,bool>())
+ .def(self == self ) // __eq__
+ .def("__str__", &TimeAttr::toString) // __str__
+ .def("time_series",&TimeAttr::time_series,return_value_policy<copy_const_reference>(), "Return the Time attributes time series")
+ ;
+
+ class_<TodayAttr>("Today",NodeAttrDoc::today_doc() ,init<TimeSlot, optional<bool> >())
+ .def( init<int,int,optional<bool> >()) // hour, minute, relative
+ .def( init<TimeSeries>())
+ .def( init<TimeSlot,TimeSlot,TimeSlot,bool>())
+ .def(self == self ) // __eq__
+ .def("__str__", &TodayAttr::toString) // __str__
+ .def("time_series",&TodayAttr::time_series,return_value_policy<copy_const_reference>(), "Return the Todays time series")
+ ;
+
+
+ class_<LateAttr, boost::shared_ptr<LateAttr> >("Late",NodeAttrDoc::late_doc())
+ .def( "submitted", &LateAttr::addSubmitted,
+ "submitted(TimeSlot):The time node can stay :term:`submitted`. Submitted is always relative. If the node stays\n"
+ "submitted longer than the time specified, the :term:`late` flag is set\n"
+ )
+ .def( "submitted", &LateAttr::add_submitted,
+ "submitted(hour,minute) The time node can stay submitted. Submitted is always relative. If the node stays\n"
+ "submitted longer than the time specified, the late flag is set\n"
+ )
+ .def( "active", &LateAttr::add_active,
+ "active(hour,minute): The time the node must become :term:`active`. If the node is still :term:`queued` or :term:`submitted`\n"
+ "by the time specified, the late flag is set"
+ )
+ .def( "active", &LateAttr::addActive,
+ "active(TimeSlot):The time the node must become :term:`active`. If the node is still :term:`queued` or :term:`submitted`\n"
+ "by the time specified, the late flag is set"
+ )
+ .def( "complete", &LateAttr::add_complete,
+ "complete(hour,minute):The time the node must become :term:`complete`. If relative, time is taken from the time\n"
+ "the node became :term:`active`, otherwise node must be :term:`complete` by the time given"
+ )
+ .def( "complete", &LateAttr::addComplete,
+ "complete(TimeSlot): The time the node must become :term:`complete`. If relative, time is taken from the time\n"
+ "the node became :term:`active`, otherwise node must be :term:`complete` by the time given"
+ )
+ .def(self == self ) // __eq__
+ .def("__str__", &LateAttr::toString) // __str__
+ .def("submitted", &LateAttr::submitted,return_value_policy<copy_const_reference>(), "Return the submitted time as a TimeSlot")
+ .def("active", &LateAttr::active, return_value_policy<copy_const_reference>(), "Return the active time as a TimeSlot")
+ .def("complete", &LateAttr::complete, return_value_policy<copy_const_reference>(), "Return the complete time as a TimeSlot")
+ .def("complete_is_relative", &LateAttr::complete_is_relative, "Returns a boolean where true means that complete is relative")
+ .def("is_late", &LateAttr::isLate, "Return True if late")
+ ;
+
+
+ class_<AutoCancelAttr, boost::shared_ptr<AutoCancelAttr> >(
+ "Autocancel",NodeAttrDoc::autocancel_doc() ,
+ init<int,int,bool >() // hour, minute, relative
+ )
+ .def( init<int>()) // days
+ .def( init<TimeSlot, bool>())
+ .def(self == self ) // __eq__
+ .def("__str__", &AutoCancelAttr::toString) // __str__
+ .def("time", &AutoCancelAttr::time, return_value_policy<copy_const_reference>(), "returns cancel time as a TimeSlot")
+ .def("relative",&AutoCancelAttr::relative, "Returns a boolean where true means the time is relative")
+ .def("days", &AutoCancelAttr::days, "Returns a boolean true if time was specified in days")
+ ;
+
+
+ class_<RepeatDate >("RepeatDate",NodeAttrDoc::repeat_date_doc() ,init< std::string, int, int, optional<int> >()) // name, start, end , delta
+ .def(self == self ) // __eq__
+ .def("__str__", &RepeatDate::toString) // __str__
+ .def("name", &RepeatDate::name, return_value_policy<copy_const_reference>(),"Return the name of the repeat.")
+ .def("start", &RepeatDate::start ,"Return the start date as an integer in yyyymmdd format")
+ .def("end", &RepeatDate::end, "Return the end date as an integer in yyyymmdd format")
+ .def("step", &RepeatDate::step, "Return the step increment. This is used to update the repeat, until end date is reached")
+ ;
+
+ class_<RepeatInteger>("RepeatInteger",NodeAttrDoc::repeat_integer_doc(),init< std::string, int, int, optional<int> >()) // name, start, end , delta = 1
+ .def(self == self ) // __eq__
+ .def("__str__", &RepeatInteger::toString) // __str__
+ .def("name", &RepeatInteger::name, return_value_policy<copy_const_reference>(),"Return the name of the repeat.")
+ .def("start", &RepeatInteger::start)
+ .def("end", &RepeatInteger::end)
+ .def("step", &RepeatInteger::step)
+ ;
+
+ // Create as shared because: we want to pass a Python list as part of the constructor,
+ // and the only way make_constructor works is with a pointer.
+ class_<RepeatEnumerated, boost::shared_ptr<RepeatEnumerated> >("RepeatEnumerated",NodeAttrDoc::repeat_enumerated_doc())
+ .def("__init__",make_constructor(&create_RepeatEnumerated) )
+ .def(self == self ) // __eq__
+ .def("__str__", &RepeatEnumerated::toString) // __str__
+ .def("name", &RepeatEnumerated::name, return_value_policy<copy_const_reference>(),"Return the name of the :term:`repeat`.")
+ .def("start", &RepeatEnumerated::start)
+ .def("end", &RepeatEnumerated::end)
+ .def("step", &RepeatEnumerated::step)
+ ;
+
+ class_<RepeatString,boost::shared_ptr<RepeatString> >("RepeatString", NodeAttrDoc::repeat_string_doc())
+ .def("__init__",make_constructor(&create_RepeatString) )
+ .def(self == self ) // __eq__
+ .def("__str__", &RepeatString::toString) // __str__
+ .def("name", &RepeatString::name, return_value_policy<copy_const_reference>(),"Return the name of the :term:`repeat`.")
+ .def("start", &RepeatString::start)
+ .def("end", &RepeatString::end)
+ .def("step", &RepeatString::step)
+ ;
+
+ class_<RepeatDay>("RepeatDay",NodeAttrDoc::repeat_day_doc(),init< optional<int> >())
+ .def(self == self ) // __eq__
+ .def("__str__", &RepeatDay::toString) // __str__
+ ;
+
+ class_<Repeat>("Repeat",NodeAttrDoc::repeat_doc() ,init< int >())
+ .def(self == self ) // __eq__
+ .def("__str__", &Repeat::toString) // __str__
+ .def("empty", &Repeat::empty ,"Return true if the repeat is empty.")
+ .def("name", &Repeat::name, return_value_policy<copy_const_reference>(), "The :term:`repeat` name, can be referenced in :term:`trigger` expressions")
+ .def("start", &Repeat::start,"The start value of the repeat, as an integer")
+ .def("end", &Repeat::end, "The last value of the repeat, as an integer")
+ .def("step", &Repeat::step, "The increment for the repeat, as an integer")
+ .def("value", &Repeat::last_valid_value,"The current value of the repeat as an integer")
+ ;
+
+
+ void (CronAttr::*add_time_series)(const TimeSeries&) = &CronAttr::addTimeSeries;
+ void (CronAttr::*add_time_series_2)( const TimeSlot& s, const TimeSlot& f, const TimeSlot& i) = &CronAttr::addTimeSeries;
+ class_<CronAttr>("Cron",NodeAttrDoc::cron_doc() )
+ .def(self == self ) // __eq__
+ .def("__str__", &CronAttr::toString) // __str__
+ .def( "set_week_days", &set_week_days , "Specifies days of week. Expects a list of integers, with integer range 0==Sun to 6==Sat")
+ .def( "set_days_of_month", &set_days_of_month,"Specifies days of the month. Expects a list of integers with integer range 1-31" )
+ .def( "set_months", &set_months , "Specifies months. Expects a list of integers, with integer range 1-12")
+ .def( "set_time_series", &CronAttr::add_time_series,(bp::arg("hour"),bp::arg("minute"),bp::arg("relative")=false),"time_series(hour(int),minute(int),relative to suite start(bool=false)), Add a time slot")
+ .def( "set_time_series", add_time_series, "Add a time series. This will never complete")
+ .def( "set_time_series", add_time_series_2, "Add a time series. This will never complete")
+ .def( "set_time_series", &add_time_series_3,"Add a time series. This will never complete")
+ .def( "time", &CronAttr::time, return_value_policy<copy_const_reference>(), "return cron time as a TimeSeries")
+ .add_property( "week_days", boost::python::range(&CronAttr::week_days_begin, &CronAttr::week_days_end), "returns a integer list of week days")
+ .add_property( "days_of_month",boost::python::range(&CronAttr::days_of_month_begin,&CronAttr::days_of_month_end), "returns a integer list of days of the month")
+ .add_property( "months", boost::python::range(&CronAttr::months_begin, &CronAttr::months_end), "returns a integer list of months of the year")
+ ;
+
+
+ class_<VerifyAttr>("Verify", init<NState::State,int>()) // state, expected
+ .def(self == self ) // __eq__
+ .def("__str__", &VerifyAttr::toString) // __str__
+ ;
+
+
+ void (ClockAttr::*start_stop_with_server)(bool) = &ClockAttr::startStopWithServer;
+ class_<ClockAttr, boost::shared_ptr<ClockAttr> >("Clock",NodeAttrDoc::clock_doc() ,init<int,int,int,optional<bool> > ()) // day, month, year, hybrid
+ .def( init<int,int,int,bool>())
+ .def( init<bool>())
+ .def(self == self ) // __eq__
+ .def("__str__", &ClockAttr::toString) // __str__
+ .def( "set_gain_in_seconds",&ClockAttr::set_gain_in_seconds, "Set the gain in seconds")
+ .def( "set_gain", &ClockAttr::set_gain, "Set the gain in hours and minutes")
+ .def( "set_virtual", start_stop_with_server, "Sets/unsets the clock as being virtual")
+ .def( "day", &ClockAttr::day, "Returns the day as an integer, range 1-31")
+ .def( "month", &ClockAttr::month, "Returns the month as an integer, range 1-12")
+ .def( "year", &ClockAttr::year, "Returns the year as an integer, > 1400")
+ .def( "gain", &ClockAttr::gain, "Returns the gain as an long. This represents seconds")
+ .def( "positive_gain",&ClockAttr::positive_gain,"Returns a boolean, where true means that the gain is positive")
+ .def( "virtual" ,&ClockAttr::is_virtual, "Returns a boolean, where true means that clock is virtual")
+ ;
+}
diff --git a/Pyext/src/ExportSuiteAndFamily.cpp b/Pyext/src/ExportSuiteAndFamily.cpp
new file mode 100644
index 0000000..c24b039
--- /dev/null
+++ b/Pyext/src/ExportSuiteAndFamily.cpp
@@ -0,0 +1,91 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #85 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/python.hpp>
+#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/make_shared.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/noncopyable.hpp>
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "BoostPythonUtil.hpp"
+
+#include "DefsDoc.hpp"
+
+using namespace ecf;
+using namespace boost::python;
+using namespace std;
+namespace bp = boost::python;
+
+// See: http://wiki.python.org/moin/boost.python/HowTo#boost.function_objects
+
+/// Since we don't pass in a child pos, the nodes are added to the end
+void add_family(NodeContainer* self,family_ptr f){ self->addFamily(f); }
+void add_task(NodeContainer* self,task_ptr t){ self->addTask(t); }
+
+suite_ptr add_clock(suite_ptr self, const ClockAttr& clk) { self->addClock(clk); return self;}
+
+// Context management, Only used to provide indentation
+suite_ptr suite_enter(suite_ptr self) { return self;}
+bool suite_exit(suite_ptr self,const boost::python::object& type,const boost::python::object& value,const boost::python::object& traceback){return false;}
+family_ptr family_enter(family_ptr self) { return self;}
+bool family_exit(family_ptr self,const boost::python::object& type,const boost::python::object& value,const boost::python::object& traceback){return false;}
+
+
+void export_SuiteAndFamily()
+{
+ // Turn off proxies by passing true as the NoProxy template parameter.
+ // shared_ptrs don't need proxies because calls on one a copy of the
+ // shared_ptr will affect all of them (duh!).
+ class_<std::vector<family_ptr> >("FamilyVec","Hold a list of :term:`family` nodes")
+ .def(vector_indexing_suite<std::vector<family_ptr>, true >()) ;
+
+ class_<std::vector<suite_ptr> >("SuiteVec","Hold a list of :term:`suite` nodes's")
+ .def(vector_indexing_suite<std::vector<suite_ptr>, true >());
+
+ // choose the correct overload
+ class_<NodeContainer, bases<Node>, boost::noncopyable >("NodeContainer",DefsDoc::node_container_doc(), no_init)
+ .def("add_family",&NodeContainer::add_family ,DefsDoc::add_family_doc())
+ .def("add_family",add_family )
+ .def("add_task", &NodeContainer::add_task , DefsDoc::add_task_doc())
+ .def("add_task", add_task )
+ .add_property("nodes",boost::python::range( &NodeContainer::node_begin,&NodeContainer::node_end),"Returns a list of Node's")
+ ;
+
+
+ class_<Family, bases<NodeContainer>, family_ptr, boost::noncopyable>("Family",DefsDoc::family_doc())
+ .def("__init__",make_constructor(&Family::create), DefsDoc::family_doc())
+ .def(self == self ) // __eq__
+ .def("__str__", &Family::to_string) // __str__
+ .def("__enter__", &family_enter) // allow with statement, hence indentation support
+ .def("__exit__", &family_exit) // allow with statement, hence indentation support
+ ;
+
+
+ class_<Suite, bases<NodeContainer>, suite_ptr, boost::noncopyable>("Suite",DefsDoc::suite_doc())
+ .def("__init__",make_constructor(&Suite::create), DefsDoc::suite_doc())
+ .def(self == self ) // __eq__
+ .def("__str__", &Suite::to_string) // __str__
+ .def("__enter__", &suite_enter) // allow with statement, hence indentation support
+ .def("__exit__", &suite_exit) // allow with statement, hence indentation support
+ .def("add_clock", &add_clock)
+ .def("get_clock", &Suite::clockAttr,"Returns the :term:`suite` :term:`clock`")
+ .def("begun", &Suite::begun, "Returns true if the :term:`suite` has begun, false otherwise")
+ ;
+}
diff --git a/Pyext/src/ExportTask.cpp b/Pyext/src/ExportTask.cpp
new file mode 100644
index 0000000..55fc263
--- /dev/null
+++ b/Pyext/src/ExportTask.cpp
@@ -0,0 +1,66 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #85 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/python.hpp>
+#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/make_shared.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/noncopyable.hpp>
+
+#include "Task.hpp"
+#include "DefsDoc.hpp"
+
+using namespace ecf;
+using namespace boost::python;
+using namespace std;
+namespace bp = boost::python;
+
+task_ptr task_enter(task_ptr self) { return self;}
+bool task_exit(task_ptr self,const boost::python::object& type,const boost::python::object& value,const boost::python::object& traceback){return false;}
+
+// See: http://wiki.python.org/moin/boost.python/HowTo#boost.function_objects
+
+void export_Task()
+{
+ // Turn off proxies by passing true as the NoProxy template parameter.
+ // shared_ptrs don't need proxies because calls on one a copy of the
+ // shared_ptr will affect all of them (duh!).
+ class_<std::vector<task_ptr> >("TaskVec","Hold a list of :term:`task` nodes")
+ .def(vector_indexing_suite<std::vector<task_ptr>, true >()) ;
+
+ class_<Submittable, bases<Node>, boost::noncopyable >("Submittable",DefsDoc::submittable_doc(), no_init)
+ .def("get_jobs_password" , &Submittable::jobsPassword, return_value_policy<copy_const_reference>(), "The password. This generated by server")
+ .def("get_process_or_remote_id",&Submittable::process_or_remote_id, return_value_policy<copy_const_reference>(),"The process or remote id of the running job")
+ .def("get_try_no" , &Submittable::tryNo, "The current try number as a string.")
+ .def("get_int_try_no" , &Submittable::try_no, "The current try number as integer.")
+ .def("get_aborted_reason" , &Submittable::abortedReason,return_value_policy<copy_const_reference>(), "If node was aborted and a reason was provided, return the string")
+ ;
+
+ class_<Task, bases<Submittable>, task_ptr, boost::noncopyable>("Task",DefsDoc::task_doc() )
+ .def("__init__",make_constructor(&Task::create), DefsDoc::task_doc())
+ .def(self == self ) // __eq__
+ .def("__enter__", &task_enter) // allow with statement, hence indentation support
+ .def("__exit__", &task_exit) // allow with statement, hence indentation support
+ .def("__str__", &Task::to_string) // __str__
+ .add_property("aliases",boost::python::range( &Task::alias_begin, &Task::alias_end), "Returns a list of aliases")
+ .add_property("nodes", boost::python::range( &Task::alias_begin, &Task::alias_end), "Returns a list of aliases")
+ ;
+
+ class_<Alias, bases<Submittable>, alias_ptr, boost::noncopyable>("Alias",DefsDoc::alias_doc(),no_init)
+ .def(self == self ) // __eq__
+ .def("__str__", &Alias::to_string) // __str__
+ ;
+}
diff --git a/Pyext/src/NodeAttrDoc.cpp b/Pyext/src/NodeAttrDoc.cpp
new file mode 100644
index 0000000..717430e
--- /dev/null
+++ b/Pyext/src/NodeAttrDoc.cpp
@@ -0,0 +1,567 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #36 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : This class is used as a helper class
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include "NodeAttrDoc.hpp"
+
+const char* NodeAttrDoc::variable_doc()
+{
+ return
+ "Defines a :term:`variable` on a :term:`node` for use in :term:`ecf script`.\n\n"
+ "A Node can have a number of variables.\n"
+ "These variables can be added at any node level: :term:`suite`, :term:`family` or :term:`task`.\n"
+ "The variables are names inside a pair of '%' characters in an :term:`ecf script`.\n"
+ "The content of a variable replaces the variable name in the :term:`ecf script` at\n"
+ "job submission time. When a variable is needed at submission time, it is first\n"
+ "sought in the task itself. If it is not found, it is sought from the tasks parent\n"
+ "and so on, up through the node levels until found. See :term:`variable inheritance`\n"
+ "A undefined variable in a :term:`ecf script`, causes the :term:`task` to be :term:`aborted`,\n"
+ "without the job being submitted.\n"
+ "\nConstructor::\n\n"
+ " Variable(name,value)\n"
+ " string name: the name of the variable\n"
+ " string value: The value of the variable\n"
+ "\nUsage::\n\n"
+ " ..."
+ " var = Variable(\"ECF_JOB_CMD\",\"/bin/sh %ECF_JOB% &\")\n"
+ " task.add_variable(var)\n"
+ " task.add_variable('JOE','90')\n"
+ ;
+}
+
+const char* NodeAttrDoc::zombie_doc()
+{
+ return
+ "The :term:`zombie` attribute defines how a :term:`zombie` should be handled in an automated fashion\n\n"
+ "Very careful consideration should be taken before this attribute is added\n"
+ "as it may hide a genuine problem.\n"
+ "It can be added to any :term:`node`. But is best defined at the :term:`suite` or :term:`family` level.\n"
+ "If there is no zombie attribute the default behaviour is to block the init,complete,abort :term:`child command`.\n"
+ "and *fob* the event,label,and meter :term:`child command`\n"
+ "This attribute allows the server to make a automated response\n"
+ "Please see: :py:class:`ecflow.ZombieType`, :py:class:`ecflow.ChildCmdType`, :py:class:`ecflow.ZombieUserActionType`\n"
+ "\nConstructor::\n\n"
+ " ZombieAttr(ZombieType,ChildCmdTypes, ZombieUserActionType, lifetime)\n"
+ " ZombieType : Must be one of ZombieType.ecf, ZombieType.path, ZombieType.user\n"
+ " ChildCmdType : A list(ChildCmdType) of Child commands. Can be left empty in\n"
+ " which case the action affect all child commands\n"
+ " ZombieUserActionType : One of [ fob, fail, block, remove, adopt ]\n"
+ " int lifetime<optional>: Defines the life time in seconds of the zombie in the server.\n"
+ " On expiration, zombie is removed automatically\n"
+ "\nUsage::\n\n"
+ " # Add a zombie attribute so that child label commands(i.e ecflow_client --label)\n"
+ " # never block the job\n"
+ " s1 = ecflow.Suite('s1')\n"
+ " child_list = [ ChildCmdType.label ]\n"
+ " zombie_attr = ZombieAttr(ZombieType.ecf, child_list, ZombieUserActionType.fob)\n"
+ " s1.add_zombie(zombie_attr)\n"
+ ;
+}
+
+const char* NodeAttrDoc::zombie_type_doc()
+{
+ return
+ ":term:`zombie` s are running jobs that fail authentication when communicating with the :term:`ecflow_server`.\n\n"
+ "See class :term:`zombie type` and :py:class:`ecflow.ZombieAttr` for further information.\n"
+ ;
+}
+
+const char* NodeAttrDoc::zombie_user_action_type_doc()
+{
+ return
+ "ZombieUserActionType is used define an automated response. See class :py:class:`ZombieAttr`\n\n"
+ "This can be either on the client side or on the server side\n"
+ "\nclient side:\n\n"
+ "- fob: The :term:`child command` always succeeds, i.e allowed to complete without blocking\n"
+ "- fail: The :term:`child command` is asked to fail.\n"
+ "- block: The :term:`child command` is asked to block. This is the default action for all child commands\n"
+ "\nserver side:\n\n"
+ "- adopt: Allows the password supplied with the :term:`child command` s, to be adopted by the server\n"
+ "- kill: Kills the zombie process associated with the :term:`child command` using ECF_KILL_CMD.\n"
+ " path zombies will need to be killed manually. If kill is specified for path zombies\n"
+ " they will be fobed, i.e allowed to complete without blocking the job.\n"
+ "- remove: :term:`ecflow_server` removes the :term:`zombie` from the zombie list.\n"
+ " The child continues blocking. The :term:`zombie` may well re-appear\n\n"
+ "Note: Only adopt will allow the :term:`child command` to continue and change the :term:`node` tree\n"
+ ;
+}
+
+const char* NodeAttrDoc::child_cmd_type_doc()
+{
+ return
+ "ChildCmdType represents the different :term:`child command` s.\n"
+ "This type is used as a parameter to the class :py:class:`ecflow.ZombieAttr`\n\n"
+ "Child commands are called within a :term:`job file`::\n\n"
+ " ChildCmdType::init corresponds to : ecflow_client --init=<process_id>\n"
+ " ChildCmdType::event corresponds to : ecflow_client --event=<event_name | number>\n"
+ " ChildCmdType::meter corresponds to : ecflow_client --meter=<meter_name>, <meter_value>\n"
+ " ChildCmdType::label corresponds to : ecflow_client --label=<label_name>. <label_value>\n"
+ " ChildCmdType::wait corresponds to : ecflow_client --wait=<expression>\n"
+ " ChildCmdType::abort corresponds to : ecflow_client --abort=<reason>\n"
+ " ChildCmdType::complete corresponds to : ecflow_client --complete\n"
+ ;
+}
+
+const char* NodeAttrDoc::label_doc()
+{
+ return
+ "A :term:`label` has a name and value and provides a way of displaying information in a GUI.\n\n"
+ "The value can be anything(ASCII) as it can not be used in triggers\n"
+ "The value of the label is set to be the default value given in the definition\n"
+ "when the :term:`suite` is begun. This is useful in repeated suites: A task sets the label\n"
+ "to be something, e.g, the number of observations, and once the :term:`suite` is :term:`complete`\n"
+ "and the next day starts) the number of observations is cleared.\n"
+ "Labels can be set at any level: Suite,Family,Task\n"
+ "There are two ways of updating the label\n"
+ "- A :term:`child command` can be used to automatically update the label on a :term:`task`\n"
+ "- By using the alter command, the labels on :term:`suite` :term:`family` and :term:`task` can be changed manually\n"
+ "\nConstructor::\n\n"
+ " Label(name,value)\n"
+ " string name: The name of the label\n"
+ " string value: The value of the label\n"
+ "\nUsage::\n\n"
+ " t1 = Task('t1')\n"
+ " t1.add_label('l1','value')\n"
+ " t1.add_label(Label('l2','value2'))\n"
+ " for label in t1.labels:\n"
+ " print label\n"
+ ;
+}
+
+const char* NodeAttrDoc::limit_doc()
+{
+ return
+ ":term:`limit` provides a simple load management\n\n"
+ "i.e. by limiting the number of :term:`task` s submitted by a server.\n"
+ "Limits are typically defined at the :term:`suite` level, or defined in a\n"
+ "separate suite, so that they can be used by multiple suites.\n"
+ "Once a limit is defined in a :term:`suite definition`, you must also assign families/tasks to use\n"
+ "this limit. See :term:`inlimit` and :py:class:`ecflow.InLimit`\n"
+ "\nConstructor::\n\n"
+ " Limit(name,value)\n"
+ " string name: the name of the limit\n"
+ " int value: The value of the limit\n"
+ "\nUsage::\n\n"
+ " limit = Limit(\"fast\", 10)\n"
+ " ...\n"
+ " suite.add_limit(limit)\n"
+ ;
+}
+
+const char* NodeAttrDoc::inlimit_doc()
+{
+ return
+ ":term:`inlimit` is used in conjunction with :term:`limit` to provide simple load management::\n\n"
+ " suite x\n"
+ " limit fast 1\n"
+ " family f\n"
+ " inlimit /x:fast\n"
+ " task t1\n"
+ " task t2\n\n"
+ "Here 'fast' is the name of limit and the number defines the maximum number of tasks\n"
+ "that can run simultaneously using this limit. Thats why you do not need a :term:`trigger`\n"
+ "between tasks 't1' and 't2'. There is no need to change the tasks. The jobs are\n"
+ "created in the order they are defined\n"
+ "\nConstructor::\n\n"
+ " InLimit(name, optional<path = ''>, optional<token = 1>)\n"
+ " string name : The name of the referenced Limit\n"
+ " string path<optional> : The path to the Limit, if this is left out, then Limit of 'name' must be specified\n"
+ " some where up the parent hierarchy\n"
+ " int value<optional> : The usage of the Limit. Each job submission will consume 'value' tokens\n"
+ " from the Limit. defaults to 1 if no value specified.\n"
+ "\nUsage::\n\n"
+ " inlimit = InLimit(\"fast\",\"/x/f\", 2)\n"
+ " ...\n"
+ " family.add_inlimit(inlimit)\n"
+ ;
+}
+
+const char* NodeAttrDoc::event_doc()
+{
+ return
+ ":term:`event` s are used as signal mechanism.\n\n"
+ "Typically they would be used to signal partial completion of a :term:`task`\n"
+ "and to be able to :term:`trigger` another job, which is waiting for this partial completion.\n"
+ "Only tasks can have events that are automatically set via a :term:`child command` s, see below.\n"
+ "Events are cleared automatically when a :term:`node` is re-queued or begun.\n"
+ "Suites and Families can have tasks, but these events must be set via the Alter command\n"
+ "Multiple events can be added to a task.\n"
+ "An Event has a number and a optional name. Events are typically used\n"
+ "in :term:`trigger` and :term:`complete expression` , to control job creation.\n"
+ "Event are fired within a :term:`job file`, i.e.::\n\n"
+ " ecflow_client --init=$$\n"
+ " ecflow_client --event=foo\n"
+ " ecflow_client --complete\n\n"
+ "Hence the defining of an event for a :term:`task`, should be followed with the addition of ecflow_client --event\n"
+ ":term:`child command` in the corresponding :term:`ecf script` file.\n"
+ "\nConstructor::\n\n"
+ " Event(number, optional<name = ''>)\n"
+ " int number : The number must be >= 0\n"
+ " string name<optional> : If name is given, can only refer to Event by its name\n"
+ "\nUsage::\n\n"
+ " event = Event(2,\"event_name\")\n"
+ " task.add_event(event)\n"
+ " task1.add_event(\"2\") # create a event '1' and add to the task\n"
+ " task2.add_event(\"name\") # create a event 'name' and add to task\n"
+ ;
+}
+
+const char* NodeAttrDoc::meter_doc()
+{
+ return
+ ":term:`meter` s can be used to indicate proportional completion of :term:`task`\n\n"
+ "They are able to :term:`trigger` another job, which is waiting on this proportion.\n"
+ "Can also be used to indicate progress of a job. Meters can be used in\n"
+ ":term:`trigger` and :term:`complete expression`.\n"
+ "\nConstructor::\n\n"
+ " Meter(name,min,max,<optional>color_change)\n"
+ " string name : The meter name\n"
+ " int min : The minimum and initial meter value\n"
+ " int max : The maximum meter value. Must be greater than min value.\n"
+ " int color_change<optional> : default = max, Must be between min-max, used in the GUI\n"
+ "\nExceptions:\n\n"
+ "- raises IndexError when an invalid Meter is specified\n"
+ "\nUsage:\n\n"
+ "Using a meter requires:\n\n"
+ "- Defining a meter on a :term:`task`::\n\n"
+ " meter = Meter(\"progress\",0,100,100)\n"
+ " task.add_meter(meter)\n\n"
+ "- Updating the corresponding :term:`ecf script` file with the meter :term:`child command`::\n\n"
+ " ecflow_client --init=$$\n"
+ " for i in 10 20 30 40 50 60 80 100; do\n"
+ " ecflow_client --meter=progress $i\n"
+ " sleep 2 # or do some work\n"
+ " done\n"
+ " ecflow_client --complete\n\n"
+ "- Optionally addition in a :term:`trigger` or :term:`complete expression` for job control::\n\n"
+ " trigger task:progress ge 60\n\n"
+ " trigger and complete expression should *avoid* using equality i.e::\n\n"
+ " trigger task:progress == 60\n\n"
+ " Due to network issues the meter event's may **not** arrive in sequential order\n"
+ " hence the :term:`ecflow_server` will ignore meter value's, which are less than the current value\n"
+ " as a result triggers's which use meter equality may never evaluate\n"
+ ;
+}
+
+const char* NodeAttrDoc::date_doc()
+{
+ return
+ "Used to define a :term:`date` dependency.\n\n"
+ "There can be multiple Date dependencies for a :term:`node`.\n"
+ "Any of the 3 attributes, i.e. day, month, year can be wild carded using a zero\n"
+ "If a hybrid :term:`clock` is defined on a suite, any node held by a date dependency\n"
+ "will be set to :term:`complete` at the beginning of the :term:`suite`, without the\n"
+ "task ever being dispatched otherwise, the suite would never complete.\n"
+ "\nConstructor::\n\n"
+ " Date(day,month,year)\n"
+ " int day : represents the day, zero means wild card. day >= 0 & day < 31\n"
+ " int month : represents the month, zero means wild card. month >= 0 & month < 12\n"
+ " int year : represents the year, zero means wild card. year >= 0\n"
+ "\nExceptions:\n\n"
+ "- raises IndexError when an invalid date is specified\n"
+ "\nUsage::\n\n"
+ " date = Date(11,12,2010) # represent 11th of December 2010\n"
+ " date = Date(1,0,0); # means the first day of every month of every year\n"
+ ;
+}
+
+const char* NodeAttrDoc::day_doc()
+{
+ return
+ "Defines a :term:`day` dependency.\n\n"
+ "There can be multiple day dependencies. If a hybrid :term:`clock` is defined\n"
+ "on a suite, any node held by a day dependency will be set to :term:`complete` at the\n"
+ "beginning of the :term:`suite`, without the task ever being dispatched otherwise\n"
+ "the suite would never complete.\n"
+ "\nConstructor::\n\n"
+ " Day(Days)\n"
+ " Days day: Is an enumerator with represent the days of the week\n"
+ "\nUsage::\n\n"
+ " day1 = Day(Days.sunday)\n"
+ " day2 = Day(Days.monday)\n"
+ ;
+}
+
+const char* NodeAttrDoc::days_enum_doc()
+{
+ return
+ "This enum is used as argument to a :py:class:`ecflow.Day` class.\n\n"
+ "It represents the days of the week\n"
+ "\nUsage::\n\n"
+ " day1 = Day(Days.sunday)\n"
+ " day2 = Day(Days.monday)\n"
+ " day3 = Day(Days.tuesday)\n"
+ ;
+}
+
+const char* NodeAttrDoc::time_doc()
+{
+ return
+ "Is used to define a :term:`time` dependency\n\n"
+ "This can then control job submission.\n"
+ "There can be multiple time dependencies for a node, however overlapping times may\n"
+ "cause unexpected results. The time dependency can be made relative to the beginning\n"
+ "of the suite or in repeated families relative to the beginning of the repeated family.\n"
+ "\nConstructor::\n\n"
+ " Time(hour,minute,relative<optional> = false)\n"
+ " int hour: hour in 24 clock\n"
+ " int minute: minute <= 59\n"
+ " bool relative<optional>: default = False, Relative to suite start or repeated node.\n\n"
+ " Time(single,relative<optional> = false)\n"
+ " TimeSlot single: A single time\n"
+ " bool relative: Relative to suite start or repeated node. Default is false\n\n"
+ " Time(start,finish,increment,relative<optional> = false)\n"
+ " TimeSlot start: The start time\n"
+ " TimeSlot finish: The finish/end time\n"
+ " TimeSlot increment: The increment\n"
+ " bool relative<optional>: default = False, relative to suite start or repeated node\n\n"
+ " Time(time_series)\n"
+ " TimeSeries time_series:Similar to constructor above\n"
+ "\nExceptions:\n\n"
+ "- raises IndexError when an invalid Time is specified\n"
+ "\nUsage::\n\n"
+ " time = Time( 10,10 ) # time 10:10 \n"
+ " time = Time( TimeSlot(10,10), true) # time +10:10 \n"
+ " time = Time( TimeSlot(10,10), TimeSlot(20,10),TimeSlot(0,10), false ) # time 10:10 20:10 00:10 \n"
+ ;
+}
+
+const char* NodeAttrDoc::today_doc()
+{
+ return
+ ":term:`today` is a time dependency that does not wrap to tomorrow.\n\n"
+ "If the :term:`suite` s begin time is past the time given for the Today,\n"
+ "then the node is free to run.\n"
+ "\nConstructor::\n\n"
+ " Today(hour,minute,relative<optional> = false)\n"
+ " int hour : hour in 24 clock\n"
+ " int minute : minute <= 59\n"
+ " bool relative<optional>: Default = false,Relative to suite start or repeated node.\n\n"
+ " Today(single,relative<optional> = false)\n"
+ " TimeSlot single : A single time\n"
+ " bool relative : Relative to suite start or repeated node. Default is false\n\n"
+ " Today(start,finish,increment,relative<optional> = false)\n"
+ " TimeSlot start : The start time\n"
+ " TimeSlot finish : The finish/end time. This must be greater than the start time.\n"
+ " TimeSlot increment : The increment\n"
+ " bool relative<optional>: Default = false, Relative to suite start or repeated node.\n\n"
+ " Today(time_series)\n"
+ " TimeSeries time_series: Similar to constructor above\n"
+ "\nExceptions:\n\n"
+ "- raises IndexError when an invalid Today is specified\n"
+ "\nUsage::\n\n"
+ " today = Today( 10,10 ) # today 10:10 \n"
+ " today = Today( TimeSlot(10,10) ) # today 10:10 \n"
+ " today = Today( TimeSlot(10,10), true) # today +10:10 \n"
+ " today = Today( TimeSlot(10,10), TimeSlot(20,10),TimeSlot(0,10), false ) # time 10:10 20:10 00:10 \n"
+ ;
+}
+
+const char* NodeAttrDoc::late_doc()
+{
+ return
+ "Sets the :term:`late` flag.\n\n"
+ "When a Node is classified as being late, the only action :term:`ecflow_server` can take\n"
+ "is to set a flag. The GUI will display this alongside the :term:`node` name as a icon.\n"
+ "Only one Late attribute can be specified on a Node.\n"
+ "\nConstructor::\n\n"
+ " Late()\n"
+ "\nUsage::\n\n"
+ " late = Late()\n"
+ " late.submitted( 0,15 )\n"
+ " late.active( 20,0 )\n"
+ " late.complete( 2,0, true )\n\n"
+ "This is interpreted as: The node can stay :term:`submitted` for a maximum of 15 minutes\n"
+ "and it must become :term:`active` by 20:00 and the run time must not exceed 2 hours"
+ ;
+}
+
+const char* NodeAttrDoc::autocancel_doc()
+{
+ return
+ "Provides a way to automatically delete/remove a node which has completed\n\n"
+ "See :term:`autocancel`\n"
+ "\nConstructor::\n\n"
+ " Autocancel(TimeSlot,relative)\n"
+ " TimeSlot single: A time\n"
+ " bool relative: Relative to completion. False means delete the node at the real time specified.\n\n"
+ " Autocancel(hour,minute,relative)\n"
+ " int hour: hour in 24 hrs\n"
+ " int minute: minute <= 59\n"
+ " bool relative: Relative to completion. False means delete the node at the real time specified.\n\n"
+ " Autocancel(days)\n"
+ " int days: Delete the node 'days' after completion\n"
+ "\nUsage::\n\n"
+ " attr = Autocancel( 1,30, true ) # delete node 1 hour and 30 minutes after completion\n"
+ " attr = Autocancel( TimeSlot(0,10), true ) # delete node 10 minutes after completion\n"
+ " attr = Autocancel( TimeSlot(10,10), false ) # delete node at 10:10 after completion\n"
+ " attr = Autocancel( 3 ) # delete node 3 days after completion\n"
+ ;
+}
+
+const char* NodeAttrDoc::repeat_doc()
+{
+ return
+ "Represents one of RepeatString,RepeatEnumerated,RepeatInteger,RepeatDate,RepeatDay\n\n"
+ ;
+}
+
+const char* NodeAttrDoc::repeat_date_doc()
+{
+ return
+ "Allows a :term:`node` to be repeated using a yyyymmdd format\n\n"
+ "A node can only have one :term:`repeat`.\n"
+ "The repeat can be referenced in :term:`trigger` expressions.\n"
+ "\nConstructor::\n\n"
+ " RepeatDate(variable,start,end,delta)\n"
+ " string variable: The name of the repeat. The current date can referenced in\n"
+ " in trigger expressions using the variable name\n"
+ " int start: Start date, must have format: yyyymmdd\n"
+ " int end: End date, must have format: yyyymmdd\n"
+ " int delta<optional>: default = 1, Always in days. The increment used to update the date\n"
+ "\nException:\n\n"
+ "- Throws a RuntimeError if start/end are not valid dates\n"
+ "\nUsage::\n\n"
+ " rep = RepeatDate(\"YMD\", 20050130, 20050203 )\n"
+ " rep = RepeatDate(\"YMD\", 20050130, 20050203, 2 )\n"
+ ;
+}
+
+const char* NodeAttrDoc::repeat_integer_doc()
+{
+ return
+ "Allows a :term:`node` to be repeated using a integer range.\n\n"
+ "A node can only have one :term:`repeat`.\n"
+ "The repeat can be referenced in :term:`trigger` expressions.\n"
+ "\nConstructor::\n\n"
+ " RepeatInteger(variable,start,end,step)\n"
+ " string variable: The name of the repeat. The current integer value can be\n"
+ " referenced in trigger expressions using the variable name\n"
+ " int start: Start integer value\n"
+ " int end: End end integer value\n"
+ " int step<optional>: Default = 1, The step amount\n"
+ "\nUsage::\n\n"
+ " rep = RepeatInteger(\"HOUR\", 6, 24, 6 )\n"
+ ;
+}
+
+const char* NodeAttrDoc::repeat_enumerated_doc()
+{
+ return
+ "Allows a node to be repeated using a enumerated list.\n\n"
+ "A :term:`node` can only have one :term:`repeat`.\n"
+ "The repeat can be referenced in :term:`trigger` expressions.\n"
+ "\nConstructor::\n\n"
+ " RepeatEnumerated(variable,list)\n"
+ " string variable: The name of the repeat. The current enumeration index can be\n"
+ " referenced in trigger expressions using the variable name\n"
+ " vector list: The list of enumerations\n"
+ "\nUsage::\n\n"
+ " rep = RepeatEnumerated(\"COLOR\", [ 'red', 'green', 'blue' ] )\n"
+ ;
+}
+
+const char* NodeAttrDoc::repeat_string_doc()
+{
+ return
+ "Allows a :term:`node` to be repeated using a string list.\n\n"
+ "A :term:`node` can only have one :term:`repeat`.\n"
+ "The repeat can be referenced in :term:`trigger` expressions.\n"
+ "\nConstructor::\n\n"
+ " RepeatString(variable,list)\n"
+ " string variable: The name of the repeat. The current index of the string list can be\n"
+ " referenced in trigger expressions using the variable name\n"
+ " vector list: The list of enumerations\n"
+ "\nUsage::\n\n"
+ " rep = RepeatString(\"COLOR\", [ 'red', 'green', 'blue' ] )\n"
+ ;
+}
+
+const char* NodeAttrDoc::repeat_day_doc()
+{
+ return
+ "A repeat that is infinite.\n\n"
+ "A node can only have one :term:`repeat`.\n"
+ "\nConstructor::\n\n"
+ " RepeatDay(step)\n"
+ " int step: The step.\n"
+ "\nUsage::\n\n"
+ " rep = RepeatDay( 1 )\n"
+ ;
+}
+
+const char* NodeAttrDoc::cron_doc()
+{
+ return
+ ":term:`cron` defines a time dependency for a node.\n\n"
+ "Crons are repeated indefinitely.\n\n"
+ "Avoid having a cron and :term:`repeat` at the same level,\n"
+ "as both provide looping functionality\n"
+ "\nConstructor::\n\n"
+ " Cron()\n"
+ "\nExceptions:\n\n"
+ "- raises IndexError when an invalid cron is specified\n"
+ "\nUsage::\n\n"
+ " cron = ecflow.Cron()\n"
+ " cron.set_week_days([0, 1, 2, 3, 4, 5, 6])\n"
+ " cron.set_days_of_month([1, 2, 3, 4, 5, 6 ])\n"
+ " cron.set_months([1, 2, 3, 4, 5, 6])\n"
+ " start = ecflow.TimeSlot(0 , 0)\n"
+ " finish = ecflow.TimeSlot(23, 0)\n"
+ " incr = ecflow.TimeSlot(0, 30)\n"
+ " ts = ecflow.TimeSeries(start, finish, incr, True) # True means relative to suite start\n"
+ " cron.set_time_series(ts)\n"
+ "\n"
+ " cron1 = ecflow.Cron()\n"
+ " cron1.set_time_series(1, 30, True) # same as cron +01:30\n"
+ "\n"
+ " cron2 = ecflow.Cron()\n"
+ " cron2.set_week_days([0, 1, 2, 3, 4, 5, 6])\n"
+ " cron2.set_time_series(\"00:30 01:30 00:01\")\n"
+ "\n"
+ " cron3 = ecflow.Cron()\n"
+ " cron3.set_week_days([0, 1, 2, 3, 4, 5, 6])\n"
+ " cron3.set_time_series(\"+00:30\")\n"
+ ;
+}
+
+const char* NodeAttrDoc::clock_doc()
+{
+ return
+ "Specifies the :term:`clock` type used by the :term:`suite`.\n\n"
+ "Only suites can have a :term:`clock`.\n"
+ "A gain can be specified to offset from the given date.\n"
+ "\nConstructor::\n\n"
+ " Clock(day,month,year,hybrid)\n"
+ " int day : Specifies the day of the month 1-31\n"
+ " int month : Specifies the month 1-12\n"
+ " int year : Specifies the year > 1400\n"
+ " bool hybrid<optional>: Default = False, true means hybrid, false means real\n"
+ " by default the clock is not real\n\n"
+ " Time will be set to midnight, use set_gain() to alter\n"
+ "\n"
+ " Clock(hybrid)\n"
+ " bool hybrid: true means hybrid, false means real\n"
+ " by default the clock is real\n"
+ " Time will be set real time of the computer\n"
+ "\n"
+ "\nExceptions:\n\n"
+ "- raises IndexError when an invalid Clock is specified\n"
+ "\nUsage::\n\n"
+ " suite = Suite('s1')\n"
+ " clock = Clock(1,1,2012,False)\n"
+ " clock.set_gain(1,10,True)\n"
+ " suite.add_clock(clock)\n"
+ ;
+}
diff --git a/Pyext/src/NodeAttrDoc.hpp b/Pyext/src/NodeAttrDoc.hpp
new file mode 100644
index 0000000..d4e7e69
--- /dev/null
+++ b/Pyext/src/NodeAttrDoc.hpp
@@ -0,0 +1,54 @@
+#ifndef NODE_ATTR_DOC_HPP_
+#define NODE_ATTR_DOC_HPP_
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #8 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+#include <boost/noncopyable.hpp>
+
+// ===========================================================================
+// IMPORTANT: These appear as python doc strings.
+// Additionally they are auto documented using sphinx-poco
+// Hence the doc strings use reStructuredText markup
+// ===========================================================================
+class NodeAttrDoc : private boost::noncopyable {
+public:
+ static const char* variable_doc();
+ static const char* zombie_doc();
+ static const char* zombie_type_doc();
+ static const char* zombie_user_action_type_doc();
+ static const char* child_cmd_type_doc();
+ static const char* label_doc();
+ static const char* limit_doc();
+ static const char* inlimit_doc();
+ static const char* event_doc();
+ static const char* meter_doc();
+ static const char* date_doc();
+ static const char* day_doc();
+ static const char* days_enum_doc();
+ static const char* time_doc();
+ static const char* today_doc();
+ static const char* late_doc();
+ static const char* autocancel_doc();
+ static const char* repeat_doc();
+ static const char* repeat_date_doc();
+ static const char* repeat_integer_doc();
+ static const char* repeat_enumerated_doc();
+ static const char* repeat_string_doc();
+ static const char* repeat_day_doc();
+ static const char* cron_doc();
+ static const char* clock_doc();
+private:
+ NodeAttrDoc(){}
+};
+#endif
diff --git a/Pyext/test/CleanupOnlineTutorial.py b/Pyext/test/CleanupOnlineTutorial.py
new file mode 100644
index 0000000..bfa1f4e
--- /dev/null
+++ b/Pyext/test/CleanupOnlineTutorial.py
@@ -0,0 +1,28 @@
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+import os
+
+# clean up any file after running the online tutorial examples
+# Place in separate exception, otherwise not all files will be removed
+try: os.remove("test.def")
+except: pass
+
+try: os.remove("TestSuite.def")
+except: pass
+
+try: os.remove("SuiteBuilder.def")
+except: pass
+
+try: os.remove("server.defs")
+except: pass
diff --git a/ecflow_4_0_7/Pyext/test/TestEmbedded.cpp b/Pyext/test/TestEmbedded.cpp
similarity index 100%
rename from ecflow_4_0_7/Pyext/test/TestEmbedded.cpp
rename to Pyext/test/TestEmbedded.cpp
diff --git a/Pyext/test/TestEmbeddedEcf.cpp b/Pyext/test/TestEmbeddedEcf.cpp
new file mode 100644
index 0000000..ab71940
--- /dev/null
+++ b/Pyext/test/TestEmbeddedEcf.cpp
@@ -0,0 +1,84 @@
+//// Commented out since we *dont* use embedded python
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+//#include <boost/python.hpp>
+//#include <boost/detail/lightweight_test.hpp>
+//#include "boost/filesystem/operations.hpp"
+//#include "boost/filesystem/path.hpp"
+//#include <iostream>
+//
+//namespace fs = boost::filesystem;
+//namespace python = boost::python;
+//
+//// init_defs is defined in BOOST_PYTHON_MODULE(_defs) in file EcfDefsExt.cpp
+//// However we need definition here. Hence expanded the pertinent contents of
+//// BOOST_PYTHON_MODULE
+//extern "C" __attribute__ ((visibility("default"))) void initecflow();
+//
+//void exec_test()
+//{
+// std::cout << "registering extension module ecflow..." << std::endl;
+//
+// // Register the module with the interpreter
+// if (PyImport_AppendInittab((char*)"_defs", initecflow) == -1)
+// throw std::runtime_error("Failed to add _defs to the interpreter's built in modules");
+//
+// std::cout << "defining Defs..." << std::endl;
+//
+// // Retrieve the main module
+// python::object main = python::import("__main__");
+//
+// // Retrieve the main module's namespace
+// python::object global(main.attr("__dict__"));
+//
+// // Define Defs in Python.
+// python::object result = python::exec(
+// "from ecflow import *\n"
+// "file = 'embedded.def'\n"
+// "defs = Defs(file)\n"
+// "suite = Suite('s1')\n"
+// "family = Family('f1')\n"
+// "for i in [ '_1', '_2', '_3' ]: family.add_task( Task( 't' + i) ) \n"
+// "defs.add_suite(suite); \n"
+// "suite.add_family(family)\n"
+// "defs.save_as_defs("embedded.def")\n",
+// global, global);
+//
+// // Check it worked by looking for the presence of embedded.def file
+// BOOST_TEST(fs::exists("embedded.def") );
+// fs::remove("embedded.def");
+//
+// std::cout << "success!" << std::endl;
+//}
+//
+//int main(int argc, char **argv)
+//{
+// // Initialize the interpreter
+// Py_Initialize();
+//
+// if ( python::handle_exception(exec_test) )
+// {
+// if (PyErr_Occurred())
+// {
+// PyErr_Print();
+// }
+// else
+// {
+// BOOST_ERROR("A C++ exception was thrown for which "
+// "there was no exception translator registered.");
+// }
+// }
+//
+// // Boost.Python doesn't support Py_Finalize yet, so don't call it!
+// return boost::report_errors();
+//}
diff --git a/ecflow_4_0_7/Pyext/test/data/.gitignore b/Pyext/test/data/.gitignore
similarity index 100%
rename from ecflow_4_0_7/Pyext/test/data/.gitignore
rename to Pyext/test/data/.gitignore
diff --git a/ecflow_4_0_7/Pyext/test/data/ECF_HOME/suite_job_gen/family/t1.ecf b/Pyext/test/data/ECF_HOME/suite_job_gen/family/t1.ecf
similarity index 100%
rename from ecflow_4_0_7/Pyext/test/data/ECF_HOME/suite_job_gen/family/t1.ecf
rename to Pyext/test/data/ECF_HOME/suite_job_gen/family/t1.ecf
diff --git a/ecflow_4_0_7/Pyext/test/data/ECF_HOME/suite_job_gen/family/t2.ecf b/Pyext/test/data/ECF_HOME/suite_job_gen/family/t2.ecf
similarity index 100%
rename from ecflow_4_0_7/Pyext/test/data/ECF_HOME/suite_job_gen/family/t2.ecf
rename to Pyext/test/data/ECF_HOME/suite_job_gen/family/t2.ecf
diff --git a/ecflow_4_0_7/Pyext/test/data/ECF_HOME/suite_job_gen/family/t3.ecf b/Pyext/test/data/ECF_HOME/suite_job_gen/family/t3.ecf
similarity index 100%
rename from ecflow_4_0_7/Pyext/test/data/ECF_HOME/suite_job_gen/family/t3.ecf
rename to Pyext/test/data/ECF_HOME/suite_job_gen/family/t3.ecf
diff --git a/Pyext/test/data/includes/head.h b/Pyext/test/data/includes/head.h
new file mode 100755
index 0000000..f044408
--- /dev/null
+++ b/Pyext/test/data/includes/head.h
@@ -0,0 +1,45 @@
+#!/bin/ksh
+
+set -e # stop the shell on first error
+set -u # fail when using an undefined variable
+set -x # echo script lines as they are executed
+
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+# Defines the variables that are needed for any
+# communication with ECF_
+
+export ECF_PORT=%ECF_PORT% # ECF portnumber
+export ECF_NODE=%ECF_NODE% # The name host that issued this task
+export ECF_NAME=%ECF_NAME% # The name of this current task
+export ECF_PASS=%ECF_PASS% # A unique password
+export ECF_TRYNO=%ECF_TRYNO% # Current try number of the task
+
+# Tell ECF_ we have stated
+# The ECF_ variable ECF_RID will be set to parameter of init
+# Here we give the current PID.
+
+%ECF_CLIENT_EXE_PATH:ecflow_client% --init=$$
+
+# Defined a error hanlder
+
+ERROR() {
+ set +e # Clear -e flag, so we don't fail
+ wait # wait for background process to stop
+ %ECF_CLIENT_EXE_PATH:ecflow_client% --abort # Notify ECF_ that something went wrong
+ trap 0 # Remove the trap
+ exit 0 # End the script
+}
+
+# Trap any calls to exit and errors caught by the -e flag
+
+trap ERROR 0
+
+# Trap any signal that may cause the script to fail
+
+trap '{ echo "Killed by a signal"; ERROR ; }' 1 2 3 4 5 6 7 8 10 12 13 15
diff --git a/ecflow_4_0_7/Pyext/test/data/includes/tail.h b/Pyext/test/data/includes/tail.h
similarity index 100%
rename from ecflow_4_0_7/Pyext/test/data/includes/tail.h
rename to Pyext/test/data/includes/tail.h
diff --git a/ecflow_4_0_7/Pyext/test/data/python_includes/head.py b/Pyext/test/data/python_includes/head.py
similarity index 100%
rename from ecflow_4_0_7/Pyext/test/data/python_includes/head.py
rename to Pyext/test/data/python_includes/head.py
diff --git a/ecflow_4_0_7/Pyext/test/data/python_includes/tail.py b/Pyext/test/data/python_includes/tail.py
similarity index 100%
rename from ecflow_4_0_7/Pyext/test/data/python_includes/tail.py
rename to Pyext/test/data/python_includes/tail.py
diff --git a/Pyext/test/ecflow_test_util.py b/Pyext/test/ecflow_test_util.py
new file mode 100644
index 0000000..5fce541
--- /dev/null
+++ b/Pyext/test/ecflow_test_util.py
@@ -0,0 +1,223 @@
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#
+# Utility code used in the tests.
+#
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+from socket import gethostname
+import os
+import fcntl
+import shutil # used to remove directory tree
+
+from ecflow import Client, debug_build, File
+
+# Enable to stop data being deleted, and stop server from being terminated
+def debugging() : return False
+
+def ecf_home(port):
+ # debug_build() is defined for ecflow. Used in test to distinguish debug/release ecflow
+ # Vary ECF_HOME based on debug/release/port allowing multiple invocations of these tests
+ if debug_build():
+ return os.getcwd() + "/test/data/ecf_home_debug_" + str(port)
+ return os.getcwd() + "/test/data/ecf_home_release_" + str(port)
+
+def get_parent_dir(file_path):
+ return os.path.dirname(file_path)
+
+def get_root_source_dir():
+ cwd = os.getcwd()
+ #print "get_root_source_dir from: " + cwd
+ while (1):
+ # Get to directory that has ecflow
+ head, tail = os.path.split(cwd)
+ #print " head:" + head
+ #print " tail:" + tail
+ if tail.find("ecflow") != -1 :
+
+ # bjam, already at the source directory
+ if os.path.exists(cwd + "/VERSION.cmake"):
+ print " Found VERSION.cmake in " + cwd
+ return cwd
+
+ if tail != "Pyext" and tail != "migrate":
+ # in cmake, we may be in the build directory, hence we need to determine source directory
+ file = cwd + "/CTestTestfile.cmake"
+ #print " searching for " + file
+ if os.path.exists(file):
+ # determine path by looking into this file:
+ for line in open(file):
+ ## Source directory: /tmp/ma0/workspace/ecflow/Acore
+ if line.find("Source directory"):
+ tokens = line.split()
+ if len(tokens) == 4:
+ #print " returning root_source_dir:", tokens[3]
+ return tokens[3]
+ raise RuntimeError("ERROR could not find Source directory in CTestTestfile.cmake")
+ else:
+ raise RuntimeError("ERROR could not find file CTestTestfile.cmake in " + cwd)
+
+ cwd = head
+ return cwd
+
+
+def log_file_path(port): return "./" + gethostname() + "." + port + ".ecf.log"
+def checkpt_file_path(port): return "./" + gethostname() + "." + port + ".ecf.check"
+def backup_checkpt_file_path(port): return "./" + gethostname() + "." + port + ".ecf.check.b"
+def white_list_file_path(port): return "./" + gethostname() + "." + port + ".ecf.lists"
+
+def clean_up_server(port):
+ print " clean_up " + port
+ try: os.remove(log_file_path(port))
+ except: pass
+ try: os.remove(checkpt_file_path(port))
+ except: pass
+ try: os.remove(backup_checkpt_file_path(port))
+ except: pass
+ try: os.remove(white_list_file_path(port))
+ except: pass
+
+def clean_up_data(port):
+ print " Attempting to Removing ECF_HOME " + ecf_home(port)
+ try:
+ shutil.rmtree(ecf_home(port),True) # True means ignore errors
+ print " Remove OK"
+ except:
+ print " Remove Failed"
+ pass
+
+# =======================================================================================
+class EcfPortLock(object):
+ """allow debug and release version of python tests to run at the same
+ time, buy generating a unique port each time"""
+ def __init__(self):
+ print " EcfPortLock:__init__"
+ pass
+
+ def find_free_port(self,seed_port):
+ print " EcfPortLock:find_free_port starting with " + str(seed_port)
+ port = seed_port
+ while 1:
+ if self._free_port(port) == True:
+ print " *FOUND* free server port " + str(port)
+ if self._do_lock(port) == True:
+ break;
+ else:
+ print " *Server* port " + str(port) + " busy, trying next port"
+ port = port + 1
+
+ return str(port)
+
+ def _free_port(self,port):
+ try:
+ ci = Client()
+ ci.set_host_port("localhost",str(port))
+ ci.ping()
+ return False
+ except RuntimeError, e:
+ return True
+
+ def _do_lock(self,port):
+ file = self._lock_file(port)
+ try:
+ fp = open(file, 'w')
+ try:
+ fcntl.lockf(fp, fcntl.LOCK_EX | fcntl.LOCK_NB)
+ self.lock_file_fp = fp
+ print " *LOCKED* file " + file
+ return True;
+ except IOError:
+ print " Could *NOT* lock file " + file + " trying next port"
+ return False
+ except IOError, e:
+ print " Could not open file " + file + " for write trying next port"
+ return False
+
+ def remove(self,port):
+ self.lock_file_fp.close()
+ os.remove(self._lock_file(port))
+
+ def _lock_file(self,port):
+ lock_file = str(port) + ".lock"
+ return lock_file
+
+# ===============================================================================
+
+class Server(object):
+ """TestServer: allow debug and release version of python tests to run at the same
+ time, by generating a unique port each time"""
+ def __init__(self):
+ print "Server:__init__: Starting server"
+ if not debugging():
+ seed_port = 3153
+ if debug_build(): seed_port = 3152
+ self.lock_file = EcfPortLock()
+ self.the_port = self.lock_file.find_free_port(seed_port)
+ else:
+ self.the_port = "3152"
+
+ # Only worth doing this test, if the server is running
+ # ON HPUX, having only one connection attempt, sometimes fails
+ #ci.set_connection_attempts(1) # improve responsiveness only make 1 attempt to connect to server
+ #ci.set_retry_connection_period(0) # Only applicable when make more than one attempt. Added to check api.
+ self.ci = Client("localhost", self.the_port)
+
+ def __enter__(self):
+ try:
+ print "Server:__enter__: About to ping localhost:" + self.the_port
+ self.ci.ping()
+ print " ------- Server all ready running *UNEXPECTED* ------"
+ except RuntimeError, e:
+ print " ------- Server not running as *EXPECTED* ------ "
+ print " ------- Start the server on port " + self.the_port + " ---------"
+ clean_up_server(str(self.the_port))
+ clean_up_data(str(self.the_port))
+
+ server_exe = File.find_server();
+ assert len(server_exe) != 0, "Could not locate the server executable"
+
+ server_exe += " --port=" + self.the_port + " --ecfinterval=4 &"
+ print " TestClient.py: Starting server ", server_exe
+ os.system(server_exe)
+
+ print " Allow time for server to start"
+ if self.ci.wait_for_server_reply() :
+ print " Server has started"
+ else:
+ print " Server failed to start after 60 second !!!!!!"
+ assert False , "Server failed to start after 60 second !!!!!!"
+
+ print " Run the tests, leaving Server:__enter__:"
+
+ # return the Client, that can call to the server
+ return self.ci
+
+ def __exit__(self,exctype,value,tb):
+ print " Server:__exit__: Kill the server, clean up log file, check pt files and lock files, ECF_HOME"
+ print " exctype:==================================================="
+ print exctype
+ print " value:====================================================="
+ print value
+ print " tb:========================================================";
+ print tb
+ print " Terminate server ===================================================="
+ self.ci.terminate_server()
+ print " Terminate server OK ================================================="
+ print " Remove lock file"
+ self.lock_file.remove(self.the_port)
+ clean_up_server(str(self.the_port))
+
+ # Do not clean up data, if an assert was raised. This allow debug
+ if exctype == None:
+ clean_up_data(str(self.the_port))
+ return False
+
+
\ No newline at end of file
diff --git a/Pyext/test/py_s_TestClientApi.py b/Pyext/test/py_s_TestClientApi.py
new file mode 100644
index 0000000..ca3c87a
--- /dev/null
+++ b/Pyext/test/py_s_TestClientApi.py
@@ -0,0 +1,1570 @@
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# code for testing client code in python
+import time
+import os
+import pwd
+from datetime import datetime
+import shutil # used to remove directory tree
+
+# ecflow_test_util, see File ecflow_test_util.py
+import ecflow_test_util as Test
+from ecflow import Defs, Clock, DState, Style, State, RepeatDate, PrintStyle, File, Client, SState, \
+ JobCreationCtrl, CheckPt, Cron, Late, debug_build
+#from __builtin__ import None
+
+def ecf_includes() : return os.getcwd() + "/test/data/includes"
+
+def create_defs(name=""):
+ defs = Defs()
+ suite_name = name
+ if len(suite_name) == 0: suite_name = "s1"
+ suite = defs.add_suite(suite_name);
+
+ ecfhome = Test.ecf_home(the_port);
+ suite.add_variable("ECF_HOME", ecfhome);
+ suite.add_variable("ECF_CLIENT_EXE_PATH", File.find_client());
+ suite.add_variable("SLEEP", "1"); # not strictly required since default is 1 second
+ suite.add_variable("ECF_INCLUDE", ecf_includes());
+
+ family = suite.add_family("f1")
+ family.add_task("t1")
+ family.add_task("t2")
+ return defs;
+
+def test_host_port(ci,host,port):
+ try :
+ ci.set_host_port(host,port)
+ return True
+ except RuntimeError:
+ return False
+
+def test_host_port_(ci,host_port):
+ try :
+ ci.set_host_port(host_port)
+ return True
+ except RuntimeError:
+ return False
+
+def test_client_host_port(host,port):
+ try :
+ Client(host,port)
+ return True
+ except RuntimeError:
+ return False
+
+def test_client_host_port_(host_port):
+ try :
+ Client(host_port)
+ return True
+ except RuntimeError:
+ return False
+
+def test_set_host_port():
+ print "test_set_host_port"
+ ci = Client();
+ print " Client.get_host() = " + ci.get_host()
+ print " Client.get_port() = " + ci.get_port()
+ assert test_host_port(ci,"host","3141") , "Expected no errors"
+ assert test_host_port(ci,"host",4444) , "Expected no errors"
+ assert test_host_port_(ci,"host:4444") , "Expected no errors"
+ assert test_host_port(ci,"","") == False , "Expected errors"
+ assert test_host_port(ci,"host","") == False , "Expected errors"
+ assert test_host_port(ci,"host","host") == False , "Expected errors"
+ assert test_host_port_(ci,"host:host") == False , "Expected errors"
+ assert test_host_port_(ci,"3141:host") == False , "Expected errors"
+
+ assert test_client_host_port("host","3141") , "Expected no errors"
+ assert test_client_host_port("host",4444) , "Expected no errors"
+ assert test_client_host_port_("host:4444") , "Expected no errors"
+ assert test_client_host_port("","") == False , "Expected errors"
+ assert test_client_host_port("host","") == False , "Expected errors"
+ assert test_client_host_port("host","host") == False , "Expected errors"
+ assert test_client_host_port_("host:host") == False , "Expected errors"
+ assert test_client_host_port_("3141:host") == False , "Expected errors"
+
+def test_version(ci):
+ client_version = ci.version();
+ server_version = ci.server_version();
+ assert client_version == server_version, "Expected client version(" + client_version +") and server version(" + server_version + ") to match\n";
+
+def test_client_get_server_defs(ci):
+ print "Client version is " + ci.version();
+ print "test_client_get_server_defs"
+ ci.delete_all() # start fresh
+ ci.load(create_defs())
+ ci.get_server_defs()
+ assert ci.get_defs().find_suite("s1") != None, "Expected to find suite of name s1:\n" + str(ci.get_defs())
+
+ ci.delete_all() # start fresh
+ ci.load(create_defs())
+ ci.sync_local()
+ assert ci.get_defs().find_suite("s1") != None, "Expected to find suite of name s1:\n" + str(ci.get_defs())
+
+
+def test_client_new_log(ci, port):
+ print "test_client_new_log"
+ try : os.remove("./test_client_new_log.log") # delete file if it exists
+ except: pass
+
+ ci.new_log("./test_client_new_log.log")
+ ci.flush_log() # close log file and force write to disk
+ assert os.path.exists("./test_client_new_log.log"), "New log does not exist"
+
+ # reset new log to original
+ ci.new_log(Test.log_file_path(port))
+ ci.ping()
+ ci.flush_log() # close log file and force write to disk
+ log_file = open(Test.log_file_path(port))
+ try: log_text = log_file.read(); # assume log file not to big
+ finally: log_file.close();
+ assert log_text.find("--ping") != -1, "Expected to find --ping in log file"
+ try: os.remove("./test_client_new_log.log")
+ except: pass
+
+
+def test_client_clear_log(ci, port):
+ print "test_client_clear_log"
+ # populate log
+ ci.ping();
+ ci.ping();
+ ci.flush_log() # close log file and force write to disk
+ log_file = open(Test.log_file_path(port))
+ try: log_text = log_file.read(); # assume log file not to big
+ finally: log_file.close();
+ assert log_text.find("--ping") != -1, "Expected to find --ping in log file"
+
+ ci.clear_log()
+ log_file = open(Test.log_file_path(port))
+ try: log_text = log_file.read(); # assume log file not to big
+ finally: log_file.close();
+ assert len(log_text) == 0, "Expected log file to be empty but found " + log_text
+
+
+def test_client_log_msg(ci, port):
+ print "test_client_log_msg"
+ # Send a message to the log file, then make sure it was written
+ ci.log_msg("Humpty dumpty sat on a wall!")
+ ci.flush_log(); # flush and close log file, so we can open it
+ log_file = open(Test.log_file_path(port))
+ try: log_text = log_file.read(); # assume log file not to big
+ finally: log_file.close();
+ assert log_text.find("Humpty dumpty sat on a wall!") != -1, "Expected to find Humpty dumpty in the log file"
+
+
+def test_client_restart_server(ci):
+ print "test_client_restart_server"
+ ci.restart_server()
+ ci.sync_local()
+ assert ci.get_defs().get_server_state() == SState.RUNNING, "Expected server to be running"
+
+ paths = list(ci.changed_node_paths)
+ assert len(paths) == 1, "expected changed node to be the root node"
+ assert paths[0] == "/", "Expected root path but found " + str(paths[0])
+
+def test_client_halt_server(ci):
+ print "test_client_halt_server"
+ ci.halt_server()
+ ci.sync_local()
+ assert ci.get_defs().get_server_state() == SState.HALTED, "Expected server to be halted"
+
+ paths = list(ci.changed_node_paths)
+ assert len(paths) == 1, "expected changed node to be the root node"
+ assert paths[0] == "/", "Expected root path but found " + str(paths[0])
+
+def test_client_shutdown_server(ci):
+ print "test_client_shutdown_server"
+ ci.shutdown_server()
+ ci.sync_local()
+ assert ci.get_defs().get_server_state() == SState.SHUTDOWN, "Expected server to be shutdown"
+
+ paths = list(ci.changed_node_paths)
+ assert len(paths) == 1, "expected changed node to be the root node"
+ assert paths[0] == "/", "Expected root path but found " + str(paths[0])
+
+
+def test_client_load_in_memory_defs(ci):
+ print "test_client_load_in_memory_defs"
+ ci.delete_all() # start fresh
+ ci.load(create_defs())
+ ci.sync_local()
+ assert ci.get_defs().find_suite("s1") != None, "Expected to find suite of name s1:\n" + str(ci.get_defs())
+
+
+def test_client_load_from_disk(ci):
+ print "test_client_load_from_disk"
+ ci.delete_all() # start fresh
+ defs = create_defs();
+ defs_file = "test_client_load_from_disk.def"
+ defs.save_as_defs(defs_file)
+ assert os.path.exists(defs_file), "Expected file " + defs_file + " to exist after defs.save_as_defs()"
+ ci.load(defs_file) # open and parse defs file, and load into server.\n"
+
+ # check load worked
+ ci.sync_local()
+ assert ci.get_defs().find_suite("s1") != None, "Expected to find suite of name s1:\n" + str(ci.get_defs())
+ os.remove(defs_file)
+
+
+def test_client_checkpt(ci, port):
+ print "test_client_checkpt"
+ # start fresh
+ ci.delete_all()
+ try:
+ os.remove(Test.checkpt_file_path(port))
+ os.remove(Test.backup_checkpt_file_path(port))
+ except: pass
+
+ ci.load(create_defs())
+ ci.checkpt()
+ assert os.path.exists(Test.checkpt_file_path(port)), "Expected check pt file to exist after ci.checkpt()"
+ assert os.path.exists(Test.backup_checkpt_file_path(port)) == False, "Expected back up check pt file to *NOT* exist"
+
+ ci.checkpt() # second check pt should cause backup check pt to be written
+ assert os.path.exists(Test.backup_checkpt_file_path(port)), "Expected back up check pt file to exist after second ci.checkpt()"
+
+ ci.checkpt(CheckPt.NEVER) # switch of check pointing
+ ci.checkpt(CheckPt.ALWAYS) # always check point, at any state change
+ ci.checkpt(CheckPt.ON_TIME) # Check point periodically, by interval set in server
+ ci.checkpt(CheckPt.ON_TIME, 200) # Check point periodically, by interval set in server
+ ci.checkpt(CheckPt.UNDEFINED, 0, 35) # Change check point save time alarm
+
+ os.remove(Test.checkpt_file_path(port))
+ os.remove(Test.backup_checkpt_file_path(port))
+
+
+def test_client_restore_from_checkpt(ci, port):
+ print "test_client_restore_from_checkpt"
+ # start fresh
+ ci.delete_all()
+ try:
+ os.remove(Test.checkpt_file_path(port))
+ os.remove(Test.backup_checkpt_file_path(port))
+ except: pass
+
+ ci.load(create_defs())
+ ci.checkpt()
+ ci.delete_all()
+
+ ci.sync_local()
+ assert ci.get_defs().find_suite("s1") == None, "Expected all suites to be delete:\n"
+
+ ci.halt_server() # server must be halted, otherwise restore_from_checkpt will throw
+ ci.restore_from_checkpt()
+
+ ci.sync_local()
+ assert ci.get_defs().find_suite("s1") != None, "Expected to find suite s1 after restore from checkpt:\n" + str(ci.get_defs())
+
+ os.remove(Test.checkpt_file_path(port))
+
+
+def get_username(): return pwd.getpwuid(os.getuid())[ 0 ]
+
+def test_client_reload_wl_file(ci, port):
+ print "test_client_reload_wl_file"
+
+ expected = False
+ try: ci.reload_wl_file();
+ except: expected = True
+ assert expected, "Expected reload to fail when no white list specified"
+
+ # create a white list file
+ wl_file = open(Test.white_list_file_path(port), 'w')
+ wl_file.write("#\n")
+ wl_file.write("4.4.14 # comment\n\n")
+ wl_file.write("# These user have read and write access to the server\n")
+ wl_file.write(get_username() + "\n") # add current user otherwise remaining test's, wont have access from server anymore
+ wl_file.write("axel # admin\n")
+ wl_file.write("john # admin\n\n")
+ wl_file.write("# Read only users\n")
+ wl_file.write("-fred # needs read access only\n")
+ wl_file.write("-joe90 # needs read access only\n")
+ wl_file.close();
+
+ ci.reload_wl_file();
+ os.remove(Test.white_list_file_path(port))
+
+
+def test_client_run(ci):
+ print "test_client_run"
+ ci.delete_all()
+ defs = create_defs("test_client_run")
+ suite = defs.find_suite("test_client_run")
+ suite.add_defstatus(DState.suspended)
+
+ defs.generate_scripts();
+
+ job_ctrl = JobCreationCtrl()
+ defs.check_job_creation(job_ctrl)
+ assert len(job_ctrl.get_error_msg()) == 0, job_ctrl.get_error_msg()
+
+ ci.restart_server()
+ ci.load(defs)
+ ci.begin_all_suites()
+ ci.run("/test_client_run", False)
+
+ count = 0
+ while 1:
+ count += 1
+ ci.sync_local() # get the changes, synced with local defs
+ suite = ci.get_defs().find_suite("test_client_run")
+ assert suite != None, "Expected to find suite test_client_run:\n" + str(ci.get_defs())
+ if suite.get_state() == State.complete:
+ break;
+ time.sleep(3)
+ if count > 20:
+ assert False, "test_client_run aborted after " + str(count) + " loops:\n" + str(ci.get_defs())
+
+ ci.log_msg("Looped " + str(count) + " times")
+
+ dir_to_remove = Test.ecf_home(the_port) + "/" + "test_client_run"
+ shutil.rmtree(dir_to_remove)
+
+def test_client_run_with_multiple_paths(ci):
+ print "test_client_run_with_multiple_paths"
+ ci.delete_all()
+ defs = create_defs("test_client_run_with_multiple_paths")
+ suite = defs.find_suite("test_client_run_with_multiple_paths")
+ suite.add_defstatus(DState.suspended)
+
+ defs.generate_scripts();
+
+ job_ctrl = JobCreationCtrl()
+ defs.check_job_creation(job_ctrl)
+ assert len(job_ctrl.get_error_msg()) == 0, job_ctrl.get_error_msg()
+
+ ci.restart_server()
+ ci.load(defs)
+ ci.begin_all_suites()
+ path_list = [ "/test_client_run_with_multiple_paths/f1/t1", "/test_client_run_with_multiple_paths/f1/t2"]
+ ci.run( path_list, False)
+
+ count = 0
+ while 1:
+ count += 1
+ ci.sync_local() # get the changes, synced with local defs
+ suite = ci.get_defs().find_suite("test_client_run_with_multiple_paths")
+ assert suite != None, "Expected to find suite test_client_run_with_multiple_paths:\n" + str(ci.get_defs())
+ if suite.get_state() == State.complete:
+ break;
+ time.sleep(3)
+ if count > 20:
+ assert False, "test_client_run_with_multiple_paths aborted after " + str(count) + " loops:\n" + str(ci.get_defs())
+
+ ci.log_msg("Looped " + str(count) + " times")
+
+ dir_to_remove = Test.ecf_home(the_port) + "/" + "test_client_run_with_multiple_paths"
+ shutil.rmtree(dir_to_remove)
+
+
+def test_client_requeue(ci):
+ print "test_client_requeue"
+ ci.delete_all()
+ defs = create_defs("test_client_requeue")
+ suite = defs.find_suite("test_client_requeue")
+ suite.add_defstatus(DState.suspended)
+
+ defs.generate_scripts();
+ job_ctrl = JobCreationCtrl()
+ defs.check_job_creation(job_ctrl)
+ assert len(job_ctrl.get_error_msg()) == 0, job_ctrl.get_error_msg()
+
+ ci.restart_server()
+ ci.load(defs)
+ ci.begin_all_suites()
+
+ ci.force_state_recursive("/test_client_requeue",State.unknown)
+ ci.sync_local();
+ suite = ci.get_defs().find_suite("test_client_requeue")
+ assert suite.get_state() == State.unknown, "Expected to find suite with state unknown"
+
+ ci.requeue("/test_client_requeue")
+ ci.sync_local();
+ suite = ci.get_defs().find_suite("test_client_requeue")
+ assert suite.get_state() == State.queued, "Expected to find suite with state queued"
+
+ dir_to_remove = Test.ecf_home(the_port) + "/" + "test_client_requeue"
+ shutil.rmtree(dir_to_remove)
+
+def test_client_requeue_with_multiple_paths(ci):
+ print "test_client_requeue_with_multiple_paths"
+ ci.delete_all()
+ defs = create_defs("test_client_requeue_with_multiple_paths")
+ suite = defs.find_suite("test_client_requeue_with_multiple_paths")
+ suite.add_defstatus(DState.suspended)
+
+ defs.generate_scripts();
+ job_ctrl = JobCreationCtrl()
+ defs.check_job_creation(job_ctrl)
+ assert len(job_ctrl.get_error_msg()) == 0, job_ctrl.get_error_msg()
+
+ ci.restart_server()
+ ci.load(defs)
+ ci.begin_all_suites()
+
+ ci.force_state_recursive("/test_client_requeue_with_multiple_paths",State.unknown)
+ ci.sync_local();
+ task1 = ci.get_defs().find_abs_node("/test_client_requeue_with_multiple_paths/f1/t1")
+ task2 = ci.get_defs().find_abs_node("/test_client_requeue_with_multiple_paths/f1/t2")
+ assert task1.get_state() == State.unknown, "Expected to find t1 with state unknown"
+ assert task2.get_state() == State.unknown, "Expected to find t2 with state unknown"
+
+ path_list = [ "/test_client_requeue_with_multiple_paths/f1/t1", "/test_client_requeue_with_multiple_paths/f1/t2" ]
+ ci.requeue( path_list)
+ ci.sync_local();
+ task1 = ci.get_defs().find_abs_node("/test_client_requeue_with_multiple_paths/f1/t1")
+ task2 = ci.get_defs().find_abs_node("/test_client_requeue_with_multiple_paths/f1/t2")
+ assert task1.get_state() == State.queued, "Expected to find task t1 with state queued"
+ assert task2.get_state() == State.queued, "Expected to find task t2 with state queued"
+
+ dir_to_remove = Test.ecf_home(the_port) + "/" + "test_client_requeue_with_multiple_paths"
+ shutil.rmtree(dir_to_remove)
+
+
+def test_client_free_dep(ci):
+ print "test_client_free_dep"
+ ci.delete_all()
+
+ # add a real clock, since we are adding date dependencies
+ # Note: adding a future time dependency on a task, will cause it to requeue, when complete
+ # Hence even when we free these dependency they get requeued.
+ # So we use todays date.
+ ltime = time.localtime();
+ day = ltime.tm_mday
+ month = ltime.tm_mon
+ year = ltime.tm_year
+
+ defs = Defs()
+ suite = defs.add_suite("test_client_free_dep");
+ suite.add_clock(Clock(False)) # true means hybrid, False means real
+ ecfhome = Test.ecf_home(the_port);
+ suite.add_variable("ECF_HOME", ecfhome);
+ suite.add_variable("ECF_CLIENT_EXE_PATH", File.find_client());
+ suite.add_variable("SLEEPTIME", "1");
+ suite.add_variable("ECF_INCLUDE", ecf_includes());
+ family = suite.add_family("f1")
+ family.add_task("t1").add_time("00:01")
+ family.add_task("t2").add_date(day,month,year)
+ family.add_task("t3").add_trigger("1 == 0")
+ t4 = family.add_task("t4")
+ t4.add_time("00:01")
+ t4.add_date(day,month,year)
+ t4.add_trigger("1 == 0")
+
+ defs.generate_scripts();
+
+ job_ctrl = JobCreationCtrl()
+ defs.check_job_creation(job_ctrl)
+ assert len(job_ctrl.get_error_msg()) == 0, job_ctrl.get_error_msg()
+
+ ci.restart_server()
+ ci.load(defs)
+ ci.begin_all_suites()
+
+ t1_path = "/test_client_free_dep/f1/t1"
+ t2_path = "/test_client_free_dep/f1/t2"
+ t3_path = "/test_client_free_dep/f1/t3"
+ t4_path = "/test_client_free_dep/f1/t4"
+ while 1:
+ ci.sync_local()
+ t1 = ci.get_defs().find_abs_node(t1_path)
+ t2 = ci.get_defs().find_abs_node(t2_path)
+ t3 = ci.get_defs().find_abs_node(t3_path)
+ t4 = ci.get_defs().find_abs_node(t4_path)
+
+ if t1.get_state() == State.queued: ci.free_time_dep(t1_path)
+ if t2.get_state() == State.queued: ci.free_date_dep(t2_path)
+ if t3.get_state() == State.queued: ci.free_trigger_dep(t3_path)
+ if t4.get_state() == State.queued: ci.free_all_dep(t4_path)
+
+ suite = ci.get_defs().find_suite("test_client_free_dep")
+ if suite.get_state() == State.complete:
+ break;
+ time.sleep(3)
+
+ dir_to_remove = Test.ecf_home(the_port) + "/" + "test_client_free_dep"
+ shutil.rmtree(dir_to_remove)
+
+
+def test_client_stats(ci):
+ print "test_client_stats"
+ ci.stats() # writes to standard out
+
+def test_client_stats_reset(ci):
+ print "test_client_stats_reset"
+ ci.stats_reset()
+ ci.stats() # should produce no ouput, where we measure requests
+
+def test_client_debug_server_on_off(ci):
+ print "test_client_debug_server_on_off"
+ ci.debug_server_on() # writes to standard out
+ ci.debug_server_off()
+
+
+def test_client_check(ci):
+ print "test_client_check"
+ ci.delete_all()
+
+ defs = Defs()
+ defs.add_extern("/a/b/c/d")
+ defs.add_extern("/a/b/c/d/e:event")
+ defs.add_extern("/a/b/c/d/e:meter")
+ defs.add_extern("/made/up/redundant/extren")
+ defs.add_extern("/made/up/redundant/extren")
+ defs.add_extern("/limits:c1a")
+ defs.add_extern("/limits:c1a")
+ defs.add_extern("fred")
+ defs.add_extern("limits:hpcd")
+ defs.add_extern("/suiteName:sg1")
+ defs.add_extern("/obs/limits:hpcd")
+ suite = defs.add_suite("extern")
+ family_f1 = suite.add_family("f1")
+ family_f1.add_task("p").add_trigger("/a/b/c/d == complete") # extern path
+ family_f1.add_task("q").add_trigger("/a/b/c/d/e:event == set") # extern event path
+ family_f1.add_task("r").add_trigger("/a/b/c/d/e:meter le 30") # extern meter path
+
+ suite.add_inlimit("c1a","/limits")
+ suite.add_inlimit("fred")
+
+ family_anon = suite.add_family("anon")
+ family_anon.add_inlimit("hpcd","limits")
+ family_anon.add_task("t1").add_inlimit("sg1","/suiteName")
+ family_anon.add_task("t2").add_inlimit("hpcd","/obs/limits")
+ family_anon.add_task("t3").add_inlimit("c1a","/limits")
+
+ # CLIENT side check
+ client_check = defs.check()
+ assert len(client_check) == 0, "Expected clean defs check due to externs but found:\n" + client_check + "\n" + str(defs)
+
+ # SERVER side check
+ ci.load(defs)
+ server_check = ci.check("") # empty string means check the whole defs, otherwise a node path can be specified.
+ # print server_check
+ assert len(server_check) > 0, "Expected defs to fail, since no externs in server "
+
+def test_client_suites(ci):
+ print "test_client_suites"
+ ci.delete_all()
+ assert len(ci.suites()) == 0 ,"expected 0 suite "
+
+ defs = create_defs("test_client_suites")
+ ci.load(defs)
+ assert len(ci.suites()) == 1 ,"expected 1 suite "
+
+ ci.delete_all()
+ defs.add_suite("s2")
+ ci.load(defs)
+ assert len(ci.suites()) == 2 ,"expected 2 suite "
+
+def test_client_ch_suites(ci):
+ print "test_client_ch_suites"
+ ci.delete_all()
+
+ defs = Defs()
+ for i in range(1,7): defs.add_suite("s" + str(i))
+ ci.load(defs)
+
+ suite_names = [ 's1', 's2', 's3' ]
+ ci.ch_register(True,suite_names) # register interest in suites s1,s2,s3 and any new suites
+ ci.ch_register(False,[ "s1"]) # register interest in suites s1
+
+ ci.ch_suites() # writes to standard out, list of suites and handles
+
+def test_client_ch_register(ci):
+ print "test_client_ch_register"
+ ci.delete_all()
+ try: ci.ch_drop_user("") # drop all handle associated with current user
+ except: pass # Drop throws if no handle registered
+
+ defs = Defs()
+ for i in range(1,7): defs.add_suite("s" + str(i))
+ ci.load(defs)
+
+ suite_names = [ 's1', 's2', 's3' ]
+ ci.ch_register(True, suite_names) # register interest in suites s1,s2,s3 and any new suites
+ ci.ch_register(False,suite_names) # register interest in suites s1,s2,s3 only
+
+
+def test_client_ch_drop(ci):
+ print "test_client_ch_drop"
+ ci.delete_all()
+ try: ci.ch_drop_user("") # drop all handle associated with current user
+ except: pass # Drop throws if no handle registered
+
+ defs = Defs()
+ for i in range(1,7): defs.add_suite("s" + str(i))
+ ci.load(defs)
+
+ try:
+ # register interest in suites s1,s2,s3 and any new suites
+ suite_names = [ 's1', 's2', 's3' ]
+ ci.ch_register(True, suite_names)
+ finally:
+ ci.ch_drop() # drop using handle stored in ci., from last register
+
+
+def test_client_ch_drop_user(ci):
+ print "test_client_ch_drop_user"
+ ci.delete_all()
+ try: ci.ch_drop_user("") # drop all handle associated with current user
+ except: pass # Drop throws if no handle registered
+
+ defs = Defs()
+ for i in range(1,7): defs.add_suite("s" + str(i))
+ ci.load(defs)
+
+ try:
+ # register interest in suites s1,s2,s3 and any new suites
+ suite_names = [ 's1', 's2', 's3' ]
+ ci.ch_register(True, suite_names)
+ except RuntimeError, e:
+ print str(e)
+
+ ci.ch_drop_user("") # drop all handle associated with current user
+
+
+def test_client_ch_add(ci):
+ print "test_client_ch_add"
+ ci.delete_all()
+ try: ci.ch_drop_user("") # drop all handle associated with current user
+ except: pass # Drop throws if no handle registered
+
+ defs = Defs()
+ for i in range(1,7): defs.add_suite("s" + str(i))
+ ci.load(defs)
+
+ try:
+ suite_names = []
+ ci.ch_register(True,suite_names) # register interest in any new suites
+ suite_names = [ 's1', 's2' ]
+ ci.ch_add(suite_names) # add suites s1,s2 to the last added handle
+ suite_names = [ 's3', 's4' ]
+ ci.ch_add( ci.ch_handle(),suite_names) # add suites s3,s4 using last handle
+ except RuntimeError, e:
+ print str(e)
+
+ ci.ch_drop_user("") # drop all handle associated with current user
+
+
+def test_client_ch_auto_add(ci):
+ print "test_client_ch_auto_add"
+ ci.delete_all()
+ try: ci.ch_drop_user("") # drop all handle associated with current user
+ except: pass # Drop throws if no handle registered
+
+ defs = Defs()
+ for i in range(1,7): defs.add_suite("s" + str(i))
+ ci.load(defs)
+
+ try:
+ suite_names = [ 's1', 's2' , 's3']
+ ci.ch_register(True,suite_names) # register interest in suites s1,s2,s3 and any new suites
+ ci.ch_auto_add( False ) # disable adding newly created suites to last registered handle\n"
+ ci.ch_auto_add( True ) # enable adding newly created suites to last registered handle\n"
+ ci.ch_auto_add( ci.ch_handle(), False ) # disable adding newly created suites to handle\n"
+ except RuntimeError, e:
+ print str(e)
+
+ ci.ch_drop_user("") # drop all handle associated with current user
+
+
+def test_client_ch_remove(ci):
+ print "test_client_ch_remove"
+ ci.delete_all()
+ try: ci.ch_drop_user("") # drop all handle associated with current user
+ except: pass # Drop throws if no handle registered
+
+ defs = Defs()
+ for i in range(1,7): defs.add_suite("s" + str(i))
+ ci.load(defs)
+
+ try:
+ suite_names = [ 's1', 's2' , 's3']
+ ci.ch_register(True,suite_names) # register interest in suites s1,s2,s3 and any new suites
+ suite_names = [ 's1' ]
+ ci.ch_remove( suite_names ) # remove suites s1 from the last added handle\n"
+ suite_names = [ 's2' ]
+ ci.ch_remove( ci.ch_handle(), suite_names ) # remove suites s2 from the last added handle\n"
+ except RuntimeError, e:
+ print str(e)
+
+ ci.ch_drop_user("") # drop all handle associated with current user
+
+
+def test_client_get_file(ci):
+ print "test_client_get_file"
+ ci.delete_all()
+ defs = create_defs("test_client_get_file")
+
+ defs.generate_scripts();
+
+ job_ctrl = JobCreationCtrl()
+ defs.check_job_creation(job_ctrl)
+ assert len(job_ctrl.get_error_msg()) == 0, job_ctrl.get_error_msg()
+
+ ci.restart_server()
+ ci.load(defs)
+ ci.begin_all_suites()
+
+ while 1:
+ if ci.news_local():
+ ci.sync_local() # get the changes, synced with local defs
+ suite = ci.get_defs().find_suite("test_client_get_file")
+ assert suite != None, "Expected to find suite"
+ if suite.get_state() == State.complete:
+ break;
+
+ try:
+ for file_t in [ 'script', 'job', 'jobout', 'manual' ]:
+ the_returned_file = ci.get_file('/test_client_get_file/f1/t1',file_t) # make a request to the server
+ assert len(the_returned_file) > 0,"Expected ci.get_file(/test_client_get_file/f1/t1," + file_t + ") to return something"
+ except RuntimeError, e:
+ print str(e)
+
+ dir_to_remove = Test.ecf_home(the_port) + "/" + "test_client_get_file"
+ shutil.rmtree(dir_to_remove,True) # True means ignore errors
+
+
+def test_client_plug(ci):
+ pass
+
+def test_client_alter_add(ci):
+ print "test_client_alter_add"
+ ci.delete_all()
+ ci.load(create_defs("test_client_alter_add"))
+
+ t1 = "/test_client_alter_add/f1/t1"
+ ci.alter(t1,"add","variable","var","var_name")
+ ci.alter(t1,"add","time","+00:30")
+ ci.alter(t1,"add","time","01:30")
+ ci.alter(t1,"add","time","01:30 20:00 00:30")
+ ci.alter(t1,"add","today","+00:30")
+ ci.alter(t1,"add","today","01:30")
+ ci.alter(t1,"add","today","01:30 20:00 00:30")
+ ci.alter(t1,"add","date","01.01.2001")
+ ci.alter(t1,"add","date","*.01.2001")
+ ci.alter(t1,"add","date","*.*.2001")
+ ci.alter(t1,"add","date","*.*.*")
+ ci.alter(t1,"add","day","sunday")
+ ci.alter(t1,"add","day","monday")
+ ci.alter(t1,"add","day","tuesday")
+ ci.alter(t1,"add","day","wednesday")
+ ci.alter(t1,"add","day","thursday")
+ ci.alter(t1,"add","day","friday")
+ ci.alter(t1,"add","day","saturday")
+ ci.alter(t1,"add","late","late -s +00:15 -a 20:00 -c +02:00")
+
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ assert( len(list(task_t1.variables))) == 1 ,"Expected 1 variable :\n" + str(ci.get_defs())
+ assert( len(list(task_t1.times))) == 3 ,"Expected 3 time :\n" + str(ci.get_defs())
+ assert( len(list(task_t1.todays))) == 3 ,"Expected 3 today's :\n" + str(ci.get_defs())
+ assert( len(list(task_t1.dates))) == 4 ,"Expected 4 dates :\n" + str(ci.get_defs())
+ assert( len(list(task_t1.days))) == 7 ,"Expected 7 days :\n" + str(ci.get_defs())
+ assert( str(task_t1.get_late()) == "late -s +00:15 -a 20:00 -c +02:00", "Expected late 'late -s +00:15 -a 20:00 -c +02:00'" + str(ci.get_defs()))
+
+
+def test_client_alter_delete(ci):
+ print "test_client_alter_delete"
+ ci.delete_all()
+ defs =create_defs("test_client_alter_delete")
+
+ t1 = "/test_client_alter_delete/f1/t1"
+ task_t1 = defs.find_abs_node(t1)
+ task_t1.add_variable("var","value")
+ task_t1.add_variable("var1","value")
+ task_t1.add_time("00:30")
+ task_t1.add_time("00:31")
+ task_t1.add_today("00:30")
+ task_t1.add_today("00:31")
+ task_t1.add_date(1,1,2001)
+ task_t1.add_date(1,1,2002)
+ task_t1.add_day("sunday")
+ task_t1.add_day("monday")
+ cron = Cron()
+ cron.set_week_days( [0,1,2,3,4,5,6] )
+ cron.set_time_series( "+00:30" )
+ task_t1.add_cron(cron)
+ task_t1.add_cron(cron)
+ task_t1.add_event("event")
+ task_t1.add_event("event1")
+ task_t1.add_meter("meter",0,100,100)
+ task_t1.add_meter("meter1",0,100,100)
+ task_t1.add_label("label","name")
+ task_t1.add_label("label1","name")
+ task_t1.add_limit("limit",10)
+ task_t1.add_limit("limit1",10)
+ task_t1.add_inlimit( "limit",t1,2)
+ task_t1.add_inlimit( "limit1",t1,2)
+ task_t1.add_trigger( "t2 == active" )
+ task_t1.add_complete( "t2 == complete" )
+
+ assert( len(str(task_t1.get_late())) == 0, "expected no late" )
+ late = Late()
+ late.submitted(20, 10)
+ late.active(20, 10)
+ late.complete(20, 10, True)
+ task_t1.add_late(late)
+ assert( len(str(task_t1.get_late())) != 0, "expected late" )
+
+
+ t2 = "/test_client_alter_delete/f1/t2"
+ task_t2 = defs.find_abs_node(t2)
+ task_t2.add_repeat( RepeatDate("date",20100111,20100115,2) ) # can't add cron and repeat at the same level
+
+ ci.load(defs)
+
+ ci.alter(t1,"delete","variable","var")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ assert( len(list(task_t1.variables))) == 1 ,"Expected 1 variable :\n" + str(ci.get_defs())
+ ci.alter(t1,"delete","variable") # delete all veriables
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ assert( len(list(task_t1.variables))) == 0 ,"Expected 0 variable :\n" + str(ci.get_defs())
+
+ ci.alter(t1,"delete","time","00:30")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ assert( len(list(task_t1.times))) == 1 ,"Expected 1 time :\n" + str(ci.get_defs())
+ ci.alter(t1,"delete","time")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ assert( len(list(task_t1.times))) == 0 ,"Expected 0 time :\n" + str(ci.get_defs())
+
+ ci.alter(t1,"delete","today","00:30")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ assert( len(list(task_t1.todays))) == 1 ,"Expected 1 today :\n" + str(ci.get_defs())
+ ci.alter(t1,"delete","today")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ assert( len(list(task_t1.todays))) == 0 ,"Expected 0 today :\n" + str(ci.get_defs())
+
+ ci.alter(t1,"delete","date","01.01.2001")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ assert( len(list(task_t1.dates))) == 1 ,"Expected 1 date :\n" + str(ci.get_defs())
+ ci.alter(t1,"delete","date")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ assert( len(list(task_t1.dates))) == 0 ,"Expected 0 date :\n" + str(ci.get_defs())
+
+ ci.alter(t1,"delete","day","sunday")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ assert( len(list(task_t1.days))) == 1 ,"Expected 1 day :\n" + str(ci.get_defs())
+ ci.alter(t1,"delete","day")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ assert( len(list(task_t1.days))) == 0 ,"Expected 0 day :\n" + str(ci.get_defs())
+
+ ci.alter(t1,"delete","event","event")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ assert( len(list(task_t1.events))) == 1 ,"Expected 1 event :\n" + str(ci.get_defs())
+ ci.alter(t1,"delete","event")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ assert( len(list(task_t1.events))) == 0 ,"Expected 0 event :\n" + str(ci.get_defs())
+
+ ci.alter(t1,"delete","meter","meter")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ assert( len(list(task_t1.meters))) == 1 ,"Expected 1 meter :\n" + str(ci.get_defs())
+ ci.alter(t1,"delete","meter")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ assert( len(list(task_t1.meters))) == 0 ,"Expected 0 meter :\n" + str(ci.get_defs())
+
+ ci.alter(t1,"delete","label","label")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ assert( len(list(task_t1.labels))) == 1 ,"Expected 1 label :\n" + str(ci.get_defs())
+ ci.alter(t1,"delete","label")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ assert( len(list(task_t1.labels))) == 0 ,"Expected 0 label :\n" + str(ci.get_defs())
+
+ ci.alter(t1,"delete","limit","limit")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ assert( len(list(task_t1.limits))) == 1 ,"Expected 1 limit :\n" + str(ci.get_defs())
+ ci.alter(t1,"delete","limit")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ assert( len(list(task_t1.limits))) == 0 ,"Expected 0 limit :\n" + str(ci.get_defs())
+
+ ci.alter(t1,"delete","inlimit","limit")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ assert( len(list(task_t1.inlimits))) == 1 ,"Expected 1 inlimit :\n" + str(ci.get_defs())
+ ci.alter(t1,"delete","inlimit")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ assert( len(list(task_t1.inlimits))) == 0 ,"Expected 0 inlimit :\n" + str(ci.get_defs())
+
+ ci.alter(t1,"delete","cron")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ assert( len(list(task_t1.crons))) == 0 ,"Expected 0 crons :\n" + str(ci.get_defs())
+
+ ci.alter(t1,"delete","late")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ assert( len(str(task_t1.get_late())) == 0, "expected no late after delete" )
+
+
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ assert task_t1.get_trigger() != None, "Expected trigger:\n" + str(ci.get_defs())
+ ci.alter(t1,"delete","trigger")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ assert task_t1.get_trigger() == None, "Expected trigger to be deleted:\n" + str(ci.get_defs())
+
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ assert task_t1.get_complete() != None, "Expected complete:\n" + str(ci.get_defs())
+ ci.alter(t1,"delete","complete")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ assert task_t1.get_complete() == None, "Expected complete to be deleted:\n" + str(ci.get_defs())
+
+ ci.alter(t2,"delete","repeat")
+ ci.sync_local()
+ task_t2 = ci.get_defs().find_abs_node(t2)
+ repeat = task_t2.get_repeat()
+ assert repeat.empty(), "Expected repeat to be deleted:\n" + str(ci.get_defs())
+
+def test_client_alter_change(ci):
+ print "test_client_alter_change"
+ ci.delete_all()
+ defs =create_defs("test_client_alter_change")
+ t1 = "/test_client_alter_change/f1/t1"
+ repeat_date_path = "/test_client_alter_change/f1/repeat_date"
+
+ task_t1 = defs.find_abs_node(t1)
+ task_t1.add_variable("var","value")
+ task_t1.add_variable("var1","value")
+ task_t1.add_event("event")
+ task_t1.add_event("event1")
+ task_t1.add_meter("meter",0,100,100)
+ task_t1.add_meter("meter1",0,100,100)
+ task_t1.add_label("label","name")
+ task_t1.add_label("label1","name1")
+ task_t1.add_limit("limit",10)
+ task_t1.add_limit("limit1",10)
+ task_t1.add_inlimit( "limit",t1,2)
+ task_t1.add_inlimit( "limit1",t1,2)
+ task_t1.add_trigger( "t2 == active" )
+ task_t1.add_complete( "t2 == complete" )
+ late = Late()
+ late.submitted(20, 10)
+ late.active(20, 10)
+ late.complete(20, 10, True)
+ task_t1.add_late(late)
+
+
+ f1 = defs.find_abs_node("/test_client_alter_change/f1")
+ repeat_date = f1.add_task("repeat_date")
+ repeat_date.add_repeat( RepeatDate("date",20100111,20100115,2) ) # can't add cron and repeat at the same level
+
+ ci.load(defs)
+
+ ci.alter(t1,"change","late","-s +10:00")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ variable = task_t1.get_late()
+ assert str(task_t1.get_late()) == "late -s +10:00", "Expected alter of late to be 'late -s +10:00' but found " + str(task_t1.get_late())
+
+
+ ci.alter(t1,"change","variable","var","changed_var")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ variable = task_t1.find_variable("var")
+ assert variable.value() == "changed_var", "Expected alter of variable to be 'change_var' but found " + variable.value()
+
+ ci.alter(t1,"change","meter","meter","10")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ meter = task_t1.find_meter("meter")
+ assert meter.value() == 10, "Expected alter of meter to be 10 but found " + str(meter.value())
+
+ ci.alter(t1,"change","event","event","set")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ event = task_t1.find_event("event")
+ assert event.value() == True, "Expected alter of event to be set but found " + str(event.value())
+
+ ci.alter(t1,"change","trigger","t2 == aborted")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ trigger = task_t1.get_trigger()
+ assert trigger.get_expression() == "t2 == aborted", "Expected alter of trigger to be 't2 == aborted' but found " + trigger.get_expression()
+
+ ci.alter(t1,"change","trigger","/s1/f1/t2 == complete")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ trigger = task_t1.get_trigger()
+ assert trigger.get_expression() == "/s1/f1/t2 == complete", "Expected alter of trigger to be '/s1/f1/t2 == complete' but found " + trigger.get_expression()
+
+ ci.alter(t1,"change","complete","t2 == aborted")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ complete = task_t1.get_complete()
+ assert complete.get_expression() == "t2 == aborted", "Expected alter of complete to be 't2 == aborted' but found " + complete.get_expression()
+
+ ci.alter(t1,"change","complete","/s1/f1/t2 == active")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ complete = task_t1.get_complete()
+ assert complete.get_expression() == "/s1/f1/t2 == active", "Expected alter of complete to be '/s1/f1/t2 == active' but found " + complete.get_expression()
+
+ ci.alter(t1,"change","limit_max","limit", "2")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ limit = task_t1.find_limit("limit")
+ assert limit != None, "Expected to find limit"
+ assert limit.limit() == 2, "Expected alter of limit_max to be 2 but found " + str(limit.limit())
+
+ ci.alter(t1,"change","limit_value","limit", "2")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ limit = task_t1.find_limit("limit")
+ assert limit != None, "Expected to find limit"
+ assert limit.value() == 2, "Expected alter of limit_value to be 2 but found " + str(limit.value())
+
+
+ ci.alter(t1,"change","label","label","new-value")
+ ci.sync_local()
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ label = task_t1.find_label("label")
+ assert label.new_value() == "new-value", "Expected alter of label to be 'new-value' but found " + label.new_value()
+
+ ci.alter(repeat_date_path,"change","repeat","20100113")
+ ci.sync_local()
+ task = ci.get_defs().find_abs_node(repeat_date_path)
+ repeat = task.get_repeat()
+ assert repeat.value() == 20100113, "Expected alter of repeat to be 20100113 but found " + str(repeat.value())
+
+
+ # ISSUES:
+ # o Currently we can only change clock attr if we have one.
+ # o Even when we have a clock attr, it only makes sense to apply clock attr changes
+ # before begin(), i.e how do we apply change in gain after begin ??
+
+ #" change clock-type name # The name must be one of 'hybrid' or 'real'.\n"
+ # " change clock-gain name # The gain must be convertible to an integer.\n"
+ # " change label name value # sets the label\n"
+ # " change repeat value # If the repeat is a date, then the value must be a valid YMD ( ie. yyyymmdd)\n"
+ # " # and be convertible to an integer, additionally the value must be in range\n"
+ # " # of the repeat start and end dates. Like wise for repeat integer. For repeat\n"
+ # " # string and enum, the name must either be an integer, that is a valid index or\n"
+ # " # if it is a string, it must correspond to one of enum's or strings list\n"
+
+
+def test_client_force(ci):
+ print "test_client_force"
+ ci.delete_all()
+ defs = create_defs("test_client_force")
+
+ path_list = [ "/test_client_force/f1/t1", "/test_client_force/f1/t2" ]
+ t1 = path_list[0]
+ for path in path_list:
+ task = defs.find_abs_node(path)
+ assert task != None, "Expected to find task at path " + path
+ task.add_event("event")
+
+ ci.load(defs)
+
+ state_list = [ State.unknown, State.active, State.complete, State.queued, State.submitted, State.aborted ]
+ for state in state_list:
+ ci.force_state(t1,state)
+ ci.sync_local()
+ task = ci.get_defs().find_abs_node(t1)
+ assert task.get_state() == state, "Expected state " + state + " but found " + str(task.get_state())
+ for state in state_list:
+ ci.force_state( path_list,state)
+ ci.sync_local()
+ for path in path_list:
+ task = ci.get_defs().find_abs_node(path)
+ assert task.get_state() == state, "Expected state " + state + " but found " + str(task.get_state())
+
+ for state in state_list:
+ ci.force_state_recursive("/test_client_force",state)
+ ci.sync_local()
+ task = ci.get_defs().find_abs_node(t1)
+ assert task.get_state() == state, "Expected state " + state + " but found " + str(task.get_state())
+ suite_paths = [ "/test_client_force"]
+ for state in state_list:
+ ci.force_state_recursive( suite_paths,state)
+ ci.sync_local()
+ task = ci.get_defs().find_abs_node(t1)
+ assert task.get_state() == state, "Expected state " + state + " but found " + str(task.get_state())
+
+ event_states = [ "set", "clear" ]
+ for ev_state in event_states:
+ for path in path_list:
+ ci.force_event(path + ":event" , ev_state)
+ ci.sync_local()
+ task = ci.get_defs().find_abs_node(path)
+ event_fnd = False
+ for event in task.events:
+ event_fnd = True
+ if ev_state == "set" : assert event.value() == True ," Expected event value to be set"
+ else: assert event.value() == False ," Expected event value to be clear"
+ assert event_fnd == True," Expected event to be found"
+
+ event_path_list = [ "/test_client_force/f1/t1:event", "/test_client_force/f1/t2:event" ]
+ event_states = [ "set", "clear" ]
+ for ev_state in event_states:
+ ci.force_event( event_path_list , ev_state)
+ ci.sync_local()
+ for path in path_list:
+ task = ci.get_defs().find_abs_node(path)
+ event_fnd = False
+ for event in task.events:
+ event_fnd = True
+ if ev_state == "set" : assert event.value() == True ," Expected event value to be set"
+ else: assert event.value() == False ," Expected event value to be clear"
+ assert event_fnd == True," Expected event to be found"
+
+
+
+def test_client_replace(ci,on_disk):
+ print "test_client_replace client_defs on disk = " + str(on_disk)
+ # Create and load the following defs
+ # s1
+ # f1
+ # t1
+ # t2
+ ci.delete_all()
+ ci.load(create_defs("s1"))
+
+ #===============================================================================
+ # Example of using replace to ADD a *NEW* node hierarchy to an existing suite
+ # we should end up with:
+ # s1
+ # f1
+ # t1
+ # t2
+ # f2
+ # t1
+ # t2
+ client_def = create_defs("s1")
+ client_def.find_suite("s1").add_family("f2").add_task("t1")
+ if on_disk:
+ client_def.save_as_defs("test_client_replace.def")
+ client_def = "test_client_replace.def"
+
+ ci.replace("/s1/f2",client_def,True,False) # True means create parents as needed, False means don't bypass checks/zombies
+ ci.get_server_defs()
+ assert len(list(ci.get_defs().suites)) == 1 ,"Expected 1 suites:\n" + str(ci.get_defs())
+ assert ci.get_defs().find_abs_node("/s1/f2/t1") != None, "Expected to find task /s1/f2/t1\n" + str(ci.get_defs())
+
+
+ # Example of using replace to *REMOVE* node hierarchy to an existing suite, could have used delete
+ assert ci.get_defs().find_abs_node("/s1/f1/t1") != None, "Expected to find task /s1/f1/t1\n" + str(ci.get_defs())
+ assert ci.get_defs().find_abs_node("/s1/f2/t1") != None, "Expected to find task /s1/f2/t1\n" + str(ci.get_defs())
+ client_def = Defs()
+ client_def.add_suite("s1") # should only have the suite
+ if on_disk:
+ client_def.save_as_defs("test_client_replace.def")
+ client_def = "test_client_replace.def"
+
+ ci.replace("/s1",client_def)
+ ci.get_server_defs()
+ assert len(list(ci.get_defs().suites)) == 1 ,"Expected 1 suites:\n" + str(ci.get_defs())
+ assert ci.get_defs().find_abs_node("/s1/f1/t1") == None, "Expected NOT to find task /s1/f1/t1\n" + str(ci.get_defs())
+ assert ci.get_defs().find_abs_node("/s1/f2/t1") == None, "Expected NOT to find task /s1/f2/t1\n" + str(ci.get_defs())
+
+
+ #===============================================================================
+ # Example of using replace to add a *NEW* suite
+ client_def = Defs();
+ client_def.add_suite("s2")
+ if on_disk:
+ client_def.save_as_defs("test_client_replace.def")
+ client_def = "test_client_replace.def"
+
+ ci.replace("/s2",client_def,True,False) # True means create parents as needed, False means don't bypass checks/zombies
+ ci.get_server_defs()
+ assert len(list(ci.get_defs().suites)) == 2 ," Expected two suites:\n" + str(ci.get_defs())
+
+ # replace added suite s2 with a new s2 which has a task,
+ # s2 must exist on the client defs
+ client_def = Defs();
+ client_def.add_suite("s2").add_task("t1")
+ if on_disk:
+ client_def.save_as_defs("test_client_replace.def")
+ client_def = "test_client_replace.def"
+
+ ci.replace("/s2",client_def)
+
+ ci.get_server_defs()
+ assert len(list(ci.get_defs().suites)) == 2 ," Expected two suites:\n" + str(ci.get_defs())
+ assert ci.get_defs().find_abs_node("/s2/t1") != None, "Expected to find task /s2/t1\n" + str(ci.get_defs())
+ if on_disk:
+ os.remove(client_def)
+
+def test_client_kill(ci):
+ pass
+
+def test_client_status(ci):
+ pass
+
+def test_client_order(ci):
+ pass
+
+def test_client_group(ci):
+ pass
+
+def test_client_suspend(ci):
+ print "test_client_suspend"
+ ci.delete_all()
+ defs = create_defs("test_client_suspend")
+ suite = defs.find_suite("test_client_suspend")
+ suite.add_variable("ECF_DUMMY_TASK","")
+
+ ci.load(defs)
+ ci.begin_all_suites()
+
+ ci.suspend("/test_client_suspend")
+
+ ci.sync_local();
+ suite = ci.get_defs().find_suite("test_client_suspend")
+ assert suite.is_suspended(), "Expected to find suite suspended"
+
+
+def test_client_suspend_multiple_paths(ci):
+ print "test_client_suspend_multiple_paths"
+ ci.delete_all()
+ defs = create_defs("test_client_suspend_multiple_paths")
+ suite = defs.find_suite("test_client_suspend_multiple_paths")
+ suite.add_variable("ECF_DUMMY_TASK","")
+
+ ci.load(defs)
+ ci.begin_all_suites()
+
+ path_list = [ "/test_client_suspend_multiple_paths/f1/t1", "/test_client_suspend_multiple_paths/f1/t2" ]
+ ci.suspend( path_list )
+
+ ci.sync_local();
+ task_t1 = ci.get_defs().find_abs_node("/test_client_suspend_multiple_paths/f1/t1")
+ task_t2 = ci.get_defs().find_abs_node("/test_client_suspend_multiple_paths/f1/t2")
+ assert task_t1.is_suspended(), "Expected to find task t1 to be suspended"
+ assert task_t2.is_suspended(), "Expected to find task t2 to be suspended"
+
+def test_client_resume(ci):
+ print "test_client_resume"
+ ci.delete_all()
+ defs = create_defs("test_client_resume")
+ suite = defs.find_suite("test_client_resume")
+ suite.add_variable("ECF_DUMMY_TASK","")
+
+ ci.load(defs)
+ ci.begin_all_suites()
+
+ ci.suspend("/test_client_resume")
+ ci.sync_local();
+ suite = ci.get_defs().find_suite("test_client_resume")
+ assert suite.is_suspended(), "Expected to find suite suspended"
+
+ ci.resume("/test_client_resume")
+ ci.sync_local();
+ suite = ci.get_defs().find_suite("test_client_resume")
+ assert suite.is_suspended() == False, "Expected to find suite resumed"
+
+def test_client_resume_multiple_paths(ci):
+ print "test_client_resume_multiple_paths"
+ ci.delete_all()
+ defs = create_defs("test_client_resume_multiple_paths")
+ suite = defs.find_suite("test_client_resume_multiple_paths")
+ suite.add_variable("ECF_DUMMY_TASK","")
+
+ ci.load(defs)
+ ci.begin_all_suites()
+
+ path_list = [ "/test_client_resume_multiple_paths/f1/t1", "/test_client_resume_multiple_paths/f1/t2" ]
+ ci.suspend( path_list )
+
+ ci.sync_local();
+ task_t1 = ci.get_defs().find_abs_node("/test_client_resume_multiple_paths/f1/t1")
+ task_t2 = ci.get_defs().find_abs_node("/test_client_resume_multiple_paths/f1/t2")
+ assert task_t1.is_suspended(), "Expected to find task t1 to be suspended"
+ assert task_t2.is_suspended(), "Expected to find task t2 to be suspended"
+
+ ci.resume( path_list )
+ ci.sync_local();
+ task_t1 = ci.get_defs().find_abs_node("/test_client_resume_multiple_paths/f1/t1")
+ task_t2 = ci.get_defs().find_abs_node("/test_client_resume_multiple_paths/f1/t2")
+ assert task_t1.is_suspended() == False, "Expected to find task t1 to be resumed"
+ assert task_t2.is_suspended() == False, "Expected to find task t2 to be resumed"
+
+
+def test_client_delete_node(ci):
+ print "test_client_delete_node"
+ ci.delete_all()
+ defs = create_defs("test_client_delete_node")
+
+ task_vec = defs.get_all_tasks();
+ assert len(task_vec) > 0, "Expected some tasks but found none:\n" + str(defs)
+
+ ci.load(defs)
+ ci.sync_local();
+ for task in task_vec:
+ node = ci.get_defs().find_abs_node(task.get_abs_node_path())
+ assert node != None , "Expected to find task " + task.get_abs_node_path() + ":\n" + str(ci.get_defs())
+
+ for task in task_vec:
+ ci.delete(task.get_abs_node_path())
+
+ ci.sync_local();
+ for task in task_vec:
+ node = ci.get_defs().find_abs_node(task.get_abs_node_path())
+ assert node == None , "Expected not to find task " + task.get_abs_node_path() + " as it should have been deleted:\n" + str(ci.get_defs())
+
+def test_client_delete_node_multiple_paths(ci):
+ print "test_client_delete_node_multiple_paths"
+ ci.delete_all()
+ defs = create_defs("test_client_delete_node_multiple_paths")
+
+ task_vec = defs.get_all_tasks();
+ assert len(task_vec) > 0, "Expected some tasks but found none:\n" + str(defs)
+
+ paths = []
+ for task in task_vec:
+ paths.append(task.get_abs_node_path())
+
+ ci.load(defs)
+
+ ci.sync_local();
+ for task in task_vec:
+ node = ci.get_defs().find_abs_node(task.get_abs_node_path())
+ assert node != None , "Expected to find task " + task.get_abs_node_path() + ":\n" + str(ci.get_defs())
+
+ ci.delete(paths)
+
+ ci.sync_local();
+ for task in task_vec:
+ node = ci.get_defs().find_abs_node(task.get_abs_node_path())
+ assert node == None , "Expected not to find task " + task.get_abs_node_path() + " as it should have been deleted:\n" + str(ci.get_defs())
+
+
+def test_client_check_defstatus(ci):
+ print "test_client_check_defstatus"
+ ci.delete_all()
+ defs = create_defs("test_client_check_defstatus")
+
+ # stop defs form running when begin is called.
+ suite = defs.find_suite("test_client_check_defstatus")
+ suite.add_defstatus(DState.suspended)
+
+ t1 = "/test_client_check_defstatus/f1/t1"
+ t2 = "/test_client_check_defstatus/f1/t2"
+ task_t1 = defs.find_abs_node(t1)
+ task_t1.add_defstatus(DState.suspended)
+
+ defs.generate_scripts();
+
+ job_ctrl = JobCreationCtrl()
+ defs.check_job_creation(job_ctrl)
+ assert len(job_ctrl.get_error_msg()) == 0, job_ctrl.get_error_msg()
+
+ ci.restart_server()
+ ci.load(defs)
+ ci.begin_all_suites()
+
+ ci.sync_local() # get the changes, synced with local defs
+ #print ci.get_defs();
+ task_t1 = ci.get_defs().find_abs_node(t1)
+ task_t2 = ci.get_defs().find_abs_node(t2)
+ assert task_t1 != None,"Could not find t1"
+ assert task_t2 != None,"Could not find t2"
+
+ assert task_t1.get_state() == State.queued, "Expected state queued but found " + str(task_t1.get_state())
+ assert task_t2.get_state() == State.queued, "Expected state queued " + str(task_t2.get_state())
+
+ assert task_t1.get_dstate() == DState.suspended, "Expected state suspended but found " + str(task_t1.get_state())
+ assert task_t2.get_dstate() == DState.queued, "Expected state queued but found " + str(task_t2.get_state())
+
+ dir_to_remove = Test.ecf_home(the_port) + "/" + "test_client_check_defstatus"
+ shutil.rmtree(dir_to_remove)
+
+def test_ECFLOW_189(ci):
+ # Bug, when a node is resumed it ignored holding dependencies higher up the tree.
+ # i.e Previously when we resumed a node, it ignored trigger/time/node state, dependencies higher up the tree
+ print "test_ECFLOW_189"
+ ci.delete_all()
+ defs = create_defs("test_ECFLOW_189")
+ defs.generate_scripts();
+
+ job_ctrl = JobCreationCtrl()
+ defs.check_job_creation(job_ctrl)
+ assert len(job_ctrl.get_error_msg()) == 0, job_ctrl.get_error_msg()
+
+ ci.restart_server()
+ ci.load(defs)
+
+ ci.suspend("/test_ECFLOW_189")
+ ci.suspend("/test_ECFLOW_189/f1/t1")
+ ci.suspend("/test_ECFLOW_189/f1/t2")
+
+ ci.begin_all_suites()
+
+ ci.sync_local() # get the changes, synced with local defs
+ #print ci.get_defs();
+ task_t1 = ci.get_defs().find_abs_node("/test_ECFLOW_189/f1/t1")
+ task_t2 = ci.get_defs().find_abs_node("/test_ECFLOW_189/f1/t2")
+ assert task_t1 != None,"Could not find /test_ECFLOW_189/f1/t1"
+ assert task_t2 != None,"Could not find /test_ECFLOW_189/f1/t2"
+
+ assert task_t1.get_state() == State.queued, "Expected state queued but found " + str(task_t1.get_state())
+ assert task_t2.get_state() == State.queued, "Expected state queued but found " + str(task_t2.get_state())
+ assert task_t1.get_dstate() == DState.suspended, "Expected state suspended but found " + str(task_t1.get_dstate())
+ assert task_t2.get_dstate() == DState.suspended, "Expected state suspended but found " + str(task_t2.get_dstate())
+
+ # ok now resume t1/t2, they should remain queued, since the Suite is still suspended
+ ci.resume("/test_ECFLOW_189/f1/t1")
+ ci.resume("/test_ECFLOW_189/f1/t2")
+
+ time.sleep(3)
+ ci.sync_local() # get the changes, synced with local defs
+ #print ci.get_defs();
+ task_t1 = ci.get_defs().find_abs_node("/test_ECFLOW_189/f1/t1")
+ task_t2 = ci.get_defs().find_abs_node("/test_ECFLOW_189/f1/t2")
+ assert task_t1.get_state() == State.queued, "Expected state queued but found " + str(task_t1.get_state())
+ assert task_t2.get_state() == State.queued, "Expected state queued but found " + str(task_t2.get_state())
+ assert task_t1.get_dstate() == DState.queued, "Expected state queued but found " + str(task_t1.get_dstate())
+ assert task_t2.get_dstate() == DState.queued, "Expected state queued but found " + str(task_t2.get_dstate())
+
+ dir_to_remove = Test.ecf_home(the_port) + "/" + "test_ECFLOW_189"
+ shutil.rmtree(dir_to_remove)
+
+
+def test_ECFLOW_199(ci):
+ # Test ClientInvoker::changed_node_paths
+ print "test_ECFLOW_199"
+ ci.delete_all()
+ defs = create_defs("test_ECFLOW_199")
+ defs.generate_scripts();
+
+ job_ctrl = JobCreationCtrl()
+ defs.check_job_creation(job_ctrl)
+ assert len(job_ctrl.get_error_msg()) == 0, job_ctrl.get_error_msg()
+
+ ci.restart_server()
+ ci.load(defs)
+
+ ci.suspend("/test_ECFLOW_199")
+ ci.suspend("/test_ECFLOW_199/f1/t1")
+ ci.suspend("/test_ECFLOW_199/f1/t2")
+
+ ci.begin_all_suites()
+
+ ci.sync_local() # get the changes, synced with local defs
+ #print ci.get_defs();
+ assert len(list(ci.changed_node_paths)) == 0, "Expected first call to sync_local, to have no changed paths but found " + str(len(list(ci.changed_node_paths)))
+
+ # ok now resume t1/t2, they should remain queued, since the Suite is still suspended
+ ci.resume("/test_ECFLOW_199/f1/t1")
+ ci.sync_local()
+ for path in ci.changed_node_paths:
+ print " changed node path " + path;
+ assert len(list(ci.changed_node_paths)) == 1, "Expected 1 changed path but found " + str(len(list(ci.changed_node_paths)))
+
+ ci.resume("/test_ECFLOW_199/f1/t2")
+ ci.sync_local()
+ for path in ci.changed_node_paths:
+ print " changed node path " + path;
+ assert len(list(ci.changed_node_paths)) == 1, "Expected 1 changed path but found " + str(len(list(ci.changed_node_paths)))
+
+ dir_to_remove = Test.ecf_home(the_port) + "/" + "test_ECFLOW_199"
+ shutil.rmtree(dir_to_remove)
+
+
+if __name__ == "__main__":
+ print "####################################################################"
+ print "Running ecflow version " + Client().version() + " debug build(" + str(debug_build()) +")"
+ print "####################################################################"
+
+ # server independent tests
+ test_set_host_port();
+
+ with Test.Server() as ci:
+ global the_port
+ the_port = ci.get_port();
+ test_version(ci)
+ PrintStyle.set_style( Style.STATE ) # show node state
+ test_client_get_server_defs(ci)
+ test_client_new_log(ci, the_port)
+ test_client_clear_log(ci, the_port)
+ test_client_log_msg(ci, the_port)
+
+ test_client_restart_server(ci)
+ test_client_halt_server(ci)
+ test_client_shutdown_server(ci)
+
+ test_client_load_in_memory_defs(ci)
+ test_client_load_from_disk(ci)
+ test_client_checkpt(ci, the_port)
+ test_client_restore_from_checkpt(ci, the_port)
+
+ test_client_reload_wl_file(ci, the_port)
+
+ test_client_run(ci)
+ test_client_run_with_multiple_paths(ci)
+ test_client_requeue(ci)
+ test_client_requeue_with_multiple_paths(ci)
+ test_client_free_dep(ci)
+
+ test_client_suites(ci)
+ test_client_ch_suites(ci)
+ test_client_ch_register(ci)
+ test_client_ch_drop(ci)
+ test_client_ch_drop_user(ci)
+ test_client_ch_add(ci)
+ test_client_ch_auto_add(ci)
+ test_client_ch_remove(ci)
+
+ test_client_get_file(ci)
+ #test_client_plug(ci)
+ test_client_alter_add(ci)
+ test_client_alter_delete(ci)
+ test_client_alter_change(ci)
+
+ test_client_force(ci)
+ test_client_replace(ci,False)
+ test_client_replace(ci,True)
+
+ #test_client_kill(ci)
+ #test_client_status(ci)
+ #test_client_order(ci)
+ #test_client_group(ci)
+ test_client_suspend(ci)
+ test_client_suspend_multiple_paths(ci)
+ test_client_resume(ci)
+ test_client_resume_multiple_paths(ci)
+ test_client_delete_node(ci)
+ test_client_delete_node_multiple_paths(ci)
+
+ test_client_check(ci)
+ test_client_check_defstatus(ci)
+
+ test_client_stats(ci)
+ test_client_stats_reset(ci)
+ test_client_debug_server_on_off(ci)
+
+ test_ECFLOW_189(ci)
+ test_ECFLOW_199(ci)
+
+ print "All Tests pass ======================================================================"
diff --git a/Pyext/test/py_s_TestPythonChildApi.py b/Pyext/test/py_s_TestPythonChildApi.py
new file mode 100644
index 0000000..0a03504
--- /dev/null
+++ b/Pyext/test/py_s_TestPythonChildApi.py
@@ -0,0 +1,140 @@
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# code for testing client code in python
+import time
+import os
+import pwd
+from datetime import datetime
+import shutil # used to remove directory tree
+
+from ecflow import Defs, Clock, DState, Style, State, PrintStyle, File, Client, SState, debug_build
+import ecflow_test_util as Test
+
+
+def ecf_includes() : return Test.get_root_source_dir() + "/Pyext" + "/test/data/python_includes"
+
+def create_defs(name,the_port):
+ defs = Defs()
+ suite_name = name
+ if len(suite_name) == 0: suite_name = "s1"
+ suite = defs.add_suite(suite_name);
+
+ ecfhome = Test.ecf_home(the_port);
+ suite.add_variable("ECF_HOME", ecfhome);
+ suite.add_variable("ECF_INCLUDE", ecf_includes());
+
+ family = suite.add_family("f1")
+ family.add_variable("ECF_JOB_CMD","python %ECF_JOB% 1> %ECF_JOBOUT% 2>&1")
+
+ task = family.add_task("t1")
+ task.add_event("event_fred")
+ task.add_meter("meter", 0, 100)
+ task.add_label("label_name", "value")
+
+ family.add_task("t2") # test wait
+
+ return defs;
+
+
+def test_client_run(ci):
+ print "\ntest_client_run " + ci.get_host() + ":" + str(ci.get_port())
+ print " ECF_HOME(" + Test.ecf_home(ci.get_port()) + ")"
+ print " ECF_INCLUDES(" + ecf_includes() + ")"
+ ci.delete_all()
+ defs = create_defs("test_client_run",ci.get_port())
+ suite = defs.find_suite("test_client_run")
+ suite.add_defstatus(DState.suspended)
+
+ # create the ecf file /test_client_run/f1/t1
+ ecf_home = Test.ecf_home(ci.get_port())
+ dir = ecf_home + "/test_client_run/f1"
+
+ # on cray creating recursive directories can fail, try again. yuk
+ try:
+ if not os.path.exists(dir): os.makedirs(dir)
+ except:
+ try:
+ if not os.path.exists(dir): os.makedirs(dir)
+ except:
+ # try breaking down
+ if not os.path.exists(ecf_home): os.makedirs(ecf_home)
+ new_dir = ecf_home + "/test_client_run"
+ if not os.path.exists(new_dir): os.makedirs(new_dir)
+ new_dir = ecf_home + "/test_client_run/f1"
+ if not os.path.exists(new_dir): os.makedirs(new_dir)
+ if not os.path.exists(dir): os.makedirs(dir)
+
+ file = dir + "/t1.ecf"
+ contents = "%include <head.py>\n\n"
+ contents += "print 'doing some work'\n"
+ contents += "try:\n"
+ contents += " ci.child_event('event_fred')\n"
+ contents += " ci.child_meter('meter',100)\n"
+ contents += " ci.child_label('label_name','100')\n"
+ contents += " print 'Finished event,meter and label child commands'\n"
+ contents += "except:\n"
+ contents += " ci.child_abort()\n\n"
+ contents += "%include <tail.py>\n"
+ open(file,'w').write(contents)
+ print " Created file " + file
+
+ # create the ecf file /test_client_run/f1/t2
+ file = dir + "/t2.ecf"
+ contents = "%include <head.py>\n\n"
+ contents += "print 'Waiting for /test_client_run/f1/t1 == complete'\n"
+ contents += "try:\n"
+ contents += " ci.child_wait('/test_client_run/f1/t1 == complete')\n"
+ contents += " print 'Finished waiting'\n"
+ contents += "except:\n"
+ contents += " ci.child_abort()\n\n"
+ contents += "%include <tail.py>\n"
+ open(file,'w').write(contents)
+ print " Created file " + file
+
+ ci.restart_server()
+ ci.load(defs)
+ ci.begin_all_suites()
+ ci.run("/test_client_run", False)
+ print " Running the test, wait for suite to complete ..."
+
+ count = 0
+ while 1:
+ count += 1
+ ci.sync_local() # get the changes, synced with local defs
+ suite = ci.get_defs().find_suite("test_client_run")
+ assert suite != None, " Expected to find suite test_client_run:\n" + str(ci.get_defs())
+ if suite.get_state() == State.complete:
+ break;
+ if suite.get_state() == State.aborted:
+ print defs;
+ assert False," Suite aborted \n"
+ time.sleep(2)
+ if count > 20:
+ assert False, " test_client_run aborted after " + str(count) + " loops:\n" + str(ci.get_defs())
+
+ ci.log_msg("Looped " + str(count) + " times")
+
+ if not Test.debugging():
+ dir_to_remove = Test.ecf_home(ci.get_port()) + "/" + "test_client_run"
+ print " Test OK: removing directory " + dir_to_remove
+ shutil.rmtree(dir_to_remove)
+
+if __name__ == "__main__":
+ print "####################################################################"
+ print "Running ecflow version " + Client().version() + " debug build(" + str(debug_build()) +")"
+ print "####################################################################"
+
+ with Test.Server() as ci:
+ PrintStyle.set_style( Style.STATE ) # show node state
+ test_client_run(ci)
+ print "\nAll Tests pass ======================================================================"
diff --git a/Pyext/test/py_u_TestAddDelete.py b/Pyext/test/py_u_TestAddDelete.py
new file mode 100644
index 0000000..465db8b
--- /dev/null
+++ b/Pyext/test/py_u_TestAddDelete.py
@@ -0,0 +1,520 @@
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+# code for testing addition and deletion
+#
+import ecflow
+import sys
+import os
+
+if __name__ == "__main__":
+
+ print "####################################################################"
+ print "Running ecflow version " + ecflow.Client().version() + " debug build(" + str(ecflow.debug_build()) +")"
+ print "PYTHONPATH: " + str(os.environ['PYTHONPATH'].split(os.pathsep))
+ print "sys.path: " + str(sys.path)
+ print "####################################################################"
+
+ #===========================================================================
+ # Defs: add and delete *USER* variables
+ #===========================================================================
+ defs = ecflow.Defs()
+ defs.add_variable("FRED", "/tmp/")
+ defs.add_variable("ECF_URL_CMD", "${BROWSER:=firefox} -remote 'openURL(%ECF_URL_BASE%/%ECF_URL%)'")
+ defs.add_variable("ECF_URL_BASE", "http://www.ecmwf.int")
+ defs.add_variable("ECF_URL", "publications/manuals/sms")
+ assert len(list(defs.user_variables)) == 4, "Expected *user* 4 variable"
+ defs.delete_variable("FRED"); assert len(list(defs.user_variables)) == 3, "Expected 3 variables since we just delete FRED"
+ defs.delete_variable(""); assert len(list(defs.user_variables)) == 0, "Expected 0 variables since we should have deleted all"
+
+ a_dict = { "name":"value", "name2":"value2", "name3":"value3", "name4":"value4" }
+ defs.add_variable(a_dict)
+ assert len(list(defs.user_variables)) == 4, "Expected 4 variable"
+ defs.delete_variable(""); assert len(list(defs.user_variables)) == 0, "Expected 0 variable since we should have deleted all"
+
+ # add a empty dictionary
+ a_dict = {}
+ defs.add_variable(a_dict)
+ assert len(list(defs.user_variables)) == 0, "Expected zero variables"
+
+ #===========================================================================
+ # Suite: add and delete variables
+ #===========================================================================
+ suite = ecflow.Suite("s1")
+ suite.add_variable(ecflow.Variable("ECF_HOME", "/tmp/"))
+ suite.add_variable("ECF_URL_CMD", "${BROWSER:=firefox} -remote 'openURL(%ECF_URL_BASE%/%ECF_URL%)'")
+ suite.add_variable("ECF_URL_BASE", "http://www.ecmwf.int")
+ suite.add_variable("ECF_URL", "publications/manuals/sms")
+ assert len(list(suite.variables)) == 4, "Expected 4 variable"
+ suite.delete_variable("ECF_HOME"); assert len(list(suite.variables)) == 3, "Expected 3 variable since we just delete ECF_HOME"
+ suite.delete_variable(""); assert len(list(suite.variables)) == 0, "Expected 0 variable since we should have deleted all"
+
+ a_dict = { "name":"value", "name2":"value2", "name3":"value3", "name4":"value4" }
+ suite.add_variable(a_dict)
+ assert len(list(suite.variables)) == 4, "Expected 4 variable"
+ suite.delete_variable(""); assert len(list(suite.variables)) == 0, "Expected 0 variable since we should have deleted all"
+
+ # add a empty dictionary
+ a_dict = { }
+ suite.add_variable(a_dict)
+ assert len(list(suite.variables)) == 0, "Expected zero variables"
+
+ # adding dictionary items that are not strings should result in a type error
+ expected_type_error = False
+ try:
+ a_bad_dict = { "name":"fred", "name2":14, "name3":"12", "name4":12 }
+ suite.add_variable(a_bad_dict)
+ except TypeError:
+ expected_type_error = True
+
+ assert expected_type_error, "Expected Type error"
+ assert len(list(suite.variables)) == 0, "Expected 0 variable since we should have deleted all"
+
+ suite.add_variable("ECF_URL_CMD", "test duplicates")
+ suite.add_variable("ECF_URL_CMD", "Expected warning") # expect a warning message to standard out
+
+
+ #===========================================================================
+ # add and delete limits
+ #===========================================================================
+ suite.add_limit(ecflow.Limit("limitName1", 10))
+ suite.add_limit(ecflow.Limit("limitName2", 10))
+ suite.add_limit("limitName3", 10)
+ suite.add_limit("limitName4", 10)
+ assert len(list(suite.limits)) == 4, "Expected 4 Limits"
+ suite.delete_limit("limitName1"); assert len(list(suite.limits)) == 3, "Expected 3 limits since we just deleted one limitName1"
+ suite.delete_limit(""); assert len(list(suite.limits)) == 0, "Expected 0 limits since we just deleted all of them"
+
+ #===========================================================================
+ # Test Limit and node paths, ECFLOW-518
+ #===========================================================================
+ the_limit = ecflow.Limit("limitName1", 10)
+ assert the_limit.name() == "limitName1", "name not as expected"
+ assert the_limit.value() == 0 ,"Expected limit value of 0"
+ assert the_limit.limit() == 10 ,"Expected limit of 10"
+ assert len(list(the_limit.node_paths())) == 0 ,"Expected nodes which have consumed a limit to be empty"
+
+ the_limit.increment(1,"/path1") ; assert the_limit.value() == 1 ,"Expected limit value of 1"
+ the_limit.increment(1,"/path2") ; assert the_limit.value() == 2 ,"Expected limit value of 2"
+ the_limit.increment(1,"/path3") ; assert the_limit.value() == 3 ,"Expected limit value of 3"
+ the_limit.increment(1,"/path4") ; assert the_limit.value() == 4 ,"Expected limit value of 4"
+ for path in the_limit.node_paths(): print path
+ assert len(list(the_limit.node_paths())) == 4 ,"expected 4 path"
+ the_limit.decrement(1,"/path1") ; assert the_limit.value() == 3 ,"Expected limit value of 3"
+ the_limit.decrement(1,"/path2") ; assert the_limit.value() == 2 ,"Expected limit value of 2"
+ the_limit.decrement(1,"/path3") ; assert the_limit.value() == 1 ,"Expected limit value of 1"
+ the_limit.decrement(1,"/path4") ; assert the_limit.value() == 0 ,"Expected limit value of 0"
+ assert len(list(the_limit.node_paths())) == 0 ,"Expected nodes which have consumed a limit to be empty"
+
+ the_limit.increment(1,"/path1") # add same path, should only consume one token
+ the_limit.increment(1,"/path1")
+ the_limit.increment(1,"/path1")
+ the_limit.increment(1,"/path1")
+ assert len(list(the_limit.node_paths())) == 1 ,"expected 1 path"
+ assert the_limit.value() == 1 ,"Expected limit value of 1"
+
+ #===========================================================================
+ # add and delete inlimits
+ #===========================================================================
+ suite.add_inlimit(ecflow.InLimit("limitName1", "/s1/f1", 2))
+ suite.add_inlimit(ecflow.InLimit("limitName2", "/s1/f1", 2))
+ suite.add_inlimit("limitName3", "/s1/f1", 2)
+ suite.add_inlimit("limitName4", "/s1/f1", 2)
+ assert len(list(suite.inlimits)) == 4, "Expected 4 inLimits"
+ suite.delete_inlimit("limitName1"); assert len(list(suite.inlimits)) == 3, "Expected 3 inlimits since we just deleted one limitName1"
+ suite.delete_inlimit(""); assert len(list(suite.inlimits)) == 0, "Expected 0 inlimits since we just deleted all of them"
+
+ #===============================================================================
+ # add and delete triggers and complete
+ #===============================================================================
+ task = ecflow.Task("task")
+ task.add_trigger("t2 == active")
+ task.add_complete("t2 == complete")
+ assert task.get_complete(), "Expected complete"
+ assert task.get_trigger(), "Expected trigger"
+ task.delete_trigger(); assert not task.get_trigger(), "Expected no trigger"
+ task.delete_complete(); assert not task.get_complete(), "Expected no complete"
+
+ task.add_part_trigger(ecflow.PartExpression("t1 == complete"))
+ task.add_part_trigger(ecflow.PartExpression("t2 == active", True)) # for long and/or expressions, subsequent expr must be and/or
+ task.add_part_complete(ecflow.PartExpression("t3 == complete"))
+ task.add_part_complete(ecflow.PartExpression("t4 == active", False)) # for long and/or expressions, subsequent expr must be and/or
+ task.delete_trigger(); assert not task.get_trigger(), "Expected no trigger"
+ task.delete_complete(); assert not task.get_complete(), "Expected no complete"
+
+ task.add_part_trigger("t1 == complete")
+ task.add_part_trigger("t2 == active", True) # for long and/or expressions, subsequent expr must be and/or
+ task.add_part_complete("t3 == complete")
+ task.add_part_complete("t4 == active", False) # for long and/or expressions, subsequent expr must be and/or
+ task.delete_trigger(); assert not task.get_trigger(), "Expected no trigger"
+ task.delete_complete(); assert not task.get_complete(), "Expected no complete"
+
+ #===========================================================================
+ # Add triggers using expressions
+ #===========================================================================
+ expr = ecflow.Expression("t1 == complete")
+ task = ecflow.Task("task")
+ task.add_trigger(expr)
+
+ expr = ecflow.Expression("t1 == complete")
+ expr.add(ecflow.PartExpression("t1 == complete", True))
+ expr.add(ecflow.PartExpression("t2 == complete", True))
+ task = ecflow.Task("task")
+ task.add_trigger(expr)
+
+
+ #===========================================================================
+ # add,delete,find events
+ #===========================================================================
+ task.add_event(ecflow.Event(1));
+ task.add_event(2)
+ task.add_event(ecflow.Event(10, "Eventname"))
+ task.add_event(10, "Eventname2")
+ task.add_event("fred")
+
+ # test find
+ event = task.find_event("EVENT")
+ assert(event.empty()),"Expected to not to find event"
+ assert(event.name() == ""),"Expected to not to find event, number is maximum int"
+ assert(event.value() == 0),"Expected to not to find event"
+
+ event = task.find_event("1");
+ assert(not event.empty()),"Expected to find event"
+ assert(event.number() == 1), "Expected to find event 1"
+ assert(event.name() == ""), "Expected name to be empty"
+ assert(event.value() == 0),"Expected to not to find event"
+
+ event = task.find_event("2");
+ assert(not event.empty()),"Expected to find event"
+ assert(event.number() == 2), "Expected to find event 1"
+ assert(event.name() == ""), "Expected name to be empty"
+ assert(event.value() == 0),"Expected to not to find event"
+
+ event = task.find_event("10");
+ assert(not event.empty()),"Expected to find event"
+ assert(event.number() == 10), "Expected to find event 10"
+ assert(event.name() == "Eventname"), "Expected name to be empty"
+ assert(event.value() == 0),"Expected to not to find event"
+
+ event = task.find_event("fred");
+ assert(not event.empty()),"Expected to find event"
+ assert(event.name() == "fred"), "Expected name to be empty, when name defind an not number, number is max_int"
+ assert(event.value() == 0),"Expected to not to find event"
+
+ for e in task.events: print str(e)," # value: ",str(e.value())
+ a_dict = {}
+ for e in task.events:
+ if e.name() != "": a_dict[e.name()] = e.value()
+ else: a_dict[e.number()] = e.value()
+ print a_dict
+
+ assert len(list(task.events)) == 5, "Expected 5 Events"
+ task.delete_event("1"); assert len(list(task.events)) == 4, "Expected 4 Events"
+ task.delete_event("Eventname"); assert len(list(task.events)) == 3, "Expected 3 Events"
+ task.delete_event(""); assert len(list(task.events)) == 0, "Expected 0 Events"
+
+
+ #===========================================================================
+ # add and delete meter
+ #===========================================================================
+ task.add_meter(ecflow.Meter("metername1", 0, 100, 50))
+ task.add_meter(ecflow.Meter("metername2", 0, 100))
+ task.add_meter("metername3", 0, 100, 50)
+ task.add_meter("metername4", 0, 100)
+ assert len(list(task.meters)) == 4, "Expected 4 Meters"
+ task.delete_meter("metername1"); assert len(list(task.meters)) == 3, "Expected 3 Meters"
+ task.delete_meter("metername4"); assert len(list(task.meters)) == 2, "Expected 2 Meters"
+ task.delete_meter(""); assert len(list(task.meters)) == 0, "Expected 0 Meters"
+
+
+ #===========================================================================
+ # add and delete label
+ #===========================================================================
+ task.add_label(ecflow.Label("label_name1", "value"))
+ task.add_label(ecflow.Label("label_name2", "value"))
+ task.add_label("label_name3", "value")
+ task.add_label("label_name4", "value")
+ assert len(list(task.labels)) == 4, "Expected 4 labels"
+ task.delete_label("label_name1"); assert len(list(task.labels)) == 3, "Expected 3 Labels"
+ task.delete_label("label_name4"); assert len(list(task.labels)) == 2, "Expected 2 Labels"
+ task.delete_label(""); assert len(list(task.labels)) == 0, "Expected 0 Labels"
+
+
+ #===========================================================================
+ # add delete Repeat
+ #===========================================================================
+ task.add_repeat(ecflow.RepeatInteger("integer", 0, 100, 2))
+ repeat = task.get_repeat(); assert not repeat.empty(), "Expected repeat"
+ task.delete_repeat()
+ repeat = task.get_repeat(); assert repeat.empty(), "Expected no repeat"
+
+ task.add_repeat(ecflow.RepeatEnumerated("enum", ["red", "green", "blue" ]))
+ print task
+ task.delete_repeat()
+ repeat = task.get_repeat(); assert repeat.empty(), "Expected no repeat"
+
+ task.add_repeat(ecflow.RepeatDate("date", 20100111, 20100115, 2))
+ task.delete_repeat()
+ repeat = task.get_repeat(); assert repeat.empty(), "Expected no repeat"
+
+ task.add_repeat(ecflow.RepeatString("string", ["a", "b", "c" ]))
+ task.delete_repeat()
+ repeat = task.get_repeat(); assert repeat.empty(), "Expected no repeat"
+
+
+ #===========================================================================
+ # create a time series, used for adding time and today
+ #===========================================================================
+ start = ecflow.TimeSlot(0, 0)
+ finish = ecflow.TimeSlot(23, 0)
+ incr = ecflow.TimeSlot(0, 30)
+ time_series = ecflow.TimeSeries(start, finish, incr, True)
+
+ # Add and delete today
+ # NOTE: **********************************************************************
+ # Do *NOT* delete attributes using iterator traversal
+ # The iterators *are* bound to the c++ iterators hence if we delete
+ # over the traversal, we can corrupt the vector, leading to undefined behavour.
+ # Hence we **can not** delete more than once over a traversal
+ # Soln 1: take a copy
+ # *****************************************************************************
+ # task.add_today( Today( 0,10 ))
+ # task.add_today( Today( 0,59, True ))
+ # task.add_today( Today(TimeSlot(20,10)) )
+ # task.add_today( Today(TimeSlot(20,20),False))
+ # for today in task.todays:
+ # task.delete_today(today) # will corrupt C++ vector
+
+ task.add_today("00:30")
+ task.add_today("+00:30")
+ task.add_today("+00:30 20:00 01:00")
+ task.add_today(ecflow.Today(time_series))
+ task.add_today(ecflow.Today(0, 10))
+ task.add_today(0, 59, True)
+ task.add_today(ecflow.Today(ecflow.TimeSlot(20, 10)))
+ task.add_today(ecflow.Today(ecflow.TimeSlot(20, 20), False))
+ assert len(list(task.todays)) == 8, "Expected 8 todays"
+ vec_copy = []
+ for today in task.todays: vec_copy.append(today)
+ for today in vec_copy: task.delete_today(today)
+ assert len(list(task.todays)) == 0, "Expected 0 todays"
+
+ #===========================================================================
+ # add and delete time
+ #===========================================================================
+ task.add_time("00:30")
+ task.add_time("+00:30")
+ task.add_time("+00:30 20:00 01:00")
+ task.add_time(ecflow.Time(time_series))
+ task.add_time(ecflow.Time(0, 10))
+ task.add_time(0, 59, True)
+ task.add_time(ecflow.Time(ecflow.TimeSlot(20, 10)))
+ task.add_time(ecflow.Time(ecflow.TimeSlot(20, 20), False))
+ assert len(list(task.times)) == 8, "Expected 8 times"
+ vec_copy = []
+ for time in task.times: vec_copy.append(time)
+ for time in vec_copy: task.delete_time(time)
+ assert len(list(task.todays)) == 0, "Expected 0 todays"
+
+ #===========================================================================
+ # add and delete date
+ #===========================================================================
+ for i in [ 1, 2, 4, 8, 16 ] :
+ task.add_date(i, 0, 0)
+ task.add_date(ecflow.Date(1, 1, 2010))
+ task.add_date(1, 1, 2010) # duplicate
+ task.add_date(ecflow.Date(2, 1, 2010))
+ task.add_date(ecflow.Date(3, 1, 2010))
+ task.add_date(ecflow.Date(4, 1, 2010))
+ assert len(list(task.dates)) == 10, "Expected 10 dates but found " + str(len(list(task.dates)))
+ vec_copy = []
+ for attr in task.dates: vec_copy.append(attr)
+ for attr in vec_copy: task.delete_date(attr)
+ assert len(list(task.dates)) == 0, "Expected 0 dates"
+
+ #===========================================================================
+ # add and delete day
+ #===========================================================================
+ task.add_day(ecflow.Day(ecflow.Days.sunday))
+ task.add_day(ecflow.Days.monday)
+ task.add_day(ecflow.Days.tuesday) # duplicate ?
+ task.add_day("sunday")
+ assert len(list(task.days)) == 4, "Expected 4 days"
+ vec_copy = []
+ for attr in task.days: vec_copy.append(attr)
+ for attr in vec_copy: task.delete_day(attr)
+ assert len(list(task.days)) == 0, "Expected 0 days"
+
+ #===========================================================================
+ # add and delete crons
+ #===========================================================================
+ cron = ecflow.Cron()
+ start = ecflow.TimeSlot(23 , 0)
+ ts = ecflow.TimeSeries(start,True) # True means relative to suite start
+ cron.set_time_series(ts)
+
+ cron = ecflow.Cron()
+ cron.set_week_days([0, 1, 2, 3, 4, 5, 6])
+ cron.set_days_of_month([1, 2, 3, 4, 5, 6 ])
+ cron.set_months([1, 2, 3, 4, 5, 6])
+ start = ecflow.TimeSlot(0 , 0)
+ finish = ecflow.TimeSlot(23, 0)
+ incr = ecflow.TimeSlot(0, 30)
+ ts = ecflow.TimeSeries(start, finish, incr, True) # True means relative to suite start
+ cron.set_time_series(ts)
+
+ cron0 = ecflow.Cron()
+ cron0.set_week_days([0, 1, 2, 3, 4, 5 ])
+ cron0.set_time_series(1, 30) # default relative = false, added in release 4.0.7
+
+ cron1 = ecflow.Cron()
+ cron1.set_week_days([0, 1, 2, 3, 4, 5, 6 ])
+ cron1.set_time_series(1, 30, True)
+
+ cron2 = ecflow.Cron()
+ cron2.set_week_days([0, 1, 2, 3, 4, 5, 6])
+ cron2.set_time_series("00:30 01:30 00:01")
+
+ cron3 = ecflow.Cron()
+ cron3.set_week_days([0, 1, 2, 3, 4, 5, 6])
+ cron3.set_time_series("+00:30")
+
+ task.add_cron(cron)
+ task.add_cron(cron1)
+ task.add_cron(cron2)
+ task.add_cron(cron3)
+ assert len(list(task.crons)) == 4, "Expected 4 crons"
+ vec_copy = []
+ for attr in task.crons: vec_copy.append(attr)
+ for attr in vec_copy: task.delete_cron(attr)
+ assert len(list(task.crons)) == 0, "Expected 0 crons"
+
+ #===========================================================================
+ # add autocancel
+ #===========================================================================
+ print "test add autoCancel"
+ t1 = ecflow.Task("t1")
+ assert t1.get_autocancel() == None, " Expected no autocancel"
+ t1.add_autocancel(3) # 3 days
+ assert t1.get_autocancel() != None, " Expected autocancel"
+ print str(t1.get_autocancel())
+
+ t3 = ecflow.Task("t3")
+ t3.add_autocancel(20, 10, True) # hour,minutes,relative
+ print str(t3.get_autocancel())
+
+ t4 = ecflow.Task("t4")
+ t4.add_autocancel(ecflow.TimeSlot(10, 10), True) # hour,minutes,relative
+ print str(t4.get_autocancel())
+
+ t5 = ecflow.Task("t5")
+ t5.add_autocancel(ecflow.Autocancel(1, 10, True)) # hour,minutes,relative
+ print str(t5.get_autocancel())
+
+ #===========================================================================
+ # add late
+ #===========================================================================
+ late = ecflow.Late()
+ late.submitted(ecflow.TimeSlot(20, 10))
+ late.active(ecflow.TimeSlot(20, 10))
+ late.complete(ecflow.TimeSlot(20, 10), True)
+ task.add_late(late)
+
+ late = ecflow.Late()
+ late.submitted(20, 10)
+ late.active(20, 10)
+ late.complete(20, 10, True)
+ t1.add_late(late)
+
+
+ #===========================================================================
+ # add defstatus, last one set takes effect
+ #===========================================================================
+ task.add_defstatus(ecflow.DState.complete)
+ assert task.get_defstatus() == ecflow.DState.complete
+ task.add_defstatus(ecflow.DState.queued)
+ assert task.get_defstatus() == ecflow.DState.queued
+ task.add_defstatus(ecflow.DState.aborted)
+ assert task.get_defstatus() == ecflow.DState.aborted
+ task.add_defstatus(ecflow.DState.submitted)
+ assert task.get_defstatus() == ecflow.DState.submitted
+ task.add_defstatus(ecflow.DState.suspended)
+ assert task.get_defstatus() == ecflow.DState.suspended
+ task.add_defstatus(ecflow.DState.active)
+ assert task.get_defstatus() == ecflow.DState.active
+
+ # the state should be unknown until the suite is begun
+ assert task.get_state() == ecflow.State.unknown
+ assert task.get_dstate() == ecflow.DState.unknown
+
+ #===========================================================================
+ # add clock
+ #===========================================================================
+ clock = ecflow.Clock(1, 1, 2010, False) # day,month, year, hybrid
+ clock.set_gain(1, 10, True) # True means positive gain
+ suite = ecflow.Suite("suite")
+ suite.add_clock(clock)
+
+ clock = ecflow.Clock(1, 1, 2011, True) # day,month, year, hybrid
+ clock.set_gain_in_seconds(12, True)
+ s1 = ecflow.Suite("s1")
+ s1.add_clock(clock)
+
+ print "#==========================================================================="
+ print "# get clock"
+ print "#==========================================================================="
+ s0 = ecflow.Suite("s0")
+ assert s0.get_clock() == None, "Expected no clock"
+
+ s0.add_clock(ecflow.Clock(1, 1, 2010, False))
+ assert s0.get_clock() != None, "Expected clock"
+
+ #===========================================================================
+ # Add zombie. Note we can *NOT* add two zombie attributes of the same ZombieType
+ #===========================================================================
+ zombie_life_time_in_server = 800
+ child_list = [ ecflow.ChildCmdType.init, ecflow.ChildCmdType.event, ecflow.ChildCmdType.meter, ecflow.ChildCmdType.label, ecflow.ChildCmdType.wait, ecflow.ChildCmdType.abort, ecflow.ChildCmdType.complete ]
+ zombie_type_list = [ ecflow.ZombieType.ecf, ecflow.ZombieType.user, ecflow.ZombieType.path ]
+ for zombie_type in zombie_type_list:
+ zombie_attr = ecflow.ZombieAttr(zombie_type, child_list, ecflow.ZombieUserActionType.block, zombie_life_time_in_server)
+ s1.add_zombie(zombie_attr)
+ assert len(list(s1.zombies)) == 3, "Expected 3 zombie attributes but found " + str(len(list(s1.zombies)))
+
+ # delete all the zombies
+ s1.delete_zombie("")
+ assert len(list(s1.zombies)) == 0, "Expected zero zombie attributes but found " + str(len(list(s1.zombies)))
+
+ # add with zombie_life_time_in_server not set, this is optional
+ for zombie_type in zombie_type_list:
+ zombie_attr = ecflow.ZombieAttr(zombie_type, child_list, ecflow.ZombieUserActionType.block)
+ s1.add_zombie(zombie_attr)
+ assert len(list(s1.zombies)) == 3, "Expected 3 zombie attributes but found " + str(len(list(s1.zombies)))
+
+ s1.delete_zombie("")
+ assert len(list(s1.zombies)) == 0, "Expected zero zombie attributes but found " + str(len(list(s1.zombies)))
+
+ # repeat the the test with empty child list. Empty child list means apply to all child commands
+ child_list = [ ]
+ zombie_type_list = [ ecflow.ZombieType.ecf, ecflow.ZombieType.user, ecflow.ZombieType.path ]
+ for zombie_type in zombie_type_list:
+ zombie_attr = ecflow.ZombieAttr(zombie_type, child_list, ecflow.ZombieUserActionType.block, zombie_life_time_in_server)
+ s1.add_zombie(zombie_attr)
+
+ # test delete of specific zombie attribute
+ assert len(list(s1.zombies)) == 1, "Expected 1 zombie attributes but found " + str(len(list(s1.zombies)))
+ s1.delete_zombie(zombie_type)
+ assert len(list(s1.zombies)) == 0, "Expected 0 zombie attributes but found " + str(len(list(s1.zombies)))
+
+
+ print "All Tests pass"
+
diff --git a/Pyext/test/py_u_TestAddDeleteError.py b/Pyext/test/py_u_TestAddDeleteError.py
new file mode 100644
index 0000000..e76c47e
--- /dev/null
+++ b/Pyext/test/py_u_TestAddDeleteError.py
@@ -0,0 +1,86 @@
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#
+from ecflow import Defs, Suite, Variable, Limit, InLimit, Task, PartExpression, \
+ Event, Meter, Label, RepeatInteger, RepeatEnumerated, RepeatDate, RepeatString, \
+ TimeSlot, TimeSeries, Today, Time, Date, Day, Days, Cron, Autocancel, Late, \
+ DState, Clock, ChildCmdType, ZombieType, ZombieAttr, ZombieUserActionType, Client, debug_build
+
+
+if __name__ == "__main__":
+
+ print "######################################################################################"
+ print "Running ecflow version " + Client().version() + " debug build(" + str(debug_build()) +")"
+ print "######################################################################################"
+
+ #
+ # Test for: See ECFLOW-106 Times/Dates attributes attached to suite node
+ #
+ defs = Defs()
+ suite = defs.add_suite("s1")
+
+ #
+ # Suite should not be allowed time based dependencies
+ # Check Today
+ expected_error = False
+ try:
+ suite.add_today("00:30")
+ except RuntimeError:
+ expected_error = True
+ assert expected_error, "Suite should not allow any time based dependencies"
+
+ expected_error = False
+ try:
+ suite.add_today(0,30)
+ except RuntimeError:
+ expected_error = True
+ assert expected_error, "Suite should not allow any time based dependencies"
+
+ #
+ # Check Time
+ expected_error = False
+ try:
+ suite.add_time("+00:30")
+ except RuntimeError:
+ expected_error = True
+ assert expected_error, "Suite should not allow any time based dependencies"
+
+ expected_error = False
+ try:
+ suite.add_time(0,30)
+ except RuntimeError:
+ expected_error = True
+ assert expected_error, "Suite should not allow any time based dependencies"
+
+ #
+ # Check Date::See ECFLOW-106 Times/Dates attributes attached to suite node
+ expected_error = False
+ try:
+ suite.add_date( 1,1,2010)
+ except RuntimeError:
+ expected_error = True
+ assert expected_error, "Suite should not allow any time based dependencies"
+
+ #
+ # Check Day:: See ECFLOW-106 Times/Dates attributes attached to suite node
+ expected_error = False
+ try:
+ suite.add_day("sunday")
+ except RuntimeError:
+ expected_error = True
+ assert expected_error, "Suite should not allow any time based dependencies"
+
+
+ print "All Tests pass"
+
\ No newline at end of file
diff --git a/Pyext/test/py_u_TestAddDeleteFunc.py b/Pyext/test/py_u_TestAddDeleteFunc.py
new file mode 100644
index 0000000..0dc3c3d
--- /dev/null
+++ b/Pyext/test/py_u_TestAddDeleteFunc.py
@@ -0,0 +1,311 @@
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#
+from ecflow import Defs, Suite, Variable, Limit, InLimit, Task, PartExpression, \
+ Event, Meter, Label, RepeatInteger, RepeatEnumerated, RepeatDate, RepeatString, \
+ TimeSlot, TimeSeries, Today, Time, Date, Day, Days, Cron, Autocancel, Late, \
+ DState, Clock, ChildCmdType, ZombieType, ZombieAttr, ZombieUserActionType, Client, debug_build
+
+
+if __name__ == "__main__":
+
+ print "####################################################################"
+ print "Running ecflow version " + Client().version() + " debug build(" + str(debug_build()) +")"
+ print "####################################################################"
+
+ #
+ # Add Nodes functional way
+ #
+ defs = Defs()
+ defs.add_suite("s1").add_task("t1").add_variable("var","v")
+ defs.add_suite("s2").add_family("f1").add_task("t1").add_variable("var","v")
+ defs.add_suite("s3").add_family("f1").add_family("f2").add_task("t1").add_variable("var","v")
+ assert len(list(defs.suites)) == 3,"Expected 3 suites"
+
+
+ # add and delete variables
+ a_dict = { "name":"value", "name2":"value2", "name3":"value3", "name4":"value4" }
+ suite = Suite("s1")
+ suite.add_variable(Variable("ECF_HOME","'/tmp/'")) \
+ .add_variable("Fred", 1)\
+ .add_variable("ECF_URL_BASE",'http://www.ecmwf.int')\
+ .add_variable("ECF_URL",'"publications/manuals/sms"')\
+ .add_variable(a_dict)
+ print suite
+ assert len(list(suite.variables)) == 8,"Expected 8 variable"
+ suite.delete_variable(""); assert len(list(suite.variables)) == 0,"Expected 0 variable since we should have deleted all"
+
+
+ # add and delete limits
+ the_limit = Limit("limitName1", 10)
+ assert len(list(the_limit.node_paths())) == 0 ,"Expected nodes which have consumed a limit to be empty"
+ suite.add_limit( Limit("limitName1", 10) )\
+ .add_limit( Limit("limitName2", 10) )\
+ .add_limit( "limitName3", 10 )\
+ .add_limit( "limitName4", 10 )
+ assert len(list(suite.limits)) == 4,"Expected 4 Limits"
+ suite.delete_limit(""); assert len(list(suite.limits)) == 0,"Expected 0 limits since we just deleted all of them"
+
+
+ # add and delete inlimits
+ suite.add_inlimit( InLimit("limitName1","/s1/f1",2) )\
+ .add_inlimit( InLimit("limitName2","/s1/f1",2))\
+ .add_inlimit( "limitName3","/s1/f1",2)\
+ .add_inlimit( "limitName4","/s1/f1",2)
+ assert len(list(suite.inlimits)) == 4,"Expected 4 inLimits"
+ suite.delete_inlimit("limitName1"); assert len(list(suite.inlimits)) == 3,"Expected 3 inlimits since we just deleted one limitName1"
+ suite.delete_inlimit(""); assert len(list(suite.inlimits)) == 0,"Expected 0 inlimits since we just deleted all of them"
+
+
+ # add and delete triggers and complete
+ task = Task("task")
+ task.add_trigger( "t2 == active" ).add_complete( "t2 == complete" )
+ assert task.get_complete(), "Expected complete"
+ assert task.get_trigger(), "Expected trigger"
+ task.delete_trigger(); assert not task.get_trigger(), "Expected no trigger"
+ task.delete_complete(); assert not task.get_complete(), "Expected no complete"
+
+ task.add_part_trigger( PartExpression("t1 == complete") )\
+ .add_part_complete( PartExpression("t3 == complete") ) \
+ .add_part_complete( PartExpression("t4 == active",False) )
+ task.delete_trigger(); assert not task.get_trigger(), "Expected no trigger"
+ task.delete_complete(); assert not task.get_complete(), "Expected no complete"
+
+ task.add_part_trigger( "t1 == complete" ) \
+ .add_part_complete( "t3 == complete" ) \
+ .add_part_complete( "t4 == active",False) # for long and/or expressions, subsequent expr must be and/or
+ task.delete_trigger(); assert not task.get_trigger(), "Expected no trigger"
+ task.delete_complete(); assert not task.get_complete(), "Expected no complete"
+
+
+ # add and delete events
+ task.add_event( Event(1) ).add_event( 2 ).add_event( Event(10, "Eventname") ).add_event( 10, "Eventname2" ).add_event( "fred" )
+ assert len(list(task.events)) == 5,"Expected 5 Events"
+ task.delete_event(""); assert len(list(task.events)) == 0,"Expected 0 Events"
+
+
+ # add and delete meter
+ task.add_meter( Meter("metername1", 0, 100, 50) )\
+ .add_meter( Meter("metername2", 0, 100) )\
+ .add_meter( "metername3", 0, 100, 50 )\
+ .add_meter( "metername4", 0, 100 )
+ assert len(list(task.meters)) == 4,"Expected 4 Meters"
+ task.delete_meter(""); assert len(list(task.meters)) == 0,"Expected 0 Meters"
+
+
+ # add and delete label
+ task.add_label( Label("label_name1", "value") )\
+ .add_label( Label("label_name2", "value") )\
+ .add_label( "label_name3", "value" )\
+ .add_label( "label_name4", "value" )
+ assert len(list(task.labels)) == 4,"Expected 4 labels"
+ task.delete_label(""); assert len(list(task.labels)) == 0,"Expected 0 Labels"
+
+
+ # add delete Repeat
+ task.add_repeat( RepeatInteger("integer", 0, 100, 2) ).add_variable("fred","j")
+ repeat = task.get_repeat(); assert not repeat.empty(), "Expected repeat"
+ task.delete_repeat()
+ repeat = task.get_repeat(); assert repeat.empty(), "Expected no repeat"
+
+ task.add_repeat( RepeatEnumerated("enum", ["red", "green", "blue" ]) ).add_variable("Q","j")
+ print task
+ task.delete_repeat()
+ repeat = task.get_repeat(); assert repeat.empty(), "Expected no repeat"
+
+ task.add_repeat( RepeatDate("date", 20100111, 20100115,2) ).add_variable("W","j")
+ task.delete_repeat()
+ repeat = task.get_repeat(); assert repeat.empty(), "Expected no repeat"
+
+ task.add_repeat( RepeatString("string", ["a", "b", "c" ] ) ).add_variable("E","j")
+ task.delete_repeat()
+ repeat = task.get_repeat(); assert repeat.empty(), "Expected no repeat"
+
+
+ # create a time series, used for adding time and today
+ start = TimeSlot(0, 0)
+ finish = TimeSlot(23, 0)
+ incr = TimeSlot(0, 30)
+ time_series = TimeSeries( start, finish, incr, True)
+
+ # Add and delete today
+ # NOTE: **********************************************************************
+ # Do *NOT* delete attributes using iterator traversal
+ # The iterators *are* bound to the c++ iterators hence if we delete
+ # over the traversal, we can corrupt the vector, leading to undefined behaviour.
+ # Hence we **can not** delete more than once over a traversal
+ # Soln 1: take a copy
+ # *****************************************************************************
+ # task.add_today( Today( 0,10 ))
+ # task.add_today( Today( 0,59, True ))
+ # task.add_today( Today(TimeSlot(20,10)) )
+ # task.add_today( Today(TimeSlot(20,20),False))
+ # for today in task.todays:
+ # task.delete_today(today) # will corrupt C++ vector
+
+ task.add_today( "00:30" ).add_today( "+00:30" ).add_today( "+00:30 20:00 01:00" )\
+ .add_today( Today( time_series) )\
+ .add_today( Today( 0,10 )).add_today( 0, 59, True )\
+ .add_today( Today(TimeSlot(20,10)) )\
+ .add_today( Today(TimeSlot(20,20),False))
+ assert len(list(task.todays)) == 8,"Expected 8 todays"
+ vec_copy = []
+ for today in task.todays: vec_copy.append(today)
+ for today in vec_copy: task.delete_today(today)
+ assert len(list(task.todays)) == 0,"Expected 0 todays"
+
+
+ # add and delete time
+ task.add_time( "00:30" ).add_time( "+00:30" ).add_time( "+00:30 20:00 01:00" )\
+ .add_time( Time(time_series ))\
+ .add_time( Time( 0,10 ))\
+ .add_time( 0, 59, True)\
+ .add_time( Time(TimeSlot(20,10)) )\
+ .add_time( Time(TimeSlot(20,20),False))
+ assert len(list(task.times)) == 8,"Expected 8 times"
+ vec_copy = []
+ for time in task.times: vec_copy.append(time)
+ for time in vec_copy: task.delete_time(time)
+ assert len(list(task.todays)) == 0,"Expected 0 todays"
+
+
+ # add and delete date
+ for i in [ 1, 2, 4, 8, 16 ] :
+ task.add_date( i, 0, 0)
+ task.add_date( Date(1, 1, 2010))\
+ .add_date( Date(2, 1, 2010))\
+ .add_date( Date(3, 1, 2010))\
+ .add_date( Date(4, 1, 2010))\
+ .add_date( 1, 1, 2010)
+ assert len(list(task.dates)) == 10,"Expected 10 dates but found " + str(len(list(task.dates)))
+ vec_copy = []
+ for attr in task.dates: vec_copy.append(attr)
+ for attr in vec_copy: task.delete_date(attr)
+ assert len(list(task.dates)) == 0,"Expected 0 dates"
+
+ # add and delete day
+ task.add_day( Day(Days.sunday))\
+ .add_day( Days.monday)\
+ .add_day( Days.tuesday)\
+ .add_day( "sunday")
+ assert len(list(task.days)) == 4,"Expected 4 days"
+ vec_copy = []
+ for attr in task.days: vec_copy.append(attr)
+ for attr in vec_copy: task.delete_day(attr)
+ assert len(list(task.days)) == 0,"Expected 0 days"
+
+ # add and delete crons
+ cron = Cron()
+ cron.set_week_days( [0, 1, 2, 3, 4, 5, 6] )
+ cron.set_days_of_month( [1, 2, 3, 4, 5, 6 ] )
+ cron.set_months( [1, 2, 3, 4, 5, 6] )
+ start = TimeSlot(0 ,0)
+ finish = TimeSlot(23, 0)
+ incr = TimeSlot(0, 30)
+ ts = TimeSeries( start, finish, incr, True) # True means relative to suite start
+ cron.set_time_series( ts )
+
+ cron1 = Cron()
+ cron1.set_week_days( [0, 1, 2, 3, 4, 5, 6 ] )
+ cron1.set_time_series( 1, 30, True )
+
+ cron2 = Cron()
+ cron2.set_week_days( [0, 1, 2, 3, 4, 5, 6] )
+ cron2.set_time_series( "00:30 01:30 00:01" )
+
+ cron3 = Cron()
+ cron3.set_week_days( [0, 1, 2, 3, 4, 5, 6] )
+ cron3.set_time_series( "+00:30" )
+
+ task.add_cron( cron ) \
+ .add_cron( cron1 ) \
+ .add_cron( cron2 ) \
+ .add_cron( cron3 )
+ assert len(list(task.crons)) == 4,"Expected 4 crons"
+ vec_copy = []
+ for attr in task.crons: vec_copy.append(attr)
+ for attr in vec_copy: task.delete_cron(attr)
+ assert len(list(task.crons)) == 0,"Expected 0 crons"
+
+
+ # add autocancel
+ t1 = Task("t1")
+ t1.add_autocancel( 3 ).add_variable("A","j")
+ t3 = Task("t3")
+ t3.add_autocancel( 20, 10, True ).add_variable("B","j")
+ t4 = Task("t4")
+ t4.add_autocancel( TimeSlot(10, 10), True ).add_variable("C","j")
+ t5 = Task("t5")
+ t5.add_autocancel( Autocancel(1, 10, True) ).add_variable("D","j")
+
+
+ # add late
+ late = Late()
+ late.submitted( TimeSlot(20, 10) )
+ late.active( TimeSlot(20, 10))
+ late.complete( TimeSlot(20, 10), True)
+ task.add_late(late ).add_variable("FRED33","j")
+
+
+ # add defstatus, last one set takes effect
+ task.add_defstatus( DState.complete )\
+ .add_defstatus( DState.queued )\
+ .add_defstatus( DState.aborted )\
+ .add_defstatus( DState.submitted )\
+ .add_defstatus( DState.suspended )\
+ .add_defstatus( DState.active )
+
+ #
+ # add clock
+ #
+ clock = Clock(1, 1, 2010, False) # day,month, year, hybrid
+ clock.set_gain(1, 10, True) # True means positive gain
+ suite = Suite("suite")
+ suite.add_clock(clock).add_variable("fred1","j")
+
+ clock = Clock(1, 1, 2011, True) # day,month, year, hybrid
+ clock.set_gain_in_seconds(12, True)
+ s1 = Suite("s1")
+ s1.add_clock(clock).add_variable("fred2","j")
+
+ #
+ # Add zombie. Note we can *NOT* add two zombie attributes of the same ZombieType
+ #
+ zombie_life_time_in_server = 800
+ child_list = [ ChildCmdType.init, ChildCmdType.event, ChildCmdType.meter, ChildCmdType.label, ChildCmdType.wait, ChildCmdType.abort, ChildCmdType.complete ]
+ zombie_type_list = [ ZombieType.ecf, ZombieType.user, ZombieType.path ]
+ for zombie_type in zombie_type_list:
+ zombie_attr = ZombieAttr(zombie_type, child_list, ZombieUserActionType.block, zombie_life_time_in_server)
+ s1.add_zombie(zombie_attr).add_variable("fred","j")
+ assert len(list(s1.zombies)) == 3,"Expected 3 zombie attributes but found " + str(len(list(s1.zombies)))
+
+ # delete all the zombies
+ s1.delete_zombie("")
+ assert len(list(s1.zombies)) == 0,"Expected zero zombie attributes but found " + str(len(list(s1.zombies)))
+
+ # repeat the the test with empty child list. Empty child list means apply to all child commands
+ # + don't specify zombie_life_time_in_server as this is optional
+ child_list = [ ]
+ zombie_type_list = [ ZombieType.ecf, ZombieType.user, ZombieType.path ]
+ for zombie_type in zombie_type_list:
+ zombie_attr = ZombieAttr(zombie_type, child_list, ZombieUserActionType.block)
+ s1.add_zombie(zombie_attr).add_variable("fred","j")
+
+ # test delete of specific zombie attribute
+ assert len(list(s1.zombies)) == 1,"Expected 1 zombie attributes but found " + str(len(list(s1.zombies)))
+ s1.delete_zombie(zombie_type)
+ assert len(list(s1.zombies)) == 0,"Expected 0 zombie attributes but found " + str(len(list(s1.zombies)))
+
+ print "All Tests pass"
+
\ No newline at end of file
diff --git a/Pyext/test/py_u_TestAddNodeFunc.py b/Pyext/test/py_u_TestAddNodeFunc.py
new file mode 100644
index 0000000..aaee178
--- /dev/null
+++ b/Pyext/test/py_u_TestAddNodeFunc.py
@@ -0,0 +1,69 @@
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+from ecflow import Defs, Client, debug_build
+
+def create_defs_sequentially():
+ local_defs = Defs()
+ suite = local_defs.add_suite("s1")
+ suite.add_variable("Var","value")
+ suite.add_trigger("t1 == complete")
+ suite.add_meter( "metername3", 0, 100, 50 )
+ suite.add_event( 2 )
+ suite.add_event( 3 )
+ f1 = suite.add_family("f1")
+ f1 = f1.add_family("f1")
+ t1 = f1.add_task("t1")
+ t1.add_variable("fred","jones")
+
+ f2 = suite.add_family("f2")
+ f1 = f2.add_family("f1")
+ t1 = f1.add_task("t1")
+ t1.add_variable("fred","jones")
+
+ f3 = suite.add_family("f3")
+ t1 = f3.add_task("t1")
+ t1.add_variable("fred", "jones")
+
+ suite.add_task("t1").add_variable("fred","jones")
+ return local_defs
+
+def create_defs_functionally():
+ f_defs = Defs()
+ suite = f_defs.add_suite("s1")
+ suite.add_variable("Var","value").add_family("f1").add_family("f1").add_task("t1").add_variable("fred","jones")
+ suite.add_trigger("t1 == complete").add_family("f2").add_family("f1").add_task("t1").add_variable("fred","jones")
+ suite.add_meter( "metername3", 0, 100, 50 ).add_family("f3").add_task("t1").add_variable("fred","jones")
+ suite.add_event( 2 ).add_event( 3 ).add_task("t1").add_variable("fred","jones")
+ return f_defs
+
+
+if __name__ == "__main__":
+ print "####################################################################"
+ print "Running ecflow version " + Client().version() + " debug build(" + str(debug_build()) +")"
+ print "####################################################################"
+
+ #
+ # Add Nodes functional way
+ #
+ defs = Defs()
+ defs.add_suite("s1").add_task("t1").add_variable("var","v")
+ defs.add_suite("s2").add_family("f1").add_task("t1").add_variable("var","v")
+ defs.add_suite("s3").add_family("f1").add_family("f2").add_task("t1").add_variable("var","v")
+ assert len(list(defs.suites)) == 3,"Expected 3 suites"
+
+ # These test show that although add_variable() returns a node_ptr, its really a suite
+ # hence calling add_family/add_task still works.
+ assert create_defs_sequentially() == create_defs_functionally(),"Functional suite not as expected "
+
+ print "All Tests pass"
+
\ No newline at end of file
diff --git a/Pyext/test/py_u_TestDefs.py b/Pyext/test/py_u_TestDefs.py
new file mode 100644
index 0000000..d272cf8
--- /dev/null
+++ b/Pyext/test/py_u_TestDefs.py
@@ -0,0 +1,221 @@
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# code for testing creation of defs file in python
+import os
+import ecflow
+print ecflow.__doc__
+print ecflow.Defs.__doc__
+
+from ecflow import Suite, Family, Task, Defs, Clock, DState, PartExpression, Variable, Limit, InLimit, \
+ Date, Day, Event, Meter, Label, Autocancel, Days, TimeSlot, TimeSeries, Style, State, \
+ RepeatString, RepeatDate, RepeatInteger, RepeatDay, RepeatEnumerated, \
+ Verify, PrintStyle, Time, Today, Late, Cron, Client, debug_build
+
+if __name__ == "__main__":
+ print "####################################################################"
+ print "Running ecflow version " + Client().version() + " debug build(" + str(debug_build()) +")"
+ print "####################################################################"
+
+ suite = Suite("s1")
+ assert (isinstance(suite, ecflow.Suite)), "Expected suite"
+ assert (not isinstance(suite, ecflow.Family)), "Expected suite"
+ assert (not isinstance(suite, ecflow.Task)), "Expected suite"
+
+ family = Family("f1")
+ assert (isinstance(family, ecflow.Family)), "Expected Family"
+ assert (not isinstance(family, ecflow.Suite)), "Expected Family"
+ assert (not isinstance(family, ecflow.Task)), "Expected Family"
+ suite.add_family(family)
+
+ task = Task("f1")
+ assert (isinstance(task, ecflow.Task)), "Expected Task"
+ assert (not isinstance(task, ecflow.Suite)), "Expected Task"
+ assert (not isinstance(task, ecflow.Family)), "Expected Task"
+ family.add_task(task)
+
+
+ defs = Defs()
+ defs2 = Defs()
+ assert defs == defs2, "Empty defs should be equal"
+
+ assert defs.get_state() == ecflow.State.unknown, "Expected default state to be unknown"
+ defs.add_suite(suite); # add existing suite to defs
+
+ suite = defs.add_suite("s2");
+ suite.add_variable(Variable("ECF_HOME","/tmp/"))
+ suite.add_variable("ECF_URL_CMD", "${BROWSER:=firefox} -remote 'openURL(%ECF_URL_BASE%/%ECF_URL%)'")
+ suite.add_variable("ECF_URL_BASE","http://www.ecmwf.int")
+ suite.add_variable("ECF_URL","publications/manuals/sms")
+ suite.add_limit( Limit("limitName", 10) )
+ suite.add_limit( "limitName_2", 10 )
+ assert suite.begun() == False, "Suite should not have begun"
+
+ clock = Clock(1,1,2010,False);
+ clock.set_gain(1,10,True);
+ suite.add_clock(clock);
+
+ assert defs != defs2, "Defs should no longer compare as they are different"
+
+ defs.add_extern("/path/to/task");
+ defs.add_extern("/fred/bill:event_name");
+
+ family = suite.add_family("f1")
+ family.add_defstatus( DState.active );
+
+ task = family.add_task("t1")
+ task.add_trigger( "t2 == active" )
+ task.add_complete( "t2 == complete" )
+ task.add_autocancel( Autocancel(3) );
+
+ task2 = family.add_task("t2")
+ task2.add_defstatus( DState.complete );
+ task2.add_part_trigger( PartExpression("t1 == complete") )
+ task2.add_part_trigger( PartExpression("t1 == active",True) ) # for long and/or expressions, subsequent expr must be and/or
+ task2.add_part_complete( PartExpression("t1 == complete") )
+ task2.add_part_complete( PartExpression("t1 == active",False) ) # for long and/or expressions, subsequent expr must be and/or
+ task2.add_label( Label("labelname", "label1") )
+ task2.add_label( "labelname2", "label1")
+ task2.add_inlimit( InLimit("limitName","/s1/f1",2) )
+ task2.add_inlimit( "limitName2" )
+ task2.add_event( 10 )
+ task2.add_event( Event(10,"Eventname") )
+ task2.add_meter( Meter("metername",0,100,50) )
+ task2.add_meter( "metername2",0,100,50 )
+ task2.add_date( Date(1,1,2010) )
+ task2.add_date( 1,2,2010 )
+ task2.add_day( Day(Days.sunday) )
+ task2.add_day( Days.monday )
+ task2.add_autocancel( Autocancel(TimeSlot(20,10),True) )
+
+ task2.add_today( 0,10 )
+ task2.add_today( Today( 0,59, True ))
+ task2.add_today( Today(TimeSlot(20,10)) )
+ task2.add_today( Today(TimeSlot(20,20),False))
+ start = TimeSlot(0,0)
+ finish = TimeSlot(23,0)
+ incr = TimeSlot(0,30)
+ ts = TimeSeries( start, finish, incr, True);
+ task2.add_today( Today(ts) )
+
+ task2.add_time( 20,10 )
+ task2.add_time( Time(20,12,True) )
+ task2.add_time( Time(TimeSlot(20,12)))
+ task2.add_time( Time(TimeSlot(20,20),True))
+ task2.add_time( Time(ts) )
+
+ late = Late()
+ late.submitted( 20,10 )
+ late.active(TimeSlot(20,10))
+ late.complete(TimeSlot(20,10),True)
+ task2.add_late( late )
+
+ cron = Cron()
+ cron.set_week_days( [0,1,2,3,4,5,6] )
+ cron.set_days_of_month( [1,2,3,4,5,6] )
+ cron.set_months( [1,2,3,4,5,6] )
+ cron.set_time_series( ts )
+ task2.add_cron( cron );
+
+ task3 = family.add_task("t3")
+ task3.add_repeat( RepeatDate("testDate",20100111,20100115,2) )
+ task3.add_defstatus( DState.queued );
+ task3.add_verify( Verify(State.complete, 1) )
+ task3.add_autocancel( Autocancel(20,10,False) )
+ task3.add_label( Label("label_name","label_value") )
+
+ task3_1 = family.add_task("t3_1")
+ task3_1.add_repeat( RepeatDate("testDate",20100111,20100115) )
+
+
+ task4 = family.add_task("t4")
+ task4.add_repeat( RepeatInteger("testInteger",0,100,2) )
+ task4.add_defstatus( DState.aborted );
+
+ task4_1 = family.add_task("t4_1")
+ task4_1.add_repeat( RepeatInteger("testInteger",0,100) )
+
+
+ task5 = family.add_task("t5")
+ task5.add_repeat( RepeatEnumerated("testInteger", ["red", "green", "blue" ] ) )
+ task5.add_defstatus( DState.submitted );
+
+ task6 = family.add_task("t6")
+ task6.add_repeat( RepeatString("test_string", ["a", "b", "c" ] ) )
+ task6.add_defstatus( DState.suspended );
+
+ task7 = family.add_task("t7")
+ task7.add_repeat( RepeatDay(2) )
+ task7.add_defstatus( DState.active );
+
+ task8 = family.add_task("t8")
+ task8.add_repeat( RepeatDay() )
+ print "task8.get_try_no() :string:",task8.get_try_no()
+ print "task8.get_int_try_no():int :",task8.get_int_try_no()
+
+ the_defs = task8.get_defs()
+
+
+ # Test find
+ assert defs.find_suite("s1") != None, "Expected to find suite of name s1"
+ assert defs.find_suite("sffff1") == None, "Should not be able to find suite of name sfffff1"
+
+ # save the defs file as a check point file and restore it again
+ checkpt_file = "py_u_TestDefs.check"
+ defs_file = "py_u_TestDefs.def"
+ if debug_build() :
+ checkpt_file = "py_u_TestDefs_debug.check"
+ defs_file = "py_u_TestDefs_debug.def"
+ defs.save_as_checkpt(checkpt_file);
+
+ restored_checkpt_defs = Defs()
+ restored_checkpt_defs.restore_from_checkpt(checkpt_file)
+
+ print "Save and restore as Defs ******************************************************"
+ defs.save_as_defs(defs_file) # default is to save as DEFS
+ restored_from_defs = Defs( defs_file ) # restore the defs
+
+ defs.save_as_defs(defs_file,Style.DEFS)
+ restored_from_defs = Defs( defs_file ) # restore the defs
+
+ print "Save and restore using STATE ******************************************************"
+ defs.save_as_defs(defs_file,Style.STATE)
+ restored_from_defs = Defs( defs_file ) # restore the defs
+
+ print "Save and restore using MIGRATE ******************************************************"
+ defs.save_as_defs(defs_file,Style.MIGRATE)
+ restored_from_defs = Defs( defs_file ) # restore the defs
+ assert restored_checkpt_defs == restored_from_defs ,"File should be the same"
+
+
+ print "Print in DEFS style ******************************************************"
+ PrintStyle.set_style(Style.DEFS)
+ the_string = str(restored_from_defs)
+ assert the_string.find("defs_state") == -1, "Print in DEFS style failed"
+ print the_string
+
+ print "Print in STATE style *****************************************************"
+ PrintStyle.set_style(Style.STATE)
+ the_string = str(restored_from_defs)
+ assert the_string.find("defs_state STATE") != -1, "Print in STATE style failed"
+ print the_string
+
+ print "Print in MIGRATE style *****************************************************"
+ PrintStyle.set_style(Style.MIGRATE)
+ the_string = str(restored_from_defs)
+ assert the_string.find("defs_state MIGRATE") != -1, "Print in MIGRATE style failed"
+ print the_string
+
+ # Comment this out if you want to see what the file looked like
+ os.remove(checkpt_file)
+ os.remove(defs_file)
+ print "All tests pass"
\ No newline at end of file
diff --git a/Pyext/test/py_u_TestDefsCheck.py b/Pyext/test/py_u_TestDefsCheck.py
new file mode 100644
index 0000000..d5e8bdb
--- /dev/null
+++ b/Pyext/test/py_u_TestDefsCheck.py
@@ -0,0 +1,72 @@
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+# Test the error and waning checks defined in the defs work
+
+from ecflow import Defs, Limit, InLimit, Client, debug_build
+
+if __name__ == "__main__":
+ print "####################################################################"
+ print "Running ecflow version " + Client().version() + " debug build(" + str(debug_build()) +")"
+ print "####################################################################"
+
+ defs = Defs()
+ suite = defs.add_suite("s1");
+ suite.add_task("t1").add_trigger("t2 == active)")
+ theCheckValue = defs.check();
+ print "Message: '" + theCheckValue + "'"
+ assert len(theCheckValue) != 0, "Expected Error: triggers fail parse, miss-matched brackets in expression."
+
+ # The number of tokens specified on the in-limit must be less than or equal to those specified on the LIMIT
+ defs = Defs()
+ suite = defs.add_suite("s1");
+ suite.add_limit( Limit("disk", 50) );
+ family = suite.add_family("anon");
+ family.add_inlimit( InLimit("disk","/s1",100) )
+ family.add_task( "t1" );
+ theCheckValue = defs.check();
+ print "Message: '" + theCheckValue + "'"
+ assert len(theCheckValue) != 0, "Expected Error: since inlimit value('100') is greater than the LIMIT value('50')"
+
+
+ # When a path is specified on the in-limit we search for the limit on that path, otherwise the extern's
+ defs = Defs()
+ suite = defs.add_suite("s1");
+ family = suite.add_family("anon");
+ family.add_inlimit( InLimit("disk","/s1",100) )
+ family.add_task( "t1" );
+ theCheckValue = defs.check();
+ print "Message: '" + theCheckValue + "'"
+ assert len(theCheckValue) != 0, "Expected warning: since inlimit PATH(/s1:disk) reference a limit('disk') that does not exist"
+
+ # Add as extern and repeat the check
+ defs.add_extern("/s1:disk")
+ assert len(defs.check()) == 0, "Expected no warnings, since extern specified: " + defs.check()
+
+
+ # When no path is specified on the in-limit, we search for the limit up the node tree, otherwise the extern's
+ defs = Defs()
+ suite = defs.add_suite("s1");
+ family = suite.add_family("anon");
+ family.add_inlimit( InLimit("disk","",100) )
+ family.add_task( "t1" );
+ theCheckValue = defs.check();
+ print "Message: '" + theCheckValue + "'"
+ assert len(theCheckValue) != 0, "Expected warning: since inlimit SHOULD reference a limit('disk') somewhere UP parent hierarchy"
+
+ # Add as extern and repeat the check
+ defs.add_extern("disk")
+ assert len(defs.check()) == 0, "Expected no warnings, since extern specified"
+
+ print "All Tests pass"
+
\ No newline at end of file
diff --git a/Pyext/test/py_u_TestDerivable.py b/Pyext/test/py_u_TestDerivable.py
new file mode 100644
index 0000000..c1fc7d1
--- /dev/null
+++ b/Pyext/test/py_u_TestDerivable.py
@@ -0,0 +1,28 @@
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+# code for testing derivation works
+import ecflow
+
+class MyDefs(ecflow.Defs): pass
+class MySuite(ecflow.Suite): pass
+class MyFamily(ecflow.Family): pass
+class MyTask(ecflow.Task): pass
+class MyClient(ecflow.Client): pass
+
+if __name__ == "__main__":
+ print "####################################################################"
+ print "Running ecflow version " + ecflow.Client().version() + " debug build(" + str(ecflow.debug_build()) +")"
+ print "####################################################################"
+
+ print "All tests pass"
\ No newline at end of file
diff --git a/Pyext/test/py_u_TestEcf.py b/Pyext/test/py_u_TestEcf.py
new file mode 100644
index 0000000..13d4cda
--- /dev/null
+++ b/Pyext/test/py_u_TestEcf.py
@@ -0,0 +1,38 @@
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# code for testing creation of defs file in python
+import os
+import ecflow
+
+from ecflow import Ecf, Client, debug_build
+
+if __name__ == "__main__":
+ print "####################################################################"
+ print "Running TestEcf, ecflow version " + Client().version() + " debug build(" + str(debug_build()) +")"
+ print "####################################################################"
+
+ default_debug_level = Ecf.debug_level()
+ assert default_debug_level == 0, "Expected default debug level to be 0"
+ Ecf.set_debug_level(10)
+ assert Ecf.debug_level() == 10, "Expected debug level to be 10"
+ Ecf.set_debug_level(0)
+ assert Ecf.debug_level() == 0, "Expected debug level to be 0"
+
+
+ assert Ecf.debug_equality() == False, "Expected default for Ecf.debug_equality() == False "
+ Ecf.set_debug_equality(True)
+ assert Ecf.debug_equality() == True, "Expected debug_equality() == True "
+ Ecf.set_debug_equality(False)
+ assert Ecf.debug_equality() == False, "Expected Ecf.debug_equality() == False "
+
+ print "All tests pass"
\ No newline at end of file
diff --git a/Pyext/test/py_u_TestError.py b/Pyext/test/py_u_TestError.py
new file mode 100644
index 0000000..467a759
--- /dev/null
+++ b/Pyext/test/py_u_TestError.py
@@ -0,0 +1,443 @@
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+# code for testing errors in creation of defs file in python
+
+import os
+from ecflow import Date, Meter, Event, Clock, Variable, Label, Limit, InLimit, \
+ RepeatDate, RepeatEnumerated, RepeatInteger, RepeatString, \
+ Task, Family, Suite, Defs, Client, debug_build
+
+def check_date(day,month,year):
+ try:
+ Date(day,month,year)
+ return True
+ except IndexError:
+ return False
+
+def check_meter(name,min_meter_value,max_meter_value,color_change):
+ try:
+ Meter(name,min_meter_value,max_meter_value,color_change)
+ return True
+ except IndexError:
+ return False
+ except RuntimeError:
+ return False
+
+def check_event_number_and_name(number,name):
+ try:
+ Event(number,name)
+ return True
+ except:
+ return False
+
+def check_event(number):
+ try:
+ Event(number)
+ return True
+ except RuntimeError:
+ return False
+
+def check_clock(day_of_month,month,year):
+ try:
+ Clock(day_of_month,month,year)
+ return True
+ except IndexError:
+ return False
+
+def check_variable(name,value):
+ try:
+ Variable(name,value)
+ return True
+ except RuntimeError:
+ return False
+
+def check_label(name,value):
+ try:
+ Label(name,value)
+ return True
+ except RuntimeError:
+ return False
+
+def check_limit(name,int_token):
+ try:
+ Limit(name,int_token)
+ return True
+ except RuntimeError:
+ return False
+ except TypeError:
+ return False
+
+def check_inlimit(name,path_to_node,int_token):
+ try:
+ InLimit(name,path_to_node,int_token)
+ return True
+ except RuntimeError:
+ return False
+ except TypeError:
+ return False
+
+def check_repeat_date(name, start, end, step):
+ try:
+ RepeatDate(name,start,end,step)
+ return True
+ except RuntimeError:
+ return False
+
+def check_repeat_integer(name, start, end, step):
+ try:
+ RepeatInteger(name,start,end,step)
+ return True
+ except RuntimeError:
+ return False
+ except TypeError:
+ return False
+
+def check_repeat_enumerated(name, list_of_strings):
+ try:
+ RepeatEnumerated(name,list_of_strings)
+ return True
+ except RuntimeError:
+ return False
+ except TypeError:
+ return False
+
+def check_repeat_string(name, list_of_strings):
+ try:
+ RepeatString(name,list_of_strings)
+ return True
+ except RuntimeError:
+ return False
+ except TypeError:
+ return False
+
+def check_node_name(name):
+ try:
+ Task(name)
+ Family(name)
+ Suite(name)
+ return True;
+ except RuntimeError:
+ return False
+
+def check_defs(path_to_defs):
+ try:
+ Defs(path_to_defs)
+ return True
+ except RuntimeError:
+ return False
+
+if __name__ == "__main__":
+ print "####################################################################"
+ print "Running ecflow version " + Client().version() + " debug build(" + str(debug_build()) +")"
+ print "####################################################################"
+
+ # Names with leading '.' should not be allowed. Will interfere with triggers
+ # Empty names not allowed
+ # Spaces not allowed
+ invalid_names = [ ".", "", " "," ", "fred doc", "1 "]
+
+ # Allow names with leading underscore
+ valid_names = [ "_", "__", "_._", "1.2", "fred.doc", "_.1"]
+
+ assert check_date(0,1,2010), "Expected valid date"
+ assert check_date(10,0,2010), "Expected valid date"
+ assert check_date(10,1,0), "Expected valid date"
+ assert check_date(0,0,0), "Expected valid date"
+ assert check_date(40,1,2010) == False, "Expected exception since day > 31"
+ assert check_date(-10,1,2010) == False, "Expected exception since day >= 0"
+ assert check_date(1,14,2010) == False, "Expected exception since month > 12"
+ assert check_date(1,-1,2010) == False, "Expected exception since month >= 0"
+ assert check_date(1,1,-2) == False, "Expected exception since year >= 0"
+
+ # clock do not support wild carding hence we cant use 0 like in Date
+ assert check_clock(12,1,2010), "Expected valid date"
+ assert check_clock(10,1,2010), "Expected valid date"
+ assert check_clock(10,1,1400), "Expected valid date"
+ assert check_clock(31,12,2010), "Expected valid date"
+ assert check_clock(40,1,2010) == False, "Expected exception since day > 31"
+ assert check_clock(-10,1,2010) == False, "Expected exception since day >= 0"
+ assert check_clock(1,14,2010) == False, "Expected exception since month > 12"
+ assert check_clock(1,-1,2010) == False, "Expected exception since month >= 0"
+ assert check_clock(1,1,-2) == False, "Expected exception since year >= 0"
+
+ assert check_meter("m",0,100,100), "Expected valid Meter"
+ assert check_meter("m",0,100,0), "Expected valid Meter"
+ assert check_meter("m",200,100,100) == False, "Expected exception since min > max"
+ assert check_meter("m",0,100,-20) == False, "Expected exception since color_change should between min-max"
+ assert check_meter("m",0,100,200) == False, "Expected exception since color_change should between min-max"
+ assert check_meter("",0,100,100) == False, "Expected exception since no name specified"
+ assert check_meter(" ",0,100,100) == False, "Expected Exception can not have spaces for a name"
+
+ assert check_event(1), "Expected valid Event"
+ assert check_event(2), "Expected valid Event"
+ assert check_event_number_and_name(2,"fred"), "Expected valid Event"
+ assert check_event_number_and_name(2,2) == False, "Expected failure since the name is not a string"
+
+ assert check_repeat_date("m",20000101,20001201,200), "Expected valid repeat"
+ assert check_repeat_date("m",20001201,20000101,200) == False, "Expected exception since end YMD > start YMD"
+ assert check_repeat_date("m",200001011,20001201,200)== False, "Expected Exception since start is invalid."
+ assert check_repeat_date("m",20000101,200012013,200)== False, "Expected Exception since send is invalid."
+ assert check_repeat_date("m",00000000,00000000,200)== False, "Expected Exception since start/end are not valid dates is invalid."
+ assert check_repeat_date("",20000101,20001201,200)==False, "Expected Exception since no name specified"
+ assert check_repeat_date(" ",20000101,20001201,200)==False, "Expected Exception can not have spaces for a name"
+ assert check_repeat_integer("name",0, 10, 2 ), "Expected valid repeat"
+ assert check_repeat_integer("",0, 10, 2 )==False, "Expected Exception since no name specified"
+ assert check_repeat_integer(" ",0, 10, 2 )==False, "Expected Exception can not have spaces for a name"
+ assert check_repeat_string("name",[ "a" ]), "Expected valid repeat"
+ assert check_repeat_string("",["a"] )==False, "Expected Exception since no name specified"
+ assert check_repeat_string(" ",["a"] )==False, "Expected Exception can not have spaces for a name"
+ assert check_repeat_string("name",[ 1,2 ])==False, "Expected Exception since a list of strings was expected"
+ assert check_repeat_enumerated("name",[ "a" ]), "Expected valid repeat"
+ assert check_repeat_enumerated("",["a"] )==False, "Expected Exception since no name specified"
+ assert check_repeat_enumerated(" ",["a"] )==False, "Expected Exception since a list of strings was expected"
+ assert check_repeat_enumerated("name",[ 1,2 ])==False, "Expected Exception since a list of strings was expected"
+
+
+ assert check_variable("name","value"), "Expected valid Variable"
+ assert check_variable("name",""), "Expected valid Variable"
+ assert check_variable("name"," "), "Expected valid Variable"
+ assert check_variable("name","12"), "Expected valid Variable"
+ assert check_variable("","12")==False, "Expected Exception name must be specified"
+ assert check_variable(" ","12")==False, "Expected Exception can not have spaces for a name"
+
+ assert check_label("name","value"), "Expected valid label"
+ assert check_label("name",""), "Expected valid label"
+ assert check_label("name"," "), "Expected valid label"
+ assert check_label("name","12"), "Expected valid label"
+ assert check_label("","12")==False, "Expected exception name must be specified"
+ assert check_label(" ","12")==False, "Expected Exception can not have spaces for a name"
+
+ assert check_limit("name",1), "Expected valid limit"
+ assert check_limit("name",20000), "Expected valid limit"
+ assert check_limit("name","ten")==False, "Expected exception, token must be a integer"
+ assert check_limit("name","2")==False, "Expected exception, token must be a integer"
+ assert check_limit("","2")==False, "Expected exception, no name specified"
+ assert check_limit(" ","2")==False, "Expected exception, can not have spaces for a name"
+
+ assert check_inlimit("limit_name","/path/to/limit",1), "Expected valid in limit"
+ assert check_inlimit("limit_name","/path/to/limit",999999), "Expected valid in limit"
+ assert check_inlimit("limit_name","",1), "Expected valid in limit"
+ assert check_inlimit("","",1)==False, "Expected exception, no limit name specified"
+ assert check_inlimit(" ","",1)==False, "Expected exception, can not have spaces for a name"
+
+
+ # ========================================================================
+ print "Check node names"
+ for i in range(25):
+ assert check_node_name(str(i)), "Integer names should be allowed"
+
+ for name in valid_names:
+ assert check_node_name(name), "Expected valid name " + name
+
+ for name in invalid_names:
+ assert check_node_name(name)==False, "Expected exception for invalid name " + name
+
+
+ assert check_defs("a_made_up_path_that_doesnt_not_exit.def") == False, "Expected exception, Defs file does not exist"
+
+ # =================================================================================
+ print "test save_as_defs"
+ defs = Defs() # create a empty definition
+ s1 = defs.add_suite("s1") # create a suite "s1" and add to defs
+ defs.save_as_defs("testerror.def") # create a defs on disk
+ assert check_defs("testerror.def"), "Expected defs file to exist"
+ os.remove("testerror.def")
+
+ # =================================================================================
+ print "Check duplicate suites not allowed"
+ test_passed = False
+ try :
+ defs = Defs() # create a empty definition
+ s1 = defs.add_suite("s1") # create a suite "s1" and add to defs
+ s2 = defs.add_suite("s1") # Exception thrown trying to add suite name "s1" again
+ except RuntimeError, e :
+ test_passed = True
+ pass
+ assert test_passed,"duplicate suite test failed"
+
+ # =================================================================================
+ test_passed = False
+ try:
+ defs = Defs()
+ defs.add_suite("1").add_today("00:30")
+ except RuntimeError, e :
+ test_passed = True
+ pass
+ assert test_passed,"Adding today at the suite level should fail"
+ print "check adding today at the suite level: RuntimeError: ",e
+
+ # =================================================================================
+ test_passed = False
+ try:
+ defs = Defs()
+ defs.add_suite("1").add_time("00:30")
+ except RuntimeError, e :
+ test_passed = True
+ pass
+ assert test_passed,"Adding time at the suite level should fail"
+ print "check adding time at the suite level: RuntimeError: ",e
+
+ # =================================================================================
+ test_passed = False
+ try:
+ defs = Defs()
+ defs.add_suite("1").add_date(1,1,2016)
+ except RuntimeError, e :
+ test_passed = True
+ pass
+ assert test_passed,"Adding date at the suite level should fail"
+ print "check adding date at the suite level: RuntimeError: ",e
+
+ # =================================================================================
+ test_passed = False
+ try:
+ defs = Defs()
+ defs.add_suite("1").add_day("monday")
+ except RuntimeError, e :
+ test_passed = True
+ pass
+ assert test_passed,"Adding day at the suite level should fail"
+ print "check adding day at the suite level: RuntimeError: ",e
+
+
+ # =================================================================================
+ print "check duplicate family not allowed"
+ test_passed = False
+ try:
+ suite = Suite("1")
+ fam1 = Family("1")
+ fam2 = Family("1")
+ suite.add_family(fam1)
+ suite.add_family(fam2)
+ except RuntimeError, e :
+ test_passed = True
+ pass
+ assert test_passed,"duplicate Family test failed"
+
+ # =================================================================================
+ print "duplicate task not allowed"
+ test_passed = False
+ try:
+ suite = Suite("1")
+ ta = Task("a")
+ tb = Task("a")
+ suite.add_task(ta)
+ suite.add_task(tb)
+ except RuntimeError, e :
+ test_passed = True
+ pass
+ assert test_passed,"duplicate Task test failed"
+
+ # =================================================================================
+ print "check duplicate meter not allowed"
+ test_passed = False
+ try:
+ defs = Defs()
+ suite = defs.add_suite("1")
+ ta = suite.add_task("a")
+ ta.add_meter("meter",0,100);
+ ta.add_meter("meter",0,100);
+ except RuntimeError, e :
+ test_passed = True
+ pass
+ assert test_passed,"duplicate event test failed"
+
+ test_passed = False
+ try:
+ defs = Defs()
+ suite = defs.add_suite("1")
+ ta = suite.add_task("a")
+ ta.add_meter(Meter("meter",0,100));
+ ta.add_meter(Meter("meter",10,100));
+ except RuntimeError, e :
+ test_passed = True
+ pass
+ assert test_passed,"duplicate meter test failed"
+
+ # =================================================================================
+ print "check duplicate event not allowed"
+ test_passed = False
+ try:
+ defs = Defs()
+ suite = defs.add_suite("1")
+ ta = suite.add_task("a")
+ ta.add_event(1);
+ ta.add_event("1");
+ except RuntimeError, e :
+ test_passed = True
+ pass
+ assert test_passed,"duplicate event test failed"
+
+ test_passed = False
+ try:
+ defs = Defs()
+ suite = defs.add_suite("1")
+ ta = suite.add_task("a")
+ ta.add_event("name");
+ ta.add_event("name");
+ except RuntimeError, e :
+ test_passed = True
+ pass
+ assert test_passed,"duplicate event test failed"
+
+ test_passed = False
+ try:
+ defs = Defs()
+ suite = defs.add_suite("1")
+ ta = suite.add_task("a")
+ ta.add_event(1,"name");
+ ta.add_event(1,"name");
+ except RuntimeError, e :
+ test_passed = True
+ pass
+ assert test_passed,"duplicate event test failed"
+
+
+ # =================================================================================
+ print "check cannot add same node to different containers"
+ defs1 = Defs();
+ suite = defs1.add_suite("s1")
+ family = suite.add_family("f1")
+ task = family.add_task("t1")
+
+ test_passed = False
+ try :
+ defs2 = Defs();
+ defs2.add_suite(suite)
+ except RuntimeError, e :
+ test_passed = True
+ pass
+ assert test_passed,"Can't add same suite to two different defs"
+
+ test_passed = False
+ try :
+ defs3 = Defs();
+ suite = defs3.add_suite(suite)
+ suite.add_family(family)
+ except RuntimeError, e :
+ test_passed = True
+ pass
+ assert test_passed,"Can't add same family to two different suites"
+
+ test_passed = False
+ try :
+ defs4 = Defs();
+ suite = defs4.add_suite("s1")
+ suite.add_task(task)
+ except RuntimeError, e :
+ test_passed = True
+ pass
+ assert test_passed,"Can't add same task to two different containers"
+
+ print "All Tests pass"
\ No newline at end of file
diff --git a/Pyext/test/py_u_TestFind.py b/Pyext/test/py_u_TestFind.py
new file mode 100644
index 0000000..31cf774
--- /dev/null
+++ b/Pyext/test/py_u_TestFind.py
@@ -0,0 +1,76 @@
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+# code for testing pointers and hierarchy in python
+
+from ecflow import Suite, Family, Task, Defs, Client, debug_build
+
+def create_defs(name=""):
+ defs = Defs()
+ defs.add_variable("DEFS_VAR","0")
+ suite_name = name
+ if len(suite_name) == 0: suite_name = "s1"
+ suite = defs.add_suite(suite_name);
+ suite.add_variable("SUITE_VAR","1")
+
+ f1 = suite.add_family("f1")
+ f1.add_task("f1_t1").add_variable("TASK_VAR","3")
+ f1.add_task("f1_t2").add_variable("TASK_VAR","3")
+ f2 = suite.add_family("f2")
+ f2.add_task("f2_t1").add_variable("TASK_VAR","3")
+ f2.add_task("f2_t2").add_variable("TASK_VAR","3")
+ return defs;
+
+
+if __name__ == "__main__":
+ print "####################################################################"
+ print "Running ecflow version " + Client().version() + " debug build(" + str(debug_build()) +")"
+ print "####################################################################"
+
+ defs = create_defs();
+ tasks = defs.get_all_tasks()
+ assert len(tasks) == 4, "Expected four tasks, but found " + str(len(tasks))
+ for task in tasks:
+ # test find variable
+ var = task.find_parent_variable("TASK_VAR")
+ assert not var.empty()
+ assert var.value() == "3"
+
+ var = task.find_variable("TASK_VAR")
+ assert not var.empty()
+ assert var.value() == "3"
+
+ var = task.find_parent_variable("SUITE_VAR");
+ assert not var.empty()
+ assert var.value() == "1"
+
+ var = task.find_parent_variable("DEFS_VAR")
+ assert not var.empty()
+ assert var.value() == "0"
+
+ var = task.find_parent_variable("MADE_UP_VAR")
+ assert var.empty()
+
+ if task.name() == "f1_t1":
+ node = task.find_node_up_the_tree("f1")
+ assert node != None
+ assert node.get_abs_node_path() == "/s1/f1"
+
+ node = task.find_node_up_the_tree("s1")
+ assert node != None
+ assert node.get_abs_node_path() == "/s1"
+
+ node = task.find_node_up_the_tree("freddd")
+ assert node == None
+
+ print "All Tests pass"
diff --git a/Pyext/test/py_u_TestFlag.py b/Pyext/test/py_u_TestFlag.py
new file mode 100644
index 0000000..06ca83d
--- /dev/null
+++ b/Pyext/test/py_u_TestFlag.py
@@ -0,0 +1,91 @@
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+import ecflow
+import sys
+import os
+
+if __name__ == "__main__":
+
+ print "####################################################################"
+ print "Running ecflow version " + ecflow.Client().version() + " debug build(" + str(ecflow.debug_build()) +")"
+ print "PYTHONPATH: " + str(os.environ['PYTHONPATH'].split(os.pathsep))
+ print "sys.path: " + str(sys.path)
+ print "####################################################################"
+
+ flag = ecflow.Flag()
+ assert str(flag) == "", "expected empty string, for an empty flag"
+
+ flag_list = flag.list() # flag_list is of type FlagTypeVec
+ my_flag_list = [ ecflow.FlagType.force_abort,
+ ecflow.FlagType.user_edit,
+ ecflow.FlagType.task_aborted,
+ ecflow.FlagType.edit_failed,
+ ecflow.FlagType.jobcmd_failed,
+ ecflow.FlagType.no_script,
+ ecflow.FlagType.killed,
+ ecflow.FlagType.migrated,
+ ecflow.FlagType.late,
+ ecflow.FlagType.message,
+ ecflow.FlagType.byrule,
+ ecflow.FlagType.queuelimit,
+ ecflow.FlagType.wait ,
+ ecflow.FlagType.locked ,
+ ecflow.FlagType.zombie ,
+ ecflow.FlagType.no_reque
+ ]
+ print "Flag list:"
+ for flg in flag_list: print "flag ",flag.type_to_string(flg)
+ print "My list:"
+ for flg in my_flag_list: print "flag ",flag.type_to_string(flg)
+
+ assert len(flag_list) == len(my_flag_list), "expected flag list have changed"
+ expected_flags = "force_aborted,user_edit,task_aborted,edit_failed,ecfcmd_failed,no_script,killed,migrated,late,message,by_rule,queue_limit,task_waiting,locked,zombie,no_reque";
+
+ #Set *ALL* the flags
+ for flg in flag_list:
+ flag.set( flg )
+ assert flag.is_set( flg ),"expected flag %r to be set" % flag.type_to_string(flg)
+
+ # clear *ALL* the flags
+ assert str(flag) == expected_flags, "Expected flags \n{0}\nbut found \n{1}".format(str(flag),expected_flags)
+ for flg in flag_list:
+ flag.clear(flg)
+ assert not flag.is_set( flg ),"expected flag {0} not to be set".format(flag.type_to_string(flg))
+
+ # test reset
+ for flg in flag_list:
+ flag.set( flg )
+ flag.reset()
+ for flg in flag_list:
+ assert not flag.is_set( flg ),"expected flag %r not to be set" % flag.type_to_string(flg)
+
+ #===========================================================================
+ # Setting flag type
+ #===========================================================================
+ for flg in my_flag_list:
+ flag.set( flg )
+ print "current flag:",flag
+ assert flag.is_set( flg ),"expected flag %r to be set" % flag.type_to_string(flg)
+
+ #===========================================================================
+ # Node: get the flag, should be empty for a newly created node.
+ #===========================================================================
+ suite = ecflow.Suite("s1")
+ flag = suite.get_flag()
+ for flg in flag_list:
+ assert not flag.is_set( flg ),"expected flag %r not to be set" % flag.type_to_string(flg)
+ assert str(flag) == "", "expected empty string, for an empty flag"
+
+ #assert False
+ print "All tests pass"
diff --git a/Pyext/test/py_u_TestGeneratedVariable.py b/Pyext/test/py_u_TestGeneratedVariable.py
new file mode 100644
index 0000000..12e2b23
--- /dev/null
+++ b/Pyext/test/py_u_TestGeneratedVariable.py
@@ -0,0 +1,76 @@
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+# code for testing generated variables
+#
+import ecflow
+
+if __name__ == "__main__":
+ print "####################################################################"
+ print "Running ecflow version " + ecflow.Client().version() + " debug build(" + str(ecflow.debug_build()) +")"
+ print "####################################################################"
+
+ #===========================================================================
+ print "Defs: test generated variables"
+ #===========================================================================
+ defs = ecflow.Defs()
+ suite = defs.add_suite("s1")
+ family = suite.add_family("f1")
+ task = family.add_task("t1")
+
+ print "\nsuite generated variables, Most of date related suite generated variables will only have values after the suite has begun"
+ variable_list = ecflow.VariableList()
+ suite.get_generated_variables(variable_list)
+ for gen_var in variable_list:
+ print gen_var
+ assert len(list(variable_list)) == 12,"Expected 12 generated variables for suites"
+ assert variable_list[0].name() == "SUITE", "expected generated variable of name SUITE but found " + variable_list[0].name()
+ assert variable_list[0].value() == "s1", "expected generated variable of value 's1' but found " + variable_list[0].value()
+
+
+ print "\nfamily generated variables"
+ variable_list = ecflow.VariableList()
+ family.get_generated_variables(variable_list)
+ for gen_var in variable_list:
+ print gen_var
+ assert len(list(variable_list)) == 2,"Expected 2 generated variables for families"
+ assert variable_list[0].name() == "FAMILY", "expected generated variable of name FAMILY but found " + variable_list[0].name()
+ assert variable_list[0].value() == "f1", "expected generated variable of value 'f1' but found " + variable_list[0].value()
+ assert variable_list[1].name() == "FAMILY1", "expected generated variable of name FAMILY1 but found " + variable_list[1].name()
+ assert variable_list[1].value() == "f1", "expected generated variable of value 'f1' but found " + variable_list[1].value()
+
+ print "\ntask generated variables"
+ variable_list = ecflow.VariableList()
+ task.get_generated_variables(variable_list)
+ for gen_var in variable_list:
+ print gen_var
+ assert len(list(variable_list)) == 8,"Expected 8 generated variables for tasks"
+ assert variable_list[0].name() == "TASK", "expected generated variable of name TASK but found " + variable_list[0].name()
+ assert variable_list[0].value() == "t1", "expected generated variable of value 't1' but found " + variable_list[0].value()
+ assert variable_list[1].name() == "ECF_JOB", "expected generated variable of name ECF_JOB but found " + variable_list[1].name()
+ assert variable_list[1].value() == "./s1/f1/t1.job0", "expected generated variable of value './s1/f1/t1.job0' but found " + variable_list[1].value()
+ assert variable_list[2].name() == "ECF_SCRIPT", "expected generated variable of name ECF_SCRIPT but found " + variable_list[2].name()
+ assert variable_list[2].value() == "./s1/f1/t1.ecf", "expected generated variable of value './s1/f1/t1.ecf' but found " + variable_list[2].value()
+ assert variable_list[3].name() == "ECF_JOBOUT", "expected generated variable of name ECF_JOBOUT but found " + variable_list[3].name()
+ assert variable_list[3].value() == "./s1/f1/t1.0", "expected generated variable of value './s1/f1/t1.0' but found " + variable_list[3].value()
+ assert variable_list[4].name() == "ECF_TRYNO", "expected generated variable of name ECF_TRYNO but found " + variable_list[4].name()
+ assert variable_list[4].value() == "0", "expected generated variable of value '0' but found " + variable_list[4].value()
+ assert variable_list[5].name() == "ECF_RID", "expected generated variable of name ECF_RID but found " + variable_list[5].name()
+ assert variable_list[5].value() == "", "expected generated variable of value '' but found " + variable_list[5].value()
+ assert variable_list[6].name() == "ECF_NAME", "expected generated variable of name ECF_NAME but found " + variable_list[6].name()
+ assert variable_list[6].value() == "/s1/f1/t1", "expected generated variable of value '/s1/f1/t1' but found " + variable_list[6].value()
+ assert variable_list[7].name() == "ECF_PASS", "expected generated variable of name ECF_NAME but found " + variable_list[7].name()
+ assert variable_list[7].value() == "_DJP_", "expected generated variable of value '_DJP_' but found " + variable_list[7].value()
+
+ print "\nAll Tests pass"
+
diff --git a/Pyext/test/py_u_TestGetAllTasks.py b/Pyext/test/py_u_TestGetAllTasks.py
new file mode 100644
index 0000000..b0004ac
--- /dev/null
+++ b/Pyext/test/py_u_TestGetAllTasks.py
@@ -0,0 +1,103 @@
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+# Simple check for get all tasks
+from ecflow import Defs, Client, debug_build
+
+def create_defs():
+ defs = Defs()
+ suite = defs.add_suite("test_get_all")
+ suite.add_task("t0")
+ fam = suite.add_family("f1")
+ fam.add_task("t1")
+ fam.add_task("t2")
+ fam2 = fam.add_family("f2")
+ fam2.add_task("t3")
+ return defs
+
+def test_get_all_tasks(defs):
+
+ task_vec2 = defs.get_all_tasks()
+ assert len(task_vec2) == 4, "Expected four tasks, but found " + str(len(task_vec2))
+
+ assert task_vec2[0].name() == "t0", "Expected task of name t0 but found " + task_vec2[0].name()
+ assert task_vec2[1].name() == "t1", "Expected task of name t1 but found " + task_vec2[1].name()
+ assert task_vec2[2].name() == "t2", "Expected task of name t2 but found " + task_vec2[2].name()
+ assert task_vec2[3].name() == "t3", "Expected task of name t3 but found " + task_vec2[3].name()
+
+ print "test_get_all_tasks PASSED"
+
+def test_get_all_nodes(defs):
+
+ # Get all the nodes make sure they are in order
+ node_vec = defs.get_all_nodes()
+ assert len(node_vec) == 7, "Expected seven nodes, but found " + str(len(node_vec))
+ assert node_vec[0].name() == "test_get_all", "Nodes should be returned in order, expected test_get_all but found" + node_vec[0].name()
+ assert node_vec[1].name() == "t0", "Nodes should be returned in order, expected 't0' but found" + node_vec[1].name()
+ assert node_vec[2].name() == "f1", "Nodes should be returned in order, expected 'f1' but found" + node_vec[2].name()
+ assert node_vec[3].name() == "t1", "Nodes should be returned in order, expected 't1' but found" + node_vec[3].name()
+ assert node_vec[4].name() == "t2", "Nodes should be returned in order, expected 't2' but found" + node_vec[4].name()
+ assert node_vec[5].name() == "f2", "Nodes should be returned in order, expected 'f2' but found" + node_vec[5].name()
+ assert node_vec[6].name() == "t3", "Nodes should be returned in order, expected 't3' but found" + node_vec[6].name()
+
+ # test empty defs
+ empty_defs = Defs()
+ node_vec = empty_defs.get_all_nodes()
+ assert len(node_vec) == 0, "Expected zero nodes, for an empty defs but found " + str(len(node_vec))
+
+ # test one suite defs
+ one_suite_defs = Defs()
+ one_suite_defs.add_suite("s1")
+ node_vec = one_suite_defs.get_all_nodes()
+ assert len(node_vec) == 1, "Expected one node, but found " + str(len(node_vec))
+
+ print "test_get_all_nodes PASSED"
+
+def test_get_all_nodes_from_nodes():
+ defs = Defs()
+ suite = defs.add_suite("test_get_all")
+ node_vec = suite.get_all_nodes()
+ assert len(node_vec) == 1, "Expected one nodes but found " + str(len(node_vec))
+
+ fam1 = suite.add_family("f1")
+ fam2 = suite.add_family("f2")
+ fam3 = suite.add_family("f3")
+ node_vec = suite.get_all_nodes()
+ assert len(node_vec) == 4, "Expected 4 nodes but found " + str(len(node_vec))
+
+ node_vec = fam1.get_all_nodes()
+ assert len(node_vec) == 1, "Expected 1 nodes but found " + str(len(node_vec))
+
+ f1_t1 = fam1.add_task("t1")
+ f1_t2 = fam1.add_task("t2")
+ node_vec = fam1.get_all_nodes()
+ assert len(node_vec) == 3, "Expected 3 nodes but found " + str(len(node_vec))
+
+ node_vec = f1_t1.get_all_nodes()
+ assert len(node_vec) == 1, "Expected 1 nodes but found " + str(len(node_vec))
+
+ node_vec = suite.get_all_nodes()
+ assert len(node_vec) == 6, "Expected 6 nodes but found " + str(len(node_vec))
+
+ print "test_get_all_nodes_from_nodes PASSED"
+
+
+if __name__ == "__main__":
+ print "####################################################################"
+ print "Running ecflow version " + Client().version() + " debug build(" + str(debug_build()) +")"
+ print "####################################################################"
+
+ test_get_all_tasks(create_defs())
+ test_get_all_nodes(create_defs())
+ test_get_all_nodes_from_nodes()
+ print "All Tests pass"
\ No newline at end of file
diff --git a/Pyext/test/py_u_TestJobGeneration.py b/Pyext/test/py_u_TestJobGeneration.py
new file mode 100644
index 0000000..63dd7bc
--- /dev/null
+++ b/Pyext/test/py_u_TestJobGeneration.py
@@ -0,0 +1,135 @@
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+# This code is used check job generation
+#
+import os
+import shutil # used to remove directory tree
+
+import ecflow_test_util as Test
+from ecflow import Defs, JobCreationCtrl, TaskVec, File, Client, debug_build
+
+def ecf_includes() : return Test.get_root_source_dir() + "/Pyext" + "/test/data/includes"
+
+def create_defs(ecf_home,task_vec):
+ defs = Defs();
+ suite = defs.add_suite("suite_job_gen");
+ suite.add_variable("ECF_HOME",ecf_home);
+ suite.add_variable("ECF_CLIENT_EXE_PATH",File.find_client());
+ suite.add_variable("SLEEPTIME","1");
+ suite.add_variable("ECF_INCLUDE",ecf_includes());
+
+ fam = suite.add_family("family")
+ t1 = fam.add_task("t1")
+ t1.add_event("eventname");
+ t1.add_meter("meter",0,100,100)
+
+ t2 = fam.add_task("t2")
+ t3 = fam.add_task("t3")
+ t4 = fam.add_task("dummy_task")
+ t4.add_variable("ECF_DUMMY_TASK","any"); # stop job generation errors for tasks without an .ecf
+ task_vec.append(t1);
+ task_vec.append(t2);
+ task_vec.append(t3);
+ task_vec.append(t4);
+
+ return defs
+
+
+def delete_jobs(task_vec, ecf_home):
+ print "delete jobs"
+ for task in task_vec:
+ the_job_file = ecf_home + task.get_abs_node_path() + ".job" + task.get_try_no()
+ if os.path.exists(the_job_file) :
+ print "removing file " + the_job_file
+ try: os.remove(the_job_file)
+ except: pass
+ man_file = ecf_home + task.get_abs_node_path() + ".man"
+ if os.path.exists(man_file) :
+ print "removing man_file " + man_file
+ try: os.remove(man_file)
+ except: pass
+
+def check_jobs(task_vec, ecf_home):
+ print "Check job file exists"
+ for task in task_vec:
+ variable = task.find_variable("ECF_DUMMY_TASK")
+ if not variable.empty(): continue;
+ the_job_file = ecf_home + task.get_abs_node_path() + ".job" + task.get_try_no()
+
+ if os.path.exists(the_job_file) :
+ print "Found job file " + the_job_file
+ else:
+ assert False, "Could not find job file " + the_job_file
+
+
+
+
+if __name__ == "__main__":
+ print "####################################################################"
+ print "Running ecflow version " + Client().version() + " debug build(" + str(debug_build()) +")"
+ print "####################################################################"
+
+ workspace = Test.get_root_source_dir();
+ print workspace
+
+ ecf_home = workspace + "/Pyext/test/data/ECF_HOME"
+ task_vec = TaskVec()
+ defs = create_defs(ecf_home,task_vec)
+ print str(defs)
+
+ print "Generate jobs for *ALL* tasks, to default locations ECF_HOME/ECF_NAME.job0"
+ print defs.check_job_creation()
+ check_jobs(task_vec,ecf_home)
+ delete_jobs(task_vec,ecf_home)
+
+ print "\nGenerate jobs for *ALL* tasks, to default locations ECF_HOME/ECF_NAME.job0"
+ job_ctrl = JobCreationCtrl()
+ defs.check_job_creation( job_ctrl )
+ print job_ctrl.get_error_msg()
+ check_jobs(task_vec,ecf_home)
+ delete_jobs(task_vec,ecf_home)
+
+ print "\nGenerate jobs for all nodes, under path, to default locations ECF_HOME/ECF_NAME.job0"
+ job_ctrl = JobCreationCtrl()
+ job_ctrl.set_node_path( task_vec[0].get_abs_node_path() )
+ defs.check_job_creation(job_ctrl)
+ print job_ctrl.get_error_msg();
+ delete_jobs(task_vec,ecf_home)
+
+ print "\nGenerate jobs for all tasks, to the specified directory"
+ # Directory will automatically created under the provided directory
+ job_ctrl = JobCreationCtrl()
+ job_ctrl.set_dir_for_job_creation(workspace + "/Pyext/test/data") # generate jobs file under this directory
+ defs.check_job_creation(job_ctrl)
+ print job_ctrl.get_error_msg()
+
+ generated_dir = job_ctrl.get_dir_for_job_creation() + "/suite_job_gen"
+ print "removing directory tree " + generated_dir
+ shutil.rmtree(generated_dir)
+
+
+ # Create jobs for all task, to a TMP directory ($TMPDIR/ecf_check_job_creation/ECF_NAME.job0
+ # When run via rsh then TMPDIR may not be defined, hence expect exception to be thrown
+ try:
+ job_ctrl = JobCreationCtrl()
+ job_ctrl.generate_temp_dir()
+ defs.check_job_creation(job_ctrl)
+ print job_ctrl.get_error_msg()
+ print "removing directory tree " + job_ctrl.get_dir_for_job_creation()
+ shutil.rmtree(job_ctrl.get_dir_for_job_creation())
+
+ delete_jobs(task_vec,ecf_home)
+ print "All test pass"
+ except RuntimeError, e:
+ print "failed: " + str(e)
diff --git a/Pyext/test/py_u_TestParent.py b/Pyext/test/py_u_TestParent.py
new file mode 100644
index 0000000..e53275b
--- /dev/null
+++ b/Pyext/test/py_u_TestParent.py
@@ -0,0 +1,77 @@
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+# code for testing pointers and hierarchy in python
+
+from ecflow import Suite, Family, Task, Defs, Client, debug_build
+
+def absNodePath(node):
+ """ Given a node return its absolute node path. """
+ """ Example of using get_parent() """
+ name_list = []
+ name_list.append(node.name())
+ parent = node.get_parent();
+ while parent:
+ name_list.append(parent.name())
+ parent = parent.get_parent()
+
+ name_list.reverse()
+ ret = ""
+ for name in name_list:
+ ret = ret + "/"
+ ret = ret + name
+ return ret
+
+
+if __name__ == "__main__":
+ print "####################################################################"
+ print "Running ecflow version " + Client().version() + " debug build(" + str(debug_build()) +")"
+ print "####################################################################"
+
+ suite = Suite("s1");
+ family = Family("f1")
+ task = Task("t1")
+
+ assert not suite.get_parent(), "Suite parent is always NULL"
+ assert not family.get_parent(), "Expect no parent"
+ assert not task.get_parent(), "Expect no parent"
+
+ print "suite.get_defs() = " + str(suite.get_defs())
+ print "family.get_defs() = " + str(family.get_defs())
+ print "task.get_defs() = " + str(task.get_defs())
+ assert not suite.get_defs(), "Expected no defs, since suite not added to defs yet"
+ assert not family.get_defs(), "Expected no defs"
+ assert not task.get_defs(), "Expected no defs"
+
+ suite.add_family(family)
+ family.add_task(task)
+
+ family2 = Family("f2")
+ family.add_family(family2)
+
+ t1 = Task("t1")
+ family2.add_task(t1)
+
+ defs = Defs()
+ defs.add_suite(suite);
+
+ print absNodePath(t1)
+ print absNodePath(family2)
+ print absNodePath(family)
+ print absNodePath(suite)
+
+ assert t1.get_abs_node_path() == absNodePath(t1), "Expected " + t1.get_abs_node_path() + " but got " + absNodePath(t1)
+ assert family2.get_abs_node_path() == absNodePath(family2),"Expected " + family2.get_abs_node_path() + " but got " + absNodePath(family2)
+ assert family.get_abs_node_path() == absNodePath(family), "Expected " + family.get_abs_node_path() + " but got " + absNodePath(family)
+ assert suite.get_abs_node_path() == absNodePath(suite), "Expected " + family.get_abs_node_path() + " but got " + absNodePath(suite)
+ print "All Tests pass"
diff --git a/Pyext/test/py_u_TestRepeatArithmetic.py b/Pyext/test/py_u_TestRepeatArithmetic.py
new file mode 100644
index 0000000..7b109b7
--- /dev/null
+++ b/Pyext/test/py_u_TestRepeatArithmetic.py
@@ -0,0 +1,52 @@
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+# This test checks trigger evaluation uses date arithmetic when
+# the expression reference a repeat DATE variable.
+# Addition and subtraction for repeat date, should follow data arithmetic
+# The repeat variable in the expression must be on the LHS(left hand side)
+# of the expression, otherwise integer arithmetic is used
+import ecflow
+
+if __name__ == "__main__":
+ print "####################################################################"
+ print "Running ecflow version " + ecflow.Client().version() + " debug build(" + str(ecflow.debug_build()) + ")"
+ print "####################################################################"
+
+ defs = ecflow.Defs()
+ s1 = defs.add_suite("s1");
+ t1 = s1.add_task("t1").add_repeat( ecflow.RepeatDate("YMD",20090101,20091231,1) );
+ t2 = s1.add_task("t2").add_trigger("t1:YMD ge 20100601");
+
+ # Check trigger expressions
+ assert len(defs.check()) == 0, "Expected no errors in parsing expressions."
+
+ # Initial value of repeat is 20090101 hence trigger should fail to evaluate
+ assert t2.evaluate_trigger() == False, "Expected trigger to evaluate. 20090101 >= 20100601"
+
+ # Check end of month - 1
+ t2.change_trigger("t1:YMD - 1 eq 20081231")
+ assert t2.evaluate_trigger(), "Expected trigger to evaluate. 20090101 - 1 == 20081231"
+
+ # check addition
+ t2.change_trigger("t1:YMD + 1 eq 20090102");
+ assert t2.evaluate_trigger(), "Expected trigger to evaluate. 20090101 + 1 == 20090102"
+
+ # Check the end of each month + 1
+ t1.delete_repeat();
+ t1.add_repeat( ecflow.RepeatDate("YMD",20090131,20101231,1))
+ t2.change_trigger("t1:YMD + 1 eq 20090201");
+ assert t2.evaluate_trigger(), "Expected trigger to evaluate. 20090131 + 1 == 20090201"
+
+ print "All Tests pass"
+
diff --git a/Pyext/test/py_u_TestSimulator.py b/Pyext/test/py_u_TestSimulator.py
new file mode 100644
index 0000000..0370545
--- /dev/null
+++ b/Pyext/test/py_u_TestSimulator.py
@@ -0,0 +1,82 @@
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+# Test the simulation works
+
+import os
+import ecflow
+
+def simulate_defs_with_time():
+ #suite test_time_series
+ # family family
+ # task t1
+ # time 00:00 23:00 04:00 # should run 6 times 00:00 04:00 08:00 12:00 16:00 20:00
+ # endfamily
+ #endsuite
+ print "simulate_defs_with_time()"
+ defs = ecflow.Defs()
+ suite = defs.add_suite("test_time_series")
+ clock = ecflow.Clock(1, 1, 2011, False) # day,month, year, hybrid make test start at midnight, otherwise current time used
+ suite.add_clock(clock)
+ family = suite.add_family("family")
+ task = family.add_task("t1")
+ ts = ecflow.TimeSeries(ecflow.TimeSlot(0,0), ecflow.TimeSlot(23,0), ecflow.TimeSlot(4,0), True)
+ task.add_time( ecflow.Time(ts) )
+ task.add_verify( ecflow.Verify(ecflow.State.complete, 6) ) # expect task to complete 6 times
+
+ theResult = defs.simulate()
+ assert len(theResult) == 0, "Expected simulation to return without any errors, but found:\n" + theResult
+
+ print " simple check for state change time"
+ print " iso_extended:",task.get_state_change_time()
+ print " iso_extended:",task.get_state_change_time("is0_extended")
+ print " iso :",task.get_state_change_time("iso")
+ print " simple :",task.get_state_change_time("simple")
+ print " rubbish :",task.get_state_change_time("rubbish")
+
+ os.remove("test_time_series.def.log")
+
+def simulate_deadlock():
+ # This simulation is expected to fail, since we have a deadlock/ race condition
+
+ # suite dead_lock
+ # family family
+ # task t1
+ # trigger t2 == complete
+ # task t2
+ # trigger t1 == complete
+ # endfamily
+ # endsuite
+
+ defs = ecflow.Defs()
+ suite = defs.add_suite("dead_lock")
+ fam = suite.add_family("family")
+ fam.add_task("t1").add_trigger("t2 == complete")
+ fam.add_task("t2").add_trigger("t1 == complete")
+
+ theResult = defs.simulate()
+ assert len(theResult) != 0, "Expected simulation to return errors, but found none"
+ print theResult
+
+ os.remove("dead_lock.def.log")
+ os.remove("defs.depth")
+ os.remove("defs.flat")
+
+if __name__ == "__main__":
+ print "####################################################################"
+ print "Running ecflow version " + ecflow.Client().version() + " debug build(" + str(ecflow.debug_build()) +")"
+ print "####################################################################"
+
+ simulate_defs_with_time()
+ simulate_deadlock()
+ print "All Tests pass"
diff --git a/Pyext/test/py_u_TestTraversal.py b/Pyext/test/py_u_TestTraversal.py
new file mode 100644
index 0000000..9774db8
--- /dev/null
+++ b/Pyext/test/py_u_TestTraversal.py
@@ -0,0 +1,221 @@
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+# This file is used to test the python traversal routines
+# This is done by loading from disk a defs file.
+# traversing this defs file, and creating another defs file
+# then comparing the two. If traversal was correct. the file should be the same
+
+import ecflow
+import os,fnmatch
+
+class Indentor:
+ """This class manages indentation, for use with context manager
+ It is used to correctly indent the definition node tree hierarchy
+ """
+ _index = 0
+ def __init__(self):
+ Indentor._index += 1
+ def __del__(self):
+ Indentor._index -= 1
+ @classmethod
+ def indent(cls,the_file):
+ for i in range(Indentor._index):
+ the_file.write(' ')
+
+class DefsTraverser:
+ """Traverse the ecflow.Defs definition and write to file.
+
+ This demonstrates that all nodes in the node tree and all attributes are accessible.
+ Additionally the state data is also accessible. This class will write state data as
+ comments. If the definition was returned from the server, it allows access to latest
+ snapshot of the state data held in the server.
+ """
+ def __init__(self,defs,file_name):
+ assert (isinstance(defs,ecflow.Defs)),"Expected ecflow.Defs as first argument"
+ assert (isinstance(file_name,str)),"Expected a string argument. Representing a file name"
+ self.__defs = defs
+ self.__file = open(file_name, 'w')
+
+ def write_to_file(self):
+ for extern in self.__defs.externs:
+ self.__writeln("extern " + extern)
+ for suite in self.__defs.suites:
+ self.__write("suite ")
+ self.__print_node(suite)
+ clock = suite.get_clock()
+ if clock:
+ indent = Indentor()
+ self.__writeln(str(clock))
+ del indent
+ self.__print_nc(suite)
+ self.__writeln("endsuite")
+ self.__file.close()
+
+ def __print_nc(self,node_container):
+ indent = Indentor()
+ for node in node_container.nodes:
+ if isinstance(node, ecflow.Task):
+ self.__write("task ")
+ self.__print_node(node)
+ self.__print_alias(node)
+ else:
+ self.__write("family ")
+ self.__print_node(node)
+ self.__print_nc(node)
+ self.__writeln("endfamily")
+ del indent
+
+ def __print_alias(self,task):
+ indent = Indentor()
+ for alias in task.nodes:
+ self.__write("alias ")
+ self.__print_node(alias)
+ self.__writeln("endalias")
+ del indent
+
+ def __print_node(self,node):
+ self.__file.write(node.name() + " # state:" + str(node.get_state()) + "\n")
+
+ indent = Indentor()
+ defStatus = node.get_defstatus()
+ if defStatus != ecflow.DState.queued:
+ self.__writeln("defstatus " + str(defStatus))
+
+ autocancel = node.get_autocancel()
+ if autocancel: self.__writeln(str(autocancel))
+
+ repeat = node.get_repeat()
+ if not repeat.empty(): self.__writeln(str(repeat) + " # value: " + str(repeat.value()))
+
+ late = node.get_late()
+ if late: self.__writeln(str(late) + " # is_late: " + str(late.is_late()))
+
+ complete_expr = node.get_complete()
+ if complete_expr:
+ for part_expr in complete_expr.parts:
+ trig = "complete "
+ if part_expr.and_expr(): trig = trig + "-a "
+ if part_expr.or_expr(): trig = trig + "-o "
+ self.__write(trig)
+ self.__file.write( part_expr.get_expression() + "\n")
+ trigger_expr = node.get_trigger()
+ if trigger_expr:
+ for part_expr in trigger_expr.parts:
+ trig = "trigger "
+ if part_expr.and_expr(): trig = trig + "-a "
+ if part_expr.or_expr(): trig = trig + "-o "
+ self.__write(trig)
+ self.__file.write( part_expr.get_expression() + "\n")
+
+ for var in node.variables: self.__writeln("edit " + var.name() + " '" + var.value() + "'")
+ for meter in node.meters: self.__writeln(str(meter) + " # value: " + str(meter.value()))
+ for event in node.events: self.__writeln(str(event) + " # value: " + str(event.value()))
+ for label in node.labels: self.__writeln(str(label) + " # value: " + label.new_value())
+ for limit in node.limits: self.__writeln(str(limit) + " # value: " + str(limit.value()))
+ for inlimit in node.inlimits: self.__writeln(str(inlimit))
+ for the_time in node.times: self.__writeln(str(the_time))
+ for today in node.todays: self.__writeln(str(today))
+ for date in node.dates: self.__writeln(str(date))
+ for day in node.days: self.__writeln(str(day))
+ for cron in node.crons: self.__writeln(str(cron))
+ for verify in node.verifies: self.__writeln(str(verify))
+ for zombie in node.zombies: self.__writeln(str(zombie))
+
+ del indent
+
+ def __write(self,the_string):
+ Indentor.indent(self.__file)
+ self.__file.write(the_string)
+
+ def __writeln(self,the_string):
+ Indentor.indent(self.__file)
+ self.__file.write(the_string + "\n")
+
+def check_traversal(path_to_def):
+ # Open a def on disk *and* load into memory
+ reference_def = ecflow.Defs( path_to_def )
+
+ # traverse the opened def and write it out again
+ file_name = "copy.def"
+ traverser = DefsTraverser(reference_def,file_name)
+ traverser.write_to_file()
+
+ # restore the defs we create via traversal. If traversal was good it should
+ # be the same as def on disk.
+ try:
+ traversed_def = ecflow.Defs( file_name )
+ except RuntimeError, e:
+ print "Could not parse file " + file_name + "\n" + str(e)
+ exit(1)
+
+ # compare the two defs
+ ecflow.Ecf.set_debug_equality(True)
+ defs_equal = (traversed_def == reference_def)
+ if not defs_equal:
+ print str(path_to_def) + " FAILED "
+ print "The traversed defs=========\n" + str(traversed_def) + "\nnot the same as reference def============\n" + str(reference_def)
+ print "===================== " + file_name + " ===================================="
+ the_traversed_def_on_disk = open(file_name)
+ for line in the_traversed_def_on_disk:
+ print line,
+
+ assert defs_equal, "Failed: ---"
+
+ # Notice: this path does not delete file_name, left for analysis of failure
+ else:
+ print str(path_to_def) + " PASSED "
+ os.remove(file_name)
+
+
+def all_files(root, patterns='*', single_level=False, yield_folders=False):
+ """Expand patterns from semi-colon separated string to list"""
+ patterns = patterns.split(';')
+ for path, subdirs, files in os.walk(root):
+ if yield_folders:
+ files.extend(subdirs)
+ files.sort()
+ for name in files:
+ for pattern in patterns:
+ if fnmatch.fnmatch(name,pattern):
+ yield os.path.join(path, name)
+ break
+ if single_level:
+ break
+
+if __name__ == "__main__":
+ print "####################################################################"
+ print "Running ecflow version " + ecflow.Client().version() + " debug build(" + str(ecflow.debug_build()) +")"
+ print "####################################################################"
+
+ cwd = os.getcwd()
+ #print cwd
+ #print "split = " + str(os.path.split(cwd))
+ #print "basename = " + os.path.basename(cwd)
+ #print "dirname = " + os.path.dirname(cwd)
+ #print "splitext = " + str( os.path.splitext(cwd) )
+ #print "isdir = " + str(os.path.isdir(cwd))
+
+ # Traverse all the good defs in the Parser directory
+ newpath = ""
+ if os.path.basename(cwd) == "Pyext":
+ newpath = os.path.join( os.path.dirname(cwd),"AParser/test/data/good_defs" )
+
+ #print newpath
+ for path_to_defs_file in all_files(newpath, '*.def;*.txt'):
+ check_traversal(path_to_defs_file)
+
+ # try the mega_def. Commented out since it takes to long
+ #mega_def = os.path.join( os.path.dirname(cwd), "AParser/test/data/single_defs/mega.def")
+ #check_traversal(mega_def)
+ print "All Tests pass"
\ No newline at end of file
diff --git a/Pyext/test/py_u_TestUserManual.py b/Pyext/test/py_u_TestUserManual.py
new file mode 100644
index 0000000..98a9248
--- /dev/null
+++ b/Pyext/test/py_u_TestUserManual.py
@@ -0,0 +1,156 @@
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+# This code is used in the user manual
+#
+
+from ecflow import Suite, Task, RepeatDate
+
+if __name__ == "__main__":
+
+ class ExperimentalSuite(object):
+ def __init__(self, start, end) :
+ self.start_ = start
+ self.end_ = end
+ self.start_cycle_ = 12
+ self.end_cycle_ = 12
+
+ def generate(self) :
+ x_suite = Suite("x")
+ make_fam = x_suite.add_family("make")
+ make_fam.add_task("build")
+ make_fam.add_task("more_work")
+
+ main_fam = x_suite.add_family("main")
+ main_fam.add_repeat( RepeatDate("YMD",self.start_,self.end_) )
+ main_fam.add_trigger( "make == complete" )
+
+ previous = 0
+ for FAM in ( 0, 6, 12, 18 ) :
+ fam_fam = x_suite.add_family(str(FAM))
+ if FAM > 0 :
+ fam_fam.add_trigger( "./" + str(previous) + " == complete " )
+
+ self.add_complete(fam_fam,FAM)
+
+ fam_fam.add_task("run")
+ fam_fam.add_task("run_more").add_trigger( "run == complete")
+ previous = FAM
+ return x_suite
+
+ def add_complete(self, family, fam):
+ if fam < self.start_cycle_ and fam > self.end_cycle_ :
+ family.add_complete("../main:YMD eq " + str(self.start_) + " or ../main:YMD ge " + str(self.end_))
+ elif fam < self.start_cycle_ :
+ family.add_complete("../main:YMD eq " + str(self.start_))
+ elif fam > self.end_cycle_ :
+ family.add_complete("../main:YMD ge " + str(self.end_))
+ return
+
+ print str( ExperimentalSuite(20050601,20050605).generate() )
+
+# ==========================================================================
+
+# Control structure and looping
+ var = "aa"
+ if var in ( "a", "aa", "aaa" ) : print "it is a kind of a "
+ elif var in ( "b", "bb", "bb" ) : print "it is a kind of b "
+ else : print "it is something else "
+
+# ==========================================================================
+
+ task = Task("task")
+ the_time = 0
+ if the_time == 0 :
+ task.add_today(17, 30)
+ task.add_variable("ANTIME", str(the_time))
+ elif the_time == 6 :
+ task.add_today(17, 30)
+ task.add_variable("ANTIME", str(the_time))
+ elif the_time == 12 :
+ task.add_today(19, 15)
+ task.add_variable("ANTIME", str(the_time))
+ elif the_time == 18 :
+ task.add_time(1, 30)
+ task.add_variable("ANTIME", str(the_time))
+ elif the_time == 24 :
+ task.add_time(3, 0)
+ task.add_variable("ANTIME", "0")
+ task.add_variable("DELTA_DAY", "1")
+ task.add_variable("EXPVER", "0002")
+
+# ====================================================================================
+
+ # Reuseable class for adding synoptic times
+ class VarAdder(object):
+ def __init__(self, node):
+ self.node = node
+
+ def add(self, time):
+ {
+ 6: lambda self : self.add6(time),
+ 12: lambda self : self.add12(time),
+ 18: lambda self : self.add18(time),
+ 24: lambda self : self.add24(time)
+ }.get(time, self.errorHandler)(self)
+
+ def add6(self, time):
+ print "add6 " + str(time)
+ self.node.add_today(17, 30)
+ self.node.add_variable("ANTIME", str(time))
+
+ def add12(self, time):
+ print "add12 " + str(time)
+ self.node.add_today(19, 15)
+ self.node.add_variable("ANTIME", str(time))
+
+ def add18(self, time):
+ print "add18 " + str(time)
+ self.node.add_time(1, 30)
+ self.node.add_variable("ANTIME", str(time))
+
+ def add24(self, time):
+ print "add24 " + str(time)
+ self.node.add_time(3, 0)
+ self.node.add_variable("ANTIME", "0")
+ self.node.add_variable("DELTA_DAY", "1")
+ self.node.add_variable("EXPVER", "0002")
+
+ def errorHandler(self, ignore): print "invalid time " + str(ignore)
+
+#for i in (0, 6 ,12, 18, 24):
+for i in (0, 6):
+ task = Task("t" + str(i))
+ print task.name()
+ varAdder = VarAdder(task)
+ varAdder.add(114)
+ for var in task.variables:
+ print str(var) + "\n"
+ for the_time in task.times :
+ print str(the_time) + "\n"
+ for today in task.todays :
+ print str(today) + "\n"
+
+# ==========================================================================
+
+suite = Suite("x")
+previous_time = 0
+for i in (0,6,12,18,24) :
+ the_fam = suite.add_family(str(i))
+ if i != 0:
+ the_fam.add_trigger("./" + previous_time + " == complete ")
+ the_fam.add_task("t1")
+ the_fam.add_task("t2").add_trigger("t1 == complete")
+ previous_time = str(i)
+
+# print str(suite)
diff --git a/Pyext/test/py_u_TestWith.py b/Pyext/test/py_u_TestWith.py
new file mode 100644
index 0000000..e5b4ed9
--- /dev/null
+++ b/Pyext/test/py_u_TestWith.py
@@ -0,0 +1,79 @@
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+# Name :
+# Author : Avi
+# Revision : $Revision: #10 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+# code for testing with statement
+# In our case it provides the ability to indent
+
+from ecflow import Defs, Suite, Family, Client, debug_build
+import sys
+
+if __name__ == "__main__":
+ print "####################################################################"
+ print "Running ecflow version " + Client().version() + " debug build(" + str(debug_build()) +")"
+ print "####################################################################"
+
+ version = sys.version_info;
+ if version[1] < 7 :
+ print "This test only run with python version 2.7, but found : " + str(version)
+ exit(0)
+
+ print "start test"
+ # Add with context manager, in our case this only provides ability to indent
+ with Defs() as defs:
+ with defs.add_suite("s2") as s2:
+ with s2.add_family("f1") as f1:
+ with f1.add_task("t1") as t1:
+ assert len(list(f1.nodes)) == 1,"Expected 1 task"
+ s2.add_family("f2")
+ s2.add_task("t1")
+ assert len(list(s2.nodes)) == 3,"Expected 2 families and one task suite"
+ assert len(list(defs.suites)) == 1,"Expected 1 suite"
+# print defs
+
+ with Suite("s2") as s2:
+ s2.add_family("f1")
+ s2.add_task("t1")
+ assert len(list(s2.nodes)) == 2,"Expected 2 nodes family and task"
+
+ with Family("f1") as f1:
+ f1.add_family("f2")
+ f1.add_task("t1")
+ assert len(list(s2.nodes)) == 2,"Expected 2 nodes family and task"
+
+
+ #
+ # Add Nodes functional way
+ #
+ defs1 = Defs()
+ defs1.add_suite("s1").add_task("t1").add_variable("var","v")
+ defs1.add_suite("s2").add_family("f1").add_task("t1").add_variable("var","v")
+ defs1.add_suite("s3").add_family("f1").add_family("f2").add_task("t1").add_variable("var","v")
+
+ # add node using with, they should compare
+ with Defs() as defs2:
+ with defs2.add_suite("s1") as s1:
+ t1 = s1.add_task("t1")
+ t1.add_variable("var","v")
+ with defs2.add_suite("s2") as s2:
+ with s2.add_family("f1") as f1:
+ with f1.add_task("t1") as t1:
+ t1.add_variable("var","v")
+ with defs2.add_suite("s3") as s3:
+ with s3.add_family("f1") as f1:
+ with f1.add_family("f2") as f2:
+ with f2.add_task("t1") as t1:
+ t1.add_variable("var","v")
+
+ assert defs1 == defs2,"expected defs to be the same"
+
+ print "All tests pass"
\ No newline at end of file
diff --git a/Pyext/test/test.ddoc b/Pyext/test/test.ddoc
new file mode 100644
index 0000000..ff31481
--- /dev/null
+++ b/Pyext/test/test.ddoc
@@ -0,0 +1,18 @@
+
+
+ self.country_data_rep_list_ = sorted(self.country_data_rep_list_, key=lambda DataRep: DataRep.total_,reverse=True)
+
+ from operator import itemgetter, attrgetter
+ self.country_data_rep_list_ = sorted(self.country_data_rep_list_, key=attrgetter('total_'),reverse=True)
+
+
+To Use a library function in the Test do:
+
+
+ # Place library function in say. Util.py in the Pyext/test directory
+ # Then change the module search path, so it gets loaded
+ #
+ import os, sys
+ test = os.getcwd() + "/test"
+ sys.path.append(test)
+ from Util import *
\ No newline at end of file
diff --git a/ecflow_4_0_7/Pyext/unicode.py b/Pyext/unicode.py
similarity index 100%
rename from ecflow_4_0_7/Pyext/unicode.py
rename to Pyext/unicode.py
diff --git a/README b/README
new file mode 100644
index 0000000..fbbae0d
--- /dev/null
+++ b/README
@@ -0,0 +1,198 @@
+===========
+**Install**
+===========
+
+* dependencies
+
+ - PYTHON_API:
+ python 2.7, Python 3.0 not tested.
+ If you intend to use ecFlow Python api, You will need to install python.
+ If python installed in non standard installation, you may need to
+ customise $BOOST_ROOT/tools/build/v2/site-config.jam
+ The python installation should include the development packages
+
+ - ecflowview:
+ Xlib, X11, XMotif for :term:`ecflowview`. Do *not* use Lesstif library
+ to compile ecflowview as a replacement for Motif. OpenMotif can be
+ downloaded from http://www.ist.co.uk/downloads/motif_download.html
+
+ - ecflow_ui: ( new GUI )
+ QT5 at least version 5.0.0 is required or Qt4 4.8.0 and above
+
+* ecfFlow consists of two tar files i.e. :
+
+ - boost_1_53_0.tar.gz
+ - ecFlow-4.1.0-Source.tar.gz
+
+* Create a directory for the build::
+
+ > mkdir /tmp/ecflow_build
+
+* Copy the the two tar file into this directory, then change directory to /tmp/ecflow_build
+
+* Un-zip then un-tar the two file files::
+
+ > tar -zxf boost_1_53_0.tar.gz
+ > tar -zxf ecFlow-4.1.0-Source.tar.gz
+
+* You should have two directories created::
+
+ - boost_1_53_0
+ - ecFlow-4.1.0-Source
+
+* Create two environment variables. These are used by some of scripts::
+
+ > export WK=/tmp/ecflow_build/ecFlow-4.1.0-Source
+ > export BOOST_ROOT=/tmp/ecflow_build/boost_1_53_0
+
+* There are two ways of building ecflow, boost-build/bjam or cmake
+ >> Preference should be given to using cmake <<
+ The new GUI ecflow_ui can only be built with cmake/ecbuild.
+
+* To maintain compatibility between different releases of ecflow, you
+ should use the same version of boost. If you do not care about this,
+ then any boost version (> 1.53) should suffice. To use an existing
+ boost release please ensure environment variable BOOST_ROOT is set
+
+boost libs
+=====================================================================
+Use the following step to build boost from scratch:
+
+* Boost uses bjam for building the boost libraries.
+ bjam source is available in boost, hence we first need to build bjam itself
+
+ > cd $BOOST_ROOT
+ > ./bootstrap.sh
+
+ Now make sure bjam is accessible from $PATH
+
+* Ecflow uses some of compiled libraries in boost. The following script
+ will build the required lib's, in both debug and release forms
+ and will configure boost build according to your platform
+
+ > cd $BOOST_ROOT
+ > $WK/build_scripts/boost_1_53_fix.sh # fix for boost, only for some platforms
+ > $WK/build_scripts/boost_build.sh # compile boost libs used by ecFlow
+
+ecflowview
+====================================================================
+
+* When compiling ecflowview in a system where motif is not installed in the
+ usual location, or where both motif and lesstif are installed, it is possible
+ to export the environment variables MOTIF_INCLUDE and MOTIF_LIBRARY to help
+ bjam to find the right location for include files and libraries.
+
+ Openmotif may be retrieve from IST server and installed locally:
+ wget http://www.ist-inc.com/motif/download/motif_files/openmotif-2.1.32-2_IST.x86_64.rpm
+ rpm2cpio openmotif-2.1.32-2_IST.x86_64.rpm | cpio -idmv
+
+ user shall then compile setting MOTIF_INCLUDE and MOTIF_LIBRARY variable.
+
+.. ecflowview shall be started setting LD_LIBRARY_PATH=${MOTIF_LIBRARY}:$LD_LIBRARY_PATH
+
+* ECFLOWVIEW_HOME shell variable may be set to link ecflowview to the directory
+ where to find 'servers' and 'ecflowview.menu' files
+
+* ECFLOWRC variable may be set to use alternative directory for user
+ ecflowview option files (default is $HOME/.ecflowrc)
+
+
+cmake
+=====================================================================
+* By default will install /usr/local, hence may require root access rights
+ > cd /tmp/ecflow_build/ecFlow-4.1.0-Source
+ > mkdir build; cd build
+ > cmake ..
+ > make -j2
+ > make install
+ > make test
+
+
+* Optionally you can specify install prefix directory:
+
+ > cd /tmp/ecflow_build/ecFlow-4.1.0-Source
+ > mkdir build; cd build
+ > cmake .. -DCMAKE_INSTALL_PREFIX=/var/tmp/$USER/install/cmake/ecflow
+ > make -j2
+ > make install
+
+
+* Optionally if you do *NOT* want to build the GUI(ecflowview) or UI(ecflow_ui) or Python api:
+
+ > cd /tmp/ecflow_build/ecFlow-4.1.0-Source
+ > mkdir build; cd build
+ > cmake .. -DCMAKE_INSTALL_PREFIX=/var/tmp/$USER/install/cmake/ecflow \
+ -DENABLE_GUI=OFF \
+ -DENABLE_UI=OFF \
+ -DENABLE_PYTHON=OFF
+ > make -j2
+ > make install
+
+
+* Optionally if you did not export BOOST_ROOT you can specify on the command line:
+
+ > cd /tmp/ecflow_build/ecFlow-4.1.0-Source
+ > mkdir build; cd build
+ > cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local/apps/ecflow \
+ -DCMAKE_BUILD_TYPE=Debug \
+ -DBOOST_ROOT=/tmp/ecflow_build/boost_1_53_0
+ > make -j2
+ > make install
+
+
+* On some platforms(AIX) you may need to specify the c++ compiler
+
+ > cd /tmp/ecflow_build/ecFlow-4.1.0-Source
+ > mkdir build; cd build
+ > cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local/apps/ecflow \
+ -DCMAKE_CXX_COMPILER=xlC_r"
+ > make -j2
+ > make install
+
+
+boost/bjam: This can not build the new UI(ecflow_ui)
+=====================================================================
+* For installation the following environment variables are required.
+
+ ECFLOW_INSTALL_DIR # Directory Location for client ,server and gui program's
+ ECFLOW_PYTHON_INSTALL_DIR # Directory Location for ecflow python package
+
+ The python installation can be customised, by changing Pyext/jamfile.jam
+ and site-config.jam
+
+* We now need to build ecFlow. Currently ecflowview is only built if
+ environment variable of name ARCH is set to linux::
+
+ > cd $WK
+ > bjam variant=release install-all
+
+ On some systems like fedora/redhat you may run into compiler errors
+ which complain about the template depth being exceeded.
+ In this case compile using:
+
+ > cd $WK
+ > bjam c++-template-depth=512 variant=release install-all
+
+ If you have a multi-core machine, you can speed up the build using:
+ the -j<n> option. Where 'n' is an integer, of the number of cores.
+
+ bjam variant=release -j4
+
+* Once ecFlow is built it can be installed.
+
+ bjam variant=release install-all
+
+ This will create directories::
+
+ <ECFLOW_INSTALL_DIR>/bin
+ <ECFLOW_INSTALL_DIR>/lib
+ <ECFLOW_INSTALL_DIR>/doc
+ <ECFLOW_PYTHON_INSTALL_DIR>
+
+ Depending on your umask setting you may need to call chmod 755 on the executables
+
+* To use the python_api, you need to add/change
+ PYTHONPATH and LD_LIBRARY_PATH
+
+ export PYTHONPATH=$PYTHONPATH:$ECFLOW_PYTHON_INSTALL_DIR
+ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ECFLOW_PYTHON_INSTALL_DIR
\ No newline at end of file
diff --git a/ecflow_4_0_7/Server/CMakeLists.txt b/Server/CMakeLists.txt
similarity index 100%
rename from ecflow_4_0_7/Server/CMakeLists.txt
rename to Server/CMakeLists.txt
diff --git a/Server/Jamfile.jam b/Server/Jamfile.jam
new file mode 100644
index 0000000..df5cc67
--- /dev/null
+++ b/Server/Jamfile.jam
@@ -0,0 +1,93 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+#
+# Server
+#
+project theServer ;
+
+#
+# IMPORTANT: server *MUST* not link with client or include any of the client code
+#
+use-project theCore : ../ACore ;
+use-project theNodeAttr : ../ANattr ;
+use-project theNode : ../ANode ;
+use-project theBase : ../Base ;
+use-project theParser : ../AParser ;
+
+lib pthread ;
+
+#
+# Split into library, so that testing can use library, and hence same compiler option
+#
+# The <include> means we will automatically add this directory to the include path
+# of any other target that uses this lib
+
+#
+# Note: boost_thread is *ONLY* needed to test multi-threaded server, i.e when ECFLOW_MT defined
+#
+lib libserver : [ glob src/*.cpp : src/*Main.cpp ]
+ : <include>../ACore/src
+ <include>../ANattr/src
+ <include>../ANode/src
+ <include>../AParser/src
+ <include>../Base/src
+ <include>../Server/src
+ <variant>debug:<define>DEBUG
+ <link>static
+ <use>/theCore//core
+ <use>/theNode//node
+ <use>/theBase//base
+ <use>/theParser//libparser
+ <use>/site-config//boost_system
+ <use>/site-config//boost_thread
+ <use>/site-config//boost_serialization
+ <use>/site-config//boost_filesystem
+ <use>/site-config//boost_program_options
+ <use>/site-config//boost_datetime
+ :
+ : <include>../Server/src
+ ;
+
+exe ecflow_server : [ glob src/*Main.cpp ]
+ pthread
+ /theCore//core
+ /theNodeAttr//nodeattr
+ /theNode//node
+ /theParser//libparser
+ /theBase//base
+ libserver
+ /site-config//boost_system
+ /site-config//boost_thread
+ /site-config//boost_serialization
+ /site-config//boost_filesystem
+ /site-config//boost_datetime
+ /site-config//boost_program_options
+ : <variant>debug:<define>DEBUG
+ ;
+
+#
+# Test for server
+# IMPORTANT: server *MUST* not link with client or include any of the client code
+#
+exe u_server : [ glob test/*.cpp ]
+ pthread
+ /theCore//core
+ /theNodeAttr//nodeattr
+ /theNode//node
+ /theParser//libparser
+ /theBase//base
+ libserver
+ /site-config//boost_system
+ /site-config//boost_thread
+ /site-config//boost_serialization
+ /site-config//boost_filesystem
+ /site-config//boost_datetime
+ /site-config//boost_program_options
+ /site-config//boost_test
+ : <variant>debug:<define>DEBUG
+ ;
diff --git a/Server/server_environment.cfg b/Server/server_environment.cfg
new file mode 100644
index 0000000..61dc98d
--- /dev/null
+++ b/Server/server_environment.cfg
@@ -0,0 +1,153 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+#
+# This file is used to define the standard defaults for ECF.
+# Most are *variables* used in the server
+# Some like ECF_TASK_THRESHOLD are used to debug job generation
+
+# ******************************************************************
+# Warning: Do *NOT* use quotes around the value part.
+# WRONG: ECF_MICRODEF = "%"
+# RIGHT: ECF_MICRODEF = %
+# ******************************************************************
+
+# *******************************************************************
+# * ECF_HOME is typically the home/root for all '.ecf' files
+# * Can be overridden with a environment variable of the same name
+# *******************************************************************
+ECF_HOME = .
+
+
+# ******************************************************************
+# * The name of check point file. i.e defs file with state
+# * Can be overridden with a environment variable of the same name
+# * default: is <host>.<port>.ecf.check
+# * Note: Any settings will be prepended with <host>.<port>.
+# ******************************************************************
+ECF_CHECK = ecf.check
+
+
+# ******************************************************************
+# * The name of the backup checkpoint file
+# * Can be overridden with a environment variable of the same name
+# * default: is <host>.<port>.ecf.check.b
+# * Note: Any settings will be prepended with <host>.<port>.
+# ******************************************************************
+ECF_CHECKOLD = ecf.check.b
+
+
+# ******************************************************************
+# * The intervals within the server that the checkpoint file should
+# * be saved.
+# * Can be overridden with a environment variable of the same name
+# ******************************************************************
+ECF_CHECKINTERVAL = 120
+
+
+# ******************************************************************
+# * Check point configuration:
+# *
+# * Mode must be one of:
+# * CHECK_NEVER /* No auto checkpointing */
+# * CHECK_ON_TIME /* At intervals specified by ECF_CHECKINTERVAL */
+# * CHECK_ALWAYS /* After any change */
+# * The checkpoint filenames can be configured using environment variables
+# ******************************************************************
+ECF_CHECKMODE = CHECK_ON_TIME
+
+
+# ******************************************************************
+# * The port number, this must be consistent between client and server
+# * If we get "Address in use" then both client/server number should changed.
+# * Also if two servers are started on the same machine with same port
+# * then we will also get "Address in use" error and server will bomb out.
+# * Can be overridden with a environment variable of the same name
+# ******************************************************************
+ECF_PORT = 3141
+
+
+# ******************************************************************
+# * The name of log file.
+# * default log file name is: <host>.<port>.ecf.log, i.e machine1.3141.ecf.log
+# * this is required since we can have multiple servers for a single
+# * machine, where each server will have a separate port number.
+# * Can be overridden with a environment variable of the same name
+# *
+# * Note: Any settings will be prepended with <host>.<port>.
+# ******************************************************************
+ECF_LOG = ecf.log
+
+
+# ******************************************************************
+# * The period in second for which we should traverse dependencies
+# * and submit jobs. This should rarely need changing, as it can affect
+# * correspondence with real time
+# ******************************************************************
+ECF_INTERVAL = 60
+
+
+# ******************************************************************
+# * The standard command use for job submission.
+# * Provides DEFAULT can be overridden by user variable
+# ******************************************************************
+ECF_JOB_CMD = %ECF_JOB% 1> %ECF_JOBOUT% 2>&1
+
+
+# ******************************************************************
+# * Define variable for killing any jobs.
+# * Provides DEFAULT can be overridden by user variable
+# * The output of the command should be written to %ECF_JOB%.kill
+# * ecmwf: ${ECF_KILL:=/home/ma/emos/bin/ecfkill} %USER% %HOST% %ECF_RID% %ECF_JOB% > %ECF_JOB%.kill 2>&1
+# ******************************************************************
+ECF_KILL_CMD = kill -15 %ECF_RID%
+
+
+# ******************************************************************
+# * define variable of obtaining status.
+# * Provides DEFAULT can be overridden by user variable
+# * The output of the command should be written to %ECF_JOB%.stat
+# * ecmwf: ${ECF_STAT:=/home/ma/emos/bin/ecfstatus} %USER% %HOST% %ECF_RID% %ECF_JOB% > %ECF_JOB%.stat 2>&1
+# ******************************************************************
+ECF_STATUS_CMD = ps --sid %ECF_RID% -f
+
+
+# ******************************************************************
+# * define variables used for url command.
+# * Provides DEFAULT can be overriden by user variables
+# ******************************************************************
+ECF_URL_CMD = ${BROWSER:=firefox} -remote 'openURL(%ECF_URL_BASE%/%ECF_URL%)'
+ECF_URL_BASE = https://software.ecmwf.int
+ECF_URL = wiki/display/ECFLOW/Home
+
+# ******************************************************************
+# * Defines the character used in ECF_ pre-processing. i.e identifies includes
+# * and is also used in variable substitution in '.ecf' scripts
+# ******************************************************************
+ECF_MICRODEF = %
+
+# ******************************************************************
+# * The ECF_LISTS is used to identify a file, that lists the user
+# * who can access the server via client commands. Each client command
+# * (ignoring task based commands, i.e init, complete, event, meter, label)
+# * will encode the user name of the process initiating the client request
+# * This is then compared with list of users in the ecf.lists file.
+# * If this file is empty, then no authentication is done
+# * Each server can potionally have a different list.
+# * default: <host>.<port>.ecf.lists
+# * Note: Any settings will be prepended with <host>.<port>.
+# ******************************************************************
+ECF_LISTS = ecf.lists
+
+
+# ***************************************************************************
+# * ECF_TASK_THRESHOLD:
+# * Report on an task taking longer than the threshold. !!
+# * export ECF_TASK_THRESHOLD=4000
+# ***************************************************************************
+ECF_TASK_THRESHOLD = 4000
+
\ No newline at end of file
diff --git a/Server/src/CConnection.cpp b/Server/src/CConnection.cpp
new file mode 100644
index 0000000..f8bf2f7
--- /dev/null
+++ b/Server/src/CConnection.cpp
@@ -0,0 +1,237 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #14 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : ONLY used if ECFLOW_MT is defined
+//
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#ifdef ECFLOW_MT
+#if defined(HPUX)
+#include <sys/select.h> // hp-ux uses pselect
+#endif
+
+#include <boost/thread/thread.hpp>
+#include <boost/bind.hpp>
+
+#include "CConnection.hpp"
+#include "Log.hpp"
+#include <vector>
+
+#include "Log.hpp"
+#include "Serialization.hpp"
+#include "Server.hpp"
+
+using namespace std;
+using namespace ecf;
+
+CConnection::CConnection(boost::asio::io_service& io_service,server* server)
+ : socket_(io_service),
+ server_(server)
+{
+}
+
+boost::asio::ip::tcp::socket& CConnection::socket()
+{
+ return socket_;
+}
+
+void CConnection::start()
+{
+ //cout << boost::this_thread::get_id() << " CConnection::start()\n";
+ boost::asio::async_read(socket_, boost::asio::buffer(inbound_header_),
+ server_->strand_.wrap(
+ boost::bind(&CConnection::handle_read_header,
+ shared_from_this(),
+ boost::asio::placeholders::error)));
+}
+
+void CConnection::handle_read_header(const boost::system::error_code& e)
+{
+ //cout << boost::this_thread::get_id() << " CConnection::handle_read_header\n";
+ if (e) {
+ LogToCout toCoutAsWell;
+ LOG(Log::ERR, " CConnection::handle_read_header error occurred " << e.message());
+ }
+ else {
+ // Determine the length of the serialized data.
+ std::istringstream is(std::string(inbound_header_, header_length));
+ std::size_t inbound_data_size = 0;
+ if (!(is >> std::hex >> inbound_data_size)) {
+
+ // Header doesn't seem to be valid. Inform the caller.
+ boost::system::error_code error(boost::asio::error::invalid_argument);
+ LogToCout toCoutAsWell;
+ LOG(Log::ERR, " CConnection::handle_read_header error occurred " << e.message());
+ return;
+ }
+
+ // Start an asynchronous call to receive the data.
+ inbound_data_.resize(inbound_data_size);
+ boost::asio::async_read(socket_,boost::asio::buffer(inbound_data_),
+ server_->strand_.wrap(
+ boost::bind(&CConnection::handle_read_data,
+ shared_from_this(),
+ boost::asio::placeholders::error)));
+ }
+}
+
+void CConnection::handle_read_data(const boost::system::error_code& e)
+{
+ //cout << boost::this_thread::get_id() << " CConnection::handle_read_data\n";
+ if (e) {
+ LogToCout toCoutAsWell;
+ LOG(Log::ERR, " CConnection::handle_read_data error occurred " << e.message());
+ return;
+ }
+
+ // Extract the data structure from the data just received.
+ try {
+ std::string archive_data(&inbound_data_[0], inbound_data_.size());
+ ecf::restore_from_string(archive_data,inbound_request_);
+ }
+ catch (const boost::archive::archive_exception& ae ) {
+ // Unable to decode data.
+ ecf::LogToCout logToCout;
+ LOG(ecf::Log::ERR,"CConnection::handle_read_data boost::archive::archive_exception " << ae.what());
+ return;
+ }
+ catch (std::exception& ) {
+ // Unable to decode data.
+ ecf::LogToCout logToCout;
+ LOG(ecf::Log::ERR,"CConnection::handle_read_data Unable to decode data");
+ return;
+ }
+
+
+ // See what kind of message we got from the client
+ // std::cout << boost::this_thread::get_id() << " server::handle_read : client request " << inbound_request_ << "\n";
+ try {
+ // Service the in bound request, handling the request will populate the outbound_response_
+ // Note:: Handle request will first authenticate
+ outbound_response_.set_cmd( inbound_request_.handleRequest( server_ ) );
+ }
+ catch (exception& ex) {
+ outbound_response_.set_cmd( PreAllocatedReply::error_cmd( ex.what() ));
+ }
+
+ // To improve performance, when the reply, is OK, don't bother replying back to the client
+ // The client will receive a EOF, and perceive this as OK.
+ // Need to specifically *ignore* for terminate, otherwise server will not shutdown cleanly
+ if (!inbound_request_.terminateRequest() && outbound_response_.get_cmd()->isOkCmd()) {
+ // cleanly close down the connection
+ socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
+ socket_.close();
+ return;
+ }
+
+ reply_back_to_client();
+}
+
+void CConnection::reply_back_to_client()
+{
+#ifdef DEBUG_CONNECTION
+ std::cout << "CConnection::reply_back_to_client, Serialise the data first so we know how large it is\n";
+#endif
+ // Serialise the data first so we know how large it is.
+ try {
+ ecf::save_as_string(outbound_data_,outbound_response_);
+ } catch (const boost::archive::archive_exception& ae ) {
+ // Unable to decode data. Something went wrong, inform the caller.
+ ecf::LogToCout logToCout;
+ LOG(ecf::Log::ERR,"Connection::async_write boost::archive::archive_exception " << ae.what());
+ return;
+ }
+
+ // Format the header.
+ std::ostringstream header_stream;
+ header_stream << std::setw(header_length) << std::hex << outbound_data_.size();
+ if (!header_stream || header_stream.str().size() != header_length) {
+ // Something went wrong, inform the caller.
+ ecf::LogToCout logToCout;
+ LOG(ecf::Log::ERR,"CConnection::reply_back_to_client: could not format header");
+ return;
+ }
+ outbound_header_ = header_stream.str();
+
+
+#ifdef DEBUG_CONNECTION
+ std::cout << "Connection::async_write Write the serialized data to the socket. \n";
+#endif
+ // Write the serialized data to the socket. We use "gather-write" to send
+ // both the header and the data in a single write operation.
+ std::vector<boost::asio::const_buffer> buffers; buffers.reserve(2);
+ buffers.push_back(boost::asio::buffer(outbound_header_));
+ buffers.push_back(boost::asio::buffer(outbound_data_));
+ boost::asio::async_write(socket_, buffers,
+ server_->strand_.wrap(
+ boost::bind(&CConnection::handle_write, shared_from_this(),
+ boost::asio::placeholders::error)));
+
+#ifdef DEBUG_CONNECTION
+ std::cout << "Connection::async_write END \n";
+#endif
+
+ // If an error occurs then no new asynchronous operations are started. This
+ // means that all shared_ptr references to the CConnection object will
+ // disappear and the object will be destroyed automatically after this
+ // handler returns. The CConnection class's destructor closes the socket.
+}
+
+void CConnection::handle_write(const boost::system::error_code& e)
+{
+ // Handle completion of a write operation.
+ // Nothing to do. The socket will be closed automatically when the last
+ // reference to the connection object goes away.
+ //cout << boost::this_thread::get_id() << " server::handle_write: client request " << inbound_request_ << " replying with " << outbound_response_ << "\n";
+
+ if (e)
+ {
+ ecf::LogToCout logToCout;
+ LOG(ecf::Log::ERR,"Connection::handle_write: " << e.message());
+
+ // No new asynchronous operations are started. This means that all shared_ptr
+ // references to the CConnection object will disappear and the object will be
+ // destroyed automatically after this handler returns. The CConnection class's
+ // destructor closes the socket.
+ return;
+ }
+
+
+ // Initiate graceful connection closure.
+ // For portable behaviour with respect to graceful closure of a connected socket, call shutdown() before closing the socket.
+ // This *CAN* throw an error if the client side socket is not connected. client may have been killed.
+ // i.e "shutdown: Transport endpoint is not connected"
+ boost::system::error_code ec;
+ socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
+ if (ec) {
+ ecf::LogToCout logToCout;
+ LOG(Log::ERR,"server::handle_write: socket shutdown both failed: " << ec.message());
+ }
+
+
+ // If asked to terminate we do it here rather than in handle_read.
+ // So that we have responded to the client.
+ // *HOWEVER* only do this if the request was successful.
+ // we do this by checking that the out bound response was ok
+ // i.e a read only user should not be allowed to terminate server.
+ if (inbound_request_.terminateRequest() && outbound_response_.get_cmd()->isOkCmd()) {
+ // cout << " <--server::handle_write exiting server via terminate() port " << endl;
+
+ server_->terminate();
+ }
+
+ // No new asynchronous operations are started. This means that all shared_ptr
+ // references to the CConnection object will disappear and the object will be
+ // destroyed automatically after this handler returns. The CConnection class's
+ // destructor closes the socket.
+}
+#endif
diff --git a/Server/src/CConnection.hpp b/Server/src/CConnection.hpp
new file mode 100644
index 0000000..15f7b24
--- /dev/null
+++ b/Server/src/CConnection.hpp
@@ -0,0 +1,74 @@
+#ifndef CCONNECTION_HPP
+#define CCONNECTION_HPP
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name :
+// Author : Avi
+// Revision : $Revision: #14 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : ONLY used if ECFLOW_MT is defined
+//
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <boost/asio.hpp>
+#include <boost/array.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+
+#include "ClientToServerRequest.hpp"
+#include "ServerToClientResponse.hpp"
+
+class server;
+
+/// Represents a single connection from a client.
+class CConnection : public boost::enable_shared_from_this<CConnection>, private boost::noncopyable {
+public:
+ /// Construct a connection with the given io_service.
+ explicit CConnection( boost::asio::io_service& io_service, server* );
+
+ /// Get the socket associated with the connection.
+ boost::asio::ip::tcp::socket& socket();
+
+ /// Start the first asynchronous operation for the connection.
+ void start();
+
+private:
+ /// Handle completion of a read operation.
+ void handle_read( const boost::system::error_code& e, std::size_t bytes_transferred );
+
+ void handle_read_data(const boost::system::error_code& e);
+ void handle_read_header(const boost::system::error_code& e);
+ void reply_back_to_client();
+
+ /// Handle completion of a write operation.
+ void handle_write( const boost::system::error_code& e );
+
+private:
+ /// Socket for the connection.
+ boost::asio::ip::tcp::socket socket_;
+
+ /// Strand to ensure the connection's handlers are not called concurrently.
+ server* server_;
+
+ /// The data, typically loaded once, and then sent to many clients
+ ClientToServerRequest inbound_request_; /// The incoming request.
+ ServerToClientResponse outbound_response_; /// The reply to be sent back to the client.
+
+
+ std::string outbound_header_; /// Holds an out-bound header.
+ std::string outbound_data_; /// Holds the out-bound data.
+ enum { header_length = 8 }; /// The size of a fixed length header.
+ char inbound_header_[header_length]; /// Holds an in-bound header.
+ std::vector<char> inbound_data_; /// Holds the in-bound data.
+};
+
+typedef boost::shared_ptr<CConnection> CConnection_ptr;
+
+#endif
diff --git a/Server/src/CheckPtSaver.cpp b/Server/src/CheckPtSaver.cpp
new file mode 100644
index 0000000..2472de2
--- /dev/null
+++ b/Server/src/CheckPtSaver.cpp
@@ -0,0 +1,243 @@
+//============================================================================
+// Name : CheckPtSaver.cpp
+// Author : Avi
+// Revision : $Revision: #43 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <fstream>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include "boost/bind.hpp"
+
+#include "CheckPtSaver.hpp"
+#include "Server.hpp"
+#include "ServerEnvironment.hpp"
+#include "Defs.hpp"
+#include "Log.hpp"
+#include "DurationTimer.hpp"
+#include "CtsApi.hpp"
+#include "Str.hpp"
+#include "Ecf.hpp"
+#include "File.hpp"
+
+//#define DEBUG_CHECKPT 1
+//#define DEBUG_CHECKPT_SAVE_ALLOWED 1
+
+#ifdef DEBUG_CHECKPT
+#include <boost/date_time/posix_time/time_formatters.hpp> // requires boost date and time lib, for to_simple_string
+#endif
+
+namespace fs = boost::filesystem;
+using namespace ecf;
+
+
+//-------------------------------------------------------------------------------------
+CheckPtSaver::CheckPtSaver(
+ Server* s,
+ boost::asio::io_service& io,
+ const ServerEnvironment* serverEnv )
+: server_( s ),
+ timer_( io, boost::posix_time::seconds( 0 ) ),
+ firstTime_(true),
+ running_(false),
+ serverEnv_(serverEnv),
+ state_change_no_(Ecf::state_change_no()),
+ modify_change_no_(Ecf::modify_change_no())
+{
+#ifdef DEBUG_CHECKPT
+ std::cout << " CheckPtSaver::CheckPtSaver period = " << serverEnv_->checkPtInterval() << "\n";
+#endif
+}
+
+CheckPtSaver::~CheckPtSaver() {
+#ifdef DEBUG_CHECKPT
+ std::cout << " ~CheckPtSaver::CheckPtSaver\n";
+#endif
+}
+
+void CheckPtSaver::start()
+{
+#ifdef DEBUG_CHECKPT
+ std::cout << " CheckPtSaver::start() check_mode: "
+ << serverEnv_->check_mode_str() << " interval = " << serverEnv_->checkPtInterval()
+ << " time = " << to_simple_string(boost::posix_time::second_clock::universal_time()) << "\n";
+#endif
+
+ // Only save check pt periodically if configuration allows it
+ if (serverEnv_->checkMode() != ecf::CheckPt::ON_TIME ) {
+#ifdef DEBUG_CHECKPT
+ std::cout << " CheckPtSaver::start() aborted as configuration does not allow it" << std::endl;
+#endif
+ return;
+ }
+
+ running_ = true;
+
+ // * important * The time should only be started *ONCE*. Otherwise we will end up with
+ // with explicit save each time server is halted/started.
+ if (firstTime_) {
+ firstTime_ = false;
+ timer_.expires_from_now( boost::posix_time::seconds( serverEnv_->checkPtInterval() ) );
+#ifdef ECFLOW_MT
+ timer_.async_wait( server_->strand_.wrap( boost::bind( &CheckPtSaver::periodicSaveCheckPt,this,boost::asio::placeholders::error ) ) );
+#else
+ timer_.async_wait( server_->io_service_.wrap( boost::bind( &CheckPtSaver::periodicSaveCheckPt,this,boost::asio::placeholders::error ) ) );
+#endif
+ }
+}
+
+void CheckPtSaver::stop()
+{ // The server is stopped by cancelling all outstanding asynchronous
+ // operations. Once all operations have finished the io_service::run() call
+ // will exit.
+#ifdef DEBUG_CHECKPT
+ std::cout << " CheckPtSaver::stop() check_mode: " << serverEnv_->check_mode_str() << " interval = " << serverEnv_->checkPtInterval() << "\n";
+#endif
+ running_ = false;
+}
+
+void CheckPtSaver::terminate()
+{
+ timer_.cancel();
+}
+
+
+void CheckPtSaver::explicitSave(bool from_server) const
+{
+ if ( server_->defs_ ) {
+
+ try {
+#ifdef DEBUG_CHECKPT
+ std::cout << " CheckPtSaver::explicitSave() Saving checkpt file " << serverEnv_->checkPtFilename() << "\n";
+#endif
+ // Time how long we take to checkpt, Help to recognise *SLOW* disk, which can *AFFECT* server performance
+ DurationTimer durationTimer;
+
+ // Backup checkpoint file if it exists & is non zero
+ // Avoid an empty file as a backup file, could results from a full file system
+ // i.e move ecf_checkpt_file --> ecf_backup_checkpt_file
+ fs::path checkPtFile(serverEnv_->checkPtFilename());
+ if (fs::exists(checkPtFile) && fs::file_size(checkPtFile) != 0) {
+
+ fs::path oldCheckPtFile(serverEnv_->oldCheckPtFilename());
+ fs::remove(oldCheckPtFile);
+ fs::rename( checkPtFile, oldCheckPtFile );
+ }
+
+ // write to ecf_checkpt_file, if file system is full this could result in an empty file. ?
+ //
+ // To optimise check pointing, we minimise system calls, i.e we can write check point as a string,
+ // and save string to a file with a single write. This is faster than calling:
+ // server_->defs_->save_as_checkpt( serverEnv_->checkPtFilename() );
+ // This solution however does require *MORE* memory.
+ std::string checkpt_as_string,error_msg;
+ server_->defs_->save_checkpt_as_string(checkpt_as_string);
+ if (!File::create(serverEnv_->checkPtFilename(),checkpt_as_string,error_msg)) {
+ throw std::runtime_error(error_msg);
+ }
+
+ state_change_no_ = Ecf::state_change_no(); // For periodic update only save checkPt if it has changed
+ modify_change_no_ = Ecf::modify_change_no(); // For periodic update only save checkPt if it has changed
+
+
+ if (from_server) {
+ // Create new time stamp otherwise we end up using the time stamp from the last command
+ if (Log::instance()) Log::instance()->cache_time_stamp();
+ std::string msg = Str::SVR_CMD(); msg += CtsApi::checkPtDefsArg();
+ std::stringstream ss; ss << msg << " in " << durationTimer.duration() << " seconds";
+ log(Log::MSG,ss.str());
+ }
+
+ /// If Save take longer than checkpt_save_time_alarm, then set a flag on server
+ /// So that user can be aware of it.
+ if (static_cast<size_t>(durationTimer.duration()) > server_->serverEnv_.checkpt_save_time_alarm() ) {
+ server_->defs_->flag().set(ecf::Flag::LATE);
+ std::stringstream ss;
+ ss << "Check pt save time(" << durationTimer.duration() << ") is greater than alarm time("
+ << server_->serverEnv_.checkpt_save_time_alarm() << "). Excessive save times can interfere with scheduling!";
+ log(Log::WAR,ss.str());
+ }
+#ifdef DEBUG_CHECKPT
+ std::cout << " backup and save took " << durationTimer.duration() << " seconds\n";
+#endif
+ }
+ catch (std::exception& e) {
+ LOG(Log::ERR,"Could not save checkPoint file! " << e.what() << " File system full?");
+ }
+ }
+ else {
+#ifdef DEBUG_CHECKPT
+ std::cout << " CheckPtSaver::explicitSave() Node tree not loaded, can not save check pt file\n";
+#endif
+ }
+}
+
+void CheckPtSaver::periodicSaveCheckPt(const boost::system::error_code& error )
+{
+#ifdef DEBUG_CHECKPT
+ std::cout << " CheckPtSaver::periodicSaveCheckPt() interval = " << serverEnv_->checkPtInterval() << " time: " << to_simple_string(boost::posix_time::second_clock::universal_time()) << "\n";
+#endif
+ if (error == boost::asio::error::operation_aborted) {
+#ifdef DEBUG_CHECKPT
+ std::cout << " CheckPtSaver::periodicSaveCheckPt : boost::asio::error::operation_aborted : time cancelled: Node running(" << running_ << ") interval = " << serverEnv_->checkPtInterval() << "\n";
+#endif
+ return;
+ }
+ else if (error) {
+ LogToCout toCoutAsWell;
+ LOG(Log::ERR, "CheckPtSaver::periodicSaveCheckPt " << error.message());
+ return;
+ }
+
+ if (running_) {
+ // state changed
+ if (state_change_no_ != Ecf::state_change_no() || modify_change_no_ != Ecf::modify_change_no()) {
+ doSave();
+ }
+ }
+
+ /// Appears that expires_from_now is more accurate then expires_at
+ timer_.expires_from_now( boost::posix_time::seconds( serverEnv_->checkPtInterval() ) );
+#ifdef ECFLOW_MT
+ timer_.async_wait( server_->strand_.wrap( boost::bind( &CheckPtSaver::periodicSaveCheckPt,this,boost::asio::placeholders::error ) ) );
+#else
+ timer_.async_wait( server_->io_service_.wrap( boost::bind( &CheckPtSaver::periodicSaveCheckPt,this,boost::asio::placeholders::error ) ) );
+#endif
+}
+
+
+void CheckPtSaver::doSave() const
+{
+#ifdef DEBUG_CHECKPT
+ std::cout << " CheckPtSaver::doSave()\n";
+#endif
+ // Check to see if configuration allows save
+ if (serverEnv_->checkMode() == ecf::CheckPt::NEVER ) {
+#ifdef DEBUG_CHECKPT
+ std::cout << " CheckPtSaver::doSave() configuration does not allow save \n";
+#endif
+ return;
+ }
+ explicitSave(true/* from the server, hence log */);
+}
+
+void CheckPtSaver::saveIfAllowed()
+{
+ // Call on each state change. Hence will get many times
+#ifdef DEBUG_CHECKPT_SAVE_ALLOWED
+ std::cout << " CheckPtSaver::saveIfAllowed()\n";
+#endif
+
+ // Check to see if configuration allows immediate save.
+ if (serverEnv_->checkMode() == ecf::CheckPt::ALWAYS ) {
+ doSave();
+ }
+}
diff --git a/Server/src/CheckPtSaver.hpp b/Server/src/CheckPtSaver.hpp
new file mode 100644
index 0000000..aaf3f49
--- /dev/null
+++ b/Server/src/CheckPtSaver.hpp
@@ -0,0 +1,86 @@
+#ifndef CHECKPTSAVER_HPP_
+#define CHECKPTSAVER_HPP_
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name : CheckPtSaver.cpp
+// Author : Avi
+// Revision : $Revision: #14 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//
+// This class will save the defs file periodically. The period is obtained from
+// ServerEnvironment. The save of the check point file is controlled by
+// the settings in ServerEnvironment
+//
+// The checkpoint files is the defs file, with state. However its saved in
+// boost serialisation format(i.e can be text,binary,portable binary)
+//
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <boost/noncopyable.hpp>
+#include <boost/asio.hpp>
+
+class ServerEnvironment;
+class Server;
+
+class CheckPtSaver : private boost::noncopyable {
+public:
+ CheckPtSaver( Server* s, boost::asio::io_service& io, const ServerEnvironment*);
+ ~CheckPtSaver();
+
+ /// Start periodical save of the checkpoint file
+ void start();
+
+ /// Stop periodical save of the checkPoint file
+ void stop();
+
+ /// terminate: This will cancel the timer and any pending async operation
+ /// If timer has already expired, then the handler function will be
+ /// passed an operation aborted error code.
+ /// Called when the server is exiting. We must be sure to cancel all
+ /// async handlers or the server, will not stop.
+ void terminate();
+
+ /// Will always save the check pt file. Independent of any server environment
+ /// The input argument is used in logging. When check pointing via user command
+ /// we log the request. However we also check point automatically via the server
+ /// This allows us to distinguish the two cases in the log file:
+ void explicitSave(bool from_server = false) const;
+
+ /// This function is called after node state changes. Check for save
+ /// CheckPt::ON_TIME - will do nothing since we will save periodically
+ /// CheckPt::NEVER - will return immediately
+ /// CheckPt::ALWAYS - will save immediately, may cause performance issues with large Node trees
+ void saveIfAllowed();
+
+private:
+ /// save the node tree in the server to a checkPt file.
+ /// this is controlled by the configuration. If the configuration does not
+ /// allow a save, does nothing
+ void doSave() const;
+
+ /// Called periodically to save checkPoint file
+ /// We use error parameter, since when we cancel the timer via, terminate
+ /// we do NOT want to do an explicit save *PLUS* we want to return without
+ /// starting another async operation. Otherwise the server will not return
+ ///
+ /// This will call doSave() but *ONLY* if there has been a state change
+ /// This avoids writing out a checkpt file, unnecessarily & filling up log file
+ void periodicSaveCheckPt(const boost::system::error_code& error);
+
+ Server* server_;
+ boost::asio::deadline_timer timer_;
+ bool firstTime_;
+ bool running_;
+ const ServerEnvironment* serverEnv_;
+ mutable unsigned int state_change_no_; // detect state change in defs
+ mutable unsigned int modify_change_no_; // detect state change in defs
+};
+#endif
diff --git a/Server/src/NodeTreeTraverser.cpp b/Server/src/NodeTreeTraverser.cpp
new file mode 100644
index 0000000..ecca943
--- /dev/null
+++ b/Server/src/NodeTreeTraverser.cpp
@@ -0,0 +1,396 @@
+//============================================================================
+// Name : NodeTreeTraverser.cpp
+// Author : Avi
+// Revision : $Revision: #101 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <iostream>
+#include "boost/bind.hpp"
+
+#include "ServerEnvironment.hpp"
+#include "NodeTreeTraverser.hpp"
+#include "Server.hpp"
+#include "Defs.hpp"
+#include "JobsParam.hpp"
+#include "Jobs.hpp"
+#include "Log.hpp"
+#include "CalendarUpdateParams.hpp"
+#include "Calendar.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::posix_time;
+
+//#define DEBUG_TRAVERSER 1
+//#define DEBUG_POLL 1
+
+// ***********************************************************************
+// It was noticed that having a poll of 60 seconds was not very accurate
+// even when the server was not active, could be out by as much as 25 seconds
+// Hence we poll every second, and check it against the minute boundary
+// ************************************************************************
+
+NodeTreeTraverser::NodeTreeTraverser( Server* s,
+ boost::asio::io_service& io,
+ const ServerEnvironment& serverEnv)
+: server_( s ),
+ serverEnv_(serverEnv),
+ timer_( io, boost::posix_time::seconds( 0 ) ),
+ interval_(0,0,serverEnv_.submitJobsInterval(),0),
+ count_( 0 ),
+ firstTime_( true),
+ running_(false)
+{
+#ifdef DEBUG_TRAVERSER
+ std::cout << "NodeTreeTraverser::NodeTreeTraverser period = " << serverEnv_.submitJobsInterval() << "\n";
+#endif
+}
+
+NodeTreeTraverser::~NodeTreeTraverser() {
+#ifdef DEBUG_TRAVERSER
+ std::cout << "~NodeTreeTraverser::NodeTreeTraverser\n";
+#endif
+}
+
+void NodeTreeTraverser::start()
+{
+#ifdef DEBUG_TRAVERSER
+ {LogToCout toCoutAsWell;LOG(Log::DBG, "NodeTreeTraverser::start() server_state(" << SState::to_string(server_->state()) << ") running(" << running_ << ") count(" << count_ << ") firstTime_(" << firstTime_ << ")" );}
+#endif
+
+ if (!running_) {
+ count_ = 0;
+ running_ = true;
+ if (firstTime_) {
+ // If the server is stopped/started we want to avoid skewing the calendar, since each time
+ // we call traverse, the calendar is updated with the server poll. hence we must make sure
+ // we only start it once here
+ last_time_ = Calendar::second_clock_time();
+ next_poll_time_ = last_time_;
+ firstTime_ = false;
+
+ /// ==========================================================================
+ /// Make sure we *ALIGN* the poll period exactly *** to the minute*** boundary
+ /// ==========================================================================
+ if ( 60 == serverEnv_.submitJobsInterval() ) {
+
+ time_duration time_of_day = last_time_.time_of_day();
+ int seconds_to_minute_boundary = 60 - time_of_day.seconds();
+
+#ifdef DEBUG_TRAVERSER
+ std::cout << " NodeTreeTraverser::start: time_of_day(" << to_simple_string(time_of_day) << ") seconds_to_minute_boundary(" << seconds_to_minute_boundary << ")\n";
+#endif
+
+ if ( seconds_to_minute_boundary != 0) {
+
+#ifdef DEBUG_TRAVERSER
+ std::cout << " NodeTreeTraverser::start: Do an immediate job generation. Since we don't want to wait for minute boundary, when starting.\n";
+#endif
+
+ // Make sure subsequent polls are *ALIGNED* to minute boundary
+ next_poll_time_ = last_time_ + seconds(seconds_to_minute_boundary);
+
+ // ************************************************************************************************
+ // ** This relies on next_poll_time_ being set first, to ensure job generation does not take longer
+ // ************************************************************************************************
+ update_suite_calendar_and_traverse_node_tree(last_time_);
+
+ timer_.expires_from_now( boost::posix_time::seconds( 1 ) );
+
+#ifdef DEBUG_TRAVERSER
+ std::cout << " NodeTreeTraverser::start: next_poll_time_(" << to_simple_string(next_poll_time_) << ")\n";
+#endif
+ }
+ }
+#ifdef ECFLOW_MT
+ timer_.async_wait( server_->strand_.wrap( boost::bind( &NodeTreeTraverser::traverse, this, boost::asio::placeholders::error ) ) );
+#else
+ timer_.async_wait( server_->io_service_.wrap( boost::bind( &NodeTreeTraverser::traverse, this, boost::asio::placeholders::error ) ) );
+#endif
+ }
+ }
+}
+
+void NodeTreeTraverser::stop()
+{
+#ifdef DEBUG_TRAVERSER
+ {LogToCout toCoutAsWell; LOG(Log::DBG, " NodeTreeTraverser::stop() count(" << count_ << ")");}
+#endif
+
+ running_ = false;
+}
+
+void NodeTreeTraverser::terminate()
+{
+#ifdef DEBUG_TRAVERSER
+ {LogToCout toCoutAsWell; LOG(Log::DBG, " NodeTreeTraverser::terminate() count(" << count_ << ")");}
+#endif
+
+ timer_.cancel();
+}
+
+void NodeTreeTraverser::do_traverse()
+{
+ // since we poll every second, if less than next poll(every 60 seconds) continue.
+ ptime time_now = Calendar::second_clock_time();
+ if (time_now < next_poll_time_) {
+
+ // minimise the number of node tree traversal, to once every second, but only *IF* required
+ // Note: if we are a few seconds to the poll time, but job generation takes a while
+ // we can get warning about the interval took to long. See below:
+
+ // LOG(Log::DBG,"get_job_generation_count() = " << server_->get_job_generation_count());
+ if (server_->get_job_generation_count() > 0) {
+ traverse_node_tree_and_job_generate( time_now , false /* not in command context */);
+ }
+
+ start_timer(); // timer fires *EVERY* second
+ return;
+ }
+ // time_now >= next_poll_time_
+
+
+ // We have SOFT real time, we poll every second, BUT only update the suite calendar at the job submission
+ // interval. However we can not guarantee to hit exactly at the next poll time
+ // *** traverse node tree and increment next_poll_time_ ***
+ time_duration duration = time_now - last_time_;
+ int diff_from_last_time = duration.total_seconds();
+ int submitJobsIntervalInSeconds = serverEnv_.submitJobsInterval();
+#ifdef DEBUG_TRAVERSER
+ int real_diff = diff_from_last_time - submitJobsIntervalInSeconds;
+ std::stringstream ss;
+ ss << " NodeTreeTraverser::traverse() diff_from_last_time:" << diff_from_last_time << " running:" << running_ << " count:" << count_ << " real_diff:" << real_diff << " time_now:" << to_simple_string(time_now);
+ if ( diff_from_last_time == 0) ss << ": FIRST time: ";
+#endif
+
+ /// Update server stat's. ie records number of requests for each poll period
+ server_->update_stats(diff_from_last_time);
+
+ /// The poll times will *vary* since we are trying to keep up with the hard real time.
+ if ( diff_from_last_time > submitJobsIntervalInSeconds ) {
+
+ /// This will happen from time to time, hence only report, for real wayward times
+ int diff = diff_from_last_time - submitJobsIntervalInSeconds;
+ if (diff > (submitJobsIntervalInSeconds * 0.25)) {
+ LOG(Log::WAR, ": interval is (" << submitJobsIntervalInSeconds << " seconds) but took (" << diff_from_last_time << " seconds)" );
+ }
+ }
+
+
+
+ /// Remove any stale zombies
+ server_->zombie_ctrl().remove_stale_zombies(time_now);
+
+#ifdef DEBUG_TRAVERSER
+ time_duration traverse_duration = Calendar::second_clock_time() - time_now;
+ ss << " Traverse duration:" << traverse_duration.total_seconds();
+#endif
+
+
+ // We poll *EVERY second but update the next_poll_time_ to be consistent with the job submission interval
+ // Hence the next poll times *will* vary( SOFT REAL TIME ).
+ // Note: On server start, we modified the next_poll_time_ to hit the minute boundary.
+ //
+ // FIRST time_now(skip) time_now(traverse node tree)
+ // | | L | S
+ // V V------------------------| V-----------------|
+ // ==========0====================0====================0====================0====================0
+ // ^ ^ ^ ^ ^
+ // | | | | |
+ // last_time_ next_poll_time_ next_poll_time_ next_poll_time_ next_poll_time_
+ // next_poll_time_
+ // ^ ^
+ // | |
+ // last_time_ last_time_
+ // reset to previous next_poll_time_, to avoid yo-yoing, messages about poll being long/short
+ //
+ // Update next_poll_time_: WE *ONLY* get here if time_now >= next_poll_time
+
+ if (time_now > next_poll_time_) {
+
+ /// Continue updating next_poll_time_ by interval_ until it is greater time_now
+#ifdef DEBUG_TRAVERSER
+ { ss << ": Shorten the poll time : Current time(" << to_simple_string(time_now) << ") > current poll_time(" << to_simple_string(next_poll_time_) << ")";
+ time_duration diff = time_now - next_poll_time_;
+ ss << " by " << diff.total_seconds() << " seconds: "; }
+#endif
+
+ while (next_poll_time_ <= time_now) { next_poll_time_ += interval_;}
+ }
+ else {
+
+ /// Hit the poll time: Should get here when traverse called for the *FIRST* time ( since time_now == next_poll_time_)
+#ifdef DEBUG_TRAVERSER
+ ss << ": On poll time: ";
+#endif
+
+ next_poll_time_ += interval_;
+ }
+
+ // At begin time for very large suites, slow disk, and in test, during job generation we can miss the next poll time(i.e a,b)
+ // This means that on the next poll time because last_time was not updated, to be immediately
+ // behind the next poll time by 'interval_' seconds an erroneous report is logged about missing the poll time
+ //
+ // FIRST Time_now
+ // | |
+ // V a b c X
+ // ==========0====================0====================0====================0====================0
+ // ^ ^ ^ ^ ^
+ // | | | | |
+ // last_time_ next_poll_time_ next_poll_time_ next_poll_time_ next_poll_time_
+ //
+ // Hence we need to ensure that last_time is always less that next_poll_time_ by interval_
+ // In the diagram above missed poll time a and b, then we need to set last_time_ to 'c' and *NOT* 'a' | 'b'
+ last_time_ = next_poll_time_ - interval_;
+
+
+#ifdef DEBUG_TRAVERSER
+ { ss << " Next Poll at:" << to_simple_string(next_poll_time_);LogToCout toCoutAsWell; LOG(Log::DBG,ss.str()); }
+#endif
+
+
+ // Start node tree traversal.
+ // ************************************************************************************************
+ // ** This relies on next_poll_time_ being set first, to ensure job generation does not take longer
+ // ************************************************************************************************
+ update_suite_calendar_and_traverse_node_tree(time_now);
+
+ start_timer(); // timer fires *EVERY* second
+}
+
+void NodeTreeTraverser::start_timer()
+{
+ /// Appears that expires_from_now is more accurate then expires_at i.e timer_.expires_at( timer_.expires_at() + boost::posix_time::seconds( poll_at ) );
+ timer_.expires_from_now( boost::posix_time::seconds( 1 ) );
+#ifdef ECFLOW_MT
+ timer_.async_wait( server_->strand_.wrap( boost::bind( &NodeTreeTraverser::traverse,this,boost::asio::placeholders::error ) ) );
+#else
+ timer_.async_wait( server_->io_service_.wrap( boost::bind( &NodeTreeTraverser::traverse,this,boost::asio::placeholders::error ) ) );
+#endif
+}
+
+void NodeTreeTraverser::traverse(const boost::system::error_code& error )
+{
+ if (error == boost::asio::error::operation_aborted) {
+#ifdef DEBUG_TRAVERSER
+ { LogToCout toCoutAsWell; LOG(Log::DBG, "NodeTreeTraverser::traverse Timer was cancelled" ); }
+#endif
+ return;
+ }
+ else if (error) {
+ LogToCout toCoutAsWell;
+ std::string msg = "NodeTreeTraverser::traverse error: "; msg += error.message();
+ ecf::log(Log::ERR, msg);
+ return;
+ }
+
+ do_traverse();
+}
+
+
+void NodeTreeTraverser::update_suite_calendar_and_traverse_node_tree(const boost::posix_time::ptime& time_now)
+{
+ // *****************************************************************************
+ // JOB SUBMISSION SEEMS TO WORK BEST IF THE CALENDAR INCREMENT HAPPENS FIRST
+ // HOWEVER THIS MEANS WE MAY MISS THE VERY FIRST JOB SUBMISSION. ??
+ // Note: events,meters and task completion kick of another job submission
+ // There seems to be greater stability in terms of testing as it allows
+ // process to complete, before the calendar is incremented.
+ // *****************************************************************************
+ if ( server_->defs_ ) {
+
+ // This functions gets called every 60 seconds or so, update calendar && time
+ // dependent variables in case any jobs depend on them. By default the calendar
+ // update interval is the same as submitJobsInterval for non-real calendars,
+ // however for testing both real/non-real calendars the calendar increment can be
+ // changed to speed up calendar. This is done by setting the calendar increment
+ // on the suite(i.e in the defs file) which will the _override_ this setting.
+ //
+ // Additionally by passing in the flag running_, it allow suites which want to
+ // stop the calendar updates, when the server is stopped to do so.
+ // For real time calendars we make one system call here, instead of many times in each suite
+ //
+ // In the case where defs/node tree is suspended updateCalendar will continue
+ // to mark those time dep' are free, as free. This information is then used
+ // during the resume
+ ++count_;
+ CalendarUpdateParams calParams(time_now, interval_/* calendar increment */, running_ );
+ server_->defs_->updateCalendar( calParams );
+
+ traverse_node_tree_and_job_generate(time_now, false /* not in command context */);
+ }
+}
+
+void NodeTreeTraverser::traverse_node_tree_and_job_generate(
+ const boost::posix_time::ptime& start_time,
+ bool user_cmd_context) const
+{
+ // **************************************************************************************
+ // This can be called at the end of a user command(force,alter,requeue,etc),
+ // hence start_time may be >= poll_time, Note: for child command we just call
+ // increment_job_generation_count()
+ // **************************************************************************************
+
+ if ( running_ && server_->defs_) {
+#ifdef DEBUG_JOB_SUBMISSION
+ jobsParam.logDebugMessage(" from NodeTreeTraverser::traverse_node_tree_and_job_generate()");
+#endif
+
+ // ** In the *NON* command context, we should always have start_time < next_poll_time_
+ if (user_cmd_context && start_time >= next_poll_time_) {
+
+ //cout << "*****************************************************************************************************\n";
+ //cout << "user Command context " << cmd_context << " start_time: " << start_time << " >= " << " next_poll_time_: " << next_poll_time_ << "\n";
+ //cout << "*****************************************************************************************************\n";
+
+ server_->increment_job_generation_count();
+ return;
+ }
+
+ server_->reset_job_generation_count();
+
+ // Pass submit jobs interval, so that we can check jobs submission occurs within the allocated time.
+ // By default job generation is enabled, however for testing, allow job generation to be disabled.
+ JobsParam jobsParam(serverEnv_.submitJobsInterval(), serverEnv_.jobGeneration());
+
+ // If job generation takes longer than the time to *reach* next_poll_time_, then time out.
+ // Hence we start out with 60 seconds, and time for job generation should decrease. Until reset back to 60
+ // Should allow greater child communication.
+ // By setting set_next_poll_time, we enable timeout of job generation.
+ // ** IMPLIES => next_poll_time_ must be set first, before *THIS* function is called **
+ // Note: There are other place where we may not want to timeout job generation.
+ jobsParam.set_next_poll_time(next_poll_time_);
+
+ Jobs jobs(server_->defs_);
+ if (!jobs.generate(jobsParam)) { ecf::log(Log::ERR, jobsParam.getErrorMsg()); }
+ if (jobsParam.timed_out_of_job_generation()) {
+
+ // Implies we timed out, hence time_out_time >= next_poll_time_
+ const ptime& time_out_time = jobsParam.time_out_time();
+ // std::cout << "Job generation *timed* out: start time:" << start_time << " time_out_time:" << time_out_time << " poll_time:" << next_poll_time_ << "\n";
+
+ // It could be that we started job generation a few seconds before the poll time,
+ // Hence to avoid excessive warnings, Only warn if time_out_time > next_poll_time_ and forgive about 5 seconds
+ if (!time_out_time.is_special() && time_out_time > next_poll_time_ ) {
+ int leeway = ( serverEnv_.submitJobsInterval() == 60) ? 5 : 1;
+ time_duration duration = time_out_time - next_poll_time_;
+ if ( duration.total_seconds() >= leeway) {
+
+ std::stringstream ss;
+ ss << "Job generation *timed* out: start time:" << start_time << " time_out_time:" << time_out_time << " poll_time:" << next_poll_time_;
+ ecf::log(Log::WAR,ss.str());
+ }
+ }
+ }
+ }
+}
+
diff --git a/Server/src/NodeTreeTraverser.hpp b/Server/src/NodeTreeTraverser.hpp
new file mode 100644
index 0000000..b8b3fbe
--- /dev/null
+++ b/Server/src/NodeTreeTraverser.hpp
@@ -0,0 +1,86 @@
+#ifndef NODETREETRAVERSER_HPP_
+#define NODETREETRAVERSER_HPP_
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name : NodeTreeTraverser.cpp
+// Author : Avi
+// Revision : $Revision: #26 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+// This class will traverse the node tree periodically, It is tied to a server.
+// This implementation uses a strand to ensure sequential processing of the node dependency traversal
+// in the the presence of multiple threads, without the need of explicit locking. i.e mutex's
+//
+// For testing we make the distinction between the poll period, and calendar update interval
+// Some suites require a real time calendar. Hence we must make sure that
+// poll interval is in sync with real time.
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <boost/asio.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+class Server;
+class ServerEnvironment;
+
+class NodeTreeTraverser : private boost::noncopyable {
+public:
+ NodeTreeTraverser( Server* s, boost::asio::io_service& io, const ServerEnvironment& serverEnv);
+ ~NodeTreeTraverser();
+
+ /// If first time Starts traversing Node tree and resolving dependencies.
+ /// This essentially starts Jobs scheduling. Calling start more than once does nothing.
+ /// On subsequent calls to start resume is called. Which may cause immediate
+ /// job generation. (i.e for those nodes whose node are free of time dependencies)
+ /// Timer will be aligned to the minute boundary
+ void start();
+
+ /// Suspends job scheduling (for real time calendars/suite)
+ /// Shutdown & suspend (are very similar) shutdown operate at the top/level.
+ /// Both should have effect of stopping job submission and not the event loop
+ ///
+ /// During a system session, a node can be placed into suspend mode.
+ /// In suspend mode, no jobs are submitted. (**** However node which are
+ /// free to run are marked****).
+ ///
+ /// When the session is resumed, those node than were marked, have
+ /// the task's submitted. ( This means that job dependent on a time dependency
+ /// does not need to be held for the following day)
+ void stop();
+
+ /// terminate: This will cancel the timer and any pending async operation
+ /// If timer has already expired, then the handler function will be
+ /// passed an operation aborted error code.
+ /// Called when the server is exiting. We must be sure to cancel all
+ /// async handlers or the server, will not stop.
+ void terminate();
+
+ /// This can be called at the end of a *USER* command(force,alter,requeue,etc), hence time_now may be >= poll_time
+ /// If this is the case, we will defer job generation
+ void traverse_node_tree_and_job_generate(const boost::posix_time::ptime& time_now, bool user_cmd_context) const;
+
+private:
+ void traverse(const boost::system::error_code& error );
+ void do_traverse();
+ void start_timer();
+ void update_suite_calendar_and_traverse_node_tree(const boost::posix_time::ptime& time_now);
+
+ Server* server_;
+ const ServerEnvironment& serverEnv_;
+ boost::asio::deadline_timer timer_;
+ boost::posix_time::ptime last_time_; // ensure poll is in sync
+ boost::posix_time::ptime next_poll_time_; // Keep as sync as possible with hard real times
+ boost::posix_time::time_duration interval_; // Job submission interval
+ int count_;
+ bool firstTime_;
+ bool running_;
+};
+
+#endif
diff --git a/Server/src/Server.cpp b/Server/src/Server.cpp
new file mode 100644
index 0000000..6c11072
--- /dev/null
+++ b/Server/src/Server.cpp
@@ -0,0 +1,716 @@
+//============================================================================
+// Name : Server.cpp
+// Author : Avi
+// Revision : $Revision: #173 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Server
+//
+// The port numbers are divided into three ranges:
+// o the Well Known Ports, (require root permission) 0 -1023
+// o the Registered Ports, 1024-49151
+// o Dynamic and/or Private Ports. 49151-65535
+//============================================================================
+
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/bind.hpp>
+#include <iostream>
+
+#include "Server.hpp" // Must come before boost/serialization headers.
+ // defines ECFLOW_MT
+#include <boost/thread/thread.hpp> // needed for ECFLOW_MT and debug() to print thread ID
+#include "Defs.hpp"
+#include "Log.hpp"
+#include "System.hpp"
+#include "ServerEnvironment.hpp"
+#include "Ecf.hpp"
+#include "Calendar.hpp"
+#include "Version.hpp"
+#include "Str.hpp"
+
+using boost::asio::ip::tcp;
+namespace fs = boost::filesystem;
+
+using namespace std;
+using namespace ecf;
+
+
+/// Constructor opens the acceptor and starts waiting for the first incoming connection.
+Server::Server( ServerEnvironment& serverEnv ) :
+ io_service_(),
+ signals_(io_service_),
+ acceptor_(io_service_),
+#ifdef ECFLOW_MT
+ strand_(io_service_),
+ thread_pool_size_(serverEnv.threads()),
+ new_connection_(),
+#endif
+ defs_(Defs::create()), // ECFLOW-182
+ traverser_ (this, io_service_, serverEnv ),
+ checkPtSaver_(this, io_service_, &serverEnv ),
+ serverState_(SState::HALTED),
+ serverEnv_(serverEnv)
+{
+#ifdef ECFLOW_MT
+ std::cout << "Server: thread pool size = " << thread_pool_size_ << endl;
+#endif
+
+ if (serverEnv_.debug()) cout << "-->Server::server starting server on port "
+ << serverEnv.port()
+#ifdef ECFLOW_MT
+ << " thread pool size = " << thread_pool_size_
+#endif
+ << endl;
+
+ // Register to handle the signals.
+ // Support for emergency check pointing during system session.
+ signals_.add(SIGTERM);
+ signals_.async_wait(boost::bind(&Server::sigterm_signal_handler, this));
+
+
+ // Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR).
+ boost::asio::ip::tcp::endpoint endpoint(serverEnv.tcp_protocol(), serverEnv.port());
+ acceptor_.open(endpoint.protocol());
+ acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
+ acceptor_.bind(endpoint);
+ acceptor_.listen(); // address is use error, when it comes, bombs out here
+
+
+ // Update stats, this is returned via --stats command option
+ stats().host_ = serverEnv.hostPort().first;
+ stats().port_ = serverEnv.hostPort().second;
+ stats().job_sub_interval_ = serverEnv.submitJobsInterval();
+ stats().checkpt_interval_ = serverEnv.checkPtInterval();
+ stats().checkpt_save_time_alarm_ = serverEnv.checkpt_save_time_alarm();
+ stats().checkpt_mode_ = serverEnv.checkMode();
+ stats().up_since_ = to_simple_string(Calendar::second_clock_time());
+ stats().version_ = Version::description();
+ stats().status_ = static_cast<int>(serverState_);
+ stats().ECF_HOME_ = serverEnv.ecf_home();
+ stats().ECF_CHECK_ = serverEnv.checkPtFilename();
+ stats().ECF_LOG_ = Log::instance()->path();
+
+ // Update log file:
+ ecf::log(Log::MSG, "Server initial state is HALTED");
+
+ // The defs_ *MUST* be updated with the server state
+ // When we load from the check pt file we call update_defs_server_state();
+ if (!load_check_pt_file_on_startup()) {
+
+ // No check pt files loaded, update defs, with server state
+ update_defs_server_state(); // works on def_
+ }
+
+ /// Setup globals used to detect incremental changes to the definition
+ Ecf::set_server(true);
+
+ // Start an accept operation for a new connection.
+ start_accept();
+}
+
+Server::~Server()
+{
+ if (serverEnv_.debug()) cout << "<--Server::~server exiting server on port " << serverEnv_.port() << endl;
+
+ defs_.reset();
+
+#ifdef DEBUG
+ if ( defs_.use_count() != 0) {
+ cout << "Server::~server() defs_.use_count() = " << defs_.use_count() << " something is still hold onto the defs, asserting\n";
+ }
+#endif
+ assert(defs_.use_count() == 0);
+}
+
+void Server::run()
+{
+ // The io_service::run() call will block until all asynchronous operations
+ // have finished. While the server is running, there is always at least one
+ // asynchronous operation outstanding: the asynchronous accept call waiting
+ // for new incoming connections.
+
+#ifdef ECFLOW_MT
+ // Create a pool of threads to run all of the io_services.
+ std::vector<boost::shared_ptr<boost::thread> > threads;
+ for (std::size_t i = 0; i < thread_pool_size_; ++i)
+ {
+ boost::shared_ptr<boost::thread> thread(new boost::thread(
+ boost::bind(&boost::asio::io_service::run, &io_service_)));
+ threads.push_back(thread);
+ }
+ // Wait for all threads in the pool to exit.
+ for (std::size_t i = 0; i < threads.size(); ++i)
+ threads[i]->join();
+#else
+ io_service_.run();
+#endif
+}
+
+void Server::start_accept()
+{
+#ifdef ECFLOW_MT
+ if (serverEnv_.debug()) cout << boost::this_thread::get_id() << " Server::start_accept()" << endl;
+ new_connection_.reset(new CConnection(io_service_, this));
+ acceptor_.async_accept(new_connection_->socket(),
+ boost::bind(&Server::handle_accept, this,
+ boost::asio::placeholders::error));
+#else
+ if (serverEnv_.debug()) cout << " Server::start_accept()" << endl;
+ connection_ptr new_conn( new connection( io_service_ ) );
+ if (serverEnv_.allow_old_client_new_server() !=0 ) {
+ new_conn->allow_old_client_new_server(serverEnv_.allow_old_client_new_server());
+ }
+ acceptor_.async_accept( new_conn->socket(),
+ boost::bind( &Server::handle_accept, this,
+ boost::asio::placeholders::error,
+ new_conn ) );
+#endif
+}
+
+#ifdef ECFLOW_MT
+void Server::handle_accept(const boost::system::error_code& e)
+{
+ // Check whether the server was stopped by a signal before this completion
+ // handler had a chance to run.
+ if (!acceptor_.is_open()) {
+ if (serverEnv_.debug()) cout << boost::this_thread::get_id() << " Server::handle_accept: acceptor is closed, returning\n";
+ return;
+ }
+
+ if (!e) {
+ new_connection_->start();
+ }
+ else {
+ LogToCout toCoutAsWell;
+ LOG(Log::ERR, "Server::handle_accept error occurred : " << e.message());
+ }
+
+ start_accept();
+}
+#else
+void Server::handle_accept( const boost::system::error_code& e, connection_ptr conn )
+{
+ // Check whether the server was stopped by a signal before this completion
+ // handler had a chance to run.
+ if (!acceptor_.is_open()) {
+ if (serverEnv_.debug()) cout << " Server::handle_accept: acceptor is closed, returning" << endl;
+ return;
+ }
+
+ if ( !e ) {
+ // Read and interpret message from the client
+ if (serverEnv_.debug()) cout << " Server::handle_accept" << endl;
+
+ // Successfully accepted a new connection. Determine what the
+ // client sent to us. The connection::async_read() function will
+ // automatically. serialise the inbound_request_ data structure for us.
+ conn->async_read( inbound_request_,
+ boost::bind( &Server::handle_read, this,
+ boost::asio::placeholders::error,conn ) );
+ }
+ else {
+ if (serverEnv_.debug()) cout << " Server::handle_accept " << e.message() << endl;
+ if (e != boost::asio::error::operation_aborted) {
+ // An error occurred. Log it
+ LogToCout toCoutAsWell;
+ LOG(Log::ERR, " Server::handle_accept error occurred " << e.message());
+ }
+ }
+
+ // Start an accept operation for a new connection.
+ // *NOTE* previously we had *ONLY* called this if there was no errors
+ // However this would means that server would run out work.
+ // When there were errors.!
+ // Moved here to follow the examples used in ASIO.
+ // However can this get into an infinite loop ???
+ start_accept();
+}
+
+void Server::handle_read( const boost::system::error_code& e,connection_ptr conn )
+{
+ /// Handle completion of a write operation.
+ // **********************************************************************************
+ // This function *must* finish with write, otherwise it ends up being called recursively
+ // ***********************************************************************************
+ if ( !e ) {
+
+ // See what kind of message we got from the client
+ if (serverEnv_.debug()) std::cout << " Server::handle_read : client request " << inbound_request_ << endl;
+
+ try {
+ // Service the in bound request, handling the request will populate the outbound_response_
+ // Note:: Handle request will first authenticate
+ outbound_response_.set_cmd( inbound_request_.handleRequest( this ) );
+ }
+ catch (exception& e) {
+ outbound_response_.set_cmd( PreAllocatedReply::error_cmd( e.what() ));
+ }
+
+ // Release >= 4.0.6 More reliable to always respond back. Get more accurate logs
+ // However allow old/new client to deal with shutdown of socket:
+ // See: void Client::handle_read() See: ECFLOW-157, ECFLOW-169
+ //
+ // if (!serverEnv_.reply_back_if_ok()) {
+ //
+ // if (!inbound_request_.terminateRequest() && outbound_response_.get_cmd()->isOkCmd()) {
+ //
+ // // cleanly close down the connection
+ // if (serverEnv_.debug()) cout << " Server::handle_read: NOT replying, since request is OK" << endl;
+ //
+ // if (shutdown_socket(conn,"Server::handle_read:")) conn->socket().close();
+ // return;
+ // }
+ // }
+
+ // *Reply* back to the client:
+ conn->async_write( outbound_response_,
+ boost::bind(&Server::handle_write,
+ this,
+ boost::asio::placeholders::error,
+ conn ) );
+ }
+ else {
+ // An error occurred.
+ // o/ If client has been killed/disconnected/timed out
+ // Server::handle_read : End of file
+ //
+ // o/ If a *new* client talks to an *old* server, with an unrecognised request/command
+ // we will see:
+ // Connection::handle_read_data boost::archive::archive_exception unregistered class
+ // Server::handle_read : Invalid argument
+ LogToCout toCoutAsWell;
+ LOG(Log::ERR, "Server::handle_read: " << e.message());
+ }
+}
+
+void Server::handle_write( const boost::system::error_code& e, connection_ptr conn )
+{
+ // Handle completion of a write operation.
+ // Nothing to do. The socket will be closed automatically when the last
+ // reference to the connection object goes away.
+ if (serverEnv_.debug())
+ cout << " Server::handle_write: client request " << inbound_request_ << " replying with " << outbound_response_ << endl;
+
+ if (e) {
+ ecf::LogToCout logToCout;
+ std::stringstream ss; ss << "Server::handle_write: " << e.message() << " : for request " << inbound_request_;
+ log(Log::ERR,ss.str());
+ return;
+ }
+
+ (void)shutdown_socket(conn,"Server::handle_write:");
+
+ // If asked to terminate we do it here rather than in handle_read.
+ // So that we have responded to the client.
+ // *HOWEVER* only do this if the request was successful.
+ // we do this by checking that the out bound response was ok
+ // i.e a read only user should not be allowed to terminate server.
+ if (inbound_request_.terminateRequest() && outbound_response_.get_cmd()->isOkCmd()) {
+ if (serverEnv_.debug()) cout << " <--Server::handle_write exiting server via terminate() port " << serverEnv_.port() << endl;
+ terminate();
+ }
+}
+
+bool Server::shutdown_socket(connection_ptr conn, const std::string& msg) const
+{
+ // For portable behaviour with respect to graceful closure of a connected socket,
+ // call shutdown() before closing the socket.
+ //
+ // conn->socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both)
+ // This *CAN* throw an error if the client side socket is not connected. client may have been killed *OR* timed out
+ // i.e "shutdown: Transport endpoint is not connected"
+ //
+ // Since this can happen, instead of throwing, we use non-throwing version & just report it
+ boost::system::error_code ec;
+ conn->socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both,ec);
+ if (ec) {
+ ecf::LogToCout logToCout;
+ std::stringstream ss; ss << msg << " socket shutdown both failed: " << ec.message() << " : for request " << inbound_request_;
+ log(Log::ERR,ss.str());
+ return false;
+ }
+ return true;
+}
+
+#endif
+
+
+void Server::terminate()
+{
+ // The server is terminated by cancelling all outstanding asynchronous
+ // operations. Once all operations have finished the io_service::run() call will exit.
+ if (serverEnv_.debug()) cout << " Server::terminate(): posting call to Server::handle_terminate" << endl;
+
+ // Post a call to the stop function so that Server::stop() is safe to call from any thread.
+ io_service_.post(boost::bind(&Server::handle_terminate, this));
+}
+
+void Server::handle_terminate()
+{
+ if (serverEnv_.debug()) cout << boost::this_thread::get_id() << " Server::handle_terminate() : cancelling checkpt and traverser timers, and signals" << endl;
+
+ // Cancel signal
+ signals_.clear();
+ signals_.cancel();
+
+ // Cancel async timers for check pointing and traversal
+ traverser_.terminate();
+ checkPtSaver_.terminate();
+
+ acceptor_.close();
+
+ // Stop the io_service object's event processing loop. Will cause run to return immediately
+ io_service_.stop();
+}
+
+// ============================== other privates ===========================================
+
+bool Server::load_check_pt_file_on_startup()
+{
+ // On start up we want different behaviour.
+ // If check pt file exists and we can't load then we want to exit
+ // This avoids the server from overwriting the check point file
+ // Which may be from a different version. let the user handle it.
+ LogToCout logToCout;
+ bool checkpt_failed = false;
+ if (restore_from_checkpt(serverEnv_.checkPtFilename(),checkpt_failed)) {
+ return true;
+ }
+ bool backup_checkpt_failed = false;
+ if (restore_from_checkpt(serverEnv_.oldCheckPtFilename(),backup_checkpt_failed)) {
+ return true;
+ }
+
+ if (backup_checkpt_failed && !fs::exists(serverEnv_.checkPtFilename())) {
+ throw std::runtime_error("Can not start server, please handle the backup checkpoint file first");
+ }
+
+ if (checkpt_failed && !fs::exists(serverEnv_.oldCheckPtFilename())) {
+ throw std::runtime_error("Can not start server, please handle the checkpoint file first");
+ }
+ return false;
+}
+
+void Server::loadCheckPtFile()
+{
+ // if the check point file starts with an absolute file load that first
+ // otherwise check in ECF_HOME then load it. Repeat for back up check point file
+ // The server environment has already asserted that we can *NOT* have an empty check point file
+ bool ignore;
+ if (restore_from_checkpt(serverEnv_.checkPtFilename(),ignore)) {
+ return;
+ }
+
+ if (restore_from_checkpt(serverEnv_.oldCheckPtFilename(),ignore)) {
+ return;
+ }
+}
+
+bool Server::restore_from_checkpt(const std::string& filename,bool& failed)
+{
+ // cout << "Server::restore_from_checkpt " << filename;
+ failed = false;
+ if (fs::exists(filename)) {
+ // cout << " file exists\n";
+ LOG(Log::MSG, "Loading check point file " << filename << " port = " << serverEnv_.port());
+
+ try {
+ defs_->restore_from_checkpt(filename); // this can throw
+ update_defs_server_state(); // works on def_
+ //cout << "Server::restore_from_checkpt SUCCEDED found " << defs_->suiteVec().size() << " suites\n";
+ return true;
+ }
+ catch (exception& e) {
+ LOG(Log::ERR, "Failed to load check point file " << filename << ", because: " << e.what());
+ failed = true;
+ }
+ }
+// else {
+// cout << " does *not* exist\n";
+// }
+ return false;
+}
+
+void Server::update_defs_server_state()
+{
+ /// The Job submission interval, and host port are not persisted, on the DEFS
+ /// Hence when restoring from a checkpoint file, Be sure to update server state
+
+ // Do any *one* time setup on the defs
+
+ // Set the server environment *ON* the defs, so that generate variables can be created.
+ // gets the environment as read in by the server, and make available for defs
+ // ECF_HOME .
+ // ECF_CHECK ecf.check
+ // ECF_CHECKOLD ecf.check.b
+ std::vector<std::pair<std::string,std::string> > envVec;
+ serverEnv_.variables(envVec);
+ defs_->set_server().add_or_update_server_variables(envVec);
+
+ defs_->set_server().hostPort( hostPort() );
+ defs_->set_server().set_state( serverState_ );
+
+ // let the defs store the job submission interval, & whether we want job generation.testing can disable this
+ defs_->set_server().jobSubmissionInterval( serverEnv_.submitJobsInterval() );
+ defs_->set_server().jobGeneration( serverEnv_.jobGeneration() );
+ LOG_ASSERT( defs_->server().jobSubmissionInterval() != 0 ,"");
+
+ /// System needs defs to handle process that have died, and need to flagged as aborted
+ ecf::System::instance()->setDefs(defs_);
+}
+
+void Server::set_server_state(SState::State ss)
+{
+ serverState_ = ss;
+ stats().status_ = static_cast<int>(serverState_);
+ defs_->set_server().set_state( serverState_ );
+}
+
+
+/// ======================================================================================
+/// AbstractServer function.
+/// ======================================================================================
+
+std::pair<std::string,std::string> Server::hostPort() const
+{
+ return serverEnv_.hostPort();
+}
+
+void Server::updateDefs( defs_ptr defs, bool force)
+{
+ if (serverEnv_.debug()) std::cout << " Server::updateDefs: Loading new suites" << endl;
+
+ // After the absorb, input defs will be left with NO suites.
+ defs_->absorb(defs.get(),force);
+
+ defs_->set_most_significant_state();
+ LOG_ASSERT( defs_->server().jobSubmissionInterval() != 0 ,"");
+}
+
+void Server::clear_defs()
+{
+ if (serverEnv_.debug()) cout << " Server::clear_defs()" << endl;
+
+ defs_->clear();
+}
+
+void Server::checkPtDefs(ecf::CheckPt::Mode m, int check_pt_interval, int check_pt_save_time_alarm)
+{
+ if (serverEnv_.debug())
+ cout << " Server::checkPtDefs() mode(" << m << ") check_pt_interval(" << check_pt_interval << ") check_pt_save_time_alarm(" << check_pt_save_time_alarm << ")" << endl;
+
+ if (m == ecf::CheckPt::UNDEFINED && check_pt_interval == 0 && check_pt_save_time_alarm == 0) {
+ checkPtSaver_.explicitSave(); // will always save
+ }
+ else {
+ if ( m != ecf::CheckPt::UNDEFINED ) {
+ serverEnv_.set_check_mode( m );
+ stats().checkpt_mode_ = serverEnv_.checkMode();
+ }
+ if ( check_pt_interval > 0) {
+ serverEnv_.set_checkpt_interval( check_pt_interval );
+ stats().checkpt_interval_ = check_pt_interval;
+ }
+ if (check_pt_save_time_alarm > 0 ) {
+ serverEnv_.set_checkpt_save_time_alarm( check_pt_save_time_alarm );
+ stats().checkpt_save_time_alarm_ = check_pt_save_time_alarm;
+ }
+ }
+}
+
+void Server::restore_defs_from_checkpt()
+{
+ if (serverEnv_.debug()) cout << " Server::restore_defs_from_checkpt()" << endl;
+
+ if (serverState_ != SState::HALTED ) {
+ throw std::runtime_error( "Can not restore from checkpt the server must be halted first");
+ }
+
+ if (!defs_->suiteVec().empty()) {
+ // suites must be deleted manually first
+ throw std::runtime_error( "Can not restore from checkpt the server suites must be deleted first");
+ }
+
+ loadCheckPtFile();
+}
+
+void Server::nodeTreeStateChanged()
+{
+ if (serverEnv_.debug()) cout << " Server::nodeTreeStateChanged()" << endl;
+
+ // will only actually save if configuration allows it
+ checkPtSaver_.saveIfAllowed();
+}
+
+bool Server::allowTaskCommunication() const
+{
+ return (serverState_ != SState::HALTED) ? true : false;
+}
+
+
+void Server::shutdown()
+{
+ /// User Request Task Request Job Scheduling Check-pointing
+ /// RUNNING yes yes yes yes
+ /// SHUTDOWN yes yes no yes
+ /// HALTED yes no no no
+ if (serverEnv_.debug()) cout << " Server::shutdown. Stop Scheduling new jobs only" << endl;
+
+ // Stop server from creating new jobs. Don't stop the checkPtSaver_ since
+ // the jobs communication with server can still change state. Which we want
+ // to check point.
+ traverser_.stop();
+
+ // Continue check pointing since, we allow tasks communication. This can change node
+ // tree state. Which we *must* be able to checkpoint.
+ // If we go from HALTED --> SHUTDOWN, then check pointing needs to be enabled
+ checkPtSaver_.start();
+
+ // Will update defs as well to stop job scheduling
+ set_server_state(SState::SHUTDOWN);
+}
+
+void Server::halted()
+{
+ /// User Request Task Request Job Scheduling Check-pointing
+ /// RUNNING yes yes yes yes
+ /// SHUTDOWN yes yes no yes
+ /// HALTED yes no no no
+ if (serverEnv_.debug()) cout << " Server::halted. Stop Scheduling new jobs *and* block task communication. Stop check pointing. Only accept user request" << endl;
+
+ // Stop server from creating new jobs. i.e Job scheduling.
+ traverser_.stop();
+
+ // *** CRITICAL*** when the server is halted, we ***MUST NOT*** do any further check pointing
+ // In a typical operational scenario where we have a home, and backup servers.
+ // The checkpoint file is copied to the backup servers periodically (via a task)
+ // hence we want to preserve the state of the last checkpoint.
+ // Added after discussion with Axel.
+ checkPtSaver_.stop();
+
+ // Stop the task communication with server. Hence nodes can be stuck
+ // in submitted/active states. Task based command will continue attempting,
+ // communication with the server for up to 24hrs.
+ // Will update defs as well to stop job scheduling
+ set_server_state(SState::HALTED);
+}
+
+void Server::restart()
+{
+ /// User Request Task Request Job Scheduling Check-pointing
+ /// RUNNING yes yes yes yes
+ /// SHUTDOWN yes yes no yes
+ /// HALTED yes no no no
+ if (serverEnv_.debug()) std::cout << " Server::restart" << endl;
+
+ // The server state *MUST* be set, *before* traverser_.start(), since that can kick off job traversal.
+ // Job Scheduling can only be done under RUNNING state, hence must be before traverser_.start();
+ //
+ // If we placed set_server_state(SState::RUNNING); after we can miss time slots
+ // See:: SUP 571- Time dependency after halt/checkpoint
+ set_server_state(SState::RUNNING);
+
+ traverser_.start();
+ checkPtSaver_.start();
+}
+
+void Server::traverse_node_tree_and_job_generate(const boost::posix_time::ptime& time_now,bool user_cmd_context ) const
+{
+ traverser_.traverse_node_tree_and_job_generate(time_now, user_cmd_context);
+}
+
+bool Server::reloadWhiteListFile(std::string& errorMsg)
+{
+ if (serverEnv_.debug()) cout << " Server::reloadWhiteListFile" << endl;
+
+ return serverEnv_.reloadWhiteListFile(errorMsg);
+}
+
+bool Server::authenticateReadAccess(const std::string& user)
+{
+ return serverEnv_.authenticateReadAccess(user);
+}
+
+bool Server::authenticateWriteAccess(const std::string& user )
+{
+ return serverEnv_.authenticateWriteAccess(user);
+}
+
+bool Server::lock(const std::string& user)
+{
+ if (serverEnv_.debug()) std::cout << " Server::lock " << user << endl;
+
+ if (userWhoHasLock_.empty()) {
+ userWhoHasLock_ = user;
+ stats().locked_by_user_ = user;
+ shutdown();
+ return true;
+ }
+ else if ( userWhoHasLock_ == user && serverState_ == SState::SHUTDOWN ) {
+ // Same user attempting multiple locks
+ return true;
+ }
+ return false;
+}
+void Server::unlock()
+{
+ if (serverEnv_.debug()) std::cout << " Server::unlock " << userWhoHasLock_ << endl;
+
+ userWhoHasLock_.clear();
+ stats().locked_by_user_.clear();
+ if ( serverState_ == SState::SHUTDOWN ) restart();
+}
+const std::string& Server::lockedUser() const
+{
+ return userWhoHasLock_;
+}
+
+
+int Server::poll_interval() const
+{
+ return serverEnv_.submitJobsInterval();
+}
+
+void Server::debug_server_on()
+{
+ serverEnv_.set_debug(true);
+ std::cout << "\nEnable DEBUG, start with DUMP of server environment:\n\n";
+ std::cout << serverEnv_.dump() << endl;
+}
+
+void Server::debug_server_off()
+{
+ serverEnv_.set_debug(false);
+}
+
+bool Server::debug() const
+{
+ return serverEnv_.debug();
+}
+
+void Server::sigterm_signal_handler()
+{
+ if (io_service_.stopped()) {
+ if (serverEnv_.debug()) cout << "-->Server::sigterm_signal_handler(): io_service is stopped returning " << endl;
+ return;
+ }
+
+ if (serverEnv_.debug()) cout << "Server::sigterm_signal_handler(): Received SIGTERM : starting check pointing" << endl;
+ ecf::log(Log::MSG,"Server::sigterm_signal_handler(): Received SIGTERM : starting check pointing");
+
+ checkPtDefs();
+
+ ecf::log(Log::MSG,"Server::sigterm_signal_handler(): finished check pointing");
+ if (serverEnv_.debug()) cout << "Server::sigterm_signal_handler(): finished check pointing" << endl;
+
+ // We need re-wait each time signal handler is called
+ signals_.async_wait(boost::bind(&Server::sigterm_signal_handler, this));
+}
diff --git a/Server/src/Server.hpp b/Server/src/Server.hpp
new file mode 100644
index 0000000..a1361e6
--- /dev/null
+++ b/Server/src/Server.hpp
@@ -0,0 +1,159 @@
+#ifndef SERVER_HPP_
+#define SERVER_HPP_
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name : Server.cpp
+// Author : Avi
+// Revision : $Revision: #62 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : ECFLOW Server. Based on ASIO
+//
+// The port numbers are divided into three ranges:
+// o the Well Known Ports, (require root permission) 0 -1023
+// o the Registered Ports, 1024-49151
+// o Dynamic and/or Private Ports. 49151-65535
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <memory>
+#include <boost/asio.hpp>
+#include <boost/shared_ptr.hpp>
+
+// ECFLOW_MT See doc/multi-threaded-server.tar/ddoc
+//#define ECFLOW_MT 1
+#ifdef ECFLOW_MT
+#include "CConnection.hpp" // Must come before boost/serialisation headers.
+#else
+#include "Connection.hpp" // Must come before boost/serialisation headers.
+#include "ClientToServerRequest.hpp"
+#include "ServerToClientResponse.hpp"
+#endif
+
+#include "NodeTreeTraverser.hpp"
+#include "CheckPtSaver.hpp"
+#include "AbstractServer.hpp"
+
+class ServerEnvironment;
+
+
+class Server : public AbstractServer {
+public:
+ /// Constructor opens the acceptor and starts waiting for the first incoming
+ /// connection.
+ Server(ServerEnvironment&);
+ virtual ~Server();
+
+ /// Start the server
+ /// The Server::run/io_service::run() call will block until all asynchronous operations
+ /// have finished. While the server is running, there is always at least one
+ /// asynchronous operation outstanding: the asynchronous accept call waiting
+ /// for new incoming connections.
+ void run();
+
+ /// Terminate the server gracefully. Need to cancel all timers, close all sockets
+ /// Server will hang if there are any pending async handlers
+ void terminate();
+
+private:
+
+#ifdef ECFLOW_MT
+ /// Handle completion of a accept operation.
+ void handle_accept(const boost::system::error_code& e);
+#else
+ /// Handle completion of a accept operation.
+ void handle_accept(const boost::system::error_code& e, connection_ptr conn);
+
+ /// Handle completion of a write operation.
+ void handle_write(const boost::system::error_code& e, connection_ptr conn);
+
+ /// Handle completion of a read operation.
+ void handle_read(const boost::system::error_code& e, connection_ptr conn);
+#endif
+
+ void handle_terminate();
+ void start_accept();
+ bool shutdown_socket(connection_ptr conn, const std::string& msg) const;
+
+private:
+
+ // abort server if check pt files exist, but can't be loaded
+ bool load_check_pt_file_on_startup();
+ void loadCheckPtFile();
+ bool restore_from_checkpt(const std::string& filename, bool& failed);
+ void update_defs_server_state();
+ void set_server_state(SState::State);
+
+protected: // Allow test to override
+
+ /// AbstractServer functions
+ virtual SState::State state() const { return serverState_; }
+ virtual std::pair<std::string,std::string> hostPort() const;
+ virtual defs_ptr defs() const { return defs_;}
+ virtual void updateDefs(defs_ptr,bool force);
+ virtual void clear_defs();
+ virtual void checkPtDefs(ecf::CheckPt::Mode m = ecf::CheckPt::UNDEFINED,
+ int check_pt_interval = 0,
+ int check_pt_save_time_alarm = 0);
+ virtual void restore_defs_from_checkpt();
+ virtual void nodeTreeStateChanged();
+ virtual bool allowTaskCommunication() const;
+ virtual void shutdown();
+ virtual void halted();
+ virtual void restart();
+ virtual bool reloadWhiteListFile(std::string& errorMsg);
+ virtual bool authenticateReadAccess(const std::string& user);
+ virtual bool authenticateWriteAccess(const std::string& user);
+ virtual bool lock(const std::string& user);
+ virtual void unlock();
+ virtual const std::string& lockedUser() const;
+ virtual void traverse_node_tree_and_job_generate(const boost::posix_time::ptime& time_now, bool user_cmd_context) const;
+ virtual int poll_interval() const;
+ virtual void debug_server_on();
+ virtual void debug_server_off();
+ virtual bool debug() const;
+
+ // used in signal, for emergency check point during system session
+ void sigterm_signal_handler();
+
+private:
+
+ /// The io_service used to perform asynchronous operations.
+ boost::asio::io_service io_service_;
+
+ /// The signal_set is used to register for automatic check pointing
+ boost::asio::signal_set signals_;
+
+ /// The acceptor object used to accept incoming socket connections.
+ boost::asio::ip::tcp::acceptor acceptor_;
+
+#ifdef ECFLOW_MT
+ /// Strand to ensure the connection's handlers are not called concurrently.
+ boost::asio::io_service::strand strand_;
+ size_t thread_pool_size_;
+ CConnection_ptr new_connection_;
+ friend class CConnection;
+#else
+ /// The data, typically loaded once, and then sent to many clients
+ ClientToServerRequest inbound_request_;
+ ServerToClientResponse outbound_response_;
+#endif
+
+ defs_ptr defs_; // shared because is deleted in Test, and used in System::instance()
+ NodeTreeTraverser traverser_;
+ friend class NodeTreeTraverser;
+
+ CheckPtSaver checkPtSaver_;
+ friend class CheckPtSaver;
+
+ SState::State serverState_;
+ ServerEnvironment& serverEnv_;
+ std::string userWhoHasLock_;
+};
+
+#endif
diff --git a/Server/src/ServerEnvironment.cpp b/Server/src/ServerEnvironment.cpp
new file mode 100644
index 0000000..fa24368
--- /dev/null
+++ b/Server/src/ServerEnvironment.cpp
@@ -0,0 +1,579 @@
+//============================================================================
+// Name : ServerEnvironment
+// Author : Avi
+// Revision : $Revision: #95 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//
+//============================================================================
+
+#include <sys/types.h> // for getpid
+#include <unistd.h> // for getpid
+#include <stdlib.h> // for getenv()
+
+#include <iostream>
+#include <fstream>
+#include <iterator>
+
+#include <boost/program_options.hpp>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/lexical_cast.hpp>
+#ifdef ECFLOW_MT
+#include <boost/thread/thread.hpp> // needed for ECFLOW_MT and debug() to print thread ID
+#endif
+
+#include "ServerEnvironment.hpp"
+#include "ServerOptions.hpp"
+#include "Log.hpp"
+#include "System.hpp"
+#include "Str.hpp"
+#include "Ecf.hpp"
+#include "Version.hpp"
+#include "Calendar.hpp"
+#include "File.hpp"
+#include "boost_archive.hpp"
+#include "JobProfiler.hpp"
+
+using namespace ecf;
+using namespace std;
+using namespace boost;
+namespace po = boost::program_options;
+namespace fs = boost::filesystem;
+
+static std::string the_check_mode(ecf::CheckPt::Mode mode)
+{
+ switch (mode) {
+ case ecf::CheckPt::NEVER: return "CHECK_NEVER"; break;
+ case ecf::CheckPt::ON_TIME: return "CHECK_ON_TIME"; break;
+ case ecf::CheckPt::ALWAYS: return "CHECK_ALWAYS"; break;
+ case ecf::CheckPt::UNDEFINED: return "UNDEFINED"; break;
+ }
+ cout << "ServerEnvironment.cpp theCheckMode: assert failed\n";
+ assert(false);
+ return std::string();
+}
+
+// This can be overridden by calling "server --ecfinterval 3" for test purposes
+const int defaultSubmitJobsInterval = 60;
+
+////////////////////////////////////////////////////////////////////////////////////////////
+// class ServerEnvironment:
+///////////////////////////////////////////////////////////////////////////////////////////
+
+ServerEnvironment::ServerEnvironment( int argc, char* argv[])
+: serverHost_(host_name_.name()),
+ serverPort_(0),
+ checkPtInterval_(0),
+ checkpt_save_time_alarm_(CheckPt::default_save_time_alarm()),
+ submitJobsInterval_(defaultSubmitJobsInterval),
+#ifdef ECFLOW_MT
+ threads_(boost::thread::hardware_concurrency()),
+#endif
+ jobGeneration_(true),
+ debug_(false),
+ help_option_(false),
+ version_option_(false),
+ allow_old_client_new_server_(0),
+ checkMode_(ecf::CheckPt::ON_TIME),
+ tcp_protocol_(boost::asio::ip::tcp::v4())
+{
+ init(argc,argv,"server_environment.cfg");
+}
+
+// This is ONLY used in test
+ServerEnvironment::ServerEnvironment(int argc, char* argv[], const std::string& path_to_config_file)
+: serverHost_(host_name_.name()),
+ serverPort_(0),
+ checkPtInterval_(0),
+ checkpt_save_time_alarm_(CheckPt::default_save_time_alarm()),
+ submitJobsInterval_(defaultSubmitJobsInterval),
+#ifdef ECFLOW_MT
+ threads_(boost::thread::hardware_concurrency()),
+#endif
+ jobGeneration_(true),
+ debug_(false),
+ help_option_(false),
+ version_option_(false),
+ allow_old_client_new_server_(0),
+ checkMode_(ecf::CheckPt::ON_TIME),
+ tcp_protocol_(boost::asio::ip::tcp::v4())
+{
+ init(argc,argv,path_to_config_file);
+}
+
+void ServerEnvironment::init(int argc, char* argv[], const std::string& path_to_config_file)
+{
+ std::string log_file_name;
+ try {
+ read_config_file(log_file_name,path_to_config_file);
+ read_environment_variables(log_file_name); // overrides any settings in the config file
+ }
+ catch ( std::exception& e) {
+ std::string msg = "Exception in ServerEnvironment::ServerEnvironment() : ";
+ std::string exception_msg = e.what();
+ // On ecgate, wrong locale, causes an exception where msg is empty
+ if (exception_msg.empty()) msg += "Invalid locale? Check locale using 'locale -a', then export/set LANG environment";
+ else msg += e.what();
+ throw ServerEnvironmentException(msg);
+ }
+
+ // get server process id. This may be visualised in xecf. makes it easier to kill server
+ try { ecf_pid_ = boost::lexical_cast<std::string>(getpid()); }
+ catch (boost::bad_lexical_cast& e) {
+ throw ServerEnvironmentException("ServerEnvironment::ServerEnvironment:: Could not convert PID to a string\n");
+ }
+ // std::cout << "PID = " << ecf_pid_ << "\n";
+
+
+ // The options(argc/argv) must be read after the environment, since they override everything else
+ ServerOptions options(argc,argv,this);
+ help_option_ = options.help_option();
+ if (help_option_) return; // User is printing the help
+ version_option_ = options.version_option();
+ if (version_option_) return; // User is printing the version
+
+
+ /// Config, Environment, or Options may have updated port, update port dependent file names
+ /// If we have default names make unique, by prefixing host and port
+ assert(!ecf_checkpt_file_.empty()); // expect name of form "ecf.check"
+ assert(!ecf_backup_checkpt_file_.empty()); // expect name of form "ecf.check.b"
+ assert(!log_file_name.empty()); // expect name of form "ecf.log"
+ assert(!ecf_white_list_file_.empty()); // expect name of form "ecf.lists"
+ std::string port = boost::lexical_cast<std::string>(serverPort_);
+
+ // If path is absolute leave as is
+ if (ecf_checkpt_file_ == Ecf::CHECKPT())
+ ecf_checkpt_file_ = host_name_.prefix_host_and_port(port,ecf_checkpt_file_);
+ if (ecf_checkpt_file_[0] != '/') {
+ // Prepend with ECF_HOME
+ std::string check_pt = ecf_home();
+ check_pt += Str::PATH_SEPERATOR();
+ check_pt += ecf_checkpt_file_;
+ ecf_checkpt_file_ = check_pt;
+ }
+
+ // If path is absolute leave as is
+ if (ecf_backup_checkpt_file_ == Ecf::BACKUP_CHECKPT())
+ ecf_backup_checkpt_file_ = host_name_.prefix_host_and_port(port,ecf_backup_checkpt_file_);
+ if (ecf_backup_checkpt_file_[0] != '/') {
+ std::string check_pt = ecf_home();
+ check_pt += Str::PATH_SEPERATOR();
+ check_pt += ecf_backup_checkpt_file_;
+ ecf_backup_checkpt_file_ = check_pt;
+ }
+
+ if (ecf_white_list_file_ == Str::WHITE_LIST_FILE())
+ ecf_white_list_file_ = host_name_.prefix_host_and_port(port,ecf_white_list_file_);
+
+ // Change directory to ECF_HOME and check thats its accessible
+ change_dir_to_ecf_home_and_check_accesibility();
+
+
+ // LOG FILE ================================================================================
+ if (log_file_name == Ecf::LOG_FILE())
+ log_file_name = host_name_.prefix_host_and_port(port,log_file_name);
+
+ // Create the Log file. The log file is obtained from the environment. Hence **must** be done last.
+ Log::create(log_file_name);
+
+
+ // Init log file:
+ LOG(Log::MSG, Version::description() );
+ LOG(Log::MSG, "Started at " << to_simple_string(Calendar::second_clock_time()) << " universal time");
+ if ( tcp_protocol_.family() == 2 /*PF_INET*/)
+ LOG(Log::MSG, "Host(" << hostPort().first << ") Port(" << hostPort().second << ") using TCP/IP v4");
+ else
+ LOG(Log::MSG, "Host(" << hostPort().first << ") Port(" << hostPort().second << ") using TCP/IP v6");
+ LOG(Log::MSG, "ECF_HOME " << ecf_home());
+ LOG(Log::MSG, "Job scheduling interval: " << submitJobsInterval_);
+ if (allow_old_client_new_server_ != 0) {
+ LOG(Log::MSG, "ECF_ALLOW_OLD_CLIENT_NEW_SERVER enabled: " << allow_old_client_new_server_);
+ }
+}
+
+ServerEnvironment::~ServerEnvironment()
+{
+ /// Destroy singleton to avoid valgrind from complaining
+ Log::destroy();
+ System::destroy();
+}
+
+bool ServerEnvironment::valid(std::string& errorMsg) const
+{
+ /// This must be called *AFTER* the constructor
+
+ if (serverHost_.empty()) {
+ errorMsg = "Could not determine the server host.";
+ return false;
+ }
+ std::stringstream ss;
+ if ( serverPort_ == 0 || serverPort_ <= 1023 || serverPort_ >= 49151) {
+
+ ss << "Server port " << serverPort_ << " not set correctly. \n";
+ ss << "The port numbers are divided into three ranges.\n";
+ ss << " o the Well Known Ports, (require root permission) 0 -1023\n";
+ ss << " o the Registered Ports, 1024 -49151\n";
+ ss << " o Dynamic and/or Private Ports. 49151 -65535\n\n";
+ ss << "Please set in the range 1024-49151 via argument or \n";
+ ss << "Server/src/environment.cfg.h or set the environment variable ECF_PORT. \n";
+ errorMsg = ss.str();
+ return false;
+ }
+ if (ecfHome_.empty()) {
+ ss << "No ECF_HOME specified. Please set in Server/server_environment.cfg or\n";
+ ss << "set the environment variable ECF_HOME\n";
+ errorMsg = ss.str();
+ return false;
+ }
+ if (!Log::instance() || Log::instance()->path().empty()) {
+ ss << "No log file name specified. Please set in Server/server_environment.cfg or\n";
+ ss << "set the environment variable ECF_LOG\n";
+ errorMsg = ss.str();
+ return false;
+ }
+ if ( checkPtInterval_ == 0 ) {
+ ss << "Checkpoint interval not set. Please set in Server/server_environment.cfg or\n";
+ ss << "set the environment variable ECF_CHECKINTERVAL. The value must be\n";
+ ss << "convertible to a integer\n";
+ errorMsg = ss.str();
+ return false;
+ }
+ if ( submitJobsInterval_ < 1 || submitJobsInterval_ > 60) {
+ ss << "Submit jobs interval not set correctly. Please set in Server/server_environment.cfg\n";
+ ss << "or provide as an argument. It must be in the range [1-60] \n";
+ errorMsg = ss.str();
+ return false;
+ }
+ if (ecf_checkpt_file_.empty()) {
+ ss << "No checkpoint file name specified. Please set in Server/server_environment.cfg or\n";
+ ss << "set the environment variable ECF_CHECK\n";
+ errorMsg = ss.str();
+ return false;
+ }
+ if (ecf_backup_checkpt_file_.empty()) {
+ ss << "No old checkpoint file name specified. Please set in Server/server_environment.cfg or\n";
+ ss << "set the environment variable ECF_CHECKOLD\n";
+ errorMsg = ss.str();
+ return false;
+ }
+ if (checkMode_ == ecf::CheckPt::UNDEFINED) {
+ ss << "No ECF_CHECKMODE specified. Please set in Server/server_environment.cfg\n";
+ errorMsg = ss.str();
+ return false;
+ }
+ if (ecf_cmd_.empty()) {
+ ss << "No ECF_JOB_CMD specified. Please set in Server/server_environment.cfg\n";
+ errorMsg = ss.str();
+ return false;
+ }
+ if (killCmd_.empty()) {
+ ss << "No ECF_KILL_CMD specified. Please set in Server/server_environment.cfg\n";
+ errorMsg = ss.str();
+ return false;
+ }
+ if (statusCmd_.empty()) {
+ ss << "No ECF_STATUS_CMD specified. Please set in Server/server_environment.cfg\n";
+ errorMsg = ss.str();
+ return false;
+ }
+ if (urlCmd_.empty()) {
+ ss << "No ECF_URL_CMD specified. Please set in Server/server_environment.cfg\n";
+ errorMsg = ss.str();
+ return false;
+ }
+ if (urlBase_.empty()) {
+ ss << "No ECF_URL_BASE specified. Please set in Server/server_environment.cfg\n";
+ errorMsg = ss.str();
+ return false;
+ }
+ if (url_.empty()) {
+ ss << "No ECF_URL specified. Please set in Server/server_environment.cfg\n";
+ errorMsg = ss.str();
+ return false;
+ }
+ if (ecf_micro_.empty()) {
+ ss << "No ECF_MICRODEF specified. Please set in Server/server_environment.cfg\n";
+ errorMsg = ss.str();
+ return false;
+ }
+
+ // If the white list file is empty or does not exist, *ON* server start, its perfectly valid
+ // i.e any user is free to access the server
+ if (ecf_white_list_file_.empty()) return true;
+ if (!fs::exists(ecf_white_list_file_)) return true;
+
+ /// read in the ecf white list file that specifies valid users and their access rights
+ /// If the file can't be opened returns false and an error message and false;
+ bool parse_result = white_list_file_.load(ecf_white_list_file_, debug(), errorMsg);
+
+ if (debug()) {
+ std::cout << white_list_file_.dump_valid_users() << "\n";
+ }
+ return parse_result;
+}
+
+std::pair<std::string,std::string> ServerEnvironment::hostPort() const
+{
+ return std::make_pair(serverHost_,the_port());
+}
+
+std::string ServerEnvironment::the_port() const
+{
+ return boost::lexical_cast< std::string >( serverPort_ );
+}
+
+void ServerEnvironment::variables(std::vector<std::pair<std::string,std::string> >& theRetVec) const
+{
+ // Variables read in from the environment
+ // Need to setup client environment.
+ // The server sets these variable for use by the client. i.e when creating the jobs
+ // The clients then uses them to communicate back with the server.
+ theRetVec.push_back( std::make_pair(Str::ECF_PORT(), the_port()) );
+ theRetVec.push_back( std::make_pair(std::string("ECF_NODE"), serverHost_) );
+
+ theRetVec.push_back( std::make_pair(Str::ECF_HOME(), ecfHome_) );
+ if (Log::instance()) theRetVec.push_back( std::make_pair(std::string("ECF_LOG"), Log::instance()->path()) );
+ else theRetVec.push_back( std::make_pair(std::string("ECF_LOG"), std::string() ));
+ theRetVec.push_back( std::make_pair(std::string("ECF_CHECK"), ecf_checkpt_file_) );
+ theRetVec.push_back( std::make_pair(std::string("ECF_CHECKOLD"), ecf_backup_checkpt_file_) );
+ theRetVec.push_back( std::make_pair(std::string("ECF_INTERVAL"), boost::lexical_cast<std::string>(submitJobsInterval_)) );
+
+ // These variable are read in from the environment, but are not exposed
+ // since they only affect the server
+ // ECF_CHECKINTERVAL
+
+ theRetVec.push_back( std::make_pair(std::string("ECF_LISTS"), ecf_white_list_file_) ); // read only variable, changing it has no effect
+
+ // variables that can be overridden, in the suite definition
+ theRetVec.push_back( std::make_pair(std::string("ECF_JOB_CMD"), ecf_cmd_) );
+ theRetVec.push_back( std::make_pair(std::string("ECF_KILL_CMD"), killCmd_) );
+ theRetVec.push_back( std::make_pair(std::string("ECF_STATUS_CMD"), statusCmd_) );
+ theRetVec.push_back( std::make_pair(std::string("ECF_URL_CMD"), urlCmd_) );
+ theRetVec.push_back( std::make_pair(std::string("ECF_URL_BASE"), urlBase_) );
+ theRetVec.push_back( std::make_pair(std::string("ECF_URL"), url_) );
+ theRetVec.push_back( std::make_pair(std::string("ECF_MICRO"), ecf_micro_) );
+
+ // Reference variable, these should be read only
+ theRetVec.push_back( std::make_pair(std::string("ECF_PID"), ecf_pid_) ); // server PID
+ theRetVec.push_back( std::make_pair(std::string("ECF_VERSION"), Version::raw()) );// server version
+}
+
+bool ServerEnvironment::reloadWhiteListFile(std::string& errorMsg)
+{
+ if (debug()) cout << "ServerEnvironment::reloadWhiteListFile:(" << ecf_white_list_file_ << ") CWD(" << fs::current_path().string() << ")\n";
+ if (ecf_white_list_file_.empty()) {
+ errorMsg += "The ECF_LISTS file ";
+ errorMsg += ecf_white_list_file_;
+ errorMsg += " has not been specified.";
+ return false;
+ }
+ if (!fs::exists(ecf_white_list_file_)) {
+ errorMsg += "The ECF_LISTS file ";
+ errorMsg += ecf_white_list_file_;
+ errorMsg += " does not exist. Server CWD : " + fs::current_path().string();
+ return false;
+ }
+
+ // Only override valid users if we successfully opened and parsed file
+ return white_list_file_.load(ecf_white_list_file_, debug(), errorMsg );
+}
+
+
+bool ServerEnvironment::authenticateReadAccess(const std::string& user) const
+{
+ // if *NO* users specified then all users are valid
+ return white_list_file_.allow_read_access(user);
+}
+
+bool ServerEnvironment::authenticateWriteAccess(const std::string& user) const
+{
+ // if *NO* users specified then all users have write access
+ return white_list_file_.allow_write_access(user);
+}
+
+// ============================================================================================
+// Privates:
+// ============================================================================================
+
+void ServerEnvironment::read_config_file(std::string& log_file_name,const std::string& path_to_config_file)
+{
+ if (debug()) cout << "ServerEnvironment::read_config_file() current_path = " << fs::current_path() << "\n";
+
+ try {
+ std::string theCheckMode;
+ int the_task_threshold = 0;
+
+ // read the environment from the config file.
+ // **** Port *must* be read before log file, and check pt files
+ po::options_description config_file_options("Configuration");
+ config_file_options.add_options()
+ ("ECF_HOME", po::value<std::string>(&ecfHome_)->default_value("."), "ECF_HOME, the home for all ECF files")
+ ("ECF_PORT", po::value<int>(&serverPort_)->default_value(3141), "The port number. Clients must use same port.")
+ ("ECF_CHECK", po::value<std::string>(&ecf_checkpt_file_)->default_value(Ecf::CHECKPT()), "Check point file name")
+ ("ECF_CHECKOLD", po::value<std::string>(&ecf_backup_checkpt_file_)->default_value(Ecf::BACKUP_CHECKPT()), "Backup checkpoint file name")
+ ("ECF_LOG", po::value<std::string>(&log_file_name)->default_value(Ecf::LOG_FILE()), "Log file name")
+ ("ECF_CHECKINTERVAL", po::value<int>(&checkPtInterval_)->default_value(CheckPt::default_interval()), "The interval in seconds to save check point file")
+ ("ECF_INTERVAL", po::value<int>(&submitJobsInterval_)->default_value(defaultSubmitJobsInterval), "Check time dependencies and submit any jobs")
+ ("ECF_CHECKMODE", po::value<std::string>(&theCheckMode), "The check mode, must be one of CHECK_NEVER, CHECK_ON_TIME, CHECK_ALWAYS")
+ ("ECF_JOB_CMD", po::value<std::string>(&ecf_cmd_)->default_value(Ecf::JOB_CMD()), "Command to be executed to submit a job.")
+ ("ECF_KILL_CMD", po::value<std::string>(&killCmd_)->default_value(Ecf::KILL_CMD()), "Command to be executed to kill a job.")
+ ("ECF_STATUS_CMD",po::value<std::string>(&statusCmd_)->default_value(Ecf::STATUS_CMD()), "Command to be obtain the status.")
+ ("ECF_URL_CMD", po::value<std::string>(&urlCmd_)->default_value(Ecf::URL_CMD()), "Command to be obtain url.")
+ ("ECF_URL_BASE", po::value<std::string>(&urlBase_)->default_value(Ecf::URL_BASE()), "Defines url base.")
+ ("ECF_URL", po::value<std::string>(&url_)->default_value(Ecf::URL()), "The default url.")
+ ("ECF_MICRODEF", po::value<std::string>(&ecf_micro_)->default_value(Ecf::MICRO()), "Preprocessor character for variable substitution and including files")
+ ("ECF_LISTS", po::value<std::string>(&ecf_white_list_file_)->default_value(Str::WHITE_LIST_FILE()), "Path name to file the list valid users and thier access rights")
+ ("ECF_TASK_THRESHOLD",po::value<int>(&the_task_threshold)->default_value(JobProfiler::task_threshold_default()),"The defaults thresholfs when profiling job generation")
+ ;
+
+ ifstream ifs(path_to_config_file.c_str());
+ if (!ifs) {
+ if (debug()) cout << "Could not load server_environment.cfg " << path_to_config_file << "\n";
+ }
+
+ /// This is *NOT* redundant, when the file is empty/not present, then the default value
+ /// defined above are set.
+ po::variables_map vm;
+ po::store(parse_config_file(ifs, config_file_options), vm);
+ po::notify( vm);
+
+ if (theCheckMode == "CHECK_ON_TIME") checkMode_ = ecf::CheckPt::ON_TIME;
+ else if (theCheckMode == "CHECK_NEVER") checkMode_ = ecf::CheckPt::NEVER;
+ else if (theCheckMode == "CHECK_ALWAYS") checkMode_ = ecf::CheckPt::ALWAYS;
+
+ if (the_task_threshold != 0 ) {
+ JobProfiler::set_task_threshold(the_task_threshold);
+ }
+ }
+ catch(std::exception& e)
+ {
+ cerr << "ServerEnvironment::read_config_file() " << e.what() << "\n";
+ }
+}
+
+void ServerEnvironment::read_environment_variables(std::string& log_file_name)
+{
+ if (debug()) cout << "ServerEnvironment::read_environment_variables()\n";
+
+ char* serverPort = getenv(Str::ECF_PORT().c_str());
+ if (serverPort) {
+ std::string port = serverPort;
+ try { serverPort_ = boost::lexical_cast< int >( port ); }
+ catch (boost::bad_lexical_cast& e) {
+ std::stringstream ss;
+ ss << "ServerEnvironment::read_environment_variables(): ECF_PORT is defined(" << port << ") but value is *not* convertible to an integer\n";
+ throw ServerEnvironmentException(ss.str());
+ }
+ }
+ char* checkPtInterval = getenv("ECF_CHECKINTERVAL");
+ if (checkPtInterval) {
+ std::string interval = checkPtInterval;
+ try { checkPtInterval_ = boost::lexical_cast< int >( interval ); }
+ catch (boost::bad_lexical_cast& e) {
+ std::stringstream ss;
+ ss << "ServerEnvironment::read_environment_variables(): ECF_CHECKINTERVAL is defined(" << interval << ") but value is *not* convertible to an integer\n";
+ throw ServerEnvironmentException(ss.str());
+ }
+ }
+
+ char* ecfHome = getenv(Str::ECF_HOME().c_str());
+ if (ecfHome) ecfHome_ = ecfHome;
+ if( ecfHome_ == "." ) { // expand to absolute paths
+ ecfHome_ = fs::current_path().string();
+ }
+
+ char* logFileName = getenv("ECF_LOG");
+ if (logFileName) log_file_name = logFileName;
+
+ char* checkPtFileName = getenv("ECF_CHECK");
+ if (checkPtFileName) ecf_checkpt_file_ = checkPtFileName;
+
+ char* oldCheckPtFileName = getenv("ECF_CHECKOLD");
+ if (oldCheckPtFileName) ecf_backup_checkpt_file_ = oldCheckPtFileName;
+
+ char* smsWhiteListFile = getenv("ECF_LISTS");
+ if (smsWhiteListFile) ecf_white_list_file_ = smsWhiteListFile;
+
+ if (getenv("ECF_DEBUG_SERVER")) {
+ debug_ = true; // can also be enabled via --debug option
+ }
+
+ if (getenv("ECF_ALLOW_OLD_CLIENT_NEW_SERVER")) {
+ // we don't need exact version of boost archive version of old client, since we can determine
+ // this from the message sent to the server from the *old* client
+ allow_old_client_new_server_ = ecf::boost_archive::version_1_47();
+ }
+
+ char* threshold = getenv("ECF_TASK_THRESHOLD");
+ if ( threshold ) {
+ std::string task_threshold = threshold;
+ try {
+ JobProfiler::set_task_threshold(boost::lexical_cast<int>(task_threshold));
+ }
+ catch ( ... ) {
+ std::stringstream ss;
+ ss << "ServerEnvironment::read_environment_variables(): ECF_TASK_THRESHOLD is defined(" << threshold << ") but value is *not* convertible to an integer\n";
+ throw ServerEnvironmentException(ss.str());
+ }
+ }
+}
+
+void ServerEnvironment::change_dir_to_ecf_home_and_check_accesibility()
+{
+ if( chdir(ecfHome_.c_str()) != 0 ) {
+ std::stringstream ss;
+ ss << "Can't chdir to ECF_HOME " << ecfHome_ << "\n";
+ throw ServerEnvironmentException(ss.str());
+ }
+ if( access(ecfHome_.c_str() , X_OK|R_OK|W_OK) != 0 ) {
+ // R_OK test for read permission
+ // W_OK test for write permission
+ // X_OK test for execute or search permission
+ // F_OK test whether the directories leading to the file can be searched and the file exists.
+ std::stringstream ss;
+ ss << "Access restriction on ECF_HOME " << ecfHome_ << "\n";
+ throw ServerEnvironmentException(ss.str());
+ }
+}
+
+std::string ServerEnvironment::check_mode_str() const { return the_check_mode(checkMode_);}
+
+std::string ServerEnvironment::dump() const
+{
+ std::stringstream ss;
+ ss << "ECF_HOME = '" << ecfHome_ << "'\n";
+ if (Log::instance()) ss << "ECF_LOG = '" << Log::instance()->path() << "'\n";
+ else ss << "ECF_LOG = ''\n";
+ ss << "ECF_PORT = '" << serverPort_ << "'\n";
+ ss << "ECF_CHECK = '" << ecf_checkpt_file_ << "'\n";
+ ss << "ECF_CHECKOLD = '" << ecf_backup_checkpt_file_ << "'\n";
+ ss << "ECF_CHECKINTERVAL = '" << checkPtInterval_ << "'\n";
+ ss << "ECF_INTERVAL = '" << submitJobsInterval_ << "'\n";
+ ss << "ECF_CHECKMODE = '" << the_check_mode(checkMode_) << "'\n";
+ ss << "ECF_JOB_CMD = '" << ecf_cmd_ << "'\n";
+ ss << "ECF_KILL_CMD = '" << killCmd_ << "'\n";
+ ss << "ECF_STATUS_CMD = '" << statusCmd_ << "'\n";
+ ss << "ECF_URL_CMD = '" << urlCmd_ << "'\n";
+ ss << "ECF_URL_BASE = '" << urlBase_ << "'\n";
+ ss << "ECF_URL = '" << url_ << "'\n";
+ ss << "ECF_MICRO = '" << ecf_micro_ << "'\n";
+ ss << "check pt save time alarm " << checkpt_save_time_alarm_ << "\n";
+ ss << "Job generation " << jobGeneration_ << "\n";
+ ss << "Server host name " << serverHost_ << "\n";
+#ifdef ECFLOW_MT
+ ss << "No of threads used by server " << threads_ << "\n";
+#endif
+ if ( tcp_protocol_.family() == 2 /*PF_INET*/) ss << "TCP Protocol v4 \n";
+ else if ( tcp_protocol_.family() == 10 /*PF_INET6*/) ss << "TCP Protocol v6 \n";
+
+ ss << white_list_file_.dump_valid_users();
+ return ss.str();
+}
diff --git a/Server/src/ServerEnvironment.hpp b/Server/src/ServerEnvironment.hpp
new file mode 100644
index 0000000..1d692eb
--- /dev/null
+++ b/Server/src/ServerEnvironment.hpp
@@ -0,0 +1,212 @@
+#ifndef SERVER_ENVIRONMENT_HPP_
+#define SERVER_ENVIRONMENT_HPP_
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name : ServerEnvironment
+// Author : Avi
+// Revision : $Revision: #52 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//
+// The server environment is read from the configuration file. This defines
+// the defaults for the server,and is configurable by the user, at run time
+// Alternatively some variable can be set via environment. See environment.cfg
+//
+// The server must be created before the log file. Since the log is initialised
+// with the log file name from the server environment
+//
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <string>
+#include <vector>
+#include <map>
+#include <exception>
+#include <boost/noncopyable.hpp>
+#include <boost/asio.hpp>
+
+#include "Host.hpp"
+#include "WhiteListFile.hpp"
+#include "CheckPt.hpp"
+
+// Added ServerEvinronmentException so that it can be in the same scope as server
+// in ServerMain. Previously we had a separate try block
+// Also distinguish between server and environment errors
+class ServerEnvironmentException : public std::runtime_error {
+public:
+ ServerEnvironmentException(const std::string& msg) : std::runtime_error(msg) {}
+};
+
+
+class ServerEnvironment : private boost::noncopyable {
+public:
+ ServerEnvironment(int argc, char* argv[]);
+ ServerEnvironment(int argc, char* argv[], const std::string& path_to_config_file); // *only used in test*
+ ~ServerEnvironment();
+
+ /// return true if option are valid false and error message otherwise
+ bool valid(std::string& errorMsg) const;
+
+ /// return the directory path associated with smshome
+ /// but can be overridden by the environment variable ECF_HOME
+ std::string ecf_home() const { return ecfHome_; }
+
+ /// returns the server host and port
+ std::pair<std::string,std::string> hostPort() const;
+
+ /// returns the server port. This has a default value defined in server_environment.cfg
+ /// but can be overridden by the environment variable ECF_PORT
+ int port() const { return serverPort_;}
+ std::string the_port() const;
+
+ /// returns the TCP protocol. default is TCPv4. Can be changed via command line to TCPv6
+ boost::asio::ip::tcp tcp_protocol() const { return tcp_protocol_;}
+
+ /// Return true if job generation is enabled. By default job generation is enabled however
+ /// for test/debug we can elect to disable, it.
+ bool jobGeneration() const { return jobGeneration_;}
+
+ /// Forward compatibility allow old clients to talk to new server
+ /// Temp: This allows ecflow to be built. i.e we have old clients(3.0.x), installed on different machines
+ /// they need to talk to new server. (i.e since we can't change the old clients)
+ /// This is controlled with ECF_ALLOW_OLD_CLIENT_NEW_SERVER
+ int allow_old_client_new_server() const { return allow_old_client_new_server_;}
+
+
+ /// Whenever we save the checkpt, we time how long this takes.
+ /// For very large definition the time can be significant and start to interfere with
+ /// the scheduling. (i.e since write to disk is blocking).
+ /// The default is 30 seconds. When the save time exceeds this, the late flag is
+ /// set on the definition. This needs to be manually reset.
+ size_t checkpt_save_time_alarm() const { return checkpt_save_time_alarm_;}
+ void set_checkpt_save_time_alarm(size_t t) { checkpt_save_time_alarm_ = t ;}
+
+ /// returns the path of the checkpoint file. This has a default name set in server_environment.cfg
+ /// but can be overridden by the environment variable ECF_CHECK
+ /// if the check point file starts with an absolute path return as is:
+ /// otherwise returns ECF_HOME/ecf_checkpt_file_
+ const std::string& checkPtFilename() const { return ecf_checkpt_file_; }
+
+ /// returns the path of the old checkPointFile. This has a default name set in server_environment.cfg
+ /// but can be overridden by the environment variable ECF_CHECKOLD
+ /// if the check point file starts with an absolute path return as is:
+ /// otherwise returns ECF_HOME/ecf_backup_checkpt_file_
+ const std::string& oldCheckPtFilename() const { return ecf_backup_checkpt_file_; }
+
+ /// returns the checkPt interval. This is the time in seconds, at which point the server
+ /// serializes the defs node tree. This is called the check point file.
+ /// This has a default value set in environment.cfg
+ /// but can be overridden by the environment variable ECF_CHECKINTERVAL
+ /// if set via environment variable it must be convertible to an integer
+ int checkPtInterval() const { return checkPtInterval_;}
+
+ /// set the check point interval. Typically set via client interface
+ /// value should > 0 for valid values.
+ void set_checkpt_interval(int v) { if (v > 0) checkPtInterval_ = v;}
+
+ /// returns the check mode. This specifies options for saving of the checkPoint file:
+ ecf::CheckPt::Mode checkMode() const { return checkMode_;}
+ void set_check_mode(ecf::CheckPt::Mode m) { checkMode_ = m; }
+ std::string check_mode_str() const;
+
+ /// returns the number of seconds at which we should check time dependencies
+ /// this includes evaluating trigger dependencies and submit the corresponding jobs.
+ /// This is set at 60 seconds. But will vary for debug/test purposes only.
+ /// For Testing the state change queued->submitted->active duration < submitJobsInterval
+ /// If this state change happens at the job submission boundary then
+ /// time series can get a skew.
+ int submitJobsInterval() const { return submitJobsInterval_;}
+
+ /// returns server variables, as vector of pairs.
+ /// Some of these variables hold environment variables
+ /// Note:: additional variable are created for use by clients, i.e like
+ /// ECF_PORT(jobs, server, client)
+ /// ECF_NODE(jobs). ECF_NODE is the server machine host name
+ void variables(std::vector<std::pair<std::string,std::string> >&) const;
+
+ /// Ask the server to reload file the hold list of users and their access rights
+ /// The white list file is specified by the environment variable ECF_LISTS
+ /// This allows/disallows user access on the live server
+ /// Return true if file is reloaded ok, else false and error message if:
+ /// a/ File does not exist
+ /// b/ File is empty
+ /// c/ Errors in parsing file
+ /// If errors arise the exist user still stay in affect
+ bool reloadWhiteListFile(std::string& errorMsg);
+
+#ifdef ECFLOW_MT
+ // returns the numbers threads to be used by the server.
+ size_t threads() const { return threads_; };
+#endif
+
+ /// There are several kinds of authentification:
+ /// a/ None
+ /// b/ List mode. ASCII file based on ECF_LISTS is defined
+ /// c/ Secure mode. binary file based ECF_PASSWD is defined
+ /// At the moment we will only implement options a/ and b/
+ //
+ /// Returns true if the given user has access to the server, false otherwise
+ bool authenticateReadAccess(const std::string& user)const;
+ bool authenticateWriteAccess(const std::string& user) const;
+
+ /// return true if help option was selected
+ bool help_option() const { return help_option_; }
+ bool version_option() const { return version_option_; }
+
+ /// debug is enabled via --debug or server invocation
+ bool debug() const { return debug_;}
+ void set_debug(bool f) { debug_ = f;}
+
+ std::string dump() const;
+
+private:
+ void init(int argc, char* argv[], const std::string& path_to_config_file);
+
+ /// defaults are read from a config file
+ void read_config_file(std::string& log_file_name,const std::string& path_to_config_file);
+
+ /// Get the standard environment variables, overwrite any settings from config file
+ void read_environment_variables(std::string& log_file_name);
+
+ void change_dir_to_ecf_home_and_check_accesibility();
+
+private:
+ ecf::Host host_name_;
+ std::string serverHost_; // must be after host_name_, since used in init
+ int serverPort_;
+ int checkPtInterval_;
+ int checkpt_save_time_alarm_;
+ int submitJobsInterval_;
+#ifdef ECFLOW_MT
+ size_t threads_;
+#endif
+ bool jobGeneration_; // used in debug/test mode only
+ bool debug_;
+ bool help_option_;
+ bool version_option_;
+ int allow_old_client_new_server_;
+ ecf::CheckPt::Mode checkMode_;
+ std::string ecfHome_;
+ std::string ecf_checkpt_file_;
+ std::string ecf_backup_checkpt_file_;
+ std::string ecf_pid_;
+ std::string killCmd_;
+ std::string statusCmd_;
+ std::string urlCmd_;
+ std::string urlBase_;
+ std::string url_;
+ std::string ecf_cmd_;
+ std::string ecf_micro_;
+ std::string ecf_white_list_file_;
+ mutable WhiteListFile white_list_file_;
+ boost::asio::ip::tcp tcp_protocol_; // defaults to IPv4 TCP protocol
+ friend class ServerOptions;
+};
+
+#endif
diff --git a/Server/src/ServerMain.cpp b/Server/src/ServerMain.cpp
new file mode 100644
index 0000000..ba04c62
--- /dev/null
+++ b/Server/src/ServerMain.cpp
@@ -0,0 +1,79 @@
+//============================================================================
+// Name : ServerMain
+// Author : Avi
+// Revision : $Revision: #37 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : Server
+//============================================================================
+
+#include <memory>
+#include "Server.hpp"
+#include "Log.hpp"
+#include "ServerEnvironment.hpp"
+
+using namespace ecf;
+using namespace std;
+
+int main( int argc, char* argv[] ) {
+
+ try {
+ // Get the environment settings, and parse argument line and init the log file
+ ServerEnvironment server_environment(argc, argv); // This can throw ServerEnvironmentException
+ if ( server_environment.help_option()) return 0;
+ if ( server_environment.version_option()) return 0;
+ std::string errorMsg;
+ if (!server_environment.valid(errorMsg)) {
+ cerr << errorMsg;
+ ecf::log(Log::ERR,errorMsg);
+ return 1;
+ }
+
+ if (server_environment.debug()) cout << "Server started: ------------------------------------------------>port:" << server_environment.port() << endl;
+ Server theServer( server_environment ); // This can throw exception, bind address in use.
+ for(;;) {
+ try {
+ theServer.run();
+ if (server_environment.debug()) cout << "Normal exit from server\n";
+ break;
+ }
+ catch ( std::exception& e ) {
+ // deal with errors from the handlers
+ std::string msg = "ServerMain:: "; msg += e.what();
+ std::cerr << msg << endl;
+ ecf::log(Log::ERR,msg);
+ }
+ }
+
+ if (server_environment.debug()) cout << "Server EXITING: <------------------------------------------------ port:" << server_environment.port() << endl;
+ return 0;
+ }
+ catch ( ServerEnvironmentException& e ) {
+ // *** deal with server options and environment exceptions
+ std::cerr << "Could not load the server environment or options :\n" << e.what() << "\n";
+ std::cerr << "Invalid locale? Check locale using 'locale -a', then export/set LANG environment\n";
+ }
+ catch ( std::exception& e ) {
+ // *** deal with errors from the server constructor ****
+ std::string msg = "Exception in ServerMain:: "; msg += e.what();
+ std::cerr << msg << endl;
+ ecf::log(Log::ERR,msg);
+
+ // dump server environment
+ cerr << "\nServer environment:\n";
+ ServerEnvironment server_env(argc, argv); // This can throw ServerEnvironmentException
+ std::cerr << server_env.dump();
+ }
+ catch ( ... ) {
+ std::string msg = "ServerMain:: unknown exception";
+ std::cerr << msg << endl;
+ ecf::log(Log::ERR,msg);
+ }
+ return 1;
+}
diff --git a/Server/src/ServerOptions.cpp b/Server/src/ServerOptions.cpp
new file mode 100644
index 0000000..f5be79b
--- /dev/null
+++ b/Server/src/ServerOptions.cpp
@@ -0,0 +1,160 @@
+//============================================================================
+// Name : ServerOptions
+// Author : Avi
+// Revision : $Revision: #28 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include "ServerOptions.hpp"
+#include "Version.hpp"
+#include "ServerEnvironment.hpp"
+#include <boost/lexical_cast.hpp>
+#include <iostream>
+
+using namespace std;
+using namespace ecf;
+namespace po = boost::program_options;
+
+ServerOptions::ServerOptions( int argc, char* argv[],ServerEnvironment* env )
+{
+ std::stringstream ss;
+ ss << "\n" << Version::description() << "\nServer options";
+ po::options_description desc( ss.str() , po::options_description::m_default_line_length + 80 );
+
+ desc.add_options()
+( "help,h",
+ "The server reads the LANG for the locale. Please ensure that\n"
+ "locale is valid otherwise the server will abort on startup.\n"
+ "For a list of valid locale use 'locale -a'.\n"
+ "\n"
+ "The server will read the following environment variables:\n"
+ "ECF_PORT:\n"
+ " Defines the port that the server will listen to.\n"
+ " The port number must be consistent between client and server\n"
+ " If two servers are started on the same machine with same port\n"
+ " then a 'Address in use' error is shown and server will exit.\n"
+ " The default value for client/server is 3141\n"
+ "ECF_HOME:\n"
+ " This is the home/root for all '.ecf' scripts.\n"
+ " When the server starts it will change directory to ECF_HOME,\n"
+ " hence the directory must be accessible and writable.\n"
+ " The default value is the current working directory\n"
+ "ECF_LOG:\n"
+ " Overrides the name of log file.\n"
+ " The default log file name is: <host>.<port>.ecf.log, i.e. machine1.3141.ecf.log\n"
+ " this is required since we can have multiple servers for a single machine.\n"
+ " Where each server will have a separate port number.\n"
+ " Note: Any settings will be prepended with <host>.<port>.\n"
+ "ECF_CHECK:\n"
+ " Defines the name of the check point file.\n"
+ " This stores the state of the definition in memory,\n"
+ " and allows recovery from crash. By default the server on start up will load\n"
+ " the check point file or back up check point file if they exist.\n"
+ " The default is <host>.<port>.ecf.check\n"
+ " Any settings will be prepended with <host>.<port>.\n"
+ "ECF_CHECKOLD:\n"
+ " The name of the backup checkpoint file\n"
+ " default is <host>.<port>.ecf.check.b\n"
+ " Any settings will be prepended with <host>.<port>.\n"
+ "ECF_CHECKINTERVAL:\n"
+ " The interval in seconds within the server that the checkpoint file is saved\n"
+ " Values less than 60 seconds are not recommended\n"
+ " The default value is 120 seconds\n"
+ "ECF_LISTS:\n"
+ " This variable is used to identify a file, that lists the user\n"
+ " who can access the server via client commands. Each client command\n"
+ " (ignoring child commands, i.e init, complete, event, meter, label, wait)\n"
+ " will encode the user name of the process initiating the client request\n"
+ " This is then compared with list of users in the ecf.lists file.\n"
+ " If this file is empty, then no authentication is done.\n"
+ " Each server can potentially have a different list.\n"
+ " The default is <host>.<port>.ecf.lists\n"
+ " Note: Any settings will be prepended with <host>.<port>.\n"
+ "ECF_TASK_THRESHOLD:\n"
+ " The Job generation process is expected to take less than 60 seconds\n"
+ " This is used to aid debugging of task tasking excessive times for job generation\n"
+ " The causes can be:\n"
+ " a/ Slow disk I/0, or when server is run an a virtual machine\n"
+ " b/ Insufficient memory, when compared to the size of the scripts/definition\n"
+ " c/ Large number of jobs submitted at the same time, and/or very large scripts\n"
+ " Any task taking longer than the specified time in milliseconds will be logged.\n"
+ " WAR:[..] Job generation for task /suite/family/dodgy_task took 5000ms, Exceeds ECF_TASK_THRESHOLD(4000ms)\n"
+ " The default threshold is 4000 milliseconds\n"
+ " Note: 1000 milliseconds = 1 second\n"
+ " export ECF_TASK_THRESHOLD=1500\n"
+ "\n"
+ "These defaults along with several other can be specified in the file\n"
+ "server_environment.cfg. The file should be placed in the current working\n"
+ "directory. It can be found in ecFlow source tree under Server/ directory.\n"
+ "Please read this file to see the available options.\n"
+ "Note: Environment variables _override_ any settings made in the\n"
+ "server_environment.cfg file."
+)
+( "port", po::value< int >(), "<int> <Allowed range 1024-49151> The socket/port the server is listening too. default = 3141\n"
+ "If set will override the environment variable ECF_PORT"
+)
+( "ecfinterval", po::value< int >(), "<int> <Allowed range 1-60> Submit jobs interval. For DEBUG/Test only" )
+#ifdef ECFLOW_MT
+( "threads", po::value< int >(), "<int> No of threads used by the server. Default is no of cores on machine" )
+#endif
+( "v6", "Use IPv6 TCP protocol. Default is IPv4" )
+( "dis_job_gen", "Disable job generation. For DEBUG/Test only." )
+( "debug,d", "Enable debug output." )
+( "version,v", "Show ecflow version number,boost library version, compiler used and compilation date, then exit" )
+ ;
+
+ po::store( po::parse_command_line( argc, argv, desc ), vm_ );
+ po::notify( vm_ );
+
+ if ( vm_.count( "help" ) ) cout << desc << "\n";
+
+ if ( vm_.count( "version" ) ) {
+ cout << Version::description() << "\n";
+ }
+
+ if ( vm_.count( "debug" ) ) env->debug_ = true;
+
+
+ if ( vm_.count( "port" ) ) {
+ if (env->debug_) cout << "ServerOptions:: The port number set to '" << vm_["port"].as< int > () << "'\n";
+ env->serverPort_ = vm_["port"].as< int > ();
+ }
+ if ( vm_.count( "ecfinterval" ) ) {
+ if (env->debug_) cout << "ServerOptions: The ecfinterval set to '" << vm_["ecfinterval"].as< int > () << "'\n";
+ env->submitJobsInterval_ = vm_["ecfinterval"].as< int > ();
+ }
+ if ( vm_.count( "v6" ) ) {
+ if (env->debug_) cout << "ServerOptions: The tcp protocol set to v6\n";
+ env->tcp_protocol_ = boost::asio::ip::tcp::v6();
+ }
+ if ( vm_.count( "dis_job_gen" ) ) {
+ if (env->debug_) cout << "ServerOptions: The dis_job_gen is set\n";
+ env->jobGeneration_ = false;
+ }
+
+#ifdef ECFLOW_MT
+ if ( vm_.count( "threads" ) ) {
+ if (env->debug_) cout << "ServerOptions: The numbers of threads set to '" << vm_["threads"].as< int > () << "'\n";
+ env->threads_ = vm_["threads"].as< int > ();
+ }
+#endif
+}
+
+bool ServerOptions::help_option() const
+{
+ if ( vm_.count( "help" ) ) return true;
+ return false;
+}
+
+bool ServerOptions::version_option() const
+{
+ if ( vm_.count( "version" ) ) return true;
+ return false;
+}
diff --git a/Server/src/ServerOptions.hpp b/Server/src/ServerOptions.hpp
new file mode 100644
index 0000000..ebd3df1
--- /dev/null
+++ b/Server/src/ServerOptions.hpp
@@ -0,0 +1,38 @@
+#ifndef SERVER_OPTIONS_HPP_
+#define SERVER_OPTIONS_HPP_
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// Name : ServerOptions
+// Author : Avi
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//
+// This class will parse the server arguments
+// It will update the ServerEnvironment
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+
+#include <boost/program_options.hpp>
+#include <boost/noncopyable.hpp>
+
+class ServerEnvironment;
+
+class ServerOptions : private boost::noncopyable {
+public:
+ ServerOptions(int argc, char* argv[], ServerEnvironment*);
+
+ /// return true if help selected, else false
+ bool help_option() const;
+ bool version_option() const;
+
+private:
+ boost::program_options::variables_map vm_;
+};
+#endif
diff --git a/Server/test/TestServer1.cpp b/Server/test/TestServer1.cpp
new file mode 100644
index 0000000..df7c8c9
--- /dev/null
+++ b/Server/test/TestServer1.cpp
@@ -0,0 +1,150 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #14 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+
+#include <boost/test/unit_test.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/foreach.hpp>
+#include "boost/filesystem/operations.hpp"
+
+#include "ServerEnvironment.hpp"
+#include "EcfPortLock.hpp"
+#include "Log.hpp"
+#include "Host.hpp"
+#include "Str.hpp"
+#include "Ecf.hpp"
+#include "File.hpp"
+#include "Server.hpp"
+#include "Defs.hpp"
+
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( TestServer )
+
+// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+// make public the function we wish to test:
+// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+class TestServer : public Server {
+public:
+ TestServer(ServerEnvironment& s) : Server(s) {}
+ virtual ~TestServer() {}
+
+ // abort server if check pt files exist, but can't be loaded
+ // bool load_check_pt_file_on_startup();
+ // void loadCheckPtFile();
+ // bool restore_from_checkpt(const std::string& filename, bool& failed);
+ // void set_server_state(SState::State);
+
+ /// AbstractServer functions
+ virtual SState::State state() const { return Server::state(); }
+ virtual std::pair<std::string,std::string> hostPort() const { return Server::hostPort(); }
+ virtual defs_ptr defs() const { return Server::defs();}
+ // virtual void updateDefs(defs_ptr,bool force);
+ virtual void clear_defs() { Server::clear_defs();}
+ // virtual void checkPtDefs(ecf::CheckPt::Mode m = ecf::CheckPt::UNDEFINED,
+ // int check_pt_interval = 0,
+ // int check_pt_save_time_alarm = 0);
+ virtual void restore_defs_from_checkpt() { Server::restore_defs_from_checkpt();}
+ virtual void nodeTreeStateChanged() { Server::nodeTreeStateChanged(); }
+ virtual bool allowTaskCommunication() const { return Server::allowTaskCommunication();}
+ virtual void shutdown() { Server::shutdown(); }
+ virtual void halted() { Server::halted(); }
+ virtual void restart() { Server::restart(); }
+ virtual bool reloadWhiteListFile(std::string& errorMsg) { return Server::reloadWhiteListFile(errorMsg);}
+ virtual bool authenticateReadAccess(const std::string& user) { return Server::authenticateReadAccess(user); }
+ virtual bool authenticateWriteAccess(const std::string& user) { return Server::authenticateWriteAccess(user); }
+ virtual bool lock(const std::string& user) { return Server::lock(user); }
+ virtual void unlock() { Server::unlock();}
+ virtual const std::string& lockedUser() const { return Server::lockedUser(); }
+ // virtual void traverse_node_tree_and_job_generate(const boost::posix_time::ptime& time_now, bool user_cmd_context) const;
+ virtual int poll_interval() const { return Server::poll_interval();}
+ // virtual void debug_server_on();
+ // virtual void debug_server_off();
+ // virtual bool debug() const;
+};
+
+
+BOOST_AUTO_TEST_CASE( test_server )
+{
+ cout << "Server:: ...test_server\n";
+
+ // Create a unique port number, allowing debug and release,gun,cland,intil to run at the same time
+ // Hence the lock file is not sufficient. Hence we will make a client server call.
+ std::string the_port1 = "3144" ;
+ cout << "Find free port to start server, starting with port " << the_port1 << "\n";
+ int the_port = boost::lexical_cast<int>(the_port1);
+ while (!EcfPortLock::is_free(the_port)) the_port++;
+ std::string port = boost::lexical_cast<std::string>(the_port);
+ EcfPortLock::create(port);
+ cout << "Found free port: " << port << "\n";
+
+ std::string server_port = "--port=" + port;
+ int argc = 3;
+ char* argv[] = { const_cast<char*>("ServerEnvironment"),
+ const_cast<char*>(server_port.c_str()),
+ const_cast<char*>("--ecfinterval=12")
+ };
+
+
+ ServerEnvironment server_environment(argc, argv); // This can throw ServerEnvironmentException
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE(server_environment.valid(errorMsg),errorMsg);
+
+ {
+ TestServer theServer( server_environment ); // This can throw exception, bind address in use.
+
+ BOOST_REQUIRE_MESSAGE(theServer.defs(),"Expected defs to be created");
+
+ const std::vector<Variable>& server_variables = theServer.defs()->server().server_variables();
+ BOOST_REQUIRE_MESSAGE(!server_variables.empty(),"Expected defs to be updated with the server variables");
+
+ //for(size_t i = 0; i < server_variables.size(); ++i) cout << server_variables[i].dump() << "\n";
+ const std::string& ecf_port = theServer.defs()->server().find_variable("ECF_PORT");
+ BOOST_REQUIRE_MESSAGE(ecf_port == port,"Expected port " << port << " but found " << ecf_port << " defs server variables, should be in sync with server");
+
+
+ const std::string& interval = theServer.defs()->server().find_variable("ECF_INTERVAL");
+ BOOST_REQUIRE_MESSAGE(interval == "12","Expected interval 12 but found " << interval << " defs server variables, should be in sync with server");
+ BOOST_REQUIRE_MESSAGE(theServer.poll_interval() == 12,"Expected poll interval 12 but found " << theServer.poll_interval());
+
+
+ BOOST_REQUIRE_MESSAGE(theServer.state() == SState::HALTED,"Expected halted at server start but found " << SState::to_string(theServer.state()));
+ theServer.halted(); BOOST_REQUIRE_MESSAGE(theServer.state() == SState::HALTED,"Expected halted ");
+ theServer.shutdown(); BOOST_REQUIRE_MESSAGE(theServer.state() == SState::SHUTDOWN,"Expected shutdown ");
+ theServer.restart(); BOOST_REQUIRE_MESSAGE(theServer.state() == SState::RUNNING,"Expected shutdown ");
+
+
+ BOOST_REQUIRE_MESSAGE(theServer.lock("fred"),"Expected to lock user fred");
+ BOOST_REQUIRE_MESSAGE(theServer.state() == SState::SHUTDOWN,"Locking should shutdown server");
+ BOOST_REQUIRE_MESSAGE(theServer.lockedUser() == "fred","Expected locked user 'fred' but found " << theServer.lockedUser());
+ theServer.unlock();
+ BOOST_REQUIRE_MESSAGE(theServer.lockedUser().empty(),"Expected no locked user but found " << theServer.lockedUser());
+ BOOST_REQUIRE_MESSAGE(theServer.state() == SState::RUNNING,"Expected unlock to restart server ");
+ }
+
+ // cleanup
+ Host h;
+ fs::remove(h.ecf_log_file(port));
+ EcfPortLock::remove(port);
+
+ /// Destroy Log singleton to avoid valgrind from complaining
+ Log::destroy();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Server/test/TestServerEnvironment.cpp b/Server/test/TestServerEnvironment.cpp
new file mode 100644
index 0000000..c0b9d08
--- /dev/null
+++ b/Server/test/TestServerEnvironment.cpp
@@ -0,0 +1,366 @@
+#define BOOST_TEST_MODULE Server
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #14 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+
+#include <boost/test/unit_test.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/foreach.hpp>
+#include "boost/filesystem/operations.hpp"
+
+#include "ServerEnvironment.hpp"
+#include "Log.hpp"
+#include "Host.hpp"
+#include "Str.hpp"
+#include "Ecf.hpp"
+#include "File.hpp"
+#include "CheckPt.hpp"
+#include "JobProfiler.hpp"
+
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( TestServer )
+
+
+BOOST_AUTO_TEST_CASE( test_server_environment_ecfinterval )
+{
+ cout << "Server:: ...test_server_environment_ecfinterval\n";
+
+ // ecflow server interval is valid for range [1-60]
+ std::string port = Str::DEFAULT_PORT_NUMBER();
+ for(int i=-10; i< 70; ++i)
+ {
+ string errorMsg;
+ string argument = "--ecfinterval=" + boost::lexical_cast<std::string>(i);
+
+ int argc = 2;
+ char* argv[] = { const_cast<char*>("ServerEnvironment"), const_cast<char*>(argument.c_str()) };
+ ServerEnvironment serverEnv(argc,argv);
+ bool valid = serverEnv.valid(errorMsg);
+ if (i > 0 && i < 61) {
+ BOOST_REQUIRE_MESSAGE(valid,"Server environment ecfinterval valid range is [1-60] " << errorMsg);
+ BOOST_CHECK_MESSAGE(serverEnv.submitJobsInterval() == i,"Expected submit jobs interval of " << i << " but found " << serverEnv.submitJobsInterval());
+ }
+ else BOOST_CHECK_MESSAGE(!valid,"Server environment ecfinterval valid range is [1-60] " << errorMsg);
+
+ port = serverEnv.the_port();
+ }
+
+ Host h;
+ fs::remove(h.ecf_log_file(port));
+}
+
+BOOST_AUTO_TEST_CASE( test_server_environment_port )
+{
+ cout << "Server:: ...test_server_environment_port\n";
+
+ // The port numbers are divided into three ranges.\n";
+ // o the Well Known Ports, (require root permission) 0 -1023\n";
+ // o the Registered Ports, 1024 -49151\n";
+ // o Dynamic and/or Private Ports. 49151 -65535\n\n";
+ // Please set in the range 1024-49151 via argument or \n";
+ Host h;
+ int argc = 2;
+ {
+ std::string errorMsg;
+ char* argv[] = { const_cast<char*>("ServerEnvironment"), const_cast<char*>("--port=0") };
+ ServerEnvironment serverEnv(argc,argv);
+ BOOST_CHECK_MESSAGE(!serverEnv.valid(errorMsg)," Server environment not valid " << errorMsg);
+ fs::remove(h.ecf_log_file(serverEnv.the_port()));
+ }
+ {
+ std::string errorMsg;
+ char* argv[] = { const_cast<char*>("ServerEnvironment"), const_cast<char*>("--port=1000") };
+ ServerEnvironment serverEnv(argc,argv);
+ BOOST_CHECK_MESSAGE(!serverEnv.valid(errorMsg)," Server environment not valid " << errorMsg);
+ fs::remove(h.ecf_log_file(serverEnv.the_port()));
+ }
+ {
+ std::string errorMsg;
+ char* argv[] = { const_cast<char*>("ServerEnvironment"), const_cast<char*>("--port=49151") };
+ ServerEnvironment serverEnv(argc,argv);
+ BOOST_CHECK_MESSAGE(!serverEnv.valid(errorMsg)," Server environment not valid " << errorMsg);
+ fs::remove(h.ecf_log_file(serverEnv.the_port()));
+ }
+
+ {
+ std::string errorMsg;
+ char* argv[] = { const_cast<char*>("ServerEnvironment"), const_cast<char*>("--port=3144") };
+ ServerEnvironment serverEnv(argc,argv);
+ BOOST_CHECK_MESSAGE(serverEnv.valid(errorMsg)," Server environment not valid " << errorMsg);
+ BOOST_CHECK_MESSAGE(serverEnv.port() == 3144,"Expected 3144 but found " << serverEnv.port());
+ fs::remove(h.ecf_log_file(serverEnv.the_port()));
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_server_environment_log_file )
+{
+ // Regression test log file creation
+ cout << "Server:: ...test_server_environment_log_file\n";
+
+ int argc = 2;
+ char* argv[] = { const_cast<char*>("ServerEnvironment"), const_cast<char*>("--port=3144") };
+ ServerEnvironment serverEnv(argc,argv);
+
+ BOOST_CHECK_MESSAGE(Log::instance(), "Log singleton not created");
+ BOOST_CHECK_MESSAGE(fs::exists(Log::instance()->path()), "Log file not created");
+
+ // Check that server variable ECF_LOG created and value is correct
+ std::vector<std::pair<std::string,std::string> > server_vars;
+ serverEnv.variables(server_vars);
+
+ bool found_var = false;
+ typedef std::pair<std::string, std::string> mpair;
+ BOOST_FOREACH(const mpair& p, server_vars ) {
+ if (Str::ECF_LOG() == p.first) {
+ BOOST_CHECK_MESSAGE(p.second == Log::instance()->path(),"Expected " << Log::instance()->path() << " but found " << p.second);
+ found_var = true;
+ break;
+ }
+ }
+ BOOST_CHECK_MESSAGE(found_var,"Failed to find server variable ECF_LOG");
+
+ // tear down remove the log file created by ServerEnvironment
+ Host h;
+ fs::remove(h.ecf_log_file(serverEnv.the_port()));
+
+ /// Destroy Log singleton to avoid valgrind from complaining
+ Log::destroy();
+}
+
+BOOST_AUTO_TEST_CASE( test_server_config_file )
+{
+ // Regression test to make sure the server environment variable don't get removed
+ cout << "Server:: ...test_server_config_file\n";
+
+ int argc = 1;
+ char* argv[] = { const_cast<char*>("ServerEnvironment") };
+
+ ServerEnvironment serverEnv(argc,argv,File::test_data("Server/server_environment.cfg","Server"));
+
+ // expected variables
+ std::vector<std::string> expected_variables;
+ expected_variables.push_back( Str::ECF_HOME() );
+ expected_variables.push_back( "ECF_LOG" );
+ expected_variables.push_back( "ECF_CHECK" );
+ expected_variables.push_back( "ECF_CHECKOLD" );
+ expected_variables.push_back( "ECF_JOB_CMD" );
+ expected_variables.push_back( "ECF_KILL_CMD" );
+ expected_variables.push_back( "ECF_STATUS_CMD" );
+ expected_variables.push_back( "ECF_URL_CMD" );
+ expected_variables.push_back( "ECF_URL_BASE" );
+ expected_variables.push_back( "ECF_URL" );
+ expected_variables.push_back( "ECF_MICRO" );
+ expected_variables.push_back( "ECF_PID" );
+ expected_variables.push_back( "ECF_VERSION" );
+ expected_variables.push_back( "ECF_LISTS" );
+ expected_variables.push_back( Str::ECF_PORT() );
+ expected_variables.push_back( "ECF_NODE");
+ expected_variables.push_back( "ECF_INTERVAL");
+
+ std::vector<std::pair<std::string,std::string> > server_vars;
+ serverEnv.variables(server_vars);
+ BOOST_FOREACH(const std::string& expected_var, expected_variables) {
+
+ bool found_var = false;
+ typedef std::pair<std::string, std::string> s_pair;
+ BOOST_FOREACH(const s_pair& p, server_vars ) {
+ if (expected_var == p.first) { found_var = true; break; }
+ }
+ BOOST_CHECK_MESSAGE(found_var,"Failed to find server var " << expected_var);
+ }
+
+ {
+ // check other way, so that this test gets updated
+ typedef std::pair<std::string, std::string> mpair;
+ BOOST_FOREACH(const mpair& p, server_vars ) {
+ bool found_var = false;
+ BOOST_FOREACH(const std::string& expected_var, expected_variables) {
+ if (expected_var == p.first) { found_var = true; break; }
+ }
+ BOOST_CHECK_MESSAGE(found_var,"Failed to update test for server var " << p.first);
+ }
+ }
+
+ // Check the values in the server config file, are the *SAME* as the defaults, when config is *NOT* present
+ // Please note do *NOT* use quotes for the values, otherwise quotes get added.
+ // WRONG: ECF_MICRODEF = "%"
+ // RIGHT: ECF_MICRODEF = %
+ // o IGNORE ECF_CHECK: We *ONLY check those value in the config, that should not be altered.
+ // since we add root path, and append with host/port
+ // o ignore ECF_CHECKMODE: not a server variable
+ //
+ typedef std::pair<std::string, std::string> mpair;
+ BOOST_FOREACH(const mpair& p, server_vars ) {
+ //std::cout << "server variables " << p.first << " " << p.second << "\n";
+ if (Str::ECF_HOME() == p.first) {
+ BOOST_CHECK_MESSAGE(p.second == fs::current_path().string(),"for ECF_HOME expected " << fs::current_path().string() << " but found " << p.second);
+ continue;
+ }
+ if (string("ECF_PORT") == p.first && !getenv("ECF_PORT")) {
+ BOOST_CHECK_MESSAGE(p.second == Str::DEFAULT_PORT_NUMBER(),"for ECF_PORT expected " << Str::DEFAULT_PORT_NUMBER() << " but found " << p.second);
+ continue;
+ }
+ if (string("ECF_CHECKINTERVAL") == p.first) {
+ std::string expected = boost::lexical_cast<std::string>(CheckPt::default_interval());
+ BOOST_CHECK_MESSAGE(p.second == expected,"for ECF_CHECKINTERVAL expected " << CheckPt::default_interval() << " but found " << p.second);
+ continue;
+ }
+ if (string("ECF_INTERVAL") == p.first) {
+ std::string expected = "60";
+ BOOST_CHECK_MESSAGE(p.second == expected,"for ECF_INTERVAL expected " << expected << " but found " << p.second);
+ continue;
+ }
+ if (string("ECF_JOB_CMD") == p.first) {
+ std::string expected = Ecf::JOB_CMD();
+ BOOST_CHECK_MESSAGE(p.second == expected,"for ECF_JOB_CMD expected " << expected << " but found " << p.second);
+ continue;
+ }
+ if (string("ECF_KILL_CMD") == p.first) {
+ std::string expected = Ecf::KILL_CMD();
+ BOOST_CHECK_MESSAGE(p.second == expected,"for ECF_KILL_CMD expected " << expected << " but found " << p.second);
+ continue;
+ }
+ if (string("ECF_STATUS_CMD") == p.first) {
+ std::string expected = Ecf::STATUS_CMD();
+ BOOST_CHECK_MESSAGE(p.second == expected,"for ECF_STATUS_CMD expected " << expected << " but found " << p.second);
+ continue;
+ }
+ if (string("ECF_URL_CMD") == p.first) {
+ std::string expected = Ecf::URL_CMD();
+ BOOST_CHECK_MESSAGE(p.second == expected,"for ECF_URL_CMD expected " << expected << " but found " << p.second);
+ continue;
+ }
+ if (string("ECF_URL_BASE") == p.first) {
+ std::string expected = Ecf::URL_BASE();
+ BOOST_CHECK_MESSAGE(p.second == expected,"for ECF_URL_BASE expected " << expected << " but found " << p.second);
+ continue;
+ }
+ if (string("ECF_URL") == p.first) {
+ std::string expected = Ecf::URL();
+ BOOST_CHECK_MESSAGE(p.second == expected,"for ECF_URL expected " << expected << " but found " << p.second);
+ continue;
+ }
+ if (string("ECF_MICRODEF") == p.first) {
+ std::string expected = Ecf::MICRO();
+ BOOST_CHECK_MESSAGE(p.second == expected,"for ECF_MICRODEF expected " << expected << " but found " << p.second);
+ continue;
+ }
+ }
+
+ // tear down remove the log file created by ServerEnvironment
+ Host host;
+ fs::remove(host.ecf_log_file(serverEnv.the_port()));
+}
+
+
+BOOST_AUTO_TEST_CASE( test_server_environment_variables )
+{
+ // Regression test to make sure the server environment variable don't get removed
+ cout << "Server:: ...test_server_environment_variables\n";
+
+ int argc = 2;
+ char* argv[] = { const_cast<char*>("ServerEnvironment"), const_cast<char*>("--port=3144") };
+ ServerEnvironment serverEnv(argc,argv);
+
+ // expected variables
+ std::vector<std::string> expected_variables;
+ expected_variables.push_back( Str::ECF_HOME() );
+ expected_variables.push_back( "ECF_LOG" );
+ expected_variables.push_back( "ECF_CHECK" );
+ expected_variables.push_back( "ECF_CHECKOLD" );
+ expected_variables.push_back( "ECF_JOB_CMD" );
+ expected_variables.push_back( "ECF_KILL_CMD" );
+ expected_variables.push_back( "ECF_STATUS_CMD" );
+ expected_variables.push_back( "ECF_URL_CMD" );
+ expected_variables.push_back( "ECF_URL_BASE" );
+ expected_variables.push_back( "ECF_URL" );
+ expected_variables.push_back( "ECF_MICRO" );
+ expected_variables.push_back( "ECF_PID" );
+ expected_variables.push_back( "ECF_VERSION" );
+ expected_variables.push_back( "ECF_LISTS" );
+ expected_variables.push_back( Str::ECF_PORT() );
+ expected_variables.push_back( "ECF_NODE");
+ expected_variables.push_back( "ECF_INTERVAL");
+
+ std::vector<std::pair<std::string,std::string> > server_vars;
+ serverEnv.variables(server_vars);
+ BOOST_FOREACH(const std::string& expected_var, expected_variables) {
+
+ bool found_var = false;
+ typedef std::pair<std::string, std::string> mpair;
+ BOOST_FOREACH(const mpair& p, server_vars ) {
+ if (expected_var == p.first) { found_var = true; break; }
+ }
+ BOOST_CHECK_MESSAGE(found_var,"Failed to find server var " << expected_var);
+ }
+
+ // check other way, so that this test gets updated
+ typedef std::pair<std::string, std::string> mpair;
+ BOOST_FOREACH(const mpair& p, server_vars ) {
+ bool found_var = false;
+ BOOST_FOREACH(const std::string& expected_var, expected_variables) {
+ if (expected_var == p.first) { found_var = true; break; }
+ }
+ BOOST_CHECK_MESSAGE(found_var,"Failed to update test for server var " << p.first);
+ }
+
+ // tear down remove the log file created by ServerEnvironment
+ Host h;
+ fs::remove(h.ecf_log_file(serverEnv.the_port()));
+
+ /// Destroy Log singleton to avoid valgrind from complaining
+ Log::destroy();
+}
+
+BOOST_AUTO_TEST_CASE( test_server_profile_threshold_environment_variable )
+{
+ cout << "Server:: ...test_server_profile_threshold_environment_variable\n";
+ int argc = 1;char* argv[] = { const_cast<char*>("ServerEnvironment") };
+ {
+ char* put = const_cast<char*>("ECF_TASK_THRESHOLD=9");
+ BOOST_CHECK_MESSAGE(putenv(put) == 0,"putenv failed for " << put);
+ }
+ ServerEnvironment serverEnv(argc,argv);
+ BOOST_CHECK_MESSAGE(JobProfiler::task_threshold() == 9,"Expected task threshold of 9 but found " << JobProfiler::task_threshold());
+
+ // ==================================================================================
+ // Note test for errors
+ vector<string> dodgy_thresholds;
+ dodgy_thresholds.push_back("ECF_TASK_THRESHOLD=x");
+ dodgy_thresholds.push_back("ECF_TASK_THRESHOLD=,");
+ dodgy_thresholds.push_back("ECF_TASK_THRESHOLD=:");
+ dodgy_thresholds.push_back("ECF_TASK_THRESHOLD=,,");
+
+ for(size_t i =0; i < dodgy_thresholds.size(); i++) {
+ //cout << "check -------> " << dodgy_thresholds[i] << endl;
+ BOOST_CHECK_MESSAGE(putenv(const_cast<char*>(dodgy_thresholds[i].c_str())) == 0,"putenv failed for " << dodgy_thresholds[i]);
+ BOOST_CHECK_THROW(ServerEnvironment serverEnv(argc,argv), std::runtime_error );
+ }
+
+ putenv(const_cast<char*>("ECF_TASK_THRESHOLD")); // remove from env, otherwise valgrind complains
+
+ Host h;
+ fs::remove(h.ecf_log_file(serverEnv.the_port()));
+
+ /// Destroy Log singleton to avoid valgrind from complaining
+ Log::destroy();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Test/CMakeLists.txt b/Test/CMakeLists.txt
new file mode 100644
index 0000000..50f15a9
--- /dev/null
+++ b/Test/CMakeLists.txt
@@ -0,0 +1,79 @@
+# =======================================================
+# to list all sources to build use:
+# cd $WK/Test
+# find src -name \*.cpp -print | sort
+# =======================================================
+file( GLOB srcs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp" )
+
+# This library is used for the syste, level testing, hence can include test directories
+ecbuild_add_library( TARGET libharness
+ NOINSTALL
+ TYPE STATIC
+ SOURCES ${srcs}
+ LIBS libclient base libparser node nodeattr core
+ INCLUDES src
+ ../ACore/src
+ ../ANattr/src
+ ../ANode/src
+ ../ANode/test
+ ../AParser/src
+ ../Base/src
+ ../Base/src/cts
+ ../Base/src/stc
+ ../Base/test
+ ../Client/src
+ ../Client/test
+ )
+
+# =================================================================
+# test
+
+if (ENABLE_ALL_TESTS)
+
+ list( APPEND test_srcs
+ ./TestAbortCmd.cpp
+ ./TestAlias.cpp
+ ./TestClkSync.cpp
+ ./TestComplete.cpp
+ ./TestCron.cpp
+ ./TestCtsWaitCmd.cpp
+ ./TestEvents.cpp
+ ./TestFileCmd.cpp
+ ./TestHandle.cpp
+ ./TestKillCmd.cpp
+ ./TestLate.cpp
+ ./TestLimit.cpp
+ ./TestOrderCmd.cpp
+ ./TestRepeat.cpp
+ ./TestRequeueNode.cpp
+ ./TestRunner.cpp
+ ./TestServer.cpp
+ ./TestSuspend.cpp
+ ./TestToday.cpp
+ ./TestTrigger.cpp
+ ./TestWhyCmd.cpp
+ ./Test_Time.cpp
+ )
+ ecbuild_add_test( TARGET s_test
+ BOOST
+ SOURCES ${test_srcs}
+ LIBS libharness
+ TEST_DEPENDS s_client
+ )
+
+
+ ecbuild_add_test( TARGET s_test_zombies
+ BOOST
+ SOURCES ./TestZombies.cpp
+ LIBS libharness
+ TEST_DEPENDS s_test
+ )
+
+ # This test runs forever, hence not suitable for unit test.
+ #ecbuild_add_test( TARGET singletest
+ # BOOST
+ # SOURCES ./TestSingle.cpp
+ # LIBS libharness
+ # TEST_DEPENDS s_client
+ # )
+endif()
\ No newline at end of file
diff --git a/Test/DummyMain.cpp b/Test/DummyMain.cpp
new file mode 100644
index 0000000..945196d
--- /dev/null
+++ b/Test/DummyMain.cpp
@@ -0,0 +1,13 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+
+int main() { return 0; }
diff --git a/Test/Jamfile.jam b/Test/Jamfile.jam
new file mode 100644
index 0000000..5830e6e
--- /dev/null
+++ b/Test/Jamfile.jam
@@ -0,0 +1,115 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+project theTest ;
+
+#
+# Test project
+#
+use-project theCore : ../ACore ;
+use-project theNodeAttr : ../ANattr ;
+use-project theNode : ../ANode ;
+use-project theParser : ../AParser ;
+use-project theBase : ../Base ;
+use-project theServer : ../Server ;
+use-project theClient : ../Client ;
+
+lib pthread ;
+
+#
+# Split into library, so that testing can use library, and hence same compiler option
+#
+# The <include> means we will automatically add this directory to the include path
+# of any other target that uses this lib
+#
+lib libharness : [ glob src/*.cpp ]
+ : <include>../ACore/src
+ <include>../ANattr/src
+ <include>../ANode/src
+ <include>../AParser/src
+ <include>../Base/src
+ <include>../Base/test
+ <include>../Client/src
+ <include>../Client/test
+ <variant>debug:<define>DEBUG
+ <link>static
+ <use>/theCore//core
+ <use>/theNodeAttr//nodeattr
+ <use>/theNode//node
+ <use>/theBase//base
+ <use>/theParser//libparser
+ <use>/theClient//libclient
+ <use>/site-config//boost_system
+ <use>/site-config//boost_serialization
+ <use>/site-config//boost_filesystem
+ <use>/site-config//boost_program_options
+ <use>/site-config//boost_datetime
+ :
+ : <include>../Test/src
+ ;
+
+# Ignore TestSingle.cpp, used for standalone testing
+exe s_test : [ glob Test*.cpp : TestSingle.cpp TestZombies.cpp ]
+ pthread
+ /theCore//core
+ /theNodeAttr//nodeattr
+ /theNode//node
+ /theParser//libparser
+ /theBase//base
+ /theClient//libclient
+ libharness
+ /site-config//boost_system
+ /site-config//boost_serialization
+ /site-config//boost_filesystem
+ /site-config//boost_program_options
+ /site-config//boost_datetime
+ /site-config//boost_test
+ : <include>../Base/test
+ <variant>debug:<define>DEBUG
+ ;
+
+# Split because this was more error prone, Now stabilised all all platforms ?
+exe s_test_zombies : [ glob TestZombies.cpp ]
+ pthread
+ /theCore//core
+ /theNodeAttr//nodeattr
+ /theNode//node
+ /theParser//libparser
+ /theBase//base
+ /theClient//libclient
+ libharness
+ /site-config//boost_system
+ /site-config//boost_serialization
+ /site-config//boost_filesystem
+ /site-config//boost_program_options
+ /site-config//boost_datetime
+ /site-config//boost_test
+ : <include>../Base/test
+ <variant>debug:<define>DEBUG
+ ;
+
+# use for standalone testing
+exe singletest : [ glob TestSingle.cpp ]
+ pthread
+ /theCore//core
+ /theNodeAttr//nodeattr
+ /theNode//node
+ /theParser//libparser
+ /theBase//base
+ /theClient//libclient
+ libharness
+ /site-config//boost_system
+ /site-config//boost_serialization
+ /site-config//boost_filesystem
+ /site-config//boost_program_options
+ /site-config//boost_datetime
+ /site-config//boost_test
+ : <include>../Base/test
+ <variant>debug:<define>DEBUG
+ ;
+
+
\ No newline at end of file
diff --git a/Test/TestAbortCmd.cpp b/Test/TestAbortCmd.cpp
new file mode 100644
index 0000000..92c558c
--- /dev/null
+++ b/Test/TestAbortCmd.cpp
@@ -0,0 +1,99 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include "ServerTestHarness.hpp"
+#include "TestFixture.hpp"
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "DurationTimer.hpp"
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/test/unit_test.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( TestSuite )
+
+// Test the abort command. This will test the abort command and the
+// retry behaviour. i.e if a task is aborted, and the variable ECF_TRIES
+// is defined. Then providing its value is less the the task's try number
+// we should do an immediate job submission.
+BOOST_AUTO_TEST_CASE( test_ )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_abort_cmd "<< flush;
+ TestClean clean_at_start_and_end;
+
+ // Create the defs file corresponding to the text below
+ // ECF_HOME variable is automatically added by the test harness.
+ // ECF_INCLUDE variable is automatically added by the test harness.
+ // SLEEPTIME variable is automatically added by the test harness.
+ // ECF_CLIENT_EXE_PATH variable is automatically added by the test harness.
+ // This is substituted in ecf includes
+ // Allows test to run without requiring installation
+
+ //# Note: we have to use relative paths, since these tests are relocatable
+ // suite test_task_abort_cmd
+ // edit ECF_TRIES '4'
+ // family family0
+ // task abort
+ // endfamily
+ // endsuite
+ Defs theDefs;
+ {
+ suite_ptr suite = theDefs.add_suite("test_abort_cmd");
+ suite->addVariable( Variable("ECF_TRIES","4") );
+ family_ptr fam0 = suite->add_family("family0");
+ task_ptr abort = fam0->add_task("abort");
+ abort->addVerify( VerifyAttr(NState::ABORTED,3) ); // task should abort 3 times & succeed on 4th attempt
+ abort->addVerify( VerifyAttr(NState::COMPLETE,1) );// task should complete 1 times
+ }
+
+ // Create a custom ecf file for test_task_abort_cmd/family0/abort to invoke the child abort command
+ std::string templateEcfFile;
+ templateEcfFile += "%include <head.h>\n";
+ templateEcfFile += "\n";
+ templateEcfFile += "echo do some work\n";
+ templateEcfFile += "if [ %ECF_TRYNO% -le 3 ] ; then\n";
+ templateEcfFile += " %ECF_CLIENT_EXE_PATH% --abort=\"expected abort at task try no %ECF_TRYNO%\"\n";
+ templateEcfFile += " trap 0 # Remove all traps\n";
+ templateEcfFile += " exit 0 # End the shell before child command complete\n";
+ templateEcfFile += "fi\n";
+ templateEcfFile += "\n";
+ templateEcfFile += "%include <tail.h>\n";
+
+ // The test harness will create corresponding directory structure
+ // Override the default ECF file, with our custom ECF_ file
+ std::map<std::string,std::string> taskEcfFileMap;
+ taskEcfFileMap.insert(std::make_pair(TestFixture::taskAbsNodePath(theDefs,"abort"),templateEcfFile));
+
+ // Avoid standard verification since we expect to abort many times
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_abort_cmd.def"), taskEcfFileMap);
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Test/TestAlias.cpp b/Test/TestAlias.cpp
new file mode 100644
index 0000000..6819b1a
--- /dev/null
+++ b/Test/TestAlias.cpp
@@ -0,0 +1,218 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//
+// This test will TEST:
+// o Alias creation and running
+// o Alias ordering
+// o Alias deletion
+// Will indirectly test the Alias memento's
+//============================================================================
+#include <iostream>
+#include <limits> // for std::numeric_limits<int>::max()
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/lexical_cast.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include "TestFixture.hpp"
+#include "ServerTestHarness.hpp"
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "DurationTimer.hpp"
+#include "PrintStyle.hpp"
+#include "ClientToServerCmd.hpp"
+#include "DefsStructureParser.hpp"
+#include "AssertTimer.hpp"
+#include "Str.hpp"
+#include "NOrder.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( TestSingleSuite )
+
+template <typename T>
+static std::vector<std::string> toStrVec(const std::vector<T>& vec)
+{
+ std::vector<std::string> retVec; retVec.reserve(vec.size());
+ BOOST_FOREACH(T s, vec) { retVec.push_back(s->name()); }
+ return retVec;
+}
+
+std::string toString(const std::vector<std::string>& c)
+{
+ std::stringstream ss;
+ std::copy (c.begin(), c.end(), std::ostream_iterator <std::string> (ss, ", "));
+ return ss.str();
+}
+
+void wait_for_alias_to_complete(const std::string& alias_path)
+{
+ AssertTimer assertTimer(10,false); // Bomb out after 10 seconds, fall back if test fail
+ while(1) {
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0, "Could not get the defs from server\n" << TestFixture::client().errorMsg());
+ defs_ptr defs = TestFixture::client().defs();
+ node_ptr alias = defs->findAbsNode(alias_path);
+ BOOST_REQUIRE_MESSAGE(alias.get(), "Could not locate created alias at path " << alias_path << "\n" << TestFixture::client().errorMsg());
+ if (alias->state() == NState::COMPLETE) break;
+ sleep(2);
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_alias )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_alias "<< flush;
+ TestClean clean_at_start_and_end;
+
+ // Create the defs file corresponding to the text below
+ // ECF_HOME variable is automatically added by the test harness.
+ // ECF_INCLUDE variable is automatically added by the test harness.
+ // SLEEPTIME variable is automatically added by the test harness.
+ // ECF_CLIENT_EXE_PATH variable is automatically added by the test harness.
+ // This is substituted in ecf includes
+ // Allows test to run without requiring installation
+ Defs theDefs;
+ task_ptr task_a;
+ {
+ suite_ptr suite = theDefs.add_suite( "test_alias" ) ;
+ suite->add_variable("SLEEPTIME","0");
+ task_a = suite->add_task("task_a");
+ task_a->addMeter( Meter("meter",0,20,20) );
+ task_a->addEvent( Event(1,"event") );
+ task_a->addLabel( Label("task_a_label","Label1") );
+ }
+
+ // The test harness will create corresponding directory structure & default ecf file
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_alias.def"));
+
+ // After the task has completed create a Alias
+ TestFixture::client().set_throw_on_error(false);
+
+ // Get the ecf script from the current task and use it to create alias
+ BOOST_REQUIRE_MESSAGE( TestFixture::client().file(task_a->absNodePath(),CFileCmd::toString(CFileCmd::ECF),"10000") == 0, "Expected to retreive script\n" << TestFixture::client().errorMsg());
+ std::string script = TestFixture::client().get_string();
+ BOOST_CHECK_MESSAGE( !script.empty(),"script for task " << task_a->absNodePath() << " is empty" );
+
+
+ // TEST Alias CREATION and running =============================================================================
+ // Split the file into line
+ std::vector<std::string> script_lines;
+ Str::split(script,script_lines,"\n");
+
+ NameValueVec used_variables;
+ int result = TestFixture::client().edit_script_submit(task_a->absNodePath(),used_variables,script_lines,true/*create alias*/,true/*run alias*/);
+ BOOST_REQUIRE_MESSAGE(result == 0, "Expected alias creation and run to succeed\n" << TestFixture::client().errorMsg());
+ std::string alias0_path = task_a->absNodePath() + "/alias0";
+
+ // Wait for alias to complete.
+ wait_for_alias_to_complete(alias0_path);
+
+//#ifdef DEBUG
+// BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0, "Could not get the defs from server\n" << TestFixture::client().errorMsg());
+// defs_ptr defs = TestFixture::client().defs();
+// PrintStyle::setStyle(PrintStyle::STATE);
+// std::cout << *defs;
+//#endif
+
+
+ // TEST ORDERING:: Create another alias, but don't run it. =============================================================================
+ result = TestFixture::client().edit_script_submit(task_a->absNodePath(),used_variables,script_lines,true/*create alias*/,false/*run alias*/);
+ BOOST_REQUIRE_MESSAGE(result == 0, "Expected alias creation succeed\n" << TestFixture::client().errorMsg());
+ {
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0, "Could not get the defs from server\n" << TestFixture::client().errorMsg());
+ defs_ptr defs = TestFixture::client().defs();
+ std::vector<alias_ptr> aliases;
+ defs->get_all_aliases(aliases);
+ BOOST_REQUIRE_MESSAGE(aliases.size() == 2, "Expected 2 aliases\n" << TestFixture::client().errorMsg());
+ }
+
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().order(alias0_path, NOrder::toString(NOrder::DOWN)) == 0, "Expected order NOrder::DOWN to succeed\n" << TestFixture::client().errorMsg());
+ {
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0, "Could not get the defs from server\n" << TestFixture::client().errorMsg());
+ defs_ptr defs = TestFixture::client().defs();
+ Task* task = defs->findAbsNode(task_a->absNodePath())->isTask();
+ BOOST_REQUIRE_MESSAGE( task,"expected to find Task");
+
+ std::vector<std::string> expected;
+ expected.push_back("alias1");
+ expected.push_back("alias0");
+ BOOST_REQUIRE_MESSAGE( toStrVec(task->aliases()) == expected,"NOrder::DOWN expected " << toString(expected) << " but found " << toString(toStrVec(task->aliases())) );
+ }
+
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().order(alias0_path, NOrder::toString(NOrder::UP)) == 0, "Expected order NOrder::UP to succeed\n" << TestFixture::client().errorMsg());
+ {
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0, "Could not get the defs from server\n" << TestFixture::client().errorMsg());
+ defs_ptr defs = TestFixture::client().defs();
+ Task* task = defs->findAbsNode(task_a->absNodePath())->isTask();
+ BOOST_REQUIRE_MESSAGE( task,"expected to find Task");
+
+ std::vector<std::string> expected;
+ expected.push_back("alias0");
+ expected.push_back("alias1");
+ BOOST_REQUIRE_MESSAGE( toStrVec(task->aliases()) == expected,"NOrder::UP expected " << toString(expected) << " but found " << toString(toStrVec(task->aliases())) );
+ }
+
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().order(alias0_path, NOrder::toString(NOrder::ORDER)) == 0, "Expected order NOrder::ORDER to succeed\n" << TestFixture::client().errorMsg());
+ {
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0, "Could not get the defs from server\n" << TestFixture::client().errorMsg());
+ defs_ptr defs = TestFixture::client().defs();
+ Task* task = defs->findAbsNode(task_a->absNodePath())->isTask();
+ BOOST_REQUIRE_MESSAGE( task,"expected to find Task");
+
+ std::vector<std::string> expected;
+ expected.push_back("alias1");
+ expected.push_back("alias0");
+ BOOST_REQUIRE_MESSAGE( toStrVec(task->aliases()) == expected,"NOrder::ORDER expected " << toString(expected) << " but found " << toString(toStrVec(task->aliases())) );
+ }
+
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().order(alias0_path, NOrder::toString(NOrder::ALPHA)) == 0, "Expected order NOrder::ALPHA to succeed\n" << TestFixture::client().errorMsg());
+ {
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0, "Could not get the defs from server\n" << TestFixture::client().errorMsg());
+ defs_ptr defs = TestFixture::client().defs();
+ Task* task = defs->findAbsNode(task_a->absNodePath())->isTask();
+ BOOST_REQUIRE_MESSAGE( task,"expected to find Task");
+
+ std::vector<std::string> expected;
+ expected.push_back("alias0");
+ expected.push_back("alias1");
+ BOOST_REQUIRE_MESSAGE( toStrVec(task->aliases()) == expected,"NOrder::ALPHA expected " << toString(expected) << " but found " << toString(toStrVec(task->aliases())) );
+ }
+
+
+ // TEST Alias DELETION =============================================================================
+ std::string alias1_path = task_a->absNodePath() + "/alias1";
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().delete_node(alias0_path) == 0, "delete alias0 failed\n" << TestFixture::client().errorMsg());
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().delete_node(alias1_path) == 0, "delete alias1 failed\n" << TestFixture::client().errorMsg());
+
+ // Get the defs from the server
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0, "Could not get the defs from server\n" << TestFixture::client().errorMsg());
+ defs_ptr defs = TestFixture::client().defs();
+ std::vector<alias_ptr> aliases;
+ defs->get_all_aliases(aliases);
+ BOOST_REQUIRE_MESSAGE(aliases.empty(), "Alias deletion falied\n" << TestFixture::client().errorMsg());
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Test/TestClkSync.cpp b/Test/TestClkSync.cpp
new file mode 100644
index 0000000..9a7ba1f
--- /dev/null
+++ b/Test/TestClkSync.cpp
@@ -0,0 +1,85 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #26 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/test/unit_test.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include "ServerTestHarness.hpp"
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "DurationTimer.hpp"
+
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( TestSuite )
+
+
+BOOST_AUTO_TEST_CASE( test_clk_sync )
+{
+ // This test is used to test sync'ing of the suite calendars
+ // The default clock type is *real*. We will create a suite with a hybrid clock attribute
+ // For the suite calendar, we do not persist the clock type(hybrid/real), since this can be
+ // obtained from the clock attribute. Hence a hybrid calendar in the server, will arrive as
+ // real calendar at the client side. (i.e via the memento). It is then up to the client
+ // to update the calendar with clock type stored in the clock attribute.
+ // See:void Suite::set_memento( const SuiteCalendarMemento* memento )
+ // This test(implicitly) will check that after an incremental sync that suite calendar and
+ // suite clock attribute, that both are of the same clock type.
+ // This is done in ServerTestHarness via invariant checking.
+
+ DurationTimer timer;
+ cout << "Test:: ...test_clk_sync "<< flush;
+ TestClean clean_at_start_and_end;
+
+ // Create the defs file corresponding to the text below
+ // ECF_HOME variable is automatically added by the test harness.
+ // ECF_INCLUDE variable is automatically added by the test harness.
+ // SLEEPTIME variable is automatically added by the test harness.
+ // ECF_CLIENT_EXE_PATH variable is automatically added by the test harness.
+ // This is substituted in ecf includes
+ // Allows test to run without requiring installation
+
+ //# Note: we have to use relative paths, since these tests are relocatable
+ // suite test_clk_sync
+ // clocl hybrid
+ // task a
+ // meter myMeter 0 100
+ // endsuite
+ Defs theDefs;
+ {
+ suite_ptr suite = theDefs.add_suite("test_clk_sync" );
+ suite->addClock(ClockAttr(true)); // add hybrid clock
+ task_ptr task_a = suite->add_task("a");
+ task_a->addMeter( Meter("myMeter",0,100,100) );
+ }
+
+ // The test harness will create corresponding directory structure & default ecf file
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_clk_sync.def"));
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Test/TestComplete.cpp b/Test/TestComplete.cpp
new file mode 100644
index 0000000..a00fea8
--- /dev/null
+++ b/Test/TestComplete.cpp
@@ -0,0 +1,178 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #25 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include "ServerTestHarness.hpp"
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "DurationTimer.hpp"
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/test/unit_test.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( TestSuite )
+
+// In the test case we will dynamically create all the test data.
+// The data is created dynamically so that we can stress test the server
+// This test does not have any time dependencies in the def file.
+//
+// This test shows the use of repeat and complete. this shows how
+// we can repeat a family without waiting for all the children to
+// complete. See page 65 of user manual
+//
+// As protection against user, a family should not complete
+// if any of its children are still in ACTIVE or SUBMIITED state.
+//
+// **************************************************************************
+// Note: When we use a complete expression. Node resolution will set complete
+// hierarchically
+// **************************************************************************
+BOOST_AUTO_TEST_CASE( test_complete )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_complete " << flush;
+ TestClean clean_at_start_and_end;
+
+ // Create the defs file corresponding to the text below
+ // ECF_HOME variable is automatically added by the test harness.
+ // ECF_INCLUDE variable is automatically added by the test harness.
+ // SLEEPTIME variable is automatically added by the test harness.
+ // ECF_CLIENT_EXE_PATH variable is automatically added by the test harness.
+ // This is substituted in sms includes
+ // Allows test to run without requiring installation
+
+ //# Note: we have to use relative paths, since these tests are relocatable
+ // suite test_complete
+ // family family
+ // repeat integer YMD 0 1
+ // complete ./family/check:nofiles # repeat family with waiting for children to complete
+ // task check
+ // event 1 nofiles
+ // task t1
+ // trigger check==complete
+ // task t2
+ // trigger t2 == complete # never runs
+ // endfamily
+ // endsuite
+ std::string eventName = "nofiles";
+ Defs theDefs;
+ {
+ suite_ptr suite = theDefs.add_suite("test_complete");
+ family_ptr fam = suite->add_family("family");
+ fam->addRepeat( RepeatInteger("VAR",0,1,1)); // repeat family 2 times
+ fam->add_complete( "/test_complete/family/check:nofiles" );
+ fam->addVerify( VerifyAttr(NState::COMPLETE,2) ); // family should complete 2 times
+
+ task_ptr task_check = fam->add_task("check");
+ task_check->addEvent( Event(1,eventName) );
+ task_check->addVerify( VerifyAttr(NState::COMPLETE,4) );
+
+ task_ptr task_t1 = fam->add_task("t1");
+ task_t1->add_trigger( "check == complete");
+ task_t1->addVerify( VerifyAttr(NState::COMPLETE,2) );
+
+ task_ptr task_t2 = fam->add_task("t2");
+ task_t2->add_trigger( "t2 == complete" );
+ task_t2->addVerify( VerifyAttr(NState::COMPLETE,2) );
+ }
+
+ // The test harness will create corresponding directory structure & default ecf file
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs, ServerTestHarness::testDataDefsLocation("test_complete.def") );
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_CASE( test_complete_does_not_hold )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_complete_does_not_hold " << flush;
+
+ /// This test shows that a complete expression should not hold a node
+ /// A complete should complete a node, and not hold it
+
+ // suite test_complete
+ // family family
+ // complete 1 == 0 # impossible expression that never evaluates
+ // task t1 # task t1 should still run
+ // task t2
+ // complete 1 == 0 # impossible expression that never evaluates
+ // trigger t1 == complete # task t2 should still run
+ // endfamily
+ // endsuite
+ Defs theDefs;
+ {
+ suite_ptr suite = theDefs.add_suite("test_complete_does_not_hold");
+ family_ptr fam = suite->add_family("family");
+ fam->add_complete( "1 == 0");
+ task_ptr t1 = fam->add_task("t1");
+ t1->addVerify( VerifyAttr(NState::COMPLETE,1) );
+ task_ptr t2 = fam->add_task("t2");
+ t2->add_trigger( "t1 == complete");
+ t2->add_complete( "1 == 0");
+ t2->addVerify( VerifyAttr(NState::COMPLETE,1) );
+ }
+
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs, ServerTestHarness::testDataDefsLocation("test_complete_does_not_hold.def") );
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_CASE( test_complete_with_empty_family )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_complete_with_empty_family " << flush;
+
+ // Test a family with a complete expression and that has no children
+
+ // suite test_complete_with_empty_family
+ // family empty
+ // complete /test_complete_with_empty_family/family/t1 == complete and
+ // /test_complete_with_empty_family/family/t2 == complete
+ // family family
+ // task t1
+ // task t2
+ // endfamily
+ // endsuite
+ Defs theDefs;
+ {
+ suite_ptr suite = theDefs.add_suite("test_complete_with_empty_family");
+ family_ptr empty = suite->add_family("empty");
+ empty->add_complete( "/test_complete_with_empty_family/family/t1 == complete and /test_complete_with_empty_family/family/t2 == complete");
+ empty->addVerify( VerifyAttr(NState::COMPLETE,1) );
+ family_ptr fam = suite->add_family("family");
+ fam->add_task("t1")->addVerify( VerifyAttr(NState::COMPLETE,1) );
+ fam->add_task("t2")->addVerify( VerifyAttr(NState::COMPLETE,1) );
+ }
+
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs, ServerTestHarness::testDataDefsLocation("test_complete_with_empty_family.def") );
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Test/TestCron.cpp b/Test/TestCron.cpp
new file mode 100644
index 0000000..d5c2174
--- /dev/null
+++ b/Test/TestCron.cpp
@@ -0,0 +1,145 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #30 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/test/unit_test.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include "ServerTestHarness.hpp"
+#include "TestFixture.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "DurationTimer.hpp"
+#include "AssertTimer.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+
+BOOST_AUTO_TEST_SUITE( TestSuite )
+
+
+static void wait_for_cron( int max_time_to_wait, const std::string& path)
+{
+ AssertTimer assertTimer(max_time_to_wait,false); // Bomb out after n seconds, fall back if test fail
+ TestFixture::client().set_throw_on_error( false );
+ while (1) {
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0, "sync_local failed should return 0\n" << TestFixture::client().errorMsg());
+ defs_ptr defs = TestFixture::client().defs();
+ if (defs) {
+ node_ptr node = defs->findAbsNode(path);
+ BOOST_REQUIRE_MESSAGE(node, "Could not find task at path " << path );
+ if (node) {
+ const std::vector<VerifyAttr>& verifys = node->verifys();
+ BOOST_REQUIRE_MESSAGE(verifys.size() == 1,"Expected 1 verify");
+ if (!verifys.empty()) {
+ if ( verifys[0].actual() == verifys[0].expected()) {
+ break;
+ }
+ }
+ }
+ }
+ // make sure test does not take too long.
+ if ( assertTimer.duration() >= assertTimer.timeConstraint() ) {
+ BOOST_REQUIRE_MESSAGE(assertTimer.duration() < assertTimer.timeConstraint(),
+ "wait_for_cron: Test wait " << assertTimer.duration() <<
+ " taking longer than time constraint of " << assertTimer.timeConstraint() <<
+ " aborting\n" << *defs);
+ break;
+ }
+ sleep(1);
+ }
+}
+
+
+BOOST_AUTO_TEST_CASE( test_cron_time_series )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_cron_time_series " << flush;
+ TestClean clean_at_start_and_end;
+
+ // SLOW SYSTEMS
+ // for each time attribute leave GAP of 3 * job submission interval
+ // on slow systems submitted->active->complete > TestFixture::job_submission_interval()
+ // Also the task duration must be greater than job_submission_interval, otherwise
+ // we will get multiple invocation for the same time step
+
+ //# Note: we have to use relative paths, since these tests are relocatable
+ //suite test_cron_time_series
+ // edit SLEEPTIME 1
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // clock real <todays date>
+ // family family
+ // task t1
+ // cron <start> <finish> <incr>
+ // endfamily
+ //endsuite
+ Defs theDefs;
+ std::string path;
+ {
+ // Initialise clock with todays date and time, then create a cron attribute
+ // with a time series, so that task runs 3 times
+
+ // Note: we don't use:
+ // boost::posix_time::ptime theLocalTime = Calendar::second_clock_time();
+ // Because this can fail with:
+ // Test:: ...test_cron_time_series unknown location(0): fatal error in
+ // "test_cron_time_series": std::out_of_range:
+ // TimeSeries::TimeSeries: Invalid time series: Start time(23:58) is greater than end time(00:02)
+ // i.e
+ // if the test is started at 23:58, then adding the end time of by doing start_time + 5 will fail the check
+ boost::posix_time::ptime theLocalTime = boost::posix_time::ptime(date(2010,6,21),time_duration(10,0,0));
+ boost::posix_time::ptime time1 = theLocalTime + minutes(1);
+ boost::posix_time::ptime time2 = theLocalTime + minutes(5);
+
+ suite_ptr suite = theDefs.add_suite("test_cron_time_series");
+ ClockAttr clockAttr(theLocalTime, false);
+ suite->addClock( clockAttr );
+
+ family_ptr fam = suite->add_family("family");
+ task_ptr task = fam->add_task("t");
+ task->addVerify( VerifyAttr(NState::COMPLETE,3) ); // task should complete 3 times
+
+ CronAttr cronAttr;
+ cronAttr.addTimeSeries( ecf::TimeSlot(time1.time_of_day()),
+ ecf::TimeSlot(time2.time_of_day()),
+ ecf::TimeSlot(0,2) );
+ task->addCron( cronAttr);
+
+ path = task->absNodePath();
+ }
+
+ // The test harness will create corresponding directory structure
+ // and populate with standard ecf files.
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.add_default_sleep_time(false); // avoid missing time steps due to submit->active->complete > job submission interval
+ serverTestHarness.run(theDefs, ServerTestHarness::testDataDefsLocation("test_cron_time_series.def"),1 /* timeout ignored*/, false /*waitForTestCompletion*/);
+
+ // crons are *infinite*, just wait for cron to complete 3 times
+ wait_for_cron(40,path);
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/Test/TestCtsWaitCmd.cpp b/Test/TestCtsWaitCmd.cpp
new file mode 100644
index 0000000..f309d78
--- /dev/null
+++ b/Test/TestCtsWaitCmd.cpp
@@ -0,0 +1,216 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #11 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/test/unit_test.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include "ServerTestHarness.hpp"
+#include "TestFixture.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "DurationTimer.hpp"
+#include "AssertTimer.hpp"
+
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( TestSuite )
+
+static void create_defs(Defs& theDefs, const std::string& suite_name)
+{
+ // suite test_wait_cmd
+ // family family0
+ // task wait
+ // family family1
+ // task a
+ // task b
+ // endfamily
+ // family family2
+ // task aa
+ // task bb
+ // endfamily
+ // endsuite
+ suite_ptr suite = theDefs.add_suite(suite_name);
+ family_ptr fam0 = suite->add_family("family0");
+ task_ptr wait = fam0->add_task("wait");
+ wait->addVerify( VerifyAttr(NState::COMPLETE,1) ); // task should complete 1 times
+
+ family_ptr fam1 = suite->add_family("family1");
+ fam1->add_task( "a" );
+ fam1->add_task( "b" );
+
+ family_ptr fam2 = suite->add_family("family2");
+ fam2->add_task( "aa" );
+ fam2->add_task( "bb" );
+}
+
+static bool wait_for_state(
+ std::vector< std::pair<std::string,NState::State> >& path_state_vec,
+ int max_time_to_wait )
+{
+ AssertTimer assertTimer(max_time_to_wait,false); // Bomb out after n seconds, fall back if test fail
+ while (1) {
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0, "sync_local failed should return 0\n" << TestFixture::client().errorMsg());
+ defs_ptr defs = TestFixture::client().defs();
+ bool all_states_ok = true;
+ for(size_t i =0; i < path_state_vec.size(); ++i) {
+ node_ptr node = defs->findAbsNode( path_state_vec[i].first );
+ BOOST_REQUIRE_MESSAGE(node,"Could not find path '" << path_state_vec[i].first << "' in the defs\n" << *defs);
+ if (node->state() != path_state_vec[i].second) {
+ all_states_ok = false;
+ break;
+ }
+ }
+ if (all_states_ok) return true;
+
+ // make sure test does not take too long.
+ if ( assertTimer.duration() >= assertTimer.timeConstraint() ) {
+ BOOST_REQUIRE_MESSAGE(assertTimer.duration() < assertTimer.timeConstraint(),
+ "wait_for_state: Test wait " << assertTimer.duration() <<
+ " taking longer than time constraint of " << assertTimer.timeConstraint() <<
+ " aborting\n" << *defs);
+ break;
+ }
+ sleep(1);
+ }
+ return false;
+}
+
+// Test the wait command. The Wait command is a child command.
+// The wait command is provided an expression. This expression is evaluated
+// in the server. If the evaluate returns false then the client should
+// blocks until the evaluation is true.
+// In this case the job associated with task 'wait' should block until the expression evaluates
+// to true, which should be after the completion of all other tasks
+BOOST_AUTO_TEST_CASE( test_wait_cmd )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_wait_cmd "<< flush;
+ TestClean clean_at_start_and_end;
+
+ Defs theDefs;
+ create_defs(theDefs,"test_wait_cmd");
+
+ // Create a custom sms file for test_wait_cmd/family0/wait to invoke the child wait command
+ // with an expression that forces it to block, until all other tasks complete
+ std::string templateEcfFileForWait;
+ templateEcfFileForWait += "%include <head.h>\n";
+ templateEcfFileForWait += "\n";
+ templateEcfFileForWait += "echo do some work\n";
+ templateEcfFileForWait += "%ECF_CLIENT_EXE_PATH% --wait=\"../family1/a eq complete and ../family1/b eq complete and ../family2/aa eq complete and ../family2/bb eq complete\"\n";
+ templateEcfFileForWait += "\n";
+ templateEcfFileForWait += "%include <tail.h>\n";
+
+ // The test harness will create corresponding directory structure
+ // Override the default ECF_ file, with our custom ECF_ file
+ std::map<std::string,std::string> taskEcfFileMap;
+ taskEcfFileMap.insert(std::make_pair(TestFixture::taskAbsNodePath(theDefs,"wait"),templateEcfFileForWait));
+
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_wait_cmd.def"), taskEcfFileMap);
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_CASE( test_wait_cmd_parse_fail )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_wait_cmd_parse_fail "<< flush;
+
+ // This time we add a wait expression that
+ // should fail to parse, and we should return an error
+ // The error should captured by the trap in .ecf script, which will
+ // then abort the task
+ Defs theDefs;
+ create_defs(theDefs,"test_wait_cmd_parse_fail");
+
+ // Create a custom ecf file for test_wait_cmd/family0/wait to invoke the child wait command
+ std::string templateEcfFileForWait;
+ templateEcfFileForWait += "%include <head.h>\n";
+ templateEcfFileForWait += "\n";
+ templateEcfFileForWait += "echo do some work\n";
+ templateEcfFileForWait += "%ECF_CLIENT_EXE_PATH% --wait=\"(((((((((../family1/a eq complete and ../family1/b eq complete and ../family2/aa eq complete and ../family2/bb eq complete\"\n";
+ templateEcfFileForWait += "\n";
+ templateEcfFileForWait += "%include <tail.h>\n";
+
+ std::map<std::string,std::string> taskEcfFileMap;
+ taskEcfFileMap.insert(std::make_pair(TestFixture::taskAbsNodePath(theDefs,"wait"),templateEcfFileForWait));
+
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_wait_cmd_parse_fail.def"), taskEcfFileMap,1 /*timeout*/, false/* don't wait for test to finish */);
+
+ // wait for family1 and family2 to complete
+ std::vector< std::pair<std::string,NState::State> > path_state_vec;
+ path_state_vec.push_back( std::make_pair( std::string("/test_wait_cmd_parse_fail/family1"), NState::COMPLETE) );
+ path_state_vec.push_back( std::make_pair( std::string("/test_wait_cmd_parse_fail/family2"), NState::COMPLETE) );
+ wait_for_state(path_state_vec,10);
+
+ // wait for 'wait' task to abort
+ path_state_vec.clear();
+ path_state_vec.push_back( std::make_pair( std::string("/test_wait_cmd_parse_fail/family0/wait"), NState::ABORTED) );
+ wait_for_state(path_state_vec,10);
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_CASE( test_wait_cmd_non_existant_paths )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_wait_cmd_non_existant_paths "<< flush;
+
+ // This time we add a wait expression that should fail
+ // because the paths referenced in the expression don't exist
+ Defs theDefs;
+ create_defs(theDefs,"test_wait_cmd_non_existant_paths");
+
+ // Create a custom ecf file for test_wait_cmd/family0/wait to invoke the child wait command
+ // NOTE: ../family1/FRED does not exist
+ std::string templateEcfFileForWait;
+ templateEcfFileForWait += "%include <head.h>\n";
+ templateEcfFileForWait += "\n";
+ templateEcfFileForWait += "echo do some work\n";
+ templateEcfFileForWait += "%ECF_CLIENT_EXE_PATH% --wait=\"../family1/FRED eq complete and ../family1/b eq complete and ../family2/aa eq complete and ../family2/bb eq complete\"\n";
+ templateEcfFileForWait += "\n";
+ templateEcfFileForWait += "%include <tail.h>\n";
+
+ std::map<std::string,std::string> taskEcfFileMap;
+ taskEcfFileMap.insert(std::make_pair(TestFixture::taskAbsNodePath(theDefs,"wait"),templateEcfFileForWait));
+
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_wait_cmd_non_existant_paths.def"), taskEcfFileMap,1 /*timeout*/, false/* don't wait for test to finish */);
+
+ // wait for family1 and family2 to complete
+ std::vector< std::pair<std::string,NState::State> > path_state_vec;
+ path_state_vec.push_back( std::make_pair( std::string("/test_wait_cmd_non_existant_paths/family1"), NState::COMPLETE) );
+ path_state_vec.push_back( std::make_pair( std::string("/test_wait_cmd_non_existant_paths/family2"), NState::COMPLETE) );
+ wait_for_state(path_state_vec,10);
+
+ // wait for 'wait' task to abort
+ path_state_vec.clear();
+ path_state_vec.push_back( std::make_pair( std::string("/test_wait_cmd_non_existant_paths/family0/wait"), NState::ABORTED) );
+ wait_for_state(path_state_vec,10);
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Test/TestEvents.cpp b/Test/TestEvents.cpp
new file mode 100644
index 0000000..721b2af
--- /dev/null
+++ b/Test/TestEvents.cpp
@@ -0,0 +1,107 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #26 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/test/unit_test.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include "ServerTestHarness.hpp"
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "DurationTimer.hpp"
+
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( TestSuite )
+
+// In the test case we will dynamically create all the test data.
+// The data is created dynamically so that we can stress test the server
+// This test does not have any time dependencies in the def file.
+
+BOOST_AUTO_TEST_CASE( test_events )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_events "<< flush;
+ TestClean clean_at_start_and_end;
+
+ // Create the defs file corresponding to the text below
+ // ECF_HOME variable is automatically added by the test harness.
+ // ECF_INCLUDE variable is automatically added by the test harness.
+ // SLEEPTIME variable is automatically added by the test harness.
+ // ECF_CLIENT_EXE_PATH variable is automatically added by the test harness.
+ // This is substituted in sms includes
+ // Allows test to run without requiring installation
+
+ //# Note: we have to use relative paths, since these tests are relocatable
+ // suite test_events
+ // family family1
+ // task a
+ // event 1 myEvent
+ // meter myMeter 0 100
+ // task b
+ // trigger a == complete
+ // endfamily
+ // family family2
+ // task aa
+ // trigger ../family1/a:myMeter >= 90 and ../family1/a:myEvent
+ // task bb
+ // trigger ../family1/a:myMeter >= 50 or ../family1/a:myEvent
+ // endfamily
+ // endsuite
+ Defs theDefs;
+ {
+ suite_ptr suite = theDefs.add_suite("test_events" );
+ {
+ family_ptr fam = suite->add_family("family1");
+ task_ptr task_a = fam->add_task("a");
+ task_ptr task_b = fam->add_task("b");
+ task_a->addMeter( Meter("myMeter",0,100,100) ); // ServerTestHarness will add correct ecf
+ task_a->addEvent( Event(1,"myEvent") ); // ServerTestHarness will add correct ecf
+ task_a->addLabel( Label("task_a_label","Label1") ); // ServerTestHarness will add correct ecf
+ task_a->addVerify( VerifyAttr(NState::COMPLETE,1) );
+
+ task_b->add_trigger( "a == complete" );
+ task_b->addLabel( Label("task_b_label","label1 label2") ); // ServerTestHarness will add correct ecf
+ task_b->addVerify( VerifyAttr(NState::COMPLETE,1) );
+ }
+ {
+ family_ptr fam2 = suite->add_family("family2");
+ task_ptr task_aa = fam2->add_task("aa");
+ task_ptr task_bb = fam2->add_task("bb");
+ task_aa->add_trigger( "../family1/a:myMeter >= 90 and ../family1/a:myEvent");
+ task_aa->addVerify( VerifyAttr(NState::COMPLETE,1) );
+ task_bb->add_trigger( "../family1/a:myMeter >= 50 or ../family1/a:myEvent" );
+ task_bb->addVerify( VerifyAttr(NState::COMPLETE,1) );
+ }
+ //cout << theDefs;
+ }
+
+ // The test harness will create corresponding directory structure & default ecf file
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_events.def"));
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Test/TestFileCmd.cpp b/Test/TestFileCmd.cpp
new file mode 100644
index 0000000..50bc194
--- /dev/null
+++ b/Test/TestFileCmd.cpp
@@ -0,0 +1,132 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #23 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : This is used to INVOKE a SINGLE test. Easier for debugging
+//============================================================================
+#include <iostream>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/lexical_cast.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include "ServerTestHarness.hpp"
+#include "TestFixture.hpp"
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "DurationTimer.hpp"
+#include "ClientToServerCmd.hpp"
+#include "File.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( TestSuite )
+
+BOOST_AUTO_TEST_CASE( test_file_cmd )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_file_cmd " << flush;
+ TestClean clean_at_start_and_end;
+
+ // Create the defs file corresponding to the text below
+ // ECF_HOME variable is automatically added by the test harness.
+ // ECF_INCLUDE variable is automatically added by the test harness.
+ // SLEEPTIME variable is automatically added by the test harness.
+ // ECF_CLIENT_EXE_PATH variable is automatically added by the test harness.
+ // This is substituted in sms includes
+ // Allows test to run without requiring installation
+
+ //# Note: we have to use relative paths, since these tests are relocate-able
+ //suite test_file_cmd
+ // edit SLEEPTIME 1
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // family family
+ // task t1
+ // task t2
+ // endfamily
+ //endsuite
+
+ Defs theDefs;
+ {
+ suite_ptr suite = theDefs.add_suite("test_file_cmd");
+ suite->addVerify( VerifyAttr(NState::COMPLETE,1) );
+ family_ptr fam = suite->add_family("family");
+ int taskSize = 2; // on linux 1024 tasks take ~4 seconds for job submission
+ for(int i=0; i < taskSize; i++) {
+ task_ptr task = fam->add_task("t" + boost::lexical_cast<std::string>(i));
+ task->addVerify( VerifyAttr(NState::COMPLETE,1) );
+ }
+ }
+
+ // The test harness will create corresponding directory structure
+ // and populate with standard ecf files AND will generate man files for node containers
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.generateManFileForNodeContainers();
+ serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_file_cmd.def"));
+
+ // Now invoke the file command to extract <ecffile,job file,job output, manual >
+ // If the requests succeeded the client needs to create a temporary file, and populate it with
+ // the contents of the string returned from the server
+ TestFixture::client().set_throw_on_error(false);
+
+ std::vector<Node*> nodeVec;
+ theDefs.getAllNodes(nodeVec);
+
+ BOOST_FOREACH(Node* node, nodeVec) {
+
+ string nodePath = node->absNodePath();
+ std::vector<CFileCmd::File_t> fileTypesVec = CFileCmd::fileTypesVec();
+ for(size_t i = 0; i < fileTypesVec.size(); i++) {
+
+ string file_type = CFileCmd::toString(fileTypesVec[i]);
+ std::vector<std::string> theArgs = CtsApi::file(nodePath,file_type,"10000");
+ std::string args; for(size_t x = 0; x < theArgs.size(); x++) { args += theArgs[x]; args += " "; }
+
+ int theResult = TestFixture::client().file(nodePath,file_type,"10000");
+// cout << "nodePath = " << nodePath << " fileType = " << file_type << " args passed = " << args << " pass = " << theResult << "\n";
+
+ /// Expect KILL and STAT file types to fail, i.e since we have not called those commands
+ if (fileTypesVec[i] == CFileCmd::KILL || fileTypesVec[i] == CFileCmd::STAT) {
+ BOOST_CHECK_MESSAGE( theResult == 1,args << " Expected " << CFileCmd::toString(fileTypesVec[i]) << " to fail");
+ continue;
+ }
+
+ if (node->isSubmittable() || fileTypesVec[i] == CFileCmd::MANUAL) {
+ // For suite and families only manual is valid
+ BOOST_CHECK_MESSAGE( theResult == 0,args << " failed for Node should return 0.\n" << TestFixture::client().errorMsg());
+ BOOST_CHECK_MESSAGE( !TestFixture::client().get_string().empty()," file contents empty for " << args );
+ }
+ else {
+ // Should fail
+ BOOST_CHECK_MESSAGE( theResult != 0, args << " Expected failure for node " << node->debugNodePath() << " with file= " << CFileCmd::toString(fileTypesVec[i]) );
+ if (theResult == 0 ) {
+ std::cout << "Found file contents:''\n";
+ std::cout << TestFixture::client().get_string();
+ std::cout << "''\n";
+ }
+ }
+ }
+ }
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/Test/TestHandle.cpp b/Test/TestHandle.cpp
new file mode 100644
index 0000000..921e51f
--- /dev/null
+++ b/Test/TestHandle.cpp
@@ -0,0 +1,390 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #22 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : This is used to INVOKE a SINGLE test.
+// Making it easier for Easier for debugging and development
+//============================================================================
+#include <iostream>
+#include <limits> // for std::numeric_limits<int>::max()
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/lexical_cast.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include "TestFixture.hpp"
+#include "ServerTestHarness.hpp"
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "DurationTimer.hpp"
+#include "PrintStyle.hpp"
+#include "ClientToServerCmd.hpp"
+#include "DefsStructureParser.hpp"
+#include "AssertTimer.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( TestSuite )
+
+//static void dump_suites_and_handles(ClientInvoker& theClient, const std::string& title)
+//{
+// std::cout << title;
+// TestFixture::client().suites();
+// {
+// const std::vector<std::string>& suites = TestFixture::client().server_reply().get_string_vec();
+// BOOST_FOREACH(const std::string& suite, suites) { std::cout << "\n---> " << suite; }
+// std::cout << "\n";
+//
+// const std::vector<std::pair<unsigned int, std::vector<std::string> > >& handles = TestFixture::client().server_reply().get_client_handle_suites();
+// std::pair<unsigned int, std::vector<std::string> > int_str_pair;
+// for(size_t i =0; i < handles.size(); i++) {
+// std::cout << "handle: " << handles[i].first << " : ";
+// BOOST_FOREACH(const std::string& suite, handles[i].second) {
+// std::cout << suite << " ";
+// }
+// std::cout << "\n";
+// }
+// }
+// std::cout << "\n";
+//}
+
+BOOST_AUTO_TEST_CASE( test_handle )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_handle " << flush;
+ TestClean clean_at_start_and_end;
+
+ Defs theDefs; {
+ for(int s = 0; s < 7; s++) {
+ suite_ptr suite = theDefs.add_suite("s" + boost::lexical_cast<std::string>(s));
+ suite->addDefStatus(DState::SUSPENDED); // NO NEED to run jobs for this test:
+ for(int t = 0; t < 2; t++) { suite->add_task("t" + boost::lexical_cast<std::string>(t)); }
+ }
+ }
+
+ // The test harness will create corresponding directory structure & default ecf file
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,
+ ServerTestHarness::testDataDefsLocation("test_handle.def"),
+ 1 /*timeout*/,
+ false/* don't wait for test to finish */);
+
+ std::vector<std::string> suites_s0_s1_s2; suites_s0_s1_s2.push_back("s0"); suites_s0_s1_s2.push_back("s1"); suites_s0_s1_s2.push_back("s2");
+ std::vector<std::string> suites_s3_s4; suites_s3_s4.push_back("s3"); suites_s3_s4.push_back("s4");
+ std::vector<std::string> suites_s0_s1_s2_s3_s4; suites_s0_s1_s2_s3_s4.push_back("s0"); suites_s0_s1_s2_s3_s4.push_back("s1"); suites_s0_s1_s2_s3_s4.push_back("s2"),suites_s0_s1_s2_s3_s4.push_back("s3"),suites_s0_s1_s2_s3_s4.push_back("s4");;
+ std::vector<std::pair<unsigned int, std::vector<std::string> > > ch_suites;
+
+ {
+ // register suites s0,s1,s2
+ TestFixture::client().ch_register(false/*add new suites to handle*/,suites_s0_s1_s2);
+
+ // get the handle associated with the registered suites
+ unsigned int client_handle = TestFixture::client().server_reply().client_handle();
+
+ // Check the sync_local() does a full sync for our handle
+ TestFixture::client().sync_local();
+ BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().in_sync(),"Expected to be in sync after syn_local()");
+ BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().full_sync(),"Expected a full_sync() after registering");
+
+ // Now check the suites were registered, correctly
+ TestFixture::client().ch_suites();
+ ch_suites = TestFixture::client().server_reply().get_client_handle_suites();
+ BOOST_CHECK_MESSAGE(!ch_suites.empty(),"Expected to have registered suites");
+ BOOST_CHECK_MESSAGE(ch_suites.size() == 1,"Expected to have registered a single set");
+ BOOST_CHECK_MESSAGE(ch_suites[0].first == client_handle,"Expected first client handle to be: " << client_handle << ", but found " << ch_suites[0].first);
+ BOOST_CHECK_MESSAGE(ch_suites[0].second == suites_s0_s1_s2,"Expected suites s0,s1,s2");
+
+ // Now drop the handle and Check handle was dropped
+ TestFixture::client().ch_drop(client_handle);
+ TestFixture::client().ch_suites();
+ BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().get_client_handle_suites().empty(),"Expected to have no registered suites");
+ }
+
+ {
+ // register suites s0,s1,s2
+ TestFixture::client().ch_register(false/*add new suites to handle*/,suites_s0_s1_s2);
+
+ // get the handle associated with the registered suites
+ unsigned int client_handle = TestFixture::client().server_reply().client_handle();
+ BOOST_CHECK_MESSAGE(client_handle == 1,"Expected to have handle 1");
+
+ // Check the sync_local() does a full sync for our handle. *THIS* should also clear the handle_changed flag
+ TestFixture::client().sync_local();
+ BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().in_sync(),"Expected to be in sync after syn_local()");
+ BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().full_sync(),"Expected a full_sync() after registering");
+
+
+ // add additional suites & check suites were added to our handle. Sync_local should returna full_sync()
+ std::vector<std::string> added_suites; added_suites.push_back("s3"); added_suites.push_back("s4");
+ TestFixture::client().ch_add(client_handle,added_suites);
+
+ TestFixture::client().ch_suites();
+ ch_suites = TestFixture::client().server_reply().get_client_handle_suites();
+ BOOST_CHECK_MESSAGE(!ch_suites.empty(),"Expected to have registered suites");
+ BOOST_CHECK_MESSAGE(ch_suites.size() == 1,"Expected to have registered a single set");
+ BOOST_CHECK_MESSAGE(ch_suites[0].first == client_handle,"Expected first client handle to be: " << client_handle << ", but found " << ch_suites[0].first);
+ BOOST_CHECK_MESSAGE(ch_suites[0].second == suites_s0_s1_s2_s3_s4,"Expected suites s0,s1,s2,s3,s4");
+
+ TestFixture::client().sync_local();
+ BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().full_sync(),"Expected a full_sync() after adding suites.");
+
+
+ // remove the added suites, and check they were removed
+ TestFixture::client().ch_remove(client_handle,added_suites);
+
+ TestFixture::client().ch_suites();
+ ch_suites = TestFixture::client().server_reply().get_client_handle_suites();
+ BOOST_CHECK_MESSAGE(!ch_suites.empty(),"Expected to have registered suites");
+ BOOST_CHECK_MESSAGE(ch_suites.size() == 1,"Expected to have registered a single set");
+ BOOST_CHECK_MESSAGE(ch_suites[0].first == client_handle,"Expected first client handle to be: " << client_handle << ", but found " << ch_suites[0].first);
+ BOOST_CHECK_MESSAGE(ch_suites[0].second == suites_s0_s1_s2,"Expected suites s0,s1,s2");
+
+ TestFixture::client().sync_local();
+ BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().full_sync(),"Expected a full_sync() after removing suites");
+
+ // Now drop the handle and check handle was dropped
+ TestFixture::client().ch_drop(client_handle);
+ TestFixture::client().ch_suites();
+ BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().get_client_handle_suites().empty(),"Expected to have no registered suites");
+ }
+
+ {
+ // register suites s0,s1,s2
+ TestFixture::client().ch_register(false/*add new suites to handle*/,suites_s0_s1_s2);
+
+ // register suite s3,s4
+ TestFixture::client().ch_register(false/*add new suites to handle*/,suites_s3_s4);
+
+ // get all the registered suites
+ TestFixture::client().ch_suites();
+ ch_suites = TestFixture::client().server_reply().get_client_handle_suites();
+ BOOST_CHECK_MESSAGE(!ch_suites.empty(),"Expected to have registered suites");
+ BOOST_CHECK_MESSAGE(ch_suites.size() == 2,"Expected to have 2 registered sets");
+ BOOST_CHECK_MESSAGE(ch_suites[0].first == 1,"Expected first client handle to be 1, but found " << ch_suites[0].first);
+ BOOST_CHECK_MESSAGE(ch_suites[0].second == suites_s0_s1_s2,"Expected suites s0,s1,s2, in first handle");
+ BOOST_CHECK_MESSAGE(ch_suites[1].first == 2,"Expected second client handle to be 2, but found " << ch_suites[1].first);
+ BOOST_CHECK_MESSAGE(ch_suites[1].second == suites_s3_s4,"Expected suites s3,s4 , in second handle");
+
+ // Drop all handles
+ for(size_t i = 0; i < ch_suites.size(); i++) TestFixture::client().ch_drop(ch_suites[i].first);
+ TestFixture::client().ch_suites();
+ BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().get_client_handle_suites().empty(),"Expected to have no registered suites");
+ }
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_CASE( test_handle_sync )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_handle_sync " << flush;
+ TestClean clean_at_start_and_end;
+
+ Defs theDefs; {
+ for(int s = 0; s < 7; s++) {
+ suite_ptr suite = theDefs.add_suite("s" + boost::lexical_cast<std::string>(s));
+ suite->addDefStatus(DState::SUSPENDED);
+ for(int t = 0; t < 2; t++) { suite->add_task("t" + boost::lexical_cast<std::string>(t)); }
+ }
+ }
+
+ // The test harness will create corresponding directory structure & default ecf file
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,
+ ServerTestHarness::testDataDefsLocation("test_handle_sync.def"),
+ 1 /*timeout*/,
+ false/* don't wait for test to finish */);
+
+ std::vector<std::string> suites_s0_s1_s2; suites_s0_s1_s2.push_back("s0"); suites_s0_s1_s2.push_back("s1"); suites_s0_s1_s2.push_back("s2");
+ std::vector<std::pair<unsigned int, std::vector<std::string> > > ch_suites;
+
+ {
+ // register suites s0,s1,s2
+ TestFixture::client().ch_register(false/*add new suites to handle*/,suites_s0_s1_s2);
+ unsigned int client_handle = TestFixture::client().server_reply().client_handle();
+ TestFixture::client().news_local();
+ BOOST_CHECK_MESSAGE(TestFixture::client().get_news(),"Expected news after registering");
+ TestFixture::client().sync_local(); // sync for any changes to get full update before test starts
+ BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().full_sync(),"Expected a full_sync() after registering");
+ BOOST_CHECK_MESSAGE(TestFixture::client().defs()->suiteVec().size() == 3,"Expected 3 suites back from sync, after registering 3 suites " << *TestFixture::client().defs());
+
+
+ // make a change to a suite not in our handle, that does not cause state propagation.
+ // State propagation changes the defs state. The defs state is sync regardless
+ TestFixture::client().suspend("/s3");
+ TestFixture::client().news_local();
+ BOOST_CHECK_MESSAGE(!TestFixture::client().get_news(),"Expected no change since suite s3 is not in our handle");
+
+ // make a change to a suite *not* in our handle, that *does* cause state propagation.
+ TestFixture::client().force("/s3/t0","aborted");
+ TestFixture::client().news_local();
+ BOOST_CHECK_MESSAGE(TestFixture::client().get_news(),"Expected change via state propagation to defs, even though s3 not in our handle");
+
+ TestFixture::client().sync_local();
+ BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().full_sync(),"Expected incremental change, not a full update");
+
+
+ // make a change to a suite in our handle
+ TestFixture::client().force("/s0","complete");
+ TestFixture::client().news_local();
+ BOOST_CHECK_MESSAGE(TestFixture::client().get_news(),"Expected news since state changed");
+
+ TestFixture::client().sync_local();
+ BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().full_sync(),"Expected incremental change, not a full update");
+
+ TestFixture::client().ch_drop(client_handle);
+ BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().get_client_handle_suites().empty(),"Expected to have no registered suites");
+ }
+
+ {
+ // register suites s0,s1,s2
+ TestFixture::client().ch_register(false/*add new suites to handle*/,suites_s0_s1_s2);
+ unsigned int client_handle = TestFixture::client().server_reply().client_handle();
+ TestFixture::client().news_local();
+ BOOST_CHECK_MESSAGE(TestFixture::client().get_news(),"Expected news after registering");
+ TestFixture::client().sync_local(); // sync for any changes to get full update before test starts
+ BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().full_sync(),"Expected a full_sync() after registering");
+
+
+ // make a small change to a suite *IN* our handle
+ TestFixture::client().force("/s1","complete");
+ TestFixture::client().sync_local();
+ BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().full_sync(),"Expected incremental change, not a full update");
+
+ // Change the order
+ TestFixture::client().order("/s0","alpha");
+ TestFixture::client().sync_local();
+ BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().full_sync(),"Expected incremental update");
+
+ TestFixture::client().ch_drop(client_handle);
+ TestFixture::client().suites();
+ BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().get_client_handle_suites().empty(),"Expected to have no registered suites");
+ }
+
+ {
+ // register suites s0,s1,s2
+ TestFixture::client().ch_register(false/*add new suites to handle*/,suites_s0_s1_s2);
+ unsigned int client_handle = TestFixture::client().server_reply().client_handle();
+ TestFixture::client().news_local();
+ BOOST_CHECK_MESSAGE(TestFixture::client().get_news(),"Expected news after registering");
+ TestFixture::client().sync_local(); // sync for any changes to get full update **before** test starts
+ BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().full_sync(),"Expected a full_sync() after registering");
+
+
+ // make a small change to a suite *IN* our handle
+ TestFixture::client().force("/s1","unknown");
+ TestFixture::client().sync_local();
+ BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().full_sync(),"Expected incremental change, not a full update");
+
+
+ // DELETE suite s2, i.e make a change that should force a *FULL* update
+ TestFixture::client().delete_node("/s2",true/*force*/);
+ TestFixture::client().news_local();
+ BOOST_CHECK_MESSAGE(TestFixture::client().get_news(),"Expected news after deleting node");
+ TestFixture::client().sync_local();
+ BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().full_sync(),"Expected full update");
+
+
+ // Check that suite s2 is STILL in our handle.
+ // delete suites STAY registered until they are explicitly deleted
+ TestFixture::client().ch_suites();
+ ch_suites = TestFixture::client().server_reply().get_client_handle_suites();
+ BOOST_CHECK_MESSAGE(ch_suites[0].second == suites_s0_s1_s2,"Expected suites s0,s1,s2, in handle");
+
+ TestFixture::client().ch_drop(client_handle);
+ TestFixture::client().ch_suites();
+ BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().get_client_handle_suites().empty(),"Expected to have no registered suites");
+ }
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+
+BOOST_AUTO_TEST_CASE( test_handle_add_remove_add )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_handle_add_remove_add " << flush;
+ TestClean clean_at_start_and_end;
+
+ defs_ptr theDefs = Defs::create(); {
+ for(int s = 0; s < 3; s++) {
+ suite_ptr suite = theDefs->add_suite("s" + boost::lexical_cast<std::string>(s));
+ suite->addDefStatus(DState::SUSPENDED); // NO NEED to run jobs for this test:
+ for(int t = 0; t < 2; t++) { suite->add_task("t" + boost::lexical_cast<std::string>(t)); }
+ }
+ }
+
+ // The test harness will create corresponding directory structure & default ecf file
+ // ADD
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(*theDefs,
+ ServerTestHarness::testDataDefsLocation("test_handle_sync.def"),
+ 1 /*timeout*/,
+ false/* don't wait for test to finish */);
+
+ TestFixture::client().set_throw_on_error( true );
+ std::vector<std::string> suites_s0_s1_s2; suites_s0_s1_s2.push_back("s0"); suites_s0_s1_s2.push_back("s1"); suites_s0_s1_s2.push_back("s2");
+
+ {
+ // register suites s0
+ TestFixture::client().ch_register(false/*add new suites to handle*/,suites_s0_s1_s2);
+ unsigned int client_handle = TestFixture::client().server_reply().client_handle();
+ BOOST_CHECK_MESSAGE(client_handle == 1 ,"Expected handle of value 1 but found " << client_handle );
+
+ // Get the registered suites
+ TestFixture::client().ch_suites();
+ BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().get_client_handle_suites().empty(),"Expected to have registered suites");
+
+
+ // Check the sync_local() does a full sync for our handle
+ TestFixture::client().sync_local();
+ BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().in_sync(),"Expected to be in sync after syn_local()");
+ BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().full_sync(),"Expected a full_sync() after registering");
+ BOOST_CHECK_MESSAGE(TestFixture::client().defs()->suiteVec().size() == 3,"Expected 3 suites back from sync " << *TestFixture::client().defs());
+
+
+ // DELETE suites. They should stay *registered*
+ TestFixture::client().delete_node("/s0");
+ TestFixture::client().delete_node("/s1");
+ TestFixture::client().delete_node("/s2");
+ TestFixture::client().sync_local();
+ BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().full_sync(),"Expected a full_sync() after deleting suite");
+ BOOST_CHECK_MESSAGE(TestFixture::client().defs()->suiteVec().size() == 0,"Expected 0 suites back from sync " << *TestFixture::client().defs());
+
+ // Check suites are still registered. Only explicit drop can remove registered suites
+ TestFixture::client().ch_suites();
+ BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().get_client_handle_suites().empty(),"Expected to have registered suites");
+
+
+ // RELOAD the defs, which includes s0,s1,s2:: THIS SHOULD GET RE_ADDED TO OUR EXISTING HANDLE's
+ // The handle references to the suites should get *refreshed*
+ TestFixture::client().load(theDefs);
+ TestFixture::client().sync_local();
+ BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().full_sync(),"Expected a full_sync() since client handle should be refreshed with new suite_pts");
+ BOOST_CHECK_MESSAGE(TestFixture::client().defs()->suiteVec().size() == 3,"Expected 3 suites back from sync " << *TestFixture::client().defs());
+
+ TestFixture::client().ch_drop(client_handle);
+ BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().get_client_handle_suites().empty(),"Expected to have no registered suites");
+ }
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Test/TestKillCmd.cpp b/Test/TestKillCmd.cpp
new file mode 100644
index 0000000..9426d16
--- /dev/null
+++ b/Test/TestKillCmd.cpp
@@ -0,0 +1,149 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #25 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : This is used to INVOKE a SINGLE test. Easier for debugging
+//============================================================================
+#include <iostream>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/lexical_cast.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include "ServerTestHarness.hpp"
+#include "TestFixture.hpp"
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "DurationTimer.hpp"
+#include "PrintStyle.hpp"
+#include "ClientToServerCmd.hpp"
+#include "AssertTimer.hpp"
+#include "File.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( TestSuite )
+
+// forward declare functions
+static bool kill_cmd(bool kill_task);
+static bool waitForTaskState(NState::State state, int max_time_to_wait);
+
+// test:: test the kill command. Create a task that runs a long time
+// The associated job is then killed. This should leave task in aborted state
+BOOST_AUTO_TEST_CASE( test_kill_cmd )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_kill_cmd " << flush;
+ TestClean clean_at_start_and_end;
+ BOOST_REQUIRE_MESSAGE(kill_cmd(true)," kill of task '/test_kill_cmd/family/t0' failed");
+ cout << timer.duration() << "\n";
+}
+
+BOOST_AUTO_TEST_CASE( test_hierarchical_kill_cmd )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_hierarchical_kill_cmd " << flush;
+ TestClean clean_at_start_and_end;
+ BOOST_REQUIRE_MESSAGE(kill_cmd(false),"kill of suite '/test_kill_cmd' failed");
+ cout << timer.duration() << "\n";
+}
+
+
+static bool kill_cmd(bool kill_task)
+{
+ /// Create dir location for log file.
+ std::string defs_location = ServerTestHarness::testDataDefsLocation("test_kill_cmd.def");
+ fs::path new_path = defs_location;
+ if (!fs::exists(new_path.parent_path())) {
+ File::createMissingDirectories(new_path.parent_path().string());
+ }
+
+ Defs theDefs;
+ std::string kill_path;
+ {
+ suite_ptr suite;
+ if (kill_task ) suite = theDefs.add_suite( "test_kill_task");
+ else suite = theDefs.add_suite( "test_kill_suite");
+ suite->addVariable( Variable("ECF_TRIES","1") ); // do not try again
+ family_ptr fam = suite->add_family( "family" );
+ task_ptr task = fam->add_task( "t0");
+ task->addMeter( Meter("meter",0,200,100) ); // Make sure it run long enough, to receive kill, on slow systems
+ task->addVerify( VerifyAttr(NState::ABORTED,1) );// task should abort 1 times
+ if (kill_task) kill_path = task->absNodePath();
+ else kill_path = suite->absNodePath();
+ }
+
+ // *******************************************************************
+ // Important: The following will *not* work:
+ // theDefs.set_server().add_or_update_variables("ECF_TRIES","1"); // Override ECF_TRIES so don't try to restart aborted jobs
+ // theDefs.set_server().add_or_update_variables("ECF_KILL_CMD","kill -15 %ECF_RID%"); // Provide a mechanism to kill the running job
+ // Since calling the begin command in the server,
+ // will update the defs with the server environment, and hence overriding
+ // any env variable of the same name, set here. Hence just use addVariable as above.
+ // *************************************************************************
+ // cout << theDefs << "\n";
+
+ // cout << "test_kill_cmd Start test\n";
+ // The test harness will create corresponding directory structure & default ecf file
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,defs_location,1 /*timeout*/, false/* don't wait for test to finish */);
+
+
+ // cout << "test_kill_cmd Waiting for task to become active\n";
+ TestFixture::client().set_throw_on_error(false);
+ (void)waitForTaskState(NState::ACTIVE,10);
+
+
+ // cout << "test_kill_cmd Now kill the active jobs\n";
+ BOOST_REQUIRE_MESSAGE( TestFixture::client().kill(kill_path) == 0,CtsApi::to_string(CtsApi::kill(kill_path)) << " failed should return 0.\n" << TestFixture::client().errorMsg());
+
+
+ // cout << "test_kill_cmd Wait for the task to be aborted\n";
+ return waitForTaskState(NState::ABORTED,20 );
+}
+
+static bool waitForTaskState(NState::State state, int max_time_to_wait)
+{
+ AssertTimer assertTimer(max_time_to_wait,false); // Bomb out after n seconds, fall back if test fail
+ while (1) {
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0, "sync_local failed should return 0\n" << TestFixture::client().errorMsg());
+ defs_ptr defs = TestFixture::client().defs();
+ vector<Task*> tasks; defs->getAllTasks(tasks);
+ BOOST_FOREACH(Task* task, tasks) {
+ if (task->state() == state) {
+ return true;
+ }
+ }
+
+ // make sure test does not take too long.
+ if ( assertTimer.duration() >= assertTimer.timeConstraint() ) {
+ BOOST_REQUIRE_MESSAGE(assertTimer.duration() < assertTimer.timeConstraint(),
+ "waitForTaskState " << NState::toString(state) << " Test wait " << assertTimer.duration() <<
+ " taking longer than time constraint of " << assertTimer.timeConstraint() <<
+ " aborting\n" << *defs);
+ break;
+ }
+ sleep(2);
+ }
+ return false;
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/Test/TestLate.cpp b/Test/TestLate.cpp
new file mode 100644
index 0000000..74774ad
--- /dev/null
+++ b/Test/TestLate.cpp
@@ -0,0 +1,136 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <iostream>
+#include <limits> // for std::numeric_limits<int>::max()
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/lexical_cast.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include "TestFixture.hpp"
+#include "ServerTestHarness.hpp"
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "DurationTimer.hpp"
+#include "PrintStyle.hpp"
+#include "ClientToServerCmd.hpp"
+#include "DefsStructureParser.hpp"
+#include "AssertTimer.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( TestSuite )
+
+BOOST_AUTO_TEST_CASE( test_late )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_late " << flush;
+ TestClean clean_at_start_and_end;
+
+ /// This test will sleep longer than the job submission interval
+ /// which cause the task to be late
+ /// as the active time has been set for 1 minute.
+ /// The check for lateness is ONLY done are server poll time.
+ /// Hence the task run time must be at least twice the poll time.
+ Defs theDefs;
+ {
+ suite_ptr suite = theDefs.add_suite("test_late");
+ suite->add_variable("SLEEPTIME",boost::lexical_cast<std::string>(TestFixture::job_submission_interval()*2) ); // this will cause the late
+
+ task_ptr task = suite->add_task("t1");
+ ecf::LateAttr lateAttr;
+ lateAttr.addComplete( ecf::TimeSlot(0,1), true);
+
+ task->addLate( lateAttr );
+ }
+
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_late.def"));
+
+ TestFixture::client().set_throw_on_error(true);
+ TestFixture::client().sync_local();
+ BOOST_CHECK_MESSAGE( TestFixture::client().defs(),"Expected defs");
+
+ node_ptr node = TestFixture::client().defs()->findAbsNode("/test_late/t1");
+ BOOST_CHECK_MESSAGE( node,"Expected task to be found");
+
+ ecf::LateAttr* late = node->get_late();
+ BOOST_CHECK_MESSAGE( late->isLate(),"Expected late to be set");
+ BOOST_CHECK_MESSAGE( node->flag().is_set(ecf::Flag::LATE),"Expected late flag to be set");
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_CASE( test_late_hierarchically )
+{
+ // ECFLOW-610
+ DurationTimer timer;
+ cout << "Test:: ...test_late_hierarchically " << flush;
+ char* the_env = getenv("ECF_DISABLE_TEST_FOR_OLD_SERVERS");
+ if (the_env) {
+ std::cout << "\n Disable test_late_hierarchically for old server *************************************************************\n";
+ return;
+ }
+ TestClean clean_at_start_and_end;
+
+ /// This test will sleep longer than the job submission interval
+ /// which cause the task to be late
+ /// as the active time has been set for 1 minute.
+ /// The check for lateness is ONLY done are server poll time.
+ /// Hence the task run time must be at least twice the poll time.
+ Defs theDefs;
+ {
+ suite_ptr suite = theDefs.add_suite("test_late_hierarchically");
+ suite->add_variable("SLEEPTIME",boost::lexical_cast<std::string>(TestFixture::job_submission_interval()*2) ); // this will cause the late
+ ecf::LateAttr lateAttr;
+ lateAttr.addComplete( ecf::TimeSlot(0,1), true);
+ suite->addLate( lateAttr );
+
+ family_ptr fam = suite->add_family("f1");
+ fam->add_task("t1");
+ fam->add_task("t2");
+ }
+
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_late_hierarchically.def"));
+
+ TestFixture::client().set_throw_on_error(true);
+ TestFixture::client().sync_local();
+ BOOST_CHECK_MESSAGE( TestFixture::client().defs(),"Expected defs");
+
+ node_ptr t1 = TestFixture::client().defs()->findAbsNode("/test_late_hierarchically/f1/t1");
+ BOOST_CHECK_MESSAGE( t1,"Expected task to be found");
+ BOOST_CHECK_MESSAGE( t1->flag().is_set(ecf::Flag::LATE),"Expected late flag to be set");
+
+ node_ptr t2 = TestFixture::client().defs()->findAbsNode("/test_late_hierarchically/f1/t2");
+ BOOST_CHECK_MESSAGE( t2,"Expected task to be found");
+ BOOST_CHECK_MESSAGE( t2->flag().is_set(ecf::Flag::LATE),"Expected late flag to be set");
+
+
+ // cout << TestFixture::client().defs() << "\n";
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Test/TestLimit.cpp b/Test/TestLimit.cpp
new file mode 100644
index 0000000..13b973c
--- /dev/null
+++ b/Test/TestLimit.cpp
@@ -0,0 +1,118 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #25 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include "ServerTestHarness.hpp"
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "DurationTimer.hpp"
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/test/unit_test.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+
+BOOST_AUTO_TEST_SUITE( TestSuite )
+
+// In the test case we will dynamically create all the test data.
+// The data is created dynamically so that we can stress test the server
+// This test does not have any time dependencies in the def file.
+// In the test case we will dynamically create all the test data.
+// The data is created dynamically so that we can stress test the server
+// This test does not have any time dependencies in the def file.
+BOOST_AUTO_TEST_CASE( test_limit )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_limit "<< flush;
+ TestClean clean_at_start_and_end;
+
+ // Create the defs file corresponding to the text below
+ // ECF_HOME variable is automatically added by the test harness.
+ // ECF_INCLUDE variable is automatically added by the test harness.
+ // SLEEPTIME variable is automatically added by the test harness.
+ // ECF_CLIENT_EXE_PATH variable is automatically added by the test harness.
+ // This is substituted in sms includes
+ // Allows test to run without requiring installation
+
+ //# Test the ecf file can be found via ECF_SCRIPT
+ //# Note: we have to use relative paths, since these tests are relocatable
+ // Create the defs file
+ // suite test_limit
+ // limit disk 50
+ // limit fast 1
+ // edit ECF_HOME data/ECF_HOME # added by test harness
+ // edit SLEEPTIME 1
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // family family
+ // inlimit /suite1:fast
+ // task t1
+ // task t2
+ // task t3
+ // endfamily
+ // family family2
+ // inlimit /suite1:disk 20
+ // task t1
+ // task t2
+ // task t3
+ // endfamily
+ // endsuite
+
+ Defs theDefs;
+ {
+ std::string suiteName = "test_limit";
+ std::string pathToLimit = "/" + suiteName;
+
+ suite_ptr suite = theDefs.add_suite( suiteName );
+ suite->addLimit(Limit("fast",1));
+ suite->addLimit(Limit("disk",50));
+
+ family_ptr fam = suite->add_family("family");
+ fam->addInLimit(InLimit("fast",pathToLimit));
+ fam->addVerify( VerifyAttr(NState::COMPLETE,1) );
+ int taskSize = 3;
+ for(int i=0; i < taskSize; i++) {
+ task_ptr task = fam->add_task( "t" + boost::lexical_cast<std::string>(i) );
+ task->addVerify( VerifyAttr(NState::COMPLETE,1) );
+ }
+
+ family_ptr fam2 = suite->add_family("family2");
+ fam2->addInLimit(InLimit("disk",pathToLimit,20));
+ fam2->addVerify( VerifyAttr(NState::COMPLETE,1) );
+ for(int i=0; i < taskSize; i++) {
+ task_ptr task = fam2->add_task( "t" + boost::lexical_cast<std::string>(i) );
+ task->addVerify( VerifyAttr(NState::COMPLETE,1) );
+ }
+ }
+
+
+ // The test harness will create corresponding directory structure
+ // and populate with standard ecf files.
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs, ServerTestHarness::testDataDefsLocation( "test_limit.def" ));
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Test/TestOrderCmd.cpp b/Test/TestOrderCmd.cpp
new file mode 100644
index 0000000..2952bbe
--- /dev/null
+++ b/Test/TestOrderCmd.cpp
@@ -0,0 +1,216 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : This is used to INVOKE a SINGLE test.
+// Making it easier for Easier for debugging and development
+//============================================================================
+#include <iostream>
+#include <limits> // for std::numeric_limits<int>::max()
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/lexical_cast.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include "ServerTestHarness.hpp"
+#include "TestFixture.hpp"
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "DurationTimer.hpp"
+#include "PrintStyle.hpp"
+#include "ClientToServerCmd.hpp"
+#include "DefsStructureParser.hpp"
+#include "AssertTimer.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( TestSuite )
+
+std::vector<std::string> to_string_vec(const std::vector<suite_ptr>& sv) {
+ std::vector<std::string> r; r.reserve(sv.size());
+ for(size_t i = 0; i < sv.size(); i++) r.push_back(sv[i]->name());
+ return r;
+}
+
+std::vector<std::string> to_string_vec(const std::vector<node_ptr>& sv) {
+ std::vector<std::string> r; r.reserve(sv.size());
+ for(size_t i = 0; i < sv.size(); i++) r.push_back(sv[i]->name());
+ return r;
+}
+
+void test_ordering() {
+
+ TestFixture::client().set_throw_on_error(true);
+ std::vector<std::string> str_a_b_c; str_a_b_c.push_back("a"); str_a_b_c.push_back("b"); str_a_b_c.push_back("c");
+ std::vector<std::string> str_c_b_a; str_c_b_a.push_back("c"); str_c_b_a.push_back("b"); str_c_b_a.push_back("a");
+ std::vector<std::string> str_b_c_a; str_b_c_a.push_back("b"); str_b_c_a.push_back("c"); str_b_c_a.push_back("a");
+ std::vector<std::string> str_b_a_c; str_b_a_c.push_back("b"); str_b_a_c.push_back("a"); str_b_a_c.push_back("c");
+ std::vector<std::string> str_a_c_b; str_a_c_b.push_back("a"); str_a_c_b.push_back("c"); str_a_c_b.push_back("b");
+ TestFixture::client().sync_local(); // First sync_local will do a full sync
+ {
+ // TEST SUITE ORDERING
+ TestFixture::client().order("/a",NOrder::toString(NOrder::ORDER));
+ TestFixture::client().sync_local();
+ BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().full_sync(),"Expected incremental sync");
+ BOOST_CHECK_MESSAGE(to_string_vec(TestFixture::client().defs()->suiteVec()) == str_c_b_a, "Order not as expected");
+
+
+ TestFixture::client().order("/a",NOrder::toString(NOrder::ALPHA));
+ TestFixture::client().sync_local();
+ BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().full_sync(),"Expected incremental sync");
+ BOOST_CHECK_MESSAGE(to_string_vec(TestFixture::client().defs()->suiteVec()) == str_a_b_c, "Order not as expected");
+
+
+ TestFixture::client().order("/a",NOrder::toString(NOrder::BOTTOM));
+ TestFixture::client().sync_local();
+ BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().full_sync(),"Expected incremental sync");
+ BOOST_CHECK_MESSAGE(to_string_vec(TestFixture::client().defs()->suiteVec()) == str_b_c_a, "Order not as expected");
+
+ TestFixture::client().order("/a",NOrder::toString(NOrder::ALPHA));
+ TestFixture::client().order("/a",NOrder::toString(NOrder::DOWN));
+ TestFixture::client().sync_local();
+ BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().full_sync(),"Expected incremental sync");
+ BOOST_CHECK_MESSAGE(to_string_vec(TestFixture::client().defs()->suiteVec()) == str_b_a_c, "Order not as expected");
+
+ TestFixture::client().order("/a",NOrder::toString(NOrder::ALPHA));
+ TestFixture::client().order("/c",NOrder::toString(NOrder::UP));
+ TestFixture::client().sync_local();
+ BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().full_sync(),"Expected incremental sync");
+ BOOST_CHECK_MESSAGE(to_string_vec(TestFixture::client().defs()->suiteVec()) == str_a_c_b, "Order not as expected");
+ }
+ {
+ // TEST FAMILY ordering
+ TestFixture::client().order("/a/a",NOrder::toString(NOrder::ORDER));
+ TestFixture::client().sync_local();
+ BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().full_sync(),"Expected incremental sync");
+ BOOST_CHECK_MESSAGE(to_string_vec(TestFixture::client().defs()->suiteVec()[0]->nodeVec()) == str_c_b_a, "Order not as expected");
+
+
+ TestFixture::client().order("/a/a",NOrder::toString(NOrder::ALPHA));
+ TestFixture::client().sync_local();
+ BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().full_sync(),"Expected incremental sync");
+ BOOST_CHECK_MESSAGE(to_string_vec(TestFixture::client().defs()->suiteVec()[0]->nodeVec()) == str_a_b_c, "Order not as expected");
+
+
+ TestFixture::client().order("/a/a",NOrder::toString(NOrder::BOTTOM));
+ TestFixture::client().sync_local();
+ BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().full_sync(),"Expected incremental sync");
+ BOOST_CHECK_MESSAGE(to_string_vec(TestFixture::client().defs()->suiteVec()[0]->nodeVec()) == str_b_c_a, "Order not as expected");
+
+ TestFixture::client().order("/a/a",NOrder::toString(NOrder::ALPHA));
+ TestFixture::client().order("/a/a",NOrder::toString(NOrder::DOWN));
+ TestFixture::client().sync_local();
+ BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().full_sync(),"Expected incremental sync");
+ BOOST_CHECK_MESSAGE(to_string_vec(TestFixture::client().defs()->suiteVec()[0]->nodeVec()) == str_b_a_c, "Order not as expected");
+
+ TestFixture::client().order("/a/a",NOrder::toString(NOrder::ALPHA));
+ TestFixture::client().order("/a/c",NOrder::toString(NOrder::UP));
+ TestFixture::client().sync_local();
+ BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().full_sync(),"Expected incremental sync");
+ BOOST_CHECK_MESSAGE(to_string_vec(TestFixture::client().defs()->suiteVec()[0]->nodeVec()) == str_a_c_b, "Order not as expected");
+ }
+}
+
+BOOST_AUTO_TEST_CASE( test_change_order )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_change_order " << flush;
+ TestClean clean_at_start_and_end;
+
+ /// NOT: We *DONT* need to run the jobs for this TEST
+ std::vector<std::string> str_a_b_c; str_a_b_c.push_back("a"); str_a_b_c.push_back("b"); str_a_b_c.push_back("c");
+ Defs theDefs; {
+ for(size_t s = 0; s < str_a_b_c.size(); s++) {
+ suite_ptr suite = theDefs.add_suite(str_a_b_c[s]);
+ suite->addDefStatus(DState::SUSPENDED); // NO NEED to run jobs for this test:
+ for(size_t f = 0; f < str_a_b_c.size(); f++) {
+ family_ptr fam = suite->add_family(str_a_b_c[f]);
+ for(size_t t = 0; t < str_a_b_c.size(); t++) {
+ fam->add_task(str_a_b_c[t]);
+ }
+ }
+ }
+ }
+
+ // The test harness will create corresponding directory structure & default ecf file
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,
+ ServerTestHarness::testDataDefsLocation("test_change_order.def"),
+ 1 /*timeout*/,
+ false/* don't wait for test to finish */);
+
+
+ test_ordering();
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+
+BOOST_AUTO_TEST_CASE( test_handle_change_order )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_handle_change_order " << flush;
+ TestClean clean_at_start_and_end;
+
+ std::vector<std::string> str_a_b_c; str_a_b_c.push_back("a"); str_a_b_c.push_back("b"); str_a_b_c.push_back("c");
+ std::vector<std::string> suite_a_b_c_d_e; suite_a_b_c_d_e.push_back("a"); suite_a_b_c_d_e.push_back("b"); suite_a_b_c_d_e.push_back("c");
+ suite_a_b_c_d_e.push_back("d"); suite_a_b_c_d_e.push_back("e");
+ Defs theDefs; {
+ for(size_t s = 0; s < suite_a_b_c_d_e.size(); s++) {
+ suite_ptr suite = theDefs.add_suite(suite_a_b_c_d_e[s]);
+ suite->addDefStatus(DState::SUSPENDED); // NO NEED to run jobs for this test:
+ for(size_t f = 0; f < str_a_b_c.size(); f++) {
+ family_ptr fam = suite->add_family(str_a_b_c[f]);
+ for(size_t t = 0; t < str_a_b_c.size(); t++) {
+ fam->add_task(str_a_b_c[t]);
+ }
+ }
+ }
+ }
+
+ // The test harness will create corresponding directory structure & default ecf file
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,
+ ServerTestHarness::testDataDefsLocation("test_change_order.def"),
+ 1 /*timeout*/,
+ false/* don't wait for test to finish */);
+
+
+ TestFixture::client().set_throw_on_error( true );
+ TestFixture::client().sync_local(); // First sync_local will do a full sync
+ {
+ // register suites a,b,c
+ std::vector<std::string> suites_a_b_c; suites_a_b_c.push_back("a"); suites_a_b_c.push_back("b"); suites_a_b_c.push_back("c");
+ TestFixture::client().ch_register(false/*add new suites to handle*/,suites_a_b_c);
+
+ // Check the sync_local() does a full sync for our handle
+ TestFixture::client().sync_local();
+ BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().in_sync(),"Expected to be in sync after syn_local()");
+ BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().full_sync(),"Expected a full_sync() after registering");
+ BOOST_CHECK_MESSAGE(TestFixture::client().defs()->suiteVec().size() == 3,"Expected sync to return 3 suites.");
+ }
+
+ // Do same test, this time sync_local will only return suite a,b,c (i.e suite d,e not registered and hence left out)
+ // Ording should still be applied to the whole suite.
+ test_ordering();
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Test/TestRepeat.cpp b/Test/TestRepeat.cpp
new file mode 100644
index 0000000..22e7c72
--- /dev/null
+++ b/Test/TestRepeat.cpp
@@ -0,0 +1,338 @@
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/test/unit_test.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include "ServerTestHarness.hpp"
+#include "TestFixture.hpp"
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "DurationTimer.hpp"
+#include "WhyCmd.hpp"
+#include "PrintStyle.hpp"
+#include "Str.hpp"
+
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( TestSuite )
+
+// In the test case we will dynamically create all the test data.
+// The data is created dynamically so that we can stress test the server
+// This test does not have any time dependencies in the def file.
+BOOST_AUTO_TEST_CASE( test_repeat_integer )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_repeat_integer " << flush;
+ TestClean clean_at_start_and_end;
+
+ // ********************************************************************************
+ // IMPORTANT: A family will only complete when it has reached the end of the repeats
+ // *********************************************************************************
+
+ // Create the defs file corresponding to the text below
+ // ECF_HOME variable is automatically added by the test harness.
+ // ECF_INCLUDE variable is automatically added by the test harness.
+ // SLEEPTIME variable is automatically added by the test harness.
+ // ECF_CLIENT_EXE_PATH variable is automatically added by the test harness.
+ // This is substituted in sms includes
+ // Allows test to run without requiring installation
+
+ //# Note: we have to use relative paths, since these tests are relocatable
+ //suite test_repeat_integer
+ // repeat integer VAR 0 1 1 # run at 0, 1 2 times
+ // edit SLEEPTIME 1
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // family family
+ // repeat integer VAR 0 2 1 # run at 0, 1 2 times
+ // task t<n>
+ // ....
+ // endfamily
+ //endsuite
+
+ // Each task/job should be run *4* times, according to the repeats
+ // Mimics nested loops
+ Defs theDefs;
+ {
+ suite_ptr suite = theDefs.add_suite( "test_repeat_integer" );
+ suite->addRepeat( RepeatInteger("VAR",0,1,1)); // repeat suite 2 times,
+ suite->addVerify( VerifyAttr(NState::COMPLETE,2) );
+ family_ptr fam = suite->add_family("family");
+ fam->addRepeat( RepeatInteger("VAR",0,1,1)); // repeat family 2 times
+ fam->addVerify( VerifyAttr(NState::COMPLETE,4) );
+ int taskSize = 2; // on linux 1024 tasks take ~4 seconds for job submission
+ for(int i=0; i < taskSize; i++) {
+ task_ptr task = fam->add_task ( "t" + boost::lexical_cast<std::string>(i) );
+ task->addVerify( VerifyAttr(NState::COMPLETE,4) ); // task should complete 4 times
+ }
+ }
+
+ // The test harness will create corresponding directory structure
+ // and populate with standard sms files.
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs, ServerTestHarness::testDataDefsLocation("test_repeat_integer.def"));
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_CASE( test_repeat_date )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_repeat_date " << flush;
+ TestClean clean_at_start_and_end;
+
+ // ********************************************************************************
+ // IMPORTANT: A family will only complete when it has reached the end of the repeats
+ // *********************************************************************************
+ //suite test_repeat_date
+ // family family
+ // repeat date DATE 20110630 20110632
+ // task t<n>
+ // ....
+ // endfamily
+ //endsuite
+ Defs theDefs; {
+ suite_ptr suite = theDefs.add_suite("test_repeat_date");
+ suite->addVerify( VerifyAttr(NState::COMPLETE,1) );
+ family_ptr fam = suite->add_family("family" );
+ fam->addRepeat( RepeatDate("DATE",20110630,20110704));
+ fam->addVerify( VerifyAttr(NState::COMPLETE,5) );
+ int taskSize = 2;
+ for(int i=0; i < taskSize; i++) {
+ task_ptr task = fam->add_task( "t" + boost::lexical_cast<std::string>(i) );
+ task->addVerify( VerifyAttr(NState::COMPLETE,5) );
+ }
+ }
+
+ // The test harness will create corresponding directory structure
+ // and populate with standard sms files.
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs, ServerTestHarness::testDataDefsLocation("test_repeat_date.def"));
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+
+BOOST_AUTO_TEST_CASE( test_repeat_enumerator )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_repeat_enumerator " << flush;
+ TestClean clean_at_start_and_end;
+
+ // ********************************************************************************
+ // IMPORTANT: A family will only complete when it has reached the end of the repeats
+ // *********************************************************************************
+ // suite test_repeat_enumerator
+ // family top
+ // family plot
+ // family iasi_plots
+ // repeat enumerated month "200801" "200802"
+ // task t1
+ // endfamily
+ // endfamily
+ // endfamily
+ // endsuite
+
+ Defs theDefs;
+ {
+ suite_ptr suite = theDefs.add_suite( "test_repeat_enumerator" );
+ family_ptr top = suite->add_family("top");
+ family_ptr plot = top->add_family("plot");
+ family_ptr iasi_plots = plot->add_family("iasi_plots");
+ vector<string> months; months.reserve(12); months.push_back("200801"); months.push_back("200802");
+ iasi_plots->addRepeat(RepeatEnumerated("month",months));
+ task_ptr t1 = iasi_plots->add_task("t1");
+ t1->addVerify( VerifyAttr(NState::COMPLETE,2) );
+ }
+
+ // The test harness will create corresponding directory structure
+ // and populate with standard ecf files.
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs, ServerTestHarness::testDataDefsLocation("test_repeat_enumerator.def") );
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_CASE( test_repeat_defstatus )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_repeat_defstatus " << flush;
+ TestClean clean_at_start_and_end;
+
+ // TEST SHOULD COMPLETE STRAIGHT AWAY SINCE WE HAVE A DEFSTATUS COMPLETE
+ // since the complete state is set on all children of suite.
+
+ // Create the defs file corresponding to the text below
+ //# Note: we have to use relative paths, since these tests are relocatable
+ //suite test_repeat_defstatus
+ // defstatus complete
+ // repeat integer VAR 0 1 1 # run at 0, 1 2 times
+ // edit SLEEPTIME 1
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // family family
+ // repeat integer VAR 0 2 1 # run at 0, 1 2 times
+ // task t<n>
+ // ....
+ // endfamily
+ //endsuite
+ Defs theDefs;
+ {
+ suite_ptr suite = theDefs.add_suite( "test_repeat_defstatus" );
+ suite->addDefStatus(DState::COMPLETE);
+ suite->addRepeat( RepeatInteger("VAR",0,1,1));
+ suite->addVerify( VerifyAttr(NState::COMPLETE,1) );
+
+ family_ptr fam = suite->add_family("family" );
+ fam->addRepeat( RepeatInteger("VAR",0,1,1));
+ fam->addVerify( VerifyAttr(NState::COMPLETE,1) );
+ int taskSize = 2; // on linux 1024 tasks take ~4 seconds for job submission
+ for(int i=0; i < taskSize; i++) {
+
+ task_ptr task = fam->add_task( "t" + boost::lexical_cast<std::string>(i) );
+ task->addVerify( VerifyAttr(NState::COMPLETE,1) );
+ }
+ }
+
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_repeat_defstatus.def"));
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+//#define DEBUG_ME 1
+BOOST_AUTO_TEST_CASE( test_repeat_clears_user_edit )
+{
+ // Tests code:: Node::requeueOrSetMostSignificantStateUpNodeTree()
+ // In *PARTICULAR* THE REQUE caused by the repeat, this ensures we clear NO_REQUE_IF_SINGLE_TIME_DEP
+ // So that the effect of manual run/force complete are negated via automated re-queue caused by a REPEAT
+
+ DurationTimer timer;
+ cout << "Test:: ...test_repeat_clears_user_edit " << flush;
+ TestClean clean_at_start_and_end;
+
+ // The functionality where the Repeat requeue clears NO_REQUE_IF_SINGLE_TIME_DEP was added in version 4.0.3
+ // Hence we need to disable this test, if the server version is less 403
+ // Since these tests can also be used to test backward compatibility. i.e new client old server
+ int the_server_version = TestFixture::server_version() ;
+ if (the_server_version < 403 ) {
+ cout << " SKIPPING, since this test requires server version >= 403, current server version is " << the_server_version << "\n";
+ return;
+ }
+
+ //# Note: we have to use relative paths, since these tests are relocatable
+ //suite test_repeat_clears_user_edit
+ // edit SLEEPTIME 1
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // family family
+ // repeat integer VAR 0 3 # run at 0,1,2 i.e 3 times
+ // task t<n>
+ // time <current time>
+ // endfamily
+ //endsuite
+
+ Defs theDefs;
+ task_ptr task;
+ {
+ boost::posix_time::ptime theLocalTime = boost::posix_time::ptime(date(2010,6,21),time_duration(10,0,0));
+ boost::posix_time::ptime time1 = theLocalTime + minutes(3);
+
+ suite_ptr suite = theDefs.add_suite( "test_repeat_clears_user_edit" );
+ ClockAttr clockAttr(theLocalTime,false);
+ suite->addClock( clockAttr );
+
+ suite->addDefStatus(DState::SUSPENDED);
+ family_ptr fam = suite->add_family("family");
+ fam->addRepeat( RepeatInteger("VAR",0,2,1)); // repeat family 3 times
+ task = fam->add_task ( "t1" );
+ task->addTime( ecf::TimeAttr(ecf::TimeSlot(time1.time_of_day())));
+ task->addVerify( VerifyAttr(NState::COMPLETE,3) );
+
+ // cout << theDefs << "\n";
+ }
+
+ // The test harness will create corresponding directory structure
+ // and populate with standard sms files.
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs, ServerTestHarness::testDataDefsLocation("test_repeat_integer.def"), 40, false /* waitFortestcompletion */);
+
+#ifdef DEBUG_ME
+ PrintStyle::setStyle(PrintStyle::STATE);
+ TestFixture::client().sync_local();
+ defs_ptr server_defs = TestFixture::client().defs();
+ cout << "At start ============================================\n";
+ cout << server_defs << "\n";
+#endif
+
+ // USER EDIT, on task with a time. The force complete will expire the time.
+ // Forcing a task with the time attribute, to complete state, should invalidate/expire the time,
+ // Hence it should hold indefinitely, or until it is re-queued manually, or automatically via a Repeat/cron.
+ // This Test ensures the the *REQUEUE* via the repeat, resets the time based attribute
+ TestFixture::client().force(task->absNodePath(),"complete",true);
+ TestFixture::client().force(task->absNodePath(),"complete",true);
+
+
+#ifdef DEBUG_ME
+ TestFixture::client().sync_local();
+ server_defs = TestFixture::client().defs();
+ cout << "After 2 force complete ============================================\n";
+ cout << server_defs << "\n";
+
+ node_ptr the_task = server_defs->findAbsNode(task->absNodePath());
+ BOOST_REQUIRE_MESSAGE(the_task, "Task " << task->absNodePath() << " not found");
+ WhyCmd whyCmd( server_defs, the_task->absNodePath());
+ std::string reason = whyCmd.why();
+ cout << "Why command ============================================\n";
+ std::cout << reason << "\n\n";
+#endif
+
+ // resume the suspend suite
+ TestFixture::client().resume("/test_repeat_clears_user_edit");
+
+#ifdef DEBUG_ME
+ TestFixture::client().sync_local();
+ server_defs = TestFixture::client().defs();
+ cout << "At Resume ============================================\n";
+ cout << server_defs << "\n";
+#endif
+
+ // Wait for final LOOP of the repeat, and test to finish
+ int timeout = 20;
+ bool verifyAttrInServer = true;
+ defs_ptr serverDefs = serverTestHarness.testWaiter(theDefs,timeout,verifyAttrInServer);
+ BOOST_REQUIRE_MESSAGE(serverDefs.get()," Failed to return defs after wait of 20 seconds");
+
+#ifdef DEBUG_ME
+ cout << "At test finish ============================================\n";
+ cout << serverDefs << "\n";
+#endif
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Test/TestRequeueNode.cpp b/Test/TestRequeueNode.cpp
new file mode 100644
index 0000000..646bd66
--- /dev/null
+++ b/Test/TestRequeueNode.cpp
@@ -0,0 +1,112 @@
+
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #17 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include "ServerTestHarness.hpp"
+#include "TestFixture.hpp"
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "DurationTimer.hpp"
+#include "PrintStyle.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+
+using namespace std;
+using namespace ecf;
+
+BOOST_AUTO_TEST_SUITE( TestSuite )
+
+BOOST_AUTO_TEST_CASE( test_requeue_node )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_requeue_node " << flush;
+ TestClean clean_at_start_and_end;
+
+ // Create the defs file corresponding to the text below
+ // ECF_HOME variable is automatically added by the test harness.
+ // ECF_INCLUDE variable is automatically added by the test harness.
+ // SLEEPTIME variable is automatically added by the test harness.
+ // ECF_CLIENT_EXE_PATH variable is automatically added by the test harness.
+ // This is substituted in sms includes
+ // Allows test to run without requiring installation
+
+ //# Note: we have to use relative paths, since these tests are relocatable
+ //suite test_repeat_integer
+ // repeat integer VAR 0 1 1 # run at 0, 1 2 times
+ // edit SLEEPTIME 1
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // family family
+ // repeat integer VAR 0 2 1 # run at 0, 1 2 times
+ // task t<n>
+ // ....
+ // endfamily
+ //endsuite
+
+ // Each task/job should be run *4* times, according to the repeats Mimics nested loops
+ Defs theDefs;
+ {
+ suite_ptr suite = theDefs.add_suite( "test_reque" );
+ suite->addRepeat( RepeatInteger("VAR",0,1,1)); // repeat suite 2 times
+ suite->addVerify( VerifyAttr(NState::COMPLETE,2) );
+ family_ptr fam = suite->add_family("family" );
+ fam->addRepeat( RepeatInteger("VAR",0,1,1)); // repeat family 2 times
+ fam->addVerify( VerifyAttr(NState::COMPLETE,4) );
+ int taskSize = 2; // on linux 1024 tasks take ~4 seconds for job submission
+ for(int i=0; i < taskSize; i++) {
+ task_ptr task = fam->add_task( "t" + boost::lexical_cast<std::string>(i));
+ task->addVerify( VerifyAttr(NState::COMPLETE,4) ); // task should complete 4 times
+ }
+ }
+
+ // The test harness will create corresponding directory structure
+ // and populate with standard sms files.
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_reque.def") );
+
+ // Now re-queue the whole suite
+ TestFixture::client().set_throw_on_error( true );
+ TestFixture::client().requeue("/test_reque");
+
+ // Wait for test to finish
+ int timeout = 30;
+ bool verifyAttrInServer = false;
+ defs_ptr serverDefs = serverTestHarness.testWaiter(theDefs,timeout,verifyAttrInServer);
+ BOOST_REQUIRE_MESSAGE(serverDefs.get()," Failed to return server after re-queue");
+
+// cout << "Printing Defs \n";
+// std::cout << *serverDefs.get();
+
+ // since we requed each task should have completed 8 times
+ std::vector<Task*> taskVec;
+ serverDefs->getAllTasks(taskVec);
+ BOOST_FOREACH(Task* t, taskVec) {
+ BOOST_FOREACH(const VerifyAttr& v, t->verifys()) {
+ if (v.state() == NState::COMPLETE) {
+ BOOST_CHECK_MESSAGE(v.actual() == 8,"Expected task " << t->absNodePath() << " to complete 8 times, due to reque, but it completed only " << v.actual() << " times\n");
+ }
+ }
+ }
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Test/TestRunner.cpp b/Test/TestRunner.cpp
new file mode 100644
index 0000000..d02da84
--- /dev/null
+++ b/Test/TestRunner.cpp
@@ -0,0 +1,21 @@
+#define BOOST_TEST_MODULE Test
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include "TestFixture.hpp"
+#include <boost/test/unit_test.hpp>
+
+// Global test fixture. Dues to boost deficiency this can't be accessed. hence
+// TestFixture makes use of global data.
+BOOST_GLOBAL_FIXTURE( TestFixture );
diff --git a/Test/TestServer.cpp b/Test/TestServer.cpp
new file mode 100644
index 0000000..7ee9c59
--- /dev/null
+++ b/Test/TestServer.cpp
@@ -0,0 +1,135 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #39 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/test/unit_test.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include "ServerTestHarness.hpp"
+#include "TestFixture.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "DurationTimer.hpp"
+#include "Host.hpp"
+#include "Str.hpp"
+
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( TestSuite )
+
+// In the test case we will dynamically create all the test data.
+// The data is created dynamically so that we can stress test the server
+// This test does not have any time dependencies in the def file.
+BOOST_AUTO_TEST_CASE( test_server_job_submission )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_server_job_submission "<< flush;
+ TestClean clean_at_start_and_end;
+
+ //# Note: we have to use relative paths, since these tests are relocatable
+ //suite test_server_job_submission
+ // edit SLEEPTIME 1
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // family family
+ // task t<n>
+ // ....
+ // endfamily
+ //endsuite
+ Defs theDefs;
+ {
+ suite_ptr suite = theDefs.add_suite( "test_server_job_submission" );
+ family_ptr fam = suite->add_family("family" );
+ fam->addVerify( VerifyAttr(NState::COMPLETE,1) );
+ int taskSize = 3; // on linux 1024 tasks take ~4 seconds for job submission
+ for(int i=0; i < taskSize; i++) {
+ task_ptr task = fam->add_task( "t" + boost::lexical_cast<std::string>(i));
+ task->addVerify( VerifyAttr(NState::COMPLETE,1) );
+ }
+ }
+
+ // The test harness will create corresponding directory structure and populate with standard ecf files.
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_server_job_submission.def"));
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_CASE( test_restore_defs_from_check_pt )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_restore_defs_from_check_pt "<< flush;
+ TestClean clean_at_start_and_end;
+ // **********************************************************************
+ // In order for this test to work, we need to disable the automatic
+ // check pointing done by the server. Otherwise it will interfere with
+ // this test. This is re-enabled at the end of the test
+ // ************************************************************************
+ Defs theDefs; {
+ suite_ptr suite = Suite::create( "test_restore_defs_from_check_pt" );
+ suite->addTask( Task::create( "t1" ) );
+ theDefs.addSuite( suite );
+ }
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_restore_defs_from_check_pt.def"));
+
+ TestFixture::client().set_throw_on_error(false);
+
+ // Disable server check pointing
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().checkPtDefs(ecf::CheckPt::NEVER) == 0,CtsApi::checkPtDefs(ecf::CheckPt::NEVER) << " failed should return 0\n" << TestFixture::client().errorMsg());
+
+ Host h;
+ std::string check_pt_file_name = h.ecf_checkpt_file(TestFixture::port());
+
+ // make sure we have a valid definition with at least one suite before start
+ BOOST_REQUIRE_MESSAGE( TestFixture::client().getDefs() == 0, "Expected getDefs() to succeed\n");
+ BOOST_REQUIRE_MESSAGE( TestFixture::client().defs()->suiteVec().size() == 1, "Expected 1 suite at the start\n");
+
+ // Check pt, make sure file exist on disk and has a non zero file size\n";
+ BOOST_REQUIRE_MESSAGE( TestFixture::client().checkPtDefs() == 0,"Expected Check-pt to succeed.\n" << TestFixture::client().errorMsg());
+ BOOST_REQUIRE_MESSAGE( fs::exists(check_pt_file_name),CtsApi::checkPtDefs() << " failed file(" << check_pt_file_name << ") not saved");
+ BOOST_REQUIRE_MESSAGE( fs::file_size(check_pt_file_name) !=0,"Expected check point file(" << check_pt_file_name << ") to have file size > 0");
+
+ // Make sure restore from check pt, only works if server is halted and there are no suites\n";
+ BOOST_REQUIRE_MESSAGE( TestFixture::client().restoreDefsFromCheckPt() == 1,"Expected restoreDefsFromCheckPt to *FAIL* since server not halted\n");
+ BOOST_REQUIRE_MESSAGE( TestFixture::client().haltServer() == 0,"Expected halt server to succeed\n" << TestFixture::client().errorMsg());
+ BOOST_REQUIRE_MESSAGE( TestFixture::client().restoreDefsFromCheckPt() == 1,"Expected restoreDefsFromCheckPt to *FAIL* since definition not deleted yet\n");
+ BOOST_REQUIRE_MESSAGE( TestFixture::client().delete_all() == 0,"Expected delete all nodes to succeed\n" << TestFixture::client().errorMsg());
+ BOOST_REQUIRE_MESSAGE( TestFixture::client().getDefs() == 0, "Expected getDefs() to succeed, i.e expected empty defs\n");
+ BOOST_REQUIRE_MESSAGE( TestFixture::client().defs()->suiteVec().empty(), "Expected no suites, after delete_all()\n");
+
+ // make sure check pt file still exists, sanity test\n";
+ BOOST_REQUIRE_MESSAGE( fs::exists(check_pt_file_name),CtsApi::checkPtDefs() << " failed file(" << check_pt_file_name << ") not saved");
+ BOOST_REQUIRE_MESSAGE( fs::file_size(check_pt_file_name) !=0,"Expected check point file(" << check_pt_file_name << ") to have file size > 0");
+
+ // make sure restore actually worked, by retrieving the definition and counting the suites\n";
+ BOOST_REQUIRE_MESSAGE( TestFixture::client().restoreDefsFromCheckPt() == 0,"Expected restoreDefsFromCheckPt to *SUCCEED*, since server halted and defs deleted \n" << TestFixture::client().errorMsg());
+ BOOST_REQUIRE_MESSAGE( TestFixture::client().getDefs() == 0, "Get defs failed should return 0\n" << TestFixture::client().errorMsg());
+ BOOST_REQUIRE_MESSAGE( TestFixture::client().defs()->suiteVec().size() == 1, "Restore from check pt did not work. expected 1 suite but found " << TestFixture::client().defs()->suiteVec().size() );
+
+ // restore default check pointing, for test that follow
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().checkPtDefs(ecf::CheckPt::ON_TIME,120) == 0,CtsApi::checkPtDefs(ecf::CheckPt::ON_TIME) << " failed should return 0\n" << TestFixture::client().errorMsg());
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Test/TestSingle.cpp b/Test/TestSingle.cpp
new file mode 100644
index 0000000..f49fa17
--- /dev/null
+++ b/Test/TestSingle.cpp
@@ -0,0 +1,182 @@
+#define BOOST_TEST_MODULE TEST_SINGLE
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #80 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : This is used to INVOKE a SINGLE test.
+// Making it easier for Easier for debugging and development
+//============================================================================
+#include <iostream>
+#include <limits> // for std::numeric_limits<int>::max()
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/lexical_cast.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include "TestFixture.hpp"
+#include "ServerTestHarness.hpp"
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "DurationTimer.hpp"
+#include "PrintStyle.hpp"
+#include "ClientToServerCmd.hpp"
+#include "DefsStructureParser.hpp"
+#include "AssertTimer.hpp"
+#include "File.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+namespace fs = boost::filesystem;
+
+BOOST_GLOBAL_FIXTURE( TestFixture );
+
+BOOST_AUTO_TEST_SUITE( TestSingleSuite )
+
+
+// DO NOT delete
+// This is used to test large defs. and hence server performance & memory leaks
+// Be sure to comment out defstatus suspended in mega.def
+BOOST_AUTO_TEST_CASE( test_mega_def )
+{
+ DurationTimer timer;
+
+ // location to mega.def and left over log file
+ std::string log_file = File::test_data("AParser/test/data/single_defs/mega.def_log","AParser");
+ std::string path = File::test_data("AParser/test/data/single_defs/mega.def","AParser");
+
+ cout << "Test:: ..." << path << " log file: " << log_file << flush;
+
+ // Remove the log file.
+ boost::filesystem::remove(log_file);
+
+ // parse in file
+ Defs theDefs;
+ DefsStructureParser checkPtParser( &theDefs, path);
+ std::string errorMsg,warningMsg;
+ BOOST_REQUIRE_MESSAGE(checkPtParser.doParse(errorMsg,warningMsg),errorMsg);
+
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.check_task_duration_less_than_server_poll(false); // Add variable CHECK_TASK_DURATION_LESS_THAN_SERVER_POLL
+ serverTestHarness.run(theDefs,path,std::numeric_limits<int>::max()/*timeout*/ );
+
+ cout << timer.duration() << "\n";
+}
+
+// DO NOT delete
+// This is used to test with thousands of labels
+//BOOST_AUTO_TEST_CASE( test_large_client_labels_calls )
+//{
+// DurationTimer timer;
+// cout << "Test:: ...test_large_client_labels_calls "<< flush;
+// TestClean clean_at_start_and_end;
+//
+// //# Note: we have to use relative paths, since these tests are relocatable
+// // suite test_large_client_labels_calls
+// // family family
+// // task t1
+// // label name "value"
+// // endfamily
+// // endsuite
+// Defs theDefs;
+// {
+// suite_ptr suite = theDefs.add_suite("test_large_client_labels_calls");
+// family_ptr fam = suite->add_family("family");
+// task_ptr t1 = fam->add_task("t1");
+// t1->addLabel( Label("name","value"));
+// }
+//
+// // Create a custom ecf file for test_large_client_labels_calls/family/t1 to invoke label commands
+// std::string templateEcfFile;
+// templateEcfFile += "%include <head.h>\n";
+// templateEcfFile += "\n";
+// templateEcfFile += "echo do some work\n";
+// templateEcfFile += "i=1\n";
+// templateEcfFile += "while [ \"$i\" -le 10000 ] \n";
+// templateEcfFile += "do\n";
+// templateEcfFile += " %ECF_CLIENT_EXE_PATH% --label=name \"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\"\n";
+// templateEcfFile += " i=$((i+1))\n";
+// templateEcfFile += "done\n";
+// templateEcfFile += "\n";
+// templateEcfFile += "%include <tail.h>\n";
+//
+// // The test harness will create corresponding directory structure
+// // Override the default ECF file, with our custom ECF_ file
+// std::map<std::string,std::string> taskEcfFileMap;
+// taskEcfFileMap.insert(std::make_pair(TestFixture::taskAbsNodePath(theDefs,"t1"),templateEcfFile));
+//
+// // Avoid standard verification since we expect to abort many times
+// ServerTestHarness serverTestHarness;
+// serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_large_client_labels_calls.def"), taskEcfFileMap,1000000);
+//
+// cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n" << endl;
+//}
+//
+
+//// DO NOT delete
+/// The following test verifies that the job generation is largely linear.
+/// Job submission interval was 3 seconds. In release mode.
+///
+/// Test duration is highly dependent on the OS/process handling.
+/// No of tasks Job generation Peak request/sec in server
+/// 10 -
+/// 100 -
+/// 500 - 364
+/// 1000 4 450
+/// 1500 6 550
+/// 2000 9 880
+/// 3000 15 800
+/// 4000 24 923
+/// 5000 29 800
+/// 6000 37 900
+//void time_for_tasks(int tasks) {
+//
+// std::string test_name = "test_stress_" + boost::lexical_cast<std::string>(tasks);
+// cout << "Test:: ..." << test_name << flush;
+//
+// Defs theDefs;
+// {
+// suite_ptr suite = theDefs.add_suite( test_name );
+// family_ptr fam = suite->add_family("fam" );
+// for(int i = 0; i < tasks; i++) {
+// fam->add_task( "t" + boost::lexical_cast<std::string>(i));
+// }
+// // suite->addRepeat( RepeatDate("YMD",19000101,99991201,1) );
+// }
+//
+// ServerTestHarness serverTestHarness;
+// serverTestHarness.check_task_duration_less_than_server_poll(false); // Add variable CHECK_TASK_DURATION_LESS_THAN_SERVER_POLL
+// DurationTimer timer;
+// serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation(test_name + ".def"), std::numeric_limits<int>::max()/*timeout*/ );
+// cout << " " << timer.duration() << "s\n";
+//}
+//
+//// Use to stress test server. i.e continually fire client requests.
+//BOOST_AUTO_TEST_CASE( test_stress )
+//{
+// time_for_tasks(10);
+// time_for_tasks(100);
+// time_for_tasks(500);
+// time_for_tasks(1000);
+// time_for_tasks(1500);
+// time_for_tasks(2000);
+// time_for_tasks(3000);
+// time_for_tasks(4000);
+// time_for_tasks(5000);
+//}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Test/TestSuspend.cpp b/Test/TestSuspend.cpp
new file mode 100644
index 0000000..f9162fc
--- /dev/null
+++ b/Test/TestSuspend.cpp
@@ -0,0 +1,228 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #24 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+
+#include <boost/test/unit_test.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include "ServerTestHarness.hpp"
+#include "TestFixture.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "DurationTimer.hpp"
+#include "PrintStyle.hpp"
+#include "AssertTimer.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+
+#if defined(_AIX)
+static int timeout = 30 ;
+#else
+static int timeout = 20 ;
+#endif
+
+
+BOOST_AUTO_TEST_SUITE( TestSuite )
+
+static void waitForTimeDependenciesToBeFree(int max_time_to_wait)
+{
+ // wait for a period of time, while time dependencies fire.
+ TestFixture::client().set_throw_on_error( false );
+ AssertTimer assertTimer(max_time_to_wait,false); // Bomb out after n seconds, fall back if test fail
+ while (1) {
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0,"sync_local failed should return 0\n" << TestFixture::client().errorMsg());
+ defs_ptr defs = TestFixture::client().defs();
+ vector<Task*> tasks; defs->getAllTasks(tasks);
+ size_t taskTimeDepIsFree = 0 ;
+ BOOST_FOREACH(Task* task, tasks) {
+ size_t attSetFree = 0;
+ BOOST_FOREACH( const ecf::TimeAttr& timeAttr, task->timeVec()) {
+ if (timeAttr.isFree(task->suite()->calendar())) attSetFree++;
+ }
+ if ( attSetFree == task->timeVec().size()) taskTimeDepIsFree++;
+ }
+ if ( taskTimeDepIsFree == tasks.size()) break;
+
+ BOOST_REQUIRE_MESSAGE(assertTimer.duration() < assertTimer.timeConstraint(),
+ "waitForTimeDependenciesToBeFree Test wait " << assertTimer.duration() <<
+ " taking longer than time constraint of " << assertTimer.timeConstraint() <<
+ " aborting");
+ sleep(1);
+ }
+}
+
+// test:: suspend/shutdown. During suspend the time dependencies should still
+// be handled. When the server/node is restarted/resumed the task should
+// be submitted straight away.(i.e providing no trigger/complete dependencies)
+BOOST_AUTO_TEST_CASE( test_shutdown )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_shutdown " << flush;
+ TestClean clean_at_start_and_end;
+
+ // Create the defs file corresponding to the text below
+ // ECF_HOME variable is automatically added by the test harness.
+ // ECF_INCLUDE variable is automatically added by the test harness.
+ // SLEEPTIME variable is automatically added by the test harness.
+ // ECF_CLIENT_EXE_PATH variable is automatically added by the test harness.
+ // This is substituted in sms includes
+ // Allows test to run without requiring installation
+
+ Defs theDefs;
+ {
+ // Initialise clock with todays date and time, then create a time attribute
+ // with todays time + minute Avoid adding directly to TimeSlot
+ // i.e if local time is 9:59 and we create a TimeSlot like
+ // task->addTime( ecf::TimeAttr( ecf::TimeSlot(theTm.tm_hour,theTm.tm_min+3) ) );
+ // The the minute will be 62, which is illegal and will not parse
+ boost::posix_time::ptime theLocalTime = Calendar::second_clock_time();
+
+ // For each 2 seconds of poll in the server update calendar by 1 minute
+ // Note: if we use 1 seconds poll to update calendar by 1 minute, then
+ // we will find that state change happens at job submission interval,
+ // and hence skews time series. Which can leave state in a queued state,
+ // and hence test never completes
+ suite_ptr suite = theDefs.add_suite("test_shutdown");
+ ClockAttr clockAttr(theLocalTime);
+ suite->addClock( clockAttr );
+
+ family_ptr fam = suite->add_family("family");
+ int taskSize = 2; // on linux 1024 tasks take ~4 seconds for job submission
+ for(int i=0; i < taskSize; i++) {
+ task_ptr task = fam->add_task("t" + boost::lexical_cast<std::string>(i));
+
+ boost::posix_time::ptime time1 = theLocalTime + minutes(1 + i);
+ task->addTime( ecf::TimeAttr( ecf::TimeSlot(time1.time_of_day()) ));
+
+ task->addVerify( VerifyAttr(NState::COMPLETE,1) ); // task should complete 1 times
+ }
+ }
+
+ // The test harness will create corresponding directory structure and populate with standard sms files.
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,
+ ServerTestHarness::testDataDefsLocation("test_shutdown.def"),
+ 1,
+ false/* don't wait for test to finish */);
+
+
+ // Shutdown the server. The time dependencies *should* still be handled
+ // *** If this test fails, in that we fail to restart() server it will mess up
+ // *** any following test.
+ TestFixture::client().set_throw_on_error( false );
+ BOOST_REQUIRE_MESSAGE( TestFixture::client().shutdownServer() == 0,CtsApi::shutdownServer() << " failed should return 0.\n" << TestFixture::client().errorMsg());
+
+ // wait for a period of time, while time dependencies fire.
+ (void)waitForTimeDependenciesToBeFree(timeout );
+
+ // restart server, all jobs should be launched straight away
+ BOOST_REQUIRE_MESSAGE( TestFixture::client().restartServer() == 0,CtsApi::restartServer() << " failed should return 0.\n" << TestFixture::client().errorMsg());
+
+ // Wait for submitted jobs in restart server to complete
+ bool verifyAttrInServer = true;
+ defs_ptr serverDefs = serverTestHarness.testWaiter(theDefs,timeout,verifyAttrInServer);
+ BOOST_REQUIRE_MESSAGE(serverDefs.get()," Failed to return server after restartServer");
+
+ // cout << "Printing Defs \n";
+ // std::cout << *serverDefs.get();
+
+ cout << timer.duration() << " update-calendar-count(" << serverDefs->updateCalendarCount() << ")\n";
+}
+
+
+// test:: suspend/shutdown. During suspend the time dependencies should still
+// be handled. When the server/node is restarted/resumed the task should
+// be submitted straight away.(i.e providing no trigger/complete dependencies)
+BOOST_AUTO_TEST_CASE( test_suspend_node )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_suspend_node " << flush;
+ TestClean clean_at_start_and_end;
+
+ // Create the defs file corresponding to the text below
+ // ECF_HOME variable is automatically added by the test harness.
+ // ECF_INCLUDE variable is automatically added by the test harness.
+ // SLEEPTIME variable is automatically added by the test harness.
+ // ECF_CLIENT_EXE_PATH variable is automatically added by the test harness.
+ // This is substituted in sms includes
+ // Allows test to run without requiring installation
+ Defs theDefs;
+ {
+ // Initialise clock with todays date and time, then create a time attribute
+ // with todays time + minute Avoid adding directly to TimeSlot
+ // i.e if local time is 9:59 and we create a TimeSlot like
+ // task->addTime( ecf::TimeAttr( ecf::TimeSlot(theTm.tm_hour,theTm.tm_min+3) ) );
+ // The the minute will be 62, which is illegal and will not parse
+ boost::posix_time::ptime theLocalTime = Calendar::second_clock_time();
+
+ suite_ptr suite = theDefs.add_suite("test_suspend_node");
+ ClockAttr clockAttr(theLocalTime);
+ suite->addClock( clockAttr );
+
+ task_ptr t1 = suite->add_task( "t1");
+ boost::posix_time::ptime time1 = theLocalTime + minutes(1);
+ t1->addTime( ecf::TimeAttr( ecf::TimeSlot(time1.time_of_day()) ));
+
+ task_ptr t2 = suite->add_task( "t2");
+ boost::posix_time::ptime time2 = theLocalTime + minutes(2);
+ t2->addTime( ecf::TimeAttr( ecf::TimeSlot(time2.time_of_day()) ));
+
+ family_ptr fam = suite->add_family("family");
+ for(int i=0; i < 2; i++) {
+ task_ptr task = fam->add_task("t" + boost::lexical_cast<std::string>(i));
+ task->addVerify( VerifyAttr(NState::COMPLETE,1) ); // task should complete 1 times
+
+ boost::posix_time::ptime time1 = theLocalTime + minutes(1 + i);
+ task->addTime( ecf::TimeAttr( ecf::TimeSlot(time1.time_of_day()) ));
+ }
+ }
+
+ // The test harness will create corresponding directory structure and populate with standard sms files.
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,
+ ServerTestHarness::testDataDefsLocation("test_suspend_node.def"),
+ 1,
+ false/* don't wait for test to finish */);
+
+ // SUSPEND the family. The time dependencies *should* still be handled
+ TestFixture::client().set_throw_on_error( false );
+ BOOST_REQUIRE_MESSAGE( TestFixture::client().suspend("/test_suspend_node/family") == 0,CtsApi::to_string(CtsApi::suspend("/test_suspend_node/family")) << " failed should return 0.\n" << TestFixture::client().errorMsg());
+
+ // wait for a period of time, while time dependencies fire.
+ waitForTimeDependenciesToBeFree(timeout);
+
+ // RESUME the family, all jobs should be launched straight away, since time dependencies should be free
+ BOOST_REQUIRE_MESSAGE( TestFixture::client().resume("/test_suspend_node/family") == 0,CtsApi::to_string(CtsApi::resume("/test_suspend_node/family")) << " failed should return 0.\n" << TestFixture::client().errorMsg());
+
+ // Wait for submitted jobs to complete
+ bool verifyAttrInServer = true;
+ defs_ptr serverDefs = serverTestHarness.testWaiter(theDefs,timeout,verifyAttrInServer);
+ BOOST_REQUIRE_MESSAGE(serverDefs.get()," Failed to return server after restartServer");
+
+ // cout << "Printing Defs \n";
+ // std::cout << *serverDefs.get();
+
+ cout << timer.duration() << " update-calendar-count(" << serverDefs->updateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Test/TestToday.cpp b/Test/TestToday.cpp
new file mode 100644
index 0000000..cf818fd
--- /dev/null
+++ b/Test/TestToday.cpp
@@ -0,0 +1,201 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #35 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/test/unit_test.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include "ServerTestHarness.hpp"
+#include "TestFixture.hpp"
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "DurationTimer.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+
+BOOST_AUTO_TEST_SUITE( TestSuite )
+
+// In the test case we will dynamically create all the test data.
+// The data is created dynamically so that we can stress test the server
+BOOST_AUTO_TEST_CASE( test_today_single_slot )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_today_single_slot " << flush;
+ TestClean clean_at_start_and_end;
+
+ // **************************************************************************
+ // It does not really make sense to have multiple today attributes
+ // since as soon as one today has expired the task is free to run
+ // suite test_today_mutiple_single_slot
+ // edit SLEEPTIME 1
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // clock real <todays date>
+ // family family
+ // task t1
+ // today 10.01 // after 10.01, the node is free, for 10.02,10.03
+ // today 10.04
+ // endfamily
+ // endsuite
+
+ //# Note: we have to use relative paths, since these tests are relocatable
+ //suite test_today_single_slot
+ // edit SLEEPTIME 1
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // clock real <todays date>
+ // family family
+ // task t1
+ // today 11.12
+ // endfamily
+ //endsuite
+ Defs theDefs;
+ {
+ // Initialise clock with todays date and time, then create a today attribute
+ // one hour past the clock todays time. The node should be free to run.
+ boost::posix_time::ptime theLocalTime = boost::posix_time::ptime(date(2010,6,21),time_duration(10,0,0));
+ boost::posix_time::ptime time_minus_hour = theLocalTime - hours(1);
+
+ suite_ptr suite = theDefs.add_suite( "test_today_single_slot");
+ ClockAttr clockAttr(theLocalTime,false,true/*positive gain*/);
+ suite->addClock( clockAttr );
+
+ family_ptr fam = suite->add_family( "family");
+ task_ptr task = fam->add_task( "t");
+ task->addToday( ecf::TodayAttr(ecf::TimeSlot(time_minus_hour.time_of_day())) );
+ }
+
+ // The test harness will create corresponding directory structure
+ // and populate with standard sms files.
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_today_single_slot.def"));
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_CASE( test_today_relative_time_series )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_today_relative_time_series " << flush;
+ TestClean clean_at_start_and_end;
+
+ // SLOW SYSTEMS
+ // for each time attribute leave GAP of 3 * job submission interval
+ // on slow systems submitted->active->complete > TestFixture::job_submission_interval()
+ // Also the task duration must be greater than job_submission_interval, otherwise
+ // we will get multiple invocation for the same time step
+
+ //# Note: we have to use relative paths, since these tests are relocatable
+ //suite test_today_relative_time_series
+ // edit SLEEPTIME 1
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // clock real <todays date>
+ // family family
+ // task t1
+ // today <start> <finish> <incr>
+ // endfamily
+ //endsuite
+ Defs theDefs;
+ {
+ // Initialise clock with todays date and time, then create a today attribute
+ // with a time series, so that task runs 3 times
+ suite_ptr suite = theDefs.add_suite( "test_today_relative_time_series");
+ suite->add_variable("SLEEPTIME",boost::lexical_cast<std::string>(TestFixture::job_submission_interval()-1));
+ ClockAttr clockAttr(Calendar::second_clock_time(),false);
+ suite->addClock( clockAttr );
+
+ family_ptr fam = suite->add_family( "family");
+ task_ptr task = fam->add_task( "t");
+ task->addToday( ecf::TodayAttr(
+ ecf::TimeSlot(0,1),
+ ecf::TimeSlot(0,7),
+ ecf::TimeSlot(0,3),
+ true /*relative to suite start*/
+ )
+ );
+ task->addVerify( VerifyAttr(NState::COMPLETE,3) ); // task should complete 3 times
+ }
+
+ // The test harness will create corresponding directory structure
+ // and populate with standard ecf files.
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_today_relative_time_series.def"));
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_CASE( test_today_real_time_series )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_today_real_time_series " << flush;
+ TestClean clean_at_start_and_end;
+
+ // SLOW SYSTEMS
+ // for each time attribute leave GAP of 3 * job submission interval
+ // on slow systems submitted->active->complete > TestFixture::job_submission_interval()
+ // Also the task duration must be greater than job_submission_interval, otherwise
+ // we will get multiple invocation for the same time step
+
+ //# Note: we have to use relative paths, since these tests are relocatable
+ //suite test_today_real_time_series
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // clock real <todays date>
+ // family family
+ // task t1
+ // today 10:01 10:07 00:03
+ // endfamily
+ //endsuite
+ Defs theDefs;
+ {
+ // Initialise clock with a fixed date and time, then create a today attribute
+ // with a time series, so that task runs 3 times
+ boost::posix_time::ptime theLocalTime = boost::posix_time::ptime(date(2010,6,21),time_duration(10,0,0));
+ boost::posix_time::ptime time1 = theLocalTime + minutes(1);
+ boost::posix_time::ptime time2 = theLocalTime + minutes(7);
+
+ suite_ptr suite = theDefs.add_suite( "test_today_real_time_series");
+ ClockAttr clockAttr(theLocalTime,false);
+ suite->addClock( clockAttr );
+ suite->add_variable("SLEEPTIME",boost::lexical_cast<std::string>(TestFixture::job_submission_interval()-1));
+ suite->addVerify( VerifyAttr(NState::COMPLETE,1) );
+
+ family_ptr fam = suite->add_family( "family");
+ fam->addVerify( VerifyAttr(NState::COMPLETE,1) );
+ task_ptr task = fam->add_task( "t");
+ task->addToday( ecf::TodayAttr(
+ ecf::TimeSlot(time1.time_of_day()),
+ ecf::TimeSlot(time2.time_of_day()),
+ ecf::TimeSlot(0,3)
+ )
+ );
+ task->addVerify( VerifyAttr(NState::COMPLETE,3) ); // task should complete 3 times
+ }
+
+ // The test harness will create corresponding directory structure
+ // and populate with standard ecf files.
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_today_real_time_series.def"));
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Test/TestTrigger.cpp b/Test/TestTrigger.cpp
new file mode 100644
index 0000000..691be9a
--- /dev/null
+++ b/Test/TestTrigger.cpp
@@ -0,0 +1,92 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #29 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/test/unit_test.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include "ServerTestHarness.hpp"
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "DurationTimer.hpp"
+#include "Str.hpp"
+
+
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( TestSuite )
+
+// In the test case we will dynamically create all the test data.
+// The data is created dynamically so that we can stress test the server
+// This test does not have any time dependencies in the def file.
+BOOST_AUTO_TEST_CASE( test_triggers_and_meters )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_triggers_and_meters " << flush;
+ TestClean clean_at_start_and_end;
+
+ //# Note: we have to use relative paths, since these tests are relocatable
+ //suite test_triggers_and_meters
+ // edit SLEEPTIME 1
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // family family
+ // task model
+ // meter file 0 100 100
+ // task t0
+ // trigger model:file ge 10
+ // task t1
+ // trigger model:file ge 20
+ // task t2
+ // trigger model:file ge 30
+ // ....
+ // endfamily
+ //endsuite
+ std::string meterName = "file";
+ std::string taskName = "model";
+ Defs theDefs;
+ {
+ suite_ptr suite = theDefs.add_suite( "test_triggers_and_meters");
+ suite->addVerify( VerifyAttr(NState::COMPLETE,1) );
+ family_ptr fam = suite->add_family( "family");
+ fam->addVerify( VerifyAttr(NState::COMPLETE,1) );
+
+ task_ptr taskModel = fam->add_task(taskName);
+ taskModel->addMeter( Meter(meterName,0,100,100) ); // ServerTestHarness will add correct ecf
+
+ int taskSize = 9; // on linux 1024 tasks take ~4 seconds for job submission
+ for(int i=0; i < taskSize; i++) {
+ task_ptr task = fam->add_task( "t" + boost::lexical_cast<std::string>(i*10 + 10) );
+ task->addVerify( VerifyAttr(NState::COMPLETE,1) );
+ task->add_trigger( taskName + Str::COLON() + meterName + " ge " + boost::lexical_cast<std::string>(i*10 + 10) );
+ }
+ }
+
+ // The test harness will create corresponding directory structure & default ecf file
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation( "test_triggers_and_meters.def"));
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Test/TestWhyCmd.cpp b/Test/TestWhyCmd.cpp
new file mode 100644
index 0000000..f522e5c
--- /dev/null
+++ b/Test/TestWhyCmd.cpp
@@ -0,0 +1,538 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #27 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <iostream>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/lexical_cast.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include "ServerTestHarness.hpp"
+#include "TestFixture.hpp"
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "DurationTimer.hpp"
+#include "PrintStyle.hpp"
+#include "ClientToServerCmd.hpp"
+#include "AssertTimer.hpp"
+#include "WhyCmd.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( TestSuite )
+
+static unsigned int waitForWhy(const std::string& path, const std::string& why, int max_time_to_wait)
+{
+ unsigned int updateCalendarCount = 0;
+ TestFixture::client().set_throw_on_error( false );
+ AssertTimer assertTimer(max_time_to_wait,false); // Bomb out after n seconds, fall back if test fail
+ while (1) {
+
+ /// Why command relies on the Suite serializing the calendar. If this is changed we need to get the full defs
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0, "sync_local failed should return 0\n" << TestFixture::client().errorMsg());
+ defs_ptr server_defs = TestFixture::client().defs();
+ updateCalendarCount = server_defs->updateCalendarCount();
+
+ WhyCmd whyCmd( server_defs, path);
+ std::string reason = whyCmd.why();
+ // std::cout << reason;
+
+ if (reason.find(why) != std::string::npos) {
+ // see the reason why job is not running
+ std::cout << reason;
+ break;
+ }
+
+ BOOST_REQUIRE_MESSAGE(assertTimer.duration() < assertTimer.timeConstraint(),
+ "waitForWhy Test wait " << assertTimer.duration() <<
+ " taking longer than time constraint of " << assertTimer.timeConstraint() <<
+ " aborting\n" << *server_defs);
+ sleep(1);
+ }
+ return updateCalendarCount;
+}
+
+BOOST_AUTO_TEST_CASE( test_why_day )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_why_day "<< flush;
+ TestClean clean_at_start_and_end;
+
+ Defs theDefs;
+ {
+ boost::posix_time::ptime today = Calendar::second_clock_time();
+ suite_ptr suite = Suite::create("test_why_day" ) ;
+ family_ptr fam = Family::create( "family" );
+ task_ptr task = Task::create( "t1" );
+
+ // Dont use hybrid for day dependency as that will force node to complete if days is not the same
+ ClockAttr clockAttr(today, false);
+ suite->addClock( clockAttr );
+
+ // ** add tomorrow days so that node stays queued **
+ task->addDay( DayAttr( today.date() + boost::gregorian::date_duration(1 ) ) );
+
+ fam->addTask( task );
+ suite->addFamily( fam );
+ theDefs.addSuite( suite );
+ }
+
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,
+ ServerTestHarness::testDataDefsLocation("test_why_day.def"),
+ 1/*timeout*/,
+ false /* waitForTestCompletion*/);
+
+ // The job should not be submitted and should stay queued since the day does not match
+ // running the why command, should report dependency on day
+ unsigned int updateCalendarCount = waitForWhy("/test_why_day/family/t1", "day", 10);
+
+ cout << " " << timer.duration() << " update-calendar-count(" << updateCalendarCount << ")\n";
+}
+
+BOOST_AUTO_TEST_CASE( test_why_date )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_why_date "<< flush;
+
+ Defs theDefs;
+ {
+ suite_ptr suite = Suite::create("test_why_date" ) ;
+ family_ptr fam = Family::create( "family" );
+ task_ptr task = Task::create( "t1" );
+
+ // Don't use hybrid for date dependency as that will force node to complete if date is not the same
+ boost::posix_time::ptime today = Calendar::second_clock_time();
+ ClockAttr clockAttr(today, false);
+ suite->addClock( clockAttr );
+
+ // ** add tomorrow date so that node stays queued **
+ task->addDate( DateAttr( today.date() + boost::gregorian::date_duration(1 )) );
+ fam->addTask( task );
+ suite->addFamily( fam );
+ theDefs.addSuite( suite );
+ }
+
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,
+ ServerTestHarness::testDataDefsLocation("test_why_date.def"),
+ 1/*timeout*/,
+ false /* waitForTestCompletion*/);
+
+ // The job should not be submitted and should stay queued since the day does not match
+ // running the why command, should report dependency on day
+ unsigned int updateCalendarCount = waitForWhy("/test_why_date/family/t1", "date", 10);
+
+ cout << " " << timer.duration() << " update-calendar-count(" << updateCalendarCount << ")\n";
+}
+
+BOOST_AUTO_TEST_CASE( test_why_time )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_why_time "<< flush;
+
+ Defs theDefs;
+ {
+ boost::posix_time::ptime theLocalTime = Calendar::second_clock_time();
+ boost::posix_time::ptime time1 = theLocalTime - hours(1);
+
+ suite_ptr suite = Suite::create("test_why_time" ) ;
+ family_ptr fam = Family::create( "family" );
+ task_ptr task = Task::create( "t1" );
+
+ ClockAttr clockAttr(theLocalTime);
+ suite->addClock( clockAttr );
+
+ task->addTime( ecf::TimeAttr( ecf::TimeSlot(time1.time_of_day()) ) );
+ fam->addTask( task );
+ suite->addFamily( fam );
+ theDefs.addSuite( suite );
+ }
+
+
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,
+ ServerTestHarness::testDataDefsLocation("test_why_time.def"),
+ 1/*timeout*/,
+ false /* waitForTestCompletion*/);
+
+ // The job should not be submitted and should stay queued since the time does not match
+ // running the why command, should report dependency on time
+ unsigned int updateCalendarCount = waitForWhy("/test_why_time/family/t1", "time", 10);
+
+ cout << " " << timer.duration() << " update-calendar-count(" << updateCalendarCount << ")\n";
+}
+
+BOOST_AUTO_TEST_CASE( test_why_today )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_why_today "<< flush;
+
+ Defs theDefs;
+ {
+ // IMPORTANT: A Node with a today attribute is *free* to run *IF* the suite
+ // calendar time is greater than the today date.
+ // Hence if we start this test just before midnight i.e 11.20,
+ // and add hour , then the today time would be 00:20
+ // *i.e node is free to run*
+ // This is not what we want for this test. i.e we depend on node being queued
+ // in order to test the why command. Also the following tests, start
+ // by deleting all nodes. This will fail due to active/submitted tasks
+ // Hence can *NOT* use:
+ // boost::posix_time::ptime theLocalTime = Calendar::second_clock_time();
+ // boost::posix_time::ptime time1 = theLocalTime + hours(1);
+
+ // Use a hard coded a time, to avoid failure if test is run just before midnight
+ boost::posix_time::ptime theLocalTime(date(2010,2,10), hours(1));
+ boost::posix_time::ptime time1 = theLocalTime + hours(1);
+
+ suite_ptr suite = theDefs.add_suite("test_why_today" ) ;
+ ClockAttr clockAttr(theLocalTime);
+ suite->addClock( clockAttr );
+
+ family_ptr fam = suite->add_family( "family" );
+ task_ptr task = fam->add_task( "t1" );
+ task->addToday( ecf::TodayAttr( ecf::TimeSlot(time1.time_of_day()) ) );
+ }
+
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,
+ ServerTestHarness::testDataDefsLocation("test_why_today.def"),
+ 1/*timeout*/,
+ false /* waitForTestCompletion*/);
+
+ // The job should not be submitted and should stay queued since the time does not match
+ // running the why command, should report dependency on time
+ unsigned int updateCalendarCount = waitForWhy("/test_why_today/family/t1", "today", 10);
+
+ cout << " " << timer.duration() << " update-calendar-count(" << updateCalendarCount << ")\n";
+}
+
+BOOST_AUTO_TEST_CASE( test_why_cron )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_why_cron "<< flush;
+
+ Defs theDefs;
+ {
+ boost::posix_time::ptime theLocalTime = boost::posix_time::ptime(date(2010,6,21),time_duration(11,0,0));
+ boost::posix_time::ptime time1 = theLocalTime - hours(3);
+ boost::posix_time::ptime time2 = theLocalTime - hours(1);
+ boost::gregorian::date todaysDate = theLocalTime.date();
+
+ suite_ptr suite = Suite::create("test_why_cron" ) ;
+ family_ptr fam = Family::create( "family" );
+ task_ptr task = Task::create( "t1" );
+
+ ClockAttr clockAttr(theLocalTime,false/*real*/);
+ suite->addClock( clockAttr );
+
+ // ** IMPORTANT **, for a date in the future we must match day of week,
+ // *************** day of month, and year, i.e the results are ANDED
+ // *************** this can lead to unexpected time in the future
+ // *************** if all 3 dependencies are present, as *below*
+ ecf::CronAttr cronAttr;
+ ecf::TimeSlot start( time1.time_of_day() ); // in the past
+ ecf::TimeSlot finish( time2.time_of_day() ); // in the past
+ ecf::TimeSlot incr( 0, 5 );
+ cronAttr.addTimeSeries(start,finish,incr);
+
+ std::vector<int> weekDays; weekDays.push_back(todaysDate.day_of_week().as_number());
+ std::vector<int> daysOfMonth; daysOfMonth.push_back( todaysDate.day() );
+ std::vector<int> months; months.push_back( todaysDate.month() );
+ cronAttr.addWeekDays( weekDays );
+ cronAttr.addDaysOfMonth( daysOfMonth );
+ cronAttr.addMonths( months );
+
+ task->addCron(cronAttr);
+
+ fam->addTask( task );
+ suite->addFamily( fam );
+ theDefs.addSuite( suite );
+ }
+
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,
+ ServerTestHarness::testDataDefsLocation("test_why_cron.def"),
+ 1/*timeout*/,
+ false /* waitForTestCompletion*/);
+
+ // The job should not be submitted and should stay queued we are past the cron time
+ // running the why command, should report dependency on cron
+ unsigned int updateCalendarCount = waitForWhy("/test_why_cron/family/t1", "cron", 10);
+
+ cout << " " << timer.duration() << " update-calendar-count(" << updateCalendarCount << ")\n";
+}
+
+BOOST_AUTO_TEST_CASE( test_why_limit )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_why_limit "<< flush;
+
+ // Testing for limits requires that we have least some jobs are submitted.
+ // we need to kill these jobs, at the end of test.
+
+ // suite test_why_limit
+ // limit disk 50
+ // family family
+ // inlimit /suite1:disk 50
+ // task t0
+ // task t1
+ // task t2
+ // task t3
+ // task t4
+ // task t5
+ // endfamily
+ // endsuite
+
+ Defs theDefs;
+ {
+ std::string suiteName = "test_why_limit";
+ std::string pathToLimit = "/" + suiteName;
+ suite_ptr suite = theDefs.add_suite(suiteName );
+ suite->addVariable( Variable("ECF_TRIES","1") );
+ suite->addLimit(Limit("disk",50));
+
+ family_ptr fam = suite->add_family( "family");
+ fam->addInLimit(InLimit("disk",pathToLimit,50));
+ int taskSize = 6;
+ for(int i=0; i < taskSize; i++) {
+ fam->addTask( Task::create("t" + boost::lexical_cast<std::string>(i)) );
+ }
+ }
+
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,
+ ServerTestHarness::testDataDefsLocation( "test_why_limit.def" ),
+ 1/*timeout*/,
+ false /* waitForTestCompletion*/);
+
+ // Only one job should be submitted, at a time, we will query on task t5, which
+ // should still be queued because the limit is full
+ // running the why command, should report dependency on limit
+ waitForWhy("/test_why_limit/family/t5", "limit", 10);
+
+ // The main check is over. Wait for jobs to complete
+ int updateCalendarCount = 0;
+ TestFixture::client().set_throw_on_error(false) ;
+ {
+ AssertTimer assertTimer(50,false); // Bomb out after n seconds, fall back if test fail
+ while (1) {
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().getDefs() == 0,CtsApi::get() << " failed should return 0\n" << TestFixture::client().errorMsg());
+ defs_ptr defs = TestFixture::client().defs();
+ updateCalendarCount = defs->updateCalendarCount();
+ bool wait = false;
+ vector<Task*> tasks; defs->getAllTasks(tasks);
+ BOOST_FOREACH(Task* task, tasks) {
+ if (task->state() != NState::COMPLETE) wait = true;
+ }
+ if (!wait) break;
+ if ( assertTimer.duration() >= assertTimer.timeConstraint()) {
+ cout << "waitFor jobs to complete, wait time of " << assertTimer.duration() <<
+ " taking longer than time constraint of " << assertTimer.timeConstraint() <<
+ " aborting, ......breaking out\n" << *defs << "\n";
+ }
+ sleep(1);
+ }
+ }
+ cout << " " << timer.duration() << " update-calendar-count(" << updateCalendarCount << ")\n";
+}
+
+BOOST_AUTO_TEST_CASE( test_why_trigger )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_why_trigger "<< flush;
+
+ Defs theDefs;
+ {
+ suite_ptr suite = Suite::create("test_why_trigger" ) ;
+ family_ptr fam = Family::create( "family" );
+ task_ptr task = Task::create( "t1" );
+ task->add_trigger( "1 == 0");
+ fam->addTask( task );
+ suite->addFamily( fam );
+ theDefs.addSuite( suite );
+ }
+
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,
+ ServerTestHarness::testDataDefsLocation("test_why_trigger.def"),
+ 1/*timeout*/,
+ false /* waitForTestCompletion*/);
+
+ // Waiting for a trigger expression which will never evaluate
+ unsigned int updateCalendarCount = waitForWhy("/test_why_trigger/family/t1", "expression", 10);
+
+ cout << " " << timer.duration() << " update-calendar-count(" << updateCalendarCount << ")\n";
+}
+
+BOOST_AUTO_TEST_CASE( test_why_meter )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_why_meter "<< flush;
+
+ Defs theDefs;
+ {
+ suite_ptr suite = Suite::create("test_why_meter" ) ;
+ family_ptr fam = Family::create( "family" );
+ fam->addMeter( Meter("meter",0,100,100) );
+ task_ptr task = Task::create( "t1" );
+ task->add_trigger( "/test_why_meter/family:meter > 20");
+ fam->addTask( task );
+ suite->addFamily( fam );
+ theDefs.addSuite( suite );
+ }
+
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,
+ ServerTestHarness::testDataDefsLocation("test_why_meter.def"),
+ 1/*timeout*/,
+ false /* waitForTestCompletion*/);
+
+ // Waiting for a trigger expression which references a meter.
+ unsigned int updateCalendarCount = waitForWhy("/test_why_meter/family/t1", "/test_why_meter/family:meter", 10);
+
+ cout << " " << timer.duration() << " update-calendar-count(" << updateCalendarCount << ")\n";
+}
+
+BOOST_AUTO_TEST_CASE( test_why_event )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_why_event "<< flush;
+
+ Defs theDefs;
+ {
+ suite_ptr suite = Suite::create("test_why_event" ) ;
+ family_ptr fam = Family::create( "family" );
+ task_ptr t1 = Task::create( "t1" );
+ task_ptr t2 = Task::create( "t2" );
+ t2->addEvent( Event(1,"theEvent") );
+ t2->add_trigger( "1 == 0" ); // make sure task t2 never runs
+ t1->add_trigger( "/test_why_event/family/t2:theEvent == set" );
+ fam->addTask( t1 );
+ fam->addTask( t2 );
+ suite->addFamily( fam );
+ theDefs.addSuite( suite );
+ }
+
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,
+ ServerTestHarness::testDataDefsLocation("test_why_event.def"),
+ 1/*timeout*/,
+ false /* waitForTestCompletion*/);
+
+ // Task t1, should stay queued because the event on task t2 is never set.
+ unsigned int updateCalendarCount = waitForWhy("/test_why_event/family/t1", "/test_why_event/family/t2:theEvent", 10);
+
+ cout << " " << timer.duration() << " update-calendar-count(" << updateCalendarCount << ")\n";
+}
+
+BOOST_AUTO_TEST_CASE( test_why_user_var )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_why_user_var "<< flush;
+
+ Defs theDefs;
+ {
+ suite_ptr suite = Suite::create("test_why_user_var" ) ;
+ family_ptr fam = Family::create( "family" );
+ task_ptr t1 = Task::create( "t1" );
+ suite->addVariable( Variable("user_var","10") );
+ t1->add_trigger( "/test_why_user_var:user_var eq 100" );
+ fam->addTask( t1 );
+ suite->addFamily( fam );
+ theDefs.addSuite( suite );
+ }
+
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,
+ ServerTestHarness::testDataDefsLocation("test_why_user_var.def"),
+ 1/*timeout*/,
+ false /* waitForTestCompletion*/);
+
+ // Task t1, should stay queued because the user variable 'user_var' value = 10, is not 100
+ unsigned int updateCalendarCount = waitForWhy("/test_why_user_var/family/t1", "/test_why_user_var:user_var", 10);
+
+ cout << " " << timer.duration() << " update-calendar-count(" << updateCalendarCount << ")\n";
+}
+
+BOOST_AUTO_TEST_CASE( test_why_gen_var )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_why_gen_var "<< flush;
+
+ Defs theDefs;
+ {
+ suite_ptr suite = Suite::create("test_why_gen_var" ) ;
+ family_ptr fam = Family::create( "family" );
+ task_ptr t1 = Task::create( "t1" );
+ t1->add_trigger( "/test_why_gen_var/family/t1:ECF_TRYNO eq 100" );
+ fam->addTask( t1 );
+ suite->addFamily( fam );
+ theDefs.addSuite( suite );
+ }
+
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,
+ ServerTestHarness::testDataDefsLocation("test_why_gen_var.def"),
+ 1/*timeout*/,
+ false /* waitForTestCompletion*/);
+
+ // Task t1, should stay queued because the generated variable 'ECF_TRYNO' value = 0, is not 100
+ unsigned int updateCalendarCount = waitForWhy("/test_why_gen_var/family/t1", "/test_why_gen_var/family/t1:ECF_TRYNO", 10);
+
+ cout << " " << timer.duration() << " update-calendar-count(" << updateCalendarCount << ")\n";
+}
+
+BOOST_AUTO_TEST_CASE( test_why_repeat )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_why_repeat "<< flush;
+
+ Defs theDefs;
+ {
+ suite_ptr suite = Suite::create("test_why_repeat" ) ;
+ family_ptr fam = Family::create( "family" );
+ task_ptr t1 = Task::create( "t1" );
+ suite->addRepeat( RepeatInteger("suite_repeat_var",0,3,1));
+ fam->addRepeat( RepeatInteger("family_repeat_var",0,3,1));
+ t1->add_trigger( "/test_why_repeat/family:family_repeat_var eq 100 or /test_why_repeat:suite_repeat_var eq 100" );
+ fam->addTask( t1 );
+ suite->addFamily( fam );
+ theDefs.addSuite( suite );
+ }
+
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,
+ ServerTestHarness::testDataDefsLocation("test_why_repeat.def"),
+ 1/*timeout*/,
+ false /* waitForTestCompletion*/);
+
+ // Task t1, should stay queued because the repeat variable on the suite and family do not match
+ unsigned int updateCalendarCount = waitForWhy("/test_why_repeat/family/t1", "/test_why_repeat/family:family_repeat_var", 10);
+
+ cout << " " << timer.duration() << " update-calendar-count(" << updateCalendarCount << ")\n";
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/Test/TestZombies.cpp b/Test/TestZombies.cpp
new file mode 100644
index 0000000..76d0b1e
--- /dev/null
+++ b/Test/TestZombies.cpp
@@ -0,0 +1,948 @@
+#define BOOST_TEST_MODULE TEST_ZOMBIES
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #58 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : This is used to INVOKE a SINGLE test.
+// Making it easier for Easier for debugging and development
+//============================================================================
+#include <iostream>
+#include <limits> // for std::numeric_limits<int>::max()
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/lexical_cast.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include "TestFixture.hpp"
+#include "ServerTestHarness.hpp"
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "DurationTimer.hpp"
+#include "PrintStyle.hpp"
+#include "AssertTimer.hpp"
+#include "Child.hpp"
+#include "ZombieUtil.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+namespace fs = boost::filesystem;
+
+// ****************************************************************
+// In the test below we create two sets of process. One of these
+// being a zombie. The test below create a list of user Zombies.
+// In the cases where these test fail
+// The dump of zombies shows that only One call was made.(i.e the initial creation of the Zombie)
+// and that the proces-id is not defined.
+// This implies that at test start, that not all process were started.
+// ??Note sure why?? This can be seen by enabling debug in TaskCmds which
+// shows that the Task INIT command was never received ???
+// Updated these test to detect STALE *user* zombies & remove them
+// i.e. where we have created a user Zombie but there is associated process ??
+// *******************************************************************
+
+//#define DEBUG_ZOMBIE 1
+#define DO_TEST1 1
+#define DO_TEST2 1
+#define DO_TEST3 1
+#define DO_TEST4 1
+#define DO_TEST5 1
+#define DO_TEST6 1
+#define DO_TEST7 1
+#define DO_TEST8 1
+#define DO_TEST9 1
+//#define DO_TEST10 1 Need to make reliable
+#define DO_TEST11 1
+
+static bool ecf_debug_enabled = false; // allow environment to enable debug
+
+
+BOOST_GLOBAL_FIXTURE( TestFixture );
+
+BOOST_AUTO_TEST_SUITE( TestSuite )
+
+enum WaitType { SINGLE, ALL };
+static int timeout = 30;
+static int NUM_OF_TASKS = 5;
+
+static void dump_zombies()
+{
+ TestFixture::client().zombieGet();
+ std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
+ std::cout << Zombie::pretty_print( zombies , 3);
+}
+
+static void dump_tasks(const vector<Task*>& tasks) {
+ BOOST_FOREACH(const Task* task, tasks) {
+ std::cout << " " << task->absNodePath() << " " << NState::toString(task->state()) << " " << task->jobsPassword() << " " << task->process_or_remote_id() << "\n";
+ }
+ std::cout << "\n";
+}
+
+static bool waitForTaskStates(WaitType num_of_tasks,NState::State state1,NState::State state2, int max_time_to_wait)
+{
+ std::string wait_type_str = (num_of_tasks == SINGLE ) ? "SINGLE" : "ALL";
+ if (ecf_debug_enabled) {
+ if ( num_of_tasks == SINGLE) {
+ if (state1 == state2) std::cout << "\n Waiting for SINGLE task to reach state " << NState::toString(state1) << "\n";
+ else std::cout << "\n Waiting for SINGLE task to reach state " << NState::toString(state1) << " || " << NState::toString(state2) << "\n";
+ }
+ else {
+ if (state1 == state2) std::cout << "\n Waiting for ALL tasks to reach state " << NState::toString(state1) << "\n";
+ else std::cout << "\n Waiting for ALL tasks to reach state " << NState::toString(state1) << " || " << NState::toString(state2) << "\n";
+ }
+ }
+ AssertTimer assertTimer(max_time_to_wait,false); // Bomb out after n seconds, fall back if test fail
+ while (1) {
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0, "waitForTaskStates: sync_local failed should return 0\n" << TestFixture::client().errorMsg());
+ defs_ptr defs = TestFixture::client().defs();
+ vector<Task*> tasks; defs->getAllTasks(tasks);
+ if (num_of_tasks == SINGLE) {
+ BOOST_FOREACH(Task* task, tasks) {
+ if (task->state() == state1 || task->state() == state2 ) {
+ if (ecf_debug_enabled) {
+ if (task->state() == state1) std::cout << " Found at least one Task with state " << NState::toString(state1) << " returning\n";
+ if (state1 != state2 && task->state() == state2) std::cout << " Found at least one Task with state " << NState::toString(state2) << " returning\n";
+ dump_zombies();
+ }
+ return true;
+ }
+ }
+ }
+ else {
+ size_t count = 0;
+ BOOST_FOREACH(Task* task, tasks) { if (task->state() == state1 || task->state() == state2) count++; }
+ if (count == tasks.size()) {
+ if (ecf_debug_enabled) {
+ if (state2 == state1) std::cout << " All tasks(" << tasks.size() << ") have reached state " << NState::toString(state1) << " returning\n";
+ else std::cout << " All tasks(" << tasks.size() << ") have reached state " << NState::toString(state1) << " || " << NState::toString(state2) << " returning\n";
+ dump_tasks(tasks);
+ }
+ return true;
+ }
+ }
+
+ if ( assertTimer.duration() >= assertTimer.timeConstraint() ) {
+ if (ecf_debug_enabled) {
+ dump_zombies();
+ dump_tasks(tasks);
+ std::cout << "waitForTaskState " << wait_type_str << " reach state " << NState::toString(state1) << " || " << NState::toString(state2)
+ << " Test taking longer than time constraint of " << assertTimer.timeConstraint() << " returning false\n";
+ }
+ break;
+ }
+ sleep(1);
+ }
+ return false;
+}
+
+static bool waitForTaskState(WaitType wait_type,NState::State state1, int max_time_to_wait)
+{
+ return waitForTaskStates(wait_type, state1, state1, max_time_to_wait);
+}
+
+static bool waitForZombieCreation(size_t no_of_zombies, int max_time_to_wait)
+{
+ if (ecf_debug_enabled) std::cout << "\n Waiting for " << no_of_zombies << " zombies to be created\n";
+
+ AssertTimer assertTimer(max_time_to_wait,false); // Bomb out after n seconds, fall back if test fail
+ while (1) {
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().zombieGet() == 0, "zombieGet failed should return 0\n" << TestFixture::client().errorMsg());
+ std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
+ if (zombies.size() == no_of_zombies) {
+ if (ecf_debug_enabled) {
+ std::cout << Zombie::pretty_print( zombies , 3);
+ std::cout << " Found " << no_of_zombies << " zombies. returning.\n";
+ }
+ return true;
+ }
+ if ( assertTimer.duration() >= assertTimer.timeConstraint() ) {
+
+ if (zombies.size() > 0) {
+ if (ecf_debug_enabled) {
+ std::cout << " Timeout out found only " << zombies.size() << " zombies." << "\n";
+ std::cout << Zombie::pretty_print( zombies , 3);
+ std::cout << " Found " << no_of_zombies << " zombies. returning.\n";
+ }
+ return true;
+ }
+
+ BOOST_REQUIRE_MESSAGE(assertTimer.duration() < assertTimer.timeConstraint(),
+ "waitForZombieCreation expected " << no_of_zombies
+ << " zombies but found " << TestFixture::client().server_reply().zombies().size()
+ << " : Test taking longer than time constraint of "
+ << assertTimer.timeConstraint() << " aborting\n"
+ << Zombie::pretty_print( zombies , 3));
+ break;
+ }
+ sleep(1);
+ }
+ return false;
+}
+
+static void remove_stale_zombies()
+{
+ // Remove those zombies that have only *ONE* call
+ // There is no associated process/child command that has updated the zombie
+ if (ecf_debug_enabled) cout << "\n remove_stale_zombies \n";
+
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().zombieGet() == 0, "zombieGet failed should return 0\n" << TestFixture::client().errorMsg());
+ std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
+ BOOST_FOREACH(const Zombie& z, zombies) {
+ if (z.calls() == 1) {
+ cout << "\n **** removing_stale_zombies ***** " << z << "\n";
+ cout << " Typically happens when a submitted job, never creates a process ?\n";
+ cout << " Since the process never communicated back, the pid is empty.\n";
+ TestFixture::client().zombieRemove(z);
+ }
+ }
+}
+
+static void wait_for_path_zombies(int no_of_tasks, int max_time_to_wait)
+{
+ if (ecf_debug_enabled) cout << "\n wait_for_path_zombies\n";
+
+ int no_of_path_zombies = 0;
+ std::vector<Zombie> zombies;
+ AssertTimer assertTimer(max_time_to_wait,false); // Bomb out after n seconds, fall back if test fail
+ while (1) {
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().zombieGet() == 0, "zombieGet failed should return 0\n" << TestFixture::client().errorMsg());
+ zombies = TestFixture::client().server_reply().zombies();
+ BOOST_FOREACH(const Zombie& z, zombies) {
+ if (z.type() == Child::PATH ) {
+ no_of_path_zombies++;
+ }
+ }
+ if (no_of_path_zombies >= no_of_tasks) break;
+ // make sure test does not take too long.
+ if ( assertTimer.duration() >= assertTimer.timeConstraint() ) {
+ // BOOST_WARN_MESSAGE(assertTimer.duration() < assertTimer.timeConstraint(),
+ std::cout << "remove_user_zombies_and_wait_for_path_zombies. Expected "
+ << no_of_tasks << " PATH zombies, but found " << no_of_path_zombies
+ << "\nTest taking longer than time constraint of " << assertTimer.timeConstraint()
+ << "\n"
+ << Zombie::pretty_print( zombies , 6) << "\n... breaking out\n";
+ break;
+ }
+ sleep(1);
+ }
+
+ if (ecf_debug_enabled) cout << Zombie::pretty_print( zombies , 6) << "\n";
+}
+
+
+static void check_expected_no_of_zombies(size_t expected)
+{
+ TestFixture::client().zombieGet();
+ std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
+
+ BOOST_CHECK_MESSAGE(zombies.size() == expected ,"Expected " << expected << " zombies but got " << zombies.size());
+ if ( zombies.size() != expected) {
+ std::cout << Zombie::pretty_print( zombies , 3);
+ return;
+ }
+}
+
+static void check_at_least_one_zombie()
+{
+ TestFixture::client().zombieGet();
+ std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
+ BOOST_CHECK_MESSAGE(zombies.size() >= 1 ,"Expected at least one zombies but got nothing\n");
+}
+
+static bool wait_for_zombie_termination(int max_time_to_wait)
+{
+ if (ecf_debug_enabled) std::cout << "\n wait_for_zombie_termination\n";
+
+ AssertTimer assertTimer(max_time_to_wait,false); // Bomb out after n seconds, fall back if test fail
+ while (1) {
+ TestFixture::client().zombieGet();
+ std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
+ if (zombies.empty() ) break;
+
+ if ( assertTimer.duration() >= assertTimer.timeConstraint() ) {
+ if (ecf_debug_enabled) {
+ std::cout << "wait_for_zombie_termination: taking longer than time constraint of " << assertTimer.timeConstraint() << " returning\n";
+ std::cout << Zombie::pretty_print( zombies , 3);
+ }
+ return false;
+ }
+ sleep(1);
+ }
+ return true;
+}
+
+static void wait_for_zombies_child_cmd(WaitType wait_type,ecf::Child::CmdType child_cmd,int max_time_to_wait, bool do_delete = false)
+{
+ if (ecf_debug_enabled) {
+ std::cout << "\n Waiting for ";
+ if (wait_type == SINGLE) std::cout << "SINGLE";
+ else std::cout << "ALL";
+ std::cout << " child (" << Child::to_string(child_cmd) << ") cmd; ";
+ if (do_delete) std::cout << " then DELETE zombies ";
+ std::cout << "=============================================================================================\n";
+ }
+
+ bool child_type_found = false;
+ AssertTimer assertTimer(max_time_to_wait,false); // Bomb out after n seconds, fall back if test fail
+ while (1) {
+ TestFixture::client().zombieGet();
+ std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
+ if (ecf_debug_enabled) std::cout << " Get zombies returned " << zombies.size() << "\n";
+
+ if (zombies.empty() && child_type_found && do_delete) {
+ if (ecf_debug_enabled) std::cout << " No zombies. (do_delete) was set returning\n";
+ return;
+ }
+
+ size_t completed_zombies = 0;
+ BOOST_FOREACH(const Zombie& z, zombies) {
+ if (ecf_debug_enabled) std::cout << " " << z << "\n";
+ if (z.last_child_cmd() == child_cmd) {
+ child_type_found = true;
+ completed_zombies++;
+ if (wait_type == SINGLE) {
+ if (ecf_debug_enabled) {
+ std::cout << " " << z << "\n";
+ std::cout << " Found SINGLE zombie of correct child type returning\n";
+ }
+ return;
+ }
+ }
+ }
+
+ if ( completed_zombies == zombies.size() && child_type_found) {
+ if (ecf_debug_enabled) {
+ std::cout << " Found ALL(" << completed_zombies << ") zombies of child type " << Child::to_string(child_cmd) << "\n";
+ std::cout << Zombie::pretty_print( zombies , 3);
+ }
+ if (do_delete) {
+ BOOST_FOREACH(const Zombie& z, zombies) {
+ if (ecf_debug_enabled) std::cout << " deleteing " << z << "\n";
+ TestFixture::client().zombieRemove(z);
+ }
+ }
+ return;
+ }
+
+ // make sure test does not take too long.
+ if ( assertTimer.duration() >= assertTimer.timeConstraint() ) {
+ std::cout << Zombie::pretty_print( zombies , 3);
+ BOOST_REQUIRE_MESSAGE(assertTimer.duration() < assertTimer.timeConstraint(),
+ "wait_for_zombies_child_cmd Test wait " << assertTimer.duration() <<
+ " taking longer than time constraint of " << assertTimer.timeConstraint() <<
+ " aborting\n");
+ }
+ sleep(1);
+ }
+}
+
+static void wait_for_no_zombies(int max_time_to_wait)
+{
+ if (ecf_debug_enabled) std::cout << "\n wait_for_no_zombies\n";
+
+ AssertTimer assertTimer(max_time_to_wait,false); // Bomb out after n seconds, fall back if test fail
+ while (1) {
+ TestFixture::client().zombieGet();
+ std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
+ if (ecf_debug_enabled) {
+ std::cout << " Get zombies returned " << zombies.size() << "\n";
+ std::cout << Zombie::pretty_print( zombies , 6) << "\n";
+ }
+ if (zombies.empty()) return;
+
+ // make sure test does not take too long.
+ if ( assertTimer.duration() >= assertTimer.timeConstraint() ) {
+ std::cout << "\n" << Zombie::pretty_print( zombies , 3);
+ BOOST_REQUIRE_MESSAGE(assertTimer.duration() < assertTimer.timeConstraint(),
+ "wait_for_no_zombies Test wait " << assertTimer.duration() <<
+ " taking longer than time constraint of " << assertTimer.timeConstraint() <<
+ " aborting\n");
+ }
+ sleep(2);
+ }
+}
+
+static void populate_defs(Defs& theDefs,const std::string& suite_name) {
+ suite_ptr suite = theDefs.add_suite(suite_name);
+ suite->addVariable(Variable("SLEEPTIME","5")); // sleep for longer than normal to allow for creation of zombies
+ family_ptr family = suite->add_family("f");
+ for (int i = 0; i < NUM_OF_TASKS; i++) {
+ family->add_task( "t" + boost::lexical_cast<std::string>(i) );
+ }
+ suite->add_variable("CHECK_TASK_DURATION_LESS_THAN_SERVER_POLL","_any_");
+}
+
+
+static void create_and_start_test(Defs& theDefs, const std::string& suite_name, const std::string& create_zombies_with) {
+ if (ecf_debug_enabled) {
+ std::cout << "\n\n=============================================================================\n";
+ std::cout << "create_and_start_test " << suite_name << " using " << create_zombies_with << "\n";
+ }
+
+ /// Avoid side effects from previous test, by removing all zombies
+ TestFixture::client().zombieGet();
+ if (!TestFixture::client().server_reply().zombies().empty()) {
+ (void)ZombieUtil::do_zombie_user_action(User::REMOVE,TestFixture::client().server_reply().zombies().size(), timeout);
+ }
+
+ if (ecf_debug_enabled) std::cout << " creating server test harness\n";
+
+ // The test harness will create corresponding directory structure & default ecf file
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,
+ ServerTestHarness::testDataDefsLocation(suite_name + ".def"),
+ 1 /*timeout*/,
+ false/* don't wait for test to finish */);
+
+ // Wait for a single task to reach state submitted or active, before creating zombies
+ waitForTaskStates(SINGLE,NState::SUBMITTED,NState::ACTIVE, timeout);
+
+ // ******************************************************************************
+ // IMPORTANT: Since 4.0.5, if Job generation takes to long i.e >= next poll
+ // then it will TIMEOUT. Hence we may no get the number of zombies
+ // that we expected
+ // *******************************************************************************
+
+ if (create_zombies_with == "delete") {
+ if (ecf_debug_enabled) std::cout << " create USER zombies by deleting all the nodes in the server\n";
+ TestFixture::client().delete_all( true /* force */);
+ }
+ else if (create_zombies_with == "begin") {
+ /// Begin with force, Should create user zombies. WILL only catch those task that are submitted
+ /// It may well be that job submission, may only get a subset, others, which come for submission *later*
+ /// on will be ECF zombies.
+ /// Note: If we wait for SUMBITTED, then we get the case, where we have two task jobs
+ /// with same password, BUT different process id ??????
+ /// i.e The begin has regenerate the job file, so we get job started twice.
+ /// This should be trapped by the server, as Task should be active
+ if (ecf_debug_enabled) std::cout << " Calling begin_all_suites, now have 2 sets of jobs, The first/original set are now zombies\n";
+ TestFixture::client().set_throw_on_error(false);
+ if (TestFixture::client().begin_all_suites( true /* force */) == 1) {
+ std::cout << " Begin raised exception: because " << TestFixture::client().errorMsg() << " ***\n";
+ }
+ TestFixture::client().set_throw_on_error(true);
+ }
+ else if (create_zombies_with == "complete") {
+
+ if (ecf_debug_enabled) std::cout << " create USER zombies by calling complete\n";
+ std::string path = "/" + suite_name;
+ TestFixture::client().force(path,"complete",true/*recursive*/);
+ }
+ else if (create_zombies_with == "aborted") {
+
+ if (ecf_debug_enabled) std::cout << " create USER zombies by calling abort\n";
+ std::string path = "/" + suite_name;
+ TestFixture::client().force(path,"aborted",true/*recursive*/);
+ }
+ else {
+ BOOST_REQUIRE_MESSAGE(false,"Create zombies via " << create_zombies_with << " unrecognised");
+ }
+
+ /// Wait for all task zombies
+ vector<Task*> tasks;
+ theDefs.getAllTasks(tasks);
+
+ /// When jobs try to communicate with server via child commands they will block the Child commands
+ if (waitForZombieCreation(tasks.size(),timeout)) {
+
+ /// Check we have zombies and they are of type USER
+ std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
+ BOOST_CHECK_MESSAGE(zombies.size() > 0," NO zombies created");
+ BOOST_FOREACH(const Zombie& z, zombies) {
+ if (create_zombies_with == "begin") {
+ BOOST_CHECK_MESSAGE(z.type() == Child::USER,"Creating zombies via begin, Expected 'user' zombie type but got: " << z);
+ }
+ else if (create_zombies_with == "delete") {
+ BOOST_CHECK_MESSAGE(z.type() == Child::USER || z.type() == Child::PATH,"Creating zombies via delete, Expected 'user | path' zombie type but got: " << z);
+ }
+ else {
+ BOOST_CHECK_MESSAGE(z.type() == Child::ECF,"Expected 'ecf' zombie type but got: " << z);
+ }
+ }
+ }
+}
+
+static void create_and_start_test(const std::string& suite_name, const std::string& create_zombies_with) {
+
+ if (ecf_debug_enabled) std::cout << " Creating defs\n";
+ Defs theDefs;
+ populate_defs(theDefs,suite_name);
+ create_and_start_test(theDefs,suite_name,create_zombies_with );
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+BOOST_AUTO_TEST_CASE( enable_debug_for_ECF_TRY_NO_Greater_than_one)
+{
+ BOOST_CHECK_MESSAGE(!ecf_debug_enabled ,"dummy test");
+
+ if (getenv("ECF_DEBUG_ZOMBIES")) {
+ ecf_debug_enabled = true;
+ cout << "Test:: ... debug_enabled" << endl;
+ }
+}
+
+#ifdef DO_TEST1
+BOOST_AUTO_TEST_CASE(test_path_zombie_creation)
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_path_zombie_creation " << flush;
+ TestClean clean_at_start_and_end;
+
+ // This command creates user zombies up front, these may not have a pid, if task in submitted state
+ // User zombies will be converted to path zombies by the server
+ create_and_start_test("test_path_zombie_creation","delete"); // create zombie via delete
+
+ // expect NUM_OF_TASKS zombies, ie because we have NUM_OF_TASKS tasks
+ check_expected_no_of_zombies(NUM_OF_TASKS);
+
+ // The server will automatically change existing zombie to be of type PATH
+ // when no task nodes exists
+ // *Note* in test environment the client invoker will try connecting to the server
+ // ****** for 5 seconds, after that an error is returned. This will cause the
+ // ****** job to abort.
+ wait_for_path_zombies(NUM_OF_TASKS,timeout);
+
+ // Fob all the zombies. This will UNBLOCK the child commands allowing them to complete
+ // Fobing does *NOT* alter node tree state, however COMPLETE should auto delete the zombie
+ // Hence after this command, the number of fobed zombies may *NOT* be the same
+ // as the number of tasks. Since the fobed zombies are auto deleted when a complete
+ // child command is recieved.
+ int no_of_fobed_zombies = ZombieUtil::do_zombie_user_action(User::FOB, NUM_OF_TASKS, timeout);
+ BOOST_CHECK_MESSAGE(no_of_fobed_zombies > 0,"Expected some fobed zombies but found none ?");
+
+ // Wait for zombies to be deleted in the server
+ if (!wait_for_zombie_termination(timeout)) {
+ remove_stale_zombies();
+ }
+
+ // The fob should have forced removal of zombies, in the server. when the COMPLETE child command was recieved
+ check_expected_no_of_zombies(0);
+
+ cout << timer.duration() << "\n";
+}
+#endif
+
+#ifdef DO_TEST2
+BOOST_AUTO_TEST_CASE( test_user_zombies_for_delete_fob )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_user_zombies_for_delete_fob " << flush;
+ TestClean clean_at_start_and_end;
+
+ // This command creates user zombies up front, these may not have a pid, if task in submitted state
+ // User zombies will be converted to path zombies by the server
+ create_and_start_test("test_user_zombies_for_delete_fob","delete"); // create zombie via delete
+
+ // expect 5 zombies, ie because we have NUM_OF_TASKS tasks
+ check_expected_no_of_zombies(NUM_OF_TASKS);
+
+ // Fob all the zombies. This will UNBLOCK the child commands allowing them to finish
+ // Fobing does *NOT* alter node tree state, however COMPLETE should auto delete the zombie
+ // Hence after this command, the number of fobed zombies may *NOT* be the same
+ // as the number of tasks. Since the fobed zombies are auto deleted when a complete
+ // child command is recieved.
+ int no_of_fobed_zombies = ZombieUtil::do_zombie_user_action(User::FOB, NUM_OF_TASKS, timeout);
+ BOOST_CHECK_MESSAGE(no_of_fobed_zombies > 0,"Expected some fobed zombies but found none ?");
+
+ // Wait for zombies to be deleted in the server
+ if (!wait_for_zombie_termination(timeout)) {
+ remove_stale_zombies(); // see notes above
+ }
+
+ // The fob should have forced removal of zombies, in the server. when the COMPLETE child command was recieved
+ check_expected_no_of_zombies(0);
+
+ cout << timer.duration() << "\n";
+}
+#endif
+
+
+#ifdef DO_TEST3
+BOOST_AUTO_TEST_CASE( test_user_zombies_for_delete_fail )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_user_zombies_for_delete_fail " << flush;
+ TestClean clean_at_start_and_end;
+
+ // This command creates user zombies up front, these may not have a pid, if task in submitted state
+ // User zombies will be converted to path zombies by the server
+ create_and_start_test("test_user_zombies_for_delete_fail","delete");
+
+ check_at_least_one_zombie();
+
+ // Fail all the zombies. This will UNBLOCK and terminate the child commands allowing them to finish
+ int no_of_failed_zombies = ZombieUtil::do_zombie_user_action(User::FAIL, NUM_OF_TASKS, timeout);
+ BOOST_CHECK_MESSAGE(no_of_failed_zombies >0,"Expected > 0 Failed zombies but found none");
+
+ check_at_least_one_zombie();
+
+ // Wait for zombies to abort, then remove all the zombies
+ wait_for_zombies_child_cmd(ALL,ecf::Child::ABORT,timeout, true /* delete */);
+
+ check_expected_no_of_zombies(0);
+ cout << timer.duration() << "\n";
+}
+#endif
+
+//test_zombies_attr_for_begin/f/t1 user 26 ZzD/ycIW <pid> 1 calls(1) BLOCK INIT
+
+#ifdef DO_TEST4
+BOOST_AUTO_TEST_CASE( test_user_zombies_for_begin )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_user_zombies_for_begin " << flush;
+ TestClean clean_at_start_and_end;
+
+ // This command creates user zombies up front, these may not have a pid, if task in submitted state
+ create_and_start_test("test_user_zombies_for_begin","begin");
+
+ /// We have two *sets* of jobs, Wait for ALL the tasks(non zombies) to complete
+ BOOST_REQUIRE_MESSAGE(waitForTaskState(ALL,NState::COMPLETE,timeout),"Expected non-zombie tasks to complete");
+
+ check_at_least_one_zombie();
+
+ // Fob all the zombies. This will UNBLOCK the child commands allowing them to finish
+ // Hence after this command, the number of fobed zombies may *NOT* be the same
+ // as the number of tasks. Since the fobed zombies are auto deleted when a complete
+ // child command is received.
+ int no_of_fobed_zombies = ZombieUtil::do_zombie_user_action(User::FOB, NUM_OF_TASKS, timeout);
+ BOOST_CHECK_MESSAGE(no_of_fobed_zombies > 0,"Expected some fobed zombies but found none ?");
+
+ // Fobing does *NOT* alter node tree state, however child COMPLETE should auto delete the zombie
+ if (!wait_for_zombie_termination(timeout)) {
+ remove_stale_zombies(); // see notes above
+ }
+
+ // The fob should have forced removal of zombies, in the server. when the COMPLETE child command was recieved
+ check_expected_no_of_zombies(0);
+
+ cout << timer.duration() << "\n";
+}
+#endif
+
+
+#ifdef DO_TEST5
+BOOST_AUTO_TEST_CASE( test_zombies_attr_for_begin )
+{
+ DurationTimer timer;
+ std::string suite_name = "test_zombies_attr_for_begin";
+ cout << "Test:: ..." << suite_name << " " << flush;
+ TestClean clean_at_start_and_end;
+
+ // This command creates user zombies up front, these may not have a pid, if task in submitted state
+ create_and_start_test(suite_name,"begin"); // create zombies via begin force
+
+ /// We have two *sets* of jobs, Wait for ALL the tasks(non zombies) to complete
+ BOOST_REQUIRE_MESSAGE(waitForTaskState(ALL,NState::COMPLETE,timeout),"Expected non-zombie tasks to complete");
+
+ check_at_least_one_zombie();
+
+ /// *** Fobbing will not change state of the node tree ****
+ if (ecf_debug_enabled) std::cout << " Add a zombie attribute 'user:fob::' to the suite, which fobs all child commands\n";
+ TestFixture::client().alter("/" + suite_name,"add","zombie","user:fob::");
+
+ // Fobbing causes auto deletion of zombies, when the Child complete is reached
+ if (!wait_for_zombie_termination(timeout)) {
+ remove_stale_zombies(); // see notes above
+ }
+
+ // The fob should have forced removal of zombies, in the server. when the COMPLETE child command was recieved
+ check_expected_no_of_zombies(0);
+
+ cout << timer.duration() << "\n";
+}
+#endif
+
+
+
+#ifdef DO_TEST6
+BOOST_AUTO_TEST_CASE( test_user_zombies_for_adopt )
+{
+ DurationTimer timer;
+ std::string suite_name = "test_user_zombies_for_adopt";
+ cout << "Test:: ..." << suite_name << " " << flush;
+ TestClean clean_at_start_and_end;
+
+ // This command creates user zombies up front, these may not have a pid, if task in submitted state
+ create_and_start_test(suite_name,"begin");
+
+ /// We have two *sets* of jobs, Wait for ALL the tasks(non zombies) to complete
+ BOOST_REQUIRE_MESSAGE(waitForTaskState(ALL,NState::COMPLETE,timeout),"Expected non-zombie tasks to complete");
+
+ check_at_least_one_zombie();
+
+ /// Adopt all the zombies. This will UNBLOCK the child commands allowing them to finish
+ /// This test below fail on AIX, its too fast , task's may already be adopted and hence don't fail
+ int no_of_adopted_zombied = ZombieUtil::do_zombie_user_action(User::ADOPT, NUM_OF_TASKS, timeout);
+ if (ecf_debug_enabled) cout << " found " << no_of_adopted_zombied << " zombies for adoption\n";
+
+ /// The blocked zombies are free, start with blocked init command
+ /// This may fail on AIX, its too fast , task's may already be complete, hence don't fail
+ (void)waitForTaskState(SINGLE,NState::ACTIVE,timeout);
+
+ /// Now wait for all tasks to complete
+ BOOST_REQUIRE_MESSAGE(waitForTaskState(ALL,NState::COMPLETE,timeout),"Expected zombie tasks to complete");
+
+
+ remove_stale_zombies(); // see notes above
+
+ // After adoption the zombies should be removed
+ check_expected_no_of_zombies(0);
+
+ cout << timer.duration() << "\n";
+}
+#endif
+
+
+#ifdef DO_TEST7
+BOOST_AUTO_TEST_CASE( test_zombies_attr_for_adopt )
+{
+ DurationTimer timer;
+ std::string suite_name = "test_zombies_attr_for_adopt";
+ cout << "Test:: ..." << suite_name << " " << flush;
+ TestClean clean_at_start_and_end;
+
+ // This command creates user zombies up front, these may not have a pid, if task in submitted state
+ create_and_start_test(suite_name,"begin");
+
+ /// We have two *sets* of jobs, Wait for ALL the tasks(non zombies) to complete
+ BOOST_REQUIRE_MESSAGE(waitForTaskState(ALL,NState::COMPLETE,timeout),"Wait for all non-zombie tasks to complete failed");
+
+ // expected 5 zombies, ie because we have NUM_OF_TASKS tasks. These should all be blocking
+ check_at_least_one_zombie();
+
+ if (ecf_debug_enabled) std::cout << " Add a zombie attribute 'user:adopt::' to the suite, which *ADOPTS* all zombies allowing them to complete\n";
+ TestFixture::client().alter("/" + suite_name,"add","zombie","user:adopt::");
+
+ if (ecf_debug_enabled) dump_zombies();
+
+ /// The blocked zombies are free, start with blocked init command
+ /// This may fail on AIX, its too fast , task's may already be complete, dont fail
+ (void)waitForTaskState(SINGLE,NState::ACTIVE,timeout);
+
+ /// Now wait for all tasks to complete. ** They may be complete from last process set **
+ BOOST_REQUIRE_MESSAGE(waitForTaskState(ALL,NState::COMPLETE,timeout),"Expected all zombie task to complete after adopt");
+
+ remove_stale_zombies(); // see notes above
+
+ // After adoption the zombies should be removed
+ check_expected_no_of_zombies(0);
+
+ cout << timer.duration() << "\n";
+}
+#endif
+
+
+#ifdef DO_TEST8
+BOOST_AUTO_TEST_CASE( test_ecf_zombie_creation_via_complete )
+{
+ DurationTimer timer;
+ std::string suite_name = "test_ecf_zombie_creation_via_complete";
+ cout << "Test:: ..." << suite_name << " " << flush;
+ TestClean clean_at_start_and_end;
+
+ // This command creates user zombies up front, these may not have a pid, if task in submitted state
+ create_and_start_test(suite_name,"complete");
+
+ /// Since we have set tasks to complete, we should only have *ONE* set of zombies
+ check_at_least_one_zombie();
+
+ // Fob all the zombies child commands allowing them to finish
+ (void) ZombieUtil::do_zombie_user_action(User::FOB, NUM_OF_TASKS, timeout);
+ // int no_of_fobed_zombies = ZombieUtil::do_zombie_user_action(User::FOB, NUM_OF_TASKS, timeout);
+ // BOOST_CHECK_MESSAGE(no_of_fobed_zombies == NUM_OF_TASKS,"Expected " << NUM_OF_TASKS << " Fobed zombies but found " << no_of_fobed_zombies);
+
+ // Wait for zombies to complete, they should get removed automatically
+ wait_for_no_zombies( timeout);
+
+ cout << timer.duration() << "\n";
+}
+#endif
+
+#ifdef DO_TEST9
+BOOST_AUTO_TEST_CASE( test_ecf_zombie_creation_via_abort )
+{
+ DurationTimer timer;
+ std::string suite_name = "test_ecf_zombie_creation_via_abort";
+ cout << "Test:: ..." << suite_name << " " << flush;
+ TestClean clean_at_start_and_end;
+
+ // This command creates user zombies up front, these may not have a pid, if task in submitted state
+ create_and_start_test(suite_name,"aborted");
+
+ /// Since we have set tasks to complete, we should only have *ONE* set of zombies
+ check_at_least_one_zombie();
+
+ // Fob all the zombies child commands allowing them to finish
+ (void) ZombieUtil::do_zombie_user_action(User::FOB, NUM_OF_TASKS, timeout);
+ // int no_of_fobed_zombies = ZombieUtil::do_zombie_user_action(User::FOB, NUM_OF_TASKS, timeout);
+ // BOOST_CHECK_MESSAGE(no_of_fobed_zombies == NUM_OF_TASKS,"Expected " << NUM_OF_TASKS << " Fobed zombies but found " << no_of_fobed_zombies);
+
+ // Wait for zombies to complete, they should get removed automatically
+ wait_for_no_zombies(timeout);
+
+ cout << timer.duration() << "\n";
+}
+#endif
+
+
+#ifdef DO_TEST10
+BOOST_AUTO_TEST_CASE( test_zombie_inheritance )
+{
+ DurationTimer timer;
+ std::string suite_name = "test_zombie_inheritance";
+ cout << "Test:: ..." << suite_name << " " << flush;
+ TestClean clean_at_start_and_end;
+
+ // Add zombie attribute, make sure it inherited
+ Defs theDefs;
+ populate_defs(theDefs,suite_name);
+ suite_ptr suite = theDefs.findSuite(suite_name);
+ suite->addZombie( ZombieAttr(ecf::Child::USER, std::vector<ecf::Child::CmdType>(), ecf::User::FOB,-1) );
+ suite->addZombie( ZombieAttr(ecf::Child::ECF, std::vector<ecf::Child::CmdType>(), ecf::User::FOB,-1) );
+ suite->addZombie( ZombieAttr(ecf::Child::PATH, std::vector<ecf::Child::CmdType>(), ecf::User::FOB,-1) );
+
+ create_and_start_test(theDefs,suite_name,"complete" );
+
+ /// Since we have set tasks to complete, we should only have *ONE* set of zombies
+ // expect NUM_OF_TASKS zombies, ie because we have NUM_OF_TASKS tasks
+ TestFixture::client().set_throw_on_error(true);
+ TestFixture::client().zombieGet();
+ std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
+ BOOST_CHECK_MESSAGE(!zombies.empty(),"No zombies found");
+ BOOST_FOREACH(const Zombie& z, zombies) {
+ BOOST_CHECK_MESSAGE(z.user_action() == ecf::User::FOB, "Expected zombies with user action of type FOB but found " << User::to_string(z.user_action()));
+ break;
+ }
+
+ // Wait for zombies to complete, they should get removed automatically
+ wait_for_no_zombies(timeout);
+
+ cout << timer.duration() << "\n";
+}
+#endif
+
+
+#ifdef DO_TEST11
+static int wait_for_killed_zombies(int no_of_tasks, int max_time_to_wait)
+{
+ if (ecf_debug_enabled) std::cout << "\n wait_for_killed_zombies\n";
+ AssertTimer assertTimer(max_time_to_wait,false); // Bomb out after n seconds, fall back if test fail
+ while (1) {
+ int killed = 0;
+ TestFixture::client().zombieGet();
+ std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
+ BOOST_FOREACH(const Zombie& z, zombies) {
+ if (z.kill()) killed++;
+ }
+ if (ecf_debug_enabled) std::cout << " found " << killed << " killed zombies\n";
+
+ if (killed == no_of_tasks) return killed;
+
+ if ( assertTimer.duration() >= assertTimer.timeConstraint() ) {
+ cout << "wait_for_killed_zombies Test wait " << assertTimer.duration() <<
+ " taking longer than time constraint of " << assertTimer.timeConstraint() <<
+ " breaking out\n" << Zombie::pretty_print( zombies , 3) << "\n";
+ return killed;
+ }
+ sleep(2);
+ }
+ return 0;
+}
+
+BOOST_AUTO_TEST_CASE( test_zombie_kill )
+{
+ DurationTimer timer;
+ std::string suite_name = "test_zombie_kill";
+ cout << "Test:: ..." << suite_name << " " << flush;
+ TestClean clean_at_start_and_end;
+
+ // This command creates user zombies up front, these may not have a pid, if task in submitted state
+ create_and_start_test(suite_name,"complete");
+
+ check_at_least_one_zombie();
+
+ // kill all the zombies, i.e kill -15 on the script
+ // This will be trapped by the signal and hence will call abort
+ (void) ZombieUtil::do_zombie_user_action(User::KILL, NUM_OF_TASKS, timeout);
+
+ // wait for kill zombies. This should eventually lead to process terminating
+ int killed = wait_for_killed_zombies(NUM_OF_TASKS,timeout);
+ BOOST_CHECK_MESSAGE(killed > 0,"Expected " << NUM_OF_TASKS << " killed ");
+
+ {
+ // wait for process to be killed: killing is a separate process, we could well
+ // have got to the complete, before the process is killed.
+ // Once the complete is fobed it terminate the process.
+ AssertTimer assertTimer(timeout,false); // Bomb out after n seconds, fall back if test fail
+ while (1) {
+ int completed = 0; int aborted = 0;
+ TestFixture::client().zombieGet();
+ std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
+ BOOST_FOREACH(const Zombie& z, zombies) {
+ if (z.last_child_cmd() == ecf::Child::ABORT) aborted++;
+ if (z.last_child_cmd() == ecf::Child::COMPLETE) completed++;
+ }
+ if (aborted + completed == NUM_OF_TASKS) break;
+ if ( assertTimer.duration() >= assertTimer.timeConstraint() ) {
+ cout << "wait for for abort: found " << aborted+completed<< " aborted & completed tasks. Test wait "
+ << assertTimer.duration() <<
+ " taking longer than time constraint of " << assertTimer.timeConstraint() <<
+ " breaking out\n" << Zombie::pretty_print( zombies , 3) << "\n";
+ break;
+ }
+ sleep(1);
+ }
+ }
+ {
+ bool task_became_blocked = false;
+ // wait for process to be die
+ AssertTimer assertTimer(timeout,false); // Bomb out after n seconds, fall back if test fail
+ while (1) {
+ TestFixture::client().zombieGet();
+ std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
+ BOOST_FOREACH(const Zombie& z, zombies) {
+ if (z.block()) { // something went wrong, fob so don't leave process hanging
+ TestFixture::client().zombieFob(z);
+ task_became_blocked = true;
+ cout << "Zombies blocking ?? " << z << "\n";
+ }
+ }
+ if ( assertTimer.duration() >= assertTimer.timeConstraint() ) {
+ if ( task_became_blocked ) {
+ cout << "Task became blocked, fobing" << assertTimer.duration() <<
+ " taking longer than time constraint of " << assertTimer.timeConstraint() <<
+ " breaking out\n" << Zombie::pretty_print( zombies , 3) << "\n";
+ }
+ break;
+ }
+ sleep(1);
+ }
+ }
+
+ // remove the killed zombies
+ (void) ZombieUtil::do_zombie_user_action(User::REMOVE,NUM_OF_TASKS, timeout,false);
+
+ wait_for_no_zombies(timeout);
+
+ cout << timer.duration() << "\n";
+}
+#endif
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Test/Test_ECF_SCRIPT_CMD.cpp b/Test/Test_ECF_SCRIPT_CMD.cpp
new file mode 100644
index 0000000..43f5fdb
--- /dev/null
+++ b/Test/Test_ECF_SCRIPT_CMD.cpp
@@ -0,0 +1,86 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #25 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include "ServerTestHarness.hpp"
+#include "TestFixture.hpp"
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "File.hpp"
+#include "DurationTimer.hpp"
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/test/unit_test.hpp>
+
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( TestSuite )
+
+BOOST_AUTO_TEST_CASE( test_ECF_SCRIPT_CMD )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_ECF_SCRIPT_CMD " << flush;
+ TestClean clean_at_start_and_end;
+
+ // Create the defs file corresponding to the text below
+ // ECF_HOME variable is automatically added by the test harness.
+ // ECF_INCLUDE variable is automatically added by the test harness.
+ // SLEEPTIME variable is automatically added by the test harness.
+ // ECF_CLIENT_EXE_PATH variable is automatically added by the test harness.
+ // This is substituted in sms includes
+ // Allows test to run without requiring installation
+
+ //# Note: we have to use relative paths, since these tests are relocatable
+ // suite test_ECF_SCRIPT_CMD
+ // family family
+ // task check
+ // edit ECF_SCRIPT_CMD "cat $ECF_HOME/test_ECF_SCRIPT_CMD/family/check.ecf"
+ // task t1
+ // trigger check == complete
+ // edit ECF_SCRIPT_CMD "cat $ECF_HOME/test_ECF_SCRIPT_CMD/family/t1.ecf"
+ // endfamily
+ // endsuite
+ Defs theDefs;
+ {
+ suite_ptr suite = theDefs.add_suite("test_ECF_SCRIPT_CMD");
+ family_ptr fam = suite->add_family("family");
+ fam->addVerify( VerifyAttr(NState::COMPLETE,1) );
+
+ task_ptr task_check = fam->add_task("check");
+ task_check->addVerify( VerifyAttr(NState::COMPLETE,1) );
+ task_check->add_variable("ECF_SCRIPT_CMD","cat " + TestFixture::smshome() + task_check->absNodePath() + File::ECF_EXTN());
+
+ task_ptr task_t1 = fam->add_task("t1");
+ task_t1->add_trigger( "check == complete");
+ task_t1->addVerify( VerifyAttr(NState::COMPLETE,1) );
+ task_t1->add_variable("ECF_SCRIPT_CMD","cat " + TestFixture::smshome() + task_t1->absNodePath() + File::ECF_EXTN());
+ }
+
+ // The test harness will create corresponding directory structure & default ecf file
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs, ServerTestHarness::testDataDefsLocation("test_ECF_SCRIPT_CMD.def") );
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Test/Test_Time.cpp b/Test/Test_Time.cpp
new file mode 100644
index 0000000..f474443
--- /dev/null
+++ b/Test/Test_Time.cpp
@@ -0,0 +1,387 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #35 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/test/unit_test.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include "ServerTestHarness.hpp"
+#include "TestFixture.hpp"
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "DurationTimer.hpp"
+#include "PrintStyle.hpp"
+
+using namespace std;
+using namespace ecf;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+
+BOOST_AUTO_TEST_SUITE( TestSuite )
+
+BOOST_AUTO_TEST_CASE( test_single_real_time )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_single_real_time " << flush;
+ TestClean clean_at_start_and_end;
+
+ // Create the defs file corresponding to the text below
+ // ECF_HOME variable is automatically added by the test harness.
+ // ECF_INCLUDE variable is automatically added by the test harness.
+ // SLEEPTIME variable is automatically added by the test harness.
+ // ECF_CLIENT_EXE_PATH variable is automatically added by the test harness.
+ // This is substituted in sms includes
+ // Allows test to run without requiring installation
+
+ //# Note: we have to use relative paths, since these tests are relocatable
+ //suite suite
+ // edit SLEEPTIME 1
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // clock real <todays date>
+ // family family
+ // task t1
+ // time 10:00
+ // endfamily
+ //endsuite
+ Defs theDefs;
+ {
+ // Initialise clock with fixed date and time, then create a time attribute
+ // with todays time + minute
+ // Avoid adding directly to TimeSlot
+ // i.e if local time is 9:59 and we create a TimeSlot like
+ // task->addTime( ecf::TimeAttr( ecf::TimeSlot(theTm.tm_hour,theTm.tm_min+3) ) );
+ // The the minute will be 62, which is illegal and will not parse
+ boost::posix_time::ptime theLocalTime = boost::posix_time::ptime(date(2010,6,21),time_duration(10,0,0));
+ boost::posix_time::ptime time1 = theLocalTime + minutes(1);
+
+ // For each 2 seconds of poll in the server update calendar by 1 minute
+ // Note: if we use 1 seconds poll to update calendar by 1 minute, then
+ // we will find that state change happens at job submission interval,
+ // and hence skews time series. Which can leave state in a queued state,
+ // and hence test never completes
+ suite_ptr suite = theDefs.add_suite("test_single_real_time");
+ ClockAttr clockAttr(theLocalTime,false);
+ suite->addClock( clockAttr );
+
+ family_ptr fam = suite->add_family("family");
+ task_ptr task = fam->add_task("t");
+ task->addTime( ecf::TimeAttr(ecf::TimeSlot(time1.time_of_day())));
+ task->addVerify( VerifyAttr(NState::COMPLETE,1) ); // task should complete 1 times
+ }
+
+ // The test harness will create corresponding directory structure
+ // and populate with standard ecf files.
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_single_real_time.def"));
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_CASE( test_time_multiple_single_slot )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_time_multiple_single_slot "<< flush;
+ TestClean clean_at_start_and_end;
+
+ // SLOW SYSTEMS
+ // for each time attribute leave GAP of 3 * job submission interval
+ // on slow systems submitted->active->complete > TestFixture::job_submission_interval()
+ // Also the task duration must be greater than job_submission_interval, otherwise
+ // we will get multiple invocation for the same time step.
+ // *sometimes* just submitted->active can take many times job submission interval.
+
+ //# Note: we have to use relative paths, since these tests are relocatable
+ //suite test_time_multiple_single_slot
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // clock real <todays date>
+ // family family
+ // task t1
+ // time 10:01
+ // time 10:04
+ // time 10:07
+ // endfamily
+ //endsuite
+ Defs theDefs;
+ {
+ // Initialise clock with todays date and time, then create a time attribute
+ // with todays time + minute.
+ boost::posix_time::ptime theLocalTime = boost::posix_time::ptime(date(2010,6,21),time_duration(10,0,0));
+ boost::posix_time::ptime time1 = theLocalTime + minutes(1);
+ boost::posix_time::ptime time2 = time1 + minutes(TestFixture::job_submission_interval());
+ boost::posix_time::ptime time3 = time2 + minutes(TestFixture::job_submission_interval());
+
+ suite_ptr suite = theDefs.add_suite("test_time_multiple_single_slot");
+ ClockAttr clockAttr(theLocalTime,false);
+ suite->addClock( clockAttr );
+ suite->add_variable("SLEEPTIME","1");
+
+ family_ptr fam = suite->add_family("family");
+ task_ptr task = fam->add_task("t");
+ task->addTime( ecf::TimeAttr( ecf::TimeSlot(time1.time_of_day()) ) );
+ task->addTime( ecf::TimeAttr( ecf::TimeSlot(time2.time_of_day()) ) );
+ task->addTime( ecf::TimeAttr( ecf::TimeSlot(time3.time_of_day()) ) );
+ task->addVerify( VerifyAttr(NState::COMPLETE,3) ); // task should complete 3 times
+ }
+
+ // The test harness will create corresponding directory structure
+ // and populate with standard ecf files.
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_time_multiple_single_slot.def"));
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+
+BOOST_AUTO_TEST_CASE( test_time_relative_time_series )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_time_relative_time_series " << flush;
+ TestClean clean_at_start_and_end;
+
+ // SLOW SYSTEMS
+ // for each time attribute leave GAP of 3 * job submission interval
+ // on slow systems submitted->active->complete > TestFixture::job_submission_interval()
+ // Also the task duration must be greater than job_submission_interval, otherwise
+ // we will get multiple invocation for the same time step
+
+ //# Note: we have to use relative paths, since these tests are relocatable
+ //suite test_time_relative_time_series
+ // edit SLEEPTIME 1
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // clock real <todays date>
+ // family family
+ // task t1
+ // time +<start> <finish> incr
+ // endfamily
+ //endsuite
+ Defs theDefs;
+ {
+ // Initialise clock with todays date and time, then create a time attribute
+ // with a time series, so that task runs 3 times relative to suite start
+ suite_ptr suite = theDefs.add_suite("test_time_relative_time_series");
+ ClockAttr clockAttr(Calendar::second_clock_time(),false);
+ suite->addClock( clockAttr );
+ suite->add_variable("SLEEPTIME",boost::lexical_cast<std::string>(TestFixture::job_submission_interval()-1));
+
+ family_ptr fam = suite->add_family("family");
+ task_ptr task = fam->add_task("t");
+ task->addTime( ecf::TimeAttr(
+ ecf::TimeSlot(0,1),
+ ecf::TimeSlot(0,7),
+ ecf::TimeSlot(0,3),
+ true /*relative to suite start*/
+ )
+ );
+ task->addVerify( VerifyAttr(NState::COMPLETE,3) ); // task should complete 3 times
+ }
+
+ // The test harness will create corresponding directory structure
+ // and populate with standard ecf files.
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs, ServerTestHarness::testDataDefsLocation("test_time_relative_time_series.def"));
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_CASE( test_time_real_series )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_time_real_series " << flush;
+ TestClean clean_at_start_and_end;
+
+ // SLOW SYSTEMS
+ // for each time attribute leave GAP of 3 * job submission interval
+ // on slow systems submitted->active->complete > TestFixture::job_submission_interval()
+ // Also the task duration must be greater than job_submission_interval, otherwise
+ // we will get multiple invocation for the same time step
+
+ //# Note: we have to use relative paths, since these tests are relocatable
+ //suite test_time_real_series
+ // edit SLEEPTIME 1
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // clock real <date>
+ // family family
+ // task t1
+ // time <start> <finish> <incr>
+ // endfamily
+ //endsuite
+ Defs theDefs;
+ {
+ // Initialise clock with todays date and time, then create a time attribute
+ // with a time series, so that task runs 3 times
+ boost::posix_time::ptime theLocalTime = boost::posix_time::ptime(date(2010,6,21),time_duration(10,0,0));
+ boost::posix_time::ptime time1 = theLocalTime + minutes(1);
+ boost::posix_time::ptime time2 = time1 + minutes(TestFixture::job_submission_interval()*2);
+
+ suite_ptr suite = theDefs.add_suite("test_time_real_series");
+ suite->add_variable("SLEEPTIME","1");
+
+ ClockAttr clockAttr(theLocalTime,false);
+ suite->addClock( clockAttr );
+
+ family_ptr fam = suite->add_family("family");
+ task_ptr task = fam->add_task("t");
+ task->addTime( ecf::TimeAttr(
+ ecf::TimeSlot(time1.time_of_day()),
+ ecf::TimeSlot(time2.time_of_day()),
+ ecf::TimeSlot(0,TestFixture::job_submission_interval())
+ ));
+ task->addVerify( VerifyAttr(NState::COMPLETE,3) ); // task should complete 3 times
+ // 1 + 7 + 13
+ // 1 + (2*n) + (2*n) = 1 + 4n
+ // start = 1, finish = 13, when n=3, when n = job submission interval
+ // to complete 3 times, we must use interval of n*2
+ }
+
+ // The test harness will create corresponding directory structure
+ // and populate with standard sms files.
+ ServerTestHarness serverTestHarness;
+ //serverTestHarness.add_default_sleep_time(false); // avoid missing time steps due to submit->active->complete > job submission interval
+ serverTestHarness.run(theDefs, ServerTestHarness::testDataDefsLocation("test_time_real_series.def"));
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_CASE( test_single_real_time_near_midnight )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_single_real_time_near_midnight " << flush;
+ int the_server_version = TestFixture::server_version() ;
+ if (the_server_version == 403 ) {
+ cout << " SKIPPING, This test does not work with 403, current server version is " << the_server_version << "\n";
+ return;
+ }
+
+ TestClean clean_at_start_and_end;
+
+ //# Note: we have to use relative paths, since these tests are relocatable
+ //suite suite
+ // edit SLEEPTIME 4
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // clock real <todays date>
+ // family family
+ // task t1
+ // time 23:59
+ // endfamily
+ //endsuite
+ Defs theDefs;
+ {
+ // ECFLOW-130
+ // Make sure job completes after midnight.
+ // The task SHOULD stay complete and *NOT* requeue
+ // Since TestHarness requires suite completion, we dont need to do anything.
+ boost::posix_time::ptime time_start = boost::posix_time::ptime(date(2010,6,21),time_duration(23,59,0));
+ boost::posix_time::ptime clock_start = time_start - minutes(1);
+
+ suite_ptr suite = theDefs.add_suite("test_single_real_time_near_midnight");
+ ClockAttr clockAttr(clock_start,false);
+ suite->addClock( clockAttr );
+ suite->add_variable("SLEEPTIME",boost::lexical_cast<string>(TestFixture::job_submission_interval()*2));
+
+ family_ptr fam = suite->add_family("family");
+ task_ptr task = fam->add_task("t");
+ task->addTime( ecf::TimeAttr(ecf::TimeSlot(time_start.time_of_day())));
+ task->addVerify( VerifyAttr(NState::COMPLETE,1) ); // task should complete 1 times
+ }
+
+ // The test harness will create corresponding directory structure and populate with standard ecf files.
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_single_real_time_near_midnight.def"));
+
+#ifdef DEBUG_ME
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0, "Could not get the defs from server\n" << TestFixture::client().errorMsg());
+ defs_ptr defs = TestFixture::client().defs();
+ PrintStyle::setStyle(PrintStyle::STATE);
+ std::cout << *defs;
+#endif
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+
+BOOST_AUTO_TEST_CASE( test_time_real_series_near_midnight )
+{
+ DurationTimer timer;
+ cout << "Test:: ...test_time_real_series_near_midnight " << flush;
+ int the_server_version = TestFixture::server_version() ;
+ if (the_server_version == 403 ) {
+ cout << " SKIPPING, This test does not work with 403, current server version is " << the_server_version << "\n";
+ return;
+ }
+
+ TestClean clean_at_start_and_end;
+
+ // SLOW SYSTEMS
+ // for each time attribute leave GAP of 3 * job submission interval
+ // on slow systems submitted->active->complete > TestFixture::job_submission_interval()
+ // Also the task duration must be greater than job_submission_interval, otherwise
+ // we will get multiple invocation for the same time step
+
+ //# Note: we have to use relative paths, since these tests are relocatable
+ //suite test_time_real_series
+ // edit SLEEPTIME 1
+ // edit ECF_INCLUDE $ECF_HOME/includes
+ // clock real <date>
+ // family family
+ // task t1
+ // time <start> <finish> <incr>
+ // endfamily
+ //endsuite
+ Defs theDefs;
+ {
+ // ECFLOW-130
+ // make sure that last job, *runs* and completes after midnight.
+ // It should stay complete and not requeue.
+ // Test harness, will check suite task->family->suite completes, hence no need to do anything
+ boost::posix_time::ptime last_time = boost::posix_time::ptime(date(2010,6,21),time_duration(23,59,0));
+ boost::posix_time::ptime first_time = last_time - minutes(TestFixture::job_submission_interval()*2);
+ boost::posix_time::ptime clock_start = first_time - minutes(1);
+
+ suite_ptr suite = theDefs.add_suite("test_time_real_series_near_midnight");
+ suite->add_variable("SLEEPTIME",boost::lexical_cast<string>(TestFixture::job_submission_interval()*2));
+
+ ClockAttr clockAttr(clock_start,false);
+ suite->addClock( clockAttr );
+
+ family_ptr fam = suite->add_family("family");
+ task_ptr task = fam->add_task("t");
+ task->addTime( ecf::TimeAttr(
+ ecf::TimeSlot(first_time.time_of_day()),
+ ecf::TimeSlot(last_time.time_of_day()),
+ ecf::TimeSlot(0,TestFixture::job_submission_interval()*2)
+ ));
+ task->addVerify( VerifyAttr(NState::COMPLETE,2) ); // task should complete 2 times
+ }
+
+ // The test harness will create corresponding directory structure and populate with standard ecf files.
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs, ServerTestHarness::testDataDefsLocation("test_time_real_series_near_midnight.def"));
+
+#ifdef DEBUG_ME
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0, "Could not get the defs from server\n" << TestFixture::client().errorMsg());
+ defs_ptr defs = TestFixture::client().defs();
+ PrintStyle::setStyle(PrintStyle::STATE);
+ std::cout << *defs;
+#endif
+
+ cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
+}
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Test/data/.gitignore b/Test/data/.gitignore
new file mode 100644
index 0000000..bc8249c
--- /dev/null
+++ b/Test/data/.gitignore
@@ -0,0 +1,6 @@
+/ECF_HOME_debug
+/ECF_HOME_release
+/ECF_HOME_release_clang/
+/ECF_HOME_release_gnu/
+/ECF_HOME_release_intel/
+/ECF_HOME_debug_gnu/
diff --git a/ecflow_4_0_7/Test/data/includes/head.h b/Test/data/includes/head.h
similarity index 100%
rename from ecflow_4_0_7/Test/data/includes/head.h
rename to Test/data/includes/head.h
diff --git a/ecflow_4_0_7/Test/data/includes/tail.h b/Test/data/includes/tail.h
similarity index 100%
rename from ecflow_4_0_7/Test/data/includes/tail.h
rename to Test/data/includes/tail.h
diff --git a/ecflow_4_0_7/Test/samples/cron.def b/Test/samples/cron.def
similarity index 100%
rename from ecflow_4_0_7/Test/samples/cron.def
rename to Test/samples/cron.def
diff --git a/ecflow_4_0_7/Test/samples/time.def b/Test/samples/time.def
similarity index 100%
rename from ecflow_4_0_7/Test/samples/time.def
rename to Test/samples/time.def
diff --git a/ecflow_4_0_7/Test/samples/today.def b/Test/samples/today.def
similarity index 100%
rename from ecflow_4_0_7/Test/samples/today.def
rename to Test/samples/today.def
diff --git a/Test/src/ServerTestHarness.cpp b/Test/src/ServerTestHarness.cpp
new file mode 100644
index 0000000..c7525b1
--- /dev/null
+++ b/Test/src/ServerTestHarness.cpp
@@ -0,0 +1,558 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #127 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <iostream>
+#include <fstream>
+#include <stdlib.h> // for getenv()
+
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/test/unit_test.hpp>
+
+#include "ServerTestHarness.hpp"
+#include "TestFixture.hpp"
+#include "DurationTimer.hpp"
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "File.hpp"
+#include "AssertTimer.hpp"
+#include "TestHelper.hpp"
+#include "PrintStyle.hpp"
+#include "WhyCmd.hpp"
+#include "Ecf.hpp"
+#include "Str.hpp"
+
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+//#define DEBUG_TEST_WAITER 1
+//#define DEBUG_TEST_WAITER_DEFS 1
+//#define DEBUG_TEST_HARNESS 1
+//#define DEBUG_DIFF 1
+
+ServerTestHarness::ServerTestHarness()
+: generateManFileForNodeContainers_(false),
+ check_task_duration_less_than_server_poll_(true),
+ add_default_sleep_time_(true),
+ serverUpdateCalendarCount_(0)
+{}
+
+void ServerTestHarness::run(
+ Defs& theClientDefs,
+ const std::string& defs_filename,
+ const std::map<std::string,
+ std::string>& customTaskSmsMap,
+ int timeout,
+ bool waitForTestCompletion)
+{
+ defs_filename_ = defs_filename;
+
+ /// RUN the TEST
+ defs_ptr serverDefs = doRun(theClientDefs,customTaskSmsMap,timeout,waitForTestCompletion);
+}
+
+void ServerTestHarness::run(Defs& defs,const std::string& defs_filename, int timeout, bool waitForTestCompletion)
+{
+ std::map<std::string,std::string> customTaskSmsMap;
+ run(defs,defs_filename,customTaskSmsMap,timeout,waitForTestCompletion);
+}
+
+struct null_deleter { void operator()(void const *) const{} };
+
+defs_ptr
+ServerTestHarness::doRun(Defs& theClientDefs, const std::map<std::string,std::string>& customTaskSmsMap,int timeout,bool waitForTestCompletion)
+{
+#ifdef DEBUG_TEST_HARNESS
+ cout << "ServerTestHarness::doRun " << defs_filename_ << " timeout=" << timeout << " waitForTestCompletion = " << waitForTestCompletion << "\n";
+#endif
+ BOOST_REQUIRE_MESSAGE(!theClientDefs.suiteVec().empty(), "No suite defined");
+
+
+#ifdef DEBUG_TEST_HARNESS
+ cout << " ServerTestHarness::doRun: Get the client exe. This can be client exe on another platform hence cant run here\n";
+#endif
+ std::string theClientExePath = TestFixture::theClientExePath();
+ BOOST_REQUIRE_MESSAGE(!theClientExePath.empty()," The client program could not be found");
+
+
+#ifdef DEBUG_TEST_HARNESS
+ cout << " ServerTestHarness::doRun: Create ECF directory structure corresponding to Node tree\n";
+#endif
+ // Automatically add variable ECF_HOME to each suite, before saving to disk
+ // This is needed to locate ECF_FILE includes
+ std::string ecf_home = testDataLocation( defs_filename_ );
+
+ // Most test just define one suite, however the mega.def has up to 26 suites
+ // If set this can be used to choose which suite to begin.
+ std::string suiteName;
+
+ // Create the client early, since we need to determine if environment variable
+ // ECF_ALLOW_NEW_CLIENT_OLD_SERVER was set, if it was, we need to update the generated .ecf scripts
+ // to embed this variable, this will allow *new child commands* to talk to old servers
+ int allow_new_client_old_server = 0;
+ if (TestFixture::client().allow_new_client_old_server() != 0) {
+ // need export ECF_ALLOW_NEW_CLIENT_OLD_SERVER
+ allow_new_client_old_server = TestFixture::client().allow_new_client_old_server();
+ }
+
+
+ // ECF_CLIENT_EXE_PATH allows dependence on client exe without installation
+ // Allow user to add SLEEPTIME, otherwise add a default
+ int customSmsCnt = 0;
+ int taskSmsMapSize = static_cast<int>(customTaskSmsMap.size());
+ BOOST_FOREACH(suite_ptr s, theClientDefs.suiteVec()) {
+ if (allow_new_client_old_server != 0) {
+ std::string value = "export ECF_ALLOW_NEW_CLIENT_OLD_SERVER=" + boost::lexical_cast<std::string>(allow_new_client_old_server);
+ s->addVariable( Variable( "ECF_ALLOW_NEW_CLIENT_OLD_SERVER", value ) );
+ }
+
+ // Always override these to correctly locate files.
+ s->addVariable( Variable( Str::ECF_HOME(), ecf_home ) );
+ s->addVariable( Variable( "ECF_CLIENT_EXE_PATH", theClientExePath ) );
+ s->addVariable( Variable( Str::ECF_INCLUDE(), TestFixture::includes() ) );
+
+ if (s->findVariable("SLEEPTIME").empty()) s->addVariable( Variable( "SLEEPTIME", "1" ) );
+
+ if (check_task_duration_less_than_server_poll_) {
+ if (s->findVariable("CHECK_TASK_DURATION_LESS_THAN_SERVER_POLL").empty()) s->addVariable( Variable( "CHECK_TASK_DURATION_LESS_THAN_SERVER_POLL", "_any_" ) );
+ }
+ suiteName = s->name();
+
+ // recursively create directory structure from ECF_HOME and populate tasks with sms files
+ createDirAndEcfFiles(s.get(),ecf_home,customTaskSmsMap,customSmsCnt);
+ }
+ BOOST_REQUIRE_MESSAGE( customSmsCnt == taskSmsMapSize,"customSmsCnt:" << customSmsCnt << " does not match " << taskSmsMapSize << " createDirAndEcfFiles did not create all sms file corresponding to tasks");
+
+
+ // If the defs has more than one suite, then start them all.
+ if ( theClientDefs.suiteVec().size() != 1) {
+ suiteName.clear();
+#ifdef DEBUG_TEST_HARNESS
+ cout << " ServerTestHarness::doRun: defs has " << theClientDefs.suiteVec().size() << " suites hence will begin all of them\n";
+#endif
+ }
+
+
+ bool load_defs_from_disk = true;
+ {
+#ifdef DEBUG_TEST_HARNESS
+ cout << " ServerTestHarness::doRun: Save the Defs file to disk. " << defs_filename_ << "\n";
+#endif
+ std::ofstream theClientDefsFile( defs_filename_.c_str() );
+ if ( theClientDefsFile.fail()) {
+ // The file is *not on disk*, just use in memory defs
+ load_defs_from_disk = false;
+ }
+ else {
+ PrintStyle::setStyle(PrintStyle::DEFS); // needed for output
+ theClientDefsFile << theClientDefs;
+ PrintStyle::setStyle(PrintStyle::STATE); // From now on show state
+ }
+ }
+
+ // Set the location of the new log file. Close the current log file and create new log file
+ // The defs file name should have been set to the test location
+ // The log file is CLEARED so that previous run is ignored
+ std::string new_log_file_path = defs_filename_ + "_log";
+#ifdef DEBUG_TEST_HARNESS
+ cout << " ServerTestHarness::new_log_file_path = " << new_log_file_path << "\n";
+#endif
+ TestFixture::client().new_log( new_log_file_path );
+ TestFixture::client().clearLog();
+
+
+#ifdef DEBUG_TEST_HARNESS
+ cout << " ServerTestHarness::doRun: Delete all nodes in server. Using force to allow as many tests as possible\n";
+#endif
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().delete_all(true/*force, even if it creates zombies*/) == 0,CtsApi::to_string(CtsApi::delete_node()) << " failed should return 0. Should Delete ALL existing defs in the server\n" << TestFixture::client().errorMsg());
+
+
+#ifdef DEBUG_TEST_HARNESS
+ cout << " ServerTestHarness::doRun: Load new defs in the server\n";
+#endif
+ if ( load_defs_from_disk ) {
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().loadDefs( defs_filename_ ) == 0,"load defs failed should return 0. Should Load defs file " << defs_filename_ << " into the server from current working directory\n" << TestFixture::client().errorMsg());
+ }
+ else {
+ // load expects a defs_ptr
+ defs_ptr defs(&theClientDefs,null_deleter());
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().load( defs ) == 0,"load defs failed should return 0. Should Load defs file " << defs_filename_ << " into the server\n" << TestFixture::client().errorMsg());
+ }
+
+#ifdef DEBUG_TEST_HARNESS
+ cout << " ServerTestHarness::doRun: Restart server \n";
+#endif
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().restartServer() == 0,CtsApi::restartServer() << " failed should return 0. Should restart the server via a client command\n" << TestFixture::client().errorMsg());
+
+
+#ifdef DEBUG_TEST_HARNESS
+ cout << " ServerTestHarness::doRun: Calling begin on suite " << suiteName << "\n";
+#endif
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().begin( suiteName ) == 0,CtsApi::begin( suiteName ) << " failed should return 0. Should Begin the suite " << suiteName << "\n" << TestFixture::client().errorMsg());
+
+
+ if (waitForTestCompletion) {
+#ifdef DEBUG_TEST_HARNESS
+ cout << " ServerTestHarness::doRun: Waiting for test to finish\n";
+#endif
+ return testWaiter(theClientDefs,timeout,true /* test against verification attributes on defs */);
+ }
+ return defs_ptr();
+}
+
+
+static void test_invariants(defs_ptr the_defs, const std::string& title) {
+ std::string errorMsg;
+ BOOST_CHECK_MESSAGE( the_defs->checkInvariants(errorMsg),title << " Invariants failed " << errorMsg);
+}
+
+bool verify_attribute_verification()
+{
+ // In version 4.0.1: We changed the way families changed states. i.e families will now change to state complete
+ // before being requeued. See ECFLOW-96 Families with loops(cron/repeat) should log complete
+ // This meant that when we run the migration tests, i.e new client with old server (with new test)
+ // It would fail some the test, during verify attribute verification. ie. where we count the number of times
+ // a node completes. To enable these tests to still run, we will disable verify attribute verification
+ static bool allow_verification = true;
+
+ if (!allow_verification) {
+ //std::cout << "Disable verify attribute verification ------------------------------------------\n";
+ return false;
+ }
+ char* the_env = getenv("DISABLE_VERIFY_ATTRIBUTE_VERIFICATION");
+ if (the_env) {
+ std::cout << "Disable verify attribute verification *************************************************************\n";
+ allow_verification= false;
+ return false;
+ }
+ return true;
+}
+
+defs_ptr
+ServerTestHarness::testWaiter( const Defs& theClientDefs, int timeout, bool verifyAttr)
+{
+#ifdef DEBUG_TEST_WAITER
+ cout << "ServerTestHarness::testWaiter \n";
+#endif
+
+#ifdef DEBUG_DIFF
+ std::string dump_defs_filename = "test.def";
+ int counter = 0;
+#endif
+
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().client_handle() == 0,"Client handle expected to be zero but found " << TestFixture::client().client_handle());
+
+ /// This function will test sync'ing. by getting the sync and full defs, then comparing them
+ AssertTimer assertTimer(timeout,false); // Bomb out after n seconds, fall back if test fail
+
+ // test the incremental changes
+ defs_ptr incremental_defs;
+ defs_ptr full_defs;
+
+ int sleepTime = (theClientDefs.suiteVec().size() == 1) ? TestFixture::job_submission_interval() : 10;
+ int sleep_fudgeFactor = TestFixture::job_submission_interval();
+
+ // How do we terminate this test?
+ // The test succeeds if the suite state is complete,
+ while( 1 ) {
+#ifdef DEBUG_TEST_WAITER
+ std::cout << "sleepTime = " << sleepTime << "\n";
+#endif
+ sleep(sleepTime); // avoid calling get excessively, by using sleep
+ DurationTimer timer; // automatically adjust sleep time
+
+ bool server_changed = false;
+ if (!full_defs.get()) {
+ server_changed = true;
+ // ********************************************************************************
+ // Calling getDefs will also force a flush of the log file. This is required since we
+ // copy the log file locally on the shared file system for cross platform testing
+ // ******************************************************************************
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().getDefs() == 0,CtsApi::get() << " failed should return 0 " << TestFixture::client().errorMsg());
+ full_defs = TestFixture::client().defs();
+ incremental_defs = TestFixture::client().defs();
+ BOOST_REQUIRE_MESSAGE( full_defs.get(),"get command failed to get node tree from server");
+ BOOST_REQUIRE_MESSAGE( incremental_defs.get(),"get command failed to get node tree from server");
+
+ // Ensure that when suite was loaded in server, that others suites were discarded
+ BOOST_CHECK_MESSAGE(theClientDefs.suiteVec().size() == full_defs->suiteVec().size(),"mismatch in client suite count " << theClientDefs.suiteVec().size() << " and server " << full_defs->suiteVec().size());
+ test_invariants(full_defs,"First time for getting full defs");
+ }
+ else {
+ BOOST_CHECK_MESSAGE(TestFixture::client().news(full_defs) == 0, "news failed should return 0 " << TestFixture::client().errorMsg());
+ server_changed = TestFixture::client().get_news();
+ // std::cout << "server_changed = " << server_changed << "\n";
+ if ( server_changed ) {
+
+ // Get the incremental changes **FIRST** and compare this with the full defs later on
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().sync(incremental_defs) == 0, "sync failed should return 0 " << TestFixture::client().errorMsg());
+ BOOST_CHECK_MESSAGE(TestFixture::client().in_sync(), "in_sync expected to return true, when we have changes in server");
+ test_invariants(incremental_defs,"After syncing with incremental defs.");
+
+ // get the FULL defs
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().getDefs() == 0,CtsApi::get() << " failed should return 0 " << TestFixture::client().errorMsg());
+ full_defs = TestFixture::client().defs();
+ BOOST_REQUIRE_MESSAGE( full_defs.get(),"get command failed to get node tree from server");
+ test_invariants(full_defs,"After getting the full defs.");
+
+ // **** NOTE ****: There could have been state change between the calls:
+ // **************: TestFixture::client().sync(incremental_defs)
+ // **************: TestFixture::client().getDefs()
+ // **************: hence we can only compare, incremental and full defs if
+ // **************: state and modification numbers are the same:
+ BOOST_REQUIRE_MESSAGE(incremental_defs.get() != full_defs.get()," Expected two different defs trees ");
+ if ( incremental_defs->state_change_no() == full_defs->state_change_no() &&
+ incremental_defs->modify_change_no() == full_defs->modify_change_no()) {
+ Ecf::set_debug_equality(true); // only has affect in DEBUG build
+ BOOST_CHECK_MESSAGE( *full_defs == *incremental_defs,
+ "Full and incremental defs should be the same. (state_change_no,modify_change_no) ("
+ << incremental_defs->state_change_no() << "," << incremental_defs->modify_change_no() << ")"
+ );
+ Ecf::set_debug_equality(false); // only has affect in DEBUG build
+ }
+ else {
+#ifdef DEBUG_TEST_WAITER
+ std::cout << "***** ServerTestHarness::testWaiter: State change between getting incremental and full defs\n";
+#endif
+ }
+ }
+ }
+
+ int hasAutoCancel = 0;
+ size_t completeSuiteCnt = 0;
+ if (server_changed) {
+
+#ifdef DEBUG_DIFF
+ {
+ PrintStyle::Type_t st = PrintStyle::getStyle();
+ PrintStyle::setStyle(PrintStyle::STATE);
+ counter++;
+ std::string filename = dump_defs_filename + boost::lexical_cast<std::string>(counter);
+ std::ofstream theFile( filename.c_str() );
+
+ std::vector<Task*> tasks;
+ full_defs->getAllTasks(tasks);
+ int unknown = 0;
+ int complete = 0;
+ int queued = 0;
+ int aborted = 0;
+ int submitted = 0;
+ int active = 0;
+ size_t password_size = 0;
+ size_t process_id_size = 0;
+ for(size_t i =0; i < tasks.size(); i++) {
+ switch (tasks[i]->state()) {
+ case NState::UNKNOWN: unknown++; break;
+ case NState::COMPLETE: complete++; break;
+ case NState::QUEUED: queued++; break;
+ case NState::ABORTED: aborted++; break;
+ case NState::SUBMITTED: submitted++; break;
+ case NState::ACTIVE: active++; break;
+ }
+ password_size += tasks[i]->jobsPassword().size();
+ process_id_size += tasks[i]->process_or_remote_id().size();
+ }
+ theFile << "task password_size(" << password_size << ") process_id_size(" << process_id_size << ") total = " << (password_size + process_id_size) << endl;
+ theFile << "unknown: " << unknown << "\n";
+ theFile << "complete: " << complete << "\n";
+ theFile << "queued: " << queued << "\n";
+ theFile << "aborted: " << aborted << "\n";
+ theFile << "submitted: " << submitted << "\n";
+ theFile << "active: " << active << "\n";
+ theFile << *full_defs.get();
+ PrintStyle::setStyle(st);
+ }
+#endif
+ std::string errorMsg;
+ BOOST_REQUIRE_MESSAGE( full_defs->checkInvariants(errorMsg),"Invariants failed " << errorMsg);
+
+ // record the number of times that the server updated the calendar. Allow debug of time dependencies
+ serverUpdateCalendarCount_ = full_defs->updateCalendarCount();
+
+ BOOST_FOREACH(suite_ptr s, full_defs->suiteVec()) {
+ if (s->state() == NState::COMPLETE) completeSuiteCnt++;
+ if (s->hasAutoCancel()) hasAutoCancel++;
+ }
+
+#ifdef DEBUG_TEST_WAITER_DEFS
+ cout << "\nPrinting Defs ==================================================================================\n";
+ std::cout << *full_defs.get();
+ cout << "completeSuiteCnt = " << completeSuiteCnt
+ << " full_defs->suiteVec().size() = " << full_defs->suiteVec().size()
+ << " hasAutoCancel = " << hasAutoCancel << "\n";
+#endif
+ if ( (full_defs->suiteVec().size() == completeSuiteCnt) && (hasAutoCancel == 0)) {
+
+ if ( verifyAttr && verify_attribute_verification()) {
+ // Do verification of expected state changes
+ string localErrorMessage;
+ BOOST_REQUIRE_MESSAGE(full_defs->verification(localErrorMessage),localErrorMessage << "\n" << *full_defs.get());
+ }
+ return full_defs;
+ }
+ }
+
+ // make sure test does not take too long.
+ if ( assertTimer.duration() >= assertTimer.timeConstraint() ) {
+ // Give clues why we are not finishing on time, by using Why and by dumping out node tree
+ cout << "Test time " << assertTimer.duration() << " taking longer than time constraint of " << assertTimer.timeConstraint() << " aborting\n";
+ cout << " completeSuiteCnt = " << completeSuiteCnt << "\n";
+ cout << " full_defs->suiteVec().size() = " << full_defs->suiteVec().size() << "\n";
+ cout << " hasAutoCancel = " << hasAutoCancel << "\n";
+ std::cout << "update-calendar-count(" << serverUpdateCalendarCount_ << ")\n";
+ std::cout << "WHY:\n";
+ WhyCmd reason(full_defs, "" /* do a top down why */ );
+ std::cout << reason.why() << "\n";
+ }
+ BOOST_REQUIRE_MESSAGE(assertTimer.duration() < assertTimer.timeConstraint(),"\n" << *full_defs);
+ if ( assertTimer.duration() >= assertTimer.timeConstraint()) break; // fix warning on AIX
+
+ // auto adjust sleep time.
+ sleepTime = timer.duration() + sleep_fudgeFactor;
+ }
+ return defs_ptr();
+}
+
+
+void ServerTestHarness::createDirAndEcfFiles(
+ NodeContainer* nc,
+ const std::string& smshome,
+ const std::map<std::string,std::string>& customTaskSmsMap,
+ int& customSmsCnt) const
+{
+ std::string directory = smshome + nc->absNodePath();
+#ifdef DEBUG_TEST_HARNESS
+ cout << "creating directory " << directory << "\n";
+#endif
+
+ if ( !fs::exists( smshome ) ) fs::create_directory( smshome );
+ if ( !fs::exists( directory ) ) fs::create_directory( directory );
+
+ if ( generateManFileForNodeContainers_ ) {
+ std::string manFileName = smshome + nc->absNodePath() + File::MAN_EXTN();
+ std::ofstream theManFile( manFileName.c_str() );
+ theManFile << "%manual\n";
+ theManFile << "This file auto generated by ServerTestHarness::createDirAndEcfFiles for all Node Containers\n";
+ theManFile << "%end\n";
+ }
+
+ BOOST_FOREACH(node_ptr n, nc->nodeVec()) {
+
+ Task* t = n->isTask();
+ if (t) {
+ std::string ecf_file = smshome + t->absNodePath() + File::ECF_EXTN();
+#ifdef DEBUG_TEST_HARNESS
+ cout << "creating ecf file " << ecf_file << "\n";
+#endif
+ // Create ECF file with default template or custom file.
+ std::ofstream theEcfFile( ecf_file.c_str() );
+ std::map<std::string,std::string>::const_iterator it = customTaskSmsMap.find(t->absNodePath());
+ if (it == customTaskSmsMap.end()) theEcfFile << getDefaultTemplateEcfFile(t);
+ else {
+ theEcfFile << (*it).second;
+ customSmsCnt++;
+ }
+ }
+ else {
+ Family* f = n->isFamily();
+ assert(f);
+ createDirAndEcfFiles(f,smshome,customTaskSmsMap,customSmsCnt);
+ }
+ }
+}
+
+
+std::string ServerTestHarness::getDefaultTemplateEcfFile(Task* t) const
+{
+ std::string templateEcfFile;
+
+ templateEcfFile += "%manual\n";
+ templateEcfFile += "This is the default ecf script file used for testing\n";
+ templateEcfFile += "%end\n";
+ templateEcfFile += "%comment\n";
+ templateEcfFile += "# Using angle brackets should use ECF_INCLUDE\n";
+ templateEcfFile += "%end\n";
+ templateEcfFile += "%include <head.h>\n";
+ templateEcfFile += "\n";
+ BOOST_FOREACH(const Event& e, t->events()) {
+ templateEcfFile += "%ECF_CLIENT_EXE_PATH% --event=" + e.name_or_number() + "\n";
+ }
+ BOOST_FOREACH(const Meter& m, t->meters()) {
+ templateEcfFile += "for i in";
+ int min = m.min();
+ int max = m.max();
+ int delta = abs(max -min)/10;
+ for(int i = min+delta; i <= max; i = i + delta) {
+ templateEcfFile += " ";
+ templateEcfFile += boost::lexical_cast<std::string>(i);
+ }
+ templateEcfFile += "\n";
+ templateEcfFile += "do\n";
+ templateEcfFile += " %ECF_CLIENT_EXE_PATH% --meter=" + m.name() + " $i\n";
+ templateEcfFile += " sleep %SLEEPTIME%\n";
+ templateEcfFile += "done\n";
+ }
+ /// labels require at least 2 arguments,
+ BOOST_FOREACH(const Label& label, t->labels()) {
+ if (!label.new_value().empty()) {
+ templateEcfFile += "%ECF_CLIENT_EXE_PATH% --label=" + label.name() + " " + label.new_value() + "\n";
+ }
+ else if (!label.value().empty()) {
+ templateEcfFile += "%ECF_CLIENT_EXE_PATH% --label=" + label.name() + " " + label.value() + "\n";
+ }
+ }
+ if (add_default_sleep_time_ && t->events().empty() && t->meters().empty()) {
+ templateEcfFile += "\n# SLEEPTIME is defined the Client Defs.def file. Test variable substitution\n";
+ templateEcfFile += "sleep %SLEEPTIME%\n";
+ }
+ templateEcfFile += "\n%include <tail.h>\n";
+ return templateEcfFile;
+}
+
+std::string ServerTestHarness::testDataDefsLocation( const std::string& defsFile)
+{
+ // DefsFile is of the form base_name.def"
+ // We want to place the defs and log file in the same location as its test directory
+ // test/data/ECF_HOME/base_name/base_name.def
+ std::string testData = testDataLocation(defsFile) + "/" + defsFile;
+ return testData;
+}
+
+std::string ServerTestHarness::testDataLocation( const std::string& defsFile)
+{
+ // DefsFile is of the form:
+ // base_name.def
+ // /tmp/path/base_name.def
+ // We want to place the defs and log file in the same location as its test directory
+ // test/data/ECF_HOME/base_name
+ //
+ std::string base_name = defsFile;
+ size_t slash_pos = defsFile.rfind('/',defsFile.length());
+ if ( slash_pos != std::string::npos) {
+ base_name = base_name.erase(0,slash_pos+1);
+ }
+
+ size_t dot_pos = base_name.rfind('.',base_name.length());
+ assert( dot_pos != std::string::npos); // missing '.'
+ base_name = base_name.substr(0,dot_pos);
+
+
+ std::string testData = TestFixture::smshome() + "/" + base_name;
+ return testData;
+}
diff --git a/Test/src/ServerTestHarness.hpp b/Test/src/ServerTestHarness.hpp
new file mode 100644
index 0000000..920b709
--- /dev/null
+++ b/Test/src/ServerTestHarness.hpp
@@ -0,0 +1,109 @@
+#ifndef SERVERTESTHARNESS_HPP_
+#define SERVERTESTHARNESS_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #46 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include <string>
+#include <map>
+#include "NodeFwd.hpp"
+#include "ZombieUtil.hpp"
+class ClientInvoker;
+
+// This class provides a test harness for running defs file in a client server environment
+// To avoid Address in use errors, we can have client/server use a different port number
+// This is more important when doing instrumentation in HP-UX, as that can take a long time.
+//
+// The Server is started/stopped by use of the Global text Fixture
+// See class TestFixture.hpp
+//
+class ServerTestHarness : private boost::noncopyable {
+public:
+ // if standardVerification is true, we test task goes through normal life cycle
+ // changes. else we compare the log file states with golden log file
+ // Comparing log files across platforms is not reliable, and ignored
+ ServerTestHarness();
+
+ /// generate man files for Suite and family nodes
+ void generateManFileForNodeContainers() { generateManFileForNodeContainers_ = true; }
+
+ /// Enable/disable checking for server poll being to small.
+ /// This test creates dummy .ecf files. Since these tests are run with the server poll
+ /// which is less than 60, we need the task duration between submit->active->complete duration to be less
+ /// the server poll. Tests with time dependencies of one minute separation will be missed.\n"
+ /// Make this configurable since for large defs, when we have 1000's of tasks the
+ /// task duration times are not deterministic
+ void check_task_duration_less_than_server_poll(bool f) { check_task_duration_less_than_server_poll_ = f;}
+
+ /// Sometimes on slow systems we want to disable sleep time.
+ /// since the time duration between submit->active->complete is greater than job submission interval
+ /// and hence time slots get missed.
+ /// The Default is to add the sleep time always for events and meters and when there is NO events or meters
+ /// This flags is used for the *specific* case when there is *no* events/meters.
+ void add_default_sleep_time(bool f) { add_default_sleep_time_ = f ;}
+
+ // Run the following defs file in the test harness.
+ // If no map is provided then a default sms file is fabricated, otherwise
+ // the map allows a sms file string to be associated with a task path
+ // map.first = absolute task path
+ // map.second = sms file string
+#if defined(_AIX)
+ void run(Defs&, const std::string& defs_file, const std::map<std::string,std::string>&, int timeout = 120, bool waitForTestCompletion = true);
+ void run(Defs&, const std::string& defs_file, int timeout = 120,bool waitForTestCompletion = true);
+#elif defined(HPUX)
+ void run(Defs&, const std::string& defs_file, const std::map<std::string,std::string>&, int timeout = 100, bool waitForTestCompletion = true);
+ void run(Defs&, const std::string& defs_file, int timeout = 100,bool waitForTestCompletion = true);
+#else
+ void run(Defs&, const std::string& defs_file, const std::map<std::string,std::string>&, int timeout = 40, bool waitForTestCompletion = true);
+ void run(Defs&, const std::string& defs_file, int timeout = 40,bool waitForTestCompletion = true);
+#endif
+
+ /// Returns the location of the defs file, such thats it in the test data area
+ static std::string testDataDefsLocation( const std::string& defsFile);
+
+ /// The test data location
+ static std::string testDataLocation( const std::string& defsFile);
+
+
+ /// This function is used for waiting for test to finish
+ /// returns the defs from the server at test completeion
+ defs_ptr testWaiter( const Defs& theClientDefs,// The defs on the client side
+ int timeout, // How long should we wait for test to finish
+ bool verifyAttr); // Test verification use verify attributes on defs
+
+ /// for debug return the number of times the calendar was updated in the server
+ unsigned int serverUpdateCalendarCount() const { return serverUpdateCalendarCount_;}
+private:
+
+ defs_ptr doRun(Defs&, const std::map<std::string,std::string>&, int sleepTime,bool waitForTestCompletion);
+
+ void createDirAndEcfFiles(
+ NodeContainer* nc,
+ const std::string& smshome,
+ const std::map<std::string,std::string>& taskSmsMap,
+ int& customSmsCnt) const;
+
+ /// default ecf file will cater for events and meters
+ std::string getDefaultTemplateEcfFile(Task* t) const;
+
+private:
+ bool generateManFileForNodeContainers_;
+ bool check_task_duration_less_than_server_poll_;
+ bool add_default_sleep_time_;
+ int serverUpdateCalendarCount_;
+ std::string defs_filename_;
+};
+#endif
diff --git a/Test/src/TestFixture.cpp b/Test/src/TestFixture.cpp
new file mode 100644
index 0000000..3be8dd2
--- /dev/null
+++ b/Test/src/TestFixture.cpp
@@ -0,0 +1,415 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #77 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : This Fixture facilitates the test of client/server on different platforms
+//============================================================================
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/lexical_cast.hpp>
+#include <iostream>
+#include <stdlib.h> // for getenv()
+#include <fstream> // for ofstream
+
+#include "TestFixture.hpp"
+#include "Defs.hpp"
+#include "Task.hpp"
+#include "ClientEnvironment.hpp" // needed for static ClientEnvironment::hostSpecified(); ONLY
+#include "File.hpp"
+#include "TestHelper.hpp"
+#include "Str.hpp"
+#include "CtsApi.hpp"
+#include "PrintStyle.hpp"
+#include "Host.hpp"
+#include "Rtt.hpp"
+#include "EcfPortLock.hpp"
+
+#ifdef DEBUG
+std::string rtt_filename = "rtt.dat";
+#else
+std::string rtt_filename = "rtt_d.dat";
+#endif
+std::string TestFixture::scratchSmsHome_ = "";
+std::string TestFixture::host_;
+std::string TestFixture::port_;
+std::string TestFixture::test_dir_;
+std::string TestFixture::project_test_dir_ = "Test";
+
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+// ************************************************************************************************
+// For test purpose the server can be started:
+// 1/ By this test fixture
+// 2/ Externally but on the same machine. by defining env variable: export ECF_NODE=localhost
+// WHY? To test for memory leak. (i.e. with valgrind)
+// 3/ Externally but on a different platform. by defining env variable: export ECF_NODE=itanium
+// In this case we NEED to copy the test data, so that it is
+// accessible by the client AND server
+//
+// When invoking the server Externally _MUST_ use .
+// ./Server/bin/gcc.<version>/debug/server --ecfinterval=2
+// The --ecfinterval=2 is _important_ or test will take a long time
+// ************************************************************************************************
+
+// Uncomment to preserve the files for test
+//#define DEBUG_HOST_SERVER 1
+#define DEBUG_LOCAL_SERVER 1
+
+TestFixture::TestFixture(const std::string& project_test_dir)
+{
+ init(project_test_dir);
+}
+
+TestFixture::TestFixture()
+{
+ init("Test");
+}
+
+ClientInvoker& TestFixture::client()
+{
+ static ClientInvoker theClient_;
+ return theClient_;
+}
+
+
+void TestFixture::init(const std::string& project_test_dir)
+{
+ TestFixture::project_test_dir_ = project_test_dir;
+
+ if ( !fs::exists( local_ecf_home() ) ) fs::create_directory( local_ecf_home() );
+
+ // client side file for recording all ClientInvoker round trip times
+ boost::filesystem::remove(rtt_filename);
+ Rtt::create(rtt_filename);
+
+ // ********************************************************
+ // Note: Global fixture Constructor can not use BOOST macro
+ // ********************************************************
+ PrintStyle::setStyle(PrintStyle::STATE);
+
+ // Let first see if we need do anything. If ECF_NODE is specified (ie the name
+ // of the machine, which has the ecflow server), only then do we need to do anything.
+ // The server must have access to the file system specified by ECF_HOME.
+ // This becomes an issue when the server is on a different machine
+ host_ = ClientEnvironment::hostSpecified();
+ port_ = ClientEnvironment::portSpecified(); // returns ECF_PORT, otherwise Str::DEFAULT_PORT_NUMBER
+ std::cout << "TestFixture::TestFixture() jobSubmissionInterval = " << job_submission_interval() << "\n";
+ if (!host_.empty() && host_ != Str::LOCALHOST()) {
+
+ client().set_host_port(host_,port_);
+ std::cout << " EXTERNAL SERVER running on _ANOTHER_ PLATFORM, assuming " << host_ << ":" << port_ << " copying test data ...\n";
+
+ // Must use a file system accessible from the server. Use $SCRATCH
+ // Duplicate test data, required to scratch area and reset ECF_HOME
+ char* scratchEnv = getenv("SCRATCH");
+ assert(scratchEnv != NULL);
+ std::string theSCRATCHArea(scratchEnv);
+ assert(!theSCRATCHArea.empty());
+
+ theSCRATCHArea += "/test_dir";
+ test_dir_ = theSCRATCHArea; // test_dir_ needed in destructor
+ if (boost::filesystem::exists(test_dir_)) {
+ boost::filesystem::remove_all(test_dir_);
+ }
+ theSCRATCHArea += "/ECF_HOME";
+ scratchSmsHome_ = theSCRATCHArea;
+
+ bool ok = File::createDirectories(theSCRATCHArea);
+ BOOST_REQUIRE_MESSAGE(ok,"File::createDirectories(theSCRATCHArea) failed");
+ ok = fs::exists(theSCRATCHArea); assert(ok);
+
+ // Ensure that local includes data exists. This needs to be copied to SCRATCH
+ ok = fs::exists(includes()); assert(ok);
+
+ // Copy over the includes directory to the SCRATCH area.
+ std::string scratchIncludes = test_dir_ + "/";
+ std::string do_copy = "cp -r " + includes() + " " + scratchIncludes;
+ if (system( do_copy.c_str() ) != 0) assert(false);
+
+ // clear log file
+ clearLog();
+ }
+ else if (!host_.empty() && host_ == Str::LOCALHOST()) {
+
+ client().set_host_port(host_,port_);
+ std::cout << " EXTERNAL SERVER running on _SAME_ PLATFORM. Assuming " << host_ << ":" << port_ << "\n";
+
+ // log file may have been deleted, by previous tests. Create a new log file
+ std::string the_log_file = TestFixture::pathToLogFile();
+ if ( !fs::exists( the_log_file )) {
+ std::cout << " Log file " << the_log_file << " does NOT exist, attempting to recreate\n";
+ std::cout << " Creating new log(via remote server) file " << the_log_file << "\n";
+ client().new_log( the_log_file );
+ client().logMsg("Created new log file. msg sent to force new log file to be written to disk");
+ }
+ else std::cout << " Log file " << the_log_file << " already exist\n";
+ }
+ else {
+ // For local host start by removing log file. Server invocation should create a new log file
+ boost::filesystem::remove( boost::filesystem::path( pathToLogFile() ) );
+ host_ = Str::LOCALHOST();
+
+ // Create a unique port number, allowing debug and release to run at the same time
+ // Note: linux64 and linux64intel, can run on same machine, on different workspace
+ // Hence the lock file is not sufficient. Hence we will make a client server call.
+ cout << "Find free port to start server, starting with port " << port_ << "\n";
+ int the_port = boost::lexical_cast<int>(port_);
+ while (!EcfPortLock::is_free(the_port)) the_port++;
+ port_ = ClientInvoker::find_free_port(the_port,true /*show debug output */);
+ EcfPortLock::create(port_);
+
+ // host_ is empty update to localhost, **since** port may have changed, update ClinetInvoker
+ client().set_host_port(host_,port_);
+
+ // Remove the generated check point files, at start of test, otherwise server will load check point file
+ Host h;
+ boost::filesystem::remove(h.ecf_checkpt_file(port_));
+ boost::filesystem::remove(h.ecf_backup_checkpt_file(port_));
+
+ std::string theServerInvokePath = File::find_ecf_server_path();
+ assert(!theServerInvokePath.empty() );
+ theServerInvokePath += " --port=" + port_ ;
+ theServerInvokePath += " --ecfinterval=" + boost::lexical_cast<std::string>( job_submission_interval() );
+ theServerInvokePath += "&";
+ if ( system( theServerInvokePath.c_str() ) != 0) assert(false); // " Server invoke failed "
+
+ std::cout << " ECF_NODE not specified, starting LOCAL " << theServerInvokePath << "\n";
+ }
+
+ /// Ping the server to see if its running
+ /// Assume remote/local server started on the default port
+ /// Either way, we wait for 60 seconds for server, for it to respond to pings
+ /// This is important when server is started locally. We must wait for it to come alive.
+ if (!client().wait_for_server_reply()) {
+ cout << "Ping server on " << host_ << Str::COLON() << port_ << " failed. Is the server running ? " << client().errorMsg() << "\n";
+ assert(false);
+ }
+
+ // Log file must exist, otherwise test will not work. Log file required for comparison
+ if ( !fs::exists( TestFixture::pathToLogFile() )) {
+ cout << "Log file " << TestFixture::pathToLogFile() << " does not exist\n";
+ assert(false);
+ }
+}
+
+
+TestFixture::~TestFixture()
+{
+ // Note: Global fixture Destructor can not use BOOST macro
+ std::cout << "TestFixture::~TestFixture() " << host_ << ":" << port_ << "\n";
+
+ // destructors should not allow exception propagation
+ try {
+#ifndef DEBUG_HOST_SERVER
+ if (!host_.empty() && boost::filesystem::exists(test_dir_)) {
+ boost::filesystem::remove_all(test_dir_);
+ }
+#endif
+#ifndef DEBUG_LOCAL_SERVER
+ if (boost::filesystem::exists(local_ecf_home())) {
+ boost::filesystem::remove_all(local_ecf_home());
+ }
+#endif
+
+ // Print the server suites
+ client().set_cli(true); // so server stats are written to standard out
+ client().set_throw_on_error( false ); // destructors should not allow exception propagation
+ if (client().suites() != 0) {
+ std::cout << "TestFixture::~TestFixture(): ClientInvoker " << CtsApi::suites() << " failed: " << client().errorMsg() << "\n";
+ }
+
+ // Print the server stats
+ if (client().stats() != 0) {
+ std::cout << "TestFixture::~TestFixture(): ClientInvoker " << CtsApi::stats() << " failed: " << client().errorMsg() << "\n";
+ }
+
+ // Kill the server, as all suites are complete. will work for local or external
+ if (client().terminateServer() != 0) {
+ std::cout << "TestFixture::~TestFixture(): ClientInvoker " << CtsApi::terminateServer() << " failed: " << client().errorMsg() << "\n";
+ EcfPortLock::remove( port_ );
+ assert(false);
+ }
+ sleep(1); // allow time to update log file
+
+ // Remove the generated check point files, at end of test
+ Host host;
+ boost::filesystem::remove(host.ecf_log_file(port_));
+ boost::filesystem::remove(host.ecf_checkpt_file(port_));
+ boost::filesystem::remove(host.ecf_backup_checkpt_file(port_));
+
+ // remove the lock file
+ EcfPortLock::remove( port_ );
+
+ // destroy, so that we flush the rtt_filename
+ Rtt::destroy();
+
+ cout << "\nTiming: *NOTE*: The child commands *NOT* recorded. Since its a separate exe(ecflow_client), called via .ecf script\n";
+ cout << Rtt::analyis(rtt_filename); // report round trip times
+ boost::filesystem::remove(rtt_filename);
+ }
+ catch (std::exception& ex) {
+ std::cout << "TestFixture::~TestFixture() caught exception " << ex.what() << "\n";
+ }
+ catch (...) {
+ std::cout << "TestFixture::~TestFixture() caught unknown exception\n";
+ }
+}
+
+int TestFixture::job_submission_interval()
+{
+ int jobSubmissionInterval = 3 ;
+#if defined(HPUX) || defined(_AIX)
+ jobSubmissionInterval += 3;
+#endif
+ return jobSubmissionInterval;
+}
+
+std::string TestFixture::smshome()
+{
+ if ( serverOnLocalMachine() )
+ return local_ecf_home();
+ return scratchSmsHome_;
+}
+
+bool TestFixture::serverOnLocalMachine() {
+ return (host_.empty() || host_ == Str::LOCALHOST());
+}
+
+std::string TestFixture::theClientExePath()
+{
+ if ( serverOnLocalMachine() ) return File::find_ecf_client_path();
+
+ char* client_path_p = getenv("ECF_CLIENT_EXE_PATH");
+ if ( client_path_p == NULL) {
+
+ // Try this before complaining
+ std::string path = "/usr/local/apps/ecflow/current/bin/ecflow_client";
+ if ( fs::exists(path) ) return path;
+
+ cout << "Please set ECF_CLIENT_EXE_PATH. This needs to be set to path to the client executable\n";
+ cout << "The client must be the one that was built on the same platform as the server\n";
+ assert(false);
+ }
+ return string(client_path_p);
+}
+
+void TestFixture::clearLog() {
+
+ // Can't remove log on remote server, just clear the log file
+ client().clearLog();
+}
+
+std::string TestFixture::pathToLogFile()
+{
+ if ( serverOnLocalMachine() ) {
+ Host host;
+ return host.ecf_log_file(port_);
+ }
+
+ char* pathToRemoteLog_p = getenv("ECF_LOG");
+ if ( pathToRemoteLog_p == NULL) {
+ cout << "TestFixture::pathToLogFile(): assert failed\n";
+ cout << "Please set ECF_LOG. This needs to be set to path to the log file\n";
+ cout << "that can be seen by the client and server\n";
+ assert(false);
+ }
+ return std::string(pathToRemoteLog_p);
+}
+
+std::string TestFixture::local_ecf_home()
+{
+ std::string rel_path = project_test_dir_;
+#ifdef DEBUG
+
+#if defined(_AIX)
+ rel_path += "/data/ECF_HOME_debug_aix";
+#elif defined(HPUX)
+ rel_path += "/data/ECF_HOME_debug_hpux";
+#else
+#if defined(__clang__)
+ rel_path += "/data/ECF_HOME_debug_clang";
+#elif defined(__INTEL_COMPILER)
+ rel_path += "/data/ECF_HOME_debug_intel";
+#elif defined(_CRAYC)
+ rel_path += "/data/ECF_HOME_debug_cray";
+#else
+ rel_path += "/data/ECF_HOME_debug_gnu";
+#endif
+#endif
+
+#else
+
+#if defined(_AIX)
+ rel_path += "/data/ECF_HOME_release_aix";
+#elif defined(HPUX)
+ rel_path += "/data/ECF_HOME_release_hpux";
+#else
+#if defined(__clang__)
+ rel_path += "/data/ECF_HOME_release_clang";
+#elif defined(__INTEL_COMPILER)
+ rel_path += "/data/ECF_HOME_release_intel";
+#elif defined(_CRAYC)
+ rel_path += "/data/ECF_HOME_release_cray";
+#else
+ rel_path += "/data/ECF_HOME_release_gnu";
+#endif
+#endif
+
+
+#endif
+
+ std::string absolute_path = File::test_data(rel_path,project_test_dir_);
+ return absolute_path;
+}
+
+std::string TestFixture::includes()
+{
+ // Get to the root source directory
+ std::string includes_path = File::root_source_dir();
+ includes_path += "/";
+ includes_path += project_test_dir_;
+ includes_path += "/data/includes";
+ //std::cout << "includes_path = " << includes_path << " ==============================================\n";
+ return includes_path;
+}
+
+
+/// Given a task name like "a" find the find the first task matching that name
+/// and returns is abs node path
+std::string TestFixture::taskAbsNodePath(const Defs& theDefs, const std::string& taskName)
+{
+ std::vector<Task*> vec;
+ theDefs.getAllTasks(vec);
+ BOOST_FOREACH(Task* t , vec ) {
+ if (t->name() == taskName) return t->absNodePath();
+ }
+
+ cout << "TestFixture::taskAbsNodePath: assert failed: Could not find task " << taskName << "\n";
+ assert(false); // could not find the task ??
+ return string();
+}
+
+int TestFixture::server_version()
+{
+ client().server_version();
+ std::string the_server_version_str = TestFixture::client().get_string();
+ //cout << "\nserver_version_str = " << the_server_version_str << "\n";
+ BOOST_REQUIRE_MESSAGE( Str::replace_all(the_server_version_str,".",""),"failed to find '.' in server version string " << TestFixture::client().get_string());
+
+ // Could 4.0.8rc1
+ Str::replace_all(the_server_version_str,"rc1","");
+ Str::replace_all(the_server_version_str,"rc2","");
+ int the_server_version = boost::lexical_cast<int>(the_server_version_str);
+ return the_server_version;
+}
diff --git a/Test/src/TestFixture.hpp b/Test/src/TestFixture.hpp
new file mode 100644
index 0000000..2515506
--- /dev/null
+++ b/Test/src/TestFixture.hpp
@@ -0,0 +1,103 @@
+#ifndef TESTFIXTURE_HPP_
+#define TESTFIXTURE_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #14 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : This Fixture facilitates the test of client/server on different platforms
+//
+// In order to carry out the test, we must have a common file system.
+// We will use $SCRATCH as this is accessible by both client and server.
+// This means copying over the test data
+//
+// When TextFixture is GLOBAL, then we can't seem to call any of the
+// BOOST_REQUIRE_MESSAGE() macro in constructor/descructor as this causes a crash
+// i.e order of initialisation issues
+//============================================================================
+
+#include "ClientInvoker.hpp"
+#include <string>
+class Defs;
+
+//
+// Need to use static data, since with boost global fixture, its not possible to access
+// the global test fixture in each of the test cases
+//
+struct TestFixture {
+
+ // Constructor will invoke the server, destructor will kill the server
+ // Since this class is static, the constructor/destructor can not call
+ // any of BOOST MACRO, since the unit test will not be there.
+ // When running across platforms will will assume server is already running
+ TestFixture(const std::string& project_test_dir /* Test or view */);
+ TestFixture();
+ ~TestFixture();
+
+ // Configure the server with the job submission interval.
+ // i.e for each 'n' seconds of job submission interval the calendar
+ // is typically incremented by 1 minute. Hence speeding up the
+ // time and thus the testing. See Calendar for further details
+ static int job_submission_interval();
+
+ /// The location of ECF home will vary. If client/server on same machines we
+ /// return test data location. Otherwise we need return a common file system location
+ /// that was created in the constructor
+ static std::string smshome();
+
+ /// Will end up checking to see if ECF_NODE is specified. This specifies the name
+ /// of the machine that is running the server. Otherwise return true
+ static bool serverOnLocalMachine();
+
+ /// If running locally returns location of client exe, if a server is on a remote
+ /// machine, we need to determine its location.
+ // Several options:
+ // a/ Search for hard code path
+ // b/ Ask server about test data, i.e. client exe path, log file location , etc
+ // More flexible
+ static std::string theClientExePath();
+
+ /// When multiple tests are run , we need to clear the log file
+ static void clearLog();
+
+ /// When local just returns ecf.log, when remote return path to log file
+ static std::string pathToLogFile();
+
+ /// Given a task name like "a" find the find the first task matching that name
+ /// and returns is abs node path
+ static std::string taskAbsNodePath(const Defs& theDefs, const std::string& taskName);
+
+ /// Location of the includes used in the ecf file
+ static std::string includes();
+
+ /// returns the server version as an integer.
+ /// This allows as to ignore some tests, when testing old servers.(with new clients).
+ static int server_version();
+
+ // Use for all comms with server
+ static ClientInvoker& client();
+ static std::string port() { return port_;}
+
+private:
+
+ static std::string local_ecf_home();
+
+ void init(const std::string& project_test_dir);
+
+private:
+
+ static std::string scratchSmsHome_;
+ static std::string host_;
+ static std::string port_;
+ static std::string test_dir_; // used when we have an external server, different platform
+ static std::string project_test_dir_; // "Test" or "view"
+};
+
+#endif
diff --git a/Test/src/ZombieUtil.hpp b/Test/src/ZombieUtil.hpp
new file mode 100644
index 0000000..c8ea6cf
--- /dev/null
+++ b/Test/src/ZombieUtil.hpp
@@ -0,0 +1,38 @@
+#ifndef ZOMBIE_UTIL_HPP_
+#define ZOMBIE_UTIL_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #57 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include <boost/noncopyable.hpp>
+#include "Child.hpp"
+class ClientInvoker;
+
+//
+class ZombieUtil : private boost::noncopyable {
+public:
+ static void test_clean_up(int timeout);
+ static int do_zombie_user_action(ecf::User::Action uc,
+ int expected_action_cnt,
+ int max_time_to_wait,
+ bool fail_if_to_long = true);
+};
+
+class TestClean : private boost::noncopyable {
+public:
+ TestClean(int timeout = 25) : timeout_(timeout) { ZombieUtil::test_clean_up(timeout);}
+ ~TestClean() { ZombieUtil::test_clean_up(timeout_);}
+private:
+ int timeout_;
+};
+
+#endif
diff --git a/Test/src/ZombieUtill.cpp b/Test/src/ZombieUtill.cpp
new file mode 100644
index 0000000..bbca69e
--- /dev/null
+++ b/Test/src/ZombieUtill.cpp
@@ -0,0 +1,184 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #57 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include <iostream>
+#include <boost/test/unit_test.hpp>
+
+#include "ZombieUtil.hpp"
+
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "PrintStyle.hpp"
+#include "ClientToServerCmd.hpp"
+#include "AssertTimer.hpp"
+#include "Zombie.hpp"
+#include "TestFixture.hpp"
+
+using namespace std;
+using namespace ecf;
+
+void ZombieUtil::test_clean_up(int timeout) {
+
+ // try to tidy up. Avoid leaving zombie process that mess up tests
+ TestFixture::client().zombieGet();
+ std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
+ if (!zombies.empty()) {
+ cout << "\n***** test_clean_up: found\n" << Zombie::pretty_print( zombies , 9) << "\n, attempting to *fob* then *remove* ...\n";
+
+ int no_fobed = do_zombie_user_action(User::FOB, zombies.size(), timeout, false /* don't fail if it takes to long */);
+
+ // In order to FOB, we must wait, till a child command, talks to the server.
+ if (no_fobed) {
+ int wait = 5;
+#if defined(HPUX) || defined(_AIX)
+ wait += 5; // On these platforms wait longer,
+#endif
+ cout << " Fobed " << no_fobed << " left over zombies. sleeping for " << wait << "s before attempting to remove\n";
+ sleep(wait);
+ }
+ (void) do_zombie_user_action(User::REMOVE, no_fobed, timeout, false /* don't fail if it takes to long */);
+ }
+}
+
+int ZombieUtil::do_zombie_user_action(User::Action uc, int expected_action_cnt, int max_time_to_wait, bool fail_if_to_long)
+{
+ /// return the number of zombies set to user action;
+ bool ecf_debug_zombies = false;
+ if (getenv("ECF_DEBUG_ZOMBIES")) {
+ ecf_debug_zombies = true;
+ cout << "\n do_zombie_user_action " << User::to_string(uc) << " expected_action_cnt " << expected_action_cnt << "\n";
+ }
+
+ int action_set = 0;
+ std::vector<Zombie> action_set_zombies;
+ AssertTimer assertTimer(max_time_to_wait,false); // Bomb out after n seconds, fall back if test fail
+ while (1) {
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().zombieGet() == 0, "zombieGet failed should return 0\n" << TestFixture::client().errorMsg());
+ std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
+ bool continue_looping = false;
+ BOOST_FOREACH(const Zombie& z, zombies) {
+ switch (uc) {
+ case User::FOB: {
+ if (!z.fob()) {
+ TestFixture::client().zombieFob(z); // UNBLOCK, child commands, allow zombie to complete, will clear server_reply().zombies()
+ continue_looping = true;
+ action_set++;
+ action_set_zombies.push_back(z);
+ }
+ break;
+ }
+ case User::FAIL: {
+ if (!z.fail()) {
+ TestFixture::client().zombieFail(z); // UNBLOCK, child commands, allow zombie to complete, will clear server_reply().zombies()
+ continue_looping = true;
+ action_set++;
+ action_set_zombies.push_back(z);
+ }
+ break;
+ }
+ case User::ADOPT: {
+ if (!z.adopt()) {
+ TestFixture::client().zombieAdopt(z); // UNBLOCK, child commands, allow zombie to complete, will clear server_reply().zombies()
+ continue_looping = true;
+ action_set++;
+ action_set_zombies.push_back(z);
+ }
+ break;
+ }
+ case User::REMOVE: {
+ if (!z.remove()) { // should always return false
+ TestFixture::client().zombieRemove(z); // This should be immediate, and is not remembered
+ continue_looping = true;
+ action_set++;
+ action_set_zombies.push_back(z);
+ }
+ break;
+ }
+ case User::BLOCK: {
+ if (!z.block()) {
+ TestFixture::client().zombieBlock(z);
+ continue_looping = true;
+ action_set++;
+ action_set_zombies.push_back(z);
+ }
+ break;
+ }
+ case User::KILL: {
+ if (!z.kill()) {
+ TestFixture::client().zombieKill(z);
+ continue_looping = true;
+ action_set++;
+ action_set_zombies.push_back(z);
+ }
+ break;
+ }
+ }
+ }
+
+ if (expected_action_cnt == action_set) {
+ break; // return
+ }
+
+ if ( !continue_looping && action_set > 0) {
+ if (expected_action_cnt == 0) break; // return, some clients set this as 0
+ if (expected_action_cnt == action_set) break; // return
+ }
+
+ // make sure test does not take too long.
+ if ( assertTimer.duration() >= assertTimer.timeConstraint() ) {
+
+ if (expected_action_cnt > 0 && action_set > 0) {
+ if (ecf_debug_zombies) cout << " timeing out after action_set = " << action_set << " expected_action_cnt = " << expected_action_cnt << "\n";
+ break;
+ }
+
+ std::stringstream ss;
+ ss << "do_zombie_user_action:\nExpected " << expected_action_cnt
+ << " zombies with user action " << User::to_string(uc) << " but found " << action_set << "\naction set zombies\n"
+ << Zombie::pretty_print( action_set_zombies , 6)
+ << ", Test taking longer than time constraint of "
+ << assertTimer.timeConstraint();
+ if (fail_if_to_long) {
+ BOOST_REQUIRE_MESSAGE(false,ss.str() << " aborting\n" << Zombie::pretty_print( zombies , 6));
+ }
+ else {
+ cout << ss.str() << " breaking out\n" << Zombie::pretty_print( zombies , 6) << "\n";
+ break;
+ }
+ }
+ sleep(1);
+ }
+
+ // return the real state of the server zombies.
+ // *** Note: remove is immediate hence z.remove() below is not valid
+ action_set = 0;
+ BOOST_REQUIRE_MESSAGE(TestFixture::client().zombieGet() == 0, "zombieGet failed should return 0\n" << TestFixture::client().errorMsg());
+ std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
+ BOOST_FOREACH(const Zombie& z, zombies) {
+ switch (uc) {
+ case User::FOB: { if (z.fob()) action_set++; break; }
+ case User::FAIL: { if (z.fail()) action_set++; break; }
+ case User::ADOPT: { if (z.adopt()) action_set++; break; }
+ case User::REMOVE: { if (z.remove()) action_set++; break; }
+ case User::BLOCK: { if (z.block()) action_set++; break; }
+ case User::KILL: { if (z.kill()) action_set++; break; }
+ }
+ }
+ if (ecf_debug_zombies) {
+ cout << " " << action_set << " zombies set to user action " << User::to_string(uc) << " returning\n";
+ cout << Zombie::pretty_print( zombies , 6);
+ }
+ return action_set;
+}
diff --git a/Test/test.ddoc b/Test/test.ddoc
new file mode 100644
index 0000000..bee6cb1
--- /dev/null
+++ b/Test/test.ddoc
@@ -0,0 +1,102 @@
+. Test design documentation
+===============================
+
+Time
+======
+ o Currently many client side test, create the test with current time + one minute.
+ However when doing cross platform test these tests can fail since
+ the date is not the same as the server machine.
+
+ i.e time on oetzi and itanium is out of sync by one minute
+ This means this test will keep on holding an not complete.
+
+ Need to be able to compensate for this.
+
+Job submission and Calendar increment
+=====================================
+o In release mode, job submission interval is same as calendar increment. i.e 60 seconds
+ However for testing, this will take too long, so we need to speed up the
+ calendar. i.e for a job submission interval of 2 seconds, we increment a calendar
+ by one minute on Linux.
+ The job submission interval is specified via the command line to the server.
+ The Calendar increment is specIfied via the clock attribute in the suite definition.
+ This allows us to have multiple suite, where the calendar increment can be
+ different.
+
+ While 2 second jobs submission interval -> calendar increment 60 seconds works
+ on linux. Its not the same on different platforms.
+
+ State change intervals: with job sub 2 seconds--> calendar 60 sec
+ On Linux(oetzi)
+ submit------------------>init---------------------> complete
+ 17:18:09 0 sec 17:18:09 1 sec 17:18:10 (Log file wall clock)
+ 17:19:02 0 sec 17:19:02 0 sec 17:19:02 (suite calendar time)
+
+ Notice that the calendar time has not changed since its incremented
+ by a minute, for each 2 seconds. (i.e only 1 second has elapsed)
+
+ Therefore on linux spawning a process from submit->init->complete
+ takes less than the job submission interval of 2 seconds.
+ This means we will will not miss any time dependency slots separated by one minute
+
+
+ On HPUX(Itanium): with job sub 1 sec ---> calendar 60 sec
+ submit------------------>init---------------------> complete
+ 8:25:37 5 sec 8:25:42 3 sec 8:25:45 (Log file wall clock)
+ 8:27:28 5 min* 8:32:28 3 min 8:35:28 (suite calendar time)
+
+ At the extreme of 1 second job submission interval on HPUX it can be seen that it
+ takes 8 seconds between submit->active->complete during this time
+ the suite calendar has increment by 8 minutes. Hence if we had any
+ time dependencies with 1 minute interval, then time slots will get missed.
+
+ HENCE FOR TESTING PURPOSES SUBMIT-->INIT-->COMPLETE MUST TAKE LESS THAN JOB SUBMISSION
+ INTERVAL ELSE THE TESTING WILL FAIL.
+ In fact the time on HPUX can very widely depending on the load.
+
+ The check above is implemented in;
+ void Node::setStateOnly(NState::State newState)
+
+
+Cross platform client server
+=============================
+
+o Issues:
+ The biggest problem is clearing/truncating the ecf.log from the client side when a
+ new test is about to be run. It appears that if the server side is holding an open
+ ofstream(i.e in the singleton log). Then clearing on the client side has no effect.
+ It may be that file is disk cached !!! and it does not write to physical medium.
+ (It appears that ofstream does not have sync() ie for forcing disk cache to be written to
+ the physical medium. Note: closing a file gives a strong hint to OS, to write the
+ file to disk, but does not guarantee it.)
+ Google search on ofstream and disk caching sync()
+
+ As an experiment the log file was change not to hold a ofstream but instead
+ buffer the log lines, and when the buffer exceeed 50, it was written
+ to the log file and closed. This was proved to work. However it is not a good
+ long term solution. Because:
+ a/ it requires explict flushing,
+ b/ the file will get huge, and opening to append will take a long time?
+ c/ A crash, would mean log file data would be lost
+
+ i.e since closing a file forces the disk cache to written to the physical medium
+
+o When testing across platforms the following environment variables must be set
+
+$SCRATCH : This specifies the location of the file system shared between the
+ client and server. The test data that resides on local linux machine
+ is copied over.
+
+ $ECF_NODE : This specfies the machine name on which the server is running.
+ The server must be running first.
+
+ $ECF_LOG : specifies the path to log file created by the server.
+ This path must be accessible by the client and server.
+ This is required by testing, as the log is copied over
+ for each test run. So that it can be compared to the golden log file.
+
+ $ECF_CLIENT_EXE_PATH : This specfies the path to client executable.
+ The Test generate the ECF_ file. When the sms file are processed into
+ the tasks. The task must be able to communicate to the server
+ Hence the test will embed the path to the client exe, in jobs.
+ Typically need equivalent to smsinit/smscomplete/ smsabort, etc
\ No newline at end of file
diff --git a/VERSION.cmake b/VERSION.cmake
new file mode 100644
index 0000000..5b14724
--- /dev/null
+++ b/VERSION.cmake
@@ -0,0 +1,7 @@
+set( ECFLOW_RELEASE "4" )
+set( ECFLOW_MAJOR "1" )
+set( ECFLOW_MINOR "0" )
+
+# use this form to be consistent with other packages,+ allow standard extraction of version from scripts
+# could replaced "4.0.8" with "${ECFLOW_RELEASE}.${ECFLOW_MAJOR}.${ECFLOW_MINOR}"
+set( ${PROJECT_NAME}_VERSION_STR "4.1.0" )
diff --git a/Viewer/CMakeLists.txt b/Viewer/CMakeLists.txt
new file mode 100644
index 0000000..40d1c46
--- /dev/null
+++ b/Viewer/CMakeLists.txt
@@ -0,0 +1,17 @@
+# avoid warning about dependency targets that don't exit
+#
+# CMake Warning (dev) at Viewer/src/CMakeLists.txt:261 (ADD_DEPENDENCIES):
+# Policy CMP0046 is not set: Error on non-existent dependency in
+# add_dependencies. Run "cmake --help-policy CMP0046" for policy details.
+# Use the cmake_policy command to set the policy and suppress this warning.
+#
+# The dependency target
+# "/tmp/ma0/workspace/ecflow/Viewer/src/../images/zombie_dock.svg" of target
+# "Qt_resource_cpp" does not exist.
+
+if (POLICY CMP0046)
+ cmake_policy(SET CMP0046 OLD)
+endif()
+
+add_subdirectory( src )
+add_subdirectory( scripts )
diff --git a/Viewer/images/add.svg b/Viewer/images/add.svg
new file mode 100644
index 0000000..33d11d5
--- /dev/null
+++ b/Viewer/images/add.svg
@@ -0,0 +1,185 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.47 r22583"
+ sodipodi:docname="add.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3608">
+ <stop
+ id="stop3610"
+ offset="0"
+ style="stop-color:#2eaf1d;stop-opacity:1;" />
+ <stop
+ id="stop3612"
+ offset="1"
+ style="stop-color:#91ff44;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3612">
+ <stop
+ style="stop-color:#616161;stop-opacity:1;"
+ offset="0"
+ id="stop3614" />
+ <stop
+ style="stop-color:#383838;stop-opacity:1;"
+ offset="1"
+ id="stop3616" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3601">
+ <stop
+ style="stop-color:#a2a2a2;stop-opacity:1;"
+ offset="0"
+ id="stop3603" />
+ <stop
+ style="stop-color:#343434;stop-opacity:1;"
+ offset="1"
+ id="stop3605" />
+ </linearGradient>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ id="perspective10" />
+ <inkscape:perspective
+ id="perspective2825"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <inkscape:perspective
+ id="perspective2841"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3601"
+ id="linearGradient3607"
+ x1="10.653805"
+ y1="3.7712457"
+ x2="24.085051"
+ y2="29.5"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.96774194,0,0,-0.96774194,0.58051457,31.158684)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3612"
+ id="linearGradient3618"
+ x1="3"
+ y1="28.806061"
+ x2="29"
+ y2="28.806061"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3612"
+ id="linearGradient3620"
+ gradientUnits="userSpaceOnUse"
+ x1="3"
+ y1="28.806061"
+ x2="29"
+ y2="28.806061"
+ gradientTransform="translate(0,-32.806061)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3608"
+ id="linearGradient3606"
+ x1="24"
+ y1="26"
+ x2="7"
+ y2="8"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(0.80606061,-0.19393939)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="15.46875"
+ inkscape:cx="-8.2472301"
+ inkscape:cy="16.354555"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer3"
+ showgrid="true"
+ inkscape:window-width="1524"
+ inkscape:window-height="855"
+ inkscape:window-x="227"
+ inkscape:window-y="134"
+ inkscape:window-maximized="0"
+ inkscape:snap-to-guides="false"
+ inkscape:snap-grids="false">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2831"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title></dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="plus"
+ style="display:inline">
+ <path
+ style="fill:url(#linearGradient3606);fill-opacity:1;stroke:#367425;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 12.806061,2.8060606 7,0 0,10.0000004 10,0 0,7 -10,0 0,10 -7,0 0,-10 -10.0000004,0 0,-7 10.0000004,0 0,-10.0000004 z"
+ id="path2826"
+ sodipodi:nodetypes="ccccccccccccc" />
+ </g>
+</svg>
diff --git a/Viewer/images/add_info.svg b/Viewer/images/add_info.svg
new file mode 100644
index 0000000..4594161
--- /dev/null
+++ b/Viewer/images/add_info.svg
@@ -0,0 +1,531 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="add_info.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3806">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop3808" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop3810" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3826">
+ <stop
+ style="stop-color:#c8d0d8;stop-opacity:1;"
+ offset="0"
+ id="stop3828" />
+ <stop
+ style="stop-color:#c8d0d8;stop-opacity:0;"
+ offset="1"
+ id="stop3830" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3798">
+ <stop
+ style="stop-color:#2d2d2d;stop-opacity:1;"
+ offset="0"
+ id="stop3800" />
+ <stop
+ style="stop-color:#2d2d2d;stop-opacity:1;"
+ offset="1"
+ id="stop3802" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3608">
+ <stop
+ id="stop3610"
+ offset="0"
+ style="stop-color:#2eaf1d;stop-opacity:1;" />
+ <stop
+ id="stop3612"
+ offset="1"
+ style="stop-color:#91ff44;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3612">
+ <stop
+ style="stop-color:#616161;stop-opacity:1;"
+ offset="0"
+ id="stop3614" />
+ <stop
+ style="stop-color:#383838;stop-opacity:1;"
+ offset="1"
+ id="stop3616" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3601">
+ <stop
+ style="stop-color:#a2a2a2;stop-opacity:1;"
+ offset="0"
+ id="stop3603" />
+ <stop
+ style="stop-color:#343434;stop-opacity:1;"
+ offset="1"
+ id="stop3605" />
+ </linearGradient>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ id="perspective10" />
+ <inkscape:perspective
+ id="perspective2825"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <inkscape:perspective
+ id="perspective2841"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3601"
+ id="linearGradient3607"
+ x1="10.653805"
+ y1="3.7712457"
+ x2="24.085051"
+ y2="29.5"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.96774194,0,0,-0.96774194,0.58051457,31.158684)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3612"
+ id="linearGradient3618"
+ x1="3"
+ y1="28.806061"
+ x2="29"
+ y2="28.806061"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3612"
+ id="linearGradient3620"
+ gradientUnits="userSpaceOnUse"
+ x1="3"
+ y1="28.806061"
+ x2="29"
+ y2="28.806061"
+ gradientTransform="translate(0,-32.806061)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3608"
+ id="linearGradient3606"
+ x1="24"
+ y1="26"
+ x2="7"
+ y2="8"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.83718675,0,0,0.87310139,-36.94508,11.435241)" />
+ <linearGradient
+ gradientUnits="userSpaceOnUse"
+ y2="23.49078"
+ x2="7.2979932"
+ y1="7.6554561"
+ x1="9.0300617"
+ id="linearGradient3765"
+ xlink:href="#linearGradient3757"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3757">
+ <stop
+ id="stop3759"
+ offset="0"
+ style="stop-color:#fdfb72;stop-opacity:1;" />
+ <stop
+ id="stop3761"
+ offset="1"
+ style="stop-color:#ffb41b;stop-opacity:1;" />
+ </linearGradient>
+ <inkscape:perspective
+ id="perspective2882"
+ inkscape:persp3d-origin="16 : 10.666667 : 1"
+ inkscape:vp_z="32 : 16 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 16 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <inkscape:perspective
+ id="perspective3015"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <linearGradient
+ id="linearGradient3845">
+ <stop
+ style="stop-color:#326dc2;stop-opacity:1;"
+ offset="0"
+ id="stop3847" />
+ <stop
+ style="stop-color:#6295be;stop-opacity:1;"
+ offset="1"
+ id="stop3849" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3826"
+ id="linearGradient3832"
+ x1="1.6569907"
+ y1="24.5"
+ x2="27.343009"
+ y2="24.5"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.8,0,0,1.909091,-24.677369,-29.324952)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3798"
+ id="linearGradient3799"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.99999997,0,0,0.5,-1,15)"
+ x1="0"
+ y1="24"
+ x2="12.484"
+ y2="24" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3798-5"
+ id="linearGradient3794-8"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.125,0,0,0.5,2.5232104,-0.9458414)"
+ x1="0"
+ y1="24"
+ x2="12.484"
+ y2="24" />
+ <linearGradient
+ id="linearGradient3798-5">
+ <stop
+ style="stop-color:#cfd1d2;stop-opacity:1;"
+ offset="0"
+ id="stop3800-1" />
+ <stop
+ style="stop-color:#476476;stop-opacity:1;"
+ offset="1"
+ id="stop3802-7" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3807"
+ id="linearGradient3813"
+ x1="22.061895"
+ y1="29.435204"
+ x2="31.061895"
+ y2="22.435204"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ id="linearGradient3807">
+ <stop
+ style="stop-color:#269e00;stop-opacity:1;"
+ offset="0"
+ id="stop3809" />
+ <stop
+ style="stop-color:#86e16b;stop-opacity:1"
+ offset="1"
+ id="stop3811" />
+ </linearGradient>
+ <linearGradient
+ gradientTransform="translate(0.02401155,-0.05510828)"
+ inkscape:collect="always"
+ xlink:href="#linearGradient3818"
+ id="linearGradient3824"
+ x1="0.71302384"
+ y1="9.9201832"
+ x2="25.372599"
+ y2="9.9201832"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ id="linearGradient3818">
+ <stop
+ style="stop-color:#267fbd;stop-opacity:1;"
+ offset="0"
+ id="stop3820" />
+ <stop
+ style="stop-color:#a5b4b8;stop-opacity:1;"
+ offset="1"
+ id="stop3822" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4194-0"
+ id="linearGradient4200-4"
+ x1="37.706196"
+ y1="3.5453706"
+ x2="2.2564189"
+ y2="25.726259"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.77976303,0,0,0.76912919,0.0689839,7.2311591)" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4194-0">
+ <stop
+ style="stop-color:#eff2fb;stop-opacity:1"
+ offset="0"
+ id="stop4196-5" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="1"
+ id="stop4198-5" />
+ </linearGradient>
+ <linearGradient
+ y2="25.726259"
+ x2="2.2564189"
+ y1="3.5453706"
+ x1="37.706196"
+ gradientTransform="matrix(0.77976303,0,0,0.76912919,0.09299555,7.1760507)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4561"
+ xlink:href="#linearGradient4194-0"
+ inkscape:collect="always" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3807-2"
+ id="linearGradient3813-0"
+ x1="22.061895"
+ y1="29.435204"
+ x2="31.061895"
+ y2="22.435204"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ id="linearGradient3807-2">
+ <stop
+ style="stop-color:#3c7eb4;stop-opacity:1;"
+ offset="0"
+ id="stop3809-8" />
+ <stop
+ style="stop-color:#3f6a8b;stop-opacity:1;"
+ offset="1"
+ id="stop3811-1" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3818-7"
+ id="linearGradient3824-7"
+ x1="0.71302384"
+ y1="9.9201832"
+ x2="25.372599"
+ y2="9.9201832"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.99498,0,0,0.93019197,0.02759017,1.039721)" />
+ <linearGradient
+ id="linearGradient3818-7">
+ <stop
+ style="stop-color:#7691a2;stop-opacity:1"
+ offset="0"
+ id="stop3820-3" />
+ <stop
+ style="stop-color:#a5b4b8;stop-opacity:1;"
+ offset="1"
+ id="stop3822-9" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4194-3"
+ id="linearGradient4200-1"
+ x1="37.706196"
+ y1="3.5453706"
+ x2="2.2564189"
+ y2="25.726259"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.77976303,0,0,0.76912919,0.0689839,7.2311591)" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4194-3">
+ <stop
+ style="stop-color:#eff2fb;stop-opacity:1"
+ offset="0"
+ id="stop4196-58" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="1"
+ id="stop4198-50" />
+ </linearGradient>
+ <linearGradient
+ y2="25.726259"
+ x2="2.2564189"
+ y1="3.5453706"
+ x1="37.706196"
+ gradientTransform="matrix(0.4623372,0,0,0.76912919,0.16568617,7.423633)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4722"
+ xlink:href="#linearGradient4194-3"
+ inkscape:collect="always" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3807-1"
+ id="linearGradient3813-3"
+ x1="22.061895"
+ y1="29.435204"
+ x2="31.061895"
+ y2="22.435204"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ id="linearGradient3807-1">
+ <stop
+ style="stop-color:#6aab3a;stop-opacity:1;"
+ offset="0"
+ id="stop3809-7" />
+ <stop
+ style="stop-color:#6bc75e;stop-opacity:1;"
+ offset="1"
+ id="stop3811-6" />
+ </linearGradient>
+ <linearGradient
+ y2="22.435204"
+ x2="31.061895"
+ y1="29.435204"
+ x1="22.061895"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3263"
+ xlink:href="#linearGradient3807-1"
+ inkscape:collect="always" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="16.15625"
+ inkscape:cx="30.528121"
+ inkscape:cy="26.064878"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:window-width="1920"
+ inkscape:window-height="1140"
+ inkscape:window-x="-4"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1"
+ inkscape:snap-to-guides="false"
+ inkscape:snap-grids="false">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2831"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="frame" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="plus"
+ style="display:inline" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="star"
+ style="display:inline">
+ <rect
+ style="fill:url(#linearGradient4722);fill-opacity:1;stroke:#4d4d4d;stroke-width:0.80585694;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="rect3804-6"
+ width="14.244038"
+ height="23.896389"
+ x="0.45186624"
+ y="7.772109"
+ ry="0" />
+ <rect
+ style="fill:url(#linearGradient3824-7);fill-opacity:1;stroke:none;display:inline"
+ id="rect4860-8"
+ width="24.535784"
+ height="4.1237912"
+ x="0.73703396"
+ y="8.2055016"
+ ry="0.27575642" />
+ <text
+ xml:space="preserve"
+ style="font-size:19.83777618px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#164450;fill-opacity:1;stroke:none;display:inline;font-family:Arial;-inkscape-font-specification:Century Schoolbook L Bold"
+ x="3.7442672"
+ y="29.816154"
+ id="text3974-1"
+ sodipodi:linespacing="125%"
+ transform="scale(1.0418617,0.9598203)"><tspan
+ sodipodi:role="line"
+ id="tspan3976-3"
+ x="3.7442672"
+ y="29.816154"
+ style="font-size:19.83777618px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#164450;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif Bold">i</tspan></text>
+ <ellipse
+ style="fill:url(#linearGradient3263);fill-opacity:1;fill-rule:evenodd;stroke:#4b8600;stroke-width:0.66774601;stroke-opacity:1;display:inline"
+ id="path2978-9"
+ cx="25.962849"
+ cy="25.718735"
+ rx="6.1450515"
+ ry="6.2331204"
+ sodipodi:cx="25.962849"
+ sodipodi:cy="25.718735"
+ sodipodi:rx="6.1450515"
+ sodipodi:ry="6.2331204"
+ transform="matrix(1.5086573,0,0,1.4865752,-17.567494,-28.081963)" />
+ <path
+ style="fill:#ffffff;fill-opacity:1;stroke:none;display:inline"
+ d="m 20.014906,3.0456245 3.655871,6.3e-6 -0.08983,5.1846495 5.132308,0 7e-6,3.4351677 -5.132304,0 -10e-6,5.268202 -3.476199,-0.08354 -0.08982,-5.268202 -5.581473,2e-6 0,-3.4351688 5.581474,0 0,-5.1011031 z"
+ id="path2826-4-5"
+ sodipodi:nodetypes="ccccccccccccc"
+ inkscape:connector-curvature="0" />
+ </g>
+</svg>
diff --git a/Viewer/images/add_tab.svg b/Viewer/images/add_tab.svg
new file mode 100644
index 0000000..29a95e9
--- /dev/null
+++ b/Viewer/images/add_tab.svg
@@ -0,0 +1,301 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.2 r9819"
+ sodipodi:docname="add_tab.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3782">
+ <stop
+ style="stop-color:#000080;stop-opacity:1;"
+ offset="0"
+ id="stop3784" />
+ <stop
+ style="stop-color:#578eb5;stop-opacity:0.9910714;"
+ offset="1"
+ id="stop3786" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3608">
+ <stop
+ id="stop3610"
+ offset="0"
+ style="stop-color:#2eaf1d;stop-opacity:1;" />
+ <stop
+ id="stop3612"
+ offset="1"
+ style="stop-color:#91ff44;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3612">
+ <stop
+ style="stop-color:#616161;stop-opacity:1;"
+ offset="0"
+ id="stop3614" />
+ <stop
+ style="stop-color:#383838;stop-opacity:1;"
+ offset="1"
+ id="stop3616" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3601">
+ <stop
+ style="stop-color:#a2a2a2;stop-opacity:1;"
+ offset="0"
+ id="stop3603" />
+ <stop
+ style="stop-color:#343434;stop-opacity:1;"
+ offset="1"
+ id="stop3605" />
+ </linearGradient>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ id="perspective10" />
+ <inkscape:perspective
+ id="perspective2825"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <inkscape:perspective
+ id="perspective2841"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3601"
+ id="linearGradient3607"
+ x1="10.653805"
+ y1="3.7712457"
+ x2="24.085051"
+ y2="29.5"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.96774194,0,0,-0.96774194,0.58051457,31.158684)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3612"
+ id="linearGradient3618"
+ x1="3"
+ y1="28.806061"
+ x2="29"
+ y2="28.806061"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3612"
+ id="linearGradient3620"
+ gradientUnits="userSpaceOnUse"
+ x1="3"
+ y1="28.806061"
+ x2="29"
+ y2="28.806061"
+ gradientTransform="translate(0,-32.806061)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3608"
+ id="linearGradient3606"
+ x1="24"
+ y1="26"
+ x2="7"
+ y2="8"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.83718675,0,0,0.87310139,-36.94508,11.435241)" />
+ <linearGradient
+ id="linearGradient3757">
+ <stop
+ id="stop3759"
+ offset="0"
+ style="stop-color:#fdfb72;stop-opacity:1;" />
+ <stop
+ id="stop3761"
+ offset="1"
+ style="stop-color:#ffb41b;stop-opacity:1;" />
+ </linearGradient>
+ <inkscape:perspective
+ id="perspective2882"
+ inkscape:persp3d-origin="16 : 10.666667 : 1"
+ inkscape:vp_z="32 : 16 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 16 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <inkscape:perspective
+ id="perspective3015"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <linearGradient
+ id="linearGradient3845">
+ <stop
+ style="stop-color:#326dc2;stop-opacity:1;"
+ offset="0"
+ id="stop3847" />
+ <stop
+ style="stop-color:#6295be;stop-opacity:1;"
+ offset="1"
+ id="stop3849" />
+ </linearGradient>
+ <linearGradient
+ y2="19.5"
+ x2="38.5"
+ y1="19.5"
+ x1="7.5"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3945"
+ xlink:href="#linearGradient3845-1"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3845-1">
+ <stop
+ style="stop-color:#3992cd;stop-opacity:1;"
+ offset="0"
+ id="stop3847-7" />
+ <stop
+ style="stop-color:#8fbce1;stop-opacity:1;"
+ offset="1"
+ id="stop3849-4" />
+ </linearGradient>
+ <linearGradient
+ y2="19.5"
+ x2="38.5"
+ y1="19.5"
+ x1="7.5"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3066"
+ xlink:href="#linearGradient3845-1"
+ inkscape:collect="always" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3845-1"
+ id="linearGradient3808"
+ x1="-12.355866"
+ y1="27.080372"
+ x2="-21.346371"
+ y2="14.270093"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.2173913,0,0,1.5555554,36.086959,-13.555554)" />
+ <filter
+ inkscape:collect="always"
+ id="filter3824">
+ <feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="0.53563009"
+ id="feGaussianBlur3826" />
+ </filter>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="16.15625"
+ inkscape:cx="-3.311412"
+ inkscape:cy="16"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:window-width="1881"
+ inkscape:window-height="1026"
+ inkscape:window-x="-8"
+ inkscape:window-y="-8"
+ inkscape:window-maximized="1"
+ inkscape:snap-to-guides="false"
+ inkscape:snap-grids="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2831"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="plus"
+ style="display:inline">
+ <rect
+ style="fill:url(#linearGradient3808);fill-opacity:1;stroke:#0d53b0;stroke-width:1.86666667;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="rect3032"
+ width="28"
+ height="28"
+ x="2"
+ y="2"
+ ry="6.6423664" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="star"
+ style="display:inline">
+ <path
+ style="fill:#1a1010;fill-opacity:1;stroke:none;display:inline;filter:url(#filter3824)"
+ d="M 14.540635,5 20,5 l -6e-6,8.638729 7.821597,0 9e-6,5.464545 -7.8216,0 0,8.678939 -5.459365,0 0.02476,-8.811855 -8.7597353,0.132916 0,-5.424336 8.7349833,0 0,-8.678938 z"
+ id="path2826-4"
+ sodipodi:nodetypes="cccccccccccccc"
+ inkscape:connector-curvature="0"
+ transform="matrix(0.85490784,0,0,0.90632942,3.215096,2.6861408)" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccc"
+ id="path3810"
+ d="m 14.04054,6.2337244 4.959466,0 L 19,14 l 7.105395,0 8e-6,4.912663 -7.105397,0 0,7.802424 -4.959466,0 0.02249,-7.921917 -7.957627,0.119493 0,-4.876515 7.935144,0 0,-7.8024236 z"
+ style="fill:#ffffff;fill-opacity:1;stroke:none;display:inline" />
+ </g>
+</svg>
diff --git a/Viewer/images/add_table.svg b/Viewer/images/add_table.svg
new file mode 100644
index 0000000..77b5bad
--- /dev/null
+++ b/Viewer/images/add_table.svg
@@ -0,0 +1,422 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="add_table.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3818">
+ <stop
+ style="stop-color:#7691a2;stop-opacity:1"
+ offset="0"
+ id="stop3820" />
+ <stop
+ style="stop-color:#a5b4b8;stop-opacity:1;"
+ offset="1"
+ id="stop3822" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3807">
+ <stop
+ style="stop-color:#6aab3a;stop-opacity:1;"
+ offset="0"
+ id="stop3809" />
+ <stop
+ style="stop-color:#6bc75e;stop-opacity:1;"
+ offset="1"
+ id="stop3811" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3806">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop3808" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop3810" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3826">
+ <stop
+ style="stop-color:#c8d0d8;stop-opacity:1;"
+ offset="0"
+ id="stop3828" />
+ <stop
+ style="stop-color:#c8d0d8;stop-opacity:0;"
+ offset="1"
+ id="stop3830" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3798">
+ <stop
+ style="stop-color:#2d2d2d;stop-opacity:1;"
+ offset="0"
+ id="stop3800" />
+ <stop
+ style="stop-color:#2d2d2d;stop-opacity:1;"
+ offset="1"
+ id="stop3802" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3608">
+ <stop
+ id="stop3610"
+ offset="0"
+ style="stop-color:#2eaf1d;stop-opacity:1;" />
+ <stop
+ id="stop3612"
+ offset="1"
+ style="stop-color:#91ff44;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3612">
+ <stop
+ style="stop-color:#616161;stop-opacity:1;"
+ offset="0"
+ id="stop3614" />
+ <stop
+ style="stop-color:#383838;stop-opacity:1;"
+ offset="1"
+ id="stop3616" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3601">
+ <stop
+ style="stop-color:#a2a2a2;stop-opacity:1;"
+ offset="0"
+ id="stop3603" />
+ <stop
+ style="stop-color:#343434;stop-opacity:1;"
+ offset="1"
+ id="stop3605" />
+ </linearGradient>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ id="perspective10" />
+ <inkscape:perspective
+ id="perspective2825"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <inkscape:perspective
+ id="perspective2841"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3601"
+ id="linearGradient3607"
+ x1="10.653805"
+ y1="3.7712457"
+ x2="24.085051"
+ y2="29.5"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.96774194,0,0,-0.96774194,0.58051457,31.158684)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3612"
+ id="linearGradient3618"
+ x1="3"
+ y1="28.806061"
+ x2="29"
+ y2="28.806061"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3612"
+ id="linearGradient3620"
+ gradientUnits="userSpaceOnUse"
+ x1="3"
+ y1="28.806061"
+ x2="29"
+ y2="28.806061"
+ gradientTransform="translate(0,-32.806061)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3608"
+ id="linearGradient3606"
+ x1="24"
+ y1="26"
+ x2="7"
+ y2="8"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.83718675,0,0,0.87310139,-36.94508,11.435241)" />
+ <linearGradient
+ gradientUnits="userSpaceOnUse"
+ y2="23.49078"
+ x2="7.2979932"
+ y1="7.6554561"
+ x1="9.0300617"
+ id="linearGradient3765"
+ xlink:href="#linearGradient3757"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3757">
+ <stop
+ id="stop3759"
+ offset="0"
+ style="stop-color:#fdfb72;stop-opacity:1;" />
+ <stop
+ id="stop3761"
+ offset="1"
+ style="stop-color:#ffb41b;stop-opacity:1;" />
+ </linearGradient>
+ <inkscape:perspective
+ id="perspective2882"
+ inkscape:persp3d-origin="16 : 10.666667 : 1"
+ inkscape:vp_z="32 : 16 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 16 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <inkscape:perspective
+ id="perspective3015"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <linearGradient
+ id="linearGradient3845">
+ <stop
+ style="stop-color:#326dc2;stop-opacity:1;"
+ offset="0"
+ id="stop3847" />
+ <stop
+ style="stop-color:#6295be;stop-opacity:1;"
+ offset="1"
+ id="stop3849" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3826"
+ id="linearGradient3832"
+ x1="1.6569907"
+ y1="24.5"
+ x2="27.343009"
+ y2="24.5"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.8,0,0,1.909091,-24.677369,-29.324952)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3798"
+ id="linearGradient3799"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.99999997,0,0,0.5,-1,15)"
+ x1="0"
+ y1="24"
+ x2="12.484"
+ y2="24" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3798-5"
+ id="linearGradient3794-8"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.125,0,0,0.5,2.5232104,-0.9458414)"
+ x1="0"
+ y1="24"
+ x2="12.484"
+ y2="24" />
+ <linearGradient
+ id="linearGradient3798-5">
+ <stop
+ style="stop-color:#cfd1d2;stop-opacity:1;"
+ offset="0"
+ id="stop3800-1" />
+ <stop
+ style="stop-color:#476476;stop-opacity:1;"
+ offset="1"
+ id="stop3802-7" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4194"
+ id="linearGradient4200"
+ x1="37.706196"
+ y1="3.5453706"
+ x2="2.2564189"
+ y2="25.726259"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.4703733,0,0,0.76912919,0.26049211,7.3549502)" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4194">
+ <stop
+ style="stop-color:#eff2fb;stop-opacity:1"
+ offset="0"
+ id="stop4196" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="1"
+ id="stop4198" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3807"
+ id="linearGradient3813"
+ x1="22.061895"
+ y1="29.435204"
+ x2="31.061895"
+ y2="22.435204"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3818"
+ id="linearGradient3824"
+ x1="0.71302384"
+ y1="9.9201834"
+ x2="25.372598"
+ y2="9.9201834"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.99498,0,0,0.93019197,0.12737048,0.84724729)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="16.15625"
+ inkscape:cx="-2.621381"
+ inkscape:cy="15.308745"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:window-width="1920"
+ inkscape:window-height="1140"
+ inkscape:window-x="-4"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1"
+ inkscape:snap-to-guides="false"
+ inkscape:snap-grids="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2831"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="frame">
+ <rect
+ style="fill:url(#linearGradient4200);fill-opacity:1;stroke:#4d4d4d;stroke-width:0.80585694;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="rect3804-6"
+ width="14.49162"
+ height="23.896389"
+ x="0.55164707"
+ y="7.7034259"
+ ry="0" />
+ <rect
+ style="fill:url(#linearGradient3824);fill-opacity:1;stroke:none;display:inline"
+ id="rect4860"
+ width="24.535784"
+ height="4.1237912"
+ x="0.83681494"
+ y="8.0130262"
+ ry="0.27575642" />
+ <ellipse
+ style="fill:url(#linearGradient3813);fill-opacity:1;fill-rule:evenodd;stroke:#4b8600;stroke-width:0.66774601000000000;stroke-opacity:1;display:inline"
+ id="path2978-9"
+ cx="25.962849"
+ cy="25.718735"
+ rx="6.1450515"
+ ry="6.2331204"
+ sodipodi:cx="25.962849"
+ sodipodi:cy="25.718735"
+ sodipodi:rx="6.1450515"
+ sodipodi:ry="6.2331204"
+ transform="matrix(1.5086573,0,0,1.4865752,-17.074665,-28.421256)" />
+ <path
+ style="fill:#ffffff;fill-opacity:1;stroke:none;display:inline"
+ d="m 20.507735,2.7063312 3.655871,6.3e-6 -0.08983,5.1846495 5.132308,0 7e-6,3.435168 -5.132304,0 -10e-6,5.268202 -3.476199,-0.08354 -0.08982,-5.268202 -5.581473,2e-6 0,-3.4351691 5.581474,0 0,-5.1011031 z"
+ id="path2826-4-5"
+ sodipodi:nodetypes="ccccccccccccc"
+ inkscape:connector-curvature="0" />
+ <rect
+ ry="0.35299808"
+ y="16.616508"
+ x="4.2410698"
+ height="2.8239846"
+ width="6.4622827"
+ id="rect4854"
+ style="fill:#004455;fill-opacity:1;stroke:none;display:inline" />
+ <rect
+ ry="0.35299808"
+ y="23.425016"
+ x="4.3029656"
+ height="2.8239846"
+ width="6.4622827"
+ id="rect4864"
+ style="fill:#004455;fill-opacity:1;stroke:none;display:inline" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="plus"
+ style="display:inline" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="star"
+ style="display:inline" />
+</svg>
diff --git a/Viewer/images/add_tree.svg b/Viewer/images/add_tree.svg
new file mode 100644
index 0000000..f73d115
--- /dev/null
+++ b/Viewer/images/add_tree.svg
@@ -0,0 +1,537 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="add_tree.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3806">
+ <stop
+ style="stop-color:#e0e0e0;stop-opacity:1;"
+ offset="0"
+ id="stop3808" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop3810" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3826">
+ <stop
+ style="stop-color:#c8d0d8;stop-opacity:1;"
+ offset="0"
+ id="stop3828" />
+ <stop
+ style="stop-color:#c8d0d8;stop-opacity:0;"
+ offset="1"
+ id="stop3830" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3798">
+ <stop
+ style="stop-color:#2d2d2d;stop-opacity:1;"
+ offset="0"
+ id="stop3800" />
+ <stop
+ style="stop-color:#2d2d2d;stop-opacity:1;"
+ offset="1"
+ id="stop3802" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3608">
+ <stop
+ id="stop3610"
+ offset="0"
+ style="stop-color:#2eaf1d;stop-opacity:1;" />
+ <stop
+ id="stop3612"
+ offset="1"
+ style="stop-color:#91ff44;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3612">
+ <stop
+ style="stop-color:#616161;stop-opacity:1;"
+ offset="0"
+ id="stop3614" />
+ <stop
+ style="stop-color:#383838;stop-opacity:1;"
+ offset="1"
+ id="stop3616" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3601">
+ <stop
+ style="stop-color:#a2a2a2;stop-opacity:1;"
+ offset="0"
+ id="stop3603" />
+ <stop
+ style="stop-color:#343434;stop-opacity:1;"
+ offset="1"
+ id="stop3605" />
+ </linearGradient>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ id="perspective10" />
+ <inkscape:perspective
+ id="perspective2825"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <inkscape:perspective
+ id="perspective2841"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3601"
+ id="linearGradient3607"
+ x1="10.653805"
+ y1="3.7712457"
+ x2="24.085051"
+ y2="29.5"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.96774194,0,0,-0.96774194,0.58051457,31.158684)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3612"
+ id="linearGradient3618"
+ x1="3"
+ y1="28.806061"
+ x2="29"
+ y2="28.806061"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3612"
+ id="linearGradient3620"
+ gradientUnits="userSpaceOnUse"
+ x1="3"
+ y1="28.806061"
+ x2="29"
+ y2="28.806061"
+ gradientTransform="translate(0,-32.806061)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3608"
+ id="linearGradient3606"
+ x1="24"
+ y1="26"
+ x2="7"
+ y2="8"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.83718675,0,0,0.87310139,-36.94508,11.435241)" />
+ <linearGradient
+ gradientUnits="userSpaceOnUse"
+ y2="23.49078"
+ x2="7.2979932"
+ y1="7.6554561"
+ x1="9.0300617"
+ id="linearGradient3765"
+ xlink:href="#linearGradient3757"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3757">
+ <stop
+ id="stop3759"
+ offset="0"
+ style="stop-color:#fdfb72;stop-opacity:1;" />
+ <stop
+ id="stop3761"
+ offset="1"
+ style="stop-color:#ffb41b;stop-opacity:1;" />
+ </linearGradient>
+ <inkscape:perspective
+ id="perspective2882"
+ inkscape:persp3d-origin="16 : 10.666667 : 1"
+ inkscape:vp_z="32 : 16 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 16 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <inkscape:perspective
+ id="perspective3015"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <linearGradient
+ id="linearGradient3845">
+ <stop
+ style="stop-color:#326dc2;stop-opacity:1;"
+ offset="0"
+ id="stop3847" />
+ <stop
+ style="stop-color:#6295be;stop-opacity:1;"
+ offset="1"
+ id="stop3849" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3826"
+ id="linearGradient3832"
+ x1="1.6569907"
+ y1="24.5"
+ x2="27.343009"
+ y2="24.5"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.8,0,0,1.909091,-24.677369,-29.324952)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3798"
+ id="linearGradient3799"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.99999997,0,0,0.5,-1,15)"
+ x1="0"
+ y1="24"
+ x2="12.484"
+ y2="24" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3798-5"
+ id="linearGradient3794-8"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.125,0,0,0.5,2.5232104,-0.9458414)"
+ x1="0"
+ y1="24"
+ x2="12.484"
+ y2="24" />
+ <linearGradient
+ id="linearGradient3798-5">
+ <stop
+ style="stop-color:#cfd1d2;stop-opacity:1;"
+ offset="0"
+ id="stop3800-1" />
+ <stop
+ style="stop-color:#476476;stop-opacity:1;"
+ offset="1"
+ id="stop3802-7" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3807">
+ <stop
+ style="stop-color:#269e00;stop-opacity:1;"
+ offset="0"
+ id="stop3809" />
+ <stop
+ style="stop-color:#86e16b;stop-opacity:1"
+ offset="1"
+ id="stop3811" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3818">
+ <stop
+ style="stop-color:#267fbd;stop-opacity:1;"
+ offset="0"
+ id="stop3820" />
+ <stop
+ style="stop-color:#a5b4b8;stop-opacity:1;"
+ offset="1"
+ id="stop3822" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4194-2"
+ id="linearGradient4200-1"
+ x1="37.706196"
+ y1="3.5453706"
+ x2="2.2564189"
+ y2="25.726259"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.77976303,0,0,0.76912919,0.0689839,7.2311591)" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4194-2">
+ <stop
+ style="stop-color:#eff2fb;stop-opacity:1"
+ offset="0"
+ id="stop4196-8" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="1"
+ id="stop4198-0" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3807-0"
+ id="linearGradient3813-5"
+ x1="22.061895"
+ y1="29.435204"
+ x2="31.061895"
+ y2="22.435204"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ id="linearGradient3807-0">
+ <stop
+ style="stop-color:#3c7eb4;stop-opacity:1;"
+ offset="0"
+ id="stop3809-9" />
+ <stop
+ style="stop-color:#3f6a8b;stop-opacity:1;"
+ offset="1"
+ id="stop3811-4" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3818-9"
+ id="linearGradient3824-3"
+ x1="0.71302384"
+ y1="9.9201832"
+ x2="25.372599"
+ y2="9.9201832"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.9901649,0,0,0.93019197,0.03989419,-1.4644418)" />
+ <linearGradient
+ id="linearGradient3818-9">
+ <stop
+ style="stop-color:#7691a2;stop-opacity:1"
+ offset="0"
+ id="stop3820-9" />
+ <stop
+ style="stop-color:#a5b4b8;stop-opacity:1;"
+ offset="1"
+ id="stop3822-3" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4194-4"
+ id="linearGradient4200-4"
+ x1="37.706196"
+ y1="3.5453706"
+ x2="2.2564189"
+ y2="25.726259"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.77976303,0,0,0.76912919,0.0689839,7.2311591)" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4194-4">
+ <stop
+ style="stop-color:#eff2fb;stop-opacity:1"
+ offset="0"
+ id="stop4196-6" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="1"
+ id="stop4198-2" />
+ </linearGradient>
+ <linearGradient
+ y2="25.726259"
+ x2="2.2564189"
+ y1="3.5453706"
+ x1="37.706196"
+ gradientTransform="matrix(0.77976303,0,0,0.84174175,0.03744411,5.064678)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4643"
+ xlink:href="#linearGradient4194-4"
+ inkscape:collect="always" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3807-4"
+ id="linearGradient3813"
+ x1="22.061895"
+ y1="29.435204"
+ x2="31.061895"
+ y2="22.435204"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ id="linearGradient3807-4">
+ <stop
+ style="stop-color:#6aab3a;stop-opacity:1;"
+ offset="0"
+ id="stop3809-2" />
+ <stop
+ style="stop-color:#6bc75e;stop-opacity:1;"
+ offset="1"
+ id="stop3811-2" />
+ </linearGradient>
+ <linearGradient
+ y2="22.435204"
+ x2="31.061895"
+ y1="29.435204"
+ x1="22.061895"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4244"
+ xlink:href="#linearGradient3807-4"
+ inkscape:collect="always" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="16.84375"
+ inkscape:cx="28.196599"
+ inkscape:cy="16"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer3"
+ showgrid="true"
+ inkscape:window-width="1920"
+ inkscape:window-height="1140"
+ inkscape:window-x="-4"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1"
+ inkscape:snap-to-guides="false"
+ inkscape:snap-grids="false">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2831"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="frame" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="plus"
+ style="display:inline">
+ <rect
+ style="fill:url(#linearGradient4643);fill-opacity:1;stroke:#4d4d4d;stroke-width:0.80585694;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="rect3804-6"
+ width="24.023535"
+ height="26.152418"
+ x="0.52010727"
+ y="5.446053"
+ ry="0" />
+ <rect
+ style="fill:url(#linearGradient3824-3);fill-opacity:1;stroke:none;display:inline"
+ id="rect4860-7"
+ width="24.417046"
+ height="4.1237912"
+ x="0.74590576"
+ y="5.7013369"
+ ry="0.27575642" />
+ <path
+ style="fill:#ffffff;fill-opacity:1;stroke:none;display:inline"
+ d="m 23.096635,2.5576535 2.728417,4.5e-6 -0.06704,3.7632986 3.830298,0 6e-6,2.493432 -3.830296,0 -7e-6,3.8239464 -2.594326,-0.06064 -0.06704,-3.8239474 -4.165515,10e-7 0,-2.493431 4.165516,0 0,-3.7026566 z"
+ id="path2826-4-5-4"
+ sodipodi:nodetypes="ccccccccccccc"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:#6f7c91;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+ d="M 5.2282004,14.881262 5.1973316,27.78469"
+ id="path3025-5"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:#0c0000;fill-opacity:1;stroke:#080000;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+ d="m 5.3810098,20.586543 7.0830472,0 0,0"
+ id="path3033-1"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc" />
+ <path
+ style="fill:#000000;fill-opacity:1;stroke:#0c0000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+ d="m 5.4658603,27.240199 7.1282157,0"
+ id="path3029-5"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <rect
+ ry="0.41978842"
+ y="12.069199"
+ x="1.957211"
+ height="3.3583074"
+ width="6.4622827"
+ id="rect4854"
+ style="fill:#004455;fill-opacity:1;stroke:none;display:inline" />
+ <rect
+ style="fill:#004455;fill-opacity:1;stroke:none;display:inline"
+ id="rect4866"
+ width="6.4622827"
+ height="3.8926303"
+ x="10.02258"
+ y="25.343897"
+ ry="0.48657879" />
+ <ellipse
+ style="fill:url(#linearGradient4244);fill-opacity:1;fill-rule:evenodd;stroke:#4b8600;stroke-width:0.66774601;stroke-opacity:1;display:inline"
+ id="path2978-9"
+ cx="25.962849"
+ cy="25.718735"
+ rx="6.1450515"
+ ry="6.2331204"
+ sodipodi:cx="25.962849"
+ sodipodi:cy="25.718735"
+ sodipodi:rx="6.1450515"
+ sodipodi:ry="6.2331204"
+ transform="matrix(1.5086573,0,0,1.4865752,-17.119192,-28.252424)" />
+ <path
+ style="fill:#ffffff;fill-opacity:1;stroke:none;display:inline"
+ d="m 20.463207,2.8751626 3.655872,6.3e-6 -0.08983,5.1846495 5.132308,0 7e-6,3.4351686 -5.132304,0 -10e-6,5.268202 -3.4762,-0.08354 -0.08982,-5.268202 -5.581473,2e-6 0,-3.4351697 5.581474,0 0,-5.1011031 z"
+ id="path2826-4-5"
+ sodipodi:nodetypes="ccccccccccccc"
+ inkscape:connector-curvature="0" />
+ <rect
+ style="fill:#004455;fill-opacity:1;stroke:none;display:inline"
+ id="rect4858"
+ width="6.4622827"
+ height="3.5364151"
+ x="9.903842"
+ y="18.721071"
+ ry="0.44205189" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="star"
+ style="display:inline" />
+</svg>
diff --git a/Viewer/images/arrow_down.svg b/Viewer/images/arrow_down.svg
new file mode 100644
index 0000000..b096b9e
--- /dev/null
+++ b/Viewer/images/arrow_down.svg
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.47 r22583"
+ sodipodi:docname="arrow_down.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3601">
+ <stop
+ style="stop-color:#a2a2a2;stop-opacity:1;"
+ offset="0"
+ id="stop3603" />
+ <stop
+ style="stop-color:#343434;stop-opacity:1;"
+ offset="1"
+ id="stop3605" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3601"
+ id="linearGradient3607"
+ x1="10.653805"
+ y1="3.7712457"
+ x2="24.085051"
+ y2="29.5"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.96774194,0,0,0.96774194,0.58051457,1.1586837)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="15.46875"
+ inkscape:cx="3.9111108"
+ inkscape:cy="16.354555"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer3"
+ showgrid="true"
+ inkscape:window-width="1280"
+ inkscape:window-height="740"
+ inkscape:window-x="-4"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1"
+ inkscape:snap-to-guides="false"
+ inkscape:snap-grids="false">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2831"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="arrow"
+ style="display:inline">
+ <path
+ style="fill:url(#linearGradient3607);fill-opacity:1;stroke:#2e2e2e;stroke-width:0.96774191px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 12.193418,3.0941677 0,14.5161293 -6.7741938,-4.83871 -3.8709677,4.83871 14.5161295,11.612903 14.516129,-11.612903 -3.870968,-4.83871 -6.774193,4.83871 0,-14.5161293 -7.741936,0 z"
+ id="path2850"
+ sodipodi:nodetypes="cccccccccc" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="bar" />
+</svg>
diff --git a/Viewer/images/arrow_up.svg b/Viewer/images/arrow_up.svg
new file mode 100644
index 0000000..7eed43e
--- /dev/null
+++ b/Viewer/images/arrow_up.svg
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.47 r22583"
+ sodipodi:docname="arrow_up.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3601">
+ <stop
+ style="stop-color:#a2a2a2;stop-opacity:1;"
+ offset="0"
+ id="stop3603" />
+ <stop
+ style="stop-color:#343434;stop-opacity:1;"
+ offset="1"
+ id="stop3605" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3601"
+ id="linearGradient3607"
+ x1="10.653805"
+ y1="3.7712457"
+ x2="24.085051"
+ y2="29.5"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.96774194,0,0,-0.96774194,0.58051457,31.158684)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="15.46875"
+ inkscape:cx="3.9111108"
+ inkscape:cy="16.354555"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer3"
+ showgrid="true"
+ inkscape:window-width="1280"
+ inkscape:window-height="740"
+ inkscape:window-x="-4"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1"
+ inkscape:snap-to-guides="false"
+ inkscape:snap-grids="false">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2831"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="arrow"
+ style="display:inline">
+ <path
+ style="fill:url(#linearGradient3607);fill-opacity:1;stroke:#2e2e2e;stroke-width:0.96774191px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 12.193418,29.2232 0,-14.516129 -6.7741938,4.83871 -3.8709677,-4.83871 14.5161295,-11.6129033 14.516129,11.6129033 -3.870968,4.83871 -6.774193,-4.83871 0,14.516129 -7.741936,0 z"
+ id="path2850"
+ sodipodi:nodetypes="cccccccccc" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="bar" />
+</svg>
diff --git a/Viewer/images/attribute.svg b/Viewer/images/attribute.svg
new file mode 100644
index 0000000..3155d5a
--- /dev/null
+++ b/Viewer/images/attribute.svg
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="attribute.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#519aed;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#e9dddd;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f1f3fb;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3614">
+ <stop
+ style="stop-color:#2c71d9;stop-opacity:1;"
+ offset="0"
+ id="stop3616" />
+ <stop
+ style="stop-color:#ececec;stop-opacity:1;"
+ offset="1"
+ id="stop3618" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3602">
+ <stop
+ style="stop-color:#f5f5f5;stop-opacity:1;"
+ offset="0"
+ id="stop3604" />
+ <stop
+ style="stop-color:#141bc6;stop-opacity:1;"
+ offset="1"
+ id="stop3606" />
+ </linearGradient>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="-4.3575197"
+ inkscape:cy="15.393958"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer3"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1920"
+ inkscape:window-height="1140"
+ inkscape:window-x="-4"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="circle"
+ style="display:inline">
+ <path
+ sodipodi:type="arc"
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#d4e2e7;stroke-width:1.52139318000000001;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path3811"
+ sodipodi:cx="11.306666"
+ sodipodi:cy="19.946667"
+ sodipodi:rx="14.506667"
+ sodipodi:ry="14.4"
+ d="m 25.813334,19.946667 a 14.506667,14.4 0 1 1 -29.0133348,0 14.506667,14.4 0 1 1 29.0133348,0 z"
+ transform="matrix(0.98230695,0,0,0.98958336,4.5833822,-3.5888898)" />
+ <text
+ xml:space="preserve"
+ style="font-size:32px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#d5e5ff;fill-opacity:1;stroke:none;font-family:Courier New KOI-8;-inkscape-font-specification:Courier New KOI-8"
+ x="6.7733331"
+ y="24.213333"
+ id="text3815"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3817"
+ x="6.7733331"
+ y="24.213333">a</tspan></text>
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <text
+ xml:space="preserve"
+ style="font-size:20;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Calibri;-inkscape-font-specification:Calibri"
+ x="3.8399999"
+ y="21.973333"
+ id="text3783"><tspan
+ sodipodi:role="line"
+ id="tspan3785"
+ x="3.8399999"
+ y="21.973333" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="7.2533331"
+ y="15.146667"
+ id="text3787"><tspan
+ sodipodi:role="line"
+ id="tspan3789"
+ x="7.2533331"
+ y="15.146667" /></text>
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="top" />
+</svg>
diff --git a/Viewer/images/bookmark.svg b/Viewer/images/bookmark.svg
new file mode 100644
index 0000000..e9122da
--- /dev/null
+++ b/Viewer/images/bookmark.svg
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.47 r22583"
+ sodipodi:docname="bookmark.svg">
+ <defs
+ id="defs4">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 16 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="32 : 16 : 1"
+ inkscape:persp3d-origin="16 : 10.666667 : 1"
+ id="perspective2882" />
+ <linearGradient
+ id="linearGradient3757">
+ <stop
+ style="stop-color:#f5ef7a;stop-opacity:1;"
+ offset="0"
+ id="stop3759" />
+ <stop
+ style="stop-color:#ffb41b;stop-opacity:1;"
+ offset="1"
+ id="stop3761" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3757"
+ id="linearGradient3765"
+ x1="9.0300617"
+ y1="7.6554561"
+ x2="7.2979932"
+ y2="23.49078"
+ gradientUnits="userSpaceOnUse" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="12.46875"
+ inkscape:cx="-4.4680284"
+ inkscape:cy="16"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:window-width="1600"
+ inkscape:window-height="925"
+ inkscape:window-x="2134"
+ inkscape:window-y="20"
+ inkscape:window-maximized="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2985"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-1020.3622)">
+ <path
+ sodipodi:type="star"
+ style="fill:url(#linearGradient3765);fill-opacity:1;fill-rule:evenodd;stroke:#764f25;stroke-width:0.94637238999999995;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="path2987"
+ sodipodi:sides="5"
+ sodipodi:cx="9"
+ sodipodi:cy="12"
+ sodipodi:r1="15"
+ sodipodi:r2="7.6500001"
+ sodipodi:arg1="0.64350111"
+ sodipodi:arg2="1.2718196"
+ inkscape:flatsided="false"
+ inkscape:rounded="0.04"
+ inkscape:randomized="-0.001"
+ d="M 20.997045,20.992528 C 20.75931,21.308892 11.617197,19.181414 11.238826,19.297493 10.860454,19.413572 4.5202372,26.329466 4.1459842,26.201371 3.7717312,26.073276 2.9704721,16.715905 2.7432329,16.391868 2.5159936,16.067831 -6.016519,12.168242 -6.0107214,11.772479 c 0.0058,-0.395763 8.6627974,-4.0484273 8.8998098,-4.3653101 0.2370125,-0.3168827 1.3050227,-9.6358293 1.6832674,-9.7523143 0.3782446,-0.116485 6.5253462,6.9706314 6.8997352,7.0989866 0.374389,0.1283552 9.578158,-1.722 [...]
+ transform="matrix(0.99363412,0.30409271,-0.29423698,1.0269168,10.313398,1022.4196)"
+ inkscape:transform-center-x="0.053227332"
+ inkscape:transform-center-y="-1.4817371" />
+ </g>
+</svg>
diff --git a/Viewer/images/case_sensitive.svg b/Viewer/images/case_sensitive.svg
new file mode 100644
index 0000000..6490ce9
--- /dev/null
+++ b/Viewer/images/case_sensitive.svg
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="case_sensitive.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#519aed;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#e9dddd;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f1f3fb;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3614">
+ <stop
+ style="stop-color:#2c71d9;stop-opacity:1;"
+ offset="0"
+ id="stop3616" />
+ <stop
+ style="stop-color:#ececec;stop-opacity:1;"
+ offset="1"
+ id="stop3618" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3602">
+ <stop
+ style="stop-color:#f5f5f5;stop-opacity:1;"
+ offset="0"
+ id="stop3604" />
+ <stop
+ style="stop-color:#141bc6;stop-opacity:1;"
+ offset="1"
+ id="stop3606" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3614"
+ id="linearGradient3691"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="12.89746"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3602"
+ id="linearGradient3693"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="2.2337441"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3728"
+ id="linearGradient3710"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-31.566354,35.860667)"
+ x1="15.413333"
+ y1="3.4795053"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3756"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-31.566354,35.860667)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="23.252936"
+ inkscape:cy="15.51908"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1408"
+ inkscape:window-height="1093"
+ inkscape:window-x="370"
+ inkscape:window-y="39"
+ inkscape:window-maximized="0"
+ showguides="true"
+ inkscape:guide-bbox="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="bg"
+ style="display:inline" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <text
+ xml:space="preserve"
+ style="font-size:20px;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Calibri;-inkscape-font-specification:Calibri"
+ x="3.8399999"
+ y="21.973333"
+ id="text3783"><tspan
+ sodipodi:role="line"
+ id="tspan3785"
+ x="3.8399999"
+ y="21.973333" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="7.2533331"
+ y="15.146667"
+ id="text3787"><tspan
+ sodipodi:role="line"
+ id="tspan3789"
+ x="7.2533331"
+ y="15.146667" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#003380;fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:Monospace"
+ x="2.0376577"
+ y="23.859152"
+ id="text3791"
+ transform="scale(1.0238296,0.97672504)"><tspan
+ sodipodi:role="line"
+ id="tspan3793"
+ x="2.0376577"
+ y="23.859152"
+ style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#003380;font-family:Monospace;-inkscape-font-specification:Monospace">Aa</tspan></text>
+ </g>
+</svg>
diff --git a/Viewer/images/chain.svg b/Viewer/images/chain.svg
new file mode 100644
index 0000000..34bfaae
--- /dev/null
+++ b/Viewer/images/chain.svg
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="chain.svg">
+ <defs
+ id="defs4" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="15.962652"
+ inkscape:cx="16"
+ inkscape:cy="16.208218"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:snap-to-guides="false"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1920"
+ inkscape:window-height="1140"
+ inkscape:window-x="-4"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2985"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-1020.3622)">
+ <path
+ style="fill:#006680;stroke:none"
+ d="m 14.238879,1035.5941 c -2.149582,2.0051 -5.3129902,4.9843 -6.2730801,6.4085 -0.8461756,1.2551 1.6972835,3.8567 2.9714591,2.6557 1.053821,-0.9933 3.081515,-2.7712 3.081515,-2.7712 0,0 1.344582,0.5074 2.047554,0.6043 0.650939,0.09 1.969417,-0.027 1.969417,-0.027 0,0 -3.158543,4.3507 -5.447676,5.3114 -5.2387886,2.2619 -9.646468,-2.4582 -7.7037827,-7.3321 0.6407728,-1.4569 5.6121857,-6.2203 6.9884327,-7.4478 1.050497,-0.9369 3.64451,-1.1504 4.952432,-0.6928 0.505166,0.1768 2.51295 [...]
+ id="path3772"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="csscscccsscc" />
+ <path
+ sodipodi:nodetypes="csscscccsscc"
+ inkscape:connector-curvature="0"
+ id="path3774"
+ d="m 18.121043,1037.5619 c 2.149565,-2.0052 5.313042,-4.9843 6.273108,-6.4084 0.84614,-1.2552 -1.697289,-3.8569 -2.971463,-2.6559 -1.05379,0.9934 -3.081524,2.7713 -3.081524,2.7713 0,0 -1.344619,-0.5075 -2.047585,-0.6043 -0.650877,-0.089 -1.969411,0.027 -1.969411,0.027 0,0 3.158558,-4.3507 5.447697,-5.3116 5.238818,-2.2619 9.646516,2.4583 7.703808,7.3323 -0.640775,1.4566 -5.612215,6.2203 -6.988457,7.4476 -1.050452,0.9369 -3.644475,1.1505 -4.95238,0.6927 -0.505242,-0.1766 -2.513036, [...]
+ style="fill:#006680;stroke:none" />
+ </g>
+</svg>
diff --git a/Viewer/images/clear_left.svg b/Viewer/images/clear_left.svg
new file mode 100644
index 0000000..7297061
--- /dev/null
+++ b/Viewer/images/clear_left.svg
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.47 r22583"
+ sodipodi:docname="clear_left.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3606">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop3608" />
+ <stop
+ style="stop-color:#cdc5c5;stop-opacity:1;"
+ offset="1"
+ id="stop3610" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3606"
+ id="linearGradient3612"
+ x1="20"
+ y1="28"
+ x2="20"
+ y2="5"
+ gradientUnits="userSpaceOnUse" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="15.46875"
+ inkscape:cx="13.436084"
+ inkscape:cy="15.888631"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer3"
+ showgrid="true"
+ inkscape:window-width="1127"
+ inkscape:window-height="732"
+ inkscape:window-x="5"
+ inkscape:window-y="-14"
+ inkscape:window-maximized="0"
+ inkscape:snap-to-guides="false"
+ inkscape:snap-grids="false">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2831"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="arrow"
+ style="display:inline">
+ <path
+ style="fill:url(#linearGradient3612);stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1"
+ d="M 29,7 29,25 10,25 2.7797985,15.385859 10,7 29,7 z"
+ id="path2836"
+ sodipodi:nodetypes="cccccc" />
+ <rect
+ style="fill:#ffffff;fill-opacity:1;stroke:none"
+ id="rect3616"
+ width="2.9999995"
+ height="13.820202"
+ x="-0.13554154"
+ y="16.856846"
+ ry="1.0476104"
+ transform="matrix(0.70238772,-0.71179456,0.71179456,0.70238772,0,0)" />
+ <rect
+ ry="1.0476104"
+ y="-5.6178875"
+ x="-25.12775"
+ height="13.820202"
+ width="2.9999995"
+ id="rect3618"
+ style="fill:#ffffff;fill-opacity:1;stroke:none"
+ transform="matrix(-0.71179456,-0.70238772,0.70238772,-0.71179456,0,0)" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="bar" />
+</svg>
diff --git a/Viewer/images/close.svg b/Viewer/images/close.svg
new file mode 100644
index 0000000..87dfebd
--- /dev/null
+++ b/Viewer/images/close.svg
@@ -0,0 +1,242 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.47 r22583"
+ sodipodi:docname="close.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3795">
+ <stop
+ style="stop-color:#c53143;stop-opacity:1;"
+ offset="0"
+ id="stop3797" />
+ <stop
+ style="stop-color:#b8382b;stop-opacity:0;"
+ offset="1"
+ id="stop3799" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#fa0c1e;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#d9afb1;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3614">
+ <stop
+ style="stop-color:#e8220f;stop-opacity:1;"
+ offset="0"
+ id="stop3616" />
+ <stop
+ style="stop-color:#ececec;stop-opacity:1;"
+ offset="1"
+ id="stop3618" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3602">
+ <stop
+ style="stop-color:#932626;stop-opacity:1;"
+ offset="0"
+ id="stop3604" />
+ <stop
+ style="stop-color:#bc4343;stop-opacity:1;"
+ offset="1"
+ id="stop3606" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3614"
+ id="linearGradient3691"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="12.89746"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3602"
+ id="linearGradient3693"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="2.2337441"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3728"
+ id="linearGradient3710"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-0.7930209,35.114)"
+ x1="15.413333"
+ y1="3.4795053"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3795"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-0.7930209,35.114)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="12.549147"
+ inkscape:cy="15.367291"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer3"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1005"
+ inkscape:window-height="751"
+ inkscape:window-x="214"
+ inkscape:window-y="-17"
+ inkscape:window-maximized="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="circle"
+ style="display:inline">
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#linearGradient3691);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3693);stroke-width:0.90856528;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path2820"
+ sodipodi:cx="15.413333"
+ sodipodi:cy="16.559999"
+ sodipodi:rx="13.76"
+ sodipodi:ry="12.613334"
+ d="m 29.173333,16.559999 a 13.76,12.613334 0 1 1 -27.5200003,0 13.76,12.613334 0 1 1 27.5200003,0 z"
+ transform="matrix(1.0537791,0,0,-1.1495772,-0.30224808,35.097001)" />
+ <path
+ style="fill:url(#linearGradient3710);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3720);stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ d="M 28.894346,9.3702377 C 27.010842,13.07042 22.728069,16.870583 17.080503,19.355951 11.585061,21.774374 6.0764534,22.392799 2.1004164,21.400807 c 2.2087693,5.337492 7.4536969,9.09961 13.5842156,9.09961 8.12285,0 14.707722,-6.591694 14.707722,-14.722963 0,-2.303016 -0.556212,-4.465993 -1.498008,-6.4072163 z"
+ id="path3695" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <text
+ xml:space="preserve"
+ style="font-size:20px;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Calibri;-inkscape-font-specification:Calibri"
+ x="3.8399999"
+ y="21.973333"
+ id="text3783"><tspan
+ sodipodi:role="line"
+ id="tspan3785"
+ x="3.8399999"
+ y="21.973333" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="7.2533331"
+ y="15.146667"
+ id="text3787"><tspan
+ sodipodi:role="line"
+ id="tspan3789"
+ x="7.2533331"
+ y="15.146667" /></text>
+ <rect
+ style="fill:#ffffff;fill-opacity:1;stroke:#fffcfc;stroke-width:3.33834791;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="rect3809"
+ width="1.4149849"
+ height="17.969641"
+ x="-0.80126238"
+ y="13.517637"
+ ry="0.11241483"
+ transform="matrix(0.69887353,-0.71524526,0.71524526,0.69887353,0,0)" />
+ <rect
+ ry="0.11177491"
+ y="-9.1074448"
+ x="-23.50547"
+ height="17.86735"
+ width="1.4193591"
+ id="rect3811"
+ style="fill:#ffffff;fill-opacity:1;stroke:#fffcfc;stroke-width:3.33397388;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ transform="matrix(-0.71524526,-0.69887353,0.69887353,-0.71524526,0,0)" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="top"
+ style="display:inline">
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#b72f3d;stroke-width:1.24076998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path3786"
+ sodipodi:cx="16.213333"
+ sodipodi:cy="17.973333"
+ sodipodi:rx="13.973333"
+ sodipodi:ry="13.706667"
+ d="m 30.186666,17.973333 a 13.973333,13.706667 0 1 1 -27.9466662,0 13.973333,13.706667 0 1 1 27.9466662,0 z"
+ transform="matrix(1.0376908,0,0,1.0578794,-0.937761,-2.9536141)" />
+ </g>
+</svg>
diff --git a/Viewer/images/colour.svg b/Viewer/images/colour.svg
new file mode 100644
index 0000000..07039e0
--- /dev/null
+++ b/Viewer/images/colour.svg
@@ -0,0 +1,283 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="64"
+ height="64"
+ viewBox="0 0 63.999999 63.999999"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.91 r13725"
+ sodipodi:docname="colour.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4435">
+ <stop
+ style="stop-color:#163d58;stop-opacity:1"
+ offset="0"
+ id="stop4437" />
+ <stop
+ style="stop-color:#0970c9;stop-opacity:1"
+ offset="0.60812658"
+ id="stop4439" />
+ <stop
+ style="stop-color:#055291;stop-opacity:1"
+ offset="1"
+ id="stop4441" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient4425"
+ inkscape:collect="always">
+ <stop
+ id="stop4427"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1" />
+ <stop
+ style="stop-color:#8ec4f1;stop-opacity:1"
+ offset="0.16729185"
+ id="stop4429" />
+ <stop
+ id="stop4431"
+ offset="0.50179923"
+ style="stop-color:#0972c9;stop-opacity:1" />
+ <stop
+ id="stop4433"
+ offset="1"
+ style="stop-color:#055291;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4409">
+ <stop
+ style="stop-color:#bb740a;stop-opacity:1"
+ offset="0"
+ id="stop4411" />
+ <stop
+ style="stop-color:#edbe46;stop-opacity:1"
+ offset="0.60812658"
+ id="stop4413" />
+ <stop
+ style="stop-color:#f49200;stop-opacity:1"
+ offset="1"
+ id="stop4415" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient4397"
+ inkscape:collect="always">
+ <stop
+ id="stop4399"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1" />
+ <stop
+ style="stop-color:#f9f464;stop-opacity:1"
+ offset="0.16729185"
+ id="stop4401" />
+ <stop
+ id="stop4403"
+ offset="0.50179923"
+ style="stop-color:#edbe46;stop-opacity:1" />
+ <stop
+ id="stop4405"
+ offset="1"
+ style="stop-color:#f49200;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient4379"
+ inkscape:collect="always">
+ <stop
+ id="stop4381"
+ offset="0"
+ style="stop-color:#700202;stop-opacity:1" />
+ <stop
+ id="stop4385"
+ offset="0.60812658"
+ style="stop-color:#f11d1c;stop-opacity:1" />
+ <stop
+ id="stop4387"
+ offset="1"
+ style="stop-color:#940202;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4351">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="0"
+ id="stop4145" />
+ <stop
+ id="stop4359"
+ offset="0.16729185"
+ style="stop-color:#fababa;stop-opacity:1" />
+ <stop
+ style="stop-color:#f11d1c;stop-opacity:1"
+ offset="0.50179923"
+ id="stop4363" />
+ <stop
+ style="stop-color:#940202;stop-opacity:1"
+ offset="1"
+ id="stop4147" />
+ </linearGradient>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4351"
+ id="radialGradient4370"
+ cx="4.1658859"
+ cy="1025.1779"
+ fx="4.1658859"
+ fy="1025.1779"
+ r="14.00876"
+ gradientTransform="matrix(-2.0497483,2.319683,-1.7334567,-2.1825464,1082.3082,2967.3248)"
+ gradientUnits="userSpaceOnUse" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4379"
+ id="radialGradient4377"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-2.098954,2.5588463,-2.2025108,-2.5532757,1563.2591,3345.0544)"
+ cx="3.606549"
+ cy="1025.6432"
+ fx="3.606549"
+ fy="1025.6432"
+ r="14.00876" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4409"
+ id="radialGradient4393"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-2.098954,2.5588463,-2.2025108,-2.5532757,1579.7068,3327.5932)"
+ cx="3.606549"
+ cy="1025.6432"
+ fx="3.606549"
+ fy="1025.6432"
+ r="14.00876" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4397"
+ id="radialGradient4395"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-2.0497483,2.319683,-1.7334567,-2.1825464,1098.7559,2949.8636)"
+ cx="4.1658859"
+ cy="1025.1779"
+ fx="4.1658859"
+ fy="1025.1779"
+ r="14.00876" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4435"
+ id="radialGradient4421"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-2.098954,2.5588463,-2.2025108,-2.5532757,1588.0569,3352.4069)"
+ cx="3.606549"
+ cy="1025.6432"
+ fx="3.606549"
+ fy="1025.6432"
+ r="14.00876" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4425"
+ id="radialGradient4423"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-2.0644821,2.3059927,-1.7130272,-2.182245,1086.2235,2974.4254)"
+ cx="4.1658859"
+ cy="1025.1779"
+ fx="4.1658859"
+ fy="1025.1779"
+ r="14.00876" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="8.421875"
+ inkscape:cx="13.844939"
+ inkscape:cy="26.122449"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:window-width="1920"
+ inkscape:window-height="1005"
+ inkscape:window-x="-9"
+ inkscape:window-y="-9"
+ inkscape:window-maximized="1"
+ units="px">
+ <inkscape:grid
+ type="xygrid"
+ id="grid4136" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-988.3622)">
+ <circle
+ transform="matrix(0.71765571,-0.69639807,0.69639807,0.71765571,0,0)"
+ style="fill:url(#radialGradient4393);fill-opacity:1;stroke:none;stroke-width:0.82663572;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="circle4389"
+ cx="-687.51428"
+ cy="738.48322"
+ r="16.5" />
+ <ellipse
+ transform="matrix(0.71765571,-0.69639807,0.69639807,0.71765571,0,0)"
+ ry="15.791519"
+ rx="15.253246"
+ cy="738.83942"
+ cx="-687.4549"
+ id="ellipse4391"
+ style="fill:url(#radialGradient4395);fill-opacity:1;stroke:none;stroke-width:0.82663572;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <circle
+ transform="matrix(0.71765571,-0.69639807,0.69639807,0.71765571,0,0)"
+ style="fill:url(#radialGradient4421);fill-opacity:1;stroke:none;stroke-width:0.82663572;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="circle4417"
+ cx="-679.16412"
+ cy="763.29694"
+ r="16.5" />
+ <ellipse
+ transform="matrix(0.71765571,-0.69639807,0.69639807,0.71765571,0,0)"
+ ry="15.791519"
+ rx="15.253246"
+ cy="763.65314"
+ cx="-679.10474"
+ id="ellipse4419"
+ style="fill:url(#radialGradient4423);fill-opacity:1;stroke:none;stroke-width:0.82663572;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <circle
+ r="16.5"
+ cy="755.9444"
+ cx="-703.96191"
+ id="circle4375"
+ style="fill:url(#radialGradient4377);fill-opacity:1;stroke:none;stroke-width:0.82663572;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ transform="matrix(0.71765571,-0.69639807,0.69639807,0.71765571,0,0)" />
+ <ellipse
+ style="fill:url(#radialGradient4370);fill-opacity:1;stroke:none;stroke-width:0.82663572;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="circle4341"
+ cx="-703.90253"
+ cy="756.3006"
+ rx="15.253246"
+ ry="15.791519"
+ transform="matrix(0.71765571,-0.69639807,0.69639807,0.71765571,0,0)" />
+ </g>
+</svg>
diff --git a/Viewer/images/configure.svg b/Viewer/images/configure.svg
new file mode 100644
index 0000000..e1a3bf3
--- /dev/null
+++ b/Viewer/images/configure.svg
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.0"
+ width="32"
+ height="32"
+ id="svg4895"
+ sodipodi:version="0.32"
+ inkscape:version="0.47 r22583"
+ sodipodi:docname="configure.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="/var/tmp/cgr/PERFORCE/metview_4/src/images/new/profile_manage.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ style="display:inline">
+ <sodipodi:namedview
+ inkscape:window-height="1070"
+ inkscape:window-width="1339"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ guidetolerance="10.0"
+ gridtolerance="4.5"
+ objecttolerance="10.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base"
+ inkscape:zoom="25.28125"
+ inkscape:cx="16"
+ inkscape:cy="16"
+ inkscape:window-x="2458"
+ inkscape:window-y="101"
+ inkscape:current-layer="layer1"
+ width="32px"
+ height="32px"
+ showgrid="true"
+ inkscape:window-maximized="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid25877"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata3436">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs3362">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 16 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="32 : 16 : 1"
+ inkscape:persp3d-origin="16 : 10.666667 : 1"
+ id="perspective2941" />
+ <!-- -->
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3685-4"
+ id="linearGradient3763"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0001757,0,0,1.0001944,0.74496639,-1.080628)"
+ x1="12"
+ y1="28"
+ x2="7"
+ y2="23" />
+ <linearGradient
+ id="linearGradient3685-4">
+ <stop
+ id="stop3687-6"
+ offset="0"
+ style="stop-color:#c78e5b;stop-opacity:1;" />
+ <stop
+ id="stop3689-9"
+ offset="1"
+ style="stop-color:#cf7d3e;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3675-2"
+ id="linearGradient3765"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0001759,0,0,1.0001946,0.74496691,-0.78037688)"
+ x1="-0.31687203"
+ y1="24.091682"
+ x2="15.869606"
+ y2="24.091682" />
+ <linearGradient
+ id="linearGradient3675-2">
+ <stop
+ id="stop3677-2"
+ offset="0"
+ style="stop-color:#e6bc10;stop-opacity:1;" />
+ <stop
+ id="stop3679-4"
+ offset="1"
+ style="stop-color:#dbe683;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3665-7">
+ <stop
+ id="stop3667-7"
+ offset="0"
+ style="stop-color:#b7b7b7;stop-opacity:1;" />
+ <stop
+ id="stop3669-5"
+ offset="1"
+ style="stop-color:#f1f1f1;stop-opacity:0.99215686;" />
+ </linearGradient>
+ <linearGradient
+ y2="15.711069"
+ x2="24.332083"
+ y1="3.2495306"
+ x1="8.3320827"
+ gradientTransform="matrix(1.0001759,0,0,1.0001946,0.74496691,-0.78037688)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3914"
+ xlink:href="#linearGradient3665-7"
+ inkscape:collect="always" />
+ </defs>
+ <g
+ inkscape:groupmode="layer"
+ id="layer5"
+ inkscape:label="config"
+ style="display:inline" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="spanner">
+ <path
+ sodipodi:nodetypes="casaacsascaaca"
+ id="path2891"
+ d="M 23.749009,10.221763 C 22.585888,10.103352 21.383966,8.9410984 21.22886,7.7822583 21.097175,6.7981935 21.496505,6.3104209 22.748842,5.2207875 24.001159,4.1311753 25.377728,3.2448739 24.749191,2.2201997 23.26421,-0.20069559 18.359173,1.2771432 16.28804,3.2203978 14.211767,5.168476 14.747438,11.621658 14.747438,11.621658 L 2.0453827,24.224479 c -1.06790401,1.059565 0.035818,3.363169 1.1615552,4.36108 1.1434739,1.013638 3.4568786,1.718519 4.5392626,0.639893 L 20.080453,16.934144 [...]
+ style="fill:url(#linearGradient3914);fill-opacity:1;stroke:#2f2f2f;stroke-width:0.99999875px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline" />
+ <path
+ sodipodi:nodetypes="ccsasc"
+ id="path3673"
+ d="m 9.7465533,15.79319 6.3707227,6.064979 -8.3710755,8.367487 c -1.4631079,1.462478 -4.7383953,0.05653 -6.001058,-1.581921 -1.00486417,-1.304093 -1.17069324,-3.781517 0,-4.939047 L 9.7465533,15.79319 z"
+ style="fill:url(#linearGradient3765);fill-opacity:1;stroke:#9f7220;stroke-width:0.99999875000000005px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline" />
+ <path
+ sodipodi:nodetypes="cccaac"
+ id="path3683"
+ d="m 12.747082,19.92344 2.000348,1.700146 -8.0014087,8.301791 c 0,0 -1.6197056,0.08989 -2.0003505,-0.480385 -0.4011723,-0.601154 0.00703,-1.500433 0.3415224,-2.141127 1.6406915,-3.143228 7.6598888,-7.380425 7.6598888,-7.380425 z"
+ style="fill:url(#linearGradient3763);fill-opacity:1;stroke:none;display:inline" />
+ <path
+ sodipodi:nodetypes="ccaaccaacaaccc"
+ id="path3731"
+ d="M 15.548048,20.360225 20,16 c 0,0 5.715587,0.316106 7.720907,-1.359499 C 29.258484,13.355732 29.924009,10.999776 29.798821,9 29.751911,8.2506444 29.445056,7.155524 28.76267,7 27.460284,8.151868 26.497,9.8929691 25,11 23.83512,11.290913 22.427413,10.808297 21.539715,9.9998089 20.745078,9.2761228 20.198252,8.0618699 20.359394,6.9992226 20.650274,5.0810275 24.798463,4.17522 24,2.4579961 23.643649,1.6915805 21.995265,1.8193843 20.999291,1.9982499 19.26857,2.3090677 17.358203,3.0945 [...]
+ style="fill:none;stroke:#7a8ca4;stroke-width:0.90000027;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" />
+ </g>
+</svg>
diff --git a/Viewer/images/directory_arrow.svg b/Viewer/images/directory_arrow.svg
new file mode 100644
index 0000000..5d5eea5
--- /dev/null
+++ b/Viewer/images/directory_arrow.svg
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.2 r9819"
+ sodipodi:docname="directory_arrow.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3624">
+ <stop
+ style="stop-color:#b2b2b2;stop-opacity:1;"
+ offset="0"
+ id="stop3626" />
+ <stop
+ style="stop-color:#515151;stop-opacity:1;"
+ offset="1"
+ id="stop3628" />
+ </linearGradient>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="15.46875"
+ inkscape:cx="-6.1737377"
+ inkscape:cy="16.354555"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer3"
+ showgrid="true"
+ inkscape:window-width="1881"
+ inkscape:window-height="1026"
+ inkscape:window-x="-8"
+ inkscape:window-y="-8"
+ inkscape:window-maximized="1"
+ inkscape:snap-to-guides="false"
+ inkscape:snap-grids="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2831"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="arrow"
+ style="display:inline">
+ <path
+ style="fill:#002255;fill-opacity:1;stroke:none"
+ d="M 10,24 22,16 10,8 z"
+ id="path3622"
+ sodipodi:nodetypes="cccc"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="bar" />
+</svg>
diff --git a/Viewer/images/dock_close.svg b/Viewer/images/dock_close.svg
new file mode 100644
index 0000000..a7c464d
--- /dev/null
+++ b/Viewer/images/dock_close.svg
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="dock_close.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3795">
+ <stop
+ style="stop-color:#c53143;stop-opacity:1;"
+ offset="0"
+ id="stop3797" />
+ <stop
+ style="stop-color:#b8382b;stop-opacity:0;"
+ offset="1"
+ id="stop3799" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#fa0c1e;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#d9afb1;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3614">
+ <stop
+ style="stop-color:#e8220f;stop-opacity:1;"
+ offset="0"
+ id="stop3616" />
+ <stop
+ style="stop-color:#ececec;stop-opacity:1;"
+ offset="1"
+ id="stop3618" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3602">
+ <stop
+ style="stop-color:#932626;stop-opacity:1;"
+ offset="0"
+ id="stop3604" />
+ <stop
+ style="stop-color:#bc4343;stop-opacity:1;"
+ offset="1"
+ id="stop3606" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3614"
+ id="linearGradient3691"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="12.89746"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3602"
+ id="linearGradient3693"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="2.2337441"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3728"
+ id="linearGradient3710"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-0.7930209,35.114)"
+ x1="15.413333"
+ y1="3.4795053"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3795"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-0.7930209,35.114)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="-0.884964"
+ inkscape:cy="15.447291"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1760"
+ inkscape:window-height="1056"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <text
+ xml:space="preserve"
+ style="font-size:20px;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Calibri;-inkscape-font-specification:Calibri"
+ x="3.8399999"
+ y="21.973333"
+ id="text3783"><tspan
+ sodipodi:role="line"
+ id="tspan3785"
+ x="3.8399999"
+ y="21.973333" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="7.2533331"
+ y="15.146667"
+ id="text3787"><tspan
+ sodipodi:role="line"
+ id="tspan3789"
+ x="7.2533331"
+ y="15.146667" /></text>
+ <rect
+ style="opacity:0;fill:#800000;fill-opacity:1;fill-rule:evenodd;stroke:#904a3d;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="rect3010"
+ width="4.0766878"
+ height="7.3514304"
+ x="17.487217"
+ y="12.575329"
+ ry="0.16140816" />
+ <path
+ style="fill:none;stroke:#f2f2f2;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="M 8.1494143,25.143057 C 23.907706,8.5869498 24.010586,8.3502757 24.010586,8.3502757"
+ id="path3774"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path3778"
+ d="M 24.010586,25.143057 C 8.252294,8.5869498 8.1494143,8.3502757 8.1494143,8.3502757"
+ style="fill:#1a1a1a;stroke:#f2f2f2;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+ </g>
+</svg>
diff --git a/Viewer/images/dock_config.svg b/Viewer/images/dock_config.svg
new file mode 100644
index 0000000..b490a04
--- /dev/null
+++ b/Viewer/images/dock_config.svg
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="dock_config.svg">
+ <defs
+ id="defs15">
+ <linearGradient
+ id="linearGradient3762">
+ <stop
+ style="stop-color:#e4ca38;stop-opacity:1;"
+ offset="0"
+ id="stop3764" />
+ <stop
+ style="stop-color:#feb42e;stop-opacity:1;"
+ offset="1"
+ id="stop3766" />
+ </linearGradient>
+ </defs>
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1361"
+ inkscape:window-height="933"
+ id="namedview13"
+ showgrid="true"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:zoom="15.353691"
+ inkscape:cx="18.903205"
+ inkscape:cy="15.644701"
+ inkscape:window-x="506"
+ inkscape:window-y="178"
+ inkscape:window-maximized="0"
+ inkscape:current-layer="layer1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2992"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata4083">image/svg+xml<rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="" />
+ </cc:Work>
+</rdf:RDF>
+</metadata>
+ <g
+ id="g7"
+ transform="matrix(0.07691065,0,0,0.07691085,1.0927959,0.98000587)"
+ style="fill:#ff9955">
+ <title
+ id="title9">Layer 1</title>
+ <g
+ id="layer1"
+ style="fill:#ff9955">
+ <path
+ d="m 177.02481,23.864586 -7.11954,40.553793 0.028,0.02714 c -8.70293,1.422173 -17.12284,3.701312 -25.16506,6.736636 l 0,-0.02717 -26.42423,-31.573095 -24.836477,14.348617 14.102387,38.664612 0.0544,0.02719 c -6.73313,5.52738 -12.904565,11.720721 -18.428452,18.456501 l -0.02713,-0.0824 -38.66459,-14.102382 -14.348612,24.836472 31.57221,26.45226 c -3.030078,8.03521 -5.289063,16.44287 -6.708583,25.13703 l -0.02804,-0.0272 -40.553767,7.11953 0,28.69724 40.553767,7.11953 0.02804,-0.0 [...]
+ id="path4050"
+ stroke-miterlimit="4"
+ inkscape:connector-curvature="0"
+ style="fill:#f9f9f9;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0"
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccsssss" />
+ </g>
+ </g>
+</svg>
diff --git a/Viewer/images/dock_float.svg b/Viewer/images/dock_float.svg
new file mode 100644
index 0000000..fcb59d8
--- /dev/null
+++ b/Viewer/images/dock_float.svg
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="dock_float.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3795">
+ <stop
+ style="stop-color:#c53143;stop-opacity:1;"
+ offset="0"
+ id="stop3797" />
+ <stop
+ style="stop-color:#b8382b;stop-opacity:0;"
+ offset="1"
+ id="stop3799" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#fa0c1e;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#d9afb1;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3614">
+ <stop
+ style="stop-color:#e8220f;stop-opacity:1;"
+ offset="0"
+ id="stop3616" />
+ <stop
+ style="stop-color:#ececec;stop-opacity:1;"
+ offset="1"
+ id="stop3618" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3602">
+ <stop
+ style="stop-color:#932626;stop-opacity:1;"
+ offset="0"
+ id="stop3604" />
+ <stop
+ style="stop-color:#bc4343;stop-opacity:1;"
+ offset="1"
+ id="stop3606" />
+ </linearGradient>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="16.235036"
+ inkscape:cy="15.367291"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-grids="true"
+ inkscape:window-width="1363"
+ inkscape:window-height="1056"
+ inkscape:window-x="549"
+ inkscape:window-y="76"
+ inkscape:window-maximized="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <text
+ xml:space="preserve"
+ style="font-size:20px;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Calibri;-inkscape-font-specification:Calibri"
+ x="3.8399999"
+ y="21.973333"
+ id="text3783"><tspan
+ sodipodi:role="line"
+ id="tspan3785"
+ x="3.8399999"
+ y="21.973333" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="7.2533331"
+ y="15.146667"
+ id="text3787"><tspan
+ sodipodi:role="line"
+ id="tspan3789"
+ x="7.2533331"
+ y="15.146667" /></text>
+ <rect
+ style="opacity:0;fill:#800000;fill-opacity:1;fill-rule:evenodd;stroke:#904a3d;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="rect3010"
+ width="4.8580384"
+ height="8.448782"
+ x="18.103594"
+ y="9.7393379"
+ ry="0.18550164" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 2.2133334,13.679999 0,14.306667 18.0000006,0 0,-14.306667 z"
+ id="path3799"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="m 2.5866667,14.666666 c 17.2266663,0 18.0000003,0 18.0000003,0"
+ id="path3801"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ sodipodi:nodetypes="ccccc"
+ inkscape:connector-curvature="0"
+ id="path3807"
+ d="m 20.586667,17.666666 9,0 0,-13.9999994 -18,0 0,9.9999994"
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path3809"
+ d="m 12.1,5.0666666 c 17.226666,0 17.226666,0 17.226666,0"
+ style="fill:none;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+ </g>
+</svg>
diff --git a/Viewer/images/dock_menu_indicator.png b/Viewer/images/dock_menu_indicator.png
new file mode 100644
index 0000000..51e50cd
Binary files /dev/null and b/Viewer/images/dock_menu_indicator.png differ
diff --git a/Viewer/images/dock_menu_indicator.svg b/Viewer/images/dock_menu_indicator.svg
new file mode 100644
index 0000000..d8e6160
--- /dev/null
+++ b/Viewer/images/dock_menu_indicator.svg
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="dock_menu_indicator.svg"
+ inkscape:export-filename="/var/tmp/cgr/git/ecflow/Viewer/images/dock_menu_indicator.png"
+ inkscape:export-xdpi="30"
+ inkscape:export-ydpi="30">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3601">
+ <stop
+ style="stop-color:#a2a2a2;stop-opacity:1;"
+ offset="0"
+ id="stop3603" />
+ <stop
+ style="stop-color:#343434;stop-opacity:1;"
+ offset="1"
+ id="stop3605" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3601"
+ id="linearGradient3607"
+ x1="14.194276"
+ y1="14.459461"
+ x2="17.471718"
+ y2="39.653805"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.96774194,0,0,0.96774194,-38.540698,-10.847573)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="15.46875"
+ inkscape:cx="2.3811445"
+ inkscape:cy="16.419201"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer3"
+ showgrid="true"
+ inkscape:window-width="1920"
+ inkscape:window-height="1140"
+ inkscape:window-x="-4"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1"
+ inkscape:snap-to-guides="false"
+ inkscape:snap-grids="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2831"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="arrow"
+ style="display:inline">
+ <path
+ style="fill:#ffffff;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="M 5,11 16,22 26,11 z"
+ id="path3757"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccc" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="bar" />
+</svg>
diff --git a/Viewer/images/drawer_close.svg b/Viewer/images/drawer_close.svg
new file mode 100644
index 0000000..f3e90d8
--- /dev/null
+++ b/Viewer/images/drawer_close.svg
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.2 r9819"
+ sodipodi:docname="drawer_close.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3760">
+ <stop
+ id="stop3762"
+ offset="0"
+ style="stop-color:#676363;stop-opacity:1;" />
+ <stop
+ id="stop3764"
+ offset="1"
+ style="stop-color:#f4f4f4;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient4000">
+ <stop
+ style="stop-color:#da0a0a;stop-opacity:1;"
+ offset="0"
+ id="stop4002" />
+ <stop
+ style="stop-color:#f9bdbd;stop-opacity:1;"
+ offset="1"
+ id="stop4004" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3760"
+ id="linearGradient4006"
+ x1="0.76666671"
+ y1="30.486666"
+ x2="33.526669"
+ y2="7.0666671"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.93451327,0,0,0.98521257,1.0298524,0.55304991)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="16.15625"
+ inkscape:cx="6.344294"
+ inkscape:cy="16"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer7"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1881"
+ inkscape:window-height="1026"
+ inkscape:window-x="-8"
+ inkscape:window-y="-8"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer6"
+ inkscape:label="Layer" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer7"
+ inkscape:label="left">
+ <path
+ sodipodi:type="star"
+ style="fill:#8e9590;fill-opacity:1;stroke:#6b6b6b;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path3768"
+ sodipodi:sides="3"
+ sodipodi:cx="8.9129591"
+ sodipodi:cy="9.6557064"
+ sodipodi:r1="8.79004"
+ sodipodi:r2="4.39502"
+ sodipodi:arg1="0.014083576"
+ sodipodi:arg2="1.0612811"
+ inkscape:flatsided="false"
+ inkscape:rounded="0"
+ inkscape:randomized="0"
+ d="M 17.702127,9.7794975 11.056648,13.492476 4.4111687,17.205454 4.518375,9.593811 4.6255812,1.9821678 11.163854,5.8808326 z"
+ inkscape:transform-center-x="-0.0077246867"
+ inkscape:transform-center-y="3.8423729"
+ transform="matrix(0.02229967,1.7514857,-1.7080924,0.02286618,32.074244,-2.8731395)" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer8"
+ inkscape:label="screw" />
+</svg>
diff --git a/Viewer/images/drawer_open.svg b/Viewer/images/drawer_open.svg
new file mode 100644
index 0000000..284613c
--- /dev/null
+++ b/Viewer/images/drawer_open.svg
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.2 r9819"
+ sodipodi:docname="drawer_open.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3760">
+ <stop
+ id="stop3762"
+ offset="0"
+ style="stop-color:#676363;stop-opacity:1;" />
+ <stop
+ id="stop3764"
+ offset="1"
+ style="stop-color:#f4f4f4;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient4000">
+ <stop
+ style="stop-color:#da0a0a;stop-opacity:1;"
+ offset="0"
+ id="stop4002" />
+ <stop
+ style="stop-color:#f9bdbd;stop-opacity:1;"
+ offset="1"
+ id="stop4004" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3760"
+ id="linearGradient4006"
+ x1="0.76666671"
+ y1="30.486666"
+ x2="33.526669"
+ y2="7.0666671"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.93451327,0,0,0.98521257,1.0298524,0.55304991)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="16.15625"
+ inkscape:cx="6.344294"
+ inkscape:cy="16"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer7"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1881"
+ inkscape:window-height="1026"
+ inkscape:window-x="-8"
+ inkscape:window-y="-8"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer6"
+ inkscape:label="Layer" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer7"
+ inkscape:label="left">
+ <path
+ sodipodi:type="star"
+ style="fill:#8e9590;fill-opacity:1;stroke:#6b6b6b;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path3768"
+ sodipodi:sides="3"
+ sodipodi:cx="8.9129591"
+ sodipodi:cy="9.6557064"
+ sodipodi:r1="8.79004"
+ sodipodi:r2="4.39502"
+ sodipodi:arg1="0.014083576"
+ sodipodi:arg2="1.0612811"
+ inkscape:flatsided="false"
+ inkscape:rounded="0"
+ inkscape:randomized="0"
+ d="M 17.702127,9.7794975 11.056648,13.492476 4.4111687,17.205454 4.518375,9.593811 4.6255812,1.9821678 11.163854,5.8808326 z"
+ inkscape:transform-center-x="-4.1408629"
+ inkscape:transform-center-y="-0.0076893717"
+ transform="matrix(1.8875478,-0.02219372,0.02464251,1.6999775,-4.9585582,0.09597224)" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer8"
+ inkscape:label="screw" />
+</svg>
diff --git a/Viewer/images/edit.svg b/Viewer/images/edit.svg
new file mode 100644
index 0000000..92d4ea1
--- /dev/null
+++ b/Viewer/images/edit.svg
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg1455"
+ sodipodi:version="0.32"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="edit.svg"
+ inkscape:export-xdpi="120.00000"
+ inkscape:export-ydpi="120.00000"
+ version="1.1"
+ style="display:inline">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient3710-9">
+ <stop
+ id="stop3712-2"
+ offset="0"
+ style="stop-color:#f8f8f8;stop-opacity:1;" />
+ <stop
+ id="stop3714-2"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="6.1443644"
+ x2="23.48575"
+ y1="30.518726"
+ x1="4.5201936"
+ gradientTransform="matrix(-0.98592882,0,0,1.0377787,26.182921,-0.80161551)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3110"
+ xlink:href="#linearGradient3710-9"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3869-6">
+ <stop
+ style="stop-color:#ffad02;stop-opacity:1;"
+ offset="0"
+ id="stop3871-9" />
+ <stop
+ style="stop-color:#c4ba4a;stop-opacity:1;"
+ offset="1"
+ id="stop3873-2" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3829">
+ <stop
+ style="stop-color:#786535;stop-opacity:1;"
+ offset="0"
+ id="stop3831" />
+ <stop
+ style="stop-color:#cd6938;stop-opacity:1;"
+ offset="1"
+ id="stop3833" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3821">
+ <stop
+ style="stop-color:#050505;stop-opacity:1;"
+ offset="0"
+ id="stop3823" />
+ <stop
+ style="stop-color:#949494;stop-opacity:1;"
+ offset="1"
+ id="stop3825" />
+ </linearGradient>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="26.28125"
+ inkscape:cx="17.233972"
+ inkscape:cy="15.429133"
+ inkscape:current-layer="g4016"
+ showgrid="true"
+ inkscape:document-units="px"
+ inkscape:grid-bbox="true"
+ inkscape:window-width="1438"
+ inkscape:window-height="1066"
+ inkscape:window-x="270"
+ inkscape:window-y="52"
+ inkscape:window-maximized="0"
+ inkscape:snap-smooth-nodes="false"
+ inkscape:object-nodes="false"
+ inkscape:snap-grids="false"
+ inkscape:snap-to-guides="false">
+ <inkscape:grid
+ type="xygrid"
+ id="grid3734"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="paper 2"
+ style="display:inline">
+ <path
+ style="fill:url(#linearGradient3110);fill-opacity:1;stroke:#080808;stroke-width:0.98463219;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+ d="m 21.253277,1.2739421 0,29.0578059 -20.70450264,0 0,-20.7555762 L 8.1592575,9.6507978 8.0883734,1.34857 21.253289,1.273948 z"
+ id="path3698-4"
+ sodipodi:nodetypes="ccccccc"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="layer1"
+ inkscape:label="paper"
+ inkscape:groupmode="layer"
+ transform="translate(0,-16)"
+ style="display:inline">
+ <path
+ style="fill:none;stroke:#050505;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+ d="M 8.0539195,17.281032 0.38674725,25.444727"
+ id="path3783-4"
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer8"
+ inkscape:label="shadow" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer6"
+ inkscape:label="pencil"
+ style="display:inline">
+ <g
+ transform="matrix(1.2554203,0.65436333,-0.62104373,1.1937046,2.3055751,-12.772196)"
+ id="g4016">
+ <path
+ sodipodi:nodetypes="cccccccac"
+ id="path3867"
+ d="m 19.95225,1.2258817 -3.608012,9.2046493 -2.929228,7.080264 0.01931,6.518218 4.765365,-4.084175 0.08712,-0.121054 6.437702,-16.5454579 c 0,0 -1.012465,-1.8189901 -1.876445,-2.1984961 C 21.956555,0.68823257 19.95225,1.2258817 19.95225,1.2258817 z"
+ style="fill:#ff9b4a;fill-opacity:1;stroke:#422a03;stroke-width:0.72452557;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="ccccccc"
+ id="path3883"
+ d="m 13.411155,17.965844 0.06031,3.786825 -0.0023,0.03023 -0.207774,2.701631 4.593269,-4.316752 -2.020605,-1.52742 z"
+ style="fill:#f4eed7;fill-opacity:1;stroke:#4c5254;stroke-width:0.72452557;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="ccccc"
+ id="path3887"
+ d="m 13.131424,20.803292 -0.204108,4.401903 2.989147,-2.702438 -1.288792,-1.112428 z"
+ style="fill:#1a1a1a;fill-opacity:1;stroke:none;display:inline"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:#241d16;fill-opacity:1;stroke:none"
+ d="m 9.9310345,18.568371 1.1414975,0.989299 0.761,1.674197 L 30.592152,5.174792 29.945303,3.6147443 29.032104,2.9678954 z"
+ id="path6691"
+ inkscape:connector-curvature="0"
+ transform="matrix(0.62662013,-0.34349975,0.32600905,0.65901701,2.7191317,9.2090589)"
+ sodipodi:nodetypes="ccccccc" />
+ </g>
+ </g>
+</svg>
diff --git a/Viewer/images/editcopy.svg b/Viewer/images/editcopy.svg
new file mode 100644
index 0000000..796fe07
--- /dev/null
+++ b/Viewer/images/editcopy.svg
@@ -0,0 +1,167 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg1455"
+ sodipodi:version="0.32"
+ inkscape:version="0.48.2 r9819"
+ sodipodi:docname="editcopy.svg"
+ inkscape:export-xdpi="120.00000"
+ inkscape:export-ydpi="120.00000"
+ version="1.1"
+ style="display:inline">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient3710-9">
+ <stop
+ id="stop3712-2"
+ offset="0"
+ style="stop-color:#e1e1e1;stop-opacity:1;" />
+ <stop
+ id="stop3714-2"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="6.1443644"
+ x2="23.48575"
+ y1="30.518726"
+ x1="4.5201936"
+ gradientTransform="matrix(0.68515292,0,0,0.71929209,-1.0125311,0.17780731)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3110"
+ xlink:href="#linearGradient3710-9"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3710-9-6">
+ <stop
+ id="stop3712-2-9"
+ offset="0"
+ style="stop-color:#e1e1e1;stop-opacity:1;" />
+ <stop
+ id="stop3714-2-2"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="6.1443644"
+ x2="23.48575"
+ y1="30.518726"
+ x1="4.5201936"
+ gradientTransform="matrix(0.68515292,0,0,0.71113853,11.810444,8.9975262)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3975"
+ xlink:href="#linearGradient3710-9-6"
+ inkscape:collect="always" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="26.28125"
+ inkscape:cx="9.5636523"
+ inkscape:cy="16.184033"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:document-units="px"
+ inkscape:grid-bbox="true"
+ inkscape:window-width="1881"
+ inkscape:window-height="1026"
+ inkscape:window-x="-8"
+ inkscape:window-y="-8"
+ inkscape:window-maximized="1"
+ inkscape:snap-smooth-nodes="false"
+ inkscape:object-nodes="false"
+ inkscape:snap-grids="false">
+ <inkscape:grid
+ type="xygrid"
+ id="grid3734"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="paper 2"
+ style="display:inline">
+ <path
+ style="fill:url(#linearGradient3110);fill-opacity:1;stroke:#000000;stroke-width:0.80000000999999998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+ d="m 2.4132344,1.6163914 0,20.1401796 14.3882116,0 0,-14.3858432 -5.288765,0.051729 0.04926,-5.7543356 -9.1487157,-0.051721 z"
+ id="path3698-4"
+ sodipodi:nodetypes="ccccccc" />
+ </g>
+ <g
+ id="layer1"
+ inkscape:label="paper"
+ inkscape:groupmode="layer"
+ transform="translate(0,-16)"
+ style="display:inline">
+ <path
+ style="fill:none;stroke:#000000;stroke-width:0.80000000999999998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+ d="m 11.661407,17.554636 5.216396,5.6884"
+ id="path3783-4"
+ sodipodi:nodetypes="cc" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="paper3">
+ <path
+ style="fill:url(#linearGradient3975);fill-opacity:1;stroke:#000000;stroke-width:0.80000000999999998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+ d="m 15.23621,10.419803 0,19.91188 14.388211,0 0,-14.222772 -5.288765,0.05114 0.04926,-5.689108 -9.148716,-0.05114 z"
+ id="path3698-4-2"
+ sodipodi:nodetypes="ccccccc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:0.80000000999999998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+ d="m 24.508121,10.336588 5.24502,5.693268"
+ id="path3783-4-4"
+ sodipodi:nodetypes="cc" />
+ </g>
+</svg>
diff --git a/Viewer/images/editpaste.svg b/Viewer/images/editpaste.svg
new file mode 100644
index 0000000..354e711
--- /dev/null
+++ b/Viewer/images/editpaste.svg
@@ -0,0 +1,185 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg1455"
+ sodipodi:version="0.32"
+ inkscape:version="0.47 r22583"
+ sodipodi:docname="editpaste.svg"
+ inkscape:export-xdpi="120.00000"
+ inkscape:export-ydpi="120.00000"
+ version="1.1"
+ style="display:inline">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient3706">
+ <stop
+ id="stop3708"
+ offset="0"
+ style="stop-color:#bebebe;stop-opacity:1;" />
+ <stop
+ id="stop3710"
+ offset="1"
+ style="stop-color:#fffefb;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3710">
+ <stop
+ id="stop3712"
+ offset="0"
+ style="stop-color:#cccccc;stop-opacity:1" />
+ <stop
+ id="stop3714"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3710"
+ id="linearGradient3090"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.72601648,0,0,0.71232532,11.187144,24.74439)"
+ x1="2.996588"
+ y1="30.701927"
+ x2="21.976355"
+ y2="5.9961967" />
+ <linearGradient
+ id="linearGradient3650-6">
+ <stop
+ style="stop-color:#e59111;stop-opacity:1;"
+ offset="0"
+ id="stop3652-9" />
+ <stop
+ style="stop-color:#f8e56c;stop-opacity:1"
+ offset="1"
+ id="stop3654-2" />
+ </linearGradient>
+ <linearGradient
+ y2="5.6694412"
+ x2="13.08918"
+ y1="26.634958"
+ x1="13.08918"
+ gradientTransform="matrix(0.89464883,0,0,0.95480226,1.1696858,0.90911403)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3675"
+ xlink:href="#linearGradient3650-6"
+ inkscape:collect="always" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3706"
+ id="linearGradient3704"
+ x1="12.423306"
+ y1="5.6367421"
+ x2="12.423306"
+ y2="0.10856482"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0245614,0,0,1.0420146,0.51293991,0.58323042)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="26.28125"
+ inkscape:cx="22.464065"
+ inkscape:cy="16.05888"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:document-units="px"
+ inkscape:grid-bbox="true"
+ inkscape:window-width="1438"
+ inkscape:window-height="1096"
+ inkscape:window-x="152"
+ inkscape:window-y="0"
+ inkscape:window-maximized="0"
+ inkscape:snap-smooth-nodes="false"
+ inkscape:object-nodes="false"
+ inkscape:snap-grids="false">
+ <inkscape:grid
+ type="xygrid"
+ id="grid3734"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="paper 2">
+ <path
+ style="fill:none;stroke:#717171;stroke-width:0.8;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;stroke-miterlimit:4;stroke-dasharray:none"
+ d="m 24.665907,10.10844 5.535581,5.615569"
+ id="path3783-4-7"
+ sodipodi:nodetypes="cc" />
+ <rect
+ style="fill:url(#linearGradient3675);fill-opacity:1;fill-rule:evenodd;stroke:#ed8c12;stroke-opacity:1;display:inline"
+ id="rect2876"
+ width="20.356718"
+ height="25.72176"
+ x="2.701546"
+ y="3.2342448"
+ ry="0.8719241" />
+ <path
+ style="fill:url(#linearGradient3704);fill-opacity:1;stroke:#999999;stroke-width:0.69999993;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="m 7.686088,5.8961419 11.110583,0.039649 c 0,0 -1.235673,-2.4746752 -2.261102,-3.3304819 C 15.649172,1.8655347 14.524398,1.230427 13.377826,1.2176079 12.031389,1.2025542 10.668471,1.8856562 9.635313,2.763903 8.70312,3.5563234 7.686088,5.8961419 7.686088,5.8961419 z"
+ id="path3696"
+ sodipodi:nodetypes="ccaaac" />
+ </g>
+ <g
+ id="layer1"
+ inkscape:label="paper"
+ inkscape:groupmode="layer"
+ transform="translate(0,-16)"
+ style="display:inline">
+ <path
+ style="fill:url(#linearGradient3090);fill-opacity:1;stroke:#717171;stroke-width:0.8;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="m 14.817226,26.169041 0,19.945109 15.246346,0 0,-14.246507 -5.604195,0.05122 0.05221,-5.698602 -9.694359,-0.05123 z"
+ id="path3698"
+ sodipodi:nodetypes="ccccccc" />
+ </g>
+</svg>
diff --git a/Viewer/images/error.svg b/Viewer/images/error.svg
new file mode 100644
index 0000000..743c52c
--- /dev/null
+++ b/Viewer/images/error.svg
@@ -0,0 +1,214 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.2 r9819"
+ sodipodi:docname="error.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3831">
+ <stop
+ id="stop3833"
+ offset="0"
+ style="stop-color:#f8f4f4;stop-opacity:1;" />
+ <stop
+ id="stop3835"
+ offset="1"
+ style="stop-color:#d40000;stop-opacity:0.30357143;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3819">
+ <stop
+ id="stop3821"
+ offset="0"
+ style="stop-color:#edcdc9;stop-opacity:1;" />
+ <stop
+ id="stop3823"
+ offset="1"
+ style="stop-color:#c91b0b;stop-opacity:0.99215686;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3783">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop3785" />
+ <stop
+ style="stop-color:#d40000;stop-opacity:1;"
+ offset="1"
+ id="stop3787" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3674">
+ <stop
+ style="stop-color:#f0c7c1;stop-opacity:1;"
+ offset="0"
+ id="stop3676" />
+ <stop
+ style="stop-color:#de1a08;stop-opacity:0.99215686;"
+ offset="1"
+ id="stop3678" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3783"
+ id="linearGradient3789"
+ x1="-4.8186264"
+ y1="4.2037883"
+ x2="-4.5480547"
+ y2="39.719273"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3674"
+ id="linearGradient3806"
+ x1="-4.7521257"
+ y1="1.3206121"
+ x2="-8.2720757"
+ y2="7.3490696"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3783"
+ id="linearGradient3808"
+ gradientUnits="userSpaceOnUse"
+ x1="-4.0871224"
+ y1="33.62529"
+ x2="-8.2720757"
+ y2="7.3490696" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3783"
+ id="linearGradient3814"
+ gradientUnits="userSpaceOnUse"
+ x1="-4.8186264"
+ y1="4.2037883"
+ x2="-4.5480547"
+ y2="39.719273"
+ gradientTransform="matrix(0.93075485,0,0,0.94458483,20.730415,-1.9099)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3674"
+ id="linearGradient3816"
+ gradientUnits="userSpaceOnUse"
+ x1="-4.7521257"
+ y1="1.3206121"
+ x2="-4.5480547"
+ y2="39.719273"
+ gradientTransform="matrix(0.93075485,0,0,0.94458483,20.730415,-1.9099)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3831"
+ id="linearGradient3829"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.56279655,-0.71788239,0.73596717,0.56540236,5.2720134,1022.061)"
+ x1="-5.2841291"
+ y1="4.1382613"
+ x2="-5.0135574"
+ y2="14.16385" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="16.15625"
+ inkscape:cx="-1.2721091"
+ inkscape:cy="17.039481"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:snap-to-guides="false"
+ inkscape:window-width="1881"
+ inkscape:window-height="1026"
+ inkscape:window-x="-8"
+ inkscape:window-y="-8"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2985"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="Layer" />
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-1020.3622)">
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#linearGradient3808);fill-opacity:1;stroke:url(#linearGradient3806);stroke-opacity:1"
+ id="path3011"
+ sodipodi:cx="-4.9825921"
+ sodipodi:cy="18.816248"
+ sodipodi:rx="15.628627"
+ sodipodi:ry="15.288201"
+ d="m 10.646035,18.816248 a 15.628627,15.288201 0 1 1 -31.257254,0 15.628627,15.288201 0 1 1 31.257254,0 z"
+ transform="matrix(0.73907864,-0.56574495,0.57415129,0.75006053,8.9719977,1019.2936)" />
+ <path
+ style="fill:url(#linearGradient3829);fill-opacity:1;stroke:none"
+ d="m 5.0764601,1027.6409 c -4.85771212,6.1963 -3.7707131,15.0997 2.4434244,19.8738 1.8564653,1.4262 3.9729615,2.2775 6.1389485,2.6693 -3.60634,-3.802 -3.383933,-10.6125 0.764022,-15.9036 3.823852,-4.8775 9.737043,-6.8773 14.253388,-5.1927 -0.88861,-1.5138 -2.083151,-2.8749 -3.564304,-4.0127 -6.214137,-4.7741 -15.1777072,-3.6306 -20.0354789,2.5659 z"
+ id="path3810"
+ inkscape:connector-curvature="0" />
+ <rect
+ style="fill:#ffffff;fill-opacity:1;stroke:none"
+ id="rect3013"
+ width="19.682785"
+ height="6.1895556"
+ x="6.7466159"
+ y="1032.9578" />
+ </g>
+</svg>
diff --git a/Viewer/images/exit.svg b/Viewer/images/exit.svg
new file mode 100644
index 0000000..a48d2f7
--- /dev/null
+++ b/Viewer/images/exit.svg
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.47 r22583"
+ sodipodi:docname="exit.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient4000">
+ <stop
+ style="stop-color:#da0a0a;stop-opacity:1;"
+ offset="0"
+ id="stop4002" />
+ <stop
+ style="stop-color:#f9bdbd;stop-opacity:1;"
+ offset="1"
+ id="stop4004" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4000"
+ id="linearGradient4006"
+ x1="0.76666671"
+ y1="30.486666"
+ x2="33.526669"
+ y2="7.0666671"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.93451327,0,0,0.98521257,1.0298524,0.55304991)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="8.7199422"
+ inkscape:cy="16.554812"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer6"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1599"
+ inkscape:window-height="990"
+ inkscape:window-x="797"
+ inkscape:window-y="87"
+ inkscape:window-maximized="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer6"
+ inkscape:label="Layer">
+ <rect
+ style="fill:url(#linearGradient4006);fill-opacity:1;fill-rule:evenodd;stroke:#bd1b1b;stroke-width:0.60000002;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="rect3998"
+ width="28.160002"
+ height="28.426666"
+ x="2.0266666"
+ y="1.8666666"
+ ry="1.4187062" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer7"
+ inkscape:label="left">
+ <rect
+ style="fill:#ffffff;fill-opacity:1;stroke:#fffcfc;stroke-width:3.33834791;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+ id="rect3809"
+ width="1.4149849"
+ height="17.969641"
+ x="-0.88293612"
+ y="13.929389"
+ ry="0.11241483"
+ transform="matrix(0.69887353,-0.71524526,0.71524526,0.69887353,0,0)" />
+ <rect
+ ry="0.11177491"
+ y="-9.1891193"
+ x="-23.917221"
+ height="17.86735"
+ width="1.4193591"
+ id="rect3811"
+ style="fill:#ffffff;fill-opacity:1;stroke:#fffcfc;stroke-width:3.33397388;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+ transform="matrix(-0.71524526,-0.69887353,0.69887353,-0.71524526,0,0)" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer8"
+ inkscape:label="screw" />
+</svg>
diff --git a/Viewer/images/favourite.svg b/Viewer/images/favourite.svg
new file mode 100644
index 0000000..e9122da
--- /dev/null
+++ b/Viewer/images/favourite.svg
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.47 r22583"
+ sodipodi:docname="bookmark.svg">
+ <defs
+ id="defs4">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 16 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="32 : 16 : 1"
+ inkscape:persp3d-origin="16 : 10.666667 : 1"
+ id="perspective2882" />
+ <linearGradient
+ id="linearGradient3757">
+ <stop
+ style="stop-color:#f5ef7a;stop-opacity:1;"
+ offset="0"
+ id="stop3759" />
+ <stop
+ style="stop-color:#ffb41b;stop-opacity:1;"
+ offset="1"
+ id="stop3761" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3757"
+ id="linearGradient3765"
+ x1="9.0300617"
+ y1="7.6554561"
+ x2="7.2979932"
+ y2="23.49078"
+ gradientUnits="userSpaceOnUse" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="12.46875"
+ inkscape:cx="-4.4680284"
+ inkscape:cy="16"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:window-width="1600"
+ inkscape:window-height="925"
+ inkscape:window-x="2134"
+ inkscape:window-y="20"
+ inkscape:window-maximized="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2985"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-1020.3622)">
+ <path
+ sodipodi:type="star"
+ style="fill:url(#linearGradient3765);fill-opacity:1;fill-rule:evenodd;stroke:#764f25;stroke-width:0.94637238999999995;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="path2987"
+ sodipodi:sides="5"
+ sodipodi:cx="9"
+ sodipodi:cy="12"
+ sodipodi:r1="15"
+ sodipodi:r2="7.6500001"
+ sodipodi:arg1="0.64350111"
+ sodipodi:arg2="1.2718196"
+ inkscape:flatsided="false"
+ inkscape:rounded="0.04"
+ inkscape:randomized="-0.001"
+ d="M 20.997045,20.992528 C 20.75931,21.308892 11.617197,19.181414 11.238826,19.297493 10.860454,19.413572 4.5202372,26.329466 4.1459842,26.201371 3.7717312,26.073276 2.9704721,16.715905 2.7432329,16.391868 2.5159936,16.067831 -6.016519,12.168242 -6.0107214,11.772479 c 0.0058,-0.395763 8.6627974,-4.0484273 8.8998098,-4.3653101 0.2370125,-0.3168827 1.3050227,-9.6358293 1.6832674,-9.7523143 0.3782446,-0.116485 6.5253462,6.9706314 6.8997352,7.0989866 0.374389,0.1283552 9.578158,-1.722 [...]
+ transform="matrix(0.99363412,0.30409271,-0.29423698,1.0269168,10.313398,1022.4196)"
+ inkscape:transform-center-x="0.053227332"
+ inkscape:transform-center-y="-1.4817371" />
+ </g>
+</svg>
diff --git a/Viewer/images/favourite_empty.svg b/Viewer/images/favourite_empty.svg
new file mode 100644
index 0000000..7562e8e
--- /dev/null
+++ b/Viewer/images/favourite_empty.svg
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.2 r9819"
+ sodipodi:docname="bookmark_empty.svg">
+ <defs
+ id="defs4">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 16 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="32 : 16 : 1"
+ inkscape:persp3d-origin="16 : 10.666667 : 1"
+ id="perspective2882" />
+ <linearGradient
+ id="linearGradient3757">
+ <stop
+ style="stop-color:#fdfb72;stop-opacity:1;"
+ offset="0"
+ id="stop3759" />
+ <stop
+ style="stop-color:#ffb41b;stop-opacity:1;"
+ offset="1"
+ id="stop3761" />
+ </linearGradient>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="12.46875"
+ inkscape:cx="-14.405339"
+ inkscape:cy="16"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:window-width="1421"
+ inkscape:window-height="925"
+ inkscape:window-x="414"
+ inkscape:window-y="57"
+ inkscape:window-maximized="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2985"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-1020.3622)">
+ <path
+ sodipodi:type="star"
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#a7723a;stroke-width:0.94637238999999995;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="path2987"
+ sodipodi:sides="5"
+ sodipodi:cx="9"
+ sodipodi:cy="12"
+ sodipodi:r1="15"
+ sodipodi:r2="7.6500001"
+ sodipodi:arg1="0.64350111"
+ sodipodi:arg2="1.2718196"
+ inkscape:flatsided="false"
+ inkscape:rounded="0.04"
+ inkscape:randomized="-0.001"
+ d="M 20.997045,20.992528 C 20.75931,21.308892 11.617197,19.181414 11.238826,19.297493 10.860454,19.413572 4.5202372,26.329466 4.1459842,26.201371 3.7717312,26.073276 2.9704721,16.715905 2.7432329,16.391868 2.5159936,16.067831 -6.016519,12.168242 -6.0107214,11.772479 c 0.0058,-0.395763 8.6627974,-4.0484273 8.8998098,-4.3653101 0.2370125,-0.3168827 1.3050227,-9.6358293 1.6832674,-9.7523143 0.3782446,-0.116485 6.5253462,6.9706314 6.8997352,7.0989866 0.374389,0.1283552 9.578158,-1.722 [...]
+ transform="matrix(0.99363412,0.30409271,-0.29423698,1.0269168,10.313398,1022.4196)"
+ inkscape:transform-center-x="0.053227332"
+ inkscape:transform-center-y="-1.4817371" />
+ </g>
+</svg>
diff --git a/Viewer/images/filesave.svg b/Viewer/images/filesave.svg
new file mode 100644
index 0000000..57a792a
--- /dev/null
+++ b/Viewer/images/filesave.svg
@@ -0,0 +1,234 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.47 r22583"
+ version="1.0"
+ sodipodi:docname="filesave.svg"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient12168">
+ <stop
+ style="stop-color:#858585;stop-opacity:1;"
+ offset="0"
+ id="stop12170" />
+ <stop
+ id="stop12172"
+ offset="0.5"
+ style="stop-color:#cbcbcb;stop-opacity:1;" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="1"
+ id="stop12174" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient11450">
+ <stop
+ style="stop-color:#191919;stop-opacity:1;"
+ offset="0"
+ id="stop11452" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop11454" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2263">
+ <stop
+ style="stop-color:#3e848c;stop-opacity:1;"
+ offset="0"
+ id="stop2265" />
+ <stop
+ style="stop-color:#b3c7de;stop-opacity:1;"
+ offset="1"
+ id="stop2267" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2263"
+ id="linearGradient7454"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.9673902,0,0,-1.1589562,-0.79677103,52.162489)"
+ x1="28.673536"
+ y1="2.2797322"
+ x2="9.2870998"
+ y2="46.581879" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient12168"
+ id="linearGradient7458"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0595231,0,0,-1.0264164,-2.3364269,49.429715)"
+ x1="13.444483"
+ y1="41.398193"
+ x2="38.408127"
+ y2="31.618719" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient11450"
+ id="linearGradient11456"
+ x1="19.784695"
+ y1="29.870388"
+ x2="19.784693"
+ y2="42.991951"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.903975,0,0,0.6975501,11.791609,-36.457522)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#efefef"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="1"
+ inkscape:pageshadow="2"
+ inkscape:zoom="27.1875"
+ inkscape:cx="3.6965521"
+ inkscape:cy="18.390381"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ inkscape:showpageshadow="false"
+ showborder="true"
+ borderlayer="top"
+ showgrid="true"
+ inkscape:grid-points="false"
+ inkscape:window-width="1585"
+ inkscape:window-height="1096"
+ inkscape:window-x="198"
+ inkscape:window-y="35"
+ width="32px"
+ height="32px"
+ inkscape:window-maximized="0"
+ inkscape:snap-grids="false">
+ <inkscape:grid
+ id="GridFromPre046Settings"
+ type="xygrid"
+ originx="0px"
+ originy="0px"
+ spacingx="1px"
+ spacingy="1px"
+ color="#9f9f9f"
+ empcolor="#9f9f9f"
+ opacity="0.10196078"
+ empopacity="0.25490196"
+ empspacing="10" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ style="display:inline">
+ <g
+ style="display:inline"
+ id="g7418"
+ inkscape:label="Layer 1"
+ transform="matrix(0.75450459,0,0,0.71126951,-2.1666557,-1.4575482)">
+ <path
+ sodipodi:nodetypes="ccccccccc"
+ id="path7428"
+ d="m 6.518876,43.354968 35.286861,0 c 0.534691,0 0.965147,-0.454103 0.965147,-1.018168 l 0,-36.1483706 c 0,-0.5640634 -0.430456,-1.0181674 -0.965147,-1.0181674 l -32.740934,0 c 0,0 -3.6085747,3.8629739 -3.6085747,3.8629739 L 5.553727,42.3368 c 0,0.564065 0.4304565,1.018168 0.965149,1.018168 z"
+ style="fill:url(#linearGradient7454);fill-opacity:1;stroke:#25375f;stroke-width:1.09204853;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
+ <path
+ sodipodi:nodetypes="ccccccc"
+ id="path7444"
+ d="m 15.597127,17.861022 17.95215,0 c 0.807146,0 1.456942,-0.646926 1.456942,-1.450506 l 0,-11.3734517 c 0,0 -20.866034,0 -20.866034,0 l 0,11.3734517 c 0,0.80358 0.649796,1.450506 1.456942,1.450506 z"
+ style="fill:url(#linearGradient7458);fill-opacity:1;stroke:#371d1d;stroke-width:0.80249828;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0" />
+ <rect
+ ry="0.47095141"
+ rx="0.63196307"
+ y="-14.153564"
+ x="27.560804"
+ height="6.3106155"
+ width="4.2313471"
+ id="rect7446"
+ style="fill:url(#linearGradient11456);fill-opacity:1;stroke:#251818;stroke-width:0.65857965;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ transform="scale(1,-1)" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="white"
+ style="display:inline">
+ <rect
+ y="-27.690033"
+ x="5.7776341"
+ height="12.439459"
+ width="20.560297"
+ id="rect7430"
+ style="fill:#ffffff;fill-opacity:1;stroke:#371d1d;stroke-width:0.63016373;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ transform="scale(1,-1)" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="label"
+ style="display:inline">
+ <rect
+ style="fill:#cccccc;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.4163833;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ id="rect11357"
+ width="15.208806"
+ height="0.61792487"
+ x="8.3011494"
+ y="-19.845976"
+ rx="0.10916411"
+ ry="0"
+ transform="scale(1,-1)" />
+ <rect
+ transform="scale(1,-1)"
+ ry="0"
+ rx="0.10925798"
+ y="-24.18055"
+ x="8.3313904"
+ height="0.58149546"
+ width="15.221885"
+ id="rect13161"
+ style="fill:#b3b3b3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.4040966;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" />
+ </g>
+ </g>
+</svg>
diff --git a/Viewer/images/filter.svg b/Viewer/images/filter.svg
new file mode 100644
index 0000000..b29c54e
--- /dev/null
+++ b/Viewer/images/filter.svg
@@ -0,0 +1,173 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.91 r13725"
+ sodipodi:docname="filter.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3617">
+ <stop
+ style="stop-color:#bdc2f8;stop-opacity:1"
+ offset="0"
+ id="stop3619" />
+ <stop
+ style="stop-color:#0e5b6f;stop-opacity:1"
+ offset="1"
+ id="stop3621" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3776">
+ <stop
+ id="stop3778"
+ offset="0"
+ style="stop-color:#61728a;stop-opacity:1;" />
+ <stop
+ id="stop3780"
+ offset="1"
+ style="stop-color:#b1bec2;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3717-3">
+ <stop
+ style="stop-color:#9cb1da;stop-opacity:1;"
+ offset="0"
+ id="stop3719-8" />
+ <stop
+ style="stop-color:#ecf0f1;stop-opacity:1;"
+ offset="1"
+ id="stop3721-3" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3617"
+ id="linearGradient4163"
+ x1="2.1983273"
+ y1="25.221609"
+ x2="14.203107"
+ y2="25.221609"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3717-3"
+ id="linearGradient4179"
+ x1="8.8120937"
+ y1="16.091959"
+ x2="8.7554102"
+ y2="20.832701"
+ gradientUnits="userSpaceOnUse" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="52.3125"
+ inkscape:cx="4.9605735"
+ inkscape:cy="9.7824462"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1920"
+ inkscape:window-height="1005"
+ inkscape:window-x="-9"
+ inkscape:window-y="-9"
+ inkscape:window-maximized="1"
+ showguides="true"
+ inkscape:guide-bbox="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="body"
+ transform="translate(0,-16)" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="connect"
+ transform="translate(0,-16)" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="lens"
+ transform="translate(0,-16)">
+ <path
+ style="fill:url(#linearGradient4163);stroke:none;fill-opacity:1.0"
+ d="M 7.1875747,30.434382 7.1684588,25.576596 2.1983274,19.672519 c 0,0 3.8335398,0.847537 6.1362007,0.784718 2.2376879,-0.06105 5.8685789,-0.728668 5.8685789,-0.728668 l -4.989248,5.866712 1e-7,4.839101 c 0,0 -0.5050549,0.334661 -1.0322581,0.33631 -0.672244,0.0021 -0.9940263,-0.33631 -0.9940263,-0.33631 z"
+ id="path3025"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccscccsc" />
+ <ellipse
+ style="fill:url(#linearGradient4179);fill-opacity:1;stroke:#3f607c;stroke-width:0.53590798;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path3795"
+ cx="8.1911592"
+ cy="19.131386"
+ rx="5.9163685"
+ ry="1.9535972" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline"
+ transform="translate(0,-16)" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer5"
+ inkscape:label="okulars"
+ transform="translate(0,-16)" />
+</svg>
diff --git a/Viewer/images/filter_decor.svg b/Viewer/images/filter_decor.svg
new file mode 100644
index 0000000..909bd40
--- /dev/null
+++ b/Viewer/images/filter_decor.svg
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.2 r9819"
+ sodipodi:docname="filter.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3617">
+ <stop
+ style="stop-color:#f7f6f2;stop-opacity:1;"
+ offset="0"
+ id="stop3619" />
+ <stop
+ style="stop-color:#0e729a;stop-opacity:1;"
+ offset="1"
+ id="stop3621" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3776">
+ <stop
+ id="stop3778"
+ offset="0"
+ style="stop-color:#61728a;stop-opacity:1;" />
+ <stop
+ id="stop3780"
+ offset="1"
+ style="stop-color:#b1bec2;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3717-3">
+ <stop
+ style="stop-color:#9cb1da;stop-opacity:1;"
+ offset="0"
+ id="stop3719-8" />
+ <stop
+ style="stop-color:#ecf0f1;stop-opacity:1;"
+ offset="1"
+ id="stop3721-3" />
+ </linearGradient>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="52.3125"
+ inkscape:cx="4.9605735"
+ inkscape:cy="8"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1881"
+ inkscape:window-height="1026"
+ inkscape:window-x="-8"
+ inkscape:window-y="-8"
+ inkscape:window-maximized="1"
+ showguides="true"
+ inkscape:guide-bbox="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="body"
+ transform="translate(0,-16)" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="connect"
+ transform="translate(0,-16)" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="lens"
+ transform="translate(0,-16)">
+ <path
+ style="fill:#666666;stroke:none"
+ d="M 7.1875747,30.434382 7.1684588,25.576596 2.1983274,19.672519 c 0,0 3.8335398,0.847537 6.1362007,0.784718 2.2376879,-0.06105 5.8685789,-0.728668 5.8685789,-0.728668 l -4.989248,5.866712 1e-7,4.839101 c 0,0 -0.5050549,0.334661 -1.0322581,0.33631 -0.672244,0.0021 -0.9940263,-0.33631 -0.9940263,-0.33631 z"
+ id="path3025"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccscccsc" />
+ <path
+ sodipodi:type="arc"
+ style="fill:#ffffff;stroke:#595959;stroke-width:0.33966306;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="path3795"
+ sodipodi:cx="4.3870969"
+ sodipodi:cy="2.7048984"
+ sodipodi:rx="5.1135006"
+ sodipodi:ry="0.90800476"
+ d="m 9.5005975,2.7048984 a 5.1135006,0.90800476 0 1 1 -10.22700121,0 5.1135006,0.90800476 0 1 1 10.22700121,0 z"
+ transform="matrix(1.1570094,0,0,2.1515275,3.0770152,13.579345)" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline"
+ transform="translate(0,-16)" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer5"
+ inkscape:label="okulars"
+ transform="translate(0,-16)" />
+</svg>
diff --git a/Viewer/images/filter_edit.svg b/Viewer/images/filter_edit.svg
new file mode 100644
index 0000000..aab2c8b
--- /dev/null
+++ b/Viewer/images/filter_edit.svg
@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="filter_edit.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3617">
+ <stop
+ style="stop-color:#fefefe;stop-opacity:1;"
+ offset="0"
+ id="stop3619" />
+ <stop
+ style="stop-color:#4f93a3;stop-opacity:1;"
+ offset="1"
+ id="stop3621" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3776">
+ <stop
+ id="stop3778"
+ offset="0"
+ style="stop-color:#61728a;stop-opacity:1;" />
+ <stop
+ id="stop3780"
+ offset="1"
+ style="stop-color:#b1bec2;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3717-3">
+ <stop
+ style="stop-color:#c1cee8;stop-opacity:1;"
+ offset="0"
+ id="stop3719-8" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop3721-3" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3617"
+ id="linearGradient4163"
+ x1="3.500973"
+ y1="25.36322"
+ x2="14.203107"
+ y2="25.221609"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(2.1063298,0,0,2.1009617,-2.5166687,-33.582356)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3717-3"
+ id="linearGradient4179"
+ x1="8.8120937"
+ y1="16.091959"
+ x2="8.7554102"
+ y2="20.832701"
+ gradientUnits="userSpaceOnUse" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="30.25"
+ inkscape:cx="5.3449688"
+ inkscape:cy="15.789501"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1920"
+ inkscape:window-height="1140"
+ inkscape:window-x="-4"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1"
+ showguides="true"
+ inkscape:guide-bbox="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="body" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="connect" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="lens">
+ <path
+ style="fill:url(#linearGradient4163);fill-opacity:1;stroke:none"
+ d="M 12.622734,30.359114 12.582469,20.153092 1.9484444,6.8893482 c 0,0 8.2399886,2.6401469 13.0901516,2.5081665 C 19.751904,9.269251 27.300584,7.1723963 27.300584,7.1723963 l -10.409827,13.0199517 0,10.166766 c 0,0 -1.063812,0.70311 -2.174276,0.706574 -1.415968,0.0044 -2.093747,-0.706574 -2.093747,-0.706574 z"
+ id="path3025"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccscccsc" />
+ <ellipse
+ style="fill:url(#linearGradient4179);fill-opacity:1;stroke:#496b80;stroke-width:0.25479595999999999;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="path3795"
+ cx="8.1911592"
+ cy="19.131386"
+ rx="5.9163685"
+ ry="1.9535972"
+ d="m 14.107528,19.131386 c 0,1.078942 -2.648849,1.953597 -5.9163688,1.953597 -3.26752,0 -5.9163684,-0.874655 -5.9163684,-1.953597 0,-1.078942 2.6488484,-1.953597 5.9163684,-1.953597 3.2675198,0 5.9163688,0.874655 5.9163688,1.953597 z"
+ sodipodi:cx="8.1911592"
+ sodipodi:cy="19.131386"
+ sodipodi:rx="5.9163685"
+ sodipodi:ry="1.9535972"
+ transform="matrix(2.1063298,0,0,2.1009617,-2.5166687,-33.582356)" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer6"
+ inkscape:label="pencil" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer5"
+ inkscape:label="okulars" />
+</svg>
diff --git a/Viewer/images/font.svg b/Viewer/images/font.svg
new file mode 100644
index 0000000..15fd8bc
--- /dev/null
+++ b/Viewer/images/font.svg
@@ -0,0 +1,261 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="font.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient4458">
+ <stop
+ style="stop-color:#9d0000;stop-opacity:1;"
+ offset="0"
+ id="stop4460" />
+ <stop
+ style="stop-color:#f9798a;stop-opacity:1;"
+ offset="1"
+ id="stop4462" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient4450">
+ <stop
+ id="stop4466"
+ offset="0"
+ style="stop-color:#0d0d0d;stop-opacity:1" />
+ <stop
+ style="stop-color:#575757;stop-opacity:1;"
+ offset="1"
+ id="stop4454" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#519aed;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#e9dddd;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f1f3fb;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3614">
+ <stop
+ style="stop-color:#2c71d9;stop-opacity:1;"
+ offset="0"
+ id="stop3616" />
+ <stop
+ style="stop-color:#ececec;stop-opacity:1;"
+ offset="1"
+ id="stop3618" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3602">
+ <stop
+ style="stop-color:#f5f5f5;stop-opacity:1;"
+ offset="0"
+ id="stop3604" />
+ <stop
+ style="stop-color:#141bc6;stop-opacity:1;"
+ offset="1"
+ id="stop3606" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3614"
+ id="linearGradient3691"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="12.89746"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3602"
+ id="linearGradient3693"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="2.2337441"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3728"
+ id="linearGradient3710"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-31.566354,35.860667)"
+ x1="15.413333"
+ y1="3.4795053"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3756"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-31.566354,35.860667)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4450"
+ id="linearGradient4456"
+ x1="20.511225"
+ y1="17.405106"
+ x2="20.511225"
+ y2="33.786377"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-2.930175,2.0476578)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4458"
+ id="linearGradient4464"
+ x1="13.67415"
+ y1="20.476593"
+ x2="13.67415"
+ y2="-10.238296"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-1.9534501,4.0953192)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="8.0105659"
+ inkscape:cy="15.51908"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-grids="true"
+ inkscape:window-width="1408"
+ inkscape:window-height="1093"
+ inkscape:window-x="2094"
+ inkscape:window-y="31"
+ inkscape:window-maximized="0"
+ showguides="true"
+ inkscape:guide-bbox="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="bg"
+ style="display:inline" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <text
+ transform="scale(1.0238296,0.97672504)"
+ id="text3936"
+ y="27.643398"
+ x="-2.0521382e-09"
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:url(#linearGradient4464);fill-opacity:1;stroke:#650005;stroke-width:0.5;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;font-family:Times New Roman;-inkscape-font-specification:Times New Roman"
+ xml:space="preserve"><tspan
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:url(#linearGradient4464);fill-opacity:1;stroke:#650005;stroke-width:0.5;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;font-family:Times New Roman;-inkscape-font-specification:Times New Roman"
+ y="27.643398"
+ x="-2.0521382e-09"
+ id="tspan3938"
+ sodipodi:role="line">T</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:20px;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Calibri;-inkscape-font-specification:Calibri"
+ x="3.8399999"
+ y="21.973333"
+ id="text3783"><tspan
+ sodipodi:role="line"
+ id="tspan3785"
+ x="3.8399999"
+ y="21.973333" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="7.2533331"
+ y="15.146667"
+ id="text3787"><tspan
+ sodipodi:role="line"
+ id="tspan3789"
+ x="7.2533331"
+ y="15.146667" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:url(#linearGradient4456);fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;font-family:Times New Roman;-inkscape-font-specification:Times New Roman"
+ x="6.8370752"
+ y="31.738718"
+ id="text3791"
+ transform="scale(1.0238296,0.97672504)"><tspan
+ sodipodi:role="line"
+ id="tspan3793"
+ x="6.8370752"
+ y="31.738718"
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:url(#linearGradient4456);fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;font-family:Times New Roman;-inkscape-font-specification:Times New Roman">T</tspan></text>
+ </g>
+</svg>
diff --git a/Viewer/images/fontsize_down.svg b/Viewer/images/fontsize_down.svg
new file mode 100644
index 0000000..d9ff0a0
--- /dev/null
+++ b/Viewer/images/fontsize_down.svg
@@ -0,0 +1,215 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="fontsize_down.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#519aed;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#e9dddd;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f1f3fb;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3614">
+ <stop
+ style="stop-color:#2c71d9;stop-opacity:1;"
+ offset="0"
+ id="stop3616" />
+ <stop
+ style="stop-color:#ececec;stop-opacity:1;"
+ offset="1"
+ id="stop3618" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3602">
+ <stop
+ style="stop-color:#f5f5f5;stop-opacity:1;"
+ offset="0"
+ id="stop3604" />
+ <stop
+ style="stop-color:#141bc6;stop-opacity:1;"
+ offset="1"
+ id="stop3606" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3614"
+ id="linearGradient3691"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="12.89746"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3602"
+ id="linearGradient3693"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="2.2337441"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3728"
+ id="linearGradient3710"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-31.566354,35.860667)"
+ x1="15.413333"
+ y1="3.4795053"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3756"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-31.566354,35.860667)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="6.452936"
+ inkscape:cy="15.51908"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-grids="true"
+ inkscape:window-width="1408"
+ inkscape:window-height="1093"
+ inkscape:window-x="2094"
+ inkscape:window-y="31"
+ inkscape:window-maximized="0"
+ showguides="true"
+ inkscape:guide-bbox="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="bg"
+ style="display:inline" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <text
+ xml:space="preserve"
+ style="font-size:20px;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Calibri;-inkscape-font-specification:Calibri"
+ x="3.8399999"
+ y="21.973333"
+ id="text3783"><tspan
+ sodipodi:role="line"
+ id="tspan3785"
+ x="3.8399999"
+ y="21.973333" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="7.2533331"
+ y="15.146667"
+ id="text3787"><tspan
+ sodipodi:role="line"
+ id="tspan3789"
+ x="7.2533331"
+ y="15.146667" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:25.99999990999999966px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#1a1a1a;fill-opacity:1;stroke:none;font-family:Times New Roman;-inkscape-font-specification:Times New Roman"
+ x="1.9534501"
+ y="29.691059"
+ id="text3791"
+ transform="scale(1.0238296,0.97672504)"><tspan
+ sodipodi:role="line"
+ id="tspan3793"
+ x="1.9534501"
+ y="29.691059"
+ style="font-size:25.99999990999999966px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#1a1a1a;font-family:Times New Roman;-inkscape-font-specification:Times New Roman">A</tspan></text>
+ <path
+ style="fill:#003380;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline"
+ inkscape:transform-center-x="-0.034736359"
+ inkscape:transform-center-y="1.2991354"
+ d="m 17.48,2.6858153 5.424725,7.6608527 5.508608,-7.6608527 z"
+ id="path3006-1"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccc" />
+ </g>
+</svg>
diff --git a/Viewer/images/fontsize_up.svg b/Viewer/images/fontsize_up.svg
new file mode 100644
index 0000000..cf96f1a
--- /dev/null
+++ b/Viewer/images/fontsize_up.svg
@@ -0,0 +1,215 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="fontsize_up.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#519aed;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#e9dddd;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f1f3fb;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3614">
+ <stop
+ style="stop-color:#2c71d9;stop-opacity:1;"
+ offset="0"
+ id="stop3616" />
+ <stop
+ style="stop-color:#ececec;stop-opacity:1;"
+ offset="1"
+ id="stop3618" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3602">
+ <stop
+ style="stop-color:#f5f5f5;stop-opacity:1;"
+ offset="0"
+ id="stop3604" />
+ <stop
+ style="stop-color:#141bc6;stop-opacity:1;"
+ offset="1"
+ id="stop3606" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3614"
+ id="linearGradient3691"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="12.89746"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3602"
+ id="linearGradient3693"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="2.2337441"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3728"
+ id="linearGradient3710"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-31.566354,35.860667)"
+ x1="15.413333"
+ y1="3.4795053"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3756"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-31.566354,35.860667)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="14.692936"
+ inkscape:cy="15.545747"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-grids="true"
+ inkscape:window-width="1408"
+ inkscape:window-height="1093"
+ inkscape:window-x="454"
+ inkscape:window-y="83"
+ inkscape:window-maximized="0"
+ showguides="true"
+ inkscape:guide-bbox="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="bg"
+ style="display:inline" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <text
+ xml:space="preserve"
+ style="font-size:20px;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Calibri;-inkscape-font-specification:Calibri"
+ x="3.8399999"
+ y="21.973333"
+ id="text3783"><tspan
+ sodipodi:role="line"
+ id="tspan3785"
+ x="3.8399999"
+ y="21.973333" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="7.2533331"
+ y="15.146667"
+ id="text3787"><tspan
+ sodipodi:role="line"
+ id="tspan3789"
+ x="7.2533331"
+ y="15.146667" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:34px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#1a1a1a;fill-opacity:1;stroke:none;font-family:Times New Roman;-inkscape-font-specification:Times New Roman"
+ x="0.97672504"
+ y="29.691059"
+ id="text3791"
+ transform="scale(1.0238296,0.97672504)"><tspan
+ sodipodi:role="line"
+ id="tspan3793"
+ x="0.97672504"
+ y="29.691059"
+ style="font-size:34px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#1a1a1a;font-family:Times New Roman;-inkscape-font-specification:Times New Roman">A</tspan></text>
+ <path
+ style="fill:#003380;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline"
+ inkscape:transform-center-x="-0.034736359"
+ inkscape:transform-center-y="-1.2991354"
+ d="M 20.146667,8.893335 25.571392,1.2324821 31.08,8.893335 z"
+ id="path3006-1"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccc" />
+ </g>
+</svg>
diff --git a/Viewer/images/genvar.svg b/Viewer/images/genvar.svg
new file mode 100644
index 0000000..5950cfc
--- /dev/null
+++ b/Viewer/images/genvar.svg
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="genvar.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#519aed;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#e9dddd;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f1f3fb;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3614">
+ <stop
+ style="stop-color:#e8f0fb;stop-opacity:1;"
+ offset="0"
+ id="stop3616" />
+ <stop
+ style="stop-color:#ececec;stop-opacity:1;"
+ offset="1"
+ id="stop3618" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3602">
+ <stop
+ style="stop-color:#f5f5f5;stop-opacity:1;"
+ offset="0"
+ id="stop3604" />
+ <stop
+ style="stop-color:#141bc6;stop-opacity:1;"
+ offset="1"
+ id="stop3606" />
+ </linearGradient>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="13.651379"
+ inkscape:cy="15.420625"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1408"
+ inkscape:window-height="1096"
+ inkscape:window-x="415"
+ inkscape:window-y="209"
+ inkscape:window-maximized="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="circle"
+ style="display:inline" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="top">
+ <path
+ sodipodi:type="arc"
+ style="fill:#f6f8fa;fill-opacity:1;stroke:#919191;stroke-width:1.21152616;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path3786"
+ sodipodi:cx="16.213333"
+ sodipodi:cy="17.973333"
+ sodipodi:rx="13.973333"
+ sodipodi:ry="13.706667"
+ d="m 30.186666,17.973333 a 13.973333,13.706667 0 1 1 -27.9466662,0 13.973333,13.706667 0 1 1 27.9466662,0 z"
+ transform="matrix(1.0627385,0,0,1.0834144,-1.4205346,-3.4425622)" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <text
+ xml:space="preserve"
+ style="font-size:20;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Calibri;-inkscape-font-specification:Calibri"
+ x="3.8399999"
+ y="21.973333"
+ id="text3783"><tspan
+ sodipodi:role="line"
+ id="tspan3785"
+ x="3.8399999"
+ y="21.973333" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="7.2533331"
+ y="15.146667"
+ id="text3787"><tspan
+ sodipodi:role="line"
+ id="tspan3789"
+ x="7.2533331"
+ y="15.146667" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:26px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#007330;fill-opacity:1;stroke:none;font-family:Arial;-inkscape-font-specification:Arial Bold"
+ x="5.4933324"
+ y="25.173332"
+ id="text3791"><tspan
+ sodipodi:role="line"
+ id="tspan3793"
+ x="5.4933324"
+ y="25.173332"
+ style="font-size:26px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#007330;font-family:Arial;-inkscape-font-specification:Arial Bold;fill-opacity:1">G</tspan></text>
+ </g>
+</svg>
diff --git a/Viewer/images/genvar_shadow.svg b/Viewer/images/genvar_shadow.svg
new file mode 100644
index 0000000..c8e66d0
--- /dev/null
+++ b/Viewer/images/genvar_shadow.svg
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="genvar_shadow.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#519aed;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#e9dddd;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f1f3fb;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3614">
+ <stop
+ style="stop-color:#e8f0fb;stop-opacity:1;"
+ offset="0"
+ id="stop3616" />
+ <stop
+ style="stop-color:#ececec;stop-opacity:1;"
+ offset="1"
+ id="stop3618" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3602">
+ <stop
+ style="stop-color:#f5f5f5;stop-opacity:1;"
+ offset="0"
+ id="stop3604" />
+ <stop
+ style="stop-color:#141bc6;stop-opacity:1;"
+ offset="1"
+ id="stop3606" />
+ </linearGradient>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="5.091379"
+ inkscape:cy="15.420625"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1408"
+ inkscape:window-height="1096"
+ inkscape:window-x="415"
+ inkscape:window-y="36"
+ inkscape:window-maximized="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="circle"
+ style="display:inline" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="top">
+ <path
+ sodipodi:type="arc"
+ style="fill:#f6f8fa;fill-opacity:1;stroke:#919191;stroke-width:1.21152616000000002;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path3786"
+ sodipodi:cx="16.213333"
+ sodipodi:cy="17.973333"
+ sodipodi:rx="13.973333"
+ sodipodi:ry="13.706667"
+ d="m 30.186666,17.973333 a 13.973333,13.706667 0 1 1 -27.9466662,0 13.973333,13.706667 0 1 1 27.9466662,0 z"
+ transform="matrix(1.0627385,0,0,1.0834144,-1.4205346,-3.4425622)" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <text
+ xml:space="preserve"
+ style="font-size:20;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Calibri;-inkscape-font-specification:Calibri"
+ x="3.8399999"
+ y="21.973333"
+ id="text3783"><tspan
+ sodipodi:role="line"
+ id="tspan3785"
+ x="3.8399999"
+ y="21.973333" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="7.2533331"
+ y="15.146667"
+ id="text3787"><tspan
+ sodipodi:role="line"
+ id="tspan3789"
+ x="7.2533331"
+ y="15.146667" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:26px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#919191;fill-opacity:1;stroke:none;font-family:Arial;-inkscape-font-specification:Arial Bold"
+ x="5.4933324"
+ y="25.173332"
+ id="text3791"><tspan
+ sodipodi:role="line"
+ id="tspan3793"
+ x="5.4933324"
+ y="25.173332"
+ style="font-size:26px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#919191;font-family:Arial;-inkscape-font-specification:Arial Bold;fill-opacity:1">G</tspan></text>
+ </g>
+</svg>
diff --git a/Viewer/images/goto_line.svg b/Viewer/images/goto_line.svg
new file mode 100644
index 0000000..07776d9
--- /dev/null
+++ b/Viewer/images/goto_line.svg
@@ -0,0 +1,321 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="goto_line.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3792">
+ <stop
+ style="stop-color:#eceded;stop-opacity:1;"
+ offset="0"
+ id="stop3794" />
+ <stop
+ style="stop-color:#b5c6d0;stop-opacity:1;"
+ offset="1"
+ id="stop3796" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3804">
+ <stop
+ style="stop-color:#464c90;stop-opacity:1;"
+ offset="0"
+ id="stop3806" />
+ <stop
+ style="stop-color:#355560;stop-opacity:1;"
+ offset="1"
+ id="stop3808" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3796">
+ <stop
+ style="stop-color:#545d96;stop-opacity:1;"
+ offset="0"
+ id="stop3798" />
+ <stop
+ style="stop-color:#76a1ab;stop-opacity:1;"
+ offset="1"
+ id="stop3800" />
+ </linearGradient>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 16 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="32 : 16 : 1"
+ inkscape:persp3d-origin="16 : 10.666667 : 1"
+ id="perspective35" />
+ <linearGradient
+ id="linearGradient3852">
+ <stop
+ style="stop-color:#467b3c;stop-opacity:1;"
+ offset="0"
+ id="stop3854" />
+ <stop
+ style="stop-color:#3d9f3d;stop-opacity:0.99215686;"
+ offset="1"
+ id="stop3856" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3799">
+ <stop
+ style="stop-color:#aae1be;stop-opacity:1;"
+ offset="0"
+ id="stop3801" />
+ <stop
+ style="stop-color:#4bc82b;stop-opacity:1;"
+ offset="1"
+ id="stop3803" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3777">
+ <stop
+ style="stop-color:#5b7db3;stop-opacity:1;"
+ offset="0"
+ id="stop3779" />
+ <stop
+ style="stop-color:#2589ce;stop-opacity:1;"
+ offset="1"
+ id="stop3781" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#519aed;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#e9dddd;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f1f3fb;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3728"
+ id="linearGradient3710"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.37353112,0,0,-0.42267705,0.93672357,33.214358)"
+ x1="15.413333"
+ y1="3.4795053"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3756"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.37353112,0,0,-0.42267705,0.93672357,33.214358)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3777"
+ id="linearGradient3783"
+ x1="1.4276053"
+ y1="16.374115"
+ x2="28.440672"
+ y2="16.374115"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0279887,0,0,1.0323478,7.1553463,-2.2096664)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3799"
+ id="linearGradient3834"
+ x1="-9.2158766"
+ y1="17.617861"
+ x2="36.303471"
+ y2="17.617861"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3852"
+ id="linearGradient3858"
+ x1="4.4050612"
+ y1="16.300755"
+ x2="23.3321"
+ y2="16.521189"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.96778437,0,0,0.96778437,1.3383248,1.0794304)" />
+ <inkscape:perspective
+ id="perspective2935"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4026"
+ id="linearGradient4032"
+ x1="16.804222"
+ y1="14.95285"
+ x2="27.970543"
+ y2="14.95285"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.7702794,0,0,1.4225865,-38.983045,1.405527)" />
+ <linearGradient
+ id="linearGradient4026">
+ <stop
+ style="stop-color:#f30e1e;stop-opacity:1;"
+ offset="0"
+ id="stop4028" />
+ <stop
+ style="stop-color:#ba2f39;stop-opacity:1;"
+ offset="1"
+ id="stop4030" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3975">
+ <stop
+ style="stop-color:#565c64;stop-opacity:1;"
+ offset="0"
+ id="stop3977" />
+ <stop
+ style="stop-color:#99a4b4;stop-opacity:1;"
+ offset="1"
+ id="stop3979" />
+ </linearGradient>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="52.3125"
+ inkscape:cx="10.091007"
+ inkscape:cy="7.64483"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1920"
+ inkscape:window-height="1137"
+ inkscape:window-x="-2"
+ inkscape:window-y="-3"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="circle"
+ style="display:inline"
+ transform="translate(0,-16)">
+ <path
+ style="fill:url(#linearGradient3710);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3720);stroke-width:0.38534608;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ d="m 1.9478697,28.248642 c -0.7129992,2.185353 -0.3564995,1.092675 0,0 z"
+ id="path3695"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <text
+ xml:space="preserve"
+ style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#3771c8;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="4.0908003"
+ y="25.06093"
+ id="text3025"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3027"
+ x="4.0908003"
+ y="25.06093" /></text>
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline"
+ transform="translate(0,-16)">
+ <path
+ style="fill:#333333;fill-opacity:1;stroke:#333333;stroke-width:0.59133035000000000;display:inline"
+ d="m 10.956915,21.42206 0.737195,-0.630326 3.220477,2.530109 -0.252689,0.568367 -0.675153,0.32092 z"
+ id="path3794"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccc" />
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#4d4d4d;stroke-width:0.82214545999999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.29999995000000013;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ id="path3869"
+ sodipodi:cx="-3.3759081"
+ sodipodi:cy="15.175204"
+ sodipodi:rx="2.6094856"
+ sodipodi:ry="1.2408743"
+ d="m -0.76642251,15.175204 a 2.6094856,1.2408743 0 1 1 -5.21897129,0 2.6094856,1.2408743 0 1 1 5.21897129,0 z"
+ transform="matrix(1.1372418,-0.06686365,0.15743711,2.1920599,10.68177,-13.951754)" />
+ <text
+ xml:space="preserve"
+ style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="-0.53524494"
+ y="30.60454"
+ id="text3069"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3071"
+ x="-0.53524494"
+ y="30.60454">123</tspan></text>
+ </g>
+</svg>
diff --git a/Viewer/images/grey_info.svg b/Viewer/images/grey_info.svg
new file mode 100644
index 0000000..9e0f4c1
--- /dev/null
+++ b/Viewer/images/grey_info.svg
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="grey_info.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#519aed;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#e9dddd;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f1f3fb;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3614">
+ <stop
+ style="stop-color:#2c71d9;stop-opacity:1;"
+ offset="0"
+ id="stop3616" />
+ <stop
+ style="stop-color:#ececec;stop-opacity:1;"
+ offset="1"
+ id="stop3618" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3602">
+ <stop
+ style="stop-color:#f5f5f5;stop-opacity:1;"
+ offset="0"
+ id="stop3604" />
+ <stop
+ style="stop-color:#141bc6;stop-opacity:1;"
+ offset="1"
+ id="stop3606" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3614"
+ id="linearGradient3691"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="12.89746"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3602"
+ id="linearGradient3693"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="2.2337441"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3728"
+ id="linearGradient3710"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-31.566354,35.860667)"
+ x1="15.413333"
+ y1="3.4795053"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3756"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-31.566354,35.860667)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="18.610523"
+ inkscape:cy="15.420625"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1408"
+ inkscape:window-height="1096"
+ inkscape:window-x="504"
+ inkscape:window-y="14"
+ inkscape:window-maximized="0"
+ showguides="true"
+ inkscape:guide-bbox="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="bg"
+ style="display:inline" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <text
+ xml:space="preserve"
+ style="font-size:20px;font-style:normal;font-weight:normal;fill:#4d4d4d;fill-opacity:1;stroke:none;font-family:Calibri;-inkscape-font-specification:Calibri"
+ x="3.8399999"
+ y="21.973333"
+ id="text3783"><tspan
+ sodipodi:role="line"
+ id="tspan3785"
+ x="3.8399999"
+ y="21.973333" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;fill:#4d4d4d;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="7.2533331"
+ y="15.146667"
+ id="text3787"><tspan
+ sodipodi:role="line"
+ id="tspan3789"
+ x="7.2533331"
+ y="15.146667" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:34.41847229px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#666666;fill-opacity:1;stroke:none;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif"
+ x="9.6788568"
+ y="28.832951"
+ id="text3791"
+ transform="scale(0.99356261,1.0064791)"><tspan
+ sodipodi:role="line"
+ id="tspan3793"
+ x="9.6788568"
+ y="28.832951"
+ style="font-size:34.41847229px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#666666;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif">i</tspan></text>
+ </g>
+</svg>
diff --git a/Viewer/images/icon_Apply.png b/Viewer/images/icon_Apply.png
new file mode 100644
index 0000000..0be4f1c
Binary files /dev/null and b/Viewer/images/icon_Apply.png differ
diff --git a/Viewer/images/icon_Chat.png b/Viewer/images/icon_Chat.png
new file mode 100644
index 0000000..f64dcef
Binary files /dev/null and b/Viewer/images/icon_Chat.png differ
diff --git a/Viewer/images/icon_Check.png b/Viewer/images/icon_Check.png
new file mode 100644
index 0000000..f5a3079
Binary files /dev/null and b/Viewer/images/icon_Check.png differ
diff --git a/Viewer/images/icon_Complete.png b/Viewer/images/icon_Complete.png
new file mode 100644
index 0000000..5acd05a
Binary files /dev/null and b/Viewer/images/icon_Complete.png differ
diff --git a/Viewer/images/icon_Edit.png b/Viewer/images/icon_Edit.png
new file mode 100644
index 0000000..87defd0
Binary files /dev/null and b/Viewer/images/icon_Edit.png differ
diff --git a/Viewer/images/icon_Info.png b/Viewer/images/icon_Info.png
new file mode 100644
index 0000000..5953fcd
Binary files /dev/null and b/Viewer/images/icon_Info.png differ
diff --git a/Viewer/images/icon_Jobstatus.png b/Viewer/images/icon_Jobstatus.png
new file mode 100644
index 0000000..5caf0fa
Binary files /dev/null and b/Viewer/images/icon_Jobstatus.png differ
diff --git a/Viewer/images/icon_Josstatus3.png b/Viewer/images/icon_Josstatus3.png
new file mode 100644
index 0000000..5caf0fa
Binary files /dev/null and b/Viewer/images/icon_Josstatus3.png differ
diff --git a/Viewer/images/icon_Load.png b/Viewer/images/icon_Load.png
new file mode 100644
index 0000000..5d3d18f
Binary files /dev/null and b/Viewer/images/icon_Load.png differ
diff --git a/Viewer/images/icon_Manual.png b/Viewer/images/icon_Manual.png
new file mode 100644
index 0000000..b67529f
Binary files /dev/null and b/Viewer/images/icon_Manual.png differ
diff --git a/Viewer/images/icon_Merge.png b/Viewer/images/icon_Merge.png
new file mode 100644
index 0000000..29e1755
Binary files /dev/null and b/Viewer/images/icon_Merge.png differ
diff --git a/Viewer/images/icon_Messages.png b/Viewer/images/icon_Messages.png
new file mode 100644
index 0000000..8d14ec0
Binary files /dev/null and b/Viewer/images/icon_Messages.png differ
diff --git a/Viewer/images/icon_Output.png b/Viewer/images/icon_Output.png
new file mode 100644
index 0000000..13986d8
Binary files /dev/null and b/Viewer/images/icon_Output.png differ
diff --git a/Viewer/images/icon_QuickFind.png b/Viewer/images/icon_QuickFind.png
new file mode 100644
index 0000000..02568d7
Binary files /dev/null and b/Viewer/images/icon_QuickFind.png differ
diff --git a/Viewer/images/icon_Script.png b/Viewer/images/icon_Script.png
new file mode 100644
index 0000000..64f0d77
Binary files /dev/null and b/Viewer/images/icon_Script.png differ
diff --git a/Viewer/images/icon_Search.png b/Viewer/images/icon_Search.png
new file mode 100644
index 0000000..f0f1c68
Binary files /dev/null and b/Viewer/images/icon_Search.png differ
diff --git a/Viewer/images/icon_Status.png b/Viewer/images/icon_Status.png
new file mode 100644
index 0000000..4ea2035
Binary files /dev/null and b/Viewer/images/icon_Status.png differ
diff --git a/Viewer/images/icon_Submit.png b/Viewer/images/icon_Submit.png
new file mode 100644
index 0000000..0be4f1c
Binary files /dev/null and b/Viewer/images/icon_Submit.png differ
diff --git a/Viewer/images/icon_Time_line.png b/Viewer/images/icon_Time_line.png
new file mode 100644
index 0000000..8c6ad76
Binary files /dev/null and b/Viewer/images/icon_Time_line.png differ
diff --git a/Viewer/images/icon_Triggers.png b/Viewer/images/icon_Triggers.png
new file mode 100644
index 0000000..0c7c992
Binary files /dev/null and b/Viewer/images/icon_Triggers.png differ
diff --git a/Viewer/images/icon_Update.png b/Viewer/images/icon_Update.png
new file mode 100644
index 0000000..4ea2035
Binary files /dev/null and b/Viewer/images/icon_Update.png differ
diff --git a/Viewer/images/icon_Use_external_editor.png b/Viewer/images/icon_Use_external_editor.png
new file mode 100644
index 0000000..c57a9fa
Binary files /dev/null and b/Viewer/images/icon_Use_external_editor.png differ
diff --git a/Viewer/images/icon_Use_external_viewer.png b/Viewer/images/icon_Use_external_viewer.png
new file mode 100644
index 0000000..4425675
Binary files /dev/null and b/Viewer/images/icon_Use_external_viewer.png differ
diff --git a/Viewer/images/icon_Variables.png b/Viewer/images/icon_Variables.png
new file mode 100644
index 0000000..714bcae
Binary files /dev/null and b/Viewer/images/icon_Variables.png differ
diff --git a/Viewer/images/icon_W.png b/Viewer/images/icon_W.png
new file mode 100644
index 0000000..74ac3e3
Binary files /dev/null and b/Viewer/images/icon_W.png differ
diff --git a/Viewer/images/icon_Why_.png b/Viewer/images/icon_Why_.png
new file mode 100644
index 0000000..b1f39cb
Binary files /dev/null and b/Viewer/images/icon_Why_.png differ
diff --git a/Viewer/images/icon_Z.png b/Viewer/images/icon_Z.png
new file mode 100644
index 0000000..74ac3e3
Binary files /dev/null and b/Viewer/images/icon_Z.png differ
diff --git a/Viewer/images/icon_Zbw.png b/Viewer/images/icon_Zbw.png
new file mode 100644
index 0000000..5543ea2
Binary files /dev/null and b/Viewer/images/icon_Zbw.png differ
diff --git a/Viewer/images/icon_calendar.png b/Viewer/images/icon_calendar.png
new file mode 100644
index 0000000..5c32e14
Binary files /dev/null and b/Viewer/images/icon_calendar.png differ
diff --git a/Viewer/images/icon_calendar.svg b/Viewer/images/icon_calendar.svg
new file mode 100644
index 0000000..f8cdb3c
--- /dev/null
+++ b/Viewer/images/icon_calendar.svg
@@ -0,0 +1,259 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="icon_calendar.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient6055">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="0"
+ id="stop6057" />
+ <stop
+ style="stop-color:#cbd4d9;stop-opacity:1;"
+ offset="1"
+ id="stop6059" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3852">
+ <stop
+ style="stop-color:#467b3c;stop-opacity:1;"
+ offset="0"
+ id="stop3854" />
+ <stop
+ style="stop-color:#3d9f3d;stop-opacity:0.99215686;"
+ offset="1"
+ id="stop3856" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3799">
+ <stop
+ style="stop-color:#aae1be;stop-opacity:1;"
+ offset="0"
+ id="stop3801" />
+ <stop
+ style="stop-color:#4bc82b;stop-opacity:1;"
+ offset="1"
+ id="stop3803" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3777">
+ <stop
+ style="stop-color:#0000ad;stop-opacity:1;"
+ offset="0"
+ id="stop3779" />
+ <stop
+ style="stop-color:#25d4ce;stop-opacity:1;"
+ offset="1"
+ id="stop3781" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#519aed;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#e9dddd;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f1f3fb;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3756"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.88279702,0,0,-1.0105621,2.7743457,34.895728)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3777"
+ id="linearGradient3783"
+ x1="1.4276053"
+ y1="16.374115"
+ x2="28.440671"
+ y2="16.374115"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0279887,0,0,1.0323478,7.1553463,-2.2096664)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient6055"
+ id="linearGradient6061"
+ x1="9.7600002"
+ y1="11.440001"
+ x2="32.959999"
+ y2="32.613335"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,1.12,0,-3.6095999)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="-1.2599566"
+ inkscape:cy="22.41561"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1920"
+ inkscape:window-height="1180"
+ inkscape:window-x="1916"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="circle"
+ style="display:inline">
+ <path
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3720);stroke-width:0.8456015;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ d="m 5.1640711,23.023394 c -1.6850903,5.224878 -0.8425452,2.612439 0,0 z"
+ id="path3695"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <rect
+ style="fill:#2d5174;fill-opacity:1;stroke:#686a87;stroke-width:0.9991532;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="rect4761"
+ width="30.774178"
+ height="30.720846"
+ x="0.63957727"
+ y="0.69290954" />
+ <path
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="M 21.887527,7.9373138 16.534793,16.63409 23.920839,15.480913 21.887527,7.9373138 Z"
+ id="path3872"
+ sodipodi:nodetypes="cccc"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-opacity:1;stroke:none"
+ d="M 14.533471,8.9060541 C 8.2079362,9.1010972 3.6985983,17.245653 8.9625445,23.464877 c 0.6417572,0.649273 3.0961365,2.317423 5.9858475,2.090667 4.846913,-0.334747 5.82096,-2.604808 5.437706,-2.69223 -0.966571,-0.220478 -0.944161,1.46117 -5.283272,1.730373 -6.4743292,-1.026823 -9.0484989,-8.479802 -3.559668,-12.579096 1.283705,-0.804623 2.485688,-1.312893 3.733094,-1.378671 1.46846,-0.07743 2.99987,0.458344 4.801649,1.845738 -0.309881,-2.281746 -2.668157,-3.2969391 -5.54443,-3.57 [...]
+ id="path3844"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccsccscc" />
+ <rect
+ style="fill:url(#linearGradient6061);fill-opacity:1;stroke:none"
+ id="rect5394"
+ width="27.626667"
+ height="22.400003"
+ x="2.2400002"
+ y="7.6800003" />
+ <text
+ xml:space="preserve"
+ style="font-size:18.66187477px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:sans-serif"
+ x="10.909545"
+ y="25.874834"
+ id="text5398"
+ sodipodi:linespacing="125%"
+ transform="scale(1.0107356,0.98937842)"><tspan
+ sodipodi:role="line"
+ id="tspan5400"
+ x="10.909545"
+ y="25.874834">7</tspan></text>
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot4638"
+ style="fill:black;stroke:none;stroke-opacity:1;stroke-width:1px;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:1;font-style:normal;font-weight:normal;font-size:9;-inkscape-font-specification:Courier New KOI-8;font-family:Courier New KOI-8;line-height:125%;letter-spacing:0px;word-spacing:0px"><flowRegion
+ id="flowRegion4640"><rect
+ id="rect4642"
+ width="37.919998"
+ height="11.146667"
+ x="-7.3066669"
+ y="-12" /></flowRegion><flowPara
+ id="flowPara4644" /></flowRoot> </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="top"
+ style="display:none"
+ sodipodi:insensitive="true">
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#2f6ab7;stroke-width:1.24076998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path3786"
+ sodipodi:cx="16.213333"
+ sodipodi:cy="17.973333"
+ sodipodi:rx="13.973333"
+ sodipodi:ry="13.706667"
+ d="m 30.186666,17.973333 a 13.973333,13.706667 0 1 1 -27.9466662,0 13.973333,13.706667 0 1 1 27.9466662,0 z"
+ transform="matrix(1.0376908,0,0,1.0578794,-0.937761,-2.9536141)" />
+ </g>
+</svg>
diff --git a/Viewer/images/icon_clock.png b/Viewer/images/icon_clock.png
new file mode 100644
index 0000000..8c6ad76
Binary files /dev/null and b/Viewer/images/icon_clock.png differ
diff --git a/Viewer/images/icon_clock.svg b/Viewer/images/icon_clock.svg
new file mode 100644
index 0000000..2024967
--- /dev/null
+++ b/Viewer/images/icon_clock.svg
@@ -0,0 +1,283 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="icon_clock.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient5467">
+ <stop
+ style="stop-color:#cbd4d9;stop-opacity:1;"
+ offset="0"
+ id="stop5469" />
+ <stop
+ style="stop-color:#fefeff;stop-opacity:1"
+ offset="1"
+ id="stop5471" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3852">
+ <stop
+ style="stop-color:#467b3c;stop-opacity:1;"
+ offset="0"
+ id="stop3854" />
+ <stop
+ style="stop-color:#3d9f3d;stop-opacity:0.99215686;"
+ offset="1"
+ id="stop3856" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3799">
+ <stop
+ style="stop-color:#aae1be;stop-opacity:1;"
+ offset="0"
+ id="stop3801" />
+ <stop
+ style="stop-color:#4bc82b;stop-opacity:1;"
+ offset="1"
+ id="stop3803" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3777">
+ <stop
+ style="stop-color:#0000ad;stop-opacity:1;"
+ offset="0"
+ id="stop3779" />
+ <stop
+ style="stop-color:#25d4ce;stop-opacity:1;"
+ offset="1"
+ id="stop3781" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#519aed;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#e9dddd;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f1f3fb;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3756"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.88279702,0,0,-1.0105621,-30.345654,34.149061)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3777"
+ id="linearGradient3783"
+ x1="1.4276053"
+ y1="16.374115"
+ x2="28.440671"
+ y2="16.374115"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0279887,0,0,1.0323478,7.1553463,-2.2096664)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5467"
+ id="linearGradient5473"
+ x1="28.637709"
+ y1="25.693333"
+ x2="13.30896"
+ y2="7.4533324"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(0,-0.10666667)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="7.7533767"
+ inkscape:cy="18.839911"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1920"
+ inkscape:window-height="1180"
+ inkscape:window-x="1916"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="circle"
+ style="display:inline">
+ <path
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3720);stroke-width:0.8456015;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ d="m -27.955929,22.276727 c -1.68509,5.224878 -0.842545,2.612439 0,0 z"
+ id="path3695"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <rect
+ style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect5394"
+ width="27.626667"
+ height="20.000002"
+ x="-30.879999"
+ y="9.333333" />
+ <circle
+ style="fill:url(#linearGradient5473);fill-opacity:1;stroke:#323232;stroke-width:1.96003901999999997;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path5406"
+ cx="15.906668"
+ cy="16.093332"
+ r="14.715606" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#323232;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 20.533334,4.7466667 -4.58667,11.7866663 7.893333,4.479997"
+ id="path5408"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc" />
+ <ellipse
+ style="fill:#323232;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path5410"
+ cx="15.786667"
+ cy="16.346666"
+ rx="1.8666667"
+ ry="1.8933332" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#323232;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="m 1.28,16.266666 4.5866667,0"
+ id="path5412"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path5414"
+ d="m 26.453334,16.16 4.32,0.05333"
+ style="fill:none;fill-rule:evenodd;stroke:#323232;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#323232;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="m 15.84,27.146666 c 0,3.84 0,3.84 0,3.84"
+ id="path5416"
+ inkscape:connector-curvature="0"
+ inkscape:transform-center-x="-1.0666667"
+ inkscape:transform-center-y="-3.7866667" />
+ <path
+ style="display:inline;fill:none;fill-rule:evenodd;stroke:#323232;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="m 15.733334,1.5466666 c 0,3.8399997 0,3.8399997 0,3.8399997"
+ id="path5416-9"
+ inkscape:connector-curvature="0"
+ inkscape:transform-center-x="-1.0666667"
+ inkscape:transform-center-y="-3.7866667" />
+ <path
+ style="display:inline;fill:#323232;fill-rule:evenodd;stroke:#323232;stroke-width:1.0427953px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1"
+ d="M 5.1434038,6.267176 C 7.3365971,8.2394907 7.3365971,8.2394907 7.3365971,8.2394907"
+ id="path5412-5"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path5448"
+ d="m 23.756737,23.813843 c 2.193193,1.972314 2.193193,1.972314 2.193193,1.972314"
+ style="display:inline;fill:none;fill-rule:evenodd;stroke:#323232;stroke-width:1.0427953px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ style="display:inline;fill:#323232;fill-opacity:1;fill-rule:evenodd;stroke:#323232;stroke-width:1.0427953px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 8.1328247,23.756737 C 6.1605096,25.94993 6.1605096,25.94993 6.1605096,25.94993"
+ id="path5412-5-2"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path5465"
+ d="m 25.199491,5.9434036 c -1.972315,2.193193 -1.972315,2.193193 -1.972315,2.193193"
+ style="display:inline;fill:#323232;fill-opacity:1;fill-rule:evenodd;stroke:#323232;stroke-width:1.0427953px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="top"
+ style="display:none"
+ sodipodi:insensitive="true">
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#2f6ab7;stroke-width:1.24076998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path3786"
+ sodipodi:cx="16.213333"
+ sodipodi:cy="17.973333"
+ sodipodi:rx="13.973333"
+ sodipodi:ry="13.706667"
+ d="m 30.186666,17.973333 a 13.973333,13.706667 0 1 1 -27.9466662,0 13.973333,13.706667 0 1 1 27.9466662,0 z"
+ transform="matrix(1.0376908,0,0,1.0578794,-0.937761,-2.9536141)" />
+ </g>
+</svg>
diff --git a/Viewer/images/icon_complete.png b/Viewer/images/icon_complete.png
new file mode 100644
index 0000000..5acd05a
Binary files /dev/null and b/Viewer/images/icon_complete.png differ
diff --git a/Viewer/images/icon_complete.svg b/Viewer/images/icon_complete.svg
new file mode 100644
index 0000000..24c22db
--- /dev/null
+++ b/Viewer/images/icon_complete.svg
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="icon_complete.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient5324">
+ <stop
+ style="stop-color:#7cbd17;stop-opacity:1;"
+ offset="0"
+ id="stop5326" />
+ <stop
+ style="stop-color:#b1e060;stop-opacity:1;"
+ offset="1"
+ id="stop5328" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5324"
+ id="linearGradient5330"
+ x1="18.005625"
+ y1="26.582415"
+ x2="10.748308"
+ y2="7.0853157"
+ gradientUnits="userSpaceOnUse" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="16.15625"
+ inkscape:cx="19.957224"
+ inkscape:cy="15.790581"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-to-guides="false"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1920"
+ inkscape:window-height="1180"
+ inkscape:window-x="1916"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2985"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="Layer"
+ style="display:inline">
+ <circle
+ style="fill:url(#linearGradient5330);fill-opacity:1;fill-rule:evenodd;stroke:#136922;stroke-width:1.50000000000000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path3346"
+ cx="15.955303"
+ cy="16.060171"
+ r="14.963701" />
+ <path
+ style="fill:#ffffff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 8.8665378,13.071566 C 8.6286267,13 5,17 5.13658,17.000004 c 2.7645077,2.745675 5.956143,5.432548 8.791853,8.104445 L 27.032309,11.649205 23.433269,8.44294 14,19.404256"
+ id="path4146"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccc" />
+ </g>
+</svg>
diff --git a/Viewer/images/icon_defstatus.png b/Viewer/images/icon_defstatus.png
new file mode 100644
index 0000000..81255b2
Binary files /dev/null and b/Viewer/images/icon_defstatus.png differ
diff --git a/Viewer/images/icon_folded.png b/Viewer/images/icon_folded.png
new file mode 100644
index 0000000..38b87fc
Binary files /dev/null and b/Viewer/images/icon_folded.png differ
diff --git a/Viewer/images/icon_late.png b/Viewer/images/icon_late.png
new file mode 100644
index 0000000..f4fabef
Binary files /dev/null and b/Viewer/images/icon_late.png differ
diff --git a/Viewer/images/icon_late.svg b/Viewer/images/icon_late.svg
new file mode 100644
index 0000000..a85f106
--- /dev/null
+++ b/Viewer/images/icon_late.svg
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="icon_late.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3753">
+ <stop
+ style="stop-color:#ffbc91;stop-opacity:1"
+ offset="0"
+ id="stop3755" />
+ <stop
+ style="stop-color:#ffe9db;stop-opacity:1;"
+ offset="1"
+ id="stop3757" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3753"
+ id="linearGradient3759"
+ x1="8.5794878"
+ y1="6.7143216"
+ x2="16.095942"
+ y2="20.866665"
+ gradientUnits="userSpaceOnUse" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="16.15625"
+ inkscape:cx="-12.50538"
+ inkscape:cy="14.520078"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-to-guides="true"
+ inkscape:snap-grids="true"
+ inkscape:window-width="1572"
+ inkscape:window-height="912"
+ inkscape:window-x="1987"
+ inkscape:window-y="29"
+ inkscape:window-maximized="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2985"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="Layer"
+ style="display:inline">
+ <circle
+ style="fill:url(#linearGradient3759);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.50643370000000010;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="path3346"
+ cx="16.144112"
+ cy="16.057049"
+ r="13.950898"
+ sodipodi:cx="16.144112"
+ sodipodi:cy="16.057049"
+ sodipodi:rx="13.950898"
+ sodipodi:ry="13.950898"
+ transform="matrix(1.0643318,0,0,1.0598951,-1.1314221,-1.1164768)" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2.4000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="m 15.690522,6.4332689 0,11.0000001 6,4"
+ id="path4148"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc" />
+ </g>
+</svg>
diff --git a/Viewer/images/icon_limit0.png b/Viewer/images/icon_limit0.png
new file mode 100644
index 0000000..95ffb12
Binary files /dev/null and b/Viewer/images/icon_limit0.png differ
diff --git a/Viewer/images/icon_limit1.png b/Viewer/images/icon_limit1.png
new file mode 100644
index 0000000..f5b35df
Binary files /dev/null and b/Viewer/images/icon_limit1.png differ
diff --git a/Viewer/images/icon_limit2.png b/Viewer/images/icon_limit2.png
new file mode 100644
index 0000000..f81788a
Binary files /dev/null and b/Viewer/images/icon_limit2.png differ
diff --git a/Viewer/images/icon_locked.png b/Viewer/images/icon_locked.png
new file mode 100644
index 0000000..73831b4
Binary files /dev/null and b/Viewer/images/icon_locked.png differ
diff --git a/Viewer/images/icon_memo.png b/Viewer/images/icon_memo.png
new file mode 100644
index 0000000..820b384
Binary files /dev/null and b/Viewer/images/icon_memo.png differ
diff --git a/Viewer/images/icon_message.png b/Viewer/images/icon_message.png
new file mode 100644
index 0000000..8d14ec0
Binary files /dev/null and b/Viewer/images/icon_message.png differ
diff --git a/Viewer/images/icon_message.svg b/Viewer/images/icon_message.svg
new file mode 100644
index 0000000..7e827a8
--- /dev/null
+++ b/Viewer/images/icon_message.svg
@@ -0,0 +1,295 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="icon_message.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3800">
+ <stop
+ style="stop-color:#f1fdff;stop-opacity:1;"
+ offset="0"
+ id="stop3802" />
+ <stop
+ style="stop-color:#c4d3d9;stop-opacity:1;"
+ offset="1"
+ id="stop3804" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3786">
+ <stop
+ id="stop3788"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop3790"
+ offset="1"
+ style="stop-color:#cbd4d9;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient4010">
+ <stop
+ id="stop4012"
+ offset="0"
+ style="stop-color:#5c8085;stop-opacity:1;" />
+ <stop
+ id="stop4014"
+ offset="1"
+ style="stop-color:#f9feff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3994">
+ <stop
+ style="stop-color:#b7c4c8;stop-opacity:1;"
+ offset="0"
+ id="stop3996" />
+ <stop
+ style="stop-color:#f9f9f9;stop-opacity:1;"
+ offset="1"
+ id="stop3998" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3986">
+ <stop
+ style="stop-color:#f5f97a;stop-opacity:1;"
+ offset="0"
+ id="stop3988" />
+ <stop
+ style="stop-color:#f6eb4c;stop-opacity:1;"
+ offset="1"
+ id="stop3990" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#519aed;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#e9dddd;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f1f3fb;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3614">
+ <stop
+ style="stop-color:#2c71d9;stop-opacity:1;"
+ offset="0"
+ id="stop3616" />
+ <stop
+ style="stop-color:#ececec;stop-opacity:1;"
+ offset="1"
+ id="stop3618" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3602">
+ <stop
+ style="stop-color:#f5f5f5;stop-opacity:1;"
+ offset="0"
+ id="stop3604" />
+ <stop
+ style="stop-color:#141bc6;stop-opacity:1;"
+ offset="1"
+ id="stop3606" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3614"
+ id="linearGradient3691"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="12.89746"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3602"
+ id="linearGradient3693"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="2.2337441"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3728"
+ id="linearGradient3710"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-0.7930209,35.114)"
+ x1="15.413333"
+ y1="3.4795053"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3756"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-0.7930209,35.114)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3786"
+ id="linearGradient3992"
+ x1="5.2533336"
+ y1="6.8800001"
+ x2="19.76"
+ y2="23.266666"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.1152726,0,0,1.1080637,0.3011146,-2.5516135)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3994"
+ id="linearGradient4000"
+ x1="8"
+ y1="31"
+ x2="8"
+ y2="23"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-23.253333,-0.96)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4010"
+ id="linearGradient4008"
+ x1="20.726667"
+ y1="4.0266666"
+ x2="22.846666"
+ y2="3.7066665"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-1,0,0,-1,40.257231,32.440001)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3800"
+ id="linearGradient3798"
+ x1="23.816666"
+ y1="25.18"
+ x2="18.809999"
+ y2="19.526669"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.1152726,0,0,1.1080637,-1.3446168,-2.1468678)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="13.310096"
+ inkscape:cy="15.38"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer3"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1408"
+ inkscape:window-height="1096"
+ inkscape:window-x="1960"
+ inkscape:window-y="36"
+ inkscape:window-maximized="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>EcflowUI icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>EcflowUI icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="first"
+ style="display:inline">
+ <path
+ style="fill:url(#linearGradient3992);fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="m 3.0967308,30.572105 0,-28.8096571 26.7665382,0 0,18.8370831 -4.907282,5.219451 -0.267046,0.284032 -4.312923,4.587285 c -5.204607,0 -17.2792872,-0.118194 -17.2792872,-0.118194 z"
+ id="path3195"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccc" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="second"
+ style="display:inline">
+ <path
+ style="fill:url(#linearGradient3798);fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="m 29.600475,20.5906 -9.115494,9.854381 0.01488,-9.795284 z"
+ id="path3016"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 7.9741394,8.3146148 25.10482,8.2115625"
+ id="path3022"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path3026"
+ d="M 7.9146584,14.106096 25.04534,14.003044"
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="top" />
+</svg>
diff --git a/Viewer/images/icon_migrated.png b/Viewer/images/icon_migrated.png
new file mode 100644
index 0000000..881044e
Binary files /dev/null and b/Viewer/images/icon_migrated.png differ
diff --git a/Viewer/images/icon_node_log.svg b/Viewer/images/icon_node_log.svg
new file mode 100644
index 0000000..ebf8c04
--- /dev/null
+++ b/Viewer/images/icon_node_log.svg
@@ -0,0 +1,214 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="icon_node_log.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3777">
+ <stop
+ id="stop3779"
+ offset="0"
+ style="stop-color:#415973;stop-opacity:1;" />
+ <stop
+ id="stop3781"
+ offset="1"
+ style="stop-color:#467e97;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3602">
+ <stop
+ style="stop-color:#4a719a;stop-opacity:1;"
+ offset="0"
+ id="stop3604" />
+ <stop
+ style="stop-color:#467e97;stop-opacity:1;"
+ offset="1"
+ id="stop3606" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3845-2">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop3847-3" />
+ <stop
+ style="stop-color:#a3cbda;stop-opacity:1"
+ offset="1"
+ id="stop3849-4" />
+ </linearGradient>
+ <linearGradient
+ y2="2.8324804"
+ x2="47.821976"
+ y1="18.634857"
+ x1="5.706666"
+ gradientTransform="matrix(1.1259772,0,0,1.1601105,-32.02086,-2.3288901)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient7198"
+ xlink:href="#linearGradient3845-2"
+ inkscape:collect="always" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3602"
+ id="linearGradient3007"
+ gradientUnits="userSpaceOnUse"
+ x1="4.7915082"
+ y1="21.301931"
+ x2="28.312923"
+ y2="21.301931" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="21.072033"
+ inkscape:cx="8.6401564"
+ inkscape:cy="14.110451"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer3"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1699"
+ inkscape:window-height="1091"
+ inkscape:window-x="213"
+ inkscape:window-y="0"
+ inkscape:window-maximized="0"
+ inkscape:snap-to-guides="true"
+ showguides="false"
+ inkscape:guide-bbox="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ <sodipodi:guide
+ orientation="-0.70710678,0.70710678"
+ position="30.816104,38.337323"
+ id="guide8408" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>EcflowUI icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>EcflowUI icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="img"
+ sodipodi:insensitive="true"
+ style="display:none">
+ <image
+ y="0.2890628"
+ x="1.3430486"
+ id="image3035"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABHNCSVQICAgIfAhkiAAAIABJREFU eJzs3Xt8HFd1OPBz7szu7EhavyX5oTy9iS1L3gADCaQ8BgLkwasUTAkkIUBiKBRSHi3Q8iu0tBT6 oEADhJAESCgtSVsawiMJSVieiWnWJLZWthPZToIS25K9trWWtLO7c+/vD2mVkbSvmV1J9+6e+/nk Y2l28r1zZ+fcczWvC0CFChUqVKhQabmCDTK8jpj+jzzyyCOPPPLIk9TT66gYAEArsYyTRx555JFH Hnlye0EHAGjbtpbJZGZGHtFoVCQSCZc88sgjjzzyyJPfC3IJAC3L0rPZ7Mz/G4lERDKZLECwUxnk kUceeeSRR94ie34HABiLxcI9PT0z/9/w8LAYGhrKBamcPPLII4888shbEs/XJQC0bd [...]
+ height="31.341492"
+ width="30.122496" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="first"
+ style="display:inline">
+ <path
+ sodipodi:type="arc"
+ style="fill:#8badb5;fill-opacity:1;stroke:#6f8a91;stroke-width:1.01746416;stroke-opacity:1"
+ id="path8398"
+ sodipodi:cx="16.552216"
+ sodipodi:cy="21.301931"
+ sodipodi:rx="11.112521"
+ sodipodi:ry="11.57878"
+ d="m 27.664737,21.301931 a 11.112521,11.57878 0 1 1 -22.2250426,0 11.112521,11.57878 0 1 1 22.2250426,0 z"
+ transform="matrix(-0.40225195,-1.3059212,1.2533359,-0.38605332,-4.0754017,45.827226)" />
+ <text
+ xml:space="preserve"
+ style="font-size:28.00000016px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;display:inline;font-family:Courier;-inkscape-font-specification:Courier Bold"
+ x="8.1850863"
+ y="23.932768"
+ id="text7062-1"
+ sodipodi:linespacing="125%"
+ transform="scale(0.98497411,1.0152551)"><tspan
+ sodipodi:role="line"
+ id="tspan7064-6"
+ x="8.1850863"
+ y="23.932768"
+ style="font-size:28.00000016px;font-weight:bold;fill:#ffffff;fill-opacity:1;-inkscape-font-specification:Courier Bold">N</tspan></text>
+ <path
+ transform="matrix(-0.4106509,-1.3242821,1.2795053,-0.39148115,32.569591,45.160188)"
+ d="m 27.664737,21.301931 a 11.112521,11.57878 0 1 1 -22.2250426,0 11.112521,11.57878 0 1 1 22.2250426,0 z"
+ sodipodi:ry="11.57878"
+ sodipodi:rx="11.112521"
+ sodipodi:cy="21.301931"
+ sodipodi:cx="16.552216"
+ id="path3001"
+ style="fill:url(#linearGradient3007);fill-opacity:1;stroke:none"
+ sodipodi:type="arc" />
+ <text
+ transform="scale(0.98497412,1.0152551)"
+ sodipodi:linespacing="125%"
+ id="text3003"
+ y="22.904417"
+ x="45.765656"
+ style="font-size:28px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;display:inline;font-family:Courier;-inkscape-font-specification:Courier Bold"
+ xml:space="preserve"><tspan
+ style="font-size:28px;font-weight:bold;fill:#ffffff;fill-opacity:1;-inkscape-font-specification:Courier Bold"
+ y="22.904417"
+ x="45.765656"
+ id="tspan3005"
+ sodipodi:role="line">N</tspan></text>
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="second"
+ style="display:inline" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="top" />
+</svg>
diff --git a/Viewer/images/icon_noway.png b/Viewer/images/icon_noway.png
new file mode 100644
index 0000000..5acd05a
Binary files /dev/null and b/Viewer/images/icon_noway.png differ
diff --git a/Viewer/images/icon_rerun.png b/Viewer/images/icon_rerun.png
new file mode 100644
index 0000000..57f8dda
Binary files /dev/null and b/Viewer/images/icon_rerun.png differ
diff --git a/Viewer/images/icon_rerun.svg b/Viewer/images/icon_rerun.svg
new file mode 100644
index 0000000..91e3e17
--- /dev/null
+++ b/Viewer/images/icon_rerun.svg
@@ -0,0 +1,208 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="icon_rerun.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3852">
+ <stop
+ style="stop-color:#467b3c;stop-opacity:1;"
+ offset="0"
+ id="stop3854" />
+ <stop
+ style="stop-color:#3d9f3d;stop-opacity:0.99215686;"
+ offset="1"
+ id="stop3856" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3799">
+ <stop
+ style="stop-color:#aae1be;stop-opacity:1;"
+ offset="0"
+ id="stop3801" />
+ <stop
+ style="stop-color:#4bc82b;stop-opacity:1;"
+ offset="1"
+ id="stop3803" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3777">
+ <stop
+ style="stop-color:#0000ad;stop-opacity:1;"
+ offset="0"
+ id="stop3779" />
+ <stop
+ style="stop-color:#25d4ce;stop-opacity:1;"
+ offset="1"
+ id="stop3781" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#519aed;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#e9dddd;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f1f3fb;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3756"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0404908,0,0,-1.215256,0.38228708,38.586128)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3777"
+ id="linearGradient3783"
+ x1="1.4276053"
+ y1="16.374115"
+ x2="28.440671"
+ y2="16.374115"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0279887,0,0,1.0323478,7.1553463,-2.2096664)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="-0.8066233"
+ inkscape:cy="10.423067"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1920"
+ inkscape:window-height="1180"
+ inkscape:window-x="1916"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="circle"
+ style="display:inline">
+ <path
+ style="fill:none;stroke:url(#linearGradient3720);stroke-width:0.8456015;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ d="m 3.1988885,24.309 c -1.9860976,6.2832 -0.9930487,3.1416 0,0 z"
+ id="path3695"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <path
+ style="fill:none;stroke:none"
+ d="M 22.909653,6.1671668 16.60076,16.625513 25.306175,15.238756 22.909653,6.1671668 z"
+ id="path3872"
+ sodipodi:nodetypes="cccc"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;stroke:none"
+ d="M 14.241944,7.3321298 C 6.786479,7.5666798 1.4716388,17.360951 7.6758828,24.839907 c 0.7563942,0.780786 3.6491992,2.786828 7.0550982,2.514141 5.712717,-0.402552 6.860758,-3.132424 6.409043,-3.237554 -1.13923,-0.265136 -1.112817,1.757137 -6.227022,2.080868 -7.6308378,-1.234811 -10.664831,-10.197423 -4.19553,-15.127048 1.513013,-0.967602 2.929706,-1.5788248 4.399935,-1.6579269 1.73077,-0.093113 3.535737,0.5511844 5.659367,2.2196019 -0.365235,-2.7439249 -3.144769,-3.9647496 -6.534 [...]
+ id="path3844"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccsccscc" />
+ <path
+ id="path3823-3"
+ style="fill:#b7b7c8;fill-opacity:1;stroke:#000000;stroke-width:0.89287883000000001;stroke-miterlimit:4;stroke-opacity:1;display:inline"
+ d="M 22.486832,22.554776 C 19.439775,25.940664 14.240651,26.201033 10.874261,23.13633 9.3587235,21.756611 8.4730084,19.938191 8.23522,18.046765 c -0.290399,-2.309904 0.3855542,-4.72869 2.060836,-6.590262 3.047057,-3.3858854 8.246179,-3.6462565 11.61257,-0.581552 0.03017,0.02745 -3.888509,4.851987 -3.858754,4.879886 L 30.228273,14.741185 29.759998,1.174775 25.710268,6.1157684 C 19.839509,0.77113026 10.772585,1.2251991 5.4587231,7.1299598 0.14486154,13.03472 0.59631617,22.154159 6.4 [...]
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cssssccccssc" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="top"
+ style="display:none"
+ sodipodi:insensitive="true">
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#2f6ab7;stroke-width:1.24076998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path3786"
+ sodipodi:cx="16.213333"
+ sodipodi:cy="17.973333"
+ sodipodi:rx="13.973333"
+ sodipodi:ry="13.706667"
+ d="m 30.186666,17.973333 a 13.973333,13.706667 0 1 1 -27.9466662,0 13.973333,13.706667 0 1 1 27.9466662,0 z"
+ transform="matrix(1.0376908,0,0,1.0578794,-0.937761,-2.9536141)" />
+ </g>
+</svg>
diff --git a/Viewer/images/icon_slow.svg b/Viewer/images/icon_slow.svg
new file mode 100644
index 0000000..57a792a
--- /dev/null
+++ b/Viewer/images/icon_slow.svg
@@ -0,0 +1,234 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.47 r22583"
+ version="1.0"
+ sodipodi:docname="filesave.svg"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient12168">
+ <stop
+ style="stop-color:#858585;stop-opacity:1;"
+ offset="0"
+ id="stop12170" />
+ <stop
+ id="stop12172"
+ offset="0.5"
+ style="stop-color:#cbcbcb;stop-opacity:1;" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="1"
+ id="stop12174" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient11450">
+ <stop
+ style="stop-color:#191919;stop-opacity:1;"
+ offset="0"
+ id="stop11452" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop11454" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2263">
+ <stop
+ style="stop-color:#3e848c;stop-opacity:1;"
+ offset="0"
+ id="stop2265" />
+ <stop
+ style="stop-color:#b3c7de;stop-opacity:1;"
+ offset="1"
+ id="stop2267" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2263"
+ id="linearGradient7454"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.9673902,0,0,-1.1589562,-0.79677103,52.162489)"
+ x1="28.673536"
+ y1="2.2797322"
+ x2="9.2870998"
+ y2="46.581879" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient12168"
+ id="linearGradient7458"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0595231,0,0,-1.0264164,-2.3364269,49.429715)"
+ x1="13.444483"
+ y1="41.398193"
+ x2="38.408127"
+ y2="31.618719" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient11450"
+ id="linearGradient11456"
+ x1="19.784695"
+ y1="29.870388"
+ x2="19.784693"
+ y2="42.991951"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.903975,0,0,0.6975501,11.791609,-36.457522)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#efefef"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="1"
+ inkscape:pageshadow="2"
+ inkscape:zoom="27.1875"
+ inkscape:cx="3.6965521"
+ inkscape:cy="18.390381"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ inkscape:showpageshadow="false"
+ showborder="true"
+ borderlayer="top"
+ showgrid="true"
+ inkscape:grid-points="false"
+ inkscape:window-width="1585"
+ inkscape:window-height="1096"
+ inkscape:window-x="198"
+ inkscape:window-y="35"
+ width="32px"
+ height="32px"
+ inkscape:window-maximized="0"
+ inkscape:snap-grids="false">
+ <inkscape:grid
+ id="GridFromPre046Settings"
+ type="xygrid"
+ originx="0px"
+ originy="0px"
+ spacingx="1px"
+ spacingy="1px"
+ color="#9f9f9f"
+ empcolor="#9f9f9f"
+ opacity="0.10196078"
+ empopacity="0.25490196"
+ empspacing="10" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ style="display:inline">
+ <g
+ style="display:inline"
+ id="g7418"
+ inkscape:label="Layer 1"
+ transform="matrix(0.75450459,0,0,0.71126951,-2.1666557,-1.4575482)">
+ <path
+ sodipodi:nodetypes="ccccccccc"
+ id="path7428"
+ d="m 6.518876,43.354968 35.286861,0 c 0.534691,0 0.965147,-0.454103 0.965147,-1.018168 l 0,-36.1483706 c 0,-0.5640634 -0.430456,-1.0181674 -0.965147,-1.0181674 l -32.740934,0 c 0,0 -3.6085747,3.8629739 -3.6085747,3.8629739 L 5.553727,42.3368 c 0,0.564065 0.4304565,1.018168 0.965149,1.018168 z"
+ style="fill:url(#linearGradient7454);fill-opacity:1;stroke:#25375f;stroke-width:1.09204853;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
+ <path
+ sodipodi:nodetypes="ccccccc"
+ id="path7444"
+ d="m 15.597127,17.861022 17.95215,0 c 0.807146,0 1.456942,-0.646926 1.456942,-1.450506 l 0,-11.3734517 c 0,0 -20.866034,0 -20.866034,0 l 0,11.3734517 c 0,0.80358 0.649796,1.450506 1.456942,1.450506 z"
+ style="fill:url(#linearGradient7458);fill-opacity:1;stroke:#371d1d;stroke-width:0.80249828;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0" />
+ <rect
+ ry="0.47095141"
+ rx="0.63196307"
+ y="-14.153564"
+ x="27.560804"
+ height="6.3106155"
+ width="4.2313471"
+ id="rect7446"
+ style="fill:url(#linearGradient11456);fill-opacity:1;stroke:#251818;stroke-width:0.65857965;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ transform="scale(1,-1)" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="white"
+ style="display:inline">
+ <rect
+ y="-27.690033"
+ x="5.7776341"
+ height="12.439459"
+ width="20.560297"
+ id="rect7430"
+ style="fill:#ffffff;fill-opacity:1;stroke:#371d1d;stroke-width:0.63016373;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ transform="scale(1,-1)" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="label"
+ style="display:inline">
+ <rect
+ style="fill:#cccccc;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.4163833;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ id="rect11357"
+ width="15.208806"
+ height="0.61792487"
+ x="8.3011494"
+ y="-19.845976"
+ rx="0.10916411"
+ ry="0"
+ transform="scale(1,-1)" />
+ <rect
+ transform="scale(1,-1)"
+ ry="0"
+ rx="0.10925798"
+ y="-24.18055"
+ x="8.3313904"
+ height="0.58149546"
+ width="15.221885"
+ id="rect13161"
+ style="fill:#b3b3b3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.4040966;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" />
+ </g>
+ </g>
+</svg>
diff --git a/Viewer/images/icon_waiting.png b/Viewer/images/icon_waiting.png
new file mode 100644
index 0000000..189db59
Binary files /dev/null and b/Viewer/images/icon_waiting.png differ
diff --git a/Viewer/images/icon_waiting.svg b/Viewer/images/icon_waiting.svg
new file mode 100644
index 0000000..5a9730b
--- /dev/null
+++ b/Viewer/images/icon_waiting.svg
@@ -0,0 +1,291 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="icon_waiting.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4646">
+ <stop
+ style="stop-color:#4d4d4d;stop-opacity:1;"
+ offset="0"
+ id="stop4648" />
+ <stop
+ style="stop-color:#858585;stop-opacity:1"
+ offset="1"
+ id="stop4650" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient6233">
+ <stop
+ id="stop6235"
+ offset="0"
+ style="stop-color:#444444;stop-opacity:1" />
+ <stop
+ id="stop6237"
+ offset="1"
+ style="stop-color:#323232;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient6193">
+ <stop
+ style="stop-color:#8d8884;stop-opacity:1;"
+ offset="0"
+ id="stop6195" />
+ <stop
+ style="stop-color:#ffecdf;stop-opacity:1"
+ offset="1"
+ id="stop6197" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient6109">
+ <stop
+ style="stop-color:#f3b030;stop-opacity:1;"
+ offset="0"
+ id="stop6111" />
+ <stop
+ style="stop-color:#f3b030;stop-opacity:0;"
+ offset="1"
+ id="stop6113" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3852">
+ <stop
+ style="stop-color:#467b3c;stop-opacity:1;"
+ offset="0"
+ id="stop3854" />
+ <stop
+ style="stop-color:#3d9f3d;stop-opacity:0.99215686;"
+ offset="1"
+ id="stop3856" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3799">
+ <stop
+ style="stop-color:#aae1be;stop-opacity:1;"
+ offset="0"
+ id="stop3801" />
+ <stop
+ style="stop-color:#4bc82b;stop-opacity:1;"
+ offset="1"
+ id="stop3803" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3777">
+ <stop
+ style="stop-color:#0000ad;stop-opacity:1;"
+ offset="0"
+ id="stop3779" />
+ <stop
+ style="stop-color:#25d4ce;stop-opacity:1;"
+ offset="1"
+ id="stop3781" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#519aed;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#e9dddd;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f1f3fb;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3756"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.81825409,-0.60999167,-0.66830961,-0.9786754,10.788748,20.127416)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3777"
+ id="linearGradient3783"
+ x1="1.4276053"
+ y1="16.374115"
+ x2="28.440671"
+ y2="16.374115"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0279887,0,0,1.0323478,7.1553463,-2.2096664)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient6109"
+ id="linearGradient6115"
+ x1="13.355194"
+ y1="18.579436"
+ x2="30.948519"
+ y2="18.579436"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.5342173,0,0,1.2340807,-18.099105,7.5550361)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4646"
+ id="linearGradient4652"
+ x1="10.605441"
+ y1="15.933449"
+ x2="20.283924"
+ y2="15.773449"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,0.9702133,-0.10666667,0.55557124)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="4.1530687"
+ inkscape:cy="19.564228"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1920"
+ inkscape:window-height="1180"
+ inkscape:window-x="1916"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1"
+ inkscape:snap-to-guides="false">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="circle"
+ style="display:inline">
+ <path
+ style="fill:none;stroke:url(#linearGradient3720);stroke-width:0.66305125;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ d="m 5.1522903,6.9784513 c 1.893449,6.2243747 0.9467253,3.1121867 0,0 z"
+ id="path3695"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <path
+ style="fill:url(#linearGradient4652);fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="M 7.3521077,1.8782517 C 8.9820225,9.8116617 12.367704,12.037931 14.887127,16.212916 11.670391,21.467444 7.5083302,23.38477 7.5530647,30.067994 l 17.3175243,0.08258 C 22.222458,21.679142 20.522906,21.094522 16.333204,16.21896 20.777186,10.341591 23.26381,9.1083692 24.804158,1.9672799 z"
+ id="path6081"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccc" />
+ <rect
+ style="fill:#333333;fill-opacity:1;stroke:#323232;stroke-width:0.83011079;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="rect6105"
+ width="27.428585"
+ height="0.33212197"
+ x="2.4101715"
+ y="1.2617034"
+ transform="matrix(0.99999992,4.0908737e-4,0.01590671,0.99987348,0,0)" />
+ <rect
+ y="30.322392"
+ x="2.1475532"
+ height="0.40123945"
+ width="27.268822"
+ id="rect6107"
+ style="fill:url(#linearGradient6115);fill-opacity:1;stroke:#323232;stroke-width:0.83630162;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ transform="matrix(0.9999937,0.00355085,0.0109304,0.99994026,0,0)" />
+ <path
+ style="fill:none;stroke:#323232;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 5.1946225,1.743326 0.1075047,28.79508"
+ id="path4634"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#323232;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 26.856817,1.5695127 27.018073,30.016968"
+ id="path4636"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="top"
+ style="display:none"
+ sodipodi:insensitive="true">
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#2f6ab7;stroke-width:1.24076998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path3786"
+ sodipodi:cx="16.213333"
+ sodipodi:cy="17.973333"
+ sodipodi:rx="13.973333"
+ sodipodi:ry="13.706667"
+ d="m 30.186666,17.973333 a 13.973333,13.706667 0 1 1 -27.9466662,0 13.973333,13.706667 0 1 1 27.9466662,0 z"
+ transform="matrix(1.0376908,0,0,1.0578794,-0.937761,-2.9536141)" />
+ </g>
+</svg>
diff --git a/Viewer/images/icon_zombie.svg b/Viewer/images/icon_zombie.svg
new file mode 100644
index 0000000..78521af
--- /dev/null
+++ b/Viewer/images/icon_zombie.svg
@@ -0,0 +1,220 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="icon_zombie.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#519aed;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#e9dddd;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f1f3fb;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3614">
+ <stop
+ style="stop-color:#2c71d9;stop-opacity:1;"
+ offset="0"
+ id="stop3616" />
+ <stop
+ style="stop-color:#ececec;stop-opacity:1;"
+ offset="1"
+ id="stop3618" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3602">
+ <stop
+ style="stop-color:#f5f5f5;stop-opacity:1;"
+ offset="0"
+ id="stop3604" />
+ <stop
+ style="stop-color:#141bc6;stop-opacity:1;"
+ offset="1"
+ id="stop3606" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3614"
+ id="linearGradient3691"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="12.89746"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3602"
+ id="linearGradient3693"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="2.2337441"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3728"
+ id="linearGradient3710"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-31.566354,35.860667)"
+ x1="15.413333"
+ y1="3.4795053"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3756"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-31.566354,35.860667)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="12.503154"
+ inkscape:cy="15.447292"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1408"
+ inkscape:window-height="1096"
+ inkscape:window-x="2051"
+ inkscape:window-y="0"
+ inkscape:window-maximized="0"
+ showguides="true"
+ inkscape:guide-bbox="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="bg"
+ style="display:inline">
+ <text
+ xml:space="preserve"
+ style="font-size:39.3039093px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#373e48;fill-opacity:1;stroke:none;display:inline;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif"
+ x="2.6301098"
+ y="31.385054"
+ id="text3791-6"
+ transform="scale(1.0222096,0.97827294)"><tspan
+ sodipodi:role="line"
+ id="tspan3793-6"
+ x="2.6301098"
+ y="31.385054"
+ style="font-size:39.3039093px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#373e48;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif">Z</tspan></text>
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <text
+ xml:space="preserve"
+ style="font-size:20px;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Calibri;-inkscape-font-specification:Calibri"
+ x="3.8399999"
+ y="21.973333"
+ id="text3783"><tspan
+ sodipodi:role="line"
+ id="tspan3785"
+ x="3.8399999"
+ y="21.973333" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="7.2533331"
+ y="15.146667"
+ id="text3787"><tspan
+ sodipodi:role="line"
+ id="tspan3789"
+ x="7.2533331"
+ y="15.146667" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:39.3039093px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#c83737;fill-opacity:1;stroke:none;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif"
+ x="1.326864"
+ y="30.498129"
+ id="text3791"
+ transform="scale(1.0222096,0.97827294)"><tspan
+ sodipodi:role="line"
+ id="tspan3793"
+ x="1.326864"
+ y="30.498129"
+ style="font-size:39.3039093px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#c83737;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif">Z</tspan></text>
+ </g>
+</svg>
diff --git a/Viewer/images/info.svg b/Viewer/images/info.svg
new file mode 100644
index 0000000..1a65ee9
--- /dev/null
+++ b/Viewer/images/info.svg
@@ -0,0 +1,234 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.47 r22583"
+ sodipodi:docname="fileInfo.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#519aed;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#e9dddd;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f1f3fb;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3614">
+ <stop
+ style="stop-color:#2c71d9;stop-opacity:1;"
+ offset="0"
+ id="stop3616" />
+ <stop
+ style="stop-color:#ececec;stop-opacity:1;"
+ offset="1"
+ id="stop3618" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3602">
+ <stop
+ style="stop-color:#f5f5f5;stop-opacity:1;"
+ offset="0"
+ id="stop3604" />
+ <stop
+ style="stop-color:#141bc6;stop-opacity:1;"
+ offset="1"
+ id="stop3606" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3614"
+ id="linearGradient3691"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="12.89746"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3602"
+ id="linearGradient3693"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="2.2337441"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3728"
+ id="linearGradient3710"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-0.7930209,35.114)"
+ x1="15.413333"
+ y1="3.4795053"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3756"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-0.7930209,35.114)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="4.2024803"
+ inkscape:cy="15.367291"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1408"
+ inkscape:window-height="1096"
+ inkscape:window-x="2082"
+ inkscape:window-y="75"
+ inkscape:window-maximized="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="circle"
+ style="display:inline">
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#linearGradient3691);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3693);stroke-width:0.90856528;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path2820"
+ sodipodi:cx="15.413333"
+ sodipodi:cy="16.559999"
+ sodipodi:rx="13.76"
+ sodipodi:ry="12.613334"
+ d="m 29.173333,16.559999 a 13.76,12.613334 0 1 1 -27.5200003,0 13.76,12.613334 0 1 1 27.5200003,0 z"
+ transform="matrix(1.0537791,0,0,-1.1495772,-0.30224808,35.097001)" />
+ <path
+ style="fill:url(#linearGradient3710);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3720);stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ d="M 28.894346,9.3702377 C 27.010842,13.07042 22.728069,16.870583 17.080503,19.355951 11.585061,21.774374 6.0764534,22.392799 2.1004164,21.400807 c 2.2087693,5.337492 7.4536969,9.09961 13.5842156,9.09961 8.12285,0 14.707722,-6.591694 14.707722,-14.722963 0,-2.303016 -0.556212,-4.465993 -1.498008,-6.4072163 z"
+ id="path3695" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <text
+ xml:space="preserve"
+ style="font-size:20;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Calibri;-inkscape-font-specification:Calibri"
+ x="3.8399999"
+ y="21.973333"
+ id="text3783"><tspan
+ sodipodi:role="line"
+ id="tspan3785"
+ x="3.8399999"
+ y="21.973333" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="7.2533331"
+ y="15.146667"
+ id="text3787"><tspan
+ sodipodi:role="line"
+ id="tspan3789"
+ x="7.2533331"
+ y="15.146667" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:30px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif"
+ x="10.559999"
+ y="26.773333"
+ id="text3791"><tspan
+ sodipodi:role="line"
+ id="tspan3793"
+ x="10.559999"
+ y="26.773333"
+ style="font-size:30px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif">i</tspan></text>
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="top">
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#2f6ab7;stroke-width:1.24076998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path3786"
+ sodipodi:cx="16.213333"
+ sodipodi:cy="17.973333"
+ sodipodi:rx="13.973333"
+ sodipodi:ry="13.706667"
+ d="m 30.186666,17.973333 a 13.973333,13.706667 0 1 1 -27.9466662,0 13.973333,13.706667 0 1 1 27.9466662,0 z"
+ transform="matrix(1.0376908,0,0,1.0578794,-0.937761,-2.9536141)" />
+ </g>
+</svg>
diff --git a/Viewer/images/job.svg b/Viewer/images/job.svg
new file mode 100644
index 0000000..4a69479
--- /dev/null
+++ b/Viewer/images/job.svg
@@ -0,0 +1,328 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="job.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3796">
+ <stop
+ style="stop-color:#2ca02c;stop-opacity:1;"
+ offset="0"
+ id="stop3798" />
+ <stop
+ style="stop-color:#71d771;stop-opacity:1;"
+ offset="1"
+ id="stop3800" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3782">
+ <stop
+ style="stop-color:#000080;stop-opacity:1;"
+ offset="0"
+ id="stop3784" />
+ <stop
+ style="stop-color:#578eb5;stop-opacity:0.9910714;"
+ offset="1"
+ id="stop3786" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3608">
+ <stop
+ id="stop3610"
+ offset="0"
+ style="stop-color:#2eaf1d;stop-opacity:1;" />
+ <stop
+ id="stop3612"
+ offset="1"
+ style="stop-color:#91ff44;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3612">
+ <stop
+ style="stop-color:#616161;stop-opacity:1;"
+ offset="0"
+ id="stop3614" />
+ <stop
+ style="stop-color:#383838;stop-opacity:1;"
+ offset="1"
+ id="stop3616" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3601">
+ <stop
+ style="stop-color:#a2a2a2;stop-opacity:1;"
+ offset="0"
+ id="stop3603" />
+ <stop
+ style="stop-color:#343434;stop-opacity:1;"
+ offset="1"
+ id="stop3605" />
+ </linearGradient>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ id="perspective10" />
+ <inkscape:perspective
+ id="perspective2825"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <inkscape:perspective
+ id="perspective2841"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3601"
+ id="linearGradient3607"
+ x1="10.653805"
+ y1="3.7712457"
+ x2="24.085051"
+ y2="29.5"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.96774194,0,0,-0.96774194,0.58051457,31.158684)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3612"
+ id="linearGradient3618"
+ x1="3"
+ y1="28.806061"
+ x2="29"
+ y2="28.806061"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3612"
+ id="linearGradient3620"
+ gradientUnits="userSpaceOnUse"
+ x1="3"
+ y1="28.806061"
+ x2="29"
+ y2="28.806061"
+ gradientTransform="translate(0,-32.806061)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3608"
+ id="linearGradient3606"
+ x1="24"
+ y1="26"
+ x2="7"
+ y2="8"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.83718675,0,0,0.87310139,-36.94508,11.435241)" />
+ <linearGradient
+ id="linearGradient3757">
+ <stop
+ id="stop3759"
+ offset="0"
+ style="stop-color:#fdfb72;stop-opacity:1;" />
+ <stop
+ id="stop3761"
+ offset="1"
+ style="stop-color:#ffb41b;stop-opacity:1;" />
+ </linearGradient>
+ <inkscape:perspective
+ id="perspective2882"
+ inkscape:persp3d-origin="16 : 10.666667 : 1"
+ inkscape:vp_z="32 : 16 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 16 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <inkscape:perspective
+ id="perspective3015"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <linearGradient
+ id="linearGradient3845">
+ <stop
+ style="stop-color:#326dc2;stop-opacity:1;"
+ offset="0"
+ id="stop3847" />
+ <stop
+ style="stop-color:#6295be;stop-opacity:1;"
+ offset="1"
+ id="stop3849" />
+ </linearGradient>
+ <linearGradient
+ y2="19.5"
+ x2="38.5"
+ y1="19.5"
+ x1="7.5"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3945"
+ xlink:href="#linearGradient3845-1"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3845-1">
+ <stop
+ style="stop-color:#018049;stop-opacity:1;"
+ offset="0"
+ id="stop3847-7" />
+ <stop
+ style="stop-color:#01b549;stop-opacity:1;"
+ offset="1"
+ id="stop3849-4" />
+ </linearGradient>
+ <linearGradient
+ y2="19.5"
+ x2="38.5"
+ y1="19.5"
+ x1="7.5"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3066"
+ xlink:href="#linearGradient3845-1"
+ inkscape:collect="always" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3845-1"
+ id="linearGradient3808"
+ x1="-12.355866"
+ y1="27.080372"
+ x2="-21.346371"
+ y2="14.270093"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.2173913,0,0,1.2185686,-9.3443756,-22.874273)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3796"
+ id="linearGradient3802"
+ x1="1.9267198"
+ y1="27.256475"
+ x2="-20.994131"
+ y2="4.1248736"
+ gradientUnits="userSpaceOnUse" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="15.401324"
+ inkscape:cx="9.1248802"
+ inkscape:cy="20.567437"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:window-width="1920"
+ inkscape:window-height="1140"
+ inkscape:window-x="-4"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1"
+ inkscape:snap-to-guides="false"
+ inkscape:snap-grids="false">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2831"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="plus"
+ style="display:inline" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="star"
+ style="display:inline">
+ <path
+ style="fill:#3771c8;stroke:none"
+ d="M 7.6619342,12.298233 C 7.8437481,10.86106 9.8408921,6.9748093 10.938011,6.5500068 12.759482,5.8447356 18.19348,6.1528173 18.19348,6.1528173 c 0,0 1.335921,0.5014586 1.62893,0.9874645 0.274312,0.4549911 -0.187512,3.3018062 -0.187512,3.3018062 L 21.16293,7.27681 c 0,0 1.574665,0.6301148 1.432842,1.5408024 -0.157333,1.0102752 -3.835116,8.6994106 -3.835116,8.6994106 0,0 3.998809,2.999115 4.099577,4.541548 0.09019,1.380535 0.420074,5.424149 0.08207,8.339411 -0.117489,1.013356 -3.00 [...]
+ id="path3034"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sscsccscssscsccss" />
+ <path
+ style="fill:#3771c8;stroke:none"
+ d="m 23.307803,9.7069466 -1.256188,3.1113174 c 0,0 1.549429,3.046977 2.842951,3.045118 2.360357,-0.0034 4.275446,0.05475 5.223097,-0.0662 0.902962,-0.115241 0.579577,-2.728591 -0.330576,-2.714126 l -4.165254,0.0662 z"
+ id="path3958"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccssscc" />
+ <path
+ style="fill:#3771c8;stroke:none"
+ d="m 12.531034,17.78313 -0.661152,5.163462 c 0,0 -3.4068968,4.110963 -4.4958297,5.031065 -0.7655477,0.646856 1.5877595,2.610519 2.3140298,1.919749 1.5759249,-1.498894 5.0165709,-4.647632 5.2230969,-5.693048 0.384056,-1.944067 0.462806,-3.839497 0.462806,-3.839497 z"
+ id="path3960"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccssscc" />
+ <rect
+ style="fill:#3771c8;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ id="rect3964"
+ width="7.9361415"
+ height="6.1546359"
+ x="10.09255"
+ y="9.354104"
+ ry="0.92650431"
+ transform="matrix(0.87554553,0.48313561,-0.48220582,0.87605796,0,0)" />
+ <path
+ sodipodi:type="arc"
+ style="fill:#3771c8;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ id="path3966"
+ sodipodi:cx="24.121304"
+ sodipodi:cy="5.6061649"
+ sodipodi:rx="2.8893621"
+ sodipodi:ry="2.6945736"
+ d="m 27.010666,5.6061649 a 2.8893621,2.6945736 0 1 1 -5.778725,0 2.8893621,2.6945736 0 1 1 5.778725,0 z"
+ transform="matrix(0.92673173,0,0,0.93355492,-0.93045588,-2.0141416)" />
+ </g>
+</svg>
diff --git a/Viewer/images/large_file_search.svg b/Viewer/images/large_file_search.svg
new file mode 100644
index 0000000..f3f96d9
--- /dev/null
+++ b/Viewer/images/large_file_search.svg
@@ -0,0 +1,163 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="large_file_search.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3674">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="0"
+ id="stop3676" />
+ <stop
+ style="stop-color:#90bbd4;stop-opacity:1;"
+ offset="1"
+ id="stop3678" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3596">
+ <stop
+ style="stop-color:#ffff00;stop-opacity:1;"
+ offset="0"
+ id="stop3598" />
+ <stop
+ style="stop-color:#ededd2;stop-opacity:0.99137932;"
+ offset="1"
+ id="stop3600" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3759">
+ <stop
+ style="stop-color:#0f1934;stop-opacity:1;"
+ offset="0"
+ id="stop3761" />
+ <stop
+ style="stop-color:#0f1123;stop-opacity:1;"
+ offset="1"
+ id="stop3763" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3674"
+ id="linearGradient3680"
+ x1="23.639265"
+ y1="1029.8322"
+ x2="-9.4723015"
+ y2="1043.9935"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.1274903,0,0,1.1742062,-0.90288397,-180.95653)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="16.15625"
+ inkscape:cx="-0.80379338"
+ inkscape:cy="17.070429"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:snap-to-guides="false"
+ inkscape:window-width="1920"
+ inkscape:window-height="1140"
+ inkscape:window-x="-4"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2985"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-1020.3622)">
+ <path
+ style="fill:url(#linearGradient3680);fill-opacity:1;stroke:#41597a;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="m 1.6792215,1047.9744 c 0,0 7.306834,-15.3271 12.7036685,-25.4536 1.503025,-2.6229 3.083285,-0.1899 3.083285,-0.1899 0.0763,0.1019 12.24441,24.4147 12.24441,24.4147 1.105246,2.6168 3.133057,5.0217 -1.16351,4.9345 l -24.4951475,-0.1548 c 0,0 -4.62537885,0.6467 -2.372706,-3.5517 z"
+ id="path2822"
+ sodipodi:nodetypes="cccccccc"
+ inkscape:connector-curvature="0" />
+ <text
+ xml:space="preserve"
+ style="font-size:24.92413139px;font-style:normal;font-weight:normal;fill:#11293d;fill-opacity:1;stroke:none;font-family:Arial;-inkscape-font-specification:Arial"
+ x="-6.313168"
+ y="1337.3267"
+ id="text3604"
+ transform="scale(1.2868668,0.7770812)"><tspan
+ sodipodi:role="line"
+ id="tspan3606"
+ x="-6.313168"
+ y="1337.3267">!</tspan></text>
+ <path
+ sodipodi:type="arc"
+ style="fill:#11293d;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ id="path3808"
+ sodipodi:cx="13.090909"
+ sodipodi:cy="37.694389"
+ sodipodi:rx="1.7640232"
+ sodipodi:ry="1.6092843"
+ d="m 14.854932,37.694389 a 1.7640232,1.6092843 0 1 1 -3.528046,0 1.7640232,1.6092843 0 1 1 3.528046,0 z"
+ transform="matrix(1.2890225,0,0,1.399682,-0.69136928,993.77957)" />
+ <path
+ style="fill:#11293d;fill-opacity:1;stroke:none"
+ d="m 15.263409,1027.2981 -0.822246,7.6043 0.822246,6.5179 1.644492,0 0.757277,-6.5179 -0.757277,-7.6043 c 0,0 -0.507749,-0.5346 -0.952183,-0.4811 -0.444432,0.053 -0.692309,0.4811 -0.692309,0.4811 z"
+ id="path3810"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccczc" />
+ </g>
+</svg>
diff --git a/Viewer/images/log_error.svg b/Viewer/images/log_error.svg
new file mode 100644
index 0000000..ae75e8a
--- /dev/null
+++ b/Viewer/images/log_error.svg
@@ -0,0 +1,218 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="log_error.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3831">
+ <stop
+ id="stop3833"
+ offset="0"
+ style="stop-color:#f8f4f4;stop-opacity:1;" />
+ <stop
+ id="stop3835"
+ offset="1"
+ style="stop-color:#d40000;stop-opacity:0.30357143;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3819">
+ <stop
+ id="stop3821"
+ offset="0"
+ style="stop-color:#edcdc9;stop-opacity:1;" />
+ <stop
+ id="stop3823"
+ offset="1"
+ style="stop-color:#c91b0b;stop-opacity:0.99215686;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3783">
+ <stop
+ style="stop-color:#f87e7e;stop-opacity:1;"
+ offset="0"
+ id="stop3785" />
+ <stop
+ style="stop-color:#d40000;stop-opacity:1;"
+ offset="1"
+ id="stop3787" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3674">
+ <stop
+ style="stop-color:#f0c7c1;stop-opacity:1;"
+ offset="0"
+ id="stop3676" />
+ <stop
+ style="stop-color:#de1a08;stop-opacity:0.99215686;"
+ offset="1"
+ id="stop3678" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3783"
+ id="linearGradient3789"
+ x1="-4.8186264"
+ y1="4.2037883"
+ x2="-4.5480547"
+ y2="39.719273"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3674"
+ id="linearGradient3806"
+ x1="-4.7521257"
+ y1="1.3206121"
+ x2="-8.2720757"
+ y2="7.3490696"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3783"
+ id="linearGradient3808"
+ gradientUnits="userSpaceOnUse"
+ x1="-4.0871224"
+ y1="33.62529"
+ x2="-8.2720757"
+ y2="7.3490696" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3783"
+ id="linearGradient3814"
+ gradientUnits="userSpaceOnUse"
+ x1="-4.8186264"
+ y1="4.2037883"
+ x2="-4.5480547"
+ y2="39.719273"
+ gradientTransform="matrix(0.93075485,0,0,0.94458483,20.730415,-1.9099)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3674"
+ id="linearGradient3816"
+ gradientUnits="userSpaceOnUse"
+ x1="-4.7521257"
+ y1="1.3206121"
+ x2="-4.5480547"
+ y2="39.719273"
+ gradientTransform="matrix(0.93075485,0,0,0.94458483,20.730415,-1.9099)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3831"
+ id="linearGradient3829"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.56279655,-0.71788239,0.73596717,0.56540236,-37.80729,1025.7128)"
+ x1="-5.2841291"
+ y1="4.1382613"
+ x2="-5.0135574"
+ y2="14.16385" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="16.15625"
+ inkscape:cx="-11.206345"
+ inkscape:cy="17.039481"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:snap-to-guides="false"
+ inkscape:window-width="1920"
+ inkscape:window-height="1140"
+ inkscape:window-x="-4"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2985"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="Layer" />
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-1020.3622)">
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#linearGradient3808);fill-opacity:1;stroke:url(#linearGradient3806);stroke-opacity:1"
+ id="path3011"
+ sodipodi:cx="-4.9825921"
+ sodipodi:cy="18.816248"
+ sodipodi:rx="15.628627"
+ sodipodi:ry="15.288201"
+ d="m 10.646035,18.816248 a 15.628627,15.288201 0 1 1 -31.257254,0 15.628627,15.288201 0 1 1 31.257254,0 z"
+ transform="matrix(0.73907864,-0.56574495,0.57415129,0.75006053,8.7863111,1019.3555)" />
+ <rect
+ style="fill:#ffffff;fill-opacity:1;stroke:none"
+ id="rect3013"
+ width="20.548933"
+ height="3.0426819"
+ x="711.58398"
+ y="743.4668"
+ transform="matrix(0.72928007,0.68421531,-0.68511968,0.72843052,0,0)" />
+ <rect
+ transform="matrix(-0.72928007,0.68421531,0.68511968,0.72843052,0,0)"
+ y="765.2937"
+ x="688.88928"
+ height="2.8565464"
+ width="20.204264"
+ id="rect3005"
+ style="fill:#ffffff;fill-opacity:1;stroke:none" />
+ </g>
+</svg>
diff --git a/Viewer/images/log_info.svg b/Viewer/images/log_info.svg
new file mode 100644
index 0000000..f4b2da2
--- /dev/null
+++ b/Viewer/images/log_info.svg
@@ -0,0 +1,220 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="log_info.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#519aed;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#e9dddd;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f1f3fb;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3614">
+ <stop
+ style="stop-color:#2c71d9;stop-opacity:1;"
+ offset="0"
+ id="stop3616" />
+ <stop
+ style="stop-color:#ececec;stop-opacity:1;"
+ offset="1"
+ id="stop3618" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3602">
+ <stop
+ style="stop-color:#f5f5f5;stop-opacity:1;"
+ offset="0"
+ id="stop3604" />
+ <stop
+ style="stop-color:#141bc6;stop-opacity:1;"
+ offset="1"
+ id="stop3606" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3614"
+ id="linearGradient3691"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="12.89746"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3602"
+ id="linearGradient3693"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="2.2337441"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3728"
+ id="linearGradient3710"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-31.566354,35.860667)"
+ x1="15.413333"
+ y1="3.4795053"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3756"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-31.566354,35.860667)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="18.610523"
+ inkscape:cy="15.393958"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1408"
+ inkscape:window-height="1096"
+ inkscape:window-x="460"
+ inkscape:window-y="47"
+ inkscape:window-maximized="0"
+ showguides="true"
+ inkscape:guide-bbox="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="bg"
+ style="display:inline">
+ <text
+ xml:space="preserve"
+ style="font-size:38.92160416px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#373e48;fill-opacity:1;stroke:none;display:inline;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif"
+ x="8.6815786"
+ y="31.507515"
+ id="text3791-6"
+ transform="scale(1.0104019,0.98970514)"><tspan
+ sodipodi:role="line"
+ id="tspan3793-6"
+ x="8.6815786"
+ y="31.507515"
+ style="font-size:38.92160416px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#373e48;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif">i</tspan></text>
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <text
+ xml:space="preserve"
+ style="font-size:20px;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Calibri;-inkscape-font-specification:Calibri"
+ x="3.8399999"
+ y="21.973333"
+ id="text3783"><tspan
+ sodipodi:role="line"
+ id="tspan3785"
+ x="3.8399999"
+ y="21.973333" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="7.2533331"
+ y="15.146667"
+ id="text3787"><tspan
+ sodipodi:role="line"
+ id="tspan3789"
+ x="7.2533331"
+ y="15.146667" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:38.92160416000000112px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#0055d4;fill-opacity:1;stroke:none;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif"
+ x="7.8132834"
+ y="31.11421"
+ id="text3791"
+ transform="scale(1.0104019,0.98970514)"><tspan
+ sodipodi:role="line"
+ id="tspan3793"
+ x="7.8132834"
+ y="31.11421"
+ style="font-size:38.92160416000000112px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#0055d4;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif">i</tspan></text>
+ </g>
+</svg>
diff --git a/Viewer/images/manage_server.svg b/Viewer/images/manage_server.svg
new file mode 100644
index 0000000..d3a4a53
--- /dev/null
+++ b/Viewer/images/manage_server.svg
@@ -0,0 +1,763 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="manage_server.svg"
+ style="display:inline"
+ inkscape:export-filename="/var/tmp/cgr/PERFORCE/development/metview/src/Flextra/FLEXTRA_RUN_128.png"
+ inkscape:export-xdpi="360"
+ inkscape:export-ydpi="360">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3928">
+ <stop
+ style="stop-color:#b1b1b1;stop-opacity:1;"
+ offset="0"
+ id="stop3930" />
+ <stop
+ style="stop-color:#7b7b7b;stop-opacity:1;"
+ offset="1"
+ id="stop3932" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3886">
+ <stop
+ id="stop3888"
+ offset="0"
+ style="stop-color:#a1a1a1;stop-opacity:1;" />
+ <stop
+ id="stop3892"
+ offset="1"
+ style="stop-color:#363636;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3878">
+ <stop
+ id="stop3880"
+ offset="0"
+ style="stop-color:#a1a1a1;stop-opacity:1;" />
+ <stop
+ style="stop-color:#5c5c5c;stop-opacity:1;"
+ offset="0.1568388"
+ id="stop3882" />
+ <stop
+ id="stop3884"
+ offset="1"
+ style="stop-color:#363636;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3870">
+ <stop
+ id="stop3872"
+ offset="0"
+ style="stop-color:#4a4a4a;stop-opacity:1;" />
+ <stop
+ style="stop-color:#828282;stop-opacity:1;"
+ offset="0.92700338"
+ id="stop3874" />
+ <stop
+ id="stop3876"
+ offset="1"
+ style="stop-color:#aaaaaa;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3852">
+ <stop
+ style="stop-color:#b1e5ff;stop-opacity:1;"
+ offset="0"
+ id="stop3854" />
+ <stop
+ style="stop-color:#4cc3ff;stop-opacity:1;"
+ offset="1"
+ id="stop3856" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3697">
+ <stop
+ style="stop-color:#0055d4;stop-opacity:1;"
+ offset="0"
+ id="stop3699" />
+ <stop
+ style="stop-color:#3c6fbd;stop-opacity:1;"
+ offset="1"
+ id="stop3701" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3689">
+ <stop
+ style="stop-color:#0066ff;stop-opacity:1;"
+ offset="0"
+ id="stop3691" />
+ <stop
+ style="stop-color:#3f84eb;stop-opacity:1;"
+ offset="1"
+ id="stop3693" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3925">
+ <stop
+ style="stop-color:#0044aa;stop-opacity:1;"
+ offset="0"
+ id="stop3927" />
+ <stop
+ style="stop-color:#0055d3;stop-opacity:1;"
+ offset="1"
+ id="stop3929" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3917">
+ <stop
+ style="stop-color:#0055d4;stop-opacity:1;"
+ offset="0"
+ id="stop3919" />
+ <stop
+ style="stop-color:#1975ff;stop-opacity:1;"
+ offset="1"
+ id="stop3921" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3909">
+ <stop
+ style="stop-color:#2a7fff;stop-opacity:1;"
+ offset="0"
+ id="stop3911" />
+ <stop
+ style="stop-color:#63a1ff;stop-opacity:1;"
+ offset="1"
+ id="stop3913" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3678">
+ <stop
+ style="stop-color:#e3e9ef;stop-opacity:1;"
+ offset="0"
+ id="stop3680" />
+ <stop
+ style="stop-color:#d9e3f2;stop-opacity:1;"
+ offset="1"
+ id="stop3682" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3648">
+ <stop
+ style="stop-color:#acc6d2;stop-opacity:1;"
+ offset="0"
+ id="stop3650" />
+ <stop
+ style="stop-color:#498ca2;stop-opacity:1;"
+ offset="1"
+ id="stop3652" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3716">
+ <stop
+ style="stop-color:#a5a5a5;stop-opacity:1;"
+ offset="0"
+ id="stop3718" />
+ <stop
+ style="stop-color:#bbbbbb;stop-opacity:1;"
+ offset="1"
+ id="stop3720" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3708">
+ <stop
+ style="stop-color:#838383;stop-opacity:1;"
+ offset="0"
+ id="stop3710" />
+ <stop
+ style="stop-color:#b3b3b3;stop-opacity:1;"
+ offset="1"
+ id="stop3712" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3700">
+ <stop
+ style="stop-color:#c3c3c3;stop-opacity:1;"
+ offset="0"
+ id="stop3702" />
+ <stop
+ style="stop-color:#969696;stop-opacity:1;"
+ offset="1"
+ id="stop3704" />
+ </linearGradient>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 16 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="32 : 16 : 1"
+ inkscape:persp3d-origin="16 : 10.666667 : 1"
+ id="perspective3219" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3749">
+ <stop
+ style="stop-color:#2f3d85;stop-opacity:1;"
+ offset="0"
+ id="stop3751" />
+ <stop
+ style="stop-color:#2f3d85;stop-opacity:0;"
+ offset="1"
+ id="stop3753" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3741">
+ <stop
+ style="stop-color:#2f3d85;stop-opacity:1;"
+ offset="0"
+ id="stop3743" />
+ <stop
+ style="stop-color:#2f3d85;stop-opacity:0;"
+ offset="1"
+ id="stop3745" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3733">
+ <stop
+ style="stop-color:#2f528a;stop-opacity:1"
+ offset="0"
+ id="stop3735" />
+ <stop
+ style="stop-color:#3f5e91;stop-opacity:0;"
+ offset="1"
+ id="stop3737" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3622-8">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="0"
+ id="stop3624-3" />
+ <stop
+ style="stop-color:#e9f0fa;stop-opacity:1"
+ offset="1"
+ id="stop3626-2" />
+ </linearGradient>
+ <linearGradient
+ y2="29.323114"
+ x2="13.269579"
+ y1="2.2007067"
+ x1="29.382435"
+ gradientTransform="matrix(1.0033899,0,0,1.006795,-0.04875293,31.924568)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4163"
+ xlink:href="#linearGradient3622-8"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3622-95">
+ <stop
+ style="stop-color:#c6cee3;stop-opacity:1;"
+ offset="0"
+ id="stop3624-5" />
+ <stop
+ style="stop-color:#eaeef9;stop-opacity:0;"
+ offset="1"
+ id="stop3626-7" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3733"
+ id="linearGradient2886"
+ gradientUnits="userSpaceOnUse"
+ x1="78.128151"
+ y1="102.62679"
+ x2="110.16354"
+ y2="102.62679"
+ gradientTransform="translate(-26.687459,-0.0778789)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3749"
+ id="linearGradient2892"
+ gradientUnits="userSpaceOnUse"
+ x1="88.325951"
+ y1="84.507774"
+ x2="119.71897"
+ y2="63.179432" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3741"
+ id="linearGradient2894"
+ gradientUnits="userSpaceOnUse"
+ x1="98.523994"
+ y1="99.79335"
+ x2="127.85975"
+ y2="99.79335" />
+ <inkscape:perspective
+ id="perspective3676"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3700"
+ id="linearGradient3706"
+ x1="22.977591"
+ y1="16.533602"
+ x2="29.822767"
+ y2="16.274597"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.7675676,0,0,1,5.1557318,30.408959)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3708"
+ id="linearGradient3714"
+ x1="12.987333"
+ y1="40.467396"
+ x2="29.933771"
+ y2="40.467396"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.9235808,0,0,1,1.6954997,-1.5910409)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3716"
+ id="linearGradient3722"
+ x1="12.98733"
+ y1="51.049667"
+ x2="23.125591"
+ y2="51.049667"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.91240876,0,0,1,1.8405944,-1.5910409)" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3648"
+ id="radialGradient3656"
+ cx="15.794774"
+ cy="23.04089"
+ fx="15.794774"
+ fy="23.04089"
+ r="1.5355394"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3678"
+ id="linearGradient3684"
+ x1="0.87100756"
+ y1="-3.0895786"
+ x2="28.755108"
+ y2="-5.2356339"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,1.0766142,0,0.03111428)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3909"
+ id="linearGradient3915"
+ x1="2.108496"
+ y1="7.6282678"
+ x2="8.558013"
+ y2="7.6282678"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-1.9191813,0.17506575)" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3648-8"
+ id="radialGradient3656-4"
+ cx="15.794774"
+ cy="23.04089"
+ fx="15.794774"
+ fy="23.04089"
+ r="1.5355394"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ id="linearGradient3648-8">
+ <stop
+ style="stop-color:#acc6d2;stop-opacity:1;"
+ offset="0"
+ id="stop3650-8" />
+ <stop
+ style="stop-color:#498ca2;stop-opacity:1;"
+ offset="1"
+ id="stop3652-2" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3886"
+ id="linearGradient3706-4"
+ x1="32.714359"
+ y1="14.128001"
+ x2="29.690975"
+ y2="14.079874"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0352934,0,0,1.3291541,-2.4775067,-6.9190948)" />
+ <linearGradient
+ id="linearGradient3700-5">
+ <stop
+ style="stop-color:#e6e6e6;stop-opacity:1;"
+ offset="0"
+ id="stop3702-5" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop3704-1" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3878"
+ id="linearGradient3714-7"
+ x1="22.47965"
+ y1="42.03252"
+ x2="22.687197"
+ y2="38.870899"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.2457235,0,0,1.3291541,-12.76261,-49.452027)" />
+ <linearGradient
+ id="linearGradient3708-1">
+ <stop
+ style="stop-color:#c9c9c9;stop-opacity:1;"
+ offset="0"
+ id="stop3710-1" />
+ <stop
+ style="stop-color:#f6f6f6;stop-opacity:1;"
+ offset="1"
+ id="stop3712-5" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3716-7"
+ id="linearGradient3722-2"
+ x1="12.98733"
+ y1="51.049667"
+ x2="23.125591"
+ y2="51.049667"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.91240876,0,0,1,1.8405944,-1.5910409)" />
+ <linearGradient
+ id="linearGradient3716-7">
+ <stop
+ style="stop-color:#a1a1a1;stop-opacity:1;"
+ offset="0"
+ id="stop3718-6" />
+ <stop
+ id="stop3860"
+ offset="0.5"
+ style="stop-color:#5c5c5c;stop-opacity:1;" />
+ <stop
+ style="stop-color:#363636;stop-opacity:1;"
+ offset="1"
+ id="stop3720-1" />
+ </linearGradient>
+ <linearGradient
+ y2="50.937008"
+ x2="23.073195"
+ y1="50.905857"
+ x1="14.300552"
+ gradientTransform="matrix(1.7739141,0,0,1.3291541,-19.779778,-49.375569)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3965"
+ xlink:href="#linearGradient3870"
+ inkscape:collect="always" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3689"
+ id="linearGradient3695"
+ x1="0.99223268"
+ y1="16.589376"
+ x2="7.4417505"
+ y2="16.589376"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-0.80291868,-0.07299261)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3697"
+ id="linearGradient3703"
+ x1="0.99223369"
+ y1="25.271418"
+ x2="7.5037656"
+ y2="25.271418"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-0.80291868,-0.07299261)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3852"
+ id="linearGradient3858"
+ x1="4.3676114"
+ y1="11.002259"
+ x2="20.676254"
+ y2="11.841675"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.98267863,0,0,1,0.3241733,0.21897781)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3852"
+ id="linearGradient3868"
+ x1="4.0026484"
+ y1="16.623831"
+ x2="20.858734"
+ y2="16.623831"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3700"
+ id="linearGradient3900"
+ x1="11.79378"
+ y1="27.419714"
+ x2="11.819339"
+ y2="29.718981"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3928"
+ id="linearGradient3934"
+ x1="4.0391447"
+ y1="26.129977"
+ x2="18.814943"
+ y2="26.129977"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.00247,0,0,1,-0.00997671,0)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3700"
+ id="linearGradient3875"
+ x1="19.89596"
+ y1="27.036503"
+ x2="29.118568"
+ y2="27.036503"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3685-4"
+ id="linearGradient3763"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.53050981,0,0,0.53060056,1.2947031,0.22548129)"
+ x1="12"
+ y1="28"
+ x2="7"
+ y2="23" />
+ <linearGradient
+ id="linearGradient3685-4">
+ <stop
+ id="stop3687-6"
+ offset="0"
+ style="stop-color:#c78e5b;stop-opacity:1;" />
+ <stop
+ id="stop3689-9"
+ offset="1"
+ style="stop-color:#cf7d3e;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3675-2"
+ id="linearGradient3765"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.53050992,0,0,0.53060066,1.2947031,0.38476339)"
+ x1="-0.31687203"
+ y1="24.091682"
+ x2="15.869606"
+ y2="24.091682" />
+ <linearGradient
+ id="linearGradient3675-2">
+ <stop
+ id="stop3677-2"
+ offset="0"
+ style="stop-color:#e6bc10;stop-opacity:1;" />
+ <stop
+ id="stop3679-4"
+ offset="1"
+ style="stop-color:#dbe683;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="15.711069"
+ x2="24.332083"
+ y1="3.2495306"
+ x1="8.3320827"
+ gradientTransform="matrix(1.0001759,0,0,1.0001946,0.74496691,-0.78037688)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3914"
+ xlink:href="#linearGradient3665-7"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3665-7">
+ <stop
+ id="stop3667-7"
+ offset="0"
+ style="stop-color:#b7b7b7;stop-opacity:1;" />
+ <stop
+ id="stop3669-5"
+ offset="1"
+ style="stop-color:#f1f1f1;stop-opacity:0.99215686;" />
+ </linearGradient>
+ <linearGradient
+ y2="15.711069"
+ x2="24.332083"
+ y1="3.2495306"
+ x1="8.3320827"
+ gradientTransform="matrix(0.53050992,0,0,0.53060066,1.2947031,0.38476339)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3360"
+ xlink:href="#linearGradient3665-7"
+ inkscape:collect="always" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="26.057194"
+ inkscape:cx="9.7823199"
+ inkscape:cy="19.054451"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ width="64px"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1920"
+ inkscape:window-height="1140"
+ inkscape:window-x="-4"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1"
+ gridtolerance="6">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Ecflowview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Ecflowview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer6"
+ inkscape:label="desktop"
+ style="display:inline"
+ sodipodi:insensitive="true">
+ <path
+ style="fill:url(#linearGradient3875);fill-opacity:1;stroke:#626262;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="m 20.145959,31.270074 0.03649,-2.956201 8.68612,-5.510941 -6e-6,2.262771 z"
+ id="path3850"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:url(#linearGradient3900);fill-opacity:1;stroke:#636363;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="M 5.2528164,26.306577 5.4014533,30.029201 20.18511,31.270073 20.21896,27.94891 z"
+ id="path3846"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:url(#linearGradient3965);fill-opacity:1;fill-rule:evenodd;stroke:#666666;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+ d="m 3.3775328,6.1108479 c -0.169966,-0.00934 17.9266262,0.986965 17.9266262,0.986965 L 21.58446,28.316755 c 0,0 -17.8770845,-1.140017 -18.0685583,-1.178641 z"
+ id="rect2870-42"
+ sodipodi:nodetypes="ccccc"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:url(#linearGradient3714-7);fill-opacity:1;fill-rule:evenodd;stroke:#666666;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+ d="m 15.116013,0.86550208 14.990055,0.56605282 -5.025189,6.526618 c 0,0 -1.733408,-0.7408621 -4.06582,-0.8304631 L 3.3390575,6.0169457 z"
+ id="rect2870-4-3"
+ sodipodi:nodetypes="cccccc"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:url(#linearGradient3706-4);fill-opacity:1;fill-rule:evenodd;stroke:#666666;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+ d="m 21.464962,7.1444025 8.787787,-5.6170782 -0.147448,20.9824597 -8.61014,5.889363 z"
+ id="rect3690-2"
+ sodipodi:nodetypes="ccccc"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:url(#linearGradient3858);fill-opacity:1;stroke:none;display:inline"
+ d="m 4.2482102,9.4658413 16.5375328,0.9442337 -4e-6,2.493566 -16.5641128,-0.974979 z"
+ id="path3726-1"
+ sodipodi:nodetypes="ccccc"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:#b3b3b3;fill-opacity:1;stroke:none;display:inline"
+ d="m 22.054602,12.51778 7.781666,-5.4553165 0.02658,-1.8852615 -7.845773,5.418269 z"
+ id="path3836"
+ sodipodi:nodetypes="ccccc"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc"
+ id="path3840"
+ d="m 4.029701,14.904931 16.829033,1.017228 -4e-6,2.420573 -16.8560816,-1.120965 z"
+ style="fill:url(#linearGradient3868);fill-opacity:1;stroke:none;display:inline" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc"
+ id="path3924"
+ d="m 4.1023808,24.210348 14.9680362,0.907737 0.218884,2.45707 -15.2501563,-1.230453 z"
+ style="fill:url(#linearGradient3934);fill-opacity:1;stroke:none;display:inline" />
+ <path
+ sodipodi:type="arc"
+ style="fill:#51c5fb;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ id="path3902"
+ sodipodi:cx="16.934284"
+ sodipodi:cy="26.854021"
+ sodipodi:rx="0.83941501"
+ sodipodi:ry="0.91240758"
+ d="m 17.773699,26.854021 a 0.83941501,0.91240758 0 1 1 -1.67883,0 0.83941501,0.91240758 0 1 1 1.67883,0 z"
+ transform="matrix(1.4782609,0,0,1.44,-6.3471826,-12.728177)"
+ inkscape:transform-center-x="0.29197043"
+ inkscape:transform-center-y="0.40145934" />
+ <path
+ inkscape:transform-center-y="0.40145934"
+ inkscape:transform-center-x="0.29197043"
+ transform="matrix(1.4782609,0,0,1.44,-9.8143315,-12.874162)"
+ d="m 17.773699,26.854021 a 0.83941501,0.91240758 0 1 1 -1.67883,0 0.83941501,0.91240758 0 1 1 1.67883,0 z"
+ sodipodi:ry="0.91240758"
+ sodipodi:rx="0.83941501"
+ sodipodi:cy="26.854021"
+ sodipodi:cx="16.934284"
+ id="path3922"
+ style="fill:#51c5fb;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ sodipodi:type="arc" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc"
+ id="path3099"
+ d="m 22.164091,17.919233 7.781666,-5.455317 0.02658,-1.885261 -7.845773,5.418269 z"
+ style="fill:#b3b3b3;fill-opacity:1;stroke:none;display:inline" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="spanner"
+ style="display:inline" />
+</svg>
diff --git a/Viewer/images/manual.svg b/Viewer/images/manual.svg
new file mode 100644
index 0000000..2ae3f31
--- /dev/null
+++ b/Viewer/images/manual.svg
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg1455"
+ sodipodi:version="0.32"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="log.svg"
+ inkscape:export-xdpi="120.00000"
+ inkscape:export-ydpi="120.00000"
+ version="1.1"
+ style="display:inline">
+ <defs
+ id="defs3" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="13.90625"
+ inkscape:cx="2.780731"
+ inkscape:cy="15.435982"
+ inkscape:current-layer="layer3"
+ showgrid="true"
+ inkscape:document-units="px"
+ inkscape:grid-bbox="true"
+ inkscape:window-width="1920"
+ inkscape:window-height="1140"
+ inkscape:window-x="-4"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1"
+ inkscape:snap-smooth-nodes="false"
+ inkscape:object-nodes="false"
+ inkscape:snap-grids="false">
+ <inkscape:grid
+ type="xygrid"
+ id="grid3734"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="book"
+ style="display:inline">
+ <path
+ style="fill:#002965;fill-opacity:1;stroke:#23205f;stroke-width:1.04872465px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 16.203615,29.644814 30.949367,22.484526 23.062105,4.6805594 12.088521,9.7121143 1.4101814,4.0940203 3.9166103,24.04763 16.203615,29.644814 z"
+ id="path2875"
+ sodipodi:nodetypes="ccccccc"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;stroke:#454e90;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="M 5.0610846,7.8294154 10.232569,11.459821"
+ id="path3757"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="layer1"
+ inkscape:label="page"
+ inkscape:groupmode="layer"
+ transform="translate(0,-16)"
+ style="display:inline">
+ <path
+ style="fill:#f9f9f9;stroke:#6f777b;stroke-width:0.62923479;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="m 16.460807,45.16101 12.259551,-9.192265 -8.144455,-18.384528 -8.40165,8.224659 4.286554,19.352134 z"
+ id="path3664"
+ sodipodi:nodetypes="ccccc"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="page2">
+ <path
+ style="fill:#f9f9f9;stroke:#6f777b;stroke-width:0.62923479;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+ d="M 16.460807,29.548054 5.6620539,22.4666 2.7650196,1.8326746 12.259983,9.6153523 16.460807,29.548054 z"
+ id="path3662"
+ sodipodi:nodetypes="ccccc"
+ inkscape:connector-curvature="0" />
+ </g>
+</svg>
diff --git a/Viewer/images/manual_ori.svg b/Viewer/images/manual_ori.svg
new file mode 100644
index 0000000..cfa4943
--- /dev/null
+++ b/Viewer/images/manual_ori.svg
@@ -0,0 +1,426 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="manual.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient4022">
+ <stop
+ style="stop-color:#eff8fd;stop-opacity:1;"
+ offset="0"
+ id="stop4024" />
+ <stop
+ style="stop-color:#b3ccd9;stop-opacity:1;"
+ offset="1"
+ id="stop4026" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3954">
+ <stop
+ style="stop-color:#8ebdc9;stop-opacity:1"
+ offset="0"
+ id="stop3956" />
+ <stop
+ style="stop-color:#abb8bb;stop-opacity:1;"
+ offset="1"
+ id="stop3958" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3936">
+ <stop
+ style="stop-color:#9bb2bc;stop-opacity:1;"
+ offset="0"
+ id="stop3938" />
+ <stop
+ style="stop-color:#5c737c;stop-opacity:1;"
+ offset="1"
+ id="stop3940" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3897">
+ <stop
+ style="stop-color:#d7d7d7;stop-opacity:1;"
+ offset="0"
+ id="stop3899" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop3901" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3889">
+ <stop
+ style="stop-color:#f9f9f9;stop-opacity:1"
+ offset="0"
+ id="stop3891" />
+ <stop
+ style="stop-color:#d7d7d7;stop-opacity:1"
+ offset="1"
+ id="stop3893" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3878">
+ <stop
+ style="stop-color:#3360ce;stop-opacity:1"
+ offset="0"
+ id="stop3880" />
+ <stop
+ style="stop-color:#80c0f3;stop-opacity:1"
+ offset="1"
+ id="stop3882" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3800">
+ <stop
+ style="stop-color:#fffff1;stop-opacity:1;"
+ offset="0"
+ id="stop3802" />
+ <stop
+ style="stop-color:#f6eb4c;stop-opacity:1;"
+ offset="1"
+ id="stop3804" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3786">
+ <stop
+ id="stop3788"
+ offset="0"
+ style="stop-color:#a4bef4;stop-opacity:1" />
+ <stop
+ id="stop3790"
+ offset="1"
+ style="stop-color:#d7dce6;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient4010">
+ <stop
+ id="stop4012"
+ offset="0"
+ style="stop-color:#5c8085;stop-opacity:1;" />
+ <stop
+ id="stop4014"
+ offset="1"
+ style="stop-color:#f9feff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3994">
+ <stop
+ style="stop-color:#b7c4c8;stop-opacity:1;"
+ offset="0"
+ id="stop3996" />
+ <stop
+ style="stop-color:#f9f9f9;stop-opacity:1;"
+ offset="1"
+ id="stop3998" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3986">
+ <stop
+ style="stop-color:#f5f97a;stop-opacity:1;"
+ offset="0"
+ id="stop3988" />
+ <stop
+ style="stop-color:#f6eb4c;stop-opacity:1;"
+ offset="1"
+ id="stop3990" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#519aed;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#e9dddd;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f1f3fb;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3614">
+ <stop
+ style="stop-color:#2c71d9;stop-opacity:1;"
+ offset="0"
+ id="stop3616" />
+ <stop
+ style="stop-color:#ececec;stop-opacity:1;"
+ offset="1"
+ id="stop3618" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3602">
+ <stop
+ style="stop-color:#f5f5f5;stop-opacity:1;"
+ offset="0"
+ id="stop3604" />
+ <stop
+ style="stop-color:#141bc6;stop-opacity:1;"
+ offset="1"
+ id="stop3606" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3614"
+ id="linearGradient3691"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="12.89746"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3602"
+ id="linearGradient3693"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="2.2337441"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3728"
+ id="linearGradient3710"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-0.7930209,35.114)"
+ x1="15.413333"
+ y1="3.4795053"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3756"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-0.7930209,35.114)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3786-4"
+ id="linearGradient3992-0"
+ x1="5.2533336"
+ y1="6.8800001"
+ x2="19.76"
+ y2="23.266666"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-0.58666673,-0.26666667)" />
+ <linearGradient
+ id="linearGradient3786-4">
+ <stop
+ id="stop3788-7"
+ offset="0"
+ style="stop-color:#f1f4a4;stop-opacity:1;" />
+ <stop
+ id="stop3790-9"
+ offset="1"
+ style="stop-color:#f6eb4c;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3889"
+ id="linearGradient3913"
+ gradientUnits="userSpaceOnUse"
+ x1="25.550001"
+ y1="5.5933337"
+ x2="25.543337"
+ y2="28.473331"
+ gradientTransform="matrix(0.83792462,0,0,0.8884368,38.935896,4.4857378)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3897"
+ id="linearGradient3915"
+ gradientUnits="userSpaceOnUse"
+ x1="8.950428"
+ y1="2.1045856"
+ x2="22.656668"
+ y2="3.9578578"
+ gradientTransform="matrix(0.83792462,0,0,0.8884368,38.935896,4.4857378)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3954-2"
+ id="linearGradient3960-6"
+ x1="13.64"
+ y1="13.173333"
+ x2="24.639999"
+ y2="24.173334"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-0.64,-1.1733333)" />
+ <linearGradient
+ id="linearGradient3954-2">
+ <stop
+ style="stop-color:#8ebdc9;stop-opacity:1"
+ offset="0"
+ id="stop3956-8" />
+ <stop
+ style="stop-color:#abb8bb;stop-opacity:1;"
+ offset="1"
+ id="stop3958-7" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4022"
+ id="linearGradient4028"
+ x1="15.474243"
+ y1="17.019863"
+ x2="24.904482"
+ y2="27.528622"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.1184951,0,0,1.1170291,0.4774533,-1.7391335)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4022"
+ id="linearGradient3062"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.1184951,0,0,1.1170291,-32.53588,-1.6858002)"
+ x1="24.867817"
+ y1="25.566343"
+ x2="7.881609"
+ y2="6.8069892" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="4.0077728"
+ inkscape:cy="14.353522"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1408"
+ inkscape:window-height="1096"
+ inkscape:window-x="215"
+ inkscape:window-y="0"
+ inkscape:window-maximized="0"
+ showguides="true"
+ inkscape:guide-bbox="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>EcflowUI icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>EcflowUI icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="back1"
+ style="display:inline" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="inner"
+ style="display:inline" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="front"
+ style="display:inline">
+ <path
+ sodipodi:nodetypes="ccccc"
+ inkscape:connector-curvature="0"
+ id="path3911-1"
+ d="m 6.0699294,29.537682 0,-26.8086989 22.3699046,0 0,26.8086989 z"
+ style="fill:url(#linearGradient4028);fill-opacity:1;stroke:#0f3a60;stroke-width:0.99999994000000003px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;display:inline" />
+ <path
+ style="fill:none;stroke:#001622;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="m 3.6272383,7.8434584 c 0.1048726,0.1016596 6.4795577,0 6.4795577,0"
+ id="path4030"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <rect
+ style="fill:#4b6b86;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ id="rect4048"
+ width="11.275421"
+ height="4.7804022"
+ x="-24.389156"
+ y="7.9400368"
+ ry="0.32928398"
+ rx="0"
+ transform="scale(-1,1)" />
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0"
+ id="path4094"
+ d="m 3.6272383,15.547706 c 0.1048726,0.10166 6.4795577,0 6.4795577,0"
+ style="fill:none;stroke:#001622;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+ <path
+ style="fill:none;stroke:#001622;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="m 3.5243882,23.940176 c 0.1048726,0.10166 6.4795578,0 6.4795578,0"
+ id="path4096"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="second"
+ style="display:inline" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer5"
+ inkscape:label="top" />
+</svg>
diff --git a/Viewer/images/node_log.svg b/Viewer/images/node_log.svg
new file mode 100644
index 0000000..cb32b69
--- /dev/null
+++ b/Viewer/images/node_log.svg
@@ -0,0 +1,291 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="node_log.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient8468">
+ <stop
+ id="stop8470"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop8472"
+ offset="1"
+ style="stop-color:#fafafa;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient7756">
+ <stop
+ style="stop-color:#384b72;stop-opacity:1;"
+ offset="0"
+ id="stop7758" />
+ <stop
+ style="stop-color:#3e5990;stop-opacity:1;"
+ offset="1"
+ id="stop7760" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3845">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop3847" />
+ <stop
+ style="stop-color:#bad9e5;stop-opacity:1;"
+ offset="1"
+ id="stop3849" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3786-4"
+ id="linearGradient4793"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.1496437,0,0,1.0974014,-0.68181471,-2.5135733)"
+ x1="29.836605"
+ y1="18.129137"
+ x2="-6.005146"
+ y2="5.2368469" />
+ <linearGradient
+ id="linearGradient3786-4">
+ <stop
+ id="stop3788-7"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop3790-8"
+ offset="1"
+ style="stop-color:#e4eef2;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient7756"
+ id="linearGradient7762"
+ x1="14.201173"
+ y1="16.0353"
+ x2="25.981173"
+ y2="16.0353"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-47.98514,-58.227027)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient7756"
+ id="linearGradient8456"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-37.458755,0.853491)"
+ x1="14.201173"
+ y1="16.0353"
+ x2="25.981173"
+ y2="16.0353" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient7756"
+ id="linearGradient8458"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-37.458755,0.853491)"
+ x1="14.201173"
+ y1="16.0353"
+ x2="25.981173"
+ y2="16.0353" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient7756"
+ id="linearGradient3937"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-57.373537,-40.58822)"
+ x1="14.201173"
+ y1="16.0353"
+ x2="25.981173"
+ y2="16.0353" />
+ <linearGradient
+ id="linearGradient3602-4">
+ <stop
+ style="stop-color:#4a719a;stop-opacity:1;"
+ offset="0"
+ id="stop3604-4" />
+ <stop
+ style="stop-color:#467e97;stop-opacity:1;"
+ offset="1"
+ id="stop3606-3" />
+ </linearGradient>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="32.390762"
+ inkscape:cx="11.822327"
+ inkscape:cy="17.211211"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer3"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1693"
+ inkscape:window-height="1132"
+ inkscape:window-x="52"
+ inkscape:window-y="100"
+ inkscape:window-maximized="0"
+ inkscape:snap-to-guides="false">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>EcflowUI icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>EcflowUI icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="img"
+ sodipodi:insensitive="true"
+ style="display:none">
+ <image
+ y="0.2890628"
+ x="1.3430486"
+ id="image3035"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABHNCSVQICAgIfAhkiAAAIABJREFU eJzs3Xt8HFd1OPBz7szu7EhavyX5oTy9iS1L3gADCaQ8BgLkwasUTAkkIUBiKBRSHi3Q8iu0tBT6 oEADhJAESCgtSVsawiMJSVieiWnWJLZWthPZToIS25K9trWWtLO7c+/vD2mVkbSvmV1J9+6e+/nk Y2l28r1zZ+fcczWvC0CFChUqVKhQabmCDTK8jpj+jzzyyCOPPPLIk9TT66gYAEArsYyTRx555JFH Hnlye0EHAGjbtpbJZGZGHtFoVCQSCZc88sgjjzzyyJPfC3IJAC3L0rPZ7Mz/G4lERDKZLECwUxnk kUceeeSRR94ie34HABiLxcI9PT0z/9/w8LAYGhrKBamcPPLII4888shbEs/XJQC0bd [...]
+ height="31.341492"
+ width="30.122496" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="first"
+ style="display:inline">
+ <path
+ style="fill:#ffffff;fill-opacity:1;stroke:#414b5c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+ d="M 7.3739141,1.9514975 4.1212534,27.144892 c 0,0 -1.1197571,1.851808 2.3110446,4.635063 0,0 18.531213,0.123445 22.611598,0.01812 0,0 2.662525,-1.885484 2.669281,-4.332135 l 0.06786,-24.577157 c 0.0031,-1.105079 -1.46329,-1.8458435 -3.338249,-1.7715975 z"
+ id="path8418"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccsssssc" />
+ <rect
+ style="fill:url(#linearGradient4793);fill-opacity:1;fill-rule:evenodd;stroke:#414b5c;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ id="rect3843"
+ width="26.395824"
+ height="28.576334"
+ x="3.5795317"
+ y="0.50062174"
+ ry="2.3835661" />
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#3d455f;stroke-width:6.44482183;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ id="path3829"
+ sodipodi:cx="-3.8666666"
+ sodipodi:cy="7.04"
+ sodipodi:rx="5.3066669"
+ sodipodi:ry="5.0479193"
+ d="M 1.4023712,7.6400769 A 5.3066669,5.0479193 0 1 1 -4.7149979,2.0569996"
+ sodipodi:start="0.11915787"
+ sodipodi:end="4.5518387"
+ transform="matrix(-0.27864429,-0.2293023,-0.50135483,0.12744222,6.6798023,4.727201)"
+ sodipodi:open="true" />
+ <path
+ sodipodi:type="arc"
+ style="fill:#769ea7;fill-opacity:1;stroke:#6f8a91;stroke-width:1.01176022999999993;stroke-opacity:1;display:inline"
+ id="path8398"
+ sodipodi:cx="16.552216"
+ sodipodi:cy="21.301931"
+ sodipodi:rx="11.112521"
+ sodipodi:ry="11.57878"
+ d="m 27.664737,21.301931 a 11.112521,11.57878 0 1 1 -22.2250426,0 11.112521,11.57878 0 1 1 22.2250426,0 z"
+ transform="matrix(-0.24413564,-0.78633963,0.76067738,-0.23245588,5.9236104,33.281366)" />
+ <text
+ xml:space="preserve"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;display:inline;font-family:Courier;-inkscape-font-specification:Courier Bold"
+ x="12.506907"
+ y="20.468391"
+ id="text7062-1"
+ sodipodi:linespacing="125%"
+ transform="scale(1.009838,0.99025785)"><tspan
+ sodipodi:role="line"
+ id="tspan7064-6"
+ x="12.506907"
+ y="20.468391"
+ style="font-size:18px;font-weight:bold;fill:#ffffff;fill-opacity:1;-inkscape-font-specification:Courier Bold">N</tspan></text>
+ <path
+ sodipodi:open="true"
+ transform="matrix(-0.27864429,-0.2293023,-0.50135483,0.12744222,6.8694669,22.176344)"
+ sodipodi:end="4.5518387"
+ sodipodi:start="0.11915787"
+ d="M 1.4023712,7.6400769 A 5.3066669,5.0479193 0 1 1 -4.7149979,2.0569996"
+ sodipodi:ry="5.0479193"
+ sodipodi:rx="5.3066669"
+ sodipodi:cy="7.04"
+ sodipodi:cx="-3.8666666"
+ id="path4612"
+ style="fill:none;stroke:#3d455f;stroke-width:6.44482183;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#3d455f;stroke-width:7.48595333;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ id="path4614"
+ sodipodi:cx="-3.8666666"
+ sodipodi:cy="7.04"
+ sodipodi:rx="5.3066669"
+ sodipodi:ry="5.0479193"
+ d="M 1.4023712,7.6400769 A 5.3066669,5.0479193 0 1 1 -4.7149979,2.0569996"
+ sodipodi:start="0.11915787"
+ sodipodi:end="4.5518387"
+ transform="matrix(-0.20652745,-0.2293023,-0.37159754,0.12744222,5.571007,13.262107)"
+ sodipodi:open="true" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="second"
+ style="display:inline" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="top" />
+</svg>
diff --git a/Viewer/images/notification.svg b/Viewer/images/notification.svg
new file mode 100644
index 0000000..a7ef7f5
--- /dev/null
+++ b/Viewer/images/notification.svg
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="notification.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#bc9443;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#cc945c;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f2c676;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3614">
+ <stop
+ style="stop-color:#c8613e;stop-opacity:1;"
+ offset="0"
+ id="stop3616" />
+ <stop
+ style="stop-color:#ececec;stop-opacity:1;"
+ offset="1"
+ id="stop3618" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3602">
+ <stop
+ style="stop-color:#facd66;stop-opacity:1;"
+ offset="0"
+ id="stop3604" />
+ <stop
+ style="stop-color:#e29b2a;stop-opacity:1;"
+ offset="1"
+ id="stop3606" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3602"
+ id="linearGradient3693"
+ gradientUnits="userSpaceOnUse"
+ x1="5.6476073"
+ y1="9.7607422"
+ x2="16.754726"
+ y2="6.5932426" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3756"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-13.554303,35.915433)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3602"
+ id="linearGradient3786"
+ x1="5.6476073"
+ y1="9.7607422"
+ x2="18.491278"
+ y2="26.818108"
+ gradientUnits="userSpaceOnUse" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="17.46875"
+ inkscape:cx="16"
+ inkscape:cy="16.057245"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer3"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="886"
+ inkscape:window-height="731"
+ inkscape:window-x="882"
+ inkscape:window-y="302"
+ inkscape:window-maximized="0"
+ showguides="true"
+ inkscape:guide-bbox="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="circle"
+ style="display:inline">
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#linearGradient3786);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3693);stroke-width:0.90856528000000003;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path2820"
+ sodipodi:cx="15.413333"
+ sodipodi:cy="16.559999"
+ sodipodi:rx="13.76"
+ sodipodi:ry="12.613334"
+ d="m 29.173333,16.559999 a 13.76,12.613334 0 1 1 -27.5200003,0 13.76,12.613334 0 1 1 27.5200003,0 z"
+ transform="matrix(1.0537791,0,0,-1.1495772,-0.30224808,35.097001)" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item">
+ <path
+ style="fill:#ffffff;stroke:none"
+ d="M 10.78709,6.3309422 C 9.9984127,6.8332191 10.768294,7.5092456 10.574989,7.6532178 9.1178557,8.7384769 8.3882346,11.15193 8.546331,13.61541 c 0.1873746,2.919701 2.442308,5.398072 2.83879,7.933031 0.08899,0.56902 -0.90573,1.672894 -1.105958,2.625689 -0.166483,0.792213 0.574611,1.674016 0.574611,1.674016 l 16.14158,-8.366108 c 0,0 -0.341433,-1.057359 -1.206999,-1.510819 -0.832102,-0.435931 -2.082133,0.08146 -2.498124,-0.204897 C 20.165422,13.615252 20.527245,11.230428 17.735582,8 [...]
+ id="path3006"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="zssssccssssz" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="top">
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#ab6309;stroke-width:1.24076998000000010;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path3786"
+ sodipodi:cx="16.213333"
+ sodipodi:cy="17.973333"
+ sodipodi:rx="13.973333"
+ sodipodi:ry="13.706667"
+ d="m 30.186666,17.973333 a 13.973333,13.706667 0 1 1 -27.9466662,0 13.973333,13.706667 0 1 1 27.9466662,0 z"
+ transform="matrix(1.0376908,0,0,1.0578794,-0.937761,-2.9536141)" />
+ <path
+ style="fill:#ffffff;stroke:none"
+ d="m 16.716124,24.323863 c 0,0 2.062872,1.553421 3.822625,0.658654 1.759753,-0.894767 1.729494,-3.461877 1.729494,-3.461877 z"
+ id="path3008"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="czcc" />
+ </g>
+</svg>
diff --git a/Viewer/images/output.svg b/Viewer/images/output.svg
new file mode 100644
index 0000000..65f1e30
--- /dev/null
+++ b/Viewer/images/output.svg
@@ -0,0 +1,226 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="output.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient6778">
+ <stop
+ id="stop6780"
+ offset="0"
+ style="stop-color:#eff4fa;stop-opacity:1;" />
+ <stop
+ id="stop6782"
+ offset="1"
+ style="stop-color:#79a0e6;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient6752">
+ <stop
+ style="stop-color:#f7e3a7;stop-opacity:1;"
+ offset="0"
+ id="stop6754" />
+ <stop
+ style="stop-color:#ffd350;stop-opacity:1;"
+ offset="1"
+ id="stop6756" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3786">
+ <stop
+ id="stop3788"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop3790"
+ offset="1"
+ style="stop-color:#ddeaef;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3786"
+ id="linearGradient3992"
+ x1="0.20513386"
+ y1="14.203694"
+ x2="31.668507"
+ y2="24.875128"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.94114523,0,0,-1.136745,0.81694213,91.926371)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3786"
+ id="linearGradient6750"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.85163378,0,0,-1.136745,6.1762589,35.286371)"
+ x1="4.115263"
+ y1="29.217321"
+ x2="17.95472"
+ y2="7.3279505" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient6778"
+ id="linearGradient6758"
+ x1="0.30000001"
+ y1="27.013332"
+ x2="31.700001"
+ y2="27.013332"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(0.26666667,-3.3333336e-8)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient6778"
+ id="linearGradient6766"
+ x1="-0.020001195"
+ y1="10.879999"
+ x2="41.566666"
+ y2="19.626667"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient6752"
+ id="linearGradient6776"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-11.2,13.493333)"
+ x1="0.3"
+ y1="27.013332"
+ x2="31.7"
+ y2="27.013332" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="14.118002"
+ inkscape:cy="14.846182"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer3"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1912"
+ inkscape:window-height="1096"
+ inkscape:window-x="1920"
+ inkscape:window-y="36"
+ inkscape:window-maximized="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>EcflowUI icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>EcflowUI icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="bg">
+ <path
+ style="fill:url(#linearGradient6766);fill-opacity:1;stroke:#334c7e;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;display:inline"
+ d="m 4.4946982,12.186667 0.2519681,19.36 L 31.679997,31.653334 31.567452,10.373333 27.515798,8.3466662 7.3469814,8.6133332 z"
+ id="path6706"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccc" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="first"
+ style="display:inline">
+ <path
+ sodipodi:nodetypes="ccccccccc"
+ inkscape:connector-curvature="0"
+ id="path6736"
+ d="m 8.9606034,1.305275 0.022468,15.334193 0.020837,14.221176 19.7463226,0 L 28.638414,8.3308177 25.002976,6.181428 24.972276,6.105698 22.579144,1.32 C 18.604853,1.32 8.9605975,1.305273 8.9606058,1.305275 z"
+ style="fill:url(#linearGradient6750);fill-opacity:1;stroke:#434964;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="second"
+ style="display:inline">
+ <path
+ style="fill:none;stroke:#757575;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+ d="m 23.649179,6.1673095 -10.578357,0"
+ id="path5639"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:#ffffff;fill-opacity:1;stroke:#434964;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="m 28.573334,8.3539773 -5.959999,-7.1066668 -1e-6,7.0533334 z"
+ id="path3016"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccc" />
+ <path
+ style="fill:url(#linearGradient6758);fill-opacity:1;stroke:#334c7e;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+ d="m 0.48000003,22.346666 4.21333407,9.28 L 31.466667,31.52 26.72,22.453332 z"
+ id="path6704"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:none;stroke:#757575;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+ d="m 24.289178,11.713977 -11.378356,0"
+ id="path6738"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0"
+ id="path6740"
+ d="m 24.395844,16.780643 -11.325023,0"
+ style="fill:none;stroke:#757575;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="top"
+ style="display:inline" />
+</svg>
diff --git a/Viewer/images/overview.svg b/Viewer/images/overview.svg
new file mode 100644
index 0000000..1e6a15c
--- /dev/null
+++ b/Viewer/images/overview.svg
@@ -0,0 +1,231 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="info_panel.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#e8e8e8;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#60838c;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#e2eaed;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#b9bfec;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3614">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop3616" />
+ <stop
+ style="stop-color:#e6e7e8;stop-opacity:1;"
+ offset="1"
+ id="stop3618" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3602">
+ <stop
+ style="stop-color:#f5f5f5;stop-opacity:1;"
+ offset="0"
+ id="stop3604" />
+ <stop
+ style="stop-color:#ececec;stop-opacity:1"
+ offset="1"
+ id="stop3606" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3614"
+ id="linearGradient3691"
+ gradientUnits="userSpaceOnUse"
+ x1="21.851521"
+ y1="14.372232"
+ x2="6.7754312"
+ y2="25.49161" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3602"
+ id="linearGradient3693"
+ gradientUnits="userSpaceOnUse"
+ x1="3.5563364"
+ y1="28.983076"
+ x2="6.7754312"
+ y2="25.49161" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3728"
+ id="linearGradient3710"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0083092,0,0,-1.0648754,-31.614004,39.369806)"
+ x1="15.413333"
+ y1="3.4795053"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3756"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0083092,0,0,-1.0648754,-31.614004,39.369806)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="10.034201"
+ inkscape:cy="15.393958"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer4"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1408"
+ inkscape:window-height="1096"
+ inkscape:window-x="262"
+ inkscape:window-y="65"
+ inkscape:window-maximized="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="circle"
+ style="display:inline">
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#linearGradient3691);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3693);stroke-width:0.93696588;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path2820"
+ sodipodi:cx="15.413333"
+ sodipodi:cy="16.559999"
+ sodipodi:rx="13.76"
+ sodipodi:ry="12.613334"
+ d="m 29.173333,16.559999 a 13.76,12.613334 0 1 1 -27.5200003,0 13.76,12.613334 0 1 1 27.5200003,0 z"
+ transform="matrix(1.0422539,0,0,-1.0928961,-0.06606908,34.015663)" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <text
+ xml:space="preserve"
+ style="font-size:20;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Calibri;-inkscape-font-specification:Calibri"
+ x="3.8399999"
+ y="21.973333"
+ id="text3783"><tspan
+ sodipodi:role="line"
+ id="tspan3785"
+ x="3.8399999"
+ y="21.973333" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="7.2533331"
+ y="15.146667"
+ id="text3787"><tspan
+ sodipodi:role="line"
+ id="tspan3789"
+ x="7.2533331"
+ y="15.146667" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:26.60503197px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#214478;fill-opacity:1;stroke:none;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif"
+ x="10.968117"
+ y="25.590544"
+ id="text3791"
+ transform="scale(1.0152922,0.98493813)"><tspan
+ sodipodi:role="line"
+ id="tspan3793"
+ x="10.968117"
+ y="25.590544"
+ style="font-size:26.60503197px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#214478;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif">i</tspan></text>
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="top">
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#2f6ab7;stroke-width:1.27955496;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path3786"
+ sodipodi:cx="16.213333"
+ sodipodi:cy="17.973333"
+ sodipodi:rx="13.973333"
+ sodipodi:ry="13.706667"
+ d="m 30.186666,17.973333 a 13.973333,13.706667 0 1 1 -27.9466662,0 13.973333,13.706667 0 1 1 27.9466662,0 z"
+ transform="matrix(1.0263416,0,0,1.0057195,-0.7537525,-2.0427931)" />
+ </g>
+</svg>
diff --git a/Viewer/images/padlock.svg b/Viewer/images/padlock.svg
new file mode 100644
index 0000000..e216074
--- /dev/null
+++ b/Viewer/images/padlock.svg
@@ -0,0 +1,213 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.2 r9819"
+ sodipodi:docname="padlock.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3855">
+ <stop
+ style="stop-color:#4a4a4a;stop-opacity:1;"
+ offset="0"
+ id="stop3857" />
+ <stop
+ style="stop-color:#535353;stop-opacity:1;"
+ offset="1"
+ id="stop3859" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3834">
+ <stop
+ style="stop-color:#cd9f63;stop-opacity:1;"
+ offset="0"
+ id="stop3836" />
+ <stop
+ style="stop-color:#f6cf96;stop-opacity:1;"
+ offset="1"
+ id="stop3838" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3834"
+ id="linearGradient3840"
+ x1="2.047343"
+ y1="21.78453"
+ x2="30.09038"
+ y2="21.78453"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3834"
+ id="linearGradient3843"
+ gradientUnits="userSpaceOnUse"
+ x1="2.047343"
+ y1="21.78453"
+ x2="30.09038"
+ y2="21.78453"
+ gradientTransform="translate(-1.2648222,22.197628)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3834"
+ id="linearGradient3853"
+ x1="-13.521739"
+ y1="24.379448"
+ x2="12.952569"
+ y2="24.379448"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.1115393,0,0,0.99709303,16.411189,-2.9647027)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3855"
+ id="linearGradient3861"
+ x1="4.0152406"
+ y1="1028.0546"
+ x2="28.12775"
+ y2="1028.0546"
+ gradientUnits="userSpaceOnUse" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="15.8125"
+ inkscape:cx="9.7522767"
+ inkscape:cy="9.9664087"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer3"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:snap-to-guides="false"
+ inkscape:window-width="1256"
+ inkscape:window-height="934"
+ inkscape:window-x="551"
+ inkscape:window-y="51"
+ inkscape:window-maximized="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2985"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="bg"
+ style="display:none">
+ <rect
+ y="0.48412517"
+ x="0.41408974"
+ height="30.846064"
+ width="31.233715"
+ id="rect3616"
+ style="fill:#ffffff;fill-opacity:1;stroke:#000007;stroke-width:1.05381024;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+ </g>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-1020.3622)"
+ style="display:inline">
+ <rect
+ style="fill:#ffffff;fill-opacity:1;stroke:none"
+ id="rect2987"
+ width="16.296986"
+ height="16.558722"
+ x="7.0974593"
+ y="1033.7483" />
+ <path
+ style="fill:url(#linearGradient3861);fill-opacity:1;stroke:#333333;stroke-width:1.22500000000000010;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="m 16.068862,1021.747 c -9.1332157,-0.01 -11.325695,7.3932 -11.4412852,12.5566 7.6274952,-0.012 15.5712622,0 23.1987762,0 0.220005,-7.1919 -4.372842,-12.7546 -11.757491,-12.5566 z m 0,12.5518 c 0.350174,0.064 -5.742645,0.084 -8.5809639,0 0.1156457,-5.1124 3.4044459,-9.4542 8.5177229,-9.4807 5.006237,-0.076 8.904693,3.3177 8.867897,9.5441 -2.977067,-0.017 -8.454482,0 -8.804656,-0.064 z"
+ id="rect3771"
+ sodipodi:nodetypes="cccccccccc"
+ inkscape:connector-curvature="0" />
+ <rect
+ style="opacity:0;fill:#ff5555;fill-opacity:1;fill-rule:evenodd;stroke:#b1575c;stroke-opacity:1"
+ id="rect2831"
+ width="21.601551"
+ height="13.864602"
+ x="-45.617023"
+ y="0.49516439"
+ transform="translate(0,1020.3622)" />
+ <path
+ sodipodi:type="star"
+ style="opacity:0;fill:#aa0000;fill-opacity:1;fill-rule:evenodd;stroke:#b1575c;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path3609"
+ sodipodi:sides="3"
+ sodipodi:cx="-39.613152"
+ sodipodi:cy="3.3423598"
+ sodipodi:r1="21.948847"
+ sodipodi:r2="10.974423"
+ sodipodi:arg1="0.65139717"
+ sodipodi:arg2="1.6985947"
+ inkscape:flatsided="false"
+ inkscape:rounded="-3.469447e-018"
+ inkscape:randomized="0"
+ d="M -22.158606,16.649903 -41.01185,14.227286 -59.865095,11.804668 -48.340424,-3.3114119 -36.815753,-18.427492 -29.48718,-0.88879442 z"
+ transform="translate(0,1020.3622)" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="fg"
+ style="display:inline">
+ <rect
+ style="fill:url(#linearGradient3853);fill-opacity:1;stroke:#484848;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="rect3845"
+ width="27.204155"
+ height="18.097435"
+ x="2.4927843"
+ y="12.295156"
+ ry="0.56916994" />
+ <path
+ sodipodi:type="arc"
+ style="fill:#484848;fill-opacity:1;stroke:#484848;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path3879"
+ sodipodi:cx="24.094862"
+ sodipodi:cy="22.671936"
+ sodipodi:rx="2.4664032"
+ sodipodi:ry="2.4347825"
+ d="m 26.561265,22.671936 a 2.4664032,2.4347825 0 1 1 -4.932806,0 2.4664032,2.4347825 0 1 1 4.932806,0 z"
+ transform="translate(-0.63241106,-2.3399209)" />
+ <path
+ transform="matrix(-1,-0.01824401,0,1,47.557313,1.2617218)"
+ d="m 24.853755,22.671936 a 0.75889337,2.4347825 0 1 1 -1.517786,0 0.75889337,2.4347825 0 1 1 1.517786,0 z"
+ sodipodi:ry="2.4347825"
+ sodipodi:rx="0.75889337"
+ sodipodi:cy="22.671936"
+ sodipodi:cx="24.094862"
+ id="path3881"
+ style="fill:#484848;fill-opacity:1;stroke:#484848;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ sodipodi:type="arc" />
+ </g>
+</svg>
diff --git a/Viewer/images/path_arrow.svg b/Viewer/images/path_arrow.svg
new file mode 100644
index 0000000..5d5eea5
--- /dev/null
+++ b/Viewer/images/path_arrow.svg
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.2 r9819"
+ sodipodi:docname="directory_arrow.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3624">
+ <stop
+ style="stop-color:#b2b2b2;stop-opacity:1;"
+ offset="0"
+ id="stop3626" />
+ <stop
+ style="stop-color:#515151;stop-opacity:1;"
+ offset="1"
+ id="stop3628" />
+ </linearGradient>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="15.46875"
+ inkscape:cx="-6.1737377"
+ inkscape:cy="16.354555"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer3"
+ showgrid="true"
+ inkscape:window-width="1881"
+ inkscape:window-height="1026"
+ inkscape:window-x="-8"
+ inkscape:window-y="-8"
+ inkscape:window-maximized="1"
+ inkscape:snap-to-guides="false"
+ inkscape:snap-grids="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2831"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="arrow"
+ style="display:inline">
+ <path
+ style="fill:#002255;fill-opacity:1;stroke:none"
+ d="M 10,24 22,16 10,8 z"
+ id="path3622"
+ sodipodi:nodetypes="cccc"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="bar" />
+</svg>
diff --git a/Viewer/images/reload.svg b/Viewer/images/reload.svg
new file mode 100644
index 0000000..cc6b494
--- /dev/null
+++ b/Viewer/images/reload.svg
@@ -0,0 +1,238 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="reload.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3852">
+ <stop
+ style="stop-color:#bd7328;stop-opacity:1"
+ offset="0"
+ id="stop3854" />
+ <stop
+ style="stop-color:#f87f1f;stop-opacity:1"
+ offset="1"
+ id="stop3856" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3799">
+ <stop
+ style="stop-color:#e9c49b;stop-opacity:1"
+ offset="0"
+ id="stop3801" />
+ <stop
+ style="stop-color:#ff9800;stop-opacity:1"
+ offset="1"
+ id="stop3803" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3777">
+ <stop
+ style="stop-color:#0000ad;stop-opacity:1;"
+ offset="0"
+ id="stop3779" />
+ <stop
+ style="stop-color:#25d4ce;stop-opacity:1;"
+ offset="1"
+ id="stop3781" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#519aed;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#e9dddd;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f1f3fb;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3728"
+ id="linearGradient3710"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.1886899,0,0,-1.2899296,-0.54032111,39.211527)"
+ x1="15.413333"
+ y1="3.4795053"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3756"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.1886899,0,0,-1.2899296,-0.54032111,39.211527)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3777"
+ id="linearGradient3783"
+ x1="1.4276053"
+ y1="16.374115"
+ x2="28.440671"
+ y2="16.374115"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0279887,0,0,1.0323478,7.1553463,-2.2096664)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3799"
+ id="linearGradient3834"
+ x1="-9.2158766"
+ y1="17.617861"
+ x2="36.303471"
+ y2="17.617861"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.6376932,0,0,0.76358518,6.7967495,3.2589676)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3852"
+ id="linearGradient3858"
+ x1="4.4050612"
+ y1="16.300755"
+ x2="23.332099"
+ y2="16.521188"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.039503,0,0,1.0329629,0.64943116,0.59425139)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="-0.35329"
+ inkscape:cy="19.861541"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1920"
+ inkscape:window-height="1140"
+ inkscape:window-x="-4"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="circle"
+ style="display:inline">
+ <path
+ style="fill:url(#linearGradient3710);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3720);stroke-width:1.03536737;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ d="m 2.677454,24.057114 c -2.26898106,6.669282 -1.1344905,3.33464 0,0 z"
+ id="path3695"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <path
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="M 25.195659,4.8005208 17.988179,15.901503 27.933522,14.429532 25.195659,4.8005208 z"
+ id="path3872"
+ sodipodi:nodetypes="cccc"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path3823"
+ style="fill:url(#linearGradient3834);fill-opacity:1;stroke:#855900;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1"
+ d="M 22.768247,22.571097 C 19.629624,25.906125 14.27426,26.162584 10.806705,23.143915 9.245624,21.784921 8.3332925,19.993813 8.0883583,18.130799 7.7892322,15.855591 8.485499,13.473137 10.211125,11.639527 c 3.138623,-3.3350283 8.493987,-3.5914882 11.961541,-0.572818 0.03107,0.02705 -4.005361,4.779107 -3.974714,4.806588 L 30.742328,14.874869 30.259982,1.5122364 26.088554,6.3790129 C 20.041371,1.1146547 10.701973,1.5619031 5.2284239,7.3779704 -0.24512559,13.194037 0.21989559,22.17649 [...]
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cssssccccssc" />
+ <path
+ style="fill:url(#linearGradient3858);fill-opacity:1;stroke:none"
+ d="M 15.293391,6.0370671 C 6.7760313,6.2860296 0.70418868,16.68213 7.7921142,24.620644 8.656243,25.449408 11.961076,27.578711 15.852084,27.289269 22.378473,26.861982 23.69003,23.964368 23.173979,23.85278 21.872487,23.571353 21.902663,25.717886 16.06003,26.061511 7.3423181,24.750823 3.8761879,15.237487 11.266923,10.004953 12.995436,8.9778917 14.613912,8.3291145 16.293549,8.2451512 18.270837,8.1463084 20.332886,8.8302016 22.758988,10.601138 22.341735,7.6886086 19.166305,6.392768 15. [...]
+ id="path3844"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccsccscc" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="top"
+ style="display:none"
+ sodipodi:insensitive="true">
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#2f6ab7;stroke-width:1.24076998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path3786"
+ sodipodi:cx="16.213333"
+ sodipodi:cy="17.973333"
+ sodipodi:rx="13.973333"
+ sodipodi:ry="13.706667"
+ d="m 30.186666,17.973333 a 13.973333,13.706667 0 1 1 -27.9466662,0 13.973333,13.706667 0 1 1 27.9466662,0 z"
+ transform="matrix(1.0376908,0,0,1.0578794,-0.937761,-2.9536141)" />
+ </g>
+</svg>
diff --git a/Viewer/images/reload_black.svg b/Viewer/images/reload_black.svg
new file mode 100644
index 0000000..304fd7a
--- /dev/null
+++ b/Viewer/images/reload_black.svg
@@ -0,0 +1,246 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="reload_black.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3852">
+ <stop
+ style="stop-color:#467b3c;stop-opacity:1;"
+ offset="0"
+ id="stop3854" />
+ <stop
+ style="stop-color:#3d9f3d;stop-opacity:0.99215686;"
+ offset="1"
+ id="stop3856" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3799">
+ <stop
+ style="stop-color:#aae1be;stop-opacity:1;"
+ offset="0"
+ id="stop3801" />
+ <stop
+ style="stop-color:#4bc82b;stop-opacity:1;"
+ offset="1"
+ id="stop3803" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3777">
+ <stop
+ style="stop-color:#0000ad;stop-opacity:1;"
+ offset="0"
+ id="stop3779" />
+ <stop
+ style="stop-color:#25d4ce;stop-opacity:1;"
+ offset="1"
+ id="stop3781" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#519aed;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#e9dddd;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f1f3fb;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3728"
+ id="linearGradient3710"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.1066784,0,0,-1.2085368,0.23065739,37.26001)"
+ x1="15.413333"
+ y1="3.4795053"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3756"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.1066784,0,0,-1.2085368,0.23065739,37.26001)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3777"
+ id="linearGradient3783"
+ x1="1.4276053"
+ y1="16.374115"
+ x2="28.440671"
+ y2="16.374115"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0279887,0,0,1.0323478,7.1553463,-2.2096664)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3799"
+ id="linearGradient3834"
+ x1="-9.2158766"
+ y1="17.617861"
+ x2="36.303471"
+ y2="17.617861"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.59369669,0,0,0.71540403,-20.45848,-2.9306599)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3852"
+ id="linearGradient3858"
+ x1="4.4050612"
+ y1="16.300755"
+ x2="23.332099"
+ y2="16.521188"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.96778437,0,0,0.96778437,-37.008342,-1.5339029)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="17.293648"
+ inkscape:cy="19.834875"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1354"
+ inkscape:window-height="920"
+ inkscape:window-x="476"
+ inkscape:window-y="405"
+ inkscape:window-maximized="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="circle"
+ style="display:inline">
+ <path
+ style="fill:url(#linearGradient3710);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3720);stroke-width:1.03536737;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ d="m 3.2264279,23.061819 c -2.1124368,6.24846 -1.0562184,3.12423 0,0 z"
+ id="path3695"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <path
+ id="path3823"
+ style="fill:url(#linearGradient3834);fill-opacity:1;stroke:#204725;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1"
+ d="m -5.5889072,15.162902 c -2.9220801,3.124593 -7.9079608,3.364869 -11.1362768,0.536674 -1.453377,-1.273244 -2.302764,-2.951335 -2.530799,-4.696796 -0.278489,-2.1316457 0.36974,-4.3637706 1.976309,-6.0816818 2.92208,-3.1245929 7.9079607,-3.3648705 11.1362767,-0.5366746 0.028925,0.02534 -3.729019,4.4775529 -3.700486,4.5032995 L 1.8350164,7.9522945 1.3859484,-4.5671748 -2.4976793,-0.00748502 C -8.127648,-4.9396697 -16.82269,-4.520642 -21.918602,0.92843966 -27.014514,6.3775206 -26.5 [...]
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cssssccccssc" />
+ <path
+ style="fill:url(#linearGradient3858);fill-opacity:1;stroke:none"
+ d="m -23.374716,3.5654787 c -7.929719,0.2332533 -13.582646,9.9733743 -6.983739,17.4109793 0.804509,0.77647 3.881331,2.771417 7.503886,2.500239 6.076112,-0.400327 7.297181,-3.115105 6.816734,-3.219652 -1.211698,-0.26367 -1.183604,1.747421 -6.623135,2.069363 -8.116249,-1.227985 -11.343239,-10.141043 -4.462415,-15.0434116 1.609257,-0.962255 3.116069,-1.5700954 4.679822,-1.6487606 1.84087,-0.092606 3.760651,0.5481345 6.019369,2.2073269 -0.388466,-2.7287525 -3.344813,-3.9428274 -6.9505 [...]
+ id="path3844"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccsccscc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="m 23.360001,24.32 c 0,0 -4.532571,4.312499 -11.146668,2.613333 -3.6333,-0.933397 -6.9299918,-5.247308 -7.4666663,-8.96 C 4.238375,14.456992 5.80793,10.608258 8.48,8.2666667 c 2.919613,-2.5585192 6.097124,-3.0763881 9.066666,-2.56 4.526192,0.7870815 7.146667,4.7466663 7.146667,4.7466663"
+ id="path3010"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cssssc" />
+ <path
+ style="fill:#1a1a1a;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ inkscape:transform-center-x="0.55689782"
+ inkscape:transform-center-y="-0.92757219"
+ d="M 19.262467,14.977119 28.621559,5.1983492 29.27707,14.973173 z"
+ id="path3012"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccc" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="top"
+ style="display:none"
+ sodipodi:insensitive="true">
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#2f6ab7;stroke-width:1.24076998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path3786"
+ sodipodi:cx="16.213333"
+ sodipodi:cy="17.973333"
+ sodipodi:rx="13.973333"
+ sodipodi:ry="13.706667"
+ d="m 30.186666,17.973333 a 13.973333,13.706667 0 1 1 -27.9466662,0 13.973333,13.706667 0 1 1 27.9466662,0 z"
+ transform="matrix(1.0376908,0,0,1.0578794,-0.937761,-2.9536141)" />
+ </g>
+</svg>
diff --git a/Viewer/images/reload_one.svg b/Viewer/images/reload_one.svg
new file mode 100644
index 0000000..12cce8c
--- /dev/null
+++ b/Viewer/images/reload_one.svg
@@ -0,0 +1,238 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="reload_one.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3852">
+ <stop
+ style="stop-color:#47a036;stop-opacity:1;"
+ offset="0"
+ id="stop3854" />
+ <stop
+ style="stop-color:#3d9f3d;stop-opacity:0.99215686;"
+ offset="1"
+ id="stop3856" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3799">
+ <stop
+ style="stop-color:#95d393;stop-opacity:1;"
+ offset="0"
+ id="stop3801" />
+ <stop
+ style="stop-color:#49d444;stop-opacity:1;"
+ offset="1"
+ id="stop3803" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3777">
+ <stop
+ style="stop-color:#0000ad;stop-opacity:1;"
+ offset="0"
+ id="stop3779" />
+ <stop
+ style="stop-color:#25d4ce;stop-opacity:1;"
+ offset="1"
+ id="stop3781" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#519aed;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#e9dddd;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f1f3fb;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3728"
+ id="linearGradient3710"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.1886899,0,0,-1.2899296,-0.54032111,39.211527)"
+ x1="15.413333"
+ y1="3.4795053"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3756"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.1886899,0,0,-1.2899296,-0.54032111,39.211527)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3777"
+ id="linearGradient3783"
+ x1="1.4276053"
+ y1="16.374115"
+ x2="28.440671"
+ y2="16.374115"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0279887,0,0,1.0323478,7.1553463,-2.2096664)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3799"
+ id="linearGradient3834"
+ x1="-9.2158766"
+ y1="17.617861"
+ x2="36.303471"
+ y2="17.617861"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.6376932,0,0,0.76358518,6.7967495,3.2589676)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3852"
+ id="linearGradient3858"
+ x1="4.4050612"
+ y1="16.300755"
+ x2="23.332099"
+ y2="16.521188"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.039503,0,0,1.0329629,0.64943116,0.59425139)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="8.20671"
+ inkscape:cy="19.861541"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1920"
+ inkscape:window-height="1140"
+ inkscape:window-x="-4"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="circle"
+ style="display:inline">
+ <path
+ style="fill:url(#linearGradient3710);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3720);stroke-width:1.03536737;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ d="m 2.677454,24.057114 c -2.26898106,6.669282 -1.1344905,3.33464 0,0 z"
+ id="path3695"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <path
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="M 25.195659,4.8005208 17.988179,15.901503 27.933522,14.429532 25.195659,4.8005208 z"
+ id="path3872"
+ sodipodi:nodetypes="cccc"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path3823"
+ style="fill:url(#linearGradient3834);fill-opacity:1;stroke:#006b0c;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1"
+ d="M 22.768247,22.571097 C 19.629624,25.906125 14.27426,26.162584 10.806705,23.143915 9.245624,21.784921 8.3332925,19.993813 8.0883583,18.130799 7.7892322,15.855591 8.485499,13.473137 10.211125,11.639527 c 3.138623,-3.3350283 8.493987,-3.5914882 11.961541,-0.572818 0.03107,0.02705 -4.005361,4.779107 -3.974714,4.806588 L 30.742328,14.874869 30.259982,1.5122364 26.088554,6.3790129 C 20.041371,1.1146547 10.701973,1.5619031 5.2284239,7.3779704 -0.24512559,13.194037 0.21989559,22.17649 [...]
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cssssccccssc" />
+ <path
+ style="fill:url(#linearGradient3858);fill-opacity:1;stroke:none"
+ d="M 15.293391,6.0370671 C 6.7760313,6.2860296 0.70418868,16.68213 7.7921142,24.620644 8.656243,25.449408 11.961076,27.578711 15.852084,27.289269 22.378473,26.861982 23.69003,23.964368 23.173979,23.85278 21.872487,23.571353 21.902663,25.717886 16.06003,26.061511 7.3423181,24.750823 3.8761879,15.237487 11.266923,10.004953 12.995436,8.9778917 14.613912,8.3291145 16.293549,8.2451512 18.270837,8.1463084 20.332886,8.8302016 22.758988,10.601138 22.341735,7.6886086 19.166305,6.392768 15. [...]
+ id="path3844"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccsccscc" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="top"
+ style="display:none"
+ sodipodi:insensitive="true">
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#2f6ab7;stroke-width:1.24076998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path3786"
+ sodipodi:cx="16.213333"
+ sodipodi:cy="17.973333"
+ sodipodi:rx="13.973333"
+ sodipodi:ry="13.706667"
+ d="m 30.186666,17.973333 a 13.973333,13.706667 0 1 1 -27.9466662,0 13.973333,13.706667 0 1 1 27.9466662,0 z"
+ transform="matrix(1.0376908,0,0,1.0578794,-0.937761,-2.9536141)" />
+ </g>
+</svg>
diff --git a/Viewer/images/rescue.svg b/Viewer/images/rescue.svg
new file mode 100644
index 0000000..a3f71d9
--- /dev/null
+++ b/Viewer/images/rescue.svg
@@ -0,0 +1,299 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="rescue.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3782">
+ <stop
+ style="stop-color:#000080;stop-opacity:1;"
+ offset="0"
+ id="stop3784" />
+ <stop
+ style="stop-color:#578eb5;stop-opacity:0.9910714;"
+ offset="1"
+ id="stop3786" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3608">
+ <stop
+ id="stop3610"
+ offset="0"
+ style="stop-color:#2eaf1d;stop-opacity:1;" />
+ <stop
+ id="stop3612"
+ offset="1"
+ style="stop-color:#91ff44;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3612">
+ <stop
+ style="stop-color:#616161;stop-opacity:1;"
+ offset="0"
+ id="stop3614" />
+ <stop
+ style="stop-color:#383838;stop-opacity:1;"
+ offset="1"
+ id="stop3616" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3601">
+ <stop
+ style="stop-color:#a2a2a2;stop-opacity:1;"
+ offset="0"
+ id="stop3603" />
+ <stop
+ style="stop-color:#343434;stop-opacity:1;"
+ offset="1"
+ id="stop3605" />
+ </linearGradient>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ id="perspective10" />
+ <inkscape:perspective
+ id="perspective2825"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <inkscape:perspective
+ id="perspective2841"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3601"
+ id="linearGradient3607"
+ x1="10.653805"
+ y1="3.7712457"
+ x2="24.085051"
+ y2="29.5"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.96774194,0,0,-0.96774194,0.58051457,31.158684)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3612"
+ id="linearGradient3618"
+ x1="3"
+ y1="28.806061"
+ x2="29"
+ y2="28.806061"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3612"
+ id="linearGradient3620"
+ gradientUnits="userSpaceOnUse"
+ x1="3"
+ y1="28.806061"
+ x2="29"
+ y2="28.806061"
+ gradientTransform="translate(0,-32.806061)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3608"
+ id="linearGradient3606"
+ x1="24"
+ y1="26"
+ x2="7"
+ y2="8"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.83718675,0,0,0.87310139,-36.94508,11.435241)" />
+ <linearGradient
+ id="linearGradient3757">
+ <stop
+ id="stop3759"
+ offset="0"
+ style="stop-color:#fdfb72;stop-opacity:1;" />
+ <stop
+ id="stop3761"
+ offset="1"
+ style="stop-color:#ffb41b;stop-opacity:1;" />
+ </linearGradient>
+ <inkscape:perspective
+ id="perspective2882"
+ inkscape:persp3d-origin="16 : 10.666667 : 1"
+ inkscape:vp_z="32 : 16 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 16 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <inkscape:perspective
+ id="perspective3015"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <linearGradient
+ id="linearGradient3845">
+ <stop
+ style="stop-color:#326dc2;stop-opacity:1;"
+ offset="0"
+ id="stop3847" />
+ <stop
+ style="stop-color:#6295be;stop-opacity:1;"
+ offset="1"
+ id="stop3849" />
+ </linearGradient>
+ <linearGradient
+ y2="19.5"
+ x2="38.5"
+ y1="19.5"
+ x1="7.5"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3945"
+ xlink:href="#linearGradient3845-1"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3845-1">
+ <stop
+ style="stop-color:#018049;stop-opacity:1;"
+ offset="0"
+ id="stop3847-7" />
+ <stop
+ style="stop-color:#01b549;stop-opacity:1;"
+ offset="1"
+ id="stop3849-4" />
+ </linearGradient>
+ <linearGradient
+ y2="19.5"
+ x2="38.5"
+ y1="19.5"
+ x1="7.5"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3066"
+ xlink:href="#linearGradient3845-1"
+ inkscape:collect="always" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3845-1"
+ id="linearGradient3808"
+ x1="-12.355866"
+ y1="27.080372"
+ x2="-21.346371"
+ y2="14.270093"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.2173913,0,0,1.2185686,36.086959,-4.1199214)" />
+ <filter
+ inkscape:collect="always"
+ id="filter3824">
+ <feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="0.53563009"
+ id="feGaussianBlur3826" />
+ </filter>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="16.15625"
+ inkscape:cx="9.8446626"
+ inkscape:cy="16"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer3"
+ showgrid="true"
+ inkscape:window-width="1372"
+ inkscape:window-height="971"
+ inkscape:window-x="460"
+ inkscape:window-y="71"
+ inkscape:window-maximized="0"
+ inkscape:snap-to-guides="false"
+ inkscape:snap-grids="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2831"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="plus"
+ style="display:inline">
+ <rect
+ style="fill:url(#linearGradient3808);fill-opacity:1;stroke:#1e702c;stroke-width:1.86666679;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="rect3032"
+ width="28"
+ height="21.934235"
+ x="2"
+ y="8.0657644"
+ ry="2.9342356" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="star"
+ style="display:inline">
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccc"
+ id="path3810"
+ d="m 13.023506,10.580271 5.374126,0 0,5.431979 5.374128,0 0,5.43198 -5.374128,0 0,5.431979 -5.374126,0 0,-5.431979 -5.4142216,0 0,-5.43198 5.4142216,0 z"
+ style="fill:#ffffff;fill-opacity:1;stroke:none;display:inline" />
+ <path
+ style="fill:none;stroke:#1e702c;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="m 9,8 1,-6 13,0 1,6"
+ id="path3790"
+ inkscape:connector-curvature="0" />
+ </g>
+</svg>
diff --git a/Viewer/images/reset.svg b/Viewer/images/reset.svg
new file mode 100644
index 0000000..cebdcdc
--- /dev/null
+++ b/Viewer/images/reset.svg
@@ -0,0 +1,282 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="reset.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3852">
+ <stop
+ style="stop-color:#467b3c;stop-opacity:1;"
+ offset="0"
+ id="stop3854" />
+ <stop
+ style="stop-color:#3d9f3d;stop-opacity:0.99215686;"
+ offset="1"
+ id="stop3856" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3799">
+ <stop
+ style="stop-color:#aae1be;stop-opacity:1;"
+ offset="0"
+ id="stop3801" />
+ <stop
+ style="stop-color:#4bc82b;stop-opacity:1;"
+ offset="1"
+ id="stop3803" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3777">
+ <stop
+ style="stop-color:#0000ad;stop-opacity:1;"
+ offset="0"
+ id="stop3779" />
+ <stop
+ style="stop-color:#25d4ce;stop-opacity:1;"
+ offset="1"
+ id="stop3781" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#519aed;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#e9dddd;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f1f3fb;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3728"
+ id="linearGradient3710"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.1066784,0,0,-1.2085368,0.23065739,37.26001)"
+ x1="15.413333"
+ y1="3.4795053"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3756"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.1066784,0,0,-1.2085368,0.23065739,37.26001)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3777"
+ id="linearGradient3783"
+ x1="1.4276053"
+ y1="16.374115"
+ x2="28.440671"
+ y2="16.374115"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0279887,0,0,1.0323478,7.1553463,-2.2096664)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3799"
+ id="linearGradient3834"
+ x1="-9.2158766"
+ y1="17.617861"
+ x2="36.303471"
+ y2="17.617861"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.58696949,0,0,0.69646685,-20.195316,-9.1731731)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3852"
+ id="linearGradient3858"
+ x1="4.4050612"
+ y1="16.300755"
+ x2="23.332099"
+ y2="16.521188"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.96778437,0,0,0.96778437,-23.995009,-11.507236)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="8.20671"
+ inkscape:cy="19.808208"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1920"
+ inkscape:window-height="1140"
+ inkscape:window-x="-4"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>ecFlow_ui icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>ecFlow_ui icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="circle"
+ style="display:inline">
+ <path
+ style="fill:url(#linearGradient3710);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3720);stroke-width:1.03536737;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ d="m 3.2264279,23.061819 c -2.1124368,6.24846 -1.0562184,3.12423 0,0 z"
+ id="path3695"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer5"
+ inkscape:label="dup">
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#904a3d;stroke-width:3.07148147;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ id="path3786-0-6"
+ sodipodi:cx="16.213333"
+ sodipodi:cy="17.973333"
+ sodipodi:rx="13.973333"
+ sodipodi:ry="13.706667"
+ d="M 30.186666,17.973333 A 13.973333,13.706667 0 1 1 17.382592,4.3147376"
+ transform="matrix(0.81471999,0.52159237,-0.53179041,0.83049208,13.199085,-6.5834619)"
+ sodipodi:start="0"
+ sodipodi:end="4.7961648"
+ sodipodi:open="true" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#ec4223;stroke-width:2.05578876;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ id="path3786-0"
+ sodipodi:cx="16.213333"
+ sodipodi:cy="17.973333"
+ sodipodi:rx="13.973333"
+ sodipodi:ry="13.706667"
+ d="M 30.186666,17.973333 A 13.973333,13.706667 0 1 1 17.382592,4.3147376"
+ transform="matrix(0.81148675,0.51953455,-0.52967998,0.82721557,12.831442,-7.3359124)"
+ sodipodi:start="0"
+ sodipodi:end="4.7961648"
+ sodipodi:open="true" />
+ <path
+ sodipodi:type="star"
+ style="opacity:0;fill:#d34868;fill-opacity:1;fill-rule:evenodd;stroke:#f77ae2;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path3864"
+ sodipodi:sides="3"
+ sodipodi:cx="15.786667"
+ sodipodi:cy="-7.7333331"
+ sodipodi:r1="7.913847"
+ sodipodi:r2="4.0360622"
+ sodipodi:arg1="0.97718631"
+ sodipodi:arg2="2.0243839"
+ inkscape:flatsided="false"
+ inkscape:rounded="0.04"
+ inkscape:randomized="-0.001"
+ d="m 20.206983,-1.1687402 c -0.227345,0.1530424 -5.939569,-2.8140148 -6.186075,-2.9340857 -0.246505,-0.120071 -6.1036701,-2.8064635 -6.1228817,-3.0799282 -0.019212,-0.2734647 5.4088617,-3.7367979 5.6360547,-3.8904889 0.227193,-0.153691 5.475481,-3.895108 5.721758,-3.77474 0.246277,0.120368 0.543755,6.5535167 0.562616,6.8271428 0.01886,0.2736261 0.615873,6.6990576 0.388528,6.8521 z"
+ inkscape:transform-center-x="1.7084076"
+ inkscape:transform-center-y="-0.27358932" />
+ <path
+ style="fill:#ec4223;stroke:none"
+ d="M 27.41997,1.0209203 21.521223,9.7969942 29.752535,9.0337011 z"
+ id="path3866"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="top"
+ style="display:inline">
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#ec4223;stroke-width:2.65748382;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path3786"
+ sodipodi:cx="16.213333"
+ sodipodi:cy="17.973333"
+ sodipodi:rx="13.973333"
+ sodipodi:ry="13.706667"
+ d="m 30.186666,17.973333 a 13.973333,13.706667 0 1 1 -27.9466662,0 13.973333,13.706667 0 1 1 27.9466662,0 z"
+ transform="matrix(0.48449427,0,0,0.49392022,9.3680655,7.5526128)" />
+ <path
+ style="fill:#ec4223;fill-opacity:1;stroke:#ec4223;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="m 17.173333,11.588813 c 0,5.675708 0,5.675708 0,5.675708"
+ id="path3798"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:#ec4223;fill-opacity:1;stroke:#ec4223;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+ d="m 16.959447,16.886046 c 3.841105,2.485937 3.841105,2.485937 3.841105,2.485937"
+ id="path3798-6"
+ inkscape:connector-curvature="0" />
+ </g>
+</svg>
diff --git a/Viewer/images/reset_to_default.svg b/Viewer/images/reset_to_default.svg
new file mode 100644
index 0000000..02ea8ce
--- /dev/null
+++ b/Viewer/images/reset_to_default.svg
@@ -0,0 +1,238 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.2 r9819"
+ sodipodi:docname="undo.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3852">
+ <stop
+ style="stop-color:#c26e1e;stop-opacity:1;"
+ offset="0"
+ id="stop3854" />
+ <stop
+ style="stop-color:#fdc030;stop-opacity:0.99215686;"
+ offset="1"
+ id="stop3856" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3799">
+ <stop
+ style="stop-color:#f2ec60;stop-opacity:1;"
+ offset="0"
+ id="stop3801" />
+ <stop
+ style="stop-color:#ecc118;stop-opacity:1;"
+ offset="1"
+ id="stop3803" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3777">
+ <stop
+ style="stop-color:#0000ad;stop-opacity:1;"
+ offset="0"
+ id="stop3779" />
+ <stop
+ style="stop-color:#25d4ce;stop-opacity:1;"
+ offset="1"
+ id="stop3781" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#519aed;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#e9dddd;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f1f3fb;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3728"
+ id="linearGradient3710"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-1.1066784,0,0,-1.2085368,31.215951,40.353343)"
+ x1="15.413333"
+ y1="3.4795053"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3756"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-1.1066784,0,0,-1.2085368,31.215951,40.353343)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3777"
+ id="linearGradient3783"
+ x1="1.4276053"
+ y1="16.374115"
+ x2="28.440671"
+ y2="16.374115"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0279887,0,0,1.0323478,7.1553463,-2.2096664)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3799"
+ id="linearGradient3834"
+ x1="-9.2158766"
+ y1="17.617861"
+ x2="36.303471"
+ y2="17.617861"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-0.59369669,0,0,0.71540403,24.385089,6.6693401)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3852"
+ id="linearGradient3823"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-0.96778437,0,0,0.96778437,29.89495,4.3327637)"
+ x1="4.4050612"
+ y1="16.300755"
+ x2="23.332099"
+ y2="16.521188" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="14.980246"
+ inkscape:cy="16.22725"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1349"
+ inkscape:window-height="828"
+ inkscape:window-x="320"
+ inkscape:window-y="43"
+ inkscape:window-maximized="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="circle"
+ style="display:inline">
+ <path
+ style="fill:url(#linearGradient3710);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3720);stroke-width:1.03536737;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ d="m 28.220181,26.155152 c 2.112436,6.24846 1.056218,3.12423 0,0 z"
+ id="path3695"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <path
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="M 7.2555798,8.1136233 13.965792,18.514148 4.7066108,17.135057 7.2555798,8.1136233 z"
+ id="path3872"
+ sodipodi:nodetypes="cccc"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path3823"
+ style="fill:url(#linearGradient3834);fill-opacity:1;stroke:#633624;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1"
+ d="m 19.211793,22.099576 c 2.78671,-1.470376 3.181437,-3.873236 3.170799,-4.27013 -0.07432,-2.772627 -1.354722,-3.843702 -2.082976,-4.428348 -1.911829,-1.534824 -6.78796,-1.978204 -10.016276,0.849992 -0.02892,0.02534 4.111848,5.095513 4.073819,5.089966 L 1.8249258,16.965628 2.0073268,4.3394918 5.9976208,9.1658483 C 11.62759,4.2336636 21.859917,4.0671464 26.591877,9.8351063 30.776543,14.93595 30.355161,20.810375 26.05155,26.498717"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="csssscccsc" />
+ <path
+ style="fill:url(#linearGradient3823);fill-opacity:1;stroke:none"
+ d="m 16.154657,8.8454786 c 9.476387,-0.1934134 12.51598,10.1867064 7.250407,15.4909784 -1.361146,-0.771641 -2.728211,-1.196299 -3.03946,-2.128405 3.302055,-2.057565 3.881514,-6.656158 -0.248944,-9.858389 -2.311195,-0.861978 -3.46514,-0.931631 -4.786489,-0.848761 -1.729731,0.108482 -3.333984,0.601468 -5.5927022,2.26066 C 10.125935,11.03281 12.548948,9.1787352 16.154657,8.8454786 z"
+ id="path3844"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccscc" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="top"
+ style="display:none"
+ sodipodi:insensitive="true">
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#2f6ab7;stroke-width:1.24076998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path3786"
+ sodipodi:cx="16.213333"
+ sodipodi:cy="17.973333"
+ sodipodi:rx="13.973333"
+ sodipodi:ry="13.706667"
+ d="m 30.186666,17.973333 a 13.973333,13.706667 0 1 1 -27.9466662,0 13.973333,13.706667 0 1 1 27.9466662,0 z"
+ transform="matrix(1.0376908,0,0,1.0578794,-0.937761,-2.9536141)" />
+ </g>
+</svg>
diff --git a/Viewer/images/script.svg b/Viewer/images/script.svg
new file mode 100644
index 0000000..a114491
--- /dev/null
+++ b/Viewer/images/script.svg
@@ -0,0 +1,293 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="script.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3796">
+ <stop
+ id="stop3798"
+ offset="0"
+ style="stop-color:#e8eef2;stop-opacity:1;" />
+ <stop
+ id="stop3800"
+ offset="1"
+ style="stop-color:#c5d9e4;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient4010">
+ <stop
+ id="stop4012"
+ offset="0"
+ style="stop-color:#5c8085;stop-opacity:1;" />
+ <stop
+ id="stop4014"
+ offset="1"
+ style="stop-color:#f9feff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3994">
+ <stop
+ style="stop-color:#a5cbe0;stop-opacity:1;"
+ offset="0"
+ id="stop3996" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop3998" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3986">
+ <stop
+ style="stop-color:#e3e1db;stop-opacity:1;"
+ offset="0"
+ id="stop3988" />
+ <stop
+ style="stop-color:#b3cbd0;stop-opacity:1;"
+ offset="1"
+ id="stop3990" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#519aed;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#e9dddd;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f1f3fb;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3614">
+ <stop
+ style="stop-color:#2c71d9;stop-opacity:1;"
+ offset="0"
+ id="stop3616" />
+ <stop
+ style="stop-color:#ececec;stop-opacity:1;"
+ offset="1"
+ id="stop3618" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3602">
+ <stop
+ style="stop-color:#f5f5f5;stop-opacity:1;"
+ offset="0"
+ id="stop3604" />
+ <stop
+ style="stop-color:#141bc6;stop-opacity:1;"
+ offset="1"
+ id="stop3606" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3614"
+ id="linearGradient3691"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="12.89746"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3602"
+ id="linearGradient3693"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="2.2337441"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3728"
+ id="linearGradient3710"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-0.7930209,35.114)"
+ x1="15.413333"
+ y1="3.4795053"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3756"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-0.7930209,35.114)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3796"
+ id="linearGradient3992"
+ x1="15.664435"
+ y1="7.5391989"
+ x2="15.664435"
+ y2="31.30624"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.93057118,0,0,0.96772665,1.4231279,0.70411639)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3994"
+ id="linearGradient4000"
+ x1="8.1421738"
+ y1="31.30624"
+ x2="8.1421738"
+ y2="24.072794"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.93057118,0,0,0.96772665,1.4231279,0.70411639)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4010"
+ id="linearGradient3790"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-33.92,-1.8133333)"
+ x1="20.726667"
+ y1="4.0266666"
+ x2="22.846666"
+ y2="3.7066665" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3986"
+ id="linearGradient3792"
+ gradientUnits="userSpaceOnUse"
+ x1="14"
+ y1="4"
+ x2="10"
+ y2="23"
+ gradientTransform="translate(-33.813333,-1.0666667)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3994"
+ id="linearGradient3794"
+ gradientUnits="userSpaceOnUse"
+ x1="8"
+ y1="31"
+ x2="8"
+ y2="23"
+ gradientTransform="translate(-33.813333,-1.0666667)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="13.358417"
+ inkscape:cy="15.420624"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer3"
+ showgrid="true"
+ inkscape:snap-grids="true"
+ inkscape:window-width="1513"
+ inkscape:window-height="1001"
+ inkscape:window-x="399"
+ inkscape:window-y="60"
+ inkscape:window-maximized="0"
+ showguides="true"
+ inkscape:guide-bbox="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="second"
+ style="display:inline">
+ <path
+ style="fill:#eaf2fd;fill-opacity:1;stroke:#000000;stroke-width:0.99999994000000003px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 20.444003,2.6266667 6.513998,0 c 1.204846,0 3.137841,0.049528 2.791713,4.8386332 l -9.305711,0 c 0,-4.8386332 0,-4.8386332 0,-4.8386332 z"
+ id="path3198"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="csccc" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="first"
+ style="display:inline">
+ <path
+ style="fill:url(#linearGradient3992);fill-opacity:1;stroke:#000000;stroke-width:0.99999994000000003px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 7.006555,29.735916 0,-24.1931664 c 0,0 0,-2.9031799 2.7917135,-2.9031799 l 13.0279965,0 c 1.603974,0 1.377835,0 1.861142,0 2.791714,0 -0.112644,0.082028 0,2.9031799 0,0 -0.02758,11.5677894 0,17.4190794 0.02938,6.23321 0.05882,6.774087 -1.861142,6.774087 -6.203808,0 -9.615903,-3e-6 -15.81971,0 z"
+ id="path3195"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccssssscc" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="top">
+ <path
+ style="fill:url(#linearGradient4000);fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1;display:inline;stroke-miterlimit:4;stroke-dasharray:none"
+ d="m 5.4183801,22.07152 c -0.9305711,0 -2.7917135,1.935454 -2.7917135,3.870907 0,1.34207 1.16348,3.878557 2.7917135,3.870907 l 16.4773139,-0.07742 c -0.930572,0 -2.791714,-2.046144 -2.791714,-3.870907 C 19.10398,22.961827 21,22 21,22 19.138857,22 7.2795225,22.07152 5.4183801,22.07152 z"
+ id="path3193-7"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ssscscs" />
+ </g>
+</svg>
diff --git a/Viewer/images/search.svg b/Viewer/images/search.svg
new file mode 100644
index 0000000..6a6ef4c
--- /dev/null
+++ b/Viewer/images/search.svg
@@ -0,0 +1,172 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2458"
+ sodipodi:version="0.32"
+ inkscape:version="0.48.4 r9939"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ sodipodi:docname="search.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ version="1.0">
+ <defs
+ id="defs2460">
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient19264">
+ <stop
+ style="stop-color:#5e4c1e;stop-opacity:1"
+ offset="0"
+ id="stop19266" />
+ <stop
+ style="stop-color:#a07847;stop-opacity:0.98823529"
+ offset="1"
+ id="stop19268" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient18283">
+ <stop
+ style="stop-color:#b3dff1;stop-opacity:1;"
+ offset="0"
+ id="stop18285" />
+ <stop
+ style="stop-color:#f5f5f5;stop-opacity:1"
+ offset="1"
+ id="stop18287" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient18283"
+ id="linearGradient18289"
+ x1="6.0879178"
+ y1="14.588083"
+ x2="17.659527"
+ y2="10.240396"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient19264"
+ id="linearGradient19270"
+ x1="17.714294"
+ y1="25.441625"
+ x2="27.404643"
+ y2="25.441625"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.2318497,-0.05354068,0.05262685,1.2108246,-5.664973,-3.9557037)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="17.412504"
+ inkscape:cx="-7.828412"
+ inkscape:cy="15.951598"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:grid-bbox="true"
+ inkscape:document-units="px"
+ inkscape:window-width="1920"
+ inkscape:window-height="1180"
+ inkscape:window-x="1916"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1"
+ inkscape:snap-grids="false"
+ inkscape:snap-to-guides="false">
+ <inkscape:grid
+ type="xygrid"
+ id="grid3243" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer5"
+ inkscape:label="inner"
+ style="display:inline">
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#linearGradient18289);fill-opacity:1;fill-rule:evenodd;stroke:#45719f;stroke-width:1.36601292999999990;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="path17312"
+ sodipodi:cx="14.271354"
+ sodipodi:cy="13.277822"
+ sodipodi:rx="8.2462254"
+ sodipodi:ry="8.0976295"
+ d="m 22.517579,13.277822 a 8.2462254,8.0976295 0 1 1 -16.4924506,0 8.2462254,8.0976295 0 1 1 16.4924506,0 z"
+ transform="matrix(0.95811218,0,0,0.96428056,-2.7875308,-2.9552112)" />
+ </g>
+ <g
+ id="layer1"
+ inkscape:label="handler"
+ inkscape:groupmode="layer"
+ style="display:inline">
+ <path
+ style="fill:#a6a8a9;fill-opacity:1;fill-rule:evenodd;stroke:#37406d;stroke-width:0.96199995;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="M 15.608372,18.55098 20.17229,23.63173 22,21.11486 18.073608,16.613819 z"
+ id="path3411"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:#e0b478;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient19270);stroke-width:1.13095403;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="m 18.090556,23.539926 1.466639,2.382869 2.799401,2.992204 3.285468,2.41503 3.231191,-2.753874 -1.744048,-3.538517 -2.594059,-3.167943 -2.059147,-1.967885 -4.385445,3.638116 z"
+ id="path3413"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#6874a2;stroke-width:3.99488853999999982;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="path2468"
+ sodipodi:cx="17.726692"
+ sodipodi:cy="18.068695"
+ sodipodi:rx="10.225221"
+ sodipodi:ry="9.2875366"
+ d="m 27.951913,18.068695 a 10.225221,9.2875366 0 1 1 -20.4504415,0 10.225221,9.2875366 0 1 1 20.4504415,0 z"
+ transform="matrix(0.83916146,0,0,0.91470537,-3.8683577,-6.1917981)" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="frame"
+ style="display:inline" />
+</svg>
diff --git a/Viewer/images/search_decor.svg b/Viewer/images/search_decor.svg
new file mode 100644
index 0000000..970d55d
--- /dev/null
+++ b/Viewer/images/search_decor.svg
@@ -0,0 +1,299 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="search_decor.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3792">
+ <stop
+ style="stop-color:#eceded;stop-opacity:1;"
+ offset="0"
+ id="stop3794" />
+ <stop
+ style="stop-color:#b5c6d0;stop-opacity:1;"
+ offset="1"
+ id="stop3796" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3804">
+ <stop
+ style="stop-color:#464c90;stop-opacity:1;"
+ offset="0"
+ id="stop3806" />
+ <stop
+ style="stop-color:#355560;stop-opacity:1;"
+ offset="1"
+ id="stop3808" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3796">
+ <stop
+ style="stop-color:#545d96;stop-opacity:1;"
+ offset="0"
+ id="stop3798" />
+ <stop
+ style="stop-color:#76a1ab;stop-opacity:1;"
+ offset="1"
+ id="stop3800" />
+ </linearGradient>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 16 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="32 : 16 : 1"
+ inkscape:persp3d-origin="16 : 10.666667 : 1"
+ id="perspective35" />
+ <linearGradient
+ id="linearGradient3852">
+ <stop
+ style="stop-color:#467b3c;stop-opacity:1;"
+ offset="0"
+ id="stop3854" />
+ <stop
+ style="stop-color:#3d9f3d;stop-opacity:0.99215686;"
+ offset="1"
+ id="stop3856" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3799">
+ <stop
+ style="stop-color:#aae1be;stop-opacity:1;"
+ offset="0"
+ id="stop3801" />
+ <stop
+ style="stop-color:#4bc82b;stop-opacity:1;"
+ offset="1"
+ id="stop3803" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3777">
+ <stop
+ style="stop-color:#5b7db3;stop-opacity:1;"
+ offset="0"
+ id="stop3779" />
+ <stop
+ style="stop-color:#2589ce;stop-opacity:1;"
+ offset="1"
+ id="stop3781" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#519aed;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#e9dddd;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f1f3fb;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3728"
+ id="linearGradient3710"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.37353112,0,0,-0.42267705,0.93672357,33.214358)"
+ x1="15.413333"
+ y1="3.4795053"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3756"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.37353112,0,0,-0.42267705,0.93672357,33.214358)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3777"
+ id="linearGradient3783"
+ x1="1.4276053"
+ y1="16.374115"
+ x2="28.440672"
+ y2="16.374115"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0279887,0,0,1.0323478,7.1553463,-2.2096664)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3799"
+ id="linearGradient3834"
+ x1="-9.2158766"
+ y1="17.617861"
+ x2="36.303471"
+ y2="17.617861"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3852"
+ id="linearGradient3858"
+ x1="4.4050612"
+ y1="16.300755"
+ x2="23.3321"
+ y2="16.521189"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.96778437,0,0,0.96778437,1.3383248,1.0794304)" />
+ <inkscape:perspective
+ id="perspective2935"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4026"
+ id="linearGradient4032"
+ x1="16.804222"
+ y1="14.95285"
+ x2="27.970543"
+ y2="14.95285"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.7702794,0,0,1.4225865,-38.983045,1.405527)" />
+ <linearGradient
+ id="linearGradient4026">
+ <stop
+ style="stop-color:#f30e1e;stop-opacity:1;"
+ offset="0"
+ id="stop4028" />
+ <stop
+ style="stop-color:#ba2f39;stop-opacity:1;"
+ offset="1"
+ id="stop4030" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3975">
+ <stop
+ style="stop-color:#565c64;stop-opacity:1;"
+ offset="0"
+ id="stop3977" />
+ <stop
+ style="stop-color:#99a4b4;stop-opacity:1;"
+ offset="1"
+ id="stop3979" />
+ </linearGradient>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="52.3125"
+ inkscape:cx="8"
+ inkscape:cy="8"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer3"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1920"
+ inkscape:window-height="1140"
+ inkscape:window-x="-4"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="circle"
+ style="display:inline"
+ transform="translate(0,-16)">
+ <path
+ style="fill:url(#linearGradient3710);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3720);stroke-width:0.38534608;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ d="m 1.9478697,28.248642 c -0.7129992,2.185353 -0.3564995,1.092675 0,0 z"
+ id="path3695"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:#333333;fill-opacity:1;stroke:none"
+ d="m 8.4526621,25.406502 1.3142002,-1.360259 5.7411577,5.460031 -0.450471,1.226545 -1.203597,0.692554 z"
+ id="path3794"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccc" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline"
+ transform="translate(0,-16)">
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#484848;stroke-width:0.82214546;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.29999995;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ id="path3869"
+ sodipodi:cx="-3.3759081"
+ sodipodi:cy="15.175204"
+ sodipodi:rx="2.6094856"
+ sodipodi:ry="1.2408743"
+ d="m -0.76642251,15.175204 a 2.6094856,1.2408743 0 1 1 -5.21897129,0 2.6094856,1.2408743 0 1 1 5.21897129,0 z"
+ transform="matrix(1.7219595,-0.11109443,0.23838407,3.6421229,8.5164787,-33.460843)" />
+ </g>
+</svg>
diff --git a/Viewer/images/search_decor_large_file_mode.svg b/Viewer/images/search_decor_large_file_mode.svg
new file mode 100644
index 0000000..f49d34e
--- /dev/null
+++ b/Viewer/images/search_decor_large_file_mode.svg
@@ -0,0 +1,352 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="search_decor_large_file_mode.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3792">
+ <stop
+ style="stop-color:#eceded;stop-opacity:1;"
+ offset="0"
+ id="stop3794" />
+ <stop
+ style="stop-color:#b5c6d0;stop-opacity:1;"
+ offset="1"
+ id="stop3796" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3804">
+ <stop
+ style="stop-color:#464c90;stop-opacity:1;"
+ offset="0"
+ id="stop3806" />
+ <stop
+ style="stop-color:#355560;stop-opacity:1;"
+ offset="1"
+ id="stop3808" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3796">
+ <stop
+ style="stop-color:#545d96;stop-opacity:1;"
+ offset="0"
+ id="stop3798" />
+ <stop
+ style="stop-color:#76a1ab;stop-opacity:1;"
+ offset="1"
+ id="stop3800" />
+ </linearGradient>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 16 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="32 : 16 : 1"
+ inkscape:persp3d-origin="16 : 10.666667 : 1"
+ id="perspective35" />
+ <linearGradient
+ id="linearGradient3852">
+ <stop
+ style="stop-color:#467b3c;stop-opacity:1;"
+ offset="0"
+ id="stop3854" />
+ <stop
+ style="stop-color:#3d9f3d;stop-opacity:0.99215686;"
+ offset="1"
+ id="stop3856" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3799">
+ <stop
+ style="stop-color:#aae1be;stop-opacity:1;"
+ offset="0"
+ id="stop3801" />
+ <stop
+ style="stop-color:#4bc82b;stop-opacity:1;"
+ offset="1"
+ id="stop3803" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3777">
+ <stop
+ style="stop-color:#5b7db3;stop-opacity:1;"
+ offset="0"
+ id="stop3779" />
+ <stop
+ style="stop-color:#2589ce;stop-opacity:1;"
+ offset="1"
+ id="stop3781" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#519aed;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#e9dddd;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f1f3fb;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3728"
+ id="linearGradient3710"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.30086126,0,0,-0.34506891,9.5206872,23.609452)"
+ x1="15.413333"
+ y1="3.4795053"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3756"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.30086126,0,0,-0.34506891,9.5206872,23.609452)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3777"
+ id="linearGradient3783"
+ x1="1.4276053"
+ y1="16.374115"
+ x2="28.440672"
+ y2="16.374115"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0279887,0,0,1.0323478,7.1553463,-2.2096664)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3799"
+ id="linearGradient3834"
+ x1="-9.2158766"
+ y1="17.617861"
+ x2="36.303471"
+ y2="17.617861"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3852"
+ id="linearGradient3858"
+ x1="4.4050612"
+ y1="16.300755"
+ x2="23.3321"
+ y2="16.521189"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.96778437,0,0,0.96778437,1.3383248,1.0794304)" />
+ <inkscape:perspective
+ id="perspective2935"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4026"
+ id="linearGradient4032"
+ x1="16.804222"
+ y1="14.95285"
+ x2="27.970543"
+ y2="14.95285"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.7702794,0,0,1.4225865,-38.983045,1.405527)" />
+ <linearGradient
+ id="linearGradient4026">
+ <stop
+ style="stop-color:#f30e1e;stop-opacity:1;"
+ offset="0"
+ id="stop4028" />
+ <stop
+ style="stop-color:#ba2f39;stop-opacity:1;"
+ offset="1"
+ id="stop4030" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3975">
+ <stop
+ style="stop-color:#565c64;stop-opacity:1;"
+ offset="0"
+ id="stop3977" />
+ <stop
+ style="stop-color:#99a4b4;stop-opacity:1;"
+ offset="1"
+ id="stop3979" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3674"
+ id="linearGradient3680"
+ x1="23.639265"
+ y1="1029.8322"
+ x2="-9.4723015"
+ y2="1043.9935"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0741762,0,0,1.0809023,-0.1291828,-84.247424)" />
+ <linearGradient
+ id="linearGradient3674">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="0"
+ id="stop3676" />
+ <stop
+ style="stop-color:#90bbd4;stop-opacity:1;"
+ offset="1"
+ id="stop3678" />
+ </linearGradient>
+ <linearGradient
+ y2="1043.9935"
+ x2="-9.4723015"
+ y1="1029.8322"
+ x1="23.639265"
+ gradientTransform="matrix(0.21517238,0,0,0.19407252,9.1981652,-181.83903)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3829"
+ xlink:href="#linearGradient3674"
+ inkscape:collect="always" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="26.40444"
+ inkscape:cx="9.0371583"
+ inkscape:cy="8.7234491"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer3"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1936"
+ inkscape:window-height="950"
+ inkscape:window-x="295"
+ inkscape:window-y="92"
+ inkscape:window-maximized="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline"
+ transform="translate(0,-16)">
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#484848;stroke-width:0.82214546;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.29999995;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ id="path3869"
+ sodipodi:cx="-3.3759081"
+ sodipodi:cy="15.175204"
+ sodipodi:rx="2.6094856"
+ sodipodi:ry="1.2408743"
+ d="m -0.76642251,15.175204 a 2.6094856,1.2408743 0 1 1 -5.21897129,0 2.6094856,1.2408743 0 1 1 5.21897129,0 z"
+ transform="matrix(1.7219595,-0.11109443,0.23838407,3.6421229,8.5164787,-33.460843)" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="circle"
+ style="display:inline"
+ transform="translate(0,-16)">
+ <path
+ style="fill:url(#linearGradient3710);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3720);stroke-width:0.38534608;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ d="m 10.335116,19.555497 c -0.5742858,1.784098 -0.287143,0.892047 0,0 z"
+ id="path3695"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:#333333;fill-opacity:1;stroke:none"
+ d="m 8.4526621,25.406502 1.3142002,-1.360259 5.7411577,5.460031 -0.450471,1.226545 -1.203597,0.692554 z"
+ id="path3794"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccc" />
+ <path
+ style="fill:url(#linearGradient3829);fill-opacity:1;stroke:#41597a;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="m 9.6909388,21.278399 c 0,0 1.3944502,-2.533261 2.4243922,-4.20696 0.286841,-0.433534 0.58842,-0.03138 0.58842,-0.03138 0.01456,0.01688 2.336746,4.035242 2.336746,4.035242 0.210928,0.432492 0.597919,0.829973 -0.222047,0.815572 l -4.6747,-0.0256 c 0,0 -0.8827153,0.10692 -0.4528112,-0.586993 z"
+ id="path2822"
+ sodipodi:nodetypes="cccccccc"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:type="arc"
+ style="fill:#11293d;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ id="path3808"
+ sodipodi:cx="13.090909"
+ sodipodi:cy="37.694389"
+ sodipodi:rx="1.7640232"
+ sodipodi:ry="1.6092843"
+ d="m 14.854932,37.694389 a 1.7640232,1.6092843 0 1 1 -3.528046,0 1.7640232,1.6092843 0 1 1 3.528046,0 z"
+ transform="matrix(0.16012212,0,0,0.160738,10.301246,14.698738)" />
+ <path
+ style="fill:#11293d;fill-opacity:1;stroke:none"
+ d="m 12.258983,18.434818 -0.118283,0.882226 0.118283,0.756194 0.236567,0 0.108937,-0.756194 -0.108937,-0.882226 c 0,0 -0.07304,-0.06203 -0.136975,-0.05583 -0.06394,0.0062 -0.09959,0.05583 -0.09959,0.05583 z"
+ id="path3810"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccczc" />
+ </g>
+</svg>
diff --git a/Viewer/images/select_all.svg b/Viewer/images/select_all.svg
new file mode 100644
index 0000000..6a5453b
--- /dev/null
+++ b/Viewer/images/select_all.svg
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="select_all.svg">
+ <defs
+ id="defs4" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="16.15625"
+ inkscape:cx="-5.1619"
+ inkscape:cy="14.48913"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-to-guides="false"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1920"
+ inkscape:window-height="1140"
+ inkscape:window-x="-4"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2985"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ <dc:description>ecFlowUi icon</dc:description>
+ <cc:license
+ rdf:resource="" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="Layer"
+ style="display:inline">
+ <rect
+ ry="0.84339386"
+ y="1.572536"
+ x="1.8568667"
+ height="23.495165"
+ width="22.938105"
+ id="rect3755"
+ style="fill:#3d4f70;fill-opacity:1;fill-rule:evenodd;stroke:#3d4f70;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
+ <rect
+ ry="0.82561916"
+ y="5.2243738"
+ x="5.1992264"
+ height="23"
+ width="23"
+ id="rect3757"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
+ <rect
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#3d4f70;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="rect2985"
+ width="22.504835"
+ height="22.56673"
+ x="7.9226303"
+ y="7.9477773"
+ ry="0.81006634" />
+ <path
+ style="fill:#1a1a1a;fill-rule:evenodd;stroke:none"
+ d="m 14.186503,17.1084 c -0.17067,-0.04976 -2.773721,2.731753 -2.675743,2.731755 1.983162,1.909287 4.27273,3.777684 6.30697,5.635667 l 9.400266,-9.356502 -2.581826,-2.229572 -6.767099,7.622276"
+ id="path4146"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccc" />
+ </g>
+</svg>
diff --git a/Viewer/images/server.svg b/Viewer/images/server.svg
new file mode 100644
index 0000000..4a9eff4
--- /dev/null
+++ b/Viewer/images/server.svg
@@ -0,0 +1,689 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="server.svg"
+ style="display:inline"
+ inkscape:export-filename="/var/tmp/cgr/PERFORCE/development/metview/src/Flextra/FLEXTRA_RUN_128.png"
+ inkscape:export-xdpi="360"
+ inkscape:export-ydpi="360">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3928">
+ <stop
+ style="stop-color:#b1b1b1;stop-opacity:1;"
+ offset="0"
+ id="stop3930" />
+ <stop
+ style="stop-color:#7b7b7b;stop-opacity:1;"
+ offset="1"
+ id="stop3932" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3886">
+ <stop
+ id="stop3888"
+ offset="0"
+ style="stop-color:#a1a1a1;stop-opacity:1;" />
+ <stop
+ id="stop3892"
+ offset="1"
+ style="stop-color:#363636;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3878">
+ <stop
+ id="stop3880"
+ offset="0"
+ style="stop-color:#a1a1a1;stop-opacity:1;" />
+ <stop
+ style="stop-color:#5c5c5c;stop-opacity:1;"
+ offset="0.1568388"
+ id="stop3882" />
+ <stop
+ id="stop3884"
+ offset="1"
+ style="stop-color:#363636;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3870">
+ <stop
+ id="stop3872"
+ offset="0"
+ style="stop-color:#4a4a4a;stop-opacity:1;" />
+ <stop
+ style="stop-color:#828282;stop-opacity:1;"
+ offset="0.92700338"
+ id="stop3874" />
+ <stop
+ id="stop3876"
+ offset="1"
+ style="stop-color:#aaaaaa;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3852">
+ <stop
+ style="stop-color:#b1e5ff;stop-opacity:1;"
+ offset="0"
+ id="stop3854" />
+ <stop
+ style="stop-color:#4cc3ff;stop-opacity:1;"
+ offset="1"
+ id="stop3856" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3697">
+ <stop
+ style="stop-color:#0055d4;stop-opacity:1;"
+ offset="0"
+ id="stop3699" />
+ <stop
+ style="stop-color:#3c6fbd;stop-opacity:1;"
+ offset="1"
+ id="stop3701" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3689">
+ <stop
+ style="stop-color:#0066ff;stop-opacity:1;"
+ offset="0"
+ id="stop3691" />
+ <stop
+ style="stop-color:#3f84eb;stop-opacity:1;"
+ offset="1"
+ id="stop3693" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3925">
+ <stop
+ style="stop-color:#0044aa;stop-opacity:1;"
+ offset="0"
+ id="stop3927" />
+ <stop
+ style="stop-color:#0055d3;stop-opacity:1;"
+ offset="1"
+ id="stop3929" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3917">
+ <stop
+ style="stop-color:#0055d4;stop-opacity:1;"
+ offset="0"
+ id="stop3919" />
+ <stop
+ style="stop-color:#1975ff;stop-opacity:1;"
+ offset="1"
+ id="stop3921" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3909">
+ <stop
+ style="stop-color:#2a7fff;stop-opacity:1;"
+ offset="0"
+ id="stop3911" />
+ <stop
+ style="stop-color:#63a1ff;stop-opacity:1;"
+ offset="1"
+ id="stop3913" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3678">
+ <stop
+ style="stop-color:#e3e9ef;stop-opacity:1;"
+ offset="0"
+ id="stop3680" />
+ <stop
+ style="stop-color:#d9e3f2;stop-opacity:1;"
+ offset="1"
+ id="stop3682" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3648">
+ <stop
+ style="stop-color:#acc6d2;stop-opacity:1;"
+ offset="0"
+ id="stop3650" />
+ <stop
+ style="stop-color:#498ca2;stop-opacity:1;"
+ offset="1"
+ id="stop3652" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3716">
+ <stop
+ style="stop-color:#a5a5a5;stop-opacity:1;"
+ offset="0"
+ id="stop3718" />
+ <stop
+ style="stop-color:#bbbbbb;stop-opacity:1;"
+ offset="1"
+ id="stop3720" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3708">
+ <stop
+ style="stop-color:#838383;stop-opacity:1;"
+ offset="0"
+ id="stop3710" />
+ <stop
+ style="stop-color:#b3b3b3;stop-opacity:1;"
+ offset="1"
+ id="stop3712" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3700">
+ <stop
+ style="stop-color:#c3c3c3;stop-opacity:1;"
+ offset="0"
+ id="stop3702" />
+ <stop
+ style="stop-color:#969696;stop-opacity:1;"
+ offset="1"
+ id="stop3704" />
+ </linearGradient>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 16 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="32 : 16 : 1"
+ inkscape:persp3d-origin="16 : 10.666667 : 1"
+ id="perspective3219" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3749">
+ <stop
+ style="stop-color:#2f3d85;stop-opacity:1;"
+ offset="0"
+ id="stop3751" />
+ <stop
+ style="stop-color:#2f3d85;stop-opacity:0;"
+ offset="1"
+ id="stop3753" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3741">
+ <stop
+ style="stop-color:#2f3d85;stop-opacity:1;"
+ offset="0"
+ id="stop3743" />
+ <stop
+ style="stop-color:#2f3d85;stop-opacity:0;"
+ offset="1"
+ id="stop3745" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3733">
+ <stop
+ style="stop-color:#2f528a;stop-opacity:1"
+ offset="0"
+ id="stop3735" />
+ <stop
+ style="stop-color:#3f5e91;stop-opacity:0;"
+ offset="1"
+ id="stop3737" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3622-8">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="0"
+ id="stop3624-3" />
+ <stop
+ style="stop-color:#e9f0fa;stop-opacity:1"
+ offset="1"
+ id="stop3626-2" />
+ </linearGradient>
+ <linearGradient
+ y2="29.323114"
+ x2="13.269579"
+ y1="2.2007067"
+ x1="29.382435"
+ gradientTransform="matrix(1.0033899,0,0,1.006795,-0.04875293,31.924568)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4163"
+ xlink:href="#linearGradient3622-8"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3622-95">
+ <stop
+ style="stop-color:#c6cee3;stop-opacity:1;"
+ offset="0"
+ id="stop3624-5" />
+ <stop
+ style="stop-color:#eaeef9;stop-opacity:0;"
+ offset="1"
+ id="stop3626-7" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3733"
+ id="linearGradient2886"
+ gradientUnits="userSpaceOnUse"
+ x1="78.128151"
+ y1="102.62679"
+ x2="110.16354"
+ y2="102.62679"
+ gradientTransform="translate(-26.687459,-0.0778789)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3749"
+ id="linearGradient2892"
+ gradientUnits="userSpaceOnUse"
+ x1="88.325951"
+ y1="84.507774"
+ x2="119.71897"
+ y2="63.179432" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3741"
+ id="linearGradient2894"
+ gradientUnits="userSpaceOnUse"
+ x1="98.523994"
+ y1="99.79335"
+ x2="127.85975"
+ y2="99.79335" />
+ <inkscape:perspective
+ id="perspective3676"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3700"
+ id="linearGradient3706"
+ x1="22.977591"
+ y1="16.533602"
+ x2="29.822767"
+ y2="16.274597"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.7675676,0,0,1,5.1557318,30.408959)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3708"
+ id="linearGradient3714"
+ x1="12.987333"
+ y1="40.467396"
+ x2="29.933771"
+ y2="40.467396"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.9235808,0,0,1,1.6954997,-1.5910409)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3716"
+ id="linearGradient3722"
+ x1="12.98733"
+ y1="51.049667"
+ x2="23.125591"
+ y2="51.049667"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.91240876,0,0,1,1.8405944,-1.5910409)" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3648"
+ id="radialGradient3656"
+ cx="15.794774"
+ cy="23.04089"
+ fx="15.794774"
+ fy="23.04089"
+ r="1.5355394"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3678"
+ id="linearGradient3684"
+ x1="0.87100756"
+ y1="-3.0895786"
+ x2="28.755108"
+ y2="-5.2356339"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,1.0766142,0,0.03111428)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3909"
+ id="linearGradient3915"
+ x1="2.108496"
+ y1="7.6282678"
+ x2="8.558013"
+ y2="7.6282678"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-1.9191813,0.17506575)" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3648-8"
+ id="radialGradient3656-4"
+ cx="15.794774"
+ cy="23.04089"
+ fx="15.794774"
+ fy="23.04089"
+ r="1.5355394"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ id="linearGradient3648-8">
+ <stop
+ style="stop-color:#acc6d2;stop-opacity:1;"
+ offset="0"
+ id="stop3650-8" />
+ <stop
+ style="stop-color:#498ca2;stop-opacity:1;"
+ offset="1"
+ id="stop3652-2" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3886"
+ id="linearGradient3706-4"
+ x1="32.714359"
+ y1="14.128001"
+ x2="29.690975"
+ y2="14.079874"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0352934,0,0,1.3291541,-2.4775067,-6.9190948)" />
+ <linearGradient
+ id="linearGradient3700-5">
+ <stop
+ style="stop-color:#e6e6e6;stop-opacity:1;"
+ offset="0"
+ id="stop3702-5" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop3704-1" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3878"
+ id="linearGradient3714-7"
+ x1="22.47965"
+ y1="42.03252"
+ x2="22.687197"
+ y2="38.870899"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.2457235,0,0,1.3291541,-12.76261,-49.452027)" />
+ <linearGradient
+ id="linearGradient3708-1">
+ <stop
+ style="stop-color:#c9c9c9;stop-opacity:1;"
+ offset="0"
+ id="stop3710-1" />
+ <stop
+ style="stop-color:#f6f6f6;stop-opacity:1;"
+ offset="1"
+ id="stop3712-5" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3716-7"
+ id="linearGradient3722-2"
+ x1="12.98733"
+ y1="51.049667"
+ x2="23.125591"
+ y2="51.049667"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.91240876,0,0,1,1.8405944,-1.5910409)" />
+ <linearGradient
+ id="linearGradient3716-7">
+ <stop
+ style="stop-color:#a1a1a1;stop-opacity:1;"
+ offset="0"
+ id="stop3718-6" />
+ <stop
+ id="stop3860"
+ offset="0.5"
+ style="stop-color:#5c5c5c;stop-opacity:1;" />
+ <stop
+ style="stop-color:#363636;stop-opacity:1;"
+ offset="1"
+ id="stop3720-1" />
+ </linearGradient>
+ <linearGradient
+ y2="50.937008"
+ x2="23.073195"
+ y1="50.905857"
+ x1="14.300552"
+ gradientTransform="matrix(1.7739141,0,0,1.3291541,-19.779778,-49.375569)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3965"
+ xlink:href="#linearGradient3870"
+ inkscape:collect="always" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3689"
+ id="linearGradient3695"
+ x1="0.99223268"
+ y1="16.589376"
+ x2="7.4417505"
+ y2="16.589376"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-0.80291868,-0.07299261)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3697"
+ id="linearGradient3703"
+ x1="0.99223369"
+ y1="25.271418"
+ x2="7.5037656"
+ y2="25.271418"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-0.80291868,-0.07299261)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3852"
+ id="linearGradient3858"
+ x1="4.3676114"
+ y1="11.002259"
+ x2="20.676254"
+ y2="11.841675"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.98267863,0,0,1,0.3241733,0.21897781)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3852"
+ id="linearGradient3868"
+ x1="4.0026484"
+ y1="16.623831"
+ x2="20.858734"
+ y2="16.623831"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3700"
+ id="linearGradient3900"
+ x1="11.79378"
+ y1="27.419714"
+ x2="11.819339"
+ y2="29.718981"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3928"
+ id="linearGradient3934"
+ x1="4.0391447"
+ y1="26.129977"
+ x2="18.814943"
+ y2="26.129977"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.00247,0,0,1,-0.00997671,0)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3700"
+ id="linearGradient3875"
+ x1="19.89596"
+ y1="27.036503"
+ x2="29.118568"
+ y2="27.036503"
+ gradientUnits="userSpaceOnUse" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="27.400035"
+ inkscape:cx="13.467564"
+ inkscape:cy="21.779259"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer6"
+ showgrid="true"
+ width="64px"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1920"
+ inkscape:window-height="1140"
+ inkscape:window-x="-4"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1"
+ gridtolerance="6">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Ecflowview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Ecflowview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="column"
+ style="display:inline" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer6"
+ inkscape:label="desktop"
+ style="display:inline">
+ <path
+ style="fill:url(#linearGradient3875);stroke:#626262;stroke-width:0.50000000000000000;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;fill-opacity:1.0"
+ d="m 20.145959,31.270074 0.03649,-2.956201 8.68612,-5.510941 -6e-6,2.262771 z"
+ id="path3850"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:url(#linearGradient3900);fill-opacity:1;stroke:#636363;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="M 5.2528164,26.306577 5.4014533,30.029201 20.18511,31.270073 20.21896,27.94891 z"
+ id="path3846"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:url(#linearGradient3965);fill-opacity:1;fill-rule:evenodd;stroke:#666666;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+ d="m 3.3775328,6.1108479 c -0.169966,-0.00934 17.9266262,0.986965 17.9266262,0.986965 L 21.58446,28.316755 c 0,0 -17.8770845,-1.140017 -18.0685583,-1.178641 z"
+ id="rect2870-42"
+ sodipodi:nodetypes="ccccc"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:url(#linearGradient3714-7);fill-opacity:1;fill-rule:evenodd;stroke:#666666;stroke-width:0.50000000000000000;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+ d="m 15.116013,0.86550208 14.990055,0.56605282 -5.025189,6.526618 c 0,0 -1.733408,-0.7408621 -4.06582,-0.8304631 L 3.3390575,6.0169457 z"
+ id="rect2870-4-3"
+ sodipodi:nodetypes="cccccc"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:url(#linearGradient3706-4);fill-opacity:1;fill-rule:evenodd;stroke:#666666;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+ d="m 21.464962,7.1444025 8.787787,-5.6170782 -0.147448,20.9824597 -8.61014,5.889363 z"
+ id="rect3690-2"
+ sodipodi:nodetypes="ccccc"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:url(#linearGradient3858);fill-opacity:1;stroke:none;display:inline"
+ d="m 4.2482102,9.4658413 16.5375328,0.9442337 -4e-6,2.493566 -16.5641128,-0.974979 z"
+ id="path3726-1"
+ sodipodi:nodetypes="ccccc"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:#b3b3b3;fill-opacity:1;stroke:none;display:inline"
+ d="m 22.054602,12.51778 7.781666,-5.4553165 0.02658,-1.8852615 -7.845773,5.418269 z"
+ id="path3836"
+ sodipodi:nodetypes="ccccc"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc"
+ id="path3840"
+ d="m 4.029701,14.904931 16.829033,1.017228 -4e-6,2.420573 -16.8560816,-1.120965 z"
+ style="fill:url(#linearGradient3868);fill-opacity:1.0;stroke:none;display:inline" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc"
+ id="path3924"
+ d="m 4.1023808,24.210348 14.9680362,0.907737 0.218884,2.45707 -15.2501563,-1.230453 z"
+ style="fill:url(#linearGradient3934);fill-opacity:1;stroke:none;display:inline" />
+ <path
+ sodipodi:type="arc"
+ style="fill:#51c5fb;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ id="path3902"
+ sodipodi:cx="16.934284"
+ sodipodi:cy="26.854021"
+ sodipodi:rx="0.83941501"
+ sodipodi:ry="0.91240758"
+ d="m 17.773699,26.854021 a 0.83941501,0.91240758 0 1 1 -1.67883,0 0.83941501,0.91240758 0 1 1 1.67883,0 z"
+ transform="matrix(1.4782609,0,0,1.44,-6.3471826,-12.728177)"
+ inkscape:transform-center-x="0.29197043"
+ inkscape:transform-center-y="0.40145934" />
+ <path
+ inkscape:transform-center-y="0.40145934"
+ inkscape:transform-center-x="0.29197043"
+ transform="matrix(1.4782609,0,0,1.44,-9.8143315,-12.874162)"
+ d="m 17.773699,26.854021 a 0.83941501,0.91240758 0 1 1 -1.67883,0 0.83941501,0.91240758 0 1 1 1.67883,0 z"
+ sodipodi:ry="0.91240758"
+ sodipodi:rx="0.83941501"
+ sodipodi:cy="26.854021"
+ sodipodi:cx="16.934284"
+ id="path3922"
+ style="fill:#51c5fb;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ sodipodi:type="arc" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc"
+ id="path3099"
+ d="m 22.164091,17.919233 7.781666,-5.455317 0.02658,-1.885261 -7.845773,5.418269 z"
+ style="fill:#b3b3b3;fill-opacity:1;stroke:none;display:inline" />
+ </g>
+</svg>
diff --git a/Viewer/images/server_log.svg b/Viewer/images/server_log.svg
new file mode 100644
index 0000000..d7600a3
--- /dev/null
+++ b/Viewer/images/server_log.svg
@@ -0,0 +1,196 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="server_log.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3845">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="0"
+ id="stop3847" />
+ <stop
+ style="stop-color:#c5c7cd;stop-opacity:1"
+ offset="1"
+ id="stop3849" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3845"
+ id="linearGradient4793"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0757737,0,0,1.0996622,0.50954173,-2.3823021)"
+ x1="27.831085"
+ y1="31.597303"
+ x2="-9.200532"
+ y2="-2.410116" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="12.070612"
+ inkscape:cx="21.954017"
+ inkscape:cy="-0.91100472"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer3"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1693"
+ inkscape:window-height="1376"
+ inkscape:window-x="230"
+ inkscape:window-y="152"
+ inkscape:window-maximized="0"
+ inkscape:snap-to-guides="false">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>EcflowUI icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>EcflowUI icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="img"
+ sodipodi:insensitive="true"
+ style="display:none">
+ <image
+ y="0.2890628"
+ x="1.3430486"
+ id="image3035"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABHNCSVQICAgIfAhkiAAAIABJREFU eJzs3Xt8HFd1OPBz7szu7EhavyX5oTy9iS1L3gADCaQ8BgLkwasUTAkkIUBiKBRSHi3Q8iu0tBT6 oEADhJAESCgtSVsawiMJSVieiWnWJLZWthPZToIS25K9trWWtLO7c+/vD2mVkbSvmV1J9+6e+/nk Y2l28r1zZ+fcczWvC0CFChUqVKhQabmCDTK8jpj+jzzyyCOPPPLIk9TT66gYAEArsYyTRx555JFH Hnlye0EHAGjbtpbJZGZGHtFoVCQSCZc88sgjjzzyyJPfC3IJAC3L0rPZ7Mz/G4lERDKZLECwUxnk kUceeeSRR94ie34HABiLxcI9PT0z/9/w8LAYGhrKBamcPPLII4888shbEs/XJQC0bd [...]
+ height="31.341492"
+ width="30.122496" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="first"
+ style="display:inline">
+ <path
+ style="fill:#ffffff;fill-opacity:1;stroke:#414b5c;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+ d="M 7.5799209,2.0058499 6.2485376,28.337233 c 0,0 -1.2856364,0.71382 2.0828458,3.497075 0,0 16.4255136,-0.06622 20.4317796,-0.171542 0,0 2.69723,-1.695869 2.713904,-4.14247 L 31.636808,4.0811267 c 0.0075,-1.1050575 -1.52982,-2.9838318 -3.37072,-2.9095851 z"
+ id="path8418"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccsssssc" />
+ <rect
+ style="fill:url(#linearGradient4793);fill-opacity:1;fill-rule:evenodd;stroke:#414b5c;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ id="rect3843"
+ width="24.699766"
+ height="28.635204"
+ x="4.4970775"
+ y="0.63810378"
+ ry="2.3884766" />
+ <text
+ xml:space="preserve"
+ style="font-size:22px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#002c5f;fill-opacity:1;stroke:none;display:inline;font-family:Courier;-inkscape-font-specification:Courier Bold"
+ x="11.088696"
+ y="21.171541"
+ id="text7062"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan7064"
+ x="11.088696"
+ y="21.171541"
+ style="font-size:22px;fill:#002c5f;fill-opacity:1">S</tspan></text>
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#3d455f;stroke-width:6.44482183;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ id="path3829-6"
+ sodipodi:cx="-3.8666666"
+ sodipodi:cy="7.04"
+ sodipodi:rx="5.3066669"
+ sodipodi:ry="5.0479193"
+ d="M 1.2103086,5.5709449 A 5.3066669,5.0479193 0 1 1 -4.714998,2.0569996"
+ sodipodi:start="5.9878905"
+ sodipodi:end="10.835024"
+ transform="matrix(-0.27864429,-0.2293023,-0.50135483,0.12744222,6.4167058,4.4686388)"
+ sodipodi:open="true" />
+ <path
+ sodipodi:open="true"
+ transform="matrix(-0.27864429,-0.2293023,-0.50135483,0.12744222,6.33386,13.167452)"
+ sodipodi:end="10.835024"
+ sodipodi:start="5.9878905"
+ d="M 1.2103086,5.5709449 A 5.3066669,5.0479193 0 1 1 -4.714998,2.0569996"
+ sodipodi:ry="5.0479193"
+ sodipodi:rx="5.3066669"
+ sodipodi:cy="7.04"
+ sodipodi:cx="-3.8666666"
+ id="path4640"
+ style="fill:none;stroke:#3d455f;stroke-width:6.44482183;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#3d455f;stroke-width:6.44482183;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ id="path4642"
+ sodipodi:cx="-3.8666666"
+ sodipodi:cy="7.04"
+ sodipodi:rx="5.3066669"
+ sodipodi:ry="5.0479193"
+ d="M 1.2103086,5.5709449 A 5.3066669,5.0479193 0 1 1 -4.714998,2.0569996"
+ sodipodi:start="5.9878905"
+ sodipodi:end="10.835024"
+ transform="matrix(-0.27864429,-0.2293023,-0.50135483,0.12744222,6.4995517,22.446186)"
+ sodipodi:open="true" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="second"
+ style="display:inline" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="top" />
+</svg>
diff --git a/Viewer/images/show_shadowed.svg b/Viewer/images/show_shadowed.svg
new file mode 100644
index 0000000..ed7509f
--- /dev/null
+++ b/Viewer/images/show_shadowed.svg
@@ -0,0 +1,219 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="show_shadowed.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#519aed;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#e9dddd;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f1f3fb;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3614">
+ <stop
+ style="stop-color:#2c71d9;stop-opacity:1;"
+ offset="0"
+ id="stop3616" />
+ <stop
+ style="stop-color:#ececec;stop-opacity:1;"
+ offset="1"
+ id="stop3618" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3602">
+ <stop
+ style="stop-color:#f5f5f5;stop-opacity:1;"
+ offset="0"
+ id="stop3604" />
+ <stop
+ style="stop-color:#141bc6;stop-opacity:1;"
+ offset="1"
+ id="stop3606" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3614"
+ id="linearGradient3691"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="12.89746"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3602"
+ id="linearGradient3693"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="2.2337441"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3728"
+ id="linearGradient3710"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-31.566354,35.860667)"
+ x1="15.413333"
+ y1="3.4795053"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3756"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-31.566354,35.860667)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="23.595961"
+ inkscape:cy="15.51908"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1408"
+ inkscape:window-height="1093"
+ inkscape:window-x="370"
+ inkscape:window-y="39"
+ inkscape:window-maximized="0"
+ showguides="true"
+ inkscape:guide-bbox="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="bg"
+ style="display:inline" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <text
+ xml:space="preserve"
+ style="font-size:20px;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Calibri;-inkscape-font-specification:Calibri"
+ x="3.8399999"
+ y="21.973333"
+ id="text3783"><tspan
+ sodipodi:role="line"
+ id="tspan3785"
+ x="3.8399999"
+ y="21.973333" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="7.2533331"
+ y="15.146667"
+ id="text3787"><tspan
+ sodipodi:role="line"
+ id="tspan3789"
+ x="7.2533331"
+ y="15.146667" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:Monospace"
+ x="1.0479099"
+ y="24.623611"
+ id="text3791"
+ transform="scale(1.0238296,0.97672504)"><tspan
+ sodipodi:role="line"
+ id="tspan3793"
+ x="1.0479099"
+ y="24.623611"
+ style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;font-family:Monospace;-inkscape-font-specification:Monospace">V</tspan></text>
+ <text
+ transform="scale(1.0238296,0.97672504)"
+ id="text3009"
+ y="24.514402"
+ x="15.894131"
+ style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#666666;fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:Monospace"
+ xml:space="preserve"><tspan
+ style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#666666;font-family:Monospace;-inkscape-font-specification:Monospace"
+ y="24.514402"
+ x="15.894131"
+ id="tspan3011"
+ sodipodi:role="line">V</tspan></text>
+ </g>
+</svg>
diff --git a/Viewer/images/spinning_wheel.gif b/Viewer/images/spinning_wheel.gif
new file mode 100644
index 0000000..5b33f7e
Binary files /dev/null and b/Viewer/images/spinning_wheel.gif differ
diff --git a/Viewer/images/splash_screen.png b/Viewer/images/splash_screen.png
new file mode 100644
index 0000000..c7118dd
Binary files /dev/null and b/Viewer/images/splash_screen.png differ
diff --git a/Viewer/images/splash_screen.svg b/Viewer/images/splash_screen.svg
new file mode 100644
index 0000000..b6444b0
--- /dev/null
+++ b/Viewer/images/splash_screen.svg
@@ -0,0 +1,943 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="300"
+ height="200"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="splash_screen.svg"
+ inkscape:export-filename="/var/tmp/cgr/git/ecflow/Viewer/images/splash_screen.png"
+ inkscape:export-xdpi="150"
+ inkscape:export-ydpi="150">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient4463">
+ <stop
+ style="stop-color:#143956;stop-opacity:1;"
+ offset="0"
+ id="stop4465" />
+ <stop
+ style="stop-color:#376081;stop-opacity:1;"
+ offset="1"
+ id="stop4467" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient4439">
+ <stop
+ style="stop-color:#1b5d8f;stop-opacity:1;"
+ offset="0"
+ id="stop4441" />
+ <stop
+ id="stop4461"
+ offset="0.5"
+ style="stop-color:#537995;stop-opacity:1;" />
+ <stop
+ style="stop-color:#1b5d8f;stop-opacity:1;"
+ offset="1"
+ id="stop4443" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient4236">
+ <stop
+ style="stop-color:#425c7a;stop-opacity:1;"
+ offset="0"
+ id="stop4238" />
+ <stop
+ style="stop-color:#2187bf;stop-opacity:1;"
+ offset="1"
+ id="stop4240" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3921">
+ <stop
+ id="stop3923"
+ offset="0"
+ style="stop-color:#add8ff;stop-opacity:1;" />
+ <stop
+ id="stop3925"
+ offset="1"
+ style="stop-color:#b0d8e6;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3837">
+ <stop
+ style="stop-color:#00a0e2;stop-opacity:1;"
+ offset="0"
+ id="stop3839" />
+ <stop
+ style="stop-color:#6ca3b9;stop-opacity:1"
+ offset="1"
+ id="stop3841" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3755">
+ <stop
+ id="stop3763"
+ offset="0"
+ style="stop-color:#1b5d8f;stop-opacity:1;" />
+ <stop
+ style="stop-color:#90afc9;stop-opacity:1;"
+ offset="0.99000001"
+ id="stop4449" />
+ <stop
+ style="stop-color:#2663a4;stop-opacity:1;"
+ offset="1"
+ id="stop3759" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3755"
+ id="linearGradient3761"
+ x1="88.848763"
+ y1="64.925453"
+ x2="206.95615"
+ y2="65.718857"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0806175,0,0,1.0294118,0.03857296,852.36218)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3837"
+ id="linearGradient3843"
+ x1="114.31874"
+ y1="78.254387"
+ x2="154.7113"
+ y2="159.10545"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-0.77369385,0.38684724)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3921-2"
+ id="linearGradient3919-3"
+ x1="60.178818"
+ y1="48.4618"
+ x2="60.543442"
+ y2="64.663994"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ id="linearGradient3921-2">
+ <stop
+ id="stop3923-8"
+ offset="0"
+ style="stop-color:#add8ff;stop-opacity:1;" />
+ <stop
+ id="stop3925-6"
+ offset="1"
+ style="stop-color:#b0d8e6;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3921-26"
+ id="linearGradient3919-1"
+ x1="60.178818"
+ y1="48.4618"
+ x2="60.543442"
+ y2="64.663994"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(0,0.19434907)" />
+ <linearGradient
+ id="linearGradient3921-26">
+ <stop
+ id="stop3923-0"
+ offset="0"
+ style="stop-color:#add8ff;stop-opacity:1;" />
+ <stop
+ id="stop3925-5"
+ offset="1"
+ style="stop-color:#b0d8e6;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="64.663994"
+ x2="60.543442"
+ y1="48.4618"
+ x1="60.178818"
+ gradientTransform="translate(16.826756,23.560921)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4010-9"
+ xlink:href="#linearGradient3921-26-3"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3921-26-3">
+ <stop
+ id="stop3923-0-4"
+ offset="0"
+ style="stop-color:#26e131;stop-opacity:1;" />
+ <stop
+ id="stop3925-5-7"
+ offset="1"
+ style="stop-color:#26e132;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="64.663994"
+ x2="60.543442"
+ y1="48.4618"
+ x1="60.178818"
+ gradientTransform="translate(34.51252,48.048904)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4067-6"
+ xlink:href="#linearGradient3921-26-3-3"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3921-26-3-3">
+ <stop
+ id="stop3923-0-4-8"
+ offset="0"
+ style="stop-color:#26e131;stop-opacity:1;" />
+ <stop
+ id="stop3925-5-7-7"
+ offset="1"
+ style="stop-color:#26e132;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="64.663994"
+ x2="60.543442"
+ y1="48.4618"
+ x1="60.178818"
+ gradientTransform="translate(16.826756,23.560921)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4010-3"
+ xlink:href="#linearGradient3921-26-7"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3921-26-7">
+ <stop
+ id="stop3923-0-8"
+ offset="0"
+ style="stop-color:#eef724;stop-opacity:1;" />
+ <stop
+ id="stop3925-5-5"
+ offset="1"
+ style="stop-color:#eef738;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="64.663994"
+ x2="60.543442"
+ y1="48.4618"
+ x1="60.178818"
+ gradientTransform="translate(60.488294,73.835705)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4165-5"
+ xlink:href="#linearGradient3921-26-7-7"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3921-26-7-7">
+ <stop
+ id="stop3923-0-8-3"
+ offset="0"
+ style="stop-color:#eef724;stop-opacity:1;" />
+ <stop
+ id="stop3925-5-5-3"
+ offset="1"
+ style="stop-color:#eef738;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="64.663994"
+ x2="60.543442"
+ y1="48.4618"
+ x1="60.178818"
+ gradientTransform="translate(77.591014,54.012102)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4107-4"
+ xlink:href="#linearGradient3921-26-3-3-2"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3921-26-3-3-2">
+ <stop
+ id="stop3923-0-4-8-2"
+ offset="0"
+ style="stop-color:#26e131;stop-opacity:1;" />
+ <stop
+ id="stop3925-5-7-7-0"
+ offset="1"
+ style="stop-color:#26e132;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="64.663994"
+ x2="60.543442"
+ y1="48.4618"
+ x1="60.178818"
+ gradientTransform="translate(77.591014,37.881128)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4067-1"
+ xlink:href="#linearGradient3921-26-3-2"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3921-26-3-2">
+ <stop
+ id="stop3923-0-4-7"
+ offset="0"
+ style="stop-color:#26e131;stop-opacity:1;" />
+ <stop
+ id="stop3925-5-7-70"
+ offset="1"
+ style="stop-color:#26e132;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="64.663994"
+ x2="60.543442"
+ y1="48.4618"
+ x1="60.178818"
+ gradientTransform="translate(59.905244,14.17054)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4010-2"
+ xlink:href="#linearGradient3921-26-4"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3921-26-4">
+ <stop
+ id="stop3923-0-1"
+ offset="0"
+ style="stop-color:#add8ff;stop-opacity:1;" />
+ <stop
+ id="stop3925-5-0"
+ offset="1"
+ style="stop-color:#b0d8e6;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3921-3"
+ id="linearGradient3919-37"
+ x1="60.178818"
+ y1="48.4618"
+ x2="60.543442"
+ y2="64.663994"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(43.078493,-9.1960318)" />
+ <linearGradient
+ id="linearGradient3921-3">
+ <stop
+ id="stop3923-9"
+ offset="0"
+ style="stop-color:#add8ff;stop-opacity:1;" />
+ <stop
+ id="stop3925-59"
+ offset="1"
+ style="stop-color:#b0d8e6;stop-opacity:1;" />
+ </linearGradient>
+ <filter
+ color-interpolation-filters="sRGB"
+ inkscape:collect="always"
+ id="filter3974-2-7"
+ x="-0.083372198"
+ width="1.1667444"
+ y="-0.11376684"
+ height="1.2275337">
+ <feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="0.62061236"
+ id="feGaussianBlur3976-4-2" />
+ </filter>
+ <filter
+ color-interpolation-filters="sRGB"
+ inkscape:collect="always"
+ id="filter3974-8-0"
+ x="-0.083372198"
+ width="1.1667444"
+ y="-0.11376684"
+ height="1.2275337">
+ <feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="0.62061236"
+ id="feGaussianBlur3976-10-2" />
+ </filter>
+ <filter
+ color-interpolation-filters="sRGB"
+ inkscape:collect="always"
+ id="filter3974-3-8"
+ x="-0.083372198"
+ width="1.1667444"
+ y="-0.11376684"
+ height="1.2275337">
+ <feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="0.62061236"
+ id="feGaussianBlur3976-1-6" />
+ </filter>
+ <filter
+ color-interpolation-filters="sRGB"
+ inkscape:collect="always"
+ id="filter3974-7"
+ x="-0.083372198"
+ width="1.1667444"
+ y="-0.11376684"
+ height="1.2275337">
+ <feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="0.62061236"
+ id="feGaussianBlur3976-0" />
+ </filter>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4439"
+ id="linearGradient4445"
+ x1="20.938387"
+ y1="110.39853"
+ x2="288.02069"
+ y2="57.627125"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0018277,0,0,1,-0.54970219,0)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4463"
+ id="linearGradient4469"
+ x1="104.49313"
+ y1="169.49153"
+ x2="301.1871"
+ y2="111.2231"
+ gradientUnits="userSpaceOnUse" />
+ <filter
+ inkscape:collect="always"
+ id="filter4513">
+ <feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="1.0230013"
+ id="feGaussianBlur4515" />
+ </filter>
+ <filter
+ inkscape:collect="always"
+ id="filter4128"
+ x="-0.012798987"
+ width="1.025598"
+ y="-0.13166636"
+ height="1.2633327">
+ <feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="0.77273529"
+ id="feGaussianBlur4130" />
+ </filter>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="2.69831"
+ inkscape:cx="66.742601"
+ inkscape:cy="93.030069"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer8"
+ showgrid="false"
+ width="200px"
+ inkscape:window-width="1920"
+ inkscape:window-height="1140"
+ inkscape:window-x="-4"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1"
+ showguides="true"
+ inkscape:guide-bbox="true">
+ <sodipodi:guide
+ orientation="1,0"
+ position="-0.54970219,213.28445"
+ id="guide4471" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer10"
+ inkscape:label="bg3"
+ style="display:inline">
+ <rect
+ style="fill:#243b4c;fill-opacity:1;stroke:none"
+ id="rect4437"
+ width="301.23676"
+ height="47.251503"
+ x="-0.54970217"
+ y="-0.09159524" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer9"
+ inkscape:label="bg2"
+ style="display:inline">
+ <path
+ style="fill:url(#linearGradient4445);fill-opacity:1;stroke:none"
+ d="M -0.16029356,200.1677 -0.54970186,43.334877 c 0,0 70.02852486,-14.612863 137.82656186,-20.700054 51.59792,-4.632676 163.47692,-11.194115 163.47692,-11.194115 0,0 -0.13064,134.163182 -0.45623,188.365922 z"
+ id="path4434"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccsccc" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer8"
+ inkscape:label="bg 1"
+ style="display:inline">
+ <path
+ style="fill:url(#linearGradient4469);fill-opacity:1;stroke:none"
+ d="m 46.724686,200.5497 c 0,0 40.136972,-46.43888 64.082454,-67.42784 18.96949,-16.62736 59.06667,-42.78647 90.48488,-56.560976 12.25317,-5.372085 23.99143,-10.812867 53.04051,-20.741634 19.78531,-6.762475 45.96587,-10.635196 45.96587,-10.635196 l 0.9384,156.465046 z"
+ id="path4431"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="csssccc" />
+ </g>
+ <g
+ inkscape:label="bg"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-852.36218)"
+ style="display:none">
+ <rect
+ style="fill:url(#linearGradient3761);fill-opacity:1;stroke:none"
+ id="rect2985"
+ width="301.43539"
+ height="200.95694"
+ x="-0.47846889"
+ y="852.36218"
+ inkscape:export-xdpi="120"
+ inkscape:export-ydpi="120" />
+ <rect
+ style="fill:#184b8a;fill-opacity:1;stroke:#414141;stroke-width:0.99999994;stroke-opacity:1"
+ id="rect3765"
+ width="301.37759"
+ height="19.712629"
+ x="-0.61869133"
+ y="1033.0702" />
+ <rect
+ style="fill:#c6e3fb;fill-opacity:1;stroke:none"
+ id="rect3776"
+ width="172.64035"
+ height="4.2553191"
+ x="116.63912"
+ y="939.66736" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer7"
+ inkscape:label="tree ori"
+ sodipodi:insensitive="true"
+ style="display:none">
+ <path
+ style="fill:#535353;fill-opacity:1;stroke:none;filter:url(#filter3974-7)"
+ d="m 96.406174,54.985623 17.796666,4.376655 -0.006,-8.506627 -17.859296,-4.585674 z"
+ id="path3042-0-8"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ sodipodi:nodetypes="ccccc"
+ inkscape:connector-curvature="0"
+ id="path4188-1"
+ d="m 112.92584,78.501861 17.79667,4.376655 -0.006,-8.506627 -17.8593,-4.585674 z"
+ style="fill:#535353;fill-opacity:1;stroke:none;filter:url(#filter3974-7)" />
+ <path
+ style="fill:#535353;fill-opacity:1;stroke:none;filter:url(#filter3974-3-8)"
+ d="m 113.70324,138.55572 17.79667,4.37666 -0.006,-8.50663 -17.8593,-4.58567 z"
+ id="path3042-0-0-8"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:#535353;fill-opacity:1;stroke:none;filter:url(#filter3974-8-0)"
+ d="m 130.61161,117.95472 17.79667,4.37666 -0.006,-8.50663 -17.8593,-4.58567 z"
+ id="path3042-0-9-3"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:#535353;fill-opacity:1;stroke:none;filter:url(#filter3974-2-7)"
+ d="m 130.80596,102.21245 17.79667,4.37665 -0.006,-8.506619 -17.8593,-4.585681 z"
+ id="path3042-0-91-0"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:none;stroke:#414141;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:5;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ d="m 102.99859,128.84331 c 0,-57.620744 0.12334,-73.569695 0.12334,-73.569695"
+ id="path3040-3"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:url(#linearGradient3919-37);fill-opacity:1;stroke:#3f3c3c;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+ d="m 94.544294,52.608752 17.796666,4.376655 -0.006,-8.506627 -17.859296,-4.585674 z"
+ id="path3042-6"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:none;stroke:#414141;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ d="m 102.81185,69.41045 c 6.05455,1.581821 8.19239,2.164868 8.19239,2.164868"
+ id="path3084-2"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#414141;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 119.20078,78.24828 0,30.74864"
+ id="path3120-0"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#383838;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 119.12978,92.35368 9.59433,2.69852"
+ id="path3122-28"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#414141;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 119.06307,108.58855 9.86976,3.12656"
+ id="path3122-9-4"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <text
+ xml:space="preserve"
+ style="font-size:9.2836895px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="114.5707"
+ y="25.221451"
+ id="text3931-1"
+ sodipodi:linespacing="125%"
+ transform="matrix(0.89573877,0.20608466,-0.24393949,1.0602732,0,0)"
+ inkscape:transform-center-x="26.57182"
+ inkscape:transform-center-y="1.5381005"><tspan
+ sodipodi:role="line"
+ id="tspan3933-8"
+ x="114.5707"
+ y="25.221451"
+ style="font-size:4.64184475px">server</tspan></text>
+ <path
+ style="fill:url(#linearGradient4010-2);fill-opacity:1;stroke:#3f3c3c;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+ d="m 111.37105,75.975324 17.79667,4.376655 -0.006,-8.506627 -17.8593,-4.585674 z"
+ id="path3042-4-3"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <text
+ xml:space="preserve"
+ style="font-size:9.2836895px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="139.56908"
+ y="42.448898"
+ id="text3931-6-7"
+ sodipodi:linespacing="125%"
+ transform="matrix(0.89573877,0.20608466,-0.24393949,1.0602732,0,0)"
+ inkscape:transform-center-x="26.57182"
+ inkscape:transform-center-y="1.5381005"><tspan
+ sodipodi:role="line"
+ id="tspan3933-7-5"
+ x="139.56908"
+ y="42.448898"
+ style="font-size:4.64184475px">suite</tspan></text>
+ <path
+ style="fill:url(#linearGradient4067-1);fill-opacity:1;stroke:#263c32;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+ d="m 129.05681,99.685911 17.79668,4.376649 -0.006,-8.50662 -17.85931,-4.58568 z"
+ id="path3042-4-8-8"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <text
+ xml:space="preserve"
+ style="font-size:9.2836895px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#260032;fill-opacity:1;stroke:none;font-family:Sans"
+ x="164.10478"
+ y="60.042637"
+ id="text3931-6-8-17"
+ sodipodi:linespacing="125%"
+ transform="matrix(0.89573877,0.20608466,-0.24393949,1.0602732,0,0)"
+ inkscape:transform-center-x="26.57182"
+ inkscape:transform-center-y="1.5381005"><tspan
+ sodipodi:role="line"
+ id="tspan3933-7-1-0"
+ x="164.10478"
+ y="60.042637"
+ style="font-size:4.64184475px;fill:#260032;fill-opacity:1">node</tspan></text>
+ <path
+ style="fill:url(#linearGradient4107-4);fill-opacity:1;stroke:#263c32;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+ d="m 129.05681,115.81689 17.79667,4.37665 -0.006,-8.50662 -17.8593,-4.58568 z"
+ id="path3042-4-8-6-4"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <text
+ xml:space="preserve"
+ style="font-size:9.2836895px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#260032;fill-opacity:1;stroke:none;font-family:Sans"
+ x="168.03975"
+ y="74.491776"
+ id="text3931-6-8-1-8"
+ sodipodi:linespacing="125%"
+ transform="matrix(0.89573877,0.20608466,-0.24393949,1.0602732,0,0)"
+ inkscape:transform-center-x="26.57182"
+ inkscape:transform-center-y="1.5381005"><tspan
+ sodipodi:role="line"
+ id="tspan3933-7-1-7-8"
+ x="168.03975"
+ y="74.491776"
+ style="font-size:4.64184475px;fill:#260032;fill-opacity:1">node</tspan></text>
+ <path
+ style="fill:none;stroke:#383838;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 102.80521,128.62346 9.59433,2.69852"
+ id="path3122-2-1"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:url(#linearGradient4165-5);fill-opacity:1;stroke:#3f3c3c;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+ d="m 111.9541,135.64049 17.79667,4.37666 -0.006,-8.50663 -17.8593,-4.58567 z"
+ id="path3042-4-85-3"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <text
+ xml:space="preserve"
+ style="font-size:9.2836895px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="154.74196"
+ y="95.773148"
+ id="text3931-6-87-6"
+ sodipodi:linespacing="125%"
+ transform="matrix(0.89573877,0.20608466,-0.24393949,1.0602732,0,0)"
+ inkscape:transform-center-x="26.57182"
+ inkscape:transform-center-y="1.5381005"><tspan
+ sodipodi:role="line"
+ id="tspan3933-7-3-7"
+ x="154.74196"
+ y="95.773148"
+ style="font-size:4.64184475px">suite</tspan></text>
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer11"
+ inkscape:label="text shadow">
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot3768-5"
+ style="font-size:43.23317719px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#1a1a1a;fill-opacity:1;stroke:none;display:inline;filter:url(#filter4513);font-family:Sans"
+ transform="matrix(0.95970142,0,0,0.9831043,91.015667,35.646289)"><flowRegion
+ id="flowRegion3770-5"><rect
+ id="rect3772-5"
+ width="262.82318"
+ height="92.554222"
+ x="20.502901"
+ y="41.005802"
+ style="font-size:43.23317719px;fill:#1a1a1a;fill-opacity:1;stroke:none" /></flowRegion><flowPara
+ id="flowPara3774-6"
+ style="font-size:43.23317719px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#1a1a1a;fill-opacity:1;stroke:none;font-family:Arial;-inkscape-font-specification:Arial Bold">ecFlowUI</flowPara></flowRoot> </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="text"
+ style="display:inline">
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot3768"
+ style="font-size:43.23317719px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#d7d7d7;fill-opacity:1;stroke:none;font-family:Sans"
+ transform="matrix(0.95970142,0,0,0.9831043,87.888382,31.200838)"><flowRegion
+ id="flowRegion3770"><rect
+ id="rect3772"
+ width="262.82318"
+ height="92.554222"
+ x="20.502901"
+ y="41.005802"
+ style="font-size:43.23317719px;fill:#d7d7d7;fill-opacity:1;stroke:none" /></flowRegion><flowPara
+ id="flowPara3774"
+ style="font-size:43.23317719px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#d7d7d7;fill-opacity:1;stroke:none;font-family:Arial;-inkscape-font-specification:Arial Bold">ecFlowUI</flowPara></flowRoot> </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer6"
+ inkscape:label="tree shadow" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer5"
+ inkscape:label="tree">
+ <path
+ style="fill:none;stroke:#eaeaea;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:5;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ d="m 27.232315,158.46746 c 0,-70.801317 -0.110087,-129.152543 -0.110087,-129.152543"
+ id="path3040"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#eaeaea;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+ d="m 15.663896,26.040475 23.773471,5.377802 -0.008,-10.452492 -23.857134,-5.634634 z"
+ id="path3042"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:none;stroke:#eaeaea;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ d="m 26.708015,46.685511 c 8.087894,1.943658 10.943701,2.660075 10.943701,2.660075"
+ id="path3084"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#eaeaea;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 48.600978,57.544968 0,37.782295"
+ id="path3120"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#eaeaea;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 48.506122,74.876936 12.816473,3.315798"
+ id="path3122"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#eaeaea;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 48.41701,94.825483 13.184407,3.84175"
+ id="path3122-9"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <text
+ xml:space="preserve"
+ style="font-size:11.89402294px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#e2e2e2;fill-opacity:1;stroke:none;font-family:Sans"
+ x="24.466516"
+ y="18.126669"
+ id="text3931"
+ sodipodi:linespacing="125%"
+ transform="matrix(0.93395739,0.19765144,-0.25434769,1.0168856,0,0)"
+ inkscape:transform-center-x="35.49565"
+ inkscape:transform-center-y="1.8899363"><tspan
+ sodipodi:role="line"
+ id="tspan3933"
+ x="24.466516"
+ y="18.126669"
+ style="font-size:5.94701147px;fill:#e2e2e2;fill-opacity:1">server</tspan></text>
+ <path
+ style="fill:none;stroke:#ebe9e9;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+ d="m 38.141719,54.75208 23.773476,5.377803 -0.008,-10.452494 -23.857138,-5.634632 z"
+ id="path3042-4"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <text
+ xml:space="preserve"
+ style="font-size:11.89402294px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#eaeaea;fill-opacity:1;stroke:none;font-family:Sans"
+ x="56.493801"
+ y="40.198032"
+ id="text3931-6"
+ sodipodi:linespacing="125%"
+ transform="matrix(0.93395739,0.19765144,-0.25434769,1.0168856,0,0)"
+ inkscape:transform-center-x="35.495653"
+ inkscape:transform-center-y="1.8899339"><tspan
+ sodipodi:role="line"
+ id="tspan3933-7"
+ x="56.493801"
+ y="40.198032"
+ style="font-size:5.94701147px;fill:#eaeaea;fill-opacity:1">suite 1</tspan></text>
+ <path
+ style="fill:none;stroke:#eaeaea;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+ d="m 61.767039,83.886392 23.773477,5.377791 -0.008,-10.452479 -23.85714,-5.634641 z"
+ id="path3042-4-8"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <text
+ xml:space="preserve"
+ style="font-size:11.89402294px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#eaeaea;fill-opacity:1;stroke:none;font-family:Sans"
+ x="87.108826"
+ y="62.785999"
+ id="text3931-6-8"
+ sodipodi:linespacing="125%"
+ transform="matrix(0.93395739,0.19765144,-0.25434769,1.0168856,0,0)"
+ inkscape:transform-center-x="35.495653"
+ inkscape:transform-center-y="1.8899383"><tspan
+ sodipodi:role="line"
+ id="tspan3933-7-1"
+ x="87.108826"
+ y="62.785999"
+ style="font-size:5.94701147px;fill:#eaeaea;fill-opacity:1">node 1</tspan></text>
+ <path
+ style="fill:none;stroke:#eaeaea;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+ d="m 61.767038,103.70728 23.773465,5.3778 -0.008,-10.452477 -23.857128,-5.63464 z"
+ id="path3042-4-8-6"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <text
+ xml:space="preserve"
+ style="font-size:11.89402294px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#eaeaea;fill-opacity:1;stroke:none;font-family:Sans"
+ x="91.260826"
+ y="81.088493"
+ id="text3931-6-8-1"
+ sodipodi:linespacing="125%"
+ transform="matrix(0.93395739,0.19765144,-0.25434769,1.0168856,0,0)"
+ inkscape:transform-center-x="35.495651"
+ inkscape:transform-center-y="1.8899396"><tspan
+ sodipodi:role="line"
+ id="tspan3933-7-1-7"
+ x="91.260826"
+ y="81.088493"
+ style="font-size:5.94701147px;fill:#eaeaea;fill-opacity:1">node 2</tspan></text>
+ <path
+ style="fill:none;stroke:#eaeaea;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 26.699149,119.44331 12.816473,3.31581"
+ id="path3122-2"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#eaeaea;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+ d="m 38.920574,128.06547 23.773475,5.37781 -0.008,-10.4525 -23.857139,-5.63463 z"
+ id="path3042-4-85"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <text
+ xml:space="preserve"
+ style="font-size:11.89402294px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#eaeaea;fill-opacity:1;stroke:none;font-family:Sans"
+ x="75.113434"
+ y="108.563"
+ id="text3931-6-87"
+ sodipodi:linespacing="125%"
+ transform="matrix(0.93395739,0.19765144,-0.25434769,1.0168856,0,0)"
+ inkscape:transform-center-x="35.495647"
+ inkscape:transform-center-y="1.8899337"><tspan
+ sodipodi:role="line"
+ id="tspan3933-7-3"
+ x="75.113434"
+ y="108.563"
+ style="font-size:5.94701147px;fill:#eaeaea;fill-opacity:1">suite 2</tspan></text>
+ <path
+ style="fill:none;stroke:#eaeaea;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 27.533517,158.29006 12.816474,3.31581"
+ id="path3122-2-6"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#eaeaea;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+ d="m 39.754943,166.91222 23.773474,5.37781 -0.008,-10.4525 -23.857138,-5.63463 z"
+ id="path3042-4-85-30"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <text
+ xml:space="preserve"
+ style="font-size:11.89402294px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#eaeaea;fill-opacity:1;stroke:none;font-family:Sans"
+ x="85.772568"
+ y="144.42261"
+ id="text3931-6-87-0"
+ sodipodi:linespacing="125%"
+ transform="matrix(0.93395739,0.19765144,-0.25434769,1.0168856,0,0)"
+ inkscape:transform-center-x="35.495647"
+ inkscape:transform-center-y="1.889933"><tspan
+ sodipodi:role="line"
+ id="tspan3933-7-3-8"
+ x="85.772568"
+ y="144.42261"
+ style="font-size:5.94701147px;fill:#eaeaea;fill-opacity:1">suite 3</tspan></text>
+ <flowRoot
+ transform="matrix(0.99786724,0,0,1.0694625,70.226549,106.14301)"
+ style="font-size:19.36024475px;font-style:normal;font-weight:bold;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#291919;fill-opacity:1;stroke:none;display:inline;filter:url(#filter4128);font-family:Sans;-inkscape-font-specification:Sans Bold"
+ id="flowRoot3904"
+ xml:space="preserve"><flowRegion
+ id="flowRegion3906"><rect
+ style="font-size:19.36024475px;font-weight:bold;fill:#291919;fill-opacity:1;stroke:none;-inkscape-font-specification:Sans Bold"
+ y="28.781721"
+ x="61.519989"
+ height="35.741665"
+ width="170.43861"
+ id="rect3908" /></flowRegion><flowPara
+ style="font-size:19.36024475px;font-weight:bold;fill:#291919;fill-opacity:1;stroke:none;-inkscape-font-specification:Sans Bold"
+ id="flowPara3910">Preview version</flowPara></flowRoot> <flowRoot
+ xml:space="preserve"
+ id="flowRoot3144"
+ style="font-size:19.36024474999999967px;font-style:normal;font-weight:bold;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#d79029;fill-opacity:1;stroke:none;stroke-width:0.38720485999999998;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline;font-family:Sans;-inkscape-font-specification:Sans Bold"
+ transform="matrix(0.99786724,0,0,1.0694625,67.632333,103.54879)"><flowRegion
+ id="flowRegion3146"
+ style="stroke-width:0.38720486"><rect
+ id="rect3148"
+ width="170.43861"
+ height="35.741665"
+ x="61.519989"
+ y="28.781721"
+ style="font-size:19.36024474999999967px;font-weight:bold;fill:#d79029;fill-opacity:1;stroke:none;stroke-width:0.38720485999999998;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;-inkscape-font-specification:Sans Bold" /></flowRegion><flowPara
+ id="flowPara3150"
+ style="font-size:19.36024474999999967px;font-weight:bold;fill:#d79029;fill-opacity:1;stroke:none;stroke-width:0.38720485999999998;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;-inkscape-font-specification:Sans Bold">Preview version</flowPara></flowRoot> </g>
+</svg>
diff --git a/Viewer/images/status.svg b/Viewer/images/status.svg
new file mode 100644
index 0000000..5b3c9f4
--- /dev/null
+++ b/Viewer/images/status.svg
@@ -0,0 +1,222 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="status.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#519aed;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#e9dddd;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f1f3fb;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3614">
+ <stop
+ style="stop-color:#2c71d9;stop-opacity:1;"
+ offset="0"
+ id="stop3616" />
+ <stop
+ style="stop-color:#ececec;stop-opacity:1;"
+ offset="1"
+ id="stop3618" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3602">
+ <stop
+ style="stop-color:#f5f5f5;stop-opacity:1;"
+ offset="0"
+ id="stop3604" />
+ <stop
+ style="stop-color:#141bc6;stop-opacity:1;"
+ offset="1"
+ id="stop3606" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3614"
+ id="linearGradient3691"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="12.89746"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3602"
+ id="linearGradient3693"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="2.2337441"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3728"
+ id="linearGradient3710"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-0.7930209,35.114)"
+ x1="15.413333"
+ y1="3.4795053"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3756"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-0.7930209,35.114)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="-4.3575197"
+ inkscape:cy="15.420624"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer3"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1920"
+ inkscape:window-height="1140"
+ inkscape:window-x="-4"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="circle"
+ style="display:inline">
+ <rect
+ style="fill:#ff9955;fill-opacity:1;fill-rule:evenodd;stroke:#626262;stroke-width:1.50000000000000000;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="rect3010"
+ width="15.893333"
+ height="13.6"
+ x="1.4400001"
+ y="2.0266666"
+ ry="0" />
+ <rect
+ ry="0"
+ y="9.4933329"
+ x="7.5733337"
+ height="13.6"
+ width="15.893333"
+ id="rect3788"
+ style="fill:#ffe680;fill-opacity:1;fill-rule:evenodd;stroke:#626262;stroke-width:1.50000000000000000;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
+ <rect
+ style="fill:#5fd35f;fill-opacity:1;fill-rule:evenodd;stroke:#626262;stroke-width:1.50000000000000000;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="rect3790"
+ width="15.893333"
+ height="13.6"
+ x="14.826667"
+ y="17.066666"
+ ry="0" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <text
+ xml:space="preserve"
+ style="font-size:20;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Calibri;-inkscape-font-specification:Calibri"
+ x="3.8399999"
+ y="21.973333"
+ id="text3783"><tspan
+ sodipodi:role="line"
+ id="tspan3785"
+ x="3.8399999"
+ y="21.973333" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="7.2533331"
+ y="15.146667"
+ id="text3787"><tspan
+ sodipodi:role="line"
+ id="tspan3789"
+ x="7.2533331"
+ y="15.146667" /></text>
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="top" />
+</svg>
diff --git a/Viewer/images/submit.svg b/Viewer/images/submit.svg
new file mode 100644
index 0000000..2966dd8
--- /dev/null
+++ b/Viewer/images/submit.svg
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="submit.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3763">
+ <stop
+ style="stop-color:#6bd35d;stop-opacity:1;"
+ offset="0"
+ id="stop3765" />
+ <stop
+ style="stop-color:#00aa00;stop-opacity:1"
+ offset="1"
+ id="stop3767" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3755">
+ <stop
+ style="stop-color:#71d771;stop-opacity:1"
+ offset="0"
+ id="stop3757" />
+ <stop
+ style="stop-color:#00aa00;stop-opacity:1"
+ offset="1"
+ id="stop3759" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3755"
+ id="linearGradient3761"
+ x1="-3.0992887"
+ y1="11.203094"
+ x2="-8.1243639"
+ y2="-10.955513"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-1.794971,-1.7949707)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3763"
+ id="linearGradient3769"
+ x1="14.045779"
+ y1="25.562862"
+ x2="12.54875"
+ y2="8.4796906"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-0.49516441,0.68085106)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="16.15625"
+ inkscape:cx="-5.1619"
+ inkscape:cy="14.48913"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-to-guides="false"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1920"
+ inkscape:window-height="1140"
+ inkscape:window-x="-4"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2985"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="Layer"
+ style="display:inline">
+ <path
+ style="fill:url(#linearGradient3769);fill-opacity:1;fill-rule:evenodd;stroke:#026a00;stroke-opacity:1"
+ d="m 6.9128816,12.452725 c -0.3145668,-0.09071 -5.11235,4.979178 -4.9317635,4.979183 3.655242,3.480067 7.8752335,6.885601 11.6246189,10.272154 L 30.931729,10.649923 26.173065,6.5860736 13.700364,20.479228 z"
+ id="path4146"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccc" />
+ </g>
+</svg>
diff --git a/Viewer/images/sync.svg b/Viewer/images/sync.svg
new file mode 100644
index 0000000..d735bf6
--- /dev/null
+++ b/Viewer/images/sync.svg
@@ -0,0 +1,401 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="sync.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient4573">
+ <stop
+ style="stop-color:#2165c4;stop-opacity:1;"
+ offset="0"
+ id="stop4575" />
+ <stop
+ style="stop-color:#5e95e2;stop-opacity:1;"
+ offset="1"
+ id="stop4577" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient4485">
+ <stop
+ id="stop4487"
+ offset="0"
+ style="stop-color:#f1bd45;stop-opacity:1;" />
+ <stop
+ id="stop4489"
+ offset="1"
+ style="stop-color:#ffeebd;stop-opacity:1;" />
+ </linearGradient>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 16 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="32 : 16 : 1"
+ inkscape:persp3d-origin="16 : 10.666667 : 1"
+ id="perspective49" />
+ <linearGradient
+ id="linearGradient5256">
+ <stop
+ style="stop-color:#cedcdd;stop-opacity:1;"
+ offset="0"
+ id="stop5258" />
+ <stop
+ style="stop-color:#7199cb;stop-opacity:1;"
+ offset="1"
+ id="stop5260" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient5222">
+ <stop
+ style="stop-color:#465178;stop-opacity:1;"
+ offset="0"
+ id="stop5224" />
+ <stop
+ style="stop-color:#314552;stop-opacity:1;"
+ offset="1"
+ id="stop5226" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient5194">
+ <stop
+ style="stop-color:#204492;stop-opacity:1;"
+ offset="0"
+ id="stop5196" />
+ <stop
+ style="stop-color:#81a2d2;stop-opacity:1;"
+ offset="1"
+ id="stop5198" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient5186">
+ <stop
+ style="stop-color:#eba34c;stop-opacity:1;"
+ offset="0"
+ id="stop5188" />
+ <stop
+ style="stop-color:#f9f9f9;stop-opacity:1;"
+ offset="1"
+ id="stop5190" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3795">
+ <stop
+ style="stop-color:#c53143;stop-opacity:1;"
+ offset="0"
+ id="stop3797" />
+ <stop
+ style="stop-color:#b8382b;stop-opacity:0;"
+ offset="1"
+ id="stop3799" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#fa0c1e;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#d9afb1;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3614">
+ <stop
+ style="stop-color:#e8220f;stop-opacity:1;"
+ offset="0"
+ id="stop3616" />
+ <stop
+ style="stop-color:#ececec;stop-opacity:1;"
+ offset="1"
+ id="stop3618" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3602">
+ <stop
+ style="stop-color:#932626;stop-opacity:1;"
+ offset="0"
+ id="stop3604" />
+ <stop
+ style="stop-color:#bc4343;stop-opacity:1;"
+ offset="1"
+ id="stop3606" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5256"
+ id="linearGradient5262"
+ x1="-5.8968949"
+ y1="8.2935667"
+ x2="-5.5726938"
+ y2="4.0554204"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.65143369,0,0,0.72465707,8.5653256,0.88669298)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5256"
+ id="linearGradient5266"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.56219622,0,0,0.55767089,7.7886026,8.071931)"
+ x1="-6.1533332"
+ y1="7.3333344"
+ x2="-5.5266666"
+ y2="3.9733334" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5256"
+ id="linearGradient5270"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.56219622,0,0,0.55767089,17.263483,11.641025)"
+ x1="-6.5266666"
+ y1="3.4400015"
+ x2="-6.1133332"
+ y2="0.18666674" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5256"
+ id="linearGradient5274"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(26.826667,5.3333334)"
+ x1="-6.5266666"
+ y1="9.0933342"
+ x2="-5.5266666"
+ y2="3.9733334" />
+ <inkscape:perspective
+ id="perspective2951"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3650"
+ id="linearGradient3593"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-0.86061684,-0.15090715,0.13376284,-0.97092167,26.431688,37.768288)"
+ x1="15.603005"
+ y1="11.415942"
+ x2="14.703928"
+ y2="5.6313658" />
+ <linearGradient
+ id="linearGradient3650">
+ <stop
+ style="stop-color:#30cf38;stop-opacity:1;"
+ offset="0"
+ id="stop3652" />
+ <stop
+ style="stop-color:#fcfcfe;stop-opacity:1;"
+ offset="1"
+ id="stop3654" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3650"
+ id="linearGradient3656"
+ x1="15.603005"
+ y1="11.415942"
+ x2="14.703928"
+ y2="5.6313658"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.86061684,0.15090715,-0.13376284,0.97092167,5.6361914,-5.6778006)" />
+ <linearGradient
+ id="linearGradient2960">
+ <stop
+ style="stop-color:#449abb;stop-opacity:1;"
+ offset="0"
+ id="stop2962" />
+ <stop
+ style="stop-color:#fcfcfe;stop-opacity:1;"
+ offset="1"
+ id="stop2964" />
+ </linearGradient>
+ <linearGradient
+ y2="5.6313658"
+ x2="14.703928"
+ y1="11.415942"
+ x1="15.603005"
+ gradientTransform="matrix(0.86061684,0.15090715,-0.13376284,0.97092167,6.2083117,-5.554955)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient2968"
+ xlink:href="#linearGradient3650"
+ inkscape:collect="always" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3650"
+ id="linearGradient3000"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.86061684,0.15090715,-0.13376284,0.97092167,6.2083117,-5.554955)"
+ x1="15.603005"
+ y1="11.415942"
+ x2="14.703928"
+ y2="5.6313658" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3650"
+ id="linearGradient3003"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.86061684,0.15090715,-0.13376284,0.97092167,6.2083117,-5.554955)"
+ x1="15.603005"
+ y1="11.415942"
+ x2="14.703928"
+ y2="5.6313658" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4485"
+ id="linearGradient3006"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.56466735,0.09622175,-0.08776439,0.61908121,14.227777,7.1986057)"
+ x1="15.603005"
+ y1="11.415942"
+ x2="14.703928"
+ y2="5.6313658" />
+ <inkscape:perspective
+ id="perspective4544"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <linearGradient
+ id="linearGradient4485-7">
+ <stop
+ id="stop4487-7"
+ offset="0"
+ style="stop-color:#f1bd45;stop-opacity:1;" />
+ <stop
+ id="stop4489-5"
+ offset="1"
+ style="stop-color:#ffeebd;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4573"
+ id="linearGradient4579"
+ x1="20.594486"
+ y1="13.137122"
+ x2="20.594486"
+ y2="30.026983"
+ gradientUnits="userSpaceOnUse" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="11.313708"
+ inkscape:cx="6.9888605"
+ inkscape:cy="15.459013"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1272"
+ inkscape:window-height="966"
+ inkscape:window-x="262"
+ inkscape:window-y="0"
+ inkscape:window-maximized="0"
+ inkscape:snap-to-guides="false">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <text
+ xml:space="preserve"
+ style="font-size:20px;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Calibri;-inkscape-font-specification:Calibri"
+ x="3.8399999"
+ y="21.973333"
+ id="text3783"><tspan
+ sodipodi:role="line"
+ id="tspan3785"
+ x="3.8399999"
+ y="21.973333" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="7.2533331"
+ y="15.146667"
+ id="text3787"><tspan
+ sodipodi:role="line"
+ id="tspan3789"
+ x="7.2533331"
+ y="15.146667" /></text>
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="top">
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#linearGradient4579);fill-opacity:1;stroke:#414a5b;stroke-width:0.41006634;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+ id="path4533-4"
+ sodipodi:cx="20.594486"
+ sodipodi:cy="20.200155"
+ sodipodi:rx="12.285981"
+ sodipodi:ry="12.948894"
+ d="m 32.880467,20.200155 a 12.285981,12.948894 0 1 1 -24.5719619,0 12.285981,12.948894 0 1 1 24.5719619,0 z"
+ transform="matrix(1.2589928,0,0,1.1808874,-9.8858242,-7.8082054)" />
+ <path
+ style="fill:#fff9f9;fill-opacity:1;stroke:none;display:inline"
+ d="M 15.405667,4.9908058 C 14.416179,4.9696766 12.379939,5.1710089 11.394671,5.7347947 9.8182439,6.6368537 7.5180123,9.2006316 7.6657467,9.4004172 8.6617506,10.747354 8.966057,11.313207 8.966057,11.313207 c 0,0 1.374952,-1.764833 2.589367,-2.6024539 1.667647,-1.1502312 2.589472,-1.231399 4.429037,-0.9235739 2.441651,0.474329 3.754065,1.9989678 5.033,4.3613158 l -3.623759,3.181197 8.077962,0.846609 1.20792,-8.8252527 -3.422438,2.8989927 c 0,0 -1.361861,-2.0412957 -2.26485,-3.001612 [...]
+ id="path2876-8"
+ sodipodi:nodetypes="csscsccccccssccccsssscscccc"
+ inkscape:connector-curvature="0" />
+ </g>
+</svg>
diff --git a/Viewer/images/terminate.svg b/Viewer/images/terminate.svg
new file mode 100644
index 0000000..ea61bd0
--- /dev/null
+++ b/Viewer/images/terminate.svg
@@ -0,0 +1,230 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="terminate.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3795">
+ <stop
+ style="stop-color:#c53143;stop-opacity:1;"
+ offset="0"
+ id="stop3797" />
+ <stop
+ style="stop-color:#b8382b;stop-opacity:0;"
+ offset="1"
+ id="stop3799" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#fa0c1e;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#d9afb1;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3614">
+ <stop
+ style="stop-color:#fc3536;stop-opacity:1;"
+ offset="0"
+ id="stop3616" />
+ <stop
+ style="stop-color:#ea6f6f;stop-opacity:1;"
+ offset="1"
+ id="stop3618" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3602">
+ <stop
+ style="stop-color:#932626;stop-opacity:1;"
+ offset="0"
+ id="stop3604" />
+ <stop
+ style="stop-color:#bc4343;stop-opacity:1;"
+ offset="1"
+ id="stop3606" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3614"
+ id="linearGradient3691"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="12.89746"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3602"
+ id="linearGradient3693"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="2.2337441"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3728"
+ id="linearGradient3710"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-37.433021,38.420666)"
+ x1="15.413333"
+ y1="3.4795053"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3795"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-37.433021,38.420666)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3614"
+ id="linearGradient3806"
+ x1="-20.545807"
+ y1="0.31892619"
+ x2="3.4800975"
+ y2="0.31892619"
+ gradientUnits="userSpaceOnUse" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="-6.1043635"
+ inkscape:cy="10.518784"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer4"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1920"
+ inkscape:window-height="1140"
+ inkscape:window-x="-4"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="circle"
+ style="display:inline">
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#linearGradient3691);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3693);stroke-width:0.90856528;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path2820"
+ sodipodi:cx="15.413333"
+ sodipodi:cy="16.559999"
+ sodipodi:rx="13.76"
+ sodipodi:ry="12.613334"
+ d="m 29.173333,16.559999 a 13.76,12.613334 0 1 1 -27.5200003,0 13.76,12.613334 0 1 1 27.5200003,0 z"
+ transform="matrix(1.0537791,0,0,-1.1495772,-0.5155813,35.097002)" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <text
+ xml:space="preserve"
+ style="font-size:20px;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Calibri;-inkscape-font-specification:Calibri"
+ x="3.8399999"
+ y="21.973333"
+ id="text3783"><tspan
+ sodipodi:role="line"
+ id="tspan3785"
+ x="3.8399999"
+ y="21.973333" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="7.2533331"
+ y="15.146667"
+ id="text3787"><tspan
+ sodipodi:role="line"
+ id="tspan3789"
+ x="7.2533331"
+ y="15.146667" /></text>
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="top"
+ style="display:inline">
+ <path
+ style="fill:none;stroke:#f7f7f7;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="m 10.826667,9.76 c 0,0 -3.8115987,2.601882 -3.7333336,7.2 0.078265,4.598118 4.4019756,8.423268 8.8533336,8.426666 4.451358,0.0034 9.222232,-3.957489 9.173332,-8.853333 -0.0489,-4.895844 -3.946666,-6.6133327 -3.946666,-6.6133327"
+ id="path3008"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="czzzc" />
+ <path
+ style="fill:none;stroke:#fffbfb;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="m 15.920147,7.1451034 0.05304,6.8297926"
+ id="path3778"
+ inkscape:connector-curvature="0" />
+ </g>
+</svg>
diff --git a/Viewer/images/tree_branch_end.png b/Viewer/images/tree_branch_end.png
new file mode 100644
index 0000000..2319808
Binary files /dev/null and b/Viewer/images/tree_branch_end.png differ
diff --git a/Viewer/images/tree_branch_more.png b/Viewer/images/tree_branch_more.png
new file mode 100644
index 0000000..a2b91ff
Binary files /dev/null and b/Viewer/images/tree_branch_more.png differ
diff --git a/Viewer/images/tree_vline.png b/Viewer/images/tree_vline.png
new file mode 100644
index 0000000..f229200
Binary files /dev/null and b/Viewer/images/tree_vline.png differ
diff --git a/Viewer/images/unknown.svg b/Viewer/images/unknown.svg
new file mode 100644
index 0000000..e29e0a7
--- /dev/null
+++ b/Viewer/images/unknown.svg
@@ -0,0 +1,198 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.47 r22583"
+ sodipodi:docname="unknown.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3614">
+ <stop
+ style="stop-color:#cecece;stop-opacity:1;"
+ offset="0"
+ id="stop3616" />
+ <stop
+ style="stop-color:#fbfbfb;stop-opacity:1;"
+ offset="1"
+ id="stop3618" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3614"
+ id="linearGradient3691"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="12.89746"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3614"
+ id="linearGradient3693"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="2.2337441"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3614"
+ id="linearGradient3710"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-33.433021,42.207333)"
+ x1="15.413333"
+ y1="3.4795053"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3614"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-33.433021,42.207333)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="10.032489"
+ inkscape:cy="16.374922"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer3"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1328"
+ inkscape:window-height="1106"
+ inkscape:window-x="2504"
+ inkscape:window-y="65"
+ inkscape:window-maximized="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="circle"
+ style="display:inline">
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#linearGradient3691);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3693);stroke-width:0.90856528;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path2820"
+ sodipodi:cx="15.413333"
+ sodipodi:cy="16.559999"
+ sodipodi:rx="13.76"
+ sodipodi:ry="12.613334"
+ d="m 29.173333,16.559999 a 13.76,12.613334 0 1 1 -27.5200003,0 13.76,12.613334 0 1 1 27.5200003,0 z"
+ transform="matrix(1.0537791,0,0,-1.1495772,-0.30224808,35.097001)" />
+ <text
+ xml:space="preserve"
+ style="font-size:28px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#808080;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Adobe Courier Bold"
+ x="7.52"
+ y="25.759998"
+ id="text3613"><tspan
+ sodipodi:role="line"
+ id="tspan3615"
+ x="7.52"
+ y="25.759998"
+ style="font-size:28px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#808080;font-family:Sans;-inkscape-font-specification:Adobe Courier Bold">?</tspan></text>
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <text
+ xml:space="preserve"
+ style="font-size:20px;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Calibri;-inkscape-font-specification:Calibri"
+ x="3.8399999"
+ y="21.973333"
+ id="text3783"><tspan
+ sodipodi:role="line"
+ id="tspan3785"
+ x="3.8399999"
+ y="21.973333" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="7.2533331"
+ y="15.146667"
+ id="text3787"><tspan
+ sodipodi:role="line"
+ id="tspan3789"
+ x="7.2533331"
+ y="15.146667" /></text>
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="top"
+ style="display:inline">
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#888888;stroke-width:1.24076998000000005;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path3786"
+ sodipodi:cx="16.213333"
+ sodipodi:cy="17.973333"
+ sodipodi:rx="13.973333"
+ sodipodi:ry="13.706667"
+ d="m 30.186666,17.973333 a 13.973333,13.706667 0 1 1 -27.9466662,0 13.973333,13.706667 0 1 1 27.9466662,0 z"
+ transform="matrix(1.0376908,0,0,1.0578794,-0.937761,-2.9536141)" />
+ </g>
+</svg>
diff --git a/Viewer/images/unselect_all.svg b/Viewer/images/unselect_all.svg
new file mode 100644
index 0000000..3a2c35b
--- /dev/null
+++ b/Viewer/images/unselect_all.svg
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="unselect_all.svg">
+ <defs
+ id="defs4" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="16.15625"
+ inkscape:cx="-5.1619"
+ inkscape:cy="14.48913"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-to-guides="false"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1920"
+ inkscape:window-height="1140"
+ inkscape:window-x="-4"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2985"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ <dc:description>ecFlowUi icon</dc:description>
+ <cc:license
+ rdf:resource="" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="Layer"
+ style="display:inline">
+ <rect
+ ry="0.84339386"
+ y="1.572536"
+ x="1.8568667"
+ height="23.495165"
+ width="22.938105"
+ id="rect3755"
+ style="fill:#3d4f70;fill-opacity:1;fill-rule:evenodd;stroke:#3d4f70;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
+ <rect
+ ry="0.82561916"
+ y="5.2243738"
+ x="5.1992264"
+ height="23"
+ width="23"
+ id="rect3757"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
+ <rect
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#3d4f70;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="rect2985"
+ width="22.504835"
+ height="22.56673"
+ x="7.9226303"
+ y="7.9477773"
+ ry="0.81006634" />
+ </g>
+</svg>
diff --git a/Viewer/images/variable.svg b/Viewer/images/variable.svg
new file mode 100644
index 0000000..6c650cc
--- /dev/null
+++ b/Viewer/images/variable.svg
@@ -0,0 +1,219 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="variable.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#519aed;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#e9dddd;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f1f3fb;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3614">
+ <stop
+ style="stop-color:#2c71d9;stop-opacity:1;"
+ offset="0"
+ id="stop3616" />
+ <stop
+ style="stop-color:#ececec;stop-opacity:1;"
+ offset="1"
+ id="stop3618" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3602">
+ <stop
+ style="stop-color:#f5f5f5;stop-opacity:1;"
+ offset="0"
+ id="stop3604" />
+ <stop
+ style="stop-color:#141bc6;stop-opacity:1;"
+ offset="1"
+ id="stop3606" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3614"
+ id="linearGradient3691"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="12.89746"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3602"
+ id="linearGradient3693"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="2.2337441"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3728"
+ id="linearGradient3710"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-31.566354,35.860667)"
+ x1="15.413333"
+ y1="3.4795053"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3756"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-31.566354,35.860667)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="23.252936"
+ inkscape:cy="15.51908"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1408"
+ inkscape:window-height="1093"
+ inkscape:window-x="370"
+ inkscape:window-y="39"
+ inkscape:window-maximized="0"
+ showguides="true"
+ inkscape:guide-bbox="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="bg"
+ style="display:inline" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <text
+ xml:space="preserve"
+ style="font-size:20px;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Calibri;-inkscape-font-specification:Calibri"
+ x="3.8399999"
+ y="21.973333"
+ id="text3783"><tspan
+ sodipodi:role="line"
+ id="tspan3785"
+ x="3.8399999"
+ y="21.973333" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="7.2533331"
+ y="15.146667"
+ id="text3787"><tspan
+ sodipodi:role="line"
+ id="tspan3789"
+ x="7.2533331"
+ y="15.146667" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:31.33018303px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#003380;fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:Monospace"
+ x="-0.15020625"
+ y="27.353823"
+ id="text3791"
+ transform="scale(1.0238296,0.97672504)"><tspan
+ sodipodi:role="line"
+ id="tspan3793"
+ x="-0.15020625"
+ y="27.353823"
+ style="font-size:31.33018303px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#003380;font-family:Monospace;-inkscape-font-specification:Monospace">V<tspan
+ style="font-size:16px"
+ id="tspan3781" /></tspan></text>
+ <path
+ style="fill:none;stroke:#003380;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="m 20.20402,18.826665 c 8.371964,0 8.371964,0 8.371964,0"
+ id="path3008"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path3010"
+ d="m 20.330688,13.386668 c 8.371964,0 8.371964,0 8.371964,0"
+ style="fill:#003380;stroke:#003380;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+ </g>
+</svg>
diff --git a/Viewer/images/warning.svg b/Viewer/images/warning.svg
new file mode 100644
index 0000000..29d81ca
--- /dev/null
+++ b/Viewer/images/warning.svg
@@ -0,0 +1,238 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="warning.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient4429">
+ <stop
+ style="stop-color:#f5ee6a;stop-opacity:1;"
+ offset="0"
+ id="stop4431" />
+ <stop
+ style="stop-color:#fff5c6;stop-opacity:1;"
+ offset="1"
+ id="stop4433" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient4421">
+ <stop
+ style="stop-color:#fffac3;stop-opacity:1;"
+ offset="0"
+ id="stop4423" />
+ <stop
+ style="stop-color:#fffbc3;stop-opacity:0.97368419;"
+ offset="1"
+ id="stop4425" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3905">
+ <stop
+ id="stop3907"
+ offset="0"
+ style="stop-color:#ff8b61;stop-opacity:1;" />
+ <stop
+ id="stop3909"
+ offset="1"
+ style="stop-color:#ff6600;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3674">
+ <stop
+ style="stop-color:#f9f9ea;stop-opacity:1;"
+ offset="0"
+ id="stop3676" />
+ <stop
+ style="stop-color:#fcf10d;stop-opacity:0.99215686;"
+ offset="1"
+ id="stop3678" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3596">
+ <stop
+ style="stop-color:#ffff00;stop-opacity:1;"
+ offset="0"
+ id="stop3598" />
+ <stop
+ style="stop-color:#ededd2;stop-opacity:0.99137932;"
+ offset="1"
+ id="stop3600" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3759">
+ <stop
+ style="stop-color:#0f1934;stop-opacity:1;"
+ offset="0"
+ id="stop3761" />
+ <stop
+ style="stop-color:#0f1123;stop-opacity:1;"
+ offset="1"
+ id="stop3763" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3674"
+ id="linearGradient3680"
+ x1="13.117022"
+ y1="1020.3622"
+ x2="19.563829"
+ y2="1053.5383"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(35.404255,-0.92843327)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3674-9"
+ id="linearGradient3680-0"
+ x1="23.639265"
+ y1="1029.8322"
+ x2="-9.4723015"
+ y2="1043.9935"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.1274903,0,0,1.1742062,-0.90288397,-180.95653)" />
+ <linearGradient
+ id="linearGradient3674-9">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="0"
+ id="stop3676-8" />
+ <stop
+ style="stop-color:#90bbd4;stop-opacity:1;"
+ offset="1"
+ id="stop3678-3" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4429"
+ id="linearGradient4435"
+ x1="7.0560932"
+ y1="1045.0276"
+ x2="25.253386"
+ y2="1043.1708"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0446809,0,0,1,-1.1158324,0)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4421"
+ id="linearGradient4439"
+ gradientUnits="userSpaceOnUse"
+ x1="13.599463"
+ y1="1040.2897"
+ x2="8.1586552"
+ y2="1028.5138"
+ gradientTransform="matrix(0.65872086,0,0,0.62103013,5.3472368,387.59247)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="16.15625"
+ inkscape:cx="15.478722"
+ inkscape:cy="17.039481"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:snap-to-guides="false"
+ inkscape:window-width="1920"
+ inkscape:window-height="1180"
+ inkscape:window-x="1916"
+ inkscape:window-y="-4"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2985"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-1020.3622)">
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccc"
+ id="path4437"
+ d="m 4.2942976,1041.7282 c 0,0 6.9176124,-13.0464 10.4726194,-19.3353 0.990074,-1.6289 2.031023,-0.1177 2.031023,-0.1177 0.05025,0.063 8.065649,15.1623 8.065649,15.1623 0.728049,1.625 2.992244,4.2327 0.162004,4.1785 l -18.3018075,1.2039 c 0,0 -3.9133707,1.5156 -2.4294879,-1.0917 z"
+ style="fill:url(#linearGradient4439);fill-opacity:1;stroke:none" />
+ <path
+ style="fill:url(#linearGradient4435);fill-opacity:1;stroke:none"
+ d="m 4.309115,1042.5827 -3.9377414,8.1703 c 10.6630484,0.9477 29.7526874,1.0314 30.3907154,-0.4333 l -5.652117,-12.7505 c -3.928647,-1.1375 -7.973767,-0.3224 -9.97651,0.062 -7.3501142,1.4097 -10.824347,4.9517 -10.824347,4.9517 z"
+ id="path4419"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccscc" />
+ <path
+ style="fill:none;stroke:#d57301;stroke-width:1.50000000000000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="m 1.6581854,1047.9364 c 0,0 7.306834,-15.3271 12.7036686,-25.4536 1.503025,-2.6229 3.083284,-0.1899 3.083284,-0.1899 0.04376,0.058 4.064206,8.0792 7.485881,14.9107 2.544876,5.081 4.758529,9.504 4.758529,9.504 1.105246,2.6168 3.133057,5.0217 -1.16351,4.9345 l -24.4951466,-0.1548 c 0,0 -4.62537905,0.6467 -2.372706,-3.5517 z"
+ id="path2822-9"
+ sodipodi:nodetypes="cccsccccc"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:type="arc"
+ style="fill:#12122b;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ id="path3808"
+ sodipodi:cx="13.090909"
+ sodipodi:cy="37.694389"
+ sodipodi:rx="1.7640232"
+ sodipodi:ry="1.6092843"
+ d="m 14.854932,37.694389 c 0,0.888784 -0.78978,1.609285 -1.764023,1.609285 -0.974243,0 -1.764023,-0.720501 -1.764023,-1.609285 0,-0.888783 0.78978,-1.609284 1.764023,-1.609284 0.974243,0 1.764023,0.720501 1.764023,1.609284 z"
+ transform="matrix(1.2890225,0,0,1.399682,-0.28646851,993.48167)" />
+ <path
+ style="fill:#191b38;fill-opacity:1;stroke:none"
+ d="m 15.358832,1028.0524 c -0.722297,1.2171 -1.27658,5.2347 -1.255515,7.6043 0.02107,2.3696 1.255515,6.5179 1.255515,6.5179 l 1.644492,0 c 0,0 1.294917,-4.1507 1.314337,-6.5179 0.01942,-2.3672 -0.307773,-6.5311 -1.12865,-7.7281 -0.993415,-1.1552 -1.615027,-0.2386 -1.830179,0.1238 z"
+ id="path3810"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="czcczcc" />
+ </g>
+</svg>
diff --git a/Viewer/images/why.svg b/Viewer/images/why.svg
new file mode 100644
index 0000000..58f829e
--- /dev/null
+++ b/Viewer/images/why.svg
@@ -0,0 +1,220 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="why.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#519aed;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#e9dddd;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f1f3fb;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3614">
+ <stop
+ style="stop-color:#2c71d9;stop-opacity:1;"
+ offset="0"
+ id="stop3616" />
+ <stop
+ style="stop-color:#ececec;stop-opacity:1;"
+ offset="1"
+ id="stop3618" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3602">
+ <stop
+ style="stop-color:#f5f5f5;stop-opacity:1;"
+ offset="0"
+ id="stop3604" />
+ <stop
+ style="stop-color:#141bc6;stop-opacity:1;"
+ offset="1"
+ id="stop3606" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3614"
+ id="linearGradient3691"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="12.89746"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3602"
+ id="linearGradient3693"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="2.2337441"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3728"
+ id="linearGradient3710"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-31.566354,35.860667)"
+ x1="15.413333"
+ y1="3.4795053"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3756"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-31.566354,35.860667)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="3.9949206"
+ inkscape:cy="15.420625"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1408"
+ inkscape:window-height="1093"
+ inkscape:window-x="271"
+ inkscape:window-y="22"
+ inkscape:window-maximized="0"
+ showguides="true"
+ inkscape:guide-bbox="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="bg"
+ style="display:inline">
+ <text
+ xml:space="preserve"
+ style="font-size:34.87540436px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#373e48;fill-opacity:1;stroke:none;display:inline;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif"
+ x="4.7299118"
+ y="28.926764"
+ id="text3791-6"
+ transform="scale(1.0012789,0.99872274)"><tspan
+ sodipodi:role="line"
+ id="tspan3793-6"
+ x="4.7299118"
+ y="28.926764"
+ style="font-size:34.87540436px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#373e48;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif">?</tspan></text>
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <text
+ xml:space="preserve"
+ style="font-size:20px;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Calibri;-inkscape-font-specification:Calibri"
+ x="3.8399999"
+ y="21.973333"
+ id="text3783"><tspan
+ sodipodi:role="line"
+ id="tspan3785"
+ x="3.8399999"
+ y="21.973333" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="7.2533331"
+ y="15.146667"
+ id="text3787"><tspan
+ sodipodi:role="line"
+ id="tspan3789"
+ x="7.2533331"
+ y="15.146667" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:34.87540435999999744px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#164450;fill-opacity:1;stroke:none;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif"
+ x="4.3724856"
+ y="28.620384"
+ id="text3791"
+ transform="scale(1.0012789,0.99872274)"><tspan
+ sodipodi:role="line"
+ id="tspan3793"
+ x="4.3724856"
+ y="28.620384"
+ style="font-size:34.87540435999999744px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#164450;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif">?</tspan></text>
+ </g>
+</svg>
diff --git a/Viewer/images/zombie.svg b/Viewer/images/zombie.svg
new file mode 100644
index 0000000..98d7f48
--- /dev/null
+++ b/Viewer/images/zombie.svg
@@ -0,0 +1,220 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="32"
+ height="32"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="zombie.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3756">
+ <stop
+ id="stop3758"
+ offset="0"
+ style="stop-color:#519aed;stop-opacity:1;" />
+ <stop
+ id="stop3760"
+ offset="1"
+ style="stop-color:#e9dddd;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3728">
+ <stop
+ style="stop-color:#f1f3fb;stop-opacity:1;"
+ offset="0"
+ id="stop3730" />
+ <stop
+ style="stop-color:#273df9;stop-opacity:0;"
+ offset="1"
+ id="stop3732" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3614">
+ <stop
+ style="stop-color:#2c71d9;stop-opacity:1;"
+ offset="0"
+ id="stop3616" />
+ <stop
+ style="stop-color:#ececec;stop-opacity:1;"
+ offset="1"
+ id="stop3618" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3602">
+ <stop
+ style="stop-color:#f5f5f5;stop-opacity:1;"
+ offset="0"
+ id="stop3604" />
+ <stop
+ style="stop-color:#141bc6;stop-opacity:1;"
+ offset="1"
+ id="stop3606" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3614"
+ id="linearGradient3691"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="12.89746"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3602"
+ id="linearGradient3693"
+ gradientUnits="userSpaceOnUse"
+ x1="15.413333"
+ y1="2.2337441"
+ x2="15.413333"
+ y2="31.085577" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3728"
+ id="linearGradient3710"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-31.566354,35.860667)"
+ x1="15.413333"
+ y1="3.4795053"
+ x2="15.941438"
+ y2="18.883736" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3756"
+ id="linearGradient3720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0688752,0,0,-1.1672542,-31.566354,35.860667)"
+ x1="24.437176"
+ y1="3.4853487"
+ x2="15.941438"
+ y2="18.883736" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="18.75"
+ inkscape:cx="12.503154"
+ inkscape:cy="15.447292"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1408"
+ inkscape:window-height="1096"
+ inkscape:window-x="460"
+ inkscape:window-y="36"
+ inkscape:window-maximized="0"
+ showguides="true"
+ inkscape:guide-bbox="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="Apache License 2.0" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>ECMWF</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:language>en-GB</dc:language>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>Metview icon</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:description>Metview icon</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="bg"
+ style="display:inline">
+ <text
+ xml:space="preserve"
+ style="font-size:34.87540436px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#373e48;fill-opacity:1;stroke:none;display:inline;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif"
+ x="3.4515469"
+ y="29.727787"
+ id="text3791-6"
+ transform="scale(1.0012789,0.99872274)"><tspan
+ sodipodi:role="line"
+ id="tspan3793-6"
+ x="3.4515469"
+ y="29.727787"
+ style="font-size:34.87540436px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#373e48;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif">Z</tspan></text>
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="item"
+ style="display:inline">
+ <text
+ xml:space="preserve"
+ style="font-size:20px;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Calibri;-inkscape-font-specification:Calibri"
+ x="3.8399999"
+ y="21.973333"
+ id="text3783"><tspan
+ sodipodi:role="line"
+ id="tspan3785"
+ x="3.8399999"
+ y="21.973333" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="7.2533331"
+ y="15.146667"
+ id="text3787"><tspan
+ sodipodi:role="line"
+ id="tspan3789"
+ x="7.2533331"
+ y="15.146667" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:34.87540436px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#d40000;fill-opacity:1;stroke:none;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif"
+ x="2.2951422"
+ y="28.940794"
+ id="text3791"
+ transform="scale(1.0012789,0.99872274)"><tspan
+ sodipodi:role="line"
+ id="tspan3793"
+ x="2.2951422"
+ y="28.940794"
+ style="font-size:34.87540436px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#d40000;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif">Z</tspan></text>
+ </g>
+</svg>
diff --git a/Viewer/scripts/CMakeLists.txt b/Viewer/scripts/CMakeLists.txt
new file mode 100644
index 0000000..af69f55
--- /dev/null
+++ b/Viewer/scripts/CMakeLists.txt
@@ -0,0 +1,30 @@
+
+# the list of files we want to install
+set (files ecflow_ui)
+
+
+
+# set variables which will be expanded in the startup script
+if(ENABLE_UI_BACKTRACE)
+ set(UI_BACKTRACE yes)
+else()
+ set(UI_BACKTRACE no)
+endif()
+
+if(NOT UI_BACKTRACE_EMAIL_ADDRESSES)
+ set(UI_BACKTRACE_EMAIL_ADDRESSES "x")
+endif()
+
+
+# for each file, copy it into the build directory at build time
+# and install it into the installation directory at install time (!)
+foreach( f ${files} )
+ configure_file(${f}.in ${CMAKE_BINARY_DIR}/bin/${f} @ONLY)
+
+
+ # ensure file is installed at install time
+ install( FILES ${CMAKE_BINARY_DIR}/bin/${f}
+ DESTINATION bin
+ PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE)
+
+endforeach()
diff --git a/Viewer/scripts/ecflow_ui.in b/Viewer/scripts/ecflow_ui.in
new file mode 100755
index 0000000..32815ee
--- /dev/null
+++ b/Viewer/scripts/ecflow_ui.in
@@ -0,0 +1,242 @@
+#!/bin/bash
+
+#============================================================================
+# Copyright 2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#============================================================================
+
+
+# Environment variables from the configuration step
+ECFLOWUI_BT=@UI_BACKTRACE@
+ECFLOWUI_BT_EMAIL_ADDRESSES=@UI_BACKTRACE_EMAIL_ADDRESSES@
+ECFLOWUI_VERSION=@ECFLOW_VERSION_STR@
+ECFLOWUI_INSTALLDIR=@CMAKE_INSTALL_PREFIX@
+
+# ----------------------------------------------------------
+# Clean up the tmp directory at the end or on error
+#-----------------------------------------------------------
+cleanup(){
+ status=$?
+ trap "" EXIT ERR
+
+ # restore stdout/stderr
+ if [ x$ECFUI_SLOG != xyes ]
+ then
+ exec 1>&5
+ exec 2>&6
+ fi
+
+
+ if [ "$status" -eq "0" ]
+ then
+ echo "$(basename $0): $1 (OK) (line $2), exit status $status, starting 'cleanup'"
+ else
+ echo "$(basename $0): $1 on ERROR (line $2), exit status $status, starting 'cleanup'"
+
+ if [ -e $ECFLOWUI_LOGFILE ] ; then
+
+ TAILNUM=50
+
+ if [ $ECFLOWUI_BT != "no" ] ; then
+ # find the backtrace tag if there
+ btline=$(grep -n "Backtrace:" $ECFLOWUI_LOGFILE | cut -f1 --delimiter=':')
+ gret=$?
+ if [ "$gret" = "0" -a "x$btline" != "x" ] ; then
+ nlines=$(wc -l $ECFLOWUI_LOGFILE | cut -f1 --delimiter=' ')
+ TAILNUM=$(expr $nlines - $btline + 100)
+ fi
+ fi
+
+ # Logic: ECFLOWUI_BT_EMAIL_ADDRESSES is not set, then the log/backtrace
+ # will go to stdout; otherwise it will be e-mailed to the
+ # addresses instead (the user will not see the backtrace).
+
+ if [ $ECFLOWUI_BT_EMAIL_ADDRESSES != "x" ] ; then
+ EFLOWUI_LOGTAIL="${ECFLOWUI_LOGFILE}.tail"
+ ecfuimsg="ecFlowUI backtrace from user $USER"
+ echo "Sending crash report by e-mail..."
+ echo "user/host : $USER/$HOST" > $EFLOWUI_LOGTAIL
+ echo "ecflow version : $ECFLOWUI_VERSION" >> $EFLOWUI_LOGTAIL
+ echo "ecflow install dir : $ECFLOWUI_INSTALLDIR" >> $EFLOWUI_LOGTAIL
+ echo "start time : $ECFLOWUI_STARTTIME" >> $EFLOWUI_LOGTAIL
+ echo "stop time : $(date)" >> $EFLOWUI_LOGTAIL
+ echo "" >> $EFLOWUI_LOGTAIL
+ tail -$TAILNUM $ECFLOWUI_LOGFILE >> $EFLOWUI_LOGTAIL
+
+ addr=$(echo $ECFLOWUI_BT_EMAIL_ADDRESSES | sed 's/,/ /g')
+ mail -s "$ecfuimsg" $addr < $EFLOWUI_LOGTAIL
+ rm -f $EFLOWUI_LOGTAIL
+ echo "Report sent"
+ else
+ echo "Last $TAILNUM lines of log file:"
+ tail -$TAILNUM $ECFLOWUI_LOGFILE
+ fi
+
+ fi
+ fi
+
+
+
+ # remove temporary directory
+ if [ $(echo $ECFLOWUI_TMPDIR | grep -c "/ecflow_ui.") -ge 1 ] ; then
+ rm -Rf $ECFLOWUI_TMPDIR
+ fi
+
+ exit $status
+}
+
+
+
+#-----------------------------------------------------------
+# checkoption()
+# Checks the command-line options
+#-----------------------------------------------------------
+
+checkoption() {
+
+while [ "$1" != "" ]
+do
+ case "$1" in
+
+ -log)
+ ECFUI_SLOG=yes
+ ;;
+
+ -slog)
+ ECFUI_SLOG=yes
+ ;;
+
+ -s)
+ export ECFUI_SESSION_MANAGER=yes
+ ;;
+
+ -h)
+ ECFUI_HELP=yes
+ ;;
+
+ esac
+ shift
+done
+}
+
+
+
+checkoption "$@"
+
+
+
+#-----------------------------------------------------------
+# Help message
+#-----------------------------------------------------------
+
+if [ "x$ECFUI_HELP" != x ]
+then
+
+ cat <<HEND
+EcflowUI
+ Command-line flags:
+ -log : write log messages to standard output
+ -s : start via the session manager
+ -h : print this help message
+HEND
+
+ exit 0
+fi
+
+
+
+
+
+#Define tmp root dir
+TMPDIR_ROOT=${TMPDIR:=/tmp}
+
+# check that TMPDIR_ROOT actually exists - we can't run without it
+if [ ! -d $TMPDIR_ROOT ]
+then
+ echo ""
+ echo " Temporary directory '$TMPDIR_ROOT' does not exist"
+ echo " ecFlowUI needs this in order to run. Check that environment"
+ echo " variable \$TMPDIR is set to a valid directory and try again."
+ exit 1
+fi
+
+#Define and create tmp dir
+export ECFLOWUI_TMPDIR=${TMPDIR_ROOT}/ecflow_ui.$$.$LOGNAME
+mkdir -p $ECFLOWUI_TMPDIR
+
+#Check if we could create it
+if [ $? -ne 0 ]
+then
+ echo ""
+ echo " Temporary directory '$ECFLOWUI_TMPDIR' could not be created."
+ echo " ecFlowUI needs this in order to run. Check that environment"
+ echo " variable \$TMPDIR is set to a valid directory and try again."
+ exit 1
+fi
+
+
+# Where to write the log file to
+ECFLOWUI_LOGFILE=$ECFLOWUI_TMPDIR/ecflowui_log_$$.$LOGNAME.txt
+
+
+#-----------------------------------------------------------
+# Close tty and redirect stdout to a file?
+#-----------------------------------------------------------
+
+if [ x$ECFUI_SLOG != xyes ]
+then
+ exec < /dev/null
+ exec 5>&1 # store for later
+ exec 6>&2 # store for later
+ exec 1> $ECFLOWUI_LOGFILE # (restored in cleanup())
+ exec 2>&1 # redirect stderr to stdout, (restored in cleanup())
+ # note that it seems to be better to do
+ # exec 2>&1
+ # rather than
+ # exec 2> $ECFLOWUI_LOGFILE
+ # because this way we get the stderr at the end rather than the start
+ # due to the difference in flushing behaviours
+fi
+
+
+
+# =============================================================
+# tmp directory cleaned automatically at end or at error.
+# on new platforms check that these signals are valid:
+
+ECFLOWUI_SIGLIST="HUP INT QUIT TERM XCPU XFSZ"
+# 1 2 3 15 30/24 31/25
+
+trap 'cleanup "EXIT" $LINENO' EXIT
+trap 'cleanup "SIGNAL trap" $LINENO' $ECFLOWUI_SIGLIST
+
+#Figure out the directory of the exe
+EXE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+
+
+# note when we started it up
+ECFLOWUI_STARTTIME=$(date)
+
+
+#-----------------------------------------------------------
+# Run the executable
+#-----------------------------------------------------------
+
+exe=${EXE_DIR}/ecflow_ui.x
+
+
+#-----------------------------------------------------------
+# Backtrace report?
+#-----------------------------------------------------------
+
+if [ $ECFLOWUI_BT != "no" ]
+then
+ catchsegv $exe
+else
+ ${exe}
+fi
+
diff --git a/Viewer/src/AboutDialog.cpp b/Viewer/src/AboutDialog.cpp
new file mode 100644
index 0000000..dc2ba13
--- /dev/null
+++ b/Viewer/src/AboutDialog.cpp
@@ -0,0 +1,74 @@
+//============================================================================
+// Copyright 2015 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "AboutDialog.hpp"
+
+#include "Version.hpp"
+
+#include <QDate>
+#include <QRegExp>
+
+AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent)
+{
+ setupUi(this);
+
+
+ QString title="EcflowUI";
+ QString ecfVersionTxt=QString::fromStdString(ecf::Version::raw());
+ QString desc=QString::fromStdString(ecf::Version::description());
+ QString descTxt="<b>ecflow version:</b> " + ecfVersionTxt;
+
+ int pos=0;
+ QRegExp rx("boost\\((\\S+)\\)");
+ if((pos = rx.indexIn(desc, pos)) != -1)
+ {
+ descTxt+="<br><b>boost version:</b> " + rx.cap(1);
+ }
+
+ rx=QRegExp("compiler\\(([^\\)]+)\\)");
+ if((pos = rx.indexIn(desc, pos)) != -1)
+ {
+ descTxt+="<br><b>compiler</b>: " + rx.cap(1);
+ }
+
+ rx=QRegExp("protocol\\((\\S+)\\)");
+ if((pos = rx.indexIn(desc, pos)) != -1)
+ {
+ descTxt+="<br><b>protocol:</b> " + rx.cap(1);
+ }
+
+ descTxt+="<br><b>compiled on:</b> " +desc.section("Compiled on",1,1);
+
+ const char *qtv=qVersion();
+ if(qtv)
+ {
+ descTxt+="<br><b>Qt version: </b>" + QString(qtv);
+ }
+
+ QString logoTxt;
+ logoTxt+="<h3> " + title + "</h3>";
+ if(!ecfVersionTxt.isEmpty())
+ {
+ logoTxt+="<p> ecflow version: " + ecfVersionTxt + "</p>";
+ }
+
+ logoLabel_->setText(logoTxt);
+
+ versionLabel_->setText(descTxt);
+
+ QString licenseText="Copyright 2009-" + QString::number(QDate::currentDate().year()) + " ECMWF.";
+ licenseText+=" This software is licensed under the terms of the Apache Licence version 2.0";
+ licenseText+=" which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.";
+ licenseText+=" In applying this licence, ECMWF does not waive the privileges and immunities";
+ licenseText+=" granted to it by virtue of its status as an intergovernmental organisation";
+ licenseText+=" nor does it submit to any jurisdiction.";
+
+ licenseLabel_->setText(licenseText);
+}
diff --git a/Viewer/src/AboutDialog.hpp b/Viewer/src/AboutDialog.hpp
new file mode 100644
index 0000000..7f52cac
--- /dev/null
+++ b/Viewer/src/AboutDialog.hpp
@@ -0,0 +1,25 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef ABOUTDIALOG_INC_
+#define ABOUTDIALOG_INC_
+
+#include <QDialog>
+
+#include "ui_AboutDialog.h"
+
+class AboutDialog : public QDialog, protected Ui::AboutDialog
+{
+public:
+ explicit AboutDialog(QWidget *parent=0);
+};
+
+#endif
+
diff --git a/Viewer/src/AboutDialog.ui b/Viewer/src/AboutDialog.ui
new file mode 100644
index 0000000..c86c5cc
--- /dev/null
+++ b/Viewer/src/AboutDialog.ui
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>AboutDialog</class>
+ <widget class="QDialog" name="AboutDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>538</width>
+ <height>251</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="windowTitle">
+ <string>About EcflowUI</string>
+ </property>
+ <property name="modal">
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QLabel" name="logoLabel_">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="palette">
+ <palette>
+ <active>
+ <colorrole role="Base">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Window">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </active>
+ <inactive>
+ <colorrole role="Base">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Window">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </inactive>
+ <disabled>
+ <colorrole role="Base">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Window">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </disabled>
+ </palette>
+ </property>
+ <property name="autoFillBackground">
+ <bool>true</bool>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="text">
+ <string>logoLabel_</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTabWidget" name="tabWidget">
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="tab1W">
+ <attribute name="title">
+ <string>Version</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QLabel" name="versionLabel_">
+ <property name="text">
+ <string>version</string>
+ </property>
+ <property name="indent">
+ <number>10</number>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tab2W">
+ <attribute name="title">
+ <string>License</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QLabel" name="licenseLabel_">
+ <property name="text">
+ <string>license</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ <property name="indent">
+ <number>10</number>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>AboutDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>257</x>
+ <y>218</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>227</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>AboutDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>274</x>
+ <y>218</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>283</x>
+ <y>227</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/Viewer/src/AbstractNodeModel.cpp b/Viewer/src/AbstractNodeModel.cpp
new file mode 100644
index 0000000..6293bda
--- /dev/null
+++ b/Viewer/src/AbstractNodeModel.cpp
@@ -0,0 +1,175 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "AbstractNodeModel.hpp"
+
+#include <QDebug>
+
+
+#include "ServerFilter.hpp"
+#include "ServerHandler.hpp"
+#include "ServerItem.hpp"
+#include "VFilter.hpp"
+#include "VModelData.hpp"
+#include "VNState.hpp"
+
+
+AbstractNodeModel::AbstractNodeModel(QObject *parent) :
+ QAbstractItemModel(parent),
+ active_(false)
+{
+ //At this point the model is not active and it cannot see its data!
+}
+
+AbstractNodeModel::~AbstractNodeModel()
+{
+ clean();
+}
+
+void AbstractNodeModel::active(bool active)
+{
+ if(active_ != active)
+ {
+ active_=active;
+
+ beginResetModel();
+
+ data()->setActive(active_);
+
+#if 0
+ //When the model becomes active we reload everything
+ if(active_)
+ {
+ data()->runFilter(false);
+ //init();
+
+ //Initialises the filter
+ //resetStateFilter(false);
+ }
+
+ //When the model becomes inactive we clean it and
+ //release all the resources
+ else
+ {
+ data()->clear(); //clean();
+ }
+#endif
+ endResetModel();
+
+ //After finishing reset the view will automatically be notified about
+ //the changes. Also the filter model will be notified!
+ }
+}
+
+//Called when the list of servers to be displayed has changed.
+//void AbstractNodeModel::notifyConfigChanged(ServerFilter*)
+//{
+// if(active_)
+// reload();
+//}
+
+void AbstractNodeModel::init()
+{
+ /*ServerFilter *filter=config_->serverFilter();
+ for(unsigned int i=0; i < filter->items().size(); i++)
+ {
+ if(ServerHandler *server=filter->items().at(i)->serverHandler())
+ {
+ //The model has to observe the nodes o the server.
+ server->addNodeObserver(this);
+
+ //The model stores the servers it has to deal with in a local object.
+ servers_->add(server,makeFilter());
+ }
+ }*/
+}
+
+void AbstractNodeModel::clean()
+{
+ /*for(int i=0; i < servers_->count(); i++)
+ {
+ if(ServerHandler *s=servers_->server(i))
+ {
+ s->removeNodeObserver(this);
+ }
+ }
+
+ servers_->clear();*/
+}
+
+//TODO!!!!!
+
+//Should be reviewed what it is actually doing!!!!!!!!!!!!!!!!!
+void AbstractNodeModel::reload()
+{
+ if(active_)
+ {
+ beginResetModel();
+ //data_->reload();
+ //clean();
+ //init();
+ //resetStateFilter(false); //do not emit change signal
+ endResetModel();
+ }
+}
+
+
+bool AbstractNodeModel::hasData() const
+{
+ return (active_ && data()->count() > 0);
+}
+
+void AbstractNodeModel::dataIsAboutToChange()
+{
+ beginResetModel();
+}
+
+void AbstractNodeModel::slotFilterDeleteBegin()
+{
+ beginResetModel();
+}
+
+
+void AbstractNodeModel::slotFilterDeleteEnd()
+{
+ endResetModel();
+}
+
+
+//----------------------------------------------
+//
+// Server to index mapping and lookup
+//
+//----------------------------------------------
+
+QModelIndex AbstractNodeModel::infoToIndex(VInfo_ptr info,int column) const
+{
+ if(info)
+ {
+ if(info->isServer())
+ {
+ if(ServerHandler *s=info->server())
+ {
+ return serverToIndex(s);
+ }
+ }
+ else if(VNode* n=info->node())
+ {
+ return nodeToIndex(n);
+ }
+ }
+
+ return QModelIndex();
+}
+
+
+
+
+
+
diff --git a/Viewer/src/AbstractNodeModel.hpp b/Viewer/src/AbstractNodeModel.hpp
new file mode 100644
index 0000000..0c602d1
--- /dev/null
+++ b/Viewer/src/AbstractNodeModel.hpp
@@ -0,0 +1,86 @@
+//============================================================================
+// Copyright 2015 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef ABSTRACTNODEMODEL_H
+#define ABSTRACTNODEMODEL_H
+
+#include <QAbstractItemModel>
+
+#include "Aspect.hpp"
+#include "NodeObserver.hpp"
+#include "VInfo.hpp"
+
+class Node;
+
+class IconFilter;
+class VModelData;
+class VModelServer;
+class VParamSet;
+
+class AbstractNodeModel;
+
+class AbstractNodeModel : public QAbstractItemModel
+{
+ Q_OBJECT
+
+public:
+ explicit AbstractNodeModel(QObject *parent=0);
+ virtual ~AbstractNodeModel();
+
+ enum CustomItemRole {FilterRole = Qt::UserRole+1, IconRole = Qt::UserRole+2,
+ ServerRole = Qt::UserRole+3, NodeNumRole = Qt::UserRole+4,
+ InfoRole = Qt::UserRole+5, LoadRole = Qt::UserRole+6,
+ ConnectionRole = Qt::UserRole+7, ServerDataRole = Qt::UserRole+8,
+ NodeDataRole = Qt::UserRole+9, AttributeRole = Qt::UserRole+10,
+ AttributeLineRole = Qt::UserRole+11, AbortedReasonRole = Qt::UserRole + 12,
+ NodeTypeRole = Qt::UserRole + 13, NodeTypeForegroundRole = Qt::UserRole + 14,
+ ServerPointerRole = Qt::UserRole + 15};
+
+ void dataIsAboutToChange();
+ virtual VInfo_ptr nodeInfo(const QModelIndex& index)=0;
+ void reload();
+ void active(bool);
+ bool active() const {return active_;}
+
+ virtual VModelData* data() const = 0;
+ virtual QModelIndex infoToIndex(VInfo_ptr,int column=0) const;
+ virtual QModelIndex nodeToIndex(const VNode*,int column=0) const=0;
+
+Q_SIGNALS:
+ void changed();
+ void filterChanged();
+ void rerender();
+
+public Q_SLOTS:
+ void slotFilterDeleteBegin();
+ void slotFilterDeleteEnd();
+
+ virtual void slotServerAddBegin(int row)=0;
+ virtual void slotServerAddEnd()=0;
+ virtual void slotServerRemoveBegin(VModelServer*,int)=0;
+ virtual void slotServerRemoveEnd(int)=0;
+
+ virtual void slotDataChanged(VModelServer*)=0;
+ virtual void slotBeginServerScan(VModelServer* server,int)=0;
+ virtual void slotEndServerScan(VModelServer* server,int)=0;
+ virtual void slotBeginServerClear(VModelServer* server,int)=0;
+ virtual void slotEndServerClear(VModelServer* server,int)=0;
+
+protected:
+ void init();
+ void clean();
+ bool hasData() const;
+
+ virtual void resetStateFilter(bool broadcast) {}
+ virtual QModelIndex serverToIndex(ServerHandler*) const=0;
+
+ bool active_;
+};
+
+#endif
diff --git a/Viewer/src/AbstractSearchLine.cpp b/Viewer/src/AbstractSearchLine.cpp
new file mode 100644
index 0000000..295d499
--- /dev/null
+++ b/Viewer/src/AbstractSearchLine.cpp
@@ -0,0 +1,208 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include <QtGlobal>
+#include <QShortcut>
+#include <QMenu>
+#include <QShowEvent>
+#include "AbstractSearchLine.hpp"
+#include "IconProvider.hpp"
+
+AbstractSearchLine::AbstractSearchLine(QWidget* parent) :
+ QWidget(parent),
+ confirmSearch_(false)
+{
+ setupUi(this);
+
+ confirmSearchLabel_->hide();
+ confirmSearchLabel_->setShowTypeTitle(false);
+
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ searchLine_->setPlaceholderText(tr("Find"));
+ label_->hide();
+#endif
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
+ searchLine_->setClearButtonEnabled(true);
+#endif
+
+ connect(searchLine_, SIGNAL(textChanged(QString)),
+ this, SLOT(slotFind(QString)));
+
+ connect(searchLine_, SIGNAL( returnPressed()),
+ this, SLOT(slotFindNext()));
+
+ connect(actionNext_,SIGNAL(triggered()),
+ this, SLOT(slotFindNext()));
+
+ connect(actionPrev_,SIGNAL(triggered()),
+ this, SLOT(slotFindPrev()));
+
+ connect(closeTb_,SIGNAL(clicked()),
+ this, SLOT(slotClose()));
+
+ nextTb_->setDefaultAction(actionNext_);
+ prevTb_->setDefaultAction(actionPrev_);
+
+ oriColour_=QColor(searchLine_->palette().color(QPalette::Base));
+ redColour_=QColor(247,230,230);
+ greenColour_=QColor(186,249,206);
+
+ // for the 'find next' functionality, although Qt (at the time of writing) uses
+ // both F3 and CTRL-G for most platforms, this is not true for Linux. Therefore,
+ // we have to add CTRL-G ourselves.
+
+ QKeySequence ctrlg(tr("Ctrl+G"));
+ QShortcut *shortcut = new QShortcut(ctrlg, parent); // should be destroyed by parent
+ connect(shortcut, SIGNAL(activated()), this, SLOT(slotFindNext()));
+
+ status_=true;
+
+ setFocusProxy(searchLine_);
+
+ // set the menu on the Options toolbutton
+ caseSensitive_ = false;
+ wholeWords_ = false;
+ highlightAll_ = false;
+ QMenu *menu=new QMenu(this);
+ menu->addAction(actionCaseSensitive_);
+ menu->addAction(actionWholeWords_);
+ menu->addAction(actionHighlightAll_);
+ optionsTb_->setMenu(menu);
+
+ matchModeCb_->setMatchMode(StringMatchMode::ContainsMatch); // set the default match mode
+ //matchModeChanged(1); // dummy call to initialise the 'whole words' option state
+
+ setConfirmSearch(false);
+}
+
+AbstractSearchLine::~AbstractSearchLine()
+{
+}
+
+void AbstractSearchLine::clear()
+{
+ //clearRequested();
+ searchLine_->clear();
+}
+
+bool AbstractSearchLine::isEmpty()
+{
+ return searchLine_->text().isEmpty();
+}
+
+void AbstractSearchLine::selectAll()
+{
+ searchLine_->selectAll();
+}
+
+void AbstractSearchLine::toDefaultState()
+{
+ QPalette p=searchLine_->palette();
+ p.setColor(QPalette::Base,oriColour_);
+ searchLine_->setPalette(p);
+}
+
+void AbstractSearchLine::updateButtons(bool found)
+{
+ status_=found;
+
+ if(searchLine_->text().isEmpty())
+ {
+ QPalette p=searchLine_->palette();
+ p.setColor(QPalette::Base,oriColour_);
+ searchLine_->setPalette(p);
+ }
+ else
+ {
+ if(!found)
+ {
+ QPalette p=searchLine_->palette();
+ p.setColor(QPalette::Base,redColour_);
+ searchLine_->setPalette(p);
+ }
+ else
+ {
+ QPalette p=searchLine_->palette();
+ p.setColor(QPalette::Base,greenColour_);
+ searchLine_->setPalette(p);
+ }
+ }
+}
+
+void AbstractSearchLine::slotClose()
+{
+ hide();
+}
+
+void AbstractSearchLine::on_actionCaseSensitive__toggled(bool b)
+{
+ caseSensitive_ = b;
+}
+
+void AbstractSearchLine::on_actionWholeWords__toggled(bool b)
+{
+ wholeWords_ = b;
+}
+
+void AbstractSearchLine::on_actionHighlightAll__toggled(bool b)
+{
+ highlightAll_ = b;
+}
+
+void AbstractSearchLine::setConfirmSearch(bool confirmSearch)
+{
+ confirmSearch_=confirmSearch;
+ //confirmSearchLabel_->setVisible(confirmSearch_);
+
+ if(confirmSearch_)
+ {
+ //confirmSearchLabel_->showWarning("Large file mode");
+ if(searchLine_->text().isEmpty())
+ {
+ status_=false;
+ toDefaultState();
+ }
+
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ searchLine_->setPlaceholderText(tr("Find (you need to hit enter to start search)"));
+#endif
+ }
+ else
+ {
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ searchLine_->setPlaceholderText(tr("Find"));
+#endif
+ }
+
+ searchLine_->setToolTip(confirmSearchText());
+}
+
+QString AbstractSearchLine::confirmSearchText() const
+{
+ return (confirmSearch_)?
+ "Search works in <b>large file mode</b>. After typing in the search term <b>press enter</b> or use the arrows to start search!":
+ "Search works in <b> continuous mode</b>. As you type in a new character the search starts immediately.";
+
+}
+
+void AbstractSearchLine::hideEvent(QHideEvent* event)
+{
+ QWidget::hideEvent(event);
+ Q_EMIT visibilityChanged();
+}
+
+void AbstractSearchLine::showEvent(QShowEvent* event)
+{
+ QWidget::showEvent(event);
+ if(!event->spontaneous())
+ slotFind(searchLine_->text());
+ //refreshSearch();
+ Q_EMIT visibilityChanged();
+}
diff --git a/Viewer/src/AbstractSearchLine.hpp b/Viewer/src/AbstractSearchLine.hpp
new file mode 100644
index 0000000..d8531b1
--- /dev/null
+++ b/Viewer/src/AbstractSearchLine.hpp
@@ -0,0 +1,66 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef ABSTRACTSEARCHLINE_HPP_
+#define ABSTRACTSEARCHLINE_HPP_
+
+#include "ui_SearchLineWidget.h"
+
+#include <QWidget>
+
+class AbstractSearchLine : public QWidget, protected Ui::SearchLineWidget
+{
+ Q_OBJECT
+
+public:
+ explicit AbstractSearchLine(QWidget *parent=0);
+ virtual ~AbstractSearchLine();
+ virtual void clear();
+ virtual bool isEmpty();
+ void selectAll();
+ void setConfirmSearch(bool);
+ bool confirmSearch() const {return confirmSearch_;}
+ QString confirmSearchText() const;
+
+ bool caseSensitive() {return caseSensitive_;}
+ bool wholeWords() {return wholeWords_;}
+ bool highlightAll() {return highlightAll_;}
+
+public Q_SLOTS:
+ virtual void slotFind(QString)=0;
+ virtual void slotFindNext()=0;
+ virtual void slotFindPrev()=0;
+ virtual void slotClose();
+ virtual void on_actionCaseSensitive__toggled(bool);
+ virtual void on_actionWholeWords__toggled(bool);
+ virtual void on_actionHighlightAll__toggled(bool);
+
+Q_SIGNALS:
+ void visibilityChanged();
+
+protected:
+ void updateButtons(bool);
+ void toDefaultState();
+ void hideEvent(QHideEvent* event);
+ void showEvent(QShowEvent* event);
+
+ bool status_;
+ bool caseSensitive_;
+ bool wholeWords_;
+ bool highlightAll_;
+ StringMatchMode matchMode_;
+
+ QColor oriColour_;
+ QColor redColour_;
+ QColor greenColour_;
+
+ bool confirmSearch_;
+};
+
+#endif
diff --git a/Viewer/src/AbstractTextEditSearchInterface.cpp b/Viewer/src/AbstractTextEditSearchInterface.cpp
new file mode 100644
index 0000000..906ed0a
--- /dev/null
+++ b/Viewer/src/AbstractTextEditSearchInterface.cpp
@@ -0,0 +1,25 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "AbstractTextEditSearchInterface.hpp"
+
+#include "VConfig.hpp"
+#include "VProperty.hpp"
+
+QColor AbstractTextEditSearchInterface::highlightColour_=QColor(200, 255, 200);
+
+AbstractTextEditSearchInterface::AbstractTextEditSearchInterface()
+{
+ if(VProperty *p=VConfig::instance()->find("panel.search.highlightColour"))
+ {
+ highlightColour_=p->value().value<QColor>();
+ }
+}
+
diff --git a/Viewer/src/AbstractTextEditSearchInterface.hpp b/Viewer/src/AbstractTextEditSearchInterface.hpp
new file mode 100644
index 0000000..b18d34c
--- /dev/null
+++ b/Viewer/src/AbstractTextEditSearchInterface.hpp
@@ -0,0 +1,39 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VIEWER_SRC_ABSTRACTTEXTEDITSEARCHINTERFACE_HPP_
+#define VIEWER_SRC_ABSTRACTTEXTEDITSEARCHINTERFACE_HPP_
+
+#include "StringMatchMode.hpp"
+
+#include <QColor>
+#include <QTextDocument>
+
+class AbstractTextEditSearchInterface
+{
+public:
+ AbstractTextEditSearchInterface();
+ virtual ~AbstractTextEditSearchInterface() {};
+
+ virtual bool findString (QString str, bool highlightAll, QTextDocument::FindFlags findFlags,
+ bool gotoStartOfWord, int iteration,StringMatchMode::Mode matchMode)=0;
+ virtual void automaticSearchForKeywords(bool)=0;
+ virtual void refreshSearch()=0;
+ virtual void clearHighlights()=0;
+ virtual void disableHighlights()=0;
+ virtual void enableHighlights()=0;
+ virtual bool highlightsNeedSearch()=0;
+
+protected:
+ static QColor highlightColour_;
+};
+
+
+#endif /* VIEWER_SRC_ABSTRACTTEXTEDITSEARCHINTERFACE_HPP_ */
diff --git a/Viewer/src/ActionHandler.cpp b/Viewer/src/ActionHandler.cpp
new file mode 100644
index 0000000..09d1b33
--- /dev/null
+++ b/Viewer/src/ActionHandler.cpp
@@ -0,0 +1,205 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include <algorithm>
+
+#include "ActionHandler.hpp"
+
+#include <QtGlobal>
+#include <QAction>
+#include <QClipboard>
+#include <QMenu>
+#include <QMessageBox>
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+#include <QGuiApplication>
+#else
+#include <QApplication>
+#endif
+
+#include "Str.hpp"
+#include "ServerHandler.hpp"
+#include "MenuHandler.hpp"
+#include "CustomCommandDialog.hpp"
+#include "UserMessage.hpp"
+
+#define _UI_ACTIONHANDLER_DEBUG
+
+ActionHandler::ActionHandler(QWidget *view) : QObject(view), parent_(view)
+{
+ connect(this,SIGNAL(viewCommand(VInfo_ptr,QString)),
+ parent_,SLOT(slotViewCommand(VInfo_ptr,QString)));
+
+ connect(this,SIGNAL(infoPanelCommand(VInfo_ptr,QString)),
+ parent_,SIGNAL(infoPanelCommand(VInfo_ptr,QString)));
+
+ connect(this,SIGNAL(dashboardCommand(VInfo_ptr,QString)),
+ parent_,SIGNAL(dashboardCommand(VInfo_ptr,QString)));
+
+ //makeShortcut();
+}
+
+void ActionHandler::contextMenu(std::vector<VInfo_ptr> nodesLst,QPoint pos)
+{
+ std::string view=parent_->property("view").toString().toStdString();
+ MenuItem* item=MenuHandler::invokeMenu("Node", nodesLst,pos, parent_,view);
+
+ if(item)
+ {
+
+#ifdef _UI_ACTIONHANDLER_DEBUG
+ UserMessage::debug("ActionHandler::contextMenu --> item=" + item->name());
+#endif
+ if(item->handler() == "info_panel")
+ {
+ Q_EMIT infoPanelCommand(nodesLst.at(0),QString::fromStdString(item->command()));
+ return;
+ }
+ else if(item->handler() == "dashboard")
+ {
+ Q_EMIT dashboardCommand(nodesLst.at(0),QString::fromStdString(item->command()));
+ return;
+ }
+ else if(item->handler() == "tree")
+ {
+ Q_EMIT viewCommand(nodesLst.at(0),QString::fromStdString(item->command()));
+ return;
+ }
+
+ /*if(action->iconText() == "Set as root")
+ {
+ //Q_EMIT viewCommand(nodesLst,"set_as_root");
+ }*/
+ else if(item->command() == "copy")
+ {
+ QString txt;
+ for(std::vector<VInfo_ptr>::const_iterator it=nodesLst.begin(); it != nodesLst.end(); ++it)
+ {
+ if(*it)
+ {
+ if(!txt.isEmpty())
+ txt+=",";
+ txt+=QString::fromStdString((*it)->path());
+ }
+ }
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+ QClipboard* cb=QGuiApplication::clipboard();
+ cb->setText(txt, QClipboard::Clipboard);
+ cb->setText(txt, QClipboard::Selection);
+#else
+ QClipboard* cb=QApplication::clipboard();
+ cb->setText(txt, QClipboard::Clipboard);
+ cb->setText(txt, QClipboard::Selection);
+#endif
+ }
+
+ else if(item->command() == "custom") // would expect this to be 'Custom...' but it's just 'Custom'
+ {
+ CustomCommandDialog customCommandDialog(0);
+ customCommandDialog.setNodes(nodesLst);
+ if (customCommandDialog.exec() == QDialog::Accepted)
+ {
+ // the user could have changed the node selection within the custom editor
+ std::vector<VInfo_ptr> selectedNodes = customCommandDialog.selectedNodes();
+
+ // send the command to the server
+ ServerHandler::command(selectedNodes, customCommandDialog.command().toStdString());
+ }
+ }
+ else
+ {
+ bool ok=true;
+ if(item && !item->question().empty() && item->shouldAskQuestion(nodesLst))
+ {
+ std::string fullNames("<ul>");
+ std::string nodeNames("<ul>");
+ if (nodesLst.size() == 1)
+ {
+ fullNames = nodesLst[0]->path();
+ nodeNames = "<b>" + nodesLst[0]->name() + "</b>";
+ }
+ else
+ {
+ int numNodes = nodesLst.size();
+ int numItemsToList = std::min(numNodes, 5);
+
+ for(int i=0; i < numItemsToList; i++)
+ {
+ fullNames += "<li><b>";
+ fullNames += nodesLst[i]->path();
+ fullNames += "</b></li>";
+
+ nodeNames += "<li><b>";
+ nodeNames += nodesLst[i]->name();
+ nodeNames += "</b></li>";
+ }
+ if(numItemsToList < nodesLst.size())
+ {
+ std::string numExtra = QString::number(numNodes-numItemsToList).toStdString();
+
+ fullNames += "<b>...and " + numExtra + " more </b></li>";
+ nodeNames += "<b>...and " + numExtra + " more </b></li>";
+ }
+ fullNames += "</ul>";
+ nodeNames += "</ul>";
+ }
+
+ std::string question(item->question());
+
+ std::string placeholder("<full_name>");
+ ecf::Str::replace_all(question, placeholder, fullNames);
+ placeholder = "<node_name>";
+ ecf::Str::replace_all(question, placeholder, nodeNames);
+
+ QMessageBox msgBox;
+ msgBox.setText(QString::fromStdString(question));
+ msgBox.setTextFormat(Qt::RichText);
+ msgBox.setIcon(QMessageBox::Question);
+ msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
+ if (msgBox.exec() == QMessageBox::Cancel)
+ {
+ ok=false;
+ }
+ }
+
+ if(ok)
+ ServerHandler::command(nodesLst,item->command());
+ //ServerHandler::command(nodesLst,action->iconText().toStdString(), true);
+ }
+ }
+
+/*
+ QMenu *menu=new QMenu(parent_);
+
+ QList<QAction*> acLst;
+
+ QAction *ac=new QAction("Requeue",parent_);
+ acLst << ac;
+
+ ac=new QAction("Submit",parent_);
+ acLst << ac;
+
+ ac=new QAction("Set as root",parent_);
+ acLst << ac;
+
+ if(QAction* res=QMenu::exec(acLst,pos,0,parent_))
+ {
+
+ if(res->iconText() == "Set as root")
+ {
+ emit viewCommand(nodesLst,"set_as_root");
+ }
+ else
+ ServerHandler::command(nodesLst,res->iconText().toStdString());
+ }
+
+ delete menu;
+*/
+}
diff --git a/Viewer/src/ActionHandler.hpp b/Viewer/src/ActionHandler.hpp
new file mode 100644
index 0000000..4aab7b4
--- /dev/null
+++ b/Viewer/src/ActionHandler.hpp
@@ -0,0 +1,42 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef ACTIONHANDLER_HPP_
+#define ACTIONHANDLER_HPP_
+
+#include <QPoint>
+#include <QObject>
+
+#include <vector>
+
+#include "VInfo.hpp"
+
+class QWidget;
+class Node;
+class ServerHandler;
+
+class ActionHandler : public QObject
+{
+Q_OBJECT
+public:
+ explicit ActionHandler(QWidget*);
+
+ void contextMenu(std::vector<VInfo_ptr>,QPoint);
+Q_SIGNALS:
+ void viewCommand(VInfo_ptr,QString);
+ void infoPanelCommand(VInfo_ptr,QString);
+ void dashboardCommand(VInfo_ptr,QString);
+
+protected:
+ QWidget *parent_;
+
+};
+
+#endif
diff --git a/Viewer/src/Animation.cpp b/Viewer/src/Animation.cpp
new file mode 100644
index 0000000..2fb6a86
--- /dev/null
+++ b/Viewer/src/Animation.cpp
@@ -0,0 +1,113 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "Animation.hpp"
+#include "ServerHandler.hpp"
+#include "VNode.hpp"
+
+#include <QWidget>
+
+//=====================================================
+//
+// Animation
+//
+//=====================================================
+
+Animation::Animation(QWidget *view,Type type) :
+ view_(view),
+ type_(type)
+{
+ if(type_ == ServerLoadType)
+ setFileName(":/viewer/spinning_wheel.gif");
+
+ setScaledSize(QSize(12,12));
+
+ connect(this,SIGNAL(frameChanged(int)),
+ this,SLOT(renderFrame(int)));
+
+ connect(this,SIGNAL(repaintRequest(Animation*)),
+ view_,SLOT(slotRepaint(Animation*)));
+}
+
+void Animation::addTarget(VNode *n)
+{
+ Q_ASSERT(n);
+ if(!targets_.contains(n))
+ targets_ << n;
+
+ ServerHandler* s=n->server();
+ Q_ASSERT(s);
+ s->addServerObserver(this);
+
+ start();
+}
+
+void Animation::removeTarget(VNode* n)
+{
+ targets_.removeAll(n);
+
+ if(targets_.isEmpty())
+ QMovie::stop();
+}
+
+void Animation::renderFrame(int frame)
+{
+ if(targets_.isEmpty())
+ QMovie::stop();
+
+ Q_EMIT(repaintRequest(this));
+}
+
+void Animation::notifyServerDelete(ServerHandler* server)
+{
+ removeTarget(server->vRoot());
+ server->removeServerObserver(this);
+ //TODO: make it work for nodes as well
+}
+
+void Animation::notifyBeginServerClear(ServerHandler* /*server*/)
+{
+ //TODO: make it work for nodes
+}
+
+//=====================================================
+//
+// AnimationHandler
+//
+//=====================================================
+
+AnimationHandler::AnimationHandler(QWidget* view) : view_(view)
+{
+
+}
+
+AnimationHandler::~AnimationHandler()
+{
+ Q_FOREACH(Animation* an,items_)
+ {
+ delete an;
+ }
+}
+
+Animation* AnimationHandler::find(Animation::Type type, bool makeIt)
+{
+ QMap<Animation::Type,Animation*>::iterator it=items_.find(type);
+ if(it != items_.end())
+ {
+ return it.value();
+ }
+ else if(makeIt)
+ {
+ Animation* an=new Animation(view_,type);
+ items_[type]=an;
+ return an;
+ }
+
+ return 0;
+}
diff --git a/Viewer/src/Animation.hpp b/Viewer/src/Animation.hpp
new file mode 100644
index 0000000..95eff6b
--- /dev/null
+++ b/Viewer/src/Animation.hpp
@@ -0,0 +1,62 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef ANIMATION_HPP_
+#define ANIMATION_HPP_
+
+#include <QMap>
+#include <QMovie>
+#include <QModelIndex>
+
+#include "ServerObserver.hpp"
+#include "VNode.hpp"
+
+class VNode;
+
+class Animation : public QMovie, public ServerObserver
+{
+Q_OBJECT
+
+public:
+ enum Type {ServerLoadType};
+ Animation(QWidget*,Type);
+
+ void addTarget(VNode*);
+ void removeTarget(VNode*);
+ QList<VNode*> targets() const {return targets_;}
+
+ void notifyDefsChanged(ServerHandler* server, const std::vector<ecf::Aspect::Type>& a) {}
+ void notifyServerDelete(ServerHandler* server);
+ void notifyBeginServerClear(ServerHandler* server);
+
+Q_SIGNALS:
+ void repaintRequest(Animation*);
+
+protected Q_SLOTS:
+ void renderFrame(int);
+
+protected:
+ QWidget* view_;
+ QList<VNode*> targets_;
+ Type type_;
+};
+
+class AnimationHandler
+{
+public:
+ explicit AnimationHandler(QWidget* view);
+ ~AnimationHandler();
+ Animation* find(Animation::Type,bool makeIt);
+
+protected:
+ QWidget* view_;
+ QMap<Animation::Type,Animation*> items_;
+};
+
+#endif
diff --git a/Viewer/src/AttributeEditor.cpp b/Viewer/src/AttributeEditor.cpp
new file mode 100644
index 0000000..49d58a5
--- /dev/null
+++ b/Viewer/src/AttributeEditor.cpp
@@ -0,0 +1,359 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "AttributeEditor.hpp"
+
+#include "AttributeEditorFactory.hpp"
+#include "ConnectState.hpp"
+#include "VAttribute.hpp"
+#include "VAttributeType.hpp"
+#include "ServerHandler.hpp"
+#include "UserMessage.hpp"
+#include "VConfig.hpp"
+#include "VRepeat.hpp"
+
+#include <QPushButton>
+
+#define _USE_MODELESS_ATTRIBUTEDITOR
+#define _UI_ATTRIBUTEDITOR_DEBUG
+
+#ifdef _USE_MODELESS_ATTRIBUTEDITOR
+static QList<AttributeEditor*> editors;
+#endif
+
+AttributeEditor::AttributeEditor(VInfo_ptr info,QString type,QWidget* parent) : QDialog(parent), info_(info), type_(type), form_(0)
+{
+ setupUi(this);
+ setAttribute(Qt::WA_DeleteOnClose);
+
+#ifdef _USE_MODELESS_ATTRIBUTEDITOR
+ setModal(false);
+#endif
+
+ Q_ASSERT(info_ && info_->isAttribute() && info_->attribute());
+ messageLabel_->hide();
+
+ QString wt="Edit " + type;
+ wt+=" - " + QString::fromStdString(VConfig::instance()->appLongName());
+ setWindowTitle(wt);
+
+ attachInfo();
+
+ connect(buttonBox_,SIGNAL(clicked(QAbstractButton*)),
+ this,SLOT(slotButton(QAbstractButton*)));
+}
+
+AttributeEditor::~AttributeEditor()
+{
+#ifdef _UI_ATTRIBUTEDITOR_DEBUG
+ UserMessage::debug("AttributeEditor::~AttributeEditor -->");
+#endif
+ detachInfo();
+#ifdef _USE_MODELESS_ATTRIBUTEDITOR
+ editors.removeOne(this);
+#endif
+}
+
+void AttributeEditor::edit(VInfo_ptr info,QWidget *parent)
+{
+ Q_ASSERT(info && info->isAttribute() && info->attribute());
+ VAttribute* a=info->attribute();
+ Q_ASSERT(a->type());
+
+#ifdef _USE_MODELESS_ATTRIBUTEDITOR
+ Q_FOREACH(AttributeEditor* e,editors)
+ {
+ if((e->info_ && info) &&
+ *(e->info_.get()) == *(info.get()))
+ {
+ e->raise();
+ return;
+ }
+ }
+#endif
+
+ //For repeats we create an editor for each type
+ std::string typeStr=a->type()->strName();
+ if(a->type()->name() == "repeat")
+ {
+ typeStr+="_" + VRepeat::type(info->node());
+ }
+
+ //The edtior will be automatically deleted on close (Qt::WA_DeleteOnClose is set)
+ if(AttributeEditor* e=AttributeEditorFactory::create(typeStr,info,0))
+ {
+#ifdef _USE_MODELESS_ATTRIBUTEDITOR
+ editors << e;
+ e->show();
+#else
+ e->exec();
+#endif
+ }
+}
+
+void AttributeEditor::addForm(QWidget* w)
+{
+ form_=w;
+ mainLayout_->insertWidget(3,w,1);
+}
+
+void AttributeEditor::accept()
+{
+ apply();
+ QDialog::accept();
+}
+
+void AttributeEditor::attachInfo()
+{
+#ifdef _UI_ATTRIBUTEDITOR_DEBUG
+ UserMessage::debug("AttributeEditor::attachInfo -->");
+#endif
+
+ if(info_)
+ {
+ if(info_->server())
+ {
+ info_->server()->addNodeObserver(this);
+ info_->server()->addServerObserver(this);
+ }
+
+ info_->addObserver(this);
+ }
+
+#ifdef _UI_ATTRIBUTEDITOR_DEBUG
+ UserMessage::debug("<-- AttributeEditor::attachInfo");
+#endif
+}
+
+void AttributeEditor::detachInfo()
+{
+#ifdef _UI_ATTRIBUTEDITOR_DEBUG
+ UserMessage::debug("AttributeEditor::detachInfo -->");
+#endif
+ if(info_)
+ {
+ if(info_->server())
+ {
+#ifdef _UI_ATTRIBUTEDITOR_DEBUG
+ UserMessage::debug(" remove NodeObserver");
+#endif
+ info_->server()->removeNodeObserver(this);
+#ifdef _UI_ATTRIBUTEDITOR_DEBUG
+ UserMessage::debug(" remove ServerObserver");
+#endif
+ info_->server()->removeServerObserver(this);
+ }
+#ifdef _UI_ATTRIBUTEDITOR_DEBUG
+ UserMessage::debug(" remove InfoObserver");
+#endif
+ info_->removeObserver(this);
+ }
+
+ messageLabel_->stopLoadLabel();
+
+#ifdef _UI_ATTRIBUTEDITOR_DEBUG
+ UserMessage::debug("<-- AttributeEditor::detachInfo");
+#endif
+}
+
+void AttributeEditor::slotButton(QAbstractButton* b)
+{
+ if(b && buttonBox_->buttonRole(b) == QDialogButtonBox::ResetRole)
+ resetValue();
+}
+
+void AttributeEditor::checkButtonStatus()
+{
+ setResetStatus(isValueChanged());
+}
+
+void AttributeEditor::setResetStatus(bool st)
+{
+ QPushButton *resetpb=buttonBox_->button(QDialogButtonBox::Reset);
+ Q_ASSERT(resetpb);
+ resetpb->setEnabled(st);
+}
+
+void AttributeEditor::setSuspended(bool st)
+{
+ UserMessage::qdebug("AttributeEditor::setSuspended --> " + QString::number(st));
+
+ Q_ASSERT(form_);
+ form_->setEnabled(!st);
+
+ QPushButton *okPb=buttonBox_->button(QDialogButtonBox::Ok);
+ Q_ASSERT(okPb);
+ okPb->setEnabled(!st);
+
+ QPushButton *resetPb=buttonBox_->button(QDialogButtonBox::Reset);
+ Q_ASSERT(resetPb);
+ resetPb->setEnabled(!st);
+}
+
+void AttributeEditor::notifyDataLost(VInfo* info)
+{
+#ifdef _UI_ATTRIBUTEDITOR_DEBUG
+ UserMessage::debug("AttributeEditor::notifyDataLost -->");
+#endif
+ if(info_ && info_.get() == info)
+ {
+ detachInfo();
+ messageLabel_->showWarning("The parent node and the edited " + type_ + " <b>is not available</b> anymore! Please close the dialog!");
+ setSuspended(true);
+ }
+#ifdef _UI_ATTRIBUTEDITOR_DEBUG
+ UserMessage::debug("<-- AttributeEditor::notifyDataLost");
+#endif
+}
+
+void AttributeEditor::notifyBeginNodeChange(const VNode* vn, const std::vector<ecf::Aspect::Type>& aspect,const VNodeChange&)
+{
+#ifdef _UI_ATTRIBUTEDITOR_DEBUG
+ UserMessage::debug("AttributeEditor::notifyBeginNodeChange -->");
+#endif
+ if(info_ && info_->node() && info_->node() == vn)
+ {
+ bool attrNumCh=(std::find(aspect.begin(),aspect.end(),ecf::Aspect::ADD_REMOVE_ATTR) != aspect.end());
+ if(attrNumCh)
+ {
+#ifdef _UI_ATTRIBUTEDITOR_DEBUG
+ UserMessage::debug(" ADD_REMOVE_ATTR");
+#endif
+ VAttribute* a=info_->attribute();
+ Q_ASSERT(a);
+ if(!a->isValid(info_->node()))
+ {
+#ifdef _UI_ATTRIBUTEDITOR_DEBUG
+ UserMessage::debug(" attribute does not exist");
+#endif
+ detachInfo();
+ messageLabel_->showWarning("The edited " + type_ + " <b>is not available</b> any more! Please close the dialog!");
+ setSuspended(true);
+ }
+ }
+ else
+ {
+ //TODO: figure ot what to do when the edited attribute changed
+ }
+ }
+#ifdef _UI_ATTRIBUTEDITOR_DEBUG
+ UserMessage::debug("<-- AttributeEditor::notifyBeginNodeChange");
+#endif
+}
+
+void AttributeEditor::notifyDefsChanged(ServerHandler* server, const std::vector<ecf::Aspect::Type>& a)
+{
+ if(info_ && info_->server() && info_->server() == server)
+ {
+ //TODO: implement
+
+ }
+}
+
+void AttributeEditor::notifyServerDelete(ServerHandler* server)
+{
+#ifdef _UI_ATTRIBUTEDITOR_DEBUG
+ UserMessage::debug("AttributeEditor::notifyServerDelete -->");
+#endif
+ if(info_ && info_->server() == server)
+ {
+ detachInfo();
+ messageLabel_->showWarning("Server <b>" + QString::fromStdString(server->name()) + "</b> was removed from ecFlowUI! The edited " + type_ + " <b>is not available</b> anymore! Please close the dialog!");
+ setSuspended(true);
+ }
+#ifdef _UI_ATTRIBUTEDITOR_DEBUG
+ UserMessage::debug("<-- AttributeEditor::notifyServerDelete");
+#endif
+}
+
+//This must be called at the beginning of a reset
+void AttributeEditor::notifyBeginServerClear(ServerHandler* server)
+{
+#ifdef _UI_ATTRIBUTEDITOR_DEBUG
+ UserMessage::debug("AttributeEditor::notifyBeginServerClear -->");
+#endif
+
+ if(info_)
+ {
+ if(info_->server() && info_->server() == server)
+ {
+ messageLabel_->showWarning("Server <b>" + QString::fromStdString(server->name()) + "</b> is being reloaded. \
+ Until it is finished this " + type_ + " <b>cannot be modified</b>!");
+
+ messageLabel_->startLoadLabel();
+
+ setSuspended(true);
+ checkButtonStatus();
+ }
+ }
+
+#ifdef _UI_ATTRIBUTEDITOR_DEBUG
+ UserMessage::debug("<-- AttributeEditor::notifyBeginServerClear");
+#endif
+}
+
+//This must be called at the end of a reset
+void AttributeEditor::notifyEndServerScan(ServerHandler* server)
+{
+#ifdef _UI_ATTRIBUTEDITOR_DEBUG
+ UserMessage::debug("AttributeEditor::notifyEndServerScan -->");
+#endif
+
+ if(info_)
+ {
+ if(info_->server() && info_->server() == server)
+ {
+ messageLabel_->hide();
+ messageLabel_->clear();
+
+ //We try to ressurect the info. We have to do it explicitly because it is not guaranteed
+ //that notifyEndServerScan() will be first called on the VInfo then on the InfoPanel. So it
+ //is possible that the node exists but is still set to NULL in VInfo.
+ info_->regainData();
+
+ //If the node is not available dataLost() was already called.
+ if(!info_)
+ return;
+
+ Q_ASSERT(info_->server() && info_->node());
+
+ setSuspended(false);
+ }
+ }
+
+#ifdef _UI_ATTRIBUTEDITOR_DEBUG
+ UserMessage::debug("<-- AttributeEditor::notifyEndServerScan");
+#endif
+}
+
+void AttributeEditor::notifyServerConnectState(ServerHandler* server)
+{
+ Q_ASSERT(server);
+ if(info_->server() && info_->server() == server)
+ {
+ switch(server->connectState()->state())
+ {
+ case ConnectState::Lost:
+ messageLabel_->showWarning("Connection lost to server <b>" + QString::fromStdString(server->name()) + "</b>. \
+ Until it the connection regained this " + type_ + " <b>cannot be modified</b>!");
+ messageLabel_->stopLoadLabel();
+ setSuspended(true);
+ break;
+ case ConnectState::Normal:
+ messageLabel_->hide();
+ messageLabel_->clear();
+ messageLabel_->stopLoadLabel();
+ setSuspended(false);
+ break;
+ default:
+ break;
+ }
+ }
+}
diff --git a/Viewer/src/AttributeEditor.hpp b/Viewer/src/AttributeEditor.hpp
new file mode 100644
index 0000000..250293c
--- /dev/null
+++ b/Viewer/src/AttributeEditor.hpp
@@ -0,0 +1,72 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef ATTRIBUTEEDITOR_HPP
+#define ATTRIBUTEEDITOR_HPP
+
+#include <QDialog>
+
+#include "NodeObserver.hpp"
+#include "ServerObserver.hpp"
+#include "VInfo.hpp"
+
+#include "ui_AttributeEditorDialog.h"
+
+class AttributeEditor : public QDialog, public ServerObserver, public NodeObserver, public VInfoObserver, protected Ui::AttributeEditorDialog
+{
+Q_OBJECT
+
+public:
+ AttributeEditor(VInfo_ptr info,QString type,QWidget* parent);
+ virtual ~AttributeEditor();
+
+ //From VInfoObserver
+ void notifyDelete(VInfo*) {}
+ void notifyDataLost(VInfo*);
+
+ //From NodeObserver
+ void notifyBeginNodeChange(const VNode* vn, const std::vector<ecf::Aspect::Type>& a,const VNodeChange&);
+ void notifyEndNodeChange(const VNode* vn, const std::vector<ecf::Aspect::Type>& a,const VNodeChange&) {}
+
+ //From ServerObserver
+ void notifyDefsChanged(ServerHandler* server, const std::vector<ecf::Aspect::Type>& a);
+ void notifyServerDelete(ServerHandler* server);
+ void notifyBeginServerClear(ServerHandler* server);
+ void notifyEndServerClear(ServerHandler* server) {}
+ void notifyBeginServerScan(ServerHandler* server,const VServerChange&) {}
+ void notifyEndServerScan(ServerHandler* server);
+ void notifyServerConnectState(ServerHandler* server);
+ void notifyServerSuiteFilterChanged(ServerHandler* server) {}
+ void notifyServerSyncFinished(ServerHandler* server) {}
+
+ static void edit(VInfo_ptr info,QWidget *parent);
+
+public Q_SLOTS:
+ void accept();
+ void slotButton(QAbstractButton*);
+
+protected:
+ void attachInfo();
+ void detachInfo();
+ void checkButtonStatus();
+ void setResetStatus(bool st);
+ void setSuspended(bool);
+ void addForm(QWidget* w);
+ void hideForm();
+ virtual void apply()=0;
+ virtual void resetValue()=0;
+ virtual bool isValueChanged()=0;
+
+ VInfo_ptr info_;
+ QWidget* form_;
+ QString type_;
+};
+
+#endif // ATTRIBUTEEDITOR_HPP
diff --git a/Viewer/src/AttributeEditorDialog.ui b/Viewer/src/AttributeEditorDialog.ui
new file mode 100644
index 0000000..3401dcf
--- /dev/null
+++ b/Viewer/src/AttributeEditorDialog.ui
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>AttributeEditorDialog</class>
+ <widget class="QDialog" name="AttributeEditorDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>275</width>
+ <height>171</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Edit label</string>
+ </property>
+ <property name="modal">
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" name="mainLayout_" stretch="0,0,0,0,0">
+ <property name="topMargin">
+ <number>4</number>
+ </property>
+ <item>
+ <widget class="EditorInfoLabel" name="header_">
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::NoTextInteraction</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="MessageLabel" name="messageLabel_" native="true"/>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>6</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>6</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox_">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Reset</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>EditorInfoLabel</class>
+ <extends>QLabel</extends>
+ <header>EditorInfoLabel.hpp</header>
+ </customwidget>
+ <customwidget>
+ <class>MessageLabel</class>
+ <extends>QWidget</extends>
+ <header>MessageLabel.hpp</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox_</sender>
+ <signal>accepted()</signal>
+ <receiver>AttributeEditorDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>257</x>
+ <y>218</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>227</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox_</sender>
+ <signal>rejected()</signal>
+ <receiver>AttributeEditorDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>274</x>
+ <y>218</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>283</x>
+ <y>227</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/Viewer/src/AttributeEditorFactory.cpp b/Viewer/src/AttributeEditorFactory.cpp
new file mode 100644
index 0000000..db1a5de
--- /dev/null
+++ b/Viewer/src/AttributeEditorFactory.cpp
@@ -0,0 +1,37 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "AttributeEditorFactory.hpp"
+
+#include <map>
+
+static std::map<std::string,AttributeEditorFactory*>* makers = 0;
+
+AttributeEditorFactory::AttributeEditorFactory(const std::string& type)
+{
+ if(makers == 0)
+ makers = new std::map<std::string,AttributeEditorFactory*>;
+
+ (*makers)[type] = this;
+}
+
+AttributeEditorFactory::~AttributeEditorFactory()
+{
+ // Not called
+}
+
+AttributeEditor* AttributeEditorFactory::create(const std::string& type,VInfo_ptr info,QWidget* parent)
+{
+ std::map<std::string,AttributeEditorFactory*>::iterator j = makers->find(type);
+ if(j != makers->end())
+ return (*j).second->make(info,parent);
+
+ return 0;
+}
diff --git a/Viewer/src/AttributeEditorFactory.hpp b/Viewer/src/AttributeEditorFactory.hpp
new file mode 100644
index 0000000..08714c2
--- /dev/null
+++ b/Viewer/src/AttributeEditorFactory.hpp
@@ -0,0 +1,42 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef ATTRIBUTEEDITORFACTORY_HPP
+#define ATTRIBUTEEDITORFACTORY_HPP
+
+#include <string>
+#include "VInfo.hpp"
+
+class AttributeEditor;
+class QWidget;
+
+class AttributeEditorFactory
+{
+public:
+ explicit AttributeEditorFactory(const std::string& type);
+ virtual ~AttributeEditorFactory();
+
+ virtual AttributeEditor* make(VInfo_ptr,QWidget*) = 0;
+ static AttributeEditor* create(const std::string&,VInfo_ptr,QWidget*);
+
+private:
+ explicit AttributeEditorFactory(const AttributeEditorFactory&);
+ AttributeEditorFactory& operator=(const AttributeEditorFactory&);
+};
+
+template<class T>
+class AttributeEditorMaker : public AttributeEditorFactory
+{
+ AttributeEditor* make(VInfo_ptr info,QWidget* parent) { return new T(info,parent); }
+public:
+ explicit AttributeEditorMaker(const std::string& t) : AttributeEditorFactory(t) {}
+};
+
+#endif // ATTRIBUTEEDITORFACTORY_HPP
diff --git a/Viewer/src/AttributeSearchPanel.cpp b/Viewer/src/AttributeSearchPanel.cpp
new file mode 100644
index 0000000..dc5f57d
--- /dev/null
+++ b/Viewer/src/AttributeSearchPanel.cpp
@@ -0,0 +1,365 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "AttributeSearchPanel.hpp"
+
+#include "CaseSensitiveButton.hpp"
+#include "NodeQuery.hpp"
+#include "StringMatchCombo.hpp"
+
+#include <QtGlobal>
+#include <QDebug>
+#include <QGridLayout>
+#include <QLabel>
+#include <QLineEdit>
+#include <QVariant>
+
+#include <assert.h>
+
+//======================================================
+//
+// AttributeLineDesc
+//
+//======================================================
+
+class AttrLineDesc
+{
+public:
+ AttrLineDesc(QString name,int row) : name_(name), row_(row) {}
+ virtual ~AttrLineDesc() {}
+
+ virtual QString value()=0;
+ QString name() const {return name_;}
+ int row() const {return row_;}
+
+protected:
+ QString name_;
+ int row_;
+};
+
+class AttrLineStringDesc : public AttrLineDesc
+{
+public:
+ AttrLineStringDesc(QString name,int row,QLineEdit *le) : AttrLineDesc(name,row), le_(le) {}
+
+ QString value() {return le_->text();}
+
+protected:
+ QLineEdit* le_;
+};
+
+
+//======================================================
+//
+// AttributeGroupDesc
+//
+//======================================================
+
+class AttrGroupDesc
+{
+public:
+ AttrGroupDesc(QString name,QGridLayout* grid) : name_(name), grid_(grid) {}
+
+ QString query() const;
+ void hide();
+ void show();
+ void add(AttrLineDesc* line) {lines_ << line;}
+
+protected:
+ QString name_;
+ QList<AttrLineDesc*> lines_;
+ QGridLayout* grid_;
+};
+
+QString AttrGroupDesc::query() const
+{
+ QString q;
+ Q_FOREACH(AttrLineDesc* line, lines_)
+ {
+ QString s=line->value();
+ if(!s.isEmpty())
+ {
+ if(!q.isEmpty())
+ q+=" or ";
+ q+=line->name() + " =\'" + s + "\'";
+ }
+ }
+
+ if(q.isEmpty())
+ q=name_;
+
+ return q;
+}
+
+void AttrGroupDesc::hide()
+{
+ Q_FOREACH(AttrLineDesc* item,lines_)
+ {
+ int row=item->row();
+ for(int i=0; i < grid_->columnCount(); i++)
+ {
+ if(QLayoutItem *li=grid_->itemAtPosition(row,i))
+ {
+ if(li->widget())
+ {
+ li->widget()->hide();
+ }
+ }
+ }
+ }
+}
+
+void AttrGroupDesc::show()
+{
+ Q_FOREACH(AttrLineDesc* item,lines_)
+ {
+ int row=item->row();
+ for(int i=0; i < grid_->columnCount(); i++)
+ {
+ if(QLayoutItem *li=grid_->itemAtPosition(row,i))
+ {
+ if(li->widget())
+ {
+ li->widget()->show();
+ }
+ }
+ }
+ }
+}
+
+//======================================================
+//
+// AttributeSearchPanel
+//
+//======================================================
+
+AttributeSearchPanel::AttributeSearchPanel(QWidget* parent) :
+ QWidget(parent),
+ query_(NULL)
+{
+ //setupUi(this);
+
+ QVBoxLayout* vb=new QVBoxLayout;
+ setLayout(vb);
+
+ grid_=new QGridLayout();
+ vb->addLayout(grid_);
+
+ //Build groups
+ //QStringList attGroupNames;
+ //attGroupNames << "date" << "event" << "label" << "late" << "limit" << "limiter" << "meter"
+ // << "repeat" << "time" << "trigger" << "variable";
+
+ Q_FOREACH(QString grName,NodeQuery::attrGroupTerms())
+ {
+ AttrGroupDesc* gr=new AttrGroupDesc(grName,grid_);
+ groups_[grName]=gr;
+
+ Q_FOREACH(QString name,NodeQuery::attrTerms(grName))
+ {
+ QString label=name;
+ addStringLine(label,name,grName);
+ }
+ }
+
+ /*
+
+ //Populate groups
+ addStringLine("Date name","date_name","date");
+ addStringLine("Event name","event_name","event");
+ //addStringLine("Date name","date_name","date");
+ addStringLine("Label name","label_name","label");
+ addStringLine("Label value","label_value","label");
+ addStringLine("Late name","late_name","late");
+ addStringLine("Limit name","limit_name","limit");
+ addStringLine("Limit value","limit_value","limit");
+ addStringLine("Limit max","limit_max","limit");
+ addStringLine("Limiter name","limiter_name","limiter");
+ addStringLine("Meter name","meter_name","meter");
+ addStringLine("Repeat name","repeat_name","repeat");
+ addStringLine("Repeat value","repeat_value","repeat");
+ addStringLine("Time name","time_name","time");
+ addStringLine("Trigger expression","trigger_expression","trigger");
+ addStringLine("Variable name","variable_name","variable");
+ addStringLine("Variable value","variable_value","variable");
+*/
+ //Initialise lines
+ QMapIterator<QString,AttrGroupDesc*> it(groups_);
+ while (it.hasNext())
+ {
+ it.next();
+ it.value()->hide();
+ }
+ hide();
+}
+
+AttributeSearchPanel::~AttributeSearchPanel()
+{
+ QMapIterator<QString,AttrGroupDesc*> it(groups_);
+ while (it.hasNext())
+ {
+ it.next();
+ delete it.value();
+ }
+}
+
+void AttributeSearchPanel::setQuery(NodeQuery* query)
+{
+ query_=query;
+}
+
+
+
+void AttributeSearchPanel::addStringLine(QString labelTxt,QString text,QString group)
+{
+ QLabel *label=new QLabel(labelTxt + ":",this);
+ QLineEdit* le=new QLineEdit(this);
+ StringMatchCombo *matchCb=new StringMatchCombo(this);
+ CaseSensitiveButton* caseTb=new CaseSensitiveButton(this);
+
+ le->setProperty("id",text);
+ matchCb->setProperty("id",text);
+ caseTb->setProperty("id",text);
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
+ le->setClearButtonEnabled(true);
+#endif
+
+ int row=grid_->rowCount();
+ grid_->addWidget(label,row,0);
+ grid_->addWidget(le,row,1);
+ grid_->addWidget(matchCb,row,2);
+ grid_->addWidget(caseTb,row,3);
+
+ connect(le,SIGNAL(textEdited(QString)),
+ this,SLOT(slotTextEdited(QString)));
+
+ connect(matchCb,SIGNAL(currentIndexChanged(int)),
+ this,SLOT(slotMatchChanged(int)));
+
+ connect(caseTb,SIGNAL(changed(bool)),
+ this,SLOT(slotCaseChanged(bool)));
+
+ AttrLineStringDesc* line=new AttrLineStringDesc(text,row,le);
+
+ QMap<QString,AttrGroupDesc*>::iterator it=groups_.find(group);
+ assert(it != groups_.end());
+ it.value()->add(line);
+}
+
+void AttributeSearchPanel::setSelection(QStringList lst)
+{
+ if(lst == selection_)
+ return;
+
+ QMapIterator<QString,AttrGroupDesc*> it(groups_);
+ while (it.hasNext())
+ {
+ it.next();
+ bool inNew=lst.contains(it.key());
+ bool inCurrent=selection_.contains(it.key());
+
+ if(inNew && !inCurrent)
+ {
+ it.value()->show();
+ }
+ else if(!inNew && inCurrent)
+ {
+ it.value()->hide();
+ }
+ }
+
+ if(lst.isEmpty())
+ hide();
+ else
+ show();
+
+ selection_=lst;
+
+ buildQuery();
+}
+
+void AttributeSearchPanel::clearSelection()
+{
+ setSelection(QStringList());
+}
+
+void AttributeSearchPanel::slotTextEdited(QString val)
+{
+ if(QLineEdit *le=static_cast<QLineEdit*>(sender()))
+ {
+ QString id=le->property("id").toString();
+ if(NodeQueryStringOption *op=query_->stringOption(id))
+ {
+ op->setValue(val);
+ }
+ }
+
+ buildQuery();
+}
+
+void AttributeSearchPanel::slotMatchChanged(int val)
+{
+ if(StringMatchCombo *cb=static_cast<StringMatchCombo*>(sender()))
+ {
+ QString id=cb->property("id").toString();
+ if(NodeQueryStringOption *op=query_->stringOption(id))
+ {
+ op->setMatchMode(cb->currentMatchMode());
+ }
+ }
+
+ buildQuery();
+}
+
+void AttributeSearchPanel::slotCaseChanged(bool val)
+{
+ if(CaseSensitiveButton *tb=static_cast<CaseSensitiveButton*>(sender()))
+ {
+ QString id=tb->property("id").toString();
+ if(NodeQueryStringOption *op=query_->stringOption(id))
+ {
+ op->setCaseSensitive(val);
+ }
+ }
+
+ buildQuery();
+}
+
+
+void AttributeSearchPanel::buildQuery()
+{
+ /*query_.clear();
+
+ QMapIterator<QString,AttrGroupDesc*> it(groups_);
+ while (it.hasNext())
+ {
+ it.next();
+ QString name=it.key();
+ if(selection_.contains(name))
+ {
+ if(!query_.isEmpty())
+ query_+=" or ";
+ query_+=it.value()->query();
+ }
+ }
+
+ Q_EMIT queryChanged();*/
+}
+
+QStringList AttributeSearchPanel::groupNames() const
+{
+ return groups_.keys();
+}
+
+void AttributeSearchPanel::init()
+{
+}
+
diff --git a/Viewer/src/AttributeSearchPanel.hpp b/Viewer/src/AttributeSearchPanel.hpp
new file mode 100644
index 0000000..bc0e158
--- /dev/null
+++ b/Viewer/src/AttributeSearchPanel.hpp
@@ -0,0 +1,56 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+#ifndef VIEWER_SRC_ATTRIBUTESEARCHPANEL_HPP_
+#define VIEWER_SRC_ATTRIBUTESEARCHPANEL_HPP_
+
+#include <QMap>
+#include <QWidget>
+
+class QGridLayout;
+class QStandardItemModel;
+class AttrGroupDesc;
+class NodeQuery;
+
+class AttributeSearchPanel : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit AttributeSearchPanel(QWidget *parent = 0);
+ ~AttributeSearchPanel();
+ //QString query() const {return query_;}
+ QStringList groupNames() const;
+ void setQuery(NodeQuery*);
+ void init();
+
+public Q_SLOTS:
+ void buildQuery();
+ void setSelection(QStringList);
+ void clearSelection();
+
+protected Q_SLOTS:
+ void slotTextEdited(QString);
+ void slotMatchChanged(int);
+ void slotCaseChanged(bool);
+
+Q_SIGNALS:
+ void queryChanged();
+
+private:
+ void addStringLine(QString labelTxt,QString text,QString group);
+
+ NodeQuery* query_;
+ QMap<QString,AttrGroupDesc*> groups_;
+ QGridLayout* grid_;
+ QStringList selection_;
+
+};
+
+#endif /* VIEWER_SRC_ATTRIBUTESEARCHPANEL_HPP_ */
diff --git a/Viewer/src/AttributeView.hpp b/Viewer/src/AttributeView.hpp
new file mode 100644
index 0000000..9aa8f3d
--- /dev/null
+++ b/Viewer/src/AttributeView.hpp
@@ -0,0 +1,9 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
diff --git a/Viewer/src/CMakeLists.txt b/Viewer/src/CMakeLists.txt
new file mode 100644
index 0000000..388e1d6
--- /dev/null
+++ b/Viewer/src/CMakeLists.txt
@@ -0,0 +1,414 @@
+
+set(viewer_srcs
+ ViewerMain.cpp
+ AboutDialog.cpp
+ AbstractNodeModel.cpp
+ AbstractSearchLine.cpp
+ AbstractTextEditSearchInterface.cpp
+ ActionHandler.cpp
+ Animation.cpp
+ AttributeEditor.cpp
+ AttributeEditorFactory.cpp
+ AttributeSearchPanel.cpp
+ CaseSensitiveButton.cpp
+ ChangeNotify.cpp
+ ChangeNotifyDialog.cpp
+ ChangeNotifyEditor.cpp
+ ChangeNotifyModel.cpp
+ ChangeNotifyWidget.cpp
+ CodeItemWidget.cpp
+ ConnectState.cpp
+ ComboMulti.cpp
+ CommandDesignerWidget.cpp
+ ConfigListDelegate.cpp
+ CustomCommandDialog.cpp
+ CustomCommandHandler.cpp
+ CustomListWidget.cpp
+ CustomTabWidget.cpp
+ Dashboard.cpp
+ DashboardDialog.cpp
+ DashboardDock.cpp
+ DashboardTitle.cpp
+ DashboardWidget.hpp
+ DirectoryHandler.cpp
+ EditItemWidget.cpp
+ EditProvider.cpp
+ EditorInfoLabel.cpp
+ ExpandState.cpp
+ FlagSet.hpp
+ FileInfoLabel.cpp
+ FileWatcher.cpp
+ FilterWidget.cpp
+ GotoLineDialog.cpp
+ Highlighter.cpp
+ HistoryItemWidget.cpp
+ IconProvider.cpp
+ InfoPanel.cpp
+ InfoPanelItem.cpp
+ InfoPanelHandler.cpp
+ InfoProvider.cpp
+ JobItemWidget.cpp
+ LabelEditor.cpp
+ LimitEditor.cpp
+ LineEdit.cpp
+ LogEvent.cpp
+ LogModel.cpp
+ LogProvider.cpp
+ LogServer.cpp
+ MainWindow.cpp
+ ManualItemWidget.cpp
+ MenuConfigDialog.cpp
+ MenuHandler.cpp
+ MessageLabel.cpp
+ MessageItemWidget.cpp
+ MeterEditor.cpp
+ ModelColumn.cpp
+ NodeExpression.cpp
+ NodeFilterDialog.cpp
+ NodePanel.cpp
+ NodePathWidget.cpp
+ NodeQuery.cpp
+ NodeQueryCombo.cpp
+ NodeQueryEditor.cpp
+ NodeQueryEngine.cpp
+ NodeQueryHandler.cpp
+ NodeQueryResult.cpp
+ NodeQueryResultModel.cpp
+ NodeQueryResultView.cpp
+ NodeQueryViewDelegate.cpp
+ NodeSearchDialog.cpp
+ NodeSearchWidget.cpp
+ NodeViewBase.cpp
+ NodeViewDelegate.cpp
+ NodeWidget.cpp
+ OneLineTextEdit.cpp
+ OutputBrowser.cpp
+ OutputCache.cpp
+ OutputClient.cpp
+ OutputFetchInfo.cpp
+ OutputFileClient.cpp
+ OutputDirClient.cpp
+ OutputModel.cpp
+ OutputItemWidget.cpp
+ OutputFileProvider.cpp
+ OutputDirProvider.cpp
+ OverviewItemWidget.cpp
+ OverviewProvider.cpp
+ Palette.cpp
+ PlainTextEdit.cpp
+ PlainTextSearchLine.cpp
+ PlainTextSearchInterface.cpp
+ PropertyDialog.cpp
+ PropertyEditor.cpp
+ PropertyLine.cpp
+ PropertyMapper.cpp
+ RepeatEditor.cpp
+ SaveSessionAsDialog.cpp
+ ScriptItemWidget.cpp
+ ServerComQueue.cpp
+ ServerComThread.cpp
+ ServerDefsAccess.cpp
+ ServerHandler.cpp
+ ServerFilter.cpp
+ ServerItem.cpp
+ ServerList.cpp
+ ServerListDialog.cpp
+ ServerSettingsItemWidget.cpp
+ SessionDialog.cpp
+ SessionRenameDialog.cpp
+ SessionHandler.cpp
+ Sound.cpp
+ StringMatchCombo.cpp
+ StringMatchMode.cpp
+ SuiteItemWidget.cpp
+ SuiteFilter.cpp
+ SuiteFilterObserver.hpp
+ SuiteModel.cpp
+ TabWidget.cpp
+ TableFilterWidget.cpp
+ TableNodeModel.cpp
+ TableNodeSortModel.cpp
+ TableNodeView.cpp
+ TableNodeViewDelegate.cpp
+ TableNodeWidget.cpp
+ TextEditSearchLine.cpp
+ TimeItemWidget.cpp
+ TriggerItemWidget.cpp
+ TreeNodeModel.cpp
+ TreeNodeView.cpp
+ TreeNodeViewDelegate.cpp
+ TreeNodeWidget.cpp
+ TreeView.cpp
+ TriggerView.cpp
+ UpdateTimer.cpp
+ UserMessage.cpp
+ VAttribute.cpp
+ VAttributeType.cpp
+ VConfig.cpp
+ VDir.cpp
+ VFilter.cpp
+ VIcon.cpp
+ VInfo.cpp
+ VFile.cpp
+ VFileInfo.cpp
+ VModelData.cpp
+ VNode.cpp
+ VNodeList.cpp
+ VNState.cpp
+ VParam.cpp
+ VProperty.cpp
+ VRepeat.cpp
+ VReply.cpp
+ VServerSettings.cpp
+ VSettings.cpp
+ VSState.cpp
+ VTask.cpp
+ VTaskNode.cpp
+ VTree.cpp
+ VariableModel.cpp
+ VariableModelData.cpp
+ VariableItemWidget.cpp
+ VariableSearchLine.cpp
+ VariableView.cpp
+ VConfigLoader.cpp
+ WhyItemWidget.cpp
+ ZombieItemWidget.cpp
+ ZombieModel.cpp
+ TextPager/TextPagerCursor.cpp
+ TextPager/TextPagerDocument.cpp
+ TextPager/TextPagerEdit.cpp
+ TextPager/TextPagerLayout_p.cpp
+ TextPager/TextPagerSearchHighlighter.cpp
+ TextPager/TextPagerSearchInterface.cpp
+ TextPager/TextPagerSection.cpp
+ TextPager/TextPagerWidget.cpp
+ TextPager/syntaxhighlighter.cpp)
+
+if(ECFLOW_QT5)
+ include_directories(${ECFLOW_QT_INCLUDE_DIR})
+else()
+ include(${QT_USE_FILE})
+ set(ECFLOW_QT_LIBRARIES ${QT_LIBRARIES})
+endif()
+
+
+set(viewer_moc_files AbstractNodeModel.hpp
+ AbstractSearchLine.hpp
+ ActionHandler.hpp
+ Animation.hpp
+ AttributeEditor.hpp
+ AttributeSearchPanel.hpp
+ CaseSensitiveButton.hpp
+ ChangeNotifyDialog.hpp
+ ChangeNotifyEditor.hpp
+ ChangeNotifyModel.hpp
+ ChangeNotifyWidget.hpp
+ ComboMulti.hpp
+ CommandDesignerWidget.hpp
+ CodeItemWidget.hpp
+ CustomCommandDialog.hpp
+ CustomListWidget.hpp
+ Dashboard.hpp
+ DashboardDialog.hpp
+ DashboardDock.hpp
+ DashboardTitle.hpp
+ DashboardWidget.hpp
+ EditItemWidget.hpp
+ FileWatcher.hpp
+ FilterWidget.hpp
+ GotoLineDialog.hpp
+ HistoryItemWidget.hpp
+ InfoPanel.hpp
+ LabelEditor.hpp
+ LimitEditor.hpp
+ LineEdit.hpp
+ LogProvider.hpp
+ MainWindow.hpp
+ MenuConfigDialog.hpp
+ MeterEditor.hpp
+ NodeFilterDialog.hpp
+ NodePanel.hpp
+ NodePathWidget.hpp
+ NodeQueryCombo.hpp
+ NodeQueryEditor.hpp
+ NodeQueryEngine.hpp
+ NodeQueryResult.hpp
+ NodeQueryResultModel.hpp
+ NodeQueryResultView.hpp
+ NodeSearchDialog.hpp
+ NodeSearchWidget.hpp
+ NodeWidget.hpp
+ OneLineTextEdit.hpp
+ OutputBrowser.hpp
+ OutputCache.hpp
+ OutputClient.hpp
+ OutputFileClient.hpp
+ OutputDirClient.hpp
+ OutputItemWidget.hpp
+ OutputFileProvider.hpp
+ OutputDirProvider.hpp
+ PlainTextEdit.hpp
+ PropertyDialog.hpp
+ PropertyEditor.hpp
+ PropertyLine.hpp
+ SaveSessionAsDialog.hpp
+ RepeatEditor.hpp
+ ServerComQueue.hpp
+ ServerComThread.hpp
+ ServerHandler.hpp
+ ServerListDialog.hpp
+ ServerSettingsItemWidget.hpp
+ SessionDialog.hpp
+ SessionRenameDialog.hpp
+ StringMatchCombo.hpp
+ SuiteItemWidget.hpp
+ TabWidget.hpp
+ TableFilterWidget.hpp
+ TableNodeModel.hpp
+ TableNodeView.hpp
+ TableNodeViewDelegate.hpp
+ TableNodeWidget.hpp
+ TextEditSearchLine.hpp
+ TreeNodeModel.hpp
+ TreeNodeView.hpp
+ TreeNodeViewDelegate.hpp
+ TreeNodeWidget.hpp
+ VariableItemWidget.hpp
+ VariableModel.hpp
+ VariableModelData.hpp
+ VariableSearchLine.hpp
+ VFilter.hpp
+ VModelData.hpp
+ VNodeList.hpp
+ ZombieItemWidget.hpp
+ TextPager/TextPagerCursor_p.hpp
+ TextPager/TextPagerDocument.hpp
+ TextPager/TextPagerDocument_p.hpp
+ TextPager/TextPagerEdit.hpp
+ TextPager/TextPagerEdit_p.hpp
+ TextPager/TextPagerSection_p.hpp
+ TextPager/TextPagerWidget.hpp
+ TextPager/syntaxhighlighter.hpp
+)
+
+set(viewer_wrap_ui_files
+ AboutDialog.ui
+ AttributeEditorDialog.ui
+ ChangeNotifyDialog.ui
+ ChangeNotifyDialogWidget.ui
+ ChangeNotifyEditor.ui
+ CommandDesignerWidget.ui
+ CustomCommandDialog.ui
+ CodeItemWidget.ui
+ DashboardDialog.ui
+ DashboardDockTitleWidget.ui
+ EditItemWidget.ui
+ GotoLineDialog.ui
+ HistoryItemWidget.ui
+ InfoPanel.ui
+ LabelEditorWidget.ui
+ LimitEditorWidget.ui
+ MainWindow.ui
+ MessageItemWidget.ui
+ MenuConfigDialog.ui
+ MeterEditorWidget.ui
+ NodeFilterDialog.ui
+ NodeQueryEditor.ui
+ NodeQuerySaveDialog.ui
+ NodeSearchDialog.ui
+ NodeSearchWidget.ui
+ OutputItemWidget.ui
+ PropertyDialog.ui
+ PropertyEditor.ui
+ RepeatEditorWidget.ui
+ SaveSessionAsDialog.ui
+ SearchLineWidget.ui
+ ServerAddDialog.ui
+ ServerEditDialog.ui
+ ServerListDialog.ui
+ ServerSettingsItemWidget.ui
+ SessionDialog.ui
+ SessionRenameDialog.ui
+ SuiteItemWidget.ui
+ TableFilterWidget.ui
+ TableNodeWidget.ui
+ TimeItemWidget.ui
+ TreeNodeWidget.ui
+ TriggerItemWidget.ui
+ VariableAddDialog.ui
+ VariablePropDialog.ui
+ VariableItemWidget.ui
+ ZombieItemWidget.ui
+)
+
+if(ECFLOW_QT5)
+ QT5_WRAP_CPP(VIEWER_MOC ${viewer_moc_files} )
+ QT5_ADD_RESOURCES (VIEWER_RES viewer.qrc)
+ QT5_WRAP_UI (VIEWER_FORMS_HEADERS ${viewer_wrap_ui_files})
+else()
+ QT4_WRAP_CPP(VIEWER_MOC ${viewer_moc_files} )
+ QT4_ADD_RESOURCES (VIEWER_RES viewer.qrc)
+ QT4_WRAP_UI (VIEWER_FORMS_HEADERS ${viewer_wrap_ui_files})
+endif()
+
+
+# add all the images as dependencies of the resource file so that it is
+# automatically recompiled when an image changes
+file( GLOB image_files "${CMAKE_CURRENT_SOURCE_DIR}/../images/*.*" )
+ADD_CUSTOM_TARGET(Qt_resource_cpp DEPENDS ${VIEWER_RES})
+ADD_DEPENDENCIES(Qt_resource_cpp ${image_files})
+
+
+
+add_definitions( -DECFLOW_SHARED_DIR="${CMAKE_INSTALL_PREFIX}/share/ecflow" )
+
+
+ecbuild_add_executable( TARGET ecflow_ui.x
+ SOURCES ${viewer_srcs} ${VIEWER_MOC} ${VIEWER_RES} ${VIEWER_FORMS_HEADERS}
+ INCLUDES .
+ ../../ACore/src
+ ../../ANattr/src
+ ../../ANode/src
+ ../../ANode/test
+ ../../Base/src
+ ../../Base/src/cts
+ ../../Base/src/stc
+ ../../Client/src
+ TextPager
+ ${Boost_INCLUDE_DIRS}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ LIBS core nodeattr node libparser base libclient
+ pthread
+ m crypt dl fl
+ ${ECFLOW_QT_LIBRARIES}
+)
+
+# This ensures that for debug config, we only link with debug boost libs, for other configs, we link with optimised boost libs
+target_link_libraries(ecflow_ui.x debug ${Boost_REGEX_LIBRARY_DEBUG} ${Boost_REGEX_LIBRARY_RELEASE} )
+
+
+set(build_ecflow_ui_log 0)
+
+if(${build_ecflow_ui_log})
+ list(REMOVE_ITEM viewer_srcs ViewerMain.cpp)
+ ecbuild_add_executable( TARGET ecflow_ui_log
+ SOURCES LogEvent.cpp
+ ${viewer_srcs} ${VIEWER_MOC} ${VIEWER_RES} ${VIEWER_FORMS_HEADERS}
+ INCLUDES .
+ ../../ACore/src
+ ../../ANattr/src
+ ../../ANode/src
+ ../../ANode/test
+ ../../Base/src
+ ../../Base/src/cts
+ ../../Base/src/stc
+ ../../Client/src
+ ${Boost_INCLUDE_DIRS}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ LIBS core nodeattr node libparser base libclient
+ pthread
+ m
+ ${ECFLOW_QT_LIBRARIES}
+ DEFINITIONS MAIN_LOG
+ )
+endif()
diff --git a/Viewer/src/CaseSensitiveButton.cpp b/Viewer/src/CaseSensitiveButton.cpp
new file mode 100644
index 0000000..cbebbe3
--- /dev/null
+++ b/Viewer/src/CaseSensitiveButton.cpp
@@ -0,0 +1,32 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "CaseSensitiveButton.hpp"
+
+CaseSensitiveButton::CaseSensitiveButton(QWidget *parent) : QToolButton(parent)
+{
+ connect(this,SIGNAL(clicked(bool)),
+ this,SLOT(slotClicked(bool)));
+
+ setCheckable(true);
+ setIcon(QPixmap(":/viewer/case_sensitive.svg"));
+
+ tooltip_[true]=tr("Case sensitivity is <b>on</b>. Toggle to turn it off.");
+ tooltip_[false]=tr("Case sensitivity is <b>off</b>. Toggle to turn it on.");
+
+ setToolTip(tooltip_[false]);
+}
+
+void CaseSensitiveButton::slotClicked(bool b)
+{
+ setToolTip(tooltip_[b]);
+ Q_EMIT changed(b);
+}
+
diff --git a/Viewer/src/CaseSensitiveButton.hpp b/Viewer/src/CaseSensitiveButton.hpp
new file mode 100644
index 0000000..279644d
--- /dev/null
+++ b/Viewer/src/CaseSensitiveButton.hpp
@@ -0,0 +1,35 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VIEWER_SRC_CASESENSITIVEBUTTON_HPP_
+#define VIEWER_SRC_CASESENSITIVEBUTTON_HPP_
+
+#include <QToolButton>
+
+#include <map>
+
+class CaseSensitiveButton : public QToolButton
+{
+Q_OBJECT
+
+public:
+ explicit CaseSensitiveButton(QWidget* parent=0);
+
+protected Q_SLOTS:
+ void slotClicked(bool);
+
+Q_SIGNALS:
+ void changed(bool);
+
+private:
+ std::map<bool,QString> tooltip_;
+};
+
+#endif /* VIEWER_SRC_CASESENSITIVEBUTTON_HPP_ */
diff --git a/ecbuild/bamboo/flags.cmake b/Viewer/src/ChangeManagerAccess
similarity index 100%
rename from ecbuild/bamboo/flags.cmake
rename to Viewer/src/ChangeManagerAccess
diff --git a/Viewer/src/ChangeNotify.cpp b/Viewer/src/ChangeNotify.cpp
new file mode 100644
index 0000000..31d0c6e
--- /dev/null
+++ b/Viewer/src/ChangeNotify.cpp
@@ -0,0 +1,400 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "ChangeNotify.hpp"
+
+#include "ChangeNotifyDialog.hpp"
+#include "ChangeNotifyModel.hpp"
+#include "ChangeNotifyWidget.hpp"
+#include "Sound.hpp"
+#include "UserMessage.hpp"
+#include "VConfig.hpp"
+#include "VConfigLoader.hpp"
+#include "VNode.hpp"
+#include "VNodeList.hpp"
+#include "VProperty.hpp"
+
+#include <stdlib.h>
+
+//#ifdef ECFLOW_QT5
+//#include <QSoundEffect>
+//#endif
+
+#include <QDebug>
+#include <QSortFilterProxyModel>
+
+#include <map>
+
+static std::map<std::string,ChangeNotify*> items;
+
+static AbortedNotify abortedNotify("aborted");
+static ChangeNotify restaredtNotify("restarted");
+static ChangeNotify lateNotify("late");
+static ChangeNotify zombieNotify("zombie");
+static ChangeNotify aliasNotify("alias");
+
+ChangeNotifyDialog* ChangeNotify::dialog_=0;
+
+//==============================================
+//
+// ChangeNotify
+//
+//==============================================
+
+ChangeNotify::ChangeNotify(const std::string& id) :
+ id_(id),
+ enabled_(false),
+ data_(0),
+ model_(0),
+ proxyModel_(0),
+ prop_(0)
+{
+ data_=new VNodeList();
+ model_=new ChangeNotifyModel();
+ model_->setData(data_);
+
+ proxyModel_=new QSortFilterProxyModel();
+ proxyModel_->setSourceModel(model_);
+ //proxyModel_->setFilterFixedString("1");
+ //proxyModel_->setFilterKeyColumn(0);
+ proxyModel_->setDynamicSortFilter(true);
+
+ items[id] = this;
+}
+
+ChangeNotifyModel* ChangeNotify::model() const
+{
+ return model_; //proxyModel_;
+}
+
+void ChangeNotify::add(VNode *node,bool popup,bool sound)
+{
+ data_->add(node);
+ //proxyModel_->invalidate();
+
+ if(popup)
+ {
+ dialog()->setCurrentTab(this);
+ dialog()->show();
+ dialog()->raise();
+ }
+ else
+ {
+ if(!dialog()->isVisible())
+ dialog()->setCurrentTab(this);
+ else
+ dialog()->raise();
+ }
+
+ if(sound)
+ {
+ bool sys=true;
+ std::string fName;
+ int loop=0;
+ if(VProperty* p=prop_->findChild("sound_file_type"))
+ {
+ sys=(p->value() == "system");
+ }
+
+ if(sys)
+ {
+ if(VProperty* p=prop_->findChild("sound_system_file"))
+ {
+ fName=p->valueAsString();
+ }
+ }
+
+ if(fName.empty())
+ return;
+
+ if(VProperty* p=prop_->findChild("sound_loop"))
+ {
+ loop=p->value().toInt();
+ }
+
+ if(sys)
+ {
+ Sound::instance()->playSystem(fName,loop);
+ }
+
+ }
+}
+
+void ChangeNotify::remove(VNode *node)
+{
+ data_->remove(node);
+}
+
+void ChangeNotify::setEnabled(bool en)
+{
+ enabled_=en;
+
+ if(!enabled_)
+ {
+ data_->clear();
+ }
+
+ proxyModel_->invalidate();
+
+ if(dialog_)
+ {
+ dialog()->setEnabledTab(this,en);
+ }
+
+ ChangeNotifyWidget::setEnabled(id_,en);
+}
+
+void ChangeNotify::setProperty(VProperty* prop)
+{
+ prop_=prop;
+
+ if(VProperty* p=prop->findChild("fill_colour"))
+ p->addObserver(this);
+
+ if(VProperty* p=prop->findChild("text_colour"))
+ p->addObserver(this);
+
+ if(VProperty* p=prop->findChild("count_fill_colour"))
+ p->addObserver(this);
+
+ if(VProperty* p=prop->findChild("count_text_colour"))
+ p->addObserver(this);
+
+ if(VProperty* p=prop->findChild("sound_file_type"))
+ p->addObserver(this);
+
+ if(VProperty* p=prop->findChild("sound_system_file"))
+ {
+ p->addObserver(this);
+
+ QStringList lst;
+ const std::vector<std::string>& vals=Sound::instance()->sysSounds();
+ for(std::vector<std::string>::const_iterator it=vals.begin(); it != vals.end(); it++)
+ {
+ lst << QString::fromStdString(*it);
+ }
+ p->setParam("values",lst.join("/"));
+ p->setParam("values_label",lst.join("/"));
+ p->setParam("dir",QString::fromStdString(Sound::instance()->sysDir()));
+ p->addObserver(this);
+ }
+
+ if(VProperty* p=prop->findChild("sound_user_file"))
+ p->addObserver(this);
+
+ if(VProperty* p=prop->findChild("sound_volume"))
+ p->addObserver(this);
+
+ if(VProperty* p=prop->findChild("sound_loop"))
+ p->addObserver(this);
+}
+
+void ChangeNotify::notifyChange(VProperty* prop)
+{
+ if(prop->name().contains("sound",Qt::CaseInsensitive))
+ return;
+
+ if(prop->name() == "max_item_num")
+ {
+ data_->setMaxNum(prop->value().toInt());
+ }
+
+ dialog()->updateSettings(this);
+ ChangeNotifyWidget::updateSettings(id_);
+}
+
+void ChangeNotify::clearData()
+{
+ data_->clear();
+ //proxyModel_->invalidate();
+}
+
+void ChangeNotify::showDialog()
+{
+ dialog()->setCurrentTab(this);
+ dialog()->show();
+ dialog()->raise();
+}
+
+
+//-----------------------------------
+//
+// Static methods
+//
+//-----------------------------------
+
+void ChangeNotify::add(const std::string& id,VNode *node,bool popup,bool sound)
+{
+ if(ChangeNotify* obj=ChangeNotify::find(id))
+ {
+ obj->add(node,popup,sound);
+ }
+}
+
+void ChangeNotify::remove(const std::string& id,VNode *node)
+{
+ if(ChangeNotify* obj=ChangeNotify::find(id))
+ {
+ obj->remove(node);
+ }
+}
+
+void ChangeNotify::setEnabled(const std::string& id,bool en)
+{
+ if(ChangeNotify* obj=ChangeNotify::find(id))
+ {
+ obj->setEnabled(en);
+ }
+}
+
+ChangeNotify* ChangeNotify::find(const std::string& id)
+{
+ std::map<std::string,ChangeNotify*>::iterator it=items.find(id);
+ if(it != items.end())
+ return it->second;
+
+ return 0;
+}
+
+void ChangeNotify::load(VProperty* group)
+{
+ if(group->name() == "notification")
+ {
+ UserMessage::message(UserMessage::DBG, false,"ChangeNotify:load() -- > notification");
+
+ for(int i=0; i < group->children().size(); i++)
+ {
+ VProperty *p=group->children().at(i);
+ if(ChangeNotify* obj=ChangeNotify::find(p->strName()))
+ {
+ obj->setProperty(p);
+ }
+ }
+
+ //This should be observed by each notification object
+ if(VProperty* p=group->find("notification.settings.max_item_num"))
+ {
+ for(std::map<std::string,ChangeNotify*>::iterator it=items.begin(); it != items.end(); ++it)
+ {
+ p->addObserver(it->second);
+ it->second->data_->setMaxNum(p->value().toInt());
+ }
+ }
+ }
+ else if(group->name() == "server")
+ {
+ for(std::map<std::string,ChangeNotify*>::iterator it=items.begin(); it != items.end(); ++it)
+ {
+ it->second->loadServerSettings();
+ }
+ }
+ else if(group->name() == "nstate")
+ {
+ for(std::map<std::string,ChangeNotify*>::iterator it=items.begin(); it != items.end(); ++it)
+ {
+ it->second->loadNodeState();
+ }
+ }
+}
+
+void ChangeNotify::loadServerSettings()
+{
+ UserMessage::message(UserMessage::DBG, false,"ChangeNotify::loadServerSettings() --> " + id_);
+
+ std::string v("server.notification." + id_ + ".enabled");
+ UserMessage::message(UserMessage::DBG, false," property: " + v);
+
+ if(VProperty *p=VConfig::instance()->find(v))
+ {
+ setEnabled(p->value().toBool());
+ }
+ else
+ {
+ UserMessage::message(UserMessage::ERROR, false,
+ std::string(" Error! Unable to find property: " + v));
+ }
+}
+
+ChangeNotifyDialog* ChangeNotify::dialog()
+{
+ if(!dialog_)
+ {
+ dialog_=new ChangeNotifyDialog();
+ for(std::map<std::string,ChangeNotify*>::iterator it=items.begin(); it != items.end(); ++it)
+ {
+ dialog_->addTab(it->second);
+ }
+
+ for(std::map<std::string,ChangeNotify*>::iterator it=items.begin(); it != items.end(); ++it)
+ {
+ dialog_->setEnabledTab(it->second,it->second->isEnabled());
+ }
+
+ }
+
+ return dialog_;
+}
+
+/*
+void ChangeNotify::showDialog(ChangeNotifyconst std::string& id)
+{
+ dialog()->setCurrentTab(id);
+ dialog()->show();
+ dialog()->raise();
+}
+*/
+/*void ChangeNotify::clearData(const std::string& id)
+{
+ if(ChangeNotify* obj=ChangeNotify::find(id))
+ {
+ obj->data()->clear();
+ }
+}*/
+
+void ChangeNotify::populate(ChangeNotifyWidget* w)
+{
+ for(std::map<std::string,ChangeNotify*>::iterator it=items.begin(); it != items.end(); ++it)
+ {
+ w->addTb(it->second);
+ }
+}
+
+//==================================================
+//
+// AbortedNotify
+//
+//==================================================
+
+void AbortedNotify::loadNodeState()
+{
+ if(VProperty *nsp=VConfig::instance()->find("nstate.aborted"))
+ {
+ VProperty* master=nsp->findChild("fill_colour");
+ VProperty* local=prop_->findChild("fill_colour");
+
+ if(master && local)
+ {
+ local->setMaster(master,true);
+ }
+
+ master=nsp->findChild("text_colour");
+ local=prop_->findChild("text_colour");
+
+ if(master && local)
+ {
+ local->setMaster(master,true);
+ }
+ }
+
+}
+
+static SimpleLoader<ChangeNotify> loaderNotify("notification");
+static SimpleLoader<ChangeNotify> loaderServerNotify("server");
+static SimpleLoader<ChangeNotify> loaderStateNotify("nstate");
diff --git a/Viewer/src/ChangeNotify.hpp b/Viewer/src/ChangeNotify.hpp
new file mode 100644
index 0000000..2e76145
--- /dev/null
+++ b/Viewer/src/ChangeNotify.hpp
@@ -0,0 +1,85 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef CHANGENOTIFYHANDLER_HPP_
+#define CHANGENOTIFYHANDLER_HPP_
+
+#include <map>
+#include <string>
+
+#include "VProperty.hpp"
+
+class ChangeNotifyDialog;
+class ChangeNotifyModel;
+class ChangeNotifyWidget;
+class VProperty;
+class VNode;
+class VNodeList;
+
+class QAbstractItemModel;
+class QSortFilterProxyModel;
+
+class ChangeNotify : public VPropertyObserver
+{
+public:
+ explicit ChangeNotify(const std::string& id);
+
+ const std::string& id() const {return id_;}
+ VNodeList* data() const {return data_;}
+ VProperty* prop() const {return prop_;}
+ ChangeNotifyModel* model() const;
+ QSortFilterProxyModel* proxyModel() const {return proxyModel_;}
+ bool isEnabled() const {return enabled_;}
+ void clearData();
+ void showDialog();
+
+ //Form VPropertyObserver
+ void notifyChange(VProperty*);
+
+ static void add(const std::string&,VNode*,bool,bool);
+ static void remove(const std::string&,VNode*);
+ static void setEnabled(const std::string&,bool);
+ static void populate(ChangeNotifyWidget* w);
+ //static void showDialog(const std::string& id);
+ //static void clearData(const std::string& id);
+
+ //Called from VConfigLoader
+ static void load(VProperty* group);
+
+protected:
+ void add(VNode*,bool,bool);
+ void remove(VNode*);
+ void setEnabled(bool);
+ void setProperty(VProperty* prop);
+ void loadServerSettings();
+ virtual void loadNodeState() {}
+
+ static ChangeNotify* find(const std::string&);
+ static ChangeNotifyDialog* dialog();
+
+ std::string id_;
+ bool enabled_;
+ VNodeList* data_;
+ ChangeNotifyModel* model_;
+ QSortFilterProxyModel* proxyModel_;
+ VProperty* prop_;
+ static ChangeNotifyDialog* dialog_;
+};
+
+class AbortedNotify : public ChangeNotify
+{
+public:
+ explicit AbortedNotify(const std::string& id) : ChangeNotify(id) {}
+protected:
+ void loadNodeState();
+};
+
+
+#endif
diff --git a/Viewer/src/ChangeNotifyDialog.cpp b/Viewer/src/ChangeNotifyDialog.cpp
new file mode 100644
index 0000000..6e62b3f
--- /dev/null
+++ b/Viewer/src/ChangeNotifyDialog.cpp
@@ -0,0 +1,492 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "ChangeNotifyDialog.hpp"
+
+#include "ChangeNotify.hpp"
+#include "ChangeNotifyModel.hpp"
+#include "MainWindow.hpp"
+#include "SessionHandler.hpp"
+#include "TreeView.hpp"
+#include "VNodeList.hpp"
+#include "VProperty.hpp"
+
+#include <QCloseEvent>
+#include <QDebug>
+#include <QPainter>
+#include <QSettings>
+#include <QVariant>
+
+ChangeNotifyDialogWidget::ChangeNotifyDialogWidget(QWidget *parent) :
+ QWidget(parent),
+ notifier_(0)
+{
+ setupUi(this);
+}
+
+void ChangeNotifyDialogWidget::init(ChangeNotify* notifier)
+{
+ notifier_=notifier;
+
+ tree_->setModel(notifier_->model());
+
+ label_->hide();
+
+ connect(notifier->data(),SIGNAL(endAppendRow()),
+ this,SLOT(slotAppend()));
+
+ connect(notifier->data(),SIGNAL(endRemoveRow(int)),
+ this,SLOT(slotRemoveRow(int)));
+
+ connect(notifier->data(),SIGNAL(endReset()),
+ this,SLOT(slotReset()));
+
+ //Selection
+ connect(tree_,SIGNAL(clicked(const QModelIndex&)),
+ this,SLOT(slotSelectItem(const QModelIndex&)));
+
+ connect(tree_,SIGNAL(doubleClicked(const QModelIndex&)),
+ this,SLOT(slotDoubleClickItem(const QModelIndex&)));
+
+
+ /*QString txt=notifier->prop()->param("description");
+ label_->setText(txt);
+
+ update(notifier);*/
+}
+
+void ChangeNotifyDialogWidget::slotAppend()
+{
+ Q_EMIT contentsChanged();
+}
+
+void ChangeNotifyDialogWidget::slotRemoveRow(int)
+{
+ Q_EMIT contentsChanged();
+}
+
+void ChangeNotifyDialogWidget::slotReset()
+{
+ Q_EMIT contentsChanged();
+}
+
+void ChangeNotifyDialogWidget::update(ChangeNotify* notifier)
+{
+ QColor bgCol(Qt::gray);
+ if(VProperty *p=notifier->prop()->findChild("fill_colour"))
+ bgCol=p->value().value<QColor>();
+
+ QColor bgLight=bgCol.lighter(150);
+
+ QString st="QLabel { \
+ background: qlineargradient(x1 :0, y1: 0, x2: 0, y2: 1, \
+ stop: 0 " + bgLight.name() + ", stop: 1 " + bgLight.name() + "); }";
+
+ label_->setStyleSheet(st);
+}
+
+void ChangeNotifyDialogWidget::slotSelectItem(const QModelIndex& idx)
+{
+ //QModelIndexList lst=tree_->selectedIndexes();
+ //if(lst.count() > 0)
+ //{
+ VInfo_ptr info=notifier_->model()->nodeInfo(idx);
+ if(info)
+ {
+ Q_EMIT selectionChanged(info);
+ }
+ //}
+}
+
+void ChangeNotifyDialogWidget::slotDoubleClickItem(const QModelIndex&)
+{
+
+}
+
+//===========================================================
+//
+// ChangeNotifyDialog
+//
+//===========================================================
+
+ChangeNotifyDialog::ChangeNotifyDialog(QWidget *parent) :
+ QDialog(parent),
+ ignoreCurrentChange_(false)
+{
+ setupUi(this);
+
+ tab_->setProperty("notify","1");
+
+#ifdef ECFLOW_QT5
+ tab_->tabBar()->setExpanding(false);
+#endif
+
+ clearOnCloseCb_->setChecked(true);
+
+ grad_.setCoordinateMode(QGradient::ObjectBoundingMode);
+ grad_.setStart(0,0);
+ grad_.setFinalStop(0,1);
+
+ readSettings();
+}
+
+ChangeNotifyDialog::~ChangeNotifyDialog()
+{
+ writeSettings();
+}
+
+void ChangeNotifyDialog::addTab(ChangeNotify* notifier)
+{
+ const std::string& id=notifier->id();
+
+ ChangeNotifyDialogWidget* w=new ChangeNotifyDialogWidget(this);
+ w->init(notifier);
+
+ connect(w,SIGNAL(contentsChanged()),
+ this,SLOT(slotContentsChanged()));
+
+ connect(w,SIGNAL(selectionChanged(VInfo_ptr)),
+ this,SLOT(slotSelectionChanged(VInfo_ptr)));
+
+ ignoreCurrentChange_=true;
+ tab_->addTab(w,"");
+ ignoreCurrentChange_=false;
+
+ tabWidgets_ << w;
+
+ int idx=tab_->count()-1;
+ if(idx == tab_->currentIndex())
+ updateStyleSheet(notifier->prop());
+
+ decorateTab(idx,notifier);
+}
+
+void ChangeNotifyDialog::slotContentsChanged()
+{
+ if(ChangeNotifyDialogWidget* w=static_cast<ChangeNotifyDialogWidget*>(sender()))
+ {
+ int idx=tab_->indexOf(w);
+ if(idx != -1)
+ {
+ decorateTab(idx,w->notifier());
+ }
+ }
+}
+
+void ChangeNotifyDialog::slotSelectionChanged(VInfo_ptr info)
+{
+ MainWindow::changeNotifySelectionChanged(info);
+}
+
+void ChangeNotifyDialog::updateStyleSheet(VProperty *currentProp)
+{
+ QColor bgCol(Qt::gray);
+ if(VProperty *p=currentProp->findChild("fill_colour"))
+ bgCol=p->value().value<QColor>();
+
+ QColor bgLight=bgCol.lighter(150);
+
+ QString st="QTabBar::tab:selected { \
+ background: qlineargradient(x1 :0, y1: 0, x2: 0, y2: 1, \
+ stop: 0 " + bgLight.name() + ", stop: 1 " + bgCol.name() + "); }";
+
+ tab_->setStyleSheet(st);
+}
+
+void ChangeNotifyDialog::decorateTabs()
+{
+ for(int i=0; i < tab_->count(); i++)
+ {
+ decorateTab(i,tabWidgets_.at(i)->notifier());
+ }
+}
+
+void ChangeNotifyDialog::decorateTab(int tabIdx,ChangeNotify* notifier)
+{
+ if(tabIdx == -1 || !notifier)
+ return;
+
+ VProperty *prop=notifier->prop();
+
+ QString numText;
+ if(notifier->data())
+ {
+ int num=notifier->data()->size();
+ if(num > 0)
+ numText=" (" + QString::number(num) + ")";
+ }
+
+
+ //Create icon for tab
+ QFont f;
+ QFontMetrics fm(f);
+ QString labelText=prop->param("labelText")+ numText;
+ int textH=fm.height();
+ int textW=fm.width(labelText);
+ int margin=3;
+
+ QColor bgCol(Qt::gray);
+ if(VProperty *p=prop->findChild("fill_colour"))
+ bgCol=p->value().value<QColor>();
+
+ QColor fgCol(Qt::black);
+ if(VProperty *p=prop->findChild("text_colour"))
+ fgCol=p->value().value<QColor>();
+
+ QColor countBgCol(58,126,194);
+ if(VProperty *p=prop->findChild("count_fill_colour"))
+ countBgCol=p->value().value<QColor>();
+
+ QColor countFgCol(Qt::white);
+ if(VProperty *p=prop->findChild("count_text_colour"))
+ countFgCol=p->value().value<QColor>();
+
+ QColor bgLight=bgCol.lighter(150);
+ grad_.setColorAt(0,bgLight);
+ grad_.setColorAt(1,bgCol);
+ QBrush bgBrush(grad_);
+
+ QFont numF;
+ numF.setBold(true);
+ numF.setPointSize(f.pointSize()-1);
+ QFontMetrics numFm(numF);
+
+ int w;
+ int h=2*margin+textH+4;
+ if(!numText.isEmpty())
+ //w=2*margin+textW + 3 + numFm.width(numText) + 3;
+ w=2*margin+textW;
+ else
+ w=2*margin+textW;
+
+ QPixmap pix(w,h);
+ pix.fill(Qt::transparent);
+
+ QPainter painter(&pix);
+
+ /* QFont f;
+ f.setBold(true);
+ f.setPointSize(f.pointSize()+1);
+ QFontMetrics fm(f);
+ int w;
+ if(!numText.isEmpty())
+ w=fm.width(text) + 6 + fm.width(numText) + 2;
+ else
+ w=fm.width(text) + 6;
+
+ int h=fm.height()+6;
+
+ QPixmap pix(w,h);
+ pix.fill(QColor(255,255,255,0));
+ QPainter painter(&pix);
+ painter.setRenderHint(QPainter::Antialiasing,true);
+ painter.setRenderHint(QPainter::TextAntialiasing,true);
+
+ QRect textRect(0,0,fm.width(text)+6,h);
+
+ QColor bgLight=bgCol.lighter(150);
+ grad_.setColorAt(0,bgLight);
+ grad_.setColorAt(1,bgCol);
+
+ painter.setBrush(QBrush(grad_));
+ painter.setPen(border);
+ painter.drawRoundedRect(textRect,2,2);
+ painter.setPen(fgCol);
+ painter.setFont(f);
+ painter.drawText(textRect,Qt::AlignHCenter|Qt::AlignVCenter,text);
+
+ if(!numText.isEmpty())
+ {
+ QRect numRect(textRect.right()-1,0,fm.width(numText)+4,fm.ascent()+4);
+ painter.setBrush(countBgCol);
+ painter.setPen(countFgCol);
+ painter.drawRoundedRect(numRect,4,4);
+ painter.setFont(f);
+ painter.drawText(numRect,Qt::AlignHCenter|Qt::AlignVCenter,numText);
+ }
+
+ setIconSize(QSize(w,h));
+ setIcon(pix);
+ */
+
+
+
+ pix.fill(Qt::transparent);
+
+ QRect textRect=QRect(margin,0,textW,pix.height());
+ painter.setPen(fgCol);
+ painter.drawText(textRect,Qt::AlignVCenter|Qt::AlignHCenter,labelText);
+
+ if(tabIdx != tab_->currentIndex())
+ {
+ QRect lineRect(textRect.left(),pix.height()/2+textH/2+1,
+ textRect.width(),3);
+
+ painter.fillRect(lineRect,bgCol);
+ }
+
+ /*if(!numText.isEmpty())
+ {
+ painter.setRenderHint(QPainter::Antialiasing,true);
+ painter.setRenderHint(QPainter::TextAntialiasing,true);
+
+ QRect numRect(textRect.right()+4,1,fm.width(numText)+4,fm.ascent()+4);
+ painter.setBrush(countBgCol);
+ painter.setPen(Qt::NoPen);
+ painter.drawRoundedRect(numRect,4,4);
+ painter.setFont(numF);
+ painter.setPen(countFgCol);
+ painter.drawText(numRect,Qt::AlignHCenter|Qt::AlignVCenter,numText);
+ }*/
+
+ tab_->setCustomIcon(tabIdx,pix);
+}
+
+
+void ChangeNotifyDialog::setCurrentTab(ChangeNotify *ntf)
+{
+ int tabIdx=ntfToTab(ntf);
+ if(tabIdx != -1)
+ {
+ tab_->setCurrentIndex(tabIdx);
+ }
+}
+
+void ChangeNotifyDialog::setEnabledTab(ChangeNotify* ntf,bool b)
+{
+ int tabIdx=ntfToTab(ntf);
+ if(tabIdx != -1)
+ {
+ tab_->setTabEnabled(tabIdx,b);
+ }
+}
+
+void ChangeNotifyDialog::on_tab__currentChanged(int idx)
+{
+ if(ignoreCurrentChange_)
+ return;
+
+ if(ChangeNotify* notifier=tabToNtf(idx))
+ {
+ updateStyleSheet(notifier->prop());
+ decorateTabs();
+ }
+}
+
+void ChangeNotifyDialog::on_closePb__clicked(bool b)
+{
+ hide();
+
+ if(clearOnCloseCb_->isChecked())
+ {
+ int idx=tab_->currentIndex();
+ if(idx != -1)
+ {
+ if(ChangeNotify *ntf=tabToNtf(idx))
+ ntf->clearData();
+ }
+ }
+
+ writeSettings();
+}
+
+void ChangeNotifyDialog::on_clearPb__clicked(bool b)
+{
+ int idx=tab_->currentIndex();
+ if(idx != -1)
+ {
+ if(ChangeNotify *ntf=tabToNtf(idx))
+ ntf->clearData();
+ }
+}
+
+ChangeNotify* ChangeNotifyDialog::tabToNtf(int idx)
+{
+ if(idx >=0 && idx < tab_->count())
+ {
+ return tabWidgets_.at(idx)->notifier();
+ }
+
+ return 0;
+}
+
+int ChangeNotifyDialog::ntfToTab(ChangeNotify* ntf)
+{
+ for(int i=0; i < tab_->count(); i++)
+ {
+ if(tabWidgets_.at(i)->notifier() == ntf)
+ return i;
+ }
+
+ return -1;
+}
+
+void ChangeNotifyDialog::updateSettings(ChangeNotify* notifier)
+{
+ int idx=ntfToTab(notifier);
+ if(idx != -1)
+ {
+ if(tab_->isTabEnabled(idx))
+ {
+ if(idx == tab_->currentIndex())
+ {
+ updateStyleSheet(notifier->prop());
+ }
+ decorateTab(idx,notifier);
+ }
+ }
+}
+
+void ChangeNotifyDialog::closeEvent(QCloseEvent* e)
+{
+ writeSettings();
+ e->accept();
+}
+
+void ChangeNotifyDialog::writeSettings()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ Q_ASSERT(cs);
+ QSettings settings(QString::fromStdString(cs->qtSettingsFile("ChangeNotifyDialog")),
+ QSettings::NativeFormat);
+
+ //We have to clear it so that should not remember all the previous values
+ settings.clear();
+
+ settings.beginGroup("main");
+ settings.setValue("size",size());
+ settings.setValue("clearOnClose",clearOnCloseCb_->isChecked());
+ settings.endGroup();
+}
+
+void ChangeNotifyDialog::readSettings()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ Q_ASSERT(cs);
+ QSettings settings(QString::fromStdString(cs->qtSettingsFile("ChangeNotifyDialog")),
+ QSettings::NativeFormat);
+
+ settings.beginGroup("main");
+ if(settings.contains("size"))
+ {
+ resize(settings.value("size").toSize());
+ }
+ else
+ {
+ resize(QSize(440,380));
+ }
+
+ if(settings.contains("clearOnClose"))
+ {
+ clearOnCloseCb_->setChecked(settings.value("clearOnClose").toBool());
+ }
+
+ settings.endGroup();
+}
diff --git a/Viewer/src/ChangeNotifyDialog.hpp b/Viewer/src/ChangeNotifyDialog.hpp
new file mode 100644
index 0000000..6fb7bb1
--- /dev/null
+++ b/Viewer/src/ChangeNotifyDialog.hpp
@@ -0,0 +1,95 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef CHANGENOTIFYDIALOG_HPP_
+#define CHANGENOTIFYDIALOG_HPP_
+
+#include <QDialog>
+#include <QLinearGradient>
+#include <QWidget>
+
+#include "ui_ChangeNotifyDialog.h"
+#include "ui_ChangeNotifyDialogWidget.h"
+
+#include "VInfo.hpp"
+
+class ChangeNotify;
+class VProperty;
+
+class QLabel;
+
+class ChangeNotifyDialogWidget : public QWidget, protected Ui::ChangeNotifyDialogWidget
+{
+ Q_OBJECT
+
+public:
+ explicit ChangeNotifyDialogWidget(QWidget* parent=0);
+ ~ChangeNotifyDialogWidget() {}
+
+ void init(ChangeNotify*);
+ void update(ChangeNotify*);
+ ChangeNotify* notifier() const {return notifier_;}
+
+public Q_SLOTS:
+ void slotAppend();
+ void slotRemoveRow(int);
+ void slotReset();
+
+protected Q_SLOTS:
+ void slotSelectItem(const QModelIndex&);
+ void slotDoubleClickItem(const QModelIndex&);
+
+Q_SIGNALS:
+ void contentsChanged();
+ void selectionChanged(VInfo_ptr);
+
+protected:
+ ChangeNotify* notifier_;
+};
+
+
+class ChangeNotifyDialog : public QDialog, protected Ui::ChangeNotifyDialog
+{
+Q_OBJECT
+
+public:
+ explicit ChangeNotifyDialog(QWidget *parent=0);
+ ~ChangeNotifyDialog();
+
+ void addTab(ChangeNotify*);
+ void setCurrentTab(ChangeNotify*);
+ void setEnabledTab(ChangeNotify*,bool b);
+ void updateSettings(ChangeNotify*);
+
+public Q_SLOTS:
+ void on_tab__currentChanged(int);
+ void on_closePb__clicked(bool b);
+ void on_clearPb__clicked(bool b);
+ void slotContentsChanged();
+
+protected Q_SLOTS:
+ void slotSelectionChanged(VInfo_ptr);
+
+protected:
+ ChangeNotify* tabToNtf(int tabIdx);
+ int ntfToTab(ChangeNotify*);
+ void decorateTabs();
+ void decorateTab(int,ChangeNotify*);
+ void updateStyleSheet(VProperty *currentProp);
+ void closeEvent(QCloseEvent*);
+ void writeSettings();
+ void readSettings();
+
+ QList<ChangeNotifyDialogWidget*> tabWidgets_;
+ bool ignoreCurrentChange_;
+ QLinearGradient grad_;
+};
+
+#endif
diff --git a/Viewer/src/ChangeNotifyDialog.ui b/Viewer/src/ChangeNotifyDialog.ui
new file mode 100644
index 0000000..6d09d79
--- /dev/null
+++ b/Viewer/src/ChangeNotifyDialog.ui
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ChangeNotifyDialog</class>
+ <widget class="QDialog" name="ChangeNotifyDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Change notification</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0,0">
+ <property name="spacing">
+ <number>2</number>
+ </property>
+ <property name="leftMargin">
+ <number>1</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>1</number>
+ </property>
+ <property name="bottomMargin">
+ <number>2</number>
+ </property>
+ <item>
+ <widget class="CustomTabWidget" name="tab_">
+ <property name="currentIndex">
+ <number>-1</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="clearOnCloseCb_">
+ <property name="text">
+ <string>C&lear current list on close</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="hbl">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="clearPb_">
+ <property name="text">
+ <string>Clea&r</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="closePb_">
+ <property name="text">
+ <string>&Close</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>CustomTabWidget</class>
+ <extends>QTabWidget</extends>
+ <header location="global">CustomTabWidget.hpp</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Viewer/src/ChangeNotifyDialogWidget.ui b/Viewer/src/ChangeNotifyDialogWidget.ui
new file mode 100644
index 0000000..8f0fa00
--- /dev/null
+++ b/Viewer/src/ChangeNotifyDialogWidget.ui
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ChangeNotifyDialogWidget</class>
+ <widget class="QWidget" name="ChangeNotifyDialogWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>502</width>
+ <height>508</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" stretch="0,1">
+ <property name="spacing">
+ <number>2</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label_">
+ <property name="autoFillBackground">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTreeView" name="tree_">
+ <property name="rootIsDecorated">
+ <bool>false</bool>
+ </property>
+ <property name="uniformRowHeights">
+ <bool>true</bool>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Viewer/src/ChangeNotifyEditor.cpp b/Viewer/src/ChangeNotifyEditor.cpp
new file mode 100644
index 0000000..e1a0844
--- /dev/null
+++ b/Viewer/src/ChangeNotifyEditor.cpp
@@ -0,0 +1,368 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "ChangeNotifyEditor.hpp"
+
+#include "PropertyLine.hpp"
+#include "VConfig.hpp"
+#include "VProperty.hpp"
+
+#include <QDebug>
+#include <QVBoxLayout>
+
+#include <assert.h>
+
+ChangeNotifyEditor::ChangeNotifyEditor(QWidget* parent) : QWidget(parent)
+{
+ setupUi(this);
+
+ model_=new ChangeNotifyEditorModel(this);
+
+ tree_->setModel(model_);
+
+ connect(tree_,SIGNAL(activated(QModelIndex)),
+ this,SLOT(slotRowSelected(QModelIndex)));
+
+ connect(tree_,SIGNAL(clicked(QModelIndex)),
+ this,SLOT(slotRowSelected(QModelIndex)));
+
+ assert(tab_->count()==0);
+ //assert(stacked_->count()==0);
+
+ QFont f;
+ QFontMetrics fm(f);
+ //tree_->setFixedHeight((fm.height()+4)*5.5);
+
+ tree_->setFixedWidth(fm.width("Restartedaaa")+30);
+
+ //tab_->hide();
+}
+
+void ChangeNotifyEditor::addRow(QString label,QList<PropertyLine*> lineLst,QWidget *stackContents)
+{
+ PropertyLine* enabledLine=0;
+ PropertyLine* popupLine=0;
+ PropertyLine* soundLine=0;
+
+ QList<VProperty*> propLst;
+ Q_FOREACH(PropertyLine* pl,lineLst)
+ {
+ if(pl)
+ {
+ propLst << pl->property();
+
+ if(pl->property()->name() == "enabled")
+ {
+ enabledLine=pl;
+ }
+ if(pl->property()->name() == "popup")
+ {
+ popupLine=pl;
+ }
+ if(pl->property()->name() == "sound")
+ {
+ soundLine=pl;
+ }
+
+ }
+ }
+
+ if(enabledLine)
+ {
+ connect(model_,SIGNAL(enabledChanged(VProperty*,QVariant)),
+ enabledLine,SLOT(slotReset(VProperty*,QVariant)));
+
+ connect(enabledLine,SIGNAL(changed(QVariant)),
+ model_,SLOT(slotEnabledChanged(QVariant)));
+
+ connect(enabledLine,SIGNAL(masterChanged(bool)),
+ model_,SLOT(slotEnabledMasterChanged(bool)));
+
+ if(popupLine)
+ {
+ connect(enabledLine,SIGNAL(changed(QVariant)),
+ popupLine,SLOT(slotEnabled(QVariant)));
+ //init
+ popupLine->slotEnabled(enabledLine->property()->value());
+ }
+ if(soundLine)
+ {
+ connect(enabledLine,SIGNAL(changed(QVariant)),
+ soundLine,SLOT(slotEnabled(QVariant)));
+
+ //init
+ soundLine->slotEnabled(enabledLine->property()->value());
+ }
+ }
+
+ model_->add(label,propLst);
+
+ QWidget* w=new QWidget(this);
+ QVBoxLayout* vb=new QVBoxLayout();
+ vb->setContentsMargins(0,5,0,5);
+ w->setLayout(vb);
+ vb->addWidget(stackContents);
+ vb->addStretch(1);
+
+ //stacked_->addWidget(w);
+ tab_->addTab(w,label);
+
+ tree_->setCurrentIndex(model_->index(0,0));
+
+ for(int i=0; i < model_->columnCount()-1; i++)
+ {
+ tree_->resizeColumnToContents(i);
+ }
+}
+
+void ChangeNotifyEditor::slotRowSelected(const QModelIndex& idx)
+{
+ //if(idx.row() == stacked_->currentIndex())
+ if(idx.row() == tab_->currentIndex())
+ return;
+
+ if(idx.row() >= 0 && idx.row() < tab_->count())
+ {
+ tab_->setCurrentIndex(idx.row());
+ }
+
+ /*if(idx.row() >= 0 && idx.row() < stacked_->count())
+ {
+ stacked_->setCurrentIndex(idx.row());
+ }*/
+}
+
+ChangeNotifyEditorModel::ChangeNotifyEditorModel(QObject *parent) :
+ QAbstractItemModel(parent)
+{
+
+}
+
+ChangeNotifyEditorModel::~ChangeNotifyEditorModel()
+{
+}
+
+void ChangeNotifyEditorModel::add(QString label,QList<VProperty*> propLst)
+{
+ beginResetModel();
+
+ ChangeNotifyEditorModelData d;
+
+ d.label_=label;
+
+ Q_FOREACH(VProperty* p,propLst)
+ {
+ if(p)
+ {
+ if(p->name() == "enabled")
+ {
+ d.enabled_=p;
+ d.enabledVal_=p->value().toBool();
+ d.enabledMaster_=(p->master() && p->useMaster());
+
+ //Get the description
+ if(p->parent())
+ {
+ if(VProperty* np=VConfig::instance()->find("notification."+ p->parent()->strName()))
+ d.desc_=np->param("description");
+ }
+ }
+ }
+ }
+
+ data_ << d;
+
+ endResetModel();
+}
+
+int ChangeNotifyEditorModel::columnCount( const QModelIndex& /*parent */ ) const
+{
+ return 2;
+}
+
+int ChangeNotifyEditorModel::rowCount( const QModelIndex& parent) const
+{
+ //Parent is the root:
+ if(!parent.isValid())
+ {
+ return data_.count();
+ }
+
+ return 0;
+}
+
+QVariant ChangeNotifyEditorModel::data( const QModelIndex& index, int role ) const
+{
+ if(!index.isValid())
+ {
+ return QVariant();
+ }
+
+ int row=index.row();
+ if(row < 0 || row >= data_.count())
+ return QVariant();
+
+ if(role == Qt::DisplayRole)
+ {
+ switch(index.column())
+ {
+ case 1:
+ return data_.at(row).label_;
+ case 2:
+ return data_.at(row).desc_;
+ default:
+ return QVariant();
+ }
+ }
+
+ else if(role == Qt::CheckStateRole)
+ {
+ switch(index.column())
+ {
+ case 0:
+ return (data_.at(row).enabledVal_)?QVariant(Qt::Checked):QVariant(Qt::Unchecked);
+ default:
+ return QVariant();
+ }
+ }
+
+ return QVariant();
+}
+
+bool ChangeNotifyEditorModel::setData(const QModelIndex& index,const QVariant& value, int role)
+{
+ if(index.column() == 0)
+ {
+ int row=index.row();
+ if(row <0 || row >= data_.count())
+ return false;
+
+ if(role == Qt::CheckStateRole)
+ {
+ bool checked=(value.toInt() == Qt::Checked)?true:false;
+ data_[row].enabledVal_=checked;
+ Q_EMIT dataChanged(index,index);
+ Q_EMIT enabledChanged(data_[row].enabled_,checked);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+QVariant ChangeNotifyEditorModel::headerData( const int section, const Qt::Orientation orient , const int role ) const
+{
+ if ( orient != Qt::Horizontal || role != Qt::DisplayRole)
+ return QAbstractItemModel::headerData( section, orient, role );
+
+ if(role == Qt::DisplayRole)
+ {
+ switch ( section )
+ {
+ case 0: return tr("E");
+ case 1: return tr("Title");
+ case 2: return tr("Description");
+ default: return QVariant();
+ }
+ }
+
+ return QVariant();
+}
+
+QModelIndex ChangeNotifyEditorModel::index( int row, int column, const QModelIndex & parent ) const
+{
+ if(row < 0 || column < 0)
+ {
+ return QModelIndex();
+ }
+
+ //When parent is the root this index refers to a node or server
+ if(!parent.isValid())
+ {
+ return createIndex(row,column);
+ }
+
+ return QModelIndex();
+
+}
+
+QModelIndex ChangeNotifyEditorModel::parent(const QModelIndex &child) const
+{
+ return QModelIndex();
+}
+
+Qt::ItemFlags ChangeNotifyEditorModel::flags( const QModelIndex & index) const
+{
+ int row=index.row();
+ if(row >=0 && row <= data_.count() &&
+ index.column() ==0 && data_.at(row).enabledMaster_)
+ {
+ return Qt::ItemIsUserCheckable| Qt::ItemIsSelectable;
+ }
+
+ Qt::ItemFlags defaultFlags=Qt::ItemIsEnabled | Qt::ItemIsSelectable;
+
+ if(index.isValid() && index.column() ==0)
+ defaultFlags=defaultFlags | Qt::ItemIsUserCheckable;
+
+ return defaultFlags;
+}
+
+int ChangeNotifyEditorModel::lineToRow(PropertyLine* line) const
+{
+ for(int i=0; i < data_.count(); i++)
+ {
+ if(data_.at(i).enabled_ == line->property())
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+
+void ChangeNotifyEditorModel::slotEnabledChanged(QVariant v)
+{
+ PropertyLine *line=static_cast<PropertyLine*>(sender());
+ assert(line);
+
+ int row=lineToRow(line);
+ if(row != -1)
+ {
+ //We want to avoid circular dependencies (e.g. this function is triggered from
+ //setData. So we have to check if the value is different from the stored one!
+ if(data_.at(row).enabledVal_ != v.toBool())
+ {
+ data_[row].enabledVal_=v.toBool();
+ QModelIndex idx=index(row,0);
+ Q_EMIT dataChanged(idx,idx);
+ }
+ }
+}
+
+void ChangeNotifyEditorModel::slotEnabledMasterChanged(bool b)
+{
+ PropertyLine *line=static_cast<PropertyLine*>(sender());
+ assert(line);
+
+ int row=lineToRow(line);
+ if(row != -1)
+ {
+ QModelIndex idx=index(row,0);
+ data_[row].enabledMaster_=b;
+ if(b)
+ {
+ data_[row].enabledMaster_=b;
+ }
+ Q_EMIT dataChanged(idx,idx);
+ }
+}
+
diff --git a/Viewer/src/ChangeNotifyEditor.hpp b/Viewer/src/ChangeNotifyEditor.hpp
new file mode 100644
index 0000000..f39b9ac
--- /dev/null
+++ b/Viewer/src/ChangeNotifyEditor.hpp
@@ -0,0 +1,90 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+#ifndef VIEWER_SRC_CHANGENOTIFYEDITOR_HPP_
+#define VIEWER_SRC_CHANGENOTIFYEDITOR_HPP_
+
+#include <QWidget>
+#include <QAbstractItemModel>
+
+#include <vector>
+#include "VProperty.hpp"
+
+#include "ui_ChangeNotifyEditor.h"
+
+class QGridlayout;
+
+class ChangeNotifyEditorModel;
+class PropertyLine;
+
+class ChangeNotifyEditor : public QWidget, protected Ui::ChangeNotifyEditor
+{
+ Q_OBJECT
+
+public:
+ explicit ChangeNotifyEditor(QWidget* parent=0);
+ void addRow(QString,QList<PropertyLine*>,QWidget*);
+
+protected Q_SLOTS:
+ void slotRowSelected(const QModelIndex& idx);
+
+private:
+ ChangeNotifyEditorModel* model_;
+};
+
+
+class ChangeNotifyEditorModelData
+{
+public:
+ ChangeNotifyEditorModelData() : enabled_(NULL), enabledMaster_(false), enabledVal_(false) {}
+
+ QString label_;
+ QString desc_;
+ VProperty* enabled_;
+ bool enabledMaster_;
+ bool enabledVal_;
+};
+
+
+class ChangeNotifyEditorModel : public QAbstractItemModel
+{
+ Q_OBJECT
+
+public:
+ explicit ChangeNotifyEditorModel(QObject *parent=0);
+ ~ChangeNotifyEditorModel();
+
+ void add(QString,QList<VProperty*>);
+
+ int columnCount (const QModelIndex& parent = QModelIndex() ) const;
+ int rowCount (const QModelIndex& parent = QModelIndex() ) const;
+
+ QVariant data (const QModelIndex& , int role = Qt::DisplayRole ) const;
+ bool setData(const QModelIndex & index, const QVariant& value, int role = Qt::EditRole);
+ QVariant headerData(int,Qt::Orientation,int role = Qt::DisplayRole ) const;
+
+ QModelIndex index (int, int, const QModelIndex& parent = QModelIndex() ) const;
+ QModelIndex parent (const QModelIndex & ) const;
+ Qt::ItemFlags flags ( const QModelIndex & index) const;
+
+public Q_SLOTS:
+ void slotEnabledChanged(QVariant v);
+ void slotEnabledMasterChanged(bool b);
+
+Q_SIGNALS:
+ void enabledChanged(VProperty*,QVariant);
+
+protected:
+ int lineToRow(PropertyLine* line) const;
+
+ QList<ChangeNotifyEditorModelData> data_;
+};
+
+
+#endif /* VIEWER_SRC_CHANGENOTIFYEDITOR_HPP_ */
diff --git a/Viewer/src/ChangeNotifyEditor.ui b/Viewer/src/ChangeNotifyEditor.ui
new file mode 100644
index 0000000..1009ac5
--- /dev/null
+++ b/Viewer/src/ChangeNotifyEditor.ui
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ChangeNotifyEditor</class>
+ <widget class="QWidget" name="ChangeNotifyEditor">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>502</width>
+ <height>508</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeView" name="tree_">
+ <property name="rootIsDecorated">
+ <bool>false</bool>
+ </property>
+ <property name="uniformRowHeights">
+ <bool>true</bool>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTabWidget" name="tab_">
+ <property name="currentIndex">
+ <number>-1</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QStackedWidget" name="stacked_"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Viewer/src/ChangeNotifyModel.cpp b/Viewer/src/ChangeNotifyModel.cpp
new file mode 100644
index 0000000..90b857a
--- /dev/null
+++ b/Viewer/src/ChangeNotifyModel.cpp
@@ -0,0 +1,241 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "ChangeNotifyModel.hpp"
+
+#include "VNode.hpp"
+#include "VNodeList.hpp"
+
+#include <QDebug>
+
+ChangeNotifyModel::ChangeNotifyModel(QObject *parent) :
+ QAbstractItemModel(parent),
+ data_(0)
+{
+}
+
+ChangeNotifyModel::~ChangeNotifyModel()
+{
+}
+
+VNodeList* ChangeNotifyModel::data()
+{
+ return data_;
+}
+
+void ChangeNotifyModel::setData(VNodeList *data)
+{
+ beginResetModel();
+
+ data_=data;
+
+ connect(data_,SIGNAL(beginAppendRow()),
+ this,SLOT(slotBeginAppendRow()));
+
+ connect(data_,SIGNAL(endAppendRow()),
+ this,SLOT(slotEndAppendRow()));
+
+ connect(data_,SIGNAL(beginRemoveRow(int)),
+ this,SLOT(slotBeginRemoveRow(int)));
+
+ connect(data_,SIGNAL(endRemoveRow(int)),
+ this,SLOT(slotEndRemoveRow(int)));
+
+ connect(data_,SIGNAL(beginRemoveRows(int,int)),
+ this,SLOT(slotBeginRemoveRows(int,int)));
+
+ connect(data_,SIGNAL(endRemoveRows(int,int)),
+ this,SLOT(slotEndRemoveRows(int,int)));
+
+ connect(data_,SIGNAL(beginReset()),
+ this,SLOT(slotBeginReset()));
+
+ connect(data_,SIGNAL(endReset()),
+ this,SLOT(slotEndReset()));
+
+ endResetModel();
+}
+
+bool ChangeNotifyModel::hasData() const
+{
+ return (data_ && data_->size() >0);
+}
+
+int ChangeNotifyModel::columnCount( const QModelIndex& /*parent */ ) const
+{
+ return 3;
+}
+
+int ChangeNotifyModel::rowCount( const QModelIndex& parent) const
+{
+ if(!hasData())
+ return 0;
+
+ //Parent is the root:
+ if(!parent.isValid())
+ {
+ return data_->size();
+ }
+
+ return 0;
+}
+
+
+QVariant ChangeNotifyModel::data( const QModelIndex& index, int role ) const
+{
+ if(!index.isValid() || !hasData())
+ {
+ return QVariant();
+ }
+ int row=index.row();
+ if(row < 0 || row >= data_->size())
+ return QVariant();
+
+ if(role == Qt::DisplayRole)
+ {
+ VNodeListItem *item=data_->itemAt(row);
+ assert(item);
+
+ switch(index.column())
+ {
+ case 0:
+ return QString::fromStdString(item->server());
+ break;
+ case 1:
+ return QString::fromStdString(item->path());
+ break;
+ case 2:
+ return item->time();
+ break;
+ default:
+ break;
+ }
+ }
+
+ return QVariant();
+}
+
+QVariant ChangeNotifyModel::headerData( const int section, const Qt::Orientation orient , const int role ) const
+{
+ if ( orient != Qt::Horizontal || (role != Qt::DisplayRole && role != Qt::ToolTipRole))
+ return QAbstractItemModel::headerData( section, orient, role );
+
+ if(role == Qt::DisplayRole)
+ {
+ switch ( section )
+ {
+ case 0: return tr("Server");
+ case 1: return tr("Node");
+ case 2: return tr("Time of change");
+ default: return QVariant();
+ }
+ }
+ else if(role== Qt::ToolTipRole)
+ {
+ switch ( section )
+ {
+ case 0: return tr("Server");
+ case 1: return tr("Node");
+ case 2: return tr("Time of change");
+ default: return QVariant();
+ }
+ }
+ return QVariant();
+}
+
+QModelIndex ChangeNotifyModel::index( int row, int column, const QModelIndex & parent ) const
+{
+ if(!hasData() || row < 0 || column < 0)
+ {
+ return QModelIndex();
+ }
+
+ //When parent is the root this index refers to a node or server
+ if(!parent.isValid())
+ {
+ return createIndex(row,column);
+ }
+
+ return QModelIndex();
+
+}
+
+QModelIndex ChangeNotifyModel::parent(const QModelIndex &child) const
+{
+ return QModelIndex();
+}
+
+VInfo_ptr ChangeNotifyModel::nodeInfo(const QModelIndex& index) const
+{
+ VInfo_ptr res;
+
+ if(!index.isValid() || !hasData())
+ {
+ return res;
+ }
+
+ int row=index.row();
+ if(row < 0 || row >= data_->size())
+ return res;
+
+ VNodeListItem *item=data_->itemAt(row);
+ Q_ASSERT(item);
+ VNode* vnode=item->node();
+ Q_ASSERT(vnode);
+
+ if(vnode->isServer())
+ return VInfoServer::create(vnode->server());
+ else
+ return VInfoNode::create(vnode);
+
+ return res;
+}
+
+void ChangeNotifyModel::slotBeginAppendRow()
+{
+ beginInsertRows(QModelIndex(),data_->size(),data_->size());
+}
+
+void ChangeNotifyModel::slotEndAppendRow()
+{
+ endInsertRows();
+}
+
+void ChangeNotifyModel::slotBeginRemoveRow(int row)
+{
+ beginRemoveRows(QModelIndex(),row,row);
+}
+
+void ChangeNotifyModel::slotEndRemoveRow(int row)
+{
+ endRemoveRows();
+}
+
+void ChangeNotifyModel::slotBeginRemoveRows(int rowStart,int rowEnd)
+{
+ beginRemoveRows(QModelIndex(),rowStart,rowEnd);
+}
+
+void ChangeNotifyModel::slotEndRemoveRows(int,int)
+{
+ endRemoveRows();
+}
+
+
+void ChangeNotifyModel::slotBeginReset()
+{
+ beginResetModel();
+}
+
+void ChangeNotifyModel::slotEndReset()
+{
+ endResetModel();
+}
+
+
diff --git a/Viewer/src/ChangeNotifyModel.hpp b/Viewer/src/ChangeNotifyModel.hpp
new file mode 100644
index 0000000..e5a8119
--- /dev/null
+++ b/Viewer/src/ChangeNotifyModel.hpp
@@ -0,0 +1,58 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef CHANGENOTIFYMODEL_HPP_
+#define CHANGENOTIFYMODEL_HPP_
+
+#include <QSortFilterProxyModel>
+
+#include <vector>
+
+#include "VInfo.hpp"
+
+class VNodeList;
+
+class ChangeNotifyModel : public QAbstractItemModel
+{
+ Q_OBJECT
+public:
+ explicit ChangeNotifyModel(QObject *parent=0);
+ ~ChangeNotifyModel();
+
+ int columnCount (const QModelIndex& parent = QModelIndex() ) const;
+ int rowCount (const QModelIndex& parent = QModelIndex() ) const;
+
+ QVariant data (const QModelIndex& , int role = Qt::DisplayRole ) const;
+ QVariant headerData(int,Qt::Orientation,int role = Qt::DisplayRole ) const;
+
+ QModelIndex index (int, int, const QModelIndex& parent = QModelIndex() ) const;
+ QModelIndex parent (const QModelIndex & ) const;
+
+ void setData(VNodeList *);
+ bool hasData() const;
+ VNodeList* data();
+ VInfo_ptr nodeInfo(const QModelIndex&) const;
+
+public Q_SLOTS:
+ void slotBeginAppendRow();
+ void slotEndAppendRow();
+ void slotBeginRemoveRow(int);
+ void slotEndRemoveRow(int);
+ void slotBeginRemoveRows(int,int);
+ void slotEndRemoveRows(int,int);
+ void slotBeginReset();
+ void slotEndReset();
+
+protected:
+ VNodeList* data_;
+};
+
+#endif
+
diff --git a/Viewer/src/ChangeNotifyWidget.cpp b/Viewer/src/ChangeNotifyWidget.cpp
new file mode 100644
index 0000000..1e24bd2
--- /dev/null
+++ b/Viewer/src/ChangeNotifyWidget.cpp
@@ -0,0 +1,229 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "ChangeNotifyWidget.hpp"
+
+#include <QHBoxLayout>
+#include <QPainter>
+#include <QSignalMapper>
+#include <QToolButton>
+
+#include "ChangeNotify.hpp"
+#include "VNodeList.hpp"
+#include "VProperty.hpp"
+
+#include <vector>
+
+std::vector<ChangeNotifyWidget*> ChangeNotifyWidget::widgets_;
+
+ChangeNotifyButton::ChangeNotifyButton(QWidget* parent) :
+ QToolButton(parent),
+ notifier_(0)
+{
+ setProperty("notify","1");
+ setAutoRaise(true);
+ setIconSize(QSize(20,20));
+
+ grad_.setCoordinateMode(QGradient::ObjectBoundingMode);
+ grad_.setStart(0,0);
+ grad_.setFinalStop(0,1);
+}
+
+void ChangeNotifyButton::setNotifier(ChangeNotify* notifier)
+{
+ notifier_=notifier;
+
+ if(notifier_->prop())
+ setToolTip(notifier_->prop()->param("tooltip"));
+
+ connect(this,SIGNAL(clicked(bool)),
+ this,SLOT(slotClicked(bool)));
+
+ connect(notifier_->data(),SIGNAL(endAppendRow()),
+ this,SLOT(slotAppend()));
+
+ connect(notifier_->data(),SIGNAL(endRemoveRow(int)),
+ this,SLOT(slotRemoveRow(int)));
+
+ connect(notifier_->data(),SIGNAL(endReset()),
+ this,SLOT(slotReset()));
+
+ updateIcon();
+}
+
+void ChangeNotifyButton::slotAppend()
+{
+ updateIcon();
+}
+
+void ChangeNotifyButton::slotRemoveRow(int)
+{
+ updateIcon();
+}
+
+void ChangeNotifyButton::slotReset()
+{
+ updateIcon();
+}
+
+void ChangeNotifyButton::slotClicked(bool)
+{
+ notifier_->showDialog();
+}
+
+void ChangeNotifyButton::updateIcon()
+{
+ QString text;
+ QString numText;
+
+ if(notifier_->prop())
+ {
+ text=notifier_->prop()->param("widgetText");
+ }
+
+ if(notifier_->data())
+ {
+ int num=notifier_->data()->size();
+ if(num > 0 && num < 10)
+ numText=QString::number(num);
+ else if(num > 10)
+ numText="9+";
+
+ }
+
+ QColor bgCol(Qt::gray);
+ QColor fgCol(Qt::black);
+ QColor countBgCol(58,126,194);
+ QColor countFgCol(Qt::white);
+ QColor border;
+
+ if(notifier_->prop())
+ {
+ if(VProperty *p=notifier_->prop()->findChild("fill_colour"))
+ bgCol=p->value().value<QColor>();
+
+ if(VProperty *p=notifier_->prop()->findChild("text_colour"))
+ fgCol=p->value().value<QColor>();
+
+ if(VProperty *p=notifier_->prop()->findChild("count_fill_colour"))
+ countBgCol=p->value().value<QColor>();
+
+ if(VProperty *p=notifier_->prop()->findChild("count_text_colour"))
+ countFgCol=p->value().value<QColor>();
+
+ border=notifier_->prop()->paramToColour("border");
+ }
+
+ QFont f;
+ f.setBold(true);
+ f.setPointSize(f.pointSize());
+ QFontMetrics fm(f);
+ int w;
+ if(!numText.isEmpty())
+ w=fm.width(text) + 6 + fm.width(numText) + 2;
+ else
+ w=fm.width(text) + 6;
+
+ int h=fm.height()+6;
+
+ QPixmap pix(w,h);
+ pix.fill(QColor(255,255,255,0));
+ QPainter painter(&pix);
+ painter.setRenderHint(QPainter::Antialiasing,true);
+ painter.setRenderHint(QPainter::TextAntialiasing,true);
+
+ QRect textRect(0,0,fm.width(text)+6,h);
+
+ QColor bgLight=bgCol.lighter(150);
+ grad_.setColorAt(0,bgLight);
+ grad_.setColorAt(1,bgCol);
+
+ painter.setBrush(QBrush(grad_));
+ painter.setPen(border);
+ painter.drawRoundedRect(textRect,2,2);
+ painter.setPen(fgCol);
+ painter.setFont(f);
+ painter.drawText(textRect,Qt::AlignHCenter|Qt::AlignVCenter,text);
+
+ if(!numText.isEmpty())
+ {
+ QRect numRect(textRect.right()-1,0,fm.width(numText)+4,fm.ascent()+4);
+ painter.setBrush(countBgCol);
+ painter.setPen(countFgCol);
+ painter.drawRoundedRect(numRect,4,4);
+ painter.setFont(f);
+ painter.drawText(numRect,Qt::AlignHCenter|Qt::AlignVCenter,numText);
+ }
+
+ setIconSize(QSize(w,h));
+ setIcon(pix);
+
+}
+
+ChangeNotifyWidget::ChangeNotifyWidget(QWidget *parent) : QWidget(parent)
+{
+ layout_=new QHBoxLayout(this);
+ layout_->setContentsMargins(0,0,0,0);
+ layout_->setSpacing(0);
+
+ ChangeNotify::populate(this);
+
+ widgets_.push_back(this);
+}
+
+ChangeNotifyWidget::~ChangeNotifyWidget()
+{
+ std::vector<ChangeNotifyWidget*>::iterator it=std::find(widgets_.begin(),widgets_.end(),this);
+ if(it != widgets_.end())
+ widgets_.erase(it);
+}
+
+ChangeNotifyButton* ChangeNotifyWidget::findButton(const std::string& id)
+{
+ std::map<std::string,ChangeNotifyButton*>::const_iterator it=buttons_.find(id);
+ if(it != buttons_.end())
+ return it->second;
+
+ return 0;
+}
+
+
+void ChangeNotifyWidget::addTb(ChangeNotify* notifier)
+{
+ ChangeNotifyButton *tb=new ChangeNotifyButton(this);
+ tb->setNotifier(notifier);
+ layout_->addWidget(tb);
+ if(!notifier->isEnabled())
+ tb->setEnabled(false);
+
+ buttons_[notifier->id()]=tb;
+}
+
+void ChangeNotifyWidget::setEnabled(const std::string& id,bool b)
+{
+ for(std::vector<ChangeNotifyWidget*>::iterator it=widgets_.begin(); it!= widgets_.end(); it++)
+ {
+ if(ChangeNotifyButton* tb=(*it)->findButton(id))
+ {
+ tb->setEnabled(b);
+ }
+ }
+}
+
+void ChangeNotifyWidget::updateSettings(const std::string& id)
+{
+ for(std::vector<ChangeNotifyWidget*>::iterator it=widgets_.begin(); it!= widgets_.end(); it++)
+ {
+ if(ChangeNotifyButton* tb=(*it)->findButton(id))
+ {
+ tb->updateIcon();
+ }
+ }
+}
diff --git a/Viewer/src/ChangeNotifyWidget.hpp b/Viewer/src/ChangeNotifyWidget.hpp
new file mode 100644
index 0000000..339e530
--- /dev/null
+++ b/Viewer/src/ChangeNotifyWidget.hpp
@@ -0,0 +1,73 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VIEWER_SRC_CHANGENOTIFYWIDGET_HPP_
+#define VIEWER_SRC_CHANGENOTIFYWIDGET_HPP_
+
+#include <QLinearGradient>
+#include <QToolButton>
+#include <QWidget>
+
+#include <map>
+#include <string>
+#include <vector>
+
+class QHBoxLayout;
+class QSignalMapper;
+
+class ChangeNotify;
+class VProperty;
+class ChangeNotifyWidget;
+
+class ChangeNotifyButton : public QToolButton
+{
+Q_OBJECT
+
+friend class ChangeNotifyWidget;
+
+public:
+ explicit ChangeNotifyButton(QWidget* parent=0);
+
+ void setNotifier(ChangeNotify*);
+
+public Q_SLOTS:
+ void slotAppend();
+ void slotRemoveRow(int);
+ void slotReset();
+ void slotClicked(bool);
+
+protected:
+ void updateIcon();
+
+ ChangeNotify* notifier_;
+ QLinearGradient grad_;
+};
+
+class ChangeNotifyWidget : public QWidget
+{
+friend class ChangeNotify;
+
+public:
+ explicit ChangeNotifyWidget(QWidget *parent=0);
+ ~ChangeNotifyWidget();
+
+ static void setEnabled(const std::string& id,bool b);
+ static void updateSettings(const std::string& id);
+
+protected:
+ void addTb(ChangeNotify*);
+ ChangeNotifyButton* findButton(const std::string& id);
+
+ QHBoxLayout* layout_;
+ std::map<std::string,ChangeNotifyButton*> buttons_;
+ static std::vector<ChangeNotifyWidget*> widgets_;
+};
+
+#endif /* VIEWER_SRC_CHANGENOTIFYWIDGET_HPP_ */
diff --git a/Viewer/src/CodeItemWidget.cpp b/Viewer/src/CodeItemWidget.cpp
new file mode 100644
index 0000000..76318ed
--- /dev/null
+++ b/Viewer/src/CodeItemWidget.cpp
@@ -0,0 +1,70 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "CodeItemWidget.hpp"
+
+#include <QDebug>
+#include <QFontDatabase>
+
+CodeItemWidget::CodeItemWidget(QWidget *parent) :
+ QWidget(parent)
+{
+ setupUi(this);
+
+ externalTb_->hide();
+
+ fileLabel_->setProperty("fileInfo","1");
+
+ searchLine_->setEditor(textEdit_);
+
+ searchLine_->setVisible(false);
+}
+
+CodeItemWidget::~CodeItemWidget()
+{
+}
+
+void CodeItemWidget::removeSpacer()
+{
+ //Remove the first spcer item!!
+ for(int i=0; horizontalLayout->count(); i++)
+ {
+ if(QSpacerItem* sp=horizontalLayout->itemAt(i)->spacerItem())
+ {
+ horizontalLayout->takeAt(i);
+ delete sp;
+ break;
+ }
+ }
+}
+
+void CodeItemWidget::on_searchTb__clicked()
+{
+ searchLine_->setVisible(true);
+ searchLine_->setFocus();
+ searchLine_->selectAll();
+}
+
+void CodeItemWidget::on_gotoLineTb__clicked()
+{
+ textEdit_->gotoLine();
+}
+
+void CodeItemWidget::on_fontSizeUpTb__clicked()
+{
+ //We need to call a custom slot here instead of "zoomIn"!!!
+ textEdit_->slotZoomIn();
+}
+
+void CodeItemWidget::on_fontSizeDownTb__clicked()
+{
+ //We need to call a custom slot here instead of "zoomOut"!!!
+ textEdit_->slotZoomOut();
+}
diff --git a/Viewer/src/CodeItemWidget.hpp b/Viewer/src/CodeItemWidget.hpp
new file mode 100644
index 0000000..0f2b839
--- /dev/null
+++ b/Viewer/src/CodeItemWidget.hpp
@@ -0,0 +1,40 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef CODEITEMWIDGET_HPP_
+#define CODEITEMWIDGET_HPP_
+
+#include <QWidget>
+
+#include "ui_CodeItemWidget.h"
+
+class CodeItemWidget : public QWidget, protected Ui::CodeItemWidget
+{
+Q_OBJECT
+
+public:
+ explicit CodeItemWidget(QWidget *parent=0);
+ ~CodeItemWidget();
+
+protected Q_SLOTS:
+ void on_searchTb__clicked();
+ void on_gotoLineTb__clicked();
+ void on_fontSizeUpTb__clicked();
+ void on_fontSizeDownTb__clicked();
+
+Q_SIGNALS:
+ void editorFontSizeChanged();
+
+protected:
+ void removeSpacer();
+};
+
+#endif
+
diff --git a/Viewer/src/CodeItemWidget.ui b/Viewer/src/CodeItemWidget.ui
new file mode 100644
index 0000000..3cfdc32
--- /dev/null
+++ b/Viewer/src/CodeItemWidget.ui
@@ -0,0 +1,204 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CodeItemWidget</class>
+ <widget class="QWidget" name="CodeItemWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>510</width>
+ <height>465</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="spacing">
+ <number>1</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0,0,0,0,0,0">
+ <property name="spacing">
+ <number>1</number>
+ </property>
+ <item>
+ <widget class="FileInfoLabel" name="fileLabel_">
+ <property name="autoFillBackground">
+ <bool>false</bool>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="margin">
+ <number>2</number>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QToolButton" name="fontSizeUpTb_">
+ <property name="toolTip">
+ <string>Increase font size in text browser <br><code>Ctrl++ or Ctrl+wheel</code></string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/fontsize_up.svg</normaloff>:/viewer/fontsize_up.svg</iconset>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl++</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="fontSizeDownTb_">
+ <property name="toolTip">
+ <string>Decrease font size in text browser <br><code>Ctrl+- or Ctrl+wheel</code></string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/fontsize_down.svg</normaloff>:/viewer/fontsize_down.svg</iconset>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+-</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="externalTb_">
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="searchTb_">
+ <property name="toolTip">
+ <string>Show search bar (CTRL-F)</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/search_decor.svg</normaloff>:/viewer/search_decor.svg</iconset>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+F</string>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="gotoLineTb_">
+ <property name="toolTip">
+ <string>Goto line number (CTRL-L)</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/images/goto_line.svg</normaloff>:/viewer/images/goto_line.svg</iconset>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+L</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="MessageLabel" name="messageLabel_" native="true"/>
+ </item>
+ <item>
+ <widget class="PlainTextEdit" name="textEdit_">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="lineWrapMode">
+ <enum>QPlainTextEdit::NoWrap</enum>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="PlainTextSearchLine" name="searchLine_" native="true"/>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>PlainTextSearchLine</class>
+ <extends>QWidget</extends>
+ <header>PlainTextSearchLine.hpp</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>PlainTextEdit</class>
+ <extends>QPlainTextEdit</extends>
+ <header>PlainTextEdit.hpp</header>
+ </customwidget>
+ <customwidget>
+ <class>MessageLabel</class>
+ <extends>QWidget</extends>
+ <header>MessageLabel.hpp</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>FileInfoLabel</class>
+ <extends>QLabel</extends>
+ <header>FileInfoLabel.hpp</header>
+ </customwidget>
+ </customwidgets>
+ <resources>
+ <include location="viewer.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/Viewer/src/ComboMulti.cpp b/Viewer/src/ComboMulti.cpp
new file mode 100644
index 0000000..89c8e1f
--- /dev/null
+++ b/Viewer/src/ComboMulti.cpp
@@ -0,0 +1,269 @@
+#include "ComboMulti.hpp"
+
+#include <QApplication>
+#include <QAbstractItemView>
+#include <QDebug>
+#include <QCheckBox>
+#include <QItemDelegate>
+#include <QPainter>
+#include <QStylePainter>
+
+//==========================================================
+//
+// ComboMulti
+//
+//==========================================================
+
+ComboMulti::ComboMulti(QWidget *widget) :
+ QComboBox(widget),
+ mode_(BasicMode),
+ dpyText_("")
+{
+ setSizeAdjustPolicy(QComboBox::AdjustToContents);
+
+ ComboMultiDelegate* del=new ComboMultiDelegate(this);
+
+ connect(del,SIGNAL(itemChecked()),
+ this,SLOT(slotChecked()));
+
+ // set delegate items view
+ view()->setItemDelegate(del);
+ //view()->setStyleSheet(" padding: 15px; ");
+ // Enable editing on items view
+ view()->setEditTriggers(QAbstractItemView::CurrentChanged);
+
+ // set "CheckBoxList::eventFilter" as event filter for items view
+ view()->viewport()->installEventFilter(this);
+
+ // it just cool to have it as defualt ;)
+ view()->setAlternatingRowColors(true);
+}
+
+
+ComboMulti::~ComboMulti()
+{
+
+}
+
+bool ComboMulti::eventFilter(QObject *object, QEvent *event)
+{
+ // don't close items view after we release the mouse button
+ // by simple eating MouseButtonRelease in viewport of items view
+ if(event->type() == QEvent::MouseButtonRelease && object==view()->viewport())
+ {
+ return true;
+ }
+ return QComboBox::eventFilter(object,event);
+}
+
+void ComboMulti::paintEvent(QPaintEvent *)
+{
+ QStylePainter painter(this);
+ painter.setPen(palette().color(QPalette::Text));
+
+ // draw the combobox frame, focusrect and selected etc.
+ QStyleOptionComboBox opt;
+ initStyleOption(&opt);
+
+ // if no display text been set , use "..." as default
+ if(dpyText_.isEmpty())
+ if(mode_ == FilterMode)
+ opt.currentText = "ALL";
+ else
+ opt.currentText="NONE";
+ else
+ {
+ opt.currentText = dpyText_;
+ }
+ painter.drawComplexControl(QStyle::CC_ComboBox, opt);
+
+ // draw the icon and text
+ painter.drawControl(QStyle::CE_ComboBoxLabel, opt);
+
+}
+
+void ComboMulti::slotChecked()
+{
+ QString s;
+ selection_.clear();
+
+ int cnt=0;
+
+ for(int i=0; i < model()->rowCount(); i++)
+ {
+ if(model()->data(model()->index(i,0),Qt::CheckStateRole).toBool())
+ {
+ selection_ << model()->data(model()->index(i,0),Qt::DisplayRole).toString();
+ }
+ }
+
+ if(selection_.count() == 0)
+ s="";
+ else
+ s=selection_.join(", ");
+
+ setDisplayText(s);
+
+ update();
+
+ Q_EMIT selectionChanged();
+}
+
+void ComboMulti::setSelection(QStringList lst)
+{
+ for(int i=0; i < count(); i++)
+ {
+ setItemData(i,false,Qt::CheckStateRole);
+ if(lst.contains(itemText(i)))
+ setItemData(i,true,Qt::CheckStateRole);
+ }
+
+ slotChecked();
+}
+
+void ComboMulti::setSelectionByData(QStringList lst)
+{
+ for(int i=0; i < count(); i++)
+ {
+ setItemData(i,false,Qt::CheckStateRole);
+ if(lst.contains(itemData(i).toString()))
+ setItemData(i,true,Qt::CheckStateRole);
+ }
+
+ slotChecked();
+}
+
+void ComboMulti::clearSelection()
+{
+ for(int i=0; i < count(); i++)
+ {
+ setItemData(i,false,Qt::CheckStateRole);
+ }
+
+ slotChecked();
+}
+
+void ComboMulti::selectSoleItem()
+{
+ if(count() == 1)
+ {
+ setItemData(0,true,Qt::CheckStateRole);
+ slotChecked();
+ }
+}
+
+QStringList ComboMulti::selectionData() const
+{
+ QStringList lst;
+ for(int i=0; i < count(); i++)
+ {
+ if(itemData(i,Qt::CheckStateRole).toBool())
+ lst << itemData(i,Qt::UserRole).toString();
+ }
+ return lst;
+}
+
+void ComboMulti::setDisplayText(QString text)
+{
+ dpyText_ = text;
+}
+
+QString ComboMulti::displayText() const
+{
+ return dpyText_;
+}
+
+QStringList ComboMulti::all() const
+{
+ QStringList lst;
+ for(int i=0; i < count(); i++)
+ lst << itemText(i);
+
+ return lst;
+}
+
+void ComboMulti::setMode(Mode mode)
+{
+ mode_=mode;
+}
+
+
+//==========================================================
+//
+// ComboMultiDelegate
+//
+//==========================================================
+
+ComboMultiDelegate::ComboMultiDelegate(QObject *parent)
+ : QItemDelegate(parent)
+{
+}
+
+void ComboMultiDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
+ const QModelIndex &index) const
+{
+ //Get item data
+ bool value = index.data(Qt::CheckStateRole).toBool();
+ QString text = index.data(Qt::DisplayRole).toString();
+
+ // fill style options with item data
+ const QStyle *style = QApplication::style();
+ QStyleOptionButton opt;
+ opt.state |= value ? QStyle::State_On : QStyle::State_Off;
+ opt.state |= QStyle::State_Enabled;
+ opt.text = text;
+ opt.rect = option.rect;
+
+ style->drawControl(QStyle::CE_CheckBox,&opt,painter);
+}
+
+QWidget* ComboMultiDelegate::createEditor(QWidget *parent,
+ const QStyleOptionViewItem & option ,
+ const QModelIndex & index ) const
+{
+ QCheckBox *editor = new QCheckBox(parent);
+ return editor;
+}
+
+void ComboMultiDelegate::setEditorData(QWidget *editor,
+ const QModelIndex &index) const
+{
+ //set editor data
+ QCheckBox *myEditor = static_cast<QCheckBox*>(editor);
+ myEditor->setText(index.data(Qt::DisplayRole).toString());
+ myEditor->setChecked(index.data(Qt::CheckStateRole).toBool());
+
+ connect(myEditor,SIGNAL(stateChanged(int)),
+ this,SLOT(slotEdited(int)));
+
+}
+
+void ComboMultiDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
+ const QModelIndex &index) const
+{
+ //get the value from the editor (CheckBox)
+ QCheckBox *myEditor = static_cast<QCheckBox*>(editor);
+ bool value = myEditor->isChecked();
+
+ if(model->data(index,Qt::CheckStateRole).toBool() != value)
+ {
+ model->setData(index,value,Qt::CheckStateRole);
+ Q_EMIT itemChecked();
+ }
+
+}
+
+void ComboMultiDelegate::updateEditorGeometry(QWidget *editor,
+ const QStyleOptionViewItem &option, const QModelIndex &index ) const
+{
+ editor->setGeometry(option.rect);
+}
+
+void ComboMultiDelegate::slotEdited(int)
+{
+ QCheckBox* cb = static_cast<QCheckBox*>(sender());
+ if(cb)
+ {
+ Q_EMIT commitData(cb);
+ }
+}
diff --git a/Viewer/src/ComboMulti.hpp b/Viewer/src/ComboMulti.hpp
new file mode 100644
index 0000000..6e9221a
--- /dev/null
+++ b/Viewer/src/ComboMulti.hpp
@@ -0,0 +1,71 @@
+#ifndef COMBOMULTI_HPP_
+#define COMBOMULTI_HPP_
+
+#include <QComboBox>
+#include <QItemDelegate>
+
+class ComboMulti: public QComboBox
+{
+Q_OBJECT;
+
+public:
+ enum Mode {BasicMode,FilterMode};
+
+ enum CustomItemRole {SelectRole = Qt::UserRole+1};
+
+ explicit ComboMulti(QWidget *widget = 0);
+ virtual ~ComboMulti();
+ bool eventFilter(QObject *object, QEvent *event);
+ virtual void paintEvent(QPaintEvent *);
+ void setDisplayText(QString text);
+ QString displayText() const;
+ bool hasSelection() const {return !selection_.isEmpty();}
+ QStringList selection() const {return selection_;}
+ QStringList all() const;
+ QStringList selectionData() const;
+ void selectSoleItem();
+ void setSelection(QStringList);
+ void setSelectionByData(QStringList);
+ void setMode(Mode);
+
+public Q_SLOTS:
+ void slotChecked();
+ void clearSelection();
+
+Q_SIGNALS:
+ void selectionChanged();
+
+private:
+ Mode mode_;
+ bool elide_;
+ QString dpyText_;
+ QStringList selection_;
+};
+
+class ComboMultiDelegate : public QItemDelegate
+{
+Q_OBJECT
+
+public:
+ explicit ComboMultiDelegate(QObject *parent);
+
+ void paint(QPainter *painter, const QStyleOptionViewItem &option,
+ const QModelIndex &index) const;
+
+ QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem & option,
+ const QModelIndex & index ) const;
+
+ void setEditorData(QWidget *editor,const QModelIndex &index) const;
+ void setModelData(QWidget *editor, QAbstractItemModel *model,const QModelIndex &index) const;
+ void updateEditorGeometry(QWidget *editor,const QStyleOptionViewItem &option, const QModelIndex &index ) const;
+
+protected Q_SLOTS:
+ void slotEdited(int);
+
+Q_SIGNALS:
+ void itemChecked() const;
+};
+
+
+#endif
+
diff --git a/Viewer/src/CommandDesignerWidget.cpp b/Viewer/src/CommandDesignerWidget.cpp
new file mode 100644
index 0000000..a1d5eb3
--- /dev/null
+++ b/Viewer/src/CommandDesignerWidget.cpp
@@ -0,0 +1,656 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include <boost/bind.hpp>
+
+#include <QMessageBox>
+
+#include "CommandDesignerWidget.hpp"
+#include "CustomCommandHandler.hpp"
+#include "Child.hpp"
+#include "Str.hpp"
+#include "MenuHandler.hpp"
+#include "NodeQueryResult.hpp"
+
+using namespace boost;
+namespace po = boost::program_options;
+
+
+CommandDesignerWidget::CommandDesignerWidget(QWidget *parent) : QWidget(parent)
+{
+ setupUi(this);
+
+
+ //at least for now, all commands will start with 'ecflow_client' and end with '<full_name>'
+ commandLineEdit_->setText("ecflow_client <full_name>");
+ //commandLineEdit_->installEventFilter(this);
+ commandLineEdit_->setFocus();
+
+ haveSetUpDefaultCommandLine_ = false;
+ inCommandEditMode_ = false;
+ saveCommandsOnExit_ = false;
+
+ addToContextMenuCb_->setChecked(true); // by default, suggest saving to context menu
+
+ // ensure the Save button is in the right state
+ on_commandLineEdit__textChanged();
+
+ saveNameLineEdit_->setPlaceholderText(tr("Unnamed"));
+
+ currentCommandSaved_ = false;
+ refreshSavedCommandList();
+
+
+ setSaveOptionsState(false, true);
+
+
+ // ensure we start on the command-builder tab
+ changeToTab(TAB_BUILD);
+ on_tabWidget__currentChanged(TAB_BUILD); // trigger the callback to ensure the correct visibility of the save buttons
+
+ // set up and populate our list of options to the ecflow client
+ // - this would be more efficient if we did it only once, in a singleton, but
+ // it seems pretty fast so we'll leave it like this for now
+ initialiseComponentListDetails();
+ clientOptionsDescriptions_ = new po::options_description("help" , po::options_description::m_default_line_length + 80);
+ cmdRegistry_.addAllOptions(*clientOptionsDescriptions_);
+ addClientCommandsToComponentList();
+
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
+ commandLineEdit_->setClearButtonEnabled(true);
+#endif
+
+
+ infoLabel_->setShowTypeTitle(false);
+ infoLabel_->showInfo(tr("Click command for help, double-click to insert"));
+
+ nodeSelectionView_->enableContextMenu(false);
+
+
+ nodeListLinkLabel_->setOpenExternalLinks(false);
+
+
+ connect(nodeSelectionView_, SIGNAL(selectionChanged()), this, SLOT(on_nodeSelectionChanged()));
+
+
+ setSavedCommandsButtonStatus();
+
+
+ // temporary
+ //saveCommandGroupBox_->setVisible(false);
+ //tabWidget_->setTabEnabled(2, false);
+ //savedCommandsGroupBox_->setVisible(false);
+
+}
+
+CommandDesignerWidget::~CommandDesignerWidget()
+{
+ delete clientOptionsDescriptions_;
+
+ if (saveCommandsOnExit_)
+ CustomSavedCommandHandler::instance()->writeSettings();
+
+ MenuHandler::refreshCustomMenuCommands();
+}
+
+
+void CommandDesignerWidget::initialiseComponentListDetails()
+{
+
+ // we don't want all the available commands to appear in the component list because they
+ // are not all relevant for one reason or another
+
+ componentBlacklist_.clear();
+
+ // The following rely on standard out:
+ componentBlacklist_.push_back("help");
+ componentBlacklist_.push_back("get");
+ componentBlacklist_.push_back("get_state");
+ componentBlacklist_.push_back("ch_suites");
+ componentBlacklist_.push_back("migrate");
+ componentBlacklist_.push_back("ping");
+ componentBlacklist_.push_back("server_version");
+ componentBlacklist_.push_back("stats");
+ componentBlacklist_.push_back("status");
+ componentBlacklist_.push_back("suites");
+ componentBlacklist_.push_back("version");
+ componentBlacklist_.push_back("zombie_get");
+
+ // The following only make sense for a persistent client. (like GUI, python):
+ componentBlacklist_.push_back("news");
+ componentBlacklist_.push_back("sync");
+ componentBlacklist_.push_back("sync_full");
+
+ // The following require a prompt:
+ componentBlacklist_.push_back("delete");
+ componentBlacklist_.push_back("terminate");
+ componentBlacklist_.push_back("halt");
+
+ // The following only make sense in a group:
+ componentBlacklist_.push_back("show");
+ componentBlacklist_.push_back("why");
+}
+
+
+void CommandDesignerWidget::initialiseCommandLine()
+{
+ if (!haveSetUpDefaultCommandLine_)
+ {
+ // put the cursor between the two pre-defined strings - this is where the command will go
+ commandLineEdit_->home(false);
+ commandLineEdit_->setCursorPosition(14);
+ commandLineEdit_->deselect();
+
+ haveSetUpDefaultCommandLine_ = true;
+ }
+}
+
+
+void CommandDesignerWidget::changeToTab(TabIndexes i)
+{
+ tabWidget_->setCurrentIndex(i);
+}
+
+
+void CommandDesignerWidget::setNodes(std::vector<VInfo_ptr> &nodes)
+{
+ nodes_ = nodes;
+
+
+ // populate the list of nodes
+ nodeSelectionView_->setSourceModel(&nodeModel_);
+ nodeModel_.slotBeginReset();
+ nodeModel_.data()->add(nodes);
+ nodeModel_.slotEndReset();
+
+ // all should be selected at first
+ nodeSelectionView_->selectAll();
+
+
+ on_nodeSelectionChanged(); // get the number of selected nodes and act accordingly
+}
+
+
+
+// when the user clicks on the hyperlinked label which tells them how many nodes
+// will be acted on, we want to switch to the Nodes tab
+void CommandDesignerWidget::on_nodeListLinkLabel__linkActivated(const QString &link)
+{
+ if (link == "#nodes")
+ {
+ changeToTab(TAB_NODES);
+ }
+}
+
+
+void CommandDesignerWidget::setNodeNumberLinkText(int numNodes)
+{
+ QString s;
+
+ s = (numNodes == 1) ? "" : "s";
+
+ nodeListLinkLabel_->setText(tr("Command will be run on %1 node%2: <a href=\"#nodes\">click here for list</a>").arg(numNodes).arg(s));
+}
+
+// triggered when the user changes their node selection
+void CommandDesignerWidget::on_nodeSelectionChanged()
+{
+ setNodeNumberLinkText(selectedNodes().size());
+ on_commandLineEdit__textChanged(); // trigger the enabling/disabling of the Run button
+}
+
+
+std::vector<VInfo_ptr> &CommandDesignerWidget::selectedNodes()
+{
+ nodeSelectionView_->getListOfSelectedNodes(nodes_);
+ return nodes_;
+}
+
+
+void CommandDesignerWidget::addClientCommandsToComponentList()
+{
+ // sort the commands into alphabetical order
+ std::vector< boost::shared_ptr<po::option_description> > options = clientOptionsDescriptions_->options();
+
+ std::sort(options.begin(),options.end(),
+ boost::bind(std::less<std::string>(),
+ boost::bind(&po::option_description::long_name,_1),
+ boost::bind(&po::option_description::long_name,_2)));
+
+ // loop through the sorted commands and add them to the list
+ size_t numOptions = options.size();
+
+ for(size_t i = 0; i < numOptions; i++)
+ {
+ std::string longName(options[i]->long_name());
+ if (!ecf::Child::valid_child_cmd(longName)) // do not show the 'child' options
+ {
+ if (std::find(componentBlacklist_.begin(), componentBlacklist_.end(), longName) == componentBlacklist_.end()) // not in blacklist?
+ {
+ componentsList_->addItem(QString("--") + QString::fromStdString(longName));
+ QString statusTip(QString::fromStdString(longName));
+ componentsList_->item(componentsList_->count()-1)->setStatusTip(statusTip);
+ }
+ }
+ }
+
+ // ensure the itemEntered slot is triggered
+ componentsList_->setMouseTracking(true);
+
+ // when the mouse hovers over an item, set the background colour of that item
+ componentsList_->setStyleSheet("QListWidget::item:hover {background-color:#FFFFDD;color:black}");
+}
+
+
+void CommandDesignerWidget::showCommandHelp(QListWidgetItem *item, bool showFullHelp)
+{
+ // get the command name
+ QString qCommand(item->text());
+ std::string command = qCommand.toStdString();
+ ecf::Str::replace_all(command, "--", ""); // remove the "--" from the start
+
+
+ // try to find it in our list of commands
+ const po::option_description* od = clientOptionsDescriptions_->find_nothrow(command,
+ false, /*approx, will find nearest match*/
+ false, /*long_ignore_case = false*/
+ false /*short_ignore_case = false*/
+ );
+
+ if (od)
+ {
+ // get the description, but only take the first line
+ std::vector< std::string > lines;
+ ecf::Str::split(od->description(),lines,"\n");
+ if (!lines.empty())
+ {
+ QString text = qCommand + QString(": ");
+ commandHelpLabel_->setText(text + QString::fromStdString(lines[0]));
+ }
+
+ if (showFullHelp)
+ {
+ commandManPage_->setText(qCommand + "\n\n" + QString::fromStdString(od->description()));
+ }
+ }
+ else
+ {
+ // not a command that we have help text for
+ commandHelpLabel_->setText("");
+ }
+}
+
+
+void CommandDesignerWidget::on_tabWidget__currentChanged(int index)
+{
+ //bool onSaveTab = (index == TAB_SAVE);
+ //saveCommandGroupBox_->setVisible(onSaveTab);
+ //saveOptionsButton_->setVisible(!onSaveTab);
+}
+
+
+
+// when the mouse moves over a command, display the help text for it
+void CommandDesignerWidget::on_componentsList__itemEntered(QListWidgetItem *item)
+{
+ showCommandHelp(item, false);
+ initialiseCommandLine();
+}
+
+// when the mouse is clicked on a command, display the help text for it
+void CommandDesignerWidget::on_componentsList__itemClicked(QListWidgetItem *item)
+{
+ showCommandHelp(item, true);
+ commandLineEdit_->setFocus(); // to keep the text cursor visible
+}
+
+// when the mouse is double-clicked on a command, insert it into the command line box
+void CommandDesignerWidget::on_componentsList__itemDoubleClicked(QListWidgetItem *item)
+{
+ insertComponent(item);
+ commandLineEdit_->setFocus(); // to keep the text cursor visible
+}
+
+
+void CommandDesignerWidget::insertComponent(QListWidgetItem *item)
+{
+ commandLineEdit_->insert(item->text() + " ");
+}
+
+
+
+void CommandDesignerWidget::on_commandLineEdit__textChanged()
+{
+ // only allow to run a non-empty command, and on 1 or more nodes
+ runButton_->setEnabled((!commandLineEdit_->text().isEmpty()) && nodes_.size() > 0);
+
+ currentCommandSaved_ = false;
+ updateSaveButtonStatus();
+}
+
+void CommandDesignerWidget::on_saveNameLineEdit__textChanged()
+{
+ currentCommandSaved_ = false;
+ updateSaveButtonStatus();
+}
+
+void CommandDesignerWidget::on_addToContextMenuCb__stateChanged()
+{
+ currentCommandSaved_ = false;
+ updateSaveButtonStatus();
+}
+
+
+void CommandDesignerWidget::updateSaveButtonStatus()
+{
+ // inCommandEditMode_ means we're editing a command from the saved list
+ if (inCommandEditMode_)
+ {
+ overwriteButton_->setEnabled(true);
+ saveAsNewButton_->setEnabled(false);
+ }
+ else
+ {
+ overwriteButton_->setEnabled(false);
+ saveAsNewButton_->setEnabled(true);
+ }
+
+ // the cancel button is only available if we're in edit mode
+ cancelSaveButton_->setEnabled(inCommandEditMode_);
+}
+
+
+void CommandDesignerWidget::setSavedCommandsButtonStatus()
+{
+ int row = savedCommandsTable_->currentRow();
+ bool isRowSelected = (row != -1);
+ deleteCommandButton_ ->setEnabled(isRowSelected);
+ editCommandButton_ ->setEnabled(isRowSelected);
+ duplicateCommandButton_->setEnabled(isRowSelected);
+ useCommandButton_ ->setEnabled(isRowSelected);
+
+ upButton_ ->setEnabled(isRowSelected && row != 0); // not the first row
+ downButton_->setEnabled(isRowSelected && row != savedCommandsTable_->rowCount()-1); // not the last row
+}
+
+
+bool CommandDesignerWidget::validSaveName(const std::string &name)
+{
+ // name empty?
+ if (name.empty())
+ {
+ QMessageBox::critical(0,QObject::tr("Custom command"), tr("Please enter a name for the command"));
+ return false;
+ }
+
+
+ // is there already a command with this name?
+ int commandWithThisName = CustomSavedCommandHandler::instance()->findIndexFromName(name);
+ bool nameUnique;
+ if (inCommandEditMode_)
+ nameUnique = (commandWithThisName == -1 || commandWithThisName == savedCommandsTable_->currentRow());
+ else
+ nameUnique = (commandWithThisName == -1);
+
+ if (!nameUnique)
+ {
+ QMessageBox::critical(0,QObject::tr("Custom command"), tr("A command with that name already exists - please choose another name"));
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
+
+void CommandDesignerWidget::selectRow(int row)
+{
+ savedCommandsTable_->setCurrentCell(row, 0);
+}
+
+
+void CommandDesignerWidget::selectLastSavedCommand()
+{
+ int lastRow = savedCommandsTable_->rowCount()-1;
+ selectRow(lastRow);
+}
+
+// swap the commands in these two positions and select the one which will end up in the second position
+void CommandDesignerWidget::swapSavedCommands(int i1, int i2)
+{
+ CustomSavedCommandHandler::instance()->swapCommandsByIndex(i1, i2);
+ refreshSavedCommandList();
+ selectRow(i2);
+ setSavedCommandsButtonStatus();
+ saveCommandsOnExit_ = true; // we won't save the commands yet, but mark for save on exit
+}
+
+
+void CommandDesignerWidget::on_saveAsNewButton__clicked()
+{
+ std::string name, command;
+ bool context;
+
+ name = saveNameLineEdit_->text().toStdString();
+ command = commandLineEdit_->text().toStdString();
+ context = addToContextMenuCb_->isChecked();
+
+ if (validSaveName(name))
+ {
+ CustomCommand *cmd = CustomSavedCommandHandler::instance()->add(name, command, context, true);
+ refreshSavedCommandList();
+ currentCommandSaved_ = true;
+ updateSaveButtonStatus();
+ changeToTab(TAB_SAVE);
+ selectLastSavedCommand();
+ setSavedCommandsButtonStatus();
+ setSaveOptionsState(true, true);
+ }
+}
+
+void CommandDesignerWidget::on_overwriteButton__clicked()
+{
+ std::string name, command;
+ bool context;
+
+ name = saveNameLineEdit_->text().toStdString();
+ command = commandLineEdit_->text().toStdString();
+ context = addToContextMenuCb_->isChecked();
+
+ if (validSaveName(name))
+ {
+ CustomCommand *cmd = CustomSavedCommandHandler::instance()->replace(savedCommandsTable_->currentRow(), name, command, context);
+ savedCommandsTable_->setEnabled(true); // to show that we are no longer busy editing an entry
+ inCommandEditMode_ = false;
+ refreshSavedCommandList();
+ currentCommandSaved_ = true;
+ updateSaveButtonStatus();
+ setSaveOptionsState(true, true);
+ }
+}
+
+
+void CommandDesignerWidget::on_runButton__clicked()
+{
+ std::string command = commandLineEdit_->text().toStdString();
+
+ // save this in the command history
+ CustomCommandHistoryHandler::instance()->add(command, command, true, true);
+
+
+ // close the dialogue - the calling function will call the command() function
+ // to retrieve the user's command
+ //accept();
+}
+
+void CommandDesignerWidget::setSaveOptionsState(bool optionsVisible, bool saveOptionsButtonEnabled)
+{
+ // we just switch to the Saved Commands tab
+ //changeToTab(TAB_SAVE);
+
+ saveCommandGroupBox_->setVisible(optionsVisible);
+ QString buttonText = (optionsVisible) ? "Save Options <<" : "Save Options >>";
+ saveOptionsButton_->setText(buttonText);
+ saveOptionsVisible_ = optionsVisible;
+ saveOptionsButton_->setEnabled(saveOptionsButtonEnabled);
+}
+
+
+void CommandDesignerWidget::on_saveOptionsButton__clicked()
+{
+ setSaveOptionsState(!saveOptionsVisible_, true);
+
+ // we just switch to the Saved Commands tab
+ //changeToTab(TAB_SAVE);
+}
+
+
+void CommandDesignerWidget::on_useCommandButton__clicked()
+{
+ // just put the command into the command edit box
+ int row = savedCommandsTable_->currentRow();
+ QTableWidgetItem *commandItem = savedCommandsTable_->item(row, 2);
+ commandLineEdit_->setText(commandItem->text());
+}
+
+
+void CommandDesignerWidget::on_editCommandButton__clicked()
+{
+ int row = savedCommandsTable_->currentRow();
+
+ // get the details of this command from the table
+ QTableWidgetItem *nameItem = savedCommandsTable_->item(row, 0);
+ QTableWidgetItem *contextItem = savedCommandsTable_->item(row, 1);
+ QTableWidgetItem *commandItem = savedCommandsTable_->item(row, 2);
+
+
+ inCommandEditMode_ = true;
+
+ // insert the details into the edit boxes
+ commandLineEdit_->setText(commandItem->text());
+ saveNameLineEdit_->setText(nameItem->text());
+ std::string context = contextItem->text().toStdString();
+ addToContextMenuCb_->setChecked(CustomSavedCommandHandler::instance()->stringToBool(context));
+
+ savedCommandsTable_ ->setEnabled(false); // to show that we are busy editing an entry
+ deleteCommandButton_ ->setEnabled(false); // to show that we are busy editing an entry
+ editCommandButton_ ->setEnabled(false); // to show that we are busy editing an entry
+ duplicateCommandButton_->setEnabled(false); // to show that we are busy editing an entry
+ useCommandButton_ ->setEnabled(false); // to show that we are busy editing an entry
+ upButton_ ->setEnabled(false); // to show that we are busy editing an entry
+ downButton_ ->setEnabled(false); // to show that we are busy editing an entry
+
+ updateSaveButtonStatus();
+
+ // users should have the Save Options visible
+ setSaveOptionsState(true, false);
+}
+
+
+void CommandDesignerWidget::on_savedCommandsTable__cellDoubleClicked(int row, int column)
+{
+ on_editCommandButton__clicked(); // same as selecting a cell and clicking 'edit'
+}
+
+void CommandDesignerWidget::on_duplicateCommandButton__clicked()
+{
+ CustomSavedCommandHandler::instance()->duplicate(savedCommandsTable_->currentRow());
+ refreshSavedCommandList();
+}
+
+
+void CommandDesignerWidget::on_deleteCommandButton__clicked()
+{
+ CustomSavedCommandHandler::instance()->remove(savedCommandsTable_->currentRow());
+ refreshSavedCommandList();
+}
+
+void CommandDesignerWidget::on_upButton__clicked()
+{
+ int row = savedCommandsTable_->currentRow();
+ swapSavedCommands(row, row-1);
+}
+
+void CommandDesignerWidget::on_downButton__clicked()
+{
+ int row = savedCommandsTable_->currentRow();
+ swapSavedCommands(row, row+1);
+}
+
+
+void CommandDesignerWidget::on_cancelSaveButton__clicked()
+{
+ savedCommandsTable_->setEnabled(true); // to show that we are no longer busy editing an entry
+ inCommandEditMode_ = false;
+ updateSaveButtonStatus();
+ refreshSavedCommandList();
+ setSaveOptionsState(true, true);
+}
+
+
+void CommandDesignerWidget::refreshSavedCommandList()
+{
+ int n = CustomSavedCommandHandler::instance()->numCommands();
+
+ savedCommandsTable_->clearContents();
+
+ for (int i = 0; i < n; i++)
+ {
+ CustomCommand *command = CustomSavedCommandHandler::instance()->commandFromIndex(i);
+ addCommandToSavedList(command, i);
+ }
+ savedCommandsTable_->setRowCount(n);
+ setSavedCommandsButtonStatus();
+}
+
+
+void CommandDesignerWidget::addCommandToSavedList(CustomCommand *command, int row)
+{
+ QTableWidgetItem *nameItem = new QTableWidgetItem(QString::fromStdString(command->name()));
+ QTableWidgetItem *contextItem = new QTableWidgetItem(QString::fromStdString(command->contextString()));
+ QTableWidgetItem *commandItem = new QTableWidgetItem(QString::fromStdString(command->command()));
+
+ // if the command already exists (by name) then we will replaced it;
+ // otherwise add a new row to the table
+
+// int thisRow = CustomCommandHandler::instance()->findIndex(command->name());
+// if (thisRow == -1)
+// thisRow = savedCommandsTable_->rowCount();
+
+ //contextItem->setCheckable();
+
+ int lastRow = savedCommandsTable_->rowCount()-1;
+
+ if (row > lastRow)
+ savedCommandsTable_->insertRow(row);
+
+ savedCommandsTable_->setItem(row, 0, nameItem);
+ savedCommandsTable_->setItem(row, 1, contextItem);
+ savedCommandsTable_->setItem(row, 2, commandItem);
+}
+
+
+void CommandDesignerWidget::on_savedCommandsTable__cellClicked(int row, int column)
+{
+ setSavedCommandsButtonStatus();
+}
+
+
+/*
+bool CommandDesignerWidget::eventFilter(QObject* object, QEvent* event)
+{
+ if(object == commandLineEdit_ && event->type() == QEvent::FocusIn)
+ {
+ initialiseCommandLine();
+ return false;
+ }
+ return false;
+}
+*/
diff --git a/Viewer/src/CommandDesignerWidget.hpp b/Viewer/src/CommandDesignerWidget.hpp
new file mode 100644
index 0000000..c10c333
--- /dev/null
+++ b/Viewer/src/CommandDesignerWidget.hpp
@@ -0,0 +1,103 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+
+#ifndef COMMANDDESIGNERWIDGET_HPP_
+#define COMMANDDESIGNERWIDGET_HPP_
+
+#include <QDialog>
+
+class CommandLineEdit;
+
+#include "ui_CommandDesignerWidget.h"
+#include "CustomCommandHandler.hpp"
+#include "NodeQueryResultModel.hpp"
+
+#include "CtsCmdRegistry.hpp"
+
+class CommandDesignerWidget : public QWidget, private Ui::commandDesignerWidget
+{
+ Q_OBJECT
+
+public:
+ explicit CommandDesignerWidget(QWidget *parent = 0);
+ ~CommandDesignerWidget();
+
+ QString command() {return commandLineEdit_->text();};
+ void setNodes(std::vector<VInfo_ptr> &nodes);
+ std::vector<VInfo_ptr> &selectedNodes();
+
+
+
+public Q_SLOTS:
+ void insertComponent(QListWidgetItem *);
+ void on_commandLineEdit__textChanged();
+ void on_saveNameLineEdit__textChanged();
+ void on_addToContextMenuCb__stateChanged();
+ void on_overwriteButton__clicked();
+ void on_saveAsNewButton__clicked();
+ void on_runButton__clicked();
+ void on_saveOptionsButton__clicked();
+ void on_editCommandButton__clicked();
+ void on_useCommandButton__clicked();
+ void on_duplicateCommandButton__clicked();
+ void on_deleteCommandButton__clicked();
+ void on_upButton__clicked();
+ void on_downButton__clicked();
+ void on_cancelSaveButton__clicked();
+ void on_savedCommandsTable__cellClicked(int row, int column);
+ void on_savedCommandsTable__cellDoubleClicked(int row, int column);
+ void on_componentsList__itemEntered(QListWidgetItem *item);
+ void on_componentsList__itemClicked(QListWidgetItem *item);
+ void on_componentsList__itemDoubleClicked(QListWidgetItem *item);
+ void on_nodeListLinkLabel__linkActivated(const QString &link);
+ void on_nodeSelectionChanged();
+ void on_tabWidget__currentChanged(int index);
+ QPushButton *runButton() {return runButton_;};
+
+
+private:
+ enum TabIndexes {TAB_BUILD, TAB_NODES, TAB_SAVE};
+
+ void initialiseComponentListDetails();
+ void updateSaveButtonStatus();
+ void addCommandToSavedList(CustomCommand *command, int row);
+ void refreshSavedCommandList();
+ void addClientCommandsToComponentList();
+ void showCommandHelp(QListWidgetItem *item, bool showFullHelp);
+ void initialiseCommandLine();
+ void setNodeNumberLinkText(int numNodes);
+ void setSavedCommandsButtonStatus();
+ bool validSaveName(const std::string &name);
+ void changeToTab(TabIndexes i);
+ void selectRow(int row);
+ void selectLastSavedCommand();
+ void swapSavedCommands(int i1, int i2);
+ void setSaveOptionsState(bool optionsVisible, bool saveOptionsButtonEnabled);
+
+ //bool eventFilter(QObject* object, QEvent* event);
+
+ bool currentCommandSaved_;
+ bool haveSetUpDefaultCommandLine_;
+ bool inCommandEditMode_;
+ bool saveCommandsOnExit_;
+ bool saveOptionsVisible_;
+ std::vector<std::string> componentBlacklist_;
+
+ std::vector<VInfo_ptr> nodes_;
+ NodeQueryResultModel nodeModel_;
+
+ CtsCmdRegistry cmdRegistry_;
+ boost::program_options::options_description* clientOptionsDescriptions_;
+};
+
+
+
+
+#endif
diff --git a/Viewer/src/CommandDesignerWidget.ui b/Viewer/src/CommandDesignerWidget.ui
new file mode 100644
index 0000000..f63e012
--- /dev/null
+++ b/Viewer/src/CommandDesignerWidget.ui
@@ -0,0 +1,396 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>commandDesignerWidget</class>
+ <widget class="QWidget" name="commandDesignerWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>940</width>
+ <height>579</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_6">
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Components</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QTabWidget" name="tabWidget_">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="buildCommandTab_">
+ <attribute name="title">
+ <string>Build command</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_6">
+ <item>
+ <widget class="MessageLabel" name="infoLabel_" native="true"/>
+ </item>
+ <item>
+ <widget class="QFrame" name="frame">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QListWidget" name="componentsList_">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <item>
+ <property name="text">
+ <string>ecflow_client</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string><node_name></string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string><full_name></string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTextBrowser" name="commandManPage_">
+ <property name="font">
+ <font>
+ <family>Monospace</family>
+ </font>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="commandHelpLabel_">
+ <property name="text">
+ <string>Description</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="NodesTab_">
+ <attribute name="title">
+ <string>Selected Nodes</string>
+ </attribute>
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <item>
+ <widget class="NodeQueryResultView" name="nodeSelectionView_"/>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="savedCommandsTab_">
+ <attribute name="title">
+ <string>Saved commands</string>
+ </attribute>
+ <layout class="QHBoxLayout" name="horizontalLayout_8">
+ <item>
+ <widget class="QTableWidget" name="savedCommandsTable_">
+ <property name="editTriggers">
+ <set>QAbstractItemView::NoEditTriggers</set>
+ </property>
+ <property name="dragEnabled">
+ <bool>true</bool>
+ </property>
+ <property name="dragDropOverwriteMode">
+ <bool>false</bool>
+ </property>
+ <property name="dragDropMode">
+ <enum>QAbstractItemView::NoDragDrop</enum>
+ </property>
+ <property name="defaultDropAction">
+ <enum>Qt::IgnoreAction</enum>
+ </property>
+ <property name="alternatingRowColors">
+ <bool>true</bool>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::SingleSelection</enum>
+ </property>
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ <attribute name="horizontalHeaderStretchLastSection">
+ <bool>true</bool>
+ </attribute>
+ <attribute name="verticalHeaderVisible">
+ <bool>false</bool>
+ </attribute>
+ <attribute name="verticalHeaderHighlightSections">
+ <bool>true</bool>
+ </attribute>
+ <column>
+ <property name="text">
+ <string>Name</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Context menu</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Command</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_5">
+ <item>
+ <widget class="QPushButton" name="useCommandButton_">
+ <property name="text">
+ <string>&Use</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="editCommandButton_">
+ <property name="text">
+ <string>&Edit</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="duplicateCommandButton_">
+ <property name="text">
+ <string>Du&plicate</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="deleteCommandButton_">
+ <property name="text">
+ <string>&Remove</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="upButton_">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/images/arrow_up.svg</normaloff>:/viewer/images/arrow_up.svg</iconset>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="downButton_">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/images/arrow_down.svg</normaloff>:/viewer/images/arrow_down.svg</iconset>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_3">
+ <property name="title">
+ <string>Command</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_5">
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_8">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Command:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="commandLineEdit_"/>
+ </item>
+ <item>
+ <widget class="QPushButton" name="runButton_">
+ <property name="text">
+ <string>&Run</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="saveOptionsButton_">
+ <property name="maximumSize">
+ <size>
+ <width>100</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>&Save ...</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QLabel" name="nodeListLinkLabel_">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string><html><head/><body><p><a href="#nodes"><span style=" text-decoration: underline; color:#0057ae;">Nodes selected</span></a></p></body></html></string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="saveCommandGroupBox_">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>500</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="title">
+ <string/>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Name:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="saveNameLineEdit_"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="addToContextMenuCb_">
+ <property name="text">
+ <string>Add to context menu</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_7">
+ <item>
+ <widget class="QPushButton" name="overwriteButton_">
+ <property name="text">
+ <string>&Save</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="saveAsNewButton_">
+ <property name="text">
+ <string>Save As &New</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="cancelSaveButton_">
+ <property name="text">
+ <string>&Cancel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>MessageLabel</class>
+ <extends>QWidget</extends>
+ <header>MessageLabel.hpp</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>NodeQueryResultView</class>
+ <extends>QTreeView</extends>
+ <header>NodeQueryResultView.hpp</header>
+ </customwidget>
+ </customwidgets>
+ <tabstops>
+ <tabstop>saveNameLineEdit_</tabstop>
+ <tabstop>tabWidget_</tabstop>
+ <tabstop>savedCommandsTable_</tabstop>
+ <tabstop>addToContextMenuCb_</tabstop>
+ <tabstop>saveAsNewButton_</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Viewer/src/ConfigListDelegate.cpp b/Viewer/src/ConfigListDelegate.cpp
new file mode 100644
index 0000000..f6fcbc9
--- /dev/null
+++ b/Viewer/src/ConfigListDelegate.cpp
@@ -0,0 +1,89 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "ConfigListDelegate.hpp"
+
+#include <QApplication>
+#include <QDebug>
+#include <QPainter>
+
+//========================================================
+//
+// VariableViewDelegate
+//
+//========================================================
+
+ConfigListDelegate::ConfigListDelegate(int iconSize,int maxWidth,QWidget *parent) :
+ QStyledItemDelegate(parent),
+ iconSize_(iconSize),
+ maxTextWidth_(maxWidth),
+ margin_(2),
+ gap_(5)
+{
+}
+
+void ConfigListDelegate::paint(QPainter *painter,const QStyleOptionViewItem &option,
+ const QModelIndex& index) const
+{
+ QStyleOptionViewItemV4 vopt(option);
+ initStyleOption(&vopt, index);
+
+ const QStyle *style = vopt.widget ? vopt.widget->style() : QApplication::style();
+ const QWidget* widget = vopt.widget;
+
+ QPixmap pix=index.data(Qt::DecorationRole).value<QPixmap>();
+
+ //Save painter state
+ painter->save();
+
+ //The background rect
+ QRect bgRect=option.rect.adjusted(0,1,0,-1);
+
+ //Paint selection. This should be transparent.
+ if(option.state & QStyle::State_Selected)
+ {
+ painter->fillRect(bgRect,QColor(200,222,250));
+ }
+
+ //pixmap
+ QRect pixRect(bgRect.center().x()-iconSize_/2,bgRect.top()+margin_,iconSize_,iconSize_);
+ painter->drawPixmap(pixRect,pix);
+
+ //text
+ QString text=index.data(Qt::DisplayRole).toString();
+ QFont f;
+ f.setBold(true);
+ QFontMetrics fm(f);
+ int textW=fm.width(text);
+ QRect textRect(bgRect.center().x()-textW/2,pixRect.bottom()+gap_,textW,fm.height());
+
+ painter->drawText(textRect,Qt::AlignHCenter| Qt::AlignVCenter,text);
+
+ //Restore painter state
+ painter->restore();
+
+
+}
+
+QSize ConfigListDelegate::sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index ) const
+{
+ QSize size=QStyledItemDelegate::sizeHint(option,index);
+
+ int w=(maxTextWidth_ > iconSize_)?maxTextWidth_:iconSize_;
+ w+=4;
+
+ QFont f;
+ QFontMetrics fm(f);
+ size=QSize(w,2*margin_+iconSize_+gap_+fm.height()+2);
+
+ return size;
+}
+
+
diff --git a/Viewer/src/ConfigListDelegate.hpp b/Viewer/src/ConfigListDelegate.hpp
new file mode 100644
index 0000000..9908e8d
--- /dev/null
+++ b/Viewer/src/ConfigListDelegate.hpp
@@ -0,0 +1,38 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VIEWER_SRC_CONFIGLISTDELEGATE_HPP_
+#define VIEWER_SRC_CONFIGLISTDELEGATE_HPP_
+
+#include <QBrush>
+#include <QMap>
+#include <QPen>
+#include <QStyledItemDelegate>
+
+#include "TreeView.hpp"
+
+#include <string>
+
+class ConfigListDelegate : public QStyledItemDelegate
+{
+public:
+ explicit ConfigListDelegate(int,int,QWidget *parent=0);
+ void paint(QPainter *painter,const QStyleOptionViewItem &option,
+ const QModelIndex& index) const;
+ QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index ) const;
+
+protected:
+ int iconSize_;
+ int maxTextWidth_;
+ int margin_;
+ int gap_;
+};
+
+#endif /* VIEWER_SRC_CONFIGLISTDELEGATE_HPP_ */
diff --git a/Viewer/src/ConnectState.cpp b/Viewer/src/ConnectState.cpp
new file mode 100644
index 0000000..56e6e1e
--- /dev/null
+++ b/Viewer/src/ConnectState.cpp
@@ -0,0 +1,96 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "ConnectState.hpp"
+
+#include <map>
+
+static std::map<ConnectState::State,std::string> descMap;
+
+ConnectState::ConnectState() :
+ state_(Undef),
+ lastConnect_(0),
+ lastFailed_(0),
+ lastDisconnect_(0)
+{
+ init();
+}
+
+void ConnectState::init()
+{
+ if(descMap.empty())
+ {
+ descMap[Undef]="";
+ descMap[Lost]="Connection to server lost";
+ descMap[Disconnected]="Server is disconnected";
+ descMap[Normal]="Server is connected";
+ }
+}
+
+const std::string& ConnectState::describe() const
+{
+ static std::string empty="";
+
+ std::map<ConnectState::State,std::string>::const_iterator it=descMap.find(state_);
+ if(it != descMap.end())
+ {
+ return it->second;
+ }
+ return empty;
+
+}
+void ConnectState::state(State state)
+{
+ state_=state;
+
+ switch(state_)
+ {
+ case Normal:
+ logConnect();
+ break;
+ case Lost:
+ logFailed();
+ break;
+ case Disconnected:
+ logDisconnect();
+ break;
+ default:
+ break;
+ }
+}
+
+void ConnectState::logConnect()
+{
+ lastConnect_=time(0);
+}
+
+void ConnectState::logFailed()
+{
+ lastFailed_=time(0);
+}
+
+void ConnectState::logDisconnect()
+{
+ lastDisconnect_=time(0);
+}
+
+void ConnectState::errorMessage(const std::string& str)
+{
+ errMsg_=str;
+
+ std::size_t pos = str.find("Client environment:");
+ if(pos != std::string::npos)
+ {
+ shortErrMsg_=str.substr(0,pos);
+ }
+ else
+ {
+ shortErrMsg_=str;
+ }
+}
diff --git a/Viewer/src/ConnectState.hpp b/Viewer/src/ConnectState.hpp
new file mode 100644
index 0000000..1ff8a6b
--- /dev/null
+++ b/Viewer/src/ConnectState.hpp
@@ -0,0 +1,47 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef CONNECTSTATE_HPP_
+#define CONNECTSTATE_HPP_
+
+#include <string>
+#include <ctime>
+
+class ConnectState
+{
+public:
+ ConnectState();
+
+ enum State {Undef,Normal,Disconnected,Lost};
+
+ void state(State state);
+ State state() const {return state_;}
+ const std::string& describe() const;
+ void errorMessage(const std::string&);
+ std::time_t lastConnectTime() const {return lastConnect_;}
+ std::time_t lastLostTime() const {return lastFailed_;}
+ std::time_t lastDisconnectTime() const {return lastDisconnect_;}
+ const std::string& errorMessage() const {return errMsg_;}
+ const std::string& shortErrorMessage() const {return shortErrMsg_;}
+
+protected:
+ void init();
+ void logConnect();
+ void logFailed();
+ void logDisconnect();
+
+ State state_;
+ std::time_t lastConnect_;
+ std::time_t lastFailed_;
+ std::time_t lastDisconnect_;
+ std::string errMsg_;
+ std::string shortErrMsg_;
+};
+
+#endif
diff --git a/Viewer/src/CustomCommandDialog.cpp b/Viewer/src/CustomCommandDialog.cpp
new file mode 100644
index 0000000..ebb4572
--- /dev/null
+++ b/Viewer/src/CustomCommandDialog.cpp
@@ -0,0 +1,20 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "CustomCommandDialog.hpp"
+
+
+CustomCommandDialog::CustomCommandDialog(QWidget *parent)
+{
+ setupUi(this);
+
+ // when the user clicks the 'Run' button, we close the dialog with ACCEPT
+ connect(commandDesigner_->runButton(), SIGNAL(clicked()), this, SLOT(accept()));
+
+}
diff --git a/Viewer/src/CustomCommandDialog.hpp b/Viewer/src/CustomCommandDialog.hpp
new file mode 100644
index 0000000..ca453fc
--- /dev/null
+++ b/Viewer/src/CustomCommandDialog.hpp
@@ -0,0 +1,36 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+
+#ifndef CUSTOMCOMMANDDIALOG_HPP_
+#define CUSTOMCOMMANDDIALOG_HPP_
+
+#include <QDialog>
+
+#include "ui_CustomCommandDialog.h"
+
+class CustomCommandDialog : public QDialog, private Ui::CustomCommandDialog
+{
+ Q_OBJECT
+
+public:
+ explicit CustomCommandDialog(QWidget *parent = 0);
+ ~CustomCommandDialog() {};
+
+ QString command() {return commandDesigner_->command();};
+ void setNodes(std::vector<VInfo_ptr> &nodes) {commandDesigner_->setNodes(nodes);};
+ std::vector<VInfo_ptr> &selectedNodes() {return commandDesigner_->selectedNodes();};
+
+
+
+//public Q_SLOTS:
+// void insertCurrentText();
+};
+
+#endif
diff --git a/Viewer/src/CustomCommandDialog.ui b/Viewer/src/CustomCommandDialog.ui
new file mode 100644
index 0000000..a9ab9b9
--- /dev/null
+++ b/Viewer/src/CustomCommandDialog.ui
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CustomCommandDialog</class>
+ <widget class="QDialog" name="CustomCommandDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>985</width>
+ <height>512</height>
+ </rect>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>369</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="windowTitle">
+ <string>Custom Command Editor</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="CommandDesignerWidget" name="commandDesigner_"/>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox_">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Close</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>CommandDesignerWidget</class>
+ <extends>QLineEdit</extends>
+ <header>CommandDesignerWidget.hpp</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox_</sender>
+ <signal>rejected()</signal>
+ <receiver>CustomCommandDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox_</sender>
+ <signal>accepted()</signal>
+ <receiver>CustomCommandDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/Viewer/src/CustomCommandHandler.cpp b/Viewer/src/CustomCommandHandler.cpp
new file mode 100644
index 0000000..4004557
--- /dev/null
+++ b/Viewer/src/CustomCommandHandler.cpp
@@ -0,0 +1,342 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include <algorithm>
+
+#include "CustomCommandHandler.hpp"
+#include "SessionHandler.hpp"
+
+#include "DirectoryHandler.hpp"
+#include "File.hpp"
+#include "VSettings.hpp"
+
+
+CustomCommand::CustomCommand(const std::string &name, const std::string &command, bool context)
+{
+ name_ = name;
+ command_ = command;
+ inContextMenu_ = context;
+}
+
+
+void CustomCommand::set(const std::string &name, const std::string &command, bool context)
+{
+ name_ = name;
+ command_ = command;
+ inContextMenu_ = context;
+}
+
+
+void CustomCommand::save(VSettings *vs)
+{
+ vs->put("name", name());
+ vs->put("command", command());
+ vs->put("context", contextString());
+}
+
+
+
+CustomCommandHandler::CustomCommandHandler()
+{
+}
+
+
+void CustomCommandHandler::init()
+{
+ readSettings();
+}
+
+
+
+
+CustomCommand* CustomCommandHandler::replace(int index, const std::string& name, const std::string& command, bool context)
+{
+ assert(index >= 0);
+ assert(index < items_.size());
+
+ CustomCommand *item;
+
+ // already in the list - just update it
+ item = items_[index];
+ item->set(name, command, context);
+
+ writeSettings();
+
+ return item;
+}
+
+CustomCommand* CustomCommandHandler::replace(int index, const CustomCommand &cmd)
+{
+ replace(index, cmd.name(), cmd.command(), cmd.inContextMenu());
+}
+
+
+
+void CustomCommandHandler::remove(int index)
+{
+ assert(index >= 0);
+ assert(index < items_.size());
+
+ items_.erase(items_.begin()+index);
+
+ writeSettings();
+}
+
+CustomCommand* CustomCommandHandler::duplicate(int index)
+{
+ assert(index >= 0);
+ assert(index < items_.size());
+
+ CustomCommand *item = items_[index];
+ std::string postfix("_1");
+ std::string newName = item->name() + postfix;
+
+ // ensure we are creating a unique new name - if we find an existing item with the same name, add another postfix
+ while(find(newName) != NULL)
+ newName += postfix;
+
+ CustomCommand*newCmd = add(newName, item->command(), item->inContextMenu(), false);
+
+ writeSettings();
+}
+
+void CustomCommandHandler::swapCommandsByIndex(int i1, int i2)
+{
+ assert(i1 >= 0);
+ assert(i1 < items_.size());
+ assert(i2 >= 0);
+ assert(i2 < items_.size());
+
+ CustomCommand *temp = items_[i2];
+ items_[i2] = items_[i1];
+ items_[i1] = temp;
+}
+
+
+CustomCommand* CustomCommandHandler::find(const std::string& name) const
+{
+ for(std::deque<CustomCommand*>::const_iterator it=items_.begin(); it != items_.end(); ++it)
+ {
+ if((*it)->name() == name)
+ return *it;
+ }
+ return NULL;
+}
+
+
+// find the index of the command which has the given name; -1 if not found
+int CustomCommandHandler::findIndexFromName(const std::string& name) const
+{
+ int i = 0;
+ for(std::deque<CustomCommand*>::const_iterator it=items_.begin(); it != items_.end(); ++it)
+ {
+ if((*it)->name() == name)
+ return i;
+ i++;
+ }
+ return -1; // it was not found
+}
+
+
+void CustomCommandHandler::writeSettings()
+{
+ std::vector<VSettings> vsItems;
+ std::string dummyFileName="dummy";
+ std::string key="commands";
+
+ std::string settingsFilePath = settingsFile();
+ VSettings vs(settingsFilePath);
+
+ for(int i = 0; i < numCommands(); i++)
+ {
+ VSettings vsThisItem(dummyFileName);
+ CustomCommand *cmd = commandFromIndex(i);
+ cmd->save(&vsThisItem);
+ vsItems.push_back(vsThisItem);
+ }
+ vs.put(key,vsItems);
+ vs.write();
+}
+
+void CustomCommandHandler::readSettings()
+{
+ std::vector<VSettings> vsItems;
+ std::string dummyFileName="dummy";
+ std::string key="commands";
+
+ std::string settingsFilePath = settingsFile();
+ VSettings vs(settingsFilePath);
+
+ bool ok = vs.read(false); // false means we don't abort if the file is not there
+
+ if (ok)
+ {
+ std::vector<VSettings> commands;
+ vs.get("commands", commands);
+
+ for (int i = 0; i < commands.size(); i++)
+ {
+ VSettings *vsCommand = &commands[i];
+ std::string emptyDefault="";
+ std::string name = vsCommand->get("name", emptyDefault);
+ std::string command = vsCommand->get("command", emptyDefault);
+ std::string context = vsCommand->get("context", emptyDefault);
+ add(name, command, stringToBool(context), false); // add it to our in-memory list
+ }
+ }
+}
+
+bool CustomCommandHandler::stringToBool(std::string &str)
+{
+ bool result = (!str.empty() && str == "yes");
+ return result;
+}
+
+
+// -------------------------
+// CustomSavedCommandHandler
+// -------------------------
+
+CustomSavedCommandHandler* CustomSavedCommandHandler::instance_=0;
+
+
+CustomSavedCommandHandler* CustomSavedCommandHandler::instance()
+{
+ if(!instance_)
+ {
+ instance_=new CustomSavedCommandHandler();
+ }
+
+ return instance_;
+}
+
+CustomCommand* CustomSavedCommandHandler::add(const std::string& name, const std::string& command, bool context, bool saveSettings)
+{
+ CustomCommand *item;
+ //int index = findIndex(name);
+
+ //if (index == -1) // not already in the list
+ {
+ item=new CustomCommand(name, command, context);
+ items_.push_back(item);
+ }
+ //else // already in the list - just update it
+ //{
+ // item = items_[index];
+ // item->set(name, command, context);
+ //}
+
+ if (saveSettings)
+ writeSettings();
+
+ return item;
+}
+
+std::string CustomSavedCommandHandler::settingsFile()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ return cs->savedCustomCommandsFile();
+}
+
+
+// ---------------------------
+// CustomCommandHistoryHandler
+// ---------------------------
+
+
+CustomCommandHistoryHandler* CustomCommandHistoryHandler::instance_=0;
+
+CustomCommandHistoryHandler::CustomCommandHistoryHandler()
+{
+ maxCommands_ = 10;
+}
+
+
+CustomCommandHistoryHandler* CustomCommandHistoryHandler::instance()
+{
+ if(!instance_)
+ {
+ instance_=new CustomCommandHistoryHandler();
+ }
+
+ return instance_;
+}
+
+
+CustomCommand* CustomCommandHistoryHandler::add(const std::string& name, const std::string& command, bool context, bool saveSettings)
+{
+ CustomCommand *item;
+ int index = findIndexFromName(name);
+
+ if (index == -1) // not already in the list
+ {
+ item=new CustomCommand(name, command, context);
+ items_.push_front(item); // add it to the front
+
+ if (items_.size() > maxCommands_) // too many commands?
+ {
+ items_.pop_back(); // remove the last item
+ }
+
+ if (saveSettings)
+ writeSettings();
+
+ return item;
+ }
+ else
+ {
+ return commandFromIndex(index);
+ }
+
+}
+
+std::string CustomCommandHistoryHandler::settingsFile()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ return cs->recentCustomCommandsFile();
+}
+
+
+/*
+void NodeQueryHandler::add(NodeQuery* item,bool saveToFile)
+{
+ items_.push_back(item);
+ if(saveToFile)
+ save(item);
+}
+
+
+void NodeQueryHandler::remove(const std::string&)
+{
+}
+
+void NodeQueryHandler::remove(NodeQuery*)
+{
+
+}
+
+
+void NodeQueryHandler::save()
+{
+}
+
+void NodeQueryHandler::save(NodeQuery *item)
+{
+ std::string f=DirectoryHandler::concatenate(dirPath_,item->name() + "." + suffix_);
+ VSettings vs(f);
+ item->save(&vs);
+ vs.write();
+
+}
+
+*/
+
+
+
diff --git a/Viewer/src/CustomCommandHandler.hpp b/Viewer/src/CustomCommandHandler.hpp
new file mode 100644
index 0000000..6d69555
--- /dev/null
+++ b/Viewer/src/CustomCommandHandler.hpp
@@ -0,0 +1,113 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+#ifndef VIEWER_SRC_CUSTOMCOMMANDHANDLER_HPP_
+#define VIEWER_SRC_CUSTOMCOMMANDHANDLER_HPP_
+
+#include <string>
+#include <deque>
+
+
+class VSettings;
+
+class CustomCommand
+{
+public:
+ CustomCommand(const std::string &name, const std::string &command, bool context);
+ std::string name() const {return name_;};
+ std::string command() const {return command_;};
+ bool inContextMenu() const {return inContextMenu_;};
+ std::string contextString() const {return (inContextMenu_ ? "yes" : "no");};
+ void set(const std::string &name, const std::string &command, bool context);
+ void save(VSettings *vs);
+
+
+private:
+ std::string name_;
+ std::string command_;
+ bool inContextMenu_;
+};
+
+
+class CustomCommandHandler
+{
+public:
+ CustomCommandHandler();
+
+ virtual CustomCommand* add(const std::string& name, const std::string& command, bool context, bool WriteSettings) = 0;
+ CustomCommand* replace(int index, const std::string& name, const std::string& command, bool context);
+ CustomCommand* replace(int index, const CustomCommand &cmd);
+ CustomCommand* duplicate(int index);
+ void remove(int index);
+ //void remove(const std::string& name);
+ //void remove(CustomCommand*);
+ //CustomCommand* find(const std::string& name) const;
+
+ //void save();
+ //void save(CustomCommand*);
+ void init();
+ //const std::vector<NodeQuery*>& items() const {return items_;}
+ CustomCommand* find(const std::string& name) const;
+ int findIndexFromName(const std::string& name) const;
+ int numCommands() {return items_.size();};
+ CustomCommand *commandFromIndex(int i) {return items_[i];};
+ bool stringToBool(std::string &str);
+ void swapCommandsByIndex(int i1, int i2);
+ void writeSettings();
+
+protected:
+ void readSettings();
+ virtual std::string settingsFile() = 0;
+
+ const std::string suffix_;
+ std::deque<CustomCommand*> items_;
+};
+
+
+
+// ----------------------------------------------------------------------------------------------
+// specialisation of CustomCommandHandler to handle the commands that the user has manually saved
+// ----------------------------------------------------------------------------------------------
+
+class CustomSavedCommandHandler : public CustomCommandHandler
+{
+public:
+ CustomSavedCommandHandler() {};
+ CustomCommand* add(const std::string& name, const std::string& command, bool context, bool saveSettings);
+
+ static CustomSavedCommandHandler* instance();
+
+protected:
+ static CustomSavedCommandHandler* instance_;
+ std::string settingsFile();
+};
+
+
+
+// --------------------------------------------------------------------------------------------
+// specialisation of CustomCommandHandler to handle the commands that the user has recently run
+// --------------------------------------------------------------------------------------------
+
+class CustomCommandHistoryHandler : public CustomCommandHandler
+{
+public:
+ CustomCommandHistoryHandler();
+ CustomCommand* add(const std::string& name, const std::string& command, bool context, bool saveSettings);
+ static CustomCommandHistoryHandler* instance();
+
+protected:
+ static CustomCommandHistoryHandler* instance_;
+ std::string settingsFile();
+ int maxCommands_;
+};
+
+
+
+
+#endif /* VIEWER_SRC_CUSTOMCOMMANDHANDLER_HPP_ */
diff --git a/Viewer/src/CustomListWidget.cpp b/Viewer/src/CustomListWidget.cpp
new file mode 100644
index 0000000..dcf4074
--- /dev/null
+++ b/Viewer/src/CustomListWidget.cpp
@@ -0,0 +1,100 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "CustomListWidget.hpp"
+
+#include <QListWidgetItem>
+#include <QPainter>
+
+CustomListWidget::CustomListWidget(QWidget* parent) : QListWidget(parent)
+{
+ setAlternatingRowColors(true);
+
+ connect(this,SIGNAL(itemChanged(QListWidgetItem*)),
+ this,SLOT(slotItemChanged(QListWidgetItem*)));
+}
+
+void CustomListWidget::addItems(QStringList lst,bool checkState)
+{
+ QListWidget::addItems(lst);
+ for(int i=0; i < count(); i++)
+ {
+ item(i)->setCheckState((checkState)?Qt::Checked:Qt::Unchecked);
+ }
+}
+
+void CustomListWidget::addItems(QStringList lst,bool checkState,QList<QColor> colLst)
+{
+ addItems(lst,checkState);
+
+ for(int i=0; i < count() && i < colLst.count(); i++)
+ {
+ QColor col=colLst[i];
+ if(col.isValid())
+ {
+ QPixmap pix(10,10);
+ QPainter painter(&pix);
+ pix.fill(col);
+ painter.setPen(Qt::black);
+ painter.drawRect(0,0,9,9);
+ item(i)->setIcon(pix);
+ }
+ }
+}
+
+void CustomListWidget::slotItemChanged(QListWidgetItem*)
+{
+ Q_EMIT selectionChanged();
+}
+
+bool CustomListWidget::hasSelection() const
+{
+ for(int i=0; i < count(); i++)
+ {
+ if(item(i)->checkState() == Qt::Checked)
+ return true;
+ }
+
+ return false;
+}
+
+
+QStringList CustomListWidget::selection() const
+{
+ QStringList lst;
+ for(int i=0; i < count(); i++)
+ {
+ if(item(i)->checkState() == Qt::Checked)
+ lst << item(i)->text();
+ }
+
+ return lst;
+}
+
+
+void CustomListWidget::clearSelection()
+{
+ for(int i=0; i < count(); i++)
+ {
+ item(i)->setCheckState(Qt::Unchecked);
+ }
+ Q_EMIT selectionChanged();
+}
+
+void CustomListWidget::setSelection(QStringList sel)
+{
+ for(int i=0; i < count(); i++)
+ {
+ item(i)->setCheckState(Qt::Unchecked);
+ if(sel.contains(item(i)->text()))
+ item(i)->setCheckState(Qt::Checked);
+ }
+}
+
diff --git a/Viewer/src/CustomListWidget.hpp b/Viewer/src/CustomListWidget.hpp
new file mode 100644
index 0000000..caa0285
--- /dev/null
+++ b/Viewer/src/CustomListWidget.hpp
@@ -0,0 +1,41 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+#ifndef VIEWER_SRC_CUSTOMLISTWIDGET_HPP_
+#define VIEWER_SRC_CUSTOMLISTWIDGET_HPP_
+
+#include <QListWidget>
+
+class CustomListWidget : public QListWidget
+{
+Q_OBJECT
+
+public:
+ explicit CustomListWidget(QWidget* parent=0);
+
+ void addItems(QStringList lst,bool checkState);
+ void addItems(QStringList lst,bool checkState,QList<QColor>);
+ QStringList selection() const;
+ bool hasSelection() const;
+ void setSelection(QStringList sel);
+
+public Q_SLOTS:
+ void clearSelection();
+
+protected Q_SLOTS:
+ void slotItemChanged(QListWidgetItem*);
+
+Q_SIGNALS:
+ void selectionChanged();
+
+
+};
+
+
+#endif /* VIEWER_SRC_CUSTOMLISTWIDGET_HPP_ */
diff --git a/Viewer/src/CustomTabWidget.cpp b/Viewer/src/CustomTabWidget.cpp
new file mode 100644
index 0000000..4004ef5
--- /dev/null
+++ b/Viewer/src/CustomTabWidget.cpp
@@ -0,0 +1,57 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "CustomTabWidget.hpp"
+
+#include <QVariant>
+
+
+CustomTabWidget::CustomTabWidget(QWidget* parent) : QTabWidget(parent)
+{
+ setProperty("change","1");
+}
+
+void CustomTabWidget::setCustomIcon(int index, QPixmap pix)
+{
+ if (index >= 0 && index < count())
+ {
+ QSize maxSize=maxIconSize();
+
+ if(maxSize.width() < pix.width())
+ maxSize.setWidth(pix.width());
+
+ if(maxSize.height() < pix.height())
+ maxSize.setHeight(pix.height());
+
+ if(maxSize != iconSize())
+ setIconSize(maxSize);
+
+ setTabIcon(index, QIcon(pix));
+ }
+}
+
+QSize CustomTabWidget::maxIconSize() const
+{
+ QSize maxSize(0,0);
+ for(int i=0; i < count(); i++)
+ {
+ if(tabIcon(i).availableSizes().count() > 0)
+ {
+ QSize avs=tabIcon(i).availableSizes().front();
+ if(maxSize.width() < avs.width())
+ maxSize.setWidth(avs.width());
+
+ if(maxSize.height() < avs.height())
+ maxSize.setHeight(avs.height());
+ }
+ }
+ return maxSize;
+}
+
diff --git a/Viewer/src/CustomTabWidget.hpp b/Viewer/src/CustomTabWidget.hpp
new file mode 100644
index 0000000..ef9a644
--- /dev/null
+++ b/Viewer/src/CustomTabWidget.hpp
@@ -0,0 +1,28 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VIEWER_SRC_CUSTOMTABWIDGET_HPP_
+#define VIEWER_SRC_CUSTOMTABWIDGET_HPP_
+
+#include <QTabWidget>
+
+class CustomTabWidget : public QTabWidget
+{
+public:
+ explicit CustomTabWidget(QWidget* parent=0);
+
+ void setCustomIcon(int index, QPixmap pix);
+
+protected:
+ QSize maxIconSize() const;
+};
+
+
+#endif /* VIEWER_SRC_CUSTOMTABWIDGET_HPP_ */
diff --git a/Viewer/src/Dashboard.cpp b/Viewer/src/Dashboard.cpp
new file mode 100644
index 0000000..1ee512b
--- /dev/null
+++ b/Viewer/src/Dashboard.cpp
@@ -0,0 +1,544 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "Dashboard.hpp"
+
+#include "DashboardDialog.hpp"
+#include "DashboardDock.hpp"
+#include "DashboardTitle.hpp"
+#include "InfoPanel.hpp"
+#include "NodeWidget.hpp"
+#include "ServerHandler.hpp"
+#include "ServerFilter.hpp"
+#include "TableNodeWidget.hpp"
+#include "TreeNodeWidget.hpp"
+#include "UserMessage.hpp"
+#include "VFilter.hpp"
+#include "VSettings.hpp"
+
+#include <QDebug>
+#include <QVBoxLayout>
+#include <QLabel>
+#include <QDockWidget>
+#include <QToolButton>
+#include "NodeSearchDialog.hpp"
+#include "NodeSearchWidget.hpp"
+
+int Dashboard::maxWidgetNum_=20;
+
+Dashboard::Dashboard(QString rootNode,QWidget *parent) :
+ QMainWindow(parent),
+ settingsAreRead_(false)
+{
+ //We use the mainwindow as a widget. Its task is
+ //to dock all the component widgets!
+ setWindowFlags(Qt::Widget);
+
+ //The serverfilter. It holds the list of servers displayed by this dashboard.
+ serverFilter_=new ServerFilter();
+ serverFilter_->addObserver(this);
+
+ titleHandler_=new DashboardTitle(serverFilter_,this);
+
+ //Central widget - we need to create it but we do not
+ //use it. So we can hide it!
+ QWidget *w=new QLabel("centre",this);
+ setCentralWidget(w);
+ w->hide();
+
+ layout()->setContentsMargins(0,0,0,0);
+
+ setDockOptions(QMainWindow::AnimatedDocks|QMainWindow::AllowTabbedDocks|QMainWindow::AllowNestedDocks);
+
+ connect(titleHandler_,SIGNAL(changed(QString,QPixmap)),
+ this,SLOT(slotTitle(QString,QPixmap)));
+}
+
+Dashboard::~Dashboard()
+{
+ Q_EMIT aboutToDelete();
+
+ serverFilter_->removeObserver(this);
+ delete serverFilter_;
+}
+
+
+DashboardWidget* Dashboard::addWidgetCore(const std::string& type)
+{
+ DashboardWidget *w=0;
+
+ //Create a dashboard widget
+ if(type == "tree")
+ {
+ NodeWidget* ctl=new TreeNodeWidget(serverFilter_,this);
+
+ connect(ctl,SIGNAL(selectionChanged(VInfo_ptr)),
+ this,SIGNAL(selectionChanged(VInfo_ptr)));
+
+ connect(ctl,SIGNAL(popInfoPanel(VInfo_ptr,QString)),
+ this,SLOT(slotPopInfoPanel(VInfo_ptr,QString)));
+
+ connect(ctl,SIGNAL(dashboardCommand(VInfo_ptr,QString)),
+ this,SLOT(slotCommand(VInfo_ptr,QString)));
+
+ w=ctl;
+ }
+ else if(type == "table")
+ {
+ NodeWidget* ctl=new TableNodeWidget(serverFilter_,this);
+
+ connect(ctl,SIGNAL(selectionChanged(VInfo_ptr)),
+ this,SIGNAL(selectionChanged(VInfo_ptr)));
+
+ connect(ctl,SIGNAL(popInfoPanel(VInfo_ptr,QString)),
+ this,SLOT(slotPopInfoPanel(VInfo_ptr,QString)));
+
+ connect(ctl,SIGNAL(dashboardCommand(VInfo_ptr,QString)),
+ this,SLOT(slotCommand(VInfo_ptr,QString)));
+
+ w=ctl;
+ }
+ else if(type == "info")
+ {
+ InfoPanel* ctl=new InfoPanel(this);
+ connect(this,SIGNAL(selectionChanged(VInfo_ptr)),
+ ctl,SLOT(slotReload(VInfo_ptr)));
+
+ connect(ctl,SIGNAL(selectionChanged(VInfo_ptr)),
+ this,SLOT(slotInfoPanelSelection(VInfo_ptr)));
+ w=ctl;
+ }
+
+ return w;
+}
+
+
+DashboardWidget* Dashboard::addWidget(const std::string& type)
+{
+ //Get a unique dockId stored as objectName
+ QString dockId=uniqueDockId();
+
+ DashboardWidget*w=addWidget(type,dockId.toStdString());
+
+ //At this point the widgets can be inactive. Reload will make them active!!!
+ w->reload();
+
+ if(type == "info")
+ {
+ VInfo_ptr info=currentSelectionInView();
+ if(info && info.get())
+ {
+ if(InfoPanel* ip=static_cast<InfoPanel*>(w))
+ {
+ ip->slotReload(info);
+ }
+ }
+ }
+
+ return w;
+}
+
+DashboardWidget* Dashboard::addWidget(const std::string& type,const std::string& dockId)
+{
+ DashboardWidget *w=Dashboard::addWidgetCore(type);
+
+ //If the db-widget creation fails we should do something!!!
+ if(!w)
+ return 0;
+
+ //Store dockId in the db-widget
+ w->id(dockId);
+
+ widgets_ << w;
+
+ //Create a dockwidget
+ DashboardDock *dw = new DashboardDock(w, this);
+
+ dw->setAllowedAreas(Qt::RightDockWidgetArea);
+
+ //Store the dockId in the dockwidget (as objectName)
+ dw->setObjectName(QString::fromStdString(dockId));
+
+ //Add the dockwidget to the dashboard
+ addDockWidget(Qt::RightDockWidgetArea, dw);
+
+ connect(dw,SIGNAL(closeRequested()),
+ this,SLOT(slotDockClose()));
+
+ return w;
+}
+
+DashboardWidget* Dashboard::addDialog(const std::string& type)
+{
+ DashboardWidget *w=Dashboard::addWidgetCore(type);
+
+ //If the db-widget creation fails we should do something!!!
+ if(!w)
+ return 0;
+
+ //The DashBoard or any of its children cannot be the parent of the
+ //dialog because in this case it would be always on top its parent. This is
+ //the behaviour when the dialog's parent is QMainWindow.
+ DashboardDialog* dia=new DashboardDialog(0);
+
+ //So the parent is 0 and we will emit a signal from the Dashboard
+ //destructor to notify the dialog about the deletion. Then we can be
+ //sure that the dialog deletes itself when the Dashboard gets deleted.
+ connect(this,SIGNAL(aboutToDelete()),
+ dia,SLOT(slotOwnerDelete()));
+
+ connect(dia,SIGNAL(finished(int)),
+ this,SLOT(slotDialogFinished(int)));
+
+ //The dialog will reparent the widget
+ dia->add(w);
+ dia->show();
+
+ return w;
+}
+
+void Dashboard::addSearchDialog()
+{
+ //It will delete itself on close!!
+ //The parent is 0, for the reason see the comment in addDialog()
+ NodeSearchDialog* d=new NodeSearchDialog(0);
+ d->queryWidget()->setServerFilter(serverFilter_);
+
+ for(int i=0; i < widgets_.count(); i++)
+ {
+ if(widgets_.at(i)->type() == "tree")
+ {
+ connect(d->queryWidget(),SIGNAL(selectionChanged(VInfo_ptr)),
+ widgets_.at(i),SLOT(setCurrentSelection(VInfo_ptr)));
+
+ }
+ }
+
+ connect(d->queryWidget(),SIGNAL(infoPanelCommand(VInfo_ptr,QString)),
+ this,SLOT(slotPopInfoPanel(VInfo_ptr,QString)));
+
+ //The dashboard signals the dialog on deletion
+ connect(this,SIGNAL(aboutToDelete()),
+ d,SLOT(slotOwnerDelete()));
+
+ d->show();
+}
+
+void Dashboard::addSearchDialog(VInfo_ptr info)
+{
+ //It will delete itself on close!!
+ //The parent is 0, for the reason see the comment in addDialog()
+ NodeSearchDialog* d=new NodeSearchDialog(0);
+ d->queryWidget()->setServerFilter(serverFilter_);
+ d->queryWidget()->setRootNode(info);
+
+ for(int i=0; i < widgets_.count(); i++)
+ {
+ if(widgets_.at(i)->type() == "tree")
+ {
+ connect(d->queryWidget(),SIGNAL(selectionChanged(VInfo_ptr)),
+ widgets_.at(i),SLOT(setCurrentSelection(VInfo_ptr)));
+ }
+ }
+
+ connect(d->queryWidget(),SIGNAL(infoPanelCommand(VInfo_ptr,QString)),
+ this,SLOT(slotPopInfoPanel(VInfo_ptr,QString)));
+
+ //The dashboard signals the dialog on deletion
+ connect(this,SIGNAL(aboutToDelete()),
+ d,SLOT(slotOwnerDelete()));
+
+ d->show();
+}
+
+void Dashboard::slotDockClose()
+{
+ if(DashboardDock *dock=static_cast<DashboardDock*>(sender()))
+ {
+ if(DashboardWidget* dw=static_cast<DashboardWidget*>(dock->widget()))
+ {
+ widgets_.removeOne(dw);
+ disconnect(this,0,dw,0);
+ dw->deleteLater();
+ }
+ }
+}
+
+VInfo_ptr Dashboard::currentSelection()
+{
+ return currentSelectionInView();
+}
+
+void Dashboard::currentSelection(VInfo_ptr n)
+{
+ //if(NodeWidget *ctl=handler_->currentControl())
+ // ctl->currentSelection(n);
+}
+
+void Dashboard::slotPopInfoPanel(QString name)
+{
+ if(DashboardWidget *dw=addDialog("info"))
+ {
+ if(InfoPanel* ip=static_cast<InfoPanel*>(dw))
+ {
+ ip->setDetached(true);
+ ip->setCurrent(name.toStdString());
+ }
+ }
+}
+
+void Dashboard::slotPopInfoPanel(VInfo_ptr info,QString name)
+{
+ if(DashboardWidget *dw=addDialog("info"))
+ {
+ if(InfoPanel* ip=static_cast<InfoPanel*>(dw))
+ {
+ ip->setDetached(true);
+ ip->slotReload(info);
+ ip->setCurrent(name.toStdString());
+ }
+ }
+}
+
+void Dashboard::slotTitle(QString s,QPixmap p)
+{
+ Q_EMIT titleChanged(this,s,p);
+}
+
+
+
+void Dashboard::slotCommand(VInfo_ptr info,QString cmd)
+{
+ if(!info || !info.get() )
+ return;
+
+ if(cmd == "search")
+ {
+ addSearchDialog(info);
+ }
+}
+
+//------------------------
+// Dialogs
+//------------------------
+
+void Dashboard::slotDialogFinished(int)
+{
+ if(DashboardDialog* dia=static_cast<DashboardDialog*>(sender()))
+ {
+ disconnect(this,0,dia->dashboardWidget(),0);
+ }
+}
+
+//------------------------
+// Rescan
+//------------------------
+
+void Dashboard::reload()
+{
+ for(int i=0; i < widgets_.count(); i++)
+ widgets_.at(i)->reload();
+}
+
+void Dashboard::rerender()
+{
+ for(int i=0; i < widgets_.count(); i++)
+ widgets_.at(i)->rerender();
+
+ titleHandler_->updateTitle();
+}
+
+//------------------------
+// ViewMode
+//------------------------
+
+Viewer::ViewMode Dashboard::viewMode()
+{
+ //return handler_->currentMode();
+ return Viewer::TreeViewMode;
+}
+
+void Dashboard::setViewMode(Viewer::ViewMode mode)
+{
+ //handler_->setCurrentMode(mode);
+}
+
+//----------------------------------
+// Save and load settings!!
+//----------------------------------
+
+void Dashboard::writeSettings(VComboSettings* vs)
+{
+ serverFilter_->writeSettings(vs);
+
+ //Qt settings
+ vs->putQs("state",saveState());
+
+ //Other setting
+ vs->put("widgetCount",findChildren<QDockWidget*>().count());
+
+ for(int i=0; i < widgets_.count(); i++)
+ {
+ std::string id=Dashboard::widgetSettingsId(i);
+ vs->beginGroup(id);
+ widgets_.at(i)->writeSettings(vs);
+ vs->endGroup();
+ }
+}
+
+void Dashboard::readSettings(VComboSettings* vs)
+{
+ settingsAreRead_=true;
+
+ //This will create the ServerHandler objects
+ serverFilter_->readSettings(vs);
+
+ //At this point each ServerHandler is running its reset()!
+
+ Q_FOREACH(QWidget* w,findChildren<QDockWidget*>())
+ {
+ UserMessage::message(UserMessage::DBG,false,std::string("DashBoard::readSettings() dock: ") + w->objectName().toStdString());
+ }
+
+ //Read the information about the dashboard widgets.
+ int cnt=vs->get<int>("widgetCount",0);
+ for(int i=0; i < cnt; i++)
+ {
+ std::string id=Dashboard::widgetSettingsId(i);
+ if(vs->contains(id))
+ {
+ vs->beginGroup(id);
+ std::string type=vs->get<std::string>("type","");
+ std::string dockId=vs->get<std::string>("dockId","");
+
+ //Create a dashboard widget
+ if(DashboardWidget *dw=addWidget(type,dockId))
+ {
+ //This will make the widgets active!!! The ServerHandler reset() can
+ //be still running at this point!
+ dw->readSettings(vs);
+ }
+ vs->endGroup();
+ }
+ }
+
+ //Restore state of the dockwidgets. It will not create the dockwidgets
+ //themselves but set their states and geometry. This is based on
+ //the the dockwidgets's objectname, so that has to be unique. We need to call
+ //it when the dockwidgets have already been created.
+ if(vs->containsQs("state"))
+ {
+ restoreState(vs->getQs("state").toByteArray());
+ }
+
+ selectFirstServerInView();
+
+ settingsAreRead_=false;
+}
+
+void Dashboard::slotInfoPanelSelection(VInfo_ptr info)
+{
+ selectInTreeView(info);
+}
+
+void Dashboard::selectFirstServerInView()
+{
+ Q_FOREACH(DashboardWidget* w,widgets_)
+ {
+ if(w->selectFirstServerInView())
+ {
+ return;
+ }
+ }
+}
+
+bool Dashboard::selectInTreeView(VInfo_ptr info)
+{
+ if(!info)
+ return false;
+
+ Q_FOREACH(DashboardWidget* w,widgets_)
+ {
+ if(w->type() == "tree")
+ {
+ w->setCurrentSelection(info);
+ return serverFilter_->isFiltered(info->server());
+ }
+ }
+
+ return false;
+}
+
+VInfo_ptr Dashboard::currentSelectionInView()
+{
+ Q_FOREACH(DashboardWidget* w,widgets_)
+ {
+ VInfo_ptr info=w->currentSelection();
+ if(info && info.get())
+ return info;
+ }
+
+ return VInfo_ptr();
+}
+
+//Find an unique id for a new dockwidget
+QString Dashboard::uniqueDockId()
+{
+ QSet<QString> ids;
+ Q_FOREACH(QDockWidget* dw, findChildren<QDockWidget*>())
+ {
+ ids << dw->objectName();
+ }
+
+ for(unsigned i=0; i < 1000; i++)
+ {
+ QString uid="dock_" + QString::number(i);
+ if(!ids.contains(uid))
+ {
+ return uid;
+ }
+ }
+
+ //We should handle this situation!!
+ assert(0);
+
+ return "dock_1000";
+}
+
+std::string Dashboard::widgetSettingsId(int i)
+{
+ return "widget_" + boost::lexical_cast<std::string>(i);
+}
+
+void Dashboard::notifyServerFilterAdded(ServerItem* item)
+{
+ if(!settingsAreRead_)
+ Q_EMIT contentsChanged();
+}
+
+void Dashboard::notifyServerFilterRemoved(ServerItem* item)
+{
+ if(!settingsAreRead_)
+ Q_EMIT contentsChanged();
+}
+
+void Dashboard::notifyServerFilterChanged(ServerItem*)
+{
+ if(!settingsAreRead_)
+ Q_EMIT contentsChanged();
+}
+
+void Dashboard::notifyServerFilterDelete()
+{
+ //if(!settingsAreRead_)
+ // Q_EMIT contentsChanged();
+}
+
+
diff --git a/Viewer/src/Dashboard.hpp b/Viewer/src/Dashboard.hpp
new file mode 100644
index 0000000..756b794
--- /dev/null
+++ b/Viewer/src/Dashboard.hpp
@@ -0,0 +1,91 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef DASHBOARD_HPP_
+#define DASHBOARD_HPP_
+
+#include "Viewer.hpp"
+
+#include <QMainWindow>
+
+#include "ServerFilter.hpp"
+#include "VInfo.hpp"
+#include "VSettings.hpp"
+
+class DashboardTitle;
+class DashboardWidget;
+class ServerFilter;
+class ServerItem;
+class VComboSettings;
+
+class Dashboard : public QMainWindow, public ServerFilterObserver
+{
+ Q_OBJECT
+
+public:
+ Dashboard(QString,QWidget* parent=0);
+ ~Dashboard();
+
+ void reload();
+ void rerender();
+
+ DashboardWidget* addWidget(const std::string& type);
+ DashboardWidget* addDialog(const std::string& type);
+ Viewer::ViewMode viewMode();
+ void setViewMode(Viewer::ViewMode);
+ ServerFilter* serverFilter() const {return serverFilter_;}
+ VInfo_ptr currentSelection();
+ void currentSelection(VInfo_ptr n);
+ void selectFirstServer();
+ bool selectInTreeView(VInfo_ptr);
+ void addSearchDialog();
+
+ void notifyServerFilterAdded(ServerItem* item);
+ void notifyServerFilterRemoved(ServerItem* item);
+ void notifyServerFilterChanged(ServerItem*);
+ void notifyServerFilterDelete();
+
+ void writeSettings(VComboSettings*);
+ void readSettings(VComboSettings*);
+
+Q_SIGNALS:
+ void selectionChanged(VInfo_ptr);
+ void titleChanged(QWidget*,QString,QPixmap);
+ void contentsChanged();
+ void aboutToDelete();
+
+public Q_SLOTS:
+ void slotPopInfoPanel(VInfo_ptr,QString);
+ void slotCommand(VInfo_ptr,QString);
+
+protected Q_SLOTS:
+ void slotTitle(QString,QPixmap);
+ void slotDockClose();
+ void slotDialogFinished(int);
+ void slotPopInfoPanel(QString);
+ void slotInfoPanelSelection(VInfo_ptr);
+
+private:
+ DashboardWidget* addWidgetCore(const std::string& type);
+ DashboardWidget* addWidget(const std::string& type,const std::string& dockId);
+ QString uniqueDockId();
+ static std::string widgetSettingsId(int i);
+ void selectFirstServerInView();
+ VInfo_ptr currentSelectionInView();
+ void addSearchDialog(VInfo_ptr);
+
+ ServerFilter* serverFilter_;
+ DashboardTitle* titleHandler_;
+ QList<DashboardWidget*> widgets_;
+ bool settingsAreRead_;
+ static int maxWidgetNum_;
+};
+
+
+#endif
diff --git a/Viewer/src/DashboardDialog.cpp b/Viewer/src/DashboardDialog.cpp
new file mode 100644
index 0000000..8dcc1ee
--- /dev/null
+++ b/Viewer/src/DashboardDialog.cpp
@@ -0,0 +1,114 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "DashboardDialog.hpp"
+
+#include "DashboardWidget.hpp"
+#include "SessionHandler.hpp"
+
+#include <QAbstractButton>
+#include <QCloseEvent>
+#include <QPushButton>
+#include <QSettings>
+
+DashboardDialog::DashboardDialog(QWidget *parent) :
+ QDialog(parent),
+ dw_(0)
+{
+ setupUi(this);
+
+ setAttribute(Qt::WA_DeleteOnClose);
+
+ //Disable the default button
+ Q_FOREACH(QAbstractButton* b,buttonBox_->buttons())
+ {
+ if(QPushButton* pb=buttonBox_->button(buttonBox_->standardButton(b)) )
+ pb->setAutoDefault(false);
+ }
+
+ readSettings();
+}
+
+DashboardDialog::~DashboardDialog()
+{
+ //dw_->deleteLater();
+}
+
+void DashboardDialog::add(DashboardWidget* dw)
+{
+ dw_=dw;
+
+ //The dialog takes ownership of the widget
+ dw_->setParent(this);
+
+ layout_->insertWidget(0,dw_,1);
+
+ connect(dw_,SIGNAL(titleUpdated(QString)),
+ this,SLOT(slotUpdateTitle(QString)));
+
+ dw_->populateDialog();
+}
+
+void DashboardDialog::reject()
+{
+ writeSettings();
+ QDialog::reject();
+}
+
+void DashboardDialog::closeEvent(QCloseEvent * event)
+{
+ event->accept();
+ writeSettings();
+}
+
+void DashboardDialog::slotUpdateTitle(QString txt)
+{
+ setWindowTitle(txt.remove("<b>").remove("</b>"));
+}
+
+void DashboardDialog::slotOwnerDelete()
+{
+ this->deleteLater();
+}
+
+void DashboardDialog::writeSettings()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ Q_ASSERT(cs);
+ QSettings settings(QString::fromStdString(cs->qtSettingsFile("DashboardDialog")),
+ QSettings::NativeFormat);
+
+ //We have to clear it so that should not remember all the previous values
+ settings.clear();
+
+ settings.beginGroup("main");
+ settings.setValue("size",size());
+ settings.endGroup();
+}
+
+void DashboardDialog::readSettings()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ Q_ASSERT(cs);
+ QSettings settings(QString::fromStdString(cs->qtSettingsFile("DashboardDialog")),
+ QSettings::NativeFormat);
+
+ settings.beginGroup("main");
+ if(settings.contains("size"))
+ {
+ resize(settings.value("size").toSize());
+ }
+ else
+ {
+ resize(QSize(520,500));
+ }
+
+ settings.endGroup();
+}
diff --git a/Viewer/src/DashboardDialog.hpp b/Viewer/src/DashboardDialog.hpp
new file mode 100644
index 0000000..009711c
--- /dev/null
+++ b/Viewer/src/DashboardDialog.hpp
@@ -0,0 +1,44 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef DASHBOARDDIALOG_HPP_
+#define DASHBOARDDIALOG_HPP_
+
+#include <QDialog>
+
+#include "ui_DashboardDialog.h"
+
+class DashboardWidget;
+
+class DashboardDialog : public QDialog, protected Ui::DashboardDialog
+{
+Q_OBJECT
+
+public:
+ explicit DashboardDialog(QWidget *parent=0);
+ ~DashboardDialog();
+
+ void add(DashboardWidget*);
+ DashboardWidget* dashboardWidget() const {return dw_;}
+
+public Q_SLOTS:
+ void reject();
+ void slotUpdateTitle(QString);
+ void slotOwnerDelete();
+
+protected:
+ void closeEvent(QCloseEvent * event);
+ void readSettings();
+ void writeSettings();
+
+ DashboardWidget* dw_;
+
+};
+
+#endif
diff --git a/Viewer/src/DashboardDialog.ui b/Viewer/src/DashboardDialog.ui
new file mode 100644
index 0000000..b1c4f9c
--- /dev/null
+++ b/Viewer/src/DashboardDialog.ui
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>DashboardDialog</class>
+ <widget class="QDialog" name="DashboardDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>538</width>
+ <height>251</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="windowTitle">
+ <string>About EcflowUI</string>
+ </property>
+ <property name="modal">
+ <bool>false</bool>
+ </property>
+ <layout class="QVBoxLayout" name="layout_" stretch="0">
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox_">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Close</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox_</sender>
+ <signal>accepted()</signal>
+ <receiver>DashboardDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>257</x>
+ <y>218</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>227</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox_</sender>
+ <signal>rejected()</signal>
+ <receiver>DashboardDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>274</x>
+ <y>218</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>283</x>
+ <y>227</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/Viewer/src/DashboardDock.cpp b/Viewer/src/DashboardDock.cpp
new file mode 100644
index 0000000..12326ae
--- /dev/null
+++ b/Viewer/src/DashboardDock.cpp
@@ -0,0 +1,182 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "DashboardDock.hpp"
+
+#include <QLinearGradient>
+#include <QPalette>
+
+#include "DashboardWidget.hpp"
+
+DashboardDockTitleWidget::DashboardDockTitleWidget(QWidget *parent) :
+ QWidget(parent)
+{
+ setupUi(this);
+
+ setProperty("dockTitle","1");
+
+ //We define the style here because it did not work from the qss file
+ QPalette p=palette();
+ QLinearGradient gr(0,0,0,1);
+ gr.setCoordinateMode(QGradient::ObjectBoundingMode);
+ gr.setColorAt(0,QColor(130,130,130));
+ gr.setColorAt(0.4,QColor(120,120,120));
+ gr.setColorAt(0.41,QColor(112,112,112));
+ gr.setColorAt(1,QColor(95,95,95));
+ p.setBrush(QPalette::Window,gr);
+ setPalette(p);
+
+ p=titleLabel_->palette();
+ p.setColor(QPalette::WindowText,Qt::white);
+ titleLabel_->setPalette(p);
+
+ optionsTb_->setProperty("docktitle","1");
+ closeTb_->setProperty("docktitle","1");
+
+ //Set the initial state of the float tool button
+ if(QDockWidget *dw = qobject_cast<QDockWidget*>(parentWidget()))
+ {
+ if(!dw->features().testFlag(QDockWidget::DockWidgetFloatable))
+ {
+ //floatTb_->setEnabled(false);
+ floatTb_->hide();
+ }
+ }
+}
+
+void DashboardDockTitleWidget::addActions(QList<QAction*> lst)
+{
+ Q_FOREACH(QAction* ac,lst)
+ {
+ QToolButton *tb=new QToolButton(this);
+ tb->setProperty("docktitle","1");
+ tb->setDefaultAction(ac);
+ tb->setAutoRaise(true);
+ tb->setPopupMode(QToolButton::InstantPopup);
+ //tb->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
+
+
+ QPalette p=tb->palette();
+ p.setColor(QPalette::ButtonText,Qt::white);
+ tb->setPalette(p);
+
+
+
+ actionLayout_->addWidget(tb);
+
+ if(!ac->isEnabled())
+ tb->hide();
+
+ actionTbList_ << tb;
+
+ connect(ac,SIGNAL(changed()),
+ this,SLOT(slotActionChanged()));
+ }
+
+ //Hide the separator line if no buttons were added
+ if(actionTbList_.isEmpty())
+ line_->hide();
+}
+
+void DashboardDockTitleWidget::slotActionChanged()
+{
+ Q_FOREACH(QToolButton *tb, actionTbList_)
+ {
+ if(!tb->isEnabled())
+ {
+ tb->hide();
+ }
+ else
+ {
+ tb->show();
+ }
+ }
+}
+
+
+QSize DashboardDockTitleWidget::sizeHint() const
+{
+ QSize s=QWidget::sizeHint();
+ //s.setHeight();
+ return s;
+}
+
+QSize DashboardDockTitleWidget::minimumSizeHint() const
+{
+ QSize s=QWidget::minimumSizeHint();
+ //s.setHeight(16);
+ return s;
+}
+
+QToolButton* DashboardDockTitleWidget::optionsTb() const
+{
+ return optionsTb_;
+}
+
+void DashboardDockTitleWidget::on_floatTb__clicked(bool)
+{
+ if(QDockWidget *dw = qobject_cast<QDockWidget*>(parentWidget()))
+ {
+ if(dw->features().testFlag(QDockWidget::DockWidgetFloatable))
+ {
+ bool current=dw->isFloating();
+ dw->setFloating(!current);
+ }
+ }
+}
+
+void DashboardDockTitleWidget::on_closeTb__clicked(bool)
+{
+ if(QDockWidget *dw = qobject_cast<QDockWidget*>(parentWidget()))
+ {
+ dw->close();
+ }
+}
+
+void DashboardDockTitleWidget::slotUpdateTitle(QString txt)
+{
+ titleLabel_->setText(txt);
+}
+
+//============================================================
+//
+// DashBoardDock
+//
+//============================================================
+
+DashboardDock::DashboardDock(DashboardWidget *dw,QWidget * parent) :
+ QDockWidget(parent)
+{
+ setFeatures(QDockWidget::DockWidgetClosable|QDockWidget::DockWidgetMovable);
+
+ DashboardDockTitleWidget *dt=new DashboardDockTitleWidget(this);
+
+ setTitleBarWidget(dt);
+
+ dt->addActions(dw->dockTitleActions());
+
+ connect(dw,SIGNAL(titleUpdated(QString)),
+ dt,SLOT(slotUpdateTitle(QString)));
+
+ dw->populateDockTitleBar(dt);
+
+ setWidget(dw);
+}
+
+void DashboardDock::showEvent(QShowEvent* event)
+{
+ QWidget::showEvent(event);
+}
+
+void DashboardDock::closeEvent (QCloseEvent *event)
+{
+ QWidget::closeEvent(event);
+ Q_EMIT closeRequested();
+}
diff --git a/Viewer/src/DashboardDock.hpp b/Viewer/src/DashboardDock.hpp
new file mode 100644
index 0000000..9bd42e5
--- /dev/null
+++ b/Viewer/src/DashboardDock.hpp
@@ -0,0 +1,60 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef DASHBOARDDOCK_HPP_
+#define DASHBOARDDOCK_HPP_
+
+#include <QDockWidget>
+
+#include "ui_DashboardDockTitleWidget.h"
+
+class DashboardWidget;
+class QToolButton;
+
+class DashboardDockTitleWidget : public QWidget, protected Ui::DashboardDockTitleWidget
+{
+Q_OBJECT
+
+public:
+ explicit DashboardDockTitleWidget(QWidget *parent=0);
+
+ void addInfoPanelActions();
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+ QToolButton* optionsTb() const;
+ void addActions(QList<QAction*> lst);
+
+public Q_SLOTS:
+ void slotUpdateTitle(QString txt);
+
+protected Q_SLOTS:
+ void on_floatTb__clicked(bool);
+ void on_closeTb__clicked(bool);
+ void slotActionChanged();
+
+protected:
+ QList<QToolButton*> actionTbList_;
+};
+
+class DashboardDock : public QDockWidget
+{
+Q_OBJECT
+
+public:
+ explicit DashboardDock(DashboardWidget* dw,QWidget * parent=0);
+
+Q_SIGNALS:
+ void closeRequested();
+
+protected:
+ void showEvent(QShowEvent* event);
+ void closeEvent (QCloseEvent *event);
+};
+
+#endif
diff --git a/Viewer/src/DashboardDockTitleWidget.ui b/Viewer/src/DashboardDockTitleWidget.ui
new file mode 100644
index 0000000..a6d929b
--- /dev/null
+++ b/Viewer/src/DashboardDockTitleWidget.ui
@@ -0,0 +1,198 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>DashboardDockTitleWidget</class>
+ <widget class="QWidget" name="DashboardDockTitleWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>711</width>
+ <height>140</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <property name="statusTip">
+ <string/>
+ </property>
+ <property name="autoFillBackground">
+ <bool>true</bool>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,0,0,0,0,0,0">
+ <property name="spacing">
+ <number>2</number>
+ </property>
+ <property name="sizeConstraint">
+ <enum>QLayout::SetMinAndMaxSize</enum>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>2</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>2</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>15</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="titleLabel_">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>8</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string>Title</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>15</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="actionLayout_">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ </layout>
+ </item>
+ <item>
+ <widget class="Line" name="line_">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="optionsTb_">
+ <property name="toolTip">
+ <string>Options</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/dock_config.svg</normaloff>:/viewer/dock_config.svg</iconset>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <property name="popupMode">
+ <enum>QToolButton::InstantPopup</enum>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="floatTb_">
+ <property name="toolTip">
+ <string>Float</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/images/dock_float.svg</normaloff>:/viewer/images/dock_float.svg</iconset>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <property name="autoRaise">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="closeTb_">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16</width>
+ <height>16</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Close</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/images/dock_close.svg</normaloff>:/viewer/images/dock_close.svg</iconset>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>16</width>
+ <height>16</height>
+ </size>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="viewer.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/Viewer/src/DashboardTitle.cpp b/Viewer/src/DashboardTitle.cpp
new file mode 100644
index 0000000..693bf1d
--- /dev/null
+++ b/Viewer/src/DashboardTitle.cpp
@@ -0,0 +1,169 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "DashboardTitle.hpp"
+
+#include "ServerHandler.hpp"
+#include "VNode.hpp"
+
+#include <QPainter>
+
+DashboardTitle::DashboardTitle(ServerFilter* filter,QObject *parent) :
+ QObject(parent),
+ filter_(filter)
+{
+ filter_->addObserver(this);
+}
+
+DashboardTitle::~DashboardTitle()
+{
+ clear();
+}
+
+void DashboardTitle::clear()
+{
+ if(!filter_)
+ return;
+
+ filter_->removeObserver(this);
+ for(std::vector<ServerItem*>::const_iterator it=filter_->items().begin(); it !=filter_->items().end(); ++it)
+ {
+ ServerHandler* s=(*it)->serverHandler();
+ s->removeServerObserver(this);
+ }
+
+ filter_=0;
+}
+
+
+void DashboardTitle::notifyServerFilterAdded(ServerItem* item)
+{
+ ServerHandler* s=item->serverHandler();
+ s->addServerObserver(this);
+ updateTitle();
+}
+
+void DashboardTitle::notifyServerFilterRemoved(ServerItem* item)
+{
+ ServerHandler* s=item->serverHandler();
+ s->removeServerObserver(this);
+ updateTitle();
+}
+
+void DashboardTitle::notifyServerFilterChanged(ServerItem*)
+{
+ updateTitle();
+}
+
+void DashboardTitle::notifyServerFilterDelete()
+{
+ clear();
+}
+
+void DashboardTitle::notifyDefsChanged(ServerHandler* server, const std::vector<ecf::Aspect::Type>& a)
+{
+ updateTitle();
+}
+
+void DashboardTitle::notifyServerDelete(ServerHandler* server)
+{
+ //server->removeServerObserver(this);
+}
+
+void DashboardTitle::notifyEndServerClear(ServerHandler* server)
+{
+ updateTitle();
+}
+
+void DashboardTitle::notifyEndServerScan(ServerHandler* server)
+{
+ updateTitle();
+}
+
+void DashboardTitle::notifyServerConnectState(ServerHandler* server)
+{
+ updateTitle();
+}
+
+void DashboardTitle::notifyServerActivityChanged(ServerHandler* server)
+{
+ updateTitle();
+}
+
+void DashboardTitle::updateTitle()
+{
+ if(!filter_)
+ return;
+
+ const int marginX=0;
+ const int marginY=0;
+ const int textMarginX=2;
+ const int textMarginY=1;
+ const int gap=8;
+ QFont f;
+ QFontMetrics fm(f);
+
+ //Compute the pixmap size
+ int w=0;
+ int h=fm.height()+2*marginY+2*textMarginY+1;
+
+ QStringList texts;
+ QList<QRect> textRects;
+ QList<QRect> fillRects;
+ QList<QColor> fillColors;
+ QList<QColor> textColors;
+
+ int xp=marginX;
+ int yp=marginY;
+ const std::vector<ServerItem*> items=filter_->items();
+ for(std::vector<ServerItem*>::const_iterator it=items.begin(); it != items.end(); ++it)
+ {
+ //Get text
+ QString str=QString::fromStdString((*it)->name());
+ textRects << QRect(xp+textMarginX,yp+textMarginY,fm.width(str),fm.height());
+ texts << str;
+
+ //Get server status
+ ServerHandler* server=(*it)->serverHandler();
+ fillColors << server->vRoot()->stateColour();
+ textColors << server->vRoot()->stateFontColour();
+ fillRects << QRect(xp,yp,fm.width(str)+2*textMarginX,fm.height()+2*textMarginY);
+
+ xp=fillRects.back().right()+gap;
+ }
+ w=xp-gap+marginX+2;
+
+ //Render the pixmap
+ QPixmap pix(w,h);
+ pix.fill(Qt::transparent);
+ QPainter painter(&pix);
+
+ for(int i=0; i < texts.count(); i++)
+ {
+ QColor c=fillColors[i].darker(110);
+
+ QColor cp=fillColors[i].darker(120);
+
+ painter.setPen(cp);
+ painter.setBrush(fillColors[i]);
+ painter.drawRoundedRect(fillRects[i],0,0);
+
+ QRect half=fillRects[i];
+ half.setY(half.center().y());
+ half.adjust(1,0,-1,-1);
+ painter.setPen(Qt::NoPen);
+ painter.fillRect(half,c);
+
+ painter.setPen(QPen(textColors[i]));
+ painter.drawText(textRects[i],texts[i]);
+ }
+
+ Q_EMIT changed("",pix);
+}
+
diff --git a/Viewer/src/DashboardTitle.hpp b/Viewer/src/DashboardTitle.hpp
new file mode 100644
index 0000000..675ce41
--- /dev/null
+++ b/Viewer/src/DashboardTitle.hpp
@@ -0,0 +1,57 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef DASHBOARDTITLE_HPP_
+#define DASHBOARDTITLE_HPP_
+
+#include <QObject>
+#include <QPixmap>
+
+#include "ServerFilter.hpp"
+#include "ServerObserver.hpp"
+
+class Dashboard;
+class ServerItem;
+
+class DashboardTitle : public QObject, public ServerFilterObserver, public ServerObserver
+{
+Q_OBJECT
+
+friend class Dashboard;
+
+public:
+ DashboardTitle(ServerFilter*,QObject *parent=0);
+ ~DashboardTitle();
+
+ void notifyServerFilterAdded(ServerItem* item);
+ void notifyServerFilterRemoved(ServerItem* item);
+ void notifyServerFilterChanged(ServerItem*);
+ void notifyServerFilterDelete();
+
+ void notifyDefsChanged(ServerHandler* server, const std::vector<ecf::Aspect::Type>& a);
+ void notifyServerDelete(ServerHandler* server);
+ void notifyBeginServerClear(ServerHandler* server) {};
+ void notifyEndServerClear(ServerHandler* server);
+ void notifyBeginServerScan(ServerHandler* server,const VServerChange&) {};
+ void notifyEndServerScan(ServerHandler* server);
+ void notifyServerConnectState(ServerHandler* server);
+ void notifyServerActivityChanged(ServerHandler* server);
+ void notifyServerSuiteFilterChanged(ServerHandler* server) {};
+
+Q_SIGNALS:
+ void changed(QString,QPixmap);
+
+private:
+ void updateTitle();
+ void clear();
+
+ ServerFilter* filter_;
+};
+
+#endif
diff --git a/Viewer/src/DashboardWidget.hpp b/Viewer/src/DashboardWidget.hpp
new file mode 100644
index 0000000..a0c3909
--- /dev/null
+++ b/Viewer/src/DashboardWidget.hpp
@@ -0,0 +1,59 @@
+/***************************** LICENSE START ***********************************
+
+ Copyright 2016 ECMWF and INPE. This software is distributed under the terms
+ of the Apache License version 2.0. In applying this license, ECMWF does not
+ waive the privileges and immunities granted to it by virtue of its status as
+ an Intergovernmental Organization or submit itself to any jurisdiction.
+
+ ***************************** LICENSE END *************************************/
+
+#ifndef DASHBOARDWIDGET_HPP_
+#define DASHBOARDWIDGET_HPP_
+
+#include <string>
+#include <QDockWidget>
+#include <QWidget>
+#include <QAction>
+
+#include "VInfo.hpp"
+
+class DashboardDockTitleWidget;
+class ServerFilter;
+class VSettings;
+
+class DashboardWidget : public QWidget
+{
+Q_OBJECT
+
+public:
+ DashboardWidget(const std::string& type, QWidget* parent=0) :
+ QWidget(parent),type_(type), acceptSetCurrent_(false) {}
+ virtual ~DashboardWidget() {}
+
+ virtual void populateDockTitleBar(DashboardDockTitleWidget*)=0;
+ virtual void populateDialog()=0;
+ virtual void reload()=0;
+ virtual void rerender()=0;
+ virtual bool selectFirstServerInView() {return false;}
+ virtual VInfo_ptr currentSelection() {return VInfo_ptr(); }
+ virtual QList<QAction*> dockTitleActions() {return QList<QAction*>();}
+
+ virtual void writeSettings(VSettings*)=0;
+ virtual void readSettings(VSettings*)=0;
+
+ const std::string type() const {return type_;}
+ void id(const std::string& id) {id_=id;}
+
+public Q_SLOTS:
+ virtual void setCurrentSelection(VInfo_ptr)=0;
+
+Q_SIGNALS:
+ void titleUpdated(QString);
+
+protected:
+ std::string id_;
+ std::string type_;
+ bool acceptSetCurrent_;
+};
+
+#endif
diff --git a/Viewer/src/DirectoryHandler.cpp b/Viewer/src/DirectoryHandler.cpp
new file mode 100644
index 0000000..009275b
--- /dev/null
+++ b/Viewer/src/DirectoryHandler.cpp
@@ -0,0 +1,362 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/foreach.hpp>
+
+#include <boost/regex.hpp>
+
+#include <boost/algorithm/string/predicate.hpp>
+
+#include "DirectoryHandler.hpp"
+#include "UserMessage.hpp"
+
+std::string DirectoryHandler::shareDir_;
+std::string DirectoryHandler::etcDir_;
+std::string DirectoryHandler::configDir_;
+std::string DirectoryHandler::rcDir_;
+std::string DirectoryHandler::tmpDir_;
+
+static bool firstStartUp=false;
+
+DirectoryHandler::DirectoryHandler()
+{
+}
+
+// -----------------------------------------------------------------------------
+// DirectoryHandler::init
+// We set all the directory paths containing any of the config files used by the viewer.
+// If we tell this class where the executable started from, then it can work out
+// where all the other directories are
+// -----------------------------------------------------------------------------
+
+void DirectoryHandler::init(const std::string& exeStr)
+{
+ //Sets paths in the home directory
+ if(char *h=getenv("HOME"))
+ {
+ boost::filesystem::path homeDir(h);
+
+ boost::filesystem::path configDir = homeDir;
+ configDir /= ".ecflow_ui";
+
+ boost::filesystem::path rcDir = homeDir;
+ rcDir /= ".ecflowrc";
+
+ configDir_=configDir.string();
+ rcDir_=rcDir.string();
+
+ //Create configDir if if does not exist
+ if(!boost::filesystem::exists(configDir))
+ {
+ firstStartUp=true;
+
+ try
+ {
+ boost::filesystem::create_directory(configDir);
+ }
+ catch(const boost::filesystem::filesystem_error& err)
+ {
+ UserMessage::message(UserMessage::ERROR, true,
+ std::string("Could not create configDir: " + configDir_ + " reason: " + err.what()));
+ exit(1);
+ }
+ }
+ }
+
+ //Sets paths in the system directory
+ boost::filesystem::path exePath(exeStr);
+
+ //If the executable path does not exist we
+ //will use the value of the ECFLOW_SHARED_DIR macro to get
+ //the location of the "share/ecflow" dir.
+ if(!boost::filesystem::exists(exePath))
+ {
+ boost::filesystem::path shareDir(ECFLOW_SHARED_DIR);
+ if(!boost::filesystem::exists(shareDir))
+ {
+ UserMessage::message(UserMessage::ERROR, true,
+ std::string("Shared dir " + shareDir.string() + " does not exist! EcflowUI cannot be launched!"));
+ exit(0);
+ }
+
+ boost::filesystem::path etcDir = shareDir;
+ etcDir /= "etc";
+
+ shareDir_ = shareDir.string();
+ etcDir_ = etcDir.string();
+ }
+ //If the executable path exits we probably use relative paths to it.
+ else
+ {
+ //TODO: make it work when we run it from within "bin"
+ boost::filesystem::path shareDir = exePath.parent_path().parent_path();
+
+ shareDir /= "share";
+ shareDir /= "ecflow";
+
+ boost::filesystem::path etcDir = shareDir;
+ etcDir /= "etc";
+
+ shareDir_ = shareDir.string();
+ etcDir_ = etcDir.string();
+ }
+
+ //Tmp dir
+ if(char *h=getenv("ECFLOWUI_TMPDIR"))
+ {
+ tmpDir_=std::string(h);
+ }
+ else if(char *h=getenv("TMPDIR"))
+ {
+ tmpDir_=std::string(h);
+ boost::filesystem::path tmp(tmpDir_);
+ tmp /= "eclow_ui.tmp";
+ if(!boost::filesystem::exists(tmp))
+ {
+ UserMessage::message(UserMessage::WARN, false,
+ "ECFLOWUI_TMPDIR env variable is not defined. ecFlowUI creates its tmp direcoty in TMPDIR as " + tmp.string());
+
+ try
+ {
+ if(boost::filesystem::create_directory(tmp))
+ {
+ tmpDir_=tmp.string();
+ UserMessage::debug("Tmp dir created: " + tmpDir_);
+ }
+ }
+ catch (const boost::filesystem::filesystem_error& e)
+ {
+ UserMessage::message(UserMessage::ERROR,true,"Creating tmp directory failed:" + std::string(e.what()));
+ }
+ }
+ }
+ else
+ {
+ UserMessage::message(UserMessage::ERROR, true,
+ "Neither of ECFLOWUI_TMPDIR and TMPDIR are defined. ecflowUI cannot be started up!");
+ exit(1);
+ }
+}
+
+
+std::string DirectoryHandler::concatenate(const std::string &path1, const std::string &path2)
+{
+ boost::filesystem::path p1(path1);
+ boost::filesystem::path p2(path2);
+ boost::filesystem::path result = p1 /= p2;
+ return result.string();
+}
+
+
+void DirectoryHandler::findDirContents(const std::string &dirPath,const std::string &filterStr, FileType type, std::vector<std::string>& res)
+{
+ boost::filesystem::path path(dirPath);
+ boost::filesystem::directory_iterator it(path), eod;
+
+ const boost::regex expr(filterStr);
+
+ BOOST_FOREACH(boost::filesystem::path const &p, std::make_pair(it, eod ))
+ {
+ boost::smatch what;
+ std::string fileName=p.filename().string();
+
+ bool rightType = (type == File) ? is_regular_file(p) : is_directory(p); // file or directory?
+
+ if(rightType && boost::regex_match(fileName, what,expr))
+ {
+ res.push_back(fileName);
+ }
+ }
+}
+
+
+void DirectoryHandler::findFiles(const std::string &dirPath,const std::string &filterStr,std::vector<std::string>& res)
+{
+ findDirContents(dirPath, filterStr, File, res);
+}
+
+void DirectoryHandler::findDirs(const std::string &dirPath,const std::string &filterStr,std::vector<std::string>& res)
+{
+ findDirContents(dirPath, filterStr, Dir, res);
+}
+
+bool DirectoryHandler::createDir(const std::string& path)
+{
+ //Create configDir if if does not exist
+ if(!boost::filesystem::exists(path))
+ {
+ try
+ {
+ boost::filesystem::create_directory(path);
+ }
+ catch(const boost::filesystem::filesystem_error& err)
+ {
+ UserMessage::message(UserMessage::ERROR, true,
+ "Could not create dir: " + path + " reason: " + err.what());
+ return false;
+ }
+ }
+
+ return true; // will also return true if the directory already exists
+}
+
+bool DirectoryHandler::isFirstStartUp()
+{
+ return firstStartUp;
+}
+
+//Return a unique non-existing tmp filename
+std::string DirectoryHandler::tmpFileName()
+{
+ boost::filesystem::path tmp(tmpDir_);
+ if(boost::filesystem::exists(tmp))
+ {
+ try
+ {
+ boost::filesystem::path model= tmp;
+ model /= "%%%%-%%%%-%%%%-%%%%";
+ return boost::filesystem::unique_path(model).string();
+ }
+ catch(const boost::filesystem::filesystem_error& err)
+ {
+ UserMessage::message(UserMessage::WARN, false,
+ std::string("Could not generate tmp filename! Reason: ") + err.what());
+ }
+ }
+
+ return std::string();
+}
+
+
+// -----------------------------------------------------
+// copyDir
+// recursively copy a directory and its contents
+// -----------------------------------------------------
+
+bool DirectoryHandler::copyDir(const std::string &srcDir, const std::string &destDir, std::string &errorMessage)
+{
+ boost::filesystem::path src(srcDir);
+ boost::filesystem::path dest(destDir);
+
+ // does the source directory exist (and is a directory)?
+ if (!boost::filesystem::exists(src) || !boost::filesystem::is_directory(src))
+ {
+ errorMessage = "Source directory (" + srcDir + ") does not exist";
+ return false;
+ }
+
+
+ // create the destination directory if it does not alreadt exist
+ if (!boost::filesystem::exists(dest))
+ {
+ bool created = createDir(dest.string());
+ if (!created)
+ {
+ errorMessage = "Could not create destination directory (" + destDir + ")";
+ return false;
+ }
+ }
+
+ // go through all the files/dirs in the
+ boost::filesystem::directory_iterator it(src), eod;
+ BOOST_FOREACH(boost::filesystem::path const &p, std::make_pair(it, eod))
+ {
+ std::string fileName = p.filename().string();
+
+ if (is_regular_file(p)) // file? then copy it into its new home
+ {
+ try
+ {
+ boost::filesystem::copy_file(p, dest / p.filename());
+ }
+ catch (const boost::filesystem::filesystem_error& err)
+ {
+ errorMessage = "Could not copy file " + fileName + " to " + destDir + "; reason: " + err.what();
+ return false;
+ }
+ }
+ else if (is_directory(p)) // directory? then copt it recursively
+ {
+ boost::filesystem::path destSubDir(destDir);
+ destSubDir /= p.filename();
+ return copyDir(p.string(), destSubDir.string(), errorMessage);
+ }
+ }
+
+ return true;
+}
+
+
+// --------------------------------------------------------
+// removeDir
+// Recursively removes the given directory and its contents
+// --------------------------------------------------------
+
+bool DirectoryHandler::removeDir(const std::string &dir, std::string &errorMessage)
+{
+ try
+ {
+ boost::filesystem::path d(dir);
+ remove_all(d);
+ }
+ catch (const boost::filesystem::filesystem_error& err)
+ {
+ errorMessage = "Could not remove directory " + dir + "; reason: " + err.what();
+ return false;
+ }
+
+ return true;
+}
+
+// --------------------------------------------------------
+// renameDir
+// Same as a 'move' - renames the directory
+// --------------------------------------------------------
+
+bool DirectoryHandler::renameDir(const std::string &dir, const std::string &newName, std::string &errorMessage)
+{
+ try
+ {
+ boost::filesystem::path d1(dir);
+ boost::filesystem::path d2(newName);
+ rename(d1, d2);
+ }
+ catch (const boost::filesystem::filesystem_error& err)
+ {
+ errorMessage = "Could not rename directory " + dir + "; reason: " + err.what();
+ return false;
+ }
+
+ return true;
+}
+
+// --------------------------------------------------------
+// removeFile
+// Removes the given file
+// --------------------------------------------------------
+
+bool DirectoryHandler::removeFile(const std::string &path, std::string &errorMessage)
+{
+ try
+ {
+ boost::filesystem::path f(path);
+ bool ok = remove(f);
+ }
+ catch (const boost::filesystem::filesystem_error& err)
+ {
+ errorMessage = "Could not remove file " + path + "; reason: " + err.what();
+ return false;
+ }
+
+ return true;
+}
+
diff --git a/Viewer/src/DirectoryHandler.hpp b/Viewer/src/DirectoryHandler.hpp
new file mode 100644
index 0000000..f85a6f6
--- /dev/null
+++ b/Viewer/src/DirectoryHandler.hpp
@@ -0,0 +1,54 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef DIRECTORY_HANDLER_HPP_
+#define DIRECTORY_HANDLER_HPP_
+
+#include <vector>
+
+class DirectoryHandler
+{
+public:
+ enum FileType {File, Dir};
+
+ DirectoryHandler();
+
+ static void init(const std::string& exePath);
+ static std::string shareDir() {return shareDir_;}
+ static std::string etcDir() {return etcDir_;}
+ static std::string configDir() {return configDir_;}
+ static std::string rcDir() {return rcDir_;}
+ static std::string concatenate(const std::string &path1, const std::string &path2);
+ static std::string tmpFileName();
+ static bool createDir(const std::string& path);
+
+ static void findDirContents(const std::string &dirPath,const std::string &filterStr,
+ FileType type, std::vector<std::string>& res);
+
+ static void findFiles(const std::string &dirPath,const std::string ®ExpPattern,
+ std::vector<std::string>& res);
+
+ static void findDirs(const std::string &dirPath,const std::string ®ExpPattern,
+ std::vector<std::string>& res);
+
+ static bool copyDir(const std::string &srcDir, const std::string &destDir, std::string &errorMessage);
+ static bool removeDir(const std::string &dir, std::string &errorMessage);
+ static bool renameDir(const std::string &dir, const std::string &newName, std::string &errorMessage);
+ static bool removeFile(const std::string &file, std::string &errorMessage);
+ static bool isFirstStartUp();
+
+private:
+ static std::string shareDir_;
+ static std::string etcDir_;
+ static std::string configDir_;
+ static std::string rcDir_;
+ static std::string tmpDir_;
+};
+
+#endif
diff --git a/Viewer/src/EditItemWidget.cpp b/Viewer/src/EditItemWidget.cpp
new file mode 100644
index 0000000..8bef98e
--- /dev/null
+++ b/Viewer/src/EditItemWidget.cpp
@@ -0,0 +1,151 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "EditItemWidget.hpp"
+
+#include "EditProvider.hpp"
+#include "Highlighter.hpp"
+#include "PropertyMapper.hpp"
+#include "VConfig.hpp"
+#include "VNode.hpp"
+#include "VReply.hpp"
+
+//========================================================
+//
+// EditItemWidget
+//
+//========================================================
+
+EditItemWidget::EditItemWidget(QWidget *parent) :
+ QWidget(parent),
+ preproc_(false),
+ alias_(false)
+{
+ setupUi(this);
+
+ infoProvider_=new EditProvider(this);
+
+ Highlighter* ih=new Highlighter(textEdit_->document(),"script");
+
+ searchLine_->setEditor(textEdit_);
+
+ searchLine_->setVisible(false);
+
+ externTb_->hide();
+
+ //connect(submitTb_,SIGNAL(clicked(bool)),
+ // this,SLOT(on_submitTb__clicked(bool)));
+
+ textEdit_->setProperty("edit","1");
+ textEdit_->setFontProperty(VConfig::instance()->find("panel.edit.font"));
+}
+
+QWidget* EditItemWidget::realWidget()
+{
+ return this;
+}
+
+void EditItemWidget::reload(VInfo_ptr info)
+{
+ assert(active_);
+
+ if(suspended_)
+ return;
+
+ clearContents();
+ info_=info;
+
+ //Info must be a node
+ if(info_ && info_->isNode() && info_->node())
+ {
+ //Get file contents
+ EditProvider* ep=static_cast<EditProvider*>(infoProvider_);
+ ep->preproc(preproc());
+ infoProvider_->info(info_);
+ }
+}
+
+void EditItemWidget::clearContents()
+{
+ InfoPanelItem::clear();
+ textEdit_->clear();
+}
+
+void EditItemWidget::infoReady(VReply* reply)
+{
+ QString s=QString::fromStdString(reply->text());
+ textEdit_->setPlainText(s);
+}
+
+void EditItemWidget::infoFailed(VReply*)
+{
+
+}
+void EditItemWidget::infoProgress(VReply*)
+{
+
+}
+
+void EditItemWidget::on_preprocTb__toggled(bool)
+{
+ reload(info_);
+}
+
+void EditItemWidget::on_submitTb__clicked(bool)
+{
+ QStringList lst=textEdit_->toPlainText().split("\n");
+ std::vector<std::string> txt;
+ Q_FOREACH(QString s,lst)
+ {
+ txt.push_back(s.toStdString());
+ }
+
+ EditProvider* ep=static_cast<EditProvider*>(infoProvider_);
+ ep->submit(txt,alias());
+}
+
+void EditItemWidget::on_searchTb__clicked()
+{
+ searchLine_->setVisible(true);
+ searchLine_->setFocus();
+ searchLine_->selectAll();
+}
+
+void EditItemWidget::on_gotoLineTb__clicked()
+{
+ textEdit_->gotoLine();
+}
+
+bool EditItemWidget::alias() const
+{
+ return aliasTb_->isChecked();
+}
+
+bool EditItemWidget::preproc() const
+{
+ return preprocTb_->isChecked();
+}
+
+//-----------------------------------------
+// Fontsize management
+//-----------------------------------------
+
+void EditItemWidget::on_fontSizeUpTb__clicked()
+{
+ //We need to call a custom slot here instead of "zoomIn"!!!
+ textEdit_->slotZoomIn();
+}
+
+void EditItemWidget::on_fontSizeDownTb__clicked()
+{
+ //We need to call a custom slot here instead of "zoomOut"!!!
+ textEdit_->slotZoomOut();
+}
+
+static InfoPanelItemMaker<EditItemWidget> maker1("edit");
diff --git a/Viewer/src/EditItemWidget.hpp b/Viewer/src/EditItemWidget.hpp
new file mode 100644
index 0000000..5ad6c3c
--- /dev/null
+++ b/Viewer/src/EditItemWidget.hpp
@@ -0,0 +1,58 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef EDITITEMWIDGET_HPP_
+#define EDITITEMWIDGET_HPP_
+
+#include <QWidget>
+
+#include "InfoPanelItem.hpp"
+#include "VInfo.hpp"
+
+#include "ui_EditItemWidget.h"
+
+class EditItemWidget : public QWidget, public InfoPanelItem, protected Ui::EditItemWidget
+{
+Q_OBJECT
+
+public:
+ explicit EditItemWidget(QWidget *parent=0);
+
+ void reload(VInfo_ptr);
+ QWidget* realWidget();
+ void clearContents();
+
+ //From VInfoPresenter
+ void infoReady(VReply*);
+ void infoFailed(VReply*);
+ void infoProgress(VReply*);
+
+ void nodeChanged(const VNode*, const std::vector<ecf::Aspect::Type>&) {}
+ void defsChanged(const std::vector<ecf::Aspect::Type>&) {}
+
+protected Q_SLOTS:
+ void on_preprocTb__toggled(bool);
+ void on_submitTb__clicked(bool);
+ void on_searchTb__clicked();
+ void on_gotoLineTb__clicked();
+ void on_fontSizeUpTb__clicked();
+ void on_fontSizeDownTb__clicked();
+
+protected:
+ bool preproc() const;
+ bool alias() const;
+ void updateState(const ChangeFlags&) {}
+
+ bool preproc_;
+ bool alias_;
+};
+
+#endif
+
diff --git a/Viewer/src/EditItemWidget.ui b/Viewer/src/EditItemWidget.ui
new file mode 100644
index 0000000..98ff27d
--- /dev/null
+++ b/Viewer/src/EditItemWidget.ui
@@ -0,0 +1,211 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>EditItemWidget</class>
+ <widget class="QWidget" name="EditItemWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>494</width>
+ <height>484</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3" stretch="0,1,0">
+ <property name="spacing">
+ <number>1</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QToolButton" name="aliasTb_">
+ <property name="toolTip">
+ <string>Send as alias</string>
+ </property>
+ <property name="text">
+ <string>Submit as alias</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="preprocTb_">
+ <property name="toolTip">
+ <string>Pre-process text</string>
+ </property>
+ <property name="text">
+ <string>Pre-process</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="fontSizeUpTb_">
+ <property name="toolTip">
+ <string>Increase font size in text editor <br><code>Ctrl++</code></string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/fontsize_up.svg</normaloff>:/viewer/fontsize_up.svg</iconset>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl++</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="fontSizeDownTb_">
+ <property name="toolTip">
+ <string>Decrease font size in text editor <br><code>Ctrl+-</code></string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/fontsize_down.svg</normaloff>:/viewer/fontsize_down.svg</iconset>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+-</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="externTb_">
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="searchTb_">
+ <property name="toolTip">
+ <string>Show search bar (CTRL-F)</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/search_decor.svg</normaloff>:/viewer/search_decor.svg</iconset>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+F</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="gotoLineTb_">
+ <property name="toolTip">
+ <string>Goto line number (CTRL-L)</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/images/goto_line.svg</normaloff>:/viewer/images/goto_line.svg</iconset>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+L</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="submitTb_">
+ <property name="toolTip">
+ <string>Submit</string>
+ </property>
+ <property name="text">
+ <string>Submit</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/submit.svg</normaloff>:/viewer/submit.svg</iconset>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="PlainTextEdit" name="textEdit_">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="lineWrapMode">
+ <enum>QPlainTextEdit::NoWrap</enum>
+ </property>
+ <property name="readOnly">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="PlainTextSearchLine" name="searchLine_" native="true"/>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>PlainTextSearchLine</class>
+ <extends>QWidget</extends>
+ <header>PlainTextSearchLine.hpp</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>PlainTextEdit</class>
+ <extends>QPlainTextEdit</extends>
+ <header location="global">PlainTextEdit.hpp</header>
+ </customwidget>
+ </customwidgets>
+ <resources>
+ <include location="viewer.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/Viewer/src/EditProvider.cpp b/Viewer/src/EditProvider.cpp
new file mode 100644
index 0000000..d2dfc4b
--- /dev/null
+++ b/Viewer/src/EditProvider.cpp
@@ -0,0 +1,125 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "EditProvider.hpp"
+
+#include "NodeFwd.hpp"
+
+#include "LogServer.hpp"
+#include "VNode.hpp"
+#include "VReply.hpp"
+#include "ServerHandler.hpp"
+#include "UserMessage.hpp"
+
+#include <boost/algorithm/string.hpp>
+
+//Node
+void EditProvider::visit(VInfoNode* info)
+{
+ //Reset the reply
+ reply_->reset();
+
+ if(!info)
+ {
+ owner_->infoFailed(reply_);
+ }
+
+ ServerHandler* server=info_->server();
+ VNode *n=info->node();
+
+ if(!n || !n->node())
+ {
+ owner_->infoFailed(reply_);
+ }
+
+ if (preproc_)
+ {
+ //Define a task for getting the info from the server.
+ task_=VTask::create(VTask::ScriptPreprocTask,n,this);
+ }
+ else
+ {
+ task_=VTask::create(VTask::ScriptEditTask,n,this);
+ }
+
+ //Run the task in the server. When it finishes taskFinished() is called. The text returned
+ //in the reply will be prepended to the string we generated above.
+ server->run(task_);
+}
+
+void EditProvider::submit(const std::vector<std::string>& txt,bool alias)
+{
+ if(!(info_ && info_.get() && info_->isNode() && info_->node()) && info_->server())
+ return;
+
+ VNode *node=info_->node();
+ ServerHandler* server=info_->server();
+
+ bool run=true;
+
+ //---------------------------
+ // Extract user variables
+ //---------------------------
+
+ static std::string defMicro="%";
+ static std::string comStartText = "comment - ecf user variables";
+ static std::string comEndText = "end - ecf user variables";
+
+ NameValueVec vars;
+
+ //Find out the micro
+ std::string microVar=node->findInheritedVariable("ECF_MICRO");
+ std::string micro = (microVar.size() == 1) ? microVar.c_str() : defMicro;
+
+ //Find out the full comment start and end texts
+ std::string comStart= micro + comStartText;
+ std::string comEnd= micro + comEndText;
+
+ bool inVars = false;
+ for(std::vector<std::string>::const_iterator it=txt.begin(); it != txt.end(); ++it)
+ {
+ const std::string& line=*it;
+
+ //We are in the variable block
+ if(inVars)
+ {
+ std::size_t pos = (*it).find("=");
+ if(pos != std::string::npos && pos+1 != (*it).size())
+ {
+ std::string name=(*it).substr(0,pos);
+ std::string val=(*it).substr(pos+1);
+ boost::trim(name);
+ boost::trim(val);
+ vars.push_back(std::make_pair(name,val));
+ }
+ }
+
+ if(line == comStart)
+ inVars = true;
+
+ if(line == comEnd)
+ break;
+ }
+
+ if(vars.empty())
+ {
+ UserMessage::message(UserMessage::DBG, false, std::string(" No user variables!"));
+ }
+
+
+ task_=VTask::create(VTask::ScriptSubmitTask,node,this);
+ task_->contents(txt);
+ task_->vars(vars);
+ task_->param("alias",(alias)?"1":"0");
+ task_->param("run",(run)?"1":"0");
+
+ //Run the task in the server. When it finishes taskFinished() is called. The text returned
+ //in the reply will be prepended to the string we generated above.
+ server->run(task_);
+}
diff --git a/Viewer/src/EditProvider.hpp b/Viewer/src/EditProvider.hpp
new file mode 100644
index 0000000..611a233
--- /dev/null
+++ b/Viewer/src/EditProvider.hpp
@@ -0,0 +1,34 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef EDITPROVIDER_HPP_
+#define EDITPROVIDER_HPP_
+
+#include "VDir.hpp"
+#include "VInfo.hpp"
+#include "InfoProvider.hpp"
+#include "VTask.hpp"
+#include "VTaskObserver.hpp"
+
+class EditProvider : public InfoProvider
+{
+public:
+ explicit EditProvider(InfoPresenter* owner) :
+ InfoProvider(owner,VTask::OutputTask), preproc_(false) {}
+
+ void visit(VInfoNode*);
+ void submit(const std::vector<std::string>& txt,bool alias);
+
+ void preproc(bool b) {preproc_=b;}
+
+private:
+ bool preproc_;
+};
+
+#endif
diff --git a/Viewer/src/EditorInfoLabel.cpp b/Viewer/src/EditorInfoLabel.cpp
new file mode 100644
index 0000000..ce9c762
--- /dev/null
+++ b/Viewer/src/EditorInfoLabel.cpp
@@ -0,0 +1,86 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "EditorInfoLabel.hpp"
+
+#include <QStringList>
+#include <QVariant>
+
+
+EditorInfoLabel::EditorInfoLabel(QWidget* parent) : QLabel(parent)
+{
+ //Define id for the css
+ setProperty("editorInfo","1");
+ setWordWrap(true);
+
+ //Set size policy
+ /*QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+ sizePolicy.setHorizontalStretch(0);
+ sizePolicy.setVerticalStretch(0);
+ sizePolicy.setHeightForWidth(this->sizePolicy().hasHeightForWidth());
+ setSizePolicy(sizePolicy);
+ //setMinimumSize(QSize(0, 60));
+ //setMaximumSize(QSize(16777215, 45));*/
+
+ setMargin(4);
+ setAlignment(Qt::AlignLeft|Qt::AlignVCenter);
+
+ //Other settings
+ setAutoFillBackground(true);
+
+ setFrameShape(QFrame::StyledPanel);
+ setTextInteractionFlags(Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse);
+}
+
+void EditorInfoLabel::setInfo(QString parent,QString type)
+{
+ setText(formatKeyLabel("Node: ") + formatNodePath(parent) + "<br>" +
+ formatKeyLabel("Attibute type: ") + type);
+}
+
+static QColor nodeNameColour(7,108,209);
+static QColor serverNameColour(0,0,0);
+static QColor labelColour(59,60,61);
+
+QString EditorInfoLabel::formatKeyLabel(QString n)
+{
+ return "<font color=\'" + labelColour.name() + "\'><b>" + n + "</b></font>";
+}
+
+QString EditorInfoLabel::formatNodeName(QString n)
+{
+ return "<font color=\'" + nodeNameColour.name() + "\'>" + n + "</font>";
+}
+
+QString EditorInfoLabel::formatNodePath(QString p)
+{
+ if(p.endsWith("://"))
+ {
+ return p;
+ }
+
+ QStringList lst=p.split("/");
+ if(lst.count() > 0)
+ {
+ QString n=lst.back();
+ lst.pop_back();
+ QColor c(80,80,80);
+ QString s="<font color=\'" + c.name() + "\'>" + lst.join("/") + "/" +
+ "</font><font color=\'" + serverNameColour.name() + "\'>" + n + "</font>";
+ return s;
+ }
+
+ return p;
+}
+
+
+
+
+
diff --git a/Viewer/src/EditorInfoLabel.hpp b/Viewer/src/EditorInfoLabel.hpp
new file mode 100644
index 0000000..545dbda
--- /dev/null
+++ b/Viewer/src/EditorInfoLabel.hpp
@@ -0,0 +1,27 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef EDITORINFOLABEL_HPP
+#define EDITORINFOLABEL_HPP
+
+#include <QLabel>
+
+class EditorInfoLabel : public QLabel
+{
+public:
+ explicit EditorInfoLabel(QWidget* parent=0);
+ void setInfo(QString parent,QString type);
+
+ static QString formatKeyLabel(QString n);
+ static QString formatNodeName(QString n);
+ static QString formatNodePath(QString p);
+};
+
+#endif // EDITORINFOLABEL_HPP
diff --git a/Viewer/src/ExpandState.cpp b/Viewer/src/ExpandState.cpp
new file mode 100644
index 0000000..8c05c0d
--- /dev/null
+++ b/Viewer/src/ExpandState.cpp
@@ -0,0 +1,217 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "ExpandState.hpp"
+
+#include <QTreeView>
+
+#include "TreeNodeModel.hpp"
+#include "VNode.hpp"
+#include "VTree.hpp"
+
+//-------------------------------------
+// ExapandStateNode
+//-------------------------------------
+
+ExpandStateNode::~ExpandStateNode()
+{
+ clear();
+}
+
+void ExpandStateNode::clear()
+{
+ name_.clear();
+ for(unsigned int i=0; i < children_.size(); i++)
+ {
+ delete children_.at(i);
+ }
+ children_.clear();
+}
+
+ExpandStateNode* ExpandStateNode::add(const std::string& name)
+{
+ ExpandStateNode *n=new ExpandStateNode(name);
+ children_.push_back(n);
+ return n;
+}
+
+//-------------------------------------
+// ExapandStateTree
+//-------------------------------------
+
+ExpandStateTree::ExpandStateTree(QTreeView * view,TreeNodeModel* model) :
+ view_(view), model_(model), root_(0)
+{
+}
+
+ExpandStateTree::~ExpandStateTree()
+{
+ clear();
+}
+
+void ExpandStateTree::clear()
+{
+ if(root_)
+ delete root_;
+
+ root_=0;
+}
+
+bool ExpandStateTree::rootSameAs(const std::string& name) const
+{
+ return (root_ && root_->name_ == name);
+}
+
+ExpandStateNode* ExpandStateTree::setRoot(const std::string& name)
+{
+ if(root_)
+ clear();
+
+ root_=new ExpandStateNode(name);
+ return root_;
+}
+
+
+//Save the expand state for the given node (it can be a server as well)
+void ExpandStateTree::save(const VTreeNode *root)
+{
+ assert(root);
+
+ clear();
+
+#if 0
+ VInfo_ptr s=currentSelection();
+ if(s)
+ {
+ if(node->server() == s->server())
+ expandState_->selection_=s;
+ }
+#endif
+
+ QModelIndex rootIdx=model_->nodeToIndex(root);
+ if(view_->isExpanded(rootIdx))
+ {
+ setRoot(root->vnode()->strName());
+ save(root_,rootIdx);
+ }
+}
+
+void ExpandStateTree::save(ExpandStateNode *parentExpand,const QModelIndex& parentIdx)
+{
+ for(int i=0; i < model_->rowCount(parentIdx); i++)
+ {
+ QModelIndex chIdx=model_->index(i, 0, parentIdx);
+
+ if(!view_->isExpanded(chIdx))
+ continue;
+ else
+ {
+ ExpandStateNode* expand=parentExpand->add(chIdx.data(Qt::DisplayRole).toString().toStdString());
+ save(expand,chIdx);
+ }
+ }
+}
+
+
+
+//Save the expand state for the given node (it can be a server as well)
+void ExpandStateTree::restore(const VTreeNode* node)
+{
+ if(!root_)
+ return;
+
+ if(node->vnode()->strName() != root_->name_)
+ {
+ clear();
+ return;
+ }
+
+ restore(root_,node);
+
+#if 0
+ if(expandState_->selection_)
+ {
+ VInfo_ptr s=currentSelection();
+ if(!s)
+ {
+ expandState_->selection_->regainData();
+ currentSelection(expandState_->selection_);
+ }
+ }
+#endif
+
+ clear();
+}
+
+void ExpandStateTree::restore(ExpandStateNode *expand,const VTreeNode* node)
+{
+ //Lookup the node in the model
+ QModelIndex nodeIdx=model_->nodeToIndex(node);
+ if(nodeIdx != QModelIndex())
+ {
+ view_->setExpanded(nodeIdx,true);
+ }
+ else
+ {
+ return;
+ }
+
+ for(int i=0; i < expand->children_.size(); i++)
+ {
+ ExpandStateNode *chExpand=expand->children_.at(i);
+ std::string name=chExpand->name_;
+
+ if(VTreeNode *chNode=node->findChild(name))
+ {
+ QModelIndex chIdx=model_->nodeToIndex(chNode);
+ if(chIdx != QModelIndex())
+ {
+ //setExpanded(chIdx,true);
+ restore(chExpand,chNode);
+ }
+ }
+ }
+}
+//-------------------------------------
+// ExapandState
+//-------------------------------------
+
+ExpandState::ExpandState(QTreeView* view,TreeNodeModel* model) : view_(view), model_(model)
+{
+
+}
+
+
+ExpandState::~ExpandState()
+{
+ clear();
+}
+
+ExpandStateTree* ExpandState::add()
+{
+ ExpandStateTree* et=new ExpandStateTree(view_,model_);
+ items_ << et;
+ return et;
+}
+
+void ExpandState::remove(ExpandStateTree* es)
+{
+ items_.removeOne(es);
+ delete es;
+}
+
+void ExpandState::clear()
+{
+ Q_FOREACH(ExpandStateTree* et,items_)
+ {
+ delete et;
+ }
+ items_.clear();
+ selection_.reset();
+}
diff --git a/Viewer/src/ExpandState.hpp b/Viewer/src/ExpandState.hpp
new file mode 100644
index 0000000..93d9207
--- /dev/null
+++ b/Viewer/src/ExpandState.hpp
@@ -0,0 +1,90 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef EXPANDNODE_HPP_
+#define EXPANDNODE_HPP_
+
+#include <string>
+#include <vector>
+
+#include <QList>
+
+#include "VInfo.hpp"
+
+class TreeNodeModel;
+class QModelIndex;
+class QTreeView;
+class VTreeNode;
+
+class ExpandStateNode
+{
+ friend class TreeNodeView;
+
+public:
+ explicit ExpandStateNode(const std::string& name) : name_(name) {}
+ ExpandStateNode() : name_("") {}
+ ~ExpandStateNode();
+
+ void clear();
+ ExpandStateNode* add(const std::string&);
+
+ std::vector<ExpandStateNode*> children_;
+ std::string name_;
+
+};
+
+class ExpandStateTree
+{
+ friend class TreeNodeView;
+
+public:
+ explicit ExpandStateTree(QTreeView*,TreeNodeModel*);
+ ~ExpandStateTree();
+
+ bool rootSameAs(const std::string&) const;
+ void save(const VTreeNode*);
+ void restore(const VTreeNode*);
+
+protected:
+ void clear();
+ ExpandStateNode* setRoot(const std::string&);
+ ExpandStateNode* root() const {return root_;}
+ void save(ExpandStateNode*,const QModelIndex&);
+ void restore(ExpandStateNode*,const VTreeNode*);
+
+ QTreeView* view_;
+ TreeNodeModel* model_;
+ ExpandStateNode* root_;
+};
+
+class ExpandState
+{
+ friend class TreeNodeView;
+
+public:
+ ExpandState(QTreeView*,TreeNodeModel*);
+ ~ExpandState();
+ ExpandStateTree* add();
+ void remove(ExpandStateTree*);
+ void clear();
+ QList<ExpandStateTree*> items() const {return items_;}
+
+protected:
+ QTreeView* view_;
+ TreeNodeModel* model_;
+ VInfo_ptr selection_;
+ QList<ExpandStateTree*> items_;
+
+};
+
+#endif
+
+
+
diff --git a/Viewer/src/FileInfoLabel.cpp b/Viewer/src/FileInfoLabel.cpp
new file mode 100644
index 0000000..388097b
--- /dev/null
+++ b/Viewer/src/FileInfoLabel.cpp
@@ -0,0 +1,275 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "FileInfoLabel.hpp"
+
+#include <QDateTime>
+#include <QVariant>
+
+#include "VFileInfo.hpp"
+#include "VReply.hpp"
+
+FileInfoLabel::FileInfoLabel(QWidget* parent) : QLabel(parent)
+{
+ //Define id for the css
+ setProperty("fileInfo","1");
+ setWordWrap(true);
+
+ //Set size policy
+ /*QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+ sizePolicy.setHorizontalStretch(0);
+ sizePolicy.setVerticalStretch(0);
+ sizePolicy.setHeightForWidth(this->sizePolicy().hasHeightForWidth());
+ setSizePolicy(sizePolicy);
+ //setMinimumSize(QSize(0, 60));
+ //setMaximumSize(QSize(16777215, 45));*/
+
+ setMargin(2);
+ setAlignment(Qt::AlignLeft|Qt::AlignVCenter);
+
+ //Other settings
+ setAutoFillBackground(true);
+
+ setFrameShape(QFrame::StyledPanel);
+ setTextInteractionFlags(Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse);
+
+}
+
+void FileInfoLabel::update(VReply* reply,QString extraText)
+{
+ if(!reply)
+ clear();
+
+ QString labelText;
+ QString ttText;
+ QString s;
+
+ QColor col(39,49,101);
+ QColor colText("#000010");
+ QColor colSize(0,0,255);
+ QColor colErr(255,0,0);
+
+ QString fileName=QString::fromStdString(reply->fileName());
+
+ if(fileName.isEmpty())
+ {
+ s="<b><font color=" + col.name() + ">File: </font></b>";
+ s+="<font color=" + colErr.name() + "> ??? </font>";
+ setText(s);
+ setToolTip(QString());
+ return;
+ }
+
+ //Name
+ labelText="<b><font color=" + col.name() + ">File: </font></b>";
+ labelText+="<font color=" +colText.name() + ">" + fileName + "</font>";
+
+ //VFileInfo f(fileName);
+
+ s="";
+
+ //Local read
+ if(reply->fileReadMode() == VReply::LocalReadMode)
+ {
+ VFile_ptr f=reply->tmpFile();
+ if(f)
+ {
+ VFileInfo fInfo(QString::fromStdString(f->path()));
+ if(fInfo.exists())
+ {
+ labelText+="<b><font color=" + col.name() + "> Size: </font></b>";
+ labelText+="<font color=" + fileSizeColour(fInfo.size()).name() + "> " + fInfo.formatSize() + "</font>";
+ s+="<b><font color=" + col.name() + "> Modified: </font></b>";
+ s+="<font color=" + colText.name() + ">" + fInfo.formatModDate() + "</font>";
+
+ }
+ }
+ else
+ {
+ VFileInfo f(fileName);
+ if(f.exists())
+ {
+ labelText+="<b><font color=" + col.name() + "> Size: </font></b>";
+ labelText+="<font color=" + fileSizeColour(f.size()).name() + "> " + f.formatSize() + "</font>";
+
+ s+="<b><font color=" + col.name() + "> Modified: </font></b>";
+ s+="<font color=" + colText.name() + ">" + f.formatModDate() + "</font>";
+ }
+ }
+
+ s+="<br>";
+ s+="<b><font color=" + col.name() + "> Source: </font></b>";
+ s+="<font color=" + colText.name() + "> read from disk</font>";
+
+ if(f)
+ {
+ QString dt=f->fetchDate().toString("yyyy-MM-dd HH:mm:ss");
+ s+="<b><font color=" + col.name() + "> at </font></b>";
+ s+="<font color=" + colText.name() + ">" + dt + + "</font>";
+ }
+
+ }
+ else if(reply->fileReadMode() == VReply::ServerReadMode)
+ {
+ VFile_ptr f=reply->tmpFile();
+ if(f)
+ {
+ if(f->storageMode() == VFile::MemoryStorage)
+ {
+ labelText+="<b><font color=" + col.name() + "> Size: </font></b>";
+ labelText+="<font color=" + fileSizeColour(f->dataSize()).name() + "> " + VFileInfo::formatSize(f->dataSize()) + "</font>";
+ }
+ else
+ {
+ VFileInfo fInfo(QString::fromStdString(f->path()));
+ if(fInfo.exists())
+ {
+ //s+="<br>";
+ labelText+="<b><font color=" + col.name() + "> Size: </font></b>";
+ labelText+="<font color=" + fileSizeColour(fInfo.size()).name() + "> " + fInfo.formatSize() + "</font>";
+ }
+ }
+
+ s+="<br>";
+ s+="<b><font color=" + col.name() + "> Source: </font></b>";
+ s+="<font color=" + colText.name() + "> " + QString::fromStdString(f->fetchModeStr()) + "</font>";
+
+ QString dt=f->fetchDate().toString("yyyy-MM-dd HH:mm:ss");
+ s+="<b><font color=" + col.name() + "> at </font></b>";
+ s+="<font color=" + colText.name() + ">" + dt + + "</font>";
+
+ int rowLimit=f->truncatedTo();
+ if(rowLimit >= 0)
+ {
+ s+=" (<i>text truncated to last " + QString::number(rowLimit) + " lines</i>)";
+ }
+ s+="</font>";
+ }
+ else if(reply->status() == VReply::TaskDone)
+ {
+ QString dt=QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss");
+ //s+="<b><font color=" + col.name() + "> Fetched: </font></b>";
+ //s+="<font color=" + colText.name() + ">" + dt + + "</font>";
+
+ s+="<br>";
+ s+="<b><font color=" + col.name() + "> Source: </font></b><font color=" + colText.name() + "> fetched from server </font>" +
+ //"<font color=" + colHighlight.name() + "server </font>" +
+ " <font color=" + col.name() + "> <b>at</b> </font><font color=" + colText.name() + ">" + dt + "</font>";
+
+ int rowLimit=reply->readTruncatedTo();
+ if(rowLimit >= 0)
+ {
+ s+=" (<i>text truncated to last " + QString::number(rowLimit) + " lines</i>)";
+ }
+ s+="</font>";
+ }
+ else
+ {
+ QString dt=QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss");
+ s+="<br>Fetch attempted from server<font color=" + col.name() + "> <b>at</b> </font>" + dt;
+ }
+ }
+
+ else if(reply->fileReadMode() == VReply::LogServerReadMode)
+ {
+ VFile_ptr f=reply->tmpFile();
+ if(f)
+ {
+ if(f->storageMode() == VFile::MemoryStorage)
+ {
+ labelText+="<b><font color=" + col.name() + "> Size: </font></b>";
+ labelText+="<font color=" + fileSizeColour(f->dataSize()).name() + "> " + VFileInfo::formatSize(f->dataSize()) + "</font>";
+ }
+ else
+ {
+ VFileInfo fInfo(QString::fromStdString(f->path()));
+ if(fInfo.exists())
+ {
+ //s+="<br>";
+ labelText+="<b><font color=" + col.name() + "> Size: </font></b>";
+ labelText+="<font color=" + fileSizeColour(fInfo.size()).name() + "> " + fInfo.formatSize() + "</font>";
+ }
+ }
+
+ s+="<br>";
+ s+="<b><font color=" + col.name() + "> Source: </font></b>";
+ s+="<font color=" + colText.name() + "> " + QString::fromStdString(f->fetchModeStr()) + "</font>";
+
+ //s+=" (took <font color=" + colSize.name() + "> " + QString::number(static_cast<float>(tmp->transferDuration())/1000.,'f',1) + " s </font>)";
+ s+=" (took " + QString::number(static_cast<float>(f->transferDuration())/1000.,'f',1) + " s)";
+
+ QString dt=f->fetchDate().toString("yyyy-MM-dd HH:mm:ss");
+ s+="<b><font color=" + col.name() + "> at </font></b>";
+ s+="<font color=" + colText.name() + ">" + dt + + "</font>";
+ if(f->cached())
+ {
+ s+=" (<b> read from cache</b>)";
+ }
+ }
+ }
+
+ ttText=s;
+ labelText += ttText;
+ if(!extraText.isEmpty())
+ {
+ labelText +=" <i>" + extraText + "</i>";
+ }
+
+ setText(labelText);
+ //setToolTip(ttText);
+}
+
+QColor FileInfoLabel::fileSizeColour(qint64 size) const
+{
+ QColor col(0,0,255);
+ if(size > 10*1024*1024)
+ col=QColor(Qt::red);
+ /*else if( size > 10*1024*1024)
+ col=QColor(255,166,0);*/
+
+ return col;
+}
+
+void DirInfoLabel::update(VDir_ptr dir)
+{
+ if(!dir)
+ clear();
+
+ QString s;
+ QColor col(Qt::black);
+ QColor colText("#000010");
+ QColor colSize(0,0,255);
+ QColor colErr(255,0,0);
+
+ QString dirName=QString::fromStdString(dir->path());
+
+ if(dirName.isEmpty())
+ {
+ s="<b><font color=" + col.name() + ">Directory: </font></b>";
+ s+="<font color=" + colErr.name() + "> ??? </font>";
+ setText(s);
+ return;
+ }
+
+ //Name
+ s="<b><font color=" + col.name() + ">Directory: </font></b>";
+ s+="<font color=" +colText.name() + ">" + dirName + "</font>";
+
+ //Where
+ QString where=QString::fromStdString(dir->where());
+ if(where.isEmpty())
+ where="???";
+
+ s+="<br>";
+ s+="<b><font color=" + col.name() + ">Host: </font></b>";
+ s+="<font color=" +colText.name() + ">" + where + "</font>";
+
+ setText(s);
+}
diff --git a/Viewer/src/FileInfoLabel.hpp b/Viewer/src/FileInfoLabel.hpp
new file mode 100644
index 0000000..eefde4b
--- /dev/null
+++ b/Viewer/src/FileInfoLabel.hpp
@@ -0,0 +1,39 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef FILEINFOLABEL_HPP_
+#define FILEINFOLABEL_HPP_
+
+#include <QLabel>
+
+#include "VDir.hpp"
+
+class VReply;
+
+class FileInfoLabel : public QLabel
+{
+public:
+ explicit FileInfoLabel(QWidget* parent=0);
+
+ void update(VReply*,QString str=QString());
+ QColor fileSizeColour(qint64 size) const;
+
+};
+
+class DirInfoLabel : public FileInfoLabel
+{
+public:
+ explicit DirInfoLabel(QWidget* parent=0) : FileInfoLabel(parent) {}
+
+ void update(VDir_ptr);
+
+};
+
+#endif
diff --git a/Viewer/src/FileWatcher.cpp b/Viewer/src/FileWatcher.cpp
new file mode 100644
index 0000000..85f4a15
--- /dev/null
+++ b/Viewer/src/FileWatcher.cpp
@@ -0,0 +1,39 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "FileWatcher.hpp"
+
+FileWatcher::FileWatcher(const std::string& filePath,qint64 offset,QObject* parent) :
+ QFileSystemWatcher(parent),
+ offset_(offset)
+{
+ connect(this,SIGNAL(fileChanged(QString)),
+ this,SLOT(slotChanged(QString)));
+
+ file_.setFileName(QString::fromStdString(filePath));
+ if (!file_.open(QIODevice::ReadOnly | QIODevice::Text))
+ return;
+ file_.seek(offset_);
+
+ addPath(file_.fileName());
+}
+
+void FileWatcher::slotChanged(const QString& path)
+{
+ QStringList lst;
+ if(path == file_.fileName())
+ {
+ while (!file_.atEnd())
+ lst << file_.readLine();
+ }
+
+ Q_EMIT linesAppended(lst);
+
+}
diff --git a/Viewer/src/FileWatcher.hpp b/Viewer/src/FileWatcher.hpp
new file mode 100644
index 0000000..2e33bf6
--- /dev/null
+++ b/Viewer/src/FileWatcher.hpp
@@ -0,0 +1,37 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VIEWER_SRC_FILEWATCHER_HPP_
+#define VIEWER_SRC_FILEWATCHER_HPP_
+
+#include <QFileSystemWatcher>
+#include <QFile>
+#include <QStringList>
+
+class FileWatcher : public QFileSystemWatcher
+{
+Q_OBJECT
+
+public:
+ FileWatcher(const std::string& filePath,qint64 offset,QObject* parent);
+
+protected Q_SLOTS:
+ void slotChanged(const QString& path);
+
+Q_SIGNALS:
+ void linesAppended(QStringList);
+
+protected:
+ QFile file_;
+ qint64 offset_;
+};
+
+
+#endif /* VIEWER_SRC_FILEWATCHER_HPP_ */
diff --git a/Viewer/src/FilterWidget.cpp b/Viewer/src/FilterWidget.cpp
new file mode 100644
index 0000000..058e299
--- /dev/null
+++ b/Viewer/src/FilterWidget.cpp
@@ -0,0 +1,497 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "FilterWidget.hpp"
+
+#include <QDebug>
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QLinearGradient>
+#include <QPainter>
+#include <QPalette>
+#include <QPixmap>
+#include <QToolButton>
+#include <QVBoxLayout>
+#include <QWidgetAction>
+
+#include "VNState.hpp"
+#include "VAttributeType.hpp"
+#include "VConfig.hpp"
+#include "VIcon.hpp"
+#include "VFilter.hpp"
+
+#include "ServerItem.hpp"
+#include "ServerFilter.hpp"
+
+//===========================================
+//
+// VParamFilterMenu
+//
+//===========================================
+
+VParamFilterMenu::VParamFilterMenu(QMenu * parent,VParamSet* filter,QString title,ItemMode itemMode,DecorMode decorMode) :
+ menu_(parent),
+ filter_(filter),
+ itemMode_(itemMode),
+ decorMode_(decorMode)
+{
+ buildTitle(title,parent);
+
+ QAction* acSep = new QAction(this);
+ acSep->setSeparator(true);
+ menu_->addAction(acSep);
+
+ //Param name must be unique
+ for(std::set<VParam*>::const_iterator it=filter_->all().begin(); it != filter_->all().end(); ++it)
+ {
+ addAction((*it)->label(),
+ (*it)->name());
+ }
+
+ if(decorMode_ == ColourDecor)
+ {
+ QLinearGradient grad;
+ grad.setCoordinateMode(QGradient::ObjectBoundingMode);
+ grad.setStart(0,0);
+ grad.setFinalStop(0,1);
+
+ int lighter=150;
+ bool useStateGrad=true;
+ if(VProperty* p=VConfig::instance()->find("view.common.node_gradient"))
+ {
+ useStateGrad=p->value().toBool();
+ }
+
+ QFont f;
+ QFontMetrics fm(f);
+ int pixSize=fm.height()-2;
+
+ Q_FOREACH(QAction* ac,menu_->actions())
+ {
+ if(!ac->isSeparator())
+ {
+ if(VNState* vs=VNState::find(ac->data().toString().toStdString()))
+ {
+ //Fill rect
+ QColor bg=vs->colour();
+ QColor bgLight=bg.lighter(lighter);
+ QColor border=bg.darker(125);
+ QBrush bgBrush;
+ if(useStateGrad)
+ {
+ grad.setColorAt(0,bgLight);
+ grad.setColorAt(1,bg);
+ bgBrush=QBrush(grad);
+ }
+ else
+ bgBrush=QBrush(bg);
+
+ QPixmap pix(pixSize,pixSize);
+ QPainter painter(&pix);
+
+ QRect fillRect(0,0,pixSize,pixSize);
+ painter.fillRect(fillRect,bgBrush);
+ painter.setPen(border);
+ painter.drawRect(fillRect.adjusted(0,0,-1,-1));
+ ac->setIcon(pix);
+ }
+ }
+ }
+ }
+
+ QAction *ac = new QAction(this);
+ ac->setSeparator(true);
+ menu_->addAction(ac);
+
+ if(itemMode_ == FilterMode)
+ {
+ ac = new QAction(this);
+ ac->setText(tr("Clear filter"));
+ menu_->addAction(ac);
+ connect(ac,SIGNAL(triggered(bool)),
+ this,SLOT(slotUnselectAll(bool)));
+ }
+ else
+ {
+ ac = new QAction(this);
+ ac->setText(tr("Show all"));
+ menu_->addAction(ac);
+ connect(ac,SIGNAL(triggered(bool)),
+ this,SLOT(slotSelectAll(bool)));
+
+ ac = new QAction(this);
+ ac->setText(tr("Hide all"));
+ menu_->addAction(ac);
+ connect(ac,SIGNAL(triggered(bool)),
+ this,SLOT(slotUnselectAll(bool)));
+
+ }
+
+ reload();
+}
+
+void VParamFilterMenu::buildTitle(QString title,QMenu* parent)
+{
+ QLabel* titleLabel=new QLabel(title,menu_);
+ QFont f=menu_->font();
+ f.setBold(true);
+ titleLabel->setFont(f);
+ titleLabel->setAlignment(Qt::AlignHCenter);
+ titleLabel->setAutoFillBackground(true);
+ QPalette pal=titleLabel->palette();
+ QColor winCol=menu_->palette().color(QPalette::Window);
+ pal.setColor(QPalette::Window,QColor(237,238,238));
+ titleLabel->setPalette(pal);
+
+ int titlePadding=3;
+ int topMargin=2;
+ if(parent && parent->isTearOffEnabled())
+ {
+ titlePadding=1;
+ topMargin=0;
+ }
+
+ QString titleQss="QLabel {padding: " + QString::number(titlePadding) + "px;}";
+ titleLabel->setStyleSheet(titleQss);
+
+ QWidget *w=new QWidget(menu_);
+ QVBoxLayout *vb=new QVBoxLayout(w);
+ vb->setContentsMargins(2,topMargin,2,2);
+ //vb->addSpacing(2);
+ vb->addWidget(titleLabel);
+ //vb->addSpacing(2);
+
+ QWidgetAction *titleAc = new QWidgetAction(menu_);
+ //Qt doc says: the ownership of the widget is passed to the widgetaction.
+ //So when the action is deleted it will be deleted as well.
+ titleAc->setDefaultWidget(w);
+ //titleAc->setEnabled(false);
+ menu_->addAction(titleAc);
+}
+
+
+void VParamFilterMenu::addAction(QString name,QString id)
+{
+ QAction *ac = new QAction(this);
+ ac->setText(name);
+ ac->setData(id);
+ ac->setCheckable(true);
+ ac->setChecked(false);
+
+ menu_->addAction(ac);
+
+ //It will not be emitted when setChecked is called!
+ connect(ac,SIGNAL(triggered(bool)),
+ this,SLOT(slotChanged(bool)));
+}
+
+void VParamFilterMenu::slotSelectAll(bool)
+{
+ Q_FOREACH(QAction* ac,menu_->actions())
+ {
+ if(!ac->isSeparator() &&
+ ac->isCheckable())
+ {
+ ac->setChecked(true);
+ }
+ }
+
+ slotChanged(true);
+}
+
+void VParamFilterMenu::slotUnselectAll(bool)
+{
+ Q_FOREACH(QAction* ac,menu_->actions())
+ {
+ if(!ac->isSeparator() &&
+ ac->isCheckable())
+ {
+ ac->setChecked(false);
+ }
+ }
+
+ slotChanged(true);
+}
+
+void VParamFilterMenu::slotChanged(bool)
+{
+ std::set<std::string> items;
+ Q_FOREACH(QAction* ac,menu_->actions())
+ {
+ if(!ac->isSeparator() &&
+ ac->isCheckable() && ac->isChecked())
+ {
+ items.insert(ac->data().toString().toStdString());
+ }
+ }
+
+ if(filter_)
+ filter_->current(items);
+}
+
+void VParamFilterMenu::reload()
+{
+ Q_FOREACH(QAction* ac,menu_->actions())
+ {
+ if(!ac->isSeparator())
+ {
+ ac->setChecked(filter_->isSet(ac->data().toString().toStdString()));
+ }
+ }
+}
+
+//===========================================
+//
+// ServerFilterMenu
+//
+//===========================================
+
+ServerFilterMenu::ServerFilterMenu(QMenu * parent) :
+ menu_(parent),
+ filter_(NULL)
+{
+ loadFont_.setBold(true);
+
+ allMenu_=new QMenu("All servers",menu_);
+ menu_->addMenu(allMenu_);
+
+ QAction* acFavSep = new QAction(this);
+ acFavSep->setSeparator(true);
+ menu_->addAction(acFavSep);
+
+ QAction* acFavTitle = new QAction(this);
+ acFavTitle->setText(tr("Favourite or loaded servers"));
+ QFont f=acFavTitle->font();
+ f.setBold(true);
+ acFavTitle->setFont(f);
+
+ menu_->addAction(acFavTitle);
+
+ init();
+
+ ServerList::instance()->addObserver(this);
+}
+
+ServerFilterMenu::~ServerFilterMenu()
+{
+ ServerList::instance()->removeObserver(this);
+ if(filter_)
+ filter_->removeObserver(this);
+}
+
+void ServerFilterMenu::aboutToDestroy()
+{
+ ServerList::instance()->removeObserver(this);
+ if(filter_)
+ filter_->removeObserver(this);
+
+ clear();
+}
+
+void ServerFilterMenu::clear()
+{
+ Q_FOREACH(QAction* ac,acAllMap_)
+ {
+ delete ac;
+ }
+ acAllMap_.clear();
+
+ clearFavourite();
+}
+
+void ServerFilterMenu::clearFavourite()
+{
+ Q_FOREACH(QAction* ac,acFavMap_)
+ {
+ delete ac;
+ }
+ acFavMap_.clear();
+}
+
+void ServerFilterMenu::init()
+{
+ clear();
+
+ for(int i=0; i < ServerList::instance()->count(); i++)
+ {
+ ServerItem* item=ServerList::instance()->itemAt(i);
+ QString name=QString::fromStdString(item->name());
+ QAction *ac=createAction(name,i);
+ acAllMap_[name]=ac;
+ }
+
+ Q_FOREACH(QAction *ac,acAllMap_)
+ {
+ allMenu_->addAction(ac);
+ }
+
+ buildFavourite();
+}
+
+void ServerFilterMenu::buildFavourite()
+{
+ clearFavourite();
+
+ for(int i=0; i < ServerList::instance()->count(); i++)
+ {
+ ServerItem* item=ServerList::instance()->itemAt(i);
+ if(item->isFavourite() || (filter_ && filter_->isFiltered(item)))
+ {
+ QString name=QString::fromStdString(item->name());
+ acFavMap_[name]=createAction(name,i);
+ }
+ }
+
+ Q_FOREACH(QAction *ac,acFavMap_)
+ {
+ menu_->addAction(ac);
+ }
+
+}
+
+QAction* ServerFilterMenu::createAction(QString name,int id)
+{
+ QAction *ac = new QAction(this);
+ ac->setText(name);
+ ac->setData(id);
+ ac->setCheckable(true);
+ ac->setChecked(false);
+
+ //It will not be emitted when setChecked is called!!
+ connect(ac,SIGNAL(triggered(bool)),
+ this,SLOT(slotChanged(bool)));
+
+ return ac;
+}
+
+
+void ServerFilterMenu::slotChanged(bool)
+{
+ if(!filter_)
+ return;
+
+ if(QAction *ac=static_cast<QAction*>(sender()))
+ {
+ if(ac->isSeparator()) return;
+
+ if(ServerItem *item=ServerList::instance()->itemAt(ac->data().toInt()))
+ {
+ QString name=ac->text();
+ bool checked=ac->isChecked();
+ if(checked)
+ filter_->addServer(item);
+ else
+ filter_->removeServer(item);
+
+ //At this point the action (ac) might be deleted so
+ //we need to use the name and check state for syncing
+ syncActionState(name,checked);
+ }
+ }
+}
+
+void ServerFilterMenu::syncActionState(QString name,bool checked)
+{
+ QMap<QString,QAction*>::const_iterator it = acAllMap_.find(name);
+ if(it != acAllMap_.end() && it.value()->isChecked() != checked)
+ {
+ //Triggered() will not be called!!
+ it.value()->setChecked(checked);
+ }
+
+ it = acFavMap_.find(name);
+ if(it != acFavMap_.end() && it.value()->isChecked() != checked)
+ {
+ //Triggered() will not be called!!
+ it.value()->setChecked(checked);
+ }
+}
+
+//Reset actions state when a new filter is loaded
+void ServerFilterMenu::reload(ServerFilter *filter)
+{
+ if(filter_)
+ filter_->removeObserver(this);
+
+ filter_=filter;
+
+ if(filter_)
+ filter_->addObserver(this);
+
+ reload();
+}
+
+//Reset actions state when a new filter is loaded
+void ServerFilterMenu::reload()
+{
+ buildFavourite();
+
+ QMap<QString,QAction*>::const_iterator it=acAllMap_.constBegin();
+ while(it != acAllMap_.constEnd())
+ {
+ if(ServerItem *item=ServerList::instance()->find(it.value()->text().toStdString()))
+ {
+ bool current=it.value()->isChecked();
+ if(current != filter_->isFiltered(item))
+ {
+ //Triggered() will not be called!!
+ it.value()->setChecked(!current);
+ it.value()->setFont(current?font_:loadFont_);
+ }
+ }
+ ++it;
+ }
+
+ it=acFavMap_.constBegin();
+ while(it != acFavMap_.constEnd())
+ {
+ if(ServerItem *item=ServerList::instance()->find(it.value()->text().toStdString()))
+ {
+ bool current=it.value()->isChecked();
+ if(current != filter_->isFiltered(item))
+ {
+ //Triggered() will not be called!!
+ it.value()->setChecked(!current);
+ it.value()->setFont(current?font_:loadFont_);
+ }
+ }
+ ++it;
+ }
+}
+
+void ServerFilterMenu::notifyServerListChanged()
+{
+ init();
+ reload();
+}
+
+void ServerFilterMenu::notifyServerListFavouriteChanged(ServerItem* item)
+{
+ reload();
+}
+
+void ServerFilterMenu::notifyServerFilterAdded(ServerItem*)
+{
+ reload();
+}
+
+void ServerFilterMenu::notifyServerFilterRemoved(ServerItem*)
+{
+ reload();
+}
+
+void ServerFilterMenu::notifyServerFilterChanged(ServerItem*)
+{
+ reload();
+}
+
+void ServerFilterMenu::notifyServerFilterDelete()
+{
+ reload(0);
+}
diff --git a/Viewer/src/FilterWidget.hpp b/Viewer/src/FilterWidget.hpp
new file mode 100644
index 0000000..26a0f4b
--- /dev/null
+++ b/Viewer/src/FilterWidget.hpp
@@ -0,0 +1,97 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef FILTERWIDGET_HPP_
+#define FILTERWIDGET_HPP_
+
+#include <QMap>
+#include <QMenu>
+#include <QSet>
+#include <QWidget>
+
+#include "DState.hpp"
+#include "ServerFilter.hpp"
+#include "ServerList.hpp"
+
+class QToolButton;
+class VParam;
+class VParamSet;
+class ServerFilter;
+
+
+class VParamFilterMenu : public QObject
+{
+Q_OBJECT
+
+public:
+ enum DecorMode {NoDecor,ColourDecor,PixmapDecor};
+ enum ItemMode {FilterMode,ShowMode};
+
+ VParamFilterMenu(QMenu* parent,VParamSet* filter,QString title,ItemMode,DecorMode decorMode=NoDecor);
+ void reload();
+
+protected Q_SLOTS:
+ void slotChanged(bool);
+ void slotSelectAll(bool);
+ void slotUnselectAll(bool);
+
+protected:
+ void buildTitle(QString,QMenu*);
+ void addAction(QString name,QString id);
+
+ QMenu* menu_;
+ VParamSet* filter_;
+ ItemMode itemMode_;
+ DecorMode decorMode_;
+};
+
+
+class ServerFilterMenu : public QObject, public ServerListObserver, public ServerFilterObserver
+{
+Q_OBJECT
+
+public:
+ explicit ServerFilterMenu(QMenu* parent);
+ ~ServerFilterMenu();
+
+ void reload(ServerFilter*);
+ void aboutToDestroy(); //Called when the parent mainwindow is being destroyed
+
+ //From ServerListObserver
+ void notifyServerListChanged();
+ void notifyServerListFavouriteChanged(ServerItem*);
+
+ //From ConfigObserver
+ void notifyServerFilterAdded(ServerItem*);
+ void notifyServerFilterRemoved(ServerItem*);
+ void notifyServerFilterChanged(ServerItem*);
+ void notifyServerFilterDelete();
+
+protected Q_SLOTS:
+ void slotChanged(bool);
+
+protected:
+ void init();
+ void clear();
+ QAction* createAction(QString name,int id);
+ void reload();
+ void buildFavourite();
+ void clearFavourite();
+ void syncActionState(QString,bool);
+
+ QMenu* menu_;
+ QMenu* allMenu_;
+ QMap<QString,QAction*> acAllMap_;
+ QMap<QString,QAction*> acFavMap_;
+ ServerFilter* filter_;
+ QFont font_;
+ QFont loadFont_;
+};
+
+#endif
diff --git a/Viewer/src/FlagSet.hpp b/Viewer/src/FlagSet.hpp
new file mode 100644
index 0000000..645c2f5
--- /dev/null
+++ b/Viewer/src/FlagSet.hpp
@@ -0,0 +1,32 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef FLAGSET_HPP_
+#define FLAGSET_HPP_
+
+template <class T>
+class FlagSet
+{
+public:
+ FlagSet() : flags_(0) {}
+ FlagSet(T t) : flags_(0) {set(t);}
+
+ void clear() {flags_=0;}
+ void set(T flag ) { flags_ |= (1 << flag); }
+ void unset(T flag ) { flags_ &= ~ (1 << flag); }
+ bool isSet(T flag) const { return (flags_ >> flag) & 1; }
+ bool isEmpty() const {return flags_==0;}
+ bool sameAs(T flag) const {return flags_ == flag;}
+
+private:
+ int flags_;
+
+};
+
+#endif // FLAGSET_HPP_
diff --git a/Viewer/src/GotoLineDialog.cpp b/Viewer/src/GotoLineDialog.cpp
new file mode 100644
index 0000000..d9b16d8
--- /dev/null
+++ b/Viewer/src/GotoLineDialog.cpp
@@ -0,0 +1,78 @@
+//============================================================================
+// Copyright 2015 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "GotoLineDialog.hpp"
+
+#include <QPushButton>
+
+GotoLineDialog::GotoLineDialog(QWidget *parent) : QDialog(parent)
+{
+ setupUi(this); // this sets up GUI// setupFileMenu();
+
+
+ connect (buttonBox, SIGNAL(accepted()), this, SLOT(done()));
+ connect (buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+ connect (lineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(setButtonStatus()));
+}
+
+
+GotoLineDialog::~GotoLineDialog()
+{
+
+}
+
+
+// ---------------------------------------------------------------------------
+// GotoLineDialog::setButtonStatus
+// if there is text in the input box, then we can activate the 'OK' button,
+// otherwise we should disable it. This function is called each time the text
+// in the box is changed.
+// ---------------------------------------------------------------------------
+
+void GotoLineDialog::setButtonStatus()
+{
+ QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
+
+ if (lineEdit->text().isEmpty())
+ {
+ okButton->setEnabled(false);
+ }
+ else
+ {
+ okButton->setEnabled(true);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// GotoLineDialog::setupUIBeforeShow
+// sets up UI elements before the dialog is displayed.
+// ---------------------------------------------------------------------------
+
+void GotoLineDialog::setupUIBeforeShow()
+{
+ lineEdit->setFocus(Qt::OtherFocusReason);
+ buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
+
+ setButtonStatus();
+}
+
+
+// ---------------------------------------------------------------------------
+// GotoLineDialog::accept
+// called when the user clicks the 'OK' button - emits a signal to tell the
+// text editor to go to the chosen line
+// ---------------------------------------------------------------------------
+
+void GotoLineDialog::done()
+{
+ int line = lineEdit->text().toInt();
+ Q_EMIT gotoLine(line);
+ close();
+}
diff --git a/Viewer/src/GotoLineDialog.hpp b/Viewer/src/GotoLineDialog.hpp
new file mode 100644
index 0000000..cbd256c
--- /dev/null
+++ b/Viewer/src/GotoLineDialog.hpp
@@ -0,0 +1,37 @@
+//============================================================================
+// Copyright 2015 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef GotoLineDialog_H
+#define GotoLineDialog_H
+
+#include "ui_GotoLineDialog.h"
+
+using namespace std;
+
+
+class GotoLineDialog : public QDialog, private Ui::GotoLineDialogQ
+{
+ Q_OBJECT
+
+public:
+ explicit GotoLineDialog(QWidget *parent = 0);
+ ~GotoLineDialog();
+ void setupUIBeforeShow();
+
+Q_SIGNALS:
+ void gotoLine(int line); // emitted when the user says 'ok'
+
+
+public Q_SLOTS:
+ void done();
+ void setButtonStatus();
+
+};
+
+#endif
diff --git a/Viewer/src/GotoLineDialog.ui b/Viewer/src/GotoLineDialog.ui
new file mode 100644
index 0000000..5976abf
--- /dev/null
+++ b/Viewer/src/GotoLineDialog.ui
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>GotoLineDialogQ</class>
+ <widget class="QDialog" name="GotoLineDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>186</width>
+ <height>113</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <widget class="QWidget" name="">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>20</y>
+ <width>162</width>
+ <height>79</height>
+ </rect>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Goto Line:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="lineEdit"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <zorder>buttonBox</zorder>
+ <zorder>lineEdit</zorder>
+ <zorder>label</zorder>
+ <zorder>label</zorder>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>Dialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>Dialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/Viewer/src/Highlighter.cpp b/Viewer/src/Highlighter.cpp
new file mode 100644
index 0000000..530988e
--- /dev/null
+++ b/Viewer/src/Highlighter.cpp
@@ -0,0 +1,110 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "Highlighter.hpp"
+#include "UserMessage.hpp"
+#include "VParam.hpp"
+
+#include <boost/property_tree/json_parser.hpp>
+#include <boost/property_tree/ptree.hpp>
+
+std::string Highlighter::parFile_;
+
+#include "VProperty.hpp"
+
+
+Highlighter::Highlighter(QTextDocument *parent,QString id)
+ : QSyntaxHighlighter(parent)
+{
+ load(id);
+}
+
+void Highlighter::addRule(QString pattern,QTextCharFormat format)
+{
+ HighlightingRule rule;
+ rule.pattern = QRegExp(pattern,Qt::CaseSensitive);
+ rule.format = format;
+ rules_.append(rule);
+}
+
+void Highlighter::highlightBlock(const QString &text)
+{
+ Q_FOREACH(HighlightingRule rule, rules_)
+ {
+ QRegExp expression(rule.pattern);
+ int index = text.indexOf(expression);
+ while (index >= 0)
+ {
+ int length = expression.matchedLength();
+ setFormat(index, length, rule.format);
+ index = text.indexOf(expression, index + length);
+ }
+ }
+ setCurrentBlockState(0);
+}
+
+void Highlighter::init(const std::string& parFile)
+{
+ parFile_=parFile;
+}
+
+void Highlighter::load(QString id)
+{
+ //Parse param file using the boost JSON property tree parser
+ using boost::property_tree::ptree;
+ ptree pt;
+
+ try
+ {
+ read_json(parFile_,pt);
+ }
+ catch (const boost::property_tree::json_parser::json_parser_error& e)
+ {
+ std::string errorMessage = e.what();
+ UserMessage::message(UserMessage::ERROR, true,
+ std::string("Error! Highlighter::load() unable to parse definition file: " + parFile_ + " Message: " +errorMessage));
+ return;
+ }
+
+ ptree::const_assoc_iterator itTop=pt.find(id.toStdString());
+ if(itTop == pt.not_found())
+ {
+ return;
+ }
+
+ //For each parameter
+ for(ptree::const_iterator itRule = itTop->second.begin(); itRule != itTop->second.end(); ++itRule)
+ {
+ QString pattern;
+ QTextCharFormat format;
+
+ ptree::const_assoc_iterator itPar;
+ ptree ptPar=itRule->second;
+
+ if((itPar=ptPar.find("pattern")) !=ptPar.not_found())
+ {
+ pattern=QString::fromStdString(itPar->second.get_value<std::string>());
+ }
+ if((itPar=ptPar.find("colour")) !=ptPar.not_found())
+ {
+ format.setForeground(VProperty::toColour(itPar->second.get_value<std::string>()));
+ }
+ if((itPar=ptPar.find("bold")) !=ptPar.not_found())
+ {
+ if(itPar->second.get_value<std::string>() == "true")
+ format.setFontWeight(QFont::Bold);
+ }
+ if((itPar=ptPar.find("italic")) !=ptPar.not_found())
+ {
+ if(itPar->second.get_value<std::string>() == "true")
+ format.setFontItalic(true);
+ }
+ addRule(pattern,format);
+ }
+}
diff --git a/Viewer/src/Highlighter.hpp b/Viewer/src/Highlighter.hpp
new file mode 100644
index 0000000..41cfe8f
--- /dev/null
+++ b/Viewer/src/Highlighter.hpp
@@ -0,0 +1,40 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef HIGHLIGHTER_HPP_
+#define HIGHLIGHTER_HPP_
+
+#include <string>
+#include <QSyntaxHighlighter>
+
+class Highlighter : public QSyntaxHighlighter
+{
+public:
+ Highlighter(QTextDocument *parent,QString id);
+ static void init(const std::string& parFile);
+
+protected:
+ void highlightBlock(const QString &text);
+ void addRule(QString,QTextCharFormat);
+
+private:
+ void load(QString);
+
+ struct HighlightingRule
+ {
+ QRegExp pattern;
+ QTextCharFormat format;
+ };
+
+ QList<HighlightingRule> rules_;
+ static std::string parFile_;
+};
+
+#endif
diff --git a/Viewer/src/HistoryItemWidget.cpp b/Viewer/src/HistoryItemWidget.cpp
new file mode 100644
index 0000000..082718a
--- /dev/null
+++ b/Viewer/src/HistoryItemWidget.cpp
@@ -0,0 +1,156 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "HistoryItemWidget.hpp"
+
+#include "LogProvider.hpp"
+#include "LogModel.hpp"
+#include "VReply.hpp"
+
+static bool firstRun=true;
+
+HistoryItemWidget::HistoryItemWidget(QWidget *parent) : QWidget(parent)
+{
+ setupUi(this);
+
+ searchTb_->setEnabled(false);
+ searchTb_->setVisible(false);
+ searchLine_->setVisible(false);
+
+ infoProvider_=new LogProvider(this);
+ infoProvider_->setAutoUpdate(true);
+
+ model_=new LogModel(this);
+
+ treeView_->setProperty("log","1");
+ treeView_->setModel(model_);
+ treeView_->setItemDelegate(new LogDelegate(this));
+
+ checkActionState();
+}
+
+QWidget* HistoryItemWidget::realWidget()
+{
+ return this;
+}
+
+void HistoryItemWidget::reload(VInfo_ptr info)
+{
+ assert(active_);
+
+ if(suspended_)
+ return;
+
+ clearContents();
+ info_=info;
+
+ if(info_)
+ {
+ infoProvider_->info(info_);
+ }
+}
+
+void HistoryItemWidget::clearContents()
+{
+ InfoPanelItem::clear();
+ model_->clearData();
+}
+
+void HistoryItemWidget::infoReady(VReply* reply)
+{
+ model_->setData(reply->text());
+ adjustColumnSize();
+ fileLabel_->update(reply,"(Last 100 lines)");
+ treeView_->scrollTo(model_->lastIndex());
+ checkActionState();
+}
+
+void HistoryItemWidget::infoProgress(VReply* reply)
+{
+ QString s=QString::fromStdString(reply->text());
+}
+
+void HistoryItemWidget::infoFailed(VReply* reply)
+{
+ QString s=QString::fromStdString(reply->errorText());
+
+ checkActionState();
+}
+
+void HistoryItemWidget::infoAppended(VReply* reply)
+{
+ model_->appendData(reply->textVec());
+ adjustColumnSize();
+ treeView_->scrollTo(model_->lastIndex());
+
+ checkActionState();
+}
+
+void HistoryItemWidget::updateState(const ChangeFlags& flags)
+{
+ if(flags.isSet(SelectedChanged))
+ {
+ if(!selected_)
+ {
+ infoProvider_->setAutoUpdate(false);
+ reloadTb_->setEnabled(false);
+ return;
+ }
+ }
+
+ if(flags.isSet(SuspendedChanged))
+ {
+ //Suspend
+ if(suspended_)
+ {
+ infoProvider_->setAutoUpdate(false);
+ reloadTb_->setEnabled(false);
+ return;
+ }
+
+ }
+
+ checkActionState();
+}
+
+void HistoryItemWidget::checkActionState()
+{
+ if(suspended_)
+ return;
+
+ if(infoProvider_->autoUpdate() == frozen_)
+ {
+ infoProvider_->setAutoUpdate(!frozen_);
+ }
+ reloadTb_->setEnabled(!infoProvider_->autoUpdate() || !infoProvider_->inAutoUpdate());
+}
+
+//Adjust column size if it is the first run
+void HistoryItemWidget::adjustColumnSize()
+{
+ if(firstRun && model_->hasData())
+ {
+ firstRun=false;
+ for(int i=0; i < model_->columnCount()-1; i++)
+ {
+ treeView_->resizeColumnToContents(i);
+ }
+ }
+}
+
+void HistoryItemWidget::on_reloadTb__clicked(bool)
+{
+ if(info_ && info_.get())
+ {
+ infoProvider_->info(info_);
+ }
+}
+
+
+static InfoPanelItemMaker<HistoryItemWidget> maker1("history");
diff --git a/Viewer/src/HistoryItemWidget.hpp b/Viewer/src/HistoryItemWidget.hpp
new file mode 100644
index 0000000..7ca1d9a
--- /dev/null
+++ b/Viewer/src/HistoryItemWidget.hpp
@@ -0,0 +1,53 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef HISTORYITEMWIDGET_HPP_
+#define HISTORYITEMWIDGET_HPP_
+
+#include "InfoPanelItem.hpp"
+#include "VInfo.hpp"
+
+#include "ServerHandler.hpp"
+
+#include "ui_HistoryItemWidget.h"
+
+class LogModel;
+
+class HistoryItemWidget : public QWidget, public InfoPanelItem, protected Ui::HistoryItemWidget
+{
+Q_OBJECT
+
+public:
+ explicit HistoryItemWidget(QWidget *parent=0);
+
+ void reload(VInfo_ptr);
+ QWidget* realWidget();
+ void clearContents();
+
+ void infoReady(VReply*);
+ void infoFailed(VReply*);
+ void infoProgress(VReply*);
+ void infoAppended(VReply*);
+
+ void nodeChanged(const VNode*, const std::vector<ecf::Aspect::Type>&) {}
+ void defsChanged(const std::vector<ecf::Aspect::Type>&) {}
+
+protected Q_SLOTS:
+ void on_reloadTb__clicked(bool);
+
+protected:
+ void updateState(const ChangeFlags&);
+ void adjustColumnSize();
+ void checkActionState();
+
+ LogModel* model_;
+};
+
+#endif
diff --git a/Viewer/src/HistoryItemWidget.ui b/Viewer/src/HistoryItemWidget.ui
new file mode 100644
index 0000000..a61c96d
--- /dev/null
+++ b/Viewer/src/HistoryItemWidget.ui
@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>HistoryItemWidget</class>
+ <widget class="QWidget" name="HistoryItemWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>510</width>
+ <height>465</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="spacing">
+ <number>1</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0,0,0">
+ <property name="spacing">
+ <number>1</number>
+ </property>
+ <item>
+ <widget class="FileInfoLabel" name="fileLabel_">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QToolButton" name="searchTb_">
+ <property name="toolTip">
+ <string>Show search bar</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/search_decor.svg</normaloff>:/viewer/search_decor.svg</iconset>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+F</string>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="reloadTb_">
+ <property name="toolTip">
+ <string>Refresh log</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/sync.svg</normaloff>:/viewer/sync.svg</iconset>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="MessageLabel" name="messageLabel_" native="true"/>
+ </item>
+ <item>
+ <widget class="TreeView" name="treeView_">
+ <property name="selectionMode">
+ <enum>QAbstractItemView::SingleSelection</enum>
+ </property>
+ <property name="rootIsDecorated">
+ <bool>false</bool>
+ </property>
+ <property name="uniformRowHeights">
+ <bool>true</bool>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="PlainTextSearchLine" name="searchLine_" native="true"/>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>PlainTextSearchLine</class>
+ <extends>QWidget</extends>
+ <header>PlainTextSearchLine.hpp</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>FileInfoLabel</class>
+ <extends>QLabel</extends>
+ <header location="global">FileInfoLabel.hpp</header>
+ </customwidget>
+ <customwidget>
+ <class>TreeView</class>
+ <extends>QTreeView</extends>
+ <header location="global">TreeView.hpp</header>
+ </customwidget>
+ <customwidget>
+ <class>MessageLabel</class>
+ <extends>QWidget</extends>
+ <header>MessageLabel.hpp</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources>
+ <include location="viewer.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/Viewer/src/IconProvider.cpp b/Viewer/src/IconProvider.cpp
new file mode 100644
index 0000000..fc30528
--- /dev/null
+++ b/Viewer/src/IconProvider.cpp
@@ -0,0 +1,167 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "IconProvider.hpp"
+
+#include <QDebug>
+#include <QImage>
+#include <QImageReader>
+#include <QPainter>
+
+static UnknownIconItem unknownIcon(":/desktop/unknown.svg");
+static IconItem linkIcon(":/desktop/link.svg");
+static IconItem linkBrokenIcon(":/desktop/link_broken.svg");
+static IconItem lockIcon(":/viewer/padlock.svg");
+static IconItem warningIcon(":/viewer/warning.svg");
+static IconItem errorIcon(":/viewer/error.svg");
+static IconItem bookmarkGroupIcon(":/desktop/bookmark_group.svg");
+static IconItem embeddedIcon(":/desktop/embedded.svg");
+static IconItem infoIcon(":/viewer/info.svg");
+
+std::map<QString,IconItem*> IconProvider::icons_;
+std::map<int,IconItem*> IconProvider::iconsById_;
+
+static int idCnt=0;
+
+//===========================================
+//
+// IconItem
+//
+//===========================================
+
+IconItem::IconItem(QString path) : path_(path), id_(idCnt++)
+{
+}
+
+QPixmap IconItem::pixmap(int size)
+{
+ std::map<int,QPixmap>::iterator it=pixmaps_.find(size);
+ if(it != pixmaps_.end())
+ return it->second;
+ else
+ {
+ QPixmap pix;
+ QImageReader imgR(path_);
+ if(imgR.canRead())
+ {
+ imgR.setScaledSize(QSize(size,size));
+ QImage img=imgR.read();
+ pix=QPixmap::fromImage(img);
+ }
+ else
+ {
+ pix=unknown(size);
+ }
+
+ pixmaps_[size]=pix;
+ return pix;
+ }
+ return QPixmap();
+}
+
+QPixmap IconItem::unknown(int size)
+{
+ return unknownIcon.pixmap(size);
+}
+
+UnknownIconItem::UnknownIconItem(QString path) : IconItem(path)
+{
+
+}
+
+QPixmap UnknownIconItem::unknown(int size)
+{
+ return QPixmap();
+}
+
+
+//===========================================
+//
+// IconProvider
+//
+//===========================================
+
+IconProvider::IconProvider()
+{
+}
+
+QString IconProvider::path(int id)
+{
+ std::map<int,IconItem*>::iterator it=iconsById_.find(id);
+ if(it != iconsById_.end())
+ return it->second->path();
+
+ return QString();
+
+}
+
+int IconProvider::add(QString path,QString name)
+{
+ std::map<QString,IconItem*>::iterator it=icons_.find(name);
+ if(it == icons_.end())
+ {
+ IconItem *p=new IconItem(path);
+ icons_[name]=p;
+ iconsById_[p->id()]=p;
+ return p->id();
+ }
+
+ return it->second->id();
+}
+
+IconItem* IconProvider::icon(QString name)
+{
+ std::map<QString,IconItem*>::iterator it=icons_.find(name);
+ if(it != icons_.end())
+ return it->second;
+
+ return &unknownIcon;
+}
+
+IconItem* IconProvider::icon(int id)
+{
+ std::map<int,IconItem*>::iterator it=iconsById_.find(id);
+ if(it != iconsById_.end())
+ return it->second;
+
+ return &unknownIcon;
+}
+
+QPixmap IconProvider::pixmap(QString name,int size)
+{
+ return icon(name)->pixmap(size);
+}
+
+QPixmap IconProvider::pixmap(int id,int size)
+{
+ return icon(id)->pixmap(size);
+}
+
+QPixmap IconProvider::lockPixmap(int size)
+{
+ return lockIcon.pixmap(size);
+}
+
+QPixmap IconProvider::warningPixmap(int size)
+{
+ return warningIcon.pixmap(size);
+}
+
+QPixmap IconProvider::errorPixmap(int size)
+{
+ return errorIcon.pixmap(size);
+}
+
+QPixmap IconProvider::infoPixmap(int size)
+{
+ return infoIcon.pixmap(size);
+}
+
+static IconProvider iconProvider;
diff --git a/Viewer/src/IconProvider.hpp b/Viewer/src/IconProvider.hpp
new file mode 100644
index 0000000..1928e75
--- /dev/null
+++ b/Viewer/src/IconProvider.hpp
@@ -0,0 +1,71 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef ICONPROVIDER_HPP_
+#define ICONPROVIDER_HPP_
+
+#include <QPixmap>
+
+#include <map>
+
+class IconItem
+{
+public:
+ explicit IconItem(QString);
+ virtual ~IconItem() {};
+
+ QPixmap pixmap(int);
+ int id () const {return id_;}
+ QString path() const {return path_;}
+
+protected:
+ static void greyOut(QImage &);
+ virtual QPixmap unknown(int);
+
+ QString path_;
+ std::map<int,QPixmap> pixmaps_;
+ int id_;
+};
+
+class UnknownIconItem : public IconItem
+{
+public:
+ explicit UnknownIconItem(QString);
+
+protected:
+ QPixmap unknown(int);
+};
+
+
+class IconProvider
+{
+public:
+ IconProvider();
+
+ static int add(QString path,QString name);
+
+ static QString path(int id);
+ static QPixmap pixmap(QString name,int size);
+ static QPixmap pixmap(int id,int size);
+
+ static QPixmap lockPixmap(int);
+ static QPixmap warningPixmap(int);
+ static QPixmap errorPixmap(int);
+ static QPixmap infoPixmap(int);
+
+private:
+ static IconItem* icon(QString name);
+ static IconItem* icon(int id);
+
+ static std::map<QString,IconItem*> icons_;
+ static std::map<int,IconItem*> iconsById_;
+};
+
+#endif
diff --git a/Viewer/src/InfoPanel.cpp b/Viewer/src/InfoPanel.cpp
new file mode 100644
index 0000000..52a39b9
--- /dev/null
+++ b/Viewer/src/InfoPanel.cpp
@@ -0,0 +1,751 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "InfoPanel.hpp"
+
+#include <QDebug>
+#include <QMenu>
+#include <QToolButton>
+#include <QVBoxLayout>
+
+#include "DashboardDock.hpp"
+#include "InfoPanelItem.hpp"
+#include "InfoPanelHandler.hpp"
+#include "ServerHandler.hpp"
+#include "UserMessage.hpp"
+#include "VSettings.hpp"
+
+//==============================================
+//
+// InfoPanelItemHandler
+//
+//==============================================
+
+QWidget* InfoPanelItemHandler::widget()
+{
+ return item_->realWidget();
+}
+
+bool InfoPanelItemHandler::match(const std::vector<InfoPanelDef*>& ids) const
+{
+ return (std::find(ids.begin(),ids.end(),def_) != ids.end());
+}
+
+void InfoPanelItemHandler::addToTab(QTabWidget *tab)
+{
+ int idx=tab->addTab(item_->realWidget(),QString::fromStdString(def_->label()));
+ tab->setTabIcon(idx,QPixmap(":/viewer/" + QString::fromStdString(def_->icon())));
+}
+
+//==============================================
+//
+// InfoPanel
+//
+//==============================================
+
+InfoPanel::InfoPanel(QWidget* parent) :
+ DashboardWidget("info",parent),
+ tabBeingCleared_(false),
+ tabBeingAdjusted_(false)
+{
+ setupUi(this);
+
+ connect(tab_,SIGNAL(currentChanged(int)),
+ this,SLOT(slotCurrentWidgetChanged(int)));
+
+ connect(bcWidget_,SIGNAL(selected(VInfo_ptr)),
+ this,SLOT(slotReloadFromBc(VInfo_ptr)));
+
+ tab_->setIconSize(QSize(16,16));
+
+ messageLabel_->hide();
+
+ //Builds the menu for the settings tool button
+ /*QMenu *menu=new QMenu(this);
+ menu->setTearOffEnabled(true);
+
+ menu->addAction(actionBreadcrumbs_);
+ menu->addAction(actionDetached_);
+ menu->addAction(actionFrozen_);
+
+ //Sets the menu on the toolbutton
+ optionTb_->setMenu(menu);*/
+
+ //Initialise action state
+ actionBreadcrumbs_->setChecked(bcWidget_->active());
+ actionFrozen_->setChecked(false);
+ actionDetached_->setChecked(false);
+}
+
+InfoPanel::~InfoPanel()
+{
+ clear();
+
+ Q_FOREACH(InfoPanelItemHandler *d,items_)
+ delete d;
+}
+
+QMenu* InfoPanel::buildOptionsMenu()
+{
+ QMenu *menu=new QMenu(this);
+ menu->setTearOffEnabled(true);
+
+ menu->addAction(actionBreadcrumbs_);
+ menu->addAction(actionDetached_);
+ menu->addAction(actionFrozen_);
+
+ return menu;
+}
+
+//When the infopanel is in a dockwidget we add the option actions
+//to the dockwidget title bar widget
+void InfoPanel::populateDockTitleBar(DashboardDockTitleWidget* tw)
+{
+ QMenu *menu=buildOptionsMenu();
+
+ //Sets the menu on the toolbutton
+ tw->optionsTb()->setMenu(menu);
+
+ //This will set the title
+ updateTitle();
+}
+
+//When the infopanel is in a dialog we need to add the optionsTb to the dialog.
+void InfoPanel::populateDialog()
+{
+ QMenu *menu=buildOptionsMenu();
+
+ QToolButton* optionsTb=new QToolButton(this);
+ optionsTb->setAutoRaise(true);
+ optionsTb->setIcon(QPixmap(":/viewer/configure.svg"));
+ optionsTb->setPopupMode(QToolButton::InstantPopup);
+ optionsTb->setToolTip(tr("Options"));
+ optionsTb->setMenu(menu);
+
+ tab_->setCornerWidget(optionsTb);
+
+ //This will set the dialog title
+ updateTitle();
+}
+
+void InfoPanel::setCurrent(const std::string& name)
+{
+ for(int i=0; i < tab_->count(); i++)
+ {
+ if(InfoPanelItemHandler* d=findHandler(tab_->widget(i)))
+ {
+ //Clear the contents
+ if(d->def() && d->def()->name() == name)
+ {
+ tab_->setCurrentIndex(i);
+ }
+ }
+ }
+}
+
+void InfoPanel::clear()
+{
+ messageLabel_->hide();
+ messageLabel_->clear();
+
+ //Unregister from observer lists
+ if(info_ && info_.get())
+ {
+ if(info_->server())
+ {
+ info_->server()->removeServerObserver(this);
+ }
+
+ info_->removeObserver(this);
+ }
+
+ //release info
+ info_.reset();
+
+ //Clear the tab contents
+ for(int i=0; i < tab_->count(); i++)
+ {
+ if(InfoPanelItem* item=findItem(tab_->widget(i)))
+ {
+ //Diable and clear the contents
+ item->setActive(false);
+ }
+ }
+ //Clear the tabs
+ clearTab();
+
+ //Clear the breadcrumbs
+ bcWidget_->clear();
+}
+
+//TODO: It should be the slot
+void InfoPanel::reset(VInfo_ptr info)
+{
+ if(info_ && info)
+ {
+ //UserMessage::debug("path: " + info_->path() + " " + info->path());
+
+ if(*(info_.get()) == *(info.get()))
+ return;
+
+ //it can happen that the stored info was not yet updated after a
+ //server reload. If there is chance for it we try to regain its data and
+ //comapare it again to the incoming node
+ else if(info_->server() == info->server() &&
+ info_->storedNodePath() == info->storedNodePath() &&
+ !info_->node() && info->node())
+ {
+ info_->regainData();
+ if(info_->node() == info->node())
+ return;
+ }
+ }
+
+ messageLabel_->hide();
+ messageLabel_->clear();
+
+ //Set info
+ adjustInfo(info);
+
+ //Set tabs
+ adjustTabs(info);
+
+ //Set breadcrumbs
+ bcWidget_->setPath(info);
+
+ updateTitle();
+}
+
+//This slot is called when the info object is selected
+void InfoPanel::slotReload(VInfo_ptr info)
+{
+ //When the mode is detached it cannot receive
+ //the reload request
+ if(info_ && detached())
+ return;
+
+ if(info && info->isAttribute())
+ {
+ reset(VInfo::createParent(info));
+ }
+ else
+ {
+ reset(info);
+ }
+}
+
+//This slot is called when the info object is selected
+void InfoPanel::slotReloadFromBc(VInfo_ptr info)
+{
+ reset(info);
+ if(!detached() && info_)
+ Q_EMIT selectionChanged(info_);
+}
+
+//Set the new VInfo object.
+//We also we need to manage the node observers. The InfoItem
+//will be the observer of the server of the object stored in
+//the new VInfo
+void InfoPanel::adjustInfo(VInfo_ptr info)
+{
+ //Check if there is data in info
+ if(info.get())
+ {
+ ServerHandler *server=info->server();
+
+ bool sameServer=(info_)?(info_->server() == server):false;
+
+ //Handle observers
+ if(!sameServer)
+ {
+ if(info_ && info_->server())
+ {
+ info_->server()->removeServerObserver(this);
+ //info_->server()->removeNodeObserver(this);
+ }
+
+ info->server()->addServerObserver(this);
+ //info->server()->addNodeObserver(this);
+ }
+ }
+ //If the there is no data we clean everything and return
+ else
+ {
+ if(info_ && info_->server())
+ {
+ info_->server()->removeServerObserver(this);
+ //info_->server()->removeNodeObserver(this);
+ }
+ }
+
+ //Set the info
+ if(info_)
+ {
+ info_->removeObserver(this);
+ }
+
+ info_=info;
+
+ if(info_)
+ {
+ info_->addObserver(this);
+ }
+
+}
+
+void InfoPanel::adjustTabs(VInfo_ptr info)
+{
+ //Set tabs according to the current set of roles
+ std::vector<InfoPanelDef*> ids;
+ InfoPanelHandler::instance()->visible(info,ids);
+
+ for(int i=0; i < ids.size(); i++)
+ {
+ UserMessage::message(UserMessage::DBG,false,std::string("InfoPanel --> tab: ") + ids[i]->name());
+ }
+
+ int match=0;
+ for(int i=0; i < tab_->count(); i++)
+ {
+ if(InfoPanelItemHandler* d=findHandler(tab_->widget(i)))
+ {
+ //Disable and force to clear the contents
+ d->item()->setActive(false);
+
+ if(d->match(ids))
+ match++;
+ }
+ }
+
+ //Remember the current widget
+ QWidget *current=tab_->currentWidget();
+ InfoPanelItem* currentItem=findItem(current);
+
+ //A new set of tabs is needed!
+ if(tab_->count() != ids.size() || match != ids.size())
+ {
+ //We set this flag true so that the change of the current tab should not
+ //trigger a reload! We want to reload the current tab only after the
+ //tab adjustment.
+ tabBeingAdjusted_=true;
+
+ //Remove the pages but does not delete them.
+ clearTab();
+
+ for(std::vector<InfoPanelDef*>::iterator it=ids.begin(); it != ids.end(); ++it)
+ {
+ if(InfoPanelItemHandler* d=findHandler(*it))
+ {
+ d->addToTab(tab_);
+ d->item()->setActive(true);
+ }
+ }
+
+ //Try to set the previous current widget as current again
+ bool hasCurrent=false;
+ for(int i=0 ; i < tab_->count(); i++)
+ {
+ if(tab_->widget(i) == current)
+ {
+ tab_->setCurrentIndex(i);
+
+ hasCurrent=true;
+ break;
+ }
+ }
+ //If the current widget is not present select the first
+ if(!hasCurrent && tab_->count() >0)
+ {
+ tab_->setCurrentIndex(0);
+ currentItem=findItem(tab_->widget(0));
+ }
+
+ tabBeingAdjusted_=false;
+ }
+
+ //We use the same set of tabs
+ else
+ {
+ for(int i=0; i < tab_->count(); i++)
+ {
+ if(InfoPanelItemHandler* d=findHandler(tab_->widget(i)))
+ {
+ d->item()->setActive(true);
+ }
+ }
+ }
+
+ //We reload the current tab
+ if(currentItem)
+ {
+ currentItem->setSelected(true,info);
+ //currentItem->reload(info);
+ }
+}
+
+InfoPanelItem* InfoPanel::findItem(QWidget* w)
+{
+ if(!w)
+ return 0;
+
+ Q_FOREACH(InfoPanelItemHandler *d,items_)
+ {
+ if(d->widget() == w)
+ return d->item();
+ }
+
+ return 0;
+}
+
+InfoPanelItemHandler* InfoPanel::findHandler(QWidget* w)
+{
+ if(!w)
+ return 0;
+
+ Q_FOREACH(InfoPanelItemHandler *d,items_)
+ {
+ if(d->widget() == w)
+ return d;
+ }
+
+ return 0;
+}
+
+InfoPanelItemHandler* InfoPanel::findHandler(InfoPanelDef* def)
+{
+ Q_FOREACH(InfoPanelItemHandler *d,items_)
+ {
+ if(d->def() == def)
+ return d;
+ }
+
+ return createHandler(def);
+}
+
+InfoPanelItemHandler* InfoPanel::createHandler(InfoPanelDef* def)
+{
+ if(InfoPanelItem *iw=InfoPanelItemFactory::create(def->name()))
+ {
+ iw->setFrozen(frozen());
+ iw->setDetached(detached());
+
+ //iw will be added to the tab so the tab will be its parent. Moreover
+ //the tab will stay its parent even if iw got removed from the tab!
+ //So when the tab is deleted all the iw-s will be correctly deleted as well.
+
+ InfoPanelItemHandler* h=new InfoPanelItemHandler(def,iw);
+ items_ << h;
+ return h;
+ }
+ return 0;
+}
+
+
+void InfoPanel::slotCurrentWidgetChanged(int idx)
+{
+ if(tabBeingCleared_ || tabBeingAdjusted_)
+ return;
+
+ if(!info_.get())
+ return;
+
+ if(InfoPanelItem* current=findItem(tab_->widget(idx)))
+ {
+ current->setSelected(true,info_);
+
+ //Reload the item if it is needed
+ /*if(!current->isSuspended() && !current->info())
+ current->reload(info_);*/
+
+ //Deselect the others
+ for(int i=0; i < tab_->count(); i++)
+ {
+ if(InfoPanelItemHandler* d=findHandler(tab_->widget(i)))
+ {
+ if(d->item() != current)
+ d->item()->setSelected(false,info_);
+ }
+ }
+ }
+}
+
+void InfoPanel::clearTab()
+{
+ tabBeingCleared_=true;
+ tab_->clear();
+ tabBeingCleared_=false;
+}
+
+void InfoPanel::setDetached(bool b)
+{
+ actionDetached_->setChecked(b);
+}
+
+
+void InfoPanel::on_actionBreadcrumbs__toggled(bool b)
+{
+ if(b)
+ {
+ bcWidget_->active(true);
+ bcWidget_->setPath(info_);
+ }
+ else
+ {
+ bcWidget_->active(false);
+ }
+
+ //bcWidget_->clear();
+}
+
+void InfoPanel::on_actionFrozen__toggled(bool b)
+{
+ Q_FOREACH(InfoPanelItemHandler *item,items_)
+ {
+ item->item()->setFrozen(b);
+ }
+ updateTitle();
+}
+
+void InfoPanel::on_actionDetached__toggled(bool b)
+{
+ Q_FOREACH(InfoPanelItemHandler *item,items_)
+ {
+ item->item()->setDetached(b);
+ }
+ updateTitle();
+}
+
+bool InfoPanel::frozen() const
+{
+ return actionFrozen_->isChecked();
+}
+
+bool InfoPanel::detached() const
+{
+ return actionDetached_->isChecked();
+}
+
+void InfoPanel::updateTitle()
+{
+ QString baseTxt="<b>Info panel</b>";
+
+ QString txt;
+ if(frozen())
+ txt+="frozen";
+
+ if(detached())
+ {
+ if(!txt.isEmpty())
+ {
+ txt+=",";
+ }
+ txt+="detached";
+ }
+
+ if(!txt.isEmpty())
+ {
+ txt=baseTxt + " (" + txt + ")";
+ }
+ else
+ {
+ txt=baseTxt;
+ }
+
+ if(info_ && info_.get())
+ {
+ txt+=" - " + QString::fromStdString(info_->path());
+ }
+
+ Q_EMIT titleUpdated(txt);
+}
+
+void InfoPanel::notifyDataLost(VInfo* info)
+{
+ if(info_ && info_.get() == info)
+ {
+ clear();
+ }
+}
+
+//-------------------------------------------------
+// ServerObserver methods
+//-------------------------------------------------
+
+void InfoPanel::notifyDefsChanged(ServerHandler *server, const std::vector<ecf::Aspect::Type>& aspect)
+{
+ if(frozen())
+ return;
+
+ if(info_)
+ {
+ if(info_->server() && info_->server() == server)
+ {
+ //Dispatch the change
+ Q_FOREACH(InfoPanelItemHandler *item,items_)
+ {
+ item->item()->defsChanged(aspect);
+ }
+ }
+ }
+}
+
+void InfoPanel::notifyServerDelete(ServerHandler* server)
+{
+ if(info_ && info_->server() == server)
+ {
+ clear();
+ }
+}
+
+//This must be called at the beginning of a reset
+void InfoPanel::notifyBeginServerClear(ServerHandler* server)
+{
+ if(info_)
+ {
+ if(info_->server() && info_->server() == server)
+ {
+ messageLabel_->showWarning("Server <b>" + QString::fromStdString(server->name()) + "</b> is being reloaded. \
+ Until it is finished only <b>limited functionalty</b> is avaliable in the Info Panel!");
+
+ messageLabel_->startLoadLabel();
+
+ Q_FOREACH(InfoPanelItemHandler *item,items_)
+ {
+ item->item()->setSuspended(true,info_);
+ }
+ }
+ }
+}
+
+//This must be called at the end of a reset
+void InfoPanel::notifyEndServerScan(ServerHandler* server)
+{
+ if(info_)
+ {
+ if(info_->server() && info_->server() == server)
+ {
+ messageLabel_->hide();
+ messageLabel_->clear();
+
+ //We try to ressurect the info. We have to do it explicitly because it is not guaranteed
+ //that notifyEndServerScan() will be first called on the VInfo then on the InfoPanel. So it
+ //is possible that the node exists but is still set to NULL in VInfo.
+ info_->regainData();
+
+ //If the info is not available dataLost() might have already been called and
+ //the panel was reset!
+ if(!info_)
+ return;
+
+ Q_ASSERT(info_->server() && info_->node());
+
+ //Otherwise we resume all the tabs
+ Q_FOREACH(InfoPanelItemHandler *item,items_)
+ {
+ item->item()->setSuspended(false,info_);
+ }
+ }
+ }
+}
+
+void InfoPanel::notifyServerConnectState(ServerHandler* server)
+{
+ if(frozen())
+ return;
+
+ if(info_)
+ {
+ if(info_->server() && info_->server() == server)
+ {
+ //Dispatch the change
+ Q_FOREACH(InfoPanelItemHandler *item,items_)
+ {
+ item->item()->connectStateChanged();
+ }
+ }
+ }
+}
+
+void InfoPanel::notifyServerSuiteFilterChanged(ServerHandler* server)
+{
+ //TODO: does frozen make sense in this case?
+ if(frozen())
+ return;
+
+ if(info_.get())
+ {
+ if(info_->server() && info_->server() == server)
+ {
+ //Dispatch the change
+ Q_FOREACH(InfoPanelItemHandler *item,items_)
+ {
+ item->item()->suiteFilterChanged();
+ }
+ }
+ }
+}
+
+void InfoPanel::notifyServerSyncFinished(ServerHandler* server)
+{
+ //TODO: does frozen make sense in this case?
+ if(frozen())
+ return;
+
+ if(info_.get())
+ {
+ if(info_->server() && info_->server() == server)
+ {
+ //Dispatch the change
+ Q_FOREACH(InfoPanelItemHandler *item,items_)
+ {
+ item->item()->serverSyncFinished();
+ }
+ }
+ }
+}
+
+void InfoPanel::rerender()
+{
+ bcWidget_->rerender();
+}
+
+void InfoPanel::writeSettings(VSettings* vs)
+{
+ vs->put("type",type_);
+ vs->put("dockId",id_);
+
+ bcWidget_->writeSettings(vs);
+
+ vs->putAsBool("frozen",frozen());
+ vs->putAsBool("detached",detached());
+}
+
+void InfoPanel::readSettings(VSettings* vs)
+{
+ std::string type=vs->get<std::string>("type","");
+ if(type != type_)
+ {
+ return;
+ }
+
+ //--------------------------
+ //Breadcrumbs
+ //--------------------------
+
+ bcWidget_->readSettings(vs);
+
+ //Synchronise the action and the breadcrumbs state
+ //This will not emit the trigered signal of the action!!
+ actionBreadcrumbs_->setChecked(bcWidget_->active());
+
+ actionFrozen_->setChecked(vs->getAsBool("frozen",frozen()));
+ actionDetached_->setChecked(vs->getAsBool("detached",detached()));
+
+}
+
diff --git a/Viewer/src/InfoPanel.hpp b/Viewer/src/InfoPanel.hpp
new file mode 100644
index 0000000..9600af4
--- /dev/null
+++ b/Viewer/src/InfoPanel.hpp
@@ -0,0 +1,120 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef INFOPANEL_HPP_
+#define INFOPANEL_HPP_
+
+#include <QWidget>
+
+#include "DashboardWidget.hpp"
+#include "ServerObserver.hpp"
+#include "VInfo.hpp"
+
+#include "ui_InfoPanel.h"
+
+class QMenu;
+class QTabWidget;
+
+class DashboardDockTitleWidget;
+class InfoPanel;
+class InfoPanelDef;
+class InfoPanelItem;
+
+class InfoPanelItemHandler
+{
+friend class InfoPanel;
+
+public:
+ InfoPanelItemHandler(InfoPanelDef* def,InfoPanelItem* item) :
+ def_(def), item_(item) {}
+
+ bool match(const std::vector<InfoPanelDef*>& defs) const;
+ InfoPanelItem* item() const {return item_;}
+ QWidget* widget();
+ InfoPanelDef* def() const {return def_;}
+
+protected:
+ void addToTab(QTabWidget *);
+
+private:
+ InfoPanelDef* def_;
+ InfoPanelItem* item_;
+};
+
+
+class InfoPanel : public DashboardWidget, public ServerObserver, public VInfoObserver, private Ui::InfoPanel
+{
+ Q_OBJECT
+
+public:
+ explicit InfoPanel(QWidget* parent=0);
+ virtual ~InfoPanel();
+ bool frozen() const;
+ bool detached() const;
+ void clear();
+ void setCurrent(const std::string& name);
+ void setDetached(bool);
+
+ void populateDialog();
+
+ //From DashboardWidget
+ void populateDockTitleBar(DashboardDockTitleWidget*);
+ void reload() {}
+ void rerender();
+ void writeSettings(VSettings*);
+ void readSettings(VSettings*);
+
+ //From VInfoObserver
+ void notifyDelete(VInfo*) {}
+ void notifyDataLost(VInfo*);
+
+ //From ServerObserver
+ void notifyDefsChanged(ServerHandler* server, const std::vector<ecf::Aspect::Type>& a);
+ void notifyServerDelete(ServerHandler* server);
+ void notifyBeginServerClear(ServerHandler* server);
+ void notifyEndServerClear(ServerHandler* server) {}
+ void notifyBeginServerScan(ServerHandler* server,const VServerChange&) {}
+ void notifyEndServerScan(ServerHandler* server);
+ void notifyServerConnectState(ServerHandler* server);
+ void notifyServerSuiteFilterChanged(ServerHandler* server);
+ void notifyServerSyncFinished(ServerHandler* server);
+
+public Q_SLOTS:
+ void slotReload(VInfo_ptr node);
+ void setCurrentSelection(VInfo_ptr node) {slotReload(node);}
+
+protected Q_SLOTS:
+ void slotReloadFromBc(VInfo_ptr node);
+ void slotCurrentWidgetChanged(int);
+ void on_actionBreadcrumbs__toggled(bool b);
+ void on_actionFrozen__toggled(bool b);
+ void on_actionDetached__toggled(bool b);
+
+Q_SIGNALS:
+ void selectionChanged(VInfo_ptr);
+
+private:
+ void reset(VInfo_ptr node);
+ void adjustInfo(VInfo_ptr node);
+ void adjustTabs(VInfo_ptr node);
+ InfoPanelItemHandler* findHandler(QWidget* w);
+ InfoPanelItemHandler* findHandler(InfoPanelDef*);
+ InfoPanelItem* findItem(QWidget* w);
+ InfoPanelItemHandler* createHandler(InfoPanelDef*);
+ void clearTab();
+ void updateTitle();
+ QMenu* buildOptionsMenu();
+
+ QList<InfoPanelItemHandler*> items_;
+ VInfo_ptr info_;
+ bool tabBeingCleared_;
+ bool tabBeingAdjusted_;
+};
+
+#endif
diff --git a/Viewer/src/InfoPanel.ui b/Viewer/src/InfoPanel.ui
new file mode 100644
index 0000000..586f718
--- /dev/null
+++ b/Viewer/src/InfoPanel.ui
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>InfoPanel</class>
+ <widget class="QWidget" name="InfoPanel">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>683</width>
+ <height>468</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,1">
+ <property name="spacing">
+ <number>1</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="NodePathWidget" name="bcWidget_" native="true"/>
+ </item>
+ <item>
+ <widget class="MessageLabel" name="messageLabel_" native="true"/>
+ </item>
+ <item>
+ <widget class="QTabWidget" name="tab_">
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="tab">
+ <attribute name="title">
+ <string>Tab 1</string>
+ </attribute>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ <action name="actionDetached_">
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Detached</string>
+ </property>
+ </action>
+ <action name="actionFrozen_">
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Frozen</string>
+ </property>
+ <property name="toolTip">
+ <string>Do not update panel when node is updated</string>
+ </property>
+ </action>
+ <action name="actionBreadcrumbs_">
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Breadcrumbs</string>
+ </property>
+ </action>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>NodePathWidget</class>
+ <extends>QWidget</extends>
+ <header>NodePathWidget.hpp</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>MessageLabel</class>
+ <extends>QWidget</extends>
+ <header location="global">MessageLabel.hpp</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Viewer/src/InfoPanelHandler.cpp b/Viewer/src/InfoPanelHandler.cpp
new file mode 100644
index 0000000..f39e338
--- /dev/null
+++ b/Viewer/src/InfoPanelHandler.cpp
@@ -0,0 +1,133 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "InfoPanelHandler.hpp"
+
+
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/json_parser.hpp>
+#include <boost/foreach.hpp>
+
+#include "NodeExpression.hpp"
+#include "UserMessage.hpp"
+
+InfoPanelHandler* InfoPanelHandler::instance_=0;
+
+
+InfoPanelDef::InfoPanelDef(const std::string& name) :
+ name_(name),
+ visibleCondition_(0),
+ enabledCondition_(0),
+ hidden_(false)
+{
+
+}
+
+InfoPanelHandler::InfoPanelHandler()
+{
+
+}
+
+InfoPanelHandler* InfoPanelHandler::instance()
+{
+ if(!instance_)
+ instance_=new InfoPanelHandler();
+
+ return instance_;
+}
+
+void InfoPanelHandler::init(const std::string &configFile)
+{
+ // parse the response using the boost JSON property tree parser
+
+ using boost::property_tree::ptree;
+ ptree pt;
+
+ try
+ {
+ read_json(configFile, pt);
+ }
+ catch (const boost::property_tree::json_parser::json_parser_error& e)
+ {
+ std::string errorMessage = e.what();
+ UserMessage::message(UserMessage::ERROR, true, std::string("Error, unable to parse JSON menu file : " + errorMessage));
+ return;
+ }
+
+
+ // iterate over the top level of the tree
+ for (ptree::const_iterator itTopLevel = pt.begin(); itTopLevel != pt.end(); ++itTopLevel)
+ {
+ if (itTopLevel->first == "info_panel")
+ {
+ UserMessage::message(UserMessage::DBG, false, std::string("Panels:"));
+
+ ptree const &panelsPt = itTopLevel->second;
+
+ // iterate through all the panels
+ for (ptree::const_iterator itPanel = panelsPt.begin(); itPanel != panelsPt.end(); ++itPanel)
+ {
+ ptree const &panelPt = itPanel->second;
+
+ std::string cname = panelPt.get("name", "");
+
+ UserMessage::message(UserMessage::DBG, false, std::string(" ") + cname);
+
+ InfoPanelDef* def= new InfoPanelDef(cname);
+
+ def->setLabel(panelPt.get("label",""));
+ def->setIcon(panelPt.get("icon",""));
+ def->setDockIcon(panelPt.get("dock_icon",""));
+ def->setShow(panelPt.get("show",""));
+ def->setTooltip(panelPt.get("tooltip",""));
+
+ std::string enabled = panelPt.get("enabled_for", "");
+ std::string visible = panelPt.get("visible_for", "");
+
+ if(panelPt.get("hidden", "") == "1")
+ {
+ def->setHidden(true);
+ }
+
+ BaseNodeCondition *enabledCond = NodeExpressionParser::instance()->parseWholeExpression(enabled);
+ if (enabledCond == NULL)
+ {
+ UserMessage::message(UserMessage::ERROR, true, std::string("Error, unable to parse enabled condition: " + enabled));
+ enabledCond = new FalseNodeCondition();
+ }
+ def->setEnabledCondition(enabledCond);
+
+
+ BaseNodeCondition *visibleCond = NodeExpressionParser::instance()->parseWholeExpression(visible);
+ if (visibleCond == NULL)
+ {
+ UserMessage::message(UserMessage::ERROR, true, std::string("Error, unable to parse visible condition: " + visible));
+ visibleCond = new FalseNodeCondition();
+ }
+ def->setVisibleCondition(visibleCond);
+
+ panels_.push_back(def);
+
+ }
+ }
+ }
+}
+
+void InfoPanelHandler::visible(VInfo_ptr info,std::vector<InfoPanelDef*>& lst)
+{
+ if(!info || !info.get())
+ return;
+
+ for(std::vector<InfoPanelDef*>::const_iterator it=panels_.begin(); it != panels_.end(); ++it)
+ {
+ if(!(*it)->hidden() && (*it)->visibleCondition()->execute(info))
+ lst.push_back((*it));
+ }
+}
+
diff --git a/Viewer/src/InfoPanelHandler.hpp b/Viewer/src/InfoPanelHandler.hpp
new file mode 100644
index 0000000..f037d9d
--- /dev/null
+++ b/Viewer/src/InfoPanelHandler.hpp
@@ -0,0 +1,74 @@
+//============================================================================
+// Copyright 2015 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef INFOPANELHANDLER_HPP_
+#define INFOPANELHANDLER_HPP_
+
+#include <string>
+#include <vector>
+
+#include "VInfo.hpp"
+
+class BaseNodeCondition;
+
+class InfoPanelDef
+{
+public:
+ explicit InfoPanelDef(const std::string&);
+
+ std::string name() const {return name_;}
+ std::string label() const {return label_;}
+ std::string icon() const {return icon_;}
+ std::string dockIcon() const {return dockIcon_;}
+ std::string show() const {return show_;}
+ std::string tooltip() const {return tooltip_;}
+ bool hidden() const {return hidden_;}
+ BaseNodeCondition* visibleCondition() const {return visibleCondition_;}
+
+ void setLabel(const std::string& s) {label_=s;}
+ void setIcon(const std::string& s) {icon_=s;}
+ void setDockIcon(const std::string& s) {dockIcon_=s;}
+ void setShow(const std::string& s) {show_=s;}
+ void setTooltip(const std::string& tooltip) {tooltip_=tooltip;}
+ void setVisibleCondition(BaseNodeCondition *visibleCond) {visibleCondition_=visibleCond;}
+ void setEnabledCondition(BaseNodeCondition *enabledCond) {enabledCondition_=enabledCond;}
+ void setHidden(bool b) {hidden_=b;}
+
+protected:
+ std::string name_;
+ std::string label_;
+ std::string icon_;
+ std::string dockIcon_;
+ std::string show_;
+ std::string tooltip_;
+ bool hidden_;
+
+ BaseNodeCondition *visibleCondition_;
+ BaseNodeCondition *enabledCondition_;
+};
+
+class InfoPanelHandler
+{
+public:
+ InfoPanelHandler();
+
+ void init(const std::string& file);
+ void visible(VInfo_ptr info,std::vector<InfoPanelDef*>& lst);
+ const std::vector<InfoPanelDef*>& panels() const {return panels_;}
+
+ static InfoPanelHandler* instance();
+
+protected:
+ static InfoPanelHandler* instance_;
+
+ std::vector<InfoPanelDef*> panels_;
+
+};
+
+#endif
diff --git a/Viewer/src/InfoPanelItem.cpp b/Viewer/src/InfoPanelItem.cpp
new file mode 100644
index 0000000..d1bfbba
--- /dev/null
+++ b/Viewer/src/InfoPanelItem.cpp
@@ -0,0 +1,264 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "InfoPanelItem.hpp"
+
+#include "InfoProvider.hpp"
+#include "ServerHandler.hpp"
+#include "VNode.hpp"
+
+#include <map>
+
+static std::map<std::string,InfoPanelItemFactory*>* makers = 0;
+
+InfoPanelItemFactory::InfoPanelItemFactory(const std::string& name)
+{
+ if(makers == 0)
+ makers = new std::map<std::string,InfoPanelItemFactory*>;
+
+ // Put in reverse order...
+ (*makers)[name] = this;
+}
+
+InfoPanelItemFactory::~InfoPanelItemFactory()
+{
+ // Not called
+}
+
+InfoPanelItem* InfoPanelItemFactory::create(const std::string& name)
+{
+ std::map<std::string,InfoPanelItemFactory*>::iterator j = makers->find(name);
+ if(j != makers->end())
+ return (*j).second->make();
+
+ return 0;
+}
+
+//=======================================================
+//
+// InfoPanelItem
+//
+//=======================================================
+
+
+InfoPanelItem::~InfoPanelItem()
+{
+ clear();
+}
+
+//Set the new VInfo object.
+//We also we need to manage the node observers. The InfoItem
+//will be the observer of the server of the object stored in
+//the new VInfo
+void InfoPanelItem::adjust(VInfo_ptr info)
+{
+ //Check if there is data in info
+ if(info)
+ {
+ ServerHandler *server=info->server();
+
+ bool sameServer=(info_)?(info_->server() == server):false;
+
+ //Handle observers
+ if(!sameServer)
+ {
+ if(info_ && info_->server())
+ {
+ info_->server()->removeNodeObserver(this);
+ }
+ info->server()->addNodeObserver(this);
+ }
+ }
+ //If the there is no data we clean everything and return
+ else
+ {
+ if(info_ && info_->server())
+ {
+ info_->server()->removeNodeObserver(this);
+ }
+ }
+
+ //Set the info
+ info_=info;
+}
+
+void InfoPanelItem::clear()
+{
+ if(info_ && info_->server())
+ {
+ //info_->server()->removeServerObserver(this);
+ info_->server()->removeNodeObserver(this);
+ }
+
+ info_.reset();
+
+ for(std::vector<InfoProvider*>::iterator it=infoProviders_.begin(); it != infoProviders_.end(); ++it)
+ {
+ (*it)->clear();
+ }
+}
+
+//This function is called when the infopanel
+// is being reset. The info_ might be unset.
+void InfoPanelItem::setActive(bool active)
+{
+ active_=active;
+
+ if(active_)
+ {
+ //Enable the infoProviders
+ for(std::vector<InfoProvider*>::iterator it=infoProviders_.begin(); it != infoProviders_.end(); ++it)
+ {
+ (*it)->setActive(true);
+ }
+ }
+ else
+ {
+ clearContents();
+
+ selected_=false;
+ suspended_=false;
+
+ //Disable the info provider
+ for(std::vector<InfoProvider*>::iterator it=infoProviders_.begin(); it != infoProviders_.end(); ++it)
+ {
+ //This will clear the providers again
+ (*it)->setActive(false);
+ }
+ }
+
+ //updateWidgetState();
+}
+
+void InfoPanelItem::setSelected(bool selected,VInfo_ptr info)
+{
+ if(selected_ == selected)
+ return;
+
+ ChangeFlags flags(SelectedChanged);
+ selected_=selected;
+
+ assert(active_);
+
+ if(selected_)
+ {
+ //Suspend
+ if(suspended_) {}
+ //Resume
+ else
+ {
+ if(unselectedFlags_.isSet(KeepContents))
+ {
+ if(!info_)
+ {
+ reload(info);
+ return;
+ }
+ }
+ else
+ {
+ reload(info);
+ return;
+ }
+ }
+ }
+
+ //if the item becomes unselected we do not do anything if it is frozen
+ //or the contents must be kept (e.g. for output)
+ else
+ {
+ if(!frozen_)
+ {
+ if(!unselectedFlags_.isSet(KeepContents))
+ {
+ //This will also clear the providers
+ clearContents();
+ }
+ }
+
+ return;
+ }
+
+ //We update the derived class
+ updateState(flags);
+}
+
+void InfoPanelItem::setSuspended(bool suspended,VInfo_ptr info)
+{
+ if(suspended_ == suspended)
+ return;
+
+ suspended_=suspended;
+ ChangeFlags flags(SuspendedChanged);
+
+ if(!active_)
+ return;
+
+ //Suspend
+ if(suspended_) {}
+ //Resume
+ else
+ {
+ if(selected_ && !info_)
+ {
+ reload(info);
+ return;
+ }
+ }
+
+ //We update the derived class
+ updateState(flags);
+}
+
+void InfoPanelItem::setFrozen(bool b)
+{
+ frozen_=b;
+ if(!active_)
+ return;
+
+ //We update the derived class
+ updateState(FrozenChanged);
+
+}
+
+void InfoPanelItem::setDetached(bool b)
+{
+ detached_=b;
+
+ if(!active_)
+ return;
+
+ //We update the derived class
+ updateState(DetachedChanged);
+
+}
+
+//From NodeObserver
+void InfoPanelItem::notifyBeginNodeChange(const VNode* node, const std::vector<ecf::Aspect::Type>& aspect,const VNodeChange&)
+{
+ if(!node || frozen_ || !active_ || suspended_)
+ return;
+
+ //Check if there is data in info
+ if(info_)
+ {
+ if(info_->isNode())
+ {
+ //Check if the updated node is handled by the item
+ if(info_->node() == node ||
+ (useAncestors_ && info_->node()->isAncestor(node)))
+ {
+ //We call the method implemented in the concrete class
+ //to handle the changes
+ nodeChanged(node,aspect);
+ return;
+ }
+ }
+ }
+}
diff --git a/Viewer/src/InfoPanelItem.hpp b/Viewer/src/InfoPanelItem.hpp
new file mode 100644
index 0000000..bf8270e
--- /dev/null
+++ b/Viewer/src/InfoPanelItem.hpp
@@ -0,0 +1,115 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef INFOPANELITEM_HPP_
+#define INFOPANELITEM_HPP_
+
+#include "FlagSet.hpp"
+#include "NodeObserver.hpp"
+#include "VInfo.hpp"
+#include "InfoPresenter.hpp"
+#include "VTask.hpp"
+#include "VTaskObserver.hpp"
+
+#include <string>
+
+class QWidget;
+class InfoPanel;
+class InfoProvider;
+
+//This is the (abstract) base class to represent one tab in the info panel.
+
+class InfoPanelItem : public VTaskObserver, public InfoPresenter, public NodeObserver
+{
+friend class InfoPanel;
+
+public:
+ InfoPanelItem() : active_(false), selected_(false), suspended_(false),
+ frozen_(false), detached_(false), unselectedFlags_(KeepContents),
+ useAncestors_(false) {}
+ virtual ~InfoPanelItem();
+
+ enum ChangeFlag {ActiveChanged=1,SelectedChanged=2,SuspendedChanged=4,FrozenChanged=8,DetachedChanged=16};
+ typedef FlagSet<ChangeFlag> ChangeFlags;
+
+ //What to do when the item is unselected
+ enum UnselectedFlag {KeepContents=1,KeepActivity=2};
+ typedef FlagSet<UnselectedFlag> UnselectedFlags;
+
+ virtual void reload(VInfo_ptr info)=0;
+ virtual QWidget* realWidget()=0;
+ virtual void clearContents()=0;
+
+ virtual void setActive(bool);
+ void setSelected(bool,VInfo_ptr);
+ void setSuspended(bool,VInfo_ptr);
+ void setFrozen(bool);
+ void setDetached(bool);
+
+ //From VTaskObserver
+ void taskChanged(VTask_ptr) {}
+
+ //From VInfoPresenter
+ void infoReady(VReply*) {}
+ void infoFailed(VReply*) {}
+ void infoProgress(VReply*) {}
+ void infoProgressStart(int min,int max,const std::string& text) {}
+ void infoProgress(int value,const std::string& text) {}
+
+ //From NodeObserver
+ void notifyBeginNodeChange(const VNode*, const std::vector<ecf::Aspect::Type>&,const VNodeChange&);
+ void notifyEndNodeChange(const VNode*, const std::vector<ecf::Aspect::Type>&,const VNodeChange&) {}
+
+protected:
+ void adjust(VInfo_ptr);
+ virtual void clear();
+ virtual void updateState(const ChangeFlags&)=0;
+
+ //Notifications about the server changes
+ virtual void defsChanged(const std::vector<ecf::Aspect::Type>&)=0;
+ virtual void connectStateChanged() {}
+ virtual void suiteFilterChanged() {}
+ virtual void serverSyncFinished() {}
+
+ //Notifications about the node changes
+ virtual void nodeChanged(const VNode*, const std::vector<ecf::Aspect::Type>&)=0;
+
+ bool active_;
+ bool selected_;
+ bool suspended_;
+ bool frozen_;
+ bool detached_;
+ UnselectedFlags unselectedFlags_;
+ bool useAncestors_;
+};
+
+class InfoPanelItemFactory
+{
+public:
+ explicit InfoPanelItemFactory(const std::string&);
+ virtual ~InfoPanelItemFactory();
+
+ virtual InfoPanelItem* make() = 0;
+ static InfoPanelItem* create(const std::string& name);
+
+private:
+ explicit InfoPanelItemFactory(const InfoPanelItemFactory&);
+ InfoPanelItemFactory& operator=(const InfoPanelItemFactory&);
+
+};
+
+template<class T>
+class InfoPanelItemMaker : public InfoPanelItemFactory
+{
+ InfoPanelItem* make() { return new T(); }
+public:
+ explicit InfoPanelItemMaker(const std::string& name) : InfoPanelItemFactory(name) {}
+};
+
+#endif
diff --git a/Viewer/src/InfoPresenter.hpp b/Viewer/src/InfoPresenter.hpp
new file mode 100644
index 0000000..0a5c268
--- /dev/null
+++ b/Viewer/src/InfoPresenter.hpp
@@ -0,0 +1,43 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef INFOPRESENTER_HPP_
+#define INFOPRESENTER_HPP_
+
+#include "VInfo.hpp"
+#include <vector>
+
+class InfoProvider;
+class VReply;
+
+//This is a base class for presenting a VInfo object. The InfoPanelItems
+//are derived from this class. It can contain an InfoProvider member that
+//is able to generate the information we want to display about the VInfo.
+
+class InfoPresenter
+{
+public:
+ InfoPresenter() : infoProvider_(0) {}
+ virtual ~InfoPresenter() {}
+ virtual void infoReady(VReply*) {}
+ virtual void infoFailed(VReply*) {}
+ virtual void infoProgress(VReply*) {}
+ virtual void infoProgressStart(const std::string& text,int max) {}
+ virtual void infoProgress(const std::string& text,int value) {}
+ virtual void infoAppended(VReply*) {}
+ VInfo_ptr info() const {return info_;}
+ void registerInfoProvider(InfoProvider* ip) {infoProviders_.push_back(ip);}
+
+protected:
+ VInfo_ptr info_;
+ InfoProvider* infoProvider_; //the main info provider
+ std::vector<InfoProvider*> infoProviders_; //the list of all the providers including the main one
+};
+
+#endif
diff --git a/Viewer/src/InfoProvider.cpp b/Viewer/src/InfoProvider.cpp
new file mode 100644
index 0000000..f9ce7a5
--- /dev/null
+++ b/Viewer/src/InfoProvider.cpp
@@ -0,0 +1,287 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "InfoProvider.hpp"
+#include "VNode.hpp"
+#include "VReply.hpp"
+#include "ServerHandler.hpp"
+
+#include <QDateTime>
+
+#include <boost/algorithm/string/predicate.hpp>
+
+InfoProvider::InfoProvider(InfoPresenter* owner,VTask::Type taskType) :
+ owner_(owner),
+ taskType_(taskType),
+ active_(false),
+ autoUpdate_(false),
+ inAutoUpdate_(false)
+{
+ reply_=new VReply(this);
+ if(owner_)
+ owner_->registerInfoProvider(this);
+}
+
+InfoProvider::~InfoProvider()
+{
+ delete reply_;
+ clear();
+}
+
+void InfoProvider::clear()
+{
+ if(task_)
+ task_->status(VTask::CANCELLED);
+
+ reply_->reset();
+ info_.reset();
+}
+
+void InfoProvider::setActive(bool b)
+{
+ active_=b;
+ if(!active_)
+ clear();
+}
+
+void InfoProvider::setAutoUpdate(bool b)
+{
+ autoUpdate_=b;
+}
+
+void InfoProvider::info(VInfo_ptr info)
+{
+ //We keep it alive
+ info_=info;
+
+ if(task_)
+ {
+ task_->status(VTask::CANCELLED);
+ task_.reset();
+ }
+
+ if(owner_ && info_)
+ info_->accept(this);
+}
+
+//Server
+void InfoProvider::visit(VInfoServer* info)
+{
+ reply_->reset();
+
+ if(!info->server())
+ {
+ owner_->infoFailed(reply_);
+ }
+
+ //Define a task for getting the info from the server.
+ task_=VTask::create(taskType_,this);
+
+ //Run the task in the server. When it completes taskFinished() is called. The text returned
+ //in the reply will be prepended to the string we generated above.
+ info->server()->run(task_);
+}
+
+//Node
+void InfoProvider::visit(VInfoNode* info)
+{
+ reply_->reset();
+
+ if(!info->node() || !info->node()->node())
+ {
+ owner_->infoFailed(reply_);
+ }
+
+ //Check if we have a server
+ if(!info->server())
+ {
+ owner_->infoFailed(reply_);
+ }
+
+ VNode *n=info->node();
+
+ std::string fileName;
+ if(!fileVarName_.empty())
+ {
+ //Get the fileName
+ fileName=n->genVariable(fileVarName_);
+ }
+
+ //We try to read the file directly from the disk
+ if(info->server()->readFromDisk())
+ {
+ //There is a variable defined for the filename
+ if(!fileName.empty())
+ {
+ if(reply_->textFromFile(fileName))
+ {
+ reply_->fileReadMode(VReply::LocalReadMode);
+ reply_->fileName(fileName);
+ owner_->infoReady(reply_);
+ return;
+ }
+ /*else if(handleFileMissing(fileName,reply_))
+ {
+ return;
+ }*/
+ }
+ }
+
+ //We try to get the file contents from the server
+ //(this will go through the threaded communication)
+
+ //Define a task for getting the info from the server.
+ task_=VTask::create(taskType_,n,this);
+ task_->reply()->fileName(fileName);
+ task_->reply()->fileReadMode(VReply::ServerReadMode);
+
+ //Run the task in the server. When it finish taskFinished() is called. The text returned
+ //in the reply will be prepended to the string we generated above.
+ info->server()->run(task_);
+
+}
+
+void InfoProvider::handleFileNotDefined(VReply *reply)
+{
+ reply->setInfoText(fileNotDefinedText_);
+ owner_->infoReady(reply_);
+}
+
+bool InfoProvider::handleFileMissing(const std::string& fileName,VReply *reply)
+{
+ return false;
+
+ //reply->setWarningText(fileMissingText_);
+ //owner_->infoReady(reply_);
+}
+
+void InfoProvider::taskChanged(VTask_ptr task)
+{
+ if(task_ != task)
+ return;
+
+ //temporary hack!
+ task_->reply()->setSender(this);
+
+ switch(task->status())
+ {
+ case VTask::FINISHED:
+ {
+ task->reply()->addLog("TRY>fetch file from ecflow server: OK");
+
+ //The file should have a copy of the reply log
+ VFile_ptr f=task_->reply()->tmpFile();
+ if(f)
+ {
+ f->setFetchDate(QDateTime::currentDateTime());
+ f->setFetchMode(VFile::ServerFetchMode);
+ f->setLog(task_->reply()->log());
+ }
+ task->reply()->status(VReply::TaskDone);
+ owner_->infoReady(task->reply());
+ task_.reset();
+ }
+ break;
+ case VTask::ABORTED:
+ case VTask::REJECTED:
+ task->reply()->addLog("TRY>fetch file from ecflow server: FAILED");
+ task->reply()->status(VReply::TaskFailed);
+ owner_->infoFailed(task->reply());
+ task_.reset();
+ break;
+ case VTask::CANCELLED:
+ if(!task->reply()->errorText().empty())
+ {
+ task->reply()->addLog("TRY>fetch file from ecflow server: FAILED");
+ task->reply()->status(VReply::TaskCancelled);
+ owner_->infoFailed(task->reply());
+ }
+ //We do not need the task anymore.
+ task_.reset();
+ break;
+ default:
+ break;
+ }
+}
+
+JobProvider::JobProvider(InfoPresenter* owner) :
+ InfoProvider(owner,VTask::JobTask)
+{
+ fileVarName_="ECF_JOB";
+
+ fileNotDefinedText_="Job is <b>not</b> defined";
+
+ fileMissingText_="Job <b>not</b> found! <br> Check <b>ECF_HOME</b> directory \
+ for read/write access. Check for file presence and read access below. \
+ The file may have been deleted or this may be a '<i>dummy</i>' task";
+}
+
+bool JobProvider::handleFileMissing(const std::string& fileName,VReply *reply)
+{
+ if(fileName.find(".job0") != std::string::npos)
+ {
+ reply->setInfoText("No job to be expected when <b>TRYNO</b> is 0!");
+ owner_->infoReady(reply_);
+ return true;
+ }
+
+
+ /*else
+ {
+ reply->setWarningText(fileMissingText_);
+ }*/
+ return false;
+}
+
+ManualProvider::ManualProvider(InfoPresenter* owner) :
+ InfoProvider(owner,VTask::ManualTask)
+{
+ fileVarName_="ECF_MANUAL";
+ fileNotDefinedText_="Manual is <b>not</b> available";
+ fileMissingText_="Manual is <b>not</b> available";
+}
+
+MessageProvider::MessageProvider(InfoPresenter* owner) :
+ InfoProvider(owner,VTask::MessageTask)
+{
+
+}
+
+ScriptProvider::ScriptProvider(InfoPresenter* owner) :
+ InfoProvider(owner,VTask::ScriptTask)
+{
+ fileVarName_="ECF_SCRIPT";
+ fileNotDefinedText_="Script is <b>not</b> defined";
+ fileMissingText_="Script <b>not/b> found! <br> Check <b>ECF_FILES</b> or <b>ECF_HOME</b> directories, \
+ for read access. Check for file presence and read access below files directory \
+ or this may be a '<i>dummy</i>' task";
+}
+
+HistoryProvider::HistoryProvider(InfoPresenter* owner) :
+ InfoProvider(owner,VTask::HistoryTask)
+{
+
+}
+
+SuiteProvider::SuiteProvider(InfoPresenter* owner) :
+ InfoProvider(owner,VTask::SuiteListTask)
+{
+
+}
+
+
+ZombieProvider::ZombieProvider(InfoPresenter* owner) :
+ InfoProvider(owner,VTask::ZombieListTask)
+{
+
+}
+
+
+
+
diff --git a/Viewer/src/InfoProvider.hpp b/Viewer/src/InfoProvider.hpp
new file mode 100644
index 0000000..c79bc30
--- /dev/null
+++ b/Viewer/src/InfoProvider.hpp
@@ -0,0 +1,106 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef INFOPROVIDER_HPP_
+#define INFOPROVIDER_HPP_
+
+#include "FlagSet.hpp"
+#include "VInfo.hpp"
+#include "InfoPresenter.hpp"
+#include "VTask.hpp"
+#include "VTaskObserver.hpp"
+
+class InfoPanelItem;
+
+class InfoProvider : public VTaskObserver, public VInfoVisitor
+{
+public:
+ InfoProvider(InfoPresenter* owner,VTask::Type);
+ virtual ~InfoProvider();
+
+ void info(VInfo_ptr);
+ void command(VTask::Type);
+ virtual void clear();
+
+ void setActive(bool);
+ virtual void setAutoUpdate(bool);
+ bool autoUpdate() const {return autoUpdate_;}
+ bool inAutoUpdate() const {return inAutoUpdate_;}
+
+ //From VInfoVisitor
+ void visit(VInfoServer*);
+ void visit(VInfoNode*);
+ void visit(VInfoAttribute*) {}
+
+ //From VTaskObserver
+ void taskChanged(VTask_ptr);
+
+protected:
+ virtual void handleFileNotDefined(VReply *reply);
+ virtual bool handleFileMissing(const std::string& fileName,VReply *reply);
+ virtual void optionsChanged() {}
+
+ InfoPresenter* owner_;
+ VInfo_ptr info_;
+ VTask_ptr task_;
+ VReply* reply_;
+ VTask::Type taskType_;
+ std::string fileVarName_;
+ std::string fileNotDefinedText_;
+ std::string fileMissingText_;
+ bool active_;
+ bool autoUpdate_;
+ bool inAutoUpdate_;
+};
+
+class JobProvider : public InfoProvider
+{
+public:
+ explicit JobProvider(InfoPresenter* owner);
+protected:
+ bool handleFileMissing(const std::string& fileName,VReply *reply);
+};
+
+class ManualProvider : public InfoProvider
+{
+public:
+ explicit ManualProvider(InfoPresenter* owner);
+};
+
+class MessageProvider : public InfoProvider
+{
+public:
+ explicit MessageProvider(InfoPresenter* owner);
+};
+
+class ScriptProvider : public InfoProvider
+{
+public:
+ explicit ScriptProvider(InfoPresenter* owner);
+};
+
+class HistoryProvider : public InfoProvider
+{
+public:
+ explicit HistoryProvider(InfoPresenter* owner);
+};
+
+class SuiteProvider : public InfoProvider
+{
+public:
+ explicit SuiteProvider(InfoPresenter* owner);
+};
+
+class ZombieProvider : public InfoProvider
+{
+public:
+ explicit ZombieProvider(InfoPresenter* owner);
+};
+
+#endif
diff --git a/Viewer/src/JobItemWidget.cpp b/Viewer/src/JobItemWidget.cpp
new file mode 100644
index 0000000..4795ac9
--- /dev/null
+++ b/Viewer/src/JobItemWidget.cpp
@@ -0,0 +1,96 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "JobItemWidget.hpp"
+
+#include "Highlighter.hpp"
+#include "InfoProvider.hpp"
+#include "VConfig.hpp"
+#include "VReply.hpp"
+#include "VNode.hpp"
+
+JobItemWidget::JobItemWidget(QWidget *parent) : CodeItemWidget(parent)
+{
+ messageLabel_->hide();
+
+ //Remove the first spacer item!!
+ removeSpacer();
+
+ Highlighter* ih=new Highlighter(textEdit_->document(),"job");
+
+ infoProvider_=new JobProvider(this);
+
+ //Editor font
+ textEdit_->setFontProperty(VConfig::instance()->find("panel.job.font"));
+}
+
+JobItemWidget::~JobItemWidget()
+{
+}
+
+QWidget* JobItemWidget::realWidget()
+{
+ return this;
+}
+
+void JobItemWidget::reload(VInfo_ptr info)
+{
+ assert(active_);
+
+ if(suspended_)
+ return;
+
+ clearContents();
+ info_=info;
+ messageLabel_->hide();
+
+ //Info must be a node
+ if(info_ && info_->isNode() && info_->node())
+ {
+ infoProvider_->info(info_);
+ }
+}
+
+void JobItemWidget::clearContents()
+{
+ InfoPanelItem::clear();
+ textEdit_->clear();
+ messageLabel_->hide();
+}
+
+void JobItemWidget::infoReady(VReply* reply)
+{
+ QString s=QString::fromStdString(reply->text());
+ textEdit_->setPlainText(s);
+
+ if(reply->hasWarning())
+ {
+ messageLabel_->showWarning(QString::fromStdString(reply->warningText()));
+ }
+ else if(reply->hasInfo())
+ {
+ messageLabel_->showInfo(QString::fromStdString(reply->infoText()));
+ }
+
+ fileLabel_->update(reply);
+}
+
+void JobItemWidget::infoProgress(VReply* reply)
+{
+ QString s=QString::fromStdString(reply->infoText());
+ messageLabel_->showInfo(s);
+}
+
+void JobItemWidget::infoFailed(VReply* reply)
+{
+ QString s=QString::fromStdString(reply->errorText());
+ messageLabel_->showError(s);
+}
+
+static InfoPanelItemMaker<JobItemWidget> maker1("job");
diff --git a/Viewer/src/JobItemWidget.hpp b/Viewer/src/JobItemWidget.hpp
new file mode 100644
index 0000000..75780fb
--- /dev/null
+++ b/Viewer/src/JobItemWidget.hpp
@@ -0,0 +1,43 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef JOBITEMWIDGET_HPP_
+#define JOBITEMWIDGET_HPP_
+
+#include "InfoPanelItem.hpp"
+#include "CodeItemWidget.hpp"
+#include "VInfo.hpp"
+
+#include "ServerHandler.hpp"
+
+class JobItemWidget : public CodeItemWidget, public InfoPanelItem
+{
+public:
+ explicit JobItemWidget(QWidget *parent=0);
+ ~JobItemWidget();
+
+ void reload(VInfo_ptr);
+ QWidget* realWidget();
+ void clearContents();
+
+ //From VInfoPresenter
+ void infoReady(VReply*);
+ void infoFailed(VReply*);
+ void infoProgress(VReply*);
+
+ void nodeChanged(const VNode*, const std::vector<ecf::Aspect::Type>&) {}
+ void defsChanged(const std::vector<ecf::Aspect::Type>&) {}
+
+protected:
+ void updateState(const ChangeFlags&) {}
+};
+
+#endif
+
diff --git a/Viewer/src/LabelEditor.cpp b/Viewer/src/LabelEditor.cpp
new file mode 100644
index 0000000..1d797c6
--- /dev/null
+++ b/Viewer/src/LabelEditor.cpp
@@ -0,0 +1,132 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "LabelEditor.hpp"
+
+#include <QSettings>
+
+#include "AttributeEditorFactory.hpp"
+#include "VAttribute.hpp"
+#include "VAttributeType.hpp"
+#include "ServerHandler.hpp"
+#include "SessionHandler.hpp"
+
+LabelEditorWidget::LabelEditorWidget(QWidget* parent) : QWidget(parent)
+{
+ setupUi(this);
+
+ QLayoutItem *item;
+ item=grid_->itemAtPosition(1,0);
+ Q_ASSERT(item);
+ item->setAlignment(Qt::AlignLeft|Qt::AlignTop);
+}
+
+LabelEditor::LabelEditor(VInfo_ptr info,QWidget* parent) : AttributeEditor(info,"label",parent)
+{
+ w_=new LabelEditorWidget(this);
+ addForm(w_);
+
+ VAttribute* a=info_->attribute();
+
+ Q_ASSERT(a);
+ Q_ASSERT(a->type());
+ Q_ASSERT(a->type()->name() == "label");
+
+ if(a->data().count() < 2)
+ return;
+
+ QString name=a->data().at(1);
+ QString val;
+ if(a->data().count() > 2)
+ val=a->data().at(2);
+
+ oriVal_=val;
+
+ w_->nameLabel_->setText(name);
+ w_->valueTe_->setPlainText(val);
+ w_->valueTe_->setFocus();
+
+ header_->setInfo(QString::fromStdString(info_->path()),"Label");
+
+ connect(w_->valueTe_,SIGNAL(textChanged()),
+ this,SLOT(slotValueChanged()));
+
+ checkButtonStatus();
+
+ readSettings();
+}
+
+LabelEditor::~LabelEditor()
+{
+ writeSettings();
+}
+
+void LabelEditor::apply()
+{
+ std::string val=w_->valueTe_->toPlainText().toStdString();
+ std::string name=w_->nameLabel_->text().toStdString();
+
+ std::vector<std::string> cmd;
+ VAttribute::buildAlterCommand(cmd,"change","label",name,val);
+ ServerHandler::command(info_,cmd);
+}
+
+void LabelEditor::resetValue()
+{
+ w_->valueTe_->setPlainText(oriVal_);
+ checkButtonStatus();
+}
+
+void LabelEditor::slotValueChanged()
+{
+ checkButtonStatus();
+}
+
+bool LabelEditor::isValueChanged()
+{
+ return (oriVal_ != w_->valueTe_->toPlainText());
+}
+
+void LabelEditor::writeSettings()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ Q_ASSERT(cs);
+ QSettings settings(QString::fromStdString(cs->qtSettingsFile("LabelEditor")),
+ QSettings::NativeFormat);
+
+ //We have to clear it so that should not remember all the previous values
+ settings.clear();
+
+ settings.beginGroup("main");
+ settings.setValue("size",size());
+ settings.endGroup();
+}
+
+void LabelEditor::readSettings()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ Q_ASSERT(cs);
+ QSettings settings(QString::fromStdString(cs->qtSettingsFile("LabelEditor")),
+ QSettings::NativeFormat);
+
+ settings.beginGroup("main");
+ if(settings.contains("size"))
+ {
+ resize(settings.value("size").toSize());
+ }
+ else
+ {
+ resize(QSize(310,200));
+ }
+
+ settings.endGroup();
+}
+
+static AttributeEditorMaker<LabelEditor> makerStr("label");
diff --git a/Viewer/src/LabelEditor.hpp b/Viewer/src/LabelEditor.hpp
new file mode 100644
index 0000000..8bcbe65
--- /dev/null
+++ b/Viewer/src/LabelEditor.hpp
@@ -0,0 +1,50 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef LABELEDITOR_HPP
+#define LABELEDITOR_HPP
+
+#include "ui_LabelEditorWidget.h"
+
+#include "AttributeEditor.hpp"
+#include "VInfo.hpp"
+
+class LabelEditor;
+
+class LabelEditorWidget : public QWidget, protected Ui::LabelEditorWidget
+{
+friend class LabelEditor;
+public:
+ LabelEditorWidget(QWidget *parent=0);
+};
+
+class LabelEditor : public AttributeEditor
+{
+Q_OBJECT
+public:
+ LabelEditor(VInfo_ptr,QWidget* parent=0);
+ ~LabelEditor();
+
+protected Q_SLOTS:
+ void slotValueChanged();
+
+protected:
+ void apply();
+ void resetValue();
+ bool isValueChanged();
+ void readSettings();
+ void writeSettings();
+
+ LabelEditorWidget* w_;
+ QString oriVal_;
+};
+
+#endif // LABELEDITOR_HPP
+
diff --git a/Viewer/src/LabelEditorWidget.ui b/Viewer/src/LabelEditorWidget.ui
new file mode 100644
index 0000000..6ea9670
--- /dev/null
+++ b/Viewer/src/LabelEditorWidget.ui
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>LabelEditorWidget</class>
+ <widget class="QWidget" name="LabelEditorWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>329</width>
+ <height>227</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" name="grid_" rowstretch="0,0">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item row="0" column="1">
+ <widget class="QLabel" name="nameLabel_">
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Value:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QPlainTextEdit" name="valueTe_">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Name:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Viewer/src/LimitEditor.cpp b/Viewer/src/LimitEditor.cpp
new file mode 100644
index 0000000..9c07bd2
--- /dev/null
+++ b/Viewer/src/LimitEditor.cpp
@@ -0,0 +1,163 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "LimitEditor.hpp"
+
+#include <QSettings>
+
+#include "AttributeEditorFactory.hpp"
+#include "VAttribute.hpp"
+#include "VAttributeType.hpp"
+#include "ServerHandler.hpp"
+#include "SessionHandler.hpp"
+
+LimitEditorWidget::LimitEditorWidget(QWidget* parent) : QWidget(parent)
+{
+ setupUi(this);
+}
+
+LimitEditor::LimitEditor(VInfo_ptr info,QWidget* parent) : AttributeEditor(info,"limit",parent)
+{
+ w_=new LimitEditorWidget(this);
+ addForm(w_);
+
+ VAttribute* a=info_->attribute();
+
+ Q_ASSERT(a);
+ Q_ASSERT(a->type());
+ Q_ASSERT(a->type()->name() == "limit");
+
+ if(a->data().count() < 4)
+ return;
+
+ QString name=a->data().at(1);
+ oriVal_=a->data().at(2).toInt();
+ oriMax_=a->data().at(3).toInt();
+
+ w_->nameLabel_->setText(name);
+ w_->valueSpin_->setValue(oriVal_);
+ w_->maxSpin_->setValue(oriMax_);
+
+ w_->valueSpin_->setFocus();
+
+ if(a->data().at(2).isEmpty() || a->data().at(3).isEmpty())
+ {
+ return;
+ }
+
+ connect(w_->valueSpin_,SIGNAL(valueChanged(int)),
+ this,SLOT(slotValueChanged(int)));
+
+ connect(w_->maxSpin_,SIGNAL(valueChanged(int)),
+ this,SLOT(slotMaxChanged(int)));
+
+ header_->setInfo(QString::fromStdString(info_->path()),"Limit");
+
+ checkButtonStatus();
+
+ readSettings();
+}
+
+void LimitEditor::apply()
+{
+ int intVal=w_->valueSpin_->value();
+ int intMax=w_->maxSpin_->value();
+ std::string val=QString::number(intVal).toStdString();
+ std::string max=QString::number(intMax).toStdString();
+ std::string name=w_->nameLabel_->text().toStdString();
+
+ std::vector<std::string> valCmd;
+ VAttribute::buildAlterCommand(valCmd,"change","limit_value",name,val);
+
+ std::vector<std::string> maxCmd;
+ VAttribute::buildAlterCommand(maxCmd,"change","limit_max",name,max);
+
+ if(oriVal_ != intVal && oriMax_ != intMax)
+ {
+ if(intVal < oriMax_)
+ {
+ ServerHandler::command(info_,valCmd);
+ ServerHandler::command(info_,maxCmd);
+ }
+ else
+ {
+ ServerHandler::command(info_,maxCmd);
+ ServerHandler::command(info_,valCmd);
+ }
+ }
+ else if(oriVal_ != intVal)
+ {
+ ServerHandler::command(info_,valCmd);
+ }
+
+ else if(oriMax_ != intMax)
+ {
+ ServerHandler::command(info_,maxCmd);
+ }
+}
+
+void LimitEditor::resetValue()
+{
+ w_->valueSpin_->setValue(oriVal_);
+ w_->maxSpin_->setValue(oriMax_);
+ checkButtonStatus();
+}
+
+void LimitEditor::slotValueChanged(int)
+{
+ checkButtonStatus();
+}
+
+void LimitEditor::slotMaxChanged(int)
+{
+ checkButtonStatus();
+}
+
+bool LimitEditor::isValueChanged()
+{
+ return (oriVal_ != w_->valueSpin_->value() || oriMax_ != w_->maxSpin_->value());
+}
+
+void LimitEditor::writeSettings()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ Q_ASSERT(cs);
+ QSettings settings(QString::fromStdString(cs->qtSettingsFile("LimitEditor")),
+ QSettings::NativeFormat);
+
+ //We have to clear it so that should not remember all the previous values
+ settings.clear();
+
+ settings.beginGroup("main");
+ settings.setValue("size",size());
+ settings.endGroup();
+}
+
+void LimitEditor::readSettings()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ Q_ASSERT(cs);
+ QSettings settings(QString::fromStdString(cs->qtSettingsFile("LimitEditor")),
+ QSettings::NativeFormat);
+
+ settings.beginGroup("main");
+ if(settings.contains("size"))
+ {
+ resize(settings.value("size").toSize());
+ }
+ else
+ {
+ resize(QSize(310,200));
+ }
+
+ settings.endGroup();
+}
+
+static AttributeEditorMaker<LimitEditor> makerStr("limit");
diff --git a/Viewer/src/LimitEditor.hpp b/Viewer/src/LimitEditor.hpp
new file mode 100644
index 0000000..836c9d3
--- /dev/null
+++ b/Viewer/src/LimitEditor.hpp
@@ -0,0 +1,52 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef LIMITEDITOR_HPP
+#define LIMITEDITOR_HPP
+
+#include "ui_LimitEditorWidget.h"
+
+#include "AttributeEditor.hpp"
+#include "VInfo.hpp"
+
+class LimitEditor;
+
+class LimitEditorWidget : public QWidget, protected Ui::LimitEditorWidget
+{
+friend class LimitEditor;
+public:
+ LimitEditorWidget(QWidget *parent=0);
+};
+
+class LimitEditor : public AttributeEditor
+{
+Q_OBJECT
+public:
+ LimitEditor(VInfo_ptr,QWidget* parent=0);
+
+protected Q_SLOTS:
+ void slotValueChanged(int);
+ void slotMaxChanged(int);
+
+protected:
+ void resetValue();
+ void apply();
+ bool isValueChanged();
+ void readSettings();
+ void writeSettings();
+
+ LimitEditorWidget* w_;
+ int oriVal_;
+ int oriMax_;
+};
+
+#endif // LIMITEDITOR_HPP
+
+
diff --git a/Viewer/src/LimitEditorWidget.ui b/Viewer/src/LimitEditorWidget.ui
new file mode 100644
index 0000000..aa54449
--- /dev/null
+++ b/Viewer/src/LimitEditorWidget.ui
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>LimitEditorWidget</class>
+ <widget class="QWidget" name="LimitEditorWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>329</width>
+ <height>227</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout_2">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="nameLabel_">
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Value:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Maximum:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QSpinBox" name="valueSpin_"/>
+ </item>
+ <item row="2" column="1">
+ <widget class="QSpinBox" name="maxSpin_"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Viewer/src/LineEdit.cpp b/Viewer/src/LineEdit.cpp
new file mode 100644
index 0000000..7b8c24d
--- /dev/null
+++ b/Viewer/src/LineEdit.cpp
@@ -0,0 +1,109 @@
+//============================================================================
+// Copyright 2015 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "LineEdit.hpp"
+
+#include <QLabel>
+#include <QResizeEvent>
+#include <QStyle>
+#include <QToolButton>
+
+LineEdit::LineEdit(QWidget *parent):
+ QLineEdit(parent),
+ iconLabel_(0)
+{
+ clearTb_=new QToolButton(this);
+ QPixmap pix(":/viewer/clear_left.svg");
+ clearTb_->setIcon(pix);
+ clearTb_->setIconSize(QSize(12,12));
+ clearTb_->setAutoRaise(true);
+ clearTb_->setCursor(Qt::ArrowCursor);
+ clearTb_->setToolTip(tr("Clear text"));
+ clearTb_->setObjectName("clearTextTb");
+
+ clearTb_->setStyleSheet("QToolButton{ border: node; padding: 0px;}");
+
+ connect(clearTb_,SIGNAL(clicked()),
+ this,SLOT(slotClear()));
+
+ adjustSize();
+
+ /*QSize tbSize=clearTb_->sizeHint();
+
+ int frame = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
+ setStyleSheet(QString("QLineEdit { padding-right: %1px; } ").arg(tbSize.width()+frame+1));
+ QSize minSize = minimumSizeHint();
+ setMinimumSize(qMax(minSize.width(),tbSize.height()+frame*2+2),
+ qMax(minSize.height(),tbSize.height()+frame*2+2));*/
+
+}
+
+void LineEdit::setDecoration(QPixmap pix)
+{
+ if(!iconLabel_)
+ iconLabel_=new QLabel(this);
+
+ iconLabel_->setPixmap(pix);
+ iconLabel_->setProperty("lineEdit","true");
+
+ adjustSize();
+
+ /*QSize icSize=iconLabel_->sizeHint();
+ QSize tbSize=clearTb_->sizeHint();
+
+ int frame = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
+ setStyleSheet(QString("QLineEdit { padding-left: %1px; } ").arg(icSize.width()+frame+1));
+ QSize minSize = minimumSizeHint();
+ setMinimumSize(qMax(minSize.width(),icSize.width()+tbSize.width()+frame*2+2),
+ qMax(minSize.height(),tbSize.height()+frame*2+2));*/
+}
+
+
+void LineEdit::adjustSize()
+{
+ int frame = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
+ QSize tbSize=clearTb_->sizeHint();
+ setStyleSheet(QString("QLineEdit { padding-right: %1px; } ").arg(tbSize.width()+frame+1));
+
+ int leftWidth=0;
+ if(iconLabel_)
+ {
+ QSize icSize=iconLabel_->sizeHint();
+ setStyleSheet(QString("QLineEdit { padding-left: %1px; } ").arg(icSize.width()+frame+1));
+ leftWidth=+icSize.width();
+ }
+ QSize minSize = minimumSizeHint();
+ setMinimumSize(qMax(minSize.width(),leftWidth+tbSize.width()+frame*2+2),
+ qMax(minSize.height(),tbSize.height()+frame*2+2));
+}
+
+
+void LineEdit::resizeEvent(QResizeEvent *)
+{
+ int frame = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
+
+ QSize tbSize = clearTb_->sizeHint();
+ clearTb_->move(rect().right()-frame-tbSize.width(),
+ (rect().bottom()+ 1-tbSize.height())/2);
+
+ if(iconLabel_)
+ {
+ QSize icSize=iconLabel_->sizeHint();
+ iconLabel_->move(rect().left()+frame+1,
+ (rect().bottom()+ 1-icSize.height())/2);
+ }
+}
+
+
+void LineEdit::slotClear()
+{
+ clear();
+ Q_EMIT textCleared();
+}
+
diff --git a/Viewer/src/LineEdit.hpp b/Viewer/src/LineEdit.hpp
new file mode 100644
index 0000000..9ea6504
--- /dev/null
+++ b/Viewer/src/LineEdit.hpp
@@ -0,0 +1,42 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef LINEEDIT_INC_
+#define LINEEDIT_INC_
+
+#include <QLineEdit>
+
+class QLabel;
+class QToolButton;
+
+class LineEdit : public QLineEdit
+{
+Q_OBJECT
+
+public:
+ explicit LineEdit (QWidget *parent=0);
+ void setDecoration(QPixmap);
+
+public Q_SLOTS:
+ void slotClear();
+
+Q_SIGNALS:
+ void textCleared();
+
+protected:
+ void adjustSize();
+ void resizeEvent(QResizeEvent*);
+
+ QToolButton *clearTb_;
+ QLabel* iconLabel_;
+};
+
+
+#endif
diff --git a/Viewer/src/LogEvent.cpp b/Viewer/src/LogEvent.cpp
new file mode 100644
index 0000000..ada00ab
--- /dev/null
+++ b/Viewer/src/LogEvent.cpp
@@ -0,0 +1,315 @@
+// #define MAIN
+
+#include <string.h>
+#include <sstream>
+#include <QFile>
+#include <QString>
+#include <QIODevice>
+#include <QTextStream>
+#include <QDateTime>
+#include <QDate>
+#include <QTime>
+#include <QVector>
+#include <QRegExp>
+#include <QStringList>
+#include <QStringRef>
+#include <QColor>
+#include <QGraphicsScene>
+#include <QWidget>
+#include <QGraphicsTextItem>
+/*
+
+shell = new QProcess(this);
+QStringList argv() << myfile.fileName();
+shell.start("./src/unzip",argv); // or in win32 - src/unzip.exe
+*/
+
+#include <QTextStream>
+// foreach(QString x, strings) QTextStream(stdout) << x << endl;
+#include "LogEvent.hpp"
+
+const int boxSize = 3;
+// namespace status {
+const QVector<QString> status (QVector<QString>() << "unknown"
+ << "suspended"
+ << "complete"
+ << "queued"
+ << "submitted"
+ << "active"
+ << "aborted"
+ << "shutdown"
+ << "halted"
+ << "event"
+ << "meter"
+ << "label"
+ );
+// }
+static EventSorter *sorter = 0x0;
+
+counted::counted()
+ : count_(0)
+{}
+
+counted::~counted()
+{}
+
+void counted::attach()
+{ ++count_; }
+
+void counted::detach()
+{ if (--count_==0) delete this; }
+
+static int compare(const void*a, const void*b) {
+ LogEvent** pa = (LogEvent**)a;
+ LogEvent** pb = (LogEvent**)b;
+ return sorter->compare(*pa, *pb);
+}
+
+bool lessThan( const LogEvent* le1, const LogEvent *le2 )
+{
+ if (le1 && le2) return le1->time() < le2->time();
+ return true;
+}
+
+class LogCache // : public QArray<LogEvent*>
+{
+public:
+ QVector<LogEvent*> add;
+ void reset() { int c = add.size(); while (c) { add[--c]->detach(); } add.clear(); }
+ void sort() { qSort(add.begin(), add.end(), lessThan); }
+ ~LogCache() {}
+};
+
+static LogCache cache;
+static QString cached;
+
+LogEvent::LogEvent(const QString& path, const QDateTime& time)
+ : time_(time)
+ , path_(path)
+{
+ attach();
+ cache.add.append(this);
+ // observe
+}
+
+LogEvent::~LogEvent()
+{}
+
+int LogEvent::load(bool reset)
+{
+ if (reset) {
+ cache.reset();
+ cached = QString();
+ }
+ return 0;
+}
+
+int LogEvent::sort(EventSorter& s)
+{
+ sorter = &s;
+ cache.sort();
+ sorter = 0x0;
+ return 0;
+}
+
+int LogEvent::scan(const QString& path, EventLister&l)
+{
+ int i = cache.add.size();
+ while (i--) {
+ if (cache.add[i]->path_.indexOf(path) != -1)
+ l.next(cache.add[i]);
+ }
+ return 0;
+}
+
+int LogEvent::find(const QString&path) { return 0; }
+
+/********************************/
+
+class StatusEvent: public LogEvent {
+ QString status_;
+ virtual bool start() { return status_ == "submitted"; }
+ virtual bool end() { return status_ == "complete"; }
+ virtual const QString& text(QString&) { return path_;}
+ virtual QString status() { return status_; }
+public:
+ StatusEvent(const QString&path, const QDateTime& time, const QString& status)
+ : LogEvent(path, time)
+ , status_ (status)
+ {}
+};
+
+class EventEvent: public LogEvent {
+ bool set_;
+public:
+ virtual QString status() { return "event"; }
+ EventEvent(const QString&path, const QDateTime& time, bool b)
+ : LogEvent(path, time)
+ , set_ (b)
+ {}
+};
+
+class MeterEvent: public LogEvent {
+ int step_;
+public:
+ virtual QString status() { return "meter"; }
+ MeterEvent(const QString&path, const QDateTime& time, int step)
+ : LogEvent(path, time)
+ , step_ (step)
+ {}
+};
+
+/********************************/
+QString logs = "/media/map/boxster/map/ecm/201502/ect/tmp/map/work/p4/metapps/suites/o/def";
+QString logf1 = logs + "/timeline/ibis.900130.log";
+QString logf2 = logs + "/tkinter/logs/vsms1.ecf.3.log";
+typedef QMap<QString, QVector<LogEvent*> > log_map_type;
+log_map_type log_map;
+QDateTime dt_min(QDateTime::fromString("00:00:00 1.1.2101", "hh:mm:ss d.M.yyyy"));
+QDateTime dt_max(QDateTime::fromString("00:00:00 1.1.2001", "hh:mm:ss d.M.yyyy"));
+
+void reader(QString filename,
+ bool onlyTask=true,
+ int max=-1,
+ int debug=0 ) {
+
+ QFile inputFile(filename);
+ log_map_type& rc = log_map;
+
+ if (inputFile.open(QIODevice::ReadOnly)) {
+ QTextStream in(&inputFile);
+ QTextStream out (stdout);
+ int num = 0;
+ QString pkind (""), ppath("");
+ while (!in.atEnd()) {
+ QString line = in.readLine();
+ int pos (line.indexOf("LOG:")),
+ sql (line.indexOf("[")),
+ sqr (line.indexOf("]"));
+ if (pos == -1 || sqr == -1) continue;
+ QString time(line.left(sqr).mid(sql+1));
+ QString log(line.mid(sqr+1).trimmed());
+ QDateTime dt(QDateTime::fromString(time, "hh:mm:ss d.M.yyyy"));
+ if (dt < dt_min) dt_min = dt;
+ if (dt > dt_max) dt_max = dt;
+
+ int ikd(log.indexOf(":")),
+ isp(log.indexOf(" "));
+ QString kind (log.left(ikd)),
+ path(log.mid(ikd+1).trimmed());
+
+ if (onlyTask && ppath.indexOf(path) == 0) continue;
+ if (kind=="meter")
+ rc[path].append(new MeterEvent(path, dt, 1));
+ else if (kind=="event")
+ rc[path].append(new EventEvent(path, dt, 1));
+ else
+ rc[path].append(new StatusEvent(path, dt, kind));
+
+ pkind = kind;
+ ppath = path.split(" ")[0];
+ if (debug) {
+ out << time << " " << dt.toString()
+ // << endl << log << endl << line << endl;
+ << " " << kind << " " << path.trimmed() << endl;
+ if (max > 0 && num > max) break;
+ ++num;
+ }
+ }
+ inputFile.close();
+ }
+ // return rc;
+}
+
+#ifdef MAIN_LOG
+/*
+make VERBOSE=1
+*/
+#include <QApplication>
+#include "TimeItemWidget.hpp"
+
+int drawScene(TimeItemWidget* qwd)
+{
+ QGraphicsScene* scene = new QGraphicsScene();
+ QMap<QString, QColor> colors;
+ colors.insert("submitted", Qt::blue);
+ colors["complete"] = Qt::yellow;
+ colors["aborted"] = Qt::red;
+ colors["active"] = Qt::green;
+ colors["meter"] = Qt::blue;
+ colors["event"] = Qt::black;
+ colors["unknown"] = Qt::gray;
+ // colors["unknown"] = Qt::grey;
+
+ qwd->view()->setScene(scene);
+ if (1) { //Populate the scene
+ for(int x = 0; x < 8400; x = x + 25) {
+ for(int y = 0; y < 100; y = y + 25) {
+ if(x % 100 == 0 && y % 100 == 0) {
+ scene->addRect(x, y, 2, 2);
+ QString pointString;
+ QTextStream stream(&pointString);
+ if (0) stream << "(" << x << "," << y << ")";
+ QGraphicsTextItem* item = scene->addText(pointString);
+ item->setPos(x, y);
+ } else {
+ scene->addRect(x, y, 1, 1);
+ }
+ }
+ }
+ }
+ /* ./work/sms/qt4/qt-book/chap08/diagram
+ /mnt/wdir/map/work/qt-5-4-1 */
+ int num = 0, inc = 10;
+ log_map_type::const_iterator mit = log_map.begin();
+ QVector<LogEvent*>::const_iterator lit;
+ while (mit != log_map.end()) {
+ num += inc;
+ QString line;
+ QTextStream stream(&line);
+ stream << mit.key();
+ QGraphicsTextItem* item = scene->addText(line);
+ item->setPos(-100, num);
+ // scene->addText(mit.key());
+ lit = mit.value().begin();
+ while (lit != mit.value().end()) {
+ int yy = ((*lit)->time().toTime_t() -
+ // kSmallDate.toTime_t()) / 10;
+ dt_min.toTime_t()) / 10;
+
+ /* QPixmap pm(5, 5);
+ pm.fill();
+ QPainter p(&pm);
+ p.setRenderHint(QPainter::Antialiasing, true);
+ p.setPen(colors[(*lit)->status()]);
+ p.setBrush(QBrush(colors[(*lit)->status()])); */
+ // QGraphicsEllipseItem *ell = p.drawEllipse(yy, num, 5, 5);
+
+ stream << yy << "\n";
+ QGraphicsEllipseItem *ell = scene->addEllipse(yy, num, 10, 10,
+ QPen(colors[(*lit)->status()]),
+ QBrush(colors[(*lit)->status()]));
+ ell->setPos(yy, num);
+
+ ++lit;
+ }
+ ++mit;
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ // Q_INIT_RESOURCE(images);
+ reader(logf1, 1, 500, 1);
+ reader(logf2, 1, 500, 1);
+
+ QApplication app(argc, argv);
+ TimeItemWidget window(0x0);
+ window.setWindowTitle("TimeLine");
+ window.show();
+ log_map.clear();
+ reader(logf2, 1);
+ drawScene(&window);
+ return app.exec();
+}
+#endif
diff --git a/Viewer/src/LogEvent.hpp b/Viewer/src/LogEvent.hpp
new file mode 100644
index 0000000..580d78e
--- /dev/null
+++ b/Viewer/src/LogEvent.hpp
@@ -0,0 +1,61 @@
+#ifndef LogEvent_H
+#define LogEvent_H
+
+class LogEvent;
+class EventLister {
+public:
+ virtual void next(LogEvent*) = 0;
+};
+
+
+class EventSorter {
+public:
+ virtual int compare(LogEvent*, LogEvent*) = 0;
+};
+
+// inline bool operator<(const DateTime&
+const QDateTime kSmallDate(QDate(1900, 1, 1), QTime());
+const QDateTime kLargeDate(QDate(2100, 1, 1), QTime());
+
+class counted
+{
+public:
+ counted();
+ void attach();
+ void detach();
+protected:
+ ~counted();
+private:
+ counted(const counted&);
+ counted& operator=(const counted&);
+ int count_;
+};
+
+class LogEvent: public counted // , public observer
+{
+public:
+ LogEvent(const QString&, const QDateTime&);
+ const QDateTime& time() const { return time_; }
+ virtual bool start() { return false; }
+ virtual bool end() { return false; }
+ virtual const QString& get_node() { return path_; }
+ virtual QString status() { return "none"; }
+
+ static int load(bool reset);
+ static int scan(const QString&, EventLister&);
+ static int sort(EventSorter&);
+ static int find(const QString&);
+ static int compare(const LogEvent*, const LogEvent*);
+ virtual ~LogEvent();
+
+protected:
+ QDateTime time_;
+ QString path_;
+private:
+ LogEvent(const LogEvent&);
+ LogEvent& operator=(const LogEvent&);
+ // notification
+ // adoption
+ // gone
+};
+#endif
diff --git a/Viewer/src/LogModel.cpp b/Viewer/src/LogModel.cpp
new file mode 100644
index 0000000..fae2ed9
--- /dev/null
+++ b/Viewer/src/LogModel.cpp
@@ -0,0 +1,361 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "LogModel.hpp"
+
+#include <QDebug>
+#include <QStringList>
+
+#include "IconProvider.hpp"
+
+LogModelLine::LogModelLine(QString s) : type_(NoType)
+{
+ QString s1=s.section("]",0,0);
+ date_=s1.section("[",1);
+ entry_=s.section("]",1);
+
+ QString t=s1.section("[",0);
+
+ if(t.contains("MSG:"))
+ {
+ type_=MessageType;
+ }
+ else if(t.contains("LOG:"))
+ {
+ type_=LogType;
+ }
+ else if(t.contains("ERR:"))
+ {
+ type_=ErrorType;
+ }
+ else if(t.contains("WAR:"))
+ {
+ type_=WarningType;
+ }
+ else if(t.contains("DBG:"))
+ {
+ type_=DebugType;
+ }
+}
+
+
+LogModel::LogModel(QObject *parent) :
+ QAbstractItemModel(parent)
+{
+ IconProvider::add(":/viewer/log_error.svg","log_error");
+ IconProvider::add(":/viewer/log_info.svg","log_info");
+ IconProvider::add(":/viewer/log_warning.svg","log_warning");
+}
+
+LogModel::~LogModel()
+{
+}
+
+void LogModel::setData(const std::string& data)
+{
+ beginResetModel();
+
+ data_.clear();
+
+ QString in=QString::fromStdString(data);
+ Q_FOREACH(QString s,in.split("\n"))
+ {
+ if(!s.simplified().isEmpty())
+ data_ << LogModelLine(s);
+ }
+
+ endResetModel();
+}
+
+void LogModel::setData(const std::vector<std::string>& data)
+{
+ beginResetModel();
+
+ data_.clear();
+
+ for(std::vector<std::string>::const_iterator it=data.begin(); it != data.end(); it++)
+ {
+ QString s=QString::fromStdString(*it);
+ if(!s.simplified().isEmpty())
+ {
+ data_ << LogModelLine(s);
+ }
+ }
+ endResetModel();
+}
+
+void LogModel::appendData(const std::vector<std::string>& data)
+{
+ int num=0;
+
+ for(std::vector<std::string>::const_iterator it=data.begin(); it != data.end(); it++)
+ {
+ QString s=QString::fromStdString(*it);
+ if(!s.simplified().isEmpty())
+ {
+ num++;
+ }
+ }
+
+ if(num >0)
+ {
+ beginInsertRows(QModelIndex(),rowCount(),rowCount()+num-1);
+
+ for(std::vector<std::string>::const_iterator it=data.begin(); it != data.end(); it++)
+ {
+ QString s=QString::fromStdString(*it);
+ if(!s.simplified().isEmpty())
+ {
+ data_ << LogModelLine(s);
+ }
+ }
+
+ endInsertRows();
+ }
+}
+
+
+
+void LogModel::clearData()
+{
+ beginResetModel();
+ data_.clear();
+ endResetModel();
+}
+
+bool LogModel::hasData() const
+{
+ return !data_.empty();
+}
+
+int LogModel::columnCount( const QModelIndex& /*parent */ ) const
+{
+ return 3;
+}
+
+int LogModel::rowCount( const QModelIndex& parent) const
+{
+ if(!hasData())
+ return 0;
+
+ //Parent is the root:
+ if(!parent.isValid())
+ {
+ return data_.size();
+ }
+
+ return 0;
+}
+
+Qt::ItemFlags LogModel::flags ( const QModelIndex & index) const
+{
+ return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
+}
+
+QVariant LogModel::data( const QModelIndex& index, int role ) const
+{
+ if(!index.isValid() || !hasData())
+ {
+ return QVariant();
+ }
+ int row=index.row();
+ if(row < 0 || row >= data_.size())
+ return QVariant();
+
+
+ if(role == Qt::DisplayRole)
+ {
+ switch(index.column())
+ {
+ case 0:
+ {
+ switch(data_.at(row).type_)
+ {
+ case LogModelLine::MessageType:
+ return "MSG ";
+ case LogModelLine::LogType:
+ return "LOG ";
+ case LogModelLine::ErrorType:
+ return "ERR ";
+ case LogModelLine::WarningType:
+ return "WAR ";
+ case LogModelLine::DebugType:
+ return "DBG ";
+ default:
+ return QVariant();
+ }
+ }
+ break;
+ case 1:
+ return data_.at(row).date_;
+ break;
+ case 2:
+ return data_.at(row).entry_;
+ break;
+ default:
+ break;
+ }
+ }
+
+ else if(role == Qt::DecorationRole)
+ {
+ if(index.column() ==0)
+ {
+ switch(data_.at(row).type_)
+ {
+ case LogModelLine::MessageType:
+ return IconProvider::pixmap("log_info",12);
+ case LogModelLine::LogType:
+ return IconProvider::pixmap("log_info",12);
+ case LogModelLine::ErrorType:
+ return IconProvider::pixmap("log_error",12);
+ case LogModelLine::WarningType:
+ return IconProvider::pixmap("log_warning",12);
+ default:
+ return QVariant();
+ }
+ }
+ }
+/*
+ else if(role == Qt::BackgroundRole)
+ {
+ if(data_.at(row).type_ == LogModelLine::ErrorType)
+ {
+ return QColor(223,152,152);
+ }
+ }
+*/
+
+ else if(role == Qt::FontRole)
+ {
+ QFont f;
+
+ /*if(data_.at(row).type_ == LogModelLine::ErrorType)
+ {
+ f.setBold(true);
+ }*/
+
+ return f;
+ }
+ /*else if(role == Qt::SizeHintRole)
+ {
+ QFont f;
+ f.setBold(true);
+ QFontMetrics fm(f);
+ return fm.height()+10;
+ }*/
+
+
+ return QVariant();
+}
+
+QVariant LogModel::headerData( const int section, const Qt::Orientation orient , const int role ) const
+{
+ if ( orient != Qt::Horizontal || (role != Qt::DisplayRole && role != Qt::ToolTipRole))
+ return QAbstractItemModel::headerData( section, orient, role );
+
+ if(role == Qt::DisplayRole)
+ {
+ switch ( section )
+ {
+ case 0: return tr("Type");
+ case 1: return tr("Date");
+ case 2: return tr("Entry");
+ default: return QVariant();
+ }
+ }
+ else if(role== Qt::ToolTipRole)
+ {
+ switch ( section )
+ {
+ case 0: return tr("Type");
+ case 1: return tr("Date");
+ case 2: return tr("Entry");
+ default: return QVariant();
+ }
+ }
+ return QVariant();
+}
+
+QModelIndex LogModel::index( int row, int column, const QModelIndex & parent ) const
+{
+ if(!hasData() || row < 0 || column < 0)
+ {
+ return QModelIndex();
+ }
+
+ //When parent is the root this index refers to a node or server
+ if(!parent.isValid())
+ {
+ return createIndex(row,column);
+ }
+
+ return QModelIndex();
+
+}
+
+QModelIndex LogModel::parent(const QModelIndex &child) const
+{
+ return QModelIndex();
+}
+
+QModelIndex LogModel::lastIndex() const
+{
+ return index(rowCount()-1,0);
+}
+
+//========================================================
+//
+// LogDelegate
+//
+//========================================================
+
+LogDelegate::LogDelegate(QWidget *parent) : QStyledItemDelegate(parent)
+{
+
+}
+
+void LogDelegate::paint(QPainter *painter,const QStyleOptionViewItem &option,
+ const QModelIndex& index) const
+{
+ QStyledItemDelegate::paint(painter,option,index);
+
+ /*if(index.column()==11)
+ {
+ QStyleOptionViewItemV4 vopt(option);
+ initStyleOption(&vopt, index);
+
+ const QStyle *style = vopt.widget ? vopt.widget->style() : QApplication::style();
+ const QWidget* widget = vopt.widget;
+
+ QString text=index.data(Qt::DisplayRole).toString();
+ QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &vopt, widget);
+ if(text == "ERR")
+ {
+ QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &vopt, widget);
+ }
+
+ painter->fillRect(textRect,Qt::red);
+ painter->drawText(textRect,Qt::AlignLeft | Qt::AlignVCenter,text);
+ }
+ else
+ {
+ QStyledItemDelegate::paint(painter,option,index);
+ }*/
+}
+
+
+QSize LogDelegate::sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index ) const
+{
+ QSize size=QStyledItemDelegate::sizeHint(option,index);
+
+ size+=QSize(0,2);
+
+ return size;
+}
diff --git a/Viewer/src/LogModel.hpp b/Viewer/src/LogModel.hpp
new file mode 100644
index 0000000..19d4776
--- /dev/null
+++ b/Viewer/src/LogModel.hpp
@@ -0,0 +1,72 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef LOGMODEL_H
+#define LOGMODEL_H
+
+#include <QAbstractItemModel>
+#include <QSortFilterProxyModel>
+#include <QStyledItemDelegate>
+
+#include <vector>
+
+class LogModelLine
+{
+public:
+ explicit LogModelLine(QString);
+
+ enum Type {NoType,MessageType,ErrorType,LogType,WarningType,DebugType};
+
+ QString date_;
+ QString entry_;
+ Type type_;
+};
+
+
+class LogModel : public QAbstractItemModel
+{
+public:
+ explicit LogModel(QObject *parent=0);
+ ~LogModel();
+
+ int columnCount (const QModelIndex& parent = QModelIndex() ) const;
+ int rowCount (const QModelIndex& parent = QModelIndex() ) const;
+
+ Qt::ItemFlags flags ( const QModelIndex & index) const;
+ QVariant data (const QModelIndex& , int role = Qt::DisplayRole ) const;
+ QVariant headerData(int,Qt::Orientation,int role = Qt::DisplayRole ) const;
+
+ QModelIndex index (int, int, const QModelIndex& parent = QModelIndex() ) const;
+ QModelIndex parent (const QModelIndex & ) const;
+
+ void setData(const std::string&);
+ void setData(const std::vector<std::string>&);
+ void appendData(const std::vector<std::string>&);
+ bool hasData() const;
+ void clearData();
+ QModelIndex lastIndex() const;
+
+protected:
+ QList<LogModelLine> data_;
+};
+
+class LogDelegate : public QStyledItemDelegate
+{
+public:
+ explicit LogDelegate(QWidget *parent=0);
+ void paint(QPainter *painter,const QStyleOptionViewItem &option,
+ const QModelIndex& index) const;
+
+ QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index ) const;
+
+};
+
+
+
+#endif
diff --git a/Viewer/src/LogProvider.cpp b/Viewer/src/LogProvider.cpp
new file mode 100644
index 0000000..d984f61
--- /dev/null
+++ b/Viewer/src/LogProvider.cpp
@@ -0,0 +1,247 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "LogProvider.hpp"
+
+#include "FileWatcher.hpp"
+#include "LogServer.hpp"
+#include "VNode.hpp"
+#include "VReply.hpp"
+#include "ServerHandler.hpp"
+
+#include <QDebug>
+
+#include <fstream>
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/algorithm/string/predicate.hpp>
+
+LogProvider::LogProvider(InfoPresenter* owner,QObject* parent) :
+ QObject(parent),
+ InfoProvider(owner,VTask::HistoryTask),
+ fileWatcher_(0)
+{
+ //NOTE: fileWatcher_'s parent (if it exits) will be "this", so
+ //fileWatcher_ will be automatically deleted in the destructor!
+}
+
+void LogProvider::clear()
+{
+ stopWatchFile();
+ InfoProvider::clear();
+}
+
+void LogProvider::setAutoUpdate(bool autoUpdate)
+{
+ InfoProvider::setAutoUpdate(autoUpdate);
+
+ if(active_)
+ {
+ if(!autoUpdate_)
+ {
+ stopWatchFile();
+ }
+ else
+ {
+ if(!inAutoUpdate_)
+ fetchFile();
+ }
+ }
+ else
+ {
+ stopWatchFile();
+ }
+}
+
+void LogProvider::visit(VInfoServer* info)
+{
+ fetchFile();
+}
+
+void LogProvider::fetchFile()
+{
+ if(!active_)
+ return;
+
+ stopWatchFile();
+
+ //Reset the reply
+ reply_->reset();
+
+ if(!info_)
+ {
+ owner_->infoFailed(reply_);
+ return;
+ }
+
+ ServerHandler* server=info_->server();
+
+ //Get the filename
+ std::string fileName=server->vRoot()->genVariable("ECF_LOG");
+
+ fetchFile(server,fileName);
+}
+
+void LogProvider::fetchFile(ServerHandler *server,const std::string& fileName)
+{
+ if(!server)
+ {
+ owner_->infoFailed(reply_);
+ return;
+ }
+
+ //Set the filename in reply
+ reply_->fileName(fileName);
+
+ //No filename is available
+ if(fileName.empty())
+ {
+ reply_->setErrorText("Variable ECF_LOG is not defined!");
+ owner_->infoFailed(reply_);
+ }
+
+ //First we try to read the file directly from the disk
+ //if(server->readFromDisk())
+ {
+ size_t size;
+ std::string err_msg;
+ reply_->text(readLastLines(fileName,100,size,err_msg));
+ if(err_msg.empty())
+ {
+ reply_->fileReadMode(VReply::LocalReadMode);
+
+ if(autoUpdate_)
+ inAutoUpdate_=true;
+
+ owner_->infoReady(reply_);
+
+ //Try to track the changes in the log file
+ watchFile(fileName,size);
+
+ return;
+ }
+ }
+
+ //Finally we try the server
+ reply_->fileReadMode(VReply::ServerReadMode);
+
+ //Define a task for getting the info from the server.
+ task_=VTask::create(taskType_,server->vRoot(),this);
+
+ //Run the task in the server. When it finish taskFinished() is called. The text returned
+ //in the reply will be prepended to the string we generated above.
+ server->run(task_);
+ return;
+
+ //If we are we could not get the file
+ owner_->infoFailed(reply_);
+}
+
+void LogProvider::watchFile(const std::string& fileName,size_t offset)
+{
+ if(autoUpdate_)
+ {
+ assert(fileWatcher_ == 0);
+ fileWatcher_=new FileWatcher(fileName,offset,this);
+
+ connect(fileWatcher_,SIGNAL(linesAppended(QStringList)),
+ this,SLOT(slotLinesAppend(QStringList)));
+
+ inAutoUpdate_=true;
+ }
+}
+
+void LogProvider::stopWatchFile()
+{
+ if(fileWatcher_)
+ {
+ delete fileWatcher_;
+ fileWatcher_=0;
+ }
+
+ inAutoUpdate_=false;
+}
+
+void LogProvider::slotLinesAppend(QStringList lst)
+{
+ //Check if the task is already running
+ if(task_)
+ {
+ task_->status(VTask::CANCELLED);
+ task_.reset();
+ }
+
+ //Reset the reply
+ reply_->reset();
+
+ if(!info_)
+ {
+ owner_->infoFailed(reply_);
+ }
+
+ //qDebug() << "LogProvider::slotLinesAppend()" << lst;
+
+ std::vector<std::string> vec;
+ Q_FOREACH(QString s,lst)
+ {
+ vec.push_back(s.toStdString());
+ }
+
+ reply_->setTextVec(vec);
+ owner_->infoAppended(reply_);
+}
+
+std::string LogProvider::readLastLines(const std::string& filename,int last_n_lines,size_t& size,std::string& error_msg)
+{
+ if ( last_n_lines <= 0 ) return std::string();
+
+ std::ifstream source( filename.c_str(), std::ios_base::in );
+ if (!source) {
+ error_msg = "File::get_last_n_lines: Could not open file " + filename;
+ return std::string();
+ }
+
+ size_t const granularity = 100 * last_n_lines;
+ source.seekg( 0, std::ios_base::end );
+ size = static_cast<size_t>( source.tellg() );
+ std::vector<char> buffer;
+ int newlineCount = 0;
+ while ( source
+ && buffer.size() != size
+ && newlineCount < last_n_lines ) {
+ buffer.resize( std::min( buffer.size() + granularity, size ) );
+ source.seekg( -static_cast<std::streamoff>( buffer.size() ),
+ std::ios_base::end );
+#if defined(HPUX) || defined(_AIX)
+ source.read( &(buffer.front()), buffer.size() );
+#else
+ source.read( buffer.data(), buffer.size() );
+#endif
+ newlineCount = std::count( buffer.begin(), buffer.end(), '\n');
+ }
+
+ std::vector<char>::iterator start = buffer.begin();
+ while ( newlineCount > last_n_lines ) {
+ start = std::find( start, buffer.end(), '\n' ) + 1;
+ -- newlineCount;
+ }
+
+ //std::vector<char>::iterator end = remove( start, buffer.end(), '\r' ); // for windows
+ return std::string( start, buffer.end() );
+}
+
+
+
+
+
+
+
+
diff --git a/Viewer/src/LogProvider.hpp b/Viewer/src/LogProvider.hpp
new file mode 100644
index 0000000..9a79f5a
--- /dev/null
+++ b/Viewer/src/LogProvider.hpp
@@ -0,0 +1,51 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+
+#ifndef VIEWER_SRC_LOGPROVIDER_HPP_
+#define VIEWER_SRC_LOGPROVIDER_HPP_
+
+#include <QObject>
+#include <QStringList>
+
+#include "VDir.hpp"
+#include "VInfo.hpp"
+#include "InfoProvider.hpp"
+#include "VTask.hpp"
+#include "VTaskObserver.hpp"
+
+class FileWatcher;
+
+class LogProvider : public QObject, public InfoProvider
+{
+ Q_OBJECT
+
+public:
+ LogProvider(InfoPresenter* owner,QObject* parent=0);
+
+ void visit(VInfoServer*);
+ void clear();
+ void setAutoUpdate(bool);
+
+public Q_SLOTS:
+ void slotLinesAppend(QStringList);
+
+private:
+ void fetchFile();
+ void fetchFile(ServerHandler *server,const std::string& fileName);
+ void watchFile(const std::string&,size_t);
+ void stopWatchFile();
+ std::string readLastLines(const std::string& filename,int last_n_lines,size_t& size,std::string& error_msg);
+
+ FileWatcher* fileWatcher_;
+
+};
+
+#endif
diff --git a/Viewer/src/LogServer.cpp b/Viewer/src/LogServer.cpp
new file mode 100644
index 0000000..58e5e48
--- /dev/null
+++ b/Viewer/src/LogServer.cpp
@@ -0,0 +1,252 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "LogServer.hpp"
+
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include "setjmp.h"
+
+#ifdef AIX
+#include <memory.h>
+#endif
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+
+#define FAIL(a) do { perror(a); exit(1); } while(0)
+
+LogServer::LogServer(std::string host,std::string cport) :
+ soc_(-1),
+ host_(host),
+ port_(cport)
+{
+ struct hostent *ht = gethostbyname( host.c_str() );
+
+ if (ht == NULL)
+ {
+ soc_ = -1;
+ return;
+ }
+ connect(host,!cport.empty() ? atoi(cport.c_str()) : 19999);
+}
+
+static jmp_buf env;
+/* static void (*old_alarm)(int); */
+
+static void catch_alarm(int)
+{
+ printf("got alarm\n");
+ /* longjmp(env,1); */
+}
+
+void LogServer::connect(std::string host,int port)
+{
+ //typedef unsigned long addr_type;
+ typedef in_addr_t addr_type;
+
+ //ddr_type none = (addr_type)-1;
+ addr_type addr;
+
+ struct sockaddr_in s_in;
+ struct hostent *him;
+
+ soc_ = socket(AF_INET, SOCK_STREAM, 0);
+ if(soc_ < 0)
+ {
+ //gui::syserr("Cannot create socket");
+ return;
+ }
+
+ bzero(&s_in,sizeof(s_in));
+
+ s_in.sin_port = htons(port);
+ s_in.sin_family = AF_INET;
+ addr = inet_addr(host.c_str());
+ s_in.sin_addr.s_addr = addr;
+
+#ifdef SVR4
+ if(addr == (in_addr_t) 0xffffffff)
+#else
+ if(addr == INADDR_NONE)
+#endif
+ {
+ if ((him=gethostbyname(host.c_str()))==NULL)
+ {
+ //gui::error("Unknown Host %s",host.c_str());
+ return;
+ }
+ s_in.sin_family = him->h_addrtype;
+ bcopy(him->h_addr_list[0],&s_in.sin_addr,him->h_length);
+ }
+
+ char* timeout = getenv ("ECFLOWVIEW_LOGTIMEOUT");
+ int time_out = timeout ? atoi(timeout) : 3;
+
+ struct sigaction sa = { { 0, }, };
+ struct sigaction old;
+ sa.sa_handler = catch_alarm;
+ sigemptyset(&sa.sa_mask);
+
+ if(sigaction(SIGALRM, &sa, &old))
+ perror("sigaction");
+
+ ::alarm(time_out);
+ perror("alarm");
+
+ if(setjmp(env) == 0)
+ {
+ printf("connect %s\n",host.c_str());
+ if(::connect(soc_,(struct sockaddr*)&s_in,sizeof(s_in)) < 0)
+ {
+ perror("connect");
+ close(soc_);
+ soc_ = -1;
+ }
+ }
+ else
+ {
+ printf("cleanup up\n");
+ close(soc_);
+ soc_ = -1;
+ }
+ ::alarm(0);
+ sigaction(SIGALRM, &old, &sa);
+}
+
+LogServer::~LogServer()
+{
+ close(soc_);
+}
+
+VFile_ptr LogServer::getFile(std::string name)
+{
+ VFile_ptr empty;
+
+ if(soc_ < 0)
+ return empty;
+
+ write(soc_,"get ",4);
+ write(soc_,name.c_str(),name.size());
+ write(soc_,"\n",1);
+
+ const int size = 64*1024;
+ char buf[size];
+ unsigned int len = 0;
+ int total = 0;
+
+ VFile_ptr out(VFile::create(false));
+ FILE *f = fopen(out->path().c_str(),"w");
+
+ printf("outFile: %s\n",out->path().c_str());
+
+
+ if(!f)
+ {
+ char buf_loc[2048];
+ sprintf(buf_loc,"Cannot create %s",out->path().c_str());
+ //gui::syserr(buf);
+ return empty;
+ }
+
+ while( (len = read(soc_,buf,size)) > 0)
+ {
+ if(fwrite(buf,1,len,f) != len)
+ {
+ char buf_loc[2048];
+ sprintf(buf_loc,"Write error on %s",out->path().c_str());
+ //gui::syserr(buf);
+ fclose(f);
+ return empty;
+ }
+ total += len;
+ }
+
+ //fwrite(buf,1,size,f);
+
+ if(fclose(f))
+ {
+ char buf_loc[2048];
+ sprintf(buf_loc,"Write error on %s",out->path().c_str());
+ //gui::syserr(buf);
+ return empty;
+ }
+
+ if(total)
+ return out;
+
+ return empty;
+}
+
+VDir_ptr LogServer::getDir(const char* name)
+{
+ VDir_ptr empty;
+
+ if(soc_ < 0)
+ return empty;
+
+ write(soc_,"list ",5);
+ write(soc_,name,strlen(name));
+ write(soc_,"\n",1);
+
+ FILE* f = fdopen(soc_,"r");
+
+ char buf[2048];
+
+ //We suppose name is a file name!
+ //Create the resulting directory object. We might need to
+ //adjust its path later.
+ boost::filesystem::path fp(name);
+ std::string dirName=fp.parent_path().string();
+ VDir_ptr dir(new VDir(dirName));
+
+ //indicates the source of the files
+ dir->where(host_ + "@" + port_);
+
+ while(fgets(buf,sizeof(buf),f))
+ {
+ int mode,uid,gid;
+ unsigned int size;
+ unsigned int atime,mtime,ctime;
+ char name[1024];
+
+ sscanf(buf,"%d %d %d %u %u %u %u %s",
+ &mode,&uid,&gid,
+ &size,
+ &atime,&mtime,&ctime,
+ name);
+
+ boost::filesystem::path p(name);
+ std::string fileDirName=fp.parent_path().string();
+ std::string fileName=p.leaf().string();
+
+ //Adjust the path in the dir
+ if(fileDirName != dirName)
+ {
+ dir->path(fileDirName,false);
+ }
+
+ dir->addItem(fileName,size,mtime);
+ }
+
+ return dir;
+}
diff --git a/Viewer/src/LogServer.hpp b/Viewer/src/LogServer.hpp
new file mode 100644
index 0000000..086b2ea
--- /dev/null
+++ b/Viewer/src/LogServer.hpp
@@ -0,0 +1,43 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef LOGSERVER_H
+#define LOGSERVER_H
+
+#include "VFile.hpp"
+#include "VDir.hpp"
+
+class LogServer;
+typedef boost::shared_ptr<LogServer> LogServer_ptr;
+
+class LogServer
+{
+
+public:
+ LogServer(std::string host,std::string port);
+ ~LogServer();
+
+ const std::string host() const {return host_;}
+ const std::string port() const {return port_;}
+
+ VFile_ptr getFile(std::string name);
+ VDir_ptr getDir(const char* name);
+ bool ok() const { return soc_ >= 0; }
+
+private:
+ LogServer(const LogServer&);
+ LogServer& operator=(const LogServer&);
+ void connect(std::string,int);
+
+ int soc_;
+ std::string host_;
+ std::string port_;
+};
+
+#endif
diff --git a/Viewer/src/MainWindow.cpp b/Viewer/src/MainWindow.cpp
new file mode 100644
index 0000000..dbda78a
--- /dev/null
+++ b/Viewer/src/MainWindow.cpp
@@ -0,0 +1,753 @@
+//============================================================================
+// Copyright 2015 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include <QActionGroup>
+#include <QApplication>
+#include <QCloseEvent>
+#include <QComboBox>
+#include <QDialog>
+#include <QDockWidget>
+#include <QLabel>
+#include <QMessageBox>
+#include <QPixmap>
+#include <QSplitter>
+#include <QToolBar>
+#include <QVBoxLayout>
+
+#include <QDebug>
+
+#include "MainWindow.hpp"
+
+#include "AboutDialog.hpp"
+#include "ChangeNotifyWidget.hpp"
+#include "FilterWidget.hpp"
+#include "InfoPanel.hpp"
+#include "InfoPanelHandler.hpp"
+#include "MenuConfigDialog.hpp"
+#include "NodePathWidget.hpp"
+#include "NodePanel.hpp"
+#include "PropertyDialog.hpp"
+#include "ServerHandler.hpp"
+#include "ServerListDialog.hpp"
+#include "SessionHandler.hpp"
+#include "SaveSessionAsDialog.hpp"
+#include "UserMessage.hpp"
+#include "VConfig.hpp"
+#include "VSettings.hpp"
+
+#include <boost/lexical_cast.hpp>
+#include <boost/property_tree/json_parser.hpp>
+
+bool MainWindow::quitStarted_=false;
+QList<MainWindow*> MainWindow::windows_;
+int MainWindow::maxWindowNum_=25;
+
+MainWindow::MainWindow(QStringList idLst,QWidget *parent) : QMainWindow(parent)
+{
+ setupUi(this);
+
+ setAttribute(Qt::WA_DeleteOnClose);
+
+ // add the name of the session to the title bar?
+ std::string sessionName = SessionHandler::instance()->current()->name();
+ if (sessionName == "default")
+ sessionName = "";
+ else
+ sessionName = " (session: " + sessionName + ")";
+
+ setWindowTitle(QString::fromStdString(VConfig::instance()->appLongName()) + " - Preview version" + QString::fromStdString(sessionName));
+
+ //Create the main layout
+ QVBoxLayout* layout=new QVBoxLayout();
+ layout->setContentsMargins(0,0,0,0);
+ QWidget *w=new QWidget(this);
+ w->setLayout(layout);
+ setCentralWidget(w);
+
+ //Servers menu menu
+ serverFilterMenu_=new ServerFilterMenu(menuServer);
+
+ //Create a node panel
+ nodePanel_=new NodePanel(this);
+ layout->addWidget(nodePanel_);
+
+ connect(nodePanel_,SIGNAL(currentWidgetChanged()),
+ this,SLOT(slotCurrentChangedInPanel()));
+
+ connect(nodePanel_,SIGNAL(selectionChanged(VInfo_ptr)),
+ this,SLOT(slotSelectionChanged(VInfo_ptr)));
+
+ connect(nodePanel_,SIGNAL(contentsChanged()),
+ this,SLOT(slotContentsChanged()));
+
+ //Add temporary preview label
+ QLabel *label=new QLabel(" This is a preview version and has not been verified for operational use! ",this);
+ label->setAutoFillBackground(true);
+ label->setProperty("previewLabel","1");
+
+ QLabel *label1=new QLabel(" ",this);
+
+ viewToolBar->addWidget(label1);
+ viewToolBar->addWidget(label);
+
+ QWidget* spacer = new QWidget();
+ spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ viewToolBar->addWidget(spacer);
+
+ //QToolBar* ipToolBar=new QToolBar(this);
+ addInfoPanelActions(viewToolBar);
+ //addToolBar(ipToolBar);
+
+ //Actions based on selection
+ actionRefreshSelected->setEnabled(false);
+ actionResetSelected->setEnabled(false);
+
+ //Status bar
+
+ //Add notification widget
+ ChangeNotifyWidget* chw=new ChangeNotifyWidget(this);
+ statusBar()->addPermanentWidget(chw);
+
+
+ //actionSearch->setVisible(false);
+
+}
+
+MainWindow::~MainWindow()
+{
+ qDebug() << "exit";
+ serverFilterMenu_->aboutToDestroy();
+}
+
+void MainWindow::init(MainWindow *win)
+{
+ nodePanel_->init();
+
+ if(!win)
+ return;
+}
+
+void MainWindow::addInfoPanelActions(QToolBar *toolbar)
+{
+ for(std::vector<InfoPanelDef*>::const_iterator it=InfoPanelHandler::instance()->panels().begin();
+ it != InfoPanelHandler::instance()->panels().end(); it++)
+ {
+ if((*it)->show().find("toolbar") != std::string::npos)
+ {
+ QAction *ac=toolbar->addAction(QString::fromStdString((*it)->label()));
+ QPixmap pix(":/viewer/" + QString::fromStdString((*it)->icon()));
+ ac->setIcon(QIcon(pix));
+ ac->setData(QString::fromStdString((*it)->name()));
+ ac->setToolTip(QString::fromStdString((*it)->tooltip()));
+
+ connect(ac,SIGNAL(triggered()),
+ this,SLOT(slotOpenInfoPanel()));
+
+ infoPanelActions_ << ac;
+ }
+ }
+}
+
+//==============================================================
+//
+// File menu
+//
+//==============================================================
+
+void MainWindow::on_actionNewTab_triggered()
+{
+ nodePanel_->slotNewTab();
+}
+
+void MainWindow::on_actionNewWindow_triggered()
+{
+ MainWindow::openWindow("",this);
+}
+
+void MainWindow::on_actionClose_triggered()
+{
+ close();
+}
+
+void MainWindow::on_actionQuit_triggered()
+{
+ MainWindow::aboutToQuit(this);
+}
+
+void MainWindow::on_actionRefresh_triggered()
+{
+ nodePanel_->refreshCurrent();
+}
+
+void MainWindow::on_actionReset_triggered()
+{
+ nodePanel_->resetCurrent();
+}
+
+void MainWindow::on_actionRefreshSelected_triggered()
+{
+ if(selection_ && selection_.get())
+ {
+ if(ServerHandler* s=selection_->server())
+ {
+ s->refresh();
+ }
+ }
+}
+
+void MainWindow::on_actionResetSelected_triggered()
+{
+ if(selection_ && selection_.get())
+ {
+ if(ServerHandler* s=selection_->server())
+ {
+ s->reset();
+ }
+ }
+}
+
+void MainWindow::on_actionPreferences_triggered()
+{
+ PropertyDialog* d=new PropertyDialog; //belongs to the whole app
+
+ connect(d,SIGNAL(configChanged()),
+ this,SLOT(slotConfigChanged()));
+
+ if(d->exec() == QDialog::Accepted)
+ {
+ if(d->isConfigChanged())
+ {
+ configChanged(this);
+ }
+ }
+
+ delete d;
+}
+
+
+void MainWindow::on_actionManageSessions_triggered()
+{
+ QMessageBox::information(0, tr("Manage Sessions"),
+ tr("To manage sessions, please restart ecFlowUI with the -s command-line option"));
+}
+
+void MainWindow::slotConfigChanged()
+{
+ configChanged(this);
+}
+
+void MainWindow::on_actionConfigureNodeMenu_triggered()
+{
+ MenuConfigDialog menuConfigDialog;
+
+ if(menuConfigDialog.exec() == QDialog::Accepted)
+ {
+ }
+}
+
+void MainWindow::on_actionSearch_triggered()
+{
+ //It takes ownership of the dialogue.
+ nodePanel_->addSearchDialog();
+}
+
+void MainWindow::on_actionManageServers_triggered()
+{
+ ServerListDialog dialog(ServerListDialog::SelectionMode,nodePanel_->serverFilter(),this);
+ dialog.exec();
+}
+
+void MainWindow::on_actionAddTreeWidget_triggered()
+{
+ nodePanel_->addToDashboard("tree");
+}
+
+void MainWindow::on_actionAddTableWidget_triggered()
+{
+ nodePanel_->addToDashboard("table");
+}
+
+void MainWindow::on_actionAddInfoPanel_triggered()
+{
+ nodePanel_->addToDashboard("info");
+}
+
+void MainWindow::on_actionShowInInfoPanel_triggered()
+{
+}
+
+void MainWindow::on_actionAbout_triggered()
+{
+ AboutDialog d;
+ d.exec();
+}
+
+void MainWindow::on_actionSaveSessionAs_triggered()
+{
+ SaveSessionAsDialog d;
+ d.exec();
+}
+
+
+void MainWindow::slotCurrentChangedInPanel()
+{
+ slotSelectionChanged(nodePanel_->currentSelection());
+
+ //filterWidget_->reload(nodePanel_->viewFilter());
+
+ serverFilterMenu_->reload(nodePanel_->serverFilter());
+
+ //breadcrumbs_->setPath(folderPanel_->currentFolder());
+ //slotUpdateNavigationActions(folderPanel_->folderNavigation());
+
+ //updateIconSizeActionState();
+ //updateSearchPanel();
+}
+
+void MainWindow::slotSelectionChanged(VInfo_ptr info)
+{
+ selection_=info;
+
+ std::vector<InfoPanelDef*> ids;
+ InfoPanelHandler::instance()->visible(selection_,ids);
+
+ Q_FOREACH(QAction* ac,infoPanelActions_)
+ {
+ ac->setEnabled(false);
+
+ std::string name=ac->data().toString().toStdString();
+
+ for(std::vector<InfoPanelDef*>::const_iterator it=ids.begin(); it != ids.end(); it++)
+ {
+ if((*it)->name() == name)
+ {
+ ac->setEnabled(true);
+ break;
+ }
+ }
+ }
+
+ updateRefreshActions();
+}
+
+void MainWindow::updateRefreshActions()
+{
+ QString serverName;
+ if(selection_ && selection_.get())
+ {
+ if(ServerHandler* s=selection_->server())
+ {
+ serverName=QString::fromStdString(s->name());
+ }
+ }
+
+ bool hasSel=(selection_ && selection_.get());
+ actionRefreshSelected->setEnabled(hasSel);
+ actionResetSelected->setEnabled(hasSel);
+
+ if(serverName.isEmpty())
+ {
+ QString tnew=tr("Refresh <b>selected</b> server<br>") +
+ + "<code>" + actionRefreshSelected->shortcut().toString() + "</code>";
+
+ actionRefreshSelected->setToolTip(tnew);
+ }
+ else
+ {
+ QString t=actionRefreshSelected->toolTip();
+ if(!t.contains(serverName))
+ {
+ QString tnew=tr("Refresh server <b>") + serverName + tr("</b><br>") +
+ + "<code>" + actionRefreshSelected->shortcut().toString() + "</code>";
+
+ actionRefreshSelected->setToolTip(tnew);
+ }
+ }
+}
+
+
+void MainWindow::slotOpenInfoPanel()
+{
+ if(QAction* ac=static_cast<QAction*>(sender()))
+ {
+ std::string name=ac->data().toString().toStdString();
+ nodePanel_->openDialog(selection_,name);
+ }
+}
+
+void MainWindow::reloadContents()
+{
+ nodePanel_->reload();
+}
+
+//Rerender all the views and breadcrumbs
+void MainWindow::rerenderContents()
+{
+ nodePanel_->rerender();
+}
+
+void MainWindow::slotContentsChanged()
+{
+ MainWindow::saveContents(NULL);
+}
+
+bool MainWindow::selectInTreeView(VInfo_ptr info)
+{
+ return nodePanel_->selectInTreeView(info);
+}
+
+//==============================================================
+//
+// Close and quit
+//
+//==============================================================
+
+void MainWindow::closeEvent(QCloseEvent* event)
+{
+ if(MainWindow::aboutToClose(this))
+ {
+ windows_.removeOne(this);
+ event->accept();
+ }
+ else
+ {
+ event->ignore();
+ }
+}
+
+//void MainWindow::slotQuit()
+//{
+// MainWindow::aboutToQuit(this);
+//}
+
+//====================================================
+//
+// Read/write settings
+//
+//====================================================
+
+void MainWindow::writeSettings(VComboSettings *vs)
+{
+ //Qt settings
+ vs->putQs("geometry",saveGeometry());
+ vs->putQs("state",saveState());
+ vs->putQs("minimized",(windowState() & Qt::WindowMinimized)?1:0);
+
+ //Other setting
+ vs->put("infoPanelCount",findChildren<QDockWidget*>().count());
+
+ //Saves nodePanel
+ nodePanel_->writeSettings(vs);
+}
+
+void MainWindow::readSettings(VComboSettings *vs)
+{
+ int cnt=vs->get<int>("infoPanelCount",0);
+ for(int i=0; i < cnt ; i++)
+ {
+ //addInfoPanel();
+ }
+
+ nodePanel_->readSettings(vs);
+
+ if(vs->getQs("minimized").toInt()== 1)
+ {
+ setWindowState(windowState() | Qt::WindowMinimized);
+ }
+
+ if(vs->containsQs("geometry"))
+ restoreGeometry(vs->getQs("geometry").toByteArray());
+
+ if(vs->containsQs("state"))
+ restoreState(vs->getQs("state").toByteArray());
+}
+
+//====================================================
+//
+// Static methods
+//
+//====================================================
+
+MainWindow* MainWindow::makeWindow(VComboSettings* vs)
+{
+ MainWindow* win=MainWindow::makeWindow();
+ win->readSettings(vs);
+ return win;
+}
+
+MainWindow* MainWindow::makeWindow()
+{
+ QStringList idLst;
+ return MainWindow::makeWindow(idLst);
+}
+
+MainWindow* MainWindow::makeWindow(QString id)
+{
+ QStringList idLst;
+ idLst << id;
+ return MainWindow::makeWindow(idLst);
+}
+
+MainWindow* MainWindow::makeWindow(QStringList idLst)
+{
+ MainWindow *win=new MainWindow(idLst);
+ windows_ << win;
+ return win;
+}
+
+void MainWindow::openWindow(QString id,QWidget *fromW)
+{
+ MainWindow* win=MainWindow::makeWindow(id);
+ win->init(findWindow(fromW));
+ win->show();
+}
+
+void MainWindow::openWindow(QStringList idLst,QWidget *fromW)
+{
+ MainWindow* win=MainWindow::makeWindow(idLst);
+ win->init(findWindow(fromW));
+ win->show();
+}
+
+void MainWindow::showWindows()
+{
+ Q_FOREACH(MainWindow *win,windows_)
+ win->show();
+}
+
+void MainWindow::configChanged(MainWindow* owner)
+{
+ Q_FOREACH(MainWindow *win,windows_)
+ win->rerenderContents();
+}
+
+void MainWindow::changeNotifySelectionChanged(VInfo_ptr info)
+{
+ Q_FOREACH(MainWindow *win,windows_)
+ if(win->selectInTreeView(info))
+ return;
+}
+
+//Return true if close is allowed, false otherwise
+bool MainWindow::aboutToClose(MainWindow* win)
+{
+ //If quit has already stared we ignore the close signal from
+ //the main windows.
+ if(quitStarted_)
+ {
+ return false;
+ }
+
+ //Otherwise
+ else
+ {
+ if(windows_.count() > 1)
+ {
+ int tabCnt=win->nodePanel_->count();
+ if(tabCnt > 1)
+ {
+ if(QMessageBox::question(0,tr("Confirm close"),tr("You are about to close <b>") + QString::number(tabCnt) + tr("</b> tabs. Are you sure you want to continue?"),
+ QMessageBox::Yes | QMessageBox::Cancel,QMessageBox::Cancel) == QMessageBox::Cancel)
+ {
+ return false;
+ }
+ }
+ }
+ else if(windows_.count() == 1)
+ {
+ return MainWindow::aboutToQuit(win);
+ }
+ return true;
+ }
+}
+
+bool MainWindow::aboutToQuit(MainWindow* topWin)
+{
+#if 0
+ if(QMessageBox::question(0,tr("Confirm quit"),
+ tr("Do you want to quit ") +
+ QString::fromStdString(VConfig::instance()->appName()) + "?",
+ QMessageBox::Yes | QMessageBox::Cancel,QMessageBox::Cancel) == QMessageBox::Yes)
+ {
+#endif
+ quitStarted_=true;
+
+ //Save browser settings
+ MainWindow::save(topWin);
+
+ //Exit ecFlowView
+ QApplication::quit();
+#if 0
+ }
+#endif
+
+ return false;
+}
+
+void MainWindow::init()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ assert(cs);
+
+ VComboSettings vs(cs->sessionFile(),cs->windowFile());
+
+
+ //Read configuration. If it fails we create an empty window!!
+ if(!vs.read())
+ {
+ MainWindow::makeWindow(&vs);
+ return;
+ }
+
+ //Get number of windows and topWindow index.
+ int cnt=vs.get<int>("windowCount",0);
+ int topWinId=vs.get<int>("topWindowId",-1);
+
+ if(cnt > maxWindowNum_)
+ {
+ cnt=maxWindowNum_;
+ }
+
+ //Create all windows (except the topWindow) in a loop. The
+ //topWindow should be created last so that it should always appear on top.
+ std::string winPattern("window_");
+ for(int i=0; i < cnt; i++)
+ {
+ if(i != topWinId)
+ {
+ std::string id=winPattern + boost::lexical_cast<std::string>(i);
+ if(vs.contains(id))
+ {
+ vs.beginGroup(id);
+ MainWindow::makeWindow(&vs);
+ vs.endGroup();
+ }
+ }
+ }
+
+ //Create the topwindow
+ if(topWinId != -1)
+ {
+ std::string id=winPattern + boost::lexical_cast<std::string>(topWinId);
+ if(vs.contains(id))
+ {
+ vs.beginGroup(id);
+ MainWindow::makeWindow(&vs);
+ vs.endGroup();
+ }
+ }
+
+ //If now windows were created we need to create an empty one
+ if(windows_.count() == 0)
+ {
+ MainWindow::makeWindow(&vs);
+ }
+}
+
+void MainWindow::save(MainWindow *topWin)
+{
+ MainWindow::saveContents(topWin);
+
+ /*SessionItem* cs=SessionHandler::instance()->current();
+ assert(cs);
+
+ VComboSettings vs(cs->sessionFile(),cs->windowFile());
+
+ //We have to clear it so that not to remember all the previous windows
+ vs.clear();
+
+ //Add total window number and id of active window
+ vs.put("windowCount",windows_.count());
+ vs.put("topWindowId",windows_.indexOf(topWin));
+
+ //Save info for all the windows
+ for(int i=0; i < windows_.count(); i++)
+ {
+ std::string id="window_"+boost::lexical_cast<std::string>(i);
+ vs.beginGroup(id);
+ windows_.at(i)->writeSettings(&vs);
+ vs.endGroup();
+ }
+
+ //Write to json
+ vs.write();*/
+
+ //Save global config
+ VConfig::instance()->saveSettings();
+
+ ServerHandler::saveSettings();
+
+ //Save non-global config
+ for(int i=0; i < windows_.count(); i++)
+ {
+ //windows_.at(i)->saveSettings();
+ }
+}
+
+void MainWindow::saveContents(MainWindow *topWin)
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ assert(cs);
+
+ VComboSettings vs(cs->sessionFile(),cs->windowFile());
+
+ //We have to clear it so that not to remember all the previous windows
+ vs.clear();
+
+ //Add total window number and id of active window
+ vs.put("windowCount",windows_.count());
+ vs.put("topWindowId",windows_.indexOf(topWin));
+
+ //Save info for all the windows
+ for(int i=0; i < windows_.count(); i++)
+ {
+ std::string id="window_"+boost::lexical_cast<std::string>(i);
+ vs.beginGroup(id);
+ windows_.at(i)->writeSettings(&vs);
+ vs.endGroup();
+ }
+
+ //Write to json
+ vs.write();
+}
+
+
+void MainWindow::reload()
+{
+ Q_FOREACH(MainWindow *w,windows_)
+ {
+ w->reloadContents();
+ }
+}
+
+void MainWindow::saveSession(SessionItem* s)
+{
+
+}
+
+MainWindow* MainWindow::findWindow(QWidget *childW)
+{
+ Q_FOREACH(MainWindow *w,windows_)
+ {
+ if(static_cast<QWidget*>(w) == childW->window())
+ return w;
+ }
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+
diff --git a/Viewer/src/MainWindow.hpp b/Viewer/src/MainWindow.hpp
new file mode 100644
index 0000000..14f125d
--- /dev/null
+++ b/Viewer/src/MainWindow.hpp
@@ -0,0 +1,106 @@
+#ifndef MAINWINDOW_HPP_
+#define MAINWINDOW_HPP_
+
+//============================================================================
+// Copyright 2015 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include <QMainWindow>
+#include <QSettings>
+
+#include "ui_MainWindow.h"
+
+#include "VInfo.hpp"
+
+#include <boost/property_tree/ptree.hpp>
+
+class QActionGroup;
+class QLabel;
+class InfoPanel;
+class NodePanel;
+class ServerFilterMenu;
+class SessionItem;
+class VComboSettings;
+
+class MainWindow : public QMainWindow, private Ui::MainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow(QStringList,QWidget *parent=0);
+ ~MainWindow();
+
+ static void init();
+ static void showWindows();
+ static void openWindow(QString id,QWidget *fromW=0);
+ static void openWindow(QStringList id,QWidget *fromW=0);
+ static void reload();
+ static void saveSession(SessionItem*);
+ static void changeNotifySelectionChanged(VInfo_ptr);
+
+protected Q_SLOTS:
+ void on_actionNewTab_triggered();
+ void on_actionNewWindow_triggered();
+ void on_actionClose_triggered();
+ void on_actionQuit_triggered();
+ void on_actionRefresh_triggered();
+ void on_actionReset_triggered();
+ void on_actionRefreshSelected_triggered();
+ void on_actionResetSelected_triggered();
+ void on_actionConfigureNodeMenu_triggered();
+ void on_actionManageServers_triggered();
+ void on_actionShowInInfoPanel_triggered();
+ void on_actionAddTreeWidget_triggered();
+ void on_actionAddTableWidget_triggered();
+ void on_actionAddInfoPanel_triggered();
+ void on_actionPreferences_triggered();
+ void on_actionSearch_triggered();
+ void on_actionAbout_triggered();
+ void on_actionSaveSessionAs_triggered();
+ void on_actionManageSessions_triggered();
+
+ void slotCurrentChangedInPanel();
+ void slotSelectionChanged(VInfo_ptr);
+ void slotOpenInfoPanel();
+ void slotConfigChanged();
+ void slotContentsChanged();
+
+private:
+ void init(MainWindow*);
+ void closeEvent(QCloseEvent*);
+ void addInfoPanelActions(QToolBar *toolbar);
+ void reloadContents();
+ void rerenderContents();
+ bool selectInTreeView(VInfo_ptr info);
+ void updateRefreshActions();
+
+ void writeSettings(VComboSettings*);
+ void readSettings(VComboSettings*);
+
+ static MainWindow* makeWindow(VComboSettings* vs);
+ static MainWindow *makeWindow();
+ static MainWindow *makeWindow(QString id);
+ static MainWindow *makeWindow(QStringList idLst);
+ static bool aboutToClose(MainWindow*);
+ static bool aboutToQuit(MainWindow*);
+ static void save(MainWindow *);
+ static void saveContents(MainWindow *);
+ static MainWindow* findWindow(QWidget *childW);
+ static void configChanged(MainWindow *);
+
+ ServerFilterMenu* serverFilterMenu_;
+ NodePanel* nodePanel_;
+ QList<QAction*> infoPanelActions_;
+ VInfo_ptr selection_;
+
+ static bool quitStarted_;
+ static QList<MainWindow*> windows_;
+ static int maxWindowNum_;
+};
+
+#endif
diff --git a/Viewer/src/MainWindow.ui b/Viewer/src/MainWindow.ui
new file mode 100644
index 0000000..82c2d53
--- /dev/null
+++ b/Viewer/src/MainWindow.ui
@@ -0,0 +1,350 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>852</width>
+ <height>675</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>ecflow_ui</string>
+ </property>
+ <property name="autoFillBackground">
+ <bool>false</bool>
+ </property>
+ <widget class="QWidget" name="centralwidget">
+ <widget class="QLabel" name="label">
+ <property name="geometry">
+ <rect>
+ <x>740</x>
+ <y>640</y>
+ <width>52</width>
+ <height>14</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </widget>
+ <widget class="QMenuBar" name="menubar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>852</width>
+ <height>19</height>
+ </rect>
+ </property>
+ <property name="nativeMenuBar">
+ <bool>false</bool>
+ </property>
+ <widget class="QMenu" name="menuLl">
+ <property name="tearOffEnabled">
+ <bool>true</bool>
+ </property>
+ <property name="title">
+ <string>&File</string>
+ </property>
+ <addaction name="separator"/>
+ <addaction name="actionNewTab"/>
+ <addaction name="actionNewWindow"/>
+ <addaction name="separator"/>
+ <addaction name="actionSaveSessionAs"/>
+ <addaction name="actionManageSessions"/>
+ <addaction name="separator"/>
+ <addaction name="actionClose"/>
+ <addaction name="actionQuit"/>
+ </widget>
+ <widget class="QMenu" name="menuEdit">
+ <property name="tearOffEnabled">
+ <bool>true</bool>
+ </property>
+ <property name="title">
+ <string>&Edit</string>
+ </property>
+ <addaction name="actionPreferences"/>
+ <addaction name="actionConfigureNodeMenu"/>
+ </widget>
+ <widget class="QMenu" name="menu_Help">
+ <property name="tearOffEnabled">
+ <bool>true</bool>
+ </property>
+ <property name="title">
+ <string>&Help</string>
+ </property>
+ <addaction name="actionAbout"/>
+ </widget>
+ <widget class="QMenu" name="menuServer">
+ <property name="tearOffEnabled">
+ <bool>true</bool>
+ </property>
+ <property name="title">
+ <string>&Servers</string>
+ </property>
+ <addaction name="actionManageServers"/>
+ <addaction name="separator"/>
+ </widget>
+ <widget class="QMenu" name="menuView">
+ <property name="title">
+ <string>View</string>
+ </property>
+ <addaction name="actionAddTreeWidget"/>
+ <addaction name="actionAddTableWidget"/>
+ <addaction name="actionAddInfoPanel"/>
+ <addaction name="actionAddLogPanel"/>
+ </widget>
+ <widget class="QMenu" name="menu_Tools">
+ <property name="title">
+ <string>&Tools</string>
+ </property>
+ <addaction name="actionSearch"/>
+ </widget>
+ <widget class="QMenu" name="menuRefresh">
+ <property name="title">
+ <string>&Refresh</string>
+ </property>
+ <addaction name="actionReset"/>
+ <addaction name="actionResetSelected"/>
+ <addaction name="separator"/>
+ <addaction name="actionRefresh"/>
+ <addaction name="actionRefreshSelected"/>
+ </widget>
+ <addaction name="menuLl"/>
+ <addaction name="menuEdit"/>
+ <addaction name="menuView"/>
+ <addaction name="menuRefresh"/>
+ <addaction name="menuServer"/>
+ <addaction name="menu_Tools"/>
+ <addaction name="menu_Help"/>
+ </widget>
+ <widget class="QStatusBar" name="statusbar"/>
+ <widget class="QToolBar" name="viewToolBar">
+ <property name="windowTitle">
+ <string>View toolbar</string>
+ </property>
+ <property name="movable">
+ <bool>true</bool>
+ </property>
+ <property name="allowedAreas">
+ <set>Qt::AllToolBarAreas</set>
+ </property>
+ <attribute name="toolBarArea">
+ <enum>TopToolBarArea</enum>
+ </attribute>
+ <attribute name="toolBarBreak">
+ <bool>false</bool>
+ </attribute>
+ <addaction name="actionRefreshSelected"/>
+ <addaction name="actionSearch"/>
+ <addaction name="actionManageServers"/>
+ </widget>
+ <action name="actionClose">
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/images/close.svg</normaloff>:/viewer/images/close.svg</iconset>
+ </property>
+ <property name="text">
+ <string>&Close</string>
+ </property>
+ <property name="toolTip">
+ <string>Close window</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+W</string>
+ </property>
+ </action>
+ <action name="actionQuit">
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/images/exit.svg</normaloff>:/viewer/images/exit.svg</iconset>
+ </property>
+ <property name="text">
+ <string>&Quit</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+Q</string>
+ </property>
+ </action>
+ <action name="actionPreferences">
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/images/configure.svg</normaloff>:/viewer/images/configure.svg</iconset>
+ </property>
+ <property name="text">
+ <string>&Preferences ...</string>
+ </property>
+ </action>
+ <action name="actionNewTab">
+ <property name="text">
+ <string>New &tab</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+T</string>
+ </property>
+ </action>
+ <action name="actionNewWindow">
+ <property name="text">
+ <string>New &window</string>
+ </property>
+ </action>
+ <action name="actionRefresh">
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/reload.svg</normaloff>:/viewer/reload.svg</iconset>
+ </property>
+ <property name="text">
+ <string>Refresh all servers in tab</string>
+ </property>
+ <property name="toolTip">
+ <string>Refresh <b>all servers</b> in current tab</string>
+ </property>
+ <property name="shortcut">
+ <string>Shift+F5</string>
+ </property>
+ </action>
+ <action name="actionReset">
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/reset.svg</normaloff>:/viewer/reset.svg</iconset>
+ </property>
+ <property name="text">
+ <string>Reset all servers in tab</string>
+ </property>
+ <property name="toolTip">
+ <string>Reset</string>
+ </property>
+ </action>
+ <action name="actionConfigureNodeMenu">
+ <property name="text">
+ <string>Configure Node &Menu</string>
+ </property>
+ <property name="visible">
+ <bool>false</bool>
+ </property>
+ </action>
+ <action name="actionContents">
+ <property name="text">
+ <string>Contents</string>
+ </property>
+ <property name="toolTip">
+ <string>View contents</string>
+ </property>
+ </action>
+ <action name="actionManageServers">
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/manage_server.svg</normaloff>:/viewer/manage_server.svg</iconset>
+ </property>
+ <property name="text">
+ <string>&Manage servers ...</string>
+ </property>
+ <property name="toolTip">
+ <string>Manage servers<br><code>Ctrl+N</code></string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+N</string>
+ </property>
+ </action>
+ <action name="actionAddInfoPanel">
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/images/add_info.svg</normaloff>:/viewer/images/add_info.svg</iconset>
+ </property>
+ <property name="text">
+ <string>Add info panel</string>
+ </property>
+ </action>
+ <action name="actionAddTreeWidget">
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/images/add_tree.svg</normaloff>:/viewer/images/add_tree.svg</iconset>
+ </property>
+ <property name="text">
+ <string>Add tree view</string>
+ </property>
+ <property name="toolTip">
+ <string>Add tree widget</string>
+ </property>
+ </action>
+ <action name="actionAddTableWidget">
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/images/add_table.svg</normaloff>:/viewer/images/add_table.svg</iconset>
+ </property>
+ <property name="text">
+ <string>Add table view</string>
+ </property>
+ <property name="toolTip">
+ <string>Add table widget</string>
+ </property>
+ </action>
+ <action name="actionAbout">
+ <property name="text">
+ <string>About EcflowUI ...</string>
+ </property>
+ </action>
+ <action name="actionAddLogPanel">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Add log panel</string>
+ </property>
+ </action>
+ <action name="actionManageSessions">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Manage sessions ...</string>
+ </property>
+ <property name="visible">
+ <bool>true</bool>
+ </property>
+ </action>
+ <action name="actionSearch">
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/search.svg</normaloff>:/viewer/search.svg</iconset>
+ </property>
+ <property name="text">
+ <string>Search ...</string>
+ </property>
+ </action>
+ <action name="actionRefreshSelected">
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/reload_one.svg</normaloff>:/viewer/reload_one.svg</iconset>
+ </property>
+ <property name="text">
+ <string>Refresh selected server</string>
+ </property>
+ <property name="shortcut">
+ <string>F5</string>
+ </property>
+ </action>
+ <action name="actionResetSelected">
+ <property name="text">
+ <string>Reset selected server</string>
+ </property>
+ <property name="toolTip">
+ <string>Reset <b>selected</b> server in current tab</string>
+ </property>
+ </action>
+ <action name="actionSaveSessionAs">
+ <property name="text">
+ <string>S&ave session as...</string>
+ </property>
+ <property name="visible">
+ <bool>false</bool>
+ </property>
+ </action>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Viewer/src/ManualItemWidget.cpp b/Viewer/src/ManualItemWidget.cpp
new file mode 100644
index 0000000..7fac4de
--- /dev/null
+++ b/Viewer/src/ManualItemWidget.cpp
@@ -0,0 +1,103 @@
+//============================================================================
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "ManualItemWidget.hpp"
+
+#include "Highlighter.hpp"
+#include "InfoProvider.hpp"
+#include "MessageLabel.hpp"
+#include "VConfig.hpp"
+#include "VReply.hpp"
+
+ManualItemWidget::ManualItemWidget(QWidget *parent) : CodeItemWidget(parent)
+{
+ fileLabel_->hide();
+ messageLabel_->hide();
+ textEdit_->setShowLineNumbers(false);
+
+ Highlighter* ih=new Highlighter(textEdit_->document(),"manual");
+
+ infoProvider_=new ManualProvider(this);
+
+ //Editor font
+ textEdit_->setFontProperty(VConfig::instance()->find("panel.manual.font"));
+}
+
+ManualItemWidget::~ManualItemWidget()
+{
+}
+
+QWidget* ManualItemWidget::realWidget()
+{
+ return this;
+}
+
+void ManualItemWidget::reload(VInfo_ptr info)
+{
+ assert(active_);
+
+ if(suspended_)
+ return;
+
+ clearContents();
+
+ info_=info;
+ messageLabel_->hide();
+
+ //Info must be a node
+ if(info_ && info_->isNode() && info_->node())
+ {
+ infoProvider_->info(info_);
+ }
+}
+
+void ManualItemWidget::clearContents()
+{
+ InfoPanelItem::clear();
+ textEdit_->clear();
+ messageLabel_->hide();
+
+}
+
+void ManualItemWidget::infoReady(VReply* reply)
+{
+ QString s=QString::fromStdString(reply->text());
+ textEdit_->setPlainText(s);
+
+ if(reply->hasWarning())
+ {
+ messageLabel_->showWarning(QString::fromStdString(reply->warningText()));
+ }
+ else if(reply->hasInfo())
+ {
+ messageLabel_->showInfo(QString::fromStdString(reply->infoText()));
+ }
+ else if(s.isEmpty())
+ {
+ messageLabel_->showInfo("Manual is <b>not</b> available");
+ }
+
+ fileLabel_->update(reply);
+}
+
+void ManualItemWidget::infoProgress(VReply* reply)
+{
+ // QString s=QString::fromStdString(reply->text());
+ messageLabel_->showInfo(QString::fromStdString(reply->infoText()));
+}
+
+void ManualItemWidget::infoFailed(VReply* reply)
+{
+ QString s=QString::fromStdString(reply->errorText());
+ messageLabel_->showError(s);
+}
+
+static InfoPanelItemMaker<ManualItemWidget> maker1("manual");
+
diff --git a/Viewer/src/ManualItemWidget.hpp b/Viewer/src/ManualItemWidget.hpp
new file mode 100644
index 0000000..9a79379
--- /dev/null
+++ b/Viewer/src/ManualItemWidget.hpp
@@ -0,0 +1,40 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef MANUALITEMWIDGET_HPP_
+#define MANUALITEMWIDGET_HPP_
+
+#include "InfoPanelItem.hpp"
+#include "CodeItemWidget.hpp"
+
+class ManualItemWidget : public CodeItemWidget, public InfoPanelItem
+{
+public:
+ explicit ManualItemWidget(QWidget *parent=0);
+ ~ManualItemWidget();
+
+ void reload(VInfo_ptr);
+ QWidget* realWidget();
+ void clearContents();
+
+ //From VInfoPresenter
+ void infoReady(VReply*);
+ void infoFailed(VReply*);
+ void infoProgress(VReply*);
+
+ void nodeChanged(const VNode*, const std::vector<ecf::Aspect::Type>&) {}
+ void defsChanged(const std::vector<ecf::Aspect::Type>&) {}
+
+protected:
+ void updateState(const ChangeFlags&) {}
+};
+
+#endif
+
diff --git a/Viewer/src/MenuConfigDialog.cpp b/Viewer/src/MenuConfigDialog.cpp
new file mode 100644
index 0000000..c8ca317
--- /dev/null
+++ b/Viewer/src/MenuConfigDialog.cpp
@@ -0,0 +1,111 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "MenuHandler.hpp"
+#include "MenuConfigDialog.hpp"
+
+
+MenuConfigDialog::MenuConfigDialog(QWidget *parent) : QDialog(parent)
+{
+ setupUi(this);
+ //connect (insertPushButton_, SIGNAL(clicked()), this, SLOT(insertCurrentText()));
+ connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+
+
+
+ // load up the user menu file if it exists XXXX
+
+ if (0)
+ {
+ }
+ else
+ {
+ // otherwise create a dummy menu to start with
+
+ Menu *menu = new Menu("UserTemp");
+ MenuHandler::addMenu(menu);
+
+ MenuItem *item = new MenuItem("UserTemp");
+ item->setAsSubMenu();
+ item->setCommand("NoCommand");
+
+ MenuHandler::addItemToMenu(item, "Node");
+
+
+ //MenuItem *item2 = new MenuItem("Com");
+ //item2->setCommand("ecflow --whatever");
+ //MenuHandler::addItemToMenu(item2, "UserTemp");
+
+ //updateMenuTree(menu);
+ updateMenuTree(MenuHandler::findMenu("Node"));
+ }
+
+
+}
+
+
+void MenuConfigDialog::updateMenuTree(Menu *menu)
+{
+ menuTreeWidget_->clear();
+ menuTreeWidget_->setColumnCount(1);
+
+
+ QTreeWidgetItem *topLevelItem = new QTreeWidgetItem(menuTreeWidget_);
+ topLevelItem->setText(0, QString::fromStdString(menu->name()));
+ //topLevelItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled);
+
+ addChildrenToMenuTree(menu, topLevelItem);
+
+}
+
+
+void MenuConfigDialog::addChildrenToMenuTree(Menu *menu, QTreeWidgetItem *parent)
+{
+ std::vector<MenuItem *>&items = menu->items();
+
+ for (std::vector<MenuItem*>::iterator itItems = items.begin(); itItems != items.end(); ++itItems)
+ {
+ QTreeWidgetItem *item = new QTreeWidgetItem(parent);
+ item->setText(0, QString::fromStdString((*itItems)->name()));
+ item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled);
+
+ if ((*itItems)->isSubMenu())
+ {
+ Menu *submenu = MenuHandler::findMenu((*itItems)->name());
+ if (menu)
+ {
+ addChildrenToMenuTree(submenu, item);
+ }
+ }
+ else if ((*itItems)->isDivider())
+ {
+ //qmenu->addSeparator();
+ }
+ else
+ {
+ //QAction *action = (*itItems)->action();
+ //qmenu->addAction(action);
+ //action->setParent(parent);
+ //action->setEnabled(compatible);
+ }
+ }
+}
+
+
+
+//void CommandDesignerWidget::insertCurrentText()
+//{
+// //commandLineEdit_->setText("Silly");
+// commandLineEdit_->insert(componentsComboBox_->currentText() + " ");
+//}
+
+void MenuConfigDialog::reject()
+{
+ QDialog::reject();
+}
diff --git a/Viewer/src/MenuConfigDialog.hpp b/Viewer/src/MenuConfigDialog.hpp
new file mode 100644
index 0000000..80aa64c
--- /dev/null
+++ b/Viewer/src/MenuConfigDialog.hpp
@@ -0,0 +1,88 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+
+#ifndef MENUCONFIGDIALOG_HPP_
+#define MENUCONFIGDIALOG_HPP_
+
+#include <QDialog>
+#include <QTreeWidget>
+#include <QSplitter>
+
+#include "MenuHandler.hpp"
+
+class ConfigTreeWidget : public QTreeWidget
+{
+public:
+ ConfigTreeWidget()
+ {
+ }
+
+ explicit ConfigTreeWidget(QSplitter*s) : QTreeWidget(s)
+ {
+ resize(200, 300);
+
+ setSelectionMode(QAbstractItemView::SingleSelection);
+ setDragEnabled(true);
+ viewport()->setAcceptDrops(true);
+ setDropIndicatorShown(true);
+ setDragDropMode(QAbstractItemView::InternalMove);
+/*
+ QTreeWidgetItem* parentItem = new QTreeWidgetItem(this);
+ parentItem->setText(0, "Test");
+ parentItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled);
+
+ for(int i = 0; i < 10; ++i)
+ {
+ QTreeWidgetItem* pItem = new QTreeWidgetItem(parentItem);
+ pItem->setText(0, QString("Number %1").arg(i) );
+ pItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled);
+ pItem->addChild(pItem);
+ }*/
+ };
+
+/*private:
+ virtual void dropEvent(QDropEvent * event)
+ {
+ QModelIndex droppedIndex = indexAt( event->pos() );
+
+ if( !droppedIndex.isValid() )
+ return;
+
+ QTreeWidget::dropEvent(event);
+ }*/
+};
+
+
+#include "ui_MenuConfigDialog.h"
+
+class MenuConfigDialog : public QDialog, private Ui::MenuConfigDialog
+{
+ Q_OBJECT
+
+public:
+ explicit MenuConfigDialog(QWidget *parent = 0);
+ ~MenuConfigDialog() {};
+
+ void updateMenuTree(Menu *menu);
+
+ void reject();
+
+
+//public Q_SLOTS:
+// void insertCurrentText();
+
+
+private:
+ void addChildrenToMenuTree(Menu *menu, QTreeWidgetItem *parent);
+
+};
+
+
+#endif
diff --git a/Viewer/src/MenuConfigDialog.ui b/Viewer/src/MenuConfigDialog.ui
new file mode 100644
index 0000000..f737a29
--- /dev/null
+++ b/Viewer/src/MenuConfigDialog.ui
@@ -0,0 +1,256 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MenuConfigDialog</class>
+ <widget class="QDialog" name="MenuConfigDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>882</width>
+ <height>627</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <item>
+ <widget class="QFrame" name="frame">
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>64</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_15">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>553</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="newItemPb_">
+ <property name="text">
+ <string>&New Item</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="duplicateItemPb_">
+ <property name="text">
+ <string>&Duplicate Item</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="newSubmenuPb_">
+ <property name="text">
+ <string>New &Submenu</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSplitter" name="splitter">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <widget class="ConfigTreeWidget" name="menuTreeWidget_">
+ <column>
+ <property name="text">
+ <string notr="true">1</string>
+ </property>
+ </column>
+ </widget>
+ <widget class="QWidget" name="formLayoutWidget">
+ <layout class="QFormLayout" name="formLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::ExpandingFieldsGrow</enum>
+ </property>
+ <property name="labelAlignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="nameLe_"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Valid Node Types:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QCheckBox" name="allTypesCb_">
+ <property name="text">
+ <string>All</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="taskCb_">
+ <property name="text">
+ <string>Task</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="aliasCb_">
+ <property name="text">
+ <string>Alias</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="familyCb_">
+ <property name="text">
+ <string>Family</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="suiteCb_">
+ <property name="text">
+ <string>Suite</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="serverCb_">
+ <property name="text">
+ <string>Server</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="unselectTypesPb_">
+ <property name="text">
+ <string>Unselect all</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Valid States:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QCheckBox" name="unknownCb_">
+ <property name="text">
+ <string>Unknown</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="queuedCb_">
+ <property name="text">
+ <string>Queued</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="suspendedCb_">
+ <property name="text">
+ <string>Suspended</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="abortedCb_">
+ <property name="text">
+ <string>Aborted</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="unselectAllStatesCb_">
+ <property name="text">
+ <string>Unselect all</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_6">
+ <property name="text">
+ <string>Valid Attributes:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QCheckBox" name="checkBox_10">
+ <property name="text">
+ <string>CheckBox</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="label_7">
+ <property name="text">
+ <string>Command:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="CommandDesignerWidget" name="lineEdit"/>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>CommandDesignerWidget</class>
+ <extends>QLineEdit</extends>
+ <header>CommandDesignerWidget.hpp</header>
+ </customwidget>
+ <customwidget>
+ <class>ConfigTreeWidget</class>
+ <extends>QTreeWidget</extends>
+ <header>MenuConfigDialog.hpp</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Viewer/src/MenuHandler.cpp b/Viewer/src/MenuHandler.cpp
new file mode 100644
index 0000000..87e1f31
--- /dev/null
+++ b/Viewer/src/MenuHandler.cpp
@@ -0,0 +1,830 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/json_parser.hpp>
+#include <boost/foreach.hpp>
+
+#include <assert.h>
+#include <iostream>
+
+#include <QMessageBox>
+#include <QMenu>
+#include <QLabel>
+#include <QLinearGradient>
+#include <QWidgetAction>
+#include <QDebug>
+#include <QObject>
+#include <QVBoxLayout>
+
+#include "Str.hpp"
+#include "MenuHandler.hpp"
+#include "ServerHandler.hpp"
+#include "UserMessage.hpp"
+#include "NodeExpression.hpp"
+#include "VConfig.hpp"
+#include "VNode.hpp"
+#include "CustomCommandHandler.hpp"
+
+int MenuItem::idCnt_=0;
+
+std::vector<Menu *> MenuHandler::menus_;
+
+
+MenuHandler::MenuHandler()
+{
+ menus_.clear();
+}
+
+
+// ---------------------------------------------------------
+// MenuHandler::readMenuConfigFile
+// Read the given config file and store the resulting menus
+// internally.
+// ---------------------------------------------------------
+
+bool MenuHandler::readMenuConfigFile(const std::string &configFile)
+{
+ // parse the response using the boost JSON property tree parser
+
+ using boost::property_tree::ptree;
+ ptree pt;
+
+ try
+ {
+ read_json(configFile, pt);
+ }
+ catch (const boost::property_tree::json_parser::json_parser_error& e)
+ {
+ std::string errorMessage = e.what();
+ UserMessage::message(UserMessage::ERROR, true, std::string("Error, unable to parse JSON menu file : " + errorMessage));
+ return false;
+ }
+
+
+
+ // iterate over the top level of the tree
+
+ for (ptree::const_iterator itTopLevel = pt.begin(); itTopLevel != pt.end(); ++itTopLevel)
+ {
+ // parse the menu definitions?
+
+ if (itTopLevel->first == "menus")
+ {
+ UserMessage::message(UserMessage::DBG, false, std::string("Menus:"));
+
+ ptree const &menusDef = itTopLevel->second;
+
+ // iterate through all the menus
+
+ for (ptree::const_iterator itMenus = menusDef.begin(); itMenus != menusDef.end(); ++itMenus)
+ {
+ ptree const &menuDef = itMenus->second;
+
+ std::string cname = menuDef.get("name", "NoName");
+ UserMessage::message(UserMessage::DBG, false, std::string(" ") + cname);
+ Menu *menu = new Menu(cname);
+
+ //ptree const &menuModesDef = menuDef.get_child("modes");
+
+ //for (ptree::const_iterator itMenuModes = menuModesDef.begin(); itMenuModes != menuModesDef.end(); ++itMenuModes)
+ //{
+ // std::cout << " +" << itMenuModes->second.data() << std::endl;
+ //}
+
+ std::string parentMenuName = menuDef.get("parent", "None");
+
+ if (parentMenuName != "None")
+ {
+ }
+
+ addMenu(menu); // add to our list of available menus
+
+ }
+ }
+
+ // parse the menu items?
+
+ else if (itTopLevel->first == "menu_items")
+ {
+ UserMessage::message(UserMessage::DBG, false, std::string("Menu items:"));
+
+ ptree const &itemsDef = itTopLevel->second;
+
+ // iterate through all the items
+
+ for (ptree::const_iterator itItems = itemsDef.begin(); itItems != itemsDef.end(); ++itItems)
+ {
+ ptree const &ItemDef = itItems->second;
+
+ std::string name = ItemDef.get("name", "NoName");
+ std::string menuName = ItemDef.get("menu", "NoMenu");
+ std::string command = ItemDef.get("command", "NoCommand");
+ std::string type = ItemDef.get("type", "Command");
+ std::string enabled = ItemDef.get("enabled_for", "");
+ std::string visible = ItemDef.get("visible_for", "");
+ std::string questFor = ItemDef.get("question_for","");
+ std::string question = ItemDef.get("question", "");
+ std::string handler = ItemDef.get("handler", "");
+ std::string views = ItemDef.get("view", "");
+ std::string icon = ItemDef.get("icon", "");
+ std::string hidden = ItemDef.get("hidden", "false");
+ std::string statustip = ItemDef.get("status_tip", "");
+
+ //std::cout << " " << name << " :" << menuName << std::endl;
+
+ UserMessage::message(UserMessage::DBG, false, std::string(" " + name));
+ MenuItem *item = new MenuItem(name);
+ item->setCommand(command);
+
+
+ BaseNodeCondition *enabledCond = NodeExpressionParser::instance()->parseWholeExpression(enabled);
+ if (enabledCond == NULL)
+ {
+ UserMessage::message(UserMessage::ERROR, true, std::string("Error, unable to parse enabled condition: " + enabled));
+ enabledCond = new FalseNodeCondition();
+ }
+ item->setEnabledCondition(enabledCond);
+
+
+ BaseNodeCondition *visibleCond = NodeExpressionParser::instance()->parseWholeExpression(visible);
+ if (visibleCond == NULL)
+ {
+ UserMessage::message(UserMessage::ERROR, true, std::string("Error, unable to parse visible condition: " + visible));
+ visibleCond = new FalseNodeCondition();
+ }
+ item->setVisibleCondition(visibleCond);
+
+ BaseNodeCondition *questionCond = NodeExpressionParser::instance()->parseWholeExpression(questFor);
+ if (questionCond == NULL)
+ {
+ UserMessage::message(UserMessage::ERROR, true, std::string("Error, unable to parse question condition: " + questFor));
+ questionCond = new FalseNodeCondition();
+ }
+ item->setQuestionCondition(questionCond);
+
+
+ item->setQuestion(question);
+ item->setHandler(handler);
+ item->setIcon(icon);
+ item->setStatustip(statustip);
+
+ if(!views.empty())
+ {
+ std::vector<std::string> viewsVec;
+ QStringList vLst=QString::fromStdString(views).split("/");
+ for(int i=0; i < vLst.count(); i++)
+ {
+ viewsVec.push_back(vLst[i].toStdString());
+ }
+
+ item->setViews(viewsVec);
+ }
+
+ if(hidden == "true")
+ item->setHidden(true);
+
+ if (type == "Submenu")
+ item->setAsSubMenu();
+
+ addItemToMenu(item, menuName);
+ //std::cout << " added" << std::endl;
+
+
+ // parse the valid node types/states for this menu item
+
+ //if( ItemDef.count("valid_types") > 0 ) // does this node exist on the tree?
+ //{
+ // ptree ptValidTypes = ItemDef.get_child("valid_types");
+ // for (ptree::const_iterator itTypes = ptValidTypes.begin(); itTypes != ptValidTypes.end(); ++itTypes)
+ // {
+ // std::string type(itTypes->second.data());
+ // //item->addValidType(type);
+ // }
+ //}
+ //else
+ //{
+ // //item->addValidType("all");
+ //}
+
+
+ if( ItemDef.count("valid_states") > 0 ) // does this node exist on the tree?
+ {
+ ptree ptValidStates = ItemDef.get_child("valid_states");
+ for (ptree::const_iterator itStates = ptValidStates.begin(); itStates != ptValidStates.end(); ++itStates)
+ {
+ std::string state(itStates->second.data());
+ //item->addValidState(state);
+ }
+ }
+ else
+ {
+ //item->addValidState("all");
+ }
+ }
+ }
+ }
+
+
+ //ptree ptMenus = pt.get_child("menus");
+
+
+
+
+ //for (ptree::const_iterator itTopLevel = pt.begin(); itTopLevel != pt.end(); ++itTopLevel)
+ //{
+ // if (itTopLevel->first == "menus")
+
+ //}
+
+
+
+
+ return true;
+}
+
+
+// ---------------------------------------------------------
+// MenuHandler::addCustomMenuCommands
+// Obtains the current list of custom commands and adds them
+// to the list of custom menu items.
+// ---------------------------------------------------------
+
+void MenuHandler::refreshCustomMenuCommands()
+{
+ BaseNodeCondition *trueCond = new TrueNodeCondition();
+ BaseNodeCondition *falseCond = new FalseNodeCondition();
+ CustomCommandHistoryHandler *customRecentCmds = CustomCommandHistoryHandler::instance();
+ CustomSavedCommandHandler *customSavedCmds = CustomSavedCommandHandler::instance();
+
+ Menu *menu = findMenu("Custom");
+ if (menu)
+ {
+ menu->clearFixedList();
+
+ // create the 'compulsary' menu items
+ MenuItem *item1 = new MenuItem("Manage commands...");
+ item1->setCommand("custom");
+ addItemToMenu(item1, "Custom");
+ item1->setEnabledCondition(trueCond);
+ item1->setVisibleCondition(trueCond);
+ item1->setQuestionCondition(falseCond);
+ item1->setIcon("configure.svg");
+
+ // Saved commands
+ MenuItem *item2 = new MenuItem("-");
+ addItemToMenu(item2, "Custom");
+ item2->setEnabledCondition(trueCond);
+ item2->setVisibleCondition(trueCond);
+ item2->setQuestionCondition(falseCond);
+
+ int numSavedCommands = customSavedCmds->numCommands();
+
+ for (int i = 0; i < numSavedCommands; i++)
+ {
+ CustomCommand *cmd = customSavedCmds->commandFromIndex(i);
+ if (cmd->inContextMenu())
+ {
+ MenuItem *item = new MenuItem(cmd->name());
+ item->setCommand(cmd->command());
+ item->setEnabledCondition(trueCond);
+ item->setVisibleCondition(trueCond);
+ item->setQuestionCondition(trueCond);
+ item->setStatustip("__cmd__");
+ addItemToMenu(item, "Custom");
+ }
+ }
+
+
+ // Recently executed commands
+ MenuItem *item3 = new MenuItem("-");
+ addItemToMenu(item3, "Custom");
+ item3->setEnabledCondition(trueCond);
+ item3->setVisibleCondition(trueCond);
+ item3->setQuestionCondition(falseCond);
+
+ MenuItem *item4 = new MenuItem("Recent");
+ addItemToMenu(item4, "Custom");
+ item4->setEnabledCondition(falseCond);
+ item4->setVisibleCondition(trueCond);
+ item4->setQuestionCondition(falseCond);
+
+ int numRecentCommands = customRecentCmds->numCommands();
+
+ for (int i = 0; i < numRecentCommands; i++)
+ {
+ CustomCommand *cmd = customRecentCmds->commandFromIndex(i);
+
+ MenuItem *item = new MenuItem(cmd->name());
+ item->setCommand(cmd->command());
+ item->setEnabledCondition(trueCond);
+ item->setVisibleCondition(trueCond);
+ item->setQuestionCondition(trueCond);
+ item->setStatustip("__cmd__");
+ addItemToMenu(item, "Custom");
+ }
+ }
+}
+
+
+Menu *MenuHandler::findMenu(const std::string &name)
+{
+ for (std::vector<Menu *>::iterator itMenus = menus_.begin(); itMenus != menus_.end(); ++itMenus)
+ {
+ if ((*itMenus)->name() == name)
+ {
+ return (*itMenus);
+ }
+ }
+
+ return NULL; // if we got to here, then the menu was not found
+}
+
+MenuItem* MenuHandler::findItem(QAction* ac)
+{
+ // ac could be NULL, e.g. if the user clicked on a separator instead of a menu item
+ if (ac)
+ {
+ for(std::vector<Menu*>::iterator itMenus = menus_.begin(); itMenus != menus_.end(); ++itMenus)
+ {
+ for(std::vector<MenuItem*>::iterator it=(*itMenus)->items().begin(); it!=(*itMenus)->items().end(); ++it)
+ {
+ if((*it)->id() == ac->data().toInt())
+ {
+ return *it;
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+MenuItem* MenuHandler::newItem(const std::string &name)
+{
+ return NULL;
+}
+
+bool MenuHandler::addItemToMenu(MenuItem *item, const std::string &menuName)
+{
+ Menu *menu = findMenu(menuName);
+ // items_.push_back(item); // add to our global list of menu items
+
+ if (menu)
+ {
+ menu->addItemToFixedList(item);
+ return true;
+ }
+ else
+ {
+ UserMessage::message(UserMessage::ERROR, false, std::string("Could not find menu called " +
+ menuName + " to add item " + item->name() + " to."));
+ return false;
+ }
+
+ return false;
+}
+
+
+MenuItem *MenuHandler::invokeMenu(const std::string &menuName, std::vector<VInfo_ptr> nodes, QPoint pos, QWidget *parent,const std::string& view)
+{
+ MenuItem *selectedItem = NULL;
+ Menu *menu = findMenu(menuName);
+
+ if (menu)
+ {
+ QList<QAction*> acLst;
+
+ //While create the menus we collect all the actions created with "parent" as the parent.
+ //QMenu does not take ownership of these actions so we need to delete them.
+ QMenu *qMenu = menu->generateMenu(nodes, parent, NULL, view,acLst);
+
+ if (qMenu)
+ {
+ QAction* selectedAction = qMenu->exec(pos);
+ selectedItem=MenuHandler::findItem(selectedAction);
+
+ delete qMenu;
+
+ //Delete all the actions with "parent" as the parent;
+ Q_FOREACH(QAction *ac,acLst)
+ {
+ assert(parent == ac->parent());
+ delete ac;
+ }
+ }
+ }
+
+ return selectedItem;
+}
+
+// -----------------------------------------------------------------
+
+
+///////////////////////////////////////////////////////////
+
+// --------------------
+// Menu class functions
+// --------------------
+
+
+
+Menu::Menu(const std::string &name) : name_(name)
+{
+}
+
+
+Menu::~Menu()
+{
+ for (std::vector<MenuItem*>::iterator itItems = itemsCombined_.begin(); itItems != itemsCombined_.end(); ++itItems)
+ {
+ if (*itItems)
+ delete (*itItems);
+ }
+}
+
+
+QMenu *Menu::generateMenu(std::vector<VInfo_ptr> nodes, QWidget *parent,QMenu* parentMenu,const std::string& view,QList<QAction*>& acLst)
+{
+ QMenu *qmenu=NULL;
+ if(parentMenu)
+ {
+ qmenu=parentMenu->addMenu(QString::fromStdString(name()));
+ }
+ else
+ {
+ qmenu=new QMenu(parent);
+ qmenu->setTitle(QString::fromStdString(name()));
+ }
+
+ if (nodes.empty())
+ return NULL;
+
+ //qmenu->setWindowFlags(Qt::Tool);
+ //qmenu->setWindowTitle("my title");
+
+ // add an inactive action(!) to the top of the menu in order to show which
+ // node has been selected
+
+ buildMenuTitle(nodes,qmenu);
+
+ //TypeNodeCondition typeCondFamily (MenuItem::FAMILY);
+ //TypeNodeCondition typeCondTask (MenuItem::TASK);
+ //StateNodeCondition stateCondUnknown ("unknown");
+ //OrNodeCondition orCond (&typeCondFamily, &typeCondTask);
+ //AndNodeCondition andCond (&orCond, &stateCondUnknown);
+
+ //std::string condString("not task");
+ //BaseNodeCondition *nodeCond = NodeExpressionParser::parseWholeExpression(condString);
+
+ //if (nodeCond == NULL)
+ //{
+ // UserMessage::message(UserMessage::ERROR, true, std::string("Error, unable to parse condition: " + condString));
+ //}
+
+
+ // merge the fixed menu items (from the config file) with the dynamic ones
+ itemsCombined_ = itemsFixed_;
+ itemsCombined_.insert(itemsCombined_.end(), itemsCustom_.begin(), itemsCustom_.end());
+
+ for (std::vector<MenuItem*>::iterator itItems = itemsCombined_.begin(); itItems != itemsCombined_.end(); ++itItems)
+ {
+ // is this item valid for the current selection?
+
+ if((*itItems)->hidden())
+ continue;
+
+ if(!(*itItems)->isValidView(view))
+ continue;
+
+ bool visible = true;
+
+ for (std::vector<VInfo_ptr>::iterator itNodes = nodes.begin(); itNodes != nodes.end(); ++itNodes)
+ {
+ //compatible = compatible && (*itItems)->compatibleWithNode(*itNodes);
+ //compatible = compatible && (nodeCond != NULL && nodeCond->execute(*itNodes));
+ visible = visible && (*itItems)->visibleCondition()->execute(*itNodes);
+ }
+
+ if (visible)
+ {
+ bool enabled = true;
+
+ for (std::vector<VInfo_ptr>::iterator itNodes = nodes.begin(); itNodes != nodes.end(); ++itNodes)
+ {
+ enabled = enabled && (*itItems)->enabledCondition()->execute(*itNodes);
+ }
+
+
+ if ((*itItems)->isSubMenu())
+ {
+ Menu *menu = MenuHandler::findMenu((*itItems)->name());
+ if (menu)
+ {
+ //The submenu will be added to qmenu and it will take ownership of it.
+ QMenu *subMenu = menu->generateMenu(nodes, parent, qmenu, view, acLst);
+ subMenu->setEnabled(enabled);
+ }
+ }
+ else if ((*itItems)->isDivider())
+ {
+ qmenu->addSeparator();
+ }
+ else
+ {
+ //When we add the action to the menu its parent (NULL a.i. the QApplication) does not change.
+ //So when the menu is deleted the action is not deleted.
+ //At least this is the behaviour with Qt 4.8. and 5.5.
+ //QAction *action = (*itItems)->action();
+ //action->setParent(parent);
+
+ //These actions will have "parent" as the parent, otherwise the statustip would not work
+ //on qmainwindows. The downside is that we need to delete these actions separately when the qmenu is deleted.
+ //In theory the parent of the actions could be the qmenu as well, but in this case the statustip does not work!
+ QAction* action=(*itItems)->createAction(parent);
+ qmenu->addAction(action);
+ action->setEnabled(enabled);
+ acLst << action;
+ }
+ }
+ }
+
+ return qmenu;
+}
+
+/*
+void Menu::addSubHeading(std::string &name)
+{
+ QLabel *nodeLabel = new QLabel(name);
+
+ QFont menuTitleFont;
+ menuTitleFont.setBold(true);
+ menuTitleFont.setItalic(true);
+ nodeLabel->setFont(menuTitleFont);
+ nodeLabel->setAlignment(Qt::AlignHCenter);
+ nodeLabel->setObjectName("nodeLabel");
+
+ QWidget* titleW=new QWidget(qmenu);
+ QVBoxLayout *titleLayout=new QVBoxLayout(titleW);
+ titleLayout->setContentsMargins(2,2,2,2);
+ titleLayout->addWidget(nodeLabel);
+ nodeLabel->setParent(titleW);
+
+ QWidgetAction *wAction = new QWidgetAction(qmenu);
+ //Qt doc says: the ownership of the widget is passed to the widgetaction.
+ //So when the action is deleted it will be deleted as well.
+ wAction->setDefaultWidget(titleW);
+ //wAction->setEnabled(false);
+ qmenu->addAction(wAction);
+
+}
+*/
+void Menu::buildMenuTitle(std::vector<VInfo_ptr> nodes, QMenu* qmenu)
+{
+ QLabel *nodeLabel = NULL;
+
+ if (nodes.size() == 1)
+ {
+ VNode *node=nodes.at(0)->node();
+
+ if(!node)
+ return;
+
+ //single node selected put a label with the node name + colour
+ nodeLabel = new QLabel(node->name());
+
+ QBrush bgBrush(node->stateColour());
+
+ if(VProperty* p=VConfig::instance()->find("view.common.node_gradient"))
+ {
+ if(p->value().toBool())
+ {
+ int lighter=150;
+ QColor bg=bgBrush.color();
+ QColor bgLight=bg.lighter(lighter);
+ QColor border=bg.darker(125);
+
+ QLinearGradient grad;
+ grad.setCoordinateMode(QGradient::ObjectBoundingMode);
+ grad.setStart(0,0);
+ grad.setFinalStop(0,1);
+
+ grad.setColorAt(0,bgLight);
+ grad.setColorAt(1,bg);
+ bgBrush=QBrush(grad);
+ }
+ }
+
+ QPalette labelPalette;
+ labelPalette.setBrush(QPalette::Window,bgBrush);
+ labelPalette.setColor(QPalette::WindowText,node->stateFontColour());//QColor(96,96,96));
+ nodeLabel->setAutoFillBackground(true);
+ nodeLabel->setPalette(labelPalette);
+
+ QString titleQss="QLabel {padding: 2px;}";
+ nodeLabel->setStyleSheet(titleQss);
+ }
+ else
+ {
+ // multiple nodes selected - say how many
+ nodeLabel = new QLabel(QObject::tr("%1 nodes selected").arg(nodes.size()));
+ }
+
+ QFont menuTitleFont;
+ menuTitleFont.setBold(true);
+ menuTitleFont.setItalic(true);
+ nodeLabel->setFont(menuTitleFont);
+ nodeLabel->setAlignment(Qt::AlignHCenter);
+ nodeLabel->setObjectName("nodeLabel");
+
+ QWidget* titleW=new QWidget(qmenu);
+ QVBoxLayout *titleLayout=new QVBoxLayout(titleW);
+ titleLayout->setContentsMargins(2,2,2,2);
+ titleLayout->addWidget(nodeLabel);
+ nodeLabel->setParent(titleW);
+
+ QWidgetAction *wAction = new QWidgetAction(qmenu);
+ //Qt doc says: the ownership of the widget is passed to the widgetaction.
+ //So when the action is deleted it will be deleted as well.
+ wAction->setDefaultWidget(titleW);
+ //wAction->setEnabled(false);
+ qmenu->addAction(wAction);
+}
+
+
+// ------------------------
+// MenuItem class functions
+// ------------------------
+
+MenuItem::MenuItem(const std::string &name) :
+ name_(name),
+ id_(idCnt_++),
+ hidden_(false),
+ visibleCondition_(NULL),
+ enabledCondition_(NULL),
+ questionCondition_(NULL),
+ isSubMenu_(false),
+ isDivider_(false)
+{
+ if (name == "-")
+ {
+ isDivider_ = true;
+ }
+}
+
+MenuItem::~MenuItem()
+{
+}
+
+void MenuItem::setCommand(const std::string &command)
+{
+ command_ = command;
+
+ //if (action_)
+ // action_->setStatusTip(QString(command.c_str())); // so we see the command in the status bar
+}
+
+void MenuItem::setHandler(const std::string& handler)
+{
+ handler_ = handler;
+}
+
+void MenuItem::setIcon(const std::string& icon)
+{
+ if(!icon.empty())
+ {
+ icon_=QIcon(QPixmap(":/viewer/" + QString::fromStdString(icon)));
+ }
+}
+
+bool MenuItem::shouldAskQuestion(std::vector<VInfo_ptr> &nodes)
+{
+ bool askQuestion = false;
+
+ // ask the question if any of the nodes require it
+ for (std::vector<VInfo_ptr>::iterator itNodes = nodes.begin(); itNodes != nodes.end(); ++itNodes)
+ {
+ askQuestion = askQuestion || questionCondition()->execute(*itNodes);
+ }
+
+ return askQuestion;
+}
+
+bool MenuItem::isValidView(const std::string& view) const
+{
+ if(views_.empty())
+ return true;
+
+ return (std::find(views_.begin(),views_.end(),view) != views_.end());
+}
+
+QAction* MenuItem::createAction(QWidget* parent)
+{
+ QAction *ac=new QAction(parent);
+ ac->setText(QString::fromStdString(name_));
+ ac->setIcon(icon_);
+
+ if(!statustip_.empty())
+ {
+ if(statustip_ == "__cmd__")
+ ac->setStatusTip(QString::fromStdString(command_)); // so we see the command in the status bar
+ else
+ ac->setStatusTip(QString::fromStdString(statustip_));
+ }
+ ac->setData(id_);
+ return ac;
+
+}
+
+
+// // adds an entry to the list of valid node types for this menu item(*itItems)
+// void MenuItem::addValidType(std::string type)
+// {
+// static NodeType all[] = {TASK, FAMILY, SUITE, SERVER, ALIAS};
+//
+// if (type == "server")
+// validNodeTypes_.push_back(SERVER);
+// else if(type == "suite")
+// validNodeTypes_.push_back(SUITE);
+// else if(type == "task")
+// validNodeTypes_.push_back(TASK);
+// else if(type == "family")
+// validNodeTypes_.push_back(FAMILY);
+// else if(type == "alias")
+// validNodeTypes_.push_back(ALIAS);
+// else if(type == "all")
+// validNodeTypes_.insert(validNodeTypes_.begin(), all, all+5);
+// }
+//
+//
+// // adds an entry to the list of valid node types for this menu item
+// void MenuItem::addValidState(std::string state)
+// {
+// DState::State dstate;
+//
+// if (DState::isValid(state))
+// {
+// dstate = DState::toState(state);
+// validNodeStates_.push_back(dstate);
+// }
+// else if (state == "all")
+// {
+// // add the list of all states
+// std::vector<DState::State> allDstates = DState::states();
+// validNodeStates_.insert(validNodeStates_.end(), allDstates.begin(), allDstates.end());
+// }
+// else
+// {
+// UserMessage::message(UserMessage::ERROR, false, std::string("Bad node state in menu file: " + state));
+// }
+// }
+
+
+// bool MenuItem::isNodeTypeValidForMenuItem(NodeType type)
+// {
+// if(std::find(validNodeTypes_.begin(), validNodeTypes_.end(), type) == validNodeTypes_.end())
+// return false;
+// else
+// return true;
+// }
+//
+//
+// bool MenuItem::compatibleWithNode(VInfo_ptr nodeInfo)
+// {
+// // check each node type and return false if we don't match
+//
+// if(nodeInfo->isServer())
+// if(std::find(validNodeTypes_.begin(), validNodeTypes_.end(), SERVER) == validNodeTypes_.end())
+// return false;
+//
+// if(nodeInfo->isNode())
+// {
+// Node *node = nodeInfo->node()->node();
+//
+// if(node->isSuite())
+// if (!isNodeTypeValidForMenuItem(SUITE))
+// return false;
+//
+// if(node->isTask())
+// if (!isNodeTypeValidForMenuItem(TASK))
+// return false;
+//
+// if(node->isAlias())
+// if (!isNodeTypeValidForMenuItem(ALIAS))
+// return false;
+//
+// if(node->isFamily())
+// if (!isNodeTypeValidForMenuItem(FAMILY))
+// return false;
+// }
+//
+// return true;
+// }
diff --git a/Viewer/src/MenuHandler.hpp b/Viewer/src/MenuHandler.hpp
new file mode 100644
index 0000000..e9bc405
--- /dev/null
+++ b/Viewer/src/MenuHandler.hpp
@@ -0,0 +1,166 @@
+//============================================================================
+// Copyright 2015 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef MENUHANDLER_HPP_
+#define MENUHANDLER_HPP_
+
+#include <vector>
+#include <QString>
+#include <QIcon>
+#include <QList>
+#include <QPoint>
+
+#include "VInfo.hpp"
+
+class QMenu;
+class QAction;
+class QWidget;
+class Node;
+class BaseNodeCondition;
+
+
+
+// -------------------------
+// MenuItem
+// A single item in a menu
+// -------------------------
+
+class MenuItem
+{
+public:
+ explicit MenuItem(const std::string &name);
+ ~MenuItem();
+
+ void setCommand(const std::string &command);
+ //bool compatibleWithNode(VInfo_ptr nodeInfo);
+ //void addValidType(std::string type);
+ //void addValidState(std::string type);
+ void setHandler(const std::string &handler);
+ void setViews(const std::vector<std::string> &views) {views_=views;};
+ void setQuestion(const std::string &question) {question_=question;}
+ void setIcon(const std::string &icon);
+ void setStatustip(const std::string &statustip) {statustip_=statustip;}
+ void setHidden(bool b) {hidden_=b;}
+ void setAsSubMenu() {isSubMenu_ = true;};
+ void setVisibleCondition(BaseNodeCondition *cond) {visibleCondition_ = cond;};
+ void setEnabledCondition(BaseNodeCondition *cond) {enabledCondition_ = cond;};
+ void setQuestionCondition(BaseNodeCondition *cond) {questionCondition_ = cond;};
+ BaseNodeCondition *visibleCondition() {return visibleCondition_;};
+ BaseNodeCondition *enabledCondition() {return enabledCondition_;};
+ BaseNodeCondition *questionCondition() {return questionCondition_;};
+ bool shouldAskQuestion(std::vector<VInfo_ptr> &nodes);
+ bool isSubMenu() {return isSubMenu_;};
+ bool isDivider() {return isDivider_;};
+ std::string &name() {return name_;};
+ const std::string handler() const {return handler_;}
+ bool isValidView(const std::string&) const;
+ const std::string command() const {return command_;}
+ const std::string question() const {return question_;}
+ bool hidden() const {return hidden_;}
+ int id() const {return id_;}
+ QAction* createAction(QWidget* parent);
+
+private:
+ //No copy allowed
+ MenuItem(const MenuItem&);
+ MenuItem& operator=(const MenuItem&);
+
+ //bool isNodeTypeValidForMenuItem(NodeType type);
+
+ std::string name_;
+ int id_;
+ std::string tooltip_;
+ std::string command_;
+ std::string statustip_;
+ std::string question_;
+ std::string defaultAnswer_;
+ std::string handler_;
+ std::vector<std::string> views_;
+ bool hidden_;
+
+ //std::vector<NodeType> validNodeTypes_;
+ //std::vector<DState::State> validNodeStates_;
+
+
+ BaseNodeCondition *visibleCondition_;
+ BaseNodeCondition *enabledCondition_;
+ BaseNodeCondition *questionCondition_;
+
+ bool isSubMenu_;
+ bool isDivider_;
+
+ QIcon icon_;
+
+ static int idCnt_;
+};
+
+
+
+// -------------------------------------------------------------
+// Menu
+// Contains all the possible items for a given menu. These will
+// be filtered at run-time according to the state of
+// the given item which has been clicked.
+// -------------------------------------------------------------
+
+class Menu
+{
+public:
+ explicit Menu(const std::string &name);
+ ~Menu();
+ QString exec(std::vector<Node *> nodes);
+ std::string &name() {return name_;};
+ void addItemToFixedList(MenuItem *item) {itemsFixed_.push_back(item);};
+ void addItemToCustomList(MenuItem *item) {itemsCustom_.push_back(item);};
+ void clearFixedList() {itemsFixed_.clear();}
+ QMenu *generateMenu(std::vector<VInfo_ptr> nodes, QWidget *parent,QMenu* parentMenu,const std::string& view,QList<QAction*>&);
+ std::vector<MenuItem *>& items() {return itemsCombined_;};
+
+private:
+ void buildMenuTitle(std::vector<VInfo_ptr> nodes, QMenu* qmenu);
+
+ std::string name_;
+ std::vector<MenuItem *> itemsFixed_;
+ std::vector<MenuItem *> itemsCustom_;
+ std::vector<MenuItem *> itemsCombined_; // items from config file plus custom commands
+
+};
+
+
+// --------------------------------------------------------------
+// MenuHandler
+// Responsible for creating menus (read from configuration files)
+// and generating 'actual' (i.e. context-dependent filtered)
+// menus at run-time.
+// --------------------------------------------------------------
+
+class MenuHandler
+{
+public:
+ MenuHandler();
+
+ //Menu *createMenu(QString &name);
+ static bool readMenuConfigFile(const std::string &configFile);
+ static MenuItem *invokeMenu(const std::string &menuName, std::vector<VInfo_ptr> nodes, QPoint pos, QWidget *parent,const std::string& view);
+ static bool addItemToMenu(MenuItem *item, const std::string &menuName);
+ static Menu *findMenu(const std::string &name);
+ static MenuItem* newItem(const std::string &name);
+ static void addMenu(Menu *menu) {menus_.push_back(menu);};
+ static void refreshCustomMenuCommands();
+
+private:
+ static MenuItem* findItem(QAction*);
+
+ static std::vector<Menu *> menus_;
+ //static std::vector<MenuItem> items_;
+
+};
+
+
+#endif
diff --git a/Viewer/src/MessageItemWidget.cpp b/Viewer/src/MessageItemWidget.cpp
new file mode 100644
index 0000000..24e9c0b
--- /dev/null
+++ b/Viewer/src/MessageItemWidget.cpp
@@ -0,0 +1,90 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "MessageItemWidget.hpp"
+
+#include "InfoProvider.hpp"
+#include "VReply.hpp"
+
+#include "LogModel.hpp"
+
+static bool firstRun=true;
+
+MessageItemWidget::MessageItemWidget(QWidget *parent) : QWidget(parent)
+{
+ setupUi(this);
+
+ searchTb_->setEnabled(false);
+ searchTb_->setVisible(false);
+ searchLine_->setVisible(false);
+
+ infoProvider_=new MessageProvider(this);
+
+ model_=new LogModel(this);
+
+ treeView_->setProperty("log","1");
+ treeView_->setModel(model_);
+ treeView_->setItemDelegate(new LogDelegate(this));
+
+ syncTb_->hide();
+}
+
+QWidget* MessageItemWidget::realWidget()
+{
+ return this;
+}
+
+void MessageItemWidget::reload(VInfo_ptr info)
+{
+ assert(active_);
+
+ if(suspended_)
+ return;
+
+ clearContents();
+ info_=info;
+
+ if(info_)
+ {
+ infoProvider_->info(info_);
+ }
+}
+
+void MessageItemWidget::clearContents()
+{
+ InfoPanelItem::clear();
+ model_->clearData();
+}
+
+void MessageItemWidget::infoReady(VReply* reply)
+{
+ model_->setData(reply->textVec());
+
+ //Adjust column size if it is the first run
+ if(firstRun && model_->hasData())
+ {
+ firstRun=false;
+ for(int i=0; i < model_->columnCount()-1; i++)
+ {
+ treeView_->resizeColumnToContents(i);
+ }
+ }
+}
+
+void MessageItemWidget::infoProgress(VReply* reply)
+{
+ QString s=QString::fromStdString(reply->text());
+}
+
+void MessageItemWidget::infoFailed(VReply* reply)
+{
+ QString s=QString::fromStdString(reply->errorText());
+}
+
+static InfoPanelItemMaker<MessageItemWidget> maker1("message");
diff --git a/Viewer/src/MessageItemWidget.hpp b/Viewer/src/MessageItemWidget.hpp
new file mode 100644
index 0000000..2d7dbc8
--- /dev/null
+++ b/Viewer/src/MessageItemWidget.hpp
@@ -0,0 +1,44 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef MESSAGEITEMWIDGET_HPP_
+#define MESSAGEITEMWIDGET_HPP_
+
+#include "InfoPanelItem.hpp"
+
+#include "ui_MessageItemWidget.h"
+
+class LogModel;
+
+class MessageItemWidget : public QWidget, public InfoPanelItem, protected Ui::MessageItemWidget
+{
+public:
+ explicit MessageItemWidget(QWidget *parent=0);
+
+ void reload(VInfo_ptr);
+ QWidget* realWidget();
+ void clearContents();
+
+ //From VInfoPresenter
+ void infoReady(VReply*);
+ void infoFailed(VReply*);
+ void infoProgress(VReply*);
+
+ void nodeChanged(const VNode*, const std::vector<ecf::Aspect::Type>&) {}
+ void defsChanged(const std::vector<ecf::Aspect::Type>&) {}
+
+protected:
+ void updateState(const ChangeFlags&) {}
+ LogModel* model_;
+
+};
+
+#endif
+
diff --git a/Viewer/src/MessageItemWidget.ui b/Viewer/src/MessageItemWidget.ui
new file mode 100644
index 0000000..d6653ef
--- /dev/null
+++ b/Viewer/src/MessageItemWidget.ui
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MessageItemWidget</class>
+ <widget class="QWidget" name="MessageItemWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>510</width>
+ <height>465</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="spacing">
+ <number>1</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,0">
+ <property name="spacing">
+ <number>1</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QToolButton" name="searchTb_">
+ <property name="toolTip">
+ <string>Show search bar</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/search_decor.svg</normaloff>:/viewer/search_decor.svg</iconset>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+F</string>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="syncTb_">
+ <property name="toolTip">
+ <string>Refresh messages</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/sync.svg</normaloff>:/viewer/sync.svg</iconset>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="MessageLabel" name="messageLabel_" native="true"/>
+ </item>
+ <item>
+ <widget class="TreeView" name="treeView_">
+ <property name="selectionMode">
+ <enum>QAbstractItemView::ExtendedSelection</enum>
+ </property>
+ <property name="rootIsDecorated">
+ <bool>false</bool>
+ </property>
+ <property name="uniformRowHeights">
+ <bool>true</bool>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="PlainTextSearchLine" name="searchLine_" native="true"/>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>MessageLabel</class>
+ <extends>QWidget</extends>
+ <header location="global">MessageLabel.hpp</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>PlainTextSearchLine</class>
+ <extends>QWidget</extends>
+ <header>PlainTextSearchLine.hpp</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>TreeView</class>
+ <extends>QTreeView</extends>
+ <header location="global">TreeView.hpp</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Viewer/src/MessageLabel.cpp b/Viewer/src/MessageLabel.cpp
new file mode 100644
index 0000000..9ccac6e
--- /dev/null
+++ b/Viewer/src/MessageLabel.cpp
@@ -0,0 +1,233 @@
+// Copyright 2014 ECMWF.
+
+#include "MessageLabel.hpp"
+
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QMovie>
+#include <QProgressBar>
+#include <QVariant>
+#include <QVBoxLayout>
+
+#include "IconProvider.hpp"
+#include "UserMessage.hpp"
+
+#include <map>
+#include <assert.h>
+
+class MessageLabelData {
+public:
+ MessageLabelData(QString iconPath,QString title,QColor bg, QColor bgLight,QColor border) :
+ title_(title), bg_(bg.name()), border_(border.name())
+ {
+ int id=IconProvider::add(iconPath,iconPath);
+ pix_=IconProvider::pixmap(id,16);
+ pixSmall_=IconProvider::pixmap(id,12);
+
+ bg_="qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 " + bg.name() +", stop: 1 " + bgLight.name() + ")";
+ }
+
+ MessageLabelData() {}
+
+ QPixmap pix_;
+ QPixmap pixSmall_;
+ QString title_;
+ QString bg_;
+ QString border_;
+
+};
+
+static std::map<MessageLabel::Type,MessageLabelData> typeData;
+
+MessageLabel::MessageLabel(QWidget *parent) :
+ QWidget(parent),
+ currentType_(NoType),
+ showTypeTitle_(true),
+ narrowMode_(false)
+{
+ setProperty("base","1");
+
+ if(typeData.empty())
+ {
+ QColor bg(236,246,252);
+ QColor bgLight=bg.lighter(105);
+ typeData[InfoType]=MessageLabelData(":/viewer/info.svg","Info",bg,bgLight,QColor(180,194,230));
+
+ bg=QColor(234,215,150);
+ bgLight=bg.lighter(112);
+ typeData[WarningType]=MessageLabelData(":/viewer/warning.svg","Warning",bg,bgLight,QColor(226,195,110)); //255,198,63
+
+ bg=QColor(255,231,231);
+ bgLight=bg.lighter(105);
+ typeData[ErrorType]=MessageLabelData(":/viewer/error.svg","Error",bg,bgLight,QColor(223,152,152));
+ }
+
+ pixLabel_=new QLabel(this);
+ pixLabel_->setAlignment(Qt::AlignCenter);
+
+ msgLabel_=new QLabel(this);
+ msgLabel_->setWordWrap(true);
+ msgLabel_->setTextInteractionFlags(Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse);
+
+ loadLabel_=new QLabel(this);
+
+ //progress widget
+ progLabel_=new QLabel(this);
+ progBar_=new QProgressBar(this);
+ progWidget_=new QWidget(this);
+ QHBoxLayout* progLayout=new QHBoxLayout(progWidget_);
+ progLayout->addWidget(progBar_);
+ progLayout->addWidget(progLabel_);
+
+ layout_=new QHBoxLayout(this);
+ layout_->setContentsMargins(2,2,2,2);
+
+ QVBoxLayout *loadLayout=new QVBoxLayout();
+ loadLayout->addWidget(loadLabel_);
+ loadLayout->addStretch(1);
+ layout_->addLayout(loadLayout);
+
+ QVBoxLayout *pixLayout=new QVBoxLayout();
+ pixLayout->addWidget(pixLabel_);
+ pixLayout->addStretch(1);
+ layout_->addLayout(pixLayout);
+
+ QVBoxLayout* rightVb=new QVBoxLayout;
+ rightVb->addWidget(msgLabel_);
+ rightVb->addWidget(progWidget_);
+ rightVb->addStretch(1);
+ layout_->addLayout(rightVb,1);
+
+ //layout_->addWidget(msgLabel_,1);
+
+ stopLoadLabel();
+ stopProgress();
+
+ hide();
+}
+
+void MessageLabel::clear()
+{
+ msgLabel_->setText("");
+ stopLoadLabel();
+ stopProgress();
+}
+
+void MessageLabel::showInfo(QString msg)
+{
+ showMessage(InfoType,msg);
+}
+
+void MessageLabel::showWarning(QString msg)
+{
+ showMessage(WarningType,msg);
+}
+
+void MessageLabel::showError(QString msg)
+{
+ showMessage(ErrorType,msg);
+}
+
+void MessageLabel::showMessage(const Type& type,QString msg)
+{
+ std::map<Type,MessageLabelData>::const_iterator it=typeData.find(type);
+ assert(it != typeData.end());
+
+ if(type != currentType_)
+ {
+ QString sh="QWidget[base=\"1\"] { \
+ background: " + it->second.bg_ + "; \
+ border: 1px solid " + it->second.border_ + "; \
+ border-radius: 0px;}";
+
+ setStyleSheet(sh);
+
+ pixLabel_->setPixmap(((!narrowMode_)?it->second.pix_:it->second.pixSmall_));
+
+ currentType_=type;
+ }
+
+ QString s=msg;
+ s.replace("\n","<br>");
+ if(showTypeTitle_)
+ s="<b>" + it->second.title_ + ": </b><br>" + s;
+
+ msgLabel_->setText(s);
+
+ show();
+}
+
+void MessageLabel::startLoadLabel()
+{
+ if(!loadLabel_->movie())
+ {
+ QMovie *movie = new QMovie(":viewer/spinning_wheel.gif", QByteArray(), loadLabel_);
+ loadLabel_->setMovie(movie);
+ }
+ loadLabel_->show();
+ loadLabel_->movie()->start();
+}
+
+
+void MessageLabel::stopLoadLabel()
+{
+ if(loadLabel_->movie())
+ {
+ loadLabel_->movie()->stop();
+ }
+
+ loadLabel_->hide();
+}
+
+void MessageLabel::startProgress(int max)
+{
+ Q_ASSERT(max >=0 && max <=100);
+ progBar_->setRange(0,max);
+ progWidget_->show();
+}
+
+void MessageLabel::stopProgress()
+{
+ progWidget_->hide();
+ progLabel_->setText("");
+ progBar_->setRange(0,0);
+}
+
+void MessageLabel::progress(QString text,int value)
+{
+ Q_ASSERT(value >=0 && value <=100);
+
+ if(progBar_->maximum() == 0)
+ progBar_->setMaximum(100);
+
+ progBar_->setValue(value);
+ progLabel_->setText(text);
+
+ //UserMessage::debug("MessageLabel::progress --> " + QString::number(value).toStdString() + "%");
+}
+
+void MessageLabel::setShowTypeTitle(bool b)
+{
+ if(showTypeTitle_ != b)
+ {
+ showTypeTitle_=b;
+ }
+}
+
+void MessageLabel::setNarrowMode(bool b)
+{
+ if(b==narrowMode_)
+ return;
+
+ narrowMode_=b;
+
+ /*if(!narrowMode_)
+ {
+ layout_->setContentsMargins(2,2,2,2);
+ }
+ else
+ {
+ layout_->setContentsMargins(2,0,2,0);
+ }*/
+}
+
diff --git a/Viewer/src/MessageLabel.hpp b/Viewer/src/MessageLabel.hpp
new file mode 100644
index 0000000..4f83e0b
--- /dev/null
+++ b/Viewer/src/MessageLabel.hpp
@@ -0,0 +1,48 @@
+// Copyright 2014 ECMWF.
+
+#ifndef MESSAGELABEL_HPP_
+#define MESSAGELABEL_HPP_
+
+#include <QWidget>
+
+class QHBoxLayout;
+class QLabel;
+class QProgressBar;
+
+class MessageLabel : public QWidget
+{
+public:
+ explicit MessageLabel(QWidget *parent=0);
+
+ enum Type {NoType,InfoType,WarningType,ErrorType};
+
+ void showInfo(QString);
+ void showWarning(QString);
+ void showError(QString);
+ void startLoadLabel();
+ void stopLoadLabel();
+ void startProgress(int max=0);
+ void stopProgress();
+ void progress(QString text,int value);
+ void setShowTypeTitle(bool);
+ void clear();
+ void setNarrowMode(bool);
+
+private:
+ void showMessage(const Type&,QString);
+
+ bool showTypeTitle_;
+ bool narrowMode_;
+ Type currentType_;
+ QLabel *pixLabel_;
+ QLabel* msgLabel_;
+ QLabel* loadLabel_;
+ QHBoxLayout* layout_;
+ QWidget* progWidget_;
+ QLabel* progLabel_;
+ QProgressBar* progBar_;
+
+};
+
+#endif
+
diff --git a/Viewer/src/MeterEditor.cpp b/Viewer/src/MeterEditor.cpp
new file mode 100644
index 0000000..35e06f5
--- /dev/null
+++ b/Viewer/src/MeterEditor.cpp
@@ -0,0 +1,135 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "MeterEditor.hpp"
+
+#include <QDebug>
+#include <QSettings>
+
+#include "AttributeEditorFactory.hpp"
+#include "VAttribute.hpp"
+#include "VAttributeType.hpp"
+#include "ServerHandler.hpp"
+#include "SessionHandler.hpp"
+
+MeterEditorWidget::MeterEditorWidget(QWidget* parent) : QWidget(parent)
+{
+ setupUi(this);
+}
+
+MeterEditor::MeterEditor(VInfo_ptr info,QWidget* parent) : AttributeEditor(info,"meter",parent), oriVal_(0)
+{
+ w_=new MeterEditorWidget(this);
+ addForm(w_);
+
+ VAttribute* a=info_->attribute();
+
+ Q_ASSERT(a);
+ Q_ASSERT(a->type());
+ Q_ASSERT(a->type()->name() == "meter");
+
+ if(a->data().count() < 5)
+ return;
+
+ oriVal_=a->data().at(2).toInt();
+ int min=a->data().at(3).toInt();
+ int max=a->data().at(4).toInt();
+
+ if(min > max || oriVal_ < min || oriVal_ > max)
+ return;
+
+ w_->nameLabel_->setText(a->data().at(1));
+ w_->valueSpin_->setRange(min,max);
+ w_->valueSpin_->setValue(oriVal_);
+
+ w_->minLabel_->setText(a->data().at(3));
+ w_->maxLabel_->setText(a->data().at(4));
+ w_->thresholdLabel_->setText(a->data().at(5));
+
+ w_->valueSpin_->setFocus();
+
+ header_->setInfo(QString::fromStdString(info_->path()),"Meter");
+
+ connect(w_->valueSpin_,SIGNAL(valueChanged(int)),
+ this,SLOT(slotValueChanged(int)));
+
+ checkButtonStatus();
+
+ readSettings();
+}
+
+MeterEditor::~MeterEditor()
+{
+ writeSettings();
+}
+
+void MeterEditor::apply()
+{
+ std::string val=QString::number(w_->valueSpin_->value()).toStdString();
+ std::string name=w_->nameLabel_->text().toStdString();
+
+ std::vector<std::string> cmd;
+ VAttribute::buildAlterCommand(cmd,"change","meter",name,val);
+ ServerHandler::command(info_,cmd);
+}
+
+void MeterEditor::resetValue()
+{
+ w_->valueSpin_->setValue(oriVal_);
+ checkButtonStatus();
+}
+
+void MeterEditor::slotValueChanged(int)
+{
+ checkButtonStatus();
+}
+
+bool MeterEditor::isValueChanged()
+{
+ return (oriVal_ != w_->valueSpin_->value());
+}
+
+void MeterEditor::writeSettings()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ Q_ASSERT(cs);
+ QSettings settings(QString::fromStdString(cs->qtSettingsFile("MeterEditor")),
+ QSettings::NativeFormat);
+
+ //We have to clear it so that should not remember all the previous values
+ settings.clear();
+
+ settings.beginGroup("main");
+ settings.setValue("size",size());
+ settings.endGroup();
+}
+
+void MeterEditor::readSettings()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ Q_ASSERT(cs);
+ QSettings settings(QString::fromStdString(cs->qtSettingsFile("MeterEditor")),
+ QSettings::NativeFormat);
+
+ settings.beginGroup("main");
+ if(settings.contains("size"))
+ {
+ resize(settings.value("size").toSize());
+ }
+ else
+ {
+ resize(QSize(310,200));
+ }
+
+ settings.endGroup();
+}
+
+static AttributeEditorMaker<MeterEditor> makerStr("meter");
+
diff --git a/Viewer/src/MeterEditor.hpp b/Viewer/src/MeterEditor.hpp
new file mode 100644
index 0000000..e6ef276
--- /dev/null
+++ b/Viewer/src/MeterEditor.hpp
@@ -0,0 +1,52 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef METEREDITOR_HPP
+#define METEREDITOR_HPP
+
+#include "ui_MeterEditorWidget.h"
+
+#include "AttributeEditor.hpp"
+#include "VInfo.hpp"
+
+class MeterEditor;
+
+class MeterEditorWidget : public QWidget, protected Ui::MeterEditorWidget
+{
+friend class MeterEditor;
+public:
+ MeterEditorWidget(QWidget *parent=0);
+};
+
+class MeterEditor : public AttributeEditor
+{
+Q_OBJECT
+
+public:
+ MeterEditor(VInfo_ptr,QWidget* parent=0);
+ ~MeterEditor();
+
+protected Q_SLOTS:
+ void slotValueChanged(int);
+
+protected:
+ void apply();
+ void resetValue();
+ bool isValueChanged();
+ void readSettings();
+ void writeSettings();
+
+ MeterEditorWidget* w_;
+ int oriVal_;
+};
+
+#endif // METEREDITOR_HPP
+
+
diff --git a/Viewer/src/MeterEditorWidget.ui b/Viewer/src/MeterEditorWidget.ui
new file mode 100644
index 0000000..79416ec
--- /dev/null
+++ b/Viewer/src/MeterEditorWidget.ui
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MeterEditorWidget</class>
+ <widget class="QWidget" name="MeterEditorWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>329</width>
+ <height>227</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="nameLabel_">
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Value:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QSpinBox" name="valueSpin_"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Minimum:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="minLabel_">
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Maximum:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLabel" name="maxLabel_">
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Threshold:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QLabel" name="thresholdLabel_">
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Viewer/src/ModelColumn.cpp b/Viewer/src/ModelColumn.cpp
new file mode 100644
index 0000000..a81f199
--- /dev/null
+++ b/Viewer/src/ModelColumn.cpp
@@ -0,0 +1,72 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "ModelColumn.hpp"
+
+#include <map>
+
+#include <QDebug>
+
+#include "VConfigLoader.hpp"
+#include "VProperty.hpp"
+
+static std::map<std::string,ModelColumn*> defs;
+
+ModelColumn::ModelColumn(const std::string& id) : id_(id)
+{
+ defs[id_]=this;
+}
+
+ModelColumn* ModelColumn::def(const std::string& id)
+{
+ std::map<std::string,ModelColumn*>::const_iterator it=defs.find(id);
+ if(it != defs.end())
+ return it->second;
+ return NULL;
+}
+
+
+int ModelColumn::indexOf(const std::string& id) const
+{
+ QString idStr=QString::fromStdString(id);
+ for(int i=0; i< items_.count(); i++)
+ {
+ if(items_.at(i)->id_ == idStr)
+ return i;
+ }
+ return -1;
+}
+
+void ModelColumn::load(VProperty* group)
+{
+ ModelColumn* m=new ModelColumn(group->strName());
+
+ for(int i=0; i < group->children().size(); i++)
+ {
+ VProperty *p=group->children().at(i);
+
+ ModelColumnItem* obj=new ModelColumnItem(p->strName());
+ obj->label_=p->param("label");
+ obj->tooltip_=p->param("tooltip");
+ obj->icon_=p->param("icon");
+ obj->index_=i;
+
+ m->items_ << obj;
+
+ }
+}
+
+ModelColumnItem::ModelColumnItem(const std::string& id) : index_(-1)
+{
+ id_=QString::fromStdString(id);
+}
+
+static SimpleLoader<ModelColumn> loaderQuery("query_columns");
+static SimpleLoader<ModelColumn> loaderTable("table_columns");
+static SimpleLoader<ModelColumn> loaderZombie("zombie_columns");
diff --git a/Viewer/src/ModelColumn.hpp b/Viewer/src/ModelColumn.hpp
new file mode 100644
index 0000000..40c3284
--- /dev/null
+++ b/Viewer/src/ModelColumn.hpp
@@ -0,0 +1,58 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef MODELCOLUMN_H
+#define MODELCOLUMN_H
+
+class VProperty;
+
+#include <assert.h>
+
+#include <QList>
+#include <QString>
+
+
+class ModelColumnItem
+{
+friend class ModelColumn;
+public:
+ explicit ModelColumnItem(const std::string& id);
+
+protected:
+ QString label_;
+ QString id_;
+ int index_;
+ QString icon_;
+ QString tooltip_;
+};
+
+
+class ModelColumn
+{
+public:
+ explicit ModelColumn(const std::string& id);
+
+ int count() const {return items_.size();}
+ int indexOf(const std::string&) const;
+ QString id(int i) const {assert(i>=0 && i < count()); return items_.at(i)->id_;}
+ QString label(int i) const {assert(i>=0 && i < count()); return items_.at(i)->label_;}
+ QString tooltip(int i) const {assert(i>=0 && i < count()); return items_.at(i)->tooltip_;}
+
+ static ModelColumn* def(const std::string& id);
+
+ //Called from VConfigLoader
+ static void load(VProperty* group);
+
+protected:
+ std::string id_;
+ QList<ModelColumnItem*> items_;
+};
+
+
+#endif
diff --git a/Viewer/src/NodeExpression.cpp b/Viewer/src/NodeExpression.cpp
new file mode 100644
index 0000000..d632d57
--- /dev/null
+++ b/Viewer/src/NodeExpression.cpp
@@ -0,0 +1,902 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include <QRegExp>
+
+#include <boost/algorithm/string.hpp>
+
+#include "Str.hpp"
+#include "Node.hpp"
+#include "Submittable.hpp"
+
+#include "NodeExpression.hpp"
+#include "ServerHandler.hpp"
+#include "UserMessage.hpp"
+#include "VAttribute.hpp"
+#include "VAttributeType.hpp"
+#include "VNode.hpp"
+
+#include <QDebug>
+
+//#define _UI_NODEXPRESSIONPARSEER_DEBUG
+
+
+// -------------------------
+// Expression parser classes
+// -------------------------
+
+NodeExpressionParser* NodeExpressionParser::instance_=NULL;
+
+
+#if 0
+std::vector<std::string> NodeExpressionParser::tokens_;
+std::vector<std::string>::const_iterator NodeExpressionParser::i_;
+
+std::map<std::string,NodeExpressionParser::NodeType> NodeExpressionParser::nameToNodeType_;
+std::map<NodeExpressionParser::NodeType,std::string> NodeExpressionParser::nodeTypeToName_;
+std::map<std::string,NodeExpressionParser::AttributeType> NodeExpressionParser::nameToAttrType_;
+std::map<NodeExpressionParser::AttributeType,std::string> NodeExpressionParser::attrTypeToName_;
+#endif
+
+NodeExpressionParser* NodeExpressionParser::instance()
+{
+ if(!instance_)
+ instance_=new NodeExpressionParser;
+
+ return instance_;
+}
+
+NodeExpressionParser::NodeExpressionParser()
+{
+ nameToNodeType_["server"]=SERVER;
+ nameToNodeType_["suite"]=SUITE;
+ nameToNodeType_["family"]=FAMILY;
+ nameToNodeType_["task"]=TASK;
+ nameToNodeType_["alias"]=ALIAS;
+ nameToNodeType_["node"]=NODE;
+
+ for(std::map<std::string,NodeType>::const_iterator it=nameToNodeType_.begin(); it != nameToNodeType_.end(); ++it)
+ {
+ nodeTypeToName_[it->second]=it->first;
+ }
+
+ nameToAttrType_["attribute"]=ATTRIBUTE;
+ nameToAttrType_["meter"]=METER;
+ nameToAttrType_["event"]=EVENT;
+ nameToAttrType_["repeat"]=REPEAT;
+ nameToAttrType_["trigger"]=TRIGGER;
+ nameToAttrType_["label"]=LABEL;
+ nameToAttrType_["time"]=TIME;
+ nameToAttrType_["date"]=DATE;
+ nameToAttrType_["late"]=LATE;
+ nameToAttrType_["limit"]=LIMIT;
+ nameToAttrType_["limiter"]=LIMITER;
+ nameToAttrType_["var"]=VAR;
+ nameToAttrType_["genvar"]=GENVAR;
+
+ for(std::map<std::string,AttributeType>::const_iterator it=nameToAttrType_.begin(); it != nameToAttrType_.end(); ++it)
+ {
+ attrTypeToName_[it->second]=it->first;
+ }
+
+ badTypeStr_="BAD";
+ badAttributeStr_="BAD";
+}
+
+NodeExpressionParser::NodeType NodeExpressionParser::nodeType(const std::string &name) const
+{
+ std::map<std::string,NodeType>::const_iterator it=nameToNodeType_.find(name);
+ if(it != nameToNodeType_.end())
+ return it->second;
+
+ return BAD;
+}
+
+const std::string& NodeExpressionParser::typeName(const NodeType& type) const
+{
+ std::map<NodeType,std::string>::const_iterator it=nodeTypeToName_.find(type);
+ if(it != nodeTypeToName_.end())
+ return it->second;
+
+ return badTypeStr_;
+}
+
+NodeExpressionParser::AttributeType NodeExpressionParser::toAttrType(const std::string &name) const
+{
+ std::map<std::string,AttributeType>::const_iterator it=nameToAttrType_.find(name);
+ if(it != nameToAttrType_.end())
+ return it->second;
+
+ return BADATTRIBUTE;
+}
+
+const std::string& NodeExpressionParser::toAttrName(const AttributeType& type) const
+{
+ std::map<AttributeType,std::string>::const_iterator it=attrTypeToName_.find(type);
+ if(it != attrTypeToName_.end())
+ return it->second;
+
+ return badAttributeStr_;
+}
+
+bool NodeExpressionParser::isUserLevel(const std::string &str) const
+{
+ if (str == "oper" || str == "admin")
+ return true;
+
+ return false;
+}
+
+bool NodeExpressionParser::isNodeHasAttribute(const std::string &str) const
+{
+ if (str == "has_triggers" || str == "has_time" || str == "has_date" || str == "locked")
+ return true;
+
+ return false;
+}
+
+bool NodeExpressionParser::isNodeFlag(const std::string &str) const
+{
+ if (str == "is_late" || str == "has_message" ||
+ str == "is_rerun" || str == "is_waiting" || str == "is_zombie")
+ return true;
+
+ return false;
+}
+
+
+bool NodeExpressionParser::isWhatToSearchIn(const std::string &str, bool &isAttr) const
+{
+ // list of non-attribute items that we can search in
+ if (str == "node_name" || str == "node_path")
+ {
+ isAttr = false;
+ return true;
+ }
+
+ // list of attributes that we can search in
+ else if (str == "label_name" || str == "label_value")
+ {
+ isAttr = true;
+ return true;
+ }
+
+ return false;
+}
+
+bool NodeExpressionParser::isAttribute(const std::string &str) const
+{
+ return (nameToAttrType_.find(str) != nameToAttrType_.end());
+}
+
+bool NodeExpressionParser::isAttributeState(const std::string &str) const
+{
+ return (str == "event_set" || str == "event_clear" ||
+ str == "repeat_date" || str == "repeat_int" || str == "repeat_string" || str == "repeat_enum" ||
+ str == "repeat_day");
+}
+
+// NodeExpressionParser::popLastNOperands
+// - utility function to remove and return the last n operands from
+// - the stack
+std::vector<BaseNodeCondition *> NodeExpressionParser::popLastNOperands(std::vector<BaseNodeCondition *> &inOperands, int n)
+{
+ std::vector<BaseNodeCondition *> resultVec;
+
+ for (int i=0; i<n; i++)
+ {
+ resultVec.push_back(inOperands.back());
+ inOperands.pop_back();
+ }
+
+ return resultVec;
+}
+
+
+
+BaseNodeCondition *NodeExpressionParser::parseWholeExpression(std::string expr, bool caseSensitiveStringMatch)
+{
+ std::vector<std::string> tokens;
+ char delimiter = ' ';
+ char insideQuote = '\0'; // \0 if not inside a quote, \' if we are inside a quote
+ // will not handle the case of nested quotes!
+
+ UserMessage::message(UserMessage::DBG, false, std::string("parseWholeExpression: ") + expr);
+
+
+ ecf::Str::replace_all(expr, std::string("("), std::string(" ( "));
+ ecf::Str::replace_all(expr, std::string(")"), std::string(" ) "));
+
+ //boost::algorithm::to_lower(expr); // convert to lowercase
+
+ int index = 0;
+ int length = expr.length();
+ std::string token = "";
+
+
+ // loop through each character in the string
+
+ while (index < length)
+ {
+ char c = expr[index];
+
+ if (c == '\'') // a quote character?
+ {
+ if (insideQuote == '\'') // this is the closing quote
+ insideQuote = '\0'; // note that we are no longer inside a quote
+ else
+ insideQuote = '\''; // this is an opening quote
+ }
+ else if (c == delimiter && insideQuote == '\0') // a delimeter but not inside a quote?
+ {
+ if (token.length()>0)
+ tokens.push_back(token);
+ token ="";
+ }
+ else
+ token += c;
+
+ index++;
+ }
+
+ if(token.length()>0)
+ tokens.push_back(token);
+
+
+ setTokens(tokens);
+
+ return parseExpression(caseSensitiveStringMatch);
+}
+
+
+BaseNodeCondition *NodeExpressionParser::parseExpression(bool caseSensitiveStringMatch)
+{
+ bool returnEarly = false;
+ BaseNodeCondition *result = NULL;
+
+ std::vector<BaseNodeCondition *> funcStack;
+ std::vector<BaseNodeCondition *> operandStack;
+
+
+ // short-circuit - if empty, then return a True condition
+
+ if (tokens_.size() == 0)
+ {
+ result = new TrueNodeCondition();
+ }
+
+
+ while (!returnEarly && i_ != tokens_.end())
+ {
+ bool tokenOk = true;
+ bool updatedOperands = false;
+
+
+ if (i_ != tokens_.end())
+ {
+
+ // are we expecting an arbitrary string?
+ if ((funcStack.size() > 0) && (funcStack.back()->operand2IsArbitraryString()))
+ {
+ WhatToSearchForOperand *whatToSearchFor = new WhatToSearchForOperand(*i_);
+ operandStack.push_back(whatToSearchFor);
+ result = whatToSearchFor;
+ updatedOperands = true;
+ }
+ else
+ {
+ bool attr = false;
+ NodeExpressionParser::AttributeType attrType=NodeExpressionParser::BADATTRIBUTE;
+
+ // node types
+ NodeExpressionParser::NodeType type = nodeType(*i_);
+ if (type != BAD)
+ {
+ TypeNodeCondition *typeCond = new TypeNodeCondition(type);
+ operandStack.push_back(typeCond);
+ result = typeCond;
+ updatedOperands = true;
+ }
+
+ // node/server states
+ else if (DState::isValid(*i_) || VSState::find(*i_))
+ {
+ StateNodeCondition *stateCond = new StateNodeCondition(QString::fromStdString(*i_));
+ operandStack.push_back(stateCond);
+ result = stateCond;
+ updatedOperands = true;
+ }
+
+ // user level
+ else if (isUserLevel(*i_))
+ {
+ UserLevelCondition *userCond = new UserLevelCondition(QString::fromStdString(*i_));
+ operandStack.push_back(userCond);
+ result = userCond;
+ updatedOperands = true;
+ }
+
+ // node attribute
+ else if (isNodeHasAttribute(*i_))
+ {
+ NodeAttributeCondition *attrCond = new NodeAttributeCondition(QString::fromStdString(*i_));
+ operandStack.push_back(attrCond);
+ result = attrCond;
+ updatedOperands = true;
+ }
+ // node flag
+ else if (isNodeFlag(*i_))
+ {
+ NodeFlagCondition *flagCond = new NodeFlagCondition(QString::fromStdString(*i_));
+ operandStack.push_back(flagCond);
+ result = flagCond;
+ updatedOperands = true;
+ }
+
+ // node attribute
+ else if ((attrType = toAttrType(*i_)) != NodeExpressionParser::BADATTRIBUTE)
+ {
+ AttributeCondition *attrCond = new AttributeCondition(attrType);
+ operandStack.push_back(attrCond);
+ result = attrCond;
+ updatedOperands = true;
+ }
+
+ // node attribute state
+ else if (isAttributeState(*i_))
+ {
+ AttributeStateCondition *attrStateCond = new AttributeStateCondition(QString::fromStdString(*i_));
+ operandStack.push_back(attrStateCond);
+ result = attrStateCond;
+ updatedOperands = true;
+ }
+
+ else if (isWhatToSearchIn(*i_, attr))
+ {
+ WhatToSearchInOperand *searchCond = new WhatToSearchInOperand(*i_, attr);
+ operandStack.push_back(searchCond);
+ result = searchCond;
+ updatedOperands = true;
+ }
+
+ // logical operators
+ else if (*i_ == "and")
+ {
+ AndNodeCondition *andCond = new AndNodeCondition();
+ funcStack.push_back(andCond);
+ result = andCond;
+ }
+
+ else if (*i_ == "or")
+ {
+ OrNodeCondition *orCond = new OrNodeCondition();
+ funcStack.push_back(orCond);
+ result = orCond;
+ }
+
+ else if (*i_ == "not")
+ {
+ NotNodeCondition *notCond = new NotNodeCondition();
+ funcStack.push_back(notCond);
+ result = notCond;
+ }
+
+ else if(StringMatchMode::operToMode(*i_) != StringMatchMode::InvalidMatch)
+ {
+ StringMatchCondition *stringMatchCond = new StringMatchCondition(StringMatchMode::operToMode(*i_), caseSensitiveStringMatch);
+ funcStack.push_back(stringMatchCond);
+ result = stringMatchCond;
+ }
+
+ else if (*i_ == "(")
+ {
+ ++i_;
+ result = parseExpression(caseSensitiveStringMatch);
+ operandStack.push_back(result);
+ }
+ else if (*i_ == ")")
+ {
+ returnEarly = true;
+ }
+
+ else
+ {
+ tokenOk = false;
+ }
+ }
+ }
+
+ else
+ {
+ // got to the end of the tokens, but we may still need to
+ // update the condition stacks
+ updatedOperands = true;
+ }
+
+
+ if (tokenOk)
+ {
+ // if there are enough operands on the stack for the last
+ // function, pop them off and create a small tree for that function
+ // but do not do this if the last function asks to delay this process
+ if (!funcStack.empty() && !funcStack.back()->delayUnwinding())
+ {
+ if(updatedOperands && (operandStack.size() >= funcStack.back()->numOperands()))
+ {
+ std::vector<BaseNodeCondition *> operands;
+ result = funcStack.back(); // last function is the current result
+ operands = popLastNOperands(operandStack, result->numOperands()); // pop its operands off the stack
+ result->setOperands(operands);
+ funcStack.pop_back(); // remove the last function from the stack
+ operandStack.push_back(result); // store the current result
+ }
+ }
+ }
+ else
+ {
+ UserMessage::message(UserMessage::ERROR, false, std::string("Error parsing expression " + *i_));
+ result = new FalseNodeCondition();
+ return result;
+ }
+
+ if (i_ != tokens_.end() && !returnEarly)
+ ++i_; // move onto the next token
+ }
+
+
+ // final unwinding of the stack
+ while (!funcStack.empty())
+ {
+ if(operandStack.size() >= funcStack.back()->numOperands())
+ {
+ std::vector<BaseNodeCondition *> operands;
+ result = funcStack.back(); // last function is the current result
+ operands = popLastNOperands(operandStack, result->numOperands()); // pop its operands off the stack
+ result->setOperands(operands);
+ funcStack.pop_back(); // remove the last function from the stack
+ operandStack.push_back(result); // store the current result
+ }
+ }
+
+
+ UserMessage::message(UserMessage::DBG, false, std::string(" ") + result->print());
+
+ return result;
+}
+
+
+bool BaseNodeCondition::execute(VInfo_ptr nodeInfo)
+{
+ if(!nodeInfo)
+ return true;
+
+ if(nodeInfo->isServer())
+ return execute(nodeInfo->server()->vRoot());
+ else if(nodeInfo->isNode())
+ return execute(nodeInfo->node());
+ else if(nodeInfo->isAttribute())
+ return execute(nodeInfo->attribute());
+
+ return false;
+}
+
+// -----------------------------------------------------------------
+
+bool BaseNodeCondition::containsAttributeSearch()
+{
+ bool contains = false;
+
+ // check child condition nodes
+ for (int i = 0; i < operands_.size(); i++)
+ {
+ contains = contains | operands_[i]->containsAttributeSearch();
+ }
+
+ // check this condition node
+ contains = contains | searchInAttributes();
+
+ return contains;
+}
+
+//=========================================================================
+//
+// AndNodeCondition
+//
+//=========================================================================
+
+bool AndNodeCondition::execute(VItem* node)
+{
+ return operands_[0]->execute(node) && operands_[1]->execute(node);
+}
+
+//=========================================================================
+//
+// OrNodeCondition
+//
+//=========================================================================
+
+bool OrNodeCondition::execute(VItem* node)
+{
+#ifdef _UI_NODEXPRESSIONPARSEER_DEBUG
+ UserMessage::debug("OrNodeCondition::execute --->");
+ qDebug() << operands_[0]->execute(node) << operands_[1]->execute(node);
+#endif
+ return operands_[0]->execute(node) || operands_[1]->execute(node);
+}
+
+
+//=========================================================================
+//
+// NotNodeCondition
+//
+//=========================================================================
+
+bool NotNodeCondition::execute(VItem* node)
+{
+ return !(operands_[0]->execute(node));
+}
+
+//=========================================================================
+//
+// TypeNodeCondition
+//
+//=========================================================================
+
+bool TypeNodeCondition::execute(VItem* item)
+{
+ if (type_ == NodeExpressionParser::SERVER)
+ {
+ return (item->isServer() != NULL);
+ }
+
+ else if(item->isNode())
+ {
+#ifdef _UI_NODEXPRESSIONPARSEER_DEBUG
+ UserMessage::debug("TypeNodeCondition::execute --> " + NodeExpressionParser::instance()->typeName(type_));
+#endif
+ //qDebug() << item->isNode() << item->isSuite() << item->isFamily() << item->isTask() << item->isAlias();
+
+ switch(type_)
+ {
+ case NodeExpressionParser::NODE:
+#ifdef _UI_NODEXPRESSIONPARSEER_DEBUG
+ UserMessage::debug(" NODE");
+#endif
+ return true;
+ break;
+ case NodeExpressionParser::SUITE:
+#ifdef _UI_NODEXPRESSIONPARSEER_DEBUG
+ UserMessage::debug(" SUITE");
+#endif
+ return (item->isSuite() != NULL);
+ break;
+ case NodeExpressionParser::TASK:
+#ifdef _UI_NODEXPRESSIONPARSEER_DEBUG
+ UserMessage::debug(" TASK");
+#endif
+ return (item->isTask() != NULL);
+ break;
+ case NodeExpressionParser::FAMILY:
+#ifdef _UI_NODEXPRESSIONPARSEER_DEBUG
+ UserMessage::debug(" FAMILY");
+#endif
+ return (item->isFamily() != NULL);
+ break;
+ case NodeExpressionParser::ALIAS:
+#ifdef _UI_NODEXPRESSIONPARSEER_DEBUG
+ UserMessage::debug(" ALIAS");
+#endif
+ return (item->isAlias() != NULL);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return false;
+}
+
+//=========================================================================
+//
+// StateNodeCondition
+//
+//=========================================================================
+
+bool StateNodeCondition::execute(VItem* item)
+{
+ if(item->isServer())
+ {
+ VServer* s=static_cast<VServer*>(item);
+ assert(s);
+ return (s->serverStateName() == stateName_);
+ }
+ else
+ {
+ VNode* n=static_cast<VNode*>(item);
+ assert(n);
+ return (n->stateName() == stateName_);
+ }
+ return false;
+}
+
+//=========================================================================
+//
+// UserLevelCondition
+//
+//=========================================================================
+
+bool UserLevelCondition::execute(VItem*)
+{
+ // since we don't currently have the concept of user levels, we just
+ // return true for now
+
+ return true;
+}
+
+
+//=========================================================================
+//
+// String match utility functions
+//
+//=========================================================================
+
+bool StringMatchExact::match(std::string searchFor, std::string searchIn)
+{
+ return searchFor == searchIn;
+}
+
+bool StringMatchContains::match(std::string searchFor, std::string searchIn)
+{
+ Qt::CaseSensitivity cs = (caseSensitive_) ? Qt::CaseSensitive : Qt::CaseInsensitive;
+ QRegExp regexp(QString::fromStdString(searchFor), cs);
+ int index = regexp.indexIn(QString::fromStdString(searchIn));
+ return (index != -1); // -1 means no match
+}
+
+bool StringMatchWildcard::match(std::string searchFor, std::string searchIn)
+{
+ Qt::CaseSensitivity cs = (caseSensitive_) ? Qt::CaseSensitive : Qt::CaseInsensitive;
+ QRegExp regexp(QString::fromStdString(searchFor), cs);
+ regexp.setPatternSyntax(QRegExp::Wildcard);
+ return regexp.exactMatch(QString::fromStdString(searchIn));
+}
+
+bool StringMatchRegexp::match(std::string searchFor, std::string searchIn)
+{
+ Qt::CaseSensitivity cs = (caseSensitive_) ? Qt::CaseSensitive : Qt::CaseInsensitive;
+ QRegExp regexp(QString::fromStdString(searchFor), cs);
+ return regexp.exactMatch(QString::fromStdString(searchIn));
+}
+
+//=========================================================================
+//
+// String match condition
+//
+//=========================================================================
+
+StringMatchCondition::StringMatchCondition(StringMatchMode::Mode matchMode, bool caseSensitive)
+{
+ switch (matchMode)
+ {
+ case StringMatchMode::ContainsMatch:
+ matcher_ = new StringMatchContains(caseSensitive);
+ break;
+ case StringMatchMode::WildcardMatch:
+ matcher_ = new StringMatchWildcard(caseSensitive);
+ break;
+ case StringMatchMode::RegexpMatch:
+ matcher_ = new StringMatchRegexp(caseSensitive);
+ break;
+ default:
+ UserMessage::message(UserMessage::ERROR, false, "StringMatchCondition: bad matchMode");
+ matcher_ = new StringMatchExact(caseSensitive);
+ break;
+ }
+}
+
+
+
+bool StringMatchCondition::execute(VItem *item)
+{
+ WhatToSearchForOperand *searchForOperand = static_cast<WhatToSearchForOperand*> (operands_[0]);
+ WhatToSearchInOperand *searchInOperand = static_cast<WhatToSearchInOperand*> (operands_[1]);
+
+ std::string searchIn = searchInOperand->what();
+
+ if(item->isNode())
+ {
+ VNode* n=static_cast<VNode*>(item);
+ //TODO XXXX check - name, label, variable, etc
+ if(searchIn == "node_name")
+ {
+ return matcher_->match(searchForOperand->what(), n->strName());
+ }
+
+ else if (searchIn == "node_path")
+ {
+ return matcher_->match(searchForOperand->what(), n->absNodePath());
+ }
+ }
+
+ return false;
+}
+
+// -----------------------------------------------------------------
+
+bool NodeAttributeCondition::execute(VItem* item)
+{
+ if (item->isServer())
+ {
+ if(nodeAttrName_ == "locked")
+ {
+ return false; // XXX temporary for now
+ }
+ }
+
+ else if(item->isNode())
+ {
+ VNode* n=static_cast<VNode*>(item);
+ node_ptr node = n->node();
+
+ if (nodeAttrName_ == "has_time")
+ {
+ return (node->timeVec().size() > 0 ||
+ node->todayVec().size() > 0 ||
+ node->crons().size() > 0);
+ }
+ else if (nodeAttrName_ == "has_date")
+ {
+ return (node->days().size() > 0 ||
+ node->dates().size() > 0);
+ }
+ else if (nodeAttrName_ == "has_triggers")
+ {
+ return (node->triggerAst() ||
+ node->completeAst());
+ }
+ }
+
+ return false;
+}
+// -----------------------------------------------------------------
+
+bool NodeFlagCondition::execute(VItem* item)
+{
+ if(item->isServer())
+ {
+ return false;
+ }
+ else if(item->isNode())
+ {
+ VNode* vnode=static_cast<VNode*>(item);
+
+ if(nodeFlagName_ == "is_zombie")
+ return vnode->isFlagSet(ecf::Flag::ZOMBIE);
+
+ if(nodeFlagName_ == "has_message")
+ return vnode->isFlagSet(ecf::Flag::MESSAGE);
+
+ else if(nodeFlagName_ == "is_late")
+ return vnode->isFlagSet(ecf::Flag::LATE);
+
+ else if(nodeFlagName_ == "is_rerun")
+ {
+ node_ptr node=vnode->node();
+ if(!node.get()) return false;
+
+ if(Submittable* s = node->isSubmittable())
+ {
+ return (s->try_no() > 1);
+ }
+ return false;
+ }
+ else if(nodeFlagName_ == "is_waiting")
+ return vnode->isFlagSet(ecf::Flag::WAIT);
+
+ }
+
+ return false;
+}
+
+WhatToSearchInOperand::WhatToSearchInOperand(std::string what, bool &attr)
+{
+ what_ = what;
+ searchInAttributes_ = attr;
+}
+
+
+WhatToSearchInOperand::~WhatToSearchInOperand() {}
+WhatToSearchForOperand::~WhatToSearchForOperand() {}
+
+//====================================================
+//
+// Attribute condition
+//
+//====================================================
+
+bool AttributeCondition::execute(VItem* item)
+{
+ if(!item)
+ return false;
+
+ VAttribute* a=item->isAttribute();
+ if(!a)
+ return false;
+
+ assert(a->type());
+
+ switch(type_)
+ {
+ case NodeExpressionParser::ATTRIBUTE:
+ return true;
+ case NodeExpressionParser::LABEL:
+ return a->type()->name() == "label";
+ case NodeExpressionParser::METER:
+ return a->type()->name() == "meter";
+ case NodeExpressionParser::EVENT:
+ return a->type()->name() == "event";
+ case NodeExpressionParser::LIMIT:
+ return a->type()->name() == "limit";
+ case NodeExpressionParser::REPEAT:
+ return a->type()->name() == "repeat";
+ default:
+ break;
+ }
+
+ return false;
+}
+
+//====================================================
+//
+// Attribute state condition
+//
+//====================================================
+
+bool AttributeStateCondition::execute(VItem* item)
+{
+ if(!item)
+ return false;
+
+ VAttribute* a=item->isAttribute();
+ if(!a)
+ return false;
+
+ assert(a->type());
+
+ if(attrState_.startsWith("event_"))
+ {
+ if(a->type()->name() == "event" && a->data().count() >= 3)
+ {
+ QString v=a->data()[2];
+ if(attrState_ == "event_set")
+ return v == "1";
+ else if(attrState_ == "event_clear")
+ return v == "0";
+ }
+ }
+ else if(attrState_.startsWith("repeat_"))
+ {
+ if(a->type()->name() == "repeat" && a->data().count() >= 2)
+ {
+ QString v=a->data()[1];
+ if(attrState_ == "repeat_date")
+ return v == "date";
+ else if(attrState_ == "repeat_int")
+ return v == "integer";
+ else if(attrState_ == "repeat_string")
+ return v == "string";
+ else if(attrState_ == "repeat_enum")
+ return v == "enumeration";
+ else if(attrState_ == "repeat_day")
+ return v == "day";
+ }
+ }
+ return false;
+}
diff --git a/Viewer/src/NodeExpression.hpp b/Viewer/src/NodeExpression.hpp
new file mode 100644
index 0000000..5379d87
--- /dev/null
+++ b/Viewer/src/NodeExpression.hpp
@@ -0,0 +1,421 @@
+#ifndef NODEEXPRESSION_HPP_
+#define NODEEXPRESSION_HPP_
+
+//============================================================================
+// Copyright 2015 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "DState.hpp"
+
+#include "VInfo.hpp"
+#include "VItem.hpp"
+#include "VNState.hpp"
+#include "VSState.hpp"
+#include "StringMatchMode.hpp"
+
+class VItem;
+
+// ----------------------
+// Node condition classes
+// ----------------------
+
+class BaseNodeCondition; // forward declaration
+
+class NodeExpressionParser
+{
+public:
+ enum NodeType {SERVER, SUITE, FAMILY, TASK, ALIAS, NODE, BAD};
+
+ enum AttributeType {ATTRIBUTE, METER, EVENT, REPEAT, TRIGGER, LABEL, TIME, DATE,
+ LATE, LIMIT, LIMITER, VAR, GENVAR, BADATTRIBUTE};
+
+ static NodeExpressionParser* instance();
+
+ BaseNodeCondition *parseWholeExpression(std::string, bool caseSensitiveStringMatch=true);
+
+ NodeType nodeType(const std::string &name) const;
+ const std::string& typeName(const NodeType&) const;
+ AttributeType toAttrType(const std::string &name) const;
+ const std::string& toAttrName(const AttributeType&) const;
+
+protected:
+ NodeExpressionParser();
+
+ bool isUserLevel(const std::string &str) const;
+ bool isNodeHasAttribute(const std::string &str) const;
+ bool isNodeFlag(const std::string &str) const;
+ bool isWhatToSearchIn(const std::string &str, bool &isAttribute) const;
+ bool isAttribute(const std::string &str) const;
+ bool isAttributeState(const std::string &str) const;
+
+ BaseNodeCondition *parseExpression(bool caseSensitiveStringMatch);
+ void setTokens(std::vector<std::string> &tokens) {tokens_ = tokens; i_ = tokens_.begin();}
+ std::vector<BaseNodeCondition *> popLastNOperands(std::vector<BaseNodeCondition *> &inOperands, int n);
+
+ static NodeExpressionParser* instance_;
+ std::vector<std::string> tokens_;
+ std::vector<std::string>::const_iterator i_;
+ std::map<std::string,NodeType> nameToNodeType_;
+ std::map<NodeType,std::string> nodeTypeToName_;
+ std::map<std::string,AttributeType> nameToAttrType_;
+ std::map<AttributeType,std::string> attrTypeToName_;
+ std::string badTypeStr_;
+ std::string badAttributeStr_;
+};
+
+
+
+// -----------------------------------------------------------------
+// BaseNodeCondition
+// The parent class for all node conditions.
+// delayUnwinding: choose whether to unwind the function stack
+// immediately after parsing this condition, or delay until we've
+// reached the end of the current sub-expression. Set to true for
+// loosely-coupled operators such as 'and', and set to false for
+// others which need to consume their arguments immediately.
+// -----------------------------------------------------------------
+
+class BaseNodeCondition
+{
+public:
+ BaseNodeCondition() {delayUnwinding_ = false;}
+ virtual ~BaseNodeCondition() {}
+
+ bool execute(VInfo_ptr nodeInfo);
+ virtual bool execute(VItem* item)=0;
+
+ virtual int numOperands() {return 0;}
+ virtual std::string print() = 0;
+ virtual bool operand2IsArbitraryString() {return false;}
+
+ void setOperands(std::vector<BaseNodeCondition *> ops) {operands_ = ops;}
+ bool containsAttributeSearch();
+ bool delayUnwinding() {return delayUnwinding_;}
+
+protected:
+ virtual bool searchInAttributes() {return false;}
+
+ std::vector<BaseNodeCondition *> operands_;
+ bool delayUnwinding_;
+};
+
+// -----------------------------------------------------------------
+
+class AndNodeCondition : public BaseNodeCondition
+{
+public:
+ AndNodeCondition() {delayUnwinding_ = true;}
+ ~AndNodeCondition() {}
+
+ bool execute(VItem* node);
+ int numOperands() {return 2;}
+ std::string print() {return std::string("and") + "(" + operands_[0]->print() + "," + operands_[1]->print() + ")";}
+};
+
+// -----------------------------------------------------------------
+
+class OrNodeCondition : public BaseNodeCondition
+{
+public:
+ OrNodeCondition() {delayUnwinding_ = true;}
+ ~OrNodeCondition() {}
+
+ bool execute(VItem* node);
+ int numOperands() {return 2;}
+ std::string print() {return std::string("or") + "(" + operands_[0]->print() + "," + operands_[1]->print() + ")";}
+};
+
+// -----------------------------------------------------------------
+
+class NotNodeCondition : public BaseNodeCondition
+{
+public:
+ NotNodeCondition() {}
+ ~NotNodeCondition() {}
+
+ bool execute(VItem* node);
+ int numOperands() {return 1;}
+ std::string print() {return std::string("not") + "(" + operands_[0]->print() + ")";}
+};
+
+
+
+// --------------------------------
+// String matching utitlity classes
+// --------------------------------
+
+// note that it would be ideal for the match() function to take references to strings
+// for efficiency, but this is not always possible.
+
+class StringMatchBase
+{
+public:
+ StringMatchBase(bool caseSensitive) {caseSensitive_ = caseSensitive;}
+ virtual ~StringMatchBase() {}
+
+ virtual bool match(std::string searchFor, std::string searchIn) = 0;
+
+protected:
+ bool caseSensitive_;
+};
+
+class StringMatchExact : public StringMatchBase
+{
+public:
+ StringMatchExact(bool caseSensitive) : StringMatchBase(caseSensitive) {}
+ ~StringMatchExact() {}
+
+ bool match(std::string searchFor, std::string searchIn);
+};
+
+class StringMatchContains : public StringMatchBase
+{
+public:
+ StringMatchContains(bool caseSensitive) : StringMatchBase(caseSensitive) {}
+ ~StringMatchContains() {}
+
+ bool match(std::string searchFor, std::string searchIn);
+};
+
+class StringMatchWildcard : public StringMatchBase
+{
+public:
+ StringMatchWildcard(bool caseSensitive) : StringMatchBase(caseSensitive) {}
+ ~StringMatchWildcard() {}
+
+ bool match(std::string searchFor, std::string searchIn);
+};
+
+class StringMatchRegexp : public StringMatchBase
+{
+public:
+ StringMatchRegexp(bool caseSensitive) : StringMatchBase(caseSensitive) {}
+ ~StringMatchRegexp() {}
+
+ bool match(std::string searchFor, std::string searchIn);
+};
+
+// -----------------------------------------------------------------
+
+// -------------------------
+// String matching condition
+// -------------------------
+
+class StringMatchCondition : public BaseNodeCondition
+{
+public:
+ StringMatchCondition(StringMatchMode::Mode matchMode, bool caseSensitive);
+ ~StringMatchCondition() {if (matcher_) delete matcher_;}
+
+ bool execute(VItem *node);
+ int numOperands() {return 2;}
+ std::string print() {return operands_[0]->print() + " = " + operands_[1]->print();}
+ bool operand2IsArbitraryString() {return true;}
+private:
+ StringMatchBase *matcher_;
+};
+
+// -----------------------------------------------------------------
+
+// ---------------------------
+// Basic true/false conditions
+// ---------------------------
+
+class TrueNodeCondition : public BaseNodeCondition
+{
+public:
+ TrueNodeCondition() {}
+ ~TrueNodeCondition() {}
+
+ bool execute(VItem*) {return true;}
+ std::string print() {return std::string("true");}
+};
+
+class FalseNodeCondition : public BaseNodeCondition
+{
+public:
+ FalseNodeCondition() {}
+ ~FalseNodeCondition() {}
+
+ bool execute(VItem*) {return false;}
+ std::string print() {return std::string("false");}
+};
+
+// -----------------------------------------------------------------
+
+// -------------------
+// Node type condition
+// -------------------
+
+class TypeNodeCondition : public BaseNodeCondition
+{
+public:
+ explicit TypeNodeCondition(NodeExpressionParser::NodeType type) {type_ = type;}
+ ~TypeNodeCondition() {}
+
+ bool execute(VItem* node);
+ std::string print() {return NodeExpressionParser::instance()->typeName(type_);}
+
+private:
+ NodeExpressionParser::NodeType type_;
+};
+
+// -----------------------------------------------------------------
+
+// --------------------
+// Node state condition
+// --------------------
+
+class StateNodeCondition : public BaseNodeCondition
+{
+public:
+ explicit StateNodeCondition(QString stateName) {stateName_ = stateName;}
+ ~StateNodeCondition() {}
+
+ bool execute(VItem* node);
+ std::string print() {return stateName_.toStdString();}
+
+private:
+ QString stateName_;
+};
+
+// -----------------------------------------------------------------
+
+// --------------------
+// User level condition
+// --------------------
+
+class UserLevelCondition : public BaseNodeCondition
+{
+public:
+ explicit UserLevelCondition(QString userLevelName) {userLevelName_ = userLevelName;}
+ ~UserLevelCondition() {}
+
+ bool execute(VItem*);
+ std::string print() {return userLevelName_.toStdString();}
+
+private:
+ QString userLevelName_;
+};
+
+// -----------------------------------------------------------------
+
+// ------------------------
+// Node attribute condition
+// ------------------------
+
+class NodeAttributeCondition : public BaseNodeCondition
+{
+public:
+ explicit NodeAttributeCondition(QString nodeAttrName) {nodeAttrName_ = nodeAttrName;}
+ ~NodeAttributeCondition() {}
+
+ bool execute(VItem*);
+ std::string print() {return nodeAttrName_.toStdString();}
+
+private:
+ QString nodeAttrName_;
+};
+
+// -----------------------------------------------------------------
+
+// ------------------------
+// Node flag condition
+// ------------------------
+
+class NodeFlagCondition : public BaseNodeCondition
+{
+public:
+ explicit NodeFlagCondition(QString nodeFlagName) {nodeFlagName_ = nodeFlagName;}
+ ~NodeFlagCondition() {}
+
+ bool execute(VItem*);
+ std::string print() {return nodeFlagName_.toStdString();}
+
+private:
+ QString nodeFlagName_;
+};
+// -----------------------------------------------------------------
+
+// -----------------
+// Search conditions
+// -----------------
+
+class WhatToSearchInOperand : public BaseNodeCondition
+{
+public:
+ explicit WhatToSearchInOperand(std::string what, bool &attr);
+ ~WhatToSearchInOperand();
+
+ std::string name() {return what_;}
+ bool execute(VItem* node) {return false;} // not called
+ std::string print() {return what_;}
+ std::string what() {return what_;}
+
+private:
+ std::string what_; // TODO XXX: optimise - we should store an enum here
+ bool searchInAttributes_;
+
+ void searchInAttributes(bool attr) {searchInAttributes_ = attr;}
+ bool searchInAttributes() {return searchInAttributes_;}
+};
+
+// -----------------------------------------------------------------
+
+class WhatToSearchForOperand : public BaseNodeCondition
+{
+public:
+ explicit WhatToSearchForOperand(std::string what) {what_ = what;}
+ ~WhatToSearchForOperand();
+
+ std::string name() {return what_;}
+ bool execute(VItem* node) {return false;} // not called
+ std::string print() {return what_;}
+ std::string what() {return what_;}
+
+private:
+ std::string what_;
+};
+
+// ------------------------
+// Attribute condition
+// ------------------------
+
+class AttributeCondition : public BaseNodeCondition
+{
+public:
+ explicit AttributeCondition(NodeExpressionParser::AttributeType type) {type_ = type;}
+ ~AttributeCondition() {}
+
+ bool execute(VItem*);
+ std::string print() {return NodeExpressionParser::instance()->toAttrName(type_);}
+
+private:
+ NodeExpressionParser::AttributeType type_;
+};
+
+//---------------------------------
+// Node attribute state condition
+// ----------------------------
+
+class AttributeStateCondition : public BaseNodeCondition
+{
+public:
+ explicit AttributeStateCondition(QString attrState) {attrState_ = attrState;}
+ ~AttributeStateCondition() {}
+
+ bool execute(VItem*);
+ std::string print() {return attrState_.toStdString();}
+
+private:
+ QString attrState_;
+};
+
+
+
+#endif
diff --git a/Viewer/src/NodeFilterDialog.cpp b/Viewer/src/NodeFilterDialog.cpp
new file mode 100644
index 0000000..74029d4
--- /dev/null
+++ b/Viewer/src/NodeFilterDialog.cpp
@@ -0,0 +1,126 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include <QCloseEvent>
+#include <QDebug>
+#include <QSettings>
+
+#include "NodeFilterDialog.hpp"
+#include "SessionHandler.hpp"
+#include "VConfig.hpp"
+
+NodeFilterDialog::NodeFilterDialog(QWidget *parent) :
+ QDialog(parent)
+{
+ setupUi(this);
+
+ //setAttribute(Qt::WA_DeleteOnClose);
+
+ QString wt=windowTitle();
+ wt+=" - " + QString::fromStdString(VConfig::instance()->appLongName());
+ setWindowTitle(wt);
+
+ connect(applyPb_,SIGNAL(clicked()),
+ this,SLOT(accept()));
+
+ connect(cancelPb_,SIGNAL(clicked()),
+ this,SLOT(reject()));
+
+ editor_->setQueryTeCanExpand(true);
+
+
+ //Read the qt settings
+ readSettings();
+}
+
+NodeFilterDialog::~NodeFilterDialog()
+{
+}
+
+void NodeFilterDialog::setQuery(NodeQuery* q)
+{
+ editor_->setQuery(q);
+}
+
+NodeQuery* NodeFilterDialog::query() const
+{
+ return editor_->query();
+}
+
+void NodeFilterDialog::setServerFilter(ServerFilter* sf)
+{
+ editor_->setServerFilter(sf);
+}
+
+void NodeFilterDialog::closeEvent(QCloseEvent * event)
+{
+ event->accept();
+ writeSettings();
+}
+
+void NodeFilterDialog::accept()
+{
+ writeSettings();
+ QDialog::accept();
+}
+
+
+void NodeFilterDialog::reject()
+{
+ writeSettings();
+ QDialog::reject();
+}
+
+//------------------------------------------
+// Settings read/write
+//------------------------------------------
+
+void NodeFilterDialog::writeSettings()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ Q_ASSERT(cs);
+ QSettings settings(QString::fromStdString(cs->qtSettingsFile("NodeFilterDialog")),
+ QSettings::NativeFormat);
+
+ //We have to clear it so that should not remember all the previous values
+ settings.clear();
+
+ settings.beginGroup("main");
+ settings.setValue("size",size());
+ //settings.setValue("current",list_->currentRow());
+ settings.endGroup();
+}
+
+void NodeFilterDialog::readSettings()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ Q_ASSERT(cs);
+ QSettings settings(QString::fromStdString(cs->qtSettingsFile("NodeFilterDialog")),
+ QSettings::NativeFormat);
+
+ settings.beginGroup("main");
+ if(settings.contains("size"))
+ {
+ resize(settings.value("size").toSize());
+ }
+ else
+ {
+ resize(QSize(550,540));
+ }
+
+ /*if(settings.contains("current"))
+ {
+ int current=settings.value("current").toInt();
+ if(current >=0)
+ list_->setCurrentRow(current);
+ }*/
+ settings.endGroup();
+}
+
diff --git a/Viewer/src/NodeFilterDialog.hpp b/Viewer/src/NodeFilterDialog.hpp
new file mode 100644
index 0000000..78364b5
--- /dev/null
+++ b/Viewer/src/NodeFilterDialog.hpp
@@ -0,0 +1,46 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VIEWER_SRC_NODEFILTERDIALOG_HPP_
+#define VIEWER_SRC_NODEFILTERDIALOG_HPP_
+
+#include <QDialog>
+
+#include "ui_NodeFilterDialog.h"
+
+class ServerFilter;
+
+class NodeFilterDialog : public QDialog, protected Ui::NodeFilterDialog
+{
+ Q_OBJECT
+
+public:
+ explicit NodeFilterDialog(QWidget *parent = 0);
+ ~NodeFilterDialog();
+
+ void setQuery(NodeQuery*);
+ NodeQuery* query() const;
+ void setServerFilter(ServerFilter*);
+
+protected Q_SLOTS:
+ void accept();
+ void reject();
+
+protected:
+ void closeEvent(QCloseEvent * event);
+
+private:
+ void readSettings();
+ void writeSettings();
+};
+
+
+
+#endif /* VIEWER_SRC_NODEFILTERDIALOG_HPP_ */
diff --git a/Viewer/src/NodeFilterDialog.ui b/Viewer/src/NodeFilterDialog.ui
new file mode 100644
index 0000000..220fa8e
--- /dev/null
+++ b/Viewer/src/NodeFilterDialog.ui
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>NodeFilterDialog</class>
+ <widget class="QDialog" name="NodeFilterDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>738</width>
+ <height>696</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Table filter</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0">
+ <item>
+ <widget class="NodeQueryEditor" name="editor_" native="true"/>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QPushButton" name="applyPb_">
+ <property name="text">
+ <string>Apply</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/submit.svg</normaloff>:/viewer/submit.svg</iconset>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="cancelPb_">
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>NodeQueryEditor</class>
+ <extends>QWidget</extends>
+ <header>NodeQueryEditor.hpp</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources>
+ <include location="viewer.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/Viewer/src/NodeObserver.hpp b/Viewer/src/NodeObserver.hpp
new file mode 100644
index 0000000..4deab1d
--- /dev/null
+++ b/Viewer/src/NodeObserver.hpp
@@ -0,0 +1,29 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef NODEOBSERVER_HPP_
+#define NODEOBSERVER_HPP_
+
+#include "Aspect.hpp"
+#include "Node.hpp"
+
+class VNode;
+class VNodeChange;
+
+class NodeObserver
+{
+public:
+ NodeObserver() {}
+ virtual ~NodeObserver() {}
+
+ virtual void notifyBeginNodeChange(const VNode* vn, const std::vector<ecf::Aspect::Type>& a,const VNodeChange&)=0;
+ virtual void notifyEndNodeChange(const VNode* vn, const std::vector<ecf::Aspect::Type>& a,const VNodeChange&)=0;
+};
+
+#endif
diff --git a/Viewer/src/NodePanel.cpp b/Viewer/src/NodePanel.cpp
new file mode 100644
index 0000000..d631686
--- /dev/null
+++ b/Viewer/src/NodePanel.cpp
@@ -0,0 +1,375 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "NodePanel.hpp"
+
+#include "Dashboard.hpp"
+#include "InfoPanel.hpp"
+#include "ServerHandler.hpp"
+#include "VSettings.hpp"
+
+NodePanel::NodePanel(QWidget* parent) :
+ TabWidget(parent)
+
+{
+ connect(this,SIGNAL(currentIndexChanged(int)),
+ this,SLOT(slotCurrentWidgetChanged(int)));
+
+ connect(this,SIGNAL(newTabRequested()),
+ this,SLOT(slotNewTab()));
+
+}
+
+NodePanel::~NodePanel()
+{
+}
+
+//=============================================
+//
+// Tab management desktopAction
+//
+//=============================================
+
+Dashboard *NodePanel::addWidget(QString id)
+{
+ Dashboard *nw=new Dashboard("",this);
+
+ QString name("node");
+ QPixmap pix;
+
+ addTab(nw,pix,name);
+
+
+ connect(nw,SIGNAL(selectionChanged(VInfo_ptr)),
+ this,SIGNAL(selectionChanged(VInfo_ptr)));
+
+ connect(nw,SIGNAL(titleChanged(QWidget*,QString,QPixmap)),
+ this,SLOT(slotTabTitle(QWidget*,QString,QPixmap)));
+
+ connect(nw,SIGNAL(contentsChanged()),
+ this,SIGNAL(contentsChanged()));
+
+ return nw;
+}
+
+
+void NodePanel::resetWidgets(QStringList idLst)
+{
+ if(idLst.count() ==0)
+ return;
+
+ clear();
+
+ Q_FOREACH(QString id,idLst)
+ {
+ addWidget(id);
+ }
+}
+
+//Handle the tab bar context menu actions
+void NodePanel::tabBarCommand(QString name,int index)
+{
+ if(name == "reloadTab")
+ {
+ Dashboard *w=nodeWidget(index);
+ if(w) w->reload();
+ }
+ else if(name == "closeOtherTabs")
+ {
+ removeOtherTabs(index);
+ }
+ else if(name == "closeTab")
+ {
+ removeTab(index);
+ }
+}
+
+Dashboard *NodePanel::nodeWidget(int index)
+{
+ QWidget *w=widget(index);
+ return (w)?static_cast<Dashboard*>(w):0;
+}
+
+Dashboard *NodePanel::currentDashboard()
+{
+ QWidget *w=currentWidget();
+ return static_cast<Dashboard*>(w);
+}
+
+void NodePanel::slotCurrentWidgetChanged(int /*index*/)
+{
+ Q_EMIT currentWidgetChanged();
+ //setDefaults(this);
+}
+
+void NodePanel::slotNewTab()
+{
+ Dashboard *w=addWidget("");
+ w->addWidget("tree");
+}
+
+VInfo_ptr NodePanel::currentSelection()
+{
+ if(Dashboard *w=currentDashboard())
+ return w->currentSelection();
+
+ return VInfo_ptr();
+}
+
+void NodePanel::slotSelection(VInfo_ptr n)
+{
+ if(Dashboard *w=currentDashboard())
+ w->currentSelection(n);
+}
+
+bool NodePanel::selectInTreeView(VInfo_ptr info)
+{
+ for(int i=0; i < count(); i++)
+ {
+ if(QWidget *w=widget(i))
+ {
+ if(Dashboard* nw=static_cast<Dashboard*>(w))
+ if(nw->selectInTreeView(info))
+ {
+ setCurrentIndex(i);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void NodePanel::setViewMode(Viewer::ViewMode mode)
+{
+ Dashboard *w=currentDashboard();
+ if(w) w->setViewMode(mode);
+ //setDefaults(this);
+}
+
+Viewer::ViewMode NodePanel::viewMode()
+{
+ Dashboard *w=currentDashboard();
+ return (w)?w->viewMode():Viewer::NoViewMode;
+}
+
+ServerFilter* NodePanel::serverFilter()
+{
+ Dashboard *w=currentDashboard();
+ return (w)?w->serverFilter():NULL;
+}
+
+void NodePanel::addToDashboard(const std::string& type)
+{
+ if(Dashboard *w=currentDashboard())
+ {
+ w->addWidget(type);
+ }
+}
+
+void NodePanel::openDialog(VInfo_ptr info,const std::string& type)
+{
+ if(Dashboard *w=currentDashboard())
+ {
+ w->slotPopInfoPanel(info,QString::fromStdString(type));
+ }
+}
+void NodePanel::addSearchDialog()
+{
+ if(Dashboard *w=currentDashboard())
+ {
+ w->addSearchDialog();
+ }
+}
+
+
+void NodePanel::slotTabTitle(QWidget* w,QString text,QPixmap pix)
+{
+ int index=indexOfWidget(w);
+ if(index != -1)
+ {
+ setTabText(index,text);
+ setTabIcon(index,pix);
+ }
+}
+
+
+/*void NodePanel::slotNewWindow(bool)
+{
+ //MainWindow::openWindow("",this);
+
+ if(Folder* f=currentFolder())
+ {
+ QString p=QString::fromStdString(f->fullName());
+ MvQFileBrowser::openBrowser(p,this);
+ }
+}*/
+
+/*void NodePanel::setViewMode(Viewer::NodeViewMode mode)
+{
+ NodeWidget *w=currentNodeWidget();
+ if(w) w->setViewMode(mode);
+ //setDefaults(this);
+}
+
+Viewer::FolderViewMode NodePanel::viewMode()
+{
+ NodeWidget *w=currentNodeWidget();
+ return (w)?w->viewMode():MvQ::NoViewMode;
+}*/
+
+//==========================================================
+//
+//
+//
+//==========================================================
+
+void NodePanel::reload()
+{
+ for(int i=0; i < count(); i++)
+ {
+ if(QWidget *w=widget(i))
+ {
+ if(Dashboard* nw=static_cast<Dashboard*>(w))
+ nw->reload();
+ }
+ }
+}
+
+void NodePanel::rerender()
+{
+ for(int i=0; i < count(); i++)
+ {
+ if(QWidget *w=widget(i))
+ {
+ if(Dashboard* nw=static_cast<Dashboard*>(w))
+ nw->rerender();
+ }
+ }
+}
+
+
+void NodePanel::refreshCurrent()
+{
+ ServerFilter* filter=serverFilter();
+ if(!filter)
+ return;
+
+ for(std::vector<ServerItem*>::const_iterator it=filter->items().begin(); it != filter->items().end(); ++it)
+ {
+ if(ServerHandler *sh=(*it)->serverHandler())
+ {
+ sh->refresh();
+ }
+ }
+}
+
+
+void NodePanel::resetCurrent()
+{
+ ServerFilter* filter=serverFilter();
+ if(!filter)
+ return;
+
+ for(std::vector<ServerItem*>::const_iterator it=filter->items().begin(); it != filter->items().end(); ++it)
+ {
+ if(ServerHandler *sh=(*it)->serverHandler())
+ {
+ sh->reset();
+ }
+ }
+}
+
+void NodePanel::init()
+{
+ Dashboard* nw=addWidget("");
+ if(nw)
+ {
+ nw->addWidget("tree");
+ }
+}
+
+//==========================================================
+//
+// Save/restore settings
+//
+//==========================================================
+
+void NodePanel::writeSettings(VComboSettings *vs)
+{
+ int currentIdx=(currentIndex()>=0)?currentIndex():0;
+
+ vs->put("tabCount",count());
+ vs->put("currentTabId",currentIdx);
+
+ for(int i=0; i < count(); i++)
+ {
+ //boost::property_tree::ptree ptTab;
+ if(Dashboard* nw=nodeWidget(i))
+ {
+ std::string id=NodePanel::tabSettingsId(i);
+ vs->beginGroup(id);
+ nw->writeSettings(vs);
+ vs->endGroup();
+ //pt.add_child("tab_"+ boost::lexical_cast<std::string>(i),ptTab);
+ }
+ }
+}
+
+void NodePanel::readSettings(VComboSettings *vs)
+{
+ using boost::property_tree::ptree;
+
+ int cnt=vs->get<int>("tabCount",0);
+ int currentIndex=vs->get<int>("currentTabId",-1);
+
+ for(int i=0; i < cnt; i++)
+ {
+ std::string id=NodePanel::tabSettingsId(i);
+ if(vs->contains(id))
+ {
+ Dashboard* nw=addWidget("");
+ if(nw)
+ {
+ vs->beginGroup(id);
+ nw->readSettings(vs);
+ vs->endGroup();
+ }
+ }
+ }
+
+ //Set current tab
+ if(currentIndex >=0 && currentIndex < count())
+ {
+ setCurrentIndex(currentIndex);
+ }
+
+ //If no tabs have been created
+ if(count()==0)
+ {
+ addWidget("");
+ setCurrentIndex(0);
+ if(Dashboard* d=currentDashboard())
+ {
+ d->addWidget("tree");
+ }
+ }
+
+ if(QWidget *w=currentDashboard())
+ w->setFocus();
+
+ //We emit it to trigger the whole window ui update!
+ Q_EMIT currentWidgetChanged();
+}
+
+std::string NodePanel::tabSettingsId(int i)
+{
+ return "tab_" + boost::lexical_cast<std::string>(i);
+}
+
+
diff --git a/Viewer/src/NodePanel.hpp b/Viewer/src/NodePanel.hpp
new file mode 100644
index 0000000..613ba24
--- /dev/null
+++ b/Viewer/src/NodePanel.hpp
@@ -0,0 +1,78 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef NODEPANEL_HPP_
+#define NODEPANEL_HPP_
+
+#include "Viewer.hpp"
+#include "TabWidget.hpp"
+#include "VInfo.hpp"
+
+#include <QIcon>
+
+#include <boost/property_tree/ptree.hpp>
+
+class Dashboard;
+class ServerFilter;
+class VComboSettings;
+
+class NodePanel : public TabWidget
+{
+ Q_OBJECT
+
+public:
+ explicit NodePanel(QWidget* parent=0);
+ virtual ~NodePanel();
+
+ void setViewMode(Viewer::ViewMode);
+ Viewer::ViewMode viewMode();
+
+ ServerFilter* serverFilter();
+
+ Dashboard* currentDashboard();
+ void addWidget();
+ void resetWidgets(QStringList);
+ void reload();
+ void rerender();
+ void refreshCurrent();
+ void resetCurrent();
+ VInfo_ptr currentSelection();
+ bool selectInTreeView(VInfo_ptr);
+ void addToDashboard(const std::string& type);
+ void init();
+ void openDialog(VInfo_ptr,const std::string& type);
+ void addSearchDialog();
+
+ void writeSettings(VComboSettings*);
+ void readSettings(VComboSettings*);
+
+public Q_SLOTS:
+ void slotCurrentWidgetChanged(int);
+ void slotSelection(VInfo_ptr);
+
+ //void slotIconCommand(QString,IconObjectH);
+ //void slotDesktopCommand(QString,QPoint);
+ void slotNewTab();
+ //void slotNewWindow(bool);
+ void slotTabTitle(QWidget* w,QString text,QPixmap pix);
+
+Q_SIGNALS:
+ void itemInfoChanged(QString);
+ void currentWidgetChanged();
+ void selectionChanged(VInfo_ptr);
+ void contentsChanged();
+
+protected:
+ Dashboard* addWidget(QString);
+ void tabBarCommand(QString, int);
+ Dashboard* nodeWidget(int index);
+ static std::string tabSettingsId(int i);
+};
+
+#endif
diff --git a/Viewer/src/NodePathWidget.cpp b/Viewer/src/NodePathWidget.cpp
new file mode 100644
index 0000000..c4bf5a8
--- /dev/null
+++ b/Viewer/src/NodePathWidget.cpp
@@ -0,0 +1,958 @@
+/***************************** LICENSE START ***********************************
+
+ Copyright 2014 ECMWF and INPE. This software is distributed under the terms
+ of the Apache License version 2.0. In applying this license, ECMWF does not
+ waive the privileges and immunities granted to it by virtue of its status as
+ an Intergovernmental Organization or submit itself to any jurisdiction.
+
+ ***************************** LICENSE END *************************************/
+
+#include "NodePathWidget.hpp"
+
+#include <QDebug>
+#include <QHBoxLayout>
+#include <QMenu>
+#include <QMouseEvent>
+#include <QPainter>
+#include <QPolygon>
+#include <QSizePolicy>
+#include <QStyleOption>
+#include <QToolButton>
+#include <QVector>
+
+#include "VNode.hpp"
+#include "VProperty.hpp"
+#include "PropertyMapper.hpp"
+#include "ServerHandler.hpp"
+#include "UserMessage.hpp"
+#include "VNState.hpp"
+#include "VSState.hpp"
+#include "VSettings.hpp"
+
+static std::vector<std::string> propVec;
+
+QColor NodePathItem::disabledBgCol_;
+QColor NodePathItem::disabledBorderCol_;
+QColor NodePathItem::disabledFontCol_;
+
+//#define _UI_NODEPATHWIDGET_DEBUG
+
+BcWidget::BcWidget(QWidget* parent) :
+ QWidget(parent),
+ hPadding_(2),
+ vPadding_(1),
+ hMargin_(1),
+ vMargin_(1),
+ triLen_(10),
+ gap_(5),
+ width_(0),
+ itemHeight_(0),
+ emptyText_("No selection"),
+ useGrad_(true),
+ gradLighter_(150),
+ hovered_(-1)
+{
+ font_=QFont();
+ QFontMetrics fm(font_);
+
+ itemHeight_=fm.height()+2*vPadding_;
+ height_=itemHeight_+2*vMargin_;
+
+ setMouseTracking(true);
+
+ //Property
+ if(propVec.empty())
+ {
+ propVec.push_back("view.common.node_style");
+ propVec.push_back("view.common.node_gradient");
+ }
+
+ prop_=new PropertyMapper(propVec,this);
+
+ updateSettings();
+
+ setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Minimum);
+ setMinimumSize(width_,height_);
+
+ reset(items_);
+}
+
+BcWidget::~BcWidget()
+{
+ delete prop_;
+}
+
+
+void BcWidget::notifyChange(VProperty *p)
+{
+ updateSettings();
+}
+
+void BcWidget::updateSettings()
+{
+ //if(VProperty *p=prop_->find("view.common.node_style"))
+ // node_style=p->value().toString()';
+ if(VProperty *p=prop_->find("view.common.node_gradient"))
+ useGrad_=p->value().toBool();
+}
+
+void BcWidget::clear()
+{
+ items_.clear();
+ reset(items_);
+}
+
+void BcWidget::resetBorder(int idx)
+{
+ if(idx >=0 && idx < items_.count())
+ {
+ QColor bgCol=items_.at(idx)->bgCol_;
+ if(idx != hovered_)
+ items_.at(idx)->borderCol_=bgCol.darker(125);
+ else
+ items_.at(idx)->borderCol_=bgCol.darker(240);
+
+ updatePixmap(idx);
+ update();
+ }
+}
+
+void BcWidget::reset(int idx,QString text,QColor bgCol,QColor fontCol)
+{
+ if(idx >=0 && idx < items_.count())
+ {
+ bool newText=(text != items_.at(idx)->text_);
+
+ if(newText)
+ items_.at(idx)->text_=text;
+
+ items_.at(idx)->bgCol_=bgCol;
+ items_.at(idx)->fontCol_=fontCol;
+
+ if(idx != hovered_)
+ items_.at(idx)->borderCol_=bgCol.darker(125);
+ else
+ items_.at(idx)->borderCol_=bgCol.darker(240);
+
+ if(newText)
+ reset(items_);
+ else
+ {
+ updatePixmap(idx);
+ update();
+ }
+ }
+}
+
+void BcWidget::reset(QList<NodePathItem*> items)
+{
+ items_=items;
+ hovered_=-1;
+
+ QFontMetrics fm(font_);
+ int xp=hMargin_;
+ int yp=vMargin_;
+
+ for(int i=0; i < items_.count(); i++)
+ {
+ int len=fm.width(items_.at(i)->text_);
+
+ QRect textRect;
+ items_.at(i)->borderCol_=items_.at(i)->bgCol_.darker(125);
+
+ QVector<QPoint> vec;
+ QVector<QPoint> menuVec;
+ if(i ==0)
+ {
+ textRect=QRect(xp+hPadding_,yp,len,itemHeight_);
+
+ vec << QPoint(xp,yp);
+ vec << QPoint(xp+len,yp);
+ vec << QPoint(xp+len+triLen_,yp+itemHeight_/2);
+ vec << QPoint(xp+len,yp+itemHeight_);
+ vec << QPoint(xp,yp+itemHeight_);
+
+ xp+=len+triLen_+gap_;
+ }
+ else
+ {
+ textRect=QRect(xp+hPadding_,yp,len,itemHeight_);
+
+ vec << QPoint(xp-triLen_,yp);
+ vec << QPoint(xp+len,yp);
+ vec << QPoint(xp+len+triLen_,yp+itemHeight_/2);
+ vec << QPoint(xp+len,yp+itemHeight_);
+ vec << QPoint(xp-triLen_,yp+itemHeight_);
+ vec << QPoint(xp,yp+itemHeight_/2);
+
+ xp+=len+triLen_+gap_;
+ }
+
+
+ // if(i < items_.count()-1)
+ // xp+=1;
+
+ items_.at(i)->shape_=QPolygon(vec);
+ items_.at(i)->textRect_=textRect;
+ }
+
+ width_=xp+hMargin_;
+
+ if(items_.count() ==0)
+ {
+ int len=fm.width(emptyText_);
+ emptyRect_=QRect(xp+hPadding_,yp,len,itemHeight_);
+ width_=xp+len+4;
+ }
+
+ crePixmap();
+
+ resize(width_,height_);
+
+ update();
+}
+
+
+void BcWidget::crePixmap()
+{
+ pix_=QPixmap(width_,height_);
+ pix_.fill(Qt::transparent);
+
+ QPainter painter(&pix_);
+ painter.setRenderHints(QPainter::Antialiasing,true);
+
+ if(items_.count() == 0)
+ {
+ painter.setPen(Qt::black);
+ painter.drawText(emptyRect_,Qt::AlignHCenter | Qt::AlignVCenter, emptyText_);
+ }
+ else
+ {
+ for(int i=0; i < items_.count(); i++)
+ {
+ items_.at(i)->enabled_=isEnabled();
+ items_.at(i)->draw(&painter,useGrad_,gradLighter_);
+ }
+ }
+}
+
+void BcWidget::updatePixmap(int idx)
+{
+ if(idx >=0 && idx < items_.count())
+ {
+ QPainter painter(&pix_);
+ painter.setRenderHints(QPainter::Antialiasing,true);
+ items_.at(idx)->draw(&painter,useGrad_,gradLighter_);
+ }
+}
+
+void BcWidget::paintEvent(QPaintEvent*)
+{
+ QPainter painter(this);
+ painter.drawPixmap(0,0,pix_);
+}
+
+void BcWidget::mouseMoveEvent(QMouseEvent *event)
+{
+ for(int i=0; i < items_.count(); i++)
+ {
+ if(items_.at(i)->shape_.containsPoint(event->pos(),Qt::OddEvenFill))
+ {
+ if(hovered_ == -1)
+ {
+ hovered_=i;
+ resetBorder(i);
+ }
+ else if(hovered_ != i)
+ {
+ int prev=hovered_;
+ hovered_=i;
+ resetBorder(prev);
+ resetBorder(i);
+ }
+
+ return;
+ }
+ }
+
+ if(hovered_ != -1)
+ {
+ int prev=hovered_;
+ hovered_=-1;
+ resetBorder(prev);
+
+ }
+}
+
+void BcWidget::mousePressEvent(QMouseEvent *event)
+{
+ if(event->button() != Qt::RightButton && event->button() != Qt::LeftButton)
+ return;
+
+ for(int i=0; i < items_.count(); i++)
+ {
+ if(items_.at(i)->shape_.containsPoint(event->pos(),Qt::OddEvenFill))
+ {
+ if(event->button() == Qt::RightButton)
+ {
+ Q_EMIT menuSelected(i,event->pos());
+ return;
+ }
+ else if(event->button() == Qt::LeftButton)
+ {
+ Q_EMIT itemSelected(i);
+ return;
+ }
+ }
+ }
+}
+
+void BcWidget::changeEvent(QEvent* event)
+{
+ if(event->type() == QEvent::EnabledChange)
+ {
+ crePixmap();
+//TODO: Will update be called automatically?
+ }
+
+ QWidget::changeEvent(event);
+}
+
+NodePathItem::NodePathItem(int index,QString text,QColor bgCol,QColor fontCol,bool hasMenu,bool current) :
+ index_(index),
+ text_(text),
+ bgCol_(bgCol),
+ fontCol_(fontCol),
+ current_(current),
+ hasMenu_(hasMenu),
+ enabled_(true)
+{
+ if(!disabledBgCol_.isValid())
+ {
+ disabledBgCol_=QColor(200,200,200);
+ disabledBorderCol_=QColor(170,170,170);
+ disabledFontCol_=QColor(40,40,40);
+ }
+
+ grad_.setCoordinateMode(QGradient::ObjectBoundingMode);
+ grad_.setStart(0,0);
+ grad_.setFinalStop(0,1);
+}
+
+void NodePathItem::setCurrent(bool)
+{
+}
+
+void NodePathItem::draw(QPainter *painter,bool useGrad,int lighter)
+{
+ /* if(current_)
+ {
+ painter->setPen(QPen(Qt::black,2));
+ }
+ else
+ {
+ painter->setPen(QPen(borderCol_,0));
+ }*/
+
+ QColor border, bg, fontCol;
+ if(enabled_)
+ {
+ border=borderCol_;
+ bg=bgCol_;
+ fontCol=fontCol_;
+ }
+ else
+ {
+ border=disabledBorderCol_;
+ bg=disabledBgCol_;
+ fontCol=disabledFontCol_;
+ }
+
+ painter->setPen(QPen(border,0));
+
+ QBrush bgBrush;
+
+ if(useGrad)
+ {
+ QColor bgLight=bg.lighter(lighter);
+ grad_.setColorAt(0,bgLight);
+ grad_.setColorAt(1,bg);
+ bgBrush=QBrush(grad_);
+ }
+ else
+ bgBrush=QBrush(bg);
+
+ painter->setBrush(bgBrush);
+ painter->drawPolygon(shape_);
+
+ /*if(current_)
+ {
+ painter->setPen(QPen(borderCol_,0));
+ }*/
+
+ painter->setPen(fontCol);
+ painter->drawText(textRect_,Qt::AlignVCenter | Qt::AlignHCenter,text_);
+
+}
+
+
+//=============================================================
+//
+// NodePathWidget
+//
+//=============================================================
+
+NodePathWidget::NodePathWidget(QWidget *parent) :
+ QWidget(parent),
+ reloadTb_(0),
+ active_(true)
+{
+ setProperty("breadcrumbs","1");
+
+ layout_=new QHBoxLayout(this);
+ layout_->setSpacing(0);
+ layout_->setContentsMargins(2,2,3,2);
+ setLayout(layout_);
+
+ bc_=new BcWidget(this);
+ layout_->addWidget(bc_);
+
+ connect(bc_,SIGNAL(itemSelected(int)),
+ this,SLOT(slotNodeSelected(int)));
+ connect(bc_,SIGNAL(menuSelected(int,QPoint)),
+ this,SLOT(slotMenuSelected(int,QPoint)));
+
+ reloadTb_=new QToolButton(this);
+ //reloadTb_->setDefaultAction(actionReload_);
+ reloadTb_->setIcon(QPixmap(":/viewer/reload_one.svg"));
+ reloadTb_->setToolTip(tr("Refresh server"));
+ reloadTb_->setAutoRaise(true);
+ //reloadTb_->setIconSize(QSize(20,20));
+ reloadTb_->setObjectName("pathIconTb");
+
+ connect(reloadTb_,SIGNAL(clicked()),
+ this,SLOT(slotRefreshServer()));
+
+ layout_->addWidget(reloadTb_);
+}
+
+NodePathWidget::~NodePathWidget()
+{
+ clear(true);
+}
+
+void NodePathWidget::clear(bool detachObservers)
+{
+ setEnabled(true);
+
+ if(detachObservers && info_ && info_->server())
+ {
+ info_->server()->removeNodeObserver(this);
+ info_->server()->removeServerObserver(this);
+ }
+
+ if(detachObservers && info_)
+ {
+ info_->removeObserver(this);
+ }
+
+ if(info_)
+ info_->removeObserver(this);
+
+ info_.reset();
+
+ clearItems();
+
+ setEnabled(true);
+
+ reloadTb_->setEnabled(false);
+ reloadTb_->setToolTip("");
+}
+
+void NodePathWidget::clearItems()
+{
+ bc_->clear();
+
+ int cnt=nodeItems_.count();
+ for(int i=0; i < cnt; i++)
+ {
+ delete nodeItems_.takeLast();
+ }
+ nodeItems_.clear();
+}
+
+void NodePathWidget::active(bool active)
+{
+ if(active_ != active)
+ active_=active;
+
+ if(active_)
+ {
+ setVisible(true);
+ }
+ else
+ {
+ setVisible(false);
+ clear();
+ }
+}
+
+
+void NodePathWidget::slotContextMenu(const QPoint& pos)
+{
+
+}
+
+void NodePathWidget::adjust(VInfo_ptr info,ServerHandler** serverOut,bool &sameServer)
+{
+ ServerHandler* server=0;
+
+ //Check if there is data in info
+ if(info)
+ {
+ server=info->server();
+
+ sameServer=(info_)?(info_->server() == server):false;
+
+ //Handle observers
+ if(!sameServer)
+ {
+ if(info_ && info_->server())
+ {
+ info_->server()->removeServerObserver(this);
+ info_->server()->removeNodeObserver(this);
+ }
+
+ info->server()->addServerObserver(this);
+ info->server()->addNodeObserver(this);
+
+ if(server)
+ {
+ if(reloadTb_)
+ {
+ reloadTb_->setToolTip("Refresh server <b>" + QString::fromStdString(server->name()) + "</b>");
+ reloadTb_->setEnabled(true);
+ }
+ }
+ else
+ {
+ reloadTb_->setToolTip("");
+ reloadTb_->setEnabled(false);
+ }
+
+ }
+ }
+ //If the there is no data we clean everything and return
+ else
+ {
+ if(info_ && info_->server())
+ {
+ info_->server()->removeServerObserver(this);
+ info_->server()->removeNodeObserver(this);
+ }
+
+ reloadTb_->setToolTip("");
+ reloadTb_->setEnabled(false);
+ }
+
+ //Set the info
+ if(info_)
+ {
+ info_->removeObserver(this);
+ }
+
+ info_=info;
+
+ if(info_)
+ {
+ info_->addObserver(this);
+ }
+
+ *serverOut=server;
+}
+
+
+void NodePathWidget::reset()
+{
+ setPath(info_);
+}
+
+void NodePathWidget::setPath(QString)
+{
+ if(!active_)
+ return;
+}
+
+void NodePathWidget::setPath(VInfo_ptr info)
+{
+#ifdef _UI_NODEPATHWIDGET_DEBUG
+ UserMessage::debug("NodePathWidget::setPath -->");
+#endif
+
+ setEnabled(true);
+
+ if(!active_)
+ return;
+
+ ServerHandler *server=0;
+ bool sameServer=false;
+
+ VInfo_ptr info_ori=info_;
+
+ adjust(info,&server,sameServer);
+
+ if(!info_ || !info_->server())
+ {
+ clear();
+ return;
+ }
+ else
+ {
+ clearItems();
+ }
+
+ //Get the node list including the server
+ std::vector<VNode*> lst;
+ if(info_->node())
+ {
+ lst=info_->node()->ancestors(VNode::ParentToChildSort);
+ }
+
+ //--------------------------------------------
+ // Reset/rebuild the contents
+ //--------------------------------------------
+
+ for(unsigned int i=0; i < lst.size(); i++)
+ {
+ //---------------------------
+ // Create node/server item
+ //---------------------------
+
+ QColor col;
+ QString name;
+ NodePathItem* nodeItem=0;
+
+ VNode *n=lst.at(i);
+ col=n->stateColour();
+#ifdef _UI_NODEPATHWIDGET_DEBUG
+ UserMessage::debug(" state=" + n->stateName().toStdString());
+#endif
+ QColor fontCol=n->stateFontColour();
+ name=n->name();
+ bool hasChildren=hasChildren=(n->numOfChildren() >0);
+
+ nodeItem=new NodePathItem(i,name,col,fontCol,hasChildren,(i == lst.size()-1)?true:false);
+ nodeItems_ << nodeItem;
+ }
+
+ bc_->reset(nodeItems_);
+
+#ifdef _UI_NODEPATHWIDGET_DEBUG
+ UserMessage::debug("<-- NodePathWidget::setPath");
+#endif
+}
+
+void NodePathWidget::slotNodeSelected(int idx)
+{
+ if(idx != -1)
+ {
+ Q_EMIT selected(nodeAt(idx));
+ }
+}
+
+void NodePathWidget::slotMenuSelected(int idx,QPoint bcPos)
+{
+ if(idx != -1)
+ {
+ loadMenu(bc_->mapToGlobal(bcPos),nodeAt(idx));
+ }
+}
+
+//-------------------------------------------------------------------------------------------
+// Get the object from nodeItems_ at position idx.
+// This is the order/position of the items:
+//
+// 0 1 2 .... nodeItems_.count()-2 nodeItems_.count()-1
+// server node's parent node (=info_)
+//--------------------------------------------------------------------------------------------
+
+VInfo_ptr NodePathWidget::nodeAt(int idx)
+{
+#ifdef _UI_NODEPATHWIDGET_DEBUG
+ UserMessage::debug("NodePathWidget::nodeAt idx=" + boost::lexical_cast<std::string>(idx));
+#endif
+ ServerHandler* server=info_->server();
+
+ if(info_ && server)
+ {
+ if(VNode *n=info_->node()->ancestorAt(idx,VNode::ParentToChildSort))
+ {
+ if(n == info_->node())
+ return info_;
+ else if(n->isServer())
+ return VInfoServer::create(n->server());
+ else
+ return VInfoNode::create(n);
+ }
+ }
+
+ return VInfo_ptr();
+}
+
+void NodePathWidget::loadMenu(const QPoint& pos,VInfo_ptr p)
+{
+ if(p && p->node())
+ {
+ QList<QAction*> acLst;
+ VNode* node=p->node();
+
+ for(unsigned int i=0; i < node->numOfChildren(); i++)
+ {
+ QAction *ac=new QAction(node->childAt(i)->name(),this);
+ ac->setData(i);
+ acLst << ac;
+ }
+
+ if(acLst.count() > 0)
+ {
+#ifdef _UI_NODEPATHWIDGET_DEBUG
+ UserMessage::message(UserMessage::DBG,false,"NodePathWidget::loadMenu");
+#endif
+
+ if(QAction *ac=QMenu::exec(acLst,pos,acLst.front(),this))
+ {
+ int idx=ac->data().toInt();
+ VInfo_ptr res=VInfoNode::create(node->childAt(idx));
+ Q_EMIT selected(res);
+ }
+ }
+
+ Q_FOREACH(QAction* ac,acLst)
+ {
+ delete ac;
+ }
+ }
+}
+
+
+void NodePathWidget::notifyBeginNodeChange(const VNode* node, const std::vector<ecf::Aspect::Type>& aspect,const VNodeChange&)
+{
+ if(!active_)
+ return;
+
+ //Check if there is data in info
+ if(info_ && !info_->isServer() && info_->node())
+ {
+ //TODO: MAKE IT SAFE!!!!
+
+ //State changed
+ if(std::find(aspect.begin(),aspect.end(),ecf::Aspect::STATE) != aspect.end() ||
+ std::find(aspect.begin(),aspect.end(),ecf::Aspect::SUSPENDED) != aspect.end())
+ {
+ std::vector<VNode*> nodes=info_->node()->ancestors(VNode::ParentToChildSort);
+ for(unsigned int i=0; i < nodes.size(); i++)
+ {
+ if(nodes.at(i) == node)
+ {
+ if(i < nodeItems_.count())
+ {
+ bc_->reset(i,node->name(),node->stateColour(),node->stateFontColour());
+ }
+ return;
+ }
+ }
+ }
+
+ //A child was removed or added
+ else if(std::find(aspect.begin(),aspect.end(),ecf::Aspect::ADD_REMOVE_NODE) != aspect.end())
+ {
+ std::vector<VNode*> nodes=info_->node()->ancestors(VNode::ParentToChildSort);
+ for(unsigned int i=0; i < nodes.size(); i++)
+ {
+ if(node == nodes.at(i))
+ {
+ //Reload everything
+ setPath(info_);
+ }
+ }
+ }
+
+ }
+}
+
+
+void NodePathWidget::notifyDefsChanged(ServerHandler* server,const std::vector<ecf::Aspect::Type>& aspect)
+{
+#ifdef _UI_NODEPATHWIDGET_DEBUG
+ UserMessage::debug("NodePathWidget::notifyDefsChanged -->");
+#endif
+
+ if(!active_)
+ return;
+
+ //Check if there is data in inf0
+ if(info_ && info_->server() && info_->server() == server)
+ {
+ //State changed
+ if(std::find(aspect.begin(),aspect.end(),ecf::Aspect::SERVER_STATE) != aspect.end())
+ {
+ if(nodeItems_.count() > 0)
+ {
+ bc_->reset(0,server->vRoot()->name(),
+ server->vRoot()->stateColour(),
+ server->vRoot()->stateFontColour());
+ }
+
+ }
+ }
+
+}
+
+//This must be called at the beginning of a reset
+void NodePathWidget::notifyBeginServerClear(ServerHandler* server)
+{
+#ifdef _UI_NODEPATHWIDGET_DEBUG
+ UserMessage::debug("NodePathWidget::notifyBeginServerClear -->");
+#endif
+ if(info_)
+ {
+ if(info_->server() && info_->server() == server)
+ {
+ setEnabled(false);
+ }
+ }
+#ifdef _UI_NODEPATHWIDGET_DEBUG
+ UserMessage::debug("<-- NodePathWidget::notifyBeginServerClear");
+#endif
+}
+
+//This must be called at the end of a reset
+void NodePathWidget::notifyEndServerScan(ServerHandler* server)
+{
+#ifdef _UI_NODEPATHWIDGET_DEBUG
+ UserMessage::debug("NodePathWidget::notifyEndServerScan -->");
+#endif
+
+ if(info_)
+ {
+ if(info_->server() && info_->server() == server)
+ {
+#ifdef _UI_NODEPATHWIDGET_DEBUG
+ UserMessage::debug(" setEnabled(true)");
+#endif
+
+ setEnabled(true);
+
+#ifdef _UI_NODEPATHWIDGET_DEBUG
+ UserMessage::debug(" regainData");
+#endif
+ //We try to ressurect the info. We have to do it explicitly because it is not guaranteed
+ //the notifyEndServerScan() will be first called on the VInfo then on the breadcrumbs. So it
+ //is possible that the node still exists but it is still set to NULL in VInfo.
+ info_->regainData();
+
+ //If the info is not available dataLost() must have already been called and
+ //the breadcrumbs were reset!
+ if(!info_)
+ return;
+
+ Q_ASSERT(info_->server() && info_->node());
+
+#ifdef _UI_NODEPATHWIDGET_DEBUG
+ UserMessage::debug(" reset");
+#endif
+ reset();
+ }
+ }
+
+#ifdef _UI_NODEPATHWIDGET_DEBUG
+ UserMessage::debug("<-- NodePathWidget::notifyEndServerScan");
+#endif
+}
+
+void NodePathWidget::notifyServerDelete(ServerHandler* server)
+{
+ if(info_ && info_->server() == server)
+ {
+ //We do not want to detach ourselves as an observer the from the server. When this function is
+ //called the server actually loops through its observers and notify them.
+ clear(false);
+ }
+}
+
+void NodePathWidget::notifyServerConnectState(ServerHandler* server)
+{
+ //TODO: we need to indicate the state here!
+ if(info_ && info_->server() == server)
+ {
+ reset();
+ }
+}
+
+void NodePathWidget::notifyServerActivityChanged(ServerHandler* /*server*/)
+{
+ //reset();
+}
+
+void NodePathWidget::notifyDataLost(VInfo* info)
+{
+#ifdef _UI_NODEPATHWIDGET_DEBUG
+ UserMessage::debug("NodePathWidget::notifyDataLost -->");
+#endif
+ if(info_ && info_.get() == info)
+ {
+#ifdef _UI_NODEPATHWIDGET_DEBUG
+ UserMessage::debug(" clear(true)");
+#endif
+ clear(true);
+ }
+#ifdef _UI_NODEPATHWIDGET_DEBUG
+ UserMessage::debug("<-- NodePathWidget::notifyDataLost");
+#endif
+}
+
+void NodePathWidget::slotRefreshServer()
+{
+ if(info_ && info_->server())
+ {
+ info_->server()->refresh();
+ }
+}
+
+void NodePathWidget::rerender()
+{
+ reset();
+}
+
+void NodePathWidget::paintEvent(QPaintEvent *)
+ {
+ QStyleOption opt;
+ opt.init(this);
+ QPainter p(this);
+ style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
+ }
+
+
+void NodePathWidget::writeSettings(VSettings *vs)
+{
+ vs->beginGroup("breadcrumbs");
+ vs->put("active",active_);
+ vs->endGroup();
+}
+
+void NodePathWidget::readSettings(VSettings* vs)
+{
+ vs->beginGroup("breadcrumbs");
+ int ival;
+
+ ival=vs->get<int>("active",1);
+ active((ival==1)?true:false);
+
+ vs->endGroup();
+}
+
+
+
+
+
+
diff --git a/Viewer/src/NodePathWidget.hpp b/Viewer/src/NodePathWidget.hpp
new file mode 100644
index 0000000..3c604e2
--- /dev/null
+++ b/Viewer/src/NodePathWidget.hpp
@@ -0,0 +1,189 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef NODEPATHWIDGET_H
+#define NODEPATHWIDGET_H
+
+#include "NodeObserver.hpp"
+#include "ServerObserver.hpp"
+#include "VInfo.hpp"
+#include "VProperty.hpp"
+
+#include <QLinearGradient>
+#include <QWidget>
+
+#include <string>
+
+class QAction;
+class QHBoxLayout;
+class QMenu;
+class QToolButton;
+
+class Node;
+class NodePathWidget;
+class PropertyMapper;
+class VProperty;
+class VSettings;
+
+class NodePathItem;
+
+class BcWidget : public QWidget, public VPropertyObserver
+{
+
+Q_OBJECT
+
+public:
+ explicit BcWidget(QWidget *parent=0);
+ ~BcWidget();
+
+ void reset(QList<NodePathItem*>);
+ void reset(int idx,QString text,QColor bgCol,QColor fontCol);
+ void clear();
+
+ void notifyChange(VProperty*);
+
+Q_SIGNALS:
+ void itemSelected(int);
+ void menuSelected(int,QPoint);
+
+protected:
+ void paintEvent(QPaintEvent*);
+ void mouseMoveEvent(QMouseEvent *event);
+ void mousePressEvent(QMouseEvent* event);
+ void changeEvent(QEvent* event);
+
+ void updateSettings();
+ void reset(int);
+ void resetBorder(int);
+ void crePixmap();
+ void updatePixmap(int);
+
+ QFont font_;
+ QPixmap pix_;
+ int hPadding_;
+ int vPadding_;
+ int hMargin_;
+ int vMargin_;
+ int triLen_;
+ int gap_;
+ int width_;
+ int height_;
+ int itemHeight_;
+ QString emptyText_;
+ QRect emptyRect_;
+ QList<NodePathItem*> items_;
+
+ PropertyMapper* prop_;
+ bool useGrad_;
+ int gradLighter_;
+ int hovered_;
+};
+
+
+class NodePathItem
+{
+
+friend class BcWidget;
+
+public:
+ NodePathItem(int index,QString text,QColor bgCol,QColor fontCol,bool hasMenu,bool current);
+ void setCurrent(bool);
+ void draw(QPainter*,bool,int);
+
+protected:
+ int index_;
+ QString text_;
+ QColor bgCol_;
+ QColor borderCol_;
+ QColor fontCol_;
+ QPolygon shape_;
+ QRect textRect_;
+ bool current_;
+ bool hasMenu_;
+ QLinearGradient grad_;
+ bool enabled_;
+ static QColor disabledBgCol_;
+ static QColor disabledBorderCol_;
+ static QColor disabledFontCol_;
+};
+
+
+class NodePathWidget : public QWidget, public NodeObserver, public ServerObserver, public VInfoObserver
+{
+Q_OBJECT
+
+public:
+ explicit NodePathWidget(QWidget* parent=0);
+ ~NodePathWidget();
+
+ bool active() const {return active_;}
+ void active(bool);
+ void clear(bool detachObservers=true);
+
+ //From NodeObserver
+ void notifyBeginNodeChange(const VNode*, const std::vector<ecf::Aspect::Type>&,const VNodeChange&);
+ void notifyEndNodeChange(const VNode*, const std::vector<ecf::Aspect::Type>&,const VNodeChange&) {}
+
+ //From ServerObserver
+ void notifyDefsChanged(ServerHandler* server,const std::vector<ecf::Aspect::Type>&);
+ void notifyServerDelete(ServerHandler* server);
+ void notifyBeginServerClear(ServerHandler* server);
+ void notifyEndServerClear(ServerHandler* server) {}
+ void notifyBeginServerScan(ServerHandler* server,const VServerChange&) {}
+ void notifyEndServerScan(ServerHandler* server);
+ void notifyServerConnectState(ServerHandler* server);
+ void notifyServerActivityChanged(ServerHandler* server);
+
+ //From VInfoObserver
+ void notifyDelete(VInfo*) {}
+ void notifyDataLost(VInfo*);
+
+ void rerender();
+
+ void writeSettings(VSettings *vs);
+ void readSettings(VSettings *vs);
+
+public Q_SLOTS:
+ void setPath(QString);
+ void setPath(VInfo_ptr);
+
+protected Q_SLOTS:
+ void slotContextMenu(const QPoint&);
+ void slotNodeSelected(int);
+ void slotMenuSelected(int,QPoint);
+ void slotRefreshServer();
+
+Q_SIGNALS:
+ void selected(VInfo_ptr);
+
+protected:
+ void clearItems();
+ void adjust(VInfo_ptr info,ServerHandler** serverOut,bool &sameServer);
+ void loadMenu(const QPoint& pos,VInfo_ptr p);
+ VInfo_ptr nodeAt(int);
+ void infoIndex(int idx);
+ void paintEvent(QPaintEvent *);
+ void reset();
+ void updateSettings();
+
+ QList<NodePathItem*> nodeItems_;
+
+ QHBoxLayout* layout_;
+ VInfo_ptr info_;
+ VInfo_ptr infoFull_;
+ QToolButton* reloadTb_;
+ BcWidget* bc_;
+
+
+ //When active_ is "true" the widget is visible and can receive and display data. When it
+ //is "false" the widget is hidden and cannot hold any data.
+ bool active_;
+};
+
+#endif
diff --git a/Viewer/src/NodeQuery.cpp b/Viewer/src/NodeQuery.cpp
new file mode 100644
index 0000000..70688d9
--- /dev/null
+++ b/Viewer/src/NodeQuery.cpp
@@ -0,0 +1,671 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "NodeQuery.hpp"
+
+#include <QDebug>
+
+#include "VSettings.hpp"
+
+StringMatchMode::Mode NodeQueryStringOption::defaultMatchMode_=StringMatchMode::WildcardMatch;
+bool NodeQueryStringOption::defaultCaseSensitive_=false;
+//QMap<NodeQueryStringOption::MatchMode,QString> NodeQueryStringOption::matchOper_;
+
+QStringList NodeQuery::nodeTerms_;
+QStringList NodeQuery::typeTerms_;
+QStringList NodeQuery::stateTerms_;
+QStringList NodeQuery::flagTerms_;
+QStringList NodeQuery::attrGroupTerms_;
+QMap<QString,QStringList> NodeQuery::attrTerms_;
+int NodeQuery::defaultMaxNum_=50000;
+
+NodeQueryStringOption::NodeQueryStringOption(QString name) :
+ name_(name),
+ matchMode_(defaultMatchMode_),
+ caseSensitive_(defaultCaseSensitive_)
+{
+ /*if(matchOper_.isEmpty())
+ {
+ matchOper_[ContainsMatch]="~";
+ matchOper_[WildcardMatch]="=";
+ matchOper_[RegexpMatch]="=~";
+ }*/
+}
+
+void NodeQueryStringOption::swap(const NodeQueryStringOption* op)
+{
+ value_=op->value();
+ matchMode_=op->matchMode();
+ caseSensitive_=op->caseSensitive();
+}
+
+
+/*QString NodeQueryStringOption::matchOperator() const
+{
+ return matchOper_.value(matchMode_);
+}*/
+
+void NodeQueryStringOption::save(VSettings* vs)
+{
+ if(value_.isEmpty() && matchMode_.mode() == defaultMatchMode_ &&
+ caseSensitive_ == defaultCaseSensitive_)
+ return;
+
+ vs->beginGroup(name_.toStdString());
+ vs->put("value",value_.toStdString());
+ vs->put("matchMode",matchMode_.toInt());
+ vs->putAsBool("caseSensistive",caseSensitive_);
+ vs->endGroup();
+}
+
+
+void NodeQueryStringOption::load(VSettings* vs)
+{
+ if(!vs->contains(name_.toStdString()))
+ return;
+
+ vs->beginGroup(name_.toStdString());
+ value_=QString::fromStdString(vs->get("value",value_.toStdString()));
+ matchMode_.setMode(static_cast<StringMatchMode::Mode>(vs->get<int>("matchMode",matchMode_.toInt())));
+ caseSensitive_=vs->getAsBool("caseSensistive",caseSensitive_);
+ vs->endGroup();
+}
+
+void NodeQuerySelectOption::swap(const NodeQuerySelectOption* op)
+{
+ selection_=op->selection();
+}
+
+void NodeQuerySelectOption::save(VSettings* vs)
+{
+ if(selection_.isEmpty())
+ return;
+
+ std::vector<std::string> v;
+ Q_FOREACH(QString s, selection_)
+ v.push_back(s.toStdString());
+
+ vs->put(name_.toStdString(),v);
+}
+
+void NodeQuerySelectOption::load(VSettings* vs)
+{
+ if(!vs->contains(name_.toStdString()))
+ return;
+
+ std::vector<std::string> v;
+ vs->get(name_.toStdString(),v);
+
+ selection_.clear();
+ for(std::vector<std::string>::const_iterator it=v.begin(); it != v.end(); ++it)
+ selection_ << QString::fromStdString(*it);
+}
+
+
+NodeQuery::NodeQuery(const std::string& name,bool ignoreMaxNum) :
+ name_(name),
+ advanced_(false),
+ //allServers_(true),
+ caseSensitive_(false),
+ maxNum_(defaultMaxNum_),
+ ignoreMaxNum_(ignoreMaxNum)
+{
+ if(nodeTerms_.isEmpty())
+ {
+ nodeTerms_ << "node_name" << "node_path";
+ typeTerms_ << "server" << "suite" << "family" << "task" << "alias";
+ stateTerms_ << "aborted" << "active" << "complete" << "queued" << "submitted" << "suspended" << "unknown";
+ flagTerms_ << "is_late" << "has_date" << "has_message" << "has_time" << "is_rerun" << "is_waiting" << "is_zombie";
+ attrGroupTerms_ << "date" << "event" << "label" << "late" << "limit" << "limiter" << "meter"
+ << "repeat" << "time" << "trigger" << "variable";
+
+ attrTerms_["date"] << "date_name";
+ attrTerms_["event"] << "event_name";
+ attrTerms_["label"] << "label_name" << "label_value";
+ attrTerms_["limit"] << "limit_name" << "limit_value" << "limit_max";
+ attrTerms_["limiter"] << "limiter_name";
+ attrTerms_["meter"] << "meter_name";
+ attrTerms_["repeat"] << "repeat_name" << "repeat_value";
+ attrTerms_["time"] << "time_name";
+ attrTerms_["trigger"] << "trigger_expression";
+ attrTerms_["variable"] << "var_name" << "var_value";
+
+ }
+
+ Q_FOREACH(QString s,nodeTerms_)
+ {
+ stringOptions_[s]=new NodeQueryStringOption(s);
+ }
+
+ Q_FOREACH(QString gr,attrGroupTerms_)
+ {
+ Q_FOREACH(QString s,attrTerms_[gr])
+ stringOptions_[s]=new NodeQueryStringOption(s);
+ }
+
+ selectOptions_["type"]=new NodeQuerySelectOption("type");
+ selectOptions_["state"]=new NodeQuerySelectOption("state");
+ selectOptions_["flag"]=new NodeQuerySelectOption("flag");
+ selectOptions_["attr"]=new NodeQuerySelectOption("attr");
+}
+
+NodeQuery::~NodeQuery()
+{
+ Q_FOREACH(QString s,stringOptions_.keys())
+ {
+ delete stringOptions_[s];
+ }
+
+ Q_FOREACH(QString s,selectOptions_.keys())
+ {
+ delete selectOptions_[s];
+ }
+}
+
+
+NodeQuery* NodeQuery::clone()
+{
+ return clone(name_);
+}
+
+NodeQuery* NodeQuery::clone(const std::string& name)
+{
+ NodeQuery *q=new NodeQuery(name);
+ q->swap(this);
+
+ return q;
+}
+
+void NodeQuery::swap(const NodeQuery* q)
+{
+ advanced_=q->advanced_;
+ query_=q->query_;
+ extQuery_=q->extQuery_;
+ rootNode_=q->rootNode_;
+ servers_=q->servers_;
+ //allServers_=q->allServers_;
+ caseSensitive_=q->caseSensitive_;
+ maxNum_=q->maxNum_;
+ ignoreMaxNum_=q->ignoreMaxNum_;
+
+ Q_FOREACH(QString s,stringOptions_.keys())
+ {
+ stringOptions_[s]->swap(q->stringOptions_.value(s));
+ }
+
+ Q_FOREACH(QString s,selectOptions_.keys())
+ {
+ selectOptions_[s]->swap(q->selectOptions_.value(s));
+ }
+
+ buildQueryString();
+}
+
+void NodeQuery::setName(const std::string& name)
+{
+ name_=name;
+}
+
+void NodeQuery::setQuery(QString query)
+{
+ query_=query;
+}
+
+bool NodeQuery::hasServer(const std::string& name) const
+{
+ qDebug() << "servers" << servers_;
+
+ if(servers_.empty())
+ return true;
+
+ return servers_.contains(QString::fromStdString(name));
+}
+
+void NodeQuery::adjustServers(const std::vector<std::string>& all)
+{
+ QStringList allLst=vecToLst(all);
+
+ /*if(allServers_)
+ {
+ servers_=allLst;
+ buildQueryString();
+ }*/
+}
+
+QStringList NodeQuery::typeSelection() const
+{
+ return selectOptions_.value("type")->selection_;
+}
+
+std::vector<std::string> NodeQuery::typeSelectionVec() const
+{
+ return lstToVec(selectOptions_.value("type")->selection_);
+}
+
+QStringList NodeQuery::stateSelection() const
+{
+ return selectOptions_.value("state")->selection_;
+}
+
+std::vector<std::string> NodeQuery::stateSelectionVec() const
+{
+ return lstToVec(selectOptions_.value("state")->selection_);
+}
+
+QStringList NodeQuery::flagSelection() const
+{
+ return selectOptions_["flag"]->selection_;
+}
+
+std::vector<std::string> NodeQuery::flagSelectionVec() const
+{
+ return lstToVec(selectOptions_["flag"]->selection_);
+}
+
+NodeQueryStringOption* NodeQuery::stringOption(QString name) const
+{
+ QMap<QString,NodeQueryStringOption*>::const_iterator it = stringOptions_.find(name);
+ if(it != stringOptions_.constEnd())
+ return it.value();
+ return NULL;
+}
+
+QStringList NodeQuery::attrGroupSelection() const
+{
+ return selectOptions_["attr"]->selection_;
+}
+
+std::vector<std::string> NodeQuery::attrGroupSelectionVec() const
+{
+ return lstToVec(selectOptions_["attr"]->selection_);
+}
+
+void NodeQuery::setTypeSelection(QStringList lst)
+{
+ selectOptions_["type"]->selection_=lst;
+}
+
+void NodeQuery::setTypeSelection(const std::vector<std::string>& vec)
+{
+ selectOptions_["type"]->selection_=vecToLst(vec);
+}
+
+
+void NodeQuery::setStateSelection(QStringList lst)
+{
+ selectOptions_["state"]->selection_=lst;
+}
+
+void NodeQuery::setStateSelection(const std::vector<std::string>& vec)
+{
+ selectOptions_["state"]->selection_=vecToLst(vec);
+}
+
+void NodeQuery::setFlagSelection(QStringList lst)
+{
+ selectOptions_["flag"]->selection_=lst;
+}
+
+void NodeQuery::setFlagSelection(const std::vector<std::string>& vec)
+{
+ selectOptions_["flag"]->selection_=vecToLst(vec);
+}
+
+void NodeQuery::setAttrGroupSelection(QStringList lst)
+{
+ selectOptions_["attr"]->selection_=lst;
+}
+
+void NodeQuery::setAttrGroupSelection(const std::vector<std::string>& vec)
+{
+ selectOptions_["attr"]->selection_=vecToLst(vec);
+}
+
+void NodeQuery::buildQueryString()
+{
+ //Scope
+ QString nodePart;
+ QString name=stringOptions_["node_name"]->value().simplified();
+ QString path=stringOptions_["node_path"]->value().simplified();
+ if(!name.isEmpty())
+ {
+ nodePart="node_name " + stringOptions_["node_name"]->matchOperator() + " \'" + name + "\'";
+ }
+ if(!path.isEmpty())
+ {
+ if(!nodePart.isEmpty())
+ nodePart+=" and ";
+
+ nodePart+="node_path " + stringOptions_["node_path"]->matchOperator() + " \'" + path + "\'";
+ }
+ if(!nodePart.isEmpty())
+ {
+ nodePart="(" + nodePart + ")";
+ }
+
+ //Type
+ QString typePart;
+ if(typeSelection().count() >0)
+ {
+ typePart="(" + typeSelection().join(" or ") + ")";
+ }
+
+ //State
+ QString statePart;
+ if(stateSelection().count() >0)
+ {
+ statePart="(" + stateSelection().join(" or ") + ")";
+ }
+
+ //Flag
+ QString flagPart;
+ if(flagSelection().count() >0)
+ {
+ flagPart="(" + flagSelection().join(" or ") + ")";
+ }
+
+ //Attributes
+ QString attrPart;
+ Q_FOREACH(QString gr,attrGroupSelection())
+ {
+ QString grPart;
+ Q_FOREACH(QString opName,attrTerms_[gr])
+ {
+ NodeQueryStringOption* op=stringOption(opName);
+ assert(op);
+ QString s=op->value();
+ if(!s.isEmpty())
+ {
+ if(!grPart.isEmpty())
+ grPart+=" or ";
+ grPart+=opName + " " + op->matchOperator() + " \'" + s + "\'";
+ }
+ }
+
+ if(grPart.isEmpty())
+ grPart=gr;
+
+
+ if(!attrPart.isEmpty())
+ attrPart+=" or ";
+ attrPart+=grPart;
+ }
+
+ if(!attrPart.isEmpty())
+ {
+ attrPart="(" + attrPart + ")";
+ }
+
+ //Put everything together
+ query_.clear();
+ extQuery_.clear();
+
+ if(!nodePart.isEmpty())
+ {
+ query_+=nodePart;
+ extQuery_["node"]=nodePart;
+ }
+
+ if(!typePart.isEmpty())
+ {
+ if(!query_.isEmpty())
+ query_+=" and ";
+
+ query_+=typePart;
+ extQuery_["type"]=typePart;
+ }
+
+ if(!statePart.isEmpty())
+ {
+ if(!query_.isEmpty())
+ query_+=" and ";
+
+ query_+=statePart;
+ extQuery_["state"]=statePart;
+ }
+
+ if(!flagPart.isEmpty())
+ {
+ if(!query_.isEmpty())
+ query_+=" and ";
+
+ query_+=flagPart;
+ extQuery_["flag"]=flagPart;
+ }
+
+ if(!attrPart.isEmpty())
+ {
+ if(!query_.isEmpty())
+ query_+=" and ";
+
+ query_+=attrPart;
+ extQuery_["attr"]=attrPart;
+ }
+
+ //Extended query
+ QString scopePart;
+ if(!servers_.isEmpty())
+ scopePart="servers = \'" + servers_.join(", ") + "\'";
+
+ if(servers_.size() <= 1 && !rootNode_.empty())
+ {
+ if(!scopePart.isEmpty())
+ scopePart+=" and ";
+
+ scopePart+="root_node = \'" + QString::fromStdString(rootNode_) + "\'";
+ }
+ if(!scopePart.isEmpty())
+ extQuery_["scope"]=scopePart;
+
+ if(query_.isEmpty())
+ extQuery_["node"] = "ALL";
+
+ QString opPart;
+ if(!ignoreMaxNum_)
+ {
+ opPart="max_results = " + QString::number(maxNum_);
+ }
+
+ if(query_.contains("="))
+ {
+ if(!opPart.isEmpty())
+ opPart+=" and ";
+ if(caseSensitive_)
+ opPart+="case_sensitive";
+ else
+ opPart+="case_insensitive";
+ }
+
+ if(!opPart.isEmpty())
+ extQuery_["options"]=opPart;
+}
+
+QString NodeQuery::extQueryHtml(bool multi,QColor bgCol,int firstColWidth) const
+{
+ QString str;
+ QString bg=bgCol.name();
+
+ if(multi)
+ {
+ str="<table width=\"100%\" cellPadding=\"2\">";
+ if(!extQuery_.value("scope").isEmpty())
+ str+="<tr><td width=\"" + QString::number(firstColWidth) + "\" bgcolor=\"" + bg +
+ "\">scope</td><td bgcolor=\"" + bg + "\">" + extQuery_.value("scope") + "</tr></td>";
+
+ QStringList nodeParts;
+ nodeParts << "node" << "type" << "state" << "flag";
+ Q_FOREACH(QString s,nodeParts)
+ {
+ if(!extQuery_.value(s).isEmpty())
+ {
+ //if(!str.isEmpty() && !str.contains("<td>nodes"))
+ // str+="<br>";
+
+ if(!str.contains("nodes</td>"))
+ str+="<tr><td bgcolor=\"" + bg + "\">nodes</td><td bgcolor=\"" + bg + "\">"+ extQuery_.value(s);
+ else
+ str+=" and<br> " + extQuery_.value(s);
+ }
+ }
+
+ if(str.contains("nodes</td>"))
+ str+="</td></tr>";
+
+ if(!extQuery_.value("options").isEmpty())
+ {
+ //if(!str.isEmpty())
+ // str+="\n";
+ str+="<tr><td bgcolor=\"" + bg + "\">options</td><td bgcolor=\"" + bg + "\">" + extQuery_.value("options") +"</td></tr>";
+ }
+
+ str+="</table>";
+ }
+
+ else
+ {
+ QString css;
+ css = "<style type=\"text/css\">";
+ css += "table.tbl {border-width: 1px;border-style: solid;border-color: \"#AAAAAA\";margin-top: 0px;margin-bottom: 0px;color: black;}";
+ //css += "table.tbl td {padding: 3px;}";
+ //css += "table.tbl th {padding: 3px;}";
+ css+="</style>";
+
+ QString bgDark=bgCol.darker(108).name();
+ str="<table cellSpacing=\"0\" class=\"tbl\">";
+
+ if(!extQuery_.value("scope").isEmpty())
+ str+="<tr><td bgcolor=\"" + bg + "\"> scope: </td>" +
+ "<td bgcolor=\"" + bgDark + "\"> " + extQuery_.value("scope") + " </td><td> </td>";
+
+ QStringList nodeParts;
+ nodeParts << "node" << "type" << "state" << "flag";
+ Q_FOREACH(QString s,nodeParts)
+ {
+ if(!extQuery_.value(s).isEmpty())
+ {
+ //if(!str.isEmpty() && !str.contains("nodes: "))
+ // str+=" | ";
+
+ if(!str.contains("nodes"))
+ str+=" <td bgcolor=\"" + bg + "\"> nodes: </td><td bgcolor=\"" + bgDark + "\"> "+ extQuery_.value(s);
+ else
+ str+=" and " + extQuery_.value(s);
+ }
+ }
+
+ if(str.contains("nodes:"))
+ str+=" </td></td><td> </td>";
+
+ if(!extQuery_.value("options").isEmpty())
+ {
+ //if(!str.isEmpty())
+ // str+=" | ";
+ str+=" <td bgcolor=\"" + bg + "\"> options: </td><td bgcolor=\"" + bgDark + "\"> " + extQuery_.value("options") + " </td>";
+ }
+
+ if(str.contains("<tr>"))
+ str+="</tr>";
+
+ str+="</table>";
+
+ //str=css+str;
+ }
+
+ return str;
+}
+
+void NodeQuery::load(VSettings* vs)
+{
+ advanced_=vs->getAsBool("advanced",advanced_);
+ caseSensitive_=vs->getAsBool("case",caseSensitive_);
+
+ int maxNum=vs->get<int>("maxNum",maxNum_);
+ if(maxNum_ > 1 && maxNum < 5000000)
+ maxNum_=maxNum;
+
+ std::vector<std::string> v;
+ vs->get("servers",v);
+ servers_.clear();
+ for(std::vector<std::string>::const_iterator it=v.begin(); it != v.end(); ++it)
+ servers_ << QString::fromStdString(*it);
+
+ //allServers_=vs->getAsBool("allServers",allServers_);
+
+ rootNode_=vs->get("rootNode",rootNode_);
+
+ Q_FOREACH(QString s,stringOptions_.keys())
+ {
+ stringOptions_[s]->load(vs);
+ }
+
+ Q_FOREACH(QString s,selectOptions_.keys())
+ {
+ selectOptions_[s]->load(vs);
+ }
+
+ buildQueryString();
+
+ //query_=QString::fromStdString(vs->get("query",query_.toStdString()));
+}
+
+void NodeQuery::save(VSettings* vs)
+{
+ if(advanced_)
+ vs->putAsBool("advanced",advanced_);
+
+ if(caseSensitive_)
+ vs->putAsBool("case",caseSensitive_);
+
+ if(maxNum_ != defaultMaxNum_)
+ vs->put("maxNum",maxNum_);
+
+ std::vector<std::string> v;
+ Q_FOREACH(QString s, servers_)
+ v.push_back(s.toStdString());
+
+ //if(!allServers_)
+ // vs->putAsBool("allServers",allServers_);
+
+ if(!v.empty())
+ vs->put("servers",v);
+
+ if(!rootNode_.empty())
+ vs->put("rootNode",rootNode_);
+
+ Q_FOREACH(QString s,stringOptions_.keys())
+ {
+ stringOptions_[s]->save(vs);
+ }
+
+ Q_FOREACH(QString s,selectOptions_.keys())
+ {
+ selectOptions_[s]->save(vs);
+ }
+
+ //vs->put("query",query_.toStdString());
+}
+
+std::vector<std::string> NodeQuery::lstToVec(QStringList lst) const
+{
+ std::vector<std::string> vec;
+ Q_FOREACH(QString s,lst)
+ vec.push_back(s.toStdString());
+ return vec;
+}
+
+QStringList NodeQuery::vecToLst(const std::vector<std::string>& vec) const
+{
+ QStringList lst;
+ for(std::vector<std::string>::const_iterator it=vec.begin(); it != vec.end(); ++it)
+ lst << QString::fromStdString(*it);
+ return lst;
+}
+
+
diff --git a/Viewer/src/NodeQuery.hpp b/Viewer/src/NodeQuery.hpp
new file mode 100644
index 0000000..94fc93d
--- /dev/null
+++ b/Viewer/src/NodeQuery.hpp
@@ -0,0 +1,179 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VIEWER_SRC_NODEQUERY_HPP_
+#define VIEWER_SRC_NODEQUERY_HPP_
+
+#include <string>
+#include <vector>
+
+#include <QColor>
+#include <QStringList>
+#include <QMap>
+
+#include "StringMatchMode.hpp"
+#include "VSettings.hpp"
+
+class NodeQuery;
+
+
+class NodeQueryStringOption
+{
+ friend class NodeQuery;
+
+public:
+ NodeQueryStringOption(QString name);
+ void swap(const NodeQueryStringOption*);
+
+ //enum MatchMode {ContainsMatch=0,WildcardMatch=1,RegexpMatch=2};
+
+ QString name() const {return name_;}
+ QString value() const {return value_;}
+ const StringMatchMode& matchMode() const {return matchMode_;}
+ QString matchOperator() const {return QString::fromStdString(matchMode_.matchOperator());}
+ bool caseSensitive() const {return caseSensitive_;}
+
+ void setValue(QString s) {value_=s;}
+ void setMatchMode(StringMatchMode::Mode m) {matchMode_.setMode(m);}
+ void setMatchMode(const StringMatchMode& m) {matchMode_=m;}
+ void setCaseSensitive(bool b) {caseSensitive_=b;}
+
+ void load(VSettings*);
+ void save(VSettings*);
+
+protected:
+ QString name_;
+ QString value_;
+ StringMatchMode matchMode_;
+ bool caseSensitive_;
+
+ static StringMatchMode::Mode defaultMatchMode_;
+ static bool defaultCaseSensitive_;
+ //static QMap<MatchMode,QString> matchOper_;
+};
+
+class NodeQuerySelectOption
+{
+ friend class NodeQuery;
+
+public:
+ NodeQuerySelectOption(QString name) : name_(name) {}
+ void swap(const NodeQuerySelectOption*);
+
+ void load(VSettings*);
+ void save(VSettings*);
+
+ QString name() const {return name_;}
+ QStringList selection() const {return selection_;}
+
+protected:
+ QString name_;
+ QStringList selection_;
+};
+
+
+class NodeQuery
+{
+public:
+ NodeQuery(const std::string& name,bool ignoreMaxNum=false);
+ ~NodeQuery();
+ NodeQuery* clone();
+ NodeQuery* clone(const std::string& name);
+
+ void swap(const NodeQuery*);
+
+ void setName(const std::string& name);
+ const std::string& name() const {return name_;}
+
+ void setQuery(QString);
+ const QString query() const {return query_;}
+
+ void setRootNode(const std::string& rootNode) {rootNode_=rootNode;}
+ const std::string& rootNode() const {return rootNode_;}
+
+ //void setServers(QStringList servers,bool all=false) {servers_=servers; allServers_=all;}
+ void setServers(QStringList servers) {servers_=servers;}
+ //const std::vector<std::string>& servers() const {return servers_;}
+ QStringList servers() const {return servers_;}
+ bool hasServer(const std::string& name) const;
+ void adjustServers(const std::vector<std::string>& servers);
+
+ QString extQueryHtml(bool multi,QColor bgCol,int firstColWidth) const;
+ void buildQueryString();
+
+ int maxNum() const {return maxNum_;}
+ void setMaxNum(int m) {maxNum_=m;}
+ bool ignoreMaxNum() const {return ignoreMaxNum_;}
+
+ void setCaseSensitive(bool b) {caseSensitive_=b;}
+ bool caseSensitive() const {return caseSensitive_;}
+
+ NodeQueryStringOption* stringOption(QString name) const;
+
+ QStringList typeSelection() const;
+ QStringList stateSelection() const;
+ QStringList flagSelection() const;
+ QStringList attrGroupSelection() const;
+
+ std::vector<std::string> typeSelectionVec() const;
+ std::vector<std::string>stateSelectionVec() const;
+ std::vector<std::string>flagSelectionVec() const;
+ std::vector<std::string>attrGroupSelectionVec() const;
+
+ void setTypeSelection(QStringList);
+ void setStateSelection(QStringList);
+ void setFlagSelection(QStringList);
+ void setAttrGroupSelection(QStringList);
+
+ void setTypeSelection(const std::vector<std::string>&);
+ void setStateSelection(const std::vector<std::string>&);
+ void setFlagSelection(const std::vector<std::string>&);
+ void setAttrGroupSelection(const std::vector<std::string>&);
+
+ static QStringList typeTerms() {return typeTerms_;}
+ static QStringList stateTerms() {return stateTerms_;}
+ static QStringList flagTerms() {return flagTerms_;}
+ static QStringList attrGroupTerms() {return attrGroupTerms_;}
+ static QStringList attrTerms(QString group) {return attrTerms_.value(group);}
+
+ void load(VSettings*);
+ void save(VSettings*);
+
+protected:
+ void checkDir();
+ std::vector<std::string> lstToVec(QStringList) const;
+ QStringList vecToLst(const std::vector<std::string>&) const;
+
+ std::string name_;
+ bool advanced_;
+ std::string rootNode_;
+ QStringList servers_;
+ bool allServers_;
+ QString query_;
+ QMap<QString,QString> extQuery_;
+ bool caseSensitive_;
+ int maxNum_;
+ bool ignoreMaxNum_;
+
+ QMap<QString,NodeQueryStringOption*> stringOptions_;
+ QMap<QString,NodeQuerySelectOption*> selectOptions_;
+
+ static QStringList nodeTerms_;
+ static QStringList typeTerms_;
+ static QStringList stateTerms_;
+ static QStringList flagTerms_;
+ static QStringList attrGroupTerms_;
+ static QMap<QString,QStringList> attrTerms_;
+
+ static bool defaultCaseSensitive_;
+ static int defaultMaxNum_;
+};
+
+#endif /* VIEWER_SRC_NODEQUERY_HPP_ */
diff --git a/Viewer/src/NodeQueryCombo.cpp b/Viewer/src/NodeQueryCombo.cpp
new file mode 100644
index 0000000..4fbda1a
--- /dev/null
+++ b/Viewer/src/NodeQueryCombo.cpp
@@ -0,0 +1,43 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "NodeQueryCombo.hpp"
+
+#include "NodeQuery.hpp"
+#include "NodeQueryHandler.hpp"
+
+#include <QVariant>
+
+NodeQueryCombo::NodeQueryCombo(QWidget* parent) : QComboBox(parent)
+{
+ for(std::vector<NodeQuery*>::const_iterator it=NodeQueryHandler::instance()->items().begin();
+ it != NodeQueryHandler::instance()->items().end(); ++it)
+ {
+ addItem(QString::fromStdString((*it)->name()));
+ }
+
+ connect(this,SIGNAL(currentIndexChanged(int)),
+ this,SLOT(slotCurrentChanged(int)));
+}
+
+void NodeQueryCombo::slotCurrentChanged(int current)
+{
+ if(current != -1)
+ Q_EMIT changed(itemData(current).toString());
+}
+
+
+
+
+
+
+
+
+
diff --git a/Viewer/src/NodeQueryCombo.hpp b/Viewer/src/NodeQueryCombo.hpp
new file mode 100644
index 0000000..fb0fd33
--- /dev/null
+++ b/Viewer/src/NodeQueryCombo.hpp
@@ -0,0 +1,29 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+#ifndef VIEWER_SRC_NODEQUERYCOMBO_HPP_
+#define VIEWER_SRC_NODEQUERYCOMBO_HPP_
+
+#include <QComboBox>
+
+class NodeQueryCombo : public QComboBox
+{
+Q_OBJECT
+
+public:
+ explicit NodeQueryCombo(QWidget* parent=0);
+
+protected Q_SLOTS:
+ void slotCurrentChanged(int current);
+
+Q_SIGNALS:
+ void changed(QString);
+};
+
+#endif /* VIEWER_SRC_NODEQUERYCOMBO_HPP_ */
diff --git a/Viewer/src/NodeQueryEditor.cpp b/Viewer/src/NodeQueryEditor.cpp
new file mode 100644
index 0000000..a28cba2
--- /dev/null
+++ b/Viewer/src/NodeQueryEditor.cpp
@@ -0,0 +1,730 @@
+//============================================================================
+// Copyright 2015 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+
+#include "NodeQueryEditor.hpp"
+
+#include "ComboMulti.hpp"
+#include "CustomListWidget.hpp"
+#include "Highlighter.hpp"
+#include "NodeQuery.hpp"
+#include "NodeQueryHandler.hpp"
+#include "ServerFilter.hpp"
+#include "ServerHandler.hpp"
+#include "VNode.hpp"
+#include "VNState.hpp"
+
+#include <QtGlobal>
+#include <QCloseEvent>
+#include <QDebug>
+#include <QMessageBox>
+#include <QPalette>
+#include <QVBoxLayout>
+
+//======================================================
+//
+// NodeQuerySaveDialog
+//
+//======================================================
+
+NodeQuerySaveDialog::NodeQuerySaveDialog(QWidget *parent) : QDialog(parent)
+{
+ setupUi(this);
+}
+
+QString NodeQuerySaveDialog::name() const
+{
+ return nameLe_->text();
+}
+
+void NodeQuerySaveDialog::accept()
+{
+ QString name=nameLe_->text();
+
+ if(!name.contains(QRegExp("[\\w|\\s]+")))
+ {
+ QMessageBox::critical(0,tr("Invalid character"),
+ "Query names can only contain alphanumeric characters, whitespaces and \"_\". Please choose a different name.");
+ return;
+
+ }
+
+ if(NodeQueryHandler::instance()->find(name.toStdString()))
+ {
+ QMessageBox::critical(0,tr("Duplicated"),
+ "The specified name is already used by another query. Please choose a different name.");
+ return;
+ }
+
+ QDialog::accept();
+}
+
+//======================================================
+//
+// NodeQueryEditor
+//
+//======================================================
+
+NodeQueryEditor::NodeQueryEditor(QWidget *parent) :
+ QWidget(parent),
+ query_(NULL),
+ serverFilter_(NULL),
+ queryTeCanExpand_(false),
+ initIsOn_(false),
+ canBeRun_(false)
+{
+ setupUi(this);
+
+ query_=new NodeQuery("tmp");
+ attrPanel_->setQuery(query_);
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
+ nameLe_->setClearButtonEnabled(true);
+ pathLe_->setClearButtonEnabled(true);
+ rootLe_->setClearButtonEnabled(true);
+#endif
+
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ nameLe_->setPlaceholderText(tr("ANY"));
+ pathLe_->setPlaceholderText(tr("ANY"));
+#endif
+
+ //-------------------------
+ // Query display
+ //-------------------------
+
+
+ //QFont f("Courier");
+ /*QFont f("Monospace");
+ f.setStyleHint(QFont::TypeWriter);
+ f.setFixedPitch(true);
+ f.setPointSize(10);
+ f.setStyleStrategy(QFont::PreferAntialias);
+ queryTe_->setFont(f);*/
+
+ QFont f;
+ QFontMetrics fm(f);
+
+ queryTe_->setFixedHeight((fm.height()+2)*3+6);
+ queryTe_->setReadOnly(true);
+ queryTe_->setWordWrapMode(QTextOption::NoWrap);
+
+ Highlighter* ih=new Highlighter(queryTe_->document(),"query");
+
+ //------------------
+ // Options
+ //------------------
+
+ //Max item num
+ numSpin_->setRange(10,250000);
+ numSpin_->setValue(query_->maxNum());
+ numSpin_->setToolTip(tr("The maximum possible value is: ") + QString::number(numSpin_->maximum()));
+
+ connect(numSpin_,SIGNAL(valueChanged(int)),
+ this,SLOT(slotMaxNum(int)));
+
+ caseCb_->setChecked(query_->caseSensitive());
+
+ connect(caseCb_,SIGNAL(clicked(bool)),
+ this,SLOT(slotCase(bool)));
+
+ //-------------------------
+ // Scope
+ //-------------------------
+
+ //Servers
+ serverCb_->setMode(ComboMulti::FilterMode);
+
+ serverResetTb_->setEnabled(serverCb_->hasSelection());
+
+ connect(serverCb_,SIGNAL(selectionChanged()),
+ this,SLOT(slotServerCbChanged()));
+
+ connect(serverResetTb_,SIGNAL(clicked()),
+ serverCb_,SLOT(clearSelection()));
+
+ //Root
+ connect(rootLe_,SIGNAL(textChanged(QString)),
+ this,SLOT(slotRootNodeEdited(QString)));
+
+ //Name
+ connect(nameLe_,SIGNAL(textChanged(QString)),
+ this,SLOT(slotNameEdited(QString)));
+
+ connect(nameMatchCb_,SIGNAL(currentIndexChanged(int)),
+ this,SLOT(slotNameMatchChanged(int)));
+
+ /*connect(nameCaseTb_,SIGNAL(changed(bool)),
+ this,SLOT(slotNameCaseChanged(bool)));*/
+
+ //Path
+ connect(pathLe_,SIGNAL(textChanged(QString)),
+ this,SLOT(slotPathEdited(QString)));
+
+ connect(pathMatchCb_,SIGNAL(currentIndexChanged(int)),
+ this,SLOT(slotPathMatchChanged(int)));
+
+ /*connect(pathCaseTb_,SIGNAL(changed(bool)),
+ this,SLOT(slotPathCaseChanged(bool)));*/
+
+ //-------------------------
+ // Filter
+ //-------------------------
+
+ //Node type
+ typeList_->addItems(NodeQuery::typeTerms(),false);
+
+ connect(typeList_,SIGNAL(selectionChanged()),
+ this,SLOT(slotTypeListChanged()));
+
+ connect(typeResetTb_,SIGNAL(clicked()),
+ typeList_,SLOT(clearSelection()));
+
+ //Node state
+ stateList_->addItems(NodeQuery::stateTerms(),false); //,stateColLst);
+
+ connect(stateList_,SIGNAL(selectionChanged()),
+ this,SLOT(slotStateListChanged()));
+
+ connect(stateResetTb_,SIGNAL(clicked()),
+ stateList_,SLOT(clearSelection()));
+
+ /*QStringList stateLst;
+ stateLst << "aborted" << "active" << "complete" << "queued" << "submitted" << "suspended" << "unknown";
+ QList<QColor> stateColLst;
+ Q_FOREACH(QString s,stateLst)
+ {
+ if(VNState* vn=VNState::find(s.toStdString()))
+ {
+ stateColLst << vn->colour();
+ }
+ else
+ {
+ stateColLst << QColor();
+ }
+ }
+
+ stateList_->addItems(stateLst,false); //,stateColLst);*/
+
+ //Node flags
+ flagList_->addItems(NodeQuery::flagTerms(),false);
+
+ connect(flagList_,SIGNAL(selectionChanged()),
+ this,SLOT(slotFlagListChanged()));
+
+ connect(flagResetTb_,SIGNAL(clicked()),
+ flagList_,SLOT(clearSelection()));
+
+ //Attributes
+ attrList_->addItems(NodeQuery::attrGroupTerms(),false);
+
+ connect(attrList_,SIGNAL(selectionChanged()),
+ this,SLOT(slotAttrListChanged()));
+
+ connect(attrResetTb_,SIGNAL(clicked()),
+ attrList_,SLOT(clearSelection()));
+
+ int listHeight=(fm.height()+2)*6+6;
+ typeList_->setFixedHeight(listHeight);
+ stateList_->setFixedHeight(listHeight);
+ flagList_->setFixedHeight(listHeight);
+ attrList_->setFixedHeight(listHeight);
+
+ typeResetTb_->setEnabled(typeList_->hasSelection());
+ stateResetTb_->setEnabled(stateList_->hasSelection());
+ flagResetTb_->setEnabled(flagList_->hasSelection());
+ attrResetTb_->setEnabled(attrList_->hasSelection());
+
+ //--------------------------------
+ // Query management
+ //--------------------------------
+
+ connect(saveAsTb_,SIGNAL(clicked()),
+ this,SLOT(slotSaveQueryAs()));
+
+
+ connect(advModeTb_,SIGNAL(clicked(bool)),
+ this,SLOT(slotAdvMode(bool)));
+
+ queryManageW_->hide();
+
+ /*advModeTb_->hide();
+ queryCbLabel_->hide();
+ queryCb_->hide();
+ saveAsTb_->hide();
+ saveTb_->hide();*/
+
+ attrList_->hide();
+ attrLabel_->hide();
+ attrResetTb_->hide();
+
+ checkGuiState();
+}
+
+NodeQueryEditor::~NodeQueryEditor()
+{
+ delete query_;
+
+ if(serverFilter_)
+ serverFilter_->removeObserver(this);
+}
+
+void NodeQueryEditor::init()
+{
+ initIsOn_=true;
+
+ numSpin_->setValue(query_->maxNum());
+ caseCb_->setChecked(query_->caseSensitive());
+
+ numSpin_->setEnabled(!query_->ignoreMaxNum());
+ numLabel_->setEnabled(!query_->ignoreMaxNum());
+
+ //Servers
+ QStringList servers=query_->servers();
+ if(servers == serverCb_->all())
+ serverCb_->clearSelection();
+ else
+ serverCb_->setSelection(servers);
+
+ //Node name
+ NodeQueryStringOption* op=query_->stringOption("node_name");
+ assert(op);
+ nameLe_->setText(op->value());
+ nameMatchCb_->setMatchMode(op->matchMode());
+ //nameCaseTb_->setChecked(op->caseSensitive());
+
+ //Node path
+ op=query_->stringOption("node_path");
+ assert(op);
+ pathLe_->setText(op->value());
+ pathMatchCb_->setMatchMode(op->matchMode());
+ //pathCaseTb_->setChecked(op->caseSensitive());
+
+ //Lists
+ typeList_->setSelection(query_->typeSelection());
+ stateList_->setSelection(query_->stateSelection());
+ flagList_->setSelection(query_->flagSelection());
+ attrList_->setSelection(query_->attrGroupSelection());
+
+ attrPanel_->init();
+
+ initIsOn_=false;
+
+ updateQueryTe();
+ checkGuiState();
+}
+
+void NodeQueryEditor::setQueryTeCanExpand(bool b)
+{
+ queryTeCanExpand_=b;
+ if(queryTeCanExpand_)
+ {
+ queryTe_->setFixedHeight(QWIDGETSIZE_MAX);
+ }
+ else
+ {
+ adjustQueryTe();
+ }
+}
+
+void NodeQueryEditor::toggleDefPanelVisible()
+{
+ bool b=isDefPanelVisible();
+ scopeBox_->setVisible(!b);
+ filterBox_->setVisible(!b);
+ optionBox_->setVisible(!b);
+}
+
+bool NodeQueryEditor::isDefPanelVisible() const
+{
+ return scopeBox_->isVisible();
+}
+
+void NodeQueryEditor::slotAdvMode(bool b)
+{
+ filterBox_->setVisible(!b);
+ queryTe_->setReadOnly(!b);
+
+ if(b)
+ {
+ adjustQueryTe(6);
+ }
+ else
+ {
+ adjustQueryTe();
+ }
+}
+
+void NodeQueryEditor::slotMaxNum(int v)
+{
+ if(!initIsOn_)
+ {
+ query_->setMaxNum(v);
+ updateQueryTe();
+ }
+}
+
+void NodeQueryEditor::slotCase(bool b)
+{
+ if(!initIsOn_)
+ {
+ query_->setCaseSensitive(b);
+ updateQueryTe();
+ }
+}
+
+void NodeQueryEditor::slotServerCbChanged()
+{
+ serverResetTb_->setEnabled(serverCb_->hasSelection());
+
+ if(!initIsOn_)
+ {
+ query_->setServers(serverCb_->selection());
+ updateQueryTe();
+ checkGuiState();
+ }
+}
+
+void NodeQueryEditor::slotRootNodeEdited(QString s)
+{
+ if(!initIsOn_)
+ {
+ query_->setRootNode(rootLe_->text().simplified().toStdString());
+ updateQueryTe();
+ checkGuiState();
+ }
+}
+
+void NodeQueryEditor::slotNameEdited(QString val)
+{
+ if(!initIsOn_)
+ {
+ NodeQueryStringOption* op=query_->stringOption("node_name");
+ assert(op);
+ op->setValue(val);
+ updateQueryTe();
+ checkGuiState();
+ }
+}
+
+void NodeQueryEditor::slotNameMatchChanged(int val)
+{
+ if(!initIsOn_)
+ {
+ NodeQueryStringOption* op=query_->stringOption("node_name");
+ assert(op);
+ op->setMatchMode(nameMatchCb_->matchMode(val));
+ updateQueryTe();
+ checkGuiState();
+ }
+}
+
+
+void NodeQueryEditor::slotNameCaseChanged(bool val)
+{
+ /*if(!initIsOn_)
+ {
+ NodeQueryStringOption* op=query_->stringOption("node_name");
+ assert(op);
+ op->setCaseSensitive(val);
+ updateQueryTe();
+ checkGuiState();
+ }*/
+}
+
+void NodeQueryEditor::slotPathEdited(QString val)
+{
+ if(!initIsOn_)
+ {
+ NodeQueryStringOption* op=query_->stringOption("node_path");
+ assert(op);
+ op->setValue(val);
+ updateQueryTe();
+ checkGuiState();
+ }
+}
+
+void NodeQueryEditor::slotPathMatchChanged(int val)
+{
+ if(!initIsOn_)
+ {
+ NodeQueryStringOption* op=query_->stringOption("node_path");
+ assert(op);
+ op->setMatchMode(pathMatchCb_->matchMode(val));
+ updateQueryTe();
+ checkGuiState();
+ }
+}
+
+void NodeQueryEditor::slotPathCaseChanged(bool val)
+{
+ /*if(!initIsOn_)
+ {
+ NodeQueryStringOption* op=query_->stringOption("node_path");
+ assert(op);
+ op->setCaseSensitive(val);
+ updateQueryTe();
+ checkGuiState();
+ }*/
+}
+
+void NodeQueryEditor::slotTypeListChanged()
+{
+ typeResetTb_->setEnabled(typeList_->hasSelection());
+ if(!initIsOn_)
+ {
+ query_->setTypeSelection(typeList_->selection());
+ updateQueryTe();
+ checkGuiState();
+ }
+}
+
+void NodeQueryEditor::slotStateListChanged()
+{
+ stateResetTb_->setEnabled(stateList_->hasSelection());
+ if(!initIsOn_)
+ {
+ query_->setStateSelection(stateList_->selection());
+ updateQueryTe();
+ checkGuiState();
+ }
+}
+
+void NodeQueryEditor::slotFlagListChanged()
+{
+ flagResetTb_->setEnabled(flagList_->hasSelection());
+ if(!initIsOn_)
+ {
+ query_->setFlagSelection(flagList_->selection());
+ updateQueryTe();
+ checkGuiState();
+ }
+}
+
+void NodeQueryEditor::slotAttrListChanged()
+{
+ if(!initIsOn_)
+ {
+ attrResetTb_->setEnabled(attrList_->hasSelection());
+ attrPanel_->setSelection(attrList_->selection());
+ query_->setAttrGroupSelection(attrList_->selection());
+ updateQueryTe();
+ checkGuiState();
+ }
+}
+
+void NodeQueryEditor::checkGuiState()
+{
+ serverResetTb_->setEnabled(serverCb_->hasSelection());
+
+ bool oneServer=(serverCb_->count() == 1 || serverCb_->selection().count() == 1);
+
+ rootLabel_->setEnabled(oneServer);
+ rootLe_->setEnabled(oneServer);
+}
+
+void NodeQueryEditor::updateQueryTe()
+{
+ query_->buildQueryString();
+
+ QColor bg(241,241,241);
+ setQueryTe(query_->extQueryHtml(true,bg,65));
+}
+
+void NodeQueryEditor::setQueryTe(QString s)
+{
+ int rowNum=s.count("<tr>")+s.count("<br>")+1;
+ if(rowNum==0 && !s.isEmpty())
+ rowNum=1;
+
+ int oldRowNum=queryTe_->toPlainText().count("\n")+1;
+ if(oldRowNum==0 && !queryTe_->toPlainText().isEmpty())
+ oldRowNum=1;
+
+ queryTe_->setHtml(s);
+
+ if(!queryTeCanExpand_)
+ {
+ if(oldRowNum != rowNum && (oldRowNum > 3 || rowNum > 3))
+ {
+ QFont f;
+ QFontMetrics fm(f);
+
+ queryTe_->setFixedHeight((fm.height()+2)*rowNum+6);
+ }
+ }
+}
+
+void NodeQueryEditor::adjustQueryTe(int rn)
+{
+ int rowNum=0;
+ if(rn <= 0)
+ {
+ rowNum=queryTe_->toPlainText().count("\n")+1;
+ }
+ else
+ {
+ rowNum=rn;
+ }
+
+ if(rowNum < 3)
+ rowNum=3;
+
+ if(!queryTeCanExpand_)
+ {
+ QFontMetrics fm(queryTe_->font());
+
+ queryTe_->setFixedHeight((fm.height()+2)*rowNum+6);
+ }
+}
+
+//------------------------------------------
+// Servers
+//------------------------------------------
+
+QStringList NodeQueryEditor::allServers() const
+{
+ return serverCb_->all();
+}
+
+void NodeQueryEditor::updateServers()
+{
+ serverCb_->clear();
+
+ if(serverFilter_)
+ {
+ for(std::vector<ServerItem*>::const_iterator it=serverFilter_->items().begin(); it != serverFilter_->items().end(); ++it)
+ {
+ serverCb_->addItem(QString::fromStdString((*it)->name()));
+ }
+ }
+
+ //Init
+ if(serverCb_->count() == 1)
+ {
+ //serverCb_->selectSoleItem();
+ }
+ else
+ {
+ //slotServerCbChanged();
+ }
+
+ slotServerCbChanged();
+
+}
+
+void NodeQueryEditor::setServerFilter(ServerFilter* sf)
+{
+ if(serverFilter_ == sf)
+ return;
+
+ if(serverFilter_)
+ {
+ serverFilter_->removeObserver(this);
+ }
+
+ serverFilter_=sf;
+
+ if(serverFilter_)
+ {
+ serverFilter_->addObserver(this);
+ }
+
+ updateServers();
+}
+
+void NodeQueryEditor::notifyServerFilterAdded(ServerItem* item)
+{
+ /*ServerHandler* s=item->serverHandler();
+ s->addServerObserver(this);
+ updateTitle();*/
+}
+
+void NodeQueryEditor::notifyServerFilterRemoved(ServerItem* item)
+{
+ /*ServerHandler* s=item->serverHandler();
+ s->removeServerObserver(this);
+ updateTitle();*/
+}
+
+void NodeQueryEditor::notifyServerFilterChanged(ServerItem*)
+{
+ //updateTitle();
+}
+
+void NodeQueryEditor::notifyServerFilterDelete()
+{
+ serverFilter_->removeObserver(this);
+ serverFilter_=0;
+}
+
+//------------------------------------------
+// Root node
+//------------------------------------------
+
+void NodeQueryEditor::setRootNode(VInfo_ptr info)
+{
+ if(info && info.get())
+ {
+ if(ServerHandler *server=info->server())
+ {
+ QStringList sel(QString::fromStdString(server->name()));
+ serverCb_->setSelection(sel);
+
+ if(info->isNode())
+ {
+ if(VNode *node=info->node())
+ {
+ rootLe_->setText(QString::fromStdString(node->absNodePath()));
+ }
+ }
+ else
+ {
+ rootLe_->clear();
+ }
+ }
+ }
+}
+
+//------------------------------------------
+// Query
+//------------------------------------------
+
+int NodeQueryEditor::maxNum() const
+{
+ return numSpin_->value();
+}
+
+NodeQuery* NodeQueryEditor::query() const
+{
+ return query_;
+}
+
+//------------------------------------------
+// Query management
+//------------------------------------------
+
+void NodeQueryEditor::setQuery(NodeQuery* q)
+{
+ query_->swap(q);
+ init();
+}
+
+
+void NodeQueryEditor::slotSaveQueryAs()
+{
+ NodeQuerySaveDialog d(this);
+ if(d.exec() == QDialog::Accepted)
+ {
+ std::string name=d.name().toStdString();
+ NodeQuery* q=query_->clone(name);
+ NodeQueryHandler::instance()->add(q,true);
+ }
+}
diff --git a/Viewer/src/NodeQueryEditor.hpp b/Viewer/src/NodeQueryEditor.hpp
new file mode 100644
index 0000000..d0a2c1d
--- /dev/null
+++ b/Viewer/src/NodeQueryEditor.hpp
@@ -0,0 +1,102 @@
+//============================================================================
+// Copyright 2015 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef NODEQUERYEDITOR_HPP_
+#define NODEQUERYEDITOR_HPP_
+
+#include "ui_NodeQueryEditor.h"
+#include "ui_NodeQuerySaveDialog.h"
+
+
+#include <QAbstractItemModel>
+#include <QDialog>
+#include <QWidget>
+
+#include "ServerFilter.hpp"
+#include "VInfo.hpp"
+
+class NodeQuery;
+class NodeQueryListModel;
+
+class NodeQuerySaveDialog : public QDialog, protected Ui::NodeQuerySaveDialog
+{
+Q_OBJECT
+
+public:
+ explicit NodeQuerySaveDialog(QWidget *parent = 0);
+ ~NodeQuerySaveDialog() {}
+ QString name() const;
+
+public Q_SLOTS:
+ void accept();
+};
+
+
+class NodeQueryEditor : public QWidget, protected Ui::NodeQueryEditor, public ServerFilterObserver
+{
+ Q_OBJECT
+
+public:
+ explicit NodeQueryEditor(QWidget *parent = 0);
+ ~NodeQueryEditor();
+
+ void setServerFilter(ServerFilter*);
+ void setRootNode(VInfo_ptr);
+ void setQuery(NodeQuery*);
+ NodeQuery* query() const;
+ void setQueryTeCanExpand(bool);
+ void toggleDefPanelVisible();
+ bool isDefPanelVisible() const;
+ int maxNum() const;
+ QStringList allServers() const;
+
+ void notifyServerFilterAdded(ServerItem*);
+ void notifyServerFilterRemoved(ServerItem*);
+ void notifyServerFilterChanged(ServerItem*);
+ void notifyServerFilterDelete();
+
+protected Q_SLOTS:
+ void slotServerCbChanged();
+ void slotRootNodeEdited(QString);
+ void slotNameEdited(QString);
+ void slotNameMatchChanged(int);
+ void slotNameCaseChanged(bool);
+ void slotPathEdited(QString);
+ void slotPathMatchChanged(int);
+ void slotPathCaseChanged(bool);
+ void slotTypeListChanged();
+ void slotStateListChanged();
+ void slotFlagListChanged();
+ void slotAttrListChanged();
+ void slotSaveQueryAs();
+ void slotAdvMode(bool b);
+ void slotMaxNum(int);
+ void slotCase(bool);
+
+Q_SIGNALS:
+ void queryEnabledChanged(bool);
+
+private:
+ void updateServers();
+ void init();
+ void initAttr();
+ void updateQueryTe();
+ void adjustQueryTe(int rowNum=0);
+ void setQueryTe(QString);
+ void checkGuiState();
+
+ NodeQuery* query_;
+ ServerFilter* serverFilter_;
+ bool queryTeCanExpand_;
+ bool initIsOn_;
+ bool canBeRun_;
+};
+
+#endif
diff --git a/Viewer/src/NodeQueryEditor.ui b/Viewer/src/NodeQueryEditor.ui
new file mode 100644
index 0000000..e0a12bc
--- /dev/null
+++ b/Viewer/src/NodeQueryEditor.ui
@@ -0,0 +1,371 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>NodeQueryEditor</class>
+ <widget class="QWidget" name="NodeQueryEditor">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>1564</width>
+ <height>1113</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="queryManageW_" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="queryCbLabel_">
+ <property name="text">
+ <string>Queries:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="NodeQueryCombo" name="queryCb_"/>
+ </item>
+ <item>
+ <widget class="QToolButton" name="saveAsTb_">
+ <property name="text">
+ <string>Save query as ...</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="saveTb_">
+ <property name="text">
+ <string>Save query</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QToolButton" name="advModeTb_">
+ <property name="text">
+ <string>Advanced mode</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QGroupBox" name="scopeBox_">
+ <property name="title">
+ <string>Scope</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="2">
+ <widget class="ComboMulti" name="serverCb_"/>
+ </item>
+ <item row="0" column="3">
+ <widget class="QToolButton" name="serverResetTb_">
+ <property name="toolTip">
+ <string>Clear server filter</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/reset_to_default.svg</normaloff>:/viewer/reset_to_default.svg</iconset>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="rootLabel_">
+ <property name="text">
+ <string>Search root node:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_6">
+ <property name="text">
+ <string>Search in servers:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <widget class="QLineEdit" name="rootLe_"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="optionBox_">
+ <property name="title">
+ <string>Options</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QLabel" name="numLabel_">
+ <property name="text">
+ <string>Max results: </string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="numSpin_">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="caseCb_">
+ <property name="text">
+ <string>Case sensitive</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="filterBox_">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Nodes</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,0,1">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetMinAndMaxSize</enum>
+ </property>
+ <item>
+ <layout class="QGridLayout" name="gridLayout_3">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_7">
+ <property name="text">
+ <string>Name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_9">
+ <property name="text">
+ <string>Path:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="StringMatchCombo" name="nameMatchCb_"/>
+ </item>
+ <item row="0" column="2">
+ <widget class="QLineEdit" name="nameLe_"/>
+ </item>
+ <item row="1" column="1">
+ <widget class="StringMatchCombo" name="pathMatchCb_"/>
+ </item>
+ <item row="1" column="2">
+ <widget class="QLineEdit" name="pathLe_"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="4">
+ <widget class="QLabel" name="label_8">
+ <property name="text">
+ <string>Flag</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="6">
+ <widget class="QLabel" name="attrLabel_">
+ <property name="text">
+ <string>Attributes</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Type</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3">
+ <widget class="QToolButton" name="stateResetTb_">
+ <property name="toolTip">
+ <string>Clear status filter</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/reset_to_default.svg</normaloff>:/viewer/reset_to_default.svg</iconset>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="7">
+ <widget class="QToolButton" name="attrResetTb_">
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/reset_to_default.svg</normaloff>:/viewer/reset_to_default.svg</iconset>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="6" colspan="2">
+ <widget class="CustomListWidget" name="attrList_"/>
+ </item>
+ <item row="0" column="1">
+ <widget class="QToolButton" name="typeResetTb_">
+ <property name="toolTip">
+ <string>Clear type filter</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/reset_to_default.svg</normaloff>:/viewer/reset_to_default.svg</iconset>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Status</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="5">
+ <widget class="QToolButton" name="flagResetTb_">
+ <property name="toolTip">
+ <string>Clear flag filter</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/reset_to_default.svg</normaloff>:/viewer/reset_to_default.svg</iconset>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" colspan="2">
+ <widget class="CustomListWidget" name="typeList_"/>
+ </item>
+ <item row="1" column="2" colspan="2">
+ <widget class="CustomListWidget" name="stateList_"/>
+ </item>
+ <item row="1" column="4" colspan="2">
+ <widget class="CustomListWidget" name="flagList_"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="AttributeSearchPanel" name="attrPanel_" native="true"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_7">
+ <property name="spacing">
+ <number>4</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Query</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTextEdit" name="queryTe_"/>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>ComboMulti</class>
+ <extends>QComboBox</extends>
+ <header location="global">ComboMulti.hpp</header>
+ </customwidget>
+ <customwidget>
+ <class>AttributeSearchPanel</class>
+ <extends>QWidget</extends>
+ <header>AttributeSearchPanel.hpp</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>CustomListWidget</class>
+ <extends>QListWidget</extends>
+ <header>CustomListWidget.hpp</header>
+ </customwidget>
+ <customwidget>
+ <class>StringMatchCombo</class>
+ <extends>QComboBox</extends>
+ <header>StringMatchCombo.hpp</header>
+ </customwidget>
+ <customwidget>
+ <class>NodeQueryCombo</class>
+ <extends>QComboBox</extends>
+ <header>NodeQueryCombo.hpp</header>
+ </customwidget>
+ </customwidgets>
+ <resources>
+ <include location="viewer.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/Viewer/src/NodeQueryEngine.cpp b/Viewer/src/NodeQueryEngine.cpp
new file mode 100644
index 0000000..7caff9c
--- /dev/null
+++ b/Viewer/src/NodeQueryEngine.cpp
@@ -0,0 +1,302 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "NodeQueryEngine.hpp"
+
+#include <QStandardItemModel>
+
+#include "NodeExpression.hpp"
+#include "NodeQuery.hpp"
+#include "ServerDefsAccess.hpp"
+#include "ServerHandler.hpp"
+#include "UserMessage.hpp"
+#include "VFilter.hpp"
+#include "VNode.hpp"
+
+static bool metaRegistered=false;
+
+NodeQueryEngine::NodeQueryEngine(QObject* parent) :
+ QThread(parent),
+ query_(new NodeQuery("tmp")),
+ parser_(NULL),
+ stopIt_(false),
+ cnt_(0),
+ scanCnt_(0),
+ maxNum_(250000),
+ chunkSize_(100),
+ rootNode_(0)
+{
+ //We will need to pass various non-Qt types via signals and slots
+ //So we need to register these types.
+ if(!metaRegistered)
+ {
+ qRegisterMetaType<NodeQueryResultTmp_ptr>("NodeQueryResultTmp_ptr");
+ qRegisterMetaType<QList<NodeQueryResultTmp_ptr> >("QList<NodeQueryResultTmp_ptr>");
+ metaRegistered=true;
+ }
+
+ connect(this,SIGNAL(finished()),
+ this,SLOT(slotFinished()));
+}
+
+NodeQueryEngine::~NodeQueryEngine()
+{
+ delete query_;
+
+ if(parser_)
+ delete parser_;
+}
+
+bool NodeQueryEngine::runQuery(NodeQuery* query,QStringList allServers)
+{
+ if(isRunning())
+ wait();
+
+ stopIt_=false;
+ res_.clear();
+ cnt_=0;
+ scanCnt_=0;
+ rootNode_=0;
+
+ query_->swap(query);
+
+ maxNum_=query_->maxNum();
+
+ servers_.clear();
+
+ if(parser_)
+ delete parser_;
+
+ UserMessage::message(UserMessage::DBG,false, std::string("Query: " + query_->query().toStdString()));
+
+ parser_=NodeExpressionParser::instance()->parseWholeExpression(query_->query().toStdString(), query->caseSensitive());
+ if(parser_ == NULL)
+ {
+ UserMessage::message(UserMessage::ERROR,true, std::string("Error, unable to parse enabled condition: " + query_->query().toStdString()));
+ return false;
+ }
+
+ QStringList serverNames=query_->servers();
+ if(query_->servers().isEmpty())
+ serverNames=allServers;
+
+ Q_FOREACH(QString s,serverNames)
+ {
+ if(ServerHandler* server=ServerHandler::find(s.toStdString()))
+ {
+ servers_.push_back(server);
+ }
+ }
+
+ if(!query_->rootNode().empty())
+ {
+ if(servers_.size() != 1)
+ return false;
+
+ rootNode_=servers_.at(0)->vRoot()->find(query_->rootNode());
+ }
+
+ //Notify the servers that the search began
+ Q_FOREACH(ServerHandler* s,servers_)
+ {
+ s->searchBegan();
+ }
+
+ //Start thread execution
+ start();
+
+ return true;
+}
+
+void NodeQueryEngine::stopQuery()
+{
+ stopIt_=true;
+ wait();
+}
+
+void NodeQueryEngine::run()
+{
+ if(rootNode_)
+ {
+ run(servers_.at(0),rootNode_);
+ }
+ else
+ {
+ for(std::vector<ServerHandler*>::const_iterator it=servers_.begin(); it != servers_.end(); ++it)
+ {
+ ServerHandler *server=*it;
+
+ run(server,server->vRoot());
+
+ if(stopIt_)
+ {
+ broadcastChunk(true);
+ return;
+ }
+ }
+ }
+
+ broadcastChunk(true);
+}
+
+void NodeQueryEngine::run(ServerHandler *server,VNode* root)
+{
+ runRecursively(root);
+}
+
+void NodeQueryEngine::runRecursively(VNode *node)
+{
+ if(stopIt_)
+ return;
+
+ if(parser_->execute(node))
+ {
+ broadcastFind(node);
+ }
+
+ scanCnt_++;
+
+ for(int i=0; i < node->numOfChildren(); i++)
+ {
+ runRecursively(node->childAt(i));
+ if(stopIt_)
+ return;
+ }
+}
+
+void NodeQueryEngine::broadcastFind(VNode* node)
+{
+ NodeQueryResultTmp_ptr d(new NodeQueryResultTmp(node));
+
+ //Add to res vector
+ res_ << d;
+
+ broadcastChunk(false);
+
+ cnt_++;
+
+ if(cnt_ >= maxNum_)
+ {
+ broadcastChunk(true);
+ stopIt_=true;
+ }
+}
+
+void NodeQueryEngine::broadcastChunk(bool force)
+{
+ bool doIt=false;
+ if(!force)
+ {
+ if(res_.count() >= chunkSize_)
+ {
+ doIt=true;
+ }
+ }
+ else if(!res_.isEmpty())
+ {
+ doIt=true;
+ }
+
+ if(doIt)
+ {
+ Q_EMIT found(res_);
+ res_.clear();
+ }
+}
+
+void NodeQueryEngine::slotFinished()
+{
+ //Notify the servers that the search finished
+ Q_FOREACH(ServerHandler* s,servers_)
+ {
+ s->searchFinished();
+ }
+}
+
+void NodeQueryEngine::slotFailed()
+{
+
+}
+
+NodeFilterEngine::NodeFilterEngine(NodeFilter* owner) :
+ query_(new NodeQuery("tmp")),
+ parser_(NULL),
+ server_(NULL),
+ owner_(owner)
+{
+}
+
+NodeFilterEngine::~NodeFilterEngine()
+{
+ delete query_;
+
+ if(parser_)
+ delete parser_;
+}
+
+void NodeFilterEngine::setQuery(NodeQuery* query)
+{
+ query_->swap(query);
+
+ if(parser_)
+ delete parser_;
+
+ parser_=NodeExpressionParser::instance()->parseWholeExpression(query_->query().toStdString());
+ if(parser_ == NULL)
+ {
+ UserMessage::message(UserMessage::ERROR, true, std::string("Error, unable to parse enabled condition: " + query_->query().toStdString()));
+ }
+}
+
+
+void NodeFilterEngine::runQuery(ServerHandler* server)
+{
+ if(!query_)
+ return;
+
+ server_=server;
+ if(!server_)
+ return;
+
+ if(!parser_)
+ return;
+
+ runRecursively(server_->vRoot());
+}
+
+void NodeFilterEngine::runRecursively(VNode *node)
+{
+ if(!node->isServer() && parser_->execute(node))
+ {
+ //UserMessage::message(UserMessage::DBG,false,"FOUND: " + node->absNodePath());
+ //owner_->res_[node->index()]=node;
+ owner_->match_.push_back(node);
+ }
+
+ for(int i=0; i < node->numOfChildren(); i++)
+ {
+ runRecursively(node->childAt(i));
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Viewer/src/NodeQueryEngine.hpp b/Viewer/src/NodeQueryEngine.hpp
new file mode 100644
index 0000000..1fd5b6e
--- /dev/null
+++ b/Viewer/src/NodeQueryEngine.hpp
@@ -0,0 +1,91 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VIEWER_SRC_NODEQUERYENGINE_HPP_
+#define VIEWER_SRC_NODEQUERYENGINE_HPP_
+
+#include <string>
+#include <vector>
+
+#include <QStringList>
+#include <QThread>
+
+#include "NodeQueryResultTmp.hpp"
+
+class BaseNodeCondition;
+class ServerHandler;
+class VNode;
+class NodeFilter;
+class NodeQuery;
+class NodeQueryOptions;
+
+class NodeQueryEngine : public QThread
+{
+
+Q_OBJECT
+
+public:
+ explicit NodeQueryEngine(QObject* parent=0);
+ ~NodeQueryEngine();
+
+ bool runQuery(NodeQuery* query,QStringList allServers);
+ void stopQuery();
+ int scannedCount() const {return scanCnt_;}
+
+protected Q_SLOTS:
+ void slotFinished();
+ void slotFailed();
+
+Q_SIGNALS:
+ void found(NodeQueryResultTmp_ptr);
+ void found(QList<NodeQueryResultTmp_ptr>);
+
+protected:
+ void run();
+
+private:
+ void run(ServerHandler*,VNode*);
+ void runRecursively(VNode *node);
+ void broadcastFind(VNode*);
+ void broadcastChunk(bool);
+
+ NodeQuery* query_;
+ BaseNodeCondition* parser_;
+ std::vector<ServerHandler*> servers_;
+ int cnt_;
+ int scanCnt_;
+ int maxNum_;
+ int chunkSize_;
+ QList<NodeQueryResultTmp_ptr> res_;
+ bool stopIt_;
+ VNode* rootNode_;
+
+};
+
+class NodeFilterEngine
+{
+public:
+ explicit NodeFilterEngine(NodeFilter*);
+ ~NodeFilterEngine();
+
+ void runQuery(ServerHandler*);
+ void setQuery(NodeQuery*);
+
+private:
+ void runRecursively(VNode *node);
+
+ NodeQuery* query_;
+ BaseNodeCondition* parser_;
+ ServerHandler* server_;
+ NodeFilter *owner_;
+};
+
+
+#endif /* VIEWER_SRC_NODEQUERYENGINE_HPP_ */
diff --git a/Viewer/src/NodeQueryHandler.cpp b/Viewer/src/NodeQueryHandler.cpp
new file mode 100644
index 0000000..895b4fb
--- /dev/null
+++ b/Viewer/src/NodeQueryHandler.cpp
@@ -0,0 +1,115 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include <algorithm>
+
+#include "NodeQueryHandler.hpp"
+
+#include "DirectoryHandler.hpp"
+#include "File.hpp"
+#include "NodeQuery.hpp"
+
+NodeQueryHandler* NodeQueryHandler::instance_=0;
+
+NodeQueryHandler::NodeQueryHandler() : suffix_("query")
+{
+}
+
+NodeQueryHandler* NodeQueryHandler::instance()
+{
+ if(!instance_)
+ {
+ instance_=new NodeQueryHandler();
+ }
+
+ return instance_;
+}
+
+NodeQuery* NodeQueryHandler::add(const std::string& name)
+{
+ NodeQuery *item=new NodeQuery(name);
+ items_.push_back(item);
+ return item;
+}
+
+NodeQuery* NodeQueryHandler::add(const std::string& name,const std::string& query)
+{
+ NodeQuery *item=new NodeQuery(name);
+ items_.push_back(item);
+ return item;
+}
+
+void NodeQueryHandler::add(NodeQuery* item,bool saveToFile)
+{
+ items_.push_back(item);
+ if(saveToFile)
+ save(item);
+}
+
+
+void NodeQueryHandler::remove(const std::string&)
+{
+}
+
+void NodeQueryHandler::remove(NodeQuery*)
+{
+
+}
+
+NodeQuery* NodeQueryHandler::find(const std::string& name) const
+{
+ for(std::vector<NodeQuery*>::const_iterator it=items_.begin(); it != items_.end(); ++it)
+ {
+ if((*it)->name() == name)
+ return *it;
+ }
+ return NULL;
+}
+
+void NodeQueryHandler::save()
+{
+}
+
+void NodeQueryHandler::save(NodeQuery *item)
+{
+ std::string f=DirectoryHandler::concatenate(dirPath_,item->name() + "." + suffix_);
+ VSettings vs(f);
+ item->save(&vs);
+ vs.write();
+
+}
+
+void NodeQueryHandler::init(const std::string& dirPath)
+{
+ dirPath_=dirPath;
+ DirectoryHandler::createDir(dirPath_);
+
+ std::vector<std::string> res;
+ std::string pattern=".*\\." + suffix_ + "$";
+ DirectoryHandler::findFiles(dirPath_,pattern,res);
+
+ for(std::vector<std::string>::const_iterator it=res.begin(); it != res.end(); ++it)
+ {
+ std::string fName=DirectoryHandler::concatenate(dirPath_,*it);
+ VSettings vs(fName);
+ vs.read();
+
+ std::size_t pos=(*it).find("." + suffix_);
+ assert(pos != std::string::npos);
+
+ std::string name=(*it).substr(0,pos);
+ NodeQuery* item=add(name);
+ item->load(&vs);
+ }
+}
+
+
+
+
diff --git a/Viewer/src/NodeQueryHandler.hpp b/Viewer/src/NodeQueryHandler.hpp
new file mode 100644
index 0000000..e130eea
--- /dev/null
+++ b/Viewer/src/NodeQueryHandler.hpp
@@ -0,0 +1,46 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+#ifndef VIEWER_SRC_NODEQUERYHANDLER_HPP_
+#define VIEWER_SRC_NODEQUERYHANDLER_HPP_
+
+#include <string>
+#include <vector>
+
+class NodeQuery;
+
+class NodeQueryHandler
+{
+public:
+ NodeQueryHandler();
+
+ NodeQuery* add(const std::string& name);
+ NodeQuery* add(const std::string& name,const std::string& query);
+ void add(NodeQuery* item,bool save);
+ void remove(const std::string& name);
+ void remove(NodeQuery*);
+ NodeQuery* find(const std::string& name) const;
+
+ void save();
+ void save(NodeQuery*);
+ void init(const std::string& dirPath);
+ const std::vector<NodeQuery*>& items() const {return items_;}
+
+ static NodeQueryHandler* instance();
+
+protected:
+ static NodeQueryHandler* instance_;
+
+ std::string dirPath_;
+ const std::string suffix_;
+ std::vector<NodeQuery*> items_;
+};
+
+
+#endif /* VIEWER_SRC_NODEQUERYHANDLER_HPP_ */
diff --git a/Viewer/src/NodeQueryResult.cpp b/Viewer/src/NodeQueryResult.cpp
new file mode 100644
index 0000000..0c641fe
--- /dev/null
+++ b/Viewer/src/NodeQueryResult.cpp
@@ -0,0 +1,420 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "NodeQueryResult.hpp"
+
+#include "ServerHandler.hpp"
+#include "VNode.hpp"
+
+//========================================================
+//
+// NodeQueryResultItem
+//
+//========================================================
+
+NodeQueryResultItem::NodeQueryResultItem(VNode* node) :
+ node_(node),
+ server_(NULL)
+{
+ if(node_)
+ server_=node_->server();
+}
+
+NodeQueryResultItem::NodeQueryResultItem(NodeQueryResultTmp_ptr d)
+{
+ node_=d->node_;
+ attr_=d->attr_;
+
+ if(node_)
+ server_=node_->server();
+}
+
+void NodeQueryResultItem::invalidateNode()
+{
+ assert(node_);
+ path_=node_->absNodePath();
+ node_=NULL;
+}
+
+bool NodeQueryResultItem::updateNode()
+{
+ if(node_)
+ return (node_->server() != NULL);
+
+ else
+ {
+ node_=server_->vRoot()->find(path_);
+ path_.clear();
+ return (node_ != NULL);
+ }
+
+ return false;
+}
+
+QString NodeQueryResultItem::serverStr() const
+{
+ return (server_)?QString::fromStdString(server_->name()):QString();
+}
+
+QString NodeQueryResultItem::pathStr() const
+{
+ if(node_)
+ return QString::fromStdString(node_->absNodePath());
+
+ return QString::fromStdString(path_);
+}
+
+QString NodeQueryResultItem::typeStr() const
+{
+ if(node_)
+ return QString::fromStdString(node_->nodeType());
+
+ return QString("???");
+}
+
+QString NodeQueryResultItem::stateStr() const
+{
+ if(node_)
+ return node_->stateName();
+ return QString("???");
+}
+
+QColor NodeQueryResultItem::stateColour() const
+{
+ if(node_)
+ return node_->stateColour();
+ return QColor(Qt::transparent);
+}
+
+void NodeQueryResultBlock::add(VNode* node,int pos)
+{
+ if(pos_==-1)
+ pos_=pos;
+
+ cnt_++;
+
+ if(nodes_[node].pos_==-1)
+ {
+ nodes_[node].pos_=pos;
+ }
+ nodes_[node].cnt_++;
+}
+
+void NodeQueryResultBlock::clear()
+{
+ pos_=-1;
+ cnt_=0;
+ nodes_.clear();
+}
+
+bool NodeQueryResultBlock::find(const VNode* nc,int &pos, int &cnt)
+{
+ QHash<VNode*,Pos>::const_iterator it = nodes_.find(const_cast<VNode*>(nc));
+ if(it != nodes_.end())
+ {
+ pos=it.value().pos_;
+ cnt=it.value().cnt_;
+ return true;
+ }
+
+ return false;
+}
+
+//========================================================
+//
+// NodeQueryResult
+//
+//========================================================
+
+NodeQueryResult::NodeQueryResult(QObject *parent) :
+ QObject(parent)
+{
+}
+
+NodeQueryResult::~NodeQueryResult()
+{
+ clear();
+}
+
+NodeQueryResultItem* NodeQueryResult::itemAt(int i)
+{
+ if(i >= 0 && i < data_.size())
+ return data_.at(i);
+
+ return NULL;
+}
+
+void NodeQueryResult::add(NodeQueryResultTmp_ptr item)
+{
+ ServerHandler *s=item->node_->server();
+ if(!s)
+ return;
+
+ attach(s);
+
+ Q_EMIT beginAppendRow();
+
+ data_.push_back(new NodeQueryResultItem(item->node_));
+ blocks_[s].add(item->node_,data_.size()-1);
+
+ Q_EMIT endAppendRow();
+}
+
+void NodeQueryResult::add(QList<NodeQueryResultTmp_ptr> items)
+{
+ if(items.count() == 0)
+ return;
+
+ Q_EMIT beginAppendRows(items.count());
+
+ for(int i=0; i < items.count(); i++)
+ {
+ VNode *node=items.at(i)->node_;
+ ServerHandler *s=node->server();
+ attach(s);
+ data_.push_back(new NodeQueryResultItem(node));
+ blocks_[s].add(node,data_.size()-1);
+ }
+
+ Q_EMIT endAppendRows(items.count());
+}
+
+void NodeQueryResult::add(std::vector<VInfo_ptr> items)
+{
+ if(items.size() == 0)
+ return;
+
+ //Count the needed items
+ int num=0;
+ for(unsigned int i=0; i < items.size(); i++)
+ {
+ assert(items.at(i) && items.at(i).get());
+ if(items.at(i)->isServer() || items.at(i)->isNode())
+ {
+ num++;
+ }
+ }
+
+ Q_EMIT beginAppendRows(items.size());
+
+ for(unsigned int i=0; i < items.size(); i++)
+ {
+ if(items.at(i)->isServer() || items.at(i)->isNode())
+ {
+ VNode *node=items.at(i)->node();
+ ServerHandler *s=items.at(i)->server();
+ attach(s);
+ data_.push_back(new NodeQueryResultItem(node));
+ blocks_[s].add(node,data_.size()-1);
+ }
+ }
+
+ Q_EMIT endAppendRows(items.size());
+}
+void NodeQueryResult::clear()
+{
+ Q_EMIT beginReset();
+
+ for(std::map<ServerHandler*,NodeQueryResultBlock>::const_iterator it=blocks_.begin(); it != blocks_.end(); it++)
+ {
+ it->first->removeServerObserver(this);
+ it->first->removeNodeObserver(this);
+ }
+ blocks_.clear();
+
+ for(std::vector<NodeQueryResultItem*>::const_iterator it=data_.begin(); it != data_.end(); it++)
+ {
+ delete *it;
+ }
+
+ data_.clear();
+
+ Q_EMIT endReset();
+}
+
+void NodeQueryResult::clear(ServerHandler* server)
+{
+ std::vector<NodeQueryResultItem*> prev=data_;
+ data_.clear();
+
+ //Adjust the servers
+ detach(server);
+
+ for(std::map<ServerHandler*,NodeQueryResultBlock>::iterator it=blocks_.begin(); it != blocks_.end(); it++)
+ {
+ it->second.clear();
+ }
+
+ //Adjust data
+ for(std::vector<NodeQueryResultItem*>::const_iterator it=prev.begin(); it != prev.end(); ++it)
+ {
+ ServerHandler *s=(*it)->node_->server();
+ if(s == server)
+ {
+ delete *it;
+ }
+ else
+ {
+ data_.push_back(*it);
+ blocks_[s].add((*it)->node_,data_.size()-1);
+ }
+ }
+}
+
+void NodeQueryResult::serverClear(ServerHandler* server)
+{
+ for(std::vector<NodeQueryResultItem*>::const_iterator it=data_.begin(); it != data_.end(); ++it)
+ {
+ if(server == (*it)->server_)
+ {
+ (*it)->invalidateNode();
+ }
+ }
+}
+
+void NodeQueryResult::serverScan(ServerHandler* server)
+{
+ std::vector<NodeQueryResultItem*> prev=data_;
+ data_.clear();
+
+ for(std::map<ServerHandler*,NodeQueryResultBlock>::iterator it=blocks_.begin(); it != blocks_.end(); it++)
+ {
+ it->second.clear();
+ }
+
+ for(std::vector<NodeQueryResultItem*>::const_iterator it=prev.begin(); it != prev.end(); ++it)
+ {
+ if(server == (*it)->server_)
+ {
+ if((*it)->updateNode())
+ {
+ data_.push_back(*it);
+ blocks_[server].add((*it)->node_,data_.size()-1);
+ }
+ else
+ delete *it;
+ }
+ else
+ {
+ data_.push_back(*it);
+ blocks_[server].add((*it)->node_,data_.size()-1);
+ }
+ }
+
+ if(blocks_[server].cnt_ == 0)
+ detach(server);
+}
+
+
+void NodeQueryResult::attach(ServerHandler *s)
+{
+ if(blocks_.find(s) == blocks_.end())
+ {
+ s->addServerObserver(this);
+ s->addNodeObserver(this);
+ }
+}
+
+void NodeQueryResult::detach(ServerHandler* s)
+{
+ std::map<ServerHandler*,NodeQueryResultBlock>::iterator it=blocks_.find(s);
+ if(it != blocks_.end())
+ {
+ blocks_.erase(it);
+
+ s->removeServerObserver(this);
+ s->removeNodeObserver(this);
+ }
+}
+
+/*void NodeQueryResult::detach(VNode *node)
+{
+ std::map<ServerHandler*,int>::iterator it=serverCnt_.find(node->server());
+ if(it != serverCnt_.end())
+ {
+ it->second--;
+ if(it->second == 0)
+ {
+ detach(node->server());
+ }
+ }
+}*/
+
+void NodeQueryResult::notifyServerDelete(ServerHandler* server)
+{
+ Q_EMIT beginReset();
+ clear(server);
+ Q_EMIT endReset();
+}
+
+void NodeQueryResult::notifyBeginServerClear(ServerHandler* server)
+{
+ serverClear(server);
+}
+
+void NodeQueryResult::notifyEndServerClear(ServerHandler* server)
+{
+}
+
+void NodeQueryResult::notifyBeginServerScan(ServerHandler* server,const VServerChange&)
+{
+ Q_EMIT beginReset();
+}
+
+void NodeQueryResult::notifyEndServerScan(ServerHandler* server)
+{
+ serverScan(server);
+ Q_EMIT endReset();
+}
+
+
+void NodeQueryResult::notifyBeginNodeChange(const VNode* node, const std::vector<ecf::Aspect::Type>& aspect,const VNodeChange& vn)
+{
+ bool changed=false;
+ for(std::vector<ecf::Aspect::Type>::const_iterator it=aspect.begin(); it != aspect.end(); ++it)
+ {
+ //Changes in the nodes
+ if(*it == ecf::Aspect::STATE || *it == ecf::Aspect::SUSPENDED)
+ {
+ changed=true;
+ break;
+ }
+ }
+
+ if(changed)
+ {
+ int pos=-1;
+ int cnt=0;
+ if(range(node,pos,cnt))
+ Q_EMIT stateChanged(node,pos,cnt);
+ }
+}
+
+void NodeQueryResult::notifyEndNodeChange(const VNode*, const std::vector<ecf::Aspect::Type>&,const VNodeChange&)
+{
+
+}
+
+//-----------------------------------------------
+// Mapping
+//-----------------------------------------------
+
+bool NodeQueryResult::range(const VNode* node,int &pos,int &cnt)
+{
+ ServerHandler *server=node->server();
+ std::map<ServerHandler*,NodeQueryResultBlock>::iterator it=blocks_.find(server);
+ if(it != blocks_.end())
+ {
+ if(it->second.find(node,pos,cnt))
+ return true;
+ }
+ return false;
+}
+
diff --git a/Viewer/src/NodeQueryResult.hpp b/Viewer/src/NodeQueryResult.hpp
new file mode 100644
index 0000000..e3fd540
--- /dev/null
+++ b/Viewer/src/NodeQueryResult.hpp
@@ -0,0 +1,133 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VIEWER_SRC_NODEQUERYRESULT_HPP_
+#define VIEWER_SRC_NODEQUERYRESULT_HPP_
+
+#include <QColor>
+#include <QHash>
+#include <QObject>
+#include <QString>
+
+#include "NodeObserver.hpp"
+#include "NodeQueryResultTmp.hpp"
+#include "ServerObserver.hpp"
+#include "VInfo.hpp"
+
+class ServerHandler;
+class VNode;
+
+class NodeQueryResultItem
+{
+ friend class NodeQueryEngine;
+ friend class NodeQueryResult;
+ friend class NodeQueryResultModel;
+
+public:
+ NodeQueryResultItem() : node_(NULL), server_(NULL) {}
+ NodeQueryResultItem(VNode* node);
+ NodeQueryResultItem(NodeQueryResultTmp_ptr);
+
+ void invalidateNode();
+ bool updateNode();
+
+ QString serverStr() const;
+ QString pathStr() const;
+ QString typeStr() const;
+ QString stateStr() const;
+ QColor stateColour() const;
+
+protected:
+ VNode* node_;
+ ServerHandler* server_;
+ QStringList attr_;
+ std::string path_;
+};
+
+struct Pos
+{
+ Pos() : pos_(-1), cnt_(0) {}
+ int pos_;
+ int cnt_;
+};
+
+struct NodeQueryResultBlock : public Pos
+{
+ NodeQueryResultBlock() : server_(0) {}
+ void add(VNode*,int);
+ void clear();
+ bool find(const VNode* node,int &pos, int &cnt);
+
+ ServerHandler* server_;
+ QHash<VNode*,Pos> nodes_;
+};
+
+
+class NodeQueryResult : public QObject, public ServerObserver, public NodeObserver
+{
+ Q_OBJECT
+
+public:
+ explicit NodeQueryResult(QObject* parent=0);
+ ~NodeQueryResult();
+
+ int size() const {return data_.size();}
+ NodeQueryResultItem* itemAt(int i);
+ void clear();
+
+ //From ServerObserver
+ void notifyDefsChanged(ServerHandler* server, const std::vector<ecf::Aspect::Type>& a) {};
+ void notifyServerDelete(ServerHandler* server);
+ void notifyBeginServerClear(ServerHandler* server);
+ void notifyEndServerClear(ServerHandler* server);
+ void notifyBeginServerScan(ServerHandler* server,const VServerChange&);
+ void notifyEndServerScan(ServerHandler* server);
+
+ //From NodeObserver
+ void notifyBeginNodeChange(const VNode*, const std::vector<ecf::Aspect::Type>&,const VNodeChange&);
+ void notifyEndNodeChange(const VNode*, const std::vector<ecf::Aspect::Type>&,const VNodeChange&);
+ void add(std::vector<VInfo_ptr>);
+
+
+public Q_SLOTS:
+ void add(NodeQueryResultTmp_ptr);
+ void add(QList<NodeQueryResultTmp_ptr> items);
+
+Q_SIGNALS:
+ void beginAppendRow();
+ void endAppendRow();
+ void beginAppendRows(int);
+ void endAppendRows(int);
+ void beginRemoveRow(int);
+ void endRemoveRow(int);
+ void beginRemoveRows(int,int);
+ void endRemoveRows(int,int);
+ void beginReset();
+ void endReset();
+ void stateChanged(const VNode*,int,int);
+
+protected:
+ void clearData(bool hideOnly);
+ void clear(ServerHandler*);
+ void serverClear(ServerHandler*);
+ void serverScan(ServerHandler*);
+ void attach(ServerHandler*);
+ void detach(ServerHandler*);
+ bool range(const VNode*,int&,int&);
+ //void detach(VNode*);
+
+ std::vector<NodeQueryResultItem*> data_;
+ //std::map<ServerHandler*,int> serverCnt_;
+ std::map<ServerHandler*,NodeQueryResultBlock> blocks_;
+};
+
+
+
+#endif /* VIEWER_SRC_NODEQUERYRESULT_HPP_ */
diff --git a/Viewer/src/NodeQueryResultModel.cpp b/Viewer/src/NodeQueryResultModel.cpp
new file mode 100644
index 0000000..d3dfae4
--- /dev/null
+++ b/Viewer/src/NodeQueryResultModel.cpp
@@ -0,0 +1,318 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "NodeQueryResultModel.hpp"
+
+#include "ModelColumn.hpp"
+#include "NodeQueryResult.hpp"
+#include "ServerHandler.hpp"
+#include "VNode.hpp"
+
+#include <QDebug>
+
+NodeQueryResultModel::NodeQueryResultModel(QObject *parent) :
+ QAbstractItemModel(parent),
+ columns_(0)
+{
+ columns_=ModelColumn::def("query_columns");
+
+ assert(columns_);
+
+ data_=new NodeQueryResult(this);
+
+ connect(data_,SIGNAL(beginAppendRow()),
+ this,SLOT(slotBeginAppendRow()));
+
+ connect(data_,SIGNAL(endAppendRow()),
+ this,SLOT(slotEndAppendRow()));
+
+ connect(data_,SIGNAL(beginAppendRows(int)),
+ this,SLOT(slotBeginAppendRows(int)));
+
+ connect(data_,SIGNAL(endAppendRows(int)),
+ this,SLOT(slotEndAppendRows(int)));
+
+ connect(data_,SIGNAL(beginRemoveRow(int)),
+ this,SLOT(slotBeginRemoveRow(int)));
+
+ connect(data_,SIGNAL(endRemoveRow(int)),
+ this,SLOT(slotEndRemoveRow(int)));
+
+ connect(data_,SIGNAL(beginRemoveRows(int,int)),
+ this,SLOT(slotBeginRemoveRows(int,int)));
+
+ connect(data_,SIGNAL(endRemoveRows(int,int)),
+ this,SLOT(slotEndRemoveRows(int,int)));
+
+ connect(data_,SIGNAL(beginReset()),
+ this,SLOT(slotBeginReset()));
+
+ connect(data_,SIGNAL(endReset()),
+ this,SLOT(slotEndReset()));
+
+ connect(data_,SIGNAL(stateChanged(const VNode*,int,int)),
+ this,SLOT(slotStateChanged(const VNode*,int,int)));
+
+}
+
+NodeQueryResultModel::~NodeQueryResultModel()
+{
+}
+
+
+void NodeQueryResultModel::clearData()
+{
+ data_->clear();
+}
+
+bool NodeQueryResultModel::hasData() const
+{
+ return data_->size() > 0;
+}
+
+int NodeQueryResultModel::columnCount( const QModelIndex& /*parent */) const
+{
+ return columns_->count();
+}
+
+int NodeQueryResultModel::rowCount( const QModelIndex& parent) const
+{
+ if(!hasData())
+ return 0;
+
+ //Parent is the root:
+ if(!parent.isValid())
+ {
+ return data_->size();
+ }
+
+ return 0;
+}
+
+Qt::ItemFlags NodeQueryResultModel::flags ( const QModelIndex & index) const
+{
+ return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
+}
+
+QVariant NodeQueryResultModel::data( const QModelIndex& index, int role ) const
+{
+ if(!index.isValid() || !hasData() ||
+ (role != Qt::DisplayRole && role != Qt::BackgroundRole && role != Qt::TextAlignmentRole))
+ {
+ return QVariant();
+ }
+
+ int row=index.row();
+ if(row < 0 || row >= data_->size())
+ return QVariant();
+
+ QString id=columns_->id(index.column());
+
+ NodeQueryResultItem* d=data_->itemAt(row);
+
+ if(role == Qt::DisplayRole)
+ {
+ if(id == "path")
+ return d->pathStr();
+ else if(id == "server")
+ return d->serverStr();
+ else if(id == "type")
+ return d->typeStr();
+ else if(id == "status")
+ return d->stateStr();
+ return QVariant();
+ }
+ else if(role == Qt::BackgroundRole)
+ {
+ if(id == "status")
+ return d->stateColour();
+
+ return QVariant();
+ }
+ else if(role == Qt::TextAlignmentRole)
+ {
+ if(id == "status" || id == "type")
+ return Qt::AlignCenter;
+
+ return QVariant();
+ }
+
+ return QVariant();
+}
+
+QVariant NodeQueryResultModel::headerData( const int section, const Qt::Orientation orient , const int role ) const
+{
+ if ( orient != Qt::Horizontal)
+ return QAbstractItemModel::headerData( section, orient, role );
+
+ QString id=columns_->id(section);
+
+ if(role == Qt::DisplayRole)
+ return columns_->label(section);
+ else if(role == Qt::UserRole)
+ return columns_->id(section);
+ else if(role == Qt::ToolTipRole)
+ return columns_->tooltip(section);
+ else if(role == Qt::TextAlignmentRole)
+ {
+ if(id == "status" || id == "type")
+ return Qt::AlignCenter;
+ }
+
+ return QVariant();
+}
+
+QModelIndex NodeQueryResultModel::index( int row, int column, const QModelIndex & parent ) const
+{
+ if(!hasData() || row < 0 || column < 0)
+ {
+ return QModelIndex();
+ }
+
+ //When parent is the root this index refers to a node or server
+ if(!parent.isValid())
+ {
+ return createIndex(row,column);
+ }
+
+ return QModelIndex();
+
+}
+
+QModelIndex NodeQueryResultModel::parent(const QModelIndex &child) const
+{
+ return QModelIndex();
+}
+
+VInfo_ptr NodeQueryResultModel::nodeInfo(const QModelIndex& index)
+{
+ //For invalid index no info is created.
+ if(!index.isValid())
+ {
+ VInfo_ptr res;
+ return res;
+ }
+
+ if(index.row() >=0 && index.row() <= data_->size())
+ {
+ NodeQueryResultItem* d=data_->itemAt(index.row());
+
+ if(ServerHandler *s=d->server_)
+ {
+ if(d->node_)
+ {
+ if(d->node_->isServer())
+ {
+ return VInfoServer::create(s);
+ }
+ else
+ {
+ return VInfoNode::create(d->node_);
+ }
+ }
+ }
+ }
+
+ VInfo_ptr res;
+ return res;
+}
+
+QModelIndex NodeQueryResultModel::infoToIndex(VInfo_ptr info)
+{
+ /*if(info && info.get())
+ {
+ if(info->isServer())
+ {
+ if(ServerHandler *s=info->server())
+ {
+ return serverToIndex(s);
+ }
+ }
+ else if(VNode* n=info->node())
+ {
+ return nodeToIndex(n);
+ }
+ }*/
+
+ return QModelIndex();
+}
+
+void NodeQueryResultModel::slotBeginAppendRow()
+{
+ int num=data_->size();
+ Q_EMIT beginInsertRows(QModelIndex(),num,num);
+
+
+ Q_EMIT endInsertRows();
+}
+
+void NodeQueryResultModel::slotEndAppendRow()
+{
+ Q_EMIT endInsertRows();
+}
+
+void NodeQueryResultModel::slotBeginAppendRows(int n)
+{
+ if(n <= 0)
+ return;
+
+ int num=data_->size();
+ Q_EMIT beginInsertRows(QModelIndex(),num,num+n-1);
+}
+
+void NodeQueryResultModel::slotEndAppendRows(int n)
+{
+ if(n <= 0)
+ return;
+ Q_EMIT endInsertRows();
+}
+
+void NodeQueryResultModel::slotBeginRemoveRow(int row)
+{
+ beginRemoveRows(QModelIndex(),row,row);
+}
+
+void NodeQueryResultModel::slotEndRemoveRow(int row)
+{
+ endRemoveRows();
+}
+
+void NodeQueryResultModel::slotBeginRemoveRows(int rowStart,int rowEnd)
+{
+ beginRemoveRows(QModelIndex(),rowStart,rowEnd);
+}
+
+void NodeQueryResultModel::slotEndRemoveRows(int,int)
+{
+ endRemoveRows();
+}
+
+void NodeQueryResultModel::slotBeginReset()
+{
+ beginResetModel();
+}
+
+void NodeQueryResultModel::slotEndReset()
+{
+ endResetModel();
+}
+
+void NodeQueryResultModel::slotStateChanged(const VNode*,int pos,int cnt)
+{
+ int col=columns_->indexOf("status");
+
+ if(col != -1)
+ {
+ QModelIndex fromIdx=index(pos,col);
+ QModelIndex toIdx=index(pos+cnt-1,col);
+
+ Q_EMIT dataChanged(fromIdx,toIdx);
+ }
+}
diff --git a/Viewer/src/NodeQueryResultModel.hpp b/Viewer/src/NodeQueryResultModel.hpp
new file mode 100644
index 0000000..9e14157
--- /dev/null
+++ b/Viewer/src/NodeQueryResultModel.hpp
@@ -0,0 +1,68 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VIEWER_SRC_NODEQUERYRESULTMODEL_HPP_
+#define VIEWER_SRC_NODEQUERYRESULTMODEL_HPP_
+
+#include <QAbstractItemModel>
+#include <QColor>
+//#include <QSortFilterProxyModel>
+
+#include "VInfo.hpp"
+
+class ModelColumn;
+class NodeQueryResult;
+
+class NodeQueryResultModel : public QAbstractItemModel
+{
+Q_OBJECT
+
+public:
+ explicit NodeQueryResultModel(QObject *parent=0);
+ ~NodeQueryResultModel();
+
+ int columnCount (const QModelIndex& parent = QModelIndex() ) const;
+ int rowCount (const QModelIndex& parent = QModelIndex() ) const;
+
+ Qt::ItemFlags flags ( const QModelIndex & index) const;
+ QVariant data (const QModelIndex& , int role = Qt::DisplayRole ) const;
+ QVariant headerData(int,Qt::Orientation,int role = Qt::DisplayRole ) const;
+
+ QModelIndex index (int, int, const QModelIndex& parent = QModelIndex() ) const;
+ QModelIndex parent (const QModelIndex & ) const;
+
+ NodeQueryResult *data() const {return data_;}
+ void clearData();
+ bool hasData() const;
+ //void addDataStart();
+ //void addDataEnd();
+
+ VInfo_ptr nodeInfo(const QModelIndex&);
+ QModelIndex infoToIndex(VInfo_ptr);
+
+public Q_SLOTS:
+ void slotBeginAppendRow();
+ void slotEndAppendRow();
+ void slotBeginAppendRows(int);
+ void slotEndAppendRows(int);
+ void slotBeginRemoveRow(int);
+ void slotEndRemoveRow(int);
+ void slotBeginRemoveRows(int,int);
+ void slotEndRemoveRows(int,int);
+ void slotBeginReset();
+ void slotEndReset();
+ void slotStateChanged(const VNode*,int,int);
+
+protected:
+ NodeQueryResult *data_;
+ ModelColumn* columns_;
+};
+
+#endif /* VIEWER_SRC_NODEQUERYRESULTMODEL_HPP_ */
diff --git a/Viewer/src/NodeQueryResultTmp.hpp b/Viewer/src/NodeQueryResultTmp.hpp
new file mode 100644
index 0000000..6bb2e00
--- /dev/null
+++ b/Viewer/src/NodeQueryResultTmp.hpp
@@ -0,0 +1,31 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+#ifndef VIEWER_SRC_NODEQUERYRESULTTMP_HPP_
+#define VIEWER_SRC_NODEQUERYRESULTTMP_HPP_
+
+#include <QString>
+#include <QStringList>
+#include <boost/shared_ptr.hpp>
+
+class VNode;
+
+class NodeQueryResultTmp;
+typedef boost::shared_ptr<NodeQueryResultTmp> NodeQueryResultTmp_ptr;
+
+struct NodeQueryResultTmp
+{
+ NodeQueryResultTmp() : node_(NULL) {}
+ NodeQueryResultTmp(VNode *node) : node_(node) {}
+
+ VNode* node_;
+ QStringList attr_;
+};
+
+#endif /* VIEWER_SRC_NODEQUERYRESULTTMP_HPP_ */
diff --git a/Viewer/src/NodeQueryResultView.cpp b/Viewer/src/NodeQueryResultView.cpp
new file mode 100644
index 0000000..9380ce5
--- /dev/null
+++ b/Viewer/src/NodeQueryResultView.cpp
@@ -0,0 +1,276 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "NodeQueryResultView.hpp"
+
+#include <QApplication>
+#include <QDebug>
+#include <QHeaderView>
+#include <QPalette>
+#include <QScrollBar>
+#include <QSortFilterProxyModel>
+
+#include "ActionHandler.hpp"
+#include "NodeQueryResultModel.hpp"
+#include "NodeQueryViewDelegate.hpp"
+#include "UserMessage.hpp"
+#include "VNode.hpp"
+
+NodeQueryResultView::NodeQueryResultView(QWidget* parent) :
+ QTreeView(parent),
+ model_(NULL),
+ sortModel_(NULL),
+ needItemsLayout_(false)
+
+{
+ //setProperty("style","nodeView");
+ setProperty("view","query");
+
+ actionHandler_=new ActionHandler(this);
+
+ sortModel_=new QSortFilterProxyModel(this);
+ //sortModel_->setDynamicSortFilter(true);
+ setModel(sortModel_);
+
+ //Create delegate to the view
+ delegate_=new NodeQueryViewDelegate(this);
+ setItemDelegate(delegate_);
+
+ connect(delegate_,SIGNAL(sizeHintChangedGlobal()),
+ this,SLOT(slotSizeHintChangedGlobal()));
+
+ //setRootIsDecorated(false);
+ setAllColumnsShowFocus(true);
+ setUniformRowHeights(true);
+ setMouseTracking(true);
+ setRootIsDecorated(false);
+ setSortingEnabled(true);
+ setSelectionMode(QAbstractItemView::ExtendedSelection);
+
+ //!!!!We need to do it because:
+ //The background colour between the view's left border and the nodes cannot be
+ //controlled by delegates or stylesheets. It always takes the QPalette::Highlight
+ //colour from the palette. Here we set this to transparent so that Qt could leave
+ //this area empty and we will fill it appropriately in our delegate.
+ QPalette pal=palette();
+ pal.setColor(QPalette::Highlight,QColor(128,128,128,0));//Qt::transparent);
+ setPalette(pal);
+
+ //Context menu
+ enableContextMenu(true);
+
+ //Selection
+ connect(this,SIGNAL(clicked(const QModelIndex&)),
+ this,SLOT(slotSelectItem(const QModelIndex&)));
+
+ connect(this,SIGNAL(doubleClicked(const QModelIndex&)),
+ this,SLOT(slotDoubleClickItem(const QModelIndex&)));
+
+}
+
+NodeQueryResultView::~NodeQueryResultView()
+{
+ delete actionHandler_;
+}
+
+
+void NodeQueryResultView::enableContextMenu(bool enable)
+{
+ if (enable)
+ {
+ setContextMenuPolicy(Qt::CustomContextMenu);
+
+ connect(this, SIGNAL(customContextMenuRequested(const QPoint &)),
+ this, SLOT(slotContextMenu(const QPoint &)));
+ }
+ else
+ {
+ setContextMenuPolicy(Qt::NoContextMenu);
+
+ disconnect(this, SIGNAL(customContextMenuRequested(const QPoint &)),
+ this, SLOT(slotContextMenu(const QPoint &)));
+ }
+}
+
+
+void NodeQueryResultView::setSourceModel(NodeQueryResultModel *model)
+{
+ model_= model;
+ sortModel_->setSourceModel(model_);
+}
+
+
+
+//Collects the selected list of indexes
+QModelIndexList NodeQueryResultView::selectedList()
+{
+ QModelIndexList lst;
+ Q_FOREACH(QModelIndex idx,selectedIndexes())
+ {
+ if(idx.column() == 0)
+ lst << idx;
+ }
+ return lst;
+}
+
+// this is called even if the user clicks outside of the node list to deselect all
+void NodeQueryResultView::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
+{
+ QTreeView::selectionChanged(selected, deselected);
+ Q_EMIT selectionChanged();
+}
+
+void NodeQueryResultView::slotSelectItem(const QModelIndex&)
+{
+ QModelIndexList lst=selectedIndexes();
+ if(lst.count() > 0)
+ {
+ VInfo_ptr info=model_->nodeInfo(sortModel_->mapToSource(lst.front()));
+ if(info)
+ {
+ Q_EMIT selectionChanged(info);
+ }
+ }
+}
+
+VInfo_ptr NodeQueryResultView::currentSelection()
+{
+ QModelIndexList lst=selectedIndexes();
+ if(lst.count() > 0)
+ {
+ return model_->nodeInfo(sortModel_->mapToSource(lst.front()));
+ }
+ return VInfo_ptr();
+}
+
+void NodeQueryResultView::currentSelection(VInfo_ptr info)
+{
+ /*QModelIndex idx=model_->infoToIndex(info);
+ if(idx.isValid())
+ {
+ setCurrentIndex(idx);
+ Q_EMIT selectionChanged(info);
+ }*/
+}
+
+void NodeQueryResultView::slotSetCurrent(VInfo_ptr info)
+{
+ /*QModelIndex idx=model_->infoToIndex(info);
+ if(idx.isValid())
+ {
+ setCurrentIndex(idx);
+ Q_EMIT selectionChanged(info);
+ }*/
+}
+
+void NodeQueryResultView::selectFirstServer()
+{
+ QModelIndex idx=sortModel_->index(0,0);
+ if(idx.isValid())
+ {
+ setCurrentIndex(idx);
+ VInfo_ptr info=model_->nodeInfo(sortModel_->mapToSource(idx));
+ Q_EMIT selectionChanged(info);
+ }
+}
+
+
+void NodeQueryResultView::getListOfSelectedNodes(std::vector<VInfo_ptr> &nodeList)
+{
+ QModelIndexList indexList=selectedList();
+
+ nodeList.clear();
+ for(int i=0; i < indexList.count(); i++)
+ {
+ VInfo_ptr info=model_->nodeInfo(sortModel_->mapToSource(indexList[i]));
+ if(info && !info->isEmpty())
+ nodeList.push_back(info);
+ }
+}
+
+
+void NodeQueryResultView::slotDoubleClickItem(const QModelIndex&)
+{
+}
+
+void NodeQueryResultView::slotContextMenu(const QPoint &position)
+{
+ QModelIndexList lst=selectedList();
+ //QModelIndex index=indexAt(position);
+ QPoint scrollOffset(horizontalScrollBar()->value(),verticalScrollBar()->value());
+
+ handleContextMenu(indexAt(position),lst,mapToGlobal(position),position+scrollOffset,this);
+}
+
+
+void NodeQueryResultView::handleContextMenu(QModelIndex indexClicked,QModelIndexList indexLst,QPoint globalPos,QPoint widgetPos,QWidget *widget)
+{
+ //Node actions
+ if(indexClicked.isValid()) //indexLst[0].isValid() && indexLst[0].column() == 0)
+ {
+ std::vector<VInfo_ptr> nodeLst;
+ for(int i=0; i < indexLst.count(); i++)
+ {
+ VInfo_ptr info=model_->nodeInfo(sortModel_->mapToSource(indexLst[i]));
+ if(info && !info->isEmpty())
+ nodeLst.push_back(info);
+ }
+
+ actionHandler_->contextMenu(nodeLst,globalPos);
+ }
+
+ //Desktop actions
+ else
+ {
+ }
+}
+
+void NodeQueryResultView::slotViewCommand(std::vector<VInfo_ptr> nodeLst,QString cmd)
+{
+
+ if(nodeLst.size() == 0)
+ return;
+
+ /*if(cmd == "set_as_root")
+ {
+ model_->setRootNode(nodeLst.at(0)->node());
+ expandAll();
+ }*/
+}
+
+void NodeQueryResultView::reload()
+{
+ //model_->reload();
+ //expandAll();
+}
+
+void NodeQueryResultView::rerender()
+{
+ if(needItemsLayout_)
+ {
+ doItemsLayout();
+ needItemsLayout_=false;
+ }
+ else
+ {
+ viewport()->update();
+ }
+}
+
+void NodeQueryResultView::slotRerender()
+{
+ rerender();
+}
+
+
+void NodeQueryResultView::slotSizeHintChangedGlobal()
+{
+ needItemsLayout_=true;
+}
diff --git a/Viewer/src/NodeQueryResultView.hpp b/Viewer/src/NodeQueryResultView.hpp
new file mode 100644
index 0000000..85c7bd9
--- /dev/null
+++ b/Viewer/src/NodeQueryResultView.hpp
@@ -0,0 +1,70 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VIEWER_SRC_NODEQUERYRESULTVIEW_HPP_
+#define VIEWER_SRC_NODEQUERYRESULTVIEW_HPP_
+
+#include <QTreeView>
+
+#include "VInfo.hpp"
+
+class ActionHandler;
+class NodeQueryResultModel;
+class NodeQueryViewDelegate;
+
+class QSortFilterProxyModel;
+
+class NodeQueryResultView : public QTreeView
+{
+Q_OBJECT
+
+public:
+ explicit NodeQueryResultView(QWidget *parent=0);
+ ~NodeQueryResultView();
+
+ void reload();
+ void rerender();
+ VInfo_ptr currentSelection();
+ void currentSelection(VInfo_ptr n);
+ void selectFirstServer();
+ void setSourceModel(NodeQueryResultModel* model);
+ void enableContextMenu(bool enable);
+ void getListOfSelectedNodes(std::vector<VInfo_ptr> &nodeList);
+
+ //void readSettings(VSettings* vs) {};
+
+public Q_SLOTS:
+ void slotSelectItem(const QModelIndex&);
+ void slotDoubleClickItem(const QModelIndex&);
+ void slotContextMenu(const QPoint &position);
+ void slotViewCommand(std::vector<VInfo_ptr>,QString);
+ void slotSetCurrent(VInfo_ptr);
+ void slotRerender();
+ void slotSizeHintChangedGlobal();
+ void selectionChanged (const QItemSelection &selected, const QItemSelection &deselected);
+
+Q_SIGNALS:
+ void selectionChanged(VInfo_ptr);
+ void selectionChanged();
+ void infoPanelCommand(VInfo_ptr,QString);
+
+protected:
+ QModelIndexList selectedList();
+ void handleContextMenu(QModelIndex indexClicked,QModelIndexList indexLst,QPoint globalPos,QPoint widgetPos,QWidget *widget);
+
+ NodeQueryResultModel* model_;
+ QSortFilterProxyModel* sortModel_;
+ ActionHandler* actionHandler_;
+ bool needItemsLayout_;
+ NodeQueryViewDelegate* delegate_;
+};
+
+
+#endif /* VIEWER_SRC_NODEQUERYRESULTVIEW_HPP_ */
diff --git a/Viewer/src/NodeQuerySaveDialog.ui b/Viewer/src/NodeQuerySaveDialog.ui
new file mode 100644
index 0000000..c31b7b8
--- /dev/null
+++ b/Viewer/src/NodeQuerySaveDialog.ui
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>NodeQuerySaveDialog</class>
+ <widget class="QDialog" name="NodeQuerySaveDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>279</width>
+ <height>77</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Save query as</string>
+ </property>
+ <property name="modal">
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QFormLayout" name="formLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::ExpandingFieldsGrow</enum>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>&Query name:</string>
+ </property>
+ <property name="buddy">
+ <cstring>label</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="nameLe_"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>NodeQuerySaveDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>257</x>
+ <y>218</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>227</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>NodeQuerySaveDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>274</x>
+ <y>218</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>283</x>
+ <y>227</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/Viewer/src/NodeQueryViewDelegate.cpp b/Viewer/src/NodeQueryViewDelegate.cpp
new file mode 100644
index 0000000..9680419
--- /dev/null
+++ b/Viewer/src/NodeQueryViewDelegate.cpp
@@ -0,0 +1,262 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "NodeQueryViewDelegate.hpp"
+
+#include <QApplication>
+#include <QDebug>
+#include <QImageReader>
+#include <QPainter>
+
+#include <QStyleOptionViewItem>
+
+#include "AbstractNodeModel.hpp"
+#include "Animation.hpp"
+#include "IconProvider.hpp"
+#include "ModelColumn.hpp"
+#include "PropertyMapper.hpp"
+
+static std::vector<std::string> propVec;
+
+NodeQueryViewDelegate::NodeQueryViewDelegate(QWidget *parent)
+{
+ borderPen_=QPen(QColor(230,230,230));
+
+ columns_=ModelColumn::def("query_columns");
+
+ /*adjustIconSize();
+
+ //Property
+ if(propVec.empty())
+ {
+ propVec.push_back("view.tree.font");
+ propVec.push_back("view.tree.displayChildCount");
+ }
+
+ prop_=new PropertyMapper(propVec,this);
+
+ updateSettings();*/
+}
+
+NodeQueryViewDelegate::~NodeQueryViewDelegate()
+{
+}
+
+void NodeQueryViewDelegate::updateSettings()
+{
+
+}
+
+QSize NodeQueryViewDelegate::sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index ) const
+{
+ QSize size=QStyledItemDelegate::sizeHint(option,index);
+
+ QFontMetrics fm(font_);
+ int h=fm.height();
+ return QSize(size.width(),h+4);
+}
+
+void NodeQueryViewDelegate::paint(QPainter *painter,const QStyleOptionViewItem &option,
+ const QModelIndex& index) const
+{
+ //Background
+ QStyleOptionViewItemV4 vopt(option);
+ initStyleOption(&vopt, index);
+
+ const QStyle *style = vopt.widget ? vopt.widget->style() : QApplication::style();
+ const QWidget* widget = vopt.widget;
+
+ //Save painter state
+ painter->save();
+
+ //Selection - we only do it once
+ /*if(index.column() == 0)
+ {
+ QRect fullRect=QRect(0,option.rect.y(),painter->device()->width(),option.rect.height());
+
+ if(option.state & QStyle::State_Selected)
+ {
+ //QRect fillRect=option.rect.adjusted(0,1,-1,-textRect.height()-1);
+ painter->fillRect(fullRect,selectBrush_);
+ painter->setPen(selectPen_);
+ painter->drawLine(fullRect.topLeft(),fullRect.topRight());
+ painter->drawLine(fullRect.bottomLeft(),fullRect.bottomRight());
+ }
+ else if(option.state & QStyle::State_MouseOver)
+ {
+ //QRect fillRect=option.rect.adjusted(0,1,-1,-1);
+ painter->fillRect(fullRect,hoverBrush_);
+ painter->setPen(hoverPen_);
+ painter->drawLine(fullRect.topLeft(),fullRect.topRight());
+ painter->drawLine(fullRect.bottomLeft(),fullRect.bottomRight());
+ }
+ }*/
+
+ //Different background for lost connection?
+ /* if(index.data(AbstractNodeModel::ConnectionRole).toInt() == 0)
+ {
+ QRect fullRect=QRect(0,option.rect.y(),painter->device()->width(),option.rect.height());
+ painter->fillRect(fullRect,lostConnectBgBrush_);
+ QRect bandRect=QRect(0,option.rect.y(),5,option.rect.height());
+ painter->fillRect(bandRect,lostConnectBandBrush_);
+
+ }*/
+
+ QString id=columns_->id(index.column());
+
+ if(id == "path")
+ {
+ QString text=index.data(Qt::DisplayRole).toString();
+ renderNode(painter,index,vopt,text);
+ }
+ else if(id == "status")
+ {
+ renderStatus(painter,index,vopt);
+ }
+
+ //Render attributes
+ else if(id == "attribute")
+ {
+ QVariant va=index.data(Qt::DisplayRole);
+ if(va.type() == QVariant::StringList)
+ {
+ QStringList lst=va.toStringList();
+ if(lst.count() > 0)
+ {
+ QMap<QString,AttributeRendererProc>::const_iterator it=attrRenderers_.find(lst.at(0));
+ if(it != attrRenderers_.end())
+ {
+ AttributeRendererProc a=it.value();
+ (this->*a)(painter,lst,vopt);
+ }
+ }
+ }
+ }
+
+ //rest of the columns
+ else
+ {
+ QString text=index.data(Qt::DisplayRole).toString();
+ QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &vopt, widget);
+ painter->setPen(Qt::black);
+
+ int rightPos=textRect.right()+1;
+ const bool setClipRect = rightPos > option.rect.right();
+ if(setClipRect)
+ {
+ painter->save();
+ painter->setClipRect(option.rect);
+ }
+
+ /*QVariant alg=index.data(Qt::TextAlignmentRole);
+ if(alg.isValid())
+ painter->drawText(textRect,alg.value<Qt::Alignment>(),text);
+ else*/
+ painter->drawText(textRect,Qt::AlignLeft | Qt::AlignVCenter,text);
+
+ if(setClipRect)
+ {
+ painter->restore();
+ }
+
+ }
+
+ //Render the horizontal border for rows. We only render the top border line.
+ //With this technique we miss the bottom border line of the last row!!!
+ //QRect fullRect=QRect(0,option.rect.y(),painter->device()->width(),option.rect.height());
+ QRect bgRect=option.rect;
+ painter->setPen(borderPen_);
+ painter->drawLine(bgRect.topLeft(),bgRect.topRight());
+
+
+ painter->restore();
+}
+
+void NodeQueryViewDelegate::renderNode(QPainter *painter,const QModelIndex& index,
+ const QStyleOptionViewItemV4& option,QString text) const
+{
+ bool selected=option.state & QStyle::State_Selected;
+ int offset=4;
+
+ QFontMetrics fm(font_);
+ int deltaH=(option.rect.height()-(fm.height()+2))/2;
+
+ //The initial filled rect (we will adjust its width)
+ QRect fillRect=option.rect.adjusted(offset,deltaH,0,-deltaH-1);
+ if(selected)
+ fillRect.adjust(0,1,0,0);
+
+ //The text rectangle
+ QRect textRect = fillRect.adjusted(offset,0,0,0);
+
+ int textWidth=fm.width(text);
+ textRect.setWidth(textWidth);
+
+ //Adjust the filled rect width
+ fillRect.setRight(textRect.right()+offset);
+
+ int currentRight=fillRect.right();
+
+ //Icons area
+ QList<QPixmap> pixLst;
+ QList<QRect> pixRectLst;
+ QVariant va=index.data(AbstractNodeModel::IconRole);
+ if(va.type() == QVariant::List)
+ {
+ QVariantList lst=va.toList();
+ int xp=currentRight+5;
+ int yp=textRect.center().y()-iconSize_/2;
+ for(int i=0; i < lst.count(); i++)
+ {
+ int id=lst[i].toInt();
+ if(id != -1)
+ {
+ pixLst << IconProvider::pixmap(id,iconSize_);
+ pixRectLst << QRect(xp,yp,pixLst.back().width(),pixLst.back().height());
+ xp+=pixLst.back().width();
+ }
+ }
+
+ if(!pixRectLst.isEmpty())
+ currentRight=pixRectLst.back().right();
+ }
+
+ //Define clipping
+ int rightPos=currentRight+1;
+ const bool setClipRect = rightPos > option.rect.right();
+ if(setClipRect)
+ {
+ painter->save();
+ painter->setClipRect(option.rect);
+ }
+
+ //Draw text
+ QColor fg=index.data(Qt::ForegroundRole).value<QColor>();
+ painter->setPen(fg);
+ painter->drawText(textRect,Qt::AlignLeft | Qt::AlignVCenter,text);
+
+ if(selected)
+ {
+ painter->setPen(nodeSelectPen_);
+ QRect selRect=textRect.adjusted(-2,0,2,0);
+ painter->drawRect(selRect);
+ }
+
+ //Draw icons
+ for(int i=0; i < pixLst.count(); i++)
+ {
+ painter->drawPixmap(pixRectLst[i],pixLst[i]);
+ }
+
+ if(setClipRect)
+ {
+ painter->restore();
+ }
+}
diff --git a/Viewer/src/NodeQueryViewDelegate.hpp b/Viewer/src/NodeQueryViewDelegate.hpp
new file mode 100644
index 0000000..380300e
--- /dev/null
+++ b/Viewer/src/NodeQueryViewDelegate.hpp
@@ -0,0 +1,48 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VIEWER_SRC_NODEQUERYVIEWDELEGATE_HPP_
+#define VIEWER_SRC_NODEQUERYVIEWDELEGATE_HPP_
+
+#include <QBrush>
+#include <QMap>
+#include <QPen>
+#include <QStyledItemDelegate>
+#include <QStyleOptionViewItem>
+
+#include "NodeViewDelegate.hpp"
+#include "VProperty.hpp"
+
+#include <string>
+
+class ModelColumn;
+
+class NodeQueryViewDelegate : public NodeViewDelegate
+{
+public:
+ explicit NodeQueryViewDelegate(QWidget *parent=0);
+ ~NodeQueryViewDelegate();
+
+ QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index ) const;
+ void paint(QPainter *painter,const QStyleOptionViewItem &option,
+ const QModelIndex& index) const;
+
+protected:
+ void updateSettings();
+
+ void renderNode(QPainter *painter,const QModelIndex& index,
+ const QStyleOptionViewItemV4& option,QString text) const;
+
+ ModelColumn* columns_;
+ QPen borderPen_;
+
+};
+
+#endif /* VIEWER_SRC_NODEQUERYVIEWDELEGATE_HPP_ */
diff --git a/Viewer/src/NodeSearchDialog.cpp b/Viewer/src/NodeSearchDialog.cpp
new file mode 100644
index 0000000..308eabb
--- /dev/null
+++ b/Viewer/src/NodeSearchDialog.cpp
@@ -0,0 +1,114 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include <QCloseEvent>
+#include <QDebug>
+#include <QSettings>
+
+#include "NodeSearchDialog.hpp"
+#include "SessionHandler.hpp"
+#include "VConfig.hpp"
+
+NodeSearchDialog::NodeSearchDialog(QWidget *parent) :
+ QDialog(parent)
+{
+ setupUi(this);
+
+ setAttribute(Qt::WA_DeleteOnClose);
+
+ QString wt=windowTitle();
+ wt+=" - " + QString::fromStdString(VConfig::instance()->appLongName());
+ setWindowTitle(wt);
+
+ connect(queryWidget_,SIGNAL(closeClicked()),
+ this,SLOT(accept()));
+
+ //Read the qt settings
+ readSettings();
+}
+
+NodeSearchDialog::~NodeSearchDialog()
+{
+}
+
+NodeSearchWidget* NodeSearchDialog::queryWidget() const
+{
+ return queryWidget_;
+}
+
+void NodeSearchDialog::closeEvent(QCloseEvent * event)
+{
+ queryWidget_->slotStop(); //The search thread might be running!!
+ event->accept();
+ writeSettings();
+}
+
+void NodeSearchDialog::accept()
+{
+ writeSettings();
+ QDialog::accept();
+}
+
+void NodeSearchDialog::reject()
+{
+ writeSettings();
+ QDialog::reject();
+}
+
+void NodeSearchDialog::slotOwnerDelete()
+{
+ deleteLater();
+}
+
+//------------------------------------------
+// Settings read/write
+//------------------------------------------
+
+void NodeSearchDialog::writeSettings()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ Q_ASSERT(cs);
+ QSettings settings(QString::fromStdString(cs->qtSettingsFile("NodeSearchDialog")),
+ QSettings::NativeFormat);
+
+ //We have to clear it so that should not remember all the previous values
+ settings.clear();
+
+ settings.beginGroup("main");
+ settings.setValue("size",size());
+ //settings.setValue("current",list_->currentRow());
+ settings.endGroup();
+}
+
+void NodeSearchDialog::readSettings()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ Q_ASSERT(cs);
+ QSettings settings(QString::fromStdString(cs->qtSettingsFile("NodeSearchDialog")),
+ QSettings::NativeFormat);
+
+ settings.beginGroup("main");
+ if(settings.contains("size"))
+ {
+ resize(settings.value("size").toSize());
+ }
+ else
+ {
+ resize(QSize(550,540));
+ }
+
+ /*if(settings.contains("current"))
+ {
+ int current=settings.value("current").toInt();
+ if(current >=0)
+ list_->setCurrentRow(current);
+ }*/
+ settings.endGroup();
+}
diff --git a/Viewer/src/NodeSearchDialog.hpp b/Viewer/src/NodeSearchDialog.hpp
new file mode 100644
index 0000000..445892e
--- /dev/null
+++ b/Viewer/src/NodeSearchDialog.hpp
@@ -0,0 +1,46 @@
+//============================================================================
+// Copyright 2015 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef NODESEARCHDIALOG_HPP_
+#define NODESEARCHDIALOG_HPP_
+
+#include <QDialog>
+
+#include "ServerFilter.hpp"
+
+#include "ui_NodeSearchDialog.h"
+
+class ServerFilter;
+
+class NodeSearchDialog : public QDialog, protected Ui::NodeSearchDialog
+{
+ Q_OBJECT
+
+public:
+ explicit NodeSearchDialog(QWidget *parent = 0);
+ ~NodeSearchDialog();
+
+ NodeSearchWidget* queryWidget() const;
+
+protected Q_SLOTS:
+ void accept();
+ void reject();
+ void slotOwnerDelete();
+
+protected:
+ void closeEvent(QCloseEvent * event);
+
+private:
+ void readSettings();
+ void writeSettings();
+};
+
+
+#endif
diff --git a/Viewer/src/NodeSearchDialog.ui b/Viewer/src/NodeSearchDialog.ui
new file mode 100644
index 0000000..90e12d0
--- /dev/null
+++ b/Viewer/src/NodeSearchDialog.ui
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>NodeSearchDialog</class>
+ <widget class="QDialog" name="NodeSearchDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>514</width>
+ <height>544</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Query</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="spacing">
+ <number>4</number>
+ </property>
+ <item>
+ <widget class="NodeSearchWidget" name="queryWidget_" native="true"/>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>NodeSearchWidget</class>
+ <extends>QWidget</extends>
+ <header>NodeSearchWidget.hpp</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources>
+ <include location="viewer.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/Viewer/src/NodeSearchWidget.cpp b/Viewer/src/NodeSearchWidget.cpp
new file mode 100644
index 0000000..662836a
--- /dev/null
+++ b/Viewer/src/NodeSearchWidget.cpp
@@ -0,0 +1,304 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "ComboMulti.hpp"
+#include "CustomListWidget.hpp"
+#include "Highlighter.hpp"
+#include "NodeQuery.hpp"
+#include "NodeQueryEngine.hpp"
+#include "NodeQueryHandler.hpp"
+#include "NodeQueryHandler.hpp"
+#include "NodeQueryResult.hpp"
+#include "NodeQueryResultModel.hpp"
+#include "ServerFilter.hpp"
+#include "UserMessage.hpp"
+#include "VNState.hpp"
+
+#include <QtGlobal>
+#include <QCloseEvent>
+#include <QDebug>
+#include <QMessageBox>
+#include <QPalette>
+#include <QVBoxLayout>
+#include "NodeSearchWidget.hpp"
+
+//======================================================
+//
+// NodeQueryWidget
+//
+//======================================================
+
+NodeSearchWidget::NodeSearchWidget(QWidget *parent) :
+ QWidget(parent),
+ query_(NULL),
+ columnsAdjusted_(false)
+{
+ setupUi(this);
+
+ //Query
+ QFont f;
+ QFontMetrics fm(f);
+
+ //Show hide def panel
+ defPanelTb_->setText("Editor <<");
+ connect(defPanelTb_,SIGNAL(clicked(bool)),
+ this,SLOT(slotShowDefPanel(bool)));
+
+ editor_->show();
+
+ connect(editor_,SIGNAL(queryEnabledChanged(bool)),
+ this,SLOT(slotQueryEnabledChanged(bool)));
+
+ //Find button
+ findPb_->setProperty("startSearch","1");
+ QPalette pal=findPb_->palette();
+ QColor col(230,245,253);
+ pal.setColor(QPalette::Button,col);
+ findPb_->setPalette(pal);
+
+ connect(findPb_,SIGNAL(clicked()),
+ this,SLOT(slotFind()));
+
+ connect(stopPb_,SIGNAL(clicked()),
+ this,SLOT(slotStop()));
+
+
+ //Close button
+ connect(closePb_,SIGNAL(clicked()),
+ this,SLOT(slotClose()));
+
+ //--------------------------------
+ // Result tree/model
+ //--------------------------------
+
+ model_=new NodeQueryResultModel(this);
+ resTree_->setSourceModel(model_);
+
+ connect(resTree_,SIGNAL(selectionChanged(VInfo_ptr)),
+ this,SIGNAL(selectionChanged(VInfo_ptr)));
+
+ connect(resTree_,SIGNAL(infoPanelCommand(VInfo_ptr,QString)),
+ this,SIGNAL(infoPanelCommand(VInfo_ptr,QString)));
+
+ //--------------------------------
+ // Query
+ //--------------------------------
+
+ query_=new NodeQuery("tmp");
+
+ //--------------------
+ // Query engine
+ //--------------------
+
+ engine_=new NodeQueryEngine(this);
+
+ connect(engine_,SIGNAL(found(QList<NodeQueryResultTmp_ptr>)),
+ model_->data(), SLOT(add(QList<NodeQueryResultTmp_ptr>)));
+
+ connect(engine_,SIGNAL(found(NodeQueryResultTmp_ptr)),
+ model_->data(),SLOT(add(NodeQueryResultTmp_ptr)));
+
+ connect(engine_,SIGNAL(started()),
+ this,SLOT(slotQueryStarted()));
+
+ connect(engine_,SIGNAL(finished()),
+ this,SLOT(slotQueryFinished()));
+
+ //-------------------
+ // Progress
+ //-------------------
+
+ queryProgress_->hide();
+
+ resW_->hide();
+ editor_->setQueryTeCanExpand(true);
+ stopPb_->setEnabled(false);
+ //mainLayout_->setStretch(1,0);
+ //mainLayout_->setStretch(0,1);
+}
+
+NodeSearchWidget::~NodeSearchWidget()
+{
+ delete query_;
+}
+
+void NodeSearchWidget::setServerFilter(ServerFilter* f)
+{
+ editor_->setServerFilter(f);
+}
+
+void NodeSearchWidget::setRootNode(VInfo_ptr info)
+{
+ editor_->setRootNode(info);
+}
+
+void NodeSearchWidget::slotShowDefPanel(bool)
+{
+ editor_->toggleDefPanelVisible();
+
+ if(editor_->isDefPanelVisible())
+ {
+ defPanelTb_->setText("Editor <<");
+ }
+ else
+ {
+ defPanelTb_->setText("Editor >>");
+ }
+}
+
+void NodeSearchWidget::slotQueryEnabledChanged(bool queryEnabled)
+{
+ //if(!engine_->isRunning())
+ //{
+#if 0
+ UserMessage::debug("NodeSearchWidget::slotQueryEnabledChanged -->" + std::string((queryEnabled?"true":"false")));
+ findPb_->setEnabled(queryEnabled);
+#endif
+ //}
+}
+
+void NodeSearchWidget::slotFind()
+{
+ UserMessage::debug("NodeSearchWidget::slotFind -->");
+
+ //Avoid double clicking
+ if(!findPb_->isEnabled())
+ {
+ UserMessage::debug("<-- NodeSearchWidget::slotFind - search is already running");
+ return;
+ }
+
+ qDebug() << engine_->isRunning();
+
+ if(!resW_->isVisible())
+ {
+ resW_->show();
+ editor_->setQueryTeCanExpand(false);
+ }
+
+ adjustColumns();
+
+ //Clear the results
+ model_->clearData();
+
+ assert(!engine_->isRunning());
+ assert(findPb_->isEnabled());
+ assert(!stopPb_->isEnabled());
+
+ //We set the button state in advance as if the engine were running
+ adjustButtonState(true);
+
+ if(!engine_->runQuery(editor_->query(),editor_->allServers()))
+ {
+ //if we are here we could not start the query and we need to reset the button state
+ adjustButtonState();
+ }
+
+ UserMessage::debug("<-- NodeSearchWidget::slotFind");
+}
+
+void NodeSearchWidget::slotStop()
+{
+ //It is a blocking call!
+ engine_->stopQuery();
+ assert(!engine_->isRunning());
+
+ adjustButtonState();
+}
+
+void NodeSearchWidget::slotClose()
+{
+ slotStop();
+ Q_EMIT closeClicked();
+}
+
+void NodeSearchWidget::slotQueryStarted()
+{
+ UserMessage::debug("NodeSearchWidget::slotQueryStarted -->");
+
+ adjustButtonState();
+
+ queryProgress_->setRange(0,0);
+ queryProgress_->show();
+
+ progressLabel_->setText("Search in progress ...");
+
+ UserMessage::debug("<-- NodeSearchWidget::slotQueryStarted");
+}
+
+void NodeSearchWidget::slotQueryFinished()
+{
+ UserMessage::debug("NodeSearchWidget::slotQueryFinished -->");
+ UserMessage::debug(" Search finished. Total node scanned: " + boost::lexical_cast<std::string>(engine_->scannedCount()));
+
+ adjustButtonState();
+
+ queryProgress_->hide();
+ queryProgress_->setRange(0,1);
+ queryProgress_->setValue(1);
+
+ progressLabel_->setText(QString::number(model_->rowCount()) + " items found");
+
+ adjustColumns();
+
+ qDebug() << engine_->isRunning();
+
+ UserMessage::debug("<-- NodeSearchWidget::slotQueryFinished");
+}
+
+void NodeSearchWidget::adjustButtonState()
+{
+ adjustButtonState(engine_->isRunning());
+}
+
+void NodeSearchWidget::adjustButtonState(bool engineRunning)
+{
+ if(engineRunning)
+ {
+ findPb_->setEnabled(false);
+ stopPb_->setEnabled(true);
+ editor_->setEnabled(false);
+ }
+ else
+ {
+ findPb_->setEnabled(true);
+ stopPb_->setEnabled(false);
+ editor_->setEnabled(true);
+ }
+
+ UserMessage::debug("NodeSearchWidget::adjustButtonState -->");
+ UserMessage::debug(" findTb_: " + boost::lexical_cast<std::string>(findPb_->isEnabled()));
+ UserMessage::debug("<-- NodeSearchWidget::adjustButtonState");
+}
+
+void NodeSearchWidget::adjustColumns()
+{
+ if(!columnsAdjusted_)
+ {
+ columnsAdjusted_=true;
+
+ //We preset the column width. Setting it dynamically can be expensive
+ //for a large number of rows (> 1M)
+ QFont f;
+ QFontMetrics fm(f);
+ resTree_->setColumnWidth(0,fm.width("serverserverser"));
+ resTree_->setColumnWidth(1,fm.width("/suite/family1/family2/longtaskname1"));
+ resTree_->setColumnWidth(2,fm.width("suspended"));
+ resTree_->setColumnWidth(3,fm.width("family"));
+
+ //for(int i=0; i < model_->columnCount()-1; i++)
+ // resTree_->resizeColumnToContents(i);
+ }
+
+}
+
+
+
+
diff --git a/Viewer/src/NodeSearchWidget.hpp b/Viewer/src/NodeSearchWidget.hpp
new file mode 100644
index 0000000..95bc2ec
--- /dev/null
+++ b/Viewer/src/NodeSearchWidget.hpp
@@ -0,0 +1,64 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+#ifndef VIEWER_SRC_NODESEARCHWIDGET_HPP_
+#define VIEWER_SRC_NODESEARCHWIDGET_HPP_
+
+#include <QAbstractItemModel>
+#include <QDialog>
+#include <QWidget>
+
+#include "ServerFilter.hpp"
+#include "VInfo.hpp"
+
+#include "ui_NodeSearchWidget.h"
+
+class NodeQuery;
+class NodeQueryEngine;
+class NodeQueryResultModel;
+
+class NodeSearchWidget : public QWidget, protected Ui::NodeSearchWidget
+{
+ Q_OBJECT
+
+public:
+ explicit NodeSearchWidget(QWidget *parent = 0);
+ ~NodeSearchWidget();
+
+ void setServerFilter(ServerFilter*);
+ void setRootNode(VInfo_ptr);
+
+public Q_SLOTS:
+ void slotStop();
+
+protected Q_SLOTS:
+ void slotShowDefPanel(bool);
+ void slotFind();
+ void slotClose();
+ void slotQueryStarted();
+ void slotQueryFinished();
+ void slotQueryEnabledChanged(bool queryEnabled);
+
+Q_SIGNALS:
+ void closeClicked();
+ void selectionChanged(VInfo_ptr);
+ void infoPanelCommand(VInfo_ptr,QString);
+
+private:
+ void adjustColumns();
+ void adjustButtonState();
+ void adjustButtonState(bool);
+
+ NodeQuery* query_;
+ NodeQueryEngine* engine_;
+ NodeQueryResultModel* model_;
+ bool columnsAdjusted_;
+};
+
+#endif /* VIEWER_SRC_NODESEARCHWIDGET_HPP_ */
diff --git a/Viewer/src/NodeSearchWidget.ui b/Viewer/src/NodeSearchWidget.ui
new file mode 100644
index 0000000..0dc06d4
--- /dev/null
+++ b/Viewer/src/NodeSearchWidget.ui
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>NodeSearchWidget</class>
+ <widget class="QWidget" name="NodeSearchWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>1564</width>
+ <height>1113</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <layout class="QVBoxLayout" name="mainLayout_" stretch="0,1">
+ <item>
+ <widget class="NodeQueryEditor" name="editor_" native="true"/>
+ </item>
+ <item>
+ <widget class="QWidget" name="resW_" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_9" stretch="1,0">
+ <property name="spacing">
+ <number>4</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="NodeQueryResultView" name="resTree_"/>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QLabel" name="progressLabel_">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QProgressBar" name="queryProgress_">
+ <property name="value">
+ <number>24</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0,0,0,0">
+ <item>
+ <widget class="QPushButton" name="findPb_">
+ <property name="text">
+ <string>Search</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/search_decor.svg</normaloff>:/viewer/search_decor.svg</iconset>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="stopPb_">
+ <property name="text">
+ <string>Stop</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="defPanelTb_">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="closePb_">
+ <property name="text">
+ <string>Close</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>NodeQueryResultView</class>
+ <extends>QTreeView</extends>
+ <header>NodeQueryResultView.hpp</header>
+ </customwidget>
+ <customwidget>
+ <class>NodeQueryEditor</class>
+ <extends>QWidget</extends>
+ <header>NodeQueryEditor.hpp</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources>
+ <include location="viewer.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/Viewer/src/NodeViewBase.cpp b/Viewer/src/NodeViewBase.cpp
new file mode 100644
index 0000000..b755188
--- /dev/null
+++ b/Viewer/src/NodeViewBase.cpp
@@ -0,0 +1,15 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "NodeViewBase.hpp"
+
+NodeViewBase::NodeViewBase(NodeFilterDef* filterDef) : filterDef_(filterDef)
+{
+
+}
diff --git a/Viewer/src/NodeViewBase.hpp b/Viewer/src/NodeViewBase.hpp
new file mode 100644
index 0000000..ff58575
--- /dev/null
+++ b/Viewer/src/NodeViewBase.hpp
@@ -0,0 +1,41 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef NODEVIEWBASE_HPP_
+#define NODEVIEWBASE_HPP_
+
+#include "Viewer.hpp"
+#include "VInfo.hpp"
+
+class QWidget;
+
+class TableNodeSortModel;
+class NodeFilterDef;
+class VSettings;
+
+class NodeViewBase
+{
+public:
+ explicit NodeViewBase(NodeFilterDef*filterDef);
+ virtual ~NodeViewBase(){}
+
+ virtual void reload()=0;
+ virtual void rerender()=0;
+ virtual QWidget* realWidget()=0;
+ virtual VInfo_ptr currentSelection()=0;
+ virtual void selectFirstServer()=0;
+ virtual void currentSelection(VInfo_ptr n)=0;
+
+ virtual void readSettings(VSettings* vs)=0;
+
+protected:
+ NodeFilterDef* filterDef_;
+};
+
+#endif
diff --git a/Viewer/src/NodeViewDelegate.cpp b/Viewer/src/NodeViewDelegate.cpp
new file mode 100644
index 0000000..e586aae
--- /dev/null
+++ b/Viewer/src/NodeViewDelegate.cpp
@@ -0,0 +1,1145 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "NodeViewDelegate.hpp"
+
+#include <QApplication>
+#include <QDebug>
+#include <QImageReader>
+#include <QPainter>
+
+#include "AbstractNodeModel.hpp"
+#include "PropertyMapper.hpp"
+
+int NodeViewDelegate::lighter_=150;
+
+static std::vector<std::string> propVec;
+
+NodeViewDelegate::NodeViewDelegate(QWidget *parent) :
+ QStyledItemDelegate(parent),
+ prop_(0),
+ iconSize_(16),
+ iconGap_(3),
+ useStateGrad_(true)
+{
+ /*//Property
+ if(propVec.empty())
+ {
+ propVec.push_back("view.tree.font");
+ propVec.push_back("view.tree.displayChildCount");
+ }
+
+ prop_=new PropertyMapper(propVec,this);
+
+ updateSettings();*/
+
+ hoverPen_=QPen(QColor(201,201,201));
+ hoverBrush_=QBrush(QColor(250,250,250,210));
+ selectPen_=QPen(QColor(125,162,206));
+ selectBrush_=QBrush(QColor(193,220,252,110));
+ nodePen_=QPen(QColor(180,180,180));
+ nodeSelectPen_=QPen(QColor(0,0,0),2);
+
+ lostConnectBgBrush_=QBrush(QColor(150,150,150,150),Qt::Dense7Pattern);
+ lostConnectBandBrush_=QBrush(QColor(255,166,0,150));
+
+ QImageReader imgR(":/viewer/warning.svg");
+ if(imgR.canRead())
+ {
+ QFont font;
+ QFontMetrics fm(font);
+ int size=fm.height()+2;
+ imgR.setScaledSize(QSize(size,size));
+ QImage img=imgR.read();
+ errPix_=QPixmap(QPixmap::fromImage(img));
+ }
+
+ grad_.setCoordinateMode(QGradient::ObjectBoundingMode);
+ grad_.setStart(0,0);
+ grad_.setFinalStop(0,1);
+
+ eventFillBrush_=QBrush(QColor(0,0,255));
+ eventFillBrush_=QBrush(QColor(240,240,240));
+ meterFillBrush_=QBrush(QColor(0,0,255));
+ meterThresholdBrush_=QBrush(QColor(0,0,255));
+ limitFillBrush_=QBrush(QColor(0,255,0));
+
+ attrRenderers_["meter"]=&NodeViewDelegate::renderMeter;
+ attrRenderers_["label"]=&NodeViewDelegate::renderLabel;
+ attrRenderers_["event"]=&NodeViewDelegate::renderEvent;
+ attrRenderers_["var"]=&NodeViewDelegate::renderVar;
+ attrRenderers_["genvar"]=&NodeViewDelegate::renderGenvar;
+ attrRenderers_["limit"]=&NodeViewDelegate::renderLimit;
+ attrRenderers_["limiter"]=&NodeViewDelegate::renderLimiter;
+ attrRenderers_["trigger"]=&NodeViewDelegate::renderTrigger;
+ attrRenderers_["time"]=&NodeViewDelegate::renderTime;
+ attrRenderers_["date"]=&NodeViewDelegate::renderDate;
+ attrRenderers_["repeat"]=&NodeViewDelegate::renderRepeat;
+ attrRenderers_["late"]=&NodeViewDelegate::renderLate;
+}
+
+NodeViewDelegate::~NodeViewDelegate()
+{
+ if(prop_)
+ delete prop_;
+}
+
+void NodeViewDelegate::notifyChange(VProperty* p)
+{
+ updateSettings();
+}
+
+void NodeViewDelegate::addBaseSettings(std::vector<std::string>& propVec)
+{
+ propVec.push_back("view.attribute.eventFillColour");
+ propVec.push_back("view.attribute.meterFillColour");
+ propVec.push_back("view.attribute.meterThresholdColour");
+ propVec.push_back("view.attribute.limitFillColour");
+}
+
+void NodeViewDelegate::updateBaseSettings()
+{
+ if(VProperty* p=prop_->find("view.attribute.eventFillColour"))
+ {
+ eventFillBrush_=QBrush(p->value().value<QColor>());
+ }
+ if(VProperty* p=prop_->find("view.attribute.meterFillColour"))
+ {
+ QLinearGradient gr;
+ gr.setCoordinateMode(QGradient::ObjectBoundingMode);
+ gr.setStart(0,0);
+ gr.setFinalStop(0,1);
+ QColor c1=p->value().value<QColor>();
+ gr.setColorAt(0,c1);
+ gr.setColorAt(1,c1.lighter(110));
+ meterFillBrush_=QBrush(gr);
+ }
+ if(VProperty* p=prop_->find("view.attribute.meterThresholdColour"))
+ {
+ QLinearGradient gr;
+ gr.setCoordinateMode(QGradient::ObjectBoundingMode);
+ gr.setStart(0,0);
+ gr.setFinalStop(0,1);
+ QColor c1=p->value().value<QColor>();
+ gr.setColorAt(0,c1);
+ gr.setColorAt(1,c1.lighter(110));
+ meterThresholdBrush_=QBrush(gr);
+ }
+ if(VProperty* p=prop_->find("view.attribute.limitFillColour"))
+ {
+ limitFillBrush_=QBrush(p->value().value<QColor>());
+ }
+
+ //limit pixmaps
+ QFontMetrics fm(attrFont_);
+ int itemSize=static_cast<int>(static_cast<float>(fm.ascent())*0.9);
+
+ QImage img(itemSize,itemSize,QImage::Format_ARGB32_Premultiplied);
+ img.fill(Qt::transparent);
+ QPainter painter(&img);
+ //painter.setRenderHint(QPainter::Antialiasing,true);
+ painter.setPen(QPen(QColor(70,70,70),0));
+ painter.setBrush(limitFillBrush_);
+ painter.drawEllipse(1,1,itemSize-2,itemSize-2);
+ limitFillPix_=QPixmap::fromImage(img);
+ painter.fillRect(QRect(QPoint(0,0),img.size()),Qt::transparent);
+ painter.setBrush(QColor(240,240,240));
+ painter.drawEllipse(1,1,itemSize-2,itemSize-2);
+ limitEmptyPix_=QPixmap::fromImage(img);
+}
+
+QSize NodeViewDelegate::sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index ) const
+{
+ QSize size=QStyledItemDelegate::sizeHint(option,index);
+
+ QFontMetrics fm(font_);
+ int h=fm.height();
+ return QSize(size.width(),h+8);
+}
+
+void NodeViewDelegate::adjustIconSize()
+{
+ QFontMetrics fm(font_);
+ int h=fm.ascent()+fm.descent()/2;
+ iconSize_=h;
+ if(iconSize_ % 2 == 1)
+ iconSize_+=1;
+
+ iconGap_=iconSize_/5;
+ if(iconGap_ < 3)
+ iconGap_=3;
+ if(iconGap_ > 10)
+ iconGap_=10;
+
+ /*if(h > 14 && h < 19 )
+ iconSize_=16;
+ else if( h < 22)
+ iconSize_=20;
+ else if( h < 29)
+ iconSize_=24;
+ else if (h < 38)
+ iconSize=32;
+ else if ()*/
+}
+
+
+void NodeViewDelegate::renderStatus(QPainter *painter,const QModelIndex& index,
+ const QStyleOptionViewItemV4& option) const
+{
+ int offset=4;
+
+ QFontMetrics fm(font_);
+ int deltaH=(option.rect.height()-(fm.height()+4))/2;
+
+ //The initial filled rect (we will adjust its width)
+ QRect fillRect=option.rect.adjusted(offset,deltaH,-offset,-deltaH-1);
+ if(option.state & QStyle::State_Selected)
+ fillRect.adjust(0,0,0,-0);
+
+ int currentRight=fillRect.right();
+
+ //The text rectangle
+ QString text=index.data(Qt::DisplayRole).toString();
+ int textWidth=fm.width(text);
+ QRect textRect = fillRect.adjusted(offset,0,0,0);
+ textRect.setWidth(textWidth);
+
+ if(textRect.right() > currentRight)
+ currentRight=textRect.right();
+
+ //Define clipping
+ int rightPos=currentRight+1;
+ const bool setClipRect = rightPos > option.rect.right();
+ if(setClipRect)
+ {
+ painter->save();
+ QRect cr=option.rect.adjusted(0,0,-offset,0);
+ painter->setClipRect(cr);
+ }
+
+ //Fill rect
+ QColor bg=index.data(Qt::BackgroundRole).value<QColor>();
+ QColor bgLight=bg.lighter(lighter_);
+ QBrush bgBrush;
+ if(useStateGrad_)
+ {
+ grad_.setColorAt(0,bgLight);
+ grad_.setColorAt(1,bg);
+ bgBrush=QBrush(grad_);
+ }
+ else
+ bgBrush=QBrush(bg);
+
+ painter->fillRect(fillRect,bgBrush);
+
+ //Draw text
+ painter->setFont(font_);
+ painter->setPen(Qt::black);
+ painter->drawText(textRect,Qt::AlignLeft | Qt::AlignVCenter,text);
+
+ if(setClipRect)
+ {
+ painter->restore();
+ }
+}
+
+//========================================================
+// data is encoded as a QStringList as follows:
+// "meter" name value min max colChange
+//========================================================
+
+void NodeViewDelegate::renderMeter(QPainter *painter,QStringList data,const QStyleOptionViewItemV4& option) const
+{
+ if(data.count() != 6)
+ return;
+
+ //The data
+ int val=data.at(2).toInt();
+ int min=data.at(3).toInt();
+ int max=data.at(4).toInt();
+ int threshold=data.at(5).toInt();
+
+ //float percent=static_cast<float>(val-min)/static_cast<float>(max-min);
+ //float thresholdPercent=static_cast<float>(threshold-min)/static_cast<float>(max-min);
+
+ QString name=data.at(1) + ":";
+ QString valStr=data.at(2); // + " (" + QString::number(100.*percent) + "%)";
+
+ int frontOffset=8;
+ int offset=2;
+ //int gap=5;
+
+ //The border rect (we will adjust its width)
+ QRect fillRect=option.rect.adjusted(frontOffset,1,0,-1);
+ if(option.state & QStyle::State_Selected)
+ fillRect.adjust(0,1,0,-1);
+
+ QFontMetrics fm(attrFont_);
+
+ //The status rectangle
+ int stHeight=static_cast<int>(static_cast<float>(fm.ascent())*0.9);
+ int stHeightDiff=(fillRect.height()-stHeight)/2;
+ QRect stRect=fillRect.adjusted(offset,stHeightDiff,
+ 0,-(fillRect.height()-stHeight-stHeightDiff));
+ stRect.setWidth(50);
+
+ //The text rectangle
+ QFont nameFont=attrFont_;
+ nameFont.setBold(true);
+ fm=QFontMetrics(nameFont);
+ int nameWidth=fm.width(name);
+ QRect nameRect = fillRect;
+ nameRect.setLeft(stRect.right()+fm.width('A'));
+ nameRect.setWidth(nameWidth);
+
+ //The value rectangle
+ QFont valFont=attrFont_;
+ fm=QFontMetrics(valFont);
+ int valWidth=fm.width(valStr);
+ QRect valRect = nameRect;
+ valRect.setLeft(nameRect.right()+fm.width('A'));
+ valRect.setWidth(valWidth);
+
+ //Adjust the filled rect width
+ fillRect.setRight(valRect.right()+offset);
+
+ //Define clipping
+ int rightPos=fillRect.right()+1;
+ const bool setClipRect = rightPos > option.rect.right();
+ if(setClipRect)
+ {
+ painter->save();
+ painter->setClipRect(option.rect);
+ }
+
+ //Fill st rect
+ painter->fillRect(stRect,QColor(229,229,229));
+
+ //Draw progress
+ if(max > min)
+ {
+ QRect progRect=stRect;
+
+ float valPercent=static_cast<float>(val-min)/static_cast<float>(max-min);
+ if(threshold > min && threshold < max && val > threshold)
+ {
+ int progWidth=static_cast<int>(static_cast<float>(stRect.width())*valPercent);
+ if(val < max)
+ {
+ progRect.setWidth(progWidth);
+ }
+ painter->fillRect(progRect,meterThresholdBrush_);
+
+ float thresholdPercent=static_cast<float>(threshold-min)/static_cast<float>(max-min);
+ progWidth=static_cast<int>(static_cast<float>(stRect.width())*thresholdPercent);
+ progRect.setWidth(progWidth);
+ painter->fillRect(progRect,meterFillBrush_);
+ }
+ else
+ {
+ int progWidth=static_cast<int>(static_cast<float>(stRect.width())*valPercent);
+ if(val < max)
+ {
+ progRect.setWidth(progWidth);
+ }
+ painter->fillRect(progRect,meterFillBrush_);
+ }
+ }
+
+ //Draw st rect border
+ if(max > min)
+ {
+ painter->setPen(QColor(140,140,140));
+ }
+ else
+ {
+ painter->setPen(QPen(QColor(140,140,140),Qt::DotLine));
+ }
+ painter->setBrush(Qt::NoBrush);
+ painter->drawRect(stRect);
+
+
+ //Draw name
+ painter->setPen(Qt::black);
+ painter->setFont(nameFont);
+ painter->drawText(nameRect,Qt::AlignLeft | Qt::AlignVCenter,name);
+
+ //Draw value
+ painter->setPen(Qt::black);
+ painter->setFont(valFont);
+ painter->drawText(valRect,Qt::AlignLeft | Qt::AlignVCenter,valStr);
+
+ if(setClipRect)
+ {
+ painter->restore();
+ }
+}
+
+//========================================================
+// data is encoded as a QStringList as follows:
+// "label" name value
+//========================================================
+
+void NodeViewDelegate::renderLabel(QPainter *painter,QStringList data,const QStyleOptionViewItemV4& option) const
+{
+ if(data.count() < 2)
+ return;
+
+ QString name=data.at(1) + ":";
+ QString val;
+ if(data.count() > 2)
+ val=data.at(2);
+
+ int frontOffset=8;
+ int offset=2;
+
+ //The border rect (we will adjust its width)
+ QRect fillRect=option.rect.adjusted(frontOffset,1,0,-1);
+ if(option.state & QStyle::State_Selected)
+ fillRect.adjust(0,1,0,-1);
+
+
+ int multiCnt=val.count('\n');
+
+ QRect nameRect;
+ QRect valRect;
+ QRect multiValRect;
+
+ QFont nameFont=attrFont_;
+ nameFont.setBold(true);
+ QFont valFont=attrFont_;
+ QString multiVal;
+
+ if(multiCnt ==0 )
+ {
+ //The text rectangle
+ QFontMetrics fm(nameFont);
+ int nameWidth=fm.width(name);
+ nameRect = fillRect.adjusted(offset,0,0,0);
+ nameRect.setWidth(nameWidth);
+
+ //The value rectangle
+ fm=QFontMetrics(valFont);
+ int valWidth=fm.width(val);
+ valRect = nameRect;
+ valRect.setLeft(nameRect.right()+fm.width('A'));
+ valRect.setWidth(valWidth);
+
+ //Adjust the filled rect width
+ fillRect.setRight(valRect.right()+offset);
+ }
+ else
+ {
+ QStringList vals=val.split('\n');
+ val=vals[0];
+ vals.removeFirst();
+
+ multiVal=vals.join(QString('\n'));
+
+ //The text rectangle
+ QFontMetrics fm(nameFont);
+ int nameWidth=fm.width(name);
+ nameRect = fillRect.adjusted(offset,0,0,0);
+ nameRect.setWidth(nameWidth);
+ nameRect.setHeight(fm.height()+offset);
+
+ //The value rectangle
+ fm=QFontMetrics(valFont);
+ int valWidth=fm.width(val);
+ valRect = nameRect;
+ valRect.setLeft(nameRect.right()+fm.width('A'));
+ valRect.setWidth(valWidth);
+ nameRect.setHeight(fm.height()+offset);
+
+ //Multiple line
+ multiValRect = QRect(nameRect.x(),
+ nameRect.bottom()+offset/2,
+ fm.width(multiVal),
+ fillRect.bottom()-(nameRect.bottom()+offset));
+ }
+
+ //Define clipping
+ int rightPos=fillRect.right()+1;
+ const bool setClipRect = rightPos > option.rect.right();
+ if(setClipRect)
+ {
+ painter->save();
+ painter->setClipRect(option.rect);
+ }
+
+ //Draw name
+ painter->setPen(Qt::black);
+ painter->setFont(nameFont);
+ painter->drawText(nameRect,Qt::AlignLeft | Qt::AlignVCenter,name);
+
+ //Draw value
+ painter->setPen(Qt::black);
+ painter->setFont(valFont);
+ painter->drawText(valRect,Qt::AlignLeft | Qt::AlignVCenter,val);
+
+ if(multiCnt > 0)
+ {
+ painter->setFont(valFont);
+ painter->drawText(multiValRect,Qt::AlignLeft | Qt::AlignTop,multiVal);
+ }
+
+ if(setClipRect)
+ {
+ painter->restore();
+ }
+}
+
+
+//========================================================
+// data is encoded as a QStringList as follows:
+// "event" name value
+//========================================================
+
+void NodeViewDelegate::renderEvent(QPainter *painter,QStringList data,const QStyleOptionViewItemV4& option) const
+{
+ if(data.count() < 2)
+ return;
+
+ QString name=data.at(1);
+ bool val=false;
+ if(data.count() > 2) val=(data.at(2) == "1");
+
+ int frontOffset=8;
+ int offset=2;
+
+ //The border rect (we will adjust its width)
+ QRect fillRect=option.rect.adjusted(frontOffset,1,0,-1);
+ if(option.state & QStyle::State_Selected)
+ fillRect.adjust(0,1,0,-1);
+
+ //The control rect
+ int ch=(fillRect.height()-4 < 10)?(fillRect.height()-4):8;
+ QRect cRect=fillRect.adjusted(offset,(fillRect.height()-ch)/2,
+ 0,-(fillRect.height()-ch)/2);
+ cRect.setWidth(cRect.height());
+
+ //The text rectangle
+ QFont font=attrFont_;
+ QFontMetrics fm(font);
+ int nameWidth=fm.width(name);
+ QRect nameRect = fillRect.adjusted(offset,0,0,0);
+ nameRect.setLeft(cRect.right()+fm.width('a'));
+ nameRect.setWidth(nameWidth);
+
+ //Adjust the filled rect width
+ fillRect.setRight(nameRect.right()+offset);
+
+ //Define clipping
+ int rightPos=fillRect.right()+1;
+ const bool setClipRect = rightPos > option.rect.right();
+ if(setClipRect)
+ {
+ painter->save();
+ painter->setClipRect(option.rect);
+ }
+
+ //Draw control
+ painter->setPen(Qt::black);
+ painter->setBrush((val)?eventFillBrush_:eventBgBrush_);
+ painter->drawRect(cRect);
+
+ //Draw name
+ painter->setPen(Qt::black);
+ painter->setFont(font);
+ painter->drawText(nameRect,Qt::AlignLeft | Qt::AlignVCenter,name);
+
+ if(setClipRect)
+ {
+ painter->restore();
+ }
+}
+
+void NodeViewDelegate::renderVar(QPainter *painter,QStringList data,const QStyleOptionViewItemV4& option) const
+{
+ QString text;
+
+ if(data.count() >1)
+ text+=data.at(1) + "=";
+ if(data.count() > 2)
+ text+=data.at(2);
+
+ int offset=2;
+ int frontOffset=8;
+
+ //The border rect (we will adjust its width)
+ QRect fillRect=option.rect.adjusted(frontOffset,1,0,-1);
+ if(option.state & QStyle::State_Selected)
+ fillRect.adjust(0,1,0,-1);
+
+ //The text rectangle
+ QFont font=attrFont_;
+ //nameFont.setBold(true);
+ QFontMetrics fm(font);
+ int textWidth=fm.width(text);
+ QRect textRect = fillRect.adjusted(offset,0,0,0);
+ textRect.setWidth(textWidth);
+
+ //Adjust the filled rect width
+ fillRect.setRight(textRect.right()+offset);
+
+ //Define clipping
+ int rightPos=fillRect.right()+1;
+ const bool setClipRect = rightPos > option.rect.right();
+ if(setClipRect)
+ {
+ painter->save();
+ painter->setClipRect(option.rect);
+ }
+
+ //Draw text
+ painter->setPen(Qt::black);
+ painter->setFont(font);
+ painter->drawText(textRect,Qt::AlignLeft | Qt::AlignVCenter,text);
+
+ if(setClipRect)
+ {
+ painter->restore();
+ }
+}
+
+void NodeViewDelegate::renderGenvar(QPainter *painter,QStringList data,const QStyleOptionViewItemV4& option) const
+{
+ QString text;
+
+ if(data.count() >1)
+ text+=data.at(1) + "=";
+ if(data.count() > 2)
+ text+=data.at(2);
+
+ int offset=2;
+ int frontOffset=8;
+
+ //The border rect (we will adjust its width)
+ QRect fillRect=option.rect.adjusted(frontOffset,1,0,-1);
+ if(option.state & QStyle::State_Selected)
+ fillRect.adjust(0,1,0,-1);
+
+ //The text rectangle
+ QFont font=attrFont_;
+ //nameFont.setBold(true);
+ QFontMetrics fm(font);
+ int textWidth=fm.width(text);
+ QRect textRect = fillRect.adjusted(offset,0,0,0);
+ textRect.setWidth(textWidth);
+
+ //Adjust the filled rect width
+ fillRect.setRight(textRect.right()+offset);
+
+ //Define clipping
+ int rightPos=fillRect.right()+1;
+ const bool setClipRect = rightPos > option.rect.right();
+ if(setClipRect)
+ {
+ painter->save();
+ painter->setClipRect(option.rect);
+ }
+
+ //Draw text
+ painter->setPen(Qt::blue);
+ painter->setFont(font);
+ painter->drawText(textRect,Qt::AlignLeft | Qt::AlignVCenter,text);
+
+ if(setClipRect)
+ {
+ painter->restore();
+ }
+}
+
+void NodeViewDelegate::renderLimit(QPainter *painter,QStringList data,const QStyleOptionViewItemV4& option) const
+{
+ if(data.count() != 4)
+ return;
+
+ //The data
+ int val=data.at(2).toInt();
+ int max=data.at(3).toInt();
+ QString name=data.at(1) + ":";
+ QString valStr=QString::number(val) + "/" + QString::number(max);
+ bool drawItem=(max < 21);
+
+ QFontMetrics fm(attrFont_);
+ int offset=2;
+ int frontOffset=8;
+
+ int itemOffset=0;
+ int gap=fm.width('A');
+ int itemSize=limitFillPix_.width();
+
+ //The border rect (we will adjust its width)
+ QRect fillRect=option.rect.adjusted(frontOffset,1,0,-1);
+ if(option.state & QStyle::State_Selected)
+ fillRect.adjust(0,1,0,-1);
+
+ //The text rectangle
+ QFont nameFont=attrFont_;
+ nameFont.setBold(true);
+ fm=QFontMetrics(nameFont);
+ int nameWidth=fm.width(name);
+ QRect nameRect = fillRect.adjusted(offset,2,0,-2);
+ //nameRect.setLeft(fillRect.left());
+ nameRect.setWidth(nameWidth);
+
+ //The value rectangle
+ QFont valFont=attrFont_;
+ fm=QFontMetrics(valFont);
+ int valWidth=fm.width(valStr);
+ QRect valRect = nameRect;
+ valRect.setLeft(nameRect.right()+gap);
+ valRect.setWidth(valWidth);
+
+ int xItem;
+ if(drawItem)
+ {
+ xItem=valRect.right()+gap;
+ fillRect.setRight(xItem+max*(itemSize+itemOffset)+itemOffset);
+ }
+ else
+ {
+ //Adjust the filled rect width
+ fillRect.setRight(valRect.right()+offset);
+ }
+
+ //Define clipping
+ int rightPos=fillRect.right()+1;
+ const bool setClipRect = rightPos > option.rect.right();
+
+ if(setClipRect || drawItem)
+ {
+ painter->save();
+ painter->setClipRect(option.rect);
+ }
+
+ //Draw name painter->setPen(Qt::black);
+ painter->setFont(nameFont);
+ painter->drawText(nameRect,Qt::AlignLeft | Qt::AlignVCenter,name);
+
+ //Draw value
+ painter->setPen(Qt::black);
+ painter->setFont(valFont);
+ painter->drawText(valRect,Qt::AlignLeft | Qt::AlignVCenter,valStr);
+
+ //Draw items
+ if(drawItem)
+ {
+ int yItem=option.rect.y()+(option.rect.height()-itemSize)/2;
+ for(int i=0; i < max; i++)
+ {
+ if(i >= val)
+ {
+
+ painter->drawPixmap(xItem,yItem,itemSize,itemSize,limitEmptyPix_);
+ }
+ else
+ {
+ painter->drawPixmap(xItem,yItem,itemSize,itemSize,limitFillPix_);
+ }
+
+
+ xItem+=itemOffset+itemSize;
+ }
+ }
+
+ if(setClipRect || drawItem)
+ {
+ painter->restore();
+ }
+}
+
+void NodeViewDelegate::renderLimiter(QPainter *painter,QStringList data,const QStyleOptionViewItemV4& option) const
+{
+ if(data.count() != 3)
+ return;
+
+ QString name="inlimit " + data.at(2) +":" +data.at(1);
+
+ int offset=2;
+ int frontOffset=8;
+
+ //The border rect (we will adjust its width)
+ QRect fillRect=option.rect.adjusted(frontOffset,1,0,-1);
+ if(option.state & QStyle::State_Selected)
+ fillRect.adjust(0,1,0,-1);
+
+ //The text rectangle
+ QFont nameFont=attrFont_;
+ //nameFont.setBold(true);
+ QFontMetrics fm(nameFont);
+ int nameWidth=fm.width(name);
+ QRect nameRect = fillRect.adjusted(offset,0,0,0);
+ nameRect.setWidth(nameWidth);
+
+ //Adjust the filled rect width
+ fillRect.setRight(nameRect.right()+offset);
+
+ //Define clipping
+ int rightPos=fillRect.right()+1;
+ const bool setClipRect = rightPos > option.rect.right();
+ if(setClipRect)
+ {
+ painter->save();
+ painter->setClipRect(option.rect);
+ }
+
+ //Draw name
+ painter->setPen(Qt::black);
+ painter->setFont(nameFont);
+ painter->drawText(nameRect,Qt::AlignLeft | Qt::AlignVCenter,name);
+
+ if(setClipRect)
+ {
+ painter->restore();
+ }
+}
+
+void NodeViewDelegate::renderTrigger(QPainter *painter,QStringList data,const QStyleOptionViewItemV4& option) const
+{
+ if(data.count() !=3)
+ return;
+
+ int triggerType=data[1].toInt();
+
+ QString text=data.at(2);
+
+ int offset=2;
+ int frontOffset=8;
+
+ //The border rect (we will adjust its width)
+ QRect fillRect=option.rect.adjusted(frontOffset,2,0,-2);
+ if(option.state & QStyle::State_Selected)
+ fillRect.adjust(0,1,0,-1);
+
+ //The text rectangle
+ QFont font=attrFont_;
+ QFontMetrics fm(font);
+ int textWidth=fm.width(text);
+ QRect textRect = fillRect.adjusted(offset,0,0,0);
+ textRect.setWidth(textWidth);
+
+ //Adjust the filled rect width
+ fillRect.setRight(textRect.right()+offset);
+
+ //Define clipping
+ int rightPos=fillRect.right()+1;
+ const bool setClipRect = rightPos > option.rect.right();
+ if(setClipRect)
+ {
+ painter->save();
+ painter->setClipRect(option.rect);
+ }
+
+ //draw rect
+ painter->setBrush(QColor(230,230,230));
+ painter->setPen(QColor(150,150,150));
+ painter->drawRect(fillRect);
+
+ //Draw text
+ if(triggerType==0)
+ painter->setPen(Qt::black);
+ else
+ painter->setPen(Qt::blue);
+ painter->setFont(font);
+ painter->drawText(textRect,Qt::AlignLeft | Qt::AlignVCenter,text);
+
+ if(setClipRect)
+ {
+ painter->restore();
+ }
+}
+
+void NodeViewDelegate::renderTime(QPainter *painter,QStringList data,const QStyleOptionViewItemV4& option) const
+{
+ if(data.count() != 2)
+ return;
+
+ QString name=data.at(1);
+
+ int offset=2;
+ int frontOffset=2;
+
+ //The border rect (we will adjust its width)
+ QRect fillRect=option.rect.adjusted(frontOffset,1,0,-1);
+ if(option.state & QStyle::State_Selected)
+ fillRect.adjust(0,1,0,-1);
+
+ //The text rectangle
+ QFont nameFont=attrFont_;
+ //nameFont.setBold(true);
+ QFontMetrics fm(nameFont);
+ int nameWidth=fm.width(name);
+ QRect nameRect = fillRect.adjusted(offset,0,0,0);
+ nameRect.setWidth(nameWidth);
+
+ //Adjust the filled rect width
+ fillRect.setRight(nameRect.right()+offset);
+
+ //Define clipping
+ int rightPos=fillRect.right()+1;
+ const bool setClipRect = rightPos > option.rect.right();
+ if(setClipRect)
+ {
+ painter->save();
+ painter->setClipRect(option.rect);
+ }
+
+ //Draw name
+ painter->setPen(Qt::black);
+ painter->setFont(nameFont);
+ painter->drawText(nameRect,Qt::AlignLeft | Qt::AlignVCenter,name);
+
+ if(setClipRect)
+ {
+ painter->restore();
+ }
+}
+
+void NodeViewDelegate::renderDate(QPainter *painter,QStringList data,const QStyleOptionViewItemV4& option) const
+{
+ if(data.count() != 2)
+ return;
+
+ QString name=data.at(1);
+
+ int offset=2;
+ int frontOffset=8;
+
+ //The border rect (we will adjust its width)
+ QRect fillRect=option.rect.adjusted(frontOffset,1,0,-1);
+ if(option.state & QStyle::State_Selected)
+ fillRect.adjust(0,1,0,-1);
+
+ //The text rectangle
+ QFont nameFont=attrFont_;
+ //nameFont.setBold(true);
+ QFontMetrics fm(nameFont);
+ int nameWidth=fm.width(name);
+ QRect nameRect = fillRect.adjusted(offset,0,0,0);
+ nameRect.setWidth(nameWidth);
+
+ //Adjust the filled rect width
+ fillRect.setRight(nameRect.right()+offset);
+
+ //Define clipping
+ int rightPos=fillRect.right()+1;
+ const bool setClipRect = rightPos > option.rect.right();
+ if(setClipRect)
+ {
+ painter->save();
+ painter->setClipRect(option.rect);
+ }
+
+ //Draw name
+ painter->setPen(Qt::black);
+ painter->setFont(nameFont);
+ painter->drawText(nameRect,Qt::AlignLeft | Qt::AlignVCenter,name);
+
+ if(setClipRect)
+ {
+ painter->restore();
+ }
+}
+
+//========================================================
+// data is encoded as a QStringList as follows:
+// "repeat" name value
+//========================================================
+
+void NodeViewDelegate::renderRepeat(QPainter *painter,QStringList data,const QStyleOptionViewItemV4& option) const
+{
+ if(data.count() != 7)
+ return;
+
+ QString type=data.at(1);
+ QString name=data.at(2);
+ QString val=data.at(3);
+ QString start=data.at(4);
+ QString end=data.at(5);
+ QString step=data.at(6);
+
+ int offset=2;
+ int frontOffset=8;
+
+ //The border rect (we will adjust its width)
+ QRect fillRect=option.rect.adjusted(frontOffset,1,0,-1);
+ if(option.state & QStyle::State_Selected)
+ fillRect.adjust(0,1,0,-1);
+
+ if(type == "day")
+ {
+ QFont nameFont=attrFont_;
+ QFontMetrics fm(nameFont);
+ name="day=" + step;
+ int nameWidth=fm.width(name);
+ QRect nameRect = fillRect.adjusted(offset,0,0,0);
+ nameRect.setWidth(nameWidth);
+
+ //Define clipping
+ int rightPos=fillRect.right()+1;
+ const bool setClipRect = rightPos > option.rect.right();
+ if(setClipRect)
+ {
+ painter->save();
+ painter->setClipRect(option.rect);
+ }
+
+ //Draw name
+ painter->setPen(Qt::black);
+ painter->setFont(nameFont);
+ painter->drawText(nameRect,Qt::AlignLeft | Qt::AlignVCenter,name);
+
+ if(setClipRect)
+ {
+ painter->restore();
+ }
+ }
+ else
+ {
+ QString endDot;
+ if(start == val)
+ {
+ name+="=";
+ endDot="...";
+ }
+ else if(end == val)
+ {
+ name+="=...";
+ endDot="";
+ }
+ else
+ {
+ name+="=...";
+ endDot="...";
+ }
+
+ //The name rectangle
+ QFont nameFont=attrFont_;
+ QFontMetrics fm(nameFont);
+ int nameWidth=fm.width(name);
+ QRect nameRect = fillRect.adjusted(offset,0,0,0);
+ nameRect.setWidth(nameWidth);
+
+ //The value rectangle
+ QFont valFont=attrFont_;
+ valFont.setBold(true);
+ fm=QFontMetrics(valFont);
+ int valWidth=fm.width(val);
+ QRect valRect = nameRect;
+ if(name.endsWith("..."))
+ valRect.setLeft(nameRect.right() + fm.width('A')/2);
+ else
+ valRect.setLeft(nameRect.right() + fm.width(' ')/2);
+
+ valRect.setWidth(valWidth);
+
+ //Adjust the filled rect width
+ fillRect.setRight(valRect.right()+offset);
+
+ //End ...
+ QRect dotRect;
+ if(!endDot.isEmpty())
+ {
+ fm=QFontMetrics(nameFont);
+ int dotWidth=fm.width("...");
+ dotRect = valRect;
+ dotRect.setLeft(valRect.right()+fm.width('A')/2);
+ dotRect.setWidth(dotWidth);
+
+ //Adjust the filled rect width
+ fillRect.setRight(dotRect.right()+offset);
+ }
+
+ //Define clipping
+ int rightPos=fillRect.right()+1;
+ const bool setClipRect = rightPos > option.rect.right();
+ if(setClipRect)
+ {
+ painter->save();
+ painter->setClipRect(option.rect);
+ }
+
+ //Draw name
+ painter->setPen(Qt::black);
+ painter->setFont(nameFont);
+ painter->drawText(nameRect,Qt::AlignLeft | Qt::AlignVCenter,name);
+
+ //Draw value
+ painter->setPen(Qt::black);
+ painter->setFont(valFont);
+ painter->drawText(valRect,Qt::AlignLeft | Qt::AlignVCenter,val);
+
+ //Draw end dots
+ if(!endDot.isEmpty())
+ {
+ painter->setPen(Qt::black);
+ painter->setFont(nameFont);
+ painter->drawText(dotRect,Qt::AlignLeft | Qt::AlignVCenter,"...");
+ }
+
+ if(setClipRect)
+ {
+ painter->restore();
+ }
+ }
+}
+
+void NodeViewDelegate::renderLate(QPainter *painter,QStringList data,const QStyleOptionViewItemV4& option) const
+{
+
+ if(data.count() != 2)
+ return;
+
+ QString name="late: " + data.at(1);
+
+ int offset=2;
+ int frontOffset=8;
+
+ //The border rect (we will adjust its width)
+ QRect fillRect=option.rect.adjusted(frontOffset,1,0,-1);
+ if(option.state & QStyle::State_Selected)
+ fillRect.adjust(0,1,0,-1);
+
+ //The text rectangle
+ QFont nameFont=attrFont_;
+ QFontMetrics fm(nameFont);
+ int nameWidth=fm.width(name);
+ QRect nameRect = fillRect.adjusted(offset,0,0,0);
+ nameRect.setWidth(nameWidth);
+
+ //Adjust the filled rect width
+ fillRect.setRight(nameRect.right()+offset);
+
+ //Define clipping
+ int rightPos=fillRect.right()+1;
+ const bool setClipRect = rightPos > option.rect.right();
+ if(setClipRect)
+ {
+ painter->save();
+ painter->setClipRect(option.rect);
+ }
+
+ //Draw name
+ painter->setPen(Qt::black);
+ painter->setFont(nameFont);
+ painter->drawText(nameRect,Qt::AlignLeft | Qt::AlignVCenter,name);
+
+ if(setClipRect)
+ {
+ painter->restore();
+ }
+}
+
+
+
+
+
+
diff --git a/Viewer/src/NodeViewDelegate.hpp b/Viewer/src/NodeViewDelegate.hpp
new file mode 100644
index 0000000..8ca9b8e
--- /dev/null
+++ b/Viewer/src/NodeViewDelegate.hpp
@@ -0,0 +1,94 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef NODEVIEWDELEGATE_HPP_
+#define NODEVIEWDELEGATE_HPP_
+
+#include <QBrush>
+#include <QLinearGradient>
+#include <QMap>
+#include <QPen>
+#include <QStyledItemDelegate>
+
+#include "VProperty.hpp"
+
+#include <string>
+
+class PropertyMapper;
+
+class NodeViewDelegate : public QStyledItemDelegate, public VPropertyObserver
+{
+public:
+ explicit NodeViewDelegate(QWidget *parent=0);
+ ~NodeViewDelegate();
+
+ QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index ) const;
+
+ void notifyChange(VProperty*);
+
+protected:
+ void adjustIconSize();
+ virtual void updateSettings()=0;
+ void addBaseSettings(std::vector<std::string>&);
+ void updateBaseSettings();
+
+ virtual void renderStatus(QPainter *painter,const QModelIndex& index,
+ const QStyleOptionViewItemV4& option) const;
+
+ typedef void (NodeViewDelegate::*AttributeRendererProc)(QPainter *painter,QStringList data,const QStyleOptionViewItemV4& option) const;
+
+ virtual void renderMeter(QPainter *painter,QStringList data,const QStyleOptionViewItemV4& option) const;
+ virtual void renderLabel(QPainter *painter,QStringList data,const QStyleOptionViewItemV4& option) const;
+ virtual void renderEvent(QPainter *painter,QStringList data,const QStyleOptionViewItemV4& option) const;
+ virtual void renderVar(QPainter *painter,QStringList data,const QStyleOptionViewItemV4& option) const;
+ virtual void renderGenvar(QPainter *painter,QStringList data,const QStyleOptionViewItemV4& option) const;
+ virtual void renderLimit(QPainter *painter,QStringList data,const QStyleOptionViewItemV4& option) const;
+ virtual void renderLimiter(QPainter *painter,QStringList data,const QStyleOptionViewItemV4& option) const;
+ virtual void renderTrigger(QPainter *painter,QStringList data,const QStyleOptionViewItemV4& option) const;
+ virtual void renderTime(QPainter *painter,QStringList data,const QStyleOptionViewItemV4& option) const;
+ virtual void renderDate(QPainter *painter,QStringList data,const QStyleOptionViewItemV4& option) const;
+ virtual void renderRepeat(QPainter *painter,QStringList data,const QStyleOptionViewItemV4& option) const;
+ virtual void renderLate(QPainter *painter,QStringList data,const QStyleOptionViewItemV4& option) const;
+
+ QPen hoverPen_;
+ QBrush hoverBrush_;
+ QPen selectPen_;
+ QBrush selectBrush_;
+ QPen nodePen_;
+ QPen nodeSelectPen_;
+ QPixmap errPix_;
+
+ QBrush lostConnectBgBrush_;
+ QBrush lostConnectBandBrush_;
+
+ QMap<QString,AttributeRendererProc> attrRenderers_;
+
+ PropertyMapper* prop_;
+ QFont font_;
+ QFont attrFont_;
+ int iconSize_;
+ int iconGap_;
+
+ bool useStateGrad_;
+ mutable QLinearGradient grad_;
+ static int lighter_;
+ QBrush eventFillBrush_;
+ QBrush eventBgBrush_;
+ QBrush meterFillBrush_;
+ QBrush meterThresholdBrush_;
+ QBrush limitFillBrush_;
+ QPixmap limitFillPix_;
+ QPixmap limitEmptyPix_;
+};
+
+#endif
+
+
+
diff --git a/Viewer/src/NodeWidget.cpp b/Viewer/src/NodeWidget.cpp
new file mode 100644
index 0000000..87a165d
--- /dev/null
+++ b/Viewer/src/NodeWidget.cpp
@@ -0,0 +1,164 @@
+/***************************** LICENSE START ***********************************
+
+ Copyright 2015 ECMWF and INPE. This software is distributed under the terms
+ of the Apache License version 2.0. In applying this license, ECMWF does not
+ waive the privileges and immunities granted to it by virtue of its status as
+ an Intergovernmental Organization or submit itself to any jurisdiction.
+
+ ***************************** LICENSE END *************************************/
+
+#include "NodeWidget.hpp"
+#include "NodeViewBase.hpp"
+
+#include "AbstractNodeModel.hpp"
+#include "InfoPanelHandler.hpp"
+#include "VFilter.hpp"
+#include "VModelData.hpp"
+
+#include <QAction>
+#include <QMenu>
+
+NodeWidget::NodeWidget(const std::string& type,ServerFilter* serverFilter,QWidget* parent) :
+ DashboardWidget(type,parent),
+ serverFilter_(serverFilter),
+ model_(0),
+ view_(0),
+ icons_(0),
+ atts_(0),
+ filterDef_(0),
+ states_(0)
+{
+ //Define the icon filter for the model. It controls what icons
+ //are displayed next to the nodes. This is exposed via a menu.
+ icons_=new IconFilter;
+
+ //Define the attribute filter for the model. It controls what attributes
+ //are displayed for a given node. This is exposed via a menu.
+ atts_=new AttributeFilter;
+
+ createActions();
+}
+
+NodeWidget::~NodeWidget()
+{
+ //We only need to delete the non-qobject members
+ delete icons_;
+ delete atts_;
+
+ if(filterDef_)
+ delete filterDef_;
+}
+
+QWidget* NodeWidget::widget()
+{
+ return view_->realWidget();
+}
+
+VInfo_ptr NodeWidget::currentSelection()
+{
+ return view_->currentSelection();
+}
+
+/*void NodeWidget::currentSelection(VInfo_ptr info)
+{
+ view_->currentSelection(info);
+}*/
+
+void NodeWidget::setCurrentSelection(VInfo_ptr info)
+{
+ view_->currentSelection(info);
+}
+
+void NodeWidget::reload()
+{
+ active(true);
+ //model_->reload();
+}
+
+void NodeWidget::active(bool b)
+{
+ model_->active(b);
+ view_->realWidget()->setEnabled(b);
+}
+
+bool NodeWidget::active() const
+{
+ return model_->active();
+}
+
+void NodeWidget::createActions()
+{
+ /*QAction* infoAc=new QAction(" ",this);
+ QPixmap pix(":/viewer/dock_info.svg");
+ infoAc->setIcon(QIcon(pix));
+ infoAc->setToolTip(tr("Start up information panel as dialog"));
+ dockActions_ << infoAc;
+ dockActionMap_["info"]=infoAc;
+
+ QMenu *menu=new QMenu(this);
+ infoAc->setMenu(menu);
+
+ for(std::vector<InfoPanelDef*>::const_iterator it=InfoPanelHandler::instance()->panels().begin();
+ it != InfoPanelHandler::instance()->panels().end(); it++)
+ {
+ if((*it)->show().find("toolbar") != std::string::npos)
+ {
+ QAction *ac=new QAction(QString::fromStdString((*it)->label()) + "...",this);
+ //QPixmap pix(":/viewer/" + QString::fromStdString((*it)->dockIcon()));
+ QPixmap pix(":/viewer/" + QString::fromStdString((*it)->icon()));
+ ac->setIcon(QIcon(pix));
+ ac->setData(QString::fromStdString((*it)->name()));
+ ac->setEnabled(false);
+
+ connect(ac,SIGNAL(triggered()),
+ this,SLOT(slotInfoPanelAction()));
+
+ infoPanelActions_ << ac;
+ }
+ }*/
+}
+
+void NodeWidget::slotInfoPanelAction()
+{
+ /*if(QAction* ac=static_cast<QAction*>(sender()))
+ {
+ Q_EMIT popInfoPanel(view_->currentSelection(),ac->data().toString());
+ }*/
+}
+
+void NodeWidget::updateActionState(VInfo_ptr info)
+{
+ /* std::vector<InfoPanelDef*> ids;
+ InfoPanelHandler::instance()->visible(info,ids);
+
+ QAction *infoAc=dockActionMap_["info"];
+ assert(infoAc);
+
+ QMenu* menu=infoAc->menu();
+ assert(menu);
+
+ menu->clear();
+
+ Q_FOREACH(QAction* ac,infoPanelActions_)
+ {
+ ac->setEnabled(false);
+
+ std::string name=ac->data().toString().toStdString();
+
+ for(std::vector<InfoPanelDef*>::const_iterator it=ids.begin(); it != ids.end(); it++)
+ {
+ if((*it)->name() == name)
+ {
+ ac->setEnabled(true);
+ menu->addAction(ac);
+ break;
+ }
+ }
+ }*/
+}
+
+
+
+
+
+
diff --git a/Viewer/src/NodeWidget.hpp b/Viewer/src/NodeWidget.hpp
new file mode 100644
index 0000000..dcd8ce5
--- /dev/null
+++ b/Viewer/src/NodeWidget.hpp
@@ -0,0 +1,83 @@
+/***************************** LICENSE START ***********************************
+
+ Copyright 2015 ECMWF and INPE. This software is distributed under the terms
+ of the Apache License version 2.0. In applying this license, ECMWF does not
+ waive the privileges and immunities granted to it by virtue of its status as
+ an Intergovernmental Organization or submit itself to any jurisdiction.
+
+ ***************************** LICENSE END *************************************/
+
+#ifndef NODEWIDGET_HPP_
+#define NODEWIDGET_HPP_
+
+#include <QString>
+#include <QWidget>
+
+#include "DashboardWidget.hpp"
+#include "Viewer.hpp"
+#include "VInfo.hpp"
+
+class QStackedLayout;
+class QWidget;
+
+class AbstractNodeModel;
+class AttributeFilter;
+class IconFilter;
+class NodeFilterDef;
+class NodeStateFilter;
+class VModelData;
+class NodePathWidget;
+class NodeViewBase;
+class ServerFilter;
+
+class NodeWidget : public DashboardWidget
+{
+Q_OBJECT
+
+public:
+ void active(bool);
+ bool active() const;
+ NodeViewBase* view() const {return view_;}
+ QWidget* widget();
+ VInfo_ptr currentSelection();
+ //void currentSelection(VInfo_ptr info);
+ void reload();
+ void populateDialog() {}
+ QList<QAction*> dockTitleActions() {return dockActions_;}
+
+public Q_SLOTS:
+ void setCurrentSelection(VInfo_ptr);
+
+protected Q_SLOTS:
+ void slotInfoPanelAction();
+
+Q_SIGNALS:
+ void selectionChanged(VInfo_ptr);
+ void popInfoPanel(VInfo_ptr,QString);
+ void dashboardCommand(VInfo_ptr,QString);
+
+protected:
+ explicit NodeWidget(const std::string& type,ServerFilter* serverFilter,QWidget* parent=0);
+ virtual ~NodeWidget();
+
+ void updateActionState(VInfo_ptr);
+
+ ServerFilter* serverFilter_;
+
+ AbstractNodeModel* model_;
+ NodeViewBase* view_;
+
+ IconFilter* icons_;
+ AttributeFilter* atts_;
+
+ NodeFilterDef* filterDef_;
+ NodeStateFilter *states_;
+
+private:
+ void createActions();
+ QList<QAction*> dockActions_;
+ QMap<QString,QAction*> dockActionMap_;
+ QList<QAction*> infoPanelActions_;
+};
+
+#endif
diff --git a/Viewer/src/OneLineTextEdit.cpp b/Viewer/src/OneLineTextEdit.cpp
new file mode 100644
index 0000000..195b0ac
--- /dev/null
+++ b/Viewer/src/OneLineTextEdit.cpp
@@ -0,0 +1,66 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "OneLineTextEdit.hpp"
+
+#include "Highlighter.hpp"
+
+#include <QApplication>
+#include <QDebug>
+#include <QStyle>
+#include <QStyleOptionFrameV3>
+
+OneLineTextEdit::OneLineTextEdit(QWidget* parent) : QTextEdit(parent)
+{
+ setReadOnly(true);
+ setWordWrapMode(QTextOption::NoWrap);
+ setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Fixed);
+
+ document()->setDocumentMargin(2);
+
+ QFont f;
+ QFontMetrics fm(f);
+
+ int h=fm.height()+fm.leading() + 1 +6;
+
+ setFixedHeight(h);
+
+ Highlighter* ih=new Highlighter(document(),"query");
+}
+
+QSize OneLineTextEdit::sizeHint() const
+{
+ return QTextEdit::sizeHint();
+ /*
+ QFontMetrics fm(font());
+ QStyleOptionFrameV3 opt;
+ QString text = document()->toHtml();
+
+ int h = qMax(fm.height(), 14) + 4;
+ int w = fm.width(text) + 4;
+
+ opt.initFrom(this);
+
+ return style()->sizeFromContents(
+ QStyle::CT_LineEdit,
+ &opt,
+ QSize(w, h).expandedTo(QApplication::globalStrut()),
+ this
+ );*/
+}
+
+void OneLineTextEdit::mousePressEvent(QMouseEvent *e)
+{
+ Q_EMIT clicked();
+}
+
+
diff --git a/Viewer/src/OneLineTextEdit.hpp b/Viewer/src/OneLineTextEdit.hpp
new file mode 100644
index 0000000..561cd96
--- /dev/null
+++ b/Viewer/src/OneLineTextEdit.hpp
@@ -0,0 +1,33 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VIEWER_SRC_ONELINETEXTEDIT_HPP_
+#define VIEWER_SRC_ONELINETEXTEDIT_HPP_
+
+#include <QTextEdit>
+
+class OneLineTextEdit : public QTextEdit
+{
+Q_OBJECT
+
+public:
+ OneLineTextEdit(QWidget* parent=0);
+ QSize sizeHint() const;
+
+Q_SIGNALS:
+ void clicked();
+
+protected:
+ void mousePressEvent(QMouseEvent *e);
+};
+
+
+
+#endif /* VIEWER_SRC_ONELINETEXTEDIT_HPP_ */
diff --git a/Viewer/src/OutputBrowser.cpp b/Viewer/src/OutputBrowser.cpp
new file mode 100644
index 0000000..244bd5c
--- /dev/null
+++ b/Viewer/src/OutputBrowser.cpp
@@ -0,0 +1,304 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "OutputBrowser.hpp"
+
+#include <QVBoxLayout>
+
+#include "Highlighter.hpp"
+#include "MessageLabel.hpp"
+#include "PlainTextEdit.hpp"
+#include "PlainTextSearchInterface.hpp"
+#include "TextEditSearchLine.hpp"
+#include "TextPager/TextPagerSearchInterface.hpp"
+#include "TextPagerWidget.hpp"
+
+int OutputBrowser::minPagerTextSize_=1*1024*1024;
+int OutputBrowser::minPagerSparseSize_=30*1024*1024;
+int OutputBrowser::minConfirmSearchSize_=5*1024*1024;
+
+OutputBrowser::OutputBrowser(QWidget* parent) :
+ QWidget(parent),
+ lastPos_(0)
+{
+ QVBoxLayout *vb=new QVBoxLayout(this);
+ vb->setContentsMargins(0,0,0,0);
+ vb->setSpacing(2);
+
+ stacked_=new QStackedWidget(this);
+ vb->addWidget(stacked_,1);
+
+ confirmSearchLabel_=new MessageLabel(this);
+ confirmSearchLabel_->setShowTypeTitle(false);
+ confirmSearchLabel_->setNarrowMode(true);
+ vb->addWidget(confirmSearchLabel_);
+
+ searchLine_=new TextEditSearchLine(this);
+ vb->addWidget(searchLine_);
+
+ //Basic textedit
+ textEdit_=new PlainTextEdit(this);
+ textEdit_->setReadOnly(true);
+ textEdit_->setWordWrapMode(QTextOption::NoWrap);
+
+ textEditSearchInterface_=new PlainTextSearchInterface();
+ textEditSearchInterface_->setEditor(textEdit_);
+
+ //This highlighter only works for jobs
+ jobHighlighter_=new Highlighter(textEdit_->document(),"job");
+ jobHighlighter_->setDocument(NULL);
+
+ //Pager for very large files
+ textPager_=new TextPagerWidget(this);
+ //textEdit_->setReadOnly(true);
+
+ textPagerSearchInterface_=new TextPagerSearchInterface();
+ textPagerSearchInterface_->setEditor(textPager_->textEditor());
+
+ stacked_->addWidget(textEdit_);
+ stacked_->addWidget(textPager_);
+
+ stacked_->setCurrentIndex(BasicIndex);
+ searchLine_->hide();
+
+ connect(searchLine_,SIGNAL(visibilityChanged()),
+ this,SLOT(showConfirmSearchLabel()));
+}
+
+OutputBrowser::~OutputBrowser()
+{
+ delete textEditSearchInterface_;
+ delete textPagerSearchInterface_;
+
+ if(jobHighlighter_ && !jobHighlighter_->parent())
+ {
+ delete jobHighlighter_;
+ }
+}
+
+void OutputBrowser::clear()
+{
+ if(stacked_->currentIndex() == BasicIndex)
+ cursorCache_[currentSourceFile_].pos_=textEdit_->textCursor().position();
+ else
+ cursorCache_[currentSourceFile_].pos_=textPager_->textEditor()->textCursor().position();
+
+ currentSourceFile_.clear();
+
+ textEdit_->clear();
+ textPager_->clear();
+ file_.reset();
+}
+
+void OutputBrowser::changeIndex(IndexType indexType,qint64 fileSize)
+{
+ if(indexType == BasicIndex)
+ {
+ stacked_->setCurrentIndex(indexType);
+ searchLine_->setConfirmSearch(false);
+ searchLine_->setSearchInterface(textEditSearchInterface_);
+ //confirmSearchLabel_->clear();
+ //confirmSearchLabel_->hide();
+
+ textPager_->clear();
+ }
+ else
+ {
+ stacked_->setCurrentIndex(indexType);
+ searchLine_->setConfirmSearch(fileSize >=minConfirmSearchSize_);
+ searchLine_->setSearchInterface(textPagerSearchInterface_);
+ //confirmSearchLabel_->show();
+ //confirmSearchLabel_->showWarning(searchLine_->confirmSearchText());
+ textEdit_->clear();
+ }
+
+ showConfirmSearchLabel();
+}
+
+void OutputBrowser::loadFile(VFile_ptr file)
+{
+ if(!file)
+ {
+ clear();
+ return;
+ }
+
+ file_=file;
+ if(file_->storageMode() == VFile::DiskStorage)
+ {
+ loadFile(QString::fromStdString(file_->path()));
+
+ //Set the cursor position from the cache
+ updateCursorFromCache(file_->sourcePath());
+ }
+ else
+ {
+ QString s(file_->data());
+ loadText(s,QString::fromStdString(file_->sourcePath()),true);
+ }
+}
+
+void OutputBrowser::loadFile(QString fileName)
+{
+ QFile file(fileName);
+ file.open(QIODevice::ReadOnly);
+ QFileInfo fInfo(file);
+ qint64 fSize=fInfo.size();
+
+ if(!isJobFile(fileName) && fSize >= minPagerTextSize_)
+ {
+ changeIndex(PagerIndex,fSize);
+
+ TextPagerDocument::DeviceMode mode=(fSize >= minPagerSparseSize_)?
+ TextPagerDocument::Sparse:TextPagerDocument::LoadAll;
+ textPager_->load(fileName, mode);
+ }
+ else
+ {
+ changeIndex(BasicIndex,fSize);
+
+ adjustHighlighter(fileName);
+
+ QString str=file.readAll();
+ textEdit_->document()->setPlainText(str);
+ }
+}
+
+void OutputBrowser::loadText(QString txt,QString fileName,bool resetFile)
+{
+ if(resetFile)
+ file_.reset();
+
+ //We estimate the size in bytes
+ qint64 txtSize=txt.size()*2;
+
+ if(!isJobFile(fileName) && txtSize > minPagerTextSize_)
+ {
+ changeIndex(PagerIndex,txtSize);
+ textPager_->setText(txt);
+ }
+ else
+ {
+ changeIndex(BasicIndex,txtSize);
+ adjustHighlighter(fileName);
+ textEdit_->document()->setPlainText(txt);
+ }
+
+ //Set the cursor position from the cache
+ updateCursorFromCache(fileName.toStdString());
+}
+
+void OutputBrowser::updateCursorFromCache(const std::string& sourcePath)
+{
+#if 0
+ //Set the cursor position from the cache
+ QMap<std::string,CursorCacheItem>::const_iterator it=cursorCache_.find(sourcePath);
+ if(it != cursorCache_.end())
+ {
+ setCursorPos(it.value().pos_);
+ }
+ currentSourceFile_=file_->sourcePath();
+#endif
+}
+
+bool OutputBrowser::isJobFile(QString fileName)
+{
+ return fileName.contains(".job");
+}
+
+void OutputBrowser::adjustHighlighter(QString fileName)
+{
+ //For job files we set the proper highlighter
+ if(isJobFile(fileName))
+ {
+ if(!jobHighlighter_)
+ {
+ jobHighlighter_=new Highlighter(textEdit_->document(),"job");
+ }
+ else if(jobHighlighter_->document() != textEdit_->document())
+ {
+ jobHighlighter_->setDocument(textEdit_->document());
+ }
+ }
+ else if(jobHighlighter_)
+ {
+ jobHighlighter_->setDocument(NULL);
+ }
+}
+
+void OutputBrowser::gotoLine()
+{
+ if(stacked_->currentIndex() == BasicIndex)
+ textEdit_->gotoLine();
+ else
+ textPager_->gotoLine();
+}
+
+void OutputBrowser::showSearchLine()
+{
+ searchLine_->setVisible(true);
+ searchLine_->setFocus();
+ searchLine_->selectAll();
+}
+
+void OutputBrowser::searchOnReload(bool userClickedReload)
+{
+ searchLine_->searchOnReload(userClickedReload);
+}
+
+void OutputBrowser::setFontProperty(VProperty* p)
+{
+ textEdit_->setFontProperty(p);
+ textPager_->setFontProperty(p);
+}
+
+void OutputBrowser::updateFont()
+{
+ textEdit_->updateFont();
+}
+
+void OutputBrowser::zoomIn()
+{
+ textEdit_->slotZoomIn();
+ textPager_->zoomIn();
+}
+
+void OutputBrowser::zoomOut()
+{
+ textEdit_->slotZoomOut();
+ textPager_->zoomOut();
+}
+
+void OutputBrowser::showConfirmSearchLabel()
+{
+ if(searchLine_->isVisible() && searchLine_->confirmSearch())
+ {
+ confirmSearchLabel_->showWarning(searchLine_->confirmSearchText());
+ //confirmSearchLabel_->show();
+ }
+ else
+ {
+ confirmSearchLabel_->hide();
+ }
+}
+
+void OutputBrowser::setCursorPos(qint64 pos)
+{
+ if(stacked_->currentIndex() == BasicIndex)
+ {
+ QTextCursor c=textEdit_->textCursor();
+ c.setPosition(pos);
+ textEdit_->setTextCursor(c);
+ }
+ else
+ {
+ textPager_->textEditor()->setCursorPosition(pos);
+ }
+}
diff --git a/Viewer/src/OutputBrowser.hpp b/Viewer/src/OutputBrowser.hpp
new file mode 100644
index 0000000..fb5612d
--- /dev/null
+++ b/Viewer/src/OutputBrowser.hpp
@@ -0,0 +1,95 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+#ifndef VIEWER_SRC_OUTPUTBROWSER_HPP_
+#define VIEWER_SRC_OUTPUTBROWSER_HPP_
+
+#include <QStackedWidget>
+#include <QMap>
+
+#include "VFile.hpp"
+
+class Highlighter;
+class MessageLabel;
+class TextEditSearchLine;
+class PlainTextEdit;
+class PlainTextSearchInterface;
+class TextPagerWidget;
+class TextPagerSearchInterface;
+class VProperty;
+
+class OutputBrowser;
+
+class CursorCacheItem
+{
+ friend class OutputBrowser;
+public:
+ CursorCacheItem() : pos_(0), verticalScrollValue_(0), viewportHeight_(0) {}
+protected:
+ int pos_;
+ int verticalScrollValue_;
+ int viewportHeight_;
+};
+
+
+class OutputBrowser : public QWidget
+{
+Q_OBJECT
+
+public:
+ explicit OutputBrowser(QWidget* parent);
+ ~OutputBrowser();
+
+ void clear();
+ void loadFile(VFile_ptr file);
+ void loadText(QString text,QString fileName,bool resetFile=true);
+ void adjustHighlighter(QString fileName);
+ void setFontProperty(VProperty* p);
+ void updateFont();
+ void gotoLine();
+ void showSearchLine();
+ void searchOnReload(bool userClickedReload);
+ void zoomIn();
+ void zoomOut();
+ void clearCursorCache() {cursorCache_.clear();}
+
+protected Q_SLOTS:
+ void showConfirmSearchLabel();
+
+private:
+ enum IndexType {BasicIndex=0,PagerIndex=1};
+ void changeIndex(IndexType indexType,qint64 fileSize);
+ bool isJobFile(QString fileName);
+ void loadFile(QString fileName);
+ void updateCursorFromCache(const std::string&);
+ void setCursorPos(qint64 pos);
+
+ QStackedWidget *stacked_;
+ PlainTextEdit* textEdit_;
+ TextPagerWidget* textPager_;
+ TextEditSearchLine* searchLine_;
+ Highlighter* jobHighlighter_;
+ PlainTextSearchInterface *textEditSearchInterface_;
+ TextPagerSearchInterface *textPagerSearchInterface_;
+ MessageLabel *confirmSearchLabel_;
+
+ //we keep a reference to it to make sure that it does not get deleted while
+ //it is being displayed
+ VFile_ptr file_;
+ int lastPos_;
+ std::string currentSourceFile_;
+
+ QMap<std::string,CursorCacheItem> cursorCache_;
+
+ static int minPagerTextSize_;
+ static int minPagerSparseSize_;
+ static int minConfirmSearchSize_;
+};
+
+#endif /* VIEWER_SRC_OUTPUTBROWSER_HPP_ */
diff --git a/Viewer/src/OutputCache.cpp b/Viewer/src/OutputCache.cpp
new file mode 100644
index 0000000..b6abbdd
--- /dev/null
+++ b/Viewer/src/OutputCache.cpp
@@ -0,0 +1,200 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "OutputCache.hpp"
+
+#include "UserMessage.hpp"
+
+OutputCache* OutputCache::instance_=NULL;
+
+#define _UI_OUTPUTCACHE_DEBUG
+
+OutputCacheItem::OutputCacheItem(const std::string& id, VFile_ptr file,QObject *parent) :
+ QTimer(parent), id_(id), file_(file), timeout_(120*1000), cnt_(0)
+{
+ attach();
+}
+
+bool OutputCacheItem::sameAs(VInfo_ptr info,const std::string& sourcePath)
+{
+ if(info && info->isNode() && info->server())
+ {
+ std::string id=info->path() + ":" + sourcePath;
+ return (id == id_);
+ }
+ return false;
+}
+
+void OutputCacheItem::attach()
+{
+ cnt_++;
+ stop();
+}
+
+void OutputCacheItem::detach()
+{
+ cnt_--;
+ if(cnt_<=0)
+ {
+ cnt_=0;
+ start(timeout_);
+ }
+}
+
+//========================================================
+//
+// OutputCache
+//
+//========================================================
+
+OutputCache::~OutputCache()
+{
+ clear();
+}
+
+OutputCache* OutputCache::instance()
+{
+ if(!instance_)
+ instance_= new OutputCache();
+
+ return instance_;
+}
+
+void OutputCache::clear()
+{
+ Q_FOREACH(OutputCacheItem* item,items_.values())
+ {
+ delete item;
+ }
+}
+
+OutputCacheItem* OutputCache::add(VInfo_ptr info,const std::string& sourcePath,VFile_ptr file)
+{
+ if(!file)
+ return NULL;
+
+#ifdef _UI_OUTPUTCACHE_DEBUG
+ UserMessage::debug("OutputCache::add --> file");
+ file->print();
+ print();
+#endif
+
+ if(info && file && info->isNode() && info->server())
+ {
+ std::string id=info->path() + ":" + sourcePath;
+ QMap<std::string, OutputCacheItem*>::iterator it = items_.find(id);
+ if(it != items_.end())
+ {
+ it.value()->attach();
+ it.value()->file_=file;
+ return it.value();
+ }
+ else
+ {
+ OutputCacheItem* item=new OutputCacheItem(id,file);
+ connect(item,SIGNAL(timeout()),
+ this,SLOT(removeItem()));
+
+ items_[id]=item;
+#ifdef _UI_OUTPUTCACHE_DEBUG
+ UserMessage::debug(" add item:" + id);
+ print();
+ UserMessage::debug("<-- OutputCache::add");
+#endif
+ return item;
+ }
+ }
+#ifdef _UI_OUTPUTCACHE_DEBUG
+ UserMessage::debug("<-- OutputCache::add");
+#endif
+
+ return NULL;
+}
+
+void OutputCache::detach(OutputCacheItem* item)
+{
+ if(item)
+ {
+#ifdef _UI_OUTPUTCACHE_DEBUG
+ UserMessage::debug("OutputCache::detach -->");
+ print();
+ UserMessage::debug(" detach item: " + item->id_);
+ item->detach();
+ print();
+ UserMessage::debug("<-- OutputCache::detach");
+#endif
+ }
+}
+
+void OutputCache::removeItem()
+{
+ if(OutputCacheItem* item=static_cast<OutputCacheItem*>(sender()))
+ {
+#ifdef _UI_OUTPUTCACHE_DEBUG
+ UserMessage::debug("OutputCache::removeItem --> file");
+ item->file_->print();
+ print();
+#endif
+ QMap<std::string, OutputCacheItem*>::iterator it = items_.begin();
+ while (it != items_.end() )
+ {
+ if(it.value() == item)
+ {
+#ifdef _UI_OUTPUTCACHE_DEBUG
+ UserMessage::debug(" remove item --> ref_count:" +
+ QString::number(it.value()->file_.use_count()).toStdString() +
+ " item:" + it.key());
+#endif
+ //assert(item->file_.use_count() == 1);
+ //The ref count is not necessarily 1 here
+ items_.erase(it);
+ item->deleteLater();
+#ifdef _UI_OUTPUTCACHE_DEBUG
+ print();
+ UserMessage::debug("<-- OutputCache::removeItem");
+#endif
+ return;
+ }
+
+ ++it;
+ }
+ }
+}
+
+OutputCacheItem* OutputCache::use(VInfo_ptr info,const std::string& sourcePath)
+{
+ if(info && info->isNode() && info->server())
+ {
+ std::string id=info->path() + ":" + sourcePath;
+ QMap<std::string, OutputCacheItem*>::iterator it = items_.find(id);
+ if(it != items_.end())
+ {
+ it.value()->attach();
+ return it.value();
+
+ }
+ }
+
+ return NULL;
+}
+
+void OutputCache::print()
+{
+ UserMessage::debug(" OutputCache contents -->");
+ QMap<std::string, OutputCacheItem*>::iterator it = items_.begin();
+ while (it != items_.end() )
+ {
+ UserMessage::debug(" item:" + it.key() + " tmp:" +
+ it.value()->file_->path() + " countdown:" +
+ ((it.value()->isActive())?"on":"off"));
+ ++it;
+ }
+ UserMessage::debug(" <-- OutputCache contents");
+}
diff --git a/Viewer/src/OutputCache.hpp b/Viewer/src/OutputCache.hpp
new file mode 100644
index 0000000..8f3028b
--- /dev/null
+++ b/Viewer/src/OutputCache.hpp
@@ -0,0 +1,73 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef OUTPUTCHACHE_HPP_
+#define OUTPUTCHACHE_HPP_
+
+#include <QMap>
+#include <QTimer>
+
+#include "OutputClient.hpp"
+#include "VFile.hpp"
+#include "VInfo.hpp"
+
+class OutputCache;
+
+struct OutputCacheItem : public QTimer
+{
+ friend class OutputCache;
+
+public:
+ OutputCacheItem(const std::string& id,VFile_ptr file,QObject *parent=0);
+ VFile_ptr file() const {return file_;}
+ bool sameAs(VInfo_ptr info,const std::string& sourcePath);
+
+protected:
+ void attach();
+ void detach();
+ void keepIt();
+
+ std::string id_;
+ VFile_ptr file_;
+ int timeout_;
+ int cnt_;
+};
+
+class OutputCache: public QObject
+{
+ Q_OBJECT
+
+public:
+ OutputCacheItem* add(VInfo_ptr info,const std::string& sourcePath,VFile_ptr file);
+ void detach(OutputCacheItem*);
+ OutputCacheItem* use(VInfo_ptr info,const std::string& sourcePath);
+
+ void print();
+ static OutputCache* instance();
+ void clear();
+
+protected Q_SLOTS:
+ void removeItem();
+
+protected:
+ OutputCache() {}
+ ~OutputCache();
+
+private:
+ OutputCache(const OutputClient&);
+ OutputCache& operator=(const OutputCache&);
+
+ static OutputCache* instance_;
+ QMap<std::string,OutputCacheItem*> items_;
+
+};
+
+#endif // OUTPUTCHACHE_HPP
+
diff --git a/Viewer/src/OutputClient.cpp b/Viewer/src/OutputClient.cpp
new file mode 100644
index 0000000..b9672fc
--- /dev/null
+++ b/Viewer/src/OutputClient.cpp
@@ -0,0 +1,63 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "OutputClient.hpp"
+
+#include <QTimer>
+
+OutputClient::OutputClient(const std::string& host,const std::string& portStr,QObject* parent) :
+ QObject(parent),
+ soc_(NULL),
+ host_(host),
+ portStr_(portStr),
+ port_(19999),
+ timeout_(3000)
+{
+ if(!portStr_.empty())
+ port_=atoi(portStr.c_str());
+
+ soc_=new QTcpSocket(0);
+ connect(soc_,SIGNAL(readyRead()),
+ this, SLOT(slotRead()));
+
+ connect(soc_,SIGNAL(error(QAbstractSocket::SocketError)),
+ this,SLOT(slotError(QAbstractSocket::SocketError)));
+
+ connect(soc_,SIGNAL(connected()),
+ this, SLOT(slotConnected()));
+
+ if(char* timeoutStr = getenv ("ECFLOWVIEW_LOGTIMEOUT"))
+ timeout_ = atoi(timeoutStr)*1000;
+}
+
+OutputClient::~OutputClient()
+{
+ soc_->abort();
+}
+
+
+void OutputClient::connectToHost(std::string host,int port)
+{
+ stopper_.start();
+ soc_->abort();
+ soc_->connectToHost(QString::fromStdString(host),port);
+
+ //We cannot change the temout through the qt api so we need this hack.
+ QTimer::singleShot(timeout_, this, SLOT(slotCheckTimeout()));
+}
+
+void OutputClient::slotCheckTimeout()
+{
+ if(soc_->state() == QAbstractSocket::HostLookupState ||
+ soc_->state() == QAbstractSocket::ConnectingState)
+ {
+ soc_->abort();
+ Q_EMIT error("Timeout error");
+ }
+}
diff --git a/Viewer/src/OutputClient.hpp b/Viewer/src/OutputClient.hpp
new file mode 100644
index 0000000..0e22605
--- /dev/null
+++ b/Viewer/src/OutputClient.hpp
@@ -0,0 +1,63 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VIEWER_SRC_OUTPUTCLIENT_HPP_
+#define VIEWER_SRC_OUTPUTCLIENT_HPP_
+
+#include <QObject>
+#include <QTcpSocket>
+#include <QTime>
+
+class QTcpSocket;
+
+class OutputClient : public QObject
+{
+ Q_OBJECT
+
+public:
+ OutputClient(const std::string& host,const std::string& port,QObject *parent);
+ ~OutputClient();
+
+ const std::string& host() const {return host_;}
+ int port() const {return port_;}
+ const std::string& portStr() const {return portStr_;}
+
+ const std::string& remoteFile() const {return remoteFile_;}
+ bool ok() const { return soc_ != NULL; }
+
+protected Q_SLOTS:
+ virtual void slotError(QAbstractSocket::SocketError err)=0;
+ virtual void slotRead()=0;
+ virtual void slotConnected()=0;
+ void slotCheckTimeout();
+
+Q_SIGNALS:
+ void error(QString);
+ void progress(QString,int);
+ void finished();
+
+protected:
+ void connectToHost(std::string,int);
+
+ QTcpSocket* soc_;
+ std::string host_;
+ std::string portStr_;
+ int port_;
+ int timeout_;
+ std::string remoteFile_;
+ QTime stopper_;
+
+private:
+ OutputClient(const OutputClient&);
+ OutputClient& operator=(const OutputClient&);
+};
+
+
+#endif /* VIEWER_SRC_OUTPUTCLIENT_HPP_ */
diff --git a/Viewer/src/OutputDirClient.cpp b/Viewer/src/OutputDirClient.cpp
new file mode 100644
index 0000000..dddfd57
--- /dev/null
+++ b/Viewer/src/OutputDirClient.cpp
@@ -0,0 +1,173 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "OutputDirClient.hpp"
+
+#include <QDebug>
+
+#include "UserMessage.hpp"
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+
+#define _UI_OUTPUTDIRCLIENT_DEBUG
+
+OutputDirClient::OutputDirClient(const std::string& host,const std::string& portStr,QObject* parent) :
+ OutputClient(host,portStr,parent)
+{
+}
+
+VDir_ptr OutputDirClient::result() const
+{
+ return dir_;
+}
+
+void OutputDirClient::slotCheckTimeout()
+{
+ if(soc_->state() == QAbstractSocket::HostLookupState ||
+ soc_->state() == QAbstractSocket::ConnectingState)
+ {
+ soc_->abort();
+ if(dir_)
+ dir_.reset();
+
+ Q_EMIT error("Timeout error");
+ }
+}
+
+void OutputDirClient::slotConnected()
+{
+ UserMessage::message(UserMessage::DBG,false,"OutputDirClient::slotConnected() connected to " +
+ soc_->peerName().toStdString());
+
+ soc_->write("list ",5);
+ soc_->write(remoteFile_.c_str(),remoteFile_.size());
+ soc_->write("\n",1);
+}
+
+void OutputDirClient::slotError(QAbstractSocket::SocketError err)
+{
+#ifdef _UI_OUTPUTDIRCLIENT_DEBUG
+ UserMessage::debug("OutputDirClient::slotError --> " + soc_->errorString().toStdString());
+#endif
+ switch(err)
+ {
+ //The logserver does not notify us if the file trasfer finish. We simply get this error.
+ case QAbstractSocket::RemoteHostClosedError:
+
+#ifdef _UI_OUTPUTDIRCLIENT_DEBUG
+ UserMessage::debug(" RemoteHostClosedError ");
+#endif
+ //qDebug() << "remote host closed";
+ //If no data was transferred we think it is a real error.
+ if(data_.isEmpty())
+ {
+#ifdef _UI_OUTPUTDIRCLIENT_DEBUG
+ UserMessage::debug(" --> data is empty: file transfer failed");
+#endif
+ break;
+ }
+ //If there is some data we think the transfer succeeded.
+ else
+ {
+#ifdef _UI_OUTPUTDIRCLIENT_DEBUG
+ UserMessage::debug(" --> has data: file transfer succeeded");
+#endif
+ if(dir_)
+ {
+ parseData();
+ }
+
+ Q_EMIT finished();
+
+ if(dir_)
+ dir_.reset();
+
+ return;
+ }
+
+ break;
+ case QAbstractSocket::UnknownSocketError:
+ if(soc_->state() != QAbstractSocket::ConnectedState)
+ {
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ soc_->abort();
+ if(dir_)
+ {
+ dir_.reset();
+ }
+ Q_EMIT error(soc_->errorString());
+}
+
+void OutputDirClient::getDir(const std::string& name)
+{
+ connectToHost(host_,port_);
+
+ boost::filesystem::path fp(name);
+ std::string dirName=fp.parent_path().string();
+
+ remoteFile_=name;
+ dir_.reset();
+ dir_=VDir_ptr(new VDir(dirName));
+ data_.clear();
+
+ //indicates the source of the files
+ dir_->where(host_ + "@" + portStr_);
+}
+
+void OutputDirClient::slotRead()
+{
+ const qint64 size = 64*1024;
+ char buf[size+1];
+ quint64 len = 0;
+
+ while((len = soc_->read(buf,size)) > 0)
+ {
+ data_.append(buf,len);
+ }
+}
+
+void OutputDirClient::parseData()
+{
+ if(!dir_)
+ return;
+
+ QTextStream in(data_);
+ while(!in.atEnd())
+ {
+ int mode,uid,gid;
+ unsigned int size;
+ unsigned int atime,mtime,ctime;
+ QString name;
+
+ in >> mode >> uid >> gid >> size >> atime >> mtime >> ctime >> name;
+
+ if(!name.isEmpty())
+ {
+ boost::filesystem::path p(name.toStdString());
+ std::string fileDirName=p.parent_path().string();
+ std::string fileName=p.leaf().string();
+
+ //Adjust the path in the dir
+ if(dir_->path() != fileDirName)
+ {
+ dir_->path(fileDirName,false);
+ }
+
+ dir_->addItem(fileName,size,mtime);
+ }
+ }
+}
diff --git a/Viewer/src/OutputDirClient.hpp b/Viewer/src/OutputDirClient.hpp
new file mode 100644
index 0000000..53af825
--- /dev/null
+++ b/Viewer/src/OutputDirClient.hpp
@@ -0,0 +1,46 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VIEWER_SRC_OUTPUTDIRCLIENT_HPP_
+#define VIEWER_SRC_OUTPUTDIRCLIENT_HPP_
+
+#include "OutputClient.hpp"
+#include "VDir.hpp"
+
+#include <QByteArray>
+
+class OutputDirClient : public OutputClient
+{
+ Q_OBJECT
+
+public:
+ OutputDirClient(const std::string& host,const std::string& port,QObject *parent);
+
+ VDir_ptr result() const;
+ void getDir(const std::string& name);
+
+protected Q_SLOTS:
+ void slotError(QAbstractSocket::SocketError err);
+ void slotRead();
+ void slotConnected();
+ void slotCheckTimeout();
+
+private:
+ OutputDirClient(const OutputDirClient&);
+ OutputDirClient& operator=(const OutputDirClient&);
+
+ void parseData();
+
+ VDir_ptr dir_;
+ QByteArray data_;
+};
+
+
+#endif /* VIEWER_SRC_OUTPUTDIRCLIENT_HPP_ */
diff --git a/Viewer/src/OutputDirProvider.cpp b/Viewer/src/OutputDirProvider.cpp
new file mode 100644
index 0000000..28c899a
--- /dev/null
+++ b/Viewer/src/OutputDirProvider.cpp
@@ -0,0 +1,273 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "OutputDirProvider.hpp"
+
+#include "LogServer.hpp"
+#include "OutputDirClient.hpp"
+#include "VNode.hpp"
+#include "VReply.hpp"
+#include "ServerHandler.hpp"
+#include "UserMessage.hpp"
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/algorithm/string/predicate.hpp>
+
+OutputDirProvider::OutputDirProvider(InfoPresenter* owner) :
+ InfoProvider(owner,VTask::NoTask),
+ outClient_(NULL)
+{
+}
+
+void OutputDirProvider::clear()
+{
+ if(outClient_)
+ {
+ delete outClient_;
+ outClient_=NULL;
+ }
+ InfoProvider::clear();
+}
+
+//Node
+void OutputDirProvider::visit(VInfoNode* info)
+{
+ //Reset the reply
+ reply_->reset();
+
+ if(!info)
+ {
+ owner_->infoFailed(reply_);
+ }
+
+ ServerHandler* server=info_->server();
+ VNode *n=info->node();
+
+ if(!n || !n->node())
+ {
+ owner_->infoFailed(reply_);
+ }
+
+ fetchDir(server,n);
+}
+
+void OutputDirProvider::fetchDir(ServerHandler* server,VNode* n)
+{
+ VDir_ptr dir;
+
+ if(!info_ || !info_->isNode() || !info_->node() || !info_->node()->node())
+ {
+ reply_->setDirectory(dir);
+ owner_->infoFailed(reply_);
+ }
+
+ //Get the jobout name
+ std::string fileName=n->findVariable("ECF_JOBOUT",true);
+
+ //Check if it is tryno 0
+ //bool tynozero=(boost::algorithm::ends_with(fileName,".0"));
+
+ //Jobout is empty: no dir path is availabale
+ if(fileName.empty())
+ {
+ reply_->setDirectory(dir);
+ owner_->infoFailed(reply_);
+
+ return;
+ }
+
+ //----------------------------------
+ // The host is the localhost
+ //----------------------------------
+#if 0
+ //if(server->isLocalHost())
+ //{
+ if(server->readFromDisk())
+ {
+ dir=fetchLocalDir(fileName,tynozero);
+ if(dir)
+ {
+ reply_->setDirectory(dir);
+ owner_->infoReady(reply_);
+ return;
+ }
+ }
+ // }
+#endif
+ //----------------------------------------------------
+ // Not the localhost or we could not read dir
+ //----------------------------------------------------
+
+ //We try the output client, its asynchronous!
+ if(fetchDirViaOutputClient(n,fileName))
+ {
+ //If we are here we created a output client and asked to the fetch the
+ //file asynchronously. The ouput client will call slotOutputClientFinished() or
+ //slotOutputClientError eventually!!
+ return;
+ }
+
+ //If there is no output client and it is not the localhost we try
+ //to read it again from the disk!!!
+
+ dir=fetchLocalDir(fileName);
+ if(dir)
+ {
+ reply_->setDirectory(dir);
+ owner_->infoReady(reply_);
+ return;
+ }
+
+ //If we are we coud not get the file
+ reply_->setDirectory(dir);
+ owner_->infoFailed(reply_);
+}
+
+bool OutputDirProvider::fetchDirViaOutputClient(VNode *n,const std::string& fileName)
+{
+ std::string host, port;
+ if(n->logServer(host,port))
+ {
+ //host=host + "baaad";
+
+ //reply_->setInfoText("Getting file through log server: " + host + "@" + port);
+ //owner_->infoProgress(reply_);
+
+ outClient_=makeOutputClient(host,port);
+ outClient_->getDir(fileName);
+
+ return true;
+ }
+
+ return false;
+}
+
+void OutputDirProvider::slotOutputClientFinished()
+{
+ VDir_ptr dir = outClient_->result();
+
+ if(dir && dir.get())
+ {
+ reply_->setInfoText("");
+ //reply_->fileReadMode(VReply::LogServerReadMode);
+
+ //std::string method="served by " + outClient_->host() + "@" + outClient_->portStr();
+ //reply_->fileReadMethod(method);
+
+ reply_->setDirectory(dir);
+ owner_->infoReady(reply_);
+ }
+}
+
+void OutputDirProvider::slotOutputClientProgress(QString,int)
+{
+ /*reply_->setInfoText(msg.toStdString());
+ owner_->infoProgress(reply_);
+ reply_->setInfoText("");*/
+}
+
+void OutputDirProvider::slotOutputClientError(QString msg)
+{
+ if(info_ && info_.get())
+ {
+ if(ServerHandler* server=info_->server())
+ {
+ if(outClient_)
+ {
+ //Check if it is tryno 0
+ //bool tynozero=(boost::algorithm::ends_with(outClient_->remoteFile(),".0"));
+ VDir_ptr dir=fetchLocalDir(outClient_->remoteFile()); //,tynozero);
+ if(dir)
+ {
+ reply_->setDirectory(dir);
+ owner_->infoReady(reply_);
+ return;
+ }
+ }
+ }
+
+ reply_->setErrorText(msg.toStdString());
+ owner_->infoFailed(reply_);
+ }
+}
+
+VDir_ptr OutputDirProvider::fetchLocalDir(const std::string& path) //,bool trynozero)
+{
+ VDir_ptr res;
+
+ boost::filesystem::path p(path);
+
+ try {
+ //Is it a directory?
+ if(boost::filesystem::is_directory(p))
+ {
+ return res;
+ }
+ //It must be a file
+ //if((trynozero || boost::filesystem::exists(p)) &&
+ if(boost::filesystem::exists(p.parent_path()))
+ {
+ std::string dirName=p.parent_path().string();
+ //std::string fileName=p.leaf().string();
+
+ if(info_ && info_->isNode() && info_->node())
+ {
+ std::string nodeName=info_->node()->strName();
+ std::string pattern=nodeName+".";
+ res=VDir_ptr(new VDir(dirName,pattern));
+ return res;
+ }
+ }
+
+ }
+ catch (const boost::filesystem::filesystem_error& e)
+ {
+ UserMessage::message(UserMessage::WARN,false,"fetchLocalDir failed:" + std::string(e.what()));
+ return res;
+ }
+
+
+ return res;
+}
+
+OutputDirClient* OutputDirProvider::makeOutputClient(const std::string& host,const std::string& port)
+{
+ if(outClient_)
+ {
+ if(outClient_->host() != host || outClient_->portStr() != port)
+ {
+ delete outClient_;
+ outClient_=0;
+ }
+ }
+
+ if(!outClient_)
+ {
+ outClient_=new OutputDirClient(host,port,this);
+
+ connect(outClient_,SIGNAL(error(QString)),
+ this,SLOT(slotOutputClientError(QString)));
+
+ connect(outClient_,SIGNAL(progress(QString,int)),
+ this,SLOT(slotOutputClientProgress(QString,int)));
+
+ connect(outClient_,SIGNAL(finished()),
+ this,SLOT(slotOutputClientFinished()));
+ }
+
+ return outClient_;
+
+
+}
+
+
+
+
diff --git a/Viewer/src/OutputDirProvider.hpp b/Viewer/src/OutputDirProvider.hpp
new file mode 100644
index 0000000..1ca4b14
--- /dev/null
+++ b/Viewer/src/OutputDirProvider.hpp
@@ -0,0 +1,49 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VIEWER_SRC_OUTPUTDIRPROVIDER_HPP_
+#define VIEWER_SRC_OUTPUTDIRPROVIDER_HPP_
+
+#include <QObject>
+
+#include "VDir.hpp"
+#include "VInfo.hpp"
+#include "InfoProvider.hpp"
+#include "VTask.hpp"
+#include "VTaskObserver.hpp"
+
+class OutputDirClient;
+
+class OutputDirProvider : public QObject, public InfoProvider
+{
+Q_OBJECT
+
+public:
+ explicit OutputDirProvider(InfoPresenter* owner);
+
+ void visit(VInfoNode*);
+ void clear();
+
+private Q_SLOTS:
+ void slotOutputClientError(QString);
+ void slotOutputClientProgress(QString,int);
+ void slotOutputClientFinished();
+
+private:
+ void fetchDir(ServerHandler*,VNode*);
+ bool fetchDirViaOutputClient(VNode *n,const std::string& fileName);
+ VDir_ptr fetchLocalDir(const std::string& path);
+ OutputDirClient* makeOutputClient(const std::string& host,const std::string& port);
+
+ OutputDirClient *outClient_;
+};
+
+
+#endif /* VIEWER_SRC_OUTPUTDIRPROVIDER_HPP_ */
diff --git a/Viewer/src/OutputFetchInfo.cpp b/Viewer/src/OutputFetchInfo.cpp
new file mode 100644
index 0000000..e023a50
--- /dev/null
+++ b/Viewer/src/OutputFetchInfo.cpp
@@ -0,0 +1,192 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "OutputFetchInfo.hpp"
+
+#include <QLabel>
+#include <QTextEdit>
+#include <QVBoxLayout>
+#include <QString>
+#include <QFile>
+
+#include <QDebug>
+
+#include "ServerHandler.hpp"
+
+OutputFetchInfo::OutputFetchInfo(QWidget* parent) : QWidget(parent)
+{
+ QVBoxLayout *vb=new QVBoxLayout(this);
+ label_=new QLabel(this);
+ label_->setText("<b>Additional information</b>");
+
+ te_=new QTextEdit(this);
+ te_->setReadOnly(true);
+ te_->setMinimumWidth(350);
+
+ vb->addWidget(label_);
+ vb->addWidget(te_,1);
+}
+
+void OutputFetchInfo::setInfo(VReply *reply,VInfo_ptr info)
+{
+ Q_ASSERT(reply);
+
+ te_->clear();
+
+ static QMap<int,QString> nums;
+ if(nums.isEmpty())
+ {
+ nums[1]="1st";
+ nums[2]="2nd";
+ nums[3]="3rd";
+ nums[4]="4th";
+ }
+
+ QStringList options;
+ QStringList remarks;
+ QStringList msg;
+ QStringList tries;
+ QStringList other;
+ QString alg;
+
+ QString html;
+
+ int cnt=1;
+ for(std::vector<std::string>::const_iterator it=reply->log().begin(); it != reply->log().end(); ++it)
+ {
+ QString s=QString::fromStdString(*it);
+ if(s.startsWith("REMARK>"))
+ {
+ remarks << s.remove(0,7);
+ continue;
+ }
+ else if(s.startsWith("OPTION>"))
+ {
+ options << s.remove(0,7);
+ continue;
+ }
+ else if(s.startsWith("MSG>"))
+ {
+ msg << s.remove(0,4);
+ continue;
+ }
+ else if(s.startsWith("TRY>"))
+ {
+ s.remove(0,4);
+ s.prepend("tried to ");
+ s.replace(" OK","<font color=\'#269e00\'><b> SUCCEEDED</b></font>");
+ s.replace(" FAILED","<font color=\'#FF0000\'><b> FAILED</b></font>");
+ s.replace(" NO ACCESS","<font><b> NO ACCESS</b></font>");
+ s.replace(" NOT DEFINED","<font><b> NOT DEFINED</b></font>");
+ tries << s;
+ cnt++;
+ continue;
+ }
+ else
+ other << s;
+ }
+
+ if(info && info->server())
+ {
+ ServerHandler* server=info->server();
+ bool rfd=server->readFromDisk();
+ QString t;
+
+ t="The following are tried in order:<ul>";
+
+ if(rfd)
+ {
+ t+="<li>Try to read the output files from the logserver \
+ (if defined)</li><li>from disk</li><li>\
+ through the ecflow server (if <b>not</b> the <b>current</b> job output) </li>";
+ }
+ else
+ {
+ t+="<li>Try to read the output files from the logserver \
+ (if defined)</li><li>from disk (if <b>not</b> the <b>current</b> job output)</li>\
+ <li>from the ecflow server (if the <b>current</b> job output)</li> ";
+ }
+ t+="</ul> (To change this behaviour go Edit -> Preferences -> Server options -> Files)";
+
+ alg=t;
+
+ if(reply->tmpFile() && reply->fileReadMode() == VReply::LocalReadMode &&
+ !server->isLocalHost())
+ {
+ remarks << "The output file was read <b>from disk</b> but the server's \
+ host (" + QString::fromStdString(server->host()) +
+ ") is not running on the local machine. If the path is machine-specific (e.g. /tmp) \
+ and there exists a file with the same path on the local machine, then\
+ this will have been read instead.";
+ }
+ }
+
+ if(!msg.isEmpty())
+ {
+ html+="<p><u>Messages</u></p>";
+ html+=buildList(msg);
+ }
+
+ if(!options.isEmpty())
+ {
+ html+="<p><u>Options</u></p>";
+ html+=buildList(options);
+ }
+
+ if(!tries.isEmpty())
+ {
+ html+="<p><u>How was this file fetched?</u></p>";
+ html+=buildList(tries,true);
+ }
+
+ if(!alg.isEmpty())
+ {
+ html+="<p><u>Algorithm:</u></p>"+alg;
+ }
+
+ if(!remarks.isEmpty())
+ {
+ html+="<p><u>Remarks</u></p>";
+ html+=buildList(remarks);
+ }
+
+ if(!other.isEmpty())
+ {
+ html+=buildList(other);
+
+ }
+
+ te_->setHtml(html);
+
+ QTextCursor cursor=te_->textCursor();
+ cursor.movePosition(QTextCursor::Start);
+ te_->setTextCursor(cursor);
+}
+
+QString OutputFetchInfo::buildList(QStringList lst,bool ordered)
+{
+ QString t;
+
+ if(lst.count() > 0)
+ {
+ t+=(ordered)?"<ol>":"<ul>";
+ Q_FOREACH(QString s,lst)
+ {
+ t+="<li>" + s + "</li>";
+ }
+ t+=(ordered)?"</ol>":"</ul>";
+ }
+
+ return t;
+}
+
+void OutputFetchInfo::clearInfo()
+{
+ te_->clear();
+}
diff --git a/Viewer/src/OutputFetchInfo.hpp b/Viewer/src/OutputFetchInfo.hpp
new file mode 100644
index 0000000..16885c7
--- /dev/null
+++ b/Viewer/src/OutputFetchInfo.hpp
@@ -0,0 +1,36 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+#ifndef OUTPUTFETCHINFO_HPP
+#define OUTPUTFETCHINFO_HPP
+
+#include <QWidget>
+
+#include "VInfo.hpp"
+#include "VReply.hpp"
+
+class QLabel;
+class QTextEdit;
+
+class OutputFetchInfo : public QWidget
+{
+public:
+ OutputFetchInfo(QWidget* parent=0);
+ void setInfo(VReply*,VInfo_ptr);
+ void clearInfo();
+
+private:
+ QString buildList(QStringList,bool ordered=false);
+
+ QLabel* label_;
+ QTextEdit* te_;
+
+};
+
+#endif // OUTPUTFETCHINFO_HPP
+
diff --git a/Viewer/src/OutputFileClient.cpp b/Viewer/src/OutputFileClient.cpp
new file mode 100644
index 0000000..9f51735
--- /dev/null
+++ b/Viewer/src/OutputFileClient.cpp
@@ -0,0 +1,198 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "OutputFileClient.hpp"
+
+#include "UserMessage.hpp"
+
+//#define _UI_OUTPUTFILECLIENT_DEBUG
+
+OutputFileClient::OutputFileClient(const std::string& host,const std::string& portStr,QObject* parent) :
+ OutputClient(host,portStr,parent),
+ total_(0),
+ expected_(0),
+ lastProgress_(0),
+ progressChunk_(1024*1024),
+ progressUnits_("MB")
+{
+}
+
+void OutputFileClient::clearResult()
+{
+ if(out_)
+ {
+ out_->close();
+ out_.reset();
+ }
+}
+
+void OutputFileClient::slotConnected()
+{
+ //Q_EMIT progress("",0);
+
+ soc_->write("get ",4);
+ soc_->write(remoteFile_.c_str(),remoteFile_.size());
+ soc_->write("\n",1);
+}
+
+void OutputFileClient::slotError(QAbstractSocket::SocketError err)
+{
+ switch(err)
+ {
+ case QAbstractSocket::RemoteHostClosedError:
+
+ soc_->abort();
+
+ if(total_ == 0)
+ {
+ out_.reset();
+ Q_EMIT error(soc_->errorString());
+ }
+ else
+ {
+ if(out_)
+ {
+ out_->setTransferDuration(stopper_.elapsed());
+ out_->setFetchDate(QDateTime::currentDateTime());
+ out_->close();
+ }
+
+ Q_EMIT finished();
+
+ if(out_)
+ out_.reset();
+
+ return;
+
+ }
+ break;
+ case QAbstractSocket::UnknownSocketError:
+ if(soc_->state() != QAbstractSocket::ConnectedState)
+ {
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ soc_->abort();
+ if(out_)
+ {
+ out_->close();
+ out_.reset();
+ }
+ Q_EMIT error(soc_->errorString());
+
+}
+
+void OutputFileClient::getFile(const std::string& name)
+{
+ connectToHost(host_,port_);
+
+ remoteFile_=name;
+ out_.reset();
+ out_=VFile_ptr(VFile::create(true)); //we will delete the file from disk
+ out_->setSourcePath(name);
+ total_=0;
+ lastProgress_=0;
+ estimateExpectedSize();
+}
+
+void OutputFileClient::slotRead()
+{
+ const qint64 size = 64*1024;
+ char buf[size];
+ quint64 len = 0;
+
+ while((len = soc_->read(buf,size)) > 0)
+ {
+ std::string err;
+ if(!out_->write(buf,len,err))
+ {
+ soc_->abort();
+ Q_EMIT error("write failed");
+ }
+ total_ += len;
+
+ if(total_/progressChunk_ > lastProgress_)
+ {
+ lastProgress_=total_/progressChunk_;
+
+ int prog=0;
+ if(expected_ > 0)
+ {
+ prog=static_cast<int>(100.*static_cast<float>(total_)/static_cast<float>(expected_));
+ if(prog>100) prog=100;
+ Q_EMIT progress(QString::number(lastProgress_) + "/" + QString::number(expected_/progressChunk_) +
+ " " + progressUnits_ + " transferred",prog);
+ }
+ else
+ Q_EMIT progress(QString::number(lastProgress_) + " " + progressUnits_ + " transferred",prog);
+ }
+ }
+}
+
+VFile_ptr OutputFileClient::result() const
+{
+ return out_;
+}
+
+void OutputFileClient::setExpectedSize(qint64 v)
+{
+ expected_=v;
+}
+
+int OutputFileClient::maxProgress() const
+{
+ return expected_/progressChunk_;
+}
+
+void OutputFileClient::setDir(VDir_ptr dir)
+{
+ if(dir != dir_)
+ {
+ dir_=dir;
+ if(expected_ == 0)
+ estimateExpectedSize();
+ }
+}
+
+void OutputFileClient::estimateExpectedSize()
+{
+ if(!dir_)
+ {
+ expected_=0;
+ return;
+ }
+
+#ifdef _UI_OUTPUTFILECLIENT_DEBUG
+ UserMessage::debug("OutputFileClient::estimateExpectedSize -->");
+#endif
+ for(unsigned int i=0; i < dir_->count(); i++)
+ {
+#ifdef _UI_OUTPUTFILECLIENT_DEBUG
+ UserMessage::debug("file: " + dir_->fullName(i));
+#endif
+ if(dir_->fullName(i) == remoteFile_)
+ {
+ expected_=dir_->items().at(i)->size_;
+#ifdef _UI_OUTPUTFILECLIENT_DEBUG
+ UserMessage::debug(" expected size=" + QString::number(expected_).toStdString());
+#endif
+ return;
+ }
+ }
+
+ expected_=0;
+#ifdef _UI_OUTPUTFILECLIENT_DEBUG
+ UserMessage::debug(" expected size=" + QString::number(expected_).toStdString());
+#endif
+}
diff --git a/Viewer/src/OutputFileClient.hpp b/Viewer/src/OutputFileClient.hpp
new file mode 100644
index 0000000..5cb3edd
--- /dev/null
+++ b/Viewer/src/OutputFileClient.hpp
@@ -0,0 +1,51 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VIEWER_SRC_OUTPUTFILECLIENT_HPP_
+#define VIEWER_SRC_OUTPUTFILECLIENT_HPP_
+
+#include "OutputClient.hpp"
+#include "VDir.hpp"
+#include "VFile.hpp"
+
+class OutputFileClient : public OutputClient
+{
+ Q_OBJECT
+
+public:
+ OutputFileClient(const std::string& host,const std::string& port,QObject *parent);
+
+ VFile_ptr result() const;
+ void clearResult();
+ void getFile(const std::string& name);
+ void setExpectedSize(qint64 v);
+ int maxProgress() const;
+ void setDir(VDir_ptr);
+
+protected Q_SLOTS:
+ void slotError(QAbstractSocket::SocketError err);
+ void slotRead();
+ void slotConnected();
+
+private:
+ OutputFileClient(const OutputClient&);
+ OutputFileClient& operator=(const OutputClient&);
+ void estimateExpectedSize();
+
+ qint64 total_;
+ qint64 expected_;
+ VFile_ptr out_;
+ VDir_ptr dir_;
+ qint64 lastProgress_;
+ const QString progressUnits_;
+ const qint64 progressChunk_;
+};
+
+#endif /* VIEWER_SRC_OUTPUTFILECLIENT_HPP_ */
diff --git a/Viewer/src/OutputFileProvider.cpp b/Viewer/src/OutputFileProvider.cpp
new file mode 100644
index 0000000..7bc4b95
--- /dev/null
+++ b/Viewer/src/OutputFileProvider.cpp
@@ -0,0 +1,447 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "OutputFileProvider.hpp"
+
+#include "LogServer.hpp"
+#include "OutputFileClient.hpp"
+#include "VNode.hpp"
+#include "VReply.hpp"
+#include "ServerHandler.hpp"
+#include "UserMessage.hpp"
+
+#include <QDateTime>
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/algorithm/string/predicate.hpp>
+
+OutputFileProvider::OutputFileProvider(InfoPresenter* owner) :
+ InfoProvider(owner,VTask::OutputTask),
+ outClient_(NULL), latestCached_(NULL)
+{
+}
+
+void OutputFileProvider::clear()
+{
+ OutputCache::instance()->detach(latestCached_);
+ latestCached_=NULL;
+
+ if(outClient_)
+ {
+ delete outClient_;
+ outClient_=NULL;
+ }
+ InfoProvider::clear();
+
+ dir_.reset();
+}
+
+//Node
+void OutputFileProvider::visit(VInfoNode* infoNode)
+{
+ assert(info_->node() == infoNode->node());
+
+ //Reset the reply
+ reply_->reset();
+
+ if(!info_)
+ {
+ owner_->infoFailed(reply_);
+ return;
+ }
+
+ ServerHandler* server=info_->server();
+ VNode *n=infoNode->node();
+
+ if(!n || !n->node())
+ {
+ owner_->infoFailed(reply_);
+ return;
+ }
+
+ //Get the filename
+ std::string jobout=joboutFileName(); //n->findVariable("ECF_JOBOUT",true);
+
+ //This is needed for the refresh!!! We want to detach the item but keep
+ //lastCached.
+ bool detachCache=!(latestCached_ && latestCached_->sameAs(info_,jobout));
+ if(!detachCache)
+ {
+ OutputCache::instance()->detach(latestCached_);
+ }
+
+ fetchFile(server,n,jobout,true,detachCache);
+}
+
+//Get a file
+void OutputFileProvider::file(const std::string& fileName)
+{
+ //When a new file is requested
+ OutputCache::instance()->detach(latestCached_);
+ latestCached_=NULL;
+
+ //Check if the task is already running
+ if(task_)
+ {
+ task_->status(VTask::CANCELLED);
+ task_.reset();
+ }
+
+ //Reset the reply
+ reply_->reset();
+
+ if(!info_->isNode() || !info_->node() || !info_->node()->node())
+ {
+ owner_->infoFailed(reply_);
+ return;
+ }
+
+ ServerHandler* server=info_->server();
+ VNode *n=info_->node();
+
+ //Get the filename
+ std::string jobout=joboutFileName(); //n->findVariable("ECF_JOBOUT",true);
+
+ fetchFile(server,n,fileName,(fileName==jobout),false);
+}
+
+void OutputFileProvider::fetchFile(ServerHandler *server,VNode *n,const std::string& fileName,bool isJobout,bool detachCache)
+{
+ if(detachCache)
+ {
+ OutputCache::instance()->detach(latestCached_);
+ latestCached_=NULL;
+ }
+
+ if(!n || !n->node() || !server)
+ {
+ owner_->infoFailed(reply_);
+ return;
+ }
+
+ //Set the filename in reply
+ reply_->fileName(fileName);
+
+ //No filename is available
+ if(fileName.empty())
+ {
+ //Joubout variable is not defined or empty
+ if(isJobout)
+ {
+ reply_->setErrorText("Variable ECF_JOBOUT is not defined!");
+ reply_->addLog("MSG>Variable ECF_JOBOUT is not defined!.");
+ owner_->infoFailed(reply_);
+ }
+ else
+ {
+ reply_->setErrorText("Output file is not defined!");
+ reply_->addLog("MSG>Output file is not defined.");
+ owner_->infoFailed(reply_);
+ }
+
+ return;
+ }
+
+ //Check if it is tryno 0
+ if(boost::algorithm::ends_with(fileName,".0"))
+ {
+ reply_->setInfoText("Current job output does not exist yet (<b>TRYNO</b> is <b>0</b>)!)");
+ reply_->addLog("MSG>Current job output does not exist yet (<b>TRYNO</b> is <b>0</b>)!");
+ owner_->infoReady(reply_);
+ return;
+ }
+
+ if(isJobout && n->isSubmitted())
+ {
+ reply_->setInfoText("Current job output does not exist yet (node status is <b>submitted</b>!)");
+ reply_->addLog("MSG>Current job output does not exist yet (node status is <b>submitted</b>!)");
+ owner_->infoReady(reply_);
+ return;
+ }
+
+ //----------------------------------
+ // The host is the localhost
+ //----------------------------------
+
+ if(isJobout)
+ reply_->addLog("REMARK>This file is the <b>current</b> job output (defined by variable <b>ECF_JOBOUT</b>).");
+ else
+ reply_->addLog("REMARK>This file is <b>not</b> the <b>current</b> job output (defined by <b>ECF_JOBOUT</b>).");
+
+#if 0
+ if(server->readFromDisk())
+ {
+ if(server->isLocalHost())
+ {
+ //We try to read the file directly from the disk
+ if(server->readFromDisk())
+ {
+ if(fetchLocalFile(fileName))
+ return;
+ }
+ }
+#endif
+
+#if 0
+ //if(server->isLocalHost())
+ // {
+ //We try to read the file directly from the disk
+ if(server->readFromDisk())
+ {
+ if(fetchLocalFile(fileName))
+ return;
+ }
+ //}
+
+#endif
+
+ //----------------------------------------------------
+ // Not the loacalhost or we could not read the file
+ //----------------------------------------------------
+
+ //We try the output client, its asynchronous!
+ if(fetchFileViaOutputClient(n,fileName))
+ {
+ //If we are here we created a output client and asked to the fetch the
+ //file asynchronously. The ouput client will call slotOutputClientFinished() or
+ //slotOutputClientError eventually!!
+ return;
+ }
+
+ reply_->addLog("TRY>fetch file from logserver: NOT DEFINED");
+
+ //If there is no output client we try
+ //to read it from the disk
+ if(server->readFromDisk() || !isJobout)
+ {
+ //Get the fileName
+ if(fetchLocalFile(fileName))
+ return;
+ }
+
+ //If we are here no output client is defined and we could not read the file from
+ //the local disk we try the server if it is the jobout file.
+ if(isJobout)
+ {
+ fetchJoboutViaServer(server,n,fileName);
+ return;
+ }
+
+ //If we are here we coud not get the file
+ owner_->infoFailed(reply_);
+}
+
+bool OutputFileProvider::fetchFileViaOutputClient(VNode *n,const std::string& fileName)
+{
+ std::string host, port;
+ assert(n);
+
+ UserMessage::debug("OutputFileProvider::fetchFileViaOutputClient <-- file: " + fileName);
+
+ //If it is not the jobout file or it is the joubout but it is not the current item in the cache
+ //(i.e. we do not want to referesh it) we try to use the cache
+ if(fileName != joboutFileName() || !(latestCached_))
+ {
+ //Check cache
+ if(OutputCacheItem* item=OutputCache::instance()->use(info_,fileName))
+ {
+ latestCached_=item;
+ VFile_ptr f=item->file();
+ assert(f);
+ f->setCached(true);
+
+ UserMessage::debug(" File found in cache");
+
+ reply_->setInfoText("");
+ reply_->fileReadMode(VReply::LogServerReadMode);
+
+ reply_->setLog(f->log());
+ reply_->addLog("REMARK>File was read from cache.");
+
+ reply_->tmpFile(f);
+ owner_->infoReady(reply_);
+ return true;
+ }
+ }
+
+ //If we are here we do not need to know the previously cached item
+ latestCached_=NULL;
+
+ //We did not used the cache
+ if(n->logServer(host,port))
+ {
+ //host=host + "baaad";
+
+ UserMessage::debug("OutputFileProvider::fetchFileViaOutputClient --> host:" + host +
+ " port:" + port + " file: " + fileName);
+
+ //reply_->setInfoText("Getting file through log server: " + host + "@" + port);
+ //owner_->infoProgress(reply_);
+ owner_->infoProgressStart("Getting file <i>" + fileName + "</i> from log server <i>" + host + "@" + port +"</i>",0);
+
+ if(!outClient_)
+ {
+ outClient_=new OutputFileClient(host,port,this);
+
+ connect(outClient_,SIGNAL(error(QString)),
+ this,SLOT(slotOutputClientError(QString)));
+
+ connect(outClient_,SIGNAL(progress(QString,int)),
+ this,SLOT(slotOutputClientProgress(QString,int)));
+
+ connect(outClient_,SIGNAL(finished()),
+ this,SLOT(slotOutputClientFinished()));
+
+ outClient_->setDir(dir_);
+ }
+
+ outClient_->getFile(fileName);
+
+ return true;
+ }
+
+ return false;
+}
+
+void OutputFileProvider::slotOutputClientFinished()
+{
+ VFile_ptr tmp = outClient_->result();
+ assert(tmp);
+
+ outClient_->clearResult();
+
+ latestCached_=OutputCache::instance()->add(info_,tmp->sourcePath(),tmp);
+
+ reply_->setInfoText("");
+ reply_->fileReadMode(VReply::LogServerReadMode);
+ reply_->addLog("TRY> fetch file from logserver: " + outClient_->host() + "@" + outClient_->portStr() + ": OK");
+
+ tmp->setFetchMode(VFile::LogServerFetchMode);
+ tmp->setLog(reply_->log());
+ std::string method="served by " + outClient_->host() + "@" + outClient_->portStr();
+ tmp->setFetchModeStr(method);
+
+ reply_->tmpFile(tmp);
+ owner_->infoReady(reply_);
+}
+
+void OutputFileProvider::slotOutputClientProgress(QString msg,int value)
+{
+ //UserMessage::debug("OutputFileProvider::slotOutputClientProgress " + msg.toStdString());
+
+ owner_->infoProgress(msg.toStdString(),value);
+
+ //reply_->setInfoText(msg.toStdString());
+ //owner_->infoProgress(reply_);
+ //reply_->setInfoText("");
+
+ //qDebug() << "prog: " << msg;
+}
+
+
+
+void OutputFileProvider::slotOutputClientError(QString msg)
+{
+ UserMessage::message(UserMessage::DBG,false,"OutputFileProvider::slotOutputClientError error:" + msg.toStdString());
+ reply_->addLog("TRY> fetch file from logserver: " + outClient_->host() + "@" + outClient_->portStr() + " FAILED");
+
+ if(info_)
+ {
+ ServerHandler* server=info_->server();
+ VNode *n=info_->node();
+
+ if(server && n)
+ {
+ std::string jobout=n->findVariable("ECF_JOBOUT",true);
+ bool isJobout=(outClient_->remoteFile() == jobout);
+
+ //We try to read the file directly from the disk
+ if(server->readFromDisk() || !isJobout)
+ {
+ if(fetchLocalFile(outClient_->remoteFile()))
+ return;
+ }
+
+ //Then we try the server
+ if(isJobout)
+ {
+ fetchJoboutViaServer(server,n,jobout);
+ return;
+ }
+ }
+ }
+
+ reply_->setErrorText("Failed to fetch file from logserver " +
+ outClient_->host() + "@" + outClient_->portStr() +
+ "Error: " + msg.toStdString());
+ owner_->infoFailed(reply_);
+}
+
+void OutputFileProvider::fetchJoboutViaServer(ServerHandler *server,VNode *n,const std::string& fileName)
+{
+ assert(server);
+ assert(n);
+
+ //Define a task for getting the info from the server.
+ task_=VTask::create(taskType_,n,this);
+
+ task_->reply()->fileReadMode(VReply::ServerReadMode);
+ task_->reply()->fileName(fileName);
+ task_->reply()->setLog(reply_->log());
+
+ //owner_->infoProgressStart("Getting file <i>" + fileName + "</i> from server",0);
+
+ //Run the task in the server. When it finish taskFinished() is called. The text returned
+ //in the reply will be prepended to the string we generated above.
+ server->run(task_);
+}
+
+bool OutputFileProvider::fetchLocalFile(const std::string& fileName)
+{
+ //we do not want to delete the file once the VFile object is destroyed!!
+ VFile_ptr f(VFile::create(fileName,false));
+ if(f->exists())
+ {
+ reply_->fileReadMode(VReply::LocalReadMode);
+ reply_->addLog("TRY> read file from disk: OK");
+
+ f->setSourcePath(f->path());
+ f->setFetchMode(VFile::LocalFetchMode);
+ f->setFetchDate(QDateTime::currentDateTime());
+ f->setLog(reply_->log());
+
+ reply_->tmpFile(f);
+ owner_->infoReady(reply_);
+ return true;
+ }
+ reply_->addLog("TRY> read file from disk: NO ACCESS");
+ return false;
+}
+
+
+std::string OutputFileProvider::joboutFileName() const
+{
+ if(info_ && info_->isNode() && info_->node() && info_->node()->node())
+ {
+ return info_->node()->findVariable("ECF_JOBOUT",true);
+ }
+
+ return std::string();
+}
+
+void OutputFileProvider::setDir(VDir_ptr dir)
+{
+ if(outClient_)
+ outClient_->setDir(dir);
+
+ if(dir != dir_)
+ dir_=dir;
+}
+
diff --git a/Viewer/src/OutputFileProvider.hpp b/Viewer/src/OutputFileProvider.hpp
new file mode 100644
index 0000000..1cdac93
--- /dev/null
+++ b/Viewer/src/OutputFileProvider.hpp
@@ -0,0 +1,56 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef OUTPUTFILEPROVIDER_HPP_
+#define OUTPUTFILEPROVIDER_HPP_
+
+#include <QObject>
+
+#include "OutputCache.hpp"
+#include "VDir.hpp"
+#include "VInfo.hpp"
+#include "InfoProvider.hpp"
+#include "VTask.hpp"
+#include "VTaskObserver.hpp"
+
+class OutputFileClient;
+
+class OutputFileProvider : public QObject, public InfoProvider
+{
+Q_OBJECT
+
+public:
+ explicit OutputFileProvider(InfoPresenter* owner);
+
+ void visit(VInfoNode*);
+ void clear();
+
+ //Get a particular jobout file
+ void file(const std::string& fileName);
+ void setDir(VDir_ptr);
+
+ std::string joboutFileName() const;
+
+private Q_SLOTS:
+ void slotOutputClientError(QString);
+ void slotOutputClientProgress(QString,int);
+ void slotOutputClientFinished();
+
+private:
+ void fetchFile(ServerHandler *server,VNode *n,const std::string& fileName,bool isJobout,bool detachCache);
+ void fetchJoboutViaServer(ServerHandler *server,VNode *n,const std::string&);
+ bool fetchFileViaOutputClient(VNode *n,const std::string& fileName);
+ bool fetchLocalFile(const std::string& fileName);
+
+ OutputFileClient *outClient_;
+ OutputCacheItem* latestCached_;
+ VDir_ptr dir_;
+};
+
+#endif
diff --git a/Viewer/src/OutputItemWidget.cpp b/Viewer/src/OutputItemWidget.cpp
new file mode 100644
index 0000000..c431a3e
--- /dev/null
+++ b/Viewer/src/OutputItemWidget.cpp
@@ -0,0 +1,586 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "OutputItemWidget.hpp"
+
+#include "OutputDirProvider.hpp"
+#include "OutputFetchInfo.hpp"
+#include "OutputFileProvider.hpp"
+#include "OutputModel.hpp"
+#include "PlainTextEdit.hpp"
+#include "ServerHandler.hpp"
+#include "TextPagerEdit.hpp"
+#include "VConfig.hpp"
+#include "VReply.hpp"
+#include "UserMessage.hpp"
+
+#include <QApplication>
+#include <QDebug>
+#include <QFile>
+#include <QFileInfo>
+#include <QItemSelectionModel>
+#include <QMovie>
+#include <QTime>
+#include <QTimer>
+#include <QWidgetAction>
+
+int OutputItemWidget::updateDirTimeout_=1000*60;
+
+OutputItemWidget::OutputItemWidget(QWidget *parent) :
+ QWidget(parent),
+ userClickedReload_(false),
+ ignoreOutputSelection_(false)
+{
+ //We try to keep the contents when clicking away
+ //tryToKeepContents_=true;
+
+ setupUi(this);
+
+ messageLabel_->hide();
+ warnLabel_->hide();
+ dirLabel_->hide();
+
+ fileLabel_->setProperty("fileInfo","1");
+
+ //--------------------------------
+ // The file contents
+ //--------------------------------
+
+ infoProvider_=new OutputFileProvider(this);
+
+ //--------------------------------
+ // The dir contents
+ //--------------------------------
+
+ dirProvider_=new OutputDirProvider(this);
+
+ //The view
+ dirView_->setRootIsDecorated(false);
+ dirView_->setAllColumnsShowFocus(true);
+ dirView_->setUniformRowHeights(true);
+ dirView_->setAlternatingRowColors(true);
+ dirView_->setSortingEnabled(true);
+ dirView_->sortByColumn(3, Qt::DescendingOrder); // sort with latest files first (0-based)
+
+ //The models
+ dirModel_=new OutputModel(this);
+ dirSortModel_=new OutputSortModel(this);
+ dirSortModel_->setSourceModel(dirModel_);
+ dirSortModel_->setDynamicSortFilter(true);
+
+ dirView_->setModel(dirSortModel_);
+
+ //When the selection changes in the view
+ connect(dirView_->selectionModel(),SIGNAL(currentChanged(QModelIndex,QModelIndex)),
+ this,SLOT(slotOutputSelected(QModelIndex,QModelIndex)));
+
+
+ //Set splitter's initial size.
+ int wHeight=size().height();
+ if(wHeight > 100)
+ {
+ QList<int> sizes;
+ sizes << wHeight-80 << 80;
+ splitter_->setSizes(sizes);
+ }
+
+ //Dir contents update timer
+ updateDirTimer_=new QTimer(this);
+ updateDirTimer_->setInterval(updateDirTimeout_);
+
+ connect(updateDirTimer_,SIGNAL(timeout()),
+ this,SLOT(slotUpdateDir()));
+
+ //Editor font
+ browser_->setFontProperty(VConfig::instance()->find("panel.output.font"));
+
+ fetchInfo_=new OutputFetchInfo(this);
+ QWidgetAction* fetchInfoAction=new QWidgetAction(this);
+ fetchInfoAction->setDefaultWidget(fetchInfo_);
+ fetchInfoTb_->addAction(fetchInfoAction);
+}
+
+OutputItemWidget::~OutputItemWidget()
+{
+}
+
+QWidget* OutputItemWidget::realWidget()
+{
+ return this;
+}
+
+void OutputItemWidget::reload(VInfo_ptr info)
+{
+ assert(active_);
+
+ if(suspended_)
+ return;
+
+ clearContents();
+
+ //enabled_=true;
+ info_=info;
+ userClickedReload_ = false;
+
+ //info must be a node
+ if(info_ && info_->isNode() && info_->node())
+ {
+ //Get file contents
+ infoProvider_->info(info_);
+
+ //Get dir contents
+ dirProvider_->info(info_);
+
+ //Start contents update timer
+ updateDirTimer_->start();
+ }
+}
+
+std::string OutputItemWidget::currentFullName() const
+{
+ QModelIndex current=dirSortModel_->mapToSource(dirView_->currentIndex());
+
+ std::string fullName;
+ if(current.isValid())
+ {
+ fullName=dirModel_->fullName(current);
+ }
+ else
+ {
+ OutputFileProvider* op=static_cast<OutputFileProvider*>(infoProvider_);
+ fullName=op->joboutFileName();
+ }
+
+ return fullName;
+}
+
+void OutputItemWidget::getLatestFile()
+{
+ messageLabel_->hide();
+ messageLabel_->stopProgress();
+ fileLabel_->clear();
+ browser_->clear();
+ fetchInfo_->clearInfo();
+
+ //Get the latest file contents
+ infoProvider_->info(info_);
+
+ updateDir(false); // get the directory listing
+}
+
+void OutputItemWidget::getCurrentFile()
+{
+ messageLabel_->hide();
+ messageLabel_->stopLoadLabel();
+ messageLabel_->stopProgress();
+ fileLabel_->clear();
+ browser_->clear();
+ fetchInfo_->clearInfo();
+
+ if(info_)
+ {
+ std::string fullName=currentFullName();
+ UserMessage::message(UserMessage::DBG,false,"output selected: " + fullName);
+ OutputFileProvider* op=static_cast<OutputFileProvider*>(infoProvider_);
+ op->file(fullName);
+ }
+}
+
+void OutputItemWidget::clearContents()
+{
+ updateDirTimer_->stop();
+ InfoPanelItem::clear();
+ enableDir(false);
+ messageLabel_->hide();
+ messageLabel_->stopProgress();
+ fileLabel_->clear();
+ browser_->clearCursorCache();
+ browser_->clear();
+ reloadTb_->setEnabled(true);
+ userClickedReload_ = false;
+ fetchInfo_->clearInfo();
+}
+
+void OutputItemWidget::updateState(const FlagSet<ChangeFlag>& flags)
+{
+ if(flags.isSet(SelectedChanged))
+ {
+ if(selected_ && !suspended_)
+ {
+ slotUpdateDir();
+ updateDirTimer_->start();
+ }
+ //If unselected we stop the dir update
+ else
+ {
+ updateDirTimer_->stop();
+ }
+ }
+
+ if(flags.isSet(SuspendedChanged))
+ {
+ //Suspend
+ if(suspended_)
+ {
+ updateDirTimer_->stop();
+ reloadTb_->setEnabled(false);
+ enableDir(false);
+ }
+ //Resume
+ else
+ {
+ if(info_ && info_->node())
+ {
+ reloadTb_->setEnabled(true);
+ enableDir(true);
+ if(selected_)
+ {
+ slotUpdateDir();
+ updateDirTimer_->start();
+ }
+ }
+ else
+ {
+ clearContents();
+ }
+ }
+ }
+}
+
+void OutputItemWidget::infoReady(VReply* reply)
+{
+ //------------------------
+ // From output provider
+ //------------------------
+
+ if(reply->sender() == infoProvider_)
+ {
+ messageLabel_->stopProgress();
+
+ //For some unknown reason the textedit font, although it is properly set in the constructor,
+ //is reset to default when we first call infoready. So we need to set it again!!
+ browser_->updateFont();
+
+ bool hasMessage=false;
+ if(reply->hasWarning())
+ {
+ messageLabel_->showWarning(QString::fromStdString(reply->warningText()));
+ hasMessage=true;
+ }
+ else if(reply->hasInfo())
+ {
+ messageLabel_->showInfo(QString::fromStdString(reply->infoText()));
+ hasMessage=true;
+ }
+
+ browser_->adjustHighlighter(QString::fromStdString(reply->fileName()));
+
+ VFile_ptr f=reply->tmpFile();
+
+ //If the info is stored in a tmp file
+ if(f)
+ {
+ browser_->loadFile(f);
+ if(f->storageMode() == VFile::DiskStorage)
+ hasMessage=false;
+
+ }
+ //If the info is stored as a string in the reply object
+ else
+ {
+ //QString s=QString::fromStdString(reply->text());
+ //browser_->loadText(s,QString::fromStdString(reply->fileName()));
+ }
+
+ if(!hasMessage)
+ {
+ messageLabel_->hide();
+ }
+ //messageLabel_->stopLoadLabel();
+
+ //Update the file label
+ fileLabel_->update(reply);
+
+ //Search for some keywords in the current jobout
+
+ if(f)
+ {
+ //We do not have dir info so the file must be the jobout
+ if(dirModel_->isEmpty())
+ searchOnReload();
+
+ //We have dir info
+ else
+ {
+ OutputFileProvider* op=static_cast<OutputFileProvider*>(infoProvider_);
+ if(reply->fileName() == op->joboutFileName())
+ {
+ searchOnReload();
+ }
+ }
+ }
+
+ userClickedReload_ = false;
+ reloadTb_->setEnabled(true);
+
+ //If we got a local file or a file via the logserver we restart the dir update timer
+ if(!suspended_ &&
+ (reply->fileReadMode() == VReply::LocalReadMode ||
+ reply->fileReadMode() == VReply::LogServerReadMode))
+ {
+ updateDirTimer_->start();
+ }
+ //Update the selection in the dir list according to the file
+ if(f)
+ {
+ setCurrentInDir(f->sourcePath());
+ }
+#if 0
+ if(reply->tmpFile() && reply->fileReadMode() == VReply::LocalReadMode &&
+ info_ && !info_->server()->isLocalHost())
+ {
+ QString msg="The output file was read <b>from disk</b> but the server's \
+ host (" + QString::fromStdString(info_->server()->host()) +
+ ") is not running on the local machine. If the path is machine-specific (e.g. /tmp) \
+ and there exists a file with the same path on the local machine, then\
+ this will have been read instead.";
+
+ warnLabel_->showWarning(msg);
+ }
+#endif
+
+
+ fetchInfo_->setInfo(reply,info_);
+ }
+
+ //------------------------
+ // From output dir provider
+ //------------------------
+ else
+ {
+ //Update the dir widget and select the proper file in the list
+ updateDir(reply->directory(),true);
+ }
+}
+
+void OutputItemWidget::infoProgress(VReply* reply)
+{
+ messageLabel_->showInfo(QString::fromStdString(reply->infoText()));
+ //messageLabel_->startLoadLabel();
+ //updateDir(true);
+}
+
+void OutputItemWidget::infoProgressStart(const std::string& text,int max)
+{
+ messageLabel_->showInfo(QString::fromStdString(text));
+ messageLabel_->startProgress(max);
+}
+
+void OutputItemWidget::infoProgress(const std::string& text,int value)
+{
+ messageLabel_->progress(QString::fromStdString(text),value);
+}
+
+void OutputItemWidget::infoFailed(VReply* reply)
+{
+ if(reply->sender() == infoProvider_)
+ {
+ QString s=QString::fromStdString(reply->errorText());
+
+ messageLabel_->showError(s);
+ //messageLabel_->stopLoadLabel();
+ messageLabel_->stopProgress();
+
+ //Update the file label
+ fileLabel_->update(reply);
+
+ userClickedReload_ = false;
+ reloadTb_->setEnabled(true);
+ //updateDir(true);
+
+ fetchInfo_->setInfo(reply,info_);
+ }
+ else
+ {
+ //We do not have directories
+ enableDir(false);
+ //the timer is stopped. It will be restarted again if we get a local file or
+ //a file via the logserver
+ updateDirTimer_->stop();
+ }
+}
+
+void OutputItemWidget::on_reloadTb__clicked()
+{
+ userClickedReload_ = true;
+ reloadTb_->setEnabled(false);
+ getLatestFile();
+ //userClickedReload_ = false;
+}
+
+//------------------------------------
+// Directory contents
+//------------------------------------
+
+void OutputItemWidget::setCurrentInDir(const std::string& fullName)
+{
+ if(!dirModel_->isEmpty())
+ {
+ //Try to preserve the selection
+ ignoreOutputSelection_=true;
+ dirView_->setCurrentIndex(dirSortModel_->fullNameToIndex(fullName));
+ ignoreOutputSelection_=false;
+ }
+}
+
+void OutputItemWidget::updateDir(VDir_ptr dir,bool restartTimer)
+{
+ UserMessage::debug("OutputItemWidget::updateDir -->");
+
+ if(restartTimer)
+ updateDirTimer_->stop();
+
+ bool status=(dir && dir->count() >0);
+
+ if(status)
+ {
+ OutputFileProvider* op=static_cast<OutputFileProvider*>(infoProvider_);
+ op->setDir(dir);
+
+ std::string fullName=currentFullName();
+
+ dirView_->selectionModel()->clearSelection();
+ dirModel_->setData(dir,op->joboutFileName());
+ dirWidget_->show();
+
+ UserMessage::qdebug(" dir item count=" + QString::number(dirModel_->rowCount()));
+
+ //Try to preserve the selection
+ ignoreOutputSelection_=true;
+ dirView_->setCurrentIndex(dirSortModel_->fullNameToIndex(fullName));
+ ignoreOutputSelection_=false;
+ }
+ else
+ {
+ dirWidget_->hide();
+ dirModel_->clearData();
+ }
+
+ if(restartTimer)
+ updateDirTimer_->start(updateDirTimeout_);
+}
+
+void OutputItemWidget::updateDir(bool restartTimer)
+{
+ dirProvider_->info(info_);
+
+ //Remember the selection
+ //std::string fullName=currentFullName();
+ //updateDir(restartTimer,fullName);
+}
+
+void OutputItemWidget::updateDir(bool restartTimer,const std::string& selectFullName)
+{
+ /*if(restartTimer)
+ updateDirTimer_->stop();
+
+ OutputProvider* op=static_cast<OutputProvider*>(infoProvider_);
+ VDir_ptr dir=op->directory();
+
+ bool status=(dir && dir.get());
+
+ if(status)
+ {
+ dirView_->selectionModel()->clearSelection();
+ dirModel_->setData(dir);
+ dirWidget_->show();
+
+ //Try to preserve the selection
+ ignoreOutputSelection_=true;
+ dirView_->setCurrentIndex(dirSortModel_->fullNameToIndex(selectFullName));
+ ignoreOutputSelection_=false;
+ }
+ else
+ {
+ dirWidget_->hide();
+ dirModel_->clearData();
+ }
+
+ if(restartTimer)
+ updateDirTimer_->start(updateDirTimeout_);*/
+}
+
+void OutputItemWidget::slotUpdateDir()
+{
+ updateDir(false);
+}
+
+void OutputItemWidget::enableDir(bool status)
+{
+ if(status)
+ {
+ dirWidget_->show();
+ }
+ else
+ {
+ dirWidget_->hide();
+ dirModel_->clearData();
+ }
+}
+
+//---------------------------------------------
+// Search
+//---------------------------------------------
+
+void OutputItemWidget::on_searchTb__clicked()
+{
+ browser_->showSearchLine();
+}
+
+void OutputItemWidget::on_gotoLineTb__clicked()
+{
+ browser_->gotoLine();
+}
+
+
+// Called when we load a new node's information into the panel, or
+// when we move to the panel from another one.
+// If the search box is open, then search for the first matching item;
+// otherwise, search for a pre-configured list of keywords. If none
+// are found, and the user has clicked on the 'reload' button then
+// we just go to the last line of the output
+void OutputItemWidget::searchOnReload()
+{
+ browser_->searchOnReload(userClickedReload_);
+}
+
+//This slot is called when a file item is selected in the output view.
+void OutputItemWidget::slotOutputSelected(QModelIndex idx1,QModelIndex idx2)
+{
+ if(!ignoreOutputSelection_)
+ getCurrentFile();
+}
+
+//-----------------------------------------
+// Fontsize management
+//-----------------------------------------
+
+void OutputItemWidget::on_fontSizeUpTb__clicked()
+{
+ //We need to call a custom slot here instead of "zoomIn"!!!
+ browser_->zoomIn();
+}
+
+void OutputItemWidget::on_fontSizeDownTb__clicked()
+{
+ //We need to call a custom slot here instead of "zoomOut"!!!
+ browser_->zoomOut();
+}
+
+static InfoPanelItemMaker<OutputItemWidget> maker1("output");
diff --git a/Viewer/src/OutputItemWidget.hpp b/Viewer/src/OutputItemWidget.hpp
new file mode 100644
index 0000000..a23aaa7
--- /dev/null
+++ b/Viewer/src/OutputItemWidget.hpp
@@ -0,0 +1,82 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef OUTPUTITEMWIDGET_HPP_
+#define OUTPUTITEMWIDGET_HPP_
+
+#include "InfoPanelItem.hpp"
+
+#include "VFile.hpp"
+#include "VDir.hpp"
+
+#include "ui_OutputItemWidget.h"
+
+class OutputDirProvider;
+class OutputFetchInfo;
+class OutputModel;
+class OutputSortModel;
+
+class OutputItemWidget : public QWidget, public InfoPanelItem, protected Ui::OutputItemWidget
+{
+Q_OBJECT
+
+public:
+ explicit OutputItemWidget(QWidget *parent=0);
+ ~OutputItemWidget();
+
+ void reload(VInfo_ptr);
+ QWidget* realWidget();
+ void clearContents();
+
+ //From VInfoPresenter
+ void infoReady(VReply*);
+ void infoFailed(VReply*);
+ void infoProgress(VReply*);
+ void infoProgressStart(const std::string& text,int max);
+ void infoProgress(const std::string& text,int value);
+
+ void nodeChanged(const VNode*, const std::vector<ecf::Aspect::Type>&) {}
+ void defsChanged(const std::vector<ecf::Aspect::Type>&) {}
+
+protected Q_SLOTS:
+ void slotOutputSelected(QModelIndex,QModelIndex);
+ void slotUpdateDir();
+ void on_searchTb__clicked();
+ void on_gotoLineTb__clicked();
+ void on_reloadTb__clicked();
+ void on_fontSizeUpTb__clicked();
+ void on_fontSizeDownTb__clicked();
+
+protected:
+ void setCurrentInDir(const std::string&);
+ void updateDir(bool);
+ void updateDir(VDir_ptr,bool);
+ void updateDir(bool,const std::string&);
+ void enableDir(bool);
+ void updateState(const FlagSet<ChangeFlag>&);
+ void searchOnReload();
+ void getCurrentFile();
+ void getLatestFile();
+ std::string currentFullName() const;
+ void updateHistoryLabel(const std::vector<std::string>&);
+
+ OutputDirProvider* dirProvider_;
+ OutputModel* dirModel_;
+ OutputSortModel* dirSortModel_;
+
+ bool userClickedReload_;
+ bool ignoreOutputSelection_;
+ QTimer* updateDirTimer_;
+ static int updateDirTimeout_;
+ OutputFetchInfo* fetchInfo_;
+};
+
+#endif
+
diff --git a/Viewer/src/OutputItemWidget.ui b/Viewer/src/OutputItemWidget.ui
new file mode 100644
index 0000000..54c36d0
--- /dev/null
+++ b/Viewer/src/OutputItemWidget.ui
@@ -0,0 +1,249 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>OutputItemWidget</class>
+ <widget class="QWidget" name="OutputItemWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>494</width>
+ <height>449</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <property name="spacing">
+ <number>1</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QSplitter" name="splitter_">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <widget class="QWidget" name="layoutWidget">
+ <layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0,1">
+ <property name="spacing">
+ <number>1</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0,0,0,0,0,0">
+ <property name="spacing">
+ <number>1</number>
+ </property>
+ <item>
+ <widget class="FileInfoLabel" name="fileLabel_">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="fetchInfoTb_">
+ <property name="toolTip">
+ <string>Additional information about the fetched output file</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/grey_info.svg</normaloff>:/viewer/grey_info.svg</iconset>
+ </property>
+ <property name="popupMode">
+ <enum>QToolButton::InstantPopup</enum>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="fontSizeUpTb_">
+ <property name="toolTip">
+ <string>Increase font size in text browser <br><code>Ctrl++ or Ctrl+wheel</code></string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/fontsize_up.svg</normaloff>:/viewer/fontsize_up.svg</iconset>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl++</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="fontSizeDownTb_">
+ <property name="toolTip">
+ <string>Descrease font size in text browser <br><code>Ctrl+- or Ctrl+wheel</code></string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/fontsize_down.svg</normaloff>:/viewer/fontsize_down.svg</iconset>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+-</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="searchTb_">
+ <property name="toolTip">
+ <string>Show search bar (CTRL-F)</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/search_decor.svg</normaloff>:/viewer/search_decor.svg</iconset>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+F</string>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="gotoLineTb_">
+ <property name="toolTip">
+ <string>Goto line number (CTRL-L)</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/images/goto_line.svg</normaloff>:/viewer/images/goto_line.svg</iconset>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+L</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="reloadTb_">
+ <property name="toolTip">
+ <string>Reload the current job output file</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/sync.svg</normaloff>:/viewer/sync.svg</iconset>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+R</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="MessageLabel" name="messageLabel_" native="true"/>
+ </item>
+ <item>
+ <widget class="MessageLabel" name="warnLabel_" native="true"/>
+ </item>
+ <item>
+ <widget class="OutputBrowser" name="browser_" native="true"/>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="dirWidget_" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <property name="spacing">
+ <number>1</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="DirInfoLabel" name="dirLabel_">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTreeView" name="dirView_"/>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>MessageLabel</class>
+ <extends>QWidget</extends>
+ <header>MessageLabel.hpp</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>FileInfoLabel</class>
+ <extends>QLabel</extends>
+ <header>FileInfoLabel.hpp</header>
+ </customwidget>
+ <customwidget>
+ <class>DirInfoLabel</class>
+ <extends>QLabel</extends>
+ <header>FileInfoLabel.hpp</header>
+ </customwidget>
+ <customwidget>
+ <class>OutputBrowser</class>
+ <extends>QWidget</extends>
+ <header>OutputBrowser.hpp</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Viewer/src/OutputModel.cpp b/Viewer/src/OutputModel.cpp
new file mode 100644
index 0000000..e7933ff
--- /dev/null
+++ b/Viewer/src/OutputModel.cpp
@@ -0,0 +1,310 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "OutputModel.hpp"
+
+#include <QColor>
+#include <QDateTime>
+#include <QDebug>
+#include <QDir>
+#include <QFont>
+
+QColor OutputModel::joboutCol_=QColor(0,115,48);
+
+//=======================================================================
+//
+// OutputModel
+//
+//=======================================================================
+
+OutputModel::OutputModel(QObject *parent) :
+ QAbstractItemModel(parent),
+ joboutRow_(-1)
+
+{
+}
+
+void OutputModel::setData(VDir_ptr dir,const std::string& jobout)
+{
+ beginResetModel();
+ dir_=dir;
+ joboutRow_=-1;
+
+ if(dir_)
+ {
+ for(int i; i < dir_->count(); i++)
+ {
+ if(dir_->fullName(i) == jobout)
+ {
+ joboutRow_=i;
+ break;
+ }
+ }
+ }
+
+ endResetModel();
+}
+
+void OutputModel::clearData()
+{
+ beginResetModel();
+ dir_.reset();
+ endResetModel();
+}
+
+int OutputModel::columnCount( const QModelIndex& parent ) const
+{
+ return 4;
+}
+
+int OutputModel::rowCount( const QModelIndex& parent) const
+{
+ if(!hasData())
+ return 0;
+
+ if(!parent.isValid())
+ return dir_->count();
+
+ return 0;
+}
+
+QVariant OutputModel::data(const QModelIndex& index, int role) const
+{
+ if(!hasData() || (role != Qt::DisplayRole && role != Qt::UserRole &&
+ role != Qt::ForegroundRole && role != Qt::ToolTipRole && role != Qt::FontRole))
+ return QVariant();
+
+ int row=index.row();
+ VDirItem *item=dir_->items().at(row);
+
+ if(role == Qt::DisplayRole)
+ {
+ switch(index.column())
+ {
+ case 0:
+ return QString::fromStdString(item->name_);
+ case 1:
+ return formatSize(item->size_);
+ case 2:
+ return formatAgo(item->mtime_);
+ case 3:
+ return formatDate(item->mtime_);
+ default:
+ break;
+ }
+ }
+ else if(role == Qt::UserRole)
+ {
+ switch(index.column())
+ {
+ case 0:
+ return QString::fromStdString(fullName(index));
+ case 1:
+ return static_cast<float>(item->size_)/1024.;
+ case 2:
+ return item->mtime_.toTime_t();
+ default:
+ break;
+ }
+ }
+ else if(role == Qt::ForegroundRole)
+ {
+ if(row == joboutRow_)
+ {
+ return joboutCol_;
+ }
+ }
+ else if(role == Qt::FontRole)
+ {
+ if(row == joboutRow_)
+ {
+ QFont f;
+ f.setBold(true);
+ return f;
+ }
+ }
+ else if(role == Qt::ToolTipRole)
+ {
+ if(row == joboutRow_)
+ {
+ return QString::fromStdString(item->name_) + " is the current job output file.";
+ }
+ }
+
+ return QVariant();
+}
+
+QVariant OutputModel::headerData( const int section, const Qt::Orientation orient , const int role ) const
+{
+ if ( orient != Qt::Horizontal || role != Qt::DisplayRole )
+ return QAbstractItemModel::headerData( section, orient, role );
+
+ switch ( section )
+ {
+ case 0: return tr("Name");
+ case 1: return tr("Size");
+ case 2: return tr("Modified (ago)");
+ case 3: return tr("Modified");
+ default: return QVariant();
+ }
+
+ return QVariant();
+}
+
+QModelIndex OutputModel::index( int row, int column, const QModelIndex & parent ) const
+{
+ if(!hasData() || row < 0 || column < 0)
+ {
+ return QModelIndex();
+ }
+
+ //When parent is the root this index refers to a node or server
+ if(!parent.isValid())
+ {
+ return createIndex(row,column,static_cast<void*>(0));
+ }
+
+ return QModelIndex();
+
+}
+
+QModelIndex OutputModel::parent(const QModelIndex &child) const
+{
+ return QModelIndex();
+
+}
+
+bool OutputModel::hasData() const
+{
+ return dir_ && dir_.get();
+}
+
+std::string OutputModel::fullName(const QModelIndex& index) const
+{
+ if(!hasData())
+ return std::string();
+
+ return dir_->fullName(index.row());
+}
+
+QString OutputModel::formatSize(unsigned int size) const
+{
+ if(size < 1024)
+ return QString::number(size) + " B";
+ else if(size < 1024*1024)
+ return QString::number(size/1024) + " KB";
+ else if(size < 1024*1024*1024)
+ return QString::number(size/(1024*1024)) + " MB";
+ else
+ return QString::number(size/(1024*1024*1024)) + " GB";
+
+ return QString();
+}
+
+QString OutputModel::formatDate(QDateTime dt) const
+{
+ //QDateTime dt=QDateTime::fromTime_t(t);
+ return dt.toString("yyyy-MM-dd hh:mm:ss");
+}
+
+QString OutputModel::formatAgo(QDateTime dt) const
+{
+ QString str=tr("Right now");
+
+ QDateTime now=QDateTime::currentDateTime();
+
+ int delta = dt.secsTo(now);
+ if(delta<0) delta = 0;
+
+ if(delta ==1)
+ str=tr("1 second ago");
+
+ else if(delta >=1 && delta < 60)
+ {
+ str=QString::number(delta) + tr(" second") + ((delta==1)?tr(""):tr("s")) + tr(" ago");
+ }
+
+ else if(delta >= 60 && delta < 60*60)
+ {
+ int val=delta/60;
+ str=QString::number(val) + tr(" minute") + ((val==1)?tr(""):tr("s")) + tr(" ago");
+ }
+
+ else if(delta >= 60*60 && delta < 60*60*24)
+ {
+ int val=delta/(60*60);
+ str=QString::number(val) + tr(" hour") + ((val==1)?tr(""):tr("s")) + tr(" ago");
+ }
+
+ else if(delta >= 60*60*24)
+ {
+ int val=delta/(60*60*24);
+ str=QString::number(val) + tr(" day") + ((val==1)?tr(""):tr("s")) + tr(" ago");
+ }
+
+ return str;
+}
+
+//=======================================================================
+//
+// OutputSortModel
+//
+//=======================================================================
+
+OutputSortModel::OutputSortModel(QObject* parent) :
+ QSortFilterProxyModel(parent)
+{
+
+}
+
+bool OutputSortModel::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const
+{
+ int col=sourceLeft.column();
+
+ //Name or modification date
+ if(col==0 || col == 3)
+ {
+ return sourceModel()->data(sourceLeft,Qt::DisplayRole).toString() < sourceModel()->data(sourceRight,Qt::DisplayRole).toString();
+ }
+ //Size
+ else if(col == 1)
+ {
+ return sourceModel()->data(sourceLeft,Qt::UserRole).toFloat() < sourceModel()->data(sourceRight,Qt::UserRole).toFloat();
+ }
+ //Ago
+ else if(col == 2)
+ {
+ return sourceModel()->data(sourceLeft,Qt::UserRole).toInt() > sourceModel()->data(sourceRight,Qt::UserRole).toInt();
+ }
+
+ return true;
+}
+
+bool OutputSortModel::filterAcceptsRow(int sourceRow,const QModelIndex& sourceParent) const
+{
+ return true;
+}
+
+QModelIndex OutputSortModel::fullNameToIndex(const std::string& fullName)
+{
+ QString name=QString::fromStdString(fullName);
+
+ for(int i=0; i < rowCount(QModelIndex()); i++)
+ {
+ QModelIndex idx=index(i,0);
+ if(name.endsWith(data(idx,Qt::DisplayRole).toString()))
+ {
+ return idx;
+ }
+ }
+ return QModelIndex();
+}
+
+
+
diff --git a/Viewer/src/OutputModel.hpp b/Viewer/src/OutputModel.hpp
new file mode 100644
index 0000000..d61248f
--- /dev/null
+++ b/Viewer/src/OutputModel.hpp
@@ -0,0 +1,57 @@
+#ifndef OUTPUTMODEL_H
+#define OUTPUTMODEL_H
+
+#include <QAbstractItemModel>
+#include <QDateTime>
+#include <QSortFilterProxyModel>
+
+#include "NodeObserver.hpp"
+#include "VDir.hpp"
+#include "VInfo.hpp"
+
+class OutputModel : public QAbstractItemModel
+{
+public:
+ explicit OutputModel(QObject *parent=0);
+
+ void setData(VDir_ptr dir,const std::string& jobout);
+ void clearData();
+ bool isEmpty() const {return (!dir_);}
+ int columnCount (const QModelIndex& parent = QModelIndex() ) const;
+ int rowCount (const QModelIndex& parent = QModelIndex() ) const;
+
+ //Qt::ItemFlags flags ( const QModelIndex & index) const;
+ QVariant data (const QModelIndex& , int role = Qt::DisplayRole ) const;
+ QVariant headerData(int,Qt::Orientation,int role = Qt::DisplayRole ) const;
+
+ QModelIndex index (int, int, const QModelIndex& parent = QModelIndex() ) const;
+ QModelIndex parent (const QModelIndex & ) const;
+
+ std::string fullName(const QModelIndex& index) const;
+
+protected:
+ bool hasData() const;
+ QString formatSize(unsigned int size) const;
+ QString formatDate(QDateTime) const;
+ QString formatAgo(QDateTime) const;
+
+ VDir_ptr dir_;
+ int joboutRow_;
+ static QColor joboutCol_;
+};
+
+//Filters and sorts the output
+class OutputSortModel : public QSortFilterProxyModel
+{
+public:
+ explicit OutputSortModel(QObject *parent=0);
+ ~OutputSortModel() {}
+
+ bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
+ bool filterAcceptsRow(int,const QModelIndex &) const;
+
+ QModelIndex fullNameToIndex(const std::string& fullName);
+};
+
+
+#endif
diff --git a/Viewer/src/OverviewItemWidget.cpp b/Viewer/src/OverviewItemWidget.cpp
new file mode 100644
index 0000000..1008a4c
--- /dev/null
+++ b/Viewer/src/OverviewItemWidget.cpp
@@ -0,0 +1,146 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "OverviewItemWidget.hpp"
+#include "Highlighter.hpp"
+#include "OverviewProvider.hpp"
+#include "VConfig.hpp"
+#include "VReply.hpp"
+
+#include <QScrollBar>
+
+
+//========================================================
+//
+// InfoItemWidget
+//
+//========================================================
+
+OverviewItemWidget::OverviewItemWidget(QWidget *parent) :
+ CodeItemWidget(parent),
+ lastScrollPos_(0)
+{
+ fileLabel_->hide();
+ externalTb_->hide();
+
+ textEdit_->setShowLineNumbers(false);
+
+ Highlighter* ih=new Highlighter(textEdit_->document(),"info");
+
+ infoProvider_=new OverviewProvider(this);
+
+ //Editor font
+ textEdit_->setFontProperty(VConfig::instance()->find("panel.overview.font"));
+}
+
+OverviewItemWidget::~OverviewItemWidget()
+{
+}
+
+QWidget* OverviewItemWidget::realWidget()
+{
+ return this;
+}
+
+void OverviewItemWidget::reload(VInfo_ptr info)
+{
+ assert(active_);
+
+ if(suspended_)
+ return;
+
+ clearContents();
+
+ //set the info
+ adjust(info);
+
+ //Info must be a node
+ if(info_)
+ {
+ infoProvider_->info(info_);
+ }
+}
+
+void OverviewItemWidget::reload()
+{
+ //Save the vertical scrollbar pos
+ lastScrollPos_=textEdit_->verticalScrollBar()->value();
+
+ textEdit_->clear();
+ infoProvider_->info(info_);
+}
+
+void OverviewItemWidget::clearContents()
+{
+ InfoPanelItem::clear();
+ textEdit_->clear();
+}
+
+void OverviewItemWidget::infoReady(VReply* reply)
+{
+ QString s=QString::fromStdString(reply->text());
+ textEdit_->setPlainText(s);
+
+ //Restore the vertical scrollbar pos
+ textEdit_->verticalScrollBar()->setValue(lastScrollPos_);
+}
+
+void OverviewItemWidget::infoProgress(VReply* reply)
+{
+ QString s=QString::fromStdString(reply->text());
+ textEdit_->setPlainText(s);
+}
+
+void OverviewItemWidget::infoFailed(VReply* reply)
+{
+ QString s=QString::fromStdString(reply->errorText());
+ textEdit_->setPlainText(s);
+}
+
+//At this point we can be sure that the node is handled by this item.
+void OverviewItemWidget::nodeChanged(const VNode* node, const std::vector<ecf::Aspect::Type>& aspect)
+{
+ if(frozen_)
+ return;
+
+ for(std::vector<ecf::Aspect::Type>::const_iterator it=aspect.begin(); it != aspect.end(); ++it)
+ {
+ if(*it == ecf::Aspect::STATE || *it == ecf::Aspect::ADD_REMOVE_NODE || *it == ecf::Aspect::ADD_REMOVE_ATTR ||
+ *it == ecf::Aspect::DEFSTATUS || *it == ecf::Aspect::SUSPENDED || *it == ecf::Aspect::NODE_VARIABLE)
+ {
+ reload();
+ return;
+ }
+ }
+}
+
+void OverviewItemWidget::defsChanged(const std::vector<ecf::Aspect::Type>& aspect)
+{
+ if(frozen_)
+ return;
+
+ for(std::vector<ecf::Aspect::Type>::const_iterator it=aspect.begin(); it != aspect.end(); ++it)
+ {
+ if(*it == ecf::Aspect::SERVER_STATE || *it == ecf::Aspect::SERVER_VARIABLE || *it == ecf::Aspect::ADD_REMOVE_ATTR)
+ {
+ reload();
+ return;
+ }
+ }
+}
+
+void OverviewItemWidget::connectStateChanged()
+{
+ if(frozen_)
+ return;
+
+ reload();
+}
+
+static InfoPanelItemMaker<OverviewItemWidget> maker1("overview");
diff --git a/Viewer/src/OverviewItemWidget.hpp b/Viewer/src/OverviewItemWidget.hpp
new file mode 100644
index 0000000..668ec59
--- /dev/null
+++ b/Viewer/src/OverviewItemWidget.hpp
@@ -0,0 +1,44 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef OVERVIEWITEMWIDGET_HPP_
+#define OVERVIEWITEMWIDGET_HPP_
+
+#include "InfoPanelItem.hpp"
+#include "CodeItemWidget.hpp"
+
+class OverviewItemWidget : public CodeItemWidget, public InfoPanelItem
+{
+public:
+ explicit OverviewItemWidget(QWidget *parent=0);
+ ~OverviewItemWidget();
+
+ void reload(VInfo_ptr);
+ QWidget* realWidget();
+ void clearContents();
+
+ //From VInfoPresenter
+ void infoReady(VReply*);
+ void infoFailed(VReply*);
+ void infoProgress(VReply*);
+
+ void nodeChanged(const VNode*, const std::vector<ecf::Aspect::Type>&);
+ void defsChanged(const std::vector<ecf::Aspect::Type>&);
+ void connectStateChanged();
+
+protected:
+ void reload();
+ void updateState(const ChangeFlags&) {}
+
+ int lastScrollPos_;
+};
+
+#endif
+
diff --git a/Viewer/src/OverviewProvider.cpp b/Viewer/src/OverviewProvider.cpp
new file mode 100644
index 0000000..45287f9
--- /dev/null
+++ b/Viewer/src/OverviewProvider.cpp
@@ -0,0 +1,276 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "OverviewProvider.hpp"
+
+#include "ConnectState.hpp"
+#include "ServerHandler.hpp"
+#include "VNode.hpp"
+#include "VNState.hpp"
+#include "VSState.hpp"
+#include "VFileInfo.hpp"
+
+OverviewProvider::OverviewProvider(InfoPresenter* owner) : InfoProvider(owner,VTask::NoTask)
+{
+
+}
+
+//==================================================
+// Server
+//==================================================
+
+void OverviewProvider::visit(VInfoServer* info)
+{
+ reply_->reset();
+
+ //Build the second part of the server info. We do not need
+ //information from the ClientInvoker for this!!
+ std::stringstream ss;
+ serverInfo(info,ss);
+ reply_->text(ss.str());
+
+ //If not connected we reply immediately!
+ if(info->server()->connectState()->state() != ConnectState::Normal)
+ {
+ owner_->infoReady(reply_);
+ return;
+ }
+
+ //Define a task for getting the stats from the server.
+ //We need ClientInvoker for this
+ task_=VTask::create(VTask::StatsTask,this);
+
+ //Run the task in the server. When it finish taskFinished() is called. The text returned
+ //in the reply will be prepended to the string we generated above.
+ info->server()->run(task_);
+}
+
+//Node
+void OverviewProvider::visit(VInfoNode* ni)
+{
+ reply_->reset();
+ std::stringstream ss;
+ nodeInfo(ni,ss);
+ reply_->text(ss.str());
+ owner_->infoReady(reply_);
+}
+
+void OverviewProvider::visit(VInfoAttribute* ptr)
+{
+}
+
+void OverviewProvider::taskChanged(VTask_ptr task)
+{
+ if(task_ != task)
+ return;
+
+ switch(task->status())
+ {
+ case VTask::FINISHED:
+ //We prepend the results to the existing text
+ reply_->prependText(task->reply()->text());
+ owner_->infoReady(reply_);
+ //We do not need the task anymore.
+ task_.reset();
+ break;
+ case VTask::ABORTED:
+ case VTask::CANCELLED:
+ case VTask::REJECTED:
+ reply_->prependText(task->reply()->text());
+ owner_->infoFailed(reply_);
+ //We do not need the task anymore.
+ task_.reset();break;
+ default:
+ break;
+ }
+}
+
+void OverviewProvider::serverInfo(VInfoServer* info,std::stringstream& f)
+{
+ static const std::string inc = " ";
+
+ ServerHandler *server=info->server();
+ if(!server) return;
+ VServer *snode=server->vRoot();
+
+ ConnectState* cst=server->connectState();
+
+ //If the server is not connected!!
+ if(cst->state() != ConnectState::Normal)
+ {
+ f << cst->describe() << "\n";
+ f << inc << "Name : " << server->name() << "\n";
+ f << inc << "Host : " << server->host() << "\n";
+ f << inc << "Port : " << server->port() << "\n";
+
+ if(cst->state() == ConnectState::Lost)
+ {
+ f << inc << "Last connection attempt : " << VFileInfo::formatDate(cst->lastLostTime()).toStdString() << "\n";
+ f << "\n";
+ if(!cst->errorMessage().empty())
+ {
+ f << "Error message:\n";
+ f << cst->errorMessage();
+ }
+ }
+ else if(cst->state() == ConnectState::Disconnected)
+ {
+ f << inc << "Disconnected : " << VFileInfo::formatDate(cst->lastDisconnectTime()).toStdString() << "\n";
+ }
+ return;
+ }
+
+ //if(!ServerDefsAccess(server).defs()) return;
+
+ using namespace boost::posix_time;
+ using namespace boost::gregorian;
+
+ std::string typeName="server";
+ std::string nodeName=server->name();
+ std::string statusName(VSState::toName(server).toStdString());
+
+ //Header
+ f << "name : " << nodeName << "\n";
+ f << "type : " << typeName << "\n";
+ f << "status : " << statusName << "\n";
+
+ f << "----------\n";
+ //Start block: Type, name
+ f << typeName << " " << server->name() << "\n";
+
+ //Generated variables
+ std::vector<Variable> gvar;
+ snode->genVariables(gvar);
+ for(std::vector<Variable>::const_iterator it = gvar.begin(); it != gvar.end(); ++it)
+ {
+ f << inc << "# edit " << (*it).name() << " '" << (*it).theValue() << "'\n";
+ }
+
+ //Variables
+ std::vector<Variable> var;
+ snode->variables(var);
+ for(std::vector<Variable>::const_iterator it = var.begin(); it != var.end(); ++it)
+ {
+ f << inc << "edit " << (*it).name() << " '" << (*it).theValue() << "'\n";
+ }
+
+ //Print children
+ VNode *vr=server->vRoot();
+ for(unsigned int i=0; i < vr->numOfChildren(); i++)
+ {
+ f << inc << vr->childAt(i)->nodeType() << " " <<
+ vr->childAt(i)->strName() << "\n";
+ }
+
+ //End block
+ f << "end" << typeName << " # " << nodeName << "\n";
+}
+
+void OverviewProvider::nodeInfo(VInfoNode* info,std::stringstream& f)
+{
+ ServerHandler *server=info->server();
+ if(!server) return;
+ //if(!ServerDefsAccess(server).defs()) return;
+
+ VNode* node=info->node();
+ if(!node) return;
+
+ static const std::string inc = " ";
+
+ using namespace boost::posix_time;
+ using namespace boost::gregorian;
+
+ std::string typeName=node->nodeType();
+ std::string nodeName(node->name().toStdString());
+ std::string statusName(node->stateName().toStdString());
+
+ //Header
+ f << "name : " << nodeName << "\n";
+ f << "type : " << typeName << "\n";
+ f << "status : " << statusName << "\n";
+
+ node_ptr nn=node->node();
+
+ boost::posix_time::ptime state_change_time = nn->state_change_time();
+ if(!state_change_time.is_special())
+ {
+ f << "at : " << boost::posix_time::to_simple_string(state_change_time) << "\n";
+ }
+
+ f << "----------\n";
+
+ //Start block: Type, name
+ f << typeName << " " << nodeName << "\n";
+
+ //Clock information for suites
+ if(Suite *suite=nn->isSuite())
+ {
+ //Suite* suite = dynamic_cast<Suite*>(nn);
+ // f << "clock : ";
+ if (suite->clockAttr())
+ {
+ suite->clockAttr().get()->print(f); // f << "\n";
+ }
+ }
+
+ //Default status: the status the node should have when the begin/re-queue is called
+ //if(st != DState::QUEUED && st != DState::UNKNOWN)
+ f << inc << "defstatus " << node->defaultStateName().toStdString() << "\n";
+
+ //Zombies attribute
+ const std::vector<ZombieAttr> & vect = nn->zombies();
+ for (std::vector<ZombieAttr>::const_iterator it = vect.begin(); it != vect.end(); ++it)
+ f << inc << it->toString() << "\n";
+
+ //Autocancel
+ if(nn->hasAutoCancel() && nn->get_autocancel())
+ f << inc << nn->get_autocancel()->toString() << "\n";
+
+ //For suspended nodes
+ if(nn->isSuspended())
+ {
+ f << inc << "# " << typeName << " " << nodeName << " is " << statusName << "\n";
+ }
+
+ if(nn->hasTimeDependencies())
+ {
+ f << inc << "# time-date-dependencies: ";
+ if (nn->isTimeFree()) f << "free\n";
+ else f << "holding\n";
+ }
+
+ //Generated variables
+ std::vector<Variable> gvar;
+ node->genVariables(gvar);
+ for(std::vector<Variable>::const_iterator it = gvar.begin(); it != gvar.end(); ++it)
+ {
+ f << inc << "# edit " << (*it).name() << " '" << (*it).theValue() << "'\n";
+ }
+
+ //Variables
+ std::vector<Variable> var;
+ node->variables(var);
+ for(std::vector<Variable>::const_iterator it = var.begin(); it != var.end(); ++it)
+ {
+ f << inc << "edit " << (*it).name() << " '" << (*it).theValue() << "'\n";
+ }
+
+ //Print children
+ for(unsigned int i=0; i < node->numOfChildren(); i++)
+ {
+ f << inc << node->childAt(i)->nodeType() << " " <<
+ node->childAt(i)->strName() << "\n";
+ }
+
+
+ //Here we should print some additional information from the attributes as well. It is not clear exactly what!
+
+ //End block
+ f << "end" << typeName << " # " << nodeName << "\n";
+}
diff --git a/Viewer/src/OverviewProvider.hpp b/Viewer/src/OverviewProvider.hpp
new file mode 100644
index 0000000..6b87a05
--- /dev/null
+++ b/Viewer/src/OverviewProvider.hpp
@@ -0,0 +1,36 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef OVERVIEWPROVIDER_HPP_
+#define OVERVIEWPROVIDER_HPP_
+
+#include "InfoProvider.hpp"
+
+class InfoPanelItem;
+
+class OverviewProvider : public InfoProvider
+{
+public:
+ explicit OverviewProvider(InfoPresenter* owner);
+
+ //From VInfoVisitor
+ void visit(VInfoServer*);
+ void visit(VInfoNode*);
+ void visit(VInfoAttribute*);
+
+ //From VTaskObserver
+ void taskChanged(VTask_ptr);
+
+protected:
+ void serverInfo(VInfoServer*,std::stringstream& f);
+ void nodeInfo(VInfoNode*,std::stringstream& f);
+
+};
+
+#endif
diff --git a/Viewer/src/Palette.cpp b/Viewer/src/Palette.cpp
new file mode 100644
index 0000000..004a851
--- /dev/null
+++ b/Viewer/src/Palette.cpp
@@ -0,0 +1,115 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "Palette.hpp"
+
+#include "UserMessage.hpp"
+#include "VProperty.hpp"
+
+#include <QApplication>
+#include <QDebug>
+#include <QMap>
+#include <QPalette>
+
+#include <boost/property_tree/json_parser.hpp>
+#include <boost/property_tree/ptree.hpp>
+
+static QMap<std::string,QPalette::ColorRole> paletteId;
+
+Palette::Palette()
+{
+}
+
+void Palette::load(const std::string& parFile)
+{
+
+ if(paletteId.isEmpty())
+ {
+ paletteId["window"]=QPalette::Window;
+ paletteId["windowtext"]=QPalette::WindowText;
+ paletteId["base"]=QPalette::Base;
+ paletteId["alternatebase"]=QPalette::AlternateBase;
+ paletteId["tooltipbase"]=QPalette::ToolTipBase;
+ paletteId["tooltiptext"]=QPalette::ToolTipText;
+ paletteId["text"]=QPalette::Text;
+ paletteId["button"]=QPalette::Button;
+ paletteId["buttontext"]=QPalette::ButtonText;
+ paletteId["brighttext"]=QPalette::BrightText;
+ paletteId["light"]=QPalette::Light;
+ paletteId["midlight"]=QPalette::Midlight;
+ paletteId["dark"]=QPalette::Dark;
+ paletteId["mid"]=QPalette::Mid;
+ paletteId["shadow"]=QPalette::Shadow;
+ paletteId["higlight"]=QPalette::Highlight;
+ paletteId["highlightedtext"]=QPalette::HighlightedText;
+ paletteId["link"]=QPalette::Link;
+ paletteId["linkvisited"]=QPalette::LinkVisited;
+ }
+
+ //Parse param file using the boost JSON property tree parser
+ using boost::property_tree::ptree;
+ ptree pt;
+
+ try
+ {
+ read_json(parFile,pt);
+ }
+ catch (const boost::property_tree::json_parser::json_parser_error& e)
+ {
+ std::string errorMessage = e.what();
+ UserMessage::message(UserMessage::ERROR, true,
+ std::string("Error! Palette::load() unable to parse definition file: " + parFile + " Message: " +errorMessage));
+ return;
+ }
+
+ QPalette palette=qApp->palette();
+
+ for(ptree::const_iterator it = pt.begin(); it != pt.end(); ++it)
+ {
+ std::string name=it->first;
+ ptree ptItem=it->second;
+
+ QPalette::ColorGroup group;
+ if(name == "active")
+ group=QPalette::Active;
+ else if(name == "inactive")
+ group=QPalette::Inactive;
+ else if(name == "disabled")
+ group=QPalette::Disabled;
+ else
+ {
+ UserMessage::message(UserMessage::ERROR, true,
+ std::string("Error! Palette::load() unable to identify group: " + name));
+ continue;
+ }
+
+ for(ptree::const_iterator itItem = ptItem.begin(); itItem != ptItem.end(); ++itItem)
+ {
+ std::string role=itItem->first;
+ std::string val=itItem->second.get_value<std::string>();
+
+ QMap<std::string,QPalette::ColorRole>::const_iterator itP=paletteId.find(role);
+ if(itP != paletteId.end())
+ {
+ QColor col=VProperty::toColour(val);
+ if(col.isValid())
+ {
+ QColor cc=palette.color(group,itP.value());
+ palette.setColor(group,itP.value(),col);
+ }
+ }
+ }
+ }
+
+ qApp->setPalette(palette);
+}
+
+
+
diff --git a/Viewer/src/Palette.hpp b/Viewer/src/Palette.hpp
new file mode 100644
index 0000000..880cd02
--- /dev/null
+++ b/Viewer/src/Palette.hpp
@@ -0,0 +1,24 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VIEWER_SRC_PALETTE_HPP_
+#define VIEWER_SRC_PALETTE_HPP_
+
+#include <string>
+
+class Palette
+{
+public:
+ Palette();
+ static void load(const std::string& parFile);
+};
+
+
+#endif /* VIEWER_SRC_PALETTE_HPP_ */
diff --git a/Viewer/src/PlainTextEdit.cpp b/Viewer/src/PlainTextEdit.cpp
new file mode 100644
index 0000000..a65ea53
--- /dev/null
+++ b/Viewer/src/PlainTextEdit.cpp
@@ -0,0 +1,529 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "PlainTextEdit.hpp"
+
+#include "GotoLineDialog.hpp"
+
+#include <QtGlobal>
+#include <QDebug>
+#include <QFile>
+#include <QPainter>
+#include <QTextBlock>
+#include <QWheelEvent>
+
+#include "VConfig.hpp"
+
+PlainTextEdit::PlainTextEdit(QWidget * parent) :
+ QPlainTextEdit(parent),
+ showLineNum_(true),
+ rightMargin_(2),
+ gotoLineDialog_(0),
+ fontProp_(NULL),
+ numAreaBgCol_(232,231,230),
+ numAreaFontCol_(102,102,102),
+ numAreaSeparatorCol_(210,210,210),
+ numAreaCurrentCol_(212,212,255)
+{
+ lineNumArea_ = new LineNumberArea(this);
+
+ connect(this,SIGNAL(blockCountChanged(int)),
+ this,SLOT(updateLineNumberAreaWidth(int)));
+
+ connect(this,SIGNAL(updateRequest(QRect,int)),
+ this,SLOT(updateLineNumberArea(QRect,int)));
+
+ connect(this,SIGNAL(cursorPositionChanged()),
+ lineNumArea_,SLOT(update()));
+
+
+ if(VProperty* p=VConfig::instance()->find("view.textEdit.numAreaBackground"))
+ numAreaBgCol_=p->value().value<QColor>();
+
+ if(VProperty* p=VConfig::instance()->find("view.textEdit.numAreaFontColour"))
+ numAreaFontCol_=p->value().value<QColor>();
+
+ if(VProperty* p=VConfig::instance()->find("view.textEdit.numAreaSeparator"))
+ numAreaSeparatorCol_=p->value().value<QColor>();
+
+ if(VProperty* p=VConfig::instance()->find("view.textEdit.numAreaCurrent"))
+ numAreaCurrentCol_=p->value().value<QColor>();
+
+ updateLineNumberAreaWidth(0);
+
+ //QFont f("Courier");
+ QFont f("Monospace");
+ f.setStyleHint(QFont::TypeWriter);
+ f.setFixedPitch(true);
+ f.setPointSize(10);
+ f.setStyleStrategy(QFont::PreferAntialias);
+ setFont(f);
+}
+
+PlainTextEdit::~PlainTextEdit()
+{
+ if (gotoLineDialog_)
+ delete gotoLineDialog_;
+
+ if(fontProp_)
+ fontProp_->removeObserver(this);
+}
+
+void PlainTextEdit::setShowLineNumbers(bool b)
+{
+ showLineNum_ = b;
+ lineNumArea_->setVisible(b);
+ updateLineNumberAreaWidth(0);
+}
+
+
+// ---------------------------------------------------------------------------
+// TextEdit::cursorRowCol
+// returns the row and column position of the cursor
+// - note that the first row and column are (1,1)
+// ---------------------------------------------------------------------------
+
+void PlainTextEdit::cursorRowCol(int *row, int *col)
+{
+ const QTextCursor cursor = textCursor();
+
+ QTextBlock cb, b;
+ int column, line = 1;
+ cb = cursor.block();
+ column = (cursor.position() - cb.position()) + 1;
+
+ // find the line number - is there a better way than this?
+
+ for (b = document()->begin(); b != document()->end(); b = b.next())
+ {
+ if( b==cb ) break;
+ line++;
+ }
+
+ *row = line;
+ *col = column;
+}
+
+
+// ---------------------------------------------------------------------------
+// TextEdit::characterBehindCursor
+// returns the character to the left of the text cursor
+// ---------------------------------------------------------------------------
+
+QChar PlainTextEdit::characterBehindCursor(QTextCursor *cursor)
+{
+ QTextCursor docTextCursor = textCursor();
+ QTextCursor *theCursor = (cursor == 0) ? &docTextCursor : cursor;
+ return document()->characterAt(theCursor->position() - 1);
+}
+
+// ---------------------------------------------------------------------------
+// TextEdit::numLinesSelected
+// returns the number of lines in the current selection
+// yes - all this code to do that!
+// ---------------------------------------------------------------------------
+
+int PlainTextEdit::numLinesSelected()
+{
+ QTextCursor cursor = textCursor(); // get the document's cursor
+ int selStart = cursor.selectionStart();
+ int selEnd = cursor.selectionEnd();
+ QTextBlock bStart = document()->findBlock(selStart);
+ QTextBlock bEnd = document()->findBlock(selEnd);
+ int lineStart = bStart.firstLineNumber();
+ int lineEnd = bEnd.firstLineNumber();
+ int numLines = (lineEnd - lineStart) + 1;
+
+ return numLines;
+}
+
+// ---------------------------------------------------------------------------
+// TextEdit::lineNumberAreaWidth
+// returns the required width to display the line numbers. This adapts to the
+// maximum number of digits we need to display.
+// ---------------------------------------------------------------------------
+
+int PlainTextEdit::lineNumberAreaWidth()
+{
+ if (showLineNumbers())
+ {
+ int digits = 1;
+ int max = qMax(1, blockCount());
+ while (max >= 10)
+ {
+ max /= 10;
+ ++digits;
+ }
+
+ int space = 3 + fontMetrics().width(QLatin1Char('9')) * digits + rightMargin_;
+
+ return space;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+// ---------------------------------------------------------------------------
+// TextEdit::updateLineNumberAreaWidth
+// called when the number of lines in the document changes. The argument is
+// the new number of lines (blocks).
+// ---------------------------------------------------------------------------
+
+void PlainTextEdit::updateLineNumberAreaWidth(int)
+{
+ setViewportMargins(lineNumberAreaWidth(), 0, 0, 0);
+}
+
+
+// ---------------------------------------------------------------------------
+// TextEdit::updateLineNumberArea
+// called when the editor is updated. We want to ensure that the line number
+// widget stays in sync with it.
+// ---------------------------------------------------------------------------
+
+void PlainTextEdit::updateLineNumberArea(const QRect &rect, int dy)
+{
+ if (dy)
+ lineNumArea_->scroll(0, dy);
+ else
+ lineNumArea_->update(0, rect.y(), lineNumArea_->width(), rect.height());
+
+ if (rect.contains(viewport()->rect()))
+ updateLineNumberAreaWidth(0);
+}
+
+
+// ---------------------------------------------------------------------------
+// TextEdit::resizeEvent
+// called when a resize event is triggered. Reset the size of the line widget.
+// ---------------------------------------------------------------------------
+
+void PlainTextEdit::resizeEvent(QResizeEvent *e)
+{
+ QPlainTextEdit::resizeEvent(e);
+
+ QRect cr = contentsRect();
+ lineNumArea_->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height()));
+}
+
+
+// ---------------------------------------------------------------------------
+// TextEdit::focusInEvent
+// called when the widget gains input focus
+// ---------------------------------------------------------------------------
+
+void PlainTextEdit::focusInEvent(QFocusEvent *event)
+{
+ Q_EMIT focusRegained();
+ QPlainTextEdit::focusInEvent(event);
+}
+
+
+// ---------------------------------------------------------------------------
+// TextEdit::focusOutEvent
+// called when the widget loses input focus
+
+// ---------------------------------------------------------------------------
+
+void PlainTextEdit::focusOutEvent(QFocusEvent *event)
+{
+ Q_EMIT focusLost();
+ QPlainTextEdit::focusOutEvent(event);
+}
+
+// ---------------------------------------------------------------------------
+// TextEdit::lineNumberAreaPaintEvent
+// called when the line number widget needs to be repainted. This is where we
+// actually draw the numbers on the widget.
+// ---------------------------------------------------------------------------
+
+void PlainTextEdit::lineNumberAreaPaintEvent(QPaintEvent *event)
+{
+ int currentRow, currentCol;
+ cursorRowCol (¤tRow, ¤tCol); // get the current line number so we can highlight it
+
+
+ QPainter painter(lineNumArea_);
+ painter.fillRect(event->rect(), numAreaBgCol_); // light grey background
+
+ painter.setPen(QPen(numAreaSeparatorCol_));
+ painter.drawLine(event->rect().topRight(),event->rect().bottomRight());
+
+ QTextBlock block = firstVisibleBlock();
+ int blockNumber = block.blockNumber();
+ int top = (int) blockBoundingGeometry(block).translated(contentOffset()).top();
+ int bottom = top + (int) blockBoundingRect(block).height();
+ QFont fontNormal(font()); // the font to use for most line numbers
+ QFont fontBold(fontNormal); // the font to use for the current line number
+ fontBold.setBold(true);
+ //painter.setPen(Qt::blue);
+ painter.setPen(numAreaFontCol_);
+
+ painter.setFont(fontNormal);
+
+ while (block.isValid() && top <= event->rect().bottom())
+ {
+ if (block.isVisible() && bottom >= event->rect().top())
+ {
+ QString number = QString::number(blockNumber + 1);
+
+ if (blockNumber == currentRow-1) // is this the current line?
+ {
+ painter.setFont(fontBold);
+ painter.fillRect(0, top, lineNumArea_->width()-rightMargin_, fontMetrics().height(), numAreaCurrentCol_); // highlight the background
+ }
+
+
+ painter.drawText(0, top, lineNumArea_->width()-rightMargin_, fontMetrics().height(), // draw the line number
+ Qt::AlignRight, number);
+
+
+ if (blockNumber == currentRow-1) // is this the current line?
+ {
+ painter.setFont(fontNormal); // reset the font to normal
+ }
+ }
+
+ block = block.next();
+ top = bottom;
+ bottom = top + (int) blockBoundingRect(block).height();
+ ++blockNumber;
+ }
+}
+
+
+QString PlainTextEdit::emptyString_ ; // used as a default argument to findString()
+
+bool PlainTextEdit::findString(const QString &s,QTextDocument::FindFlags flags, bool replace, const QString &r)
+{
+
+ lastFindString_ = s; // store for repeat searches
+ lastFindFlags_ = flags; // store for repeat searches
+ bool found = false;
+
+ if (find(s,flags)) // find and select the string - were we successful?
+ {
+ //statusMessage("", 0);
+ found = true;
+ }
+ else // did not find the string
+ {
+ if (1) // 'wraparound' search - on by default, we can add a user option if it might be useful to turn it off
+ {
+ QTextCursor original_cursor = textCursor(); // get the document's cursor
+ QTextCursor cursor(original_cursor);
+
+ if (flags & QTextDocument::FindBackward) // move to the start or end of the document to continue the search
+ cursor.movePosition(QTextCursor::End);
+ else
+ cursor.movePosition(QTextCursor::Start);
+
+ setTextCursor(cursor); // send the cursor back to the document
+
+ if (find(s,flags)) // search again, from the new position
+ {
+ //statusMessage("", 0);
+ found = true;
+ }
+ else
+ {
+ setTextCursor(original_cursor); // not found - restore the cursor to its original position
+ }
+ }
+ }
+
+
+ if (found)
+ {
+ if (replace)
+ {
+ // perform the 'replace'
+ insertPlainText (r);
+
+ // highlight the replaced text - the current text cursor will be
+ // at the end of the replaced text, so we move it back to the start
+ // (anchored so that the text is selected)
+ QTextCursor cursor = textCursor(); // get the document's cursor
+ cursor.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor, r.length());
+ setTextCursor(cursor); // send the cursor back to the document
+ }
+ ensureCursorVisible();
+ }
+
+ else
+ {
+ //statusMessage(tr("Searched whole file, string not found"), 5000);
+ }
+
+ return found;
+}
+
+
+// ---------------------------------------------------------------------------
+// TextEdit::gotoLine
+// triggered when the user asks to bring up the 'go to line' dialog
+// ---------------------------------------------------------------------------
+
+void PlainTextEdit::gotoLine()
+{
+ // create the dialog if it does not already exist
+
+ if (!gotoLineDialog_)
+ {
+ gotoLineDialog_ = new GotoLineDialog(this);
+
+ connect(gotoLineDialog_, SIGNAL(gotoLine(int)), this, SLOT(gotoLine(int)));
+ }
+
+
+ // if created, set it up and display it
+
+ if (gotoLineDialog_)
+ {
+ gotoLineDialog_->show();
+ gotoLineDialog_->raise();
+ gotoLineDialog_->activateWindow();
+ gotoLineDialog_->setupUIBeforeShow();
+ }
+}
+
+// ---------------------------------------------------------------------------
+// TextEdit::gotoLine
+// triggered from the GotoLine dialog when the user wants to go to that line
+// ---------------------------------------------------------------------------
+
+void PlainTextEdit::gotoLine(int line)
+{
+ int bn = 0;
+ QTextBlock b;
+
+ if (line <= document()->blockCount())
+ {
+ for (b = document()->begin(); b != document()->end(); b = b.next())
+ {
+ if (bn == line-1)
+ {
+ QTextCursor cursor = textCursor(); // get the document's cursor
+ cursor.setPosition (b.position()); // set it to the right position
+ cursor.select(QTextCursor::LineUnderCursor); // select the whole line
+ setTextCursor(cursor); // send the cursor back to the document
+ break;
+ }
+ bn++;
+ }
+ }
+
+ else
+ {
+ // line number outside range of line numbers
+ // TODO: disable the 'ok' button if the number is out of range
+ }
+}
+
+//---------------------------------------------
+// Fontsize management
+//---------------------------------------------
+
+void PlainTextEdit::setFontProperty(VProperty* p)
+{
+ fontProp_=p;
+ fontProp_->addObserver(this);
+ updateFont();
+}
+
+void PlainTextEdit::wheelEvent(QWheelEvent *event)
+{
+ int fps=font().pointSize();
+
+ if(isReadOnly())
+ {
+ QPlainTextEdit::wheelEvent(event);
+ if(font().pointSize() != fps)
+ fontSizeChangedByZoom();
+ }
+ //For readOnly document the zoom does not work so we
+ //need this custom code!
+ else
+ {
+ if(event->modifiers() & Qt::ControlModifier)
+ {
+ const int delta = event->delta();
+ if (delta < 0)
+ slotZoomOut();
+ else if (delta > 0)
+ slotZoomIn();
+ return;
+ }
+
+ QPlainTextEdit::wheelEvent(event);
+ }
+}
+
+void PlainTextEdit::slotZoomIn()
+{
+#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 1)
+ zoomIn();
+#else
+ QFont f=font();
+ int fps=f.pointSize();
+ f.setPointSize(fps+1);
+ setFont(f);
+#endif
+ fontSizeChangedByZoom();
+}
+
+void PlainTextEdit::slotZoomOut()
+{
+ int oriSize=font().pointSize();
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 1)
+ zoomOut();
+#else
+ QFont f=font();
+ int fps=f.pointSize();
+ if(fps > 1)
+ {
+ f.setPointSize(fps-1);
+ setFont(f);
+ }
+#endif
+
+ if(font().pointSize() != oriSize)
+ fontSizeChangedByZoom();
+}
+
+void PlainTextEdit::fontSizeChangedByZoom()
+{
+ if(fontProp_)
+ fontProp_->setValue(font());
+}
+
+void PlainTextEdit::updateFont()
+{
+ if(fontProp_)
+ {
+ QFont f=fontProp_->value().value<QFont>();
+ if(font() != f)
+ setFont(f);
+ }
+}
+
+void PlainTextEdit::notifyChange(VProperty* p)
+{
+ if(fontProp_ ==p)
+ {
+ setFont(p->value().value<QFont>());
+ }
+}
+
+
+
+
diff --git a/Viewer/src/PlainTextEdit.hpp b/Viewer/src/PlainTextEdit.hpp
new file mode 100644
index 0000000..37b337f
--- /dev/null
+++ b/Viewer/src/PlainTextEdit.hpp
@@ -0,0 +1,98 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef TEXTEDIT_HPP_
+#define TEXTEDIT_HPP_
+
+#include <QPlainTextEdit>
+
+#include "VProperty.hpp"
+
+class LineNumberArea;
+class GotoLineDialog;
+
+class PlainTextEdit : public QPlainTextEdit, public VPropertyObserver
+{
+Q_OBJECT
+
+public:
+ explicit PlainTextEdit(QWidget* parent = 0);
+ ~PlainTextEdit();
+
+ void lineNumberAreaPaintEvent(QPaintEvent *event);
+ int lineNumberAreaWidth();
+
+ bool showLineNumbers() {return showLineNum_;}
+ void setShowLineNumbers(bool b);
+
+ void cursorRowCol(int *row, int *col);
+ QChar characterBehindCursor(QTextCursor *cursor=0);
+
+ int numLinesSelected();
+ bool findString(const QString &,QTextDocument::FindFlags,bool replace=false,const QString &r=emptyString_);
+
+ void setFontProperty(VProperty* p);
+ void updateFont();
+ void notifyChange(VProperty* p);
+
+public Q_SLOTS:
+ void gotoLine();
+ void slotZoomIn();
+ void slotZoomOut();
+
+private Q_SLOTS:
+ void updateLineNumberAreaWidth(int newBlockCount);
+ void updateLineNumberArea(const QRect &, int);
+ void gotoLine(int line);
+
+Q_SIGNALS:
+ void focusRegained ();
+ void focusLost();
+ void fontSizeChangedByWheel();
+
+protected:
+ void resizeEvent(QResizeEvent *event);
+ void focusInEvent(QFocusEvent *event);
+ void focusOutEvent(QFocusEvent *event);
+ void wheelEvent(QWheelEvent *event);
+
+private:
+ void fontSizeChangedByZoom();
+
+ bool showLineNum_;
+ QWidget *lineNumArea_;
+ int rightMargin_;
+ QString lastFindString_;
+ QTextDocument::FindFlags lastFindFlags_;
+ GotoLineDialog *gotoLineDialog_;
+ static QString emptyString_;
+
+ QColor numAreaBgCol_;
+ QColor numAreaFontCol_;
+ QColor numAreaSeparatorCol_;
+ QColor numAreaCurrentCol_;
+ VProperty *fontProp_;
+};
+
+
+class LineNumberArea : public QWidget
+{
+public:
+ explicit LineNumberArea(PlainTextEdit *editor) : QWidget(editor) {textEditor = editor;}
+ QSize sizeHint() const {return QSize(textEditor->lineNumberAreaWidth(), 0);}
+
+protected:
+ void paintEvent(QPaintEvent *event) { textEditor->lineNumberAreaPaintEvent(event);}
+
+private:
+ PlainTextEdit *textEditor;
+};
+
+
+#endif
diff --git a/Viewer/src/PlainTextSearchInterface.cpp b/Viewer/src/PlainTextSearchInterface.cpp
new file mode 100644
index 0000000..c7b02ff
--- /dev/null
+++ b/Viewer/src/PlainTextSearchInterface.cpp
@@ -0,0 +1,212 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "PlainTextSearchInterface.hpp"
+
+#include <QPlainTextEdit>
+
+
+bool PlainTextSearchInterface::findString (QString str, bool highlightAll, QTextDocument::FindFlags flags,
+ bool gotoStartOfWord, int iteration,StringMatchMode::Mode matchMode)
+{
+ if(!editor_)
+ return false;
+
+ if(editor_->document()->isEmpty())
+ return false;
+
+ QTextCursor cursor(editor_->textCursor());
+
+ if (highlightAll) // if highlighting all matches, start from the start of the document
+ cursor.movePosition(QTextCursor::Start);
+
+ else if (gotoStartOfWord) // go to start of word?
+ cursor.movePosition(QTextCursor::StartOfWord);
+
+
+ QList<QTextEdit::ExtraSelection> extraSelections;
+ bool found = false;
+ bool keepGoing = true;
+ int numMatches = 0;
+
+ Qt::CaseSensitivity cs = (flags & QTextDocument::FindCaseSensitively) ? Qt::CaseSensitive : Qt::CaseInsensitive;
+
+ while (keepGoing)
+ {
+ switch (matchMode)
+ {
+ case StringMatchMode::ContainsMatch:
+ {
+ cursor = editor_->document()->find(str, cursor, flags); // perform the search
+ found = (!cursor.isNull());
+
+ break;
+ }
+ case StringMatchMode::WildcardMatch:
+ {
+ QRegExp regexp(str);
+ regexp.setCaseSensitivity(cs);
+ regexp.setPatternSyntax(QRegExp::Wildcard);
+
+ cursor = editor_->document()->find(regexp, cursor, flags); // perform the search
+ found = (!cursor.isNull());
+
+ break;
+ }
+ case StringMatchMode::RegexpMatch:
+ {
+ QRegExp regexp(str);
+ regexp.setCaseSensitivity(cs);
+
+ cursor = editor_->document()->find(regexp, cursor, flags); // perform the search
+ found = (!cursor.isNull());
+
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+
+
+ if (found)
+ {
+ if (highlightAll)
+ {
+ QTextEdit::ExtraSelection highlight;
+ highlight.cursor = cursor;
+ highlight.format.setBackground(highlightColour_);
+ extraSelections << highlight;
+ numMatches++;
+ }
+ else
+ {
+ editor_->setTextCursor(cursor); // mark the selection of the match
+ }
+ }
+
+
+ if (found && !highlightAll) // found a match and we only want one - stop here and select it
+ keepGoing = false;
+
+ else if (!found && !highlightAll && (iteration != 0)) // didn't find a match, only want one, we HAVE wrapped around
+ keepGoing = false;
+
+ if (!found && highlightAll) // want to highlight all, but no more matches found
+ keepGoing = false;
+
+
+
+ // not found, and we only want one match, then we need to wrap around and keep going
+ if (keepGoing)
+ {
+ if (!highlightAll)
+ {
+ cursor=editor_->textCursor();
+ if (flags & QTextDocument::FindBackward)
+ cursor.movePosition(QTextCursor::End);
+ else
+ cursor.movePosition(QTextCursor::Start);
+ editor_->setTextCursor(cursor);
+ iteration = 1; // iteration=1 to avoid infinite wraparound!
+ }
+ }
+ }
+
+
+ if (highlightAll)
+ {
+ //char num[64];
+ //sprintf(num, "%d", numMatches);
+ //UserMessage::message(UserMessage::DBG, false," highlighting : " + std::string(num));
+
+ editor_->setExtraSelections( extraSelections );
+ }
+
+ return (found);
+}
+
+void PlainTextSearchInterface::automaticSearchForKeywords(bool userClickedReload)
+{
+ if(editor_->document()->isEmpty())
+ return;
+
+ bool found = false;
+
+ QTextDocument::FindFlags findFlags = QTextDocument::FindBackward;
+ QTextCursor cursor(editor_->textCursor());
+ cursor.movePosition(QTextCursor::End);
+
+ QRegExp regexp("--(abort|complete)");
+ QTextCursor findCursor = editor_->document()->find(regexp, cursor, findFlags); // perform the search
+ found = (!findCursor.isNull());
+ if(found)
+ {
+ editor_->setTextCursor(findCursor);
+ }
+
+#if 0
+ QStringList keywords;
+ keywords << "--abort" << "--complete";// << "xabort" << "xcomplete"
+ << "System Billing Units";
+
+ // find any of the keywords and stop at the first one
+ int i = 0;
+ while (!found && i < keywords.size())
+ {
+ cursor.movePosition(QTextCursor::End);
+ textEdit_->setTextCursor(cursor);
+ found = textEdit_->findString(keywords.at(i), findFlags);
+ i++;
+ }
+#endif
+
+ else
+ {
+ if(userClickedReload)
+ {
+ // move the cursor to the start of the last line
+ QTextCursor cursor = editor_->textCursor();
+ cursor.movePosition(QTextCursor::End);
+ cursor.movePosition(QTextCursor::StartOfLine);
+ editor_->setTextCursor(cursor);
+ }
+ }
+}
+
+void PlainTextSearchInterface::refreshSearch()
+{
+ if(!editor_)
+ return;
+
+ QTextCursor cursor(editor_->textCursor());
+ if (cursor.hasSelection())
+ {
+ cursor.movePosition(QTextCursor::StartOfLine, QTextCursor::MoveAnchor);
+ editor_->setTextCursor(cursor);
+ }
+}
+
+
+void PlainTextSearchInterface::clearHighlights()
+{
+ if(!editor_)
+ return;
+
+ QList<QTextEdit::ExtraSelection> empty;
+ editor_->setExtraSelections(empty);
+}
+
+void PlainTextSearchInterface::disableHighlights()
+{
+ clearHighlights();
+}
diff --git a/Viewer/src/PlainTextSearchInterface.hpp b/Viewer/src/PlainTextSearchInterface.hpp
new file mode 100644
index 0000000..b77c259
--- /dev/null
+++ b/Viewer/src/PlainTextSearchInterface.hpp
@@ -0,0 +1,40 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VIEWER_SRC_PLAINTEXTSEARCHINTERFACE_HPP_
+#define VIEWER_SRC_PLAINTEXTSEARCHINTERFACE_HPP_
+
+#include "AbstractTextEditSearchInterface.hpp"
+
+class QPlainTextEdit;
+
+class PlainTextSearchInterface : public AbstractTextEditSearchInterface
+{
+public:
+ PlainTextSearchInterface() : editor_(NULL) {}
+ void setEditor(QPlainTextEdit* e) {editor_=e;}
+
+ bool findString (QString str, bool highlightAll, QTextDocument::FindFlags findFlags,
+ bool gotoStartOfWord, int iteration,StringMatchMode::Mode matchMode);
+
+ void automaticSearchForKeywords(bool);
+ void refreshSearch();
+ void clearHighlights();
+ void disableHighlights();
+ void enableHighlights() {}
+ bool highlightsNeedSearch() {return true;}
+
+protected:
+
+ QPlainTextEdit *editor_;
+
+};
+
+#endif /* VIEWER_SRC_PLAINTEXTSEARCHINTERFACE_HPP_ */
diff --git a/Viewer/src/PlainTextSearchLine.cpp b/Viewer/src/PlainTextSearchLine.cpp
new file mode 100644
index 0000000..855145e
--- /dev/null
+++ b/Viewer/src/PlainTextSearchLine.cpp
@@ -0,0 +1,333 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "PlainTextSearchLine.hpp"
+#include "PlainTextSearchInterface.hpp"
+
+#include <assert.h>
+
+PlainTextSearchLine::PlainTextSearchLine(QWidget *parent) :
+ TextEditSearchLine(parent)
+{
+ interface_=new PlainTextSearchInterface;
+ TextEditSearchLine::setSearchInterface(interface_);
+}
+
+PlainTextSearchLine::~PlainTextSearchLine()
+{
+ delete interface_;
+}
+
+void PlainTextSearchLine::setEditor(QPlainTextEdit *e)
+{
+ PlainTextSearchInterface *pti=static_cast<PlainTextSearchInterface*>(interface_);
+ assert(pti);
+ pti->setEditor(e);
+}
+
+
+#if 0
+PlainTextSearchLine::PlainTextSearchLine(QWidget *parent) :
+ AbstractSearchLine(parent),
+ editor_(0),
+ highlightColour_(QColor(200, 255, 200))
+{
+ connect(matchModeCb_,SIGNAL(currentIndexChanged(int)),
+ this, SLOT(matchModeChanged(int)));
+
+ if(VProperty *p=VConfig::instance()->find("panel.search.highlightColour"))
+ {
+ highlightColour_=p->value().value<QColor>();
+ }
+}
+
+PlainTextSearchLine::~PlainTextSearchLine()
+{
+
+}
+
+void PlainTextSearchLine::setEditor(QPlainTextEdit *e)
+{
+ editor_=e;
+}
+
+
+bool PlainTextSearchLine::findString (QString str, bool highlightAll, QTextDocument::FindFlags extraFlags, bool gotoStartOfWord, int iteration)
+{
+ QTextDocument::FindFlags flags = findFlags() | extraFlags;
+
+ QTextCursor cursor(editor_->textCursor());
+
+ if (highlightAll) // if highlighting all matches, start from the start of the document
+ cursor.movePosition(QTextCursor::Start);
+
+ else if (gotoStartOfWord) // go to start of word?
+ cursor.movePosition(QTextCursor::StartOfWord);
+
+
+ QList<QTextEdit::ExtraSelection> extraSelections;
+ bool found = false;
+ bool keepGoing = true;
+ int numMatches = 0;
+
+ Qt::CaseSensitivity cs = (flags & QTextDocument::FindCaseSensitively) ? Qt::CaseSensitive : Qt::CaseInsensitive;
+
+ while (keepGoing)
+ {
+ switch (matchModeCb_->currentMatchMode())
+ {
+ case StringMatchMode::ContainsMatch:
+ {
+ cursor = editor_->document()->find(str, cursor, flags); // perform the search
+ found = (!cursor.isNull());
+
+ break;
+ }
+ case StringMatchMode::WildcardMatch:
+ {
+ QRegExp regexp(str);
+ regexp.setCaseSensitivity(cs);
+ regexp.setPatternSyntax(QRegExp::Wildcard);
+
+ cursor = editor_->document()->find(regexp, cursor, flags); // perform the search
+ found = (!cursor.isNull());
+
+ break;
+ }
+ case StringMatchMode::RegexpMatch:
+ {
+ QRegExp regexp(str);
+ regexp.setCaseSensitivity(cs);
+
+ cursor = editor_->document()->find(regexp, cursor, flags); // perform the search
+ found = (!cursor.isNull());
+
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+
+
+ if (found)
+ {
+ if (highlightAll)
+ {
+ QTextEdit::ExtraSelection highlight;
+ highlight.cursor = cursor;
+ highlight.format.setBackground(highlightColour_);
+ extraSelections << highlight;
+ numMatches++;
+ }
+ else
+ {
+ editor_->setTextCursor(cursor); // mark the selection of the match
+ }
+ }
+
+
+ if (found && !highlightAll) // found a match and we only want one - stop here and select it
+ keepGoing = false;
+
+ else if (!found && !highlightAll && (iteration != 0)) // didn't find a match, only want one, we HAVE wrapped around
+ keepGoing = false;
+
+ if (!found && highlightAll) // want to highlight all, but no more matches found
+ keepGoing = false;
+
+
+
+ // not found, and we only want one match, then we need to wrap around and keep going
+ if (keepGoing)
+ {
+ if (!highlightAll)
+ {
+ cursor=editor_->textCursor();
+ if (extraFlags & QTextDocument::FindBackward)
+ cursor.movePosition(QTextCursor::End);
+ else
+ cursor.movePosition(QTextCursor::Start);
+ editor_->setTextCursor(cursor);
+ iteration = 1; // iteration=1 to avoid infinite wraparound!
+ }
+ }
+ }
+
+
+ if (highlightAll)
+ {
+ //char num[64];
+ //sprintf(num, "%d", numMatches);
+ //UserMessage::message(UserMessage::DBG, false," highlighting : " + std::string(num));
+
+ editor_->setExtraSelections( extraSelections );
+ }
+
+ return (found);
+}
+
+
+
+void PlainTextSearchLine::highlightMatches(QString txt)
+{
+ if (!txt.isEmpty())
+ findString(txt, true, 0, true, 0); // highlight all matches
+}
+
+
+void PlainTextSearchLine::slotHighlight()
+{
+ //UserMessage::message(UserMessage::DBG, false," highlight: " + searchLine_->text().toStdString());
+
+ highlightAllTimer_.stop();
+
+ if (highlightAll())
+ highlightMatches(searchLine_->text());
+}
+
+
+void PlainTextSearchLine::slotFind(QString txt)
+{
+ if(!editor_)
+ return;
+
+ highlightAllTimer_.stop();
+ bool found = findString(txt, false, 0, true, 0); // find the next match
+
+ if (!isEmpty()) // there is a search term supplied by the user
+ {
+ // don't highlight the matches immediately - this can be expensive for large files,
+ // and we don't want to highlight each time the user types a new character; wait
+ // a moment and then start the highlight
+ highlightAllTimer_.setInterval(500);
+ highlightAllTimer_.disconnect();
+ connect(&highlightAllTimer_, SIGNAL(timeout()), this, SLOT(slotHighlight()));
+ highlightAllTimer_.start();
+ }
+ else
+ {
+ clearHighlights();
+ }
+
+ updateButtons(found);
+}
+
+void PlainTextSearchLine::slotFindNext()
+{
+ if(!editor_)
+ return;
+
+ bool found = findString(searchLine_->text(), false, 0, false, 0);
+ updateButtons(found);
+}
+
+void PlainTextSearchLine::slotFindPrev()
+{
+ if(!editor_)
+ return;
+
+ bool found = findString(searchLine_->text(), false, QTextDocument::FindBackward, false, 0);
+ updateButtons(found);
+}
+
+QTextDocument::FindFlags PlainTextSearchLine::findFlags()
+{
+ QTextDocument::FindFlags flags;
+
+ if(caseSensitive())
+ {
+ flags = flags | QTextDocument::FindCaseSensitively;
+ }
+
+ if(wholeWords())
+ {
+ flags = flags | QTextDocument::FindWholeWords;
+ }
+
+ return flags;
+}
+
+
+
+
+
+// PlainTextSearchLine::refreshSearch
+// performed when the user changes search parameters such as case sensitivity - we want to
+// re-do the search from the current point, but if the current selection still matches then
+// we'd like it to be found first.
+
+void PlainTextSearchLine::refreshSearch()
+{
+ // if there's something selected already then move the cursor to the start of the line and search again
+ QTextCursor cursor(editor_->textCursor());
+ if (cursor.hasSelection())
+ {
+ cursor.movePosition(QTextCursor::StartOfLine, QTextCursor::MoveAnchor);
+ editor_->setTextCursor(cursor);
+ }
+ slotFindNext();
+ slotHighlight();
+}
+
+
+void PlainTextSearchLine::clearHighlights()
+{
+ QList<QTextEdit::ExtraSelection> empty;
+ editor_->setExtraSelections(empty);
+}
+
+
+void PlainTextSearchLine::matchModeChanged(int notUsed)
+{
+ if(matchModeCb_->currentMatchMode() == StringMatchMode::ContainsMatch)
+ actionWholeWords_->setEnabled(true);
+ else
+ actionWholeWords_->setEnabled(false);
+
+ refreshSearch();
+}
+
+
+void PlainTextSearchLine::on_actionCaseSensitive__toggled(bool b)
+{
+ AbstractSearchLine::on_actionCaseSensitive__toggled(b);
+
+ refreshSearch();
+}
+
+
+void PlainTextSearchLine::on_actionWholeWords__toggled(bool b)
+{
+ AbstractSearchLine::on_actionWholeWords__toggled(b);
+
+ refreshSearch();
+}
+
+void PlainTextSearchLine::on_actionHighlightAll__toggled(bool b)
+{
+ AbstractSearchLine::on_actionHighlightAll__toggled(b);
+
+ if (b) // user switched on the highlights
+ slotHighlight();
+ else // user switched off the highlights
+ clearHighlights();
+
+
+ refreshSearch();
+}
+
+void PlainTextSearchLine::slotClose()
+{
+ AbstractSearchLine::slotClose();
+ clearHighlights();
+}
+#endif
diff --git a/Viewer/src/PlainTextSearchLine.hpp b/Viewer/src/PlainTextSearchLine.hpp
new file mode 100644
index 0000000..672a72c
--- /dev/null
+++ b/Viewer/src/PlainTextSearchLine.hpp
@@ -0,0 +1,69 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef PLAINTEXTSEARCHLINE_HPP_
+#define PLAINTEXTSEARCHLINE_HPP_
+
+#include <QPlainTextEdit>
+
+#include "TextEditSearchLine.hpp"
+
+class AbstractTextSearchInterface;
+
+class PlainTextSearchLine : public TextEditSearchLine
+{
+public:
+ explicit PlainTextSearchLine(QWidget *parent=0);
+ ~PlainTextSearchLine();
+ void setEditor(QPlainTextEdit*);
+
+private:
+ //The interface is set internally
+ void setSearchInterface(AbstractTextSearchInterface*) {};
+
+};
+
+
+#if 0
+class PlainTextSearchLine : public AbstractSearchLine
+{
+ Q_OBJECT
+
+public:
+ explicit PlainTextSearchLine(QWidget *parent);
+ ~PlainTextSearchLine();
+ void setEditor(QPlainTextEdit*);
+
+public Q_SLOTS:
+ void slotFind(QString);
+ void slotFindNext();
+ void slotFindPrev();
+ void slotFindNext(bool) {slotFindNext();}
+ void slotFindPrev(bool) {slotFindPrev();}
+ void matchModeChanged(int newIndex);
+ void on_actionCaseSensitive__toggled(bool);
+ void on_actionWholeWords__toggled(bool);
+ void on_actionHighlightAll__toggled(bool);
+ void slotClose();
+ void slotHighlight();
+
+protected:
+ QTextDocument::FindFlags findFlags();
+ bool findString (QString str, bool highlightAll, QTextDocument::FindFlags extraFlags, bool gotoStartOfWord, int iteration);
+ void refreshSearch();
+ void highlightMatches(QString txt);
+ void clearHighlights();
+ QTimer highlightAllTimer_;
+ QPlainTextEdit* editor_;
+ QColor highlightColour_;
+};
+#endif
+
+
+#endif
diff --git a/Viewer/src/PropertyDialog.cpp b/Viewer/src/PropertyDialog.cpp
new file mode 100644
index 0000000..df448a1
--- /dev/null
+++ b/Viewer/src/PropertyDialog.cpp
@@ -0,0 +1,212 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "PropertyDialog.hpp"
+
+#include <QAbstractButton>
+#include <QCloseEvent>
+#include <QSettings>
+
+#include "ConfigListDelegate.hpp"
+#include "IconProvider.hpp"
+#include "PropertyEditor.hpp"
+#include "SessionHandler.hpp"
+#include "VConfig.hpp"
+#include "VConfigLoader.hpp"
+#include "VProperty.hpp"
+
+VProperty* PropertyDialog::prop_=0;
+
+PropertyDialog::PropertyDialog(QWidget* parent) :
+ QDialog(parent),
+ configChanged_(false)
+{
+ setupUi(this);
+
+ QString wt=windowTitle();
+ wt+=" - " + QString::fromStdString(VConfig::instance()->appLongName());
+ setWindowTitle(wt);
+
+ QFont f;
+ f.setBold(true);
+ QFontMetrics fm(f);
+ int maxW=fm.width("Server options ATAT");
+ list_->setMaximumWidth(maxW+6);
+ list_->setFont(f);
+
+ list_->setItemDelegate(new ConfigListDelegate(32,maxW,this));
+
+ connect(list_,SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
+ this, SLOT(slotChangePage(QListWidgetItem*,QListWidgetItem*)));
+
+ connect(buttonBox_,SIGNAL(clicked(QAbstractButton*)),
+ this,SLOT(slotButton(QAbstractButton*)));
+
+ build();
+
+ readSettings();
+
+ if(list_->count() >0 && list_->currentRow() == -1)
+ list_->setCurrentRow(0);
+}
+
+void PropertyDialog::closeEvent(QCloseEvent * event)
+{
+ event->accept();
+ writeSettings();
+}
+
+//Build the property tree from the the definitions
+void PropertyDialog::build()
+{
+ if(prop_)
+ {
+ Q_FOREACH(VProperty* vPage,prop_->children())
+ {
+ if(vPage->param("visible") == "false")
+ continue;
+
+ QPixmap pix(32,32);
+ QPixmap edPix;
+ QString iconStr=vPage->param("icon");
+
+ if(!iconStr.isEmpty())
+ {
+ IconProvider::add(":/viewer/" + iconStr,iconStr);
+ pix=IconProvider::pixmap(iconStr,32);
+ edPix=IconProvider::pixmap(iconStr,20);
+ }
+
+ PropertyEditor* ed=new PropertyEditor(this);
+ ed->edit(vPage,edPix);
+
+ addPage(ed,pix,vPage->param("label"));
+ editors_ << ed;
+ }
+ }
+}
+
+void PropertyDialog::apply()
+{
+ manageChange(true);
+}
+
+void PropertyDialog::accept()
+{
+ manageChange(false);
+ writeSettings();
+ QDialog::accept();
+}
+
+
+void PropertyDialog::reject()
+{
+ writeSettings();
+ QDialog::reject();
+}
+
+void PropertyDialog::addPage(QWidget *w,QPixmap pix,QString txt)
+{
+ QListWidgetItem *item = new QListWidgetItem(list_);
+ item->setData(Qt::DecorationRole, pix);
+ item->setData(Qt::DisplayRole,txt);
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+
+ page_->addWidget(w);
+}
+
+void PropertyDialog::slotChangePage(QListWidgetItem *current, QListWidgetItem *previous)
+{
+ if (!current)
+ current = previous;
+
+ page_->setCurrentIndex(list_->row(current));
+}
+
+void PropertyDialog::slotButton(QAbstractButton* pb)
+{
+ if(buttonBox_->buttonRole(pb) == QDialogButtonBox::ApplyRole)
+ {
+ apply();
+ }
+}
+
+
+void PropertyDialog::manageChange(bool inApply)
+{
+ bool hasChange=false;
+ Q_FOREACH(PropertyEditor* ed,editors_)
+ {
+ if(ed->applyChange())
+ {
+ hasChange=true;
+ VProperty* p=ed->property();
+ if(p && p->name() != "server")
+ {
+ if(inApply)
+ Q_EMIT configChanged();
+ else
+ configChanged_=true;
+ }
+ }
+ }
+
+ if(hasChange)
+ VConfig::instance()->saveSettings();
+}
+
+void PropertyDialog::load(VProperty* p)
+{
+ prop_=p;
+}
+
+void PropertyDialog::writeSettings()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ Q_ASSERT(cs);
+ QSettings settings(QString::fromStdString(cs->qtSettingsFile("PropertyDialog")),
+ QSettings::NativeFormat);
+
+ //We have to clear it so that should not remember all the previous values
+ settings.clear();
+
+ settings.beginGroup("main");
+ settings.setValue("size",size());
+ settings.setValue("current",list_->currentRow());
+ settings.endGroup();
+}
+
+void PropertyDialog::readSettings()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ Q_ASSERT(cs);
+ QSettings settings(QString::fromStdString(cs->qtSettingsFile("PropertyDialog")),
+ QSettings::NativeFormat);
+
+ settings.beginGroup("main");
+ if(settings.contains("size"))
+ {
+ resize(settings.value("size").toSize());
+ }
+ else
+ {
+ resize(QSize(550,540));
+ }
+
+ if(settings.contains("current"))
+ {
+ int current=settings.value("current").toInt();
+ if(current >=0)
+ list_->setCurrentRow(current);
+ }
+ settings.endGroup();
+}
+
+
+static SimpleLoader<PropertyDialog> loader("gui");
diff --git a/Viewer/src/PropertyDialog.hpp b/Viewer/src/PropertyDialog.hpp
new file mode 100644
index 0000000..87020df
--- /dev/null
+++ b/Viewer/src/PropertyDialog.hpp
@@ -0,0 +1,63 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef PROPERTYDIALOG_INC_
+#define PROPERTYDIALOG_INC_
+
+#include "ui_PropertyDialog.h"
+
+#include <QDialog>
+
+class QAbstractButton;
+
+class PropertyEditor;
+class VProperty;
+
+class PropertyDialog : public QDialog, private Ui::PropertyDialog
+{
+
+Q_OBJECT
+
+public:
+ explicit PropertyDialog(QWidget *parent=0);
+ ~PropertyDialog() {};
+
+ bool isConfigChanged() const {return configChanged_;}
+
+ //Called from VConfigLoader
+ static void load(VProperty*);
+
+public Q_SLOTS:
+ void accept();
+ void reject();
+ void slotChangePage(QListWidgetItem *current, QListWidgetItem *previous);
+ void slotButton(QAbstractButton*);
+
+Q_SIGNALS:
+ void configChanged();
+
+private:
+ void build();
+ void addPage(QWidget *w,QPixmap pix,QString txt);
+ void manageChange(bool);
+ void apply();
+
+ void closeEvent(QCloseEvent * event);
+ void readSettings();
+ void writeSettings();
+
+ QList<PropertyEditor*> editors_;
+ bool configChanged_;
+
+ static VProperty* prop_;
+
+};
+
+#endif
+
diff --git a/Viewer/src/PropertyDialog.ui b/Viewer/src/PropertyDialog.ui
new file mode 100644
index 0000000..1f0db9e
--- /dev/null
+++ b/Viewer/src/PropertyDialog.ui
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PropertyDialog</class>
+ <widget class="QDialog" name="PropertyDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>924</width>
+ <height>695</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Configuration</string>
+ </property>
+ <property name="modal">
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="spacing">
+ <number>2</number>
+ </property>
+ <property name="margin">
+ <number>2</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="spacing">
+ <number>4</number>
+ </property>
+ <property name="margin">
+ <number>2</number>
+ </property>
+ <item>
+ <widget class="QListWidget" name="list_">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QStackedWidget" name="page_">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox_">
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox_</sender>
+ <signal>accepted()</signal>
+ <receiver>PropertyDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>199</x>
+ <y>278</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>199</x>
+ <y>149</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox_</sender>
+ <signal>rejected()</signal>
+ <receiver>PropertyDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>199</x>
+ <y>278</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>199</x>
+ <y>149</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/Viewer/src/PropertyEditor.cpp b/Viewer/src/PropertyEditor.cpp
new file mode 100644
index 0000000..57c6ce9
--- /dev/null
+++ b/Viewer/src/PropertyEditor.cpp
@@ -0,0 +1,568 @@
+//============================================================================
+// Copyright 2015 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "PropertyEditor.hpp"
+
+#include <QDebug>
+#include <QGroupBox>
+#include <QFrame>
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QTabWidget>
+#include <QToolButton>
+
+#include "ChangeNotifyEditor.hpp"
+#include "IconProvider.hpp"
+#include "PropertyLine.hpp"
+#include "VConfig.hpp"
+#include "VProperty.hpp"
+
+PropertyEditor::PropertyEditor(QWidget* parent) : QWidget(parent),
+ group_(0),
+ currentGrid_(0),
+ holder_(0)
+{
+ setupUi(this);
+
+ headerWidget_->setProperty("editorHeader","1");
+ scArea_->setProperty("editor","1");
+ scAreaContents_->setProperty("editorArea","1");
+
+ pixLabel_->clear();
+}
+
+PropertyEditor::~PropertyEditor()
+{
+}
+
+void PropertyEditor::edit(VProperty * vGroup,QPixmap pix)
+{
+ clear();
+
+ group_=vGroup;
+
+ QString txt=group_->param("desc");
+ headerLabel_->setText(txt);
+
+ pixLabel_->setPixmap(pix);
+
+ build();
+}
+
+void PropertyEditor::edit(VProperty * vGroup,QString serverName)
+{
+ clear();
+
+ group_=vGroup;
+
+ headerWidget_->hide();
+
+ serverName_=serverName;
+
+ build();
+}
+
+void PropertyEditor::clear()
+{
+ if(holder_)
+ {
+ vBox_->removeWidget(holder_);
+ delete holder_;
+ holder_=NULL;
+ }
+
+ currentGrid_=0;
+ lineItems_.clear();
+}
+
+
+//Build the property tree from the the definitions
+void PropertyEditor::build()
+{
+ if(!group_)
+ return;
+
+ assert(holder_==NULL);
+
+ holder_=new QWidget(scAreaContents_);
+ QVBoxLayout *vb=new QVBoxLayout(holder_);
+ vb->setContentsMargins(0,0,0,0);
+ vBox_->addWidget(holder_);
+
+ //Loop over the children of the group
+ Q_FOREACH(VProperty* vProp,group_->children())
+ {
+ addItem(vProp,vb,holder_);
+ }
+
+ addHelpers();
+}
+
+void PropertyEditor::addHelpers()
+{
+ QMap<std::string,PropertyLine*> lineMap;
+ Q_FOREACH(PropertyLine* line,lineItems_)
+ {
+ lineMap[line->property()->path()]=line;
+ }
+
+ Q_FOREACH(PropertyLine* line,lineItems_)
+ {
+ QString h=line->guiProperty()->param("helpers");
+ if(!h.isEmpty())
+ {
+ Q_FOREACH(QString s,h.split("/"))
+ {
+ if(PropertyLine* hl=lineMap.value(s.toStdString(),NULL))
+ {
+ line->addHelper(hl);
+ }
+ }
+ }
+ }
+}
+
+
+void PropertyEditor::addItem(VProperty* vProp,QVBoxLayout *layout,QWidget *parent)
+{
+ if(vProp->name() == "line")
+ {
+ if (!currentGrid_)
+ {
+ currentGrid_=new QGridLayout();
+ layout->addLayout(currentGrid_);
+ }
+ addLine(vProp,currentGrid_,parent);
+ }
+
+ else if(vProp->name() == "group")
+ {
+ currentGrid_=0;
+ addGroup(vProp,layout,parent);
+ }
+ else if(vProp->name() == "grid")
+ {
+ currentGrid_=0;
+ addGrid(vProp,layout,parent);
+ }
+ else if(vProp->name() == "custom-notification")
+ {
+ currentGrid_=0;
+ addNotification(vProp,layout,parent);
+ }
+ else if(vProp->name() == "note")
+ {
+ if(currentGrid_)
+ {
+ addNote(vProp,currentGrid_,parent);
+ }
+ else
+ {
+ addNote(vProp,layout,parent);
+ }
+ }
+ else if(vProp->name() == "tabs")
+ {
+ currentGrid_=0;
+ addTabs(vProp,layout,parent);
+ }
+
+}
+
+PropertyLine* PropertyEditor::addLine(VProperty *vProp,QGridLayout *gridLayout,QWidget *parent)
+{
+ PropertyLine* item = PropertyLineFactory::create(vProp,true,parent);
+
+ if(item)
+ {
+ item->init();
+ //item->reset(vProp->link()->value());
+
+ int row=gridLayout->rowCount();
+
+ QLabel* lw=item->label();
+ QLabel* slw=item->suffixLabel();
+
+ if(lw)
+ {
+ gridLayout->addWidget(lw,row,0,Qt::AlignLeft);
+
+ if(slw)
+ {
+ QHBoxLayout* hb=new QHBoxLayout;
+ hb->addWidget(item->item());
+ hb->addWidget(slw);
+ gridLayout->addLayout(hb,row,1,Qt::AlignLeft);
+ }
+ else
+ {
+ if(item->canExpand())
+ {
+ QHBoxLayout* hb=new QHBoxLayout;
+ hb->addWidget(item->item());
+ gridLayout->addLayout(hb,row,1,Qt::AlignLeft);
+ }
+ else
+ gridLayout->addWidget(item->item(),row,1,Qt::AlignLeft);
+ }
+ }
+ else
+ {
+ gridLayout->addWidget(item->item(),row,0,1,2,Qt::AlignLeft);
+ }
+
+ QWidget *bw=item->button();
+ if(bw)
+ gridLayout->addWidget(bw,row,2);
+
+
+ QToolButton* defTb=item->defaultTb();
+ if(defTb)
+ {
+ gridLayout->addWidget(defTb,row,3);
+ }
+
+ QToolButton* masterTb=item->masterTb();
+ if(masterTb)
+ {
+ gridLayout->addWidget(masterTb,row,4);
+ }
+
+ connect(item,SIGNAL(changed()),
+ this,SIGNAL(changed()));
+
+ lineItems_ << item;
+ }
+
+ return item;
+}
+
+void PropertyEditor::addGroup(VProperty* vProp,QVBoxLayout * layout,QWidget *parent)
+{
+ if(vProp->name() != "group")
+ return;
+
+ QGroupBox *groupBox = new QGroupBox(vProp->param("title"),parent);
+ groupBox->setObjectName("editorGroupBox");
+ QGridLayout *grid=new QGridLayout();
+ grid->setColumnStretch(1,1);
+ groupBox->setLayout(grid);
+ layout->addWidget(groupBox);
+
+ currentGrid_=grid;
+
+ //Loop over the children of the group
+ Q_FOREACH(VProperty* chProp,vProp->children())
+ {
+ //Add each item to the the editor
+ addItem(chProp,layout,groupBox);
+ }
+ currentGrid_=0;
+}
+
+void PropertyEditor::addGrid(VProperty* vProp,QVBoxLayout *layout,QWidget *parent)
+{
+ if(vProp->name() != "grid")
+ return;
+
+ QGroupBox *groupBox = new QGroupBox(vProp->param("title"),parent);
+ groupBox->setObjectName("editorGroupBox");
+ QGridLayout* grid=new QGridLayout();
+ groupBox->setLayout(grid);
+
+ layout->addWidget(groupBox);
+
+ //Add header
+ for(int i=1; i < 10; i++)
+ {
+ QString h=vProp->param("h" + QString::number(i));
+
+ if(h.isEmpty())
+ {
+ grid->setColumnStretch(i+1,1);
+ break;
+ }
+
+ h+=" ";
+ QLabel* hLabel=new QLabel(h,groupBox);
+ grid->addWidget(hLabel,0,i,Qt::AlignHCenter);
+ }
+
+ //Add rows
+ Q_FOREACH(VProperty* chProp,vProp->children())
+ {
+ addGridRow(chProp,grid,groupBox);
+ }
+}
+
+
+void PropertyEditor::addGridRow(VProperty* vProp,QGridLayout *grid,QWidget *parent)
+{
+ if(vProp->name() != "row")
+ {
+ if(vProp->name() == "note")
+ {
+ QLabel *empty=new QLabel(" ",parent);
+ grid->addWidget(empty,grid->rowCount(),0,1,-1,Qt::AlignVCenter);
+ QLabel *label=new QLabel(" <b>Note:</b> " + vProp->value().toString(),parent);
+ grid->addWidget(label,grid->rowCount(),0,1,-1,Qt::AlignVCenter);
+ }
+ return;
+ }
+
+ int row=grid->rowCount();
+ QString labelText=vProp->param("label");
+ QLabel* label=new QLabel(labelText,parent);
+ grid->addWidget(label,row,0);
+
+ int col=1;
+ Q_FOREACH(VProperty* chProp,vProp->children())
+ {
+ if(chProp->name() == "line")
+ {
+ PropertyLine* item = PropertyLineFactory::create(chProp,false,parent);
+
+ if(item)
+ {
+ item->init();
+ //item->reset(chProp->link()->value());
+
+ //QLabel* lw=item->label();
+ //QLabel* slw=item->suffixLabel();
+
+ //gridLayout->addWidget(item->item(),row,col,Qt::AlignLeft);
+
+ /*QWidget *bw=item->button();
+ if(bw)
+ gridLayout->addWidget(bw,row,2);*/
+
+
+ QToolButton* defTb=item->defaultTb();
+ QToolButton* masterTb=item->masterTb();
+ if(defTb || masterTb)
+ {
+ QHBoxLayout *hb=new QHBoxLayout();
+ hb->addWidget(item->item());
+ if(defTb)
+ hb->addWidget(defTb);
+ if(masterTb)
+ hb->addWidget(masterTb);
+
+ hb->addSpacing(15);
+ hb->addStretch(1);
+ grid->addLayout(hb,row,col);
+ }
+ else
+ {
+ grid->addWidget(item->item(),row,col,Qt::AlignLeft);
+ }
+
+ connect(item,SIGNAL(changed()),
+ this,SIGNAL(changed()));
+ lineItems_ << item;
+ col++;
+ }
+ }
+ }
+
+
+}
+
+void PropertyEditor::addNotification(VProperty* vProp,QVBoxLayout* layout,QWidget *parent)
+{
+ if(vProp->name() != "custom-notification")
+ return;
+
+ //ChangeNotifyEditor* ne=new ChangeNotifyEditor(parent);
+
+ QTabWidget* tab=new QTabWidget(parent);
+
+ bool useGroup=(vProp->param("group") == "true");
+
+ if(useGroup)
+ {
+ QString labelText=vProp->param("title");
+ QGroupBox *groupBox = new QGroupBox(labelText,parent);
+ groupBox->setObjectName("editorGroupBox");
+ QVBoxLayout* vb=new QVBoxLayout();
+ groupBox->setLayout(vb);
+ vb->addWidget(tab);
+ layout->addWidget(groupBox);
+
+ }
+ else
+ {
+ layout->addWidget(tab);
+ }
+
+ //Add rows
+ Q_FOREACH(VProperty* chProp,vProp->children())
+ {
+ if(chProp->name() == "row")
+ {
+ QString labelText=chProp->param("label");
+
+ QList<PropertyLine*> lineLst;
+
+ QWidget* w=new QWidget(parent);
+ QVBoxLayout* vb=new QVBoxLayout(w);
+ //vb->setContentsMargins(4,4,4,4);
+
+ currentGrid_=0;
+
+ if(VProperty *root=VConfig::instance()->find(chProp->param("root").toStdString()))
+ {
+ QLabel *labelDesc=new QLabel(tr("Description: <b>") + root->param("description") + "</b>",w);
+ //labelDesc->setProperty("editorNotifyHeader","1");
+ vb->addWidget(labelDesc);
+ vb->addSpacing(5);
+ }
+
+ int lineLstPos=lineItems_.count();
+ Q_FOREACH(VProperty* lineProp,chProp->children())
+ {
+ addItem(lineProp,vb,w);
+ }
+ for(int i=lineLstPos; i < lineItems_.count(); i++)
+ lineLst << lineItems_[i];
+
+ tab->addTab(w,labelText);
+
+ //Connect up different components
+ PropertyLine* enabledLine=0;
+ PropertyLine* popupLine=0;
+ PropertyLine* soundLine=0;
+ Q_FOREACH(PropertyLine* pl,lineLst)
+ {
+ if(pl->property()->name() == "enabled")
+ {
+ enabledLine=pl;
+ }
+ if(pl->property()->name() == "popup")
+ {
+ popupLine=pl;
+ }
+ if(pl->property()->name() == "sound")
+ {
+ soundLine=pl;
+ }
+ }
+
+ if(enabledLine)
+ {
+ if(popupLine)
+ {
+ connect(enabledLine,SIGNAL(changed(QVariant)),
+ popupLine,SLOT(slotEnabled(QVariant)));
+ //init
+ popupLine->slotEnabled(enabledLine->property()->value());
+ }
+ if(soundLine)
+ {
+ connect(enabledLine,SIGNAL(changed(QVariant)),
+ soundLine,SLOT(slotEnabled(QVariant)));
+ //init
+ soundLine->slotEnabled(enabledLine->property()->value());
+ }
+ }
+
+ //ne->addRow(labelText,lineLst,w);
+ }
+ }
+}
+
+void PropertyEditor::addTabs(VProperty* vProp,QVBoxLayout *layout,QWidget* parent)
+{
+ if(vProp->name() != "tabs")
+ return;
+
+ QTabWidget *t=new QTabWidget(parent);
+ layout->addWidget(t);
+
+ int col=1;
+ Q_FOREACH(VProperty* chProp,vProp->children())
+ {
+ if(chProp->name() == "tab")
+ {
+ addTab(chProp,t);
+ }
+ }
+}
+
+void PropertyEditor::addTab(VProperty* vProp,QTabWidget* tab)
+{
+ if(vProp->name() != "tab")
+ return;
+
+ QWidget *w=new QWidget(tab);
+ QVBoxLayout* vb=new QVBoxLayout();
+ w->setLayout(vb);
+
+ tab->addTab(w,vProp->param("label"));
+
+ Q_FOREACH(VProperty* chProp,vProp->children())
+ {
+ addItem(chProp,vb,w);
+ }
+
+ vb->addStretch(1);
+}
+
+void PropertyEditor::addNote(VProperty* vProp,QVBoxLayout* layout,QWidget *parent)
+{
+ if(vProp->name() != "note")
+ return;
+
+ QString txt=vProp->value().toString();
+ txt.replace("%SERVER%",(serverName_.isEmpty())?"?":"<b>" + serverName_ + "</b>");
+
+ layout->addSpacing(5);
+ QLabel *label=new QLabel("<i>Note:</i> " + txt,parent);
+ layout->addWidget(label);
+}
+
+void PropertyEditor::addNote(VProperty* vProp,QGridLayout* layout,QWidget *parent)
+{
+ if(vProp->name() != "note")
+ return;
+
+ QString txt=vProp->value().toString();
+ txt.replace("%SERVER%",(serverName_.isEmpty())?"?":"<b>" + serverName_ + "</b>");
+
+ //QLabel *empty=new QLabel(" ",parent);
+ //layout->addWidget(empty,layout->rowCount(),0,1,-1,Qt::AlignVCenter);
+ //QLabel *label=new QLabel(" <b>Note:</b> " + txt,parent);
+
+ //QFrame* fr=new QFrame(parent);
+ //fr->setFrameShape(QFrame::HLine);
+ //layout->addWidget(fr,layout->rowCount(),0,1,-1,Qt::AlignVCenter);
+
+ QLabel *label=new QLabel("<table><tr><td><b> </b></td><td><i>Note:</i> " + txt + "</td></tr></table>",parent);
+ label->setWordWrap(true);
+ layout->addWidget(label,layout->rowCount(),0,1,-1,Qt::AlignVCenter);
+}
+
+
+bool PropertyEditor::applyChange()
+{
+ bool changed=false;
+ //Loop over the top level properties (groups) in the browser
+ Q_FOREACH(PropertyLine* item, lineItems_)
+ {
+ //Sync the changes to VConfig
+ if(item->applyChange())
+ {
+ changed=true;
+ }
+ }
+
+ return changed;
+}
+
diff --git a/Viewer/src/PropertyEditor.hpp b/Viewer/src/PropertyEditor.hpp
new file mode 100644
index 0000000..8e07a72
--- /dev/null
+++ b/Viewer/src/PropertyEditor.hpp
@@ -0,0 +1,65 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef PROPERTYEDITOR_INC_
+#define PROPERTYEDITOR_INC_
+
+#include <QWidget>
+
+#include "ui_PropertyEditor.h"
+
+class QGridLayout;
+class QTabWidget;
+
+class PropertyLine;
+class VProperty;
+
+class PropertyEditor : public QWidget, protected Ui::PropertyEditor
+{
+Q_OBJECT
+
+public:
+ explicit PropertyEditor(QWidget *parent=0);
+ ~PropertyEditor();
+
+ void edit(VProperty*,QPixmap pixmap);
+ void edit(VProperty*,QString label);
+ bool applyChange();
+ VProperty* property() const {return group_;}
+
+Q_SIGNALS:
+ void changed();
+
+private:
+ void clear();
+ void build();
+ void addHelpers();
+
+ void addItem(VProperty*,QVBoxLayout*,QWidget*);
+ PropertyLine* addLine(VProperty* vProp,QGridLayout* grid,QWidget*);
+ void addGroup(VProperty*,QVBoxLayout*,QWidget*);
+ void addGrid(VProperty*,QVBoxLayout*,QWidget*);
+ void addGridRow(VProperty* prop,QGridLayout *grid,QWidget*);
+ void addNotification(VProperty* prop,QVBoxLayout*,QWidget*);
+ void addTabs(VProperty*,QVBoxLayout*,QWidget*);
+ void addTab(VProperty*,QTabWidget*);
+ void addNote(VProperty* vProp,QVBoxLayout*,QWidget*);
+ void addNote(VProperty* vProp,QGridLayout* layout,QWidget*);
+
+ VProperty* group_;
+ QGridLayout* currentGrid_;
+ QList<PropertyLine*> lineItems_;
+ QString serverName_;
+ QWidget* holder_;
+};
+
+
+#endif
+
diff --git a/Viewer/src/PropertyEditor.ui b/Viewer/src/PropertyEditor.ui
new file mode 100644
index 0000000..b94ad40
--- /dev/null
+++ b/Viewer/src/PropertyEditor.ui
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PropertyEditor</class>
+ <widget class="QWidget" name="PropertyEditor">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>502</width>
+ <height>506</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" stretch="0,1">
+ <property name="spacing">
+ <number>2</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="headerWidget_" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <property name="margin">
+ <number>1</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="headerLabel_">
+ <property name="autoFillBackground">
+ <bool>false</bool>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ <property name="margin">
+ <number>4</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="pixLabel_">
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>5</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QScrollArea" name="scArea_">
+ <property name="widgetResizable">
+ <bool>true</bool>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+ </property>
+ <widget class="QWidget" name="scAreaContents_">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>498</width>
+ <height>472</height>
+ </rect>
+ </property>
+ <property name="autoFillBackground">
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetMinAndMaxSize</enum>
+ </property>
+ <item>
+ <layout class="QVBoxLayout" name="vBox_"/>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Viewer/src/PropertyLine.cpp b/Viewer/src/PropertyLine.cpp
new file mode 100644
index 0000000..4df6a9d
--- /dev/null
+++ b/Viewer/src/PropertyLine.cpp
@@ -0,0 +1,930 @@
+//============================================================================
+// Copyright 2015 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "PropertyLine.hpp"
+
+#include <QCheckBox>
+#include <QComboBox>
+#include <QColorDialog>
+#include <QDebug>
+#include <QFontDatabase>
+#include <QFontDialog>
+#include <QHBoxLayout>
+#include <QIntValidator>
+#include <QLabel>
+#include <QLineEdit>
+#include <QPainter>
+#include <QPalette>
+#include <QPushButton>
+#include <QToolButton>
+
+#include "ComboMulti.hpp"
+#include "Sound.hpp"
+
+#include <assert.h>
+
+static std::map<VProperty::GuiType,PropertyLineFactory*>* makers = 0;
+
+FontSizeSpin::FontSizeSpin(QWidget *parent) : QSpinBox(parent)
+{
+}
+
+void FontSizeSpin::setFamily(QString family)
+{
+ QFontDatabase db;
+ vals_=db.pointSizes(family);
+ setRange(0,vals_.count()-1);
+}
+
+QString FontSizeSpin::textFromValue(int value) const
+{
+ if(value >=0 && value < vals_.count())
+ return QString::number(vals_.at(value));
+
+ return QString();
+}
+
+
+
+//=========================================================================
+//
+// PropertyLineFactory
+//
+//=========================================================================
+
+PropertyLineFactory::PropertyLineFactory(VProperty::GuiType type)
+{
+ if(makers == 0)
+ makers = new std::map<VProperty::GuiType,PropertyLineFactory*>;
+
+ (*makers)[type] = this;
+}
+
+PropertyLineFactory::~PropertyLineFactory()
+{
+ // Not called
+}
+
+PropertyLine* PropertyLineFactory::create(VProperty* p,bool addLabel,QWidget* parent)
+{
+ if(!p || !p->link())
+ return 0;
+
+ VProperty::GuiType t=p->link()->guiType();
+ std::map<VProperty::GuiType,PropertyLineFactory*>::iterator j = makers->find(t);
+ if(j != makers->end())
+ return (*j).second->make(p,addLabel,parent);
+
+ return 0;
+}
+
+//=========================================================================
+//
+// PropertyLine
+//
+//=========================================================================
+
+PropertyLine::PropertyLine(VProperty* guiProp,bool addLabel,QWidget * parent) :
+ QObject(parent),
+ prop_(NULL),
+ guiProp_(guiProp),
+ label_(0),
+ suffixLabel_(0),
+ defaultTb_(0),
+ masterTb_(0),
+ enabled_(true),
+ doNotEmitChange_(false)
+{
+ prop_=guiProp_->link();
+ assert(prop_);
+
+ oriVal_=prop_->value();
+
+ if(addLabel)
+ {
+ label_=new QLabel(prop_->param("label"),parent);
+ label_->setToolTip(prop_->param("tooltip"));
+ }
+
+ QString suffixText=prop_->param("suffix");
+ if(!suffixText.isEmpty())
+ {
+ suffixLabel_=new QLabel(suffixText,parent);
+ }
+
+ defaultTb_= new QToolButton(parent);
+ defaultTb_->setToolTip(tr("Reset to default value"));
+ defaultTb_->setIcon(QPixmap(":/viewer/reset_to_default.svg"));
+ defaultTb_->setAutoRaise(true);
+
+ connect(defaultTb_,SIGNAL(clicked(bool)),
+ this,SLOT(slotResetToDefault(bool)));
+
+ if(prop_->master())
+ {
+ masterTb_=new QToolButton(parent);
+ masterTb_->setCheckable(true);
+ masterTb_->setText("Use global");
+ masterTb_->setToolTip(tr("Use global server settings"));
+ masterTb_->setIcon(QPixmap(":/viewer/chain.svg"));
+ masterTb_->setAutoRaise(true);
+ masterTb_->setChecked(prop_->useMaster());
+
+ connect(masterTb_,SIGNAL(toggled(bool)),
+ this,SLOT(slotMaster(bool)));
+ }
+
+}
+
+PropertyLine::~PropertyLine()
+{
+}
+
+void PropertyLine::init()
+{
+ doNotEmitChange_=true;
+ if(prop_->master())
+ {
+ if(masterTb_->isChecked() != prop_->useMaster())
+ masterTb_->setChecked(prop_->useMaster());
+ else
+ slotMaster(prop_->useMaster());
+ }
+ else
+ {
+ slotReset(prop_->value());
+ }
+ doNotEmitChange_=false;
+
+ if(item())
+ item()->setToolTip(prop_->param("tooltip"));
+}
+
+void PropertyLine::slotResetToDefault(bool)
+{
+ slotReset(prop_->defaultValue());
+ checkState();
+}
+
+void PropertyLine::slotEnabled(QVariant v)
+{
+ if(enabled_ != v.toBool())
+ {
+ if(!masterTb_ || !masterTb_->isChecked())
+ {
+ enabled_=v.toBool();
+ checkState();
+ }
+ }
+}
+
+void PropertyLine::checkState()
+{
+ if(label_)
+ {
+ label_->setEnabled(enabled_);
+ }
+ if(masterTb_)
+ {
+ masterTb_->setEnabled(enabled_);
+ }
+ if(suffixLabel_)
+ {
+ suffixLabel_->setEnabled(enabled_);
+ }
+
+ defaultTb_->setEnabled(enabled_);
+
+ setEnabledEditable(enabled_);
+
+ if(masterTb_ && masterTb_->isChecked())
+ return;
+
+ if(enabled_)
+ {
+ if(prop_->defaultValue() != currentValue())
+ defaultTb_->setEnabled(true);
+ else
+ defaultTb_->setEnabled(false);
+ }
+}
+
+bool PropertyLine::applyMaster()
+{
+ if(masterTb_ && prop_->useMaster() != masterTb_->isChecked())
+ {
+ prop_->setUseMaster(masterTb_->isChecked());
+ return true;
+ }
+ return false;
+}
+
+
+void PropertyLine::slotMaster(bool b)
+{
+ if(b)
+ {
+ slotReset(prop_->master()->value());
+ defaultTb_->setEnabled(false);
+ setEnabledEditable(false);
+ }
+ else
+ {
+ slotReset(prop_->value());
+ defaultTb_->setEnabled(true);
+ checkState();
+ setEnabledEditable(true);
+ }
+
+ Q_EMIT masterChanged(b);
+
+ valueChanged();
+}
+
+void PropertyLine::slotReset(VProperty* prop,QVariant v)
+{
+ if(prop == prop_)
+ slotReset(v);
+}
+
+void PropertyLine::valueChanged()
+{
+ if(!doNotEmitChange_)
+ Q_EMIT changed();
+}
+
+void PropertyLine::addHelper(PropertyLine* line)
+{
+ if(line)
+ helpers_[line->property()->name()]=line;
+}
+
+//=========================================================================
+//
+// StringPropertyLine
+//
+//=========================================================================
+
+StringPropertyLine::StringPropertyLine(VProperty* guiProp,bool addLabel,QWidget * parent) : PropertyLine(guiProp,addLabel,parent)
+{
+ if(label_)
+ label_->setText(label_->text() + ":");
+
+ le_=new QLineEdit(parent);
+
+ connect(le_,SIGNAL(textEdited(QString)),
+ this,SLOT(slotEdited(QString)));
+}
+
+QWidget* StringPropertyLine::item()
+{
+ return le_;
+}
+
+QWidget* StringPropertyLine::button()
+{
+ return NULL;
+}
+
+void StringPropertyLine::slotReset(QVariant v)
+{
+ le_->setText(v.toString());
+ PropertyLine::checkState();
+ valueChanged();
+}
+
+bool StringPropertyLine::applyChange()
+{
+ PropertyLine::applyMaster();
+
+ QString v=oriVal_.toString();
+ if(v != le_->text())
+ {
+ prop_->setValue(le_->text());
+ oriVal_=prop_->value();
+ return true;
+ }
+ return false;
+}
+
+QVariant StringPropertyLine::currentValue()
+{
+ return le_->text();
+}
+
+void StringPropertyLine::slotEdited(QString)
+{
+ PropertyLine::checkState();
+ valueChanged();
+}
+
+void StringPropertyLine::setEnabledEditable(bool b)
+{
+ le_->setEnabled(b);
+}
+
+//=========================================================================
+//
+// ColourPropertyLine
+//
+//=========================================================================
+
+ColourPropertyLine::ColourPropertyLine(VProperty* guiProp,bool addLabel,QWidget * parent) : PropertyLine(guiProp,addLabel,parent)
+{
+ if(label_)
+ label_->setText(label_->text() + ":");
+
+ QFont f;
+ QFontMetrics fm(f);
+ int height=fm.height();
+ int width=fm.width("AAAAAAA");
+
+ cb_=new QToolButton(parent);
+ cb_->setFixedWidth(width);
+ cb_->setFixedHeight(height+2);
+ cb_->setToolTip(tr("Click to select a colour"));
+
+ styleSheet_="QToolButton { background: BG; border: 1px solid rgb(120,120,120); border-radius: 2px;}";
+
+ connect(cb_,SIGNAL(clicked(bool)),
+ this,SLOT(slotEdit(bool)));
+}
+
+QWidget* ColourPropertyLine::item()
+{
+ return cb_;
+}
+
+QWidget* ColourPropertyLine::button()
+{
+ return NULL;
+}
+
+void ColourPropertyLine::slotReset(QVariant v)
+{
+ QColor c=v.value<QColor>();
+
+ QString st=styleSheet_;
+ st.replace("BG","rgb(" + QString::number(c.red()) + "," +
+ QString::number(c.green()) + "," + QString::number(c.blue()) + ")");
+
+ cb_->setStyleSheet(st);
+
+ currentCol_=c;
+
+ PropertyLine::checkState();
+ valueChanged();
+}
+
+void ColourPropertyLine::slotEdit(bool)
+{
+ QColor currentCol=currentValue().value<QColor>();
+ QColor col=QColorDialog::getColor(currentCol,cb_->parentWidget());
+
+ if(col.isValid())
+ {
+ slotReset(col);
+ }
+}
+
+bool ColourPropertyLine::applyChange()
+{
+ PropertyLine::applyMaster();
+
+ QColor v=oriVal_.value<QColor>();
+ QColor c=currentValue().value<QColor>();
+
+ if(v != c)
+ {
+ prop_->setValue(c);
+ oriVal_=prop_->value();
+ return true;
+ }
+
+ return false;
+}
+
+QVariant ColourPropertyLine::currentValue()
+{
+ return currentCol_;
+}
+
+void ColourPropertyLine::setEnabledEditable(bool b)
+{
+ cb_->setEnabled(b);
+}
+
+
+//=========================================================================
+//
+// FontPropertyLine
+//
+//=========================================================================
+
+FontPropertyLine::FontPropertyLine(VProperty* guiProp,bool addLabel,QWidget * parent) : PropertyLine(guiProp,addLabel,parent)
+{
+ if(label_)
+ label_->setText(label_->text() + ":");
+
+ holderW_=new QWidget(parent);
+
+ QHBoxLayout* hb=new QHBoxLayout(holderW_);
+ hb->setContentsMargins(0,0,0,0);
+
+ QFontDatabase db;
+
+ familyCb_=new QComboBox(parent);
+ hb->addWidget(familyCb_);
+ Q_FOREACH(QString s,db.families(QFontDatabase::Latin))
+ familyCb_->addItem(s);
+
+ sizeSpin_=new QSpinBox(parent);
+ sizeSpin_->setRange(1,200);
+ hb->addWidget(sizeSpin_);
+
+ QLabel *sizeLabel=new QLabel("pt",parent);
+ hb->addWidget(sizeLabel);
+
+ lName_=new QLabel(parent);
+
+ connect(familyCb_,SIGNAL(currentIndexChanged(int)),
+ this,SLOT(slotFamilyChanged(int)));
+
+ connect(sizeSpin_,SIGNAL(valueChanged(int)),
+ this,SLOT(slotSizeChanged(int)));
+
+ /*tbEdit_=new QToolButton(parent);
+ tbEdit_->setToolTip(tr("Edit"));
+
+ connect(tbEdit_,SIGNAL(clicked(bool)),
+ this,SLOT(slotEdit(bool)));*/
+}
+
+QWidget* FontPropertyLine::item()
+{
+ return holderW_;
+}
+
+QWidget* FontPropertyLine::button()
+{
+ return NULL; //tbEdit_;
+}
+
+void FontPropertyLine::slotReset(QVariant v)
+{
+ font_=v.value<QFont>();
+
+ for(int i=0; i < familyCb_->count(); i++)
+ if(familyCb_->itemText(i) == font_.family())
+ familyCb_->setCurrentIndex(i);
+
+ sizeSpin_->setValue(font_.pointSize());
+
+ PropertyLine::checkState();
+ valueChanged();
+}
+
+void FontPropertyLine::slotEdit(bool)
+{
+ QFont c;
+
+ bool ok;
+ QFont f = QFontDialog::getFont(&ok,c,lName_->parentWidget());
+
+ if(ok)
+ {
+ lName_->setText(f.toString());
+ font_=f;
+ }
+ valueChanged();
+}
+
+void FontPropertyLine::slotFamilyChanged(int idx)
+{
+ if(idx != -1)
+ {
+ QString family=familyCb_->itemText(idx);
+ if(font_.family() != family)
+ {
+ font_.setFamily(family);
+ PropertyLine::checkState();
+ valueChanged();
+ }
+ }
+}
+
+void FontPropertyLine::slotSizeChanged(int val)
+{
+ if(val != font_.pointSize())
+ {
+ font_.setPointSize(val);
+ PropertyLine::checkState();
+ valueChanged();
+ }
+}
+
+
+bool FontPropertyLine::applyChange()
+{
+ PropertyLine::applyMaster();
+
+ if(oriVal_.value<QFont>() != font_)
+ {
+ prop_->setValue(font_);
+ oriVal_=prop_->value();
+ return true;
+ }
+ return false;
+}
+
+QVariant FontPropertyLine::currentValue()
+{
+ return font_;
+}
+
+void FontPropertyLine::setEnabledEditable(bool b)
+{
+ //tbEdit_->setEnabled(b);
+}
+
+//=========================================================================
+//
+// IntPropertyLine
+//
+//=========================================================================
+
+IntPropertyLine::IntPropertyLine(VProperty* guiProp,bool addLabel,QWidget * parent) : PropertyLine(guiProp,addLabel,parent)
+{
+ if(label_)
+ label_->setText(label_->text() + ":");
+
+ le_=new QLineEdit(parent);
+ QIntValidator* validator=new QIntValidator(le_);
+
+ QString s=guiProp->param("max");
+ if(!s.isEmpty())
+ {
+ validator->setTop(s.toInt());
+ }
+
+ s=guiProp->param("min");
+ if(!s.isEmpty())
+ {
+ validator->setBottom(s.toInt());
+ }
+
+ le_->setValidator(validator);
+
+ connect(le_,SIGNAL(textEdited(QString)),
+ this,SLOT(slotEdited(QString)));
+}
+
+QWidget* IntPropertyLine::item()
+{
+ return le_;
+}
+
+QWidget* IntPropertyLine::button()
+{
+ return NULL;
+}
+
+void IntPropertyLine::slotReset(QVariant v)
+{
+ le_->setText(QString::number(v.toInt()));
+ PropertyLine::checkState();
+ valueChanged();
+}
+
+bool IntPropertyLine::applyChange()
+{
+ PropertyLine::applyMaster();
+
+ int cv=le_->text().toInt();
+ if(oriVal_.toInt() != cv)
+ {
+ prop_->setValue(cv);
+ oriVal_=prop_->value();
+ return true;
+ }
+ return false;
+}
+
+QVariant IntPropertyLine::currentValue()
+{
+ return le_->text().toInt();
+}
+
+void IntPropertyLine::slotEdited(QString)
+{
+ PropertyLine::checkState();
+ valueChanged();
+}
+
+void IntPropertyLine::setEnabledEditable(bool b)
+{
+ le_->setEnabled(b);
+}
+
+//=========================================================================
+//
+// BoolPropertyLine
+//
+//=========================================================================
+
+BoolPropertyLine::BoolPropertyLine(VProperty* guiProp,bool addLabel,QWidget * parent) : PropertyLine(guiProp,false,parent)
+{
+ cb_=new QCheckBox(prop_->param("label"),parent);
+
+ connect(cb_,SIGNAL(stateChanged(int)),
+ this,SLOT(slotStateChanged(int)));
+}
+
+QWidget* BoolPropertyLine::item()
+{
+ return cb_;
+}
+
+QWidget* BoolPropertyLine::button()
+{
+ return NULL;
+}
+
+void BoolPropertyLine::slotReset(QVariant v)
+{
+ cb_->setChecked(v.toBool());
+ PropertyLine::checkState();
+ valueChanged();
+
+ //BoolLines emit this signal because they might control
+ //other lines' status
+ Q_EMIT changed(currentValue());
+}
+
+bool BoolPropertyLine::applyChange()
+{
+ PropertyLine::applyMaster();
+
+ if(oriVal_.toBool() != cb_->isChecked())
+ {
+ prop_->setValue(cb_->isChecked());
+ oriVal_=prop_->value();
+ return true;
+ }
+ return false;
+}
+
+QVariant BoolPropertyLine::currentValue()
+{
+ return cb_->isChecked();
+}
+
+void BoolPropertyLine::slotStateChanged(int)
+{
+ PropertyLine::checkState();
+ valueChanged();
+
+ //BoolLines emit this signal because they might control
+ //other lines' status
+ Q_EMIT changed(currentValue());
+}
+
+void BoolPropertyLine::setEnabledEditable(bool b)
+{
+ cb_->setEnabled(b);
+}
+
+//=========================================================================
+//
+// ComboPropertyLine
+//
+//=========================================================================
+
+ComboPropertyLine::ComboPropertyLine(VProperty* guiProp,bool addLabel,QWidget * parent) : PropertyLine(guiProp,addLabel,parent)
+{
+ if(label_)
+ label_->setText(label_->text() + ":");
+
+ cb_=new QComboBox(parent);//(vProp->param("label"));
+
+ connect(cb_,SIGNAL(currentIndexChanged(int)),
+ this,SLOT(slotCurrentChanged(int)));
+
+ QStringList lst=prop_->param("values_label").split("/");
+ QStringList lstData=prop_->param("values").split("/");
+ if(prop_->param("values_label").simplified().isEmpty())
+ lst=lstData;
+
+ assert(lst.count() == lstData.count());
+ for(int i=0; i < lst.count(); i++)
+ cb_->addItem(lst[i],lstData[i]);
+}
+
+QWidget* ComboPropertyLine::item()
+{
+ return cb_;
+}
+
+QWidget* ComboPropertyLine::button()
+{
+ return NULL;
+}
+
+void ComboPropertyLine::slotReset(QVariant v)
+{
+ QStringList lst=prop_->param("values").split("/");
+ int idx=lst.indexOf(v.toString());
+ if(idx != -1)
+ cb_->setCurrentIndex(idx);
+
+ PropertyLine::checkState();
+ valueChanged();
+}
+
+bool ComboPropertyLine::applyChange()
+{
+ PropertyLine::applyMaster();
+
+ int idx=cb_->currentIndex();
+
+ if(idx != -1)
+ {
+ QString currentDataVal=cb_->itemData(idx).toString();
+ if(oriVal_.toString() != currentDataVal)
+ {
+ prop_->setValue(currentDataVal);
+ oriVal_=prop_->value();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+QVariant ComboPropertyLine::currentValue()
+{
+ int idx=cb_->currentIndex();
+
+ if(idx != -1)
+ {
+ return cb_->itemData(idx).toString();
+ }
+
+ return QString();
+}
+
+void ComboPropertyLine::slotCurrentChanged(int)
+{
+ PropertyLine::checkState();
+ valueChanged();
+}
+
+void ComboPropertyLine::setEnabledEditable(bool b)
+{
+ cb_->setEnabled(b);
+}
+
+//=========================================================================
+//
+// ComboMultiPropertyLine
+//
+//=========================================================================
+
+ComboMultiPropertyLine::ComboMultiPropertyLine(VProperty* guiProp,bool addLabel,QWidget * parent) : PropertyLine(guiProp,addLabel,parent)
+{
+ if(label_)
+ label_->setText(label_->text() + ":");
+
+ cb_=new ComboMulti(parent);//(vProp->param("label"));
+
+ cb_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+
+ connect(cb_,SIGNAL(currentIndexChanged(int)),
+ this,SLOT(slotCurrentChanged(int)));
+
+ QStringList lst=prop_->param("values_label").split("/");
+ QStringList lstData=prop_->param("values").split("/");
+ if(prop_->param("values_label").simplified().isEmpty())
+ lst=lstData;
+
+ assert(lst.count() == lstData.count());
+ for(int i=0; i < lst.count(); i++)
+ {
+ cb_->addItem(lst[i],lstData[i]);
+ }
+}
+
+QWidget* ComboMultiPropertyLine::item()
+{
+ return cb_;
+}
+
+QWidget* ComboMultiPropertyLine::button()
+{
+ return NULL;
+}
+
+void ComboMultiPropertyLine::slotReset(QVariant v)
+{
+ QStringList vals=v.toString().split("/");
+
+ cb_->setSelectionByData(vals);
+
+ PropertyLine::checkState();
+ valueChanged();
+}
+
+bool ComboMultiPropertyLine::applyChange()
+{
+ PropertyLine::applyMaster();
+
+ QString currentVal=cb_->selectionData().join("/");
+
+ if(oriVal_.toString() != currentVal)
+ {
+ prop_->setValue(currentVal);
+ oriVal_=prop_->value();
+ return true;
+ }
+
+ return false;
+}
+
+QVariant ComboMultiPropertyLine::currentValue()
+{
+ QStringList lst=cb_->selection();
+
+ return lst.join("/");
+}
+
+void ComboMultiPropertyLine::slotCurrentChanged(int)
+{
+ PropertyLine::checkState();
+ valueChanged();
+}
+
+void ComboMultiPropertyLine::setEnabledEditable(bool b)
+{
+ cb_->setEnabled(b);
+}
+
+
+//=========================================================================
+//
+// SoundComboPropertyLine
+//
+//=========================================================================
+
+SoundComboPropertyLine::SoundComboPropertyLine(VProperty* guiProp,bool addLabel,QWidget * parent) :
+ ComboPropertyLine(guiProp,addLabel,parent),
+ playTb_(NULL)
+{
+ playTb_=new QToolButton(parent);
+ playTb_->setText("play");
+ playTb_->setToolTip(tr("Play sound"));
+
+ connect(playTb_,SIGNAL(clicked(bool)),
+ this,SLOT(slotPlay(bool)));
+}
+
+QWidget* SoundComboPropertyLine::item()
+{
+ return cb_;
+}
+
+QWidget* SoundComboPropertyLine::button()
+{
+ return playTb_;
+}
+
+void SoundComboPropertyLine::setEnabledEditable(bool b)
+{
+ cb_->setEnabled(b);
+ playTb_->setEnabled(b);
+}
+
+void SoundComboPropertyLine::slotPlay(bool)
+{
+ int loopCount=1;
+ if(PropertyLine* line=helpers_.value("sound_loop",NULL))
+ loopCount=line->currentValue().toInt();
+
+ Sound::instance()->playSystem(currentValue().toString().toStdString(),loopCount);
+}
+
+
+static PropertyLineMaker<StringPropertyLine> makerStr(VProperty::StringGui);
+static PropertyLineMaker<ColourPropertyLine> makerCol(VProperty::ColourGui);
+static PropertyLineMaker<FontPropertyLine> makerFont(VProperty::FontGui);
+static PropertyLineMaker<IntPropertyLine> makerInt(VProperty::IntGui);
+static PropertyLineMaker<BoolPropertyLine> makerBool(VProperty::BoolGui);
+static PropertyLineMaker<ComboPropertyLine> makerCombo(VProperty::StringComboGui);
+static PropertyLineMaker<ComboMultiPropertyLine> makerComboMulti(VProperty::MultiStringComboGui);
+static PropertyLineMaker<SoundComboPropertyLine> makerSoundCombo(VProperty::SoundComboGui);
diff --git a/Viewer/src/PropertyLine.hpp b/Viewer/src/PropertyLine.hpp
new file mode 100644
index 0000000..6c0fe1a
--- /dev/null
+++ b/Viewer/src/PropertyLine.hpp
@@ -0,0 +1,357 @@
+//============================================================================
+// Copyright 2015 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef PROPERTYLINE_INC_
+#define PROPERTYLINE_INC_
+
+#include <string>
+
+#include <QFont>
+#include <QObject>
+#include <QSpinBox>
+#include <QVariant>
+
+class QComboBox;
+class QCheckBox;
+class QLabel;
+class QLineEdit;
+class QSpinBox;
+class QToolButton;
+class QWidget;
+class ComboMulti;
+
+#include "VProperty.hpp"
+
+class PropertyLine;
+
+class FontSizeSpin : public QSpinBox
+{
+public:
+ FontSizeSpin(QWidget* parent=0);
+ void setFamily(QString);
+
+protected:
+ QString textFromValue(int value) const;
+
+ QList<int> vals_;
+
+};
+
+
+
+//-------------------------------------
+// Factory
+//------------------------------------
+
+class PropertyLineFactory
+{
+public:
+ explicit PropertyLineFactory(VProperty::GuiType);
+ virtual ~PropertyLineFactory();
+
+ virtual PropertyLine* make(VProperty* p,bool,QWidget* w) = 0;
+ static PropertyLine* create(VProperty* p,bool,QWidget* w);
+
+private:
+ explicit PropertyLineFactory(const PropertyLineFactory&);
+ PropertyLineFactory& operator=(const PropertyLineFactory&);
+
+};
+
+template<class T>
+class PropertyLineMaker : public PropertyLineFactory
+{
+ PropertyLine* make(VProperty* p,bool addLabel,QWidget* w) { return new T(p,addLabel,w); }
+public:
+ explicit PropertyLineMaker(VProperty::GuiType t) : PropertyLineFactory(t) {}
+};
+
+
+//-------------------------------------
+// Abstract property line editor
+//------------------------------------
+
+class PropertyLine: public QObject
+{
+ Q_OBJECT
+
+public:
+ PropertyLine(VProperty*,bool addLabel,QWidget* parent=0);
+ virtual ~PropertyLine();
+
+ QLabel* label() {return label_;};
+ QLabel* suffixLabel() {return suffixLabel_;};
+ virtual QWidget* item()=0;
+ virtual QWidget* button()=0;
+ QToolButton* defaultTb() {return defaultTb_;};
+ QToolButton* masterTb() {return masterTb_;};
+ VProperty* property() const {return prop_;}
+ VProperty* guiProperty() const {return guiProp_;}
+ virtual bool canExpand() const {return false;}
+
+ void addHelper(PropertyLine*);
+
+ void init();
+ virtual bool applyChange()=0;
+ virtual QVariant currentValue()=0;
+
+public Q_SLOTS:
+ virtual void slotReset(QVariant)=0;
+ virtual void slotReset(VProperty*,QVariant);
+ virtual void slotEnabled(QVariant);
+
+protected Q_SLOTS:
+ void slotResetToDefault(bool);
+ void slotMaster(bool b);
+ void checkState();
+
+Q_SIGNALS:
+ void changed(QVariant);
+ void masterChanged(bool);
+ void changed();
+
+protected:
+ virtual void setEnabledEditable(bool)=0;
+ bool applyMaster();
+ void valueChanged();
+
+ VProperty* prop_;
+ VProperty* guiProp_;
+ QLabel* label_;
+ QLabel* suffixLabel_;
+ QToolButton* defaultTb_;
+ QToolButton* masterTb_;
+ bool enabled_;
+ QVariant oriVal_;
+ bool doNotEmitChange_;
+ QMap<QString,PropertyLine*> helpers_;
+};
+
+//-------------------------------------
+// String editor
+//------------------------------------
+
+class StringPropertyLine : public PropertyLine
+{
+ Q_OBJECT
+
+public:
+ StringPropertyLine(VProperty* vProp,bool addLabel,QWidget * parent=0);
+ QWidget* item();
+ QWidget* button();
+ bool applyChange();
+ QVariant currentValue();
+
+public Q_SLOTS:
+ void slotEdited(QString);
+ void slotReset(QVariant);
+
+protected:
+ void setEnabledEditable(bool);
+
+private:
+ QLineEdit* le_;
+};
+
+//-------------------------------------
+// Colour editor
+//------------------------------------
+
+class ColourPropertyLine : public PropertyLine
+{
+Q_OBJECT
+
+public:
+ ColourPropertyLine(VProperty* vProp,bool addLabel,QWidget * parent=0);
+ QWidget* item();
+ QWidget* button();
+ bool applyChange();
+ QVariant currentValue();
+
+private Q_SLOTS:
+ void slotEdit(bool);
+ void slotReset(QVariant);
+
+protected:
+ void setEnabledEditable(bool);
+
+private:
+ QToolButton* cb_;
+ QColor currentCol_;
+ QString styleSheet_;
+};
+
+//-------------------------------------
+// Font editor
+//------------------------------------
+
+class FontPropertyLine : public PropertyLine
+{
+Q_OBJECT
+
+public:
+ FontPropertyLine(VProperty* vProp,bool addLabel,QWidget * parent=0);
+ QWidget* item();
+ QWidget* button();
+ bool applyChange();
+ QVariant currentValue();
+
+private Q_SLOTS:
+ void slotEdit(bool);
+ void slotReset(QVariant);
+ void slotFamilyChanged(int);
+ void slotSizeChanged(int);
+
+protected:
+ void setEnabledEditable(bool);
+
+private:
+ QWidget* holderW_;
+ QComboBox* familyCb_;
+ QSpinBox* sizeSpin_;
+ QLabel* lName_;
+ QToolButton *tbEdit_;
+ QFont font_;
+};
+
+//-------------------------------------
+// Int editor
+//------------------------------------
+
+class IntPropertyLine : public PropertyLine
+{
+ Q_OBJECT
+
+public:
+ IntPropertyLine(VProperty* vProp,bool addLabel,QWidget * parent=0);
+ QWidget* item();
+ QWidget* button();
+ bool applyChange();
+ QVariant currentValue();
+
+public Q_SLOTS:
+ void slotEdited(QString);
+ void slotReset(QVariant);
+
+protected:
+ void setEnabledEditable(bool);
+
+private:
+ QLineEdit* le_;
+};
+
+//-------------------------------------
+// Boolean editor
+//------------------------------------
+
+class BoolPropertyLine : public PropertyLine
+{
+ Q_OBJECT
+
+public:
+ BoolPropertyLine(VProperty* vProp,bool addLabel,QWidget * parent=0);
+ QWidget* item();
+ QWidget* button();
+ bool applyChange();
+ QVariant currentValue();
+
+public Q_SLOTS:
+ void slotStateChanged(int);
+ void slotReset(QVariant);
+
+protected:
+ void setEnabledEditable(bool);
+
+private:
+ QCheckBox* cb_;
+};
+
+//-------------------------------------
+// Combo box editor
+//------------------------------------
+
+class ComboPropertyLine : public PropertyLine
+{
+ Q_OBJECT
+
+public:
+ ComboPropertyLine(VProperty* vProp,bool addLabel,QWidget * parent=0);
+ QWidget* item();
+ QWidget* button();
+ bool applyChange();
+ QVariant currentValue();
+
+public Q_SLOTS:
+ void slotCurrentChanged(int);
+ void slotReset(QVariant);
+
+protected:
+ void setEnabledEditable(bool);
+
+protected:
+ QComboBox* cb_;
+};
+
+
+//-------------------------------------
+// Combo box editor
+//------------------------------------
+
+class ComboMultiPropertyLine : public PropertyLine
+{
+ Q_OBJECT
+
+public:
+ ComboMultiPropertyLine(VProperty* vProp,bool addLabel,QWidget * parent=0);
+ QWidget* item();
+ QWidget* button();
+ bool applyChange();
+ QVariant currentValue();
+ bool canExpand() const {return true;}
+
+public Q_SLOTS:
+ void slotCurrentChanged(int);
+ void slotReset(QVariant);
+
+protected:
+ void setEnabledEditable(bool);
+
+protected:
+ ComboMulti* cb_;
+};
+
+//-------------------------------------
+// Combo box editor
+//------------------------------------
+
+class SoundComboPropertyLine : public ComboPropertyLine
+{
+ Q_OBJECT
+
+public:
+ SoundComboPropertyLine(VProperty* vProp,bool addLabel,QWidget * parent=0);
+ QWidget* item();
+ QWidget* button();
+
+public Q_SLOTS:
+ void slotPlay(bool);
+
+protected:
+ void setEnabledEditable(bool);
+
+private:
+ QToolButton* playTb_;
+
+};
+
+
+
+#endif
+
diff --git a/Viewer/src/PropertyMapper.cpp b/Viewer/src/PropertyMapper.cpp
new file mode 100644
index 0000000..1d15760
--- /dev/null
+++ b/Viewer/src/PropertyMapper.cpp
@@ -0,0 +1,36 @@
+// Copyright 2015 ECMWF.
+
+#include "PropertyMapper.hpp"
+
+#include "VConfig.hpp"
+
+PropertyMapper::PropertyMapper(const std::vector<std::string>& names,VPropertyObserver* obs) : obs_(obs)
+{
+ for(std::vector<std::string>::const_iterator it=names.begin(); it != names.end(); ++it)
+ {
+ if(VProperty* p=VConfig::instance()->find(*it))
+ {
+ p->addObserver(obs);
+ props_.push_back(p);
+ }
+ }
+}
+
+PropertyMapper::~PropertyMapper()
+{
+ for(std::vector<VProperty*>::const_iterator it=props_.begin(); it != props_.end(); ++it)
+ {
+ (*it)->removeObserver(obs_);
+ }
+}
+
+VProperty* PropertyMapper::find(const std::string& path) const
+{
+ for(std::vector<VProperty*>::const_iterator it=props_.begin(); it != props_.end(); ++it)
+ {
+ if((*it)->path() == path)
+ return *it;
+ }
+
+ return 0;
+}
diff --git a/Viewer/src/PropertyMapper.hpp b/Viewer/src/PropertyMapper.hpp
new file mode 100644
index 0000000..3d3586a
--- /dev/null
+++ b/Viewer/src/PropertyMapper.hpp
@@ -0,0 +1,22 @@
+// Copyright 2014 ECMWF.
+
+#ifndef PROPERTYMAPPER_INC_
+#define PROPERTYMAPPER_INC_
+
+#include "VProperty.hpp"
+
+
+class PropertyMapper
+{
+public:
+ PropertyMapper(const std::vector<std::string>&,VPropertyObserver* obs);
+ ~PropertyMapper();
+ VProperty* find(const std::string& path) const;
+
+private:
+ VPropertyObserver* obs_;
+ std::vector<VProperty*> props_;
+};
+
+#endif
+
diff --git a/Viewer/src/RepeatEditor.cpp b/Viewer/src/RepeatEditor.cpp
new file mode 100644
index 0000000..676d7bb
--- /dev/null
+++ b/Viewer/src/RepeatEditor.cpp
@@ -0,0 +1,388 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "RepeatEditor.hpp"
+
+#include <QtGlobal>
+#include <QIntValidator>
+#include <QStringListModel>
+#include <QSettings>
+
+#include "Node.hpp"
+#include "AttributeEditorFactory.hpp"
+#include "VAttribute.hpp"
+#include "VAttributeType.hpp"
+#include "ServerHandler.hpp"
+#include "SessionHandler.hpp"
+#include "VInfo.hpp"
+#include "VNode.hpp"
+#include "VRepeat.hpp"
+
+RepeatEditorWidget::RepeatEditorWidget(QWidget* parent) : QWidget(parent)
+{
+ setupUi(this);
+}
+
+void RepeatEditorWidget::hideRow(QWidget* w)
+{
+ w->hide();
+ QWidget* item=formLayout_->labelForField(w);
+ Q_ASSERT(item);
+ item->hide();
+}
+
+//================================================================
+//
+// RepeatEditor
+//
+//================================================================
+
+RepeatEditor::RepeatEditor(VInfo_ptr info,QWidget* parent) :
+ AttributeEditor(info,"repeat",parent),
+ repeat_(0),
+ model_(0)
+{
+ w_=new RepeatEditorWidget(this);
+ addForm(w_);
+
+ VAttribute* a=info_->attribute();
+
+ Q_ASSERT(a);
+ Q_ASSERT(a->type());
+ Q_ASSERT(a->type()->name() == "repeat");
+
+ if(a->data().count() < 7)
+ return;
+
+ VNode *vnode=info_->node();
+ Q_ASSERT(vnode);
+ node_ptr node=vnode->node();
+ Q_ASSERT(node);
+ const Repeat& r=node->repeat();
+ repeat_=VRepeat::make(r);
+
+ oriVal_=a->data().at(3);
+
+ w_->nameLabel_->setText(a->data().at(2));
+ //w_->valueLe_->setText(a->data().at(3));
+ w_->startLabel_->setText(a->data().at(4));
+ w_->endLabel_->setText(a->data().at(5));
+ w_->stepLabel_->setText(a->data().at(6));
+
+ //Value will be initailised in the subclasses
+ oriVal_=a->data().at(3);
+
+ buildList();
+
+#if 0
+ QIntValidator *validator=new QIntValidator(this);
+ if(!a->data().at(3).isEmpty() && !a->data().at(4).isEmpty())
+ {
+ validator->setRange(a->data().at(3).toInt(),
+ a->data().at(4).toInt());
+ }
+ valueLe_->setValidator(validator);
+#endif
+
+ header_->setInfo(QString::fromStdString(info_->path()),"Repeat " + QString::fromStdString(repeat_->type()));
+
+ readSettings();
+}
+
+RepeatEditor::~RepeatEditor()
+{
+ if(repeat_)
+ delete repeat_;
+}
+
+void RepeatEditor::buildList()
+{
+ int start=repeat_->startIndex();
+ int end=repeat_->endIndex();
+ int step=repeat_->step();
+ int current=repeat_->currentIndex();
+
+ if(step<=0 || end <= start)
+ {
+ return;
+ }
+
+ modelData_.clear();
+ int cnt=end-start;
+ if(cnt >1 && cnt < 100)
+ {
+ for(size_t i=start; i <= end; i++)
+ modelData_ << QString::fromStdString(repeat_->value(i));
+
+ model_=new QStringListModel(this);
+ model_->setStringList(modelData_);
+ w_->valueView_->setModel(model_);
+ w_->valueView_->setCurrentIndex(model_->index(current,0));
+
+ connect(w_->valueView_,SIGNAL(activated(const QModelIndex&)),
+ this,SLOT(slotSelectedInView(const QModelIndex&)));
+ }
+ else
+ {
+ w_->valueView_->hide();
+ }
+}
+
+void RepeatEditor::slotSelectedInView(const QModelIndex& idx)
+{
+ setValue(idx.data().toString());
+ checkButtonStatus();
+}
+
+bool RepeatEditor::isListMode() const
+{
+ return (model_)?true:false;
+}
+
+void RepeatEditor::writeSettings()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ Q_ASSERT(cs);
+ QSettings settings(QString::fromStdString(cs->qtSettingsFile("RepeatEditor")),
+ QSettings::NativeFormat);
+
+ //We have to clear it so that should not remember all the previous values
+ settings.clear();
+
+ settings.beginGroup("main");
+ settings.setValue("size",size());
+ settings.endGroup();
+}
+
+void RepeatEditor::readSettings()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ Q_ASSERT(cs);
+ QSettings settings(QString::fromStdString(cs->qtSettingsFile("RepeatEditor")),
+ QSettings::NativeFormat);
+
+ settings.beginGroup("main");
+ if(settings.contains("size"))
+ {
+ resize(settings.value("size").toSize());
+ }
+ else
+ {
+ resize(QSize(310,340));
+ }
+
+ settings.endGroup();
+}
+
+//================================================================
+//
+// RepeatIntEditor
+//
+//================================================================
+
+RepeatIntEditor::RepeatIntEditor(VInfo_ptr info,QWidget* parent) :
+ RepeatEditor(info,parent)
+{
+ if(!repeat_)
+ return;
+
+ w_->hideRow(w_->valueLe_);
+ w_->valueSpin_->setValue(oriVal_.toInt());
+
+ connect(w_->valueSpin_,SIGNAL(valueChanged(int)),
+ this,SLOT(slotValueChanged(int)));
+
+ checkButtonStatus();
+}
+
+void RepeatIntEditor::setValue(QString val)
+{
+ w_->valueSpin_->setValue(val.toInt());
+}
+
+void RepeatIntEditor::slotValueChanged(int val)
+{
+ if(isListMode())
+ {
+ QString txt=QString::number(val);
+ int row=modelData_.indexOf(txt);
+ if(row != -1)
+ {
+ w_->valueView_->setCurrentIndex(model_->index(row,0));
+ }
+ else
+ {
+ w_->valueView_->clearSelection();
+ w_->valueView_->setCurrentIndex(QModelIndex());
+ }
+ }
+ checkButtonStatus();
+}
+
+void RepeatIntEditor::resetValue()
+{
+ w_->valueSpin_->setValue(oriVal_.toInt());
+ slotValueChanged(oriVal_.toInt());
+ checkButtonStatus();
+}
+
+bool RepeatIntEditor::isValueChanged()
+{
+ return(oriVal_.toInt() != w_->valueSpin_->value());
+}
+
+void RepeatIntEditor::apply()
+{
+ std::string val=QString::number(w_->valueSpin_->value()).toStdString();
+ //std::string name=w_->nameLabel_->text().toStdString();
+
+ std::vector<std::string> cmd;
+ VAttribute::buildAlterCommand(cmd,"change","repeat",val);
+ ServerHandler::command(info_,cmd);
+}
+
+//================================================================
+//
+// RepeatStringEditor
+//
+//================================================================
+
+RepeatStringEditor::RepeatStringEditor(VInfo_ptr info,QWidget* parent) :
+ RepeatEditor(info,parent)
+{
+ if(!repeat_)
+ return;
+
+ w_->hideRow(w_->valueSpin_);
+ w_->hideRow(w_->stepLabel_);
+ w_->valueLe_->setText(oriVal_);
+
+ connect(w_->valueLe_,SIGNAL(textEdited(QString)),
+ this,SLOT(slotValueEdited(QString)));
+
+ checkButtonStatus();
+}
+
+void RepeatStringEditor::setValue(QString val)
+{
+ w_->valueLe_->setText(val);
+}
+
+void RepeatStringEditor::slotValueEdited(QString txt)
+{
+ if(isListMode())
+ {
+ int row=modelData_.indexOf(txt);
+ if(row != -1)
+ {
+ w_->valueView_->setCurrentIndex(model_->index(row,0));
+ }
+ else
+ {
+ w_->valueView_->clearSelection();
+ w_->valueView_->setCurrentIndex(QModelIndex());
+ }
+ }
+ checkButtonStatus();
+}
+
+void RepeatStringEditor::resetValue()
+{
+ w_->valueLe_->setText(oriVal_);
+ slotValueEdited(oriVal_);
+ checkButtonStatus();
+}
+
+bool RepeatStringEditor::isValueChanged()
+{
+ return(oriVal_ != w_->valueLe_->text());
+}
+
+void RepeatStringEditor::apply()
+{
+ std::string val=w_->valueLe_->text().toStdString();
+ //std::string name=w_->nameLabel_->text().toStdString();
+
+ std::vector<std::string> cmd;
+ VAttribute::buildAlterCommand(cmd,"change","repeat",val);
+ ServerHandler::command(info_,cmd);
+}
+
+//================================================================
+//
+// RepeatDateEditor
+//
+//================================================================
+
+RepeatDateEditor::RepeatDateEditor(VInfo_ptr info,QWidget* parent) :
+ RepeatEditor(info,parent)
+{
+ if(!repeat_)
+ return;
+
+ w_->hideRow(w_->valueSpin_);
+ w_->valueLe_->setText(oriVal_);
+
+ connect(w_->valueLe_,SIGNAL(textEdited(QString)),
+ this,SLOT(slotValueEdited(QString)));
+
+ checkButtonStatus();
+}
+
+void RepeatDateEditor::setValue(QString val)
+{
+ w_->valueLe_->setText(val);
+}
+
+void RepeatDateEditor::slotValueEdited(QString txt)
+{
+ if(isListMode())
+ {
+ int row=modelData_.indexOf(txt);
+ if(row != -1)
+ {
+ w_->valueView_->setCurrentIndex(model_->index(row,0));
+ }
+ else
+ {
+ w_->valueView_->clearSelection();
+ w_->valueView_->setCurrentIndex(QModelIndex());
+ }
+ }
+ checkButtonStatus();
+}
+
+void RepeatDateEditor::resetValue()
+{
+ w_->valueLe_->setText(oriVal_);
+ slotValueEdited(oriVal_);
+ checkButtonStatus();
+}
+
+bool RepeatDateEditor::isValueChanged()
+{
+ return(oriVal_ != w_->valueLe_->text());
+}
+
+void RepeatDateEditor::apply()
+{
+ std::string val=w_->valueLe_->text().toStdString();
+ //std::string name=w_->nameLabel_->text().toStdString();
+
+ std::vector<std::string> cmd;
+ VAttribute::buildAlterCommand(cmd,"change","repeat",val);
+ ServerHandler::command(info_,cmd);
+}
+
+
+static AttributeEditorMaker<RepeatIntEditor> makerStr1("repeat_integer");
+static AttributeEditorMaker<RepeatStringEditor> makerStr2("repeat_string");
+static AttributeEditorMaker<RepeatStringEditor> makerStr3("repeat_enumerated");
+static AttributeEditorMaker<RepeatDateEditor> makerStr4("repeat_date");
diff --git a/Viewer/src/RepeatEditor.hpp b/Viewer/src/RepeatEditor.hpp
new file mode 100644
index 0000000..1ac1810
--- /dev/null
+++ b/Viewer/src/RepeatEditor.hpp
@@ -0,0 +1,112 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef REPEATEDITOR_HPP
+#define REPEATEDITOR_HPP
+
+#include "ui_RepeatEditorWidget.h"
+
+#include "AttributeEditor.hpp"
+#include "VInfo.hpp"
+
+class QModelIndex;
+class QStringList;
+class QStringListModel;
+class VRepeat;
+class RepeatEditor;
+
+class RepeatEditorWidget : public QWidget, protected Ui::RepeatEditorWidget
+{
+friend class RepeatEditor;
+friend class RepeatIntEditor;
+friend class RepeatStringEditor;
+friend class RepeatDateEditor;
+public:
+ RepeatEditorWidget(QWidget *parent=0);
+protected:
+ void hideRow(QWidget* w);
+};
+
+class RepeatEditor : public AttributeEditor
+{
+Q_OBJECT
+
+public:
+ RepeatEditor(VInfo_ptr,QWidget* parent=0);
+ ~RepeatEditor();
+
+protected Q_SLOTS:
+ void slotSelectedInView(const QModelIndex&);
+
+protected:
+ void buildList();
+ bool isListMode() const;
+ virtual void setValue(QString)=0;
+ void readSettings();
+ void writeSettings();
+
+ RepeatEditorWidget* w_;
+ VRepeat* repeat_;
+ QStringListModel* model_;
+ QStringList modelData_;
+ QString oriVal_;
+};
+
+class RepeatIntEditor : public RepeatEditor
+{
+Q_OBJECT
+public:
+ RepeatIntEditor(VInfo_ptr,QWidget* parent=0);
+
+protected Q_SLOTS:
+ void slotValueChanged(int);
+
+protected:
+ void apply();
+ void setValue(QString val);
+ void resetValue();
+ bool isValueChanged();
+};
+
+class RepeatStringEditor : public RepeatEditor
+{
+Q_OBJECT
+public:
+ RepeatStringEditor(VInfo_ptr,QWidget* parent=0);
+
+protected Q_SLOTS:
+ void slotValueEdited(QString);
+
+protected:
+ void apply();
+ void setValue(QString val);
+ void resetValue();
+ bool isValueChanged();
+};
+
+class RepeatDateEditor : public RepeatEditor
+{
+Q_OBJECT
+public:
+ RepeatDateEditor(VInfo_ptr,QWidget* parent=0);
+
+protected Q_SLOTS:
+ void slotValueEdited(QString);
+
+protected:
+ void apply();
+ void setValue(QString val);
+ void resetValue();
+ bool isValueChanged();
+};
+
+#endif // REPEATEDITOR_HPP
+
+
diff --git a/Viewer/src/RepeatEditorWidget.ui b/Viewer/src/RepeatEditorWidget.ui
new file mode 100644
index 0000000..1d23732
--- /dev/null
+++ b/Viewer/src/RepeatEditorWidget.ui
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>RepeatEditorWidget</class>
+ <widget class="QWidget" name="RepeatEditorWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>329</width>
+ <height>227</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout_">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="nameLabel_">
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Start:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="startLabel_">
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>End:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="endLabel_">
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_6">
+ <property name="text">
+ <string>Step:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLabel" name="stepLabel_">
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Value:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1">
+ <widget class="QLineEdit" name="valueLe_"/>
+ </item>
+ <item row="6" column="1">
+ <widget class="QListView" name="valueView_"/>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Value:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QSpinBox" name="valueSpin_"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Viewer/src/SaveSessionAsDialog.cpp b/Viewer/src/SaveSessionAsDialog.cpp
new file mode 100644
index 0000000..35f6a7f
--- /dev/null
+++ b/Viewer/src/SaveSessionAsDialog.cpp
@@ -0,0 +1,120 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include <QMessageBox>
+
+
+#include "SaveSessionAsDialog.hpp"
+#include "ui_SaveSessionAsDialog.h"
+
+#include "DirectoryHandler.hpp"
+
+
+SaveSessionAsDialog::SaveSessionAsDialog(QWidget *parent) : QDialog(parent)
+{
+ //ui->setupUi(this);
+ setupUi(this);
+
+ refreshListOfSavedSessions();
+
+ // ensure the correct state of the Save button
+ on_sessionNameEdit__textChanged();
+}
+
+SaveSessionAsDialog::~SaveSessionAsDialog()
+{
+ //delete ui;
+}
+
+void SaveSessionAsDialog::refreshListOfSavedSessions()
+{
+ //sessionsTable_->clearContents();
+ savedSessionsList_->clear();
+
+ // get the list of existing sessions
+ int numSessions = SessionHandler::instance()->numSessions();
+ for (int i = 0; i < numSessions; i++)
+ {
+ SessionItem *s = SessionHandler::instance()->sessionFromIndex(i);
+ addSessionToTable(s);
+ }
+}
+
+void SaveSessionAsDialog::addSessionToTable(SessionItem *s)
+{
+
+ savedSessionsList_->addItem(QString::fromStdString(s->name()));
+/*
+ int lastRow = sessionsTable_->rowCount()-1;
+ sessionsTable_->insertRow(lastRow+1);
+
+ QTableWidgetItem *nameItem = new QTableWidgetItem(QString::fromStdString(s->name()));
+ sessionsTable_->setItem(lastRow+1, 0, nameItem);
+*/
+}
+
+bool SaveSessionAsDialog::validSaveName(const std::string &name)
+{
+ QString boxName(QObject::tr("Save session"));
+ // name empty?
+ if (name.empty())
+ {
+ QMessageBox::critical(0,boxName, tr("Please enter a name for the session"));
+ return false;
+ }
+
+
+ // is there already a session with this name?
+ bool sessionWithThisName = (SessionHandler::instance()->find(name) != NULL);
+
+ if (sessionWithThisName)
+ {
+ QMessageBox::critical(0,boxName, tr("A session with that name already exists - please choose another name"));
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
+
+void SaveSessionAsDialog::on_sessionNameEdit__textChanged()
+{
+ // only allow to save a non-empty session name
+ saveButton_->setEnabled(!sessionNameEdit_->text().isEmpty());
+}
+
+
+void SaveSessionAsDialog::on_saveButton__clicked()
+{
+ std::string name = sessionNameEdit_->text().toStdString();
+
+ if (validSaveName(name))
+ {
+ SessionItem* newSession = SessionHandler::instance()->copySession(SessionHandler::instance()->current(), name);
+ if (newSession)
+ {
+ //SessionHandler::instance()->add(name);
+ refreshListOfSavedSessions();
+ SessionHandler::instance()->current(newSession);
+ QMessageBox::information(0,tr("Session"), tr("Session saved"));
+ }
+ else
+ {
+ QMessageBox::critical(0,tr("Session"), tr("Failed to save session"));
+ }
+ close();
+ }
+}
+
+// called when the user clicks the Save button
+//void SaveSessionAsDialog::accept()
+//{
+//
+//}
diff --git a/Viewer/src/SaveSessionAsDialog.hpp b/Viewer/src/SaveSessionAsDialog.hpp
new file mode 100644
index 0000000..82d76b3
--- /dev/null
+++ b/Viewer/src/SaveSessionAsDialog.hpp
@@ -0,0 +1,41 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef SAVESESSIONASDIALOG_HPP
+#define SAVESESSIONASDIALOG_HPP
+
+#include <QDialog>
+#include "ui_SaveSessionAsDialog.h"
+
+#include "SessionHandler.hpp"
+
+namespace Ui {
+class SaveSessionAsDialog;
+}
+
+class SaveSessionAsDialog : public QDialog, protected Ui::SaveSessionAsDialog
+{
+ Q_OBJECT
+
+public:
+ explicit SaveSessionAsDialog(QWidget *parent = 0);
+ ~SaveSessionAsDialog();
+
+public Q_SLOTS:
+ void on_saveButton__clicked();
+ void on_sessionNameEdit__textChanged();
+
+private:
+ //Ui::SaveSessionAsDialog *ui;
+ void addSessionToTable(SessionItem *s);
+ bool validSaveName(const std::string &name);
+ void refreshListOfSavedSessions();
+};
+
+#endif // SAVESESSIONASDIALOG_HPP
diff --git a/Viewer/src/SaveSessionAsDialog.ui b/Viewer/src/SaveSessionAsDialog.ui
new file mode 100644
index 0000000..14b9623
--- /dev/null
+++ b/Viewer/src/SaveSessionAsDialog.ui
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SaveSessionAsDialog</class>
+ <widget class="QDialog" name="SaveSessionAsDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>411</width>
+ <height>292</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Save session</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Existing sessions</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QListWidget" name="savedSessionsList_">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::NoSelection</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>New session:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Name:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="sessionNameEdit_"/>
+ </item>
+ <item>
+ <widget class="QPushButton" name="saveButton_">
+ <property name="text">
+ <string>&Save</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox_">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Close</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox_</sender>
+ <signal>accepted()</signal>
+ <receiver>SaveSessionAsDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox_</sender>
+ <signal>rejected()</signal>
+ <receiver>SaveSessionAsDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/Viewer/src/ScriptItemWidget.cpp b/Viewer/src/ScriptItemWidget.cpp
new file mode 100644
index 0000000..1580444
--- /dev/null
+++ b/Viewer/src/ScriptItemWidget.cpp
@@ -0,0 +1,109 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "ScriptItemWidget.hpp"
+
+#include "Highlighter.hpp"
+#include "InfoProvider.hpp"
+#include "MessageLabel.hpp"
+#include "VConfig.hpp"
+#include "VNode.hpp"
+#include "VReply.hpp"
+
+//========================================================
+//
+// ScriptItemWidget
+//
+//========================================================
+
+ScriptItemWidget::ScriptItemWidget(QWidget *parent) : CodeItemWidget(parent)
+{
+ messageLabel_->hide();
+
+ //Remove the first spacer item!!
+ removeSpacer();
+
+ Highlighter* ih=new Highlighter(textEdit_->document(),"script");
+
+ infoProvider_=new ScriptProvider(this);
+
+ //Editor font
+ textEdit_->setFontProperty(VConfig::instance()->find("panel.script.font"));
+}
+
+ScriptItemWidget::~ScriptItemWidget()
+{
+}
+
+QWidget* ScriptItemWidget::realWidget()
+{
+ return this;
+}
+
+void ScriptItemWidget::reload(VInfo_ptr info)
+{
+ assert(active_);
+
+ if(suspended_)
+ return;
+
+ clearContents();
+ info_=info;
+ messageLabel_->hide();
+
+ //Info must be a node
+ if(info_ && info_->isNode() && info_->node())
+ {
+ infoProvider_->info(info_);
+ }
+}
+
+void ScriptItemWidget::clearContents()
+{
+ InfoPanelItem::clear();
+ fileLabel_->clear();
+ textEdit_->clear();
+ messageLabel_->hide();
+}
+
+void ScriptItemWidget::infoReady(VReply* reply)
+{
+ messageLabel_->hide();
+
+ QString s=QString::fromStdString(reply->text());
+ textEdit_->setPlainText(s);
+
+ if(reply->hasWarning())
+ {
+ messageLabel_->showWarning(QString::fromStdString(reply->warningText()));
+ }
+ else if(reply->hasInfo())
+ {
+ messageLabel_->showInfo(QString::fromStdString(reply->infoText()));
+ }
+
+ fileLabel_->update(reply);
+
+}
+
+void ScriptItemWidget::infoProgress(VReply* reply)
+{
+ QString s=QString::fromStdString(reply->text());
+ messageLabel_->showInfo(QString::fromStdString(reply->infoText()));
+}
+
+void ScriptItemWidget::infoFailed(VReply* reply)
+{
+ QString s=QString::fromStdString(reply->errorText());
+ //textEdit_->setPlainText(s);
+ messageLabel_->showError(s);
+}
+
+
+static InfoPanelItemMaker<ScriptItemWidget> maker1("script");
diff --git a/Viewer/src/ScriptItemWidget.hpp b/Viewer/src/ScriptItemWidget.hpp
new file mode 100644
index 0000000..31e6e51
--- /dev/null
+++ b/Viewer/src/ScriptItemWidget.hpp
@@ -0,0 +1,40 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef SCRIPTITEMWIDGET_HPP_
+#define SCRIPTITEMWIDGET_HPP_
+
+#include "InfoPanelItem.hpp"
+#include "CodeItemWidget.hpp"
+
+class ScriptItemWidget : public CodeItemWidget, public InfoPanelItem
+{
+public:
+ explicit ScriptItemWidget(QWidget *parent=0);
+ ~ScriptItemWidget();
+
+ void reload(VInfo_ptr);
+ QWidget* realWidget();
+ void clearContents();
+
+ //From VInfoPresenter
+ void infoReady(VReply*);
+ void infoFailed(VReply*);
+ void infoProgress(VReply*);
+
+ void nodeChanged(const VNode*, const std::vector<ecf::Aspect::Type>&) {}
+ void defsChanged(const std::vector<ecf::Aspect::Type>&) {}
+
+protected:
+ void updateState(const ChangeFlags&) {}
+};
+
+#endif
+
diff --git a/Viewer/src/SearchLineWidget.ui b/Viewer/src/SearchLineWidget.ui
new file mode 100644
index 0000000..b2eb7ce
--- /dev/null
+++ b/Viewer/src/SearchLineWidget.ui
@@ -0,0 +1,212 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SearchLineWidget</class>
+ <widget class="QWidget" name="SearchLineWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>744</width>
+ <height>266</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0,0,0,1,0,0,0,0,0">
+ <property name="spacing">
+ <number>1</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label_">
+ <property name="text">
+ <string>&Find:</string>
+ </property>
+ <property name="buddy">
+ <cstring>searchLine_</cstring>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="MessageLabel" name="confirmSearchLabel_" native="true"/>
+ </item>
+ <item>
+ <widget class="StringMatchCombo" name="matchModeCb_"/>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="searchLine_"/>
+ </item>
+ <item>
+ <widget class="QToolButton" name="nextTb_">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonIconOnly</enum>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="prevTb_">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonIconOnly</enum>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="optionsTb_">
+ <property name="toolTip">
+ <string>Search options</string>
+ </property>
+ <property name="text">
+ <string>Options</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/images/configure.svg</normaloff>:/viewer/images/configure.svg</iconset>
+ </property>
+ <property name="popupMode">
+ <enum>QToolButton::InstantPopup</enum>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QToolButton" name="closeTb_">
+ <property name="toolTip">
+ <string>Close search bar</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/images/close.svg</normaloff>:/viewer/images/close.svg</iconset>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ <action name="actionCaseSensitive_">
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Case sensitive</string>
+ </property>
+ <property name="toolTip">
+ <string>Case sensitive search</string>
+ </property>
+ <property name="shortcut">
+ <string>Alt+C</string>
+ </property>
+ </action>
+ <action name="actionWholeWords_">
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Whole words</string>
+ </property>
+ <property name="toolTip">
+ <string>Search for whole words only</string>
+ </property>
+ <property name="shortcut">
+ <string>Alt+O</string>
+ </property>
+ </action>
+ <action name="actionNext_">
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/images/arrow_down.svg</normaloff>:/viewer/images/arrow_down.svg</iconset>
+ </property>
+ <property name="text">
+ <string>Find next</string>
+ </property>
+ <property name="toolTip">
+ <string>Jump to next match <code>F3</code></string>
+ </property>
+ <property name="shortcut">
+ <string>F3</string>
+ </property>
+ </action>
+ <action name="actionPrev_">
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/images/arrow_up.svg</normaloff>:/viewer/images/arrow_up.svg</iconset>
+ </property>
+ <property name="text">
+ <string>Find prev</string>
+ </property>
+ <property name="toolTip">
+ <string>Jump to previous match <code>Shift+F3</code></string>
+ </property>
+ <property name="shortcut">
+ <string>Shift+F3</string>
+ </property>
+ </action>
+ <action name="actionHighlightAll_">
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Highlight All</string>
+ </property>
+ <property name="toolTip">
+ <string>Highlight all occurrences of the text</string>
+ </property>
+ <property name="shortcut">
+ <string>Alt+A</string>
+ </property>
+ </action>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>MessageLabel</class>
+ <extends>QWidget</extends>
+ <header>MessageLabel.hpp</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>StringMatchCombo</class>
+ <extends>QComboBox</extends>
+ <header>StringMatchCombo.hpp</header>
+ </customwidget>
+ </customwidgets>
+ <resources>
+ <include location="viewer.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/Viewer/src/ServerAddDialog.ui b/Viewer/src/ServerAddDialog.ui
new file mode 100644
index 0000000..2937fb4
--- /dev/null
+++ b/Viewer/src/ServerAddDialog.ui
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ServerAddDialog</class>
+ <widget class="QDialog" name="ServerAddDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>294</width>
+ <height>172</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Add new server</string>
+ </property>
+ <property name="modal">
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>&Name:</string>
+ </property>
+ <property name="buddy">
+ <cstring>label</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="nameEdit"/>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="hostEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>&Host:</string>
+ </property>
+ <property name="buddy">
+ <cstring>hostEdit</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>&Port:</string>
+ </property>
+ <property name="buddy">
+ <cstring>portEdit</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="portEdit"/>
+ </item>
+ <item row="3" column="1">
+ <widget class="QCheckBox" name="addToCurrentCb">
+ <property name="text">
+ <string>Add server to current &view</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>ServerAddDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>257</x>
+ <y>218</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>227</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>ServerAddDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>274</x>
+ <y>218</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>283</x>
+ <y>227</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/Viewer/src/ServerComQueue.cpp b/Viewer/src/ServerComQueue.cpp
new file mode 100644
index 0000000..1c02d87
--- /dev/null
+++ b/Viewer/src/ServerComQueue.cpp
@@ -0,0 +1,393 @@
+//============================================================================
+// Copyright 2015 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "ServerComQueue.hpp"
+
+#include "ClientInvoker.hpp"
+#include "ServerComThread.hpp"
+#include "ServerHandler.hpp"
+#include "UserMessage.hpp"
+
+// This class manages the tasks to be sent to the ServerComThread, which controls
+// the communication with the ClientInvoker. The ClientInvoker is hidden from the
+// ServerHandler. The ServerHandler defines a task and sends it to
+// ServerComQueue, which then passes it on to the ClientInvoker. When a task is finished
+// ServerComQueue notifies the ServerHandler about it.
+
+ServerComQueue::ServerComQueue(ServerHandler *server,ClientInvoker *client, ServerComThread *comThread) :
+ QObject(server),
+ server_(server),
+ client_(client),
+ comThread_(comThread),
+ timeout_(500),
+ state_(NoState), //the queue is enabled but not running
+ taskIsBeingFinished_(false),
+ taskIsBeingFailed_(false)
+{
+ timer_=new QTimer(this);
+ timer_->setInterval(timeout_);
+
+ connect(timer_,SIGNAL(timeout()),
+ this,SLOT(slotRun()));
+
+ //When the ServerComThread finishes it emits a signal that
+ //is connected to the queue.
+ connect(comThread_, SIGNAL(finished()),
+ this, SLOT(slotTaskFinished()));
+
+ //When there is an error in ServerComThread it emits the
+ //failed() signal that is connected to the queue.
+ connect(comThread_, SIGNAL(failed(std::string)),
+ this, SLOT(slotTaskFailed(std::string)));
+}
+
+ServerComQueue::~ServerComQueue()
+{
+ state_=DisabledState;
+
+ //Stop the timer
+ timer_->stop();
+
+ //Empty the tasks
+ tasks_.clear();
+
+ //Disconnects all the signals from the thread
+ comThread_->disconnect(0,this);
+
+ //If the comthread is running we need to wait
+ //until it finishes its task.
+ comThread_->wait();
+
+ //Send a logout task
+ VTask_ptr task=VTask::create(VTask::LogOutTask);
+ comThread_->task(task);
+
+ //Wait unit the logout finishes
+ comThread_->wait();
+
+ delete comThread_;
+}
+
+void ServerComQueue::enable()
+{
+ state_=NoState;
+ start();
+}
+
+void ServerComQueue::disable()
+{
+ if(state_ == DisabledState)
+ return;
+
+ state_=DisabledState;
+
+ //Remove all tasks
+ tasks_.clear();
+
+ //Stop the timer
+ timer_->stop();
+
+ //If the comthread is running we need to wait
+ //until it finishes its task.
+ comThread_->wait();
+
+ UserMessage::message(UserMessage::DBG, false, std::string("ServerComQueue::disable"));
+
+ //Clear the current task
+ if(current_)
+ current_.reset();
+}
+
+
+//This is a special mode to reload the whole ClientInvoker
+bool ServerComQueue::prepareReset()
+{
+ if(state_ == DisabledState || state_ == ResetState || state_ == SuspendedState)
+ return false;
+
+ //Stop the timer
+ timer_->stop();
+
+ //Remove all tasks
+ tasks_.clear();
+
+ state_=ResetState;
+
+ //If the comthread is running we need to wait
+ //until it finishes its task.
+ comThread_->wait();
+
+ //The thread cannot be running
+ assert(comThread_->isRunning() == false);
+
+ return true;
+}
+
+//This is a special mode to reload the whole ClientInvoker. Must be called after prepareReset returned true;
+void ServerComQueue::reset()
+{
+ assert(state_ == ResetState);
+
+ //The thread cannot be running
+ assert(comThread_->isRunning() == false);
+
+ //We send a Reset command to the thread!! This is the only task that is allowed
+ //during the reset!!
+ VTask_ptr task=VTask::create(VTask::ResetTask);
+ tasks_.push_back(task);
+
+ //TODO: why do we not run it directly
+ //We start the timer with a shorter interval
+ timer_->start(100);
+}
+
+void ServerComQueue::endReset()
+{
+ if(state_ == ResetState)
+ {
+ state_=SuspendedState;
+ start();
+ }
+}
+
+
+//When the queue is started:
+// -it is ready to accept tasks
+// -its timer is running
+void ServerComQueue::start()
+{
+ if(state_ != DisabledState && state_ != ResetState)
+ {
+ UserMessage::message(UserMessage::DBG, false, std::string("comQueue::start"));
+
+ //If the comthread is running we need to wait
+ //until it finishes its task.
+ comThread_->wait();
+
+ state_=RunningState;
+
+ UserMessage::message(UserMessage::DBG, false, std::string("comQueue::start start timer"));
+
+ //Starts the timer
+ timer_->start(timeout_);
+ }
+}
+
+//The queue contents remains the same but the timer is stopped. Until start() is
+//called nothing will be submitted to the queue.
+void ServerComQueue::suspend(bool wait)
+{
+ if(state_ != DisabledState && state_ != ResetState &&
+ state_ != SuspendedState)
+ {
+ state_=SuspendedState;
+ timer_->stop();
+ if(wait)
+ {
+ comThread_->wait();
+ }
+ }
+}
+
+bool ServerComQueue::hasTask(VTask::Type t) const
+{
+ for(std::deque<VTask_ptr>::const_iterator it=tasks_.begin(); it != tasks_.end(); ++it)
+ {
+ if(*it && (*it)->type() == t && (*it)->status() != VTask::CANCELLED &&
+ (*it)->status() != VTask::ABORTED )
+ return true;
+
+ }
+ return false;
+}
+
+bool ServerComQueue::isNextTask(VTask::Type t) const
+{
+ return (!tasks_.empty() && tasks_.back()->type() == t);
+}
+
+
+void ServerComQueue::addTask(VTask_ptr task)
+{
+ if(!task)
+ return;
+
+ if(isNextTask(VTask::ZombieListTask) && tasks_.back()->type() == task->type())
+ return;
+
+ if(state_ == DisabledState || state_ == ResetState ||
+ (task && task->type() ==VTask::ResetTask) )
+ return;
+
+ tasks_.push_back(task);
+ if(state_ != SuspendedState)
+ {
+ if(!timer_->isActive())
+ {
+ //we immediately execute the "current" task
+ slotRun();
+ //and only start the timer after it
+ timer_->start(timeout_);
+ }
+ }
+}
+
+void ServerComQueue::addNewsTask()
+{
+ if(state_ == DisabledState || state_ == ResetState)
+ return;
+
+ if(isNextTask(VTask::NewsTask))
+ return;
+
+ VTask_ptr task=VTask::create(VTask::NewsTask);
+ addTask(task);
+}
+
+void ServerComQueue::addSyncTask()
+{
+ if(state_ == DisabledState || state_ == ResetState)
+ return;
+
+ if(isNextTask(VTask::SyncTask))
+ return;
+
+ VTask_ptr task=VTask::create(VTask::SyncTask);
+ addTask(task);
+}
+
+void ServerComQueue::addSuiteListTask()
+{
+ if(state_ == DisabledState || state_ == ResetState)
+ return;
+
+ if(isNextTask(VTask::SuiteListTask))
+ return;
+
+ VTask_ptr task=VTask::create(VTask::SuiteListTask);
+ addTask(task);
+}
+
+void ServerComQueue::addSuiteAutoRegisterTask()
+{
+ if(state_ == DisabledState || state_ == ResetState)
+ return;
+
+ if(isNextTask(VTask::SuiteAutoRegisterTask))
+ return;
+
+ VTask_ptr task=VTask::create(VTask::SuiteAutoRegisterTask);
+ addTask(task);
+}
+
+void ServerComQueue::slotRun()
+{
+ if(state_ == DisabledState ||state_ == SuspendedState )
+ return;
+
+ if(taskIsBeingFinished_ || taskIsBeingFailed_)
+ return;
+
+ //UserMessage::message(UserMessage::DBG, false, std::string("ServerComQueue::slotRun"));
+ //UserMessage::message(UserMessage::DBG, false, std::string(" --> number of tasks: " + boost::lexical_cast<std::string>(tasks_.size()) ));
+ //for(std::deque<VTask_ptr>::const_iterator it=tasks_.begin(); it != tasks_.end(); it++)
+ //{
+ // UserMessage::message(UserMessage::DBG, false," -task: " + (*it)->typeString());
+ //}
+
+ if(tasks_.empty())
+ {
+ //UserMessage::message(UserMessage::DBG, false, std::string(" --> stop timer"));
+ timer_->stop();
+ return;
+ }
+
+ if(current_)
+ {
+ //UserMessage::message(UserMessage::DBG, false, std::string(" --> processing reply from previous task"));
+ return;
+ }
+
+ if(comThread_->isRunning())
+ {
+ //UserMessage::message(UserMessage::DBG, false, std::string(" --> thread is active"));
+ return;
+ }
+
+ //We search for the first non-cancelled/aborted task
+ while(!tasks_.empty())
+ {
+ current_=tasks_.front();
+ tasks_.pop_front();
+ if(current_->status() != VTask::CANCELLED &&
+ current_->status() != VTask::ABORTED )
+ {
+ break;
+ }
+ }
+
+ if(!current_)
+ {
+ timer_->stop();
+ return;
+ }
+
+ //UserMessage::message(UserMessage::DBG, false," --> run task: " + current_->typeString());
+
+ //Send it to the thread
+ comThread_->task(current_);
+}
+
+//This slot is called when ComThread finishes its task. At this point the
+//thread is not running so it is safe to access the ClientInvoker!
+void ServerComQueue::slotTaskFinished()
+{
+ taskIsBeingFinished_=true;
+
+ UserMessage::message(UserMessage::DBG, false,std::string("ServerComQueue::slotTaskFinished"));
+
+ //We need to leave the load mode
+ endReset();
+
+ //If the current task is empty there must have been an error that was
+ //handled by the sloTaskFailed slot.
+ if(current_)
+ {
+ VTask_ptr task=current_;
+ current_.reset();
+
+ //We notify the server that the task has finished and the results can be accessed.
+ server_->clientTaskFinished(task,client_->server_reply());
+ }
+
+ taskIsBeingFinished_=false;
+}
+
+//This slot is called when the task failed in the ComThread. Right after this signal is emitted
+//the thread will finish and and emits the finished() signal that is connected
+//to the slotTaskFinished slot.
+void ServerComQueue::slotTaskFailed(std::string msg)
+{
+ taskIsBeingFailed_=true;
+
+ UserMessage::message(UserMessage::DBG, false,std::string("ServerComQueue::slotTaskFailed"));
+
+ //We need to leave the load mode
+ endReset();
+
+ assert(current_);
+
+ VTask_ptr task=current_;
+ current_.reset();
+
+ //We notify the server that the task has failed
+ server_->clientTaskFailed(task,msg);
+
+ taskIsBeingFailed_=false;
+}
diff --git a/Viewer/src/ServerComQueue.hpp b/Viewer/src/ServerComQueue.hpp
new file mode 100644
index 0000000..9b86b53
--- /dev/null
+++ b/Viewer/src/ServerComQueue.hpp
@@ -0,0 +1,80 @@
+//============================================================================
+// Copyright 2015 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef SERVERCOMQUEUE_HPP_
+#define SERVERCOMQUEUE_HPP_
+
+#include <deque>
+#include <vector>
+
+#include "VTask.hpp"
+
+#include <QObject>
+#include <QTimer>
+
+class ClientInvoker;
+class NodeObserver;
+class ServerHandler;
+class ServerComThread;
+
+// --------------------------------------------------------------
+// ServerComQueue - a class to provide a queueing system for
+// sending tasks to the ClientIvoker via the ServerComThread.
+// --------------------------------------------------------------
+
+class ServerComQueue : public QObject
+{
+Q_OBJECT
+
+public:
+ ServerComQueue(ServerHandler *server,ClientInvoker* client,ServerComThread* comThread);
+ ~ServerComQueue();
+
+ enum State {NoState,RunningState,SuspendedState,ResetState,DisabledState};
+ State state() const {return state_;}
+
+ void addTask(VTask_ptr);
+ void addNewsTask();
+ void addSyncTask();
+ void addSuiteListTask();
+ void addSuiteAutoRegisterTask();
+
+ void enable();
+ void disable();
+ void start();
+ void suspend(bool);
+ bool prepareReset();
+ void reset();
+ bool isSuspended() const {return state_==SuspendedState;}
+
+protected Q_SLOTS:
+ void slotRun();
+
+protected Q_SLOTS:
+ void slotTaskFinished();
+ void slotTaskFailed(std::string);
+
+protected:
+ void endReset();
+ bool hasTask(VTask::Type t) const;
+ bool isNextTask(VTask::Type t) const;
+
+ ServerHandler *server_;
+ ClientInvoker* client_;
+ ServerComThread *comThread_;
+ QTimer* timer_;
+ int timeout_;
+ std::deque<VTask_ptr> tasks_;
+ VTask_ptr current_;
+ State state_;
+ bool taskIsBeingFinished_;
+ bool taskIsBeingFailed_;
+};
+
+#endif
diff --git a/Viewer/src/ServerComThread.cpp b/Viewer/src/ServerComThread.cpp
new file mode 100644
index 0000000..505c24d
--- /dev/null
+++ b/Viewer/src/ServerComThread.cpp
@@ -0,0 +1,613 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "ServerComThread.hpp"
+
+#include "Defs.hpp"
+#include "ClientInvoker.hpp"
+#include "ArgvCreator.hpp"
+
+#include "ServerDefsAccess.hpp"
+#include "ServerComQueue.hpp"
+#include "ServerHandler.hpp"
+#include "SuiteFilter.hpp"
+#include "UserMessage.hpp"
+
+#include <algorithm>
+#include <sstream>
+
+#include <boost/algorithm/string/join.hpp>
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include <QDebug>
+
+ServerComThread::ServerComThread(ServerHandler *server, ClientInvoker *ci) :
+ server_(server),
+ ci_(ci),
+ taskType_(VTask::NoTask),
+ rescanNeed_(false),
+ hasSuiteFilter_(false),
+ autoAddNewSuites_(false),
+ maxLineNum_(-1)
+{
+}
+
+ServerComThread::~ServerComThread()
+{
+ detach();
+}
+
+void ServerComThread::task(VTask_ptr task)
+{
+ // do not execute thread if already running
+
+ if (isRunning())
+ {
+ UserMessage::message(UserMessage::ERROR, true, std::string("ServerComThread::sendCommand - thread already running, will not execute command"));
+ }
+ else
+ {
+ //if(!server_ && server)
+ // initObserver(server);
+
+ //We set the parameters needed to run the task. These members are not protected by
+ //a mutex, because apart from this function only run() can access them!!
+ command_=task->command();
+ params_=task->params();
+ contents_=task->contents();
+ vars_=task->vars();
+ nodePath_.clear();
+ taskType_=task->type();
+ nodePath_=task->targetPath();
+
+ //Suite filter
+ hasSuiteFilter_=server_->suiteFilter()->isEnabled();
+ autoAddNewSuites_=server_->suiteFilter()->autoAddNewSuites();
+ filteredSuites_=server_->suiteFilter()->filter();
+
+ maxLineNum_=server_->conf()->intValue(VServerSettings::MaxOutputFileLines);
+
+ //Start the thread execution
+ start();
+ }
+}
+
+void ServerComThread::run()
+{
+ //Can we use it? We are in the thread!!!
+ //UserMessage::message(UserMessage::DBG, false, std::string(" ServerComThread::run start"));
+
+ UserMessage::message(UserMessage::DBG, false, std::string("ServerComThread::run path: ") + nodePath_);
+
+ //Init flags
+ rescanNeed_=false;
+
+ try
+ {
+ switch (taskType_)
+ {
+ case VTask::CommandTask:
+ {
+ // call the client invoker with the saved command
+ UserMessage::message(UserMessage::DBG, false, std::string(" COMMAND"));
+ ArgvCreator argvCreator(command_);
+ //UserMessage::message(UserMessage::DBG, false, argvCreator.toString());
+
+ ci_->invoke(argvCreator.argc(), argvCreator.argv());
+
+ /*ci_->news_local();
+ switch (ci_->server_reply().get_news())
+ {
+ case ServerReply::NO_NEWS:
+ case ServerReply::NEWS:
+ ci_->sync_local();
+ break;
+ case ServerReply::DO_FULL_SYNC:
+
+ break;
+ }*/
+ break;
+ }
+
+ case VTask::NewsTask:
+ {
+ UserMessage::message(UserMessage::DBG, false, std::string(" NEWS"));
+ ci_->news_local(); // call the server
+ break;
+ }
+
+ case VTask::SyncTask:
+ {
+ UserMessage::message(UserMessage::DBG, false, std::string(" SYNC"));
+ sync_local();
+ break;
+ }
+
+ //This is called during reset
+ case VTask::ResetTask:
+ {
+ UserMessage::message(UserMessage::DBG, false, std::string(" RESET"));
+ reset();
+ break;
+ }
+
+ case VTask::JobTask:
+ case VTask::ManualTask:
+ case VTask::ScriptTask:
+ case VTask::OutputTask:
+ {
+ UserMessage::message(UserMessage::DBG, false, std::string(" FILE"));
+ if(maxLineNum_ < 0)
+ ci_->file(nodePath_,params_["clientPar"]);
+ else
+ ci_->file(nodePath_,params_["clientPar"],boost::lexical_cast<std::string>(maxLineNum_));
+
+ break;
+ }
+
+ case VTask::MessageTask:
+ {
+ UserMessage::message(UserMessage::DBG, false, std::string(" EDIT HISTORY"));
+ ci_->edit_history(nodePath_);
+ break;
+ }
+
+ case VTask::StatsTask:
+ {
+ UserMessage::message(UserMessage::DBG, false, std::string(" STATS"));
+ ci_->stats();
+ break;
+ }
+
+ case VTask::HistoryTask:
+ {
+ UserMessage::message(UserMessage::DBG, false, std::string(" HISTORY"));
+ ci_->getLog(100);
+ break;
+ }
+
+ case VTask::ScriptPreprocTask:
+ UserMessage::message(UserMessage::DBG, false, std::string(" SCRIP PREPROCESS"));
+ ci_->edit_script_preprocess(nodePath_);
+ break;
+
+ case VTask::ScriptEditTask:
+ UserMessage::message(UserMessage::DBG, false, std::string(" SCRIP EDIT"));
+ ci_->edit_script_edit(nodePath_);
+ break;
+
+ case VTask::ScriptSubmitTask:
+ UserMessage::message(UserMessage::DBG, false, std::string(" SCRIP SUBMIT"));
+ ci_->edit_script_submit(nodePath_, vars_, contents_,
+ (params_["alias"]=="1")?true:false,
+ (params_["run"] == "1")?true:false);
+ break;
+
+ case VTask::SuiteListTask:
+ UserMessage::message(UserMessage::DBG, false, std::string(" SUITES"));
+ ci_->suites();
+ break;
+
+ case VTask::SuiteAutoRegisterTask:
+ UserMessage::message(UserMessage::DBG, false, std::string(" SUITE AUTO REGISTER"));
+ if(hasSuiteFilter_)
+ {
+ ci_->ch1_auto_add(autoAddNewSuites_);
+ }
+ break;
+
+ case VTask::ZombieListTask:
+ UserMessage::message(UserMessage::DBG, false, std::string(" ZOMBIES"));
+ ci_->zombieGet();
+ break;
+
+ case VTask::LogOutTask:
+ UserMessage::message(UserMessage::DBG, false, std::string(" LOGOUT"));
+ detach();
+ if(ci_->client_handle() > 0)
+ {
+ ci_->ch1_drop();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ catch(std::exception& e)
+ {
+ // note that we need to emit a signal rather than directly call a message function
+ // because we can't call Qt widgets from a worker thread
+
+ std::string errorString = e.what();
+ Q_EMIT failed(errorString);
+
+ UserMessage::message(UserMessage::DBG, false, std::string(" ServerComThread::run failed: ") + errorString);
+
+ //Reset flags
+ rescanNeed_=false;
+
+ //This will stop the thread.
+ return;
+ }
+
+ //Reset flags
+ rescanNeed_=false;
+
+ //Can we use it? We are in the thread!!!
+ //UserMessage::message(UserMessage::DBG, false, std::string(" ServerComThread::run finished"));
+}
+
+
+void ServerComThread::sync_local()
+{
+ //For this part we need to lock the mutex on defs
+ {
+ ServerDefsAccess defsAccess(server_);
+
+ UserMessage::message(UserMessage::DBG, false, "ServerComThread::sync -- begin");
+ ci_->sync_local();
+ UserMessage::message(UserMessage::DBG, false, std::string("ServerComThread::sync -- end"));
+
+ //If a rescan or fullscan is needed we have either added/remove nodes or deleted the defs.
+ //So there were significant changes.
+
+ //We detach the nodes currently available in defs, then we attach them again. We can still have nodes
+ //that were removed from the defs but are still attached. These will be detached when in ServerHandler we
+ //clear the tree. This tree contains shared pointers to the nodes, so when the tree is cleared
+ //the shared pointer are reset, the node descturctor is called and finally update_delete is called and
+ //we can detach the node.
+
+ if(rescanNeed_ || ci_->server_reply().full_sync())
+ {
+ UserMessage::message(UserMessage::DBG, false, std::string(" --> rescan needed!"));
+ detach(defsAccess.defs());
+ attach(defsAccess.defs());
+ }
+ }
+
+ /*if(rescanNeed_ || ci_->server_reply().full_sync())
+ {
+ updateRegSuites();
+ }*/
+}
+
+void ServerComThread::reset()
+{
+ UserMessage::message(UserMessage::DBG, false,"ServerComThread::reset -- begin");
+
+ //Lock the mutex on defs
+ ServerDefsAccess defsAccess(server_);
+
+ //Detach the defs and the nodes from the observer
+ detach(defsAccess.defs());
+
+ /// registering with empty set would lead
+ // to retrieve all server content,
+ // opposite of expected result
+
+ //If we have already set a handle we
+ //need to drop it.
+ if(ci_->client_handle() > 0)
+ {
+ try
+ {
+ ci_->ch1_drop();
+ }
+ catch (std::exception &e)
+ {
+ UserMessage::message(UserMessage::DBG, false, std::string("no drop possible") + e.what());
+ }
+ }
+
+ if(hasSuiteFilter_)
+ {
+ //reset client handle + defs
+ ci_->reset();
+
+ if(!filteredSuites_.empty())
+ {
+ UserMessage::message(UserMessage::DBG, false, std::string(" REGISTER SUITES"));
+
+ //This will add a new handle to the client
+ ci_->ch_register(autoAddNewSuites_, filteredSuites_);
+ }
+ }
+ else
+ {
+ // reset client handle + defs
+ ci_->reset();
+ }
+
+ UserMessage::message(UserMessage::DBG, false, std::string(" INIT SYNC"));
+ ci_->sync_local();
+ UserMessage::message(UserMessage::DBG, false, std::string(" INIT SYNC FINISHED"));
+
+ //Attach the nodes to the observer
+ attach(defsAccess.defs());
+
+ UserMessage::message(UserMessage::DBG, false,"ServerComThread::reset -- end");
+}
+
+
+//Called from sync local!!!
+void ServerComThread::updateRegSuites()
+{
+ if(!hasSuiteFilter_)
+ return;
+
+ //----------------------------------------
+ // Get the registered list of suites!!
+ //----------------------------------------
+ try
+ {
+ ci_->ch_suites();
+ }
+ catch ( std::exception& e )
+ {
+ UserMessage::message(UserMessage::DBG, false, std::string("host::update-reg-suite-error:") + e.what());
+ }
+
+ const std::vector<std::pair<unsigned int, std::vector<std::string> > >& vct=ci_->server_reply().get_client_handle_suites();
+
+ std::vector<std::string> regSuites;
+ for(size_t i = 0; i < vct.size(); ++i)
+ {
+ if(vct[i].first == static_cast<unsigned int>(ci_->client_handle()))
+ {
+ regSuites = vct[i].second;
+ break;
+ }
+ }
+
+ //-----------------------------------------
+ // Get the list of suites from the defs
+ //-----------------------------------------
+ const std::vector<suite_ptr>& defSuites = ci_->defs()->suiteVec();
+
+ //-----------------------------------------------------------------------
+ // If something is registered but not in the defs we need to remove it
+ //-----------------------------------------------------------------------
+
+ std::vector<std::string> delSuites;
+ for(std::vector<std::string>::iterator it=regSuites.begin(); it != regSuites.end(); ++it)
+ {
+ bool found=0;
+ for(size_t i = 0; i < defSuites.size(); ++i)
+ {
+ if(defSuites.at(i)->name() == *it)
+ {
+ found=true;
+ break;
+ }
+ }
+ if(!found)
+ {
+ delSuites.push_back(*it);
+ }
+ }
+
+ if(!delSuites.empty())
+ {
+ ci_->ch_remove(ci_->client_handle(),delSuites);
+ }
+
+ //------------------------------------------------------
+ // If something is loaded and in the filter but
+ // not registered we need to register it!!
+ //------------------------------------------------------
+
+ if(!autoAddNewSuites_)
+ {
+ //get the list of loaded suites
+ ci_->suites();
+ const std::vector<std::string>& loadedSuites=ci_->server_reply().get_string_vec();
+
+ std::vector<std::string> addSuites;
+ for(std::vector<std::string>::const_iterator it=loadedSuites.begin(); it != loadedSuites.end(); ++it)
+ {
+ if(std::find(filteredSuites_.begin(),filteredSuites_.end(),*it) != filteredSuites_.end() &&
+ std::find(regSuites.begin(),regSuites.end(),*it) != regSuites.end())
+ {
+ addSuites.push_back(*it);
+ }
+ }
+
+ if(!addSuites.empty())
+ {
+ ci_->ch_add(ci_->client_handle(),addSuites);
+ }
+ }
+
+ UserMessage::message(UserMessage::DBG, false, std::string("Suite update finished"));
+}
+
+//This is an observer notification method!!
+void ServerComThread::update(const Node* node, const std::vector<ecf::Aspect::Type>& types)
+{
+ //This function can only be called during a SYNC_LOCAl task!!!!
+ assert(taskType_ == VTask::SyncTask);
+
+ std::vector<ecf::Aspect::Type> typesCopy=types;
+
+ UserMessage::message(UserMessage::DBG, false, std::string("ServerComThread::update - node: ") + node->name());
+ for(std::vector<ecf::Aspect::Type>::const_iterator it=types.begin(); it != types.end(); ++it)
+ {
+ int i=*it;
+ std::stringstream ss;
+ ss << i;
+ UserMessage::message(UserMessage::DBG, false, std::string(" aspect: ") + ss.str());
+ }
+
+ //If a node was already requested to be added/deleted in the thread we do not go further. At the end of the sync
+ //we will regenerate everything (the tree as well in ServerHandle).
+ if(rescanNeed_)
+ {
+ UserMessage::message(UserMessage::DBG, false, std::string(" --> No signal emitted (rescan needed)"));
+ return;
+ }
+
+ //This is a radical change
+ if(std::find(types.begin(),types.end(),ecf::Aspect::ADD_REMOVE_NODE) != types.end())
+ {
+ UserMessage::message(UserMessage::DBG, false, std::string(" --> Rescan needed"));
+ rescanNeed_=true;
+
+ //We notify ServerHandler about the radical changes. When ServerHandler receives this signal
+ //it will clear its tree, which stores shared pointers to the nodes (node_ptr). If these pointers are
+ //reset update_delete() might be called, so it should not write any shared variables!
+ Q_EMIT rescanNeed();
+
+ return;
+
+ }
+
+ //This will notify SeverHandler
+ UserMessage::message(UserMessage::DBG, false, std::string(" --> nodeChanged() emitted"));
+ Q_EMIT nodeChanged(node,types);
+}
+
+
+void ServerComThread::update(const Defs* dc, const std::vector<ecf::Aspect::Type>& types)
+{
+ std::vector<ecf::Aspect::Type> typesCopy=types;
+
+ UserMessage::message(UserMessage::DBG, false, std::string("ServerComThread::update - defs: "));
+ for(std::vector<ecf::Aspect::Type>::const_iterator it=types.begin(); it != types.end(); ++it)
+ {
+ int i=*it;
+ std::stringstream ss;
+ ss << i;
+ UserMessage::message(UserMessage::DBG, false, std::string(" aspect: ") + ss.str());
+ }
+
+ //If anything was requested to be deleted in the thread we do not go further
+ //because it will trigger a full rescan in ServerHandler!
+ if(rescanNeed_)
+ {
+ UserMessage::message(UserMessage::DBG, false, std::string(" --> No signal emitted (rescan needed)"));
+ return;
+ }
+
+ //This will notify SeverHandler
+ UserMessage::message(UserMessage::DBG, false, std::string(" --> defsChanged() emitted"));
+ Q_EMIT defsChanged(typesCopy);
+}
+
+void ServerComThread::update_delete(const Node* nc)
+{
+ Node *n=const_cast<Node*>(nc);
+ n->detach(this);
+ //UserMessage::message(UserMessage::DBG, false, std::string("Update delete: ") + n->name());
+}
+
+//This only be called when ComThread is running or from the ComThread desctructor. So it is safe to set
+//rescanNeed in it.
+void ServerComThread::update_delete(const Defs* dc)
+{
+ UserMessage::message(UserMessage::DBG, false, std::string("Update defs delete: "));
+
+ Defs *d=const_cast<Defs*>(dc);
+ d->detach(this);
+
+ //If we are in a SYNC_LOCAl task!!!!
+ if(taskType_ == VTask::SyncTask)
+ {
+ //We notify ServerHandler about the radical changes. When ServerHandler receives this signal
+ //it will clear its tree, which stores shared pointers to the nodes (node_ptr). If these pointers are
+ //reset update_delete() might be called, so it should not write any shared variables!
+ Q_EMIT rescanNeed();
+
+ rescanNeed_=true;
+ }
+}
+
+//Attach each node and the defs to the observer
+void ServerComThread::attach()
+{
+ ServerDefsAccess defsAccess(server_); // will reliquish its resources on destruction
+ defs_ptr d = defsAccess.defs();
+ if(d == NULL)
+ return;
+
+ attach(d);
+}
+
+//Attach each node and the defs to the observer. The access to
+//the defs is safe so we do not need to set a mutex on it.
+void ServerComThread::attach(defs_ptr d)
+{
+ if(d == NULL)
+ return;
+
+ d->attach(this);
+
+ const std::vector<suite_ptr> &suites = d->suiteVec();
+ for(unsigned int i=0; i < suites.size();i++)
+ {
+ attach(suites.at(i).get());
+ }
+}
+
+//Attach a node to the observer
+void ServerComThread::attach(Node *node)
+{
+ std::vector<node_ptr> nodes;
+ node->immediateChildren(nodes);
+
+ node->attach(this);
+
+ for(std::vector<node_ptr>::const_iterator it=nodes.begin(); it != nodes.end(); ++it)
+ {
+ attach((*it).get());
+ }
+}
+
+//Detach each node and the defs from the observer
+void ServerComThread::detach()
+{
+ ServerDefsAccess defsAccess(server_); // will reliquish its resources on destruction
+ defs_ptr d = defsAccess.defs();
+ if(d == NULL)
+ return;
+
+ detach(d);
+}
+
+
+//Detach each node and the defs from the observer. The access to
+//the defs is safe so we do not need to set a mutex on it.
+void ServerComThread::detach(defs_ptr d)
+{
+ if(d == NULL)
+ return;
+
+ d->detach(this);
+
+ const std::vector<suite_ptr> &suites = d->suiteVec();
+ for(unsigned int i=0; i < suites.size();i++)
+ {
+ detach(suites.at(i).get());
+ }
+}
+
+//Detach a node from the observer
+void ServerComThread::detach(Node *node)
+{
+ std::vector<node_ptr> nodes;
+ node->immediateChildren(nodes);
+
+ node->detach(this);
+
+ for(std::vector<node_ptr>::const_iterator it=nodes.begin(); it != nodes.end(); ++it)
+ {
+ detach((*it).get());
+ }
+}
diff --git a/Viewer/src/ServerComThread.hpp b/Viewer/src/ServerComThread.hpp
new file mode 100644
index 0000000..d2a4446
--- /dev/null
+++ b/Viewer/src/ServerComThread.hpp
@@ -0,0 +1,87 @@
+//============================================================================
+// Copyright 2015 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef SERVERCOMTHREAD_HPP_
+#define SERVERCOMTHREAD_HPP_
+
+#include <deque>
+#include <utility>
+#include <string>
+#include <vector>
+
+#include "Defs.hpp"
+#include "AbstractObserver.hpp"
+
+#include "VTask.hpp"
+
+#include <QThread>
+
+class ChangeMgrSingleton;
+class ClientInvoker;
+class ServerComQueue;
+class ServerHandler;
+
+// -------------------------------------------------------
+// ServerComThread - a class to handler communication with
+// an ecflow server.
+// -------------------------------------------------------
+
+class ServerComThread : public QThread, public AbstractObserver
+{
+ Q_OBJECT
+
+public:
+ ServerComThread(ServerHandler *server, ClientInvoker *ci);
+ ~ServerComThread();
+
+ void task(VTask_ptr);
+
+ //From AbstractObserver
+ void update(const Node*, const std::vector<ecf::Aspect::Type>&);
+ void update(const Defs*, const std::vector<ecf::Aspect::Type>&);
+ void update_delete(const Node*);
+ void update_delete(const Defs*);
+
+Q_SIGNALS:
+ void nodeChanged(const Node*, std::vector<ecf::Aspect::Type>);
+ void defsChanged(std::vector<ecf::Aspect::Type>);
+ void rescanNeed();
+ void failed(std::string message);
+ void suiteListChanged(const std::vector<std::string>&,const std::vector<std::string>&);
+
+protected:
+ void run();
+ void reset();
+ void sync_local();
+ void updateRegSuites();
+
+private:
+ void attach();
+ void attach(defs_ptr d);
+ void attach(Node *node);
+ void detach();
+ void detach(defs_ptr d);
+ void detach(Node *node);
+
+ ServerHandler *server_;
+ ClientInvoker *ci_;
+ VTask::Type taskType_;
+ std::vector<std::string> command_;
+ std::map<std::string,std::string> params_;
+ std::vector<std::string> contents_;
+ NameValueVec vars_;
+ std::string nodePath_;
+ bool rescanNeed_;
+ bool hasSuiteFilter_;
+ std::vector<std::string> filteredSuites_;
+ bool autoAddNewSuites_;
+ int maxLineNum_;
+};
+
+#endif
diff --git a/Viewer/src/ServerDefsAccess.cpp b/Viewer/src/ServerDefsAccess.cpp
new file mode 100644
index 0000000..24abccb
--- /dev/null
+++ b/Viewer/src/ServerDefsAccess.cpp
@@ -0,0 +1,29 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "ServerDefsAccess.hpp"
+
+#include "ServerHandler.hpp"
+
+ServerDefsAccess::ServerDefsAccess(ServerHandler *server) :
+ server_(server)
+{
+ server_->defsMutex_.lock(); // lock the resource on construction
+}
+
+
+ServerDefsAccess::~ServerDefsAccess()
+{
+ server_->defsMutex_.unlock(); // unlock the resource on destruction
+}
+
+defs_ptr ServerDefsAccess::defs()
+{
+ return server_->defs(); // the resource will always be locked when we use it
+}
diff --git a/Viewer/src/ServerDefsAccess.hpp b/Viewer/src/ServerDefsAccess.hpp
new file mode 100644
index 0000000..3333690
--- /dev/null
+++ b/Viewer/src/ServerDefsAccess.hpp
@@ -0,0 +1,34 @@
+//============================================================================
+// Copyright 2015 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef SERVERDEFSACCESS_HPP_
+#define SERVERDEFSACCESS_HPP_
+
+#include "Defs.hpp"
+
+class ServerHandler;
+
+// -------------------------------------------------------------------------
+// ServerDefsAccess - a class to manage access to the server definition tree
+// - required for multi-threaded access
+// -------------------------------------------------------------------------
+
+class ServerDefsAccess
+{
+public:
+ explicit ServerDefsAccess(ServerHandler *server);
+ ~ServerDefsAccess();
+
+ defs_ptr defs();
+
+private:
+ ServerHandler *server_;
+};
+
+#endif
diff --git a/Viewer/src/ServerDialog.ui b/Viewer/src/ServerDialog.ui
new file mode 100644
index 0000000..c96b145
--- /dev/null
+++ b/Viewer/src/ServerDialog.ui
@@ -0,0 +1,178 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ServerDialog</class>
+ <widget class="QDialog" name="ServerDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>787</width>
+ <height>646</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Select servers</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QToolButton" name="editTb">
+ <property name="toolTip">
+ <string>Edit</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/images/configure.svg</normaloff>:/viewer/images/configure.svg</iconset>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="addTb">
+ <property name="toolTip">
+ <string>Add server</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/images/add.svg</normaloff>:/viewer/images/add.svg</iconset>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="deleteTb">
+ <property name="toolTip">
+ <string>Delete server</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/images/close.svg</normaloff>:/viewer/images/close.svg</iconset>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="rescanTb">
+ <property name="toolTip">
+ <string>Rescan network</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/images/reload.svg</normaloff>:/viewer/images/reload.svg</iconset>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QTreeView" name="contentsView"/>
+ </item>
+ <item>
+ <widget class="QPushButton" name="pushButton">
+ <property name="text">
+ <string>PushButton</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTreeView" name="serverView">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="rootIsDecorated">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="viewer.qrc"/>
+ </resources>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>ServerDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>ServerDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/Viewer/src/ServerEditDialog.ui b/Viewer/src/ServerEditDialog.ui
new file mode 100644
index 0000000..efab017
--- /dev/null
+++ b/Viewer/src/ServerEditDialog.ui
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ServerEditDialog</class>
+ <widget class="QDialog" name="ServerEditDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>284</width>
+ <height>228</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Edit server properties</string>
+ </property>
+ <property name="modal">
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QFormLayout" name="formLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::ExpandingFieldsGrow</enum>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>&Name:</string>
+ </property>
+ <property name="buddy">
+ <cstring>label</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="nameEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>&Host:</string>
+ </property>
+ <property name="buddy">
+ <cstring>hostEdit</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="hostEdit"/>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>&Port:</string>
+ </property>
+ <property name="buddy">
+ <cstring>portEdit</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLineEdit" name="portEdit"/>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>&Favourite:</string>
+ </property>
+ <property name="buddy">
+ <cstring>favCh</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QCheckBox" name="favCh">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>ServerEditDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>257</x>
+ <y>218</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>227</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>ServerEditDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>274</x>
+ <y>218</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>283</x>
+ <y>227</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/Viewer/src/ServerFilter.cpp b/Viewer/src/ServerFilter.cpp
new file mode 100644
index 0000000..73073f1
--- /dev/null
+++ b/Viewer/src/ServerFilter.cpp
@@ -0,0 +1,202 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "ServerFilter.hpp"
+
+#include "ServerHandler.hpp"
+#include "ServerItem.hpp"
+#include "ServerList.hpp"
+#include "VSettings.hpp"
+
+//==============================================
+//
+// ServerFilter
+//
+//==============================================
+
+ServerFilter::ServerFilter()
+{
+}
+
+ServerFilter::~ServerFilter()
+{
+ std::vector<ServerFilterObserver*> obsCopy=observers_;
+
+ for(std::vector<ServerFilterObserver*>::const_iterator it=obsCopy.begin(); it != obsCopy.end(); ++it)
+ {
+ (*it)->notifyServerFilterDelete();
+ }
+
+
+ for(std::vector<ServerItem*>::const_iterator it=items_.begin(); it != items_.end(); ++it)
+ {
+ (*it)->removeObserver(this);
+ }
+}
+
+void ServerFilter::serverNames(std::vector<std::string>& vec) const
+{
+ for(std::vector<ServerItem*>::const_iterator it=items_.begin(); it != items_.end(); ++it)
+ {
+ vec.push_back((*it)->name());
+ }
+}
+
+void ServerFilter::addServer(ServerItem *item,bool broadcast)
+{
+ if(item && ServerList::instance()->find(item->name()) == item)
+ {
+ //ServerFilterItem* s=new ServerFilterItem(item->name(),item->host(),item->port());
+ //ServerItem* s=new ServerFilterItem(item->name());
+
+ items_.push_back(item);
+
+ item->addObserver(this);
+
+ if(broadcast)
+ broadcastAdd(item);
+ }
+}
+
+void ServerFilter::removeServer(ServerItem *server)
+{
+ if(!server) return;
+
+ std::vector<ServerItem*>::iterator it=std::find(items_.begin(),items_.end(),server);
+ if(it != items_.end())
+ {
+ //Remove the item from the filter. This should come
+ //first because the observers update themselves according to the
+ //contents of items_!!!!
+ items_.erase(it);
+
+ //Notifies the view about the changes
+ broadcastRemove(server);
+
+ //Remove the filter from the observers
+ server->removeObserver(this);
+ }
+}
+
+void ServerFilter::notifyServerItemChanged(ServerItem *server)
+{
+ if(isFiltered(server))
+ broadcastChange(server);
+}
+
+//Do not remove the observer in this method!!
+void ServerFilter::notifyServerItemDeletion(ServerItem *server)
+{
+ if(!server) return;
+
+ std::vector<ServerItem*>::iterator it=std::find(items_.begin(),items_.end(),server);
+ if(it != items_.end())
+ {
+ items_.erase(it);
+
+ //Notifies the view about the changes
+ broadcastRemove(server);
+ }
+}
+
+bool ServerFilter::isFiltered(ServerItem* item) const
+{
+ for(std::vector<ServerItem*>::const_iterator it=items_.begin(); it != items_.end(); ++it)
+ {
+ if((*it) == item)
+ return true;
+ }
+ return false;
+}
+
+bool ServerFilter::isFiltered(ServerHandler* server) const
+{
+ for(std::vector<ServerItem*>::const_iterator it=items_.begin(); it != items_.end(); ++it)
+ {
+ if((*it)->serverHandler() == server)
+ return true;
+ }
+ return false;
+}
+
+void ServerFilter::writeSettings(VSettings* vs) const
+{
+ std::vector<std::string> array;
+ for(std::vector<ServerItem*>::const_iterator it=items_.begin(); it != items_.end(); ++it)
+ {
+ array.push_back((*it)->name());
+ }
+
+ vs->put("server",array);
+}
+
+void ServerFilter::readSettings(VSettings* vs)
+{
+ items_.clear();
+
+ std::vector<std::string> array;
+ vs->get("server",array);
+
+ for(std::vector<std::string>::const_iterator it = array.begin(); it != array.end(); ++it)
+ {
+ std::string name=*it;
+ if(ServerItem* s=ServerList::instance()->find(name))
+ {
+ addServer(s,true);
+ }
+ }
+}
+
+//===========================================================
+// Observers
+//===========================================================
+
+void ServerFilter::broadcastAdd(ServerItem *server)
+{
+ for(std::vector<ServerFilterObserver*>::const_iterator it=observers_.begin(); it != observers_.end(); ++it)
+ {
+ (*it)->notifyServerFilterAdded(server);
+ }
+}
+
+void ServerFilter::broadcastRemove(ServerItem *server)
+{
+ for(std::vector<ServerFilterObserver*>::const_iterator it=observers_.begin(); it != observers_.end(); ++it)
+ {
+ (*it)->notifyServerFilterRemoved(server);
+ }
+}
+
+void ServerFilter::broadcastChange(ServerItem *server)
+{
+ for(std::vector<ServerFilterObserver*>::const_iterator it=observers_.begin(); it != observers_.end(); ++it)
+ {
+ (*it)->notifyServerFilterChanged(server);
+ }
+}
+
+void ServerFilter::addObserver(ServerFilterObserver* o)
+{
+ std::vector<ServerFilterObserver*>::iterator it=std::find(observers_.begin(),observers_.end(),o);
+ if(it == observers_.end())
+ {
+ observers_.push_back(o);
+ }
+}
+
+void ServerFilter::removeObserver(ServerFilterObserver* o)
+{
+ std::vector<ServerFilterObserver*>::iterator it=std::find(observers_.begin(),observers_.end(),o);
+ if(it != observers_.end())
+ {
+ observers_.erase(it);
+ }
+}
+
+
diff --git a/Viewer/src/ServerFilter.hpp b/Viewer/src/ServerFilter.hpp
new file mode 100644
index 0000000..fb73708
--- /dev/null
+++ b/Viewer/src/ServerFilter.hpp
@@ -0,0 +1,68 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef SERVERFILTER_HPP_
+#define SERVERFILTER_HPP_
+
+#include <vector>
+
+#include "Node.hpp"
+#include "ServerItem.hpp"
+
+class VSettings;
+
+#include <boost/property_tree/ptree.hpp>
+
+class ServerFilterObserver
+{
+public:
+ virtual ~ServerFilterObserver() {};
+ virtual void notifyServerFilterAdded(ServerItem*)=0;
+ virtual void notifyServerFilterRemoved(ServerItem*)=0;
+ virtual void notifyServerFilterChanged(ServerItem*)=0;
+ virtual void notifyServerFilterDelete()=0;
+};
+
+class ServerFilter : public ServerItemObserver
+{
+public:
+ ServerFilter();
+ ~ServerFilter();
+
+ enum ChangeAspect {Reset,Added,Removed};
+
+ const std::vector<ServerItem*>& items() const {return items_;}
+ void serverNames(std::vector<std::string>&) const;
+
+ void addServer(ServerItem*,bool broadcast=true);
+ void removeServer(ServerItem*);
+ bool isFiltered(ServerItem*) const;
+ bool isFiltered(ServerHandler*) const;
+
+ void writeSettings(VSettings*) const;
+ void readSettings(VSettings*);
+
+ void addObserver(ServerFilterObserver*);
+ void removeObserver(ServerFilterObserver*);
+
+ //From ServerItemObserver
+ void notifyServerItemChanged(ServerItem*);
+ void notifyServerItemDeletion(ServerItem*);
+
+protected:
+ void broadcastAdd(ServerItem*);
+ void broadcastRemove(ServerItem*);
+ void broadcastChange(ServerItem*);
+
+private:
+ std::vector<ServerItem*> items_;
+ std::vector<ServerFilterObserver*> observers_;
+};
+
+#endif
diff --git a/Viewer/src/ServerHandler.cpp b/Viewer/src/ServerHandler.cpp
new file mode 100644
index 0000000..c89fdc2
--- /dev/null
+++ b/Viewer/src/ServerHandler.cpp
@@ -0,0 +1,1547 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "ServerHandler.hpp"
+
+#include "Defs.hpp"
+#include "ClientInvoker.hpp"
+#include "File.hpp"
+#include "NodeFwd.hpp"
+#include "ArgvCreator.hpp"
+#include "Str.hpp"
+
+#include "ChangeNotify.hpp"
+#include "ConnectState.hpp"
+#include "DirectoryHandler.hpp"
+#include "NodeObserver.hpp"
+#include "SessionHandler.hpp"
+#include "ServerComQueue.hpp"
+#include "ServerComThread.hpp"
+#include "ServerDefsAccess.hpp"
+#include "ServerObserver.hpp"
+#include "SuiteFilter.hpp"
+#include "UpdateTimer.hpp"
+#include "UserMessage.hpp"
+#include "VNode.hpp"
+#include "VSettings.hpp"
+#include "VTaskObserver.hpp"
+
+#include <QDebug>
+#include <QMessageBox>
+#include <QMetaType>
+
+#include <iostream>
+#include <algorithm>
+
+#include <boost/algorithm/string/join.hpp>
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/asio/ip/host_name.hpp>
+
+std::vector<ServerHandler*> ServerHandler::servers_;
+std::string ServerHandler::localHostName_;
+
+//#define __UI_SERVEROBSERVER_DEBUG
+#define __UI_SERVERUPDATE_DEBUG
+
+ServerHandler::ServerHandler(const std::string& name,const std::string& host, const std::string& port) :
+ name_(name),
+ host_(host),
+ port_(port),
+ client_(0),
+ updating_(false),
+ communicating_(false),
+ comQueue_(0),
+ activity_(NoActivity),
+ connectState_(new ConnectState()),
+ suiteFilter_(new SuiteFilter()),
+ conf_(0),
+ prevServerState_(SState::RUNNING)
+{
+ if(localHostName_.empty())
+ {
+ localHostName_=boost::asio::ip::host_name();
+ }
+
+ //Create longname
+ longName_=host_ + "@" + port_;
+
+ conf_=new VServerSettings(this);
+
+ //Create the client invoker. At this point it is empty.
+ client_=new ClientInvoker(host,port);
+ client_->set_retry_connection_period(1);
+ client_->set_throw_on_error(true);
+
+ //Create the vnode root. This will represent the node tree in the viewer, but
+ //at this point it is empty.
+ vRoot_=new VServer(this);
+
+ //Connect up the timer for refreshing the server info. The timer has not
+ //started yet.
+
+ refreshTimer_=new UpdateTimer(this);
+ connect(refreshTimer_, SIGNAL(timeout()),
+ this, SLOT(refreshServerInfo()));
+
+
+ //We will need to pass various non-Qt types via signals and slots for error messages.
+ //So we need to register these types.
+ if(servers_.empty())
+ {
+ qRegisterMetaType<std::string>("std::string");
+ qRegisterMetaType<QList<ecf::Aspect::Type> >("QList<ecf::Aspect::Type>");
+ qRegisterMetaType<std::vector<ecf::Aspect::Type> >("std::vector<ecf::Aspect::Type>");
+ }
+
+ //Add this instance to the servers_ list.
+ servers_.push_back(this);
+
+ //NOTE: we may not always want to create a thread here because of resource
+ // issues; another strategy would be to create threads on demand, only
+ // when server communication is about to start.
+
+ //We create a ServerComThread here. It is not a member, because we will
+ //pass its ownership on to ServerComQueue. At this point the thread is not doing anything.
+ ServerComThread* comThread=new ServerComThread(this,client_);
+
+ //The ServerComThread is observing the actual server and its nodes. When there is a change it
+ //emits a signal to notify the ServerHandler about it.
+ connect(comThread,SIGNAL(nodeChanged(const Node*, std::vector<ecf::Aspect::Type>)),
+ this,SLOT(slotNodeChanged(const Node*, std::vector<ecf::Aspect::Type>)));
+
+ connect(comThread,SIGNAL(defsChanged(std::vector<ecf::Aspect::Type>)),
+ this,SLOT(slotDefsChanged(std::vector<ecf::Aspect::Type>)));
+
+ connect(comThread,SIGNAL(rescanNeed()),
+ this,SLOT(slotRescanNeed()));
+
+
+ //Create the queue for the tasks to be sent to the client (via the ServerComThread)! It will
+ //take ownership of the ServerComThread. At this point the queue has not started yet.
+ comQueue_=new ServerComQueue (this,client_,comThread);
+
+
+ //Load settings
+ loadConf();
+
+ //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ // At this point nothing is running or active!!!!
+
+ //Indicate that we start an init (initial load)
+ //activity_=LoadActivity;
+
+ //Try to connect to the server and load the defs etc. This might fail!
+ reset();
+}
+
+ServerHandler::~ServerHandler()
+{
+ //Save setings
+ saveConf();
+
+ //Notify the observers
+ broadcast(&ServerObserver::notifyServerDelete);
+
+ //The queue must be deleted before the client, since the thread might
+ //be running a job on the client!!
+ if (comQueue_)
+ delete comQueue_;
+
+ //Remove itself from the server vector
+ std::vector<ServerHandler*>::iterator it=std::find(servers_.begin(),servers_.end(),this);
+ if(it != servers_.end())
+ servers_.erase(it);
+
+ delete vRoot_;
+ delete connectState_;
+ delete suiteFilter_;
+
+ //The safest is to delete the client in the end
+ if(client_)
+ delete client_;
+
+ delete conf_;
+}
+
+int ServerHandler::secsSinceLastRefresh() const
+{
+ return static_cast<int>(lastRefresh_.secsTo(QDateTime::currentDateTime()));
+}
+
+int ServerHandler::secsTillNextRefresh() const
+{
+ if(refreshTimer_->isActive())
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+ return refreshTimer_->remainingTime()/1000;
+#else
+ return 0;
+#endif
+ return -1;
+}
+
+void ServerHandler::stopRefreshTimer()
+{
+ refreshTimer_->stop();
+#ifdef __UI_SERVERUPDATE_DEBUG
+ UserMessage::debug("stopRefreshTimer -->");
+#endif
+}
+
+void ServerHandler::startRefreshTimer()
+{
+ UserMessage::debug("startRefreshTimer -->");
+
+ if(!conf_->boolValue(VServerSettings::AutoUpdate))
+ {
+ return;
+ }
+
+ //If we are not connected to the server the
+ //timer should not run.
+ if(connectState_->state() == ConnectState::Disconnected)
+ return;
+
+ if(!refreshTimer_->isActive())
+ {
+ refreshTimer_->setInterval(conf_->intValue(VServerSettings::UpdateRate)*1000);
+ refreshTimer_->start();
+ }
+
+#ifdef __UI_SERVERUPDATE_DEBUG
+ UserMessage::debug("startRefreshTimer --> " + QString::number(refreshTimer_->interval()).toStdString());
+#endif
+}
+
+void ServerHandler::updateRefreshTimer()
+{
+ UserMessage::debug("updateRefreshTimer -->");
+
+ if(!conf_->boolValue(VServerSettings::AutoUpdate))
+ {
+ stopRefreshTimer();
+ return;
+ }
+
+ //If we are not connected to the server the
+ //timer should not run.
+ if(connectState_->state() == ConnectState::Disconnected)
+ return;
+
+ if(refreshTimer_->isActive())
+ {
+ refreshTimer_->stop();
+ refreshTimer_->setInterval(conf_->intValue(VServerSettings::UpdateRate)*1000);
+ refreshTimer_->start();
+ }
+
+#ifdef __UI_SERVERUPDATE_DEBUG
+ UserMessage::debug("updateRefreshTimer --> " + QString::number(refreshTimer_->interval()).toStdString());
+#endif
+
+}
+
+void ServerHandler::driftRefreshTimer()
+{
+ if(!conf_->boolValue(VServerSettings::AutoUpdate))
+ {
+ return;
+ }
+
+ //We increase the update frequency
+ if(activity_ != LoadActivity &&
+ conf_->boolValue(VServerSettings::AdaptiveUpdate))
+ {
+ refreshTimer_->drift(conf_->intValue(VServerSettings::AdaptiveUpdateIncrement),
+ conf_->intValue(VServerSettings::MaxAdaptiveUpdateRate));
+ }
+
+#ifdef __UI_SERVERUPDATE_DEBUG
+ UserMessage::debug("driftRefreshTimer --> " + QString::number(refreshTimer_->interval()).toStdString());
+#endif
+
+}
+
+
+void ServerHandler::setActivity(Activity ac)
+{
+ activity_=ac;
+ broadcast(&ServerObserver::notifyServerActivityChanged);
+}
+
+ServerHandler* ServerHandler::addServer(const std::string& name,const std::string& host, const std::string& port)
+{
+ ServerHandler* sh=new ServerHandler(name,host,port);
+ return sh;
+}
+
+void ServerHandler::removeServer(ServerHandler* server)
+{
+ std::vector<ServerHandler*>::iterator it=std::find(servers_.begin(), servers_.end(),server);
+ if(it != servers_.end())
+ {
+ ServerHandler *s=*it;
+ servers_.erase(it);
+ delete s;
+ }
+}
+
+//This function can be called many times so we need to avoid locking the mutex.
+SState::State ServerHandler::serverState()
+{
+ SState::State state;
+ if(connectState_->state() != ConnectState::Normal || activity() == LoadActivity)
+ {
+ prevServerState_= SState::RUNNING;
+
+ }
+ //If we are here we can be sure that the defs pointer is not being deleted!! We
+ //access it without locking the mutex!!!
+ else
+ {
+ //If get the defs can be 100% sure that it is not being deleted!! So we can
+ //access it without locking the mutex!!!
+ defs_ptr d=safelyAccessSimpleDefsMembers();
+ if(d && d.get())
+ {
+ prevServerState_= d->set_server().get_state();
+ return prevServerState_;
+ }
+ }
+
+ return prevServerState_;
+}
+
+//This function can be called many times so we need to avoid locking the mutex.
+NState::State ServerHandler::state(bool& suspended)
+{
+ if(connectState_->state() != ConnectState::Normal || activity() == LoadActivity)
+ return NState::UNKNOWN;
+
+ suspended=false;
+
+ defs_ptr d=safelyAccessSimpleDefsMembers();
+ if(d && d.get())
+ {
+ suspended=d->isSuspended();
+ return d->state();
+ }
+
+ return NState::UNKNOWN;
+}
+
+defs_ptr ServerHandler::defs()
+{
+ defs_ptr null;
+
+ if(client_)
+ {
+ return client_->defs();
+ }
+ else
+ {
+ return null;
+ }
+}
+
+defs_ptr ServerHandler::safelyAccessSimpleDefsMembers()
+{
+ defs_ptr null;
+
+ //The defs might be deleted during reset so it cannot be accessed.
+ if(activity_ == LoadActivity)
+ {
+ return null;
+ }
+ //Otherwise it is safe to access certain non-vector members
+ else if(client_)
+ {
+ return client_->defs();
+ }
+ else
+ {
+ return null;
+ }
+}
+
+
+void ServerHandler::errorMessage(std::string message)
+{
+ UserMessage::message(UserMessage::ERROR, true, message);
+}
+
+//-------------------------------------------------------------
+// Run client tasks.
+//
+// The preferred way to run client tasks is to define and add a task to the queue. The
+// queue will manage the task and will send it to the ClientInvoker. When the task
+// finishes the ServerHandler::clientTaskFinished method is called where the
+// result/reply can be processed.
+//--------------------------------------------------------------
+
+void ServerHandler::runCommand(const std::vector<std::string>& cmd)
+{
+ if(connectState_->state() == ConnectState::Disconnected)
+ return;
+
+ VTask_ptr task=VTask::create(VTask::CommandTask);
+ task->command(cmd);
+ comQueue_->addTask(task);
+}
+
+void ServerHandler::run(VTask_ptr task)
+{
+ if(connectState_->state() == ConnectState::Disconnected)
+ return;
+
+ switch(task->type())
+ {
+ case VTask::ScriptTask:
+ return script(task);
+ break;
+ case VTask::JobTask:
+ return job(task);
+ break;
+ case VTask::OutputTask:
+ return jobout(task);
+ break;
+ case VTask::ManualTask:
+ return manual(task);
+ break;
+ case VTask::HistoryTask:
+ case VTask::MessageTask:
+ case VTask::StatsTask:
+ case VTask::ScriptPreprocTask:
+ case VTask::ScriptEditTask:
+ case VTask::ScriptSubmitTask:
+ case VTask::SuiteListTask:
+ case VTask::ZombieListTask:
+ comQueue_->addTask(task);
+ break;
+ default:
+ //If we are here we have an unhandled task type.
+ task->status(VTask::REJECTED);
+ break;
+ }
+}
+
+void ServerHandler::script(VTask_ptr task)
+{
+ /*static std::string errText="no script!\n"
+ "check ECF_FILES or ECF_HOME directories, for read access\n"
+ "check for file presence and read access below files directory\n"
+ "or this may be a 'dummy' task.\n";*/
+
+ task->param("clientPar","script");
+ comQueue_->addTask(task);
+}
+
+void ServerHandler::job(VTask_ptr task)
+{
+ /*static std::string errText="no script!\n"
+ "check ECF_FILES or ECF_HOME directories, for read access\n"
+ "check for file presence and read access below files directory\n"
+ "or this may be a 'dummy' task.\n";*/
+
+ task->param("clientPar","job");
+ comQueue_->addTask(task);
+}
+
+void ServerHandler::jobout(VTask_ptr task)
+{
+ //static std::string errText="no job output...";
+
+ task->param("clientPar","jobout");
+ comQueue_->addTask(task);
+}
+
+void ServerHandler::manual(VTask_ptr task)
+{
+ //std::string errText="no manual ...";
+ task->param("clientPar","manual");
+ comQueue_->addTask(task);
+}
+
+//The user initiated a refresh
+void ServerHandler::refresh()
+{
+ //We add and refresh task to the queue. On startup this function can be called
+ //before the comQueue_ was created so we need to check if it exists.
+ if(comQueue_)
+ {
+ comQueue_->addNewsTask();
+ lastRefresh_=QDateTime::currentDateTime();
+ }
+
+ //Reset the timer to its original value (i.e. remove the drift)
+ updateRefreshTimer();
+}
+
+
+//The user initiated a refresh
+void ServerHandler::refreshInternal()
+{
+ //We add and refresh task to the queue. On startup this function can be called
+ //before the comQueue_ was created so we need to check if it exists.
+ if(comQueue_)
+ {
+ comQueue_->addNewsTask();
+ lastRefresh_=QDateTime::currentDateTime();
+ }
+}
+
+//This slot is called by the timer regularly to get news from the server.
+void ServerHandler::refreshServerInfo()
+{
+ UserMessage::message(UserMessage::DBG, false, std::string("auto refreshing server info for ") + name());
+ refreshInternal();
+
+ //We reduce the update frequency
+ driftRefreshTimer();
+}
+
+std::string ServerHandler::commandToString(const std::vector<std::string>& cmd)
+{
+ return boost::algorithm::join(cmd," ");
+}
+
+//Send a command to a server. The command is specified as a string vector, while the node or server for that
+//the command will be applied is specified in a VInfo object.
+void ServerHandler::command(VInfo_ptr info,const std::vector<std::string>& cmd)
+{
+ std::vector<std::string> realCommand=cmd;
+
+ if (!realCommand.empty())
+ {
+ UserMessage::message(UserMessage::DBG, false, std::string("command: ") + commandToString(realCommand));
+
+ //Get the name of the object for that the command will be applied
+ std::string nodeFullName;
+ std::string nodeName;
+ ServerHandler* serverHandler = info->server();
+
+ if(info->isNode() || info->isAttribute())
+ {
+ nodeFullName = info->node()->node()->absNodePath();
+ nodeName = info->node()->node()->name();
+ //UserMessage::message(UserMessage::DBG, false, std::string(" --> for node: ") + nodeFullName + " (server: " + info[i]->server()->longName() + ")");
+ }
+ else if(info->isServer())
+ {
+ nodeFullName = "/";
+ nodeName = "/";
+ //UserMessage::message(UserMessage::DBG, false, std::string(" --> for server: ") + nodeFullName);
+ }
+
+ //Replace placeholders with real node names
+ for(unsigned int i=0; i < cmd.size(); i++)
+ {
+ if(realCommand[i]=="<full_name>")
+ realCommand[i]=nodeFullName;
+ else if(realCommand[i]=="<node_name>")
+ realCommand[i]=nodeName;
+ }
+
+ UserMessage::message(UserMessage::DBG, false, std::string("final command: ") + commandToString(realCommand));
+
+ // get the command into the right format by first splitting into tokens
+ // and then converting to argc, argv format
+
+ //std::vector<std::string> strs;
+ //std::string delimiters(" ");
+ //ecf::Str::split(realCommand, strs, delimiters);
+
+ // set up and run the thread for server communication
+ serverHandler->runCommand(realCommand);
+ }
+ else
+ {
+ UserMessage::message(UserMessage::ERROR, true, std::string("command is not recognised."));
+ }
+}
+//Send the same command for a list of objects (nodes/servers) specified in a VInfo vector.
+//The command is specified as a string.
+
+void ServerHandler::command(std::vector<VInfo_ptr> info, std::string cmd)
+{
+ std::string realCommand(cmd);
+
+ std::vector<ServerHandler *> targetServers;
+
+ if (!realCommand.empty())
+ {
+ UserMessage::message(UserMessage::DBG, false, std::string("command: ") + cmd + " (real: " + realCommand + ")");
+
+ std::map<ServerHandler*,std::string> targetNodeNames;
+ std::map<ServerHandler*,std::string> targetNodeFullNames;
+ std::map<ServerHandler*,std::string> targetParentFullNames;
+
+
+ //Figure out what objects (node/server) the command should be applied to
+ for(int i=0; i < info.size(); i++)
+ {
+ std::string nodeFullName;
+ std::string nodeName;
+ std::string parentFullName;
+
+ if(realCommand.find("<node_name>") != std::string::npos)
+ {
+ nodeName=info[i]->name();
+ }
+
+ if(realCommand.find("<full_name>") != std::string::npos)
+ {
+ if(info[i]->isNode())
+ nodeFullName = info[i]->node()->absNodePath();
+ else if(info[i]->isServer())
+ info[i]->server()->longName();
+ else if(info[i]->isAttribute())
+ parentFullName = info[i]->node()->absNodePath();
+ }
+
+ if(realCommand.find("<parent_name>") != std::string::npos)
+ {
+ if(info[i]->isNode())
+ {
+ if(VNode *p=info[i]->node()->parent())
+ parentFullName = p->absNodePath();
+ }
+ else if(info[i]->isAttribute())
+ parentFullName = info[i]->node()->absNodePath();
+ }
+
+#if 0
+ nodeName = info[i]->name();
+
+ //Get the name
+ if(info[i]->isNode())
+ {
+ //nodeName = info[i]->name();
+ nodeFullName = info[i]->node()->absNodePath();
+ if(realCommand.
+
+ parentFullName = info[i]->node()->parent()->absNodePath();
+ //UserMessage::message(UserMessage::DBG, false, std::string(" --> for node: ") + nodeFullName + " (server: " + info[i]->server()->longName() + ")");
+ }
+ else if(info[i]->isServer())
+ {
+ nodeFullName = info[i]->server()->longName();
+ //UserMessage::message(UserMessage::DBG, false, std::string(" --> for server: ") + nodeFullName);
+ }
+ else if(info[i]->isAttribute())
+ {
+ nodeFullName = nodeName;
+ parentFullName = info[i]->node()->absNodePath();
+ //UserMessage::message(UserMessage::DBG, false, std::string(" --> for node: ") + nodeFullName + " (server: " + info[i]->server()->longName() + ")");
+ }
+#endif
+
+ //Storre the names per target servers
+ targetNodeNames[info[i]->server()] += " " + nodeName;
+ targetNodeFullNames[info[i]->server()] += " " + nodeFullName;
+ targetParentFullNames[info[i]->server()] += " " + parentFullName;
+
+ //info[i]->server()->targetNodeNames_ += " " + nodeName; // build up the list of nodes for each server
+ //info[i]->server()->targetNodeFullNames_ += " " + nodeFullName; // build up the list of nodes for each server
+
+
+ // add this to our list of target servers?
+ if (std::find(targetServers.begin(), targetServers.end(), info[i]->server()) == targetServers.end())
+ {
+ targetServers.push_back(info[i]->server());
+ }
+ }
+
+
+ // for each target server, construct and send its command
+
+ for (size_t s = 0; s < targetServers.size(); s++)
+ {
+ ServerHandler* serverHandler = targetServers[s];
+
+ // replace placeholders with real node names
+
+ std::string placeholder("<full_name>");
+ ecf::Str::replace_all(realCommand, placeholder, targetNodeFullNames[serverHandler]);
+
+ placeholder = "<node_name>";
+ ecf::Str::replace_all(realCommand, placeholder, targetNodeNames[serverHandler]);
+
+ placeholder = "<parent_name>";
+ ecf::Str::replace_all(realCommand, placeholder, targetParentFullNames[serverHandler]);
+
+ UserMessage::message(UserMessage::DBG, false, std::string("final command: ") + realCommand);
+
+ // get the command into the right format by first splitting into tokens
+ // and then converting to argc, argv format
+
+ std::vector<std::string> strs;
+ std::string delimiters(" ");
+ ecf::Str::split(realCommand, strs, delimiters);
+
+ // set up and run the thread for server communication
+ serverHandler->runCommand(strs);
+
+ //serverHandler->targetNodeNames_.clear(); // reset the target node names for next time
+ //serverHandler->targetNodeFullNames_.clear(); // reset the target node names for next time
+ //serverHandler->refresh();
+ }
+ }
+ else
+ {
+ UserMessage::message(UserMessage::ERROR, true, std::string("command ") + cmd + " is not recognised. Check the menu definition.");
+ }
+}
+
+//Send the same command for a list of nodes specified by their paths.
+//The command is specified as a string.
+
+void ServerHandler::command(const std::vector<std::string>& fullPaths, const std::vector<std::string>& cmd)
+{
+ std::vector<std::string> realCommand=cmd;
+
+ if (!realCommand.empty())
+ {
+ UserMessage::message(UserMessage::DBG, false, "command: " + commandToString(realCommand));
+
+ std::string fullNameStr;
+
+ for(unsigned int i=0; i < fullPaths.size(); ++i)
+ {
+ if(i>0)
+ {
+ fullNameStr+= " ";
+ }
+
+ fullNameStr+=fullPaths[i];
+ }
+
+ //Replace placeholders with real node names
+ for(unsigned int i=0; i < realCommand.size(); i++)
+ {
+ if(realCommand[i]=="<full_name>")
+ realCommand[i]=fullNameStr;
+ }
+
+ UserMessage::message(UserMessage::DBG, false, std::string("final command: ") + commandToString(realCommand));
+
+ // set up and run the thread for server communication
+ runCommand(realCommand);
+ }
+ else
+ {
+ UserMessage::message(UserMessage::ERROR, true, std::string("command ") + commandToString(cmd) + " is not recognised. Check the menu definition.");
+ }
+}
+
+
+
+//======================================================================================
+// Manages node changes.
+//======================================================================================
+
+//This slot is called when a node changes.
+void ServerHandler::slotNodeChanged(const Node* nc,std::vector<ecf::Aspect::Type> aspect)
+{
+ UserMessage::message(UserMessage::DBG, false, std::string("ServerHandler::slotNodeChanged - node: ") + nc->name());
+ for(std::vector<ecf::Aspect::Type>::const_iterator it=aspect.begin(); it != aspect.end(); ++it)
+ UserMessage::message(UserMessage::DBG, false, std::string(" aspect: ") + boost::lexical_cast<std::string>(*it));
+
+ //This can happen if we initiated a reset while we sync in the thread
+ if(vRoot_->isEmpty())
+ {
+ UserMessage::message(UserMessage::DBG, false, " --> no change - tree is empty");
+ return;
+ }
+
+ VNode* vn=vRoot_->toVNode(nc);
+
+ //We must have this VNode
+ assert(vn != NULL);
+
+ //Begin update for the VNode
+ VNodeChange change;
+ vRoot_->beginUpdate(vn,aspect,change);
+
+ //TODO: what about the infopanel or breadcrumbs??????
+ if(change.ignore_)
+ {
+ UserMessage::message(UserMessage::DBG, false," --> Update ignored");
+ return;
+ }
+ else
+ {
+ //Notify the observers
+ broadcast(&NodeObserver::notifyBeginNodeChange,vn,aspect,change);
+
+ //End update for the VNode
+ vRoot_->endUpdate(vn,aspect,change);
+
+ //Notify the observers
+ broadcast(&NodeObserver::notifyEndNodeChange,vn,aspect,change);
+
+ UserMessage::message(UserMessage::DBG, false," --> Update applied");
+ }
+}
+
+void ServerHandler::addNodeObserver(NodeObserver *obs)
+{
+ std::vector<NodeObserver*>::iterator it=std::find(nodeObservers_.begin(),nodeObservers_.end(),obs);
+ if(it == nodeObservers_.end())
+ {
+ nodeObservers_.push_back(obs);
+ }
+}
+
+void ServerHandler::removeNodeObserver(NodeObserver *obs)
+{
+ std::vector<NodeObserver*>::iterator it=std::find(nodeObservers_.begin(),nodeObservers_.end(),obs);
+ if(it != nodeObservers_.end())
+ {
+ nodeObservers_.erase(it);
+ }
+}
+
+void ServerHandler::broadcast(NoMethod proc,const VNode* node)
+{
+ for(std::vector<NodeObserver*>::const_iterator it=nodeObservers_.begin(); it != nodeObservers_.end(); ++it)
+ ((*it)->*proc)(node);
+}
+
+void ServerHandler::broadcast(NoMethodV1 proc,const VNode* node,const std::vector<ecf::Aspect::Type>& aspect,const VNodeChange& change)
+{
+ for(std::vector<NodeObserver*>::const_iterator it=nodeObservers_.begin(); it != nodeObservers_.end(); ++it)
+ ((*it)->*proc)(node,aspect,change);
+}
+
+//---------------------------------------------------------------------------
+// Manages Defs changes and desf observers. Defs observers are notified when
+// there is a change.
+//---------------------------------------------------------------------------
+
+//This slot is called when the Defs change.
+void ServerHandler::slotDefsChanged(std::vector<ecf::Aspect::Type> aspect)
+{
+ UserMessage::message(UserMessage::DBG, false, std::string("ServerHandler::slotDefsChanged"));
+ for(std::vector<ecf::Aspect::Type>::const_iterator it=aspect.begin(); it != aspect.end(); ++it)
+ UserMessage::message(UserMessage::DBG, false, std::string(" aspect: ") + boost::lexical_cast<std::string>(*it));
+
+ //Begin update for the VNode
+ VNodeChange change;
+ vRoot_->beginUpdate(aspect);
+
+ //Notify the observers
+ //broadcast(&NodeObserver::notifyBeginNodeChange,vn,aspect,change);
+
+ //End update for the VNode
+ //vRoot_->endUpdate(vn,aspect,change);
+
+ //Notify the observers
+ //broadcast(&NodeObserver::notifyEndNodeChange,vn,aspect,change);
+
+ //UserMessage::message(UserMessage::DBG, false," --> Update applied");
+
+ for(std::vector<ServerObserver*>::const_iterator it=serverObservers_.begin(); it != serverObservers_.end(); ++it)
+ (*it)->notifyDefsChanged(this,aspect);
+}
+
+void ServerHandler::addServerObserver(ServerObserver *obs)
+{
+ std::vector<ServerObserver*>::iterator it=std::find(serverObservers_.begin(),serverObservers_.end(),obs);
+ if(it == serverObservers_.end())
+ {
+ serverObservers_.push_back(obs);
+#ifdef __UI_SERVEROBSERVER_DEBUG
+ UserMessage::debug("ServerHandler::addServerObserver --> " + boost::lexical_cast<std::string>(obs));
+#endif
+ }
+}
+
+void ServerHandler::removeServerObserver(ServerObserver *obs)
+{
+ std::vector<ServerObserver*>::iterator it=std::find(serverObservers_.begin(),serverObservers_.end(),obs);
+ if(it != serverObservers_.end())
+ {
+ serverObservers_.erase(it);
+#ifdef __UI_SERVEROBSERVER_DEBUG
+ UserMessage::debug("ServerHandler::removeServerObserver --> " + boost::lexical_cast<std::string>(obs));
+#endif
+ }
+}
+
+void ServerHandler::broadcast(SoMethod proc)
+{
+ bool checkExistence=true;
+
+ //When the observers are being notified (in a loop) they might
+ //want to remove themselves from the observer list. This will cause a crash. To avoid
+ //this we create a copy of the observers and use it in the notification loop.
+ std::vector<ServerObserver*> sObsCopy=serverObservers_;
+
+ for(std::vector<ServerObserver*>::const_iterator it=sObsCopy.begin(); it != sObsCopy.end(); ++it)
+ {
+ //We need to check if the given observer is still in the original list. When we delete the server, due to
+ //dependencies it is possible that the observer is already deleted at this point.
+ if(!checkExistence || std::find(serverObservers_.begin(),serverObservers_.end(),*it) != serverObservers_.end())
+ ((*it)->*proc)(this);
+ }
+
+}
+
+void ServerHandler::broadcast(SoMethodV1 proc,const VServerChange& ch)
+{
+ for(std::vector<ServerObserver*>::const_iterator it=serverObservers_.begin(); it != serverObservers_.end(); ++it)
+ ((*it)->*proc)(this,ch);
+}
+
+//-------------------------------------------------------------------
+// This slot is called when the comThread finished the given task!!
+//-------------------------------------------------------------------
+
+//There was a drastic change during the SYNC! As a safety measure we need to clear
+//the tree. We will rebuild it when the SYNC finishes.
+void ServerHandler::slotRescanNeed()
+{
+ clearTree();
+}
+
+void ServerHandler::clientTaskFinished(VTask_ptr task,const ServerReply& serverReply)
+{
+ UserMessage::message(UserMessage::DBG, false, std::string("ServerHandler::clientTaskFinished"));
+
+ //See which type of task finished. What we do now will depend on that.
+ switch(task->type())
+ {
+ case VTask::CommandTask:
+ {
+ // a command was sent - we should now check whether there have been
+ // any updates on the server (there should have been, because we
+ // just did something!)
+
+ UserMessage::message(UserMessage::DBG, false, std::string(" --> COMMAND finished"));
+ comQueue_->addNewsTask();
+ break;
+ }
+ case VTask::NewsTask:
+ {
+ // we've just asked the server if anything has changed - has it?
+
+ switch (serverReply.get_news())
+ {
+ case ServerReply::NO_NEWS:
+ {
+ // no news, nothing to do
+ UserMessage::message(UserMessage::DBG, false, std::string(" --> No news from server"));
+
+ //If we just regained the connection we need to reset
+ if(connectionGained())
+ {
+ reset();
+ }
+ break;
+ }
+
+ case ServerReply::NEWS:
+ {
+ // yes, something's changed - synchronise with the server
+
+ //If we just regained the connection we need to reset
+ UserMessage::message(UserMessage::DBG, false, std::string(" --> News from server - send SYNC command"));
+ if(connectionGained())
+ {
+ reset();
+ }
+ else
+ {
+ comQueue_->addSyncTask();
+ }
+ break;
+ }
+
+ case ServerReply::DO_FULL_SYNC:
+ {
+ // yes, a lot of things have changed - we need to reset!!!!!!
+
+ UserMessage::message(UserMessage::DBG, false, std::string(" --> DO_FULL_SYNC from server"));
+ connectionGained();
+ reset();
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+ break;
+ }
+ case VTask::SyncTask:
+ {
+ UserMessage::message(UserMessage::DBG, false, std::string(" --> Sync finished"));
+
+ //This typically happens when a suite is added/removed
+ if(serverReply.full_sync() || vRoot_->isEmpty())
+ {
+ UserMessage::message(UserMessage::DBG, false, std::string(" --> Full sync requested --> rescanTree"));
+
+ //This will update the suites
+ rescanTree();
+ }
+ else
+ {
+ broadcast(&ServerObserver::notifyEndServerSync);
+ }
+
+ //UserMessage::message(UserMessage::DBG, false, std::string(" --> Update suite filter after sync"));
+ //comQueue_->addSuiteListTask();
+
+ break;
+ }
+
+ case VTask::ResetTask:
+ {
+ //If not yet connected but the sync task was successful
+ resetFinished();
+ break;
+ }
+
+ case VTask::ScriptTask:
+ case VTask::ManualTask:
+ case VTask::HistoryTask:
+ case VTask::JobTask:
+ {
+ task->reply()->fileReadMode(VReply::ServerReadMode);
+ task->reply()->setText(serverReply.get_string());
+ task->reply()->setReadTruncatedTo(truncatedLinesFromServer(task->reply()->text()));
+ task->status(VTask::FINISHED);
+ break;
+ }
+
+ case VTask::OutputTask:
+ {
+ task->reply()->fileReadMode(VReply::ServerReadMode);
+
+ std::string err;
+ VFile_ptr f(VFile::create(false));
+ f->setFetchMode(VFile::ServerFetchMode);
+ f->setFetchModeStr("fetched from server " + name());
+ f->setSourcePath(task->reply()->fileName());
+ f->setTruncatedTo(truncatedLinesFromServer(serverReply.get_string()));
+ f->write(serverReply.get_string(),err);
+ task->reply()->tmpFile(f);
+
+ task->status(VTask::FINISHED);
+ break;
+ }
+
+ case VTask::MessageTask:
+ {
+ task->reply()->setTextVec(serverReply.get_string_vec());
+ task->status(VTask::FINISHED);
+ break;
+ }
+
+ case VTask::StatsTask:
+ {
+ std::stringstream ss;
+ serverReply.stats().show(ss);
+ task->reply()->text(ss.str());
+ task->status(VTask::FINISHED);
+ break;
+ }
+
+ case VTask::ScriptPreprocTask:
+ case VTask::ScriptEditTask:
+ {
+ task->reply()->text(serverReply.get_string());
+ task->status(VTask::FINISHED);
+ break;
+ }
+ case VTask::ScriptSubmitTask:
+ {
+ UserMessage::message(UserMessage::DBG, false, std::string(" --> Script submit finished"));
+
+ task->reply()->text(serverReply.get_string());
+ task->status(VTask::FINISHED);
+
+ //Submitting the task was successful - we should now get updates from the server
+ UserMessage::message(UserMessage::DBG, false, std::string(" --> Send NEWS command"));
+ comQueue_->addNewsTask();
+ break;
+ }
+
+ case VTask::SuiteListTask:
+ {
+ //Update the suite filter with the list of suites actually loaded onto the server.
+ //If the suitefilter is enabled this might have only a subset of it in our tree.
+ updateSuiteFilterWithLoaded(serverReply.get_string_vec());
+ break;
+ }
+
+ case VTask::ZombieListTask:
+ {
+ task->reply()->zombies(serverReply.zombies());
+ task->status(VTask::FINISHED);
+ break;
+ }
+
+ default:
+ break;
+
+ }
+}
+
+//-------------------------------------------------------------------
+// This slot is called when the comThread finished the given task!!
+//-------------------------------------------------------------------
+
+void ServerHandler::clientTaskFailed(VTask_ptr task,const std::string& errMsg)
+{
+ //UserMessage::message(UserMessage::DBG, false, std::string("Client task finished"));
+
+ //TODO: suite filter + ci_ observers
+
+
+ //See which type of task finished. What we do now will depend on that.
+ switch(task->type())
+ {
+ case VTask::SyncTask:
+ connectionLost(errMsg);
+ break;
+
+ //The initialisation failed
+ case VTask::ResetTask:
+ {
+ resetFailed(errMsg);
+ break;
+ }
+ case VTask::NewsTask:
+ case VTask::StatsTask:
+ {
+ connectionLost(errMsg);
+ break;
+ }
+ default:
+ task->reply()->setErrorText(errMsg);
+ task->status(VTask::ABORTED);
+ break;
+
+ }
+}
+
+void ServerHandler::connectionLost(const std::string& errMsg)
+{
+ connectState_->state(ConnectState::Lost);
+ connectState_->errorMessage(errMsg);
+ broadcast(&ServerObserver::notifyServerConnectState);
+}
+
+bool ServerHandler::connectionGained()
+{
+ if(connectState_->state() != ConnectState::Normal)
+ {
+ connectState_->state(ConnectState::Normal);
+ broadcast(&ServerObserver::notifyServerConnectState);
+ return true;
+ }
+ return false;
+
+}
+
+void ServerHandler::disconnectServer()
+{
+ if(connectState_->state() != ConnectState::Disconnected)
+ {
+ connectState_->state(ConnectState::Disconnected);
+ broadcast(&ServerObserver::notifyServerConnectState);
+
+ //Stop the queue
+ comQueue_->disable();
+
+ //Stop the timer
+ stopRefreshTimer();
+ }
+}
+
+void ServerHandler::connectServer()
+{
+ if(connectState_->state() == ConnectState::Disconnected)
+ {
+ //Start the queue
+ comQueue_->enable();
+
+ //Start the timer
+ startRefreshTimer();
+
+ //Try to get the news
+ refreshInternal();
+
+ //TODO: attach the observers!!!!
+ }
+}
+
+void ServerHandler::reset()
+{
+ UserMessage::message(UserMessage::DBG, false, std::string("ServerHandler::reset"));
+
+ //---------------------------------
+ // First part of reset: clearing
+ //---------------------------------
+
+ if(comQueue_->prepareReset())
+ {
+ //Stop the timer
+ stopRefreshTimer();
+
+ // First part of reset: clear the tree
+ clearTree();
+
+ // Second part of reset: loading
+
+ //Indicate that we reload the defs
+ setActivity(LoadActivity);
+
+ //NOTE: at this point the queue is not running but reset() will start it.
+ //While the queue is in reset mode it does not accept tasks.
+ comQueue_->reset();
+ }
+ else
+ {
+ UserMessage::message(UserMessage::DBG, false, " --> skip reset");
+ }
+}
+
+//The reset was successful
+void ServerHandler::resetFinished()
+{
+ setActivity(NoActivity);
+
+ //Set server host and port in defs. It is used to find the server of
+ //a given node in the viewer.
+ {
+ ServerDefsAccess defsAccess(this); // will reliquish its resources on destruction
+
+ defs_ptr defs = defsAccess.defs();
+ if(defs != NULL)
+ {
+ ServerState& st=defs->set_server();
+ st.hostPort(std::make_pair(host_,port_));
+ }
+ }
+
+ //Create an object to inform the observers about the change
+ VServerChange change;
+
+ //Begin the full scan to get the tree. This call does not actually
+ //run the scan but counts how many suits will be available.
+ vRoot_->beginScan(change);
+
+ //Notify the observers that the scan has started
+ broadcast(&ServerObserver::notifyBeginServerScan,change);
+
+ //Finish full scan
+ vRoot_->endScan();
+
+ //assert(change.suiteNum_ == vRoot_->numOfChildren());
+
+ //Notify the observers that scan has ended
+ broadcast(&ServerObserver::notifyEndServerScan);
+
+ //The suites might have been changed
+ updateSuiteFilter();
+
+ //Restart the timer
+ startRefreshTimer();
+
+ //Set the connection state
+ if(connectState_->state() != ConnectState::Normal)
+ {
+ connectState_->state(ConnectState::Normal);
+ broadcast(&ServerObserver::notifyServerConnectState);
+ }
+}
+
+//The reset failed and we could not connect to the server, e.g. because the the server
+//may be down, or there is a network error, or the authorisation is missing.
+void ServerHandler::resetFailed(const std::string& errMsg)
+{
+ //This status is indicated by the connectStat_. Each object needs to be aware of it
+ //and do its tasks accordingly.
+
+ //Create an object to inform the observers about the change
+ VServerChange change;
+ //Notify the observers that the scan has started
+ broadcast(&ServerObserver::notifyBeginServerScan,change);
+ //Notify the observers that scan has ended
+ broadcast(&ServerObserver::notifyEndServerScan);
+
+ connectState_->state(ConnectState::Lost);
+ connectState_->errorMessage(errMsg);
+ setActivity(NoActivity);
+
+ broadcast(&ServerObserver::notifyServerConnectState);
+
+ //Restart the timer
+ startRefreshTimer();
+}
+
+//This function must be called during a SYNC!!!!!!!!
+
+void ServerHandler::clearTree()
+{
+ UserMessage::message(UserMessage::DBG, false, std::string("ServerHandler::clearTree -- begin"));
+
+ if(!vRoot_->isEmpty())
+ {
+ //Notify observers that the clear is about to begin
+ broadcast(&ServerObserver::notifyBeginServerClear);
+
+ //Clear vnode
+ vRoot_->clear();
+
+ //Notify observers that the clear ended
+ broadcast(&ServerObserver::notifyEndServerClear);
+ }
+
+ UserMessage::message(UserMessage::DBG, false, std::string("ServerHandler::clearTree -- end"));
+}
+
+
+void ServerHandler::rescanTree()
+{
+ UserMessage::message(UserMessage::DBG, false, std::string("ServerHandler::rescanTree -- begin"));
+
+ setActivity(RescanActivity);
+
+ //---------------------------------
+ // First part of rescan: clearing
+ //---------------------------------
+
+ //Stop the timer
+ stopRefreshTimer();
+
+ //Stop the queue as a safety measure: we do not want any changes during the rescan
+ comQueue_->suspend(false);
+
+ //clear the tree
+ clearTree();
+
+ //At this point nothing is running and the tree is empty (it only contains
+ //the root node)
+
+ //--------------------------------------
+ // Second part of rescan: loading
+ //--------------------------------------
+
+ //Create an object to inform the observers about the change
+ VServerChange change;
+
+ //Begin the full scan to get the tree. This call does not actually
+ //run the scan but counts how many suits will be available.
+ vRoot_->beginScan(change);
+
+ //Notify the observers that the scan has started
+ broadcast(&ServerObserver::notifyBeginServerScan,change);
+
+ //Finish full scan
+ vRoot_->endScan();
+
+ //Notify the observers that scan has ended
+ broadcast(&ServerObserver::notifyEndServerScan);
+
+ //Restart the queue
+ comQueue_->start();
+
+ //The suites might have been changed
+ updateSuiteFilter();
+
+ //Start the timer
+ startRefreshTimer();
+
+ setActivity(NoActivity);
+
+ UserMessage::message(UserMessage::DBG, false, std::string("ServerHandler::rescanTree -- end"));
+}
+
+//====================================================
+// Suite filter
+//====================================================
+
+void ServerHandler::updateSuiteFilter(SuiteFilter* sf)
+{
+ if(suiteFilter_->update(sf))
+ {
+ //If only this flag has changed we exec a custom task for it
+ if(suiteFilter_->changeFlags().sameAs(SuiteFilter::AutoAddChanged))
+ {
+ comQueue_->addSuiteAutoRegisterTask();
+ }
+ //Otherwise we need a full reset
+ else
+ {
+ reset();
+ }
+ }
+}
+
+//Update the suite filter with the list of suites actually loaded onto the server.
+//If the suitefilter is enabled this might have only a subset of it in our tree.
+void ServerHandler::updateSuiteFilterWithLoaded(const std::vector<std::string>& loadedSuites)
+{
+ suiteFilter_->setLoaded(loadedSuites);
+}
+
+//Update the suite filter with the list of suites stored in the defs (in the tree). It only
+//makes sense if the filter is disabled since in this case the defs stores all the loaded servers.
+void ServerHandler::updateSuiteFilterWithDefs()
+{
+ if(suiteFilter_->isEnabled())
+ return;
+
+ std::vector<std::string> defSuites;
+ vRoot_->suites(defSuites);
+ suiteFilter_->setLoaded(defSuites);
+}
+
+//Only called internally after reset or serverscan!!
+void ServerHandler::updateSuiteFilter()
+{
+ bool hasObserver=suiteFilter_->hasObserver();
+
+ //We only fetch the full list of loaded suites from the server
+ //via the thread when the suiteFilter is observerved and it is
+ //enabled!
+ if(hasObserver && suiteFilter_->isEnabled())
+ {
+ //This will call updateSuiteFilterWithLoaded()
+ comQueue_->addSuiteListTask();
+ }
+ else
+ {
+ std::vector<std::string> defSuites;
+ vRoot_->suites(defSuites);
+ suiteFilter_->setLoaded(defSuites);
+ }
+}
+
+
+bool ServerHandler::readFromDisk() const
+{
+ return conf_->boolValue(VServerSettings::ReadFromDisk);
+}
+
+void ServerHandler::confChanged(VServerSettings::Param par,VProperty* prop)
+{
+ switch(par)
+ {
+ case VServerSettings::AutoUpdate:
+ updateRefreshTimer();
+ break;
+ case VServerSettings::UpdateRate:
+ updateRefreshTimer();
+ break;
+ case VServerSettings::NotifyAbortedEnabled:
+ case VServerSettings::NotifyRestartedEnabled:
+ case VServerSettings::NotifyLateEnabled:
+ case VServerSettings::NotifyZombieEnabled:
+ case VServerSettings::NotifyAliasEnabled:
+ checkNotificationState(par);
+ break;
+ default:
+ break;
+ }
+}
+
+void ServerHandler::checkNotificationState(VServerSettings::Param par)
+{
+ std::string id=VServerSettings::notificationId(par);
+ if(id.empty())
+ return;
+
+ bool enabled=false;
+
+ for(std::vector<ServerHandler*>::const_iterator it=servers_.begin(); it != servers_.end(); ++it)
+ {
+ ServerHandler *s=*it;
+
+ if(s->conf()->boolValue(par))
+ {
+ enabled=true;
+ break;
+ }
+ }
+
+ ChangeNotify::setEnabled(id,enabled);
+}
+
+
+void ServerHandler::saveSettings()
+{
+ for(std::vector<ServerHandler*>::const_iterator it=servers_.begin(); it != servers_.end(); ++it)
+ (*it)->saveConf();
+}
+
+void ServerHandler::saveConf()
+{
+ conf_->saveSettings();
+}
+
+void ServerHandler::loadConf()
+{
+ //This will call confChanged for any non-default settings
+ conf_->loadSettings();
+}
+
+//--------------------------------------------
+// Other
+//--------------------------------------------
+
+void ServerHandler::searchBegan()
+{
+ UserMessage::message(UserMessage::DBG, false,"(" + name() + ") ServerHandler::searchBegan -- suspend queue");
+ comQueue_->suspend(true);
+}
+
+void ServerHandler::searchFinished()
+{
+ UserMessage::message(UserMessage::DBG, false, "(" + name() + ") ServerHandler::searchFinished -- start queue");
+ comQueue_->start();
+
+}
+
+int ServerHandler::truncatedLinesFromServer(const std::string& txt) const
+{
+ //if the text is truncated the following line is added to the bottom of it:
+ //# >>>>>>>> File truncated down to 15. Truncated from the end of file <<<<<<<<<
+ //We search for this string and if truncation did happen we indicate it in the reply
+ size_t txtSize=txt.size();
+ if(txt.find(">> File truncated down to",
+ (txtSize > 200)?(txtSize-100):0) != std::string::npos)
+ {
+ return conf_->intValue(VServerSettings::MaxOutputFileLines);
+ }
+
+ return -1;
+}
+
+//--------------------------------------------------------------
+//
+// Find the server for a node.
+// TODO: this is just a backup method. We might not want to use it
+// at all, since it is not safe.
+//
+//--------------------------------------------------------------
+
+ServerHandler* ServerHandler::find(const std::string& name)
+{
+ for(std::vector<ServerHandler*>::const_iterator it=servers_.begin(); it != servers_.end(); ++it)
+ if((*it)->name() == name)
+ return *it;
+ return NULL;
+}
diff --git a/Viewer/src/ServerHandler.hpp b/Viewer/src/ServerHandler.hpp
new file mode 100644
index 0000000..e949255
--- /dev/null
+++ b/Viewer/src/ServerHandler.hpp
@@ -0,0 +1,212 @@
+//============================================================================
+// Copyright 2015 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef SERVERHANDLER_HPP_
+#define SERVERHANDLER_HPP_
+
+#include <deque>
+#include <utility>
+#include <string>
+#include <vector>
+#include <ctime>
+
+#include "Defs.hpp"
+
+#include "VReply.hpp"
+#include "VTask.hpp"
+#include "VInfo.hpp"
+#include "VServerSettings.hpp"
+
+#include <QMutex>
+
+class ClientInvoker;
+class ServerReply;
+
+class ConnectState;
+class NodeObserver;
+class ServerHandler;
+class ServerComQueue;
+class ServerObserver;
+class SuiteFilter;
+class UpdateTimer;
+class VNodeChange;
+class VServer;
+class VServerChange;
+class VSettings;
+
+
+class ServerHandler : public QObject
+{
+ Q_OBJECT // inherits from QObject in order to gain signal/slots
+
+ friend class ServerDefsAccess;
+ friend class ServerComQueue;
+
+public:
+ enum Activity {NoActivity,LoadActivity,RescanActivity};
+
+ const std::string& name() const {return name_;}
+ const std::string& host() const {return host_;}
+ const std::string& longName() const {return longName_;}
+ const std::string& port() const {return port_;}
+
+ Activity activity() const {return activity_;}
+ ConnectState* connectState() const {return connectState_;}
+ bool communicating() {return communicating_;}
+ bool readFromDisk() const;
+ SuiteFilter* suiteFilter() const {return suiteFilter_;}
+
+ void updateSuiteFilter(SuiteFilter*);
+ void updateSuiteFilterWithDefs();
+
+ void connectServer();
+ void disconnectServer();
+ void reset();
+
+ void refresh();
+ void setUpdatingStatus(bool newStatus) {updating_ = newStatus;}
+
+ VServer* vRoot() const {return vRoot_;}
+ SState::State serverState();
+ NState::State state(bool& isSuspended);
+
+ void runCommand(const std::vector<std::string>& cmd);
+ void run(VTask_ptr);
+
+ void addNodeObserver(NodeObserver* obs);
+ void removeNodeObserver(NodeObserver* obs);
+
+ void addServerObserver(ServerObserver* obs);
+ void removeServerObserver(ServerObserver* obs);
+
+ void confChanged(VServerSettings::Param,VProperty*);
+ VServerSettings* conf() const {return conf_;}
+
+ bool isLocalHost() {return (localHostName_ == host_ || host_ == "localhost");}
+
+ static void saveSettings();
+
+ static const std::vector<ServerHandler*>& servers() {return servers_;}
+ static ServerHandler* addServer(const std::string &name,const std::string &host, const std::string &port);
+ static void removeServer(ServerHandler*);
+
+ void command(const std::vector<std::string>& fullPaths, const std::vector<std::string>& cmd);
+ static void command(VInfo_ptr,const std::vector<std::string>&);
+ static void command(std::vector<VInfo_ptr>,std::string);
+
+ void searchBegan();
+ void searchFinished();
+ int secsSinceLastRefresh() const;
+ int secsTillNextRefresh() const;
+
+ static ServerHandler* find(const std::string& name);
+
+protected:
+ ServerHandler(const std::string& name,const std::string& host,const std::string& port);
+ ~ServerHandler();
+
+ void connectToServer();
+ void setCommunicatingStatus(bool c) {communicating_ = c;}
+ void clientTaskFinished(VTask_ptr task,const ServerReply& serverReply);
+ void clientTaskFailed(VTask_ptr task,const std::string& errMsg);
+
+ static std::string commandToString(const std::vector<std::string>& cmd);
+ static void checkNotificationState(VServerSettings::Param par);
+
+ std::string name_;
+ std::string host_;
+ std::string port_;
+ ClientInvoker* client_;
+ std::string longName_;
+ bool updating_;
+ bool communicating_;
+ std::vector<NodeObserver*> nodeObservers_;
+ std::vector<ServerObserver*> serverObservers_;
+
+ VServer* vRoot_;
+
+ //The list of suites the server makes accessible
+ SuiteFilter* suiteFilter_;
+
+ static std::vector<ServerHandler*> servers_;
+
+private Q_SLOTS:
+ void errorMessage(std::string message); // invoked when an error message is received
+ void refreshServerInfo();
+ void slotNodeChanged(const Node* n, std::vector<ecf::Aspect::Type>);
+ void slotDefsChanged(std::vector<ecf::Aspect::Type>);
+ void slotRescanNeed();
+
+private:
+ //Begin and end the initialisation by connecting to the server and syncing.
+ void refreshInternal();
+ void resetFinished();
+ void resetFailed(const std::string& errMsg);
+ void clearTree();
+ void rescanTree();
+ void connectionLost(const std::string& errMsg);
+ bool connectionGained();
+
+ void updateSuiteFilterWithLoaded(const std::vector<std::string>&);
+ void updateSuiteFilter();
+
+ //Handle the refresh timer
+ void stopRefreshTimer();
+ void startRefreshTimer();
+ void updateRefreshTimer();
+ void driftRefreshTimer();
+
+ void script(VTask_ptr req);
+ void job(VTask_ptr req);
+ void jobout(VTask_ptr req);
+ void manual(VTask_ptr req);
+
+ defs_ptr defs();
+ defs_ptr safelyAccessSimpleDefsMembers();
+
+ void setActivity(Activity activity);
+
+ typedef void (ServerObserver::*SoMethod)(ServerHandler*);
+ typedef void (ServerObserver::*SoMethodV1)(ServerHandler*,const VServerChange&);
+ void broadcast(SoMethod);
+ void broadcast(SoMethodV1,const VServerChange&);
+
+ typedef void (NodeObserver::*NoMethod)(const VNode*);
+ typedef void (NodeObserver::*NoMethodV1)(const VNode*,const std::vector<ecf::Aspect::Type>&,const VNodeChange&);
+ typedef void (NodeObserver::*NoMethodV2)(const VNode*,const VNodeChange&);
+ void broadcast(NoMethod,const VNode*);
+ void broadcast(NoMethodV1,const VNode*,const std::vector<ecf::Aspect::Type>&,const VNodeChange&);
+ void broadcast(NoMethodV2,const VNode*,const VNodeChange&);
+
+ void saveConf();
+ void loadConf();
+
+ int truncatedLinesFromServer(const std::string& txt) const;
+
+ QMutex defsMutex_;
+ defs_ptr defs_;
+
+ ServerComQueue* comQueue_;
+
+ //std::string targetNodeNames_; // used when building up a command in ServerHandler::command
+ //std::string targetNodeFullNames_; // used when building up a command in ServerHandler::command
+
+ UpdateTimer* refreshTimer_;
+ QDateTime lastRefresh_;
+
+ Activity activity_;
+ ConnectState* connectState_;
+ SState::State prevServerState_;
+
+ VServerSettings* conf_;
+
+ static std::string localHostName_;
+};
+
+#endif
diff --git a/Viewer/src/ServerItem.cpp b/Viewer/src/ServerItem.cpp
new file mode 100644
index 0000000..faa8529
--- /dev/null
+++ b/Viewer/src/ServerItem.cpp
@@ -0,0 +1,124 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "ServerItem.hpp"
+#include "ServerHandler.hpp"
+
+#include <algorithm>
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <stdlib.h>
+
+
+ServerItem::ServerItem(const std::string& name) :
+ name_(name),
+ useCnt_(0),
+ handler_(0),
+ favourite_(false)
+{
+}
+
+ServerItem::ServerItem(const std::string& name,const std::string& host,const std::string& port, bool favourite) :
+ name_(name), host_(host), port_(port),
+ useCnt_(0),
+ handler_(0),
+ favourite_(favourite)
+{
+}
+
+ServerItem::~ServerItem()
+{
+ broadcastDeletion();
+
+ if(handler_)
+ ServerHandler::removeServer(handler_);
+}
+
+bool ServerItem::isUsed() const
+{
+ return (handler_ != NULL);
+}
+
+
+void ServerItem::reset(const std::string& name,const std::string& host,const std::string& port)
+{
+ name_=name;
+ host_=host;
+ port_=port;
+
+ broadcastChanged();
+}
+
+void ServerItem::setFavourite(bool b)
+{
+ favourite_=b;
+ broadcastChanged();
+}
+//===========================================================
+// Register the usage of the server. Create and destroys the
+// the ServerHandler.
+//===========================================================
+
+void ServerItem::registerUsageBegin()
+{
+ useCnt_++;
+ if(!handler_)
+ {
+ handler_=ServerHandler::addServer(name_,host_,port_);
+ }
+}
+
+void ServerItem::registerUsageEnd()
+{
+ useCnt_--;
+ if(useCnt_ == 0 && handler_)
+ {
+ ServerHandler::removeServer(handler_);
+ handler_=0;
+ }
+}
+
+//===========================================================
+// Observers
+//===========================================================
+
+void ServerItem::addObserver(ServerItemObserver* o)
+{
+ std::vector<ServerItemObserver*>::iterator it=std::find(observers_.begin(),observers_.end(),o);
+ if(it == observers_.end())
+ {
+ observers_.push_back(o);
+ registerUsageBegin();
+ }
+}
+
+void ServerItem::removeObserver(ServerItemObserver* o)
+{
+ std::vector<ServerItemObserver*>::iterator it=std::find(observers_.begin(),observers_.end(),o);
+ if(it != observers_.end())
+ {
+ observers_.erase(it);
+ registerUsageEnd();
+ }
+}
+
+void ServerItem::broadcastChanged()
+{
+ for(std::vector<ServerItemObserver*>::const_iterator it=observers_.begin(); it != observers_.end(); ++it)
+ (*it)->notifyServerItemChanged(this);
+}
+
+void ServerItem::broadcastDeletion()
+{
+ std::vector<ServerItemObserver*> obsCopy=observers_;
+
+ for(std::vector<ServerItemObserver*>::const_iterator it=obsCopy.begin(); it != obsCopy.end(); ++it)
+ (*it)->notifyServerItemDeletion(this);
+}
diff --git a/Viewer/src/ServerItem.hpp b/Viewer/src/ServerItem.hpp
new file mode 100644
index 0000000..0d604dd
--- /dev/null
+++ b/Viewer/src/ServerItem.hpp
@@ -0,0 +1,81 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef SERVERITEM_HPP_
+#define SERVERITEM_HPP_
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include <cstddef>
+#include <boost/shared_ptr.hpp>
+
+class ServerHandler;
+class ServerItem;
+
+class ServerItemObserver
+{
+public:
+ ServerItemObserver() {}
+ virtual ~ServerItemObserver() {}
+ virtual void notifyServerItemChanged(ServerItem*)=0;
+ virtual void notifyServerItemDeletion(ServerItem*)=0;
+};
+
+
+class ServerItem
+{
+
+friend class ServerList;
+
+public:
+ const std::string& name() const {return name_;}
+ const std::string& host() const {return host_;}
+ const std::string& port() const {return port_;}
+ bool isFavourite() const {return favourite_;}
+
+ bool isUsed() const;
+ int useCnt() const {return useCnt_;}
+ ServerHandler* serverHandler() const {return handler_;}
+
+ void addObserver(ServerItemObserver*);
+ void removeObserver(ServerItemObserver*);
+
+protected:
+ explicit ServerItem(const std::string&);
+ ServerItem(const std::string&,const std::string&,const std::string&,bool favourite=false);
+ ~ServerItem();
+
+ void name(const std::string& name) {name_=name;}
+ void host(const std::string& host) {host_=host;}
+ void port(const std::string& port) {port_=port;}
+ void reset(const std::string& name,const std::string& host,const std::string& port);
+ void setFavourite(bool b);
+
+ void registerUsageBegin();
+ void registerUsageEnd();
+
+ void broadcastChanged();
+ void broadcastDeletion();
+
+ std::string name_;
+ std::string host_;
+ std::string port_;
+ bool favourite_;
+ int useCnt_;
+ ServerHandler* handler_;
+
+ std::set<std::string> suiteFilter_;
+ std::vector<ServerItemObserver*> observers_;
+};
+
+typedef boost::shared_ptr<ServerItem> ServerItem_ptr;
+
+#endif
diff --git a/Viewer/src/ServerList.cpp b/Viewer/src/ServerList.cpp
new file mode 100644
index 0000000..e72797d
--- /dev/null
+++ b/Viewer/src/ServerList.cpp
@@ -0,0 +1,328 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include <boost/algorithm/string.hpp>
+
+#include "ServerList.hpp"
+
+#include "DirectoryHandler.hpp"
+#include "ServerItem.hpp"
+
+#include <algorithm>
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <stdlib.h>
+
+ServerList* ServerList::instance_=0;
+
+
+//Singleton instance method
+ServerList* ServerList::instance()
+{
+ if(!instance_)
+ instance_=new ServerList();
+ return instance_;
+}
+
+//===========================================================
+// Managing server items
+//===========================================================
+
+ServerItem* ServerList::itemAt(int index)
+{
+ return (index >=0 && index < static_cast<int>(items_.size()))?items_.at(index):0;
+}
+
+ServerItem* ServerList::find(const std::string& name)
+{
+ for(std::vector<ServerItem*>::const_iterator it=items_.begin(); it != items_.end(); ++it)
+ {
+ if((*it)->name() == name)
+ return *it;
+ }
+ return 0;
+}
+
+ServerItem* ServerList::add(const std::string& name,const std::string& host,const std::string& port,bool favourite,bool saveIt)
+{
+ //Check if there is an item with the same name. Names have to be unique!
+ if(find(name))
+ return 0;
+
+ ServerItem* item=new ServerItem(name,host,port,favourite);
+ items_.push_back(item);
+
+ if(saveIt)
+ save();
+
+ broadcastChanged();
+
+ return item;
+}
+
+void ServerList::remove(ServerItem *item)
+{
+ std::vector<ServerItem*>::iterator it=std::find(items_.begin(),items_.end(),item);
+ if(it != items_.end())
+ {
+ items_.erase(it);
+ //item->broadcastDeletion();
+ delete item;
+
+ save();
+ broadcastChanged();
+ }
+}
+
+void ServerList::reset(ServerItem* item,const std::string& name,const std::string& host,const std::string& port)
+{
+ std::vector<ServerItem*>::iterator it=std::find(items_.begin(),items_.end(),item);
+ if(it != items_.end())
+ {
+ //Check if there is an item with the same name. names have to be unique!
+ if(item->name() != name && find(name))
+ return;
+
+ item->reset(name,host,port);
+
+ save();
+ broadcastChanged();
+ }
+}
+
+void ServerList::setFavourite(ServerItem* item,bool b)
+{
+ std::vector<ServerItem*>::iterator it=std::find(items_.begin(),items_.end(),item);
+ if(it != items_.end())
+ {
+ item->setFavourite(b);
+ for(std::vector<ServerListObserver*>::const_iterator it=observers_.begin(); it != observers_.end(); ++it)
+ (*it)->notifyServerListFavouriteChanged(item);
+ }
+}
+
+std::string ServerList::uniqueName(const std::string& name)
+{
+ bool hasIt=false;
+ for(std::vector<ServerItem*>::const_iterator it=items_.begin(); it != items_.end(); ++it)
+ {
+ if((*it)->name() == name)
+ {
+ hasIt=true;
+ break;
+ }
+ }
+ if(!hasIt)
+ {
+ return name;
+ }
+
+ for(int i=1; i < 100; i++)
+ {
+ std::ostringstream c;
+ c << i;
+ std::string currentName=name+"_"+c.str();
+
+ hasIt=false;
+ for(std::vector<ServerItem*>::const_iterator it=items_.begin(); it != items_.end(); ++it)
+ {
+ if((*it)->name() == currentName)
+ {
+ hasIt=true;
+ break;
+ }
+ }
+ if(!hasIt)
+ {
+ return currentName;
+ }
+ }
+
+ return name;
+
+}
+
+
+void ServerList::rescan()
+{
+
+}
+
+//===========================================================
+// Initialisation
+//===========================================================
+
+void ServerList::init()
+{
+ serversPath_ = DirectoryHandler::concatenate(DirectoryHandler::configDir(), "servers.txt");
+
+ if(load() == false)
+ {
+ if(readRcFile() == false)
+ {
+ readSystemFile();
+ }
+ save();
+ }
+}
+
+bool ServerList::load()
+{
+ std::ifstream in(serversPath_.c_str());
+ if(!in.good())
+ return false;
+
+ std::string line;
+ while(getline(in,line))
+ {
+ //We ignore comment lines
+ std::string buf=boost::trim_left_copy(line);
+ if(buf.size() > 0 && buf.at(0) == '#')
+ continue;
+
+ std::vector<std::string> sv;
+ boost::split(sv,line,boost::is_any_of(","));
+
+ bool favourite=false;
+ if(sv.size() >= 4)
+ favourite=(sv[3]=="1")?true:false;
+
+ if(sv.size() >= 3)
+ {
+ add(sv[0],sv[1],sv[2],favourite,false);
+ }
+ }
+
+ in.close();
+
+ if(count() == 0)
+ return false;
+
+ return true;
+}
+
+void ServerList::save()
+{
+ std::ofstream out;
+ out.open(serversPath_.c_str());
+ if(!out.good())
+ return;
+
+ out << "#Name Host Port Favourite" << std::endl;
+
+ for(std::vector<ServerItem*>::iterator it=items_.begin(); it != items_.end(); ++it)
+ {
+ std::string fav=((*it)->isFavourite())?"1":"0";
+ out << (*it)->name() << "," << (*it)->host() << "," << (*it)->port() << "," << fav << std::endl;
+ }
+ out.close();
+}
+
+
+bool ServerList::readRcFile()
+{
+ std::string path(DirectoryHandler::concatenate(DirectoryHandler::rcDir(), "servers"));
+
+ std::ifstream in(path.c_str());
+
+ if(in.good())
+ {
+ std::string line;
+ while(getline(in,line))
+ {
+ std::string buf=boost::trim_left_copy(line);
+ if(buf.size() > 0 && buf.at(0) == '#')
+ continue;
+
+ std::stringstream ssdata(line);
+ std::vector<std::string> vec;
+
+ while(ssdata >> buf)
+ {
+ vec.push_back(buf);
+ }
+
+ if(vec.size() >= 3)
+ {
+ add(vec[0],vec[1],vec[2],false,false);
+ }
+ }
+ }
+ else
+ return false;
+
+ in.close();
+
+ return true;
+}
+
+bool ServerList::readSystemFile()
+{
+ std::string path(DirectoryHandler::concatenate(DirectoryHandler::shareDir(), "servers"));
+ std::ifstream in(path.c_str());
+
+ if(in.good())
+ {
+ std::string line;
+ while(getline(in,line))
+ {
+ std::string buf=boost::trim_left_copy(line);
+ if(buf.size() >0 && buf.at(0) == '#')
+ continue;
+
+ std::stringstream ssdata(line);
+ std::vector<std::string> vec;
+
+ while(ssdata >> buf)
+ {
+ vec.push_back(buf);
+ }
+
+ if(vec.size() >= 3)
+ {
+ add(vec[0],vec[1],vec[2],false,false);
+ }
+ }
+ }
+ else
+ return false;
+
+ in.close();
+
+ return true;
+}
+
+//===========================================================
+// Observers
+//===========================================================
+
+void ServerList::addObserver(ServerListObserver* o)
+{
+ std::vector<ServerListObserver*>::iterator it=std::find(observers_.begin(),observers_.end(),o);
+ if(it == observers_.end())
+ {
+ observers_.push_back(o);
+ }
+}
+
+void ServerList::removeObserver(ServerListObserver* o)
+{
+ std::vector<ServerListObserver*>::iterator it=std::find(observers_.begin(),observers_.end(),o);
+ if(it != observers_.end())
+ {
+ observers_.erase(it);
+ }
+}
+
+void ServerList::broadcastChanged()
+{
+ for(std::vector<ServerListObserver*>::const_iterator it=observers_.begin(); it != observers_.end(); ++it)
+ (*it)->notifyServerListChanged();
+}
diff --git a/Viewer/src/ServerList.hpp b/Viewer/src/ServerList.hpp
new file mode 100644
index 0000000..67ae794
--- /dev/null
+++ b/Viewer/src/ServerList.hpp
@@ -0,0 +1,72 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef SERVERLIST_HPP_
+#define SERVERLIST_HPP_
+
+#include <string>
+#include <vector>
+
+class ServerItem;
+class ServerList;
+
+class ServerListObserver
+{
+public:
+ ServerListObserver() {};
+ virtual ~ServerListObserver() {};
+ virtual void notifyServerListChanged()=0;
+ virtual void notifyServerListFavouriteChanged(ServerItem*)=0;
+};
+
+class ServerList
+{
+public:
+ int count() {return static_cast<int>(items_.size());}
+ ServerItem* itemAt(int);
+ ServerItem* find(const std::string& name);
+
+ //Can be added or changed only via these static methods
+ ServerItem* add(const std::string&,const std::string&,const std::string&,bool,bool saveIt=true);
+ void remove(ServerItem*);
+ void reset(ServerItem*,const std::string& name,const std::string& host,const std::string& port);
+ void setFavourite(ServerItem*,bool);
+
+ std::string uniqueName(const std::string&);
+
+ void init();
+ void save();
+ void rescan();
+
+ void addObserver(ServerListObserver*);
+ void removeObserver(ServerListObserver*);
+
+ static ServerList* instance();
+
+protected:
+ ServerList() {};
+ ~ServerList() {};
+
+ static ServerList* instance_;
+
+ bool load();
+ bool readRcFile();
+ bool readSystemFile();
+
+ void broadcastChanged();
+ void broadcastChanged(ServerItem*);
+
+ std::vector<ServerItem*> items_;
+ std::string serversPath_;
+ std::vector<ServerListObserver*> observers_;
+};
+
+
+
+#endif
diff --git a/Viewer/src/ServerListDialog.cpp b/Viewer/src/ServerListDialog.cpp
new file mode 100644
index 0000000..d6ed4e8
--- /dev/null
+++ b/Viewer/src/ServerListDialog.cpp
@@ -0,0 +1,848 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "ServerListDialog.hpp"
+
+#include <QtGlobal>
+#include <QCloseEvent>
+#include <QMessageBox>
+#include <QPushButton>
+#include <QSettings>
+#include <QSortFilterProxyModel>
+
+#include "IconProvider.hpp"
+#include "ServerFilter.hpp"
+#include "ServerItem.hpp"
+#include "ServerList.hpp"
+#include "SessionHandler.hpp"
+#include "VConfig.hpp"
+
+//======================================
+//
+// ServerDialogChecked
+//
+//======================================
+
+bool ServerDialogChecker::checkName(QString name,QString oriName)
+{
+ if(name.simplified().isEmpty())
+ {
+ error(QObject::tr("<b>Name</b> cannot be empty!"));
+ return false;
+ }
+ else if(name.contains(","))
+ {
+ error(QObject::tr("<b>Name</b> cannot contain comma character!"));
+ return false;
+ }
+
+ if(oriName != name && ServerList::instance()->find(name.toStdString()) )
+ {
+ error(QObject::tr("The specified server already exists! Please select a different name!"));
+ return false;
+ }
+
+ return true;
+}
+
+bool ServerDialogChecker::checkHost(QString host)
+{
+ if(host.simplified().isEmpty())
+ {
+ error(QObject::tr("<b>Host</b> cannot be empty!"));
+ return false;
+ }
+ else if(host.contains(","))
+ {
+ error(QObject::tr("<b>Host</b> cannot contain comma character!"));
+ return false;
+ }
+
+ return true;
+}
+
+bool ServerDialogChecker::checkPort(QString port)
+{
+ if(port.simplified().isEmpty())
+ {
+ error(QObject::tr("<b>Port</b> cannot be empty!"));
+ return false;
+ }
+ else if(port.contains(","))
+ {
+ error(QObject::tr("<b>Port</b> cannot contain comma character!"));
+ return false;
+ }
+ return true;
+}
+
+
+void ServerDialogChecker::error(QString msg)
+{
+ QMessageBox::critical(0,QObject::tr("Server item"),errorText_ + "<br>"+ msg);
+}
+
+//======================================
+//
+// ServerAddDialog
+//
+//======================================
+
+ServerAddDialog::ServerAddDialog(QWidget *parent) :
+ QDialog(parent),
+ ServerDialogChecker(tr("Cannot create new server!"))
+{
+ setupUi(this);
+
+ //nameEdit->setText();
+ //hostEdit->setText();
+ //portEdit->setText();
+ addToCurrentCb->setChecked(true);
+
+ //Validators
+ //nameEdit->setValidator(new QRegExpValidator(""));
+ //hostEdit->setValidator(new QRegExpValidator(""));
+ portEdit->setValidator(new QIntValidator(1025,65535,this));
+}
+
+void ServerAddDialog::accept()
+{
+ QString name=nameEdit->text();
+ QString host=hostEdit->text();
+ QString port=portEdit->text();
+
+ if(!checkName(name) || !checkHost(host) || !checkPort(port))
+ return;
+
+ QDialog::accept();
+}
+
+QString ServerAddDialog::name() const
+{
+ return nameEdit->text();
+}
+
+QString ServerAddDialog::host() const
+{
+ return hostEdit->text();
+}
+
+QString ServerAddDialog::port() const
+{
+ return portEdit->text();
+}
+
+bool ServerAddDialog::addToView() const
+{
+ return addToCurrentCb->isChecked();
+}
+
+//======================================
+//
+// ServerEditDialog
+//
+//======================================
+
+ServerEditDialog::ServerEditDialog(QString name, QString host, QString port,bool favourite,QWidget *parent) :
+ QDialog(parent),
+ ServerDialogChecker(tr("Cannot modify server!")),
+ oriName_(name)
+{
+ setupUi(this);
+
+ nameEdit->setText(name);
+ hostEdit->setText(host);
+ portEdit->setText(port);
+ favCh->setChecked(favourite);
+
+ //Validators
+ //nameEdit->setValidator(new QRegExpValidator(""));
+ //hostEdit->setValidator(new QRegExpValidator(""));
+ portEdit->setValidator(new QIntValidator(1025,65535,this));
+}
+
+void ServerEditDialog::accept()
+{
+ QString name=nameEdit->text();
+ QString host=hostEdit->text();
+ QString port=portEdit->text();
+
+ if(!checkName(name,oriName_) || !checkHost(host) || !checkPort(port))
+ return;
+
+ QDialog::accept();
+}
+
+
+QString ServerEditDialog::name() const
+{
+ return nameEdit->text();
+}
+
+QString ServerEditDialog::host() const
+{
+ return hostEdit->text();
+}
+
+QString ServerEditDialog::port() const
+{
+ return portEdit->text();
+}
+
+bool ServerEditDialog::isFavourite() const
+{
+ return favCh->isChecked();
+}
+
+//======================================
+//
+// ServerListDialog
+//
+//======================================
+
+ServerListDialog::ServerListDialog(Mode mode,ServerFilter *filter,QWidget *parent) :
+ QDialog(parent),
+ mode_(mode),
+ filter_(filter)
+{
+ setupUi(this);
+
+ QString wt=windowTitle();
+ wt+=" - " + QString::fromStdString(VConfig::instance()->appLongName());
+ setWindowTitle(wt);
+
+ sortModel_=new ServerListFilterModel(this);
+ model_=new ServerListModel(filter_,this);
+ sortModel_->setSourceModel(model_);
+ sortModel_->setDynamicSortFilter(true);
+
+ serverView->setRootIsDecorated(false);
+ serverView->setAllColumnsShowFocus(true);
+ serverView->setUniformRowHeights(true);
+ serverView->setAlternatingRowColors(true);
+ serverView->setSortingEnabled(true);
+ serverView->setSelectionMode(QAbstractItemView::ExtendedSelection);
+ serverView->sortByColumn(ServerListModel::NameColumn,Qt::AscendingOrder);
+
+ serverView->setModel(sortModel_);
+
+ //Add context menu actions to the view
+ QAction* sep1=new QAction(this);
+ sep1->setSeparator(true);
+ QAction* sep2=new QAction(this);
+ sep2->setSeparator(true);
+ QAction* sep3=new QAction(this);
+ sep3->setSeparator(true);
+
+ serverView->addAction(actionAdd);
+ serverView->addAction(sep1);
+ serverView->addAction(actionDuplicate);
+ serverView->addAction(actionEdit);
+ serverView->addAction(sep2);
+ serverView->addAction(actionDelete);
+ serverView->addAction(sep3);
+ serverView->addAction(actionFavourite);
+
+ //Add actions for the toolbuttons
+ addTb->setDefaultAction(actionAdd);
+ deleteTb->setDefaultAction(actionDelete);
+ editTb->setDefaultAction(actionEdit);
+ duplicateTb->setDefaultAction(actionDuplicate);
+ //rescanTb->setDefaultAction(actionRescan);
+
+ checkActionState();
+
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ filterLe_->setPlaceholderText(tr("Filter"));
+#endif
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
+ filterLe_->setClearButtonEnabled(true);
+#endif
+
+ connect(filterLe_,SIGNAL(textEdited(QString)),
+ this,SLOT(slotFilter(QString)));
+
+ connect(filterFavTb_,SIGNAL(clicked(bool)),
+ this,SLOT(slotFilterFavourite(bool)));
+
+ //Load settings
+ readSettings();
+
+ //The selection changes in the view
+ connect(serverView->selectionModel(),SIGNAL(currentChanged(QModelIndex,QModelIndex)),
+ this,SLOT(slotItemSelected(QModelIndex,QModelIndex)));
+
+ connect(serverView,SIGNAL(clicked(QModelIndex)),
+ this,SLOT(slotItemClicked(QModelIndex)));
+
+
+ for(int i=0; i < model_->columnCount()-1; i++)
+ serverView->resizeColumnToContents(i);
+}
+
+ServerListDialog::~ServerListDialog()
+{
+ writeSettings();
+}
+
+void ServerListDialog::closeEvent(QCloseEvent* event)
+{
+ event->accept();
+ writeSettings();
+ ServerList::instance()->save();
+}
+
+void ServerListDialog::accept()
+{
+ //Overwrite ServerList with the actual data
+ writeSettings();
+ QDialog::accept();
+ ServerList::instance()->save();
+}
+
+void ServerListDialog::reject()
+{
+ //Overwrite ServerList with the actual data
+ writeSettings();
+ QDialog::reject();
+ ServerList::instance()->save();
+}
+
+void ServerListDialog::editItem(const QModelIndex& index)
+{
+ if(ServerItem* item=model_->indexToServer(sortModel_->mapToSource(index)))
+ {
+ ServerEditDialog d(QString::fromStdString(item->name()),
+ QString::fromStdString(item->host()),
+ QString::fromStdString(item->port()),
+ item->isFavourite(),this);
+
+ //The dialog checks the name, host and port!
+ if(d.exec()== QDialog::Accepted)
+ {
+ ServerList::instance()->reset(item,d.name().toStdString(),d.host().toStdString(),d.port().toStdString());
+
+ if(item->isFavourite() != d.isFavourite())
+ {
+ ServerList::instance()->setFavourite(item,d.isFavourite());
+ QModelIndex idx=sortModel_->index(index.row(),ServerListModel::FavouriteColumn);
+ serverView->update(idx);
+ }
+ }
+ }
+}
+
+void ServerListDialog::duplicateItem(const QModelIndex& index)
+{
+ if(ServerItem* item=model_->indexToServer(sortModel_->mapToSource(index)))
+ {
+ std::string dname=ServerList::instance()->uniqueName(item->name());
+
+ ServerEditDialog d(QString::fromStdString(dname),
+ QString::fromStdString(item->host()),
+ QString::fromStdString(item->port()),item->isFavourite(),this);
+
+ //The dialog checks the name, host and port!
+ if(d.exec() == QDialog::Accepted)
+ {
+ model_->dataIsAboutToChange();
+ ServerList::instance()->add(d.name().toStdString(),d.host().toStdString(),d.port().toStdString(),false);
+ model_->dataChangeFinished();
+ }
+ }
+}
+
+void ServerListDialog::addItem()
+{
+ ServerAddDialog d(this);
+
+ //The dialog checks the name, host and port!
+ if(d.exec() == QDialog::Accepted)
+ {
+ model_->dataIsAboutToChange();
+ ServerItem* item=ServerList::instance()->add(d.name().toStdString(),d.host().toStdString(),d.port().toStdString(),false);
+ model_->dataChangeFinished();
+ if(d.addToView() && filter_)
+ {
+ filter_->addServer(item);
+ }
+ }
+}
+
+void ServerListDialog::removeItem(const QModelIndex& index)
+{
+ ServerItem* item=model_->indexToServer(sortModel_->mapToSource(index));
+
+ if(!item)
+ return;
+
+ QString str=tr("Are you sure that you want to delete server: <b>");
+ str+=QString::fromStdString(item->name()) ;
+ str+="</b>?";
+ str+=tr("<br>It will be removed from all the existing views!");
+
+ QMessageBox msgBox;
+ msgBox.setWindowTitle(tr("Delete server"));
+ msgBox.setText(str);
+ msgBox.setIcon(QMessageBox::Warning);
+ msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
+ msgBox.setDefaultButton(QMessageBox::Cancel);
+ int ret=msgBox.exec();
+
+ switch (ret)
+ {
+ case QMessageBox::Yes:
+ model_->dataIsAboutToChange();
+ //It will delete item as well!
+ ServerList::instance()->remove(item);
+ model_->dataChangeFinished();
+ break;
+ case QMessageBox::Cancel:
+ // Cancel was clicked
+ break;
+ default:
+ // should never be reached
+ break;
+ }
+}
+
+
+void ServerListDialog::setFavouriteItem(const QModelIndex& index,bool b)
+{
+ ServerItem* item=model_->indexToServer(sortModel_->mapToSource(index));
+
+ if(!item)
+ return;
+
+ ServerList::instance()->setFavourite(item,b);
+
+ QModelIndex idx=sortModel_->index(index.row(),ServerListModel::FavouriteColumn);
+ serverView->update(idx);
+}
+
+
+void ServerListDialog::on_serverView_doubleClicked(const QModelIndex& index)
+{
+ int col=index.column();
+ if(col == ServerListModel::NameColumn || col == ServerListModel::HostColumn ||
+ col == ServerListModel::PortColumn)
+ {
+ editItem(index);
+ }
+}
+
+void ServerListDialog::on_actionEdit_triggered()
+{
+ QModelIndex index=serverView->currentIndex();
+ editItem(index);
+}
+
+void ServerListDialog::on_actionAdd_triggered()
+{
+ addItem();
+}
+
+void ServerListDialog::on_actionDelete_triggered()
+{
+ QModelIndex index=serverView->currentIndex();
+ removeItem(index);
+}
+
+void ServerListDialog::on_actionDuplicate_triggered()
+{
+ QModelIndex index=serverView->currentIndex();
+ duplicateItem(index);
+}
+
+void ServerListDialog::on_actionFavourite_triggered(bool checked)
+{
+ QModelIndex index=serverView->currentIndex();
+ setFavouriteItem(index,checked);
+}
+
+void ServerListDialog::on_actionRescan_triggered()
+{
+
+}
+
+void ServerListDialog::slotItemSelected(const QModelIndex& current,const QModelIndex& prev)
+{
+ checkActionState();
+}
+
+void ServerListDialog::slotItemClicked(const QModelIndex& current)
+{
+ if(ServerItem* item=model_->indexToServer(sortModel_->mapToSource(current)))
+ {
+ if(current.column() == ServerListModel::FavouriteColumn)
+ {
+ setFavouriteItem(current,!item->isFavourite());
+ }
+ }
+
+ checkActionState();
+}
+
+void ServerListDialog::checkActionState()
+{
+ QModelIndex index=serverView->currentIndex();
+
+ if(!index.isValid())
+ {
+ actionEdit->setEnabled(false);
+ actionDuplicate->setEnabled(false);
+ actionDelete->setEnabled(false);
+ actionFavourite->setEnabled(false);
+ }
+ else
+ {
+ ServerItem* item=model_->indexToServer(sortModel_->mapToSource(index));
+
+ assert(item);
+
+ actionEdit->setEnabled(true);
+ actionDuplicate->setEnabled(true);
+ actionDelete->setEnabled(true);
+ actionFavourite->setEnabled(true);
+ actionFavourite->setChecked(item->isFavourite());
+ }
+}
+
+void ServerListDialog::slotFilter(QString txt)
+{
+ sortModel_->setFilterStr(txt);
+}
+
+void ServerListDialog::slotFilterFavourite(bool b)
+{
+ sortModel_->setFilterFavourite(b);
+}
+
+void ServerListDialog::writeSettings()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ Q_ASSERT(cs);
+ QSettings settings(QString::fromStdString(cs->qtSettingsFile("ServerListDialog")),
+ QSettings::NativeFormat);
+
+ //We have to clear it not to remember all the previous windows
+ settings.clear();
+
+ settings.beginGroup("main");
+ settings.setValue("size",size());
+ settings.setValue("filterFav",filterFavTb_->isChecked());
+ settings.endGroup();
+}
+
+void ServerListDialog::readSettings()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ Q_ASSERT(cs);
+ QSettings settings(QString::fromStdString(cs->qtSettingsFile("ServerListDialog")),
+ QSettings::NativeFormat);
+
+ settings.beginGroup("main");
+ if(settings.contains("size"))
+ {
+ resize(settings.value("size").toSize());
+ }
+ else
+ {
+ resize(QSize(350,500));
+ }
+
+ if(settings.contains("filterFav"))
+ {
+ //This does not emit the clicked signal
+ filterFavTb_->setChecked(settings.value("filterFav").toBool());
+ //so we need to do it explicitly
+ sortModel_->setFilterFavourite(filterFavTb_->isChecked());
+ }
+
+ settings.endGroup();
+}
+
+//======================================
+//
+// ServerListModel
+//
+//======================================
+
+ServerListModel::ServerListModel(ServerFilter* filter,QObject *parent) :
+ QAbstractItemModel(parent),
+ filter_(filter)
+{
+ int id=IconProvider::add(":/viewer/favourite.svg","favourite");
+ favPix_=IconProvider::pixmap(id,12);
+
+ id=IconProvider::add(":/viewer/favourite_empty.svg","favourite_empty");
+ favEmptyPix_=IconProvider::pixmap(id,12);
+
+ loadFont_.setBold(true);
+}
+
+ServerListModel::~ServerListModel()
+{
+}
+
+void ServerListModel::dataIsAboutToChange()
+{
+ beginResetModel();
+}
+
+void ServerListModel::dataChangeFinished()
+{
+ endResetModel();
+}
+
+int ServerListModel::columnCount(const QModelIndex& parent) const
+{
+ return 6;
+}
+
+int ServerListModel::rowCount(const QModelIndex& parent) const
+{
+ if(!parent.isValid())
+ return static_cast<int>(ServerList::instance()->count());
+
+ return 0;
+}
+
+QVariant ServerListModel::data(const QModelIndex& index, int role) const
+{
+ if(!index.isValid() ||
+ (role != Qt::DisplayRole && role != Qt::ForegroundRole && role != Qt::DecorationRole &&
+ role != Qt::CheckStateRole && role != Qt::UserRole && role != Qt::FontRole))
+ {
+ return QVariant();
+ }
+
+ ServerItem* item=ServerList::instance()->itemAt(index.row());
+
+ if(!item)
+ return QVariant();
+
+ if(role == Qt::DisplayRole)
+ {
+ switch(index.column())
+ {
+ case NameColumn: return QString::fromStdString(item->name());
+ case HostColumn: return QString::fromStdString(item->host());
+ case PortColumn: return QString::fromStdString(item->port());
+ case UseColumn:
+ {
+ int i=item->useCnt();
+ if(item->useCnt() > 0)
+ return "used (" + QString::number(item->useCnt()) + ")";
+
+ return QVariant();
+ }
+ default: return QVariant();
+ }
+ }
+ else if (role == Qt::ForegroundRole)
+ {
+ //QColor selectCol_=QColor(34,51,136);
+
+ //if(index.column() != LoadColumn && index.column() != FavouriteColumn &&
+ // filter_ && filter_->isFiltered(item))
+ // return selectCol_;
+
+ return QVariant();
+ }
+ else if (role == Qt::DecorationRole)
+ {
+ if(index.column() == FavouriteColumn)
+ return (item->isFavourite())?favPix_:favEmptyPix_;
+
+ return QVariant();
+ }
+ else if (role == Qt::UserRole)
+ {
+ if(index.column() == FavouriteColumn)
+ return item->isFavourite();
+
+ return QVariant();
+ }
+ else if (role == Qt::CheckStateRole)
+ {
+ if(index.column() == LoadColumn && filter_)
+ return (filter_->isFiltered(item))?QVariant(Qt::Checked):QVariant(Qt::Unchecked);
+
+ return QVariant();
+ }
+ else if (role == Qt::FontRole)
+ {
+ if(index.column() != LoadColumn && index.column() != FavouriteColumn &&
+ filter_ && filter_->isFiltered(item))
+ return loadFont_;
+
+ return QVariant();
+ }
+
+ return QVariant();
+}
+
+QVariant ServerListModel::headerData(int section,Qt::Orientation ori,int role) const
+{
+ if(ori != Qt::Horizontal)
+ {
+ return QVariant();
+ }
+
+ if(role == Qt::DisplayRole)
+ {
+ switch(section)
+ {
+ case LoadColumn: return tr("L");
+ case NameColumn: return tr("Name");
+ case HostColumn: return tr("Host");
+ case PortColumn: return tr("Port");
+ case FavouriteColumn: return tr("F");
+ case UseColumn: return tr("Usage");
+ default: return QVariant();
+ }
+ }
+ else if(role == Qt::ToolTipRole)
+ {
+ switch(section)
+ {
+ case LoadColumn: return tr("Indicates if the server is <b>loaded</b> in the <b>current</b> tab");
+ case NameColumn: return tr("Server name is a freely customisable <b>nickname</b>. It is only used by the </b>viewer</b>.");
+ case HostColumn: return tr("Hostname of the server");
+ case PortColumn: return tr("Port number of the server");
+ case FavouriteColumn: return tr("Indicates if a server is a <b>favourite</b>. Only favourite and loaded servers \
+ are appearing in the server list under the <b>Servers menu</b> in the menubar");
+ case UseColumn: return tr("Indicates the <b>number of tabs</b> where the server is loaded.");
+ default: return QVariant();
+ }
+ }
+ else if(role == Qt::TextAlignmentRole)
+ {
+ return Qt::AlignCenter;
+ }
+
+
+
+ return QVariant();
+}
+
+bool ServerListModel::setData(const QModelIndex& idx, const QVariant & value, int role )
+{
+ if(filter_ && idx.column() == LoadColumn && role == Qt::CheckStateRole)
+ {
+ int row=idx.row();
+ if(ServerItem* item=ServerList::instance()->itemAt(idx.row()))
+ {
+ bool checked=(value.toInt() == Qt::Checked)?true:false;
+ if(checked)
+ filter_->addServer(item);
+ else
+ filter_->removeServer(item);
+
+ QModelIndex startIdx=index(idx.row(),0);
+ QModelIndex endIdx=index(idx.row(),columnCount()-1);
+
+ Q_EMIT dataChanged(startIdx,endIdx);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+QModelIndex ServerListModel::index(int row, int column, const QModelIndex& /*parent*/) const
+{
+ return createIndex(row,column,static_cast<void*>(0));
+}
+
+QModelIndex ServerListModel::parent(const QModelIndex &) const
+{
+ return QModelIndex();
+}
+
+Qt::ItemFlags ServerListModel::flags ( const QModelIndex & index) const
+{
+ Qt::ItemFlags defaultFlags=Qt::ItemIsEnabled | Qt::ItemIsSelectable;
+
+ if(filter_ && index.column() == LoadColumn)
+ {
+ defaultFlags=defaultFlags | Qt::ItemIsUserCheckable;
+ }
+
+ return defaultFlags;
+}
+
+ServerItem* ServerListModel::indexToServer(const QModelIndex& index)
+{
+ return ServerList::instance()->itemAt(index.row());
+}
+
+//======================================
+//
+// ServerListFilterModel
+//
+//======================================
+
+ServerListFilterModel::ServerListFilterModel(QObject *parent) :
+ QSortFilterProxyModel(parent),
+ filterFavourite_(false)
+{
+
+}
+
+void ServerListFilterModel::setFilterStr(QString t)
+{
+ QString newStr=t.simplified();
+ if(newStr != filterStr_)
+ {
+ filterStr_=newStr;
+ invalidateFilter();
+ }
+}
+
+void ServerListFilterModel::setFilterFavourite(bool b)
+{
+ if(b != filterFavourite_)
+ {
+ filterFavourite_=b;
+ invalidateFilter();
+ }
+}
+
+
+bool ServerListFilterModel::filterAcceptsRow(int sourceRow,const QModelIndex &sourceParent) const
+{
+ if(filterFavourite_)
+ {
+ QModelIndex idxLoad = sourceModel()->index(sourceRow, ServerListModel::LoadColumn, sourceParent);
+ QModelIndex idxFav = sourceModel()->index(sourceRow, ServerListModel::FavouriteColumn, sourceParent);
+ if(!sourceModel()->data(idxFav,Qt::UserRole).toBool() &&
+ sourceModel()->data(idxLoad,Qt::CheckStateRole).toInt() != Qt::Checked)
+ return false;
+ }
+
+ if(filterStr_.isEmpty())
+ return true;
+
+ QModelIndex idxName = sourceModel()->index(sourceRow,ServerListModel::NameColumn, sourceParent);
+ QModelIndex idxHost= sourceModel()->index(sourceRow,ServerListModel::HostColumn, sourceParent);
+
+ if(sourceModel()->data(idxName).toString().contains(filterStr_,Qt::CaseInsensitive) ||
+ sourceModel()->data(idxHost).toString().contains(filterStr_,Qt::CaseInsensitive))
+ return true;
+
+ return false;
+
+}
+
+
diff --git a/Viewer/src/ServerListDialog.hpp b/Viewer/src/ServerListDialog.hpp
new file mode 100644
index 0000000..2c62173
--- /dev/null
+++ b/Viewer/src/ServerListDialog.hpp
@@ -0,0 +1,168 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef SERVERLISTDIALOG_HPP_
+#define SERVERLISTDIALOG_HPP_
+
+#include <QAbstractItemModel>
+#include <QSortFilterProxyModel>
+
+#include "ui_ServerListDialog.h"
+#include "ui_ServerEditDialog.h"
+#include "ui_ServerAddDialog.h"
+
+class ServerFilter;
+class ServerItem;
+class ServerListModel;
+class ServerListFilterModel;
+
+class ServerDialogChecker
+{
+protected:
+ explicit ServerDialogChecker(QString txt) : errorText_(txt) {};
+
+ bool checkName(QString name,QString oriName=QString());
+ bool checkHost(QString host);
+ bool checkPort(QString port);
+ void error(QString msg);
+
+ QString errorText_;
+};
+
+
+class ServerEditDialog : public QDialog, private Ui::ServerEditDialog, public ServerDialogChecker
+{
+Q_OBJECT
+
+public:
+ ServerEditDialog(QString name,QString host, QString port,bool favourite,QWidget* parent=0);
+
+ QString name() const;
+ QString host() const;
+ QString port() const;
+ bool isFavourite() const;
+
+public Q_SLOTS:
+ void accept();
+
+private:
+ QString oriName_;
+
+};
+
+class ServerAddDialog : public QDialog, private Ui::ServerAddDialog, public ServerDialogChecker
+{
+Q_OBJECT
+
+public:
+ explicit ServerAddDialog(QWidget* parent=0);
+
+ QString name() const;
+ QString host() const;
+ QString port() const;
+ bool addToView() const;
+
+public Q_SLOTS:
+ void accept();
+};
+
+
+class ServerListDialog : public QDialog, protected Ui::ServerListDialog
+{
+Q_OBJECT
+
+public:
+ enum Mode {SelectionMode,ManageMode};
+
+ ServerListDialog(Mode,ServerFilter*,QWidget *parent=0);
+ ~ServerListDialog();
+
+public Q_SLOTS:
+ void accept();
+ void reject();
+
+protected Q_SLOTS:
+ void on_actionEdit_triggered();
+ void on_actionAdd_triggered();
+ void on_actionDuplicate_triggered();
+ void on_actionDelete_triggered();
+ void on_actionRescan_triggered();
+ void on_serverView_doubleClicked(const QModelIndex& index);
+ void on_actionFavourite_triggered(bool checked);
+ void slotItemSelected(const QModelIndex&,const QModelIndex&);
+ void slotItemClicked(const QModelIndex&);
+ void slotFilter(QString);
+ void slotFilterFavourite(bool);
+
+protected:
+ void closeEvent(QCloseEvent*);
+ void editItem(const QModelIndex& index);
+ void duplicateItem(const QModelIndex& index);
+ void addItem();
+ void removeItem(const QModelIndex& index);
+ void setFavouriteItem(const QModelIndex& index,bool b);
+ void checkActionState();
+ void writeSettings();
+ void readSettings();
+
+ ServerFilter* filter_;
+ ServerListModel* model_;
+ ServerListFilterModel* sortModel_;
+ Mode mode_;
+};
+
+
+class ServerListModel : public QAbstractItemModel
+{
+public:
+ explicit ServerListModel(ServerFilter*,QObject *parent=0);
+ ~ServerListModel();
+
+ int columnCount (const QModelIndex& parent = QModelIndex() ) const;
+ int rowCount (const QModelIndex& parent = QModelIndex() ) const;
+
+ QVariant data (const QModelIndex& , int role = Qt::DisplayRole ) const;
+ bool setData( const QModelIndex &, const QVariant &, int role = Qt::EditRole );
+ QVariant headerData(int,Qt::Orientation,int role = Qt::DisplayRole ) const;
+
+ QModelIndex index (int, int, const QModelIndex& parent = QModelIndex() ) const;
+ QModelIndex parent (const QModelIndex & ) const;
+ Qt::ItemFlags flags ( const QModelIndex & index) const;
+
+ void dataIsAboutToChange();
+ void dataChangeFinished();
+ ServerItem* indexToServer(const QModelIndex& index);
+
+ enum Columns {LoadColumn=0, NameColumn = 1, HostColumn =2, PortColumn =3, FavouriteColumn= 4, UseColumn=5};
+
+protected:
+ ServerFilter* filter_;
+ QPixmap favPix_;
+ QPixmap favEmptyPix_;
+ QFont loadFont_;
+};
+
+class ServerListFilterModel : public QSortFilterProxyModel
+{
+public:
+ explicit ServerListFilterModel(QObject *parent=0);
+ ~ServerListFilterModel() {};
+ void setFilterStr(QString);
+ void setFilterFavourite(bool b);
+
+protected:
+ bool filterAcceptsRow(int sourceRow,const QModelIndex &sourceParent) const;
+
+ QString filterStr_;
+ bool filterFavourite_;
+};
+
+#endif
+
diff --git a/Viewer/src/ServerListDialog.ui b/Viewer/src/ServerListDialog.ui
new file mode 100644
index 0000000..eef3472
--- /dev/null
+++ b/Viewer/src/ServerListDialog.ui
@@ -0,0 +1,290 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ServerListDialog</class>
+ <widget class="QDialog" name="ServerListDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>599</width>
+ <height>661</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Manage servers</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QLineEdit" name="filterLe_"/>
+ </item>
+ <item>
+ <widget class="QToolButton" name="filterFavTb_">
+ <property name="statusTip">
+ <string>Show favourite servers only</string>
+ </property>
+ <property name="text">
+ <string>Show favourite and loaded only</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/favourite.svg</normaloff>:/viewer/favourite.svg</iconset>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0">
+ <widget class="QTreeView" name="serverView">
+ <property name="contextMenuPolicy">
+ <enum>Qt::ActionsContextMenu</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QToolButton" name="editTb">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&Edit server</string>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ <property name="autoRaise">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="addTb">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&Add server</string>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ <property name="autoRaise">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="duplicateTb">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&Duplicate server</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="deleteTb">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&Remove server</string>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ <property name="autoRaise">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Close</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ <action name="actionAdd">
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/images/add.svg</normaloff>:/viewer/images/add.svg</iconset>
+ </property>
+ <property name="text">
+ <string>&Add server</string>
+ </property>
+ <property name="toolTip">
+ <string>Add server</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+N</string>
+ </property>
+ </action>
+ <action name="actionDelete">
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/images/close.svg</normaloff>:/viewer/images/close.svg</iconset>
+ </property>
+ <property name="text">
+ <string>&Remove server</string>
+ </property>
+ <property name="toolTip">
+ <string>Delete server</string>
+ </property>
+ <property name="shortcut">
+ <string>Del</string>
+ </property>
+ </action>
+ <action name="actionEdit">
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/images/configure.svg</normaloff>:/viewer/images/configure.svg</iconset>
+ </property>
+ <property name="text">
+ <string>&Edit server </string>
+ </property>
+ <property name="toolTip">
+ <string>Edit server properties</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+E</string>
+ </property>
+ </action>
+ <action name="actionRescan">
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/images/reload.svg</normaloff>:/viewer/images/reload.svg</iconset>
+ </property>
+ <property name="text">
+ <string>Rescan</string>
+ </property>
+ <property name="toolTip">
+ <string>Rescan network for servers</string>
+ </property>
+ </action>
+ <action name="actionDuplicate">
+ <property name="text">
+ <string>Du&plicate server</string>
+ </property>
+ <property name="toolTip">
+ <string>Duplicate server</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+D</string>
+ </property>
+ </action>
+ <action name="actionFavourite">
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/favourite.svg</normaloff>:/viewer/favourite.svg</iconset>
+ </property>
+ <property name="text">
+ <string>Set as &favourite</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+B</string>
+ </property>
+ </action>
+ <zorder>buttonBox</zorder>
+ <zorder></zorder>
+ </widget>
+ <resources>
+ <include location="viewer.qrc"/>
+ </resources>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>ServerListDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>ServerListDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/Viewer/src/ServerObserver.hpp b/Viewer/src/ServerObserver.hpp
new file mode 100644
index 0000000..091c2fe
--- /dev/null
+++ b/Viewer/src/ServerObserver.hpp
@@ -0,0 +1,37 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef SERVEROBSERVER_HPP_
+#define SERVEROBSERVER_HPP_
+
+#include <vector>
+#include "Aspect.hpp"
+
+class ServerHandler;
+class VServerChange;
+
+class ServerObserver
+{
+public:
+ ServerObserver() {}
+ virtual ~ServerObserver() {}
+ virtual void notifyDefsChanged(ServerHandler* server, const std::vector<ecf::Aspect::Type>& a)=0;
+ virtual void notifyServerDelete(ServerHandler* server)=0;
+ virtual void notifyBeginServerClear(ServerHandler* server) {}
+ virtual void notifyEndServerClear(ServerHandler* server) {}
+ virtual void notifyBeginServerScan(ServerHandler* server,const VServerChange&) {}
+ virtual void notifyEndServerScan(ServerHandler* server) {}
+ virtual void notifyServerConnectState(ServerHandler* server) {}
+ virtual void notifyServerActivityChanged(ServerHandler* server) {}
+ virtual void notifyServerSuiteFilterChanged(ServerHandler* server) {}
+ virtual void notifyEndServerSync(ServerHandler* server) {}
+};
+
+
+#endif
diff --git a/Viewer/src/ServerSettingsItemWidget.cpp b/Viewer/src/ServerSettingsItemWidget.cpp
new file mode 100644
index 0000000..52d8111
--- /dev/null
+++ b/Viewer/src/ServerSettingsItemWidget.cpp
@@ -0,0 +1,129 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "ServerSettingsItemWidget.hpp"
+
+#include "Node.hpp"
+#include "ServerHandler.hpp"
+#include "VNode.hpp"
+
+#include <QPushButton>
+
+#include <assert.h>
+
+//========================================================
+//
+// ServerSettingsItemWidget
+//
+//========================================================
+
+ServerSettingsItemWidget::ServerSettingsItemWidget(QWidget *parent) : QWidget(parent)
+{
+ setupUi(this);
+
+ connect(buttonBox_,SIGNAL(clicked(QAbstractButton*)),
+ this,SLOT(slotClicked(QAbstractButton *)));
+
+ QPushButton* applyPb=buttonBox_->button(QDialogButtonBox::Apply);
+ assert(applyPb);
+ applyPb->setEnabled(false);
+
+ connect(editor_,SIGNAL(changed()),
+ this,SLOT(slotEditorChanged()));
+}
+
+QWidget* ServerSettingsItemWidget::realWidget()
+{
+ return this;
+}
+
+void ServerSettingsItemWidget::reload(VInfo_ptr info)
+{
+ assert(active_);
+
+ clearContents();
+
+ info_=info;
+
+ if(info_ && info_->isServer() && info_->server())
+ {
+ editor_->edit(info_->server()->conf()->guiProp(),
+ QString::fromStdString(info_->server()->name()));
+ }
+ else
+ {
+
+ }
+}
+
+void ServerSettingsItemWidget::clearContents()
+{
+ InfoPanelItem::clear();
+ //TODO: properly set gui state
+}
+
+void ServerSettingsItemWidget::updateState(const FlagSet<ChangeFlag>& flags)
+{
+ if(flags.isSet(ActiveChanged))
+ {
+ if(active_)
+ {
+ editor_->setEnabled(true);
+ buttonBox_->setEnabled(true);
+ }
+ }
+
+ if(flags.isSet(SuspendedChanged))
+ {
+ if(active_)
+ {
+ if(suspended_)
+ {
+ editor_->setEnabled(false);
+ buttonBox_->setEnabled(false);
+ }
+ else
+ {
+ editor_->setEnabled(true);
+ buttonBox_->setEnabled(true);
+ }
+ }
+ }
+
+}
+
+void ServerSettingsItemWidget::slotEditorChanged()
+{
+ QPushButton* applyPb=buttonBox_->button(QDialogButtonBox::Apply);
+ assert(applyPb);
+ applyPb->setEnabled(true);
+}
+
+void ServerSettingsItemWidget::slotClicked(QAbstractButton* button)
+{
+ if(!active_)
+ return;
+
+ switch(buttonBox_->standardButton(button))
+ {
+ case QDialogButtonBox::Apply:
+ {
+ if(editor_->applyChange())
+ {
+ if(info_ && info_->server())
+ info_->server()->conf()->saveSettings();
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static InfoPanelItemMaker<ServerSettingsItemWidget> maker1("server_settings");
diff --git a/Viewer/src/ServerSettingsItemWidget.hpp b/Viewer/src/ServerSettingsItemWidget.hpp
new file mode 100644
index 0000000..f23e0ce
--- /dev/null
+++ b/Viewer/src/ServerSettingsItemWidget.hpp
@@ -0,0 +1,49 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef SERVERSETTINGSITEMWIDGET_HPP_
+#define SERVERSETTINGSITEMWIDGET_HPP_
+
+#include <QWidget>
+
+#include "InfoPanelItem.hpp"
+#include "PropertyEditor.hpp"
+#include "VInfo.hpp"
+
+#include "ui_ServerSettingsItemWidget.h"
+
+class QAbstractButton;
+
+class VNode;
+
+class ServerSettingsItemWidget : public QWidget, public InfoPanelItem, protected Ui::ServerSettingsItemWidget
+{
+Q_OBJECT
+
+public:
+ explicit ServerSettingsItemWidget(QWidget *parent=0);
+
+ void reload(VInfo_ptr);
+ QWidget* realWidget();
+ void clearContents();
+
+ void nodeChanged(const VNode*, const std::vector<ecf::Aspect::Type>&) {}
+ void defsChanged(const std::vector<ecf::Aspect::Type>&) {}
+
+protected Q_SLOTS:
+ void slotClicked(QAbstractButton* button);
+ void slotEditorChanged();
+
+protected:
+ void updateState(const ChangeFlags&);
+};
+
+#endif
+
diff --git a/Viewer/src/ServerSettingsItemWidget.ui b/Viewer/src/ServerSettingsItemWidget.ui
new file mode 100644
index 0000000..2cd6651
--- /dev/null
+++ b/Viewer/src/ServerSettingsItemWidget.ui
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ServerSettingsItemWidget</class>
+ <widget class="QWidget" name="ServerSettingsItemWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>579</width>
+ <height>594</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="PropertyEditor" name="editor_" native="true"/>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox_">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Apply|QDialogButtonBox::Reset</set>
+ </property>
+ <property name="centerButtons">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>PropertyEditor</class>
+ <extends>QWidget</extends>
+ <header location="global">PropertyEditor.hpp</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Viewer/src/ServerWidget.ui b/Viewer/src/ServerWidget.ui
new file mode 100644
index 0000000..9d996c6
--- /dev/null
+++ b/Viewer/src/ServerWidget.ui
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ServerWidget</class>
+ <widget class="QWidget" name="ServerWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>413</width>
+ <height>529</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QToolButton" name="editTb">
+ <property name="toolTip">
+ <string>Edit</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/images/configure.svg</normaloff>:/viewer/images/configure.svg</iconset>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="addTb">
+ <property name="toolTip">
+ <string>Add server</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/images/add.svg</normaloff>:/viewer/images/add.svg</iconset>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="deleteTb">
+ <property name="toolTip">
+ <string>Delete server</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/images/close.svg</normaloff>:/viewer/images/close.svg</iconset>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="rescanTb">
+ <property name="toolTip">
+ <string>Rescan network</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/images/reload.svg</normaloff>:/viewer/images/reload.svg</iconset>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QTreeView" name="serverView">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="rootIsDecorated">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="viewer.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/Viewer/src/SessionDialog.cpp b/Viewer/src/SessionDialog.cpp
new file mode 100644
index 0000000..0ba0ec0
--- /dev/null
+++ b/Viewer/src/SessionDialog.cpp
@@ -0,0 +1,262 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include <assert.h>
+#include <QMessageBox>
+
+
+#include "SessionDialog.hpp"
+#include "ui_SessionDialog.h"
+
+#include "DirectoryHandler.hpp"
+#include "SessionRenameDialog.hpp"
+
+
+SessionDialog::SessionDialog(QWidget *parent) : QDialog(parent)
+{
+ //ui->setupUi(this);
+ setupUi(this);
+
+ refreshListOfSavedSessions();
+
+
+ // what was saved last time?
+ std::string lastSessionName = SessionHandler::instance()->lastSessionName();
+ int index = SessionHandler::instance()->indexFromName(lastSessionName);
+ if (index != -1)
+ savedSessionsList_->setCurrentRow(index); // select this one in the table
+
+
+ if (SessionHandler::instance()->loadLastSessionAtStartup())
+ restoreLastSessionCb_->setCheckState(Qt::Checked);
+ else
+ restoreLastSessionCb_->setCheckState(Qt::Unchecked);
+
+
+ newButton_->setVisible(false); // XXX TODO: enable New Session functionality
+
+ // ensure the correct state of the Save button
+ on_sessionNameEdit__textChanged();
+ setButtonsEnabledStatus();
+}
+
+SessionDialog::~SessionDialog()
+{
+ //delete ui;
+}
+
+void SessionDialog::refreshListOfSavedSessions()
+{
+
+ //sessionsTable_->clearContents();
+ savedSessionsList_->clear();
+
+ // get the list of existing sessions
+ int numSessions = SessionHandler::instance()->numSessions();
+ for (int i = 0; i < numSessions; i++)
+ {
+ SessionItem *s = SessionHandler::instance()->sessionFromIndex(i);
+ addSessionToTable(s);
+ }
+}
+
+void SessionDialog::addSessionToTable(SessionItem *s)
+{
+ QListWidgetItem *item = new QListWidgetItem(QString::fromStdString(s->name()));
+ //item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
+ //item->setCheckState(Qt::Unchecked);
+ savedSessionsList_->addItem(item);
+/*
+ int lastRow = sessionsTable_->rowCount()-1;
+ sessionsTable_->insertRow(lastRow+1);
+
+ QTableWidgetItem *nameItem = new QTableWidgetItem(QString::fromStdString(s->name()));
+ sessionsTable_->setItem(lastRow+1, 0, nameItem);
+*/
+}
+
+
+std::string SessionDialog::selectedSessionName()
+{
+ QListWidgetItem *ci = savedSessionsList_->currentItem();
+ if (ci)
+ return ci->text().toStdString();
+ else
+ return "";
+}
+
+
+
+// ---------------------------------------------------------------------------------------------
+// setButtonsEnabledStatus
+// - checks which session has been chosen and enables/disables the action buttons appropriately
+// ---------------------------------------------------------------------------------------------
+
+void SessionDialog::setButtonsEnabledStatus()
+{
+ std::string name = selectedSessionName();
+
+ // if somehow no session is selected, then we need different logic
+ if (name.empty())
+ {
+ cloneButton_ ->setEnabled(false);
+ deleteButton_ ->setEnabled(false);
+ renameButton_ ->setEnabled(false);
+ switchToButton_->setEnabled(false);
+ }
+ else
+ {
+ // the default session is special and cannot be deleted or renamed
+ bool enable = (name == "default") ? false : true;
+ deleteButton_ ->setEnabled(enable);
+ renameButton_ ->setEnabled(enable);
+ switchToButton_->setEnabled(true); // always available for a valid session
+ cloneButton_ ->setEnabled(true);
+ }
+}
+
+
+bool SessionDialog::validSaveName(const std::string &name)
+{
+/*
+ QString boxName(QObject::tr("Save session"));
+ // name empty?
+ if (name.empty())
+ {
+ QMessageBox::critical(0,boxName, tr("Please enter a name for the session"));
+ return false;
+ }
+
+
+ // is there already a session with this name?
+ bool sessionWithThisName = (SessionHandler::instance()->find(name) != NULL);
+
+ if (sessionWithThisName)
+ {
+ QMessageBox::critical(0,boxName, tr("A session with that name already exists - please choose another name"));
+ return false;
+ }
+ else
+ {
+ return true;
+ }*/
+}
+
+void SessionDialog::on_sessionNameEdit__textChanged()
+{
+ // only allow to save a non-empty session name
+// saveButton_->setEnabled(!sessionNameEdit_->text().isEmpty());
+}
+
+void SessionDialog::on_savedSessionsList__currentRowChanged(int currentRow)
+{
+ setButtonsEnabledStatus();
+}
+
+void SessionDialog::on_cloneButton__clicked()
+{
+ std::string sessionName = selectedSessionName();
+ assert(!sessionName.empty()); // it should not be possible for the name to be empty
+
+ SessionRenameDialog renameDialog;
+ renameDialog.exec();
+
+ int result = renameDialog.result();
+ if (result == QDialog::Accepted)
+ {
+ std::string newName = renameDialog.newName();
+ SessionHandler::instance()->copySession(sessionName, newName);
+ refreshListOfSavedSessions();
+ }
+}
+
+void SessionDialog::on_deleteButton__clicked()
+{
+ std::string sessionName = selectedSessionName();
+ assert(!sessionName.empty()); // it should not be possible for the name to be empty
+
+ QString message = tr("Are you sure that you want to delete the session '") + QString::fromStdString(sessionName) + tr("'' from disk?");
+ if(QMessageBox::question(0,tr("Confirm: remove session"),
+ message,
+ QMessageBox::Ok | QMessageBox::Cancel,QMessageBox::Cancel) == QMessageBox::Ok)
+ {
+ SessionHandler::instance()->remove(sessionName);
+ refreshListOfSavedSessions();
+ }
+}
+
+
+void SessionDialog::on_renameButton__clicked()
+{
+ std::string sessionName = selectedSessionName();
+ assert(!sessionName.empty()); // it should not be possible for the name to be empty
+
+ SessionItem *item = SessionHandler::instance()->find(sessionName);
+ assert(item); // it should not be possible for the name to be empty
+
+ SessionRenameDialog renameDialog;
+ renameDialog.exec();
+
+ int result = renameDialog.result();
+ if (result == QDialog::Accepted)
+ {
+ std::string newName = renameDialog.newName();
+ SessionHandler::instance()->rename(item, newName);
+ refreshListOfSavedSessions();
+ }
+}
+
+
+void SessionDialog::on_switchToButton__clicked()
+{
+ std::string sessionName = selectedSessionName();
+ assert(!sessionName.empty()); // it should not be possible for the name to be empty
+
+ SessionItem *item = SessionHandler::instance()->find(sessionName);
+ assert(item); // it should not be possible for the name to be empty
+
+ SessionHandler::instance()->current(item); // set this session as the current one
+
+ if (restoreLastSessionCb_->checkState() == Qt::Checked) // save details of the selected session?
+ SessionHandler::instance()->saveLastSessionName();
+ else
+ SessionHandler::instance()->removeLastSessionName(); // no, so we can delete the file
+
+ accept(); // close the dialogue and continue loading the main user interface
+}
+
+
+void SessionDialog::on_saveButton__clicked()
+{
+/*
+ std::string name = sessionNameEdit_->text().toStdString();
+
+ if (validSaveName(name))
+ {
+ SessionItem* newSession = SessionHandler::instance()->copySession(SessionHandler::instance()->current(), name);
+ if (newSession)
+ {
+ //SessionHandler::instance()->add(name);
+ refreshListOfSavedSessions();
+ SessionHandler::instance()->current(newSession);
+ QMessageBox::information(0,tr("Session"), tr("Session saved"));
+ }
+ else
+ {
+ QMessageBox::critical(0,tr("Session"), tr("Failed to save session"));
+ }
+ close();
+ }*/
+}
+
+// called when the user clicks the Save button
+//void SaveSessionAsDialog::accept()
+//{
+//
+//}
diff --git a/Viewer/src/SessionDialog.hpp b/Viewer/src/SessionDialog.hpp
new file mode 100644
index 0000000..514859a
--- /dev/null
+++ b/Viewer/src/SessionDialog.hpp
@@ -0,0 +1,48 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef SESSIONDIALOG_HPP
+#define SESSIONDIALOG_HPP
+
+#include <QDialog>
+#include "ui_SessionDialog.h"
+
+#include "SessionHandler.hpp"
+
+namespace Ui {
+class SessionDialog;
+}
+
+class SessionDialog : public QDialog, protected Ui::SessionDialog
+{
+ Q_OBJECT
+
+public:
+ explicit SessionDialog(QWidget *parent = 0);
+ ~SessionDialog();
+
+public Q_SLOTS:
+ void on_saveButton__clicked();
+ void on_sessionNameEdit__textChanged();
+ void on_savedSessionsList__currentRowChanged(int currentRow);
+ void on_cloneButton__clicked();
+ void on_deleteButton__clicked();
+ void on_renameButton__clicked();
+ void on_switchToButton__clicked();
+
+private:
+ //Ui::SaveSessionAsDialog *ui;
+ void addSessionToTable(SessionItem *s);
+ bool validSaveName(const std::string &name);
+ void refreshListOfSavedSessions();
+ void setButtonsEnabledStatus();
+ std::string selectedSessionName();
+};
+
+#endif // SESSIONDIALOG_HPP
diff --git a/Viewer/src/SessionDialog.ui b/Viewer/src/SessionDialog.ui
new file mode 100644
index 0000000..eb60240
--- /dev/null
+++ b/Viewer/src/SessionDialog.ui
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SessionDialog</class>
+ <widget class="QDialog" name="SessionDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>ecFlowUI Session Manager</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QListWidget" name="savedSessionsList_"/>
+ </item>
+ <item>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QPushButton" name="newButton_">
+ <property name="text">
+ <string>New</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QPushButton" name="deleteButton_">
+ <property name="text">
+ <string>Delete</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QPushButton" name="renameButton_">
+ <property name="text">
+ <string>Rename</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="0">
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="0">
+ <widget class="QPushButton" name="cloneButton_">
+ <property name="text">
+ <string>Clone</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="restoreLastSessionCb_">
+ <property name="text">
+ <string>Use this session without asking at startup</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QPushButton" name="switchToButton_">
+ <property name="text">
+ <string>Start with this session</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>SessionDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>SessionDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/Viewer/src/SessionHandler.cpp b/Viewer/src/SessionHandler.cpp
new file mode 100644
index 0000000..7a30ca2
--- /dev/null
+++ b/Viewer/src/SessionHandler.cpp
@@ -0,0 +1,364 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include <algorithm>
+#include <assert.h>
+#include <fstream>
+
+#include "SessionHandler.hpp"
+#include "DirectoryHandler.hpp"
+#include "Str.hpp"
+#include "UserMessage.hpp"
+
+
+SessionHandler* SessionHandler::instance_=0;
+
+
+SessionItem::SessionItem(const std::string& name) :
+ name_(name)
+{
+ checkDir();
+}
+
+void SessionItem::checkDir()
+{
+ dirPath_ = SessionHandler::sessionDirName(name_);
+ DirectoryHandler::createDir(dirPath_);
+
+ qtPath_= SessionHandler::sessionQtDirName(name_);
+ DirectoryHandler::createDir(qtPath_);
+}
+
+std::string SessionItem::sessionFile() const
+{
+ return DirectoryHandler::concatenate(dirPath_, "session.json");
+}
+
+std::string SessionItem::windowFile() const
+{
+ return DirectoryHandler::concatenate(dirPath_, "window.conf");
+}
+
+std::string SessionItem::settingsFile() const
+{
+ return DirectoryHandler::concatenate(dirPath_, "settings.json");
+}
+
+std::string SessionItem::recentCustomCommandsFile() const
+{
+ return DirectoryHandler::concatenate(dirPath_, "recent_custom_commands.json");
+}
+
+std::string SessionItem::savedCustomCommandsFile() const
+{
+ return DirectoryHandler::concatenate(dirPath_, "saved_custom_commands.json");
+}
+
+std::string SessionItem::serverFile(const std::string& serverName) const
+{
+ return DirectoryHandler::concatenate(dirPath_, serverName + ".conf.json");
+}
+
+std::string SessionItem::qtDir() const
+{
+ return qtPath_;
+}
+
+std::string SessionItem::qtSettingsFile(const std::string name) const
+{
+ return DirectoryHandler::concatenate(qtPath_, name + ".conf");
+}
+
+//=================================================
+//
+// SessionHandler
+//
+//=================================================
+
+SessionHandler::SessionHandler() :
+ current_(0)
+{
+ //The default must always be exist!
+ current_=add(defaultSessionName());
+ loadedLastSessionName_ = false;
+
+ readSessionListFromDisk();
+ readLastSessionName();
+}
+
+SessionHandler* SessionHandler::instance()
+{
+ if(!instance_)
+ {
+ instance_=new SessionHandler();
+ }
+
+ return instance_;
+}
+
+std::string SessionHandler::sessionDirName(const std::string &sessionName)
+{
+ return DirectoryHandler::concatenate(DirectoryHandler::configDir(), sessionName + ".session");
+}
+
+std::string SessionHandler::sessionQtDirName(const std::string &sessionName)
+{
+ std::string basedir = sessionDirName(sessionName);
+ return DirectoryHandler::concatenate(basedir, "qt");
+}
+
+SessionItem* SessionHandler::find(const std::string& name)
+{
+ for(std::vector<SessionItem*>::const_iterator it=sessions_.begin(); it != sessions_.end(); ++it)
+ {
+ if((*it)->name() == name)
+ return *it;
+ }
+ return NULL;
+
+}
+
+
+// returns -1 if the session name is not found
+int SessionHandler::indexFromName(const std::string& name)
+{
+ int n = 0;
+ for(std::vector<SessionItem*>::const_iterator it=sessions_.begin(); it != sessions_.end(); ++it)
+ {
+ if((*it)->name() == name)
+ return n;
+ n++;
+ }
+ return -1;
+}
+
+void SessionHandler::readSessionListFromDisk()
+{
+ // get the list of existing sessions (by listing the directories)
+ std::string configDir = DirectoryHandler::configDir();
+ std::string filter = ".*\\.session";
+ std::vector<std::string> dirs;
+ DirectoryHandler::findDirs(configDir, filter, dirs);
+
+ // add each session to our list (but remove the .session first)
+ for(std::vector<std::string>::const_iterator it=dirs.begin(); it != dirs.end(); ++it)
+ {
+ std::string dirName = (*it);
+ std::string toRemove = ".session";
+ std::string toReplaceWith = "";
+ ecf::Str::replace(dirName, toRemove, toReplaceWith);
+ add(dirName);
+ }
+}
+
+bool SessionHandler::loadLastSessionAtStartup()
+{
+ // if there was a last session file, then it means the user wanted to load at startup
+ return loadedLastSessionName_;
+}
+
+
+
+SessionItem* SessionHandler::add(const std::string& name)
+{
+ // only add if not already there
+ if (find(name) == NULL)
+ {
+ SessionItem *item=new SessionItem(name);
+ sessions_.push_back(item);
+ return item;
+ }
+ else
+ return NULL;
+}
+
+void SessionHandler::remove(const std::string& sessionName)
+{
+ SessionItem *session = find(sessionName);
+ assert(session);
+
+ remove(session);
+}
+
+void SessionHandler::remove(SessionItem* session)
+{
+ std::vector<SessionItem*>::iterator it = std::find(sessions_.begin(), sessions_.end(), session);
+ assert(it != sessions_.end()); // session was not found - should not be possible
+
+
+ // remove the session's directory
+ std::string errorMessage;
+ bool ok = DirectoryHandler::removeDir(sessionDirName(session->name()), errorMessage);
+
+ if (ok)
+ {
+ // remove it from our list
+ sessions_.erase(it);
+ }
+ else
+ {
+ UserMessage::message(UserMessage::ERROR, true, errorMessage);
+ }
+}
+
+
+void SessionHandler::rename(SessionItem* item, const std::string& newName)
+{
+ std::string errorMessage;
+ bool ok = DirectoryHandler::renameDir(sessionDirName(item->name()), sessionDirName(newName), errorMessage);
+
+ if (ok)
+ {
+ item->name(newName);
+ }
+ else
+ {
+ UserMessage::message(UserMessage::ERROR, true, errorMessage);
+ }
+}
+
+
+void SessionHandler::current(SessionItem* item)
+{
+ if(std::find(sessions_.begin(),sessions_.end(),item) != sessions_.end())
+ {
+ current_=item;
+ load();
+ }
+}
+
+
+SessionItem* SessionHandler::current()
+{
+ return current_;
+}
+
+void SessionHandler::save()
+{
+ if(current_)
+ {
+ //current_->save();
+ }
+}
+
+void SessionHandler::load()
+{
+
+}
+
+
+bool SessionHandler::requestStartupViaSessionManager()
+{
+ char *sm = getenv("ECFUI_SESSION_MANAGER");
+ if (sm)
+ return true;
+ else
+ return false;
+}
+
+
+void SessionHandler::saveLastSessionName()
+{
+ std::string configDir = DirectoryHandler::configDir();
+ std::string lastSessionFilename = DirectoryHandler::concatenate(configDir, "last_session.txt");
+
+ // open the last_session.txt file and try to read it
+ std::ofstream out(lastSessionFilename.c_str());
+
+ if (out.good())
+ {
+ // the file is a one-line file containing the name of the current session
+ std::string line = current()->name();
+ out << line << std::endl;
+ }
+}
+
+void SessionHandler::removeLastSessionName()
+{
+ std::string configDir = DirectoryHandler::configDir();
+ std::string lastSessionFilename = DirectoryHandler::concatenate(configDir, "last_session.txt");
+
+ std::string errorMessage;
+ bool ok = DirectoryHandler::removeFile(lastSessionFilename, errorMessage);
+
+ if (!ok)
+ {
+ UserMessage::message(UserMessage::ERROR, true, errorMessage);
+ }
+}
+
+
+void SessionHandler::readLastSessionName()
+{
+ std::string configDir = DirectoryHandler::configDir();
+ std::string lastSessionFilename = DirectoryHandler::concatenate(configDir, "last_session.txt");
+
+ // open the last_session.txt file and try to read it
+ std::ifstream in(lastSessionFilename.c_str());
+
+ if (in.good())
+ {
+ // the file is a one-line file containing the name of the session we want
+ std::string line;
+ if (getline(in, line))
+ {
+ loadedLastSessionName_ = true;
+ lastSessionName_ = line;
+ }
+ else
+ lastSessionName_ = defaultSessionName();
+ }
+ else
+ {
+ // could not read the file, so just use the default
+ lastSessionName_ = defaultSessionName();
+ }
+
+
+ // set this session as the current one if it exists
+ SessionItem *item = find(lastSessionName_);
+ if (item)
+ {
+ current(item);
+ }
+ else
+ {
+ lastSessionName_ = defaultSessionName(); // the last session file contained the name of a non-existant session
+ }
+}
+
+
+SessionItem *SessionHandler::copySession(SessionItem* source, std::string &destName)
+{
+ // the main work is to make a copy of the source session's directory (recursively)
+ std::string errorMessage;
+ std::string sourceSessionDir = sessionDirName(source->name());
+ std::string destSessionDir = sessionDirName(destName);
+ bool ok = DirectoryHandler::copyDir(sourceSessionDir, destSessionDir, errorMessage);
+ if (ok)
+ {
+ // add it to our list
+ SessionItem *newItem = add(destName);
+ return newItem;
+ }
+ else
+ {
+ UserMessage::message(UserMessage::ERROR, true, errorMessage);
+ return NULL;
+ }
+}
+
+SessionItem *SessionHandler::copySession(std::string &source, std::string &destName)
+{
+ SessionItem *sourceSession = find(source);
+ assert(sourceSession);
+
+ copySession(sourceSession, destName);
+}
+
diff --git a/Viewer/src/SessionHandler.hpp b/Viewer/src/SessionHandler.hpp
new file mode 100644
index 0000000..655f346
--- /dev/null
+++ b/Viewer/src/SessionHandler.hpp
@@ -0,0 +1,87 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef SESSIONHANDLER_HPP_
+#define SESSIONHANDLER_HPP_
+
+#include <string>
+#include <vector>
+
+class SessionItem
+{
+public:
+ explicit SessionItem(const std::string&);
+ virtual ~SessionItem() {}
+
+ void name(const std::string& name) {name_ = name;}
+ const std::string& name() const {return name_;}
+
+ std::string sessionFile() const;
+ std::string windowFile() const;
+ std::string settingsFile() const ;
+ std::string recentCustomCommandsFile() const ;
+ std::string savedCustomCommandsFile() const ;
+ std::string serverFile(const std::string& serverName) const;
+ std::string qtDir() const;
+ std::string qtSettingsFile(const std::string name) const;
+
+protected:
+ void checkDir();
+
+ std::string name_;
+ std::string dirPath_;
+ std::string qtPath_;
+};
+
+class SessionHandler
+{
+public:
+ SessionHandler();
+
+ SessionItem* add(const std::string&);
+ void remove(const std::string&);
+ void remove(SessionItem*);
+ void rename(SessionItem*, const std::string&);
+ void current(SessionItem*);
+ SessionItem* current();
+ void save();
+ void load();
+ int numSessions() {return sessions_.size();};
+ SessionItem *find(const std::string&);
+ int indexFromName(const std::string&);
+ SessionItem *sessionFromIndex(int i) {return sessions_[i];};
+ SessionItem *copySession(SessionItem* source, std::string &destName);
+ SessionItem *copySession(std::string &source, std::string &destName);
+ void saveLastSessionName();
+ void removeLastSessionName();
+ bool loadLastSessionAtStartup();
+ std::string lastSessionName() {return lastSessionName_;};
+
+
+ const std::vector<SessionItem*>& sessions() const {return sessions_;}
+
+ static std::string sessionDirName(const std::string &sessionName); // static because they are called from the constructor
+ static std::string sessionQtDirName(const std::string &sessionName); // static because they are called from the constructor
+ static SessionHandler* instance();
+ static bool requestStartupViaSessionManager();
+
+protected:
+ void readSessionListFromDisk();
+ std::string defaultSessionName() {return "default";};
+ void readLastSessionName();
+
+ static SessionHandler* instance_;
+
+ std::vector<SessionItem*> sessions_;
+ SessionItem* current_;
+ bool loadedLastSessionName_;
+ std::string lastSessionName_;
+};
+
+#endif
diff --git a/Viewer/src/SessionRenameDialog.cpp b/Viewer/src/SessionRenameDialog.cpp
new file mode 100644
index 0000000..26a3821
--- /dev/null
+++ b/Viewer/src/SessionRenameDialog.cpp
@@ -0,0 +1,49 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include <QMessageBox>
+
+#include "SessionHandler.hpp"
+
+#include "SessionRenameDialog.hpp"
+#include "ui_SessionRenameDialog.h"
+
+SessionRenameDialog::SessionRenameDialog(QWidget *parent) : QDialog(parent)
+{
+ setupUi(this);
+}
+
+SessionRenameDialog::~SessionRenameDialog()
+{
+}
+
+
+void SessionRenameDialog::on_buttonBox__accepted()
+{
+ // store the name
+ newName_ = nameEdit_->text().toStdString();
+
+
+ // check it does not clash with an existing session name
+ if (SessionHandler::instance()->find(newName_))
+ {
+ QMessageBox::critical(0,tr("Rename session"), tr("A session with that name already exists - please choose another name"));
+ }
+ else
+ {
+ // close the dialogue
+ accept();
+ }
+}
+
+void SessionRenameDialog::on_buttonBox__rejected()
+{
+ // close the dialogue
+ reject();
+}
diff --git a/Viewer/src/SessionRenameDialog.hpp b/Viewer/src/SessionRenameDialog.hpp
new file mode 100644
index 0000000..708b89e
--- /dev/null
+++ b/Viewer/src/SessionRenameDialog.hpp
@@ -0,0 +1,40 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef SESSIONRENAMEDIALOG_HPP
+#define SESSIONRENAMEDIALOG_HPP
+
+#include <QDialog>
+#include "ui_SessionRenameDialog.h"
+
+#include "SessionHandler.hpp"
+
+namespace Ui {
+class SessionRenameDialog;
+}
+
+class SessionRenameDialog : public QDialog, protected Ui::SessionRenameDialog
+{
+ Q_OBJECT
+
+public:
+ explicit SessionRenameDialog(QWidget *parent = 0);
+ ~SessionRenameDialog();
+
+ std::string newName() {return newName_;};
+
+public Q_SLOTS:
+ void on_buttonBox__accepted();
+ void on_buttonBox__rejected();
+
+private:
+ std::string newName_;
+ };
+
+#endif // SESSIONRENAMEDIALOG_HPP
diff --git a/Viewer/src/SessionRenameDialog.ui b/Viewer/src/SessionRenameDialog.ui
new file mode 100644
index 0000000..a82d3c8
--- /dev/null
+++ b/Viewer/src/SessionRenameDialog.ui
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SessionRenameDialog</class>
+ <widget class="QDialog" name="SessionRenameDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>284</width>
+ <height>129</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Add variable</string>
+ </property>
+ <property name="modal">
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QLabel" name="infoLabel_">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>New name:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_1">
+ <property name="text">
+ <string>&Name:</string>
+ </property>
+ <property name="buddy">
+ <cstring>label_1</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="nameEdit_">
+ <property name="readOnly">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox_">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Viewer/src/Sound.cpp b/Viewer/src/Sound.cpp
new file mode 100644
index 0000000..677a370
--- /dev/null
+++ b/Viewer/src/Sound.cpp
@@ -0,0 +1,158 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "Sound.hpp"
+
+#include "DirectoryHandler.hpp"
+#include "UserMessage.hpp"
+#include "VConfig.hpp"
+#include "VConfigLoader.hpp"
+#include "VProperty.hpp"
+
+#include <assert.h>
+#include <stdlib.h>
+
+//#ifdef ECFLOW_QT5
+//#include <QSoundEffect>
+//#endif
+
+
+#include <boost/algorithm/string/replace.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/regex.hpp>
+
+Sound* Sound::instance_=NULL;
+
+
+/*
+ if(sound)
+ {
+ const char *soundCmd = "play -q /usr/share/xemacs/xemacs-packages/etc/sounds/boing.wav";
+ if (system(soundCmd))
+ UserMessage::message(UserMessage::DBG, false,"ChangeNotify:add() could not play sound alert");
+*/
+//#ifdef ECFLOW_QT5
+// QSoundEffect effect(dialog_);
+// effect.setSource(QUrl::fromLocalFile("file:/usr/share/xemacs/xemacs-packages/etc/sounds/boing.wav"));
+// effect.setLoopCount(1);
+// effect.setVolume(0.25f);
+// effect.play();
+//#endif
+
+
+Sound::Sound() :
+ prevPlayedAt_(0),
+ delay_(2),
+ prop_(NULL)
+{
+ formats_=".+\\.(wav|mp3|ogg|oga)";
+
+ sysDir_=DirectoryHandler::concatenate(DirectoryHandler::etcDir(), "sounds");
+
+ std::vector<std::string> res;
+
+ DirectoryHandler::findFiles(sysDir_,formats_,res);
+
+ for(unsigned int i=0; i < res.size(); i++)
+ {
+ sysSounds_.push_back(res.at(i));
+ }
+}
+
+Sound* Sound::instance()
+{
+ if(!instance_)
+ instance_=new Sound();
+
+ return instance_;
+}
+
+void Sound::playSystem(const std::string& fName,int loopCount)
+{
+ std::string fullName=DirectoryHandler::concatenate(sysDir_, fName);
+ play(fullName,loopCount);
+}
+
+void Sound::play(const std::string& fName,int loopCount)
+{
+ assert(loopCount < 6);
+
+ time_t t=time(NULL);
+ if(t < prevPlayedAt_+delay_)
+ return;
+
+ if(currentCmd_.empty())
+ {
+
+ }
+ else
+ {
+ std::string cmd=currentCmd_;
+ boost::replace_first(cmd,"%FILE%",fName);
+ boost::replace_first(cmd,"%REPEAT%",boost::lexical_cast<std::string>(loopCount-1));
+ if(system(cmd.c_str()))
+ {
+ UserMessage::message(UserMessage::DBG, false,"Sound::play() could not play sound alert. Command: " + cmd);
+ }
+ }
+
+ prevPlayedAt_=time(NULL);
+}
+
+void Sound::setCurrentPlayer(const std::string& current)
+{
+ std::map<std::string,std::string>::const_iterator it=players_.find(current);
+ if(it != players_.end())
+ {
+ currentPlayer_=it->first;
+ currentCmd_=it->second;
+ }
+ else
+ assert(0);
+}
+
+bool Sound::isSoundFile(const std::string& fName) const
+{
+ const boost::regex expr(formats_);
+ boost::smatch what;
+ if(boost::regex_match(fName, what,expr))
+ return true;
+ return false;
+}
+
+void Sound::load(VProperty* prop)
+{
+ UserMessage::message(UserMessage::DBG, false,"Sound:load() -- > begin");
+
+ if(prop->name() != "sound")
+ {
+ UserMessage::message(UserMessage::ERROR, false,"Sound:load() -- > no property found!");
+ return;
+ }
+
+ Sound::instance_->prop_=prop;
+
+ if(VProperty *pp=prop->findChild("players"))
+ {
+ Q_FOREACH(VProperty* p,pp->children())
+ {
+ Sound::instance_->players_[p->strName()]=p->param("command").toStdString();
+ }
+ }
+
+ if(VProperty *pp=prop->findChild("player"))
+ {
+ Sound::instance_->setCurrentPlayer(pp->valueAsString());
+ }
+
+ UserMessage::message(UserMessage::DBG, false,"Sound:load() -- > end");
+}
+
+static SimpleLoader<Sound> loaderSound("sound");
diff --git a/Viewer/src/Sound.hpp b/Viewer/src/Sound.hpp
new file mode 100644
index 0000000..43d53d2
--- /dev/null
+++ b/Viewer/src/Sound.hpp
@@ -0,0 +1,54 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef SOUND_HPP_
+#define SOUND_HPP_
+
+#include <vector>
+#include <string>
+
+#include "VProperty.hpp"
+
+class Sound : public VPropertyObserver
+{
+public:
+ static Sound* instance();
+
+ const std::vector<std::string>& sysSounds() const {return sysSounds_;}
+ const std::string sysDir() const {return sysDir_;}
+
+ void playSystem(const std::string&,int repeat);
+ void play(const std::string&,int repeat);
+ bool isSoundFile(const std::string& fName) const;
+
+ void notifyChange(VProperty*) {};
+
+ //Called from VConfigLoader
+ static void load(VProperty* group);
+
+protected:
+ Sound();
+ void setCurrentPlayer(const std::string&);
+
+ static Sound* instance_;
+
+ std::map<std::string,std::string> players_;
+ std::string currentPlayer_;
+ std::string currentCmd_;
+
+ std::string formats_;
+ std::string sysDir_;
+ std::vector<std::string> sysSounds_;
+ time_t prevPlayedAt_;
+ int delay_;
+ VProperty* prop_;
+};
+
+#endif
diff --git a/Viewer/src/StringMatchCombo.cpp b/Viewer/src/StringMatchCombo.cpp
new file mode 100644
index 0000000..dd5f419
--- /dev/null
+++ b/Viewer/src/StringMatchCombo.cpp
@@ -0,0 +1,49 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "StringMatchCombo.hpp"
+
+#include <QVariant>
+
+StringMatchCombo::StringMatchCombo(QWidget* parent) : QComboBox(parent)
+{
+ //addItem("Exact match","=");
+ addItem("Contains",StringMatchMode::ContainsMatch);
+ addItem("Matches",StringMatchMode::WildcardMatch);
+ addItem("Regexp",StringMatchMode::RegexpMatch);
+
+ setCurrentIndex(1);
+}
+
+StringMatchMode::Mode StringMatchCombo::matchMode(int index) const
+{
+ if(index >=0 && index < count())
+ {
+ return static_cast<StringMatchMode::Mode>(itemData(index).toInt());
+ }
+ return StringMatchMode::WildcardMatch;
+}
+
+StringMatchMode::Mode StringMatchCombo::currentMatchMode() const
+{
+ return matchMode(currentIndex());
+}
+
+void StringMatchCombo::setMatchMode(const StringMatchMode& mode)
+{
+ int im=mode.toInt();
+ for(int i=0; i < count(); i++)
+ {
+ if(itemData(i).toInt() == im)
+ {
+ setCurrentIndex(i);
+ }
+ }
+}
diff --git a/Viewer/src/StringMatchCombo.hpp b/Viewer/src/StringMatchCombo.hpp
new file mode 100644
index 0000000..4ae8a76
--- /dev/null
+++ b/Viewer/src/StringMatchCombo.hpp
@@ -0,0 +1,30 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VIEWER_SRC_STRINGMATCHCOMBO_HPP_
+#define VIEWER_SRC_STRINGMATCHCOMBO_HPP_
+
+#include <QComboBox>
+
+#include "StringMatchMode.hpp"
+
+class StringMatchCombo : public QComboBox
+{
+Q_OBJECT
+
+public:
+ explicit StringMatchCombo(QWidget* parent=0);
+
+ StringMatchMode::Mode matchMode(int) const;
+ StringMatchMode::Mode currentMatchMode() const;
+ void setMatchMode(const StringMatchMode& mode);
+};
+
+#endif /* VIEWER_SRC_STRINGMATCHCOMBO_HPP_ */
diff --git a/Viewer/src/StringMatchMode.cpp b/Viewer/src/StringMatchMode.cpp
new file mode 100644
index 0000000..c7fe2e5
--- /dev/null
+++ b/Viewer/src/StringMatchMode.cpp
@@ -0,0 +1,56 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+
+#include "StringMatchMode.hpp"
+
+std::map<StringMatchMode::Mode,std::string> StringMatchMode::matchOper_;
+
+StringMatchMode::StringMatchMode() :
+ mode_(WildcardMatch)
+{
+ init();
+}
+
+StringMatchMode::StringMatchMode(Mode mode) :
+ mode_(mode)
+{
+ init();
+}
+
+void StringMatchMode::init()
+{
+ if(matchOper_.empty())
+ {
+ matchOper_[ContainsMatch]="~";
+ matchOper_[WildcardMatch]="=";
+ matchOper_[RegexpMatch]="=~";
+ }
+}
+
+const std::string& StringMatchMode::matchOperator() const
+{
+ static std::string emptyStr;
+ std::map<Mode,std::string>::const_iterator it=matchOper_.find(mode_);
+ if(it != matchOper_.end())
+ return it->second;
+
+ return emptyStr;
+}
+
+StringMatchMode::Mode StringMatchMode::operToMode(const std::string& op)
+{
+ for(std::map<Mode,std::string>::const_iterator it=matchOper_.begin(); it != matchOper_.end(); ++it)
+ {
+ if(op == it->second)
+ return it->first;
+ }
+ return InvalidMatch;
+}
diff --git a/Viewer/src/StringMatchMode.hpp b/Viewer/src/StringMatchMode.hpp
new file mode 100644
index 0000000..00d49e4
--- /dev/null
+++ b/Viewer/src/StringMatchMode.hpp
@@ -0,0 +1,41 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VIEWER_SRC_STRINGMATCHMODE_HPP_
+#define VIEWER_SRC_STRINGMATCHMODE_HPP_
+
+#include <string>
+#include <map>
+
+class StringMatchMode
+{
+public:
+ enum Mode {InvalidMatch=-1,ContainsMatch=0,WildcardMatch=1,RegexpMatch=2};
+
+ StringMatchMode();
+ StringMatchMode(Mode m);
+ StringMatchMode(const StringMatchMode& r) {mode_=r.mode_;}
+
+ Mode mode() const {return mode_;}
+ void setMode(Mode m) {mode_=m;}
+ const std::string& matchOperator() const;
+ int toInt() const {return static_cast<int>(mode_);}
+
+ static Mode operToMode(const std::string&);
+
+private:
+ void init();
+
+ Mode mode_;
+ static std::map<Mode,std::string> matchOper_;
+};
+
+
+#endif /* VIEWER_SRC_STRINGMATCHMODE_HPP_ */
diff --git a/Viewer/src/SuiteFilter.cpp b/Viewer/src/SuiteFilter.cpp
new file mode 100644
index 0000000..40246d0
--- /dev/null
+++ b/Viewer/src/SuiteFilter.cpp
@@ -0,0 +1,316 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "SuiteFilter.hpp"
+
+#include "SuiteFilterObserver.hpp"
+#include "VSettings.hpp"
+#include "VProperty.hpp"
+
+#include <algorithm>
+
+//=================================================================
+//
+// SuiteFilterItem
+//
+//=================================================================
+
+SuiteFilterItem::SuiteFilterItem(const SuiteFilterItem& other) :
+ name_(other.name_),
+ present_(other.present_),
+ filtered_(other.filtered_)
+{
+}
+
+//=================================================================
+//
+// SuiteFilter
+//
+//=================================================================
+
+/*void SuiteFilter::current(const std::vector<std::string>& suites)
+{
+ current_=suites;
+ adjust();
+}*/
+
+SuiteFilter::~SuiteFilter()
+{
+ std::vector<SuiteFilterObserver*> obsCopy=observers_;
+ for(std::vector<SuiteFilterObserver*>::const_iterator it=obsCopy.begin(); it != obsCopy.end(); ++it)
+ {
+ (*it)->notifyDelete(this);
+ }
+}
+
+void SuiteFilter::clear()
+{
+ items_.clear();
+ filter_.clear();
+ broadcastChange();
+}
+
+void SuiteFilter::checkForNewLoaded(const std::vector<std::string>& loaded)
+{
+ if(enabled_ && autoAddNew_)
+ {
+ for(std::vector<std::string>::const_iterator it=loaded.begin(); it != loaded.end(); ++it)
+ {
+ if(std::find(loaded_.begin(), loaded_.end(),*it) == loaded_.end())
+ {
+ if(std::find(filter_.begin(), filter_.end(),*it) == filter_.end())
+ {
+ filter_.push_back(*it);
+ }
+ }
+ }
+ }
+}
+
+void SuiteFilter::adjust()
+{
+ items_.clear();
+
+ //Items present in current_
+ for(std::vector<std::string>::const_iterator it=loaded_.begin(); it != loaded_.end(); ++it)
+ {
+ bool filtered=false;
+ if(std::find(filter_.begin(), filter_.end(),*it) != filter_.end())
+ {
+ filtered=true;
+ }
+
+ items_.push_back(SuiteFilterItem(*it,true,filtered));
+ }
+
+ //Items present in filter_ only
+ for(std::vector<std::string>::const_iterator it=filter_.begin(); it != filter_.end(); ++it)
+ {
+ if(std::find(loaded_.begin(), loaded_.end(),*it) == loaded_.end())
+ {
+ items_.push_back(SuiteFilterItem(*it,false,true));
+ }
+ }
+
+ broadcastChange();
+}
+
+void SuiteFilter::setFiltered(int index,bool val)
+{
+ if(index >=0 && index < count())
+ {
+ items_.at(index).filtered_=val;
+
+ const std::string& name=items_.at(index).name_;
+ std::vector<std::string>::iterator it=std::find(filter_.begin(),filter_.end(),name);
+
+ if(val == true)
+ {
+ if(it == filter_.end())
+ filter_.push_back(name);
+ }
+ else
+ {
+ if(it != filter_.end())
+ filter_.erase(it);
+ }
+
+ }
+}
+
+SuiteFilter* SuiteFilter::clone()
+{
+ SuiteFilter* sf=new SuiteFilter();
+ sf->loaded_=loaded_;
+ sf->filter_=filter_;
+ sf->items_=items_;
+ sf->enabled_=enabled_;
+ sf->autoAddNew_=autoAddNew_;
+
+ return sf;
+}
+
+
+bool SuiteFilter::loadedSameAs(const std::vector<std::string>& loaded) const
+{
+ if(loaded.size() != loaded_.size())
+ return false;
+ else
+ {
+ for(unsigned int i=0; i < loaded.size(); i++)
+ {
+ if(loaded.at(i) != loaded_.at(i))
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+/*
+bool SuiteFilter::setLoadedInDefs(const std::vector<std::string>& loadedInDefs)
+{
+ bool changed=false;
+ std::vector<std::string> loadedTmp=loaded_;
+ for(std::vector<std::string>::const_iterator it=loadedInDefs.begin(); it != loadedInDefs.end(); ++it)
+ {
+ std::vector<std::string>::const_iterator itF=std::find(loaded_.begin(),loaded_.end(),*it);
+ if(itF != loaded_.end())
+ {
+ loadedTmp.push_back(*it);
+ changed=true;
+ }
+ }
+
+ if(changed)
+ {
+ loaded_=loadedTmp;
+ adjust();
+ }
+
+ return changed;
+
+}
+*/
+
+bool SuiteFilter::setLoaded(const std::vector<std::string>& loaded,bool checkDiff)
+{
+ bool same=false;
+ if(checkDiff)
+ same=loadedSameAs(loaded);
+
+ if(!checkDiff || !same)
+ {
+ checkForNewLoaded(loaded);
+ loaded_=loaded;
+ adjust();
+ return true;
+ }
+
+ return !same;
+}
+
+
+bool SuiteFilter::update(SuiteFilter* sf)
+{
+ changeFlags_.clear();
+
+ if(!sf)
+ return false;
+
+ if(sf->count() != count())
+ return false;
+
+ if(autoAddNew_ != sf->autoAddNewSuites())
+ {
+ autoAddNew_ = sf->autoAddNewSuites();
+ changeFlags_.set(AutoAddChanged);
+ }
+
+ if(enabled_ != sf->isEnabled())
+ {
+ enabled_ = sf->isEnabled();
+ changeFlags_.set(EnabledChanged);
+ }
+
+ if(filter_.size() != sf->filter_.size())
+ {
+ filter_=sf->filter_;
+ changeFlags_.set(ItemChanged);
+ }
+ else
+ {
+ for(size_t i=0; i < filter_.size(); i++)
+ {
+ if(filter_[i] != sf->filter_.at(i))
+ {
+ filter_[i]=sf->filter_.at(i);
+ changeFlags_.set(ItemChanged);
+ }
+ }
+ }
+
+ adjust();
+
+ return (changeFlags_.isEmpty() == false);
+}
+
+void SuiteFilter::selectAll()
+{
+ for(size_t i=0; i < items_.size(); i++)
+ {
+ setFiltered(static_cast<int>(i),true);
+ }
+}
+
+void SuiteFilter::unselectAll()
+{
+ filter_.clear();
+ adjust();
+}
+
+void SuiteFilter::addObserver(SuiteFilterObserver* o)
+{
+ assert(o);
+
+ std::vector<SuiteFilterObserver*>::const_iterator it=std::find(observers_.begin(),observers_.end(),o);
+ if(it == observers_.end())
+ observers_.push_back(o);
+}
+
+void SuiteFilter::removeObserver(SuiteFilterObserver* o)
+{
+ std::vector<SuiteFilterObserver*>::iterator it=std::find(observers_.begin(),observers_.end(),o);
+ if(it != observers_.end())
+ observers_.erase(it);
+}
+
+void SuiteFilter::broadcastChange()
+{
+ for(std::vector<SuiteFilterObserver*>::const_iterator it=observers_.begin(); it != observers_.end(); ++it)
+ {
+ (*it)->notifyChange(this);
+ }
+}
+
+void SuiteFilter::readSettings(VSettings *vs)
+{
+ clear();
+
+ enabled_=vs->getAsBool("enabled",enabled_);
+ autoAddNew_=vs->getAsBool("autoAddNew",autoAddNew_);
+
+ if(vs->contains("suites"))
+ {
+ vs->get("suites",filter_);
+ }
+
+ adjust();
+
+ changeFlags_.clear();
+ changeFlags_.set(ItemChanged);
+}
+
+void SuiteFilter::writeSettings(VSettings *vs)
+{
+ vs->putAsBool("enabled",enabled_);
+ vs->putAsBool("autoAddNew",autoAddNew_);
+
+ if(filter_.size() >0)
+ {
+ std::vector<std::string> array;
+ for(std::vector<std::string>::const_iterator it=filter_.begin(); it != filter_.end(); ++it)
+ {
+ array.push_back(*it);
+ }
+
+ vs->put("suites",array);
+ }
+}
diff --git a/Viewer/src/SuiteFilter.hpp b/Viewer/src/SuiteFilter.hpp
new file mode 100644
index 0000000..a6f5ee5
--- /dev/null
+++ b/Viewer/src/SuiteFilter.hpp
@@ -0,0 +1,113 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef SUITEFILTER_HPP_
+#define SUITEFILTER_HPP_
+
+#include <string>
+#include <vector>
+
+#include "FlagSet.hpp"
+
+class SuiteFilterObserver;
+class VSettings;
+
+#if 0
+template <class T>
+class FlagSet
+{
+public:
+ FlagSet() : flags_(0) {}
+
+ void clear() {flags_=0;}
+ void set(T flag ) { flags_ |= (1 << flag); }
+ void unset(T flag ) { flags_ &= ~ (1 << flag); }
+ bool isSet(T flag) const { return (flags_ >> flag) & 1; }
+ bool isEmpty() const {return flags_==0;}
+ bool sameAs(T flag) const {return flags_ == flag;}
+
+private:
+ int flags_;
+
+};
+
+#endif
+
+class SuiteFilterItem
+{
+public:
+ SuiteFilterItem(const std::string& name,bool present, bool filtered) :
+ name_(name), present_(present), filtered_(filtered) {}
+
+ SuiteFilterItem(const SuiteFilterItem& other);
+
+ std::string name_;
+ bool present_;
+ bool filtered_;
+};
+
+class SuiteFilter
+{
+public:
+ SuiteFilter() : autoAddNew_(false), enabled_(false) {}
+ ~SuiteFilter();
+
+ enum ChangeFlag {AutoAddChanged=1,EnabledChanged=2,ItemChanged=4};
+
+ SuiteFilter* clone();
+
+ const std::vector<std::string>& filter() const {return filter_;}
+ const std::vector<std::string>& loaded() const {return loaded_;}
+ const std::vector<SuiteFilterItem> items() const {return items_;}
+
+ void current(const std::vector<std::string>& suites);
+ int count() const {return static_cast<int>(items_.size());}
+ void setFiltered(int index,bool val);
+
+ bool autoAddNewSuites() const {return autoAddNew_;}
+ bool isEnabled() const {return enabled_;}
+
+ void setAutoAddNewSuites(bool b) {autoAddNew_=b;}
+ void setEnabled(bool b) {enabled_=b;}
+ void selectAll();
+ void unselectAll();
+
+ bool update(SuiteFilter*);
+ bool setLoaded(const std::vector<std::string>& loaded,bool checkDiff=true);
+ bool loadedSameAs(const std::vector<std::string>& loaded) const;
+ const FlagSet<ChangeFlag>& changeFlags() {return changeFlags_;}
+
+ bool hasObserver() const {return !observers_.empty();}
+ void addObserver(SuiteFilterObserver*);
+ void removeObserver(SuiteFilterObserver*);
+
+ void readSettings(VSettings *vs);
+ void writeSettings(VSettings *vs);
+
+private:
+ void clear();
+ void adjust();
+ void broadcastChange();
+ void checkForNewLoaded(const std::vector<std::string>& loaded);
+
+ //All the suites currently loaded onto the server
+ std::vector<std::string> loaded_;
+
+ //The suites we want to filter (they might not be loaded)
+ std::vector<std::string> filter_;
+
+ std::vector<SuiteFilterItem> items_;
+ bool autoAddNew_;
+ bool enabled_;
+ FlagSet<ChangeFlag> changeFlags_;
+ std::vector<SuiteFilterObserver*> observers_;
+};
+
+
+#endif
diff --git a/Viewer/src/SuiteFilterObserver.hpp b/Viewer/src/SuiteFilterObserver.hpp
new file mode 100644
index 0000000..94a5804
--- /dev/null
+++ b/Viewer/src/SuiteFilterObserver.hpp
@@ -0,0 +1,25 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VIEWER_SRC_SUITEFILTEROBSERVER_HPP_
+#define VIEWER_SRC_SUITEFILTEROBSERVER_HPP_
+
+class SuiteFilter;
+
+class SuiteFilterObserver
+{
+public:
+ SuiteFilterObserver() {};
+ virtual ~SuiteFilterObserver() {};
+
+ virtual void notifyChange(SuiteFilter*)=0;
+ virtual void notifyDelete(SuiteFilter*)=0;
+};
+#endif /* VIEWER_SRC_SUITEFILTEROBSERVER_HPP_ */
diff --git a/Viewer/src/SuiteItemWidget.cpp b/Viewer/src/SuiteItemWidget.cpp
new file mode 100644
index 0000000..c0e24d3
--- /dev/null
+++ b/Viewer/src/SuiteItemWidget.cpp
@@ -0,0 +1,261 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "SuiteItemWidget.hpp"
+
+#include "InfoProvider.hpp"
+#include "ServerHandler.hpp"
+#include "SuiteFilter.hpp"
+#include "SuiteModel.hpp"
+#include "VNode.hpp"
+#include "VReply.hpp"
+
+//========================================================
+//
+// SuiteItemWidget
+//
+//========================================================
+
+SuiteItemWidget::SuiteItemWidget(QWidget *parent) : QWidget(parent)
+{
+ setupUi(this);
+
+ infoProvider_=new SuiteProvider(this);
+
+ model_=new SuiteModel(this);
+
+ suiteView->setModel(model_);
+
+ connect(model_,SIGNAL(dataChanged(QModelIndex,QModelIndex)),
+ this,SLOT(slotModelEdited(QModelIndex,QModelIndex)));
+
+ //messageLabel->hide();
+
+ okTb->setEnabled(false);
+ enableTb->setChecked(false);
+
+ checkActionState();
+}
+
+QWidget* SuiteItemWidget::realWidget()
+{
+ return this;
+}
+
+void SuiteItemWidget::reload(VInfo_ptr info)
+{
+ assert(active_);
+
+ if(suspended_)
+ return;
+
+ clearContents();
+
+ info_=info;
+
+ if(info_ && info_->isServer() && info_->server())
+ {
+ //Get the current suitefilter
+ SuiteFilter *sf=info_->server()->suiteFilter();
+
+ assert(sf);
+
+ //The model will be an observer of the suitefilter
+ model_->setData(sf);
+
+ enableTb->setChecked(sf->isEnabled());
+ autoCb->setChecked(sf->autoAddNewSuites());
+
+ checkActionState();
+
+ //We update the filter because it might not show the current status. If
+ //there is a change the model will be notified
+
+ //If the filter is disabled we update the filter with the
+ //current list of suites in the defs. These are all the suites
+ //loaded to the server.
+ if(!sf->isEnabled())
+ {
+ info_->server()->updateSuiteFilterWithDefs();
+ }
+ //If the filter is enabled we need to fetch the total list of suites
+ //loaded onto the server directly from the server (through the thread)
+ else
+ {
+ //inforReady or infoFailed will always be called.
+ infoProvider_->info(info_);
+ }
+ }
+}
+
+void SuiteItemWidget::updateData()
+{
+ /*if(info_.get() && info_->isServer() && info_->server())
+ {
+ model_->updateData(info_->server()->suiteFilter());
+ }*/
+}
+
+void SuiteItemWidget::infoReady(VReply* reply)
+{
+ //updateData();
+}
+
+void SuiteItemWidget::infoFailed(VReply* reply)
+{
+ //commandSent_=false;
+ //QString s=QString::fromStdString(reply->errorText());
+ //checkActionState();
+}
+
+void SuiteItemWidget::clearContents()
+{
+ model_->setData(0);
+ InfoPanelItem::clear();
+ okTb->setEnabled(false);
+ //messageLabel->hide();
+}
+
+void SuiteItemWidget::updateState(const FlagSet<ChangeFlag>&)
+{
+ checkActionState();
+}
+
+void SuiteItemWidget::checkActionState()
+{
+ if(suspended_)
+ {
+ enableTb->setEnabled(false);
+ autoCb->setEnabled(false);
+ selectAllTb->setEnabled(false);
+ unselectAllTb->setEnabled(false);
+ syncTb->setEnabled(false);
+ suiteView->setEnabled(false);
+ okTb->setEnabled(false);
+ return;
+ }
+ else
+ {
+ enableTb->setEnabled(true);
+ okTb->setEnabled(true);
+ suiteView->setEnabled(true);
+ }
+
+ if(enableTb->isChecked())
+ {
+ autoCb->setEnabled(true);
+ selectAllTb->setEnabled(true);
+ unselectAllTb->setEnabled(true);
+
+ if(SuiteFilter* sf=model_->filter())
+ {
+ autoCb->setChecked(sf->autoAddNewSuites());
+
+ if(!sf->autoAddNewSuites())
+ {
+ syncTb->setEnabled(true);
+ }
+ else
+ {
+ syncTb->setEnabled(false);
+ }
+ }
+ else
+ {
+ syncTb->setEnabled(false);
+ }
+ }
+ else
+ {
+ autoCb->setEnabled(false);
+ selectAllTb->setEnabled(false);
+ unselectAllTb->setEnabled(false);
+ syncTb->setEnabled(false);
+ }
+}
+
+void SuiteItemWidget::on_autoCb_clicked(bool val)
+{
+ if(SuiteFilter* sf=model_->filter())
+ {
+ sf->setAutoAddNewSuites(val);
+ }
+
+ checkActionState();
+}
+
+void SuiteItemWidget::on_enableTb_clicked(bool val)
+{
+ if(SuiteFilter* sf=model_->filter())
+ {
+ sf->setEnabled(val);
+ model_->reloadData();
+ settingsChanged();
+ }
+
+ checkActionState();
+}
+
+void SuiteItemWidget::on_selectAllTb_clicked(bool)
+{
+ if(SuiteFilter* sf=model_->filter())
+ {
+ sf->selectAll();
+ model_->reloadData();
+ settingsChanged();
+ }
+}
+
+void SuiteItemWidget::on_unselectAllTb_clicked(bool)
+{
+ if(SuiteFilter* sf=model_->filter())
+ {
+ sf->unselectAll();
+ model_->reloadData();
+ settingsChanged();
+ }
+}
+
+//get a fresh suite list from the server
+void SuiteItemWidget::on_syncTb_clicked(bool)
+{
+ if(info_.get() && info_->isServer() && info_->server())
+ {
+ infoProvider_->info(info_);
+ }
+}
+
+void SuiteItemWidget::on_okTb_clicked(bool)
+{
+ if(info_.get() && info_->isServer() && info_->server())
+ {
+ //This replace the edited filter in model the one
+ //stored by the server
+ info_->server()->updateSuiteFilter(model_->filter());
+ okTb->setEnabled(false);
+ }
+}
+
+void SuiteItemWidget::slotModelEdited(const QModelIndex&,const QModelIndex&)
+{
+ settingsChanged();
+}
+
+void SuiteItemWidget::settingsChanged()
+{
+ if(!okTb->isEnabled())
+ {
+ okTb->setEnabled(true);
+ //messageLabel->show();
+ //messageLabel->showInfo("The suite filter changed!");
+ }
+}
+
+
+static InfoPanelItemMaker<SuiteItemWidget> maker1("suite");
diff --git a/Viewer/src/SuiteItemWidget.hpp b/Viewer/src/SuiteItemWidget.hpp
new file mode 100644
index 0000000..06b4661
--- /dev/null
+++ b/Viewer/src/SuiteItemWidget.hpp
@@ -0,0 +1,61 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef SUITEITEMWIDGET_HPP_
+#define SUITEITEMWIDGET_HPP_
+
+#include <QWidget>
+
+#include "InfoPanelItem.hpp"
+#include "VInfo.hpp"
+
+#include "ui_SuiteItemWidget.h"
+
+class SuiteModel;
+
+class SuiteItemWidget : public QWidget, public InfoPanelItem, protected Ui::SuiteItemWidget
+{
+Q_OBJECT
+
+public:
+ explicit SuiteItemWidget(QWidget *parent=0);
+
+ void reload(VInfo_ptr);
+ QWidget* realWidget();
+ void clearContents();
+
+ //From VInfoPresenter
+ void infoReady(VReply*);
+ void infoFailed(VReply*);
+ void infoProgress(VReply*) {}
+
+ void nodeChanged(const VNode*, const std::vector<ecf::Aspect::Type>&) {}
+ void defsChanged(const std::vector<ecf::Aspect::Type>&) {}
+
+protected Q_SLOTS:
+ void on_autoCb_clicked(bool);
+ void on_enableTb_clicked(bool);
+ void on_selectAllTb_clicked(bool);
+ void on_unselectAllTb_clicked(bool);
+ void on_syncTb_clicked(bool);
+ void on_okTb_clicked(bool);
+ void slotModelEdited(const QModelIndex&,const QModelIndex&);
+
+protected:
+ void updateData();
+ void updateState(const ChangeFlags&);
+ void settingsChanged();
+ void checkActionState();
+
+ SuiteModel *model_;
+};
+
+#endif
+
diff --git a/Viewer/src/SuiteItemWidget.ui b/Viewer/src/SuiteItemWidget.ui
new file mode 100644
index 0000000..887ec44
--- /dev/null
+++ b/Viewer/src/SuiteItemWidget.ui
@@ -0,0 +1,252 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SuiteItemWidget</class>
+ <widget class="QWidget" name="SuiteItemWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>564</width>
+ <height>470</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <property name="statusTip">
+ <string/>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="spacing">
+ <number>4</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>2</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>4</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QToolButton" name="enableTb">
+ <property name="text">
+ <string>Enable filter</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/filter_decor.svg</normaloff>:/viewer/filter_decor.svg</iconset>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ <property name="autoRaise">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="autoCb">
+ <property name="text">
+ <string>Automatically add new suites to filter</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QToolButton" name="syncTb">
+ <property name="toolTip">
+ <string>Get the current list of <b>loaded suites</b> from the server</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/sync.svg</normaloff>:/viewer/sync.svg</iconset>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QTreeView" name="suiteView">
+ <property name="contextMenuPolicy">
+ <enum>Qt::ActionsContextMenu</enum>
+ </property>
+ <property name="alternatingRowColors">
+ <bool>true</bool>
+ </property>
+ <property name="rootIsDecorated">
+ <bool>false</bool>
+ </property>
+ <property name="uniformRowHeights">
+ <bool>true</bool>
+ </property>
+ <property name="itemsExpandable">
+ <bool>false</bool>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ <property name="expandsOnDoubleClick">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QToolButton" name="selectAllTb">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip">
+ <string>Select all suites</string>
+ </property>
+ <property name="text">
+ <string>Select &all</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/select_all.svg</normaloff>:/viewer/select_all.svg</iconset>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ <property name="autoRaise">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="unselectAllTb">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip">
+ <string>Unselect all suites</string>
+ </property>
+ <property name="text">
+ <string>&Unselect all</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/unselect_all.svg</normaloff>:/viewer/unselect_all.svg</iconset>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ <property name="autoRaise">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="okTb">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip">
+ <string>Apply changes</string>
+ </property>
+ <property name="text">
+ <string>&Submit</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/submit.svg</normaloff>:/viewer/submit.svg</iconset>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="viewer.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/Viewer/src/SuiteModel.cpp b/Viewer/src/SuiteModel.cpp
new file mode 100644
index 0000000..5a49e30
--- /dev/null
+++ b/Viewer/src/SuiteModel.cpp
@@ -0,0 +1,254 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "SuiteModel.hpp"
+
+#include <QDebug>
+
+#include "SuiteFilter.hpp"
+
+SuiteModel::SuiteModel(QObject *parent) :
+ QAbstractItemModel(parent),
+ data_(0),
+ realData_(0),
+ presentCol_(QColor(1,128,73)),
+ notPresentCol_(QColor(255,0,0))
+{
+
+}
+
+SuiteModel::~SuiteModel()
+{
+ beginResetModel();
+ clearData();
+ endResetModel();
+}
+
+void SuiteModel::clearData()
+{
+ if(data_)
+ delete data_;
+
+ data_=0;
+
+ if(realData_)
+ realData_->removeObserver(this);
+
+ realData_=0;
+}
+
+void SuiteModel::setData(SuiteFilter* filter)
+{
+ beginResetModel();
+
+ if(data_ && data_ != filter)
+ {
+ clearData();
+ }
+
+ if(filter)
+ {
+ data_=filter->clone();
+ realData_=filter;
+ realData_->addObserver(this);
+ }
+
+ endResetModel();
+}
+
+void SuiteModel::notifyChange(SuiteFilter *filter)
+{
+ if(filter && filter == realData_)
+ {
+ updateData();
+ }
+}
+
+void SuiteModel::notifyDelete(SuiteFilter *filter)
+{
+ if(filter && filter == realData_)
+ {
+ beginResetModel();
+ clearData();
+ endResetModel();
+ }
+}
+
+void SuiteModel::updateData()
+{
+ if(realData_ && data_ &&
+ !data_->loadedSameAs(realData_->loaded()))
+ {
+ beginResetModel();
+ data_->setLoaded(realData_->loaded());
+ endResetModel();
+ }
+}
+
+void SuiteModel::reloadData()
+{
+ beginResetModel();
+ endResetModel();
+}
+
+bool SuiteModel::hasData() const
+{
+ return (data_ && data_->count() > 0);
+}
+
+int SuiteModel::columnCount( const QModelIndex& /*parent */ ) const
+{
+ return 2;
+}
+
+int SuiteModel::rowCount( const QModelIndex& parent) const
+{
+ if(!hasData())
+ return 0;
+
+ //Parent is the root:
+ if(!parent.isValid())
+ {
+ return data_->count();
+ }
+
+ return 0;
+}
+
+Qt::ItemFlags SuiteModel::flags ( const QModelIndex & index) const
+{
+ Qt::ItemFlags defaultFlags;
+
+ if(data_->isEnabled())
+ {
+ defaultFlags=Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable; // | Qt::ItemIsEditable;
+ }
+
+ return defaultFlags;
+}
+
+QVariant SuiteModel::data( const QModelIndex& index, int role ) const
+{
+ if(!index.isValid() || !hasData())
+ {
+ return QVariant();
+ }
+
+ //Data lookup can be costly so we immediately return a default value for all
+ //the cases where the default should be used.
+ //if(role != Qt::DisplayRole && role != Qt::BackgroundRole && role != Qt::ForegroundRole)
+ //{
+ // return QVariant();
+ //}
+ //qDebug() << "data" << index << role;
+
+ int row=index.row();
+ if(row < 0 || row >= data_->count())
+ return QVariant();
+
+ if(role == Qt::DisplayRole)
+ {
+ switch(index.column())
+ {
+ case 0:
+ return QString::fromStdString(data_->items().at(row).name_);
+ break;
+ case 1:
+ return (data_->items().at(row).present_)?"loaded":"not loaded";
+ break;
+ default:
+ break;
+ }
+ }
+ else if(role == Qt::CheckStateRole)
+ {
+ if(index.column()==0)
+ return (data_->items().at(row).filtered_)?QVariant(Qt::Checked):QVariant(Qt::Unchecked);
+ }
+ else if(role == Qt::ForegroundRole)
+ {
+ if(!data_->isEnabled())
+ {
+ return QVariant();
+ }
+ else if(index.column() == 1)
+ {
+ return (data_->items().at(row).present_)?presentCol_:notPresentCol_;
+ }
+ return QVariant();
+ }
+
+ return QVariant();
+}
+
+bool SuiteModel::setData(const QModelIndex& index, const QVariant & value, int role )
+{
+ if(index.column() == 0 && role == Qt::CheckStateRole)
+ {
+ int row=index.row();
+ if(row >=0 && row < data_->count())
+ {
+ bool checked=(value.toInt() == Qt::Checked)?true:false;
+ data_->setFiltered(row,checked);
+ Q_EMIT dataChanged(index,index);
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+QVariant SuiteModel::headerData( const int section, const Qt::Orientation orient , const int role ) const
+{
+ if ( orient != Qt::Horizontal || (role != Qt::DisplayRole && role != Qt::ToolTipRole))
+ return QAbstractItemModel::headerData( section, orient, role );
+
+ if(role == Qt::DisplayRole)
+ {
+ switch ( section )
+ {
+ case 0: return tr("Suite");
+ case 1: return tr("Status on server");
+ default: return QVariant();
+ }
+ }
+ else if(role== Qt::ToolTipRole)
+ {
+ switch ( section )
+ {
+ case 0: return tr("Suite filter status");
+ case 1: return tr("Indicates if the suite is currently <b>loaded</b> on the server");
+ default: return QVariant();
+ }
+ }
+ return QVariant();
+}
+
+QModelIndex SuiteModel::index( int row, int column, const QModelIndex & parent ) const
+{
+ if(!hasData() || row < 0 || column < 0)
+ {
+ return QModelIndex();
+ }
+
+ //When parent is the root this index refers to a node or server
+ if(!parent.isValid())
+ {
+ return createIndex(row,column);
+ }
+
+ return QModelIndex();
+
+}
+
+QModelIndex SuiteModel::parent(const QModelIndex &child) const
+{
+ return QModelIndex();
+}
diff --git a/Viewer/src/SuiteModel.hpp b/Viewer/src/SuiteModel.hpp
new file mode 100644
index 0000000..4103195
--- /dev/null
+++ b/Viewer/src/SuiteModel.hpp
@@ -0,0 +1,47 @@
+#ifndef SUITEMODEL_H
+#define SUITEMODEL_H
+
+#include <QAbstractItemModel>
+#include <QColor>
+
+#include "SuiteFilterObserver.hpp"
+
+class SuiteFilter;
+
+class SuiteModel : public QAbstractItemModel, public SuiteFilterObserver
+{
+public:
+ explicit SuiteModel(QObject *parent=0);
+ ~SuiteModel();
+
+ int columnCount (const QModelIndex& parent = QModelIndex() ) const;
+ int rowCount (const QModelIndex& parent = QModelIndex() ) const;
+
+ Qt::ItemFlags flags ( const QModelIndex & index) const;
+ QVariant data (const QModelIndex& , int role = Qt::DisplayRole ) const;
+ bool setData(const QModelIndex & index, const QVariant & value, int role );
+ QVariant headerData(int,Qt::Orientation,int role = Qt::DisplayRole ) const;
+
+ QModelIndex index (int, int, const QModelIndex& parent = QModelIndex() ) const;
+ QModelIndex parent (const QModelIndex & ) const;
+
+ void setData(SuiteFilter* filter);
+ void reloadData();
+
+ SuiteFilter* filter() const {return data_;}
+
+ void notifyChange(SuiteFilter*);
+ void notifyDelete(SuiteFilter*);
+
+protected:
+ bool hasData() const;
+ void clearData();
+ void updateData();
+
+ SuiteFilter* data_;
+ SuiteFilter* realData_;
+ QColor presentCol_;
+ QColor notPresentCol_;
+};
+
+#endif
diff --git a/Viewer/src/TabWidget.cpp b/Viewer/src/TabWidget.cpp
new file mode 100644
index 0000000..15835b0
--- /dev/null
+++ b/Viewer/src/TabWidget.cpp
@@ -0,0 +1,278 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "TabWidget.hpp"
+
+#include <QDebug>
+#include <QStackedWidget>
+#include <QTabBar>
+#include <QToolButton>
+#include <QVBoxLayout>
+
+#include "UserMessage.hpp"
+
+TabWidget::TabWidget(QWidget* parent) :
+ QWidget(parent),
+ beingCleared_(false)
+{
+ //Main layout
+ QVBoxLayout* layout = new QVBoxLayout(this);
+ layout->setSpacing(0);
+ layout->setContentsMargins(0, 0, 0, 0);
+
+ //Horizontal layout for the tab bar
+ QHBoxLayout* hb = new QHBoxLayout(this);
+ hb->setSpacing(0);
+ hb->setContentsMargins(0, 0, 0, 0);
+ layout->addLayout(hb);
+
+ //Tab bar
+ bar_ = new QTabBar(this);
+ hb->addWidget(bar_, 1);
+
+ //bar_->setProperty("mvStyle","folder");
+ bar_->setMovable(true);
+ bar_->setExpanding(true);
+
+ //QString st=bar_->styleSheet();
+ //st+="QTabBar::tab{padding: 4px;}";
+ //st+="QTabBar::tab {margin-left: 4px;}";
+ //st+="QTabBar::tab:selected {font: bold;}";
+ //bar_->setStyleSheet(st);
+
+ //Add tab button on the right
+ addTb_ = new QToolButton(this);
+ addTb_->setAutoRaise(true);
+ addTb_->setIcon(QPixmap(":/viewer/add_tab.svg"));
+ addTb_->setToolTip(tr("Open a new tab"));
+ hb->addWidget(addTb_);
+
+ //Stacked widget to store the actual tab widgets
+ stacked_ = new QStackedWidget(this);
+ stacked_->setMinimumHeight(1);
+ stacked_->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
+ layout->addWidget(stacked_);
+
+ //Context menu for tha tabs
+ bar_->setContextMenuPolicy(Qt::CustomContextMenu);
+
+ connect(bar_,SIGNAL(customContextMenuRequested(const QPoint &)),
+ this,SLOT(slotContextMenu(const QPoint &)));
+
+ connect(bar_,SIGNAL(tabMoved(int,int)),
+ this,SLOT(tabMoved(int,int)));
+
+ connect(bar_,SIGNAL(currentChanged(int)),
+ this,SLOT(currentTabChanged(int)));
+
+ connect(bar_,SIGNAL(tabCloseRequested(int)),
+ this,SLOT(removeTab(int)));
+
+ connect(addTb_,SIGNAL(clicked()),
+ this,SIGNAL(newTabRequested()));
+}
+
+void TabWidget::slotContextMenu(const QPoint& pos) {
+ if (pos.isNull())
+ return;
+
+ /*MvQContextItemSet *cms = cmSet();
+ if (!cms)
+ return;
+
+ int index = bar_->tabAt(pos);
+
+ QString selection = MvQContextMenu::instance()->exec(cms->icon(),
+ mapToGlobal(pos), this,
+ //QString::number(bar_->count()));
+ "path=" + folderPath(index));
+ if (!selection.isEmpty())
+ tabBarCommand(selection, index);*/
+}
+
+int TabWidget::count() const
+{
+ return bar_->count();
+}
+
+int TabWidget::currentIndex() const
+{
+ return bar_->currentIndex();
+}
+
+void TabWidget::setCurrentIndex(int index)
+{
+ bar_->setCurrentIndex(index);
+}
+
+QWidget* TabWidget::widget(int index) const
+{
+ if (index >= 0 && index < bar_->count())
+ {
+ return stacked_->widget(index);
+ }
+
+ return 0;
+}
+
+QWidget* TabWidget::currentWidget() const
+{
+ return widget(bar_->currentIndex());
+}
+
+int TabWidget::indexOfWidget(QWidget *w) const
+{
+ for (int i = 0; i < stacked_->count(); i++)
+ if (w == stacked_->widget(i))
+ return i;
+
+ return -1;
+}
+
+void TabWidget::clear()
+{
+ beingCleared_=true;
+ while (bar_->count() > 0) {
+ removeTab(0);
+ }
+ beingCleared_=false;
+}
+
+void TabWidget::addTab(QWidget *w, QPixmap pix, QString name)
+{
+ stacked_->addWidget(w);
+ bar_->addTab(pix, name);
+ bar_->setCurrentIndex(count() - 1);
+ checkTabStatus();
+}
+
+void TabWidget::removeTab(int index)
+{
+ if (index >= 0 && index < bar_->count()) {
+ QWidget *w = stacked_->widget(index);
+ stacked_->removeWidget(w);
+ bar_->removeTab(index);
+ w->hide();
+ w->deleteLater();
+ }
+
+ checkTabStatus();
+}
+
+void TabWidget::removeOtherTabs(int index)
+{
+ QWidget *actW = stacked_->widget(index);
+
+ while (bar_->count() > 0) {
+ if (stacked_->widget(0) != actW) {
+ removeTab(0);
+ } else
+ break;
+ }
+
+ while (bar_->count() > 1) {
+ if (stacked_->widget(1) != actW) {
+ removeTab(1);
+ }
+ }
+
+ checkTabStatus();
+}
+
+void TabWidget::currentTabChanged(int index)
+{
+ if (stacked_->count() == bar_->count()) {
+ stacked_->setCurrentIndex(index);
+ Q_EMIT currentIndexChanged(index);
+
+ checkTabStatus();
+ }
+}
+
+void TabWidget::tabMoved(int from, int to)
+{
+ QWidget *w = stacked_->widget(from);
+ stacked_->removeWidget(w);
+ stacked_->insertWidget(to, w);
+
+ //bar_->setCurrentIndex(to);
+ currentTabChanged(to);
+}
+
+void TabWidget::setTabText(int index, QString txt)
+{
+ if (index >= 0 && index < bar_->count()) {
+ bar_->setTabText(index, txt);
+ }
+}
+
+void TabWidget::setTabIcon(int index, QPixmap pix)
+{
+ if (index >= 0 && index < bar_->count())
+ {
+ QSize maxSize=maxIconSize();
+
+ if(maxSize.width() < pix.width())
+ maxSize.setWidth(pix.width());
+
+ if(maxSize.height() < pix.height())
+ maxSize.setHeight(pix.height());
+
+ if(maxSize != bar_->iconSize())
+ bar_->setIconSize(maxSize);
+
+ bar_->setTabIcon(index, QIcon(pix));
+ }
+}
+
+QSize TabWidget::maxIconSize() const
+{
+ QSize maxSize(0,0);
+ for(int i=0; i < bar_->count(); i++)
+ {
+ if(bar_->tabIcon(i).availableSizes().count() > 0)
+ {
+ QSize avs=bar_->tabIcon(i).availableSizes().front();
+ if(maxSize.width() < avs.width())
+ maxSize.setWidth(avs.width());
+
+ if(maxSize.height() < avs.height())
+ maxSize.setHeight(avs.height());
+ }
+ }
+ return maxSize;
+}
+
+
+void TabWidget::checkTabStatus()
+{
+ if (bar_->count() > 1)
+ {
+ bar_->show();
+ bar_->setTabsClosable(true);
+ addTb_->show();
+ }
+ else
+ {
+ bar_->hide();
+ bar_->setTabsClosable(false);
+ addTb_->hide();
+ }
+
+ for (int i = 0; i < bar_->count(); i++)
+ {
+ if (QWidget *w = bar_->tabButton(i, QTabBar::RightSide))
+ {
+ if (i == bar_->currentIndex())
+ w->show();
+ else
+ w->hide();
+ }
+ }
+}
diff --git a/Viewer/src/TabWidget.hpp b/Viewer/src/TabWidget.hpp
new file mode 100644
index 0000000..941c6f6
--- /dev/null
+++ b/Viewer/src/TabWidget.hpp
@@ -0,0 +1,67 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef TABWIDGET_HPP_
+#define TABWIDGET_HPP_
+
+#include <QWidget>
+
+class QMenu;
+class QStackedWidget;
+class QTabBar;
+class QToolButton;
+class QVBoxLayout;
+
+class TabWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit TabWidget(QWidget *parent=0);
+
+ int currentIndex() const;
+ int indexOfWidget(QWidget*) const;
+ QWidget *widget(int) const;
+ QWidget *currentWidget() const;
+ void checkTabStatus();
+ void addTab(QWidget *,QPixmap,QString);
+ void setTabText(int,QString);
+ void setTabIcon(int,QPixmap);
+ int count() const;
+ void clear();
+ bool beingCleared() const {return beingCleared_;}
+
+public Q_SLOTS:
+ void removeTab(int);
+ void removeOtherTabs(int);
+ void setCurrentIndex(int);
+
+private Q_SLOTS:
+ void slotContextMenu(const QPoint&);
+ void currentTabChanged(int index);
+ void tabMoved(int from,int to);
+
+Q_SIGNALS:
+ void currentIndexChanged(int);
+ void newTabRequested();
+
+protected:
+ //virtual MvQContextItemSet* cmSet()=0;
+ virtual void tabBarCommand(QString,int)=0;
+
+private:
+ QSize maxIconSize() const;
+
+ QTabBar *bar_;
+ QStackedWidget *stacked_;
+ QToolButton* addTb_;
+ bool beingCleared_;
+};
+
+#endif
diff --git a/Viewer/src/TableFilterWidget.cpp b/Viewer/src/TableFilterWidget.cpp
new file mode 100644
index 0000000..8bfc4a4
--- /dev/null
+++ b/Viewer/src/TableFilterWidget.cpp
@@ -0,0 +1,102 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "TableFilterWidget.hpp"
+
+#include <QDebug>
+#include <QMenu>
+#include <QToolButton>
+
+#include "FilterWidget.hpp"
+#include "NodeFilterDialog.hpp"
+#include "NodeQuery.hpp"
+#include "ServerFilter.hpp"
+#include "UserMessage.hpp"
+#include "VFilter.hpp"
+
+#include <assert.h>
+
+TableFilterWidget::TableFilterWidget(QWidget *parent) :
+ QWidget(parent),
+ filterDef_(0),
+ serverFilter_(0)
+{
+ setupUi(this);
+
+ connect(queryTe_,SIGNAL(clicked()),
+ this,SLOT(slotEdit()));
+
+ numLabel_->hide();
+
+ slotTotalNumChanged(0);
+
+ //queryTe_->setFixedHeight(18);
+}
+
+void TableFilterWidget::slotEdit()
+{
+ assert(filterDef_);
+ assert(serverFilter_);
+
+ NodeFilterDialog d(this);
+ d.setServerFilter(serverFilter_);
+ d.setQuery(filterDef_->query());
+ if(d.exec() == QDialog::Accepted)
+ {
+ filterDef_->setQuery(d.query());
+ UserMessage::message(UserMessage::DBG,false,"new table query: " + filterDef_->query()->query().toStdString());
+ }
+}
+
+void TableFilterWidget::build(NodeFilterDef* def,ServerFilter *sf)
+{
+ filterDef_=def;
+ serverFilter_=sf;
+
+ connect(filterDef_,SIGNAL(changed()),
+ this,SLOT(slotDefChanged()));
+
+ slotDefChanged();
+}
+
+void TableFilterWidget::slotDefChanged()
+{
+ QColor bg(240,240,240);
+ queryTe_->setHtml(filterDef_->query()->extQueryHtml(false,bg,0));
+}
+
+void TableFilterWidget::slotHeaderFilter(QString column,QPoint globalPos)
+{
+ NodeQuery *q=filterDef_->query()->clone();
+ if(column == "status")
+ {
+ QMenu *menu=new QMenu(this);
+ //stateFilterMenu_=new StateFilterMenu(menuState,filter_->menu());
+
+ NodeStateFilter sf;
+ sf.setCurrent(q->stateSelection());
+ VParamFilterMenu* sfm= new VParamFilterMenu(menu,&sf,"Status filter",
+ VParamFilterMenu::FilterMode,VParamFilterMenu::ColourDecor);
+
+ if(menu->exec(globalPos) != NULL)
+ {
+ q->setStateSelection(sf.currentAsList());
+ filterDef_->setQuery(q);
+ }
+
+ delete menu;
+ }
+
+ delete q;
+}
+
+void TableFilterWidget::slotTotalNumChanged(int n)
+{
+ numLabel_->setText(tr("Total: ") + QString::number(n));
+}
diff --git a/Viewer/src/TableFilterWidget.hpp b/Viewer/src/TableFilterWidget.hpp
new file mode 100644
index 0000000..a9d968b
--- /dev/null
+++ b/Viewer/src/TableFilterWidget.hpp
@@ -0,0 +1,42 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef TABLEFILTERWIDGET_INC_
+#define TABLEFILTERWIDGET_INC_
+
+#include "ui_TableFilterWidget.h"
+
+#include <QWidget>
+
+class NodeFilterDef;
+class ServerFilter;
+
+class TableFilterWidget : public QWidget, private Ui::TableFilterWidget
+{
+Q_OBJECT
+
+public:
+ explicit TableFilterWidget(QWidget *parent=0);
+ ~TableFilterWidget() {};
+
+ void build(NodeFilterDef*,ServerFilter*);
+
+public Q_SLOTS:
+ void slotEdit();
+ void slotDefChanged();
+ void slotHeaderFilter(QString column,QPoint globalPos);
+ void slotTotalNumChanged(int);
+
+private:
+ NodeFilterDef* filterDef_;
+ ServerFilter* serverFilter_;
+};
+
+#endif
+
diff --git a/Viewer/src/TableFilterWidget.ui b/Viewer/src/TableFilterWidget.ui
new file mode 100644
index 0000000..ac07a0c
--- /dev/null
+++ b/Viewer/src/TableFilterWidget.ui
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>TableFilterWidget</class>
+ <widget class="QWidget" name="TableFilterWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>412</width>
+ <height>118</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1,0">
+ <property name="leftMargin">
+ <number>2</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Filter:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="OneLineTextEdit" name="queryTe_"/>
+ </item>
+ <item>
+ <widget class="QLabel" name="numLabel_">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ <action name="actionBreadcrumbs">
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Breadcrumbs</string>
+ </property>
+ <property name="toolTip">
+ <string>Show breadcrumbs</string>
+ </property>
+ </action>
+ <action name="actionFrozen">
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Frozen</string>
+ </property>
+ <property name="toolTip">
+ <string>Do not update panel when node changes</string>
+ </property>
+ </action>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>OneLineTextEdit</class>
+ <extends>QTextEdit</extends>
+ <header>OneLineTextEdit.hpp</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Viewer/src/TableNodeModel.cpp b/Viewer/src/TableNodeModel.cpp
new file mode 100644
index 0000000..1147139
--- /dev/null
+++ b/Viewer/src/TableNodeModel.cpp
@@ -0,0 +1,365 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "TableNodeModel.hpp"
+
+#include <QDebug>
+#include <QMetaMethod>
+
+#include "ModelColumn.hpp"
+#include "ServerHandler.hpp"
+#include "UserMessage.hpp"
+#include "VFilter.hpp"
+#include "VIcon.hpp"
+#include "VModelData.hpp"
+#include "VNode.hpp"
+#include "VNState.hpp"
+
+//#define _UI_TABLENODEMODEL_DEBUG
+
+//static int hitCount=0;
+
+//=======================================================
+//
+// TableNodeModel
+//
+//=======================================================
+
+
+TableNodeModel::TableNodeModel(ServerFilter* serverFilter,NodeFilterDef* filterDef,QObject *parent) :
+ AbstractNodeModel(parent),
+ data_(0),
+ columns_(0)
+{
+ columns_=ModelColumn::def("table_columns");
+
+ Q_ASSERT(columns_);
+
+ //Create the data handler for the model.
+ data_=new VTableModelData(filterDef,this);
+
+ data_->reset(serverFilter);
+}
+
+VModelData* TableNodeModel::data() const
+{
+ return data_;
+}
+
+int TableNodeModel::columnCount( const QModelIndex& /*parent */ ) const
+{
+ return columns_->count();
+}
+
+int TableNodeModel::rowCount( const QModelIndex& parent) const
+{
+#ifdef _UI_TABLENODEMODEL_DEBUG
+ //qDebug() << "rowCount" << parent;
+#endif
+
+ //There are no servers
+ if(!hasData())
+ {
+ return 0;
+ }
+ //We use only column 0
+ else if(parent.column() > 0)
+ {
+ return 0;
+ }
+ //"parent" is the root
+ else if(!parent.isValid())
+ {
+ //The total number of nodes displayed
+ int cnt=0;
+ for(int i=0; i < data_->count(); i++)
+ {
+ if(!data_->server(i)->inScan())
+ cnt+=data_->numOfNodes(i);
+ }
+#ifdef _UI_TABLENODEMODEL_DEBUG
+ //qDebug() << "table count" << cnt;
+#endif
+ return cnt;
+ }
+
+ return 0;
+}
+
+
+QVariant TableNodeModel::data( const QModelIndex& index, int role ) const
+{
+ //Data lookup can be costly so we immediately return a default value for all
+ //the cases where the default should be used.
+ if( !index.isValid() ||
+ (role != Qt::DisplayRole && role != Qt::ToolTipRole &&
+ role != Qt::BackgroundRole && role != IconRole))
+ {
+ return QVariant();
+ }
+
+ //We only display nodes!!
+ return nodeData(index,role);
+}
+
+QVariant TableNodeModel::nodeData(const QModelIndex& index, int role) const
+{
+ VNode* vnode=indexToNode(index);
+ if(!vnode || !vnode->node())
+ return QVariant();
+
+ if(role == Qt::DisplayRole)
+ {
+ QString id=columns_->id(index.column());
+
+ if(id == "path")
+ { return QString::fromStdString(vnode->absNodePath());
+ }
+ else if(id == "status")
+ return vnode->stateName();
+ else if(id == "type")
+ return QString::fromStdString(vnode->nodeType());
+
+ //Attributes
+ else if(id == "event" || id == "label" || id == "meter" || id == "trigger")
+ {
+ QStringList lst;
+ if(vnode->getAttributeData(id.toStdString(),0,lst))
+ return lst;
+ else
+ return QVariant();
+ }
+
+ else if(id == "icon")
+ return VIcon::pixmapList(vnode,0);
+ }
+ else if(role == Qt::BackgroundRole)
+ {
+ return vnode->stateColour();
+ }
+ else if(role == IconRole)
+ {
+ if(columns_->id(index.column()) =="path")
+ return VIcon::pixmapList(vnode,0);
+ else
+ return QVariant();
+ }
+
+ return QVariant();
+}
+
+QVariant TableNodeModel::headerData( const int section, const Qt::Orientation orient , const int role ) const
+{
+ if ( orient != Qt::Horizontal || (role != Qt::DisplayRole && role != Qt::UserRole ))
+ return QAbstractItemModel::headerData( section, orient, role );
+
+ if (section < 0 || section >= columns_->count()) // this can happen during a server reset
+ return QVariant();
+
+ if(role == Qt::DisplayRole)
+ return columns_->label(section);
+ else if(role == Qt::UserRole)
+ return columns_->id(section);
+
+ return QVariant();
+}
+
+
+QModelIndex TableNodeModel::index( int row, int column, const QModelIndex & parent ) const
+{
+ if(!hasData() || row < 0 || column < 0 || parent.isValid())
+ {
+ return QModelIndex();
+ }
+
+ if(VNode *node=data_->nodeAt(row))
+ {
+ return createIndex(row,column,node);
+ }
+
+ return QModelIndex();
+}
+
+QModelIndex TableNodeModel::parent(const QModelIndex& /*child*/) const
+{
+ //Parent is always the root!!!
+ return QModelIndex();
+}
+
+//----------------------------------------------
+//
+// Server to index mapping and lookup
+//
+//----------------------------------------------
+
+VNode* TableNodeModel::indexToNode( const QModelIndex & index) const
+{
+ if(index.isValid())
+ {
+ return static_cast<VNode*>(index.internalPointer());
+ }
+ return NULL;
+}
+
+QModelIndex TableNodeModel::nodeToIndex(const VNode* node, int column) const
+{
+ if(!node)
+ return QModelIndex();
+
+ int row=0;
+ if((row=data_->position(node)) != -1)
+ {
+ return createIndex(row,column,const_cast<VNode*>(node));
+ }
+ return QModelIndex();
+}
+
+
+//Find the index for the node when we know what the server is!
+QModelIndex TableNodeModel::nodeToIndex(VTableServer* server,const VNode* node, int column) const
+{
+ if(!node)
+ return QModelIndex();
+
+ int row=0;
+ if((row=data_->position(server,node)) != -1)
+ {
+ return createIndex(row,column,const_cast<VNode*>(node));
+ }
+ return QModelIndex();
+}
+
+VInfo_ptr TableNodeModel::nodeInfo(const QModelIndex& index)
+{
+ VNode *n=indexToNode(index);
+ if(n)
+ {
+ return VInfoNode::create(n);
+ }
+
+ VInfo_ptr info;
+ return info;
+}
+
+
+//Server is about to be added
+void TableNodeModel::slotServerAddBegin(int /*row*/)
+{
+}
+
+//Addition of the new server has finished
+void TableNodeModel::slotServerAddEnd()
+{
+}
+
+//Server is about to be removed
+void TableNodeModel::slotServerRemoveBegin(VModelServer* server,int num)
+{
+ Q_ASSERT(active_ == true);
+ Q_ASSERT(server);
+
+ if(num >0)
+ {
+ int start=-1;
+ int count=-1;
+ data_->position(server->tableServer(),start,count);
+
+ Q_ASSERT(start >=0);
+ Q_ASSERT(count == num);
+
+ beginRemoveRows(QModelIndex(),start,start+count-1);
+ }
+}
+
+//Removal of the server has finished
+void TableNodeModel::slotServerRemoveEnd(int num)
+{
+ assert(active_ == true);
+
+ if(num >0)
+ endRemoveRows();
+}
+
+//The node changed (it status etc)
+void TableNodeModel::slotNodeChanged(VTableServer* server,const VNode* node)
+{
+ if(!node)
+ return;
+
+ QModelIndex index=nodeToIndex(server,node,0);
+
+ if(!index.isValid())
+ return;
+
+ Q_EMIT dataChanged(index,index);
+}
+
+void TableNodeModel::slotBeginServerScan(VModelServer* server,int num)
+{
+ Q_ASSERT(active_ == true);
+ Q_ASSERT(server);
+
+#ifdef _UI_TABLENODEMODEL_DEBUG
+ UserMessage::debug("TableNodeModel::slotBeginServerScan --> " + server->realServer()->name() + " " + QString::number(num).toStdString());
+#endif
+
+ if(num >0)
+ {
+ int count=num;
+ int start=data_->position(server->tableServer());
+ beginInsertRows(QModelIndex(),start,start+count-1);
+ }
+}
+
+void TableNodeModel::slotEndServerScan(VModelServer* server,int num)
+{
+ assert(active_ == true);
+
+#ifdef _UI_TABLENODEMODEL_DEBUG
+ UserMessage::debug("TableNodeModel::slotEndServerScan --> " + server->realServer()->name() + " " + QString::number(num).toStdString());
+ QTime t;
+ t.start();
+#endif
+
+ if(num >0)
+ endInsertRows();
+
+#ifdef _UI_TABLENODEMODEL_DEBUG
+ UserMessage::debug(" elapsed: " + QString::number(t.elapsed()).toStdString() + " ms");
+ UserMessage::debug("<-- TableNodeModel::slotEndServerScan");
+
+ //qDebug() << "hit" << hitCount;
+#endif
+}
+
+void TableNodeModel::slotBeginServerClear(VModelServer* server,int num)
+{
+ Q_ASSERT(active_ == true);
+ Q_ASSERT(server);
+
+ if(num >0)
+ {
+ int start=-1;
+ int count=-1;
+ data_->position(server->tableServer(),start,count);
+
+ Q_ASSERT(start >=0);
+ Q_ASSERT(count == num);
+
+ beginRemoveRows(QModelIndex(),start,start+count-1);
+ }
+}
+
+void TableNodeModel::slotEndServerClear(VModelServer* server,int num)
+{
+ assert(active_ == true);
+
+ if(num >0)
+ endRemoveRows();
+}
diff --git a/Viewer/src/TableNodeModel.hpp b/Viewer/src/TableNodeModel.hpp
new file mode 100644
index 0000000..ac2d87a
--- /dev/null
+++ b/Viewer/src/TableNodeModel.hpp
@@ -0,0 +1,85 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef TABLENODEMODEL_H
+#define TABLENODEMODEL_H
+
+#include <QAbstractItemModel>
+
+#include "AbstractNodeModel.hpp"
+#include "VInfo.hpp"
+
+class ModelColumn;
+class Node;
+class NodeFilterDef;
+class ServerFilter;
+class ServerHandler;
+class VTableModelData;
+class VTableServer;
+
+class TableNodeModel : public AbstractNodeModel
+{
+Q_OBJECT
+
+ friend class TableNodeSortModel;
+
+public:
+ TableNodeModel(ServerFilter* serverFilter,NodeFilterDef* filterDef,QObject *parent=0);
+
+ int columnCount (const QModelIndex& parent = QModelIndex() ) const;
+ int rowCount (const QModelIndex& parent = QModelIndex() ) const;
+
+ QVariant data (const QModelIndex& , int role = Qt::DisplayRole ) const;
+ QVariant headerData(int,Qt::Orientation,int role = Qt::DisplayRole ) const;
+
+ QModelIndex index (int, int, const QModelIndex& parent = QModelIndex() ) const;
+ QModelIndex parent (const QModelIndex & ) const;
+
+ VInfo_ptr nodeInfo(const QModelIndex&);
+
+ VModelData* data() const;
+
+public Q_SLOTS:
+ void slotServerAddBegin(int);
+ void slotServerAddEnd();
+ void slotServerRemoveBegin(VModelServer* server,int);
+ void slotServerRemoveEnd(int);
+
+ void slotDataChanged(VModelServer*) {}
+ void slotNodeChanged(VTableServer*,const VNode*);
+ void slotAttributesChanged(VModelServer*,const VNode*) {}
+ void slotBeginAddRemoveAttributes(VModelServer*,const VNode*,int,int) {}
+ void slotEndAddRemoveAttributes(VModelServer*,const VNode*,int,int) {}
+
+ void slotBeginServerScan(VModelServer* server,int);
+ void slotEndServerScan(VModelServer* server,int);
+ void slotBeginServerClear(VModelServer* server,int);
+ void slotEndServerClear(VModelServer* server,int);
+
+Q_SIGNALS:
+ void filterChangeBegun();
+ void filterChangeEnded();
+
+protected:
+ bool isServer(const QModelIndex & index) const {return false;}
+ ServerHandler* indexToRealServer(const QModelIndex & index) const {return NULL;}
+ VModelServer* indexToServer(const QModelIndex & index) const {return NULL;}
+ QModelIndex serverToIndex(ServerHandler*) const {return QModelIndex();}
+
+ QModelIndex nodeToIndex(VTableServer* server,const VNode* node, int column) const;
+ QModelIndex nodeToIndex(const VNode*,int column=0) const;
+ VNode* indexToNode( const QModelIndex & index) const;
+
+ QVariant nodeData(const QModelIndex& index,int role) const;
+
+ VTableModelData* data_;
+ ModelColumn* columns_;
+};
+
+#endif
diff --git a/Viewer/src/TableNodeSortModel.cpp b/Viewer/src/TableNodeSortModel.cpp
new file mode 100644
index 0000000..c33bf94
--- /dev/null
+++ b/Viewer/src/TableNodeSortModel.cpp
@@ -0,0 +1,52 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "TableNodeSortModel.hpp"
+
+#include "TableNodeModel.hpp"
+
+TableNodeSortModel::TableNodeSortModel(TableNodeModel* nodeModel,QObject *parent) :
+ QSortFilterProxyModel(parent),
+ nodeModel_(nodeModel)
+{
+ //connect(nodeModel_,SIGNAL(filterChanged()),
+ // this,SLOT(slotFilterChanged()));
+
+ QSortFilterProxyModel::setSourceModel(nodeModel_);
+
+ setDynamicSortFilter(false);
+}
+
+TableNodeSortModel::~TableNodeSortModel()
+{
+}
+
+VInfo_ptr TableNodeSortModel::nodeInfo(const QModelIndex& index)
+{
+ return nodeModel_->nodeInfo(mapToSource(index));
+}
+
+QModelIndex TableNodeSortModel::infoToIndex(VInfo_ptr info)
+{
+ return mapFromSource(nodeModel_->infoToIndex(info));
+}
+
+QModelIndex TableNodeSortModel::nodeToIndex(const VNode *node)
+{
+ return mapFromSource(nodeModel_->nodeToIndex(node));
+}
+
+bool TableNodeSortModel::lessThan(const QModelIndex &left,
+ const QModelIndex &right) const
+{
+ QVariant leftData = nodeModel_->data(left);
+ QVariant rightData = nodeModel_->data(right);
+
+ return leftData.toString() < rightData.toString();
+}
diff --git a/Viewer/src/TableNodeSortModel.hpp b/Viewer/src/TableNodeSortModel.hpp
new file mode 100644
index 0000000..7fd9619
--- /dev/null
+++ b/Viewer/src/TableNodeSortModel.hpp
@@ -0,0 +1,41 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef TABLENODEFILTERMODEL_H
+#define TABLENODEFILTERMODEL_H
+
+#include <QSortFilterProxyModel>
+
+#include "VInfo.hpp"
+
+class TableNodeModel;
+class NodeFilterDef;
+
+class TableNodeSortModel : public QSortFilterProxyModel
+{
+public:
+ TableNodeSortModel(TableNodeModel*,QObject *parent=0);
+ ~TableNodeSortModel();
+
+ //From QSortFilterProxyModel:
+ //we set the source model in the constructor. So this function should not do anything.
+ void setSourceModel(QAbstractItemModel*) {}
+
+ VInfo_ptr nodeInfo(const QModelIndex&);
+ QModelIndex infoToIndex(VInfo_ptr);
+ QModelIndex nodeToIndex(const VNode *node);
+
+protected:
+ bool lessThan(const QModelIndex &left,
+ const QModelIndex &right) const;
+
+ TableNodeModel* nodeModel_;
+};
+
+#endif
diff --git a/Viewer/src/TableNodeView.cpp b/Viewer/src/TableNodeView.cpp
new file mode 100644
index 0000000..ce16512
--- /dev/null
+++ b/Viewer/src/TableNodeView.cpp
@@ -0,0 +1,606 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "TableNodeView.hpp"
+
+#include <QtGlobal>
+#include <QComboBox>
+#include <QDebug>
+#include <QHBoxLayout>
+#include <QHeaderView>
+#include <QMenu>
+#include <QMouseEvent>
+#include <QPainter>
+#include <QScrollBar>
+#include <QStyle>
+#include <QToolButton>
+
+#include "ActionHandler.hpp"
+#include "FilterWidget.hpp"
+#include "IconProvider.hpp"
+#include "TableNodeSortModel.hpp"
+#include "PropertyMapper.hpp"
+#include "TableNodeModel.hpp"
+#include "TableNodeViewDelegate.hpp"
+#include "VFilter.hpp"
+#include "VSettings.hpp"
+
+TableNodeView::TableNodeView(TableNodeSortModel* model,NodeFilterDef* filterDef,QWidget* parent) :
+ QTreeView(parent),
+ NodeViewBase(filterDef),
+ model_(model),
+ needItemsLayout_(false),
+ prop_(NULL)
+{
+ setProperty("style","nodeView");
+ setProperty("view","table");
+
+ setRootIsDecorated(false);
+
+ setSortingEnabled(true);
+ //sortByColumn(0,Qt::AscendingOrder);
+
+ setAllColumnsShowFocus(true);
+ setUniformRowHeights(true);
+ setMouseTracking(true);
+ setSelectionMode(QAbstractItemView::ExtendedSelection);
+
+ //!!!!We need to do it because:
+ //The background colour between the views left border and the nodes cannot be
+ //controlled by delegates or stylesheets. It always takes the QPalette::Highlight
+ //colour from the palette. Here we set this to transparent so that Qt could leave
+ //this area empty and we fill it appropriately in our delegate.
+ QPalette pal=palette();
+ pal.setColor(QPalette::Highlight,QColor(128,128,128,0));
+ setPalette(pal);
+
+ //Context menu
+ setContextMenuPolicy(Qt::CustomContextMenu);
+
+ connect(this, SIGNAL(customContextMenuRequested(const QPoint &)),
+ this, SLOT(slotContextMenu(const QPoint &)));
+
+ //Selection
+ connect(this,SIGNAL(clicked(const QModelIndex&)),
+ this,SLOT(slotSelectItem(const QModelIndex)));
+
+ connect(this,SIGNAL(doubleClicked(const QModelIndex&)),
+ this,SLOT(slotDoubleClickItem(const QModelIndex)));
+
+ actionHandler_=new ActionHandler(this);
+
+ //expandAll();
+
+ //Header
+ header_=new TableNodeHeader(this);
+
+ setHeader(header_);
+
+ //Set header ContextMenuPolicy
+ header_->setContextMenuPolicy(Qt::CustomContextMenu);
+
+ connect(header_,SIGNAL(customContextMenuRequested(const QPoint &)),
+ this, SLOT(slotHeaderContextMenu(const QPoint &)));
+
+ connect(header_,SIGNAL(customButtonClicked(QString,QPoint)),
+ this,SIGNAL(headerButtonClicked(QString,QPoint)));
+
+ //for(int i=0; i < model_->columnCount(QModelIndex())-1; i++)
+ // resizeColumnToContents(i);
+
+ /*connect(header(),SIGNAL(sectionMoved(int,int,int)),
+ this, SLOT(slotMessageTreeColumnMoved(int,int,int)));*/
+
+ QTreeView::setModel(model_);
+
+ //Create delegate to the view
+ TableNodeViewDelegate *delegate=new TableNodeViewDelegate(this);
+ setItemDelegate(delegate);
+
+ connect(delegate,SIGNAL(sizeHintChangedGlobal()),
+ this,SLOT(slotSizeHintChangedGlobal()));
+
+ //Properties
+ std::vector<std::string> propVec;
+ propVec.push_back("view.table.background");
+ prop_=new PropertyMapper(propVec,this);
+
+ //Initialise bg
+ adjustBackground(prop_->find("view.table.background")->value().value<QColor>());
+}
+
+TableNodeView::~TableNodeView()
+{
+ delete prop_;
+}
+
+void TableNodeView::setModel(TableNodeSortModel *model)
+{
+ model_= model;
+
+ //Set the model.
+ QTreeView::setModel(model_);
+}
+
+QWidget* TableNodeView::realWidget()
+{
+ return this;
+}
+
+//Collects the selected list of indexes
+QModelIndexList TableNodeView::selectedList()
+{
+ QModelIndexList lst;
+ Q_FOREACH(QModelIndex idx,selectedIndexes())
+ if(idx.column() == 0)
+ lst << idx;
+ return lst;
+}
+
+void TableNodeView::slotSelectItem(const QModelIndex&)
+{
+ QModelIndexList lst=selectedIndexes();
+ if(lst.count() > 0)
+ {
+ VInfo_ptr info=model_->nodeInfo(lst.front());
+ if(info && !info->isEmpty())
+ {
+ Q_EMIT selectionChanged(info);
+ }
+ }
+}
+
+VInfo_ptr TableNodeView::currentSelection()
+{
+ QModelIndexList lst=selectedIndexes();
+ if(lst.count() > 0)
+ {
+ return model_->nodeInfo(lst.front());
+ }
+ return VInfo_ptr();
+}
+
+void TableNodeView::slotDoubleClickItem(const QModelIndex&)
+{
+}
+
+void TableNodeView::slotContextMenu(const QPoint &position)
+{
+ QModelIndexList lst=selectedList();
+ //QModelIndex index=indexAt(position);
+ QPoint scrollOffset(horizontalScrollBar()->value(),verticalScrollBar()->value());
+
+ handleContextMenu(indexAt(position),lst,mapToGlobal(position),position+scrollOffset,this);
+}
+
+
+void TableNodeView::handleContextMenu(QModelIndex indexClicked,QModelIndexList indexLst,QPoint globalPos,QPoint widgetPos,QWidget *widget)
+{
+ //Node actions
+ if(indexClicked.isValid() && indexClicked.column() == 0) //indexLst[0].isValid() && indexLst[0].column() == 0)
+ {
+ qDebug() << "context menu" << indexClicked;
+
+ std::vector<VInfo_ptr> nodeLst;
+ for(int i=0; i < indexLst.count(); i++)
+ {
+ VInfo_ptr info=model_->nodeInfo(indexLst[i]);
+ if(!info->isEmpty())
+ nodeLst.push_back(info);
+ }
+
+ actionHandler_->contextMenu(nodeLst,globalPos);
+ }
+
+ //Desktop actions
+ else
+ {
+ }
+}
+
+void TableNodeView::slotViewCommand(std::vector<VInfo_ptr> nodeLst,QString cmd)
+{
+
+ if(nodeLst.size() == 0)
+ return;
+
+ if(cmd == "set_as_root")
+ {
+ qDebug() << "set as root";
+ //model_->setRootNode(nodeLst.at(0)->node());
+ //expandAll();
+ }
+}
+
+void TableNodeView::rerender()
+{
+ if(needItemsLayout_)
+ {
+ doItemsLayout();
+ needItemsLayout_=false;
+ }
+ else
+ {
+ viewport()->update();
+ }
+}
+
+void TableNodeView::slotRerender()
+{
+ rerender();
+}
+
+void TableNodeView::slotSizeHintChangedGlobal()
+{
+ needItemsLayout_=true;
+}
+
+void TableNodeView::adjustBackground(QColor col)
+{
+ if(col.isValid())
+ {
+ QString sh="QTreeView { background : " + col.name() + ";}";
+ setStyleSheet(sh);
+ }
+}
+
+void TableNodeView::notifyChange(VProperty* p)
+{
+ if(p->path() == "view.table.background")
+ {
+ adjustBackground(p->value().value<QColor>());
+ }
+}
+
+//=========================================
+// Header
+//=========================================
+
+void TableNodeView::slotHeaderContextMenu(const QPoint &position)
+{
+ int section=header_->logicalIndexAt(position);
+
+ if(section< 0 || section >= header_->count())
+ return;
+
+ QList<QAction*> lst;
+ QMenu *menu=new QMenu(this);
+ QAction *ac;
+
+ for(int i=0; i <header_->count(); i++)
+ {
+ QString name=header_->model()->headerData(i,Qt::Horizontal).toString();
+ ac=new QAction(menu);
+ ac->setText(name);
+ ac->setCheckable(true);
+ ac->setData(i);
+
+ if(i==0)
+ {
+ ac->setChecked(true);
+ ac->setEnabled(false);
+ }
+ else
+ {
+ ac->setChecked(!(header_->isSectionHidden(i)));
+ }
+
+ menu->addAction(ac);
+ }
+
+
+ //stateFilterMenu_=new StateFilterMenu(menuState,filter_->menu());
+ //VParamFilterMenu stateFilterMenu(menu,filterDef_->nodeState(),VParamFilterMenu::ColourDecor);
+
+ ac=menu->exec(header_->mapToGlobal(position));
+ if(ac && ac->isEnabled() && ac->isCheckable())
+ {
+ int i=ac->data().toInt();
+ header_->setSectionHidden(i,!ac->isChecked());
+ //MvQDesktopSettings::headerVisible_[i]=ac->isChecked();
+ //broadcastHeaderChange();
+ }
+ delete menu;
+}
+
+void TableNodeView::readSettings(VSettings* vs)
+{
+ std::vector<std::string> array;
+ vs->get("columns",array);
+
+ for(std::vector<std::string>::const_iterator it = array.begin(); it != array.end(); ++it)
+ {
+ std::string id=*it;
+ for(int i=0; i < model_->columnCount(QModelIndex()); i++)
+ {
+ if(model_->headerData(i,Qt::Horizontal,Qt::UserRole).toString().toStdString() == id)
+ {
+ header()->setSectionHidden(i,false);
+ break;
+ }
+ }
+ }
+}
+
+
+//=========================================
+// TableNodeHeader
+//=========================================
+
+TableNodeHeader::TableNodeHeader(QWidget *parent) : QHeaderView(Qt::Horizontal, parent)
+{
+ setStretchLastSection(true);
+
+ connect(this, SIGNAL(sectionResized(int, int, int)),
+ this, SLOT(slotSectionResized(int)));
+
+ int pixId=IconProvider::add(":viewer/filter_decor.svg","filter_decor");
+
+ customPix_=IconProvider::pixmap(pixId,10);
+
+
+ //connect(this, SIGNAL(sectionMoved(int, int, int)), this,
+ // SLOT(handleSectionMoved(int, int, int)));
+
+ //setMovable(true);
+}
+
+void TableNodeHeader::showEvent(QShowEvent *e)
+{
+ /* for(int i=0;i<count();i++)
+ {
+
+
+ if(1)
+ {
+ widgets_[i]->setGeometry(sectionViewportPosition(i),0,
+ sectionSize(i),height());
+ widgets_[i]->show();
+ }
+ }
+ */
+
+ QHeaderView::showEvent(e);
+}
+
+void TableNodeHeader::slotSectionResized(int i)
+{
+ /*for (int j=visualIndex(i);j<count();j++)
+ {
+ int logical = logicalIndex(j);
+
+ if(combo_[logical])
+ {
+ combo_[logical]->setGeometry(sectionViewportPosition(logical), height()/2,
+ sectionSize(logical) - 16, height());
+ }
+ }*/
+}
+
+QSize TableNodeHeader::sizeHint() const
+{
+ return QHeaderView::sizeHint();
+
+ QSize s = size();
+ //s.setHeight(headerSections[0]->minimumSizeHint().height() + 35);
+ //s.setHeight(2*35);
+ return s;
+}
+
+void TableNodeHeader::setModel(QAbstractItemModel *model)
+{
+ if(model)
+ {
+ for(int i=0; i< model->columnCount(); i++)
+ {
+ QString id=model->headerData(i,Qt::Horizontal,Qt::UserRole).toString();
+ if(id == "status")
+ customButton_.insert(i,TableNodeHeaderButton(id));
+ }
+ }
+ QHeaderView::setModel(model);
+}
+
+void TableNodeHeader::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
+{
+ painter->save();
+ //QHeaderView::paintSection(painter, rect, logicalIndex);
+ //painter->restore();
+
+
+ /*QPixmap customPix(":viewer/filter_decor.svg");
+ QRect cbRect(0,0,12,12);
+ cbRect.moveCenter(QPoint(rect.right()-16-6,rect.center().y()));
+ customButton_[logicalIndex].setRect(cbRect);
+ painter->drawPixmap(cbRect,pix);*/
+
+ if (!rect.isValid())
+ return;
+
+ QStyleOptionHeader opt;
+ initStyleOption(&opt);
+ QStyle::State state = QStyle::State_None;
+ if(isEnabled())
+ state |= QStyle::State_Enabled;
+ if(window()->isActiveWindow())
+ state |= QStyle::State_Active;
+
+ bool clickable;
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+ clickable=sectionsClickable();
+#else
+ clickable=isClickable();
+#endif
+
+ if(clickable)
+ {
+ /*if (logicalIndex == d->hover)
+ state |= QStyle::State_MouseOver;
+ if (logicalIndex == d->pressed)
+ state |= QStyle::State_Sunken;
+ else if (d->highlightSelected) {
+ if (d->sectionIntersectsSelection(logicalIndex))
+ state |= QStyle::State_On;
+ if (d->isSectionSelected(logicalIndex))
+ state |= QStyle::State_Sunken;
+ }*/
+
+ }
+
+ // if(isSortIndicatorShown() && sortIndicatorSection() == logicalIndex)
+ // opt.sortIndicator = (sortIndicatorOrder() == Qt::AscendingOrder)
+ // ? QStyleOptionHeader::SortDown : QStyleOptionHeader::SortUp;
+
+ // setup the style options structure
+ //QVariant textAlignment = model->headerData(logicalIndex, d->orientation,
+ // Qt::TextAlignmentRole);
+ opt.rect = rect;
+ opt.section = logicalIndex;
+ opt.state |= state;
+ //opt.textAlignment = Qt::Alignment(textAlignment.isValid()
+ // ? Qt::Alignment(textAlignment.toInt())
+ // : d->defaultAlignment);
+
+ //opt.text = model()->headerData(logicalIndex, Qt::Horizontal),
+ // Qt::DisplayRole).toString();
+
+ QVariant foregroundBrush;
+ if (foregroundBrush.canConvert<QBrush>())
+ opt.palette.setBrush(QPalette::ButtonText, qvariant_cast<QBrush>(foregroundBrush));
+
+ QPointF oldBO = painter->brushOrigin();
+ QVariant backgroundBrush;
+ if (backgroundBrush.canConvert<QBrush>())
+ {
+ opt.palette.setBrush(QPalette::Button, qvariant_cast<QBrush>(backgroundBrush));
+ opt.palette.setBrush(QPalette::Window, qvariant_cast<QBrush>(backgroundBrush));
+ painter->setBrushOrigin(opt.rect.topLeft());
+ }
+
+ // the section position
+ int visual = visualIndex(logicalIndex);
+ assert(visual != -1);
+
+ if (count() == 1)
+ opt.position = QStyleOptionHeader::OnlyOneSection;
+ else if (visual == 0)
+ opt.position = QStyleOptionHeader::Beginning;
+ else if (visual == count() - 1)
+ opt.position = QStyleOptionHeader::End;
+ else
+ opt.position = QStyleOptionHeader::Middle;
+
+ opt.orientation = Qt::Horizontal;
+
+ // the selected position
+ /*bool previousSelected = d->isSectionSelected(logicalIndex(visual - 1));
+ bool nextSelected = d->isSectionSelected(logicalIndex(visual + 1));
+ if (previousSelected && nextSelected)
+ opt.selectedPosition = QStyleOptionHeader::NextAndPreviousAreSelected;
+ else if (previousSelected)
+ opt.selectedPosition = QStyleOptionHeader::PreviousIsSelected;
+ else if (nextSelected)
+ opt.selectedPosition = QStyleOptionHeader::NextIsSelected;
+ else
+ opt.selectedPosition = QStyleOptionHeader::NotAdjacent;
+ */
+
+ // draw the section
+ style()->drawControl(QStyle::CE_Header, &opt, painter, this);
+ painter->setBrushOrigin(oldBO);
+
+ painter->restore();
+
+
+ int rightPos=rect.right();
+ if(isSortIndicatorShown() && sortIndicatorSection() == logicalIndex)
+ opt.sortIndicator = (sortIndicatorOrder() == Qt::AscendingOrder)
+ ? QStyleOptionHeader::SortDown : QStyleOptionHeader::SortUp;
+ if (opt.sortIndicator != QStyleOptionHeader::None)
+ {
+ QStyleOptionHeader subopt = opt;
+ subopt.rect = style()->subElementRect(QStyle::SE_HeaderArrow, &opt, this);
+ rightPos=subopt.rect.left();
+ style()->drawPrimitive(QStyle::PE_IndicatorHeaderArrow, &subopt, painter, this);
+ }
+
+
+ QMap<int,TableNodeHeaderButton>::iterator it=customButton_.find(logicalIndex);
+ if(it != customButton_.end())
+ {
+ //Custom button
+ QStyleOptionButton optButton;
+
+ //visPbOpt.text="Visualise";
+ optButton.state = QStyle::State_AutoRaise ; //QStyle::State_Active | QStyle::State_Enabled;
+ //optButton.icon=customIcon_;
+ //optButton.iconSize=QSize(12,12);
+
+ int buttonWidth=customPix_.width();
+ int buttonHeight=buttonWidth;
+ optButton.rect = QRect(rightPos-4-buttonWidth,(rect.height()-buttonWidth)/2,
+ buttonWidth,buttonHeight);
+
+ painter->drawPixmap(optButton.rect,customPix_);
+
+ rightPos=optButton.rect.left();
+ it.value().setRect(optButton.rect);
+ }
+
+ QString text=model()->headerData(logicalIndex,Qt::Horizontal).toString();
+ QRect textRect=rect;
+ textRect.setRight(rightPos-5);
+
+ painter->drawText(textRect,Qt::AlignHCenter | Qt::AlignVCenter,text);
+
+
+ //style()->drawControl(QStyle::CE_PushButton, &optButton,painter,this);
+}
+
+void TableNodeHeader::mousePressEvent(QMouseEvent *event)
+{
+ QMap<int,TableNodeHeaderButton>::const_iterator it = customButton_.constBegin();
+ while(it != customButton_.constEnd())
+ {
+ if(it.value().rect_.contains(event->pos()))
+ {
+ qDebug() << "header" << it.key() << "clicked";
+ Q_EMIT customButtonClicked(it.value().id(),event->globalPos());
+ }
+ ++it;
+ }
+
+ QHeaderView::mousePressEvent(event);
+}
+
+/*void TableNodeHeader::mouseMoveEvent(QMouseEvent *event)
+{
+ int prevIndex=hoverIndex_;
+ QMap<int,TableNodeHeaderButton>::const_iterator it = customButton_.constBegin();
+ while(it != customButton_.constEnd())
+ {
+ if(it.value().rect_.contains(event->pos()))
+ {
+ hoverIndex_=it.key();
+ if(hoveIndex != prevIndex)
+ {
+ rerender;
+ }
+ }
+ ++it;
+ }
+
+ if(preIndex !=-1)
+ {
+
+ }
+ hoverIndex_=-1;
+}*/
+
diff --git a/Viewer/src/TableNodeView.hpp b/Viewer/src/TableNodeView.hpp
new file mode 100644
index 0000000..877f40b
--- /dev/null
+++ b/Viewer/src/TableNodeView.hpp
@@ -0,0 +1,122 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef TABLENODEVIEW_HPP_
+#define TABLENODEVIEW_HPP_
+
+#include <QHeaderView>
+#include <QTreeView>
+
+#include "NodeViewBase.hpp"
+
+#include "VInfo.hpp"
+#include "VProperty.hpp"
+
+class QComboBox;
+
+class ActionHandler;
+class TableNodeModel;
+class TableNodeSortModel;
+class NodeFilterDef;
+class PropertyMapper;
+class TableNodeHeader;
+
+class TableNodeView : public QTreeView, public NodeViewBase, public VPropertyObserver
+{
+Q_OBJECT
+
+public:
+
+ explicit TableNodeView(TableNodeSortModel* model,NodeFilterDef* filterDef,QWidget *parent=0);
+ ~TableNodeView();
+
+ void reload() {}
+ void rerender();
+ QWidget* realWidget();
+ VInfo_ptr currentSelection();
+ void currentSelection(VInfo_ptr n) {}
+ void selectFirstServer() {}
+ void setModel(TableNodeSortModel *model);
+
+ void notifyChange(VProperty* p);
+
+ void readSettings(VSettings* vs);
+
+public Q_SLOTS:
+ void slotSelectItem(const QModelIndex&);
+ void slotDoubleClickItem(const QModelIndex&);
+ void slotContextMenu(const QPoint &position);
+ void slotViewCommand(std::vector<VInfo_ptr>,QString);
+ void slotHeaderContextMenu(const QPoint &position);
+ void slotSizeHintChangedGlobal();
+ void slotRerender();
+ void slotViewCommand(VInfo_ptr,QString) {}
+ void slotSetCurrent(VInfo_ptr) {}
+
+Q_SIGNALS:
+ void selectionChanged(VInfo_ptr);
+ void infoPanelCommand(VInfo_ptr,QString);
+ void dashboardCommand(VInfo_ptr,QString);
+ void headerButtonClicked(QString,QPoint);
+
+protected:
+ QModelIndexList selectedList();
+ void handleContextMenu(QModelIndex indexClicked,QModelIndexList indexLst,QPoint globalPos,QPoint widgetPos,QWidget *widget);
+ void adjustBackground(QColor col);
+
+ TableNodeSortModel* model_;
+ ActionHandler* actionHandler_;
+ TableNodeHeader* header_;
+ bool needItemsLayout_;
+ PropertyMapper* prop_;
+};
+
+class TableNodeHeaderButton
+{
+public:
+ TableNodeHeaderButton(QString id) : id_(id) {}
+
+ QString id() const {return id_;}
+ void setRect(QRect r) {rect_=r;}
+ QRect rect() const {return rect_;}
+
+ QString id_;
+ QRect rect_;
+};
+
+class TableNodeHeader : public QHeaderView
+{
+Q_OBJECT
+
+public:
+ explicit TableNodeHeader(QWidget *parent=0);
+
+ QSize sizeHint() const;
+ void setModel(QAbstractItemModel *model);
+
+public Q_SLOTS:
+ void slotSectionResized(int i);
+
+Q_SIGNALS:
+ void customButtonClicked(QString,QPoint);
+
+protected:
+ void showEvent(QShowEvent *QSize);
+ void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const;
+ void mousePressEvent(QMouseEvent *event);
+
+ QPixmap customPix_;
+ mutable QMap<int,TableNodeHeaderButton> customButton_;
+};
+
+#endif
+
+
+
diff --git a/Viewer/src/TableNodeViewDelegate.cpp b/Viewer/src/TableNodeViewDelegate.cpp
new file mode 100644
index 0000000..ebc0a31
--- /dev/null
+++ b/Viewer/src/TableNodeViewDelegate.cpp
@@ -0,0 +1,255 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "TableNodeViewDelegate.hpp"
+
+#include <QApplication>
+#include <QDebug>
+#include <QImageReader>
+#include <QPainter>
+
+#include <QStyleOptionViewItem>
+
+#include "AbstractNodeModel.hpp"
+#include "Animation.hpp"
+#include "IconProvider.hpp"
+#include "ModelColumn.hpp"
+#include "PropertyMapper.hpp"
+
+static std::vector<std::string> propVec;
+
+TableNodeViewDelegate::TableNodeViewDelegate(QWidget *parent)
+{
+ borderPen_=QPen(QColor(230,230,230));
+
+ columns_=ModelColumn::def("table_columns");
+
+ adjustIconSize();
+
+ //Property
+ if(propVec.empty())
+ {
+ propVec.push_back("view.table.font");
+
+ //Base settings
+ addBaseSettings(propVec);
+ }
+
+ prop_=new PropertyMapper(propVec,this);
+
+ updateSettings();
+}
+
+TableNodeViewDelegate::~TableNodeViewDelegate()
+{
+}
+
+void TableNodeViewDelegate::updateSettings()
+{
+ if(VProperty* p=prop_->find("view.table.font"))
+ {
+ QFont newFont=p->value().value<QFont>();
+
+ if(font_ != newFont)
+ {
+ font_=newFont;
+ attrFont_=newFont;
+ Q_EMIT sizeHintChangedGlobal();
+ }
+ }
+
+ //Update the settings handled by the base class
+ updateBaseSettings();
+}
+
+void TableNodeViewDelegate::paint(QPainter *painter,const QStyleOptionViewItem &option,
+ const QModelIndex& index) const
+{
+ //Background
+ QStyleOptionViewItemV4 vopt(option);
+ initStyleOption(&vopt, index);
+
+ const QStyle *style = vopt.widget ? vopt.widget->style() : QApplication::style();
+ const QWidget* widget = vopt.widget;
+
+ //Save painter state
+ painter->save();
+
+ //Selection - we only do it once
+ /*if(index.column() == 0)
+ {
+ QRect fullRect=QRect(0,option.rect.y(),painter->device()->width(),option.rect.height());
+
+ if(option.state & QStyle::State_Selected)
+ {
+ //QRect fillRect=option.rect.adjusted(0,1,-1,-textRect.height()-1);
+ painter->fillRect(fullRect,selectBrush_);
+ painter->setPen(selectPen_);
+ painter->drawLine(fullRect.topLeft(),fullRect.topRight());
+ painter->drawLine(fullRect.bottomLeft(),fullRect.bottomRight());
+ }
+ else if(option.state & QStyle::State_MouseOver)
+ {
+ //QRect fillRect=option.rect.adjusted(0,1,-1,-1);
+ painter->fillRect(fullRect,hoverBrush_);
+ painter->setPen(hoverPen_);
+ painter->drawLine(fullRect.topLeft(),fullRect.topRight());
+ painter->drawLine(fullRect.bottomLeft(),fullRect.bottomRight());
+ }
+ }*/
+
+ //Different background for lost connection?
+ /* if(index.data(AbstractNodeModel::ConnectionRole).toInt() == 0)
+ {
+ QRect fullRect=QRect(0,option.rect.y(),painter->device()->width(),option.rect.height());
+ painter->fillRect(fullRect,lostConnectBgBrush_);
+ QRect bandRect=QRect(0,option.rect.y(),5,option.rect.height());
+ painter->fillRect(bandRect,lostConnectBandBrush_);
+
+ }*/
+
+ QString id=columns_->id(index.column());
+
+
+ if(id == "path")
+ {
+ QString text=index.data(Qt::DisplayRole).toString();
+ renderNode(painter,index,vopt,text);
+ }
+ else if(id == "status")
+ {
+ renderStatus(painter,index,vopt);
+ }
+
+ //Render attributes
+ else if(id == "event" || id == "label" || id == "meter" || id == "trigger")
+ {
+ QVariant va=index.data(Qt::DisplayRole);
+ if(va.type() == QVariant::StringList)
+ {
+ QStringList lst=va.toStringList();
+ if(lst.count() > 0)
+ {
+ QMap<QString,AttributeRendererProc>::const_iterator it=attrRenderers_.find(lst.at(0));
+ if(it != attrRenderers_.end())
+ {
+ AttributeRendererProc a=it.value();
+ (this->*a)(painter,lst,vopt);
+ }
+ }
+ }
+ }
+
+ //rest of the columns
+ else
+ {
+ QString text=index.data(Qt::DisplayRole).toString();
+ QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &vopt, widget);
+ painter->setFont(font_);
+ painter->setPen(Qt::black);
+ painter->drawText(textRect,Qt::AlignLeft | Qt::AlignVCenter,text);
+ }
+
+ //Render the horizontal border for rows. We only render the top border line.
+ //With this technique we miss the bottom border line of the last row!!!
+ //QRect fullRect=QRect(0,option.rect.y(),painter->device()->width(),option.rect.height());
+ QRect bgRect=option.rect;
+ painter->setPen(borderPen_);
+ painter->drawLine(bgRect.topLeft(),bgRect.topRight());
+
+
+ painter->restore();
+}
+
+
+
+void TableNodeViewDelegate::renderNode(QPainter *painter,const QModelIndex& index,
+ const QStyleOptionViewItemV4& option,QString text) const
+{
+ bool selected=option.state & QStyle::State_Selected;
+
+ int offset=4;
+
+ QFontMetrics fm(font_);
+ int deltaH=(option.rect.height()-(fm.height()+4))/2;
+
+ //The initial filled rect (we will adjust its width)
+ QRect fillRect=option.rect.adjusted(offset,deltaH,0,-deltaH-1);
+ if(selected)
+ fillRect.adjust(0,0,0,0);
+
+ //The text rectangle
+ QRect textRect = fillRect.adjusted(offset,0,0,0);
+
+ int textWidth=fm.width(text);
+ textRect.setWidth(textWidth);
+
+ //Adjust the filled rect width
+ fillRect.setRight(textRect.right()+offset);
+
+ int currentRight=fillRect.right();
+
+ //Icons area
+ QList<QPixmap> pixLst;
+ QList<QRect> pixRectLst;
+ QVariant va=index.data(AbstractNodeModel::IconRole);
+ if(va.type() == QVariant::List)
+ {
+ QVariantList lst=va.toList();
+ int xp=currentRight+5;
+ int yp=textRect.center().y()-iconSize_/2;
+ for(int i=0; i < lst.count(); i++)
+ {
+ int id=lst[i].toInt();
+ if(id != -1)
+ {
+ pixLst << IconProvider::pixmap(id,iconSize_);
+ pixRectLst << QRect(xp,yp,pixLst.back().width(),pixLst.back().height());
+ xp+=pixLst.back().width()+2;
+ }
+ }
+
+ if(!pixRectLst.isEmpty())
+ currentRight=pixRectLst.back().right();
+ }
+
+ //Define clipping
+ int rightPos=currentRight+1;
+ const bool setClipRect = rightPos > option.rect.right();
+ if(setClipRect)
+ {
+ painter->save();
+ painter->setClipRect(option.rect);
+ }
+
+ //Draw text
+ QColor fg=index.data(Qt::ForegroundRole).value<QColor>();
+ painter->setPen(fg);
+ painter->setFont(font_);
+ painter->drawText(textRect,Qt::AlignLeft | Qt::AlignVCenter,text);
+
+
+ if(selected)
+ {
+ painter->setPen(nodeSelectPen_);
+ QRect selRect=textRect.adjusted(-2,0,2,0);
+ painter->drawRect(selRect);
+ }
+
+ //Draw icons
+ for(int i=0; i < pixLst.count(); i++)
+ {
+ painter->drawPixmap(pixRectLst[i],pixLst[i]);
+ }
+
+ if(setClipRect)
+ {
+ painter->restore();
+ }
+}
diff --git a/Viewer/src/TableNodeViewDelegate.hpp b/Viewer/src/TableNodeViewDelegate.hpp
new file mode 100644
index 0000000..ee090c4
--- /dev/null
+++ b/Viewer/src/TableNodeViewDelegate.hpp
@@ -0,0 +1,51 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef TABLENODEVIEWDELEGATE_HPP
+#define TABLENODEVIEWDELEGATE_HPP
+
+#include <QBrush>
+#include <QMap>
+#include <QPen>
+#include <QStyledItemDelegate>
+#include <QStyleOptionViewItem>
+
+#include "NodeViewDelegate.hpp"
+#include "VProperty.hpp"
+
+#include <string>
+
+class ModelColumn;
+
+class TableNodeViewDelegate : public NodeViewDelegate
+{
+ Q_OBJECT
+public:
+ explicit TableNodeViewDelegate(QWidget *parent=0);
+ ~TableNodeViewDelegate();
+
+ void paint(QPainter *painter,const QStyleOptionViewItem &option,
+ const QModelIndex& index) const;
+
+Q_SIGNALS:
+ void sizeHintChangedGlobal();
+
+protected:
+ void updateSettings();
+
+ void renderNode(QPainter *painter,const QModelIndex& index,
+ const QStyleOptionViewItemV4& option,QString text) const;
+
+ ModelColumn* columns_;
+ QPen borderPen_;
+};
+
+#endif // TABLENODEVIEWDELEGATE_HPP
+
diff --git a/Viewer/src/TableNodeWidget.cpp b/Viewer/src/TableNodeWidget.cpp
new file mode 100644
index 0000000..c6d0dbf
--- /dev/null
+++ b/Viewer/src/TableNodeWidget.cpp
@@ -0,0 +1,400 @@
+/***************************** LICENSE START ***********************************
+
+ Copyright 2015 ECMWF and INPE. This software is distributed under the terms
+ of the Apache License version 2.0. In applying this license, ECMWF does not
+ waive the privileges and immunities granted to it by virtue of its status as
+ an Intergovernmental Organization or submit itself to any jurisdiction.
+
+ ***************************** LICENSE END *************************************/
+
+#include "TableNodeWidget.hpp"
+
+#include <QDebug>
+#include <QHBoxLayout>
+
+#include "AbstractNodeModel.hpp"
+#include "DashboardDock.hpp"
+#include "FilterWidget.hpp"
+#include "NodePathWidget.hpp"
+#include "NodeViewBase.hpp"
+#include "TableFilterWidget.hpp"
+#include "TableNodeModel.hpp"
+#include "TableNodeSortModel.hpp"
+#include "TableNodeView.hpp"
+#include "VFilter.hpp"
+#include "VSettings.hpp"
+
+#include <QHBoxLayout>
+
+TableNodeWidget::TableNodeWidget(ServerFilter* serverFilter,QWidget * parent) :
+ NodeWidget("table",serverFilter,parent),
+ sortModel_(0)
+{
+ //Init qt-creator form
+ setupUi(this);
+
+ //This defines how to filter the nodes in the tree. We only want to filter according to node status.
+ filterDef_=new NodeFilterDef(serverFilter_,NodeFilterDef::GeneralScope);
+
+ //Create the table model. It uses the datahandler to access the data.
+ TableNodeModel* tModel=new TableNodeModel(serverFilter_,filterDef_,this);
+ model_=tModel;
+
+ //Create a filter model for the tree.
+ sortModel_=new TableNodeSortModel(tModel,this);
+
+ //Build the filter widget
+ filterW_->build(filterDef_,serverFilter_);
+
+ //Create the view
+ QHBoxLayout *hb=new QHBoxLayout(viewHolder_);
+ hb->setContentsMargins(0,0,0,0);
+ hb->setSpacing(0);
+ TableNodeView *tv=new TableNodeView(sortModel_,filterDef_,this);
+ hb->addWidget(tv);
+
+ //Store the pointer to the (non-QObject) base class of the view!!!
+ view_=tv;
+
+ //Signals-slots
+
+ connect(view_->realWidget(),SIGNAL(selectionChanged(VInfo_ptr)),
+ this,SLOT(slotSelectionChangedInView(VInfo_ptr)));
+
+ connect(view_->realWidget(),SIGNAL(infoPanelCommand(VInfo_ptr,QString)),
+ this,SIGNAL(popInfoPanel(VInfo_ptr,QString)));
+
+ connect(view_->realWidget(),SIGNAL(dashboardCommand(VInfo_ptr,QString)),
+ this,SIGNAL(dashboardCommand(VInfo_ptr,QString)));
+
+ connect(bcWidget_,SIGNAL(selected(VInfo_ptr)),
+ view_->realWidget(),SLOT(slotSetCurrent(VInfo_ptr)));
+
+ connect(view_->realWidget(),SIGNAL(headerButtonClicked(QString,QPoint)),
+ filterW_,SLOT(slotHeaderFilter(QString,QPoint)));
+
+#if 0
+ connect(model_,SIGNAL(clearBegun(const VNode*)),
+ view_->realWidget(),SLOT(slotSaveExpand(const VNode*)));
+
+ connect(model_,SIGNAL(scanEnded(const VNode*)),
+ view_->realWidget(),SLOT(slotRestoreExpand(const VNode*)));
+#endif
+
+ connect(model_,SIGNAL(rerender()),
+ view_->realWidget(),SLOT(slotRerender()));
+
+ //This will not emit the trigered signal of the action!!
+ //Synchronise the action and the breadcrumbs state
+ actionBreadcrumbs->setChecked(bcWidget_->active());
+
+ //The node status filter is exposed via a menu. So we need a reference to it.
+ states_=filterDef_->nodeState();
+}
+
+TableNodeWidget::~TableNodeWidget()
+{
+
+}
+
+void TableNodeWidget::populateDockTitleBar(DashboardDockTitleWidget* tw)
+{
+ //Builds the menu for the settings tool button
+ QMenu *menu=new QMenu(this);
+ menu->setTearOffEnabled(true);
+
+ menu->addAction(actionBreadcrumbs);
+ QMenu *menuState=menu->addMenu(tr("Status"));
+
+ menuState->setTearOffEnabled(true);
+
+ //stateFilterMenu_=new StateFilterMenu(menuState,filter_->menu());
+ stateFilterMenu_=new VParamFilterMenu(menuState,states_,"Status filter",
+ VParamFilterMenu::FilterMode,VParamFilterMenu::ColourDecor);
+
+ //Sets the menu on the toolbutton
+ tw->optionsTb()->setMenu(menu);
+
+ //Sets the title
+ tw->slotUpdateTitle("<b>Table</b>");
+
+ QList<QAction*> acLst;
+ QAction* acFilterEdit=new QAction(this);
+ acFilterEdit->setIcon(QPixmap(":viewer/filter_edit.svg"));
+ acFilterEdit->setToolTip("Edit filter ...");
+ acLst << acFilterEdit;
+
+ connect(acFilterEdit,SIGNAL(triggered()),
+ filterW_,SLOT(slotEdit()));
+
+ tw->addActions(acLst);
+}
+
+
+void TableNodeWidget::slotSelectionChangedInView(VInfo_ptr info)
+{
+ updateActionState(info);
+ bcWidget_->setPath(info);
+ Q_EMIT selectionChanged(info);
+}
+
+void TableNodeWidget::on_actionBreadcrumbs_triggered(bool b)
+{
+ if(b)
+ {
+ bcWidget_->active(true);
+ bcWidget_->setPath(view_->currentSelection());
+ }
+ else
+ {
+ bcWidget_->active(false);
+ }
+
+ //bcWidget_->clear();
+}
+
+
+void TableNodeWidget::rerender()
+{
+ bcWidget_->rerender();
+ view_->rerender();
+}
+
+
+void TableNodeWidget::writeSettings(VSettings* vs)
+{
+ vs->put("type",type_);
+ vs->put("dockId",id_);
+
+ bcWidget_->writeSettings(vs);
+
+ states_->writeSettings(vs);
+ filterDef_->writeSettings(vs);
+
+ //atts_->writeSettings(vs);
+ //icons_->writeSettings(vs);
+}
+
+void TableNodeWidget::readSettings(VSettings* vs)
+{
+ std::string type=vs->get<std::string>("type","");
+ if(type != type_)
+ return;
+
+ //This will not emit the changed signal. So the "observers" will
+ //not notice the change.
+ states_->readSettings(vs);
+ //atts_->readSettings(vs);
+ //icons_->readSettings(vs);
+ filterDef_->readSettings(vs);
+
+ //The model at this point is inactive (not using its data). We make it active:
+ // -it will instruct its data provider to filter the data according
+ // to the current settings
+ // -it will load and display the data
+ model_->active(true);
+
+ //--------------------------
+ //Breadcrumbs
+ //--------------------------
+
+ bcWidget_->readSettings(vs);
+
+ //Synchronise the action and the breadcrumbs state
+ //This will not emit the trigered signal of the action!!
+ actionBreadcrumbs->setChecked(bcWidget_->active());
+
+ //attrFilterMenu_->reload();
+ //iconFilterMenu_->reload();
+ stateFilterMenu_->reload();
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*
+
+#include "TreeNodeWidget.hpp"
+
+
+#include "NodeViewBase.hpp"
+
+#include "AbstractNodeModel.hpp"
+#include "NodeFilterModel.hpp"
+#include "NodePathWidget.hpp"
+#include "TreeNodeModel.hpp"
+#include "TreeNodeView.hpp"
+#include "VFilter.hpp"
+#include "VModelData.hpp"
+#include "VSettings.hpp"
+
+#include "FilterWidget.hpp"
+
+TreeNodeWidget::TreeNodeWidget(ServerFilter* servers,QWidget* parent) : NodeWidget(parent)
+{
+ //Init qt-creator form
+ setupUi(this);
+
+ //Define the icon filter for the model. It controls what icons
+ //are displayed next to the nodes. This is exposed via a menu.
+ icons_=new IconFilter;
+
+ //Define the attribute filter for the model. It controls what attributes
+ //are displayed for a given node. This is exposed via a menu.
+ atts_=new AttributeFilter;
+
+ //This defines how to filter the nodes in the tree. We only want to filter according to node status.
+ NodeFilterDef *filterDef_=new NodeFilterDef(NodeFilterDef::NodeState);
+
+ //The node status filter is exposed via a menu. So we need a reference to it.
+ states_=filterDef_->nodeState();
+
+ //Create the data handler for the tree model.
+ data_=new VModelData(servers,filterDef_,VModelData::TreeModel);
+
+ //Create the tree model. It uses the datahandler to access the data.
+ model_=new TreeNodeModel(data_,atts_,icons_,parent);
+
+ //Create a filter model for the tree.
+ filterModel_=new NodeFilterModel(model_,parent);
+
+ //Set the model on the view.
+ viewWidget_->setModel(filterModel_);
+
+ //Store the pointer to the (non-QObject) base class of the view!!!
+ view_=viewWidget_;
+
+ //Signals-slots
+
+ connect(view_->realWidget(),SIGNAL(selectionChanged(VInfo_ptr)),
+ bcWidget_,SLOT(setPath(VInfo_ptr)));
+
+ connect(bcWidget_,SIGNAL(selected(VInfo_ptr)),
+ view_->realWidget(),SLOT(slotSetCurrent(VInfo_ptr)));
+
+ connect(view_->realWidget(),SIGNAL(selectionChanged(VInfo_ptr)),
+ this,SIGNAL(selectionChanged(VInfo_ptr)));
+
+ connect(model_,SIGNAL(clearBegun(const VNode*)),
+ view_->realWidget(),SLOT(slotSaveExpand(const VNode*)));
+
+ connect(model_,SIGNAL(scanEnded(const VNode*)),
+ view_->realWidget(),SLOT(slotRestoreExpand(const VNode*)));
+
+ connect(data_,SIGNAL(rerender()),
+ view_->realWidget(),SLOT(slotRerender()));
+
+ //Builds the menu for the settings tool button
+ QMenu *menu=new QMenu(this);
+ menu->setTearOffEnabled(true);
+
+ menu->addAction(actionBreadcrumbs);
+ QMenu *menuState=menu->addMenu(tr("Status"));
+ QMenu *menuType=menu->addMenu(tr("Attribute"));
+ QMenu *menuIcon=menu->addMenu(tr("Icon"));
+
+ menuState->setTearOffEnabled(true);
+ menuType->setTearOffEnabled(true);
+ menuIcon->setTearOffEnabled(true);
+
+ //stateFilterMenu_=new StateFilterMenu(menuState,filter_->menu());
+ attrFilterMenu_=new VParamFilterMenu(menuType,atts_);
+ iconFilterMenu_=new VParamFilterMenu(menuIcon,icons_);
+ stateFilterMenu_=new VParamFilterMenu(menuState,states_,VParamFilterMenu::ColourDecor);
+
+ //Sets the menu on the toolbutton
+ viewTb->setMenu(menu);
+
+
+ //This will not emit the trigered signal of the action!!
+ //Synchronise the action and the breadcrumbs state
+ actionBreadcrumbs->setChecked(bcWidget_->active());
+
+}
+
+void TreeNodeWidget::on_actionBreadcrumbs_triggered(bool b)
+{
+ if(b)
+ {
+ bcWidget_->active(true);
+ bcWidget_->setPath(view_->currentSelection());
+ }
+ else
+ {
+ bcWidget_->active(false);
+ }
+
+ //bcWidget_->clear();
+}
+
+bool TreeNodeWidget::selectFirstServerInView()
+{
+ view_->selectFirstServer();
+ return true;
+}
+
+
+void TreeNodeWidget::writeSettings(VSettings* vs)
+{
+ vs->put("type",std::string("tree"));
+ vs->put("dockId",id_);
+
+ bcWidget_->writeSettings(vs);
+
+ states_->writeSettings(vs);
+ atts_->writeSettings(vs);
+ icons_->writeSettings(vs);
+}
+
+void TreeNodeWidget::readSettings(VSettings* vs)
+{
+ std::string type=vs->get<std::string>("type","");
+ if(type != "tree")
+ return;
+
+ //This will not emit the changed signal. So the "observers" will
+ //not notice the change.
+ states_->readSettings(vs);
+ atts_->readSettings(vs);
+ icons_->readSettings(vs);
+
+ //The model at this point is inactive (not using its data). We make it active:
+ // -it will instruct its data provider to filter the data according
+ // to the current settings
+ // -it will load and display the data
+ model_->active(true);
+
+ //--------------------------
+ //Breadcrumbs
+ //--------------------------
+
+ bcWidget_->readSettings(vs);
+
+ //Synchronise the action and the breadcrumbs state
+ //This will not emit the trigered signal of the action!!
+ actionBreadcrumbs->setChecked(bcWidget_->active());
+
+ attrFilterMenu_->reload();
+ iconFilterMenu_->reload();
+ stateFilterMenu_->reload();
+}
+
+
+*/
+
+
+
+
+
+
+
diff --git a/Viewer/src/TableNodeWidget.hpp b/Viewer/src/TableNodeWidget.hpp
new file mode 100644
index 0000000..a197bd6
--- /dev/null
+++ b/Viewer/src/TableNodeWidget.hpp
@@ -0,0 +1,46 @@
+/***************************** LICENSE START ***********************************
+
+ Copyright 2015 ECMWF and INPE. This software is distributed under the terms
+ of the Apache License version 2.0. In applying this license, ECMWF does not
+ waive the privileges and immunities granted to it by virtue of its status as
+ an Intergovernmental Organization or submit itself to any jurisdiction.
+
+ ***************************** LICENSE END *************************************/
+
+#ifndef TABLENODEWIDGET_HPP_
+#define TABLENODEWIDGET_HPP_
+
+#include "ui_TableNodeWidget.h"
+
+#include "NodeWidget.hpp"
+
+class NodeStateFilter;
+class TableNodeSortModel;
+class VParamFilterMenu;
+class VSettings;
+
+class TableNodeWidget : public NodeWidget, protected Ui::TableNodeWidget
+{
+Q_OBJECT
+
+public:
+ TableNodeWidget(ServerFilter* servers,QWidget* parent=0);
+ ~TableNodeWidget();
+
+ void populateDockTitleBar(DashboardDockTitleWidget* tw);
+ void rerender();
+
+ void writeSettings(VSettings*);
+ void readSettings(VSettings*);
+
+protected Q_SLOTS:
+ void on_actionBreadcrumbs_triggered(bool b);
+ void slotSelectionChangedInView(VInfo_ptr info);
+
+private:
+ TableNodeSortModel *sortModel_;
+ VParamFilterMenu *stateFilterMenu_;
+};
+
+#endif
+
diff --git a/Viewer/src/TableNodeWidget.ui b/Viewer/src/TableNodeWidget.ui
new file mode 100644
index 0000000..eca75b6
--- /dev/null
+++ b/Viewer/src/TableNodeWidget.ui
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>TableNodeWidget</class>
+ <widget class="QWidget" name="TableNodeWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>683</width>
+ <height>491</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,1">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1">
+ <property name="spacing">
+ <number>1</number>
+ </property>
+ <item>
+ <widget class="NodePathWidget" name="bcWidget_" native="true"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="TableFilterWidget" name="filterW_" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="viewHolder_" native="true"/>
+ </item>
+ </layout>
+ <action name="actionBreadcrumbs">
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Breadcrumbs</string>
+ </property>
+ <property name="toolTip">
+ <string>Show breadcrumbs</string>
+ </property>
+ </action>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>NodePathWidget</class>
+ <extends>QWidget</extends>
+ <header>NodePathWidget.hpp</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>TableFilterWidget</class>
+ <extends>QWidget</extends>
+ <header>TableFilterWidget.hpp</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources>
+ <include location="viewer.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/Viewer/src/TextEditSearchLine.cpp b/Viewer/src/TextEditSearchLine.cpp
new file mode 100644
index 0000000..6c0cfb6
--- /dev/null
+++ b/Viewer/src/TextEditSearchLine.cpp
@@ -0,0 +1,243 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+
+#include "TextEditSearchLine.hpp"
+
+#include "AbstractTextEditSearchInterface.hpp"
+
+#include <QColor>
+#include <QDebug>
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QLineEdit>
+#include <QPushButton>
+
+//#include "UserMessage.hpp"
+
+TextEditSearchLine::TextEditSearchLine(QWidget *parent) :
+ AbstractSearchLine(parent),
+ interface_(0)
+{
+ connect(matchModeCb_,SIGNAL(currentIndexChanged(int)),
+ this, SLOT(matchModeChanged(int)));
+}
+
+TextEditSearchLine::~TextEditSearchLine()
+{
+
+}
+
+void TextEditSearchLine::setSearchInterface(AbstractTextEditSearchInterface *e)
+{
+ interface_=e;
+}
+
+bool TextEditSearchLine::findString (QString str, bool highlightAll, QTextDocument::FindFlags extraFlags, bool gotoStartOfWord, int iteration)
+{
+ QTextDocument::FindFlags flags = findFlags() | extraFlags;
+ return interface_->findString(str,highlightAll,flags,gotoStartOfWord,iteration,matchModeCb_->currentMatchMode());
+}
+
+void TextEditSearchLine::highlightMatches(QString txt)
+{
+ if(interface_)
+ {
+ interface_->enableHighlights();
+ if(interface_->highlightsNeedSearch() && !txt.isEmpty())
+ {
+ findString(txt, true, 0, true, 0); // highlight all matches
+ }
+ }
+}
+
+void TextEditSearchLine::slotHighlight()
+{
+ //UserMessage::message(UserMessage::DBG, false," highlight: " + searchLine_->text().toStdString());
+
+ highlightAllTimer_.stop();
+
+ if (highlightAll())
+ highlightMatches(searchLine_->text());
+}
+
+//This slot is called as we type in the search string
+void TextEditSearchLine::slotFind(QString txt)
+{
+ if(!interface_)
+ return;
+
+ //In confirmSearch mode we do not start the search
+ if(confirmSearch_)
+ {
+ toDefaultState();
+ return;
+ }
+
+ if(txt.isEmpty())
+ {
+ highlightAllTimer_.stop();
+ toDefaultState();
+ return;
+ }
+
+ highlightAllTimer_.stop();
+ bool found = findString(txt, false, 0, true, 0); // find the next match
+
+ if (!isEmpty()) // there is a search term supplied by the user
+ {
+ // don't highlight the matches immediately - this can be expensive for large files,
+ // and we don't want to highlight each time the user types a new character; wait
+ // a moment and then start the highlight
+ highlightAllTimer_.setInterval(500);
+ highlightAllTimer_.disconnect();
+ connect(&highlightAllTimer_, SIGNAL(timeout()), this, SLOT(slotHighlight()));
+ highlightAllTimer_.start();
+ }
+ else
+ {
+ clearHighlights();
+ }
+
+ updateButtons(found);
+}
+
+void TextEditSearchLine::slotFindNext()
+{
+ if(!interface_)
+ return;
+
+ bool found = findString(searchLine_->text(), false, 0, false, 0);
+ updateButtons(found);
+}
+
+void TextEditSearchLine::slotFindPrev()
+{
+ if(!interface_)
+ return;
+
+ bool found = findString(searchLine_->text(), false, QTextDocument::FindBackward, false, 0);
+ updateButtons(found);
+}
+
+QTextDocument::FindFlags TextEditSearchLine::findFlags()
+{
+ QTextDocument::FindFlags flags;
+
+ if(caseSensitive())
+ {
+ flags = flags | QTextDocument::FindCaseSensitively;
+ }
+
+ if(wholeWords())
+ {
+ flags = flags | QTextDocument::FindWholeWords;
+ }
+
+ return flags;
+}
+
+
+// EditorSearchLine::refreshSearch
+// performed when the user changes search parameters such as case sensitivity - we want to
+// re-do the search from the current point, but if the current selection still matches then
+// we'd like it to be found first.
+
+void TextEditSearchLine::refreshSearch()
+{
+ if(!interface_)
+ return;
+
+ // if there's something selected already then move the cursor to the start of the line and search again
+ interface_->refreshSearch();
+
+ slotFindNext();
+ slotHighlight();
+}
+
+void TextEditSearchLine::disableHighlights()
+{
+ if(interface_)
+ interface_->disableHighlights();
+}
+
+
+void TextEditSearchLine::clearHighlights()
+{
+ if(interface_)
+ interface_->clearHighlights();
+}
+
+void TextEditSearchLine::matchModeChanged(int notUsed)
+{
+ if(matchModeCb_->currentMatchMode() == StringMatchMode::ContainsMatch)
+ actionWholeWords_->setEnabled(true);
+ else
+ actionWholeWords_->setEnabled(false);
+
+ refreshSearch();
+}
+
+
+void TextEditSearchLine::on_actionCaseSensitive__toggled(bool b)
+{
+ AbstractSearchLine::on_actionCaseSensitive__toggled(b);
+
+ refreshSearch();
+}
+
+
+void TextEditSearchLine::on_actionWholeWords__toggled(bool b)
+{
+ AbstractSearchLine::on_actionWholeWords__toggled(b);
+
+ refreshSearch();
+}
+
+void TextEditSearchLine::on_actionHighlightAll__toggled(bool b)
+{
+ AbstractSearchLine::on_actionHighlightAll__toggled(b);
+
+ if (b) // user switched on the highlights
+ slotHighlight();
+ else // user switched off the highlights
+ disableHighlights();
+
+ if(interface_ && interface_->highlightsNeedSearch())
+ refreshSearch();
+}
+
+void TextEditSearchLine::slotClose()
+{
+ AbstractSearchLine::slotClose();
+ clearHighlights();
+}
+
+// Called when we load a new node's information into the panel, or
+// when we move to the panel from another one.
+// If the search box is open, then search for the first matching item;
+// otherwise, search for a pre-configured list of keywords. If none
+// are found, and the user has clicked on the 'reload' button then
+// we just go to the last line of the output
+void TextEditSearchLine::searchOnReload(bool userClickedReload)
+{
+ if (isVisible() && !isEmpty())
+ {
+ slotFindNext();
+ slotHighlight();
+ }
+ else if(interface_)
+ {
+ // search for a highlight any of the pre-defined keywords so that
+ // the (probably) most important piece of information is highlighted
+ interface_->automaticSearchForKeywords(userClickedReload);
+ }
+}
+
diff --git a/Viewer/src/TextEditSearchLine.hpp b/Viewer/src/TextEditSearchLine.hpp
new file mode 100644
index 0000000..0e8469c
--- /dev/null
+++ b/Viewer/src/TextEditSearchLine.hpp
@@ -0,0 +1,57 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VIEWER_SRC_TEXTEDITSEARCHLINE_HPP_
+#define VIEWER_SRC_TEXTEDITSEARCHLINE_HPP_
+
+#include <QTextDocument>
+#include <QTimer>
+
+#include "AbstractSearchLine.hpp"
+
+class AbstractTextEditSearchInterface;
+
+class TextEditSearchLine : public AbstractSearchLine
+{
+ Q_OBJECT
+
+public:
+ explicit TextEditSearchLine(QWidget *parent);
+ ~TextEditSearchLine();
+ void setSearchInterface(AbstractTextEditSearchInterface*);
+ void searchOnReload(bool userClickedReload);
+
+public Q_SLOTS:
+ void slotFind(QString);
+ void slotFindNext();
+ void slotFindPrev();
+ void slotFindNext(bool) {slotFindNext();}
+ void slotFindPrev(bool) {slotFindPrev();}
+ void matchModeChanged(int newIndex);
+ void on_actionCaseSensitive__toggled(bool);
+ void on_actionWholeWords__toggled(bool);
+ void on_actionHighlightAll__toggled(bool);
+ void slotClose();
+ void slotHighlight();
+
+protected:
+ QTextDocument::FindFlags findFlags();
+ bool findString (QString str, bool highlightAll, QTextDocument::FindFlags extraFlags, bool gotoStartOfWord, int iteration);
+ void refreshSearch();
+ void highlightMatches(QString txt);
+ void clearHighlights();
+ void disableHighlights();
+
+ AbstractTextEditSearchInterface* interface_;
+ QTimer highlightAllTimer_;
+ QColor highlightColour_;
+};
+
+#endif /* VIEWER_SRC_TEXTEDITSEARCHLINE_HPP_ */
diff --git a/Viewer/src/TextPager/TextPagerCursor.cpp b/Viewer/src/TextPager/TextPagerCursor.cpp
new file mode 100644
index 0000000..64bf126
--- /dev/null
+++ b/Viewer/src/TextPager/TextPagerCursor.cpp
@@ -0,0 +1,780 @@
+// Copyright 2010 Anders Bakken
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "TextPagerCursor.hpp"
+#include "TextPagerCursor_p.hpp"
+#include "TextPagerDocument.hpp"
+#include "TextPagerDocument_p.hpp"
+#include "TextPagerEdit_p.hpp"
+#include "TextPagerLayout_p.hpp"
+#include "TextPagerEdit.hpp"
+
+class SelectionChangedEmitter
+{
+public:
+ SelectionChangedEmitter(TextPagerEdit *t)
+ : selectionStart(-1), selectionEnd(-1), textEdit(t)
+ {
+ if (textEdit) {
+ selectionStart = textEdit->textCursor().selectionStart();
+ selectionEnd = textEdit->textCursor().selectionEnd();
+ }
+ }
+
+ ~SelectionChangedEmitter()
+ {
+ if (textEdit) {
+ const TextPagerCursor &cursor = textEdit->textCursor();
+ if (((selectionStart != selectionEnd) != cursor.hasSelection())
+ || (selectionStart != selectionEnd
+ && (selectionStart != cursor.selectionStart()
+ || selectionEnd != cursor.selectionEnd()))) {
+ QMetaObject::invokeMethod(textEdit, "selectionChanged");
+ }
+ }
+ }
+private:
+ int selectionStart, selectionEnd;
+ TextPagerEdit *textEdit;
+};
+
+TextPagerCursor::TextPagerCursor()
+ : d(0), textEdit(0)
+{
+}
+
+TextPagerCursor::TextPagerCursor(const TextPagerDocument *document, int pos, int anc)
+ : d(0), textEdit(0)
+{
+ if (document) {
+ const int documentSize = document->d->documentSize;
+ if (pos < 0 || pos > documentSize || anc < -1 || anc > documentSize) {
+#ifndef LAZYTEXTEDIT_AUTOTEST
+ qWarning("Invalid cursor data %d %d - %d\n",
+ pos, anc, documentSize);
+ Q_ASSERT(0);
+#endif
+ return;
+ }
+ d = new TextCursorSharedPrivate;
+ d->document = const_cast<TextPagerDocument*>(document);
+ d->position = pos;
+ d->anchor = anc == -1 ? pos : anc;
+ d->document->d->textCursors.insert(d);
+ }
+}
+
+TextPagerCursor::TextPagerCursor(const TextPagerEdit *edit, int pos, int anc)
+ : d(0), textEdit(0)
+{
+ if (edit) {
+ TextPagerDocument *document = edit->document();
+ const int documentSize = document->d->documentSize;
+ if (pos < 0 || pos > documentSize || anc < -1 || anc > documentSize) {
+#ifndef LAZYTEXTEDIT_AUTOTEST
+ qWarning("Invalid cursor data %d %d - %d\n",
+ pos, anc, documentSize);
+ Q_ASSERT(0);
+#endif
+ return;
+ }
+ d = new TextCursorSharedPrivate;
+ d->document = const_cast<TextPagerDocument*>(document);
+ d->position = pos;
+ d->anchor = anc == -1 ? pos : anc;
+ d->document->d->textCursors.insert(d);
+ }
+}
+
+TextPagerCursor::TextPagerCursor(const TextPagerCursor &cursor)
+ : d(cursor.d), textEdit(0)
+{
+ ref();
+}
+
+TextPagerCursor &TextPagerCursor::operator=(const TextPagerCursor &other)
+{
+ deref();
+ d = other.d;
+ textEdit = 0;
+ ref();
+ return *this;
+}
+
+TextPagerCursor::~TextPagerCursor()
+{
+ deref();
+}
+
+bool TextPagerCursor::isNull() const
+{
+ return !d || !d->document;
+}
+
+TextPagerDocument *TextPagerCursor::document() const
+{
+ return d ? d->document : 0;
+}
+
+void TextPagerCursor::setSelection(int pos, int length) // can be negative
+{
+ setPosition(pos + length);
+ if (length != 0)
+ setPosition(pos, KeepAnchor);
+}
+
+void TextPagerCursor::setPosition(int pos, MoveMode mode)
+{
+ Q_ASSERT(!isNull());
+ d->overrideColumn = -1;
+ if (pos < 0 || pos > d->document->documentSize()) {
+ clearSelection();
+ return;
+ } else if (pos == d->position && (mode == KeepAnchor || d->anchor == d->position)) {
+ return;
+ }
+
+ SelectionChangedEmitter emitter(textEdit);
+ detach();
+ cursorChanged(false);
+
+#if 0
+ Link *link = d->document->links(pos, 1).value(0, 0);
+ if (link && link->position < pos && link->position + link->size > pos) { // inside a link
+ pos = (pos > d->position ? link->position + link->size : link->position);
+ }
+#endif
+
+ if (mode ==TextPagerCursor::MoveAnchor) {
+ clearSelection();
+ }
+
+ d->position = pos;
+ if (mode == MoveAnchor) {
+ d->anchor = pos;
+ }
+ cursorChanged(true);
+}
+
+int TextPagerCursor::position() const
+{
+ return isNull() ? -1 : d->position;
+}
+
+int TextPagerCursor::anchor() const
+{
+ return isNull() ? -1 : d->anchor;
+}
+
+bool TextPagerCursor::movePosition(TextPagerCursor::MoveOperation op,TextPagerCursor::MoveMode mode, int n)
+{
+ if (!d || !d->document || n <= 0)
+ return false;
+
+ switch (op) {
+ case Start:
+ case StartOfLine:
+ case End:
+ case EndOfLine:
+ n = 1;
+ break;
+ default:
+ break;
+ }
+
+ if (n > 1) {
+ while (n > 0 && movePosition(op, mode, 1))
+ --n;
+ return n == 0;
+ }
+ detach();
+
+ switch (op) {
+ case NoMove:
+ return true;
+
+ case PreviousCharacter:
+ case NextCharacter:
+ return movePosition(op ==TextPagerCursor::PreviousCharacter
+ ?TextPagerCursor::Left :TextPagerCursor::Right, mode);
+
+ case End:
+ case Start:
+ setPosition(op ==TextPagerCursor::Start ? 0 : d->document->documentSize(), mode);
+ break;
+
+ case Up:
+ case Down: {
+ TextPagerLayout *textLayout = TextLayoutCacheManager::requestLayout(*this, 1); // should I use 1?
+ Q_ASSERT(textLayout);
+ int index;
+ bool currentIsLast;
+ const QTextLine currentLine = textLayout->lineForPosition(d->position, 0,
+ &index,
+ ¤tIsLast);
+ Q_ASSERT(textLayout->lines.size() <= 1 || (index != -1 && currentLine.isValid()));
+ if (!currentLine.isValid())
+ return false;
+ const int col = columnNumber();
+ int targetLinePos;
+ if (op == Up) {
+ targetLinePos = d->position - col - 1;
+// qDebug() << "I was at column" << col << "and position"
+// << d->position << "so naturally I can find the previous line around"
+// << (d->position - col - 1);
+ } else {
+ targetLinePos = d->position + currentLine.textLength() - col
+ + (currentIsLast ? 1 : 0);
+// qDebug() << "currentLine.textLength" << currentLine.textLength() << "col" << col
+// << "currentIsLast" << currentIsLast;
+ // ### probably need to add only if last line in layout
+ }
+ if (targetLinePos < 0) {
+ if (d->position == 0) {
+ return false;
+ } else {
+ setPosition(0, mode);
+ return true;
+ }
+ } else if (targetLinePos >= d->document->documentSize()) {
+ if (d->position == d->document->documentSize()) {
+ return false;
+ } else {
+ setPosition(d->document->documentSize(), mode);
+ return true;
+ }
+ }
+ int offsetInLine;
+
+ const QTextLine targetLine = textLayout->lineForPosition(targetLinePos, &offsetInLine);
+ if (!targetLine.isValid())
+ return false;
+ targetLinePos -= offsetInLine; // targetLinePos should now be at col 0
+
+// qDebug() << "finding targetLine at" << targetLinePos
+// << d->document->read(targetLinePos, 7)
+// << "d->position" << d->position
+// << "col" << col
+// << "offsetInLine" << offsetInLine;
+
+ int gotoCol = qMax(d->overrideColumn, col);
+ if (gotoCol > targetLine.textLength()) {
+ d->overrideColumn = qMax(d->overrideColumn, gotoCol);
+ gotoCol = targetLine.textLength();
+ }
+ const int overrideColumn = d->overrideColumn;
+ setPosition(targetLinePos + gotoCol, mode);
+ d->overrideColumn = overrideColumn;
+ break; }
+
+ case EndOfLine:
+ case StartOfLine: {
+ int offset;
+ bool lastLine;
+ TextPagerLayout *textLayout = TextLayoutCacheManager::requestLayout(*this, 1);
+ QTextLine line = textLayout->lineForPosition(position(), &offset,
+ 0, &lastLine);
+ if (!line.isValid())
+ return false;
+ if (op ==TextPagerCursor::StartOfLine) {
+ setPosition(position() - offset, mode);
+ } else {
+ int pos = position() - offset + line.textLength();
+ if (!lastLine)
+ --pos;
+ setPosition(pos, mode);
+ }
+ break; }
+
+ case StartOfBlock: {
+ TextDocumentIterator it(d->document->d, d->position);
+ const QLatin1Char newline('\n');
+ while (it.hasPrevious() && it.previous() != newline) ;
+ if (it.hasPrevious())
+ it.next();
+ setPosition(it.position(), mode);
+ break; }
+ case EndOfBlock: {
+ TextDocumentIterator it(d->document->d, d->position);
+ const QLatin1Char newline('\n');
+ while (it.current() != newline && it.hasNext() && it.next() != newline) ;
+ setPosition(it.position(), mode);
+ break; }
+
+ case StartOfWord:
+ case PreviousWord:
+ case WordLeft: {
+ TextDocumentIterator it(d->document->d, d->position);
+
+ while (it.hasPrevious()) {
+ const QChar ch = it.previous();
+ if (d->document->isWordCharacter(ch, it.position()))
+ break;
+ }
+ while (it.hasPrevious()) {
+ const QChar ch = it.previous();
+ if (!d->document->isWordCharacter(ch, it.position()))
+ break;
+ }
+ if (it.hasPrevious())
+ it.next();
+ setPosition(it.position(), mode);
+ d->overrideColumn = -1;
+ break; }
+
+ case NextWord:
+ case WordRight:
+ case EndOfWord: {
+ TextDocumentIterator it(d->document->d, d->position);
+ while (it.hasNext()) {
+ const QChar ch = it.next();
+ if (d->document->isWordCharacter(ch, it.position()))
+ break;
+ }
+ while (it.hasNext()) {
+ const QChar ch = it.next();
+ if (!d->document->isWordCharacter(ch, it.position()))
+ break;
+ }
+ setPosition(it.position(), mode);
+ d->overrideColumn = -1;
+ break; }
+
+ case PreviousBlock:
+ movePosition(TextPagerCursor::StartOfBlock, mode);
+ movePosition(TextPagerCursor::Left, mode);
+ movePosition(TextPagerCursor::StartOfBlock, mode);
+ break;
+
+ case NextBlock:
+ movePosition(TextPagerCursor::EndOfBlock, mode);
+ movePosition(TextPagerCursor::Right, mode);
+ return true;
+
+ case Left:
+ case Right:
+ d->overrideColumn = -1;
+ setPosition(qBound<int>(0, position() + (op ==TextPagerCursor::Left ? -1 : 1),
+ d->document->documentSize()), mode);
+ break;
+ };
+
+ return true;
+}
+
+void TextPagerCursor::select(SelectionType selection)
+{
+ if (!d || !d->document)
+ return;
+
+ clearSelection();
+
+ switch (selection) {
+ case LineUnderCursor:
+ movePosition(StartOfLine);
+ movePosition(EndOfLine, KeepAnchor);
+ break;
+ case WordUnderCursor:
+ movePosition(StartOfWord);
+ movePosition(EndOfWord, KeepAnchor);
+ break;
+ case BlockUnderCursor:
+ movePosition(StartOfBlock);
+ // also select the paragraph separator
+ if (movePosition(PreviousBlock)) {
+ movePosition(EndOfBlock);
+ movePosition(NextBlock, KeepAnchor);
+ }
+ movePosition(EndOfBlock, KeepAnchor);
+ break;
+ }
+}
+
+bool TextPagerCursor::hasSelection() const
+{
+ return !isNull() && d->anchor != d->position;
+}
+
+void TextPagerCursor::clearSelection()
+{
+ Q_ASSERT(!isNull());
+ if (hasSelection()) {
+ detach();
+ SelectionChangedEmitter emitter(textEdit);
+ d->anchor = d->position;
+ }
+}
+
+int TextPagerCursor::selectionStart() const
+{
+ return qMin(d->anchor, d->position);
+}
+
+int TextPagerCursor::selectionEnd() const
+{
+ return qMax(d->anchor, d->position);
+}
+
+int TextPagerCursor::selectionSize() const
+{
+ return selectionEnd() - selectionStart();
+}
+
+
+QString TextPagerCursor::selectedText() const
+{
+ if (isNull() || d->anchor == d->position)
+ return QString();
+
+ const int min = qMin(d->anchor, d->position);
+ const int max = qMax(d->anchor, d->position);
+ return d->document->read(min, max - min);
+}
+
+bool TextPagerCursor::atBlockStart() const
+{
+ Q_ASSERT(!isNull());
+ return atStart() || d->document->read(d->position - 1, 1).at(0) == '\n';
+}
+
+bool TextPagerCursor::atBlockEnd() const
+{
+ Q_ASSERT(!isNull());
+ return atEnd() || d->document->read(d->position, 1).at(0) == '\n'; // ### is this right?
+}
+
+bool TextPagerCursor::atStart() const
+{
+ Q_ASSERT(!isNull());
+ return d->position == 0;
+}
+
+bool TextPagerCursor::atEnd() const
+{
+ Q_ASSERT(!isNull());
+ return d->position == d->document->documentSize();
+}
+
+
+bool TextPagerCursor::operator!=(const TextPagerCursor &rhs) const
+{
+ return !(*this == rhs);
+}
+
+bool TextPagerCursor::operator<(const TextPagerCursor &rhs) const
+{
+ if (!d)
+ return true;
+
+ if (!rhs.d)
+ return false;
+
+ Q_ASSERT_X(d->document == rhs.d->document, "TextCursor::operator<",
+ "cannot compare cursors attached to different documents");
+
+ return d->position < rhs.d->position;
+}
+
+bool TextPagerCursor::operator<=(const TextPagerCursor &rhs) const
+{
+ return *this < rhs || *this == rhs;
+}
+
+bool TextPagerCursor::operator==(const TextPagerCursor &rhs) const
+{
+ if (isCopyOf(rhs))
+ return true;
+
+ if (!d || !rhs.d)
+ return false;
+
+ return (d->position == rhs.d->position
+ && d->anchor == rhs.d->anchor
+ && d->document == rhs.d->document);
+}
+
+bool TextPagerCursor::operator>=(const TextPagerCursor &rhs) const
+{
+ return *this > rhs || *this == rhs;
+}
+
+bool TextPagerCursor::operator>(const TextPagerCursor &rhs) const
+{
+ if (!d)
+ return false;
+
+ if (!rhs.d)
+ return true;
+
+ Q_ASSERT_X(d->document == rhs.d->document, "TextCursor::operator>=",
+ "cannot compare cursors attached to different documents");
+
+ return d->position > rhs.d->position;
+}
+
+bool TextPagerCursor::isCopyOf(const TextPagerCursor &other) const
+{
+ return d == other.d;
+}
+
+int TextPagerCursor::columnNumber() const
+{
+ Q_ASSERT(d && d->document);
+ TextPagerLayout *textLayout = TextLayoutCacheManager::requestLayout(*this, 0);
+ int col;
+ textLayout->lineForPosition(d->position, &col);
+ return col;
+}
+
+int TextPagerCursor::lineNumber() const
+{
+ Q_ASSERT(d && d->document);
+ return d->document->lineNumber(position());
+}
+
+void TextPagerCursor::detach()
+{
+ Q_ASSERT(d);
+ if (d->ref > 1) {
+ d->ref.deref();
+ TextCursorSharedPrivate *p = new TextCursorSharedPrivate;
+ p->position = d->position;
+ p->overrideColumn = d->overrideColumn;
+ p->anchor = d->anchor;
+ p->document = d->document;
+ d->document->d->textCursors.insert(p);
+ d = p;
+ }
+}
+
+bool TextPagerCursor::ref()
+{
+ return d && d->ref.ref();
+}
+
+bool TextPagerCursor::deref()
+{
+ TextCursorSharedPrivate *dd = d;
+ d = 0;
+ if (dd && !dd->ref.deref()) {
+ if (dd->document) {
+ const bool removed = dd->document->d->textCursors.remove(dd);
+ Q_ASSERT(removed);
+ Q_UNUSED(removed)
+ }
+ delete dd;
+ return false;
+ }
+ return true;
+}
+
+void TextPagerCursor::cursorChanged(bool ensureVisible)
+{
+ if (textEdit) {
+ if (textEdit->d->cursorBlinkTimer.isActive())
+ textEdit->d->cursorVisible = true;
+ if (ensureVisible) {
+ Q_EMIT textEdit->cursorPositionChanged(d->position);
+ textEdit->ensureCursorVisible();
+ }
+ const QRect r = textEdit->cursorBlockRect(*this) & textEdit->viewport()->rect();
+ if (!r.isNull()) {
+ textEdit->viewport()->update(r);
+ }
+ }
+}
+
+bool TextPagerCursor::cursorMoveKeyEvent(QKeyEvent *e)
+{
+ MoveMode mode = MoveAnchor;
+ MoveOperation op = NoMove;
+
+ if (e == QKeySequence::MoveToNextChar) {
+ op = Right;
+ } else if (e == QKeySequence::MoveToPreviousChar) {
+ op = Left;
+ } else if (e == QKeySequence::SelectNextChar) {
+ op = Right;
+ mode = KeepAnchor;
+ } else if (e == QKeySequence::SelectPreviousChar) {
+ op = Left;
+ mode = KeepAnchor;
+ } else if (e == QKeySequence::SelectNextWord) {
+ op = WordRight;
+ mode = KeepAnchor;
+ } else if (e == QKeySequence::SelectPreviousWord) {
+ op = WordLeft;
+ mode = KeepAnchor;
+ } else if (e == QKeySequence::SelectStartOfLine) {
+ op = StartOfLine;
+ mode = KeepAnchor;
+ } else if (e == QKeySequence::SelectEndOfLine) {
+ op = EndOfLine;
+ mode = KeepAnchor;
+ } else if (e == QKeySequence::SelectStartOfBlock) {
+ op = StartOfBlock;
+ mode = KeepAnchor;
+ } else if (e == QKeySequence::SelectEndOfBlock) {
+ op = EndOfBlock;
+ mode = KeepAnchor;
+ } else if (e == QKeySequence::SelectStartOfDocument) {
+ op = Start;
+ mode = KeepAnchor;
+ } else if (e == QKeySequence::SelectEndOfDocument) {
+ op = End;
+ mode = KeepAnchor;
+ } else if (e == QKeySequence::SelectPreviousLine) {
+ op = Up;
+ mode = KeepAnchor;
+ } else if (e == QKeySequence::SelectNextLine) {
+ op = Down;
+ mode = KeepAnchor;
+#if 0
+ {
+ QTextBlock block = cursor.block();
+ QTextLine line = currentTextLine(cursor);
+ if (!block.next().isValid()
+ && line.isValid()
+ && line.lineNumber() == block.layout()->lineCount() - 1)
+ op = End;
+ }
+#endif
+ } else if (e == QKeySequence::MoveToNextWord) {
+ op = WordRight;
+ } else if (e == QKeySequence::MoveToPreviousWord) {
+ op = WordLeft;
+ } else if (e == QKeySequence::MoveToEndOfBlock) {
+ op = EndOfBlock;
+ } else if (e == QKeySequence::MoveToStartOfBlock) {
+ op = StartOfBlock;
+ } else if (e == QKeySequence::MoveToNextLine) {
+ op = Down;
+ } else if (e == QKeySequence::MoveToPreviousLine) {
+ op = Up;
+ } else if (e == QKeySequence::MoveToStartOfLine) {
+ op = StartOfLine;
+ } else if (e == QKeySequence::MoveToEndOfLine) {
+ op = EndOfLine;
+ } else if (e == QKeySequence::MoveToStartOfDocument) {
+ op = Start;
+ } else if (e == QKeySequence::MoveToEndOfDocument) {
+ op = End;
+ } else if (e == QKeySequence::MoveToNextPage || e == QKeySequence::MoveToPreviousPage
+ || e == QKeySequence::SelectNextPage || e == QKeySequence::SelectPreviousPage) {
+ const MoveMode mode = (e == QKeySequence::MoveToNextPage
+ || e == QKeySequence::MoveToPreviousPage
+ ? MoveAnchor : KeepAnchor);
+ const MoveOperation operation = (e == QKeySequence::MoveToNextPage
+ || e == QKeySequence::SelectNextPage
+ ? Down : Up);
+ int visibleLines = 10;
+ if (textEdit)
+ visibleLines = textEdit->d->visibleLines;
+ for (int i=0; i<visibleLines; ++i) {
+ if (!movePosition(operation, mode))
+ break;
+ }
+ return true;
+ } else {
+ return false;
+ }
+ return movePosition(op, mode);
+}
+
+int TextPagerCursor::viewportWidth() const
+{
+ return textEdit ? textEdit->viewport()->width() : d->viewportWidth;
+}
+
+void TextPagerCursor::setViewportWidth(int width)
+{
+ if (textEdit) {
+ qWarning("It makes no sense to set the viewportWidth of a text cursor that belongs to a text edit. The actual viewportWidth will be used");
+ return;
+ }
+ d->viewportWidth = width;
+}
+
+QChar TextPagerCursor::cursorCharacter() const
+{
+ Q_ASSERT(d && d->document);
+ return d->document->readCharacter(d->anchor);
+}
+
+QString TextPagerCursor::cursorLine() const
+{
+ Q_ASSERT(d && d->document);
+ int layoutIndex = -1;
+ TextPagerLayout *textLayout = TextLayoutCacheManager::requestLayout(*this, 2); // should I use 1?
+
+ QTextLine line = textLayout->lineForPosition(position(), 0, &layoutIndex);
+ Q_ASSERT(line.isValid()); // ### could this be legitimate?
+ Q_ASSERT(textLayout);
+ return textLayout->textLayouts.at(layoutIndex)->text()
+ .mid(line.textStart(), line.textLength());
+ // ### there is a bug here. It doesn't seem to use the right
+ // ### viewportWidth even though it is the textEdit's cursor
+}
+
+int TextPagerCursor::lineHeight() const
+{
+ int res = -1;
+ Q_ASSERT(d && d->document);
+ int layoutIndex = -1;
+ TextPagerLayout *textLayout = TextLayoutCacheManager::requestLayout(*this, 2);
+ QTextLine line = textLayout->lineForPosition(position(), 0, &layoutIndex);
+ if (line.isValid())
+ res = line.height();
+ return res;
+}
+
+
+QString TextPagerCursor::wordUnderCursor() const
+{
+ Q_ASSERT(!isNull());
+ return d->document->d->wordAt(d->position);
+}
+
+QString TextPagerCursor::paragraphUnderCursor() const
+{
+ Q_ASSERT(!isNull());
+ return d->document->d->paragraphAt(d->position);
+}
+
+QDebug operator<<(QDebug dbg, const TextPagerCursor &cursor)
+{
+ QString ret = QString::fromLatin1("TextCursor(");
+ if (cursor.isNull()) {
+ ret.append(QLatin1String("null)"));
+ dbg.maybeSpace() << ret;
+ } else {
+ if (!cursor.hasSelection()) {
+ dbg << "anchor/position:" << cursor.anchor() << "character:" << cursor.cursorCharacter();
+ } else {
+ dbg << "anchor:" << cursor.anchor() << "position:" << cursor.position()
+ << "selectionSize:" << cursor.selectionSize();
+ QString selectedText;
+ if (cursor.selectionSize() > 10) {
+ selectedText = cursor.document()->read(cursor.selectionStart(), 7);
+ selectedText.append("...");
+ } else {
+ selectedText = cursor.selectedText();
+ }
+ dbg << "selectedText:" << selectedText;
+ }
+ }
+ return dbg.space();
+}
+
+
diff --git a/Viewer/src/TextPager/TextPagerCursor.hpp b/Viewer/src/TextPager/TextPagerCursor.hpp
new file mode 100644
index 0000000..be8e193
--- /dev/null
+++ b/Viewer/src/TextPager/TextPagerCursor.hpp
@@ -0,0 +1,140 @@
+// Copyright 2010 Anders Bakken
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef TEXTPAGERCURSOR_HPP__
+#define TEXTPAGERCURSOR_HPP__
+
+#include <QString>
+#include <QKeyEvent>
+#include <QSize>
+#include <QTextLine>
+
+class TextPagerEdit;
+class TextPagerLayout;
+class TextPagerDocument;
+class TextCursorSharedPrivate;
+class TextPagerCursor
+{
+public:
+ TextPagerCursor();
+ explicit TextPagerCursor(const TextPagerDocument *document, int pos = 0, int anchor = -1);
+ explicit TextPagerCursor(const TextPagerEdit *document, int pos = 0, int anchor = -1);
+ TextPagerCursor(const TextPagerCursor &cursor);
+ TextPagerCursor &operator=(const TextPagerCursor &other);
+ ~TextPagerCursor();
+
+ TextPagerDocument *document() const;
+ bool isNull() const;
+ inline bool isValid() const { return !isNull(); }
+
+ enum MoveMode {
+ MoveAnchor,
+ KeepAnchor
+ };
+
+ void setPosition(int pos, MoveMode mode = MoveAnchor);
+ int position() const;
+
+ void setSelection(int pos, int length); // can be negative
+
+ int viewportWidth() const;
+ void setViewportWidth(int width);
+
+ int anchor() const;
+
+ QChar cursorCharacter() const;
+ QString cursorLine() const;
+ int lineHeight() const;
+
+ QString wordUnderCursor() const;
+ QString paragraphUnderCursor() const;
+
+ enum MoveOperation {
+ NoMove,
+ Start,
+ Up,
+ StartOfLine,
+ StartOfBlock,
+ StartOfWord,
+ PreviousBlock,
+ PreviousCharacter,
+ PreviousWord,
+ Left,
+ WordLeft,
+ End,
+ Down,
+ EndOfLine,
+ EndOfWord,
+ EndOfBlock,
+ NextBlock,
+ NextCharacter,
+ NextWord,
+ Right,
+ WordRight
+ };
+
+ bool movePosition(MoveOperation op, MoveMode = MoveAnchor, int n = 1);
+
+ enum SelectionType {
+ WordUnderCursor,
+ LineUnderCursor,
+ BlockUnderCursor
+ };
+
+ void select(SelectionType selection);
+
+ bool hasSelection() const;
+
+ void clearSelection();
+ int selectionStart() const;
+ int selectionEnd() const;
+ int selectionSize() const;
+ inline int selectionLength() const { return selectionSize(); }
+
+ QString selectedText() const;
+
+ bool atBlockStart() const;
+ bool atBlockEnd() const;
+ bool atStart() const;
+ bool atEnd() const;
+
+ bool operator!=(const TextPagerCursor &rhs) const;
+ bool operator<(const TextPagerCursor &rhs) const;
+ bool operator<=(const TextPagerCursor &rhs) const;
+ bool operator==(const TextPagerCursor &rhs) const;
+ bool operator>=(const TextPagerCursor &rhs) const;
+ bool operator>(const TextPagerCursor &rhs) const;
+
+ bool isCopyOf(const TextPagerCursor &other) const;
+
+ int columnNumber() const;
+ int lineNumber() const;
+private:
+ bool cursorMoveKeyEvent(QKeyEvent *e);
+ void cursorChanged(bool ensureCursorVisible);
+ void detach();
+ bool ref();
+ bool deref();
+
+ TextCursorSharedPrivate *d;
+ TextPagerEdit *textEdit;
+ friend class TextPagerEdit;
+ friend class TextLayoutCacheManager;
+ friend class TextPagerDocument;
+ friend class TextDocumentPrivate;
+};
+
+QDebug operator<<(QDebug dbg, const TextPagerCursor &cursor);
+
+#endif
diff --git a/Viewer/src/TextPager/TextPagerCursor_p.hpp b/Viewer/src/TextPager/TextPagerCursor_p.hpp
new file mode 100644
index 0000000..1bd6e35
--- /dev/null
+++ b/Viewer/src/TextPager/TextPagerCursor_p.hpp
@@ -0,0 +1,214 @@
+// Copyright 2010 Anders Bakken
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef TEXTPAGERCURSOR_P_HPP__
+#define TEXTPAGERCURSOR_P_HPP__
+
+#include <QSize>
+#include <QList>
+#include <QObject>
+#include <QHash>
+#include <QAtomicInt>
+#include <QCoreApplication>
+#include <QTextCursor>
+#include "TextPagerCursor_p.hpp"
+#include "TextPagerEdit.hpp"
+#include "TextPagerEdit_p.hpp"
+
+static inline bool match(const TextPagerCursor &cursor, const TextPagerLayout *layout, int lines)
+{
+ Q_ASSERT(cursor.document() == layout->document);
+ if (cursor.viewportWidth() != -1 && cursor.viewportWidth() != layout->viewport) {
+ return false;
+ }
+ if (layout->viewportPosition > cursor.position()
+ || layout->layoutEnd < cursor.position()) {
+ return false;
+ }
+ int index = -1;
+ if (!layout->layoutForPosition(cursor.position(), 0, &index)) {
+ // ### need an interface for this if I am going to have a mode
+ // ### that doesn't break lines
+ return false;
+ }
+
+ if (index < lines && layout->viewportPosition > 0) {
+ return false; // need more margin before the cursor
+ } else if (layout->textLayouts.size() - index - 1 < lines && layout->layoutEnd < layout->document->documentSize()) {
+ return false; // need more margin after cursor
+ }
+ return true;
+}
+
+class TextLayoutCacheManager : public QObject
+{
+ Q_OBJECT
+public:
+ static TextLayoutCacheManager *instance()
+ {
+ static TextLayoutCacheManager *inst = new TextLayoutCacheManager(QCoreApplication::instance());
+ return inst;
+ }
+ // ### this class doesn't react to TextSections added or removed. I
+ // ### don't think it needs to since it's only being used for
+ // ### cursor movement which shouldn't be impacted by these things
+
+ static TextPagerLayout *requestLayout(const TextPagerCursor &cursor, int margin)
+ {
+ Q_ASSERT(cursor.document());
+ if (cursor.textEdit && match(cursor, cursor.textEdit->d, margin)) {
+ return cursor.textEdit->d;
+ }
+
+ TextPagerDocument *doc = cursor.document();
+ Q_ASSERT(doc);
+ QList<TextPagerLayout*> &layouts = instance()->cache[doc];
+ Q_ASSERT(cursor.document());
+ Q_FOREACH(TextPagerLayout *l, layouts) {
+ if (match(cursor, l, margin)) {
+ return l;
+ }
+ }
+ if (layouts.size() < instance()->maxLayouts) {
+ if (layouts.isEmpty()) {
+ connect(cursor.document(), SIGNAL(charactersAdded(int, int)),
+ instance(), SLOT(onCharactersAddedOrRemoved(int)));
+ connect(cursor.document(), SIGNAL(charactersRemoved(int, int)),
+ instance(), SLOT(onCharactersAddedOrRemoved(int)));
+ connect(cursor.document(), SIGNAL(destroyed(QObject*)),
+ instance(), SLOT(onDocumentDestroyed(QObject*)));
+ }
+ layouts.append(new TextPagerLayout(doc));
+ }
+ TextPagerLayout *l = layouts.last();
+ l->viewport = cursor.viewportWidth();
+ if (l->viewport == -1)
+ l->viewport = INT_MAX - 1024; // prevent overflow in comparisons.
+ if (cursor.textEdit) {
+ l->textEdit = cursor.textEdit;
+ l->suppressTextEditUpdates = true;
+ l->lineBreaking = cursor.textEdit->lineBreaking();
+ l->sections = cursor.textEdit->d->sections;
+ l->font = cursor.textEdit->font();
+ l->syntaxHighlighters = cursor.textEdit->syntaxHighlighters();
+// l->extraSelections = cursor.textEdit->extraSelections();
+ // ### can the extra selections impact layout? If so they
+ // ### need to be in the actual textLayout shouldn't need
+ // ### to care about the actual selection
+ }
+ int startPos = (cursor.position() == 0
+ ? 0
+ : qMax(0, doc->find(QLatin1Char('\n'), cursor.position() - 1, TextPagerDocument::FindBackward).anchor()));
+ // We start at the beginning of the current line
+ int linesAbove = margin;
+ if (startPos > 0) {
+ while (linesAbove > 0) {
+ const TextPagerCursor c = doc->find(QLatin1Char('\n'), startPos - 1, TextPagerDocument::FindBackward);
+ if (c.isNull()) {
+ startPos = 0;
+ break;
+ }
+ startPos = c.anchor();
+ ASSUME(c.anchor() == 0 || c.cursorCharacter() == QLatin1Char('\n'));
+ ASSUME(c.anchor() == 0 || doc->readCharacter(c.anchor()) == QLatin1Char('\n'));
+ ASSUME(c.cursorCharacter() == doc->readCharacter(c.anchor()));
+
+ --linesAbove;
+ }
+ }
+
+ int linesBelow = margin;
+ int endPos = cursor.position();
+ if (endPos < doc->documentSize()) {
+ while (linesBelow > 0) {
+ const TextPagerCursor c = doc->find(QLatin1Char('\n'), endPos + 1);
+ if (c.isNull()) {
+ endPos = doc->documentSize();
+ break;
+ }
+ endPos = c.anchor();
+ --linesBelow;
+ }
+ }
+ if (startPos > 0)
+ ++startPos; // in this case startPos points to the newline before it
+ l->viewportPosition = startPos;
+ l->layoutDirty = true;
+ ASSUME(l->viewportPosition == 0 || doc->readCharacter(l->viewportPosition - 1) == QLatin1Char('\n'));
+ l->relayoutByPosition(endPos - startPos + 100); // ### fudged a couple of lines likely
+ ASSUME(l->viewportPosition < l->layoutEnd
+ || (l->viewportPosition == l->layoutEnd && l->viewportPosition == doc->documentSize()));
+ ASSUME(l->textLayouts.size() > margin * 2 || l->viewportPosition == 0 || l->layoutEnd == doc->documentSize());
+ return l;
+ }
+private Q_SLOTS:
+ void onDocumentDestroyed(QObject *o)
+ {
+ qDeleteAll(cache.take(static_cast<TextPagerDocument*>(o)));
+ }
+
+ void onCharactersAddedOrRemoved(int pos)
+ {
+ QList<TextPagerLayout*> &layouts = cache[qobject_cast<TextPagerDocument*>(sender())];
+ ASSUME(!layouts.isEmpty());
+ for (int i=layouts.size() - 1; i>=0; --i) {
+ TextPagerLayout *l = layouts.at(i);
+ if (pos <= l->layoutEnd) {
+ delete l;
+ layouts.removeAt(i);
+ }
+ }
+ if (layouts.isEmpty()) {
+ disconnect(sender(), 0, this, 0);
+ cache.remove(qobject_cast<TextPagerDocument*>(sender()));
+ }
+ }
+private:
+ TextLayoutCacheManager(QObject *parent)
+ : QObject(parent)
+ {
+ maxLayouts = qMax(1, qgetenv("TEXTCURSOR_MAX_CACHED_TEXTLAYOUTS").toInt());
+ }
+
+ int maxLayouts;
+ QHash<TextPagerDocument*, QList<TextPagerLayout*> > cache;
+};
+
+class TextPagerLayout;
+struct TextCursorSharedPrivate
+{
+public:
+ TextCursorSharedPrivate() : ref(1), position(-1), anchor(-1),
+ overrideColumn(-1), viewportWidth(-1),
+ document(0)
+ {}
+
+ ~TextCursorSharedPrivate()
+ {
+ ASSUME(ref == 0);
+ }
+
+ void invalidate()
+ {
+
+ }
+
+ mutable QAtomicInt ref;
+ int position, anchor, overrideColumn, viewportWidth;
+
+ TextPagerDocument *document;
+};
+
+
+#endif
diff --git a/Viewer/src/TextPager/TextPagerDocument.cpp b/Viewer/src/TextPager/TextPagerDocument.cpp
new file mode 100644
index 0000000..5c603ce
--- /dev/null
+++ b/Viewer/src/TextPager/TextPagerDocument.cpp
@@ -0,0 +1,1795 @@
+#include "TextPagerDocument.hpp"
+#include "TextPagerCursor.hpp"
+#include "TextPagerCursor_p.hpp"
+#include "TextPagerDocument_p.hpp"
+#include <QBuffer>
+#include <QIODevice>
+#include <QObject>
+#include <QString>
+#include <QString>
+#include <QFile>
+#include <QFileInfo>
+#include <QList>
+#include <QTextCharFormat>
+#include <QVariant>
+#include <QDesktopServices>
+#include <qalgorithms.h>
+
+//#define TEXTDOCUMENT_FIND_DEBUG
+#define TEXTDOCUMENT_USE_FILE_LOCK
+
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+ #include <QStandardPaths>
+#endif
+
+// #define DEBUG_CACHE_HITS
+
+#ifndef TEXTDOCUMENT_FIND_INTERVAL_PERCENTAGE
+#define TEXTDOCUMENT_FIND_INTERVAL_PERCENTAGE 1000
+#endif
+
+#ifndef TEXTDOCUMENT_MAX_INTERVAL
+#define TEXTDOCUMENT_MAX_INTERVAL 1000
+#endif
+
+#ifdef TEXTDOCUMENT_FIND_SLEEP
+static void findSleep(const TextPagerDocument *document)
+{
+ Q_ASSERT(document);
+ const int duration = document->property("TEXTDOCUMENT_FIND_SLEEP").toInt();
+ if (duration > 0) {
+ usleep(duration * 1000);
+ }
+}
+#endif
+
+TextPagerDocument::TextPagerDocument(QObject *parent)
+ : QObject(parent), d(new TextDocumentPrivate(this))
+{
+}
+
+TextPagerDocument::~TextPagerDocument()
+{
+ {
+ QWriteLocker locker(d->readWriteLock);
+ Q_FOREACH(TextCursorSharedPrivate *cursor, d->textCursors) {
+ cursor->document = 0;
+ }
+ Chunk *c = d->first;
+ while (c) {
+ if (!(d->options & KeepTemporaryFiles) && !c->swap.isEmpty())
+ QFile::remove(c->swap);
+ Chunk *tmp = c;
+ c = c->next;
+ delete tmp;
+ }
+ Q_FOREACH(TextPagerSection *section, d->sections) {
+ section->d.document = 0;
+ section->d.textEdit = 0;
+ delete section;
+ }
+ if (d->ownDevice)
+ delete d->device.data();
+ }
+ delete d->readWriteLock;
+ delete d;
+}
+
+bool TextPagerDocument::load(QIODevice *device, DeviceMode mode, QTextCodec *codec)
+{
+ QWriteLocker locker(d->readWriteLock);
+ Q_ASSERT(device);
+ if (!device->isReadable())
+ return false;
+
+ Options options = d->options;
+ if (options & ConvertCarriageReturns && mode == Sparse) {
+ qWarning("TextPagerDocument::load() ConvertCarriageReturns is incompatible with Sparse");
+ options &= ~ConvertCarriageReturns;
+ }
+ if ((options & (AutoDetectCarriageReturns|ConvertCarriageReturns)) == (AutoDetectCarriageReturns|ConvertCarriageReturns))
+ options &= ~AutoDetectCarriageReturns;
+
+ Q_FOREACH(TextPagerSection *section, d->sections) {
+ Q_EMIT sectionRemoved(section);
+ section->d.document = 0;
+ delete section;
+ }
+ d->sections.clear();
+
+ if (d->documentSize > 0) {
+ Q_EMIT charactersRemoved(0, d->documentSize);
+ }
+
+ Chunk *c = d->first;
+ while (c) {
+ Chunk *tmp = c;
+ c = c->next;
+ delete tmp;
+ }
+
+ d->textCodec = codec;
+ d->documentSize = device->size();
+ if (d->documentSize <= d->chunkSize && mode == Sparse && !(options & NoImplicitLoadAll))
+ mode = LoadAll;
+#if 0
+ if (codec && mode == Sparse) {
+
+ qWarning("Sparse mode doesn't really work with unicode data yet. I am working on it.\n--\nAnders");
+ }
+#endif
+ d->first = d->last = 0;
+
+ if (d->device) {
+ if (d->ownDevice && d->device.data() != device) // this is done when saving to the same file
+ delete d->device.data();
+ }
+
+ d->ownDevice = false;
+ d->device = device;
+ d->deviceMode = mode;
+#ifndef NO_TEXTDOCUMENT_CHUNK_CACHE
+ d->cachedChunk = 0;
+ d->cachedChunkPos = -1;
+ d->cachedChunkData.clear();
+#endif
+#ifndef NO_TEXTDOCUMENT_READ_CACHE
+ d->cachePos = -1;
+ d->cache.clear();
+#endif
+
+ switch (d->deviceMode) {
+ case LoadAll: {
+ device->seek(0);
+ QTextStream ts(device);
+ if (d->textCodec)
+ ts.setCodec(d->textCodec);
+ Chunk *current = 0;
+ d->documentSize = 0; // in case of unicode
+ do {
+ Chunk *c = new Chunk;
+ c->data = ts.read(d->chunkSize);
+ if (options & AutoDetectCarriageReturns) {
+ if (c->data.contains(QLatin1Char('\n'))) {
+ options |= ConvertCarriageReturns;
+ }
+ options &= ~AutoDetectCarriageReturns;
+ }
+ if (options & ConvertCarriageReturns)
+ c->data.remove(QLatin1Char('\r'));
+ d->documentSize += c->data.size();
+ if (current) {
+ current->next = c;
+ c->previous = current;
+ } else {
+ d->first = c;
+ }
+ current = c;
+ } while (!ts.atEnd());
+
+ d->last = current;
+ break; }
+
+ case Sparse: {
+ int index = 0;
+ Chunk *current = 0;
+ do {
+ Chunk *chunk = new Chunk;
+ chunk->from = index;
+ chunk->length = qMin<int>(d->documentSize - index, d->chunkSize);
+ if (!current) {
+ d->first = chunk;
+ } else {
+ chunk->previous = current;
+ current->next = chunk;
+ }
+ current = chunk;
+ index += chunk->length;
+ } while (index < d->documentSize);
+
+ d->last = current;
+ break; }
+ }
+// if (d->first)
+// d->first->firstLineIndex = 0;
+ Q_EMIT charactersAdded(0, d->documentSize);
+ Q_EMIT documentSizeChanged(d->documentSize);
+ Q_EMIT textChanged();
+
+ return true;
+}
+
+bool TextPagerDocument::load(const QString &fileName, DeviceMode mode, QTextCodec *codec)
+{
+ if (mode == LoadAll) {
+ QFile from(fileName);
+ return from.open(QIODevice::ReadOnly) && load(&from, mode, codec);
+ } else {
+ QFile *file = new QFile(fileName);
+ if (file->open(QIODevice::ReadOnly) && load(file, mode, codec)) {
+ d->ownDevice = true;
+ return true;
+ } else {
+ delete file;
+ d->ownDevice = false;
+ return false;
+ }
+ }
+}
+
+void TextPagerDocument::clear()
+{
+ setText(QString());
+}
+
+QString TextPagerDocument::read(int pos, int size) const
+{
+ QReadLocker locker(d->readWriteLock);
+ Q_ASSERT(size >= 0);
+ if (size == 0 || pos == d->documentSize) {
+ return QString();
+ }
+ Q_ASSERT(pos < d->documentSize);
+
+#ifndef NO_TEXTDOCUMENT_READ_CACHE
+#ifdef DEBUG_CACHE_HITS
+ static int hits = 0;
+ static int misses = 0;
+#endif
+ if (d->cachePos != -1 && pos >= d->cachePos && d->cache.size() - (pos - d->cachePos) >= size) {
+#ifdef DEBUG_CACHE_HITS
+ qWarning() << "read hits" << ++hits << "misses" << misses;
+#endif
+ return d->cache.mid(pos - d->cachePos, size);
+ }
+#ifdef DEBUG_CACHE_HITS
+ qWarning() << "read hits" << hits << "misses" << ++misses;
+#endif
+#endif
+
+ QString ret(size, '\0');
+ int written = 0;
+ int offset;
+ Chunk *c = d->chunkAt(pos, &offset);
+ Q_ASSERT(c);
+ int chunkPos = pos - offset;
+
+ while (written < size && c) {
+ const int max = qMin(size - written, c->size() - offset);
+ const QString data = d->chunkData(c, chunkPos);
+ chunkPos += data.size();
+ ret.replace(written, max, data.constData() + offset, max);
+ written += max;
+ offset = 0;
+ c = c->next;
+ }
+
+ if (written < size) {
+ ret.truncate(written);
+ }
+ Q_ASSERT(!c || written == size);
+#ifndef NO_TEXTDOCUMENT_READ_CACHE
+ d->cachePos = pos;
+ d->cache = ret;
+#endif
+ return ret;
+}
+
+QStringRef TextPagerDocument::readRef(int pos, int size) const
+{
+ QReadLocker locker(d->readWriteLock);
+ int offset;
+ Chunk *c = d->chunkAt(pos, &offset);
+ if (c && pos + offset + size <= c->size()) {
+ const QString string = d->chunkData(c, pos - offset);
+ return string.midRef(offset, size);
+ }
+ return QStringRef();
+}
+
+static bool isSameFile(const QIODevice *left, const QIODevice *right)
+{
+ if (left == right)
+ return true;
+ if (const QFile *lf = qobject_cast<const QFile *>(left)) {
+ if (const QFile *rf = qobject_cast<const QFile *>(right)) {
+ return QFileInfo(*lf) == QFileInfo(*rf);
+ }
+ }
+ return false;
+}
+
+int TextPagerDocument::documentSize() const
+{
+ QReadLocker locker(d->readWriteLock);
+ return d->documentSize;
+}
+
+int TextPagerDocument::chunkCount() const
+{
+ QReadLocker locker(d->readWriteLock);
+ Chunk *c = d->first;
+ int count = 0;
+ while (c) {
+ ++count;
+ c = c->next;
+ }
+ return count;
+}
+
+int TextPagerDocument::instantiatedChunkCount() const
+{
+ QReadLocker locker(d->readWriteLock);
+ Chunk *c = d->first;
+ int count = 0;
+ while (c) {
+ if (!c->data.isEmpty())
+ ++count;
+ c = c->next;
+ }
+ return count;
+}
+
+int TextPagerDocument::swappedChunkCount() const
+{
+ QReadLocker locker(d->readWriteLock);
+ Chunk *c = d->first;
+ int count = 0;
+ while (c) {
+ if (!c->swap.isEmpty())
+ ++count;
+ c = c->next;
+ }
+ return count;
+}
+
+TextPagerDocument::DeviceMode TextPagerDocument::deviceMode() const
+{
+ QReadLocker locker(d->readWriteLock);
+ return d->deviceMode;
+}
+
+QTextCodec * TextPagerDocument::textCodec() const
+{
+ QReadLocker locker(d->readWriteLock);
+ return d->textCodec;
+}
+
+class FindScope
+{
+public:
+ FindScope(TextDocumentPrivate::FindState *s) : state(s) { if (state) *state = TextDocumentPrivate::Finding; }
+ ~FindScope() { if (state) *state = TextDocumentPrivate::NotFinding; }
+ TextDocumentPrivate::FindState *state;
+};
+
+static void initFind(const TextPagerCursor &cursor, bool reverse, int *start, int *limit)
+{
+ if (cursor.hasSelection()) {
+ *start = cursor.selectionStart();
+ *limit = cursor.selectionEnd();
+ if (reverse) {
+ qSwap(*start, *limit);
+ }
+ } else {
+ *start = cursor.position();
+ *limit = (reverse ? 0 : cursor.document()->documentSize());
+ }
+
+
+}
+
+static void initFindForLines(const TextPagerCursor &cursor, bool reverse, int *start, int *limit)
+{
+ *start = cursor.position();
+ if(*limit == -1)
+ *limit = (reverse ? 0 : cursor.document()->documentSize());
+
+#ifdef TEXTDOCUMENT_FIND_DEBUG
+ qDebug() << "initial position" << "pos:" << *start << "anchor:" << cursor.anchor();
+#endif
+
+ //Change the search position according to the selection and search
+ //direction
+ if(cursor.anchor() >=0)
+ {
+ int ca=cursor.anchor();
+
+ if(!reverse)
+ {
+ if(*start < ca)
+ *start=ca;
+ }
+ else
+ {
+ if(*start > ca && ca >0)
+ *start=ca-1;
+ else if(*start >0)
+ *start=(*start)-1;
+ }
+ }
+
+#ifdef TEXTDOCUMENT_FIND_DEBUG
+ qDebug() << "modified position" << "pos:" << *start << "anchor:" << cursor.anchor();
+#endif
+
+}
+
+TextPagerCursor TextPagerDocument::find(const QRegExp ®exp, const TextPagerCursor &cursor, FindMode flags,int limit) const
+{
+#ifdef TEXTDOCUMENT_FIND_DEBUG
+ qDebug() << "---> TextPagerDocument::find" << "regexp" << regexp;
+#endif
+
+ if(documentSize() == 0 || cursor.textEdit == NULL)
+ return TextPagerCursor();
+
+ if(regexp.isEmpty())
+ return TextPagerCursor();
+
+ QReadLocker locker(d->readWriteLock);
+ if (flags & FindWholeWords) {
+ qWarning("FindWholeWords doesn't work with regexps. Instead use an actual RegExp for this");
+ }
+ if (flags & FindCaseSensitively) {
+ qWarning("FindCaseSensitively doesn't work with regexps. Instead use an QRegExp::caseSensitivity for this");
+ }
+ /* if (flags & FindWrap && cursor.hasSelection()) {
+ qWarning("It makes no sense to pass FindWrap and set a selection for the cursor. The entire selection will be searched");
+ flags &= ~FindWrap;
+ }*/
+
+ const bool reverse = flags & FindBackward;
+ int pos;
+ ::initFindForLines(cursor, reverse, &pos, &limit);
+
+ if(reverse) {
+ if(pos < limit)
+ return TextPagerCursor();
+ } else {
+ if(pos > limit)
+ return TextPagerCursor();
+ }
+
+ if (pos == d->documentSize) {
+ if (reverse) {
+ --pos;
+ } else if (!(flags & FindWrap)) {
+ return TextPagerCursor();
+ }
+ }
+
+ const TextDocumentIterator::Direction direction = (reverse
+ ? TextDocumentIterator::Left
+ : TextDocumentIterator::Right);
+ TextDocumentIterator it(d, pos);
+ if (reverse) {
+ it.setMinBoundary(limit);
+ } else {
+ it.setMaxBoundary(limit);
+ }
+ const QLatin1Char newline('\n');
+ int last = pos;
+ bool ok = true;
+ int progressInterval = 0;
+ int lastProgress = pos;
+ const int initialPos = pos;
+ int maxFindLength = 0;
+ const FindScope scope(flags & FindAllowInterrupt ? &d->findState : 0);
+ QTime lastProgressTime;
+ if (flags & FindAllowInterrupt) {
+ progressInterval = qMax<int>(1, (reverse
+ ? (static_cast<qreal>(pos) / static_cast<qreal>(TEXTDOCUMENT_FIND_INTERVAL_PERCENTAGE))
+ : (static_cast<qreal>(d->documentSize) - static_cast<qreal>(pos)) / 100.0));
+ maxFindLength = (reverse ? pos : d->documentSize - pos);
+ lastProgressTime.start();
+ }
+
+ QString line;
+ int index;
+ int from;
+#ifdef TEXTDOCUMENT_FIND_DEBUG
+ QTime lap;
+ lap.start();
+#endif
+
+ //Loop over the lines in the document. Since we can have millions of lines it has to be
+ //extremely fast.
+ do {
+#ifdef TEXTDOCUMENT_FIND_SLEEP
+ findSleep(this);
+#endif
+
+ //This clears the string without reallocation
+ line.resize(0);
+
+ if(((reverse)?it.prevLine(line):it.nextLine(line)) == 0)
+ {
+ ok=false;
+ if(line.isEmpty())
+ break;
+ }
+
+ //We only search for the first occurrence. So the FindAll flag is ignored.
+
+ //QRegExp::lastIndexIn() is 3 times slower than QRegExp::indexIn()!! So we always call
+ //indexIn() first the lastIndexIn() if we need the reverse order.
+
+ if((index = regexp.indexIn(line, 0)) != -1) {
+
+#ifdef TEXTDOCUMENT_FIND_DEBUG
+ qDebug() << line;
+#endif
+
+ if(reverse) {
+ index = regexp.lastIndexIn(line, line.size());
+ from = it.position(); //-line.size();
+
+ if(from + index < limit) {
+ ok = false;
+ } else {
+ const TextPagerCursor ret(this, from + index, from + index + regexp.matchedLength());
+#ifdef TEXTDOCUMENT_FIND_DEBUG
+ qDebug() << "total time" << lap.elapsed();
+ qDebug() << "result" << "pos:" << ret.position() << "anchor:" << ret.anchor();
+#endif
+ return ret;
+ }
+ } else {
+
+ from = it.position()-line.size()+1;
+
+ if(from + index + regexp.matchedLength() > limit) {
+ ok = false;
+ } else {
+
+ //we need to remove the newline char from the end of the matching text
+ QString captured=regexp.capturedTexts().first();
+ if(index + regexp.matchedLength() == line.size() && line.endsWith(newline))
+ {
+ captured.chop(1);
+ }
+
+ const TextPagerCursor ret(this, from + index + captured.size(), from + index);
+#ifdef TEXTDOCUMENT_FIND_DEBUG
+ qDebug() << "current:" << it.current() << it.position() << line.size();
+ qDebug() << "captured:" << index << captured;
+ qDebug() << "cursor:" << ret.selectedText();
+#endif
+ Q_ASSERT(ret.selectedText() == captured);
+#ifdef TEXTDOCUMENT_FIND_DEBUG
+ qDebug() << "total time" << lap.elapsed();
+ qDebug() << "result" << "pos:" << ret.position() << "anchor:" << ret.anchor();
+#endif
+ return ret;
+ }
+ }
+ }
+
+
+ /*if (progressInterval != 0) {
+ const int progress = qAbs(it.position() - lastProgress);
+ if (progress >= progressInterval
+ || (lastProgressTime.elapsed() >= TEXTDOCUMENT_MAX_INTERVAL)) {
+ const qreal progress = qAbs<int>(static_cast<qreal>(it.position() - initialPos)) / static_cast<qreal>(maxFindLength);
+ Q_EMIT findProgress(progress * 100.0, it.position());
+ if (d->findState == TextDocumentPrivate::AbortFind) {
+ return TextPagerCursor();
+ }
+ lastProgress = it.position();
+ lastProgressTime.restart();
+ }
+ }*/
+
+ } while (ok);
+
+#ifdef TEXTDOCUMENT_FIND_DEBUG
+ qDebug() << "total time" << lap.elapsed();
+ qDebug() << "iterator position:" << it.position();
+#endif
+
+ if (flags & FindWrap) {
+
+#ifdef TEXTDOCUMENT_FIND_DEBUG
+ qDebug() << "---> end of doc reached. FindWrap will start.";
+#endif
+ //Q_ASSERT(!cursor.hasSelection());
+ if (reverse) {
+ if (cursor.position() + 1 < d->documentSize) {
+ return find(regexp, TextPagerCursor(this, d->documentSize), flags & ~FindWrap, cursor.position());
+ }
+ } else if (cursor.position() > 0) {
+ return find(regexp, TextPagerCursor(this, 0), flags & ~FindWrap, cursor.position());
+ }
+ }
+
+ return TextPagerCursor();
+}
+
+TextPagerCursor TextPagerDocument::find(const QString &in, const TextPagerCursor &cursor, FindMode flags, int limit) const
+{
+#ifdef TEXTDOCUMENT_FIND_DEBUG
+ qDebug() << "---> TextPagerDocument::find" << "string:" << in;
+#endif
+
+ if (in.isEmpty()) {
+ return TextPagerCursor();
+ }
+
+ QReadLocker locker(d->readWriteLock);
+
+ const bool reverse = flags & FindBackward;
+ const bool caseSensitive = flags & FindCaseSensitively;
+ const bool wholeWords = flags & FindWholeWords;
+
+ /* if (flags & FindWrap && cursor.hasSelection()) {
+ qWarning("It makes no sense to pass FindWrap and set a selection for the cursor. The entire selection will be searched");
+ flags &= ~FindWrap;
+ }
+*/
+ const QLatin1Char newline('\n');
+ int pos;
+ ::initFindForLines(cursor, reverse, &pos, &limit);
+
+ //Sanity check!!
+ Q_ASSERT(pos >= 0 && pos <= d->documentSize);
+ Q_ASSERT(limit >= 0 && limit <= d->documentSize);
+
+ if(reverse) {
+ if(pos < limit)
+ return TextPagerCursor();
+ } else {
+ if(pos > limit)
+ return TextPagerCursor();
+ }
+
+ if (pos == d->documentSize) {
+ if (reverse) {
+ --pos;
+ } else if (!(flags & FindWrap)) {
+ return TextPagerCursor();
+ }
+ }
+
+ // ### what if one searches for a string with non-word characters in it and FindWholeWords?
+ const TextDocumentIterator::Direction direction = (reverse ? TextDocumentIterator::Left : TextDocumentIterator::Right);
+ QString word = caseSensitive ? in : in.toLower();
+
+ TextDocumentIterator it(d, pos);
+ if (reverse) {
+ it.setMinBoundary(limit);
+ } else {
+ it.setMaxBoundary(limit);
+ }
+
+#ifdef TEXTDOCUMENT_FIND_DEBUG
+ qDebug() << "current character:" << it.current();
+#endif
+
+ if (!caseSensitive)
+ it.setConvertToLowerCase(true);
+
+ bool ok = true;
+ QChar ch = it.current();
+ int wordIndex = 0;
+ int progressInterval = 0;
+ int lastProgress = pos;
+ const int initialPos = pos;
+ int maxFindLength = 0;
+ const FindScope scope(flags & FindAllowInterrupt ? &d->findState : 0);
+ QTime lastProgressTime;
+ if (flags & FindAllowInterrupt) {
+ progressInterval = qMax<int>(1, (reverse
+ ? (static_cast<qreal>(pos) / static_cast<qreal>(TEXTDOCUMENT_FIND_INTERVAL_PERCENTAGE))
+ : (static_cast<qreal>(d->documentSize) - static_cast<qreal>(pos)) / 100.0));
+ maxFindLength = (reverse ? pos : d->documentSize - pos);
+ lastProgressTime.start();
+ }
+
+ QString line;
+ int index;
+ int from;
+#ifdef TEXTDOCUMENT_FIND_DEBUG
+ QTime lap;
+ lap.start();
+#endif
+
+ do {
+#ifdef TEXTDOCUMENT_FIND_SLEEP
+ findSleep(this);
+#endif
+ /* if (progressInterval != 0) {
+ const int progress = qAbs(it.position() - lastProgress);
+ if (progress >= progressInterval
+ || (progress % 10 == 0 && lastProgressTime.elapsed() >= TEXTDOCUMENT_MAX_INTERVAL)) {
+ const qreal progress = qAbs<int>(static_cast<qreal>(it.position() - initialPos)) / static_cast<qreal>(maxFindLength);
+ Q_EMIT findProgress(progress * 100.0, it.position());
+ if (d->findState == TextDocumentPrivate::AbortFind) {
+ return TextPagerCursor();
+ }
+ lastProgress = it.position();
+ lastProgressTime.restart();
+ }
+ }*/
+
+ //This clears the string without reallocation
+ line.resize(0);
+
+ if(((reverse)?it.prevLine(line):it.nextLine(line)) == 0)
+ {
+ ok=false;
+ if(line.isEmpty())
+ break;
+ }
+
+ if(!caseSensitive)
+ line=line.toLower();
+
+#ifdef TEXTDOCUMENT_FIND_DEBUG
+ //qDebug() << line;
+#endif
+
+ if((index=line.indexOf(word)) != -1) {
+
+ //Backward:
+ //The iterator is positioned at the linebreak character of the previous line, or at
+ //the start of the document
+ if(reverse) {
+ from = it.position();
+ index=line.lastIndexOf(word);
+ }
+ //Forward:
+ //The iterator is positioned at the linebreak character at the end of the line or at
+ //the end of the document
+ else {
+ from = it.position()-line.size()+1;
+ }
+
+ while(ok && index != -1) {
+
+ const int startPos=from + index;
+ const int endPos=from + index + word.size();
+
+ if(!reverse && endPos > limit) {
+ ok = false;
+ break;
+ }
+
+ bool found=true;
+ if(wholeWords) {
+
+ if(TextDocumentIterator::Left != d->wordBoundariesAt(startPos)) {
+ found = false;
+ }
+ if(found) {
+ if(TextDocumentIterator::Right != d->wordBoundariesAt(endPos-1)) {
+ found = false;
+ }
+ }
+ }
+
+ if(found) {
+
+#ifdef TEXTDOCUMENT_FIND_DEBUG
+ qDebug() << line;
+#endif
+ //Backward
+ if(reverse) {
+ TextPagerCursor ret(this, startPos, endPos);
+#ifdef TEXTDOCUMENT_FIND_DEBUG
+ qDebug() << "total time" << lap.elapsed();
+ qDebug() << "current:" << it.current() << it.position() << line.size();
+ qDebug() << "result" << "pos:" << ret.position() << "anchor:" << ret.anchor();
+#endif
+ return ret;
+ //Forward
+ } else {
+
+ TextPagerCursor ret(this, endPos,startPos);
+#ifdef TEXTDOCUMENT_FIND_DEBUG
+ qDebug() << "total time" << lap.elapsed();
+ qDebug() << "current:" << it.current() << it.position() << line.size();
+ qDebug() << "result" << "pos:" << ret.position() << "anchor:" << ret.anchor();
+#endif
+ return ret;
+ }
+
+ //If it is not a wholeword we try to match every other match int he same line
+ } else {
+
+ if(reverse) {
+ index=line.lastIndexOf(word,index-1);
+ } else {
+ index=line.indexOf(word,index+word.size());
+ }
+
+ }
+ } //while
+
+ }
+
+#if 0
+ bool found = ch == word.at(wordIndex);
+ if (found && wholeWords && (wordIndex == 0 || wordIndex == word.size() - 1)) {
+ Q_ASSERT(word.size() > 1);
+ const uint requiredBounds = ((wordIndex == 0) != reverse)
+ ? TextDocumentIterator::Left
+ : TextDocumentIterator::Right;
+ const uint bounds = d->wordBoundariesAt(it.position());
+ if (requiredBounds & ~bounds) {
+ found = false;
+ }
+ }
+ if (found) {
+ if (++wordIndex == word.size()) {
+ const int pos = it.position() - (reverse ? 0 : word.size() - 1);
+ // the iterator reads one past the last matched character so we have to account for that here
+ const TextPagerCursor ret(this, pos + wordIndex, pos);
+ if (flags & FindAll) {
+ Q_EMIT entryFound(ret);
+ if (d->findState == TextDocumentPrivate::AbortFind)
+ return TextPagerCursor();
+ wordIndex = 0;
+ } else {
+ return ret;
+ }
+ }
+ } else if (wordIndex != 0) {
+ wordIndex = 0;
+ continue;
+ }
+ ch = it.nextPrev(direction, ok);
+
+#endif
+
+ } while (ok);
+
+#ifdef TEXTDOCUMENT_FIND_DEBUG
+ qDebug() << "total time" << lap.elapsed();
+#endif
+
+ if (flags & FindWrap) {
+ //Q_ASSERT(!cursor.hasSelection());
+ if (reverse) {
+
+ if (cursor.position() + 1 < d->documentSize) {
+ return find(in, TextPagerCursor(this, d->documentSize), flags & ~FindWrap,cursor.position());
+ }
+ } else if (cursor.position() > 0) {
+ return find(in, TextPagerCursor(this, 0), flags & ~FindWrap,cursor.position());
+ }
+ }
+
+ return TextPagerCursor();
+}
+
+TextPagerCursor TextPagerDocument::find(const QChar &chIn, const TextPagerCursor &cursor, FindMode flags) const
+{
+ QReadLocker locker(d->readWriteLock);
+ if (flags & FindWrap && cursor.hasSelection()) {
+ qWarning("It makes no sense to pass FindWrap and set a selection for the cursor. The entire selection will be searched");
+ flags &= ~FindWrap;
+ }
+
+ const bool reverse = flags & FindBackward;
+ int pos;
+ int limit;
+ ::initFind(cursor, reverse, &pos, &limit);
+ if (pos == d->documentSize) {
+ if (reverse) {
+ --pos;
+ } else if (!(flags & FindWrap)) {
+ return TextPagerCursor();
+ }
+ }
+ Q_ASSERT(pos >= 0 && pos <= d->documentSize);
+
+ const bool caseSensitive = flags & FindCaseSensitively;
+ const bool wholeWords = flags & FindWholeWords;
+ const QChar ch = (caseSensitive ? chIn : chIn.toLower());
+ TextDocumentIterator it(d, pos);
+ if (reverse) {
+ it.setMinBoundary(limit);
+ } else {
+ it.setMaxBoundary(limit);
+ }
+ const TextDocumentIterator::Direction dir = (reverse
+ ? TextDocumentIterator::Left
+ : TextDocumentIterator::Right);
+ int lastProgress = pos;
+ const int initialPos = pos;
+ int maxFindLength = 0;
+ int progressInterval = 0;
+ const FindScope scope(flags & FindAllowInterrupt ? &d->findState : 0);
+ QTime lastProgressTime;
+ if (flags & FindAllowInterrupt) {
+ progressInterval = qMax<int>(1, (reverse
+ ? (static_cast<qreal>(pos) / static_cast<qreal>(TEXTDOCUMENT_FIND_INTERVAL_PERCENTAGE))
+ : (static_cast<qreal>(d->documentSize) - static_cast<qreal>(pos)) / 100.0));
+ maxFindLength = (reverse ? pos : d->documentSize - pos);
+ lastProgressTime.start();
+ }
+
+ QChar c = it.current();
+ bool ok = true;
+ do {
+#ifdef TEXTDOCUMENT_FIND_SLEEP
+ findSleep(this);
+#endif
+ if (((caseSensitive ? c : c.toLower()) == ch)
+ && (!wholeWords || (d->wordBoundariesAt(it.position()) == TextDocumentIterator::Both))) {
+ const TextPagerCursor ret(this, it.position() + 1, it.position());
+ if (flags & FindAll) {
+ Q_EMIT entryFound(ret);
+ if (d->findState == TextDocumentPrivate::AbortFind)
+ return TextPagerCursor();
+ } else {
+ return ret;
+ }
+ }
+ c = it.nextPrev(dir, ok);
+// qDebug() << "progressInterval" << progressInterval << qAbs(it.position() - lastProgress)
+// << lastProgressTime.elapsed() << TEXTDOCUMENT_MAX_INTERVAL;
+ if (progressInterval != 0) {
+ const int progress = qAbs(it.position() - lastProgress);
+ if (progress >= progressInterval
+ || (progress % 10 == 0 && lastProgressTime.elapsed() >= TEXTDOCUMENT_MAX_INTERVAL)) {
+ const qreal progress = qAbs<int>(static_cast<qreal>(it.position() - initialPos)) / static_cast<qreal>(maxFindLength);
+ Q_EMIT findProgress(progress * 100.0, it.position());
+ if (d->findState == TextDocumentPrivate::AbortFind) {
+ return TextPagerCursor();
+ }
+ lastProgress = it.position();
+ lastProgressTime.restart();
+ }
+ }
+ } while (ok);
+
+ if (flags & FindWrap) {
+ Q_ASSERT(!cursor.hasSelection());
+ if (reverse) {
+ if (cursor.position() + 1 < d->documentSize) {
+ return find(ch, TextPagerCursor(this, cursor.position(), d->documentSize), flags & ~FindWrap);
+ }
+ } else if (cursor.position() > 0) {
+ return find(ch, TextPagerCursor(this, 0, cursor.position()), flags & ~FindWrap);
+ }
+ }
+
+ return TextPagerCursor();
+}
+
+static inline int count(const QString &string, int from, int size, const QChar &ch)
+{
+ Q_ASSERT(from + size <= string.size());
+ const ushort needle = ch.unicode();
+ const ushort *haystack = string.utf16() + from;
+ int num = 0;
+ for (int i=0; i<size; ++i) {
+ if (*haystack++ == needle)
+ ++num;
+ }
+// Q_ASSERT(string.mid(from, size).count(ch) == num);
+ return num;
+}
+
+void TextPagerDocument::takeTextSection(TextPagerSection *section)
+{
+ QWriteLocker locker(d->readWriteLock);
+ Q_ASSERT(section);
+ Q_ASSERT(section->document() == this);
+
+ QList<TextPagerSection*>::iterator first = qLowerBound(d->sections.begin(), d->sections.end(), section, compareTextSection);
+ Q_ASSERT(first != d->sections.end());
+ const QList<TextPagerSection*>::iterator last = qUpperBound(d->sections.begin(), d->sections.end(), section, compareTextSection);
+
+ while (first != last) {
+ if (*first == section) {
+ Q_EMIT sectionRemoved(section);
+ d->sections.erase(first);
+ break;
+ }
+ ++first;
+ }
+
+ // Moved this to the end as the slots called by sectionRemoved (presently) rely
+ // on section->d.document to be valid.
+ section->d.textEdit = 0;
+ section->d.document = 0;
+}
+
+QList<TextPagerSection*> TextPagerDocument::sections(int pos, int size, TextPagerSection::TextSectionOptions flags) const
+{
+ QReadLocker locker(d->readWriteLock);
+ return d->getSections(pos, size, flags, 0);
+}
+
+void TextPagerDocument::insertTextSection(TextPagerSection *section)
+{
+ QWriteLocker locker(d->readWriteLock);
+ Q_ASSERT(!d->sections.contains(section));
+ QList<TextPagerSection*>::iterator it = qLowerBound<QList<TextPagerSection*>::iterator>(d->sections.begin(), d->sections.end(),
+ section, compareTextSection);
+ d->sections.insert(it, section);
+ Q_EMIT sectionAdded(section);
+}
+
+TextPagerSection *TextPagerDocument::insertTextSection(int pos, int size,
+ const QTextCharFormat &format, const QVariant &data)
+{
+ QWriteLocker locker(d->readWriteLock);
+ Q_ASSERT(pos >= 0);
+ Q_ASSERT(size >= 0);
+ Q_ASSERT(pos < d->documentSize);
+
+ TextPagerSection *l = new TextPagerSection(pos, size, this, format, data);
+ QList<TextPagerSection*>::iterator it = qLowerBound<QList<TextPagerSection*>::iterator>(d->sections.begin(), d->sections.end(), l, compareTextSection);
+ d->sections.insert(it, l);
+ Q_EMIT sectionAdded(l);
+ return l;
+}
+
+bool TextPagerDocument::abortSave()
+{
+ if (d->saveState == TextDocumentPrivate::Saving) {
+ d->saveState = TextDocumentPrivate::AbortSave;
+ return true;
+ }
+ return false;
+}
+
+bool TextPagerDocument::abortFind() const
+{
+ if (d->findState == TextDocumentPrivate::Finding) {
+ d->findState = TextDocumentPrivate::AbortFind;
+ return true;
+ }
+ return false;
+}
+
+
+QChar TextPagerDocument::readCharacter(int pos) const
+{
+ QReadLocker locker(d->readWriteLock);
+ if (pos == d->documentSize)
+ return QChar();
+ Q_ASSERT(pos >= 0 && pos < d->documentSize);
+#ifndef NO_TEXTDOCUMENT_READ_CACHE
+#ifdef DEBUG_CACHE_HITS
+ static int hits = 0;
+ static int misses = 0;
+#endif
+ if (pos >= d->cachePos && pos < d->cachePos + d->cache.size()) {
+#ifdef DEBUG_CACHE_HITS
+ qWarning() << "readCharacter hits" << ++hits << "misses" << misses;
+#endif
+ return d->cache.at(pos - d->cachePos);
+ }
+#ifdef DEBUG_CACHE_HITS
+ qWarning() << "readCharacter hits" << hits << "misses" << ++misses;
+#endif
+#endif
+
+ int offset;
+ Chunk *c = d->chunkAt(pos, &offset);
+ return d->chunkData(c, pos - offset).at(offset);
+}
+
+void TextPagerDocument::setText(const QString &text)
+{
+ // ### could optimize this to avoid detach and copy if text.size() <= chunkSize
+ // ### but is it worth it?
+ QBuffer buffer;
+ buffer.open(QIODevice::WriteOnly);
+ QTextStream ts(&buffer);
+ if (d->textCodec)
+ ts.setCodec(d->textCodec);
+ ts << text;
+ buffer.close();
+ buffer.open(QIODevice::ReadOnly);
+ const bool ret = load(&buffer, LoadAll);
+ Q_ASSERT(ret);
+ Q_UNUSED(ret);
+}
+
+int TextPagerDocument::chunkSize() const
+{
+ QReadLocker locker(d->readWriteLock);
+ return d->chunkSize;
+}
+
+void TextPagerDocument::setChunkSize(int size)
+{
+ QWriteLocker locker(d->readWriteLock);
+ Q_ASSERT(d->chunkSize > 0);
+ d->chunkSize = size;
+}
+
+int TextPagerDocument::currentMemoryUsage() const
+{
+ QReadLocker locker(d->readWriteLock);
+ Chunk *c = d->first;
+ int used = 0;
+ while (c) {
+ used += c->data.size() * sizeof(QChar);
+ c = c->next;
+ }
+ return used;
+}
+
+bool TextPagerDocument::isModified() const
+{
+ // ### should it lock for read?
+ return d->modified;
+}
+
+int TextPagerDocument::lineNumber(int position) const
+{
+ QReadLocker locker(d->readWriteLock);
+ d->hasChunksWithLineNumbers = true; // does this need to be a write lock?
+ int offset;
+ Chunk *c = d->chunkAt(position, &offset);
+ d->updateChunkLineNumbers(c, position - offset);
+ Q_ASSERT(c->firstLineIndex != -1);
+ Q_ASSERT(d->first->firstLineIndex != -1);
+ const int extra = (offset == 0 ? 0 : d->countNewLines(c, position - offset, offset));
+
+//#ifdef QT_DEBUG
+#if 0
+ if (position <= 16000) {
+ const QString data = read(0, position);
+ // if we're on a newline it shouldn't count so we do read(0, position)
+ // not read(0, position + 1);
+ const int count = data.count(QLatin1Char('\n'));
+ if (count != c->firstLineIndex + extra) {
+ qDebug() << "TextPagerDocument::lineNumber returns" << (c->firstLineIndex + extra)
+ << "should have returned" << (count + 1)
+ << "for index" << position;
+ }
+ }
+#endif
+
+ return c->firstLineIndex + extra;
+}
+
+int TextPagerDocument::columnNumber(int position) const
+{
+ TextPagerCursor cursor(this, position);
+ return cursor.isNull() ? -1 : cursor.columnNumber();
+}
+
+int TextPagerDocument::lineNumber(const TextPagerCursor &cursor) const
+{
+ return cursor.document() == this ? lineNumber(cursor.position()) : -1;
+}
+
+int TextPagerDocument::columnNumber(const TextPagerCursor &cursor) const
+{
+ return cursor.document() == this ? cursor.columnNumber() : -1;
+}
+
+TextPagerCursor TextPagerDocument::findLine(int lineNum, const TextPagerCursor &cursor) const
+{
+ if(lineNum <=0)
+ return TextPagerCursor();
+
+ lineNum--;
+
+ Q_ASSERT(cursor.position() >=0);
+
+ int current=lineNumber(cursor);
+
+#ifdef TEXTDOCUMENT_FIND_DEBUG
+ qDebug() << "findLine --> line:" << lineNum << "current:" << current;
+#endif
+
+ if(lineNum == current)
+ return cursor;
+
+ int offset;
+ Chunk *c = d->chunkAt(cursor.position(), &offset);
+
+ Q_ASSERT(c != NULL);
+
+ int pos=cursor.position() - offset; //points to the chunks beginning
+ d->updateChunkLineNumbers(c, pos);
+
+#ifdef TEXTDOCUMENT_FIND_DEBUG
+ qDebug() << "chunk - first line:" << c->firstLineIndex << "pos:" << pos;
+#endif
+
+ if(lineNum < current) {
+
+ while(c->firstLineIndex > lineNum && c->previous) {
+ pos-=c->size();
+ c=c->previous;
+ d->updateChunkLineNumbers(c,pos);
+#ifdef TEXTDOCUMENT_FIND_DEBUG
+ //qDebug() << "chunk - first line:" << c->firstLineIndex << "pos:" << pos;
+#endif
+ }
+
+ } else if(lineNum > current) {
+
+ while(c->firstLineIndex < lineNum && c->next) {
+ pos+=c->size();
+ c=c->next;
+ d->updateChunkLineNumbers(c,pos);
+#ifdef TEXTDOCUMENT_FIND_DEBUG
+ //qDebug() << "chunk - first line:" << c->firstLineIndex << "pos:" << pos;
+#endif
+ }
+
+ Q_ASSERT(c != NULL && c->previous != NULL);
+
+ c=c->previous;
+ pos-=c->size();
+ }
+
+#ifdef TEXTDOCUMENT_FIND_DEBUG
+ if(c) qDebug() << "chunk found - first line:" << c->firstLineIndex << "pos:" << pos;
+ else qDebug() << "chunk not found";
+#endif
+ if(c && c->firstLineIndex != -1 && c->firstLineIndex <= lineNum) {
+
+ current=c->firstLineIndex;
+ if(current == lineNum)
+ return TextPagerCursor(this,pos);
+
+ QChar newline('\n');
+ int index=0;
+ QString data=d->chunkData(c,-1);
+ while((index=data.indexOf(newline,index)) != -1) {
+#ifdef TEXTDOCUMENT_FIND_DEBUG
+ //qDebug() << "chunk found - line:" << current << "index:" << index;
+#endif
+ if(current == lineNum) {
+ TextPagerCursor ret(this,pos+index);
+ return ret;
+ }
+ index++;
+ current++;
+ }
+ }
+
+ return TextPagerCursor();
+}
+
+
+void TextPagerDocument::setOptions(Options opt)
+{
+ d->options = opt;
+ if ((d->options & Locking) != (d->readWriteLock != 0)) {
+ if (d->readWriteLock) {
+ delete d->readWriteLock;
+ } else {
+ d->readWriteLock = new QReadWriteLock(QReadWriteLock::Recursive);
+ }
+ }
+}
+
+TextPagerDocument::Options TextPagerDocument::options() const
+{
+ return d->options;
+}
+
+bool TextPagerDocument::isWordCharacter(const QChar &ch, int /*index*/) const
+{
+ // from qregexp.
+ return ch.isLetterOrNumber() || ch.isMark() || ch == QLatin1Char('_');
+}
+
+QString TextPagerDocument::swapFileName(Chunk *chunk)
+{
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+ QReadLocker locker(d->readWriteLock);
+ QString file = QStandardPaths::standardLocations(QStandardPaths::TempLocation).first();
+ file.reserve(file.size() + 24);
+ QTextStream ts(&file);
+ ts << QLatin1Char('/') << QLatin1String("lte_") << chunk << QLatin1Char('_')
+ << this << QLatin1Char('_') << QCoreApplication::applicationPid();
+ return file;
+#endif
+ return QString();
+}
+
+//===========================================================================
+//
+// TextDocumentPrivate
+//
+//===========================================================================
+
+Chunk *TextDocumentPrivate::chunkAt(int p, int *offset) const
+{
+ Q_ASSERT(p <= documentSize);
+ Q_ASSERT(p >= 0);
+ Q_ASSERT(first);
+ Q_ASSERT(last);
+ if (p == documentSize) {
+ if (offset)
+ *offset = last->size();
+ return last;
+ }
+#ifndef NO_TEXTDOCUMENT_CHUNK_CACHE
+ Q_ASSERT(!cachedChunk || cachedChunkPos != -1);
+ if (cachedChunk && p >= cachedChunkPos && p < cachedChunkPos + cachedChunkData.size()) {
+ if (offset)
+ *offset = p - cachedChunkPos;
+ return cachedChunk;
+ }
+#endif
+ int pos = p;
+ Chunk *c = first;
+
+ Q_FOREVER {
+ const int size = c->size();
+ if (pos < size) {
+ break;
+ }
+ pos -= size;
+ c = c->next;
+ Q_ASSERT(c);
+ }
+
+ if (offset)
+ *offset = pos;
+
+ Q_ASSERT(c);
+ return c;
+}
+
+
+/* Evil double meaning of pos here. If it's -1 we don't cache it. */
+QString TextDocumentPrivate::chunkData(const Chunk *chunk, int chunkPos) const
+{
+#ifndef NO_TEXTDOCUMENT_CHUNK_CACHE
+#ifdef DEBUG_CACHE_HITS
+ static int hits = 0;
+ static int misses = 0;
+#endif
+ if (chunk == cachedChunk) {
+#ifdef DEBUG_CACHE_HITS
+ qWarning() << "chunkData hits" << ++hits << "misses" << misses;
+#endif
+ Q_ASSERT(cachedChunkData.size() == chunk->size());
+ return cachedChunkData;
+ } else
+#endif
+ if (chunk->from == -1) {
+ return chunk->data;
+ } else if (!device && chunk->swap.isEmpty()) {
+ // Can only happen if the device gets deleted behind our back when in Sparse mode
+ return QString().fill(QLatin1Char(' '), chunk->size());
+ } else {
+ QIODevice *dev = device.data();
+#if 0
+ QFile file;
+ if (!chunk->swap.isEmpty()) {
+ file.setFileName(chunk->swap);
+ if (!file.open(QIODevice::ReadOnly)) {
+ qWarning("TextDocumentPrivate::chunkData() Can't open file for reading '%s'", qPrintable(chunk->swap));
+ return QString().fill(QLatin1Char(' '), chunk->size());
+ }
+ dev = &file;
+ }
+#endif
+ QTextStream ts(dev);
+ //if (textCodec)
+ // ts.setCodec(textCodec);
+// if (!chunk->swap.isEmpty()) {
+// qDebug() << "reading stuff from swap" << chunk << chunk->from << chunk->size() << chunk->swap;
+// }
+ ts.seek(chunk->from);
+
+#ifndef NO_TEXTDOCUMENT_CHUNK_CACHE
+
+ if (chunkPos != -1) {
+ cachedChunkData = ts.read(chunk->length);
+
+ Q_ASSERT(cachedChunkData.size() == chunk->size());
+
+ cachedChunk = const_cast<Chunk*>(chunk);
+ cachedChunkPos = chunkPos;
+
+ return cachedChunkData;
+/*#ifdef QT_DEBUG
+ if (chunkPos != chunk->pos()) {
+ qWarning() << chunkPos << chunk->pos();
+ }
+ Q_ASSERT(chunkPos == chunk->pos());
+#endif*/
+ } else {
+ const QString data = ts.read(chunk->length);
+ return data;
+ }
+
+#else
+ const QString data = ts.read(chunk->length);
+ return data;
+#endif
+ }
+ //Q_ASSERT(data.size() == chunk->size());
+#ifndef NO_TEXTDOCUMENT_CHUNK_CACHE
+#ifdef DEBUG_CACHE_HITS
+ qWarning() << "chunkData hits" << hits << "misses" << ++misses;
+#endif
+#endif
+
+#if 0
+ if (chunkPos != -1) {
+ cachedChunk = const_cast<Chunk*>(chunk);
+ cachedChunkData = data;
+ cachedChunkPos = chunkPos;
+#ifdef QT_DEBUG
+ if (chunkPos != chunk->pos()) {
+ qWarning() << chunkPos << chunk->pos();
+ }
+ Q_ASSERT(chunkPos == chunk->pos());
+#endif
+ }
+
+ //return data;
+ }
+#endif
+ return QString();
+}
+
+int TextDocumentPrivate::chunkIndex(const Chunk *c) const
+{
+ int index = 0;
+ while (c->previous) {
+ ++index;
+ c = c->previous;
+ }
+ return index;
+}
+
+void TextDocumentPrivate::instantiateChunk(Chunk *chunk)
+{
+ if (chunk->from == -1 && chunk->swap.isEmpty())
+ return;
+ chunk->data = chunkData(chunk, -1);
+// qDebug() << "instantiateChunk" << chunk << chunk->swap;
+ chunk->swap.clear();
+#ifndef NO_TEXTDOCUMENT_CHUNK_CACHE
+ // Don't want to cache this chunk since it's going away. If it
+ // already was cached then sure, but otherwise don't
+ if (chunk == cachedChunk) {
+ cachedChunk = 0;
+ cachedChunkPos = -1;
+ cachedChunkData.clear();
+ }
+#endif
+ chunk->from = chunk->length = -1;
+}
+
+void TextDocumentPrivate::removeChunk(Chunk *c)
+{
+ Q_ASSERT(c);
+ if (c == first) {
+ first = c->next;
+ } else {
+ c->previous->next = c->next;
+ }
+ if (c == last) {
+ last = c->previous;
+ } else {
+ c->next->previous = c->previous;
+ }
+#ifndef NO_TEXTDOCUMENT_CHUNK_CACHE
+ if (c == cachedChunk) {
+ cachedChunk = 0;
+ cachedChunkPos = -1;
+ cachedChunkData.clear();
+ }
+#endif
+ if (!first) {
+ Q_ASSERT(!last);
+ first = last = new Chunk;
+ }
+
+ delete c;
+}
+
+QString TextDocumentPrivate::wordAt(int position, int *start) const
+{
+ TextDocumentIterator from(this, position);
+ if (!q->isWordCharacter(from.current(), position)) {
+ if (start)
+ *start = -1;
+ return QString();
+ }
+
+ while (from.hasPrevious()) {
+ const QChar ch = from.previous();
+ if (!q->isWordCharacter(ch, from.position())) {
+ // ### could just peek rather than going one too far
+ from.next();
+ break;
+ }
+ }
+ TextDocumentIterator to(this, position);
+ while (to.hasNext()) {
+ const QChar ch = to.next();
+ if (!q->isWordCharacter(ch, to.position()))
+ break;
+ }
+
+ if (start)
+ *start = from.position();
+ return q->read(from.position(), to.position() - from.position());
+}
+
+QString TextDocumentPrivate::paragraphAt(int position, int *start) const
+{
+ const QLatin1Char newline('\n');
+ TextDocumentIterator from(this, position);
+ while (from.hasPrevious() && from.previous() != newline)
+ ;
+ TextDocumentIterator to(this, position);
+ while (to.hasNext() && to.next() != newline)
+ ;
+ if (start)
+ *start = from.position();
+ return q->read(from.position(), to.position() - from.position());
+}
+
+uint TextDocumentPrivate::wordBoundariesAt(int pos) const
+{
+ Q_ASSERT(pos >= 0 && pos < documentSize);
+ uint ret = 0;
+ if (pos == 0 || !q->isWordCharacter(q->readCharacter(pos - 1), pos - 1)) {
+ ret |= TextDocumentIterator::Left;
+ }
+ if (pos + 1 == documentSize || !q->isWordCharacter(q->readCharacter(pos + 1), pos + 1)) {
+ ret |= TextDocumentIterator::Right;
+ }
+ return ret;
+}
+
+void TextDocumentPrivate::updateChunkLineNumbers(Chunk *c, int chunkPos) const
+{
+ Q_ASSERT(c);
+ if (c->firstLineIndex == -1) {
+ Chunk *cc = c;
+ int pos = chunkPos;
+ while (cc->previous && cc->previous->firstLineIndex == -1) {
+ //pos -= cc->size();
+ //Here chunkPos points to the position (the beginning) of the chunk so
+ //the line above was incorrect had to be changed like this:
+ pos -=cc->previous->size();
+ cc = cc->previous;
+ }
+ // cc is at the first chunk that has firstLineIndex != -1
+ Q_ASSERT(!cc->previous || cc->previous->firstLineIndex != -1);
+ Q_ASSERT(cc->firstLineIndex == 1 || cc->firstLineIndex == -1);
+ // special case for first chunk
+ do {
+ const int size = cc->size();
+ if (!cc->previous) {
+ cc->firstLineIndex = 0;
+ } else {
+ const int prevSize = cc->previous->size();
+ const int lineCount = countNewLines(cc->previous, pos - prevSize, prevSize);
+ Q_ASSERT(cc->previous->firstLineIndex != -1);
+ cc->firstLineIndex = cc->previous->firstLineIndex + lineCount;
+ }
+ pos += size;
+ cc = cc->next;
+ } while (cc && cc != c->next);
+ countNewLines(c, chunkPos, c->size());
+ }
+ Q_ASSERT(c->firstLineIndex != -1);
+}
+
+static inline QList<int> dumpNewLines(const QString &string, int from, int size)
+{
+ QList<int> ret;
+ for (int i=from; i<from + size; ++i) {
+ if (string.at(i) == QLatin1Char('\n'))
+ ret.append(i);
+ }
+ return ret;
+}
+
+
+int TextDocumentPrivate::countNewLines(Chunk *c, int chunkPos, int size) const
+{
+// qDebug() << "CALLING countNewLines on" << chunkIndex(c) << chunkPos << size;
+// qDebug() << (c == first) << c->firstLineIndex << chunkPos << size
+// << c->size();
+ int ret = 0;
+#ifndef TEXTDOCUMENT_LINENUMBER_CACHE
+ if (size == c->size()) {
+ if (c->lines == -1) {
+ c->lines = ::count(chunkData(c, chunkPos), 0, size, QLatin1Char('\n'));
+// qDebug() << "counting" << c->lines << "in" << chunkIndex(c)
+// << "Size" << size << "chunkPos" << chunkPos;
+ }
+ ret = c->lines;
+ } else {
+ ret = ::count(chunkData(c, chunkPos), 0, size, QLatin1Char('\n'));
+ }
+#else
+// qDebug() << size << ret << c->lineNumbers << chunkPos
+// << dumpNewLines(chunkData(c, chunkPos), 0, c->size());
+ static const int lineNumberCacheInterval = TEXTDOCUMENT_LINENUMBER_CACHE_INTERVAL;
+ if (c->lineNumbers.isEmpty()) {
+ const QString data = chunkData(c, chunkPos);
+ const int s = data.size();
+ c->lineNumbers.fill(0, (s + lineNumberCacheInterval - 1) / lineNumberCacheInterval);
+// qDebug() << data.size() << c->lineNumbers.size() << lineNumberCacheInterval;
+
+ for (int i=0; i<s; ++i) {
+ if (data.at(i) == QLatin1Char('\n')) {
+ ++c->lineNumbers[i / lineNumberCacheInterval];
+// qDebug() << "found one at" << i << "put it in" << (i / lineNumberCacheInterval)
+// << "chunkPos" << chunkPos;
+ if (i < size)
+ ++ret;
+ }
+ }
+ } else {
+ for (int i=0; i<c->lineNumbers.size(); ++i) {
+ if (i * lineNumberCacheInterval > size) {
+ break;
+ } else if (c->lineNumbers.at(i) == 0) {
+ // nothing in this area
+ continue;
+ } else if ((i + 1) * lineNumberCacheInterval > size) {
+ ret += ::count(chunkData(c, chunkPos), i * lineNumberCacheInterval,
+ size - i * lineNumberCacheInterval, QChar('\n'));
+ // partly
+ break;
+ } else {
+ ret += c->lineNumbers.at(i);
+ }
+ }
+ }
+#endif
+ return ret;
+}
+
+void TextDocumentPrivate::swapOutChunk(Chunk *c)
+{
+ if (!c->swap.isEmpty())
+ return;
+ Q_ASSERT(!c->data.isEmpty());
+ c->from = 0;
+ c->length = c->data.size();
+ c->swap = q->swapFileName(c);
+ QFile file(c->swap);
+ if (!file.open(QIODevice::WriteOnly)) {
+ qWarning("TextDocumentPrivate::chunkData() Can't open file for writing '%s'", qPrintable(c->swap));
+ c->swap.clear();
+ return;
+ }
+ QTextStream ts(&file);
+ if (textCodec)
+ ts.setCodec(textCodec);
+ ts << c->data;
+ c->data.clear();
+#ifndef NO_TEXTDOCUMENT_CHUNK_CACHE
+ // ### do I want to do this?
+ if (cachedChunk == c) {
+ cachedChunk = 0;
+ cachedChunkPos = -1;
+ cachedChunkData.clear();
+ }
+#endif
+}
+
+static inline bool match(int pos, int left, int size)
+{
+ return pos >= left && pos < left + size;
+}
+
+static inline bool match(int pos, int size, const TextPagerSection *section, TextPagerSection::TextSectionOptions flags)
+{
+ const int sectionPos = section->position();
+ const int sectionSize = section->size();
+
+ if (::match(sectionPos, pos, size) && ::match(sectionPos + sectionSize - 1, pos, size)) {
+ return true;
+ } else if (flags & TextPagerSection::IncludePartial) {
+ const int boundaries[] = { pos, pos + size - 1 };
+ for (int i=0; i<2; ++i) {
+ if (::match(boundaries[i], sectionPos, sectionSize))
+ return true;
+ }
+ }
+ return false;
+}
+
+static inline void filter(QList<TextPagerSection*> §ions, const TextPagerEdit *filter)
+{
+ if (filter) {
+ for (int i=sections.size() - 1; i>=0; --i) {
+ if (!::matchSection(sections.at(i), filter))
+ sections.removeAt(i);
+ }
+ }
+}
+
+QList<TextPagerSection*> TextDocumentPrivate::getSections(int pos, int size, TextPagerSection::TextSectionOptions flags, const TextPagerEdit *filter) const
+{
+ if (size == -1)
+ size = documentSize - pos;
+ QList<TextPagerSection*> ret;
+ if (pos == 0 && size == documentSize) {
+ ret = sections;
+ ::filter(ret, filter);
+ return ret;
+ }
+ // binary search. TextPagerSections are sorted in order of position
+ if (sections.isEmpty()) {
+ return ret;
+ }
+
+ const TextPagerSection tmp(pos, size, static_cast<TextPagerDocument*>(0), QTextCharFormat(), QVariant());
+ QList<TextPagerSection*>::const_iterator it = qLowerBound(sections.begin(), sections.end(), &tmp, compareTextSection);
+ if (flags & TextPagerSection::IncludePartial && it != sections.begin()) {
+ QList<TextPagerSection*>::const_iterator prev = it;
+ do {
+ if (::match(pos, size, *--prev, flags))
+ ret.append(*prev);
+ } while (prev != sections.begin());
+ }
+ while (it != sections.end()) {
+ if (::match(pos, size, *it, flags)) {
+ ret.append(*it);
+ } else {
+ break;
+ }
+ ++it;
+ }
+ ::filter(ret, filter);
+ return ret;
+}
+
+void TextDocumentPrivate::textEditDestroyed(TextPagerEdit *edit)
+{
+ QMutableListIterator<TextPagerSection*> i(sections);
+ while (i.hasNext()) {
+ TextPagerSection *section = i.next();
+ if (section->textEdit() == edit) {
+ section->d.document = 0;
+ // Make sure we also remove it from the list of sections so it
+ // isn't deleted in the TextDocument destructor too.
+ i.remove();
+ delete section;
+ }
+ }
+}
+
+void TextPagerDocument::lockForRead()
+{
+ Q_ASSERT(d->readWriteLock);
+ d->readWriteLock->lockForRead();
+}
+
+void TextPagerDocument::lockForWrite()
+{
+ Q_ASSERT(d->readWriteLock);
+ d->readWriteLock->lockForWrite();
+}
+
+bool TextPagerDocument::tryLockForRead()
+{
+ Q_ASSERT(d->readWriteLock);
+ return d->readWriteLock->tryLockForRead();
+}
+
+bool TextPagerDocument::tryLockForWrite()
+{
+ Q_ASSERT(d->readWriteLock);
+ return d->readWriteLock->tryLockForWrite();
+}
+
+void TextPagerDocument::unlock()
+{
+ Q_ASSERT(d->readWriteLock);
+ d->readWriteLock->unlock();
+}
+
diff --git a/Viewer/src/TextPager/TextPagerDocument.hpp b/Viewer/src/TextPager/TextPagerDocument.hpp
new file mode 100644
index 0000000..6e23ea7
--- /dev/null
+++ b/Viewer/src/TextPager/TextPagerDocument.hpp
@@ -0,0 +1,176 @@
+// Copyright 2010 Anders Bakken
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef TEXTPAGERDOCUMENT_HPP__
+#define TEXTPAGERDOCUMENT_HPP__
+
+#include <QObject>
+#include <QString>
+#include <QString>
+#include <QPair>
+#include <QEventLoop>
+#include <QList>
+#include <QVariant>
+#include <QTextCharFormat>
+#include <QTextCodec>
+#include <QChar>
+#include <QRegExp>
+
+#include "TextPagerCursor.hpp"
+#include "TextPagerSection.hpp"
+
+class Chunk;
+class TextDocumentPrivate;
+class TextPagerDocument : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int documentSize READ documentSize)
+ Q_PROPERTY(int chunkCount READ chunkCount)
+ Q_PROPERTY(int instantiatedChunkCount READ instantiatedChunkCount)
+ Q_PROPERTY(int swappedChunkCount READ swappedChunkCount)
+ Q_PROPERTY(int chunkSize READ chunkSize WRITE setChunkSize)
+ Q_ENUMS(DeviceMode)
+ Q_FLAGS(Options)
+ Q_FLAGS(FindMode)
+
+public:
+ TextPagerDocument(QObject *parent = 0);
+ ~TextPagerDocument();
+
+ enum DeviceMode {
+ Sparse,
+ LoadAll
+ };
+
+ enum Option {
+ NoOptions = 0x0000,
+ SwapChunks = 0x0001,
+ KeepTemporaryFiles = 0x0002,
+ ConvertCarriageReturns = 0x0004, // incompatible with Sparse and must be set before loading
+ AutoDetectCarriageReturns = 0x0010,
+ NoImplicitLoadAll = 0x0020,
+ Locking = 0x0040,
+ DefaultOptions = AutoDetectCarriageReturns
+ };
+ Q_DECLARE_FLAGS(Options, Option);
+
+ Options options() const;
+ void setOptions(Options opt);
+ inline void setOption(Option opt, bool on = true) { setOptions(on ? (options() | opt) : (options() &= ~opt)); }
+
+ inline bool load(QIODevice *device, DeviceMode mode, const QByteArray &codecName)
+ { return load(device, mode, QTextCodec::codecForName(codecName)); }
+ inline bool load(const QString &fileName, DeviceMode mode, const QByteArray &codecName)
+ { return load(fileName, mode, QTextCodec::codecForName(codecName)); }
+ bool load(QIODevice *device, DeviceMode mode = Sparse, QTextCodec *codec = 0);
+ bool load(const QString &fileName, DeviceMode mode = Sparse, QTextCodec *codec = 0);
+
+ void clear();
+ DeviceMode deviceMode() const;
+
+ QTextCodec *textCodec() const;
+
+ void setText(const QString &text);
+ QString read(int pos, int size) const;
+ QStringRef readRef(int pos, int size) const;
+ QChar readCharacter(int index) const;
+
+ int documentSize() const;
+ int chunkCount() const;
+ int instantiatedChunkCount() const;
+ int swappedChunkCount() const;
+
+ void lockForRead();
+ void lockForWrite();
+ bool tryLockForRead();
+ bool tryLockForWrite();
+ void unlock();
+
+ enum FindModeFlag {
+ FindNone = 0x00000,
+ FindBackward = 0x00001,
+ FindCaseSensitively = 0x00002,
+ FindWholeWords = 0x00004,
+ FindAllowInterrupt = 0x00008,
+ FindWrap = 0x00010,
+ FindAll = 0x00020
+ };
+ Q_DECLARE_FLAGS(FindMode, FindModeFlag);
+
+ int chunkSize() const;
+ void setChunkSize(int pos);
+
+ QIODevice *device() const;
+
+ TextPagerCursor find(const QRegExp &rx, const TextPagerCursor &cursor, FindMode flags = 0,int limit = -1) const;
+ TextPagerCursor find(const QString &ba, const TextPagerCursor &cursor, FindMode flags = 0, int limit = -1) const;
+ TextPagerCursor find(const QChar &ch, const TextPagerCursor &cursor, FindMode flags = 0) const;
+ TextPagerCursor findLine(int lineNum, const TextPagerCursor &cursor) const;
+
+ inline TextPagerCursor find(const QRegExp &rx, int pos = 0, FindMode flags = 0) const
+ { return find(rx, TextPagerCursor(this, pos), flags); }
+ inline TextPagerCursor find(const QString &ba, int pos = 0, FindMode flags = 0) const
+ { return find(ba, TextPagerCursor(this, pos), flags); }
+ inline TextPagerCursor find(const QChar &ch, int pos = 0, FindMode flags = 0) const
+ { return find(ch, TextPagerCursor(this, pos), flags); }
+
+
+ QList<TextPagerSection*> sections(int from = 0, int size = -1, TextPagerSection::TextSectionOptions opt = 0) const;
+ inline TextPagerSection *sectionAt(int pos) const { return sections(pos, 1, TextPagerSection::IncludePartial).value(0); }
+ TextPagerSection *insertTextSection(int pos, int size, const QTextCharFormat &format = QTextCharFormat(),
+ const QVariant &data = QVariant());
+ void insertTextSection(TextPagerSection *section);
+ void takeTextSection(TextPagerSection *section);
+ int currentMemoryUsage() const;
+
+ bool isModified() const;
+
+ int lineNumber(int position) const;
+ int columnNumber(int position) const;
+ int lineNumber(const TextPagerCursor &cursor) const;
+ int columnNumber(const TextPagerCursor &cursor) const;
+ virtual bool isWordCharacter(const QChar &ch, int index) const;
+
+public Q_SLOTS:
+ bool abortSave();
+ bool abortFind() const;
+
+Q_SIGNALS:
+ void entryFound(const TextPagerCursor &cursor) const;
+ void textChanged();
+ void sectionAdded(TextPagerSection *section);
+ void sectionRemoved(TextPagerSection *removed);
+ void charactersAdded(int from, int count);
+ void charactersRemoved(int from, int count);
+ void saveProgress(qreal progress);
+ void findProgress(qreal progress, int position) const;
+ void documentSizeChanged(int size);
+ void modificationChanged(bool modified);
+
+protected:
+ virtual QString swapFileName(Chunk *chunk);
+
+private:
+ TextDocumentPrivate *d;
+ friend class TextPagerEdit;
+ friend class TextPagerCursor;
+ friend class TextDocumentPrivate;
+ friend class TextPagerLayout;
+ friend class TextPagerSection;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(TextPagerDocument::FindMode);
+Q_DECLARE_OPERATORS_FOR_FLAGS(TextPagerDocument::Options);
+
+#endif
diff --git a/Viewer/src/TextPager/TextPagerDocument_p.hpp b/Viewer/src/TextPager/TextPagerDocument_p.hpp
new file mode 100644
index 0000000..1593567
--- /dev/null
+++ b/Viewer/src/TextPager/TextPagerDocument_p.hpp
@@ -0,0 +1,703 @@
+// Copyright 2010 Anders Bakken
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef TEXTPAGERDOCUMENT_P_HPP__
+#define TEXTPAGERDOCUMENT_P_HPP__
+
+#include <QString>
+#include <QApplication>
+#include <QThread>
+#include <QIODevice>
+#include <QTime>
+#include <QMutexLocker>
+#include <QReadWriteLock>
+#include <QMutex>
+#include <QSet>
+#include <QTemporaryFile>
+#include <QDebug>
+#include <QPointer>
+
+#ifndef ASSUME
+#ifdef FATAL_ASSUMES
+#define ASSUME(cond) Q_ASSERT(cond)
+#elif defined Q_OS_SOLARIS
+#define ASSUME(cond) if (!(cond)) qWarning("Failed assumption %s:%d %s", __FILE__, __LINE__, #cond);
+#else
+#define ASSUME(cond) if (!(cond)) qWarning("Failed assumption %s:%d (%s) %s", __FILE__, __LINE__, __FUNCTION__, #cond);
+#endif
+#endif
+
+#define Q_COMPARE_ASSERT(left, right) if (left != right) { qWarning() << left << right; Q_ASSERT(left == right); }
+
+#include "TextPagerDocument.hpp"
+#ifdef NO_TEXTDOCUMENT_CACHE
+#define NO_TEXTDOCUMENT_CHUNK_CACHE
+#define NO_TEXTDOCUMENT_READ_CACHE
+#endif
+
+#if defined TEXTDOCUMENT_LINENUMBER_CACHE && !defined TEXTDOCUMENT_LINENUMBER_CACHE_INTERVAL
+#define TEXTDOCUMENT_LINENUMBER_CACHE_INTERVAL 100
+#endif
+
+#ifdef QT_DEBUG
+#define _UI_TEXTPAGER_ITERATOR_DEBUG
+#endif
+
+static inline bool matchSection(const TextPagerSection *section, const TextPagerEdit *textEdit)
+{
+ if (!textEdit) {
+ return true;
+ } else if (!section->textEdit()) {
+ return true;
+ } else {
+ return textEdit == section->textEdit();
+ }
+}
+
+
+struct Chunk {
+ Chunk() : previous(0), next(0), from(-1), length(0), firstLineIndex(-1)
+#ifndef TEXTDOCUMENT_LINENUMBER_CACHE
+ , lines(-1)
+#endif
+ {}
+
+ mutable QString data;
+ Chunk *previous, *next;
+ int size() const { return data.isEmpty() ? length : data.size(); }
+#ifdef QT_DEBUG
+ int pos() const { int p = 0; Chunk *c = previous; while (c) { p += c->size(); c = c->previous; }; return p; }
+#endif
+ mutable int from, length; // Not used when all is loaded
+ mutable int firstLineIndex;
+#ifdef TEXTDOCUMENT_LINENUMBER_CACHE
+ mutable QVector<int> lineNumbers;
+ // format is how many endlines in the area from (n *
+ // TEXTDOCUMENT_LINENUMBER_CACHE_INTERVAL) to
+ // ((n + 1) * TEXTDOCUMENT_LINENUMBER_CACHE_INTERVAL)
+#else
+ mutable int lines;
+#endif
+ QString swap;
+};
+
+
+// should really use this stuff for all of this stuff
+
+static inline QPair<int, int> intersection(int index1, int size1, int index2, int size2)
+{
+ QPair<int, int> ret;
+ ret.first = qMax(index1, index2);
+ const int right = qMin(index1 + size1, index2 + size2);
+ ret.second = right - ret.first;
+ if (ret.second <= 0)
+ return qMakePair(-1, 0);
+ return ret;
+}
+
+static inline bool compareTextSection(const TextPagerSection *left, const TextPagerSection *right)
+{
+ // don't make this compare document. Look at ::sections()
+ return left->position() < right->position();
+}
+
+class TextDocumentIterator;
+struct DocumentCommand {
+ enum Type {
+ None,
+ Inserted,
+ Removed
+ };
+
+ DocumentCommand(Type t, int pos = -1, const QString &string = QString())
+ : type(t), position(pos), text(string), joinStatus(NoJoin)
+ {}
+
+ const Type type;
+ int position;
+ QString text;
+
+ enum JoinStatus {
+ NoJoin,
+ Forward,
+ Backward
+ } joinStatus;
+};
+
+struct TextPagerSection;
+struct TextCursorSharedPrivate;
+struct TextDocumentPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ TextDocumentPrivate(TextPagerDocument *doc)
+ : q(doc), first(0), last(0),
+#ifndef NO_TEXTDOCUMENT_CHUNK_CACHE
+ cachedChunk(0), cachedChunkPos(-1),
+#endif
+#ifndef NO_TEXTDOCUMENT_READ_CACHE
+ cachePos(-1),
+#endif
+ documentSize(0),
+ saveState(NotSaving), findState(NotFinding), ownDevice(false), modified(false),
+ deviceMode(TextPagerDocument::Sparse), chunkSize(64*1024), //chunkSize(1024*64), //chunkSize(16384),
+ //undoRedoStackCurrent(0), modifiedIndex(-1), undoRedoEnabled(true), ignoreUndoRedo(false),
+ //collapseInsertUndo(false),
+ hasChunksWithLineNumbers(false), textCodec(0), options(TextPagerDocument::DefaultOptions),
+ readWriteLock(0), cursorCommand(false)
+ {
+ first = last = new Chunk;
+ }
+
+ TextPagerDocument *q;
+ QSet<TextCursorSharedPrivate*> textCursors;
+ mutable Chunk *first, *last;
+
+#ifndef NO_TEXTDOCUMENT_CHUNK_CACHE
+ mutable Chunk *cachedChunk;
+ mutable int cachedChunkPos;
+ mutable QString cachedChunkData; // last uninstantiated chunk's read from file
+#endif
+#ifndef NO_TEXTDOCUMENT_READ_CACHE
+ mutable int cachePos;
+ mutable QString cache; // results of last read(). Could span chunks
+#endif
+
+ int documentSize;
+ enum SaveState { NotSaving, Saving, AbortSave } saveState;
+ enum FindState { NotFinding, Finding, AbortFind } mutable findState;
+ QList<TextPagerSection*> sections;
+ QPointer<QIODevice> device;
+ bool ownDevice, modified;
+ TextPagerDocument::DeviceMode deviceMode;
+ int chunkSize;
+
+#if 0
+ QList<DocumentCommand*> undoRedoStack;
+ int undoRedoStackCurrent, modifiedIndex;
+ bool undoRedoEnabled, ignoreUndoRedo, collapseInsertUndo;
+#endif
+
+ bool hasChunksWithLineNumbers;
+ QTextCodec *textCodec;
+ TextPagerDocument::Options options;
+ QReadWriteLock *readWriteLock;
+ bool cursorCommand;
+
+#ifdef QT_DEBUG
+ mutable QSet<TextDocumentIterator*> iterators;
+#endif
+
+#if 0
+ void joinLastTwoCommands();
+#endif
+
+ void removeChunk(Chunk *c);
+ QString chunkData(const Chunk *chunk, int pos) const;
+ int chunkIndex(const Chunk *c) const;
+
+ // evil API. pos < 0 means don't cache
+
+ void updateChunkLineNumbers(Chunk *c, int pos) const;
+ int countNewLines(Chunk *c, int chunkPos, int index) const;
+
+ void instantiateChunk(Chunk *chunk);
+ Chunk *chunkAt(int pos, int *offset) const;
+
+#if 0
+ void clearRedo();
+ void undoRedo(bool undo);
+#endif
+
+ QString wordAt(int position, int *start = 0) const;
+ QString paragraphAt(int position, int *start = 0) const;
+
+ uint wordBoundariesAt(int pos) const;
+
+ friend class TextPagerDocument;
+ void swapOutChunk(Chunk *c);
+ QList<TextPagerSection*> getSections(int from, int size, TextPagerSection::TextSectionOptions opt, const TextPagerEdit *filter) const;
+ inline TextPagerSection *sectionAt(int pos, const TextPagerEdit *filter) const { return getSections(pos, 1, TextPagerSection::IncludePartial, filter).value(0); }
+ void textEditDestroyed(TextPagerEdit *edit);
+Q_SIGNALS:
+ void sectionFormatChanged(TextPagerSection *section);
+ void sectionCursorChanged(TextPagerSection *section);
+
+#if 0
+ void undoRedoCommandInserted(DocumentCommand *cmd);
+ void undoRedoCommandRemoved(DocumentCommand *cmd);
+ void undoRedoCommandTriggered(DocumentCommand *cmd, bool undo);
+ void undoRedoCommandFinished(DocumentCommand *cmd);
+#endif
+
+private:
+ friend class TextPagerSection;
+};
+
+// should not be kept as a member. Invalidated on inserts/removes
+class TextDocumentIterator
+{
+public:
+ TextDocumentIterator(const TextDocumentPrivate *d, int p)
+ : doc(d), pos(p), min(0), max(-1), convert(false), newline('\n')
+ {
+ Q_ASSERT(doc);
+
+ end_=end();
+
+#ifndef NO_TEXTDOCUMENTITERATOR_CACHE
+ chunk = doc->chunkAt(p, &offset);
+ Q_ASSERT(chunk);
+ const int chunkPos = p - offset;
+ chunkData = doc->chunkData(chunk, chunkPos);
+ //chunkLines = chunkData.split('\n');
+ Q_COMPARE_ASSERT(chunkData.size(), chunk->size());
+#ifdef QT_DEBUG
+ if (p != d->documentSize) {
+ if (doc->q->readCharacter(p) != chunkData.at(offset)) {
+ qDebug() << "got" << chunkData.at(offset) << "at" << offset << "in" << chunk << "of size" << chunkData.size()
+ << "expected" << doc->q->readCharacter(p) << "at document pos" << pos;
+ }
+ Q_ASSERT(chunkData.at(offset) == doc->q->readCharacter(p));
+ } else {
+ Q_ASSERT(chunkData.size() == offset);
+ }
+#endif
+#endif
+
+#ifdef QT_DEBUG
+ doc->iterators.insert(this);
+#endif
+ }
+#ifdef QT_DEBUG
+ ~TextDocumentIterator()
+ {
+ Q_ASSERT(doc->iterators.remove(this));
+ }
+#endif
+
+ int end() const
+ {
+ return max != -1 ? max : doc->documentSize;
+ }
+
+ void setMinBoundary(int bound)
+ {
+ min = bound;
+ Q_ASSERT(pos >= min);
+ }
+
+ void setMaxBoundary(int bound)
+ {
+ max = bound;
+ Q_ASSERT(pos <= max);
+
+ //We suppose that the document size does not change
+ end_=end();
+ }
+
+
+ inline bool hasNext() const
+ {
+ return pos < end();
+ }
+
+ inline bool hasPrevious() const
+ {
+ return pos > min;
+ }
+
+ inline int position() const
+ {
+ return pos;
+ }
+
+ inline QChar current() const
+ {
+ Q_ASSERT(doc);
+#ifndef NO_TEXTDOCUMENTITERATOR_CACHE
+ Q_ASSERT(chunk);
+ Q_COMPARE_ASSERT(chunkData.size(), chunk->size());
+ if (pos == end())
+ return QChar();
+
+//Calling readCharacter is very expensive during find!!! So we try not to call it!!!
+#if 0
+#ifdef QT_DEBUG
+ if (doc->q->readCharacter(pos) != chunkData.at(offset)) {
+ qDebug() << "got" << chunkData.at(offset) << "at" << offset << "in" << chunk << "of size" << chunkData.size()
+ << "expected" << doc->q->readCharacter(pos) << "at document pos" << pos;
+ }
+#endif
+#endif
+#if 0
+ ASSUME(doc->q->readCharacter(pos) == chunkData.at(offset));
+#endif
+ return convert ? chunkData.at(offset).toLower() : chunkData.at(offset);
+ //return convert ? chunkData[offset].toLower() : chunkData[offset];
+#else
+ return convert ? doc->q->readCharacter(pos).toLower() : doc->q->readCharacter(pos);
+#endif
+ }
+
+ inline QChar next()
+ {
+ Q_ASSERT(doc);
+ ++pos;
+#ifndef NO_TEXTDOCUMENTITERATOR_CACHE
+ Q_ASSERT(chunk);
+ if (++offset >= chunkData.size() && chunk->next) { // special case for offset == chunkData.size() and !chunk->next
+ offset = 0;
+ chunk = chunk->next;
+ Q_ASSERT(chunk);
+ chunkData = doc->chunkData(chunk, pos);
+ Q_COMPARE_ASSERT(chunkData.size(), chunk->size());
+ }
+#endif
+ return current();
+ }
+
+ inline QChar previous()
+ {
+ Q_ASSERT(doc);
+ Q_ASSERT(hasPrevious());
+ --pos;
+ Q_ASSERT(pos >= min);
+ Q_ASSERT(pos <= end());
+#ifndef NO_TEXTDOCUMENTITERATOR_CACHE
+ Q_ASSERT(chunk);
+ if (--offset < 0) {
+ chunk = chunk->previous;
+ Q_ASSERT(chunk);
+ chunkData = doc->chunkData(chunk, pos - chunk->size() + 1);
+ Q_COMPARE_ASSERT(chunkData.size(), chunk->size());
+ offset = chunkData.size() - 1;
+ }
+#endif
+ return current();
+ }
+
+ enum Direction { None = 0x0, Left = 0x1, Right = 0x2, Both = Left|Right };
+ inline QChar nextPrev(Direction dir, bool &ok)
+ {
+ if (dir == Left) {
+ if (!hasPrevious()) {
+ ok = false;
+ return QChar();
+ }
+ ok = true;
+ return previous();
+ } else {
+ if (!hasNext()) {
+ ok = false;
+ return QChar();
+ }
+ ok = true;
+ return next();
+ }
+ }
+
+// Gets the previous line preceding the current iterator position. It is only
+// used for TextPagerDocument::find and was added to speed up the original find
+// algorithm. it is only implemented for cached textdocument iterators!
+
+ inline unsigned char prevLine(QString& str)
+ {
+#ifndef NO_TEXTDOCUMENTITERATOR_CACHE
+ Q_ASSERT(doc);
+
+#ifdef _UI_TEXTPAGER_ITERATOR_DEBUG
+ //qDebug() << "prevLine --->" << pos << offset; //<< chunkData;
+#endif
+
+ //If we are at the start
+ if(pos <= min)
+ return 0;
+
+ //Get the QString in the chunk as a const pointer. It is faster to iterate through it than
+ //calling QString::at()
+ const QChar *data = chunkData.constData();
+ data+=offset;
+
+ Q_ASSERT(*data == chunkData.at(offset));
+
+ //The current character is probably a newline (the
+ //result of the previous call) so we need to take a step back
+ if(*data == newline)
+ {
+ --pos;
+ --offset;
+
+ //See if we need the previous chunk
+ if(offset < 0) {
+ //The previous chunk must exist
+ bool b=loadPrevChunk();
+ Q_ASSERT( b == true);
+ data = chunkData.constData();
+ data+=offset;
+ } else {
+ --data;
+ }
+
+ if(pos == min)
+ return 0;
+ }
+
+ //Mark the line end position within the chunk
+ int to=offset;
+
+ //We will go backwards until we find a newline
+ while(*data != newline)
+ {
+ //Q_ASSERT(*data == chunkData.at(offset));
+#ifdef _UI_TEXTPAGER_ITERATOR_DEBUG
+ //qDebug() << pos << offset << chunkData.at(offset) << to;
+#endif
+ if(pos <= min) {
+ if(to != offset) {
+ if(str.size() == 0) {
+ str=chunkData.mid(offset,to-offset+1);
+ } else {
+ str.prepend(chunkData.mid(offset,to-offset+1));
+ }
+ }
+ return 0;
+ }
+
+ --pos;
+
+ //If we need the previous chunk
+ if(--offset < 0) {
+
+ //Copy the line portion from this chunk to the result
+ if(str.size() == 0)
+ str=chunkData.mid(0,to);
+ else
+ str.prepend(chunkData.mid(0,to));
+
+ //Get previous chunk
+ bool b=loadPrevChunk();
+ Q_ASSERT(b==true);
+
+ //Initialise the search positions
+ data = chunkData.constData();
+ data+=offset;
+ to=offset;
+
+#ifdef _UI_TEXTPAGER_ITERATOR_DEBUG
+ //qDebug() << "change" << pos << offset << *data << chunkData.at(offset);
+#endif
+ } else {
+ --data;
+ }
+ }
+
+#ifdef _UI_TEXTPAGER_ITERATOR_DEBUG
+ //qDebug() << pos << offset << to;
+#endif
+
+ //offset is either a newline charter or 0 (the start of the document)
+
+ if(to != offset) {
+ if(str.size() == 0) {
+ str=chunkData.mid(offset,to-offset+1);
+ } else {
+ str.prepend(chunkData.mid(offset,to-offset+1));
+ }
+ }
+#endif
+
+#ifdef _UI_TEXTPAGER_ITERATOR_DEBUG
+ //qDebug() << "line:" << str;
+#endif
+
+ return 1;
+ }
+
+ // Gets the next line following- the current iterator position. It is only
+ // used for TextPagerDocument::find and was added to speed up the original find
+ // algorithm. it is only implemented for cached textdocument iterators!
+
+ inline unsigned char nextLine(QString& str)
+ {
+#ifndef NO_TEXTDOCUMENTITERATOR_CACHE
+ Q_ASSERT(doc);
+
+#ifdef _UI_TEXTPAGER_ITERATOR_DEBUG
+ //qDebug() << "nextLine --->" << pos << offset << chunkData.size() << chunkData.at(offset);
+#endif
+ int posEnd=end();
+ if(pos >= posEnd)
+ return 0;
+
+ //Get the QString in the chunk as a const pointer. It is faster to iterate through it than
+ //calling QString::at()
+ const QChar *data = chunkData.constData();
+ data+=offset;
+
+ Q_ASSERT(*data == chunkData.at(offset));
+
+ //The current character is probably a newline (the
+ //result of the previous call) so we need to take a step forward
+ if(*data == newline)
+ {
+ ++pos;
+ ++offset;
+
+ //See if we need the next chunk
+ if(offset >= chunkData.size()) {
+ //Has next chunk
+ if(loadNextChunk()) {
+ data = chunkData.constData();
+ Q_ASSERT(offset == 0);
+ } else {
+ pos--;
+ offset--;
+ return 0;
+ }
+
+ } else {
+ ++data;
+ }
+
+ if(pos >= posEnd)
+ return 0;
+
+ }
+
+ //Mark the line start position within the chunk
+ int from=offset;
+
+ //We will go forward until we find a newline
+ while(*data != newline)
+ {
+#ifdef _UI_TEXTPAGER_ITERATOR_DEBUG
+ //qDebug() << pos << offset << chunkData.at(offset);
+#endif
+ if(pos >= posEnd)
+ {
+ if(str.size() == 0)
+ str=chunkData.mid(from,offset-from+1);
+ else
+ str.append(chunkData.mid(from,offset-from+1));
+
+ return 0;
+ }
+
+ ++pos;
+
+ //If we need the next chunk
+ if(++offset >= chunkData.size()) {
+
+ //Copy the line portion from this chunk to the result
+ if(str.size() == 0)
+ str=chunkData.mid(from,offset-from);
+ else
+ str.append(chunkData.mid(from,offset-from));
+
+ //Get next chunk
+ if(loadNextChunk()) {
+ //Initialise the search positions
+ data = chunkData.constData();
+ from=0;
+ } else {
+ pos--;
+ offset--;
+ return 0;
+ }
+ }
+ else {
+ ++data;
+ }
+ }
+
+ if(from != offset) {
+ if(str.size() == 0)
+ {
+ str=chunkData.mid(from,offset-from+1);
+ }
+ else
+ str.append(chunkData.mid(from,offset-from+1));
+ }
+
+#endif
+
+#ifdef _UI_TEXTPAGER_ITERATOR_DEBUG
+ //qDebug() << "line:" << str;
+#endif
+
+ return 1;
+ }
+
+
+ inline bool loadPrevChunk()
+ {
+#ifndef NO_TEXTDOCUMENTITERATOR_CACHE
+ Q_ASSERT(chunk);
+ if (chunk->previous) {
+ chunk = chunk->previous;
+ Q_ASSERT(chunk);
+ chunkData = doc->chunkData(chunk, pos - chunk->size() + 1);
+ Q_COMPARE_ASSERT(chunkData.size(), chunk->size());
+ offset = chunkData.size() - 1;
+ return true;
+ }
+#endif
+ return false;
+ }
+
+ inline bool loadNextChunk()
+ {
+#ifndef NO_TEXTDOCUMENTITERATOR_CACHE
+ Q_ASSERT(chunk);
+ if (chunk->next) {
+ chunk = chunk->next;
+ Q_ASSERT(chunk);
+ chunkData = doc->chunkData(chunk, pos);
+ Q_COMPARE_ASSERT(chunkData.size(), chunk->size());
+ offset = 0;
+ return true;
+ }
+#endif
+ return false;
+ }
+
+
+ inline bool convertToLowerCase() const
+ {
+ return convert;
+ }
+
+ inline void setConvertToLowerCase(bool on)
+ {
+ convert = on;
+ }
+
+private:
+ const TextDocumentPrivate *doc;
+ int pos;
+ int min, max;
+ int end_; // to speed things up
+#ifndef NO_TEXTDOCUMENTITERATOR_CACHE
+ int offset;
+ QString chunkData;
+ QStringList chunkLines;
+ Chunk *chunk;
+#endif
+ bool convert;
+ const QChar newline;
+};
+
+
+#endif
diff --git a/Viewer/src/TextPager/TextPagerEdit.cpp b/Viewer/src/TextPager/TextPagerEdit.cpp
new file mode 100644
index 0000000..3d80924
--- /dev/null
+++ b/Viewer/src/TextPager/TextPagerEdit.cpp
@@ -0,0 +1,1896 @@
+// Copyright 2010 Anders Bakken
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <QScrollArea>
+#include <QScrollBar>
+#include <QDesktopWidget>
+#include <QVariant>
+#include "TextPagerEdit.hpp"
+#include "TextPagerEdit_p.hpp"
+#include "TextPagerCursor_p.hpp"
+#include "TextPagerDocument_p.hpp"
+#include "TextPagerSearchHighlighter.hpp"
+#include "UserMessage.hpp"
+#include "VConfig.hpp"
+
+#include <cmath>
+
+//#define _UI_TEXTPAGER_DEBUG
+//#define DEBUG_TEXTPAGER_LASTPAGESIZE
+//#define DEBUG_TEXTPAGER
+
+#ifdef DEBUG_TEXTPAGER
+bool doLog = false;
+QString logFileName;
+#endif
+
+/*!
+ Constructs an empty TextPagerEdit with parent \a parent.
+*/
+
+TextPagerEdit::TextPagerEdit(QWidget *parent) :
+ QAbstractScrollArea(parent),
+ d(new TextEditPrivate(this)),
+ useSearchHighlight_(false),
+ lineNumArea_(0),
+ fontProp_(NULL)
+{
+ viewport()->setCursor(Qt::IBeamCursor);
+
+ setProperty("pager","1");
+
+#ifdef DEBUG_TEXTPAGER
+ if (logFileName.isEmpty())
+ logFileName = QDateTime::currentDateTime().toString("yyyyMMdd_hhmmsszzz.log");
+#endif
+
+ connect(verticalScrollBar(), SIGNAL(valueChanged(int)), d, SLOT(onScrollBarValueChanged(int)));
+ connect(verticalScrollBar(), SIGNAL(actionTriggered(int)), d, SLOT(onScrollBarActionTriggered(int)));
+ connect(verticalScrollBar(), SIGNAL(sliderReleased()), d, SLOT(updateScrollBar()));
+
+ setDocument(new TextPagerDocument(this));
+ setViewportMargins(0, 0, 0, 0);
+ struct {
+ QString text;
+ const char *member;
+ QKeySequence::StandardKey key;
+ } shortcuts[] = {
+ { tr("Copy"), SLOT(copy()), QKeySequence::Copy },
+ { tr("Select All"), SLOT(selectAll()), QKeySequence::SelectAll },
+ { QString(), 0, QKeySequence::UnknownKey } };
+ for (int i=0; shortcuts[i].member; ++i) {
+ d->actions[i] = new QAction(shortcuts[i].text, this);
+ d->actions[i]->setShortcutContext(Qt::WidgetShortcut);
+ d->actions[i]->setShortcut(QKeySequence(shortcuts[i].key));
+ d->actions[i]->setShortcutContext(Qt::WidgetShortcut);
+ connect(d->actions[i], SIGNAL(triggered(bool)), this, shortcuts[i].member);
+ addAction(d->actions[i]);
+ }
+ //connect(this, SIGNAL(undoAvailableChanged(bool)), d->actions[UndoAction], SLOT(setEnabled(bool)));
+ //connect(this, SIGNAL(redoAvailableChanged(bool)), d->actions[RedoAction], SLOT(setEnabled(bool)));
+ //d->actions[UndoAction]->setEnabled(false);
+ //d->actions[RedoAction]->setEnabled(false);
+ setContextMenuPolicy(Qt::ActionsContextMenu);
+ //setCursorVisible(true); // starts blinking
+ connect(this, SIGNAL(selectionChanged()), d, SLOT(onSelectionChanged()));
+
+
+ setReadOnly(true);
+
+ searchHighlight_=new TextPagerSearchHighlighter(this);
+}
+
+
+/*!
+ returns the current cursor position
+*/
+
+int TextPagerEdit::cursorPosition() const
+{
+ return d->textCursor.position();
+}
+
+/*!
+ ensures that \a cursor is visible with \a linesMargin lines of
+ margin on each side (if possible)
+*/
+
+void TextPagerEdit::ensureCursorVisible(const TextPagerCursor &cursor, int linesMargin)
+{
+ linesMargin = qMin(d->visibleLines, linesMargin); // ### could this be a problem down at the bottom of the document?
+ Q_ASSERT(cursor.document() == document());
+ TextPagerCursor above = cursor;
+ for (int i=0; i<linesMargin; ++i) {
+ if (!above.movePosition(TextPagerCursor::Up))
+ break;
+ }
+ if (above.position() < d->viewportPosition) {
+ d->updateViewportPosition(above.position(), TextPagerLayout::Backward);
+ return;
+ }
+
+ TextPagerCursor below = cursor;
+ for (int i=0; i<linesMargin; ++i) {
+ if (!below.movePosition(TextPagerCursor::Down))
+ break;
+ }
+
+ if (below.position() > d->lastVisibleCharacter) {
+ for (int i=0; i<d->visibleLines; ++i) {
+ below.movePosition(TextPagerCursor::Up);
+ d->updateViewportPosition(below.position(), TextPagerLayout::Forward);
+ }
+ }
+}
+
+/*!
+ returns the QAction * for \a type.
+*/
+
+QAction *TextPagerEdit::action(ActionType type) const
+{
+ return d->actions[type];
+}
+
+/*!
+ Called when the textEdit is deleted
+*/
+
+TextPagerEdit::~TextPagerEdit()
+{
+ if (d->document) {
+ Q_FOREACH(SyntaxHighlighter *syntaxHighlighter, d->syntaxHighlighters) {
+ if (syntaxHighlighter->parent() == this)
+ disconnect(syntaxHighlighter, 0, d, 0);
+ syntaxHighlighter->d->textEdit = 0;
+ syntaxHighlighter->d->textLayout = 0;
+ }
+ disconnect(d->document, 0, this, 0);
+ disconnect(d->document, 0, d, 0);
+ disconnect(d->document->d, 0, this, 0);
+ disconnect(d->document->d, 0, d, 0);
+
+ if (d->document->parent() == this) {
+ delete d->document;
+ d->document = 0;
+ } else {
+ d->document->d->textEditDestroyed(this);
+ }
+ // to make sure we don't do anything drastic on shutdown
+ }
+ delete d;
+
+ if(fontProp_)
+ fontProp_->removeObserver(this);
+}
+
+/*!
+ returns the text edit's document. document() always returns a
+ valid TextPagerDocument *
+ \sa setDocument
+*/
+
+
+TextPagerDocument *TextPagerEdit::document() const
+{
+ return d->document;
+}
+
+/*!
+ sets the text edit's document to \a doc. The previous document
+ will be deleted if it's parented to the text edit.
+
+ If \a doc is 0 a default TextPagerDocument will be set.
+ \sa document
+*/
+
+void TextPagerEdit::setDocument(TextPagerDocument *doc)
+{
+ if (doc == d->document)
+ return;
+
+ if (d->document) {
+ disconnect(d->document, 0, this, 0);
+ disconnect(d->document, 0, d, 0);
+ disconnect(d->document->d, 0, this, 0);
+ disconnect(d->document->d, 0, d, 0);
+ if (d->document->parent() == this)
+ delete d->document;
+ }
+ if (!doc)
+ doc = new TextPagerDocument(this);
+
+ d->sections.clear();
+ d->buffer.clear();
+ d->sectionsDirty = true;
+ d->document = doc;
+ d->sectionPressed = 0;
+ d->layoutDirty = true;
+ qDeleteAll(d->unusedTextLayouts);
+ d->unusedTextLayouts.clear();
+ qDeleteAll(d->textLayouts);
+ d->textLayouts.clear();
+ viewport()->setCursor(Qt::IBeamCursor);
+ viewport()->setMouseTracking(true);
+ d->sectionCount = 0;
+
+ d->textCursor = TextPagerCursor(doc);
+ d->textCursor.textEdit = this;
+
+ /*connect(d->document->d, SIGNAL(undoRedoCommandInserted(DocumentCommand *)),
+ d, SLOT(onDocumentCommandInserted(DocumentCommand *)));
+ connect(d->document, SIGNAL(sectionAdded(TextPagerSection *)),
+ d, SLOT(onTextSectionAdded(TextPagerSection *)));
+ connect(d->document, SIGNAL(sectionRemoved(TextPagerSection *)),
+ d, SLOT(onTextSectionRemoved(TextPagerSection *)));
+ connect(d->document->d, SIGNAL(undoRedoCommandRemoved(DocumentCommand *)),
+ d, SLOT(onDocumentCommandRemoved(DocumentCommand *)));
+ connect(d->document->d, SIGNAL(undoRedoCommandTriggered(DocumentCommand *, bool)),
+ d, SLOT(onDocumentCommandTriggered(DocumentCommand *, bool)));*/
+
+ connect(d->document, SIGNAL(charactersAdded(int, int)),
+ d, SLOT(onCharactersAddedOrRemoved(int, int)));
+ connect(d->document, SIGNAL(charactersRemoved(int, int)),
+ d, SLOT(onCharactersAddedOrRemoved(int, int)));
+
+ /*connect(d->document, SIGNAL(textChanged()), this, SIGNAL(textChanged()));
+ connect(d->document, SIGNAL(undoAvailableChanged(bool)),
+ this, SIGNAL(undoAvailableChanged(bool)));
+ connect(d->document, SIGNAL(redoAvailableChanged(bool)),
+ this, SIGNAL(redoAvailableChanged(bool)));*/
+
+ connect(d->document, SIGNAL(documentSizeChanged(int)), d, SLOT(onDocumentSizeChanged(int)));
+ connect(d->document, SIGNAL(destroyed(QObject*)), d, SLOT(onDocumentDestroyed()));
+ connect(d->document->d, SIGNAL(sectionFormatChanged(TextPagerSection *)),
+ d, SLOT(onTextSectionFormatChanged(TextPagerSection *)));
+ connect(d->document->d, SIGNAL(sectionCursorChanged(TextPagerSection *)),
+ d, SLOT(onTextSectionCursorChanged(TextPagerSection *)));
+
+ d->onDocumentSizeChanged(d->document->documentSize());
+
+ viewport()->update();
+}
+
+/*!
+ returns the textCursor's width (in pixels)
+ \sa setCursorWidth
+*/
+
+int TextPagerEdit::cursorWidth() const
+{
+ return d->cursorWidth;
+}
+
+/*!
+ sets the cursorWidth of the text edit to \a cw pixels.
+ \a cw must be a valid integer larger than 0.
+
+ \sa setCursorVisible
+*/
+
+void TextPagerEdit::setCursorWidth(int cw)
+{
+ Q_ASSERT(d->cursorWidth > 0);
+ d->cursorWidth = cw;
+ viewport()->update();
+}
+
+/*!
+ Loads the contenst of \a dev into the text edit's document.
+ Equivalent to calling document()->load(\a dev, \a mode);
+
+ \sa setCursorVisible
+*/
+
+#if 0
+bool TextPagerEdit::load(QIODevice *dev, TextPagerDocument::DeviceMode mode, QTextCodec *codec)
+{
+#ifdef DEBUG_TEXTPAGER
+ if (doLog) {
+ QFile f(logFileName);
+ f.open(QIODevice::WriteOnly);
+ QDataStream ds(&f);
+ if (QFile *ff = qobject_cast<QFile*>(dev)) {
+ ds << ff->fileName();
+ } else {
+ ds << QString::fromLatin1(dev->metaObject()->className());
+ }
+ }
+#endif
+ //we have to check to font here because the initial setting in setFontProperty doe not have any effect
+ updateFont();
+ return d->document->load(dev, mode, codec);
+}
+#endif
+
+bool TextPagerEdit::load(const QString &file, TextPagerDocument::DeviceMode mode, QTextCodec *codec)
+{
+#ifdef DEBUG_TEXTPAGER
+ if (doLog) {
+ QFile f(logFileName);
+ f.open(QIODevice::WriteOnly);
+ QDataStream ds(&f);
+ ds << file;
+ }
+#endif
+
+ UserMessage::message(UserMessage::DBG,false,"TextPagerEdit::load fileName" + file.toStdString());
+ //we have to check to font here because the initial setting in setFontProperty doe not have any effect
+ updateFont();
+ bool ret=d->document->load(file, mode, codec);
+ UserMessage::message(UserMessage::DBG,false," cursor: " + QString::number(textCursor().position()).toStdString());
+ return ret;
+}
+
+void TextPagerEdit::setText(const QString &txt)
+{
+ //we have to check to font here because the initial setting in setFontProperty doe not have any effect
+ updateFont();
+ d->document->setText(txt);
+}
+
+enum SelectionAddStatus {
+ Invalid,
+ Before,
+ After,
+ Success
+};
+
+
+
+
+
+static inline SelectionAddStatus addSelection(int layoutStart, int layoutLength,
+ const TextPagerCursor &cursor, QTextLayout::FormatRange *format)
+{
+ Q_ASSERT(format);
+ if (!cursor.hasSelection())
+ return Invalid;
+ if (cursor.selectionEnd() < layoutStart)
+ return Before;
+ if (cursor.selectionStart() > layoutStart + layoutLength)
+ return After;
+
+ format->start = qMax(0, cursor.selectionStart() - layoutStart);
+ format->length = qMin(layoutLength - format->start,
+ cursor.selectionEnd() - layoutStart - format->start);
+ return Success;
+}
+
+void TextPagerEdit::paintEvent(QPaintEvent *e)
+{
+ d->updateScrollBarPosition();
+ d->relayout();
+ if (d->updateScrollBarPageStepPending) {
+ d->updateScrollBarPageStepPending = false;
+ d->updateScrollBarPageStep();
+ }
+
+ QPainter p(viewport());
+
+ const QRect er = e->rect();
+ p.translate(-horizontalScrollBar()->value(), 0);
+ p.setFont(font());
+ QVector<QTextLayout::FormatRange> selections;
+ selections.reserve(d->extraSelections.size() + 1);
+ int textLayoutOffset = d->viewportPosition;
+
+ const QTextLayout *cursorLayout = d->cursorVisible ? d->layoutForPosition(d->textCursor.position()) : 0;
+ int extraSelectionIndex = 0;
+ QTextLayout::FormatRange selectionRange;
+ selectionRange.start = -1;
+ Q_FOREACH(QTextLayout *l, d->textLayouts) {
+ const int textSize = l->text().size();
+ const QRect r = l->boundingRect().toRect();
+ if (r.intersects(er)) {
+ const QBrush background = d->blockFormats.value(l).background();
+ if (background.style() != Qt::NoBrush) {
+ p.fillRect(r, background);
+ }
+ if (::addSelection(textLayoutOffset, textSize, d->textCursor, &selectionRange) == Success) {
+ selectionRange.format.setBackground(palette().highlight());
+ selectionRange.format.setForeground(palette().highlightedText());
+ }
+ int lowestIncompleteSelection = -1;
+ while (extraSelectionIndex < d->extraSelections.size()) {
+ QTextLayout::FormatRange range;
+ const SelectionAddStatus s = ::addSelection(textLayoutOffset, textSize,
+ d->extraSelections.at(extraSelectionIndex).
+ cursor, &range);
+ if (s == Success) {
+ range.format = d->extraSelections.at(extraSelectionIndex).format;
+ selections.append(range);
+
+ const TextPagerCursor &cursor = d->extraSelections.at(extraSelectionIndex).cursor;
+ int lastPos = cursor.position() + cursor.selectionSize();
+ if (lastPos > textLayoutOffset+textSize && lowestIncompleteSelection < 0) {
+ lowestIncompleteSelection = extraSelectionIndex;
+ }
+ } else if (s == After) {
+ break;
+ }
+ ++extraSelectionIndex;
+ }
+ if (lowestIncompleteSelection > -1) {
+ extraSelectionIndex = lowestIncompleteSelection;
+ }
+
+ // is this the current line?
+ /*if(cursorLayout == l)
+ {
+ p.fillRect(r, QColor(216,228,239)); // highlight the current line
+ }*/
+
+
+ if (selectionRange.start != -1) {
+ // The last range in the vector has priority, that
+ // should probably be the real selection
+ selections.append(selectionRange);
+ selectionRange.start = -1;
+ }
+
+ l->draw(&p, QPoint(0, 0), selections);
+ if (!selections.isEmpty())
+ selections.clear();
+ if (cursorLayout == l) {
+ cursorLayout->drawCursor(&p, QPoint(0, 0), d->textCursor.position() - textLayoutOffset,
+ d->cursorWidth);
+ }
+ } else if (r.top() > er.bottom()) {
+ break;
+ }
+ textLayoutOffset += l->text().size() + 1;
+ }
+
+
+ //paintLineNumberArea(e);
+}
+
+void TextPagerEdit::scrollContentsBy(int dx, int dy)
+{
+ Q_UNUSED(dx);
+ Q_UNUSED(dy);
+// viewport()->update();
+ viewport()->scroll(dx, dy); // seems to jitter more
+}
+
+int TextPagerEdit::viewportPosition() const
+{
+ return d->viewportPosition;
+}
+
+void TextPagerEdit::mousePressEvent(QMouseEvent *e)
+{
+ d->inMouseEvent = true;
+ if (e->button() == Qt::LeftButton) {
+#ifdef DEBUG_TEXTPAGER
+ if (doLog) {
+ QFile file(logFileName);
+ file.open(QIODevice::Append);
+ QDataStream ds(&file);
+ ds << int(e->type()) << e->pos() << e->button() << e->buttons() << e->modifiers();
+ }
+#endif
+ if (d->tripleClickTimer.isActive()) {
+ d->tripleClickTimer.stop();
+ d->textCursor.movePosition(TextPagerCursor::StartOfBlock);
+ d->textCursor.movePosition(TextPagerCursor::EndOfBlock, TextPagerCursor::KeepAnchor);
+ } else {
+ const bool shift = e->modifiers() & Qt::ShiftModifier;
+ if (!shift) {
+ clearSelection();
+ }
+ int pos = textPositionAt(e->pos());
+ if (pos == -1)
+ pos = d->document->documentSize() - 1;
+ d->sectionPressed = d->document->d->sectionAt(pos, this);
+ setCursorPosition(pos, shift ? TextPagerCursor::KeepAnchor : TextPagerCursor::MoveAnchor);
+ }
+
+ e->accept();
+
+ //The cursor changed so wee need to update the selected line number
+ lineNumArea_->update();
+ }
+ else {
+ QAbstractScrollArea::mousePressEvent(e);
+ }
+}
+
+void TextPagerEdit::mouseDoubleClickEvent(QMouseEvent *e)
+{
+ if (e->button() == Qt::LeftButton) {
+#ifdef DEBUG_TEXTPAGER
+ if (doLog) {
+ QFile file(logFileName);
+ file.open(QIODevice::Append);
+ QDataStream ds(&file);
+ ds << int(e->type()) << e->pos() << e->button() << e->buttons() << e->modifiers();
+ }
+#endif
+ const int pos = textPositionAt(e->pos());
+ if (pos == d->textCursor.position()) {
+ d->tripleClickTimer.start(qApp->doubleClickInterval(), d);
+ if (d->document->isWordCharacter(d->textCursor.cursorCharacter(),
+ d->textCursor.position())) {
+ // ### this is not quite right
+ d->textCursor.movePosition(TextPagerCursor::StartOfWord);
+ d->textCursor.movePosition(TextPagerCursor::EndOfWord, TextPagerCursor::KeepAnchor);
+ return;
+ }
+ }
+ mousePressEvent(e);
+ }
+}
+
+void TextPagerEdit::mouseMoveEvent(QMouseEvent *e)
+{
+ if (e->buttons() == Qt::NoButton) {
+ d->updateCursorPosition(e->pos());
+ } else if (e->buttons() == Qt::LeftButton && d->document->documentSize()) {
+#ifdef DEBUG_TEXTPAGER
+ if (doLog) {
+ QFile file(logFileName);
+ file.open(QIODevice::Append);
+ QDataStream ds(&file);
+ ds << int(e->type()) << e->pos() << e->button() << e->buttons() << e->modifiers();
+ }
+#endif
+ const QRect r = viewport()->rect();
+ d->lastMouseMove = e->pos();
+ e->accept();
+ if (e->y() < r.top()) {
+ if (d->atBeginning()) {
+ d->updateHorizontalPosition();
+ d->autoScrollTimer.stop();
+ return;
+ }
+ } else if (e->y() > r.bottom()) {
+ if (d->atEnd()) {
+ d->updateHorizontalPosition();
+ d->autoScrollTimer.stop();
+ return;
+ }
+ } else {
+ int pos = textPositionAt(QPoint(qBound(0, d->lastMouseMove.x(), r.right()), d->lastMouseMove.y()));
+ if (pos == -1)
+ pos = d->document->documentSize();
+ d->autoScrollTimer.stop();
+ setCursorPosition(pos, TextPagerCursor::KeepAnchor);
+
+ //The cursor changed so wee need to update the selected line number
+ lineNumArea_->update();
+
+ return;
+ }
+ const int distance = qMax(r.top() - d->lastMouseMove.y(), d->lastMouseMove.y() - r.bottom());
+ Q_ASSERT(distance != 0);
+ enum { MinimumTimeOut = 3 };
+ int timeout = qMax<int>(MinimumTimeOut, 100 - distance);
+ enum { Margin = 3 };
+ if (qApp->desktop()->screenGeometry(this).bottom() - mapToGlobal(d->lastMouseMove).y() <= Margin) {
+ timeout = MinimumTimeOut;
+ }
+ d->autoScrollLines = 1 + ((100 - timeout) / 30);
+ if (d->autoScrollTimer.isActive()) {
+ d->pendingTimeOut = timeout;
+ } else {
+ d->pendingTimeOut = -1;
+ d->autoScrollTimer.start(timeout, d);
+ }
+ } else {
+ QAbstractScrollArea::mouseMoveEvent(e);
+ }
+}
+
+void TextPagerEdit::mouseReleaseEvent(QMouseEvent *e)
+{
+ d->inMouseEvent = false;
+ if (e->button() == Qt::LeftButton) {
+#ifdef DEBUG_TEXTPAGER
+ if (doLog) {
+ QFile file(logFileName);
+ file.open(QIODevice::Append);
+ QDataStream ds(&file);
+ ds << int(e->type()) << e->pos() << e->button() << e->buttons() << e->modifiers();
+ }
+#endif
+ d->autoScrollTimer.stop();
+ d->pendingTimeOut = -1;
+ e->accept();
+ if (d->sectionPressed && sectionAt(e->pos()) == d->sectionPressed) {
+ Q_EMIT sectionClicked(d->sectionPressed, e->pos());
+ }
+ d->sectionPressed = 0;
+ } else {
+ QAbstractScrollArea::mouseReleaseEvent(e);
+ }
+}
+
+void TextPagerEdit::resizeEvent(QResizeEvent *e)
+{
+#ifdef DEBUG_TEXTPAGER
+ if (doLog) {
+ QFile file(logFileName);
+ file.open(QIODevice::Append);
+ QDataStream ds(&file);
+ ds << int(e->type()) << e->size();
+ }
+#endif
+ QAbstractScrollArea::resizeEvent(e);
+ if(e->oldSize().height() != e->size().height())
+ d->adjustVerticalScrollBar();
+ d->updateScrollBarPageStepPending = true;
+ d->layoutDirty = true;
+}
+
+int TextPagerEdit::textPositionAt(const QPoint &pos) const
+{
+ if (!viewport()->rect().contains(pos))
+ return -1;
+
+ QPoint realPos=pos;
+ realPos+=QPoint(horizontalScrollBar()->value(),0);
+
+ //Adjust the horizontal position
+ /* if(pos.x() > horizontalScrollBar()->value()+viewport()->rect().width())
+ {
+ int hval=realCrect.left()-r.width()/2;
+ horizontalScrollBar()->setValue((hval < horizontalScrollBar()->maximum())?
+ hval:
+ horizontalScrollBar()->maximum());
+ }
+ else if(realCrect.right() < horizontalScrollBar()->value())
+ {
+ int hval=realCrect.left()-r.width()/2;
+ horizontalScrollBar()->setValue((hval > horizontalScrollBar()->minimum())?
+ hval:
+ horizontalScrollBar()->minimum());
+ }
+}*/
+
+
+
+
+
+
+ return d->textPositionAt(realPos);
+}
+
+bool TextPagerEdit::readOnly() const
+{
+ return d->readOnly;
+}
+
+void TextPagerEdit::setReadOnly(bool rr)
+{
+ d->readOnly = rr;
+
+ setCursorVisible(!rr);
+
+ /* //d->actions[PasteAction]->setEnabled(!rr);
+ //d->actions[CutAction]->setEnabled(!rr);
+ //d->actions[PasteAction]->setVisible(!rr);
+ //d->actions[CutAction]->setVisible(!rr);
+
+ const bool redoWasAvailable = isRedoAvailable();
+ const bool undoWasAvailable = isUndoAvailable();
+
+ // d->actions[UndoAction]->setEnabled(!rr);
+ // d->actions[RedoAction]->setEnabled(!rr);
+ // d->actions[UndoAction]->setVisible(!rr);
+ // d->actions[RedoAction]->setVisible(!rr);
+
+
+ if (undoWasAvailable != isUndoAvailable())
+ Q_EMIT undoAvailableChanged(!undoWasAvailable);
+ if (redoWasAvailable != isRedoAvailable())
+ Q_EMIT redoAvailableChanged(!redoWasAvailable);
+ */
+}
+
+bool TextPagerEdit::lineBreaking() const
+{
+ return d->lineBreaking;
+}
+
+void TextPagerEdit::setLineBreaking(bool lineBreaking)
+{
+ if (d->lineBreaking != lineBreaking) {
+ d->lineBreaking = lineBreaking;
+ d->layoutDirty = true;
+ viewport()->update();
+ }
+}
+
+
+int TextPagerEdit::maximumSizeCopy() const
+{
+ return d->maximumSizeCopy;
+}
+
+void TextPagerEdit::setMaximumSizeCopy(int max)
+{
+ d->maximumSizeCopy = qMax(0, max);
+ d->updateCopyAndCutEnabled();
+}
+
+QRect TextPagerEdit::cursorBlockRect(const TextPagerCursor &textCursor) const
+{
+ if (const QTextLayout *l = d->layoutForPosition(textCursor.position())) {
+ return l->boundingRect().toRect();
+ }
+ return QRect();
+}
+
+QRect TextPagerEdit::cursorRect(const TextPagerCursor &textCursor) const
+{
+ int offset = -1;
+ if (d->layoutForPosition(textCursor.position(), &offset)) {
+ ASSUME(offset != -1);
+ QTextLine line = d->lineForPosition(textCursor.position());
+
+ //if line is empty line.cursorToX() crashes. A qt bug?
+ if(line.isValid()) {
+ qreal x = line.cursorToX(offset);
+ return QRect(x, line.y(), d->cursorWidth, line.height());
+ }
+ }
+ return QRect();
+}
+
+int TextPagerEdit::lineNumber(int position) const
+{
+ return d->document->lineNumber(position);
+}
+
+int TextPagerEdit::columnNumber(int position) const
+{
+ TextPagerCursor cursor(this, position);
+ return cursor.isNull() ? -1 : cursor.columnNumber();
+}
+
+int TextPagerEdit::lineNumber(const TextPagerCursor &cursor) const
+{
+ return cursor.document() == d->document
+ ? d->document->lineNumber(cursor.position()) : -1;
+}
+
+int TextPagerEdit::columnNumber(const TextPagerCursor &cursor) const
+{
+ return cursor.document() == d->document
+ ? cursor.columnNumber() : -1;
+}
+
+void TextPagerEdit::wheelEvent(QWheelEvent *e)
+{
+ if (e->orientation() == Qt::Vertical) {
+ d->scrollLines(3 * (e->delta() > 0 ? -1 : 1));
+ } else {
+ QAbstractScrollArea::wheelEvent(e);
+ }
+
+ if(e->modifiers() & Qt::ControlModifier)
+ {
+ const int delta = e->delta();
+ if (delta < 0)
+ zoomOut();
+ else if (delta > 0)
+ zoomIn();
+ return;
+ }
+}
+
+void TextPagerEdit::changeEvent(QEvent *e)
+{
+ if (e->type() == QEvent::FontChange) {
+ d->font = font();
+ Q_FOREACH(QTextLayout *l, d->textLayouts) {
+ l->setFont(d->font);
+ }
+ Q_FOREACH(QTextLayout *l, d->unusedTextLayouts) {
+ l->setFont(d->font);
+ }
+
+ d->adjustVerticalScrollBar();
+
+ lineNumArea_->updateWidth();
+
+ d->layoutDirty = true;
+ viewport()->update();
+ }
+}
+
+void TextPagerEdit::keyPressEvent(QKeyEvent *e)
+{
+#ifdef DEBUG_TEXTPAGER
+ if (doLog) {
+ QFile file(logFileName);
+ file.open(QIODevice::Append);
+ QDataStream ds(&file);
+ ds << int(e->type()) << e->key() << int(e->modifiers()) << e->text() << e->isAutoRepeat() << e->count();
+ }
+#endif
+
+ Q_ASSERT(d->textCursor.textEdit == this);
+ if (d->readOnly) {
+ d->cursorMoveKeyEventReadOnly(e);
+ return;
+ }
+}
+
+void TextPagerEdit::keyReleaseEvent(QKeyEvent *e)
+{
+#ifdef DEBUG_TEXTPAGER
+ if (doLog) { // ### does it make any sense to replay these? Probably not
+ QFile file(logFileName);
+ file.open(QIODevice::Append);
+ QDataStream ds(&file);
+ ds << int(e->type()) << e->key() << int(e->modifiers()) << e->text() << e->isAutoRepeat() << e->count();
+ }
+#endif
+ QAbstractScrollArea::keyReleaseEvent(e);
+}
+
+void TextPagerEdit::setCursorPosition(int pos, TextPagerCursor::MoveMode mode)
+{
+ d->textCursor.setPosition(pos, mode);
+}
+
+bool TextPagerEdit::moveCursorPosition(TextPagerCursor::MoveOperation op, TextPagerCursor::MoveMode mode, int n)
+{
+ return d->textCursor.movePosition(op, mode, n);
+}
+
+void TextPagerEdit::copy(QClipboard::Mode mode)
+{
+ if (d->textCursor.selectionSize() <= d->maximumSizeCopy) {
+ QApplication::clipboard()->setText(selectedText(), mode);
+ }
+}
+
+bool TextPagerEdit::cursorVisible() const
+{
+ return d->cursorBlinkTimer.isActive();
+}
+
+void TextPagerEdit::setCursorVisible(bool cc)
+{
+ if (cc == d->cursorBlinkTimer.isActive())
+ return;
+
+ d->cursorVisible = cc;
+ if (cc) {
+ d->cursorBlinkTimer.start(QApplication::cursorFlashTime(), d);
+ } else {
+ d->cursorBlinkTimer.stop();
+ }
+ const QRect r = cursorRect(d->textCursor) & viewport()->rect();
+ if (!r.isNull()) {
+ viewport()->update(r);
+ }
+}
+
+void TextPagerEdit::clearSelection()
+{
+ if (!d->textCursor.hasSelection())
+ return;
+
+ d->textCursor.clearSelection();
+}
+
+QString TextPagerEdit::selectedText() const
+{
+ return d->textCursor.selectedText();
+}
+
+bool TextPagerEdit::hasSelection() const
+{
+ return d->textCursor.hasSelection();
+}
+
+void TextPagerEdit::selectAll()
+{
+ TextPagerCursor cursor(d->document);
+ Q_ASSERT(cursor.position() == 0);
+ cursor.movePosition(TextPagerCursor::End, TextPagerCursor::KeepAnchor);
+ setTextCursor(cursor);
+ Q_EMIT selectionChanged();
+}
+
+QString TextPagerEdit::read(int pos, int size) const
+{
+ return d->document->read(pos, size);
+}
+
+QChar TextPagerEdit::readCharacter(int index) const
+{
+ return d->document->readCharacter(index);
+}
+
+void TextEditPrivate::onDocumentSizeChanged(int size)
+{
+ adjustVerticalScrollBar();
+
+ /*int s=findLastPageSize();
+
+ qDebug() << "lat page position" << s;
+
+ if(s != -1)
+ textEdit->verticalScrollBar()->setRange(0, s);
+ else
+ textEdit->verticalScrollBar()->setRange(0, qMax(0, size));
+
+
+ //textEdit->verticalScrollBar()->setRange(0, qMax(0, size));
+// qDebug() << findLastPageSize();
+ maxViewportPosition = textEdit->verticalScrollBar()->maximum();
+ updateScrollBarPageStepPending = true;*/
+}
+
+
+void TextEditPrivate::adjustVerticalScrollBar()
+{
+ int s=findLastPageSize();
+
+ int size=(document != 0)?(document->documentSize()):0;
+
+#ifdef DEBUG_TEXTPAGER_LASTPAGESIZE
+ qDebug() << "last page position" << s;
+#endif
+ if(s == 0) {
+ textEdit->verticalScrollBar()->hide();
+ textEdit->verticalScrollBar()->setEnabled(false);
+ } else {
+ textEdit->verticalScrollBar()->setEnabled(true);
+ textEdit->verticalScrollBar()->show();
+
+ if(s != -1)
+ textEdit->verticalScrollBar()->setRange(0, s);
+ else
+ textEdit->verticalScrollBar()->setRange(0, qMax(0, size));
+ }
+
+ //textEdit->verticalScrollBar()->setRange(0, qMax(0, size));
+// qDebug() << findLastPageSize();
+ maxViewportPosition = textEdit->verticalScrollBar()->maximum();
+ updateScrollBarPageStepPending = true;
+}
+
+void TextEditPrivate::updateCopyAndCutEnabled()
+{
+ const bool wasEnabled = actions[TextPagerEdit::CopyAction]->isEnabled();
+ const bool enable = qAbs(textCursor.position() - textCursor.anchor()) <= maximumSizeCopy;
+ actions[TextPagerEdit::CopyAction]->setEnabled(enable);
+ //actions[TextPagerEdit::CutAction]->setEnabled(enable);
+ if (wasEnabled != enable) {
+ Q_EMIT textEdit->copyAvailable(enable);
+ }
+}
+
+void TextPagerEdit::takeSyntaxHighlighter(SyntaxHighlighter *highlighter)
+{
+ Q_ASSERT(highlighter);
+ const bool found = d->syntaxHighlighters.removeOne(highlighter);
+ Q_ASSERT(found);
+ Q_UNUSED(found);
+ highlighter->d->textEdit = 0;
+ highlighter->d->textLayout = 0;
+ disconnect(highlighter, 0, d, 0);
+}
+
+void TextPagerEdit::removeSyntaxHighlighter(SyntaxHighlighter *highlighter)
+{
+ takeSyntaxHighlighter(highlighter);
+ delete highlighter;
+}
+
+void TextPagerEdit::addSyntaxHighlighter(SyntaxHighlighter *highlighter)
+{
+ Q_ASSERT(highlighter);
+ if (highlighter->textEdit() != this) {
+ if (highlighter->textEdit()) {
+ qWarning("A SyntaxHighlighter can only be added to 1 TextPagerEdit. If this is a "
+ "use case you care about (having a syntaxHighlighter added to multiple "
+ "text edits) I could fix it. Anders");
+ return;
+ }
+ d->syntaxHighlighters.append(highlighter);
+ connect(highlighter, SIGNAL(destroyed(QObject*)), d, SLOT(onSyntaxHighlighterDestroyed(QObject*)));
+ highlighter->d->textEdit = this;
+ highlighter->d->textLayout = d;
+ d->layoutDirty = true;
+ viewport()->update();
+ }
+}
+
+void TextPagerEdit::clearSyntaxHighlighters()
+{
+ Q_FOREACH(SyntaxHighlighter *highlighter, d->syntaxHighlighters) {
+ if (highlighter->parent() == this) {
+ removeSyntaxHighlighter(highlighter);
+ } else {
+ takeSyntaxHighlighter(highlighter);
+ }
+ }
+ Q_ASSERT(d->syntaxHighlighters.isEmpty());
+}
+
+
+void TextEditPrivate::onSyntaxHighlighterDestroyed(QObject *o)
+{
+ const bool found = syntaxHighlighters.removeOne(static_cast<SyntaxHighlighter*>(o));
+ Q_ASSERT(found);
+ Q_UNUSED(found);
+ layoutDirty = true;
+ textEdit->viewport()->update();
+}
+
+QList<SyntaxHighlighter*> TextPagerEdit::syntaxHighlighters() const
+{
+ return d->syntaxHighlighters;
+}
+
+static inline bool compareExtraSelection(const TextPagerEdit::ExtraSelection &left, const TextPagerEdit::ExtraSelection &right)
+{
+ return left.cursor < right.cursor;
+}
+
+void TextPagerEdit::setExtraSelections(const QList<ExtraSelection> &selections)
+{
+ d->extraSelections = selections;
+ qSort(d->extraSelections.begin(), d->extraSelections.end(), compareExtraSelection);
+ d->layoutDirty = true;
+ viewport()->update();
+}
+
+QList<TextPagerEdit::ExtraSelection> TextPagerEdit::extraSelections() const
+{
+ return d->extraSelections;
+}
+
+void TextEditPrivate::onTextSectionRemoved(TextPagerSection *section)
+{
+ Q_ASSERT(section);
+ if (!dirtyForSection(section))
+ return;
+
+ sectionsDirty = true;
+ if (section == sectionPressed) {
+ sectionPressed = 0;
+ }
+ if (section->hasCursor()) {
+ updateCursorPosition(lastHoverPos);
+ }
+}
+
+void TextEditPrivate::onTextSectionAdded(TextPagerSection *section)
+{
+ dirtyForSection(section);
+ updateCursorPosition(lastHoverPos);
+ sectionsDirty = true;
+}
+
+void TextEditPrivate::onScrollBarValueChanged(int value)
+{
+ if (blockScrollBarUpdate || value == requestedScrollBarPosition || value == viewportPosition)
+ return;
+ requestedScrollBarPosition = value;
+ layoutDirty = true;
+ textEdit->viewport()->update();
+
+ Q_EMIT scrollBarChanged();
+}
+
+void TextEditPrivate::onScrollBarActionTriggered(int action)
+{
+ switch (action) {
+ case QAbstractSlider::SliderSingleStepAdd:
+ scrollLines(1); requestedScrollBarPosition = -1; break;
+ case QAbstractSlider::SliderSingleStepSub:
+ scrollLines(-1); requestedScrollBarPosition = -1; break;
+ default: break;
+ }
+
+ Q_EMIT scrollBarChanged();
+}
+
+void TextEditPrivate::updateScrollBar()
+{
+ Q_ASSERT(!textEdit->verticalScrollBar()->isSliderDown());
+ if (pendingScrollBarUpdate) {
+ const bool old = blockScrollBarUpdate;
+ blockScrollBarUpdate = true;
+ textEdit->verticalScrollBar()->setValue(viewportPosition);
+ blockScrollBarUpdate = old;
+ pendingScrollBarUpdate = false;
+
+ Q_EMIT scrollBarChanged();
+ }
+}
+
+void TextEditPrivate::onCharactersAddedOrRemoved(int from, int count)
+{
+ Q_ASSERT(count >= 0);
+ Q_UNUSED(count);
+
+ textCursor.clearSelection();
+
+ if(textCursor.position() > document->documentSize())
+ textCursor.setPosition(0);
+
+ UserMessage::message(UserMessage::DBG,false,
+ "TextEditPrivate::onCharactersAddedOrRemoved --> textCursor: " + QString::number(textCursor.position()).toStdString());
+
+ /*if (from > qMin(bufferPosition + buffer.size(), layoutEnd)) {
+ return;
+ }*/
+ buffer.clear(); // isn't it better to just add them here?
+ layoutDirty = true;
+ textEdit->viewport()->update();
+}
+
+void TextPagerEdit::ensureCursorVisible()
+{
+ if (d->textCursor.position() < d->viewportPosition) {
+ d->updateViewportPosition(qMax(0, d->textCursor.position() - 1), TextPagerLayout::Backward);
+ } else if (d->textCursor.position() > d->layoutEnd) {
+ d->updateViewportPosition(d->textCursor.position(), TextPagerLayout::Backward);
+ viewport()->update();
+ } else {
+ const QRect r = viewport()->rect();
+ QRect realCrect = cursorRect(d->textCursor);
+ QRect crect = realCrect;
+ crect.setLeft(r.left());
+ crect.setRight(r.right());
+ // ### what if the cursor is out of bounds horizontally?
+
+ //qDebug() << "ensureCursorVisible" << r << crect << cursorRect(d->textCursor) << horizontalScrollBar()->value() << horizontalScrollBar()->maximum() << d->widest;
+ if (!r.contains(crect)) {
+ if (r.intersects(crect)) {
+ int scroll;
+ if (d->autoScrollLines != 0) {
+ scroll = d->autoScrollLines;
+ } else {
+ scroll = (crect.top() < r.top() ? -1 : 1);
+ }
+ d->scrollLines(scroll);
+ } else {
+ d->updateViewportPosition(d->textCursor.position(), TextPagerLayout::Backward);
+ }
+ viewport()->update();
+ }
+
+ //Adjust the horizontal position
+ if(realCrect.left() > horizontalScrollBar()->value()+r.width())
+ {
+ int hval=realCrect.left()-r.width()/2;
+ horizontalScrollBar()->setValue((hval < horizontalScrollBar()->maximum())?
+ hval:
+ horizontalScrollBar()->maximum());
+ }
+ else if(realCrect.right() < horizontalScrollBar()->value())
+ {
+ int hval=realCrect.left()-r.width()/2;
+ horizontalScrollBar()->setValue((hval > horizontalScrollBar()->minimum())?
+ hval:
+ horizontalScrollBar()->minimum());
+ }
+ }
+}
+
+//textEdit->horizontalScrollBar()->setPageStep(s.width());
+//textEdit->horizontalScrollBar()->setMaximum(qMax(0, widest - s.width()));
+
+
+TextPagerCursor &TextPagerEdit::textCursor()
+{
+ return d->textCursor;
+}
+
+const TextPagerCursor &TextPagerEdit::textCursor() const
+{
+ return d->textCursor;
+}
+
+void TextPagerEdit::setTextCursor(const TextPagerCursor &textCursor)
+{
+ const bool doEmit = (d->textCursor != textCursor);
+ d->textCursor = textCursor;
+ d->textCursor.textEdit = this;
+ if (doEmit) {
+ ensureCursorVisible();
+ viewport()->update();
+ Q_EMIT cursorPositionChanged(textCursor.position());
+ }
+}
+
+TextPagerCursor TextPagerEdit::cursorForPosition(const QPoint &pos) const
+{
+ const int idx = textPositionAt(pos);
+ if (idx == -1)
+ return TextPagerCursor();
+ return TextPagerCursor(this, idx);
+}
+
+TextPagerSection *TextPagerEdit::sectionAt(const QPoint &pos) const
+{
+ Q_ASSERT(d->document);
+ int textPos = textPositionAt(pos);
+ if (textPos == -1)
+ textPos = d->document->d->documentSize - 1;
+ return d->document->d->sectionAt(textPos, this);
+}
+
+QList<TextPagerSection*> TextPagerEdit::sections(int from, int size, TextPagerSection::TextSectionOptions opt) const
+{
+ Q_ASSERT(d->document);
+ QList<TextPagerSection*> sections = d->document->d->getSections(from, size, opt, this);
+ return sections;
+}
+
+TextPagerSection *TextPagerEdit::insertTextSection(int pos, int size, const QTextCharFormat &format, const QVariant &data)
+{
+ Q_ASSERT(d->document);
+ TextPagerSection *section = d->document->insertTextSection(pos, size, format, data);
+ if (section) {
+ section->d.textEdit = this;
+ section->d.priority = 100;
+ }
+ return section;
+}
+
+void TextEditPrivate::updateHorizontalPosition()
+{
+ const QRect r = textEdit->viewport()->rect();
+ const QPoint p(qBound(0, lastMouseMove.x(), r.right()),
+ qBound(0, lastMouseMove.y(), r.bottom()));
+ int pos = textPositionAt(p);
+ if (pos == -1)
+ pos = document->documentSize() - 1;
+ textEdit->setCursorPosition(pos, TextPagerCursor::KeepAnchor);
+}
+
+void TextEditPrivate::updateScrollBarPosition()
+{
+ if (requestedScrollBarPosition == -1) {
+ return;
+ } else if (requestedScrollBarPosition == viewportPosition) {
+ requestedScrollBarPosition = -1;
+ return;
+ }
+
+ const int req = requestedScrollBarPosition;
+ requestedScrollBarPosition = -1;
+
+ Direction direction = Forward;
+ if (lastRequestedScrollBarPosition != -1 && lastRequestedScrollBarPosition != req) {
+ if (lastRequestedScrollBarPosition > req) {
+ direction = Backward;
+ }
+ } else if (req < viewportPosition) {
+ direction = Backward;
+ }
+
+ lastRequestedScrollBarPosition = req;
+
+ updateViewportPosition(req, direction);
+}
+
+void TextEditPrivate::updateScrollBarPageStep()
+{
+ if (lines.isEmpty()) {
+ textEdit->verticalScrollBar()->setPageStep(1);
+ return;
+ }
+ const int visibleCharacters = lines.at(qMin(visibleLines, lines.size() - 1)).first - lines.at(0).first;
+ textEdit->verticalScrollBar()->setPageStep(visibleCharacters);
+}
+
+void TextEditPrivate::onDocumentDestroyed()
+{
+ document = 0;
+ textEdit->setDocument(new TextPagerDocument(this)); // there should always be a document
+}
+
+void TextEditPrivate::scrollLines(int lines)
+{
+ int pos = viewportPosition;
+ const Direction d = (lines < 0 ? Backward : Forward);
+ const int add = lines < 0 ? -1 : 1;
+
+ while (pos + add >= 0 && pos + add < document->documentSize()) {
+ if (d == Forward &&
+ (lines - add == 0) &&
+ bufferReadCharacter(pos) == '\n') {
+ // When iterating forwards, be sure not to skip over blank lines
+ // (ie. lines containing only '\n') by just ignoring them here
+ // - updateViewportPosition automatically takes us one index past
+ // this newline, thus displaying the next line)
+ break;
+ } else {
+ pos += add;
+ if (bufferReadCharacter(pos) == '\n') {
+ if ((lines -= add) == 0) {
+ break;
+ }
+ }
+ }
+ }
+ updateViewportPosition(pos, d);
+}
+
+void TextEditPrivate::timerEvent(QTimerEvent *e)
+{
+ if (e->timerId() == tripleClickTimer.timerId()) {
+ tripleClickTimer.stop();
+ } else if (e->timerId() == autoScrollTimer.timerId()) {
+ if (pendingTimeOut != -1) {
+ autoScrollTimer.start(pendingTimeOut, this);
+ pendingTimeOut = -1;
+ }
+ const QRect r = textEdit->viewport()->rect();
+ Q_ASSERT(!r.contains(lastMouseMove));
+ enum { LineCount = 1 };
+ if (lastMouseMove.y() < r.top()) {
+ scrollLines(-LineCount);
+ if (atBeginning())
+ autoScrollTimer.stop();
+ } else {
+ Q_ASSERT(lastMouseMove.y() > r.bottom());
+ scrollLines(LineCount);
+ if (atEnd())
+ autoScrollTimer.stop();
+ }
+ const QPoint p(qBound(0, lastMouseMove.x(), r.right()),
+ qBound(0, lastMouseMove.y(), r.bottom()));
+ int pos = textPositionAt(p);
+ if (pos == -1)
+ pos = document->documentSize() - 1;
+ textEdit->setCursorPosition(pos, TextPagerCursor::KeepAnchor);
+ } else if (e->timerId() == cursorBlinkTimer.timerId()) {
+ cursorVisible = !cursorVisible;
+ const QRect r = textEdit->cursorRect(textCursor) & textEdit->viewport()->rect();
+ if (!r.isNull())
+ textEdit->viewport()->update(r);
+ } else {
+ Q_ASSERT(0);
+ }
+}
+
+static inline bool compareTextSectionByPriority(const TextPagerSection *left, const TextPagerSection *right)
+{
+ return left->priority() > right->priority();
+}
+
+void TextEditPrivate::updateCursorPosition(const QPoint &pos)
+{
+ lastHoverPos = pos;
+ const int textPos = textPositionAt(pos);
+ if (textPos != -1) {
+ QList<TextPagerSection*> hovered = textEdit->sections(textPos, 1, TextPagerSection::IncludePartial);
+ qSort(hovered.begin(), hovered.end(), compareTextSectionByPriority);
+ Q_FOREACH(TextPagerSection *section, hovered) {
+ if (section->hasCursor()) {
+ delete sectionCursor;
+ sectionCursor = new QCursor(section->cursor());
+ textEdit->viewport()->setCursor(*sectionCursor);
+ return;
+ }
+ }
+ }
+ // no cursor
+ if (sectionCursor) {
+ textEdit->viewport()->setCursor(Qt::IBeamCursor);
+ delete sectionCursor;
+ sectionCursor = 0;
+ }
+
+ //To notify the line num area widge!
+ Q_EMIT scrollBarChanged();
+}
+
+bool TextEditPrivate::isSectionOnScreen(const TextPagerSection *section) const
+{
+ Q_ASSERT(section->document() == document);
+ return (::matchSection(section, textEdit)
+ && section->position() <= layoutEnd
+ && section->position() + section->size() >= viewportPosition);
+}
+
+void TextEditPrivate::cursorMoveKeyEventReadOnly(QKeyEvent *e)
+{
+ if (e == QKeySequence::MoveToNextLine) {
+ scrollLines(1);
+ } else if (e == QKeySequence::MoveToPreviousLine) {
+ scrollLines(-1);
+ } else if (e == QKeySequence::MoveToStartOfDocument) {
+ textEdit->verticalScrollBar()->setValue(0);
+ } else if (e == QKeySequence::MoveToEndOfDocument) {
+ textEdit->verticalScrollBar()->setValue(textEdit->verticalScrollBar()->maximum());
+ } else if (e == QKeySequence::MoveToNextPage) {
+ scrollLines(qMax(1, visibleLines - 1));
+ } else if (e == QKeySequence::MoveToPreviousPage) {
+ scrollLines(-qMax(1, visibleLines));
+ } else if (e == QKeySequence::MoveToStartOfLine) {
+ textCursor.movePosition(TextPagerCursor::StartOfLine);
+ e->accept();
+ return;
+ } else if (e == QKeySequence::MoveToEndOfLine) {
+ textCursor.movePosition(TextPagerCursor::EndOfLine);
+ e->accept();
+ return;
+ }
+
+ else {
+ e->ignore();
+ return;
+ }
+ e->accept();
+ textCursor.setPosition(viewportPosition);
+}
+
+void TextEditPrivate::relayout()
+{
+ const QSize s = textEdit->viewport()->size();
+
+ int widestOri=widest;
+
+ widest=-1;
+ relayoutByGeometry(s.height());
+ if(widest == -1)
+ widest=widestOri;
+
+ textEdit->horizontalScrollBar()->setPageStep(s.width());
+ textEdit->horizontalScrollBar()->setMaximum(qMax(0, widest - s.width()));
+#ifdef _UI_TEXTPAGER_DEBUG
+ qDebug() << widest << s.width() << textEdit->horizontalScrollBar()->maximum();
+#endif
+}
+
+bool TextEditPrivate::dirtyForSection(TextPagerSection *section)
+{
+ if (isSectionOnScreen(section)) {
+ layoutDirty = true;
+ textEdit->viewport()->update();
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void TextEditPrivate::onTextSectionFormatChanged(TextPagerSection *section)
+{
+ dirtyForSection(section);
+}
+
+void TextEditPrivate::onTextSectionCursorChanged(TextPagerSection *section)
+{
+ if (isSectionOnScreen(section)) {
+ updateCursorPosition(lastHoverPos);
+ }
+}
+
+void TextEditPrivate::onSelectionChanged()
+{
+ if (inMouseEvent && textCursor.hasSelection() && QApplication::clipboard()->supportsSelection()) {
+ textEdit->copy(QClipboard::Selection);
+ }
+
+ textEdit->viewport()->update();
+ // ### could figure out old selection rect and | it with new one
+ // ### and update that but is it worth it?
+ updateCopyAndCutEnabled();
+}
+
+bool TextEditPrivate::canInsertFromMimeData(const QMimeData *data) const
+{
+ return data->hasText();
+}
+
+
+//Find the viewport position for the end of the document supposing the the last line
+//is exactly located at the bottom of the viewport.
+int TextEditPrivate::findLastPageSize() const
+{
+ if (!document || document->documentSize() == 0)
+ return -1;
+
+#ifdef DEBUG_TEXTPAGER_LASTPAGESIZE
+ qDebug() << "TextEditPrivate::findLastPageSize -->";
+#endif
+ TextEditPrivate p(textEdit);
+ p.font=textEdit->font();
+ p.viewportPosition = 0;
+ p.document = document;
+ const int documentSize = document->documentSize();
+ p.maxViewportPosition = documentSize;
+
+ //The viewport height (including the height of the horizontal slider)
+ int vh=p.textEdit->viewport()->height(); //-p.textEdit->horizontalScrollBar()->height();
+
+ //Max 1.5*MinimumBufferSize can be kept in the buffer after the viewportPosition
+ int maxCharNum=p.MinimumBufferSize*1.5-200;
+
+ //We use the lastpage cache to find a better start position
+
+#ifdef DEBUG_TEXTPAGER_LASTPAGESIZE
+ qDebug() << " lastPageCache height:" << lastPage.height << "position:" << lastPage.position <<
+ "documentSize:" << lastPage.documentSize << "widest:" << lastPage.widest;
+#endif
+
+ if(lastPage.documentSize != documentSize)
+ {
+ lastPage.clear();
+ lastPage.documentSize = documentSize;
+ }
+
+ Direction sizeChangeDir=Forward;
+ if(lastPage.height != -1) {
+ if(lastPage.height > vh) {
+ maxCharNum=documentSize-lastPage.position+1;
+ sizeChangeDir=Backward;
+ } else if(lastPage.height< vh) {
+ maxCharNum=documentSize-lastPage.position+1000;
+ sizeChangeDir=Backward;
+ } else {
+ return lastPage.position;
+ }
+ }
+
+ lastPage.height=vh;
+
+ Q_ASSERT(maxCharNum>=0);
+
+ int start = documentSize-maxCharNum;
+ if(start < 0) start=0;
+ int i = 0;
+#ifdef DEBUG_TEXTPAGER_LASTPAGESIZE
+ QTime tm;
+ tm.start();
+#endif
+
+ //Try to find the last page by iteration
+ int step=0;
+ const int maxStep=10;
+ bool reachedTop=(start == 0);
+
+ while(step < maxStep) {
+#ifdef DEBUG_TEXTPAGER_LASTPAGESIZE
+ qDebug() << " ITERATION STEP:" << step;
+ qDebug() << " start:" << start << "maxCharNum:" << maxCharNum;
+#endif
+ //We get the viewportPosition closest to start
+ p.updateViewportPosition(start,sizeChangeDir,false);
+
+#ifdef DEBUG_TEXTPAGER_LASTPAGESIZE
+ qDebug() << " after updateviewport> start-viewportPos:" << start-p.viewportPosition;
+#endif
+ //adjust the max number of characters
+ if(start > p.viewportPosition)
+ maxCharNum+=(start-p.viewportPosition)+1;
+
+ //Relayout using the max number of characters
+ p.relayoutByPosition(maxCharNum);
+
+#ifdef DEBUG_TEXTPAGER_LASTPAGESIZE
+ qDebug() << " vh:" << vh << "fontSize:" << font.pointSize();
+ qDebug() << " viewport size" << textEdit->viewport()->size();
+ qDebug() << " layoutEnd:" << p.layoutEnd << "documentSize:" << documentSize << "viewportPosition:" << p.viewportPosition << p.contentRect;
+ qDebug() << " bottom:" << p.textLayouts.last()->boundingRect().bottom();
+#endif
+
+ //The end of the layout should be the end of the document
+ if(p.layoutEnd == documentSize && p.textLayouts.count() >0) {
+
+ int top=p.textLayouts.last()->boundingRect().bottom()+4-vh;
+ int pos=documentSize-p.textLayouts.last()->text().size();
+
+ for(int i=p.textLayouts.count()-2; i >=0; i--) {
+
+ if(p.textLayouts.at(i)->boundingRect().top() <= top) {
+#ifdef DEBUG_TEXTPAGER_LASTPAGESIZE
+ qDebug() << " find position:" << pos; // << "line:" << p.document->lineNumber(pos);
+#endif
+ p.updateViewportPosition(pos, Backward,false);
+#ifdef DEBUG_TEXTPAGER_LASTPAGESIZE
+ qDebug() << " viewPortPosition:" << p.viewportPosition << "time:" << tm.elapsed(); // << "line:" << p.document->lineNumber(p.viewportPosition);
+#endif
+ lastPage.position=p.viewportPosition;
+ lastPage.widest=p.widest;
+ return p.viewportPosition;
+ }
+ pos-=p.textLayouts.at(i)->text().size();
+ }
+ }
+ //We could not find the last page. We try again from a larger number of characters from the
+ //end of the document
+ step++;
+ maxCharNum+=1000;
+ start = documentSize-maxCharNum;
+
+ if(start < 0 && reachedTop)
+ break;
+
+ if(start < 0)
+ {
+ reachedTop=true;
+ start=0;
+ }
+ }
+
+ lastPage.clear();
+
+ //the whole text is in the viewport, no vertical scrollbar is needed
+ if(reachedTop)
+ return -1;
+
+ //If we are here we the last page position will be the end of the document and there will be
+ //a white space block after the last row in the editor.
+ //TODO: improve it!
+ return documentSize;
+}
+
+void TextPagerEdit::setSyntaxHighlighter(SyntaxHighlighter *h)
+{
+ if (h && h->textEdit() == this) {
+ if (d->syntaxHighlighters.size() == 1)
+ return;
+ takeSyntaxHighlighter(h);
+ }
+ clearSyntaxHighlighters();
+ if (h) {
+ addSyntaxHighlighter(h);
+ }
+}
+
+
+void TextPagerEdit::setEnableSearchHighlighter(bool b)
+{
+ useSearchHighlight_=b;
+ if(useSearchHighlight_) {
+ setSyntaxHighlighter(searchHighlight_);
+ } else {
+ //searchHighlight_ can only be deleted when the editor is deleted.
+ //Because clearSyntaxHighlighters() deletes the highlighters we need to use
+ //takeSyntaxHighlighter() instead.
+ if(d->syntaxHighlighters.contains(searchHighlight_)) {
+ takeSyntaxHighlighter(searchHighlight_);
+ d->layoutDirty = true;
+ viewport()->update();
+ //clearSyntaxHighlighters();
+ }
+ }
+}
+
+void TextPagerEdit::clearSearchHighlighter()
+{
+ searchHighlight_->clear();
+}
+
+void TextPagerEdit::setSearchHighlighter(QString txt,TextPagerDocument::FindMode mode)
+{
+ searchHighlight_->reset(txt,mode,useSearchHighlight_);
+}
+
+void TextPagerEdit::setSearchHighlighter(QRegExp rx,TextPagerDocument::FindMode mode)
+{
+ searchHighlight_->reset(rx,mode,useSearchHighlight_);
+}
+
+void TextPagerEdit::gotoLine(int lineNum)
+{
+ TextPagerCursor cursor=d->document->findLine(lineNum,textCursor());
+ if(!cursor.isNull())
+ setTextCursor(cursor);
+}
+
+//---------------------------------------------
+// Fontsize management
+//---------------------------------------------
+
+void TextPagerEdit::setFontProperty(VProperty* p)
+{
+ fontProp_=p;
+ fontProp_->addObserver(this);
+ updateFont();
+}
+
+void TextPagerEdit::zoomIn()
+{
+ QFont f=font();
+ int fps=f.pointSize();
+ f.setPointSize(fps+1);
+ setFont(f);
+
+ fontSizeChangedByZoom();
+}
+
+void TextPagerEdit::zoomOut()
+{
+ int oriSize=font().pointSize();
+
+ QFont f=font();
+ int fps=f.pointSize();
+ if(fps > 1)
+ {
+ f.setPointSize(fps-1);
+ setFont(f);
+ }
+
+ if(font().pointSize() != oriSize)
+ fontSizeChangedByZoom();
+}
+
+void TextPagerEdit::fontSizeChangedByZoom()
+{
+ if(fontProp_)
+ fontProp_->setValue(font());
+}
+
+void TextPagerEdit::updateFont()
+{
+ if(fontProp_)
+ {
+ QFont f=fontProp_->value().value<QFont>();
+ if(font() != f)
+ setFont(f);
+ }
+}
+
+void TextPagerEdit::notifyChange(VProperty* p)
+{
+ if(fontProp_ ==p)
+ {
+ setFont(p->value().value<QFont>());
+ }
+}
+
+void TextPagerEdit::setLineNumberArea(TextPagerLineNumberArea *a)
+{
+ lineNumArea_=a;
+ connect(d,SIGNAL(scrollBarChanged()),
+ lineNumArea_,SLOT(update()));
+
+ //Initialise the width
+ lineNumArea_->updateWidth();
+}
+
+void TextPagerEdit::lineNumberAreaPaintEvent(QPaintEvent *e)
+{
+ if(!lineNumArea_)
+ return;
+
+ QPainter painter(lineNumArea_);
+ const QRect er = e->rect();
+ //painter.translate(-horizontalScrollBar()->value(), 0);
+ //painter.setFont(font());
+
+ QVector<QTextLayout::FormatRange> selections;
+ selections.reserve(d->extraSelections.size() + 1);
+ int textLayoutOffset = d->viewportPosition;
+
+ QRect numRect=er;
+
+ //Background and border
+ painter.fillRect(numRect, lineNumArea_->bgColour());
+ painter.setPen(QPen(lineNumArea_->separatorColour()));
+ painter.drawLine(lineNumArea_->width()-1,er.y(),lineNumArea_->width()-1,er.bottom());
+
+ int numWidth=lineNumArea_->width()-lineNumArea_->rightMargin();
+
+ QFont fontNormal(font()); // the font to use for most line numbers
+ QFont fontBold(fontNormal); // the font to use for the current line number
+ fontBold.setBold(true);
+ painter.setPen(lineNumArea_->fontColour());
+ painter.setFont(fontNormal);
+
+ int cursorPos=d->textCursor.position();
+
+ //const QTextLayout *cursorLayout = d->cursorVisible ? d->layoutForPosition(d->textCursor.position()) : 0;
+ //int extraSelectionIndex = 0;
+ QTextLayout::FormatRange selectionRange;
+ selectionRange.start = -1;
+ int maxLineNum=-1;
+ Q_FOREACH(QTextLayout *l, d->textLayouts) {
+ const int textSize = l->text().size();
+ const QRect r = l->boundingRect().toRect();
+ if (r.intersects(er)) {
+
+ const int lineNum=lineNumber(textLayoutOffset)+1;
+ maxLineNum=lineNum;
+ QRect lRect(0,r.y(),numWidth,r.height());
+
+ // is this the current line?
+ if(cursorPos >= textLayoutOffset && cursorPos <= textLayoutOffset+l->text().size())
+ {
+ painter.setFont(fontBold);
+ painter.fillRect(lRect, lineNumArea_->currentColour()); // highlight the background
+ painter.drawText(lRect,QString::number(lineNum),Qt::AlignRight|Qt::AlignVCenter);
+ painter.setFont(fontNormal);
+ }
+ else
+ {
+ painter.drawText(lRect,QString::number(lineNum),Qt::AlignRight|Qt::AlignVCenter);
+ }
+
+ } else if (r.top() > er.bottom()) {
+ break;
+ }
+ textLayoutOffset += textSize + 1;
+ }
+
+ if(maxLineNum != -1)
+ lineNumArea_->updateWidth(maxLineNum);
+}
+
+//==========================================================================
+//
+// TextPagerLineNumberArea
+//
+//==========================================================================
+
+TextPagerLineNumberArea::TextPagerLineNumberArea(TextPagerEdit *editor) :
+ QWidget(editor), textEditor_ (editor), digits_(6), rightMargin_(3),
+ bgCol_(232,231,230), fontCol_(220,220,200), separatorCol_(220,220,200),
+ currentCol_(212,212,255)
+{
+ Q_ASSERT(textEditor_);
+
+ if(VProperty* p=VConfig::instance()->find("view.textEdit.numAreaBackground"))
+ bgCol_=p->value().value<QColor>();
+
+ if(VProperty* p=VConfig::instance()->find("view.textEdit.numAreaFontColour"))
+ fontCol_=p->value().value<QColor>();
+
+ if(VProperty* p=VConfig::instance()->find("view.textEdit.numAreaSeparator"))
+ separatorCol_=p->value().value<QColor>();
+
+ if(VProperty* p=VConfig::instance()->find("view.textEdit.numAreaCurrent"))
+ currentCol_=p->value().value<QColor>();
+
+ editor->setLineNumberArea(this);
+}
+
+void TextPagerLineNumberArea::updateWidth(int maxLineNum)
+{
+ if(maxLineNum == -1 || pow(10,digits_)-1 < maxLineNum)
+ {
+ setFixedWidth(computeWidth(maxLineNum));
+ }
+}
+
+int TextPagerLineNumberArea::computeWidth(int maxLineNum) const
+{
+ if(maxLineNum > 0)
+ {
+ int maxDigits=1;
+ int mx = maxLineNum;
+ while ( mx >= 10)
+ {
+ mx /= 10;
+ ++maxDigits;
+ }
+
+ if(maxDigits > digits_)
+ digits_=maxDigits;
+ }
+
+ return (textEditor_)?(3 + textEditor_->fontMetrics().width(QLatin1Char('9')) * digits_ + rightMargin_):3+rightMargin_;
+
+}
+
+
+
+
diff --git a/Viewer/src/TextPager/TextPagerEdit.hpp b/Viewer/src/TextPager/TextPagerEdit.hpp
new file mode 100644
index 0000000..1c6f3dc
--- /dev/null
+++ b/Viewer/src/TextPager/TextPagerEdit.hpp
@@ -0,0 +1,226 @@
+// Copyright 2010 Anders Bakken
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef TEXTPAGEREDIT_HPP__
+#define TEXTPAGEREDIT_HPP__
+
+#include <QtGui>
+#include <QAbstractScrollArea>
+
+#include "syntaxhighlighter.hpp"
+#include "TextPagerDocument.hpp"
+#include "TextPagerCursor.hpp"
+#include "TextPagerSection.hpp"
+
+#include "VProperty.hpp"
+
+class TextPagerLineNumberArea;
+class TextEditPrivate;
+class TextPagerSearchHighlighter;
+
+class TextPagerEdit : public QAbstractScrollArea, public VPropertyObserver
+{
+ friend class TextPagerLineNumberArea;
+
+ Q_OBJECT
+ Q_PROPERTY(int cursorWidth READ cursorWidth WRITE setCursorWidth)
+ Q_PROPERTY(bool readOnly READ readOnly WRITE setReadOnly)
+ Q_PROPERTY(bool cursorVisible READ cursorVisible WRITE setCursorVisible)
+ Q_PROPERTY(QString selectedText READ selectedText)
+ Q_PROPERTY(int maximumSizeCopy READ maximumSizeCopy WRITE setMaximumSizeCopy)
+ Q_PROPERTY(bool lineBreaking READ lineBreaking WRITE setLineBreaking)
+
+public:
+ TextPagerEdit(QWidget *parent = 0);
+ ~TextPagerEdit();
+
+ TextPagerDocument *document() const;
+ void setDocument(TextPagerDocument *doc);
+
+ int cursorWidth() const;
+ void setCursorWidth(int cc);
+
+ struct ExtraSelection
+ {
+ TextPagerCursor cursor;
+ QTextCharFormat format;
+ };
+
+ void setExtraSelections(const QList<ExtraSelection> &selections);
+ QList<ExtraSelection> extraSelections() const;
+
+ void setSyntaxHighlighter(SyntaxHighlighter *h);
+ inline SyntaxHighlighter *syntaxHighlighter() const { return syntaxHighlighters().value(0); }
+
+ QList<SyntaxHighlighter*> syntaxHighlighters() const;
+ void addSyntaxHighlighter(SyntaxHighlighter *highlighter);
+ void takeSyntaxHighlighter(SyntaxHighlighter *highlighter);
+ void removeSyntaxHighlighter(SyntaxHighlighter *highlighter);
+ void clearSyntaxHighlighters();
+
+ //bool load(QIODevice *device, TextPagerDocument::DeviceMode mode = TextPagerDocument::Sparse, QTextCodec *codec = 0);
+
+ bool load(const QString &fileName, TextPagerDocument::DeviceMode mode = TextPagerDocument::Sparse, QTextCodec *codec = 0);
+
+ void paintEvent(QPaintEvent *e);
+ void scrollContentsBy(int dx, int dy);
+
+ bool moveCursorPosition(TextPagerCursor::MoveOperation op, TextPagerCursor::MoveMode = TextPagerCursor::MoveAnchor, int n = 1);
+ void setCursorPosition(int pos, TextPagerCursor::MoveMode mode = TextPagerCursor::MoveAnchor);
+
+ int viewportPosition() const;
+ int cursorPosition() const;
+
+ int textPositionAt(const QPoint &pos) const;
+
+ bool readOnly() const;
+ void setReadOnly(bool rr);
+
+ bool lineBreaking() const;
+ void setLineBreaking(bool lb);
+
+ int maximumSizeCopy() const;
+ void setMaximumSizeCopy(int max);
+
+ QRect cursorBlockRect(const TextPagerCursor &cursor) const;
+ QRect cursorRect(const TextPagerCursor &cursor) const;
+
+ int lineNumber(int position) const;
+ int columnNumber(int position) const;
+ int lineNumber(const TextPagerCursor &cursor) const;
+ int columnNumber(const TextPagerCursor &cursor) const;
+
+ bool cursorVisible() const;
+ void setCursorVisible(bool cc);
+
+ QString selectedText() const;
+ bool hasSelection() const;
+
+ void setText(const QString &text);
+ QString read(int pos, int size) const;
+ QChar readCharacter(int index) const;
+
+ void insert(int pos, const QString &text);
+ void remove(int from, int size);
+
+ TextPagerCursor &textCursor();
+ const TextPagerCursor &textCursor() const;
+ void setTextCursor(const TextPagerCursor &textCursor);
+
+ TextPagerCursor cursorForPosition(const QPoint &pos) const;
+
+ TextPagerSection *sectionAt(const QPoint &pos) const;
+
+ QList<TextPagerSection*> sections(int from = 0, int size = -1, TextPagerSection::TextSectionOptions opt = 0) const;
+ inline TextPagerSection *sectionAt(int pos) const { return sections(pos, 1, TextPagerSection::IncludePartial).value(0); }
+ TextPagerSection *insertTextSection(int pos, int size, const QTextCharFormat &format = QTextCharFormat(),
+ const QVariant &data = QVariant());
+
+ void ensureCursorVisible(const TextPagerCursor &cursor, int linesMargin = 0);
+
+ void setEnableSearchHighlighter(bool);
+ void clearSearchHighlighter();
+ void setSearchHighlighter(QString txt,TextPagerDocument::FindMode mode);
+ void setSearchHighlighter(QRegExp rx,TextPagerDocument::FindMode mode);
+
+ void gotoLine(int);
+ void setFontProperty(VProperty* p);
+ void notifyChange(VProperty* p);
+ void zoomIn();
+ void zoomOut();
+
+ void setLineNumberArea(TextPagerLineNumberArea *a);
+
+ enum ActionType {
+ CopyAction,
+ SelectAllAction
+ };
+ QAction *action(ActionType type) const;
+
+public Q_SLOTS:
+ void ensureCursorVisible();
+ void copy(QClipboard::Mode mode = QClipboard::Clipboard);
+ void selectAll();
+ void clearSelection();
+
+Q_SIGNALS:
+ void copyAvailable(bool on);
+ void textChanged();
+ void selectionChanged();
+ void cursorPositionChanged(int pos);
+ void sectionClicked(TextPagerSection *section, const QPoint &pos);
+
+protected:
+ //virtual void paste(int position, QClipboard::Mode mode);
+ virtual void changeEvent(QEvent *e);
+ virtual void keyPressEvent(QKeyEvent *e);
+ virtual void keyReleaseEvent(QKeyEvent *e);
+ virtual void wheelEvent(QWheelEvent *e);
+ virtual void mousePressEvent(QMouseEvent *e);
+ virtual void mouseDoubleClickEvent(QMouseEvent *);
+ virtual void mouseMoveEvent(QMouseEvent *e);
+ virtual void mouseReleaseEvent(QMouseEvent *e);
+ virtual void resizeEvent(QResizeEvent *e);
+
+private:
+ void updateFont();
+ void fontSizeChangedByZoom();
+
+ void lineNumberAreaPaintEvent(QPaintEvent *e);
+ int lineNumberAreaWidth();
+ void updateLineNumberArea();
+
+ TextEditPrivate *d;
+ friend class TextLayoutCacheManager;
+ friend class TextEditPrivate;
+ friend class TextPagerCursor;
+
+ TextPagerSearchHighlighter* searchHighlight_;
+ bool useSearchHighlight_;
+
+ TextPagerLineNumberArea* lineNumArea_;
+ VProperty* fontProp_;
+};
+
+
+class TextPagerLineNumberArea : public QWidget
+{
+public:
+ explicit TextPagerLineNumberArea(TextPagerEdit *editor);
+ QSize sizeHint() const {return QSize(computeWidth(), 0);}
+ int rightMargin() const {return rightMargin_;}
+ void updateWidth(int maxLineNum=-1);
+ QColor bgColour() const {return bgCol_;}
+ QColor fontColour() const {return fontCol_;}
+ QColor separatorColour() const {return separatorCol_;}
+ QColor currentColour() const {return currentCol_;}
+
+protected:
+ void paintEvent(QPaintEvent *event) { textEditor_->lineNumberAreaPaintEvent(event);}
+
+private:
+ int computeWidth(int maxLineNum=-1) const;
+
+ TextPagerEdit *textEditor_;
+ mutable int digits_;
+ int rightMargin_;
+ QColor bgCol_;
+ QColor fontCol_;
+ QColor separatorCol_;
+ QColor currentCol_;
+};
+
+
+
+#endif
diff --git a/Viewer/src/TextPager/TextPagerEdit_p.hpp b/Viewer/src/TextPager/TextPagerEdit_p.hpp
new file mode 100644
index 0000000..e699a7d
--- /dev/null
+++ b/Viewer/src/TextPager/TextPagerEdit_p.hpp
@@ -0,0 +1,146 @@
+// Copyright 2010 Anders Bakken
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef TEXTPAGEREDIT_P_HPP__
+#define TEXTPAGEREDIT_P_HPP__
+
+#include <QBasicTimer>
+#include <QPoint>
+#include <QAction>
+#include <QScrollArea>
+#include <QScrollBar>
+#include "TextPagerLayout_p.hpp"
+#include "TextPagerDocument_p.hpp"
+#include "TextPagerCursor.hpp"
+#include "TextPagerEdit.hpp"
+
+struct DocumentCommand;
+struct CursorData {
+ int position, anchor;
+};
+
+struct LastPageCache {
+ LastPageCache() : position(-1),height(-1),widest(-1), documentSize(-1) {}
+ void clear() {position=-1; height=-1; widest=-1; documentSize=-1;}
+ int position;
+ int height;
+ int widest;
+ int documentSize;
+};
+
+class TextEditPrivate : public QObject, public TextPagerLayout
+{
+ Q_OBJECT
+public:
+ TextEditPrivate(TextPagerEdit *qptr)
+ : requestedScrollBarPosition(-1), lastRequestedScrollBarPosition(-1), cursorWidth(2),
+ sectionCount(0), maximumSizeCopy(50000), pendingTimeOut(-1), autoScrollLines(0),
+ readOnly(true), cursorVisible(false), blockScrollBarUpdate(false),
+ updateScrollBarPageStepPending(true), inMouseEvent(false), sectionPressed(0),
+ pendingScrollBarUpdate(false), sectionCursor(0)
+ {
+ textEdit = qptr;
+ }
+
+ bool canInsertFromMimeData(const QMimeData *data) const;
+ void updateHorizontalPosition();
+ void updateScrollBarPosition();
+ void updateScrollBarPageStep();
+ void scrollLines(int lines);
+ void timerEvent(QTimerEvent *e);
+ void updateCursorPosition(const QPoint &pos);
+ int findLastPageSize() const;
+ bool atBeginning() const { return viewportPosition == 0; }
+ bool atEnd() const { return textEdit->verticalScrollBar()->value() == textEdit->verticalScrollBar()->maximum(); }
+ bool dirtyForSection(TextPagerSection *section);
+ void updateCopyAndCutEnabled();
+ bool isSectionOnScreen(const TextPagerSection *section) const;
+ void cursorMoveKeyEventReadOnly(QKeyEvent *e);
+ virtual void relayout(); // from TextPagerLayout
+ void adjustVerticalScrollBar();
+
+ int requestedScrollBarPosition, lastRequestedScrollBarPosition, cursorWidth, sectionCount,
+ maximumSizeCopy, pendingTimeOut, autoScrollLines;
+ bool readOnly, cursorVisible, blockScrollBarUpdate, updateScrollBarPageStepPending, inMouseEvent;
+ QBasicTimer autoScrollTimer, cursorBlinkTimer;
+ QAction *actions[TextPagerEdit::SelectAllAction];
+ TextPagerSection *sectionPressed;
+ TextPagerCursor textCursor, dragOverrideCursor;
+ QBasicTimer tripleClickTimer;
+ bool pendingScrollBarUpdate;
+ QCursor *sectionCursor;
+ QPoint lastHoverPos, lastMouseMove;
+ QHash<DocumentCommand *, QPair<CursorData, CursorData> > undoRedoCommands;
+ mutable LastPageCache lastPage;
+
+public Q_SLOTS:
+ void onSyntaxHighlighterDestroyed(QObject *o);
+ void onSelectionChanged();
+ void onTextSectionAdded(TextPagerSection *section);
+ void onTextSectionRemoved(TextPagerSection *section);
+ void onTextSectionFormatChanged(TextPagerSection *section);
+ void onTextSectionCursorChanged(TextPagerSection *section);
+ void updateScrollBar();
+ void onDocumentDestroyed();
+ void onDocumentSizeChanged(int size);
+
+#if 0
+ void onDocumentCommandInserted(DocumentCommand *cmd);
+ void onDocumentCommandFinished(DocumentCommand *cmd);
+ void onDocumentCommandRemoved(DocumentCommand *cmd);
+ void onDocumentCommandTriggered(DocumentCommand *cmd, bool undo);
+#endif
+
+
+ void onScrollBarValueChanged(int value);
+ void onScrollBarActionTriggered(int action);
+ void onCharactersAddedOrRemoved(int index, int count);
+
+Q_SIGNALS:
+ void scrollBarChanged();
+};
+
+/*
+class DebugWindow : public QWidget
+{
+public:
+ DebugWindow(TextEditPrivate *p)
+ : priv(p)
+ {
+ }
+
+ void paintEvent(QPaintEvent *)
+ {
+ if (priv->lines.isEmpty())
+ return;
+
+ QPainter p(this);
+ p.fillRect(QRect(0, pixels(priv->viewportPosition), width(),
+ pixels(priv->lines.last().first +
+ priv->lines.last().second.textLength())),
+ Qt::black);
+ p.fillRect(QRect(0, pixels(priv->viewportPosition), width(), pixels(priv->layoutEnd)), Qt::red);
+ }
+
+ int pixels(int pos) const
+ {
+ double fraction = double(pos) / double(priv->document->documentSize());
+ return int(double(height()) * fraction);
+ }
+private:
+ TextEditPrivate *priv;
+};
+*/
+
+#endif
diff --git a/Viewer/src/TextPager/TextPagerLayout_p.cpp b/Viewer/src/TextPager/TextPagerLayout_p.cpp
new file mode 100644
index 0000000..52f7ca9
--- /dev/null
+++ b/Viewer/src/TextPager/TextPagerLayout_p.cpp
@@ -0,0 +1,454 @@
+// Copyright 2010 Anders Bakken
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "TextPagerLayout_p.hpp"
+#include "TextPagerEdit_p.hpp"
+#include "TextPagerDocument.hpp"
+#include "TextPagerEdit.hpp"
+
+int TextPagerLayout::viewportWidth() const
+{
+ if (!lineBreaking)
+ return INT_MAX - 1024;
+ return textEdit ? textEdit->viewport()->width() : viewport;
+}
+
+int TextPagerLayout::doLayout(int index, QList<TextPagerSection*> *sections) // index is in document coordinates
+{
+ QTextLayout *textLayout = 0;
+ if (!unusedTextLayouts.isEmpty()) {
+ textLayout = unusedTextLayouts.takeLast();
+ textLayout->clearAdditionalFormats();
+ } else {
+ textLayout = new QTextLayout;
+ textLayout->setCacheEnabled(true);
+ textLayout->setFont(font);
+ QTextOption option;
+ option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
+ textLayout->setTextOption(option);
+ }
+ textLayouts.append(textLayout);
+ if (index != 0 && bufferReadCharacter(index - 1) != '\n') {
+ qWarning() << index << viewportPosition << document->read(index - 1, 20)
+ << bufferReadCharacter(index - 1);
+ }
+ Q_ASSERT(index == 0 || bufferReadCharacter(index - 1) == '\n');
+ const int max = bufferPosition + buffer.size();
+ const int lineStart = index;
+ while (index < max && bufferReadCharacter(index) != '\n')
+ ++index;
+
+ const QString string = buffer.mid(lineStart - bufferPosition, index - lineStart);
+ Q_ASSERT(string.size() == index - lineStart);
+ Q_ASSERT(!string.contains('\n'));
+ if (index < max)
+ ++index; // for the newline
+ textLayout->setText(string);
+
+ QMultiMap<int, QTextLayout::FormatRange> formatMap;
+ if (sections) {
+ do {
+ Q_ASSERT(!sections->isEmpty());
+ TextPagerSection *l = sections->first();
+ Q_ASSERT(::matchSection(l, textEdit));
+ Q_ASSERT(l->position() + l->size() >= lineStart);
+ if (l->position() >= index) {
+ break;
+ }
+ // section is in this QTextLayout
+ QTextLayout::FormatRange range;
+ range.start = qMax(0, l->position() - lineStart); // offset in QTextLayout
+ range.length = qMin(l->position() + l->size(), index) - lineStart - range.start;
+ range.format = l->format();
+ formatMap.insertMulti(l->priority(), range);
+ if (l->position() + l->size() >= index) { // > ### ???
+ // means section didn't end here. It continues in the next QTextLayout
+ break;
+ }
+ sections->removeFirst();
+ } while (!sections->isEmpty());
+ }
+ QList<QTextLayout::FormatRange> formats = formatMap.values();
+
+ int leftMargin = LeftMargin;
+ int rightMargin = 0;
+ int topMargin = 0;
+ int bottomMargin = 0;
+ Q_FOREACH(SyntaxHighlighter *syntaxHighlighter, syntaxHighlighters) {
+ syntaxHighlighter->d->currentBlockPosition = lineStart;
+ syntaxHighlighter->d->formatRanges.clear();
+ syntaxHighlighter->d->currentBlock = string;
+ syntaxHighlighter->highlightBlock(string);
+ syntaxHighlighter->d->currentBlock.clear();
+ if (syntaxHighlighter->d->blockFormat.isValid()) {
+ blockFormats[textLayout] = syntaxHighlighter->d->blockFormat;
+ if (syntaxHighlighter->d->blockFormat.hasProperty(QTextFormat::BlockLeftMargin))
+ leftMargin = syntaxHighlighter->d->blockFormat.leftMargin();
+ if (syntaxHighlighter->d->blockFormat.hasProperty(QTextFormat::BlockRightMargin))
+ rightMargin = syntaxHighlighter->d->blockFormat.rightMargin();
+ if (syntaxHighlighter->d->blockFormat.hasProperty(QTextFormat::BlockTopMargin))
+ topMargin = syntaxHighlighter->d->blockFormat.topMargin();
+ if (syntaxHighlighter->d->blockFormat.hasProperty(QTextFormat::BlockBottomMargin))
+ bottomMargin = syntaxHighlighter->d->blockFormat.bottomMargin();
+
+ }
+ syntaxHighlighter->d->previousBlockState = syntaxHighlighter->d->currentBlockState;
+ if (!syntaxHighlighter->d->formatRanges.isEmpty())
+ formats += syntaxHighlighter->d->formatRanges;
+ }
+ textLayout->setAdditionalFormats(formats);
+ textLayout->beginLayout();
+ const int lineWidth = viewportWidth() - (leftMargin + rightMargin);
+
+ int localWidest = -1;
+ Q_FOREVER {
+ QTextLine line = textLayout->createLine();
+ if (!line.isValid()) {
+ break;
+ }
+ line.setLineWidth(lineWidth);
+ if (!lineBreaking)
+ localWidest = qMax<int>(localWidest, line.naturalTextWidth() + (LeftMargin * 2));
+ // ### support blockformat margins etc
+ int y = topMargin + lastBottomMargin;
+ if (!lines.isEmpty()) {
+ y += int(lines.last().second.rect().bottom());
+ // QTextLine doesn't seem to get its rect() update until a
+ // new line has been created (or presumably in endLayout)
+ }
+ line.setPosition(QPoint(leftMargin, y));
+ lines.append(qMakePair(lineStart + line.textStart(), line));
+ }
+
+ widest = qMax(widest, localWidest);
+ lastBottomMargin = bottomMargin;
+
+ textLayout->endLayout();
+#ifndef QT_NO_DEBUG
+ for (int i=1; i<lines.size(); ++i) {
+ Q_ASSERT(lines.at(i).first - (lines.at(i - 1).first + lines.at(i - 1).second.textLength()) <= 1);
+ }
+#endif
+
+
+ QRect r = textLayout->boundingRect().toRect();
+ // this will actually take the entire width set in setLineWidth
+ // and not what it actually uses.
+ r.setWidth(localWidest);
+
+ contentRect |= r;
+ Q_ASSERT(!lineBreaking || contentRect.right() <= qint64(viewportWidth()) + LeftMargin
+ || viewportWidth() == -1);
+
+ Q_FOREACH(SyntaxHighlighter *syntaxHighlighter, syntaxHighlighters) {
+ syntaxHighlighter->d->formatRanges.clear();
+ syntaxHighlighter->d->blockFormat = QTextBlockFormat();
+ syntaxHighlighter->d->currentBlockPosition = -1;
+ }
+
+ return index;
+}
+
+int TextPagerLayout::textPositionAt(const QPoint &p) const
+{
+ QPoint pos = p;
+ if (pos.x() >= 0 && pos.x() < LeftMargin)
+ pos.rx() = LeftMargin; // clicking in the margin area should count as the first characters
+
+ int textLayoutOffset = viewportPosition;
+ Q_FOREACH(const QTextLayout *l, textLayouts) {
+ if(l->boundingRect().y() <= pos.y() && l->boundingRect().bottom() >=pos.y()) {
+ //if (l->boundingRect().toRect().contains(pos)) {
+ const int lineCount = l->lineCount();
+ for (int i=0; i<lineCount; ++i) {
+ const QTextLine line = l->lineAt(i);
+ if (line.y() <= pos.y() && pos.y() <= line.height() + line.y()) { // ### < ???
+ {
+ if(pos.x() > l->boundingRect().right())
+ pos.setX(l->boundingRect().right()-1);
+
+ return textLayoutOffset + line.xToCursor(qMax<int>(LeftMargin, pos.x()));
+ }
+ }
+ }
+ }
+ textLayoutOffset += l->text().size() + 1; // + 1 for newlines which aren't in the QTextLayout
+ }
+ return -1;
+}
+
+QList<TextPagerSection*> TextPagerLayout::relayoutCommon()
+{
+// widest = -1; // ### should this be relative to current content or remember? What if you remove the line that was the widest?
+ Q_ASSERT(layoutDirty);
+ layoutDirty = false;
+ Q_ASSERT(document);
+ lines.clear();
+ unusedTextLayouts = textLayouts;
+ textLayouts.clear();
+ contentRect = QRect();
+ visibleLines = lastVisibleCharacter = -1;
+
+ Q_FOREACH(SyntaxHighlighter *syntaxHighlighter, syntaxHighlighters) {
+ syntaxHighlighter->d->previousBlockState = syntaxHighlighter->d->currentBlockState = -1;
+ }
+
+ if (viewportPosition < bufferPosition
+ || (bufferPosition + buffer.size() < document->documentSize()
+ && buffer.size() - bufferOffset() < MinimumBufferSize)) {
+ bufferPosition = qMax(0, viewportPosition - MinimumBufferSize);
+ buffer = document->read(bufferPosition, int(MinimumBufferSize * 2.5));
+ sections = document->d->getSections(bufferPosition, buffer.size(), TextPagerSection::IncludePartial, textEdit);
+ } else if (sectionsDirty) {
+ sections = document->d->getSections(bufferPosition, buffer.size(), TextPagerSection::IncludePartial, textEdit);
+ }
+ sectionsDirty = false;
+ QList<TextPagerSection*> l = sections;
+ while (!l.isEmpty() && l.first()->position() + l.first()->size() < viewportPosition)
+ l.takeFirst(); // could cache these as well
+ return l;
+}
+
+void TextPagerLayout::relayoutByGeometry(int height)
+{
+ if (!layoutDirty)
+ return;
+
+ QList<TextPagerSection*> l = relayoutCommon();
+
+ const int max = viewportPosition + buffer.size() - bufferOffset(); // in document coordinates
+ ASSUME(viewportPosition == 0 || bufferReadCharacter(viewportPosition - 1) == '\n');
+
+ static const int extraLines = qMax(2, qgetenv("LAZYTEXTEDIT_EXTRA_LINES").toInt());
+ int index = viewportPosition;
+ while (index < max) {
+ index = doLayout(index, l.isEmpty() ? 0 : &l);
+ Q_ASSERT(index == max || document->readCharacter(index - 1) == '\n');
+ Q_ASSERT(!textLayouts.isEmpty());
+ const int y = int(textLayouts.last()->boundingRect().bottom());
+ if (y >= height) {
+ if (visibleLines == -1) {
+ visibleLines = lines.size();
+ lastVisibleCharacter = index;
+ } else if (lines.size() >= visibleLines + extraLines) {
+ break;
+ }
+ }
+ }
+ if (visibleLines == -1) {
+ visibleLines = lines.size();
+ lastVisibleCharacter = index;
+ }
+
+
+ layoutEnd = qMin(index, max);
+ qDeleteAll(unusedTextLayouts);
+ unusedTextLayouts.clear();
+ Q_ASSERT(viewportPosition < layoutEnd ||
+ (viewportPosition == layoutEnd && viewportPosition == document->documentSize()));
+// qDebug() << "layoutEnd" << layoutEnd << "viewportPosition" << viewportPosition;
+}
+
+void TextPagerLayout::relayoutByPosition(int size)
+{
+ if (!layoutDirty)
+ return;
+
+ QList<TextPagerSection*> l = relayoutCommon();
+
+ const int max = viewportPosition + qMin(size, buffer.size() - bufferOffset());
+ Q_ASSERT(viewportPosition == 0 || bufferReadCharacter(viewportPosition - 1) == '\n');
+ int index = viewportPosition;
+ while (index < max) {
+ index = doLayout(index, l.isEmpty() ? 0 : &l);
+ }
+ layoutEnd = index;
+
+ qDeleteAll(unusedTextLayouts);
+ unusedTextLayouts.clear();
+ Q_ASSERT(viewportPosition < layoutEnd ||
+ (viewportPosition == layoutEnd && viewportPosition == document->documentSize()));
+}
+
+void TextPagerLayout::relayout()
+{
+ //relayoutByPosition(2000); // ### totally arbitrary number
+ relayoutByPosition(1.5*MinimumBufferSize);
+}
+
+QTextLayout *TextPagerLayout::layoutForPosition(int pos, int *offset, int *index) const
+{
+ if (offset)
+ *offset = -1;
+ if (index)
+ *index = -1;
+
+ if (textLayouts.isEmpty() || pos < viewportPosition || pos > layoutEnd) {
+ return 0;
+ }
+
+ int textLayoutOffset = viewportPosition;
+ int i = 0;
+
+ Q_FOREACH(QTextLayout *l, textLayouts) {
+ if (pos >= textLayoutOffset && pos <= l->text().size() + textLayoutOffset) {
+ if (offset)
+ *offset = pos - textLayoutOffset;
+ if (index)
+ *index = i;
+ return l;
+ }
+ ++i;
+ textLayoutOffset += l->text().size() + 1;
+ }
+ return 0;
+}
+
+QTextLine TextPagerLayout::lineForPosition(int pos, int *offsetInLine, int *lineIndex, bool *lastLine) const
+{
+ if (offsetInLine)
+ *offsetInLine = -1;
+ if (lineIndex)
+ *lineIndex = -1;
+ if (lastLine)
+ *lastLine = false;
+
+ if (pos < viewportPosition || pos >= layoutEnd || textLayouts.isEmpty() || lines.isEmpty()) {
+ return QTextLine();
+ }
+ int layoutIndex = 0;
+ QTextLayout *layout = textLayouts.value(layoutIndex);
+ Q_ASSERT(layout);
+ for (int i=0; i<lines.size(); ++i) {
+ const QPair<int, QTextLine> &line = lines.at(i);
+ int lineEnd = line.first + line.second.textLength();
+ const bool last = line.second.lineNumber() + 1 == layout->lineCount();
+ if (last) {
+ ++lineEnd;
+ // 1 is for newline characters
+ layout = textLayouts.value(++layoutIndex);
+ // could be 0
+ }
+ if (pos < lineEnd) {
+ if (offsetInLine) {
+ *offsetInLine = pos - line.first;
+ Q_ASSERT(*offsetInLine >= 0);
+ Q_ASSERT(*offsetInLine < lineEnd + pos);
+ }
+ if (lineIndex) {
+ *lineIndex = i;
+ }
+ if (lastLine)
+ *lastLine = last;
+ return line.second;
+ } else if (!layout) {
+ break;
+ }
+ }
+ qWarning() << "Couldn't find a line for" << pos << "viewportPosition" << viewportPosition
+ << "layoutEnd" << layoutEnd;
+ Q_ASSERT(0);
+ return QTextLine();
+}
+
+// pos is not necessarily on a newline. Finds closest newline in the
+// right direction and sets viewportPosition to that. Updates
+// scrollbars if this is a TextEditPrivate
+
+void TextPagerLayout::updateViewportPosition(int pos, Direction direction,bool applyIt)
+{
+ pos = qMin(pos, maxViewportPosition);
+ if (document->documentSize() == 0) {
+ viewportPosition = 0;
+ } else {
+ Q_ASSERT(document->documentSize() > 0);
+ int index = document->find('\n', qMax(0, pos + (direction == Backward ? -1 : 0)),
+ TextPagerDocument::FindMode(direction)).anchor();
+ if (index == -1) {
+ if (direction == Backward) {
+ index = 0;
+ } else {
+ index = qMax(0, document->find('\n', document->documentSize() - 1, TextPagerDocument::FindBackward).position());
+ // position after last newline in document
+ // if there is no newline put it at 0
+ }
+ } else {
+ ++index;
+ }
+ Q_ASSERT(index != -1);
+ viewportPosition = index;
+
+ if (viewportPosition != 0 && document->read(viewportPosition - 1, 1) != QString("\n"))
+ qWarning() << "viewportPosition" << viewportPosition << document->read(viewportPosition - 1, 10) << this;
+ ASSUME(viewportPosition == 0 || document->read(viewportPosition - 1, 1) == QString("\n"));
+ }
+ if (viewportPosition > maxViewportPosition && direction == Forward) {
+ updateViewportPosition(viewportPosition, Backward);
+ return;
+ }
+ layoutDirty = true;
+
+ if(applyIt) {
+
+ if (textEdit && !suppressTextEditUpdates) {
+ textEdit->viewport()->update();
+ TextEditPrivate *p = static_cast<TextEditPrivate*>(this);
+ p->pendingScrollBarUpdate = true;
+ p->updateCursorPosition(p->lastHoverPos);
+ if (!textEdit->verticalScrollBar()->isSliderDown()) {
+ p->updateScrollBar();
+ } // sliderReleased is connected to updateScrollBar()
+ }
+
+ relayout();
+ }
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug &operator<<(QDebug &str, const QTextLine &line)
+{
+ if (!line.isValid()) {
+ str << "QTextLine() (invalid)";
+ return str;
+ }
+ str.space() << "lineNumber" << line.lineNumber()
+ << "textStart" << line.textStart()
+ << "textLength" << line.textLength()
+ << "position" << line.position();
+ return str;
+}
+
+QString TextPagerLayout::dump() const
+{
+ QString out;
+ QTextStream ts(&out, QIODevice::WriteOnly);
+ ts << "viewportPosition " << viewportPosition
+ << " layoutEnd " << layoutEnd
+ << " viewportWidth " << viewportWidth() << '\n';
+ for (int i=0; i<textLayouts.size(); ++i) {
+ QTextLayout *layout = textLayouts.at(i);
+ for (int j=0; j<layout->lineCount(); ++j) {
+ QTextLine line = layout->lineAt(j);
+ ts << layout->text().mid(line.textStart(), line.textLength());
+ if (j + 1 < layout->lineCount()) {
+ ts << "<linebreak>\n";
+ } else {
+ ts << "\n";
+ }
+ }
+ }
+ return out;
+}
+
+#endif
diff --git a/Viewer/src/TextPager/TextPagerLayout_p.hpp b/Viewer/src/TextPager/TextPagerLayout_p.hpp
new file mode 100644
index 0000000..da2e665
--- /dev/null
+++ b/Viewer/src/TextPager/TextPagerLayout_p.hpp
@@ -0,0 +1,125 @@
+// Copyright 2010 Anders Bakken
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef TEXTPAGERLAYOUT_P_HPP_
+#define TEXTPAGERLAYOUT_P_HPP_
+
+#include <QList>
+#include <QTextLayout>
+#include <QRect>
+#include <QString>
+#include <QSize>
+#include <QTextLine>
+#include <QKeyEvent>
+#ifndef QT_NO_DEBUG_STREAM
+#include <QDebug>
+#endif
+#include "TextPagerDocument.hpp"
+#include "TextPagerEdit.hpp"
+#include "syntaxhighlighter.hpp"
+#include "WeakPointer.hpp"
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug &operator<<(QDebug &str, const QTextLine &line);
+#endif
+
+class TextDocumentBuffer
+{
+public:
+ TextDocumentBuffer(TextPagerDocument *doc) : document(doc), bufferPosition(0) {}
+ virtual ~TextDocumentBuffer() {}
+
+ inline QString bufferRead(int from, int size) const
+ {
+ Q_ASSERT(document);
+ if (from < bufferPosition || from + size > bufferPosition + buffer.size()) {
+ return document->read(from, size);
+ }
+ return buffer.mid(from - bufferPosition, size);
+ }
+ inline QChar bufferReadCharacter(int index) const // document coordinates
+ {
+ Q_ASSERT(document);
+ if (index >= bufferPosition && index < bufferPosition + buffer.size()) {
+ return buffer.at(index - bufferPosition);
+ } else {
+ Q_ASSERT(index >= 0 && index < document->documentSize()); // what if index == documentSize?
+ return document->readCharacter(index);
+ }
+ }
+
+ TextPagerDocument *document;
+ int bufferPosition;
+ QString buffer;
+};
+
+class TextPagerEdit;
+class TextPagerLayout : public TextDocumentBuffer
+{
+public:
+ enum { MinimumBufferSize = 90000, LeftMargin = 3 };
+ TextPagerLayout(TextPagerDocument *doc = 0)
+ : TextDocumentBuffer(doc), textEdit(0),
+ viewportPosition(0), layoutEnd(-1), viewport(-1),
+ visibleLines(-1), lastVisibleCharacter(-1), lastBottomMargin(0),
+ widest(-1), maxViewportPosition(0), layoutDirty(true), sectionsDirty(true),
+ lineBreaking(false), suppressTextEditUpdates(false)
+ {
+ }
+
+ virtual ~TextPagerLayout()
+ {
+ qDeleteAll(textLayouts);
+ qDeleteAll(unusedTextLayouts);
+ }
+
+ TextPagerEdit *textEdit;
+ QList<SyntaxHighlighter*> syntaxHighlighters;
+ int viewportPosition, layoutEnd, viewport, visibleLines,
+ lastVisibleCharacter, lastBottomMargin, widest, maxViewportPosition;
+ bool layoutDirty, sectionsDirty, lineBreaking, suppressTextEditUpdates;
+ QList<QTextLayout*> textLayouts, unusedTextLayouts;
+ QHash<QTextLayout*, QTextBlockFormat> blockFormats;
+ QList<TextPagerEdit::ExtraSelection> extraSelections;
+ QList<QPair<int, QTextLine> > lines; // int is start position of line in document coordinates
+ QRect contentRect; // contentRect means the laid out area, not just the area currently visible
+ QList<TextPagerSection*> sections; // these are all the sections in the buffer. Some might be before the current viewport
+ QFont font;
+
+ QList<TextPagerSection*> relayoutCommon(); // should maybe be smarter about MinimumScreenSize. Detect it based on font and viewport size
+ void relayoutByPosition(int size);
+ void relayoutByGeometry(int height);
+ virtual void relayout();
+
+ int viewportWidth() const;
+
+ int doLayout(int index, QList<TextPagerSection*> *sections);
+
+ QTextLine lineForPosition(int pos, int *offsetInLine = 0,
+ int *lineIndex = 0, bool *lastLine = 0) const;
+ QTextLayout *layoutForPosition(int pos, int *offset = 0, int *index = 0) const;
+
+ int textPositionAt(const QPoint &pos) const;
+ inline int bufferOffset() const { return viewportPosition - bufferPosition; }
+
+ QString dump() const;
+
+ enum Direction {
+ Forward = 0,
+ Backward = TextPagerDocument::FindBackward
+ };
+ void updateViewportPosition(int pos, Direction direction,bool applyIt=true);
+};
+
+#endif
diff --git a/Viewer/src/TextPager/TextPagerSearchHighlighter.cpp b/Viewer/src/TextPager/TextPagerSearchHighlighter.cpp
new file mode 100644
index 0000000..4542e80
--- /dev/null
+++ b/Viewer/src/TextPager/TextPagerSearchHighlighter.cpp
@@ -0,0 +1,145 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "TextPagerSearchHighlighter.hpp"
+
+#include "VConfig.hpp"
+#include "VProperty.hpp"
+
+#include <QDebug>
+
+QColor TextPagerSearchHighlighter::bgColour_=QColor(200, 255, 200);
+
+TextPagerSearchHighlighter::TextPagerSearchHighlighter(QObject *parent) :
+ SyntaxHighlighter(parent),
+ mode_(NoMode),
+ caseSensitive_(false),
+ wholeWords_(false)
+ {
+ if(VProperty *p=VConfig::instance()->find("panel.search.highlightColour"))
+ {
+ bgColour_=p->value().value<QColor>();
+ }
+
+ format_.setBackground(Qt::yellow);
+
+ rx_=QRegExp("(server)");
+ }
+
+//from QRegExp
+bool TextPagerSearchHighlighter::isWordCharacter(const QChar& ch) const
+{
+ return ch.isLetterOrNumber() || ch.isMark() || ch == QLatin1Char('_');
+}
+
+void TextPagerSearchHighlighter::highlightBlock(const QString &string)
+{
+ if(string.simplified().isEmpty())
+ return;
+
+ if(mode_ == RegexpMode)
+ {
+ if(rx_.isEmpty()) return;
+ int index=0;
+ while((index = rx_.indexIn(string, index)) != -1) {
+
+ if(rx_.matchedLength() == 0)
+ return;
+ setFormat(index, rx_.matchedLength(), format_);
+ index+=rx_.matchedLength();
+ }
+ }
+ else if(mode_ == TextMode)
+ {
+ if(text_.isEmpty()) return;
+ int index=0;
+ while((index = string.indexOf(text_,index,
+ caseSensitive_?Qt::CaseSensitive:Qt::CaseInsensitive)) != -1)
+ {
+ bool found=true;
+ if(wholeWords_)
+ {
+ if(index>0)
+ found=!isWordCharacter(string.at(index-1));
+ if(found && index + text_.size() < string.size())
+ found=!isWordCharacter(string.at(index+text_.size()));
+ }
+ if(found)
+ setFormat(index, text_.size(), format_);
+
+ index+=string.size();
+ }
+ }
+}
+
+void TextPagerSearchHighlighter::reset(QString txt,TextPagerDocument::FindMode mode,bool apply)
+{
+ bool changed=false;
+ if(mode_ != TextMode)
+ {
+ mode_=TextMode;
+ rx_=QRegExp();
+ changed=true;
+ }
+
+ if(txt != text_)
+ {
+ text_=txt;
+ changed=true;
+ }
+
+ bool cs=mode & TextPagerDocument::FindCaseSensitively;
+ if(cs != caseSensitive_)
+ {
+ caseSensitive_=cs;
+ changed=true;
+ }
+
+ bool ww=mode & TextPagerDocument::FindWholeWords;
+ if(ww != wholeWords_)
+ {
+ wholeWords_=ww;
+ changed=true;
+ }
+
+ if(changed && apply)
+ rehighlight();
+
+}
+
+void TextPagerSearchHighlighter::reset(QRegExp rx,TextPagerDocument::FindMode mode,bool apply)
+{
+ bool changed=false;
+ if(mode_ != RegexpMode)
+ {
+ mode_=RegexpMode;
+ text_.clear();
+ changed=true;
+ }
+
+ if(rx_.pattern() != rx.pattern() || rx_.caseSensitivity() != rx.caseSensitivity() ||
+ rx_.patternSyntax() != rx.patternSyntax())
+ {
+ rx_=rx;
+ changed=true;
+ }
+
+ if(changed && apply)
+ rehighlight();
+}
+
+void TextPagerSearchHighlighter::clear()
+{
+ rx_=QRegExp();
+ text_.clear();
+ rehighlight();
+}
+
+
diff --git a/Viewer/src/TextPager/TextPagerSearchHighlighter.hpp b/Viewer/src/TextPager/TextPagerSearchHighlighter.hpp
new file mode 100644
index 0000000..9aa2462
--- /dev/null
+++ b/Viewer/src/TextPager/TextPagerSearchHighlighter.hpp
@@ -0,0 +1,43 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VIEWER_SRC_TEXTPAGER_TEXTPAGERSEARCHHIGHLIGHTER_HPP_
+#define VIEWER_SRC_TEXTPAGER_TEXTPAGERSEARCHHIGHLIGHTER_HPP_
+
+#include "syntaxhighlighter.hpp"
+
+#include "TextPagerDocument.hpp"
+
+#include <QColor>
+#include <QRegExp>
+
+class TextPagerSearchHighlighter : public SyntaxHighlighter
+{
+public:
+ TextPagerSearchHighlighter(QObject *parent=0);
+ virtual void highlightBlock(const QString &string);
+ void reset(QString txt,TextPagerDocument::FindMode mode,bool apply);
+ void reset(QRegExp rx,TextPagerDocument::FindMode mode, bool apply);
+ void clear();
+ enum Mode {NoMode,TextMode,RegexpMode};
+
+protected:
+ bool isWordCharacter(const QChar& ch) const;
+
+ Mode mode_;
+ QRegExp rx_;
+ QString text_;
+ QTextCharFormat format_;
+ bool caseSensitive_;
+ bool wholeWords_;
+ static QColor bgColour_;
+};
+
+#endif /* VIEWER_SRC_TEXTPAGER_TEXTPAGERSEARCHHIGHLIGHTER_HPP_ */
diff --git a/Viewer/src/TextPager/TextPagerSearchInterface.cpp b/Viewer/src/TextPager/TextPagerSearchInterface.cpp
new file mode 100644
index 0000000..8d7aa11
--- /dev/null
+++ b/Viewer/src/TextPager/TextPagerSearchInterface.cpp
@@ -0,0 +1,218 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+// Copyright 2014 ECMWF.
+
+#include "TextPager/TextPagerSearchInterface.hpp"
+
+//#include <QTextEdit>
+#include "TextPagerEdit.hpp"
+#include "UserMessage.hpp"
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+#include <QGuiApplication>
+#endif
+
+bool TextPagerSearchInterface::findString (QString str, bool highlightAll, QTextDocument::FindFlags flags,
+ bool gotoStartOfWord, int iteration,StringMatchMode::Mode matchMode)
+{
+ if(!editor_)
+ return false;
+
+ if(editor_->document()->documentSize() ==0)
+ return false;
+
+ bool doSearch=true;
+ if(str.simplified().isEmpty())
+ {
+ doSearch=false;
+ }
+
+ TextPagerCursor cursor(editor_->textCursor());
+
+ if (gotoStartOfWord) // go to start of word?
+ cursor.movePosition(TextPagerCursor::StartOfWord);
+
+ TextPagerDocument::FindMode mode=TextPagerDocument::FindWrap;
+
+ if(flags & QTextDocument::FindCaseSensitively)
+ mode |= TextPagerDocument::FindCaseSensitively;
+
+ if(flags & QTextDocument::FindBackward)
+ mode |= TextPagerDocument::FindBackward;
+
+ if(flags & QTextDocument::FindWholeWords)
+ mode |= TextPagerDocument::FindWholeWords;
+
+ bool found = false;
+
+ Qt::CaseSensitivity cs = (flags & QTextDocument::FindCaseSensitively) ? Qt::CaseSensitive : Qt::CaseInsensitive;
+
+ if(doSearch)
+ {
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+ QGuiApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+#endif
+ }
+
+ switch (matchMode)
+ {
+ case StringMatchMode::ContainsMatch:
+ {
+ editor_->setSearchHighlighter(str,mode);
+
+ if(doSearch)
+ {
+ cursor = editor_->document()->find(str, cursor, mode); // perform the search
+ found = (!cursor.isNull());
+ }
+ break;
+ }
+ case StringMatchMode::WildcardMatch:
+ {
+ QRegExp regexp(str);
+ regexp.setCaseSensitivity(cs);
+ regexp.setPatternSyntax(QRegExp::Wildcard);
+
+ editor_->setSearchHighlighter(regexp,mode);
+
+ if(doSearch)
+ {
+ cursor = editor_->document()->find(regexp, cursor, mode); // perform the search }
+ found = (!cursor.isNull());
+ }
+ break;
+ }
+ case StringMatchMode::RegexpMatch:
+ {
+ QRegExp regexp(str);
+ regexp.setCaseSensitivity(cs);
+
+ editor_->setSearchHighlighter(regexp,mode);
+
+ if(doSearch)
+ {
+ cursor = editor_->document()->find(regexp, cursor, mode); // perform the search
+ found = (!cursor.isNull());
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ if(found)
+ {
+ editor_->setTextCursor(cursor); // mark the selection of the match
+ editor_->ensureCursorVisible();
+ cursor.movePosition(TextPagerCursor::StartOfLine);
+ }
+
+ if(doSearch)
+ {
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+ QGuiApplication::restoreOverrideCursor();
+#endif
+ }
+
+ return found;
+}
+
+void TextPagerSearchInterface::automaticSearchForKeywords(bool userClickedReload)
+{
+ if(editor_->document()->documentSize() ==0)
+ return;
+
+ bool found = false;
+ TextPagerDocument::FindMode findMode = TextPagerDocument::FindBackward;
+ TextPagerCursor cursor(editor_->textCursor());
+ cursor.movePosition(TextPagerCursor::End);
+
+ qDebug() << "automaticSearchForKeyword" << editor_->textCursor().position();
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+ QGuiApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+#endif
+
+ //QRegExp regexp("10:56:45 4");
+ QRegExp regexp("--(abort|complete)");
+ TextPagerCursor findCursor = editor_->document()->find(regexp, cursor, findMode); // perform the search
+ //TextPagerCursor findCursor = editor_->document()->find("--abort", cursor, findMode);
+ found = (!findCursor.isNull());
+ if(found)
+ {
+ editor_->setTextCursor(findCursor);
+ }
+
+#if 0
+ QStringList keywords;
+ keywords << "--abort" << "--complete";// << "xabort" << "xcomplete"
+ << "System Billing Units";
+
+ // find any of the keywords and stop at the first one
+ int i = 0;
+ while (!found && i < keywords.size())
+ {
+ cursor.movePosition(QTextCursor::End);
+ textEdit_->setTextCursor(cursor);
+ found = textEdit_->findString(keywords.at(i), findFlags);
+ i++;
+ }
+#endif
+
+ else
+ {
+ if(userClickedReload)
+ {
+ // move the cursor to the start of the last line
+ TextPagerCursor cursor = editor_->textCursor();
+ cursor.movePosition(TextPagerCursor::End);
+ cursor.movePosition(TextPagerCursor::StartOfLine);
+ editor_->setTextCursor(cursor);
+ }
+ }
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+ QGuiApplication::restoreOverrideCursor();
+#endif
+}
+
+void TextPagerSearchInterface::refreshSearch()
+{
+ if(!editor_)
+ return;
+
+ TextPagerCursor cursor(editor_->textCursor());
+ if (cursor.hasSelection())
+ {
+ cursor.movePosition(TextPagerCursor::StartOfLine, TextPagerCursor::MoveAnchor);
+ editor_->setTextCursor(cursor);
+ }
+}
+
+
+void TextPagerSearchInterface::clearHighlights()
+{
+ if(editor_)
+ editor_->clearSearchHighlighter();
+}
+
+void TextPagerSearchInterface::enableHighlights()
+{
+ if(editor_)
+ editor_->setEnableSearchHighlighter(true);
+}
+
+void TextPagerSearchInterface::disableHighlights()
+{
+ if(editor_)
+ editor_->setEnableSearchHighlighter(false);
+}
diff --git a/Viewer/src/TextPager/TextPagerSearchInterface.hpp b/Viewer/src/TextPager/TextPagerSearchInterface.hpp
new file mode 100644
index 0000000..4054134
--- /dev/null
+++ b/Viewer/src/TextPager/TextPagerSearchInterface.hpp
@@ -0,0 +1,40 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VIEWER_SRC_TEXTPAGER_TEXTPAGERSEARCHINTERFACE_HPP_
+#define VIEWER_SRC_TEXTPAGER_TEXTPAGERSEARCHINTERFACE_HPP_
+
+#include "AbstractTextEditSearchInterface.hpp"
+
+class TextPagerEdit;
+
+class TextPagerSearchInterface : public AbstractTextEditSearchInterface
+{
+public:
+ TextPagerSearchInterface() : editor_(NULL) {}
+ void setEditor(TextPagerEdit* e) {editor_=e;}
+
+ bool findString (QString str, bool highlightAll, QTextDocument::FindFlags findFlags,
+ bool gotoStartOfWord, int iteration,StringMatchMode::Mode matchMode);
+
+ void automaticSearchForKeywords(bool);
+ void refreshSearch();
+ void clearHighlights();
+ void disableHighlights();
+ void enableHighlights();
+ bool highlightsNeedSearch() {return false;}
+
+protected:
+
+ TextPagerEdit *editor_;
+
+};
+
+#endif /* VIEWER_SRC_TEXTPAGER_TEXTPAGERSEARCHINTERFACE_HPP_ */
diff --git a/Viewer/src/TextPager/TextPagerSection.cpp b/Viewer/src/TextPager/TextPagerSection.cpp
new file mode 100644
index 0000000..a744651
--- /dev/null
+++ b/Viewer/src/TextPager/TextPagerSection.cpp
@@ -0,0 +1,66 @@
+// Copyright 2010 Anders Bakken
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "TextPagerSection.hpp"
+#include "TextPagerDocument.hpp"
+#include "TextPagerDocument_p.hpp"
+
+TextPagerSection::~TextPagerSection()
+{
+ if (d.document)
+ d.document->takeTextSection(this);
+}
+
+QString TextPagerSection::text() const
+{
+ Q_ASSERT(d.document);
+ return d.document->read(d.position, d.size);
+}
+
+void TextPagerSection::setFormat(const QTextCharFormat &format)
+{
+ Q_ASSERT(d.document);
+ d.format = format;
+ Q_EMIT d.document->d->sectionFormatChanged(this);
+}
+
+QCursor TextPagerSection::cursor() const
+{
+ return d.cursor;
+}
+
+void TextPagerSection::setCursor(const QCursor &cursor)
+{
+ d.cursor = cursor;
+ d.hasCursor = true;
+ Q_EMIT d.document->d->sectionCursorChanged(this);
+}
+
+void TextPagerSection::resetCursor()
+{
+ d.hasCursor = false;
+ d.cursor = QCursor();
+ Q_EMIT d.document->d->sectionCursorChanged(this);
+}
+
+bool TextPagerSection::hasCursor() const
+{
+ return d.hasCursor;
+}
+
+void TextPagerSection::setPriority(int priority)
+{
+ d.priority = priority;
+ Q_EMIT d.document->d->sectionFormatChanged(this); // ### it hasn't really but I to need it dirtied
+}
diff --git a/Viewer/src/TextPager/TextPagerSection.hpp b/Viewer/src/TextPager/TextPagerSection.hpp
new file mode 100644
index 0000000..c5d836b
--- /dev/null
+++ b/Viewer/src/TextPager/TextPagerSection.hpp
@@ -0,0 +1,75 @@
+// Copyright 2010 Anders Bakken
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef TEXTPAGERSECTION_HPP__
+#define TEXTPAGERSECTION_HPP__
+
+#include <QString>
+#include <QTextCharFormat>
+#include <QVariant>
+#include <QCursor>
+
+class TextPagerDocument;
+class TextPagerEdit;
+class TextPagerSection
+{
+public:
+ enum TextSectionOption {
+ IncludePartial = 0x01
+ };
+ Q_DECLARE_FLAGS(TextSectionOptions, TextSectionOption);
+
+ ~TextPagerSection();
+ QString text() const;
+ int position() const { return d.position; }
+ int size() const { return d.size; }
+ QTextCharFormat format() const { return d.format; }
+ void setFormat(const QTextCharFormat &format);
+ QVariant data() const { return d.data; }
+ void setData(const QVariant &data) { d.data = data; }
+ TextPagerDocument *document() const { return d.document; }
+ TextPagerEdit *textEdit() const { return d.textEdit; }
+ QCursor cursor() const;
+ void setCursor(const QCursor &cursor);
+ void resetCursor();
+ bool hasCursor() const;
+ int priority() const { return d.priority; }
+ void setPriority(int priority);
+private:
+ struct Data {
+ Data(int p, int s, TextPagerDocument *doc, const QTextCharFormat &f, const QVariant &d)
+ : position(p), size(s), priority(0), document(doc), textEdit(0), format(f), data(d), hasCursor(false)
+ {}
+ int position, size, priority;
+ TextPagerDocument *document;
+ TextPagerEdit *textEdit;
+ QTextCharFormat format;
+ QVariant data;
+ QCursor cursor;
+ bool hasCursor;
+ } d;
+
+ TextPagerSection(int pos, int size, TextPagerDocument *doc, const QTextCharFormat &format, const QVariant &data)
+ : d(pos, size, doc, format, data)
+ {}
+
+ friend class TextPagerDocument;
+ friend class TextDocumentPrivate;
+ friend class TextPagerEdit;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(TextPagerSection::TextSectionOptions);
+
+
+#endif
diff --git a/Viewer/src/TextPager/TextPagerSection_p.hpp b/Viewer/src/TextPager/TextPagerSection_p.hpp
new file mode 100644
index 0000000..e5e0cfd
--- /dev/null
+++ b/Viewer/src/TextPager/TextPagerSection_p.hpp
@@ -0,0 +1,34 @@
+// Copyright 2010 Anders Bakken
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef TEXTPAGERSECTION_P_HPP_
+#define TEXTPAGERSECTION_P_HPP_
+
+#include <QObject>
+#include <QCoreApplication>
+class TextPagerSection;
+class TextSectionManager : public QObject
+{
+ Q_OBJECT
+public:
+ static TextSectionManager *instance() { static TextSectionManager *inst = new TextSectionManager; return inst; }
+Q_SIGNALS:
+ void sectionFormatChanged(TextPagerSection *section);
+ void sectionCursorChanged(TextPagerSection *section);
+private:
+ TextSectionManager() : QObject(QCoreApplication::instance()) {}
+ friend class TextPagerSection;
+};
+
+#endif
diff --git a/Viewer/src/TextPager/TextPagerWidget.cpp b/Viewer/src/TextPager/TextPagerWidget.cpp
new file mode 100644
index 0000000..fb69582
--- /dev/null
+++ b/Viewer/src/TextPager/TextPagerWidget.cpp
@@ -0,0 +1,113 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include <QWidget>
+#include <QString>
+#include <QFont>
+#include <QMainWindow>
+#include <QHBoxLayout>
+#include <QVBoxLayout>
+#include <QApplication>
+#include <QEvent>
+#include <QSpinBox>
+#include <QLineEdit>
+#include <QLabel>
+#include <QPlainTextEdit>
+#include <QShortcut>
+#include <QMenu>
+#include <QMenuBar>
+#include <QFileDialog>
+#include <QMessageBox>
+#include <QInputDialog>
+
+#include "TextPagerWidget.hpp"
+
+#include "GotoLineDialog.hpp"
+
+bool add = false;
+
+TextPagerWidget::TextPagerWidget(QWidget *parent) :
+ //TextPagerEdit(parent),
+ doLineNumbers(true),
+ gotoLineDialog_(NULL)
+{
+ QHBoxLayout* hb=new QHBoxLayout(this);
+ hb->setContentsMargins(0,0,0,0);
+ hb->setSpacing(0);
+
+ textEditor_=new TextPagerEdit(this);
+ lineNumArea_ = new TextPagerLineNumberArea(textEditor_);
+
+ hb->addWidget(lineNumArea_);
+ hb->addWidget(textEditor_,1);
+
+ setAttribute(Qt::WA_MouseTracking);
+}
+
+void TextPagerWidget::clear()
+{
+ textEditor_->document()->clear();
+}
+
+bool TextPagerWidget::load(const QString &fileName, TextPagerDocument::DeviceMode mode)
+{
+ return textEditor_->load(fileName, mode, NULL);
+}
+
+void TextPagerWidget::setText(const QString &txt)
+{
+ textEditor_->setText(txt);
+}
+
+void TextPagerWidget::setFontProperty(VProperty* p)
+{
+ textEditor_->setFontProperty(p);
+}
+
+void TextPagerWidget::zoomIn()
+{
+ textEditor_->zoomIn();
+}
+
+void TextPagerWidget::zoomOut()
+{
+ textEditor_->zoomOut();
+}
+// ---------------------------------------------------------------------------
+// TextEdit::gotoLine
+// triggered when the user asks to bring up the 'go to line' dialog
+// ---------------------------------------------------------------------------
+
+void TextPagerWidget::gotoLine()
+{
+ // create the dialog if it does not already exist
+
+ if (!gotoLineDialog_)
+ {
+ gotoLineDialog_ = new GotoLineDialog(this);
+
+ connect(gotoLineDialog_, SIGNAL(gotoLine(int)), this, SLOT(gotoLine(int)));
+ }
+
+ // if created, set it up and display it
+
+ if (gotoLineDialog_)
+ {
+ gotoLineDialog_->show();
+ gotoLineDialog_->raise();
+ gotoLineDialog_->activateWindow();
+ gotoLineDialog_->setupUIBeforeShow();
+ }
+}
+
+void TextPagerWidget::gotoLine(int line)
+{
+ textEditor_->gotoLine(line);
+}
diff --git a/Viewer/src/TextPager/TextPagerWidget.hpp b/Viewer/src/TextPager/TextPagerWidget.hpp
new file mode 100644
index 0000000..7196ee8
--- /dev/null
+++ b/Viewer/src/TextPager/TextPagerWidget.hpp
@@ -0,0 +1,53 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VIEWER_SRC_TEXTPAGERWIDGET_HPP_
+#define VIEWER_SRC_TEXTPAGERWIDGET_HPP_
+
+#include "TextPagerEdit.hpp"
+
+class GotoLineDialog;
+
+class TextPagerWidget : public QWidget //TextPagerEdit
+{
+ Q_OBJECT
+public:
+ TextPagerWidget(QWidget *parent = 0);
+
+ TextPagerEdit* textEditor() const {return textEditor_;}
+ void clear();
+ bool load(const QString &fileName, TextPagerDocument::DeviceMode mode = TextPagerDocument::Sparse);
+ void setText(const QString& txt);
+
+ void setFontProperty(VProperty* p);
+ void zoomIn();
+ void zoomOut();
+ void gotoLine();
+
+ //void mouseMoveEvent(QMouseEvent *e);
+ //void timerEvent(QTimerEvent *e);
+protected Q_SLOTS:
+ void gotoLine(int);
+
+Q_SIGNALS:
+ void cursorCharacter(const QChar &ch);
+
+private:
+
+ bool doLineNumbers;
+ QBasicTimer appendTimer, changeSelectionTimer;
+ TextPagerEdit *textEditor_;
+
+ TextPagerLineNumberArea *lineNumArea_;
+ GotoLineDialog *gotoLineDialog_;
+};
+
+
+#endif /* VIEWER_SRC_TEXTPAGER_TEXTPAGERWIDGET_HPP_ */
diff --git a/Viewer/src/TextPager/WeakPointer.hpp b/Viewer/src/TextPager/WeakPointer.hpp
new file mode 100644
index 0000000..9370126
--- /dev/null
+++ b/Viewer/src/TextPager/WeakPointer.hpp
@@ -0,0 +1,16 @@
+#ifndef WEAKPOINTER_H
+#define WEAKPOINTER_H
+
+#include <qglobal.h>
+
+#if (QT_VERSION < QT_VERSION_CHECK(4, 6, 0))
+// while QWeakPointer existed in Qt 4.5 it lacked certain APIs (like
+// data so I'll stick with QPointer until 4.6)
+#include <QPointer>
+#define WeakPointer QPointer
+#else
+#include <QWeakPointer>
+#define WeakPointer QWeakPointer
+#endif
+
+#endif
diff --git a/Viewer/src/TextPager/syntaxhighlighter.cpp b/Viewer/src/TextPager/syntaxhighlighter.cpp
new file mode 100644
index 0000000..f922dab
--- /dev/null
+++ b/Viewer/src/TextPager/syntaxhighlighter.cpp
@@ -0,0 +1,133 @@
+// Copyright 2010 Anders Bakken
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "syntaxhighlighter.hpp"
+
+#include "TextPagerEdit.hpp"
+#include "TextPagerDocument.hpp"
+#include "TextPagerLayout_p.hpp"
+#include "TextPagerDocument_p.hpp"
+
+SyntaxHighlighter::SyntaxHighlighter(QObject *parent)
+ : QObject(parent), d(new Private)
+{
+}
+
+SyntaxHighlighter::SyntaxHighlighter(TextPagerEdit *parent)
+ : QObject(parent), d(new Private)
+{
+ if (parent) {
+ parent->addSyntaxHighlighter(this);
+ }
+}
+
+SyntaxHighlighter::~SyntaxHighlighter()
+{
+ delete d;
+}
+
+void SyntaxHighlighter::setTextEdit(TextPagerEdit *doc)
+{
+ Q_ASSERT(doc);
+ doc->addSyntaxHighlighter(this);
+}
+TextPagerEdit *SyntaxHighlighter::textEdit() const
+{
+ return d->textEdit;
+}
+
+
+TextPagerDocument * SyntaxHighlighter::document() const
+{
+ return d->textEdit ? d->textEdit->document() : 0;
+}
+
+void SyntaxHighlighter::rehighlight()
+{
+ if (d->textEdit) {
+ Q_ASSERT(d->textLayout);
+ d->textLayout->layoutDirty = true;
+ d->textEdit->viewport()->update();
+ }
+}
+
+void SyntaxHighlighter::setFormat(int start, int count, const QTextCharFormat &format)
+{
+ ASSUME(d->textEdit);
+ Q_ASSERT(start >= 0);
+ Q_ASSERT(start + count <= d->currentBlock.size());
+ d->formatRanges.append(QTextLayout::FormatRange());
+ QTextLayout::FormatRange &range = d->formatRanges.last();
+ range.start = start;
+ range.length = count;
+ range.format = format;
+}
+
+void SyntaxHighlighter::setFormat(int start, int count, const QColor &color)
+{
+ QTextCharFormat format;
+ format.setForeground(color);
+ setFormat(start, count, format);
+}
+
+void SyntaxHighlighter::setFormat(int start, int count, const QFont &font)
+{
+ QTextCharFormat format;
+ format.setFont(font);
+ setFormat(start, count, format);
+}
+
+QTextCharFormat SyntaxHighlighter::format(int pos) const
+{
+ QTextCharFormat ret;
+ Q_FOREACH(const QTextLayout::FormatRange &range, d->formatRanges) {
+ if (range.start <= pos && range.start + range.length > pos) {
+ ret.merge(range.format);
+ } else if (range.start > pos) {
+ break;
+ }
+ }
+ return ret;
+}
+
+
+int SyntaxHighlighter::previousBlockState() const
+{
+ return d->previousBlockState;
+}
+
+int SyntaxHighlighter::currentBlockState() const
+{
+ return d->currentBlockState;
+}
+
+void SyntaxHighlighter::setCurrentBlockState(int s)
+{
+ d->previousBlockState = d->currentBlockState;
+ d->currentBlockState = s; // ### These don't entirely follow QSyntaxHighlighter's behavior
+}
+
+int SyntaxHighlighter::currentBlockPosition() const
+{
+ return d->currentBlockPosition;
+}
+
+QTextBlockFormat SyntaxHighlighter::blockFormat() const
+{
+ return d->blockFormat;
+}
+
+void SyntaxHighlighter::setBlockFormat(const QTextBlockFormat &format)
+{
+ d->blockFormat = format;
+}
diff --git a/Viewer/src/TextPager/syntaxhighlighter.hpp b/Viewer/src/TextPager/syntaxhighlighter.hpp
new file mode 100644
index 0000000..c162c00
--- /dev/null
+++ b/Viewer/src/TextPager/syntaxhighlighter.hpp
@@ -0,0 +1,78 @@
+// Copyright 2010 Anders Bakken
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SYNTAXHIGHLIGHTER_HPP__
+#define SYNTAXHIGHLIGHTER_HPP__
+
+#include <QObject>
+#include <QString>
+#include <QTextCharFormat>
+#include <QColor>
+#include <QFont>
+#include <QList>
+#include <QTextLayout>
+
+class TextPagerEdit;
+class TextPagerLayout;
+class TextPagerDocument;
+class SyntaxHighlighter : public QObject
+{
+ Q_OBJECT
+public:
+ SyntaxHighlighter(QObject *parent = 0);
+ SyntaxHighlighter(TextPagerEdit *parent);
+ ~SyntaxHighlighter();
+ void setTextEdit(TextPagerEdit *doc);
+ TextPagerEdit *textEdit() const;
+ TextPagerDocument *document() const;
+ virtual void highlightBlock(const QString &text) = 0;
+ QString currentBlock() const { return d->currentBlock; }
+ void setFormat(int start, int count, const QTextCharFormat &format);
+ void setFormat(int start, int count, const QColor &color);
+ inline void setColor(int start, int count, const QColor &color)
+ { setFormat(start, count, color); }
+ inline void setBackground(int start, int count, const QBrush &brush)
+ { QTextCharFormat format; format.setBackground(brush); setFormat(start, count, format); }
+ inline void setBackgroundColor(int start, int count, const QColor &color)
+ { setBackground(start, count, color); }
+ void setFormat(int start, int count, const QFont &font);
+ inline void setFont(int start, int count, const QFont &font)
+ { setFormat(start, count, font); }
+ QTextBlockFormat blockFormat() const;
+ void setBlockFormat(const QTextBlockFormat &format);
+ QTextCharFormat format(int pos) const;
+ int previousBlockState() const;
+ int currentBlockState() const;
+ void setCurrentBlockState(int s);
+ int currentBlockPosition() const;
+public Q_SLOTS:
+ void rehighlight();
+private:
+ struct Private {
+ Private() : textEdit(0), textLayout(0), previousBlockState(0), currentBlockState(0),
+ currentBlockPosition(-1) {}
+ TextPagerEdit *textEdit;
+ TextPagerLayout *textLayout;
+ int previousBlockState, currentBlockState, currentBlockPosition;
+ QList<QTextLayout::FormatRange> formatRanges;
+ QTextBlockFormat blockFormat;
+ QString currentBlock;
+ } *d;
+
+ friend class TextPagerEdit;
+ friend class TextPagerLayout;
+};
+
+
+#endif
diff --git a/Viewer/src/TimeItemWidget.cpp b/Viewer/src/TimeItemWidget.cpp
new file mode 100644
index 0000000..9c0d82f
--- /dev/null
+++ b/Viewer/src/TimeItemWidget.cpp
@@ -0,0 +1,44 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "LineEdit.hpp"
+
+#include "TimeItemWidget.hpp"
+
+#include "Node.hpp"
+
+//========================================================
+//
+// TimeItemWidget
+//
+//========================================================
+
+TimeItemWidget::TimeItemWidget(QWidget *parent) : QWidget(parent)
+{
+ setupUi(this);
+
+}
+
+QWidget* TimeItemWidget::realWidget()
+{
+ return this;
+}
+
+void TimeItemWidget::reload(VInfo_ptr nodeInfo)
+{
+ active_=true;
+}
+
+void TimeItemWidget::clearContents()
+{
+ InfoPanelItem::clear();
+}
+
+
+static InfoPanelItemMaker<TimeItemWidget> maker1("time");
diff --git a/Viewer/src/TimeItemWidget.hpp b/Viewer/src/TimeItemWidget.hpp
new file mode 100644
index 0000000..1b3b716
--- /dev/null
+++ b/Viewer/src/TimeItemWidget.hpp
@@ -0,0 +1,45 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef TIMEITEMWIDGET_HPP_
+#define TIMEITEMWIDGET_HPP_
+#include "ui_TimeItemWidget.h"
+
+#include <QWidget>
+
+#include "InfoPanelItem.hpp"
+#include "VInfo.hpp"
+
+class LineEdit;
+
+class TimeItemWidget
+ : public QWidget
+ , public InfoPanelItem
+ , protected Ui::TimeItemWidget
+
+{
+public:
+ explicit TimeItemWidget(QWidget *parent=0);
+
+ void reload(VInfo_ptr);
+ QWidget* realWidget();
+ void clearContents();
+
+ void nodeChanged(const VNode*, const std::vector<ecf::Aspect::Type>&) {}
+ void defsChanged(const std::vector<ecf::Aspect::Type>&) {}
+
+ QGraphicsView* view() { return graphicsView; }
+
+protected:
+ void updateState(const ChangeFlags&) {}
+};
+
+#endif
+
diff --git a/Viewer/src/TimeItemWidget.ui b/Viewer/src/TimeItemWidget.ui
new file mode 100644
index 0000000..8e052b0
--- /dev/null
+++ b/Viewer/src/TimeItemWidget.ui
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>TimeItemWidget</class>
+ <widget class="QWidget" name="TimeItemWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>859</width>
+ <height>621</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="0">
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLineEdit" name="lineEdit">
+ <property name="text">
+ <string>%ECF_LOG%</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="rb_all">
+ <property name="text">
+ <string>All</string>
+ </property>
+ <attribute name="buttonGroup">
+ <string notr="true">filterGroup</string>
+ </attribute>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="rb_task">
+ <property name="text">
+ <string>Tasks</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <attribute name="buttonGroup">
+ <string notr="true">filterGroup</string>
+ </attribute>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="rb_sortT">
+ <property name="text">
+ <string>TimeSort</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <attribute name="buttonGroup">
+ <string notr="true">sortGroup</string>
+ </attribute>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="rb_sortN">
+ <property name="text">
+ <string>NameSort</string>
+ </property>
+ <attribute name="buttonGroup">
+ <string notr="true">sortGroup</string>
+ </attribute>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDateTimeEdit" name="le_tb">
+ <property name="date">
+ <date>
+ <year>2015</year>
+ <month>1</month>
+ <day>1</day>
+ </date>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDateTimeEdit" name="le_te">
+ <property name="date">
+ <date>
+ <year>2100</year>
+ <month>1</month>
+ <day>1</day>
+ </date>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="pb_merge">
+ <property name="maximumSize">
+ <size>
+ <width>16</width>
+ <height>16</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string extracomment="Merge"/>
+ </property>
+ <property name="statusTip">
+ <string extracomment="Merge"/>
+ </property>
+ <property name="text">
+ <string>M</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="pb_load">
+ <property name="maximumSize">
+ <size>
+ <width>16</width>
+ <height>16</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string extracomment="Load"/>
+ </property>
+ <property name="statusTip">
+ <string extracomment="Load"/>
+ </property>
+ <property name="text">
+ <string>L</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="pb_update">
+ <property name="maximumSize">
+ <size>
+ <width>16</width>
+ <height>16</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string extracomment="Update"/>
+ </property>
+ <property name="statusTip">
+ <string extracomment="Update"/>
+ </property>
+ <property name="text">
+ <string>U</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QToolButton" name="viewTb">
+ <property name="toolTip">
+ <string>View options</string>
+ </property>
+ <property name="text">
+ <string>Detached</string>
+ </property>
+ <property name="icon">
+ <iconset resource="viewer.qrc">
+ <normaloff>:/viewer/images/configure.svg</normaloff>:/viewer/images/configure.svg</iconset>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0">
+ <layout class="QHBoxLayout" name="horizontalLayout_5">
+ <item>
+ <widget class="QGraphicsView" name="graphicsView"/>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="viewer.qrc"/>
+ </resources>
+ <connections/>
+ <buttongroups>
+ <buttongroup name="sortGroup"/>
+ <buttongroup name="filterGroup"/>
+ </buttongroups>
+</ui>
diff --git a/Viewer/src/TreeNodeModel.cpp b/Viewer/src/TreeNodeModel.cpp
new file mode 100644
index 0000000..2e8034e
--- /dev/null
+++ b/Viewer/src/TreeNodeModel.cpp
@@ -0,0 +1,1117 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "TreeNodeModel.hpp"
+
+#include <QDebug>
+#include <QMetaMethod>
+
+#include "ConnectState.hpp"
+#include "VFilter.hpp"
+#include "ServerFilter.hpp"
+#include "ServerHandler.hpp"
+#include "UserMessage.hpp"
+#include "VFilter.hpp"
+#include "VNState.hpp"
+#include "VSState.hpp"
+#include "VAttributeType.hpp"
+#include "VNode.hpp"
+#include "VIcon.hpp"
+#include "VFileInfo.hpp"
+#include "VModelData.hpp"
+#include "VTree.hpp"
+
+//#define _UI_TREENODEMODEL_DEBUG
+
+//=======================================
+//
+// TreeNodeModel
+//
+//=======================================
+
+TreeNodeModel::TreeNodeModel(ServerFilter* serverFilter,NodeFilterDef* filterDef,
+ AttributeFilter *atts,IconFilter* icons,QObject *parent) :
+ AbstractNodeModel(parent),
+ data_(0),
+ atts_(atts),
+ icons_(icons),
+ serverToolTip_(true),
+ nodeToolTip_(true),
+ attributeToolTip_(true)
+{
+ //Create the data handler for the tree model.
+ data_=new VTreeModelData(filterDef,atts_,this);
+
+ //Reset the data handler
+ data_->reset(serverFilter);
+
+ //Icon filter changes
+ connect(icons_,SIGNAL(changed()),
+ this,SIGNAL(rerender()));
+
+}
+
+VModelData* TreeNodeModel::data() const
+{
+ return data_;
+}
+
+
+int TreeNodeModel::columnCount( const QModelIndex& /*parent */ ) const
+{
+ return 1;
+}
+
+int TreeNodeModel::rowCount( const QModelIndex& parent) const
+{
+ //qDebug() << "rowCount" << parent;
+
+ //There is no data at all
+ if(!hasData())
+ {
+ return 0;
+ }
+ //We use only column 0
+ else if(parent.column() > 0)
+ {
+ return 0;
+ }
+ //"parent" is the root
+ else if(!parent.isValid())
+ {
+ return data_->count();
+ }
+ //"parent" is a server
+ else if(isServer(parent))
+ {
+ if(VTreeServer *server=indexToServer(parent))
+ {
+ if(server->inScan())
+ return 0;
+ else
+ return server->tree()->attrNum(atts_)+server->tree()->numOfChildren();
+ }
+ }
+ //"parent" is a node
+ else if(VTreeNode* parentNode=indexToNode(parent))
+ {
+ return parentNode->attrNum(atts_)+parentNode->numOfChildren();
+ }
+
+ return 0;
+}
+
+Qt::ItemFlags TreeNodeModel::flags ( const QModelIndex & index) const
+{
+ Qt::ItemFlags defaultFlags;
+
+ defaultFlags=Qt::ItemIsEnabled | Qt::ItemIsSelectable;
+
+ return defaultFlags;
+}
+
+QVariant TreeNodeModel::data( const QModelIndex& index, int role ) const
+{
+ //Data lookup can be costly so we immediately return a default value for all
+ //the cases where the default should be used.
+ if( !index.isValid() ||
+ (role != Qt::DisplayRole && role != Qt::ToolTipRole && role != Qt::BackgroundRole &&
+ role != Qt::ForegroundRole &&
+ role != IconRole && role != ServerRole && role != NodeNumRole &&
+ role != InfoRole && role != LoadRole && role != ConnectionRole && role != AttributeRole && role != AttributeLineRole &&
+ role != AbortedReasonRole && role != NodeTypeRole && role != NodeTypeForegroundRole && role != ServerPointerRole))
+ {
+ return QVariant();
+ }
+
+ //Identifies server
+ if(role == ServerRole)
+ {
+ if(isServer(index))
+ return 0;
+ else
+ return -1;
+ }
+
+ if(role == AttributeRole)
+ {
+ return isAttribute(index);
+ }
+
+ //Server
+ if(isServer(index))
+ {
+ if(role == AttributeLineRole)
+ return 0;
+
+ return serverData(index,role);
+ }
+
+ //We only continue for the relevant roles for nodes and attributes
+ if(role == InfoRole || role == LoadRole)
+ {
+ return QVariant();
+ }
+
+ //Node
+ if(isNode(index))
+ {
+ if(role == AttributeLineRole)
+ return 0;
+
+ return nodeData(index,role);
+ }
+
+ //We only continue for the relevant roles for attributes
+ if(role == IconRole)
+ {
+ return QVariant();
+ }
+
+ //Attribute
+ else if(isAttribute(index))
+ return attributesData(index,role);
+
+ return QVariant();
+}
+
+QVariant TreeNodeModel::serverData(const QModelIndex& index,int role) const
+{
+ if(role == FilterRole)
+ return true;
+
+ if(role == Qt::ToolTipRole & !serverToolTip_)
+ return QVariant();
+
+ ServerHandler *server=indexToServerHandler(index);
+ if(!server)
+ return QVariant();
+
+ if(index.column() == 0)
+ {
+ if(role == ServerPointerRole)
+ return qVariantFromValue((void *) server);
+
+ //The colour of the server node
+ if(role == ConnectionRole)
+ return (server->connectState()->state() == ConnectState::Lost)?0:1;
+
+ //The colour of the server node
+ else if(role == Qt::BackgroundRole)
+ return server->vRoot()->stateColour();
+
+ //The font colour of the server node
+ else if(role == Qt::ForegroundRole)
+ return server->vRoot()->stateFontColour();
+
+ //The text
+ else if(role == Qt::DisplayRole)
+ return QString::fromStdString(server->name());
+
+ //The number of nodes the server has
+ else if(role == NodeNumRole)
+ {
+ ConnectState* st=server->connectState();
+ if(server->activity() != ServerHandler::LoadActivity)
+ {
+ return server->vRoot()->totalNum();
+ }
+ return QVariant();
+ }
+
+ //Extra information about the server activity
+ else if(role == InfoRole)
+ {
+ switch(server->activity())
+ {
+ case ServerHandler::LoadActivity:
+ return "Loading ...";
+ default:
+ return "";
+ }
+ }
+
+ else if(role == LoadRole)
+ return (server->activity() == ServerHandler::LoadActivity);
+
+ //icon decoration
+ /*else if(role == IconRole)
+ {
+ //TODO: add a proper iconprovider
+ ConnectState* st=server->connectState();
+ if(server->activity() != ServerHandler::LoadActivity &&
+ st->state() != ConnectState::Normal)
+ {
+ return "d";
+ }
+ return QVariant();
+ }*/
+
+ else if(role == IconRole)
+ {
+ if(icons_->isEmpty())
+ return QVariant();
+ else
+ return VIcon::pixmapList(server->vRoot(),icons_);
+ }
+
+ //Tooltip
+ else if(role == Qt::ToolTipRole)
+ {
+ QString txt=server->vRoot()->toolTip();
+ txt+=VIcon::toolTip(server->vRoot(),icons_);
+ return txt;
+ }
+ }
+
+ return QVariant();
+}
+
+QVariant TreeNodeModel::nodeData(const QModelIndex& index, int role) const
+{
+ if(role == Qt::ToolTipRole & !nodeToolTip_)
+ return QVariant();
+
+ VTreeNode* tnode=indexToNode(index);
+ if(!tnode)
+ return QVariant();
+
+ VNode* vnode=tnode->vnode();
+ if(!vnode || !vnode->node())
+ return QVariant();
+
+ if(index.column() == 0)
+ {
+ //The colour of the server node
+ if(role == ConnectionRole)
+ {
+ return (vnode->server()->connectState()->state() == ConnectState::Lost)?0:1;
+ }
+
+ else if(role == Qt::DisplayRole)
+ return vnode->name();
+
+ else if(role == Qt::BackgroundRole)
+ {
+ if(vnode->isSuspended())
+ {
+ QVariantList lst;
+ lst << vnode->stateColour() << vnode->realStateColour();
+ return lst;
+ }
+ else
+ return vnode->stateColour() ;
+ }
+
+ else if(role == Qt::ForegroundRole)
+ return vnode->stateFontColour();
+
+ else if(role == NodeTypeRole)
+ {
+ if(vnode->isTask()) return 2;
+ else if(vnode->isSuite()) return 0;
+ else if(vnode->isFamily()) return 1;
+ else if(vnode->isAlias()) return 3;
+ return 0;
+ }
+ else if(role == NodeTypeForegroundRole)
+ {
+ return vnode->typeFontColour();
+ }
+ else if(role == IconRole)
+ {
+ if(icons_->isEmpty())
+ return QVariant();
+ else
+ return VIcon::pixmapList(vnode,icons_);
+ }
+ else if(role == Qt::ToolTipRole)
+ {
+ QString txt=vnode->toolTip();
+ txt+=VIcon::toolTip(vnode,icons_);
+ return txt;
+ }
+
+ //The number of nodes a suite has
+ else if(role == NodeNumRole)
+ {
+ if(vnode->isTopLevel())
+ {
+ if(data_->isFilterNull())
+ return vnode->server()->vRoot()->totalNumOfTopLevel(vnode);
+ else
+ return QString::number(tnode->root()->totalNumOfTopLevel(tnode)) + "/" +
+ QString::number(vnode->server()->vRoot()->totalNumOfTopLevel(vnode));
+ }
+ return QVariant();
+ }
+
+ //The number of nodes a suite has
+ else if(role == AbortedReasonRole && vnode->isAborted())
+ {
+ return QString::fromStdString(vnode->abortedReason());
+ }
+ }
+
+ return QVariant();
+}
+
+//=======================================================================
+//
+// Attributes data
+//
+//=======================================================================
+
+QVariant TreeNodeModel::attributesData(const QModelIndex& index, int role) const
+{
+ if(role == Qt::ToolTipRole & !attributeToolTip_)
+ return QVariant();
+
+ if(role == IconRole)
+ return QVariant();
+
+ if(index.column()!=0)
+ return QVariant();
+
+ if(role != Qt::BackgroundRole && role != Qt::DisplayRole && role != Qt::ToolTipRole && role != ConnectionRole && role != AttributeLineRole )
+ return QVariant();
+
+ if(role == Qt::BackgroundRole)
+ return QColor(220,220,220);
+
+ VTreeNode* node=0;
+ //Here we have to be sure this is an attribute!
+
+ if(VModelServer *mserver=data_->server(index.internalPointer()))
+ {
+ VTreeServer *ts=mserver->treeServer();
+ Q_ASSERT(ts);
+ node=ts->tree();
+ Q_ASSERT(node);
+ }
+ else
+ {
+ node=static_cast<VTreeNode*>(index.internalPointer());
+ }
+
+ Q_ASSERT(node);
+ VNode *vnode=node->vnode();
+ Q_ASSERT(vnode);
+
+
+ if(role == ConnectionRole)
+ {
+ return (vnode->server()->connectState()->state() == ConnectState::Lost)?0:1;
+ }
+
+ else if(role == Qt::DisplayRole)
+ {
+ return vnode->getAttributeData(index.row(),atts_);
+ }
+ else if(role == AttributeLineRole)
+ {
+ return vnode->getAttributeLineNum(index.row(),atts_);
+ }
+ else if(role == Qt::ToolTipRole)
+ {
+ return vnode->attributeToolTip(index.row(),atts_);
+ }
+
+ return QVariant();
+}
+
+QVariant TreeNodeModel::headerData( const int section, const Qt::Orientation orient , const int role ) const
+{
+ //No header!!!
+ return QVariant();
+}
+
+QModelIndex TreeNodeModel::index( int row, int column, const QModelIndex & parent ) const
+{
+ if(!hasData() || row < 0 || column < 0)
+ {
+ return QModelIndex();
+ }
+
+ //When "parent" is the root this index refers to a server
+ if(!parent.isValid())
+ {
+ //For the server the internal pointer is NULL
+ if(row < data_->count())
+ {
+ //qDebug() << "SERVER" << parent;
+ return createIndex(row,column,(void*)NULL);
+ }
+ }
+
+ //Here we must be under one of the servers
+ else
+ {
+ //If "parent" is a server this index refers to a topLevel node (suite).
+ //We set the server as an internal pointer
+ if(VTreeServer* server=indexToServer(parent))
+ {
+ //qDebug() << "NODE1" << parent << server->realServer()->name().c_str();
+ return createIndex(row,column,server);
+ }
+
+ //If "parent" is not a server it must be a tree node. The internal pointer is the parent tree node.
+ else if(VTreeNode* parentNode=indexToNode(parent))
+ {
+ //qDebug() << "NODE2" << parent << parentNode->name().c_str() << VAttribute::totalNum(parentNode);
+ //qDebug() << "NODE2" << parent << parentNode->node()->name().c_str();
+ return createIndex(row,column,parentNode);
+ }
+
+ //qDebug() << "BAD" << parent;
+ }
+
+ //qDebug() << "EMPTY" << parent;
+ return QModelIndex();
+
+}
+
+QModelIndex TreeNodeModel::parent(const QModelIndex &child) const
+{
+ //If "child" is a server the parent is the root
+ if(isServer(child))
+ return QModelIndex();
+
+ int row=-1;
+
+ //If the "child"'s internal pointer is a server it can be a server attribute or a topLevel node (suite)
+ //and the parent is this server.
+ if((row=data_->indexOfServer(child.internalPointer())) != -1)
+ {
+ return createIndex(row,0,(void*)NULL);
+ }
+
+ //The "child" cannot be a server attribute or a topLevel node so it must be a node or an attribute.
+ //Its internal pointer must point to the parent node.
+ else if(VTreeNode *parentNode=static_cast<VTreeNode*>(child.internalPointer()))
+ {
+ //The parent is a topLevel node (suite): its internal pointer is the server
+ if(parentNode->isTopLevel())
+ {
+ VTreeNode* root=parentNode->parent();
+ Q_ASSERT(root);
+ row=root->indexOfChild(parentNode);
+ Q_ASSERT(row >=0);
+ VTreeServer *ts=root->server();
+
+ int serverAttrNum=root->attrNum();
+ return createIndex(serverAttrNum+row,0,ts);
+
+#if 0
+ VModelServer *server=NULL;
+ row=-1;
+ if(data_->identifyTopLevelNode(parentNode,&server,row))
+ {
+ int serverAttrNum=server->attrNum();
+
+ //qDebug() << "PARENT 1" << child << server->realServer()->name().c_str();
+ return createIndex(serverAttrNum+row,0,server);
+ }
+#endif
+ }
+ //The parent is a non topLevel node (non-suite): its internal pointer
+ //is its parent (i.e.. the grandparent)
+ else if(VTreeNode *grandParentNode=parentNode->parent())
+ {
+ int num=grandParentNode->attrNum()+grandParentNode->indexOfChild(parentNode);
+
+ //qDebug() << "PARENT 2" << child << grandParentNode->node()->name().c_str() << num;
+ return createIndex(num,0,grandParentNode);
+ }
+ }
+
+ return QModelIndex();
+}
+
+//----------------------------------------------
+//
+// Server to index mapping and lookup
+//
+//----------------------------------------------
+
+bool TreeNodeModel::isServer(const QModelIndex & index) const
+{
+ //For the servers the internal pointer is NULL
+ return (index.isValid() && index.internalPointer() == NULL);
+}
+
+bool TreeNodeModel::isNode(const QModelIndex & index) const
+{
+ return (indexToNode(index) != NULL);
+}
+
+bool TreeNodeModel::isAttribute(const QModelIndex & index) const
+{
+ return (index.isValid() && !isServer(index) && !isNode(index));
+}
+
+ServerHandler* TreeNodeModel::indexToServerHandler(const QModelIndex & index) const
+{
+ //For servers the internal id is a null pointer
+ if(index.isValid())
+ {
+ if(index.internalPointer() == NULL)
+ return data_->serverHandler(index.row());
+ }
+
+ return NULL;
+}
+
+VTreeServer* TreeNodeModel::indexToServer(const QModelIndex & index) const
+{
+ //For servers the internal id is a null pointer
+ if(index.isValid())
+ {
+ if(index.internalPointer() == NULL)
+ return data_->server(index.row())->treeServer();
+ }
+
+ return NULL;
+}
+
+VTreeServer* TreeNodeModel::nameToServer(const std::string& name) const
+{
+ VModelServer* ms=data_->server(name);
+ return (ms)?ms->treeServer():NULL;
+}
+
+QModelIndex TreeNodeModel::serverToIndex(ServerHandler* server) const
+{
+ //For servers the internal id is set to their position in servers_ + 1
+ int i;
+ if((i=data_->indexOfServer(server))!= -1)
+ return createIndex(i,0,(void*)NULL);
+
+ return QModelIndex();
+}
+
+QModelIndex TreeNodeModel::serverToIndex(VModelServer* server) const
+{
+ //For servers the internal id is set to their position in servers_ + 1
+ int i;
+ if((i=data_->indexOfServer(server))!= -1)
+ return createIndex(i,0,(void*)NULL);
+
+ return QModelIndex();
+}
+
+//----------------------------------------------
+//
+// Node to index mapping and lookup
+//
+//----------------------------------------------
+
+VTreeNode* TreeNodeModel::indexToNode( const QModelIndex & index) const
+{
+ //If it is not a sever ...
+ if(index.isValid() && !isServer(index))
+ {
+ //If the internal pointer is a server it is either a server attribute or a
+ //top level node (suite)
+
+ if(VModelServer *mserver=data_->server(index.internalPointer()))
+ {
+ VTreeServer* server=mserver->treeServer();
+ Q_ASSERT(server);
+
+ int serverAttNum=server->tree()->attrNum(atts_);
+
+ //It is an attribute
+ if(index.row() < serverAttNum)
+ {
+ return NULL;
+ }
+ //It is a top level node
+ else
+ {
+ return server->tree()->childAt(index.row()-serverAttNum);
+ }
+ }
+
+ //Otherwise the internal pointer points to the parent node.
+ else if(VTreeNode *parentNode=static_cast<VTreeNode*>(index.internalPointer()))
+ {
+ int attNum=parentNode->attrNum(atts_);
+ if(index.row() >= attNum)
+ {
+ return parentNode->childAt(index.row()-attNum);
+ }
+ }
+ }
+
+ return NULL;
+}
+
+//Find the index for the node! The VNode can be a server as well!!!
+QModelIndex TreeNodeModel::nodeToIndex(const VNode* node, int column) const
+{
+ if(!node)
+ return QModelIndex();
+
+ //This is a server!!!
+ if(node->isServer())
+ {
+ return serverToIndex(node->server());
+ }
+ //If the node is toplevel node (suite).
+ else if(node->isTopLevel())
+ {
+ if(VModelServer *mserver=data_->server(node->server()))
+ {
+ VTreeServer* server=mserver->treeServer();
+ Q_ASSERT(server);
+
+ if(VTreeNode* tn=server->tree()->find(node))
+ {
+ int row=tn->indexInParent();
+ Q_ASSERT(tn->parent() == server->tree());
+ Q_ASSERT(row >=0);
+ row+=server->tree()->attrNum(atts_);
+ return createIndex(row,column,server);
+ }
+ }
+ }
+
+ //Other nodes
+ else if(VNode *parentNode=node->parent())
+ {
+ if(VModelServer *mserver=data_->server(node->server()))
+ {
+ VTreeServer* server=mserver->treeServer();
+ Q_ASSERT(server);
+
+ if(VTreeNode* tn=server->tree()->find(node))
+ {
+ VTreeNode* tnParent=tn->parent();
+ Q_ASSERT(tnParent);
+ Q_ASSERT(tnParent->vnode() == parentNode);
+ int row=tnParent->indexOfChild(tn);
+ row+=tnParent->attrNum(atts_);
+ return createIndex(row,column,tnParent);
+ }
+ }
+ }
+
+ return QModelIndex();
+}
+
+//Find the index for the node
+QModelIndex TreeNodeModel::nodeToIndex(const VTreeNode* node, int column) const
+{
+ if(!node)
+ return QModelIndex();
+
+ //It is a server
+ if(node->parent() == 0)
+ {
+ VTreeServer *server=node->server();
+ Q_ASSERT(server);
+ return serverToIndex(server);
+ }
+ else if(node->isTopLevel())
+ {
+ VTree *vt=node->root();
+ Q_ASSERT(vt);
+ Q_ASSERT(vt == node->parent());
+ int row=vt->indexOfChild(node);
+ if(row != -1)
+ {
+ row+=vt->attrNum(atts_);
+ return createIndex(row,column,vt->server());
+ }
+
+ }
+ if(VTreeNode *parentNode=node->parent())
+ {
+ int row=parentNode->indexOfChild(node);
+ if(row != -1)
+ {
+ row+=parentNode->attrNum(atts_);
+ return createIndex(row,column,parentNode);
+ }
+ }
+
+ return QModelIndex();
+
+}
+
+//Find the index for the node when we know what the server is!
+QModelIndex TreeNodeModel::nodeToIndex(VTreeServer* server,const VTreeNode* node, int column) const
+{
+ if(!node)
+ return QModelIndex();
+
+ //If the node is toplevel node (suite).
+ if(node->isTopLevel())
+ {
+ Q_ASSERT(node->parent() == server->tree());
+ int row=server->tree()->indexOfChild(node);
+ Q_ASSERT(row >=0);
+
+ row+=server->tree()->attrNum(atts_);
+ return createIndex(row,column,server);
+ }
+ //Other nodes
+ else if(VTreeNode *parentNode=node->parent())
+ {
+ int row=parentNode->indexOfChild(node);
+ if(row != -1)
+ {
+ row+=parentNode->attrNum(atts_);
+ return createIndex(row,column,parentNode);
+ }
+ }
+
+ return QModelIndex();
+
+}
+
+//------------------------------------------------------------------
+// Create info object to index. It is used to identify nodes in
+// the tree all over in the programme outside the view.
+//------------------------------------------------------------------
+
+VInfo_ptr TreeNodeModel::nodeInfo(const QModelIndex& index)
+{
+ //For invalid index no info is created.
+ if(!index.isValid())
+ {
+ VInfo_ptr res;
+ return res;
+ }
+
+ //Check if the node is a server
+ if(ServerHandler *s=indexToServerHandler(index))
+ {
+ return VInfoServer::create(s);
+ }
+
+
+ //If the internal pointer is a server it is either a server attribute or a
+ //top level node (suite)
+ if(VModelServer *mserver=data_->server(index.internalPointer()))
+ {
+ VTreeServer *server=mserver->treeServer();
+ Q_ASSERT(server);
+
+ int serverAttNum=server->tree()->attrNum(atts_);
+
+ //It is a top level node
+ if(index.row() >= serverAttNum)
+ {
+ VNode *n=server->tree()->childAt(index.row()-serverAttNum)->vnode();
+ return VInfoNode::create(n);
+ }
+ else
+ {
+ //TODO: serverattribute
+ }
+ }
+
+ //Otherwise the internal pointer points to the parent node
+ else if(VTreeNode *parentNode=static_cast<VTreeNode*>(index.internalPointer()))
+ {
+ int attNum=parentNode->attrNum(atts_);
+
+ //It is a node
+ if(index.row() >= attNum)
+ {
+ VNode *n=parentNode->childAt(index.row()-attNum)->vnode();
+ return VInfoNode::create(n);
+ }
+ //It is an attribute
+ else
+ {
+ int realAttrRow=parentNode->attrRow(index.row(),atts_);
+ Q_ASSERT(realAttrRow >= 0);
+
+ VInfo_ptr p=VInfoAttribute::create(parentNode->vnode(),realAttrRow);
+ qDebug() << p->isAttribute() << p->attribute() << p->server() << p->node();
+ return p;
+ }
+ }
+
+ VInfo_ptr res;
+ return res;
+}
+
+//----------------------------------------
+// Slots
+//----------------------------------------
+
+//Server is about to be added
+void TreeNodeModel::slotServerAddBegin(int row)
+{
+ beginInsertRows(QModelIndex(),row,row);
+}
+
+//Addition of the new server has finished
+void TreeNodeModel::slotServerAddEnd()
+{
+ endInsertRows();
+}
+
+//Server is about to be removed
+void TreeNodeModel::slotServerRemoveBegin(VModelServer* server,int /*nodeNum*/)
+{
+#ifdef _UI_TREENODEMODEL_DEBUG
+ UserMessage::debug("TreeNodeModel::slotServerRemoveBegin -->");
+#endif
+
+ int row=data_->indexOfServer(server);
+ Q_ASSERT(row >= 0);
+
+#ifdef _UI_TREENODEMODEL_DEBUG
+ UserMessage::debug(" row: " + QString::number(row).toStdString());
+#endif
+ beginRemoveRows(QModelIndex(),row,row);
+}
+
+//Removal of the server has finished
+void TreeNodeModel::slotServerRemoveEnd(int /*nodeNum*/)
+{
+#ifdef _UI_TREENODEMODEL_DEBUG
+ UserMessage::debug("TreeNodeModel::slotServerRemoveEnd -->");
+#endif
+
+ endRemoveRows();
+}
+
+void TreeNodeModel::slotDataChanged(VModelServer* server)
+{
+ QModelIndex idx=serverToIndex(server);
+ Q_EMIT dataChanged(idx,idx);
+}
+
+//The node changed (it status etc)
+void TreeNodeModel::slotNodeChanged(VTreeServer* server,const VTreeNode* node)
+{
+ if(!node)
+ return;
+
+ QModelIndex index=nodeToIndex(server,node,0);
+
+ if(!index.isValid())
+ return;
+
+ Q_EMIT dataChanged(index,index);
+}
+
+//One of the attributes of the node changed. The total number of the
+//attributes is the same.
+void TreeNodeModel::slotAttributesChanged(VTreeServer* server,const VTreeNode* node)
+{
+ if(!node)
+ return;
+
+ //Find the index of the node.
+ QModelIndex parent=nodeToIndex(server,node,0);
+ if(!parent.isValid())
+ return;
+
+ //Find out the indexes for all the attributes. For an attribute
+ //the internal pointer of the index points to the parent VNode.
+ QModelIndex idx1=index(0,0,parent);
+ QModelIndex idx2=index(node->attrNum(atts_)-1,0,parent);
+
+ Q_EMIT dataChanged(idx1,idx2);
+}
+
+//Attributes were added or removed
+void TreeNodeModel::slotBeginAddRemoveAttributes(VTreeServer* server,const VTreeNode* node,int currentNum,int cachedNum)
+{
+ int diff=currentNum-cachedNum;
+ if(diff==0)
+ return;
+
+ //Find the index of the node. This call does not use the
+ //number of attributes of the node so it is safe.
+ QModelIndex parent=nodeToIndex(server,node,0);
+ if(!parent.isValid())
+ return;
+
+ //At this point the model state is based on cachedNum!!!!
+ //So VNode::attr() must return cachedNum and we need to pretend we have
+ //cachedNum number of attributes
+
+ //Insertion
+ if(diff > 0)
+ {
+ //We add extra rows to the end of the attributes
+ beginInsertRows(parent,cachedNum,cachedNum+diff-1);
+ }
+ //Deletion
+ else if(diff <0)
+ {
+ //We remove rows from the end
+ beginRemoveRows(parent,cachedNum+diff,cachedNum-1);
+ }
+
+ //At this point the model state is based on currentNum!!!!
+}
+
+//Attributes were added or removed
+void TreeNodeModel::slotEndAddRemoveAttributes(VTreeServer* server,const VTreeNode* node,int currentNum,int cachedNum)
+{
+ int diff=currentNum-cachedNum;
+ if(diff==0)
+ return;
+
+ //Find the index of the node. This call does not use the
+ //number of attributes of the node so it is safe.
+ QModelIndex parent=nodeToIndex(server,node,0);
+ if(!parent.isValid())
+ return;
+
+ //At this point the model state is based on currentNum!!!!
+
+ //Insertion
+ if(diff > 0)
+ {
+ endInsertRows();
+ }
+ //Deletion
+ else if(diff <0)
+ {
+ endRemoveRows();
+ }
+
+ //We need to update all the attributes to reflect the change!
+ //(Since we do not have information about what attribute was actually added
+ //we always add or remove attributes at the end of the attribute list!!! Then the
+ //call below will update all the attributes of the node in the tree).
+ slotAttributesChanged(server,node);
+}
+
+//The server scan has started (to populate the tree). At this point the tree is empty only containing the
+//root node. Num tells us the number of children nodes (aka suites) the root node will contain.
+void TreeNodeModel::slotBeginServerScan(VModelServer* server,int num)
+{
+ assert(active_ == true);
+
+ QModelIndex idx=serverToIndex(server);
+
+ //At this point the server node does not have any rows in the model!!!
+ if(idx.isValid() && num >0)
+ {
+ beginInsertRows(idx,0,num-1);
+ }
+}
+
+//The server scan has finished. The tree is fully populated.
+void TreeNodeModel::slotEndServerScan(VModelServer* server,int num)
+{
+ assert(active_ == true);
+
+ QModelIndex idx=serverToIndex(server);
+ if(idx.isValid() && num >0)
+ {
+ beginInsertRows(idx,0,num-1);
+ endInsertRows();
+ }
+
+ VTreeServer *ts=server->treeServer();
+ Q_ASSERT(ts);
+ Q_EMIT scanEnded(ts->tree());
+}
+
+//The server clear has started. It well remove all the nodes except the root node.
+//So we need to remove all the rows belonging to the rootnode.
+void TreeNodeModel::slotBeginServerClear(VModelServer* server,int)
+{
+ assert(active_ == true);
+
+ QModelIndex idx=serverToIndex(server);
+
+ if(idx.isValid())
+ {
+ VTreeServer *ts=server->treeServer();
+ Q_ASSERT(ts);
+ Q_EMIT clearBegun(ts->tree());
+
+ //We removes the attributes as well!!!
+ int num=rowCount(idx);
+ beginRemoveRows(idx,0,num-1);
+ }
+}
+//The server clear has finished. The tree is empty only containing the rootnode
+void TreeNodeModel::slotEndServerClear(VModelServer* server,int)
+{
+ assert(active_ == true);
+ endRemoveRows();
+}
+
+void TreeNodeModel::slotBeginFilterUpdateRemove(VTreeServer* server,const VTreeNode* topChange,int totalRows)
+{
+ Q_ASSERT(topChange);
+ Q_ASSERT(!topChange->isRoot());
+
+ QModelIndex idx=nodeToIndex(server,topChange);
+ int attrNum=topChange->attrNum(atts_);
+ int chNum=topChange->numOfChildren();
+ int totalNum=attrNum+chNum;
+
+ Q_ASSERT(totalNum == totalRows);
+ Q_ASSERT(attrNum >=0);
+ Q_ASSERT(chNum >=0);
+
+ if(totalRows >0)
+ {
+ Q_EMIT filterUpdateRemoveBegun(topChange);
+ beginRemoveRows(idx,attrNum,attrNum+chNum-1);
+ }
+}
+
+void TreeNodeModel::slotEndFilterUpdateRemove(VTreeServer* /*server*/,const VTreeNode* topChange,int totalRows)
+{
+ Q_ASSERT(!topChange->isRoot());
+
+ if(totalRows >0)
+ {
+ endRemoveRows();
+ }
+}
+
+void TreeNodeModel::slotBeginFilterUpdateAdd(VTreeServer* server,const VTreeNode* topChange,int chNum)
+{
+ Q_ASSERT(topChange);
+ Q_ASSERT(!topChange->isRoot());
+
+ QModelIndex idx=nodeToIndex(server,topChange);
+ int attrNum=topChange->attrNum(atts_);
+ //int totalNum=attrNum+chNum;
+
+ Q_ASSERT(attrNum >=0);
+ Q_ASSERT(chNum >=0);
+
+ if(chNum >0)
+ {
+ beginInsertRows(idx,attrNum,attrNum+chNum-1);
+ }
+}
+
+void TreeNodeModel::slotEndFilterUpdateAdd(VTreeServer* /*server*/,const VTreeNode* topChange,int chNum)
+{
+ Q_ASSERT(topChange);
+ Q_ASSERT(!topChange->isRoot());
+
+ if(chNum >0)
+ {
+ endInsertRows();
+ }
+
+ Q_EMIT filterUpdateAddEnded(topChange);
+}
+
+
diff --git a/Viewer/src/TreeNodeModel.hpp b/Viewer/src/TreeNodeModel.hpp
new file mode 100644
index 0000000..64cfa0e
--- /dev/null
+++ b/Viewer/src/TreeNodeModel.hpp
@@ -0,0 +1,117 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef TREENODEMODEL_H
+#define TREENODEMODEL_H
+
+#include <QAbstractItemModel>
+
+#include "AbstractNodeModel.hpp"
+#include "Node.hpp"
+#include "VAttributeType.hpp"
+#include "Viewer.hpp"
+#include "VInfo.hpp"
+
+class AttributeFilter;
+class NodeFilterDef;
+class ServerFilter;
+class ServerHandler;
+class VModelServer;
+class VTreeModelData;
+class VTreeNode;
+class VTreeServer;
+
+class TreeNodeModel : public AbstractNodeModel
+{
+Q_OBJECT
+
+public:
+ TreeNodeModel(ServerFilter* serverFilter,NodeFilterDef* filterDef,
+ AttributeFilter *atts,IconFilter* icons,QObject *parent=0);
+
+ int columnCount (const QModelIndex& parent = QModelIndex() ) const;
+ int rowCount (const QModelIndex& parent = QModelIndex() ) const;
+
+ Qt::ItemFlags flags ( const QModelIndex & index) const;
+ QVariant data (const QModelIndex& , int role = Qt::DisplayRole ) const;
+ QVariant headerData(int,Qt::Orientation,int role = Qt::DisplayRole ) const;
+
+ QModelIndex index (int, int, const QModelIndex& parent = QModelIndex() ) const;
+ QModelIndex parent (const QModelIndex & ) const;
+
+ QModelIndex nodeToIndex(const VTreeNode*,int column=0) const;
+ QModelIndex nodeToIndex(const VNode*,int column=0) const;
+ VTreeServer* indexToServer(const QModelIndex & index) const;
+ VTreeServer* nameToServer(const std::string&) const;
+ VInfo_ptr nodeInfo(const QModelIndex& index);
+
+ void setEnableServerToolTip(bool st) {serverToolTip_=st;}
+ void setEnableNodeToolTip(bool st) {nodeToolTip_=st;}
+ void setEnableAttributeToolTip(bool st) {attributeToolTip_=st;}
+
+ VModelData* data() const;
+
+public Q_SLOTS:
+ void slotServerAddBegin(int row);
+ void slotServerAddEnd();
+ void slotServerRemoveBegin(VModelServer*,int);
+ void slotServerRemoveEnd(int);
+
+ void slotNodeChanged(VTreeServer*,const VTreeNode*);
+ void slotAttributesChanged(VTreeServer*,const VTreeNode*);
+ void slotBeginAddRemoveAttributes(VTreeServer*,const VTreeNode*,int,int);
+ void slotEndAddRemoveAttributes(VTreeServer*,const VTreeNode*,int,int);
+ void slotBeginFilterUpdateRemove(VTreeServer*,const VTreeNode*,int);
+ void slotEndFilterUpdateRemove(VTreeServer*,const VTreeNode*,int);
+ void slotBeginFilterUpdateAdd(VTreeServer*,const VTreeNode*,int);
+ void slotEndFilterUpdateAdd(VTreeServer*,const VTreeNode*,int);
+
+ //void slotResetBranch(VModelServer*,const VNode*);
+ void slotDataChanged(VModelServer*);
+ void slotBeginServerScan(VModelServer* server,int);
+ void slotEndServerScan(VModelServer* server,int);
+ void slotBeginServerClear(VModelServer* server,int);
+ void slotEndServerClear(VModelServer* server,int);
+
+Q_SIGNALS:
+ void clearBegun(const VTreeNode*);
+ void scanEnded(const VTreeNode*);
+ void filterUpdateRemoveBegun(const VTreeNode*);
+ void filterUpdateAddEnded(const VTreeNode*);
+ void filterChangeBegun();
+ void filterChangeEnded();
+
+private:
+ bool isServer(const QModelIndex & index) const;
+ bool isNode(const QModelIndex & index) const;
+ bool isAttribute(const QModelIndex & index) const;
+
+ ServerHandler* indexToServerHandler(const QModelIndex & index) const;
+ QModelIndex serverToIndex(VModelServer* server) const;
+ QModelIndex serverToIndex(ServerHandler*) const;
+
+ QModelIndex nodeToIndex(VTreeServer*,const VTreeNode*,int column=0) const;
+ VTreeNode* indexToNode( const QModelIndex & index) const;
+
+ QVariant serverData(const QModelIndex& index,int role) const;
+ QVariant nodeData(const QModelIndex& index,int role) const;
+ QVariant attributesData(const QModelIndex& index,int role) const;
+
+ //Attribute filter
+ VTreeModelData* data_;
+ AttributeFilter* atts_;
+ IconFilter* icons_;
+
+ bool serverToolTip_;
+ bool nodeToolTip_;
+ bool attributeToolTip_;
+};
+
+
+#endif
diff --git a/Viewer/src/TreeNodeView.cpp b/Viewer/src/TreeNodeView.cpp
new file mode 100644
index 0000000..f760a9f
--- /dev/null
+++ b/Viewer/src/TreeNodeView.cpp
@@ -0,0 +1,656 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "TreeNodeView.hpp"
+
+#include <QApplication>
+#include <QDebug>
+#include <QHeaderView>
+#include <QPalette>
+#include <QScrollBar>
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+#include <QGuiApplication>
+#endif
+
+#include "ActionHandler.hpp"
+#include "Animation.hpp"
+#include "AttributeEditor.hpp"
+#include "ExpandState.hpp"
+#include "TableNodeSortModel.hpp"
+#include "PropertyMapper.hpp"
+#include "TreeNodeModel.hpp"
+#include "TreeNodeViewDelegate.hpp"
+#include "VNode.hpp"
+#include "VModelData.hpp"
+#include "VTree.hpp"
+
+TreeNodeView::TreeNodeView(TreeNodeModel* model,NodeFilterDef* filterDef,QWidget* parent) :
+ QTreeView(parent),
+ NodeViewBase(filterDef),
+ model_(model),
+ needItemsLayout_(false),
+ defaultIndentation_(indentation()),
+ prop_(NULL)
+{
+ setProperty("style","nodeView");
+ setProperty("view","tree");
+
+ expandState_=new ExpandState(this,model_);
+ actionHandler_=new ActionHandler(this);
+
+ //Set the model.
+ setModel(model_);
+
+ //Create delegate to the view
+ delegate_=new TreeNodeViewDelegate(this);
+ setItemDelegate(delegate_);
+
+ connect(delegate_,SIGNAL(sizeHintChangedGlobal()),
+ this,SLOT(slotSizeHintChangedGlobal()));
+
+ //setRootIsDecorated(false);
+ setAllColumnsShowFocus(true);
+ //setUniformRowHeights(true);
+ setMouseTracking(true);
+ setSelectionMode(QAbstractItemView::ExtendedSelection);
+
+ //!!!!We need to do it because:
+ //The background colour between the view's left border and the nodes cannot be
+ //controlled by delegates or stylesheets. It always takes the QPalette::Highlight
+ //colour from the palette. Here we set this to transparent so that Qt could leave
+ //this area empty and we will fill it appropriately in our delegate.
+ QPalette pal=palette();
+ pal.setColor(QPalette::Highlight,QColor(128,128,128,0));//Qt::transparent);
+ setPalette(pal);
+
+ //Hide header
+ header()->hide();
+
+ //Context menu
+ setContextMenuPolicy(Qt::CustomContextMenu);
+
+ connect(this, SIGNAL(customContextMenuRequested(const QPoint &)),
+ this, SLOT(slotContextMenu(const QPoint &)));
+
+ //Selection
+ connect(this,SIGNAL(clicked(const QModelIndex&)),
+ this,SLOT(slotSelectItem(const QModelIndex)));
+
+ connect(this,SIGNAL(doubleClicked(const QModelIndex&)),
+ this,SLOT(slotDoubleClickItem(const QModelIndex)));
+
+ //expandAll();
+
+ //Properties
+ std::vector<std::string> propVec;
+ propVec.push_back("view.tree.indentation");
+ propVec.push_back("view.tree.background");
+ propVec.push_back("view.tree.drawBranchLine");
+ propVec.push_back("view.tree.serverToolTip");
+ propVec.push_back("view.tree.nodeToolTip");
+ propVec.push_back("view.tree.attributeToolTip");
+ prop_=new PropertyMapper(propVec,this);
+
+ //Initialise indentation
+ Q_ASSERT(prop_->find("view.tree.indentation"));
+ adjustIndentation(prop_->find("view.tree.indentation")->value().toInt());
+
+ //Init stylesheet related properties
+ Q_ASSERT(prop_->find("view.tree.background"));
+ adjustBackground(prop_->find("view.tree.background")->value().value<QColor>(),false);
+ Q_ASSERT(prop_->find("view.tree.drawBranchLine"));
+ adjustBranchLines(prop_->find("view.tree.drawBranchLine")->value().toBool(),false);
+ adjustStyleSheet();
+
+ //Adjust tooltip
+ Q_ASSERT(prop_->find("view.tree.serverToolTip"));
+ adjustServerToolTip(prop_->find("view.tree.serverToolTip")->value().toBool());
+
+ Q_ASSERT(prop_->find("view.tree.nodeToolTip"));
+ adjustNodeToolTip(prop_->find("view.tree.nodeToolTip")->value().toBool());
+
+ Q_ASSERT(prop_->find("view.tree.attributeToolTip"));
+ adjustAttributeToolTip(prop_->find("view.tree.attributeToolTip")->value().toBool());
+}
+
+TreeNodeView::~TreeNodeView()
+{
+ delete expandState_;
+ delete actionHandler_;
+ delete prop_;
+}
+
+#if 0
+void TreeNodeView::setModel(NodeFilterModel *model)
+{
+ model_= model;
+
+ //Set the model.
+ QTreeView::setModel(model_);
+}
+#endif
+
+QWidget* TreeNodeView::realWidget()
+{
+ return this;
+}
+
+//Collects the selected list of indexes
+QModelIndexList TreeNodeView::selectedList()
+{
+ QModelIndexList lst;
+ Q_FOREACH(QModelIndex idx,selectedIndexes())
+ if(idx.column() == 0)
+ lst << idx;
+ return lst;
+}
+
+void TreeNodeView::slotSelectItem(const QModelIndex&)
+{
+ QModelIndexList lst=selectedIndexes();
+ if(lst.count() > 0)
+ {
+ VInfo_ptr info=model_->nodeInfo(lst.front());
+ if(info)
+ {
+ Q_EMIT selectionChanged(info);
+ }
+ }
+}
+VInfo_ptr TreeNodeView::currentSelection()
+{
+ QModelIndexList lst=selectedIndexes();
+ if(lst.count() > 0)
+ {
+ return model_->nodeInfo(lst.front());
+ }
+ return VInfo_ptr();
+}
+
+void TreeNodeView::currentSelection(VInfo_ptr info)
+{
+ QModelIndex idx=model_->infoToIndex(info);
+ if(idx.isValid())
+ {
+ setCurrentIndex(idx);
+ Q_EMIT selectionChanged(info);
+ }
+}
+
+void TreeNodeView::slotSetCurrent(VInfo_ptr info)
+{
+ QModelIndex idx=model_->infoToIndex(info);
+ if(idx.isValid())
+ {
+ setCurrentIndex(idx);
+ Q_EMIT selectionChanged(info);
+ }
+}
+
+void TreeNodeView::selectFirstServer()
+{
+ QModelIndex idx=model_->index(0,0);
+ if(idx.isValid())
+ {
+ setCurrentIndex(idx);
+ VInfo_ptr info=model_->nodeInfo(idx);
+ Q_EMIT selectionChanged(info);
+ }
+}
+
+
+void TreeNodeView::slotDoubleClickItem(const QModelIndex& idx)
+{
+ VInfo_ptr info=model_->nodeInfo(idx);
+ if(info && info->isAttribute())
+ {
+ slotViewCommand(info,"edit");
+ }
+}
+
+void TreeNodeView::slotContextMenu(const QPoint &position)
+{
+ QModelIndexList lst=selectedList();
+ //QModelIndex index=indexAt(position);
+ QPoint scrollOffset(horizontalScrollBar()->value(),verticalScrollBar()->value());
+
+ handleContextMenu(indexAt(position),lst,mapToGlobal(position),position+scrollOffset,this);
+}
+
+
+void TreeNodeView::handleContextMenu(QModelIndex indexClicked,QModelIndexList indexLst,QPoint globalPos,QPoint widgetPos,QWidget *widget)
+{
+ //Node actions
+ if(indexClicked.isValid() && indexClicked.column() == 0) //indexLst[0].isValid() && indexLst[0].column() == 0)
+ {
+ //qDebug() << "context menu" << indexClicked;
+
+ std::vector<VInfo_ptr> nodeLst;
+ for(int i=0; i < indexLst.count(); i++)
+ {
+ VInfo_ptr info=model_->nodeInfo(indexLst[i]);
+ if(info && !info->isEmpty())
+ nodeLst.push_back(info);
+ }
+
+ actionHandler_->contextMenu(nodeLst,globalPos);
+ }
+
+ //Desktop actions
+ else
+ {
+ }
+}
+
+void TreeNodeView::slotViewCommand(VInfo_ptr info,QString cmd)
+{
+ if(cmd == "expand")
+ {
+ QModelIndex idx=model_->infoToIndex(info);
+ if(idx.isValid())
+ {
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+ QGuiApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+#endif
+ expandAll(idx);
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+ QGuiApplication::restoreOverrideCursor();
+#endif
+
+ }
+ }
+ else if(cmd == "collapse")
+ {
+ QModelIndex idx=model_->infoToIndex(info);
+ if(idx.isValid())
+ {
+ collapseAll(idx);
+ }
+ }
+
+ else if(cmd == "edit")
+ {
+ if(info && info->isAttribute())
+ {
+ AttributeEditor::edit(info,this);
+ }
+ }
+
+ /*if(cmd == "set_as_root")
+ {
+ model_->setRootNode(nodeLst.at(0)->node());
+ expandAll();
+ }*/
+}
+
+void TreeNodeView::reload()
+{
+ //model_->reload();
+ //expandAll();
+}
+
+void TreeNodeView::rerender()
+{
+ if(needItemsLayout_)
+ {
+ doItemsLayout();
+ needItemsLayout_=false;
+ }
+ else
+ {
+ viewport()->update();
+ }
+}
+
+void TreeNodeView::slotRerender()
+{
+ rerender();
+}
+
+void TreeNodeView::slotRepaint(Animation* an)
+{
+ if(!an)
+ return;
+
+ Q_FOREACH(VNode* n,an->targets())
+ {
+ update(model_->nodeToIndex(n));
+ }
+}
+
+
+void TreeNodeView::slotSizeHintChangedGlobal()
+{
+ needItemsLayout_=true;
+}
+
+void TreeNodeView::adjustStyleSheet()
+{
+ QString sh;
+ if(styleSheet_.contains("bg"))
+ sh+=styleSheet_["bg"];
+ if(styleSheet_.contains("branch"))
+ sh+=styleSheet_["branch"];
+
+ qDebug() << "stylesheet" << sh;
+
+ setStyleSheet(sh);
+}
+
+void TreeNodeView::adjustIndentation(int offset)
+{
+ if(offset >=0)
+ {
+ setIndentation(defaultIndentation_+offset);
+ delegate_->setIndentation(indentation());
+ }
+}
+
+void TreeNodeView::adjustBackground(QColor col,bool adjust)
+{
+ if(col.isValid())
+ {
+ styleSheet_["bg"]="QTreeView { background : " + col.name() + ";}";
+
+ if(adjust)
+ adjustStyleSheet();
+ }
+}
+
+void TreeNodeView::adjustBranchLines(bool st,bool adjust)
+{
+ if(styleSheet_.contains("branch"))
+ {
+ bool oriSt=styleSheet_["branch"].contains("url(:");
+ if(oriSt == st)
+ return;
+ }
+
+ QString vline((st)?"url(:/viewer/tree_vline.png) 0":"none");
+ QString bmore((st)?"url(:/viewer/tree_branch_more.png) 0":"none");
+ QString bend((st)?"url(:/viewer/tree_branch_end.png) 0":"none");
+
+ styleSheet_["branch"]="QTreeView::branch:has-siblings:!adjoins-item { border-image: " + vline + ";}" \
+ "QTreeView::branch:!has-children:has-siblings:adjoins-item {border-image: " + bmore + ";}" \
+ "QTreeView::branch:!has-children:!has-siblings:adjoins-item {border-image: " + bend + ";}";
+
+ if(adjust)
+ adjustStyleSheet();
+}
+
+void TreeNodeView::adjustServerToolTip(bool st)
+{
+ model_->setEnableServerToolTip(st);
+}
+
+void TreeNodeView::adjustNodeToolTip(bool st)
+{
+ model_->setEnableNodeToolTip(st);
+}
+
+void TreeNodeView::adjustAttributeToolTip(bool st)
+{
+ model_->setEnableAttributeToolTip(st);
+}
+
+void TreeNodeView::notifyChange(VProperty* p)
+{
+ if(p->path() == "view.tree.indentation")
+ {
+ adjustIndentation(p->value().toInt());
+ }
+ else if(p->path() == "view.tree.background")
+ {
+ adjustBackground(p->value().value<QColor>());
+ }
+ else if(p->path() == "view.tree.drawBranchLine")
+ {
+ adjustBranchLines(p->value().toBool());
+ }
+ else if(p->path() == "view.tree.serverToolTip")
+ {
+ adjustServerToolTip(p->value().toBool());
+ }
+ else if(p->path() == "view.tree.nodeToolTip")
+ {
+ adjustNodeToolTip(p->value().toBool());
+ }
+ else if(p->path() == "view.tree.attributeToolTip")
+ {
+ adjustAttributeToolTip(p->value().toBool());
+ }
+}
+
+//====================================================
+// Expand state management
+//====================================================
+
+void TreeNodeView::expandAll(const QModelIndex& idx)
+{
+ expand(idx);
+
+ for(int i=0; i < model_->rowCount(idx); i++)
+ {
+ QModelIndex chIdx=model_->index(i, 0, idx);
+ expandAll(chIdx);
+ }
+}
+
+void TreeNodeView::collapseAll(const QModelIndex& idx)
+{
+ collapse(idx);
+
+ for(int i=0; i < model_->rowCount(idx); i++)
+ {
+ QModelIndex chIdx=model_->index(i, 0, idx);
+ collapseAll(chIdx);
+ }
+}
+
+//Save all
+void TreeNodeView::slotSaveExpand()
+{
+ for(int i=0; i < model_->rowCount(); i++)
+ {
+ QModelIndex serverIdx=model_->index(i, 0);
+ VTreeServer* ts=model_->indexToServer(serverIdx);
+ Q_ASSERT(ts);
+ ExpandStateTree* es=expandState_->add();
+ es->save(ts->tree());
+ }
+
+ VInfo_ptr s=currentSelection();
+ if(s)
+ {
+ expandState_->selection_=s;
+ }
+
+}
+
+void TreeNodeView::slotRestoreExpand()
+{
+ Q_FOREACH(ExpandStateTree* es,expandState_->items())
+ {
+ if(es->root())
+ {
+ VTreeServer* ts=model_->nameToServer(es->root()->name_);
+ if(ts)
+ {
+ es->restore(ts->tree());
+ }
+ }
+ }
+
+ if(expandState_->selection_)
+ {
+ VInfo_ptr s=currentSelection();
+ if(!s)
+ {
+ expandState_->selection_->regainData();
+ if(!expandState_->selection_->server())
+ {
+ expandState_->selection_.reset();
+ }
+ else
+ {
+ currentSelection(expandState_->selection_);
+ }
+ }
+ }
+
+ expandState_->clear();
+}
+
+//Save the expand state for the given node (it can be a server as well)
+void TreeNodeView::slotSaveExpand(const VTreeNode* node)
+{
+ VInfo_ptr s=currentSelection();
+ if(s)
+ {
+ if(node->server()->realServer() == s->server())
+ expandState_->selection_=s;
+ }
+
+
+ ExpandStateTree* es=expandState_->add();
+ es->save(node);
+}
+
+//Save the expand state for the given node (it can be a server as well)
+void TreeNodeView::slotRestoreExpand(const VTreeNode* node)
+{
+ Q_FOREACH(ExpandStateTree* es,expandState_->items())
+ {
+ if(es->rootSameAs(node->vnode()->strName()))
+ {
+ es->restore(node);
+
+ if(expandState_->selection_)
+ {
+ VInfo_ptr s=currentSelection();
+ if(!s)
+ {
+ expandState_->selection_->regainData();
+ if(!expandState_->selection_->server())
+ {
+ expandState_->selection_.reset();
+ }
+ else if(node->server()->realServer() == expandState_->selection_->server())
+ {
+ currentSelection(expandState_->selection_);
+ expandState_->selection_.reset();
+ }
+ }
+ }
+
+ expandState_->remove(es);
+ }
+ }
+}
+
+
+#if 0
+
+//Save the expand state for the given node (it can be a server as well)
+void TreeNodeView::slotSaveExpand(const VNode* node)
+{
+ assert(node);
+
+ expandState_->clear();
+
+ VInfo_ptr s=currentSelection();
+ if(s)
+ {
+ if(node->server() == s->server())
+ expandState_->selection_=s;
+ }
+
+ QModelIndex idx=model_->nodeToIndex(node);
+ if(isExpanded(idx))
+ {
+ expandState_->setRoot(node->strName());
+ saveExpand(expandState_->root(),idx);
+ }
+}
+
+void TreeNodeView::saveExpand(ExpandNode *parentExpand,const QModelIndex& idx)
+{
+ for(int i=0; i < model_->rowCount(idx); i++)
+ {
+ QModelIndex chIdx=model_->index(i, 0, idx);
+
+ if(!isExpanded(chIdx))
+ continue;
+ else
+ {
+ ExpandNode* expand=parentExpand->add(chIdx.data(Qt::DisplayRole).toString().toStdString());
+ saveExpand(expand,chIdx);
+ }
+ }
+}
+
+//Save the expand state for the given node (it can be a server as well)
+void TreeNodeView::slotRestoreExpand(const VNode* node)
+{
+ if(!expandState_->root())
+ return;
+
+ if(node->strName() != expandState_->root()->name_)
+ {
+ expandState_->clear();
+ return;
+ }
+
+ restoreExpand(expandState_->root(),node);
+
+ if(expandState_->selection_)
+ {
+ VInfo_ptr s=currentSelection();
+ if(!s)
+ {
+ expandState_->selection_->regainData();
+ currentSelection(expandState_->selection_);
+ }
+ }
+
+ expandState_->clear();
+}
+
+void TreeNodeView::restoreExpand(ExpandNode *expand,const VNode* node)
+{
+ //Lookup the mnode in the model
+ QModelIndex nodeIdx=model_->nodeToIndex(node);
+ if(nodeIdx != QModelIndex())
+ {
+ setExpanded(nodeIdx,true);
+ }
+ else
+ {
+ return;
+ }
+
+ for(int i=0; i < expand->children_.size(); i++)
+ {
+ ExpandNode *chExpand=expand->children_.at(i);
+ std::string name=chExpand->name_;
+
+ if(VNode *chNode=node->findChild(name))
+ {
+ QModelIndex chIdx=model_->nodeToIndex(chNode);
+ if(chIdx != QModelIndex())
+ {
+ //setExpanded(chIdx,true);
+ restoreExpand(chExpand,chNode);
+ }
+ }
+ }
+}
+
+#endif
diff --git a/Viewer/src/TreeNodeView.hpp b/Viewer/src/TreeNodeView.hpp
new file mode 100644
index 0000000..a5b44fb
--- /dev/null
+++ b/Viewer/src/TreeNodeView.hpp
@@ -0,0 +1,99 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef TreeNodeView_HPP_
+#define TreeNodeView_HPP_
+
+#include <QTreeView>
+
+#include "NodeViewBase.hpp"
+
+#include "VInfo.hpp"
+#include "VProperty.hpp"
+
+class ActionHandler;
+class Animation;
+class ExpandNode;
+class ExpandState;
+class TableNodeSortModel;
+class PropertyMapper;
+class TreeNodeModel;
+class TreeNodeViewDelegate;
+class VTreeNode;
+
+class TreeNodeView : public QTreeView, public NodeViewBase, public VPropertyObserver
+{
+Q_OBJECT
+
+public:
+ explicit TreeNodeView(TreeNodeModel* model,NodeFilterDef* filterDef,QWidget *parent=0);
+ ~TreeNodeView();
+
+ void reload();
+ void rerender();
+ QWidget* realWidget();
+ VInfo_ptr currentSelection();
+ void currentSelection(VInfo_ptr n);
+ void selectFirstServer();
+#if 0
+ void setModel(NodeFilterModel* model);
+#endif
+ void notifyChange(VProperty* p);
+
+ void readSettings(VSettings* vs) {}
+
+public Q_SLOTS:
+ void slotSelectItem(const QModelIndex&);
+ void slotDoubleClickItem(const QModelIndex&);
+ void slotContextMenu(const QPoint &position);
+ void slotViewCommand(VInfo_ptr,QString);
+ void slotSetCurrent(VInfo_ptr);
+ void slotSaveExpand();
+ void slotRestoreExpand();
+ void slotSaveExpand(const VTreeNode* node);
+ void slotRestoreExpand(const VTreeNode* node);
+ void slotRepaint(Animation*);
+ void slotRerender();
+ void slotSizeHintChangedGlobal();
+
+Q_SIGNALS:
+ void selectionChanged(VInfo_ptr);
+ void infoPanelCommand(VInfo_ptr,QString);
+ void dashboardCommand(VInfo_ptr,QString);
+
+protected:
+ QModelIndexList selectedList();
+ void handleContextMenu(QModelIndex indexClicked,QModelIndexList indexLst,QPoint globalPos,QPoint widgetPos,QWidget *widget);
+ void saveExpand(ExpandNode *parentExpand,const QModelIndex& idx);
+ void restoreExpand(ExpandNode *expand,const VNode* node);
+ void adjustIndentation(int);
+ void adjustBackground(QColor col,bool asjustStyleSheet=true);
+ void adjustBranchLines(bool,bool asjustStyleSheet=true);
+ void adjustStyleSheet();
+ void adjustServerToolTip(bool);
+ void adjustNodeToolTip(bool);
+ void adjustAttributeToolTip(bool);
+ void expandAll(const QModelIndex& idx);
+ void collapseAll(const QModelIndex& idx);
+
+ TreeNodeModel* model_;
+ ActionHandler* actionHandler_;
+ ExpandState *expandState_;
+ bool needItemsLayout_;
+ int defaultIndentation_;
+ TreeNodeViewDelegate* delegate_;
+ PropertyMapper* prop_;
+ QMap<QString,QString> styleSheet_;
+};
+
+#endif
+
+
+
diff --git a/Viewer/src/TreeNodeViewDelegate.cpp b/Viewer/src/TreeNodeViewDelegate.cpp
new file mode 100644
index 0000000..8a41124
--- /dev/null
+++ b/Viewer/src/TreeNodeViewDelegate.cpp
@@ -0,0 +1,1058 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "TreeNodeViewDelegate.hpp"
+
+#include <QApplication>
+#include <QDebug>
+#include <QImageReader>
+#include <QLinearGradient>
+#include <QPainter>
+
+#include "AbstractNodeModel.hpp"
+#include "Animation.hpp"
+#include "IconProvider.hpp"
+#include "PropertyMapper.hpp"
+#include "ServerHandler.hpp"
+
+static std::vector<std::string> propVec;
+
+static QColor typeFgColourClassic=QColor(Qt::white);
+static QColor typeBgColourClassic=QColor(150,150,150);
+static QColor childCountColour=QColor(90,91,92);
+
+
+struct NodeShape
+{
+ QColor col_;
+ QPolygon shape_;
+};
+
+struct NodeText
+{
+ QColor fgCol_;
+ QColor bgCol_;
+ QRect br_;
+ QString text_;
+};
+
+struct ServerUpdateData
+{
+ QRect br_;
+ int prevTime_;
+ int nextTime_;
+ QString prevText_;
+ QString nextText_;
+ float prog_;
+};
+
+TreeNodeViewDelegate::TreeNodeViewDelegate(QWidget *parent) :
+ nodeRectRad_(0),
+ drawChildCount_(true),
+ nodeStyle_(ClassicNodeStyle),
+ indentation_(0),
+ drawNodeType_(true),
+ bgCol_(Qt::white)
+{
+ attrFont_=font_;
+ attrFont_.setPointSize(8);
+
+ serverInfoFont_=font_;
+
+ serverInfoFont_=font_;
+ //serverNumFont_.setBold(true);
+
+ suiteNumFont_=font_;
+ //suiteNumFont_.setBold(true);
+
+ abortedReasonFont_=font_;
+ abortedReasonFont_.setBold(true);
+
+ typeFont_=font_;
+ typeFont_.setBold(true);
+ typeFont_.setPointSize(font_.pointSize()-1);
+
+ adjustIconSize();
+
+ //Property
+ if(propVec.empty())
+ {
+ propVec.push_back("view.tree.nodeFont");
+ propVec.push_back("view.tree.attributeFont");
+ propVec.push_back("view.tree.display_child_count");
+ propVec.push_back("view.tree.displayNodeType");
+ propVec.push_back("view.tree.background");
+ propVec.push_back("view.common.node_style");
+ propVec.push_back("view.common.node_gradient");
+
+ //Base settings
+ addBaseSettings(propVec);
+ }
+
+ prop_=new PropertyMapper(propVec,this);
+
+ updateSettings();
+
+ //The parent must be the view!!!
+ animation_=new AnimationHandler(parent);
+}
+
+TreeNodeViewDelegate::~TreeNodeViewDelegate()
+{
+ delete animation_;
+}
+
+/*void TreeNodeViewDelegate::notifyChange(VProperty* p)
+{
+ updateSettings();
+}*/
+
+void TreeNodeViewDelegate::updateSettings()
+{
+ if(VProperty* p=prop_->find("view.common.node_style"))
+ {
+ if(p->value().toString() == "classic")
+ nodeStyle_=ClassicNodeStyle;
+ else
+ nodeStyle_=BoxAndTextNodeStyle;
+ }
+ if(VProperty* p=prop_->find("view.common.node_gradient"))
+ {
+ useStateGrad_=p->value().toBool();
+ }
+
+ if(VProperty* p=prop_->find("view.tree.nodeRectRadius"))
+ {
+ nodeRectRad_=p->value().toInt();
+ }
+ if(VProperty* p=prop_->find("view.tree.nodeFont"))
+ {
+ QFont newFont=p->value().value<QFont>();
+
+ if(font_ != newFont )
+ {
+ font_=newFont;
+ serverInfoFont_=font_;
+ serverNumFont_.setFamily(font_.family());
+ serverNumFont_.setPointSize(font_.pointSize()-1);
+ suiteNumFont_.setFamily(font_.family());
+ suiteNumFont_.setPointSize(font_.pointSize()-1);
+ abortedReasonFont_.setFamily(font_.family());
+ abortedReasonFont_.setPointSize(font_.pointSize());
+ typeFont_.setFamily(font_.family());
+ typeFont_.setPointSize(font_.pointSize()-1);
+ adjustIconSize();
+
+ Q_EMIT sizeHintChangedGlobal();
+ }
+ }
+ if(VProperty* p=prop_->find("view.tree.attributeFont"))
+ {
+ QFont newFont=p->value().value<QFont>();
+
+ if(attrFont_ != newFont)
+ {
+ attrFont_=newFont;
+ Q_EMIT sizeHintChangedGlobal();
+ }
+ }
+
+ if(VProperty* p=prop_->find("view.tree.display_child_count"))
+ {
+ drawChildCount_=p->value().toBool();
+ }
+
+ if(VProperty* p=prop_->find("view.tree.displayNodeType"))
+ {
+ drawNodeType_=p->value().toBool();
+ }
+
+ if(VProperty* p=prop_->find("view.tree.background"))
+ {
+ bgCol_=p->value().value<QColor>();
+ }
+
+ //Update the settings handled by the base class
+ updateBaseSettings();
+}
+
+QSize TreeNodeViewDelegate::sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index ) const
+{
+ QSize size=QStyledItemDelegate::sizeHint(option,index);
+
+ int attLineNum=0;
+ if((attLineNum=index.data(AbstractNodeModel::AttributeLineRole).toInt()) > 0)
+ {
+ QFontMetrics fm(attrFont_);
+ int h=fm.height();
+ if(attLineNum==1)
+ return QSize(size.width(),h+6);
+ else
+ {
+ QStringList lst;
+ for(int i=0; i < attLineNum; i++)
+ lst << "1";
+
+ return QSize(size.width(),fm.size(0,lst.join(QString('\n'))).height()+6);
+ }
+ }
+
+ QFontMetrics fm(font_);
+ int h=fm.height();
+ return QSize(size.width(),h+8);
+}
+
+
+void TreeNodeViewDelegate::paint(QPainter *painter,const QStyleOptionViewItem &option,
+ const QModelIndex& index) const
+{
+ //Background
+ QStyleOptionViewItemV4 vopt(option);
+ initStyleOption(&vopt, index);
+
+ //Both the plastique and fusion styles render the tree expand indicator in the middle of the
+ //indentation rectangle. This rectangle spans as far as the left hand side of the option rect that the
+ //delegate renders into. For large indentations there can be a big gap between the indicator and
+ //rendered item. To avoid it we expand the opt rect to the left to get it closer to the
+ //indicator as much as possible.
+
+ if(indentation_>0)
+ //vopt.rect.setLeft(vopt.rect.x()-indentation_/2 + 10);
+ vopt.rect.setLeft(vopt.rect.x()-indentation_/2 + 5);
+
+ const QStyle *style = vopt.widget ? vopt.widget->style() : QApplication::style();
+ const QWidget* widget = vopt.widget;
+
+ //Save painter state
+ painter->save();
+
+ //Selection - we only do it once
+ /*if(index.column() == 0)
+ {
+ QRect fullRect=QRect(0,option.rect.y(),painter->device()->width(),option.rect.height());
+
+ if(option.state & QStyle::State_Selected)
+ {
+ //QRect fillRect=option.rect.adjusted(0,1,-1,-textRect.height()-1);
+ painter->fillRect(fullRect,selectBrush_);
+ painter->setPen(selectPen_);
+ painter->drawLine(fullRect.topLeft(),fullRect.topRight());
+ painter->drawLine(fullRect.bottomLeft(),fullRect.bottomRight());
+ }
+ else if(option.state & QStyle::State_MouseOver)
+ {
+ //QRect fillRect=option.rect.adjusted(0,1,-1,-1);
+ painter->fillRect(fullRect,hoverBrush_);
+ painter->setPen(hoverPen_);
+ painter->drawLine(fullRect.topLeft(),fullRect.topRight());
+ painter->drawLine(fullRect.bottomLeft(),fullRect.bottomRight());
+ }
+ }*/
+
+ if(index.data(AbstractNodeModel::ConnectionRole).toInt() == 0)
+ {
+ QRect fullRect=QRect(0,vopt.rect.y(),painter->device()->width(),vopt.rect.height());
+ painter->fillRect(fullRect,lostConnectBgBrush_);
+ QRect bandRect=QRect(0,vopt.rect.y(),5,vopt.rect.height());
+ painter->fillRect(bandRect,lostConnectBandBrush_);
+
+ }
+
+ //First column (nodes)
+ if(index.column() == 0)
+ {
+ QVariant tVar=index.data(Qt::DisplayRole);
+ QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &vopt, widget);
+
+ painter->setFont(font_);
+
+ if(tVar.type() == QVariant::String)
+ {
+ QString text=index.data(Qt::DisplayRole).toString();
+ if(index.data(AbstractNodeModel::ServerRole).toInt() ==0)
+ {
+ renderServer(painter,index,vopt,text);
+ }
+ else
+ {
+ renderNode(painter,index,vopt,text);
+ }
+ }
+ //Render attributes
+ else if(tVar.type() == QVariant::StringList)
+ {
+ QStringList lst=tVar.toStringList();
+ if(lst.count() > 0)
+ {
+ QMap<QString,AttributeRendererProc>::const_iterator it=attrRenderers_.find(lst.at(0));
+ if(it != attrRenderers_.end())
+ {
+ AttributeRendererProc a=it.value();
+ (this->*a)(painter,lst,vopt);
+ }
+ }
+
+ }
+ }
+ //rest of the columns
+ else if(index.column() < 3)
+ {
+ QString text=index.data(Qt::DisplayRole).toString();
+ QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &vopt, widget);
+ painter->setPen(Qt::black);
+ painter->drawText(textRect,Qt::AlignLeft | Qt::AlignVCenter,text);
+
+ }
+
+ painter->restore();
+
+ //else
+ // QStyledItemDelegate::paint(painter,option,index);
+}
+
+
+void TreeNodeViewDelegate::renderServer(QPainter *painter,const QModelIndex& index,
+ const QStyleOptionViewItemV4& option,QString text) const
+{
+ ServerHandler* server=static_cast<ServerHandler*>(index.data(AbstractNodeModel::ServerPointerRole).value<void*>());
+ Q_ASSERT(server);
+
+ bool selected=option.state & QStyle::State_Selected;
+ int offset=4;
+
+ QFontMetrics fm(font_);
+ int deltaH=(option.rect.height()-(fm.height()+4))/2;
+
+ //The initial filled rect (we will adjust its width)
+ //QRect fillRect=option.rect.adjusted(offset,1,0,-2);
+ QRect itemRect=option.rect.adjusted(2*offset,deltaH+2,0,-deltaH-2);
+ if(option.state & QStyle::State_Selected)
+ itemRect.adjust(0,0,0,0);
+
+#if 0
+ painter->setPen(QColor(190,190,190));
+ painter->drawLine(0,option.rect.y()+1,painter->device()->width(),option.rect.y()+1);
+ painter->drawLine(0,option.rect.bottom()-1,painter->device()->width(),option.rect.bottom()-1);
+#endif
+#if 0
+
+ QRect progRect(0,itemRect.y()-deltaH,painter->device()->width(),itemRect.height()+2*deltaH);
+ progRect.setWidth(painter->device()->width());
+ painter->setBrush(Qt::NoBrush);
+ painter->setPen(QColor(190,190,190));
+ painter->drawRect(progRect);
+ painter->setBrush(QColor(230,230,230));
+ painter->drawRect(progRect.adjusted(0,0,-progRect.width()*0.4,0));
+#endif
+ int currentRight=itemRect.left();
+
+ NodeShape stateShape;
+ stateShape.col_=index.data(Qt::BackgroundRole).value<QColor>();
+
+ NodeText nodeText;
+ nodeText.text_=text;
+ int textWidth=fm.width(text);
+
+ if(nodeStyle_ == BoxAndTextNodeStyle)
+ {
+ stateShape.shape_=QPolygon(QRect(itemRect.x(),itemRect.y(),itemRect.height(),itemRect.height()));
+ currentRight=stateShape.shape_.boundingRect().right()+offset;
+ nodeText.br_=QRect(currentRight+offset,itemRect.y(),textWidth, itemRect.height());
+ nodeText.fgCol_=QColor(Qt::black);
+ currentRight=nodeText.br_.right();
+ }
+ else
+ {
+ stateShape.shape_=QPolygon(QRect(itemRect.x(),itemRect.y(),textWidth+2*offset+1,itemRect.height()));
+ nodeText.br_=QRect(itemRect.x()+offset,itemRect.y(),textWidth, itemRect.height());
+ nodeText.fgCol_=index.data(Qt::ForegroundRole).value<QColor>();
+ currentRight=stateShape.shape_.boundingRect().right()+offset;
+ }
+
+ //Refresh timer
+ /* bool hasTimer=true;
+ QRect timeRect(currentRight+offset,itemRect.y()-1,itemRect.height()+2,itemRect.height()+2);
+ currentRight=timeRect.right();*/
+
+ //Icons area
+ QList<QPixmap> pixLst;
+ QList<QRect> pixRectLst;
+
+ QVariant va=index.data(AbstractNodeModel::IconRole);
+ if(va.type() == QVariant::List)
+ {
+ QVariantList lst=va.toList();
+ int xp=currentRight+5;
+ int yp=itemRect.center().y()-iconSize_/2;
+ for(int i=0; i < lst.count(); i++)
+ {
+ int id=lst[i].toInt();
+ if(id != -1)
+ {
+ pixLst << IconProvider::pixmap(id,iconSize_);
+ pixRectLst << QRect(xp,yp,pixLst.back().width(),pixLst.back().height());
+ xp+=pixLst.back().width()+iconGap_;
+ }
+ }
+
+ if(!pixRectLst.isEmpty())
+ currentRight=pixRectLst.back().right();
+ }
+
+ //The pixmap (optional)
+ bool hasPix=false;
+ QRect pixRect;
+
+ //The info rectangle (optional)
+ QRect infoRect;
+ QString infoTxt=index.data(AbstractNodeModel::InfoRole).toString();
+ bool hasInfo=(infoTxt.isEmpty() == false);
+
+ if(hasInfo)
+ {
+ //infoFont.setBold(true);
+ fm=QFontMetrics(serverInfoFont_);
+
+ int infoWidth=fm.width(infoTxt);
+ infoRect = nodeText.br_;
+ infoRect.setLeft(currentRight+fm.width('A'));
+ infoRect.setWidth(infoWidth);
+ currentRight=infoRect.right();
+ }
+
+ //The load icon (optional)
+ QRect loadRect;
+ bool hasLoad=index.data(AbstractNodeModel::LoadRole).toBool();
+ Animation* an=0;
+
+ //Update load animation
+ if(hasLoad)
+ {
+ an=animation_->find(Animation::ServerLoadType,true);
+
+ loadRect = QRect(currentRight+fm.width('A'),
+ itemRect.top()+(itemRect.height()-an->scaledSize().height())/2,
+ an->scaledSize().width(),
+ an->scaledSize().height());
+
+ currentRight=loadRect.right();
+
+ //Add this index to the animations
+ //There is no guarantee that this index will be valid in the future!!!
+ an->addTarget(server->vRoot());
+ }
+ //Stops load animation
+ else
+ {
+ if((an=animation_->find(Animation::ServerLoadType,false)) != NULL)
+ an->removeTarget(server->vRoot());
+ }
+
+ //The node number (optional)
+ QRect numRect;
+ QString numTxt;
+ bool hasNum=false;
+
+ if(drawChildCount_)
+ {
+ QVariant va=index.data(AbstractNodeModel::NodeNumRole);
+ hasNum=(va.isNull() == false);
+ if(hasNum)
+ {
+ numTxt="(" + QString::number(va.toInt()) + ")";
+
+ QFontMetrics fmNum(serverNumFont_);
+
+ int numWidth=fmNum.width(numTxt);
+ numRect = nodeText.br_;
+ numRect.setLeft(currentRight+fmNum.width('A'));
+ numRect.setWidth(numWidth);
+ currentRight=numRect.right();
+ }
+ }
+
+ //Update
+ bool hasUpdate=false;
+ ServerUpdateData updateData;
+#if 0
+ if(server)
+ {
+ hasUpdate=true;
+ updateData.br_=QRect(currentRight+3*offset,itemRect.y()-1,0,itemRect.height()+2);
+ updateData.prevTime_=server->secsSinceLastRefresh();
+ updateData.nextTime_=server->secsTillNextRefresh();
+ if(updateData.prevTime_ >=0)
+ {
+ if(updateData.nextTime_ >=0)
+ {
+ updateData.prevText_="-" + formatTime(updateData.prevTime_);
+ updateData.nextText_="+" +formatTime(updateData.nextTime_);
+ updateData.prog_=(static_cast<float>(updateData.prevTime_)/static_cast<float>(updateData.prevTime_+updateData.nextTime_));
+ updateData.br_.setWidth(fm.width("ABCDE")+fm.width(updateData.prevText_)+fm.width(updateData.nextText_)+2*offset);
+ }
+ else
+ {
+ updateData.prevText_="last update: " + formatTime(updateData.prevTime_);
+ updateData.prog_=0;
+ updateData.br_.setWidth(fm.width(updateData.prevText_));
+ }
+ currentRight=updateData.br_.right();
+ }
+ else
+ {
+ hasUpdate=false;
+ }
+ }
+#endif
+
+ //Define clipping
+ int rightPos=currentRight+1;
+ const bool setClipRect = rightPos > option.rect.right();
+ if(setClipRect)
+ {
+ painter->save();
+ painter->setClipRect(option.rect);
+ }
+
+ //Draw state/node rect
+ renderServerCell(painter,stateShape,nodeText,selected);
+
+ //Draw timer
+ /*int remaining=6*60*1000; // server->remainingTimeToRefresh();
+ int total=10*60*1000; //server->refreshPeriod() ;
+ renderTimer(painter,timeRect,remaining,total);*/
+
+ //Draw icons
+ for(int i=0; i < pixLst.count(); i++)
+ {
+ painter->drawPixmap(pixRectLst[i],pixLst[i]);
+ }
+
+ //Draw pixmap if needed
+ if(hasPix)
+ {
+ painter->drawPixmap(pixRect,errPix_);
+ }
+
+ //Draw info
+ if(hasInfo)
+ {
+ painter->setPen(Qt::black);
+ painter->setFont(serverInfoFont_);
+ painter->drawText(infoRect,Qt::AlignLeft | Qt::AlignVCenter,infoTxt);
+ }
+
+ //Draw number
+ if(hasNum)
+ {
+ painter->setPen(childCountColour);
+ painter->setFont(serverNumFont_);
+ painter->drawText(numRect,Qt::AlignLeft | Qt::AlignVCenter,numTxt);
+ }
+
+ //Draw load animation
+ if(hasLoad)
+ {
+ Animation* an=animation_->find(Animation::ServerLoadType,false);
+ if(an)
+ {
+ painter->drawPixmap(loadRect,an->currentPixmap());
+ }
+ }
+#if 0
+ if(hasUpdate)
+ {
+ renderServerUpdate(painter,updateData);
+ }
+#endif
+ if(setClipRect)
+ {
+ painter->restore();
+ }
+}
+
+
+void TreeNodeViewDelegate::renderNode(QPainter *painter,const QModelIndex& index,
+ const QStyleOptionViewItemV4& option,QString text) const
+{
+
+ bool selected=option.state & QStyle::State_Selected;
+ int offset=4;
+
+ QFontMetrics fm(font_);
+ int deltaH=(option.rect.height()-(fm.height()+4))/2;
+
+ //The initial filled rect (we will adjust its width)
+ QRect itemRect=option.rect.adjusted(2*offset,deltaH+1+1,0,-deltaH-1-1);
+ if(option.state & QStyle::State_Selected)
+ itemRect.adjust(0,0,0,-0);
+
+ NodeShape stateShape;
+ NodeShape realShape;
+ NodeText nodeText;
+ NodeText typeText;
+
+ //get the colours
+ QVariant bgVa=index.data(Qt::BackgroundRole);
+ bool hasRealBg=false;
+ if(bgVa.type() == QVariant::List)
+ {
+ QVariantList lst=bgVa.toList();
+ if(lst.count() == 2)
+ {
+ hasRealBg=true;
+ stateShape.col_=lst[0].value<QColor>();
+ realShape.col_=lst[1].value<QColor>();
+ }
+ }
+ else
+ {
+ stateShape.col_=bgVa.value<QColor>();
+ }
+
+ int currentRight=itemRect.left();
+
+ //Node type
+ QFontMetrics fmType(typeFont_);
+ int typeWidth=fmType.width(" S");
+
+ if(drawNodeType_)
+ {
+ int nodeType=index.data(AbstractNodeModel::NodeTypeRole).toInt();
+ switch(nodeType)
+ {
+ case 0: typeText.text_="S"; break;
+ case 1: typeText.text_="F"; break;
+ case 2: typeText.text_="T"; break;
+ case 3: typeText.text_="A"; break;
+ default: break;
+ }
+ }
+
+ //The text rectangle
+ nodeText.text_=text;
+ int textWidth=fm.width(text);
+
+ if(nodeStyle_ == BoxAndTextNodeStyle)
+ {
+ int realW=itemRect.height()/4;
+
+ QRect r1(currentRight,itemRect.y(),itemRect.height(),itemRect.height());
+ if(hasRealBg)
+ r1.adjust(0,0,-realW,0);
+
+ stateShape.shape_=QPolygon(r1);
+
+ if(hasRealBg)
+ {
+ QRect r2(r1.right(),r1.top(),realW+1,r1.height());
+ realShape.shape_=QPolygon(r2);
+ currentRight=r2.right()+2;
+ }
+ else
+ currentRight=r1.right()+2;
+
+ if(drawNodeType_)
+ {
+ typeText.br_=r1;
+ typeText.fgCol_=index.data(AbstractNodeModel::NodeTypeForegroundRole).value<QColor>();
+ }
+
+ nodeText.br_=QRect(currentRight+offset,r1.top(),textWidth,r1.height());
+ nodeText.fgCol_=QColor(Qt::black);
+ currentRight=nodeText.br_.right();
+
+ }
+ //Classic style
+ else
+ {
+ if(drawNodeType_)
+ {
+ typeText.br_=QRect(currentRight,itemRect.y(),typeWidth,itemRect.height());
+ typeText.fgCol_=typeFgColourClassic;
+ typeText.bgCol_=typeBgColourClassic;
+ currentRight=typeText.br_.right()+2;
+ }
+
+ QRect r1(currentRight,itemRect.y(),textWidth+2*offset+1,itemRect.height());
+ stateShape.shape_=QPolygon(r1);
+ currentRight=r1.right()+2;
+
+ nodeText.br_=QRect(r1.left()+offset,r1.top(),textWidth,r1.height());
+ nodeText.fgCol_=index.data(Qt::ForegroundRole).value<QColor>();
+
+ if(hasRealBg)
+ {
+ int realW=6;
+ QRect r2(r1.right(),r1.top(),realW+1,r1.height());
+ realShape.shape_=QPolygon(r2);
+ currentRight=r2.right()+2;
+ }
+ }
+
+ //Icons area
+ QList<QPixmap> pixLst;
+ QList<QRect> pixRectLst;
+
+ QVariant va=index.data(AbstractNodeModel::IconRole);
+ if(va.type() == QVariant::List)
+ {
+ QVariantList lst=va.toList();
+ int xp=currentRight+5;
+ int yp=itemRect.center().y()-iconSize_/2;
+ for(int i=0; i < lst.count(); i++)
+ {
+ int id=lst[i].toInt();
+ if(id != -1)
+ {
+ pixLst << IconProvider::pixmap(id,iconSize_);
+ pixRectLst << QRect(xp,yp,pixLst.back().width(),pixLst.back().height());
+ xp+=pixLst.back().width()+iconGap_;
+ }
+ }
+
+ if(!pixRectLst.isEmpty())
+ currentRight=pixRectLst.back().right();
+ }
+
+ //The node number (optional)
+ QRect numRect;
+ QString numTxt;
+ bool hasNum=false;
+
+ if(drawChildCount_)
+ {
+ va=index.data(AbstractNodeModel::NodeNumRole);
+ hasNum=(va.isNull() == false);
+
+ if(hasNum)
+ {
+ numTxt="(" + va.toString() + ")";
+ QFontMetrics fmNum(suiteNumFont_);
+
+ int numWidth=fmNum.width(numTxt);
+ numRect = nodeText.br_;
+ numRect.setLeft(currentRight+fmNum.width('A'));
+ numRect.setWidth(numWidth);
+ currentRight=numRect.right();
+ }
+ }
+
+ //The aborted reason
+ QRect reasonRect;
+ QString reasonTxt=index.data(AbstractNodeModel::AbortedReasonRole).toString();
+ if(reasonTxt.contains('\n'))
+ reasonTxt=reasonTxt.split("\n").first();
+
+ bool hasReason=(!reasonTxt.isEmpty());
+ if(hasReason)
+ {
+ QFontMetrics fmReason(abortedReasonFont_);
+ reasonRect = nodeText.br_;
+ reasonRect.setLeft(currentRight+fmReason.width('A'));
+ reasonTxt=fmReason.elidedText(reasonTxt,Qt::ElideRight,220);
+ reasonRect.setWidth(fmReason.width(reasonTxt));
+ currentRight=reasonRect.right();
+ }
+
+ //Define clipping
+ int rightPos=currentRight+1;
+ const bool setClipRect = rightPos > option.rect.right();
+ if(setClipRect)
+ {
+ painter->save();
+ painter->setClipRect(option.rect);
+ }
+
+ renderNodeCell(painter,stateShape,realShape,nodeText,typeText,selected);
+
+ //Draw icons
+ for(int i=0; i < pixLst.count(); i++)
+ {
+ painter->drawPixmap(pixRectLst[i],pixLst[i]);
+ }
+
+ //Draw number
+ if(hasNum)
+ {
+ painter->setPen(childCountColour);
+ painter->setFont(suiteNumFont_);
+ painter->drawText(numRect,Qt::AlignLeft | Qt::AlignVCenter,numTxt);
+ }
+
+ //Draw aborted reason
+ if(hasReason)
+ {
+ painter->setPen(stateShape.col_);
+ painter->setFont(abortedReasonFont_);
+ painter->drawText(reasonRect,Qt::AlignLeft | Qt::AlignVCenter,reasonTxt);
+ }
+
+ if(setClipRect)
+ {
+ painter->restore();
+ }
+}
+
+void TreeNodeViewDelegate::renderServerCell(QPainter *painter,const NodeShape& stateShape,
+ const NodeText& text,bool selected) const
+{
+ renderNodeShape(painter,stateShape);
+
+ //Draw text
+ painter->setFont(font_);
+ painter->setPen(QPen(text.fgCol_,0));
+ painter->drawText(text.br_,Qt::AlignLeft | Qt::AlignVCenter,text.text_);
+
+ //selection
+ painter->setPen(nodeSelectPen_);
+ painter->setBrush(Qt::NoBrush);
+ QPolygon sel=stateShape.shape_;
+
+ if(selected)
+ {
+ if(nodeStyle_ == BoxAndTextNodeStyle)
+ {
+ sel=sel.united(QPolygon(text.br_.adjusted(0,0,2,0)));
+ }
+ painter->drawRect(sel.boundingRect());
+ }
+}
+
+void TreeNodeViewDelegate::renderNodeCell(QPainter *painter,const NodeShape& stateShape,const NodeShape &realShape,
+ const NodeText& nodeText,const NodeText& typeText,bool selected) const
+{
+ renderNodeShape(painter,stateShape);
+ renderNodeShape(painter,realShape);
+
+ //Draw type
+ if(drawNodeType_)
+ {
+ if(typeText.bgCol_.isValid())
+ painter->fillRect(typeText.br_,typeText.bgCol_);
+ painter->setFont(typeFont_);
+ painter->setPen(typeText.fgCol_);
+ painter->setBrush(Qt::NoBrush);
+ painter->drawText(typeText.br_,Qt::AlignCenter,typeText.text_);
+ }
+
+ //Draw text
+ painter->setFont(font_);
+ painter->setPen(QPen(nodeText.fgCol_,0));
+ painter->drawText(nodeText.br_,Qt::AlignLeft | Qt::AlignVCenter,nodeText.text_);
+
+ //selection
+ painter->setPen(nodeSelectPen_);
+ painter->setBrush(Qt::NoBrush);
+ QPolygon sel=stateShape.shape_;
+
+ if(selected)
+ {
+ if(nodeStyle_ == BoxAndTextNodeStyle)
+ {
+ if(!realShape.shape_.isEmpty())
+ sel=sel.united(realShape.shape_);
+
+ sel=sel.united(QPolygon(nodeText.br_.adjusted(0,0,2,0)));
+ }
+ else
+ {
+ if(!realShape.shape_.isEmpty())
+ sel=sel.united(realShape.shape_);
+ }
+ painter->drawRect(sel.boundingRect());
+ }
+
+ /*
+
+ if(nodeStyle_ == BoxAndTextNodeStyle)
+ {
+ painter->setFont(typeFont_);
+ painter->setPen();
+ painter->drawText(typeText.br_,Qt::AlignCenter,typeText.text_);
+ }
+ else
+ {
+ painter->setPen(Qt::NoPen);
+
+ if(typeTxt == "S")
+ painter->setBrush(QColor(150,150,150)); //bgBrush);
+ else if(typeTxt == "F")
+ painter->setBrush(QColor(150,150,150)); //bgBrush);
+ else
+ painter->setBrush(QColor(190,190,190)); //bgBrush);
+
+ painter->drawRect(typeRect);
+
+ painter->setPen(Qt::white);
+ painter->setFont(typeFont_);
+ painter->drawText(typeRect,Qt::AlignCenter,typeTxt);
+ }
+ }
+
+ //Draw text
+ painter->setFont(font_);
+ painter->setPen(QPen(fg,0));
+ painter->drawText(textRect,Qt::AlignLeft | Qt::AlignVCenter,text);
+
+ //selection
+ painter->setPen(nodeSelectPen_);
+ painter->setBrush(Qt::NoBrush);
+ QPolygon sel=stateShape.shape_;
+
+ if(selected)
+ {
+ if(nodeStyle_ == BoxAndTextNodeStyle)
+ {
+ if(!realShape.shape_.isEmpty())
+ sel=sel.united(realShape.shape_);
+
+ sel=sel.united(QPolygon(textRect.adjusted(0,0,2,0)));
+ }
+ else
+ {
+ if(!realShape.shape_.isEmpty())
+ sel=sel.united(realShape.shape_);
+ }
+ painter->drawRect(sel.boundingRect());
+ //painter->drawPolygon(sel);
+ }
+*/
+ //painter->setRenderHints(QPainter::Antialiasing,false);
+}
+
+
+void TreeNodeViewDelegate::renderNodeShape(QPainter* painter,const NodeShape& shape) const
+{
+ if(shape.shape_.isEmpty())
+ return;
+
+ QColor bg=shape.col_;
+ QColor bgLight;
+ if(bg.value() < 235)
+ bgLight=bg.lighter(130);
+ else
+ bgLight=bg.lighter(lighter_);
+
+ QColor borderCol=bg.darker(150); //125
+
+ QBrush bgBrush;
+ if(useStateGrad_)
+ {
+ grad_.setColorAt(0,bgLight);
+ grad_.setColorAt(1,bg);
+ bgBrush=QBrush(grad_);
+ }
+ else
+ bgBrush=QBrush(bg);
+
+ //Fill shape
+ painter->setPen(borderCol);
+ painter->setBrush(bgBrush);
+ painter->drawPolygon(shape.shape_);
+}
+
+void TreeNodeViewDelegate::renderTimer(QPainter *painter,QRect target,int remaining, int total) const
+{
+ QImage img(target.width(),target.height(),QImage::Format_ARGB32_Premultiplied);
+ QRect r=img.rect().adjusted(2,2,-2,-2);
+ img.fill(Qt::transparent);
+ QPainter p(&img);
+ p.setRenderHint(QPainter::Antialiasing,true);
+
+ int angle=static_cast<int>(360.*static_cast<float>(total-remaining)/static_cast<float>(total));
+ /*angle-=90.;
+ if(angle >=0 && angle <= 90) angle=90-angle;
+ else
+ angle=450-angle;*/
+
+ QColor c(43,97,158);
+
+ QBrush b(c);
+ p.setBrush(b);
+ p.setPen(c);
+ p.drawPie(r,90*16,-angle*16);
+ p.setBrush(Qt::NoBrush);
+ p.drawEllipse(r);
+
+ painter->drawImage(target,img,img.rect());
+}
+
+
+void TreeNodeViewDelegate::renderServerUpdate(QPainter* painter,const ServerUpdateData& data) const
+{
+ QFont font(font_);
+ font.setPointSize(font_.pointSize()-1);
+ QFontMetrics fm(font);
+ painter->setFont(font);
+ painter->setPen(Qt::black);
+
+ QColor minCol=QColor(198,215,253);
+ QColor maxCol=QColor(43,97,158);
+
+ QRect r1=data.br_;
+ r1.setWidth(fm.width(data.prevText_));
+ painter->setPen(minCol);
+ //painter->setPen(Qt::red);
+ painter->drawText(r1,Qt::AlignLeft | Qt::AlignVCenter,data.prevText_);
+
+ if(!data.prevText_.isEmpty())
+ {
+ QRect r2=data.br_;
+ r2.setX(data.br_.right()-fm.width(data.nextText_));
+ //painter->setPen(QColor(1,128,73));
+ painter->setPen(maxCol);
+ painter->drawText(r2,Qt::AlignRight | Qt::AlignVCenter,data.nextText_);
+
+ int dh=(data.br_.height()-fm.height()+1)/2;
+ QRect r=data.br_.adjusted(r1.width()+4,2*dh,-r2.width()-4,-2*dh);
+
+ int pos=static_cast<int>(data.prog_* r.width());
+ QRect rPrev=r.adjusted(0,0,-(r.width()-pos),0);
+
+ QLinearGradient grad;
+ grad.setCoordinateMode(QGradient::ObjectBoundingMode);
+ grad.setStart(0,0);
+ grad.setFinalStop(1,0);
+ QColor posCol=interpolate(minCol,maxCol,data.prog_);
+
+ grad.setColorAt(0,minCol);
+ grad.setColorAt(1,posCol);
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(grad);
+ painter->drawRect(rPrev);
+
+ painter->setBrush(Qt::NoBrush);
+ painter->setPen(QColor(190,190,190));
+ painter->drawRect(r);
+ }
+}
+
+QString TreeNodeViewDelegate::formatTime(int timeInSec) const
+{
+ int h=timeInSec/3600;
+ int r=timeInSec%3600;
+ int m=r/60;
+ int s=r%60;
+
+ QTime t(h,m,s);
+ if(h > 0)
+ return t.toString("h:mm:ss");
+ else
+ return t.toString("m:ss");
+
+ return QString();
+}
+
+QColor TreeNodeViewDelegate::interpolate(QColor c1,QColor c2,float r) const
+{
+ return QColor::fromRgbF(c1.redF()+r*(c2.redF()-c1.redF()),
+ c1.greenF()+r*(c2.greenF()-c1.greenF()),
+ c1.blueF()+r*(c2.blueF()-c1.blueF()));
+}
diff --git a/Viewer/src/TreeNodeViewDelegate.hpp b/Viewer/src/TreeNodeViewDelegate.hpp
new file mode 100644
index 0000000..1728584
--- /dev/null
+++ b/Viewer/src/TreeNodeViewDelegate.hpp
@@ -0,0 +1,93 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef TreeNodeViewDelegate_HPP_
+#define TreeNodeViewDelegate_HPP_
+
+#include <QBrush>
+#include <QMap>
+#include <QPen>
+#include <QStyledItemDelegate>
+
+#include "NodeViewDelegate.hpp"
+#include "VProperty.hpp"
+
+#include <string>
+
+class AnimationHandler;
+class PropertyMapper;
+class NodeShape;
+class NodeText;
+class ServerUpdateData;
+
+class TreeNodeViewDelegate : public NodeViewDelegate
+{
+Q_OBJECT
+
+public:
+ explicit TreeNodeViewDelegate(QWidget *parent=0);
+ ~TreeNodeViewDelegate();
+
+ void paint(QPainter *painter,const QStyleOptionViewItem &option,
+ const QModelIndex& index) const;
+
+ QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index ) const;
+
+ void setIndentation(int o) {indentation_=o;}
+
+
+Q_SIGNALS:
+ void sizeHintChangedGlobal();
+
+protected:
+ void updateSettings();
+
+ void renderServer(QPainter *painter,const QModelIndex& index,
+ const QStyleOptionViewItemV4& option,QString text) const;
+
+ void renderNode(QPainter *painter,const QModelIndex& index,
+ const QStyleOptionViewItemV4& option,QString text) const;
+
+ void renderServerCell(QPainter *painter,const NodeShape& stateShape,
+ const NodeText& text,bool selected) const;
+
+ void renderNodeCell(QPainter *painter,const NodeShape& stateShape,const NodeShape &realShape,
+ const NodeText& nodeText,const NodeText& typeText,bool selected) const;
+
+ void renderNodeShape(QPainter* painter,const NodeShape& shape) const;
+ void renderTimer(QPainter *painter,QRect target, int remaining, int total) const;
+ void renderServerUpdate(QPainter* painter,const ServerUpdateData&) const;
+
+ QString formatTime(int timeInSec) const;
+ QColor interpolate(QColor c1,QColor c2,float r) const;
+
+ enum NodeStyle {ClassicNodeStyle,BoxAndTextNodeStyle};
+
+ AnimationHandler* animation_;
+
+ int nodeRectRad_;
+ bool drawChildCount_;
+ NodeStyle nodeStyle_;
+ int indentation_;
+ bool drawNodeType_;
+ QColor typeBgCol_;
+
+ QFont serverNumFont_;
+ QFont suiteNumFont_;
+ QFont serverInfoFont_;
+ QFont abortedReasonFont_;
+ QFont typeFont_;
+ QColor bgCol_;
+};
+
+#endif
+
+
+
diff --git a/Viewer/src/TreeNodeWidget.cpp b/Viewer/src/TreeNodeWidget.cpp
new file mode 100644
index 0000000..4187f3a
--- /dev/null
+++ b/Viewer/src/TreeNodeWidget.cpp
@@ -0,0 +1,252 @@
+/***************************** LICENSE START ***********************************
+
+ Copyright 2015 ECMWF and INPE. This software is distributed under the terms
+ of the Apache License version 2.0. In applying this license, ECMWF does not
+ waive the privileges and immunities granted to it by virtue of its status as
+ an Intergovernmental Organization or submit itself to any jurisdiction.
+
+ ***************************** LICENSE END *************************************/
+
+#include "TreeNodeWidget.hpp"
+
+#include <QDebug>
+#include <QHBoxLayout>
+
+#include "AbstractNodeModel.hpp"
+#include "DashboardDock.hpp"
+#include "NodePathWidget.hpp"
+#include "NodeViewBase.hpp"
+#include "TreeNodeModel.hpp"
+#include "TreeNodeView.hpp"
+#include "VFilter.hpp"
+#include "VConfig.hpp"
+#include "VSettings.hpp"
+
+#include "FilterWidget.hpp"
+
+AttributeFilter* TreeNodeWidget::lastAtts_=NULL;
+
+TreeNodeWidget::TreeNodeWidget(ServerFilter* serverFilter,QWidget* parent) : NodeWidget("tree",serverFilter,parent)
+{
+ //Init qt-creator form
+ setupUi(this);
+
+ if(!lastAtts_)
+ {
+ lastAtts_=new AttributeFilter();
+ }
+
+ initAtts();
+
+ //This defines how to filter the nodes in the tree. We only want to filter according to node status.
+ filterDef_=new NodeFilterDef(serverFilter_,NodeFilterDef::NodeStateScope);
+
+ //Create the tree model. It uses the datahandler to access the data.
+ model_=new TreeNodeModel(serverFilter_,filterDef_,atts_,icons_,this);
+
+ //Create the view
+ QHBoxLayout *hb=new QHBoxLayout(viewHolder_);
+ hb->setContentsMargins(0,0,0,0);
+ hb->setSpacing(0);
+ TreeNodeView *tv=new TreeNodeView((TreeNodeModel*)model_,filterDef_,this);
+ hb->addWidget(tv);
+
+ //Store the pointer to the (non-QObject) base class of the view!!!
+ view_=tv;
+
+ //Signals-slots
+ connect(view_->realWidget(),SIGNAL(selectionChanged(VInfo_ptr)),
+ this,SLOT(slotSelectionChangedInView(VInfo_ptr)));
+
+ connect(view_->realWidget(),SIGNAL(infoPanelCommand(VInfo_ptr,QString)),
+ this,SIGNAL(popInfoPanel(VInfo_ptr,QString)));
+
+ connect(view_->realWidget(),SIGNAL(dashboardCommand(VInfo_ptr,QString)),
+ this,SIGNAL(dashboardCommand(VInfo_ptr,QString)));
+
+ connect(bcWidget_,SIGNAL(selected(VInfo_ptr)),
+ view_->realWidget(),SLOT(slotSetCurrent(VInfo_ptr)));
+
+ connect(model_,SIGNAL(clearBegun(const VTreeNode*)),
+ view_->realWidget(),SLOT(slotSaveExpand(const VTreeNode*)));
+
+ connect(model_,SIGNAL(scanEnded(const VTreeNode*)),
+ view_->realWidget(),SLOT(slotRestoreExpand(const VTreeNode*)));
+
+ connect(model_,SIGNAL(rerender()),
+ view_->realWidget(),SLOT(slotRerender()));
+
+ connect(model_,SIGNAL(filterChangeBegun()),
+ view_->realWidget(),SLOT(slotSaveExpand()));
+
+ connect(model_,SIGNAL(filterChangeEnded()),
+ view_->realWidget(),SLOT(slotRestoreExpand()));
+
+ connect(model_,SIGNAL(filterUpdateRemoveBegun(const VTreeNode*)),
+ view_->realWidget(),SLOT(slotSaveExpand(const VTreeNode*)));
+
+ connect(model_,SIGNAL(filterUpdateAddEnded(const VTreeNode*)),
+ view_->realWidget(),SLOT(slotRestoreExpand(const VTreeNode*)));
+
+ connect(atts_,SIGNAL(changed()),
+ this,SLOT(slotAttsChanged()));
+
+ //This will not emit the trigered signal of the action!!
+ //Synchronise the action and the breadcrumbs state
+ actionBreadcrumbs->setChecked(bcWidget_->active());
+
+ //The node status filter is exposed via a menu. So we need a reference to it.
+ states_=filterDef_->nodeState();
+
+}
+
+TreeNodeWidget::~TreeNodeWidget()
+{
+}
+
+void TreeNodeWidget::initAtts()
+{
+ if(VProperty *prop=VConfig::instance()->find("view.tree.attributesPolicy"))
+ {
+ if(prop->valueAsString() == "last")
+ {
+ atts_->setCurrent(lastAtts_->current());
+ }
+ else if(VProperty *propDef=VConfig::instance()->find("view.tree.defaultAttributes"))
+ {
+ //qDebug() << "atts" << propDef->value().toString() << propDef->value().toString().split("/");
+ atts_->setCurrent(propDef->value().toString().split("/"));
+ }
+ }
+}
+
+void TreeNodeWidget::populateDockTitleBar(DashboardDockTitleWidget* tw)
+{
+ //Builds the menu for the settings tool button
+ QMenu *menu=new QMenu(this);
+ menu->setTearOffEnabled(true);
+
+ menu->addAction(actionBreadcrumbs);
+ QMenu *menuState=new QMenu(this); //menu->addMenu(tr("Status"));
+ QMenu *menuType=new QMenu(this); //menu->addMenu(tr("Attribute"));
+ QMenu *menuIcon=menu->addMenu(tr("Icon"));
+
+ menuState->setTearOffEnabled(true);
+ menuType->setTearOffEnabled(true);
+ menuIcon->setTearOffEnabled(true);
+
+ //stateFilterMenu_=new StateFilterMenu(menuState,filter_->menu());
+ attrFilterMenu_=new VParamFilterMenu(menuType,atts_,"Show attributes",VParamFilterMenu::ShowMode);
+ iconFilterMenu_=new VParamFilterMenu(menuIcon,icons_,"Show icons",VParamFilterMenu::ShowMode);
+ stateFilterMenu_=new VParamFilterMenu(menuState,states_,"Status filter",
+ VParamFilterMenu::FilterMode,VParamFilterMenu::ColourDecor);
+
+ //Sets the menu on the toolbutton
+ tw->optionsTb()->setMenu(menu);
+
+ //Sets the title
+ tw->slotUpdateTitle("<b>Tree</b>");
+
+ QList<QAction*> acLst;
+ QAction* acState=new QAction(this);
+ acState->setIcon(QPixmap(":viewer/status.svg"));
+ acState->setToolTip("Status filter");
+ acState->setMenu(menuState);
+ acLst << acState;
+
+ QAction* acAttr=new QAction(this);
+ acAttr->setIcon(QPixmap(":viewer/attribute.svg"));
+ acAttr->setToolTip("Show attributes");
+ //acAttr->setText("Attributes ");
+ acAttr->setMenu(menuType);
+ acLst << acAttr;
+
+ tw->addActions(acLst);
+}
+
+void TreeNodeWidget::slotSelectionChangedInView(VInfo_ptr info)
+{
+ updateActionState(info);
+ bcWidget_->setPath(info);
+ Q_EMIT selectionChanged(info);
+}
+
+
+void TreeNodeWidget::on_actionBreadcrumbs_triggered(bool b)
+{
+ if(b)
+ {
+ bcWidget_->active(true);
+ bcWidget_->setPath(view_->currentSelection());
+ }
+ else
+ {
+ bcWidget_->active(false);
+ }
+
+ //bcWidget_->clear();
+}
+
+void TreeNodeWidget::rerender()
+{
+ bcWidget_->rerender();
+ view_->rerender();
+}
+
+bool TreeNodeWidget::selectFirstServerInView()
+{
+ view_->selectFirstServer();
+ return true;
+}
+
+void TreeNodeWidget::slotAttsChanged()
+{
+ lastAtts_->setCurrent(atts_->current());
+}
+
+void TreeNodeWidget::writeSettings(VSettings* vs)
+{
+ vs->put("type",type_);
+ vs->put("dockId",id_);
+
+ bcWidget_->writeSettings(vs);
+
+ states_->writeSettings(vs);
+ atts_->writeSettings(vs);
+ icons_->writeSettings(vs);
+}
+
+void TreeNodeWidget::readSettings(VSettings* vs)
+{
+ std::string type=vs->get<std::string>("type","");
+ if(type != type_)
+ return;
+
+ //This will not emit the changed signal. So the "observers" will
+ //not notice the change.
+ states_->readSettings(vs);
+ atts_->readSettings(vs);
+ icons_->readSettings(vs);
+
+ lastAtts_->setCurrent(atts_->current());
+
+ //The model at this point is inactive (not using its data). We make it active:
+ // -it will instruct its data provider to filter the data according
+ // to the current settings
+ // -it will load and display the data
+ model_->active(true);
+
+ //--------------------------
+ //Breadcrumbs
+ //--------------------------
+
+ bcWidget_->readSettings(vs);
+
+ //Synchronise the action and the breadcrumbs state
+ //This will not emit the trigered signal of the action!!
+ actionBreadcrumbs->setChecked(bcWidget_->active());
+
+ attrFilterMenu_->reload();
+ iconFilterMenu_->reload();
+ stateFilterMenu_->reload();
+}
diff --git a/Viewer/src/TreeNodeWidget.hpp b/Viewer/src/TreeNodeWidget.hpp
new file mode 100644
index 0000000..ece6ffa
--- /dev/null
+++ b/Viewer/src/TreeNodeWidget.hpp
@@ -0,0 +1,54 @@
+/***************************** LICENSE START ***********************************
+
+ Copyright 2015 ECMWF and INPE. This software is distributed under the terms
+ of the Apache License version 2.0. In applying this license, ECMWF does not
+ waive the privileges and immunities granted to it by virtue of its status as
+ an Intergovernmental Organization or submit itself to any jurisdiction.
+
+ ***************************** LICENSE END *************************************/
+
+#ifndef TREENODEWIDGET_HPP_
+#define TREENODEWIDGET_HPP_
+
+#include "ui_TreeNodeWidget.h"
+
+#include "NodeWidget.hpp"
+
+class AttributeFilter;
+class NodeStateFilter;
+class ServerFilter;
+class VParamFilterMenu;
+class VSettings;
+
+
+class TreeNodeWidget : public NodeWidget, protected Ui::TreeNodeWidget
+{
+Q_OBJECT
+
+public:
+ TreeNodeWidget(ServerFilter*,QWidget* parent=0);
+ ~TreeNodeWidget();
+
+ void populateDockTitleBar(DashboardDockTitleWidget* tw);
+
+ void rerender();
+ bool selectFirstServerInView();
+ void writeSettings(VSettings*);
+ void readSettings(VSettings*);
+
+protected Q_SLOTS:
+ void on_actionBreadcrumbs_triggered(bool b);
+ void slotSelectionChangedInView(VInfo_ptr info);
+ void slotAttsChanged();
+
+protected:
+ void initAtts();
+
+ VParamFilterMenu *stateFilterMenu_;
+ VParamFilterMenu *attrFilterMenu_;
+ VParamFilterMenu *iconFilterMenu_;
+
+ static AttributeFilter* lastAtts_;
+};
+
+#endif
diff --git a/Viewer/src/TreeNodeWidget.ui b/Viewer/src/TreeNodeWidget.ui
new file mode 100644
index 0000000..45240f0
--- /dev/null
+++ b/Viewer/src/TreeNodeWidget.ui
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>TreeNodeWidget</class>
+ <widget class="QWidget" name="TreeNodeWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>683</width>
+ <height>491</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" stretch="0,1">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="NodePathWidget" name="bcWidget_" native="true"/>
+ </item>
+ <item>
+ <widget class="QWidget" name="viewHolder_" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ <action name="actionBreadcrumbs">
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Breadcrumbs</string>
+ </property>
+ <property name="toolTip">
+ <string>Sho/hide breadcrumbs</string>
+ </property>
+ </action>
+ <action name="actionFrozen">
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Frozen</string>
+ </property>
+ <property name="toolTip">
+ <string>Do not update panel when node changes</string>
+ </property>
+ </action>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>NodePathWidget</class>
+ <extends>QWidget</extends>
+ <header>NodePathWidget.hpp</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources>
+ <include location="viewer.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/Viewer/src/TreeView.cpp b/Viewer/src/TreeView.cpp
new file mode 100644
index 0000000..1ce1863
--- /dev/null
+++ b/Viewer/src/TreeView.cpp
@@ -0,0 +1,28 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "TreeView.hpp"
+
+#include <QPalette>
+
+TreeView::TreeView(QWidget* parent) : QTreeView(parent)
+{
+ //!!!!We need to do it because:
+ //The background colour between the views left border and the nodes cannot be
+ //controlled by delegates or stylesheets. It always takes the QPalette::Highlight
+ //colour from the palette. Here we set this to transparent so that Qt could leave
+ //this are empty and we will fill it appropriately in our delegate.
+
+ QPalette pal=palette();
+ pal.setColor(QPalette::Highlight,QColor(255,255,255,0));
+ setPalette(pal);
+}
+
+
diff --git a/Viewer/src/TreeView.hpp b/Viewer/src/TreeView.hpp
new file mode 100644
index 0000000..0538eed
--- /dev/null
+++ b/Viewer/src/TreeView.hpp
@@ -0,0 +1,21 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+#ifndef VIEWER_SRC_TREEVIEW_HPP_
+#define VIEWER_SRC_TREEVIEW_HPP_
+
+#include <QTreeView>
+
+class TreeView : public QTreeView
+{
+public:
+ explicit TreeView(QWidget* parent=0);
+};
+
+#endif /* VIEWER_SRC_TREEVIEW_HPP_ */
diff --git a/Viewer/src/TriggerItemWidget.cpp b/Viewer/src/TriggerItemWidget.cpp
new file mode 100644
index 0000000..4da2112
--- /dev/null
+++ b/Viewer/src/TriggerItemWidget.cpp
@@ -0,0 +1,53 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "TriggerItemWidget.hpp"
+
+#include "Node.hpp"
+#include "TriggerView.hpp"
+
+//========================================================
+//
+// TriggerItemWidget
+//
+//========================================================
+
+TriggerItemWidget::TriggerItemWidget(QWidget *parent) : QWidget(parent)
+{
+ setupUi(this);
+}
+
+QWidget* TriggerItemWidget::realWidget()
+{
+ return this;
+}
+
+void TriggerItemWidget::reload(VInfo_ptr nodeInfo)
+{
+ clearContents();
+
+ active_=true;
+
+ if(nodeInfo.get() != 0 && nodeInfo->isNode())
+ {
+ //Node* n=nodeInfo->node();
+ }
+ else
+ {
+
+ }
+
+}
+
+void TriggerItemWidget::clearContents()
+{
+ InfoPanelItem::clear();
+}
+
+static InfoPanelItemMaker<TriggerItemWidget> maker1("triggers");
diff --git a/Viewer/src/TriggerItemWidget.hpp b/Viewer/src/TriggerItemWidget.hpp
new file mode 100644
index 0000000..68845cf
--- /dev/null
+++ b/Viewer/src/TriggerItemWidget.hpp
@@ -0,0 +1,39 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef TRIGGERITEMWIDGET_HPP_
+#define TRIGGERITEMWIDGET_HPP_
+
+#include <QWidget>
+
+#include "InfoPanelItem.hpp"
+#include "VInfo.hpp"
+
+#include "ui_TriggerItemWidget.h"
+
+class TriggerItemWidget : public QWidget, public InfoPanelItem, protected Ui::TriggerItemWidget
+{
+public:
+ explicit TriggerItemWidget(QWidget *parent=0);
+
+ void reload(VInfo_ptr);
+ QWidget* realWidget();
+ void clearContents();
+
+ void nodeChanged(const VNode*, const std::vector<ecf::Aspect::Type>&) {}
+ void defsChanged(const std::vector<ecf::Aspect::Type>&) {}
+
+protected:
+ void updateState(const ChangeFlags&) {}
+
+};
+
+#endif
+
diff --git a/Viewer/src/TriggerItemWidget.ui b/Viewer/src/TriggerItemWidget.ui
new file mode 100644
index 0000000..47aec5e
--- /dev/null
+++ b/Viewer/src/TriggerItemWidget.ui
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>TriggerItemWidget</class>
+ <widget class="QWidget" name="TriggerItemWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>510</width>
+ <height>465</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QToolButton" name="textTb_">
+ <property name="text">
+ <string>Text</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="graphTb_">
+ <property name="text">
+ <string>graphics</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QToolButton" name="dependTb_">
+ <property name="text">
+ <string>Dependencies</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="TriggerView" name="triggerView_"/>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>TriggerView</class>
+ <extends>QGraphicsView</extends>
+ <header location="global">TriggerView.hpp</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Viewer/src/TriggerView.cpp b/Viewer/src/TriggerView.cpp
new file mode 100644
index 0000000..23512bc
--- /dev/null
+++ b/Viewer/src/TriggerView.cpp
@@ -0,0 +1,422 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "TriggerView.hpp"
+
+
+NodeItem::NodeItem()
+{
+
+}
+
+QRectF NodeItem::boundingRect() const
+{
+ return QRectF();
+}
+
+void paint(QPainter*, const QStyleOptionGraphicsItem *,QWidget*)
+{
+
+}
+
+
+
+TriggerScene::TriggerScene(QWidget *parent) : QGraphicsScene(parent)
+{
+}
+
+void TriggerScene::reset(VInfo_ptr info)
+{
+ clear();
+
+}
+
+/*int TriggerScene::grow(VInfo_ptr info,bool)
+{
+
+}*/
+
+
+TriggerView::TriggerView(QWidget *parent) : QGraphicsView(parent)
+{
+
+}
+
+
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////
+/*
+class TriggerList
+{
+public:
+
+ TriggerList() {}
+ virtual ~TriggerList() {}
+
+ enum { normal = 0, // Normal trigger_node
+ parent = 1, // Through parent
+ child = 2, // Through child
+ hierarchy = 3 // Through child
+ };
+
+ virtual void next_node(node&, node*,int,node*) = 0;
+ virtual bool parents() { return false; }
+ virtual bool kids() { return false; }
+ virtual bool self() { return true; }
+
+private:
+ TriggerList(const trigger_lister&);
+ TriggerList& operator=(const trigger_lister&);
+};
+*/
+
+
+
+
+
+
+
+
+
+
+/*
+void simple_node::scan(Ast *m,trigger_lister& tlr,node* trg)
+{
+ if(!m) return;
+ std::string path = "";
+ { AstNode *an = dynamic_cast<AstNode*> (m);
+ if(an) { path = an->nodePath(); path = m->expression(); } }
+ { AstVariable *an = dynamic_cast<AstVariable*> (m);
+ if(an) { path = an->nodePath(); path = m->expression(); } }
+
+ if (path != "") {
+ node* n = parent() ? parent()->find(path) : node::find(path);
+
+ if(n) {
+ tlr.next_node(*n,0,trigger_lister::normal,trg);
+ } else if (external::is_external(path))
+ tlr.next_node(external::get(path),0,trigger_lister::normal,trg);
+ }
+ {
+ scan(m->left(), tlr,trg);
+ scan(m->right(),tlr,trg);
+ }
+}
+
+
+class fik : public trigger_lister {
+ node* n_;
+ node* k_;
+ trigger_lister& l_;
+public:
+
+ fik(node* n,node* k,trigger_lister& l): n_(n),k_(k),l_(l) {};
+
+ void next_node(node& n, node*,int type,node *t) {
+ if(!n.is_my_parent(n_)) {
+ // k is a kid of n whose trigger_panel is outside its subtree
+ l_.next_node(n,k_,trigger_lister::child,t);
+ }
+ }
+};
+
+class fip : public trigger_lister {
+ node* p_;
+ trigger_lister& l_;
+
+public:
+ fip(node* p,trigger_lister& l) : p_(p), l_(l) {}
+
+ void next_node(node& n, node*,int type,node *t)
+ { l_.next_node(n,p_,trigger_lister::parent,t); }
+};
+
+
+
+static void find_in_kids(node& n,node* k,trigger_lister& tlr)
+{
+ while(k) {
+ fik f(&n,k,tlr);
+ k->triggers(f);
+ find_in_kids(n,k->kids(),tlr);
+ k = k->next();
+ }
+}
+#include <ExprAstVisitor.hpp>
+
+class AstCollateXNodesVisitor : public ecf::ExprAstVisitor {
+public:
+ AstCollateXNodesVisitor( std::set<node*>& );
+ virtual ~AstCollateXNodesVisitor();
+
+ virtual void visitTop(AstTop*){}
+ virtual void visitRoot(AstRoot*){}
+ virtual void visitAnd(AstAnd*){}
+ virtual void visitNot(AstNot*){}
+ virtual void visitPlus(AstPlus*){}
+ virtual void visitMinus(AstMinus*){}
+ virtual void visitDivide(AstDivide*){}
+ virtual void visitMultiply(AstMultiply*){}
+ virtual void visitModulo(AstModulo*){}
+ virtual void visitOr(AstOr*){}
+ virtual void visitEqual(AstEqual*){}
+ virtual void visitNotEqual(AstNotEqual*){}
+ virtual void visitLessEqual(AstLessEqual*){}
+ virtual void visitGreaterEqual(AstGreaterEqual*){}
+ virtual void visitGreaterThan(AstGreaterThan*){}
+ virtual void visitLessThan(AstLessThan*){}
+ virtual void visitLeaf(AstLeaf*){}
+ virtual void visitInteger(AstInteger*){}
+ virtual void visitString(AstString*){}
+ virtual void visitNodeState(AstNodeState*){}
+ virtual void visitEventState(AstEventState*);
+ virtual void visitNode(AstNode*);
+ virtual void visitVariable(AstVariable*);
+
+private:
+ std::set<node*>& theSet_;
+};
+
+
+AstCollateXNodesVisitor::AstCollateXNodesVisitor( std::set<node*>& s) : theSet_(s) {}
+AstCollateXNodesVisitor::~AstCollateXNodesVisitor() {}
+
+void AstCollateXNodesVisitor::visitEventState(AstEventState* astNode)
+{
+}
+
+void AstCollateXNodesVisitor::visitNode(AstNode* astNode)
+{
+ Node* referencedNode = astNode->referencedNode();
+ node* xnode = NULL;
+ if (referencedNode)
+ xnode = (node*) referencedNode->graphic_ptr();
+ if ( xnode ) theSet_.insert(xnode);
+}
+
+void AstCollateXNodesVisitor::visitVariable(AstVariable* astVar)
+{
+ Node* referencedNode = astVar->referencedNode();
+ if (referencedNode) {
+ simple_node* xnode = (simple_node*) referencedNode->graphic_ptr();
+ if (0 == xnode) return;
+
+ int type;
+ node* run;
+ for (run = xnode->kids(); 0 != run; run = run->next()) {
+ if (run->name() == astVar->name()) {
+ type = run->type();
+ if (type == NODE_EVENT
+ || type == NODE_METER
+ || type == NODE_VARIABLE) {
+ theSet_.insert(run);
+ }
+ }
+ }
+ }
+}
+
+
+//Get the triggers list for the Triggers view
+void simple_node::triggers(trigger_lister& tlr)
+{
+ //Check the node itself
+ if(tlr.self())
+ {
+ if(node_ && !node_->isSuite())
+ {
+ std::set<VNode*> theSet;
+ std::set<VNode*>::iterator sit;
+ AstCollateXNodesVisitor astVisitor(theSet);
+
+ if(node_->completeAst())
+ node_->completeAst()->accept(astVisitor);
+
+ if(node_->triggerAst())
+ node_->triggerAst()->accept(astVisitor);
+
+ for (sit = theSet.begin(); sit != theSet.end(); ++sit)
+ tlr.next_node( *(*sit), 0, trigger_lister::normal, *sit);
+ }
+
+
+ for(std::vector<VNode*>::itertor it=children_.begin(); it!= n ; n = n->next()) {
+ int type = n->type();
+ {
+ ecf_concrete_node<InLimit const> *c =
+ dynamic_cast<ecf_concrete_node<InLimit const>*> (n->__node__());
+ InLimit const * i = c ? c->get() : 0;
+ if (i) {
+ node *xn = 0;
+ if ((xn = find_limit(i->pathToNode(), i->name())))
+ tlr.next_node(*xn,0,trigger_lister::normal,xn);
+ }
+ }
+ if (type == NODE_DATE || type == NODE_TIME)
+ tlr.next_node(*n,0,trigger_lister::normal,n);
+ }
+ }
+ }
+
+
+if(tlr.parents()) {
+ node* p = parent();
+ while(p) {
+ fip f(p,tlr);
+ p->triggers(f);
+ p = p->parent();
+ }
+ }
+
+ if(tlr.kids())
+ find_in_kids(*this,kids(),tlr);
+ }
+
+void simple_node::scan_limit(Ast* m,std::ostream& f)
+{
+ if(!m) return;
+
+ AstNode *an = dynamic_cast<AstNode*> (m);
+ if(an) {
+ const node* n = node::find(an->nodePath());
+ if(!n)
+ f << "limit_node not found??\n";
+ else if(n->evaluate())
+ f << n->type_name() << " " << n->name() << " is " << n->status_name() << "\n";
+ } else {
+ scan_limit(m->left(),f);
+ scan_limit(m->right(),f);
+ }
+}
+
+int kind(Ast *t) {
+ int rc = 0;
+ if (!t) return rc;
+
+ ++rc ; if (t->type() == "or") return rc;
+ ++rc ; if (t->type() == "and") return rc;
+ ++rc ; if (t->type() == "equal") return rc;
+ ++rc ; if (t->type() == "not-equal") return rc;
+ ++rc ; if (t->type() == "less-than") return rc;
+ ++rc ; if (t->type() == "less-equal") return rc;
+ ++rc ; if (t->type() == "greater-than") return rc;
+ ++rc ; if (t->type() == "greater-equal") return rc;
+ ++rc ; if (t->type() == "plus") return rc;
+ ++rc ; if (t->type() == "minus") return rc;
+ ++rc ; // if (t->type == "multiply") return rc;
+ ++rc ; // if (t->type == "divide") return rc;
+ ++rc ; // if (t->type == "mod") return rc;
+ ++rc ; // if (t->type == "pow") return rc;
+ ++rc ; if (t->type() == "not") return rc;
+ ++rc ; if (t->type() == "unary") return rc;
+ ++rc ; if (t->type() == "open") return rc;
+ ++rc ; if (t->type() == "close") return rc;
+ ++rc ; if (t->type() == "node") return rc;
+ if (t->type() == "variable") return rc;
+ if (t->type() == "event_state") return rc;
+ return 0;
+}
+
+static struct {
+ int eval_;
+ int print_;
+ char* pos_;
+ char* neg_;
+} names [] = {
+ {0,0,(char*)"",(char*)"",}, // M_NIL
+ {1,0,(char*)"",(char*)"",}, // M_OR
+ {1,0,(char*)"",(char*)"",}, // M_AND
+ {1,1,(char*)"is", (char*)"is not",}, // M_EQ
+ {1,1,(char*)"is not", (char*)"is",}, // M_NE
+ {1,1,(char*)"is less than", (char*)"is greater or equal to",}, // M_LT
+ {1,1,(char*)"is less or equal to", (char*)"is greater than",}, // M_LE
+ {1,1,(char*)"is greater than", (char*)"is less or equal to",}, // M_GT
+ {1,1,(char*)"is greater or equal to",(char*)"is less than",}, // M_GE
+ {0,1,(char*)" + ",(char*)" + ",}, // M_ADD
+ {0,1,(char*)" - ",(char*)" - ",}, // M_SUB
+ {0,0,(char*)"",(char*)"",}, // M_MUL
+ {0,0,(char*)"",(char*)"",}, // M_DIV
+ {0,0,(char*)"",(char*)"",}, // M_MOD
+ {0,0,(char*)"",(char*)"",}, // M_POW
+ {0,0,(char*)"",(char*)"",}, // M_NOT
+ {0,0,(char*)"",(char*)"",}, // M_UNARY
+ {0,0,(char*)"",(char*)"",}, // M_OPEN
+ {0,0,(char*)"",(char*)"",}, // M_CLOSE
+ {0,0,(char*)"",(char*)"",}, // M_NAME
+};
+
+void simple_node::scan(Ast* m,std::ostream& f,bool b)
+{
+ if(m == 0) return;
+ std::cout << "# scan:" << m->expression() << "\n";
+ std::string cp = "";
+
+ { AstNode *an = dynamic_cast<AstNode*> (m);
+ if(an) { cp = an->nodePath(); cp = m->expression();} }
+ { AstVariable *an = dynamic_cast<AstVariable*> (m);
+ if(an) { cp = an->nodePath(); cp = m->expression();} }
+
+ if(cp != "") {
+ const node* n = node::find(cp);
+ if(!n) {
+ if(external::is_external(cp))
+ f << " (unknown)";
+ else
+ f << cp << " (not found?)";
+ return;
+ }
+
+ f << n->type_name() << ' ' << n->name() << '(' << n->status_name() << ')';
+ // node* s = f.source(); if(s && n->is_my_parent(s)) f << cancel;
+ } else {
+ if(external::is_external(cp))
+ f << " (unknown)";
+ }
+
+ if(m->type() == "not")
+ b = !b;
+
+ scan(m->left(),f,b);
+
+ f << ' ' << (b ? names[kind(m)].pos_ : names[kind(m)].neg_) << ' ';
+
+ scan(m->right(),f,b);
+
+ if(names[kind(m)].print_)
+ f << "\n";
+}
+
+class why_triggers : public trigger_lister {
+ std::ostream& f_;
+
+public:
+
+ virtual Boolean self() { return False; }
+ virtual Boolean kids() { return True; }
+ virtual Boolean parents() { return True; }
+
+ why_triggers(std::ostream& f) : f_(f) {}
+
+ void next_node(node& n, node* p,int type,node*) {
+ if(p && p->status() == STATUS_QUEUED)
+ p->why(f_);
+ }
+};
+
+*/
+
+
+
+
+
diff --git a/Viewer/src/TriggerView.hpp b/Viewer/src/TriggerView.hpp
new file mode 100644
index 0000000..f54f0ed
--- /dev/null
+++ b/Viewer/src/TriggerView.hpp
@@ -0,0 +1,44 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef TRIGGERVIEW_HPP_
+#define TRIGGERVIEW_HPP_
+
+#include <QGraphicsItem>
+#include <QGraphicsScene>
+#include <QGraphicsView>
+
+#include "VInfo.hpp"
+
+class NodeItem : public QGraphicsItem
+{
+public:
+ NodeItem();
+
+ QRectF boundingRect() const;
+ void paint(QPainter*, const QStyleOptionGraphicsItem *,QWidget*) {};
+};
+
+
+class TriggerScene : public QGraphicsScene
+{
+public:
+ explicit TriggerScene(QWidget *parent=0);
+
+ void reset(VInfo_ptr info);
+};
+
+class TriggerView : public QGraphicsView
+{
+public:
+ explicit TriggerView(QWidget *parent=0);
+};
+
+#endif
diff --git a/Viewer/src/UpdateTimer.cpp b/Viewer/src/UpdateTimer.cpp
new file mode 100644
index 0000000..d905281
--- /dev/null
+++ b/Viewer/src/UpdateTimer.cpp
@@ -0,0 +1,20 @@
+//============================================================================
+// Copyright 2015 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "UpdateTimer.hpp"
+
+void UpdateTimer::drift(int dValSec, int maxValMin)
+{
+ double v = interval() + dValSec*1000;
+ if( v > maxValMin*1000*60)
+ v=maxValMin*1000*60;
+
+ setInterval(v);
+}
+
diff --git a/Viewer/src/UpdateTimer.hpp b/Viewer/src/UpdateTimer.hpp
new file mode 100644
index 0000000..f5dab33
--- /dev/null
+++ b/Viewer/src/UpdateTimer.hpp
@@ -0,0 +1,22 @@
+//============================================================================
+// Copyright 2015 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef UPDATETIMER_HPP_
+#define UPDATETIMER_HPP_
+
+#include <QTimer>
+
+class UpdateTimer : public QTimer
+{
+public:
+ UpdateTimer(QObject* parent=0) : QTimer(parent) {}
+ void drift(int,int);
+};
+
+#endif // UPDATETIMER_HPP_
diff --git a/Viewer/src/UserMessage.cpp b/Viewer/src/UserMessage.cpp
new file mode 100644
index 0000000..88b7eff
--- /dev/null
+++ b/Viewer/src/UserMessage.cpp
@@ -0,0 +1,73 @@
+
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include <iostream>
+
+#include <QMessageBox>
+
+#include "UserMessage.hpp"
+
+bool UserMessage::echoToCout_ = true; // XXX should be false to start with
+
+UserMessage::UserMessage()
+{
+}
+
+void UserMessage::message(MessageType type, bool popup, const std::string& message)
+{
+
+ if (echoToCout_)
+ {
+ switch (type)
+ {
+ case INFO: std::cout << "INFO : "; break;
+ case WARN: std::cout << "WARN : "; break;
+ case ERROR: std::cout << "ERROR : "; break;
+ case DBG: std::cout << "DEBUG : "; break;
+ default: std::cout << " : "; break;
+ }
+
+ std::cout << message << std::endl;
+ }
+
+ if (popup)
+ {
+ QMessageBox::Icon icon;
+ switch (type)
+ {
+ case INFO: icon = QMessageBox::Information; break;
+ case WARN: icon = QMessageBox::Warning; break;
+ case ERROR: icon = QMessageBox::Critical; break;
+ case DBG: icon = QMessageBox::NoIcon; break;
+ default: icon = QMessageBox::NoIcon; break;
+ }
+ QString title("Ecflowview");
+ QString qmsg = QString::fromStdString(message);
+
+ QMessageBox box(icon, title, qmsg);
+ box.exec();
+ }
+
+}
+
+void UserMessage::debug(const std::string& message)
+{
+ std::cout << "DEBUG : " << message << std::endl;
+}
+
+void UserMessage::qdebug(QString message)
+{
+ std::cout << "DEBUG : " << message.toStdString() << std::endl;
+}
+
+std::string UserMessage::toString(int v)
+{
+ return QString::number(v).toStdString();
+}
diff --git a/Viewer/src/UserMessage.hpp b/Viewer/src/UserMessage.hpp
new file mode 100644
index 0000000..afefcf9
--- /dev/null
+++ b/Viewer/src/UserMessage.hpp
@@ -0,0 +1,40 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef USER_MESSAGE_HPP_
+#define USER_MESSAGE_HPP_
+
+#include <QDebug>
+#include <QString>
+
+#include <string>
+
+class UserMessage
+{
+//Q_OBJECT
+public:
+ UserMessage();
+
+ enum MessageType {INFO, WARN, ERROR, DBG}; // note: cannot have DEBUG because of possible -DDEBUG in cpp!
+
+ static void setEchoToCout(bool toggle) {echoToCout_ = toggle;}
+ static void message(MessageType type, bool popup, const std::string& message);
+
+ static void debug(const std::string& message);
+ static void qdebug(QString message);
+ static std::string toString(int);
+
+private:
+ static bool echoToCout_;
+
+
+};
+
+
+#endif
diff --git a/Viewer/src/VAttribute.cpp b/Viewer/src/VAttribute.cpp
new file mode 100644
index 0000000..5746c12
--- /dev/null
+++ b/Viewer/src/VAttribute.cpp
@@ -0,0 +1,79 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "VAttribute.hpp"
+#include "VAttributeType.hpp"
+
+#include "VNode.hpp"
+
+VAttribute::VAttribute(VNode* parent,int index) : VItem(parent), type_(0), index_(index)
+{
+ data_=parent_->getAttributeData(index_,type_) ;
+}
+
+QString VAttribute::toolTip() const
+{
+ return (type_)?(type_->toolTip(data_)):QString();
+}
+
+void VAttribute::buildAlterCommand(std::vector<std::string>& cmd,
+ const std::string& action, const std::string& type,
+ const std::string& name,const std::string& value)
+{
+ cmd.push_back("ecflow_client");
+ cmd.push_back("--alter");
+ cmd.push_back(action);
+ cmd.push_back(type);
+
+ if(!name.empty())
+ {
+ cmd.push_back(name);
+ cmd.push_back(value);
+ }
+
+ cmd.push_back("<full_name>");
+
+}
+
+void VAttribute::buildAlterCommand(std::vector<std::string>& cmd,
+ const std::string& action, const std::string& type,
+ const std::string& value)
+{
+ cmd.push_back("ecflow_client");
+ cmd.push_back("--alter");
+ cmd.push_back(action);
+ cmd.push_back(type);
+ cmd.push_back(value);
+
+ cmd.push_back("<full_name>");
+}
+
+QString VAttribute::name() const
+{
+ if(data_.count() >= 2)
+ return data_[1];
+
+ return QString();
+}
+
+std::string VAttribute::strName() const
+{
+ return name().toStdString();
+}
+
+bool VAttribute::isValid(VNode* parent)
+{
+ if(type_)
+ {
+ return type_->exists(parent,data_);
+ }
+
+ return false;
+}
diff --git a/Viewer/src/VAttribute.hpp b/Viewer/src/VAttribute.hpp
new file mode 100644
index 0000000..ccfb4de
--- /dev/null
+++ b/Viewer/src/VAttribute.hpp
@@ -0,0 +1,51 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VATTRIBUTE_HPP
+#define VATTRIBUTE_HPP
+
+#include "VItem.hpp"
+
+#include <QStringList>
+#include <string>
+#include <vector>
+
+class VAttributeType;
+class VNode;
+
+class VAttribute : public VItem
+{
+public:
+ VAttribute(VNode* parent,int index);
+
+ VAttribute* isAttribute() const {return const_cast<VAttribute*>(this);}
+ VAttributeType* type() const {return type_;}
+ QStringList data() const {return data_;}
+ QString toolTip() const;
+ QString name() const;
+ std::string strName() const;
+ bool isValid(VNode* parent);
+
+ static void buildAlterCommand(std::vector<std::string>& cmd,
+ const std::string& action, const std::string& type,
+ const std::string& name,const std::string& value);
+
+ static void buildAlterCommand(std::vector<std::string>& cmd,
+ const std::string& action, const std::string& type,
+ const std::string& value);
+protected:
+ VAttributeType* type_;
+ QStringList data_;
+ int index_;
+};
+
+
+#endif // VATTRIBUTE_HPP
+
diff --git a/Viewer/src/VAttributeType.cpp b/Viewer/src/VAttributeType.cpp
new file mode 100644
index 0000000..dbfaf37
--- /dev/null
+++ b/Viewer/src/VAttributeType.cpp
@@ -0,0 +1,1280 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "VAttributeType.hpp"
+
+#include <QDebug>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <map>
+
+#include "VNode.hpp"
+#include "UserMessage.hpp"
+#include "VConfigLoader.hpp"
+#include "VProperty.hpp"
+#include "VFilter.hpp"
+#include "VRepeat.hpp"
+
+std::map<std::string,VAttributeType*> VAttributeType::items_;
+
+//#define _UI_ATTR_DEBUG
+
+class VMeterAttribute : public VAttributeType
+{
+public:
+ explicit VMeterAttribute(const std::string& n) : VAttributeType(n) {}
+ int num(const VNode *node);
+ bool getData(VNode *node,int row,int& size,QStringList& data);
+ QString toolTip(QStringList d) const;
+ bool exists(const VNode* vnode,QStringList) const;
+};
+
+class VEventAttribute : public VAttributeType
+{
+public:
+ explicit VEventAttribute(const std::string& n) : VAttributeType(n) {}
+ int num(const VNode *node);
+ bool getData(VNode *node,int row,int& size,QStringList& data);
+ QString toolTip(QStringList d) const;
+ bool exists(const VNode* vnode,QStringList) const;
+};
+
+class VRepeatAttribute : public VAttributeType
+{
+public:
+ explicit VRepeatAttribute(const std::string& n) : VAttributeType(n) {}
+ int num(const VNode *node);
+ bool getData(VNode *node,int row,int& size,QStringList& data);
+ QString toolTip(QStringList d) const;
+ bool exists(const VNode* vnode,QStringList) const;
+};
+
+class VTriggerAttribute : public VAttributeType
+{
+public:
+ explicit VTriggerAttribute(const std::string& n) : VAttributeType(n) {}
+ int num(const VNode *node);
+ bool getData(VNode *node,int row,int& size,QStringList& data);
+ QString toolTip(QStringList d) const;
+};
+
+class VLabelAttribute : public VAttributeType
+{
+public:
+ explicit VLabelAttribute(const std::string& n) : VAttributeType(n) {}
+ int num(const VNode *node);
+ bool getData(VNode *node,int row,int& size,QStringList& data);
+ int lineNum(const VNode* vnode,int row);
+ QString toolTip(QStringList d) const;
+ bool exists(const VNode* vnode,QStringList) const;
+};
+
+class VDateAttribute : public VAttributeType
+{
+public:
+ explicit VDateAttribute(const std::string& n) : VAttributeType(n) {}
+ int num(const VNode *node);
+ bool getData(VNode *node,int row,int& size,QStringList& data);
+ QString toolTip(QStringList d) const;
+};
+
+class VTimeAttribute : public VAttributeType
+{
+public:
+ explicit VTimeAttribute(const std::string& n) : VAttributeType(n) {}
+ int num(const VNode *node);
+ bool getData(VNode *node,int row,int& size,QStringList& data);
+ QString toolTip(QStringList d) const;
+};
+
+class VLimitAttribute : public VAttributeType
+{
+public:
+ explicit VLimitAttribute(const std::string& n) : VAttributeType(n) {}
+ int num(const VNode *node);
+ bool getData(VNode *node,int row,int& size,QStringList& data);
+ QString toolTip(QStringList d) const;
+ bool exists(const VNode* vnode,QStringList) const;
+};
+
+class VLimiterAttribute : public VAttributeType
+{
+public:
+ explicit VLimiterAttribute(const std::string& n) : VAttributeType(n) {}
+ int num(const VNode *node);
+ bool getData(VNode *node,int row,int& size,QStringList& data);
+ QString toolTip(QStringList d) const;
+};
+
+class VLateAttribute : public VAttributeType
+{
+public:
+ explicit VLateAttribute(const std::string& n) : VAttributeType(n) {}
+ int num(const VNode *node);
+ bool getData(VNode *node,int row,int& size,QStringList& data);
+ QString toolTip(QStringList d) const;
+};
+
+class VVarAttribute : public VAttributeType
+{
+public:
+ explicit VVarAttribute(const std::string& n) : VAttributeType(n) {}
+ int num(const VNode *node);
+ bool getData(VNode *node,int row,int& size,QStringList& data);
+ bool exists(const VNode* vnode,QStringList) const;
+};
+
+class VGenvarAttribute : public VAttributeType
+{
+public:
+ explicit VGenvarAttribute(const std::string& n) : VAttributeType(n) {}
+ int num(const VNode *node);
+ bool getData(VNode *node,int row,int& size,QStringList& data);
+ bool exists(const VNode* vnode,QStringList) const;
+};
+
+static VMeterAttribute meterAttr("meter");
+static VEventAttribute eventAttr("event");
+static VRepeatAttribute repeatAttr("repeat");
+static VTriggerAttribute triggerAttr("trigger");
+static VLabelAttribute labelAttr("label");
+static VTimeAttribute timeAttr("time");
+static VDateAttribute dateAttr("date");
+static VLimitAttribute limitAttr("limit");
+static VLimiterAttribute limiterAttr("limiter");
+static VLateAttribute lateAttr("late");
+static VVarAttribute varAttr("var");
+static VGenvarAttribute genvarAttr("genvar");
+
+
+VAttributeType::VAttributeType(const std::string& name) :
+ VParam(name)
+{
+ //items_.push_back(this);
+ items_[name]=this;
+}
+
+std::vector<VParam*> VAttributeType::filterItems()
+{
+ std::vector<VParam*> v;
+ for(std::map<std::string,VAttributeType*>::const_iterator it=items_.begin(); it != items_.end(); ++it)
+ {
+ v.push_back(it->second);
+ }
+
+ return v;
+}
+
+
+VAttributeType* VAttributeType::find(const std::string& name)
+{
+ std::map<std::string,VAttributeType*>::const_iterator it=items_.find(name);
+ if(it != items_.end())
+ return it->second;
+
+ return 0;
+
+ /* for(std::vector<VAttribute*>::const_iterator it=items_.begin(); it != items_.end(); it++)
+ {
+ if((*it)->stdName() == name)
+ return *it;
+ }
+
+ return NULL;*/
+}
+
+int VAttributeType::totalNum(const VNode *vnode, AttributeFilter *filter)
+{
+ if(!vnode)
+ return 0;
+
+ int total=0;
+ for(std::map<std::string,VAttributeType*>::const_iterator it=items_.begin(); it != items_.end(); ++it)
+ {
+ if(!filter || filter->isSet(it->second))
+ {
+ total+=it->second->num(vnode);
+ }
+ }
+
+ return total;
+}
+
+VAttributeType* VAttributeType::getType(const VNode *vnode,int row,AttributeFilter *filter)
+{
+ if(!vnode)
+ return NULL;
+
+ int totalRow=0;
+ for(std::map<std::string,VAttributeType*>::const_iterator it=items_.begin(); it != items_.end(); ++it)
+ {
+ if(!filter || filter->isSet(it->second))
+ {
+ int size=it->second->num(vnode);
+ if(row-totalRow >=0 && row-totalRow < size)
+ {
+ return it->second;
+ }
+ totalRow+=size;
+ }
+ }
+
+ return NULL;
+}
+
+bool VAttributeType::getData(VNode *vnode,int row,VAttributeType* &type,QStringList& data,AttributeFilter *filter)
+{
+ type=0;
+
+ if(!vnode)
+ return false;
+
+ int totalRow=0;
+ for(std::map<std::string,VAttributeType*>::const_iterator it=items_.begin(); it != items_.end(); ++it)
+ {
+ if(!filter || filter->isSet(it->second))
+ {
+ int size=0;
+ if(it->second->getData(vnode,row-totalRow,size,data))
+ {
+ type=it->second;
+ return true;
+ }
+ totalRow+=size;
+ }
+ }
+
+ return false;
+}
+
+bool VAttributeType::getData(const std::string& type,VNode* vnode,int row,QStringList& data,AttributeFilter *filter)
+{
+ if(VAttributeType* va=find(type))
+ {
+ if(!filter || filter->isSet(va))
+ {
+ int size=0;
+ return va->getData(vnode,row,size,data);
+ }
+ }
+ return false;
+}
+
+int VAttributeType::getLineNum(const VNode *vnode,int row,AttributeFilter *filter)
+{
+ if(!vnode)
+ return 1;
+
+ int totalRow=0;
+ for(std::map<std::string,VAttributeType*>::const_iterator it=items_.begin(); it != items_.end(); ++it)
+ {
+ if(!filter || filter->isSet(it->second))
+ {
+ int size=it->second->num(vnode);
+ if(row-totalRow >=0 && row-totalRow < size)
+ {
+ return it->second->lineNum(vnode,row-totalRow);
+ }
+ totalRow+=size;
+ }
+ }
+
+ return 1;
+}
+
+int VAttributeType::getRow(const VNode *vnode,int row,AttributeFilter *filter)
+{
+ if(!vnode)
+ return -1;
+
+ if(!filter)
+ return row;
+
+ int totalRow=0;
+ int realRow=0;
+ for(std::map<std::string,VAttributeType*>::const_iterator it=items_.begin(); it != items_.end(); ++it)
+ {
+ if(!filter || filter->isSet(it->second))
+ {
+ int size=it->second->num(vnode);
+ if(row-totalRow >=0 && row-totalRow < size)
+ {
+ return realRow+row-totalRow;
+ }
+ totalRow+=size;
+ realRow+=size;
+ }
+ else
+ {
+ realRow+=it->second->num(vnode);
+ }
+ }
+
+ return -1;
+}
+
+void VAttributeType::load(VProperty* group)
+{
+ Q_FOREACH(VProperty* p,group->children())
+ {
+ if(VAttributeType* obj=VAttributeType::find(p->strName()))
+ {
+ obj->setProperty(p);
+ }
+ }
+}
+
+//================================
+// Meters
+//================================
+
+int VMeterAttribute::num(const VNode *vnode)
+{
+ if(vnode->isServer())
+ return 0;
+
+ node_ptr node=vnode->node();
+ return (node.get())?static_cast<int>(node->meters().size()):0;
+}
+
+bool VMeterAttribute::getData(VNode *vnode,int row,int& size,QStringList& data)
+{
+ if(vnode->isServer())
+ return false;
+
+ node_ptr node=vnode->node();
+ if(!node.get())
+ return false;
+
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug("VMeterAttribute::getData -->");
+#endif
+ const std::vector<Meter>& v=node->meters();
+ if(row >=0 && row < v.size())
+ {
+ data << qName_ <<
+ QString::fromStdString(v.at(row).name()) <<
+ QString::number(v.at(row).value()) << QString::number(v.at(row).min()) << QString::number(v.at(row).max()) <<
+ QString::number(v.at(row).colorChange());
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug(" data=" + data.join(",").toStdString());
+#endif
+ return true;
+ }
+
+ size=v.size();
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug(" size=" + QString::number(size).toStdString());
+#endif
+ return false;
+}
+
+QString VMeterAttribute::toolTip(QStringList d) const
+{
+ QString t="<b>Type:</b> Meter<br>";
+ if(d.count() >=5)
+ {
+ t+="<b>Name:</b> " + d[1] + "<br>";
+ t+="<b>Value:</b> " + d[2]+ "<br>";
+ t+="<b>Minimum:</b> " + d[3] + "<br>";
+ t+="<b>Maximum:</b> " + d[4];
+ }
+ return t;
+}
+
+bool VMeterAttribute::exists(const VNode* vnode,QStringList data) const
+{
+ if(vnode->isServer())
+ return false;
+
+ node_ptr node=vnode->node();
+ if(!node)
+ return false;
+
+ if(data.count() != 6 && data[0] != qName_)
+ return false;
+
+ const std::vector<Meter>& v=node->meters();
+ for(size_t i=0; i < v.size(); i++)
+ {
+ if(v[i].name() == data[1].toStdString())
+ return true;
+ }
+
+ return false;
+}
+
+//================================
+// Labels
+//================================
+
+int VLabelAttribute::num(const VNode *vnode)
+{
+ if(vnode->isServer())
+ return 0;
+
+ node_ptr node=vnode->node();
+ return (node.get())?static_cast<int>(node->labels().size()):0;
+}
+
+bool VLabelAttribute::getData(VNode *vnode,int row,int& size,QStringList& data)
+{
+ if(vnode->isServer())
+ return false;
+
+ node_ptr node=vnode->node();
+ if(!node.get())
+ return false;
+
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug("VLabelAttribute::getData -->");
+#endif
+ const std::vector<Label>& v=node->labels();
+ if(row >=0 && row < v.size())
+ {
+ std::string val=v.at(row).new_value();
+ if(val.empty() || val == " ")
+ {
+ val=v.at(row).value();
+ }
+
+ data << qName_ <<
+ QString::fromStdString(v.at(row).name()) <<
+ QString::fromStdString(val);
+
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug(" data=" + data.join(",").toStdString());
+#endif
+ return true;
+ }
+ size=v.size();
+
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug(" size=" + QString::number(size).toStdString());
+#endif
+
+ return false;
+}
+
+int VLabelAttribute::lineNum(const VNode* vnode,int row)
+{
+ if(vnode->isServer())
+ return 1;
+
+ node_ptr node=vnode->node();
+ if(!node.get())
+ return 1;
+
+ const std::vector<Label>& v=node->labels();
+ if(row >=0 && row < v.size())
+ {
+ std::string val=v.at(row).new_value();
+ if(val.empty() || val == " ")
+ {
+ val=v.at(row).value();
+ }
+ return std::count(val.begin(), val.end(), '\n')+1;
+ }
+
+ return 1;
+}
+
+QString VLabelAttribute::toolTip(QStringList d) const
+{
+ QString t="<b>Type:</b> Label<br>";
+ if(d.count() >= 3)
+ {
+ t+="<b>Name:</b> " + d[1] + "<br>";
+ t+="<b>Value:</b> " + d[2];
+ }
+ return t;
+}
+
+bool VLabelAttribute::exists(const VNode* vnode,QStringList data) const
+{
+ if(vnode->isServer())
+ return false;
+
+ node_ptr node=vnode->node();
+ if(!node)
+ return false;
+
+ if(data.count() != 3 && data[0] != qName_)
+ return false;
+
+ const std::vector<Label>& v=node->labels();
+ for(size_t i=0; i < v.size(); i++)
+ {
+ if(v[i].name() == data[1].toStdString())
+ return true;
+ }
+
+ return false;
+}
+
+//================================
+// Events
+//================================
+
+int VEventAttribute::num(const VNode *vnode)
+{
+ if(vnode->isServer())
+ return 0;
+
+ node_ptr node=vnode->node();
+ return (node.get())? static_cast<int>(node->events().size()):0;
+}
+
+bool VEventAttribute::getData(VNode *vnode,int row,int& size,QStringList& data)
+{
+ if(vnode->isServer())
+ return false;
+
+ node_ptr node=vnode->node();
+ if(!node.get())
+ return false;
+
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug("VEventAttribute::getData -->");
+#endif
+ const std::vector<Event>& v=node->events();
+ if(row >=0 && row < v.size())
+ {
+ data << qName_ <<
+ QString::fromStdString(v.at(row).name_or_number()) <<
+ QString::number((v.at(row).value()==true)?1:0);
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug(" data=" + data.join(",").toStdString());
+#endif
+ return true;
+ }
+ size=v.size();
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug(" size=" + QString::number(size).toStdString());
+#endif
+
+ return false;
+}
+
+QString VEventAttribute::toolTip(QStringList d) const
+{
+ QString t="<b>Type:</b> Event<br>";
+ if(d.count() >=3)
+ {
+ t+="<b>Name:</b> " + d[1] + "<br>";
+ t+="<b>Status:</b> ";
+ t+=(d[2] == "1")?"set (true)":"clear (false)";
+
+ }
+ return t;
+}
+
+bool VEventAttribute::exists(const VNode* vnode,QStringList data) const
+{
+ if(vnode->isServer())
+ return false;
+
+ node_ptr node=vnode->node();
+ if(!node)
+ return false;
+
+ if(data.count() != 3 && data[0] != qName_)
+ return false;
+
+ const std::vector<Event>& v=node->events();
+ for(size_t i=0; i < v.size(); i++)
+ {
+ if(v[i].name_or_number() == data[1].toStdString())
+ return true;
+ }
+
+ return false;
+}
+
+//================================
+//Generated Variables
+//================================
+
+int VGenvarAttribute::num(const VNode *vnode)
+{
+ return vnode->genVariablesNum();
+
+ /*node_ptr node=vnode->node();
+ if(node.get())
+ {
+ std::vector<Variable> genV;
+ node->gen_variables(genV);
+ return static_cast<int>(genV.size());
+ }
+ return 0;*/
+}
+
+bool VGenvarAttribute::getData(VNode *vnode,int row,int& size,QStringList& data)
+{
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug("VGenvarAttribute::getData -->");
+#endif
+
+ std::vector<Variable> genV;
+ vnode->genVariables(genV);
+
+ /*node_ptr node=vnode->node();
+ if(!node.get())
+ return false;
+
+ std::vector<Variable> genV;
+ node->gen_variables(genV);*/
+
+ if(row >=0 && row < genV.size())
+ {
+ data << qName_ <<
+ QString::fromStdString(genV.at(row).name()) <<
+ QString::fromStdString(genV.at(row).theValue());
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug(" data=" + data.join(",").toStdString());
+#endif
+ return true;
+ }
+ size=genV.size();
+
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug(" size=" + QString::number(size).toStdString());
+#endif
+ return false;
+}
+
+bool VGenvarAttribute::exists(const VNode* vnode,QStringList data) const
+{
+ if(vnode->isServer())
+ return false;
+
+ node_ptr node=vnode->node();
+ if(!node)
+ return false;
+
+ if(data.count() != 3 && data[0] != qName_)
+ return false;
+
+ std::vector<Variable> v;
+ vnode->genVariables(v);
+
+ for(size_t i=0; i < v.size(); i++)
+ {
+ if(v[i].name() == data[1].toStdString())
+ return true;
+ }
+
+ return false;
+}
+
+//================================
+//Variables
+//================================
+
+int VVarAttribute::num(const VNode *vnode)
+{
+ return vnode->variablesNum();
+
+ //node_ptr node=vnode->node();
+ //return (node.get())?static_cast<int>(node->variables().size()):0;
+}
+
+bool VVarAttribute::getData(VNode *vnode,int row,int& size,QStringList& data)
+{
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug("VVarAttribute::getData -->");
+#endif
+
+ if(vnode->isServer())
+ {
+ std::vector<Variable> v;
+ vnode->variables(v);
+ //node_ptr node=vnode->node();
+ if(row >=0 && row < v.size())
+ {
+ data << qName_ <<
+ QString::fromStdString(v.at(row).name()) <<
+ QString::fromStdString(v.at(row).theValue());
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug(" data=" + data.join(",").toStdString());
+#endif
+ return true;
+ }
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug(" size=" + QString::number(size).toStdString());
+#endif
+ size=v.size();
+ }
+ else
+ {
+ node_ptr node=vnode->node();
+ if(!node.get())
+ return false;
+
+ const std::vector<Variable>& v=node->variables();
+ if(row >=0 && row < v.size())
+ {
+ data << qName_ <<
+ QString::fromStdString(v.at(row).name()) <<
+ QString::fromStdString(v.at(row).theValue());
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug(" data=" + data.join(",").toStdString());
+#endif
+ return true;
+ }
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug(" size=" + QString::number(size).toStdString());
+#endif
+ size=v.size();
+ }
+
+ return false;
+}
+
+bool VVarAttribute::exists(const VNode* vnode,QStringList data) const
+{
+ if(vnode->isServer())
+ return false;
+
+ node_ptr node=vnode->node();
+ if(!node)
+ return false;
+
+ if(data.count() != 3 && data[0] != qName_)
+ return false;
+
+ if(vnode->isServer())
+ {
+ std::vector<Variable> v;
+ vnode->variables(v);
+ for(size_t i=0; i < v.size(); i++)
+ {
+ if(v[i].name() == data[1].toStdString())
+ return true;
+ }
+ }
+ else
+ {
+ const std::vector<Variable>& v=node->variables();
+ for(size_t i=0; i < v.size(); i++)
+ {
+ if(v[i].name() == data[1].toStdString())
+ return true;
+ }
+ }
+
+ return false;
+}
+
+//================================
+// Limits
+//================================
+
+int VLimitAttribute::num(const VNode *vnode)
+{
+ if(vnode->isServer())
+ return 0;
+
+ node_ptr node=vnode->node();
+ return (node.get())?static_cast<int>(node->limits().size()):0;
+}
+
+bool VLimitAttribute::getData(VNode *vnode,int row,int& size,QStringList& data)
+{
+ if(vnode->isServer())
+ return false;
+
+ node_ptr node=vnode->node();
+ if(!node.get())
+ return false;
+
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug("VLimitAttribute::getData -->");
+#endif
+
+ const std::vector<limit_ptr>& v=node->limits();
+ if(row >=0 && row < v.size())
+ {
+ data << qName_ <<
+ QString::fromStdString(v.at(row)->name()) <<
+ QString::number(v.at(row)->value()) <<
+ QString::number(v.at(row)->theLimit());
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug(" data=" + data.join(",").toStdString());
+#endif
+
+ return true;
+ }
+ size=v.size();
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug(" size=" + QString::number(size).toStdString());
+#endif
+
+ return false;
+}
+
+QString VLimitAttribute::toolTip(QStringList d) const
+{
+ QString t="<b>Type:</b> Limit<br>";
+ if(d.count() >=4)
+ {
+ t+="<b>Name:</b> " + d[1] + "<br>";
+ t+="<b>Value:</b> " + d[2] + "<br>";
+ t+="<b>Maximum:</b> " + d[3];
+ }
+ return t;
+}
+
+bool VLimitAttribute::exists(const VNode* vnode,QStringList data) const
+{
+ if(vnode->isServer())
+ return false;
+
+ node_ptr node=vnode->node();
+ if(!node)
+ return false;
+
+ if(data.count() != 4 && data[0] != qName_)
+ return false;
+
+ const std::vector<limit_ptr>& v=node->limits();
+ for(size_t i=0; i < v.size(); i++)
+ {
+ if(v[i]->name() == data[1].toStdString())
+ return true;
+ }
+
+ return false;
+}
+
+//================================
+//Limiters
+//================================
+
+int VLimiterAttribute::num(const VNode *vnode)
+{
+ if(vnode->isServer())
+ return 0;
+
+ node_ptr node=vnode->node();
+ return (node)?static_cast<int>(node->inlimits().size()):0;
+}
+
+bool VLimiterAttribute::getData(VNode *vnode,int row,int& size,QStringList& data)
+{
+ if(vnode->isServer())
+ return false;
+
+ node_ptr node=vnode->node();
+ if(!node.get())
+ return false;
+
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug("VLimiterAttribute::getData -->");
+#endif
+ const std::vector<InLimit>& v=node->inlimits();
+ if(row >=0 && row < v.size())
+ {
+ data << qName_ <<
+ QString::fromStdString(v.at(row).name()) <<
+ QString::fromStdString(v.at(row).pathToNode());
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug(" data=" + data.join(",").toStdString());
+#endif
+ return true;
+ }
+ size=v.size();
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug(" size=" + QString::number(size).toStdString());
+#endif
+ return false;
+}
+
+QString VLimiterAttribute::toolTip(QStringList d) const
+{
+ QString t="<b>Type:</b> Limiter<br>";
+ if(d.count() >=3)
+ {
+ t+="<b>Limit:</b> " + d[1] + "<br>";
+ t+="<b>Node:</b> " + d[2];
+
+ }
+ return t;
+}
+
+//================================
+//Triggers
+//================================
+
+int VTriggerAttribute::num(const VNode *vnode)
+{
+ if(vnode->isServer())
+ return 0;
+
+ node_ptr node=vnode->node();
+ if(!node.get())
+ return false;
+ int num=(node->get_trigger())?1:0;
+ num+=(node->get_complete())?1:0;
+ return num;
+}
+
+bool VTriggerAttribute::getData(VNode *vnode,int row,int& size,QStringList& data)
+{
+ if(vnode->isServer())
+ return false;
+
+ node_ptr node=vnode->node();
+ if(!node.get())
+ return false;
+
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug("VTriggerAttribute::getData -->");
+#endif
+
+ Expression* eT=node->get_trigger();
+ Expression* eC=node->get_complete();
+
+ bool getTrigger=false;
+ bool getComplete=false;
+
+ if(row == 0)
+ { if(eT)
+ getTrigger=true;
+ else if(eC)
+ getComplete=true;
+ }
+ else if(row==1 && eC)
+ getComplete=true;
+
+ if(getTrigger)
+ {
+ data << qName_;
+ data << "0" << QString::fromStdString(eT->expression());
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug(" data=" + data.join(",").toStdString());
+#endif
+ return true;
+ }
+ else if(getComplete)
+ {
+ data << qName_;
+ data << "1" << QString::fromStdString(eC->expression());
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug(" data=" + data.join(",").toStdString());
+#endif
+ return true;
+ }
+
+ size=(eT)?1:0;
+ size+=(eC)?1:0;
+
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug(" size=" + QString::number(size).toStdString());
+#endif
+ return false;
+}
+
+QString VTriggerAttribute::toolTip(QStringList d) const
+{
+ QString t;
+ if(d.count() >=3)
+ {
+ if(d[1] == "0")
+ t+="<b>Type:</b> Trigger<br>";
+ else if(d[1] == "1")
+ t+="<b>Type:</b> Complete<br>";
+ else
+ return t;
+
+ t+="<b>Expression:</b> " + d[2];
+ }
+ return t;
+}
+
+//================================
+//Times
+//================================
+
+int VTimeAttribute::num(const VNode *vnode)
+{
+ if(vnode->isServer())
+ return 0;
+
+ node_ptr node=vnode->node();
+ return (node.get())?static_cast<int>(node->timeVec().size() + node->todayVec().size()+ node->crons().size()):0;
+}
+
+bool VTimeAttribute::getData(VNode *vnode,int row,int& size,QStringList& data)
+{
+ if(vnode->isServer())
+ return false;
+
+ node_ptr node=vnode->node();
+ if(!node.get())
+ return false;
+
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug("VTimeAttribute::getData -->");
+#endif
+
+ const std::vector<ecf::TimeAttr>& tV=node->timeVec();
+ const std::vector<ecf::TodayAttr>& tdV=node->todayVec();
+ const std::vector<ecf::CronAttr>& cV=node->crons();
+
+ if(row >=0 && row < tV.size()+tdV.size()+ cV.size())
+ {
+ data << qName_;
+ if(row < tV.size())
+ data << QString::fromStdString(tV.at(row).name());
+ else if(row < tV.size() + tdV.size())
+ data << QString::fromStdString(tdV.at(row-tV.size()).name());
+ else
+ data << QString::fromStdString(cV.at(row-tV.size()-tdV.size()).name());
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug(" data=" + data.join(",").toStdString());
+#endif
+ return true;
+ }
+
+ size=tV.size()+tdV.size()+ cV.size();
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug(" size=" + QString::number(size).toStdString());
+#endif
+ return false;
+}
+
+QString VTimeAttribute::toolTip(QStringList d) const
+{
+ QString t="<b>Type:</b> Time<br>";
+ if(d.count() >=2)
+ {
+ t+="<b>Name:</b> " + d[1];
+ }
+ return t;
+}
+
+
+
+//================================
+//Date
+//================================
+
+int VDateAttribute::num(const VNode *vnode)
+{
+ if(vnode->isServer())
+ return 0;
+
+ node_ptr node=vnode->node();
+ return (node.get())?static_cast<int>(node->dates().size() + node->days().size()):0;
+}
+
+bool VDateAttribute::getData(VNode *vnode,int row,int& size,QStringList& data)
+{
+ if(vnode->isServer())
+ return false;
+
+ node_ptr node=vnode->node();
+ if(!node.get())
+ return false;
+
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug("VDateAttribute::getData -->");
+#endif
+
+ const std::vector<DateAttr>& dV=node->dates();
+ const std::vector<DayAttr>& dayV=node->days();
+
+ if(row >=0 && row < dV.size()+dayV.size())
+ {
+ data << qName_;
+ if(row < dV.size())
+ data << QString::fromStdString(dV.at(row).name());
+ else
+ data << QString::fromStdString(dayV.at(row-dV.size()).name());
+
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug(" data=" + data.join(",").toStdString());
+#endif
+
+ return true;
+ }
+ size=dV.size()+dayV.size();
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug(" size=" + QString::number(size).toStdString());
+#endif
+ return false;
+}
+
+QString VDateAttribute::toolTip(QStringList d) const
+{
+ QString t="<b>Type:</b> Date<br>";
+ if(d.count() >=2)
+ {
+ t+="<b>Name:</b> " + d[1];
+ }
+ return t;
+}
+
+//================================
+//Repeat
+//================================
+
+int VRepeatAttribute::num(const VNode *vnode)
+{
+ if(vnode->isServer())
+ return 0;
+
+ node_ptr node=vnode->node();
+ return (node.get())?((node->repeat().empty())?0:1):0;
+}
+
+bool VRepeatAttribute::getData(VNode *vnode,int row,int& size,QStringList& data)
+{
+ if(vnode->isServer())
+ return false;
+
+ node_ptr node=vnode->node();
+ if(!node.get())
+ return false;
+
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug("VRepeatAttribute::getData -->");
+#endif
+
+ const Repeat& r=node->repeat();
+ if(row ==0 && !r.empty())
+ {
+ //We try to avoid creating a VRepeat object everytime we are here
+ std::string type=VRepeat::type(r);
+
+ data << qName_ << QString::fromStdString(type) <<
+ QString::fromStdString(r.name()) <<
+ QString::fromStdString(r.valueAsString()) <<
+ QString::fromStdString(r.value_as_string(r.start())) <<
+ QString::fromStdString(r.value_as_string(r.end())) <<
+ QString::number(r.step());
+
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug(" data=" + data.join(",").toStdString());
+#endif
+ return true;
+ }
+ size=(r.empty())?0:1;
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug(" size=" + QString::number(size).toStdString());
+#endif
+ return false;
+}
+
+QString VRepeatAttribute::toolTip(QStringList d) const
+{
+ QString t="<b>Type:</b> Repeat";
+ if(d.count() == 7)
+ {
+ t+=" " + d[1] + "<br>";
+
+ if(d[1] != "day")
+ {
+ t+="<b>Name:</b> " + d[2] + "<br>";
+ t+="<b>Value:</b> " + d[3] + "<br>";
+ t+="<b>Start:</b> " + d[4] + "<br>";
+ t+="<b>End:</b> " + d[5] + "<br>";
+ t+="<b>Step:</b> " + d[6];
+ }
+ else
+ {
+ t+="<b>Step:</b> " + d[6];
+ }
+ }
+
+ return t;
+}
+
+bool VRepeatAttribute::exists(const VNode* vnode,QStringList data) const
+{
+ if(vnode->isServer())
+ return false;
+
+ node_ptr node=vnode->node();
+ if(!node)
+ return false;
+
+ if(data.count() != 7 && data[0] != qName_)
+ return false;
+
+ const Repeat& r=node->repeat();
+ if(r.name() == data[2].toStdString())
+ {
+ return (VRepeat::type(r) == data[1].toStdString());
+ }
+
+ return false;
+}
+
+//================================
+//Late
+//================================
+
+int VLateAttribute::num(const VNode *vnode)
+{
+ if(vnode->isServer())
+ return 0;
+
+ node_ptr node=vnode->node();
+ return (node.get())?((node->get_late())?1:0):0;
+}
+
+bool VLateAttribute::getData(VNode *vnode,int row,int& size,QStringList& data)
+{
+ if(vnode->isServer())
+ return false;
+
+ node_ptr node=vnode->node();
+ if(!node.get())
+ return false;
+
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug("VLateAttribute::getData -->");
+#endif
+
+ ecf::LateAttr *late=node->get_late();
+ if(row ==0 && late)
+ {
+ data << qName_ << QString::fromStdString(late->name());
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug(" data=" + data.join(",").toStdString());
+#endif
+ return true;
+ }
+ size=(late)?1:0;
+#ifdef _UI_ATTR_DEBUG
+ UserMessage::debug(" size=" + QString::number(size).toStdString());
+#endif
+ return false;
+}
+
+QString VLateAttribute::toolTip(QStringList d) const
+{
+ QString t="<b>Type:</b> Late<br>";
+ if(d.count() >=2)
+ {
+ t+="<b>Name:</b> " + d[1];
+ }
+ return t;
+}
+
+static SimpleLoader<VAttributeType> loader("attribute");
+
diff --git a/Viewer/src/VAttributeType.hpp b/Viewer/src/VAttributeType.hpp
new file mode 100644
index 0000000..e19e403
--- /dev/null
+++ b/Viewer/src/VAttributeType.hpp
@@ -0,0 +1,56 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VATTRIBUTETYPE_HPP_
+#define VATTRIBUTETYPE_HPP_
+
+#include <set>
+#include <vector>
+#include <string>
+
+#include "VParam.hpp"
+
+class AttributeFilter;
+class VNode;
+
+class VAttributeType : public VParam
+{
+public:
+ explicit VAttributeType(const std::string& name);
+ virtual ~VAttributeType() {}
+
+ static std::vector<VParam*> filterItems();
+
+ static VAttributeType* getType(const VNode *vnode,int row,AttributeFilter *filter=0);
+ static bool getData(VNode* vnode,int row,VAttributeType* &type,QStringList& data,AttributeFilter *filter=0);
+ static bool getData(const std::string& type,VNode* vnode,int row,QStringList& data,AttributeFilter *filter=0);
+ static int totalNum(const VNode *vnode,AttributeFilter *filter=0);
+ static void init(const std::string& parFile);
+ static int getLineNum(const VNode *vnode,int row,AttributeFilter *filter=0);
+ static int getRow(const VNode *vnode,int row,AttributeFilter *filter=0);
+
+ static VAttributeType* find(const std::string& name);
+
+ //Called from VConfigLoader
+ static void load(VProperty*);
+
+ virtual QString toolTip(QStringList d) const {return QString();}
+ virtual bool exists(const VNode* vnode,QStringList) const {return false;}
+
+protected:
+ virtual bool getData(VNode *vnode,int row,int& totalRow,QStringList& data)=0;
+ virtual int num(const VNode* vnode)=0;
+ virtual int lineNum(const VNode* vnode,int row) {return 1;}
+
+private:
+ static std::map<std::string,VAttributeType*> items_;
+};
+
+#endif
diff --git a/Viewer/src/VConfig.cpp b/Viewer/src/VConfig.cpp
new file mode 100644
index 0000000..25ce49e
--- /dev/null
+++ b/Viewer/src/VConfig.cpp
@@ -0,0 +1,635 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "VConfig.hpp"
+#include "VConfigLoader.hpp"
+#include "VProperty.hpp"
+#include "VSettings.hpp"
+
+#include "DirectoryHandler.hpp"
+#include "SessionHandler.hpp"
+#include "UserMessage.hpp"
+
+#include "Version.hpp"
+
+#include <QDebug>
+
+#include <boost/property_tree/json_parser.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+
+VConfig* VConfig::instance_=0;
+
+//#define _UI_CONFIG_LOAD_DEBUG
+
+VConfig::VConfig()
+{
+ appName_="ecFlowUI";
+ appLongName_=appName_ + " (" + ecf::Version::raw() + ")";
+}
+
+VConfig::~VConfig()
+{
+ for(std::vector<VProperty*>::iterator it=groups_.begin(); it != groups_.end(); ++it)
+ {
+ delete *it;
+ }
+ groups_.clear();
+}
+
+
+VConfig* VConfig::instance()
+{
+ if(!instance_)
+ instance_=new VConfig();
+
+ return instance_;
+}
+
+void VConfig::init(const std::string& parDirPath)
+{
+ namespace fs=boost::filesystem;
+
+ fs::path parDir(parDirPath);
+
+ if(fs::exists(parDir) && fs::is_directory(parDir))
+ {
+ //fs::directory_iterator it(parDir);
+
+ //The conf files have to be loaded in alphabetical order!! At least NotifyChange require it!
+ //So we read the paths into a vector and sort it.
+ std::vector<fs::path> vec;
+ copy(fs::directory_iterator(parDir), fs::directory_iterator(), back_inserter(vec));
+ std::sort(vec.begin(), vec.end());
+
+ //The paths are now in alphabetical order
+ for(std::vector<fs::path>::const_iterator it=vec.begin(); it != vec.end(); ++it)
+ {
+ if(fs::is_regular_file(*it))
+ {
+ std::string name=it->filename().string();
+ if(name.find("_conf.json") != std::string::npos)
+ {
+ loadInit(it->string());
+ }
+ }
+ }
+ }
+
+ //Read gui definition for the editable properties
+ std::string guiFile=DirectoryHandler::concatenate(parDir.string(),"ecflowview_gui.json");
+ loadInit(guiFile);
+
+ //Read gui definition for the editable properties tahat can be cutomised per server
+ std::string guiServerFile=DirectoryHandler::concatenate(parDir.string(),"ecflowview_gui_server.json");
+ loadInit(guiServerFile);
+
+ //Load existing user settings for the editable properties
+ loadSettings();
+
+}
+
+void VConfig::loadInit(const std::string& parFile)
+{
+ //Parse param file using the boost JSON property tree parser
+ using boost::property_tree::ptree;
+ ptree pt;
+
+ try
+ {
+ read_json(parFile,pt);
+ }
+ catch (const boost::property_tree::json_parser::json_parser_error& e)
+ {
+ std::string errorMessage = e.what();
+ UserMessage::message(UserMessage::ERROR, true,
+ std::string("Fatal error!\nVConfig::load() unable to parse definition file: " + parFile + "\nMessage: " +errorMessage));
+ exit(1);
+ return;
+ }
+
+ //Loop over the groups
+ for(ptree::const_iterator itGr = pt.begin(); itGr != pt.end(); ++itGr)
+ {
+ ptree ptGr=itGr->second;
+
+ //Get the group name and create it
+ std::string groupName=itGr->first;
+ VProperty *grProp=new VProperty(groupName);
+ groups_.push_back(grProp);
+
+ UserMessage::message(UserMessage::DBG,false,std::string("VConfig::loadInit() read config group: ") + groupName);
+
+ //Load the property parameters. It will recursively add all the
+ //children properties.
+ loadProperty(ptGr,grProp);
+
+ //Add the group we created to the registered configloader
+ VConfigLoader::process(groupName,grProp);
+ }
+ }
+
+void VConfig::loadProperty(const boost::property_tree::ptree& pt,VProperty *prop)
+{
+ using boost::property_tree::ptree;
+
+ ptree::const_assoc_iterator itProp;
+
+ //Loop over the possible properties
+ for(ptree::const_iterator it = pt.begin(); it != pt.end(); ++it)
+ {
+ std::string name=it->first;
+ ptree ptProp=it->second;
+
+#ifdef _UI_CONFIG_LOAD_DEBUG
+ UserMessage::message(UserMessage::DBG,false," VConfig::loadProperty() read item: " + name);
+#endif
+ //Default value
+ if(name == "default")
+ {
+ std::string val=ptProp.get_value<std::string>();
+ prop->setDefaultValue(val);
+ }
+
+ //If it is just a key/value pair "line"
+ else if(name == "line" && ptProp.empty())
+ {
+ VProperty *chProp=new VProperty(name);
+ prop->addChild(chProp);
+ std::string val=ptProp.get_value<std::string>();
+
+ QString prefix=prop->param("prefix");
+ if(!prefix.isEmpty())
+ val=prefix.toStdString() + "." + val;
+
+#ifdef _UI_CONFIG_LOAD_DEBUG
+ UserMessage::message(UserMessage::DBG,false," VConfig::loadProperty() line: " + val);
+#endif
+ if(VProperty* lineEditProp=find(val))
+ {
+#ifdef _UI_CONFIG_LOAD_DEBUG
+ UserMessage::message(UserMessage::DBG,false," --> link found");
+#endif
+ chProp->setLink(lineEditProp);
+ }
+ else
+ {
+#ifdef _UI_CONFIG_LOAD_DEBUG
+ UserMessage::message(UserMessage::DBG,false," --> link NOT found");
+#endif
+ }
+ }
+ //If the property is a "line" (i.e. a line with additional parameters)
+ else if(prop->name() == "line" && name == "link")
+ {
+ std::string val=ptProp.get_value<std::string>();
+
+#ifdef _UI_CONFIG_LOAD_DEBUG
+ UserMessage::message(UserMessage::DBG,false," VConfig::loadProperty() line link: " + val);
+#endif
+ if(VProperty* lineEditProp=find(val))
+ {
+#ifdef _UI_CONFIG_LOAD_DEBUG
+ UserMessage::message(UserMessage::DBG,false," --> link found");
+#endif
+ prop->setLink(lineEditProp);
+ }
+ else
+ {
+#ifdef _UI_CONFIG_LOAD_DEBUG
+ UserMessage::message(UserMessage::DBG,false," --> link NOT found");
+#endif
+ }
+ }
+
+ //Here we only load the properties with
+ //children (i.e. key/value pairs (like "line" etc above)
+ //are ignored.
+ else if(!ptProp.empty())
+ {
+ VProperty *chProp=new VProperty(name);
+ prop->addChild(chProp);
+ loadProperty(ptProp,chProp);
+ chProp->adjustAfterLoad();
+ }
+ else
+ {
+ QString val=QString::fromStdString(ptProp.get_value<std::string>());
+ prop->setParam(QString::fromStdString(name),val);
+ }
+ }
+}
+
+VProperty* VConfig::find(const std::string& path)
+{
+ VProperty* res=0;
+
+ for(std::vector<VProperty*>::const_iterator it=groups_.begin();it != groups_.end(); ++it)
+ {
+ VProperty *vGroup=*it;
+ res=vGroup->find(path);
+ if(res)
+ {
+ return res;
+ }
+ }
+
+ return res;
+}
+
+VProperty* VConfig::group(const std::string& name)
+{
+ for(std::vector<VProperty*>::const_iterator it=groups_.begin();it != groups_.end(); ++it)
+ {
+ if((*it)->strName() == name)
+ return *it;
+ }
+
+ return 0;
+}
+
+VProperty* VConfig::cloneServerGui(VProperty *linkTarget)
+{
+ VProperty* gr=find("gui_server.server");
+
+ assert(gr);
+
+ VProperty* cGr=gr->clone(true,false);
+
+ std::vector<VProperty*> chVec;
+ cGr->collectChildren(chVec);
+ for(std::vector<VProperty*>::iterator it=chVec.begin(); it != chVec.end(); ++it)
+ {
+ VProperty *p=*it;
+ if(p->link())
+ {
+ p->setLink(linkTarget->find(p->link()->path()));
+ }
+ }
+
+ return cGr;
+}
+
+//Saves the global settings that can be edited through the gui
+void VConfig::saveSettings()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ std::string fName=cs->settingsFile();
+
+ VProperty *guiProp=group("gui");
+
+ saveSettings(fName,guiProp,NULL,true);
+}
+
+//Saves the settings per server that can be edited through the servers option gui
+void VConfig::saveSettings(const std::string& parFile,VProperty* guiProp,VSettings* vs,bool global)
+{
+ using boost::property_tree::ptree;
+ ptree pt;
+
+ //Get editable properties. We will operate on the links.
+ std::vector<VProperty*> linkVec;
+ guiProp->collectLinks(linkVec);
+
+ for(std::vector<VProperty*>::const_iterator it=linkVec.begin(); it != linkVec.end(); ++it)
+ {
+ if(global)
+ {
+ if((*it)->changed())
+ {
+ pt.put((*it)->path(),(*it)->valueAsString());
+ }
+ }
+
+ else
+ {
+ if(!(*it)->useMaster())
+ {
+ pt.put((*it)->path(),(*it)->valueAsString());
+ }
+ }
+ }
+
+ //Add settings stored in VSettings
+ if(vs)
+ {
+ //Loop over the possible properties
+ for(ptree::const_iterator it = vs->propertyTree().begin(); it != vs->propertyTree().end(); ++it)
+ {
+ pt.add_child(it->first,it->second);
+ }
+ }
+
+ write_json(parFile,pt);
+}
+
+//Loads the global settings that can be edited through the gui
+void VConfig::loadSettings()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ std::string parFile=cs->settingsFile();
+
+ VProperty *guiProp=group("gui");
+
+ loadSettings(parFile,guiProp,true);
+}
+
+//Loads the settings per server that can be edited through the servers option gui
+void VConfig::loadSettings(const std::string& parFile,VProperty* guiProp,bool global)
+{
+ //We will operate on the links
+ std::vector<VProperty*> linkVec;
+ guiProp->collectLinks(linkVec);
+
+ //Parse file using the boost JSON property tree parser
+ using boost::property_tree::ptree;
+ ptree pt;
+
+ try
+ {
+ read_json(parFile,pt);
+ }
+ catch (const boost::property_tree::json_parser::json_parser_error& e)
+ {
+ if(boost::filesystem::exists(parFile))
+ {
+ std::string errorMessage = e.what();
+ UserMessage::message(UserMessage::ERROR, true,
+ std::string("Error! VConfig::loadSettings() unable to parse settings file: " + parFile + " Message: " +errorMessage));
+ }
+ return;
+ }
+
+ for(std::vector<VProperty*>::const_iterator it=linkVec.begin(); it != linkVec.end(); ++it)
+ {
+ if(pt.get_child_optional((*it)->path()) != boost::none)
+ {
+ std::string val=pt.get<std::string>((*it)->path());
+
+ if(!global)
+ {
+ (*it)->setUseMaster(false);
+ }
+
+ (*it)->setValue(val);
+ }
+ }
+}
+
+void VConfig::loadImportedSettings(const boost::property_tree::ptree& pt,VProperty* guiProp)
+{
+ std::vector<VProperty*> linkVec;
+ guiProp->collectLinks(linkVec);
+
+ for(std::vector<VProperty*>::const_iterator it=linkVec.begin(); it != linkVec.end(); ++it)
+ {
+ if(pt.get_child_optional((*it)->path()) != boost::none)
+ {
+ std::string val=pt.get<std::string>((*it)->path());
+ (*it)->setValue(val);
+ }
+ else if((*it)->master())
+ {
+ (*it)->setUseMaster(true);
+ }
+ }
+}
+
+void VConfig::importSettings()
+{
+ boost::property_tree::ptree pt;
+
+ std::string globalRcFile(DirectoryHandler::concatenate(DirectoryHandler::rcDir(),"user.default.options"));
+ if(readRcFile(globalRcFile,pt))
+ {
+ VProperty* gr=VConfig::find("gui");
+ loadImportedSettings(pt,gr);
+ VConfig::saveSettings();
+ }
+}
+
+bool VConfig::readRcFile(const std::string& rcFile,boost::property_tree::ptree& pt)
+{
+ std::ifstream in(rcFile.c_str());
+
+ if(!in.good())
+ return false;;
+
+ bool hasValue=false;
+
+ std::string line;
+ while(getline(in,line))
+ {
+ std::string buf;
+ std::stringstream ssdata(line);
+ std::vector<std::string> vec;
+
+ while(ssdata >> buf)
+ {
+ vec.push_back(buf);
+ }
+
+ if(vec.size() >= 1)
+ {
+ std::vector<std::string> par;
+ boost::split(par,vec[0],boost::is_any_of(":"));
+
+ if(par.size()==2)
+ {
+ //Update
+ if(par[0] == "timeout")
+ {
+ pt.put("server.update.updateRateInSec",par[1]);
+ hasValue=true;
+ }
+ else if(par[0] == "poll")
+ {
+ pt.put("server.update.update",par[1]);
+ hasValue=true;
+ }
+
+ else if(par[0] == "drift")
+ {
+ pt.put("server.update.adaptiveUpdate",par[1]);
+ hasValue=true;
+ }
+ else if(par[0] == "maximum")
+ {
+ pt.put("server.update.maxAdaptiveUpdateRateInMin",par[1]);
+ hasValue=true;
+ }
+
+ //Files
+ else if(par[0] == "direct_read")
+ {
+ pt.put("server.files.readFilesFromDisk",par[1]);
+ hasValue=true;
+ }
+ else if(par[0] == "jobfile_length")
+ {
+ pt.put("server.files.maxOutputFileLines",par[1]);
+ hasValue=true;
+ }
+
+ //Popup
+ else if(par[0] == "aborted")
+ {
+ pt.put("server.notification.aborted.enabled",par[1]);
+ pt.put("server.notification.aborted.popup",par[1]);
+ hasValue=true;
+ }
+ else if(par[0] == "restarted")
+ {
+ pt.put("server.notification.restarted.enabled",par[1]);
+ pt.put("server.notification.restarted.popup",par[1]);
+ hasValue=true;
+ }
+ else if(par[0] == "late")
+ {
+ pt.put("server.notification.late.enabled",par[1]);
+ pt.put("server.notification.late.popup",par[1]);
+ hasValue=true;
+ }
+ else if(par[0] == "zombies")
+ {
+ pt.put("server.notification.zombie.enabled",par[1]);
+ pt.put("server.notification.zombie.popup",par[1]);
+ hasValue=true;
+ }
+ else if(par[0] == "aliases")
+ {
+ pt.put("server.notification.alias.enabled",par[1]);
+ pt.put("server.notification.alias.popup",par[1]);
+ hasValue=true;
+ }
+ //Suites
+ else if(par[0] == "new_suites")
+ {
+ pt.put("suite_filter.autoAddNew",par[1]);
+ hasValue=true;
+
+ }
+ else if(par[0] == "suites")
+ {
+ boost::property_tree::ptree suites;
+ suites.push_back(std::make_pair("",par[1]));
+
+ for(unsigned int j=1; j < vec.size(); j++)
+ {
+ suites.push_back(std::make_pair("",vec.at(j)));
+ }
+
+ pt.put_child("suite_filter.suites",suites);
+
+ pt.put("suite_filter.enabled","true");
+
+ hasValue=true;
+ }
+ }
+ }
+
+ } //while(getline)
+
+ in.close();
+
+ return hasValue;
+
+}
+/*
+void VConfig::decodeShowMask()
+{
+
+option<int> show::status32_ (globals::instance(), "show_mask32", 0);
+
+option<int> show::status_ (globals::instance(), "show_mask",
+ (1<<show::unknown)
+ |(1<<show::suspended)
+ |(1<<show::complete)
+ |(1<<show::queued)
+ |(1<<show::submitted)
+ |(1<<show::active)
+ |(1<<show::aborted)
+ |(1<<show::time_dependant)
+ |(1<<show::late_nodes)
+ // |(1<<show::migrated_nodes)
+ |(1<<show::rerun_tasks)
+ |(1<<show::nodes_with_messages)
+ |(1<<show::label)
+ |(1<<show::meter)
+ |(1<<show::event)
+ |(1<<show::repeat)
+ |(1<<show::time)
+ |(1<<show::date)
+ |(1<<show::late)
+ |(1<<show::inlimit)
+ |(1<<show::limit)
+ |(1<<show::trigger)
+ // & (~(1<<show::variable))
+ // & (~(1<<show::genvar))
+ |(1<<show::time_icon)
+ |(1<<show::date_icon)
+ |(1<<show::late_icon)
+ |(1<<show::waiting_icon)
+ |(1<<show::rerun_icon)
+ // |(1<<show::migrated_icon)
+ |(1<<show::message_icon)
+ // & (~(1<<show::defstatus_icon)) & (~(1<<show::zombie_icon))
+ );
+
+show::show(int f) : flag_(f) {
+ status_ = status_ & (~(1<<show::variable));
+ status_ = status_ & (~(1<<show::genvar));
+}
+
+show::~show() {}
+
+void show::on()
+{
+ if (flag_ > 31) {
+ status32_ = int(status32_) | (1<<(flag_-32));
+ } else {
+ status_ = int(status_ ) | (1<<(flag_));
+ }
+}
+
+void show::off()
+{
+ if (flag_ == show::all) {
+ status_ = 0xFFFF ; status32_ = 0xFFFF;
+ status32_ = (int) (status32_) & (~(1<<(show::none-32)));
+ status32_ = (int) (status32_) & (~(1<<(show::all -32)));
+ } else if (flag_ == show::none) {
+ status_ = 0; status32_ = 0;
+ } else if (flag_ > 31) {
+ status32_ = int(status32_) & (~(1<<(flag_-32)));
+ } else {
+ status_ = int(status_) & (~(1<<flag_));
+ }
+}
+
+bool show::wanted()
+{
+ if (flag_ > 31) {
+ return (int(status32_) & (1<<(flag_-32))) != 0;
+ } else {
+ return (int(status_ ) & (1<<flag_)) != 0;
+ }
+
+*/
+
+
+
+
+
+
+
+
+
diff --git a/Viewer/src/VConfig.hpp b/Viewer/src/VConfig.hpp
new file mode 100644
index 0000000..9bbee0c
--- /dev/null
+++ b/Viewer/src/VConfig.hpp
@@ -0,0 +1,64 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VCONFIG_HPP_
+#define VCONFIG_HPP_
+
+#include <vector>
+
+#include <boost/property_tree/ptree.hpp>
+
+class VProperty;
+class VServerSettings;
+class VSettings;
+
+//This singleton class stores the configuration of the viewer.
+
+class VConfig
+{
+ friend class VServerSettings;
+
+public:
+ ~VConfig();
+
+ static VConfig* instance();
+
+ const std::string& appName() {return appName_;}
+ const std::string& appLongName() {return appLongName_;}
+ void init(const std::string& parDir);
+ const std::vector<VProperty*>& groups() {return groups_;}
+ VProperty* find(const std::string& path);
+
+ VProperty* cloneServerGui(VProperty *linkTarget);
+
+ void saveSettings();
+ void importSettings();
+
+protected:
+ VConfig();
+
+ void loadInit(const std::string& parFile);
+ void loadProperty(const boost::property_tree::ptree& pt,VProperty *prop);
+ void loadSettings();
+ void saveSettings(const std::string& parFile,VProperty* guiProp,VSettings* vs,bool);
+ void loadSettings(const std::string& parFile,VProperty* guiProp,bool);
+ void loadImportedSettings(const boost::property_tree::ptree& pt,VProperty* guiProp);
+ bool readRcFile(const std::string& rcFile,boost::property_tree::ptree& pt);
+
+ VProperty* group(const std::string& name);
+
+ static VConfig* instance_;
+
+ std::string appName_;
+ std::string appLongName_;
+ std::vector<VProperty*> groups_;
+};
+
+#endif
diff --git a/Viewer/src/VConfigLoader.cpp b/Viewer/src/VConfigLoader.cpp
new file mode 100644
index 0000000..87ecb70
--- /dev/null
+++ b/Viewer/src/VConfigLoader.cpp
@@ -0,0 +1,51 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "VConfigLoader.hpp"
+
+#include <map>
+
+
+typedef std::multimap<std::string,VConfigLoader*> Map;
+
+static Map* makers = 0;
+
+VConfigLoader::VConfigLoader(const std::string& name)
+{
+ if(makers == 0)
+ makers = new Map();
+
+ makers->insert(Map::value_type(name,this));
+}
+
+VConfigLoader::~VConfigLoader()
+{
+ // Not called
+}
+
+bool VConfigLoader::process(const std::string& name,VProperty *prop)
+{
+ Map::size_type entries=makers->count(name);
+ Map::iterator it=makers->find(name);
+
+ bool retVal=false;
+ for(Map::size_type cnt=0; cnt != entries; ++cnt, ++it)
+ {
+ (*it).second->load(prop);
+ retVal=true;
+ }
+
+ /* if(it != makers->end())
+ {
+ (*it).second->load(prop);
+ return true;
+ }*/
+ return retVal;
+}
diff --git a/Viewer/src/VConfigLoader.hpp b/Viewer/src/VConfigLoader.hpp
new file mode 100644
index 0000000..688687f
--- /dev/null
+++ b/Viewer/src/VConfigLoader.hpp
@@ -0,0 +1,40 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VCONFIGLOADER_HPP_
+#define VCONFIGLOADER_HPP_
+
+#include <string>
+
+class VProperty;
+
+class VConfigLoader
+{
+public:
+ explicit VConfigLoader(const std::string& name);
+ virtual ~VConfigLoader();
+
+ virtual void load(VProperty* group) = 0;
+ static bool process(const std::string& name,VProperty*);
+
+private:
+ // No copy allowed
+ explicit VConfigLoader(const VConfigLoader&);
+ VConfigLoader& operator=(const VConfigLoader&);
+};
+
+template<class T>
+class SimpleLoader : public VConfigLoader {
+ void load(VProperty* prop) { T::load(prop); }
+public:
+ explicit SimpleLoader(const std::string& name) : VConfigLoader(name) {}
+};
+
+#endif
diff --git a/Viewer/src/VDir.cpp b/Viewer/src/VDir.cpp
new file mode 100644
index 0000000..15bbfc6
--- /dev/null
+++ b/Viewer/src/VDir.cpp
@@ -0,0 +1,99 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "VDir.hpp"
+#include "DirectoryHandler.hpp"
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/foreach.hpp>
+
+#include <boost/algorithm/string/predicate.hpp>
+
+
+VDir::VDir(const std::string& path) : path_(path)
+{
+}
+
+VDir::VDir(const std::string& path,const std::string& pattern) :
+ path_(path),
+ pattern_(pattern)
+{
+ reload();
+}
+
+VDir::~VDir()
+{
+ clear();
+}
+
+void VDir::path(const std::string& path,bool doReload)
+{
+ path_=path;
+ if(doReload)
+ reload();
+}
+
+void VDir::clear()
+{
+ for(std::vector<VDirItem*>::iterator it=items_.begin(); it != items_.end(); ++it)
+ delete (*it);
+}
+
+void VDir::addItem(const std::string& name, unsigned int size,unsigned int mtime)
+{
+ VDirItem* item=new VDirItem;
+
+ boost::filesystem::path p(name);
+ //std::string dirName=p.parent_path().string();
+ std::string fileName=p.leaf().string();
+
+ item->name_=fileName;
+ item->size_=size;
+ item->mtime_ = QDateTime::fromTime_t(mtime);
+
+ items_.push_back(item);
+
+}
+
+void VDir::reload()
+{
+ clear();
+
+ where_="localhost";
+
+ boost::filesystem::path path(path_);
+
+ boost::filesystem::directory_iterator it(path), eod;
+
+ BOOST_FOREACH(boost::filesystem::path const &p, std::make_pair(it, eod ))
+ {
+ if(is_regular_file(p) && boost::algorithm::starts_with(p.filename().string(),pattern_))
+ {
+ VDirItem* item=new VDirItem;
+
+ item->name_ = p.filename().string();
+ item->size_ = boost::filesystem::file_size(p);
+ item->size_ = boost::filesystem::file_size(p);
+ item->mtime_ = QDateTime::fromTime_t(boost::filesystem::last_write_time(p));
+ items_.push_back(item);
+
+ }
+ }
+}
+
+std::string VDir::fullName(int row)
+{
+ std::string res;
+ if(row >=0 && row < items_.size())
+ {
+ res=DirectoryHandler::concatenate(path_,items_.at(row)->name_);
+ }
+ return res;
+}
diff --git a/Viewer/src/VDir.hpp b/Viewer/src/VDir.hpp
new file mode 100644
index 0000000..74c7124
--- /dev/null
+++ b/Viewer/src/VDir.hpp
@@ -0,0 +1,66 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef VDIR_H
+#define VDIR_H
+
+#include <string>
+#include <vector>
+
+#include <QDateTime>
+
+#include <boost/shared_ptr.hpp>
+
+class VDirItem
+{
+public:
+ std::string name_;
+ //int mode_;
+ //int uid_;
+ //int gid_;
+ unsigned int size_;
+ //int atime_;
+ QDateTime mtime_;
+ //int ctime_;
+ std::string method_;
+};
+
+class VDir
+{
+public:
+ explicit VDir(const std::string& path);
+ VDir(const std::string& path, const std::string& pattern);
+
+ ~VDir();
+
+ const std::string& path() const {return path_;}
+ void path(const std::string& path,bool reload=true);
+
+ const std::string& where() const {return where_;}
+ void where(const std::string& w) {where_=w;}
+
+ std::string fullName(int row);
+
+ int count() const {return static_cast<int>(items_.size());}
+ void clear();
+ void reload();
+ void addItem(const std::string&, unsigned int, unsigned int);
+ const std::vector<VDirItem*>& items() const {return items_;}
+
+protected:
+ std::string path_;
+ std::string pattern_;
+ std::string where_;
+ std::vector<VDirItem*> items_;
+};
+
+class VDir;
+typedef boost::shared_ptr<VDir> VDir_ptr;
+
+#endif
diff --git a/Viewer/src/VFile.cpp b/Viewer/src/VFile.cpp
new file mode 100644
index 0000000..209e3ac
--- /dev/null
+++ b/Viewer/src/VFile.cpp
@@ -0,0 +1,265 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <iostream>
+#include <fstream>
+#include <string.h>
+
+#include "DirectoryHandler.hpp"
+#include "VFile.hpp"
+#include "UserMessage.hpp"
+
+#include <boost/lexical_cast.hpp>
+
+const size_t VFile::maxDataSize_=1024*1024*10;
+
+VFile::VFile(const std::string& name,const std::string& str,bool deleteFile) :
+ path_(name),
+ deleteFile_(deleteFile),
+ storageMode_(DiskStorage),
+ data_(0),
+ dataSize_(0),
+ fp_(0),
+ fetchMode_(NoFetchMode),
+ transferDuration_(0),
+ cached_(false)
+{
+ std::ofstream f(path_.c_str());
+ if(f.is_open())
+ {
+ f << str;
+ f.close();
+ }
+}
+
+VFile::VFile(const std::string& name,bool deleteFile) :
+ path_(name),
+ deleteFile_(deleteFile),
+ storageMode_(DiskStorage),
+ data_(0),
+ dataSize_(0),
+ fp_(0),
+ fetchMode_(NoFetchMode),
+ transferDuration_(0),
+ cached_(false)
+{
+}
+
+VFile::VFile(bool deleteFile) :
+ path_(""),
+ deleteFile_(deleteFile),
+ storageMode_(MemoryStorage),
+ data_(0),
+ dataSize_(0),
+ fp_(0),
+ fetchMode_(NoFetchMode),
+ transferDuration_(0),
+ cached_(false)
+{
+}
+
+VFile::~VFile()
+{
+ close();
+
+ UserMessage::message(UserMessage::DBG,false,"VFile::~VFile -->");
+ print();
+
+ if(data_)
+ {
+ delete [] data_;
+ UserMessage::debug(" memory released");
+ }
+
+ //TODO: add further/better checks
+ if(deleteFile_ &&
+ exists() && !path_.empty() && path_ != "/" && path_.size() > 4)
+ {
+ unlink(path_.c_str());
+ UserMessage::debug(" file deleted from disk");
+ }
+ else if(!path_.empty() && exists())
+ {
+ UserMessage::debug(" file was kept on disk");
+ }
+
+ UserMessage::debug("<-- VFile::~VFile");
+}
+
+bool VFile::exists() const
+{
+ if(path_.empty())
+ return false;
+ return (access(path_.c_str(), R_OK) ==0);
+}
+
+VFile_ptr VFile::create(const std::string& path,const std::string& str,bool deleteFile)
+{
+ return VFile_ptr(new VFile(path,str,deleteFile));
+}
+
+VFile_ptr VFile::create(const std::string& path,bool deleteFile)
+{
+ return VFile_ptr(new VFile(path,deleteFile));
+}
+
+VFile_ptr VFile::create(bool deleteFile)
+{
+ return VFile_ptr(new VFile(deleteFile));
+}
+
+void VFile::setStorageMode(StorageMode mode)
+{
+ if(storageMode_ == mode)
+ return;
+
+ storageMode_=mode;
+
+ if(storageMode_== DiskStorage)
+ {
+ if(dataSize_ > 0)
+ {
+ if(path_.empty())
+ path_=DirectoryHandler::tmpFileName();
+
+ fp_ = fopen(path_.c_str(),"w");
+ if(fwrite(data_,1,dataSize_,fp_) != dataSize_)
+ {
+
+ }
+ fclose(fp_);
+ fp_=NULL;
+ delete [] data_;
+ data_=0;
+ dataSize_=0;
+ }
+ }
+}
+
+bool VFile::write(const std::string& buf,std::string& err)
+{
+ return write(buf.c_str(),buf.size(),err);
+}
+
+bool VFile::write(const char *buf,size_t len,std::string& err)
+{
+ //printf("total:%d \n len: %d \n",dataSize_,len);
+
+ //Keep data in memory
+ if(storageMode_ == MemoryStorage)
+ {
+ if(!data_)
+ {
+ data_ = new char[maxDataSize_+1];
+ }
+
+ if(dataSize_ + len < maxDataSize_)
+ {
+ memcpy(data_+dataSize_,buf,len);
+ dataSize_+=len;
+ return true;
+ }
+ else
+ {
+ setStorageMode(DiskStorage);
+ }
+ }
+
+ //Write data to disk
+ if(storageMode_ == DiskStorage)
+ {
+ if(!fp_)
+ {
+ if(path_.empty())
+ path_=DirectoryHandler::tmpFileName();
+
+ fp_ = fopen(path_.c_str(),"a");
+ }
+
+ if(fwrite(buf,1,len,fp_) != len)
+ {
+ //char buf_loc[2048];
+ //sprintf(buf_loc,"Write error on %s",out->path().c_str());
+ //gui::syserr(buf);
+ fclose(fp_);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void VFile::close()
+{
+ if(fp_)
+ {
+ fclose(fp_);
+ fp_=NULL;
+ }
+ if(data_)
+ {
+ data_[dataSize_]='\0';
+ dataSize_++;
+ }
+}
+
+/*
+std::string VFile::tmpName()
+{
+ std::string res;
+
+#if defined(linux) || defined(_AIX)
+
+ char *path = getenv("SCRATCH");
+ char *s = (char*) malloc(128);
+
+ if (!path || !access(path, R_OK))
+ path=getenv("TMPDIR");
+
+ if (!path || !access(path, R_OK))
+ path=(char*)"/tmp";
+
+ snprintf(s, 128, "%s/%sXXXXXX", path, "ecflow_ui");
+ if(mkstemp(s) != -1)
+ {
+ res=std::string(s);
+ }
+
+ free(s);
+
+#else
+
+// char* s=std::string(tmpnam(NULL));
+ res=std::string(tmpnam(NULL));
+
+#endif
+
+ return res;
+
+}
+*/
+
+void VFile::print()
+{
+ std::string str=" VFile contents --> storage:";
+ if(storageMode_ == MemoryStorage)
+ {
+ str+="memory size:" + boost::lexical_cast<std::string>(dataSize_);
+ }
+ else
+ {
+ str+="disk path: " + path_;
+ }
+
+ UserMessage::message(UserMessage::DBG,false,str);
+}
+
diff --git a/Viewer/src/VFile.hpp b/Viewer/src/VFile.hpp
new file mode 100644
index 0000000..c510b06
--- /dev/null
+++ b/Viewer/src/VFile.hpp
@@ -0,0 +1,98 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef VFILE_INC__
+#define VFILE_INC__
+
+#include <string>
+#include <vector>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+
+#include <QDateTime>
+
+class VFile;
+typedef boost::shared_ptr<VFile> VFile_ptr;
+
+class VFile : public boost::enable_shared_from_this<VFile>
+{
+public:
+ virtual ~VFile();
+
+ enum StorageMode {MemoryStorage,DiskStorage};
+ enum FetchMode {NoFetchMode,LocalFetchMode,ServerFetchMode,LogServerFetchMode};
+
+ const std::string& path() const {return path_;}
+ const std::string& sourcePath() const {return sourcePath_;}
+ void setSourcePath(const std::string& p) {sourcePath_=p;}
+ void setContents(const std::string);
+ bool exists() const;
+
+ StorageMode storageMode() const {return storageMode_;}
+ static const size_t maxDataSize() {return maxDataSize_;}
+ size_t dataSize() const {return dataSize_;}
+ const char* data() const {return data_;}
+
+ void setTransferDuration(unsigned int d) {transferDuration_=d;}
+ unsigned int transferDuration() const {return transferDuration_;}
+ void setFetchDate(QDateTime d) {fetchDate_=d;}
+ QDateTime fetchDate() const {return fetchDate_;}
+ void setFetchMode(FetchMode m) {fetchMode_=m;}
+ FetchMode fetchMode() const {return fetchMode_;}
+ void setFetchModeStr(const std::string& fetchMethod) {fetchModeStr_=fetchMethod;}
+ const std::string& fetchModeStr() const {return fetchModeStr_;}
+ int truncatedTo() const {return truncatedTo_;}
+ void setTruncatedTo(int t) {truncatedTo_=t;}
+ void setCached(bool b) {cached_=b;}
+ bool cached() const {return cached_;}
+ void setLog(const std::vector<std::string>& log) {log_=log;}
+ void addToLog(const std::string& s) {log_.push_back(s);}
+ const std::vector<std::string>& log() const {return log_;}
+
+ bool write(const char *buf,size_t len,std::string& err);
+ bool write(const std::string& buf,std::string& err);
+
+ void close();
+ void print();
+
+ static VFile_ptr create(const std::string& path,const std::string& contents,bool deleteFile=true);
+ static VFile_ptr create(const std::string& path,bool deleteFile= true);
+ static VFile_ptr create(bool deleteFile= true);
+
+ //static std::string tmpName();
+
+protected:
+ VFile(const std::string& name,const std::string& str,bool deleteFile=true);
+ VFile(const std::string& str,bool deleteFile= true);
+ explicit VFile(bool deleteFile= true);
+ void setStorageMode(StorageMode);
+
+ std::string path_;
+ std::string sourcePath_;
+ bool deleteFile_;
+
+ StorageMode storageMode_;
+ static const size_t maxDataSize_;
+ char* data_;
+ size_t dataSize_;
+ FILE* fp_;
+
+ FetchMode fetchMode_;
+ std::string fetchModeStr_;
+ QDateTime fetchDate_;
+ unsigned int transferDuration_;
+ int truncatedTo_;
+
+ bool cached_;
+ std::vector<std::string> log_;
+
+};
+
+#endif
diff --git a/Viewer/src/VFileInfo.cpp b/Viewer/src/VFileInfo.cpp
new file mode 100644
index 0000000..d96a647
--- /dev/null
+++ b/Viewer/src/VFileInfo.cpp
@@ -0,0 +1,107 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "VFileInfo.hpp"
+
+#include <QDateTime>
+#include <QObject>
+
+QString VFileInfo::formatSize() const
+{
+ return formatSize(size());
+}
+
+QString VFileInfo::formatModDate() const
+{
+ QDateTime dt=lastModified();
+ return dt.toString("yyyy-MM-dd hh:mm:ss");
+}
+
+QString VFileInfo::formatPermissions() const
+{
+ QString str(permission(QFile::ReadOwner)?"r":"-");
+ str+=(permission(QFile::WriteOwner)?"w":"-");
+ str+=(permission(QFile::ExeOwner)?"x":"-");
+ str+=(permission(QFile::ReadGroup)?"r":"-");
+ str+=(permission(QFile::WriteGroup)?"w":"-");
+ str+=(permission(QFile::ExeGroup)?"x":"-");
+ str+=(permission(QFile::ReadOther)?"r":"-");
+ str+=(permission(QFile::WriteOther)?"w":"-");
+ str+=(permission(QFile::ExeOther)?"x":"-");
+
+ return str;
+}
+
+QString VFileInfo::formatSize(unsigned int size)
+{
+ if(size < 1024)
+ return QString::number(size) + " B";
+ else if(size < 1024*1024)
+ return QString::number(size/1024) + " KB";
+ else if(size < 1024*1024*1024)
+ return QString::number(size/(1024*1024)) + " MB";
+ else
+ return QString::number(size/(1024*1024*1024)) + " GB";
+
+ return QString();
+}
+
+QString VFileInfo::formatDate(const std::time_t& t)
+{
+ QDateTime dt=QDateTime::fromTime_t(t);
+ return dt.toString("yyyy-MM-dd hh:mm:ss");
+}
+
+QString VFileInfo::formatDateAgo(const std::time_t& t)
+{
+ QString str=QObject::tr("Right now");
+
+ time_t now = time(0);
+
+ int delta = now - t;
+ if(delta<0) delta = 0;
+
+ if( t== 0)
+ {
+ return QObject::tr("never");
+ }
+
+ if(delta ==1)
+ str=QObject::tr("1 second ago");
+
+ else if(delta >=1 && delta < 60)
+ {
+ str=QString::number(delta) + QObject::tr(" second") + ((delta==1)?"":"s") + QObject::tr(" ago");
+ }
+
+ else if(delta >= 60 && delta < 60*60)
+ {
+ int val=delta/60;
+ str=QString::number(val) + QObject::tr(" minute") + ((val==1)?"":"s") + QObject::tr(" ago");
+ }
+
+ else if(delta >= 60*60 && delta < 60*60*24)
+ {
+ int val=delta/(60*60);
+ str=QString::number(val) + QObject::tr(" hour") + ((val==1)?"":"s") + QObject::tr(" ago");
+ }
+
+ else if(delta >= 60*60*24)
+ {
+ int val=delta/(60*60*24);
+ str=QString::number(val) + QObject::tr(" day") + ((val==1)?"":"s") + QObject::tr(" ago");
+ }
+
+ return str;
+}
+
+
+
+
+
diff --git a/Viewer/src/VFileInfo.hpp b/Viewer/src/VFileInfo.hpp
new file mode 100644
index 0000000..2df8590
--- /dev/null
+++ b/Viewer/src/VFileInfo.hpp
@@ -0,0 +1,31 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef VFILEINFO_H_
+#define VFILEINFO_H_
+
+#include <QFileInfo>
+
+#include <ctime>
+
+class VFileInfo : public QFileInfo
+{
+public:
+ explicit VFileInfo(const QString& file) : QFileInfo(file) {}
+
+ QString formatSize() const;
+ QString formatModDate() const;
+ QString formatPermissions() const;
+
+ static QString formatSize(unsigned int size);
+ static QString formatDate(const std::time_t& t);
+ static QString formatDateAgo(const std::time_t& t);
+};
+
+#endif
diff --git a/Viewer/src/VFilter.cpp b/Viewer/src/VFilter.cpp
new file mode 100644
index 0000000..be5c17a
--- /dev/null
+++ b/Viewer/src/VFilter.cpp
@@ -0,0 +1,597 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "VFilter.hpp"
+
+#include "NodeQuery.hpp"
+#include "NodeQueryEngine.hpp"
+#include "UserMessage.hpp"
+#include "VNState.hpp"
+#include "VAttributeType.hpp"
+#include "VIcon.hpp"
+#include "VNode.hpp"
+#include "VParam.hpp"
+#include "VSettings.hpp"
+#include "VTree.hpp"
+
+#include "ServerFilter.hpp"
+#include "ServerHandler.hpp"
+
+#include <QDebug>
+#include <QTime>
+
+#include <algorithm>
+
+#define _UI_VFILTER_DEBUG
+
+//==============================================
+//
+// VFilter
+//
+//==============================================
+
+VParamSet::VParamSet()
+{
+}
+
+void VParamSet::init(const std::vector<VParam*>& items)
+{
+ for(std::vector<VParam*>::const_iterator it=items.begin(); it != items.end(); ++it)
+ {
+ all_.insert((*it));
+ }
+}
+
+bool VParamSet::isSet(VParam* p) const
+{
+ if(!p)
+ return false;
+
+ return (current_.find(p) != current_.end());
+}
+
+bool VParamSet::isSet(const std::string &name) const
+{
+ for(std::set<VParam*>::const_iterator it=current_.begin(); it != current_.end(); ++it)
+ {
+ if((*it)->strName() == name)
+ return true;
+ }
+ return false;
+}
+
+QStringList VParamSet::currentAsList() const
+{
+ QStringList lst;
+ for(std::set<VParam*>::const_iterator it=current_.begin(); it != current_.end(); ++it)
+ {
+ lst << QString::fromStdString((*it)->strName());
+ }
+ return lst;
+}
+
+void VParamSet::setCurrent(const std::set<VParam*>& items)
+{
+ current_.clear();
+ for(std::set<VParam*>::const_iterator it=all_.begin(); it != all_.end(); ++it)
+ {
+ if(items.find(*it) != items.end())
+ current_.insert(*it);
+ }
+
+ Q_EMIT changed();
+}
+
+void VParamSet::current(const std::set<std::string>& names)
+{
+ current_.clear();
+ for(std::set<VParam*>::const_iterator it=all_.begin(); it != all_.end(); ++it)
+ {
+ if(names.find((*it)->strName()) != names.end())
+ current_.insert(*it);
+ }
+
+ Q_EMIT changed();
+}
+
+void VParamSet::setCurrent(QStringList names)
+{
+ current_.clear();
+ for(std::set<VParam*>::const_iterator it=all_.begin(); it != all_.end(); ++it)
+ {
+ if(names.contains(QString::fromStdString((*it)->strName())))
+ current_.insert(*it);
+ }
+
+ Q_EMIT changed();
+}
+
+
+void VParamSet::writeSettings(VSettings *vs)
+{
+ std::vector<std::string> array;
+
+ for(std::set<VParam*>::const_iterator it=current_.begin(); it != current_.end(); ++it)
+ {
+ array.push_back((*it)->strName());
+ }
+
+ vs->put(settingsId_,array);
+}
+
+void VParamSet::readSettings(VSettings* vs)
+{
+ current_.clear();
+
+ std::vector<std::string> array;
+ vs->get(settingsId_,array);
+
+ for(std::vector<std::string>::const_iterator it = array.begin(); it != array.end(); ++it)
+ {
+ std::string name=*it;
+ for(std::set<VParam*>::const_iterator itA=all_.begin(); itA != all_.end(); ++itA)
+ {
+ if((*itA)->strName() == name)
+ current_.insert(*itA);
+ }
+ }
+}
+
+//==============================================
+//
+// StateFilter
+//
+//==============================================
+
+NodeStateFilter::NodeStateFilter() : VParamSet()
+{
+ settingsId_="state";
+ std::vector<VParam*> v=VNState::filterItems();
+ init(v);
+}
+
+
+//==============================================
+//
+// AttributeFilter
+//
+//==============================================
+
+AttributeFilter::AttributeFilter() : VParamSet()
+{
+ settingsId_="attribute";
+ std::vector<VParam*> v=VAttributeType::filterItems();
+ init(v);
+
+ /*for(std::set<VParam*>::const_iterator it=all_.begin(); it != all_.end(); ++it)
+ {
+ if((*it)->strName() != "var" && (*it)->strName() != "genvar")
+ current_.insert(*it);
+ }*/
+}
+
+//==============================================
+//
+// IconFilter
+//
+//==============================================
+
+IconFilter::IconFilter() : VParamSet()
+{
+ settingsId_="icon";
+ std::vector<VParam*> v=VIcon::filterItems();
+ init(v);
+ current_=all_;
+}
+
+
+NodeFilterDef::NodeFilterDef(ServerFilter* serverFilter,Scope scope) :
+ serverFilter_(serverFilter),
+ nodeState_(0)
+{
+ nodeState_=new NodeStateFilter;
+
+ //if(scope == NodeStateScope)
+ // nodeState_=new NodeStateFilter;
+
+ //else if(scope == GeneralScope)
+ // nodeState_=new NodeStateFilter;
+
+ if(nodeState_)
+ {
+ exprStr_="state = all";
+
+ connect(nodeState_,SIGNAL(changed()),
+ this,SIGNAL(changed()));
+ }
+
+ query_=new NodeQuery("tmp",true);
+ //QStringList sel("aborted");
+ //query_->setStateSelection(sel);
+}
+
+NodeFilterDef::~NodeFilterDef()
+{
+ delete query_;
+}
+
+NodeQuery* NodeFilterDef::query() const
+{
+ return query_;
+}
+
+void NodeFilterDef::setQuery(NodeQuery* q)
+{
+ query_->swap(q);
+ Q_EMIT changed();
+}
+
+void NodeFilterDef::writeSettings(VSettings *vs)
+{
+ vs->beginGroup("query");
+ query_->save(vs);
+ vs->endGroup();
+}
+
+void NodeFilterDef::readSettings(VSettings *vs)
+{
+ vs->beginGroup("query");
+ query_->load(vs);
+ vs->endGroup();
+
+ Q_EMIT changed();
+}
+
+NodeFilter::NodeFilter(NodeFilterDef* def,ServerHandler* server) :
+ def_(def),
+ matchMode_(VectorMatch),
+ server_(server)
+{
+ assert(server_);
+
+ queryEngine_=new NodeFilterEngine(this);
+}
+
+NodeFilter::~NodeFilter()
+{
+ delete queryEngine_;
+}
+
+//============================================
+//
+// TreeNodeFilter
+//
+//============================================
+
+TreeNodeFilter::TreeNodeFilter(NodeFilterDef* def,ServerHandler* server,VTree* tree) :
+ NodeFilter(def,server),
+ tree_(tree)
+{
+}
+
+void TreeNodeFilter::clear()
+{
+ match_=std::vector<VNode*>();
+}
+
+bool TreeNodeFilter::isNull()
+{
+ return def_->nodeState_->isComplete() || def_->nodeState_->isEmpty();
+}
+
+//
+bool TreeNodeFilter::update(const std::vector<VNode*>& topChange,std::vector<VNode*>& topFilterChange)
+{
+#ifdef _UI_VFILTER_DEBUG
+ UserMessage::debug("TreeNodeFilter::update --> " + server_->name());
+#endif
+
+ //nodes_.clear();
+
+ //If all states are visible
+ if(def_->nodeState_->isComplete() || def_->nodeState_->isEmpty())
+ {
+ //deallocate the match vector
+ match_=std::vector<VNode*>();
+ //assert(match_.capacity() == 0);
+#ifdef _UI_VFILTER_DEBUG
+ UserMessage::debug(" no filter is defined!");
+#endif
+ return false;
+ }
+
+#ifdef _UI_VFILTER_DEBUG
+ QTime timer;
+ timer.start();
+#endif
+
+ VServer* root=server_->vRoot();
+ if(root->totalNum() > 0)
+ {
+ bool fullRun=false;
+
+ //The number of nodes changed: we need to rerun everything
+ if(match_.size() != root->totalNum() || match_.size() != tree_->nodeVec().size())
+ {
+ //Deallocates the match vector
+ match_=std::vector<VNode*>();
+ //match_.reserve(root->totalNum());
+ VNode *n=0;
+ match_.resize(root->totalNum(),n);
+ //td::fill(match_.begin(), match_.end(), n);
+ fullRun=true;
+ }
+
+ //The topchange vector is empty: it can only happen when we need to rerun everything
+ else if(topChange.empty())
+ {
+ VNode *n=0;
+ //match_.clear();
+ std::fill(match_.begin(), match_.end(), n);
+ fullRun=true;
+ }
+
+ //We rerun everything
+ if(fullRun)
+ {
+ for(size_t i=0; i < root->numOfChildren(); i++)
+ {
+ filterState(root->childAt(i),def_->nodeState_);
+ }
+ }
+
+ //We only check the branches defined by the nodes in topChange
+ else
+ {
+ //At this point the tree_->nodeVec() and match must have the same content
+ assert(tree_->nodeVec().size() == match_.size());
+
+ //Update the filter results
+ for(size_t i=0; i < topChange.size(); i++)
+ {
+ filterState(topChange[i],def_->nodeState_);
+ }
+
+#ifdef _UI_VFILTER_DEBUG
+ int diffCnt=0;
+ for(size_t i=0; i < match_.size(); i++)
+ {
+ if(tree_->vnodeAt(i) != match_[i])
+ diffCnt++;
+ }
+ UserMessage::debug(" number of differences in filter: " + QString::number(diffCnt).toStdString());
+#endif
+
+ //We collect the topmost nodes with changes. It could be different to
+ //topChange so we need this step!
+ for(size_t i=0; i < topChange.size(); i++)
+ {
+ checkState(topChange[i],topFilterChange);
+ }
+
+#ifdef _UI_VFILTER_DEBUG
+ assert(topFilterChange.size() <= diffCnt);
+ if(diffCnt > 0)
+ assert(topFilterChange.size() >0);
+#endif
+ }
+
+#ifdef _UI_VFILTER_DEBUG
+ UserMessage::debug(" Top level nodes that changed in filter:");
+ for(size_t i= 0; i < topFilterChange.size(); i++)
+ UserMessage::debug(" " + topFilterChange.at(i)->strName());
+#endif
+
+ }
+ else
+ {
+ match_.clear();
+ }
+
+#ifdef _UI_VFILTER_DEBUG
+ UserMessage::debug(" elapsed time: " + QString::number(timer.elapsed()).toStdString() + " ms");
+ UserMessage::debug(" filter size:" + QString::number(match_.size()).toStdString());
+ UserMessage::debug(" capacity:" + QString::number(match_.capacity()).toStdString());
+#endif
+
+ return true;
+}
+
+bool TreeNodeFilter::update()
+{
+ std::vector<VNode*> topChange;
+ std::vector<VNode*> topFilterChange;
+ return update(topChange,topFilterChange);
+}
+
+bool TreeNodeFilter::checkState(VNode* n,std::vector<VNode*>& topFilterChange)
+{
+ int idx=n->index();
+ if(tree_->vnodeAt(idx) != match_[idx])
+ {
+ VNode *pn=n->parent();
+ if(!pn) pn=n;
+
+ if(std::find(topFilterChange.begin(),topFilterChange.end(),pn) == topFilterChange.end())
+ topFilterChange.push_back(pn);
+
+ return true;
+ }
+ else
+ {
+ for(unsigned int i=0; i < n->numOfChildren(); i++)
+ {
+ checkState(n->childAt(i),topFilterChange);
+ }
+ }
+
+ return false;
+}
+
+bool TreeNodeFilter::filterState(VNode* node,VParamSet* stateFilter)
+{
+ bool ok=false;
+ //Suites always match!!
+ if(node->isSuite() || stateFilter->isSet(VNState::toState(node)))
+ {
+ ok=true;
+ }
+
+ for(unsigned int i=0; i < node->numOfChildren(); i++)
+ {
+ if(filterState(node->childAt(i),stateFilter) == true && ok == false)
+ {
+ ok=true;
+ }
+ }
+
+ if(ok)
+ {
+ match_[node->index()]=node;
+ }
+ else
+ {
+ match_[node->index()]=NULL;
+ }
+
+ return ok;
+}
+
+//===========================================================
+//
+// TableNodeFilter
+//
+//===========================================================
+
+TableNodeFilter::TableNodeFilter(NodeFilterDef* def,ServerHandler* server) :
+ NodeFilter(def,server),
+ matchCount_(0)
+{
+}
+
+bool TableNodeFilter::isNull()
+{
+ return def_->nodeState_->isComplete();
+}
+
+void TableNodeFilter::clear()
+{
+ match_.clear();
+ index_.clear();
+ matchCount_=0;
+}
+
+int TableNodeFilter::indexOf(const VNode* node) const
+{
+ switch(matchMode_)
+ {
+ case VectorMatch:
+ return index_[node->index()];
+ case AllMatch:
+ return node->index();
+ case NoneMatch:
+ return -1;
+ default:
+ assert(0);
+ return -1;
+ }
+
+ return -1;
+}
+
+VNode* TableNodeFilter::nodeAt(int index) const
+{
+ switch(matchMode_)
+ {
+ case VectorMatch:
+ return match_[index];
+ case AllMatch:
+ return server_->vRoot()->nodeAt(index);
+ case NoneMatch:
+ return NULL;
+ default:
+ assert(0);
+ return NULL;
+ }
+
+ return NULL;
+}
+
+bool TableNodeFilter::update()
+{
+#ifdef _UI_VFILTER_DEBUG
+ UserMessage::debug("TableNodeFilter::update --> " + server_->name());
+#endif
+
+ NodeQuery* q=def_->query_;
+
+ if(!q->hasServer(server_->name()) || server_->vRoot()->totalNum() ==0)
+ {
+ matchMode_=NoneMatch;
+ //Deallocates
+ match_=std::vector<VNode*>();
+ index_=std::vector<int>();
+ matchCount_=0;
+#ifdef _UI_VFILTER_DEBUG
+ UserMessage::debug(" no nodes are filtered!");
+#endif
+ return true;
+ }
+
+ if(q->query().isEmpty() && q->rootNode().empty())
+ {
+ matchMode_=AllMatch;
+ //Deallocates
+ match_=std::vector<VNode*>();
+ index_=std::vector<int>();
+ matchCount_=server_->vRoot()->totalNum();
+#ifdef _UI_VFILTER_DEBUG
+ UserMessage::debug(" all the nodes are filtered!");
+#endif
+ return true;
+ }
+
+#ifdef _UI_VFILTER_DEBUG
+ QTime timer;
+ timer.start();
+#endif
+
+ matchMode_=VectorMatch;
+ match_.clear();
+ int num=server_->vRoot()->totalNum();
+ if(num != index_.size())
+ {
+ //Reallocates
+ index_=std::vector<int>();
+ index_.resize(num,-1);
+ }
+ else
+ {
+ std::fill(index_.begin(), index_.end(), -1);
+ }
+
+ queryEngine_->setQuery(def_->query_);
+ queryEngine_->runQuery(server_);
+
+ matchCount_=match_.size();
+ for(size_t i=0; i < match_.size(); i++)
+ {
+ index_[match_[i]->index()]=i;
+ }
+
+#ifdef _UI_VFILTER_DEBUG
+ UserMessage::debug(" elapsed time: " + QString::number(timer.elapsed()).toStdString() + " ms");
+ UserMessage::debug(" filter size:" + QString::number(match_.size()).toStdString());
+ UserMessage::debug(" capacity:" + QString::number(match_.capacity()).toStdString());
+#endif
+
+ return true;
+
+}
+
diff --git a/Viewer/src/VFilter.hpp b/Viewer/src/VFilter.hpp
new file mode 100644
index 0000000..e99545b
--- /dev/null
+++ b/Viewer/src/VFilter.hpp
@@ -0,0 +1,188 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef VIEWFILTER_HPP_
+#define VIEWFILTER_HPP_
+
+#include <set>
+#include <vector>
+
+#include <QObject>
+#include <QStringList>
+
+#include "VParam.hpp"
+
+#include "Node.hpp"
+
+class NodeQuery;
+class NodeFilterEngine;
+class ServerFilter;
+class ServerHandler;
+class VNode;
+class VSettings;
+class VTree;
+
+#include <boost/property_tree/ptree.hpp>
+
+class VParamSet : public QObject
+{
+Q_OBJECT
+
+public:
+ VParamSet();
+ virtual ~VParamSet() {};
+
+ const std::set<VParam*>& current() const {return current_;}
+ void setCurrent(const std::set<VParam*>&);
+ QStringList currentAsList() const;
+ void current(const std::set<std::string>&);
+ void setCurrent(QStringList);
+ const std::set<VParam*>& all() const {return all_;}
+
+ bool isEmpty() const {return current_.empty();}
+ bool isComplete() const { return all_.size() == current_.size();}
+ bool isSet(const std::string&) const;
+ bool isSet(VParam*) const;
+
+ void writeSettings(VSettings* vs);
+ void readSettings(VSettings* vs);
+
+Q_SIGNALS:
+ void changed();
+
+protected:
+ void init(const std::vector<VParam*>& items);
+
+ std::set<VParam*> all_;
+ std::set<VParam*> current_;
+ std::string settingsId_;
+};
+
+class NodeStateFilter : public VParamSet
+{
+public:
+ NodeStateFilter();
+};
+
+class AttributeFilter : public VParamSet
+{
+public:
+ AttributeFilter();
+};
+
+class IconFilter : public VParamSet
+{
+public:
+ IconFilter();
+};
+
+
+class TreeNodeFilter;
+class TableNodeFilter;
+
+class NodeFilterDef : public QObject
+{
+Q_OBJECT
+
+friend class TreeNodeFilter;
+friend class TableNodeFilter;
+
+public:
+ enum Scope {NodeStateScope,GeneralScope};
+ NodeFilterDef(ServerFilter*,Scope);
+ ~NodeFilterDef();
+
+ NodeStateFilter* nodeState() const {return nodeState_;}
+
+ const std::string& exprStr() const {return exprStr_;}
+ NodeQuery* query() const;
+ void setQuery(NodeQuery*);
+
+ void writeSettings(VSettings *vs);
+ void readSettings(VSettings *vs);
+
+Q_SIGNALS:
+ void changed();
+
+protected:
+ ServerFilter *serverFilter_;
+ std::string exprStr_;
+ NodeStateFilter *nodeState_;
+ std::string nodePath_;
+ std::string nodeType_;
+ NodeQuery* query_;
+
+ //AttributeFilter *attribute_;
+ //std::string nodeType_;
+ //std::string nodeName_;
+};
+
+
+class NodeFilter
+{
+ friend class NodeFilterEngine;
+ friend class VTreeServer;
+
+public:
+ enum MatchMode {NoneMatch,AllMatch,VectorMatch};
+
+ NodeFilter(NodeFilterDef* def,ServerHandler*);
+ virtual ~NodeFilter();
+
+ virtual void clear()=0;
+ virtual bool isNull()=0;
+ virtual int matchCount() const = 0;
+ virtual bool update()=0;
+
+protected:
+ NodeFilterDef* def_;
+ NodeFilterEngine* queryEngine_;
+ std::set<std::string> type_;
+ MatchMode matchMode_;
+ std::vector<VNode*> match_;
+ ServerHandler * server_;
+};
+
+class TreeNodeFilter : public NodeFilter
+{
+public:
+ explicit TreeNodeFilter(NodeFilterDef* def,ServerHandler*,VTree*);
+
+ void clear();
+ bool isNull();
+ int matchCount() const {return 0;}
+ bool update();
+ bool update(const std::vector<VNode*>& topChange,
+ std::vector<VNode*>& topFilterChange);
+
+private:
+ bool filterState(VNode* node,VParamSet* stateFilter);
+ bool checkState(VNode* n,std::vector<VNode*>& topFilterChange);
+
+ VTree* tree_;
+};
+
+class TableNodeFilter : public NodeFilter
+{
+public:
+ explicit TableNodeFilter(NodeFilterDef* def,ServerHandler*);
+
+ void clear();
+ bool isNull();
+ int matchCount() const {return matchCount_;}
+ bool update();
+ int indexOf(const VNode*) const;
+ VNode* nodeAt(int index) const;
+
+private:
+ std::vector<int> index_;
+ int matchCount_;
+};
+
+#endif
diff --git a/Viewer/src/VIcon.cpp b/Viewer/src/VIcon.cpp
new file mode 100644
index 0000000..10287e7
--- /dev/null
+++ b/Viewer/src/VIcon.cpp
@@ -0,0 +1,422 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "VIcon.hpp"
+
+#include <QDebug>
+#include <QImage>
+#include <QImageReader>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "ExprAst.hpp"
+
+#include "IconProvider.hpp"
+#include "Submittable.hpp"
+#include "UserMessage.hpp"
+#include "VConfigLoader.hpp"
+#include "VFilter.hpp"
+#include "VNode.hpp"
+#include "VProperty.hpp"
+
+std::map<std::string,VIcon*> VIcon::items_;
+std::vector<VIcon*> VIcon::itemsVec_;
+
+//==========================================================
+//
+// Define VIcon subclasses implementing the various icons.
+// These do not need to be visible outside the class so we
+// define them here in the cpp file.
+//
+//==========================================================
+
+class VWaitIcon : public VIcon
+{
+public:
+ explicit VWaitIcon(const std::string& name) : VIcon(name) {};
+ bool show(VNode*);
+};
+
+class VRerunIcon : public VIcon
+{
+public:
+ explicit VRerunIcon(const std::string& name) : VIcon(name) {};
+ bool show(VNode*);
+};
+
+class VNodeLogIcon : public VIcon
+{
+public:
+ explicit VNodeLogIcon(const std::string& name) : VIcon(name) {};
+ bool show(VNode*);
+};
+
+class VCompleteIcon : public VIcon
+{
+public:
+ explicit VCompleteIcon(const std::string& name) : VIcon(name) {};
+ bool show(VNode*);
+};
+
+class VTimeIcon : public VIcon
+{
+public:
+ explicit VTimeIcon(const std::string& name) : VIcon(name) {};
+ bool show(VNode*);
+};
+
+class VDateIcon : public VIcon
+{
+public:
+ explicit VDateIcon(const std::string& name) : VIcon(name) {};
+ bool show(VNode*);
+};
+
+class VZombieIcon : public VIcon
+{
+public:
+ explicit VZombieIcon(const std::string& name) : VIcon(name) {};
+ bool show(VNode*);
+};
+
+class VLateIcon : public VIcon
+{
+public:
+ explicit VLateIcon(const std::string& name) : VIcon(name) {};
+ bool show(VNode*);
+};
+
+class VSlowIcon : public VIcon
+{
+public:
+ explicit VSlowIcon(const std::string& name) : VIcon(name) {};
+ bool show(VNode*);
+};
+
+//==========================================================
+//
+// Create VIcon instances
+//
+//==========================================================
+
+//This also defines the order the icons will appear in the views
+static VNodeLogIcon nodeLogIcon("message");
+static VRerunIcon rerunIcon("rerun");
+static VCompleteIcon completeIcon("complete");
+static VLateIcon lateIcon("late");
+static VTimeIcon timeIcon("time");
+static VDateIcon dateIcon("date");
+static VWaitIcon waitIcon("wait");
+static VZombieIcon zombieIcon("zombie");
+static VSlowIcon slowIcon("slow");
+
+//==========================================================
+//
+// The VIcon baseclass
+//
+//==========================================================
+
+VIcon::VIcon(const std::string& name) :
+ VParam(name),
+ pixId_(-1)
+{
+ items_[name]=this;
+ itemsVec_.push_back(this);
+}
+
+VIcon::~VIcon()
+{
+}
+
+void VIcon::initPixmap()
+{
+ if(!prop_)
+ {
+ UserMessage::message(UserMessage::WARN, true,
+ std::string("Warning! VIcon::initPixmap() unable to create icon image for: " + strName()));
+ return;
+ }
+
+ //Add icon to iconprovider
+ if(VProperty* ip=prop_->findChild("icon"))
+ {
+ pixId_=IconProvider::add(":/viewer/" + ip->value().toString(),name());
+ }
+}
+
+QPixmap VIcon::pixmap(int size)
+{
+ return IconProvider::pixmap(name(),size);
+}
+
+//===============================================================
+//
+// Static methods
+//
+//===============================================================
+
+std::vector<VParam*> VIcon::filterItems()
+{
+ std::vector<VParam*> v;
+ for(std::map<std::string,VIcon*>::const_iterator it=items_.begin(); it != items_.end(); ++it)
+ {
+ v.push_back(it->second);
+ }
+
+ return v;
+}
+
+VIcon* VIcon::find(const std::string& name)
+{
+ std::map<std::string,VIcon*>::const_iterator it=items_.find(name);
+ if(it != items_.end())
+ return it->second;
+
+ return NULL;
+}
+
+//Create the pixmap containing all the relevant icons for the given node according to the filter.
+QVariantList VIcon::pixmapList(VNode *vnode,VParamSet *filter)
+{
+ QVariantList lst;
+ if(!vnode)
+ return lst;
+
+ for(std::vector<VIcon*>::const_iterator it=itemsVec_.begin(); it != itemsVec_.end(); ++it)
+ {
+ VIcon *v=*it;
+
+ if(!filter || filter->current().find(v) != filter->current().end())
+ {
+ if(v->show(vnode))
+ {
+ lst << v->pixId_;
+ }
+ }
+ }
+
+ return lst;
+}
+
+QString VIcon::toolTip(VNode *vnode,VParamSet *filter)
+{
+ if(filter->isEmpty())
+ return QString();
+
+ int iconSize=16;
+ QString txt;
+
+ for(std::vector<VIcon*>::const_iterator it=itemsVec_.begin(); it != itemsVec_.end(); ++it)
+ {
+ VIcon *v=*it;
+
+ if(!filter || filter->current().find(v) != filter->current().end())
+ {
+ if(v->show(vnode))
+ {
+ if(txt.isEmpty())
+ {
+ txt+="<br><b>Icons:</b><table cellpadding=\'1\'>";
+ }
+
+ txt+="<tr><td><img src=\'" + IconProvider::path(v->pixId_) + "\' width=\'" +
+ QString::number(iconSize) + "\' height=\'" + QString::number(iconSize) + "\'></td><td>" + v->shortDescription() + "</tr>";
+ }
+ }
+ }
+
+ if(!txt.isEmpty())
+ txt+="</table>";
+
+ return txt;
+}
+
+QString VIcon::shortDescription() const
+{
+ QString v;
+ if(prop_)
+ v=prop_->param("shortDesc");
+
+ if(v.isEmpty())
+ v=name();
+
+ return v;
+}
+
+void VIcon::load(VProperty* group)
+{
+ Q_FOREACH(VProperty* p,group->children())
+ {
+ if(VIcon* obj=VIcon::find(p->strName()))
+ {
+ obj->setProperty(p);
+ obj->initPixmap();
+ }
+ }
+}
+
+static SimpleLoader<VIcon> loader("icon");
+
+
+//==========================================================
+// Wait
+//==========================================================
+
+//Task only
+bool VWaitIcon::show(VNode *n)
+{
+ if(!n || n->isServer())
+ return false;
+
+ return n->isFlagSet(ecf::Flag::WAIT);
+}
+
+//==========================================================
+// Rerun
+//==========================================================
+
+//Task only
+bool VRerunIcon::show(VNode *n)
+{
+ if(!n || n->isServer())
+ return false;
+
+ node_ptr node=n->node();
+ if(!node.get()) return false;
+
+ if(Submittable* s = node->isSubmittable())
+ {
+ return (s->try_no() > 1);
+ }
+
+ return false;
+}
+
+//==========================================================
+// Message
+//==========================================================
+
+//Node and server
+bool VNodeLogIcon::show(VNode *n)
+{
+ if(!n)
+ return false;
+
+ return n->isFlagSet(ecf::Flag::MESSAGE);
+}
+
+//==========================================================
+// Complete
+//==========================================================
+
+//Task only
+bool VCompleteIcon::show(VNode *n)
+{
+ if(!n || n->isServer())
+ return false;
+
+ if(!n->node())
+ return false;
+
+ node_ptr node=n->node();
+ if(!node.get()) return false;
+
+ if(n->isDefaultStateComplete())
+ return true;
+
+ if(AstTop* t = node->completeAst())
+ {
+ if(t->evaluate())
+ return true;
+ }
+ return false;
+}
+
+//==========================================================
+// Date
+//==========================================================
+
+//Node only?
+bool VDateIcon::show(VNode *n)
+{
+ if(!n || n->isServer())
+ return false;
+
+ node_ptr node=n->node();
+
+ if(!node.get()) return false;
+
+ return (node->days().size() > 0 || node->dates().size() > 0);
+}
+
+//==========================================================
+// Time
+//==========================================================
+
+//Node only?
+bool VTimeIcon::show(VNode *n)
+{
+ if(!n || n->isServer())
+ return false;
+
+ node_ptr node=n->node();
+
+ //Check if time is held
+ if(TimeDepAttrs *attr = node->get_time_dep_attrs())
+ {
+ return !attr->time_today_cron_is_free();
+ }
+
+ return (node->timeVec().size() > 0 ||
+ node->todayVec().size() > 0 ||
+ node->crons().size() > 0);
+}
+
+//==========================================================
+// Zombie
+//==========================================================
+
+//Node only?
+bool VZombieIcon::show(VNode *n)
+{
+ if(!n)
+ return false;
+
+ return n->isFlagSet(ecf::Flag::ZOMBIE);
+}
+
+//==========================================================
+// Late
+//==========================================================
+
+//Node and server
+bool VLateIcon::show(VNode *n)
+{
+ if(!n || n->isServer())
+ return false;
+
+ return n->isFlagSet(ecf::Flag::LATE);
+}
+
+//==========================================================
+// Slow
+//==========================================================
+
+//Server only
+bool VSlowIcon::show(VNode *n)
+{
+ if(!n || !n->isServer())
+ return false;
+
+ return n->isFlagSet(ecf::Flag::LATE);
+}
diff --git a/Viewer/src/VIcon.hpp b/Viewer/src/VIcon.hpp
new file mode 100644
index 0000000..15793c7
--- /dev/null
+++ b/Viewer/src/VIcon.hpp
@@ -0,0 +1,54 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VICON_HPP_
+#define VICON_HPP_
+
+#include <map>
+#include <set>
+#include <vector>
+#include <string>
+
+#include "VParam.hpp"
+
+#include <QPair>
+#include <QPixmap>
+#include <QVariant>
+
+class VNode;
+class VParamSet;
+
+class VIcon : public VParam
+{
+public:
+ explicit VIcon(const std::string& name);
+ virtual ~VIcon();
+
+ static std::vector<VParam*> filterItems();
+ static QVariantList pixmapList(VNode *vnode,VParamSet *filter);
+ static QString toolTip(VNode *vnode,VParamSet *filter);
+ static VIcon* find(const std::string& name);
+
+ //Called from VConfigLoader
+ static void load(VProperty* group);
+
+protected:
+ void initPixmap();
+ QPixmap pixmap(int size);
+ virtual bool show(VNode*)=0;
+ QString shortDescription() const;
+
+ int pixId_;
+
+ static std::map<std::string,VIcon*> items_;
+ static std::vector<VIcon*> itemsVec_;
+};
+
+#endif
diff --git a/Viewer/src/VInfo.cpp b/Viewer/src/VInfo.cpp
new file mode 100644
index 0000000..c50070d
--- /dev/null
+++ b/Viewer/src/VInfo.cpp
@@ -0,0 +1,390 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "VInfo.hpp"
+
+#include "ServerHandler.hpp"
+#include "UserMessage.hpp"
+#include "VAttribute.hpp"
+#include "VAttributeType.hpp"
+#include "VNode.hpp"
+//#include "VNState.hpp"
+//#include "VSState.hpp"
+
+#include <boost/lexical_cast.hpp>
+
+#if 0
+
+static std::map<std::string,VInfoAttributeFactory*>* makers = 0;
+
+//#define _UI_VINFO_DEBUG
+
+//========================================
+//
+// VInfoAttributeFactory
+//
+//========================================
+
+
+VInfoAttributeFactory::VInfoAttributeFactory(const std::string& name)
+{
+ if(makers == 0)
+ makers = new std::map<std::string,VInfoAttributeFactory*>;
+
+ // Put in reverse order...
+ (*makers)[name] = this;
+}
+
+VInfoAttributeFactory::~VInfoAttributeFactory()
+{
+ // Not called
+}
+
+VInfoAttribute* VInfoAttributeFactory::create(VAttributeType* att,int attIndex,VNode* node,ServerHandler* server)
+{
+ std::string name=att->name().toStdString();
+
+ std::map<std::string,VInfoAttributeFactory*>::iterator j = makers->find(name);
+ if(j != makers->end())
+ return (*j).second->make(att,attIndex,node,server);
+
+ //Default
+ //return new MvQTextLine(e,p);
+ //return new MvQLineEditItem(e,p) ;
+ return 0;
+}
+
+#endif
+
+//========================================
+//
+// VInfo
+//
+//========================================
+
+VInfo::VInfo(ServerHandler* server,VNode* node) :
+ server_(server),
+ node_(node)
+{
+ if(node)
+ nodePath_=node->absNodePath();
+
+ if(server_)
+ server_->addServerObserver(this);
+}
+
+VInfo::~VInfo()
+{
+#ifdef _UI_VINFO_DEBUG
+ UserMessage::debug("VInfo::~VInfo() --> \n" + boost::lexical_cast<std::string>(this));
+#endif
+ if(server_)
+ server_->removeServerObserver(this);
+
+ for(std::vector<VInfoObserver*>::const_iterator it=observers_.begin(); it != observers_.end(); ++it)
+ (*it)->notifyDelete(this);
+
+#ifdef _UI_VINFO_DEBUG
+ UserMessage::debug("<-- VInfo::~VInfo()");
+#endif
+}
+
+void VInfo::notifyServerDelete(ServerHandler* server)
+{
+ //This function is called from the server destructor. We do not remove this object from the ServerObservers
+
+ server_=NULL;
+ node_=NULL;
+
+ dataLost();
+}
+
+void VInfo::dataLost()
+{
+ std::vector<VInfoObserver*> obsTmp=observers_;
+ observers_.clear();
+
+ for(std::vector<VInfoObserver*>::iterator it=obsTmp.begin(); it != obsTmp.end(); ++it)
+ {
+ VInfoObserver* o=*it;
+ o->notifyDataLost(this);
+ }
+}
+
+void VInfo::notifyBeginServerClear(ServerHandler* server)
+{
+ node_=NULL;
+}
+
+void VInfo::notifyEndServerClear(ServerHandler* server)
+{
+ node_=NULL;
+}
+
+void VInfo::notifyEndServerScan(ServerHandler* server)
+{
+ regainData();
+}
+
+void VInfo::regainData()
+{
+ if(!server_)
+ {
+ dataLost();
+ return;
+ }
+
+ if(node_)
+ return;
+
+ if(isServer())
+ {
+ node_=server_->vRoot();
+ }
+ else
+ {
+ node_=server_->vRoot()->find(nodePath_);
+ if(!node_)
+ {
+ dataLost();
+ }
+ }
+}
+
+void VInfo::addObserver(VInfoObserver* o)
+{
+ std::vector<VInfoObserver*>::iterator it=std::find(observers_.begin(),observers_.end(),o);
+ if(it == observers_.end())
+ observers_.push_back(o);
+}
+
+void VInfo::removeObserver(VInfoObserver* o)
+{
+ std::vector<VInfoObserver*>::iterator it=std::find(observers_.begin(),observers_.end(),o);
+ if(it != observers_.end())
+ observers_.erase(it);
+}
+
+bool VInfo::operator ==(const VInfo& other)
+{
+ if(server_ == other.server_ && node_ == other.node_ &&
+ nodePath_ == other.nodePath_)
+ {
+ if((!attribute() && other.attribute()) ||
+ (attribute() && !other.attribute()))
+ return false;
+
+ else if(attribute() && other.attribute())
+ {
+ return (attribute()->type() == other.attribute()->type() &&
+ attribute()->data() == other.attribute()->data());
+ }
+ else
+ return true;
+ }
+ return false;
+}
+
+VInfo_ptr VInfo::createParent(VInfo_ptr info)
+{
+ if(!info)
+ return VInfo_ptr();
+
+ if(info->isServer())
+ return info;
+ else if(info->isNode())
+ {
+ return VInfoServer::create(info->server());
+ }
+ else if(info->isAttribute())
+ {
+ return VInfoNode::create(info->node());
+ }
+
+ return VInfo_ptr();
+}
+
+
+//=========================================
+//
+// VInfoServer
+//
+//=========================================
+
+VInfoServer::VInfoServer(ServerHandler *server) : VInfo(server,NULL)
+{
+ if(server_)
+ {
+ node_=server_->vRoot();
+ //server_->addServerObserver(this);
+ }
+}
+
+VInfo_ptr VInfoServer::create(ServerHandler *server)
+{
+ return VInfo_ptr(new VInfoServer(server));
+}
+
+void VInfoServer::accept(VInfoVisitor* v)
+{
+ v->visit(this);
+}
+
+std::string VInfoServer::name()
+{
+ if(server_)
+ return server_->name();
+
+ return std::string();
+}
+
+std::string VInfoServer::path()
+{
+ return name() + "://";
+}
+
+//=========================================
+//
+// VInfoNode
+//
+//=========================================
+
+
+VInfoNode::VInfoNode(ServerHandler* server,VNode* node) : VInfo(server,node)
+{
+ //if(server_)
+ // server_->addServerObserver(this);
+}
+
+VInfo_ptr VInfoNode::create(VNode *node)
+{
+ ServerHandler* server=NULL;
+ if(node)
+ {
+ server=node->server();
+ }
+ return VInfo_ptr(new VInfoNode(server,node));
+}
+
+void VInfoNode::accept(VInfoVisitor* v)
+{
+ v->visit(this);
+}
+
+std::string VInfoNode::name()
+{
+ if(node_ && node_->node())
+ return node_->strName();
+
+ return std::string();
+}
+
+std::string VInfoNode::path()
+{
+ std::string p;
+ if(server_)
+ p=server_->name();
+
+ if(node_ && node_->node())
+ p+=":/" + node_->absNodePath();
+
+ return p;
+}
+
+//=========================================
+//
+// VInfoAttribute
+//
+//=========================================
+
+
+VInfoAttribute::VInfoAttribute(ServerHandler* server,VNode* node,VAttribute* attr) :
+ VInfo(server,node),
+ attr_(attr)
+{
+
+}
+
+VInfoAttribute::~VInfoAttribute()
+{
+ if(attr_)
+ delete attr_;
+}
+
+void VInfoAttribute::accept(VInfoVisitor* v)
+{
+ v->visit(this);
+}
+
+VInfo_ptr VInfoAttribute::create(VNode* node,int attIndex)
+{
+ ServerHandler* server=NULL;
+ VAttribute* att=NULL;
+ if(node)
+ {
+ server=node->server();
+ att=new VAttribute(node,attIndex);
+ }
+
+ return VInfo_ptr(new VInfoAttribute(server,node,att));
+}
+
+std::string VInfoAttribute::path()
+{
+ std::string p;
+ if(server_)
+ p=server_->name();
+
+ if(node_ && node_->node())
+ p+=":/" + node_->absNodePath();
+
+ return p;
+}
+
+std::string VInfoAttribute::name()
+{
+ return (attr_)?attr_->strName():std::string();
+}
+
+
+/*
+VInfoLimit::VInfoLimit(VAttribute* att,int attIndex,VNode* node,ServerHandler *server) :
+ VInfoAttribute(att,attIndex,node,server)
+{
+
+}
+
+static VInfoAttributeMaker<VInfoLimit> maker1("limit");
+*/
+
+
+/*static VMeterAttribute meterAttr("meter");
+static VEventAttribute eventAttr("event");
+static VRepeatAttribute repeatAttr("repeat");
+static VTriggerAttribute triggerAttr("trigger");
+static VLabelAttribute labelAttr("label");
+static VTimeAttribute timeAttr("time");
+static VDateAttribute dateAttr("date");
+static VLimitAttribute limitAttr("limit");
+static VLimiterAttribute limiterAttr("limiter");
+static VLateAttribute lateAttr("late");
+static VVarAttribute varAttr("var");
+static VGenvarAttribute genvarAttr("genvar");*/
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Viewer/src/VInfo.hpp b/Viewer/src/VInfo.hpp
new file mode 100644
index 0000000..8f8ab82
--- /dev/null
+++ b/Viewer/src/VInfo.hpp
@@ -0,0 +1,271 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VINFO_HPP_
+#define VINFO_HPP_
+
+#include <cstddef>
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+
+#include <string>
+#include <vector>
+
+#include "ServerObserver.hpp"
+#include "Variable.hpp"
+
+class ServerHandler;
+class VAttribute;
+class VNode;
+
+class VInfoObserver;
+class VInfoVisitor;
+
+class VInfo;
+typedef boost::shared_ptr<VInfo> VInfo_ptr;
+
+//==============================================================================
+// For each selected item in any of the views a new VInfo object is created.
+// This class offers the same interface to access information about any selected
+// items: servers, nodes, attributes. The concrete implementation of
+// these access methods are done in subclasses derived from VInfo.
+//
+// VInfo is regarded as a temporary object. We only need it while the selection
+// is used in breadcrumbs, info panels or other widgets outside the main views.
+//==============================================================================
+
+class VInfo : public ServerObserver
+{
+public:
+ virtual ~VInfo();
+
+ virtual bool isServer() {return false;}
+ virtual bool isNode() {return false;}
+ virtual bool isAttribute() {return false;}
+ virtual bool isEmpty() {return true;}
+
+ ServerHandler* server() const {return server_;}
+ VNode* node() const {return node_;}
+ virtual VAttribute* attribute() const {return NULL;}
+
+ virtual std::string name()=0;
+ virtual std::string path()=0;
+ const std::string& storedNodePath() const {return nodePath_;}
+
+ virtual void accept(VInfoVisitor*)=0;
+
+ void regainData();
+ void addObserver(VInfoObserver*);
+ void removeObserver(VInfoObserver*);
+
+ //Form ServerObserver
+ void notifyDefsChanged(ServerHandler* server, const std::vector<ecf::Aspect::Type>& a) {}
+ void notifyServerDelete(ServerHandler* server);
+ void notifyBeginServerClear(ServerHandler* server);
+ void notifyEndServerClear(ServerHandler* server);
+ void notifyBeginServerScan(ServerHandler* server,const VServerChange&) {}
+ void notifyEndServerScan(ServerHandler* server);
+ void notifyServerConnectState(ServerHandler* server) {}
+ void notifyServerActivityChanged(ServerHandler* server) {}
+ void notifyServerSuiteFilterChanged(ServerHandler* server) {}
+
+ bool operator ==(const VInfo&);
+
+ static VInfo_ptr createParent(VInfo_ptr);
+
+protected:
+ VInfo(ServerHandler* server,VNode* node);
+ void dataLost();
+
+ mutable ServerHandler* server_;
+ mutable std::string nodePath_;
+ mutable VNode* node_;
+
+ std::vector<VInfoObserver*> observers_;
+};
+
+
+// Implements the info object for server selections
+class VInfoServer : public VInfo, public boost::enable_shared_from_this<VInfo>
+{
+public:
+ bool isServer() {return true;}
+ bool isEmpty() {return false;}
+ void accept(VInfoVisitor*);
+ std::string name();
+ std::string path();
+ static VInfo_ptr create(ServerHandler*);
+
+protected:
+ explicit VInfoServer(ServerHandler*);
+};
+
+
+// Implements the info object for node selections
+class VInfoNode: public VInfo, public boost::enable_shared_from_this<VInfo>
+{
+public:
+ bool isNode() {return true;}
+ bool isEmpty() {return false;}
+ void accept(VInfoVisitor*);
+ std::string path();
+ std::string name();
+ static VInfo_ptr create(VNode*);
+
+protected:
+ VInfoNode(ServerHandler*,VNode*);
+};
+
+
+// Implements the info base class for attribute selections
+class VInfoAttribute: public VInfo, public boost::enable_shared_from_this<VInfo>
+{
+public:
+ ~VInfoAttribute();
+ VAttribute* attribute() const {return attr_;}
+ bool isAttribute() {return true;}
+ bool isEmpty() {return false;}
+ void accept(VInfoVisitor*);
+ std::string name();
+ std::string path();
+
+ static VInfo_ptr create(VNode*,int);
+
+protected:
+ VInfoAttribute(ServerHandler*,VNode*,VAttribute*);
+
+ mutable VAttribute* attr_;
+};
+
+//=================================================
+// Factory to make attribute info objects
+//=================================================
+
+#if 0
+
+class VInfoAttributeFactory
+{
+public:
+ explicit VInfoAttributeFactory(const std::string&);
+ virtual ~VInfoAttributeFactory();
+
+ virtual VInfoAttribute* make(VAttributeType*,int,VNode*,ServerHandler* server=0) = 0;
+ static VInfoAttribute* create(VAttributeType* att,int attIndex,VNode* node,ServerHandler* server=0);
+
+private:
+ explicit VInfoAttributeFactory(const VInfoAttributeFactory&);
+ VInfoAttributeFactory& operator=(const VInfoAttributeFactory &);
+
+};
+
+template<class T>
+class VInfoAttributeMaker : public VInfoAttributeFactory
+{
+ VInfoAttribute* make(VAttributeType* att,int attIndex,VNode* node,ServerHandler* server=0)
+ { return new T(att,attIndex,node,server); }
+public:
+ explicit VInfoAttributeMaker(const std::string& name) : VInfoAttributeFactory(name) {}
+};
+
+
+#endif
+
+typedef boost::shared_ptr<VInfoServer> VInfoServer_ptr;
+typedef boost::shared_ptr<VInfoNode> VInfoNode_ptr;
+typedef boost::shared_ptr<VInfoAttribute> VInfoAttribute_ptr;
+
+
+class VInfoVisitor
+{
+public:
+ VInfoVisitor() {}
+ virtual ~VInfoVisitor() {}
+
+ virtual void visit(VInfoServer*)=0;
+ virtual void visit(VInfoNode*)=0;
+ virtual void visit(VInfoAttribute*)=0;
+
+};
+
+class VInfoObserver
+{
+public:
+ VInfoObserver() {}
+ virtual ~VInfoObserver() {}
+
+ virtual void notifyDataLost(VInfo*)=0;
+ virtual void notifyDelete(VInfo*)=0;
+};
+
+/*class VInfoVisitor
+{
+public:
+ VInfoVisitor() {};
+ virtual ~VInfoVisitor() {};
+
+ virtual void visit(boost::shared_ptr<VInfoServer>)=0;
+ virtual void visit(boost::shared_ptr<VInfoNode>)=0;
+ virtual void visit(boost::shared_ptr<VInfoAttribute>)=0;
+};
+*/
+
+
+/*
+#include "ViewNodeInfo.hpp"
+
+#include "ServerHandler.hpp"
+
+ViewNodeInfo::ViewNodeInfo() : node_(NULL),server_(NULL)
+{
+}
+
+ViewNodeInfo::ViewNodeInfo(Node *node,ServerHandler* server) : node_(node), server_(server)
+{
+}
+
+ViewNodeInfo::ViewNodeInfo(ServerHandler* server) : node_(NULL),server_(server)
+{
+
+}
+
+bool ViewNodeInfo::isNode() const
+{
+ return (node_ != NULL);
+}
+
+bool ViewNodeInfo::isServer() const
+{
+ return (node_ == NULL && server_ != NULL);
+}
+
+bool ViewNodeInfo::isEmpty() const
+{
+ return (node_ == NULL && server_ == NULL);
+}
+
+Node* ViewNodeInfo::node() const
+{
+ return node_;
+}
+
+ServerHandler* ViewNodeInfo::server() const
+{
+ if(server_ == NULL && node_)
+ {
+ server_=ServerHandler::find(node_);
+ }
+ return server_;
+}
+*/
+
+
+
+#endif
+
diff --git a/Viewer/src/VItem.hpp b/Viewer/src/VItem.hpp
new file mode 100644
index 0000000..adf3f00
--- /dev/null
+++ b/Viewer/src/VItem.hpp
@@ -0,0 +1,66 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VITEM_HPP_
+#define VITEM_HPP_
+
+#include <cstdlib>
+#include <QString>
+
+class ServerHandler;
+class VNode;
+class VServer;
+class VSuiteNode;
+class VFamilyNode;
+class VAliasNode;
+class VTaskNode;
+class VAttribute;
+class VItemVisitor;
+
+class VItem
+{
+public:
+ VItem(VNode* parent) : parent_(parent) {}
+
+ VNode* parent() const {return parent_;}
+ //virtual ServerHandler* server() const;
+ //node_ptr node() const {return node_;}
+ virtual VServer* isServer() const {return NULL;}
+ virtual VNode* isNode() const {return NULL;}
+ virtual VSuiteNode* isSuite() const {return NULL;}
+ virtual VFamilyNode* isFamily() const {return NULL;}
+ virtual VTaskNode* isTask() const {return NULL;}
+ virtual VAliasNode* isAlias() const {return NULL;}
+ virtual VAttribute* isAttribute() const {return NULL;}
+
+ virtual bool isTopLevel() const {return false;}
+ virtual std::string strName() const=0;
+ virtual QString name() const=0;
+
+protected:
+ VNode* parent_;
+};
+
+#if 0
+class VItemVisitor
+{
+public:
+ VItemVisitor() {}
+ virtual ~VItemVisitor() {}
+
+ virtual void visit(VServer*) {}
+ virtual void visit(VNode*) {}
+ virtual void visit(VAttribute*) {}
+};
+#endif
+
+
+#endif // VITEM_HPP_
+
diff --git a/Viewer/src/VModelData.cpp b/Viewer/src/VModelData.cpp
new file mode 100644
index 0000000..4428fb6
--- /dev/null
+++ b/Viewer/src/VModelData.cpp
@@ -0,0 +1,1137 @@
+//============================================================================
+// Copyright 2015 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "VModelData.hpp"
+
+#include "AbstractNodeModel.hpp"
+#include "NodeQuery.hpp"
+#include "VFilter.hpp"
+#include "ServerHandler.hpp"
+#include "UserMessage.hpp"
+#include "VAttributeType.hpp"
+#include "VNode.hpp"
+#include "VTree.hpp"
+
+#include <QDebug>
+#include <QMetaMethod>
+
+#define _UI_VMODELDATA_DEBUG
+
+void VTreeChangeInfo::addStateChange(const VNode* n)
+{
+ VNode* s=n->suite();
+ Q_ASSERT(s->isTopLevel());
+ Q_ASSERT(s);
+ if(std::find(stateSuites_.begin(),stateSuites_.end(),s) == stateSuites_.end())
+ stateSuites_.push_back(s);
+}
+
+//==========================================
+//
+// VModelServer
+//
+//==========================================
+
+//It takes ownership of the filter
+
+VModelServer::VModelServer(ServerHandler *server) :
+ server_(server),
+ inScan_(0)
+{
+ //We has to observe the nodes of the server.
+ server_->addNodeObserver(this);
+
+ //We has to observe the server.
+ server_->addServerObserver(this);
+
+}
+
+VModelServer::~VModelServer()
+{
+ server_->removeNodeObserver(this);
+ server_->removeServerObserver(this);
+}
+
+int VModelServer::totalNodeNum() const
+{
+ return server_->vRoot()->totalNum();
+}
+
+//==========================================
+//
+// VTreeServer
+//
+//==========================================
+
+//It takes ownership of the filter
+
+VTreeServer::VTreeServer(ServerHandler *server,NodeFilterDef* filterDef,AttributeFilter* attrFilter) :
+ VModelServer(server),
+ changeInfo_(new VTreeChangeInfo()),
+ attrFilter_(attrFilter)
+{
+ tree_=new VTree(this);
+ filter_=new TreeNodeFilter(filterDef,server_,tree_);
+ //We has to observe the nodes of the server.
+ //server_->addNodeObserver(this);
+}
+
+VTreeServer::~VTreeServer()
+{
+ delete tree_;
+ delete changeInfo_;
+ delete filter_;
+}
+
+NodeFilter* VTreeServer::filter() const
+{
+ return const_cast<TreeNodeFilter*>(filter_);
+}
+
+int VTreeServer::nodeNum() const
+{
+ return tree_->totalNum();
+}
+
+//--------------------------------------------------
+// ServerObserver methods
+//--------------------------------------------------
+
+void VTreeServer::notifyDefsChanged(ServerHandler* server, const std::vector<ecf::Aspect::Type>& a)
+{
+ //When the defs changed we need to update the server node in the model/view
+ Q_EMIT dataChanged(this);
+ //TODO: what about node or attr num changes!
+}
+
+void VTreeServer::notifyServerDelete(ServerHandler*)
+{
+#ifdef _UI_VMODELDATA_DEBUG
+ UserMessage::debug("VTreeServer::notifyServerDelete ---> should never be called!!");
+#endif
+ Q_ASSERT(0);
+}
+
+void VTreeServer::notifyBeginServerScan(ServerHandler* server,const VServerChange& change)
+{
+ //When the server scan begins we must be in inScan mode so that the model should think that
+ //this server tree is empty.
+ inScan_=true;
+ Q_ASSERT(tree_->numOfChildren() == 0);
+ changeInfo_->clear();
+}
+
+void VTreeServer::notifyEndServerScan(ServerHandler* /*server*/)
+{
+ //We still must be in inScan mode so that the model should think
+ //that this server tree is empty.
+ inScan_=true;
+
+ //When the server scan ends we need to rebuild the tree.
+ if(filter_->isNull())
+ {
+ tree_->build();
+ }
+ else
+ {
+ filter_->update();
+ tree_->build(filter_->match_);
+ }
+
+ //Notifies the model of the number of children nodes to be added to the server node.
+ Q_EMIT beginServerScan(this, tree_->attrNum(attrFilter_)+tree_->numOfChildren());
+ //We leave the inScan mode. From this moment on the model can see the whole tree in the server.
+ inScan_=false;
+ //Notifies the model that the scan finished. The model can now relayout its new contents.
+ Q_EMIT endServerScan(this, tree_->attrNum(attrFilter_)+tree_->numOfChildren());
+}
+
+void VTreeServer::notifyBeginServerClear(ServerHandler* server)
+{
+ Q_EMIT beginServerClear(this,-1);
+ changeInfo_->clear();
+ tree_->clear();
+ filter_->clear();
+ inScan_=true;
+}
+
+void VTreeServer::notifyEndServerClear(ServerHandler* server)
+{
+ Q_EMIT endServerClear(this,-1);
+}
+
+void VTreeServer::notifyServerConnectState(ServerHandler* server)
+{
+ Q_EMIT rerender();
+}
+
+void VTreeServer::notifyServerActivityChanged(ServerHandler* server)
+{
+ Q_EMIT dataChanged(this);
+}
+
+//This is called when a normal sync (neither reset nor rescan) is finished. We have delayed the update of the
+//filter to this point but now we need to do it.
+void VTreeServer::notifyEndServerSync(ServerHandler* server)
+{
+#ifdef _UI_VMODELDATA_DEBUG
+ UserMessage::debug("VTreeServer::notifyEndServerSync --> number of state changes: " + QString::number(changeInfo_->stateChangeSuites().size()).toStdString());
+#endif
+
+ //if there was a state change during the sync
+ if(changeInfo_->stateChangeSuites().size() > 0 && !filter_->isNull())
+ {
+#ifdef _UI_VMODELDATA_DEBUG
+ UserMessage::debug(" Suites changed:");
+ for(size_t i= 0; i < changeInfo_->stateChangeSuites().size(); i++)
+ UserMessage::debug(" " + changeInfo_->stateChangeSuites().at(i)->strName());
+#endif
+ //Update the filter for the suites with a status change. topFilterChange
+ //will contain the branches where the filter changed. A branch is
+ //defined by the parent of the top level nodes with a filter status change in a given
+ //suite. Suites are always visible (part of the tree) so a branch cannot be a server (root)
+ //but at most a suite.
+ std::vector<VNode*> topFilterChange;
+ filter_->update(changeInfo_->stateChangeSuites(),topFilterChange);
+
+#ifdef _UI_VMODELDATA_DEBUG
+ UserMessage::debug(" Top level nodes that changed in filter:");
+ for(size_t i= 0; i < topFilterChange.size(); i++)
+ UserMessage::debug(" " + topFilterChange.at(i)->strName());
+#endif
+
+ //A topFilterChange branch cannot be the root (server)
+ for(size_t i=0; i < topFilterChange.size(); i++)
+ {
+ Q_ASSERT(!topFilterChange[i]->isServer());
+ }
+
+ //If something changed in the list of filtered nodes
+ for(size_t i=0; i < topFilterChange.size(); i++)
+ {
+#ifdef _UI_VMODELDATA_DEBUG
+ UserMessage::debug(" Branch: " + topFilterChange[i]->absNodePath());
+#endif
+ //This is the branch where there is a change in the filter
+ VTreeNode* tn=tree_->find(topFilterChange[i]);
+
+ //If the branch is not in tree (not yet filtered) we need to
+ //find it nearest ancestor up in the tree. This must exist because
+ //the suites are always part of the tree.
+ if(!tn)
+ {
+ tn=tree_->findAncestor(topFilterChange[i]);
+ Q_ASSERT(tn);
+ Q_ASSERT(!tn->isRoot());
+ }
+
+#ifdef _UI_VMODELDATA_DEBUG
+ UserMessage::debug(" Branch treeNode: " + tn->vnode()->absNodePath());
+#endif
+ //First, we remove the branch contents
+ if(tn->numOfChildren())
+ {
+ int totalRows=tn->attrNum(attrFilter_) + tn->numOfChildren();
+ Q_EMIT beginFilterUpdateRemove(this,tn,totalRows);
+ tree_->removeChildren(tn);
+ Q_EMIT endFilterUpdateRemove(this,tn,totalRows);
+ }
+
+ //Second, we add the new contents
+ VTreeNode *branch=new VTreeNode(tn->vnode(),0);
+ tree_->buildBranch(filter_->match_,tn,branch);
+ int chNum=branch->numOfChildren();
+
+ Q_EMIT beginFilterUpdateAdd(this,tn,chNum);
+ if(chNum)
+ {
+ tree_->addBranch(tn,branch);
+ }
+ Q_EMIT endFilterUpdateAdd(this,tn,chNum);
+
+ //branch must be empty now
+ Q_ASSERT(branch->numOfChildren() == 0);
+
+ delete branch;
+ }
+ }
+
+ changeInfo_->clear();
+
+#ifdef _UI_VMODELDATA_DEBUG
+ UserMessage::debug("<-- VTreeServer::notifyEndServerSync");
+#endif
+}
+
+//--------------------------------------------------
+// NodeObserver methods
+//--------------------------------------------------
+
+void VTreeServer::notifyBeginNodeChange(const VNode* vnode, const std::vector<ecf::Aspect::Type>& aspect, const VNodeChange& change)
+{
+ if(vnode==NULL)
+ return;
+
+ VTreeNode* node=tree_->find(vnode);
+
+ bool attrNumCh=(std::find(aspect.begin(),aspect.end(),ecf::Aspect::ADD_REMOVE_ATTR) != aspect.end());
+ bool nodeNumCh=(std::find(aspect.begin(),aspect.end(),ecf::Aspect::ADD_REMOVE_NODE) != aspect.end());
+
+ //-----------------------------------------------------------------------
+ // The number of attributes changed but the number of nodes is the same!
+ //-----------------------------------------------------------------------
+ if(node && attrNumCh && !nodeNumCh)
+ {
+ //We do not deal with the attributes if they were never used for the given node.
+ //The first access to the attributes makes them initialised in the tree node.
+ if(node->isAttrInitialised())
+ {
+ //This is the already updated attribute num
+ int currentNum=vnode->attrNum(attrFilter_);
+
+ //That is the attribute num we store in the tree node.
+ int cachedNum=node->attrNum(attrFilter_);
+
+ Q_ASSERT(cachedNum >= 0);
+
+ int diff=currentNum-cachedNum;
+ if(diff != 0)
+ {
+ Q_EMIT beginAddRemoveAttributes(this,node,currentNum,cachedNum);
+
+ //We update the attribute num in the tree node
+ node->updateAttrNum(attrFilter_);
+ Q_EMIT endAddRemoveAttributes(this,node,currentNum,cachedNum);
+ }
+ }
+ }
+
+ //----------------------------------------------------------------------
+ // The number of nodes changed but number of attributes is the same!
+ //----------------------------------------------------------------------
+ else if(!attrNumCh && nodeNumCh)
+ {
+ //This can never happen
+ assert(0);
+ }
+
+ //---------------------------------------------------------------------
+ // Both the number of nodes and the number of attributes changed!
+ //---------------------------------------------------------------------
+ else if(attrNumCh && nodeNumCh)
+ {
+ //This can never happen
+ assert(0);
+ }
+
+ //---------------------------------------------------------------------
+ // The number of attributes and nodes did not change
+ //---------------------------------------------------------------------
+ else
+ {
+ //Check the aspects
+ for(std::vector<ecf::Aspect::Type>::const_iterator it=aspect.begin(); it != aspect.end(); ++it)
+ {
+ //Changes in the nodes
+ if(*it == ecf::Aspect::STATE || *it == ecf::Aspect::DEFSTATUS ||
+ *it == ecf::Aspect::SUSPENDED)
+ {
+ if(node && node->isAttrInitialised())
+ {
+ Q_EMIT nodeChanged(this,node);
+ }
+
+ if(!vnode->isServer())
+ changeInfo_->addStateChange(vnode);
+
+#ifdef _UI_VMODELDATA_DEBUG
+ UserMessage::debug(" node status changed: " + vnode->strName());
+#endif
+ }
+
+ //Changes might affect the icons
+ else if (*it == ecf::Aspect::FLAG || *it == ecf::Aspect::SUBMITTABLE ||
+ *it == ecf::Aspect::TODAY || *it == ecf::Aspect::TIME ||
+ *it == ecf::Aspect::DAY || *it == ecf::Aspect::CRON || *it == ecf::Aspect::DATE)
+ {
+ if(node && node->isAttrInitialised())
+ {
+ Q_EMIT nodeChanged(this,node);
+ }
+ }
+
+ //Changes in the attributes
+ if(*it == ecf::Aspect::METER || *it == ecf::Aspect::EVENT ||
+ *it == ecf::Aspect::LABEL || *it == ecf::Aspect::LIMIT ||
+ *it == ecf::Aspect::EXPR_TRIGGER || *it == ecf::Aspect::EXPR_COMPLETE ||
+ *it == ecf::Aspect::REPEAT || *it == ecf::Aspect::NODE_VARIABLE ||
+ *it == ecf::Aspect::LATE || *it == ecf::Aspect::TODAY || *it == ecf::Aspect::TIME ||
+ *it == ecf::Aspect::DAY || *it == ecf::Aspect::CRON || *it == ecf::Aspect::DATE )
+ {
+ if(node && node->isAttrInitialised())
+ {
+ Q_EMIT attributesChanged(this,node);
+ }
+ }
+ }
+ }
+}
+
+void VTreeServer::notifyEndNodeChange(const VNode* vnode, const std::vector<ecf::Aspect::Type>& aspect, const VNodeChange& change)
+{
+}
+
+void VTreeServer::reload()
+{
+ changeInfo_->clear();
+
+ Q_EMIT beginServerClear(this,-1);
+ tree_->clear();
+ inScan_=true;
+ Q_EMIT endServerClear(this,-1);
+
+ Q_ASSERT(filter_);
+
+ if(filter_->isNull())
+ {
+ tree_->build();
+ }
+
+ else
+ {
+ filter_->update();
+ tree_->build(filter_->match_);
+ }
+
+ Q_EMIT beginServerScan(this, tree_->attrNum(attrFilter_)+tree_->numOfChildren());
+ inScan_=false;
+ Q_EMIT endServerScan(this, tree_->attrNum(attrFilter_)+tree_->numOfChildren());
+}
+
+
+void VTreeServer::attrFilterChanged()
+{
+ //In the tree root the attrNum must be cached/initialised
+ Q_ASSERT(tree_->isAttrInitialised());
+ int oriNum=tree_->attrNum(attrFilter_)+tree_->numOfChildren();
+ Q_EMIT beginServerClear(this,oriNum);
+ inScan_=true;
+ Q_EMIT endServerClear(this,oriNum);
+
+ //We reset the attrNum to the uninitailsed value in the whole tree
+ tree_->resetAttrNum();
+
+ //Get the current num of attr and children
+ int num=tree_->attrNum(attrFilter_)+tree_->numOfChildren();
+ Q_EMIT beginServerScan(this,num);
+ inScan_=false;
+ Q_EMIT endServerScan(this,num);
+}
+
+//==========================================
+//
+// VTableServer
+//
+//==========================================
+
+//It takes ownership of the filter
+
+VTableServer::VTableServer(ServerHandler *server,NodeFilterDef* filterDef) :
+ VModelServer(server)
+{
+ filter_=new TableNodeFilter(filterDef,server);
+
+ //We have to observe the nodes of the server.
+ //server_->addNodeObserver(this);
+}
+
+VTableServer::~VTableServer()
+{
+ delete filter_;
+}
+
+NodeFilter* VTableServer::filter() const
+{
+ return const_cast<TableNodeFilter*>(filter_);
+}
+
+int VTableServer::nodeNum() const
+{
+ return filter_->matchCount();
+}
+
+//Node at the position in the list of filtered nodes
+VNode* VTableServer::nodeAt(int index) const
+{
+ return filter_->nodeAt(index);
+}
+
+//Position in the list of filtered nodes
+int VTableServer::indexOf(const VNode* node) const
+{
+ return filter_->indexOf(node);
+}
+
+//--------------------------------------------------
+// ServerObserver methods
+//--------------------------------------------------
+
+void VTableServer::notifyServerDelete(ServerHandler*)
+{
+#ifdef _UI_VMODELDATA_DEBUG
+ UserMessage::debug("VTableServer::notifyServerDelete ---> should never be called!!");
+#endif
+ Q_ASSERT(0);
+}
+
+void VTableServer::notifyBeginServerScan(ServerHandler* server,const VServerChange& change)
+{
+ inScan_=true;
+ Q_ASSERT(nodeNum() == 0);
+ //At this point we do not know how many nodes we will have in the filter!
+}
+
+void VTableServer::notifyEndServerScan(ServerHandler* server)
+{
+ Q_ASSERT(inScan_);
+ filter_->update();
+ Q_EMIT beginServerScan(this,nodeNum());
+ inScan_=false;
+ Q_EMIT endServerScan(this,nodeNum());
+}
+
+void VTableServer::notifyBeginServerClear(ServerHandler* server)
+{
+ Q_EMIT beginServerClear(this,nodeNum());
+}
+
+void VTableServer::notifyEndServerClear(ServerHandler* server)
+{
+ int oriNodeNum=nodeNum();
+ filter_->clear();
+ Q_EMIT endServerClear(this,oriNodeNum);
+}
+
+void VTableServer::notifyServerConnectState(ServerHandler* server)
+{
+ Q_EMIT rerender();
+}
+
+void VTableServer::notifyServerActivityChanged(ServerHandler* server)
+{
+ Q_EMIT dataChanged(this);
+}
+
+//This is called when a normal sync (no reset or rescan) is finished. We have delayed the update of the
+//filter to this point but now we need to do it.
+void VTableServer::notifyEndServerSync(ServerHandler*)
+{
+ reload();
+}
+
+void VTableServer::notifyBeginNodeChange(const VNode* node, const std::vector<ecf::Aspect::Type>& types,const VNodeChange&)
+{
+ Q_EMIT nodeChanged(this,node);
+}
+
+void VTableServer::notifyEndNodeChange(const VNode* node, const std::vector<ecf::Aspect::Type>& types,const VNodeChange&)
+{
+}
+
+void VTableServer::reload()
+{
+#ifdef _UI_VMODELDATA_DEBUG
+ UserMessage::debug("VTableServer::reload --> " + server_->name());
+#endif
+
+ int oriNodeNum=nodeNum();
+#ifdef _UI_VMODELDATA_DEBUG
+ UserMessage::debug(" oriNodeNum: " + QString::number(oriNodeNum).toStdString());
+#endif
+
+ Q_EMIT beginServerClear(this,oriNodeNum);
+ filter_->clear();
+ inScan_=true;
+ Q_EMIT endServerClear(this,oriNodeNum);
+
+ filter_->update();
+
+ Q_EMIT beginServerScan(this, nodeNum());
+ inScan_=false;
+ Q_EMIT endServerScan(this, nodeNum());
+
+#ifdef _UI_VMODELDATA_DEBUG
+ UserMessage::debug(" nodeNum: " + QString::number(oriNodeNum).toStdString());
+ UserMessage::debug("<-- VTableServer::reload");
+#endif
+
+
+}
+
+//==========================================
+//
+// VModelData
+//
+//==========================================
+
+VModelData::VModelData(NodeFilterDef *filterDef,AbstractNodeModel* model) :
+ QObject(model),
+ serverFilter_(0),
+ filterDef_(filterDef),
+ model_(model),
+ active_(false)
+{
+ connect(filterDef_,SIGNAL(changed()),
+ this,SLOT(slotFilterDefChanged()));
+
+ connect(this,SIGNAL(filterDeleteBegin()),
+ model_,SLOT(slotFilterDeleteBegin()));
+
+ connect(this,SIGNAL(filterDeleteEnd()),
+ model_,SLOT(slotFilterDeleteEnd()));
+
+ connect(this,SIGNAL(serverAddBegin(int)),
+ model_,SLOT(slotServerAddBegin(int)));
+
+ connect(this,SIGNAL(serverAddEnd()),
+ model_,SLOT(slotServerAddEnd()));
+
+ connect(this,SIGNAL(serverRemoveBegin(VModelServer*,int)),
+ model_,SLOT(slotServerRemoveBegin(VModelServer*,int)));
+
+ connect(this,SIGNAL(serverRemoveEnd(int)),
+ model_,SLOT(slotServerRemoveEnd(int)));
+
+ connect(this,SIGNAL(filterChangeBegun()),
+ model_,SIGNAL(filterChangeBegun()));
+
+ connect(this,SIGNAL(filterChangeEnded()),
+ model_,SIGNAL(filterChangeEnded()));
+
+}
+
+VModelData::~VModelData()
+{
+ clear();
+}
+
+void VModelData::connectToModel(VModelServer* d)
+{
+ connect(d,SIGNAL(dataChanged(VModelServer*)),
+ model_,SLOT(slotDataChanged(VModelServer*)));
+
+ connect(d,SIGNAL(beginServerScan(VModelServer*,int)),
+ model_,SLOT(slotBeginServerScan(VModelServer*,int)));
+
+ connect(d,SIGNAL(endServerScan(VModelServer*,int)),
+ model_,SLOT(slotEndServerScan(VModelServer*,int)));
+
+ connect(d,SIGNAL(beginServerClear(VModelServer*,int)),
+ model_,SLOT(slotBeginServerClear(VModelServer*,int)));
+
+ connect(d,SIGNAL(endServerClear(VModelServer*,int)),
+ model_,SLOT(slotEndServerClear(VModelServer*,int)));
+
+ //The model relays this signal
+ connect(d,SIGNAL(rerender()),
+ model_,SIGNAL(rerender()));
+}
+
+//Completely clear the data and rebuild everything with a new
+//ServerFilter.
+void VModelData::reset(ServerFilter* serverFilter)
+{
+ clear();
+ serverFilter_=serverFilter;
+
+ init();
+}
+
+void VModelData::init()
+{
+ serverFilter_->addObserver(this);
+
+ for(unsigned int i=0; i < serverFilter_->items().size(); i++)
+ {
+ if(ServerHandler *server=serverFilter_->items().at(i)->serverHandler())
+ {
+ add(server);
+ }
+ }
+}
+
+void VModelData::clear()
+{
+#ifdef _UI_VMODELDATA_DEBUG
+ UserMessage::debug("VModelData::clear --> " + QString::number((qint64)this,16).toStdString());
+ qDebug() << " serverFilter_" << serverFilter_;
+#endif
+
+ if(serverFilter_)
+ serverFilter_->removeObserver(this);
+
+ serverFilter_=NULL;
+
+ for(int i=0; i < servers_.size(); i++)
+ {
+ delete servers_.at(i);
+ }
+
+ servers_.clear();
+
+#ifdef _UI_VMODELDATA_DEBUG
+ UserMessage::debug("<-- VModelData::clear");
+#endif
+}
+
+VModelServer* VModelData::server(int n) const
+{
+ return (n >=0 && n < servers_.size())?servers_.at(n):0;
+}
+
+ServerHandler* VModelData::serverHandler(int n) const
+{
+ return (n >=0 && n < servers_.size())?servers_.at(n)->server_:0;
+}
+
+int VModelData::indexOfServer(void* idPointer) const
+{
+ for(unsigned int i=0; i < servers_.size(); i++)
+ if(servers_.at(i) == idPointer)
+ return i;
+
+ return -1;
+}
+
+ServerHandler* VModelData::serverHandler(void* idPointer) const
+{
+ for(unsigned int i=0; i < servers_.size(); i++)
+ if(servers_.at(i) == idPointer)
+ return servers_.at(i)->server_;
+
+ return NULL;
+}
+
+VModelServer* VModelData::server(const void* idPointer) const
+{
+ for(unsigned int i=0; i < servers_.size(); i++)
+ if(servers_.at(i) == idPointer)
+ return servers_.at(i);
+
+ return NULL;
+}
+
+VModelServer* VModelData::server(const std::string& name) const
+{
+ for(unsigned int i=0; i < servers_.size(); i++)
+ if(servers_.at(i)->server_->name() == name)
+ return servers_.at(i);
+
+ return NULL;
+}
+
+VModelServer* VModelData::server(ServerHandler* s) const
+{
+ for(unsigned int i=0; i < servers_.size(); i++)
+ if(servers_.at(i)->server_ == s)
+ return servers_.at(i);
+
+ return NULL;
+}
+
+
+int VModelData::indexOfServer(ServerHandler* s) const
+{
+ for(unsigned int i=0; i < servers_.size(); i++)
+ if(servers_.at(i)->server_ == s)
+ return i;
+ return -1;
+}
+
+int VModelData::numOfNodes(int index) const
+{
+ if(VModelServer *d=server(index))
+ {
+ return d->nodeNum();
+ }
+ return 0;
+}
+
+//ServerFilter observer methods
+
+void VModelData::notifyServerFilterAdded(ServerItem* item)
+{
+ if(!item)
+ return;
+
+ if(ServerHandler *server=item->serverHandler())
+ {
+ //Notifies the model that a change will happen
+ Q_EMIT serverAddBegin(count());
+
+ add(server);
+
+ //Notifies the model that the change has finished
+ Q_EMIT serverAddEnd();
+ return;
+ }
+}
+
+void VModelData::notifyServerFilterRemoved(ServerItem* item)
+{
+#ifdef _UI_VMODELDATA_DEBUG
+ UserMessage::debug("VModelData::notifyServerFilterRemoved --> ");
+#endif
+
+ if(!item)
+ return;
+
+#ifdef _UI_VMODELDATA_DEBUG
+ UserMessage::debug(" server=" + item->name());
+#endif
+
+ int i=0;
+ for(std::vector<VModelServer*>::iterator it=servers_.begin(); it!= servers_.end(); ++it)
+ {
+ if((*it)->server_ == item->serverHandler())
+ {
+ int nodeNum=(*it)->nodeNum();
+
+#ifdef _UI_VMODELDATA_DEBUG
+ UserMessage::debug(" emit serverRemoveBegin");
+#endif
+ //Notifies the model that a change will happen
+ Q_EMIT serverRemoveBegin(*it,nodeNum);
+
+ delete *it;
+ servers_.erase(it);
+
+#ifdef _UI_VMODELDATA_DEBUG
+ UserMessage::debug(" emit serverRemoveEnd");
+#endif
+ //Notifies the model that the change has finished
+ Q_EMIT serverRemoveEnd(nodeNum);
+#ifdef _UI_VMODELDATA_DEBUG
+ UserMessage::debug("<-- VModelData::notifyServerFilterRemoved");
+#endif
+ return;
+ }
+ i++;
+ }
+
+#ifdef _UI_VMODELDATA_DEBUG
+ UserMessage::debug("<-- VModelData::notifyServerFilterRemoved");
+#endif
+}
+
+void VModelData::notifyServerFilterChanged(ServerItem* item)
+{
+ //Q_EMIT dataChanged();
+}
+
+void VModelData::notifyServerFilterDelete()
+{
+#ifdef _UI_VMODELDATA_DEBUG
+ UserMessage::debug("VModelData::notifyServerFilterDelete --> " + QString::number((qint64)this,16).toStdString());
+#endif
+
+ Q_EMIT filterDeleteBegin();
+
+#ifdef _UI_VMODELDATA_DEBUG
+ UserMessage::debug(" filterDeleteBegin emitted");
+#endif
+
+ clear();
+
+#ifdef _UI_VMODELDATA_DEBUG
+ UserMessage::debug(" filterDeleteEnd emitted");
+#endif
+
+ Q_EMIT filterDeleteEnd();
+
+#ifdef _UI_VMODELDATA_DEBUG
+ UserMessage::debug("<-- VModelData::notifyServerFilterDelete");
+#endif
+
+}
+
+//Should only be called once at the beginning
+void VModelData::setActive(bool active)
+{
+ if(active != active_)
+ {
+ active_=active;
+ if(active_)
+ reload(false);
+ else
+ clear();
+ }
+}
+
+void VModelData::reload(bool broadcast)
+{
+#ifdef _UI_VMODELDATA_DEBUG
+ UserMessage::debug("VModelData::reload --> ");
+#endif
+
+ Q_ASSERT(active_);
+
+ if(broadcast)
+ Q_EMIT filterChangeBegun();
+
+ for(unsigned int i=0; i < servers_.size(); i++)
+ {
+ servers_.at(i)->reload();
+ }
+
+ if(broadcast)
+ Q_EMIT filterChangeEnded();
+
+#ifdef _UI_VMODELDATA_DEBUG
+ UserMessage::debug("<-- VModelData::reload");
+#endif
+}
+
+void VModelData::slotFilterDefChanged()
+{
+#ifdef _UI_VMODELDATA_DEBUG
+ UserMessage::debug("VModelData::slotFilterDefChanged --> ");
+#endif
+
+ if(active_)
+ reload(true);
+}
+
+bool VModelData::isFilterNull() const
+{
+ for(unsigned int i=0; i < servers_.size(); i++)
+ {
+ return servers_.at(i)->filter()->isNull();
+ }
+
+ return true;
+}
+
+//==============================================================
+//
+// VTreeModelData
+//
+//==============================================================
+
+VTreeModelData::VTreeModelData(NodeFilterDef* filterDef,AttributeFilter* attrFilter,AbstractNodeModel* model) :
+ VModelData(filterDef,model),
+ attrFilter_(attrFilter)
+{
+ //Attribute filter changes
+ connect(attrFilter_,SIGNAL(changed()),
+ this,SLOT(slotAttrFilterChanged()));
+}
+
+void VTreeModelData::connectToModel(VModelServer* s)
+{
+ VModelData::connectToModel(s);
+
+ VTreeServer* ts=s->treeServer();
+ Q_ASSERT(ts);
+
+ connect(ts,SIGNAL(beginAddRemoveAttributes(VTreeServer*,const VTreeNode*,int,int)),
+ model_,SLOT(slotBeginAddRemoveAttributes(VTreeServer*,const VTreeNode*,int,int)));
+
+ connect(ts,SIGNAL(endAddRemoveAttributes(VTreeServer*,const VTreeNode*,int,int)),
+ model_,SLOT(slotEndAddRemoveAttributes(VTreeServer*,const VTreeNode*,int,int)));
+
+ connect(ts,SIGNAL(nodeChanged(VTreeServer*,const VTreeNode*)),
+ model_,SLOT(slotNodeChanged(VTreeServer*,const VTreeNode*)));
+
+ connect(ts,SIGNAL(attributesChanged(VTreeServer*,const VTreeNode*)),
+ model_,SLOT(slotAttributesChanged(VTreeServer*,const VTreeNode*)));
+
+ connect(ts,SIGNAL(beginFilterUpdateRemove(VTreeServer*,const VTreeNode*,int)),
+ model_,SLOT(slotBeginFilterUpdateRemove(VTreeServer*,const VTreeNode*,int)));
+
+ connect(ts,SIGNAL(endFilterUpdateRemove(VTreeServer*,const VTreeNode*,int)),
+ model_,SLOT(slotEndFilterUpdateRemove(VTreeServer*,const VTreeNode*,int)));
+
+ connect(ts,SIGNAL(beginFilterUpdateAdd(VTreeServer*,const VTreeNode*,int)),
+ model_,SLOT(slotBeginFilterUpdateAdd(VTreeServer*,const VTreeNode*,int)));
+
+ connect(ts,SIGNAL(endFilterUpdateAdd(VTreeServer*,const VTreeNode*,int)),
+ model_,SLOT(slotEndFilterUpdateAdd(VTreeServer*,const VTreeNode*,int)));
+}
+
+void VTreeModelData::add(ServerHandler *server)
+{
+ VModelServer* d=NULL;
+
+ d=new VTreeServer(server,filterDef_,attrFilter_);
+
+ connectToModel(d);
+
+ servers_.push_back(d);
+
+ if(active_)
+ reload(true);
+}
+
+void VTreeModelData::slotAttrFilterChanged()
+{
+ Q_EMIT filterChangeBegun();
+
+ for(unsigned int i=0; i < servers_.size(); i++)
+ {
+ servers_.at(i)->treeServer()->attrFilterChanged();
+ }
+
+ Q_EMIT filterChangeEnded();
+
+}
+
+//==============================================================
+//
+// VTableModelData
+//
+//==============================================================
+
+VTableModelData::VTableModelData(NodeFilterDef* filterDef,AbstractNodeModel* model) :
+ VModelData(filterDef,model)
+{
+}
+void VTableModelData::connectToModel(VModelServer* s)
+{
+ VModelData::connectToModel(s);
+
+ VTableServer* ts=s->tableServer();
+ Q_ASSERT(ts);
+
+ connect(ts,SIGNAL(nodeChanged(VTableServer*,const VNode*)),
+ model_,SLOT(slotNodeChanged(VTableServer*,const VNode*)));
+
+}
+void VTableModelData::add(ServerHandler *server)
+{
+ VModelServer* d=NULL;
+
+ d=new VTableServer(server,filterDef_);
+
+ connectToModel(d);
+
+ servers_.push_back(d);
+
+ if(active_)
+ reload(false);
+}
+
+//Gives the position of this server in the full list of filtered nodes.
+int VTableModelData::position(VTableServer* server)
+{
+ int start=-1;
+
+ if(server)
+ {
+ start=0;
+ for(unsigned int i=0; i < servers_.size(); i++)
+ {
+ if(servers_.at(i) == server)
+ {
+ return start;
+ }
+ start+=servers_[i]->nodeNum();
+ }
+ }
+
+ return start;
+}
+
+//Identifies the range of nodes belonging to this server in the full list of filtered nodes.
+bool VTableModelData::position(VTableServer* server,int& start,int& count)
+{
+ start=-1;
+ count=-1;
+
+ if(server)
+ {
+ if(server->nodeNum() > 0)
+ {
+ count=server->nodeNum();
+ start=0;
+ for(unsigned int i=0; i < servers_.size(); i++)
+ {
+ if(servers_.at(i) == server)
+ {
+ return true;
+ }
+ start+=servers_.at(i)->nodeNum();
+ }
+ }
+ }
+
+ return false;
+}
+
+//Gets the position of the given node in the full list of filtered nodes.
+//This has to be very fast!!!
+int VTableModelData::position(VTableServer* server,const VNode *node) const
+{
+ if(server)
+ {
+ int totalRow=0;
+ for(unsigned int i=0; i < servers_.size(); i++)
+ {
+ if(servers_.at(i) == server)
+ {
+ int pos=server->tableServer()->indexOf(node);
+ if(pos != -1)
+ {
+ totalRow+=pos;
+ return totalRow;
+ }
+ else
+ return -1;
+ }
+ else
+ {
+ totalRow+=server->nodeNum();
+ }
+ }
+ }
+
+ return -1;
+}
+
+//This has to be very fast!!!
+int VTableModelData::position(const VNode *node) const
+{
+ int serverIdx=indexOfServer(node->server());
+ if(serverIdx != -1)
+ {
+ return position(servers_[serverIdx]->tableServer(),node);
+ }
+
+ return -1;
+}
+
+VNode* VTableModelData::nodeAt(int totalRow)
+{
+ int cnt=0;
+
+ if(totalRow < 0)
+ return NULL;
+
+ for(unsigned int i=0; i < servers_.size(); i++)
+ {
+ int pos=totalRow-cnt;
+ if(pos < servers_[i]->nodeNum())
+ {
+ return servers_[i]->tableServer()->nodeAt(pos);
+ }
+ cnt+= servers_[i]->nodeNum();
+ }
+
+ return NULL;
+}
diff --git a/Viewer/src/VModelData.hpp b/Viewer/src/VModelData.hpp
new file mode 100644
index 0000000..70c0eed
--- /dev/null
+++ b/Viewer/src/VModelData.hpp
@@ -0,0 +1,276 @@
+//============================================================================
+// Copyright 2015 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef VMODELDATA_H
+#define VMODELDATA_H
+
+#include <vector>
+
+#include <QObject>
+
+#include "NodeObserver.hpp"
+#include "ServerFilter.hpp"
+#include "ServerObserver.hpp"
+
+class Node;
+class VNode;
+class VServer;
+
+class AbstractNodeModel;
+class AttributeFilter;
+class NodeFilter;
+class NodeFilterDef;
+class NodeQUery;
+class ServerHandler;
+class TableNodeFilter;
+class TreeNodeFilter;
+class VParamSet;
+class VAttributeType;
+class VTreeServer;
+class VTableServer;
+class VTree;
+class VTreeNode;
+
+
+class VTreeChangeInfo
+{
+public:
+ VTreeChangeInfo() {}
+ void addStateChange(const VNode*);
+ const std::vector<VNode*> stateChangeSuites() const { return stateSuites_;}
+ void clear() {stateSuites_.clear();}
+
+protected:
+ std::vector<VNode*> stateSuites_;
+};
+
+
+class VModelServer : public QObject, public ServerObserver, public NodeObserver
+{
+Q_OBJECT
+
+friend class VModelData;
+friend class VTableModelData;
+friend class VTreeModelData;
+
+public:
+ explicit VModelServer(ServerHandler *server);
+ virtual ~VModelServer();
+
+ ServerHandler* realServer() const {return server_;}
+
+ int totalNodeNum() const;
+ virtual int nodeNum() const = 0;
+ virtual void reload()=0;
+ //virtual void filterChanged()=0;
+ bool inScan() const {return inScan_;}
+ virtual NodeFilter* filter() const=0;
+
+ //Performance hack to avoid casts
+ virtual VTreeServer* treeServer() const {return NULL;}
+ virtual VTableServer* tableServer() const {return NULL;}
+
+Q_SIGNALS:
+ void dataChanged(VModelServer*);
+ void beginServerScan(VModelServer*,int);
+ void endServerScan(VModelServer*,int);
+ void beginServerClear(VModelServer*,int);
+ void endServerClear(VModelServer*,int);
+
+ void rerender();
+
+protected:
+ ServerHandler *server_;
+ bool inScan_;
+};
+
+class VTreeServer : public VModelServer
+{
+Q_OBJECT
+
+public:
+ VTreeServer(ServerHandler *server,NodeFilterDef* filterDef,AttributeFilter *attrFilter);
+ ~VTreeServer();
+
+ void reload();
+ void filterChanged();
+ int nodeNum() const;
+ NodeFilter* filter() const;
+ VTree* tree() const {return tree_;}
+ VTreeServer* treeServer() const {return const_cast<VTreeServer*>(this);}
+ void attrFilterChanged();
+
+ //From ServerObserver
+ void notifyDefsChanged(ServerHandler* server, const std::vector<ecf::Aspect::Type>& a);
+ void notifyServerDelete(ServerHandler*);
+ void notifyBeginServerClear(ServerHandler* server);
+ void notifyEndServerClear(ServerHandler* server);
+ void notifyBeginServerScan(ServerHandler* server,const VServerChange&);
+ void notifyEndServerScan(ServerHandler* server);
+ void notifyServerConnectState(ServerHandler* server);
+ void notifyServerActivityChanged(ServerHandler* server);
+ void notifyEndServerSync(ServerHandler* server);
+
+ //From NodeObserver
+ void notifyBeginNodeChange(const VNode*, const std::vector<ecf::Aspect::Type>&,const VNodeChange&);
+ void notifyEndNodeChange(const VNode*, const std::vector<ecf::Aspect::Type>&,const VNodeChange&);
+
+Q_SIGNALS:
+ void beginAddRemoveAttributes(VTreeServer*,const VTreeNode*,int,int);
+ void endAddRemoveAttributes(VTreeServer*,const VTreeNode*,int,int);
+ void nodeChanged(VTreeServer*,const VTreeNode*);
+ void attributesChanged(VTreeServer*,const VTreeNode*);
+ void beginFilterUpdateRemove(VTreeServer*,const VTreeNode*,int);
+ void endFilterUpdateRemove(VTreeServer*,const VTreeNode*,int);
+ void beginFilterUpdateAdd(VTreeServer*,const VTreeNode*,int);
+ void endFilterUpdateAdd(VTreeServer*,const VTreeNode*,int);
+
+private:
+ VTree* tree_;
+ VTreeChangeInfo* changeInfo_;
+ AttributeFilter *attrFilter_;
+ TreeNodeFilter* filter_;
+};
+
+class VTableServer : public VModelServer
+{
+ Q_OBJECT
+public:
+ VTableServer(ServerHandler *server,NodeFilterDef* filterDef);
+ ~VTableServer();
+
+ void reload();
+ void filterChanged() {}
+ int nodeNum() const;
+ VNode* nodeAt(int) const;
+ int indexOf(const VNode* node) const;
+ NodeFilter* filter() const;
+ VTableServer* tableServer() const {return const_cast<VTableServer*>(this);}
+
+ //From ServerObserver
+ void notifyDefsChanged(ServerHandler* server, const std::vector<ecf::Aspect::Type>& a) {}
+ void notifyServerDelete(ServerHandler*);
+ void notifyBeginServerClear(ServerHandler* server);
+ void notifyEndServerClear(ServerHandler* server);
+ void notifyBeginServerScan(ServerHandler* server,const VServerChange&);
+ void notifyEndServerScan(ServerHandler* server);
+ void notifyServerConnectState(ServerHandler* server);
+ void notifyServerActivityChanged(ServerHandler* server);
+ void notifyEndServerSync(ServerHandler* server);
+
+ //From NodeObserver
+ void notifyBeginNodeChange(const VNode*, const std::vector<ecf::Aspect::Type>&,const VNodeChange&);
+ void notifyEndNodeChange(const VNode*, const std::vector<ecf::Aspect::Type>&,const VNodeChange&);
+
+Q_SIGNALS:
+ void nodeChanged(VTableServer*,const VNode*);
+
+private:
+ TableNodeFilter* filter_;
+};
+
+//This class defines the data a given Node Model (Tree or Table) displays. The
+//node models can only access data through this interface. The class internally stores
+//a vector of VModelServer objects each representing a server the model displays.
+
+class VModelData : public QObject, public ServerFilterObserver
+{
+Q_OBJECT
+
+public:
+ enum ModelType {TreeModel,TableModel};
+
+ VModelData(NodeFilterDef* filterDef,AbstractNodeModel* model);
+ ~VModelData();
+
+ void setActive(bool);
+ void clear();
+ void reset(ServerFilter* servers);
+
+ void reload(bool broadcast);
+
+ int count() const {return static_cast<int>(servers_.size());}
+ int indexOfServer(void*) const;
+ ServerHandler* serverHandler(void*) const;
+ ServerHandler* serverHandler(int) const;
+ VModelServer* server(int) const;
+ VModelServer* server(const void*) const;
+ VModelServer* server(const std::string&) const;
+ VModelServer* server(ServerHandler*) const;
+ int indexOfServer(ServerHandler* s) const;
+ int numOfNodes(int) const;
+ bool isFilterNull() const;
+
+ //From ServerFilterObserver
+ void notifyServerFilterAdded(ServerItem*);
+ void notifyServerFilterRemoved(ServerItem*);
+ void notifyServerFilterChanged(ServerItem*);
+ void notifyServerFilterDelete();
+
+public Q_SLOTS:
+ void slotFilterDefChanged();
+
+Q_SIGNALS:
+ //void filterChanged();
+ void filterDeleteBegin();
+ void filterDeleteEnd();
+ void filterChangeBegun();
+ void filterChangeEnded();
+ void serverAddBegin(int);
+ void serverAddEnd();
+ void serverRemoveBegin(VModelServer*,int);
+ void serverRemoveEnd(int);
+
+protected:
+ void init();
+ virtual void add(ServerHandler*)=0;
+ virtual void connectToModel(VModelServer* d);
+
+ std::vector<VModelServer*> servers_;
+ ServerFilter *serverFilter_;
+ NodeFilterDef* filterDef_;
+ AbstractNodeModel* model_;
+ bool active_;
+};
+
+class VTreeModelData : public VModelData
+{
+ Q_OBJECT
+
+public:
+ VTreeModelData(NodeFilterDef* filterDef,AttributeFilter* attrFilter,AbstractNodeModel* model);
+
+protected Q_SLOTS:
+ void slotAttrFilterChanged();
+
+protected:
+ void add(ServerHandler *server);
+ void connectToModel(VModelServer* d);
+
+ AttributeFilter *attrFilter_;
+};
+
+class VTableModelData : public VModelData
+{
+public:
+ VTableModelData(NodeFilterDef* filterDef,AbstractNodeModel* model);
+
+ int numOfFiltered(int index) const;
+ VNode* nodeAt(int totalRow);
+ int position(const VNode *node) const;
+ int position(VTableServer*,const VNode *node) const;
+ int position(VTableServer* server);
+ bool position(VTableServer* server,int& start,int& count);
+
+protected:
+ void add(ServerHandler *server);
+ void connectToModel(VModelServer* d);
+};
+
+#endif
diff --git a/Viewer/src/VNState.cpp b/Viewer/src/VNState.cpp
new file mode 100644
index 0000000..e7695ef
--- /dev/null
+++ b/Viewer/src/VNState.cpp
@@ -0,0 +1,226 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "VNState.hpp"
+
+#include <QDebug>
+#include <QImage>
+#include <QImageReader>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <map>
+
+#include "VNode.hpp"
+#include "ServerHandler.hpp"
+#include "Submittable.hpp"
+#include "UserMessage.hpp"
+#include "VConfigLoader.hpp"
+#include "VProperty.hpp"
+
+std::map<std::string,VNState*> VNState::items_;
+static std::map<NState::State,VNState*> stateMap_;
+
+static VNState unSt("unknown",NState::UNKNOWN);
+static VNState compSt("complete",NState::COMPLETE);
+static VNState queuedSt("queued",NState::QUEUED);
+static VNState abortedSt("aborted",NState::ABORTED);
+static VNState submittedSt("submitted",NState::SUBMITTED);
+static VNState activeSt("active",NState::ACTIVE);
+static VNState suspendedSt("suspended");
+
+VNState::VNState(const std::string& name,NState::State nstate) :
+ VParam(name)
+{
+ items_[name]=this;
+ stateMap_[nstate]=this;
+}
+
+VNState::VNState(const std::string& name) :
+ VParam(name)
+{
+ items_[name]=this;
+}
+
+//===============================================================
+//
+// Static methods
+//
+//===============================================================
+
+std::vector<VParam*> VNState::filterItems()
+{
+ std::vector<VParam*> v;
+ for(std::map<std::string,VNState*>::const_iterator it=items_.begin(); it != items_.end(); ++it)
+ {
+ v.push_back(it->second);
+ }
+
+ return v;
+}
+
+VNState* VNState::toState(const VNode *n)
+{
+ if(!n || !n->node().get())
+ return NULL;
+
+ node_ptr node=n->node();
+
+ if(node->isSuspended())
+ return items_["suspended"];
+ else
+ {
+ std::map<NState::State,VNState*>::const_iterator it=stateMap_.find(node->state());
+ if(it != stateMap_.end())
+ return it->second;
+ }
+
+ return NULL;
+}
+
+VNState* VNState::toRealState(const VNode *n)
+{
+ if(!n || !n->node().get())
+ return NULL;
+
+ node_ptr node=n->node();
+
+ std::map<NState::State,VNState*>::const_iterator it=stateMap_.find(node->state());
+ if(it != stateMap_.end())
+ return it->second;
+
+ return NULL;
+}
+
+VNState* VNState::toDefaultState(const VNode *n)
+{
+ if(!n || !n->node().get())
+ return NULL;
+
+ node_ptr node=n->node();
+
+ std::map<NState::State,VNState*>::const_iterator it=stateMap_.find(DState::convert(node->defStatus()));
+ if(it != stateMap_.end())
+ return it->second;
+
+ return NULL;
+}
+
+VNState* VNState::find(const std::string& name)
+{
+ std::map<std::string,VNState*>::const_iterator it=items_.find(name);
+ if(it != items_.end())
+ return it->second;
+
+ return NULL;
+}
+
+//
+//Has to be very quick!!
+//
+
+QColor VNState::toColour(const VNode *n)
+{
+ VNState *obj=VNState::toState(n);
+ return (obj)?(obj->colour()):QColor();
+}
+
+QColor VNState::toRealColour(const VNode *n)
+{
+ VNState *obj=VNState::toRealState(n);
+ return (obj)?(obj->colour()):QColor();
+}
+
+QColor VNState::toFontColour(const VNode *n)
+{
+ VNState *obj=VNState::toState(n);
+ return (obj)?(obj->fontColour()):QColor();
+}
+
+QColor VNState::toTypeColour(const VNode *n)
+{
+ VNState *obj=VNState::toState(n);
+ return (obj)?(obj->typeColour()):QColor();
+}
+
+QString VNState::toName(const VNode *n)
+{
+ VNState *obj=VNState::toState(n);
+ return (obj)?(obj->name()):QString();
+}
+
+QString VNState::toDefaultStateName(const VNode *n)
+{
+ VNState *obj=VNState::toDefaultState(n);
+ return (obj)?(obj->name()):QString();
+}
+
+QString VNState::toRealStateName(const VNode *n)
+{
+ VNState *obj=VNState::toRealState(n);
+ return (obj)?(obj->name()):QString();
+}
+
+//==================================================
+// Server state
+//==================================================
+
+VNState* VNState::toState(ServerHandler *s)
+{
+ if(!s)
+ return NULL;
+
+ bool susp=false;
+ NState::State ns=s->state(susp);
+
+ if(susp)
+ return items_["suspended"];
+ else
+ {
+ std::map<NState::State,VNState*>::const_iterator it=stateMap_.find(ns);
+ if(it != stateMap_.end())
+ return it->second;
+ }
+
+ return NULL;
+}
+
+QString VNState::toName(ServerHandler *s)
+{
+ VNState *obj=VNState::toState(s);
+ return (obj)?(obj->name()):QString();
+}
+
+QColor VNState::toColour(ServerHandler *s)
+{
+ VNState *obj=VNState::toState(s);
+ return (obj)?(obj->colour()):QColor();
+}
+
+QColor VNState::toFontColour(ServerHandler *s)
+{
+ VNState *obj=VNState::toState(s);
+ return (obj)?(obj->fontColour()):QColor();
+}
+
+void VNState::load(VProperty* group)
+{
+ Q_FOREACH(VProperty* p,group->children())
+ {
+ if(VNState* obj=VNState::find(p->strName()))
+ {
+ obj->setProperty(p);
+ }
+ }
+}
+
+static SimpleLoader<VNState> loader("nstate");
diff --git a/Viewer/src/VNState.hpp b/Viewer/src/VNState.hpp
new file mode 100644
index 0000000..5ceb641
--- /dev/null
+++ b/Viewer/src/VNState.hpp
@@ -0,0 +1,59 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VNSTATE_HPP_
+#define VNSTATE_HPP_
+
+#include <map>
+#include <vector>
+#include <string>
+
+#include "NState.hpp"
+#include "VParam.hpp"
+
+class VNode;
+class ServerHandler;
+class VProperty;
+
+class VNState : public VParam
+{
+public:
+ VNState(const std::string& name,NState::State);
+ explicit VNState(const std::string& name);
+
+ //Nodes
+ static QString toName(const VNode*);
+ static QString toDefaultStateName(const VNode*);
+ static QString toRealStateName(const VNode*);
+ static QColor toColour(const VNode* n);
+ static QColor toRealColour(const VNode* n);
+ static QColor toFontColour(const VNode* n);
+ static QColor toTypeColour(const VNode* n);
+ static VNState* toState(const VNode* n);
+ static VNState* toDefaultState(const VNode* n);
+ static VNState* toRealState(const VNode* n);
+
+ //Server
+ static QString toName(ServerHandler*);
+ static QColor toColour(ServerHandler*);
+ static VNState* toState(ServerHandler*);
+ static QColor toFontColour(ServerHandler*);
+
+ static std::vector<VParam*> filterItems();
+ static VNState* find(const std::string& name);
+
+ //Called from VConfigLoader
+ static void load(VProperty*);
+
+private:
+ static std::map<std::string,VNState*> items_;
+};
+
+#endif
diff --git a/Viewer/src/VNode.cpp b/Viewer/src/VNode.cpp
new file mode 100644
index 0000000..940c871
--- /dev/null
+++ b/Viewer/src/VNode.cpp
@@ -0,0 +1,1323 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "VNode.hpp"
+
+#include "Node.hpp"
+#include "Variable.hpp"
+
+#include "ConnectState.hpp"
+#include "ServerDefsAccess.hpp"
+#include "ServerHandler.hpp"
+#include "VAttributeType.hpp"
+#include "VFileInfo.hpp"
+#include "VNState.hpp"
+#include "VSState.hpp"
+#include "VTaskNode.hpp"
+
+#include <boost/algorithm/string.hpp>
+
+//=================================================
+// VNode
+//=================================================
+
+VNode::VNode(VNode* parent,node_ptr node) :
+ VItem(parent),
+ node_(node),
+ //parent_(parent),
+#if 0
+ attrNum_(-1),
+ cachedAttrNum_(-1),
+#endif
+ index_(-1)
+{
+ if(parent_)
+ parent_->addChild(this);
+
+ if(node_)
+ node_->set_graphic_ptr(this);
+}
+
+ServerHandler* VNode::server() const
+{
+ return (parent_)?(parent_->server()):NULL;
+}
+
+VNode* VNode::suite() const
+{
+ if(isTopLevel())
+ return const_cast<VNode*>(this);
+
+ VNode* p=parent();
+ while(p)
+ {
+ if(p->isTopLevel())
+ return p;
+ p=p->parent();
+ }
+
+ assert(0);
+
+ return NULL;
+}
+
+bool VNode::isTopLevel() const
+{
+ return isSuite();
+ //return (parent_ && parent_->isServer());
+ //return (node_)?(node_->isSuite() != NULL):false;
+}
+
+void VNode::clear()
+{
+ children_.clear();
+#if 0
+ attrNum_=-1,
+ cachedAttrNum_=-1;
+#endif
+}
+
+bool VNode::hasAccessed() const
+{
+ return true; //!name_.empty();
+}
+
+#if 0
+//At the beginning of the update we get the current number of attributes
+void VNode::beginUpdateAttrNum()
+{
+ //if(attrNum_ != -1)
+ //{
+ // attrNum_=cachedAttrNum_;
+ //}
+
+ //attrNum_=VAttribute::totalNum(node_);
+}
+
+//At the end of the update we set the cached value to the current number of attributes
+void VNode::endUpdateAttrNum()
+{
+ cachedAttrNum_=attrNum_;
+ attrNum_=VAttributeType::totalNum(this);
+}
+
+short VNode::cachedAttrNum() const
+{
+ return cachedAttrNum_;
+}
+#endif
+
+int VNode::attrNum(AttributeFilter *filter) const
+{
+ return VAttributeType::totalNum(this,filter);
+
+#if 0
+ //If if was not initialised we get its value
+ if(attrNum_==-1)
+ {
+ attrNum_=VAttributeType::totalNum(this);
+
+ if(cachedAttrNum_ == -1)
+ cachedAttrNum_=attrNum_;
+ }
+
+ return attrNum_;
+#endif
+
+}
+
+#if 0
+short VNode::currentAttrNum() const
+{
+ return VAttributeType::totalNum(this);
+}
+#endif
+
+QStringList VNode::getAttributeData(int row,VAttributeType*& type)
+{
+ QStringList lst;
+ VAttributeType::getData(this,row,type,lst);
+ return lst;
+}
+
+QStringList VNode::getAttributeData(int row,AttributeFilter *filter)
+{
+ VAttributeType* type;
+ QStringList lst;
+ VAttributeType::getData(this,row,type,lst,filter);
+ return lst;
+}
+
+#if 0
+VAttributeType* VNode::getAttributeType(int row)
+{
+ return VAttributeType::getType(this,row);
+}
+#endif
+
+bool VNode::getAttributeData(const std::string& type,int row,QStringList& data)
+{
+ return VAttributeType::getData(type,this,row,data);
+}
+
+int VNode::getAttributeLineNum(int row,AttributeFilter *filter)
+{
+ return VAttributeType::getLineNum(this,row,filter);
+}
+
+QString VNode::attributeToolTip(int row,AttributeFilter *filter)
+{
+ VAttributeType* type;
+ QStringList lst;
+ VAttributeType::getData(this,row,type,lst,filter);
+ return (type)?(type->toolTip(lst)):QString();
+}
+
+void VNode::addChild(VNode* vn)
+{
+ children_.push_back(vn);
+}
+
+void VNode::removeChild(VNode* vn)
+{
+ std::vector<VNode*>::iterator it=std::find(children_.begin(),children_.end(),vn);
+ if(it != children_.end())
+ {
+ children_.erase(it);
+ }
+}
+
+VNode* VNode::childAt(int index) const
+{
+ assert(index>=0 && index < children_.size());
+ return children_[index];
+}
+
+int VNode::indexOfChild(const VNode* vn) const
+{
+ for(unsigned int i=0; i < children_.size(); i++)
+ {
+ if(children_[i] == vn)
+ return i;
+ }
+
+ return -1;
+}
+
+int VNode::indexOfChild(node_ptr n) const
+{
+ for(unsigned int i=0; i < children_.size(); i++)
+ {
+ if(children_[i]->node() == n)
+ return i;
+ }
+
+ return -1;
+}
+
+VNode *VNode::findChild(const std::string& name) const
+{
+ for(unsigned int i=0; i < children_.size(); i++)
+ {
+ if(children_[i]->sameName(name))
+ return children_.at(i);
+ }
+ return 0;
+}
+
+void VNode::collect(std::vector<VNode*>& vec) const
+{
+ for(int i=0; i < numOfChildren(); i++)
+ {
+ vec.push_back(children_.at(i));
+ children_[i]->collect(vec);
+ }
+}
+
+int VNode::tryNo() const
+{
+ std::string v=genVariable("ECF_TRYNO");
+ if(v.empty())
+ return 0;
+
+ return boost::lexical_cast<int>(v);
+}
+
+
+VNode* VNode::find(const std::vector<std::string>& pathVec)
+{
+ if(pathVec.size() == 0)
+ return this;
+
+ if(pathVec.size() == 1)
+ {
+ return findChild(pathVec.at(0));
+ }
+
+ std::vector<std::string> rest(pathVec.begin()+1,pathVec.end());
+ VNode *n = findChild(pathVec.at(0));
+
+ return n?n->find(rest):NULL;
+}
+
+std::string VNode::genVariable(const std::string& key) const
+{
+ std::string val;
+ if(node_ )
+ node_->findGenVariableValue(key,val);
+ return val;
+}
+
+std::string VNode::findVariable(const std::string& key,bool substitute) const
+{
+ std::string val;
+ if(!node_ )
+ return val;
+
+ const Variable& var=node_->findVariable(key);
+ if(!var.empty())
+ {
+ val=var.theValue();
+ if(substitute)
+ {
+ node_->variableSubsitution(val);
+ }
+ return val;
+ }
+ const Variable& gvar=node_->findGenVariable(key);
+ if(!gvar.empty())
+ {
+ val=gvar.theValue();
+ if(substitute)
+ {
+ node_->variableSubsitution(val);
+ }
+ return val;
+ }
+
+ return val;
+}
+
+std::string VNode::findInheritedVariable(const std::string& key,bool substitute) const
+{
+ std::string val;
+ if(!node_ )
+ return val;
+
+ const Variable& var=node_->findVariable(key);
+ if(!var.empty())
+ {
+ val=var.theValue();
+ if(substitute)
+ {
+ node_->variableSubsitution(val);
+ }
+ return val;
+ }
+ const Variable& gvar=node_->findGenVariable(key);
+ if(!gvar.empty())
+ {
+ val=gvar.theValue();
+ if(substitute)
+ {
+ node_->variableSubsitution(val);
+ }
+ return val;
+ }
+
+ //Try to find it in the parent
+ if(parent())
+ {
+ return parent()->findInheritedVariable(key,substitute);
+ }
+
+ return val;
+}
+
+int VNode::variablesNum() const
+{
+ if(node_.get())
+ return static_cast<int>(node_->variables().size());
+
+ return 0;
+}
+
+int VNode::genVariablesNum() const
+{
+ std::vector<Variable> gv;
+
+ if(node_)
+ {
+ node_->gen_variables(gv);
+ return static_cast<int>(gv.size());
+ }
+
+ return 0;
+}
+
+void VNode::variables(std::vector<Variable>& vars) const
+{
+ vars.clear();
+ if(node_)
+ vars=node_->variables();
+}
+
+void VNode::genVariables(std::vector<Variable>& genVars) const
+{
+ genVars.clear();
+ if(node_)
+ node_->gen_variables(genVars);
+}
+
+std::string VNode::absNodePath() const
+{
+ return (node_)?node_->absNodePath():"";
+}
+
+bool VNode::sameName(const std::string& name) const
+{
+ return(strName() == name)?true:false;
+ //return (node_)?(node_->name() == name):false;
+}
+
+std::string VNode::strName() const
+{
+ if(node_ && node_.get())
+ return node_->name();
+
+ return std::string();
+ /*
+ if(name_.empty())
+ {
+ if(node_)
+ name_=node_->name();
+ }
+ return name_;*/
+}
+
+QString VNode::name() const
+{
+ return QString::fromStdString(strName());
+ //return (node_)?QString::fromStdString(node_->name()):QString();
+}
+
+std::string VNode::serverName() const
+{
+ if(ServerHandler* s=server())
+ {
+ return s->name();
+ }
+ return std::string();
+}
+
+QString VNode::stateName()
+{
+ return VNState::toName(this);
+}
+
+bool VNode::isDefaultStateComplete()
+{
+ if(node_)
+ return (node_->defStatus() == DState::COMPLETE);
+
+ return false;
+}
+
+QString VNode::defaultStateName()
+{
+ return VNState::toDefaultStateName(this);
+}
+
+QString VNode::serverStateName()
+{
+ return QString("");
+}
+
+bool VNode::isSuspended() const
+{
+ return (node_ && node_->isSuspended());
+}
+
+bool VNode::isAborted() const
+{
+ return (node_ && node_->state() == NState::ABORTED && !node_->isSuspended());
+}
+
+bool VNode::isSubmitted() const
+{
+ return (node_ && node_->state() == NState::SUBMITTED);
+}
+
+QColor VNode::stateColour() const
+{
+ return VNState::toColour(this);
+}
+
+QColor VNode::realStateColour() const
+{
+ return VNState::toRealColour(this);
+}
+
+QColor VNode::stateFontColour() const
+{
+ return VNState::toFontColour(this);
+}
+
+QColor VNode::typeFontColour() const
+{
+ return VNState::toTypeColour(this);
+}
+
+LogServer_ptr VNode::logServer()
+{
+ LogServer_ptr lsv;
+
+ if(!node_)
+ return lsv;
+
+ std::string logHost=findInheritedVariable("ECF_LOGHOST",true);
+ std::string logPort=findInheritedVariable("ECF_LOGPORT");
+ //if(logHost.empty())
+ //{
+ // logHost=findInheritedVariable("LOGHOST",true);
+ // logPort=findInheritedVariable("LOGPORT");
+ //}
+
+ std::string micro=findInheritedVariable("ECF_MICRO");
+ if(!logHost.empty() && !logPort.empty() &&
+ (micro.empty() || logHost.find(micro) == std::string::npos))
+ {
+ lsv=LogServer_ptr(new LogServer(logHost,logPort));
+ return lsv;
+ }
+
+ return lsv;
+}
+
+bool VNode::logServer(std::string& host,std::string& port)
+{
+ if(!node_)
+ return false;
+
+ host=findInheritedVariable("ECF_LOGHOST",true);
+ port=findInheritedVariable("ECF_LOGPORT");
+ //if(logHost.empty())
+ //{
+ // logHost=findInheritedVariable("LOGHOST",true);
+ // logPort=findInheritedVariable("LOGPORT");
+ //}
+
+ std::string micro=findInheritedVariable("ECF_MICRO");
+ if(!host.empty() && !port.empty() &&
+ (micro.empty() || host.find(micro) == std::string::npos))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+
+bool VNode::isAncestor(const VNode* n)
+{
+ if(n == this)
+ return true;
+
+ VNode* nd=parent();
+ while(nd)
+ {
+ if(n == nd)
+ return true;
+
+ nd=nd->parent();
+ }
+ return false;
+}
+
+std::vector<VNode*> VNode::ancestors(SortMode sortMode)
+{
+ std::vector<VNode*> nodes;
+
+ VNode* n=this;
+
+ nodes.push_back(n);
+ n=n->parent();
+
+ if(sortMode == ChildToParentSort)
+ {
+ while(n)
+ {
+ nodes.push_back(n);
+ n=n->parent();
+ }
+ }
+
+ else if (sortMode == ParentToChildSort)
+ {
+ while(n)
+ {
+ nodes.insert(nodes.begin(),n);
+ n=n->parent();
+ }
+ }
+
+ return nodes;
+}
+
+VNode* VNode::ancestorAt(int idx,SortMode sortMode)
+{
+ if(sortMode == ChildToParentSort && idx==0)
+ return this;
+
+ std::vector<VNode*> nodes=ancestors(sortMode);
+
+ if(nodes.size() > idx)
+ {
+ return nodes.at(idx);
+ }
+
+ return NULL;
+}
+
+const std::string& VNode::nodeType()
+{
+ static std::string suiteStr("suite");
+ static std::string familyStr("family");
+ static std::string taskStr("task");
+ static std::string defaultStr("node");
+ static std::string serverStr("server");
+
+ if(isServer())
+ return serverStr;
+
+ node_ptr np=node();
+
+ if(!np || !np.get())
+ return defaultStr;
+
+ if(np->isSuite())
+ return suiteStr;
+ else if(np->isFamily())
+ return familyStr;
+ else if(np->isTask())
+ return taskStr;
+
+ return defaultStr;
+}
+
+#if 0
+bool VNode::isFamily() const
+{
+ node_ptr np=node();
+
+ if(!np || !np.get())
+ return false;
+
+ return (np->isFamily())?true:false;
+}
+
+bool VNode::isAlias() const
+{
+ node_ptr np=node();
+
+ if(!np || !np.get())
+ return false;
+
+ return (np->isAlias())?true:false;
+}
+#endif
+
+bool VNode::isFlagSet(ecf::Flag::Type f) const
+{
+ if(node_ && node_.get())
+ {
+ return node_->flag().is_set(f);
+ }
+ return false;
+}
+
+void VNode::why(std::vector<std::string>& theReasonWhy) const
+{
+ if(node_ && node_.get())
+ {
+ node_->bottom_up_why(theReasonWhy);
+ }
+}
+
+const std::string& VNode::abortedReason() const
+{
+ if(node_ && node_.get())
+ {
+ return node_->abortedReason();
+ }
+
+ static std::string emptyStr;
+ return emptyStr;
+
+}
+
+QString VNode::toolTip()
+{
+ QString txt="<b>Name</b>: " + name() + "<br>";
+ txt+="<b>Path</b>: " + QString::fromStdString(absNodePath()) + "<br>";
+ txt+="<b>Type</b>: " + QString::fromStdString(nodeType()) + "<br>";
+
+ txt+="<b>Status</b>: " + stateName();
+ if(isSuspended())
+ txt+=" (" + VNState::toRealStateName(this) + ")";
+
+ txt+="<br>";
+ txt+="<b>Default status</b>: " + defaultStateName() + "<br>";
+
+ txt+="<b>Server:</b> " + QString::fromStdString(server()->name()) + "<br>";
+ txt+="<b>Host</b>: " + QString::fromStdString(server()->host());
+ txt+=" <b>Port</b>: " + QString::fromStdString(server()->port());
+
+ QString rs=QString::fromStdString(abortedReason());
+ if(!rs.isEmpty())
+ txt+="<br><b>Aborted reason</b>:" + rs;
+
+ return txt;
+}
+
+//=================================================
+//
+// VNodeRoot - this represents the server
+//
+//=================================================
+
+VServer::VServer(ServerHandler* server) :
+ VNode(0,node_ptr()),
+ server_(server),
+ totalNum_(0)
+{
+}
+
+VServer::~VServer()
+{
+ clear();
+}
+
+
+int VServer::totalNumOfTopLevel(VNode* n) const
+{
+ if(!n->isTopLevel())
+ return -1;
+
+ int idx=indexOfChild(n);
+ if(idx != -1)
+ return totalNumOfTopLevel(idx);
+
+ return -1;
+}
+
+int VServer::totalNumOfTopLevel(int idx) const
+{
+ assert(totalNumInChild_.size() == children_.size());
+
+ if(idx >=0 && idx < totalNumInChild_.size())
+ {
+ return totalNumInChild_.at(idx);
+ }
+
+ return -1;
+}
+
+//--------------------------------
+// Clear
+//--------------------------------
+
+//Clear the whole contents
+void VServer::clear()
+{
+ if(totalNum_==0)
+ return;
+
+ cache_.clear();
+ prevNodeState_.clear();
+
+ bool hasNotifications=server_->conf()->notificationsEnabled();
+
+ //Delete the children nodes. It will recursively delete all the nodes. It also saves the prevNodeState!!
+ for(std::vector<VNode*>::const_iterator it=children_.begin(); it != children_.end(); ++it)
+ {
+ deleteNode(*it,hasNotifications);
+ }
+
+ //Clear the children vector
+ children_.clear();
+
+ totalNumInChild_.clear();
+
+ //A sanity check
+ assert(totalNum_ == 0);
+
+ //Deallocate the nodes vector
+ nodes_=std::vector<VNode*>();
+}
+
+//Clear the contents of a particular VNode
+/*void VServer::clear(VNode* node)
+{
+ //Delete the children of node. It will recursively delete all the nodes
+ //below this node
+ for(unsigned int i=0; i < node->numOfChildren(); i++)
+ {
+ deleteNode(node->childAt(i));
+ }
+
+ //Clear the node contents
+ node->clear();
+}*/
+
+//Delete a particular node
+void VServer::deleteNode(VNode* node,bool hasNotifications)
+{
+ for(unsigned int i=0; i < node->numOfChildren(); i++)
+ {
+ deleteNode(node->childAt(i),hasNotifications);
+ }
+
+ //If there are notifications we need to save previous state
+ if(hasNotifications)
+ {
+ if(node->node_->isTask())
+ {
+ VNodeInternalState st;
+ node->internalState(st);
+ prevNodeState_[node->absNodePath()]=st;
+ }
+ }
+
+ delete node;
+ totalNum_--;
+}
+
+//------------------------------------------
+// Variables
+//------------------------------------------
+
+int VServer::variablesNum() const
+{
+ return cache_.vars_.size();
+}
+
+int VServer::genVariablesNum() const
+{
+ return cache_.genVars_.size();
+}
+
+void VServer::variables(std::vector<Variable>& vars) const
+{
+ vars.clear();
+ vars=cache_.vars_;
+}
+
+void VServer::genVariables(std::vector<Variable>& vars) const
+{
+ vars.clear();
+ vars=cache_.genVars_;
+}
+
+std::string VServer::genVariable(const std::string& key) const
+{
+ std::string val;
+
+ for(std::vector<Variable>::const_iterator it=cache_.genVars_.begin(); it != cache_.genVars_.end(); ++it)
+ {
+ if((*it).name() == key)
+ val=(*it).theValue();
+ }
+
+ return val;
+}
+
+//------------------------------------------
+// Find
+//------------------------------------------
+
+VNode* VServer::toVNode(const Node* nc) const
+{
+ return static_cast<VNode*>(nc->graphic_ptr());
+}
+
+VNode* VServer::find(const std::string& fullPath)
+{
+ if(fullPath.empty())
+ return NULL;
+
+ if(fullPath == "/")
+ return this;
+
+ std::vector<std::string> pathVec;
+ boost::split(pathVec,fullPath,boost::is_any_of("/"));
+
+ if(pathVec.size() > 0 && pathVec.at(0).empty())
+ {
+ pathVec.erase(pathVec.begin());
+ }
+
+ return VNode::find(pathVec);
+}
+
+std::string VServer::findVariable(const std::string& key,bool substitute) const
+{
+ std::string val;
+
+ //Search user variables first
+ for(std::vector<Variable>::const_iterator it=cache_.vars_.begin(); it != cache_.vars_.end(); ++it)
+ {
+ if((*it).name() == key)
+ {
+ val=(*it).theValue();
+ if(substitute)
+ val=substituteVariableValue(val);
+
+ return val;
+ }
+ }
+
+ //Then search server variables
+ for(std::vector<Variable>::const_iterator it=cache_.genVars_.begin(); it != cache_.genVars_.end(); ++it)
+ {
+ if((*it).name() == key)
+ {
+ val=(*it).theValue();
+ if(substitute)
+ val=substituteVariableValue(val);
+
+ return val;
+ }
+ }
+
+ return val;
+}
+
+std::string VServer::findInheritedVariable(const std::string& key,bool substitute) const
+{
+ return findVariable(key,substitute);
+}
+
+std::string VServer::substituteVariableValue(const std::string& inVal) const
+{
+ std::string val=inVal;
+
+ if(val.empty())
+ return val;
+
+ ServerDefsAccess defsAccess(server_); // will reliquish its resources on destruction
+ defs_ptr defs = defsAccess.defs();
+ if (!defs)
+ return val;
+
+ defs->server().variableSubsitution(val);
+
+ return val;
+}
+
+//----------------------------------------------
+// Scan
+//----------------------------------------------
+
+//Clear the contents and get the number of children (suites)
+//the server contain. At this point we do not build the tree.
+void VServer::beginScan(VServerChange& change)
+{
+ //Clear the contents
+ clear();
+#if 0
+ //Get the Defs.
+ {
+ ServerDefsAccess defsAccess(server_); // will reliquish its resources on destruction
+ defs_ptr defs = defsAccess.defs();
+ if (!defs)
+ return;
+
+ const std::vector<suite_ptr> &suites = defs->suiteVec();
+ change.suiteNum_=suites.size();
+
+ std::vector<node_ptr> nv;
+ defs->get_all_nodes(nv);
+ change.totalNum_=change.suiteNum_+nv.size();
+
+ //We need to update the cache server variables
+ updateCache(defs);
+ }
+
+ //This will use ServerDefsAccess as well. So we have to be sure that t=the mutex is
+ //released at this point.
+ change.attrNum_=currentAttrNum();
+#endif
+ //Get the Defs.
+ {
+ ServerDefsAccess defsAccess(server_); // will reliquish its resources on destruction
+ defs_ptr defs = defsAccess.defs();
+ if (!defs)
+ return;
+
+ //We need to update the cache server variables
+ updateCache(defs);
+ }
+}
+
+//Build the whole tree.
+void VServer::endScan()
+{
+ totalNum_=0;
+
+ //Get the Defs
+ {
+ ServerDefsAccess defsAccess(server_); // will reliquish its resources on destruction
+ defs_ptr defs = defsAccess.defs();
+ if (!defs)
+ return;
+
+ bool hasNotifications=server_->conf()->notificationsEnabled();
+
+ //Scan the suits.This will recursively scan all nodes in the tree.
+ const std::vector<suite_ptr> &suites = defs->suiteVec();
+
+ for(unsigned int i=0; i < suites.size();i++)
+ {
+ VNode* vn=new VSuiteNode(this,suites.at(i));
+ totalNum_++;
+ scan(vn,hasNotifications);
+ }
+ }
+
+#if 0
+ //This will use ServerDefsAccess as well. So we have to be sure that the mutex is
+ //released at this point.
+ endUpdateAttrNum();
+#endif
+
+ if(totalNum_ > 0)
+ {
+ nodes_.reserve(totalNum_);
+ collect(nodes_);
+ for(size_t i=0; i < nodes_.size(); i++)
+ nodes_[i]->setIndex(i);
+ }
+}
+
+void VServer::scan(VNode *node,bool hasNotifications)
+{
+ int prevTotalNum=totalNum_;
+
+ std::vector<node_ptr> nodes;
+ node->node()->immediateChildren(nodes);
+
+ //totalNum_+=nodes.size();
+
+ //Preallocates the children vector to the reqiuired size to save memory.
+ if(nodes.size() > 0)
+ node->children_.reserve(nodes.size());
+
+ for(std::vector<node_ptr>::const_iterator it=nodes.begin(); it != nodes.end(); ++it)
+ {
+ VNode* vn=NULL;
+ if((*it)->isTask())
+ {
+ vn=new VTaskNode(node,*it);
+
+ //If there are notifications we need to check them using the previous state
+ if(hasNotifications)
+ {
+ std::string path=(*it)->absNodePath();
+ std::map<std::string,VNodeInternalState>::const_iterator itP=prevNodeState_.find(path);
+ if(itP != prevNodeState_.end())
+ vn->check(server_->conf(),itP->second);
+ }
+ }
+ else if((*it)->isFamily())
+ {
+ vn=new VFamilyNode(node,*it);
+ }
+ else if((*it)->isAlias())
+ {
+ vn=new VAliasNode(node,*it);
+ }
+ else
+ {
+ assert(0);
+
+ }
+ totalNum_++;
+ scan(vn,hasNotifications);
+ }
+
+ if(node->parent() == this)
+ {
+ totalNumInChild_.push_back(totalNum_-prevTotalNum);
+ }
+}
+
+VNode* VServer::nodeAt(int idx) const
+{
+ assert(idx>=0 && idx < nodes_.size());
+ return nodes_.at(idx);
+}
+
+//----------------------------------------------
+// Update
+//----------------------------------------------
+
+void VServer::beginUpdate(VNode* node,const std::vector<ecf::Aspect::Type>& aspect,VNodeChange& change)
+{
+ //NOTE: when this function is called the real node (Node) has already been updated. However the
+ //views do not know about this change. So at this point (this is the begin step of the update)
+ //all VNode functions have to return the values valid before the update happened!!!!!!!
+ //The main goal of this function is to cleverly provide the views with some information about the nature of the update.
+
+ //Update the generated variables. There is no notification about their change so we have to to do it!!!
+ if(node->node())
+ {
+ Suite *s=NULL;
+ s=node->node()->isSuite();
+ if(!s)
+ {
+ s=node->node()->suite();
+ }
+
+ if(s && s->begun())
+ {
+ node->node()->update_generated_variables();
+ }
+
+ if(node->nodeType() == "task")
+ {
+ bool stateCh=(std::find(aspect.begin(),aspect.end(),ecf::Aspect::STATE) != aspect.end());
+ node->check(server_->conf(),stateCh);
+ }
+ }
+#if 0
+ bool attrNumCh=(std::find(aspect.begin(),aspect.end(),ecf::Aspect::ADD_REMOVE_ATTR) != aspect.end());
+#endif
+ bool nodeNumCh=(std::find(aspect.begin(),aspect.end(),ecf::Aspect::ADD_REMOVE_NODE) != aspect.end());
+
+ //----------------------------------------------------------------------
+ // The number of attributes changed but the number of nodes did not
+ //----------------------------------------------------------------------
+
+#if 0
+ if(attrNumCh && !nodeNumCh)
+ {
+ //The attributes were never used. None of the views have ever
+ //wanted to display/access these attributes so far, so we can
+ //just ignore this update!!
+ if(!node->isAttrNumInitialised())
+ {
+ change.ignore_=true;
+ }
+ //Otherwise we just register the number of attributes before and after the update
+ else
+ {
+ node->beginUpdateAttrNum();
+
+ //This it the current number of attributes stored in the real Node. This call will not change the
+ //the number of attributes (attrNum_ stored in the VNode!!!!)
+ change.attrNum_=node->currentAttrNum();
+
+ //this is the number of attributes before the update.
+ change.cachedAttrNum_=node->cachedAttrNum();
+ }
+
+ return;
+ }
+#endif
+ //---------------------------------------------------------------------------------
+ // The number of nodes changed.
+ //---------------------------------------------------------------------------------
+ if(nodeNumCh)
+ {
+ change.rescan_=true;
+ }
+
+ //In any other cases it is just a simple update (value or status changed)
+}
+
+//-------------------------------------------------------------------------------------------
+// Finishes the update. It has to be consistent with the changes registered in VNodeChange.
+// If anything does not match we return false that will call reset!!!
+//-------------------------------------------------------------------------------------------
+
+void VServer::endUpdate(VNode* node,const std::vector<ecf::Aspect::Type>& aspect,const VNodeChange& change)
+{
+#if 0
+ bool attrNumCh=(std::find(aspect.begin(),aspect.end(),ecf::Aspect::ADD_REMOVE_ATTR) != aspect.end());
+ bool nodeNumCh=(std::find(aspect.begin(),aspect.end(),ecf::Aspect::ADD_REMOVE_NODE) != aspect.end());
+
+ //--------------------------------------------------------------
+ // The number of attributes changed but the number of nodes did not
+ //-------------------------------------------------------------
+
+ if(attrNumCh && ! nodeNumCh)
+ {
+ //This call updates the number of attributes stored in the VNode
+ node->endUpdateAttrNum();
+ }
+#endif
+}
+
+void VServer::beginUpdate(const std::vector<ecf::Aspect::Type>& aspect)
+{
+ //We need to update the cached server variables
+ if(std::find(aspect.begin(),aspect.end(),ecf::Aspect::SERVER_VARIABLE) != aspect.end() ||
+ std::find(aspect.begin(),aspect.end(),ecf::Aspect::FLAG) != aspect.end())
+ {
+ //This will use the defs!!!
+ updateCache();
+ }
+}
+
+void VServer::suites(std::vector<std::string>& sv)
+{
+ for(int i=0; i < numOfChildren(); i++)
+ {
+ sv.push_back(children_.at(i)->strName());
+ }
+}
+
+std::string VServer::strName() const
+{
+ if(server_)
+ return server_->name();
+
+ return std::string();
+
+
+ /*if(name_.empty())
+ {
+ if(server_)
+ name_=server_->name();
+ }
+ return name_;*/
+}
+
+QString VServer::stateName()
+{
+ if(VSState::isRunningState(server_))
+ {
+ return VNState::toName(server_);
+ }
+
+ return VSState::toName(server_);
+}
+
+QString VServer::defaultStateName()
+{
+ return stateName();
+}
+
+QString VServer::serverStateName()
+{
+ return VSState::toName(server_);
+}
+
+bool VServer::isSuspended() const
+{
+ return false;
+}
+
+QColor VServer::stateColour() const
+{
+ if(VSState::isRunningState(server_))
+ {
+ return VNState::toColour(server_);
+ }
+
+ return VSState::toColour(server_);
+}
+
+QColor VServer::stateFontColour() const
+{
+ if(VSState::isRunningState(server_))
+ {
+ return VNState::toFontColour(server_);
+ }
+
+ return VSState::toFontColour(server_);
+}
+
+void VServer::why(std::vector<std::string>& theReasonWhy) const
+{
+ ServerDefsAccess defsAccess(server_); // will reliquish its resources on destruction
+ defs_ptr defs = defsAccess.defs();
+ if (!defs)
+ return;
+
+ defs->why(theReasonWhy);
+}
+
+
+
+bool VServer::isFlagSet(ecf::Flag::Type f) const
+{
+ return cache_.flag_.is_set(f);
+}
+
+void VServer::updateCache()
+{
+ cache_.clear();
+
+ ServerDefsAccess defsAccess(server_); // will reliquish its resources on destruction
+ defs_ptr defs = defsAccess.defs();
+ if (!defs)
+ return;
+
+ updateCache(defs);
+}
+
+void VServer::updateCache(defs_ptr defs)
+{
+ cache_.vars_=defs->server().user_variables();
+ cache_.genVars_=defs->server().server_variables();
+ cache_.flag_=defs->flag();
+}
+
+QString VServer::toolTip()
+{
+ QString txt="<b>Server</b>: " + QString::fromStdString(server_->name()) + "<br>";
+ txt+="<b>Host</b>: " + QString::fromStdString(server_->host());
+ txt+=" <b>Port</b>: " + QString::fromStdString(server_->port()) + "<br>";
+
+ ConnectState* st=server_->connectState();
+
+ if(server_->activity() == ServerHandler::LoadActivity)
+ {
+ txt+="<b>Server is being loaded!</b><br>";
+ //txt+="<b>Started</b>: " + VFileInfo::formatDateAgo(st->lastConnectTime()) + "<br>";
+ }
+ else
+ {
+ if(st->state() == ConnectState::Normal)
+ {
+ txt+="<b>Server status</b>: " + VSState::toName(server_) + "<br>";
+ txt+="<b>Status</b>: " + VNState::toName(server_) + "<br>";
+ txt+="<b>Total number of nodes</b>: " + QString::number(totalNum_);
+ }
+ else if(st->state() == ConnectState::Lost)
+ {
+ QColor colErr(255,0,0);
+ txt+="<b><font color=" + colErr.name() +">Failed to connect to server!</b><br>";
+ txt+="<b>Last connection</b>: " + VFileInfo::formatDateAgo(st->lastConnectTime()) + "<br>";
+ txt+="<b>Last failed attempt</b>: " + VFileInfo::formatDateAgo(st->lastLostTime()) + "<br>";
+ if(!st->errorMessage().empty())
+ txt+="<b>Error message</b>:<br>" + QString::fromStdString(st->shortErrorMessage());
+ }
+ else if(st->state() == ConnectState::Disconnected)
+ {
+ QColor colErr(255,0,0);
+ txt+="<b><font color=" + colErr.name() +">Server is disconnected!</b><br>";
+ txt+="<b>Disconnected</b>: " + VFileInfo::formatDateAgo(st->lastDisconnectTime()) + "<br>";
+ }
+ }
+ return txt;
+}
diff --git a/Viewer/src/VNode.hpp b/Viewer/src/VNode.hpp
new file mode 100644
index 0000000..f1efd0a
--- /dev/null
+++ b/Viewer/src/VNode.hpp
@@ -0,0 +1,322 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VNODE_HPP_
+#define VNODE_HPP_
+
+#include <vector>
+
+#include <QColor>
+#include <QStringList>
+
+#include "Aspect.hpp"
+#include "LogServer.hpp"
+#include "Node.hpp"
+
+class AttributeFilter;
+#include "VItem.hpp"
+
+class IconFilter;
+class ServerHandler;
+class VAttributeType;
+class VServer;
+class VServerSettings;
+
+class VNodeInternalState
+{
+public:
+ VNodeInternalState() : tryNo_(0), flag_(0) {}
+
+ unsigned char tryNo_;
+ unsigned char flag_;
+};
+
+
+//Describes the major changes during an update
+class VNodeChange
+{
+public:
+ VNodeChange() : cachedAttrNum_(-1), attrNum_(-1), cachedNodeNum_(-1),
+ nodeNum_(-1), nodeAddAt_(-1), nodeRemoveAt_(-1),
+ ignore_(false), rescan_(false) {}
+ int cachedAttrNum_;
+ int attrNum_;
+ int cachedNodeNum_;
+ int nodeNum_;
+ int nodeAddAt_;
+ int nodeRemoveAt_;
+ bool ignore_;
+ bool rescan_;
+};
+
+//Describes the major changes during an update
+class VServerChange
+{
+public:
+ VServerChange() : suiteNum_(0), attrNum_(0) {} //, totalNum_(0) {}
+ int suiteNum_;
+ int attrNum_;
+ //int totalNum_;
+};
+
+class VServerCache
+{
+public:
+ std::vector<Variable> vars_;
+ std::vector<Variable> genVars_;
+ ecf::Flag flag_;
+
+ void clear() {
+ vars_.clear();
+ genVars_.clear();
+ flag_.reset();
+ }
+};
+
+class VNode : public VItem
+{
+friend class VServer;
+
+public:
+ VNode(VNode* parent,node_ptr);
+ virtual ~VNode() {}
+
+ enum SortMode {ParentToChildSort,ChildToParentSort};
+
+ virtual ServerHandler* server() const;
+ virtual VNode* suite() const;
+ node_ptr node() const {return node_;}
+
+ //VServer* isServer() const {return NULL;}
+ VNode* isNode() const {return const_cast<VNode*>(this);}
+ //VSuiteNode* isSuite() const {return NULL;}
+ //VFamilyNode* isFamily() const {return NULL;}
+ //VTaskNode* isTask() const {return NULL;}
+ //VAliasNode* isAlias() const {return NULL;}
+ //virtual VAttribute* isAttribute() const {return NULL;}
+
+ bool isTopLevel() const;
+ //bool isServer() const {return false;}
+
+ /*bool isSuite() const {return isTopLevel();}
+ bool isFamily() const;
+ bool isTask() const {return false;}
+ bool isAlias() const;*/
+
+#if 0
+ void beginUpdateAttrNum();
+ void endUpdateAttrNum();
+ short cachedAttrNum() const;
+#endif
+
+ int attrNum(AttributeFilter* filter=0) const;
+
+ QStringList getAttributeData(int,VAttributeType*&);
+ QStringList getAttributeData(int,AttributeFilter *filter=0);
+ bool getAttributeData(const std::string& type,int row, QStringList&);
+#if 0
+ VAttributeType* getAttributeType(int);
+#endif
+ int getAttributeLineNum(int row,AttributeFilter *filter=0);
+ QString attributeToolTip(int row,AttributeFilter *filter=0);
+
+ //VNode* parent() const {return parent_;}
+ int numOfChildren() const { return static_cast<int>(children_.size());}
+ VNode* childAt(int index) const;
+ int indexOfChild(const VNode* vn) const;
+ int indexOfChild(node_ptr n) const;
+ VNode* findChild(const std::string& name) const;
+ void collect(std::vector<VNode*>& vec) const;
+
+ //Get all the variables
+ virtual int variablesNum() const;
+ virtual int genVariablesNum() const;
+ virtual void variables(std::vector<Variable>& vars) const;
+ virtual void genVariables(std::vector<Variable>& genVars) const;
+
+ virtual std::string genVariable(const std::string& key) const;
+ virtual std::string findVariable(const std::string& key,bool substitute=false) const;
+
+ //Find a variable in the given node or in its ancestors. Both the variables and the
+ //generated variables are searched.
+ virtual std::string findInheritedVariable(const std::string& key,bool substitute=false) const;
+
+ virtual std::string absNodePath() const;
+ bool sameName(const std::string& name) const;
+ std::string strName() const;
+ QString name() const;
+ std::string serverName() const;
+ virtual QString stateName();
+ virtual QString serverStateName();
+ virtual QString defaultStateName();
+ virtual bool isDefaultStateComplete();
+ virtual bool isSuspended() const;
+ virtual bool isAborted() const;
+ virtual bool isSubmitted() const;
+ virtual QColor stateColour() const;
+ virtual QColor realStateColour() const;
+ virtual QColor stateFontColour() const;
+ virtual QColor typeFontColour() const;
+ virtual int tryNo() const;
+ virtual void internalState(VNodeInternalState&) {}
+
+ bool hasAccessed() const;
+ bool isAncestor(const VNode* n);
+ std::vector<VNode*> ancestors(SortMode sortMode);
+ VNode* ancestorAt(int idx,SortMode sortMode);
+
+ virtual bool isFlagSet(ecf::Flag::Type f) const;
+
+ int index() const {return index_;}
+
+ const std::string& nodeType();
+ virtual QString toolTip();
+
+ virtual void why(std::vector<std::string>& theReasonWhy) const;
+ const std::string& abortedReason() const;
+
+ LogServer_ptr logServer();
+ bool logServer(std::string& host,std::string& port);
+
+protected:
+ void clear();
+ void addChild(VNode*);
+ void removeChild(VNode*);
+#if 0
+ short currentAttrNum() const;
+ bool isAttrNumInitialised() const {return attrNum_!=-1;}
+#endif
+ VNode* find(const std::vector<std::string>& pathVec);
+ virtual void check(VServerSettings* conf,bool) {}
+ virtual void check(VServerSettings* conf,const VNodeInternalState&) {}
+ void setIndex(int i) {index_=i;}
+
+ node_ptr node_;
+ //VNode* parent_;
+ std::vector<VNode*> children_;
+#if 0
+ mutable short attrNum_;
+ mutable short cachedAttrNum_;
+#endif
+ int index_;
+};
+
+class VSuiteNode : public VNode
+{
+public:
+ VSuiteNode(VNode* parent,node_ptr node) : VNode(parent,node) {}
+ VSuiteNode* isSuite() const {return const_cast<VSuiteNode*>(this);}
+};
+
+class VFamilyNode : public VNode
+{
+public:
+ VFamilyNode(VNode* parent,node_ptr node) : VNode(parent,node) {}
+ VFamilyNode* isFamily() const {return const_cast<VFamilyNode*>(this);}
+};
+
+class VAliasNode : public VNode
+{
+public:
+ VAliasNode(VNode* parent,node_ptr node) : VNode(parent,node) {}
+ VAliasNode* isAlias() const {return const_cast<VAliasNode*>(this);}
+};
+
+//This is the root node representing the Server.
+class VServer : public VNode
+{
+ friend class ServerHandler;
+
+public:
+ explicit VServer(ServerHandler*);
+ ~VServer();
+
+ ServerHandler* server() const {return server_;}
+ VNode* suite() const {return NULL;}
+
+ bool isEmpty() const { return numOfChildren() == 0;}
+ bool isTopLevel() const {return false;}
+ VServer* isServer() const {return const_cast<VServer*>(this);}
+ VNode* isNode() const {return NULL;}
+
+ int totalNum() const {return totalNum_;}
+ int totalNumOfTopLevel(int) const;
+ int totalNumOfTopLevel(VNode*) const;
+
+ VNode* toVNode(const Node* nc) const;
+ void beginUpdate(VNode* node,const std::vector<ecf::Aspect::Type>& aspect,VNodeChange&);
+ void endUpdate(VNode* node,const std::vector<ecf::Aspect::Type>& aspect,const VNodeChange&);
+ void beginUpdate(const std::vector<ecf::Aspect::Type>& aspect);
+
+ VNode* nodeAt(int) const;
+ const std::vector<VNode*>& nodes() const {return nodes_;}
+
+ QString toolTip();
+
+ //From VNode
+ std::string absNodePath() const {return "/";}
+ QString stateName();
+ QString defaultStateName();
+ QString serverStateName();
+ bool isSuspended() const;
+ QColor stateColour() const;
+ QColor stateFontColour() const;
+ std::string strName() const;
+ int tryNo() const {return 0;}
+
+ void suites(std::vector<std::string>&);
+ VNode* find(const std::string& fullPath);
+
+ //Get all the variables
+ int variablesNum() const;
+ int genVariablesNum() const;
+ void variables(std::vector<Variable>& vars) const;
+ void genVariables(std::vector<Variable>& genVars) const;
+ std::string genVariable(const std::string& key) const;
+
+ //Find a variable in the Defs. Both the user_variables and the
+ //server variables are searched.
+ std::string findVariable(const std::string& key,bool substitute=false) const;
+ std::string findInheritedVariable(const std::string& key,bool substitute=false) const;
+
+ bool isFlagSet(ecf::Flag::Type f) const;
+
+ void why(std::vector<std::string>& theReasonWhy) const;
+
+protected:
+ //Clear contents and rebuild the whole tree.
+ void beginScan(VServerChange&);
+ void endScan();
+
+private:
+ void clear();
+ //void clear(VNode*);
+ void scan(VNode*,bool);
+ void deleteNode(VNode* node,bool);
+ std::string substituteVariableValue(const std::string& val) const;
+ void updateCache();
+ void updateCache(defs_ptr defs);
+
+ ServerHandler* server_;
+ int totalNum_;
+ std::vector<int> totalNumInChild_;
+ std::vector<VNode*> nodes_;
+
+ VServerCache cache_;
+ std::vector<Variable> prevGenVars_;
+ ecf::Flag prevFlag_;
+
+ std::map<std::string,VNodeInternalState> prevNodeState_;
+};
+
+
+
+
+#endif
diff --git a/Viewer/src/VNodeList.cpp b/Viewer/src/VNodeList.cpp
new file mode 100644
index 0000000..fea80d0
--- /dev/null
+++ b/Viewer/src/VNodeList.cpp
@@ -0,0 +1,327 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "VNodeList.hpp"
+
+#include "ServerHandler.hpp"
+#include "VNode.hpp"
+
+#include <QDateTime>
+
+//========================================================
+//
+// VNodeListItem
+//
+//========================================================
+
+VNodeListItem::VNodeListItem(VNode* n) :node_(n)
+{
+ if(n)
+ {
+ server_=n->server()->name();
+ path_=n->absNodePath();
+ time_=QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
+ }
+}
+
+bool VNodeListItem::sameAs(VNode *node) const
+{
+ if(!node) return false;
+
+ if(node_)
+ return (node_ == node);
+
+ return (server_== node->server()->name() && path_ == node->absNodePath());
+}
+
+void VNodeListItem::invalidateNode()
+{
+ node_=NULL;
+}
+
+bool VNodeListItem::updateNode(ServerHandler* s)
+{
+ if(node_)
+ return (node_->server() == s);
+ else if(s->name() == server_)
+ {
+ node_=s->vRoot()->find(path_);
+ return (node_ != NULL);
+ }
+
+ return false;
+}
+
+//========================================================
+//
+// VNodeList
+//
+//========================================================
+
+VNodeList::VNodeList(QObject *parent) :
+ QObject(parent),
+ maxNum_(200)
+{
+}
+
+VNodeList::~VNodeList()
+{
+ clear();
+}
+
+VNodeListItem* VNodeList::itemAt(int i)
+{
+ if(i >= 0 && i < data_.size())
+ return data_.at(i);
+
+ return NULL;
+}
+
+void VNodeList::setMaxNum(int maxNum)
+{
+ if(maxNum_ != maxNum)
+ {
+ assert(maxNum>0);
+ maxNum_=maxNum;
+ trim();
+ }
+}
+
+void VNodeList::add(VNode *node)
+{
+ if(contains(node))
+ return;
+
+ ServerHandler *s=node->server();
+ if(!s)
+ return;
+
+ attach(s);
+
+ Q_EMIT beginAppendRow();
+ data_.push_back(new VNodeListItem(node));
+ serverCnt_[s]++;
+ Q_EMIT endAppendRow();
+
+ trim();
+}
+
+void VNodeList::remove(VNode *node)
+{
+ if(!node)
+ return;
+
+ for(std::vector<VNodeListItem*>::iterator it=data_.begin(); it != data_.end(); it++)
+ {
+ if((*it)->sameAs(node))
+ {
+ int row=it -data_.begin();
+
+ Q_EMIT beginRemoveRow(row);
+ delete *it;
+ data_.erase(it);
+
+ detach(node);
+
+ Q_EMIT endRemoveRow(row);
+
+ return;
+ }
+ }
+}
+
+void VNodeList::trim()
+{
+ int cnt=data_.size();
+ bool doTrim=(cnt >0 && cnt > maxNum_);
+
+ if(!doTrim)
+ return;
+
+ Q_EMIT beginRemoveRows(0,cnt-maxNum_-1);
+
+ for(int row=cnt-1; row >= maxNum_; row--)
+ {
+ VNode *node=data_.front()->node();
+
+ delete data_.front();
+
+ if(node)
+ {
+ detach(node);
+ }
+
+ data_.erase(data_.begin());
+ }
+
+ Q_EMIT endRemoveRows(0,cnt-maxNum_-1);
+}
+
+bool VNodeList::contains(VNode *node)
+{
+ for(std::vector<VNodeListItem*>::const_iterator it=data_.begin(); it != data_.end(); it++)
+ {
+ if((*it)->sameAs(node))
+ return true;
+ }
+
+ return false;
+}
+
+
+void VNodeList::clear()
+{
+ Q_EMIT beginReset();
+
+ for(std::map<ServerHandler*,int>::const_iterator it=serverCnt_.begin(); it != serverCnt_.end(); it++)
+ {
+ it->first->removeServerObserver(this);
+ it->first->removeNodeObserver(this);
+ }
+ serverCnt_.clear();
+
+ for(std::vector<VNodeListItem*>::const_iterator it=data_.begin(); it != data_.end(); it++)
+ {
+ delete *it;
+ }
+
+ data_.clear();
+
+ Q_EMIT endReset();
+}
+
+void VNodeList::clear(ServerHandler* server)
+{
+ std::vector<VNodeListItem*> prev=data_;
+ data_.clear();
+
+ detach(server);
+
+ for(std::vector<VNodeListItem*>::const_iterator it=prev.begin(); it != prev.end(); ++it)
+ {
+ ServerHandler *s=(*it)->node_->server();
+ if((*it)->server() == s->name())
+ {
+ delete *it;
+ }
+ else
+ {
+ data_.push_back(*it);
+ }
+ }
+}
+
+void VNodeList::serverClear(ServerHandler* server)
+{
+ for(std::vector<VNodeListItem*>::const_iterator it=data_.begin(); it != data_.end(); ++it)
+ {
+ if(server->name() == (*it)->server())
+ {
+ (*it)->invalidateNode();
+ }
+ }
+}
+
+void VNodeList::serverScan(ServerHandler* server)
+{
+ std::vector<VNodeListItem*> prev=data_;
+ data_.clear();
+
+ serverCnt_[server]=0;
+
+ for(std::vector<VNodeListItem*>::const_iterator it=prev.begin(); it != prev.end(); ++it)
+ {
+ if(server->name() == (*it)->server())
+ {
+ if((*it)->updateNode(server))
+ {
+ data_.push_back(*it);
+ serverCnt_[server]++;
+ }
+ else
+ delete *it;
+ }
+ }
+
+ if(serverCnt_[server] == 0)
+ detach(server);
+}
+
+
+void VNodeList::attach(ServerHandler *s)
+{
+ if(serverCnt_.find(s) == serverCnt_.end())
+ {
+ s->addServerObserver(this);
+ s->addNodeObserver(this);
+ serverCnt_[s]=0;
+ }
+}
+
+void VNodeList::detach(ServerHandler* s)
+{
+ std::map<ServerHandler*,int>::iterator it=serverCnt_.find(s);
+ if(it != serverCnt_.end())
+ {
+ serverCnt_.erase(it);
+ s->removeServerObserver(this);
+ s->removeNodeObserver(this);
+ }
+}
+
+void VNodeList::detach(VNode *node)
+{
+ std::map<ServerHandler*,int>::iterator it=serverCnt_.find(node->server());
+ if(it != serverCnt_.end())
+ {
+ it->second--;
+ if(it->second == 0)
+ {
+ detach(node->server());
+ }
+ }
+}
+
+void VNodeList::notifyServerDelete(ServerHandler* server)
+{
+ Q_EMIT beginReset();
+ clear(server);
+ Q_EMIT endReset();
+}
+
+void VNodeList::notifyBeginServerClear(ServerHandler* server)
+{
+ serverClear(server);
+}
+
+void VNodeList::notifyEndServerClear(ServerHandler* server)
+{
+}
+
+void VNodeList::notifyBeginServerScan(ServerHandler* server,const VServerChange&)
+{
+ Q_EMIT beginReset();
+}
+
+void VNodeList::notifyEndServerScan(ServerHandler* server)
+{
+ serverScan(server);
+ Q_EMIT endReset();
+}
+
+
+void VNodeList::notifyBeginNodeChange(const VNode*, const std::vector<ecf::Aspect::Type>&,const VNodeChange&)
+{
+
+}
+
+void VNodeList::notifyEndNodeChange(const VNode*, const std::vector<ecf::Aspect::Type>&,const VNodeChange&)
+{
+}
diff --git a/Viewer/src/VNodeList.hpp b/Viewer/src/VNodeList.hpp
new file mode 100644
index 0000000..cb96667
--- /dev/null
+++ b/Viewer/src/VNodeList.hpp
@@ -0,0 +1,98 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VIEWER_SRC_VNODELIST_HPP_
+#define VIEWER_SRC_VNODELIST_HPP_
+
+#include "ServerObserver.hpp"
+#include "NodeObserver.hpp"
+
+#include <QObject>
+
+#include <map>
+#include <vector>
+
+class VNodeList;
+
+class VNodeListItem
+{
+friend class VNodeList;
+
+public:
+ explicit VNodeListItem(VNode* n);
+ VNode *node() const {return node_;}
+ const std::string& server() const {return server_;}
+ const std::string& path() const {return path_;}
+ QString time() const {return time_;}
+ bool sameAs(VNode *node) const;
+ void invalidateNode();
+ bool updateNode(ServerHandler*);
+
+protected:
+ VNode* node_;
+ std::string server_;
+ std::string path_;
+ QString time_;
+};
+
+class VNodeList : public QObject, public ServerObserver, public NodeObserver
+{
+ Q_OBJECT
+
+public:
+ explicit VNodeList(QObject* parent=0);
+ ~VNodeList();
+
+ int size() const {return data_.size();}
+ VNodeListItem* itemAt(int i);
+ void add(VNode*);
+ void remove(VNode*);
+ void clear();
+ bool contains(VNode*);
+ void setMaxNum(int);
+
+ //From ServerObserver
+ void notifyDefsChanged(ServerHandler* server, const std::vector<ecf::Aspect::Type>& a) {}
+ void notifyServerDelete(ServerHandler* server);
+ void notifyBeginServerClear(ServerHandler* server);
+ void notifyEndServerClear(ServerHandler* server);
+ void notifyBeginServerScan(ServerHandler* server,const VServerChange&);
+ void notifyEndServerScan(ServerHandler* server);
+
+ //From NodeObserver
+ void notifyBeginNodeChange(const VNode*, const std::vector<ecf::Aspect::Type>&,const VNodeChange&);
+ void notifyEndNodeChange(const VNode*, const std::vector<ecf::Aspect::Type>&,const VNodeChange&);
+
+Q_SIGNALS:
+ void beginAppendRow();
+ void endAppendRow();
+ void beginRemoveRow(int);
+ void endRemoveRow(int);
+ void beginRemoveRows(int,int);
+ void endRemoveRows(int,int);
+ void beginReset();
+ void endReset();
+
+protected:
+ void clearData(bool hideOnly);
+ void clear(ServerHandler*);
+ void serverClear(ServerHandler*);
+ void serverScan(ServerHandler*);
+ void attach(ServerHandler*);
+ void detach(ServerHandler*);
+ void detach(VNode*);
+ void trim();
+
+ std::vector<VNodeListItem*> data_;
+ std::map<ServerHandler*,int> serverCnt_;
+ int maxNum_;
+};
+
+#endif /* VIEWER_SRC_VNODELIST_HPP_ */
diff --git a/Viewer/src/VParam.cpp b/Viewer/src/VParam.cpp
new file mode 100644
index 0000000..1e8247c
--- /dev/null
+++ b/Viewer/src/VParam.cpp
@@ -0,0 +1,235 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "VParam.hpp"
+
+#include <QDebug>
+
+#include "VProperty.hpp"
+
+VParam::VParam(const std::string& name) :
+ name_(name),
+ qName_(QString::fromStdString(name)),
+ prop_(0),
+ colourPropName_("fill_colour"),
+ fontColourPropName_("font_colour"),
+ typeColourPropName_("type_colour")
+{
+}
+
+VParam::~VParam()
+{
+ if(prop_)
+ prop_->removeObserver(this);
+}
+
+void VParam::setProperty(VProperty* prop)
+{
+ prop_=prop;
+
+ label_=prop->param("label");
+
+ if(!colourPropName_.isEmpty())
+ {
+ if(VProperty* p=prop->findChild(colourPropName_))
+ {
+ p->addObserver(this);
+ colour_=p->value().value<QColor>();
+ }
+ }
+
+ if(!fontColourPropName_.isEmpty())
+ {
+ if(VProperty* p=prop->findChild(fontColourPropName_))
+ {
+ p->addObserver(this);
+ fontColour_=p->value().value<QColor>();
+ }
+ }
+ if(!typeColourPropName_.isEmpty())
+ {
+ if(VProperty* p=prop->findChild(typeColourPropName_))
+ {
+ p->addObserver(this);
+ typeColour_=p->value().value<QColor>();
+ }
+ }
+}
+
+void VParam::notifyChange(VProperty* prop)
+{
+ if(prop->name() == colourPropName_)
+ colour_=prop->value().value<QColor>();
+
+ else if(prop->name() == fontColourPropName_)
+ fontColour_=prop->value().value<QColor>();
+
+ else if(prop->name() == typeColourPropName_)
+ typeColour_=prop->value().value<QColor>();
+}
+
+/*
+void VParam::addAttributes(const std::map<std::string,std::string>& attr)
+{
+ for(std::map<std::string,std::string>::const_iterator it=attr.begin(); it != attr.end(); it++)
+ {
+ std::string key=it->first;
+ std::string val=it->second;
+ if(isColour(val))
+ {
+ colourMap_[key]=toColour(val);
+ }
+ else if(isFont(val))
+ {
+ fontMap_[key]=toFont(val);
+ }
+ else if(isNumber(val))
+ {
+ numberMap_[key]=1;
+ }
+
+ textMap_[key]=val;
+ }
+}
+
+std::string VParam::text(const std::string& key) const
+{
+ std::map<std::string,std::string>::const_iterator it=textMap_.find(key);
+ if(it != textMap_.end())
+ return it->second;
+
+ return std::string();
+}
+
+QColor VParam::colour(const std::string& key) const
+{
+ std::map<std::string,QColor>::const_iterator it=colourMap_.find(key);
+ if(it != colourMap_.end())
+ return it->second;
+
+ return QColor();
+}
+
+int VParam::number(const std::string& key) const
+{
+ std::map<std::string,int>::const_iterator it=numberMap_.find(key);
+ if(it != numberMap_.end())
+ return it->second;
+
+ return -1;
+}
+
+QFont VParam::font(const std::string& key) const
+{
+ std::map<std::string,QFont>::const_iterator it=fontMap_.find(key);
+ if(it != fontMap_.end())
+ return it->second;
+
+ return QFont();
+}
+
+bool VParam::isColour(const std::string& val)
+{
+ return QString::fromStdString(val).simplified().startsWith("rgb");
+}
+
+bool VParam::isFont(const std::string& val)
+{
+ return QString::fromStdString(val).simplified().startsWith("font");
+}
+
+bool VParam::isNumber(const std::string& val)
+{
+ return false;
+}
+
+QColor VParam::toColour(const std::string& name)
+{
+ QString qn=QString::fromStdString(name);
+ qDebug() << qn;
+ QColor col;
+ QRegExp rx("rgb\\((\\d+),(\\d+),(\\d+)");
+
+ if(rx.indexIn(qn) > -1 && rx.captureCount() == 3)
+ {
+ col=QColor(rx.cap(1).toInt(),
+ rx.cap(2).toInt(),
+ rx.cap(3).toInt());
+
+ }
+
+ qDebug() << col;
+
+ return col;
+}
+
+QFont VParam::toFont(const std::string& name)
+{
+ return QFont();
+}
+
+int VParam::toNumber(const std::string& name)
+{
+ return 0;
+}
+
+
+void VParam::init(const std::string& parFile,const std::string id,std::map<std::string,std::map<std::string,std::string> >& vals)
+{
+ //Parse param file using the boost JSON property tree parser
+ using boost::property_tree::ptree;
+ ptree pt;
+
+ try
+ {
+ read_json(parFile,pt);
+ }
+ catch (const boost::property_tree::json_parser::json_parser_error& e)
+ {
+ std::string errorMessage = e.what();
+ UserMessage::message(UserMessage::ERROR, true, std::string("Error, unable to parse JSON attributes file : " + errorMessage));
+ return;
+ }
+
+ ptree::const_iterator itTop = pt.begin();
+ if(itTop == pt.end() || itTop->first != id)
+ {
+ return;
+ }
+
+ //For each parameter
+ for(ptree::const_iterator itPar = itTop->second.begin(); itPar != itTop->second.end(); ++itPar)
+ {
+ std::string name=itPar->first;
+ ptree const &parPt = itPar->second;
+
+ //std::map<QString,QString> vals;
+ for(ptree::const_iterator itV = parPt.begin(); itV != parPt.end(); ++itV)
+ {
+ vals[name].insert(make_pair(itV->first,itV->second.get_value<std::string>()));
+ }
+ }
+}
+*/
+
+/*QStringList VParam::toList(const boost::property_tree::ptree& array)
+{
+ QStringList lst;
+ for(boost::property_tree::ptree::const_iterator it = array.begin(); it != array.end(); ++it)
+ {
+ std::string name=it->second.get_value<std::string>();
+ lst << QString::fromStdString(name);
+ }
+
+ return lst;
+}
+*/
+
+
diff --git a/Viewer/src/VParam.hpp b/Viewer/src/VParam.hpp
new file mode 100644
index 0000000..f5eb3b7
--- /dev/null
+++ b/Viewer/src/VParam.hpp
@@ -0,0 +1,73 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VPARAM_HPP_
+#define VPARAM_HPP_
+
+#include <QColor>
+
+#include "VProperty.hpp"
+
+class VParam : public VPropertyObserver
+{
+public:
+ explicit VParam(const std::string& name);
+ ~VParam();
+
+ QString name() const {return qName_;}
+ const std::string& strName() const {return name_;}
+
+ QString label() const {return label_;}
+ QColor colour() const {return colour_;}
+ QColor fontColour() const {return fontColour_;}
+ QColor typeColour() const {return typeColour_;}
+
+ void setProperty(VProperty*);
+
+ void notifyChange(VProperty*);
+
+ /*
+ int number(const std::string&) const;
+ QColor colour(const std::string&) const;
+ std::string text(const std::string&) const;
+ QFont font(const std::string&) const;
+
+ static QColor toColour(const std::string&) ;
+ static QFont toFont(const std::string&);
+ static int toNumber(const std::string&);
+ static bool isColour(const std::string&);
+ static bool isFont(const std::string&);
+ static bool isNumber(const std::string&);*/
+
+protected:
+ //void addAttributes(const std::map<std::string,std::string>& attr);
+ //static void init(const std::string& parFile,const std::string id,std::map<std::string,std::map<std::string,std::string> >& vals);
+
+ std::string name_;
+ QString qName_;
+ QString label_;
+
+ //Cached information
+ QColor colour_;
+ QColor fontColour_;
+ QColor typeColour_;
+
+ /*std::map<std::string,int> numberMap_;
+ std::map<std::string,std::string> textMap_;
+ std::map<std::string,QColor> colourMap_;
+ std::map<std::string,QFont> fontMap_;*/
+
+ VProperty* prop_;
+ QString colourPropName_;
+ QString fontColourPropName_;
+ QString typeColourPropName_;
+};
+
+#endif
diff --git a/Viewer/src/VProperty.cpp b/Viewer/src/VProperty.cpp
new file mode 100644
index 0000000..482781f
--- /dev/null
+++ b/Viewer/src/VProperty.cpp
@@ -0,0 +1,530 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "VProperty.hpp"
+
+#include <QDebug>
+#include <QRegExp>
+
+#include "Sound.hpp"
+#include "UserMessage.hpp"
+
+#include <boost/algorithm/string.hpp>
+
+
+VProperty::VProperty(const std::string& name) :
+ strName_(name),
+ name_(QString::fromStdString(name)),
+ parent_(0),
+ master_(0),
+ useMaster_(false),
+ type_(StringType),
+ guiType_(StringGui),
+ link_(0)
+{
+}
+
+VProperty::~VProperty()
+{
+ Q_FOREACH(VProperty *p,children_)
+ {
+ delete p;
+ }
+
+ children_.clear();
+
+ if(master_)
+ master_->removeObserver(this);
+}
+
+QVariant VProperty::value() const
+{
+ if(master_ && useMaster_)
+ return master_->value();
+
+ return value_;
+}
+
+
+void VProperty::setDefaultValue(const std::string& val)
+{
+ //Colour
+ if(isColour(val))
+ {
+ defaultValue_=toColour(val);
+ type_=ColourType;
+ guiType_=ColourGui;
+ }
+ //Font
+ else if(isFont(val))
+ {
+ defaultValue_=toFont(val);
+ type_=FontType;
+ guiType_=FontGui;
+ }
+ //Sound
+ else if(isSound(val))
+ {
+ defaultValue_=QString::fromStdString(val);
+ type_=SoundType;
+ guiType_=SoundGui;
+ }
+ //int
+ else if(isNumber(val))
+ {
+ defaultValue_=toNumber(val);
+ type_=IntType;
+ guiType_=IntGui;
+ }
+ //bool
+ else if(isBool(val))
+ {
+ defaultValue_=toBool(val);
+ type_=BoolType;
+ guiType_=BoolGui;
+ }
+ //text
+ else
+ {
+ defaultValue_=QString::fromStdString(val);
+ type_=StringType;
+ guiType_=StringGui;
+ }
+
+ if(value_.isNull())
+ value_=defaultValue_;
+
+ //qDebug() << "Prop:" << name_ << defaultValue_ << value_.value<QColor>();
+}
+
+void VProperty::setValue(const std::string& val)
+{
+ if(master_ && useMaster_)
+ return;
+
+ bool changed=false;
+
+ if(isColour(val))
+ {
+ QColor col=toColour(val);
+ changed=(value_.value<QColor>() != col);
+ value_=col;
+ }
+ else if(isFont(val))
+ {
+ QFont font=toFont(val);
+ changed=(value_.value<QFont>() != font);
+ value_=font;
+ }
+
+ else if(isNumber(val))
+ {
+ int num=toNumber(val);
+ changed=(value_.toInt() != num);
+ value_=num;
+ }
+ else if(isBool(val))
+ {
+ bool b=toBool(val);
+ changed=(value_.toBool() != b);
+ value_=b;
+ }
+ //Sound or string
+ else
+ {
+ QString str=QString::fromStdString(val);
+ changed=(value_ != str);
+ value_=str;
+ }
+
+ if(!defaultValue_.isNull() &&
+ defaultValue_.type() != value_.type())
+ {
+ changed=true;
+ value_=defaultValue_;
+ //An error message should be shown!
+ }
+
+ if(changed)
+ dispatchChange();
+}
+
+void VProperty::setValue(QVariant val)
+{
+ if(master_ && useMaster_)
+ return;
+
+ if(!defaultValue_.isNull() &&
+ defaultValue_.type() != val.type())
+ {
+ return;
+ }
+
+ bool changed=(value_ != val);
+
+ value_=val;
+
+ if(changed)
+ dispatchChange();
+}
+
+std::string VProperty::valueAsString() const
+{
+ QString s;
+
+ switch(type_)
+ {
+ case StringType:
+ s=value().toString();
+ break;
+ case IntType:
+ s=QString::number(value_.toInt());
+ break;
+ case BoolType:
+ s=(value().toBool() == true)?"true":"false";
+ break;
+ case ColourType:
+ s=VProperty::toString(value().value<QColor>());
+ break;
+ case FontType:
+ s=VProperty::toString(value().value<QFont>());
+ break;
+ case SoundType:
+ s=value().toString();
+ break;
+ default:
+ break;
+
+ }
+
+ return s.toStdString();
+}
+
+void VProperty::setParam(QString name,QString value)
+{
+ /*if(name == "values")
+ {
+ if(type_ == SoundType)
+ guiType_=SoundComboGui;
+ else
+ guiType_=StringComboGui;
+ }
+
+ if(name == "multi" && value == "true")
+ {
+ if(type_ == StringType || guiType_ == StringComboGui)
+ guiType_ == MultiStringComboGui;
+ }*/
+
+ params_[name]=value;
+}
+
+QString VProperty::param(QString name)
+{
+ QMap<QString,QString>::const_iterator it=params_.find(name);
+ if(it != params_.end())
+ return it.value();
+
+ return QString();
+}
+
+void VProperty::adjustAfterLoad()
+{
+ QString vals=param("values");
+ QString multi=param("multi");
+
+ if(!vals.isEmpty())
+ {
+ if(type_ == SoundType)
+ guiType_=SoundComboGui;
+ else
+ {
+ if(multi == "true")
+ {
+ guiType_ = MultiStringComboGui;
+ }
+ else
+ {
+ guiType_=StringComboGui;
+ }
+ }
+ }
+}
+
+
+void VProperty::addChild(VProperty *prop)
+{
+ children_ << prop;
+ prop->setParent(this);
+}
+
+void VProperty::addObserver(VPropertyObserver* obs)
+{
+ observers_ << obs;
+}
+
+void VProperty::removeObserver(VPropertyObserver* obs)
+{
+ observers_.removeAll(obs);
+}
+
+void VProperty::dispatchChange()
+{
+ Q_FOREACH(VPropertyObserver* obs,observers_)
+ {
+ obs->notifyChange(this);
+ }
+}
+
+VProperty* VProperty::findChild(QString name)
+{
+ Q_FOREACH(VProperty* p,children_)
+ {
+ if(p->name() == name)
+ return p;
+ }
+
+ return 0;
+}
+
+VProperty* VProperty::find(const std::string& fullPath)
+{
+ if(fullPath.empty())
+ return NULL;
+
+ if(fullPath == strName_)
+ return this;
+
+ std::vector<std::string> pathVec;
+ boost::split(pathVec,fullPath,boost::is_any_of("."));
+
+ if(pathVec.size() > 0)
+ {
+ if(pathVec.at(0) != strName_)
+ return NULL;
+ }
+
+ return VProperty::find(pathVec);
+}
+
+VProperty* VProperty::find(const std::vector<std::string>& pathVec)
+{
+ if(pathVec.size() == 0)
+ {
+ return NULL;
+ }
+
+ if(pathVec.size() == 1)
+ {
+ return this;
+ }
+
+ //The vec size >=2
+
+ std::vector<std::string> rest(pathVec.begin()+1,pathVec.end());
+ VProperty *n = findChild(QString::fromStdString(pathVec.at(1)));
+
+ return n?n->find(rest):NULL;
+}
+
+void VProperty::collectChildren(std::vector<VProperty*>& chVec) const
+{
+ Q_FOREACH(VProperty* p,children_)
+ {
+ chVec.push_back(p);
+ p->collectChildren(chVec);
+ }
+}
+
+bool VProperty:: changed() const
+{
+ return value() != defaultValue_;
+}
+
+void VProperty::collectLinks(std::vector<VProperty*>& linkVec)
+{
+ if(link_)
+ linkVec.push_back(link_);
+
+ Q_FOREACH(VProperty* p,children_)
+ {
+ p->collectLinks(linkVec);
+ }
+}
+
+std::string VProperty::path()
+{
+ if(parent_)
+ return parent_->path() + "." + strName_;
+
+ return strName_;
+}
+
+void VProperty::setMaster(VProperty* m,bool useMaster)
+{
+ if(master_)
+ master_->removeObserver(this);
+
+ master_=m;
+ master_->addObserver(this);
+
+ setUseMaster(useMaster);
+}
+
+void VProperty::setUseMaster(bool b)
+{
+ assert(master_);
+
+ if(useMaster_ != b)
+ {
+ useMaster_=b;
+
+ if(useMaster_)
+ {
+ value_=master_->value_;
+ }
+ }
+}
+
+VProperty* VProperty::clone(bool addLink,bool setMaster,bool useMaster)
+{
+ VProperty *cp=new VProperty(strName_);
+
+ cp->value_=value_;
+ cp->defaultValue_=defaultValue_;
+ cp->type_=type_;
+ cp->guiType_=guiType_;
+
+ if(addLink)
+ {
+ cp->link_=link_;
+ }
+
+ cp->params_=params_;
+
+ if(setMaster)
+ {
+ cp->setMaster(this,useMaster);
+ }
+
+ Q_FOREACH(VProperty* p,children_)
+ {
+ VProperty *ch=p->clone(addLink,setMaster,useMaster);
+ cp->addChild(ch);
+ }
+
+ return cp;
+}
+
+void VProperty::notifyChange(VProperty* p)
+{
+ if(master_ && p== master_ && useMaster_)
+ {
+ value_=master_->value_;
+ dispatchChange();
+ }
+}
+
+//=============================
+//
+// Static methods
+//
+//=============================
+
+bool VProperty::isColour(const std::string& val)
+{
+ return QString::fromStdString(val).simplified().startsWith("rgb(");
+}
+
+bool VProperty::isFont(const std::string& val)
+{
+ return QString::fromStdString(val).simplified().startsWith("font(");
+}
+
+bool VProperty::isSound(const std::string& val)
+{
+ return Sound::instance()->isSoundFile(val);
+}
+
+bool VProperty::isNumber(const std::string& val)
+{
+ QString str=QString::fromStdString(val);
+ QRegExp re("\\d*");
+ return (re.exactMatch(str));
+}
+
+bool VProperty::isBool(const std::string& val)
+{
+ return (val == "true" || val == "false");
+}
+
+QColor VProperty::toColour(const std::string& name)
+{
+ QString qn=QString::fromStdString(name);
+ QColor col;
+ QRegExp rx("rgb\\((\\d+),(\\d+),(\\d+)");
+
+ if(rx.indexIn(qn) > -1 && rx.captureCount() == 3)
+ {
+ col=QColor(rx.cap(1).toInt(),
+ rx.cap(2).toInt(),
+ rx.cap(3).toInt());
+
+ }
+ return col;
+}
+
+QFont VProperty::toFont(const std::string& name)
+{
+ QString qn=QString::fromStdString(name);
+ QFont f;
+ QRegExp rx("font\\((.*),(.*)\\)");
+ if(rx.indexIn(qn) > -1 && rx.captureCount() == 2)
+ {
+ QString family=rx.cap(1);
+ int size=rx.cap(2).toInt();
+
+ if(!family.isEmpty())
+ f.setFamily(family);
+
+ if(size >=1 && size < 200)
+ f.setPointSize(size);
+
+ //qDebug() << family << size
+ //f.fromString(rx.cap(1));
+ }
+
+ return f;
+}
+
+int VProperty::toNumber(const std::string& name)
+{
+ QString qn=QString::fromStdString(name);
+ return qn.toInt();
+}
+
+bool VProperty::toBool(const std::string& name)
+{
+ return (name == "true")?true:false;
+}
+
+QString VProperty::toString(QColor col)
+{
+ return "rgb(" + QString::number(col.red()) + "," +
+ QString::number(col.green()) + "," +
+ QString::number(col.blue()) + ")";
+}
+
+QString VProperty::toString(QFont f)
+{
+ return "font(" + f.family() +"," + QString::number(f.pointSize()) + ")";
+}
+
+
diff --git a/Viewer/src/VProperty.hpp b/Viewer/src/VProperty.hpp
new file mode 100644
index 0000000..ff53972
--- /dev/null
+++ b/Viewer/src/VProperty.hpp
@@ -0,0 +1,136 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VPROPERTY_HPP_
+#define VPROPERTY_HPP_
+
+#include <QColor>
+#include <QFont>
+#include <QList>
+#include <QVariant>
+
+#include <vector>
+
+class VProperty;
+
+class VPropertyObserver
+{
+public:
+ VPropertyObserver() {}
+ virtual ~VPropertyObserver() {}
+
+ virtual void notifyChange(VProperty*)=0;
+};
+
+class VPropertyVisitor
+{
+public:
+ VPropertyVisitor() {};
+ virtual ~VPropertyVisitor() {};
+ virtual void visit(VProperty*)=0;
+};
+
+
+
+//This class defines a property storing its value as a QVariant.
+//Properties are used to store the viewer's configuration. Editable properties
+//store all the information needed to display them in a property editor.
+//Properties can have children so trees can be built up from them.
+
+class VProperty : public VPropertyObserver
+{
+public:
+ explicit VProperty(const std::string& name);
+ ~VProperty();
+
+ enum Type {StringType,IntType,BoolType,ColourType,FontType,SoundType};
+
+ enum GuiType {StringGui,IntGui,BoolGui,ColourGui,FontGui,SoundGui,
+ StringComboGui,MultiStringComboGui,SoundComboGui};
+
+ QString name() const {return name_;}
+ const std::string& strName() const {return strName_;}
+ QVariant defaultValue() const {return defaultValue_;}
+ QVariant value() const;
+ std::string valueAsString() const;
+ Type type() const {return type_;}
+ GuiType guiType() const {return guiType_;}
+ QString param(QString name);
+ QColor paramToColour(QString name) {return toColour(param(name).toStdString()) ;}
+
+ void setDefaultValue(const std::string&);
+ void setValue(const std::string&);
+ void setValue(QVariant);
+ void setParam(QString,QString);
+ void adjustAfterLoad();
+
+ std::string path();
+ VProperty* parent() const {return parent_;}
+ void setParent(VProperty* p) {parent_=p;}
+ bool hasChildren() const {return children_.count() >0;}
+ QList<VProperty*> children() const {return children_;}
+ void addChild(VProperty*);
+ VProperty* findChild(QString name);
+ VProperty* find(const std::string& fullPath);
+ void collectChildren(std::vector<VProperty*>&) const;
+
+ bool changed() const;
+ void collectLinks(std::vector<VProperty*>&);
+
+ void setLink(VProperty* p) {link_=p;}
+ VProperty* link() const {return link_;}
+
+ void setMaster(VProperty*,bool useMaster=false);
+ VProperty* master() const {return master_;}
+ void setUseMaster(bool);
+ bool useMaster() const {return useMaster_;}
+ VProperty *clone(bool addLink,bool setMaster,bool useMaster=false);
+
+ void addObserver(VPropertyObserver*);
+ void removeObserver(VPropertyObserver*);
+
+ void notifyChange(VProperty*);
+
+ static bool isColour(const std::string&);
+ static bool isFont(const std::string&);
+ static bool isSound(const std::string&);
+ static bool isNumber(const std::string&);
+ static bool isBool(const std::string&);
+
+ static QColor toColour(const std::string&) ;
+ static QFont toFont(const std::string&);
+ static int toNumber(const std::string&);
+ static bool toBool(const std::string&);
+
+ static QString toString(QColor col);
+ static QString toString(QFont f);
+
+private:
+ void dispatchChange();
+ VProperty* find(const std::vector<std::string>& pathVec);
+
+ std::string strName_; //The name of the property as an std::string
+ QString name_; //The name of the property. Used as an id.
+ QVariant defaultValue_; //The default value
+ QVariant value_; //The current value
+
+ VProperty* parent_;
+ QList<VProperty*> children_;
+ QList<VPropertyObserver*> observers_;
+ VProperty* master_;
+ bool useMaster_;
+ Type type_;
+ GuiType guiType_;
+ QMap<QString,QString> params_;
+ VProperty* link_;
+};
+
+
+#endif
diff --git a/Viewer/src/VRepeat.cpp b/Viewer/src/VRepeat.cpp
new file mode 100644
index 0000000..c863837
--- /dev/null
+++ b/Viewer/src/VRepeat.cpp
@@ -0,0 +1,215 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "VRepeat.hpp"
+
+#include <sstream>
+#include "RepeatAttr.hpp"
+#include "VNode.hpp"
+
+std::map<std::string,std::string> VRepeat::typeNames_;
+
+static long ecf_repeat_date_to_julian(long ddate);
+static long ecf_repeat_julian_to_date(long jdate);
+
+long ecf_repeat_julian_to_date(long jdate)
+{
+ long x,y,d,m,e;
+ long day,month,year;
+
+ x = 4 * jdate - 6884477;
+ y = (x / 146097) * 100;
+ e = x % 146097;
+ d = e / 4;
+
+ x = 4 * d + 3;
+ y = (x / 1461) + y;
+ e = x % 1461;
+ d = e / 4 + 1;
+
+ x = 5 * d - 3;
+ m = x / 153 + 1;
+ e = x % 153;
+ d = e / 5 + 1;
+
+ if( m < 11 )
+ month = m + 2;
+ else
+ month = m - 10;
+
+
+ day = d;
+ year = y + m / 11;
+
+ return year * 10000 + month * 100 + day;
+}
+
+long ecf_repeat_date_to_julian(long ddate)
+{
+ long m1,y1,a,b,c,d,j1;
+
+ long month,day,year;
+
+ year = ddate / 10000;
+ ddate %= 10000;
+ month = ddate / 100;
+ ddate %= 100;
+ day = ddate;
+
+ if (0) {
+ a = (14 - month) / 12;
+ y1 = year + 4800 - a;
+ m1 = month + 12*a - 3;
+ j1 = day + (153*m1 + 2)/5 + 365*y1 + y1/4 - y1/100 + y1/400 - 32045;
+ return j1 - 0.5;
+ }
+
+ if (month > 2)
+ {
+ m1 = month - 3;
+ y1 = year;
+ }
+ else
+ {
+ m1 = month + 9;
+ y1 = year - 1;
+ }
+ a = 146097*(y1/100)/4;
+ d = y1 % 100;
+ b = 1461*d/4;
+ c = (153*m1+2)/5+day+1721119;
+ j1 = a+b+c;
+
+ return j1;
+}
+
+const std::string& VRepeat::type(const Repeat& r)
+{
+ if(typeNames_.empty())
+ {
+ typeNames_["repeat date"]="date";
+ typeNames_["repeat integer"]="integer";
+ typeNames_["repeat string"]="string";
+ typeNames_["repeat enumerated"]="enumerated";
+ typeNames_["repeat day"]="day";
+ }
+
+ static std::string noTypeName="";
+
+ std::string t=r.toString();
+ for(std::map<std::string,std::string>::const_iterator it=typeNames_.begin(); it != typeNames_.end(); ++it)
+ {
+ if(t.find(it->first) == 0)
+ return it->second;
+ }
+
+ return noTypeName;
+}
+
+const std::string& VRepeat::type(VNode* n)
+{
+ if(n && n->node())
+ {
+ return VRepeat::type(n->node()->repeat());
+ }
+ static std::string noTypeName="";
+ return noTypeName;
+}
+
+VRepeat* VRepeat::make(const Repeat& r)
+{
+ const std::string t=VRepeat::type(r);
+ if(t == "date")
+ return new VRepeatDate(r);
+ else if(t == "integer")
+ return new VRepeatInt(r);
+ else if(t == "string")
+ return new VRepeatString(r);
+ else if(t == "enumerated")
+ return new VRepeatEnum(r);
+ else if(t == "day")
+ return new VRepeatDay(r);
+
+ return NULL;
+}
+
+int VRepeatDate::endIndex() const
+{
+ return (ecf_repeat_date_to_julian(repeat_.end()) -
+ ecf_repeat_date_to_julian(repeat_.start())) / repeat_.step() + 1;
+}
+
+int VRepeatDate::currentIndex() const
+{
+ int cur=(ecf_repeat_date_to_julian(repeat_.index_or_value()) -
+ ecf_repeat_date_to_julian(repeat_.start())) / repeat_.step();
+
+ //int gui = ecf_repeat_julian_to_date(ecf_repeat_date_to_julian(repeat_.start()) + cur * step());
+ return cur;
+}
+
+std::string VRepeatDate::value(int index) const
+{
+ std::stringstream ss;
+ ss << (ecf_repeat_julian_to_date
+ (ecf_repeat_date_to_julian(repeat_.start()) + index * repeat_.step()));
+
+ return ss.str();
+}
+
+
+int VRepeatInt::endIndex() const
+{
+ if(repeat_.step() >0)
+ {
+ int index=(repeat_.end() - repeat_.start()) / repeat_.step() + 1;
+ int val=repeat_.start() + index*repeat_.step();
+ while(val > repeat_.end() && index >=1)
+ {
+ index--;
+ val=repeat_.start() + index*repeat_.step();
+ }
+ return index;
+ }
+ return 0;
+}
+
+int VRepeatInt::currentIndex() const
+{
+ if(repeat_.step() >0)
+ {
+ return (repeat_.index_or_value() - repeat_.start())/repeat_.step();
+ }
+ return 0;
+}
+
+std::string VRepeatInt::value(int index) const
+{
+ std::stringstream ss;
+ ss << repeat_.start() + index*repeat_.step();
+ return ss.str();
+}
+
+std::string VRepeatDay::value(int /*index*/) const
+{
+ std::stringstream ss;
+ ss << repeat_.step();
+ return ss.str();
+}
+
+std::string VRepeatEnum::value(int index) const
+{
+ return repeat_.value_as_string(index);
+}
+
+std::string VRepeatString::value(int index) const
+{
+ return repeat_.value_as_string(index);
+}
diff --git a/Viewer/src/VRepeat.hpp b/Viewer/src/VRepeat.hpp
new file mode 100644
index 0000000..a0c335b
--- /dev/null
+++ b/Viewer/src/VRepeat.hpp
@@ -0,0 +1,94 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VREPEAT_HPP
+#define VREPEAT_HPP
+
+#include <string>
+#include <map>
+#include "RepeatAttr.hpp"
+
+class VNode;
+
+class VRepeat
+{
+public:
+ enum ValyeType {StringType,IntType,NoType};
+
+ virtual ~VRepeat() {}
+ int startIndex() const {return 0;}
+ virtual int endIndex() const=0;
+ virtual int currentIndex() const=0;
+ virtual int step() const {return repeat_.step();}
+ virtual std::string value(int index) const=0;
+ const std::string& type() const {return type_;}
+ ValyeType valueType() const {return valueType_;}
+
+ static VRepeat* make(const Repeat& r);
+ static const std::string& type(const Repeat& r);
+ static const std::string& type(VNode*);
+
+protected:
+ VRepeat(const Repeat& r,const std::string& type,ValyeType t) : repeat_(r), type_(type), valueType_(t) {}
+
+ const Repeat& repeat_;
+ std::string type_;
+ ValyeType valueType_;
+ static std::map<std::string,std::string> typeNames_;
+};
+
+class VRepeatDate : public VRepeat
+{
+public:
+ VRepeatDate(const Repeat& r) : VRepeat(r,"date",IntType) {}
+ int endIndex() const;
+ int currentIndex() const;
+ std::string value(int index) const;
+};
+
+class VRepeatDay : public VRepeat
+{
+public:
+ VRepeatDay(const Repeat& r) : VRepeat(r,"day",IntType) {}
+ int endIndex() const {return 0;}
+ int currentIndex() const {return 0;}
+ std::string value(int index) const;
+};
+
+class VRepeatInt : public VRepeat
+{
+public:
+ VRepeatInt(const Repeat& r) : VRepeat(r,"integer",IntType) {}
+ int endIndex() const;
+ int currentIndex() const;
+ std::string value(int index) const;
+};
+
+class VRepeatEnum : public VRepeat
+{
+public:
+ VRepeatEnum(const Repeat& r) : VRepeat(r,"enumeated",StringType) {}
+ int endIndex() const {return repeat_.end();}
+ int currentIndex() const {return repeat_.index_or_value();}
+ std::string value(int index) const;
+};
+
+class VRepeatString : public VRepeat
+{
+public:
+ VRepeatString(const Repeat& r) : VRepeat(r,"string",StringType) {}
+ int endIndex() const {return repeat_.end();}
+ int currentIndex() const {return repeat_.index_or_value();}
+ std::string value(int index) const;
+};
+
+
+#endif // VREPEAT_HPP
+
diff --git a/Viewer/src/VReply.cpp b/Viewer/src/VReply.cpp
new file mode 100644
index 0000000..3444bc3
--- /dev/null
+++ b/Viewer/src/VReply.cpp
@@ -0,0 +1,57 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "VReply.hpp"
+
+#include "File.hpp"
+
+bool VReply::textFromFile(const std::string& fileName)
+{
+ if(!fileName.empty() &&
+ ecf::File::open(fileName,text_))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+void VReply::text(const std::vector<std::string>& msg)
+{
+ text_.clear();
+ for(std::vector<std::string>::const_iterator it=msg.begin(); it != msg.end(); ++it)
+ {
+ text_+=*it + "\n";
+ }
+}
+
+void VReply::prependText(const std::string& txt)
+{
+ text_.insert(0,txt);
+}
+
+void VReply::appendText(const std::string& txt)
+{
+ text_.append(txt);
+}
+
+void VReply::reset()
+{
+ status_=NoStatus;
+ text_.clear();
+ errorText_.clear();
+ warningText_.clear();
+ infoText_.clear();
+ fileName_.clear();
+ zombies_.clear();
+ readMode_=NoReadMode;
+ readMethod_.clear();
+ tmpFile_.reset();
+ log_.clear();
+}
diff --git a/Viewer/src/VReply.hpp b/Viewer/src/VReply.hpp
new file mode 100644
index 0000000..5c0e7c0
--- /dev/null
+++ b/Viewer/src/VReply.hpp
@@ -0,0 +1,93 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef VREPLY_HPP_
+#define VREPLY_HPP_
+
+#include <string>
+#include <vector>
+
+#include "Zombie.hpp"
+#include "VFile.hpp"
+#include "VDir.hpp"
+
+class VReply
+{
+public:
+ enum Status {NoStatus,TaskDone,TaskFailed,TaskCancelled};
+ enum FileReadMode {NoReadMode,LocalReadMode,ServerReadMode,LogServerReadMode};
+ VReply(void* sender=NULL) : sender_(sender), status_(NoStatus), readMode_(NoReadMode),readTruncatedTo_(-1) {}
+ ~VReply() {}
+
+ void reset();
+
+ void* sender() const {return sender_;}
+ void setSender(void* s) {sender_=s;}
+
+ const std::string& errorText() const {return errorText_;}
+ const std::string& warningText() const {return warningText_;}
+ const std::string& infoText() const {return infoText_;}
+ const std::string& text() const {return text_;}
+ const std::vector<std::string>& textVec() const {return textVec_;}
+ Status status() const {return status_;}
+ const std::string fileName() const {return fileName_;}
+ FileReadMode fileReadMode() const {return readMode_;}
+ const std::string fileReadMethod() {return readMethod_;}
+ VFile_ptr tmpFile() const {return tmpFile_;}
+ VDir_ptr directory() const {return dir_;}
+ const std::vector<Zombie>& zombies() const {return zombies_;}
+ void setReadTruncatedTo(int ival) {readTruncatedTo_=ival;}
+ const std::vector<std::string>& log() const {return log_;}
+
+ bool textFromFile(const std::string&);
+ void text(const std::vector<std::string>& msg);
+ void setTextVec(const std::vector<std::string>& msg) {textVec_=msg;;}
+ void text(const std::string& s) {text_=s;}
+ void setErrorText(const std::string& s) {errorText_=s;}
+ void setWarningText(const std::string& s) {warningText_=s;}
+ void setInfoText(const std::string& s) {infoText_=s;}
+ void fileName(const std::string& s) {fileName_=s;}
+ void fileReadMode(FileReadMode m) {readMode_=m;}
+ void fileReadMethod(const std::string& m) {readMethod_=m;}
+ void tmpFile(VFile_ptr f) {tmpFile_=f;}
+ void setDirectory(VDir_ptr d) {dir_=d;}
+ void zombies(const std::vector<Zombie>& z) { zombies_=z;}
+ int readTruncatedTo() const {return readTruncatedTo_;}
+ void addLog(const std::string& s) {log_.push_back(s);}
+ void setLog(const std::vector<std::string>& s) {log_=s;}
+ void clearLog() {log_.clear();}
+ void setText(const std::string& txt) {text_=txt;}
+
+ bool hasWarning() const {return !warningText_.empty();}
+ bool hasInfo() const {return !infoText_.empty();}
+
+ void prependText(const std::string&);
+ void appendText(const std::string&);
+
+ void status(Status s) {status_=s;}
+
+protected:
+ void* sender_;
+ Status status_;
+ std::string errorText_;
+ std::string warningText_;
+ std::string infoText_;
+ std::string text_;
+ std::vector<std::string> textVec_;
+ std::string fileName_;
+ FileReadMode readMode_;
+ std::string readMethod_;
+ int readTruncatedTo_;
+ std::vector<std::string> log_;
+ VFile_ptr tmpFile_;
+ VDir_ptr dir_;
+ std::vector<Zombie> zombies_;
+};
+
+#endif
diff --git a/Viewer/src/VSState.cpp b/Viewer/src/VSState.cpp
new file mode 100644
index 0000000..cc9cfc1
--- /dev/null
+++ b/Viewer/src/VSState.cpp
@@ -0,0 +1,121 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "VSState.hpp"
+
+#include <QDebug>
+#include <QImage>
+#include <QImageReader>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <map>
+
+#include "ConnectState.hpp"
+#include "ServerHandler.hpp"
+#include "Submittable.hpp"
+#include "UserMessage.hpp"
+#include "VConfigLoader.hpp"
+#include "VProperty.hpp"
+
+std::map<std::string,VSState*> VSState::items_;
+static std::map<SState::State,VSState*> stateMap_;
+
+static VSState haltedSt("halted",SState::HALTED);
+static VSState runningSt("running",SState::RUNNING);
+static VSState shutSt("shutdown",SState::SHUTDOWN);
+static VSState disconnectedSt("disconnected");
+
+VSState::VSState(const std::string& name,SState::State Sstate) :
+ VParam(name)
+{
+ items_[name]=this;
+ stateMap_[Sstate]=this;
+}
+
+VSState::VSState(const std::string& name) :
+ VParam(name)
+{
+ items_[name]=this;
+}
+
+//===============================================================
+//
+// Static methods
+//
+//===============================================================
+
+bool VSState::isRunningState(ServerHandler* s)
+{
+ return toState(s)==items_["running"];
+}
+
+
+VSState* VSState::toState(ServerHandler* s)
+{
+ if(!s)
+ return NULL;
+
+ if(s->connectState()->state() != ConnectState::Normal)
+ return items_["disconnected"];
+
+ std::map<SState::State,VSState*>::const_iterator it=stateMap_.find(s->serverState());
+ if(it != stateMap_.end())
+ return it->second;
+
+ return NULL;
+}
+
+VSState* VSState::find(const std::string& name)
+{
+ std::map<std::string,VSState*>::const_iterator it=items_.find(name);
+ if(it != items_.end())
+ return it->second;
+
+ return NULL;
+}
+
+//
+//Has to be very quick!!
+//
+
+QColor VSState::toColour(ServerHandler* s)
+{
+ VSState *obj=VSState::toState(s);
+ return (obj)?(obj->colour()):QColor();
+}
+
+QColor VSState::toFontColour(ServerHandler* s)
+{
+ VSState *obj=VSState::toState(s);
+ return (obj)?(obj->fontColour()):QColor();
+}
+
+QString VSState::toName(ServerHandler* s)
+{
+ VSState *obj=VSState::toState(s);
+ return (obj)?(obj->name()):QString();
+}
+
+void VSState::load(VProperty* group)
+{
+ Q_FOREACH(VProperty* p,group->children())
+ {
+ if(VSState* obj=VSState::find(p->strName()))
+ {
+ obj->setProperty(p);
+ }
+ }
+}
+
+static SimpleLoader<VSState> loader("sstate");
+
diff --git a/Viewer/src/VSState.hpp b/Viewer/src/VSState.hpp
new file mode 100644
index 0000000..69f7653
--- /dev/null
+++ b/Viewer/src/VSState.hpp
@@ -0,0 +1,44 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VSSTATE_HPP_
+#define VSSTATE_HPP_
+
+#include <map>
+#include <vector>
+#include <string>
+
+#include "SState.hpp"
+#include "VParam.hpp"
+
+class ServerHandler;
+class VProperty;
+
+class VSState : public VParam
+{
+public:
+ VSState(const std::string& name,SState::State);
+ explicit VSState(const std::string& name);
+
+ static bool isRunningState(ServerHandler*);
+ static QString toName(ServerHandler*);
+ static QColor toColour(ServerHandler* n);
+ static QColor toFontColour(ServerHandler* n);
+ static VSState* toState(ServerHandler* n);
+ static VSState* find(const std::string& name);
+
+ //Called from VConfigLoader
+ static void load(VProperty* group);
+
+private:
+ static std::map<std::string,VSState*> items_;
+};
+
+#endif
diff --git a/Viewer/src/VServerSettings.cpp b/Viewer/src/VServerSettings.cpp
new file mode 100644
index 0000000..a7ace20
--- /dev/null
+++ b/Viewer/src/VServerSettings.cpp
@@ -0,0 +1,227 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "VServerSettings.hpp"
+
+#include <assert.h>
+
+#include "DirectoryHandler.hpp"
+#include "ServerHandler.hpp"
+#include "ServerItem.hpp"
+#include "ServerList.hpp"
+#include "SessionHandler.hpp"
+#include "SuiteFilter.hpp"
+#include "UserMessage.hpp"
+#include "VConfig.hpp"
+#include "VConfigLoader.hpp"
+#include "VProperty.hpp"
+#include "VSettings.hpp"
+
+#include <boost/property_tree/json_parser.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/filesystem/operations.hpp>
+
+std::map<VServerSettings::Param,std::string> VServerSettings::notifyIds_;
+std::map<VServerSettings::Param,std::string> VServerSettings::parNames_;
+VProperty* VServerSettings::globalProp_=0;
+
+VServerSettings::VServerSettings(ServerHandler* server) :
+ server_(server),
+ prop_(NULL),
+ guiProp_(NULL)
+{
+ if(parNames_.empty())
+ {
+ parNames_[AutoUpdate]="server.update.autoUpdate";
+ parNames_[UpdateRate]="server.update.updateRateInSec";
+ parNames_[AdaptiveUpdate]="server.update.adaptiveUpdate";
+ parNames_[AdaptiveUpdateIncrement]="server.update.adaptiveUpdateIncrementInSec";
+ parNames_[MaxAdaptiveUpdateRate]="server.update.maxAdaptiveUpdateRateInMin";
+
+ parNames_[MaxOutputFileLines]="server.files.maxOutputFileLines";
+ parNames_[ReadFromDisk]="server.files.readFilesFromDisk";
+
+ parNames_[NotifyAbortedEnabled]="server.notification.aborted.enabled";
+ parNames_[NotifyAbortedPopup]="server.notification.aborted.popup";
+ parNames_[NotifyAbortedSound]="server.notification.aborted.sound";
+
+ parNames_[NotifyRestartedEnabled]="server.notification.restarted.enabled";
+ parNames_[NotifyRestartedPopup]="server.notification.restarted.popup";
+ parNames_[NotifyRestartedSound]="server.notification.restarted.sound";
+
+ parNames_[NotifyLateEnabled]="server.notification.late.enabled";
+ parNames_[NotifyLatePopup]="server.notification.late.popup";
+ parNames_[NotifyLateSound]="server.notification.late.sound";
+
+ parNames_[NotifyZombieEnabled]="server.notification.zombie.enabled";
+ parNames_[NotifyZombiePopup]="server.notification.zombie.popup";
+ parNames_[NotifyZombieSound]="server.notification.zombie.sound";
+
+ parNames_[NotifyAliasEnabled]="server.notification.alias.enabled";
+ parNames_[NotifyAliasPopup]="server.notification.alias.popup";
+ parNames_[NotifyAliasSound]="server.notification.alias.sound";
+
+ notifyIds_[NotifyAbortedEnabled]="aborted";
+ notifyIds_[NotifyRestartedEnabled]="restarted";
+ notifyIds_[NotifyLateEnabled]="late";
+ notifyIds_[NotifyZombieEnabled]="zombie";
+ notifyIds_[NotifyAliasEnabled]="alias";
+ }
+
+ assert(globalProp_);
+
+ prop_=globalProp_->clone(false,true,true); //they all use their master by default!
+
+ for(std::map<Param,std::string>::const_iterator it=parNames_.begin(); it != parNames_.end(); ++it)
+ {
+ if(VProperty* p=prop_->find(it->second))
+ {
+ parToProp_[it->first]=p;
+ propToPar_[p]=it->first;
+ p->addObserver(this);
+ }
+ else
+ {
+ UserMessage::message(UserMessage::DBG, false, std::string("VServerSettings - could not find property: ") + it->second);
+ assert(0);
+ }
+ }
+
+ guiProp_=VConfig::instance()->cloneServerGui(prop_);
+ assert(guiProp_);
+}
+
+VServerSettings::~VServerSettings()
+{
+ delete prop_;
+ delete guiProp_;
+}
+
+
+int VServerSettings::intValue(Param par) const
+{
+ return property(par)->value().toInt();
+}
+
+bool VServerSettings::boolValue(Param par) const
+{
+ return property(par)->value().toBool();
+}
+
+VProperty* VServerSettings::property(Param par) const
+{
+ std::map<Param,VProperty*>::const_iterator it=parToProp_.find(par);
+ if(it != parToProp_.end())
+ {
+ return it->second;
+ }
+ else
+ {
+ assert(0);
+ }
+
+ return NULL;
+}
+
+void VServerSettings::notifyChange(VProperty* p)
+{
+ std::map<VProperty*,Param>::iterator it=propToPar_.find(p);
+ if(it != propToPar_.end())
+ {
+ server_->confChanged(it->second,it->first);
+
+ }
+ else
+ {
+ assert(0);
+ }
+}
+
+std::string VServerSettings::notificationId(Param par)
+{
+ std::map<Param,std::string>::const_iterator it=notifyIds_.find(par);
+ if(it != notifyIds_.end())
+ {
+ return it->second;
+ }
+ return std::string();
+}
+
+bool VServerSettings::notificationsEnabled() const
+{
+ for(std::map<Param,std::string>::const_iterator it=notifyIds_.begin(); it != notifyIds_.end(); it++)
+ {
+ if(boolValue(it->first))
+ return true;
+ }
+ return false;
+}
+
+void VServerSettings::loadSettings()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ std::string fName=cs->serverFile(server_->name());
+
+ //Load settings stored in VProperty
+ VConfig::instance()->loadSettings(fName,guiProp_,false);
+
+ //Some settings are read through VSettings
+ if(boost::filesystem::exists(fName))
+ {
+ VSettings vs(fName);
+ vs.read();
+ vs.beginGroup("suite_filter");
+ server_->suiteFilter()->readSettings(&vs);
+ vs.endGroup();
+ }
+}
+
+void VServerSettings::saveSettings()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ std::string fName=cs->serverFile(server_->name());
+
+ //We save the suite filter through VSettings
+ VSettings vs("");
+ vs.beginGroup("suite_filter");
+ server_->suiteFilter()->writeSettings(&vs);
+ vs.endGroup();
+
+ VConfig::instance()->saveSettings(fName,guiProp_,&vs,false);
+}
+
+
+void VServerSettings::importRcFiles()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+
+ for(int i=0; i < ServerList::instance()->count(); i++)
+ {
+ std::string name=ServerList::instance()->itemAt(i)->name();
+
+ std::string rcFile(DirectoryHandler::concatenate(DirectoryHandler::rcDir(),name + ".options"));
+
+ using boost::property_tree::ptree;
+ ptree pt;
+
+ if(VConfig::instance()->readRcFile(rcFile,pt))
+ {
+ std::string jsonName=cs->serverFile(name);
+ write_json(jsonName,pt);
+ }
+ }
+}
+
+//Called from VConfigLoader
+void VServerSettings::load(VProperty* p)
+{
+ globalProp_=p;
+}
+
+static SimpleLoader<VServerSettings> loader("server");
diff --git a/Viewer/src/VServerSettings.hpp b/Viewer/src/VServerSettings.hpp
new file mode 100644
index 0000000..c61659c
--- /dev/null
+++ b/Viewer/src/VServerSettings.hpp
@@ -0,0 +1,68 @@
+//============================================================================
+// Copyright 2015 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+
+#ifndef VSERVERSETTINGS_HPP_
+#define VSERVERSETTINGS_HPP_
+
+#include "VProperty.hpp"
+
+#include <set>
+
+class ServerHandler;
+
+class VServerSettings : public VPropertyObserver
+{
+ friend class ServerHandler;
+
+public:
+ enum Param {AutoUpdate, UpdateRate,
+ AdaptiveUpdate,AdaptiveUpdateIncrement,MaxAdaptiveUpdateRate,
+ MaxOutputFileLines,ReadFromDisk,
+ NotifyAbortedEnabled, NotifyAbortedPopup, NotifyAbortedSound,
+ NotifyRestartedEnabled, NotifyRestartedPopup, NotifyRestartedSound,
+ NotifyLateEnabled, NotifyLatePopup, NotifyLateSound,
+ NotifyZombieEnabled, NotifyZombiePopup, NotifyZombieSound,
+ NotifyAliasEnabled, NotifyAliasPopup, NotifyAliasSound};
+
+ int intValue(Param par) const;
+ bool boolValue(Param par) const;
+ VProperty* guiProp() const {return guiProp_;}
+ bool notificationsEnabled() const;
+ static std::string notificationId(Param);
+
+ void saveSettings();
+
+ //From VPropertyObserver
+ void notifyChange(VProperty*);
+
+ //Called from VConfigLoader
+ static void load(VProperty*);
+
+ static void importRcFiles();
+
+protected:
+ explicit VServerSettings(ServerHandler* server);
+ ~VServerSettings();
+
+ VProperty* property(Param par) const;
+ void loadSettings();
+
+ ServerHandler* server_;
+ VProperty* prop_;
+ VProperty* guiProp_;
+ std::map<Param,VProperty*> parToProp_;
+ std::map<VProperty*,Param> propToPar_;
+
+ static std::map<Param,std::string> parNames_;
+ static VProperty* globalProp_;
+ static std::map<Param,std::string> notifyIds_;
+};
+
+#endif
diff --git a/Viewer/src/VSettings.cpp b/Viewer/src/VSettings.cpp
new file mode 100644
index 0000000..c50f7cc
--- /dev/null
+++ b/Viewer/src/VSettings.cpp
@@ -0,0 +1,288 @@
+//============================================================================
+// Copyright 2015 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "VSettings.hpp"
+
+#include "DirectoryHandler.hpp"
+#include "UserMessage.hpp"
+
+#include <QDebug>
+
+#include <boost/algorithm/string/join.hpp>
+#include <boost/property_tree/json_parser.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/filesystem/operations.hpp>
+
+//#define _UI_SETTINGS_DEBUG
+
+//======================================================
+//
+// VSettingsPath
+//
+//======================================================
+
+void VSettingsPath::add(const std::string& key)
+{
+ path_.push_back(key);
+}
+
+void VSettingsPath::pop()
+{
+ if(!path_.empty())
+ path_.pop_back();
+}
+
+std::string VSettingsPath::path() const
+{
+ return join(".");
+}
+
+std::string VSettingsPath::path(const std::string& key) const
+{
+ std::string s=path();
+ return (s.empty())?key:(s+"."+key);
+}
+
+std::string VSettingsPath::join(const std::string& sep) const
+{
+ return boost::algorithm::join(path_,sep);
+}
+
+//======================================================
+//
+// VSettings
+//
+//======================================================
+
+VSettings::VSettings(const std::string& file) : file_(file)
+{
+}
+
+VSettings::VSettings(boost::property_tree::ptree pt) : pt_(pt)
+{
+}
+
+
+void VSettings::clear()
+{
+ pt_.clear();
+
+}
+
+bool VSettings::contains(const std::string& key)
+{
+ return (pt_.get_child_optional(path_.path(key)) != boost::none);
+}
+
+bool VSettings::containsFullPath(const std::string& key)
+{
+ return (pt_.get_child_optional(key) != boost::none);
+}
+
+
+//bool VSettings::read(const std::string &fs)
+bool VSettings::read(bool failIfFileDoesNotExist)
+{
+ try
+ {
+ boost::property_tree::json_parser::read_json(file_,pt_);
+ }
+ catch (const boost::property_tree::json_parser::json_parser_error& e)
+ {
+ namespace fs=boost::filesystem;
+ fs::path boostpath(file_);
+ if (!failIfFileDoesNotExist && !fs::exists(boostpath)) // no file and that's ok
+ return false;
+
+ if(!DirectoryHandler::isFirstStartUp())
+ {
+ std::string errorMessage = e.what();
+ UserMessage::message(UserMessage::ERROR, true, std::string("Error, unable to parse JSON session file : " + errorMessage));
+ }
+ return false;
+ }
+
+ return true;
+}
+
+//void VSettings::write(const std::string &fs)
+void VSettings::write()
+{
+ //Write to json
+ write_json(file_,pt_);
+}
+
+void VSettings::put(const std::string& key,int val)
+{
+ pt_.put(path_.path(key),val);
+}
+
+/*void VSettings::put(const std::string& key,bool val)
+{
+ pt_.put(path_.path(key),val);
+}*/
+
+void VSettings::put(const std::string& key,const std::string& val)
+{
+ pt_.put(path_.path(key),val);
+}
+
+
+void VSettings::put(const std::string& key,const std::vector<std::string>& val)
+{
+ boost::property_tree::ptree array;
+ for(std::vector<std::string>::const_iterator it=val.begin(); it != val.end(); ++it)
+ {
+ array.push_back(std::make_pair("",(*it)));
+ }
+ pt_.put_child(path_.path(key),array);
+}
+
+
+// for adding a list of 'structs'
+void VSettings::put(const std::string& key,const std::vector<VSettings>& val)
+{
+ boost::property_tree::ptree array;
+ for(std::vector<VSettings>::const_iterator it=val.begin(); it != val.end(); ++it)
+ {
+ array.push_back(std::make_pair("",(*it).pt_));
+ }
+ pt_.put_child(path_.path(key),array);
+}
+
+
+void VSettings::putAsBool(const std::string& key,bool val)
+{
+ pt_.put(path_.path(key),val?"true":"false");
+}
+
+
+void VSettings::get(const std::string& key,std::vector<std::string>& val)
+{
+ boost::optional<boost::property_tree::ptree& > ptArray=pt_.get_child_optional(path_.path(key));
+ if(!ptArray)
+ {
+ return;
+ }
+
+ //boost::property_tree::ptree ptArray=it->second;
+ for(boost::property_tree::ptree::const_iterator it = ptArray.get().begin(); it != ptArray.get().end(); ++it)
+ {
+ std::string name=it->second.get_value<std::string>();
+ val.push_back(name);
+ }
+}
+
+bool VSettings::getAsBool(const std::string& key,bool defaultVal)
+{
+ std::string v=pt_.get<std::string>(path_.path(key),(defaultVal)?"true":"false");
+ if(v == "true" || v == "1")
+ return true;
+
+ return false;
+
+}
+
+// for getting a list of 'structs'
+void VSettings::get(const std::string& key, std::vector<VSettings>& val)
+{
+ boost::optional<boost::property_tree::ptree& > ptArray=pt_.get_child_optional(path_.path(key));
+ if(!ptArray)
+ {
+ return;
+ }
+
+ for(boost::property_tree::ptree::const_iterator it = ptArray.get().begin(); it != ptArray.get().end(); ++it)
+ {
+ boost::property_tree::ptree child = it->second;
+ VSettings vs(child);
+ val.push_back(vs);
+ }
+}
+
+
+void VSettings::beginGroup(const std::string &id)
+{
+ path_.add(id);
+}
+
+void VSettings::endGroup()
+{
+ path_.pop();
+}
+
+
+//======================================================
+//
+// VSettings
+//
+//======================================================
+
+VComboSettings::VComboSettings(const std::string& file,const std::string& qsFile) :
+ VSettings(file),
+ qs_(QString::fromStdString(qsFile),QSettings::NativeFormat)
+{
+
+ //qs_(QString::fromStdString(application))
+ //QSettings::setPath(QSettings::IniFormat, QSettings::UserScope,"/home/graphics/cgr/.ecflowview");
+ //QSettings::setPath(QSettings::IniFormat, QSettings::UserScope,"/home/graphics/cgr/.ecflowview");
+#ifdef _UI_SETTINGS_DEBUG
+ UserMessage::message(UserMessage::DBG,false,"VComboSettings --> fileName=" + qs_.fileName().toStdString());
+#endif
+}
+
+VComboSettings::~VComboSettings()
+{
+}
+
+void VComboSettings::clear()
+{
+ VSettings::clear();
+ pt_.clear();
+}
+
+bool VComboSettings::containsQs(const std::string& key)
+{
+ return qs_.contains(QString::fromStdString(key));
+}
+
+void VComboSettings::write()
+{
+ VSettings::write();
+ qs_.sync();
+}
+
+void VComboSettings::putQs(const std::string& key,QVariant val)
+{
+ qs_.setValue(QString::fromStdString(key),val);
+}
+
+QVariant VComboSettings::getQs(const std::string& key)
+{
+#ifdef _UI_SETTINGS_DEBUG
+ qDebug() << "qt group" << qs_.group();
+#endif
+ return qs_.value(QString::fromStdString(key));
+}
+
+void VComboSettings::beginGroup(const std::string &id)
+{
+ VSettings::beginGroup(id);
+ qs_.beginGroup(QString::fromStdString(id));
+#ifdef _UI_SETTINGS_DEBUG
+ qDebug() << "qt group" << qs_.group();
+#endif
+}
+
+void VComboSettings::endGroup()
+{
+ VSettings::endGroup();
+ qs_.endGroup();
+}
diff --git a/Viewer/src/VSettings.hpp b/Viewer/src/VSettings.hpp
new file mode 100644
index 0000000..ecb71f8
--- /dev/null
+++ b/Viewer/src/VSettings.hpp
@@ -0,0 +1,107 @@
+//============================================================================
+// Copyright 2015 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VSETTINGS_HPP_
+#define VSETTINGS_HPP_
+
+#include <boost/property_tree/ptree.hpp>
+#include <QSettings>
+
+#include <vector>
+
+class VSettingsPath
+{
+public:
+ void add(const std::string& key);
+ void pop();
+
+ std::string path() const;
+ std::string path(const std::string& key) const;
+
+protected:
+ std::string join(const std::string& sep) const;
+
+ std::vector<std::string> path_;
+};
+
+//This class stores the settings as a boost property tree and read/write them into/from json.
+class VSettings
+{
+public:
+ explicit VSettings(const std::string& file);
+ explicit VSettings(boost::property_tree::ptree pt);
+ virtual ~VSettings() {};
+
+ //bool read(const std::string &fs);
+ //virtual void write(const std::string &fs);
+
+ bool read(bool failIfFileDoesNotExist = true);
+ virtual void write();
+
+ virtual void clear();
+ bool contains(const std::string& key);
+ bool containsFullPath(const std::string& key);
+
+ virtual void beginGroup(const std::string&);
+ virtual void endGroup();
+
+ void put(const std::string& key,int val);
+ //void put(const std::string& key,bool val);
+ void put(const std::string& key,const std::string& val);
+ void put(const std::string& key,const std::vector<std::string>& val);
+ void put(const std::string& key,const std::vector<VSettings>& val);
+ void putAsBool(const std::string& key,bool val);
+
+ template <typename T>
+ T get(const std::string& key,const T& defaultVal)
+ {
+ return pt_.get<T>(path_.path(key),defaultVal);
+ }
+ void get(const std::string& key,std::vector<std::string>& val);
+ bool getAsBool(const std::string& key,bool defaultVal);
+ void get(const std::string& key,std::vector<VSettings>& val);
+
+ const boost::property_tree::ptree & propertyTree() const {return pt_;}
+
+
+protected:
+ boost::property_tree::ptree pt_;
+ VSettingsPath path_;
+ std::string file_;
+};
+
+//This class uses both the boost property tree and QSettings to store and manage the settings. The idea
+//is that Qt based settings like window geometry, window state etc. are handled by QSettings while
+//all the others by the boost property tree.
+class VComboSettings : public VSettings
+{
+public:
+ VComboSettings(const std::string& file,const std::string& qsFile);
+ ~VComboSettings();
+
+ //void write(const std::string &fs);
+ void clear();
+
+ void write();
+
+
+ bool containsQs(const std::string& key);
+
+ void beginGroup(const std::string&);
+ void endGroup();
+
+ void putQs(const std::string& key,QVariant val);
+ QVariant getQs(const std::string& key);
+
+protected:
+ QSettings qs_;
+};
+
+#endif
diff --git a/Viewer/src/VTask.cpp b/Viewer/src/VTask.cpp
new file mode 100644
index 0000000..3acae35
--- /dev/null
+++ b/Viewer/src/VTask.cpp
@@ -0,0 +1,117 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "VTask.hpp"
+#include "VNode.hpp"
+#include "VReply.hpp"
+#include "VTaskObserver.hpp"
+
+VTask::VTask(Type t,VTaskObserver* obs) :
+ type_(t),
+ status_(NOSTATUS),
+ targetPath_("/"),
+ node_(0),
+ reply_(0)
+{
+ if(obs)
+ observers_.push_back(obs);
+ reply_=new VReply();
+}
+
+VTask::VTask(Type t,VNode *node,VTaskObserver* obs) :
+ type_(t),
+ status_(NOSTATUS),
+ node_(node),
+ reply_(0)
+{
+ if(node_)
+ targetPath_=node_->absNodePath();
+
+ if(obs)
+ observers_.push_back(obs);
+
+ reply_=new VReply();
+}
+
+VTask::~VTask()
+{
+ delete reply_;
+}
+
+//Task for a server
+VTask_ptr VTask::create(Type t,VTaskObserver* obs)
+{
+ return VTask_ptr(new VTask(t,obs));
+}
+
+//Task for a node
+VTask_ptr VTask::create(Type t,VNode *node,VTaskObserver* obs)
+{
+ return VTask_ptr(new VTask(t,node,obs));
+}
+
+
+const std::string& VTask::typeString() const
+{
+ static std::map<Type,std::string> names;
+ if(names.empty())
+ {
+ names[NoTask]="notask";
+ names[CommandTask]="command";
+ names[OverviewTask]="overview";
+ names[WhyTask]="why";
+ names[ManualTask]="manual";
+ names[ScriptTask]="script";
+ names[JobTask]="job";
+ names[MessageTask]="message";
+ names[OutputTask]="output";
+ names[StatsTask]="stats";
+ names[NewsTask]="news";
+ names[SyncTask]="sync";
+ }
+
+ if(names.find(type_) != names.end())
+ return names[type_];
+
+ return names[NoTask];
+}
+
+const std::string& VTask::param(const std::string& key) const
+{
+ static std::string emptyStr("");
+ std::map<std::string,std::string>::const_iterator it=params_.find(key);
+ if(it != params_.end())
+ return it->second;
+ return emptyStr;
+}
+
+void VTask::status(Status s, bool broadcastIt)
+{
+ status_=s;
+ if(broadcastIt)
+ broadcast();
+}
+void VTask::removeObserver(VTaskObserver* o)
+{
+ std::vector<VTaskObserver*>::iterator it=std::find(observers_.begin(), observers_.end(),o);
+ if(it != observers_.end())
+ {
+ observers_.erase(it);
+ }
+}
+
+void VTask::broadcast()
+{
+ //VTask always exists as a shared pointer, so it is safe to pass on
+ //this shared pointer to the observer.
+ for(std::vector<VTaskObserver*>::iterator it=observers_.begin(); it != observers_.end(); ++it)
+ {
+ (*it)->taskChanged(shared_from_this());
+ }
+}
diff --git a/Viewer/src/VTask.hpp b/Viewer/src/VTask.hpp
new file mode 100644
index 0000000..ac11a2f
--- /dev/null
+++ b/Viewer/src/VTask.hpp
@@ -0,0 +1,91 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef VTASK_HPP_
+#define VTASK_HPP_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "NodeFwd.hpp"
+
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+
+//#include "VReply.hpp"
+class VReply;
+
+class Node;
+class VNode;
+class VTaskObserver;
+
+//This class defines a task that can be sent to the server to be executed.
+//A VTask can only be created through the static create methods that return back
+//a shared pointer of VTask. So VTask can only exist as a shared pointer.
+
+class VTask;
+typedef boost::shared_ptr<VTask> VTask_ptr;
+
+class VTask : public boost::enable_shared_from_this<VTask>
+{
+public:
+ enum Type {NoTask,CommandTask,OverviewTask,WhyTask,ManualTask,ScriptTask,
+ JobTask,MessageTask,OutputTask,StatsTask,NewsTask,SyncTask,ResetTask,SuiteAutoRegisterTask,
+ SuiteListTask,ScriptEditTask,ScriptPreprocTask,ScriptSubmitTask,HistoryTask,LogOutTask,
+ ZombieListTask};
+ enum Status {NOSTATUS,QUEUED,RUNNING,FINISHED,CANCELLED,ABORTED,REJECTED};
+
+ virtual ~VTask();
+
+ Type type() const {return type_;}
+ const std::string& typeString() const;
+ VNode* node() const {return node_;}
+ Status status() {return status_;}
+ const std::string& targetPath() const {return targetPath_;}
+
+ const std::string& param(const std::string& key) const;
+ const std::map<std::string,std::string>& params() const {return params_;}
+ const std::vector<std::string>& command() const {return command_;}
+ const std::vector<std::string>& contents() const {return contents_;}
+ const NameValueVec& vars() const {return vars_;}
+ VReply* reply() const {return reply_;}
+
+ void param(const std::string& key,const std::string& val) {params_[key]=val;}
+ void command(const std::vector<std::string>& cmd) {command_=cmd;}
+ void contents(const std::vector<std::string>& c) {contents_=c;}
+ void vars(const NameValueVec& v) {vars_=v;}
+
+ //When it is called the observers are notified about the change in status.
+ void status(Status s,bool broadcast=true);
+
+ void aborted(const std::string&,bool broadcast=true) {}
+ void broadcast();
+ void removeObserver(VTaskObserver*);
+
+ static VTask_ptr create(Type t,VTaskObserver* obs=0);
+ static VTask_ptr create(Type t,VNode *node,VTaskObserver* obs=0);
+
+protected:
+ VTask(Type t,VTaskObserver* obs=0);
+ VTask(Type t,VNode *node,VTaskObserver* obs=0);
+
+ Type type_;
+ Status status_;
+ std::map<std::string,std::string> params_;
+ std::vector<std::string> command_;
+ std::vector<std::string> contents_;
+ NameValueVec vars_;
+ std::string targetPath_;
+ VNode *node_;
+ std::vector<VTaskObserver*> observers_;
+ VReply* reply_;
+};
+
+#endif
diff --git a/Viewer/src/VTaskNode.cpp b/Viewer/src/VTaskNode.cpp
new file mode 100644
index 0000000..5e4acd8
--- /dev/null
+++ b/Viewer/src/VTaskNode.cpp
@@ -0,0 +1,179 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include "VTaskNode.hpp"
+
+#include "ServerDefsAccess.hpp"
+#include "ServerHandler.hpp"
+#include "VNState.hpp"
+
+#include <boost/algorithm/string.hpp>
+#include "ChangeNotify.hpp"
+
+VTaskNode::VTaskNode(VNode* parent,node_ptr node) :
+ VNode(parent,node),
+ prevTryNo_(0),
+ prevFlag_(0)
+{
+ unsigned int tn=tryNo();
+ NState::State new_status = node_->state();
+
+ bool aborted=(new_status == NState::ABORTED);
+ bool zombie=node_->flag().is_set(ecf::Flag::ZOMBIE);
+ bool late=node_->flag().is_set(ecf::Flag::LATE);
+
+ updatePrev(tn,aborted,zombie,late);
+}
+
+VTaskNode::~VTaskNode()
+{
+
+}
+
+void VTaskNode::internalState(VNodeInternalState& st)
+{
+ st.tryNo_=prevTryNo_;
+ st.flag_=prevFlag_;
+}
+
+void VTaskNode::updatePrev(int tn,bool aborted,bool zombie,bool late)
+{
+ prevTryNo_=tn;
+
+ if(aborted)
+ prevFlag_ |= AbortedMask; //(0x01 << AbortedPos);
+ else
+ prevFlag_ &= ~AbortedMask; //0x01 << AbortedPos);
+
+ if(zombie)
+ prevFlag_ |= ZombieMask;
+ else
+ prevFlag_ &= ~ZombieMask;
+
+ if(late)
+ prevFlag_ |= LateMask;
+ else
+ prevFlag_ &= ~LateMask;
+}
+
+bool VTaskNode::isZombie() const
+{
+ if(node_)
+ return node_->flag().is_set(ecf::Flag::ZOMBIE);
+ return false;
+}
+
+bool VTaskNode::isLate() const
+{
+ if(node_)
+ return node_->flag().is_set(ecf::Flag::LATE);
+ return false;
+}
+
+bool VTaskNode::prevAborted() const
+{
+ return prevFlag_ & AbortedMask;
+}
+
+bool VTaskNode::prevZombie() const
+{
+ return prevFlag_ & ZombieMask;
+}
+
+bool VTaskNode::prevLate() const
+{
+ return prevFlag_ & LateMask;
+}
+
+void VTaskNode::check(VServerSettings* conf,const VNodeInternalState& st)
+{
+ //if(st)
+ //{
+ prevTryNo_=st.tryNo_;
+ prevFlag_=st.flag_;
+
+ check(conf,true);
+ //}
+}
+
+void VTaskNode::check(VServerSettings* conf,bool stateChange)
+{
+ NState::State new_status = node_->state();
+
+ bool new_aborted=(new_status == NState::ABORTED);
+ unsigned int new_tryNo=tryNo();
+ bool new_zombie=isZombie();
+ bool new_late=isLate();
+
+ //Aborted
+ if(stateChange)
+ {
+ if(conf->boolValue(VServerSettings::NotifyAbortedEnabled))
+ {
+ bool prev_aborted=prevAborted();
+
+ //Check for aborted
+ if(new_aborted && !prev_aborted)
+ {
+ bool popup=conf->boolValue(VServerSettings::NotifyAbortedPopup);
+ bool sound=conf->boolValue(VServerSettings::NotifyAbortedSound);
+ ChangeNotify::add("aborted",this,popup,sound);
+ }
+ else if(!new_aborted && prev_aborted)
+ {
+ ChangeNotify::remove("aborted",this);
+ }
+ }
+ }
+
+ //Restarted
+ if(conf->boolValue(VServerSettings::NotifyRestartedEnabled))
+ {
+ if(new_status == NState::SUBMITTED || new_status == NState::ACTIVE)
+ {
+ if(new_tryNo > 1 && new_tryNo != prevTryNo_)
+ {
+ bool popup=conf->boolValue(VServerSettings::NotifyRestartedPopup);
+ bool sound=conf->boolValue(VServerSettings::NotifyRestartedSound);
+ ChangeNotify::add("restarted",this,popup,sound);
+ }
+ }
+ }
+
+ //Zombie
+ if(conf->boolValue(VServerSettings::NotifyZombieEnabled))
+ {
+ if(node_)
+ {
+ if(new_zombie && !prevZombie())
+ {
+ bool popup=conf->boolValue(VServerSettings::NotifyZombiePopup);
+ bool sound=conf->boolValue(VServerSettings::NotifyZombieSound);
+ ChangeNotify::add("zombie",this,popup,sound);
+ }
+ }
+ }
+
+ //Late
+ if(conf->boolValue(VServerSettings::NotifyLateEnabled))
+ {
+ if(node_)
+ {
+ if(new_late && !prevLate())
+ {
+ bool popup=conf->boolValue(VServerSettings::NotifyLatePopup);
+ bool sound=conf->boolValue(VServerSettings::NotifyLateSound);
+ ChangeNotify::add("late",this,popup,sound);
+ }
+ }
+ }
+
+ updatePrev(new_tryNo,new_aborted,new_zombie,new_late);
+}
diff --git a/Viewer/src/VTaskNode.hpp b/Viewer/src/VTaskNode.hpp
new file mode 100644
index 0000000..063af05
--- /dev/null
+++ b/Viewer/src/VTaskNode.hpp
@@ -0,0 +1,53 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+#ifndef VIEWER_SRC_VTASKNODE_HPP_
+#define VIEWER_SRC_VTASKNODE_HPP_
+
+#include "VNode.hpp"
+#include "Node.hpp"
+
+class ServerHandler;
+class VServer;
+class VServerSettings;
+
+class VTaskNode : public VNode
+{
+ friend class ServerHandler;
+
+public:
+ explicit VTaskNode(VNode* parent,node_ptr);
+ ~VTaskNode();
+
+ bool isEmpty() const { return true;}
+ //bool isNode() const {return true;}
+ bool isTopLevel() const {return false;}
+ //bool isServer() const {return false;}
+ VTaskNode* isTask() const {return const_cast<VTaskNode*>(this);}
+ void internalState(VNodeInternalState&);
+
+protected:
+ void check(VServerSettings* conf,const VNodeInternalState&);
+ void check(VServerSettings* conf,bool);
+
+private:
+ void updatePrev(int,bool,bool,bool);
+ bool isZombie() const;
+ bool isLate() const;
+ bool prevAborted() const;
+ bool prevZombie() const;
+ bool prevLate() const;
+
+ enum FlagMask {AbortedMask=0x01,ZombieMask=0x02,LateMask=0x04};
+ unsigned char prevTryNo_;
+ unsigned char prevFlag_;
+};
+
+
+#endif /* VIEWER_SRC_VTASKNODE_HPP_ */
diff --git a/Viewer/src/VTaskObserver.hpp b/Viewer/src/VTaskObserver.hpp
new file mode 100644
index 0000000..ac91124
--- /dev/null
+++ b/Viewer/src/VTaskObserver.hpp
@@ -0,0 +1,22 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef VTaskObserver_HPP_
+#define VTaskObserver_HPP_
+
+#include "VTask.hpp"
+
+class VTaskObserver
+{
+public:
+ virtual ~VTaskObserver() {};
+ virtual void taskChanged(VTask_ptr)=0;
+};
+
+#endif
diff --git a/Viewer/src/VTree.cpp b/Viewer/src/VTree.cpp
new file mode 100644
index 0000000..7e6340d
--- /dev/null
+++ b/Viewer/src/VTree.cpp
@@ -0,0 +1,322 @@
+//============================================================================
+// Copyright 2015 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "VTree.hpp"
+
+#include "ServerHandler.hpp"
+#include "UserMessage.hpp"
+#include "VAttributeType.hpp"
+#include "VNode.hpp"
+#include "VFilter.hpp"
+#include "VModelData.hpp"
+
+//==========================================
+//
+// VTreeNode
+//
+//==========================================
+
+
+VTreeNode::VTreeNode(VNode* n,VTreeNode* parent) : vnode_(n), parent_(parent), attrNum_(-1)
+{
+ if(parent_)
+ parent_->addChild(this);
+}
+
+VTreeNode::~VTreeNode()
+{
+ for(std::vector<VTreeNode*>::iterator it=children_.begin(); it != children_.end();++it)
+ delete *it;
+}
+
+VTree* VTreeNode::root() const
+{
+ return (parent_)?parent_->root():NULL;
+}
+
+VTreeServer* VTreeNode::server() const
+{
+ return (parent_)?parent_->server():NULL;
+}
+
+void VTreeNode::addChild(VTreeNode* ch)
+{
+ children_.push_back(ch);
+}
+
+VTreeNode* VTreeNode::findChild(const std::string& name) const
+{
+ for(unsigned int i=0; i < children_.size(); i++)
+ {
+ if(children_[i]->vnode_->strName() == name)
+ return children_[i];
+ }
+
+ return NULL;
+}
+
+
+int VTreeNode::indexOfChild(const VTreeNode* vn) const
+{
+ for(unsigned int i=0; i < children_.size(); i++)
+ {
+ if(children_[i] == vn)
+ return i;
+ }
+
+ return -1;
+}
+
+int VTreeNode::indexInParent() const
+{
+ if(parent_)
+ {
+ return parent_->indexOfChild(this);
+ }
+ return -1;
+}
+
+bool VTreeNode::isAttrInitialised() const
+{
+ return (attrNum_ != -1);
+}
+
+int VTreeNode::attrRow(int row,AttributeFilter *filter) const
+{
+ return VAttributeType::getRow(vnode_,row,filter);
+}
+
+int VTreeNode::attrNum(AttributeFilter *filter) const
+{
+ if(!filter)
+ return attrNum_;
+
+ if(!isAttrInitialised())
+ attrNum_=vnode_->attrNum(filter);
+
+ return attrNum_;
+}
+
+void VTreeNode::updateAttrNum(AttributeFilter *filter)
+{
+ attrNum_=vnode_->attrNum(filter);
+}
+
+void VTreeNode::resetAttrNum()
+{
+ attrNum_=-1;
+ for(unsigned int i=0; i < children_.size(); i++)
+ {
+ children_[i]->resetAttrNum();
+ }
+}
+
+//========================================================
+//
+// VTree
+//
+//========================================================
+
+VTree::VTree(VTreeServer* server) : VTreeNode(server->realServer()->vRoot(),0), server_(server)
+{
+
+}
+
+VTree::~VTree()
+{
+ clear();
+}
+
+VTree* VTree::root() const
+{
+ return const_cast<VTree*>(this);
+}
+
+VNode* VTree::vnodeAt(int index) const
+{
+ return (nodeVec_[index])?(nodeVec_[index]->vnode()):NULL;
+}
+
+VTreeNode* VTree::find(const VNode* vn) const
+{
+ Q_ASSERT(vn->index() < nodeVec_.size());
+ return nodeVec_[vn->index()];
+}
+
+VTreeNode *VTree::findAncestor(const VNode* vn)
+{
+ VNode* p=vn->parent();
+ while(p)
+ {
+ if(VTreeNode* n=find(p))
+ return n;
+
+ p=p->parent();
+ }
+
+ return NULL;
+}
+
+int VTree::totalNumOfTopLevel(VTreeNode* n) const
+{
+ if(!n->isTopLevel())
+ return -1;
+
+ int idx=indexOfChild(n);
+ if(idx != -1)
+ return totalNumOfTopLevel(idx);
+
+ return -1;
+}
+
+int VTree::totalNumOfTopLevel(int idx) const
+{
+ assert(totalNumInChild_.size() == children_.size());
+
+ if(idx >=0 && idx < totalNumInChild_.size())
+ {
+ return totalNumInChild_.at(idx);
+ }
+
+ return -1;
+}
+
+
+
+#if 0
+VTreeNode* VTree::topLevelNode(int row) const
+{
+ return children_[row];
+}
+
+int VTree::indexOfTopLevelNode(const VTreeNode* node) const
+{
+ return indexOfChild(node);
+}
+
+int VTree::topLevelNodeNum() const
+{
+ return numOfChildren();
+}
+#endif
+
+void VTree::removeChildren(VTreeNode* node)
+{
+ for(std::vector<VTreeNode*>::iterator it=node->children_.begin(); it != node->children_.end();++it)
+ {
+ nodeVec_[(*it)->vnode()->index()]=NULL;
+ removeChildren(*it);
+ delete *it;
+ }
+
+ node->children_.clear();
+}
+
+void VTree::buildBranch(const std::vector<VNode*>& filter,VTreeNode* node,VTreeNode* branch)
+{
+ VNode* vnode=node->vnode();
+ assert(filter[vnode->index()] != NULL);
+
+ for(unsigned int i=0; i < vnode->numOfChildren();i++)
+ {
+ build(branch,vnode->childAt(i),filter);
+ }
+}
+
+void VTree::addBranch(VTreeNode* node,VTreeNode* branch)
+{
+ assert(node->vnode() == branch->vnode());
+
+ for(unsigned int i=0; i < branch->numOfChildren();i++)
+ {
+ branch->childAt(i)->parent_=node;
+ node->addChild(branch->childAt(i));
+ }
+
+ branch->children_.clear();
+}
+
+
+void VTree::clear()
+{
+ for(std::vector<VTreeNode*>::iterator it=children_.begin(); it != children_.end();++it)
+ delete *it;
+
+ children_.clear();
+ nodeVec_.clear();
+ attrNum_=-1;
+ totalNum_=0;
+ totalNumInChild_.clear();
+}
+
+void VTree::build(const std::vector<VNode*>& filter)
+{
+ clear();
+ VServer* s=server_->realServer()->vRoot();
+ nodeVec_.resize(s->totalNum());
+ VTreeNode *nptr=0;
+ std::fill(nodeVec_.begin(), nodeVec_.end(), nptr);
+
+ int prevTotalNum=0;
+ for(unsigned int j=0; j < s->numOfChildren();j++)
+ {
+ build(this,s->childAt(j),filter);
+ totalNumInChild_.push_back(totalNum_-prevTotalNum-1);
+ prevTotalNum=totalNum_;
+ }
+}
+
+void VTree::build(VTreeNode* parent,VNode* node,const std::vector<VNode*>& filter)
+{
+ if(filter[node->index()])
+ {
+ VTreeNode *n=new VTreeNode(node,parent);
+ totalNum_++;
+ nodeVec_[node->index()]=n;
+
+ for(unsigned int j=0; j < node->numOfChildren();j++)
+ {
+ build(n,node->childAt(j),filter);
+ }
+ }
+}
+
+void VTree::build()
+{
+ clear();
+ VServer* s=server_->realServer()->vRoot();
+ nodeVec_.resize(s->totalNum());
+ VTreeNode *nptr=0;
+ std::fill(nodeVec_.begin(), nodeVec_.end(), nptr);
+
+ int prevTotalNum=0;
+ for(unsigned int j=0; j < s->numOfChildren();j++)
+ {
+ build(this,s->childAt(j));
+ totalNumInChild_.push_back(totalNum_-prevTotalNum-1);
+ prevTotalNum=totalNum_;
+ }
+}
+
+void VTree::build(VTreeNode* parent,VNode* vnode)
+{
+ VTreeNode *n=new VTreeNode(vnode,parent);
+ nodeVec_[vnode->index()]=n;
+ totalNum_++;
+
+ //Preallocates the children. With this we will only use the memory we really need.
+ if(vnode->numOfChildren() > 0)
+ n->children_.reserve(vnode->numOfChildren());
+
+ for(unsigned int j=0; j < vnode->numOfChildren();j++)
+ {
+ build(n,vnode->childAt(j));
+ }
+}
+
diff --git a/Viewer/src/VTree.hpp b/Viewer/src/VTree.hpp
new file mode 100644
index 0000000..cc79f2a
--- /dev/null
+++ b/Viewer/src/VTree.hpp
@@ -0,0 +1,97 @@
+//============================================================================
+// Copyright 2015 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef VTREENODE_HPP
+#define VTREENODE_HPP
+
+#include <vector>
+
+#include <QStringList>
+
+class VNode;
+class VAttributeType;
+class AttributeFilter;
+class VTreeServer;
+class VTree;
+
+class VTreeNode
+{
+public:
+ VTreeNode(VNode* vnode,VTreeNode* parent);
+ virtual ~VTreeNode();
+
+ VNode* vnode() const {return vnode_;}
+ void addChild(VTreeNode*);
+ int numOfChildren() const {return children_.size();}
+ VTreeNode* findChild(const std::string&) const;
+ int indexOfChild(const VTreeNode* vn) const;
+ int indexInParent() const;
+ VTreeNode* childAt(int i) {return children_[i];}
+ VTreeNode* parent() const {return parent_;}
+ virtual VTree* root() const;
+ virtual VTreeServer* server() const;
+
+ int attrRow(int row,AttributeFilter *filter) const;
+ int attrNum(AttributeFilter* filter=0) const;
+ bool isAttrInitialised() const;
+ void updateAttrNum(AttributeFilter* filter=0);
+ void resetAttrNum();
+
+ virtual bool isTopLevel() const {if(parent_) return (parent_->parent())?false:true; return false;}
+ virtual bool isRoot() const {return false;}
+
+public:
+ VNode* vnode_;
+ std::vector<VTreeNode*> children_;
+ VTreeNode *parent_;
+ mutable short attrNum_;
+};
+
+class VTree : public VTreeNode
+{
+friend class VTreeServer;
+
+public:
+ VTree(VTreeServer*);
+ ~VTree();
+
+ VTreeNode* find(const VNode*) const;
+ VTree* root() const;
+ VTreeServer* server() const {return server_;}
+
+ VTreeNode *findAncestor(const VNode*);
+ bool isTopLevel() const {return false;}
+ bool isRoot() const {return true;}
+ int totalNum() const {return totalNum_;}
+ int totalNumOfTopLevel(VTreeNode*) const;
+ int totalNumOfTopLevel(int i) const;
+ VNode* vnodeAt(int index) const;
+
+ const std::vector<VTreeNode*>& nodeVec() const {return nodeVec_;}
+
+protected:
+ void clear();
+ void build(const std::vector<VNode*>& filter);
+ void build();
+ void removeChildren(VTreeNode*);
+ void buildBranch(const std::vector<VNode*>& filter,VTreeNode* node,VTreeNode* branch);
+ void addBranch(VTreeNode* node,VTreeNode* branch);
+
+private:
+ void build(VTreeNode* parent,VNode* vnode,const std::vector<VNode*>& filter);
+ void build(VTreeNode* parent,VNode* vnode);
+
+ VTreeServer* server_;
+ std::vector<VTreeNode*> nodeVec_;
+ int totalNum_;
+ std::vector<int> totalNumInChild_;
+};
+
+#endif // VTREENODE_HPP
+
diff --git a/Viewer/src/VariableAddDialog.ui b/Viewer/src/VariableAddDialog.ui
new file mode 100644
index 0000000..cd8cab8
--- /dev/null
+++ b/Viewer/src/VariableAddDialog.ui
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>VariableAddDialog</class>
+ <widget class="QDialog" name="VariableAddDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>286</width>
+ <height>161</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Add variable</string>
+ </property>
+ <property name="modal">
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0,1,0">
+ <item>
+ <widget class="QLabel" name="label_">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Add new variable for</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="MessageLabel" name="messageLabel_" native="true"/>
+ </item>
+ <item>
+ <widget class="QWidget" name="form_" native="true">
+ <layout class="QFormLayout" name="formLayout_2">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>&Name:</string>
+ </property>
+ <property name="buddy">
+ <cstring>nameEdit_</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="nameEdit_">
+ <property name="readOnly">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>&Value:</string>
+ </property>
+ <property name="buddy">
+ <cstring>valueEdit_</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="valueEdit_"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox_">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>MessageLabel</class>
+ <extends>QWidget</extends>
+ <header>MessageLabel.hpp</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox_</sender>
+ <signal>accepted()</signal>
+ <receiver>VariableAddDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>257</x>
+ <y>218</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>227</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox_</sender>
+ <signal>rejected()</signal>
+ <receiver>VariableAddDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>274</x>
+ <y>218</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>283</x>
+ <y>227</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/Viewer/src/VariableItemWidget.cpp b/Viewer/src/VariableItemWidget.cpp
new file mode 100644
index 0000000..84b0db2
--- /dev/null
+++ b/Viewer/src/VariableItemWidget.cpp
@@ -0,0 +1,1128 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "VariableItemWidget.hpp"
+
+#include <QClipboard>
+#include <QDebug>
+#include <QItemSelectionModel>
+#include <QMessageBox>
+#include <QPushButton>
+#include <QSettings>
+#include <QVBoxLayout>
+
+#include "IconProvider.hpp"
+#include "LineEdit.hpp"
+#include "SessionHandler.hpp"
+#include "UserMessage.hpp"
+#include "VariableModel.hpp"
+#include "VariableModelData.hpp"
+#include "VariableSearchLine.hpp"
+#include "VConfig.hpp"
+#include "VProperty.hpp"
+
+#define _UI_VARIABLEITEMWIDGET_DEBUG
+
+//======================================
+//
+// VariablePropDialog
+//
+//======================================
+
+VariablePropDialog::VariablePropDialog(VariableModelDataHandler *data,int defineIndex,QString name, QString value,bool frozen,QWidget *parent) :
+ QDialog(parent),
+ genVar_(false),
+ data_(data),
+ defineIndex_(defineIndex),
+ oriName_(name),
+ cleared_(false)
+{
+ setupUi(this);
+ setAttribute(Qt::WA_DeleteOnClose);
+ setModal(false);
+
+ Q_ASSERT(data_);
+ Q_ASSERT(data_->count() > 0);
+ Q_ASSERT(data_->count() > defineIndex_);
+
+ nodeName_=QString::fromStdString(data_->data(0)->name());
+ nodeType_=QString::fromStdString(data_->data(0)->type());
+ nodeTypeCapital_=nodeType_;
+ if(nodeTypeCapital_.size() > 0)
+ {
+ QChar s=nodeTypeCapital_.at(0);
+ s=s.toUpper();
+ nodeTypeCapital_.replace(0,1,s);
+ }
+
+ data_->addObserver(this);
+
+ genVar_=data_->data(defineIndex)->isGenVar(name.toStdString());
+
+ QString path=QString::fromStdString(data_->data(0)->fullPath());
+ QString h=EditorInfoLabel::formatKeyLabel("Node to modify: ") + "<b>" +
+ EditorInfoLabel::formatNodeName(nodeName_) + "</b><br>";
+ h+= EditorInfoLabel::formatKeyLabel("Path: ") + EditorInfoLabel::formatNodePath(path) + "<br>";
+
+ VariableModelData* defineData=data_->data(defineIndex_);
+ Q_ASSERT(defineData);
+ defineNodeName_=QString::fromStdString(defineData->name());
+ defineNodeType_=QString::fromStdString(defineData->type());
+
+ genVar_=defineData->isGenVar(name.toStdString());
+ h+=EditorInfoLabel::formatKeyLabel("Variable type: ");
+ h+=(genVar_)?tr("generated variable"):tr("user variable");
+
+ bool readOnly=defineData->isReadOnly(name.toStdString());
+ if(readOnly)
+ {
+ h+=" (read only)";
+ }
+
+ if(defineIndex_ > 0)
+ {
+ QString definePath=QString::fromStdString(defineData->fullPath());
+ h+=" <br>" + EditorInfoLabel::formatKeyLabel("Inherited from: ") + EditorInfoLabel::formatNodePath(definePath);
+ }
+ header_->setText(h);
+ valueEdit_->setProperty("form","1");
+ nameEdit_->setText(name);
+ valueEdit_->setPlainText(value);
+ valueEdit_->setFocus();
+
+ if(frozen || readOnly)
+ {
+ nameEdit_->setReadOnly(true);
+ valueEdit_->setReadOnly(true);
+
+ QPushButton* sb=buttonBox_->button(QDialogButtonBox::Save);
+ Q_ASSERT(sb);
+ sb->setEnabled(false);
+ }
+
+ messageLabel_->hide();
+
+ readSettings();
+}
+
+VariablePropDialog::~VariablePropDialog()
+{
+#ifdef _UI_VARIABLEITEMWIDGET_DEBUG
+ UserMessage::debug("VariablePropDialog::~VariablePropDialog -->");
+#endif
+ Q_ASSERT(data_);
+ data_->removeObserver(this);
+ writeSettings();
+}
+
+void VariablePropDialog::accept()
+{
+ QString name=nameEdit_->text();
+ //QString value=valueEdit_->toPlainText();
+
+ Q_ASSERT(data_);
+ Q_ASSERT(data_->count() > 0);
+ Q_ASSERT(data_->count() > defineIndex_);
+
+ //var does not exists in SELECTED node
+ if(!data_->data(0)->hasName(name.toStdString()))
+ {
+ for(size_t i=1; i < data_->count(); i++)
+ {
+ //but exists in one of the parents
+ if(data_->data(i)->hasName(name.toStdString()))
+ {
+ QString type=QString::fromStdString(data_->data(i)->type());
+ QString path =QString::fromStdString(data_->data(i)->fullPath());
+ if(QMessageBox::question(0,tr("Confirm: create new variable"),
+ tr("Variable <b>") + name + tr("</b> is originally defined in ") + type + " <b>" + path +
+ tr("</b>. A new user variable will be created for ") + nodeType_ + " <b>" + nodeName_ +
+ tr("</b> and shadow the original one.<br><br>Do you want to proceed?"),
+ QMessageBox::Ok|QMessageBox::Cancel,QMessageBox::Cancel) == QMessageBox::Cancel)
+ {
+ return;
+ }
+ else
+ {
+ QDialog::accept();
+ return;
+ }
+ }
+ }
+
+ //It is a ne variable
+ if(QMessageBox::question(0,tr("Confirm: create new variable"),
+ tr("You are about to create a <b>new</b> variable in ") + nodeType_ + " <b>" + nodeName_ + "</b>." +
+ tr("<br>Do you want to proceed?"),
+ QMessageBox::Ok|QMessageBox::Cancel,QMessageBox::Cancel) == QMessageBox::Cancel)
+ {
+ return;
+ }
+ else
+ {
+ QDialog::accept();
+ return;
+ }
+ }
+ else if(data_->data(0)->isGenVar(name.toStdString()))
+ {
+ if(QMessageBox::question(0,QObject::tr("Confirm: change variable"),
+ tr("You are about to modify a <b>generated variable</b>.<br>Do you want to proceed?"),
+ QMessageBox::Ok|QMessageBox::Cancel,QMessageBox::Cancel) == QMessageBox::Cancel)
+ {
+ return;
+ }
+ else
+ {
+ QDialog::accept();
+ return;
+ }
+ }
+
+ QDialog::accept();
+}
+
+void VariablePropDialog::on_nameEdit__textEdited(QString)
+{
+ messageLabel_->hide();
+}
+
+void VariablePropDialog::on_valueEdit__textChanged()
+{
+ messageLabel_->hide();
+}
+
+QString VariablePropDialog::name() const
+{
+ return nameEdit_->text();
+}
+
+QString VariablePropDialog::value() const
+{
+ return valueEdit_->toPlainText();
+}
+
+void VariablePropDialog::notifyCleared(VariableModelDataHandler*)
+{
+ //data_->removeObserver(this);
+ //cleared_=true;
+ close();
+
+ /*
+ messageLabel_->showWarning(nodeTypeCapital_ + " <b>" + nodeName_ +
+ "</b> is not the node to modify any more in the Variables panel. Please close the dialog!");
+
+ suspendEdit(true);
+
+ data_->removeObserver(this);
+ cleared_=true;
+ */
+}
+
+void VariablePropDialog::notifyUpdated(VariableModelDataHandler*)
+{
+ QString name=nameEdit_->text();
+ QString value=valueEdit_->toPlainText();
+
+ bool st=false;
+ QString v=QString::fromStdString(data_->value(defineNodeName_.toStdString(),name.toStdString(),st));
+ if(!st)
+ {
+ messageLabel_->showWarning("Variable <b>" + name + "</b> is not defined any more in " + defineNodeType_ +
+ " <b>" + defineNodeName_ + "</b>!");
+ }
+ else if(v != value)
+ {
+ messageLabel_->showWarning("The value of variable <b>" + name + "</b> changed in " + defineNodeType_ +
+ " <b>" + defineNodeName_ + "</b>!");
+ }
+ else
+ {
+ messageLabel_->hide();
+ }
+}
+
+void VariablePropDialog::slotSuspendedChanged(bool s)
+{
+ if(cleared_)
+ return;
+
+ if(s)
+ {
+ messageLabel_->showWarning("The server holding " + nodeType_ + " <b>" + nodeName_ +
+ "</b> is being reloaded. \
+ Until it is finished variables <b>cannot be edited<b>!");
+
+ suspendEdit(true);
+ }
+ else
+ {
+ messageLabel_->clear();
+ messageLabel_->hide();
+ suspendEdit(false);
+ }
+}
+
+void VariablePropDialog::suspendEdit(bool st)
+{
+ if(st)
+ {
+ QPushButton* sb=buttonBox_->button(QDialogButtonBox::Save);
+ Q_ASSERT(sb);
+ sb->setEnabled(false);
+ form_->setEnabled(false);
+ }
+ else
+ {
+ QPushButton* sb=buttonBox_->button(QDialogButtonBox::Save);
+ Q_ASSERT(sb);
+ sb->setEnabled(true);
+ form_->setEnabled(true);
+ }
+}
+
+void VariablePropDialog::writeSettings()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ Q_ASSERT(cs);
+ QSettings settings(QString::fromStdString(cs->qtSettingsFile("VariablePropDialog")),
+ QSettings::NativeFormat);
+
+ //We have to clear it not to remember all the previous windows
+ settings.clear();
+
+ settings.beginGroup("main");
+ settings.setValue("size",size());
+ settings.endGroup();
+}
+
+void VariablePropDialog::readSettings()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ Q_ASSERT(cs);
+ QSettings settings(QString::fromStdString(cs->qtSettingsFile("VariablePropDialog")),
+ QSettings::NativeFormat);
+
+ settings.beginGroup("main");
+ if(settings.contains("size"))
+ {
+ resize(settings.value("size").toSize());
+ }
+ else
+ {
+ resize(QSize(350,250));
+ }
+
+ settings.endGroup();
+}
+
+
+//======================================
+//
+// VariableAddDialog
+//
+//======================================
+
+VariableAddDialog::VariableAddDialog(VariableModelDataHandler *data,QWidget *parent) :
+ QDialog(parent),
+ data_(data),
+ cleared_(false)
+{
+ setupUi(this);
+
+ init();
+ nameEdit_->setFocus();
+
+ readSettings();
+}
+
+VariableAddDialog::VariableAddDialog(VariableModelDataHandler *data,QString name, QString value,QWidget *parent) :
+ QDialog(parent),
+ data_(data),
+ cleared_(false)
+{
+ setupUi(this);
+
+ init();
+
+ nameEdit_->setText(name + "_copy");
+ valueEdit_->setText(value);
+ nameEdit_->setFocus();
+
+ readSettings();
+}
+
+VariableAddDialog::~VariableAddDialog()
+{
+ data_->removeObserver(this);
+ writeSettings();
+}
+
+void VariableAddDialog::init()
+{
+ setAttribute(Qt::WA_DeleteOnClose);
+ setModal(false);
+
+ Q_ASSERT(data_);
+ Q_ASSERT(data_->count() > 0);
+
+ nodeName_=QString::fromStdString(data_->data(0)->name());
+ nodeType_=QString::fromStdString(data_->data(0)->type());
+ nodeTypeCapital_=nodeType_;
+ if(nodeTypeCapital_.size() > 0)
+ {
+ QChar s=nodeTypeCapital_.at(0);
+ s=s.toUpper();
+ nodeTypeCapital_.replace(0,1,s);
+ }
+ data_->addObserver(this);
+
+ label_->setText(tr("Add new variable to ") +
+ nodeType_ + " <b> " +
+ nodeName_ + "</b>") ;
+ //+ "<br>Path: " +
+ // QString::fromStdString(data_->data(0)->fullPath()));
+
+ messageLabel_->hide();
+}
+
+
+void VariableAddDialog::accept()
+{
+ QString name=nameEdit_->text();
+
+ if(name.simplified().isEmpty())
+ {
+ QMessageBox::critical(0,tr("Invalid variable name"),
+ tr("Variable name cannot be empty! Please specify a valid name!"),
+ QMessageBox::Ok,QMessageBox::Ok);
+ return;
+ }
+
+ Q_ASSERT(data_);
+ Q_ASSERT(data_->count() > 0);
+
+ if(data_->data(0)->hasName(name.toStdString()))
+ {
+ QString q;
+ if(data_->data(0)->isGenVar(name.toStdString()))
+ {
+ q=tr("Generated variable <b>") + name + tr("</b> is already defined in ") +
+ nodeType_ + " <b>" + nodeName_ + "</b>" +
+ tr("</b>. A new user variable will be created and the original variable will be hidden. \
+ <br>Do you want to proceed?");
+ }
+ else
+ {
+ q=tr("User variable <b>") + name + tr("</b> is already defined in ") +
+ nodeType_ + " <b>" + nodeName_ + "</b>" +
+ tr(".<br>Do you want to overwrite it?");
+ }
+
+ if(QMessageBox::question(0,tr("Confirm: overwrite variable"),q,
+ QMessageBox::Ok|QMessageBox::Cancel,QMessageBox::Cancel) == QMessageBox::Cancel)
+ {
+ return;
+ }
+ else
+ {
+ QDialog::accept();
+ }
+ return;
+ }
+
+ for(size_t i=1; i <data_->count(); i++)
+ {
+ if(data_->data(i)->hasName(name.toStdString()))
+ {
+ QString nodeName=QString::fromStdString(data_->data(i)->name());
+ QString nodeType=QString::fromStdString(data_->data(i)->type());
+
+ QString q;
+ if(data_->data(i)->isGenVar(name.toStdString()))
+ {
+ q=tr("Generated variable");
+ }
+ else
+ {
+ q=tr("User variable");
+ }
+ q+=" <b>" + name + tr("</b> is already defined in ") +
+ nodeType + " <b>" + nodeName + "</b>" +
+ tr("</b>. A new user variable will be created for ") + nodeType_ + " <b>" +
+ nodeName_ + tr(" </b> and shadow the original one. \
+ <br>Do you want to proceed?");
+
+ if(QMessageBox::question(0,tr("Confirm: overwrite variable"),q,
+ QMessageBox::Ok|QMessageBox::Cancel,QMessageBox::Cancel) == QMessageBox::Cancel)
+ {
+ return;
+ }
+ else
+ {
+ QDialog::accept();
+ }
+ return;
+ }
+ }
+
+ QDialog::accept();
+}
+
+QString VariableAddDialog::name() const
+{
+ return nameEdit_->text();
+}
+
+QString VariableAddDialog::value() const
+{
+ return valueEdit_->text();
+}
+
+void VariableAddDialog::notifyCleared(VariableModelDataHandler*)
+{
+ close();
+
+#if 0
+ messageLabel_->showWarning(nodeTypeCapital_ + " <b>" + nodeName_ +
+ "</b> is not the node to modify any more in the Variables panel. Please close the dialog!");
+
+ suspendEdit(true);
+
+ data_->removeObserver(this);
+ cleared_=true;
+#endif
+}
+
+void VariableAddDialog::slotSuspendedChanged(bool s)
+{
+ if(cleared_)
+ return;
+
+ if(s)
+ {
+ messageLabel_->showWarning("The server holding " + nodeType_ + " <b>" + nodeName_ +
+ "</b> is being reloaded. \
+ Until it is finished variables <b>cannot be added<b>!");
+
+ suspendEdit(true);
+ }
+ else
+ {
+ messageLabel_->clear();
+ messageLabel_->hide();
+ suspendEdit(false);
+ }
+}
+
+void VariableAddDialog::suspendEdit(bool st)
+{
+ if(st)
+ {
+ QPushButton* sb=buttonBox_->button(QDialogButtonBox::Ok);
+ Q_ASSERT(sb);
+ sb->setEnabled(false);
+ form_->setEnabled(false);
+ }
+ else
+ {
+ QPushButton* sb=buttonBox_->button(QDialogButtonBox::Ok);
+ Q_ASSERT(sb);
+ sb->setEnabled(true);
+ form_->setEnabled(true);
+ }
+}
+
+void VariableAddDialog::writeSettings()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ Q_ASSERT(cs);
+ QSettings settings(QString::fromStdString(cs->qtSettingsFile("VariableAddDialog")),
+ QSettings::NativeFormat);
+
+ //We have to clear it not to remember all the previous windows
+ settings.clear();
+
+ settings.beginGroup("main");
+ settings.setValue("size",size());
+ settings.endGroup();
+}
+
+void VariableAddDialog::readSettings()
+{
+ SessionItem* cs=SessionHandler::instance()->current();
+ Q_ASSERT(cs);
+ QSettings settings(QString::fromStdString(cs->qtSettingsFile("VariableAddDialog")),
+ QSettings::NativeFormat);
+
+ settings.beginGroup("main");
+ if(settings.contains("size"))
+ {
+ resize(settings.value("size").toSize());
+ }
+ else
+ {
+ resize(QSize(320,220));
+ }
+
+ settings.endGroup();
+}
+
+//========================================================
+//
+// VariableItemWidget
+//
+//========================================================
+
+VariableItemWidget::VariableItemWidget(QWidget *parent) : shadowProp_(0)
+{
+ //This item displays all the ancestors of the info object
+ useAncestors_=true;
+
+ setupUi(this);
+
+ data_=new VariableModelDataHandler();
+
+ //The model and the sort-filter model
+ model_=new VariableModel(data_,this);
+ sortModel_= new VariableSortModel(model_,this);
+
+ //Set the model on the view
+ varView->setModel(sortModel_);
+
+ varView->setSelectionBehavior(QAbstractItemView::SelectRows);
+ varView->setSelectionMode(QAbstractItemView::SingleSelection);
+
+ //Shadowed variables
+ bool showShadowed = true;
+ //We do not want to observe it!
+ shadowProp_=VConfig::instance()->find("panel.variable.showShadowed");
+ if(shadowProp_)
+ {
+ showShadowed=shadowProp_->value().toBool();
+ }
+ sortModel_->slotShowShadowed(showShadowed);
+ shadowTb->setChecked(showShadowed);
+
+ //Search and filter interface: we have a menu attached to a toolbutton and a
+ //stackedwidget connected up.
+
+ //Populate the toolbuttons menu
+ findModeTb->addAction(actionFilter);
+ findModeTb->addAction(actionSearch);
+
+ //The filter line editor
+ filterLine_=new LineEdit;
+ stackedWidget->addWidget(filterLine_);
+
+ //The search line editor. Its a custom widget handling its own signals and slots.
+ searchLine_=new VariableSearchLine(this);
+ stackedWidget->addWidget(searchLine_);
+ searchLine_->setView(varView);
+
+ //The filter editor changes
+ connect(filterLine_,SIGNAL(textChanged(QString)),
+ this,SLOT(slotFilterTextChanged(QString)));
+
+ //The selection changes in the view
+ connect(varView->selectionModel(),SIGNAL(currentChanged(QModelIndex,QModelIndex)),
+ this,SLOT(slotItemSelected(QModelIndex,QModelIndex)));
+
+ //Init the find mode selection
+ if(sortModel_->matchMode() == VariableSortModel::FilterMode)
+ {
+ actionFilter->trigger();
+ }
+ else
+ {
+ actionSearch->trigger();
+ }
+
+ //Add context menu actions to the view
+ QAction* sep1=new QAction(this);
+ sep1->setSeparator(true);
+ QAction* sep2=new QAction(this);
+ sep2->setSeparator(true);
+ QAction* sep3=new QAction(this);
+ sep3->setSeparator(true);
+
+ //Build context menu
+ varView->addAction(actionAdd);
+ varView->addAction(sep1);
+ varView->addAction(actionCopy);
+ varView->addAction(actionCopyFull);
+ //varView->addAction(actionPaste);
+ varView->addAction(sep2);
+ varView->addAction(actionDelete);
+ varView->addAction(sep3);
+ varView->addAction(actionProp);
+
+ //Add actions for the toolbuttons
+ addTb->setDefaultAction(actionAdd);
+ deleteTb->setDefaultAction(actionDelete);
+ propTb->setDefaultAction(actionProp);
+ exportTb->setDefaultAction(actionExport);
+
+ //TODO: implemet it
+ actionExport->setEnabled(false);
+
+ //Initialise action state (it depends on the selection)
+ checkActionState();
+}
+
+VariableItemWidget::~VariableItemWidget()
+{
+
+}
+
+QWidget* VariableItemWidget::realWidget()
+{
+ return this;
+}
+
+//A new info object is set
+void VariableItemWidget::reload(VInfo_ptr info)
+{
+ assert(active_);
+
+ if(suspended_)
+ return;
+
+ clearContents();
+ adjust(info);
+
+ data_->reload(info);
+ varView->expandAll();
+ varView->resizeColumnToContents(0);
+
+ if(data_->count() > 0)
+ {
+ actionAdd->setText(tr("Add &new variable to ") +
+ QString::fromStdString(data_->data(0)->name()));
+
+ actionAdd->setToolTip(tr("Add new variable to ") +
+ "<b>" + QString::fromStdString(data_->data(0)->name()) + "</b>");
+ }
+}
+
+void VariableItemWidget::clearContents()
+{
+ InfoPanelItem::clear();
+ data_->clear();
+ actionAdd->setText(tr("Add &new variable"));
+}
+
+
+void VariableItemWidget::slotItemSelected(const QModelIndex& idx,const QModelIndex& prevIdx)
+{
+#ifdef _UI_VARIABLEITEMWIDGET_DEBUG
+ UserMessage::debug("VariableItemWidget::slotItemSelected -->");
+ qDebug() << " current:" << idx << "prev:" << prevIdx;
+ qDebug() << " in view:" << varView->currentIndex();
+#endif
+
+ checkActionState();
+}
+
+void VariableItemWidget::updateState(const FlagSet<ChangeFlag>& flags)
+{
+ if(flags.isSet(SuspendedChanged))
+ Q_EMIT suspendedChanged(suspended_);
+
+ checkActionState();
+}
+
+void VariableItemWidget::checkActionState()
+{
+ QModelIndex vIndex=varView->currentIndex();
+ QModelIndex index=sortModel_->mapToSource(vIndex);
+
+ if(suspended_)
+ {
+ actionAdd->setEnabled(false);
+ actionProp->setEnabled(false);
+ actionDelete->setEnabled(false);
+ actionCopy->setEnabled(false);
+ actionCopyFull->setEnabled(false);
+ return;
+ }
+
+ //The index is invalid (no selection)
+ if(!index.isValid())
+ {
+ actionAdd->setEnabled(false);
+ actionProp->setEnabled(false);
+ actionDelete->setEnabled(false);
+ actionCopy->setEnabled(false);
+ actionCopyFull->setEnabled(false);
+ }
+ else
+ {
+ //Variables
+ if(model_->isVariable(index))
+ {
+ if(frozen_)
+ {
+ actionAdd->setEnabled(false);
+ actionDelete->setEnabled(false);
+ }
+ else
+ {
+ actionAdd->setEnabled(true);
+ int block=-1;
+ if(model_->indexToData(index,block))
+ {
+ if(block==0)
+ actionDelete->setEnabled(true);
+ else
+ actionDelete->setEnabled(false);
+ }
+ else
+ actionDelete->setEnabled(false);
+ }
+ actionProp->setEnabled(true);
+ actionCopy->setEnabled(true);
+ actionCopyFull->setEnabled(true);
+ }
+ //Server or nodes
+ else
+ {
+ if(frozen_)
+ {
+ actionAdd->setEnabled(false);
+ actionDelete->setEnabled(false);
+ }
+ else
+ {
+ actionAdd->setEnabled(true);
+ actionDelete->setEnabled(false);
+ }
+ actionProp->setEnabled(false);
+ actionCopy->setEnabled(false);
+ actionCopyFull->setEnabled(false);
+ }
+ }
+}
+
+void VariableItemWidget::editItem(const QModelIndex& index)
+{
+ QString name;
+ QString value;
+ bool genVar;
+
+#ifdef _UI_VARIABLEITEMWIDGET_DEBUG
+ UserMessage::debug("VariableItemWidget::editItem -->");
+ qDebug() << " index:" << index;
+#endif
+
+ QModelIndex vIndex=sortModel_->mapToSource(index);
+
+#ifdef _UI_VARIABLEITEMWIDGET_DEBUG
+ qDebug() << " vIndex:" << vIndex;
+#endif
+
+ int block=-1;
+ VariableModelData* data=model_->indexToData(vIndex,block);
+
+#ifdef _UI_VARIABLEITEMWIDGET_DEBUG
+ UserMessage::qdebug(" block=" + QString::number(block));
+#endif
+
+ //Get the data from the model
+ if(data && model_->variable(vIndex,name,value,genVar))
+ {
+ Q_ASSERT(data_->count() > 0);
+ Q_ASSERT(block >=0);
+
+ //Start edit dialog (will be deleted on close - deleteOnClose is set)
+ VariablePropDialog* d=new VariablePropDialog(data_,block,name,value,frozen_,this);
+ connect(d,SIGNAL(accepted()),
+ this,SLOT(slotVariableEdited()));
+ connect(this,SIGNAL(suspendedChanged(bool)),
+ d,SLOT(slotSuspendedChanged(bool)));
+ d->show();
+
+#ifdef _UI_VARIABLEITEMWIDGET_DEBUG
+ qDebug() << "selected after:" << varView->currentIndex();
+#endif
+ }
+
+#ifdef _UI_VARIABLEITEMWIDGET_DEBUG
+ UserMessage::debug("<-- VariableItemWidget::editItem");
+#endif
+
+}
+
+void VariableItemWidget::duplicateItem(const QModelIndex& index)
+{
+ if(frozen_)
+ return;
+
+#if 0
+ QString name;
+ QString value;
+ bool genVar;
+
+ QModelIndex vIndex=sortModel_->mapToSource(index);
+
+ VariableModelData* data=model_->indexToData(vIndex);
+
+ //Get the data from the model
+ if(data && model_->variable(vIndex,name,value,genVar))
+ {
+ //Start add dialog
+ VariableAddDialog d(data,name,value,this);
+
+ if(d.exec() == QDialog::Accepted)
+ {
+ data->alter(d.name().toStdString(),d.value().toStdString());
+ //data->add(d.name().toStdString(),d.value().toStdString());
+ }
+ }
+#endif
+
+}
+
+void VariableItemWidget::addItem(const QModelIndex& index)
+{
+ if(frozen_)
+ return;
+
+ if(data_->count() > 0)
+ {
+ //Start add dialog (will be deleted on close - deleteOnClose is set)
+ VariableAddDialog* d=new VariableAddDialog(data_,this);
+ connect(d,SIGNAL(accepted()),
+ this,SLOT(slotVariableAdded()));
+ connect(this,SIGNAL(suspendedChanged(bool)),
+ d,SLOT(slotSuspendedChanged(bool)));
+ d->show();
+
+ }
+}
+
+void VariableItemWidget::removeItem(const QModelIndex& index)
+{
+ if(frozen_)
+ return;
+
+ QString name;
+ QString value;
+ bool genVar;
+
+ QModelIndex vIndex=sortModel_->mapToSource(index);
+
+ VariableModelData* data=model_->indexToData(vIndex);
+
+ //Get the data from the model
+ if(data && model_->variable(vIndex,name,value,genVar))
+ {
+ if(QMessageBox::question(0,tr("Confirm: delete variable"),
+ tr("Are you sure that you want to delete variable <b>") + name + "</b> from " +
+ QString::fromStdString(data->type()) + " <b>" + QString::fromStdString(data->name()) + "</b>?",
+ QMessageBox::Ok | QMessageBox::Cancel,QMessageBox::Cancel) == QMessageBox::Ok)
+ {
+ //data might have deleted while the dialog was open
+ //so we alter it via the model that can properly lookup the
+ //data object
+ model_->removeVariable(vIndex,name,value);
+ }
+ }
+}
+
+void VariableItemWidget::slotVariableEdited()
+{
+ VariablePropDialog* d=static_cast<VariablePropDialog*>(sender());
+ Q_ASSERT(d);
+
+ model_->alterVariable(QModelIndex(),d->name(),d->value());
+}
+
+void VariableItemWidget::slotVariableAdded()
+{
+ VariableAddDialog* d=static_cast<VariableAddDialog*>(sender());
+ Q_ASSERT(d);
+ Q_ASSERT(data_->count() > 0);
+ data_->data(0)->alter(d->name().toStdString(),d->value().toStdString());
+}
+
+void VariableItemWidget::on_varView_doubleClicked(const QModelIndex& index)
+{
+ if(!suspended_)
+ editItem(index);
+}
+
+void VariableItemWidget::on_actionProp_triggered()
+{
+ QModelIndex index=varView->currentIndex();
+ editItem(index);
+}
+
+void VariableItemWidget::on_actionAdd_triggered()
+{
+ QModelIndex index=varView->currentIndex();
+ addItem(index);
+}
+
+void VariableItemWidget::on_actionDelete_triggered()
+{
+ QModelIndex index=varView->currentIndex();
+ removeItem(index);
+}
+
+void VariableItemWidget::on_actionFilter_triggered()
+{
+ findModeTb->setIcon(actionFilter->icon());
+ sortModel_->setMatchMode(VariableSortModel::FilterMode);
+ filterLine_->clear();
+ searchLine_->clear();
+
+ //Notify stackedwidget
+ stackedWidget->setCurrentIndex(0);
+}
+
+void VariableItemWidget::on_actionSearch_triggered()
+{
+ findModeTb->setIcon(actionSearch->icon());
+ sortModel_->setMatchMode(VariableSortModel::SearchMode);
+ filterLine_->clear();
+ searchLine_->clear();
+
+ //Notify stackedwidget
+ stackedWidget->setCurrentIndex(1);
+
+}
+
+void VariableItemWidget::on_actionCopy_triggered()
+{
+ QModelIndex idx=sortModel_->mapToSource(varView->currentIndex());
+ QString name, val;
+ bool gen;
+
+ if(model_->variable(idx,name,val,gen))
+ {
+ QString txt;
+ if(idx.column() == 0)
+ toClipboard(name);
+ else if(idx.column() == 1)
+ toClipboard(val);
+ }
+}
+
+void VariableItemWidget::on_actionCopyFull_triggered()
+{
+ QModelIndex idx=sortModel_->mapToSource(varView->currentIndex());
+ QString name, val;
+ bool gen;
+
+ if(model_->variable(idx,name,val,gen))
+ {
+ toClipboard(name + "=" + val);
+ }
+}
+
+void VariableItemWidget::on_shadowTb_clicked(bool showShadowed)
+{
+ if(shadowProp_)
+ {
+ shadowProp_->setValue(showShadowed);
+ qDebug() << shadowProp_->value().toBool();
+ }
+ sortModel_->slotShowShadowed(showShadowed);
+}
+
+void VariableItemWidget::toClipboard(QString txt) const
+{
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+ QClipboard* cb=QGuiApplication::clipboard();
+ cb->setText(txt, QClipboard::Clipboard);
+ cb->setText(txt, QClipboard::Selection);
+#else
+ QClipboard* cb=QApplication::clipboard();
+ cb->setText(txt, QClipboard::Clipboard);
+ cb->setText(txt, QClipboard::Selection);
+#endif
+}
+
+
+void VariableItemWidget::slotFilterTextChanged(QString text)
+{
+#ifdef _UI_VARIABLEITEMWIDGET_DEBUG
+ UserMessage::debug("VariableItemWidget::slotFilterTextChanged -->");
+ qDebug() << "selected before:" << varView->currentIndex();
+#endif
+ sortModel_->setMatchText(text);
+#ifdef _UI_VARIABLEITEMWIDGET_DEBUG
+ qDebug() << "selected after:" << varView->currentIndex();
+ qDebug() << sortModel_->data(varView->currentIndex());
+ //UserMessage::debug("<-- VariableItemWidget::slotFilterTextChanged");
+#endif
+}
+
+
+void VariableItemWidget::nodeChanged(const VNode* node, const std::vector<ecf::Aspect::Type>& aspect)
+{
+#ifdef _UI_VARIABLEITEMWIDGET_DEBUG
+ UserMessage::debug("VariableItemWidget::nodeChanged -->");
+ qDebug() << "selected before:" << varView->currentIndex();
+#endif
+
+ QModelIndex cIdx=sortModel_->mapToSource(varView->currentIndex());
+
+ if(data_->nodeChanged(node,aspect))
+ {
+#ifdef _UI_VARIABLEITEMWIDGET_DEBUG
+ UserMessage::debug(" reselect currentIndex!");
+#endif
+ //After any change we need to reselect the current row. See issue ECFLOW-613.
+ reselectCurrent();
+ }
+#ifdef _UI_VARIABLEITEMWIDGET_DEBUG
+ qDebug() << "selected after:" << varView->currentIndex();
+ UserMessage::debug("<-- VariableItemWidget::nodeChanged");
+#endif
+}
+
+void VariableItemWidget::defsChanged(const std::vector<ecf::Aspect::Type>& aspect)
+{
+#ifdef _UI_VARIABLEITEMWIDGET_DEBUG
+ UserMessage::debug("VariableItemWidget::defsChanged -->");
+ qDebug() << "selected before:" << varView->currentIndex();
+#endif
+ if(data_->defsChanged(aspect))
+ {
+#ifdef _UI_VARIABLEITEMWIDGET_DEBUG
+ UserMessage::debug(" reselect currentIndex!");
+#endif
+ //After any change we need to reselect the current row. See issue ECFLOW-613.
+ reselectCurrent();
+ }
+#ifdef _UI_VARIABLEITEMWIDGET_DEBUG
+ qDebug() << "selected after:" << varView->currentIndex();
+ UserMessage::debug("<-- VariableItemWidget::defsChanged");
+#endif
+}
+
+//This is a fairly complicated solution but reselection does not work otherwise
+//if the second column is selected initially!!!
+void VariableItemWidget::reselectCurrent()
+{
+ QModelIndex idx=sortModel_->mapToSource(varView->currentIndex());
+ if(idx.column() == 1)
+ {
+ idx=model_->index(idx.row(),0,idx.parent());
+ }
+ varView->selectionModel()->clear();
+ QModelIndex sortIdx=sortModel_->mapFromSource(idx);
+ varView->selectionModel()->setCurrentIndex(sortIdx,QItemSelectionModel::Rows|
+ QItemSelectionModel::Select);
+}
+
+//Register at the factory
+static InfoPanelItemMaker<VariableItemWidget> maker1("variable");
diff --git a/Viewer/src/VariableItemWidget.hpp b/Viewer/src/VariableItemWidget.hpp
new file mode 100644
index 0000000..123a0d8
--- /dev/null
+++ b/Viewer/src/VariableItemWidget.hpp
@@ -0,0 +1,159 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VARIABLEITEMWIDGET_HPP_
+#define VARIABLEITEMWIDGET_HPP_
+
+#include "ui_VariablePropDialog.h"
+#include "ui_VariableAddDialog.h"
+#include "ui_VariableItemWidget.h"
+
+#include "InfoPanelItem.hpp"
+#include "VariableModelDataObserver.hpp"
+#include "VInfo.hpp"
+
+class LineEdit;
+class VariableModel;
+class VariableModelData;
+class VariableModelDataHandler;
+class VariableSortModel;
+class VariableSearchLine;
+class VProperty;
+
+class VariablePropDialog : public QDialog, public VariableModelDataObserver, private Ui::VariablePropDialog
+{
+Q_OBJECT
+
+public:
+ VariablePropDialog(VariableModelDataHandler* data,int defineIndex,QString name,QString value,bool frozen,QWidget* parent=0);
+ ~VariablePropDialog();
+
+ QString name() const;
+ QString value() const;
+
+ void notifyCleared(VariableModelDataHandler*);
+ void notifyUpdated(VariableModelDataHandler*);
+
+public Q_SLOTS:
+ void accept();
+ void slotSuspendedChanged(bool s);
+
+protected Q_SLOTS:
+ void on_nameEdit__textEdited(QString);
+ void on_valueEdit__textChanged();
+
+protected:
+ void suspendEdit(bool);
+ void readSettings();
+ void writeSettings();
+
+ bool genVar_;
+ VariableModelDataHandler* data_;
+ int defineIndex_;
+ QString oriName_;
+ QString nodeName_;
+ QString nodeType_;
+ QString nodeTypeCapital_;
+ QString defineNodeName_;
+ QString defineNodeType_;
+ bool cleared_;
+
+};
+
+class VariableAddDialog : public QDialog, public VariableModelDataObserver, private Ui::VariableAddDialog
+{
+Q_OBJECT
+
+public:
+ VariableAddDialog(VariableModelDataHandler* data,QWidget* parent=0);
+ VariableAddDialog(VariableModelDataHandler* data,QString name,QString value,QWidget* parent=0);
+ ~VariableAddDialog();
+
+ QString name() const;
+ QString value() const;
+
+ void notifyCleared(VariableModelDataHandler*);
+ void notifyUpdated(VariableModelDataHandler*) {}
+
+public Q_SLOTS:
+ void accept();
+ void slotSuspendedChanged(bool s);
+
+protected:
+ void init();
+ void suspendEdit(bool);
+ void readSettings();
+ void writeSettings();
+
+ VariableModelDataHandler* data_;
+ QString nodeName_;
+ QString nodeType_;
+ QString nodeTypeCapital_;
+ bool cleared_;
+};
+
+
+class VariableItemWidget : public QWidget, public InfoPanelItem, protected Ui::VariableItemWidget
+{
+Q_OBJECT
+
+public:
+ explicit VariableItemWidget(QWidget *parent=0);
+ ~VariableItemWidget();
+
+ void reload(VInfo_ptr);
+ QWidget* realWidget();
+ void clearContents();
+
+public Q_SLOTS:
+ void slotFilterTextChanged(QString text);
+ void slotItemSelected(const QModelIndex& idx,const QModelIndex& prevIdx);
+
+protected Q_SLOTS:
+ void on_actionProp_triggered();
+ void on_actionAdd_triggered();
+ void on_actionDelete_triggered();
+ void on_varView_doubleClicked(const QModelIndex& index);
+ void on_actionFilter_triggered();
+ void on_actionSearch_triggered();
+ void on_actionCopy_triggered();
+ void on_actionCopyFull_triggered();
+ void on_shadowTb_clicked(bool showShadowed);
+ void slotVariableEdited();
+ void slotVariableAdded();
+
+Q_SIGNALS:
+ void suspendedChanged(bool);
+
+protected:
+ void checkActionState();
+ void editItem(const QModelIndex& index);
+ void duplicateItem(const QModelIndex& index);
+ void addItem(const QModelIndex& index);
+ void removeItem(const QModelIndex& index);
+ void updateState(const ChangeFlags&);
+ void toClipboard(QString txt) const;
+ void reselectCurrent();
+
+ void nodeChanged(const VNode*, const std::vector<ecf::Aspect::Type>&);
+ void defsChanged(const std::vector<ecf::Aspect::Type>&);
+
+ VariableModelDataHandler* data_;
+ VariableModel* model_;
+ VariableSortModel* sortModel_;
+
+ LineEdit* filterLine_;
+ VariableSearchLine *searchLine_;
+
+ VProperty* shadowProp_;
+};
+
+#endif
+
diff --git a/Viewer/src/VariableItemWidget.ui b/Viewer/src/VariableItemWidget.ui
new file mode 100644
index 0000000..4c5eca9
--- /dev/null
+++ b/Viewer/src/VariableItemWidget.ui
@@ -0,0 +1,261 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>VariableItemWidget</class>
+ <widget class="QWidget" name="VariableItemWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>615</width>
+ <height>482</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" stretch="0,1">
+ <property name="spacing">
+ <number>2</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QToolButton" name="findModeTb">
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="popupMode">
+ <enum>QToolButton::InstantPopup</enum>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonIconOnly</enum>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QStackedWidget" name="stackedWidget"/>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QToolButton" name="shadowTb">
+ <property name="toolTip">
+ <string>Show <b>shadowed</b> variables. A variable is shadowed when it is redefined in one of the descendants of its node shown in this panel.</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/show_shadowed.svg</normaloff>:/viewer/show_shadowed.svg</iconset>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="addTb">
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="deleteTb">
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="propTb">
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="exportTb">
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="VariableView" name="varView"/>
+ </item>
+ </layout>
+ <action name="actionAdd">
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/images/add.svg</normaloff>:/viewer/images/add.svg</iconset>
+ </property>
+ <property name="text">
+ <string>Add &new variable</string>
+ </property>
+ <property name="toolTip">
+ <string>Add new variable</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+N</string>
+ </property>
+ </action>
+ <action name="actionProp">
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/edit.svg</normaloff>:/viewer/edit.svg</iconset>
+ </property>
+ <property name="text">
+ <string>&Edit variable</string>
+ </property>
+ <property name="toolTip">
+ <string>See/edit variable's properties</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+E</string>
+ </property>
+ </action>
+ <action name="actionDelete">
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/images/close.svg</normaloff>:/viewer/images/close.svg</iconset>
+ </property>
+ <property name="text">
+ <string>&Delete variable</string>
+ </property>
+ <property name="toolTip">
+ <string>Delete variable</string>
+ </property>
+ <property name="shortcut">
+ <string>Del</string>
+ </property>
+ </action>
+ <action name="actionExport">
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/filesave.svg</normaloff>:/viewer/filesave.svg</iconset>
+ </property>
+ <property name="text">
+ <string>E&xport</string>
+ </property>
+ <property name="toolTip">
+ <string>Export variables</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+S</string>
+ </property>
+ </action>
+ <action name="actionCopy">
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/editcopy.svg</normaloff>:/viewer/editcopy.svg</iconset>
+ </property>
+ <property name="text">
+ <string>&Copy item</string>
+ </property>
+ <property name="toolTip">
+ <string>Copy variable</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+C</string>
+ </property>
+ </action>
+ <action name="actionPaste">
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/editpaste.svg</normaloff>:/viewer/editpaste.svg</iconset>
+ </property>
+ <property name="text">
+ <string>Pa&ste as new</string>
+ </property>
+ <property name="toolTip">
+ <string>Paste as new variable</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+V</string>
+ </property>
+ </action>
+ <action name="actionFilter">
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/filter_decor.svg</normaloff>:/viewer/filter_decor.svg</iconset>
+ </property>
+ <property name="text">
+ <string>&Filter mode</string>
+ </property>
+ <property name="toolTip">
+ <string>Filter mode</string>
+ </property>
+ </action>
+ <action name="actionSearch">
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/search_decor.svg</normaloff>:/viewer/search_decor.svg</iconset>
+ </property>
+ <property name="text">
+ <string>&Search mode</string>
+ </property>
+ <property name="toolTip">
+ <string>Search mode</string>
+ </property>
+ </action>
+ <action name="actionCopyFull">
+ <property name="text">
+ <string>Copy name and value</string>
+ </property>
+ <property name="toolTip">
+ <string>Copy variable's name and value</string>
+ </property>
+ </action>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>VariableView</class>
+ <extends>QTreeView</extends>
+ <header location="global">VariableView.hpp</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Viewer/src/VariableModel.cpp b/Viewer/src/VariableModel.cpp
new file mode 100644
index 0000000..163c950
--- /dev/null
+++ b/Viewer/src/VariableModel.cpp
@@ -0,0 +1,759 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "VariableModel.hpp"
+
+#include <QColor>
+#include <QDebug>
+
+#include "ServerHandler.hpp"
+#include "UserMessage.hpp"
+#include "VariableModelData.hpp"
+
+QColor VariableModel::varCol_=QColor(40,41,42);
+//QColor VariableModel::genVarCol_=QColor(34,51,136);
+QColor VariableModel::genVarCol_=QColor(0,115,48);
+QColor VariableModel::shadowCol_=QColor(130,130,130);
+QColor VariableModel::blockBgCol_=QColor(122,122,122);
+QColor VariableModel::blockFgCol_=QColor(255,255,255);
+
+#define _UI_VARIABLEMODEL_DEBUG
+
+//=======================================================================
+//
+// VariabletModel
+//
+//=======================================================================
+
+VariableModel::VariableModel(VariableModelDataHandler* data,QObject *parent) :
+ QAbstractItemModel(parent),
+ data_(data)
+{
+ connect(data_,SIGNAL(reloadBegin()),
+ this,SLOT(slotReloadBegin()));
+
+ connect(data_,SIGNAL(reloadEnd()),
+ this,SLOT(slotReloadEnd()));
+
+ connect(data_,SIGNAL(addRemoveBegin(int,int)),
+ this,SLOT(slotAddRemoveBegin(int,int)));
+
+ connect(data_,SIGNAL(addRemoveEnd(int)),
+ this,SLOT(slotAddRemoveEnd(int)));
+
+ connect(data_,SIGNAL(dataChanged(int)),
+ this,SLOT(slotDataChanged(int)));
+
+ connect(data_,SIGNAL(rerunFilter()),
+ this,SIGNAL(rerunFilter()));
+}
+
+bool VariableModel::hasData() const
+{
+ return (data_->count() > 0);
+}
+
+int VariableModel::columnCount( const QModelIndex& /*parent */ ) const
+{
+ return 2;
+}
+
+int VariableModel::rowCount( const QModelIndex& parent) const
+{
+
+ //Parent is the root: the item must be a node or a server
+ if(!parent.isValid())
+ {
+ return data_->count();
+ }
+ //The parent is a server or a node
+ else if(!isVariable(parent))
+ {
+ int row=parent.row();
+ return data_->varNum(row);
+ }
+
+ //parent is a variable
+ return 0;
+}
+
+Qt::ItemFlags VariableModel::flags ( const QModelIndex & index) const
+{
+ Qt::ItemFlags defaultFlags;
+
+ defaultFlags=Qt::ItemIsEnabled | Qt::ItemIsSelectable;
+
+ return defaultFlags;
+}
+
+QVariant VariableModel::data( const QModelIndex& index, int role ) const
+{
+ if( !index.isValid())
+ {
+ return QVariant();
+ }
+
+ //Data lookup can be costly so we immediately return a default value for all
+ //the cases where the default should be used.
+ if(role != Qt::DisplayRole && role != Qt::BackgroundRole && role != Qt::ForegroundRole &&
+ role != ReadOnlyRole && role != Qt::ToolTipRole && role != GenVarRole && role != Qt::FontRole &&
+ role != ShadowRole )
+ {
+ return QVariant();
+ }
+
+ int row=index.row();
+ int level=indexToLevel(index);
+
+ //Server or node
+ if(level == 1)
+ {
+ if(role == ReadOnlyRole)
+ return QVariant();
+
+ if(role == Qt:: BackgroundRole)
+ return blockBgCol_;
+
+ else if(role == Qt::ForegroundRole)
+ return blockFgCol_;
+
+
+ VariableModelData *d=data_->data(row);
+ if(!d)
+ {
+ return QVariant();
+ }
+
+ if(index.column() == 0)
+ {
+ if(role == Qt::DisplayRole)
+ {
+ if(index.row() ==0)
+ return "defined in " + QString::fromStdString(d->type()) + " " + QString::fromStdString(d->name());
+ else
+ return "inherited from " + QString::fromStdString(d->type()) + " " + QString::fromStdString(d->name());
+ }
+ }
+
+ return QVariant();
+ }
+
+ //Variables
+ else if (level == 2)
+ {
+ VariableModelData *d=data_->data(index.parent().row());
+ if(!d)
+ {
+ return QVariant();
+ }
+
+ if(role == Qt::ForegroundRole)
+ {
+ if(d->isShadowed(row))
+ {
+ return shadowCol_;
+ }
+
+ //Generated variable
+ if(d->isGenVar(row) && index.column() == 0)
+ return genVarCol_;
+ else
+ return varCol_;
+ }
+ else if(role == Qt::DisplayRole)
+ {
+ if(index.column() == 0)
+ {
+ QString s=QString::fromStdString(d->name(row));
+ //if(d->isGenVar(row))
+ // s+=" (g)";
+ return s;
+ }
+ else if(index.column() == 1)
+ {
+ return QString::fromStdString(d->value(row));
+ }
+ }
+ else if(role == Qt::ToolTipRole)
+ {
+ QString s="User defined variable";
+ if(d->isGenVar(row))
+ {
+ s="Generated variable";
+ }
+ if(d->isReadOnly(row))
+ s+= " (read only)";
+
+ if(d->isShadowed(row))
+ {
+ s+=".<br>Please note that this variable is <b>shadowed</b> i.e. \
+ overwritten in one of the descendants of this node shown in this panel!";
+ }
+ return s;
+ }
+ else if(role == ReadOnlyRole)
+ {
+ return (d->isReadOnly(row))?true:false;
+ }
+
+ else if(role == GenVarRole)
+ {
+ return (d->isGenVar(row))?true:false;
+ }
+
+ else if(role == ShadowRole)
+ {
+ return (d->isShadowed(row))?true:false;
+ }
+
+ return QVariant();
+ }
+
+ return QVariant();
+}
+
+bool VariableModel::variable(const QModelIndex& idx, QString& name,QString& value,bool& genVar) const
+{
+ int block=-1;
+ int row=-1;
+
+ identify(idx,block,row);
+
+ if(row < 0)
+ return false;
+
+ if(block >=0 && block < data_->count())
+ {
+ name=QString::fromStdString(data_->data(block)->name(row));
+ value=QString::fromStdString(data_->data(block)->value(row));
+ genVar=data_->data(block)->isGenVar(row);
+ return true;
+ }
+
+ return false;
+}
+
+bool VariableModel::alterVariable(const QModelIndex& index, QString name,QString value)
+{
+#ifdef _UI_VARIABLEMODEL_DEBUG
+ qDebug() << "DEBUG :" << "VariableModel::alterVariable --> index" << index << " name=" <<
+ name << " value=" << value;
+#endif
+
+ if(data_->count() > 0)
+ {
+ //This will call the ServerComThread so we
+ //do not know if it was successful or not. The model will be
+ //updated through the observer when the value will actually
+ //change.
+ data_->data(0)->alter(name.toStdString(),value.toStdString());
+ }
+
+#if 0
+ int block;
+ int row;
+
+ identify(index,block,row);
+
+#ifdef _UI_VARIABLEMODEL_DEBUG
+ qDebug() << " block=" << block << " row=" << row;
+#endif
+
+ if(block == -1 || row == -1)
+ return false;
+
+ if(block >=0 && block < data_->count())
+ {
+ //This will call the ServerComThread so we
+ //do not know if it was successful or not. The model will be
+ //updated through the observer when the value will actually
+ //change.
+ data_->data(block)->alter(name.toStdString(),value.toStdString());
+ }
+#endif
+
+#ifdef _UI_VARIABLEMODEL_DEBUG
+ UserMessage::debug("<-- VariableModel::alterVariable");
+#endif
+ return false;
+}
+
+bool VariableModel::setVariable(const QModelIndex& index, QString name,QString value)
+{
+ int block;
+ int row;
+
+ identify(index,block,row);
+
+ if(block == -1 || row == -1)
+ return false;
+
+ if(block >=0 && block < data_->count())
+ {
+ //double check
+ if(data_->data(block)->name(row) != name.toStdString())
+ {
+ assert(0);
+ return false;
+ }
+
+ //This will call the ServerComThread so we
+ //do not know if it was successful or not. The model will be
+ //updated through the observer when the value will actually
+ //change.
+ data_->data(block)->setValue(row,value.toStdString());
+ }
+
+ return false;
+}
+
+bool VariableModel::removeVariable(const QModelIndex& index, QString name,QString value)
+{
+ int block;
+ int row;
+
+ identify(index,block,row);
+
+ if(block == -1 || row == -1)
+ return false;
+
+ if(block >=0 && block < data_->count())
+ {
+ //double check
+ if(data_->data(block)->name(row) != name.toStdString())
+ {
+ assert(0);
+ return false;
+ }
+
+ //This will call the ServerComThread so we
+ //do not know if it was succesful. The model will be
+ //updated through the observer when the value will actually
+ //change.
+ data_->data(block)->remove(row,name.toStdString());
+ }
+
+ return false;
+}
+
+QVariant VariableModel::headerData( const int section, const Qt::Orientation orient , const int role ) const
+{
+ if ( orient != Qt::Horizontal || role != Qt::DisplayRole )
+ return QAbstractItemModel::headerData( section, orient, role );
+
+ switch ( section )
+ {
+ case 0: return tr("Name");
+ case 1: return tr("Value");
+ default: return QVariant();
+ }
+
+ return QVariant();
+}
+
+QModelIndex VariableModel::index( int row, int column, const QModelIndex & parent ) const
+{
+ if(!hasData() || row < 0 || column < 0)
+ {
+ return QModelIndex();
+ }
+
+ //When parent is the root this index refers to a node or server
+ if(!parent.isValid())
+ {
+#ifdef ECFLOW_QT5
+ return createIndex(row,column,quintptr(0));
+#else
+ return createIndex(row,column,0);
+#endif
+ }
+
+ //We are under one of the nodes
+ else
+ {
+ return createIndex(row,column,(parent.row()+1)*1000);
+ }
+
+ return QModelIndex();
+
+}
+
+QModelIndex VariableModel::parent(const QModelIndex &child) const
+{
+ if(!child.isValid())
+ return QModelIndex();
+
+ int level=indexToLevel(child);
+ if(level == 1)
+ return QModelIndex();
+ else if(level == 2)
+ {
+ int id=child.internalId();
+ int r=id/1000-1;
+#ifdef ECFLOW_QT5
+ return createIndex(r,child.column(),quintptr(0));
+#else
+ return createIndex(r,child.column(),0);
+#endif
+ }
+
+ return QModelIndex();
+}
+
+//----------------------------------------------
+//
+// Server to index mapping and lookup
+//
+//----------------------------------------------
+
+int VariableModel::indexToLevel(const QModelIndex& index) const
+{
+ if(!index.isValid())
+ return 0;
+
+ int id=index.internalId();
+ if(id >=0 && id < 1000)
+ {
+ return 1;
+ }
+ return 2;
+}
+
+VariableModelData* VariableModel::indexToData(const QModelIndex& index) const
+{
+ int block=-1;
+ return indexToData(index,block);
+}
+
+VariableModelData* VariableModel::indexToData(const QModelIndex& index,int& block) const
+{
+ int row;
+
+ identify(index,block,row);
+
+ if(block != -1)
+ return data_->data(block);
+
+ return NULL;
+}
+
+
+//----------------------------------------------
+//
+// Server to index mapping and lookup
+//
+//----------------------------------------------
+
+bool VariableModel::isVariable(const QModelIndex & index) const
+{
+ return (indexToLevel(index) == 2);
+}
+
+void VariableModel::identify(const QModelIndex& index,int& block,int& row) const
+{
+ block=-1;
+ row=-1;
+
+ if(!index.isValid())
+ {
+ return;
+ }
+
+ int level=indexToLevel(index);
+
+ if(level == 1)
+ {
+ block=index.row();
+ row=-1;
+ }
+ else if(level == 2)
+ {
+ block=parent(index).row();
+ row=index.row();
+ }
+}
+
+void VariableModel::slotReloadBegin()
+{
+ //Reset the whole model
+ beginResetModel();
+}
+
+void VariableModel::slotReloadEnd()
+{
+ endResetModel();
+}
+
+void VariableModel::slotAddRemoveBegin(int block,int diff)
+{
+ QModelIndex parent=index(block,0);
+ if(!parent.isValid())
+ return;
+
+ int num=rowCount(parent);
+
+ //Insertion
+ if(diff > 0)
+ {
+ //We add extra rows to the end
+ beginInsertRows(parent,num,num+diff-1);
+ }
+ //Deletion
+ else if(diff <0)
+ {
+ //We remove rows from the end
+ beginRemoveRows(parent,num+diff,num-1);
+ }
+}
+
+void VariableModel::slotAddRemoveEnd(int diff)
+{
+ //Insertion
+ if(diff > 0)
+ {
+ endInsertRows();
+ }
+ //Deletion
+ else if(diff <0)
+ {
+ endRemoveRows();
+ }
+}
+
+//It must be called after any data change
+void VariableModel::slotDataChanged(int block)
+{
+#ifdef _UI_VARIABLEMODEL_DEBUG
+ UserMessage::debug("VariableModel::slotDataChanged -->");
+#endif
+ QModelIndex blockIndex0=index(block,0);
+ QModelIndex blockIndex1=index(block,1);
+
+#ifdef _UI_VARIABLEMODEL_DEBUG
+ qDebug() << " emit dataChanged:" << blockIndex0 << blockIndex1;
+#endif
+ Q_EMIT dataChanged(blockIndex0,blockIndex1);
+
+ //We need to rerun the filter in the proxy model!
+ Q_EMIT filterChanged();
+
+#ifdef _UI_VARIABLEMODEL_DEBUG
+ UserMessage::debug("<-- VariableModel::slotDataChanged");
+#endif
+}
+
+//=======================================================================
+//
+// VariableSortModel
+//
+//=======================================================================
+
+VariableSortModel::VariableSortModel(VariableModel *varModel,QObject* parent) :
+ QSortFilterProxyModel(parent),
+ varModel_(varModel),
+ showShadowed_(true),
+ matchMode_(FilterMode),
+ ignoreDuplicateNames_(false)
+{
+ QSortFilterProxyModel::setSourceModel(varModel_);
+ setDynamicSortFilter(true);
+
+ connect(varModel_,SIGNAL(filterChanged()),
+ this,SLOT(slotFilterChanged()));
+
+ connect(varModel_,SIGNAL(rerunFilter()),
+ this,SLOT(slotRerunFilter()));
+}
+
+void VariableSortModel::setMatchMode(MatchMode mode)
+{
+ if(matchMode_ == mode)
+ return;
+
+ matchMode_=mode;
+
+ matchLst_.clear();
+ matchText_.clear();
+
+ //reload the filter model
+ invalidate();
+}
+
+void VariableSortModel::setMatchText(QString txt)
+{
+ matchText_=txt;
+
+ if(matchMode_ == FilterMode)
+ {
+#ifdef _UI_VARIABLEMODEL_DEBUG
+ //qDebug() << "before";
+ //print(QModelIndex());
+#endif
+ //reload the filter model
+ invalidate();
+#ifdef _UI_VARIABLEMODEL_DEBUG
+ //qDebug() << "after";
+ //print(QModelIndex());
+#endif
+
+ }
+}
+
+void VariableSortModel::print(const QModelIndex idx)
+{
+ if(rowCount(idx) > 0)
+ qDebug() << "-->" << idx << mapToSource(idx) << data(idx);
+ else
+ qDebug() << idx << mapToSource(idx) << data(idx);
+
+ if(rowCount(idx) > 0) qDebug() << "children:";
+ for(int i=0; i < rowCount(idx); i++)
+ {
+ print(index(i,0,idx));
+ }
+}
+
+void VariableSortModel::slotFilterChanged()
+{
+ if(matchMode_ == FilterMode)
+ invalidate();
+}
+
+void VariableSortModel::slotRerunFilter()
+{
+#ifdef _UI_VARIABLEMODEL_DEBUG
+ UserMessage::debug("VariableSortModel::slotRerunFilter-->");
+#endif
+ invalidate();
+}
+
+void VariableSortModel::slotShowShadowed(bool b)
+{
+ if(showShadowed_ != b)
+ {
+ showShadowed_=b;
+ invalidate();
+ }
+}
+
+bool VariableSortModel::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const
+{
+ //Node or server. Here we want the nodes and server to stay unsorted. That is the order should stay as
+ //it is defined in the data handler: the selected node stays on top and its ancestors and the server
+ //follow each other downwards. This order is reflected in the row index of these items in
+ //the varModel: the selected node's row is 0, its parent's row is 1, etc.
+ if(!varModel_->isVariable(sourceLeft))
+ {
+ if(sortOrder() == Qt::AscendingOrder)
+ return (sourceLeft.row() < sourceRight.row());
+ else
+ return (sourceLeft.row() > sourceRight.row());
+ }
+ //For variables we simply sort according to the string
+ else
+ {
+ return varModel_->data(sourceLeft,Qt::DisplayRole).toString() < varModel_->data(sourceRight,Qt::DisplayRole).toString();
+ }
+ return true;
+}
+
+bool VariableSortModel::filterAcceptsRow(int sourceRow,const QModelIndex& sourceParent) const
+{
+ if(!sourceParent.isValid())
+ return true;
+
+ QModelIndex idx=varModel_->index(sourceRow,0,sourceParent);
+
+ if(!showShadowed_)
+ {
+ if(varModel_->data(idx,VariableModel::ShadowRole).toBool())
+ return false;
+ }
+
+ if(matchMode_ != FilterMode || matchText_.simplified().isEmpty())
+ return true;
+
+ QModelIndex idx2=varModel_->index(sourceRow,1,sourceParent);
+
+ QString s=varModel_->data(idx,Qt::DisplayRole).toString();
+ QString s2=varModel_->data(idx2,Qt::DisplayRole).toString();
+
+ if(s.contains(matchText_,Qt::CaseInsensitive) || s2.contains(matchText_,Qt::CaseInsensitive))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+QVariant VariableSortModel::data(const QModelIndex& idx,int role) const
+{
+ if(role != Qt::UserRole)
+ {
+ return QSortFilterProxyModel::data(idx,role);
+ }
+
+ //We highlight the matching items (the entire row).
+ if(matchMode_ == SearchMode && matchLst_.count() >0)
+ {
+ int col2=(idx.column()==0)?1:0;
+ QModelIndex idx2=index(idx.row(),col2,idx.parent());
+
+ //qDebug() << idx << idx2;
+
+ if(matchLst_.contains(idx) || matchLst_.contains(idx2))
+ return QColor(169,210,176);
+ }
+
+ return QSortFilterProxyModel::data(idx,role);
+}
+
+
+QModelIndexList VariableSortModel::match(const QModelIndex& start,int role,const QVariant& value,int hits,Qt::MatchFlags flags) const
+{
+ if(matchMode_ != SearchMode)
+ return QModelIndexList();
+
+ QModelIndex root;
+ matchText_=value.toString();
+
+ matchLst_.clear();
+
+ if(matchText_.simplified().isEmpty())
+ return matchLst_;
+
+ for(int i=0; i < rowCount(); i++)
+ {
+ QModelIndex idx=index(i,0);
+ for(int row=0; row < rowCount(idx);row++)
+ {
+ //Name column
+ QModelIndex colIdx=index(row,0,idx);
+ QString s=data(colIdx,Qt::DisplayRole).toString();
+
+ if(s.contains(matchText_,Qt::CaseInsensitive))
+ {
+ matchLst_ << colIdx;
+ continue;
+ }
+
+ //Value columns
+ QModelIndex colIdx1=index(row,1,idx);
+ s=data(colIdx1,Qt::DisplayRole).toString();
+ if(s.contains(matchText_,Qt::CaseInsensitive))
+ {
+ matchLst_ << colIdx;
+ }
+ }
+ }
+
+ return matchLst_;
+}
+
+
diff --git a/Viewer/src/VariableModel.hpp b/Viewer/src/VariableModel.hpp
new file mode 100644
index 0000000..06ce7b1
--- /dev/null
+++ b/Viewer/src/VariableModel.hpp
@@ -0,0 +1,123 @@
+#ifndef VARIABLEMODEL_H
+#define VARIABLEMODEL_H
+
+#include <QAbstractItemModel>
+#include <QSortFilterProxyModel>
+
+#include <vector>
+
+#include "NodeObserver.hpp"
+#include "VInfo.hpp"
+
+class Node;
+class VariableModelData;
+class VariableModelDataHandler;
+class VariableSortModel;
+
+class VariableModel : public QAbstractItemModel
+{
+Q_OBJECT
+
+friend class VariableSortModel;
+
+public:
+ VariableModel(VariableModelDataHandler* data,QObject *parent=0);
+
+ enum CustomItemRole {ReadOnlyRole = Qt::UserRole+1,GenVarRole = Qt::UserRole+2,ShadowRole = Qt::UserRole+3};
+
+ int columnCount (const QModelIndex& parent = QModelIndex() ) const;
+ int rowCount (const QModelIndex& parent = QModelIndex() ) const;
+
+ Qt::ItemFlags flags ( const QModelIndex & index) const;
+ QVariant data (const QModelIndex& , int role = Qt::DisplayRole ) const;
+ QVariant headerData(int,Qt::Orientation,int role = Qt::DisplayRole ) const;
+
+ QModelIndex index (int, int, const QModelIndex& parent = QModelIndex() ) const;
+ QModelIndex parent (const QModelIndex & ) const;
+
+ bool variable(const QModelIndex& index, QString& name,QString& value,bool& genVar) const;
+ bool alterVariable(const QModelIndex& index,QString name,QString value);
+ bool setVariable(const QModelIndex& index,QString name,QString value);
+ bool removeVariable(const QModelIndex& index,QString name,QString value);
+
+ VariableModelData* indexToData(const QModelIndex& index) const;
+ VariableModelData* indexToData(const QModelIndex& index,int& block) const;
+
+ bool isVariable(const QModelIndex & index) const;
+
+public Q_SLOTS:
+ void slotReloadBegin();
+ void slotReloadEnd();
+ void slotAddRemoveBegin(int block,int diff);
+ void slotAddRemoveEnd(int diff);
+ void slotDataChanged(int);
+
+Q_SIGNALS:
+ void filterChanged();
+ void rerunFilter();
+
+protected:
+ bool hasData() const;
+
+ int indexToLevel(const QModelIndex&) const;
+ void identify(const QModelIndex& index,int& parent,int& row) const;
+
+ VariableModelDataHandler* data_;
+ static QColor varCol_;
+ static QColor genVarCol_;
+ static QColor shadowCol_;
+ static QColor blockBgCol_;
+ static QColor blockFgCol_;
+};
+
+
+//Filter and sorts the variables
+
+class VariableSortModel : public QSortFilterProxyModel
+{
+ Q_OBJECT
+
+public:
+ enum MatchMode {FilterMode,SearchMode};
+
+ VariableSortModel(VariableModel*,QObject *parent=0);
+ ~VariableSortModel() {}
+
+ MatchMode matchMode() const {return matchMode_;}
+ void setMatchMode(MatchMode mode);
+ void setMatchText(QString text);
+
+ bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
+ bool filterAcceptsRow(int,const QModelIndex &) const;
+
+ //From QSortFilterProxyModel:
+ //we set the source model in the constructor. So this function should not do anything.
+ void setSourceModel(QAbstractItemModel*) {}
+ QVariant data (const QModelIndex& , int role = Qt::DisplayRole ) const;
+
+ QModelIndexList match(const QModelIndex& start,int role,const QVariant& value,int hits = 1, Qt::MatchFlags flags = Qt::MatchFlags( Qt::MatchStartsWith | Qt::MatchWrap )) const;
+
+public Q_SLOTS:
+ void slotShowShadowed(bool);
+
+protected Q_SLOTS:
+ void slotFilterChanged();
+ void slotRerunFilter();
+
+protected:
+ void match(QString text);
+ void print(const QModelIndex idx);
+
+ VariableModel* varModel_;
+ bool showShadowed_;
+
+ MatchMode matchMode_;
+ mutable QString matchText_;
+ mutable QModelIndexList matchLst_;
+
+ QMap<QString,int> nameCnt_;
+ bool ignoreDuplicateNames_; //Ignore duplicate names across ancestors
+};
+
+
+#endif
diff --git a/Viewer/src/VariableModelData.cpp b/Viewer/src/VariableModelData.cpp
new file mode 100644
index 0000000..b69070b
--- /dev/null
+++ b/Viewer/src/VariableModelData.cpp
@@ -0,0 +1,863 @@
+//============================================================================
+// Copyright 2015 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "VariableModelData.hpp"
+
+#include "ServerHandler.hpp"
+#include "UserMessage.hpp"
+#include "VariableModelDataObserver.hpp"
+#include "VNode.hpp"
+#include "VNState.hpp"
+
+#include <QDebug>
+#include <QString>
+
+static std::string defaultStr("");
+
+QStringList VariableModelData::readOnlyVars_;
+
+#define _UI_VARIABLEMODELDATA_DEBBUG
+
+//==========================================
+//
+// VariableModelData
+//
+//==========================================
+
+VariableModelData::VariableModelData(VInfo_ptr info) :
+ info_(info)
+{
+ reload();
+
+ if(readOnlyVars_.isEmpty())
+ {
+ readOnlyVars_ << "ECF_NODE" << "ECF_PORT" << "ECF_PID" << "ECF_VERSION" <<
+ "ECF_LISTS";
+ }
+}
+
+VariableModelData::~VariableModelData()
+{
+}
+
+void VariableModelData::clear()
+{
+ vars_.clear();
+ genVars_.clear();
+}
+
+void VariableModelData::reload()
+{
+ clear();
+
+ if(info_ && info_->node())
+ {
+ info_->node()->variables(vars_);
+ info_->node()->genVariables(genVars_);
+ removeDuplicates(vars_,genVars_);
+ }
+}
+
+//When this function called duplicates must have already been removed!!
+void VariableModelData::reset(const std::vector<Variable>& vars,const std::vector<Variable>& genVars)
+{
+ clear();
+
+ if(info_ && info_->node())
+ {
+ vars_=vars;
+ genVars_=genVars;
+ }
+}
+
+void VariableModelData::removeDuplicates(const std::vector<Variable>& vars,std::vector<Variable>& genVars)
+{
+ std::vector<Variable> gvOri=genVars;
+ genVars.clear();
+
+ for(std::vector<Variable>::const_iterator it=gvOri.begin(); it != gvOri.end(); ++it)
+ {
+ bool hasIt=false;
+ for(std::vector<Variable>::const_iterator itV=vars.begin(); itV != vars.end(); ++itV)
+ {
+ if((*it).name() == (*itV).name())
+ {
+ hasIt=true;
+ break;
+ }
+ }
+ if(!hasIt)
+ genVars.push_back(*it);
+ }
+}
+
+std::string VariableModelData::fullPath()
+{
+ if(info_ && info_->node())
+ return info_->path();
+
+ return std::string();
+}
+
+std::string VariableModelData::name()
+{
+ return info_->name();
+}
+
+std::string VariableModelData::type()
+{
+ if(info_)
+ {
+ if(info_->isServer())
+ return "server";
+ else if(info_->node())
+ return info_->node()->nodeType();
+ }
+
+ return std::string();
+}
+
+VNode* VariableModelData::node() const
+{
+ if(info_ && info_->isNode())
+ return info_->node();
+
+ return NULL;
+}
+
+const std::string& VariableModelData::name(int index) const
+{
+ if(index < 0 || index >= varNum())
+ return defaultStr;
+
+ if(!isGenVar(index))
+ {
+ return vars_.at(index).name();
+ }
+ else
+ {
+ return genVars_.at(index-vars_.size()).name();
+ }
+
+ return defaultStr;
+}
+
+const std::string& VariableModelData::value(int index) const
+{
+ if(index < 0 || index >= varNum())
+ return defaultStr;
+
+ if(!isGenVar(index))
+ {
+ return vars_.at(index).theValue();
+ }
+ else
+ {
+ return genVars_.at(index-vars_.size()).theValue();
+ }
+
+ return defaultStr;
+}
+
+const std::string& VariableModelData::value(const std::string n,bool& hasIt) const
+{
+ hasIt=false;
+ if(n.empty())
+ return defaultStr;
+
+ for(std::vector<Variable>::const_iterator it=vars_.begin(); it != vars_.end(); ++it)
+ {
+ if((*it).name() == n)
+ {
+ hasIt=true;
+ return (*it).theValue();
+ }
+ }
+ for(std::vector<Variable>::const_iterator it=genVars_.begin(); it != genVars_.end(); ++it)
+ {
+ if((*it).name() == n)
+ {
+ hasIt=true;
+ return (*it).theValue();
+ }
+ }
+
+ return defaultStr;
+}
+
+bool VariableModelData::hasName(const std::string& n) const
+{
+ for(std::vector<Variable>::const_iterator it=vars_.begin(); it != vars_.end(); ++it)
+ {
+ if((*it).name() == n)
+ {
+ return true;
+ }
+ }
+
+ for(std::vector<Variable>::const_iterator it=genVars_.begin(); it != genVars_.end(); ++it)
+ {
+ if((*it).name() == n)
+ {
+ return true;
+ }
+ }
+
+ return false;
+
+}
+
+void VariableModelData::buildAlterCommand(std::vector<std::string>& cmd,
+ const std::string& action, const std::string& type,
+ const std::string& name,const std::string& value)
+{
+ cmd.push_back("ecflow_client");
+ cmd.push_back("--alter");
+ cmd.push_back(action);
+ cmd.push_back(type);
+
+ if(!name.empty())
+ {
+ cmd.push_back(name);
+ cmd.push_back(value);
+ }
+
+ cmd.push_back("<full_name>");
+
+}
+
+void VariableModelData::setValue(int index,const std::string& val)
+{
+ std::vector<std::string> cmd;
+ buildAlterCommand(cmd,"change","variable",name(index),val);
+
+ ServerHandler::command(info_,cmd);
+}
+
+void VariableModelData::alter(const std::string& name,const std::string& val)
+{
+ std::string mode="add";
+
+ //Existing name
+ if(hasName(name))
+ {
+ //Generated variables cannot be changed. We instead add user variable with the same
+ //name. It will shadow the original gen variable.
+ if(isGenVar(name))
+ {
+ mode="add";
+ }
+ else
+ {
+ mode="change";
+ }
+ }
+
+ std::vector<std::string> cmd;
+ buildAlterCommand(cmd,mode,"variable",name,val);
+ ServerHandler::command(info_,cmd);
+}
+
+
+void VariableModelData::add(const std::string& name,const std::string& val)
+{
+ std::vector<std::string> cmd;
+ buildAlterCommand(cmd,(hasName(name))?"change":"add","variable",name,val);
+
+ ServerHandler::command(info_,cmd);
+}
+
+void VariableModelData::remove(int index,const std::string& varName)
+{
+ if(varName == name(index))
+ {
+ std::vector<std::string> cmd;
+ buildAlterCommand(cmd,"delete","variable",varName,"");
+
+ ServerHandler::command(info_,cmd);
+ }
+}
+
+bool VariableModelData::isGenVar(int index) const
+{
+ return (index >= vars_.size());
+}
+
+bool VariableModelData::isGenVar(const std::string& n) const
+{
+ for(std::vector<Variable>::const_iterator it=genVars_.begin(); it != genVars_.end(); ++it)
+ {
+ if((*it).name() == n)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool VariableModelData::isReadOnly(int index) const
+{
+ return isReadOnly(name(index));
+}
+
+bool VariableModelData::isReadOnly(const std::string& varName) const
+{
+ return readOnlyVars_.contains(QString::fromStdString(varName));
+}
+
+bool VariableModelData::isShadowed(int index) const
+{
+ return (shadowed_.find(name(index)) != shadowed_.end());
+}
+
+int VariableModelData::varNum() const
+{
+ return vars_.size() + genVars_.size();
+}
+
+void VariableModelData::latestVars(std::vector<Variable>& v,std::vector<Variable>& vg)
+{
+ if(info_ && info_->node())
+ {
+ info_->node()->variables(v);
+ info_->node()->genVariables(vg);
+ removeDuplicates(v,vg);
+ }
+}
+
+bool VariableModelData::updateShadowed(std::set<std::string>& names)
+{
+#ifdef _UI_VARIABLEMODELDATA_DEBBUG
+ UserMessage::debug("VariableModelData::updateShadowed --> node=" + name());
+#endif
+
+ std::set<std::string> ori=shadowed_;
+ shadowed_.clear();
+ bool changed=false;
+
+#ifdef _UI_VARIABLEMODELDATA_DEBBUG
+ UserMessage::debug(" ori shadowed:");
+ for(std::set<std::string>::const_iterator it=ori.begin(); it != ori.end(); ++it)
+ {
+ UserMessage::debug(" " + *it);
+ }
+#endif
+
+ for(std::set<std::string>::const_iterator it = names.begin(); it != names.end(); ++it)
+ {
+ if(hasName(*it))
+ {
+ shadowed_.insert(*it);
+ if(ori.find(*it) == ori.end())
+ changed=true;
+ }
+ }
+
+ for(unsigned int i=0; i < vars_.size(); i++)
+ {
+ names.insert(vars_[i].name());
+ }
+ for(unsigned int i=0; i < genVars_.size(); i++)
+ {
+ names.insert(genVars_[i].name());
+ }
+
+#ifdef _UI_VARIABLEMODELDATA_DEBBUG
+ UserMessage::debug(" shadowed:");
+ for(std::set<std::string>::const_iterator it=shadowed_.begin(); it != shadowed_.end(); ++it)
+ {
+ UserMessage::debug(" " + *it);
+ }
+
+ UserMessage::qdebug(" changed: " + QString::number(changed));
+#endif
+
+#ifdef _UI_VARIABLEMODELDATA_DEBBUG
+ UserMessage::debug("<-- VariableModelData::updateShadowed");
+#endif
+
+ return changed;
+}
+
+bool VariableModelData::checkUpdateNames(const std::vector<Variable>& v,const std::vector<Variable>& vg)
+{
+ for(unsigned int i=0; i < vars_.size(); i++)
+ {
+ if(vars_[i].name() != v[i].name())
+ {
+ return true;
+ }
+ }
+
+ for(unsigned int i=0; i < genVars_.size(); i++)
+ {
+ if(genVars_[i].name() != vg[i].name())
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+//Check if the total number of variables will change. It does not update the local data!
+int VariableModelData::checkUpdateDiff(std::vector<Variable>& v,std::vector<Variable>& vg)
+{
+ if(info_ && info_->node() && v.empty() && vg.empty())
+ {
+ latestVars(v,vg);
+ }
+
+ //Return the change in the total size of variables
+ return v.size()+vg.size() -(vars_.size() + genVars_.size());
+}
+
+
+//Check if any of the names or values has changed. We suppose that the number of current and new
+//variables are the same but some of their names or values have been changed.
+bool VariableModelData::update(const std::vector<Variable>& v,const std::vector<Variable>& vg)
+{
+#ifdef _UI_VARIABLEMODELDATA_DEBBUG
+ UserMessage::debug("VariableModelData::update -->");
+#endif
+
+#if 0
+ if(info_ && info_->node() && v.empty() && vg.empty())
+ {
+ latestVars(v,vg);
+
+#ifdef _UI_VARIABLEMODELDATA_DEBBUG
+ UserMessage::debug(" call latestVars");
+#endif
+
+ }
+#endif
+
+#ifdef _UI_VARIABLEMODELDATA_DEBBUG
+ UserMessage::debug(" new list of variables:");
+ for(size_t i=0; i < v.size(); i++)
+ UserMessage::debug(" " + v[i].name() + "=" + v[i].theValue());
+ UserMessage::debug(" new list of generated variables:");
+ for(size_t i=0; i < vg.size(); i++)
+ UserMessage::debug(" " + vg[i].name() + "=" + vg[i].theValue());
+#endif
+
+ //We must have the same number of variables
+ assert(v.size() + vg.size() == vars_.size() + genVars_.size());
+
+ bool changed=false;
+ if(v.size() != vars_.size() || vg.size() != genVars_.size())
+ {
+ changed=true;
+#ifdef _UI_VARIABLEMODELDATA_DEBBUG
+ UserMessage::qdebug(" variables size changed! var: " + QString::number(vars_.size()) +
+ " -> " + QString::number(v.size()) + "gen var: " +
+ QString::number(genVars_.size()) + " -> " + QString::number(vg.size()));
+#endif
+ }
+ else
+ {
+ for(unsigned int i=0; i < vars_.size(); i++)
+ {
+ if(vars_[i].name() != v[i].name() || vars_[i].theValue() != v[i].theValue())
+ {
+#ifdef _UI_VARIABLEMODELDATA_DEBBUG
+ UserMessage::debug(" variable changed! name: " + vars_[i].name() + " -> " +
+ v[i].name() + " value: " + vars_[i].theValue() + " -> " + v[i].theValue());
+#endif
+ changed=true;
+ break;
+ }
+ }
+
+ if(changed == false)
+ {
+ for(unsigned int i=0; i < genVars_.size(); i++)
+ {
+ if(genVars_[i].name() != vg[i].name() || genVars_[i].theValue() != vg[i].theValue())
+ {
+#ifdef _UI_VARIABLEMODELDATA_DEBBUG
+ UserMessage::debug(" generated variable changed! name: " + genVars_[i].name() + " -> " +
+ vg[i].name() + " value: " + genVars_[i].theValue() + " -> " + vg[i].theValue());
+#endif
+
+ changed=true;
+ break;
+ }
+ }
+ }
+ }
+
+ if(changed)
+ {
+ vars_=v;
+ genVars_=vg;
+#ifdef _UI_VARIABLEMODELDATA_DEBBUG
+ UserMessage::debug(" updated vars and genvars");
+#endif
+ }
+
+#ifdef _UI_VARIABLEMODELDATA_DEBBUG
+ UserMessage::debug("<-- VariableModelData::update");
+#endif
+
+ return changed;
+
+}
+
+//==========================================
+//
+// VariableModelDataHandler
+//
+//==========================================
+
+VariableModelDataHandler::VariableModelDataHandler() : server_(0)
+{
+}
+
+VariableModelDataHandler::~VariableModelDataHandler()
+{
+ clear();
+}
+
+void VariableModelDataHandler::reload(VInfo_ptr info)
+{
+ //Notifies the model that a change will happen
+ Q_EMIT reloadBegin();
+
+ clear(false);
+
+ if(info && info->node())
+ {
+ server_=info->server();
+
+ std::vector<VNode*> nodes=info->node()->ancestors(VNode::ChildToParentSort);
+
+ for(std::vector<VNode*>::iterator it=nodes.begin(); it != nodes.end(); ++it)
+ {
+ VNode* n=*it;
+
+ if(n->isServer())
+ {
+ VInfo_ptr ptr=VInfoServer::create(n->server());
+ data_.push_back(new VariableModelData(ptr));
+ }
+ else
+ {
+ VInfo_ptr ptr=VInfoNode::create(n);
+ data_.push_back(new VariableModelData(ptr));
+ }
+ }
+
+ updateShadowed();
+ }
+
+ Q_EMIT reloadEnd();
+}
+
+#if 0
+void VariableModelDataHandler::reload()
+{
+ //Notifies the model that a change will happen
+ Q_EMIT reloadBegin();
+
+ for(std::vector<VariableModelData*>::iterator it=data_.begin(); it != data_.end(); ++it)
+ {
+ (*it)->reload();
+ }
+
+ updateShadowed();
+
+ Q_EMIT reloadEnd();
+}
+#endif
+
+bool VariableModelDataHandler::updateShadowed()
+{
+#ifdef _UI_VARIABLEMODELDATA_DEBBUG
+ UserMessage::debug("VariableModelDataHandler::updateShadowed -->");
+#endif
+
+ bool shadowChanged=false;
+
+ names_.clear();
+
+ if(data_.size()== 0)
+ return shadowChanged;
+
+ //There are no shadowed vars in the first node
+ for(size_t i=0; i < data_[0]->varNum(); i++)
+ {
+ names_.insert(data_[0]->name(i));
+ }
+
+ for(size_t i=1; i < data_.size(); i++)
+ {
+ if(data_[i]->updateShadowed(names_))
+ shadowChanged=true;
+ }
+
+#ifdef _UI_VARIABLEMODELDATA_DEBBUG
+ UserMessage::debug(" names:");
+ for(std::set<std::string>::const_iterator it=names_.begin(); it != names_.end(); ++it)
+ {
+ UserMessage::debug(" " + *it);
+ }
+#endif
+
+ return shadowChanged;
+}
+
+void VariableModelDataHandler::clear(bool emitSignal)
+{
+ if(emitSignal)
+ Q_EMIT reloadBegin();
+
+ for(std::vector<VariableModelData*>::iterator it=data_.begin(); it != data_.end(); ++it)
+ {
+ delete *it;
+ }
+
+ server_=0;
+ data_.clear();
+ names_.clear();
+
+ broadcastClear();
+
+ if(emitSignal)
+ Q_EMIT reloadEnd();
+}
+
+int VariableModelDataHandler::varNum(int index) const
+{
+ if(index >=0 && index < data_.size())
+ return data_.at(index)->varNum();
+
+ return -1;
+}
+
+VariableModelData* VariableModelDataHandler::data(int index) const
+{
+ if(index >=0 && index < data_.size())
+ return data_.at(index);
+
+ return 0;
+}
+
+//It is called when a node changed.
+bool VariableModelDataHandler::nodeChanged(const VNode* node, const std::vector<ecf::Aspect::Type>& aspect)
+{
+#ifdef _UI_VARIABLEMODELDATA_DEBBUG
+ UserMessage::debug("VariableModelDataHandler::nodeChanged -->");
+#endif
+ int dataIndex=-1;
+ for(unsigned int i=0; i < data_.size(); i++)
+ {
+ if(data_.at(i)->node() == node)
+ {
+ dataIndex=i;
+ break;
+ }
+ }
+
+#ifdef _UI_VARIABLEMODELDATA_DEBBUG
+ UserMessage::qdebug(" dataIndex=" + QString::number(dataIndex));
+#endif
+ Q_ASSERT(dataIndex != -1);
+
+ bool retVal=updateVariables(dataIndex);
+
+#ifdef _UI_VARIABLEMODELDATA_DEBBUG
+ UserMessage::debug("<-- VariableModelDataHandler::nodeChanged");
+#endif
+ if(retVal)
+ broadcastUpdate();
+
+ return retVal;
+}
+
+//It is called when the server defs was changed
+bool VariableModelDataHandler::defsChanged(const std::vector<ecf::Aspect::Type>& aspect)
+{
+#ifdef _UI_VARIABLEMODELDATA_DEBBUG
+ UserMessage::debug("VariableModelDataHandler::defsChanged -->");
+#endif
+
+ if(data_.size() == 0)
+ {
+#ifdef _UI_VARIABLEMODELDATA_DEBBUG
+ UserMessage::debug("<-- VariableModelDataHandler::defsChanged");
+#endif
+ return false;
+ }
+
+ int dataIndex=data_.size()-1;
+ Q_ASSERT(dataIndex >=0 && dataIndex < data_.size());
+ VariableModelData* d=data_.at(data_.size()-1);
+ Q_ASSERT(d);
+ Q_ASSERT(d->type() == "server");
+
+ bool retVal=updateVariables(dataIndex);
+
+#ifdef _UI_VARIABLEMODELDATA_DEBBUG
+ UserMessage::debug("<-- VariableModelDataHandler::defsChanged");
+#endif
+
+ if(retVal)
+ broadcastUpdate();
+
+ return retVal;
+}
+
+//It is called when the server defs was changed
+bool VariableModelDataHandler::updateVariables(int dataIndex)
+{
+#ifdef _UI_VARIABLEMODELDATA_DEBBUG
+ UserMessage::debug("VariableModelDataHandler::updateVariables -->");
+#endif
+
+ bool retVal=false;
+
+ //There is no notification about generated variables. Basically they can change at any update!!
+ //So we have to check all the variables at every update!!
+ std::vector<Variable> v;
+ std::vector<Variable> vg;
+
+ //Get the current set of variables and check if the total number of variables
+ //has changed. At this point v and vg do not contain any duplicates.
+ int cntDiff=data_.at(dataIndex)->checkUpdateDiff(v,vg);
+
+ //If the number of the variables is not the same as we store we reset the given block in the model
+ if(cntDiff != 0)
+ {
+#ifdef _UI_VARIABLEMODELDATA_DEBBUG
+ UserMessage::qdebug(" cntDiff=" + QString::number(cntDiff));
+#endif
+ const int numNew=v.size()+vg.size();
+
+ //Notifies the model that rows will be added or removed for this data item
+ Q_EMIT addRemoveBegin(dataIndex,cntDiff);
+
+ //Reset the variables using v and vg.
+ data_.at(dataIndex)->reset(v,vg);
+ Q_ASSERT(data_.at(dataIndex)->varNum() == numNew);
+
+ //Notifies the model that the change happened
+ Q_EMIT addRemoveEnd(cntDiff);
+
+ //Check if the shadowed list of variables changed
+ if(updateShadowed())
+ {
+#ifdef _UI_VARIABLEMODELDATA_DEBBUG
+ UserMessage::qdebug(" emit rerunFilter");
+#endif
+ Q_EMIT rerunFilter();
+ }
+ //The shadowed list did not change
+ else
+ {
+#ifdef _UI_VARIABLEMODELDATA_DEBBUG
+ UserMessage::qdebug(" emit dataChanged");
+#endif
+ //Update the data item in the model
+ Q_EMIT dataChanged(dataIndex);
+ }
+
+ retVal=true;
+ }
+ //Check if some variables' name or value changed
+ else
+ {
+#ifdef _UI_VARIABLEMODELDATA_DEBBUG
+ UserMessage::debug(" Change: NODE_VARIABLE");
+#endif
+ //At this point we must have the same number of vars
+ const int numNew=v.size()+vg.size();
+ Q_ASSERT(data_.at(dataIndex)->varNum() == numNew);
+
+ //Find out if any names chhanged
+ bool nameChanged=data_.at(dataIndex)->checkUpdateNames(v,vg);
+
+ //Update the names/values
+ if(data_.at(dataIndex)->update(v,vg))
+ {
+#ifdef _UI_VARIABLEMODELDATA_DEBBUG
+ UserMessage::debug(" Variable name or value changed");
+#endif
+ //At this point the stored variables are already updated
+ if(nameChanged)
+ {
+ if(updateShadowed())
+ {
+ Q_EMIT rerunFilter();
+ }
+ else
+ //Update the data item in the model
+ Q_EMIT dataChanged(dataIndex);
+ }
+ else
+ {
+ //Update the data item in the model
+ Q_EMIT dataChanged(dataIndex);
+ }
+ }
+ retVal=true;
+ }
+
+#ifdef _UI_VARIABLEMODELDATA_DEBBUG
+ UserMessage::debug("<-- VariableModelDataHandler::updateVariables");
+#endif
+
+ return retVal;
+}
+
+const std::string& VariableModelDataHandler::value(const std::string& node,const std::string& name, bool& hasIt) const
+{
+ hasIt=false;
+ for(unsigned int i=0; i < data_.size(); i++)
+ {
+ if(data_.at(i)->name() == node)
+ {
+ return data_.at(i)->value(name,hasIt);
+ }
+ }
+
+ return defaultStr;
+}
+
+void VariableModelDataHandler::addObserver(VariableModelDataObserver* o)
+{
+ std::vector<VariableModelDataObserver*>::iterator it=std::find(observers_.begin(),observers_.end(),o);
+ if(it == observers_.end())
+ observers_.push_back(o);
+}
+
+void VariableModelDataHandler::removeObserver(VariableModelDataObserver* o)
+{
+ std::vector<VariableModelDataObserver*>::iterator it=std::find(observers_.begin(),observers_.end(),o);
+ if(it != observers_.end())
+ observers_.erase(it);
+}
+
+void VariableModelDataHandler::broadcastClear()
+{
+ std::vector<VariableModelDataObserver*> obsCopy=observers_;
+ for(std::vector<VariableModelDataObserver*>::const_iterator it=obsCopy.begin(); it != obsCopy.end(); ++it)
+ {
+ (*it)->notifyCleared(this);
+ }
+}
+
+void VariableModelDataHandler::broadcastUpdate()
+{
+ for(std::vector<VariableModelDataObserver*>::const_iterator it=observers_.begin(); it != observers_.end(); ++it)
+ {
+ (*it)->notifyUpdated(this);
+ }
+}
diff --git a/Viewer/src/VariableModelData.hpp b/Viewer/src/VariableModelData.hpp
new file mode 100644
index 0000000..ec40c5a
--- /dev/null
+++ b/Viewer/src/VariableModelData.hpp
@@ -0,0 +1,121 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef VARIABLEMODELDATA_H
+#define VARIABLEMODELDATA_H
+
+#include <vector>
+#include <set>
+
+#include <QColor>
+#include <QObject>
+
+#include "NodeObserver.hpp"
+#include "VInfo.hpp"
+
+class Node;
+class ServerHandler;
+class VariableModelDataHandler;
+class VariableModelDataObserver;
+
+class VariableModelData
+{
+ friend class VariableModelDataHandler;
+
+public:
+ explicit VariableModelData(VInfo_ptr info);
+ virtual ~VariableModelData();
+
+ std::string fullPath();
+ std::string name();
+ std::string type();
+ const std::string& name(int index) const;
+ const std::string& value(int index) const;
+ const std::string& value(const std::string name,bool&) const;
+ bool isGenVar(const std::string& varName) const;
+ bool isGenVar(int index) const;
+ bool isReadOnly(int index) const;
+ bool isReadOnly(const std::string& varName) const;
+ bool isShadowed(int index) const;
+ int varNum() const;
+ bool hasName(const std::string& n) const;
+ VNode* node() const;
+
+ void buildAlterCommand(std::vector<std::string>& cmd,
+ const std::string& action, const std::string& type,
+ const std::string& name,const std::string& value);
+
+ void clear();
+ void setValue(int index,const std::string& val);
+ void alter(const std::string& name,const std::string& val);
+ void add(const std::string& name,const std::string& val);
+ void remove(int index,const std::string& val);
+
+ //const std::vector<Variable>& vars() const {return vars_;}
+ //const std::vector<Variable>& genVars() const {return genVars_;}
+
+protected:
+ void reload();
+ void removeDuplicates(const std::vector<Variable>& vars,std::vector<Variable>& genVars);
+ void latestVars(std::vector<Variable>& v,std::vector<Variable>& gv);
+ int checkUpdateDiff(std::vector<Variable>& v,std::vector<Variable>& gv);
+ bool checkUpdateNames(const std::vector<Variable>& v,const std::vector<Variable>& vg);
+ void reset(const std::vector<Variable>& v,const std::vector<Variable>& gv);
+ bool update(const std::vector<Variable>& v,const std::vector<Variable>& gv);
+ bool updateShadowed(std::set<std::string>& names);
+
+ std::vector<Variable> vars_;
+ std::vector<Variable> genVars_;
+ std::set<std::string> shadowed_;
+ VInfo_ptr info_;
+
+ static QStringList readOnlyVars_;
+};
+
+class VariableModelDataHandler : public QObject
+{
+Q_OBJECT
+
+public:
+ VariableModelDataHandler();
+ ~VariableModelDataHandler();
+
+ void reload(VInfo_ptr info);
+ void clear(bool emitSignal=true);
+ int count() const {return static_cast<int>(data_.size());}
+ int varNum(int index) const;
+ VariableModelData* data(int index) const;
+ bool nodeChanged(const VNode* node, const std::vector<ecf::Aspect::Type>&);
+ bool defsChanged(const std::vector<ecf::Aspect::Type>&);
+ const std::string& value(const std::string& node,const std::string& name,bool&) const;
+ void addObserver(VariableModelDataObserver*);
+ void removeObserver(VariableModelDataObserver*);
+
+Q_SIGNALS:
+ void reloadBegin();
+ void reloadEnd();
+ void addRemoveBegin(int,int);
+ void addRemoveEnd(int);
+ void dataChanged(int);
+ void rerunFilter();
+
+protected:
+ //void reload();
+ bool updateVariables(int);
+ bool updateShadowed();
+ void broadcastClear();
+ void broadcastUpdate();
+
+ std::vector<VariableModelData*> data_;
+ ServerHandler* server_;
+ std::set<std::string> names_;
+ std::vector<VariableModelDataObserver*> observers_;
+};
+
+#endif
diff --git a/Viewer/src/VariableModelDataObserver.hpp b/Viewer/src/VariableModelDataObserver.hpp
new file mode 100644
index 0000000..04604c4
--- /dev/null
+++ b/Viewer/src/VariableModelDataObserver.hpp
@@ -0,0 +1,23 @@
+//============================================================================
+// Copyright 2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef VARIABLEMODELDATAOBSERVER_HPP
+#define VARIABLEMODELDATAOBSERVER_HPP
+
+class VariableModelDataHandler;
+
+class VariableModelDataObserver
+{
+public:
+ VariableModelDataObserver() {}
+ virtual void notifyCleared(VariableModelDataHandler*)=0;
+ virtual void notifyUpdated(VariableModelDataHandler*)=0;
+};
+
+#endif // VARIABLEMODELDATAOBSERVER_HPP
diff --git a/Viewer/src/VariablePropDialog.ui b/Viewer/src/VariablePropDialog.ui
new file mode 100644
index 0000000..4d02941
--- /dev/null
+++ b/Viewer/src/VariablePropDialog.ui
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>VariablePropDialog</class>
+ <widget class="QDialog" name="VariablePropDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>625</width>
+ <height>378</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Edit variable</string>
+ </property>
+ <property name="modal">
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,1,0">
+ <property name="spacing">
+ <number>4</number>
+ </property>
+ <property name="topMargin">
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="EditorInfoLabel" name="header_" native="true"/>
+ </item>
+ <item>
+ <widget class="MessageLabel" name="messageLabel_" native="true"/>
+ </item>
+ <item>
+ <widget class="QWidget" name="form_" native="true">
+ <layout class="QFormLayout" name="formLayout">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>&Name:</string>
+ </property>
+ <property name="buddy">
+ <cstring>nameEdit_</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="nameEdit_"/>
+ </item>
+ <item row="1" column="1">
+ <widget class="QPlainTextEdit" name="valueEdit_">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>&Value:</string>
+ </property>
+ <property name="buddy">
+ <cstring>valueEdit_</cstring>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox_">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Save</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>EditorInfoLabel</class>
+ <extends>QWidget</extends>
+ <header>EditorInfoLabel.hpp</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>MessageLabel</class>
+ <extends>QWidget</extends>
+ <header>MessageLabel.hpp</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox_</sender>
+ <signal>accepted()</signal>
+ <receiver>VariablePropDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>257</x>
+ <y>218</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>227</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox_</sender>
+ <signal>rejected()</signal>
+ <receiver>VariablePropDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>274</x>
+ <y>218</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>283</x>
+ <y>227</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/Viewer/src/VariableSearchLine.cpp b/Viewer/src/VariableSearchLine.cpp
new file mode 100644
index 0000000..3a2935f
--- /dev/null
+++ b/Viewer/src/VariableSearchLine.cpp
@@ -0,0 +1,146 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include <assert.h>
+
+#include <QLineEdit>
+#include <QPushButton>
+#include <QTreeView>
+
+#include "VariableSearchLine.hpp"
+
+VariableSearchLine::VariableSearchLine(QWidget *parent) :
+ AbstractSearchLine(parent),
+ view_(0),
+ currentResultItem_(-1)
+{
+ label_->hide();
+ closeTb_->hide();
+}
+
+VariableSearchLine::~VariableSearchLine()
+{
+
+}
+
+//This should only be called once!!
+void VariableSearchLine::setView(QTreeView* view)
+{
+ //We should disconnect from the previous view ...
+ view_=view;
+
+ //We detect when the sorting changes in the view
+ connect(view_->header(),SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)),
+ this,SLOT(slotSortHappened(int,Qt::SortOrder)));
+
+ //At this point the model has to be set on the view!!!
+ assert(view_->model() != 0);
+
+ //We detect when the model is reset
+ connect(view_->model(),SIGNAL(modelReset()),
+ this,SLOT(slotUpdate()));
+
+ //We should detect when the model changes!!!!
+ connect(view_->model(),SIGNAL(dataChanged(QModelIndex,QModelIndex)),
+ this,SLOT(slotUpdate(QModelIndex,QModelIndex)));
+}
+
+void VariableSearchLine::slotFind(QString txt)
+{
+ if(!view_)
+ return;
+
+ if(txt.simplified().isEmpty() && resultItems_.isEmpty())
+ {
+ return;
+ }
+
+ QModelIndex current=view_->currentIndex();
+
+ //The (sort) model redoes the match.
+ resultItems_=view_->model()->match(current,Qt::DisplayRole,txt,-1,
+ Qt::MatchStartsWith | Qt::MatchRecursive | Qt::MatchWrap);
+
+ //The view needs to be rerendered!
+ view_->dataChanged(QModelIndex(),QModelIndex());
+
+ if(resultItems_.count() > 0)
+ {
+ selectIndex(resultItems_[0]);
+ currentResultItem_=0;
+ updateButtons(true);
+ }
+ else
+ {
+ currentResultItem_=0;
+ updateButtons(false);
+ }
+
+}
+
+void VariableSearchLine::slotFindNext()
+{
+ if(!view_)
+ return;
+
+
+ if(status_==true && resultItems_.count() > 0)
+ {
+ currentResultItem_++;
+ if(currentResultItem_ >= resultItems_.count())
+ {
+ currentResultItem_=0;
+ }
+ selectIndex(resultItems_[currentResultItem_]);
+ }
+}
+
+void VariableSearchLine::slotFindPrev()
+{
+ if(!view_)
+ return;
+
+ if(status_==true && resultItems_.count() > 0)
+ {
+ currentResultItem_--;
+ if(currentResultItem_ <0)
+ {
+ currentResultItem_=resultItems_.count()-1;
+ }
+ selectIndex(resultItems_[currentResultItem_]);
+ }
+}
+
+void VariableSearchLine::selectIndex(const QModelIndex& index)
+{
+ if(!view_)
+ return;
+
+ view_->setCurrentIndex(index);
+ //emit indexSelected(index);
+}
+
+//Called when sorting changed in the view
+void VariableSearchLine::slotSortHappened(int,Qt::SortOrder)
+{
+ slotUpdate();
+}
+
+void VariableSearchLine::slotUpdate()
+{
+ slotFind(searchLine_->text());
+}
+
+void VariableSearchLine::slotUpdate(const QModelIndex&,const QModelIndex&)
+{
+ slotUpdate();
+}
+
+
+
diff --git a/Viewer/src/VariableSearchLine.hpp b/Viewer/src/VariableSearchLine.hpp
new file mode 100644
index 0000000..db897f1
--- /dev/null
+++ b/Viewer/src/VariableSearchLine.hpp
@@ -0,0 +1,47 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#ifndef VARIABLESEARCHLINE_HPP_
+#define VARIABLESEARCHLINE_HPP_
+
+#include "AbstractSearchLine.hpp"
+
+#include <QModelIndex>
+
+class QTreeView;
+
+class VariableSearchLine : public AbstractSearchLine
+{
+ Q_OBJECT
+
+public:
+ explicit VariableSearchLine(QWidget *parent);
+ ~VariableSearchLine();
+ void setView(QTreeView* view);
+
+public Q_SLOTS:
+ void slotFind(QString);
+ void slotFindNext();
+ void slotFindPrev();
+ void slotFindNext(bool) { slotFindNext();}
+ void slotFindPrev(bool) {slotFindPrev();}
+ void slotSortHappened(int,Qt::SortOrder);
+ void slotUpdate();
+ void slotUpdate(const QModelIndex&,const QModelIndex&);
+
+protected:
+ void selectIndex(const QModelIndex& index);
+ void clearRequested() {}
+
+ QTreeView* view_;
+ QModelIndexList resultItems_;
+ int currentResultItem_;
+};
+
+#endif
diff --git a/Viewer/src/VariableView.cpp b/Viewer/src/VariableView.cpp
new file mode 100644
index 0000000..7d7efe3
--- /dev/null
+++ b/Viewer/src/VariableView.cpp
@@ -0,0 +1,317 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "VariableView.hpp"
+
+#include <QApplication>
+#include <QDebug>
+#include <QImageReader>
+#include <QItemSelectionModel>
+#include <QPainter>
+
+#include "IconProvider.hpp"
+#include "VariableModel.hpp"
+#include "VParam.hpp"
+
+//========================================================
+//
+// VariableViewDelegate
+//
+//========================================================
+
+VariableDelegate::VariableDelegate(QWidget *parent) : QStyledItemDelegate(parent)
+{
+ selectPen_=QPen(QColor(8,117,182));
+ selectBrush_=QBrush(QColor(65,139,212));
+ selectBrushBlock_=QBrush(QColor(48,102,178));
+ borderPen_=QPen(QColor(230,230,230));
+ genVarPixId_=IconProvider::add(":/viewer/genvar.svg","genvar");
+ shadowGenVarPixId_=IconProvider::add(":/viewer/genvar_shadow.svg","genvar_shadow");
+}
+
+void VariableDelegate::paint(QPainter *painter,const QStyleOptionViewItem &option,
+ const QModelIndex& index) const
+{
+ QStyleOptionViewItemV4 vopt(option);
+ initStyleOption(&vopt, index);
+
+ const QStyle *style = vopt.widget ? vopt.widget->style() : QApplication::style();
+ const QWidget* widget = vopt.widget;
+
+ //This indicates that the item is a parent item (node or server),
+ // hence it has branch controls.
+ bool hasChild=!index.parent().isValid();
+
+ bool selected=option.state & QStyle::State_Selected;
+
+ //Save painter state
+ painter->save();
+
+ //The background rect
+ QRect bgRect=option.rect;
+
+ //For variables in the first column we want to extend the item
+ //rect to the left for the background painting.
+ if(index.column()==0 && !hasChild)
+ {
+ bgRect.setX(0);
+ }
+
+ //Paint item highlight!! It is taken from the UserRole
+ QColor highCol=index.data(Qt::UserRole).value<QColor>();
+ if(highCol.isValid())
+ {
+ painter->fillRect(bgRect.adjusted(1,1,-1,-1),highCol);
+ }
+ //otherwise paint item background!!
+ else if(!selected)
+ {
+ //Paint the item background
+ QColor bg=index.data(Qt::BackgroundRole).value<QColor>();
+ if(bg.isValid())
+ {
+ painter->fillRect(bgRect,bg);
+ }
+ }
+
+ //Paint selection. This should be transparent.
+ if(selected)
+ {
+ //The selection rect
+ QRect selectRect;
+ if(hasChild)
+ {
+ selectRect=option.rect.adjusted(0,1,0,-1);
+ painter->fillRect(selectRect,selectBrushBlock_);
+ }
+ else
+ {
+ selectRect=option.rect.adjusted(0,1,0,-1);
+
+ //For the first column we extend the selection
+ //rect to left edge.
+ if(index.column()==0)
+ {
+ selectRect.setX(0);
+ }
+ painter->fillRect(selectRect,selectBrush_);
+
+ }
+ }
+
+ //Render the horizontal border for rows. We only render the top border line.
+ //With this technique we miss the bottom border line of the last row!!!
+ painter->setPen(borderPen_);
+ painter->drawLine(bgRect.topLeft(),bgRect.topRight());
+
+ if(index.column() == 0 && !hasChild)
+ {
+ painter->drawLine(bgRect.topRight(),bgRect.bottomRight());
+ }
+
+ //Display text
+ QString text=index.data(Qt::DisplayRole).toString();
+ QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &vopt, widget);
+ QFont f;
+ QFontMetrics fm(f);
+ textRect.setWidth(fm.width(text));
+
+ if(index.column() == 0 && !hasChild)
+ {
+ bool hasLock=false;
+ QPixmap lockPix;
+ QRect lockRect;
+ bool hasGen=false;
+ QPixmap genPix;
+ QRect genRect;
+
+ textRect.setLeft(option.rect.x()-17);
+ bool locked=index.data(VariableModel::ReadOnlyRole).toBool();
+ if(locked)
+ {
+ hasLock=true;
+ lockPix=IconProvider::lockPixmap(textRect.height()-6);
+
+ lockRect=QRect(textRect.left()-4-lockPix.width(),
+ textRect.top()+(textRect.height()-lockPix.height())/2,
+ lockPix.width(),lockPix.height());
+ }
+
+ bool gen=index.data(VariableModel::GenVarRole).toBool();
+ if(gen && genVarPixId_ >= 0)
+ {
+ int pixId=genVarPixId_;
+ if(index.data(VariableModel::ShadowRole).toBool())
+ {
+ pixId=shadowGenVarPixId_;
+ }
+ if(pixId >=0)
+ {
+ hasGen=true;
+
+ genPix=IconProvider::pixmap(pixId,textRect.height()-4);
+ genRect=QRect(textRect.left(),
+ textRect.top()+(textRect.height()-genPix.height())/2,
+ genPix.width(), genPix.height());
+
+ textRect.moveLeft(genRect.right()+4);
+ }
+ }
+
+ if(textRect.right()+1 > option.rect.right())
+ {
+ painter->setClipRect(option.rect.adjusted(-option.rect.left(),0,0,0));
+ }
+ QColor fg;
+ if(option.state & QStyle::State_Selected)
+ {
+ fg=Qt::white;
+ }
+ else
+ {
+ fg=index.data(Qt::ForegroundRole).value<QColor>();
+ if(!fg.isValid())
+ fg=Qt::black;
+ }
+
+ painter->setPen(fg);
+
+ painter->drawText(textRect,Qt::AlignLeft | Qt::AlignVCenter,text);
+
+ if(hasLock)
+ painter->drawPixmap(lockRect,lockPix);
+
+ if(hasGen)
+ painter->drawPixmap(genRect,genPix);
+
+ }
+ else if(index.column() == 0)
+ {
+ QColor fg=index.data(Qt::ForegroundRole).value<QColor>();
+ if(!fg.isValid())
+ fg=Qt::black;
+ painter->setPen(fg);
+
+ QRegExp rx("^(.+)\\s(\\S+)$");
+ //QRegExp rx("inherited from (\\S+) (\\S+)");
+ if(rx.indexIn(text) > -1 && rx.captureCount() == 2)
+ {
+ QFont f;
+ f.setPointSize(f.pointSize()-1);
+ QFontMetrics fm(f);
+ QString txt1=rx.cap(1);
+ textRect.setWidth(fm.width(txt1));
+ painter->setFont(f);
+ painter->drawText(textRect,Qt::AlignLeft | Qt::AlignVCenter,txt1);
+ textRect.setLeft(textRect.right()+fm.width("D"));
+ text=rx.cap(2);
+ }
+
+ QFont fBold;
+ fBold.setPointSize(fBold.pointSize()-1);
+ fBold.setBold(true);
+ QFontMetrics fmBold(fBold);
+ textRect.setWidth(fmBold.width(text + "a"));
+ painter->setFont(fBold);
+
+ painter->drawText(textRect,Qt::AlignLeft | Qt::AlignVCenter,text);
+
+ }
+ else if(index.column() == 1)
+ {
+ textRect.adjust(2,0,2,0);
+
+ QColor fg;
+ if(selected)
+ {
+ fg=Qt::white;
+ }
+ else
+ {
+ fg=index.data(Qt::ForegroundRole).value<QColor>();
+ if(!fg.isValid())
+ fg=Qt::black;
+ }
+
+ painter->setPen(fg);
+ painter->drawText(textRect,Qt::AlignLeft | Qt::AlignVCenter,text);
+ }
+
+ //Restore painter state
+ painter->restore();
+}
+
+QSize VariableDelegate::sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index ) const
+{
+ QSize size=QStyledItemDelegate::sizeHint(option,index);
+
+ size+=QSize(0,2);
+
+ return size;
+}
+
+//========================================================
+//
+// VariableView
+//
+//========================================================
+
+VariableView::VariableView(QWidget* parent) : TreeView(parent)
+{
+ setProperty("var","1");
+
+ delegate_=new VariableDelegate(this);
+ setItemDelegate(delegate_);
+
+ setRootIsDecorated(true);
+ setAllColumnsShowFocus(true);
+ setUniformRowHeights(true);
+ setAlternatingRowColors(true);
+ setSortingEnabled(true);
+
+ //Context menu
+ setContextMenuPolicy(Qt::ActionsContextMenu);
+}
+
+//We do not want to render the branches for the variable items. We only
+//render the branch for the group items (nodes or server).
+void VariableView::drawBranches(QPainter* painter,const QRect& rect,const QModelIndex& index ) const
+{
+ if(!index.parent().isValid() && index.column()==0)
+ {
+ //We need to fill the branch area here. We cannot do it in the delegate
+ //because when the delegate is called the branch control is already
+ //rendered, so the delegate would just overpaint it!!!
+
+ if(selectionModel()->rowIntersectsSelection(index.row(),QModelIndex()))
+ {
+ painter->fillRect(rect.adjusted(0,1,0,-1),delegate_->selectBrushBlock_);
+ }
+ else
+ {
+ painter->fillRect(rect.adjusted(0,1,0,0),index.data(Qt::BackgroundRole).value<QColor>());
+ }
+
+ //Draw the branch with the default method
+ QTreeView::drawBranches(painter,rect,index);
+ }
+}
+
+/*
+void VariableView::slotSelectItem(const QModelIndex&)
+{
+
+}
+
+void VariableView::reload(VInfo_ptr info)
+{
+ //model_->setData(info);
+ //expandAll();
+}
+*/
diff --git a/Viewer/src/VariableView.hpp b/Viewer/src/VariableView.hpp
new file mode 100644
index 0000000..835a55e
--- /dev/null
+++ b/Viewer/src/VariableView.hpp
@@ -0,0 +1,55 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VARIABLEVIEW_HPP_
+#define VARIABLEVIEW_HPP_
+
+
+#include <QBrush>
+#include <QMap>
+#include <QPen>
+#include <QStyledItemDelegate>
+
+#include "TreeView.hpp"
+
+class VariableView;
+
+class VariableDelegate : public QStyledItemDelegate
+{
+ friend class VariableView;
+
+public:
+ explicit VariableDelegate(QWidget *parent=0);
+ void paint(QPainter *painter,const QStyleOptionViewItem &option,
+ const QModelIndex& index) const;
+ QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index ) const;
+
+protected:
+ QPen selectPen_;
+ QBrush selectBrush_;
+ QBrush selectBrushBlock_;
+ QPen borderPen_;
+ QPixmap lockPix_;
+ int genVarPixId_;
+ int shadowGenVarPixId_;
+};
+
+class VariableView : public TreeView
+{
+public:
+ explicit VariableView(QWidget *parent=0);
+
+protected:
+ void drawBranches(QPainter* painter,const QRect& rect,const QModelIndex& index ) const;
+ VariableDelegate *delegate_;
+};
+
+
+#endif
diff --git a/Viewer/src/Viewer.hpp b/Viewer/src/Viewer.hpp
new file mode 100644
index 0000000..d68d725
--- /dev/null
+++ b/Viewer/src/Viewer.hpp
@@ -0,0 +1,25 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef VIEWER_HPP_
+#define VIEWER_HPP_
+
+namespace Viewer
+{
+ enum ViewMode {TreeViewMode,TableViewMode,NoViewMode};
+ enum ItemRole {InfoRole,ManualRole,ScriptRole,JobRole,OutputRole,WhyRole,TriggersRole,TimelineRole,VariableRole,EditRole,MessageRole};
+ enum AttributeType {NoAttribute,LabelAttribute,MeterAttribute,EventAttribute,RepeatAttribute,TimeAttribute,DateAttribute,
+ TriggerAttribute,VarAttribute,GenVarAttribute,LateAttribute,LimitAttribute,LimiterAttribute};
+
+
+ enum Param {UnknownParam,UnknownState,ActiveState,AbortedState,NoIcon,WaitIcon,RerunIcon,MessageIcon,CompleteIcon,TimeIcon,DateIcon,ZombieIcon,LateIcon};
+}
+
+#endif
diff --git a/Viewer/src/ViewerMain.cpp b/Viewer/src/ViewerMain.cpp
new file mode 100644
index 0000000..f3e39ad
--- /dev/null
+++ b/Viewer/src/ViewerMain.cpp
@@ -0,0 +1,147 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#include <string>
+#include <iostream>
+
+#include <QApplication>
+#include <QDebug>
+#include <QFile>
+#include <QStyleFactory>
+
+#include "File.hpp"
+#include "MainWindow.hpp"
+#include "ServerHandler.hpp"
+#include "MenuHandler.hpp"
+#include "InfoPanelHandler.hpp"
+#include "DirectoryHandler.hpp"
+#include "Highlighter.hpp"
+#include "NodeQueryHandler.hpp"
+#include "CustomCommandHandler.hpp"
+#include "Palette.hpp"
+#include "ServerList.hpp"
+#include "VConfig.hpp"
+#include "VServerSettings.hpp"
+#include "SessionHandler.hpp"
+#include "SessionDialog.hpp"
+
+int main(int argc, char **argv)
+{
+ //if (argc != 3)
+ //{
+ // std::cout << "Usage:" << std::endl;
+ // std::cout << argv[0] << " <host> <port>" << std::endl;
+ // return 1;
+ //
+
+ //Init qt
+ QApplication app(argc, argv);
+
+ QStringList styleLst=QStyleFactory::keys();
+
+ //Set the style
+ QString style="Plastique";
+ if(styleLst.contains(style))
+ {
+ app.setStyle(style);
+ }
+ else
+ {
+ style="Fusion";
+ if(styleLst.contains(style))
+ {
+ app.setStyle(style);
+ }
+ }
+
+ //Set font size for application
+ //QFont font=app.font();
+ //font.setPointSize(9);
+ //app.setFont(font);
+
+ //Initialise the config and other paths
+ DirectoryHandler::init(std::string(argv[0])); // we need to tell the Directory class where we started from
+
+ //Set the stylesheet
+ std::string styleSheetFileName="viewer.qss";
+ std::string styleSheetPath=DirectoryHandler::concatenate(DirectoryHandler::etcDir(),styleSheetFileName);
+
+ QFile shFile(QString::fromStdString(styleSheetPath));
+ if(shFile.open(QIODevice::ReadOnly | QIODevice::Text))
+ {
+ app.setStyleSheet(shFile.readAll());
+ }
+ shFile.close();
+
+ //Load the configurable menu items
+ std::string menuFilename("ecflowview_menus.json");
+ std::string menuPath = DirectoryHandler::concatenate(DirectoryHandler::etcDir(), menuFilename);
+ MenuHandler::readMenuConfigFile(menuPath);
+
+ //Load the custom context menu commands
+ CustomCommandHistoryHandler::instance()->init();
+ CustomSavedCommandHandler::instance()->init();
+ MenuHandler::refreshCustomMenuCommands();
+
+ //Load the info panel definition
+ std::string panelFile = DirectoryHandler::concatenate(DirectoryHandler::etcDir(), "ecflowview_panels.json");
+ InfoPanelHandler::instance()->init(panelFile);
+
+ //Load the queries
+ std::string queryDir = DirectoryHandler::concatenate(DirectoryHandler::configDir(), "query");
+ NodeQueryHandler::instance()->init(queryDir);
+
+ //Initialise the server list
+ ServerList::instance()->init();
+
+ //Load the global configurations
+ VConfig::instance()->init(DirectoryHandler::etcDir());
+
+ //Import server settings from the previous viewer
+ if(DirectoryHandler::isFirstStartUp())
+ {
+ VConfig::instance()->importSettings();
+ VServerSettings::importRcFiles();
+ }
+
+ //Initialise highlighter
+ Highlighter::init(DirectoryHandler::concatenate(DirectoryHandler::etcDir(),
+ "ecflowview_highlighter.json"));
+
+ //Initialise the system palette
+ Palette::load(DirectoryHandler::concatenate(DirectoryHandler::etcDir(),
+ "ecflowview_palette.json"));
+
+
+ // startup - via the session manager, or straight to the main window?
+ bool startMainWindow = true;
+
+ if (SessionHandler::requestStartupViaSessionManager())
+ {
+ SessionDialog sessionDialog;
+ if (sessionDialog.exec() != QDialog::Accepted)
+ startMainWindow = false;
+ }
+
+ if (startMainWindow)
+ {
+ //Build the GUI
+ MainWindow::init();
+
+ //Show all the windows
+ MainWindow::showWindows();
+
+ return app.exec();
+ }
+ else
+ {
+ return 0; // user quit from within the session manager
+ }
+}
diff --git a/Viewer/src/WhyItemWidget.cpp b/Viewer/src/WhyItemWidget.cpp
new file mode 100644
index 0000000..f8201f1
--- /dev/null
+++ b/Viewer/src/WhyItemWidget.cpp
@@ -0,0 +1,92 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "WhyItemWidget.hpp"
+
+#include "Node.hpp"
+
+#include "VConfig.hpp"
+#include "VNode.hpp"
+
+
+//========================================================
+//
+// WhyItemWidget
+//
+//========================================================
+
+WhyItemWidget::WhyItemWidget(QWidget *parent) : CodeItemWidget(parent)
+{
+ messageLabel_->hide();
+ fileLabel_->hide();
+ textEdit_->setShowLineNumbers(false);
+
+ //Editor font
+ textEdit_->setFontProperty(VConfig::instance()->find("panel.why.font"));
+
+}
+
+WhyItemWidget::~WhyItemWidget()
+{
+}
+
+
+QWidget* WhyItemWidget::realWidget()
+{
+ return this;
+}
+
+void WhyItemWidget::reload(VInfo_ptr info)
+{
+ assert(active_);
+
+ if(suspended_)
+ return;
+
+ clearContents();
+ info_=info;
+
+ if(info_)
+ {
+ textEdit_->setPlainText(why());
+ }
+}
+
+void WhyItemWidget::clearContents()
+{
+ InfoPanelItem::clear();
+ textEdit_->clear();
+}
+
+QString WhyItemWidget::why() const
+{
+ QString s;
+
+ std::vector<std::string> theReasonWhy;
+
+ if(info_ && info_.get())
+ {
+ if(info_->isServer())
+ {
+ info_->node()->why(theReasonWhy);
+ }
+ else if(info_->isNode() && info_->node())
+ {
+ info_->node()->why(theReasonWhy);
+ }
+ }
+
+ for (std::vector<std::string>::const_iterator it=theReasonWhy.begin(); it != theReasonWhy.end(); ++it)
+ s+=QString::fromStdString(*it) + "\n";
+
+ return s;
+}
+
+static InfoPanelItemMaker<WhyItemWidget> maker1("why");
+
diff --git a/Viewer/src/WhyItemWidget.hpp b/Viewer/src/WhyItemWidget.hpp
new file mode 100644
index 0000000..3988066
--- /dev/null
+++ b/Viewer/src/WhyItemWidget.hpp
@@ -0,0 +1,43 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef WHYITEMWIDGET_HPP_
+#define WHYITEMWIDGET_HPP_
+
+#include <QPlainTextEdit>
+
+#include "InfoPanelItem.hpp"
+#include "CodeItemWidget.hpp"
+#include "VInfo.hpp"
+
+class VNode;
+
+class WhyItemWidget : public CodeItemWidget, public InfoPanelItem
+{
+public:
+ explicit WhyItemWidget(QWidget *parent=0);
+ ~WhyItemWidget();
+
+ void reload(VInfo_ptr);
+ QWidget* realWidget();
+ void clearContents();
+
+ void nodeChanged(const VNode*, const std::vector<ecf::Aspect::Type>&) {}
+ void defsChanged(const std::vector<ecf::Aspect::Type>&) {}
+
+protected:
+ void updateState(const ChangeFlags&) {}
+
+private:
+ QString why() const;
+};
+
+#endif
+
diff --git a/Viewer/src/ZombieItemWidget.cpp b/Viewer/src/ZombieItemWidget.cpp
new file mode 100644
index 0000000..f6e0305
--- /dev/null
+++ b/Viewer/src/ZombieItemWidget.cpp
@@ -0,0 +1,294 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "ZombieItemWidget.hpp"
+
+#include <QItemSelectionModel>
+#include <QSortFilterProxyModel>
+
+#include "ServerHandler.hpp"
+#include "VNode.hpp"
+#include "VReply.hpp"
+#include "InfoProvider.hpp"
+#include "ZombieModel.hpp"
+
+static bool firstRun=true;
+
+//========================================================
+//
+// ZombieItemWidget
+//
+//========================================================
+
+ZombieItemWidget::ZombieItemWidget(QWidget *parent) :
+ QWidget(parent),
+ commandSent_(false)
+{
+ setupUi(this);
+
+ infoProvider_=new ZombieProvider(this);
+
+ model_=new ZombieModel(this);
+
+ sortModel_=new QSortFilterProxyModel(this);
+ sortModel_->setSourceModel(model_);
+
+ zombieView->setModel(sortModel_);
+
+ //The selection changes in the view
+ connect(zombieView->selectionModel(),SIGNAL(currentChanged(QModelIndex,QModelIndex)),
+ this,SLOT(slotItemSelected(QModelIndex,QModelIndex)));
+
+ //Build context menu
+ zombieView->addAction(actionRescue);
+ zombieView->addAction(actionFoboff);
+ zombieView->addAction(actionKill);
+ zombieView->addAction(actionTerminate);
+ zombieView->addAction(actionDelete);
+
+ //Add actions for the pushbuttons
+ terminateTb_->setDefaultAction(actionTerminate);
+ rescueTb_->setDefaultAction(actionRescue);
+ foboffTb_->setDefaultAction(actionFoboff);
+ deleteTb_->setDefaultAction(actionDelete);
+ killTb_->setDefaultAction(actionKill);
+
+ checkActionState();
+}
+
+ZombieItemWidget::~ZombieItemWidget()
+{
+
+}
+
+QWidget* ZombieItemWidget::realWidget()
+{
+ return this;
+}
+
+void ZombieItemWidget::reload(VInfo_ptr info)
+{
+ assert(active_);
+
+ if(suspended_)
+ return;
+
+ clearContents();
+ info_=info;
+
+ if(info_ && info_->isServer() && info_->server())
+ {
+ commandSent_=false;
+ infoProvider_->info(info_);
+ }
+}
+
+void ZombieItemWidget::clearContents()
+{
+ InfoPanelItem::clear();
+ model_->clearData();
+ checkActionState();
+}
+
+
+void ZombieItemWidget::updateContents()
+{
+ //model_->clearData();
+ if(info_ && info_->isServer() && info_->server())
+ {
+ infoProvider_->info(info_);
+ }
+}
+
+void ZombieItemWidget::updateState(const FlagSet<ChangeFlag>&)
+{
+ checkActionState();
+}
+
+/*
+void ZombieItemWidget::saveSelection()
+{
+ QModelIndexList lst=zombieView->selectionModel()->selectedRows(0);
+ lastSelection_.clear();
+
+ if(!lst.isEmpty())
+ {
+ std::vector<std::string> paths;
+ Q_FOREACH(QModelIndex idx,lst)
+ {
+ lastSelection_.push_back(model_->data(idx,Qt::DisplayRole).toString().toStdString());
+ }
+ }
+}
+
+void ZombieItemWidget::resetSelection()
+{
+ Q_FOREACH(QString s,lastSelection_)
+ {
+
+
+ QModelIndex idx,lst)
+ {
+ lastSelection_.push_back(model_->data(idx,Qt::DisplayRole).toString().toStdString());
+ }
+
+
+ QModelIndexList lst=zombieView->selectionModel()->selectedRows(0);
+ lastSelection_.clear();
+
+ if(!lst.isEmpty())
+ {
+ std::vector<std::string> paths;
+ Q_FOREACH(QModelIndex idx,lst)
+ {
+ lastSelection_.push_back(model_->data(idx,Qt::DisplayRole).toString().toStdString());
+ }
+ }
+}
+*/
+
+
+void ZombieItemWidget::infoReady(VReply* reply)
+{
+ commandSent_=false;
+
+ //We need to know what task it was!
+ if(model_->hasData())
+ {
+ model_->updateData(reply->zombies());
+ }
+ else
+ {
+ model_->setData(reply->zombies());
+ }
+
+ //Adjust column size if it is the first run
+ if(firstRun && model_->hasData())
+ {
+ firstRun=false;
+ for(int i=0; i < model_->columnCount()-1; i++)
+ {
+ zombieView->resizeColumnToContents(i);
+ }
+ }
+ checkActionState();
+}
+
+void ZombieItemWidget::infoFailed(VReply* reply)
+{
+ commandSent_=false;
+ //QString s=QString::fromStdString(reply->errorText());
+ checkActionState();
+}
+
+void ZombieItemWidget::on_actionTerminate_triggered()
+{
+ command("zombie_fail");
+}
+
+void ZombieItemWidget::on_actionRescue_triggered()
+{
+ command("zombie_adopt");
+}
+
+void ZombieItemWidget::on_actionFoboff_triggered()
+{
+ command("zombie_fob");
+}
+
+void ZombieItemWidget::on_actionDelete_triggered()
+{
+ command("zombie_remove");
+}
+
+void ZombieItemWidget::on_actionKill_triggered()
+{
+ command("zombie_kill");
+}
+
+void ZombieItemWidget::on_reloadTb__clicked(bool)
+{
+ updateContents();
+}
+
+void ZombieItemWidget::command(const std::string& cmdName)
+{
+ if(info_ && info_->server())
+ {
+ //Get selection form view
+ QModelIndexList lst=zombieView->selectionModel()->selectedRows(0);
+
+ if(!lst.isEmpty())
+ {
+ std::vector<std::string> paths;
+ Q_FOREACH(QModelIndex idx,lst)
+ {
+ paths.push_back(model_->data(sortModel_->mapToSource(idx),Qt::DisplayRole).toString().toStdString());
+ }
+
+ std::vector<std::string> cmd;
+ cmd.push_back("ecflow_client");
+ cmd.push_back("--" + cmdName);
+ cmd.push_back("<full_name>");
+
+ commandSent_=true;
+
+ info_->server()->command(paths,cmd);
+ }
+ }
+}
+
+
+void ZombieItemWidget::slotItemSelected(QModelIndex,QModelIndex)
+{
+ checkActionState();
+}
+
+void ZombieItemWidget::checkActionState()
+{
+ if(suspended_)
+ {
+ reloadTb_->setEnabled(false);
+ actionRescue->setEnabled(false);
+ actionFoboff->setEnabled(false);
+ actionKill->setEnabled(false);
+ actionTerminate->setEnabled(false);
+ actionDelete->setEnabled(false);
+ return;
+ }
+ else
+ {
+ reloadTb_->setEnabled(true);
+ }
+
+ QModelIndex vIndex=zombieView->currentIndex();
+ QModelIndex index=sortModel_->mapToSource(vIndex);
+
+ bool acState=(index.isValid())?true:false;
+
+ actionRescue->setEnabled(acState);
+ actionFoboff->setEnabled(acState);
+ actionKill->setEnabled(acState);
+ actionTerminate->setEnabled(acState);
+ actionDelete->setEnabled(acState);
+}
+
+void ZombieItemWidget::serverSyncFinished()
+{
+ //If a command has previously sent
+ if(commandSent_)
+ {
+ commandSent_=false;
+ updateContents();
+ }
+}
+
+
+static InfoPanelItemMaker<ZombieItemWidget> maker1("zombie");
+
diff --git a/Viewer/src/ZombieItemWidget.hpp b/Viewer/src/ZombieItemWidget.hpp
new file mode 100644
index 0000000..b01cf2e
--- /dev/null
+++ b/Viewer/src/ZombieItemWidget.hpp
@@ -0,0 +1,68 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+//============================================================================
+
+#ifndef ZOMBIEITEMWIDGET_HPP_
+#define ZOMBIEITEMWIDGET_HPP_
+
+#include <QWidget>
+
+#include "InfoPanelItem.hpp"
+#include "VInfo.hpp"
+
+#include "ui_ZombieItemWidget.h"
+
+class ZombieModel;
+class QSortFilterProxyModel;
+
+class ZombieItemWidget : public QWidget, public InfoPanelItem, protected Ui::ZombieItemWidget
+{
+Q_OBJECT
+
+public:
+ explicit ZombieItemWidget(QWidget *parent=0);
+ ~ZombieItemWidget();
+ void reload(VInfo_ptr);
+ QWidget* realWidget();
+ void clearContents();
+
+ //From VInfoPresenter
+ void infoReady(VReply*);
+ void infoFailed(VReply*);
+ void infoProgress(VReply*) {}
+
+ void nodeChanged(const VNode*, const std::vector<ecf::Aspect::Type>&) {}
+ void defsChanged(const std::vector<ecf::Aspect::Type>&) {}
+
+protected Q_SLOTS:
+ void on_actionTerminate_triggered();
+ void on_actionRescue_triggered();
+ void on_actionFoboff_triggered();
+ void on_actionDelete_triggered();
+ void on_actionKill_triggered();
+ void on_reloadTb__clicked(bool);
+ void slotItemSelected(QModelIndex,QModelIndex);
+
+protected:
+ void updateState(const ChangeFlags&);
+ void serverSyncFinished();
+
+private:
+ void command(const std::string& cmdName);
+ void updateContents();
+ void checkActionState();
+
+ ZombieModel *model_;
+ QSortFilterProxyModel* sortModel_;
+ bool commandSent_;
+ QStringList lastSelection_;
+};
+
+#endif
+
diff --git a/Viewer/src/ZombieItemWidget.ui b/Viewer/src/ZombieItemWidget.ui
new file mode 100644
index 0000000..83a237d
--- /dev/null
+++ b/Viewer/src/ZombieItemWidget.ui
@@ -0,0 +1,247 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ZombieItemWidget</class>
+ <widget class="QWidget" name="ZombieItemWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>570</width>
+ <height>470</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <property name="statusTip">
+ <string/>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" stretch="0,1">
+ <property name="spacing">
+ <number>1</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QToolButton" name="rescueTb_">
+ <property name="toolTip">
+ <string>Rescue</string>
+ </property>
+ <property name="text">
+ <string>Rescue</string>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="foboffTb_">
+ <property name="toolTip">
+ <string>Fob off</string>
+ </property>
+ <property name="text">
+ <string>Fob off</string>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="killTb_">
+ <property name="toolTip">
+ <string>Kill</string>
+ </property>
+ <property name="text">
+ <string>Kill</string>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="terminateTb_">
+ <property name="toolTip">
+ <string>Terminate</string>
+ </property>
+ <property name="text">
+ <string>Terminate</string>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="deleteTb_">
+ <property name="toolTip">
+ <string>Delete</string>
+ </property>
+ <property name="text">
+ <string>Delete</string>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="reloadTb_">
+ <property name="toolTip">
+ <string>Reload zombie list</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/sync.svg</normaloff>:/viewer/sync.svg</iconset>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="TreeView" name="zombieView">
+ <property name="contextMenuPolicy">
+ <enum>Qt::ActionsContextMenu</enum>
+ </property>
+ <property name="alternatingRowColors">
+ <bool>true</bool>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::ExtendedSelection</enum>
+ </property>
+ <property name="rootIsDecorated">
+ <bool>false</bool>
+ </property>
+ <property name="uniformRowHeights">
+ <bool>true</bool>
+ </property>
+ <property name="itemsExpandable">
+ <bool>false</bool>
+ </property>
+ <property name="sortingEnabled">
+ <bool>true</bool>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ <property name="expandsOnDoubleClick">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ <action name="actionTerminate">
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/terminate.svg</normaloff>:/viewer/terminate.svg</iconset>
+ </property>
+ <property name="text">
+ <string>Terminate</string>
+ </property>
+ </action>
+ <action name="actionRescue">
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/rescue.svg</normaloff>:/viewer/rescue.svg</iconset>
+ </property>
+ <property name="text">
+ <string>Rescue</string>
+ </property>
+ </action>
+ <action name="actionFoboff">
+ <property name="text">
+ <string>Fob off</string>
+ </property>
+ </action>
+ <action name="actionDelete">
+ <property name="icon">
+ <iconset>
+ <normaloff>:/viewer/images/close.svg</normaloff>:/viewer/images/close.svg</iconset>
+ </property>
+ <property name="text">
+ <string>Delete</string>
+ </property>
+ </action>
+ <action name="actionKill">
+ <property name="text">
+ <string>Kill</string>
+ </property>
+ </action>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>TreeView</class>
+ <extends>QTreeView</extends>
+ <header>TreeView.hpp</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Viewer/src/ZombieModel.cpp b/Viewer/src/ZombieModel.cpp
new file mode 100644
index 0000000..736e5bd
--- /dev/null
+++ b/Viewer/src/ZombieModel.cpp
@@ -0,0 +1,197 @@
+//============================================================================
+// Copyright 2014 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+
+#include "ZombieModel.hpp"
+
+#include "ModelColumn.hpp"
+
+#include <QDebug>
+
+#include "boost/date_time/posix_time/posix_time.hpp"
+
+ZombieModel::ZombieModel(QObject *parent) :
+ QAbstractItemModel(parent),
+ columns_(0)
+{
+ columns_=ModelColumn::def("zombie_columns");
+
+ assert(columns_);
+}
+
+ZombieModel::~ZombieModel()
+{
+}
+
+void ZombieModel::setData(const std::vector<Zombie>& data)
+{
+ beginResetModel();
+ data_=data;
+ endResetModel();
+}
+
+bool ZombieModel::updateData(const std::vector<Zombie>& data)
+{
+ bool sameAs=false;
+ if(hasData() && data.size() == data_.size())
+ {
+ sameAs=true;
+ for(std::vector<Zombie>::const_iterator it=data.begin(); it != data.end(); it++)
+ {
+ bool hasIt=false;
+ std::string p=(*it).path_to_task();
+ for(std::vector<Zombie>::const_iterator itM=data_.begin(); itM != data_.end(); itM++)
+ {
+ if(p == (*itM).path_to_task())
+ {
+ hasIt=true;
+ break;
+ }
+ }
+
+ if(!hasIt)
+ {
+ sameAs=false;
+ break;
+ }
+ }
+ }
+
+ if(sameAs)
+ {
+ data_=data;
+ Q_EMIT dataChanged(index(0,0),index(data_.size()-1,columns_->count()));
+ return false;
+ }
+ else
+ {
+ beginResetModel();
+ data_=data;
+ endResetModel();
+ return true;
+ }
+}
+
+
+void ZombieModel::clearData()
+{
+ beginResetModel();
+ data_.clear();
+ endResetModel();
+}
+
+bool ZombieModel::hasData() const
+{
+ return !data_.empty();
+}
+
+int ZombieModel::columnCount( const QModelIndex& /*parent */) const
+{
+ return columns_->count();
+}
+
+int ZombieModel::rowCount( const QModelIndex& parent) const
+{
+ if(!hasData())
+ return 0;
+
+ //Parent is the root:
+ if(!parent.isValid())
+ {
+ return static_cast<int>(data_.size());
+ }
+
+ return 0;
+}
+
+Qt::ItemFlags ZombieModel::flags ( const QModelIndex & index) const
+{
+ return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
+}
+
+QVariant ZombieModel::data( const QModelIndex& index, int role ) const
+{
+ if(!index.isValid() || !hasData())
+ {
+ return QVariant();
+ }
+
+ int row=index.row();
+ if(row < 0 || row >= data_.size())
+ return QVariant();
+
+ QString id=columns_->id(index.column());
+
+ if(role == Qt::DisplayRole)
+ {
+ if(id == "path")
+ return QString::fromStdString(data_.at(row).path_to_task());
+ else if(id == "type")
+ return QString::fromStdString(data_.at(row).type_str());
+ else if(id == "tryno")
+ return data_.at(row).try_no();
+ else if(id == "duration")
+ return QString::number(data_.at(row).duration()) + " s";
+ else if(id == "creation")
+ {
+ const boost::posix_time::ptime& t= data_.at(row).creation_time();
+ return QString::fromStdString(boost::posix_time::to_simple_string(t));
+ }
+ else if(id == "allowed")
+ return QString::number(data_.at(row).allowed_age()) + " s";
+ else if(id == "calls")
+ return data_.at(row).calls();
+ else if(id == "action")
+ return QString::fromStdString(data_.at(row).user_action_str());
+ else if(id == "password")
+ return QString::fromStdString(data_.at(row).jobs_password());
+ else if(id == "child")
+ return QString::fromStdString(ecf::Child::to_string(data_.at(row).last_child_cmd()));
+ else if(id == "pid")
+ return QString::fromStdString(data_.at(row).process_or_remote_id());
+ else
+ return QVariant();
+ }
+
+ return QVariant();
+}
+
+QVariant ZombieModel::headerData( const int section, const Qt::Orientation orient , const int role ) const
+{
+ if ( orient != Qt::Horizontal || (role != Qt::DisplayRole && role != Qt::UserRole ))
+ return QAbstractItemModel::headerData( section, orient, role );
+
+ if(role == Qt::DisplayRole)
+ return columns_->label(section);
+ else if(role == Qt::UserRole)
+ return columns_->id(section);
+
+ return QVariant();
+}
+
+QModelIndex ZombieModel::index( int row, int column, const QModelIndex & parent ) const
+{
+ if(!hasData() || row < 0 || column < 0)
+ {
+ return QModelIndex();
+ }
+
+ //When parent is the root this index refers to a node or server
+ if(!parent.isValid())
+ {
+ return createIndex(row,column);
+ }
+
+ return QModelIndex();
+
+}
+
+QModelIndex ZombieModel::parent(const QModelIndex &child) const
+{
+ return QModelIndex();
+}
diff --git a/Viewer/src/ZombieModel.hpp b/Viewer/src/ZombieModel.hpp
new file mode 100644
index 0000000..b63321c
--- /dev/null
+++ b/Viewer/src/ZombieModel.hpp
@@ -0,0 +1,40 @@
+#ifndef ZOMBIEMODEL_H
+#define ZOMBIEMODEL_H
+
+#include <QAbstractItemModel>
+#include <QSortFilterProxyModel>
+
+#include <vector>
+
+#include "Zombie.hpp"
+
+class ModelColumn;
+
+class ZombieModel : public QAbstractItemModel
+{
+public:
+ explicit ZombieModel(QObject *parent=0);
+ ~ZombieModel();
+
+ int columnCount (const QModelIndex& parent = QModelIndex() ) const;
+ int rowCount (const QModelIndex& parent = QModelIndex() ) const;
+
+ Qt::ItemFlags flags ( const QModelIndex & index) const;
+ QVariant data (const QModelIndex& , int role = Qt::DisplayRole ) const;
+ QVariant headerData(int,Qt::Orientation,int role = Qt::DisplayRole ) const;
+
+ QModelIndex index (int, int, const QModelIndex& parent = QModelIndex() ) const;
+ QModelIndex parent (const QModelIndex & ) const;
+
+ void setData(const std::vector<Zombie>&);
+ bool updateData(const std::vector<Zombie>&);
+ void clearData();
+ bool hasData() const;
+
+protected:
+ std::vector<Zombie> data_;
+ ModelColumn* columns_;
+};
+
+
+#endif
diff --git a/Viewer/src/viewer.qrc b/Viewer/src/viewer.qrc
new file mode 100644
index 0000000..353537d
--- /dev/null
+++ b/Viewer/src/viewer.qrc
@@ -0,0 +1,93 @@
+<RCC>
+ <qresource prefix="viewer">
+ <file>../images/goto_line.svg</file>
+ <file>../images/dock_float.svg</file>
+ <file>../images/dock_close.svg</file>
+ <file alias="configure.svg">../images/configure.svg</file>
+ <file alias="reset.svg">../images/reset.svg</file>
+ <file alias="search.svg">../images/search.svg</file>
+ <file alias="info.svg">../images/info.svg</file>
+ <file>../images/add_info.svg</file>
+ <file>../images/add_table.svg</file>
+ <file>../images/add_tree.svg</file>
+ <file alias="icon_calendar.svg">../images/icon_calendar.svg</file>
+ <file alias="icon_clock.svg">../images/icon_clock.svg</file>
+ <file alias="icon_complete.svg">../images/icon_complete.svg</file>
+ <file alias="icon_late.svg">../images/icon_late.svg</file>
+ <file alias="icon_node_log.svg">../images/icon_node_log.svg</file>
+ <file alias="icon_rerun.svg">../images/icon_rerun.svg</file>
+ <file alias="icon_slow.svg">../images/icon_slow.svg</file>
+ <file alias="icon_waiting.svg">../images/icon_waiting.svg</file>
+ <file alias="icon_zombie.svg">../images/icon_zombie.svg</file>
+ <file>../images/arrow_up.svg</file>
+ <file>../images/arrow_down.svg</file>
+ <file>../images/add.svg</file>
+ <file>../images/close.svg</file>
+ <file>../images/configure.svg</file>
+ <file>../images/exit.svg</file>
+ <file alias="add_tab.svg">../images/add_tab.svg</file>
+ <file alias="attribute.svg">../images/attribute.svg</file>
+ <file alias="chain.svg">../images/chain.svg</file>
+ <file alias="clear_left.svg">../images/clear_left.svg</file>
+ <file alias="case_sensitive.svg">../images/case_sensitive.svg</file>
+ <file alias="colour.svg">../images/colour.svg</file>
+ <file alias="directory_arrow.svg">../images/directory_arrow.svg</file>
+ <file alias="dock_config.svg">../images/dock_config.svg</file>
+ <file alias="dock_menu_indicator.png">../images/dock_menu_indicator.png</file>
+ <file alias="drawer_open.svg">../images/drawer_open.svg</file>
+ <file alias="drawer_close.svg">../images/drawer_close.svg</file>
+ <file alias="edit.svg">../images/edit.svg</file>
+ <file alias="editcopy.svg">../images/editcopy.svg</file>
+ <file alias="editpaste.svg">../images/editpaste.svg</file>
+ <file alias="error.svg">../images/error.svg</file>
+ <file alias="favourite.svg">../images/favourite.svg</file>
+ <file alias="favourite_empty.svg">../images/favourite_empty.svg</file>
+ <file alias="filesave.svg">../images/filesave.svg</file>
+ <file alias="filter_decor.svg">../images/filter_decor.svg</file>
+ <file alias="filter_edit.svg">../images/filter_edit.svg</file>
+ <file alias="filter.svg">../images/filter.svg</file>
+ <file alias="font.svg">../images/font.svg</file>
+ <file alias="fontsize_down.svg">../images/fontsize_down.svg</file>
+ <file alias="fontsize_up.svg">../images/fontsize_up.svg</file>
+ <file alias="genvar.svg">../images/genvar.svg</file>
+ <file alias="genvar_shadow.svg">../images/genvar_shadow.svg</file>
+ <file alias="grey_info.svg">../images/grey_info.svg</file>
+ <file alias="overview.svg">../images/overview.svg</file>
+ <file alias="job.svg">../images/job.svg</file>
+ <file alias="large_file_search.svg">../images/large_file_search.svg</file>
+ <file alias="log_info.svg">../images/log_info.svg</file>
+ <file alias="log_error.svg">../images/log_error.svg</file>
+ <file alias="manage_server.svg">../images/manage_server.svg</file>
+ <file alias="manual.svg">../images/manual.svg</file>
+ <file alias="node_log.svg">../images/node_log.svg</file>
+ <file alias="notification.svg">../images/notification.svg</file>
+ <file alias="output.svg">../images/output.svg</file>
+ <file alias="padlock.svg">../images/padlock.svg</file>
+ <file alias="path_arrow.svg">../images/path_arrow.svg</file>
+ <file alias="reload.svg">../images/reload.svg</file>
+ <file alias="reload_one.svg">../images/reload_one.svg</file>
+ <file alias="rescue.svg">../images/rescue.svg</file>
+ <file alias="reset_to_default.svg">../images/reset_to_default.svg</file>
+ <file alias="script.svg">../images/script.svg</file>
+ <file alias="search_decor.svg">../images/search_decor.svg</file>
+ <file alias="select_all.svg">../images/select_all.svg</file>
+ <file alias="server.svg">../images/server.svg</file>
+ <file alias="server_log.svg">../images/server_log.svg</file>
+ <file alias="show_shadowed.svg">../images/show_shadowed.svg</file>
+ <file alias="spinning_wheel.gif">../images/spinning_wheel.gif</file>
+ <file alias="splash_screen.png">../images/splash_screen.png</file>
+ <file alias="status.svg">../images/status.svg</file>
+ <file alias="submit.svg">../images/submit.svg</file>
+ <file alias="sync.svg">../images/sync.svg</file>
+ <file alias="terminate.svg">../images/terminate.svg</file>
+ <file alias="tree_branch_end.png">../images/tree_branch_end.png</file>
+ <file alias="tree_branch_more.png">../images/tree_branch_more.png</file>
+ <file alias="tree_vline.png">../images/tree_vline.png</file>
+ <file alias="unknown.svg">../images/unknown.svg</file>
+ <file alias="unselect_all.svg">../images/unselect_all.svg</file>
+ <file alias="variable.svg">../images/variable.svg</file>
+ <file alias="warning.svg">../images/warning.svg</file>
+ <file alias="why.svg">../images/why.svg</file>
+ <file alias="zombie.svg">../images/zombie.svg</file>
+ </qresource>
+</RCC>
diff --git a/bin/ecbuild b/bin/ecbuild
new file mode 100755
index 0000000..d1ffff4
--- /dev/null
+++ b/bin/ecbuild
@@ -0,0 +1,442 @@
+#!/bin/bash
+
+set -eua
+
+CMAKE_MIN_REQUIRED=2.8.10
+CMAKE_BUILD_VERSION=3.4.1
+
+usage()
+{
+ echo "Usage: ecbuild [--help] [--version]"
+ exit $1
+}
+
+help()
+{
+ cat <<EOF
+USAGE:
+
+ ecbuild [--help] [--version] [--toolchains]
+ ecbuild [option...] [--] [cmake-argument...] <path-to-source>
+ ecbuild [option...] [--] [cmake-argument...] <path-to-existing-build>
+
+DESCRIPTION:
+
+ ecbuild is a build system based on CMake, but providing a lot of macro's
+ to make it easier to work with. Upon execution,
+ the equivalent cmake command is printed.
+
+ ecbuild/cmake must be called from an out-of-source build directory and
+ forbids in-source builds.
+
+SYNOPSIS:
+
+ --help Display this help
+ --version Display ecbuild version
+ --toolchains Display list of pre-installed toolchains (see below)
+
+
+Available values for "option":
+
+ --cmakebin=<path>
+ Set which cmake binary to use. Default is 'cmake'
+
+ --prefix=<prefix>
+ Set the install path to <prefix>.
+ Equivalent to cmake argument "-DCMAKE_INSTALL_PREFIX=<prefix>"
+
+ --build=<build-type>
+ Set the build-type to <build-type>.
+ Equivalent to cmake argument "-DCMAKE_BUILD_TYPE=<build-type>"
+ <build-type> can be any of:
+ - debug : Lowest optimization level, useful for debugging
+ - release : Highest optimization level, for best performance
+ - bit : Highest optimization level while staying bit-reproducible
+ - ...others depending on project
+
+ --log=<log-level>
+ Set the ecbuild log-level
+ Equivalent to "-DECBUILD_LOG_LEVEL=<log-level>"
+ <log-level> can be any of:
+ - DEBUG
+ - INFO
+ - WARN
+ - ERROR
+ - CRITICAL
+ - OFF
+ Every choice outputs also the log-levels listed below itself
+
+ --static
+ Build static libraries.
+ Equivalent to "-DBUILD_SHARED_LIBS=OFF"
+
+ --dynamic, --shared
+ Build dynamic libraries (usually the default).
+ Equivalent to "-DBUILD_SHARED_LIBS=ON"
+
+ --config=<config>
+ Configuration file using CMake syntax that gets included
+ Equivalent to cmake argument "-DECBUILD_CONFIG=<config-file>"
+
+ --toolchain=<toolchain>
+ Use a platform specific toolchain, containing settings such
+ as compilation flags, locations of commonly used dependencies.
+ <toolchain> can be the path to a custom toolchain file, or a
+ pre-installed toolchain provided with ecbuild. For a list of
+ pre-installed toolchains, run "ecbuild --toolchains".
+ Equivalent to cmake argument "-DCMAKE_TOOLCHAIN_FILE=<toolchain-file>"
+
+ --cache=<ecbuild-cache-file> (advanced)
+ A file called "ecbuild-cache.cmake" is generated during configuration.
+ This file can be moved to a safe location, and specified for future
+ builds to speed up checking of compiler/platform capabilities. Note
+ that this is only accelerating fresh builds, as cmake internally
+ caches also. Therefore this option is *not* recommended.
+
+ --build-cmake
+ Automatically download and build CMake version $CMAKE_BUILD_VERSION if the CMake
+ version found does not meet the minimum requirements (version $CMAKE_MIN_REQUIRED
+ is required). Requires an internet connection and may take a while.
+
+ --dryrun
+ Don't actually execute the cmake call, just print what would have
+ been executed.
+
+
+Available values for "cmake-argument":
+
+ Any value that can be usually passed to cmake to (re)configure the build.
+ Typically these values start with "-D".
+ example: -DENABLE_TESTS=ON -DENABLE_MPI=OFF -DECKIT_PATH=...
+
+ They can be explicitly separated from [option...] with a "--", for the case
+ there is a conflicting option with the "cmake" executable, and the latter's
+ option is requested.
+
+------------------------------------------------------------------------
+
+NOTE: When reconfiguring a build, it is only necessary to change the relevant
+options, as everything stays cached. For example:
+ > ecbuild --prefix=PREFIX .
+ > ecbuild -DENABLE_TESTS=ON .
+
+------------------------------------------------------------------------
+
+Compiling:
+
+ To compile the project with <N> threads:
+ > make -j<N>
+
+ To get verbose compilation/linking output:
+ > make VERBOSE=1
+
+Testing:
+
+ To run the project's tests
+ > ctest
+
+ Also check the ctest manual/help for more options on running tests
+
+Installing:
+
+ To install the project in location PREFIX with
+ "--prefix=PREFIX" or
+ "-DCMAKE_INSTALL_PREFIX=PREFIX"
+ > make install
+
+------------------------------------------------------------------------
+ECMWF"
+
+EOF
+ exit $1
+}
+
+INSTALL_DIR="$( cd $( dirname "${BASH_SOURCE[0]}" ) && pwd -P )"
+ECBUILD_MODULE_PATH=""
+# If there is a directory share/ecbuild/cmake relative to the parent directory
+# (as in an install tree), add it to CMAKE_MODULE_PATH
+if [ -d $INSTALL_DIR/../share/ecbuild/cmake ]; then
+ ECBUILD_MODULE_PATH="$( cd "$INSTALL_DIR/../share/ecbuild/cmake" && pwd -P )"
+# If there is a cmake subdirectory relative to the script directory (as in a
+# tarball), add it to CMAKE_MODULE_PATH
+elif [ -d $INSTALL_DIR/../cmake ]; then
+ ECBUILD_MODULE_PATH="$( cd "$INSTALL_DIR/../cmake" && pwd -P )"
+fi
+
+# Fail if we couldn't find ecBuild modules
+if [ ! -f "$ECBUILD_MODULE_PATH/VERSION.cmake" ]; then
+ echo "FATAL: ecBuild modules could not be found in either $INSTALL_DIR/../share/ecbuild/cmake or $INSTALL_DIR/../cmake" >&2
+ exit 1
+fi
+
+ADD_ECBUILD_OPTIONS="-DCMAKE_MODULE_PATH=$ECBUILD_MODULE_PATH"
+
+if [ -d $INSTALL_DIR/../share/ecbuild/toolchains ]; then
+ ECBUILD_TOOLCHAIN_DIR="$( cd "$INSTALL_DIR/../share/ecbuild/toolchains" && pwd -P )"
+elif [ -d $INSTALL_DIR/share/ecbuild/toolchains ]; then
+ ECBUILD_TOOLCHAIN_DIR="$( cd "$INSTALL_DIR/share/ecbuild/toolchains" && pwd -P )"
+fi
+
+version()
+{
+ ecbuild_version=$(cat ${ECBUILD_MODULE_PATH}/VERSION.cmake | grep ECBUILD_VERSION_STR | perl -p -e 's/.*([\d]\.[\d]\.[\d]).*/\1/' )
+ echo "ecbuild version ${ecbuild_version}"
+ command -v cmake >/dev/null 2>&1 || { exit 0; }
+ cmake --version | head -1
+ exit 0
+}
+
+log()
+{
+ log_level=$(tr "[a-z]" "[A-Z]" <<< "$1")
+ ADD_ECBUILD_OPTIONS="$ADD_ECBUILD_OPTIONS -DECBUILD_LOG_LEVEL=${log_level}"
+}
+
+toolchains()
+{
+ if [ -d $ECBUILD_TOOLCHAIN_DIR ]; then
+ cd $ECBUILD_TOOLCHAIN_DIR
+ echo "Available toolchains:"
+ ls | while read fname
+ do
+ echo " - ${fname%%.*}"
+ done
+ exit 0
+ else
+ echo "No toolchains available."
+ exit 1
+ fi
+}
+
+prefix()
+{
+ ADD_ECBUILD_OPTIONS="$ADD_ECBUILD_OPTIONS -DCMAKE_INSTALL_PREFIX=${1/#\~\//$HOME/}"
+}
+
+config()
+{
+ arg=${1/#\~\//$HOME/}
+ if [ -f $arg ]; then
+ config_file=$arg
+ config_file="$( cd $( dirname "${config_file}" ) && pwd -P )/$( basename ${config_file} )"
+ else
+ echo "Error:"
+ echo " Config file [$arg] is not found or is not a file."
+ exit 1
+ fi
+ ADD_ECBUILD_OPTIONS="$ADD_ECBUILD_OPTIONS -DECBUILD_CONFIG=${config_file}"
+}
+
+toolchain()
+{
+ arg=${1/#\~\//$HOME/}
+ if [ -f $arg ]; then
+ toolchain_file=$arg
+ else
+ if [ -f $ECBUILD_TOOLCHAIN_DIR/$arg.cmake ]; then
+ toolchain_file=$ECBUILD_TOOLCHAIN_DIR/$arg.cmake
+ fi
+ fi
+ if [ -z ${toolchain_file+x} ]; then
+ echo "Error:"
+ echo " Toolchain [$arg] is not valid: [$arg.cmake] cannot be"
+ echo " found in [$ECBUILD_TOOLCHAIN_DIR]"
+ exit 1
+ else
+ ADD_ECBUILD_OPTIONS="$ADD_ECBUILD_OPTIONS -DCMAKE_TOOLCHAIN_FILE=${toolchain_file}"
+ fi
+}
+
+cache()
+{
+ arg=$1
+ if [ -f $arg ]; then
+ cache_file=$arg
+ cache_file="$( cd $( dirname "${cache_file}" ) && pwd -P )/$( basename ${cache_file} )"
+ else
+ echo "Error:"
+ echo " Cache file [$arg] is not found or is not a file."
+ exit 1
+ fi
+ ADD_ECBUILD_OPTIONS="$ADD_ECBUILD_OPTIONS -DECBUILD_CACHE=${cache_file}"
+}
+
+if test $# -eq 0; then
+ usage 1
+fi
+
+while test $# -gt 0; do
+
+ # Split --option=value in $opt="--option" and $val="value"
+
+ opt=""
+ val=""
+
+ case "$1" in
+ --*=*)
+ opt=`echo "$1" | sed 's/=.*//'`
+ val=`echo "$1" | sed 's/--[_a-zA-Z0-9]*=//'`
+ ;;
+ --*)
+ opt=$1
+ ;;
+ # -D*)
+ # ADD_ECBUILD_OPTIONS="$ADD_ECBUILD_OPTIONS $1"
+ # ;;
+ *)
+ break
+ ;;
+ esac
+
+ # echo "debug opt: $opt $val"
+
+ # Parse options
+ case "$opt" in
+ --help)
+ help 0
+ ;;
+ --version)
+ version
+ ;;
+ --dryrun)
+ dryrun="yes"
+ ;;
+ --toolchains)
+ toolchains
+ ;;
+ --cmakebin)
+ cmakebin="$val"
+ ;;
+ --prefix)
+ prefix "$val"
+ ;;
+ --build)
+ ADD_ECBUILD_OPTIONS="$ADD_ECBUILD_OPTIONS -DCMAKE_BUILD_TYPE=$val"
+ ;;
+ --log)
+ log $val
+ ;;
+ --static)
+ ADD_ECBUILD_OPTIONS="$ADD_ECBUILD_OPTIONS -DBUILD_SHARED_LIBS=OFF"
+ ;;
+ --dynamic)
+ ADD_ECBUILD_OPTIONS="$ADD_ECBUILD_OPTIONS -DBUILD_SHARED_LIBS=ON"
+ ;;
+ --shared)
+ ADD_ECBUILD_OPTIONS="$ADD_ECBUILD_OPTIONS -DBUILD_SHARED_LIBS=ON"
+ ;;
+ --toolchain)
+ toolchain $val
+ ;;
+ --config)
+ config $val
+ ;;
+ --cache)
+ cache $val
+ ;;
+ --build-cmake)
+ build_cmake="yes"
+ ;;
+ --)
+ shift
+ break
+ ;;
+ *)
+ echo "unknown option: $opt"
+ usage 1
+ ;;
+ esac
+ shift
+done
+
+# If no arguments remain, set srcARG to "."
+if [ $# -eq 0 ]; then
+ srcARG="."
+fi
+
+src=${srcARG:=""}
+cmake=${cmakebin:=cmake}
+dryrun=${dryrun:=no}
+build_cmake=${build_cmake:=""}
+cmake_found=""
+cmake_version_sufficient=""
+
+
+# Check that version $1 satisfies $2
+# CMake versions have no more than 4 fields
+# (adapted from http://stackoverflow.com/a/25731924/396967)
+version_gte() {
+ [ "$2" = "$(echo -e "$1\n$2" | sort -t '.' -k 1,1 -k 2,2 -k 3,3 -k 4,4 -g | head -n1)" ]
+}
+
+# Check if the cmake version is sufficient
+check_cmake() {
+ # Check if cmake is available
+ if $(command -v $cmake >/dev/null 2>&1); then
+ cmake_found="yes"
+ cmake_version=$($cmake --version | head -n1 | awk '{ print $3 }')
+ echo "Found CMake version $cmake_version" >& 2
+ if version_gte $cmake_version $CMAKE_MIN_REQUIRED; then
+ cmake_version_sufficient="yes"
+ fi
+ fi
+}
+check_cmake
+# Use already built CMake if any
+if [[ ! $cmake_version_sufficient && -x bin/cmake ]]; then
+ echo "Using already built CMake in $PWD/bin/cmake" >&2
+ cmake=bin/cmake
+ check_cmake
+fi
+
+# Build CMake if requested and no sufficient version found
+if [[ ! $cmake_version_sufficient && $build_cmake ]]; then
+ echo "CMake version $CMAKE_MIN_REQUIRED is required but only $cmake_version was found." >&2
+ echo "Building CMake version ${CMAKE_BUILD_VERSION} ..." >&2
+ tarball=cmake-${CMAKE_BUILD_VERSION}.tar.gz
+ if [[ ! -r $tarball ]]; then
+ url=http://www.cmake.org/files/v${CMAKE_BUILD_VERSION:0:3}/$tarball
+ # -N Download only if the remote version of the file is newer
+ # --continue Continue an interrupted download
+ # -T 60 Time out a download attempt after 60 seconds
+ # -t 3 Only make 3 download attempts
+ wget -N --continue -T 60 -t 3 $url || {
+ echo "Failed to download CMake release $CMAKE_BUILD_VERSION." >&2
+ echo "Please download from $url" >&2
+ echo "and place $tarball in $PWD" >&2
+ exit 1
+ }
+ fi
+ tar xzf cmake-${CMAKE_BUILD_VERSION}.tar.gz
+ (
+ mkdir -p build_cmake
+ cd build_cmake
+ ../cmake-${CMAKE_BUILD_VERSION}/bootstrap --prefix=.. && make && make install
+ )
+ cmake=bin/cmake
+ check_cmake
+fi
+
+# Fail if we don't have a sufficient CMake
+if [[ ! $cmake_version_sufficient ]]; then
+ if [[ ! $cmake_found ]]; then
+ echo "CMake is required and cannot be found in the PATH." >&2
+ else
+ echo "CMake version $CMAKE_MIN_REQUIRED is required but only $cmake_version was found." >&2
+ fi
+ echo "" >&2
+ echo " Try 'module load cmake', specify a CMake binary with --cmakebin=/path/to/cmake" >&2
+ echo " or let ecbuild download and build CMake with the --build-cmake option." >&2
+ exit 1
+fi
+
+echo ""
+echo "$cmake ${ADD_ECBUILD_OPTIONS} $@ $src"
+echo ""
+
+if [ ${dryrun} == "yes" ]; then
+ echo "[DRYRUN] -- not executing"
+ exit 0
+fi
+
+$cmake ${ADD_ECBUILD_OPTIONS} "$@" $src
diff --git a/ecflow_4_0_7/boost-build.jam b/boost-build.jam
similarity index 100%
rename from ecflow_4_0_7/boost-build.jam
rename to boost-build.jam
diff --git a/build_scripts/.pydevproject b/build_scripts/.pydevproject
new file mode 100644
index 0000000..a9cca03
--- /dev/null
+++ b/build_scripts/.pydevproject
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?eclipse-pydev version="1.0"?>
+
+<pydev_project>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
+</pydev_project>
diff --git a/build_scripts/aix_fix/README b/build_scripts/aix_fix/README
new file mode 100644
index 0000000..1e440fd
--- /dev/null
+++ b/build_scripts/aix_fix/README
@@ -0,0 +1,118 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+Boost 1.44
+=================================================================================
+force_include.hpp needs to be moved to boost/serialization/force_include.hpp
+This file fixes serialization via base ptr bugs, for Boost version < 1.44
+
+
+Boost 1.45, Serialisation crashes in release mode.
+==================================================================================
+
+FROM IBM:
+We have a Boost patch fix that fixes Serialization library runtime problems experienced at -O3
+
+The symptom's root cause is in singleton pattern of Serialization library that uses static object
+that is created but not referenced.
+A trick in the library code is used to make a reference to this object by passing
+it to a function with empty body to keep it around for static initialization.
+Our optimizer aggressively inlines away the function with empty body, eliminating
+this trick of a reference. This explains why turning off inlining also works.
+Ensuring that we don't inline away this function will keep the static object around.
+
+This is a questionable Boost trick which we will advise either not use, or protect under macros.
+The fix is in your Boost header and no compiler changes are needed.
+
+The changes are in two header files attached:
+boost/serialization/force_include.hpp and
+boost/serialization/singleton.hpp
+
+(See attached file: singleton.hpp)(See attached file: force_include.hpp)
+(See attached file: header_diff_item2.txt)
+
+
+Boost 1.45
+=====================================================================================
+1/boost will will not build cleanly due to a compilation error in v3 filesystem
+the work around is to comment out the v3 file system dependencies.
+in $BOOST_ROOT/libs/filesystem/build/Jamfile.v2
+
+>>>>>> OR
+
+Change file path.hpp:
+FROM:
+ //------------------------------------------------------------------------------------//
+ // class path::iterator //
+ //------------------------------------------------------------------------------------//
+
+ class path::iterator
+ : public boost::iterator_facade<
+ iterator,
+ path const,
+ boost::bidirectional_traversal_tag >
+ {
+ ....
+TO:
+ //------------------------------------------------------------------------------------//
+ // class path::iterator //
+ //------------------------------------------------------------------------------------//
+
+ class path::iterator
+ : public boost::iterator_facade<
+ path::iterator,
+ path const,
+ boost::bidirectional_traversal_tag >
+ {
+ ....
+
+ie. since iterator_facade uses CRTP, the iterator is being interperted as "boost::iterator"
+ passing "path::iterator" as the template argument fixes the compile error on AIX.
+ This should be safe for other platforms as well
+
+ This has been registered as a bug. ticket #4912
+
+2/ Problems running python examples, with boost filesystem linked,
+
+
+Python: Effects all boost versions where we want to embed python interpreter in C++
+=====================================================================================
+The following exe's,on AIX, python 2.5 64 bit, acc v11.1,
+raise *hundreds* of warning messages of the type:
+ ld: 0711-224 WARNING: Duplicate symbol: _PyObject_New.
+linking with flags -bloadmap:PARM, reveals:
+
+ _Py_NoneStruct Objects/object.c(/usr/local/python64/lib/python2.5/config/libpython2.5.a[object.o])
+ ** Duplicate ** /usr/local/python64/lib/python2.5/config/python.exp{.}
+.Py_FatalError Python/pythonrun.c(/usr/local/python64/lib/python2.5/config/libpython2.5.a[pythonrun.o])
+ ** Duplicate ** /usr/local/python64/lib/python2.5/config/python.exp{.}
+
+It appears that the symbols are defined libpython2.5.a and in the exports file 'python.exp':
+removing the export file: -Wl,-bI:/usr/local/python64/lib/python2.5/config/python.exp
+from the link line removes the warning messages
+
+This can be done explicitly: $BOOST_ROOT/tools/build/v2/tools/python.jam
+Go to line: 992 and comment out <linkflags>-Wl,-bI:$(libraries[1])/python.exp
+
+ else if $(target-os) = aix
+ {
+ alias python_for_extensions
+ :
+ : $(target-requirements)
+ :
+ : $(usage-requirements) # <linkflags>-Wl,-bI:$(libraries[1])/python.exp
+ ;
+ }
+
+
+This is not an absolute requirement, if you can live with warnings messages.
+The notes in python.jam seems to expect them: file python.jam
+
+ # the Python framework, even when building extensions. Note that framework
+ # builds of Python always use shared libraries, so we do not need to worry
+ # about duplicate Python symbols.
+
\ No newline at end of file
diff --git a/ecflow_4_0_7/build/aix_fix/boost_1_53_0/README b/build_scripts/aix_fix/boost_1_53_0/README
similarity index 100%
rename from ecflow_4_0_7/build/aix_fix/boost_1_53_0/README
rename to build_scripts/aix_fix/boost_1_53_0/README
diff --git a/ecflow_4_0_7/build/aix_fix/boost_1_53_0/thread.cpp b/build_scripts/aix_fix/boost_1_53_0/thread.cpp
similarity index 100%
rename from ecflow_4_0_7/build/aix_fix/boost_1_53_0/thread.cpp
rename to build_scripts/aix_fix/boost_1_53_0/thread.cpp
diff --git a/ecflow_4_0_7/build/aix_fix/force_include.hpp b/build_scripts/aix_fix/force_include.hpp
similarity index 100%
rename from ecflow_4_0_7/build/aix_fix/force_include.hpp
rename to build_scripts/aix_fix/force_include.hpp
diff --git a/ecflow_4_0_7/build/aix_fix/force_include.hpp_boost_1.44 b/build_scripts/aix_fix/force_include.hpp_boost_1.44
similarity index 100%
rename from ecflow_4_0_7/build/aix_fix/force_include.hpp_boost_1.44
rename to build_scripts/aix_fix/force_include.hpp_boost_1.44
diff --git a/ecflow_4_0_7/build/aix_fix/header_diff_item2.txt b/build_scripts/aix_fix/header_diff_item2.txt
similarity index 100%
rename from ecflow_4_0_7/build/aix_fix/header_diff_item2.txt
rename to build_scripts/aix_fix/header_diff_item2.txt
diff --git a/build_scripts/aix_fix/path.hpp b/build_scripts/aix_fix/path.hpp
new file mode 100644
index 0000000..5ccd721
--- /dev/null
+++ b/build_scripts/aix_fix/path.hpp
@@ -0,0 +1,714 @@
+// filesystem path.hpp ---------------------------------------------------------------//
+
+// Copyright Beman Dawes 2002-2005, 2009
+// Copyright Vladimir Prus 2002
+
+// Distributed under the Boost Software License, Version 1.0.
+// See http://www.boost.org/LICENSE_1_0.txt
+
+// Library home page: http://www.boost.org/libs/filesystem
+
+// path::stem(), extension(), and replace_extension() are based on
+// basename(), extension(), and change_extension() from the original
+// filesystem/convenience.hpp header by Vladimir Prus.
+
+#ifndef BOOST_FILESYSTEM_PATH_HPP
+#define BOOST_FILESYSTEM_PATH_HPP
+
+#include <boost/config.hpp>
+
+# if defined( BOOST_NO_STD_WSTRING )
+# error Configuration not supported: Boost.Filesystem V3 and later requires std::wstring support
+# endif
+
+#include <boost/filesystem/v3/config.hpp>
+#include <boost/filesystem/v3/path_traits.hpp> // includes <cwchar>
+#include <boost/system/error_code.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/iterator/iterator_facade.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/io/detail/quoted_manip.hpp>
+#include <boost/static_assert.hpp>
+#include <string>
+#include <iterator>
+#include <cstring>
+#include <iosfwd>
+#include <stdexcept>
+#include <cassert>
+#include <locale>
+#include <algorithm>
+
+#include <boost/config/abi_prefix.hpp> // must be the last #include
+
+namespace boost
+{
+namespace filesystem3
+{
+ //------------------------------------------------------------------------------------//
+ // //
+ // class path //
+ // //
+ //------------------------------------------------------------------------------------//
+
+ class BOOST_FILESYSTEM_DECL path
+ {
+ public:
+
+ // value_type is the character type used by the operating system API to
+ // represent paths.
+
+# ifdef BOOST_WINDOWS_API
+ typedef wchar_t value_type;
+# else
+ typedef char value_type;
+# endif
+ typedef std::basic_string<value_type> string_type;
+ typedef std::codecvt<wchar_t, char, std::mbstate_t> codecvt_type;
+
+
+ // ----- character encoding conversions -----
+
+ // Following the principle of least astonishment, path input arguments
+ // passed to or obtained from the operating system via objects of
+ // class path behave as if they were directly passed to or
+ // obtained from the O/S API, unless conversion is explicitly requested.
+ //
+ // POSIX specfies that path strings are passed unchanged to and from the
+ // API. Note that this is different from the POSIX command line utilities,
+ // which convert according to a locale.
+ //
+ // Thus for POSIX, char strings do not undergo conversion. wchar_t strings
+ // are converted to/from char using the path locale or, if a conversion
+ // argument is given, using a conversion object modeled on
+ // std::wstring_convert.
+ //
+ // The path locale, which is global to the thread, can be changed by the
+ // imbue() function. It is initialized to an implementation defined locale.
+ //
+ // For Windows, wchar_t strings do not undergo conversion. char strings
+ // are converted using the "ANSI" or "OEM" code pages, as determined by
+ // the AreFileApisANSI() function, or, if a conversion argument is given,
+ // using a conversion object modeled on std::wstring_convert.
+ //
+ // See m_pathname comments for further important rationale.
+
+ // rules needed for operating systems that use / or .
+ // differently, or format directory paths differently from file paths.
+ //
+ // ************************************************************************
+ //
+ // More work needed: How to handle an operating system that may have
+ // slash characters or dot characters in valid filenames, either because
+ // it doesn't follow the POSIX standard, or because it allows MBCS
+ // filename encodings that may contain slash or dot characters. For
+ // example, ISO/IEC 2022 (JIS) encoding which allows switching to
+ // JIS x0208-1983 encoding. A valid filename in this set of encodings is
+ // 0x1B 0x24 0x42 [switch to X0208-1983] 0x24 0x2F [U+304F Kiragana letter KU]
+ // ^^^^
+ // Note that 0x2F is the ASCII slash character
+ //
+ // ************************************************************************
+
+ // Supported source arguments: half-open iterator range, container, c-array,
+ // and single pointer to null terminated string.
+
+ // All source arguments except pointers to null terminated byte strings support
+ // multi-byte character strings which may have embedded nulls. Embedded null
+ // support is required for some Asian languages on Windows.
+
+ // "const codecvt_type& cvt=codecvt()" default arguments are not used because some
+ // compilers, such as Microsoft prior to VC++ 10, do not handle defaults correctly
+ // in templates.
+
+ // ----- constructors -----
+
+ path(){}
+
+ path(const path& p) : m_pathname(p.m_pathname) {}
+
+ template <class Source>
+ path(Source const& source,
+ typename boost::enable_if<path_traits::is_pathable<
+ typename boost::decay<Source>::type> >::type* =0)
+ {
+ path_traits::dispatch(source, m_pathname, codecvt());
+ }
+
+ template <class Source>
+ path(Source const& source, const codecvt_type& cvt)
+ // see note above explaining why codecvt() default arguments are not used
+ {
+ path_traits::dispatch(source, m_pathname, cvt);
+ }
+
+ template <class InputIterator>
+ path(InputIterator begin, InputIterator end)
+ {
+ if (begin != end)
+ {
+ std::basic_string<typename std::iterator_traits<InputIterator>::value_type>
+ s(begin, end);
+ path_traits::convert(s.c_str(), s.c_str()+s.size(), m_pathname, codecvt());
+ }
+ }
+
+ template <class InputIterator>
+ path(InputIterator begin, InputIterator end, const codecvt_type& cvt)
+ {
+ if (begin != end)
+ {
+ std::basic_string<typename std::iterator_traits<InputIterator>::value_type>
+ s(begin, end);
+ path_traits::convert(s.c_str(), s.c_str()+s.size(), m_pathname, cvt);
+ }
+ }
+
+ // ----- assignments -----
+
+ path& operator=(const path& p)
+ {
+ m_pathname = p.m_pathname;
+ return *this;
+ }
+
+ template <class Source>
+ typename boost::enable_if<path_traits::is_pathable<
+ typename boost::decay<Source>::type>, path&>::type
+ operator=(Source const& source)
+ {
+ m_pathname.clear();
+ path_traits::dispatch(source, m_pathname, codecvt());
+ return *this;
+ }
+
+ template <class Source>
+ path& assign(Source const& source, const codecvt_type& cvt)
+ {
+ m_pathname.clear();
+ path_traits::dispatch(source, m_pathname, cvt);
+ return *this;
+ }
+
+ template <class InputIterator>
+ path& assign(InputIterator begin, InputIterator end)
+ {
+ return assign(begin, end, codecvt());
+ }
+
+ template <class InputIterator>
+ path& assign(InputIterator begin, InputIterator end, const codecvt_type& cvt)
+ {
+ m_pathname.clear();
+ if (begin != end)
+ {
+ std::basic_string<typename std::iterator_traits<InputIterator>::value_type>
+ s(begin, end);
+ path_traits::convert(s.c_str(), s.c_str()+s.size(), m_pathname, cvt);
+ }
+ return *this;
+ }
+
+ // ----- appends -----
+
+ // if a separator is added, it is the preferred separator for the platform;
+ // slash for POSIX, backslash for Windows
+
+ path& operator/=(const path& p);
+
+ template <class Source>
+ typename boost::enable_if<path_traits::is_pathable<
+ typename boost::decay<Source>::type>, path&>::type
+ operator/=(Source const& source)
+ {
+ return append(source, codecvt());
+ }
+
+ template <class Source>
+ path& append(Source const& source, const codecvt_type& cvt);
+
+ template <class InputIterator>
+ path& append(InputIterator begin, InputIterator end)
+ {
+ return append(begin, end, codecvt());
+ }
+
+ template <class InputIterator>
+ path& append(InputIterator begin, InputIterator end, const codecvt_type& cvt);
+
+ // ----- modifiers -----
+
+ void clear() { m_pathname.clear(); }
+ path& make_preferred()
+# ifdef BOOST_POSIX_API
+ { return *this; } // POSIX no effect
+# else // BOOST_WINDOWS_API
+ ; // change slashes to backslashes
+# endif
+ path& remove_filename();
+ path& replace_extension(const path& new_extension = path());
+ void swap(path& rhs) { m_pathname.swap(rhs.m_pathname); }
+
+ // ----- observers -----
+
+ // For operating systems that format file paths differently than directory
+ // paths, return values from observers are formatted as file names unless there
+ // is a trailing separator, in which case returns are formatted as directory
+ // paths. POSIX and Windows make no such distinction.
+
+ // Implementations are permitted to return const values or const references.
+
+ // The string or path returned by an observer are specified as being formatted
+ // as "native" or "generic".
+ //
+ // For POSIX, these are all the same format; slashes and backslashes are as input and
+ // are not modified.
+ //
+ // For Windows, native: as input; slashes and backslashes are not modified;
+ // this is the format of the internally stored string.
+ // generic: backslashes are converted to slashes
+
+ // ----- native format observers -----
+
+ const string_type& native() const { return m_pathname; } // Throws: nothing
+ const value_type* c_str() const { return m_pathname.c_str(); } // Throws: nothing
+
+ template <class String>
+ String string() const;
+
+ template <class String>
+ String string(const codecvt_type& cvt) const;
+
+# ifdef BOOST_WINDOWS_API
+ const std::string string() const { return string(codecvt()); }
+ const std::string string(const codecvt_type& cvt) const
+ {
+ std::string tmp;
+ if (!m_pathname.empty())
+ path_traits::convert(&*m_pathname.begin(), &*m_pathname.begin()+m_pathname.size(),
+ tmp, cvt);
+ return tmp;
+ }
+
+ // string_type is std::wstring, so there is no conversion
+ const std::wstring& wstring() const { return m_pathname; }
+ const std::wstring& wstring(const codecvt_type&) const { return m_pathname; }
+
+# else // BOOST_POSIX_API
+ // string_type is std::string, so there is no conversion
+ const std::string& string() const { return m_pathname; }
+ const std::string& string(const codecvt_type&) const { return m_pathname; }
+
+ const std::wstring wstring() const { return wstring(codecvt()); }
+ const std::wstring wstring(const codecvt_type& cvt) const
+ {
+ std::wstring tmp;
+ if (!m_pathname.empty())
+ path_traits::convert(&*m_pathname.begin(), &*m_pathname.begin()+m_pathname.size(),
+ tmp, cvt);
+ return tmp;
+ }
+
+# endif
+
+ // ----- generic format observers -----
+
+ template <class String>
+ String generic_string() const;
+
+ template <class String>
+ String generic_string(const codecvt_type& cvt) const;
+
+# ifdef BOOST_WINDOWS_API
+ const std::string generic_string() const { return generic_string(codecvt()); }
+ const std::string generic_string(const codecvt_type& cvt) const;
+ const std::wstring generic_wstring() const;
+ const std::wstring generic_wstring(const codecvt_type&) const { return generic_wstring(); };
+
+# else // BOOST_POSIX_API
+ // On POSIX-like systems, the generic format is the same as the native format
+ const std::string& generic_string() const { return m_pathname; }
+ const std::string& generic_string(const codecvt_type&) const { return m_pathname; }
+ const std::wstring generic_wstring() const { return wstring(codecvt()); }
+ const std::wstring generic_wstring(const codecvt_type& cvt) const { return wstring(cvt); }
+
+# endif
+
+ // ----- decomposition -----
+
+ path root_path() const;
+ path root_name() const; // returns 0 or 1 element path
+ // even on POSIX, root_name() is non-empty() for network paths
+ path root_directory() const; // returns 0 or 1 element path
+ path relative_path() const;
+ path parent_path() const;
+ path filename() const; // returns 0 or 1 element path
+ path stem() const; // returns 0 or 1 element path
+ path extension() const; // returns 0 or 1 element path
+
+ // ----- query -----
+
+ bool empty() const { return m_pathname.empty(); } // name consistent with std containers
+ bool has_root_path() const { return has_root_directory() || has_root_name(); }
+ bool has_root_name() const { return !root_name().empty(); }
+ bool has_root_directory() const { return !root_directory().empty(); }
+ bool has_relative_path() const { return !relative_path().empty(); }
+ bool has_parent_path() const { return !parent_path().empty(); }
+ bool has_filename() const { return !m_pathname.empty(); }
+ bool has_stem() const { return !stem().empty(); }
+ bool has_extension() const { return !extension().empty(); }
+ bool is_absolute() const
+ {
+# ifdef BOOST_WINDOWS_API
+ return has_root_name() && has_root_directory();
+# else
+ return has_root_directory();
+# endif
+ }
+ bool is_relative() const { return !is_absolute(); }
+
+ // ----- imbue -----
+
+ static std::locale imbue(const std::locale& loc);
+
+ // ----- codecvt -----
+
+ static const codecvt_type& codecvt()
+ {
+ return *wchar_t_codecvt_facet();
+ }
+
+ // ----- iterators -----
+
+ class iterator;
+ typedef iterator const_iterator;
+
+ iterator begin() const;
+ iterator end() const;
+
+ // ----- deprecated functions -----
+
+# if defined(BOOST_FILESYSTEM_DEPRECATED) && defined(BOOST_FILESYSTEM_NO_DEPRECATED)
+# error both BOOST_FILESYSTEM_DEPRECATED and BOOST_FILESYSTEM_NO_DEPRECATED are defined
+# endif
+
+# if !defined(BOOST_FILESYSTEM_NO_DEPRECATED)
+ // recently deprecated functions supplied by default
+ path& normalize() { return m_normalize(); }
+ path& remove_leaf() { return remove_filename(); }
+ path leaf() const { return filename(); }
+ path branch_path() const { return parent_path(); }
+ bool has_leaf() const { return !m_pathname.empty(); }
+ bool has_branch_path() const { return !parent_path().empty(); }
+ bool is_complete() const { return is_absolute(); }
+# endif
+
+# if defined(BOOST_FILESYSTEM_DEPRECATED)
+ // deprecated functions with enough signature or semantic changes that they are
+ // not supplied by default
+ const std::string file_string() const { return string(); }
+ const std::string directory_string() const { return string(); }
+ const std::string native_file_string() const { return string(); }
+ const std::string native_directory_string() const { return string(); }
+ const string_type external_file_string() const { return native(); }
+ const string_type external_directory_string() const { return native(); }
+
+ // older functions no longer supported
+ //typedef bool (*name_check)(const std::string & name);
+ //basic_path(const string_type& str, name_check) { operator/=(str); }
+ //basic_path(const typename string_type::value_type* s, name_check)
+ // { operator/=(s);}
+ //static bool default_name_check_writable() { return false; }
+ //static void default_name_check(name_check) {}
+ //static name_check default_name_check() { return 0; }
+ //basic_path& canonize();
+# endif
+
+//--------------------------------------------------------------------------------------//
+// class path private members //
+//--------------------------------------------------------------------------------------//
+
+ private:
+# if defined(_MSC_VER)
+# pragma warning(push) // Save warning settings
+# pragma warning(disable : 4251) // disable warning: class 'std::basic_string<_Elem,_Traits,_Ax>'
+# endif // needs to have dll-interface...
+/*
+ m_pathname has the type, encoding, and format required by the native
+ operating system. Thus for POSIX and Windows there is no conversion for
+ passing m_pathname.c_str() to the O/S API or when obtaining a path from the
+ O/S API. POSIX encoding is unspecified other than for dot and slash
+ characters; POSIX just treats paths as a sequence of bytes. Windows
+ encoding is UCS-2 or UTF-16 depending on the version.
+*/
+ string_type m_pathname; // Windows: as input; backslashes NOT converted to slashes,
+ // slashes NOT converted to backslashes
+# if defined(_MSC_VER)
+# pragma warning(pop) // restore warning settings.
+# endif
+
+ string_type::size_type m_append_separator_if_needed();
+ // Returns: If separator is to be appended, m_pathname.size() before append. Otherwise 0.
+ // Note: An append is never performed if size()==0, so a returned 0 is unambiguous.
+
+ void m_erase_redundant_separator(string_type::size_type sep_pos);
+ string_type::size_type m_parent_path_end() const;
+ void m_portable();
+
+ path& m_normalize();
+
+ // Was qualified; como433beta8 reports:
+ // warning #427-D: qualified name is not allowed in member declaration
+ friend class iterator;
+ friend bool operator<(const path& lhs, const path& rhs);
+
+ // see path::iterator::increment/decrement comment below
+ static void m_path_iterator_increment(path::iterator & it);
+ static void m_path_iterator_decrement(path::iterator & it);
+
+ static const codecvt_type *& wchar_t_codecvt_facet();
+
+ }; // class path
+
+# ifndef BOOST_FILESYSTEM_NO_DEPRECATED
+ typedef path wpath;
+# endif
+
+ //------------------------------------------------------------------------------------//
+ // class path::iterator //
+ //------------------------------------------------------------------------------------//
+
+ class path::iterator
+ : public boost::iterator_facade<
+ path::iterator,
+ path const,
+ boost::bidirectional_traversal_tag >
+ {
+ private:
+ friend class boost::iterator_core_access;
+ friend class boost::filesystem3::path;
+ friend void m_path_iterator_increment(path::iterator & it);
+ friend void m_path_iterator_decrement(path::iterator & it);
+
+ const path& dereference() const { return m_element; }
+
+ bool equal(const iterator & rhs) const
+ {
+ return m_path_ptr == rhs.m_path_ptr && m_pos == rhs.m_pos;
+ }
+
+ // iterator_facade derived classes don't seem to like implementations in
+ // separate translation unit dll's, so forward to class path static members
+ void increment() { m_path_iterator_increment(*this); }
+ void decrement() { m_path_iterator_decrement(*this); }
+
+ path m_element; // current element
+ const path * m_path_ptr; // path being iterated over
+ string_type::size_type m_pos; // position of name in
+ // m_path_ptr->m_pathname. The
+ // end() iterator is indicated by
+ // m_pos == m_path_ptr->m_pathname.size()
+ }; // path::iterator
+
+ //------------------------------------------------------------------------------------//
+ // //
+ // non-member functions //
+ // //
+ //------------------------------------------------------------------------------------//
+
+ // std::lexicographical_compare would infinately recurse because path iterators
+ // yield paths, so provide a path aware version
+ inline bool lexicographical_compare(path::iterator first1, path::iterator last1,
+ path::iterator first2, path::iterator last2)
+ {
+ for (; first1 != last1 && first2 != last2 ; ++first1, ++first2)
+ {
+ if (first1->native() < first2->native()) return true;
+ if (first2->native() < first1->native()) return false;
+ }
+ return first1 == last1 && first2 != last2;
+ }
+
+ inline bool operator<(const path& lhs, const path& rhs)
+ {
+ return lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
+ }
+
+ inline bool operator<=(const path& lhs, const path& rhs) { return !(rhs < lhs); }
+ inline bool operator> (const path& lhs, const path& rhs) { return rhs < lhs; }
+ inline bool operator>=(const path& lhs, const path& rhs) { return !(lhs < rhs); }
+
+ // equality operators act as if comparing generic format strings, to achieve the
+ // effect of lexicographical_compare element by element compare.
+ // operator==() efficiency is a concern; a user reported the original version 2
+ // !(lhs < rhs) && !(rhs < lhs) implementation caused a serious performance problem
+ // for a map of 10,000 paths.
+
+# ifdef BOOST_WINDOWS_API
+ inline bool operator==(const path& lhs, const path::value_type* rhs)
+ {
+ const path::value_type* l(lhs.c_str());
+ while ((*l == *rhs || (*l == L'\\' && *rhs == L'/') || (*l == L'/' && *rhs == L'\\'))
+ && *l) { ++l; ++rhs; }
+ return *l == *rhs || (*l == L'\\' && *rhs == L'/') || (*l == L'/' && *rhs == L'\\');
+ }
+ inline bool operator==(const path& lhs, const path& rhs) { return lhs == rhs.c_str(); }
+ inline bool operator==(const path& lhs, const path::string_type& rhs) { return lhs == rhs.c_str(); }
+ inline bool operator==(const path::string_type& lhs, const path& rhs) { return rhs == lhs.c_str(); }
+ inline bool operator==(const path::value_type* lhs, const path& rhs) { return rhs == lhs; }
+# else // BOOST_POSIX_API
+ inline bool operator==(const path& lhs, const path& rhs) { return lhs.native() == rhs.native(); }
+ inline bool operator==(const path& lhs, const path::string_type& rhs) { return lhs.native() == rhs; }
+ inline bool operator==(const path& lhs, const path::value_type* rhs) { return lhs.native() == rhs; }
+ inline bool operator==(const path::string_type& lhs, const path& rhs) { return lhs == rhs.native(); }
+ inline bool operator==(const path::value_type* lhs, const path& rhs) { return lhs == rhs.native(); }
+# endif
+
+ inline bool operator!=(const path& lhs, const path& rhs) { return !(lhs == rhs); }
+ inline bool operator!=(const path& lhs, const path::string_type& rhs) { return !(lhs == rhs); }
+ inline bool operator!=(const path& lhs, const path::value_type* rhs) { return !(lhs == rhs); }
+ inline bool operator!=(const path::string_type& lhs, const path& rhs) { return !(lhs == rhs); }
+ inline bool operator!=(const path::value_type* lhs, const path& rhs) { return !(lhs == rhs); }
+
+ inline void swap(path& lhs, path& rhs) { lhs.swap(rhs); }
+
+ inline path operator/(const path& lhs, const path& rhs) { return path(lhs) /= rhs; }
+
+ // inserters and extractors
+ // use boost::io::quoted() to handle spaces in paths
+ // use '&' as escape character to ease use for Windows paths
+
+ template <class Char, class Traits>
+ inline std::basic_ostream<Char, Traits>&
+ operator<<(std::basic_ostream<Char, Traits>& os, const path& p)
+ {
+ return os
+ << boost::io::quoted(p.string<std::basic_string<Char> >(), static_cast<Char>('&'));
+ }
+
+ template <class Char, class Traits>
+ inline std::basic_istream<Char, Traits>&
+ operator>>(std::basic_istream<Char, Traits>& is, path& p)
+ {
+ std::basic_string<Char> str;
+ is >> boost::io::quoted(str, static_cast<Char>('&'));
+ p = str;
+ return is;
+ }
+
+ // name_checks
+
+ // These functions are holdovers from version 1. It isn't clear they have much
+ // usefulness, or how to generalize them for later versions.
+
+ BOOST_FILESYSTEM_DECL bool portable_posix_name(const std::string & name);
+ BOOST_FILESYSTEM_DECL bool windows_name(const std::string & name);
+ BOOST_FILESYSTEM_DECL bool portable_name(const std::string & name);
+ BOOST_FILESYSTEM_DECL bool portable_directory_name(const std::string & name);
+ BOOST_FILESYSTEM_DECL bool portable_file_name(const std::string & name);
+ BOOST_FILESYSTEM_DECL bool native(const std::string & name);
+
+//--------------------------------------------------------------------------------------//
+// class path member template implementation //
+//--------------------------------------------------------------------------------------//
+
+ template <class InputIterator>
+ path& path::append(InputIterator begin, InputIterator end, const codecvt_type& cvt)
+ {
+ if (begin == end)
+ return *this;
+ string_type::size_type sep_pos(m_append_separator_if_needed());
+ std::basic_string<typename std::iterator_traits<InputIterator>::value_type>
+ s(begin, end);
+ path_traits::convert(s.c_str(), s.c_str()+s.size(), m_pathname, cvt);
+ if (sep_pos)
+ m_erase_redundant_separator(sep_pos);
+ return *this;
+ }
+
+ template <class Source>
+ path& path::append(Source const & source, const codecvt_type& cvt)
+ {
+ if (path_traits::empty(source))
+ return *this;
+ string_type::size_type sep_pos(m_append_separator_if_needed());
+ path_traits::dispatch(source, m_pathname, cvt);
+ if (sep_pos)
+ m_erase_redundant_separator(sep_pos);
+ return *this;
+ }
+
+//--------------------------------------------------------------------------------------//
+// class path member template specializations //
+//--------------------------------------------------------------------------------------//
+
+ template <> inline
+ std::string path::string<std::string>() const
+ { return string(); }
+
+ template <> inline
+ std::wstring path::string<std::wstring>() const
+ { return wstring(); }
+
+ template <> inline
+ std::string path::string<std::string>(const codecvt_type& cvt) const
+ { return string(cvt); }
+
+ template <> inline
+ std::wstring path::string<std::wstring>(const codecvt_type& cvt) const
+ { return wstring(cvt); }
+
+ template <> inline
+ std::string path::generic_string<std::string>() const
+ { return generic_string(); }
+
+ template <> inline
+ std::wstring path::generic_string<std::wstring>() const
+ { return generic_wstring(); }
+
+ template <> inline
+ std::string path::generic_string<std::string>(const codecvt_type& cvt) const
+ { return generic_string(cvt); }
+
+ template <> inline
+ std::wstring path::generic_string<std::wstring>(const codecvt_type& cvt) const
+ { return generic_wstring(cvt); }
+
+
+} // namespace filesystem3
+} // namespace boost
+
+//----------------------------------------------------------------------------//
+
+namespace boost
+{
+ namespace filesystem
+ {
+ using filesystem3::path;
+# ifndef BOOST_FILESYSTEM_NO_DEPRECATED
+ using filesystem3::wpath;
+# endif
+ using filesystem3::lexicographical_compare;
+ using filesystem3::portable_posix_name;
+ using filesystem3::windows_name;
+ using filesystem3::portable_name;
+ using filesystem3::portable_directory_name;
+ using filesystem3::portable_file_name;
+ using filesystem3::native;
+ using filesystem3::swap;
+ using filesystem3::operator<;
+ using filesystem3::operator==;
+ using filesystem3::operator!=;
+ using filesystem3::operator>;
+ using filesystem3::operator<=;
+ using filesystem3::operator>=;
+ using filesystem3::operator/;
+ using filesystem3::operator<<;
+ using filesystem3::operator>>;
+ }
+}
+
+//----------------------------------------------------------------------------//
+
+#include <boost/config/abi_suffix.hpp> // pops abi_prefix.hpp pragmas
+
+#endif // BOOST_FILESYSTEM_PATH_HPP
diff --git a/ecflow_4_0_7/build/aix_fix/singleton.hpp b/build_scripts/aix_fix/singleton.hpp
similarity index 100%
rename from ecflow_4_0_7/build/aix_fix/singleton.hpp
rename to build_scripts/aix_fix/singleton.hpp
diff --git a/build_scripts/boost_1_47_fix.sh b/build_scripts/boost_1_47_fix.sh
new file mode 100644
index 0000000..e6169d4
--- /dev/null
+++ b/build_scripts/boost_1_47_fix.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+# This file is used paths up version of the boost libs
+# This script Use $BOOST_ROOT and $WK environment variable
+# Assumes boost version 1.47
+
+# Check that a command is in the PATH.
+test_path ()
+{
+ if `command -v command 1>/dev/null 2>/dev/null`; then
+ command -v $1 1>/dev/null 2>/dev/null
+ else
+ hash $1 1>/dev/null 2>/dev/null
+ fi
+}
+
+test_uname ()
+{
+ if test_path uname; then
+ test `uname` = $*
+ fi
+}
+
+if test_uname Linux ; then
+
+ echo "Nothing to fix"
+
+elif test_uname HP-UX ; then
+
+ # Hack for utf8_codecvt_facet due to compiler build error on ACC
+ cp $WK/build_scripts/hpux_fix/utf8_codecvt_facet.cpp $BOOST_ROOT/libs/detail/
+
+elif test_uname AIX ; then
+
+ # Fix bug where release version crashes due to bug in Serialization/compiler
+ # See file $WK/build_scripts/aix_fix/README
+ cp $WK/build_scripts/aix_fix/singleton.hpp $BOOST_ROOT/boost/serialization/
+ cp $WK/build_scripts/aix_fix/force_include.hpp $BOOST_ROOT/boost/serialization/
+fi
diff --git a/build_scripts/boost_1_48_fix.sh b/build_scripts/boost_1_48_fix.sh
new file mode 100644
index 0000000..bbb306d
--- /dev/null
+++ b/build_scripts/boost_1_48_fix.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+# This file is used paths up version of the boost libs
+# This script Use $BOOST_ROOT and $WK environment variable
+# Assumes boost version 1.48
+
+# Check that a command is in the PATH.
+test_path ()
+{
+ if `command -v command 1>/dev/null 2>/dev/null`; then
+ command -v $1 1>/dev/null 2>/dev/null
+ else
+ hash $1 1>/dev/null 2>/dev/null
+ fi
+}
+
+test_uname ()
+{
+ if test_path uname; then
+ test `uname` = $*
+ fi
+}
+
+if test_uname Linux ; then
+
+ echo "Nothing to fix"
+
+elif test_uname HP-UX ; then
+
+ # Hack for utf8_codecvt_facet due to compiler build error on ACC
+ cp $WK/build_scripts/hpux_fix/utf8_codecvt_facet.cpp $BOOST_ROOT/libs/detail/
+
+ # Hack because boost::int8_t was being interpreted as a char,
+ # This cause duplicate class definition during template instantiation.
+ # in the file ./boost/numeric/conversion/detail/preprocessed/numeric_cast_traits.hpp
+ # See:: https://svn.boost.org/trac/boost/attachment/ticket/6158/cstdint_patch.diff
+ cp $WK/build_scripts/hpux_fix/cstdint.hpp $BOOST_ROOT/boost/
+
+elif test_uname AIX ; then
+
+ # Fix bug where release version crashes due to bug in Serialization/compiler
+ # See file $WK/build_scripts/aix_fix/README
+ cp $WK/build_scripts/aix_fix/singleton.hpp $BOOST_ROOT/boost/serialization/
+ cp $WK/build_scripts/aix_fix/force_include.hpp $BOOST_ROOT/boost/serialization/
+fi
diff --git a/build_scripts/boost_1_51_fix.sh b/build_scripts/boost_1_51_fix.sh
new file mode 100644
index 0000000..c0dba4a
--- /dev/null
+++ b/build_scripts/boost_1_51_fix.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+# This file is used paths up version of the boost libs
+# This script Use $BOOST_ROOT and $WK environment variable
+# Assumes boost version 1.51
+
+# Check that a command is in the PATH.
+test_path ()
+{
+ if `command -v command 1>/dev/null 2>/dev/null`; then
+ command -v $1 1>/dev/null 2>/dev/null
+ else
+ hash $1 1>/dev/null 2>/dev/null
+ fi
+}
+
+test_uname ()
+{
+ if test_path uname; then
+ test `uname` = $*
+ fi
+}
+
+if test_uname HP-UX ; then
+
+ # Hack for utf8_codecvt_facet due to compiler build error on ACC
+ cp $WK/build_scripts/hpux_fix/boost_1_51_0/utf8_codecvt_facet.ipp $BOOST_ROOT/boost/detail/.
+
+fi
diff --git a/build_scripts/boost_1_53_fix.sh b/build_scripts/boost_1_53_fix.sh
new file mode 100755
index 0000000..fb0291a
--- /dev/null
+++ b/build_scripts/boost_1_53_fix.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+# This file is used paths up version of the boost libs
+# This script Use $BOOST_ROOT and $WK environment variable
+# Assumes boost version 1.51
+
+# Check that a command is in the PATH.
+test_path ()
+{
+ if `command -v command 1>/dev/null 2>/dev/null`; then
+ command -v $1 1>/dev/null 2>/dev/null
+ else
+ hash $1 1>/dev/null 2>/dev/null
+ fi
+}
+
+test_uname ()
+{
+ if test_path uname; then
+ test `uname` = $*
+ fi
+}
+
+if test_uname Linux ; then
+
+ echo "Nothing to fix"
+
+elif test_uname HP-UX ; then
+
+ # Hack for utf8_codecvt_facet due to compiler build error on ACC
+ cp $WK/build_scripts/hpux_fix/boost_1_53_0/utf8_codecvt_facet.ipp $BOOST_ROOT/boost/detail/.
+
+ # Seems to only affect debug build of ecflow(serialisation) on HP-UX
+ # Hack because:
+ # more than one instance of overloaded function "throw_exception" matches the argument list
+ #
+ cp $WK/build_scripts/hpux_fix/boost_1_53_0/smart_cast.hpp $BOOST_ROOT/boost/serialization/.
+
+elif test_uname AIX ; then
+
+ # Fix bug with thread.cpp libs/thread/src/pthread/thread.cpp
+ # See file $WK/build_scripts/aix_fix/README
+ cp $WK/build_scripts/aix_fix/boost_1_53_0/thread.cpp $BOOST_ROOT/libs/thread/src/pthread/
+fi
diff --git a/build_scripts/boost_1_56_fix.sh b/build_scripts/boost_1_56_fix.sh
new file mode 100644
index 0000000..0cd9fd7
--- /dev/null
+++ b/build_scripts/boost_1_56_fix.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+# This script Use $BOOST_ROOT and $WK environment variable
+# Assumes boost version 1.56
+
+# See: https://svn.boost.org/trac/boost/ticket/10348
+cp $WK/build_scripts/fix/boost_1_56_0/shared_ptr_helper.hpp $BOOST_ROOT/boost/serialization/.
diff --git a/build_scripts/boost_1_57_fix.sh b/build_scripts/boost_1_57_fix.sh
new file mode 100644
index 0000000..afb27d0
--- /dev/null
+++ b/build_scripts/boost_1_57_fix.sh
@@ -0,0 +1,54 @@
+#!/bin/sh
+
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+# Assumes boost version 1.57
+
+# Fix 1:
+# o https://svn.boost.org/trac/boost/ticket/10749
+#
+# This fix was implemented directly on the boost dir, then the tar recreated
+# modify : shared_ptr_helper.hpp
+# to add
+# #include <boost/serialization/type_info_implementation.hpp>
+
+# Fix 2:
+# o maintain compatibility with boost 1.53 server/archives
+# Modified Boost archive version is specified in: $BOOST_ROOT/libs/serialization/src/basic_archive.cpp
+# From 11 -> 10
+#
+# There has not been any changes to boost that affects, text archives.
+# Testing with old version of the servers, and new clients, do not show any issues.
+#
+
+# Fix 1 notes:
+# In file included from /var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr.hpp:29:0,
+# from Base/src/cts/ClientToServerCmd.hpp:25,
+# from Base/test/TestRequeueNodeCmd.cpp:17:
+#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp: In static member function 'static const boost::serialization::extended_type_info* boost::serialization::shared_ptr_helper<SPT>::non_polymorphic::get_object_type(U&)':
+#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:108:39: error: 'type_info_implementation' in namespace 'boost::serialization' does not name a type
+#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:108:63: error: expected template-argument before '<' token
+#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:108:63: error: expected '>' before '<' token
+#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:109:13: error: template argument 1 is invalid
+#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:109:16: error: expected '(' before 'get_const_instance'
+#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:109:16: error: expected ';' before 'get_const_instance'
+#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:109:35: error: there are no arguments to 'get_const_instance' that depend on a template parameter, so a declaration of 'get_const_instance' must be available
+#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:109:35: note: (if you use '-fpermissive', G++ will accept your code, but allowing the use of an undeclared name is deprecated)
+#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp: In static member function 'static const boost::serialization::extended_type_info* boost::serialization::shared_ptr_helper<SPT>::polymorphic::get_object_type(U&)':
+#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:118:39: error: 'type_info_implementation' in namespace 'boost::serialization' does not name a type
+#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:118:63: error: expected template-argument before '<' token
+#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:118:63: error: expected '>' before '<' token
+#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:119:13: error: template argument 1 is invalid
+#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:119:16: error: expected '(' before 'get_const_instance'
+#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:119:16: error: expected ';' before 'get_const_instance'
+#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:119:35: error: there are no arguments to 'get_const_instance' that depend on a template parameter, so a declaration of 'get_const_instance' must be available
+#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp: In member function 'void boost::serialization::shared_ptr_helper<SPT>::reset(SPT<T>&, T*)':
+#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:131:17: error: 'type_info_implementation' is not a member of 'boost::serialization'
+#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:131:67: error: expected primary-expression before '>' token
+#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:131:70: error: '::type' has not been declared
+#...failed gcc.compile.c++ Base/bin/gcc-4.5/release/test/TestRequeueNodeCmd.o...
\ No newline at end of file
diff --git a/build_scripts/boost_build.sh b/build_scripts/boost_build.sh
new file mode 100755
index 0000000..e941265
--- /dev/null
+++ b/build_scripts/boost_build.sh
@@ -0,0 +1,178 @@
+#!/bin/sh
+
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+# ===============================================================
+# allow tool to be overridden
+tool=gcc
+if [ "$#" = 1 ] ; then
+ tool=$1
+fi
+
+# ===============================================================
+# This file is used build the boost libs used by ecflow
+# This script Use $BOOST_ROOT and $WK environment variable
+echo "WK=$WK"
+echo "BOOST_ROOT=$BOOST_ROOT"
+
+
+# ===============================================================
+# From boost 1.56 > the location of site-config.jam location has changed
+#
+SITE_CONFIG_LOCATION=$BOOST_ROOT/tools/build/v2/site-config.jam
+BOOST_VERSION="$(basename $BOOST_ROOT)"
+if [ "$BOOST_VERSION" = boost_1_56_0 -o "$BOOST_VERSION" = boost_1_57_0 -o "$BOOST_VERSION" = boost_1_58_0 ] ; then
+ SITE_CONFIG_LOCATION=$BOOST_ROOT/tools/build/src/site-config.jam
+fi
+
+
+# Check that a command is in the PATH.
+test_path ()
+{
+ if `command -v command 1>/dev/null 2>/dev/null`; then
+ command -v $1 1>/dev/null 2>/dev/null
+ else
+ hash $1 1>/dev/null 2>/dev/null
+ fi
+}
+
+test_uname ()
+{
+ if test_path uname; then
+ test `uname` = $*
+ fi
+}
+
+#
+# --layout=system -> libboost_system.a (default)
+# --layout=tagged -> libboost_system-mt-d.a(debug) libboost_system-mt.a(release)
+# --layout=versioned -> libboost_system-xlc-mt-d-1.42(debug) libboost_system-xlc-mt-1_42.a(release)
+#
+# for some reason on cray versioned does not embed the compiler name as a part
+# of the library name. However it it does add the boost version.
+# Hence we will use this to distinguish between the g++ and cray boost libs
+# On *CRAY* we can have 3 compilers we will use the versioned for CRAY and INTEL library
+layout=tagged
+
+CXXFLAGS=
+if test_uname Linux ; then
+ X64=$(uname -m)
+ if [ "$X64" = x86_64 ]
+ then
+ # PE_ENV is defined in cray environment, at least on sandy bridge
+ if [ "$PE_ENV" = GNU -o "$PE_ENV" = INTEL -o "$PE_ENV" = CRAY ]
+ then
+ CXXFLAGS=cxxflags=-fPIC
+ layout=versioned
+ tool=gcc
+ cp $WK/build_scripts/site_config/site-config-cray.jam $SITE_CONFIG_LOCATION
+ if [ "$PE_ENV" = INTEL ] ; then
+ tool=intel
+ fi
+ if [ "$PE_ENV" = CRAY ] ; then
+ tool=cray
+ fi
+ else
+ if [ $tool = gcc ] ; then
+
+ cp $WK/build_scripts/site_config/site-config-Linux64.jam $SITE_CONFIG_LOCATION
+ # for boost 1.53 and > gcc 4.8 get a lot warning messages use suppress
+ #CXXFLAGS=-no-unused-local-typedefs
+
+ elif [ $tool = intel ] ; then
+
+ cp $WK/build_scripts/site_config/site-config-Linux64-intel.jam $SITE_CONFIG_LOCATION
+ #module unload gnu
+ #module load intel/15.0.2
+
+ elif [ $tool = clang ] ; then
+
+ cp $WK/build_scripts/site_config/site-config-Linux64-clang.jam $SITE_CONFIG_LOCATION
+ fi
+ fi
+
+ else
+ cp $WK/build_scripts/site_config/site-config-Linux.jam $SITE_CONFIG_LOCATION
+ fi
+
+
+elif test_uname HP-UX ; then
+
+ tool=acc
+ cp $WK/build_scripts/site_config/site-config-HPUX.jam $SITE_CONFIG_LOCATION
+
+elif test_uname AIX ; then
+
+ # on c1a
+ tool=vacpp
+ cp $WK/build_scripts/site_config/site-config-AIX.jam $SITE_CONFIG_LOCATION
+fi
+
+# Only uncomment for debugging this script
+#rm -rf stage
+#rm -rf tmpBuildDir
+
+#
+# Note: if '--build-dir=./tmpBuildDir' is omitted, boost will build the libs in a directory:
+# bin.v2/
+# On completion, the library is copied to:
+# stage/lib/
+#
+
+# We use tagged as that allows the debug and release builds to built together
+#
+echo "using compiler $tool with build $1 variants "
+# ========================================================================
+# Note: boost thread *ONLY* need to test multi-threaded server See: define ECFLOW_MT
+# ========================================================================
+./bjam --build-dir=./tmpBuildDir toolset=$tool $CXXFLAGS stage link=static --layout=$layout --with-system variant=debug -j2
+./bjam --build-dir=./tmpBuildDir toolset=$tool $CXXFLAGS stage link=static --layout=$layout --with-date_time variant=debug -j2
+./bjam --build-dir=./tmpBuildDir toolset=$tool $CXXFLAGS stage link=static --layout=$layout --with-filesystem variant=debug -j2
+./bjam --build-dir=./tmpBuildDir toolset=$tool $CXXFLAGS stage link=static --layout=$layout --with-program_options variant=debug -j2
+./bjam --build-dir=./tmpBuildDir toolset=$tool $CXXFLAGS stage link=static --layout=$layout --with-serialization variant=debug -j2
+./bjam --build-dir=./tmpBuildDir toolset=$tool $CXXFLAGS stage link=static --layout=$layout --with-test variant=debug -j2
+./bjam --build-dir=./tmpBuildDir toolset=$tool $CXXFLAGS stage link=static --layout=$layout --with-thread variant=debug -j2
+./bjam --build-dir=./tmpBuildDir toolset=$tool $CXXFLAGS stage link=static --layout=$layout --with-regex variant=debug -j2 # ecflowUi
+
+
+
+# ========================================================================
+# Note: boost thread *ONLY* need to test multi-threaded server See: define ECFLOW_MT
+# ========================================================================
+./bjam --build-dir=./tmpBuildDir toolset=$tool $CXXFLAGS stage link=static --layout=$layout --with-system variant=release -j2
+./bjam --build-dir=./tmpBuildDir toolset=$tool $CXXFLAGS stage link=static --layout=$layout --with-date_time variant=release -j2
+./bjam --build-dir=./tmpBuildDir toolset=$tool $CXXFLAGS stage link=static --layout=$layout --with-filesystem variant=release -j2
+./bjam --build-dir=./tmpBuildDir toolset=$tool $CXXFLAGS stage link=static --layout=$layout --with-program_options variant=release -j2
+./bjam --build-dir=./tmpBuildDir toolset=$tool $CXXFLAGS stage link=static --layout=$layout --with-serialization variant=release -j2
+./bjam --build-dir=./tmpBuildDir toolset=$tool $CXXFLAGS stage link=static --layout=$layout --with-test variant=release -j2
+./bjam --build-dir=./tmpBuildDir toolset=$tool $CXXFLAGS stage link=static --layout=$layout --with-thread variant=release -j2
+./bjam --build-dir=./tmpBuildDir toolset=$tool $CXXFLAGS stage link=static --layout=$layout --with-regex variant=release -j2
+
+
+# Allow python to be disabled
+if [ -n "$ECF_NO_PYTHON" ] ; then
+ echo "****************************************************************************"
+ echo "Ignore boost python. ECF_NO_PYTHON set."
+ echo "****************************************************************************"
+else
+ # ================================================================================
+ # Build python
+ # ================================================================================
+ #*** If the boost python HAS not been built, and we build in $WK/Pyext, then it will build
+ #*** boost python in $BOOST_ROOT/bin.v2/
+ #*** It appears to build boost python single threaded. (i.e you do not see threading-multi) in the directory path.
+ #
+ # To prebuild the boost python, hence we need to do the following: For now build both variants, keeps cmake happy! (i.e when finding libs)
+ #
+ ./bjam toolset=$tool link=shared variant=debug $CXXFLAGS stage --layout=$layout threading=multi --with-python -d2 -j2
+ ./bjam toolset=$tool link=shared variant=release $CXXFLAGS stage --layout=$layout threading=multi --with-python -d2 -j2
+ ./bjam toolset=$tool link=static variant=debug $CXXFLAGS stage --layout=$layout threading=multi --with-python -d2 -j2
+ ./bjam toolset=$tool link=static variant=release $CXXFLAGS stage --layout=$layout threading=multi --with-python -d2 -j2
+fi
+
+
diff --git a/build_scripts/clean.sh b/build_scripts/clean.sh
new file mode 100755
index 0000000..992d9e5
--- /dev/null
+++ b/build_scripts/clean.sh
@@ -0,0 +1,67 @@
+#!/bin/sh
+
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+cd $WK
+
+# Remove the bin directories
+rm -rf ACore/bin
+rm -rf ANattr/bin
+rm -rf ANode/bin
+rm -rf AParser/bin
+rm -rf Base/bin
+rm -rf CSim/bin
+rm -rf Client/bin
+rm -rf Server/bin
+rm -rf Test/bin
+rm -rf Pyext/bin
+rm -rf view/bin
+
+# remove generated files
+rm -rf Doc/online/_build/*
+rm -rf Test/data/ECF_HOME_debug*
+rm -rf Test/data/ECF_HOME_release*
+rm -rf view/data/ECF_HOME_debug*
+rm -rf view/data/ECF_HOME_release*
+rm -rf AParser/test/data/single_defs/mega.def_log
+rm -rf Pyext/test.def
+rm -rf Pyext/build
+rm -rf Pyext/timestamp
+rm -rf bin
+rm -rf build
+rm -rf RemoteSystemsTempFiles
+rm -rf *.dat
+rm -rf *.log
+
+find . -name \*~ -exec rm -rf \*~ {} \; -print
+find . -name \*.mk -exec rm -rf \*.mk {} \; -print
+find . -name \*.o -exec rm -rf \*.mk {} \; -print
+find . -name \*.so -exec rm -rf \*.so {} \; -print
+find . -name \*.tmp -exec rm -rf \*.tmp {} \; -print
+find . -name \*.job\* -exec rm -rf \*.job\* {} \; -print
+find . -name \*.check -exec rm -rf \*.check {} \; -print
+find . -name \*.flat -exec rm -rf \*.flat {} \; -print
+find . -name \*.depth -exec rm -rf \*.depth {} \; -print
+find . -name \*.out -exec rm -rf \*.out {} \; -print
+find . -name \*.pyc -exec rm -rf \*.pyc {} \; -print
+find . -name t\*.1 -exec rm -rf t\*.1 {} \; -print
+find . -name gmon.out -exec rm -rf gmon.out {} \; -print
+find . -name gnuplot.dat -exec rm -rf gnuplot.dat {} \; -print
+find . -name gnuplot.script -exec rm -rf gnuplot.script {} \; -print
+find . -name ecflow.html -exec rm -rf ecflow.html {} \; -print
+find . -name core -exec rm -rf core {} \; -print
+find . -name `hostname`.*.ecf.* -exec rm -rf `hostname`.*.ecf.* {} \; -print
+find . -name callgrind.out.\* -exec rm -rf callgrind.out.\* {} \; -print
+find . -name massif.out.\* -exec rm -rf massif.out.* {} \; -print
+
+# remove any defs file at the workspace level. There should not be any
+rm -rf *.def
+
+# Remove any lock file create by tests which used EcfPortLock.hpp
+rm -rf *.lock
+
diff --git a/ecflow_4_0_7/build/cray_fix/boost_1_55_0/README b/build_scripts/cray_fix/boost_1_55_0/README
similarity index 100%
rename from ecflow_4_0_7/build/cray_fix/boost_1_55_0/README
rename to build_scripts/cray_fix/boost_1_55_0/README
diff --git a/ecflow_4_0_7/build/cray_fix/boost_1_55_0/cray.hpp b/build_scripts/cray_fix/boost_1_55_0/cray.hpp
similarity index 100%
rename from ecflow_4_0_7/build/cray_fix/boost_1_55_0/cray.hpp
rename to build_scripts/cray_fix/boost_1_55_0/cray.hpp
diff --git a/ecflow_4_0_7/build/cray_fix/boost_1_55_0/smalldiff b/build_scripts/cray_fix/boost_1_55_0/smalldiff
similarity index 100%
rename from ecflow_4_0_7/build/cray_fix/boost_1_55_0/smalldiff
rename to build_scripts/cray_fix/boost_1_55_0/smalldiff
diff --git a/build_scripts/cray_fix/swap.sh b/build_scripts/cray_fix/swap.sh
new file mode 100644
index 0000000..3aa51fd
--- /dev/null
+++ b/build_scripts/cray_fix/swap.sh
@@ -0,0 +1,100 @@
+#!/bin/ksh
+
+# ==================================================================
+# Setup environment on CRAY, allow switch between cray,intel and gnu
+# ==================================================================
+
+#set -e # stop the shell on first error
+#set -u # fail when using an undefined variable
+#set -x # echo script lines as they are executed
+
+if [[ "$#" != 1 ]] ; then
+ echo "Expect one of [ gnu, intel, cray ] "
+ exit 1
+else
+ if [[ "$1" != cray && "$1" != intel && "$1" != gnu ]] ; then
+ echo "Expect one of [ gnu, intel, cray ] "
+ exit 1
+ fi
+fi
+
+echo "STARTING PE_ENV=$PE_ENV"
+
+# access the module functionality
+. /opt/modules/default/etc/modules.sh
+
+# setup boost
+export BOOST_ROOT=/perm/ma/ma0/boost/boost_1_53_0
+cp $WK/build_scripts/site_config/site-config-cray.jam $BOOST_ROOT/tools/build/v2/site-config.jam
+
+if [[ "$1" = cray ]] ; then
+ if [[ "$PE_ENV" = INTEL ]] ; then
+ module swap PrgEnv-intel PrgEnv-cray
+ fi
+ if [[ "$PE_ENV" = GNU ]] ; then
+ module swap PrgEnv-gnu PrgEnv-cray
+ fi
+
+ module unload cce
+ module load cce/8.3.0.186
+ export COMPILER_VERSION=$(echo $CRAY_CC_VERSION | sed 's/\.//' | cut -c1-2)
+ export WK=/perm/ma/ma0/workspace/$PE_ENV/ecflow
+ export BOOST_ROOT=/perm/ma/ma0/boost/boost_1_55_0
+ cp $WK/build_scripts/site_config/site-config-cray.jam $BOOST_ROOT/tools/build/v2/site-config.jam
+ alias bjam='$BOOST_ROOT/bjam cxxflags=-hPIC toolset=cray'
+
+ # module cray-libsci interferes with ecflow linking, hence disable
+ module unload cray-libsci
+fi
+
+
+if [[ "$1" = intel ]] ; then
+ if [[ "$PE_ENV" = CRAY ]] ; then
+ module swap PrgEnv-cray PrgEnv-intel
+ fi
+ if [[ "$PE_ENV" = GNU ]] ; then
+ module swap PrgEnv-gnu PrgEnv-intel
+ fi
+
+ # for compiler version icc -dumpversion
+ export COMPILER_VERSION=$(icc -dumpversion | sed 's/\.//' | cut -c1-3)
+ export WK=/perm/ma/ma0/workspace/$PE_ENV/ecflow
+ alias bjam='$BOOST_ROOT/bjam cxxflags=-fPIC toolset=intel'
+fi
+
+if [[ "$1" = gnu ]] ; then
+ if [[ "$PE_ENV" = CRAY ]] ; then
+ module swap PrgEnv-cray PrgEnv-gnu
+ fi
+ if [[ "$PE_ENV" = INTEL ]] ; then
+ module swap PrgEnv-intel PrgEnv-gnu
+ fi
+
+ # for compiler version gcc -dumpversion
+ #module load gcc/4.6.3
+
+ export COMPILER_VERSION=$(gcc -dumpversion | sed 's/\.//' | cut -c1-2)
+ export WK=/perm/ma/ma0/workspace/$PE_ENV/ecflow
+ alias bjam='$BOOST_ROOT/bjam cxxflags=-fPIC toolset=gcc'
+fi
+
+
+# =================================================================================================
+# Determine the release,major,minor numbers for this version
+cd $WK
+release=$(cat VERSION.cmake | grep 'set( ECFLOW_RELEASE' | awk '{print $3}'| sed 's/["]//g')
+major=$(cat VERSION.cmake | grep 'set( ECFLOW_MAJOR' | awk '{print $3}'| sed 's/["]//g')
+minor=$(cat VERSION.cmake | grep 'set( ECFLOW_MINOR' | awk '{print $3}'| sed 's/["]//g')
+ECFLOW_VERSION=$release.$major.$minor
+
+export ECFLOW_INSTALL_DIR=/usr/local/apps/ecflow/$release.$major.$minor
+export ECFLOW_PYTHON_INSTALL_DIR=$ECFLOW_INSTALL_DIR/lib/python/2.7/site-packages/ecflow
+
+
+echo "AFTER SWAP PE_ENV=$PE_ENV"
+echo "WK=$WK"
+echo "BOOST_ROOT=$BOOST_ROOT"
+echo "COMPILER_VERSION=$COMPILER_VERSION"
+echo "ECFLOW_INSTALL_DIR=$ECFLOW_INSTALL_DIR"
+echo "ECFLOW_PYTHON_INSTALL_DIR=$ECFLOW_PYTHON_INSTALL_DIR"
+
diff --git a/build_scripts/cray_fix/update_cray_swap.sh b/build_scripts/cray_fix/update_cray_swap.sh
new file mode 100755
index 0000000..c7faa70
--- /dev/null
+++ b/build_scripts/cray_fix/update_cray_swap.sh
@@ -0,0 +1,9 @@
+#!/bin/ksh
+
+# ==================================================================
+# Setup environment on CRAY, allow switch between cray,intel and gnu
+# ==================================================================
+
+scp $WK/build_scripts/cray_fix/swap.sh cca:/home/ma/ma0/.
+
+echo "copied swap.sh to cca:/home/ma/ma0/."
diff --git a/ecflow_4_0_7/build/fix/boost_1_56_0/shared_ptr_helper.hpp b/build_scripts/fix/boost_1_56_0/shared_ptr_helper.hpp
similarity index 100%
rename from ecflow_4_0_7/build/fix/boost_1_56_0/shared_ptr_helper.hpp
rename to build_scripts/fix/boost_1_56_0/shared_ptr_helper.hpp
diff --git a/build_scripts/hpux_fix/README b/build_scripts/hpux_fix/README
new file mode 100644
index 0000000..44e80d3
--- /dev/null
+++ b/build_scripts/hpux_fix/README
@@ -0,0 +1,199 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+Compilation problems with: <boost_root>/boost/detail/utf8_codecvt_facet.ipp ( boost 1.53/1.51)
+was prevously file <boost_root>/libs/detail/utf8_codecvt_facet.cpp ( boost 1.42 --> 1.48)
+==========================================================================
+
+This needs to be fixed to boost versions:
+ 1.42:
+ 1.43:
+ 1.44: (not tested)
+ 1.45:
+ 1.51
+ 1.53
+
+Affects filesystem,program_options,serialisation
+
+Work around is to rewrite "get_cont_octet_out_count_impl"
+ignoring the preprocessor directives (which are window specific anyway)
+(see below). This needs to be done for each release as we dont know
+what else has changed.
+
+>>>>>>>>
+For 1.42 can no longer build boost on HP-UX.
+File-system, program-options and serialisation all show a similar
+problem
+
++ bjam --build-dir=./tmpBuildDir toolset=acc stage link=static --with-filesystem variant=debug
+...patience...
+.......
+acc.compile.c++ tmpBuildDir/boost/bin.v2/libs/filesystem/build/acc/debug/link-static/threading-multi/utf8_codecvt_facet.o
+"./libs/detail/utf8_codecvt_facet.cpp", line 255: error #2014-D: extra text after expected end of preprocessing directive
+ #elif WCHAR_MAX > 0x10000
+
+
+
+File: <boost_root>/boost/detail/utf8_codecvt_facet.ipp ( boost 1.53/1.51)
+was prevously file <boost_root>/libs/detail/utf8_codecvt_facet.cpp ( boost 1.42 --> 1.48)
+
+appears to have been changed in boost 1.40
+for the function get_cont_octet_out_count_impl
+
+FROM:
+// note the following code will generate on some platforms where
+// wchar_t is defined as UCS2. The warnings are superfluous as
+// the specialization is never instantitiated with such compilers.
+template<>
+int get_cont_octet_out_count_impl<4>(wchar_t word){
+ if (word < 0x80) {
+ return 0;
+ }
+ if (word < 0x800) {
+ return 1;
+ }
+ if (word < 0x10000) {
+ return 2;
+ }
+ if (word < 0x200000) {
+ return 3;
+ }
+ if (word < 0x4000000) {
+ return 4;
+ }
+ return 5;
+}
+
+TO:
+
+template<>
+int get_cont_octet_out_count_impl<4>(wchar_t word){
+ if (word < 0x80) {
+ return 0;
+ }
+ if (word < 0x800) {
+ return 1;
+ }
+
+ // Note that the following code will generate warnings on some platforms
+ // where wchar_t is defined as UCS2. The warnings are superfluous as the
+ // specialization is never instantitiated with such compilers, but this
+ // can cause problems if warnings are being treated as errors, so we guard
+ // against that. Including <boost/detail/utf8_codecvt_facet.hpp> as we do
+ // should be enough to get WCHAR_MAX defined.
+#if !defined(WCHAR_MAX)
+# error WCHAR_MAX not defined!
+#endif
+ // cope with VC++ 7.1 or earlier having invalid WCHAR_MAX
+#if defined(_MSC_VER) && _MSC_VER <= 1310 // 7.1 or earlier
+ return 2;
+#elif WCHAR_MAX > 0x10000
+
+ if (word < 0x10000) {
+ return 2;
+ }
+ if (word < 0x200000) {
+ return 3;
+ }
+ if (word < 0x4000000) {
+ return 4;
+ }
+ return 5;
+
+#else
+ return 2;
+#endif
+}
+
+
+
+
+
+acc version 6 compiler problems with /boost/asio/detail/socket_ops.hpp
+==================================================================================================
+**** This is required for all boost version < 1.45
+**** Seem to have been fixed in boost 1.45
+
+1/ The asio /boost/asio/detail/socket_ops.hpp (Line 643)
+ make a reference to ::pselect which is not defined on HPUX 11.23
+
+ In HP_UX 11.11,11.23 select() was defined in <sys/time.h>
+ In HP-UX 11.31 select() was moved to <sys/select.h> and pselect() was introduced in the same file
+
+ Hence boost/socket_ops.hpp needs a way of distinguishing OS versions.
+ for the moment the work around may be to introduce a define like 011.31 | OS_IS_HPUX11_31
+
+ // avi>> added ' && defined(OS_IS_HPUX11_31)'
+ #if defined(__hpux) && defined(__HP_aCC) && defined(OS_IS_HPUX11_31)
+
+ SO THAT WE CHOOSE select and NOT pselect
+
+2/ additionally in 11.23 there are 2 ::select to choose:
+
+ #include <sys/time.h>
+
+ int select(int nfds, fd_set *readfds, fd_set *writefds,
+ fd_set *errorfds, struct timeval *timeout);
+
+ For Backward Compatibility Only: (_XOPEN_SOURCE_EXTENDED not defined)
+
+ #include <time.h>
+
+ int select(size_t nfds, int *readfds, int *writefds,
+ int *exceptds, const struct timeval *timeout);
+
+
+ to get round the problem had to compile as:
+
+ bjam define=_XOPEN_SOURCE_EXTENDED
+
+ to choose the right select
+
+
+ Compilation problems with boost 1.48
+ ==============================================================
+ acc.compile.c++ tmpBuildDir/boost/bin.v2/libs/date_time/build/acc/debug/link-static/threading-multi/gregorian/greg_month.o
+"./boost/numeric/conversion/detail/preprocessed/numeric_cast_traits.hpp", line 25: error #2247: class "boost::numeric::numeric_cast_traits<char, char, void>" has already been defined
+ struct numeric_cast_traits
+ ^
+
+"./boost/numeric/conversion/detail/preprocessed/numeric_cast_traits.hpp", line 158: error #2247: class "boost::numeric::numeric_cast_traits<char, char, void>" has already been defined
+ struct numeric_cast_traits
+ ^
+
+"./boost/numeric/conversion/detail/preprocessed/numeric_cast_traits.hpp", line 170: error #2247: class "boost::numeric::numeric_cast_traits<char, char, void>" has already been defined
+ struct numeric_cast_traits
+ ^
+
+"./boost/numeric/conversion/detail/preprocessed/numeric_cast_traits.hpp", line 182: error #2247: class "boost::numeric::numeric_cast_traits<char, uint8_t, void>" has already been defined
+ struct numeric_cast_traits
+ ^
+
+"./boost/numeric/conversion/detail/preprocessed/numeric_cast_traits.hpp", line 194: error #2247: class "boost::numeric::numeric_cast_traits<char, int16_t, void>" has already been defined
+ struct numeric_cast_traits
+
+
+ >>>
+ >>> See:: https://svn.boost.org/trac/boost/attachment/ticket/6158/cstdint_patch.diff
+ >>>
+ *****
+ ***** Had to apply the same patch: i.e around line 101 of file $BOOST_ROOT/boost/cstdint.hpp
+ *****
+ 103c103,107
+2 < using ::int8_t;
+3 ---
+4 > #if defined(sun) || defined(__sun)
+5 > typedef signed char int8_t;
+6 > #else
+7 > using ::int8_t;
+8 > #endif
+
+ # Hack because boost::int8_t was being interpreted as a char,
+ # This cause duplicate class definition during template instantiation.
+ # in the file ./boost/numeric/conversion/detail/preprocessed/numeric_cast_traits.hpp
+
+
diff --git a/ecflow_4_0_7/build/hpux_fix/boost_1_51_0/future.hpp b/build_scripts/hpux_fix/boost_1_51_0/future.hpp
similarity index 100%
rename from ecflow_4_0_7/build/hpux_fix/boost_1_51_0/future.hpp
rename to build_scripts/hpux_fix/boost_1_51_0/future.hpp
diff --git a/ecflow_4_0_7/build/hpux_fix/boost_1_51_0/overflow_helpers.hpp b/build_scripts/hpux_fix/boost_1_51_0/overflow_helpers.hpp
similarity index 100%
rename from ecflow_4_0_7/build/hpux_fix/boost_1_51_0/overflow_helpers.hpp
rename to build_scripts/hpux_fix/boost_1_51_0/overflow_helpers.hpp
diff --git a/build_scripts/hpux_fix/boost_1_51_0/system_clocks.hpp b/build_scripts/hpux_fix/boost_1_51_0/system_clocks.hpp
new file mode 100644
index 0000000..885296d
--- /dev/null
+++ b/build_scripts/hpux_fix/boost_1_51_0/system_clocks.hpp
@@ -0,0 +1,232 @@
+// boost/chrono/system_clocks.hpp --------------------------------------------------------------//
+
+// Copyright 2008 Howard Hinnant
+// Copyright 2008 Beman Dawes
+// Copyright 2009-2011 Vicente J. Botet Escriba
+
+// Distributed under the Boost Software License, Version 1.0.
+// See http://www.boost.org/LICENSE_1_0.txt
+
+/*
+
+This code was derived by Beman Dawes from Howard Hinnant's time2_demo prototype.
+Many thanks to Howard for making his code available under the Boost license.
+The original code was modified to conform to Boost conventions and to section
+20.9 Time utilities [time] of the C++ committee's working paper N2798.
+See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2798.pdf.
+
+time2_demo contained this comment:
+
+ Much thanks to Andrei Alexandrescu,
+ Walter Brown,
+ Peter Dimov,
+ Jeff Garland,
+ Terry Golubiewski,
+ Daniel Krugler,
+ Anthony Williams.
+*/
+
+/*
+
+ * Fully implement error handling, with test cases.
+ * Consider issues raised by Michael Marcin:
+
+ > In the past I've seen QueryPerformanceCounter give incorrect results,
+ > especially with SpeedStep processors on laptops. This was many years ago and
+ > might have been fixed by service packs and drivers.
+ >
+ > Typically you check the results of QPC against GetTickCount to see if the
+ > results are reasonable.
+ > http://support.microsoft.com/kb/274323
+ >
+ > I've also heard of problems with QueryPerformanceCounter in multi-processor
+ > systems.
+ >
+ > I know some people SetThreadAffinityMask to 1 for the current thread call
+ > their QueryPerformance* functions then restore SetThreadAffinityMask. This
+ > seems horrible to me because it forces your program to jump to another
+ > physical processor if it isn't already on cpu0 but they claim it worked well
+ > in practice because they called the timing functions infrequently.
+ >
+ > In the past I have chosen to use timeGetTime with timeBeginPeriod(1) for
+ > high resolution timers to avoid these issues.
+
+*/
+
+#ifndef BOOST_CHRONO_SYSTEM_CLOCKS_HPP
+#define BOOST_CHRONO_SYSTEM_CLOCKS_HPP
+
+#include <boost/chrono/config.hpp>
+#include <boost/chrono/duration.hpp>
+#include <boost/chrono/time_point.hpp>
+#include <boost/chrono/detail/system.hpp>
+#include <boost/chrono/clock_string.hpp>
+
+#include <ctime>
+
+// avib
+//# if defined( BOOST_CHRONO_POSIX_API )
+//# if ! defined(CLOCK_REALTIME)
+//# error <time.h> does not supply CLOCK_REALTIME
+//# endif
+//# endif
+
+#ifdef BOOST_CHRONO_WINDOWS_API
+// The system_clock tick is 100 nanoseconds
+# define BOOST_SYSTEM_CLOCK_DURATION boost::chrono::duration<boost::int_least64_t, ratio<BOOST_RATIO_INTMAX_C(1), BOOST_RATIO_INTMAX_C(10000000)> >
+#else
+# define BOOST_SYSTEM_CLOCK_DURATION boost::chrono::nanoseconds
+#endif
+
+// this must occur after all of the includes and before any code appears:
+#ifndef BOOST_CHRONO_HEADER_ONLY
+#include <boost/config/abi_prefix.hpp> // must be the last #include
+#endif
+
+
+//----------------------------------------------------------------------------//
+// //
+// 20.9 Time utilities [time] //
+// synopsis //
+// //
+//----------------------------------------------------------------------------//
+
+namespace boost {
+namespace chrono {
+
+ // Clocks
+ class BOOST_CHRONO_DECL system_clock;
+#ifdef BOOST_CHRONO_HAS_CLOCK_STEADY
+ class BOOST_CHRONO_DECL steady_clock;
+#endif
+
+#ifdef BOOST_CHRONO_HAS_CLOCK_STEADY
+ typedef steady_clock high_resolution_clock; // as permitted by [time.clock.hires]
+#else
+ typedef system_clock high_resolution_clock; // as permitted by [time.clock.hires]
+#endif
+
+//----------------------------------------------------------------------------//
+// //
+// 20.9.5 Clocks [time.clock] //
+// //
+//----------------------------------------------------------------------------//
+
+// If you're porting, clocks are the system-specific (non-portable) part.
+// You'll need to know how to get the current time and implement that under now().
+// You'll need to know what units (tick period) and representation makes the most
+// sense for your clock and set those accordingly.
+// If you know how to map this clock to time_t (perhaps your clock is std::time, which
+// makes that trivial), then you can fill out system_clock's to_time_t() and from_time_t().
+
+//----------------------------------------------------------------------------//
+// 20.9.5.1 Class system_clock [time.clock.system] //
+//----------------------------------------------------------------------------//
+
+ class BOOST_CHRONO_DECL system_clock
+ {
+ public:
+ typedef BOOST_SYSTEM_CLOCK_DURATION duration;
+ typedef duration::rep rep;
+ typedef duration::period period;
+ typedef chrono::time_point<system_clock> time_point;
+ BOOST_STATIC_CONSTEXPR bool is_steady = false;
+
+ static BOOST_CHRONO_INLINE time_point now() BOOST_NOEXCEPT;
+#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING
+ static BOOST_CHRONO_INLINE time_point now(system::error_code & ec);
+#endif
+
+ static BOOST_CHRONO_INLINE std::time_t to_time_t(const time_point& t) BOOST_NOEXCEPT;
+ static BOOST_CHRONO_INLINE time_point from_time_t(std::time_t t) BOOST_NOEXCEPT;
+ };
+
+//----------------------------------------------------------------------------//
+// 20.9.5.2 Class steady_clock [time.clock.steady] //
+//----------------------------------------------------------------------------//
+
+// As permitted by [time.clock.steady]
+// The class steady_clock is conditionally supported.
+
+#ifdef BOOST_CHRONO_HAS_CLOCK_STEADY
+ class BOOST_CHRONO_DECL steady_clock
+ {
+ public:
+ typedef nanoseconds duration;
+ typedef duration::rep rep;
+ typedef duration::period period;
+ typedef chrono::time_point<steady_clock> time_point;
+ BOOST_STATIC_CONSTEXPR bool is_steady = true;
+
+ static BOOST_CHRONO_INLINE time_point now() BOOST_NOEXCEPT;
+#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING
+ static BOOST_CHRONO_INLINE time_point now(system::error_code & ec);
+#endif
+ };
+#endif
+//----------------------------------------------------------------------------//
+// 20.9.5.3 Class high_resolution_clock [time.clock.hires] //
+//----------------------------------------------------------------------------//
+
+// As permitted, steady_clock or system_clock is a typedef for high_resolution_clock.
+// See synopsis.
+
+
+ template<class CharT>
+ struct clock_string<system_clock, CharT>
+ {
+ static std::basic_string<CharT> name()
+ {
+ static const CharT u[] =
+ { 's', 'y', 's', 't', 'e', 'm', '_', 'c', 'l', 'o', 'c', 'k' };
+ static const std::basic_string<CharT> str(u, u + sizeof(u)
+ / sizeof(u[0]));
+ return str;
+ }
+ static std::basic_string<CharT> since()
+ {
+ static const CharT
+ u[] =
+ { ' ', 's', 'i', 'n', 'c', 'e', ' ', 'J', 'a', 'n', ' ', '1', ',', ' ', '1', '9', '7', '0' };
+ static const std::basic_string<CharT> str(u, u + sizeof(u)
+ / sizeof(u[0]));
+ return str;
+ }
+ };
+
+#ifdef BOOST_CHRONO_HAS_CLOCK_STEADY
+
+ template<class CharT>
+ struct clock_string<steady_clock, CharT>
+ {
+ static std::basic_string<CharT> name()
+ {
+ static const CharT
+ u[] =
+ { 's', 't', 'e', 'a', 'd', 'y', '_', 'c', 'l', 'o', 'c', 'k' };
+ static const std::basic_string<CharT> str(u, u + sizeof(u)
+ / sizeof(u[0]));
+ return str;
+ }
+ static std::basic_string<CharT> since()
+ {
+ const CharT u[] =
+ { ' ', 's', 'i', 'n', 'c', 'e', ' ', 'b', 'o', 'o', 't' };
+ const std::basic_string<CharT> str(u, u + sizeof(u) / sizeof(u[0]));
+ return str;
+ }
+ };
+
+#endif
+
+} // namespace chrono
+} // namespace boost
+
+#ifndef BOOST_CHRONO_HEADER_ONLY
+// the suffix header occurs after all of our code:
+#include <boost/config/abi_suffix.hpp> // pops abi_prefix.hpp pragmas
+#else
+#include <boost/chrono/detail/inlined/chrono.hpp>
+#endif
+
+#endif // BOOST_CHRONO_SYSTEM_CLOCKS_HPP
diff --git a/ecflow_4_0_7/build/hpux_fix/boost_1_51_0/utf8_codecvt_facet.ipp b/build_scripts/hpux_fix/boost_1_51_0/utf8_codecvt_facet.ipp
similarity index 100%
rename from ecflow_4_0_7/build/hpux_fix/boost_1_51_0/utf8_codecvt_facet.ipp
rename to build_scripts/hpux_fix/boost_1_51_0/utf8_codecvt_facet.ipp
diff --git a/ecflow_4_0_7/build/hpux_fix/boost_1_53_0/README b/build_scripts/hpux_fix/boost_1_53_0/README
similarity index 100%
rename from ecflow_4_0_7/build/hpux_fix/boost_1_53_0/README
rename to build_scripts/hpux_fix/boost_1_53_0/README
diff --git a/ecflow_4_0_7/build/hpux_fix/boost_1_53_0/smart_cast.hpp b/build_scripts/hpux_fix/boost_1_53_0/smart_cast.hpp
similarity index 100%
rename from ecflow_4_0_7/build/hpux_fix/boost_1_53_0/smart_cast.hpp
rename to build_scripts/hpux_fix/boost_1_53_0/smart_cast.hpp
diff --git a/ecflow_4_0_7/build/hpux_fix/boost_1_53_0/utf8_codecvt_facet.ipp b/build_scripts/hpux_fix/boost_1_53_0/utf8_codecvt_facet.ipp
similarity index 100%
rename from ecflow_4_0_7/build/hpux_fix/boost_1_53_0/utf8_codecvt_facet.ipp
rename to build_scripts/hpux_fix/boost_1_53_0/utf8_codecvt_facet.ipp
diff --git a/ecflow_4_0_7/build/hpux_fix/cstdint.hpp b/build_scripts/hpux_fix/cstdint.hpp
similarity index 100%
rename from ecflow_4_0_7/build/hpux_fix/cstdint.hpp
rename to build_scripts/hpux_fix/cstdint.hpp
diff --git a/ecflow_4_0_7/build/hpux_fix/socket_ops.hpp b/build_scripts/hpux_fix/socket_ops.hpp
similarity index 100%
rename from ecflow_4_0_7/build/hpux_fix/socket_ops.hpp
rename to build_scripts/hpux_fix/socket_ops.hpp
diff --git a/ecflow_4_0_7/build/hpux_fix/utf8_codecvt_facet.cpp b/build_scripts/hpux_fix/utf8_codecvt_facet.cpp
similarity index 100%
rename from ecflow_4_0_7/build/hpux_fix/utf8_codecvt_facet.cpp
rename to build_scripts/hpux_fix/utf8_codecvt_facet.cpp
diff --git a/build_scripts/kill_ecf.sh b/build_scripts/kill_ecf.sh
new file mode 100755
index 0000000..9e2d86f
--- /dev/null
+++ b/build_scripts/kill_ecf.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+# kill any existing test based server
+ps -ef | grep ma0 | grep ecfinterval | grep ecflow_server | cut -c9-14 | xargs kill -9
+ps -ef | grep ma0 | grep dis_job_gen | grep ecflow_server | cut -c9-14 | xargs kill -9
+ps -ef | grep ma0 | grep ecbuild | grep debug | grep ecflow_server | cut -c9-14 | xargs kill -9
+ps -ef | grep ma0 | grep gcc | grep ecflow_server | cut -c9-14 | xargs kill -9
+ps -ef | grep ma0 | grep gcc | grep ecflow_client | cut -c9-14 | xargs kill -9
+
+ps -ef | grep ma0 | grep workspace | grep ecbuild | grep debug | cut -c9-14 | xargs kill -9
+ps -ef | grep ma0 | grep workspace | grep ecbuild | grep release | cut -c9-14 | xargs kill -9
+
+# kill any jobs
+ps -ef | grep ma0 | grep job | grep test | cut -c9-14 | xargs kill -9
+
+# kill any running test
+ps -ef | grep ma0 | grep test.sh | cut -c9-14 | xargs kill -9 || true
\ No newline at end of file
diff --git a/build_scripts/massif.sh b/build_scripts/massif.sh
new file mode 100755
index 0000000..5234303
--- /dev/null
+++ b/build_scripts/massif.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+cd $WK
+
+# if argument is release test the release version else stick with debug
+mode=debug
+if test "$1" = release
+then
+ mode=release
+fi
+
+
+compiler=gcc-$(gcc -dumpversion)
+echo "valgrind: variant=$mode compiler=$compiler"
+
+valgrind --tool=massif ACore/bin/$compiler/$mode/u_acore
+valgrind --tool=massif ANattr/bin/$compiler/$mode/u_anattr
+valgrind --tool=massif ANode/bin/$compiler/$mode/u_anode
+valgrind --tool=massif AParser/bin/$compiler/$mode/u_aparser
+valgrind --tool=massif Base/bin/$compiler/$mode/u_base
+valgrind --tool=massif Client/bin/$compiler/$mode/s_client
+valgrind --tool=massif Server/bin/$compiler/$mode/u_server
+valgrind --tool=massif Test/bin/$compiler/$mode/s_test
+valgrind --tool=massif Simulator/bin/$compiler/$mode/c_csim
+#valgrind --tool=massif AParser/bin/$compiler/$mode/perf_aparser
+
diff --git a/build_scripts/migrate.sh b/build_scripts/migrate.sh
new file mode 100644
index 0000000..d655051
--- /dev/null
+++ b/build_scripts/migrate.sh
@@ -0,0 +1,15 @@
+
+
+prepare_migration() {
+ use ecflow
+ while read nick host port
+ do
+ LOG="--host=$host --port=$port"
+ ecflow_client $LOG --ping || continue
+ version=$(ecflow_client $LOG --server_version)
+ echo $nick $host $port $version
+ /usr/local/apps/ecflow/$version/bin/ecflow_client $LOG --migrate > $host.$port.mig
+ done < /usr/local/apps/ecflow/current/lib/servers
+}
+
+prepare_migration
diff --git a/build_scripts/profile.sh b/build_scripts/profile.sh
new file mode 100755
index 0000000..578a2bc
--- /dev/null
+++ b/build_scripts/profile.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+# will run gprof
+
+echo "building profile versions";
+cd $WK
+bjam -j2 -q variant=profile
+
+
+compiler=gcc-$(gcc -dumpversion)
+echo "gprof: variant=profile compiler=$compiler"
+
+#
+cd ACore
+bin/$compiler/profile/u_acore
+gprof bin/$compiler/profile/u_acore gmon.out > gprof.out
+
+cd ../ANattr
+bin/$compiler/profile/u_anattr
+gprof bin/$compiler/profile/u_anattr gmon.out > gprof.out
+
+cd ../ANode
+bin/$compiler/profile/u_anode
+gprof bin/$compiler/profile/u_anode gmon.out > gprof.out
+
+cd ../AParser
+bin/$compiler/profile/u_aparser
+gprof bin/$compiler/profile/u_aparser gmon.out > gprof.out
+
+cd ../Base
+bin/$compiler/profile/u_base
+gprof bin/$compiler/profile/u_base gmon.out > gprof.out
+
+cd ../Client
+bin/$compiler/profile/s_client
+gprof bin/$compiler/profile/s_client gmon.out > gprof.out
+
+cd ../Server
+bin/$compiler/profile/u_server
+gprof bin/$compiler/profile/u_server gmon.out > gprof.out
+
+cd ../Test
+bin/$compiler/profile/test
+gprof bin/$compiler/profile/test gmon.out > gprof.out
+
+cd ../Simulator
+bin/$compiler/profile/c_csim
+gprof bin/$compiler/profile/c_csim gmon.out > gprof.out
+
+cd ../AParser
+bin/$compiler/profile/perf_aparser
+gprof bin/$compiler/profile/perf_aparser gmon.out > gprof.out
diff --git a/build_scripts/rmbin.sh b/build_scripts/rmbin.sh
new file mode 100755
index 0000000..8314d55
--- /dev/null
+++ b/build_scripts/rmbin.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+cd $WK
+
+rm -rf ACore/bin
+rm -rf ANattr/bin
+rm -rf ANode/bin
+rm -rf AParser/bin
+rm -rf Base/bin
+rm -rf CSim/bin
+rm -rf Client/bin
+rm -rf Server/bin
+rm -rf Test/bin
+rm -rf Pyext/bin
+rm -rf view/bin
+
diff --git a/build_scripts/site_config/install.ddoc b/build_scripts/site_config/install.ddoc
new file mode 100644
index 0000000..065504b
--- /dev/null
+++ b/build_scripts/site_config/install.ddoc
@@ -0,0 +1,105 @@
+using python in bjam file
+=========================
+
+ In the site-config.jam file we can specify
+
+ using python ;
+
+This will determine the default python from $PATH.
+If there several python versions, then the python required must be added
+to the $PATH first. The python must include the devel packages.
+As the headers in these packages is used by boost python.
+
+using python
+ : # version
+ : # cmd-or-prefix
+ : # includes
+ : # libraries
+ : # condition
+ ;
+
+By using a specific version, it means that the unit tests, will use the
+same specific version.
+
+However we did not want to hard code the version of python.
+As that would restrict install for the general case.
+Is is assumed that the Autoconf tools will determine the correct
+python version. We current only support python 2.5->2.7
+
+
+Linux 32
+===========
+# Buy using a specific version we don't need to update $PATH,
+# when python tests invoked from scripts
+
+# Note sure how to access python version, hence defined a project wide constant variable
+# This is used during installation
+python_version = [ os.environ PYTHON_VERSION ] ;
+python_version default = 2.7 ; # if PYTHON_VERSION not set, use this default
+constant PYTHON_VERSION : $(python_version) ;
+
+using python
+ : $(python_version) # version
+ : /usr/local/apps/python/2.7.2-01/bin/python # cmd-or-prefix
+ : # includes
+ : # libraries
+ : # condition
+ ;
+
+
+AIX Power6
+===========
+using python
+ : 2.5 # version
+ : /usr/local/python64/bin/python # cmd-or-prefix
+ : /usr/local/include/python2.5 /usr/local/python64/include/python2.5/ # includes
+ : # libraries
+ : # condition
+ ;
+
+Now update to python 2.7
+using python : 2.7 ;
+
+
+HPUX - itanium
+==============
+
+using python
+ : # version
+ : /usr/local/apps/python/2.7/bin/python # cmd-or-prefix (for python 2.5 use )/opt/python/usr/local/bin/python
+ : # includes
+ : # libraries
+ : # condition
+ ;
+
+#using python
+# : # version
+# : /opt/python/usr/local/bin/python # cmd-or-prefix
+# : # includes
+# : # libraries
+# : # condition
+# ;
+
+=================================================================================
+
+Install structure
+-----------------
+$ECFLOW_DESTDIR/$ECFLOW_INSTALL_DIR/bin/ecflow_client
+ ecflow_server
+ ecflowview (<dll_path>=$ECFLOW_INSTALL_DIR/lib/libxpmcc.so)
+ ecflow_start.sh
+ ecflow_stop.sh
+ noconnect.sh
+
+$ECFLOW_DESTDIR/$ECFLOW_INSTALL_DIR/doc/ecflow/user_manual.docx
+ user_manual.pdf
+ client_options.docx
+
+$ECFLOW_INSTALL_DIR/lib/libxpmcc.so
+
+$ECFLOW_DESTDIR/$ECFLOW_PYTHON_INSTALL_DIR/__init__.py
+ libboost_python.so
+ ecflow.so <dll-path>=$ECFLOW_PYTHON_INSTALL_DIR/lib/libboost_python.so)
+
+
+
diff --git a/build_scripts/site_config/issues.ddoc b/build_scripts/site_config/issues.ddoc
new file mode 100644
index 0000000..ef5e59d
--- /dev/null
+++ b/build_scripts/site_config/issues.ddoc
@@ -0,0 +1,35 @@
+AIX
+===========================================================================================
+
+# ECF/Boost serialisation has problems in release mode: This was an attempt to make it work:
+# Note: when building boost on AIX, comment out.
+# override compiler release flags, see usage below: Just using <variant>release:<cxxflags>-O2
+# may not be enough, since -O3 is still added., and hence probably still overrides the -O2
+# hence use this alternative approach.
+#
+import feature ;
+feature.extend optimization : unspecified ;
+
+project site-config
+ : requirements <include>$(BOOST_ROOT)
+ : requirements <threading>multi
+ : requirements <define>AIX
+ : requirements <cxxflags>-qsuppress=1540-0198 # (W) The omitted keyword "private" is assumed for base class
+ : requirements <cxxflags>-qsuppress=1540-2883 # (W) Inline function "<function>" given attribute noinline.
+ : requirements <variant>release:<cxxflags>-qsuppress=1500-029 # supress could not be inlined message
+ : requirements <variant>release:<cxxflags>-O2 # serialization has problems with -O3
+ : requirements <variant>release:<optimization>unspecified <variant>release:<cflags>-O2 # serialization has problems with -O3
+ : requirements <linkflags>-bbigtoc
+ ;
+
+
+# -bbigtoc:
+# we get TOC overflow, because compiler/linker has 64k limit on
+# the number of global symbols. Options are use:
+# 0/ Break up shared lib
+# 1/ -bbigtoc to overcome at the cost of performance degradation
+# 2/ --qipa=level=0 if this fails try
+# 3/ --qipa=level=1 if this fails try
+# 4/ --qipa=level=2 if this fails, revert to -bbigtoc
+# Currently option 2-4 didn't work!
+
\ No newline at end of file
diff --git a/build_scripts/site_config/site-config-AIX.jam b/build_scripts/site_config/site-config-AIX.jam
new file mode 100644
index 0000000..fa0aae5
--- /dev/null
+++ b/build_scripts/site_config/site-config-AIX.jam
@@ -0,0 +1,100 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+#
+# site-config.jam for AIX v11.1 compiler
+# This file should be place in $HOME or $BOOST_ROOT/tools/build/v2/
+#-----------------------------------------------------------------
+
+import os ;
+local BOOST_ROOT = [ os.environ BOOST_ROOT ] ;
+
+# ========================= referenced libs =========================================
+
+# Boost libraries referenced in client/server programs.
+# Assumes --layout=tagged
+#
+lib boost_serialization : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt-d.a ;
+lib boost_system : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt-d.a ;
+lib boost_thread : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt-d.a ;
+lib boost_test : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt-d.a ;
+lib boost_test_monitor : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt-d.a ;
+lib boost_program_options : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt-d.a ;
+lib boost_filesystem : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt-d.a ;
+lib boost_datetime : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt-d.a ;
+lib boost_python : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-d.so ;
+lib boost_python_static : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-d.a ;
+
+# profile uses release libs
+lib boost_serialization : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt.a ;
+lib boost_system : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt.a ;
+lib boost_thread : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt.a ;
+lib boost_test : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt.a ;
+lib boost_test_monitor : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt.a ;
+lib boost_program_options : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt.a ;
+lib boost_filesystem : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt.a ;
+lib boost_datetime : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt.a ;
+lib boost_python : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.so ;
+lib boost_python_static : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.a ;
+
+lib boost_serialization : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt.a ;
+lib boost_system : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt.a ;
+lib boost_thread : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt.a ;
+lib boost_test : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt.a ;
+lib boost_test_monitor : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt.a ;
+lib boost_program_options : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt.a ;
+lib boost_filesystem : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt.a ;
+lib boost_datetime : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt.a ;
+lib boost_python : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.so ;
+lib boost_python_static : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.a ;
+
+
+#======================= project site-config ================================
+
+# -bbigtoc:
+# we get TOC overflow, because compiler/linker has 64k limit on
+# the number of global symbols. Options are use:
+# 0/ Break up shared lib
+# 1/ -bbigtoc to overcome at the cost of performance degradation
+# 2/ --qipa=level=0 if this fails try
+# 3/ --qipa=level=1 if this fails try
+# 4/ --qipa=level=2 if this fails, revert to -bbigtoc
+# Currently option 2-4 didn't work!
+
+# <threading>multi
+# Note: in order to use xlC_r compiler, you have to use either
+# "bjam threading=multi" OR
+# add
+# requirements <threading>multi
+# as below.
+#
+
+# <cxxflags>-qsuppress=1500-029
+# In release mode we get hundreds of 1500-029 warning message, ie failure to inline
+# hence decided to supress this.
+#
+# Suppress 1540-2883 (W) Inline function "<funtion>" given attribute noinline.
+# This was the fix for release mode of the compiler & fixed the serialisation crash
+# Unfortunately it generates hundreds of warnings for each type seralized in each header file
+# "/s1a/emos_esuite/emos_data/sms/boost/boost_1_45_0/boost/serialization/singleton.hpp", line 126.17: 1540-2883 (W) Inline function "void use(const void_caster_primitive<Alias,Submittable> &)" given attribute noinline.
+# "/s1a/emos_esuite/emos_data/sms/boost/boost_1_45_0/boost/serialization/singleton.hpp", line 126.17: 1540-2883 (W) Inline function "void use(const iserializer<boost::archive::text_iarchive,PartExpression> &)" given attribute noinline.
+
+project site-config
+ : requirements <include>$(BOOST_ROOT)
+ : requirements <threading>multi
+ : requirements <cxxflags>-qsuppress=1540-0198 # (W) The omitted keyword "private" is assumed for base class
+ : requirements <cxxflags>-qsuppress=1540-2883 # (W) Inline function "<function>" given attribute noinline.
+ : requirements <variant>release:<cxxflags>-qsuppress=1500-029 # supress could not be inlined message
+ : requirements <linkflags>-bbigtoc
+ ;
+
+# using syntax:
+# using toolset-name : version :invocation-command : options ;
+# where options allows <cflags, cxxflags, compileflags and linkflags >
+#
+using vacpp ;
+using testing ;
diff --git a/build_scripts/site_config/site-config-HPUX.jam b/build_scripts/site_config/site-config-HPUX.jam
new file mode 100644
index 0000000..b8e7b6f
--- /dev/null
+++ b/build_scripts/site_config/site-config-HPUX.jam
@@ -0,0 +1,111 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+#
+# This file should be changed depending on the new system
+# no other files should need changing
+# This file should be place in $HOME or $BOOST_ROOT/tools/build/v2/
+#-----------------------------------------------------------------
+
+import os ;
+local BOOST_ROOT = [ os.environ BOOST_ROOT ] ;
+
+#
+# Boost libraries referenced in client/server programs
+#
+lib boost_serialization : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt-d.a ;
+lib boost_system : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt-d.a ;
+lib boost_thread : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt-d.a ;
+lib boost_test : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt-d.a ;
+lib boost_test_monitor : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt-d.a ;
+lib boost_program_options : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt-d.a ;
+lib boost_filesystem : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt-d.a ;
+lib boost_datetime : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt-d.a ;
+lib boost_python : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-d.so ;
+lib boost_python_static : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-d.a ;
+
+lib boost_serialization : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt.a ;
+lib boost_system : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt.a ;
+lib boost_thread : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt.a ;
+lib boost_test : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt.a ;
+lib boost_test_monitor : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt.a ;
+lib boost_program_options : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt.a ;
+lib boost_filesystem : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt.a ;
+lib boost_datetime : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt.a ;
+lib boost_python : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.so ;
+lib boost_python_static : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.a ;
+
+# Lib for run time checks, use for debug builds only
+lib rtc : : <variant>debug <file>/opt/langtools/lib/hpux32/librtc.so ;
+
+
+# project wide settings. Please disable requirements <variant>debug:<linkflags>+check=all
+# for release build.
+# Note: _XOPEN_SOURCE_EXTENDED is only needed for Client/Server categories
+# assuming its no harm to define everywhere
+#
+# Boost CHRONO does not work properly with HPUX compiler( boost version 1.51 )
+# hence use of BOOST_THREAD_DONT_USE_CHRONO, See http://www.boost.org/doc/libs/1_51_0/doc/html/thread/build.html
+# Even with this boost thread/chrono does not compile. Kept in case fixed in the future
+#
+project site-config
+ : requirements <include>$(BOOST_ROOT)
+ : requirements <threading>multi
+ : requirements <define>HPUX
+ : requirements <define>_XOPEN_SOURCE_EXTENDED
+ : requirements <define>BOOST_THREAD_DONT_USE_CHRONO
+# : requirements <library>rtc
+# : requirements <variant>debug:<linkflags>+check=all
+ ;
+
+
+# STATIC: Additional Lint type checks.Will drastically slow down compiles, hence optional
+#
+# use <compileflags>+w for additional lint style checking
+# Suppress the most prevalent boost warnings, this allows us to see lint
+# checks in our own code
+#
+# suppress - warning #2261-D: controlling expression is constant
+# - warning #2236-D: controlling expression is constant
+# - remark #4296-D: arithmetic operation on boolean type
+# - remark #2401-D: destructor for base class is not virtual
+# - remark #2340-D: value copied to temporary, reference to temporary use
+# - remark #4255-D: padding size of struct "d1" with 3 bytes to alignment boundary>]" at line 62
+# - remark #4227-D: padding struct with 3 bytes to align member "old_mask_"
+# - remark #2193-D: zero used for undefined preprocessing identifier "__GNUC__"
+# - remark #2324-D: duplicate friend declaration
+# - remark #4285-D: operator= does not have a check for the source and destination addresses being non-identical
+#
+# RUNTIME: Will drastically slow run runs, but will give very useful information, hence optional
+#
+# enable +check=all, to enable all runtime checks:
+# +check=bounds
+# +check=malloc
+# +check=stack:variables
+# +check=uninit -z
+#using acc : : : <compileflags>+w
+# <compileflags>+W2236,2461,2261,2236,4296,2401,2340,4255,4227,2193,2324,4285
+# <compileflags>+check=all
+# ;
+
+
+#
+# suppress - warning #2236-D: controlling expression is constant
+# warning #2461-D: initial value of reference to non-const must be an lvalue
+# warning #2191-D: type qualifier is meaningless on cast type
+# warning #2815-D: type qualifier on return type is meaningless
+# warning #4232-D: conversion from "boost::python::converter::rvalue_from_python_stage1_data *" to a more strictly aligned type "boost::python::converter::rvalue_from_python_storage<boost::shared_ptr<CtsApi>> *" may cause misaligned access
+# warning #4189-D: warning #4189-D: a non-POD class type used in offsetof macro BOOST_STATIC_ASSERT(BOOST_PYTHON_OFFSETOF(rvalue_from_python_storage<T>,stage1) == 0);
+#
+# using syntax:
+# using toolset-name : version : invocation-command : options ;
+# where options allows <cflags, cxxflags, compileflags and linkflags >
+#
+using acc : : : <compileflags>+W2236,2461,2191,2815,4232,4189
+ ;
+
+using testing ;
diff --git a/build_scripts/site_config/site-config-Linux.jam b/build_scripts/site_config/site-config-Linux.jam
new file mode 100644
index 0000000..52231f4
--- /dev/null
+++ b/build_scripts/site_config/site-config-Linux.jam
@@ -0,0 +1,83 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+# ===================================================================
+# site-config.jam file for Linux/gcc
+# This file should be placed in $HOME or $BOOST_ROOT/tools/build/v2/
+# ===================================================================
+
+#
+# Pull in environment variables
+#
+import os ;
+local BOOST_ROOT = [ os.environ BOOST_ROOT ] ;
+
+#
+# --layout=system -> libboost_system.a (default)
+# --layout=tagged -> libboost_system-mt-d.a(debug) libboost_system-mt.a(release)
+# --layout=versioned -> libboost_system-xlc-mt-d-1.42(debug) libboost_system-xlc-mt-1_42.a(release)
+#
+# Boost libraries referenced in client/server programs
+# assumes --layout=tagged for the debug release and profile variant
+#
+lib boost_serialization : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt-d.a ;
+lib boost_system : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt-d.a ;
+lib boost_thread : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt-d.a ;
+lib boost_test : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt-d.a ;
+lib boost_test_monitor : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt-d.a ;
+lib boost_program_options : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt-d.a ;
+lib boost_filesystem : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt-d.a ;
+lib boost_datetime : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt-d.a ;
+lib boost_python : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-d.so ;
+lib boost_python_static : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-d.a ;
+
+# profile uses release libs
+lib boost_serialization : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt.a ;
+lib boost_system : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt.a ;
+lib boost_thread : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt.a ;
+lib boost_test : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt.a ;
+lib boost_test_monitor : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt.a ;
+lib boost_program_options : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt.a ;
+lib boost_filesystem : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt.a ;
+lib boost_datetime : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt.a ;
+lib boost_python : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.so ;
+lib boost_python_static : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.a ;
+
+lib boost_serialization : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt.a ;
+lib boost_system : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt.a ;
+lib boost_thread : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt.a ;
+lib boost_test : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt.a ;
+lib boost_test_monitor : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt.a ;
+lib boost_program_options : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt.a ;
+lib boost_filesystem : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt.a ;
+lib boost_datetime : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt.a ;
+lib boost_python : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.so ;
+lib boost_python_static : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.a ;
+
+#
+# Notice: we don't add requirements <library>pthread , because
+# a/ Not all tests require it
+# b/ Can cause links errors
+# Hence left to individual projects/test
+project site-config
+ : requirements <include>$(BOOST_ROOT)
+ ;
+
+# using syntax:
+# using toolset-name : version : invocation-command : options ;
+# where options allows <cflags, cxxflags, compileflags and linkflags >
+#
+using gcc ;
+using testing ;
+
+# ==================== ECFLOWVIEW =======================================================
+
+local motif_library = [ os.environ MOTIF_LIBRARY ] ;
+motif_library default = "/usr/lib64" ;
+constant MOTIF_LIBRARY : $(motif_library) ;
+
+MOTIF_LIBRARY default = /usr/lib ;
diff --git a/build_scripts/site_config/site-config-Linux64-clang.jam b/build_scripts/site_config/site-config-Linux64-clang.jam
new file mode 100644
index 0000000..0b2cea5
--- /dev/null
+++ b/build_scripts/site_config/site-config-Linux64-clang.jam
@@ -0,0 +1,84 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+# ===================================================================
+# This file should be placed in $HOME or $BOOST_ROOT/tools/build/v2/
+# ===================================================================
+
+#
+# Pull in environment variables
+#
+import os ;
+local BOOST_ROOT = [ os.environ BOOST_ROOT ] ;
+
+#
+# --layout=system -> libboost_system.a (default)
+# --layout=tagged -> libboost_system-mt-d.a(debug) libboost_system-mt.a(release)
+# --layout=versioned -> libboost_system-xlc-mt-d-1.42(debug) libboost_system-xlc-mt-1_42.a(release)
+#
+# Boost libraries referenced in client/server programs
+# assumes --layout=tagged for the debug release and profile variant
+#
+lib boost_serialization : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt-d.a ;
+lib boost_system : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt-d.a ;
+lib boost_thread : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt-d.a ;
+lib boost_test : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt-d.a ;
+lib boost_test_monitor : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt-d.a ;
+lib boost_program_options : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt-d.a ;
+lib boost_filesystem : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt-d.a ;
+lib boost_datetime : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt-d.a ;
+lib boost_python : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-d.so ;
+lib boost_python_static : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-d.a ;
+
+# profile uses release libs
+lib boost_serialization : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt.a ;
+lib boost_system : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt.a ;
+lib boost_thread : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt.a ;
+lib boost_test : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt.a ;
+lib boost_test_monitor : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt.a ;
+lib boost_program_options : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt.a ;
+lib boost_filesystem : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt.a ;
+lib boost_datetime : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt.a ;
+lib boost_python : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.so ;
+lib boost_python_static : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.a ;
+
+lib boost_serialization : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt.a ;
+lib boost_system : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt.a ;
+lib boost_thread : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt.a ;
+lib boost_test : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt.a ;
+lib boost_test_monitor : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt.a ;
+lib boost_program_options : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt.a ;
+lib boost_filesystem : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt.a ;
+lib boost_datetime : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt.a ;
+lib boost_python : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.so ;
+lib boost_python_static : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.a ;
+
+#
+# Notice: we don't add requirements <library>pthread , because
+# a/ Not all tests require it
+# b/ Can cause links errors
+# Hence left to individual projects/test
+#
+project site-config
+ : requirements <include>$(BOOST_ROOT)
+ ;
+
+# using syntax:
+# using toolset-name : version :invocation-command : options ;
+# where options allows <cflags, cxxflags, compileflags and linkflags >
+#
+# On linux 64, because most of the static library's, are placed in a shared libs(ecflow.so)
+# hence we need to compile with -fPIC
+using clang : : : <cxxflags>-fPIC ;
+
+using testing ;
+
+# ==================== ECFLOWVIEW/install =======================================================
+
+local motif_library = [ os.environ MOTIF_LIBRARY ] ;
+motif_library default = "/usr/lib64" ;
+constant MOTIF_LIBRARY : $(motif_library) ;
diff --git a/build_scripts/site_config/site-config-Linux64-intel.jam b/build_scripts/site_config/site-config-Linux64-intel.jam
new file mode 100644
index 0000000..5ef00f9
--- /dev/null
+++ b/build_scripts/site_config/site-config-Linux64-intel.jam
@@ -0,0 +1,91 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+# ===================================================================
+# This file should be placed in $HOME or $BOOST_ROOT/tools/build/v2/
+# ===================================================================
+
+#
+# Pull in environment variables
+#
+import os ;
+local BOOST_ROOT = [ os.environ BOOST_ROOT ] ;
+
+#
+# --layout=system -> libboost_system.a (default)
+# --layout=tagged -> libboost_system-mt-d.a(debug) libboost_system-mt.a(release)
+# --layout=versioned -> libboost_system-xlc-mt-d-1.42(debug) libboost_system-xlc-mt-1_42.a(release)
+#
+# Boost libraries referenced in client/server programs
+# assumes --layout=tagged for the debug release and profile variant
+#
+lib boost_serialization : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt-d.a ;
+lib boost_system : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt-d.a ;
+lib boost_thread : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt-d.a ;
+lib boost_test : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt-d.a ;
+lib boost_test_monitor : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt-d.a ;
+lib boost_program_options : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt-d.a ;
+lib boost_filesystem : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt-d.a ;
+lib boost_datetime : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt-d.a ;
+lib boost_python : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-d.so ;
+lib boost_python_static : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-d.a ;
+
+# profile uses release libs
+lib boost_serialization : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt.a ;
+lib boost_system : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt.a ;
+lib boost_thread : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt.a ;
+lib boost_test : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt.a ;
+lib boost_test_monitor : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt.a ;
+lib boost_program_options : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt.a ;
+lib boost_filesystem : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt.a ;
+lib boost_datetime : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt.a ;
+lib boost_python : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.so ;
+lib boost_python_static : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.a ;
+
+lib boost_serialization : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt.a ;
+lib boost_system : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt.a ;
+lib boost_thread : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt.a ;
+lib boost_test : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt.a ;
+lib boost_test_monitor : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt.a ;
+lib boost_program_options : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt.a ;
+lib boost_filesystem : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt.a ;
+lib boost_datetime : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt.a ;
+lib boost_python : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.so ;
+lib boost_python_static : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.a ;
+
+#
+# Notice: we don't add requirements <library>pthread , because
+# a/ Not all tests require it
+# b/ Can cause links errors
+# Hence left to individual projects/test
+#
+project site-config
+ : requirements <include>$(BOOST_ROOT)
+ ;
+
+# On linux 64, because most of the static library's, are placed in a shared libs(ecflow.so)
+# hence we need to compile with -fPIC
+#
+# using syntax:
+# using toolset-name : version : invocation-command : options ;
+# where options allows <cflags, cxxflags, compileflags and linkflags >
+#
+# Suppress the following warnings:
+# warning #1875: offsetof applied to non-POD (Plain Old Data) types is nonstandard
+# This warning is mostly from boost python headers
+# warning #1881: argument must be a constant null pointer value
+# This warning is in the vewier, with X-windows
+#
+using intel-linux : : : <cxxflags>-fPIC <compileflags>-wd1875,1881 ;
+
+using testing ;
+
+# ==================== ECFLOWVIEW/install =======================================================
+
+local motif_library = [ os.environ MOTIF_LIBRARY ] ;
+motif_library default = "/usr/lib64" ;
+constant MOTIF_LIBRARY : $(motif_library) ;
diff --git a/build_scripts/site_config/site-config-Linux64.jam b/build_scripts/site_config/site-config-Linux64.jam
new file mode 100644
index 0000000..8ae2710
--- /dev/null
+++ b/build_scripts/site_config/site-config-Linux64.jam
@@ -0,0 +1,94 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+# ===================================================================
+# site-config.jam file for Linux/gcc
+# This file should be placed in $HOME or $BOOST_ROOT/tools/build/v2/
+# ===================================================================
+
+#
+# Pull in environment variables
+#
+import os ;
+local BOOST_ROOT = [ os.environ BOOST_ROOT ] ;
+
+#
+# --layout=system -> libboost_system.a (default)
+# --layout=tagged -> libboost_system-mt-d.a(debug) libboost_system-mt.a(release)
+# --layout=versioned -> libboost_system-xlc-mt-d-1.42(debug) libboost_system-xlc-mt-1_42.a(release)
+#
+# Boost libraries referenced in client/server programs
+# assumes --layout=tagged for the debug release and profile variant
+#
+lib boost_serialization : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt-d.a ;
+lib boost_system : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt-d.a ;
+lib boost_thread : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt-d.a ;
+lib boost_test : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt-d.a ;
+lib boost_test_monitor : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt-d.a ;
+lib boost_program_options : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt-d.a ;
+lib boost_filesystem : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt-d.a ;
+lib boost_datetime : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt-d.a ;
+lib boost_python : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-d.so ;
+lib boost_python_static : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-d.a ;
+
+# profile uses release libs
+lib boost_serialization : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt.a ;
+lib boost_system : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt.a ;
+lib boost_thread : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt.a ;
+lib boost_test : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt.a ;
+lib boost_test_monitor : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt.a ;
+lib boost_program_options : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt.a ;
+lib boost_filesystem : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt.a ;
+lib boost_datetime : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt.a ;
+lib boost_python : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.so ;
+lib boost_python_static : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.a ;
+
+lib boost_serialization : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt.a ;
+lib boost_system : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt.a ;
+lib boost_thread : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt.a ;
+lib boost_test : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt.a ;
+lib boost_test_monitor : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt.a ;
+lib boost_program_options : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt.a ;
+lib boost_filesystem : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt.a ;
+lib boost_datetime : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt.a ;
+lib boost_python : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.so ;
+lib boost_python_static : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.a ;
+
+#
+# Notice: we don't add requirements <library>pthread , because
+# a/ Not all tests require it
+# b/ Can cause links errors
+# Hence left to individual projects/test
+#
+# Boost 1.53 with > gcc 4.8, to many warnings: suppress with: <toolset>gcc:<cxxflags>-Wno-unused-local-typedefs
+# However Wno-unused-local-typedefs does not work with gcc 4.3, i.e rpm fails, hence keep for local use
+#
+project site-config
+ : requirements <include>$(BOOST_ROOT)
+ #<toolset>gcc:<cxxflags>-Wno-unused-local-typedefs
+ ;
+
+# using syntax:
+# using toolset-name : version :invocation-command : options ;
+# where options allows <cflags, cxxflags, compileflags and linkflags >
+#
+# On linux 64, because most of the static library's, are placed in a shared libs(ecflow.so)
+# hence we need to compile with -fPIC
+using gcc : : : <cxxflags>-fPIC ;
+
+#
+# $BOOST_ROOT/bjam --toolset=gcc cflags="-std=gnu++11" c++-template-depth=512
+# using gcc : 4.7.2 : : <cxxflags>-fPIC <cxxflags>-std=gnu++11 <cxxflags>-ftemplate-depth=512 ;
+
+using testing ;
+
+# ==================== ECFLOWVIEW/install =======================================================
+
+local motif_library = [ os.environ MOTIF_LIBRARY ] ;
+motif_library default = "/usr/lib64" ;
+constant MOTIF_LIBRARY : $(motif_library) ;
+
diff --git a/build_scripts/site_config/site-config-cray.jam b/build_scripts/site_config/site-config-cray.jam
new file mode 100644
index 0000000..b1889d3
--- /dev/null
+++ b/build_scripts/site_config/site-config-cray.jam
@@ -0,0 +1,197 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+# ===================================================================
+# site-config.jam file for Linux/cray
+# This file should be placed in $HOME or $BOOST_ROOT/tools/build/v2/
+# ===================================================================
+
+#
+# Pull in environment variables
+#
+import os ;
+local BOOST_ROOT = [ os.environ BOOST_ROOT ] ;
+local MACHINE_NAME = [ os.environ MACHINE_NAME ] ;
+
+#
+# --layout=system -> libboost_system.a (default)
+# --layout=tagged -> libboost_system-mt-d.a(debug) libboost_system-mt.a(release)
+# --layout=versioned -> libboost_system-xlc-mt-d-1.42(debug) libboost_system-xlc-mt-1_42.a(release)
+#
+# Boost libraries referenced in client/server programs
+# assumes --layout=tagged for the debug release and profile variant
+#
+
+GCC_TAG = gcc46 ;
+VERSION_TAG = 1_53 ;
+switch $(BOOST_ROOT) {
+ case *boost_1_55_0 : VERSION_TAG = 1_55 ;
+ case *boost_1_56_0 : VERSION_TAG = 1_56 ;
+ case *boost_1_57_0 : VERSION_TAG = 1_57 ;
+}
+
+switch $(MACHINE_NAME) {
+ case cca : GCC_TAG = gcc48 ;
+ case ccb : GCC_TAG = gcc48 ;
+}
+
+
+lib boost_serialization : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-$(GCC_TAG)-mt-d-$(VERSION_TAG).a ;
+lib boost_system : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_system-$(GCC_TAG)-mt-d-$(VERSION_TAG).a ;
+lib boost_thread : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_thread-$(GCC_TAG)-mt-d-$(VERSION_TAG).a ;
+lib boost_test : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-$(GCC_TAG)-mt-d-$(VERSION_TAG).a ;
+lib boost_test_monitor : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-$(GCC_TAG)-mt-d-$(VERSION_TAG).a ;
+lib boost_program_options : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-$(GCC_TAG)-mt-d-$(VERSION_TAG).a ;
+lib boost_filesystem : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-$(GCC_TAG)-mt-d-$(VERSION_TAG).a ;
+lib boost_datetime : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-$(GCC_TAG)-mt-d-$(VERSION_TAG).a ;
+lib boost_python : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-$(GCC_TAG)-mt-d-$(VERSION_TAG).so ;
+lib boost_python_static : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-$(GCC_TAG)-mt-d-$(VERSION_TAG).a ;
+
+# profile uses release libs
+lib boost_serialization : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
+lib boost_system : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_system-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
+lib boost_thread : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_thread-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
+lib boost_test : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
+lib boost_test_monitor : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
+lib boost_program_options : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
+lib boost_filesystem : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
+lib boost_datetime : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
+lib boost_python : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-$(GCC_TAG)-mt-$(VERSION_TAG).so ;
+lib boost_python_static : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
+
+lib boost_serialization : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
+lib boost_system : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_system-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
+lib boost_thread : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_thread-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
+lib boost_test : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
+lib boost_test_monitor : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
+lib boost_program_options : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
+lib boost_filesystem : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
+lib boost_datetime : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
+lib boost_python : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-$(GCC_TAG)-mt-$(VERSION_TAG).so ;
+lib boost_python_static : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
+
+# INTEL ================================================================================================
+
+lib boost_serialization : : <toolset>intel <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-il-mt-d-$(VERSION_TAG).a ;
+lib boost_system : : <toolset>intel <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_system-il-mt-d-$(VERSION_TAG).a ;
+lib boost_thread : : <toolset>intel <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_thread-il-mt-d-$(VERSION_TAG).a ;
+lib boost_test : : <toolset>intel <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-il-mt-d-$(VERSION_TAG).a ;
+lib boost_test_monitor : : <toolset>intel <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-il-mt-d-$(VERSION_TAG).a ;
+lib boost_program_options : : <toolset>intel <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-il-mt-d-$(VERSION_TAG).a ;
+lib boost_filesystem : : <toolset>intel <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-il-mt-d-$(VERSION_TAG).a ;
+lib boost_datetime : : <toolset>intel <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-il-mt-d-$(VERSION_TAG).a ;
+lib boost_python : : <toolset>intel <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-il-mt-d-$(VERSION_TAG).so ;
+lib boost_python_static : : <toolset>intel <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-il-mt-d-$(VERSION_TAG).a ;
+
+lib boost_serialization : : <toolset>intel <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-il-mt-$(VERSION_TAG).a ;
+lib boost_system : : <toolset>intel <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_system-il-mt-$(VERSION_TAG).a ;
+lib boost_thread : : <toolset>intel <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_thread-il-mt-$(VERSION_TAG).a ;
+lib boost_test : : <toolset>intel <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-il-mt-$(VERSION_TAG).a ;
+lib boost_test_monitor : : <toolset>intel <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-il-mt-$(VERSION_TAG).a ;
+lib boost_program_options : : <toolset>intel <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-il-mt-$(VERSION_TAG).a ;
+lib boost_filesystem : : <toolset>intel <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-il-mt-$(VERSION_TAG).a ;
+lib boost_datetime : : <toolset>intel <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-il-mt-$(VERSION_TAG).a ;
+lib boost_python : : <toolset>intel <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-il-mt-$(VERSION_TAG).so ;
+lib boost_python_static : : <toolset>intel <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-il-mt-$(VERSION_TAG).a ;
+
+lib boost_serialization : : <toolset>intel <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-il-mt-$(VERSION_TAG).a ;
+lib boost_system : : <toolset>intel <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_system-il-mt-$(VERSION_TAG).a ;
+lib boost_thread : : <toolset>intel <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_thread-il-mt-$(VERSION_TAG).a ;
+lib boost_test : : <toolset>intel <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-il-mt-$(VERSION_TAG).a ;
+lib boost_test_monitor : : <toolset>intel <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-il-mt-$(VERSION_TAG).a ;
+lib boost_program_options : : <toolset>intel <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-il-mt-$(VERSION_TAG).a ;
+lib boost_filesystem : : <toolset>intel <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-il-mt-$(VERSION_TAG).a ;
+lib boost_datetime : : <toolset>intel <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-il-mt-$(VERSION_TAG).a ;
+lib boost_python : : <toolset>intel <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-il-mt-$(VERSION_TAG).so ;
+lib boost_python_static : : <toolset>intel <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-il-mt-$(VERSION_TAG).a ;
+
+# CRAY ================================================================================================
+lib boost_serialization : : <toolset>cray <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt-d-$(VERSION_TAG).a ;
+lib boost_system : : <toolset>cray <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt-d-$(VERSION_TAG).a ;
+lib boost_thread : : <toolset>cray <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt-d-$(VERSION_TAG).a ;
+lib boost_test : : <toolset>cray <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt-d-$(VERSION_TAG).a ;
+lib boost_test_monitor : : <toolset>cray <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt-d-$(VERSION_TAG).a ;
+lib boost_program_options : : <toolset>cray <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt-d-$(VERSION_TAG).a ;
+lib boost_filesystem : : <toolset>cray <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt-d-$(VERSION_TAG).a ;
+lib boost_datetime : : <toolset>cray <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt-d-$(VERSION_TAG).a ;
+lib boost_python : : <toolset>cray <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-d-$(VERSION_TAG).so ;
+lib boost_python_static : : <toolset>cray <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-d-$(VERSION_TAG).a ;
+
+lib boost_serialization : : <toolset>cray <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt-$(VERSION_TAG).a ;
+lib boost_system : : <toolset>cray <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt-$(VERSION_TAG).a ;
+lib boost_thread : : <toolset>cray <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt-$(VERSION_TAG).a ;
+lib boost_test : : <toolset>cray <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt-$(VERSION_TAG).a ;
+lib boost_test_monitor : : <toolset>cray <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt-$(VERSION_TAG).a ;
+lib boost_program_options : : <toolset>cray <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt-$(VERSION_TAG).a ;
+lib boost_filesystem : : <toolset>cray <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt-$(VERSION_TAG).a ;
+lib boost_datetime : : <toolset>cray <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt-$(VERSION_TAG).a ;
+lib boost_python : : <toolset>cray <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-$(VERSION_TAG).so ;
+lib boost_python_static : : <toolset>cray <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-$(VERSION_TAG).a ;
+
+lib boost_serialization : : <toolset>cray <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt-$(VERSION_TAG).a ;
+lib boost_system : : <toolset>cray <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt-$(VERSION_TAG).a ;
+lib boost_thread : : <toolset>cray <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt-$(VERSION_TAG).a ;
+lib boost_test : : <toolset>cray <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt-$(VERSION_TAG).a ;
+lib boost_test_monitor : : <toolset>cray <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt-$(VERSION_TAG).a ;
+lib boost_program_options : : <toolset>cray <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt-$(VERSION_TAG).a ;
+lib boost_filesystem : : <toolset>cray <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt-$(VERSION_TAG).a ;
+lib boost_datetime : : <toolset>cray <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt-$(VERSION_TAG).a ;
+lib boost_python : : <toolset>cray <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-$(VERSION_TAG).so ;
+lib boost_python_static : : <toolset>cray <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-$(VERSION_TAG).a ;
+
+
+# ******************** CRAY Compiler specific ************************************
+# The customer may be able to work around this by adding
+#
+# -DBOOST_ASIO_DISABLE_FENCED_BLOCK=1
+#
+# to the compiler invocation.
+#
+# The issue is that the various compiler macros set are causing a file with gcc
+# inline assembly to be included. CCE does not currently support inline assembly.
+#
+# Note that adding this macro to the command line may cause additional Boost
+# compilation errors to surface.
+#
+# Notice: we don't add requirements <library>pthread , because
+# a/ Not all tests require it
+# b/ Can cause links errors
+# Hence left to individual projects/test
+#
+# ***********************************************************************************
+project site-config
+ : requirements <include>$(BOOST_ROOT)
+ : requirements <toolset>cray:<define>BOOST_ASIO_DISABLE_FENCED_BLOCK
+ <toolset>gcc:<cxxflags>-Wno-unused-local-typedefs
+ ;
+
+# On linux 64, because most of the static library's, are placed in a shared libs(ecflow.so)
+# hence we need to compile with -fPIC
+#
+# using syntax:
+# using toolset-name : version :invocation-command : options ;
+# where options allows <cflags, cxxflags, compileflags and linkflags >
+#
+#using gcc : : : <cxxflags>-fPIC ;
+#using cray : : : <cxxflags>-fPIC ;
+#using intel-linux : : : <cxxflags>-fPIC ;
+
+
+# For cray use the 'CC' wrapper script, however this assumes you linking with MPI, then barf's
+# using gcc : : CC : <cxxflags>-fPIC ;
+#
+#
+# $BOOST_ROOT/bjam --toolset=gcc cflags="-std=gnu++11" c++-template-depth=512
+# using gcc : 4.7.2 : : <cxxflags>-fPIC <cxxflags>-std=gnu++11 <cxxflags>-ftemplate-depth=512 ;
+
+using testing ;
+
+# ==================== ECFLOWVIEW/install =======================================================
+
+local motif_library = [ os.environ MOTIF_LIBRARY ] ;
+motif_library default = "/usr/lib64" ;
+constant MOTIF_LIBRARY : $(motif_library) ;
diff --git a/build_scripts/tar_ecflow.sh b/build_scripts/tar_ecflow.sh
new file mode 100755
index 0000000..e04a16a
--- /dev/null
+++ b/build_scripts/tar_ecflow.sh
@@ -0,0 +1,146 @@
+#!/bin/sh
+
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+# Tar up ecflow
+# Assumes $WK(root workspace) is defined
+
+set -e # stop the shell on first error
+set -u # fail when using an undefined variable
+
+# ===============================================================================
+# Test/data/ECF_HOME is used by Test to recursively generate directory structure
+# and populate with defs file, and job output, etc, hence exclude this directory
+# ===============================================================================
+cd $WK
+rm -rf *.dat
+rm -rf *lock
+rm -rf *log
+rm -rf *.check
+rm -rf *.def
+rm -rf rtt.dat
+rm -rf Test/data/ECF_HOME_debug*
+rm -rf Test/data/ECF_HOME_release*
+rm -rf view/data/ECF_HOME_debug*
+rm -rf view/data/ECF_HOME_release*
+rm -rf AParser/test/data/single_defs/mega.def_log
+rm -rf Pyext/test.def
+rm -rf Pyext/build
+rm -rf Pyext/test/data/ecf_home_*
+
+# ================================================================================
+# Remove generated files before taring ecFlow
+# Be careful with *.txt extension. i.e do not to delete CMakeList.txt file.
+# ================================================================================
+cd $WK
+
+# exclude log files from hidden files/directories like .metadata
+find . \( ! -regex '.*/\..*' \) -type f -name \*.log -exec rm -rf \*.log {} \; -print
+
+find . -name \*~ -exec rm -rf \*~ {} \; -print
+find . -name \*.mk -exec rm -rf \*.mk {} \; -print
+find . -name \*.so -exec rm -rf \*.so {} \; -print
+find . -name \*.tmp -exec rm -rf \*.tmp {} \; -print
+find . -name \*.job\* -exec rm -rf \*.job\* {} \; -print
+find . -name \*.check -exec rm -rf \*.check {} \; -print
+find . -name \*.flat -exec rm -rf \*.flat {} \; -print
+find . -name \*.depth -exec rm -rf \*.depth {} \; -print
+find . -name \*.out -exec rm -rf \*.out {} \; -print
+find . -name \*.pyc -exec rm -rf \*.pyc {} \; -print
+find . -name t\*.1 -exec rm -rf t\*.1 {} \; -print
+find . -name gmon.out -exec rm -rf gmon.out {} \; -print
+find . -name gnuplot.dat -exec rm -rf gnuplot.dat {} \; -print
+find . -name gnuplot.script -exec rm -rf gnuplot.script {} \; -print
+find . -name ecflow.html -exec rm -rf ecflow.html {} \; -print
+find . -name core -exec rm -rf core {} \; -print
+find . -name `hostname`.*.ecf.* -exec rm -rf `hostname`.*.ecf.* {} \; -print
+find . -name callgrind.out.\* -exec rm -rf callgrind.out.\* {} \; -print
+find . -name massif.out.\* -exec rm -rf massif.out.* {} \; -print
+
+# ======================================================================
+# Create the tar file name based on the version
+# Determine ecflow build directory name: see ACore/doc/extracting_version_number.ddoc
+# ========================================================================
+cd $WK
+
+release=$(cat VERSION.cmake | grep 'set( ECFLOW_RELEASE' | awk '{print $3}'| sed 's/["]//g')
+major=$(cat VERSION.cmake | grep 'set( ECFLOW_MAJOR' | awk '{print $3}'| sed 's/["]//g')
+minor=$(cat VERSION.cmake | grep 'set( ECFLOW_MINOR' | awk '{print $3}'| sed 's/["]//g')
+
+ECFLOW_WS_DIR=ecflow_${release}_${major}_${minor}
+
+# ================================================================================
+# Create ecflow tar file
+# ================================================================================
+cd $WK
+cd ..
+
+# remove old tar files
+ECFLOWTAR=$ECFLOW_WS_DIR.tar
+rm -rf $ECFLOWTAR.gz
+rm -rf $ECFLOWTAR
+
+# temporarily create a symbolic link ECFLOW_WS_DIR, so that tar file directory name has version number in it
+ln -s ecflow $ECFLOW_WS_DIR
+
+# Exclusions from tar file:
+# o/ .pydevproject used by Pydev eclipse plug-in
+# o/ .metadata, .cproject, .project, .settings, csettings are eclipse dir
+# o/ --exclude=SCRATCH - has code for recording stand alone bugs.
+# o/ bin directory contains the build object files and exe's
+# o/ Debug is the eclipse/make dir
+# o/ operations: this consists of the mega defs file used in operations for reference only /AParser/test/data/operations
+# o/ Pyext/ecf/ecflow.so is ecFlow python extension
+# o/ Exclude ddoc file's
+# o/ Exclude *CERTAIN* Documentation directory , this includes the sphinx generated file '_build' ~4 Mb
+# ** STILL NEED Doc/online as this used in the python unit tests.
+# ** STILL NEED user-manual as this is installed
+# o/ Exclude check point and back up check point files, --exclude=*.check --exclude=*.check.b
+# o/ Exclude build/include
+# o/ RemoteSystemsTempFile dir generated by eclipse
+# o/ Xcdp, xcdp old ecflowview dirs
+# o/ exclude ecbuild used for CMAKE. Still needs sorting out
+# o/ exclude Pyext/test/data/CUSTOMER
+# o/ gcc4.5 this directory is under build/, used for CMAKE
+tar --exclude=*.check --exclude=*.check.b \
+ --exclude=*.ddoc \
+ --exclude=.p4config \
+ --exclude=SCRATCH \
+ --exclude=New_viewer \
+ --exclude=_build --exclude=func_spec --exclude=misc --exclude=newsletter --exclude=presentations --exclude=seminar --exclude=tac --exclude=Thumbs.db \
+ --exclude=.pydevproject \
+ --exclude=.git \
+ --exclude=.metadata --exclude=.cproject --exclude=.project --exclude=.settings --exclude=.csettings \
+ --exclude=ecbuild \
+ --exclude=bin \
+ --exclude=gcc4.8 \
+ --exclude=Debug \
+ --exclude=operations \
+ --exclude=ecflow.so \
+ --exclude=profile.sh \
+ --exclude=CUSTOMER \
+ --exclude=massive.sh \
+ --exclude=val.sh \
+ --exclude=include \
+ --exclude=test_bench \
+ --exclude=nightly \
+ --exclude=online \
+ --exclude=RemoteSystemsTempFiles \
+ -cf $ECFLOWTAR $ECFLOW_WS_DIR/.
+
+# Remove the link
+rm $ECFLOW_WS_DIR
+
+# add ecbuild/ into tar file, exclude any .git files
+tar -rvf $ECFLOWTAR --exclude=.git ecbuild/
+
+ls -lh $ECFLOWTAR
+gzip $ECFLOWTAR
+
+# Move tar file to /var/tmp/ma0/
+mv $ECFLOWTAR.gz ../.
diff --git a/build_scripts/test.sh b/build_scripts/test.sh
new file mode 100755
index 0000000..aad518a
--- /dev/null
+++ b/build_scripts/test.sh
@@ -0,0 +1,186 @@
+#!/bin/sh
+
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+#===================================================================
+# Run all the ecflow tests, note use !/bin/bash to keep rpm happy, it uses bash
+#===================================================================
+
+if [ "$#" -gt 3 ] ; then
+ echo "Maximum of 3 arguments expected"
+ echo " arg1-mode (optional) default = debug, valid values = [ debug | release ]"
+ echo " arg2-compiler(optional) default = linux/gcc-$(gcc -dumpversion)"
+ echo " arg3-safe (optional) default = no, valid values = [ no | safe ],"
+ echo " safe means only run deterministic tests"
+ exit 1
+fi
+
+mode=debug
+compiler_arg=
+safe=no
+while [ "$#" -ne 0 ] ; do
+ if [ "$1" = debug -o "$1" = release -o "$1" = profile ] ; then
+ mode=$1
+ elif [ "$1" = safe ] ; then
+ safe=yes
+ else
+ compiler_arg=$1
+ fi
+ # shift remove last argument
+ shift
+done
+
+if [ ${#mode} -eq 0 ] ; then
+ echo "test expects mode i.e. debug or release"
+ exit 1
+fi
+
+echo "mode=$mode compiler=$compiler_arg safe=$safe"
+#exit 1;
+
+#======================================================================
+# remove python test, so that they are rerun
+rm -rf Pyext/bin/*.test
+
+# Remove any lock file create by tests which used EcfPortLock.hpp
+# ** However DO *NOT* remove this locks for in ecflow test.ecf
+# ** as they allow the debug and release test to run at the same time.
+rm -rf *.lock
+
+# Check that a command is in the PATH.
+test_path ()
+{
+ if `command -v command 1>/dev/null 2>/dev/null`; then
+ command -v $1 1>/dev/null 2>/dev/null
+ else
+ hash $1 1>/dev/null 2>/dev/null
+ fi
+}
+
+# Check that the OS name, as returned by "uname", is as given.
+test_uname ()
+{
+ if test_path uname; then
+ test `uname` = $*
+ fi
+}
+
+unset ECF_PORT
+
+if test_uname Linux ; then
+
+ TOOLSET=
+ CXXFLAGS=
+ compiler=gcc-$(gcc -dumpversion)
+
+ # When on cray check PE_ENV for environment
+ if [ "$PE_ENV" = INTEL -o "$PE_ENV" = CRAY -o "$PE_ENV" = GNU ]
+ then
+ CXXFLAGS=cxxflags=-fPIC
+ TOOLSET=toolset=gcc
+ if [ "$PE_ENV" = INTEL ] ; then
+ compiler=intel-linux
+ TOOLSET=toolset=intel
+ fi
+ if [ "$PE_ENV" = CRAY ] ; then
+ compiler=cray
+ TOOLSET=toolset=cray
+ fi
+ fi
+
+ # Allow the compiler to be overridden on linux
+ if [ ${#compiler_arg} -ne 0 ] ; then
+ compiler=$compiler_arg
+ fi
+
+ echo "*****************************************"
+ echo "Testing: variant=$mode compiler=$compiler"
+ echo "*****************************************"
+
+ ACore/bin/$compiler/$mode/u_acore --log_level=message $TEST_OPTS
+ ANattr/bin/$compiler/$mode/u_anattr --log_level=message $TEST_OPTS
+ ANode/bin/$compiler/$mode/u_anode --log_level=message $TEST_OPTS
+ AParser/bin/$compiler/$mode/u_aparser --log_level=message $TEST_OPTS
+ if [ "$safe" = no ] ; then
+ AParser/bin/$compiler/$mode/perf_aparser --log_level=message $TEST_OPTS
+ fi
+ Base/bin/$compiler/$mode/u_base --log_level=message $TEST_OPTS
+ Client/bin/$compiler/$mode/s_client --log_level=message $TEST_OPTS
+ Server/bin/$compiler/$mode/u_server --log_level=message $TEST_OPTS
+ CSim/bin/$compiler/$mode/c_csim --log_level=message $TEST_OPTS
+ if [ "$safe" = no ] ; then
+ Test/bin/$compiler/$mode/s_test --log_level=message $TEST_OPTS
+ Test/bin/$compiler/$mode/s_test_zombies --log_level=message $TEST_OPTS
+ fi
+
+ if [ "$safe" = no ] ; then
+ # run python/C++ test
+ cd Pyext
+ $BOOST_ROOT/bjam $TOOLSET $CXXFLAGS variant=$mode test-all $TEST_OPTS
+ cd ..
+ fi
+
+ if [ x$DISPLAY = x ]; then
+ echo "DISPLAY variable is not defined, ecflowview is not tested..."
+ else
+ view/bin/$compiler/$mode/test-view --log_level=message $TEST_OPTS
+ fi
+
+elif test_uname HP-UX ; then
+
+ echo "Testing: variant=$mode"
+ ACore/bin/acc/$mode/threading-multi/u_acore --log_level=message $TEST_OPTS
+ ANattr/bin/acc/$mode/threading-multi/u_anattr --log_level=message $TEST_OPTS
+ ANode/bin/acc/$mode/threading-multi/u_anode --log_level=message $TEST_OPTS
+ AParser/bin/acc/$mode/threading-multi/u_aparser --log_level=message $TEST_OPTS
+ if [ "$safe" = no ] ; then
+ AParser/bin/acc/$mode/threading-multi/perf_aparser --log_level=message $TEST_OPTS
+ fi
+ Base/bin/acc/$mode/threading-multi/u_base --log_level=message $TEST_OPTS
+ Client/bin/acc/$mode/threading-multi/s_client --log_level=message $TEST_OPTS
+ Server/bin/acc/$mode/threading-multi/u_server --log_level=message $TEST_OPTS
+ CSim/bin/acc/$mode/threading-multi/c_csim --log_level=message $TEST_OPTS
+ if [ "$safe" = no ] ; then
+ Test/bin/acc/$mode/threading-multi/s_test --log_level=message $TEST_OPTS
+ Test/bin/acc/$mode/threading-multi/s_test_zombies --log_level=message $TEST_OPTS
+ fi
+
+ if [ "$safe" = no ] ; then
+ # run python/C++ test, use test to bypass 'with' statement tests
+ cd Pyext
+ $BOOST_ROOT/bjam variant=$mode test $TEST_OPTS
+ cd ..
+ fi
+
+elif test_uname AIX ; then
+
+ echo "Testing: $ARCH variant=$mode"
+
+ ACore/bin/vacpp/$mode/threading-multi/u_acore --log_level=message $TEST_OPTS
+ ANattr/bin/vacpp/$mode/threading-multi/u_anattr --log_level=message $TEST_OPTS
+ ANode/bin/vacpp/$mode/threading-multi/u_anode --log_level=message $TEST_OPTS
+ AParser/bin/vacpp/$mode/threading-multi/u_aparser --log_level=message $TEST_OPTS
+ if [ "$safe" = no ] ; then
+ AParser/bin/vacpp/$mode/threading-multi/perf_aparser --log_level=message $TEST_OPTS
+ fi
+ Base/bin/vacpp/$mode/threading-multi/u_base --log_level=message $TEST_OPTS
+ Client/bin/vacpp/$mode/threading-multi/s_client --log_level=message $TEST_OPTS
+ Server/bin/vacpp/$mode/threading-multi/u_server --log_level=message $TEST_OPTS
+ CSim/bin/vacpp/$mode/threading-multi/c_csim --log_level=message $TEST_OPTS
+ if [ "$safe" = no ] ; then
+ Test/bin/vacpp/$mode/threading-multi/s_test --log_level=message $TEST_OPTS
+ Test/bin/vacpp/$mode/threading-multi/s_test_zombies --log_level=message $TEST_OPTS
+ fi
+
+ if [ "$safe" = no ] ; then
+ # run python/C++ test
+ cd Pyext
+ $BOOST_ROOT/bjam variant=$mode test-all $TEST_OPTS
+ cd ..
+ fi
+fi
diff --git a/build_scripts/update_site_config.sh b/build_scripts/update_site_config.sh
new file mode 100644
index 0000000..ee31158
--- /dev/null
+++ b/build_scripts/update_site_config.sh
@@ -0,0 +1,83 @@
+#!/bin/sh
+
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+# This file is used build the boost libs used by ecflow
+# This script Use $BOOST_ROOT and $WK environment variable
+
+echo "WK=$WK"
+echo "BOOST_ROOT=$BOOST_ROOT"
+
+#
+# From boost 1.56 > the location of site-config.jam location has changed
+#
+SITE_CONFIG_LOCATION=$BOOST_ROOT/tools/build/v2/site-config.jam
+BOOST_VERSION="$(basename $BOOST_ROOT)"
+if [[ "$BOOST_VERSION" = boost_1_56_0 || "$BOOST_VERSION" = boost_1_57_0 ]] ; then
+ SITE_CONFIG_LOCATION=$BOOST_ROOT/tools/build/src/site-config.jam
+fi
+
+tool=
+
+# Check that a command is in the PATH.
+test_path ()
+{
+ if `command -v command 1>/dev/null 2>/dev/null`; then
+ command -v $1 1>/dev/null 2>/dev/null
+ else
+ hash $1 1>/dev/null 2>/dev/null
+ fi
+}
+
+test_uname ()
+{
+ if test_path uname; then
+ test `uname` = $*
+ fi
+}
+
+if test_uname Linux ; then
+ tool=gcc
+ X64=$(uname -m)
+ if [ "$X64" = x86_64 ]
+ then
+ # PE_ENV is defined in cray environment, at least on sandy bridge
+ if [ "$PE_ENV" = GNU -o "$PE_ENV" = INTEL -o "$PE_ENV" = CRAY ]
+ then
+ CXXFLAGS=cxxflags=-fPIC
+ layout=versioned
+
+ cp $WK/build_scripts/site_config/site-config-cray.jam $SITE_CONFIG_LOCATION
+ if [ "$PE_ENV" = INTEL ] ; then
+ tool=intel
+ fi
+ if [ "$PE_ENV" = CRAY ] ; then
+ tool=cray
+ fi
+ else
+ cp $WK/build_scripts/site_config/site-config-Linux64.jam $SITE_CONFIG_LOCATION
+ fi
+
+ else
+ cp $WK/build_scripts/site_config/site-config-Linux.jam $SITE_CONFIG_LOCATION
+ fi
+
+elif test_uname HP-UX ; then
+
+ tool=acc
+ cp $WK/build_scripts/site_config/site-config-HPUX.jam $SITE_CONFIG_LOCATION
+
+elif test_uname AIX ; then
+
+ # on c1a
+ tool=vacpp
+ cp $WK/build_scripts/site_config/site-config-AIX.jam $SITE_CONFIG_LOCATION
+
+fi
+
+
\ No newline at end of file
diff --git a/build_scripts/val.sh b/build_scripts/val.sh
new file mode 100755
index 0000000..94127aa
--- /dev/null
+++ b/build_scripts/val.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+# This script will run valgrind on all the automated test
+# Assume WK is defined
+
+#===========================================================================
+# load the latest valgrind
+module load valgrind/3.11.0
+#===========================================================================
+
+cd $WK
+
+# if argument is release test the release version else stick with debug
+mode=debug
+if test "$1" = release
+then
+ mode=release
+fi
+
+compiler=gcc-$(gcc -dumpversion)
+
+echo "valgrind: variant=$mode compiler=$compiler"
+
+#
+# Use valgrind which is newer than standard installation
+#
+# Note: To valgrind the server, start it separately on a different shell and define ECF_NODE=localhost
+# export ECF_NODE=localhost
+# valgrind Server/bin/$compiler/$mode/ecflow_server --interval=3
+# Then restart this shell
+
+
+# Use the valgrind option --track-origins=yes to have it track the origin of uninitialized values.
+# This will make it slower and take more memory, but can be very helpful if you need to track down
+# the origin of an uninitialized value.
+
+valgrind --num-callers=24 --leak-check=full --show-reachable=yes --error-exitcode=1 --partial-loads-ok=yes ACore/bin/$compiler/$mode/u_acore
+valgrind --num-callers=24 --leak-check=full --show-reachable=yes --error-exitcode=1 --partial-loads-ok=yes ANattr/bin/$compiler/$mode/u_anattr
+valgrind --num-callers=24 --leak-check=full --show-reachable=yes --error-exitcode=1 --partial-loads-ok=yes ANode/bin/$compiler/$mode/u_anode
+valgrind --num-callers=24 --leak-check=full --show-reachable=yes --error-exitcode=1 --partial-loads-ok=yes AParser/bin/$compiler/$mode/u_aparser
+valgrind --num-callers=24 --leak-check=full --show-reachable=yes --error-exitcode=1 --partial-loads-ok=yes Base/bin/$compiler/$mode/u_base
+valgrind --num-callers=24 --leak-check=full --show-reachable=yes --error-exitcode=1 --partial-loads-ok=yes Client/bin/$compiler/$mode/s_client
+valgrind --num-callers=24 --leak-check=full --show-reachable=yes --error-exitcode=1 --partial-loads-ok=yes Server/bin/$compiler/$mode/u_server
+valgrind --num-callers=24 --leak-check=full --show-reachable=yes --num-callers=30 --error-exitcode=1 --partial-loads-ok=yes Test/bin/$compiler/$mode/s_test
+valgrind --num-callers=24 --leak-check=full --show-reachable=yes --num-callers=30 --error-exitcode=1 --partial-loads-ok=yes Test/bin/$compiler/$mode/s_test_zombies
+valgrind --num-callers=24 --leak-check=full --show-reachable=yes --error-exitcode=1 --partial-loads-ok=yes CSim/bin/$compiler/$mode/c_csim
diff --git a/cmake.sh b/cmake.sh
new file mode 100755
index 0000000..f203263
--- /dev/null
+++ b/cmake.sh
@@ -0,0 +1,243 @@
+#!/bin/ksh
+# ==================================================================
+# Error handling
+set -e # stop the shell on first error
+set -u # fail when using an undefined variable
+
+# ensure correct permission for installation
+umask 0022
+
+# ====================================================================
+show_error_and_exit() {
+ echo "cmake.sh expects at least one argument"
+ echo " cmake.sh debug || release [clang] [san] [make] [verbose] [test] [package_source] [debug]"
+ echo " "
+ echo " make - run make after cmake"
+ echo " test - run all the tests"
+ echo " test_safe - only run deterministic tests"
+ echo " ctest - all ctest -R <test> -V"
+ echo " san - is short for clang thread sanitiser"
+ echo " package_source - produces ecFlow-<version>-Source.tar.gz file, for users"
+ echo " copies the tar file to $SCRATCH"
+ echo " copy_tarball - copies ecFlow-<version>-Source.tar.gz to /tmp/$USER/tmp/. and untars file"
+ exit 1
+}
+
+copy_tarball_arg=
+package_source_arg=
+make_arg=
+make_only_arg=
+test_arg=
+test_safe_arg=
+clang_arg=
+intel_arg=
+clang_sanitiser_arg=
+mode_arg=release
+verbose_arg=
+ctest_arg=
+clean_arg=
+while [[ "$#" != 0 ]] ; do
+ if [[ "$1" = debug || "$1" = release ]] ; then
+ mode_arg=$1
+ elif [[ "$1" = make_only ]] ; then
+ make_only_arg=make
+ shift
+ while [[ "$#" != 0 ]] ; do
+ make_only_arg="$make_only_arg $1"
+ shift
+ done
+ break
+ elif [[ "$1" = make ]] ; then
+ make_arg=$1
+ shift
+ while [[ "$#" != 0 ]] ; do
+ make_arg="$make_arg $1"
+ shift
+ done
+ break
+ elif [[ "$1" = clang ]] ; then
+ clang_arg=$1
+ elif [[ "$1" = intel ]] ; then
+ intel_arg=$1
+ elif [[ "$1" = clean ]] ; then
+ clean_arg=$1
+ elif [[ "$1" = san ]] ; then
+ clang_sanitiser_arg=$1
+ elif [[ "$1" = package_source ]] ; then
+ package_source_arg=$1
+ elif [[ "$1" = copy_tarball ]] ; then
+ copy_tarball_arg=$1
+ elif [[ "$1" = test ]] ; then
+ test_arg=$1
+ elif [[ "$1" = test_safe ]] ; then
+ test_safe_arg=$1
+ elif [[ "$1" = ctest ]] ; then
+ ctest_arg=$1 ;
+ shift
+ while [[ "$#" != 0 ]] ; do
+ ctest_arg="$ctest_arg $1"
+ shift
+ done
+ break
+ else
+ show_error_and_exit
+ fi
+
+ # shift remove last argument
+ shift
+done
+
+echo "copy_tarball_arg=$copy_tarball_arg"
+echo "package_source_arg=$package_source_arg"
+echo "make_arg=$make_arg"
+echo "test_arg=$test_arg"
+echo "test_safe_arg=$test_safe_arg"
+echo "clang_arg=$clang_arg"
+echo "clang_sanitiser_arg=$clang_sanitiser_arg"
+echo "mode_arg=$mode_arg"
+echo "verbose_arg=$verbose_arg"
+set -x # echo script lines as they are executed
+
+# ==================== modules ================================================
+# To load module automatically requires Korn shell, system start scripts
+
+module load cmake/3.3.2
+module load ecbuild/2.2.0
+cmake_extra_options=""
+if [[ "$clang_arg" = clang ]] ; then
+ module unload gnu
+ module load clang
+ cmake_extra_options="-DCMAKE_CXX_FLAGS=-ftemplate-depth=512"
+fi
+if [[ "$clang_sanitiser_arg" = san ]] ; then
+ module unload gnu
+ module load clang
+ cmake_extra_options="$cmake_extra_options -DCMAKE_C_FLAGS=-fsanitize=thread"
+fi
+if [[ "$ARCH" = cray ]] ; then
+ cmake_extra_options="$cmake_extra_options -DENABLE_UI=OFF"
+
+ if [[ $intel_arg = intel ]] ; then
+ module swap PrgEnv-cray PrgEnv-intel
+ else
+ module swap PrgEnv-cray PrgEnv-gnu
+ fi
+fi
+
+# boost
+#module load boost/1.59.0
+
+# ====================================================================================
+cmake_build_type=
+if [[ $mode_arg = debug ]] ; then
+ cmake_build_type=Debug
+else
+ cmake_build_type=Release
+fi
+
+# ====================================================================================
+# Use for local install
+release=$(cat VERSION.cmake | grep 'set( ECFLOW_RELEASE' | awk '{print $3}'| sed 's/["]//g')
+major=$(cat VERSION.cmake | grep 'set( ECFLOW_MAJOR' | awk '{print $3}'| sed 's/["]//g')
+minor=$(cat VERSION.cmake | grep 'set( ECFLOW_MINOR' | awk '{print $3}'| sed 's/["]//g')
+
+# ====================================================================================
+# clean up source before packaging, do this after deleting ecbuild
+if [[ $package_source_arg = package_source ]] ; then
+ source build_scripts/clean.sh
+fi
+
+# =======================================================================================
+# Change directory
+source_dir=$(pwd)
+workspace=$(pwd)/..
+
+if [[ $clean_arg = clean ]] ; then
+ rm -rf ../bdir/$mode_arg/ecflow
+fi
+
+mkdir -p ../bdir/$mode_arg/ecflow
+cd ../bdir/$mode_arg/ecflow
+
+
+# =============================================================================================
+if [[ $test_arg = test || $test_safe_arg = test_safe ]] ; then
+ ctest -R ^u_
+ ctest -R c_
+ ctest -R py_u
+ ctest -R s_client
+ if [[ $test_safe_arg = test_safe ]] ; then
+ exit 0
+ fi
+fi
+if [[ $test_arg = test ]] ; then
+ ctest -R s_test
+ ctest -R py_s
+ exit 0
+fi
+
+# ctest
+if [[ "$ctest_arg" != "" ]] ; then
+ $ctest_arg
+ exit 0
+fi
+
+if [[ "$make_only_arg" != "" ]] ; then
+ $make_only_arg
+ exit 0
+fi
+
+# ====================================================================================
+#
+# -DCMAKE_PYTHON_INSTALL_TYPE = [ local | setup ]
+# -DCMAKE_PYTHON_INSTALL_PREFIX should *only* used when using python setup.py (CMAKE_PYTHON_INSTALL_TYPE=setup)
+# *AND* for testing python install to local directory
+#
+
+ecbuild $source_dir \
+ -DCMAKE_BUILD_TYPE=$cmake_build_type \
+ -DCMAKE_INSTALL_PREFIX=/var/tmp/$USER/install/cmake/ecflow/$release.$major.$minor \
+ -DCMAKE_PYTHON_INSTALL_TYPE=local \
+ -DENABLE_WARNINGS=ON \
+ -DENABLE_ALL_TESTS=ON \
+ -DCMAKE_CXX_FLAGS="-Wno-unused-local-typedefs" \
+ -DCMAKE_PREFIX_PATH="/usr/local/apps/qt/5.5.0/5.5/gcc_64/" \
+ ${cmake_extra_options}
+ #-DCMAKE_PYTHON_INSTALL_PREFIX=/var/tmp/$USER/install/cmake/ecflow/$release.$major.$minor/lib/python2.7/site-packages/ecflow
+ #-DCMAKE_MODULE_PATH=$workspace/ecbuild/cmake \
+
+# =============================================================================================
+if [[ "$make_arg" != "" ]] ; then
+ $make_arg
+ exit 0
+fi
+
+# =============================================================================================
+if [[ $package_source_arg = package_source ]] ; then
+ make package_source
+
+ if [[ $copy_tarball_arg = copy_tarball ]] ; then
+ rm -rf /tmp/$USER/tmp
+ mkdir -p /tmp/$USER/tmp
+ cp ecFlow-$release.$major.$minor-Source.tar.gz /tmp/$USER/tmp/.
+ cd /tmp/$USER/tmp/
+ tar -zxf ecFlow-$release.$major.$minor-Source.tar.gz
+ fi
+
+ cp ecFlow-$release.$major.$minor-Source.tar.gz $SCRATCH/.
+fi
+
+# =========================================================================================
+# NOTES:
+# Boost:
+# By default it looks for environment variable BOOST_ROOT, if not it can specified on the command line. i.e
+# -DBOOST_ROOT=/var/tmp/$USER/boost/boost_1_53_0
+
+# ============================================================================================
+# Python:
+# -DCMAKE_PYTHON_INSTALL_TYPE = [ local | setup ]
+# local : this will install to $INSTALL_PREFIX/$release.$major.$minor/lib/python2.7/site-packages/ecflow/
+# setup : experimental only, python way of installing
+#
+# -DCMAKE_PYTHON_INSTALL_PREFIX should *only* used when using python setup.py (CMAKE_PYTHON_INSTALL_TYPE=setup)
+# *AND* for testing python install to local directory
diff --git a/ecbuild/cmake/2.8/CMakePushCheckState.cmake b/cmake/2.8/CMakePushCheckState.cmake
similarity index 100%
rename from ecbuild/cmake/2.8/CMakePushCheckState.cmake
rename to cmake/2.8/CMakePushCheckState.cmake
diff --git a/ecbuild/cmake/CheckFortranCompilerFlag.cmake b/cmake/CheckFortranCompilerFlag.cmake
similarity index 100%
rename from ecbuild/cmake/CheckFortranCompilerFlag.cmake
rename to cmake/CheckFortranCompilerFlag.cmake
diff --git a/cmake/CheckFortranSourceCompiles.cmake b/cmake/CheckFortranSourceCompiles.cmake
new file mode 100644
index 0000000..d3dc968
--- /dev/null
+++ b/cmake/CheckFortranSourceCompiles.cmake
@@ -0,0 +1,94 @@
+# - Check if given Fortran source compiles and links into an executable
+# CHECK_FORTRAN_SOURCE_COMPILES(<code> <var> [FAIL_REGEX <fail-regex>])
+# <code> - source code to try to compile, must define 'main'
+# <var> - variable to store whether the source code compiled
+# <fail-regex> - fail if test output matches this regex
+# The following variables may be set before calling this macro to
+# modify the way the check is run:
+#
+# CMAKE_REQUIRED_FLAGS = string of compile command line flags
+# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
+# CMAKE_REQUIRED_INCLUDES = list of include directories
+# CMAKE_REQUIRED_LIBRARIES = list of libraries to link
+
+#=============================================================================
+# Copyright 2005-2009 Kitware, Inc.
+# Fortran version, 2013, James Tappin
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+# License text for the above reference.)
+
+
+
+macro(CHECK_FORTRAN_SOURCE_COMPILES SOURCE VAR)
+
+if( ${VAR} MATCHES "^${VAR}$" )
+ set(_FAIL_REGEX)
+ set(_key)
+ foreach(arg ${ARGN})
+ if("${arg}" MATCHES "^(FAIL_REGEX)$")
+ set(_key "${arg}")
+ elseif(_key)
+ list(APPEND _${_key} "${arg}")
+ else()
+ ecbuild_critical("Unknown argument:\n ${arg}\n")
+ endif()
+ endforeach()
+ set(MACRO_CHECK_FUNCTION_DEFINITIONS
+ "-D${VAR} ${CMAKE_REQUIRED_FLAGS}")
+ if(CMAKE_REQUIRED_LIBRARIES)
+ set(CHECK_FORTRAN_SOURCE_COMPILES_ADD_LIBRARIES
+ LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES})
+ else()
+ set(CHECK_FORTRAN_SOURCE_COMPILES_ADD_LIBRARIES)
+ endif()
+ if(CMAKE_REQUIRED_INCLUDES)
+ set(CHECK_FORTRAN_SOURCE_COMPILES_ADD_INCLUDES
+ "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}")
+ else()
+ set(CHECK_FORTRAN_SOURCE_COMPILES_ADD_INCLUDES)
+ endif()
+ file(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.f90"
+ "${SOURCE}\n")
+
+ ecbuild_debug("Performing Test ${VAR}")
+ try_compile(${VAR}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.f90
+ COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+ ${CHECK_FORTRAN_SOURCE_COMPILES_ADD_LIBRARIES}
+ CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS}
+ "${CHECK_FORTRAN_SOURCE_COMPILES_ADD_INCLUDES}"
+ OUTPUT_VARIABLE OUTPUT)
+
+ foreach(_regex ${_FAIL_REGEX})
+ if("${OUTPUT}" MATCHES "${_regex}")
+ set(${VAR} 0)
+ endif()
+ endforeach()
+
+ if(${VAR})
+ set(${VAR} 1 CACHE INTERNAL "Test ${VAR}")
+ ecbuild_debug("Performing Test ${VAR} - Success")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Performing Fortran SOURCE FILE Test ${VAR} succeded with the following output:\n"
+ "${OUTPUT}\n"
+ "Source file was:\n${SOURCE}\n")
+ else()
+ ecbuild_debug("Performing Test ${VAR} - Failed")
+ set(${VAR} "" CACHE INTERNAL "Test ${VAR}")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Performing Fortran SOURCE FILE Test ${VAR} failed with the following output:\n"
+ "${OUTPUT}\n"
+ "Source file was:\n${SOURCE}\n")
+ endif()
+ endif()
+endmacro()
+
diff --git a/cmake/FindADSM.cmake b/cmake/FindADSM.cmake
new file mode 100644
index 0000000..b46e798
--- /dev/null
+++ b/cmake/FindADSM.cmake
@@ -0,0 +1,43 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+# - Try to find ADSM
+# Once done this will define
+# ADSM_FOUND - System has ADSM
+# ADSM_INCLUDE_DIRS - The ADSM include directories
+# ADSM_LIBRARIES - The libraries needed to use ADSM
+
+if( EC_OS_BITS EQUAL 32 )
+ set( ADSM_LIBNAME ApiDS )
+endif()
+if( EC_OS_BITS EQUAL 64 )
+ set( ADSM_LIBNAME ApiTSM64 )
+endif()
+if( NOT DEFINED ADSM_LIBNAME )
+ message( STATUS "MARS only supports ADSM with 32 or 64 bits" )
+endif()
+
+if( DEFINED ADSM_PATH )
+ find_path(ADSM_INCLUDE_DIR dsmapitd.h PATHS ${ADSM_PATH} ${ADSM_PATH}/include ${ADSM_PATH}/sample NO_DEFAULT_PATH )
+ find_library(ADSM_LIBRARY ${ADSM_LIBNAME} PATHS ${ADSM_PATH} ${ADSM_PATH}/lib ${ADSM_PATH}/lib64 NO_DEFAULT_PATH )
+endif()
+
+find_path(ADSM_INCLUDE_DIR dsmapitd.h PATH_SUFFIXES bin64 )
+find_library( ADSM_LIBRARY ${ADSM_LIBNAME} PATH_SUFFIXES bin64 )
+
+set( ADSM_LIBRARIES ${ADSM_LIBRARY} )
+set( ADSM_INCLUDE_DIRS ${ADSM_INCLUDE_DIR} )
+
+include(FindPackageHandleStandardArgs)
+
+# handle the QUIETLY and REQUIRED arguments and set ADSM_FOUND to TRUE
+# if all listed variables are TRUE
+find_package_handle_standard_args(ADSM DEFAULT_MSG
+ ADSM_LIBRARY ADSM_INCLUDE_DIR)
+
+mark_as_advanced(ADSM_INCLUDE_DIR ADSM_LIBRARY )
diff --git a/cmake/FindAEC.cmake b/cmake/FindAEC.cmake
new file mode 100644
index 0000000..767544f
--- /dev/null
+++ b/cmake/FindAEC.cmake
@@ -0,0 +1,32 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+# - Try to find AEC (Adaptive Entropy Coding library)
+# See https://www.dkrz.de/redmine/projects/aec/wiki
+
+# Once done this will define
+# AEC_FOUND - System has AEC
+# AEC_INCLUDE_DIRS - The AEC include directories
+# AEC_LIBRARIES - The libraries needed to use AEC
+
+if( DEFINED AEC_PATH )
+ find_path( AEC_INCLUDE_DIR szlib.h PATHS ${AEC_PATH}/include PATH_SUFFIXES aec NO_DEFAULT_PATH )
+ find_library( AEC_LIBRARY NAMES aec PATHS ${AEC_PATH}/lib PATH_SUFFIXES aec NO_DEFAULT_PATH )
+endif()
+
+find_path( AEC_INCLUDE_DIR szlib.h PATH_SUFFIXES aec )
+find_library( AEC_LIBRARY NAMES aec PATH_SUFFIXES aec )
+
+set( AEC_LIBRARIES ${AEC_LIBRARY} )
+set( AEC_INCLUDE_DIRS ${AEC_INCLUDE_DIR} )
+
+include(FindPackageHandleStandardArgs)
+
+find_package_handle_standard_args(AEC DEFAULT_MSG AEC_LIBRARY AEC_INCLUDE_DIR)
+
+mark_as_advanced(AEC_INCLUDE_DIR AEC_LIBRARY )
diff --git a/cmake/FindAIO.cmake b/cmake/FindAIO.cmake
new file mode 100644
index 0000000..76e357a
--- /dev/null
+++ b/cmake/FindAIO.cmake
@@ -0,0 +1,66 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+# OUTPUT:
+# RT_LIB = the library to link against
+
+if( CMAKE_SYSTEM_NAME MATCHES "Linux" )
+
+ find_package( Realtime )
+
+ if( REALTIME_FOUND ) # check that aio needs realtime
+ set( AIO_LIBRARIES ${RT_LIB} )
+ endif()
+
+endif()
+
+find_path( AIO_INCLUDE_DIRS NAMES aio.h HINTS ENV AIO_PATH ${AIO_PATH} )
+
+mark_as_advanced( AIO_INCLUDE_DIRS )
+
+include(FindPackageHandleStandardArgs)
+
+find_package_handle_standard_args( AIO DEFAULT_MSG AIO_INCLUDE_DIRS )
+
+# checks for AIO64 vs AIO
+if( AIO_FOUND )
+
+ include( CheckCSourceCompiles )
+ include( CMakePushCheckState )
+
+ cmake_push_check_state()
+
+ set( CMAKE_REQUIRED_INCLUDES ${AIO_INCLUDE_DIRS} )
+
+ if( AIO_LIBRARIES )
+ set( CMAKE_REQUIRED_LIBRARIES ${AIO_LIBRARIES} )
+ endif()
+
+ check_c_source_compiles( "#include <aio.h>
+ #include <fcntl.h>
+ int main(){
+ struct aiocb* aiocbp;
+ int n = aio_write(aiocbp);
+ n = aio_read(aiocbp);
+ n = aio_fsync(O_SYNC,aiocbp);
+ return 0; }"
+ EC_HAVE_AIOCB )
+
+ check_c_source_compiles( "#include <aio.h>
+ #include <fcntl.h>
+ int main(){
+ struct aiocb64* aiocbp;
+ int n = aio_write64(aiocbp);
+ n = aio_read64(aiocbp);
+ n = aio_fsync64(O_SYNC,aiocbp);
+ return 0; }"
+ EC_HAVE_AIOCB64 )
+
+ cmake_pop_check_state()
+
+endif()
diff --git a/cmake/FindArmadillo.cmake b/cmake/FindArmadillo.cmake
new file mode 100644
index 0000000..4ef1a4a
--- /dev/null
+++ b/cmake/FindArmadillo.cmake
@@ -0,0 +1,43 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+# - Try to find Armadillo
+# Once done this will define
+#
+# ARMADILLO_FOUND - system has Armadillo
+# ARMADILLO_INCLUDE_DIRS - the Armadillo include directory
+# ARMADILLO_LIBRARIES - the Armadillo library
+#
+# The following paths will be searched with priority if set in CMake or env
+#
+# ARMADILLO_PATH - prefix path of the Armadillo installation
+
+# Search with priority for ARMADILLO_PATH if given as CMake or env var
+find_path(ARMADILLO_INCLUDE_DIR armadillo
+ PATHS ${ARMADILLO_PATH} ENV ARMADILLO_PATH
+ PATH_SUFFIXES include NO_DEFAULT_PATH)
+find_path(ARMADILLO_INCLUDE_DIR armadillo PATH_SUFFIXES include )
+
+# Search with priority for ARMADILLO_PATH if given as CMake or env var
+find_library(ARMADILLO_LIBRARY armadillo
+ PATHS ${ARMADILLO_PATH} ENV ARMADILLO_PATH
+ PATH_SUFFIXES lib64 lib NO_DEFAULT_PATH)
+find_library( ARMADILLO_LIBRARY armadillo PATH_SUFFIXES lib64 lib )
+
+set( ARMADILLO_LIBRARIES ${ARMADILLO_LIBRARY} )
+set( ARMADILLO_INCLUDE_DIRS ${ARMADILLO_INCLUDE_DIR} )
+
+include(FindPackageHandleStandardArgs)
+
+# handle the QUIET and REQUIRED arguments and set ARMADILLO_FOUND to TRUE
+# if all listed variables are TRUE
+# Note: capitalisation of the package name must be the same as in the file name
+find_package_handle_standard_args(Armadillo DEFAULT_MSG
+ ARMADILLO_LIBRARY ARMADILLO_INCLUDE_DIR)
+
+mark_as_advanced(ARMADILLO_INCLUDE_DIR ARMADILLO_LIBRARY )
diff --git a/cmake/FindCMath.cmake b/cmake/FindCMath.cmake
new file mode 100644
index 0000000..b8a2a0b
--- /dev/null
+++ b/cmake/FindCMath.cmake
@@ -0,0 +1,26 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+#Sets:
+# CMATH_LIBRARIES = the library to link against (RT etc)
+
+IF(UNIX)
+ if( DEFINED CMATH_PATH )
+ find_library(CMATH_LIBRARIES m PATHS ${CMATH_PATH}/lib NO_DEFAULT_PATH )
+ endif()
+
+ find_library(CMATH_LIBRARIES m )
+
+ include(FindPackageHandleStandardArgs)
+
+ # handle the QUIET and REQUIRED arguments and set CMATH_FOUND to TRUE
+ # if all listed variables are TRUE
+ # Note: capitalisation of the package name must be the same as in the file name
+ find_package_handle_standard_args(CMath DEFAULT_MSG CMATH_LIBRARIES )
+
+ENDIF(UNIX)
diff --git a/cmake/FindCairo.cmake b/cmake/FindCairo.cmake
new file mode 100644
index 0000000..4298a1d
--- /dev/null
+++ b/cmake/FindCairo.cmake
@@ -0,0 +1,59 @@
+# - Try to find the cairo library
+# Once done this will define
+#
+# CAIRO_FOUND - system has cairo
+# CAIRO_INCLUDE_DIRS - the cairo include directory
+# CAIRO_LIBRARIES - Link these to use cairo
+#
+# Define CAIRO_MIN_VERSION for which version desired.
+
+
+if( NOT DEFINED CAIRO_PATH AND NOT "$ENV{CAIRO_PATH}" STREQUAL "" )
+ set( APPEND CAIRO_PATH "$ENV{CAIRO_PATH}" )
+endif()
+
+if( NOT DEFINED CAIRO_PATH )
+
+ include(FindPkgConfig)
+
+ if(Cairo_FIND_REQUIRED)
+ set(_pkgconfig_REQUIRED "REQUIRED")
+ else()
+ set(_pkgconfig_REQUIRED "")
+ endif()
+
+ if(CAIRO_MIN_VERSION)
+ pkg_check_modules(PKCAIRO ${_pkgconfig_REQUIRED} cairo>=${CAIRO_MIN_VERSION})
+ else()
+ pkg_check_modules(PKCAIRO ${_pkgconfig_REQUIRED} cairo)
+ endif()
+
+ if( PKG_CONFIG_FOUND AND PKCAIRO_FOUND )
+
+ find_path(CAIRO_INCLUDE_DIR cairo.h HINTS ${PKCAIRO_INCLUDEDIR} ${PKCAIRO_INCLUDE_DIRS} PATH_SUFFIXES cairo NO_DEFAULT_PATH )
+ find_library(CAIRO_LIBRARY cairo HINTS ${PKCAIRO_LIBDIR} ${PKCAIRO_LIBRARY_DIRS} PATH_SUFFIXES cairo NO_DEFAULT_PATH )
+
+ endif()
+
+else()
+
+ find_path(CAIRO_INCLUDE_DIR cairo.h PATHS ${CAIRO_PATH}/include PATH_SUFFIXES cairo NO_DEFAULT_PATH )
+ find_library(CAIRO_LIBRARY cairo PATHS ${CAIRO_PATH}/lib PATH_SUFFIXES cairo NO_DEFAULT_PATH )
+
+endif()
+
+find_path(CAIRO_INCLUDE_DIR cairo.h PATH_SUFFIXES cairo )
+find_library( CAIRO_LIBRARY cairo PATH_SUFFIXES cairo )
+
+set( CAIRO_LIBRARIES ${CAIRO_LIBRARY} )
+set( CAIRO_INCLUDE_DIRS ${CAIRO_INCLUDE_DIR} )
+
+include(FindPackageHandleStandardArgs)
+
+# handle the QUIET and REQUIRED arguments and set CAIRO_FOUND to TRUE
+# if all listed variables are TRUE
+# Note: capitalisation of the package name must be the same as in the file name
+find_package_handle_standard_args(Cairo DEFAULT_MSG
+ CAIRO_LIBRARY CAIRO_INCLUDE_DIR)
+
+mark_as_advanced( CAIRO_INCLUDE_DIR CAIRO_LIBRARY )
diff --git a/cmake/FindDl.cmake b/cmake/FindDl.cmake
new file mode 100644
index 0000000..16463c6
--- /dev/null
+++ b/cmake/FindDl.cmake
@@ -0,0 +1,23 @@
+# © Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+#Sets:
+# DL_LIBRARIES = the library to link against (RT etc)
+
+if( DEFINED DL_PATH )
+ find_library(DL_LIBRARIES dl PATHS ${DL_PATH}/lib NO_DEFAULT_PATH )
+endif()
+
+find_library(DL_LIBRARIES dl )
+
+include(FindPackageHandleStandardArgs)
+
+# handle the QUIET and REQUIRED arguments and set DL_FOUND to TRUE
+# if all listed variables are TRUE
+# Note: capitalisation of the package name must be the same as in the file name
+find_package_handle_standard_args(Dl DEFAULT_MSG DL_LIBRARIES )
diff --git a/cmake/FindEMOS.cmake b/cmake/FindEMOS.cmake
new file mode 100644
index 0000000..c549fc2
--- /dev/null
+++ b/cmake/FindEMOS.cmake
@@ -0,0 +1,35 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+# - Try to find EMOS
+# Once done this will define
+# EMOS_FOUND - System has EMOS
+# EMOS_INCLUDE_DIRS - The EMOS include directories
+# EMOS_LIBRARIES - The libraries needed to use EMOS
+
+if( NOT DEFINED EMOS_PATH AND DEFINED $ENV{EMOS_PATH} )
+ set( EMOS_PATH $ENV{EMOS_PATH} )
+endif()
+
+if( DEFINED EMOS_PATH )
+ find_library( EMOS_LIBRARY NAMES emos.R64.D64.I32 emos.R64 emosR64 emos PATHS ${EMOS_PATH} PATH_SUFFIXES lib lib/emos NO_DEFAULT_PATH)
+endif()
+
+find_library( EMOS_LIBRARY NAMES emos.R64.D64.I32 emos.R64 emosR64 emos)
+
+ecbuild_find_fortranlibs()
+
+include(FindPackageHandleStandardArgs)
+
+find_package_handle_standard_args( EMOS DEFAULT_MSG EMOS_LIBRARY FORTRANLIBS_FOUND )
+
+mark_as_advanced(EMOS_LIBRARY)
+
+if( EMOS_FOUND )
+ set( EMOS_LIBRARIES ${EMOS_LIBRARY} ${FORTRAN_LIBRARIES} )
+endif()
diff --git a/cmake/FindFDB.cmake b/cmake/FindFDB.cmake
new file mode 100644
index 0000000..4bcbdf3
--- /dev/null
+++ b/cmake/FindFDB.cmake
@@ -0,0 +1,35 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+# - Try to find FDB
+# Once done this will define
+# FDB_FOUND - System has FDB
+# FDB_INCLUDE_DIRS - The FDB include directories
+# FDB_LIBRARIES - The libraries needed to use FDB
+
+
+if( NOT FDB_FOUND )
+
+ if( DEFINED FDB_PATH )
+ find_library( FDB_LIBRARY NAMES fdb PATHS ${FDB_PATH} ${FDB_PATH}/lib NO_DEFAULT_PATH)
+ endif()
+
+ find_library( FDB_LIBRARY NAMES fdb )
+
+ set( FDB_LIBRARIES ${FDB_LIBRARY} )
+
+ include(FindPackageHandleStandardArgs)
+
+ # handle the QUIETLY and REQUIRED arguments and set FDB_FOUND to TRUE
+ # if all listed variables are TRUE
+ find_package_handle_standard_args(FDB DEFAULT_MSG
+ FDB_LIBRARY )
+
+ mark_as_advanced(FDB_LIBRARY)
+
+endif()
diff --git a/cmake/FindGeoTIFF.cmake b/cmake/FindGeoTIFF.cmake
new file mode 100644
index 0000000..83c868c
--- /dev/null
+++ b/cmake/FindGeoTIFF.cmake
@@ -0,0 +1,38 @@
+###############################################################################
+#
+# CMake module to search for GeoTIFF library
+#
+# On success, the macro sets the following variables:
+# GEOTIFF_FOUND = if the library found
+# GEOTIFF_LIBRARIES = full path to the library
+# GEOTIFF_INCLUDE_DIR = where to find the library headers
+# also defined, but not for general use are
+# GEOTIFF_LIBRARY, where to find the PROJ.4 library.
+#
+# Copyright (c) 2009 Mateusz Loskot <mateusz at loskot.net>
+#
+# Module source: http://github.com/mloskot/workshop/tree/master/cmake/
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+#
+###############################################################################
+
+SET(GEOTIFF_NAMES geotiff)
+
+
+ FIND_PATH(GEOTIFF_INCLUDE_DIR geotiff.h PATH_PREFIXES geotiff
+ PATHS /usr/local/include/libgeotiff /usr/include/libgeotiff)
+
+ FIND_LIBRARY(GEOTIFF_LIBRARY NAMES ${GEOTIFF_NAMES})
+
+
+IF(GEOTIFF_FOUND)
+ SET(GEOTIFF_LIBRARIES ${GEOTIFF_LIBRARY})
+ENDIF()
+
+# Handle the QUIET and REQUIRED arguments and set GEOTIFF_FOUND to TRUE
+# if all listed variables are TRUE
+# Note: capitalisation of the package name must be the same as in the file name
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(GEOTiff DEFAULT_MSG GEOTIFF_LIBRARY GEOTIFF_INCLUDE_DIR)
diff --git a/cmake/FindHPSS.cmake b/cmake/FindHPSS.cmake
new file mode 100644
index 0000000..b2b662b
--- /dev/null
+++ b/cmake/FindHPSS.cmake
@@ -0,0 +1,39 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+# - Try to find HPSS
+# Once done this will define
+# HPSS_FOUND - System has HPSS
+# HPSS_INCLUDE_DIRS - The HPSS include directories
+# HPSS_LIBRARIES - The libraries needed to use HPSS
+# HPSS_DEFINITIONS - Compiler switches required for using HPSS
+
+if( DEFINED HPSS_PATH )
+ find_path(HPSS_INCLUDE_DIR hpss_api.h PATHS ${HPSS_PATH}/include PATH_SUFFIXES hpss NO_DEFAULT_PATH)
+ find_library(HPSS_LIBRARY hpss PATHS ${HPSS_PATH}/lib PATH_SUFFIXES hpss NO_DEFAULT_PATH)
+endif()
+
+find_path(HPSS_INCLUDE_DIR hpss_api.h PATH_SUFFIXES hpss )
+find_library( HPSS_LIBRARY hpss PATH_SUFFIXES hpss )
+
+include(FindPackageHandleStandardArgs)
+
+# handle the QUIETLY and REQUIRED arguments and set HPSS_FOUND to TRUE
+# if all listed variables are TRUE
+find_package_handle_standard_args(HPSS DEFAULT_MSG
+ HPSS_LIBRARY HPSS_INCLUDE_DIR)
+
+mark_as_advanced(HPSS_INCLUDE_DIR HPSS_LIBRARY )
+
+if( HPSS_FOUND )
+ set( HPSS_LIBRARIES ${HPSS_LIBRARY} )
+ set( HPSS_INCLUDE_DIRS ${HPSS_INCLUDE_DIR} )
+else()
+ set( HPSS_LIBRARIES "" )
+ set( HPSS_INCLUDE_DIRS "" )
+endif()
diff --git a/cmake/FindLEX.cmake b/cmake/FindLEX.cmake
new file mode 100644
index 0000000..221868f
--- /dev/null
+++ b/cmake/FindLEX.cmake
@@ -0,0 +1,129 @@
+# - Find lex executable and provides a macro to generate custom build rules
+#
+# The module defines the following variables:
+# LEX_FOUND - true is lex executable is found
+# LEX_EXECUTABLE - the path to the lex executable
+# LEX_LIBRARIES - The lex libraries
+# LEX_INCLUDE_DIRS - The path to the lex headers
+#
+#
+# If lex is found on the system, the module provides the macro:
+# LEX_TARGET(Name LexInput LexOutput [COMPILE_FLAGS <string>])
+# which creates a custom command to generate the <LexOutput> file from
+# the <LexInput> file. If COMPILE_FLAGS option is specified, the next
+# parameter is added to the lex command line. Name is an alias used to
+# get details of this custom command. Indeed the macro defines the
+# following variables:
+# LEX_${Name}_DEFINED - true is the macro ran successfully
+# LEX_${Name}_OUTPUTS - the source file generated by the custom rule, an
+# alias for LexOutput
+# LEX_${Name}_INPUT - the lex source file, an alias for ${LexInput}
+#
+# Lex scanners oftenly use tokens defined by Yacc: the code generated
+# by Lex depends of the header generated by Yacc. This module also
+# defines a macro:
+# ADD_LEX_YACC_DEPENDENCY(LexTarget YaccTarget)
+# which adds the required dependency between a scanner and a parser
+# where <LexTarget> and <YaccTarget> are the first parameters of
+# respectively LEX_TARGET and YACC_TARGET macros.
+#
+# ====================================================================
+
+#=============================================================================
+# Copyright 2009 Kitware, Inc.
+# Copyright 2006 Tristan Carel
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+
+# This file is based on the FindFLEX CMake macro, and adapted by ECMWF
+
+#=============================================================================
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+FIND_PROGRAM(LEX_EXECUTABLE lex DOC "path to the lex executable")
+MARK_AS_ADVANCED(LEX_EXECUTABLE)
+
+FIND_LIBRARY(FL_LIBRARY NAMES fl
+ DOC "Path to the fl library")
+
+FIND_PATH(LEX_INCLUDE_DIR LexLexer.h
+ DOC "Path to the lex headers")
+
+MARK_AS_ADVANCED(FL_LIBRARY LEX_INCLUDE_DIR)
+
+SET(LEX_INCLUDE_DIRS ${LEX_INCLUDE_DIR})
+SET(LEX_LIBRARIES ${FL_LIBRARY})
+
+IF(LEX_EXECUTABLE)
+
+ #============================================================
+ # LEX_TARGET (public macro)
+ #============================================================
+ #
+ MACRO(LEX_TARGET Name Input Output)
+ SET(LEX_TARGET_usage "LEX_TARGET(<Name> <Input> <Output> [COMPILE_FLAGS <string>]")
+ IF(${ARGC} GREATER 3)
+ IF(${ARGC} EQUAL 5)
+ IF("${ARGV3}" STREQUAL "COMPILE_FLAGS")
+ SET(LEX_EXECUTABLE_opts "${ARGV4}")
+ SEPARATE_ARGUMENTS(LEX_EXECUTABLE_opts)
+ ELSE()
+ MESSAGE(SEND_ERROR ${LEX_TARGET_usage})
+ ENDIF()
+ ELSE()
+ MESSAGE(SEND_ERROR ${LEX_TARGET_usage})
+ ENDIF()
+ ENDIF()
+
+ message( STATUS "${LEX_EXECUTABLE} ${LEX_EXECUTABLE_opts} -t ${Input} > ${Output}" )
+
+ ADD_CUSTOM_COMMAND(OUTPUT ${Output}
+ COMMAND ${LEX_EXECUTABLE} ${LEX_EXECUTABLE_opts} -t ${Input} > ${Output}
+ DEPENDS ${Input}
+ COMMENT "[LEX][${Name}] Building scanner with lex ${LEX_VERSION}"
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
+
+ SET(LEX_${Name}_DEFINED TRUE)
+ SET(LEX_${Name}_OUTPUTS ${Output})
+ SET(LEX_${Name}_INPUT ${Input})
+ SET(LEX_${Name}_COMPILE_FLAGS ${LEX_EXECUTABLE_opts})
+ ENDMACRO(LEX_TARGET)
+ #============================================================
+
+
+ #============================================================
+ # ADD_LEX_YACC_DEPENDENCY (public macro)
+ #============================================================
+ #
+ MACRO(ADD_LEX_YACC_DEPENDENCY LexTarget YaccTarget)
+
+ IF(NOT LEX_${LexTarget}_OUTPUTS)
+ MESSAGE(SEND_ERROR "Lex target `${LexTarget}' does not exists.")
+ ENDIF()
+
+ IF(NOT YACC_${YaccTarget}_OUTPUT_HEADER)
+ MESSAGE(SEND_ERROR "Yacc target `${YaccTarget}' does not exists.")
+ ENDIF()
+
+ SET_SOURCE_FILES_PROPERTIES(${LEX_${LexTarget}_OUTPUTS}
+ PROPERTIES OBJECT_DEPENDS ${YACC_${YaccTarget}_OUTPUT_HEADER})
+ ENDMACRO(ADD_LEX_YACC_DEPENDENCY)
+ #============================================================
+
+ENDIF(LEX_EXECUTABLE)
+
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LEX REQUIRED_VARS LEX_EXECUTABLE)
+
+# FindLEX.cmake ends here
diff --git a/cmake/FindLibGFortran.cmake b/cmake/FindLibGFortran.cmake
new file mode 100644
index 0000000..a293ea5
--- /dev/null
+++ b/cmake/FindLibGFortran.cmake
@@ -0,0 +1,53 @@
+# © Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+###############################################################################
+# gfortran libs
+
+set( __libgfortran_names gfortran libgfortran.so.1 libgfortran.so.3 )
+
+# use gfortran to find the library
+
+find_program( GFORTRAN_EXECUTABLE gfortran )
+
+if( GFORTRAN_EXECUTABLE )
+
+ execute_process(COMMAND ${GFORTRAN_EXECUTABLE} "-print-search-dirs"
+ RESULT_VARIABLE _GFORTRAN_SEARCH_SUCCESS
+ OUTPUT_VARIABLE _GFORTRAN_VALUES_OUTPUT
+ ERROR_VARIABLE _GFORTRAN_ERROR_VALUE
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+# ecbuild_debug_var(_GFORTRAN_SEARCH_SUCCESS)
+# ecbuild_debug_var(_GFORTRAN_VALUES_OUTPUT)
+# ecbuild_debug_var(_GFORTRAN_ERROR_VALUE)
+
+ if(_GFORTRAN_SEARCH_SUCCESS MATCHES 0)
+ string(REGEX REPLACE ".*libraries: =(.*)" "\\1" _result ${_GFORTRAN_VALUES_OUTPUT})
+ string(REGEX REPLACE ":" ";" _gfortran_hints ${_result} )
+ endif()
+
+ ecbuild_debug_var( _gfortran_hints )
+
+endif()
+
+find_library( GFORTRAN_LIB NAMES ${__libgfortran_names} HINTS ${LIBGFORTRAN_PATH} ENV LIBGFORTRAN_PATH PATHS PATH_SUFFIXES lib64 lib NO_DEFAULT_PATH )
+find_library( GFORTRAN_LIB NAMES ${__libgfortran_names} HINTS ${_gfortran_hints} PATHS PATH_SUFFIXES lib64 lib )
+
+mark_as_advanced( GFORTRAN_LIB )
+
+if( GFORTRAN_LIB )
+ set( GFORTRAN_LIBRARIES ${GFORTRAN_LIB} )
+endif()
+
+include(FindPackageHandleStandardArgs)
+
+# Handle the QUIET and REQUIRED arguments and set LIBGFORTRAN_FOUND to TRUE
+# if all listed variables are TRUE
+# Note: capitalisation of the package name must be the same as in the file name
+find_package_handle_standard_args( LibGFortran DEFAULT_MSG GFORTRAN_LIBRARIES )
diff --git a/cmake/FindLibIFort.cmake b/cmake/FindLibIFort.cmake
new file mode 100644
index 0000000..da782a4
--- /dev/null
+++ b/cmake/FindLibIFort.cmake
@@ -0,0 +1,50 @@
+# © Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+# date: July 2015
+# author: Florian Rathgeber
+
+###############################################################################
+
+# - Try to find Intel Fortran (ifort) runtime libraries libifcore and libifport
+# Once done this will define
+#
+# LIBIFORT_FOUND - system has Intel Fortran (ifort) runtime libraries
+# IFORT_LIBRARIES - the Intel Fortran (ifort) runtime libraries
+#
+# The following paths will be searched with priority if set in CMake or env
+#
+# INTEL_PATH - prefix path of the Intel installation
+#
+# Otherwise the libraries are assumed to be on LIBRARY_PATH or LD_LIBRARY_PATH
+
+# FIXME: might need to add further libraries in future, see
+# http://nf.nci.org.au/facilities/software/Compilers/Intel8/doc/f_ug1/files_32.htm
+
+# Search with priority for INTEL_PATH if given as CMake or env var
+find_library( IFORT_LIB_CORE ifcore PATHS ${INTEL_PATH} ENV INTEL_PATH
+ PATH_SUFFIXES lib/intel64 compiler/lib/intel64 NO_DEFAULT_PATH )
+find_library( IFORT_LIB_PORT ifport PATHS ${INTEL_PATH} ENV INTEL_PATH
+ PATH_SUFFIXES lib/intel64 compiler/lib/intel64 NO_DEFAULT_PATH )
+
+# Otherwise, search LIBRARY_PATH and LD_LIBRARY_PATH
+find_library( IFORT_LIB_CORE ifcore PATHS ENV LIBRARY_PATH LD_LIBRARY_PATH )
+find_library( IFORT_LIB_PORT ifport PATHS ENV LIBRARY_PATH LD_LIBRARY_PATH )
+
+mark_as_advanced( IFORT_LIB_CORE IFORT_LIB_PORT )
+
+if( IFORT_LIB_CORE AND IFORT_LIB_PORT )
+ set( IFORT_LIBRARIES ${IFORT_LIB_CORE} ${IFORT_LIB_PORT} )
+endif()
+
+include(FindPackageHandleStandardArgs)
+
+# Handle the QUIET and REQUIRED arguments and set LIBIFORT_FOUND to TRUE
+# if all listed variables are TRUE
+# Note: capitalisation of the package name must be the same as in the file name
+find_package_handle_standard_args( LibIFort DEFAULT_MSG IFORT_LIBRARIES )
diff --git a/cmake/FindMKL.cmake b/cmake/FindMKL.cmake
new file mode 100644
index 0000000..1123234
--- /dev/null
+++ b/cmake/FindMKL.cmake
@@ -0,0 +1,77 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+# - Try to find MKL
+# Once done this will define
+#
+# MKL_FOUND - system has Intel MKL
+# MKL_INCLUDE_DIRS - the MKL include directories
+# MKL_LIBRARIES - link these to use MKL
+#
+# The following paths will be searched with priority if set in CMake or env
+#
+# MKL_PATH - root directory of the MKL installation
+# MKL_ROOT - root directory of the MKL installation
+
+option( MKL_PARALLEL "if mkl shoudl be parallel" OFF )
+
+if( MKL_PARALLEL )
+
+ set( __mkl_lib_par MKL_LIB_INTEL_THREAD )
+ set( __mkl_lib_name mkl_intel_thread )
+
+ find_package(Threads)
+
+else()
+
+ set( __mkl_lib_par MKL_LIB_SEQUENTIAL )
+ set( __mkl_lib_name mkl_sequential )
+
+endif()
+
+# Search with priority for MKL_ROOT and MKL_PATH if set in CMake or env
+find_path(MKL_INCLUDE_DIR mkl.h
+ PATHS ${MKL_PATH} ${MKL_ROOT} ENV MKL_PATH MKL_ROOT
+ PATH_SUFFIXES include NO_DEFAULT_PATH)
+find_path(MKL_INCLUDE_DIR mkl.h
+ PATH_SUFFIXES include)
+
+if( MKL_INCLUDE_DIR ) # use include dir to find libs
+
+ set( MKL_INCLUDE_DIRS ${MKL_INCLUDE_DIR} )
+
+ if( CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" )
+ get_filename_component( MKL_LIB_PATH ${MKL_INCLUDE_DIR}/../lib/intel64 ABSOLUTE )
+ set( __libsfx _lp64 )
+ else()
+ get_filename_component( MKL_LIB_PATH ${MKL_INCLUDE_DIR}/../lib/ia32 ABSOLUTE )
+ set( __libsfx "" )
+ endif()
+
+ message( STATUS "ICC_LIB_PATH ${ICC_LIB_PATH}" )
+
+ find_library( MKL_LIB_INTEL NAMES mkl_intel${__libsfx} PATHS ${MKL_LIB_PATH} )
+ find_library( ${__mkl_lib_par} NAMES ${__mkl_lib_name} PATHS ${MKL_LIB_PATH} )
+ find_library( MKL_LIB_CORE NAMES mkl_core PATHS ${MKL_LIB_PATH} )
+
+ if( MKL_PARALLEL )
+ find_library( MKL_LIB_IOMP5 NAMES iomp5 PATHS ${MKL_LIB_PATH} )
+ endif()
+
+ if( MKL_LIB_INTEL AND ${__mkl_lib_par} AND MKL_LIB_CORE )
+ set( MKL_LIBRARIES ${MKL_LIB_INTEL} ${${__mkl_lib_par}} ${MKL_LIB_CORE} ${MKL_LIB_IOMP5} ${CMAKE_THREAD_LIBS_INIT} )
+ endif()
+
+endif()
+
+include(FindPackageHandleStandardArgs)
+
+find_package_handle_standard_args( MKL DEFAULT_MSG
+ MKL_LIBRARIES MKL_INCLUDE_DIRS )
+
+mark_as_advanced( MKL_INCLUDE_DIR MKL_LIB_LAPACK MKL_LIB_INTEL MKL_LIB_SEQUENTIAL MKL_LIB_CORE )
diff --git a/cmake/FindNDBM.cmake b/cmake/FindNDBM.cmake
new file mode 100644
index 0000000..869223f
--- /dev/null
+++ b/cmake/FindNDBM.cmake
@@ -0,0 +1,34 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+# - Try to find NetCDF
+# Once done this will define
+# NDBM_FOUND - System has NetCDF
+# NDBM_INCLUDE_DIRS - The NetCDF include directories
+# NDBM_LIBRARIES - The libraries needed to use NetCDF
+# NDBM_DEFINITIONS - Compiler switches required for using NetCDF
+
+if( DEFINED NDBM_PATH )
+ find_path(NDBM_INCLUDE_DIR NAMES ndbm.h PATHS ${NDBM_PATH} ${NDBM_PATH}/include PATH_SUFFIXES ndbm NO_DEFAULT_PATH)
+ find_library(NDBM_LIBRARY NAMES ndbm dbm PATHS ${NDBM_PATH} ${NDBM_PATH}/lib PATH_SUFFIXES ndbm NO_DEFAULT_PATH)
+endif()
+
+find_path(NDBM_INCLUDE_DIR NAMES ndbm.h PATH_SUFFIXES ndbm )
+find_library( NDBM_LIBRARY NAMES ndbm dbm PATH_SUFFIXES ndbm )
+
+set( NDBM_LIBRARIES ${NDBM_LIBRARY} )
+set( NDBM_INCLUDE_DIRS ${NDBM_INCLUDE_DIR} )
+
+include(FindPackageHandleStandardArgs)
+
+# handle the QUIETLY and REQUIRED arguments and set GRIBAPI_FOUND to TRUE
+# if all listed variables are TRUE
+find_package_handle_standard_args(NDBM DEFAULT_MSG
+ NDBM_LIBRARY NDBM_INCLUDE_DIR)
+
+mark_as_advanced(NDBM_INCLUDE_DIR NDBM_LIBRARY )
diff --git a/cmake/FindNetCDF.cmake b/cmake/FindNetCDF.cmake
new file mode 100644
index 0000000..9084549
--- /dev/null
+++ b/cmake/FindNetCDF.cmake
@@ -0,0 +1,164 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+# Try to find NetCDF3 or NetCDF4 -- default is 4
+#
+# find_package( NetCDF <version> COMPONENTS C CXX Fortran )
+#
+# Input:
+# * NETCDF_PATH - user defined path where to search for the library first
+# * NETCDF_DIR - user defined path where to search for the library first
+# * NETCDF_ROOT - user defined path where to search for the library first
+#
+# Output:
+# NETCDF_FOUND - System has NetCDF
+# NETCDF_DEFINITIONS
+# NETCDF_INCLUDE_DIRS - The NetCDF include directories
+# NETCDF_LIBRARIES - The libraries needed to use NetCDF
+
+# default is netcdf4
+if( NetCDF_FIND_VERSION STREQUAL "3" )
+ set( PREFER_NETCDF3 1 )
+endif()
+
+if( NOT PREFER_NETCDF3 )
+ set( PREFER_NETCDF4 1 )
+else()
+ set( PREFER_NETCDF4 0 )
+endif()
+mark_as_advanced( PREFER_NETCDF4 PREFER_NETCDF3 )
+
+set( NETCDF_FIND_REQUIRED ${NetCDF_FIND_REQUIRED} )
+set( NETCDF_FIND_QUIETLY ${NetCDF_FIND_QUIETLY} )
+set( NETCDF_FIND_COMPONENTS ${NetCDF_FIND_COMPONENTS} )
+
+list( APPEND NETCDF_FIND_COMPONENTS C )
+
+if( NETCDF_CXX )
+ ecbuild_debug( "FindNetCDF: also looking for C++ libraries" )
+ list( APPEND NETCDF_FIND_COMPONENTS CXX )
+endif()
+
+if( NETCDF_Fortran OR NETCDF_FORTRAN OR NETCDF_F90 )
+ ecbuild_debug( "FindNetCDF: also looking for Fortran libraries" )
+ list( APPEND NETCDF_FIND_COMPONENTS FORTRAN F90 )
+endif()
+
+list(FIND NETCDF_FIND_COMPONENTS "FORTRAN" _index)
+if(${_index} GREATER -1)
+ list( APPEND NETCDF_FIND_COMPONENTS F90 )
+endif()
+
+list (FIND NETCDF_FIND_COMPONENTS "F90" _index)
+if(${_index} GREATER -1)
+ list( APPEND NETCDF_FIND_COMPONENTS FORTRAN )
+endif()
+
+list(FIND NETCDF_FIND_COMPONENTS "Fortran" _index)
+if(${_index} GREATER -1)
+ list( REMOVE_ITEM NETCDF_FIND_COMPONENTS Fortran )
+ list( APPEND NETCDF_FIND_COMPONENTS FORTRAN F90 )
+endif()
+
+list( REMOVE_DUPLICATES NETCDF_FIND_COMPONENTS )
+ecbuild_debug( "FindNetCDF: looking for components ${NETCDF_FIND_COMPONENTS}" )
+
+### NetCDF4
+
+if( PREFER_NETCDF4 )
+
+ ecbuild_debug( "FindNetCDF: looking for NetCDF4" )
+
+ ## hdf5
+
+ # Note: Only the HDF5 C-library is required for NetCDF
+ # ( even for Fortan and CXX bindings)
+ find_package( HDF5 COMPONENTS C QUIET )
+
+ ## netcdf4
+
+ # CONFIGURE the NETCDF_FIND_COMPONENTS variable
+
+ # Find NetCDF4
+
+ # message( "NETCDF CMAKE_PREFIX_PATH = [${CMAKE_PREFIX_PATH}]")
+ # ecbuild_debug_var( NETCDF_ROOT )
+ # ecbuild_debug_var( NETCDF_FIND_COMPONENTS )
+ # ecbuild_debug_var( NETCDF_FIND_QUIETLY )
+ # ecbuild_debug_var( NETCDF_FIND_REQUIRED )
+ find_package( NetCDF4 COMPONENTS ${NETCDF_FIND_COMPONENTS} )
+ # ecbuild_debug_var( NETCDF4_FOUND )
+ # ecbuild_debug_var( NETCDF_FOUND )
+ # ecbuild_debug_var( NETCDF_LIBRARIES )
+ # ecbuild_debug_var( NETCDF_INCLUDE_DIRS )
+
+ list( APPEND NETCDF_Fortran_LIBRARIES ${NETCDF_FORTRAN_LIBRARIES} ${NETCDF_F90_LIBRARIES} )
+ if( NETCDF_Fortran_LIBRARIES )
+ list( REMOVE_DUPLICATES NETCDF_Fortran_LIBRARIES )
+ endif()
+
+ # ecbuild_debug_var( NETCDF_Fortran_LIBRARIES )
+ # ecbuild_debug_var( NETCDF_C_LIBRARIES )
+ # ecbuild_debug_var( NETCDF_CXX_LIBRARIES )
+
+
+ set_package_properties( NetCDF4 PROPERTIES TYPE RECOMMENDED PURPOSE "support for NetCDF4 file format" )
+
+ if( NETCDF_FOUND AND HDF5_FOUND )
+ # list( APPEND NETCDF_DEFINITIONS ${HDF5_DEFINITIONS} )
+ list( APPEND NETCDF_LIBRARIES ${HDF5_HL_LIBRARIES} ${HDF5_LIBRARIES} )
+ list( APPEND NETCDF_INCLUDE_DIRS ${HDF5_INCLUDE_DIRS} )
+ endif()
+
+ #ecbuild_debug_var( NETCDF_FOUND )
+ #ecbuild_debug_var( NETCDF_LIBRARIES )
+ #ecbuild_debug_var( NETCDF_INCLUDE_DIRS )
+ #ecbuild_debug_var( HDF5_FOUND )
+ #ecbuild_debug_var( HDF5_INCLUDE_DIRS )
+ #ecbuild_debug_var( HDF5_HL_LIBRARIES )
+ #ecbuild_debug_var( HDF5_LIBRARIES )
+
+endif()
+
+### NetCDF3
+
+if( PREFER_NETCDF3 )
+
+ ecbuild_debug( "FindNetCDF: looking for NetCDF3" )
+
+ # ecbuild_debug_var( NetCDF_FIND_COMPONENTS )
+ # ecbuild_debug_var( NetCDF_FIND_QUIETLY )
+ # ecbuild_debug_var( NetCDF_FIND_REQUIRED )
+
+ list(FIND NetCDF_FIND_COMPONENTS "CXX" _index)
+ if(${_index} GREATER -1)
+ set( NETCDF_CXX 1 )
+ endif()
+
+ list(FIND NetCDF_FIND_COMPONENTS "Fortran" _index)
+ if(${_index} GREATER -1)
+ set( NETCDF_Fortran 1 )
+ endif()
+
+ list(FIND NetCDF_FIND_COMPONENTS "FORTRAN" _index)
+ if(${_index} GREATER -1)
+ set( NETCDF_Fortran 1 )
+ endif()
+
+ list(FIND NetCDF_FIND_COMPONENTS "F90" _index)
+ if(${_index} GREATER -1)
+ set( NETCDF_Fortran 1 )
+ endif()
+
+ #message( "NETCDF CMAKE_PREFIX_PATH = ${CMAKE_PREFIX_PATH}" )
+
+ find_package( NetCDF3 COMPONENTS ${NETCDF_FIND_COMPONENTS} )
+
+ set_package_properties( NetCDF3 PROPERTIES TYPE RECOMMENDED PURPOSE "support for NetCDF3 file format" )
+
+endif()
diff --git a/cmake/FindNetCDF3.cmake b/cmake/FindNetCDF3.cmake
new file mode 100644
index 0000000..5519fd6
--- /dev/null
+++ b/cmake/FindNetCDF3.cmake
@@ -0,0 +1,113 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+# Try to find NetCDF
+#
+# Input:
+# * NETCDF_PATH - user defined path where to search for the library first
+# (CMake or environment variable)
+# * NETCDF_DIR - user defined path where to search for the library first
+# (CMake or environment variable)
+# * NETCDF_CXX - search also for netcdf_c++ wrapper library
+# * NETCDF_Fortran - search also for netcdff wrapper library
+#
+# Output:
+# NETCDF_FOUND - System has NetCDF
+# NETCDF_INCLUDE_DIRS - The NetCDF include directories
+# NETCDF_LIBRARIES - The libraries needed to use NetCDF
+
+### TODO: generalize this into a macro for all ecbuild
+
+if( DEFINED NETCDF_PATH )
+ list( APPEND _netcdf_incs ${NETCDF_PATH} ${NETCDF_PATH}/include )
+ list( APPEND _netcdf_libs ${NETCDF_PATH} ${NETCDF_PATH}/lib )
+endif()
+
+if( DEFINED NETCDF_DIR )
+ list( APPEND _netcdf_incs ${NETCDF_DIR} ${NETCDF_DIR}/include )
+ list( APPEND _netcdf_libs ${NETCDF_DIR} ${NETCDF_DIR}/lib )
+endif()
+
+# Honour environment variables NETCDF_DIR, NETCDF_PATH
+list( APPEND _netcdf_incs ENV NETCDF_DIR ENV NETCDF_PATH )
+list( APPEND _netcdf_libs ENV NETCDF_DIR ENV NETCDF_PATH )
+
+###
+
+set( _inc_sfx netcdf include )
+set( _lib_sfx netcdf lib64 lib )
+
+find_path( NETCDF_INCLUDE_DIR netcdf.h PATHS ${_netcdf_incs} PATH_SUFFIXES ${_inc_sfx} NO_DEFAULT_PATH )
+find_path( NETCDF_INCLUDE_DIR netcdf.h PATHS ${_netcdf_incs} PATH_SUFFIXES ${_inc_sfx} )
+
+find_library( NETCDF_LIBRARY netcdf PATHS ${_netcdf_libs} PATH_SUFFIXES ${_lib_sfx} NO_DEFAULT_PATH )
+find_library( NETCDF_LIBRARY netcdf PATHS ${_netcdf_libs} PATH_SUFFIXES ${_lib_sfx} )
+
+set( NETCDF_LIBRARIES ${NETCDF_LIBRARY} )
+set( NETCDF_INCLUDE_DIRS ${NETCDF_INCLUDE_DIR} )
+
+mark_as_advanced(NETCDF_INCLUDE_DIR NETCDF_LIBRARY )
+
+list( APPEND NETCDF_REQUIRED_VARS NETCDF_LIBRARY NETCDF_INCLUDE_DIR )
+
+if( NETCDF_CXX )
+
+ find_path( NETCDF_CXX_INCLUDE_DIR netcdfcpp.h PATHS ${_netcdf_incs} PATH_SUFFIXES ${_inc_sfx} NO_DEFAULT_PATH)
+ find_path( NETCDF_CXX_INCLUDE_DIR netcdfcpp.h PATHS ${_netcdf_incs} PATH_SUFFIXES ${_inc_sfx} )
+
+ set( _ncdf_cxx netcdf_c++ netcdf_c++ netcdf_c++4 )
+
+ find_library( NETCDF_CXX_LIBRARY NAMES ${_ncdf_cxx} PATHS ${_netcdf_libs} PATH_SUFFIXES ${_lib_sfx} NO_DEFAULT_PATH )
+ find_library( NETCDF_CXX_LIBRARY NAMES ${_ncdf_cxx} PATHS ${_netcdf_libs} PATH_SUFFIXES ${_lib_sfx} )
+
+ list( APPEND NETCDF_INCLUDE_DIRS ${NETCDF_CXX_INCLUDE_DIR} )
+ list( APPEND NETCDF_LIBRARIES ${NETCDF_CXX_LIBRARY} )
+
+ list( APPEND NETCDF_REQUIRED_VARS NETCDF_CXX_INCLUDE_DIR NETCDF_CXX_LIBRARY )
+
+ mark_as_advanced(NETCDF_CXX_INCLUDE_DIR NETCDF_CXX_LIBRARY )
+
+endif()
+
+if( NETCDF_Fortran )
+
+ find_path( NETCDF_Fortran_INCLUDE_DIR netcdf.mod PATHS ${_netcdf_incs} PATH_SUFFIXES ${_inc_sfx} NO_DEFAULT_PATH)
+ find_path( NETCDF_Fortran_INCLUDE_DIR netcdf.mod PATHS ${_netcdf_incs} PATH_SUFFIXES ${_inc_sfx} )
+
+ set( _ncdf_fortran netcdff )
+
+ find_library( NETCDF_Fortran_LIBRARY NAMES ${_ncdf_fortran} PATHS ${_netcdf_libs} PATH_SUFFIXES ${_lib_sfx} NO_DEFAULT_PATH )
+ find_library( NETCDF_Fortran_LIBRARY NAMES ${_ncdf_fortran} PATHS ${_netcdf_libs} PATH_SUFFIXES ${_lib_sfx} )
+
+ list( APPEND NETCDF_INCLUDE_DIRS ${NETCDF_Fortran_INCLUDE_DIR} )
+ list( APPEND NETCDF_LIBRARIES ${NETCDF_Fortran_LIBRARY} )
+
+ list( APPEND NETCDF_REQUIRED_VARS NETCDF_Fortran_INCLUDE_DIR NETCDF_Fortran_LIBRARY )
+
+ mark_as_advanced(NETCDF_Fortran_INCLUDE_DIR NETCDF_Fortran_LIBRARY )
+
+endif()
+
+list( REMOVE_DUPLICATES NETCDF_INCLUDE_DIRS )
+
+include(FindPackageHandleStandardArgs)
+
+if( NETCDF_FIND_QUIETLY )
+ set( NETCDF3_FIND_QUIETLY ${NETCDF_FIND_QUIETLY} )
+endif()
+if( NETCDF_FIND_REQUIRED )
+ set( NETCDF3_FIND_REQUIRED ${NETCDF_FIND_REQUIRED} )
+endif()
+
+# Handle the QUIET and REQUIRED arguments and set NETCDF3_FOUND to TRUE
+# if all listed variables are TRUE
+# Note: capitalisation of the package name must be the same as in the file name
+find_package_handle_standard_args( NetCDF3 DEFAULT_MSG ${NETCDF_REQUIRED_VARS} )
+
+set( NETCDF_FOUND ${NETCDF3_FOUND} )
+
diff --git a/cmake/FindODB.cmake b/cmake/FindODB.cmake
new file mode 100644
index 0000000..1beb5c8
--- /dev/null
+++ b/cmake/FindODB.cmake
@@ -0,0 +1,53 @@
+# © Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+# - Try to find ODB
+# Once done this will define
+# ODB_FOUND - System has ODB
+# ODB_INCLUDE_DIRS - The ODB include directories
+# ODB_LIBRARIES - The libraries needed to use ODB
+
+# /usr/local/apps/odb/CY37R3.001/pgf90/LP64/include/odbdump.h
+# /usr/local/apps/odb/CY37R3.001/pgf90/LP64/module/odb.mod
+
+# -lodb -lodbec -lifsaux -lmpi_serial -lodbdummy
+
+find_package( Dl ) # find the dynamic linker
+
+list( APPEND _odb_search_libs odb odbec ifsaux mpi_serial odbdummy )
+
+if( DEFINED ODB_PATH )
+ find_path(ODB_INCLUDE_DIR odbdump.h PATHS ${ODB_ROOT} ${ODB_ROOT}/include ${ODB_PATH} ${ODB_PATH}/include PATH_SUFFIXES odb NO_DEFAULT_PATH)
+ find_path(ODB_MODULE_DIR odb.mod PATHS ${ODB_ROOT} ${ODB_ROOT}/module ${ODB_PATH} ${ODB_PATH}/module PATH_SUFFIXES odb NO_DEFAULT_PATH)
+ foreach( _lib ${_odb_search_libs} )
+ find_library(ODB_LIBRARY_${_lib} ${_lib} PATHS ${ODB_ROOT} ${ODB_ROOT}/lib ${ODB_PATH} ${ODB_PATH}/lib PATH_SUFFIXES odb NO_DEFAULT_PATH)
+ endforeach()
+endif()
+
+find_path(ODB_INCLUDE_DIR odbdump.h PATH_SUFFIXES odb )
+find_path(ODB_MODULE_DIR odb.mod PATH_SUFFIXES odb )
+foreach( _lib ${_odb_search_libs} )
+ find_library( ODB_LIBRARY_${_lib} ${_lib} PATH_SUFFIXES odb )
+endforeach()
+
+foreach( _lib ${_odb_search_libs} )
+ list( APPEND ODB_LIB_LIST ODB_LIBRARY_${_lib} )
+ list( APPEND ODB_LIBRARIES ${ODB_LIBRARY_${_lib}} )
+ mark_as_advanced(${ODB_LIBRARY_${_lib}})
+endforeach()
+
+set( ODB_INCLUDE_DIRS ${ODB_INCLUDE_DIR} ${ODB_MODULE_DIR})
+mark_as_advanced(ODB_INCLUDE_DIR )
+
+include(FindPackageHandleStandardArgs)
+
+# handle the QUIETLY and REQUIRED arguments and set GRIBAPI_FOUND to TRUE
+# if all listed variables are TRUE
+find_package_handle_standard_args(ODB DEFAULT_MSG
+ ODB_INCLUDE_DIR ${ODB_LIB_LIST} )
+
diff --git a/cmake/FindOpenCL.cmake b/cmake/FindOpenCL.cmake
new file mode 100644
index 0000000..9b6e978
--- /dev/null
+++ b/cmake/FindOpenCL.cmake
@@ -0,0 +1,70 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+# - Try to find OpenCL
+# Once done this will define
+#
+# OPENCL_FOUND - system has OpenCL
+# OPENCL_INCLUDE_DIRS - the OpenCL include directory
+# OPENCL_LIBRARIES - link these to use OpenCL
+#
+# The following paths will be searched with priority if set in CMake or env
+#
+# OPENCL_ROOT - root folder of the OpenCL installation
+# CUDA_TOOLKIT_ROOT_DIR - root folder of the CUDA installation (ships OpenCL)
+# CUDA_ROOT - root folder of the CUDA installation (ships OpenCL)
+
+if(UNIX)
+
+ if(APPLE)
+
+ # Search with priority for OPENCL_ROOT if given as CMake or env var
+ find_path(OPENCL_INCLUDE_DIRS OpenCL/cl.h
+ PATHS ${OPENCL_ROOT} ENV OPENCL_ROOT
+ PATH_SUFFIXES include NO_DEFAULT_PATH)
+ find_path(OPENCL_INCLUDE_DIRS OpenCL/cl.h
+ PATH_SUFFIXES include )
+
+ # Search with priority for OPENCL_ROOT if given as CMake or env var
+ find_library(OPENCL_LIBRARIES OpenCL
+ PATHS ${OPENCL_ROOT} ENV OPENCL_ROOT
+ PATH_SUFFIXES lib NO_DEFAULT_PATH)
+ find_library(OPENCL_LIBRARIES OpenCL
+ PATH_SUFFIXES lib )
+
+ else()
+
+ # Search with priority for OPENCL_ROOT if given as CMake or env var
+ find_path(OPENCL_INCLUDE_DIRS NAMES CL/cl.h CL/opencl.h
+ PATHS ${OPENCL_ROOT} ENV OPENCL_ROOT
+ PATH_SUFFIXES include NO_DEFAULT_PATH)
+ find_path(OPENCL_INCLUDE_DIRS NAMES CL/cl.h CL/opencl.h
+ PATHS ${CUDA_TOOLKIT_ROOT_DIR} ${CUDA_ROOT} /usr/local/cuda
+ PATH_SUFFIXES include )
+
+ # Search with priority for OPENCL_ROOT if given as CMake or env var
+ find_library(OPENCL_LIBRARIES OpenCL
+ PATHS ${OPENCL_ROOT} ENV OPENCL_ROOT
+ PATH_SUFFIXES lib64 lib NO_DEFAULT_PATH)
+ find_library(OPENCL_LIBRARIES OpenCL
+ PATHS ${CUDA_TOOLKIT_ROOT_DIR} ${CUDA_ROOT} /usr/local/cuda
+ PATH_SUFFIXES lib64 lib )
+
+ endif()
+
+endif()
+
+include(FindPackageHandleStandardArgs)
+
+# Handle the QUIET and REQUIRED arguments and set OPENCL_FOUND to TRUE
+# if all listed variables are TRUE
+# Note: capitalisation of the package name must be the same as in the file name
+find_package_handle_standard_args( OpenCL DEFAULT_MSG
+ OPENCL_LIBRARIES OPENCL_INCLUDE_DIRS )
+
+mark_as_advanced( OPENCL_INCLUDE_DIRS OPENCL_LIBRARIES )
diff --git a/cmake/FindOpenJPEG.cmake b/cmake/FindOpenJPEG.cmake
new file mode 100644
index 0000000..805f091
--- /dev/null
+++ b/cmake/FindOpenJPEG.cmake
@@ -0,0 +1,42 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+# - Try to find the OpenJPEG includes and library
+# This module defines
+# OPENJPEG_FOUND - System has OpenJPEG
+# OPENJPEG_INCLUDE_DIRS - the OpenJPEG include directories
+# OPENJPEG_LIBRARIES - the libraries needed to use OpenJPEG
+#
+# also defined internally:
+# OPENJPEG_LIBRARY, where to find the OpenJPEG library.
+# OPENJPEG_INCLUDE_DIR, where to find the openjpeg.h header
+
+IF( NOT DEFINED OPENJPEG_PATH AND NOT "$ENV{OPENJPEG_PATH}" STREQUAL "" )
+ SET( OPENJPEG_PATH "$ENV{OPENJPEG_PATH}" )
+ENDIF()
+
+# TODO: This only works for OpenJPEG v1.x.y and not for v2 which has a different API, library name etc
+if( DEFINED OPENJPEG_PATH )
+ find_path(OPENJPEG_INCLUDE_DIR openjpeg.h PATHS ${OPENJPEG_PATH}/include PATH_SUFFIXES openjpeg NO_DEFAULT_PATH)
+ find_library(OPENJPEG_LIBRARY openjpeg PATHS ${OPENJPEG_PATH}/lib PATH_SUFFIXES openjpeg NO_DEFAULT_PATH)
+endif()
+
+find_path(OPENJPEG_INCLUDE_DIR openjpeg.h PATH_SUFFIXES openjpeg )
+find_library( OPENJPEG_LIBRARY openjpeg PATH_SUFFIXES openjpeg )
+
+set( OPENJPEG_LIBRARIES ${OPENJPEG_LIBRARY} )
+set( OPENJPEG_INCLUDE_DIRS ${OPENJPEG_INCLUDE_DIR} )
+
+include(FindPackageHandleStandardArgs)
+
+# handle the QUIETLY and REQUIRED arguments and set OPENJPEG_FOUND to TRUE
+# if all listed variables are TRUE
+find_package_handle_standard_args(OpenJPEG DEFAULT_MSG
+ OPENJPEG_LIBRARY OPENJPEG_INCLUDE_DIR)
+
+mark_as_advanced(OPENJPEG_INCLUDE_DIR OPENJPEG_LIBRARY )
diff --git a/cmake/FindPGIFortran.cmake b/cmake/FindPGIFortran.cmake
new file mode 100644
index 0000000..e68bdf6
--- /dev/null
+++ b/cmake/FindPGIFortran.cmake
@@ -0,0 +1,49 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+###############################################################################
+# FORTRAN support
+
+# set( PGIFORTRAN_SEARCH_LIBS pgmp pgbind numa pgf90 pgf90_rpm1 pgf902 pgf90rtl pgftnrtl nspgc pgc rt pgsse1 pgsse2 ) # init
+# set( PGIFORTRAN_SEARCH_LIBS pgf90 pgf90_rpm1 pgf902 pgf90rtl pgftnrtl pghpf pgc pgf90 rt pgsse1 pgsse2 ) # mars client linux.2
+# set( PGIFORTRAN_SEARCH_LIBS pgftnrtl nspgc pgc rt pgsse1 pgsse2 ) # mars client linux.3
+
+if( NOT DEFINED PGIFORTRAN_SEARCH_LIBS )
+ set( PGIFORTRAN_SEARCH_LIBS pgmp pgbind numa pgf90 pgf90_rpm1 pgf902 pgf90rtl pgftnrtl pghpf nspgc pgc pgf90 pgf902 pghpf_rpm1 pghpf2 pgsse1 pgsse2 ) # better ? #
+endif()
+
+set( pgi_fortran_all_libs_found 1 )
+
+foreach( pglib ${PGIFORTRAN_SEARCH_LIBS} )
+
+ find_library( ${pglib}_lib ${pglib} PATHS ${PGI_PATH} PATH_SUFFIXES lib libso NO_DEFAULT_PATH )
+
+ find_library( ${pglib}_lib ${pglib} HINTS /usr/local/apps/pgi/pgi-10.8/linux86-64/10.8 PATH PATH_SUFFIXES lib libso )
+
+ if( ${pglib}_lib )
+ list( APPEND PGIFORTRAN_LIBRARIES ${${pglib}_lib} )
+# else()
+# set( pgi_fortran_all_libs_found 0 )
+ endif()
+
+endforeach()
+
+include(FindPackageHandleStandardArgs)
+
+# Handle the QUIET and REQUIRED arguments and set PGIFORTRAN_FOUND to TRUE
+# if all listed variables are TRUE
+# Note: capitalisation of the package name must be the same as in the file name
+find_package_handle_standard_args( PGIFortran DEFAULT_MSG pgi_fortran_all_libs_found PGIFORTRAN_LIBRARIES )
+
+if( PGIFORTRAN_FOUND )
+ find_package( Realtime )
+endif()
+
+if( REALTIME_FOUND )
+ set( PGIFORTRAN_LIBRARIES ${PGIFORTRAN_LIBRARIES} ${RT_LIB} )
+endif()
diff --git a/cmake/FindPango.cmake b/cmake/FindPango.cmake
new file mode 100644
index 0000000..76e152a
--- /dev/null
+++ b/cmake/FindPango.cmake
@@ -0,0 +1,33 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+# - Try to find Pango
+
+# Output:
+# PANGO_FOUND
+# PANGO_LIBRARIES
+# PANGO_INCLUDE_DIRS
+
+find_package(PkgConfig)
+
+pkg_check_modules(PC_LIBPANGO QUIET pango)
+
+ecbuild_debug_var( PC_LIBPANGO_FOUND )
+ecbuild_debug_var( PC_LIBPANGO_VERSION )
+ecbuild_debug_var( PC_LIBPANGO_LIBRARIES )
+ecbuild_debug_var( PC_LIBPANGO_INCLUDE_DIRS )
+
+include(FindPackageHandleStandardArgs)
+# Handle the QUIET and REQUIRED arguments and set PANGO_FOUND to TRUE
+# if all listed variables are TRUE
+# Note: capitalisation of the package name must be the same as in the file name
+find_package_handle_standard_args( Pango DEFAULT_MSG PC_LIBPANGO_LIBRARIES PC_LIBPANGO_INCLUDE_DIRS )
+
+set( PANGO_VERSION ${PC_LIBPANGO_VERSION} )
+set( PANGO_LIBRARIES ${PC_LIBPANGO_LIBRARIES} )
+set( PANGO_INCLUDE_DIRS ${PC_LIBPANGO_INCLUDE_DIRS} )
diff --git a/cmake/FindPangoCairo.cmake b/cmake/FindPangoCairo.cmake
new file mode 100644
index 0000000..9979550
--- /dev/null
+++ b/cmake/FindPangoCairo.cmake
@@ -0,0 +1,96 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+# - Try to find PangoCairo
+
+# Output:
+# PANGOCAIRO_FOUND
+# PANGOCAIRO_LIBRARIES
+# PANGOCAIRO_INCLUDE_DIRS
+
+
+find_package(PkgConfig)
+
+pkg_check_modules(PC_LIBPANGOCAIRO QUIET pangocairo)
+
+#ecbuild_debug_var( PC_LIBPANGOCAIRO_FOUND )
+#ecbuild_debug_var( PC_LIBPANGOCAIRO_VERSION )
+#ecbuild_debug_var( PC_LIBPANGOCAIRO_LIBRARIES )
+#ecbuild_debug_var( PC_LIBPANGOCAIRO_LDFLAGS )
+#ecbuild_debug_var( PC_LIBPANGOCAIRO_LDFLAGS_OTHER )
+#ecbuild_debug_var( PC_LIBPANGOCAIRO_INCLUDE_DIRS )
+
+if(PC_LIBPANGOCAIRO_FOUND)
+
+ include(FindPackageHandleStandardArgs)
+ # Handle the QUIET and REQUIRED arguments and set PANGOCAIRO_FOUND to TRUE
+ # if all listed variables are TRUE
+ # Note: capitalisation of the package name must be the same as in file name
+ find_package_handle_standard_args( PangoCairo DEFAULT_MSG PC_LIBPANGOCAIRO_LIBRARIES PC_LIBPANGOCAIRO_INCLUDE_DIRS )
+ set( PANGOCAIRO_VERSION ${PC_LIBPANGOCAIRO_VERSION} )
+ set( PANGOCAIRO_LIBRARIES "${PC_LIBPANGOCAIRO_LDFLAGS} ${PC_LIBPANGOCAIRO_LDFLAGS_OTHER}" )
+ set( PANGOCAIRO_INCLUDE_DIRS ${PC_LIBPANGOCAIRO_INCLUDE_DIRS} )
+
+else()
+
+ # this is to get magics compiling on mac with macbrew
+
+ include(FindPackageHandleStandardArgs)
+
+ set(PANGO_VERSION 1.0)
+ set(GLIB_VERSION 2.0)
+
+ find_path( _PANGOCAIRO_INCLUDE_DIRS
+ NAMES pango/pangocairo.h
+ HINTS /usr/local/include PATH_SUFFIXES pango-${PANGO_VERSION})
+
+ find_path( _CAIRO_INCLUDE_DIRS
+ NAMES cairo.h
+ HINTS /usr/local/include PATH_SUFFIXES cairo)
+
+ find_path( _GLIB_INCLUDE_DIRS_1
+ NAMES glib.h
+ HINTS /usr/local/include PATH_SUFFIXES glib-${GLIB_VERSION})
+
+ find_path( _GLIB_INCLUDE_DIRS_2
+ NAMES glibconfig.h
+ HINTS /usr/local/lib/glib-${GLIB_VERSION} PATH_SUFFIXES include)
+
+
+ find_package(X11)
+
+ set(PANGOCAIRO_INCLUDE_DIRS
+ ${_PANGOCAIRO_INCLUDE_DIRS}
+ ${_CAIRO_INCLUDE_DIRS}
+ ${_GLIB_INCLUDE_DIRS_1}
+ ${_GLIB_INCLUDE_DIRS_2}
+ ${X11_INCLUDE_DIR}
+ )
+
+ find_library( _PANGOCAIRO_LIBRARIES NAMES pangocairo pangocairo-${PANGO_VERSION})
+ find_library( _PANGO_LIBRARIES NAMES pango pango-${PANGO_VERSION})
+ find_library( _CAIRO_LIBRARIES NAMES cairo)
+ find_library( _GLIB_LIBRARIES NAMES glib-${GLIB_VERSION})
+
+ set(PANGOCAIRO_LIBRARIES
+ ${_PANGOCAIRO_LIBRARIES}
+ ${_PANGO_LIBRARIES}
+ ${_CAIRO_LIBRARIES}
+ ${_GLIB_LIBRARIES}
+ ${X11_LIBRARIES}
+ )
+
+ # Handle the QUIET and REQUIRED arguments and set PANGOCAIRO_FOUND to TRUE
+ # if all listed variables are TRUE
+ # Note: capitalisation of the package name must be the same as in file name
+ find_package_handle_standard_args( PangoCairo DEFAULT_MSG
+ PANGOCAIRO_LIBRARIES
+ PANGOCAIRO_INCLUDE_DIRS )
+
+endif()
+
diff --git a/cmake/FindProj4.cmake b/cmake/FindProj4.cmake
new file mode 100644
index 0000000..a3560b2
--- /dev/null
+++ b/cmake/FindProj4.cmake
@@ -0,0 +1,69 @@
+# - Try to find the proj4 library
+# Once done this will define
+#
+# PROJ4_FOUND - system has proj4
+# PROJ4_INCLUDE_DIRS - the proj4 include directory
+# PROJ4_LIBRARIES - Link these to use proj4
+#
+# Define PROJ4_MIN_VERSION for which version desired.
+
+if( NOT PROJ4_PATH )
+ if ( NOT "$ENV{PROJ4_PATH}" STREQUAL "" )
+ set( PROJ4_PATH "$ENV{PROJ4_PATH}" )
+ elseif ( NOT "$ENV{PROJ4_DIR}" STREQUAL "" )
+ set( PROJ4_PATH "$ENV{PROJ4_DIR}" )
+ endif()
+endif()
+
+if( NOT PROJ4_PATH )
+
+ include(FindPkgConfig)
+
+# if(Proj4_FIND_REQUIRED)
+# set(_pkgconfig_REQUIRED "REQUIRED")
+# else()
+# set(_pkgconfig_REQUIRED "")
+# endif()
+
+ if(PROJ4_MIN_VERSION)
+ pkg_check_modules(PKPROJ4 ${_pkgconfig_REQUIRED} QUIET proj4>=${PROJ4_MIN_VERSION})
+ else()
+ pkg_check_modules(PKPROJ4 ${_pkgconfig_REQUIRED} QUIET proj4)
+ endif()
+
+ if( PKG_CONFIG_FOUND AND PKPROJ4_FOUND )
+
+ find_path(PROJ4_INCLUDE_DIR proj_api.h HINTS ${PKPROJ4_INCLUDEDIR} ${PKPROJ4_INCLUDE_DIRS} PATH_SUFFIXES proj4 NO_DEFAULT_PATH )
+ find_library(PROJ4_LIBRARY proj HINTS ${PKPROJ4_LIBDIR} ${PKPROJ4_LIBRARY_DIRS} PATH_SUFFIXES proj4 NO_DEFAULT_PATH )
+
+ endif()
+
+# ecbuild_debug_var( PKG_CONFIG_FOUND )
+# ecbuild_debug_var( PKPROJ4_FOUND )
+# ecbuild_debug_var( PROJ4_MIN_VERSION )
+
+endif()
+
+if( PROJ4_PATH )
+
+ find_path(PROJ4_INCLUDE_DIR NAMES proj_api.h PATHS ${PROJ4_PATH} ${PROJ4_PATH}/include PATH_SUFFIXES proj4 NO_DEFAULT_PATH )
+ find_library(PROJ4_LIBRARY NAMES proj PATHS ${PROJ4_PATH} ${PROJ4_PATH}/lib PATH_SUFFIXES proj4 NO_DEFAULT_PATH )
+
+endif()
+
+find_path(PROJ4_INCLUDE_DIR NAMES proj_api.h PATHS PATH_SUFFIXES proj4 )
+find_library( PROJ4_LIBRARY NAMES proj PATHS PATH_SUFFIXES proj4 )
+
+
+# ecbuild_debug_var( PROJ4_INCLUDE_DIR )
+# ecbuild_debug_var( PROJ4_LIBRARY )
+
+# handle the QUIETLY and REQUIRED arguments and set GRIBAPI_FOUND
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Proj4 DEFAULT_MSG
+ PROJ4_LIBRARY PROJ4_INCLUDE_DIR)
+
+set( PROJ4_LIBRARIES ${PROJ4_LIBRARY} )
+set( PROJ4_INCLUDE_DIRS ${PROJ4_INCLUDE_DIR} )
+
+mark_as_advanced( PROJ4_INCLUDE_DIR PROJ4_LIBRARY )
diff --git a/cmake/FindREADLINE.cmake b/cmake/FindREADLINE.cmake
new file mode 100644
index 0000000..2ba08b4
--- /dev/null
+++ b/cmake/FindREADLINE.cmake
@@ -0,0 +1,87 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+# - Try to find READLINE
+# Once done this will define
+# READLINE_FOUND - System has READLINE
+# READLINE_INCLUDE_DIRS - The READLINE include directories
+# READLINE_LIBRARIES - The libraries needed to use READLINE
+# READLINE_DEFINITIONS - Compiler switches required for using READLINE
+
+if( DEFINED READLINE_PATH )
+ find_path(READLINE_INCLUDE_DIR readline/readline.h PATHS ${READLINE_PATH}/include NO_DEFAULT_PATH)
+ find_library(READLINE_LIBRARY readline PATHS ${READLINE_PATH}/lib PATH_SUFFIXES readline NO_DEFAULT_PATH)
+endif()
+
+find_path(READLINE_INCLUDE_DIR readline/readline.h )
+find_library( READLINE_LIBRARY readline PATH_SUFFIXES readline )
+
+# check what version we got
+cmake_push_check_state()
+
+ set( CMAKE_REQUIRED_LIBRARIES ${READLINE_LIBRARY} )
+ set( CMAKE_REQUIRED_INCLUDES ${READLINE_INCLUDE_DIR} )
+
+ # sometimes the link might fail missing -ltermcap or -l(n)curses
+ # if we searched before for Curses, then lets try to use it
+ if(CURSES_FOUND)
+ list( APPEND CMAKE_REQUIRED_LIBRARIES ${CURSES_LIBRARIES} )
+ list( APPEND CMAKE_REQUIRED_INCLUDES ${CURSES_INCLUDE_DIR} )
+ endif()
+
+ ecbuild_check_cxx_source_return(
+ "#include <stdio.h>
+ #include <readline/readline.h>
+ #include <iostream>
+ int main() {
+ std::cout << rl_library_version << std::flush;
+ return 0;
+ }"
+ VAR readline_version
+ OUTPUT __readline_version_out )
+
+cmake_pop_check_state()
+
+# ecbuild_debug_var( readline_version )
+# ecbuild_debug_var( __readline_version_out )
+
+set( __readline_fail 0 )
+if( __readline_version_out )
+
+ if( "${__readline_version_out}" MATCHES "^EditLine" )
+ message( STATUS "Found EditLine instead of Readline at '${READLINE_INCLUDE_DIR}'" )
+ if( READLINE_WRAPPER_OK )
+ set( READLINE_WRAPPER "EditLine" )
+ set( __readline_fail 0 )
+ else()
+ message( STATUS "Readline wrapper not accepted -- rejecting Readline at '${READLINE_INCLUDE_DIR}'" )
+ set( __readline_fail 1 )
+ endif()
+ endif()
+
+else()
+ message( STATUS "Readline test run failed -- rejecting Readline at '${READLINE_INCLUDE_DIR}'" )
+ set( __readline_fail 1 )
+endif()
+
+if( __readline_fail )
+ set( READLINE_LIBRARY READLINE_LIBRARY-NOTFOUND )
+ set( READLINE_INCLUDE_DIR READLINE_INCLUDE_DIR-NOTFOUND )
+endif()
+
+include(FindPackageHandleStandardArgs)
+
+find_package_handle_standard_args(READLINE DEFAULT_MSG READLINE_LIBRARY READLINE_INCLUDE_DIR)
+
+if( READLINE_FOUND )
+ set( READLINE_VERSION ${__readline_version_out} )
+ set( READLINE_LIBRARIES ${READLINE_LIBRARY} )
+ set( READLINE_INCLUDE_DIRS ${READLINE_INCLUDE_DIR} )
+endif()
+
+mark_as_advanced(READLINE_INCLUDE_DIR READLINE_LIBRARY )
diff --git a/cmake/FindRPCGEN.cmake b/cmake/FindRPCGEN.cmake
new file mode 100644
index 0000000..fd42e9f
--- /dev/null
+++ b/cmake/FindRPCGEN.cmake
@@ -0,0 +1,20 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+#Sets:
+# RPCGEN_FOUND = prcgen was found
+# RPCGEN_EXECUTABLE = the executable rpcgen
+
+if( DEFINED RPCGEN_PATH )
+ find_program( RPCGEN_EXECUTABLE NAMES rpcgen PATHS ${RPCGEN_PATH} PATH_SUFFIXES bin NO_DEFAULT_PATH )
+endif()
+find_program( RPCGEN_EXECUTABLE NAMES rpcgen )
+
+include(FindPackageHandleStandardArgs)
+
+find_package_handle_standard_args( RPCGEN DEFAULT_MSG RPCGEN_EXECUTABLE )
diff --git a/cmake/FindRealtime.cmake b/cmake/FindRealtime.cmake
new file mode 100644
index 0000000..843a54f
--- /dev/null
+++ b/cmake/FindRealtime.cmake
@@ -0,0 +1,24 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+#Sets:
+# RT_LIB = the library to link against
+
+if( DEFINED REALTIME_PATH )
+ find_library(RT_LIB rt PATHS ${REALTIME_PATH}/lib NO_DEFAULT_PATH )
+endif()
+
+find_library( RT_LIB rt )
+
+mark_as_advanced( RT_LIB )
+
+include(FindPackageHandleStandardArgs)
+# Handle the QUIET and REQUIRED arguments and set REALTIME_FOUND to TRUE
+# if all listed variables are TRUE
+# Note: capitalisation of the package name must be the same as in the file name
+find_package_handle_standard_args(Realtime DEFAULT_MSG RT_LIB )
diff --git a/cmake/FindSZip.cmake b/cmake/FindSZip.cmake
new file mode 100644
index 0000000..925348c
--- /dev/null
+++ b/cmake/FindSZip.cmake
@@ -0,0 +1,30 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+# - Try to find SZip
+# Once done this will define
+# SZIP_FOUND - System has SZip
+# SZIP_INCLUDE_DIRS - The SZip include directories
+# SZIP_LIBRARIES - The libraries needed to use SZip
+
+if( DEFINED SZIP_PATH )
+ find_path( SZIP_INCLUDE_DIR szlib.h PATHS ${SZIP_PATH}/include PATH_SUFFIXES szip NO_DEFAULT_PATH )
+ find_library( SZIP_LIBRARY NAMES szip sz PATHS ${SZIP_PATH}/lib PATH_SUFFIXES szip NO_DEFAULT_PATH )
+endif()
+
+find_path( SZIP_INCLUDE_DIR szlib.h PATH_SUFFIXES szip )
+find_library( SZIP_LIBRARY NAMES szip sz PATH_SUFFIXES szip )
+
+set( SZIP_LIBRARIES ${SZIP_LIBRARY} )
+set( SZIP_INCLUDE_DIRS ${SZIP_INCLUDE_DIR} )
+
+include(FindPackageHandleStandardArgs)
+
+find_package_handle_standard_args(SZip DEFAULT_MSG SZIP_LIBRARY SZIP_INCLUDE_DIR)
+
+mark_as_advanced(SZIP_INCLUDE_DIR SZIP_LIBRARY )
diff --git a/cmake/FindTrilinos.cmake b/cmake/FindTrilinos.cmake
new file mode 100644
index 0000000..0d99b54
--- /dev/null
+++ b/cmake/FindTrilinos.cmake
@@ -0,0 +1,49 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+# Try to find the Trilinos library
+#
+# Needs environmental variables
+# TRILINOS_PATH
+# Sets
+# TRILINOS_INCLUDE_DIRS
+# TRILINOS_LIBRARIES
+# TRILINOS_FOUND
+
+# Try to find Trilinos using Trilinos recommendations
+
+if( DEFINED $ENV{TRILINOS_PATH} )
+ find_package(Trilinos PATHS $ENV{TRILINOS_PATH}/lib/cmake/Trilinos $ENV{TRILINOS_PATH}/include )
+endif()
+
+if( TRILINOS_PATH )
+ find_package(Trilinos PATHS ${TRILINOS_PATH}/lib/cmake/Trilinos ${TRILINOS_PATH}/include )
+endif()
+
+if( Trilinos_FOUND )
+
+ set( TRILINOS_INCLUDE_DIRS "" )
+
+ list( APPEND TRILINOS_INCLUDE_DIRS ${Trilinos_INCLUDE_DIRS} )
+ list( APPEND TRILINOS_INCLUDE_DIRS ${Trilinos_TPL_INCLUDE_DIRS} )
+
+ foreach( test_lib ${Trilinos_LIBRARIES} )
+ if(NOT ${test_lib} STREQUAL "pytrilinos")
+ find_library( ${test_lib}_lib ${test_lib} PATHS ${Trilinos_LIBRARY_DIRS} NO_DEFAULT_PATH)
+ find_library( ${test_lib}_lib ${test_lib})
+ mark_as_advanced( ${test_lib}_lib )
+ list( APPEND TRILINOS_LIBRARIES ${${test_lib}_lib} )
+ endif()
+ endforeach()
+
+ list( APPEND TRILINOS_LIBRARIES ${Trilinos_TPL_LIBRARIES} )
+
+ set( TRILINOS_FOUND TRUE )
+ set( TRILINOS_VERSION ${Trilinos_VERSION} )
+
+endif()
diff --git a/cmake/FindViennaCL.cmake b/cmake/FindViennaCL.cmake
new file mode 100644
index 0000000..aba2980
--- /dev/null
+++ b/cmake/FindViennaCL.cmake
@@ -0,0 +1,39 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+# - Try to find ViennaCL
+# Once done this will define
+#
+# VIENNACL_FOUND - system has ViennaCL
+# VIENNACL_INCLUDE_DIRS - the ViennaCL include directories
+#
+# The following paths will be searched with priority if set in CMake or env
+#
+# VIENNACL_PATH - prefix path of the ViennaCL installation
+#
+# ViennaCL is header only, so there are no libraries to be found
+
+# Search with priority for VIENNACL_PATH if given as CMake or env var
+find_path(VIENNACL_INCLUDE_DIR viennacl/version.hpp
+ PATHS ${VIENNACL_PATH} ENV VIENNACL_PATH
+ PATH_SUFFIXES include NO_DEFAULT_PATH)
+
+find_path(VIENNACL_INCLUDE_DIR viennacl/version.hpp
+ PATH_SUFFIXES include )
+
+set( VIENNACL_INCLUDE_DIRS ${VIENNACL_INCLUDE_DIR} )
+
+include(FindPackageHandleStandardArgs)
+
+# handle the QUIET and REQUIRED arguments and set VIENNACL_FOUND to TRUE
+# if all listed variables are valid
+# Note: capitalisation of the package name must be the same as in the file name
+find_package_handle_standard_args(ViennaCL DEFAULT_MSG
+ VIENNACL_INCLUDE_DIR)
+
+mark_as_advanced(VIENNACL_INCLUDE_DIRS)
diff --git a/cmake/FindXLFortranLibs.cmake b/cmake/FindXLFortranLibs.cmake
new file mode 100644
index 0000000..37800c7
--- /dev/null
+++ b/cmake/FindXLFortranLibs.cmake
@@ -0,0 +1,51 @@
+# © Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+###############################################################################
+
+list( APPEND xl_libs xlf90 xlopt xlf xlsmp )
+
+set( xlf_all_libs_found 1 )
+
+foreach( lib ${xl_libs} )
+
+ find_library( ${lib}_lib ${lib} PATHS ${XLF_PATH} PATH_SUFFIXES lib lib64 NO_DEFAULT_PATH )
+
+ find_library( ${lib}_lib ${lib} )
+
+ if( ${lib}_lib )
+ list( APPEND XLFORTRAN_LIBRARIES ${${lib}_lib} )
+ else()
+ set( xlf_all_libs_found 0 )
+ endif()
+
+endforeach()
+
+include(FindPackageHandleStandardArgs)
+# handle the QUIET and REQUIRED arguments and set XLFORTRANLIBS_FOUND to TRUE
+# if all listed variables are valid
+# Note: capitalisation of the package name must be the same as in the file name
+find_package_handle_standard_args( XLFortranLibs DEFAULT_MSG xlf_all_libs_found XLFORTRAN_LIBRARIES )
+
+# HACK for support libraries
+
+if( LIBXLFORTRAN_FOUND )
+ list( APPEND xl_extra_libs pthreads m essl )
+ foreach( lib ${xl_extra_libs} )
+
+ find_library( ${lib}_lib ${lib} PATHS ${XLF_PATH} PATH_SUFFIXES lib lib64 NO_DEFAULT_PATH )
+
+ find_library( ${lib}_lib ${lib} )
+
+ if( ${lib}_lib )
+ list( APPEND XLFORTRAN_LIBRARIES ${${lib}_lib} )
+ endif()
+
+ endforeach()
+endif()
+
diff --git a/cmake/FindYACC.cmake b/cmake/FindYACC.cmake
new file mode 100644
index 0000000..7b15bfe
--- /dev/null
+++ b/cmake/FindYACC.cmake
@@ -0,0 +1,157 @@
+# - Find yacc executable and provides macros to generate custom build rules
+# The module defines the following variables:
+#
+# YACC_EXECUTABLE - path to the yacc program
+# YACC_FOUND - true if the program was found
+#
+# The minimum required version of yacc can be specified using the
+# standard CMake syntax, e.g. find_package(YACC 2.1.3)
+#
+# If yacc is found, the module defines the macros:
+# YACC_TARGET(<Name> <YaccInput> <CodeOutput> [VERBOSE <file>]
+# [COMPILE_FLAGS <string>])
+# which will create a custom rule to generate a parser. <YaccInput> is
+# the path to a yacc file. <CodeOutput> is the name of the source file
+# generated by yacc. A header file is also be generated, and contains
+# the token list. If COMPILE_FLAGS option is specified, the next
+# parameter is added in the yacc command line. if VERBOSE option is
+# specified, <file> is created and contains verbose descriptions of the
+# grammar and parser. The macro defines a set of variables:
+# YACC_${Name}_DEFINED - true is the macro ran successfully
+# YACC_${Name}_INPUT - The input source file, an alias for <YaccInput>
+# YACC_${Name}_OUTPUT_SOURCE - The source file generated by yacc
+# YACC_${Name}_OUTPUT_HEADER - The header file generated by yacc
+# YACC_${Name}_OUTPUTS - The sources files generated by yacc
+# YACC_${Name}_COMPILE_FLAGS - Options used in the yacc command line
+#
+# ====================================================================
+
+#=============================================================================
+# Copyright 2009 Kitware, Inc.
+# Copyright 2006 Tristan Carel
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+
+# This file is based on the FindFLEX CMake macro, and adapted by ECMWF
+
+#=============================================================================
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+FIND_PROGRAM(YACC_EXECUTABLE yacc DOC "path to the yacc/yacc executable")
+MARK_AS_ADVANCED(YACC_EXECUTABLE)
+
+IF(YACC_EXECUTABLE)
+ # the yacc commands should be executed with the C locale, otherwise
+ # the message (which are parsed) may be translated
+ SET(_Yacc_SAVED_LC_ALL "$ENV{LC_ALL}")
+ SET(ENV{LC_ALL} C)
+
+ SET(ENV{LC_ALL} ${_Yacc_SAVED_LC_ALL})
+
+ # internal macro
+ MACRO(YACC_TARGET_option_verbose Name YaccOutput filename)
+ LIST(APPEND YACC_TARGET_cmdopt "--verbose")
+ GET_FILENAME_COMPONENT(YACC_TARGET_output_path "${YaccOutput}" PATH)
+ GET_FILENAME_COMPONENT(YACC_TARGET_output_name "${YaccOutput}" NAME_WE)
+ ADD_CUSTOM_COMMAND(OUTPUT ${filename}
+ COMMAND ${CMAKE_COMMAND}
+ ARGS -E copy
+ "${YACC_TARGET_output_path}/${YACC_TARGET_output_name}.output"
+ "${filename}"
+ DEPENDS
+ "${YACC_TARGET_output_path}/${YACC_TARGET_output_name}.output"
+ COMMENT "[YACC][${Name}] Copying yacc verbose table to ${filename}"
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
+ SET(YACC_${Name}_VERBOSE_FILE ${filename})
+ LIST(APPEND YACC_TARGET_extraoutputs
+ "${YACC_TARGET_output_path}/${YACC_TARGET_output_name}.output")
+ ENDMACRO(YACC_TARGET_option_verbose)
+
+ # internal macro
+ MACRO(YACC_TARGET_option_extraopts Options)
+ SET(YACC_TARGET_extraopts "${Options}")
+ SEPARATE_ARGUMENTS(YACC_TARGET_extraopts)
+ LIST(APPEND YACC_TARGET_cmdopt ${YACC_TARGET_extraopts})
+ ENDMACRO(YACC_TARGET_option_extraopts)
+
+ #============================================================
+ # YACC_TARGET (public macro)
+ #============================================================
+ #
+ MACRO(YACC_TARGET Name YaccInput YaccOutput)
+ SET(YACC_TARGET_output_header "")
+ SET(YACC_TARGET_cmdopt "")
+ SET(YACC_TARGET_outputs "${YaccOutput}")
+ IF(NOT ${ARGC} EQUAL 3 AND NOT ${ARGC} EQUAL 5 AND NOT ${ARGC} EQUAL 7)
+ MESSAGE(SEND_ERROR "Usage")
+ ELSE()
+ # Parsing parameters
+ IF(${ARGC} GREATER 5 OR ${ARGC} EQUAL 5)
+ IF("${ARGV3}" STREQUAL "VERBOSE")
+ YACC_TARGET_option_verbose(${Name} ${YaccOutput} "${ARGV4}")
+ ENDIF()
+ IF("${ARGV3}" STREQUAL "COMPILE_FLAGS")
+ YACC_TARGET_option_extraopts("${ARGV4}")
+ ENDIF()
+ ENDIF()
+
+ IF(${ARGC} EQUAL 7)
+ IF("${ARGV5}" STREQUAL "VERBOSE")
+ YACC_TARGET_option_verbose(${Name} ${YaccOutput} "${ARGV6}")
+ ENDIF()
+
+ IF("${ARGV5}" STREQUAL "COMPILE_FLAGS")
+ YACC_TARGET_option_extraopts("${ARGV6}")
+ ENDIF()
+ ENDIF()
+
+ # Header's name generated by yacc (see option -d)
+ LIST(APPEND YACC_TARGET_cmdopt "-d")
+ STRING(REGEX REPLACE "^(.*)(\\.[^.]*)$" "\\2" _fileext "${ARGV2}")
+ STRING(REPLACE "c" "h" _fileext ${_fileext})
+ STRING(REGEX REPLACE "^(.*)(\\.[^.]*)$" "\\1${_fileext}"
+ YACC_${Name}_OUTPUT_HEADER "${ARGV2}")
+ LIST(APPEND YACC_TARGET_outputs "${YACC_${Name}_OUTPUT_HEADER}")
+
+# message ( STATUS "${YACC_EXECUTABLE} ${YACC_TARGET_cmdopt} ${CMAKE_CURRENT_BINARY_DIR}/${ARGV1}" )
+# message ( STATUS "${CMAKE_COMMAND} -E rename ${CMAKE_CURRENT_BINARY_DIR}/y.tab.h ${YACC_${Name}_OUTPUT_HEADER}" )
+# message ( STATUS "${CMAKE_COMMAND} -E rename ${CMAKE_CURRENT_BINARY_DIR}/y.tab.c ${ARGV2}" )
+
+ ADD_CUSTOM_COMMAND(OUTPUT ${YACC_TARGET_outputs} ${YACC_TARGET_extraoutputs}
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/${ARGV1} ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND ${YACC_EXECUTABLE} ${YACC_TARGET_cmdopt} ${CMAKE_CURRENT_BINARY_DIR}/${ARGV1}
+ COMMAND ${CMAKE_COMMAND} -E rename ${CMAKE_CURRENT_BINARY_DIR}/y.tab.h ${YACC_${Name}_OUTPUT_HEADER}
+ COMMAND ${CMAKE_COMMAND} -E rename ${CMAKE_CURRENT_BINARY_DIR}/y.tab.c ${ARGV2}
+ DEPENDS ${ARGV1}
+ COMMENT "[YACC][${Name}] Building parser with yacc"
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+
+ # define target variables
+ SET(YACC_${Name}_DEFINED TRUE)
+ SET(YACC_${Name}_INPUT ${ARGV1})
+ SET(YACC_${Name}_OUTPUTS ${YACC_TARGET_outputs})
+ SET(YACC_${Name}_COMPILE_FLAGS ${YACC_TARGET_cmdopt})
+ SET(YACC_${Name}_OUTPUT_SOURCE "${YaccOutput}")
+
+ ENDIF(NOT ${ARGC} EQUAL 3 AND NOT ${ARGC} EQUAL 5 AND NOT ${ARGC} EQUAL 7)
+ ENDMACRO(YACC_TARGET)
+ #
+ #============================================================
+
+ENDIF(YACC_EXECUTABLE)
+
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(YACC REQUIRED_VARS YACC_EXECUTABLE )
+
+# FindYACC.cmake ends here
diff --git a/cmake/Findgrib_api.cmake b/cmake/Findgrib_api.cmake
new file mode 100644
index 0000000..ab6fc0b
--- /dev/null
+++ b/cmake/Findgrib_api.cmake
@@ -0,0 +1,133 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+# - Try to find GRIB_API
+# Once done this will define
+# GRIB_API_FOUND - System has GRIB_API
+# GRIB_API_INCLUDE_DIRS - The GRIB_API include directories
+# GRIB_API_LIBRARIES - The libraries needed to use GRIB_API
+# GRIB_API_DEFINITIONS - Compiler switches required for using GRIB_API
+
+option( NO_GRIB_API_BINARIES "skip trying to find grib_api installed binaries" OFF )
+option( GRIB_API_PNG "use png with grib_api" ON )
+option( GRIB_API_JPG "use jpg with grib_api" ON )
+
+if( NOT grib_api_FOUND AND NOT NO_GRIB_API_BINARIES )
+
+ if( GRIB_API_JPG ) # jpeg support
+
+ find_package( JPEG QUIET ) # grib_api might be a static .a library in which
+
+ if( NOT "$ENV{JASPER_PATH}" STREQUAL "" )
+ list( APPEND CMAKE_PREFIX_PATH "$ENV{JASPER_PATH}" )
+ endif()
+ find_package( Jasper QUIET ) # case we don't know if which jpeg library was used
+
+ find_package( OpenJPEG QUIET ) # so we try to find all jpeg libs and link to them
+
+ if(JPEG_FOUND)
+ list( APPEND _grib_api_jpg_incs ${JPEG_INCLUDE_DIR} )
+ list( APPEND _grib_api_jpg_libs ${JPEG_LIBRARIES} )
+ endif()
+ if(JASPER_FOUND)
+ list( APPEND _grib_api_jpg_incs ${JASPER_INCLUDE_DIR} )
+ list( APPEND _grib_api_jpg_libs ${JASPER_LIBRARIES} )
+ endif()
+ if(OPENJPEG_FOUND)
+ list( APPEND _grib_api_jpg_incs ${OPENJPEG_INCLUDE_DIR} )
+ list( APPEND _grib_api_jpg_libs ${OPENJPEG_LIBRARIES} )
+ endif()
+
+ endif()
+
+ if( GRIB_API_PNG ) # png support
+
+ find_package(PNG)
+
+ if( DEFINED PNG_PNG_INCLUDE_DIR AND NOT DEFINED PNG_INCLUDE_DIRS )
+ set( PNG_INCLUDE_DIRS ${PNG_PNG_INCLUDE_DIR} CACHE INTERNAL "PNG include dirs" )
+ endif()
+ if( DEFINED PNG_LIBRARY AND NOT DEFINED PNG_LIBRARIES )
+ set( PNG_LIBRARIES ${PNG_LIBRARY} CACHE INTERNAL "PNG libraries" )
+ endif()
+
+ if(PNG_FOUND)
+ list( APPEND _grib_api_png_defs ${PNG_DEFINITIONS} )
+ list( APPEND _grib_api_png_incs ${PNG_INCLUDE_DIRS} )
+ list( APPEND _grib_api_png_libs ${PNG_LIBRARIES} )
+ endif()
+
+ endif()
+
+ # The grib_api on macos that comes with 'port' is linked against ghostscript
+ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+ find_library(GS_LIBRARIES NAMES gs)
+ if( GS_LIBRARIES )
+ list( APPEND GRIB_API_LIBRARIES ${GS_LIBRARIES} )
+ endif()
+ endif()
+
+ # find external grib_api
+
+ if( NOT DEFINED GRIB_API_PATH AND NOT "$ENV{GRIB_API_PATH}" STREQUAL "" )
+ list( APPEND GRIB_API_PATH "$ENV{GRIB_API_PATH}" )
+ endif()
+
+ if( DEFINED GRIB_API_PATH )
+ find_path(GRIB_API_INCLUDE_DIR NAMES grib_api.h PATHS ${GRIB_API_PATH} ${GRIB_API_PATH}/include PATH_SUFFIXES grib_api NO_DEFAULT_PATH)
+ find_library(GRIB_API_LIBRARY NAMES grib_api PATHS ${GRIB_API_PATH} ${GRIB_API_PATH}/lib PATH_SUFFIXES grib_api NO_DEFAULT_PATH)
+ find_library(GRIB_API_LIB_F90 NAMES grib_api_f90 PATHS ${GRIB_API_PATH} ${GRIB_API_PATH}/lib PATH_SUFFIXES grib_api NO_DEFAULT_PATH)
+ find_library(GRIB_API_LIB_F77 NAMES grib_api_f77 PATHS ${GRIB_API_PATH} ${GRIB_API_PATH}/lib PATH_SUFFIXES grib_api NO_DEFAULT_PATH)
+ find_program(GRIB_API_INFO NAMES grib_info PATHS ${GRIB_API_PATH} ${GRIB_API_PATH}/bin PATH_SUFFIXES grib_api NO_DEFAULT_PATH)
+ endif()
+
+ find_path(GRIB_API_INCLUDE_DIR NAMES grib_api.h PATHS PATH_SUFFIXES grib_api )
+ find_library( GRIB_API_LIBRARY NAMES grib_api PATHS PATH_SUFFIXES grib_api )
+ find_library( GRIB_API_LIB_F90 NAMES grib_api_f90 PATHS PATH_SUFFIXES grib_api )
+ find_library( GRIB_API_LIB_F77 NAMES grib_api_f77 PATHS PATH_SUFFIXES grib_api )
+ find_program(GRIB_API_INFO NAMES grib_info PATHS PATH_SUFFIXES grib_api )
+
+ list( APPEND GRIB_API_LIBRARIES ${GRIB_API_LIBRARY} ${GRIB_API_LIB_F90} ${GRIB_API_LIB_F77} )
+ set( GRIB_API_INCLUDE_DIRS ${GRIB_API_INCLUDE_DIR} )
+
+ if( GRIB_API_INFO )
+
+ execute_process( COMMAND ${GRIB_API_INFO} -v OUTPUT_VARIABLE _grib_info_out ERROR_VARIABLE _grib_info_err OUTPUT_STRIP_TRAILING_WHITESPACE )
+
+ # ecbuild_debug_var( _grib_info_out )
+
+ string( REPLACE "." " " _version_list ${_grib_info_out} ) # dots to spaces
+ separate_arguments( _version_list )
+
+ list( GET _version_list 0 GRIB_API_MAJOR_VERSION )
+ list( GET _version_list 1 GRIB_API_MINOR_VERSION )
+ list( GET _version_list 2 GRIB_API_PATCH_VERSION )
+
+ set( GRIB_API_VERSION "${GRIB_API_MAJOR_VERSION}.${GRIB_API_MINOR_VERSION}.${GRIB_API_PATCH_VERSION}" )
+ set( GRIB_API_VERSION_STR "${_grib_info_out}" )
+
+ set( grib_api_VERSION "${GRIB_API_VERSION}" )
+ set( grib_api_VERSION_STR "${GRIB_API_VERSION_STR}" )
+
+ endif()
+
+ include(FindPackageHandleStandardArgs)
+
+ # handle the QUIETLY and REQUIRED arguments and set GRIB_API_FOUND to TRUE
+ find_package_handle_standard_args( grib_api DEFAULT_MSG
+ GRIB_API_LIBRARY GRIB_API_INCLUDE_DIR GRIB_API_INFO )
+
+ mark_as_advanced( GRIB_API_INCLUDE_DIR GRIB_API_LIBRARY GRIB_API_INFO )
+
+ list( APPEND GRIB_API_DEFINITIONS ${_grib_api_jpg_defs} ${_grib_api_png_defs} )
+ list( APPEND GRIB_API_INCLUDE_DIRS ${_grib_api_jpg_incs} ${_grib_api_png_incs} )
+ list( APPEND GRIB_API_LIBRARIES ${_grib_api_jpg_libs} ${_grib_api_png_libs} )
+
+ set( grib_api_FOUND ${GRIB_API_FOUND} )
+
+endif()
diff --git a/cmake/Findodb_api.cmake b/cmake/Findodb_api.cmake
new file mode 100644
index 0000000..0058fbe
--- /dev/null
+++ b/cmake/Findodb_api.cmake
@@ -0,0 +1,97 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+# - Try to find ODB_API
+# Once done this will define
+# ODB_API_FOUND - System has ODB_API
+# ODB_API_INCLUDE_DIRS - The ODB_API include directories
+# ODB_API_LIBRARIES - The libraries needed to use ODB_API
+# ODB_API_DEFINITIONS - Compiler switches required for using ODB_API
+
+if( NOT odb_api_FOUND )
+
+ # find external odb_api
+
+ if( NOT DEFINED ODB_API_PATH AND NOT "$ENV{ODB_API_PATH}" STREQUAL "" )
+ list( APPEND ODB_API_PATH "$ENV{ODB_API_PATH}" )
+ endif()
+
+ if( DEFINED ODB_API_PATH )
+
+ find_path( ODB_API_INCLUDE_DIR
+ NAMES odb_api_config.h
+ PATHS ${ODB_API_PATH} ${ODB_API_PATH}/include
+ PATH_SUFFIXES odb_api
+ NO_DEFAULT_PATH )
+
+ find_library( ODB_API_LIBRARY NAMES Odb
+ PATHS ${ODB_API_PATH} ${ODB_API_PATH}/lib
+ PATH_SUFFIXES odb_api
+ NO_DEFAULT_PATH )
+
+ find_library( ODB_API_ECLIB_LIBRARY NAMES Ec
+ PATHS ${ODB_API_PATH} ${ODB_API_PATH}/lib
+ PATH_SUFFIXES odb_api
+ NO_DEFAULT_PATH )
+ endif()
+
+ find_path( ODB_API_INCLUDE_DIR
+ NAMES odb_api_config.h
+ PATHS
+ PATH_SUFFIXES odb_api )
+
+ find_library( ODB_API_LIBRARY NAMES Odb
+ PATHS
+ PATH_SUFFIXES odb_api )
+
+ find_library( ODB_API_ECLIB_LIBRARY NAMES Ec
+ PATHS
+ PATH_SUFFIXES odb_api )
+
+
+ # get the version
+
+ if( ODB_API_INCLUDE_DIR )
+
+ set(_odb_api_VERSION_REGEX "([0-9]+)")
+
+ foreach( v MAJOR MINOR PATCH )
+
+ file(STRINGS "${ODB_API_INCLUDE_DIR}/odb_api_config.h" _odb_api_${v}_VERSION_CONTENTS REGEX "#define ODB_API_${v}_VERSION ")
+
+ if( "${_odb_api_${v}_VERSION_CONTENTS}" MATCHES ".*#define ODB_API_${v}_VERSION ${_odb_api_VERSION_REGEX}.*")
+
+ set( ODB_API_${v}_VERSION "${CMAKE_MATCH_1}" )
+
+ endif()
+
+ endforeach()
+
+ endif()
+
+ set( ODB_API_VERSION "${ODB_API_MAJOR_VERSION}.${ODB_API_MINOR_VERSION}.${ODB_API_PATCH_VERSION}" )
+ set( ODB_API_VERSION_STR "${_odb_info_out}" )
+
+ set( odb_api_VERSION "${ODB_API_VERSION}" )
+ set( odb_api_VERSION_STR "${ODB_API_VERSION_STR}" )
+
+ # handle the QUIETLY and REQUIRED arguments and set ODB_API_FOUND to TRUE
+
+ include(FindPackageHandleStandardArgs)
+
+ find_package_handle_standard_args( odb_api DEFAULT_MSG
+ ODB_API_LIBRARY ODB_API_ECLIB_LIBRARY ODB_API_INCLUDE_DIR )
+
+ set( ODB_API_LIBRARIES ${ODB_API_LIBRARY} ${ODB_API_ECLIB_LIBRARY} )
+ set( ODB_API_INCLUDE_DIRS ${ODB_API_INCLUDE_DIR} )
+
+ mark_as_advanced( ODB_API_INCLUDE_DIR ODB_API_LIBRARY ODB_API_ECLIB_LIBRARY )
+
+ set( odb_api_FOUND ${ODB_API_FOUND} )
+
+endif()
diff --git a/cmake/Findspot.cmake b/cmake/Findspot.cmake
new file mode 100644
index 0000000..52e0fb5
--- /dev/null
+++ b/cmake/Findspot.cmake
@@ -0,0 +1,65 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+# - Try to find ODB_API
+# Once done this will define
+# ODB_API_FOUND - System has ODB_API
+# ODB_API_INCLUDE_DIRS - The ODB_API include directories
+# ODB_API_LIBRARIES - The libraries needed to use ODB_API
+# ODB_API_DEFINITIONS - Compiler switches required for using ODB_API
+
+if( NOT spot_FOUND )
+
+ # find external odb_api
+
+ if( NOT DEFINED SPOT_PATH AND NOT "$ENV{SPOT_PATH}" STREQUAL "" )
+ list( APPEND SPOT_PATH "$ENV{SPOT_PATH}" )
+ endif()
+
+ if( DEFINED SPOT_PATH )
+
+ find_path( SPOT_INCLUDE_DIR
+ NAMES spot_database.h
+ PATHS ${SPOT_PATH} ${SPOT_PATH}/include
+ NO_DEFAULT_PATH )
+
+ find_library( SPOT_LIBRARY NAMES spot_database
+ PATHS ${SPOT_PATH} ${SPOT_PATH}/lib
+ NO_DEFAULT_PATH )
+
+ endif()
+
+ find_path( SPOT_INCLUDE_DIR
+ NAMES spot_database.h
+ PATHS
+ PATH_SUFFIXES spot )
+
+ find_library( SPOT_LIBRARY NAMES spot_database
+ PATHS
+ PATH_SUFFIXES odb_api )
+
+ find_library( ODB_API_ECLIB_LIBRARY NAMES Ec
+ PATHS
+ PATH_SUFFIXES spot )
+
+
+ # get the version
+
+ include(FindPackageHandleStandardArgs)
+
+ find_package_handle_standard_args( spot DEFAULT_MSG
+ SPOT_LIBRARY SPOT_INCLUDE_DIR )
+
+ set( SPOT_LIBRARIES ${SPOT_LIBRARY} )
+ set( SPOT_INCLUDE_DIRS ${SPOT_INCLUDE_DIR} )
+
+ mark_as_advanced( SPOT_INCLUDE_DIR SPOT_LIBRARY )
+
+ set( spot_FOUND ${SPOT_FOUND} )
+
+endif()
diff --git a/cmake/VERSION.cmake b/cmake/VERSION.cmake
new file mode 100644
index 0000000..a65cc6d
--- /dev/null
+++ b/cmake/VERSION.cmake
@@ -0,0 +1,7 @@
+set( ECBUILD_MAJOR_VERSION "2" )
+set( ECBUILD_MINOR_VERSION "2" )
+set( ECBUILD_PATCH_VERSION "0" )
+
+set( ECBUILD_VERSION_STR "2.2.0" )
+
+set( ECBUILD_MACRO_VERSION "${ECBUILD_MAJOR_VERSION}.${ECBUILD_MINOR_VERSION}" )
diff --git a/cmake/compiler_flags/Clang_C.cmake b/cmake/compiler_flags/Clang_C.cmake
new file mode 100644
index 0000000..bc73c69
--- /dev/null
+++ b/cmake/compiler_flags/Clang_C.cmake
@@ -0,0 +1,13 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+set( CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG" CACHE STRING "C compiler flags for Release builds" FORCE )
+set( CMAKE_C_FLAGS_BIT "-O2 -DNDEBUG" CACHE STRING "C compiler flags for Bit-reproducible builds" FORCE )
+set( CMAKE_C_FLAGS_DEBUG "-O0 -g -ftrapv" CACHE STRING "C compiler flags for Debug builds" FORCE )
+set( CMAKE_C_FLAGS_PRODUCTION "-O3 -g" CACHE STRING "C compiler flags for Production builds." FORCE )
+set( CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g" CACHE STRING "C compiler flags for RelWithDebInfo builds." FORCE )
diff --git a/cmake/compiler_flags/Clang_CXX.cmake b/cmake/compiler_flags/Clang_CXX.cmake
new file mode 100644
index 0000000..53f0f21
--- /dev/null
+++ b/cmake/compiler_flags/Clang_CXX.cmake
@@ -0,0 +1,13 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+set( CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG" CACHE STRING "C++ compiler flags for Release builds" FORCE )
+set( CMAKE_CXX_FLAGS_BIT "-O2 -DNDEBUG" CACHE STRING "C++ compiler flags for Bit-reproducible builds" FORCE )
+set( CMAKE_CXX_FLAGS_DEBUG "-O0 -g -ftrapv" CACHE STRING "C++ compiler flags for Debug builds" FORCE )
+set( CMAKE_CXX_FLAGS_PRODUCTION "-O3 -g" CACHE STRING "C++ compiler flags for Production builds." FORCE )
+set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g" CACHE STRING "C++ compiler flags for RelWithDebInfo builds." FORCE )
diff --git a/cmake/compiler_flags/Cray_C.cmake b/cmake/compiler_flags/Cray_C.cmake
new file mode 100644
index 0000000..76779f9
--- /dev/null
+++ b/cmake/compiler_flags/Cray_C.cmake
@@ -0,0 +1,14 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+set( CMAKE_C_FLAGS_ALL "-hlist=amid" CACHE STRING "Common flags for all build-types" FORCE )
+set( CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_ALL} -O3 -hfp3 -hscalar3 -hvector3 -DNDEBUG" CACHE STRING "Release C flags" FORCE )
+set( CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_ALL} -O2 -hfp1 -Gfast -DNDEBUG" CACHE STRING "Release-with-debug-info C flags" FORCE )
+set( CMAKE_C_FLAGS_PRODUCTION "${CMAKE_C_FLAGS_ALL} -O2 -hfp1 -G2" CACHE STRING "Production C flags" FORCE )
+set( CMAKE_C_FLAGS_BIT "${CMAKE_C_FLAGS_ALL} -O2 -hfp1 -G2 -hflex_mp=conservative -hadd_paren -DNDEBUG" CACHE STRING "Bit-reproducible C flags" FORCE )
+set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_ALL} -O0 -G0" CACHE STRING "Debug Cflags" FORCE )
diff --git a/cmake/compiler_flags/Cray_CXX.cmake b/cmake/compiler_flags/Cray_CXX.cmake
new file mode 100644
index 0000000..d599bff
--- /dev/null
+++ b/cmake/compiler_flags/Cray_CXX.cmake
@@ -0,0 +1,14 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+set( CMAKE_CXX_FLAGS_ALL "-hlist=amid" CACHE STRING "Common flags for all build-types" FORCE )
+set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_ALL} -O3 -hfp3 -hscalar3 -hvector3 -DNDEBUG" CACHE STRING "Release C++ flags" FORCE )
+set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_ALL} -O2 -hfp1 -Gfast -DNDEBUG" CACHE STRING "Release-with-debug-info C++ flags" FORCE )
+set( CMAKE_CXX_FLAGS_PRODUCTION "${CMAKE_CXX_FLAGS_ALL} -O2 -hfp1 -G2" CACHE STRING "Production C++ flags" FORCE )
+set( CMAKE_CXX_FLAGS_BIT "${CMAKE_CXX_FLAGS_ALL} -O2 -hfp1 -G2 -hflex_mp=conservative -hadd_paren -DNDEBUG" CACHE STRING "Bit-reproducible C++ flags" FORCE )
+set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_ALL} -O0 -G0" CACHE STRING "Debug CXX flags" FORCE )
diff --git a/cmake/compiler_flags/Cray_Fortran.cmake b/cmake/compiler_flags/Cray_Fortran.cmake
new file mode 100644
index 0000000..b2c23de
--- /dev/null
+++ b/cmake/compiler_flags/Cray_Fortran.cmake
@@ -0,0 +1,15 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+# -emf activates .mods and uses lower case
+set( CMAKE_Fortran_FLAGS_ALL "-emf" CACHE STRING "Common flags for all build-types" FORCE )
+set( CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_ALL} -O3 -hfp3 -hscalar3 -hvector3 -DNDEBUG" CACHE STRING "Release Fortran flags" FORCE )
+set( CMAKE_Fortran_FLAGS_RELWITHDEBINFO "${CMAKE_Fortran_FLAGS_ALL} -O2 -hfp1 -Gfast -DNDEBUG" CACHE STRING "Release-with-debug-info Fortran flags" FORCE )
+set( CMAKE_Fortran_FLAGS_PRODUCTION "${CMAKE_Fortran_FLAGS_ALL} -O2 -hfp1 -G2" CACHE STRING "Production Fortran flags" FORCE )
+set( CMAKE_Fortran_FLAGS_BIT "${CMAKE_Fortran_FLAGS_ALL} -O2 -hfp1 -G2 -hflex_mp=conservative -hadd_paren -DNDEBUG" CACHE STRING "Bit-reproducible Fortran flags" FORCE )
+set( CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_ALL} -O0 -G0" CACHE STRING "Debug Fortran flags" FORCE )
diff --git a/cmake/compiler_flags/GNU_C.cmake b/cmake/compiler_flags/GNU_C.cmake
new file mode 100644
index 0000000..955f527
--- /dev/null
+++ b/cmake/compiler_flags/GNU_C.cmake
@@ -0,0 +1,18 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+set( CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG" CACHE STRING "C compiler flags for Release builds" FORCE )
+set( CMAKE_C_FLAGS_BIT "-g -O2 -m64 -march=native -DNDEBUG" CACHE STRING "C compiler flags for Bit-reproducible builds" FORCE )
+set( CMAKE_C_FLAGS_DEBUG "-O0 -g" CACHE STRING "C compiler flags for Debug builds" FORCE )
+set( CMAKE_C_FLAGS_PRODUCTION "-O2 -g" CACHE STRING "C compiler flags for Production builds." FORCE )
+set( CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g" CACHE STRING "C compiler flags for RelWithDebInfo builds." FORCE )
+
+# NOTE: gcc does not guarrante that -O3 performs better than -O2
+# -- it can perform worse due to assembly code bloating.
+# Moreover for gcc 4.1.2 we found that -O3 remove the parser code generated from Lex/Yacc
+# and therefore in production mode we downgrade to -O2 if the compiler is GCC (for all versions).
diff --git a/cmake/compiler_flags/GNU_CXX.cmake b/cmake/compiler_flags/GNU_CXX.cmake
new file mode 100644
index 0000000..0ab8c3a
--- /dev/null
+++ b/cmake/compiler_flags/GNU_CXX.cmake
@@ -0,0 +1,18 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+set( CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG" CACHE STRING "C++ compiler flags for Release builds" FORCE )
+set( CMAKE_CXX_FLAGS_BIT "-g -O2 -m64 -march=native -DNDEBUG" CACHE STRING "C++ compiler flags for Bit-reproducible builds" FORCE )
+set( CMAKE_CXX_FLAGS_DEBUG "-O0 -g" CACHE STRING "C++ compiler flags for Debug builds" FORCE )
+set( CMAKE_CXX_FLAGS_PRODUCTION "-O2 -g" CACHE STRING "C++ compiler flags for Production builds." FORCE )
+set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g" CACHE STRING "C++ compiler flags for RelWithDebInfo builds." FORCE )
+
+# NOTE: gcc does not guarrante that -O3 performs better than -O2
+# -- it can perform worse due to assembly code bloating.
+# Moreover for gcc 4.1.2 we found that -O3 remove the parser code generated from Lex/Yacc
+# and therefore in production mode we downgrade to -O2 if the compiler is GCC (for all versions).
diff --git a/cmake/compiler_flags/GNU_Fortran.cmake b/cmake/compiler_flags/GNU_Fortran.cmake
new file mode 100644
index 0000000..a12abec
--- /dev/null
+++ b/cmake/compiler_flags/GNU_Fortran.cmake
@@ -0,0 +1,21 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+set( CMAKE_Fortran_FLAGS_RELEASE "-O3 -funroll-all-loops -finline-functions" CACHE STRING "Fortran compiler flags for Release builds" FORCE )
+set( CMAKE_Fortran_FLAGS_BIT "-g -O2 -m64 -march=native -DNDEBUG -fno-range-check -fconvert=big-endian" CACHE STRING "Fortran compiler flags for Bit-reproducible builds" FORCE )
+set( CMAKE_Fortran_FLAGS_DEBUG "-O0 -g -fcheck=bounds -fbacktrace -finit-real=snan" CACHE STRING "Fortran compiler flags for Debug builds" FORCE )
+set( CMAKE_Fortran_FLAGS_PRODUCTION "-O2 -g" CACHE STRING "Fortran compiler flags for Production builds." FORCE )
+set( CMAKE_Fortran_FLAGS_RELWITHDEBINFO "-O2 -g" CACHE STRING "Fortran compiler flags for RelWithDebInfo builds." FORCE )
+
+####################################################################
+
+# Meaning of flags
+# ----------------
+# -fstack-arrays : Allocate automatic arrays on the stack (needs large stacksize!!!)
+# -funroll-all-loops : Unroll all loops
+# -fcheck=bounds : Bounds checking
diff --git a/cmake/compiler_flags/Intel_C.cmake b/cmake/compiler_flags/Intel_C.cmake
new file mode 100644
index 0000000..dbea59f
--- /dev/null
+++ b/cmake/compiler_flags/Intel_C.cmake
@@ -0,0 +1,13 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+set( CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG" CACHE STRING "Release C compiler flags" FORCE )
+set( CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g" CACHE STRING "Release-with-debug-info C compiler flags" FORCE )
+set( CMAKE_C_FLAGS_BIT "-O2 -DNDEBUG" CACHE STRING "Bit-reproducible C compiler flags" FORCE )
+set( CMAKE_C_FLAGS_DEBUG "-O0 -g -traceback" CACHE STRING "Debug C compiler flags" FORCE )
+set( CMAKE_C_FLAGS_PRODUCTION "-O3 -g" CACHE STRING "Production C compiler flags" FORCE )
diff --git a/cmake/compiler_flags/Intel_CXX.cmake b/cmake/compiler_flags/Intel_CXX.cmake
new file mode 100644
index 0000000..5b8dc78
--- /dev/null
+++ b/cmake/compiler_flags/Intel_CXX.cmake
@@ -0,0 +1,13 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+set( CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG" CACHE STRING "Release C++ compiler flags" FORCE )
+set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g" CACHE STRING "Release-with-debug-info C++ compiler flags" FORCE )
+set( CMAKE_CXX_FLAGS_BIT "-O2 -DNDEBUG" CACHE STRING "Bit-reproducible C++ compiler flags" FORCE )
+set( CMAKE_CXX_FLAGS_DEBUG "-O0 -g -traceback" CACHE STRING "Debug C++ compiler flags" FORCE )
+set( CMAKE_CXX_FLAGS_PRODUCTION "-O3 -g" CACHE STRING "Production C++ compiler flags" FORCE )
diff --git a/cmake/compiler_flags/Intel_Fortran.cmake b/cmake/compiler_flags/Intel_Fortran.cmake
new file mode 100644
index 0000000..86b69dc
--- /dev/null
+++ b/cmake/compiler_flags/Intel_Fortran.cmake
@@ -0,0 +1,14 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+set( CMAKE_Fortran_FLAGS_RELEASE "-O3 -unroll -inline -heap-arrays" CACHE STRING "Release Fortran flags" FORCE )
+set( CMAKE_Fortran_FLAGS_RELWITHDEBINFO "-O2 -g" CACHE STRING "Release-with-debug-info Fortran flags" FORCE )
+set( CMAKE_Fortran_FLAGS_BIT "-O2 -unroll -inline -heap-arrays" CACHE STRING "Bit-reproducible Fortran flags" FORCE )
+# -check all implies -check bounds
+set( CMAKE_Fortran_FLAGS_DEBUG "-O0 -g -traceback -heap-arrays -check all" CACHE STRING "Debug Fortran flags" FORCE )
+set( CMAKE_Fortran_FLAGS_PRODUCTION "-O3 -g" CACHE STRING "Production Fortran compiler flags" FORCE )
diff --git a/cmake/compiler_flags/PGI_C.cmake b/cmake/compiler_flags/PGI_C.cmake
new file mode 100644
index 0000000..6784a14
--- /dev/null
+++ b/cmake/compiler_flags/PGI_C.cmake
@@ -0,0 +1,11 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+set( CMAKE_C_FLAGS_RELEASE "-fast -O3 -DNDEBUG" CACHE STRING "Release C compiler flags" FORCE )
+
+set( CMAKE_C_LINK_FLAGS "" CACHE STRING "" )
diff --git a/cmake/compiler_flags/PGI_CXX.cmake b/cmake/compiler_flags/PGI_CXX.cmake
new file mode 100644
index 0000000..877ef3f
--- /dev/null
+++ b/cmake/compiler_flags/PGI_CXX.cmake
@@ -0,0 +1,11 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+set( CMAKE_CXX_FLAGS_RELEASE "-fast -O3 -DNDEBUG" CACHE STRING "Release C++ compiler flags" FORCE )
+
+set( CMAKE_CXX_LINK_FLAGS "" CACHE STRING "" )
diff --git a/cmake/compiler_flags/PGI_Fortran.cmake b/cmake/compiler_flags/PGI_Fortran.cmake
new file mode 100644
index 0000000..a268cc9
--- /dev/null
+++ b/cmake/compiler_flags/PGI_Fortran.cmake
@@ -0,0 +1,11 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+set( CMAKE_Fortran_FLAGS_RELEASE "-fast -O3" CACHE STRING "Release Fortran compiler flags" FORCE )
+
+set( CMAKE_Fortran_LINK_FLAGS "" CACHE STRING "" )
diff --git a/ecbuild/cmake/contrib/CheckFortranCompilerFlag.cmake b/cmake/contrib/CheckFortranCompilerFlag.cmake
similarity index 100%
rename from ecbuild/cmake/contrib/CheckFortranCompilerFlag.cmake
rename to cmake/contrib/CheckFortranCompilerFlag.cmake
diff --git a/ecbuild/cmake/contrib/CheckFortranSourceCompiles.cmake b/cmake/contrib/CheckFortranSourceCompiles.cmake
similarity index 100%
rename from ecbuild/cmake/contrib/CheckFortranSourceCompiles.cmake
rename to cmake/contrib/CheckFortranSourceCompiles.cmake
diff --git a/cmake/contrib/FindEigen3.cmake b/cmake/contrib/FindEigen3.cmake
new file mode 100644
index 0000000..9315294
--- /dev/null
+++ b/cmake/contrib/FindEigen3.cmake
@@ -0,0 +1,97 @@
+# - Try to find Eigen3 lib
+#
+# This module supports requiring a minimum version, e.g. you can do
+# find_package(Eigen3 3.1.2)
+# to require version 3.1.2 or newer of Eigen3.
+#
+# Once done this will define
+#
+# EIGEN3_FOUND - system has eigen lib with correct version
+# EIGEN3_INCLUDE_DIR - the eigen include directory
+# EIGEN3_VERSION - eigen version
+
+# Copyright (c) 2006, 2007 Montel Laurent, <montel at kde.org>
+# Copyright (c) 2008, 2009 Gael Guennebaud, <g.gael at free.fr>
+# Copyright (c) 2009 Benoit Jacob <jacob.benoit.1 at gmail.com>
+# Redistribution and use is allowed according to the terms of the 2-clause BSD license.
+
+if(NOT Eigen3_FIND_VERSION)
+ if(NOT Eigen3_FIND_VERSION_MAJOR)
+ set(Eigen3_FIND_VERSION_MAJOR 2)
+ endif(NOT Eigen3_FIND_VERSION_MAJOR)
+ if(NOT Eigen3_FIND_VERSION_MINOR)
+ set(Eigen3_FIND_VERSION_MINOR 91)
+ endif(NOT Eigen3_FIND_VERSION_MINOR)
+ if(NOT Eigen3_FIND_VERSION_PATCH)
+ set(Eigen3_FIND_VERSION_PATCH 0)
+ endif(NOT Eigen3_FIND_VERSION_PATCH)
+
+ set(Eigen3_FIND_VERSION "${Eigen3_FIND_VERSION_MAJOR}.${Eigen3_FIND_VERSION_MINOR}.${Eigen3_FIND_VERSION_PATCH}")
+endif(NOT Eigen3_FIND_VERSION)
+
+macro(_eigen3_check_version)
+ file(READ "${EIGEN3_INCLUDE_DIR}/Eigen/src/Core/util/Macros.h" _eigen3_version_header)
+
+ string(REGEX MATCH "define[ \t]+EIGEN_WORLD_VERSION[ \t]+([0-9]+)" _eigen3_world_version_match "${_eigen3_version_header}")
+ set(EIGEN3_WORLD_VERSION "${CMAKE_MATCH_1}")
+ string(REGEX MATCH "define[ \t]+EIGEN_MAJOR_VERSION[ \t]+([0-9]+)" _eigen3_major_version_match "${_eigen3_version_header}")
+ set(EIGEN3_MAJOR_VERSION "${CMAKE_MATCH_1}")
+ string(REGEX MATCH "define[ \t]+EIGEN_MINOR_VERSION[ \t]+([0-9]+)" _eigen3_minor_version_match "${_eigen3_version_header}")
+ set(EIGEN3_MINOR_VERSION "${CMAKE_MATCH_1}")
+
+ set(EIGEN3_VERSION ${EIGEN3_WORLD_VERSION}.${EIGEN3_MAJOR_VERSION}.${EIGEN3_MINOR_VERSION})
+ if(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION})
+ set(EIGEN3_VERSION_OK FALSE)
+ else(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION})
+ set(EIGEN3_VERSION_OK TRUE)
+ endif(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION})
+
+ if(NOT EIGEN3_VERSION_OK)
+
+ message(STATUS "Eigen3 version ${EIGEN3_VERSION} found in ${EIGEN3_INCLUDE_DIR}, "
+ "but at least version ${Eigen3_FIND_VERSION} is required")
+ else()
+ set( EIGEN3_VERSION ${EIGEN3_VERSION} CACHE INTERNAL "Eigen3 version" )
+ endif()
+
+endmacro(_eigen3_check_version)
+
+if(EIGEN3_INCLUDE_DIR)
+
+ # in cache already
+ _eigen3_check_version()
+ set(EIGEN3_FOUND ${EIGEN3_VERSION_OK})
+
+else(EIGEN3_INCLUDE_DIR)
+
+ find_path(EIGEN3_INCLUDE_DIR NAMES signature_of_eigen3_matrix_library
+ PATHS
+ ${CMAKE_INSTALL_PREFIX}/include
+ ${KDE4_INCLUDE_DIR}
+ ${EIGEN3_PATH}/include
+ ${EIGEN3_DIR}/include
+ ${EIGEN3_ROOT}/include
+ ${EIGEN_PATH}/include
+ ${EIGEN_DIR}/include
+ ${EIGEN_ROOT}/include
+ ENV EIGEN3_PATH
+ ENV EIGEN3_DIR
+ ENV EIGEN3_ROOT
+ ENV EIGEN_PATH
+ ENV EIGEN_DIR
+ ENV EIGEN_ROOT
+ PATH_SUFFIXES eigen3 eigen include/eigen3 include/eigen
+ )
+
+ if(EIGEN3_INCLUDE_DIR)
+ _eigen3_check_version()
+ endif(EIGEN3_INCLUDE_DIR)
+
+ include(FindPackageHandleStandardArgs)
+ find_package_handle_standard_args(Eigen3 DEFAULT_MSG EIGEN3_INCLUDE_DIR EIGEN3_VERSION_OK)
+
+ mark_as_advanced(EIGEN3_INCLUDE_DIR)
+
+endif(EIGEN3_INCLUDE_DIR)
+
+set( EIGEN3_INCLUDE_DIRS ${EIGEN3_INCLUDE_DIR} )
diff --git a/cmake/contrib/FindFFTW.cmake b/cmake/contrib/FindFFTW.cmake
new file mode 100644
index 0000000..5ef46df
--- /dev/null
+++ b/cmake/contrib/FindFFTW.cmake
@@ -0,0 +1,217 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# FindFFTW
+# ========
+#
+# Find the FFTW library. ::
+#
+# find_package(FFTW [REQUIRED] [QUIET]
+# [COMPONENTS [single] [double] [long_double] [quad]])
+#
+# By default, search for the double precision library ``fftw3``
+#
+# Components
+# ----------
+#
+# If a different version or multiple versions of the library are required,
+# these need to be specified as ``COMPONENTS``. Note that double must be given
+# explicitly if any ``COMPONENTS`` are specified.
+#
+# The libraries corresponding to each of the ``COMPONENTS`` are:
+#
+# :single: ``fftw3f``
+# :double: ``fftw3``
+# :long_double: ``fftw3l``
+# :quad: ``fftw3q``
+#
+# Output variables
+# ----------------
+#
+# The following CMake variables are set on completion:
+#
+# :FFTW_FOUND: true if FFTW is found on the system
+# :FFTW_LIBRARIES: full paths to requested FFTW libraries
+# :FFTW_INCLUDES: FFTW include directory
+#
+# Input variables
+# ---------------
+#
+# The following CMake variables are checked by the function:
+#
+# :FFTW_USE_STATIC_LIBS: if true, only static libraries are found
+# :FFTW_ROOT: if set, this path is exclusively searched
+# :FFTW_DIR: equivalent to FFTW_ROOT
+# :FFTW_PATH: equivalent to FFTW_ROOT
+# :FFTW_LIBRARY: FFTW library to use
+# :FFTW_INCLUDE_DIR: FFTW include directory
+#
+##############################################################################
+
+#============================================#
+# #
+# From Eigen3, modified by W Deconinck #
+# #
+#============================================#
+
+if( (NOT FFTW_ROOT) AND EXISTS $ENV{FFTW_ROOT} )
+ set( FFTW_ROOT ${FFTW_ROOT} )
+endif()
+if( NOT FFTW_ROOT AND $FFTW_DIR )
+ set( FFTW_ROOT ${FFTW_DIR} )
+endif()
+if( (NOT FFTW_ROOT) AND EXISTS $ENV{FFTW_DIR} )
+ set( FFTW_ROOT $ENV{FFTW_DIR} )
+endif()
+if( (NOT FFTW_ROOT) AND FFTWDIR )
+ set( FFTW_ROOT ${FFTWDIR} )
+endif()
+if( (NOT FFTW_ROOT) AND EXISTS $ENV{FFTWDIR} )
+ set( FFTW_ROOT $ENV{FFTWDIR} )
+endif()
+if( (NOT FFTW_ROOT) AND FFTW_PATH )
+ set( FFTW_ROOT ${FFTW_PATH} )
+endif()
+if( (NOT FFTW_ROOT) AND EXISTS $ENV{FFTW_PATH})
+ set( FFTW_ROOT $ENV{FFTW_PATH} )
+endif()
+
+if( FFTW_ROOT ) # On cc[a|b|t] FFTW_DIR is set to the lib directory :(
+ get_filename_component(_dirname ${FFTW_ROOT} NAME)
+ if( _dirname MATCHES "lib" )
+ set( FFTW_ROOT "${FFTW_ROOT}/.." )
+ endif()
+endif()
+
+if( NOT FFTW_ROOT )
+ # Check if we can use PkgConfig
+ find_package(PkgConfig)
+
+ #Determine from PKG
+ if( PKG_CONFIG_FOUND AND NOT FFTW_ROOT )
+ pkg_check_modules( PKG_FFTW QUIET "fftw3" )
+ endif()
+endif()
+
+#Check whether to search static or dynamic libs
+set( CMAKE_FIND_LIBRARY_SUFFIXES_SAV ${CMAKE_FIND_LIBRARY_SUFFIXES} )
+
+if( ${FFTW_USE_STATIC_LIBS} )
+ set( CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX} )
+else()
+ set( CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_SHARED_LIBRARY_SUFFIX} )
+endif()
+
+if( FFTW_FIND_COMPONENTS )
+ ecbuild_debug( "FindFFTW: looking for components: ${FFTW_FIND_COMPONENTS}" )
+ foreach( _component ${FFTW_FIND_COMPONENTS} )
+ if( _component MATCHES "single" )
+ ecbuild_debug( "FindFFTW: looking for single precision (fftw3f)" )
+ set( _require_sp TRUE )
+ elseif( _component MATCHES "double" )
+ ecbuild_debug( "FindFFTW: looking for double precision (fftw3)" )
+ set( _require_dp TRUE )
+ elseif( _component MATCHES "long_double" )
+ ecbuild_debug( "FindFFTW: looking for long double precision (fftw3l)" )
+ set( _require_lp TRUE )
+ elseif( _component MATCHES "quad" )
+ ecbuild_debug( "FindFFTW: looking for quad precision (fftw3q)" )
+ set( _require_qp TRUE )
+ else()
+ endif()
+ endforeach()
+else()
+ ecbuild_debug( "FindFFTW: no components specified, looking for double precision (fftw3)" )
+ set( _require_dp TRUE )
+endif()
+
+if( FFTW_ROOT )
+ set( _default_paths NO_DEFAULT_PATH )
+ set( _lib_paths ${FFTW_ROOT} )
+ set( _include_paths ${FFTW_ROOT} )
+else()
+ set( _lib_paths ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} )
+ set( _include_paths ${PKG_FFTW_INCLUDE_DIRS} ${INCLUDE_INSTALL_DIR} )
+endif()
+
+#find libs
+
+if( _require_dp )
+ find_library(
+ FFTW_LIB
+ NAMES "fftw3"
+ PATHS ${_lib_paths}
+ PATH_SUFFIXES "lib" "lib64"
+ ${_default_paths}
+ )
+ if( NOT FFTW_LIB )
+ ecbuild_warn("FindFFTW: double precision required, but fftw3 was not found")
+ endif()
+endif()
+
+if( _require_sp )
+ find_library(
+ FFTWF_LIB
+ NAMES "fftw3f"
+ PATHS ${_lib_paths}
+ PATH_SUFFIXES "lib" "lib64"
+ ${_default_paths}
+ )
+ if( NOT FFTWF_LIB )
+ ecbuild_warn("FindFFTW: single precision required, but fftw3f was not found")
+ endif()
+endif()
+
+if( _require_lp )
+ find_library(
+ FFTWL_LIB
+ NAMES "fftw3l"
+ PATHS ${_lib_paths}
+ PATH_SUFFIXES "lib" "lib64"
+ ${_default_paths}
+ )
+ if( NOT FFTWL_LIB )
+ ecbuild_warn("FindFFTW: long double precision required, but fftw3l was not found")
+ endif()
+endif()
+
+if( _require_qp )
+ find_library(
+ FFTWQ_LIB
+ NAMES "fftw3q"
+ PATHS ${_lib_paths}
+ PATH_SUFFIXES "lib" "lib64"
+ ${_default_paths}
+ )
+ if( NOT FFTWQ_LIB )
+ ecbuild_warn("FindFFTW: quad precision required, but fftw3q was not found")
+ endif()
+endif()
+
+#find includes
+
+find_path(
+ FFTW_INCLUDES
+ NAMES "fftw3.h"
+ PATHS ${_include_paths}
+ PATH_SUFFIXES "include"
+ ${_default_paths}
+)
+
+set(FFTW_LIBRARIES ${FFTW_LIB} ${FFTWF_LIB} ${FFTWL_LIB} ${FFTWQ_LIB})
+
+set( CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_SAV} )
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(FFTW DEFAULT_MSG
+ FFTW_INCLUDES FFTW_LIBRARIES)
+
+mark_as_advanced(FFTW_INCLUDES FFTW_LIBRARIES FFTW_LIB FFTWF_LIB FFTWL_LIB)
diff --git a/cmake/contrib/FindNetCDF4.cmake b/cmake/contrib/FindNetCDF4.cmake
new file mode 100644
index 0000000..6bba4e0
--- /dev/null
+++ b/cmake/contrib/FindNetCDF4.cmake
@@ -0,0 +1,337 @@
+# Project uclales
+# http://gitorious.org/uclales
+# License: Academic Free License v3.0
+#
+# - Find NETCDF, a library for reading and writing self describing array data.
+#
+# This module invokes the NETCDF wrapper compiler that should be installed
+# alongside NETCDF. Depending upon the NETCDF Configuration, the wrapper compiler
+# is called either h5cc or h5pcc. If this succeeds, the module will then call
+# the compiler with the -show argument to see what flags are used when compiling
+# an NETCDF client application.
+#
+# The module will optionally accept the COMPONENTS argument. If no COMPONENTS
+# are specified, then the find module will default to finding only the NETCDF C
+# library. If one or more COMPONENTS are specified, the module will attempt to
+# find the language bindings for the specified components. Currently, the only
+# valid components are C, CXX, FORTRAN and F90.
+#
+# On UNIX systems, this module will read the variable NETCDF_USE_STATIC_LIBRARIES
+# to determine whether or not to prefer a static link to a dynamic link for NETCDF
+# and all of it's dependencies. To use this feature, make sure that the
+# NETCDF_USE_STATIC_LIBRARIES variable is set before the call to find_package.
+#
+# To provide the module with a hint about where to find your NETCDF installation,
+# set the CMake or environment variable NETCDF_ROOT, NETCDF_DIR, NETCDF_PATH or
+# NETCDF4_DIR. The Find module will then look in this path when searching for
+# NETCDF executables, paths, and libraries.
+#
+# In addition to finding the includes and libraries required to compile an NETCDF
+# client application, this module also makes an effort to find tools that come
+# with the NETCDF distribution that may be useful for regression testing.
+#
+# This module will define the following variables:
+# NETCDF_INCLUDE_DIRS - Location of the NETCDF includes
+# NETCDF_INCLUDE_DIR - Location of the NETCDF includes (deprecated)
+# NETCDF_DEFINITIONS - Required compiler definitions for NETCDF
+# NETCDF_C_LIBRARIES - Required libraries for the NETCDF C bindings.
+# NETCDF_CXX_LIBRARIES - Required libraries for the NETCDF C++ bindings
+# NETCDF_FORTRAN_LIBRARIES - Required libraries for the NETCDF FORTRAN bindings
+# NETCDF_F90_LIBRARIES - Required libraries for the NETCDF FORTRAN 90 bindings
+# NETCDF_LIBRARIES - Required libraries for all requested bindings
+# NETCDF_FOUND - true if NETCDF was found on the system
+# NETCDF_LIBRARY_DIRS - the full set of library directories
+# NETCDF_IS_PARALLEL - Whether or not NETCDF was found with parallel IO support
+# NETCDF_CONFIG_EXECUTABLE - the path to the NC-CONFIG tool
+
+#=============================================================================
+# Copyright 2009 Kitware, Inc.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+# License text for the above reference.)
+
+# This module is maintained by Thijs Heus <thijs.heus at zmaw.de>.
+
+include(SelectLibraryConfigurations)
+include(FindPackageHandleStandardArgs)
+
+# List of the valid NETCDF components
+set( NETCDF_VALID_COMPONENTS
+ FORTRAN
+ F90
+ CXX
+ C
+)
+
+# Invoke the NETCDF wrapper compiler. The compiler return value is stored to the
+# return_value argument, the text output is stored to the output variable.
+macro( _NETCDF_CONFIG flag output return_value )
+ if( NETCDF_CONFIG_EXECUTABLE )
+ exec_program( ${NETCDF_CONFIG_EXECUTABLE}
+ ARGS ${flag}
+ OUTPUT_VARIABLE ${output}
+ RETURN_VALUE ${return_value}
+ )
+ if( ${${return_value}} EQUAL 0 )
+ # do nothing
+ else()
+ message( STATUS
+ "Unable to determine ${flag} from NC-CONFIG." )
+ endif()
+ endif()
+endmacro()
+#
+# try to find the NETCDF wrapper compilers
+find_program( NETCDF_CONFIG_EXECUTABLE
+ NAMES nc-config
+ HINTS ${NETCDF_ROOT} ${NETCDF_DIR} ${NETCDF_PATH} ${NETCDF4_DIR}
+ ENV NETCDF_ROOT ENV NETCDF_DIR ENV NETCDF_PATH ENV NETCDF4_DIR
+ PATH_SUFFIXES bin Bin
+ DOC "NETCDF CONFIG PROGRAM. Used only to detect NETCDF compile flags." )
+mark_as_advanced( NETCDF_CONFIG_EXECUTABLE )
+ecbuild_debug("FindNetCDF4: nc-config executable = ${NETCDF_CONFIG_EXECUTABLE}")
+
+set(output "no")
+_NETCDF_CONFIG (--has-hdf5 output return)
+set(HAS_HDF5 FALSE)
+
+if(${output} STREQUAL yes)
+ set(HAS_HDF5 TRUE)
+ set(HDF5_FIND_QUIETLY ${NETCDF_FIND_QUIETLY})
+ set(HDF5_FIND_REQUIRED ${NETCDF_FIND_REQUIRED})
+ find_package(HDF5)
+# list( APPEND NETCDF_LIBRARIES_DEBUG
+# ${HDF5_LIBRARIES_DEBUG} )
+# list( APPEND NETCDF_LIBRARIES_RELEASE
+# ${HDF5_LIBRARIES_RELEASE} )
+ set (NETCDF_IS_PARALLEL ${HDF5_IS_PARALLEL})
+endif()
+_NETCDF_CONFIG (--has-pnetcdf output return)
+if(${output} STREQUAL yes)
+ set (NETCDF_IS_PARALLEL TRUE)
+else()
+# set(NETCDF_IS_PARALLEL FALSE)
+endif()
+set( NETCDF_IS_PARALLEL TRUE CACHE BOOL
+ "NETCDF library compiled with parallel IO support" )
+
+
+if( NETCDF_INCLUDE_DIRS AND NETCDF_LIBRARIES )
+ # Do nothing: we already have NETCDF_INCLUDE_PATH and NETCDF_LIBRARIES in the
+ # cache, it would be a shame to override them
+else()
+ if( NOT NETCDF_FIND_COMPONENTS )
+ set( NETCDF_LANGUAGE_BINDINGS "C" )
+ else()
+ # add the extra specified components, ensuring that they are valid.
+ foreach( component ${NETCDF_FIND_COMPONENTS} )
+ list( FIND NETCDF_VALID_COMPONENTS ${component} component_location )
+ if( ${component_location} EQUAL -1 )
+ message( FATAL_ERROR
+ "\"${component}\" is not a valid NETCDF component." )
+ else()
+ list( APPEND NETCDF_LANGUAGE_BINDINGS ${component} )
+ endif()
+ endforeach()
+ endif()
+
+ # seed the initial lists of libraries to find with items we know we need
+ set( NETCDF_C_INCLUDE_NAMES netcdf.h )
+ set( NETCDF_CXX_INCLUDE_NAMES netcdfcpp.h ${NETCDF_C_INCLUDE_NAMES} )
+ set( NETCDF_FORTRAN_INCLUDE_NAMES ${NETCDF_C_INCLUDE_NAMES} )
+ set( NETCDF_F90_INCLUDE_NAMES netcdf.mod typesizes.mod ${NETCDF_C_INCLUDE_NAMES} )
+
+ set( NETCDF_C_LIBRARY_NAMES netcdf)
+ set( NETCDF_CXX_LIBRARY_NAMES netcdf_c++ ${NETCDF_C_LIBRARY_NAMES} )
+ set( NETCDF_FORTRAN_LIBRARY_NAMES netcdff ${NETCDF_C_LIBRARY_NAMES})
+ set( NETCDF_F90_LIBRARY_NAMES ${NETCDF_FORTRAN_LIBRARY_NAMES} )
+
+ set( NETCDF_REQUIRED netcdf.h netcdfcpp.h netcdf.mod typesizes.mod netcdf netcdff netcdf_c++)
+
+ foreach( LANGUAGE ${NETCDF_LANGUAGE_BINDINGS} )
+ ecbuild_debug("FindNetCDF4: looking for ${LANGUAGE} language bindings")
+
+ set( NETCDF_${LANGUAGE}_FOUND 1 ) # disable this in following if necessary
+
+ # find the NETCDF includes
+ foreach( INC ${NETCDF_${LANGUAGE}_INCLUDE_NAMES} )
+ #ecbuild_debug( "FindNetCDF4: looking for include file ${INC}")
+
+ find_path( NETCDF_${INC}_INCLUDE_DIR ${INC}
+ HINTS ${NETCDF_${LANGUAGE}_INCLUDE_FLAGS}
+ ${NETCDF_ROOT} ${NETCDF_DIR} ${NETCDF_PATH} ${NETCDF4_DIR}
+ ENV NETCDF_ROOT ENV NETCDF_DIR ENV NETCDF_PATH ENV NETCDF4_DIR
+ PATH_SUFFIXES
+ include
+ Include
+ )
+ if( NOT NETCDF_${INC}_INCLUDE_DIR )
+ #ecbuild_debug( "FindNetCDF4: ${INC} not found" )
+ GET_FILENAME_COMPONENT( _basename ${INC} NAME_WE )
+ GET_FILENAME_COMPONENT( _ext ${INC} EXT )
+ string( TOUPPER ${_basename} _BASENAME )
+ set( INC_MOD "${_BASENAME}${_ext}")
+ #ecbuild_debug( "FindNetCDF4: try ${INC_MOD}" )
+ find_path( NETCDF_${INC}_INCLUDE_DIR ${INC_MOD}
+ HINTS ${NETCDF_${LANGUAGE}_INCLUDE_FLAGS}
+ ${NETCDF_ROOT} ${NETCDF_DIR} ${NETCDF_PATH} ${NETCDF4_DIR}
+ ENV NETCDF_ROOT ENV NETCDF_DIR ENV NETCDF_PATH ENV NETCDF4_DIR
+ PATH_SUFFIXES
+ include
+ Include
+ )
+ endif()
+
+ mark_as_advanced( NETCDF_${INC}_INCLUDE_DIR )
+ #ecbuild_debug_var( NETCDF_${INC}_INCLUDE_DIR)
+ if (NETCDF_${INC}_INCLUDE_DIR)
+ list( APPEND NETCDF_INCLUDE_DIRS ${NETCDF_${INC}_INCLUDE_DIR} )
+ else()
+ list( FIND NETCDF_REQUIRED ${INC} location )
+ if( ${location} EQUAL -1 )
+ else()
+ if(NETCDF_FIND_REQUIRED)
+ ecbuild_error( "\"${INC}\" is not found for NetCDF component ${LANGUAGE}" )
+ elseif( NOT NETCDF_FIND_QUIETLY )
+ message( STATUS "\"${INC}\" is not found for NetCDF component ${LANGUAGE}" )
+ endif()
+ set( NETCDF_${LANGUAGE}_FOUND 0 )
+ else()
+ endif()
+ endif()
+ endforeach()
+ # find the NETCDF libraries
+ foreach( LIB ${NETCDF_${LANGUAGE}_LIBRARY_NAMES} )
+ if( UNIX AND NETCDF_USE_STATIC_LIBRARIES )
+ # According to bug 1643 on the CMake bug tracker, this is the
+ # preferred method for searching for a static library.
+ # See http://www.cmake.org/Bug/view.php?id=1643. We search
+ # first for the full static library name, but fall back to a
+ # generic search on the name if the static search fails.
+ set( THIS_LIBRARY_SEARCH_DEBUG lib${LIB}d.a ${LIB}d )
+ set( THIS_LIBRARY_SEARCH_RELEASE lib${LIB}.a ${LIB} )
+ else()
+ set( THIS_LIBRARY_SEARCH_DEBUG ${LIB}d )
+ set( THIS_LIBRARY_SEARCH_RELEASE ${LIB} )
+ endif()
+ find_library( NETCDF_${LIB}_LIBRARY_DEBUG
+ NAMES ${THIS_LIBRARY_SEARCH_DEBUG}
+ HINTS ${NETCDF_${LANGUAGE}_LIBRARY_DIRS}
+ ${NETCDF_ROOT} ${NETCDF_DIR} ${NETCDF_PATH} ${NETCDF4_DIR}
+ ENV NETCDF_ROOT ENV NETCDF_DIR ENV NETCDF_PATH ENV NETCDF4_DIR
+ PATH_SUFFIXES lib64 Lib64 lib Lib)
+ find_library( NETCDF_${LIB}_LIBRARY_RELEASE
+ NAMES ${THIS_LIBRARY_SEARCH_RELEASE}
+ HINTS ${NETCDF_${LANGUAGE}_LIBRARY_DIRS}
+ ${NETCDF_ROOT} ${NETCDF_DIR} ${NETCDF_PATH} ${NETCDF4_DIR}
+ ENV NETCDF_ROOT ENV NETCDF_DIR ENV NETCDF_PATH ENV NETCDF4_DIR
+ PATH_SUFFIXES lib64 Lib64 lib Lib )
+ select_library_configurations( NETCDF_${LIB} )
+ # even though we adjusted the individual library names in
+ # select_library_configurations, we still need to distinguish
+ # between debug and release variants because NETCDF_LIBRARIES will
+ # need to specify different lists for debug and optimized builds.
+ # We can't just use the NETCDF_${LIB}_LIBRARY variable (which was set
+ # up by the selection macro above) because it may specify debug and
+ # optimized variants for a particular library, but a list of
+ # libraries is allowed to specify debug and optimized only once.
+ if (NETCDF_${LIB}_LIBRARY_RELEASE)
+ list( APPEND NETCDF_LIBRARIES_RELEASE ${NETCDF_${LIB}_LIBRARY_RELEASE} )
+ list( APPEND NETCDF_${LANGUAGE}_LIBRARIES_RELEASE ${NETCDF_${LIB}_LIBRARY_RELEASE} )
+ endif()
+ if (NETCDF_${LIB}_LIBRARY_DEBUG)
+ list( APPEND NETCDF_LIBRARIES_DEBUG ${NETCDF_${LIB}_LIBRARY_DEBUG} )
+ list( APPEND NETCDF_${LANGUAGE}_LIBRARIES_DEBUG ${NETCDF_${LIB}_LIBRARY_DEBUG} )
+ endif()
+ if (NETCDF_${LIB}_LIBRARY_RELEASE OR NETCDF_${LIB}_LIBRARY_DEBUG )
+ else()
+ list( FIND NETCDF_REQUIRED ${LIB} location )
+ if( ${location} EQUAL -1 )
+ else()
+ if(NETCDF_FIND_REQUIRED)
+ message( SEND_ERROR "\"${LIB}\" is not found for NetCDF component ${LANGUAGE}." )
+ elseif( NOT NETCDF_FIND_QUIETLY )
+ message( STATUS "\"${LIB}\" is not found for NetCDF component ${LANGUAGE}." )
+ else()
+ set( NETCDF_${LANGUAGE}_FOUND 0 )
+ endif()
+ endif()
+ endif()
+ endforeach()
+ list( APPEND NETCDF_LIBRARY_DIRS ${NETCDF_${LANGUAGE}_LIBRARY_DIRS} )
+
+ # Append the libraries for this language binding to the list of all
+ # required libraries.
+
+ if( NETCDF_${LANGUAGE}_FOUND )
+ ecbuild_debug( "FindNetCDF4: ${LANGUAGE} language bindings found" )
+ if( CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE )
+ list( APPEND NETCDF_${LANGUAGE}_LIBRARIES
+ debug ${NETCDF_${LANGUAGE}_LIBRARIES_DEBUG}
+ optimized ${NETCDF_${LANGUAGE}_LIBRARIES_RELEASE} )
+ else()
+ list( APPEND NETCDF_${LANGUAGE}_LIBRARIES
+ ${NETCDF_${LANGUAGE}_LIBRARIES_RELEASE} )
+ endif()
+ endif()
+ # ecbuild_debug_var( NETCDF_${LANGUAGE}_LIBRARIES )
+ list( APPEND NETCDF_FOUND_REQUIRED_VARS NETCDF_${LANGUAGE}_FOUND )
+ endforeach()
+
+ # We may have picked up some duplicates in various lists during the above
+ # process for the language bindings (both the C and C++ bindings depend on
+ # libz for example). Remove the duplicates.
+ if( NETCDF_INCLUDE_DIRS )
+ list( REMOVE_DUPLICATES NETCDF_INCLUDE_DIRS )
+ endif()
+ if( NETCDF_LIBRARIES_DEBUG )
+ list( REMOVE_DUPLICATES NETCDF_LIBRARIES_DEBUG )
+ endif()
+ if( NETCDF_LIBRARIES_RELEASE )
+ list( REMOVE_DUPLICATES NETCDF_LIBRARIES_RELEASE )
+ endif()
+ if( NETCDF_LIBRARY_DIRS )
+ list( REMOVE_DUPLICATES NETCDF_LIBRARY_DIRS )
+ endif()
+
+ # Construct the complete list of NETCDF libraries with debug and optimized
+ # variants when the generator supports them.
+ if( CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE )
+ set( NETCDF_LIBRARIES
+ debug ${NETCDF_LIBRARIES_DEBUG}
+ optimized ${NETCDF_LIBRARIES_RELEASE} )
+ else()
+ set( NETCDF_LIBRARIES ${NETCDF_LIBRARIES_RELEASE} )
+ endif()
+endif()
+
+set( NETCDF4_FIND_QUIETLY ${NETCDF_FIND_QUIETLY} )
+set( NETCDF4_FIND_REQUIRED ${NETCDF_FIND_REQUIRED} )
+# handle the QUIET and REQUIRED arguments and set NETCDF4_FOUND to TRUE
+# if all listed variables are valid
+# Note: capitalisation of the package name must be the same as in the file name
+find_package_handle_standard_args( NetCDF4 DEFAULT_MSG
+ ${NETCDF_FOUND_REQUIRED_VARS}
+ NETCDF_LIBRARIES
+ NETCDF_INCLUDE_DIRS
+)
+
+mark_as_advanced(
+ NETCDF_INCLUDE_DIRS
+ NETCDF_LIBRARIES
+ NETCDF_LIBRARY_DIRS
+)
+
+set( NETCDF_FOUND ${NETCDF4_FOUND} )
+
+# For backwards compatibility we set NETCDF_INCLUDE_DIR to the value of
+# NETCDF_INCLUDE_DIRS
+set( NETCDF_INCLUDE_DIR "${NETCDF_INCLUDE_DIRS}" )
+
diff --git a/ecbuild/cmake/contrib/FindNumPy.cmake b/cmake/contrib/FindNumPy.cmake
similarity index 100%
rename from ecbuild/cmake/contrib/FindNumPy.cmake
rename to cmake/contrib/FindNumPy.cmake
diff --git a/ecbuild/cmake/contrib/GetGitRevisionDescription.cmake b/cmake/contrib/GetGitRevisionDescription.cmake
similarity index 100%
rename from ecbuild/cmake/contrib/GetGitRevisionDescription.cmake
rename to cmake/contrib/GetGitRevisionDescription.cmake
diff --git a/cmake/contrib/GetGitRevisionDescription.cmake.in b/cmake/contrib/GetGitRevisionDescription.cmake.in
new file mode 100644
index 0000000..9fd3e64
--- /dev/null
+++ b/cmake/contrib/GetGitRevisionDescription.cmake.in
@@ -0,0 +1,42 @@
+#
+# Internal file for GetGitRevisionDescription.cmake
+#
+# Requires CMake 2.6 or newer (uses the 'function' command)
+#
+# Original Author:
+# 2009-2010 Ryan Pavlik <rpavlik at iastate.edu> <abiryan at ryand.net>
+# http://academic.cleardefinition.com
+# Iowa State University HCI Graduate Program/VRAC
+#
+# Copyright Iowa State University 2009-2010.
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+set(HEAD_HASH)
+
+file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
+
+string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
+if(HEAD_CONTENTS MATCHES "ref")
+ # named branch
+ string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
+ if(EXISTS "@GIT_DIR@/${HEAD_REF}")
+ configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
+ elseif(EXISTS "@GIT_DIR@/logs/${HEAD_REF}")
+ configure_file("@GIT_DIR@/logs/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
+ set(HEAD_HASH "${HEAD_REF}")
+ endif()
+else()
+ # detached HEAD
+ configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
+endif()
+
+if(NOT HEAD_HASH)
+ if(EXISTS "@GIT_DATA@/head-ref")
+ file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
+ string(STRIP "${HEAD_HASH}" HEAD_HASH)
+ else()
+ set(HEAD_HASH "unknown")
+ endif()
+endif()
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/.gitattributes b/cmake/contrib/GreatCMakeCookOff/.gitattributes
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/.gitattributes
rename to cmake/contrib/GreatCMakeCookOff/.gitattributes
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/.gitignore b/cmake/contrib/GreatCMakeCookOff/.gitignore
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/.gitignore
rename to cmake/contrib/GreatCMakeCookOff/.gitignore
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/AddCPP11Flags.cmake b/cmake/contrib/GreatCMakeCookOff/AddCPP11Flags.cmake
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/AddCPP11Flags.cmake
rename to cmake/contrib/GreatCMakeCookOff/AddCPP11Flags.cmake
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/AddGTest.cmake b/cmake/contrib/GreatCMakeCookOff/AddGTest.cmake
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/AddGTest.cmake
rename to cmake/contrib/GreatCMakeCookOff/AddGTest.cmake
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/CheckCXX11Features.cmake b/cmake/contrib/GreatCMakeCookOff/CheckCXX11Features.cmake
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/CheckCXX11Features.cmake
rename to cmake/contrib/GreatCMakeCookOff/CheckCXX11Features.cmake
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/CheckIsNaN.cmake b/cmake/contrib/GreatCMakeCookOff/CheckIsNaN.cmake
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/CheckIsNaN.cmake
rename to cmake/contrib/GreatCMakeCookOff/CheckIsNaN.cmake
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/FindEigen.cmake b/cmake/contrib/GreatCMakeCookOff/FindEigen.cmake
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/FindEigen.cmake
rename to cmake/contrib/GreatCMakeCookOff/FindEigen.cmake
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/LICENSE b/cmake/contrib/GreatCMakeCookOff/LICENSE
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/LICENSE
rename to cmake/contrib/GreatCMakeCookOff/LICENSE
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/README.md b/cmake/contrib/GreatCMakeCookOff/README.md
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/README.md
rename to cmake/contrib/GreatCMakeCookOff/README.md
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/TestCMake.cmake b/cmake/contrib/GreatCMakeCookOff/TestCMake.cmake
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/TestCMake.cmake
rename to cmake/contrib/GreatCMakeCookOff/TestCMake.cmake
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/__func__-N2340.cpp b/cmake/contrib/GreatCMakeCookOff/cpp11/__func__-N2340.cpp
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/__func__-N2340.cpp
rename to cmake/contrib/GreatCMakeCookOff/cpp11/__func__-N2340.cpp
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/auto-N2546.cpp b/cmake/contrib/GreatCMakeCookOff/cpp11/auto-N2546.cpp
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/auto-N2546.cpp
rename to cmake/contrib/GreatCMakeCookOff/cpp11/auto-N2546.cpp
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/begin_function.cc b/cmake/contrib/GreatCMakeCookOff/cpp11/begin_function.cc
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/begin_function.cc
rename to cmake/contrib/GreatCMakeCookOff/cpp11/begin_function.cc
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/constexpr-N2235.cpp b/cmake/contrib/GreatCMakeCookOff/cpp11/constexpr-N2235.cpp
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/constexpr-N2235.cpp
rename to cmake/contrib/GreatCMakeCookOff/cpp11/constexpr-N2235.cpp
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/constructor_delegate.cpp b/cmake/contrib/GreatCMakeCookOff/cpp11/constructor_delegate.cpp
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/constructor_delegate.cpp
rename to cmake/contrib/GreatCMakeCookOff/cpp11/constructor_delegate.cpp
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/cstdint.cpp b/cmake/contrib/GreatCMakeCookOff/cpp11/cstdint.cpp
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/cstdint.cpp
rename to cmake/contrib/GreatCMakeCookOff/cpp11/cstdint.cpp
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/decltype-N2343.cpp b/cmake/contrib/GreatCMakeCookOff/cpp11/decltype-N2343.cpp
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/decltype-N2343.cpp
rename to cmake/contrib/GreatCMakeCookOff/cpp11/decltype-N2343.cpp
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/deleted_constructor.cpp b/cmake/contrib/GreatCMakeCookOff/cpp11/deleted_constructor.cpp
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/deleted_constructor.cpp
rename to cmake/contrib/GreatCMakeCookOff/cpp11/deleted_constructor.cpp
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/deleted_constructor_fail_compile.cpp b/cmake/contrib/GreatCMakeCookOff/cpp11/deleted_constructor_fail_compile.cpp
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/deleted_constructor_fail_compile.cpp
rename to cmake/contrib/GreatCMakeCookOff/cpp11/deleted_constructor_fail_compile.cpp
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/enable_if.cpp b/cmake/contrib/GreatCMakeCookOff/cpp11/enable_if.cpp
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/enable_if.cpp
rename to cmake/contrib/GreatCMakeCookOff/cpp11/enable_if.cpp
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/explicit_cast.cpp b/cmake/contrib/GreatCMakeCookOff/cpp11/explicit_cast.cpp
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/explicit_cast.cpp
rename to cmake/contrib/GreatCMakeCookOff/cpp11/explicit_cast.cpp
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/initialization.cpp b/cmake/contrib/GreatCMakeCookOff/cpp11/initialization.cpp
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/initialization.cpp
rename to cmake/contrib/GreatCMakeCookOff/cpp11/initialization.cpp
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/lambda-N2927.cpp b/cmake/contrib/GreatCMakeCookOff/cpp11/lambda-N2927.cpp
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/lambda-N2927.cpp
rename to cmake/contrib/GreatCMakeCookOff/cpp11/lambda-N2927.cpp
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/long_double.cpp b/cmake/contrib/GreatCMakeCookOff/cpp11/long_double.cpp
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/long_double.cpp
rename to cmake/contrib/GreatCMakeCookOff/cpp11/long_double.cpp
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/long_long-N1811.cpp b/cmake/contrib/GreatCMakeCookOff/cpp11/long_long-N1811.cpp
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/long_long-N1811.cpp
rename to cmake/contrib/GreatCMakeCookOff/cpp11/long_long-N1811.cpp
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/noexcept.cpp b/cmake/contrib/GreatCMakeCookOff/cpp11/noexcept.cpp
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/noexcept.cpp
rename to cmake/contrib/GreatCMakeCookOff/cpp11/noexcept.cpp
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/nullptr-N2431.cpp b/cmake/contrib/GreatCMakeCookOff/cpp11/nullptr-N2431.cpp
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/nullptr-N2431.cpp
rename to cmake/contrib/GreatCMakeCookOff/cpp11/nullptr-N2431.cpp
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/nullptr-N2431_fail_compile.cpp b/cmake/contrib/GreatCMakeCookOff/cpp11/nullptr-N2431_fail_compile.cpp
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/nullptr-N2431_fail_compile.cpp
rename to cmake/contrib/GreatCMakeCookOff/cpp11/nullptr-N2431_fail_compile.cpp
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/override.cpp b/cmake/contrib/GreatCMakeCookOff/cpp11/override.cpp
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/override.cpp
rename to cmake/contrib/GreatCMakeCookOff/cpp11/override.cpp
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/override_fail_compile.cpp b/cmake/contrib/GreatCMakeCookOff/cpp11/override_fail_compile.cpp
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/override_fail_compile.cpp
rename to cmake/contrib/GreatCMakeCookOff/cpp11/override_fail_compile.cpp
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/random_device.cpp b/cmake/contrib/GreatCMakeCookOff/cpp11/random_device.cpp
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/random_device.cpp
rename to cmake/contrib/GreatCMakeCookOff/cpp11/random_device.cpp
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/rvalue_references-N2118.cpp b/cmake/contrib/GreatCMakeCookOff/cpp11/rvalue_references-N2118.cpp
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/rvalue_references-N2118.cpp
rename to cmake/contrib/GreatCMakeCookOff/cpp11/rvalue_references-N2118.cpp
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/shared_ptr.cpp b/cmake/contrib/GreatCMakeCookOff/cpp11/shared_ptr.cpp
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/shared_ptr.cpp
rename to cmake/contrib/GreatCMakeCookOff/cpp11/shared_ptr.cpp
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/sizeof_member-N2253.cpp b/cmake/contrib/GreatCMakeCookOff/cpp11/sizeof_member-N2253.cpp
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/sizeof_member-N2253.cpp
rename to cmake/contrib/GreatCMakeCookOff/cpp11/sizeof_member-N2253.cpp
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/static_assert-N1720.cpp b/cmake/contrib/GreatCMakeCookOff/cpp11/static_assert-N1720.cpp
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/static_assert-N1720.cpp
rename to cmake/contrib/GreatCMakeCookOff/cpp11/static_assert-N1720.cpp
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/static_assert-N1720_fail_compile.cpp b/cmake/contrib/GreatCMakeCookOff/cpp11/static_assert-N1720_fail_compile.cpp
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/static_assert-N1720_fail_compile.cpp
rename to cmake/contrib/GreatCMakeCookOff/cpp11/static_assert-N1720_fail_compile.cpp
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/template_alias.cpp b/cmake/contrib/GreatCMakeCookOff/cpp11/template_alias.cpp
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/template_alias.cpp
rename to cmake/contrib/GreatCMakeCookOff/cpp11/template_alias.cpp
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/trivial_type_traits.cpp b/cmake/contrib/GreatCMakeCookOff/cpp11/trivial_type_traits.cpp
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/trivial_type_traits.cpp
rename to cmake/contrib/GreatCMakeCookOff/cpp11/trivial_type_traits.cpp
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/type_traits.cpp b/cmake/contrib/GreatCMakeCookOff/cpp11/type_traits.cpp
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/type_traits.cpp
rename to cmake/contrib/GreatCMakeCookOff/cpp11/type_traits.cpp
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/unique_ptr.cpp b/cmake/contrib/GreatCMakeCookOff/cpp11/unique_ptr.cpp
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/unique_ptr.cpp
rename to cmake/contrib/GreatCMakeCookOff/cpp11/unique_ptr.cpp
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/variadic_templates-N2555.cpp b/cmake/contrib/GreatCMakeCookOff/cpp11/variadic_templates-N2555.cpp
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/cpp11/variadic_templates-N2555.cpp
rename to cmake/contrib/GreatCMakeCookOff/cpp11/variadic_templates-N2555.cpp
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/tests/addgtest.cmake b/cmake/contrib/GreatCMakeCookOff/tests/addgtest.cmake
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/tests/addgtest.cmake
rename to cmake/contrib/GreatCMakeCookOff/tests/addgtest.cmake
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/tests/checkcpp11flags.cmake b/cmake/contrib/GreatCMakeCookOff/tests/checkcpp11flags.cmake
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/tests/checkcpp11flags.cmake
rename to cmake/contrib/GreatCMakeCookOff/tests/checkcpp11flags.cmake
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/tests/checkisnan.cmake b/cmake/contrib/GreatCMakeCookOff/tests/checkisnan.cmake
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/tests/checkisnan.cmake
rename to cmake/contrib/GreatCMakeCookOff/tests/checkisnan.cmake
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/tests/cpp11/allfeatures.cmake b/cmake/contrib/GreatCMakeCookOff/tests/cpp11/allfeatures.cmake
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/tests/cpp11/allfeatures.cmake
rename to cmake/contrib/GreatCMakeCookOff/tests/cpp11/allfeatures.cmake
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/tests/cpp11/check_features.cmake b/cmake/contrib/GreatCMakeCookOff/tests/cpp11/check_features.cmake
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/tests/cpp11/check_features.cmake
rename to cmake/contrib/GreatCMakeCookOff/tests/cpp11/check_features.cmake
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/tests/cpp11/parse_input_features.cmake b/cmake/contrib/GreatCMakeCookOff/tests/cpp11/parse_input_features.cmake
similarity index 100%
rename from ecbuild/cmake/contrib/GreatCMakeCookOff/tests/cpp11/parse_input_features.cmake
rename to cmake/contrib/GreatCMakeCookOff/tests/cpp11/parse_input_features.cmake
diff --git a/cmake/ecbuild-config-version.cmake b/cmake/ecbuild-config-version.cmake
new file mode 100644
index 0000000..655d394
--- /dev/null
+++ b/cmake/ecbuild-config-version.cmake
@@ -0,0 +1,12 @@
+set(PACKAGE_VERSION "2.2.0")
+
+# check whether the requested PACKAGE_FIND_VERSION is compatible
+
+if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+else()
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
+ set(PACKAGE_VERSION_EXACT TRUE)
+ endif()
+endif()
diff --git a/cmake/ecbuild-config.cmake b/cmake/ecbuild-config.cmake
new file mode 100644
index 0000000..9e63c3d
--- /dev/null
+++ b/cmake/ecbuild-config.cmake
@@ -0,0 +1,97 @@
+# Config file for the ecbuild package
+# Defines the following variables:
+#
+# ECBUILD_INCLUDE_DIRS - include directories
+# ECBUILD_DEFINITIONS - preprocessor definitions
+# ECBUILD_LIBRARIES - libraries to link against
+# ECBUILD_FEATURES - list of enabled features
+# ECBUILD_VERSION - version of the package
+# ECBUILD_GIT_SHA1 - Git revision of the package
+# ECBUILD_GIT_SHA1_SHORT - short Git revision of the package
+#
+# Also defines ecbuild third-party library dependencies:
+# ECBUILD_TPLS - package names of third-party library dependencies
+# ECBUILD_TPL_INCLUDE_DIRS - include directories
+# ECBUILD_TPL_DEFINITIONS - preprocessor definitions
+# ECBUILD_TPL_LIBRARIES - libraries to link against
+
+### compute paths
+
+get_filename_component(ECBUILD_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
+
+set( ECBUILD_SELF_INCLUDE_DIRS "${ECBUILD_CMAKE_DIR}/../../../include" )
+set( ECBUILD_SELF_DEFINITIONS "" )
+set( ECBUILD_SELF_LIBRARIES "" )
+
+set( ECBUILD_TPLS "" )
+set( ECBUILD_TPL_INCLUDE_DIRS "" )
+set( ECBUILD_TPL_DEFINITIONS "" )
+set( ECBUILD_TPL_LIBRARIES "" )
+
+set( ECBUILD_VERSION "2.2.0" )
+set( ECBUILD_GIT_SHA1 "2aab713da140125a8d6a6d4620ff314740e82562" )
+set( ECBUILD_GIT_SHA1_SHORT "2aab713" )
+
+### export include paths as absolute paths
+
+set( ECBUILD_INCLUDE_DIRS "" )
+foreach( path ${ECBUILD_SELF_INCLUDE_DIRS} )
+ get_filename_component( abspath ${path} ABSOLUTE )
+ list( APPEND ECBUILD_INCLUDE_DIRS ${abspath} )
+endforeach()
+list( APPEND ECBUILD_INCLUDE_DIRS ${ECBUILD_TPL_INCLUDE_DIRS} )
+
+### export definitions
+
+set( ECBUILD_DEFINITIONS ${ECBUILD_SELF_DEFINITIONS} ${ECBUILD_TPL_DEFINITIONS} )
+
+### export list of all libraries
+
+set( ECBUILD_LIBRARIES ${ECBUILD_SELF_LIBRARIES} ${ECBUILD_TPL_LIBRARIES} )
+
+### export the features provided by the package
+
+set( ECBUILD_FEATURES "TESTS;INSTALL" )
+foreach( _f ${ECBUILD_FEATURES} )
+ set( ECBUILD_HAVE_${_f} 1 )
+endforeach()
+
+# Has this configuration been exported from a build tree?
+set( ECBUILD_IS_BUILD_DIR_EXPORT OFF )
+
+if( EXISTS ${ECBUILD_CMAKE_DIR}/ecbuild-import.cmake )
+ set( ECBUILD_IMPORT_FILE "${ECBUILD_CMAKE_DIR}/ecbuild-import.cmake" )
+ include( ${ECBUILD_IMPORT_FILE} )
+endif()
+
+# here goes the imports of the TPL's
+
+include( ${CMAKE_CURRENT_LIST_FILE}.tpls OPTIONAL )
+
+# insert definitions for IMPORTED targets
+
+if( NOT ecbuild_BINARY_DIR )
+
+ if( ECBUILD_IS_BUILD_DIR_EXPORT )
+ include( "/tmp/metabuilds/ecflow-metab_5062/opensuse131/ecbuild/builds/ecbuild-targets.cmake" OPTIONAL )
+ else()
+ include( "${ECBUILD_CMAKE_DIR}/ecbuild-targets.cmake" )
+ endif()
+
+endif()
+
+# publish this file as imported
+
+set( ECBUILD_IMPORT_FILE ${CMAKE_CURRENT_LIST_FILE} )
+mark_as_advanced( ECBUILD_IMPORT_FILE )
+
+# set ecbuild_BASE_DIR for final installations or build directories
+
+if( NOT ecbuild )
+ if( ECBUILD_IS_BUILD_DIR_EXPORT )
+ set( ecbuild_BASE_DIR /tmp/metabuilds/ecflow-metab_5062/opensuse131/ecbuild/builds )
+ else()
+ get_filename_component( abspath ${CMAKE_CURRENT_LIST_DIR}/../../.. ABSOLUTE )
+ set( ecbuild_BASE_DIR ${abspath} )
+ endif()
+endif()
diff --git a/cmake/ecbuild_add_c_flags.cmake b/cmake/ecbuild_add_c_flags.cmake
new file mode 100644
index 0000000..e6923a9
--- /dev/null
+++ b/cmake/ecbuild_add_c_flags.cmake
@@ -0,0 +1,92 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_add_c_flags
+# ===================
+#
+# Add C compiler flags to CMAKE_C_FLAGS only if supported by the compiler. ::
+#
+# ecbuild_add_c_flags( <flag1> [ <flag2> ... ]
+# [ BUILD <build> ]
+# [ NAME <name> ] )
+#
+# Options
+# -------
+#
+# BUILD : optional
+# add flags to ``CMAKE_C_FLAGS_<build>`` instead of ``CMAKE_C_FLAGS``
+#
+# NAME : optional
+# name of the check (if omitted, checks are enumerated)
+#
+##############################################################################
+
+macro( ecbuild_add_c_flags m_c_flags )
+
+ set( _flags ${m_c_flags} )
+
+ if( _flags AND CMAKE_C_COMPILER_LOADED )
+ set( options )
+ set( single_value_args BUILD NAME )
+ set( multi_value_args )
+
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ set( _try_add_flag TRUE )
+ if( _PAR_BUILD )
+ string( TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_CAPS )
+ string( TOUPPER ${_PAR_BUILD} _PAR_BUILD_CAPS )
+ if( NOT CMAKE_BUILD_TYPE_CAPS MATCHES "${_PAR_BUILD_CAPS}" )
+ set( _try_add_flag FALSE )
+ endif()
+ endif()
+ if( _try_add_flag )
+ if( NOT DEFINED N_CFLAG )
+ set( N_CFLAG 0 )
+ endif()
+
+ math( EXPR N_CFLAG '${N_CFLAG}+1' )
+
+ if( NOT ECBUILD_TRUST_FLAGS )
+ if( DEFINED _PAR_NAME )
+ check_c_compiler_flag( ${_flags} ${_PAR_NAME} )
+ set( _flag_ok ${${_PAR_NAME}} )
+ else()
+ check_c_compiler_flag( ${_flags} C_FLAG_TEST_${N_CFLAG} )
+ set( _flag_ok ${C_FLAG_TEST_${N_CFLAG}} )
+ endif()
+ else()
+ set( _flag_ok 1 )
+ endif()
+
+ if( _flag_ok )
+ if( _PAR_BUILD )
+ set( CMAKE_C_FLAGS_${_PAR_BUILD} "${CMAKE_C_FLAGS_${_PAR_BUILD}} ${_flags}" )
+ ecbuild_debug( "C FLAG [${_flags}] added for build type ${_PAR_BUILD}" )
+ else()
+ set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_flags}" )
+ ecbuild_debug( "C FLAG [${_flags}] added" )
+ endif()
+ else()
+ ecbuild_warn( "Unrecognised C flag [${_flags}] -- skipping" )
+ endif()
+ endif()
+ unset( _flags )
+ unset( _flag_ok )
+ unset( _try_add_flag )
+ endif()
+
+endmacro()
+
+macro( cmake_add_c_flags m_c_flags )
+ ecbuild_deprecate( " cmake_add_c_flags is deprecated, use ecbuild_add_c_flags instead." )
+ ecbuild_add_c_flags( ${m_c_flags} )
+endmacro()
diff --git a/cmake/ecbuild_add_cxx11_flags.cmake b/cmake/ecbuild_add_cxx11_flags.cmake
new file mode 100644
index 0000000..df8cde5
--- /dev/null
+++ b/cmake/ecbuild_add_cxx11_flags.cmake
@@ -0,0 +1,35 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_add_cxx11_flags
+# =======================
+#
+# Add cxx11 flags to CXX compilation flags. ::
+#
+# ecbuild_add_cxx11_flags()
+#
+# This macro uses macros from http://github.com/UCL/GreatCMakeCookOff.
+#
+##############################################################################
+
+macro( ecbuild_add_cxx11_flags )
+
+ # if( CMAKE_COMPILER_IS_GNUCXX )
+ # if( CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7 )
+ # ecbuild_add_cxx_flags("-std=c++0x")
+ # else()
+ # ecbuild_add_cxx_flags("-std=c++11")
+ # endif()
+ # endif()
+
+ include( ${ECBUILD_MACROS_DIR}/contrib/GreatCMakeCookOff/AddCPP11Flags.cmake )
+
+endmacro( ecbuild_add_cxx11_flags )
diff --git a/cmake/ecbuild_add_cxx_flags.cmake b/cmake/ecbuild_add_cxx_flags.cmake
new file mode 100644
index 0000000..63c442e
--- /dev/null
+++ b/cmake/ecbuild_add_cxx_flags.cmake
@@ -0,0 +1,92 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_add_cxx_flags
+# =====================
+#
+# Add C++ compiler flags to CMAKE_CXX_FLAGS only if supported by compiler. ::
+#
+# ecbuild_add_cxx_flags( <flag1> [ <flag2> ... ]
+# [ BUILD <build> ]
+# [ NAME <name> ] )
+#
+# Options
+# -------
+#
+# BUILD : optional
+# add flags to ``CMAKE_CXX_FLAGS_<build>`` instead of ``CMAKE_CXX_FLAGS``
+#
+# NAME : optional
+# name of the check (if omitted, checks are enumerated)
+#
+##############################################################################
+
+macro( ecbuild_add_cxx_flags m_cxx_flags )
+
+ set( _flags ${m_cxx_flags} )
+ if( _flags AND CMAKE_CXX_COMPILER_LOADED )
+ set( options )
+ set( single_value_args BUILD NAME )
+ set( multi_value_args )
+
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ set( _try_add_flag TRUE )
+ if( _PAR_BUILD )
+ string( TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_CAPS )
+ string( TOUPPER ${_PAR_BUILD} _PAR_BUILD_CAPS )
+ if( NOT CMAKE_BUILD_TYPE_CAPS MATCHES "${_PAR_BUILD_CAPS}" )
+ set( _try_add_flag FALSE )
+ endif()
+ endif()
+ if( _try_add_flag )
+
+ if( NOT DEFINED N_CXXFLAG )
+ set( N_CXXFLAG 0 )
+ endif()
+
+ math( EXPR N_CXXFLAG '${N_CXXFLAG}+1' )
+
+ if( NOT ECBUILD_TRUST_FLAGS )
+ if( DEFINED _PAR_NAME )
+ check_cxx_compiler_flag( ${_flags} ${_PAR_NAME} )
+ set( _flag_ok ${${_PAR_NAME}} )
+ else()
+ check_cxx_compiler_flag( ${_flags} CXX_FLAG_TEST_${N_CXXFLAG} )
+ set( _flag_ok CXX_FLAG_TEST_${N_CXXFLAG} )
+ endif()
+ else()
+ set( _flag_ok 1 )
+ endif()
+
+ if( _flag_ok )
+ if( _PAR_BUILD )
+ set( CMAKE_CXX_FLAGS_${_PAR_BUILD} "${CMAKE_CXX_FLAGS_${_PAR_BUILD}} ${_flags}" )
+ ecbuild_debug( "C++ FLAG [${_flags}] added for build type ${_PAR_BUILD}" )
+ else()
+ set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${_flags}" )
+ ecbuild_debug( "C++ FLAG [${_flags}] added" )
+ endif()
+ else()
+ ecbuild_info( "Unrecognised CXX flag [${_flags}] -- skipping" )
+ endif()
+ endif()
+ unset( _flags )
+ unset( _flag_ok )
+ unset( _try_add_flag )
+ endif()
+
+endmacro()
+
+macro( cmake_add_cxx_flags m_cxx_flags )
+ ecbuild_deprecate( " cmake_add_cxx_flags is deprecated, use ecbuild_add_cxx_flags instead." )
+ ecbuild_add_cxx_flags( ${m_cxx_flags} )
+endmacro()
diff --git a/cmake/ecbuild_add_executable.cmake b/cmake/ecbuild_add_executable.cmake
new file mode 100644
index 0000000..4572832
--- /dev/null
+++ b/cmake/ecbuild_add_executable.cmake
@@ -0,0 +1,381 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_add_executable
+# ======================
+#
+# Add an executable with a given list of source files. ::
+#
+# ecbuild_add_executable( TARGET <name>
+# SOURCES <source1> [<source2> ...]
+# [ SOURCES_GLOB <glob1> [<glob2> ...] ]
+# [ SOURCES_EXCLUDE_REGEX <regex1> [<regex2> ...] ]
+# [ OBJECTS <obj1> [<obj2> ...] ]
+# [ TEMPLATES <template1> [<template2> ...] ]
+# [ LIBS <library1> [<library2> ...] ]
+# [ INCLUDES <path1> [<path2> ...] ]
+# [ DEFINITIONS <definition1> [<definition2> ...] ]
+# [ PERSISTENT <file1> [<file2> ...] ]
+# [ GENERATED <file1> [<file2> ...] ]
+# [ DEPENDS <target1> [<target2> ...] ]
+# [ CONDITION <condition1> [<condition2> ...] ]
+# [ NOINSTALL ]
+# [ VERSION <version> | AUTO_VERSION ]
+# [ CFLAGS <flag1> [<flag2> ...] ]
+# [ CXXFLAGS <flag1> [<flag2> ...] ]
+# [ FFLAGS <flag1> [<flag2> ...] ]
+# [ LINKER_LANGUAGE <lang> ]
+# [ OUTPUT_NAME <name> ] )
+#
+# Options
+# -------
+#
+# TARGET : required
+# target name
+#
+# SOURCES : required
+# list of source files
+#
+# SOURCES_GLOB : optional
+# search pattern to find source files to compile (note: not recommend according to CMake guidelines)
+# it is usually better to explicitly list the source files in the CMakeList.txt
+#
+# SOURCES_EXCLUDE_REGEX : optional
+# search pattern to exclude source files from compilation, applies o the results of SOURCES_GLOB
+#
+# OBJECTS : optional
+# list of object libraries to add to this target
+#
+# TEMPLATES : optional
+# list of files specified as SOURCES which are not to be compiled separately
+# (these are commonly template implementation files included in a header)
+#
+# LIBS : optional
+# list of libraries to link against (CMake targets or external libraries)
+#
+# INCLUDES : optional
+# list of paths to add to include directories
+#
+# DEFINITIONS : optional
+# list of definitions to add to preprocessor defines
+#
+# PERSISTENT : optional
+# list of persistent layer object files
+#
+# GENERATED : optional
+# list of files to mark as generated (sets GENERATED source file property)
+#
+# DEPENDS : optional
+# list of targets to be built before this target
+#
+# CONDITION : optional
+# conditional expression which must evaluate to true for this target to be
+# built (must be valid in a CMake ``if`` statement)
+#
+# NOINSTALL : optional
+# do not install the executable
+#
+# VERSION : optional, AUTO_VERSION or LIBS_VERSION is used if not specified
+# version to use as executable version
+#
+# AUTO_VERSION : optional, ignored if VERSION is specified
+# automatically version the executable with the package version
+#
+# CFLAGS : optional
+# list of C compiler flags to use for all C source files
+#
+# CXXFLAGS : optional
+# list of C++ compiler flags to use for all C++ source files
+#
+# FFLAGS : optional
+# list of Fortran compiler flags to use for all Fortran source files
+#
+# LINKER_LANGUAGE : optional
+# sets the LINKER_LANGUAGE property on the target
+#
+# OUTPUT_NAME : optional
+# sets the OUTPUT_NAME property on the target
+#
+##############################################################################
+
+macro( ecbuild_add_executable )
+
+ set( options NOINSTALL AUTO_VERSION )
+ set( single_value_args TARGET COMPONENT LINKER_LANGUAGE VERSION OUTPUT_NAME )
+ set( multi_value_args SOURCES SOURCES_GLOB SOURCES_EXCLUDE_REGEX OBJECTS TEMPLATES LIBS INCLUDES DEPENDS PERSISTENT DEFINITIONS CFLAGS CXXFLAGS FFLAGS GENERATED CONDITION )
+
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_PAR_UNPARSED_ARGUMENTS)
+ ecbuild_critical("Unknown keywords given to ecbuild_add_executable(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if( NOT _PAR_TARGET )
+ ecbuild_critical("The call to ecbuild_add_executable() doesn't specify the TARGET.")
+ endif()
+
+ if( NOT _PAR_SOURCES AND NOT _PAR_OBJECTS AND NOT _PAR_SOURCES_GLOB )
+ ecbuild_critical("The call to ecbuild_add_executable() specifies neither SOURCES nor OBJECTS nor SOURCES_GLOB.")
+ endif()
+
+ ### conditional build
+
+ if( DEFINED _PAR_CONDITION )
+ set(_target_condition_file "${CMAKE_CURRENT_BINARY_DIR}/set_${_PAR_TARGET}_condition.cmake")
+ file( WRITE ${_target_condition_file} " if( ")
+ foreach( term ${_PAR_CONDITION} )
+ file( APPEND ${_target_condition_file} " ${term}")
+ endforeach()
+ file( APPEND ${_target_condition_file} " )\n set(_${_PAR_TARGET}_condition TRUE)\n else()\n set(_${_PAR_TARGET}_condition FALSE)\n endif()\n")
+ include( ${_target_condition_file} )
+ else()
+ set( _${_PAR_TARGET}_condition TRUE )
+ endif()
+
+ if( _${_PAR_TARGET}_condition )
+
+ # add persistent layer files
+ if( DEFINED _PAR_PERSISTENT )
+ if( DEFINED PERSISTENT_NAMESPACE )
+ ecbuild_add_persistent( SRC_LIST _PAR_SOURCES FILES ${_PAR_PERSISTENT} NAMESPACE ${PERSISTENT_NAMESPACE} )
+ else()
+ ecbuild_add_persistent( SRC_LIST _PAR_SOURCES FILES ${_PAR_PERSISTENT} )
+ endif()
+ endif()
+
+ # remove templates from compilation sources
+ if( DEFINED _PAR_TEMPLATES )
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): removing ${_PAR_TEMPLATES} from sources")
+ list( REMOVE_ITEM _PAR_SOURCES ${_PAR_TEMPLATES} )
+ add_custom_target( ${_PAR_TARGET}_templates SOURCES ${_PAR_TEMPLATES} )
+ endif()
+
+ # glob sources
+ unset( _glob_srcs )
+ foreach( pattern ${_PAR_SOURCES_GLOB} )
+ ecbuild_list_add_pattern( LIST _glob_srcs GLOB "${pattern}" )
+ endforeach()
+
+ foreach( pattern ${_PAR_SOURCES_EXCLUDE_REGEX} )
+ ecbuild_list_exclude_pattern( LIST _glob_srcs REGEX "${pattern}" )
+ endforeach()
+
+ # insert already compiled objects (from OBJECT libraries)
+ unset( _all_objects )
+ foreach( _obj ${_PAR_OBJECTS} )
+ list( APPEND _all_objects $<TARGET_OBJECTS:${_obj}> )
+ endforeach()
+
+ list( APPEND _PAR_SOURCES ${_glob_srcs} )
+
+ if( ECBUILD_LIST_SOURCES )
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): sources ${_PAR_SOURCES}")
+ endif()
+
+ add_executable( ${_PAR_TARGET} ${_PAR_SOURCES} ${_all_objects} )
+
+ # ecbuild_echo_target( ${_PAR_TARGET} )
+
+ # add include dirs if defined
+ if( DEFINED _PAR_INCLUDES )
+ list(REMOVE_DUPLICATES _PAR_INCLUDES )
+ foreach( path ${_PAR_INCLUDES} ) # skip NOTFOUND
+ if( path )
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): add ${path} to include_directories")
+ target_include_directories( ${_PAR_TARGET} PRIVATE ${path} )
+ else()
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): ${path} not found - not adding to include_directories")
+ endif()
+ endforeach()
+ endif()
+
+ # set OUTPUT_NAME
+
+ if( DEFINED _PAR_OUTPUT_NAME )
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): set OUTPUT_NAME to ${_PAR_OUTPUT_NAME}")
+ set_target_properties( ${_PAR_TARGET} PROPERTIES OUTPUT_NAME ${_PAR_OUTPUT_NAME} )
+ endif()
+
+ # add extra dependencies
+ if( DEFINED _PAR_DEPENDS)
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): add dependency on ${_PAR_DEPENDS}")
+ add_dependencies( ${_PAR_TARGET} ${_PAR_DEPENDS} )
+ endif()
+
+ # add the link libraries
+ if( DEFINED _PAR_LIBS )
+ list(REMOVE_DUPLICATES _PAR_LIBS )
+ list(REMOVE_ITEM _PAR_LIBS debug)
+ list(REMOVE_ITEM _PAR_LIBS optimized)
+ foreach( lib ${_PAR_LIBS} ) # skip NOTFOUND
+ if( lib )
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): linking with ${lib}")
+ target_link_libraries( ${_PAR_TARGET} ${lib} )
+ else()
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): ${lib} not found - not linking")
+ endif()
+ endforeach()
+ endif()
+
+ # filter sources
+
+ ecbuild_separate_sources( TARGET ${_PAR_TARGET} SOURCES ${_PAR_SOURCES} )
+
+ # ecbuild_debug_var( ${_PAR_TARGET}_h_srcs )
+ # ecbuild_debug_var( ${_PAR_TARGET}_c_srcs )
+ # ecbuild_debug_var( ${_PAR_TARGET}_cxx_srcs )
+ # ecbuild_debug_var( ${_PAR_TARGET}_f_srcs )
+
+ # add local flags
+
+ if( ${_PAR_TARGET}_c_srcs )
+
+ if( ECBUILD_SOURCE_FLAGS )
+ ecbuild_source_flags( ${_PAR_TARGET}_C_SOURCE_FLAGS
+ ${_PAR_TARGET}_c
+ "${_PAR_CFLAGS}"
+ "${${_PAR_TARGET}_c_srcs}" )
+
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): setting source file C flags from ${${_PAR_TARGET}_C_SOURCE_FLAGS}")
+ include( ${${_PAR_TARGET}_C_SOURCE_FLAGS} )
+
+ elseif( DEFINED _PAR_CFLAGS )
+
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): use C flags ${_PAR_CFLAGS}")
+ set_source_files_properties( ${${_PAR_TARGET}_c_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_CFLAGS}" )
+
+ endif()
+ endif()
+
+ if( ${_PAR_TARGET}_cxx_srcs )
+
+ if( ECBUILD_SOURCE_FLAGS )
+ ecbuild_source_flags( ${_PAR_TARGET}_CXX_SOURCE_FLAGS
+ ${_PAR_TARGET}_cxx
+ "${_PAR_CXXFLAGS}"
+ "${${_PAR_TARGET}_cxx_srcs}" )
+
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): setting source file CXX flags from ${${_PAR_TARGET}_CXX_SOURCE_FLAGS}")
+ include( ${${_PAR_TARGET}_CXX_SOURCE_FLAGS} )
+
+ elseif( DEFINED _PAR_CXXFLAGS )
+
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): use C++ flags ${_PAR_CFLAGS}")
+ set_source_files_properties( ${${_PAR_TARGET}_cxx_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_CXXFLAGS}" )
+
+ endif()
+ endif()
+
+ if( ${_PAR_TARGET}_f_srcs )
+
+ if( ECBUILD_SOURCE_FLAGS )
+ ecbuild_source_flags( ${_PAR_TARGET}_Fortran_SOURCE_FLAGS
+ ${_PAR_TARGET}_f
+ "${_PAR_FFLAGS}"
+ "${${_PAR_TARGET}_f_srcs}" )
+
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): setting source file Fortran flags from ${${_PAR_TARGET}_Fortran_SOURCE_FLAGS}")
+ include( ${${_PAR_TARGET}_Fortran_SOURCE_FLAGS} )
+
+ elseif( DEFINED _PAR_FFLAGS )
+
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): use Fortran flags ${_PAR_CFLAGS}")
+ set_source_files_properties( ${${_PAR_TARGET}_f_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_FFLAGS}" )
+
+ endif()
+ endif()
+
+ # define VERSION if requested
+ if( DEFINED _PAR_VERSION )
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): set version to ${_PAR_VERSION}")
+ set_target_properties( ${_PAR_TARGET} PROPERTIES VERSION "${_PAR_VERSION}" )
+ else()
+ if( _PAR_AUTO_VERSION )
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): set version to ${${PNAME}_MAJOR_VERSION}.${${PNAME}_MINOR_VERSION}")
+ set_target_properties( ${_PAR_TARGET} PROPERTIES VERSION "${${PNAME}_MAJOR_VERSION}.${${PNAME}_MINOR_VERSION}" )
+ endif()
+ endif()
+
+ # installation
+
+ if( NOT _PAR_NOINSTALL )
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): installing to ${INSTALL_BIN_DIR}")
+
+ # add installation paths and associate with defined component
+ # if( DEFINED _PAR_COMPONENT )
+ # set( COMPONENT_DIRECTIVE "${_PAR_COMPONENT}" )
+ # else()
+ # set( COMPONENT_DIRECTIVE "${PROJECT_NAME}" )
+ # endif()
+
+ install( TARGETS ${_PAR_TARGET}
+ EXPORT ${PROJECT_NAME}-targets
+ RUNTIME DESTINATION ${INSTALL_BIN_DIR}
+ LIBRARY DESTINATION ${INSTALL_LIB_DIR}
+ ARCHIVE DESTINATION ${INSTALL_LIB_DIR} )
+ # COMPONENT ${COMPONENT_DIRECTIVE} )
+
+ # set build location
+
+ set_property( TARGET ${_PAR_TARGET} PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin )
+
+ # export location of target to other projects -- must be exactly after setting the build location (see previous command)
+
+ export( TARGETS ${_PAR_TARGET} APPEND FILE "${TOP_PROJECT_TARGETS_FILE}" )
+
+ else()
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): not installing")
+ # NOINSTALL targets are always built the build_rpath, not the install_rpath
+ set_property( TARGET ${_PAR_TARGET} PROPERTY SKIP_BUILD_RPATH FALSE )
+ set_property( TARGET ${_PAR_TARGET} PROPERTY BUILD_WITH_INSTALL_RPATH FALSE )
+ endif()
+
+ # add definitions to compilation
+ if( DEFINED _PAR_DEFINITIONS )
+ get_property( _target_defs TARGET ${_PAR_TARGET} PROPERTY COMPILE_DEFINITIONS )
+ list( APPEND _target_defs ${_PAR_DEFINITIONS} )
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): using definitions ${_target_defs}")
+ set_property( TARGET ${_PAR_TARGET} PROPERTY COMPILE_DEFINITIONS ${_target_defs} )
+ endif()
+
+ # set linker language
+ if( DEFINED _PAR_LINKER_LANGUAGE )
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): using linker language ${_PAR_LINKER_LANGUAGE}")
+ set_property( TARGET ${_PAR_TARGET} PROPERTY LINKER_LANGUAGE ${_PAR_LINKER_LANGUAGE} )
+ if( ECBUILD_${_PAR_LINKER_LANGUAGE}_IMPLICIT_LINK_LIBRARIES )
+ target_link_libraries( ${_PAR_TARGET} ${ECBUILD_${_PAR_LINKER_LANGUAGE}_IMPLICIT_LINK_LIBRARIES} )
+ endif()
+ endif()
+
+ if( ECBUILD_IMPLICIT_LINK_LIBRARIES )
+ target_link_libraries( ${_PAR_TARGET} ${ECBUILD_IMPLICIT_LINK_LIBRARIES} )
+ endif()
+
+ # make sure target is removed before - some problems with AIX
+ add_custom_command( TARGET ${_PAR_TARGET} PRE_BUILD COMMAND ${CMAKE_COMMAND} -E remove $<TARGET_FILE:${_PAR_TARGET}> )
+
+ # for the links target
+ if( NOT _PAR_NOINSTALL )
+ ecbuild_link_exe( ${_PAR_TARGET} $<TARGET_FILE_NAME:${_PAR_TARGET}> $<TARGET_FILE:${_PAR_TARGET}> )
+ endif()
+
+ # append to the list of this project targets
+ set( ${PROJECT_NAME}_ALL_EXES ${${PROJECT_NAME}_ALL_EXES} ${_PAR_TARGET} CACHE INTERNAL "" )
+
+ endif()
+
+ # mark source files as used
+ ecbuild_declare_project_files( ${_PAR_SOURCES} )
+ if( DEFINED _PAR_TEMPLATES )
+ ecbuild_declare_project_files( ${_PAR_TEMPLATES} )
+ endif()
+
+endmacro( ecbuild_add_executable )
diff --git a/cmake/ecbuild_add_extra_search_paths.cmake b/cmake/ecbuild_add_extra_search_paths.cmake
new file mode 100644
index 0000000..94ac85b
--- /dev/null
+++ b/cmake/ecbuild_add_extra_search_paths.cmake
@@ -0,0 +1,33 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+###############################################################################
+#
+# macro for adding search paths to CMAKE_PREFIX_PATH
+# for example the ECMWF /usr/local/apps paths
+#
+# usage: ecbuild_add_extra_search_paths( netcdf4 )
+
+function( ecbuild_add_extra_search_paths pkg )
+
+ ecbuild_deprecate( " ecbuild_add_extra_search_paths modifies CMAKE_PREFIX_PATH,"
+ " which can affect future package discovery if not undone by the caller."
+ " The current CMAKE_PREFIX_PATH is being backed up as _CMAKE_PREFIX_PATH"
+ " so it can later be restored." )
+
+ # Back up current CMAKE_PREFIX_PATH so the caller can reset it
+ set( _CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} PARENT_SCOPE )
+
+ string( TOUPPER ${pkg} _PKG )
+
+ ecbuild_list_extra_search_paths( ${pkg} CMAKE_PREFIX_PATH )
+
+ set( CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} PARENT_SCOPE )
+ # ecbuild_debug_var( CMAKE_PREFIX_PATH )
+
+endfunction()
diff --git a/cmake/ecbuild_add_fortran_flags.cmake b/cmake/ecbuild_add_fortran_flags.cmake
new file mode 100644
index 0000000..86cea83
--- /dev/null
+++ b/cmake/ecbuild_add_fortran_flags.cmake
@@ -0,0 +1,98 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_add_fortran_flags
+# =========================
+#
+# Add Fortran compiler flags to CMAKE_Fortran_FLAGS only if supported by the
+# compiler. ::
+#
+# ecbuild_add_fortran_flags( <flag1> [ <flag2> ... ]
+# [ BUILD <build> ]
+# [ NAME <name> ] )
+#
+# Options
+# -------
+#
+# BUILD : optional
+# add flags to ``CMAKE_Fortran_FLAGS_<build>`` instead of
+# ``CMAKE_Fortran_FLAGS``
+#
+# NAME : optional
+# name of the check (if omitted, checks are enumerated)
+#
+##############################################################################
+
+include( CheckFortranCompilerFlag )
+macro( ecbuild_add_fortran_flags m_fortran_flags )
+
+ set( _flags ${m_fortran_flags} )
+
+ if( _flags AND CMAKE_Fortran_COMPILER_LOADED )
+
+ set( options )
+ set( single_value_args BUILD NAME )
+ set( multi_value_args )
+
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ set( _try_add_flag TRUE )
+ if( _PAR_BUILD )
+ string( TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_CAPS )
+ string( TOUPPER ${_PAR_BUILD} _PAR_BUILD_CAPS )
+ if( NOT CMAKE_BUILD_TYPE_CAPS MATCHES "${_PAR_BUILD_CAPS}" )
+ set( _try_add_flag FALSE )
+ endif()
+ endif()
+
+ if( _try_add_flag )
+ if( NOT DEFINED N_FortranFLAG )
+ set( N_FortranFLAG 0 )
+ endif()
+
+ math( EXPR N_FortranFLAG '${N_FortranFLAG}+1' )
+
+ if( NOT ECBUILD_TRUST_FLAGS )
+ if( DEFINED _PAR_NAME )
+ check_fortran_compiler_flag( ${_flags} ${_PAR_NAME} )
+ set( _flag_ok ${${_PAR_NAME}} )
+ else()
+ check_fortran_compiler_flag( ${_flags} Fortran_FLAG_TEST_${N_FortranFLAG} )
+ set( _flag_ok ${Fortran_FLAG_TEST_${N_FortranFLAG}} )
+ endif()
+ else()
+ set( _flag_ok 1 )
+ endif()
+
+ if( _flag_ok )
+ if( _PAR_BUILD )
+ set( CMAKE_Fortran_FLAGS_${_PAR_BUILD} "${CMAKE_Fortran_FLAGS_${_PAR_BUILD}} ${_flags}" )
+ ecbuild_debug( "Fortran FLAG [${_flags}] added for build type ${_PAR_BUILD}" )
+ else()
+ set( CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${_flags}" )
+ ecbuild_debug( "Fortran FLAG [${_flags}] added" )
+ endif()
+ else()
+ ecbuild_info( "Unrecognised Fortran flag [${_flags}] -- skipping" )
+ endif()
+ endif()
+
+ unset( _flags )
+ unset( _flag_ok )
+ unset( _try_add_flag )
+ endif()
+
+endmacro()
+
+macro( cmake_add_fortran_flags m_fortran_flags )
+ ecbuild_deprecate( " cmake_add_fortran_flags is deprecated, use ecbuild_add_fortran_flags instead." )
+ ecbuild_add_fortran_flags( ${m_fortran_flags} )
+endmacro()
diff --git a/cmake/ecbuild_add_library.cmake b/cmake/ecbuild_add_library.cmake
new file mode 100644
index 0000000..48602a4
--- /dev/null
+++ b/cmake/ecbuild_add_library.cmake
@@ -0,0 +1,587 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_add_library
+# ===================
+#
+# Add a library with a given list of source files. ::
+#
+# ecbuild_add_library( TARGET <name>
+# SOURCES <source1> [<source2> ...]
+# [ SOURCES_GLOB <glob1> [<glob2> ...] ]
+# [ SOURCES_EXCLUDE_REGEX <regex1> [<regex2> ...] ]
+# [ TYPE SHARED|STATIC|MODULE|OBJECT ]
+# [ OBJECTS <obj1> [<obj2> ...] ]
+# [ TEMPLATES <template1> [<template2> ...] ]
+# [ LIBS <library1> [<library2> ...] ]
+# [ INCLUDES <path1> [<path2> ...] ]
+# [ PRIVATE_INCLUDES <path1> [<path2> ...] ]
+# [ PUBLIC_INCLUDES <path1> [<path2> ...] ]
+# [ DEFINITIONS <definition1> [<definition2> ...] ]
+# [ PERSISTENT <file1> [<file2> ...] ]
+# [ GENERATED <file1> [<file2> ...] ]
+# [ DEPENDS <target1> [<target2> ...] ]
+# [ CONDITION <condition1> [<condition2> ...] ]
+# [ NOINSTALL ]
+# [ HEADER_DESTINATION <path> ]
+# [ INSTALL_HEADERS LISTED|ALL ]
+# [ INSTALL_HEADERS_LIST <header1> [<header2> ...] ]
+# [ INSTALL_HEADERS_REGEX <pattern> ]
+# [ VERSION <version> | AUTO_VERSION ]
+# [ CFLAGS <flag1> [<flag2> ...] ]
+# [ CXXFLAGS <flag1> [<flag2> ...] ]
+# [ FFLAGS <flag1> [<flag2> ...] ]
+# [ LINKER_LANGUAGE <lang> ]
+# [ OUTPUT_NAME <name> ] )
+#
+# Options
+# -------
+#
+# TARGET : required
+# target name
+#
+# SOURCES : required
+# list of source files
+#
+# TYPE : optional
+# library type, one of:
+#
+# :SHARED: libraries are linked dynamically and loaded at runtime
+# :STATIC: archives of object files for use when linking other targets.
+# :MODULE: plugins that are not linked into other targets but may be loaded
+# dynamically at runtime using dlopen-like functionality
+# :OBJECT: files are just compiled into objects
+#
+# SOURCES_GLOB : optional
+# search pattern to find source files to compile (note: not recommend according to CMake guidelines)
+# it is usually better to explicitly list the source files in the CMakeList.txt
+#
+# SOURCES_EXCLUDE_REGEX : optional
+# search pattern to exclude source files from compilation, applies o the results of SOURCES_GLOB
+#
+# OBJECTS : optional
+# list of object libraries to add to this target
+#
+# TEMPLATES : optional
+# list of files specified as SOURCES which are not to be compiled separately
+# (these are commonly template implementation files included in a header)
+#
+# LIBS : optional
+# list of libraries to link against (CMake targets or external libraries)
+#
+# INCLUDES : (DEPRECATED) optional
+# list of paths to add to include directories, behaves as PUBLIC_INCLUDES if CMake >= 2.8.11
+# and reverts to include_directories() for CMake < 2.8.11
+#
+# PUBLIC_INCLUDES : optional
+# list of paths to add to include directories which will be publicly exported to other projects
+#
+# PRIVATE_INCLUDES : optional
+# list of paths to add to include directories which won't be exported to other projects,
+# equivalent to using a include_directories() before calling this macro
+#
+# DEFINITIONS : optional
+# list of definitions to add to preprocessor defines
+#
+# PERSISTENT : optional
+# list of persistent layer object files
+#
+# GENERATED : optional
+# list of files to mark as generated (sets GENERATED source file property)
+#
+# DEPENDS : optional
+# list of targets to be built before this target
+#
+# CONDITION : optional
+# conditional expression which must evaluate to true for this target to be
+# built (must be valid in a CMake ``if`` statement)
+#
+# NOINSTALL : optional
+# do not install the library
+#
+# HEADER_DESTINATION
+# directory to install headers (if not specified, INSTALL_INCLUDE_DIR is used)
+#
+# INSTALL_HEADERS : optional
+# specify which header files to install:
+#
+# :LISTED: install header files listed as SOURCES
+# :ALL: install all header files ending in .h, .hh, .hpp, .H
+#
+# INSTALL_HEADERS_LIST : optional
+# list of extra headers to install
+#
+# INSTALL_HEADERS_REGEX : optional
+# regular expression to match extra headers to install
+#
+# VERSION : optional, AUTO_VERSION or LIBS_VERSION is used if not specified
+# version to use as library version
+#
+# AUTO_VERSION : optional, ignored if VERSION is specified
+# automatically version the library with the package version
+#
+# CFLAGS : optional
+# list of C compiler flags to use for all C source files
+#
+# CXXFLAGS : optional
+# list of C++ compiler flags to use for all C++ source files
+#
+# FFLAGS : optional
+# list of Fortran compiler flags to use for all Fortran source files
+#
+# LINKER_LANGUAGE : optional
+# sets the LINKER_LANGUAGE property on the target
+#
+# OUTPUT_NAME : optional
+# sets the OUTPUT_NAME property on the target
+#
+##############################################################################
+
+function( ecbuild_add_library_impl )
+
+ set( options NOINSTALL AUTO_VERSION )
+ set( single_value_args TARGET TYPE COMPONENT INSTALL_HEADERS INSTALL_HEADERS_REGEX LINKER_LANGUAGE HEADER_DESTINATION VERSION OUTPUT_NAME )
+ set( multi_value_args SOURCES SOURCES_GLOB SOURCES_EXCLUDE_REGEX OBJECTS TEMPLATES LIBS INCLUDES PRIVATE_INCLUDES PUBLIC_INCLUDES DEPENDS PERSISTENT DEFINITIONS INSTALL_HEADERS_LIST CFLAGS CXXFLAGS FFLAGS GENERATED CONDITION )
+
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_PAR_UNPARSED_ARGUMENTS)
+ ecbuild_critical("Unknown keywords given to ecbuild_add_library(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if( NOT _PAR_TARGET )
+ ecbuild_critical("The call to ecbuild_add_library() doesn't specify the TARGET.")
+ endif()
+
+ if( NOT _PAR_SOURCES AND NOT _PAR_OBJECTS AND NOT _PAR_SOURCES_GLOB )
+ ecbuild_critical("The call to ecbuild_add_library() specifies neither SOURCES nor OBJECTS nor SOURCES_GLOB")
+ endif()
+
+ ### conditional build
+
+ if( DEFINED _PAR_CONDITION )
+ set(_target_condition_file "${CMAKE_CURRENT_BINARY_DIR}/set_${_PAR_TARGET}_condition.cmake")
+ file( WRITE ${_target_condition_file} " if( ")
+ foreach( term ${_PAR_CONDITION} )
+ file( APPEND ${_target_condition_file} " ${term}")
+ endforeach()
+ file( APPEND ${_target_condition_file} " )\n set(_${_PAR_TARGET}_condition TRUE)\n else()\n set(_${_PAR_TARGET}_condition FALSE)\n endif()\n")
+ include( ${_target_condition_file} )
+ else()
+ set( _${_PAR_TARGET}_condition TRUE )
+ endif()
+
+ if( _${_PAR_TARGET}_condition )
+
+ # defines the type of library
+ if( DEFINED _PAR_TYPE )
+ # checks that is either SHARED or STATIC or MODULE
+ if( NOT _PAR_TYPE MATCHES "STATIC" AND
+ NOT _PAR_TYPE MATCHES "SHARED" AND
+ NOT _PAR_TYPE MATCHES "OBJECT" AND
+ NOT _PAR_TYPE MATCHES "MODULE" )
+ ecbuild_critical( "library type must be one of [ STATIC | SHARED | MODULE | OBJECT ]" )
+ endif()
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): library type is ${_PAR_TYPE}")
+ endif()
+
+
+ # add persistent layer files
+ if( DEFINED _PAR_PERSISTENT )
+ if( DEFINED PERSISTENT_NAMESPACE )
+ ecbuild_add_persistent( SRC_LIST _PAR_SOURCES FILES ${_PAR_PERSISTENT} NAMESPACE ${PERSISTENT_NAMESPACE} )
+ else()
+ ecbuild_add_persistent( SRC_LIST _PAR_SOURCES FILES ${_PAR_PERSISTENT} )
+ endif()
+ endif()
+
+ # remove templates from compilation sources
+ if( DEFINED _PAR_TEMPLATES )
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): removing ${_PAR_TEMPLATES} from sources")
+ list( REMOVE_ITEM _PAR_SOURCES ${_PAR_TEMPLATES} )
+ add_custom_target( ${_PAR_TARGET}_templates SOURCES ${_PAR_TEMPLATES} )
+ endif()
+
+ # glob sources
+ unset( _glob_srcs )
+ foreach( pattern ${_PAR_SOURCES_GLOB} )
+ ecbuild_list_add_pattern( LIST _glob_srcs GLOB "${pattern}" )
+ endforeach()
+
+ foreach( pattern ${_PAR_SOURCES_EXCLUDE_REGEX} )
+ ecbuild_list_exclude_pattern( LIST _glob_srcs REGEX "${pattern}" )
+ endforeach()
+
+ # insert already compiled objects (from OBJECT libraries)
+ unset( _all_objects )
+ foreach( _obj ${_PAR_OBJECTS} )
+ list( APPEND _all_objects $<TARGET_OBJECTS:${_obj}> )
+ endforeach()
+
+ list( APPEND _PAR_SOURCES ${_glob_srcs} )
+
+ if( ECBUILD_LIST_SOURCES )
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): sources ${_PAR_SOURCES}")
+ endif()
+
+ add_library( ${_PAR_TARGET} ${_PAR_TYPE} ${_PAR_SOURCES} ${_all_objects} )
+
+ # ecbuild_echo_target( ${_PAR_TARGET} )
+
+ # set OUTPUT_NAME
+
+ if( DEFINED _PAR_OUTPUT_NAME )
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): set OUTPUT_NAME to ${_PAR_OUTPUT_NAME}")
+ set_target_properties( ${_PAR_TARGET} PROPERTIES OUTPUT_NAME ${_PAR_OUTPUT_NAME} )
+ endif()
+
+ # add extra dependencies
+ if( DEFINED _PAR_DEPENDS)
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): add dependency on ${_PAR_DEPENDS}")
+ add_dependencies( ${_PAR_TARGET} ${_PAR_DEPENDS} )
+ endif()
+
+ # add the link libraries
+ if( DEFINED _PAR_LIBS )
+ list(REMOVE_DUPLICATES _PAR_LIBS )
+ list(REMOVE_ITEM _PAR_LIBS debug)
+ list(REMOVE_ITEM _PAR_LIBS optimized)
+ foreach( lib ${_PAR_LIBS} ) # skip NOTFOUND
+ if( lib )
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): linking with ${lib}")
+ target_link_libraries( ${_PAR_TARGET} ${lib} )
+ else()
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): ${lib} not found - not linking")
+ endif()
+ endforeach()
+ endif()
+
+ # add include dirs if defined
+ if( DEFINED _PAR_INCLUDES )
+ list( REMOVE_DUPLICATES _PAR_INCLUDES )
+ foreach( path ${_PAR_INCLUDES} ) # skip NOTFOUND
+ if( path )
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): add ${path} to include_directories")
+ if( "${CMAKE_VERSION}" VERSION_LESS "2.8.11" OR ECBUILD_USE_INCLUDE_DIRECTORIES )
+ include_directories( ${path} )
+ else()
+ target_include_directories( ${_PAR_TARGET} PUBLIC ${path} )
+ endif()
+ else()
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): ${path} not found - not adding to include_directories")
+ endif()
+ endforeach()
+ endif()
+
+ # add private include dirs if defined
+ if( DEFINED _PAR_PRIVATE_INCLUDES )
+ if( "${CMAKE_VERSION}" VERSION_LESS "2.8.11" )
+ ecbuild_critical("ecbuild_add_library(${_PAR_TARGET}): cannot use PRIVATE_INCLUDES with CMake < 2.8.11" )
+ endif()
+ list( REMOVE_DUPLICATES _PAR_PRIVATE_INCLUDES )
+ foreach( path ${_PAR_PRIVATE_INCLUDES} ) # skip NOTFOUND
+ if( path )
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): add ${path} to include_directories")
+ target_include_directories( ${_PAR_TARGET} PRIVATE ${path} )
+ else()
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): ${path} not found - not adding to include_directories")
+ endif()
+ endforeach()
+ endif()
+
+ # add public include dirs if defined
+ if( DEFINED _PAR_PUBLIC_INCLUDES )
+ if( "${CMAKE_VERSION}" VERSION_LESS "2.8.11" )
+ ecbuild_critical("ecbuild_add_library(${_PAR_TARGET}): cannot use PUBLIC_INCLUDES with CMake < 2.8.11" )
+ endif()
+ list( REMOVE_DUPLICATES _PAR_PUBLIC_INCLUDES )
+ foreach( path ${_PAR_PUBLIC_INCLUDES} ) # skip NOTFOUND
+ if( path )
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): add ${path} to include_directories")
+ target_include_directories( ${_PAR_TARGET} PUBLIC ${path} )
+ else()
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): ${path} not found - not adding to include_directories")
+ endif()
+ endforeach()
+ endif()
+
+ # FIX: Cray compiler PIC option is not detected by CMake
+
+ get_property( _target_pic TARGET ${_PAR_TARGET} PROPERTY POSITION_INDEPENDENT_CODE )
+ if( _target_pic )
+ if( "${CMAKE_C_COMPILER_ID}" STREQUAL "Cray" )
+ set( _PAR_CFLAGS "-fPIC -h PIC ${_PAR_CFLAGS}" )
+ endif()
+ if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Cray" )
+ set( _PAR_CXXFLAGS "-fPIC -h PIC ${_PAR_CXXFLAGS}" )
+ endif()
+ if( "${CMAKE_Fortran_COMPILER_ID}" STREQUAL "Cray" )
+ set( _PAR_FFLAGS "-fPIC -h PIC ${_PAR_FFLAGS}" )
+ endif()
+ endif()
+
+ # define VERSION if requested
+ if( DEFINED _PAR_VERSION )
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): set version to ${_PAR_VERSION}")
+ set_target_properties( ${_PAR_TARGET} PROPERTIES VERSION "${_PAR_VERSION}" )
+ else()
+ if( _PAR_AUTO_VERSION OR LIBS_VERSION MATCHES "[Aa][Uu][Tt][Oo]")
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): set version to ${${PNAME}_MAJOR_VERSION}.${${PNAME}_MINOR_VERSION} (auto)")
+ set_target_properties( ${_PAR_TARGET} PROPERTIES VERSION "${${PNAME}_MAJOR_VERSION}.${${PNAME}_MINOR_VERSION}" )
+ endif()
+ if( LIBS_VERSION AND NOT LIBS_VERSION MATCHES "[Aa][Uu][Tt][Oo]" )
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): set version to ${LIBS_VERSION}")
+ set_target_properties( ${_PAR_TARGET} PROPERTIES VERSION "${LIBS_VERSION}" )
+ endif()
+ endif()
+
+ # filter sources
+
+ if( _PAR_SOURCES )
+ ecbuild_separate_sources( TARGET ${_PAR_TARGET} SOURCES ${_PAR_SOURCES} )
+ endif()
+
+ # ecbuild_debug_var( ${_PAR_TARGET}_h_srcs )
+ # ecbuild_debug_var( ${_PAR_TARGET}_c_srcs )
+ # ecbuild_debug_var( ${_PAR_TARGET}_cxx_srcs )
+ # ecbuild_debug_var( ${_PAR_TARGET}_f_srcs )
+
+ # add local flags
+
+ if( ${_PAR_TARGET}_c_srcs )
+
+ if( ECBUILD_SOURCE_FLAGS )
+ ecbuild_source_flags( ${_PAR_TARGET}_C_SOURCE_FLAGS
+ ${_PAR_TARGET}_c
+ "${_PAR_CFLAGS}"
+ "${${_PAR_TARGET}_c_srcs}" )
+
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): setting source file C flags from ${${_PAR_TARGET}_C_SOURCE_FLAGS}")
+ include( ${${_PAR_TARGET}_C_SOURCE_FLAGS} )
+
+ elseif( DEFINED _PAR_CFLAGS )
+
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): use C flags ${_PAR_CFLAGS}")
+ set_source_files_properties( ${${_PAR_TARGET}_c_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_CFLAGS}" )
+
+ endif()
+ endif()
+
+ if( ${_PAR_TARGET}_cxx_srcs )
+
+ if( ECBUILD_SOURCE_FLAGS )
+ ecbuild_source_flags( ${_PAR_TARGET}_CXX_SOURCE_FLAGS
+ ${_PAR_TARGET}_cxx
+ "${_PAR_CXXFLAGS}"
+ "${${_PAR_TARGET}_cxx_srcs}" )
+
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): setting source file CXX flags from ${${_PAR_TARGET}_CXX_SOURCE_FLAGS}")
+ include( ${${_PAR_TARGET}_CXX_SOURCE_FLAGS} )
+
+ elseif( DEFINED _PAR_CXXFLAGS )
+
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): use C++ flags ${_PAR_CFLAGS}")
+ set_source_files_properties( ${${_PAR_TARGET}_cxx_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_CXXFLAGS}" )
+
+ endif()
+ endif()
+
+ if( ${_PAR_TARGET}_f_srcs )
+
+ if( ECBUILD_SOURCE_FLAGS )
+ ecbuild_source_flags( ${_PAR_TARGET}_Fortran_SOURCE_FLAGS
+ ${_PAR_TARGET}_f
+ "${_PAR_FFLAGS}"
+ "${${_PAR_TARGET}_f_srcs}" )
+
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): setting source file Fortran flags from ${${_PAR_TARGET}_Fortran_SOURCE_FLAGS}")
+ include( ${${_PAR_TARGET}_Fortran_SOURCE_FLAGS} )
+
+ elseif( DEFINED _PAR_FFLAGS )
+
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): use Fortran flags ${_PAR_CFLAGS}")
+ set_source_files_properties( ${${_PAR_TARGET}_f_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_FFLAGS}" )
+
+ endif()
+ endif()
+
+ if( DEFINED _PAR_GENERATED )
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): mark as generated ${_PAR_GENERATED}")
+ set_source_files_properties( ${_PAR_GENERATED} PROPERTIES GENERATED 1 )
+ endif()
+
+ # set linker language
+ if( DEFINED _PAR_LINKER_LANGUAGE )
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): using linker language ${_PAR_LINKER_LANGUAGE}")
+ set_property( TARGET ${_PAR_TARGET} PROPERTY LINKER_LANGUAGE ${_PAR_LINKER_LANGUAGE} )
+ if( ECBUILD_${_PAR_LINKER_LANGUAGE}_IMPLICIT_LINK_LIBRARIES )
+ target_link_libraries( ${_PAR_TARGET} ${ECBUILD_${_PAR_LINKER_LANGUAGE}_IMPLICIT_LINK_LIBRARIES} )
+ endif()
+ endif()
+
+ if( ECBUILD_IMPLICIT_LINK_LIBRARIES )
+ target_link_libraries( ${_PAR_TARGET} ${ECBUILD_IMPLICIT_LINK_LIBRARIES} )
+ endif()
+
+ # installation (except for OBJECT libraries)
+
+ if( NOT _PAR_NOINSTALL AND NOT _PAR_TYPE MATCHES "OBJECT" )
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): installing to ${INSTALL_LIB_DIR}")
+
+ # and associate with defined component
+ # if( DEFINED _PAR_COMPONENT )
+ # set( COMPONENT_DIRECTIVE "${_PAR_COMPONENT}" )
+ # else()
+ # set( COMPONENT_DIRECTIVE "${PROJECT_NAME}" )
+ # endif()
+
+ install( TARGETS ${_PAR_TARGET}
+ EXPORT ${PROJECT_NAME}-targets
+ RUNTIME DESTINATION ${INSTALL_BIN_DIR}
+ LIBRARY DESTINATION ${INSTALL_LIB_DIR}
+ ARCHIVE DESTINATION ${INSTALL_LIB_DIR} )
+ # COMPONENT ${COMPONENT_DIRECTIVE} )
+
+ # install headers
+ if( _PAR_HEADER_DESTINATION )
+ set( _h_destination "${_PAR_HEADER_DESTINATION}" )
+ else()
+ set( _h_destination "${INSTALL_INCLUDE_DIR}" )
+ endif()
+
+ if( _PAR_INSTALL_HEADERS )
+ if( _PAR_INSTALL_HEADERS MATCHES "LISTED" )
+ foreach( file ${${_PAR_TARGET}_h_srcs} )
+ get_filename_component( _file_dir ${file} PATH )
+ install( FILES ${file} DESTINATION "${_h_destination}/${_file_dir}" )
+ endforeach()
+ if( DEFINED _PAR_TEMPLATES )
+ foreach( file ${_PAR_TEMPLATES} )
+ get_filename_component( _file_dir ${file} PATH )
+ install( FILES ${file} DESTINATION "${_h_destination}/${_file_dir}" )
+ endforeach()
+ endif()
+ if( DEFINED _PAR_PERSISTENT )
+ foreach( file ${_PAR_PERSISTENT} )
+ get_filename_component( _file_dir ${file} PATH )
+ get_filename_component( _file_we ${file} NAME_WE )
+ set( pfile "${CMAKE_CURRENT_BINARY_DIR}/${_file_dir}/${_file_we}.b" )
+ install( FILES ${pfile} DESTINATION "${_h_destination}/${_file_dir}" )
+ endforeach()
+ endif()
+ endif()
+ if( _PAR_INSTALL_HEADERS MATCHES "ALL" ) # "(\\.h|\\.b|\\.hxx|\\.hh|\\.hpp|\\.H)" ????
+ install( DIRECTORY ./ DESTINATION ${_h_destination} FILES_MATCHING PATTERN "*.h" )
+ install( DIRECTORY ./ DESTINATION ${_h_destination} FILES_MATCHING PATTERN "*.hh" )
+ install( DIRECTORY ./ DESTINATION ${_h_destination} FILES_MATCHING PATTERN "*.hpp" )
+ install( DIRECTORY ./ DESTINATION ${_h_destination} FILES_MATCHING PATTERN "*.H" )
+ endif()
+ endif()
+
+ if( DEFINED _PAR_INSTALL_HEADERS_LIST )
+ install( FILES ${_PAR_INSTALL_HEADERS_LIST} DESTINATION ${_h_destination} )
+ endif()
+
+ if( DEFINED _PAR_INSTALL_HEADERS_REGEX )
+ install( DIRECTORY ./ DESTINATION ${_h_destination} FILES_MATCHING PATTERN "${_PAR_INSTALL_HEADERS_REGEX}")
+ endif()
+
+ # set build location
+
+ set_property( TARGET ${_PAR_TARGET} PROPERTY LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
+ set_property( TARGET ${_PAR_TARGET} PROPERTY ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
+
+ # export location of target to other projects -- must be exactly after setting the build location (see previous 2 commands)
+
+ export( TARGETS ${_PAR_TARGET} APPEND FILE "${TOP_PROJECT_TARGETS_FILE}" )
+
+ endif()
+
+ # add definitions to compilation
+ if( DEFINED _PAR_DEFINITIONS )
+ get_property( _target_defs TARGET ${_PAR_TARGET} PROPERTY COMPILE_DEFINITIONS )
+ list( APPEND _target_defs ${_PAR_DEFINITIONS} )
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): using definitions ${_target_defs}")
+ set_property( TARGET ${_PAR_TARGET} PROPERTY COMPILE_DEFINITIONS ${_target_defs} )
+ endif()
+
+ # make sure target is removed before - some problems with AIX
+ if( NOT _PAR_TYPE MATCHES "OBJECT" )
+ add_custom_command( TARGET ${_PAR_TARGET} PRE_BUILD COMMAND ${CMAKE_COMMAND} -E remove $<TARGET_FILE:${_PAR_TARGET}> )
+ endif()
+
+ # for the links target
+ if( NOT _PAR_NOINSTALL )
+ ecbuild_link_lib( ${_PAR_TARGET} $<TARGET_FILE_NAME:${_PAR_TARGET}> $<TARGET_FILE:${_PAR_TARGET}> )
+ endif()
+
+ # append to the list of this project targets
+ set( ${PROJECT_NAME}_ALL_LIBS ${${PROJECT_NAME}_ALL_LIBS} ${_PAR_TARGET} CACHE INTERNAL "" )
+
+ endif()
+
+ # mark source files as used
+ ecbuild_declare_project_files( ${_PAR_SOURCES} )
+ if( DEFINED _PAR_TEMPLATES )
+ ecbuild_declare_project_files( ${_PAR_TEMPLATES} )
+ endif()
+
+endfunction( ecbuild_add_library_impl )
+
+##############################################################################
+# auxiliary macro for adding a library
+##############################################################################
+
+macro( ecbuild_add_library )
+
+ set( options )
+ set( single_value_args TARGET TYPE )
+ set( multi_value_args )
+
+ cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if( DEFINED _p_TYPE ) # don't do anything if TYPE was specified
+
+ if( _p_TYPE MATCHES "[Bb][Oo][Tt][Hh]" ) # build both types
+
+ ecbuild_add_library_impl( TARGET ${_p_TARGET} TYPE SHARED ${_p_UNPARSED_ARGUMENTS} )
+ ecbuild_add_library_impl( TARGET ${_p_TARGET}-static TYPE STATIC ${_p_UNPARSED_ARGUMENTS} OUTPUT_NAME ${_p_TARGET} DEPENDS ${_p_TARGET} )
+
+ else()
+
+ ecbuild_add_library_impl( ${ARGV} )
+
+ endif()
+
+ else()
+
+ if( NOT DEFINED _p_TARGET )
+ ecbuild_critical("The call to ecbuild_add_library() doesn't specify the TARGET.")
+ else()
+
+ if( BUILD_SHARED_LIBS MATCHES "[Bb][Oo][Tt][Hh]" ) # build both types
+
+ ecbuild_add_library_impl( TARGET ${_p_TARGET} TYPE SHARED ${_p_UNPARSED_ARGUMENTS} )
+ ecbuild_add_library_impl( TARGET ${_p_TARGET}-static TYPE STATIC ${_p_UNPARSED_ARGUMENTS} DEPENDS ${_p_TARGET} )
+
+ set_target_properties( ${_p_TARGET}-static PROPERTIES OUTPUT_NAME ${_p_TARGET} )
+
+ else()
+
+ ecbuild_add_library_impl( ${ARGV} )
+
+ endif()
+
+ endif()
+
+ endif()
+
+endmacro( ecbuild_add_library )
diff --git a/cmake/ecbuild_add_option.cmake b/cmake/ecbuild_add_option.cmake
new file mode 100644
index 0000000..c270517
--- /dev/null
+++ b/cmake/ecbuild_add_option.cmake
@@ -0,0 +1,314 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_add_option
+# ==================
+#
+# Add a CMake configuration option, which may depend on a list of packages. ::
+#
+# ecbuild_add_option( FEATURE <name>
+# [ DEFAULT ON|OFF ]
+# [ DESCRIPTION <description> ]
+# [ PURPOSE <purpose> ]
+# [ REQUIRED_PACKAGES <package1> [<package2> ...] ]
+# [ CONDITION <condition1> [<condition2> ...] ]
+# [ ADVANCED ] )
+#
+# Options
+# -------
+#
+# FEATURE : required
+# name of the feature / option
+#
+# DEFAULT : optional, defaults to ON
+# if set to ON, the feature is enabled even if not explicitly requested
+#
+# DESCRIPTION : optional
+# string describing the feature (shown in summary and stored in the cache)
+#
+# TYPE : optional, one of RUNTIME|OPTIONAL|RECOMMENDED|REQUIRED
+# type of dependency of the project on this package (defaults to OPTIONAL)
+#
+# PURPOSE : optional
+# string describing which functionality this package enables in the project
+#
+# REQUIRED_PACKAGES : optional
+# list of packages required to be found for this feature to be enabled
+#
+# The package specification can have one of two forms. Either ::
+#
+# "<package> [ <version> ... ]"
+#
+# to search for a given package using the CMake ``find_package`` mechanism.
+# The entire specification must be enclosed in quotes and is passed on
+# verbatim. Any options of ``find_package`` are supported.
+#
+# The other specification must start with ``PROJECT`` like this ::
+#
+# "PROJECT <name> [ VERSION <version> ... ]"
+#
+# and is used to search for an ecBuild project via ``ecbuild_use_package``.
+# The entire specification must be enclosed in quotes and is passed on
+# verbatim. Any options of ``ecbuild_use_package`` are supported.
+#
+# CONDITION : optional
+# conditional expression which must evaluate to true for this option to be
+# enabled (must be valid in a CMake ``if`` statement)
+#
+# ADVANCED : optional
+# mark the feature as advanced
+#
+# Usage
+# -----
+#
+# Features with ``DEFAULT OFF`` need to be explcitly enabled by the user with
+# ``-DENABLE_<FEATURE>=ON``. If a feature is enabled, all ``REQUIRED_PACKAGES``
+# are found and ``CONDITION`` is met, ecBuild sets the variable
+# ``HAVE_<FEATURE>`` to ``ON``. This is the variable to use to check for the
+# availability of the feature.
+#
+# If a feature is explicitly enabled but the required packages are not found,
+# configuration fails. This only applies when configuring from *clean cache*.
+# With an already populated cache, use ``-DENABLE_<FEATURE>=REQUIRE`` to make
+# the feature a required feature (this cannot be done via the CMake GUI).
+#
+##############################################################################
+
+macro( ecbuild_add_option )
+
+ set( options ADVANCED )
+ set( single_value_args FEATURE DEFAULT DESCRIPTION TYPE PURPOSE )
+ set( multi_value_args REQUIRED_PACKAGES CONDITION )
+
+ cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if( _p_UNPARSED_ARGUMENTS )
+ ecbuild_critical("Unknown keywords given to ecbuild_add_option(): \"${_p_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ # check FEATURE parameter
+
+ if( NOT _p_FEATURE )
+ ecbuild_critical("The call to ecbuild_add_option() doesn't specify the FEATURE.")
+ endif()
+
+ # check DEFAULT parameter
+
+ if( NOT DEFINED _p_DEFAULT )
+ set( _p_DEFAULT ON )
+ else()
+ if( NOT _p_DEFAULT MATCHES "[Oo][Nn]" AND NOT _p_DEFAULT MATCHES "[Oo][Ff][Ff]" )
+ ecbuild_critical("In macro ecbuild_add_option(), DEFAULT is either ON or OFF: \"${_p_DEFAULT}\"")
+ endif()
+ endif()
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): defaults to ${_p_DEFAULT}")
+
+ if( NOT _p_TYPE )
+ set( _p_TYPE OPTIONAL )
+ endif()
+
+ # check CONDITION parameter
+ if( DEFINED _p_CONDITION )
+ set(_feature_condition_file "${CMAKE_CURRENT_BINARY_DIR}/set_${_p_FEATURE}_condition.cmake")
+ file( WRITE ${_feature_condition_file} " if( ")
+ foreach( term ${_p_CONDITION} )
+ file( APPEND ${_feature_condition_file} " ${term}")
+ endforeach()
+ file( APPEND ${_feature_condition_file} " )\n set(_${_p_FEATURE}_condition TRUE)\n else()\n set(_${_p_FEATURE}_condition FALSE)\n endif()\n")
+ include( ${_feature_condition_file} )
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): checking condition ${_p_CONDITION} -> ${_${_p_FEATURE}_condition}")
+ else()
+ set( _${_p_FEATURE}_condition TRUE )
+ endif()
+
+ # check if user provided value
+
+ get_property( _in_cache CACHE ENABLE_${_p_FEATURE} PROPERTY VALUE )
+
+ # A feature set to REQUIRE is always treated as explicitly enabled
+ if( ENABLE_${_p_FEATURE} MATCHES "REQUIRE" )
+ set( ENABLE_${_p_FEATURE} ON CACHE BOOL "" FORCE )
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): ENABLE_${_p_FEATURE} was required")
+ set( ${_p_FEATURE}_user_provided_input 1 CACHE BOOL "" FORCE )
+ elseif( NOT "${ENABLE_${_p_FEATURE}}" STREQUAL "" AND _in_cache )
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): ENABLE_${_p_FEATURE} was found in cache")
+ set( ${_p_FEATURE}_user_provided_input 1 CACHE BOOL "" )
+ else()
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): ENABLE_${_p_FEATURE} not found in cache")
+ set( ${_p_FEATURE}_user_provided_input 0 CACHE BOOL "" )
+ endif()
+
+ mark_as_advanced( ${_p_FEATURE}_user_provided_input )
+
+
+ # define the option -- for cmake GUI
+
+ option( ENABLE_${_p_FEATURE} "${_p_DESCRIPTION}" ${_p_DEFAULT} )
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): defining option ENABLE_${_p_FEATURE} '${_p_DESCRIPTION}' ${_p_DEFAULT}")
+ ecbuild_set_feature( ${_p_FEATURE} ENABLED ${_p_DEFAULT} )
+ set_package_properties( ${_p_FEATURE} PROPERTIES
+ DESCRIPTION "${_p_DESCRIPTION}"
+ TYPE ${_p_TYPE}
+ PURPOSE "${_p_PURPOSE}" )
+
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): ENABLE_${_p_FEATURE} = ${ENABLE_${_p_FEATURE}}")
+ set( _do_search ${ENABLE_${_p_FEATURE}} )
+ if( _p_FEATURE STREQUAL "OMP" )
+ set( _do_search TRUE )
+ endif()
+
+ if( _do_search )
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): feature enabled")
+
+ set( HAVE_${_p_FEATURE} 1 )
+
+ if( _${_p_FEATURE}_condition )
+
+ ### search for dependent packages
+
+ set( _failed_to_find_packages ) # clear variable
+ foreach( pkg ${_p_REQUIRED_PACKAGES} )
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): searching for dependent package ${pkg}")
+
+ string(REPLACE " " ";" pkglist ${pkg}) # string to list
+
+ list( GET pkglist 0 pkgname )
+
+ if( pkgname STREQUAL "PROJECT" ) # if 1st entry is PROJECT, then we are looking for a ecbuild project
+ set( pkgproject 1 )
+ list( GET pkglist 1 pkgname )
+ else() # else 1st entry is package name
+ set( pkgproject 0 )
+ endif()
+
+ # ecbuild_debug_var( pkg )
+ # ecbuild_debug_var( pkglist )
+ # ecbuild_debug_var( pkgname )
+
+ string( TOUPPER ${pkgname} pkgUPPER )
+ string( TOLOWER ${pkgname} pkgLOWER )
+
+ if( ${pkgname}_FOUND OR ${pkgUPPER}_FOUND OR ${pkgLOWER}_FOUND )
+
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): ${pkgname} has already been found")
+ set( ${pkgname}_already_found 1 )
+
+ else()
+
+ if( pkgproject )
+
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): searching for ecbuild project ${pkgname}")
+ ecbuild_use_package( ${pkglist} )
+
+ else()
+
+ if( pkgname STREQUAL "MPI" )
+ set( _find_args ${pkglist} )
+ list( REMOVE_ITEM _find_args "MPI" )
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): searching for MPI")
+ ecbuild_find_mpi( ${_find_args} )
+ elseif( pkgname STREQUAL "OMP" )
+ set( _find_args ${pkglist} )
+ list( REMOVE_ITEM _find_args "OMP" )
+ if( NOT ENABLE_${_p_FEATURE} )
+ list( APPEND _find_args STUBS )
+ endif()
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): searching for OpenMP")
+ ecbuild_find_omp( ${_find_args} )
+ elseif( pkgname STREQUAL "Python" OR pkgname STREQUAL "PYTHON" )
+ set( _find_args ${pkglist} )
+ list( REMOVE_ITEM _find_args ${pkgname} )
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): searching for Python")
+ ecbuild_find_python( ${_find_args} )
+ elseif( pkgname STREQUAL "LEXYACC" )
+ set( _find_args ${pkglist} )
+ list( REMOVE_ITEM _find_args ${pkgname} )
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): searching for lex-yacc")
+ ecbuild_find_lexyacc( ${_find_args} )
+ else()
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): searching for package ${pkgname}")
+ find_package( ${pkglist} )
+ endif()
+
+ endif()
+
+ endif()
+
+ # if found append to list of third-party libraries (to be forward to other packages )
+ if( ${pkgname}_FOUND OR ${pkgUPPER}_FOUND OR ${pkgLOWER}_FOUND )
+
+ list( APPEND ${PROJECT_NAME_CAPS}_TPLS ${pkgname} )
+ list( REMOVE_DUPLICATES ${PROJECT_NAME_CAPS}_TPLS )
+
+ endif()
+
+ # ecbuild_debug_var( ${pkgname}_FOUND )
+ # ecbuild_debug_var( ${pkgLOWER}_FOUND )
+ # ecbuild_debug_var( ${pkgUPPER}_FOUND )
+
+ # we have feature if all required packages were FOUND
+
+ if( ${pkgname}_FOUND OR ${pkgUPPER}_FOUND OR ${pkgLOWER}_FOUND )
+ ecbuild_info( "Found package ${pkgname} required for feature ${_p_FEATURE}" )
+ else()
+ ecbuild_info( "Could not find package ${pkgname} required for feature ${_p_FEATURE} -- Provide ${pkgname} location with -D${pkgUPPER}_PATH=/..." )
+ set( HAVE_${_p_FEATURE} 0 )
+ list( APPEND _failed_to_find_packages ${pkgname} )
+ endif()
+
+ endforeach()
+ else( _${_p_FEATURE}_condition )
+ set( HAVE_${_p_FEATURE} 0 )
+ endif( _${_p_FEATURE}_condition )
+
+ ecbuild_set_feature( ${_p_FEATURE} ENABLED ${HAVE_${_p_FEATURE}} )
+ # FINAL CHECK
+
+ if( HAVE_${_p_FEATURE} )
+
+ ecbuild_info( "Feature ${_p_FEATURE} enabled" )
+
+ else() # if user provided input and we cannot satisfy FAIL otherwise WARN
+
+ if( ${_p_FEATURE}_user_provided_input )
+ if( _${_p_FEATURE}_condition )
+ ecbuild_critical( "Feature ${_p_FEATURE} cannot be enabled -- following required packages weren't found: ${_failed_to_find_packages}" )
+ else()
+ ecbuild_critical( "Feature ${_p_FEATURE} cannot be enabled -- following condition was not met: ${_p_CONDITION}" )
+ endif()
+ else()
+ if( _${_p_FEATURE}_condition )
+ ecbuild_info( "Feature ${_p_FEATURE} was not enabled (also not requested) -- following condition was not met: ${_p_CONDITION}" )
+ else()
+ ecbuild_info( "Feature ${_p_FEATURE} was not enabled (also not requested) -- following required packages weren't found: ${_failed_to_find_packages}" )
+ endif()
+ set( ENABLE_${_p_FEATURE} OFF )
+ ecbuild_set_feature( ${_p_FEATURE} ENABLED OFF )
+ endif()
+
+ endif()
+
+ else( _do_search )
+
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): feature disabled")
+ set( HAVE_${_p_FEATURE} 0 )
+ ecbuild_set_feature( ${_p_FEATURE} ENABLED OFF )
+
+ endif( _do_search )
+
+
+ if( ${_p_ADVANCED} )
+ mark_as_advanced( ENABLE_${_p_FEATURE} )
+ endif()
+
+ set( ${PROJECT_NAME_CAPS}_HAVE_${_p_FEATURE} ${HAVE_${_p_FEATURE}} )
+
+endmacro( ecbuild_add_option )
diff --git a/cmake/ecbuild_add_persistent.cmake b/cmake/ecbuild_add_persistent.cmake
new file mode 100644
index 0000000..42bb44b
--- /dev/null
+++ b/cmake/ecbuild_add_persistent.cmake
@@ -0,0 +1,85 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_add_persistent
+# ======================
+#
+# Add persistent layer object classes. ::
+#
+# ecbuild_add_persistent( SRC_LIST <variable>
+# FILES <file1> [<file2> ...] ]
+# [ NAMESPACE <namespace> ] )
+#
+# Options
+# -------
+#
+# SRC_LIST : required
+# CMake variable to append the generated persistent layer objects to
+#
+# FILES : required
+# list of base names of files to build persistent class information for
+#
+# The source file is expected to have a .h extension, the generated file
+# gets a .b extension.
+#
+# NAMESPACE : optional
+# C++ namespace to place the persistent class information in
+#
+##############################################################################
+
+# define the script to build the persistent class information
+set( sg_perl "${CMAKE_CURRENT_LIST_DIR}/sg.pl" CACHE INTERNAL "perl script to generate persistent objects" )
+
+macro( ecbuild_add_persistent )
+
+ ecbuild_find_perl( REQUIRED )
+
+ set( options )
+ set( single_value_args SRC_LIST NAMESPACE )
+ set( multi_value_args FILES )
+
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_PAR_UNPARSED_ARGUMENTS)
+ ecbuild_critical("Unknown keywords given to ecbuild_add_persistent(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if( NOT _PAR_SRC_LIST )
+ ecbuild_critical("The call to ecbuild_add_persistent() doesn't specify the SRC_LIST.")
+ endif()
+
+ if( NOT _PAR_FILES )
+ ecbuild_critical("The call to ecbuild_add_persistent() doesn't specify the FILES.")
+ endif()
+
+ foreach( file ${_PAR_FILES} )
+
+ get_filename_component( _file_dir ${file} PATH )
+ get_filename_component( _file_we ${file} NAME_WE )
+
+ set( file ${_file_we} )
+ if( _file_dir )
+ file( MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${_file_dir} )
+ set( file ${_file_dir}/${_file_we} )
+ endif()
+
+ # ecbuild_debug_var(file)
+
+ add_custom_command( OUTPUT ${file}.b
+ COMMAND ${PERL_EXECUTABLE} ${sg_perl} ${CMAKE_CURRENT_SOURCE_DIR}/${file}.h
+ ${CMAKE_CURRENT_BINARY_DIR}/${_file_dir} ${_PAR_NAMESPACE}
+ DEPENDS ${sg_perl} ${file}.h )
+ set_source_files_properties( ${file}.h PROPERTIES OBJECT_DEPENDS "${file}.b" )
+ list( APPEND ${_PAR_SRC_LIST} ${CMAKE_CURRENT_BINARY_DIR}/${file}.b )
+
+ endforeach()
+
+endmacro( ecbuild_add_persistent )
diff --git a/cmake/ecbuild_add_resources.cmake b/cmake/ecbuild_add_resources.cmake
new file mode 100644
index 0000000..cf0543b
--- /dev/null
+++ b/cmake/ecbuild_add_resources.cmake
@@ -0,0 +1,151 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_add_resources
+# =====================
+#
+# Add resources as project files but optionally exclude them from packaging. ::
+#
+# ecbuild_add_resources( TARGET <name>
+# [ SOURCES <source1> [<source2> ...] ]
+# [ SOURCES_PACK <source1> [<source2> ...] ]
+# [ SOURCES_DONT_PACK <source1> [<source2> ...] ]
+# [ PACK <file1> [<file2> ...] ]
+# [ DONT_PACK <file1> [<file2> ...] ]
+# [ DONT_PACK_DIRS <directory1> [<directory2> ...] ]
+# [ DONT_PACK_REGEX <regex1> [<regex2> ...] ] )
+#
+# Options
+# -------
+#
+# TARGET : required
+# target name (target will only be created if there are any sources)
+#
+# SOURCES : optional, alias for SOURCES_PACK
+# list of source files included when packaging
+#
+# SOURCES_PACK : optional, alias for SOURCES
+# list of source files included when packaging
+#
+# SOURCES_DONT_PACK : optional
+# list of source files excluded when packaging
+#
+# PACK : optional, priority over DONT_PACK, DONT_PACK_DIRS, DONT_PACK_REGEX
+# list of files to include when packaging
+#
+# DONT_PACK : optional
+# list of files to exclude when packaging
+#
+# DONT_PACK_DIRS : optional
+# list of directories to exclude when packaging
+#
+# DONT_PACK_REGEX : optional
+# list of regular expressions to match files and directories to exclude when
+# packaging
+#
+##############################################################################
+
+macro( ecbuild_add_resources )
+
+ set( options )
+ set( single_value_args TARGET )
+ set( multi_value_args SOURCES SOURCES_PACK SOURCES_DONT_PACK PACK DONT_PACK DONT_PACK_DIRS DONT_PACK_REGEX )
+
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_PAR_UNPARSED_ARGUMENTS)
+ ecbuild_critical("Unknown keywords given to ecbuild_add_resources(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if( NOT _PAR_TARGET )
+ ecbuild_critical("The call to ecbuild_add_resources() doesn't specify the TARGET.")
+ endif()
+
+ set( LOCAL_FILES_NOT_TO_PACK "" )
+
+ # all recursive files are not to pack
+ if( DEFINED _PAR_DONT_PACK_REGEX )
+ foreach( exp ${_PAR_DONT_PACK_REGEX} )
+ file( GLOB_RECURSE all_files_in_subdirs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${exp} )
+ list( APPEND LOCAL_FILES_NOT_TO_PACK ${all_files_in_subdirs} )
+ endforeach()
+ endif()
+
+ # selected dirs not to pack
+ if( DEFINED _PAR_DONT_PACK_DIRS )
+ foreach( dir ${_PAR_DONT_PACK_DIRS} )
+ list( APPEND LOCAL_FILES_NOT_TO_PACK ${dir}/ )
+ endforeach()
+ endif()
+
+ # selected files not to pack
+ if( DEFINED _PAR_DONT_PACK )
+ list( APPEND LOCAL_FILES_NOT_TO_PACK ${_PAR_DONT_PACK} )
+ endif()
+
+ # now lets remove files that we want to pack from the list
+ # note that these have priority over the files not to pack
+ # so we can GLOB_RECURSE * -> DONT_PACK and then select only the ones we pack
+
+ # files to pack but are not project files
+ if( DEFINED _PAR_PACK )
+ foreach( file ${_PAR_PACK} )
+ list( REMOVE_ITEM LOCAL_FILES_NOT_TO_PACK ${file} )
+ endforeach()
+ endif()
+
+ # define as project files, but dont pack them
+ if( DEFINED _PAR_SOURCES_DONT_PACK )
+ list( APPEND LOCAL_FILES_NOT_TO_PACK ${_PAR_SOURCES_DONT_PACK} )
+ foreach( sfile ${_PAR_SOURCES_DONT_PACK} )
+ set( _full_sfile "${CMAKE_CURRENT_SOURCE_DIR}/${sfile}" )
+ if( EXISTS ${_full_sfile} )
+ list( APPEND ${_PAR_TARGET}_files ${_full_sfile} )
+ endif()
+ endforeach()
+ endif()
+
+ # define as project files and pack them
+ # SOURCES_PACK is alias to SOURCES
+ if( DEFINED _PAR_SOURCES_PACK )
+ list( APPEND _PAR_SOURCES ${_PAR_SOURCES_PACK} )
+ endif()
+ if( DEFINED _PAR_SOURCES )
+ list( APPEND ${_PAR_TARGET}_files ${_PAR_SOURCES} )
+ foreach( file ${_PAR_SOURCES} )
+ list( REMOVE_ITEM LOCAL_FILES_NOT_TO_PACK ${file} )
+ endforeach()
+ endif()
+
+ # there are project files, so lets create the target
+ if( DEFINED ${_PAR_TARGET}_files )
+ add_custom_target( ${_PAR_TARGET} SOURCES ${${_PAR_TARGET}_files} )
+ endif()
+
+ # remove CMakeLists.txt
+ foreach( file ${LOCAL_FILES_NOT_TO_PACK} )
+ if( ${file} MATCHES "CMakeLists.txt" )
+ list( REMOVE_ITEM LOCAL_FILES_NOT_TO_PACK ${file} )
+ endif()
+ endforeach()
+
+ # transform the local files to full absolute paths
+ # and place them in the global list of files not to pack
+ foreach( file ${LOCAL_FILES_NOT_TO_PACK} )
+ list( APPEND ECBUILD_DONT_PACK_FILES ${CMAKE_CURRENT_SOURCE_DIR}/${file} )
+ endforeach()
+
+ # save cache if we added any files not to pack
+ if( LOCAL_FILES_NOT_TO_PACK )
+ set( ECBUILD_DONT_PACK_FILES ${ECBUILD_DONT_PACK_FILES} CACHE INTERNAL "" )
+ endif()
+
+endmacro( ecbuild_add_resources )
diff --git a/cmake/ecbuild_add_test.cmake b/cmake/ecbuild_add_test.cmake
new file mode 100644
index 0000000..2097683
--- /dev/null
+++ b/cmake/ecbuild_add_test.cmake
@@ -0,0 +1,471 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_add_test
+# ================
+#
+# Add a test as a script or an executable with a given list of source files. ::
+#
+# ecbuild_add_test( [ TARGET <name> ]
+# [ SOURCES <source1> [<source2> ...] ]
+# [ OBJECTS <obj1> [<obj2> ...] ]
+# [ COMMAND <executable> ]
+# [ TYPE EXE|SCRIPT|PYTHON ]
+# [ ARGS <argument1> [<argument2> ...] ]
+# [ RESOURCES <file1> [<file2> ...] ]
+# [ TEST_DATA <file1> [<file2> ...] ]
+# [ BOOST ]
+# [ MPI <number-of-mpi-tasks> ]
+# [ OMP <number-of-threads-per-mpi-task> ]
+# [ ENABLED ON|OFF ]
+# [ LIBS <library1> [<library2> ...] ]
+# [ INCLUDES <path1> [<path2> ...] ]
+# [ DEFINITIONS <definition1> [<definition2> ...] ]
+# [ PERSISTENT <file1> [<file2> ...] ]
+# [ GENERATED <file1> [<file2> ...] ]
+# [ DEPENDS <target1> [<target2> ...] ]
+# [ TEST_DEPENDS <target1> [<target2> ...] ]
+# [ CONDITION <condition1> [<condition2> ...] ]
+# [ ENVIRONMENT <variable1> [<variable2> ...] ]
+# [ WORKING_DIRECTORY <path> ]
+# [ CFLAGS <flag1> [<flag2> ...] ]
+# [ CXXFLAGS <flag1> [<flag2> ...] ]
+# [ FFLAGS <flag1> [<flag2> ...] ]
+# [ LINKER_LANGUAGE <lang> ] )
+#
+# Options
+# -------
+#
+# TARGET : either TARGET or COMMAND must be provided, unless TYPE is PYTHON
+# target name to be built
+#
+# SOURCES : required if TARGET is provided
+# list of source files to be compiled
+#
+# OBJECTS : optional
+# list of object libraries to add to this target
+#
+# COMMAND : either TARGET or COMMAND must be provided, unless TYPE is PYTHON
+# command or script to execute (no executable is built)
+#
+# TYPE : optional
+# test type, one of:
+#
+# :EXE: run built executable, default if TARGET is provided
+# :SCRIPT: run command or script, default if COMMAND is provided
+# :PYTHON: run a Python script (requires the Python interpreter to be found)
+#
+# ARGS : optional
+# list of arguments to pass to TARGET or COMMAND when running the test
+#
+# RESOURCES : optional
+# list of files to copy from the test source directory to the test directory
+#
+# TEST_DATA : optional
+# list of test data files to download
+#
+# BOOST : optional
+# use the Boost Unit Test Framework
+#
+# MPI : optional
+# number of MPI tasks to use.
+#
+# If greater than 1, and MPI is not available, the test is disabled.
+#
+# OMP : optional
+# number of OpenMP threads per MPI task to use.
+#
+# If set, the environment variable OMP_NUM_THREADS will set.
+# Also, in case of launchers like aprun, the OMP_NUMTHREADS_FLAG will be used.
+#
+# ENABLED : optional
+# if set to OFF, the test is built but not enabled as a test case
+#
+# LIBS : optional
+# list of libraries to link against (CMake targets or external libraries)
+#
+# INCLUDES : optional
+# list of paths to add to include directories
+#
+# DEFINITIONS : optional
+# list of definitions to add to preprocessor defines
+#
+# PERSISTENT : optional
+# list of persistent layer object files
+#
+# GENERATED : optional
+# list of files to mark as generated (sets GENERATED source file property)
+#
+# DEPENDS : optional
+# list of targets to be built before this target
+#
+# TEST_DEPENDS : optional
+# list of tests to be run before this one
+#
+# CONDITION : optional
+# conditional expression which must evaluate to true for this target to be
+# built (must be valid in a CMake ``if`` statement)
+#
+# ENVIRONMENT : optional
+# list of environment variables to set in the test environment
+#
+# WORKING_DIRECTORY : optional
+# directory to switch to before running the test
+#
+# CFLAGS : optional
+# list of C compiler flags to use for all C source files
+#
+# CXXFLAGS : optional
+# list of C++ compiler flags to use for all C++ source files
+#
+# FFLAGS : optional
+# list of Fortran compiler flags to use for all Fortran source files
+#
+# LINKER_LANGUAGE : optional
+# sets the LINKER_LANGUAGE property on the target
+#
+##############################################################################
+
+macro( ecbuild_add_test )
+
+ set( options BOOST )
+ set( single_value_args TARGET ENABLED COMMAND TYPE LINKER_LANGUAGE MPI OMP WORKING_DIRECTORY )
+ set( multi_value_args SOURCES OBJECTS LIBS INCLUDES TEST_DEPENDS DEPENDS ARGS
+ PERSISTENT DEFINITIONS RESOURCES TEST_DATA CFLAGS
+ CXXFLAGS FFLAGS GENERATED CONDITION ENVIRONMENT )
+
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_PAR_UNPARSED_ARGUMENTS)
+ ecbuild_critical("Unknown keywords given to ecbuild_add_test(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ set( _TEST_DIR ${CMAKE_CURRENT_BINARY_DIR} )
+
+ # Check for MPI
+ if(_PAR_MPI)
+ if( (_PAR_MPI GREATER 1) AND ( (NOT MPI_FOUND) OR (NOT MPIEXEC) ) )
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): ${_PAR_MPI} MPI ranks requested but MPI not available - disabling test")
+ set( _PAR_ENABLED 0 )
+ elseif( (_PAR_MPI EQUAL 1) AND (NOT MPI_FOUND) )
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): 1 MPI rank requested but MPI not available - disabling MPI")
+ set( _PAR_MPI 0 )
+ else()
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): Running using ${_PAR_MPI} MPI rank(s)")
+ endif()
+ endif()
+
+ # Check for OMP
+ if( NOT DEFINED _PAR_OMP )
+ set( _PAR_OMP 1 )
+ endif()
+ list( APPEND _PAR_ENVIRONMENT "OMP_NUM_THREADS=${_PAR_OMP}" )
+
+
+ # default is enabled
+ if( NOT DEFINED _PAR_ENABLED )
+ set( _PAR_ENABLED 1 )
+ endif()
+
+
+ ### check test type
+
+ # command implies script
+ if( DEFINED _PAR_COMMAND )
+ set( _PAR_TYPE "SCRIPT" )
+ endif()
+
+ # default of TYPE
+ if( NOT _PAR_TYPE AND DEFINED _PAR_TARGET )
+ set( _PAR_TYPE "EXE" )
+ if( NOT _PAR_SOURCES )
+ ecbuild_critical("The call to ecbuild_add_test() defines a TARGET without SOURCES.")
+ endif()
+ endif()
+
+ if( _PAR_TYPE MATCHES "PYTHON" )
+ if( PYTHONINTERP_FOUND )
+ set( _PAR_COMMAND ${PYTHON_EXECUTABLE} )
+ else()
+ ecbuild_warn( "Requested a python test but python interpreter not found - disabling test\nPYTHON_EXECUTABLE: [${PYTHON_EXECUTABLE}]" )
+ set( _PAR_ENABLED 0 )
+ endif()
+ endif()
+
+ ### further checks
+
+ if( _PAR_ENABLED AND NOT _PAR_TARGET AND NOT _PAR_COMMAND )
+ ecbuild_critical("The call to ecbuild_add_test() defines neither a TARGET nor a COMMAND.")
+ endif()
+
+ if( _PAR_ENABLED AND NOT _PAR_COMMAND AND NOT _PAR_SOURCES )
+ ecbuild_critical("The call to ecbuild_add_test() defines neither a COMMAND nor SOURCES, so no test can be defined or built.")
+ endif()
+
+ if( _PAR_TYPE MATCHES "SCRIPT" AND NOT _PAR_COMMAND )
+ ecbuild_critical("The call to ecbuild_add_test() defines a 'script' but doesn't specify the COMMAND.")
+ endif()
+
+ ### conditional build
+
+ if( DEFINED _PAR_CONDITION )
+ set(_target_condition_file "${_TEST_DIR}/set_${_PAR_TARGET}_condition.cmake")
+ file( WRITE ${_target_condition_file} " if( ")
+ foreach( term ${_PAR_CONDITION} )
+ file( APPEND ${_target_condition_file} " ${term}")
+ endforeach()
+ file( APPEND ${_target_condition_file} " )\n set(_${_PAR_TARGET}_condition TRUE)\n else()\n set(_${_PAR_TARGET}_condition FALSE)\n endif()\n")
+ include( ${_target_condition_file} )
+ else()
+ set( _${_PAR_TARGET}_condition TRUE )
+ endif()
+
+ # boost unit test linking to unit_test lib ?
+
+ if( _PAR_BOOST AND ENABLE_TESTS AND _${_PAR_TARGET}_condition )
+
+ if( HAVE_BOOST_UNIT_TEST )
+ if( BOOST_UNIT_TEST_FRAMEWORK_HEADER_ONLY )
+ include_directories( ${ECBUILD_BOOST_HEADER_DIRS} )
+ include_directories( ${Boost_INCLUDE_DIRS} ) # temporary until we ship Boost Unit Test with ecBuild
+ else()
+ include_directories( ${ECBUILD_BOOST_HEADER_DIRS} ${Boost_INCLUDE_DIRS} )
+ endif()
+ else()
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): boost unit test framework not available - not building test")
+ set( _${_PAR_TARGET}_condition FALSE )
+ endif()
+
+ endif()
+
+ ### enable the tests
+
+ if( ENABLE_TESTS AND _${_PAR_TARGET}_condition )
+
+ # add resources
+
+ if( DEFINED _PAR_RESOURCES )
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): copying resources ${_PAR_RESOURCES}")
+ foreach( rfile ${_PAR_RESOURCES} )
+ execute_process( COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/${rfile} ${_TEST_DIR} )
+ endforeach()
+ endif()
+
+ # build executable
+
+ if( DEFINED _PAR_SOURCES )
+
+ # add include dirs if defined
+ if( DEFINED _PAR_INCLUDES )
+ list(REMOVE_DUPLICATES _PAR_INCLUDES )
+ foreach( path ${_PAR_INCLUDES} ) # skip NOTFOUND
+ if( path )
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): add ${path} to include_directories")
+ include_directories( ${path} )
+ else()
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): ${path} not found - not adding to include_directories")
+ endif()
+ endforeach()
+ endif()
+
+ # add persistent layer files
+ if( DEFINED _PAR_PERSISTENT )
+ if( DEFINED PERSISTENT_NAMESPACE )
+ ecbuild_add_persistent( SRC_LIST _PAR_SOURCES FILES ${_PAR_PERSISTENT} NAMESPACE ${PERSISTENT_NAMESPACE} )
+ else()
+ ecbuild_add_persistent( SRC_LIST _PAR_SOURCES FILES ${_PAR_PERSISTENT} )
+ endif()
+ endif()
+
+ # insert already compiled objects (from OBJECT libraries)
+ unset( _all_objects )
+ foreach( _obj ${_PAR_OBJECTS} )
+ list( APPEND _all_objects $<TARGET_OBJECTS:${_obj}> )
+ endforeach()
+
+ add_executable( ${_PAR_TARGET} ${_PAR_SOURCES} ${_all_objects} )
+
+ # add extra dependencies
+ if( DEFINED _PAR_DEPENDS)
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): add dependency on ${_PAR_DEPENDS}")
+ add_dependencies( ${_PAR_TARGET} ${_PAR_DEPENDS} )
+ endif()
+
+ # add the link libraries
+ if( DEFINED _PAR_LIBS )
+ list(REMOVE_DUPLICATES _PAR_LIBS )
+ list(REMOVE_ITEM _PAR_LIBS debug)
+ list(REMOVE_ITEM _PAR_LIBS optimized)
+ foreach( lib ${_PAR_LIBS} ) # skip NOTFOUND
+ if( lib )
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): linking with ${lib}")
+ target_link_libraries( ${_PAR_TARGET} ${lib} )
+ else()
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): ${lib} not found - not linking")
+ endif()
+ endforeach()
+ endif()
+
+ # add test libraries
+ if( _PAR_BOOST AND BOOST_UNIT_TEST_FRAMEWORK_LINKED AND HAVE_BOOST_UNIT_TEST )
+ target_link_libraries( ${_PAR_TARGET} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} ${Boost_TEST_EXEC_MONITOR_LIBRARY} )
+ endif()
+
+ # filter sources
+ ecbuild_separate_sources( TARGET ${_PAR_TARGET} SOURCES ${_PAR_SOURCES} )
+
+ # add local flags
+ if( DEFINED _PAR_CFLAGS )
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): use C flags ${_PAR_CFLAGS}")
+ set_source_files_properties( ${${_PAR_TARGET}_c_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_CFLAGS}" )
+ endif()
+ if( DEFINED _PAR_CXXFLAGS )
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): use C++ flags ${_PAR_CFLAGS}")
+ set_source_files_properties( ${${_PAR_TARGET}_cxx_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_CXXFLAGS}" )
+ endif()
+ if( DEFINED _PAR_FFLAGS )
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): use Fortran flags ${_PAR_CFLAGS}")
+ set_source_files_properties( ${${_PAR_TARGET}_f_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_FFLAGS}" )
+ endif()
+ if( DEFINED _PAR_GENERATED )
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): mark as generated ${_PAR_GENERATED}")
+ set_source_files_properties( ${_PAR_GENERATED} PROPERTIES GENERATED 1 )
+ endif()
+
+
+ # modify definitions to compilation ( -D... )
+ get_property( _target_defs TARGET ${_PAR_TARGET} PROPERTY COMPILE_DEFINITIONS )
+
+ if( DEFINED _PAR_DEFINITIONS )
+ list( APPEND _target_defs ${_PAR_DEFINITIONS} )
+ endif()
+
+ if( _PAR_BOOST AND BOOST_UNIT_TEST_FRAMEWORK_HEADER_ONLY )
+ list( APPEND _target_defs BOOST_UNIT_TEST_FRAMEWORK_HEADER_ONLY )
+ endif()
+
+ if( _target_defs )
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): using definitions ${_target_defs}")
+ set_property( TARGET ${_PAR_TARGET} PROPERTY COMPILE_DEFINITIONS ${_target_defs} )
+ endif()
+
+ # set build location to local build dir
+ # not the project base as defined for libs and execs
+ set_property( TARGET ${_PAR_TARGET} PROPERTY RUNTIME_OUTPUT_DIRECTORY ${_TEST_DIR} )
+
+ # whatever project settings are, we always build tests with the build_rpath, not the install_rpath
+ set_property( TARGET ${_PAR_TARGET} PROPERTY BUILD_WITH_INSTALL_RPATH FALSE )
+ set_property( TARGET ${_PAR_TARGET} PROPERTY SKIP_BUILD_RPATH FALSE )
+
+ # set linker language
+ if( DEFINED _PAR_LINKER_LANGUAGE )
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): using linker language ${_PAR_LINKER_LANGUAGE}")
+ set_property( TARGET ${_PAR_TARGET} PROPERTY LINKER_LANGUAGE ${_PAR_LINKER_LANGUAGE} )
+ endif()
+
+ # make sure target is removed before - some problems with AIX
+ get_target_property(EXE_FILENAME ${_PAR_TARGET} OUTPUT_NAME)
+ add_custom_command( TARGET ${_PAR_TARGET}
+ PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E remove ${EXE_FILENAME} )
+
+ endif() # _PAR_SOURCES
+
+ if( DEFINED _PAR_COMMAND AND NOT _PAR_TARGET ) # in the absence of target, we use the command as a name
+ set( _PAR_TARGET ${_PAR_COMMAND} )
+ endif()
+
+ # scripts dont have actual build targets
+ # we build a phony target to trigger the dependencies
+ if( DEFINED _PAR_COMMAND AND DEFINED _PAR_DEPENDS )
+
+ add_custom_target( ${_PAR_TARGET}.x ALL COMMAND ${CMAKE_COMMAND} -E touch ${_PAR_TARGET}.x )
+
+ add_dependencies( ${_PAR_TARGET}.x ${_PAR_DEPENDS} )
+
+ endif()
+
+
+ # define the arguments
+ set( TEST_ARGS "" )
+ # Boost Unit Test >= 1.60 requires arguments to be passed to the application to be separated by --
+ if( DEFINED _PAR_ARGS AND _PAR_BOOST )
+ list( APPEND TEST_ARGS "--" ${_PAR_ARGS} )
+ elseif( DEFINED _PAR_ARGS )
+ list( APPEND TEST_ARGS ${_PAR_ARGS} )
+ endif()
+
+ # Wrap with MPIEXEC
+ if( _PAR_MPI )
+
+ set( MPIEXEC_TASKS ${MPIEXEC_NUMPROC_FLAG} ${_PAR_MPI} )
+ if( DEFINED MPIEXEC_NUMTHREAD_FLAG )
+ set( MPIEXEC_THREADS ${MPIEXEC_NUMTHREAD_FLAG} ${_PAR_OMP} )
+ endif()
+
+ set( _LAUNCH ${MPIEXEC} ${MPIEXEC_TASKS} ${MPIEXEC_THREADS} )
+
+ if( DEFINED _PAR_COMMAND )
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): running as ${_LAUNCH} ${_PAR_COMMAND}")
+ set( _PAR_COMMAND ${_LAUNCH} ${_PAR_COMMAND} )
+ else()
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): running as ${_LAUNCH} ${_TEST_DIR}/${_PAR_TARGET}")
+ set( _PAR_COMMAND ${_LAUNCH} ${_TEST_DIR}/${_PAR_TARGET} )
+ endif()
+ endif()
+
+ ### define the test
+
+ if( _PAR_ENABLED ) # we can disable and still build it but not run it with 'make tests'
+
+ if( DEFINED _PAR_COMMAND )
+ add_test( NAME ${_PAR_TARGET} COMMAND ${_PAR_COMMAND} ${TEST_ARGS} ${_working_dir} ) # run a command as test
+ else()
+ add_test( NAME ${_PAR_TARGET} COMMAND ${_PAR_TARGET} ${TEST_ARGS} ${_working_dir} ) # run the test that was generated
+ endif()
+
+ # get test data
+
+ if( _PAR_TEST_DATA )
+
+ ecbuild_get_test_multidata( TARGET ${_PAR_TARGET}_data NAMES ${_PAR_TEST_DATA} )
+
+ list( APPEND _PAR_TEST_DEPENDS ${_PAR_TARGET}_data )
+
+ endif()
+
+ if( DEFINED _PAR_ENVIRONMENT )
+ set_property( TEST ${_PAR_TARGET} APPEND PROPERTY ENVIRONMENT "${_PAR_ENVIRONMENT}" )
+ endif()
+
+ if( DEFINED _PAR_WORKING_DIRECTORY )
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): set working directory to ${_PAR_WORKING_DIRECTORY}")
+ set_tests_properties( ${_PAR_TARGET} PROPERTIES WORKING_DIRECTORY "${_PAR_WORKING_DIRECTORY}")
+ endif()
+
+ if( DEFINED _PAR_TEST_DEPENDS )
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): set test dependencies to ${_PAR_TEST_DEPENDS}")
+ set_property( TEST ${_PAR_TARGET} APPEND PROPERTY DEPENDS "${_PAR_TEST_DEPENDS}" )
+ endif()
+
+ endif()
+
+ # add to the overall list of tests
+ list( APPEND ECBUILD_ALL_TESTS ${_PAR_TARGET} )
+ list( REMOVE_DUPLICATES ECBUILD_ALL_TESTS )
+ set( ECBUILD_ALL_TESTS ${ECBUILD_ALL_TESTS} CACHE INTERNAL "" )
+
+ endif() # _condition
+
+ # finally mark project files
+ ecbuild_declare_project_files( ${_PAR_SOURCES} )
+
+endmacro( ecbuild_add_test )
diff --git a/cmake/ecbuild_append_to_rpath.cmake b/cmake/ecbuild_append_to_rpath.cmake
new file mode 100644
index 0000000..9ecde3e
--- /dev/null
+++ b/cmake/ecbuild_append_to_rpath.cmake
@@ -0,0 +1,97 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_append_to_rpath
+# =======================
+#
+# Append paths to the rpath. ::
+#
+# ecbuild_append_to_rpath( RPATH_DIRS )
+#
+# ``RPATH_DIRS`` is a list of directories to append to ``CMAKE_INSTALL_RPATH``.
+#
+# * If a directory is absolute, simply append it.
+# * If a directory is relative, build a platform-dependent relative path
+# (using ``@loader_path`` on Mac OSX, ``$ORIGIN`` on Linux and Solaris)
+# or fall back to making it absolute by prepending the install prefix.
+#
+##############################################################################
+
+function( _path_append var path )
+ if( "${${var}}" STREQUAL "" )
+ set( ${var} "${path}" PARENT_SCOPE )
+ else()
+ list( FIND ${var} ${path} _found )
+ if( _found EQUAL "-1" )
+ set( ${var} "${${var}}:${path}" PARENT_SCOPE )
+ endif()
+ endif()
+endfunction()
+
+macro( ecbuild_append_to_rpath RPATH_DIRS )
+
+ if( NOT ${ARGC} EQUAL 1 )
+ ecbuild_error( "ecbuild_append_to_rpath takes 1 argument")
+ endif()
+
+ foreach( RPATH_DIR ${RPATH_DIRS} )
+
+ if( NOT ${RPATH_DIR} STREQUAL "" )
+
+ file( TO_CMAKE_PATH ${RPATH_DIR} RPATH_DIR ) # sanitize the path
+
+ if( IS_ABSOLUTE ${RPATH_DIR} )
+
+ _path_append( CMAKE_INSTALL_RPATH "${RPATH_DIR}" )
+
+ else()
+
+ set( _done 0 )
+
+ if( EC_OS_NAME STREQUAL "macosx" )
+
+ if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" VERSION_LESS 3.0) # cmake < 3.0
+ set( CMAKE_INSTALL_NAME_DIR "@loader_path/${RPATH_DIR}" )
+ endif()
+ _path_append( CMAKE_INSTALL_RPATH "@loader_path/${RPATH_DIR}" )
+
+ set( _done 1 )
+
+ endif()
+
+ if( EC_OS_NAME STREQUAL "linux" )
+ _path_append( CMAKE_INSTALL_RPATH "$ORIGIN/${RPATH_DIR}" )
+ set( _done 1 )
+ endif()
+
+ if( EC_OS_NAME STREQUAL "solaris" )
+ _path_append( CMAKE_INSTALL_RPATH "$ORIGIN/${RPATH_DIR}" )
+ set( _done 1 )
+ endif()
+
+ if( EC_OS_NAME STREQUAL "aix" ) # always relative to exectuable path
+ _path_append( CMAKE_INSTALL_RPATH "${RPATH_DIR}" )
+ set( _done 1 )
+ endif()
+
+ # fallback
+
+ if( NOT _done )
+ _path_append( CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${RPATH_DIR}" )
+ endif()
+
+ endif()
+
+ endif()
+
+ endforeach()
+
+endmacro( ecbuild_append_to_rpath )
diff --git a/cmake/ecbuild_bundle.cmake b/cmake/ecbuild_bundle.cmake
new file mode 100644
index 0000000..83b0bba
--- /dev/null
+++ b/cmake/ecbuild_bundle.cmake
@@ -0,0 +1,174 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+# Set policies
+include( ecbuild_policies NO_POLICY_SCOPE )
+
+include(CMakeParseArguments)
+
+include(ecbuild_git)
+
+##############################################################################
+#.rst:
+#
+# ecbuild_bundle_initialize
+# =========================
+#
+# Initialise the ecBuild environment for a bundle. *Must* be called *before*
+# any call to ecbuild_bundle.
+#
+##############################################################################
+
+macro( ecbuild_bundle_initialize )
+
+ include( local-config.cmake OPTIONAL )
+
+ # ecmwf_stash( PROJECT ecbuild DIR ${PROJECT_SOURCE_DIR}/ecbuild STASH "ecsdk/ecbuild" BRANCH develop )
+
+ # set( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/ecbuild/cmake;${CMAKE_MODULE_PATH}" )
+
+ include( ecbuild_system )
+
+ ecbuild_requires_macro_version( 1.6 )
+
+ ecbuild_declare_project()
+
+ file( GLOB local_config_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *local-config.cmake )
+
+ ecbuild_add_resources( TARGET ecbuild_bundle_dont_pack DONT_PACK "${local_config_files}" )
+
+ if( EXISTS "${PROJECT_SOURCE_DIR}/README.md" )
+ add_custom_target( ${PROJECT_NAME}_readme SOURCES "${PROJECT_SOURCE_DIR}/README.md" )
+ endif()
+
+endmacro()
+
+##############################################################################
+#.rst:
+#
+# ecbuild_bundle
+# ==============
+#
+# Declare a subproject to be built as part of this bundle. ::
+#
+# ecbuild_bundle( PROJECT <name>
+# STASH <repository> | GIT <giturl> | SOURCE <path>
+# [ BRANCH <gitbranch> | TAG <gittag> ]
+# [ UPDATE | NOREMOTE ] )
+# [ MANUAL ] )
+#
+# Options
+# -------
+#
+# PROJECT : required
+# project name for the Git repository to be managed
+#
+# STASH : cannot be combined with GIT or SOURCE
+# Stash repository in the form <project>/<repository>
+#
+# GIT : cannot be combined with STASH or SOURCE
+# Git URL of the remote repository to clone (see ``git help clone``)
+#
+# SOURCE : cannot be combined with STASH or GIT
+# Path to an existing local repository, which will be symlinked
+#
+# BRANCH : optional, cannot be combined with TAG
+# Git branch to check out
+#
+# TAG : optional, cannot be combined with BRANCH
+# Git tag or commit id to check out
+#
+# UPDATE : optional, requires BRANCH, cannot be combined with NOREMOTE
+# Create a CMake target update to fetch changes from the remote repository
+#
+# NOREMOTE : optional, cannot be combined with UPDATE
+# Do not fetch changes from the remote repository
+#
+# MANUAL : optional
+# Do not automatically switch branches or tags
+#
+# Usage
+# -----
+#
+# A bundle is used to build a number of projects together. Each subproject
+# needs to be declared with a call to ecbuild_bundle, where the order of
+# projects is important and needs to respect dependencies: if project B
+# depends on project A, A should be listed before B in the bundle.
+#
+# The first time a bundle is built, the sources of all subprojects are cloned
+# into directories named according to project in the *source* tree of the
+# bundle (which means these directories should be added to ``.gitignore``).
+# If the ``SOURCE`` option is used it must point to an existing local
+# repository on disk and no new repository is cloned. Be aware that using the
+# ``BRANCH`` or ``TAG`` option leads to the corresponding version being checked
+# out in that repository!
+#
+# Subprojects are configured and built in order. Due to being added as a
+# subproject, the usual project discovery mechanism (i.e. locating and
+# importing a ``<project>-config.cmake`` file) is not used. Also there are no
+# ``<project>-config.cmake`` files being generated for individual subprojects.
+# However there *are* package-config files being generated for each library.
+#
+# To switch off a subproject when building a bundle, set the CMake variable
+# ``BUNDLE_SKIP_<PNAME>`` where ``PNAME`` is the capitalised project name.
+#
+##############################################################################
+
+macro( ecbuild_bundle )
+
+ set( options )
+ set( single_value_args PROJECT STASH GIT SOURCE )
+ set( multi_value_args )
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ string(TOUPPER "${_PAR_PROJECT}" PNAME)
+
+ if( BUNDLE_SKIP_${PNAME} )
+ ecbuild_info( "Skipping bundle project ${PNAME}" )
+ else()
+
+ if( _PAR_STASH )
+ ecmwf_stash( PROJECT ${_PAR_PROJECT} DIR ${PROJECT_SOURCE_DIR}/${_PAR_PROJECT} STASH ${_PAR_STASH} ${_PAR_UNPARSED_ARGUMENTS} )
+ elseif( _PAR_GIT )
+ ecbuild_git( PROJECT ${_PAR_PROJECT} DIR ${PROJECT_SOURCE_DIR}/${_PAR_PROJECT} URL ${_PAR_GIT} ${_PAR_UNPARSED_ARGUMENTS} )
+ elseif( _PAR_SOURCE )
+ if( DEFINED ${PNAME}_SOURCE )
+ ecbuild_critical( "ecbuild_bundle called with SOURCE for project ${_PAR_PROJECT} but ${PNAME}_SOURCE is defined" )
+ endif()
+ execute_process( COMMAND ${CMAKE_COMMAND} -E create_symlink ${_PAR_SOURCE} ${PROJECT_SOURCE_DIR}/${_PAR_PROJECT} )
+ endif()
+
+ if( NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${_PAR_PROJECT} OR NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${_PAR_PROJECT}/CMakeLists.txt )
+ ecbuild_critical("Source directory '${CMAKE_CURRENT_SOURCE_DIR}/${_PAR_PROJECT}' for subproject '${_PAR_PROJECT}' does not exist or does not contain a CMakeLists.txt file.")
+ endif()
+
+ ecbuild_use_package( PROJECT ${_PAR_PROJECT} )
+ endif()
+
+endmacro()
+
+##############################################################################
+#.rst:
+#
+# ecbuild_bundle_finalize
+# =======================
+#
+# Finalise the ecBuild environment for a bundle. *Must* be called *after* the
+# last call to ecbuild_bundle.
+#
+##############################################################################
+
+macro( ecbuild_bundle_finalize )
+
+ add_custom_target( update DEPENDS ${git_update_targets} )
+
+ ecbuild_install_project( NAME ${CMAKE_PROJECT_NAME} )
+
+ ecbuild_print_summary()
+
+endmacro()
diff --git a/cmake/ecbuild_cache.cmake b/cmake/ecbuild_cache.cmake
new file mode 100644
index 0000000..e257b36
--- /dev/null
+++ b/cmake/ecbuild_cache.cmake
@@ -0,0 +1,95 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecBuild Cache
+# =============
+#
+# During initialisation, ecBuild introspects the compiler and operating system
+# and performs a number of checks. The result of these is written to a
+# dedicated ``ecbuild-cache.cmake`` file in the build tree. This cache may be
+# used to speed up subsequent *clean* builds i.e. those where no CMakeCache.txt
+# exists yet.
+#
+# To use the ecBuild cache, configure with ``-DECBUILD_CACHE=<cache-file>``,
+# where ``<cache-file>`` is the path to an existing ``ecbuild-cache.cmake``.
+#
+# .. note ::
+#
+# The ecBuild cache is specific to compiler *and* operating system. Do *not*
+# attempt to use a cache file created on a different machine or with a
+# different compiler!
+#
+##############################################################################
+
+# Prepare the cache and clobber any existing ecbuild-cache.cmake
+macro( ecbuild_prepare_cache )
+ include( CheckSymbolExists )
+ include( CheckIncludeFiles )
+ include( CheckCSourceCompiles )
+ include( CheckCXXSourceCompiles )
+ include( CheckTypeSize )
+ set( ecbuild_cache_file ${CMAKE_BINARY_DIR}/ecbuild-cache.cmake )
+ file(WRITE ${ecbuild_cache_file} "# ecbuild cache file\n\n")
+endmacro()
+
+# Buffer the CMake variable var to be written to the ecBuild cache
+function( ecbuild_cache_var var )
+ if( NOT ${var} )
+ set( ${var} 0 )
+ endif()
+ set( ECBUILD_CACHE_BUFFER "${ECBUILD_CACHE_BUFFER}set( ${var} ${${var}} )\n" CACHE INTERNAL "Cache buffer" )
+endfunction()
+
+# Call check_symbol_exists only if the output is not defined yet
+function( ecbuild_cache_check_symbol_exists symbol includes output )
+ if( NOT DEFINED ${output} )
+ check_symbol_exists( ${symbol} ${includes} ${output} )
+ endif()
+ ecbuild_cache_var( ${output} )
+endfunction()
+
+# Call check_include_files only if the output is not defined yet
+function( ecbuild_cache_check_include_files includes output )
+ if( NOT DEFINED ${output} )
+ check_include_files( ${includes} ${output} )
+ endif()
+ ecbuild_cache_var( ${output} )
+endfunction()
+
+# Call check_c_source_compiles only if the output is not defined yet
+function( ecbuild_cache_check_c_source_compiles source output )
+ if( NOT DEFINED ${output} )
+ check_c_source_compiles( "${source}" ${output} )
+ endif()
+ ecbuild_cache_var( ${output} )
+endfunction()
+
+# Call check_cxx_source_compiles only if the output is not defined yet
+function( ecbuild_cache_check_cxx_source_compiles source output )
+ if( NOT DEFINED ${output} )
+ check_cxx_source_compiles( "${source}" ${output} )
+ endif()
+ ecbuild_cache_var( ${output} )
+endfunction()
+
+# Call check_type_size only if the output is not defined yet
+function( ecbuild_cache_check_type_size type output )
+ if( NOT DEFINED ${output} )
+ check_type_size( "${type}" ${output} )
+ endif()
+ ecbuild_cache_var( ${output} )
+endfunction()
+
+# Flush the ecBuild cache to disk and reset the buffer
+function( ecbuild_flush_cache )
+ file( APPEND ${ecbuild_cache_file} "${ECBUILD_CACHE_BUFFER}" )
+ set( ECBUILD_CACHE_BUFFER "" CACHE INTERNAL "Cache buffer" )
+endfunction()
diff --git a/cmake/ecbuild_check_c_source_return.cmake b/cmake/ecbuild_check_c_source_return.cmake
new file mode 100644
index 0000000..18b6117
--- /dev/null
+++ b/cmake/ecbuild_check_c_source_return.cmake
@@ -0,0 +1,154 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_check_c_source_return
+# =============================
+#
+# Compile and run a given C source code and return its output. ::
+#
+# ecbuild_check_c_source_return( <source>
+# VAR <name>
+# OUTPUT <name>
+# [ INCLUDES <path1> [ <path2> ... ] ]
+# [ LIBS <library1> [ <library2> ... ] ]
+# [ DEFINITIONS <definition1> [ <definition2> ... ] ] )
+#
+# Options
+# -------
+#
+# VAR : required
+# name of the check and name of the CMake variable to write result to
+#
+# OUTPUT : required
+# name of CMake variable to write the output to
+#
+# INCLUDES : optional
+# list of paths to add to include directories
+#
+# LIBS : optional
+# list of libraries to link against (CMake targets or external libraries)
+#
+# DEFINITIONS : optional
+# list of definitions to add to preprocessor defines
+#
+# Usage
+# -----
+#
+# This will write the given source to a .c file and compile and run it with
+# try_run. If successful, ``${VAR}`` is set to 1 and ``${OUTPUT}`` is set to
+# the output of the successful run in the CMake cache.
+#
+# The check will not run if ``${VAR}`` is defined (e.g. from ecBuild cache).
+#
+##############################################################################
+
+macro( ecbuild_check_c_source_return SOURCE )
+
+ set( options )
+ set( single_value_args VAR OUTPUT )
+ set( multi_value_args INCLUDES LIBS DEFINITIONS )
+
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_PAR_UNPARSED_ARGUMENTS)
+ ecbuild_critical("Unknown keywords given to ecbuild_check_c_source_return(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if( NOT _PAR_VAR OR NOT _PAR_OUTPUT )
+ ecbuild_critical("The call to ecbuild_check_c_source_return() doesn't specify either SOURCE, VAR or OUTPUT")
+ endif()
+
+
+ if( NOT DEFINED ${_PAR_VAR} )
+
+ set(MACRO_CHECK_FUNCTION_DEFINITIONS "-D${_PAR_VAR} ${CMAKE_REQUIRED_FLAGS}")
+
+ set(CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES)
+ if( CMAKE_REQUIRED_LIBRARIES )
+ list( APPEND __add_libs ${CMAKE_REQUIRED_LIBRARIES} )
+ endif()
+ if( _PAR_LIBS )
+ list( APPEND __add_libs ${_PAR_LIBS} )
+ endif()
+ if( __add_libs )
+ set(CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES "-DLINK_LIBRARIES:STRING=${__add_libs}")
+ endif()
+
+ set(CHECK_C_SOURCE_COMPILES_ADD_INCLUDES)
+ if( CMAKE_REQUIRED_INCLUDES )
+ list( APPEND __add_incs ${CMAKE_REQUIRED_INCLUDES} )
+ endif()
+ if( _PAR_INCLUDES )
+ list( APPEND __add_incs ${_PAR_INCLUDES} )
+ endif()
+ if( __add_incs )
+ set(CHECK_C_SOURCE_COMPILES_ADD_INCLUDES "-DINCLUDE_DIRECTORIES:STRING=${__add_incs}")
+ endif()
+
+ # write the source file
+
+ file( WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/test_${_PAR_VAR}.c" "${SOURCE}\n" )
+
+ ecbuild_debug( "Performing Test ${_PAR_VAR}" )
+ try_run( ${_PAR_VAR}_EXITCODE ${_PAR_VAR}_COMPILED
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/test_${_PAR_VAR}.c
+ COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+ CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS}
+ -DCMAKE_SKIP_RPATH:BOOL=${CMAKE_SKIP_RPATH}
+ "${CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES}"
+ "${CHECK_C_SOURCE_COMPILES_ADD_INCLUDES}"
+ COMPILE_OUTPUT_VARIABLE compile_OUTPUT
+ RUN_OUTPUT_VARIABLE run_OUTPUT )
+
+ # if it did not compile make the return value fail code of 1
+ if( NOT ${_PAR_VAR}_COMPILED )
+ set( ${_PAR_VAR}_EXITCODE 1 )
+ endif()
+
+ # if the return value was 0 then it worked
+ if("${${_PAR_VAR}_EXITCODE}" EQUAL 0)
+
+ ecbuild_debug("Performing Test ${_PAR_VAR} - Success")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Performing C SOURCE FILE Test ${_PAR_VAR} succeded with the following compile output:\n"
+ "${compile_OUTPUT}\n"
+ "Performing C SOURCE FILE Run ${_PAR_VAR} succeded with the following run output:\n"
+ "${run_OUTPUT}\n"
+ "Return value: ${${_PAR_VAR}}\n"
+ "Source file was:\n${SOURCE}\n")
+
+ set( ${_PAR_VAR} 1 CACHE INTERNAL "Test ${_PAR_VAR}")
+ set( ${_PAR_OUTPUT} "${run_OUTPUT}" CACHE INTERNAL "Test ${_PAR_VAR} output")
+
+ else()
+
+ if(CMAKE_CROSSCOMPILING AND "${${_PAR_VAR}_EXITCODE}" MATCHES "FAILED_TO_RUN")
+ set(${_PAR_VAR} "${${_PAR_VAR}_EXITCODE}")
+ set(${OUTPUT} "")
+ else()
+ set(${_PAR_VAR} "" CACHE INTERNAL "Test ${_PAR_VAR}")
+ set(${_PAR_OUTPUT} "" CACHE INTERNAL "Test ${_PAR_VAR} output")
+ endif()
+
+ ecbuild_debug("Performing Test ${_PAR_VAR} - Failed")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Performing C SOURCE FILE Test ${_PAR_VAR} failed with the following compile output:\n"
+ "${compile_OUTPUT}\n"
+ "Performing C SOURCE FILE Run ${_PAR_VAR} failed with the following run output:\n"
+ "${run_OUTPUT}\n"
+ "Return value: ${${_PAR_VAR}_EXITCODE}\n"
+ "Source file was:\n${SOURCE}\n")
+ endif()
+
+ endif()
+
+endmacro()
diff --git a/cmake/ecbuild_check_compiler.cmake b/cmake/ecbuild_check_compiler.cmake
new file mode 100644
index 0000000..437b81e
--- /dev/null
+++ b/cmake/ecbuild_check_compiler.cmake
@@ -0,0 +1,156 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+###################################################################################################
+# enable C to use in system introspection
+
+if( NOT CMAKE_C_COMPILER_LOADED AND ENABLE_OS_TESTS )
+ enable_language( C )
+ ecbuild_compiler_flags( C )
+endif()
+
+############################################################################################
+# try to get compiler version if cmake did not
+
+if( NOT CMAKE_C_COMPILER_VERSION )
+
+ set( EC_COMPILER_VERSION "?.?" )
+
+ if( CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Intel" )
+ exec_program( ${CMAKE_C_COMPILER}
+ ARGS ${CMAKE_C_COMPILER_ARG1} -dumpversion
+ OUTPUT_VARIABLE EC_COMPILER_VERSION )
+
+ string(REGEX REPLACE "([0-9])\\.([0-9])(\\.([0-9]))?" "\\1.\\2" EC_COMPILER_VERSION ${EC_COMPILER_VERSION} )
+ endif()
+
+ if( CMAKE_C_COMPILER_ID MATCHES "Clang" )
+ exec_program( ${CMAKE_C_COMPILER}
+ ARGS ${CMAKE_C_COMPILER_ARG1} --version
+ OUTPUT_VARIABLE EC_COMPILER_VERSION )
+
+ string(REGEX REPLACE ".*clang version ([0-9])\\.([0-9])(\\.([0-9]))?.*" "\\1.\\2" EC_COMPILER_VERSION ${EC_COMPILER_VERSION} )
+ endif()
+
+ if( CMAKE_C_COMPILER_ID MATCHES "SunPro" )
+ exec_program( ${CMAKE_C_COMPILER}
+ ARGS ${CMAKE_C_COMPILER_ARG1} -V
+ OUTPUT_VARIABLE EC_COMPILER_VERSION )
+
+ string(REGEX REPLACE ".*([0-9]+)\\.([0-9]+).*" "\\1.\\2" EC_COMPILER_VERSION ${EC_COMPILER_VERSION} )
+ endif()
+
+ if( CMAKE_C_COMPILER_ID MATCHES "XL" )
+ exec_program( ${CMAKE_C_COMPILER}
+ ARGS ${CMAKE_C_COMPILER_ARG1} -qversion
+ OUTPUT_VARIABLE EC_COMPILER_VERSION )
+
+ string(REGEX REPLACE ".*V([0-9]+)\\.([0-9]+).*" "\\1.\\2" EC_COMPILER_VERSION ${EC_COMPILER_VERSION} )
+
+ endif()
+
+ if( NOT EC_COMPILER_VERSION STREQUAL "?.?" )
+ set(CMAKE_C_COMPILER_VERSION "${EC_COMPILER_VERSION}" )
+ endif()
+
+endif()
+
+############################################################################################
+# c compiler tests
+
+if( CMAKE_C_COMPILER_LOADED AND ENABLE_OS_TESTS )
+
+ ecbuild_cache_check_c_source_compiles(
+ " typedef int foo_t;
+ static inline foo_t static_foo(){return 0;}
+ foo_t foo(){return 0;}
+ int main(int argc, char *argv[]){return 0;}
+ " EC_HAVE_C_INLINE )
+
+endif()
+
+############################################################################################
+# c++ compiler tests
+
+if( CMAKE_CXX_COMPILER_LOADED AND ENABLE_OS_TESTS )
+
+ # check for __FUNCTION__
+ ecbuild_cache_check_cxx_source_compiles( "#include <iostream>\nint main(int argc, char* argv[]) { std::cout << __FUNCTION__ << std::endl; }"
+ EC_HAVE_FUNCTION_DEF )
+
+ # check for c++ abi, usually present in GNU compilers
+ ecbuild_cache_check_cxx_source_compiles( "#include <cxxabi.h>\n int main() { char * type; int status; char * r = abi::__cxa_demangle(type, 0, 0, &status); }"
+ EC_HAVE_CXXABI_H )
+
+ # check for bool
+ ecbuild_cache_check_cxx_source_compiles( "int main() { bool aflag = true; }"
+ EC_HAVE_CXX_BOOL )
+
+ # check for sstream
+ ecbuild_cache_check_cxx_source_compiles( "#include <sstream>\nint main() { std::stringstream s; }"
+ EC_HAVE_CXX_SSTREAM )
+
+endif()
+
+############################################################################################
+# enable warnings
+
+if( CMAKE_COMPILER_IS_GNUCC )
+
+ ecbuild_add_c_flags("-pipe") # use pipe for faster compilation
+
+ if( ENABLE_WARNINGS )
+ ecbuild_add_c_flags("-Wall")
+ # ecbuild_add_c_flags("-pedantic")
+ # ecbuild_add_c_flags("-Wextra")
+ endif()
+
+endif()
+
+if( CMAKE_COMPILER_IS_GNUCXX )
+
+ ecbuild_add_cxx_flags("-pipe") # use pipe for faster compilation
+
+ if( ENABLE_WARNINGS )
+ ecbuild_add_cxx_flags("-Wall")
+ # ecbuild_add_cxx_flags("-Wextra")
+ endif()
+
+endif()
+
+if( ENABLE_WARNINGS AND CMAKE_Fortran_COMPILER_ID MATCHES "Intel" )
+ ecbuild_add_fortran_flags("-warn all")
+endif()
+
+############################################################################################
+# compiler dependent fixes
+
+# For Cray compilers add "-Wl,-Bdynamic" at very end of linker commands, in order to produce dynamic executables by default
+
+if( "${CMAKE_C_COMPILER_ID}" STREQUAL "Cray" )
+ set( CMAKE_C_LINK_EXECUTABLE "<CMAKE_C_COMPILER> <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Wl,-Bdynamic" )
+endif()
+
+if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Cray" )
+ set( CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_CXX_COMPILER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Wl,-Bdynamic" )
+endif()
+
+if( "${CMAKE_Fortran_COMPILER_ID}" STREQUAL "Cray" )
+ set(CMAKE_Fortran_LINK_EXECUTABLE "<CMAKE_Fortran_COMPILER> <CMAKE_Fortran_LINK_FLAGS> <LINK_FLAGS> <FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Wl,-Bdynamic" )
+endif()
+
+############################################################################################
+# Fortran compiler specific flags
+# if( NOT HAVE_SINGLE_PRECISION )
+# if(CMAKE_Fortran_COMPILER_ID STREQUAL "PGI")
+# ecbuild_add_fortran_flags("-r8")
+# elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
+# # NOTE that if we add -fdefault-real-8 then we NEED -fdefault-double-8 to avoid quadmath
+# ecbuild_add_fortran_flags("-fdefault-real-8 -fdefault-double-8")
+# endif()
+# endif()
diff --git a/cmake/ecbuild_check_cxx11.cmake b/cmake/ecbuild_check_cxx11.cmake
new file mode 100644
index 0000000..390462b
--- /dev/null
+++ b/cmake/ecbuild_check_cxx11.cmake
@@ -0,0 +1,132 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_check_cxx11
+# ===================
+#
+# Check for C++11 features. ::
+#
+# ecbuild_check_cxx11( [ FEATURES <feature1> [ <feature2> ... ] ]
+# [ REQUIRED <feature1> [ <feature2> ... ] ]
+# [ PRINT ] )
+#
+# This function uses macros from http://github.com/UCL/GreatCMakeCookOff
+#
+# Options
+# -------
+#
+# FEATURES : optional, checks for all features if omitted
+# list of features to check for
+#
+# REQUIRED : optional
+# list of required features to check for
+#
+# PRINT : optional
+# print a summary of features check for, found and not found
+#
+##############################################################################
+
+function( ecbuild_check_cxx11 )
+
+ # parse parameters
+
+ set( options PRINT )
+ set( single_value_args )
+ set( multi_value_args FEATURES REQUIRED )
+
+ cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_PAR_UNPARSED_ARGUMENTS)
+ ecbuild_critical("Unknown keywords given to ecbuild_check_cxx11(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ include( ${ECBUILD_MACROS_DIR}/contrib/GreatCMakeCookOff/CheckCXX11Features.cmake )
+
+ cxx11_find_all_features( ALL_FEATURES ) # list all available features to check
+
+ # Save CXX flags
+ set( CXX_FLAGS_SNASHOT ${CMAKE_CXX_FLAGS} )
+
+ # Add C++11 flags
+ include( ${ECBUILD_MACROS_DIR}/ecbuild_get_cxx11_flags.cmake )
+ ecbuild_get_cxx11_flags( CXX11_FLAGS )
+ set( CMAKE_CXX_FLAGS "${CXX11_FLAGS} ${CMAKE_CXX_FLAGS}" )
+
+ if( NOT _p_FEATURES AND NOT _p_REQUIRED ) # no input, then search for all features
+
+ cxx11_feature_check()
+
+ else()
+
+ foreach( _f ${_p_FEATURES} )
+ cxx11_feature_check( ${_f} )
+ endforeach()
+
+ foreach( _f ${_p_REQUIRED} )
+ cxx11_feature_check( REQUIRED ${_f} )
+ endforeach()
+
+ endif()
+
+ # Restore CXX flags
+ set( CMAKE_CXX_FLAGS ${CXX_FLAGS_SNAPSHOT} )
+
+ if( _p_FEATURES OR _p_REQUIRED )
+ set( CXX11_CHECKED_FEATURES ${_p_FEATURES} ${_p_REQUIRED} )
+ else()
+ set( CXX11_CHECKED_FEATURES ${ALL_FEATURES} )
+ endif()
+
+ foreach( f ${CXX11_CHECKED_FEATURES} )
+ string( TOUPPER ${f} FEAT )
+ if( HAS_CXX11_${FEAT} )
+ list( APPEND CXX11_SUPPORTED_FEATURES ${f} )
+ else()
+ list( APPEND CXX11_NOT_SUPPORTED_FEATURES ${f} )
+ endif()
+ endforeach()
+
+ if( CXX11_CHECKED_FEATURES )
+ list( SORT CXX11_CHECKED_FEATURES )
+ endif()
+ if( CXX11_SUPPORTED_FEATURES )
+ list( SORT CXX11_SUPPORTED_FEATURES )
+ endif()
+ if( CXX11_NOT_SUPPORTED_FEATURES )
+ list( SORT CXX11_NOT_SUPPORTED_FEATURES )
+ endif()
+
+ set( CXX11_CHECKED_FEATURES ${CXX11_CHECKED_FEATURES} PARENT_SCOPE )
+ set( CXX11_SUPPORTED_FEATURES ${CXX11_SUPPORTED_FEATURES} PARENT_SCOPE )
+ set( CXX11_NOT_SUPPORTED_FEATURES ${CXX11_NOT_SUPPORTED_FEATURES} PARENT_SCOPE )
+
+ if( _p_PRINT )
+ if( CXX11_CHECKED_FEATURES )
+ join( CXX11_CHECKED_FEATURES " " CXX11_CHECKED_FEATURES_STR )
+ ecbuild_info( "Checked C++11 features: ${CXX11_CHECKED_FEATURES_STR}" )
+ else()
+ ecbuild_info( "Checked no C++11 features" )
+ endif()
+ if( CXX11_SUPPORTED_FEATURES )
+ join( CXX11_SUPPORTED_FEATURES " " CXX11_SUPPORTED_FEATURES_STR )
+ ecbuild_info( "Found C++11 features: ${CXX11_SUPPORTED_FEATURES_STR}" )
+ else()
+ ecbuild_info( "Found no C++11 features" )
+ endif()
+ if( CXX11_NOT_SUPPORTED_FEATURES )
+ join( CXX11_NOT_SUPPORTED_FEATURES " " CXX11_NOT_SUPPORTED_FEATURES_STR )
+ ecbuild_info( "Not found C++11 features: ${CXX11_NOT_SUPPORTED_FEATURES_STR}" )
+ else()
+ ecbuild_info( "Found all checked C++11 features" )
+ endif()
+ endif()
+
+endfunction( ecbuild_check_cxx11 )
diff --git a/cmake/ecbuild_check_cxx_source_return.cmake b/cmake/ecbuild_check_cxx_source_return.cmake
new file mode 100644
index 0000000..0868b22
--- /dev/null
+++ b/cmake/ecbuild_check_cxx_source_return.cmake
@@ -0,0 +1,163 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_check_cxx_source_return
+# ===============================
+#
+# Compile and run a given C++ code and return its output. ::
+#
+# ecbuild_check_cxx_source_return( <source>
+# VAR <name>
+# OUTPUT <name>
+# [ INCLUDES <path1> [ <path2> ... ] ]
+# [ LIBS <library1> [ <library2> ... ] ]
+# [ DEFINITIONS <definition1> [ <definition2> ... ] ] )
+#
+# Options
+# -------
+#
+# VAR : required
+# name of the check and name of the CMake variable to write result to
+#
+# OUTPUT : required
+# name of CMake variable to write the output to
+#
+# INCLUDES : optional
+# list of paths to add to include directories
+#
+# LIBS : optional
+# list of libraries to link against (CMake targets or external libraries)
+#
+# DEFINITIONS : optional
+# list of definitions to add to preprocessor defines
+#
+# Usage
+# -----
+#
+# This will write the given source to a .cxx file and compile and run it with
+# try_run. If successful, ``${VAR}`` is set to 1 and ``${OUTPUT}`` is set to
+# the output of the successful run in the CMake cache.
+#
+# The check will not run if ``${VAR}`` is defined (e.g. from ecBuild cache).
+#
+##############################################################################
+
+macro( ecbuild_check_cxx_source_return SOURCE )
+
+ set( options )
+ set( single_value_args VAR OUTPUT )
+ set( multi_value_args INCLUDES LIBS DEFINITIONS )
+
+ cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_p_UNPARSED_ARGUMENTS)
+ ecbuild_critical("Unknown keywords given to ecbuild_check_cxx_source_return(): \"${_p_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if( NOT _p_VAR OR NOT _p_OUTPUT )
+ ecbuild_critical("The call to ecbuild_check_cxx_source_return() doesn't specify either SOURCE, VAR or OUTPUT")
+ endif()
+
+ set( _msg "Testing ${_p_VAR}:" )
+
+ if( NOT DEFINED ${_p_VAR} )
+
+ set(MACRO_CHECK_FUNCTION_DEFINITIONS "-D${_p_VAR} ${CMAKE_REQUIRED_FLAGS}")
+
+ set(CHECK_CXX_SOURCE_COMPILES_ADD_LIBRARIES)
+ if(CMAKE_REQUIRED_LIBRARIES)
+ list( APPEND __add_libs ${CMAKE_REQUIRED_LIBRARIES} )
+ endif()
+ if( _p_LIBS )
+ list( APPEND __add_libs ${_p_LIBS} )
+ endif()
+ if( __add_libs )
+ set(CHECK_CXX_SOURCE_COMPILES_ADD_LIBRARIES "-DLINK_LIBRARIES:STRING=${__add_libs}")
+ endif()
+
+ set(CHECK_CXX_SOURCE_COMPILES_ADD_INCLUDES)
+ if(CMAKE_REQUIRED_INCLUDES)
+ list( APPEND __add_incs ${CMAKE_REQUIRED_INCLUDES} )
+ endif()
+ if( _p_INCLUDES )
+ list( APPEND __add_incs ${_p_INCLUDES} )
+ endif()
+ if( __add_incs )
+ set(CHECK_CXX_SOURCE_COMPILES_ADD_INCLUDES "-DINCLUDE_DIRECTORIES:STRING=${__add_incs}")
+ endif()
+
+ # write the source file
+
+ file( WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/test_${_p_VAR}.cxx" "${SOURCE}\n" )
+
+ ecbuild_debug( "${_msg}" )
+ try_run( ${_p_VAR}_EXITCODE ${_p_VAR}_COMPILED
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/test_${_p_VAR}.cxx
+ COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+ CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS}
+ -DCMAKE_SKIP_RPATH:BOOL=${CMAKE_SKIP_RPATH}
+ "${CHECK_CXX_SOURCE_COMPILES_ADD_LIBRARIES}"
+ "${CHECK_CXX_SOURCE_COMPILES_ADD_INCLUDES}"
+ COMPILE_OUTPUT_VARIABLE compile_OUTPUT
+ RUN_OUTPUT_VARIABLE run_OUTPUT )
+
+ # ecbuild_debug_var( ${_p_VAR}_COMPILED )
+ # ecbuild_debug_var( ${_p_VAR}_EXITCODE )
+
+ # if it did not compile make the return value fail code of 1
+
+ if( NOT ${_p_VAR}_COMPILED )
+ ecbuild_debug( "${_msg} failed to compile" )
+ endif()
+
+ if( "${${_p_VAR}_EXITCODE}" MATCHES "FAILED_TO_RUN" )
+ ecbuild_debug( "${_msg} failed to run" )
+ endif()
+
+ # if the return value was 0 then it worked
+ if( ${_p_VAR}_COMPILED AND "${${_p_VAR}_EXITCODE}" EQUAL 0 )
+
+ ecbuild_debug("${_msg} Success")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Performing C++ SOURCE FILE Test ${_p_VAR} succeded with the following compile output:\n"
+ "${compile_OUTPUT}\n"
+ "Performing C++ SOURCE FILE Run ${_p_VAR} succeded with the following run output:\n"
+ "${run_OUTPUT}\n"
+ "Return value: ${${_p_VAR}}\n"
+ "Source file was:\n${SOURCE}\n")
+
+ set( ${_p_VAR} 1 CACHE INTERNAL "Test ${_p_VAR}")
+ set( ${_p_OUTPUT} "${run_OUTPUT}" CACHE INTERNAL "Test ${_p_VAR} output")
+
+ else()
+
+ if(CMAKE_CROSSCOMPILING AND "${${_p_VAR}_EXITCODE}" MATCHES "FAILED_TO_RUN")
+ set(${_p_VAR} "${${_p_VAR}_EXITCODE}")
+ set(${OUTPUT} "")
+ else()
+ set(${_p_VAR} "" CACHE INTERNAL "Test ${_p_VAR}")
+ set(${_p_OUTPUT} "" CACHE INTERNAL "Test ${_p_VAR} output")
+ endif()
+
+ ecbuild_debug("Test ${_p_VAR} - Failed")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Performing C++ SOURCE FILE Test ${_p_VAR} failed with the following compile output:\n"
+ "${compile_OUTPUT}\n"
+ "Performing C++ SOURCE FILE Run ${_p_VAR} failed with the following run output:\n"
+ "${run_OUTPUT}\n"
+ "Return value: ${${_p_VAR}_EXITCODE}\n"
+ "Source file was:\n${SOURCE}\n")
+ endif()
+
+ endif()
+
+endmacro()
diff --git a/cmake/ecbuild_check_fortran_source_return.cmake b/cmake/ecbuild_check_fortran_source_return.cmake
new file mode 100644
index 0000000..6b007df
--- /dev/null
+++ b/cmake/ecbuild_check_fortran_source_return.cmake
@@ -0,0 +1,155 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_check_fortran_source_return
+# ===================================
+#
+# Compile and run a given Fortran code and return its output. ::
+#
+# ecbuild_check_fortran_source_return( <source>
+# VAR <name>
+# OUTPUT <name>
+# [ INCLUDES <path1> [ <path2> ... ] ]
+# [ LIBS <library1> [ <library2> ... ] ]
+# [ DEFINITIONS <def1> [ <def2> ... ] ] )
+#
+# Options
+# -------
+#
+# VAR : required
+# name of the check and name of the CMake variable to write result to
+#
+# OUTPUT : required
+# name of CMake variable to write the output to
+#
+# INCLUDES : optional
+# list of paths to add to include directories
+#
+# LIBS : optional
+# list of libraries to link against (CMake targets or external libraries)
+#
+# DEFINITIONS : optional
+# list of definitions to add to preprocessor defines
+#
+# Usage
+# -----
+#
+# This will write the given source to a .f file and compile and run it with
+# try_run. If successful, ``${VAR}`` is set to 1 and ``${OUTPUT}`` is set to
+# the output of the successful run in the CMake cache.
+#
+# The check will not run if ``${VAR}`` is defined (e.g. from ecBuild cache).
+#
+##############################################################################
+
+macro( ecbuild_check_fortran_source_return SOURCE )
+
+ ecbuild_warn( "This macro ecbuild_check_fortran_source has never been tested" )
+ set( options )
+ set( single_value_args VAR OUTPUT )
+ set( multi_value_args INCLUDES LIBS DEFINITIONS )
+
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_PAR_UNPARSED_ARGUMENTS)
+ ecbuild_critical("Unknown keywords given to ecbuild_check_fortran_source_return(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if( NOT _PAR_VAR OR NOT _PAR_OUTPUT )
+ ecbuild_critical("The call to ecbuild_check_fortran_source_return() doesn't specify either SOURCE, VAR or OUTPUT")
+ endif()
+
+
+ if( NOT DEFINED ${_PAR_VAR} )
+
+ set(MACRO_CHECK_FUNCTION_DEFINITIONS "-D${_PAR_VAR} ${CMAKE_REQUIRED_FLAGS}")
+
+ set(CHECK_Fortran_SOURCE_COMPILES_ADD_LIBRARIES)
+ if( CMAKE_REQUIRED_LIBRARIES )
+ list( APPEND __add_libs ${CMAKE_REQUIRED_LIBRARIES} )
+ endif()
+ if( _PAR_LIBS )
+ list( APPEND __add_libs ${_PAR_LIBS} )
+ endif()
+ if( __add_libs )
+ set(CHECK_Fortran_SOURCE_COMPILES_ADD_LIBRARIES "-DLINK_LIBRARIES:STRING=${__add_libs}")
+ endif()
+
+ set(CHECK_Fortran_SOURCE_COMPILES_ADD_INCLUDES)
+ if( CMAKE_REQUIRED_INCLUDES )
+ list( APPEND __add_incs ${CMAKE_REQUIRED_INCLUDES} )
+ endif()
+ if( _PAR_INCLUDES )
+ list( APPEND __add_incs ${_PAR_INCLUDES} )
+ endif()
+ if( __add_libs )
+ set(CHECK_Fortran_SOURCE_COMPILES_ADD_INCLUDES "-DINCLUDE_DIRECTORIES:STRING=${__add_incs}")
+ endif()
+
+ # write the source file
+
+ file( WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/test_${_PAR_VAR}.f" "${SOURCE}\n" )
+
+ ecbuild_debug( "Performing Test ${_PAR_VAR}" )
+ try_run( ${_PAR_VAR}_EXITCODE ${_PAR_VAR}_COMPILED
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/test_${_PAR_VAR}.f
+ COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+ CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS}
+ -DCMAKE_SKIP_RPATH:BOOL=${CMAKE_SKIP_RPATH}
+ "${CHECK_Fortran_SOURCE_COMPILES_ADD_LIBRARIES}"
+ "${CHECK_Fortran_SOURCE_COMPILES_ADD_INCLUDES}"
+ COMPILE_OUTPUT_VARIABLE compile_OUTPUT
+ RUN_OUTPUT_VARIABLE run_OUTPUT )
+
+ # if it did not compile make the return value fail code of 1
+ if( NOT ${_PAR_VAR}_COMPILED )
+ set( ${_PAR_VAR}_EXITCODE 1 )
+ endif()
+
+ # if the return value was 0 then it worked
+ if("${${_PAR_VAR}_EXITCODE}" EQUAL 0)
+
+ ecbuild_debug("Performing Test ${_PAR_VAR} - Success")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Performing Fortran SOURCE FILE Test ${_PAR_VAR} succeded with the following compile output:\n"
+ "${compile_OUTPUT}\n"
+ "Performing Fortran SOURCE FILE Run ${_PAR_VAR} succeded with the following run output:\n"
+ "${run_OUTPUT}\n"
+ "Return value: ${${_PAR_VAR}}\n"
+ "Source file was:\n${SOURCE}\n")
+
+ set( ${_PAR_VAR} 1 CACHE INTERNAL "Test ${_PAR_VAR}")
+ set( ${_PAR_OUTPUT} "${run_OUTPUT}" CACHE INTERNAL "Test ${_PAR_VAR} output")
+
+ else()
+
+ if(CMAKE_CROSSCOMPILING AND "${${_PAR_VAR}_EXITCODE}" MATCHES "FAILED_TO_RUN")
+ set(${_PAR_VAR} "${${_PAR_VAR}_EXITCODE}")
+ set(${OUTPUT} "")
+ else()
+ set(${_PAR_VAR} "" CACHE INTERNAL "Test ${_PAR_VAR}")
+ set(${_PAR_OUTPUT} "" CACHE INTERNAL "Test ${_PAR_VAR} output")
+ endif()
+
+ ecbuild_debug("Performing Test ${_PAR_VAR} - Failed")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Performing C SOURCE FILE Test ${_PAR_VAR} failed with the following compile output:\n"
+ "${compile_OUTPUT}\n"
+ "Performing C SOURCE FILE Run ${_PAR_VAR} failed with the following run output:\n"
+ "${run_OUTPUT}\n"
+ "Return value: ${${_PAR_VAR}_EXITCODE}\n"
+ "Source file was:\n${SOURCE}\n")
+ endif()
+
+ endif()
+
+endmacro()
diff --git a/cmake/ecbuild_check_functions.cmake b/cmake/ecbuild_check_functions.cmake
new file mode 100644
index 0000000..7b850e9
--- /dev/null
+++ b/cmake/ecbuild_check_functions.cmake
@@ -0,0 +1,172 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+############################################################################################
+# os capability checks
+
+if( ENABLE_OS_FUNCTIONS_TEST )
+
+ ### symbol checks ##################
+
+ ecbuild_cache_check_symbol_exists( fseek "stdio.h" EC_HAVE_FSEEK )
+ ecbuild_cache_check_symbol_exists( fseeko "stdio.h" EC_HAVE_FSEEKO )
+ ecbuild_cache_check_symbol_exists( ftello "stdio.h" EC_HAVE_FTELLO )
+ ecbuild_cache_check_symbol_exists( lseek "sys/types.h;unistd.h" EC_HAVE_LSEEK )
+ ecbuild_cache_check_symbol_exists( ftruncate "sys/types.h;unistd.h" EC_HAVE_FTRUNCATE )
+ ecbuild_cache_check_symbol_exists( open "sys/types.h;sys/stat.h;fcntl.h" EC_HAVE_OPEN )
+ ecbuild_cache_check_symbol_exists( fopen "stdio.h" EC_HAVE_FOPEN )
+ ecbuild_cache_check_symbol_exists( flock "sys/file.h" EC_HAVE_FLOCK )
+ ecbuild_cache_check_symbol_exists( mmap "sys/mman.h" EC_HAVE_MMAP )
+
+ ecbuild_cache_check_symbol_exists( posix_memalign "stdlib.h" EC_HAVE_POSIX_MEMALIGN )
+
+ ecbuild_cache_check_symbol_exists( F_GETLK "fcntl.h" EC_HAVE_F_GETLK )
+ ecbuild_cache_check_symbol_exists( F_SETLK "fcntl.h" EC_HAVE_F_SETLK )
+ ecbuild_cache_check_symbol_exists( F_SETLKW "fcntl.h" EC_HAVE_F_SETLKW )
+
+ ecbuild_cache_check_symbol_exists( F_GETLK64 "fcntl.h" EC_HAVE_F_GETLK64 )
+ ecbuild_cache_check_symbol_exists( F_SETLK64 "fcntl.h" EC_HAVE_F_SETLK64 )
+ ecbuild_cache_check_symbol_exists( F_SETLKW64 "fcntl.h" EC_HAVE_F_SETLKW64 )
+
+ ecbuild_cache_check_symbol_exists( MAP_ANONYMOUS "sys/mman.h" EC_HAVE_MAP_ANONYMOUS )
+ ecbuild_cache_check_symbol_exists( MAP_ANON "sys/mman.h" EC_HAVE_MAP_ANON )
+
+ ### include files checks ##################
+
+ ecbuild_cache_check_include_files( assert.h EC_HAVE_ASSERT_H )
+ ecbuild_cache_check_include_files( stdlib.h EC_HAVE_STDLIB_H )
+ ecbuild_cache_check_include_files( unistd.h EC_HAVE_UNISTD_H )
+ ecbuild_cache_check_include_files( string.h EC_HAVE_STRING_H )
+ ecbuild_cache_check_include_files( strings.h EC_HAVE_STRINGS_H )
+ ecbuild_cache_check_include_files( sys/stat.h EC_HAVE_SYS_STAT_H )
+ ecbuild_cache_check_include_files( sys/time.h EC_HAVE_SYS_TIME_H )
+ ecbuild_cache_check_include_files( sys/types.h EC_HAVE_SYS_TYPES_H )
+ ecbuild_cache_check_include_files( malloc.h EC_HAVE_MALLOC_H )
+ ecbuild_cache_check_include_files( sys/malloc.h EC_HAVE_SYS_MALLOC_H )
+
+ ecbuild_cache_check_include_files( sys/param.h EC_HAVE_SYS_PARAM_H )
+ ecbuild_cache_check_include_files( sys/mount.h EC_HAVE_SYS_MOUNT_H )
+ ecbuild_cache_check_include_files( sys/vfs.h EC_HAVE_SYS_VFS_H )
+
+ ### capability checks ##################
+
+ # test off_t
+ ecbuild_cache_check_c_source_compiles( "#include <sys/types.h>\nint main(){ off_t l=0; return 0;}\n" EC_HAVE_OFFT )
+ # test off64_t
+ ecbuild_cache_check_c_source_compiles( "#define _LARGEFILE64_SOURCE\n#include <stdio.h>\n#include <sys/types.h>\nint main(){ off64_t l=0; return 0;}\n" EC_HAVE_OFF64T )
+ # test struct stat
+ ecbuild_cache_check_c_source_compiles( "#include <sys/stat.h>\nint main(){ struct stat s; return 0; }" EC_HAVE_STRUCT_STAT )
+ # test struct stat64
+ ecbuild_cache_check_c_source_compiles( "#define _LARGEFILE64_SOURCE\n#include <sys/stat.h>\nint main(){ struct stat64 s; return 0; }" EC_HAVE_STRUCT_STAT64 )
+ # test stat
+ ecbuild_cache_check_c_source_compiles( "#include <sys/stat.h>\nint main(){ struct stat s; stat(\"\",&s); return 0; }" EC_HAVE_STAT )
+ # test stat64
+ ecbuild_cache_check_c_source_compiles( "#define _LARGEFILE64_SOURCE\n#include <sys/stat.h>\nint main(){ struct stat64 s; stat64(\"\",&s); return 0; }" EC_HAVE_STAT64 )
+ # test fstat
+ ecbuild_cache_check_c_source_compiles( "#include <sys/stat.h>\nint main(){ struct stat s; fstat(1,&s); return 0; }" EC_HAVE_FSTAT )
+ # test fstat64
+ ecbuild_cache_check_c_source_compiles( "#define _LARGEFILE64_SOURCE\n#include <sys/stat.h>\nint main(){ struct stat64 s; fstat64(1,&s); return 0; }" EC_HAVE_FSTAT64 )
+ # test fseeko64
+ ecbuild_cache_check_c_source_compiles( "#define _LARGEFILE64_SOURCE\n#include <stdio.h>\n#include <sys/types.h>\nint main(){FILE* file;off64_t l=0;fseeko64(file,l,SEEK_CUR);return 0;}\n" EC_HAVE_FSEEKO64 )
+
+ # test for ftello64
+ ecbuild_cache_check_c_source_compiles( "#define _LARGEFILE64_SOURCE\n#include <stdio.h>\n#include <sys/types.h>\nint main(){FILE* file;off64_t l = ftello64(file);return 0;}\n" EC_HAVE_FTELLO64 )
+
+ # test for lseek64
+ ecbuild_cache_check_c_source_compiles( "#define _LARGEFILE64_SOURCE\n#include <sys/types.h>\n#include <unistd.h>\nint main(){off64_t h = lseek64(0,0,SEEK_SET);return 0;}\n" EC_HAVE_LSEEK64 )
+ # test for open64
+ ecbuild_cache_check_c_source_compiles( "#define _LARGEFILE64_SOURCE\n#include <fcntl.h>\nint main(){int fd = open64(\"name\",O_RDWR|O_CREAT,0777);return 0;}\n" EC_HAVE_OPEN64 )
+ # test for fopen64
+ ecbuild_cache_check_c_source_compiles( "#define _LARGEFILE64_SOURCE\n#include <stdio.h>\nint main(){FILE* file = fopen64(\"name\",\"w\");return 0;}\n" EC_HAVE_FOPEN64 )
+ # test for ftruncate64
+ ecbuild_cache_check_c_source_compiles( "#define _LARGEFILE64_SOURCE\n#include <unistd.h>\n#include <sys/types.h>\nint main(){ftruncate64(0,(off64_t)0);return 0;}\n" EC_HAVE_FTRUNCATE64 )
+ # test for flock64
+ ecbuild_cache_check_c_source_compiles( "#define _LARGEFILE64_SOURCE\n#include <fcntl.h>\nint main(){struct flock64 l;return 0;}\n" EC_HAVE_FLOCK64 )
+ # test for mmap64
+ ecbuild_cache_check_c_source_compiles( "#define _LARGEFILE64_SOURCE\n#include <sys/mman.h>\nint main(){void* addr = mmap64(0,10,PROT_READ|PROT_WRITE,MAP_PRIVATE,10,0); return 0;}\n" EC_HAVE_MMAP64 )
+ # test for struct statvfs
+ ecbuild_cache_check_c_source_compiles( "#include <sys/statvfs.h>\nint main(){ struct statvfs v; }" EC_HAVE_STRUCT_STATVFS )
+ # test for struct statvfs64
+ ecbuild_cache_check_c_source_compiles( "#define _LARGEFILE64_SOURCE\n#include <sys/statvfs.h>\nint main(){ struct statvfs64 v; }" EC_HAVE_STRUCT_STATVFS64 )
+
+ # test for fsync
+ ecbuild_cache_check_symbol_exists(fsync "unistd.h" EC_HAVE_FSYNC)
+ # test for fdatasync
+ ecbuild_cache_check_symbol_exists(fdatasync "unistd.h" EC_HAVE_FDATASYNC)
+ # test for dirfd
+ ecbuild_cache_check_c_source_compiles( "#include <sys/types.h>\n#include <dirent.h>\nint main(){ DIR *dirp; int i = dirfd(dirp); }\n" EC_HAVE_DIRFD )
+ # test for sys/proc.h
+ ecbuild_cache_check_c_source_compiles( "#include <sys/proc.h>\nint main(){ return 0; }\n" EC_HAVE_SYSPROC )
+ # test for procfs
+ ecbuild_cache_check_c_source_compiles( "#include <sys/procfs.h>\nint main(){ return 0; }\n" EC_HAVE_SYSPROCFS )
+ # test for backtrace
+ ecbuild_cache_check_c_source_compiles( "#include <unistd.h>\n#include <execinfo.h>\n int main(){ void ** buffer; int i = backtrace(buffer, 256); }\n" EC_HAVE_EXECINFO_BACKTRACE )
+
+ #### reentrant funtions support #############
+
+ # test for gmtime_r
+ ecbuild_cache_check_c_source_compiles( "#include <time.h>\nint main(){ time_t now; time(&now); struct tm t; gmtime_r(&now,&t); }\n" EC_HAVE_GMTIME_R )
+ # test for getpwuid_r
+ ecbuild_cache_check_c_source_compiles( "#include <unistd.h>\n#include <sys/types.h>\n#include <pwd.h>\nint main(){ char buf[4096]; struct passwd pwbuf; struct passwd *pwbufp = 0; getpwuid_r(getuid(), &pwbuf, buf, sizeof(buf), &pwbufp); }\n" EC_HAVE_GETPWUID_R )
+ # test for getpwnam_r
+ ecbuild_cache_check_c_source_compiles( "#include <sys/types.h>\n#include <pwd.h>\nint main(){ struct passwd p; char line[1024]; int n = getpwnam_r(\"user\",&p,line,sizeof(line),0); }\n" EC_HAVE_GETPWNAM_R )
+ # test for readdir_r
+ ecbuild_cache_check_c_source_compiles( "#include <dirent.h>\nint main(){ DIR *dirp; struct dirent *entry; struct dirent **result; int i = readdir_r(dirp, entry, result); }\n" EC_HAVE_READDIR_R )
+ # test for gethostbyname_r
+ ecbuild_cache_check_c_source_compiles( "#include <netdb.h>\nint main(){ const char *name; struct hostent *ret; char *buf; struct hostent **result; size_t buflen; int *h_errnop; int i = gethostbyname_r(name,ret,buf,buflen,result,h_errnop); }\n" EC_HAVE_GETHOSTBYNAME_R )
+
+ #### special compiler __atributes__ #############
+
+ # test for __attribute__ ((__constructor__)) -- usually present in GCC, Clang, Intel on Linux, Solaris, MacOSX; not present in AIX XLC
+ ecbuild_cache_check_c_source_compiles( "#include <stdio.h>\nstatic int argc_;static char** argv_;static char** envp_;\nint main(){printf(\"%d\", argc_);}\n__attribute__ ((__constructor__)) static void before_main(int argc, char* argv[], char* envp[]){argc_ = argc;argv_ = argv;envp_ = envp;}\n" EC_HAVE_ATTRIBUTE_CONSTRUCTOR )
+
+ if( NOT DEFINED EC_ATTRIBUTE_CONSTRUCTOR_INITS_ARGV )
+ ecbuild_check_c_source_return("
+ #include <stdio.h>
+ #include <string.h>
+ int main(){return 0;}
+ __attribute__ ((__constructor__))
+ static void before_main(int argc, char* argv[], char* envp[])
+ {
+ printf(\"%d:%d\",argc, strstr(argv[0],\"cmTryCompileExec\")?1:0);
+ }"
+ VAR EC_ATTRIBUTE_CONSTRUCTOR_INITS_ARGV
+ OUTPUT EC_ATTRIBUTE_CONSTRUCTOR_INITS_OUTPUT )
+
+ if( EC_ATTRIBUTE_CONSTRUCTOR_INITS_ARGV AND NOT EC_ATTRIBUTE_CONSTRUCTOR_INITS_OUTPUT STREQUAL "1:1" )
+ set(EC_ATTRIBUTE_CONSTRUCTOR_INITS_ARGV 0 CACHE INTERNAL "ATTRIBUTE_CONSTRUCTOR doesnt init argv correctly")
+ endif()
+ endif()
+ ecbuild_cache_var( EC_ATTRIBUTE_CONSTRUCTOR_INITS_ARGV )
+
+
+ #### check for some Linux stuff #############
+
+ if( NOT DEFINED EC_HAVE_PROCFS )
+ ecbuild_check_c_source_return("
+ #include <sys/types.h>
+ #include <dirent.h>
+ int main()
+ {
+ DIR* d = opendir(\"/proc\");
+ if(d)
+ return 0;
+ else
+ return -1;
+ }"
+ VAR EC_HAVE_PROCFS
+ OUTPUT EC_HAVE_PROCFS_OUTPUT )
+ endif()
+ ecbuild_cache_var( EC_HAVE_PROCFS )
+
+# ecbuild_debug_var(EC_HAVE_PROCFS)
+# ecbuild_debug_var(EC_HAVE_PROCFS_OUTPUT)
+
+endif()
+
+
diff --git a/cmake/ecbuild_check_os.cmake b/cmake/ecbuild_check_os.cmake
new file mode 100644
index 0000000..7bbb344
--- /dev/null
+++ b/cmake/ecbuild_check_os.cmake
@@ -0,0 +1,396 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+############################################################################################
+# check size of pointer
+
+# Re-check size of void pointer since for some compiler combinations this is not properly set
+ecbuild_cache_check_type_size( "void*" CMAKE_SIZEOF_VOID_P )
+
+if( NOT CMAKE_C_COMPILER_LOADED AND ENABLE_OS_TESTS )
+
+ enable_language( C )
+ ecbuild_compiler_flags( C )
+
+endif()
+
+math( EXPR EC_OS_BITS "${CMAKE_SIZEOF_VOID_P} * 8" )
+
+# we only support 32 and 64 bit operating systems
+if( NOT EC_OS_BITS EQUAL "32" AND NOT EC_OS_BITS EQUAL "64" )
+ ecbuild_critical( "operating system ${CMAKE_SYSTEM} ${EC_OS_BITS} bits -- ecbuild only supports 32 or 64 bit OS's" )
+endif()
+
+############################################################################################
+# For 64 bit architectures enable PIC (position-independent code)
+
+# Allow overriding the position independent code setting (ECBUILD-220)
+if( DEFINED ECBUILD_POSITION_INDEPENDENT_CODE )
+ set( CMAKE_POSITION_INDEPENDENT_CODE ${ECBUILD_POSITION_INDEPENDENT_CODE} )
+elseif( ${EC_OS_BITS} EQUAL 64 )
+ set( CMAKE_POSITION_INDEPENDENT_CODE ON )
+endif()
+
+
+############################################################################################
+# check architecture
+
+if( ENABLE_OS_TYPES_TEST )
+
+ set( EC_SIZEOF_PTR ${CMAKE_SIZEOF_VOID_P} )
+ ecbuild_cache_var( EC_SIZEOF_PTR )
+ ecbuild_cache_check_type_size( char EC_SIZEOF_CHAR )
+ ecbuild_cache_check_type_size( short EC_SIZEOF_SHORT )
+ ecbuild_cache_check_type_size( int EC_SIZEOF_INT )
+ ecbuild_cache_check_type_size( long EC_SIZEOF_LONG )
+ ecbuild_cache_check_type_size( "long long" EC_SIZEOF_LONG_LONG )
+ ecbuild_cache_check_type_size( float EC_SIZEOF_FLOAT )
+ ecbuild_cache_check_type_size( double EC_SIZEOF_DOUBLE )
+ ecbuild_cache_check_type_size( "long double" EC_SIZEOF_LONG_DOUBLE )
+ ecbuild_cache_check_type_size( size_t EC_SIZEOF_SIZE_T )
+ ecbuild_cache_check_type_size( ssize_t EC_SIZEOF_SSIZE_T )
+ ecbuild_cache_check_type_size( off_t EC_SIZEOF_OFF_T )
+
+# ecbuild_info( "sizeof void* [${EC_SIZEOF_PTR}]" )
+# ecbuild_info( "sizeof off_t [${EC_SIZEOF_OFF_T}]" )
+# ecbuild_info( "sizeof int [${EC_SIZEOF_INT}]" )
+# ecbuild_info( "sizeof short [${EC_SIZEOF_SHORT}]" )
+# ecbuild_info( "sizeof long [${EC_SIZEOF_LONG}]" )
+# ecbuild_info( "sizeof size_t [${EC_SIZEOF_SIZE_T}]" )
+# ecbuild_info( "sizeof float [${EC_SIZEOF_FLOAT}]" )
+# ecbuild_info( "sizeof double [${EC_SIZEOF_DOUBLE}]" )
+# ecbuild_info( "sizeof long long [${EC_SIZEOF_LONG_LONG}]" )
+# ecbuild_info( "sizeof long double [${EC_SIZEOF_LONG_DOUBLE}]" )
+
+# ecbuild_info( "system sizeof :" )
+# ecbuild_info( " void* [${EC_SIZEOF_PTR}] size_t [${EC_SIZEOF_SIZE_T}] off_t [${EC_SIZEOF_OFF_T}] short [${EC_SIZEOF_SHORT}]" )
+# ecbuild_info( " int [${EC_SIZEOF_INT}] long [${EC_SIZEOF_LONG}] long long [${EC_SIZEOF_LONG_LONG}]" )
+# ecbuild_info( " float [${EC_SIZEOF_FLOAT}] double [${EC_SIZEOF_DOUBLE}] long double [${EC_SIZEOF_LONG_DOUBLE}]" )
+
+endif()
+
+############################################################################################
+# check for large file support
+
+# ensure we use 64bit access to files even on 32bit os -- aka Large File Support
+# by making off_t 64bit and stat behave as stat64
+
+if( ENABLE_LARGE_FILE_SUPPORT )
+
+ ecbuild_cache_check_type_size( off_t EC_SIZEOF_OFF_T )
+
+ if( EC_SIZEOF_OFF_T LESS "8" )
+
+ if( ${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "Darwin" )
+ add_definitions( -D_FILE_OFFSET_BITS=64 )
+ endif()
+
+ if( ${CMAKE_SYSTEM_NAME} MATCHES "AIX" )
+ add_definitions( -D_LARGE_FILES=64 )
+ endif()
+
+ get_directory_property( __compile_defs COMPILE_DEFINITIONS )
+
+ if( __compile_defs )
+ foreach( def ${__compile_defs} )
+ list( APPEND CMAKE_REQUIRED_DEFINITIONS -D${def} )
+ endforeach()
+ endif()
+
+ endif()
+
+endif()
+
+############################################################################################
+# check endiness
+
+if( ENABLE_OS_ENDINESS_TEST )
+
+ if( NOT DEFINED EC_BIG_ENDIAN AND NOT DEFINED EC_LITTLE_ENDIAN )
+
+ test_big_endian( _BIG_ENDIAN )
+
+ if( _BIG_ENDIAN )
+ set( EC_BIG_ENDIAN 1 )
+ set( EC_LITTLE_ENDIAN 0 )
+ else()
+ set( EC_BIG_ENDIAN 0 )
+ set( EC_LITTLE_ENDIAN 1 )
+ endif()
+
+ endif()
+
+ ecbuild_cache_var( EC_BIG_ENDIAN )
+ ecbuild_cache_var( EC_LITTLE_ENDIAN )
+
+ if( NOT DEFINED IEEE_BE )
+ check_c_source_runs(
+ "int compare(unsigned char* a,unsigned char* b) {
+ while(*a != 0) if (*(b++)!=*(a++)) return 1;
+ return 0;
+ }
+ int main(int argc,char** argv) {
+ unsigned char dc[]={0x30,0x61,0xDE,0x80,0x93,0x67,0xCC,0xD9,0};
+ double da=1.23456789e-75;
+ unsigned char* ca;
+
+ unsigned char fc[]={0x05,0x83,0x48,0x22,0};
+ float fa=1.23456789e-35;
+
+ if (sizeof(double)!=8) return 1;
+
+ ca=(unsigned char*)&da;
+ if (compare(dc,ca)) return 1;
+
+ if (sizeof(float)!=4) return 1;
+
+ ca=(unsigned char*)&fa;
+ if (compare(fc,ca)) return 1;
+
+ return 0;
+ }" IEEE_BE )
+
+ if( "${IEEE_BE}" STREQUAL "" )
+ set( IEEE_BE 0 CACHE INTERNAL "Test IEEE_BE")
+ endif()
+
+ endif()
+
+ ecbuild_cache_var( IEEE_BE )
+
+ if( EC_BIG_ENDIAN AND NOT IEEE_BE )
+ ecbuild_critical("Failed to sanity check on endiness: OS should be Big-Endian but compiled code runs differently -- to ignore this pass -DIEEE_BE=0 to CMake/ecBuild")
+ endif()
+
+ if( NOT DEFINED IEEE_LE )
+ check_c_source_runs(
+ "int compare(unsigned char* a,unsigned char* b) {
+ while(*a != 0) if (*(b++)!=*(a++)) return 1;
+ return 0;
+ }
+ int main(int argc,char** argv) {
+ unsigned char dc[]={0xD9,0xCC,0x67,0x93,0x80,0xDE,0x61,0x30,0};
+ double da=1.23456789e-75;
+ unsigned char* ca;
+
+ unsigned char fc[]={0x22,0x48,0x83,0x05,0};
+ float fa=1.23456789e-35;
+
+ if (sizeof(double)!=8) return 1;
+
+ ca=(unsigned char*)&da;
+ if (compare(dc,ca)) return 1;
+
+ if (sizeof(float)!=4) return 1;
+
+ ca=(unsigned char*)&fa;
+ if (compare(fc,ca)) return 1;
+
+ return 0;
+ }" IEEE_LE )
+
+ if( "${IEEE_LE}" STREQUAL "" )
+ set( IEEE_LE 0 CACHE INTERNAL "Test IEEE_LE")
+ endif()
+ endif()
+
+ ecbuild_cache_var( IEEE_LE )
+
+ if( EC_LITTLE_ENDIAN AND NOT IEEE_LE )
+ ecbuild_critical("Failed to sanity check on endiness: OS should be Little-Endian but compiled code runs differently -- to ignore this pass -DIEEE_LE=0 to CMake/ecBuild")
+ endif()
+
+endif()
+
+############################################################################################
+# enable profiling
+
+if( ENABLE_PROFILING )
+
+ if( CMAKE_C_COMPILER_ID MATCHES "GNU" )
+
+ set( _flags "-pg --coverage" )
+
+ set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${_flags}" )
+ set( CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${_flags}" )
+ set( CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${_flags}" )
+
+ set( _trust_flags ${ECBUILD_TRUST_FLAGS} )
+ set( ECBUILD_TRUST_FLAGS ON )
+ ecbuild_add_c_flags( "${_flags}" )
+ ecbuild_add_cxx_flags( "${_flags}" )
+ ecbuild_add_fortran_flags( "${_flags}" )
+ set( ECBUILD_TRUST_FLAGS ${_trust_flags} )
+ unset( _trust_flags )
+
+ unset( _flags )
+
+ else()
+ ecbuild_warn( "Profiling enabled but ecbuild doesn't know how to enable for this particular compiler ${CMAKE_C_COMPILER_ID}")
+ endif()
+
+endif()
+
+############################################################################################
+# check operating system
+
+set( EC_OS_NAME "UNKNOWN" )
+
+### Unix's -- Proper operating systems
+
+if( UNIX )
+
+ ### APPLE ###
+
+ if( APPLE AND ${CMAKE_SYSTEM_NAME} MATCHES "Darwin" )
+ set( EC_OS_NAME "macosx" )
+ endif()
+
+ ### Linux ###
+
+ if( ${CMAKE_SYSTEM_NAME} MATCHES "Linux" )
+
+ set( EC_OS_NAME "linux" )
+
+ # recent linkers default to --enable-new-dtags
+ # which then adds both RPATH and RUNPATH to executables
+ # thus invalidating RPATH setting, and making LD_LIBRARY_PATH take precedence
+ # to be sure, use tool 'readelf -a <exe> | grep PATH' to see what paths are built-in
+ # see:
+ # * http://blog.qt.digia.com/blog/2011/10/28/rpath-and-runpath
+ # * http://www.cmake.org/Wiki/CMake_RPATH_handling
+ # * man ld
+ # * http://blog.tremily.us/posts/rpath
+ # * http://fwarmerdam.blogspot.co.uk/2010/12/rpath-runpath-and-ldlibrarypath.html
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--disable-new-dtags")
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--disable-new-dtags")
+ set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--disable-new-dtags")
+
+ endif()
+
+ ### Solaris ###
+
+ if( ${CMAKE_SYSTEM_NAME} MATCHES "SunOS" )
+ set( EC_OS_NAME "solaris" )
+ endif()
+
+ ### AIX ###
+
+ if( ${CMAKE_SYSTEM_NAME} MATCHES "AIX" )
+
+ set( EC_OS_NAME "aix" )
+
+ set( CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -bbigtoc" )
+
+ if( CMAKE_C_COMPILER_ID MATCHES "GNU" )
+ set( CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Xlinker" )
+ endif()
+
+ if( CMAKE_COMPILER_IS_GNUCC )
+ if( EC_OS_BITS EQUAL "64" )
+ ecbuild_add_c_flags("-maix64")
+ endif()
+ if( EC_OS_BITS EQUAL "32" )
+ ecbuild_add_c_flags("-maix32")
+ endif()
+ endif()
+
+ if( CMAKE_COMPILER_IS_GNUCXX )
+ if( EC_OS_BITS EQUAL "64" )
+ ecbuild_add_cxx_flags("-maix64")
+ endif()
+ if( EC_OS_BITS EQUAL "32" )
+ ecbuild_add_cxx_flags("-maix32")
+ endif()
+ endif()
+
+ if( CMAKE_C_COMPILER_ID MATCHES "XL" )
+
+ ecbuild_add_c_flags("-qpic=large")
+# ecbuild_add_c_flags("-qweaksymbol")
+
+ if(EC_OS_BITS EQUAL "32" )
+ ecbuild_add_c_flags("-q32")
+ endif()
+
+ if(${CMAKE_BUILD_TYPE} MATCHES "Release" OR ${CMAKE_BUILD_TYPE} MATCHES "Production" )
+ ecbuild_add_c_flags("-qstrict")
+ ecbuild_add_c_flags("-qinline")
+ endif()
+
+ if(${CMAKE_BUILD_TYPE} MATCHES "Debug")
+ ecbuild_add_c_flags("-qfullpath")
+ ecbuild_add_c_flags("-qkeepparm")
+ endif()
+
+ endif()
+
+ if( CMAKE_CXX_COMPILER_ID MATCHES "XL" )
+
+ ecbuild_add_cxx_flags("-qpic=large")
+ ecbuild_add_cxx_flags("-bmaxdata:0x40000000")
+ ecbuild_add_cxx_flags("-qrtti")
+ ecbuild_add_cxx_flags("-qfuncsect")
+
+# ecbuild_add_cxx_flags("-qweaksymbol")
+
+ if(EC_OS_BITS EQUAL "32" )
+ ecbuild_add_cxx_flags("-q32")
+ endif()
+
+ if(${CMAKE_BUILD_TYPE} MATCHES "Release" OR ${CMAKE_BUILD_TYPE} MATCHES "Production" )
+ ecbuild_add_cxx_flags("-qstrict")
+ ecbuild_add_cxx_flags("-qinline")
+ endif()
+
+ if(${CMAKE_BUILD_TYPE} MATCHES "Debug")
+ ecbuild_add_cxx_flags("-qfullpath")
+ ecbuild_add_cxx_flags("-qkeepparm")
+ endif()
+
+ endif()
+
+ if( CMAKE_Fortran_COMPILER_ID MATCHES "XL" )
+
+ ecbuild_add_fortran_flags("-qxflag=dealloc_cfptr")
+ ecbuild_add_fortran_flags("-qextname")
+ ecbuild_add_fortran_flags("-qdpc=e")
+ ecbuild_add_fortran_flags("-bmaxdata:0x40000000")
+ ecbuild_add_fortran_flags("-bloadmap:loadmap -bmap:loadmap")
+
+ if(EC_OS_BITS EQUAL "32" )
+ ecbuild_add_fortran_flags("-q32")
+ endif()
+ endif()
+
+ endif()
+
+endif()
+
+### Cygwin
+
+if( ${CMAKE_SYSTEM_NAME} MATCHES "CYGWIN" )
+
+ set( EC_OS_NAME "cygwin" )
+ ecbuild_warn( "Building on Cygwin should work but is untested" )
+
+endif()
+
+### final warning / error
+
+if( ${EC_OS_NAME} MATCHES "UNKNOWN" )
+
+ if( DISABLE_OS_CHECK )
+ ecbuild_warn( "ecBuild is untested for this operating system: [${CMAKE_SYSTEM_NAME}]"
+ " -- DISABLE_OS_CHECK is ON so proceeding at your own risk ..." )
+ else()
+ ecbuild_critical( "ecBuild is untested for this operating system: [${CMAKE_SYSTEM_NAME}]"
+ " -- refusing to continue. Disable this check with -DDISABLE_OS_CHECK=ON" )
+ endif()
+
+endif()
diff --git a/cmake/ecbuild_compiler_flags.cmake b/cmake/ecbuild_compiler_flags.cmake
new file mode 100644
index 0000000..b97eb2c
--- /dev/null
+++ b/cmake/ecbuild_compiler_flags.cmake
@@ -0,0 +1,97 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_compiler_flags
+# ======================
+#
+# Set default compiler flags for a given language. ::
+#
+# ecbuild_compiler_flags( <lang> )
+#
+# The procedure is as follows:
+#
+# 1. ecBuild does *not* set ``CMAKE_<lang>_FLAGS`` i.e. the user can set these
+# via -D or the CMake cache and these will be the "base" flags.
+#
+# 2. ecBuild *overwrites* ``CMAKE_<lang>_FLAGS_<btype>`` in the CMake cache
+# for all build types with compiler specific defaults for the currently
+# loaded compiler i.e. any value set by the user via -D or the CMake cache
+# *has no effect*.
+#
+# 3. Any value the user provides via ``ECBUILD_<lang>_FLAGS`` or
+# ``ECBUILD_<lang>_FLAGS_<btype>`` *overrides* the corresponding
+# ``CMAKE_<lang>_FLAGS`` or ``CMAKE_<lang>_FLAGS_<btype>`` *without being
+# written to the CMake cache*.
+#
+##############################################################################
+
+macro( ecbuild_compiler_flags _lang )
+
+ if( CMAKE_${_lang}_COMPILER_LOADED )
+
+ ecbuild_debug( "try include ${ECBUILD_MACROS_DIR}/compiler_flags/${CMAKE_${_lang}_COMPILER_ID}_${_lang}.cmake ")
+
+ include( ${ECBUILD_MACROS_DIR}/compiler_flags/${CMAKE_${_lang}_COMPILER_ID}_${_lang}.cmake OPTIONAL )
+
+ ecbuild_debug_var( CMAKE_${_lang}_FLAGS )
+
+ foreach( _btype NONE DEBUG BIT PRODUCTION RELEASE RELWITHDEBINFO )
+ ecbuild_debug_var( CMAKE_${_lang}_FLAGS_${_btype} )
+ endforeach()
+
+ endif()
+
+ foreach( _btype NONE DEBUG BIT PRODUCTION RELEASE RELWITHDEBINFO )
+ if( DEFINED ECBUILD_${_lang}_FLAGS_${_btype} )
+ set( CMAKE_${_lang}_FLAGS_${_btype} ${ECBUILD_${_lang}_FLAGS_${_btype}} )
+ endif()
+ mark_as_advanced( CMAKE_${_lang}_FLAGS_${_btype} )
+ endforeach()
+
+ if( DEFINED ECBUILD_${_lang}_FLAGS )
+ set( CMAKE_${_lang}_FLAGS "${ECBUILD_${_lang}_FLAGS}" )
+ endif()
+
+ mark_as_advanced( CMAKE_${_lang}_FLAGS )
+
+ if( DEFINED ECBUILD_${_lang}_LINK_FLAGS )
+ set( CMAKE_${_lang}_LINK_FLAGS "${ECBUILD_${_lang}_LINK_FLAGS}" )
+ endif()
+
+ mark_as_advanced( CMAKE_${_lang}_LINK_FLAGS )
+
+endmacro()
+
+#-----------------------------------------------------------------------------------------------------------------------
+
+### OVERRIDE Compiler FLAGS (we override because CMake forcely defines them) -- see ecbuild_compiler_flags() macro
+
+foreach( _lang C CXX Fortran )
+ if( CMAKE_${_lang}_COMPILER_LOADED )
+ ecbuild_compiler_flags( ${_lang} )
+ endif()
+endforeach()
+
+### OVERRIDE Linker FLAGS per object type (we override because CMake forcely defines them)
+
+foreach( _btype NONE DEBUG BIT PRODUCTION RELEASE RELWITHDEBINFO )
+
+ foreach( _obj EXE SHARED MODULE )
+ if( ECBUILD_${_obj}_LINKER_FLAGS_${_btype} )
+ set( CMAKE_${_obj}_LINKER_FLAGS_${_btype} ${ECBUILD_${_obj}_LINKER_FLAGS_${_btype}} )
+ endif()
+ endforeach()
+
+endforeach()
+
+#-----------------------------------------------------------------------------------------------------------------------
+
+mark_as_advanced( CMAKE_C_FLAGS_BIT )
diff --git a/cmake/ecbuild_config.h.in b/cmake/ecbuild_config.h.in
new file mode 100644
index 0000000..eef9b85
--- /dev/null
+++ b/cmake/ecbuild_config.h.in
@@ -0,0 +1,192 @@
+/*
+ * (C) Copyright 1996-2016 ECMWF.
+ *
+ * This software is licensed under the terms of the Apache Licence Version 2.0
+ * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+ * In applying this licence, ECMWF does not waive the privileges and immunities
+ * granted to it by virtue of its status as an intergovernmental organisation nor
+ * does it submit to any jurisdiction.
+ */
+
+#ifndef @PROJECT_NAME at _ecbuild_config_h
+#define @PROJECT_NAME at _ecbuild_config_h
+
+/* ecbuild info */
+
+#ifndef ECBUILD_VERSION_STR
+#define ECBUILD_VERSION_STR "@ECBUILD_VERSION_STR@"
+#endif
+#ifndef ECBUILD_MACROS_DIR
+#define ECBUILD_MACROS_DIR "@ECBUILD_MACROS_DIR@"
+#endif
+
+/* cpu arch info */
+
+#cmakedefine EC_BIG_ENDIAN @EC_BIG_ENDIAN@
+#cmakedefine EC_LITTLE_ENDIAN @EC_LITTLE_ENDIAN@
+
+/* compiler support */
+
+#cmakedefine EC_HAVE_FUNCTION_DEF
+
+/* os capability checks */
+
+/* --- symbols --- */
+
+#cmakedefine EC_HAVE_FSEEK
+#cmakedefine EC_HAVE_FSEEKO
+#cmakedefine EC_HAVE_FTELLO
+#cmakedefine EC_HAVE_LSEEK
+#cmakedefine EC_HAVE_FTRUNCATE
+#cmakedefine EC_HAVE_OPEN
+#cmakedefine EC_HAVE_FOPEN
+#cmakedefine EC_HAVE_FLOCK
+#cmakedefine EC_HAVE_MMAP
+
+#cmakedefine EC_HAVE_POSIX_MEMALIGN
+
+#cmakedefine EC_HAVE_F_GETLK
+#cmakedefine EC_HAVE_F_SETLKW
+#cmakedefine EC_HAVE_F_SETLK
+
+#cmakedefine EC_HAVE_F_GETLK64
+#cmakedefine EC_HAVE_F_SETLKW64
+#cmakedefine EC_HAVE_F_SETLK64
+
+#cmakedefine EC_HAVE_MAP_ANONYMOUS
+#cmakedefine EC_HAVE_MAP_ANON
+
+/* --- include files --- */
+
+#cmakedefine EC_HAVE_ASSERT_H
+#cmakedefine EC_HAVE_STDLIB_H
+#cmakedefine EC_HAVE_UNISTD_H
+#cmakedefine EC_HAVE_STRING_H
+#cmakedefine EC_HAVE_STRINGS_H
+#cmakedefine EC_HAVE_SYS_STAT_H
+#cmakedefine EC_HAVE_SYS_TIME_H
+#cmakedefine EC_HAVE_SYS_TYPES_H
+
+#cmakedefine EC_HAVE_MALLOC_H
+#cmakedefine EC_HAVE_SYS_MALLOC_H
+
+#cmakedefine EC_HAVE_SYS_PARAM_H
+#cmakedefine EC_HAVE_SYS_MOUNT_H
+#cmakedefine EC_HAVE_SYS_VFS_H
+
+/* --- capabilities --- */
+
+#cmakedefine EC_HAVE_OFFT
+#cmakedefine EC_HAVE_OFF64T
+
+#cmakedefine EC_HAVE_STRUCT_STAT
+#cmakedefine EC_HAVE_STRUCT_STAT64
+#cmakedefine EC_HAVE_STAT
+#cmakedefine EC_HAVE_STAT64
+#cmakedefine EC_HAVE_FSTAT
+#cmakedefine EC_HAVE_FSTAT64
+
+#cmakedefine EC_HAVE_FSEEKO64
+#cmakedefine EC_HAVE_FTELLO64
+#cmakedefine EC_HAVE_LSEEK64
+#cmakedefine EC_HAVE_OPEN64
+#cmakedefine EC_HAVE_FOPEN64
+#cmakedefine EC_HAVE_FTRUNCATE64
+#cmakedefine EC_HAVE_FLOCK64
+#cmakedefine EC_HAVE_MMAP64
+
+#cmakedefine EC_HAVE_STRUCT_STATVFS
+#cmakedefine EC_HAVE_STRUCT_STATVFS64
+#cmakedefine EC_HAVE_STATVFS
+#cmakedefine EC_HAVE_STATVFS64
+
+#cmakedefine EC_HAVE_FSYNC
+#cmakedefine EC_HAVE_FDATASYNC
+#cmakedefine EC_HAVE_DIRFD
+#cmakedefine EC_HAVE_SYSPROC
+#cmakedefine EC_HAVE_SYSPROCFS
+
+#cmakedefine EC_HAVE_EXECINFO_BACKTRACE
+
+/* --- asynchronous IO support --- */
+
+#cmakedefine EC_HAVE_AIOCB
+#cmakedefine EC_HAVE_AIO64CB
+
+/* --- reentrant funtions support --- */
+
+#cmakedefine EC_HAVE_GMTIME_R
+#cmakedefine EC_HAVE_GETPWUID_R
+#cmakedefine EC_HAVE_GETPWNAM_R
+#cmakedefine EC_HAVE_READDIR_R
+#cmakedefine EC_HAVE_GETHOSTBYNAME_R
+
+/* --- compiler __attribute__ support --- */
+
+#cmakedefine EC_HAVE_ATTRIBUTE_CONSTRUCTOR
+#cmakedefine EC_ATTRIBUTE_CONSTRUCTOR_INITS_ARGV
+#cmakedefine EC_HAVE_PROCFS
+
+/* --- c compiler support --- */
+
+#cmakedefine EC_HAVE_C_INLINE
+
+/* --- c++ compiler support --- */
+
+#cmakedefine EC_HAVE_FUNCTION_DEF
+
+#cmakedefine EC_HAVE_CXXABI_H
+#cmakedefine EC_HAVE_CXX_BOOL
+
+#cmakedefine EC_HAVE_CXX_SSTREAM
+
+/* config info */
+
+#define @PNAME at _OS_NAME "@CMAKE_SYSTEM@"
+#define @PNAME at _OS_BITS @EC_OS_BITS@
+#define @PNAME at _OS_BITS_STR "@EC_OS_BITS@"
+#define @PNAME at _OS_STR "@EC_OS_NAME at .@EC_OS_BITS@"
+#define @PNAME at _OS_VERSION "@CMAKE_SYSTEM_VERSION@"
+#define @PNAME at _SYS_PROCESSOR "@CMAKE_SYSTEM_PROCESSOR@"
+
+#define @PNAME at _BUILD_TIMESTAMP "@EC_BUILD_TIMESTAMP@"
+#define @PNAME at _BUILD_TYPE "@CMAKE_BUILD_TYPE@"
+
+#define @PNAME at _C_COMPILER_ID "@CMAKE_C_COMPILER_ID@"
+#define @PNAME at _C_COMPILER_VERSION "@CMAKE_C_COMPILER_VERSION@"
+
+#define @PNAME at _CXX_COMPILER_ID "@CMAKE_CXX_COMPILER_ID@"
+#define @PNAME at _CXX_COMPILER_VERSION "@CMAKE_CXX_COMPILER_VERSION@"
+
+#define @PNAME at _C_COMPILER "@CMAKE_C_COMPILER@"
+#define @PNAME at _C_FLAGS "@EC_C_FLAGS@"
+
+#define @PNAME at _CXX_COMPILER "@CMAKE_CXX_COMPILER@"
+#define @PNAME at _CXX_FLAGS "@EC_CXX_FLAGS@"
+
+/* Needed for finding per package config files */
+
+#define @PNAME at _INSTALL_DIR "@CMAKE_INSTALL_PREFIX@"
+#define @PNAME at _INSTALL_BIN_DIR "@CMAKE_INSTALL_PREFIX@/@INSTALL_BIN_DIR@"
+#define @PNAME at _INSTALL_LIB_DIR "@CMAKE_INSTALL_PREFIX@/@INSTALL_LIB_DIR@"
+#define @PNAME at _INSTALL_DATA_DIR "@CMAKE_INSTALL_PREFIX@/@INSTALL_DATA_DIR@"
+
+#define @PNAME at _DEVELOPER_SRC_DIR "@CMAKE_SOURCE_DIR@"
+#define @PNAME at _DEVELOPER_BIN_DIR "@CMAKE_BINARY_DIR@"
+
+#cmakedefine EC_HAVE_FORTRAN
+
+#ifdef EC_HAVE_FORTRAN
+
+#define @PNAME at _Fortran_COMPILER_ID "@CMAKE_Fortran_COMPILER_ID@"
+#define @PNAME at _Fortran_COMPILER_VERSION "@CMAKE_Fortran_COMPILER_VERSION@"
+
+#define @PNAME at _Fortran_COMPILER "@CMAKE_Fortran_COMPILER@"
+#define @PNAME at _Fortran_FLAGS "@EC_Fortran_FLAGS@"
+
+#endif
+
+#cmakedefine BOOST_UNIT_TEST_FRAMEWORK_HEADER_ONLY
+#cmakedefine BOOST_UNIT_TEST_FRAMEWORK_LINKED
+
+#endif /* @PROJECT_NAME at _ecbuild_config_h */
diff --git a/cmake/ecbuild_declare_project.cmake b/cmake/ecbuild_declare_project.cmake
new file mode 100644
index 0000000..1c2e93b
--- /dev/null
+++ b/cmake/ecbuild_declare_project.cmake
@@ -0,0 +1,193 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_declare_project
+# =======================
+#
+# Initialise an ecBuild project. A CMake project must have previously been
+# declared with ``project( <name> ... )``. ::
+#
+# ecbuild_declare_project()
+#
+# Sets the following CMake variables
+# (where ``PNAME`` is the capitalised project name):
+#
+# :<PNAME>_GIT_SHA1: Git revision (if project is a Git repo)
+# :<PNAME>_GIT_SHA1_SHORT: short Git revision (if project is a Git repo)
+# :<PNAME>_VERSION: version in format ``MAJOR.MINOR.PATCH``
+# :<PNAME>_VERSION_STR: version as given in ``VERSION.cmake`` or 0.0.0
+# :<PNAME>_MAJOR_VERSION: major version number
+# :<PNAME>_MINOR_VERSION: minor version number
+# :<PNAME>_PATCH_VERSION: patch version number
+# :INSTALL_BIN_DIR: relative install directory for executables
+# (default: ``bin``)
+# :INSTALL_LIB_DIR: relative install directory for libraries
+# (default: ``lib``)
+# :INSTALL_INCLUDE_DIR: relative install directory for include files
+# (default: ``include``)
+# :INSTALL_DATA_DIR: relative install directory for data
+# (default: ``share/<project_name>``)
+# :INSTALL_CMAKE_DIR: relative install directory for CMake files
+# (default: ``share/<project_name>/cmake``)
+#
+# The relative installation directories of components can be customised by
+# setting the following CMake variables on the command line or in cache:
+#
+# :<PNAME>_INSTALL_BIN_DIR: directory for installing executables
+# :<PNAME>_INSTALL_LIB_DIR: directory for installing libraries
+# :<PNAME>_INSTALL_INCLUDE_DIR: directory for installing include files
+# :<PNAME>_INSTALL_DATA_DIR: directory for installing data
+# :<PNAME>_INSTALL_CMAKE_DIR: directory for installing CMake files
+#
+# Using *relative* paths is recommended, which are interpreted relative to the
+# ``CMAKE_INSTALL_PREFIX``. Using absolute paths makes the build
+# non-relocatable and may break the generation of relocatable binary packages.
+#
+##############################################################################
+
+macro( ecbuild_declare_project )
+
+ string( TOUPPER ${PROJECT_NAME} PNAME )
+
+ # reset the lists of targets (executables, libs, tests & resources)
+
+ set( ${PROJECT_NAME}_ALL_EXES "" CACHE INTERNAL "" )
+ set( ${PROJECT_NAME}_ALL_LIBS "" CACHE INTERNAL "" )
+
+ # if git project get its HEAD SHA1
+ # leave it here so we may use ${PNAME}_GIT_SHA1 on the version file
+
+ if( EXISTS ${PROJECT_SOURCE_DIR}/.git )
+ get_git_head_revision( GIT_REFSPEC ${PNAME}_GIT_SHA1 )
+ if( ${PNAME}_GIT_SHA1 )
+ string( SUBSTRING "${${PNAME}_GIT_SHA1}" 0 7 ${PNAME}_GIT_SHA1_SHORT )
+ # ecbuild_debug_var( ${PNAME}_GIT_SHA1 )
+ # ecbuild_debug_var( ${PNAME}_GIT_SHA1_SHORT )
+ else()
+ ecbuild_debug( "Could not get git-sha1 for project ${PNAME}")
+ endif()
+ endif()
+
+ # read and parse project version file
+ if( EXISTS ${PROJECT_SOURCE_DIR}/VERSION.cmake )
+ include( ${PROJECT_SOURCE_DIR}/VERSION.cmake )
+ else()
+ set( ${PROJECT_NAME}_VERSION_STR "0.0.0" )
+ endif()
+
+ string( REPLACE "." " " _version_list ${${PROJECT_NAME}_VERSION_STR} ) # dots to spaces
+
+ separate_arguments( _version_list )
+
+ list( GET _version_list 0 ${PNAME}_MAJOR_VERSION )
+ list( GET _version_list 1 ${PNAME}_MINOR_VERSION )
+ list( GET _version_list 2 ${PNAME}_PATCH_VERSION )
+
+ # cleanup patch version of any extra qualifiers ( -dev -rc1 ... )
+
+ string( REGEX REPLACE "^([0-9]+).*" "\\1" ${PNAME}_PATCH_VERSION "${${PNAME}_PATCH_VERSION}" )
+
+ set( ${PNAME}_VERSION "${${PNAME}_MAJOR_VERSION}.${${PNAME}_MINOR_VERSION}.${${PNAME}_PATCH_VERSION}"
+ CACHE INTERNAL "package ${PNAME} version" )
+
+ set( ${PNAME}_VERSION_STR "${${PROJECT_NAME}_VERSION_STR}"
+ CACHE INTERNAL "package ${PNAME} version string" ) # ignore caps
+
+ # ecbuild_debug_var( ${PNAME}_VERSION )
+ # ecbuild_debug_var( ${PNAME}_VERSION_STR )
+ # ecbuild_debug_var( ${PNAME}_MAJOR_VERSION )
+ # ecbuild_debug_var( ${PNAME}_MINOR_VERSION )
+ # ecbuild_debug_var( ${PNAME}_PATCH_VERSION )
+
+ # install dirs for this project
+
+ set( INSTALL_BIN_DIR bin )
+ set( INSTALL_LIB_DIR lib )
+ set( INSTALL_INCLUDE_DIR include )
+ set( INSTALL_DATA_DIR share/${PROJECT_NAME} )
+ set( INSTALL_CMAKE_DIR share/${PROJECT_NAME}/cmake )
+
+ mark_as_advanced( INSTALL_BIN_DIR )
+ mark_as_advanced( INSTALL_LIB_DIR )
+ mark_as_advanced( INSTALL_INCLUDE_DIR )
+ mark_as_advanced( INSTALL_DATA_DIR )
+ mark_as_advanced( INSTALL_CMAKE_DIR )
+
+ # overrides of install dirs
+
+ foreach( p LIB BIN INCLUDE DATA CMAKE )
+ if( ${PNAME}_INSTALL_${p}_DIR )
+ set( INSTALL_${p}_DIR ${${PNAME}_INSTALL_${p}_DIR} )
+ endif()
+ endforeach()
+
+ # warnings for non-relocatable projects
+
+ foreach( p LIB BIN INCLUDE DATA CMAKE )
+ if( IS_ABSOLUTE ${INSTALL_${p}_DIR} )
+ ecbuild_warn( "Defining INSTALL_${p}_DIR as absolute path '${INSTALL_${p}_DIR}' makes this build non-relocatable, possibly breaking the installation of RPMS and DEB packages" )
+ endif()
+ endforeach()
+
+ # make relative paths absolute ( needed later on ) and cache them ...
+ foreach( p LIB BIN INCLUDE DATA CMAKE )
+
+ set( var INSTALL_${p}_DIR )
+
+ if( NOT IS_ABSOLUTE "${${var}}" )
+ set( ${PNAME}_FULL_INSTALL_${p}_DIR "${CMAKE_INSTALL_PREFIX}/${${var}}"
+ CACHE INTERNAL "${PNAME} ${p} full install path" )
+ else()
+ ecbuild_warn( "Setting an absolute path for ${VAR} in project ${PNAME}, breakes generation of relocatable binary packages (rpm,deb,...)" )
+ set( ${PNAME}_FULL_INSTALL_${p}_DIR "${${var}}"
+ CACHE INTERNAL "${PNAME} ${p} full install path" )
+ endif()
+
+ # ecbuild_debug_var( ${PNAME}_FULL_INSTALL_${p}_DIR )
+
+ endforeach()
+
+ # correctly set CMAKE_INSTALL_RPATH
+
+ if( ENABLE_RPATHS )
+
+ if( ENABLE_RELATIVE_RPATHS )
+
+ file( RELATIVE_PATH relative_rpath ${${PNAME}_FULL_INSTALL_BIN_DIR} ${${PNAME}_FULL_INSTALL_LIB_DIR} )
+ # ecbuild_debug_var( relative_rpath )
+
+ ecbuild_append_to_rpath( ${relative_rpath} )
+
+ else() # make rpaths absolute
+
+ if( IS_ABSOLUTE ${INSTALL_LIB_DIR} )
+ ecbuild_append_to_rpath( "${INSTALL_LIB_DIR}" )
+ else()
+ ecbuild_append_to_rpath( "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIB_DIR}" )
+ endif()
+
+ endif()
+
+ endif()
+
+ # ecbuild_debug_var( CMAKE_INSTALL_RPATH )
+
+ # print project header
+
+ message( STATUS "---------------------------------------------------------" )
+
+ if( ${PNAME}_GIT_SHA1_SHORT )
+ ecbuild_info( "[${PROJECT_NAME}] (${${PNAME}_VERSION_STR}) [${${PNAME}_GIT_SHA1_SHORT}]" )
+ else()
+ ecbuild_info( "[${PROJECT_NAME}] (${${PNAME}_VERSION_STR})" )
+ endif()
+
+endmacro( ecbuild_declare_project )
diff --git a/cmake/ecbuild_define_build_types.cmake b/cmake/ecbuild_define_build_types.cmake
new file mode 100644
index 0000000..cf92d23
--- /dev/null
+++ b/cmake/ecbuild_define_build_types.cmake
@@ -0,0 +1,59 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+############################################################################################
+# define default build type
+
+set( _BUILD_TYPE_MSG "Build type options are: [ None | Debug | Bit | Production | Release | RelWithDebInfo ]" )
+
+if( NOT ECBUILD_DEFAULT_BUILD_TYPE )
+ set( ECBUILD_DEFAULT_BUILD_TYPE "RelWithDebInfo" )
+endif()
+
+if(NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE ${ECBUILD_DEFAULT_BUILD_TYPE} CACHE STRING ${_BUILD_TYPE_MSG} FORCE )
+endif()
+
+# capitalize the build type for easy use with conditionals
+string( TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_CAPS )
+
+# correct capitatlization of the build type
+
+if( CMAKE_BUILD_TYPE_CAPS STREQUAL "NONE" )
+ set(CMAKE_BUILD_TYPE None CACHE STRING ${_BUILD_TYPE_MSG} FORCE )
+endif()
+
+if( CMAKE_BUILD_TYPE_CAPS STREQUAL "DEBUG" )
+ set(CMAKE_BUILD_TYPE Debug CACHE STRING ${_BUILD_TYPE_MSG} FORCE )
+endif()
+
+if( CMAKE_BUILD_TYPE_CAPS STREQUAL "BIT" )
+ set(CMAKE_BUILD_TYPE Bit CACHE STRING ${_BUILD_TYPE_MSG} FORCE )
+endif()
+
+if( CMAKE_BUILD_TYPE_CAPS STREQUAL "PRODUCTION" )
+ set(CMAKE_BUILD_TYPE Production CACHE STRING ${_BUILD_TYPE_MSG} FORCE )
+endif()
+
+if( CMAKE_BUILD_TYPE_CAPS STREQUAL "RELEASE" )
+ set(CMAKE_BUILD_TYPE Release CACHE STRING ${_BUILD_TYPE_MSG} FORCE )
+endif()
+
+if( CMAKE_BUILD_TYPE_CAPS STREQUAL "RELWITHDEBINFO" )
+ set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING ${_BUILD_TYPE_MSG} FORCE )
+endif()
+
+# fail if build type is not one of the defined ones
+if( NOT CMAKE_BUILD_TYPE MATCHES "None" AND
+ NOT CMAKE_BUILD_TYPE MATCHES "Debug" AND
+ NOT CMAKE_BUILD_TYPE MATCHES "Bit" AND
+ NOT CMAKE_BUILD_TYPE MATCHES "Production" AND
+ NOT CMAKE_BUILD_TYPE MATCHES "Release" AND
+ NOT CMAKE_BUILD_TYPE MATCHES "RelWithDebInfo" )
+ ecbuild_critical( "CMAKE_BUILD_TYPE is not recognized. ${_BUILD_TYPE_MSG}" )
+endif()
diff --git a/cmake/ecbuild_define_libs_and_execs_target.cmake b/cmake/ecbuild_define_libs_and_execs_target.cmake
new file mode 100644
index 0000000..812f42c
--- /dev/null
+++ b/cmake/ecbuild_define_libs_and_execs_target.cmake
@@ -0,0 +1,29 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+set( EC_ALL_EXES "" CACHE INTERNAL "" )
+set( EC_ALL_LIBS "" CACHE INTERNAL "" )
+
+############################################################################################
+# define libs and execs targets
+
+macro( ecbuild_define_libs_and_execs_targets )
+
+ add_custom_target( libs )
+
+ if( EC_ALL_LIBS )
+ add_dependencies( libs ${EC_ALL_LIBS} )
+ endif()
+
+ add_custom_target( execs )
+
+ if( EC_ALL_EXECS )
+ add_dependencies( execs ${EC_ALL_EXES} )
+ endif()
+
+endmacro(ecbuild_define_libs_and_execs_targets)
diff --git a/cmake/ecbuild_define_links_target.cmake b/cmake/ecbuild_define_links_target.cmake
new file mode 100644
index 0000000..b5f53fe
--- /dev/null
+++ b/cmake/ecbuild_define_links_target.cmake
@@ -0,0 +1,74 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+############################################################################################
+# macro for adding a link to library on a development system
+
+set( EC_ALL_EXES "" CACHE INTERNAL "" )
+set( EC_ALL_LIBS "" CACHE INTERNAL "" )
+
+macro( ecbuild_link_exe TARGET FILENAME FILEPATH )
+
+ if( DEFINED EC_LINK_DIR )
+ add_custom_target(${TARGET}_link
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${EC_LINK_DIR}
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${EC_LINK_DIR}/bin
+ COMMAND ${CMAKE_COMMAND} -E remove ${EC_LINK_DIR}/bin/${FILENAME}
+ COMMAND ${CMAKE_COMMAND} -E create_symlink ${FILEPATH} ${EC_LINK_DIR}/bin/${FILENAME}
+ DEPENDS ${TARGET}
+ COMMENT "link ${EC_LINK_DIR}/bin/${FILENAME}" )
+ endif()
+
+ set( EC_ALL_EXES ${EC_ALL_EXES} ${TARGET} CACHE INTERNAL "" )
+
+endmacro( ecbuild_link_exe )
+
+###############################################################################
+# macro for adding a link to library on a development system
+
+macro( ecbuild_link_lib TARGET FILENAME FILEPATH )
+
+ if( DEFINED EC_LINK_DIR )
+ add_custom_target(${TARGET}_link
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${EC_LINK_DIR}
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${EC_LINK_DIR}/lib
+ COMMAND ${CMAKE_COMMAND} -E remove ${EC_LINK_DIR}/lib/${FILENAME}
+ COMMAND ${CMAKE_COMMAND} -E create_symlink ${FILEPATH} ${EC_LINK_DIR}/lib/${FILENAME}
+ DEPENDS ${TARGET}
+ COMMENT "link ${EC_LINK_DIR}/lib/${FILENAME}" )
+ endif()
+
+ set( EC_ALL_LIBS ${EC_ALL_LIBS} ${TARGET} CACHE INTERNAL "" )
+
+endmacro( ecbuild_link_lib )
+
+############################################################################################
+# define make links target
+
+macro( ecbuild_define_links_target )
+
+ if( DEFINED EC_LINK_DIR )
+
+ foreach( lib ${EC_ALL_LIBS} )
+ list( APPEND ec_link_libs ${lib}_link )
+ endforeach()
+ foreach( exe ${EC_ALL_EXES} )
+ list( APPEND ec_link_exes ${exe}_link )
+ endforeach()
+
+ add_custom_target( links DEPENDS ${ec_link_libs} ${ec_link_exes} )
+
+ # ecbuild_debug_var( EC_ALL_EXES )
+ # ecbuild_debug_var( ec_link_exes )
+
+ # ecbuild_debug_var( EC_ALL_LIBS )
+ # ecbuild_debug_var( ec_link_libs )
+
+ endif()
+
+endmacro(ecbuild_define_links_target)
diff --git a/cmake/ecbuild_define_options.cmake b/cmake/ecbuild_define_options.cmake
new file mode 100644
index 0000000..af40ae1
--- /dev/null
+++ b/cmake/ecbuild_define_options.cmake
@@ -0,0 +1,52 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+# general options
+
+option( BUILD_SHARED_LIBS "build shared libraries when possible" ON )
+
+option( ENABLE_RPATHS "when installing insert RPATHS into binaries" ON )
+option( ENABLE_RELATIVE_RPATHS "try to use relative RPATHS, including build dir" ON )
+option( ENABLE_WARNINGS "enable compiler warnings" OFF )
+
+option( ENABLE_LARGE_FILE_SUPPORT "build with large file support" ON )
+
+option( ENABLE_PROFILING "build with profiling support" OFF )
+
+mark_as_advanced( ENABLE_LARGE_FILE_SUPPORT )
+
+option( ENABLE_OS_TESTS "Run all OS tests" ON )
+
+mark_as_advanced( ENABLE_OS_TESTS )
+
+option( ENABLE_FORTRAN_C_INTERFACE "Enable Fortran/C Interface" OFF )
+mark_as_advanced( ENABLE_FORTRAN_C_INTERFACE )
+
+option( DEVELOPER_MODE "activates developer mode" OFF )
+option( CHECK_UNUSED_FILES "check for unused project files (slow)" OFF )
+
+mark_as_advanced( DEVELOPER_MODE )
+mark_as_advanced( CHECK_UNUSED_FILES )
+
+include( CMakeDependentOption ) # make options depend on one another
+
+cmake_dependent_option( ENABLE_OS_TYPES_TEST "Run sizeof tests on C types" ON "ENABLE_OS_TESTS" OFF)
+cmake_dependent_option( ENABLE_OS_ENDINESS_TEST "Run OS endiness tests" ON "ENABLE_OS_TESTS" OFF)
+cmake_dependent_option( ENABLE_OS_FUNCTIONS_TEST "Run OS functions tests" ON "ENABLE_OS_TESTS" OFF)
+
+mark_as_advanced( ENABLE_OS_TYPES_TEST ENABLE_OS_ENDINESS_TEST ENABLE_OS_FUNCTIONS_TEST )
+
+option( ECBUILD_USE_INCLUDE_DIRECTORIES "Forces to use global include_directories() instead of target specific. Adverse effect on PkgConfig generation." OFF )
+
+mark_as_advanced( ECBUILD_USE_INCLUDE_DIRECTORIES )
+
+set( CMAKE_NO_SYSTEM_FROM_IMPORTED ON )
+
+# hide some CMake options from CMake UI
+
+mark_as_advanced( CMAKE_OSX_ARCHITECTURES CMAKE_OSX_DEPLOYMENT_TARGET CMAKE_OSX_SYSROOT )
\ No newline at end of file
diff --git a/cmake/ecbuild_define_paths.cmake b/cmake/ecbuild_define_paths.cmake
new file mode 100644
index 0000000..856903d
--- /dev/null
+++ b/cmake/ecbuild_define_paths.cmake
@@ -0,0 +1,41 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+# define project paths
+
+file( MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/bin )
+file( MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
+
+#######################################################################################################
+
+# setup library building rpaths (both in build dir and then when installed)
+
+set( CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE ) # add the automatic parts to RPATH which point to dirs outside build tree
+
+# use RPATHs for the build tree
+set( CMAKE_SKIP_BUILD_RPATH FALSE )
+
+if( ENABLE_RELATIVE_RPATHS )
+ # when building, use the install RPATH immedietly
+ set( CMAKE_BUILD_WITH_INSTALL_RPATH TRUE )
+else()
+ # when building, don't use the install RPATH yet, but later on when installing
+ set( CMAKE_BUILD_WITH_INSTALL_RPATH FALSE )
+endif()
+
+# Always include srcdir and builddir in include path
+# This saves typing ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}
+# in about every subdir
+
+set( CMAKE_INCLUDE_CURRENT_DIR OFF )
+
+# put the include dirs which are in the source or build tree
+# before all other include dirs, so the headers in the sources
+# are prefered over the already installed ones (since cmake 2.4.1)
+
+set(CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE ON)
diff --git a/cmake/ecbuild_define_uninstall.cmake b/cmake/ecbuild_define_uninstall.cmake
new file mode 100644
index 0000000..cc6efa9
--- /dev/null
+++ b/cmake/ecbuild_define_uninstall.cmake
@@ -0,0 +1,7 @@
+### adds uninstall target ###############
+
+configure_file(
+ "${CMAKE_CURRENT_LIST_DIR}/ecbuild_uninstall.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/ecbuild_uninstall.cmake" IMMEDIATE @ONLY)
+
+add_custom_target( uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/ecbuild_uninstall.cmake")
diff --git a/cmake/ecbuild_dont_pack.cmake b/cmake/ecbuild_dont_pack.cmake
new file mode 100644
index 0000000..bc62182
--- /dev/null
+++ b/cmake/ecbuild_dont_pack.cmake
@@ -0,0 +1,82 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_dont_pack
+# =================
+#
+# Specify files and directories to exclude from packaging. ::
+#
+# ecbuild_dont_pack( [ FILES <file1> [ <file2> ... ] ]
+# [ DIRS <dir1> [ <dir2> ... ] ]
+# [ REGEX <regex> ] )
+#
+# Options
+# -------
+#
+# FILES : optional, one of FILES, DIRS, REGEX required
+# list of files to exclude from packaging
+#
+# DIRS : optional, one of FILES, DIRS, REGEX required
+# list of directories to exclude from packaging
+#
+# REGEX : optional, one of FILES, DIRS, REGEX required
+# regular expression to match files / directories to exclude from packaging
+#
+##############################################################################
+
+macro( ecbuild_dont_pack )
+
+ set( options )
+ set( single_value_args REGEX )
+ set( multi_value_args FILES DIRS )
+
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_PAR_UNPARSED_ARGUMENTS)
+ ecbuild_critical("Unknown keywords given to ecbuild_dont_pack(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if( NOT DEFINED _PAR_REGEX AND NOT DEFINED _PAR_FILES AND NOT DEFINED _PAR_DIRS )
+ ecbuild_critical("Call to ecbuild_dont_pack does not speficify any list to avoid packing.")
+ endif()
+
+ set( LOCAL_FILES_NOT_TO_PACK "" )
+
+ # all recursive files are not to pack
+ if( DEFINED _PAR_REGEX )
+ file( GLOB_RECURSE all_files_in_subdirs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${_PAR_REGEX} )
+ list( APPEND LOCAL_FILES_NOT_TO_PACK ${all_files_in_subdirs} )
+ endif()
+
+ # selected dirs not to pack
+ if( DEFINED _PAR_DIRS )
+ foreach( dir ${_PAR_DIRS} )
+ list( APPEND LOCAL_FILES_NOT_TO_PACK ${dir}/ )
+ endforeach()
+ endif()
+
+ # selected files not to pack
+ if( DEFINED _PAR_FILES )
+ list( APPEND LOCAL_FILES_NOT_TO_PACK ${_PAR_FILES} )
+ endif()
+
+ # transform the local files to full absolute paths
+ # and place them in the global list of files not to pack
+ foreach( file ${LOCAL_FILES_NOT_TO_PACK} )
+ list( APPEND ECBUILD_DONT_PACK_FILES ${CMAKE_CURRENT_SOURCE_DIR}/${file} )
+ endforeach()
+
+ # save cache if we added any files not to pack
+ if( LOCAL_FILES_NOT_TO_PACK )
+ set( ECBUILD_DONT_PACK_FILES ${ECBUILD_DONT_PACK_FILES} CACHE INTERNAL "" )
+ endif()
+
+endmacro()
diff --git a/cmake/ecbuild_download_resource.cmake b/cmake/ecbuild_download_resource.cmake
new file mode 100644
index 0000000..3b2f90e
--- /dev/null
+++ b/cmake/ecbuild_download_resource.cmake
@@ -0,0 +1,47 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_download_resource
+# =========================
+#
+# Download a file from a given URL and save to FILE at configure time. ::
+#
+# ecbuild_download_resource( FILE URL )
+#
+# curl or wget is required (curl is preferred if available).
+#
+##############################################################################
+
+function( ecbuild_download_resource _p_OUT _p_URL )
+
+ if( NOT EXISTS ${_p_OUT} )
+
+ find_program( CURL_PROGRAM curl )
+ if( CURL_PROGRAM )
+ execute_process( COMMAND ${CURL_PROGRAM} --silent --show-error --fail --output ${_p_OUT} ${_p_URL}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} RESULT_VARIABLE CMD_RESULT )
+ else()
+ find_program( WGET_PROGRAM wget )
+ if( WGET_PROGRAM )
+ execute_process( COMMAND ${WGET_PROGRAM} -nv -O ${_p_OUT} ${_p_URL}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} RESULT_VARIABLE CMD_RESULT )
+ else()
+ ecbuild_critical("Could not find curl or wget. Error downloading ${_p_URL}")
+ endif()
+ endif()
+
+ if(CMD_RESULT)
+ ecbuild_critical("Error downloading ${_p_URL}")
+ endif()
+
+ endif()
+
+endfunction()
diff --git a/cmake/ecbuild_echo_targets.cmake b/cmake/ecbuild_echo_targets.cmake
new file mode 100644
index 0000000..1406a1f
--- /dev/null
+++ b/cmake/ecbuild_echo_targets.cmake
@@ -0,0 +1,233 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_echo_target_property
+# ============================
+#
+# Output a given property of a given target. ::
+#
+# ecbuild_echo_target_property( <target> <property> )
+#
+##############################################################################
+
+function(ecbuild_echo_target_property tgt prop)
+
+ cmake_policy(PUSH)
+
+ if( POLICY CMP0026 )
+ cmake_policy( SET CMP0026 OLD)
+ endif()
+
+ # v for value, d for defined, s for set
+ get_property(v TARGET ${tgt} PROPERTY ${prop})
+ get_property(d TARGET ${tgt} PROPERTY ${prop} DEFINED)
+ get_property(s TARGET ${tgt} PROPERTY ${prop} SET)
+
+ # only produce output for values that are set
+ if(s)
+ ecbuild_debug("tgt='${tgt}' prop='${prop}'")
+ ecbuild_debug(" value='${v}'")
+ ecbuild_debug(" defined='${d}'")
+ ecbuild_debug(" set='${s}'")
+ ecbuild_debug("")
+ endif()
+
+ cmake_policy(POP)
+
+endfunction()
+
+##############################################################################
+#.rst:
+#
+# ecbuild_echo_target
+# ===================
+#
+# Output all possible target properties of a given target. ::
+#
+# ecbuild_echo_target( <target> )
+#
+##############################################################################
+
+function(ecbuild_echo_target tgt)
+ if(NOT TARGET ${tgt})
+ ecbuild_debug("There is no target named '${tgt}'")
+ return()
+ endif()
+
+ set(props
+DEBUG_OUTPUT_NAME
+DEBUG_POSTFIX
+RELEASE_OUTPUT_NAME
+RELEASE_POSTFIX
+ARCHIVE_OUTPUT_DIRECTORY
+ARCHIVE_OUTPUT_DIRECTORY_DEBUG
+ARCHIVE_OUTPUT_DIRECTORY_RELEASE
+ARCHIVE_OUTPUT_NAME
+ARCHIVE_OUTPUT_NAME_DEBUG
+ARCHIVE_OUTPUT_NAME_RELEASE
+AUTOMOC
+AUTOMOC_MOC_OPTIONS
+BUILD_WITH_INSTALL_RPATH
+BUNDLE
+BUNDLE_EXTENSION
+COMPILE_DEFINITIONS
+COMPILE_DEFINITIONS_DEBUG
+COMPILE_DEFINITIONS_RELEASE
+COMPILE_FLAGS
+DEBUG_POSTFIX
+RELEASE_POSTFIX
+DEFINE_SYMBOL
+ENABLE_EXPORTS
+EXCLUDE_FROM_ALL
+EchoString
+FOLDER
+FRAMEWORK
+Fortran_FORMAT
+Fortran_MODULE_DIRECTORY
+GENERATOR_FILE_NAME
+GNUtoMS
+HAS_CXX
+IMPLICIT_DEPENDS_INCLUDE_TRANSFORM
+IMPORTED
+IMPORTED_CONFIGURATIONS
+IMPORTED_IMPLIB
+IMPORTED_IMPLIB_DEBUG
+IMPORTED_IMPLIB_RELEASE
+IMPORTED_LINK_DEPENDENT_LIBRARIES
+IMPORTED_LINK_DEPENDENT_LIBRARIES_DEBUG
+IMPORTED_LINK_DEPENDENT_LIBRARIES_RELEASE
+IMPORTED_LINK_INTERFACE_LANGUAGES
+IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG
+IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE
+IMPORTED_LINK_INTERFACE_LIBRARIES
+IMPORTED_LINK_INTERFACE_LIBRARIES_DEBUG
+IMPORTED_LINK_INTERFACE_LIBRARIES_RELEASE
+IMPORTED_LINK_INTERFACE_MULTIPLICITY
+IMPORTED_LINK_INTERFACE_MULTIPLICITY_DEBUG
+IMPORTED_LINK_INTERFACE_MULTIPLICITY_RELEASE
+IMPORTED_LOCATION
+IMPORTED_LOCATION_DEBUG
+IMPORTED_LOCATION_RELEASE
+IMPORTED_NO_SONAME
+IMPORTED_NO_SONAME_DEBUG
+IMPORTED_NO_SONAME_RELEASE
+IMPORTED_SONAME
+IMPORTED_SONAME_DEBUG
+IMPORTED_SONAME_RELEASE
+IMPORT_PREFIX
+IMPORT_SUFFIX
+INCLUDE_DIRECTORIES
+INSTALL_NAME_DIR
+INSTALL_RPATH
+INSTALL_RPATH_USE_LINK_PATH
+INTERPROCEDURAL_OPTIMIZATION
+INTERPROCEDURAL_OPTIMIZATION_DEBUG
+INTERPROCEDURAL_OPTIMIZATION_RELEASE
+LABELS
+LIBRARY_OUTPUT_DIRECTORY
+LIBRARY_OUTPUT_DIRECTORY_DEBUG
+LIBRARY_OUTPUT_DIRECTORY_RELEASE
+LIBRARY_OUTPUT_NAME
+LIBRARY_OUTPUT_NAME_DEBUG
+LIBRARY_OUTPUT_NAME_RELEASE
+LINKER_LANGUAGE
+LINK_DEPENDS
+LINK_FLAGS
+LINK_FLAGS_DEBUG
+LINK_FLAGS_RELEASE
+LINK_INTERFACE_LIBRARIES
+LINK_INTERFACE_LIBRARIES_DEBUG
+LINK_INTERFACE_LIBRARIES_RELEASE
+LINK_INTERFACE_MULTIPLICITY
+LINK_INTERFACE_MULTIPLICITY_DEBUG
+LINK_INTERFACE_MULTIPLICITY_RELEASE
+LINK_SEARCH_END_STATIC
+LINK_SEARCH_START_STATIC
+LOCATION
+LOCATION_DEBUG
+LOCATION_RELEASE
+MACOSX_BUNDLE
+MACOSX_BUNDLE_INFO_PLIST
+MACOSX_FRAMEWORK_INFO_PLIST
+MAP_IMPORTED_CONFIG_DEBUG
+MAP_IMPORTED_CONFIG_RELEASE
+OSX_ARCHITECTURES
+OSX_ARCHITECTURES_DEBUG
+OSX_ARCHITECTURES_RELEASE
+OUTPUT_NAME
+OUTPUT_NAME_DEBUG
+OUTPUT_NAME_RELEASE
+POST_INSTALL_SCRIPT
+PREFIX
+PRE_INSTALL_SCRIPT
+PRIVATE_HEADER
+PROJECT_LABEL
+PUBLIC_HEADER
+RESOURCE
+RULE_LAUNCH_COMPILE
+RULE_LAUNCH_CUSTOM
+RULE_LAUNCH_LINK
+RUNTIME_OUTPUT_DIRECTORY
+RUNTIME_OUTPUT_DIRECTORY_DEBUG
+RUNTIME_OUTPUT_DIRECTORY_RELEASE
+RUNTIME_OUTPUT_NAME
+RUNTIME_OUTPUT_NAME_DEBUG
+RUNTIME_OUTPUT_NAME_RELEASE
+SKIP_BUILD_RPATH
+SOURCES
+SOVERSION
+STATIC_LIBRARY_FLAGS
+STATIC_LIBRARY_FLAGS_DEBUG
+STATIC_LIBRARY_FLAGS_RELEASE
+SUFFIX
+TYPE
+VERSION
+VS_DOTNET_REFERENCES
+VS_GLOBAL_WHATEVER
+VS_GLOBAL_KEYWORD
+VS_GLOBAL_PROJECT_TYPES
+VS_KEYWORD
+VS_SCC_AUXPATH
+VS_SCC_LOCALPATH
+VS_SCC_PROJECTNAME
+VS_SCC_PROVIDER
+VS_WINRT_EXTENSIONS
+VS_WINRT_REFERENCES
+WIN32_EXECUTABLE
+XCODE_ATTRIBUTE_WHATEVER
+)
+
+ ecbuild_debug("======================== ${tgt} ========================")
+ foreach(p ${props})
+ ecbuild_echo_target_property("${tgt}" "${p}")
+ endforeach()
+ ecbuild_debug("")
+endfunction()
+
+##############################################################################
+#.rst:
+#
+# ecbuild_echo_targets
+# ====================
+#
+# Output all possible target properties of the specified list-of-targets.
+# This is very useful for debugging. ::
+#
+# ecbuild_echo_targets( <list-of-targets> )
+#
+##############################################################################
+
+function(ecbuild_echo_targets)
+ set(tgts ${ARGV})
+ foreach(t ${tgts})
+ ecbuild_echo_target("${t}")
+ endforeach()
+endfunction()
diff --git a/cmake/ecbuild_enable_fortran.cmake b/cmake/ecbuild_enable_fortran.cmake
new file mode 100644
index 0000000..c1c5503
--- /dev/null
+++ b/cmake/ecbuild_enable_fortran.cmake
@@ -0,0 +1,81 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_enable_fortran
+# ======================
+#
+# Enable the Fortran language. ::
+#
+# ecbuild_enable_fortran( [ MODULE_DIRECTORY <directory> ] [ REQUIRED ] )
+#
+# Options
+# -------
+#
+# MODULE_DIRECTORY : optional, defaults to ``${CMAKE_BINARY_DIR}/module``
+# set the CMAKE_Fortran_MODULE_DIRECTORY
+#
+# REQUIRED : optional
+# fail if no working Fortran compiler was detected
+#
+##############################################################################
+
+macro( ecbuild_enable_fortran )
+
+ set( options REQUIRED )
+ set( single_value_args MODULE_DIRECTORY )
+ set( multi_value_args )
+
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_PAR_UNPARSED_ARGUMENTS)
+ ecbuild_critical("Unknown keywords given to ecbuild_enable_fortran(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if( NOT CMAKE_Fortran_COMPILER_LOADED )
+ enable_language( Fortran )
+ ecbuild_compiler_flags( Fortran )
+ if( ENABLE_WARNINGS AND CMAKE_Fortran_COMPILER_ID MATCHES "Intel" )
+ set( CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -warn all" )
+ ecbuild_debug( "Fortran FLAG [-warn all] added" )
+ endif()
+ endif()
+
+ if( DEFINED _PAR_REQUIRED )
+ if( CMAKE_Fortran_COMPILER_FORCED )
+ set( CMAKE_Fortran_COMPILER_WORKS 1 )
+ endif()
+ if( NOT CMAKE_Fortran_COMPILER OR NOT CMAKE_Fortran_COMPILER_WORKS )
+ ecbuild_critical( "Fortran compiler required by project ${PROJECT_NAME} but does not seem to work" )
+ endif()
+ endif()
+
+ if( CMAKE_Fortran_COMPILER_LOADED )
+ include(CheckFortranFunctionExists)
+ if( CMAKE_C_COMPILER_LOADED AND ENABLE_FORTRAN_C_INTERFACE )
+ include(FortranCInterface)
+ endif()
+ set( EC_HAVE_FORTRAN 1 )
+ endif()
+
+ if( DEFINED _PAR_MODULE_DIRECTORY )
+ set( CMAKE_Fortran_MODULE_DIRECTORY ${_PAR_MODULE_DIRECTORY} )
+ else()
+ set( CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/module
+ CACHE PATH "directory for all fortran modules." )
+ endif()
+
+ file( MAKE_DIRECTORY ${CMAKE_Fortran_MODULE_DIRECTORY} )
+
+ include_directories( ${CMAKE_Fortran_MODULE_DIRECTORY} )
+
+ install( CODE "EXECUTE_PROCESS (COMMAND \"${CMAKE_COMMAND}\" -E copy_directory \"${CMAKE_Fortran_MODULE_DIRECTORY}/\${BUILD_TYPE}\" \"${INSTALL_INCLUDE_DIR}\")" )
+
+endmacro( ecbuild_enable_fortran )
diff --git a/cmake/ecbuild_features.cmake b/cmake/ecbuild_features.cmake
new file mode 100644
index 0000000..6d20038
--- /dev/null
+++ b/cmake/ecbuild_features.cmake
@@ -0,0 +1,98 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+# Internal macros to handle CMake features
+
+include( FeatureSummary )
+
+# Write list of enabled features to CMake variable ${OUT}
+macro( ecbuild_enabled_features OUT )
+ get_property( ${OUT} GLOBAL PROPERTY ENABLED_FEATURES )
+endmacro()
+
+# Write list of disabled features to CMake variable ${OUT}
+macro( ecbuild_disabled_features OUT )
+ get_property( ${OUT} GLOBAL PROPERTY DISABLED_FEATURES )
+endmacro()
+
+# Enable the feature ${_name} (add to enabled features, remove from disabled)
+function( ecbuild_enable_feature _name )
+
+ get_property( _enabled_features GLOBAL PROPERTY ENABLED_FEATURES )
+ get_property( _disabled_features GLOBAL PROPERTY DISABLED_FEATURES )
+
+ if( _disabled_features )
+ list( REMOVE_ITEM _disabled_features ${_name} )
+ endif()
+
+ list( APPEND _enabled_features ${_name} )
+ list( REMOVE_DUPLICATES _enabled_features )
+
+ set_property(GLOBAL PROPERTY ENABLED_FEATURES "${_enabled_features}" )
+ set_property(GLOBAL PROPERTY DISABLED_FEATURES "${_disabled_features}" )
+
+endfunction()
+
+# Disable the feature ${_name} (add to disabled features, remove from enabled)
+function( ecbuild_disable_feature _name )
+
+ get_property( _enabled_features GLOBAL PROPERTY ENABLED_FEATURES )
+ get_property( _disabled_features GLOBAL PROPERTY DISABLED_FEATURES )
+
+ if( _enabled_features )
+ list( REMOVE_ITEM _enabled_features ${_name} )
+ endif()
+
+ list( APPEND _disabled_features ${_name} )
+ list( REMOVE_DUPLICATES _disabled_features )
+
+ set_property(GLOBAL PROPERTY ENABLED_FEATURES "${_enabled_features}" )
+ set_property(GLOBAL PROPERTY DISABLED_FEATURES "${_disabled_features}" )
+
+endfunction()
+
+# en/disable feature ${_name} and set its description and purpose
+function( ecbuild_set_feature _name )
+
+ set(options ) # none
+ set(oneValueArgs ENABLED )
+ set(multiValueArgs ) # none
+
+ cmake_parse_arguments( _PAR "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
+
+ get_property( _feature_desc GLOBAL PROPERTY _CMAKE_${_name}_DESCRIPTION )
+ get_property( _enabled_features GLOBAL PROPERTY ENABLED_FEATURES )
+ get_property( _disabled_features GLOBAL PROPERTY DISABLED_FEATURES )
+
+ if( DEFINED _PAR_ENABLED )
+ if( _PAR_ENABLED )
+ ecbuild_debug( "ecbuild_set_feature(${_name}): enabling feature" )
+ ecbuild_enable_feature( ${_name} )
+ else()
+ ecbuild_debug( "ecbuild_set_feature(${_name}): disabling feature" )
+ ecbuild_disable_feature( ${_name} )
+ endif()
+ endif()
+
+ ecbuild_enabled_features( _enabled_features )
+ list (FIND _enabled_features "${_name}" _index)
+ if (${_index} GREATER -1)
+ set( _feature_found 1 )
+ endif()
+
+ ecbuild_disabled_features( _disabled_features )
+ list (FIND _disabled_features "${_name}" _index)
+ if (${_index} GREATER -1)
+ set( _feature_found 1 )
+ endif()
+
+ if( NOT _feature_found )
+ ecbuild_warn( "Feature ${_name} has not yet been enabled or disabled" )
+ endif()
+
+endfunction()
diff --git a/cmake/ecbuild_find_fortranlibs.cmake b/cmake/ecbuild_find_fortranlibs.cmake
new file mode 100644
index 0000000..279833f
--- /dev/null
+++ b/cmake/ecbuild_find_fortranlibs.cmake
@@ -0,0 +1,163 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_find_fortranlibs
+# ========================
+#
+# Find the Fortran (static) link libraries. ::
+#
+# ecbuild_find_fortranlibs( [ COMPILER gfortran|pgi|xlf|intel ]
+# [ REQUIRED ] )
+#
+# Options
+# -------
+#
+# COMPILER : optional, defaults to gfortran
+# request a given Fortran compiler (``gfortran``, ``pgi``, ``xlf``, ``intel``)
+#
+# REQUIRED : optional
+# fail if Fortran libraries were not found
+#
+##############################################################################
+
+macro( ecbuild_find_fortranlibs )
+
+ # parse parameters
+
+ set( options REQUIRED )
+ set( single_value_args COMPILER )
+ set( multi_value_args )
+
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_PAR_UNPARSED_ARGUMENTS)
+ ecbuild_critical("Unknown keywords given to ecbuild_find_python(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if( NOT FORTRANLIBS_FOUND ) # don't repeat search
+
+ if( _PAR_COMPILER )
+ set( __known_fcomp 0 )
+ endif()
+
+ if( _PAR_COMPILER MATCHES "gfortran" )
+ set( WITH_LIBGFORTRAN 1 )
+ set( __known_fcomp 1 )
+ endif()
+
+ if( _PAR_COMPILER MATCHES "pgi" )
+ set( WITH_PGI_FORTRAN 1 )
+ set( __known_fcomp 1 )
+ endif()
+
+ if( _PAR_COMPILER MATCHES "xlf" )
+ set( WITH_XL_FORTRAN 1 )
+ set( __known_fcomp 1 )
+ endif()
+
+ if( _PAR_COMPILER MATCHES "intel" )
+ set( WITH_INTEL_FORTRAN 1 )
+ set( __known_fcomp 1 )
+ endif()
+
+ if( _PAR_COMPILER AND NOT __known_fcomp )
+ ecbuild_critical( "unknown fortran compiler ${_PAR_COMPILER}" )
+ endif()
+
+ ### set path from environment variables
+
+ foreach( _fortran_lib PGI XLF LIBGFORTRAN INTEL )
+ if( NOT ${_fortran_lib}_PATH AND NOT "$ENV{${_fortran_lib}_PATH}" STREQUAL "" )
+ set( ${_fortran_lib}_PATH "$ENV{${_fortran_lib}_PATH}" )
+ endif()
+ endforeach()
+
+ set( _flibs_found 0 )
+
+ ### default is to search for gfortran
+
+ if( NOT (WITH_PGI_FORTRAN OR WITH_LIBGFORTRAN OR
+ WITH_XL_FORTRAN OR WITH_INTEL_FORTRAN)
+ AND NOT (DEFINED PGI_PATH OR DEFINED LIBGFORTRAN_PATH OR
+ DEFINED XLF_PATH OR DEFINED INTEL_PATH) )
+ ecbuild_warn( "Finding fortran libs for unspecified Fortran compiler: default search [ gfortran ]" )
+ set( WITH_LIBGFORTRAN 1 )
+ endif()
+
+ ### actual search ...
+
+ if( WITH_PGI_FORTRAN OR DEFINED PGI_PATH )
+
+ find_package(PGIFortran)
+
+ if( LIBPGIFORTRAN_FOUND )
+ set( FORTRAN_LIBRARIES ${PGIFORTRAN_LIBRARIES} )
+ set( _flibs_found 1 )
+ set( _flibs_txt "PGI" )
+ endif()
+
+ endif()
+
+ if( WITH_LIBGFORTRAN OR DEFINED LIBGFORTRAN_PATH )
+
+ find_package(LibGFortran)
+
+ if( LIBGFORTRAN_FOUND )
+ set( FORTRAN_LIBRARIES ${GFORTRAN_LIBRARIES} )
+ set( _flibs_found 1 )
+ set( _flibs_txt "gfortran" )
+ endif()
+
+ endif()
+
+ if( WITH_XL_FORTRAN OR DEFINED XLF_PATH )
+
+ find_package(XLFortranLibs)
+
+ if( LIBXLFORTRAN_FOUND )
+ set( FORTRAN_LIBRARIES ${XLFORTRAN_LIBRARIES} )
+ set( _flibs_found 1 )
+ set( _flibs_txt "XLF" )
+ endif()
+
+ endif()
+
+ if( WITH_INTEL_FORTRAN OR DEFINED INTEL_PATH )
+
+ find_package(LibIFort)
+
+ if( LIBIFORT_FOUND )
+ set( FORTRAN_LIBRARIES ${IFORT_LIBRARIES} )
+ set( _flibs_found 1 )
+ set( _flibs_txt "Intel" )
+ endif()
+
+ endif()
+
+ ### set found
+
+ if( _flibs_found )
+ set( FORTRANLIBS_FOUND 1 CACHE INTERNAL "Fortran libraries found" )
+ set( FORTRANLIBS_NAME ${_flibs_txt} CACHE INTERNAL "Fortran library name" )
+ set( FORTRAN_LIBRARIES ${FORTRAN_LIBRARIES} CACHE INTERNAL "Fortran libraries" )
+ ecbuild_info( "Found Fortran libraries: ${_flibs_txt}" )
+ else()
+ set( FORTRANLIBS_FOUND 0 )
+ if( _PAR_REQUIRED )
+ ecbuild_critical( "Failed to find Fortran libraries" )
+ else()
+ ecbuild_warn( "Failed to find Fortran libraries" )
+ endif()
+ endif()
+
+ endif( NOT FORTRANLIBS_FOUND )
+
+endmacro( ecbuild_find_fortranlibs )
diff --git a/cmake/ecbuild_find_lexyacc.cmake b/cmake/ecbuild_find_lexyacc.cmake
new file mode 100644
index 0000000..628488f
--- /dev/null
+++ b/cmake/ecbuild_find_lexyacc.cmake
@@ -0,0 +1,92 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_find_lexyacc
+# ====================
+#
+# Find flex and bison (preferred) or lex and yacc.
+#
+# Input variables
+# ---------------
+#
+# The following CMake variables can set to skip search for bison or yacc:
+#
+# :SKIP_BISON: do not search for flex and bison
+# :SKIP_YACC: do not search for lex and yacc
+#
+# Output variables
+# ----------------
+#
+# The following CMake variables are set if flex and bison were found:
+#
+# :FLEX_FOUND: flex was found
+# :BISON_FOUND: bison was found
+# :FLEX_EXECUTABLE: path to the flex executable
+# :BISON_EXECUTABLE: path to the bison executable
+#
+# The following CMake variables are set if lex and yacc were found:
+#
+# :LEXYACC_FOUND: Found suitable combination of bison, lex, yacc, flex
+# :LEX_FOUND: lex was found
+# :YACC_FOUND: yacc was found
+# :LEX_EXECUTABLE: path to the lex executable
+# :YACC_EXECUTABLE: path to the yacc executable
+#
+##############################################################################
+
+macro( ecbuild_find_lexyacc )
+
+ # find preferably bison or else yacc
+
+ if( NOT SKIP_BISON )
+
+ find_package( BISON 2.3 )
+ find_package( FLEX )
+
+ endif()
+
+ if( NOT BISON_FOUND AND NOT SKIP_YACC )
+
+ find_package( YACC )
+ find_package( LEX )
+
+ endif()
+
+ set( LEXYACC_FOUND 1 )
+
+ if( NOT YACC_FOUND AND NOT BISON_FOUND ) # neither bison nor yacc were found
+ ecbuild_debug( "Neither bison or yacc were found - at least one is required (together with its lexical analyser" )
+ set( LEXYACC_FOUND 0 )
+ endif()
+
+ if( NOT YACC_FOUND ) # check for both bison & flex together
+ if( BISON_FOUND AND NOT FLEX_FOUND )
+ set( LEXYACC_FOUND 0 )
+ ecbuild_debug( "Both bison and flex are required - flex not found" )
+ endif()
+ if( FLEX_FOUND AND NOT BISON_FOUND )
+ set( LEXYACC_FOUND 0 )
+ ecbuild_debug( "Both bison and flex are required - bison not found" )
+ endif()
+ endif()
+
+ if( NOT BISON_FOUND ) # check for both yacc & lex together
+ if( YACC_FOUND AND NOT LEX_FOUND )
+ set( LEXYACC_FOUND 0 )
+ ecbuild_debug( "Both yacc and lex are required - lex not found" )
+ endif()
+ if( LEX_FOUND AND NOT YACC_FOUND )
+ set( LEXYACC_FOUND 0 )
+ ecbuild_debug( "Both yacc and lex are required - yacc not found" )
+ endif()
+ endif()
+
+endmacro( ecbuild_find_lexyacc )
diff --git a/cmake/ecbuild_find_mpi.cmake b/cmake/ecbuild_find_mpi.cmake
new file mode 100644
index 0000000..a0c6cfa
--- /dev/null
+++ b/cmake/ecbuild_find_mpi.cmake
@@ -0,0 +1,328 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_find_mpi
+# ================
+#
+# Find MPI and check if MPI compilers successfully compile C/C++/Fortran. ::
+#
+# ecbuild_find_mpi( [ COMPONENTS <component1> [ <component2> ... ] ]
+# [ REQUIRED ] )
+#
+# Options
+# -------
+#
+# COMPONENTS : optional, defaults to C
+# list of required languages bindings
+#
+# REQUIRED : optional
+# fail if MPI was not found
+#
+# Input variables
+# ---------------
+#
+# ECBUILD_FIND_MPI : optional, defaults to TRUE
+# test C/C++/Fortran MPI compiler wrappers (assume working if FALSE)
+#
+# Output variables
+# ----------------
+#
+# The following CMake variables are set if MPI was found: ::
+#
+# MPI_FOUND
+# MPI_LIBRARY
+# MPI_EXTRA_LIBRARY
+#
+# The following CMake variables are set if C bindings were found: ::
+#
+# MPI_C_FOUND
+# MPI_C_COMPILER
+# MPI_C_COMPILE_FLAGS
+# MPI_C_INCLUDE_PATH
+# MPI_C_LIBRARIES
+# MPI_C_LINK_FLAGS
+#
+# The following CMake variables are set if C++ bindings were found: ::
+#
+# MPI_CXX_FOUND
+# MPI_CXX_COMPILER
+# MPI_CXX_COMPILE_FLAGS
+# MPI_CXX_INCLUDE_PATH
+# MPI_CXX_LIBRARIES
+# MPI_CXX_LINK_FLAGS
+#
+# The following CMake variables are set if Fortran bindings were found: ::
+#
+# MPI_Fortran_FOUND
+# MPI_Fortran_COMPILER
+# MPI_Fortran_COMPILE_FLAGS
+# MPI_Fortran_INCLUDE_PATH
+# MPI_Fortran_LIBRARIES
+# MPI_Fortran_LINK_FLAGS
+#
+##############################################################################
+
+macro( ecbuild_find_mpi )
+
+ # parse parameters
+
+ set( options REQUIRED )
+ set( single_value_args )
+ set( multi_value_args COMPONENTS )
+
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_PAR_UNPARSED_ARGUMENTS)
+ ecbuild_critical("Unknown keywords given to ecbuild_find_mpi(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ # if user defined compilers are MPI compliant, then we use them ...
+ if( NOT DEFINED ECBUILD_FIND_MPI )
+ set( ECBUILD_FIND_MPI TRUE )
+ endif()
+ if( ECBUILD_FIND_MPI )
+
+ # C compiler
+
+ if( CMAKE_C_COMPILER_LOADED AND NOT MPI_C_COMPILER )
+
+ include(CheckCSourceCompiles)
+
+ check_c_source_compiles("
+ #include <mpi.h>
+ int main(int argc, char* argv[])
+ {
+ int rank;
+ MPI_Init(&argc, &argv);
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ MPI_Finalize();
+ return 0;
+ }
+ "
+ C_COMPILER_SUPPORTS_MPI )
+
+ if( C_COMPILER_SUPPORTS_MPI )
+ ecbuild_info( "C compiler supports MPI -- ${CMAKE_C_COMPILER}" )
+ set( MPI_C_COMPILER ${CMAKE_C_COMPILER} )
+ endif()
+
+ endif()
+
+ # CXX compiler
+
+ if( CMAKE_CXX_COMPILER_LOADED AND NOT MPI_CXX_COMPILER )
+
+ include(CheckCXXSourceCompiles)
+
+ check_cxx_source_compiles("
+ #include <mpi.h>
+ #include <iostream>
+ int main(int argc, char* argv[])
+ {
+ MPI_Init(&argc, &argv); int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Finalize();
+ return 0;
+ }
+ "
+ CXX_COMPILER_SUPPORTS_MPI )
+
+ if( CXX_COMPILER_SUPPORTS_MPI )
+ ecbuild_info( "C++ compiler supports MPI -- ${CMAKE_CXX_COMPILER}" )
+ set( MPI_CXX_COMPILER ${CMAKE_CXX_COMPILER} )
+ endif()
+
+ endif()
+
+ # Fortran compiler
+
+ if( CMAKE_Fortran_COMPILER_LOADED AND NOT MPI_Fortran_COMPILER )
+
+ include(CheckFortranSourceCompiles)
+
+ check_fortran_source_compiles("
+ program main
+ use MPI
+ integer ierr
+ call MPI_INIT( ierr )
+ call MPI_FINALIZE( ierr )
+ end
+ "
+ Fortran_COMPILER_SUPPORTS_MPI )
+
+ if( Fortran_COMPILER_SUPPORTS_MPI )
+ ecbuild_info( "Fortran compiler supports MPI (F90) -- ${CMAKE_Fortran_COMPILER}" )
+ set( MPI_Fortran_COMPILER ${CMAKE_Fortran_COMPILER} )
+ set( MPI_Fortran_FOUND TRUE )
+ endif()
+
+ endif()
+
+ if( NOT _PAR_REQUIRED )
+ find_package( MPI QUIET )
+ else()
+ find_package( MPI QUIET REQUIRED )
+ endif()
+
+ if( C_COMPILER_SUPPORTS_MPI )
+ set( MPI_C_FOUND TRUE )
+ endif()
+ if( CXX_COMPILER_SUPPORTS_MPI )
+ set( MPI_CXX_FOUND TRUE )
+ endif()
+ if( Fortran_COMPILER_SUPPORTS_MPI )
+ set( MPI_Fortran_FOUND TRUE )
+ endif()
+
+ else()
+
+ # find_package with Cray compiler did not send MPI_<lang>_FOUND
+ if( CMAKE_C_COMPILER_LOADED )
+ set( C_COMPILER_SUPPORTS_MPI TRUE )
+ set( MPI_C_FOUND TRUE )
+ endif()
+ if( CMAKE_CXX_COMPILER_LOADED )
+ set( CXX_COMPILER_SUPPORTS_MPI TRUE )
+ set( MPI_CXX_FOUND TRUE )
+ endif()
+ if( CMAKE_Fortran_COMPILER_LOADED )
+ set( Fortran_COMPILER_SUPPORTS_MPI TRUE )
+ set( MPI_Fortran_FOUND TRUE )
+ endif()
+
+ endif( ECBUILD_FIND_MPI )
+
+ # hide these variables from UI
+
+ mark_as_advanced( MPI_LIBRARY MPI_EXTRA_LIBRARY )
+
+ if( NOT _PAR_COMPONENTS )
+ set( _PAR_COMPONENTS C )
+ endif()
+
+ set( MPI_FOUND TRUE )
+ foreach( _lang ${_PAR_COMPONENTS} )
+ if( NOT MPI_${_lang}_FOUND )
+ set( MPI_FOUND FALSE )
+ endif()
+ endforeach()
+
+endmacro( ecbuild_find_mpi )
+
+##############################################################################
+#.rst:
+#
+# ecbuild_enable_mpi
+# ==================
+#
+# Find MPI, add include directories and set compiler flags. ::
+#
+# ecbuild_enable_mpi( [ COMPONENTS <component1> [ <component2> ... ] ]
+# [ REQUIRED ] )
+#
+# For each MPI language binding found, set the corresponding compiler flags
+# and add the include directories.
+#
+# See ``ecbuild_find_mpi`` for input and output variables.
+#
+# Options
+# -------
+#
+# COMPONENTS : optional, defaults to C
+# list of required languages bindings
+#
+# REQUIRED : optional
+# fail if MPI was not found
+#
+##############################################################################
+
+macro( ecbuild_enable_mpi )
+
+ set( options REQUIRED )
+ set( single_value_args )
+ set( multi_value_args COMPONENTS )
+
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_PAR_UNPARSED_ARGUMENTS)
+ ecbuild_critical("Unknown keywords given to ecbuild_find_mpi(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if( NOT _PAR_COMPONENTS )
+ set (_PAR_COMPONENTS C )
+ endif()
+
+ if( NOT _PAR_REQUIRED )
+ ecbuild_find_mpi( COMPONENTS ${_PAR_COMPONENTS} )
+ else()
+ ecbuild_find_mpi( COMPONENTS ${_PAR_COMPONENTS} REQUIRED )
+ endif()
+
+ if( MPI_C_FOUND AND NOT C_COMPILER_SUPPORTS_MPI )
+ ecbuild_add_c_flags("${MPI_C_COMPILE_FLAGS}")
+ include_directories(${MPI_C_INCLUDE_PATH})
+ endif()
+
+ if( MPI_CXX_FOUND AND NOT CXX_COMPILER_SUPPORTS_MPI )
+ ecbuild_add_cxx_flags("${MPI_CXX_COMPILE_FLAGS}")
+ include_directories(${MPI_CXX_INCLUDE_PATH})
+ endif()
+
+ if( MPI_Fortran_FOUND AND NOT Fortran_COMPILER_SUPPORTS_MPI )
+ include( ecbuild_check_fortran_source_return )
+ ecbuild_add_fortran_flags("${MPI_Fortran_COMPILE_FLAGS}")
+ include_directories(${MPI_Fortran_INCLUDE_PATH})
+ endif()
+
+endmacro( ecbuild_enable_mpi )
+
+##############################################################################
+#.rst:
+#
+# ecbuild_include_mpi
+# ===================
+#
+# Add MPI include directories and set compiler flags, assuming MPI was found.
+#
+# For each MPI language binding found, set corresponding compiler flags and
+# add include directories. ``ecbuild_find_mpi`` must have been called before.
+#
+##############################################################################
+
+macro( ecbuild_include_mpi )
+
+ set( options )
+ set( single_value_args )
+ set( multi_value_args )
+
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_PAR_UNPARSED_ARGUMENTS)
+ ecbuild_critical("Unknown keywords given to ecbuild_find_mpi(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if( MPI_C_FOUND AND NOT C_COMPILER_SUPPORTS_MPI )
+ include( ecbuild_check_c_source_return )
+ ecbuild_add_c_flags("${MPI_C_COMPILE_FLAGS}")
+ include_directories(${MPI_C_INCLUDE_PATH})
+ endif()
+
+ if( MPI_CXX_FOUND AND NOT CXX_COMPILER_SUPPORTS_MPI )
+ include( ecbuild_check_cxx_source_return )
+ ecbuild_add_cxx_flags("${MPI_CXX_COMPILE_FLAGS}")
+ include_directories(${MPI_CXX_INCLUDE_PATH})
+ endif()
+
+ if( MPI_Fortran_FOUND AND NOT Fortran_COMPILER_SUPPORTS_MPI )
+ include( ecbuild_check_fortran_source_return )
+ ecbuild_add_fortran_flags("${MPI_Fortran_COMPILE_FLAGS}")
+ include_directories(${MPI_Fortran_INCLUDE_PATH})
+ endif()
+
+endmacro( ecbuild_include_mpi )
diff --git a/cmake/ecbuild_find_omp.cmake b/cmake/ecbuild_find_omp.cmake
new file mode 100644
index 0000000..47c05c2
--- /dev/null
+++ b/cmake/ecbuild_find_omp.cmake
@@ -0,0 +1,259 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+# macro for looking for openmp flags
+
+macro( lookup_omp_flags )
+ set(_OMP_FLAG_GNU "-fopenmp")
+ set(_OMPSTUBS_FLAG_GNU "-fno-openmp")
+
+ set(_OMP_FLAG_Cray "-homp")
+ set(_OMPSTUBS_FLAG_Cray "-hnoomp")
+
+ set(_OMP_FLAG_XL "-qsmp=omp")
+ set(_OMPSTUBS_FLAG_XL "-qsmp=noomp")
+
+ set(_OMP_FLAG_Intel "-openmp")
+ set(_OMPSTUBS_FLAG_Intel "-openmp-stubs")
+
+ # sample C openmp source code to test
+ set(_OMP_C_TEST_SOURCE
+ "
+ #include <omp.h>
+ int main() {
+ #ifdef _OPENMP
+ #pragma omp parallel
+ {
+ int id = omp_get_thread_num();
+ }
+ return 0;
+ #else
+ breaks_on_purpose
+ #endif
+ }
+ ")
+ set( _OMP_CXX_TEST_SOURCE ${_OMP_C_TEST_SOURCE} )
+
+
+ # sample C openmp source code to test
+ set(_OMPSTUBS_C_TEST_SOURCE
+ "
+ // Include must be found
+ #include <omp.h>
+ int main() {
+ #ifdef _OPENMP
+ breaks_on_purpose
+ #else
+ #pragma omp parallel
+ {
+ // This pragma should have passed compilation
+ int id = 0;
+ }
+ return 0;
+ #endif
+ }
+ ")
+ set( _OMPSTUBS_CXX_TEST_SOURCE ${_OMPSTUBS_C_TEST_SOURCE} )
+
+
+ # sample Fortran openmp source code to test
+ set(_OMP_Fortran_TEST_SOURCE
+ "
+ program main
+ use omp_lib
+ end program
+ ")
+ set( _OMPSTUBS_Fortran_TEST_SOURCE ${_OMP_Fortran_TEST_SOURCE} )
+
+endmacro()
+
+##############################################################################
+#.rst:
+#
+# ecbuild_find_omp
+# ================
+#
+# Find OpenMP. ::
+#
+# ecbuild_find_omp( [ COMPONENTS <component1> [ <component2> ... ] ]
+# [ REQUIRED ]
+# [ STUBS ] )
+#
+# Options
+# -------
+#
+# COMPONENTS : optional, defaults to C
+# list of required languages bindings
+#
+# REQUIRED : optional
+# fail if OpenMP was not found
+#
+# STUBS : optional
+# search for OpenMP stubs
+#
+# Output variables
+# ----------------
+#
+# The following CMake variables are set if OpenMP was found:
+#
+# :OMP_FOUND: OpenMP was found
+#
+# For each language listed in COMPONENTS, the following variables are set:
+#
+# :OMP_<LANG>_FOUND: OpenMP bindings for LANG were found
+# :OMP_<LANG>_FLAGS: OpenMP compiler flags for LANG
+#
+# If the STUBS option was given, all variables are also set with the OMPSTUBS
+# instead of the OMP prefix.
+#
+##############################################################################
+
+macro( ecbuild_find_omp )
+
+ set( options REQUIRED STUBS )
+ set( single_value_args )
+ set( multi_value_args COMPONENTS )
+
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if( NOT _PAR_COMPONENTS )
+ ecbuild_critical( "No COMPONENTS were specified, looking for OMP.\n Please find with COMPONENTS C CXX Fortran " )
+ endif()
+
+ set( _STUBS "" )
+ if( _PAR_STUBS )
+ set( _STUBS "STUBS" )
+ endif()
+
+ lookup_omp_flags()
+
+ set( OMP${_STUBS}_FOUND TRUE )
+
+ foreach( _LANG ${_PAR_COMPONENTS} )
+
+ if( NOT OMP${_STUBS}_${_LANG}_FLAGS )
+
+ if( DEFINED _OMP${_STUBS}_FLAG_${CMAKE_${_LANG}_COMPILER_ID} )
+ set( _OMP${_STUBS}_${_LANG}_FLAG "${_OMP${_STUBS}_FLAG_${CMAKE_${_LANG}_COMPILER_ID}}" )
+ endif()
+ if( CMAKE_${_LANG}_COMPILER_LOADED AND _OMP${_STUBS}_${_LANG}_FLAG )
+ set(SAVE_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
+ set(CMAKE_REQUIRED_FLAGS "${_OMP${_STUBS}_${_LANG}_FLAG}")
+ include(Check${_LANG}SourceCompiles)
+ set( _SOURCE ${_OMP${_STUBS}_${_LANG}_TEST_SOURCE} )
+ set( _FLAG ${_LANG}_COMPILER_SUPPORTS_OMP${_STUBS})
+ if( _LANG STREQUAL "C" )
+ check_c_source_compiles("${_SOURCE}" ${_FLAG} )
+ endif()
+ if( _LANG STREQUAL "CXX" )
+ check_cxx_source_compiles("${_SOURCE}" ${_FLAG} )
+ endif()
+ if( _LANG STREQUAL "Fortran" )
+ check_fortran_source_compiles("${_SOURCE}" ${_FLAG} )
+ endif()
+ set(CMAKE_REQUIRED_FLAGS "${SAVE_CMAKE_REQUIRED_FLAGS}")
+ endif()
+
+ if( ${_LANG}_COMPILER_SUPPORTS_OMP${_STUBS} )
+ set( OMP${_STUBS}_${_LANG}_FLAGS ${_OMP${_STUBS}_${_LANG}_FLAG} )
+ endif()
+
+ else()
+ set( ${_LANG}_COMPILER_SUPPORTS_OMP${_STUBS} TRUE )
+ endif()
+
+
+ set( OMP${_STUBS}_${_LANG}_FIND_QUIETLY TRUE )
+ find_package_handle_standard_args( OMP${_STUBS}_${_LANG} REQUIRED_VARS ${_LANG}_COMPILER_SUPPORTS_OMP${_STUBS} )
+
+ if( OMP${_STUBS}_FORTRAN_FOUND )
+ set( OMP${_STUBS}_Fortran_FOUND TRUE )
+ endif()
+
+ if( NOT OMP${_STUBS}_${_LANG}_FOUND )
+ set( OMP${_STUBS}_FOUND FALSE )
+ endif()
+
+ if( _PAR_STUBS )
+ set( OMP_${_LANG}_FOUND ${OMPSTUBS_${_LANG}_FOUND} )
+ set( OMP_${_LANG}_FLAGS ${OMPSTUBS_${_LANG}_FLAGS} )
+ endif()
+
+ endforeach()
+
+ if( _PAR_STUBS )
+ set( OMP_FOUND ${OMPSTUBS_FOUND} )
+ endif()
+
+endmacro( ecbuild_find_omp )
+
+##############################################################################
+#.rst:
+#
+# ecbuild_enable_omp
+# ==================
+#
+# Find OpenMP for C, C++ and Fortran and set the compiler flags for each
+# language for which OpenMP support was detected.
+#
+##############################################################################
+
+macro( ecbuild_enable_omp )
+
+ ecbuild_debug("ecbuild_enable_omp: Trying to enable OpenMP")
+ ecbuild_find_omp( COMPONENTS C CXX Fortran )
+
+ ecbuild_debug_var("OMP_C_FOUND")
+ if( OMP_C_FOUND )
+ ecbuild_debug("Adding ${OMP_C_FLAGS} to CMAKE_C_FLAGS")
+ set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OMP_C_FLAGS}" )
+ endif()
+
+ ecbuild_debug_var("OMP_CXX_FOUND")
+ if( OMP_CXX_FOUND )
+ ecbuild_debug("Adding ${OMP_CXX_FLAGS} to CMAKE_CXX_FLAGS")
+ set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OMP_CXX_FLAGS}" )
+ endif()
+
+ ecbuild_debug_var("OMP_Fortran_FOUND")
+ if( OMP_Fortran_FOUND )
+ ecbuild_debug("Adding ${OMP_Fortran_FLAGS} to CMAKE_Fortran_FLAGS")
+ set( CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${OMP_Fortran_FLAGS}" )
+ endif()
+
+endmacro( ecbuild_enable_omp )
+
+##############################################################################
+#.rst:
+#
+# ecbuild_enable_ompstubs
+# =======================
+#
+# Find OpenMP stubs for C, C++ and Fortran and set the compiler flags for each
+# language for which OpenMP stubs were detected.
+#
+##############################################################################
+
+macro( ecbuild_enable_ompstubs )
+
+ ecbuild_find_omp( COMPONENTS C CXX Fortran STUBS )
+
+ if( OMPSTUBS_C_FOUND )
+ set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OMPSTUBS_C_FLAGS}" )
+ endif()
+
+ if( OMPSTUBS_CXX_FOUND )
+ set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OMPSTUBS_CXX_FLAGS}" )
+ endif()
+
+ if( OMPSTUBS_Fortran_FOUND )
+ set( CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${OMPSTUBS_Fortran_FLAGS}" )
+ endif()
+
+endmacro( ecbuild_enable_ompstubs )
diff --git a/cmake/ecbuild_find_package.cmake b/cmake/ecbuild_find_package.cmake
new file mode 100644
index 0000000..f7f1a9c
--- /dev/null
+++ b/cmake/ecbuild_find_package.cmake
@@ -0,0 +1,325 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_find_package
+# ====================
+#
+# Find a package and import its configuration. ::
+#
+# ecbuild_find_package( NAME <name>
+# [ VERSION <version> [ EXACT ] ]
+# [ COMPONENTS <component1> [ <component2> ... ] ]
+# [ REQUIRED ]
+# [ QUIET ] )
+#
+# Options
+# -------
+#
+# NAME : required
+# package name (used as ``Find<name>.cmake`` and ``<name>-config.cmake``)
+#
+# VERSION : optional
+# minimum required package version
+#
+# COMPONENTS : optional
+# list of package components to find (behaviour depends on the package)
+#
+# EXACT : optional, requires VERSION
+# require the exact version rather than a minimum version
+#
+# REQUIRED : optional
+# fail if package cannot be found
+#
+# QUIET : optional
+# do not output package information if found
+#
+# Input variables
+# ---------------
+#
+# The following CMake variables influence the behaviour if set (``<name>`` is
+# the package name as given, ``<NAME>`` is the capitalised version):
+#
+# :DEVELOPER_MODE: if enabled, discover projects parallel in the build tree
+# :<name>_PATH: install prefix path of the package
+# :<NAME>_PATH: install prefix path of the package
+# :<name>_DIR: directory containing the ``<name>-config.cmake`` file
+# (usually ``<install-prefix>/share/<name>/cmake``)
+#
+# The environment variables ``<name>_PATH``, ``<NAME>_PATH``, ``<name>_DIR``
+# are taken into account only if the corresponding CMake variables are unset.
+#
+# Usage
+# -----
+#
+# The search proceeds as follows:
+#
+# 1. If any paths have been specified by the user via CMake or environment
+# variables as given above or a parallel build tree has been discovered in
+# DEVELOPER_MODE:
+#
+# * search for ``<name>-config.cmake`` in those paths only
+# * search using ``Find<name>.cmake`` (which should respect those paths)
+# * fail if the package was not found in any of those paths
+#
+# 2. Search for ``<name>-config.cmake`` in the ``CMAKE_PREFIX_PATH`` and if
+# DEVELOPER_MODE is enabled also in the user package registry.
+#
+# 3. Search system paths for ``<name>-config.cmake``.
+#
+# 4. Search system paths using ``Find<name>.cmake``.
+#
+# 5. If the package was found, and a minimum version was requested, check if
+# the version is acceptable and if not, unset ``<NAME>_FOUND``.
+#
+# 6. Fail if the package was not found and is REQUIRED.
+#
+##############################################################################
+
+macro( ecbuild_find_package )
+
+ set( options REQUIRED QUIET EXACT )
+ set( single_value_args NAME VERSION )
+ set( multi_value_args COMPONENTS )
+
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_PAR_UNPARSED_ARGUMENTS)
+ ecbuild_critical("Unknown keywords given to ecbuild_find_package(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if( NOT _PAR_NAME )
+ ecbuild_critical("The call to ecbuild_find_package() doesn't specify the NAME.")
+ endif()
+
+ if( _PAR_EXACT AND NOT _PAR_VERSION )
+ ecbuild_critical("Call to ecbuild_find_package() requests EXACT but doesn't specify VERSION.")
+ endif()
+
+ # ecbuild_debug_var( _PAR_NAME )
+
+ string( TOUPPER ${_PAR_NAME} pkgUPPER )
+ string( TOLOWER ${_PAR_NAME} pkgLOWER )
+
+ set( _${pkgUPPER}_version "" )
+ if( _PAR_VERSION )
+ set( _${pkgUPPER}_version ${_PAR_VERSION} )
+ if( _PAR_EXACT )
+ set( _${pkgUPPER}_version ${_PAR_VERSION} EXACT )
+ endif()
+ endif()
+
+ # check developer mode (search in cmake cache )
+
+ if( NOT ${DEVELOPER_MODE} )
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): Not in DEVELOPER_MODE - do not search package registry or recent GUI build paths")
+ set( NO_DEV_BUILD_DIRS NO_CMAKE_PACKAGE_REGISTRY NO_CMAKE_BUILDS_PATH )
+ endif()
+
+ # in DEVELOPER_MODE we give priority to projects parallel in the build tree
+ # so lets prepend a parallel build tree to the search path if we find it
+
+ if( DEVELOPER_MODE )
+ get_filename_component( _proj_bdir "${CMAKE_BINARY_DIR}/../${pkgLOWER}" ABSOLUTE )
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): in DEVELOPER_MODE - searching for ${pkgLOWER}-config.cmake in ${_proj_bdir}")
+ if( EXISTS ${_proj_bdir}/${pkgLOWER}-config.cmake )
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): in DEVELOPER_MODE - found parallel build tree in ${_proj_bdir}")
+ if( ${pkgUPPER}_PATH )
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): in DEVELOPER_MODE - ${pkgUPPER}_PATH already set to ${${pkgUPPER}_PATH}, not modifying")
+ else()
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): in DEVELOPER_MODE - setting ${pkgUPPER}_PATH to ${_proj_bdir}")
+ set( ${pkgUPPER}_PATH "${_proj_bdir}" )
+ endif()
+ endif()
+ endif()
+
+ # Read environment variables but ONLY if the corresponding CMake variables are unset
+
+ if( NOT DEFINED ${pkgUPPER}_PATH AND NOT "$ENV{${pkgUPPER}_PATH}" STREQUAL "" )
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): setting ${pkgUPPER}_PATH=${${pkgUPPER}_PATH} from environment")
+ set( ${pkgUPPER}_PATH "$ENV{${pkgUPPER}_PATH}" )
+ endif()
+
+ if( NOT DEFINED ${_PAR_NAME}_PATH AND NOT "$ENV{${_PAR_NAME}_PATH}" STREQUAL "" )
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): setting ${_PAR_NAME}_PATH=${${_PAR_NAME}_PATH} from environment")
+ set( ${_PAR_NAME}_PATH "$ENV{${_PAR_NAME}_PATH}" )
+ endif()
+
+ if( NOT DEFINED ${_PAR_NAME}_DIR AND NOT "$ENV{${_PAR_NAME}_DIR}" STREQUAL "" )
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): setting ${_PAR_NAME}_DIR=${${_PAR_NAME}_DIR} from environment")
+ set( ${_PAR_NAME}_DIR "$ENV{${_PAR_NAME}_DIR}" )
+ endif()
+
+ # Find packages quietly unless in DEVELOPER_MODE or LOG_LEVEL is DEBUG
+
+ if( NOT DEVELOPER_MODE AND ( ECBUILD_LOG_LEVEL GREATER ${ECBUILD_DEBUG} ) )
+ set( _find_quiet QUIET )
+ endif()
+
+ # search user defined paths first
+
+ if( ${_PAR_NAME}_PATH OR ${pkgUPPER}_PATH OR ${_PAR_NAME}_DIR )
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): ${_PAR_NAME}_PATH=${${_PAR_NAME}_PATH}, ${pkgUPPER}_PATH=${${pkgUPPER}_PATH}, ${_PAR_NAME}_DIR=${${_PAR_NAME}_DIR}")
+
+ # 1) search using CONFIG mode -- try to locate a configuration file provided by the package (package-config.cmake)
+
+ if( NOT ${_PAR_NAME}_FOUND )
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): 1) search using CONFIG mode -- try to locate ${_PAR_NAME}-config.cmake")
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): using hints ${pkgUPPER}_PATH=${${pkgUPPER}_PATH}, ${_PAR_NAME}_PATH=${${_PAR_NAME}_PATH}, ${_PAR_NAME}_DIR=${${_PAR_NAME}_DIR}")
+ find_package( ${_PAR_NAME} ${_${pkgUPPER}_version} NO_MODULE ${_find_quiet}
+ COMPONENTS ${_PAR_COMPONENTS}
+ HINTS ${${pkgUPPER}_PATH} ${${_PAR_NAME}_PATH} ${${_PAR_NAME}_DIR}
+ NO_DEFAULT_PATH )
+ endif()
+
+ # 2) search using a file Find<package>.cmake if it exists ( macro should itself take *_PATH into account )
+
+ if( NOT ${_PAR_NAME}_FOUND )
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): 2) search using a file Find${_PAR_NAME}.cmake if it exists")
+ find_package( ${_PAR_NAME} ${_${pkgUPPER}_version} MODULE ${_find_quiet}
+ COMPONENTS ${_PAR_COMPONENTS} )
+ endif()
+
+ # is <package>_PATH was given and we don't find anything then we FAIL
+
+ if( NOT ${_PAR_NAME}_FOUND )
+ if( ${_PAR_NAME}_PATH )
+ ecbuild_critical( "${_PAR_NAME}_PATH was provided by user but package ${_PAR_NAME} wasn't found" )
+ endif()
+ if( ${pkgUPPER}_PATH )
+ ecbuild_critical( "${pkgUPPER}_PATH was provided by user but package ${_PAR_NAME} wasn't found" )
+ endif()
+ endif()
+
+ endif()
+
+ # 3) search developer cache and recently configured packages in the CMake GUI if in DEVELOPER_MODE
+ # otherwise only search CMAKE_PREFIX_PATH and <package>_PATH
+
+ if( NOT ${_PAR_NAME}_FOUND )
+ if (NO_DEV_BUILD_DIRS)
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): 3) search CMAKE_PREFIX_PATH and \$${pkgUPPER}_PATH")
+ else()
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): 3) search CMAKE_PREFIX_PATH and \$${pkgUPPER}_PATH and package registry")
+ endif()
+
+ find_package( ${_PAR_NAME} ${_${pkgUPPER}_version} ${_find_quiet} NO_MODULE
+ COMPONENTS ${_PAR_COMPONENTS}
+ HINTS ENV ${pkgUPPER}_PATH
+ ${NO_DEV_BUILD_DIRS}
+ NO_CMAKE_ENVIRONMENT_PATH
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH
+ NO_CMAKE_SYSTEM_PACKAGE_REGISTRY )
+
+ endif()
+
+ # 4) search system paths, for <package>-config.cmake
+
+ if( NOT ${_PAR_NAME}_FOUND )
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): 5) search system paths, for ${_PAR_NAME}-config.cmake")
+
+ find_package( ${_PAR_NAME} ${_${pkgUPPER}_version} ${_find_quiet} NO_MODULE
+ COMPONENTS ${_PAR_COMPONENTS}
+ ${NO_DEV_BUILD_DIRS} )
+
+ endif()
+
+ # 5) search system paths, using Find<package>.cmake if it exists
+
+ if( NOT ${_PAR_NAME}_FOUND )
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): 6) search system paths, using Find${_PAR_NAME}.cmake if it exists")
+
+ find_package( ${_PAR_NAME} ${_${pkgUPPER}_version} ${_find_quiet} MODULE
+ COMPONENTS ${_PAR_COMPONENTS} )
+
+ endif()
+
+ # check version found is acceptable
+
+ if( ${_PAR_NAME}_FOUND )
+ set( _version_acceptable 1 )
+ if( _PAR_VERSION )
+ if( ${_PAR_NAME}_VERSION )
+ if( _PAR_EXACT )
+ if( NOT ${_PAR_NAME}_VERSION VERSION_EQUAL _PAR_VERSION )
+ ecbuild_warn( "${PROJECT_NAME} requires (exactly) ${_PAR_NAME} = ${_PAR_VERSION} -- found ${${_PAR_NAME}_VERSION}" )
+ set( _version_acceptable 0 )
+ endif()
+ else()
+ if( _PAR_VERSION VERSION_LESS ${_PAR_NAME}_VERSION OR _PAR_VERSION VERSION_EQUAL ${_PAR_NAME}_VERSION )
+ set( _version_acceptable 1 )
+ else()
+ if( NOT _PAR_QUIET )
+ ecbuild_warn( "${PROJECT_NAME} requires ${_PAR_NAME} >= ${_PAR_VERSION} -- found ${${_PAR_NAME}_VERSION}" )
+ endif()
+ set( _version_acceptable 0 )
+ endif()
+ endif()
+ else()
+ if( NOT _PAR_QUIET )
+ ecbuild_warn( "${PROJECT_NAME} found ${_PAR_NAME} but no version information, so cannot check if satisfies ${_PAR_VERSION}" )
+ endif()
+ set( _version_acceptable 0 )
+ endif()
+ endif()
+ endif()
+
+ if( ${_PAR_NAME}_FOUND )
+
+ if( _version_acceptable )
+ set( ${pkgUPPER}_FOUND ${${_PAR_NAME}_FOUND} )
+ else()
+ if( NOT _PAR_QUIET )
+ ecbuild_warn( "${PROJECT_NAME} found ${_PAR_NAME} but with unsuitable version" )
+ endif()
+ set( ${pkgUPPER}_FOUND 0 )
+ set( ${_PAR_NAME}_FOUND 0 )
+ endif()
+
+ endif()
+
+ ### final messages
+
+ set( _failed_message
+ "\n"
+ " ${PROJECT_NAME} FAILED to find package ${_PAR_NAME}\n"
+ "\n"
+ " Provide location with \"-D${pkgUPPER}_PATH=/...\" or \"-D${_PAR_NAME}_DIR=/...\" \n"
+ " You may also export environment variables ${pkgUPPER}_PATH or ${_PAR_NAME}_DIR\n"
+ "\n"
+ " Values (note CAPITALISATION):\n"
+ " ${pkgUPPER}_PATH should contain the path to the install prefix (as in <install>/bin <install>/lib <install>/include)\n"
+ " ${_PAR_NAME}_DIR should be a directory containing a <package>-config.cmake file (usually <install>/share/<package>/cmake)\n"
+ "\n"
+ )
+
+ if( ${_PAR_NAME}_FOUND OR ${pkgUPPER}_FOUND )
+ if( NOT _PAR_QUIET )
+ ecbuild_info( "[${_PAR_NAME}] (${${_PAR_NAME}_VERSION})" )
+ foreach( var in ITEMS INCLUDE_DIR INCLUDE_DIRS DEFINITIONS LIBRARY LIBRARIES )
+ if( ${pkgUPPER}_${var} )
+ ecbuild_info( " ${pkgUPPER}_${var} : [${${pkgUPPER}_${var}}]" )
+ elseif( ${_PAR_NAME}_${var} )
+ ecbuild_info( " ${_PAR_NAME}_${var} : [${${_PAR_NAME}_${var}}]" )
+ endif()
+ endforeach()
+ endif()
+ else()
+ if( _PAR_REQUIRED )
+ ecbuild_critical( ${_failed_message} " !! ${PROJECT_NAME} requires package ${_PAR_NAME} !!" )
+ else()
+ if( NOT _PAR_QUIET )
+ ecbuild_warn( ${_failed_message} )
+ endif()
+ endif()
+ endif()
+
+endmacro()
diff --git a/cmake/ecbuild_find_perl.cmake b/cmake/ecbuild_find_perl.cmake
new file mode 100644
index 0000000..97b22f8
--- /dev/null
+++ b/cmake/ecbuild_find_perl.cmake
@@ -0,0 +1,73 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_find_perl
+# =================
+#
+# Find perl executable and its version. ::
+#
+# ecbuild_find_perl( [ REQUIRED ] )
+#
+# Options
+# -------
+#
+# REQUIRED : optional
+# fail if perl was not found
+#
+# Output variables
+# ----------------
+#
+# The following CMake variables are set if perl was found:
+#
+# :PERL_FOUND: perl was found
+# :PERL_EXECUTABLE: path to the perl executable
+# :PERL_VERSION: perl version
+# :PERL_VERSION_STRING: perl version (same as ``PERL_VERSION``)
+#
+##############################################################################
+
+macro( ecbuild_find_perl )
+
+ # parse parameters
+
+ set( options REQUIRED )
+ set( single_value_args )
+ set( multi_value_args )
+
+ cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_p_UNPARSED_ARGUMENTS)
+ ecbuild_critical("Unknown keywords given to ecbuild_find_perl(): \"${_p_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ find_package( Perl )
+
+ if( NOT PERL_EXECUTABLE AND _p_REQUIRED )
+ ecbuild_critical( "Failed to find Perl (REQUIRED)" )
+ endif()
+
+ if( PERL_EXECUTABLE )
+
+ execute_process( COMMAND ${PERL_EXECUTABLE} -V:version OUTPUT_VARIABLE perl_version_output_variable RESULT_VARIABLE perl_version_return )
+ if( NOT perl_version_return )
+ string(REGEX REPLACE "version='([^']+)'.*" "\\1" PERL_VERSION ${perl_version_output_variable})
+ endif()
+
+ # from cmake 2.8.8 onwards
+ if( NOT PERL_VERSION_STRING )
+ set( PERL_VERSION_STRING ${PERL_VERSION} )
+ endif()
+
+ ecbuild_debug("ecbuild_find_perl: found perl version ${PERL_VERSION_STRING} as ${PERL_EXECUTABLE}")
+
+ endif()
+
+endmacro( ecbuild_find_perl )
diff --git a/cmake/ecbuild_find_python.cmake b/cmake/ecbuild_find_python.cmake
new file mode 100644
index 0000000..48ba28f
--- /dev/null
+++ b/cmake/ecbuild_find_python.cmake
@@ -0,0 +1,205 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_find_python
+# ===================
+#
+# Find Python interpreter, its version and the Python libraries. ::
+#
+# ecbuild_find_python( [ VERSION <version> ] [ REQUIRED ] [ NO_LIBS ] )
+#
+# Options
+# -------
+#
+# VERSION : optional
+# minimum required version
+#
+# REQUIRED : optional
+# fail if Python was not found
+#
+# NO_LIBS : optional
+# only search for the Python interpreter, not the libraries
+#
+# Output variables
+# ----------------
+#
+# The following CMake variables are set if python was found:
+#
+# :PYTHONINTERP_FOUND: Python interpreter was found
+# :PYTHONLIBS_FOUND: Python libraries were found
+# :PYTHON_FOUND: Python was found (both interpreter and libraries)
+# :PYTHON_EXECUTABLE: Python executable
+# :PYTHON_VERSION_MAJOR: major version number
+# :PYTHON_VERSION_MINOR: minor version number
+# :PYTHON_VERSION_PATCH: patch version number
+# :PYTHON_VERSION_STRING: Python version
+# :PYTHON_INCLUDE_DIRS: Python include directories
+# :PYTHON_LIBRARIES: Python libraries
+# :PYTHON_SITE_PACKAGES: Python site packages directory
+#
+##############################################################################
+
+set( __test_python ${CMAKE_CURRENT_LIST_DIR}/pymain.c )
+
+function( ecbuild_find_python )
+
+ # parse parameters
+
+ set( options REQUIRED NO_LIBS )
+ set( single_value_args VERSION )
+ set( multi_value_args )
+
+ cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_p_UNPARSED_ARGUMENTS)
+ ecbuild_critical("Unknown keywords given to ecbuild_find_python(): \"${_p_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ # find python executable
+
+ find_package( PythonInterp )
+
+ if( NOT PYTHONINTERP_FOUND AND _p_REQUIRED )
+ ecbuild_error( "Failed to find any Python interpreter (REQUIRED)" )
+ endif()
+
+ # find python version
+ # execute_process( COMMAND ${PYTHON_EXECUTABLE} -V ERROR_VARIABLE _version RESULT_VARIABLE _return ERROR_STRIP_TRAILING_WHITESPACE)
+ # if( NOT _return )
+ # string(REGEX REPLACE ".*([0-9]+)\\.([0-9]+)\\.([0-9]+)" "\\1.\\2.\\3" PYTHON_VERSION ${_version} )
+ # endif()
+ # endif()
+
+ # ecbuild_debug( "Python version ${PYTHON_VERSION_STRING}" )
+ # ecbuild_debug_var(PYTHON_VERSION_MAJOR)
+ # ecbuild_debug_var(PYTHON_VERSION_MINOR)
+ # ecbuild_debug_var(PYTHON_VERSION_PATCH)
+
+ if( PYTHONINTERP_FOUND AND DEFINED _p_VERSION )
+ if( _p_VERSION VERSION_GREATER "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}.${PYTHON_VERSION_PATCH}" )
+ set( PYTHONINTERP_FOUND 0 )
+ set( PYTHON_EXECUTABLE "PYTHON_EXECUTABLE-NOTFOUND" )
+ if( _p_REQUIRED )
+ ecbuild_critical( "Required python version at least ${_p_VERSION} but found only ${PYTHON_VERSION_STRING}" )
+ else()
+ ecbuild_warn( "Looking for python version at least ${_p_VERSION} but found only ${PYTHON_VERSION_STRING}\nMarking Python as NOTFOUND" )
+ endif()
+ endif()
+ endif()
+
+ if( PYTHONINTERP_FOUND )
+ ecbuild_debug( "ecbuild_find_python: Found Python interpreter version ${PYTHON_VERSION_STRING} at ${PYTHON_EXECUTABLE}" )
+
+ # find where python site-packages are ...
+
+ if( PYTHON_EXECUTABLE )
+ execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()" OUTPUT_VARIABLE PYTHON_SITE_PACKAGES OUTPUT_STRIP_TRAILING_WHITESPACE)
+ endif()
+ ecbuild_debug( "ecbuild_find_python: PYTHON_SITE_PACKAGES=${PYTHON_SITE_PACKAGES}" )
+
+ endif()
+ if( PYTHONINTERP_FOUND AND NOT _p_NO_LIBS )
+ # find python config
+
+ if( PYTHON_EXECUTABLE AND EXISTS ${PYTHON_EXECUTABLE}-config )
+ set(PYTHON_CONFIG_EXECUTABLE ${PYTHON_EXECUTABLE}-config CACHE PATH "" FORCE)
+ else()
+ find_program( PYTHON_CONFIG_EXECUTABLE NAMES python-config python-config${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR} )
+ endif()
+
+ ecbuild_debug_var( PYTHON_CONFIG_EXECUTABLE )
+
+ # find python libs
+
+ # The OpenBSD python packages have python-config's
+ # that don't reliably report linking flags that will work.
+
+ if( PYTHON_CONFIG_EXECUTABLE AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD" )
+ ecbuild_debug( "ecbuild_find_python: Searching for Python include directories and libraries using ${PYTHON_CONFIG_EXECUTABLE}" )
+
+ execute_process(COMMAND "${PYTHON_CONFIG_EXECUTABLE}" --ldflags
+ OUTPUT_VARIABLE PYTHON_LIBRARIES
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_QUIET)
+
+ execute_process(COMMAND "${PYTHON_CONFIG_EXECUTABLE}" --includes
+ OUTPUT_VARIABLE PYTHON_INCLUDE_DIRS
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_QUIET)
+
+ string(REGEX REPLACE "^[-I]" "" PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIRS}")
+ string(REGEX REPLACE "[ ]-I" " " PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIRS}")
+
+ separate_arguments(PYTHON_INCLUDE_DIRS)
+
+ else() # revert to finding pythonlibs the standard way (cmake macro)
+ ecbuild_debug( "ecbuild_find_python: Searching for Python include directories and libraries using find_package(PythonLibs)" )
+
+ find_package(PythonLibs)
+ if( PYTHON_INCLUDE_PATH AND NOT PYTHON_INCLUDE_DIRS )
+ set(PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_PATH}")
+ endif()
+
+ endif()
+
+ # Remove duplicate include directories
+ list(REMOVE_DUPLICATES PYTHON_INCLUDE_DIRS)
+
+
+ if( PYTHON_LIBRARIES AND PYTHON_INCLUDE_DIRS )
+ # Test if we can link against the Python libraries and include Python.h
+ try_compile( PYTHON_LIBS_WORKING ${CMAKE_CURRENT_BINARY_DIR}
+ ${__test_python}
+ CMAKE_FLAGS "-DINCLUDE_DIRECTORIES=${PYTHON_INCLUDE_DIRS}"
+ LINK_LIBRARIES ${PYTHON_LIBRARIES} )
+
+ # set output variables
+
+ find_package_handle_standard_args( PythonLibs DEFAULT_MSG
+ PYTHON_INCLUDE_DIRS PYTHON_LIBRARIES PYTHON_LIBS_WORKING )
+ ecbuild_debug( "ecbuild_find_python: PYTHON_INCLUDE_DIRS=${PYTHON_INCLUDE_DIRS}" )
+ ecbuild_debug( "ecbuild_find_python: PYTHON_LIBRARIES=${PYTHON_LIBRARIES}" )
+
+ endif()
+
+ # Also set PYTHON_FOUND and Python_FOUND for compatibility with ecbuild_add_option
+ if( PYTHONLIBS_FOUND )
+ set( PYTHON_FOUND 1 )
+ set( Python_FOUND 1 )
+ endif()
+
+ endif()
+
+ ecbuild_debug_var( PYTHONINTERP_FOUND )
+ ecbuild_debug_var( PYTHON_FOUND )
+ ecbuild_debug_var( PYTHON_EXECUTABLE )
+ ecbuild_debug_var( PYTHON_CONFIG_EXECUTABLE )
+ ecbuild_debug_var( PYTHON_VERSION_MAJOR )
+ ecbuild_debug_var( PYTHON_VERSION_MINOR )
+ ecbuild_debug_var( PYTHON_VERSION_PATCH )
+ ecbuild_debug_var( PYTHON_VERSION_STRING )
+ ecbuild_debug_var( PYTHON_INCLUDE_DIRS )
+ ecbuild_debug_var( PYTHON_LIBRARIES )
+ ecbuild_debug_var( PYTHON_SITE_PACKAGES )
+
+ set( PYTHONINTERP_FOUND ${PYTHONINTERP_FOUND} PARENT_SCOPE )
+ set( PYTHONLIBS_FOUND ${PYTHONLIBS_FOUND} PARENT_SCOPE )
+ set( PYTHON_FOUND ${PYTHON_FOUND} PARENT_SCOPE )
+ set( PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE} PARENT_SCOPE )
+ set( PYTHON_VERSION_MAJOR ${PYTHON_VERSION_MAJOR} PARENT_SCOPE )
+ set( PYTHON_VERSION_MINOR ${PYTHON_VERSION_MINOR} PARENT_SCOPE )
+ set( PYTHON_VERSION_PATCH ${PYTHON_VERSION_PATCH} PARENT_SCOPE )
+ set( PYTHON_VERSION_STRING ${PYTHON_VERSION_STRING} PARENT_SCOPE )
+ set( PYTHON_INCLUDE_DIRS ${PYTHON_INCLUDE_DIRS} PARENT_SCOPE )
+ set( PYTHON_LIBRARIES ${PYTHON_LIBRARIES} PARENT_SCOPE )
+ set( PYTHON_SITE_PACKAGES ${PYTHON_SITE_PACKAGES} PARENT_SCOPE )
+
+endfunction( ecbuild_find_python )
diff --git a/cmake/ecbuild_generate_config_headers.cmake b/cmake/ecbuild_generate_config_headers.cmake
new file mode 100644
index 0000000..6bc8301
--- /dev/null
+++ b/cmake/ecbuild_generate_config_headers.cmake
@@ -0,0 +1,63 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_generate_config_headers
+# ===============================
+#
+# Generates the ecBuild configuration header for the project with the system
+# introspection done by CMake. ::
+#
+# ecbuild_generate_config_headers( [ DESTINATION <directory> ] )
+#
+# Options
+# -------
+#
+# DESTINATION : optional
+# installation destination directory
+#
+##############################################################################
+
+function( ecbuild_generate_config_headers )
+
+ # parse parameters
+
+ set( options )
+ set( single_value_args DESTINATION )
+ set( multi_value_args )
+
+ cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_PAR_UNPARSED_ARGUMENTS)
+ ecbuild_critical("Unknown keywords given to ecbuild_generate_config_headers(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ # generate list of compiler flags
+
+ string( TOUPPER ${PROJECT_NAME} PNAME )
+
+ get_property( langs GLOBAL PROPERTY ENABLED_LANGUAGES )
+
+ foreach( lang ${langs} )
+ set( EC_${lang}_FLAGS "${CMAKE_${lang}_FLAGS} ${CMAKE_${lang}_FLAGS_${CMAKE_BUILD_TYPE_CAPS}}" )
+ endforeach()
+
+ configure_file( ${ECBUILD_MACROS_DIR}/ecbuild_config.h.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}_ecbuild_config.h )
+
+ # install ecbuild configuration
+
+ set( _destination ${INSTALL_INCLUDE_DIR} )
+ if( _p_DESTINATION )
+ set( _destination ${_p_DESTINATION} )
+ endif()
+
+ install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}_ecbuild_config.h DESTINATION ${_destination} )
+
+endfunction( ecbuild_generate_config_headers )
diff --git a/cmake/ecbuild_generate_fortran_interfaces.cmake b/cmake/ecbuild_generate_fortran_interfaces.cmake
new file mode 100644
index 0000000..d586248
--- /dev/null
+++ b/cmake/ecbuild_generate_fortran_interfaces.cmake
@@ -0,0 +1,143 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_generate_fortran_interfaces
+# ===================================
+#
+# Generates interfaces form the Fortran source files. ::
+#
+# ecbuild_generate_fortran_interfaces()
+#
+# Options
+# -------
+#
+# TARGET : required
+# target name
+#
+##############################################################################
+
+function( ecbuild_generate_fortran_interfaces )
+
+ find_program( FCM_EXECUTABLE fcm REQUIRED DOC "Fortran interface generator" )
+
+ if( NOT FCM_EXECUTABLE )
+ ecbuild_error( "ecbuild_generate_fortran_interfaces: fcm executable not found." )
+ endif()
+
+ set( options )
+ set( single_value_args TARGET DESTINATION PARALLEL INCLUDE_DIRS GENERATED SOURCE_DIR FCM_CONFIG_FILE )
+ set( multi_value_args DIRECTORIES )
+
+ cmake_parse_arguments( P "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if( NOT DEFINED P_TARGET )
+ ecbuild_error( "ecbuild_generate_fortran_interfaces: TARGET argument missing" )
+ endif()
+
+ if( NOT DEFINED P_DESTINATION )
+ ecbuild_error( "ecbuild_generate_fortran_interfaces: DESTINATION argument missing" )
+ endif()
+
+ if( NOT DEFINED P_DIRECTORIES )
+ ecbuild_error( "ecbuild_generate_fortran_interfaces: DIRECTORIES argument missing" )
+ endif()
+
+ if( NOT DEFINED P_PARALLEL OR (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") )
+ set( P_PARALLEL 1 )
+ endif()
+
+ ecbuild_debug_var( P_PARALLEL )
+
+ if( NOT DEFINED P_SOURCE_DIR )
+ ecbuild_error( "ecbuild_generate_fortran_interfaces: SOURCE_DIR argument missing")
+ endif()
+
+ if( DEFINED P_FCM_CONFIG_FILE )
+ set( FCM_CONFIG_FILE ${P_FCM_CONFIG_FILE} )
+ endif()
+
+ if( NOT FCM_CONFIG_FILE )
+ set( PROJECT_FCM_CONFIG_FILE "${PROJECT_SOURCE_DIR}/cmake/fcm-make-interfaces.cfg" )
+ if( EXISTS ${PROJECT_FCM_CONFIG_FILE} )
+ set( FCM_CONFIG_FILE ${PROJECT_FCM_CONFIG_FILE} )
+ ecbuild_debug( "ecbuild_generate_fortran_interfaces: fcm configuration found in ${PROJECT_FCM_CONFIG_FILE}" )
+ else()
+ ecbuild_debug( "ecbuild_generate_fortran_interfaces: fcm configuration not found in ${PROJECT_FCM_CONFIG_FILE}" )
+ endif()
+ endif()
+
+ if( NOT FCM_CONFIG_FILE )
+ set( DEFAULT_FCM_CONFIG_FILE "${ECBUILD_MACROS_DIR}/fcm-make-interfaces.cfg" )
+ if( EXISTS ${DEFAULT_FCM_CONFIG_FILE} )
+ set( FCM_CONFIG_FILE ${DEFAULT_FCM_CONFIG_FILE} )
+ ecbuild_debug( "ecbuild_generate_fortran_interfaces: fcm configuration found in ${DEFAULT_FCM_CONFIG_FILE}" )
+ else()
+ ecbuild_debug( "ecbuild_generate_fortran_interfaces: fcm configuration not found in ${DEFAULT_FCM_CONFIG_FILE}" )
+ endif()
+ endif()
+
+ ecbuild_debug_var( FCM_CONFIG_FILE )
+
+ if( NOT EXISTS ${FCM_CONFIG_FILE} )
+ ecbuild_error( "ecbuild_generate_fortran_interfaces: needs fcm configuration in ${FCM_CONFIG_FILE}" )
+ endif()
+
+ foreach( _srcdir ${P_DIRECTORIES} )
+ if( _srcdir MATCHES "/$" )
+ ecbuild_critical("ecbuild_generate_fortran_interfaces: directory ${_srcdir} must not end with /")
+ endif()
+ ecbuild_list_add_pattern( LIST fortran_files SOURCE_DIR ${P_SOURCE_DIR} GLOB ${_srcdir}/*.F* )
+ endforeach()
+
+ string( REPLACE ";" " " _srcdirs "${P_DIRECTORIES}" )
+
+ set( _cnt 0 )
+ foreach( file ${_fortran_files} )
+ if( ${${SRC}/file} IS_NEWER_THAN ${${SRC}/file} )
+ set( run_fcm 1 )
+ endif()
+ endforeach()
+
+ foreach( fortran_file ${fortran_files} )
+ #list( APPEND fullpath_fortran_files ${CMAKE_CURRENT_SOURCE_DIR}/${fortran_file} )
+ get_filename_component(base ${fortran_file} NAME_WE)
+ set( interface_file "${CMAKE_CURRENT_BINARY_DIR}/interfaces/include/${base}.intfb.h" )
+ list( APPEND interface_files ${interface_file} )
+ set_source_files_properties( ${interface_file} PROPERTIES GENERATED TRUE )
+ math(EXPR _cnt "${_cnt}+1")
+ endforeach()
+
+ ecbuild_info("Target ${P_TARGET} will generate ${_cnt} interface files using FCM")
+
+
+
+ if( DEFINED P_GENERATED )
+ set( ${P_GENERATED} ${interface_files} PARENT_SCOPE )
+ endif()
+
+ set( include_dir ${CMAKE_CURRENT_BINARY_DIR}/${P_DESTINATION}/interfaces/include )
+ set( ${P_INCLUDE_DIRS} ${include_dir} PARENT_SCOPE )
+
+ execute_process( COMMAND ${CMAKE_COMMAND} -E make_directory ${include_dir}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} )
+
+ add_custom_command(
+ OUTPUT "${P_DESTINATION}/${P_TARGET}.timestamp"
+ COMMAND ${FCM_EXECUTABLE} make -j ${P_PARALLEL} --config-file=${FCM_CONFIG_FILE} interfaces.ns-incl=${_srcdirs} interfaces.source=${P_SOURCE_DIR}
+ COMMAND touch "${P_TARGET}.timestamp"
+ DEPENDS ${fortran_files}
+ COMMENT "Generating ${_cnt} interface files for target ${P_TARGET}"
+ WORKING_DIRECTORY ${P_DESTINATION} VERBATIM )
+
+ add_custom_target( ${P_TARGET} DEPENDS ${P_DESTINATION}/${P_TARGET}.timestamp )
+
+
+endfunction( ecbuild_generate_fortran_interfaces )
diff --git a/cmake/ecbuild_generate_rpc.cmake b/cmake/ecbuild_generate_rpc.cmake
new file mode 100644
index 0000000..f06624f
--- /dev/null
+++ b/cmake/ecbuild_generate_rpc.cmake
@@ -0,0 +1,100 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_generate_rpc
+# ====================
+#
+# Process RPC (Remote Procedure Call) Language files using rpcgen. ::
+#
+# ecbuild_generate_rpc( SOURCE <file>
+# [ TARGET_H <file> ]
+# [ TARGET_C <file> ]
+# [ DEPENDANT <file1> [ <file2> ... ] ] )
+#
+# Options
+# -------
+#
+# SOURCE : required
+# RPC source file
+#
+# TARGET_H : optional (required if TARGET_C not given)
+# name of header file to be generated
+#
+# TARGET_C : optional (required if TARGET_H not given)
+# name of source file to be generated
+#
+# DEPENDANT : optional
+# list of files which depend on the generated source and header files
+#
+##############################################################################
+
+macro( ecbuild_generate_rpc )
+
+ set( options )
+ set( single_value_args SOURCE TARGET_H TARGET_C )
+ set( multi_value_args DEPENDANT )
+
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_PAR_UNPARSED_ARGUMENTS)
+ ecbuild_critical("Unknown keywords given to ecbuild_generate_rpc(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if( NOT _PAR_SOURCE )
+ ecbuild_critical("The call to ecbuild_generate_rpc() doesn't specify the SOURCE file.")
+ endif()
+
+# optional
+# if( NOT _PAR_DEPENDANT )
+# ecbuild_critical("The call to ecbuild_generate_rpc() doesn't specify the DEPENDANT files.")
+# endif()
+
+ if( NOT DEFINED _PAR_TARGET_H AND NOT DEFINED _PAR_TARGET_C )
+ ecbuild_critical("The call to ecbuild_generate_rpc() doesn't specify the _PAR_TARGET_H or _PAR_TARGET_C files.")
+ endif()
+
+ find_package( RPCGEN REQUIRED )
+
+ if( DEFINED _PAR_TARGET_H )
+
+ add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_TARGET_H}
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/${_PAR_SOURCE} ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_SOURCE}
+ COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_TARGET_H}
+ COMMAND ${RPCGEN_EXECUTABLE} -h -o ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_TARGET_H} ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_SOURCE}
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${_PAR_SOURCE} )
+
+ if( DEFINED _PAR_DEPENDANT )
+ foreach( file ${_PAR_DEPENDANT} )
+ set_source_files_properties( ${file} PROPERTIES OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${_PAR_TARGET_H}" )
+ endforeach()
+ endif()
+
+ endif()
+
+ if( DEFINED _PAR_TARGET_C )
+
+ add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_TARGET_C}
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/${_PAR_SOURCE} ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_SOURCE}
+ COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_TARGET_C}
+ COMMAND ${RPCGEN_EXECUTABLE} -c -o ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_TARGET_C} ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_SOURCE}
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${_PAR_SOURCE} )
+
+ if( DEFINED _PAR_DEPENDANT )
+ foreach( file ${_PAR_DEPENDANT} )
+ set_source_files_properties( ${file} PROPERTIES OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${_PAR_TARGET_C}" )
+ endforeach()
+ endif()
+
+ endif()
+
+endmacro( ecbuild_generate_rpc )
diff --git a/cmake/ecbuild_generate_yy.cmake b/cmake/ecbuild_generate_yy.cmake
new file mode 100644
index 0000000..35088fb
--- /dev/null
+++ b/cmake/ecbuild_generate_yy.cmake
@@ -0,0 +1,201 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_generate_yy
+# ===================
+#
+# Process lex/yacc files. ::
+#
+# ecbuild_generate_yy( YYPREFIX <prefix>
+# YACC <file>
+# LEX <file>
+# DEPENDANT <file1> [ <file2> ... ]
+# [ SOURCE_DIR <dir> ]
+# [ OUTPUT_DIRECTORY <dir> ]
+# [ YACC_TARGET <file> ]
+# [ LEX_TARGET <file> ]
+# [ YACC_FLAGS <flags> ]
+# [ LEX_FLAGS <flags> ]
+# [ BISON_FLAGS <flags> ]
+# [ FLEX_FLAGS <flags> ] )
+#
+# Options
+# -------
+#
+# YYPREFIX : required
+# prefix to use for file and function names
+#
+# YACC : required
+# base name of the yacc source file (without .y extension)
+#
+# LEX : required
+# base name of the lex source file (without .l extension)
+#
+# DEPENDANT : required
+# list of files which depend on the generated lex and yacc target files
+# At least one should be an existing source file (not generated itself).
+#
+# SOURCE_DIR : optional, defaults to CMAKE_CURRENT_SOURCE_DIR
+# directory where yacc and lex source files are located
+#
+# OUTPUT_DIRECTORY : optional, defaults to CMAKE_CURRENT_BINARY_DIR
+# output directory for yacc and lex target files
+#
+# YACC_TARGET : optional, defaults to YACC
+# base name of the generated yacc target file (without .c extension)
+#
+# LEX_TARGET : optional, defaults to LEX
+# base name of the generated lex target file (without .c extension)
+#
+# YACC_FLAGS : optional, defaults to -t
+# flags to pass to yacc executable
+#
+# LEX_FLAGS : optional
+# flags to pass to lex executable
+#
+# BISON_FLAGS : optional, defaults to -t
+# flags to pass to bison executable
+#
+# FLEX_FLAGS : optional, defaults to -l
+# flags to pass to flex executable
+#
+##############################################################################
+
+macro( ecbuild_generate_yy )
+
+ ecbuild_find_lexyacc() # find [ yacc|byson ] and [ lex|flex ]
+
+ ecbuild_find_perl( REQUIRED )
+
+ set( options )
+ set( single_value_args YYPREFIX YACC LEX SOURCE_DIR OUTPUT_DIRECTORY YACC_TARGET LEX_TARGET LEX_FLAGS YACC_FLAGS FLEX_FLAGS BISON_FLAGS )
+ set( multi_value_args DEPENDANT )
+
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_PAR_UNPARSED_ARGUMENTS)
+ ecbuild_critical("Unknown keywords given to ecbuild_generate_yy(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if( NOT _PAR_YYPREFIX )
+ ecbuild_critical("The call to ecbuild_generate_yy() doesn't specify the YYPREFIX.")
+ endif()
+
+ if( NOT _PAR_YACC )
+ ecbuild_critical("The call to ecbuild_generate_yy() doesn't specify the YACC file.")
+ endif()
+
+ if( NOT _PAR_LEX )
+ ecbuild_critical("The call to ecbuild_generate_yy() doesn't specify the LEX file.")
+ endif()
+
+ if( NOT _PAR_DEPENDANT )
+ ecbuild_critical("The call to ecbuild_generate_yy() doesn't specify the DEPENDANT files.")
+ endif()
+
+ set( BASE ${_PAR_YYPREFIX}_${_PAR_YACC} )
+
+ ## default flags
+
+ if( NOT _PAR_LEX_FLAGS )
+ set( _PAR_LEX_FLAGS "" )
+ endif()
+
+ if( NOT _PAR_FLEX_FLAGS )
+ set( _PAR_FLEX_FLAGS "-l" )
+ endif()
+
+ if( NOT _PAR_YACC_FLAGS )
+ set( _PAR_YACC_FLAGS "-t" )
+ endif()
+
+ if( NOT _PAR_BISON_FLAGS )
+ set( _PAR_BISON_FLAGS "-t" )
+ endif()
+
+ if( NOT _PAR_YACC_TARGET )
+ set ( _PAR_YACC_TARGET ${_PAR_YACC} )
+ endif()
+
+ if ( NOT _PAR_LEX_TARGET )
+ set ( _PAR_LEX_TARGET ${_PAR_LEX} )
+ endif()
+
+ if( NOT _PAR_SOURCE_DIR )
+ set( _PAR_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} )
+ endif()
+
+ if( NOT _PAR_OUTPUT_DIRECTORY )
+ set( _PAR_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} )
+ else()
+ file( MAKE_DIRECTORY ${_PAR_OUTPUT_DIRECTORY} )
+ endif()
+
+ set( ${BASE}yy_tmp_target ${_PAR_OUTPUT_DIRECTORY}/${_PAR_YACC_TARGET}.tmp.c )
+ set( ${BASE}yh_tmp_target ${_PAR_OUTPUT_DIRECTORY}/${_PAR_YACC_TARGET}.tmp.h )
+ set( ${BASE}yl_tmp_target ${_PAR_OUTPUT_DIRECTORY}/${_PAR_LEX_TARGET}.tmp.c )
+
+ set( ${BASE}yy_target ${_PAR_OUTPUT_DIRECTORY}/${_PAR_YACC_TARGET}.c )
+ set( ${BASE}yh_target ${_PAR_OUTPUT_DIRECTORY}/${_PAR_YACC_TARGET}.h )
+ set( ${BASE}yl_target ${_PAR_OUTPUT_DIRECTORY}/${_PAR_LEX_TARGET}.c )
+
+ if( BISON_FOUND )
+ bison_target( ${BASE}_parser ${_PAR_SOURCE_DIR}/${_PAR_YACC}.y ${${BASE}yy_tmp_target} COMPILE_FLAGS "${_PAR_BISON_FLAGS}" )
+ else()
+ yacc_target( ${BASE}_parser ${_PAR_SOURCE_DIR}/${_PAR_YACC}.y ${${BASE}yy_tmp_target} COMPILE_FLAGS "${_PAR_YACC_FLAGS}" )
+ endif()
+
+ if( FLEX_FOUND )
+ flex_target( ${BASE}_scanner ${_PAR_SOURCE_DIR}/${_PAR_LEX}.l ${${BASE}yl_tmp_target} COMPILE_FLAGS "${_PAR_FLEX_FLAGS}" )
+ add_flex_bison_dependency(${BASE}_scanner ${BASE}_parser)
+ else()
+ lex_target( ${BASE}_scanner ${_PAR_SOURCE_DIR}/${_PAR_LEX}.l ${${BASE}yl_tmp_target} COMPILE_FLAGS "${_PAR_LEX_FLAGS}" )
+ add_lex_yacc_dependency(${BASE}_scanner ${BASE}_parser)
+ endif()
+
+ set_source_files_properties(${${BASE}yy_tmp_target} GENERATED)
+ set_source_files_properties(${${BASE}yh_tmp_target} GENERATED)
+ set_source_files_properties(${${BASE}yl_tmp_target} GENERATED)
+
+ add_custom_command(OUTPUT ${${BASE}yy_target}
+ COMMAND ${CMAKE_COMMAND} -E copy ${${BASE}yy_tmp_target} ${${BASE}yy_target}
+ COMMAND ${PERL_EXECUTABLE} -pi -e 's/yy/${_PAR_YYPREFIX}/g' ${${BASE}yy_target}
+ COMMAND ${PERL_EXECUTABLE} -pi -e 's/\\.tmp\\.c/\\.c/g' ${${BASE}yy_target}
+ DEPENDS ${${BASE}yy_tmp_target}
+ )
+
+ add_custom_command(OUTPUT ${${BASE}yh_target}
+ COMMAND ${CMAKE_COMMAND} -E copy ${${BASE}yh_tmp_target} ${${BASE}yh_target}
+ COMMAND ${PERL_EXECUTABLE} -pi -e 's/yy/${_PAR_YYPREFIX}/g' ${${BASE}yh_target}
+ COMMAND ${PERL_EXECUTABLE} -pi -e 's/\\.tmp\\.h/\\.h/g' ${${BASE}yh_target}
+ DEPENDS ${${BASE}yh_tmp_target}
+ )
+
+ add_custom_command(OUTPUT ${${BASE}yl_target}
+ COMMAND ${CMAKE_COMMAND} -E copy ${${BASE}yl_tmp_target} ${${BASE}yl_target}
+ COMMAND ${PERL_EXECUTABLE} -pi -e 's/yy/${_PAR_YYPREFIX}/g' ${${BASE}yl_target}
+ COMMAND ${PERL_EXECUTABLE} -pi -e 's/\\.tmp\\.c/\\.c/g' ${${BASE}yl_target}
+ DEPENDS ${${BASE}yl_tmp_target}
+ )
+
+ set_source_files_properties(${${BASE}yy_target} GENERATED)
+ set_source_files_properties(${${BASE}yh_target} GENERATED)
+ set_source_files_properties(${${BASE}yl_target} GENERATED)
+
+ foreach( file ${_PAR_DEPENDANT} )
+ if( NOT IS_ABSOLUTE ${file})
+ set( file ${_PAR_SOURCE_DIR}/${file} )
+ endif()
+ set_source_files_properties( ${file} PROPERTIES
+ OBJECT_DEPENDS "${${BASE}yy_target};${${BASE}yh_target};${${BASE}yl_target}" )
+ endforeach()
+
+endmacro( ecbuild_generate_yy )
diff --git a/cmake/ecbuild_get_cxx11_flags.cmake b/cmake/ecbuild_get_cxx11_flags.cmake
new file mode 100644
index 0000000..47d0e1a
--- /dev/null
+++ b/cmake/ecbuild_get_cxx11_flags.cmake
@@ -0,0 +1,71 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_get_cxx11_flags
+# =======================
+#
+# Set the CMake variable ``${CXX11_FLAGS}`` to the C++11 flags for the current
+# compiler (based on macros from https://github.com/UCL/GreatCMakeCookOff). ::
+#
+# ecbuild_get_cxx11_flags( CXX11_FLAGS )
+#
+##############################################################################
+
+function( ecbuild_get_cxx11_flags CXX11_FLAGS )
+
+ include(CheckCXXCompilerFlag)
+
+ # On older cmake versions + newer compilers,
+ # the given version of CheckCXXCompilerFlags does not quite work.
+ if(CMAKE_VERSION VERSION_LESS 2.8.9)
+ macro (CHECK_CXX_COMPILER_FLAG _FLAG _RESULT)
+ set(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}")
+ set(CMAKE_REQUIRED_DEFINITIONS "${_FLAG}")
+ CHECK_CXX_SOURCE_COMPILES("int main() { return 0;}" ${_RESULT}
+ # Some compilers do not fail with a bad flag
+ FAIL_REGEX "command line option .* is valid for .* but not for C\\\\+\\\\+" # GNU
+ FAIL_REGEX "unrecognized .*option" # GNU
+ FAIL_REGEX "unknown .*option" # Clang
+ FAIL_REGEX "ignoring unknown option" # MSVC
+ FAIL_REGEX "warning D9002" # MSVC, any lang
+ FAIL_REGEX "option.*not supported" # Intel
+ FAIL_REGEX "invalid argument .*option" # Intel
+ FAIL_REGEX "ignoring option .*argument required" # Intel
+ FAIL_REGEX "[Uu]nknown option" # HP
+ FAIL_REGEX "[Ww]arning: [Oo]ption" # SunPro
+ FAIL_REGEX "command option .* is not recognized" # XL
+ FAIL_REGEX "not supported in this configuration; ignored" # AIX
+ FAIL_REGEX "File with unknown suffix passed to linker" # PGI
+ FAIL_REGEX "WARNING: unknown flag:" # Open64
+ )
+ set (CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}")
+ endmacro ()
+ endif(CMAKE_VERSION VERSION_LESS 2.8.9)
+
+ check_cxx_compiler_flag(-std=c++11 has_std_cpp11)
+ check_cxx_compiler_flag(-std=c++0x has_std_cpp0x)
+ if(MINGW)
+ check_cxx_compiler_flag(-std=gnu++11 has_std_gnupp11)
+ check_cxx_compiler_flag(-std=gnu++0x has_std_gnupp0x)
+ endif(MINGW)
+ if(has_std_gnupp11)
+ set(${CXX11_FLAGS} "-std=gnu++11" PARENT_SCOPE)
+ elseif(has_std_gnupp0x)
+ set(${CXX11_FLAGS} "-std=gnu++0x" PARENT_SCOPE)
+ elseif(has_std_cpp11)
+ set(${CXX11_FLAGS} "-std=c++11" PARENT_SCOPE)
+ elseif(has_std_cpp0x)
+ set(${CXX11_FLAGS} "-std=c++0x" PARENT_SCOPE)
+ else()
+ ecbuild_critical("Could not detect C++11 flags")
+ endif(has_std_gnupp11)
+
+endfunction()
diff --git a/cmake/ecbuild_get_date.cmake b/cmake/ecbuild_get_date.cmake
new file mode 100644
index 0000000..730ea54
--- /dev/null
+++ b/cmake/ecbuild_get_date.cmake
@@ -0,0 +1,52 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_get_date
+# ================
+#
+# Set the CMake variable ``${DATE}`` to the current date in the form
+# YYYY.mm.DD. ::
+#
+# ecbuild_get_date( DATE )
+#
+##############################################################################
+
+macro(ecbuild_get_date RESULT)
+ if(UNIX)
+ execute_process(COMMAND "date" "+%d/%m/%Y" OUTPUT_VARIABLE ${RESULT})
+ string(REGEX REPLACE "(..)/(..)/(....).*" "\\3.\\2.\\1" ${RESULT} ${${RESULT}})
+ else()
+ ecbuild_error("date not implemented")
+ endif()
+endmacro(ecbuild_get_date)
+
+##############################################################################
+#.rst:
+#
+# ecbuild_get_timestamp
+# =====================
+#
+# Set the CMake variable ``${TIMESTAMP}`` to the current date and time in the
+# form YYYYmmDDHHMMSS. ::
+#
+# ecbuild_get_timestamp( TIMESTAMP )
+#
+##############################################################################
+
+macro(ecbuild_get_timestamp RESULT)
+ if(UNIX)
+ execute_process(COMMAND "date" "+%Y/%m/%d/%H/%M/%S" OUTPUT_VARIABLE _timestamp)
+ string(REGEX REPLACE "(....)/(..)/(..)/(..)/(..)/(..).*" "\\1\\2\\3\\4\\5\\6" ${RESULT} ${_timestamp})
+ else()
+ ecbuild_warn("This is NOT UNIX - timestamp not implemented")
+ endif()
+endmacro(ecbuild_get_timestamp)
+
diff --git a/cmake/ecbuild_get_resources.cmake b/cmake/ecbuild_get_resources.cmake
new file mode 100644
index 0000000..f531d82
--- /dev/null
+++ b/cmake/ecbuild_get_resources.cmake
@@ -0,0 +1,52 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+# macro for adding a test
+##############################################################################
+
+macro( ecbuild_get_resources )
+
+ set( options )
+ set( single_value_args TO_DIR )
+ set( multi_value_args LIST )
+
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_PAR_UNPARSED_ARGUMENTS)
+ ecbuild_critical("Unknown keywords given to ecbuild_get_resources(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if( NOT _PAR_LIST )
+ ecbuild_critical( "Missing parameter LIST of resources in macro ecbuild_get_resources()" )
+ endif()
+
+ if( NOT _PAR_TO_DIR )
+ set( _PAR_TO_DIR ${CMAKE_CURRENT_BINARY_DIR} )
+ endif()
+
+ list( LENGTH _PAR_LIST _rsize )
+ math( EXPR _max "${_rsize}-1" )
+ foreach( i RANGE 0 ${_max} 2 )
+
+ math( EXPR in "${i}+1" )
+
+ list( GET _PAR_LIST ${i} r )
+ list( GET _PAR_LIST ${in} rh )
+
+# ecbuild_debug_var( r )
+# ecbuild_debug_var( rh )
+
+ get_filename_component( rf ${r} NAME )
+
+ file( DOWNLOAD ${r} ${_PAR_TO_DIR}/${rf} EXPECTED_HASH SHA1=${rh} )
+
+ endforeach()
+
+
+endmacro()
diff --git a/cmake/ecbuild_get_test_data.cmake b/cmake/ecbuild_get_test_data.cmake
new file mode 100644
index 0000000..c19a760
--- /dev/null
+++ b/cmake/ecbuild_get_test_data.cmake
@@ -0,0 +1,390 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+
+# function for downloading test data
+
+function( _download_test_data _p_NAME _p_DIRNAME )
+
+ # TODO: make that 'at ecmwf'
+ #if(1)
+ #unset(ENV{no_proxy})
+ #unset(ENV{NO_PROXY})
+ #set(ENV{http_proxy} "http://proxy.ecmwf.int:3333")
+ #endif()
+
+ find_program( CURL_PROGRAM curl )
+
+ if( CURL_PROGRAM )
+
+ add_custom_command( OUTPUT ${_p_NAME}
+ COMMENT "(curl) downloading http://download.ecmwf.org/test-data/${_p_DIRNAME}/${_p_NAME}"
+ COMMAND ${CURL_PROGRAM} --silent --show-error --fail --output ${_p_NAME}
+ http://download.ecmwf.org/test-data/${_p_DIRNAME}/${_p_NAME} )
+
+ else()
+
+ find_program( WGET_PROGRAM wget )
+
+ if( WGET_PROGRAM )
+
+ add_custom_command( OUTPUT ${_p_NAME}
+ COMMENT "(wget) downloading http://download.ecmwf.org/test-data/${_p_DIRNAME}/${_p_NAME}"
+ COMMAND ${WGET_PROGRAM} -nv -O ${_p_NAME}
+ http://download.ecmwf.org/test-data/${_p_DIRNAME}/${_p_NAME} )
+
+ else()
+
+ if( WARNING_CANNOT_DOWNLOAD_TEST_DATA )
+ ecbuild_warn( "Couldn't find curl neither wget -- cannot download test data from server.\nPlease obtain the test data by other means and pleace it in the build directory." )
+ set( WARNING_CANNOT_DOWNLOAD_TEST_DATA 1 CACHE INTERNAL "Couldn't find curl neither wget -- cannot download test data from server" )
+ mark_as_advanced( WARNING_CANNOT_DOWNLOAD_TEST_DATA )
+ endif()
+
+ endif()
+
+ endif()
+
+endfunction()
+
+##############################################################################
+#.rst:
+#
+# ecbuild_get_test_data
+# =====================
+#
+# Download a test data set at build time. ::
+#
+# ecbuild_get_test_data( NAME <name>
+# [ TARGET <target> ]
+# [ DIRNAME <dir> ]
+# [ MD5 <hash> ]
+# [ EXTRACT ]
+# [ NOCHECK ] )
+#
+# curl or wget is required (curl is preferred if available).
+#
+# Options
+# -------
+#
+# NAME : required
+# name of the test data file
+#
+# TARGET : optional, defaults to test_data_<name>
+# CMake target name
+#
+# DIRNAME : optional, defaults to <project>/<relative path to current dir>
+# directory in which the test data resides
+#
+# MD5 : optional, ignored if NOCHECK is given
+# md5 checksum of the data set to verify. If not given and NOCHECK is *not*
+# set, download the md5 checksum and verify
+#
+# EXTRACT : optional
+# extract the downloaded file (supported archives: tar, zip, tar.gz, tar.bz2)
+#
+# NOCHECK : optional
+# do not verify the md5 checksum of the data file
+#
+# Usage
+# -----
+#
+# Download test data from ``http://download.ecmwf.org/test-data/<DIRNAME>/<NAME>``
+#
+# If the ``DIRNAME`` argument is not given, the project name followed by the
+# relative path from the root directory to the current directory is used.
+#
+# By default, the downloaded file is verified against an md5 checksum, either
+# given as the ``MD5`` argument or downloaded from the server otherwise. Use
+# the argument ``NOCHECK`` to disable this check.
+#
+# Examples
+# --------
+#
+# Do not verify the checksum: ::
+#
+# ecbuild_get_test_data( NAME msl.grib NOCHECK )
+#
+# Checksum agains remote md5 file: ::
+#
+# ecbuild_get_test_data( NAME msl.grib )
+#
+# Checksum agains local md5: ::
+#
+# ecbuild_get_test_data( NAME msl.grib MD5 f69ca0929d1122c7878d19f32401abe9 )
+#
+##############################################################################
+
+function( ecbuild_get_test_data )
+
+ set( options NOCHECK EXTRACT )
+ set( single_value_args TARGET URL NAME DIRNAME MD5 SHA1)
+ set( multi_value_args )
+
+ cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_p_UNPARSED_ARGUMENTS)
+ ecbuild_critical("Unknown keywords given to ecbuild_get_test_data(): \"${_p_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ file( RELATIVE_PATH currdir ${PROJECT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR} )
+
+ ### check parameters
+
+ if( NOT _p_NAME )
+ ecbuild_critical("ecbuild_get_test_data() expects a NAME")
+ endif()
+
+ if( NOT _p_TARGET )
+ string( REGEX REPLACE "[^A-Za-z0-9_]" "_" _p_TARGET "test_data_${_p_NAME}")
+# string( REGEX REPLACE "[^A-Za-z0-9_]" "_" _p_TARGET "${_p_NAME}")
+# set( _p_TARGET ${_p_NAME} )
+ endif()
+
+ if( NOT _p_DIRNAME )
+ set( _p_DIRNAME ${PROJECT_NAME}/${currdir} )
+ endif()
+
+# ecbuild_debug_var( _p_TARGET )
+# ecbuild_debug_var( _p_NAME )
+# ecbuild_debug_var( _p_URL )
+# ecbuild_debug_var( _p_DIRNAME )
+
+ # download the data
+
+ _download_test_data( ${_p_NAME} ${_p_DIRNAME} )
+
+ # perform the checksum if requested
+
+ set( _deps ${_p_NAME} )
+
+ if( NOT _p_NOCHECK )
+
+ if( NOT _p_MD5 AND NOT _p_SHA1) # use remote md5
+
+ add_custom_command( OUTPUT ${_p_NAME}.localmd5
+ COMMAND ${CMAKE_COMMAND} -E md5sum ${_p_NAME} > ${_p_NAME}.localmd5
+ DEPENDS ${_p_NAME} )
+
+ _download_test_data( ${_p_NAME}.md5 ${_p_DIRNAME} )
+
+ add_custom_command( OUTPUT ${_p_NAME}.ok
+ COMMAND ${CMAKE_COMMAND} -E compare_files ${_p_NAME}.md5 ${_p_NAME}.localmd5 &&
+ ${CMAKE_COMMAND} -E touch ${_p_NAME}.ok
+ DEPENDS ${_p_NAME}.localmd5 ${_p_NAME}.md5 )
+
+ list( APPEND _deps ${_p_NAME}.localmd5 ${_p_NAME}.ok )
+
+ endif()
+
+ if( _p_MD5 )
+
+ add_custom_command( OUTPUT ${_p_NAME}.localmd5
+ COMMAND ${CMAKE_COMMAND} -E md5sum ${_p_NAME} > ${_p_NAME}.localmd5
+ DEPENDS ${_p_NAME} )
+
+ configure_file( "${ECBUILD_MACROS_DIR}/md5.in" ${_p_NAME}.md5 @ONLY )
+
+ add_custom_command( OUTPUT ${_p_NAME}.ok
+ COMMAND ${CMAKE_COMMAND} -E compare_files ${_p_NAME}.md5 ${_p_NAME}.localmd5 &&
+ ${CMAKE_COMMAND} -E touch ${_p_NAME}.ok
+ DEPENDS ${_p_NAME}.localmd5 )
+
+ list( APPEND _deps ${_p_NAME}.localmd5 ${_p_NAME}.ok )
+
+ endif()
+
+# if( _p_SHA1 )
+
+# find_program( SHASUM NAMES sha1sum shasum )
+# if( SHASUM )
+# add_custom_command( OUTPUT ${_p_NAME}.localsha1
+# COMMAND ${SHASUM} ${_p_NAME} > ${_p_NAME}.localsha1 )
+
+# add_custom_command( OUTPUT ${_p_NAME}.ok
+# COMMAND diff ${_p_NAME}.sha1 ${_p_NAME}.localsha1 && touch ${_p_NAME}.ok )
+
+# configure_file( "${ECBUILD_MACROS_DIR}/sha1.in" ${_p_NAME}.sha1 @ONLY )
+
+# list( APPEND _deps ${_p_NAME}.localsha1 ${_p_NAME}.ok )
+# endif()
+
+# endif()
+
+ endif()
+
+ add_custom_target( ${_p_TARGET} DEPENDS ${_deps} )
+
+ if( _p_EXTRACT )
+ ecbuild_debug("ecbuild_get_test_data: extracting ${_p_NAME} (post-build for target ${_p_TARGET}")
+ add_custom_command( TARGET ${_p_TARGET} POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E tar xv ${_p_NAME} )
+ endif()
+
+endfunction(ecbuild_get_test_data)
+
+##############################################################################
+#.rst:
+#
+# ecbuild_get_test_multidata
+# ==========================
+#
+# Download multiple test data sets at build time. ::
+#
+# ecbuild_get_test_multidata( NAMES <name1> [ <name2> ... ]
+# TARGET <target>
+# [ DIRNAME <dir> ]
+# [ EXTRACT ]
+# [ NOCHECK ] )
+#
+# curl or wget is required (curl is preferred if available).
+#
+# Options
+# -------
+#
+# NAMES : required
+# list of names of the test data files
+#
+# TARGET : optional
+# CMake target name
+#
+# DIRNAME : optional, defaults to <project>/<relative path to current dir>
+# directory in which the test data resides
+#
+# EXTRACT : optional
+# extract downloaded files (supported archives: tar, zip, tar.gz, tar.bz2)
+#
+# NOCHECK : optional
+# do not verify the md5 checksum of the data file
+#
+# Usage
+# -----
+#
+# Download test data from ``http://download.ecmwf.org/test-data/<DIRNAME>``
+# for each name given in the list of ``NAMES``. Each name may contain a
+# relative path, which is appended to ``DIRNAME`` and may be followed by an
+# md5 checksum, separated with a ``:`` (the name must not contain spaces).
+#
+# If the ``DIRNAME`` argument is not given, the project name followed by the
+# relative path from the root directory to the current directory is used.
+#
+# By default, each downloaded file is verified against an md5 checksum, either
+# given as part of the name as described above or a remote checksum downloaded
+# from the server. Use the argument ``NOCHECK`` to disable this check.
+#
+# Examples
+# --------
+#
+# Do not verify checksums: ::
+#
+# ecbuild_get_test_multidata( TARGET get_grib_data NAMES foo.grib bar.grib
+# DIRNAME test/data/dir NOCHECK )
+#
+# Checksums agains remote md5 file: ::
+#
+# ecbuild_get_test_multidata( TARGET get_grib_data NAMES foo.grib bar.grib
+# DIRNAME test/data/dir )
+#
+# Checksum agains local md5: ::
+#
+# ecbuild_get_test_multidata( TARGET get_grib_data DIRNAME test/data/dir
+# NAMES msl.grib:f69ca0929d1122c7878d19f32401abe9 )
+#
+##############################################################################
+
+function( ecbuild_get_test_multidata )
+
+ set( options EXTRACT NOCHECK )
+ set( single_value_args TARGET DIRNAME )
+ set( multi_value_args NAMES )
+
+ cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_p_UNPARSED_ARGUMENTS)
+ ecbuild_critical("Unknown keywords given to ecbuild_get_test_data(): \"${_p_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ ### check parameters
+
+ if( NOT _p_NAMES )
+ ecbuild_critical("ecbuild_get_test_data() expects a NAMES")
+ endif()
+
+ if( NOT _p_TARGET )
+ ecbuild_critical("ecbuild_get_test_data() expects a TARGET")
+ endif()
+
+# ecbuild_debug_var( _p_TARGET )
+# ecbuild_debug_var( _p_NAME )
+# ecbuild_debug_var( _p_DIRNAME )
+
+ if( _p_EXTRACT )
+ set( _extract EXTRACT )
+ endif()
+
+ if( _p_NOCHECK )
+ set( _nocheck NOCHECK )
+ endif()
+
+ ### prepare file
+
+ set( _script ${CMAKE_CURRENT_BINARY_DIR}/get_data_${_p_TARGET}.cmake )
+
+ file( WRITE ${_script} "
+function(EXEC_CHECK)
+ execute_process(COMMAND \${ARGV} RESULT_VARIABLE CMD_RESULT)
+ if(CMD_RESULT)
+ message(FATAL_ERROR \"Error running ${CMD}\")
+ endif()
+endfunction()\n\n" )
+
+ foreach( _d ${_p_NAMES} )
+
+ string( REGEX MATCH "[^:]+" _f "${_d}" )
+
+ get_filename_component( _file ${_f} NAME )
+ get_filename_component( _dir ${_f} PATH )
+
+ list( APPEND _path_comps ${_p_DIRNAME} ${_dir} )
+ join( _path_comps "/" _dirname )
+ if( _dirname )
+ set( _dirname DIRNAME ${_dirname} )
+ endif()
+ unset( _path_comps )
+
+ string( REPLACE "." "_" _name "${_file}" )
+ string( REGEX MATCH ":.*" _md5 "${_d}" )
+ string( REPLACE ":" "" _md5 "${_md5}" )
+
+ if( _md5 )
+ set( _md5 MD5 ${_md5} )
+ endif()
+
+ #ecbuild_debug_var(_f)
+ #ecbuild_debug_var(_file)
+ #ecbuild_debug_var(_dirname)
+ #ecbuild_debug_var(_name)
+ #ecbuild_debug_var(_md5)
+
+ ecbuild_get_test_data(
+ TARGET __get_data_${_p_TARGET}_${_name}
+ NAME ${_file} ${_dirname} ${_md5} ${_extract} ${_nocheck} )
+
+ # The option /fast disables dependency checking on a target, see
+ # https://cmake.org/Wiki/CMake_FAQ#Is_there_a_way_to_skip_checking_of_dependent_libraries_when_compiling.3F
+ file( APPEND ${_script}
+ "exec_check( \"${CMAKE_COMMAND}\" --build \"${CMAKE_BINARY_DIR}\" --target __get_data_${_p_TARGET}_${_name}/fast )\n" )
+
+ endforeach()
+
+ if( ENABLE_TESTS )
+ add_test( NAME ${_p_TARGET} COMMAND ${CMAKE_COMMAND} -P ${_script} )
+ endif()
+
+endfunction(ecbuild_get_test_multidata)
diff --git a/cmake/ecbuild_git.cmake b/cmake/ecbuild_git.cmake
new file mode 100644
index 0000000..0a378a6
--- /dev/null
+++ b/cmake/ecbuild_git.cmake
@@ -0,0 +1,298 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+set( ECBUILD_GIT ON CACHE BOOL "Turn on/off ecbuild_git() function" )
+
+mark_as_advanced(ECBUILD_GIT)
+
+if( ECBUILD_GIT )
+
+ find_package(Git)
+
+ set( ECMWF_USER $ENV{USER} CACHE STRING "ECMWF git user" )
+ set( ECMWF_GIT SSH CACHE STRING "ECMWF git protocol" )
+
+ set( ECMWF_GIT_SSH "ssh://git@software.ecmwf.int:7999" CACHE INTERNAL "ECMWF ssh address" )
+ set( ECMWF_GIT_HTTPS "https://${ECMWF_USER}@software.ecmwf.int/stash/scm" CACHE INTERNAL "ECMWF https address" )
+
+ if( ECMWF_GIT MATCHES "[Ss][Ss][Hh]" )
+ set( ECMWF_GIT_ADDRESS ${ECMWF_GIT_SSH} CACHE INTERNAL "" )
+ else()
+ set( ECMWF_GIT_ADDRESS ${ECMWF_GIT_HTTPS} CACHE INTERNAL "" )
+ endif()
+
+endif()
+
+##############################################################################
+#.rst:
+#
+# ecbuild_git
+# ===========
+#
+# Manages an external Git repository. ::
+#
+# ecbuild_git( PROJECT <name>
+# DIR <directory>
+# URL <giturl>
+# [ BRANCH <gitbranch> | TAG <gittag> ]
+# [ UPDATE | NOREMOTE ] )
+# [ MANUAL ] )
+#
+# Options
+# -------
+#
+# PROJECT : required
+# project name for the Git repository to be managed
+#
+# DIR : required
+# directory to clone the repository into (can be relative)
+#
+# URL : required
+# Git URL of the remote repository to clone (see ``git help clone``)
+#
+# BRANCH : optional, cannot be combined with TAG
+# Git branch to check out
+#
+# TAG : optional, cannot be combined with BRANCH
+# Git tag or commit id to check out
+#
+# UPDATE : optional, requires BRANCH, cannot be combined with NOREMOTE
+# Create a CMake target update to fetch changes from the remote repository
+#
+# NOREMOTE : optional, cannot be combined with UPDATE
+# Do not fetch changes from the remote repository
+#
+# MANUAL : optional
+# Do not automatically switch branches or tags
+#
+##############################################################################
+
+macro( ecbuild_git )
+
+ set( options UPDATE NOREMOTE MANUAL )
+ set( single_value_args PROJECT DIR URL TAG BRANCH )
+ set( multi_value_args )
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if( DEFINED _PAR_BRANCH AND DEFINED _PAR_TAG )
+ ecbuild_critical( "Cannot defined both BRANCH and TAG in macro ecbuild_git" )
+ endif()
+
+ if( _PAR_UPDATE AND _PAR_NOREMOTE )
+ ecbuild_critical( "Cannot pass both NOREMOTE and UPDATE in macro ecbuild_git" )
+ endif()
+
+ if(_PAR_UNPARSED_ARGUMENTS)
+ ecbuild_critical("Unknown keywords given to ecbuild_git(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if( ECBUILD_GIT )
+
+ set( _needs_switch 0 )
+
+ get_filename_component( ABS_PAR_DIR "${_PAR_DIR}" ABSOLUTE )
+ get_filename_component( PARENT_DIR "${_PAR_DIR}/.." ABSOLUTE )
+
+ ### clone if no directory
+
+ if( NOT EXISTS "${_PAR_DIR}" )
+
+ ecbuild_info( "Cloning ${_PAR_PROJECT} from ${_PAR_URL} into ${_PAR_DIR}...")
+ execute_process(
+ COMMAND ${GIT_EXECUTABLE} "clone" ${_PAR_URL} ${clone_args} ${_PAR_DIR} "-q"
+ RESULT_VARIABLE nok ERROR_VARIABLE error
+ WORKING_DIRECTORY "${PARENT_DIR}")
+ if(nok)
+ ecbuild_critical("${_PAR_DIR} git clone failed:\n ${GIT_EXECUTABLE} clone ${_PAR_URL} ${clone_args} ${_PAR_DIR} -q\n ${error}\n")
+ endif()
+ ecbuild_info( "${_PAR_DIR} retrieved.")
+ set( _needs_switch 1 )
+
+ endif()
+
+ ### check current tag and sha1
+
+ if( IS_DIRECTORY "${_PAR_DIR}/.git" )
+
+ execute_process( COMMAND ${GIT_EXECUTABLE} rev-parse HEAD
+ OUTPUT_VARIABLE _sha1 RESULT_VARIABLE nok ERROR_VARIABLE error
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ WORKING_DIRECTORY "${ABS_PAR_DIR}" )
+ if(nok)
+ ecbuild_info("git rev-parse HEAD on ${_PAR_DIR} failed:\n ${error}")
+ endif()
+
+ execute_process( COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD
+ OUTPUT_VARIABLE _current_branch RESULT_VARIABLE nok ERROR_VARIABLE error
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ WORKING_DIRECTORY "${ABS_PAR_DIR}" )
+ if( nok OR _current_branch STREQUAL "" )
+ ecbuild_info("git rev-parse --abbrev-ref HEAD on ${_PAR_DIR} failed:\n ${error}")
+ endif()
+
+ execute_process( COMMAND ${GIT_EXECUTABLE} describe --exact-match --abbrev=0
+ OUTPUT_VARIABLE _current_tag RESULT_VARIABLE nok ERROR_VARIABLE error
+ OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_STRIP_TRAILING_WHITESPACE
+ WORKING_DIRECTORY "${ABS_PAR_DIR}" )
+
+ if( error MATCHES "no tag exactly matches" OR error MATCHES "No names found" )
+ unset( _current_tag )
+ else()
+ if( nok )
+ ecbuild_info("git describe --exact-match --abbrev=0 on ${_PAR_DIR} failed:\n ${error}")
+ endif()
+ endif()
+
+ if( NOT _current_tag ) # try nother method
+ execute_process( COMMAND ${GIT_EXECUTABLE} name-rev --tags --name-only ${_sha1}
+ OUTPUT_VARIABLE _current_tag RESULT_VARIABLE nok ERROR_VARIABLE error
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ WORKING_DIRECTORY "${ABS_PAR_DIR}" )
+ if( nok OR _current_tag STREQUAL "" )
+ ecbuild_info("git name-rev --tags --name-only on ${_PAR_DIR} failed:\n ${error}")
+ endif()
+ endif()
+
+ endif()
+
+ if( NOT _PAR_MANUAL AND DEFINED _PAR_BRANCH AND NOT "${_current_branch}" STREQUAL "${_PAR_BRANCH}" )
+ set( _needs_switch 1 )
+ endif()
+
+ if( NOT _PAR_MANUAL AND DEFINED _PAR_TAG AND NOT "${_current_tag}" STREQUAL "${_PAR_TAG}" )
+ set( _needs_switch 1 )
+ endif()
+
+ if( DEFINED _PAR_BRANCH AND _PAR_UPDATE AND NOT _PAR_NOREMOTE )
+
+ add_custom_target( git_update_${_PAR_PROJECT}
+ COMMAND "${GIT_EXECUTABLE}" pull -q
+ WORKING_DIRECTORY "${ABS_PAR_DIR}"
+ COMMENT "git pull of branch ${_PAR_BRANCH} on ${_PAR_DIR}" )
+
+ set( git_update_targets "git_update_${_PAR_PROJECT};${git_update_targets}" )
+
+ endif()
+
+ ### updates
+
+ if( _needs_switch AND IS_DIRECTORY "${_PAR_DIR}/.git" )
+
+ if( DEFINED _PAR_BRANCH )
+ set ( _gitref ${_PAR_BRANCH} )
+ ecbuild_info("Updating ${_PAR_PROJECT} to head of BRANCH ${_PAR_BRANCH}...")
+ else()
+ ecbuild_info("Updating ${_PAR_PROJECT} to TAG ${_PAR_TAG}...")
+ set ( _gitref ${_PAR_TAG} )
+ endif()
+
+ # fetching latest tags and branches
+
+ if( NOT _PAR_NOREMOTE )
+
+ ecbuild_info("git fetch --all @ ${ABS_PAR_DIR}")
+ execute_process( COMMAND "${GIT_EXECUTABLE}" fetch --all -q
+ RESULT_VARIABLE nok ERROR_VARIABLE error
+ WORKING_DIRECTORY "${ABS_PAR_DIR}")
+ if(nok)
+ ecbuild_warn("git fetch --all in ${_PAR_DIR} failed:\n ${error}")
+ endif()
+
+ ecbuild_info("git fetch --all --tags @ ${ABS_PAR_DIR}")
+ execute_process( COMMAND "${GIT_EXECUTABLE}" fetch --all --tags -q
+ RESULT_VARIABLE nok ERROR_VARIABLE error
+ WORKING_DIRECTORY "${ABS_PAR_DIR}")
+ if(nok)
+ ecbuild_warn("git fetch --all --tags in ${_PAR_DIR} failed:\n ${error}")
+ endif()
+
+ else()
+ ecbuild_info("${_PAR_DIR} marked NOREMOTE : Skipping git fetch")
+ endif()
+
+ # checking out gitref
+
+ ecbuild_info("git checkout ${_gitref} @ ${ABS_PAR_DIR}")
+ execute_process( COMMAND "${GIT_EXECUTABLE}" checkout -q "${_gitref}"
+ RESULT_VARIABLE nok ERROR_VARIABLE error
+ WORKING_DIRECTORY "${ABS_PAR_DIR}")
+ if(nok)
+ ecbuild_critical("git checkout ${_gitref} on ${_PAR_DIR} failed:\n ${GIT_EXECUTABLE} checkout -q ${_gitref}\n ${error}")
+ endif()
+
+ if( DEFINED _PAR_BRANCH AND _PAR_UPDATE ) #############################################################################
+
+ execute_process( COMMAND "${GIT_EXECUTABLE}" pull -q
+ RESULT_VARIABLE nok ERROR_VARIABLE error
+ WORKING_DIRECTORY "${ABS_PAR_DIR}")
+ if(nok)
+ ecbuild_warn("git pull of branch ${_PAR_BRANCH} on ${_PAR_DIR} failed:\n ${error}")
+ endif()
+
+ endif() ####################################################################################
+
+ endif( _needs_switch AND IS_DIRECTORY "${_PAR_DIR}/.git" )
+
+ endif( ECBUILD_GIT )
+
+endmacro()
+
+##############################################################################
+#.rst:
+#
+# ecbuild_stash
+# =============
+#
+# Manages an external Git repository on ECMWF Stash. ::
+#
+# ecbuild_stash( PROJECT <name>
+# DIR <directory>
+# STASH <repository>
+# [ BRANCH <gitbranch> | TAG <gittag> ]
+# [ UPDATE | NOREMOTE ] )
+# [ MANUAL ] )
+#
+# Options
+# -------
+#
+# PROJECT : required
+# project name for the Git repository to be managed
+#
+# DIR : required
+# directory to clone the repository into (can be relative)
+#
+# STASH : required
+# Stash repository in the form <project>/<repository>
+#
+# BRANCH : optional, cannot be combined with TAG
+# Git branch to check out
+#
+# TAG : optional, cannot be combined with BRANCH
+# Git tag or commit id to check out
+#
+# UPDATE : optional, requires BRANCH, cannot be combined with NOREMOTE
+# Create a CMake target update to fetch changes from the remote repository
+#
+# NOREMOTE : optional, cannot be combined with UPDATE
+# Do not fetch changes from the remote repository
+#
+# MANUAL : optional
+# Do not automatically switch branches or tags
+#
+##############################################################################
+
+macro( ecmwf_stash )
+
+ set( options )
+ set( single_value_args STASH )
+ set( multi_value_args )
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ ecbuild_git( URL "${ECMWF_GIT_ADDRESS}/${_PAR_STASH}.git" ${_PAR_UNPARSED_ARGUMENTS} )
+
+endmacro()
diff --git a/cmake/ecbuild_install_project.cmake b/cmake/ecbuild_install_project.cmake
new file mode 100644
index 0000000..2ba472e
--- /dev/null
+++ b/cmake/ecbuild_install_project.cmake
@@ -0,0 +1,432 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_install_project
+# =======================
+#
+# Set up packaging and export configuration. ::
+#
+# ecbuild_install_project( NAME <name> [ DESCRIPTION <description> ] )
+#
+# Options
+# -------
+#
+# NAME : required
+# project name used for packaging
+#
+# DESCRIPTION : optional
+# project description used for packaging
+#
+# Usage
+# -----
+#
+# ``ecbuild_install_project`` should be called at the very end of any ecBuild
+# project (only followed by ``ecbuild_print_summary``), sets up packaging of
+# the project with cpack and exports the configuration and targets for other
+# projects to use.
+#
+# Unless ECBUILD_SKIP_<PNAME>_EXPORT is set, the following files are generated:
+#
+# :<project>-config.cmake: default project configuration
+# :<project>-config-version.cmake: project version number
+# :<project>-import.cmake: extra project configuration (optional)
+# :<project>-config.cmake.tpls: 3rd party project configurations
+# :<project>-targets.cmake: exported targets
+#
+# For ``<project>-import.cmake`` to be exported to build and install tree,
+# ``<project>-import.cmake`` or ``<project>-import.cmake.in`` must exist in
+# the source tree. ``<project>-config.cmake.in`` and
+# ``<project>-config-version.cmake.in`` can be provided in the source tree to
+# override the default templates used to generate ``<project>-config.cmake``
+# and ``<project>-config-version.cmake``.
+#
+# In DEVELOPER_MODE, the build tree location is also added to the CMake user
+# package registry for top level projects.
+#
+# If the project is added as a subdirectory, the following CMake variables
+# are set in the parent scope:
+#
+# :<PROJECT>_FOUND: set to ``TRUE``
+# :<project>_FOUND: set to ``TRUE``
+# :<PROJECT>_VERSION: version string
+# :<project>_VERSION: version string
+# :<PROJECT>_INCLUDE_DIRS: list of include directories
+# :<PROJECT>_LIBRARIES: list of libraries
+# :<PROJECT>_DEFINITIONS: list of compiler definitions
+# :<PROJECT>_TPLS: list of 3rd party dependencies
+# :<PROJECT>_TPL_LIBRARIES: libraries of 3rd party dependencies
+# :<PROJECT>_TPL_DEFINITIONS: compiler definitions of 3rd party dependencies
+# :<PROJECT>_TPL_INCLUDE_DIRS: include directories of 3rd party dependencies
+# :<PROJECT>_FEATURES: list of enabled features
+# :<PROJECT>_HAVE_<FEATURE>: set to 1 for each enabled features
+#
+##############################################################################
+
+macro( ecbuild_install_project )
+
+ set( options )
+ set( single_value_args NAME DESCRIPTION )
+ set( multi_value_args COMPONENTS )
+
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_PAR_UNPARSED_ARGUMENTS)
+ ecbuild_critical("Unknown keywords given to ecbuild_install_project(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if( NOT _PAR_NAME )
+ ecbuild_critical("The call to ecbuild_install_project() doesn't specify the NAME.")
+ endif()
+
+ ### EXTRA TARGETS #####################################################
+
+ # added here to avoid adding another macro call at the end of each project,
+
+ if( PROJECT_NAME STREQUAL CMAKE_PROJECT_NAME )
+
+ ecbuild_define_libs_and_execs_targets()
+ ecbuild_define_links_target()
+
+ endif()
+
+ ### PACKAGING ########################################################
+
+ set( PNAME ${PROJECT_NAME_CAPS} )
+ set( LNAME ${PROJECT_NAME_LOWCASE} )
+
+ # components
+
+ # if( DEFINED _PAR_COMPONENTS )
+ # set(CPACK_COMPONENTS_ALL "${_PAR_COMPONENTS}")
+ # else()
+ # set(CPACK_COMPONENTS_ALL "${PROJECT_NAME}")
+ # endif()
+
+ # name, version, etc ...
+
+ set(CPACK_PACKAGE_NAME "${_PAR_NAME}")
+ set(CPACK_PACKAGE_VERSION "${${PNAME}_VERSION_STR}")
+
+ set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}")
+
+ set(CPACK_DEBIAN_PACKAGE_MAINTAINER "ECMWF") # required for DEB
+
+ # set(CPACK_ARCHIVE_COMPONENT_INSTALL "ON")
+ # set(CPACK_RPM_COMPONENT_INSTALL "ON")
+
+ # set(CPACK_GENERATOR "TGZ;RPM;DEB")
+ set(CPACK_GENERATOR "TGZ")
+ set(CPACK_SOURCE_GENERATOR "TGZ")
+ set(CPACK_PACKAGE_VENDOR "ECMWF")
+
+ # short description
+
+ if( _PAR_DESCRIPTION )
+ set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${_PAR_DESCRIPTION}" )
+ else()
+ set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${_PAR_NAME} misses a description" )
+ endif()
+
+ # long description
+
+ if( EXISTS ${PROJECT_SOURCE_DIR}/INSTALL )
+ set(CPACK_PACKAGE_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/INSTALL")
+ endif()
+ if( EXISTS ${PROJECT_SOURCE_DIR}/LICENSE )
+ set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE")
+ endif()
+
+ # set(CPACK_PACKAGE_EXECUTABLES ${ECBUILD_ALL_EXES})
+
+ list( APPEND CPACK_SOURCE_INSTALLED_DIRECTORIES
+ "${PROJECT_SOURCE_DIR}" "."
+ "${ECBUILD_MACROS_DIR}" "cmake/" )
+
+ # what to pack and not
+
+ set(CPACK_SOURCE_IGNORE_FILES
+ /build/
+ /\\\\.git/
+ /\\\\.svn/
+ CMakeLists.txt.user
+ \\\\.swp$
+ p4config
+ )
+
+ # skip the files that were declared as DONT_PACK
+
+ list( APPEND CPACK_SOURCE_IGNORE_FILES ${ECBUILD_DONT_PACK_FILES} )
+
+ # Find the ecbuild toolchain files and include in the source package if found
+ find_path( ECBUILD_TOOLCHAIN_DIR ecmwf-XC30-GNU.cmake
+ PATHS ${ECBUILD_MACROS_DIR}/../toolchains
+ ${ECBUILD_MACROS_DIR}/../share/ecbuild/toolchains )
+
+ mark_as_advanced( ECBUILD_TOOLCHAIN_DIR )
+
+ if( ECBUILD_TOOLCHAIN_DIR )
+ list( APPEND CPACK_SOURCE_INSTALLED_DIRECTORIES "${ECBUILD_TOOLCHAIN_DIR}" "share/ecbuild/toolchains/" )
+ endif()
+
+ # Find the ecbuild bin directory and include in the source package if found
+ find_program( ECBUILD_SCRIPT ecbuild
+ PATHS ${ECBUILD_MACROS_DIR}/../bin
+ ${ECBUILD_MACROS_DIR}/../../../bin )
+
+ mark_as_advanced( ECBUILD_SCRIPT )
+
+ if( ECBUILD_SCRIPT )
+ get_filename_component( ECBUILD_BIN_DIR ${ECBUILD_SCRIPT} PATH )
+ list( APPEND CPACK_SOURCE_INSTALLED_DIRECTORIES "${ECBUILD_BIN_DIR}" "bin/" )
+ endif()
+
+ # cpack config file
+
+ # set(CPACK_INSTALL_CMAKE_PROJECTS "${${PROJECT_NAME}_BINARY_DIR}" "${PROJECT_NAME}" "${CPACK_COMPONENTS_ALL}" "*" )
+
+ include( CPack )
+
+ ### EXPORTS ########################################################
+
+ ecbuild_enabled_features( ${PROJECT_NAME_CAPS}_FEATURES )
+ foreach( _f ${${PNAME}_FEATURES} )
+ set( ${PNAME}_HAVE_${_f} 1 )
+ endforeach()
+
+ ecbuild_info( "${PROJECT_NAME_CAPS}_TPLS: ${${PROJECT_NAME_CAPS}_TPLS}" )
+
+ foreach( _tpl ${${PNAME}_TPLS} )
+ string( TOUPPER ${_tpl} _TPL )
+
+ if( ${_tpl}_INCLUDE_DIRS )
+ list( APPEND ${PNAME}_TPL_INCLUDE_DIRS ${${_tpl}_INCLUDE_DIRS} )
+ elseif( ${_tpl}_INCLUDE_DIR )
+ list( APPEND ${PNAME}_TPL_INCLUDE_DIRS ${${_tpl}_INCLUDE_DIR} )
+ elseif( ${_TPL}_INCLUDE_DIRS )
+ list( APPEND ${PNAME}_TPL_INCLUDE_DIRS ${${_TPL}_INCLUDE_DIRS} )
+ elseif( ${_TPL}_INCLUDE_DIR )
+ list( APPEND ${PNAME}_TPL_INCLUDE_DIRS ${${_TPL}_INCLUDE_DIR} )
+ endif()
+
+ if( ${_tpl}_LIBRARIES )
+ list( APPEND ${PNAME}_TPL_LIBRARIES ${${_tpl}_LIBRARIES} )
+ elseif( ${_tpl}_LIBRARY )
+ list( APPEND ${PNAME}_TPL_LIBRARIES ${${_tpl}_LIBRARY} )
+ elseif( ${_TPL}_LIBRARIES )
+ list( APPEND ${PNAME}_TPL_LIBRARIES ${${_TPL}_LIBRARIES} )
+ elseif( ${_TPL}_LIBRARY )
+ list( APPEND ${PNAME}_TPL_LIBRARIES ${${_TPL}_LIBRARY} )
+ endif()
+
+ if( ${_tpl}_DEFINITIONS )
+ list( APPEND ${PNAME}_TPL_DEFINITIONS ${${_tpl}_DEFINITIONS} )
+ elseif( ${_TPL}_DEFINITIONS )
+ list( APPEND ${PNAME}_TPL_DEFINITIONS ${${_TPL}_DEFINITIONS} )
+ endif()
+ endforeach()
+
+ # Generate the project .cmake config files
+ # All variables here must be (sub)project specific in order to work within bundles
+ if ( NOT ECBUILD_SKIP_${PNAME}_EXPORT )
+
+ set( _template_config "${ECBUILD_MACROS_DIR}/project-config.cmake.in" )
+ if( EXISTS ${LNAME}-config.cmake.in )
+ set( _template_config "${LNAME}-config.cmake.in" )
+ endif()
+
+ set( _template_config_version "${ECBUILD_MACROS_DIR}/project-config-version.cmake.in" )
+ if( EXISTS ${LNAME}-config-version.cmake.in )
+ set( _template_config_version "${LNAME}-config-version.cmake.in" )
+ endif()
+
+ # project-config-version.cmake -- format ([0-9]+).([0-9]+).([0-9]+)
+
+ set( PACKAGE_VERSION "${${PNAME}_VERSION}" )
+ set( PACKAGE_GIT_SHA1 "${${PNAME}_GIT_SHA1}" )
+ set( PACKAGE_GIT_SHA1_SHORT "${${PNAME}_GIT_SHA1_SHORT}" )
+
+ configure_file( "${_template_config_version}" "${PROJECT_BINARY_DIR}/${LNAME}-config-version.cmake" @ONLY )
+
+ install( FILES "${PROJECT_BINARY_DIR}/${LNAME}-config-version.cmake" DESTINATION "${INSTALL_CMAKE_DIR}" )
+
+ # prepare imutable variables (don't depend on install path)
+
+ if( ${PNAME}_FEATURES )
+ set( CONF_FEATURES ${${PNAME}_FEATURES} )
+ endif()
+
+ set( CONF_LIBRARIES ${${PROJECT_NAME}_ALL_LIBS} )
+ if( ${PNAME}_LIBRARIES )
+ set( CONF_LIBRARIES ${${PNAME}_LIBRARIES} )
+ endif()
+
+ set( CONF_DEFINITIONS "" )
+ if( ${PNAME}_DEFINITIONS )
+ set( CONF_DEFINITIONS ${${PNAME}_DEFINITIONS} )
+ endif()
+
+ set( CONF_TPL_LIBRARIES "" )
+ if( ${PNAME}_TPL_LIBRARIES )
+ set( CONF_TPL_LIBRARIES ${${PNAME}_TPL_LIBRARIES} )
+ endif()
+
+ # project-config.cmake @ build tree
+
+ set( CONF_TPLS ${${PNAME}_TPLS} )
+
+ set( CONF_INCLUDE_DIRS "${PROJECT_SOURCE_DIR}" "${PROJECT_BINARY_DIR}" )
+ if( ${PNAME}_INCLUDE_DIRS )
+ set( CONF_INCLUDE_DIRS ${${PNAME}_INCLUDE_DIRS} )
+ endif()
+
+ set( CONF_TPL_INCLUDE_DIRS "" )
+ foreach( _tpl ${${PNAME}_TPLS} )
+ string( TOUPPER ${_tpl} TPL )
+ if( ${_tpl}_INCLUDE_DIRS )
+ list( APPEND CONF_TPL_INCLUDE_DIRS ${${_tpl}_INCLUDE_DIRS} )
+ elseif( ${_tpl}_INCLUDE_DIR )
+ list( APPEND CONF_TPL_INCLUDE_DIRS ${${_tpl}_INCLUDE_DIR} )
+ elseif( ${TPL}_INCLUDE_DIRS )
+ list( APPEND CONF_TPL_INCLUDE_DIRS ${${TPL}_INCLUDE_DIRS} )
+ elseif( ${TPL}_INCLUDE_DIR )
+ list( APPEND CONF_TPL_INCLUDE_DIRS ${${TPL}_INCLUDE_DIR} )
+ endif()
+ endforeach()
+
+ set( CONF_IMPORT_FILE "${LNAME}-import.cmake" )
+
+ # If <project>-import.cmake.in exist in source tree, configure it to
+ # the build tree and install the configured version
+ if( EXISTS "${PROJECT_SOURCE_DIR}/${CONF_IMPORT_FILE}.in" )
+ ecbuild_debug( "Found ${PROJECT_SOURCE_DIR}/${CONF_IMPORT_FILE}.in - configuring to ${PROJECT_BINARY_DIR}/${CONF_IMPORT_FILE}" )
+ configure_file( "${PROJECT_SOURCE_DIR}/${CONF_IMPORT_FILE}.in"
+ "${PROJECT_BINARY_DIR}/${CONF_IMPORT_FILE}" @ONLY )
+ install( FILES "${PROJECT_BINARY_DIR}/${CONF_IMPORT_FILE}"
+ DESTINATION "${INSTALL_CMAKE_DIR}" )
+ # Otherwise, if <project>-import.cmake exist in source tree, copy it to
+ # the build tree and install it
+ elseif( EXISTS "${PROJECT_SOURCE_DIR}/${CONF_IMPORT_FILE}" )
+ ecbuild_debug( "Found ${PROJECT_SOURCE_DIR}/${CONF_IMPORT_FILE} - copying to ${PROJECT_BINARY_DIR}/${CONF_IMPORT_FILE}" )
+ configure_file( "${PROJECT_SOURCE_DIR}/${CONF_IMPORT_FILE}"
+ "${PROJECT_BINARY_DIR}/${CONF_IMPORT_FILE}" COPYONLY )
+ install( FILES "${PROJECT_SOURCE_DIR}/${CONF_IMPORT_FILE}"
+ DESTINATION "${INSTALL_CMAKE_DIR}" )
+ else()
+ ecbuild_debug( "No ${CONF_IMPORT_FILE} found in ${PROJECT_SOURCE_DIR}" )
+ endif()
+
+ set( _lname_config "${PROJECT_BINARY_DIR}/${LNAME}-config.cmake")
+
+ set( _is_build_dir_export ON )
+ configure_file( "${_template_config}" "${_lname_config}" @ONLY )
+
+ file( REMOVE ${_lname_config}.tpls.in )
+
+ foreach( _tpl ${${PNAME}_TPLS} )
+
+ string( TOUPPER ${_tpl} TPL )
+
+ if( ${TPL}_IMPORT_FILE ) # ecBuild packages should trigger this if they export themselves
+
+ ecbuild_debug( "Adding TPL ${TPL} import file to ${_lname_config}.tpls.in" )
+ set( __import_file "${${TPL}_IMPORT_FILE}" )
+ file( APPEND "${_lname_config}.tpls.in" "if( NOT ${TPL}_IMPORT_FILE )\n" )
+ file( APPEND "${_lname_config}.tpls.in" " include( \"${__import_file}\" OPTIONAL )\n" )
+ file( APPEND "${_lname_config}.tpls.in" "endif()\n" )
+
+ elseif( ${TPL}_CONFIG ) # cmake built packages (e.g. CGAL) may have exported their targets
+
+ ecbuild_debug( "Adding TPL ${TPL} import file to ${_lname_config}.tpls.in" )
+ set( __import_file "${${TPL}_CONFIG}" )
+ file( APPEND "${_lname_config}.tpls.in" "if( NOT ${TPL}_CONFIG )\n" )
+ file( APPEND "${_lname_config}.tpls.in" " include( \"${__import_file}\" OPTIONAL )\n" )
+ file( APPEND "${_lname_config}.tpls.in" " set( ${TPL}_CONFIG \"${__import_file}\" )\n" )
+ file( APPEND "${_lname_config}.tpls.in" "endif()\n" )
+
+ endif()
+
+ endforeach()
+
+ if( EXISTS "${_lname_config}.tpls.in" )
+ configure_file( "${_lname_config}.tpls.in" "${_lname_config}.tpls" @ONLY )
+ install( FILES "${_lname_config}.tpls" DESTINATION "${INSTALL_CMAKE_DIR}" )
+ endif()
+
+ # project-config.cmake @ install tree
+
+ file( RELATIVE_PATH REL_INCLUDE_DIR "${${PNAME}_FULL_INSTALL_CMAKE_DIR}" "${${PNAME}_FULL_INSTALL_INCLUDE_DIR}" )
+ set( CONF_INCLUDE_DIRS "\${${PNAME}_CMAKE_DIR}/${REL_INCLUDE_DIR}" )
+
+ set( CONF_TPL_INCLUDE_DIRS "" )
+ foreach( _tpl ${${PNAME}_TPLS} )
+ string( TOUPPER ${_tpl} TPL )
+ if( ${TPL}_FULL_INSTALL_INCLUDE_DIR )
+ list( APPEND CONF_TPL_INCLUDE_DIRS "\${${PNAME}_CMAKE_DIR}/${REL_INCLUDE_DIR}" )
+ endif()
+ if( ${_tpl}_INCLUDE_DIRS )
+ list( APPEND CONF_TPL_INCLUDE_DIRS ${${_tpl}_INCLUDE_DIRS} )
+ elseif( ${_tpl}_INCLUDE_DIR )
+ list( APPEND CONF_TPL_INCLUDE_DIRS ${${_tpl}_INCLUDE_DIR} )
+ elseif( ${TPL}_INCLUDE_DIRS )
+ list( APPEND CONF_TPL_INCLUDE_DIRS ${${TPL}_INCLUDE_DIRS} )
+ elseif( ${TPL}_INCLUDE_DIR )
+ list( APPEND CONF_TPL_INCLUDE_DIRS ${${TPL}_INCLUDE_DIR} )
+ endif()
+ endforeach()
+
+ set( _is_build_dir_export OFF )
+ configure_file( "${_template_config}" "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${LNAME}-config.cmake" @ONLY )
+ install( FILES "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${LNAME}-config.cmake" DESTINATION "${INSTALL_CMAKE_DIR}" )
+
+ # install the export
+
+ if( ${PROJECT_NAME}_ALL_EXES OR ${PROJECT_NAME}_ALL_LIBS )
+ install( EXPORT ${PROJECT_NAME}-targets
+ DESTINATION "${INSTALL_CMAKE_DIR}" )
+ endif()
+
+ endif() # if ( NOT ECBUILD_SKIP_${PNAME}_EXPORT )
+
+ # exports the package for use from the build-tree but only in DEVELOPER_MODE
+ # inserts <package> into the CMake user package registry
+
+ if( PROJECT_NAME STREQUAL CMAKE_PROJECT_NAME )
+
+ if( DEVELOPER_MODE )
+ export( PACKAGE ${PROJECT_NAME} )
+ endif()
+
+ else()
+
+ # export variables for upper projects
+
+ set( ${PNAME}_FOUND TRUE PARENT_SCOPE )
+ set( ${PROJECT_NAME}_FOUND TRUE PARENT_SCOPE )
+ set( ${PNAME}_VERSION ${${PNAME}_VERSION} PARENT_SCOPE )
+ set( ${PNAME}_GIT_SHA1 ${${PNAME}_GIT_SHA1} PARENT_SCOPE )
+ set( ${PNAME}_GIT_SHA1_SHORT ${${PNAME}_GIT_SHA1_SHORT} PARENT_SCOPE )
+ set( ${PROJECT_NAME}_VERSION ${${PNAME}_VERSION} PARENT_SCOPE )
+ set( ${PNAME}_INCLUDE_DIRS ${${PNAME}_INCLUDE_DIRS} PARENT_SCOPE )
+ set( ${PNAME}_LIBRARIES ${${PNAME}_LIBRARIES} PARENT_SCOPE )
+ set( ${PNAME}_DEFINITIONS ${${PNAME}_DEFINITIONS} PARENT_SCOPE )
+ set( ${PNAME}_PACKAGES ${${PNAME}_PACKAGES} PARENT_SCOPE )
+ set( ${PNAME}_TPLS ${${PNAME}_TPLS} PARENT_SCOPE )
+ set( ${PNAME}_TPL_LIBRARIES ${${PNAME}_TPL_LIBRARIES} PARENT_SCOPE )
+ set( ${PNAME}_TPL_DEFINITIONS ${${PNAME}_TPL_DEFINITIONS} PARENT_SCOPE )
+ set( ${PNAME}_TPL_INCLUDE_DIRS ${${PNAME}_TPL_INCLUDE_DIRS} PARENT_SCOPE )
+ set( ${PNAME}_FEATURES ${${PNAME}_FEATURES} PARENT_SCOPE )
+ foreach( _f ${${PNAME}_FEATURES} )
+ set( ${PNAME}_HAVE_${_f} ${${PNAME}_HAVE_${_f}} PARENT_SCOPE )
+ endforeach()
+
+ endif()
+
+endmacro( ecbuild_install_project )
diff --git a/cmake/ecbuild_list_add_pattern.cmake b/cmake/ecbuild_list_add_pattern.cmake
new file mode 100644
index 0000000..0f68217
--- /dev/null
+++ b/cmake/ecbuild_list_add_pattern.cmake
@@ -0,0 +1,102 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_list_add_pattern
+# ========================
+#
+# Exclude items from a list that match a list of patterns. ::
+#
+# ecbuild_list_add_pattern( LIST <input_list>
+# GLOB <pattern1> [ <pattern2> ... ]
+# [ SOURCE_DIR <source_dir> ]
+# [ QUIET ] )
+#
+# Options
+# -------
+#
+# LIST : required
+# list variable to be appended to
+#
+# GLOB : required
+# Regex pattern of exclusion
+#
+# SOURCE_DIR : optional
+# Directory from where to start search
+#
+# QUIET : optional
+# Don't warn if patterns don't match
+#
+##############################################################################
+
+function( ecbuild_list_add_pattern )
+
+ set( options QUIET )
+ set( single_value_args LIST SOURCE_DIR )
+ set( multi_value_args GLOB )
+
+ cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_p_UNPARSED_ARGUMENTS)
+ ecbuild_critical("Unknown keywords given to ecbuild_list_add_pattern(): \"${_p_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if( NOT _p_LIST )
+ ecbuild_critical("The call to ecbuild_list_add_pattern() doesn't specify the LIST.")
+ endif()
+
+ if( NOT _p_GLOB )
+ ecbuild_critical("The call to ecbuild_list_add_pattern() doesn't specify the GLOB.")
+ endif()
+
+ #####
+
+ set( input_list ${${_p_LIST}} )
+ unset( matched_files )
+
+ foreach( pattern ${_p_GLOB} )
+
+ if( IS_ABSOLUTE ${pattern} )
+ ecbuild_debug( "ecbuild_list_add_pattern: Adding ${pattern}" )
+ file( GLOB_RECURSE matched_files ${pattern} )
+ else()
+
+ if(_p_SOURCE_DIR)
+ if( IS_ABSOLUTE ${_p_SOURCE_DIR} )
+ ecbuild_debug( "ecbuild_list_add_pattern: Adding ${_p_SOURCE_DIR}/${pattern}" )
+ file( GLOB_RECURSE matched_files ${_p_SOURCE_DIR}/${pattern} )
+ else()
+ ecbuild_debug( "ecbuild_list_add_pattern: Adding ${_p_SOURCE_DIR}/${pattern}" )
+ file( GLOB_RECURSE matched_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${_p_SOURCE_DIR}/${pattern} )
+ endif()
+ else()
+ ecbuild_debug( "ecbuild_list_add_pattern: Adding ${pattern} ")
+ file( GLOB_RECURSE matched_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${pattern} )
+ endif()
+
+ endif()
+
+ if(matched_files)
+ ecbuild_debug( "ecbuild_list_add_pattern: Found ${matched_files}" )
+ list( APPEND input_list ${matched_files} )
+ list( REMOVE_DUPLICATES input_list )
+ set( ${_p_LIST} ${input_list} PARENT_SCOPE )
+ else()
+ if(NOT _p_QUIET)
+ ecbuild_warn( "ecbuild_list_add_pattern: no matches found for patterns ${pattern}" )
+ else()
+ ecbuild_debug( "ecbuild_list_add_pattern:no matches found for patterns ${pattern}" )
+ endif()
+ endif()
+
+ endforeach()
+
+
+endfunction(ecbuild_list_add_pattern)
diff --git a/cmake/ecbuild_list_exclude_pattern.cmake b/cmake/ecbuild_list_exclude_pattern.cmake
new file mode 100644
index 0000000..7e02f47
--- /dev/null
+++ b/cmake/ecbuild_list_exclude_pattern.cmake
@@ -0,0 +1,88 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_list_exclude_pattern
+# ============================
+#
+# Exclude items from a list that match a list of patterns. ::
+#
+# ecbuild_list_exclude_pattern( LIST <input_list>
+# REGEX <regex1> [ <regex2> ... ]
+# [ QUIET ] )
+#
+# Options
+# -------
+#
+# LIST : required
+# list variable to be cleaned
+#
+# REGEX : required
+# Regex pattern of exclusions
+#
+# QUIET : optional
+# Don't warn if patterns don't match
+#
+##############################################################################
+
+function( ecbuild_list_exclude_pattern )
+
+ set( options QUIET )
+ set( single_value_args LIST )
+ set( multi_value_args REGEX )
+
+ cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_p_UNPARSED_ARGUMENTS)
+ ecbuild_critical("Unknown keywords given to ecbuild_list_exclude_pattern(): \"${_p_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if( NOT _p_LIST )
+ ecbuild_critical("The call to ecbuild_list_exclude_pattern() doesn't specify the LIST.")
+ endif()
+
+ if( NOT _p_REGEX )
+ ecbuild_critical("The call to ecbuild_list_exclude_pattern() doesn't specify the REGEX.")
+ endif()
+
+ #####
+
+ set( result "" )
+ set( matches_found 0 )
+
+ # ecbuild_debug_var(_p_REGEX)
+
+ foreach( item ${${_p_LIST}} )
+
+ set( _keep 1 )
+
+ foreach( pattern ${_p_REGEX} )
+ if( ${item} MATCHES ${pattern} )
+ set( _keep 0 )
+ set( matches_found 1 )
+ endif()
+ endforeach()
+ if( _keep )
+ list( APPEND result ${item} )
+# else()
+# ecbuild_warn( "removing ${item}" )
+ endif()
+
+ endforeach()
+
+ if( matches_found )
+ set( ${_p_LIST} ${result} PARENT_SCOPE )
+ else()
+ if( NOT _p_QUIET )
+ ecbuild_warn( "ecbuild_list_exclude_pattern: no matches found for patterns ${_p_REGEX} in ${_p_LIST}" )
+ endif()
+ endif()
+
+endfunction(ecbuild_list_exclude_pattern)
diff --git a/cmake/ecbuild_list_extra_search_paths.cmake b/cmake/ecbuild_list_extra_search_paths.cmake
new file mode 100644
index 0000000..b81f062
--- /dev/null
+++ b/cmake/ecbuild_list_extra_search_paths.cmake
@@ -0,0 +1,81 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+############################################################################################
+#
+# macro for adding search paths for a package to a given CMake variable
+#
+# usage: ecbuild_list_extra_search_paths( netcdf4 VARIABLE )
+
+function( ecbuild_list_extra_search_paths pkg var )
+
+ ecbuild_deprecate( " ecbuild_list_extra_search_paths should no longer be"
+ " used and is going to be removed in a future version of ecBuild." )
+
+ # ecbuild_debug_var( pkg )
+ # ecbuild_debug_var( var )
+
+ string( TOUPPER ${pkg} _PKG )
+
+ # PKG_PATH (upper case)
+
+ if( DEFINED ${_PKG}_PATH AND EXISTS ${${_PKG}_PATH} )
+ ecbuild_debug("ecbuild_list_extra_search_paths(${pkg}): appending ${_PKG}_PATH = ${${_PKG}_PATH} to ${var}")
+ list( APPEND ${var} ${${_PKG}_PATH} )
+ endif()
+
+ # ENV PKG_PATH (upper case)
+
+ if( DEFINED ENV{${_PKG}_PATH} AND EXISTS $ENV{${_PKG}_PATH} )
+ ecbuild_debug("ecbuild_list_extra_search_paths(${pkg}): appending \$${_PKG}_PATH = $ENV{${_PKG}_PATH} to ${var}")
+ list( APPEND ${var} $ENV{${_PKG}_PATH} )
+ endif()
+
+ # pkg_PATH (lower case)
+
+ if( DEFINED ${pkg}_PATH AND EXISTS ${${pkg}_PATH} )
+ ecbuild_debug("ecbuild_list_extra_search_paths(${pkg}): appending ${pkg}_PATH = ${${pkg}_PATH} to ${var}")
+ list( APPEND ${var} ${${pkg}_PATH} )
+ endif()
+
+ # ENV pkg_PATH (lower case)
+
+ if( DEFINED ${pkg}_PATH AND EXISTS $ENV{${pkg}_PATH} )
+ ecbuild_debug("ecbuild_list_extra_search_paths(${pkg}): appending \$${pkg}_PATH = $ENV{${pkg}_PATH} to ${var}")
+ list( APPEND ${var} $ENV{${pkg}_PATH} )
+ endif()
+
+ # ENV PKG_DIR (upper case)
+
+ if( DEFINED ENV{${_PKG}_DIR} AND EXISTS $ENV{${_PKG}_DIR} )
+ ecbuild_debug("ecbuild_list_extra_search_paths(${pkg}): appending \$${_PKG}_DIR = $ENV{${_PKG}_DIR} to ${var}")
+ list( APPEND ${var} $ENV{${_PKG}_DIR} )
+ endif()
+
+ # ENV pkg_DIR (lower case)
+
+ if( DEFINED ENV{${pkg}_DIR} AND EXISTS $ENV{${pkg}_DIR} )
+ ecbuild_debug("ecbuild_list_extra_search_paths(${pkg}): appending \$${pkg}_DIR = $ENV{${pkg}_DIR} to ${var}")
+ list( APPEND ${var} $ENV{${pkg}_DIR} )
+ endif()
+
+ # sanitize the list
+
+ if( ${var} )
+ list( REMOVE_DUPLICATES ${var} )
+ endif()
+
+ # define it out of the function
+
+ ecbuild_debug("ecbuild_list_extra_search_paths(${pkg}): setting ${var} to ${${var}}")
+ set( ${var} ${${var}} PARENT_SCOPE )
+
+# ecbuild_debug_var( ${var} )
+
+endfunction()
+
diff --git a/cmake/ecbuild_list_macros.cmake b/cmake/ecbuild_list_macros.cmake
new file mode 100644
index 0000000..176a161
--- /dev/null
+++ b/cmake/ecbuild_list_macros.cmake
@@ -0,0 +1,58 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+# function for concatenating list into a string
+#
+# examples:
+#
+# set( _paths "foo" "bar" )
+# join( _paths "/" _mypath )
+#
+# message( "${_mpath}" ) # produces "foo/bar"
+
+function( JOIN _listname _glue _output )
+
+ set( _ret "" )
+
+ foreach( _v ${${_listname}} )
+ if( _ret )
+ set(_ret "${_ret}${_glue}${_v}") # append
+ else()
+ set(_ret "${_v}") # init
+ endif()
+ endforeach()
+
+ set(${_output} "${_ret}" PARENT_SCOPE)
+
+endfunction()
+
+##############################################################################
+# function for inserting a key / value into a map
+#
+# examples:
+#
+# map_insert( "mymap" "foo" "bar" )
+#
+
+function( MAP_INSERT _map _key _value )
+ set( "_${_map}_${_key}" "${_value}" PARENT_SCOPE )
+endfunction(MAP_INSERT)
+
+##############################################################################
+# function for inserting a key / value into a map
+#
+# examples:
+#
+# map_get( "mymap" "foo" VAR )
+#
+
+function( MAP_GET _map _key _var )
+ set( ${_var} "${_${_map}_${_key}}" PARENT_SCOPE )
+endfunction(MAP_GET)
+
diff --git a/cmake/ecbuild_log.cmake b/cmake/ecbuild_log.cmake
new file mode 100644
index 0000000..ec99495
--- /dev/null
+++ b/cmake/ecbuild_log.cmake
@@ -0,0 +1,256 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# Logging
+# =======
+#
+# ecBuild provides functions for logging based on a log level set by the user,
+# similar to the Python logging module:
+#
+# :ecbuild_debug: logs a ``STATUS`` message if log level <= ``DEBUG``
+# :ecbuild_info: logs a ``STATUS`` message if log level <= ``INFO``
+# :ecbuild_warn: logs a ``WARNING`` message if log level <= ``WARN``
+# :ecbuild_error: logs a ``SEND_ERROR`` message if log level <= ``ERROR``
+# :ecbuild_critical: logs a ``FATAL_ERROR`` message if log level <= ``CRITICAL``
+# :ecbuild_deprecate: logs a ``DEPRECATION`` message
+#
+# Furthermore there are auxilliary functions for outputting CMake variables,
+# CMake lists and environment variables if the log level is ``DEBUG``:
+#
+# :ecbuild_debug_var: logs given CMake variables if log level <= ``DEBUG``
+# :ecbuild_debug_list: logs given CMake lists if log level <= ``DEBUG``
+# :ecbuild_debug_env_var: logs given environment variables if log level <= ``DEBUG``
+#
+# To log a message to the ecBuild log file only at a given log level, use ::
+#
+# ecbuild_log( <level> <msg> )
+#
+# Input variables
+# ---------------
+#
+# CMake variables controlling logging behaviour:
+#
+# ECBUILD_LOG_FILE : path
+# set the log file, defaults to ``${CMAKE_BINARY_DIR}/ecbuild.log``
+#
+# All ecBuild log functions write their messages to this log file with a time
+# stamp. Messages emitted by CMake directly cannot be logged to file.
+#
+# ECBUILD_LOG_LEVEL : string, one of DEBUG, INFO, WARN, ERROR, CRITICAL, OFF
+# desired log level, defaults to ``INFO``, ``OFF`` to disable logging
+#
+# ECBUILD_NO_COLOUR : bool
+# if set, does not colour log output (by default log output is coloured)
+#
+# ECBUILD_NO_DEPRECATIONS : bool
+# if set, does not output deprecation messages (only set this if you *really*
+# know what you are doing!)
+#
+# Usage
+# -----
+#
+# The functions ``ecbuild_debug`` and ``ecbuild_info`` can be used to output
+# messages which are not printed by default. Many ecBuild macros use this
+# facility to log debugging hints. When debugging a CMake run, users can use
+# ``-DECBUILD_LOG_LEVEL=DEBUG`` to get detailed diagnostics.
+#
+##############################################################################
+
+# Define colour escape sequences (https://stackoverflow.com/a/19578320/396967)
+if(NOT (WIN32 OR ECBUILD_NO_COLOUR))
+ string(ASCII 27 Esc)
+ set(ColourReset "${Esc}[m")
+ set(ColourBold "${Esc}[1m")
+ set(Red "${Esc}[31m")
+ set(Green "${Esc}[32m")
+ set(Yellow "${Esc}[33m")
+ set(Blue "${Esc}[34m")
+ set(Magenta "${Esc}[35m")
+ set(Cyan "${Esc}[36m")
+ set(White "${Esc}[37m")
+ set(BoldRed "${Esc}[1;31m")
+ set(BoldGreen "${Esc}[1;32m")
+ set(BoldYellow "${Esc}[1;33m")
+ set(BoldBlue "${Esc}[1;34m")
+ set(BoldMagenta "${Esc}[1;35m")
+ set(BoldCyan "${Esc}[1;36m")
+ set(BoldWhite "${Esc}[1;37m")
+endif()
+
+set(ECBUILD_DEBUG 10)
+set(ECBUILD_INFO 20)
+set(ECBUILD_WARN 30)
+set(ECBUILD_ERROR 40)
+set(ECBUILD_CRITICAL 50)
+
+if( NOT DEFINED ECBUILD_LOG_LEVEL )
+ set(ECBUILD_LOG_LEVEL ${ECBUILD_INFO})
+elseif( NOT ECBUILD_LOG_LEVEL )
+ set(ECBUILD_LOG_LEVEL 60)
+elseif( ECBUILD_LOG_LEVEL STREQUAL "DEBUG" )
+ set(ECBUILD_LOG_LEVEL ${ECBUILD_DEBUG})
+elseif( ECBUILD_LOG_LEVEL STREQUAL "INFO" )
+ set(ECBUILD_LOG_LEVEL ${ECBUILD_INFO})
+elseif( ECBUILD_LOG_LEVEL STREQUAL "WARN" )
+ set(ECBUILD_LOG_LEVEL ${ECBUILD_WARN})
+elseif( ECBUILD_LOG_LEVEL STREQUAL "ERROR" )
+ set(ECBUILD_LOG_LEVEL ${ECBUILD_ERROR})
+elseif( ECBUILD_LOG_LEVEL STREQUAL "CRITICAL" )
+ set(ECBUILD_LOG_LEVEL ${ECBUILD_CRITICAL})
+else()
+ message(WARNING "Unknown log level ${ECBUILD_LOG_LEVEL} (valid are DEBUG, INFO, WARN, ERROR, CRITICAL) - using WARN")
+ set(ECBUILD_LOG_LEVEL ${ECBUILD_WARN})
+endif()
+
+if( NOT DEFINED ECBUILD_LOG_FILE )
+ set( ECBUILD_LOG_FILE ${CMAKE_BINARY_DIR}/ecbuild.log )
+endif()
+
+##############################################################################
+
+function( ecbuild_log LEVEL )
+ string( REPLACE ";" " " MSG "${ARGN}" )
+ string( TIMESTAMP _time )
+ file( APPEND ${ECBUILD_LOG_FILE} "${_time} - ${LEVEL} - ${MSG}\n" )
+endfunction( ecbuild_log )
+
+##############################################################################
+
+function( ecbuild_debug )
+ string( REPLACE ";" " " MSG "${ARGV}" )
+ ecbuild_log(DEBUG "${MSG}")
+ if( ECBUILD_LOG_LEVEL LESS 11)
+ message(STATUS "${Blue}DEBUG - ${MSG}${ColourReset}")
+ endif()
+endfunction( ecbuild_debug )
+
+##############################################################################
+
+function( ecbuild_info )
+ string( REPLACE ";" " " MSG "${ARGV}" )
+ ecbuild_log(INFO "${MSG}")
+ if( ECBUILD_LOG_LEVEL LESS 21)
+ message(STATUS "${MSG}")
+ endif()
+endfunction( ecbuild_info )
+
+##############################################################################
+
+function( ecbuild_warn )
+ string( REPLACE ";" " " MSG "${ARGV}" )
+ ecbuild_log(WARNING "${MSG}")
+ if( ECBUILD_LOG_LEVEL LESS 31)
+ message(WARNING "${Yellow}WARN - ${MSG}${ColourReset}")
+ endif()
+endfunction( ecbuild_warn )
+
+##############################################################################
+
+function( ecbuild_error )
+ string( REPLACE ";" " " MSG "${ARGV}" )
+ ecbuild_log(ERROR "${MSG}")
+ if( ECBUILD_LOG_LEVEL LESS 41)
+ message(SEND_ERROR "${BoldRed}ERROR - ${MSG}${ColourReset}")
+ endif()
+endfunction( ecbuild_error )
+
+##############################################################################
+
+function( ecbuild_deprecate )
+ string(REPLACE ";" " " MSG ${ARGV})
+ ecbuild_log(DEPRECATION "${MSG}")
+ if( NOT ECBUILD_NO_DEPRECATIONS )
+ message(DEPRECATION "${BoldRed}${MSG}${ColourReset}")
+ endif()
+endfunction( ecbuild_deprecate )
+
+##############################################################################
+
+function( ecbuild_critical )
+ string(REPLACE ";" " " MSG ${ARGV})
+ ecbuild_log(FATAL_ERROR "${MSG}")
+ if( ECBUILD_LOG_LEVEL LESS 51)
+ message(FATAL_ERROR "${BoldMagenta}CRITICAL - ${MSG}${ColourReset}")
+ endif()
+endfunction( ecbuild_critical )
+
+##############################################################################
+# function for debugging CMake variables
+
+function( ecbuild_debug_var )
+ foreach( VAR ${ARGV} )
+ ecbuild_log(DEBUG "${VAR} : ${${VAR}}")
+ if( ECBUILD_LOG_LEVEL LESS 11)
+ message(STATUS "${Blue}DEBUG - ${VAR} : ${${VAR}}${ColourReset}")
+ endif()
+ endforeach()
+endfunction()
+
+##############################################################################
+# function for debugging CMake lists
+
+function( ecbuild_debug_list )
+ foreach( VAR ${ARGV} )
+ ecbuild_log(DEBUG "${VAR} : ${${VAR}}")
+ foreach( _elem ${${VAR}} )
+ ecbuild_log( DEBUG " ${_elem}" )
+ endforeach()
+ if( ECBUILD_LOG_LEVEL LESS 11)
+ message( STATUS "${Blue}DEBUG - ${VAR}" )
+ foreach( _elem ${${VAR}} )
+ message( STATUS " ${_elem}" )
+ endforeach()
+ message(STATUS "${ColourReset}")
+ endif()
+ endforeach()
+endfunction()
+
+##############################################################################
+# function for debugging environment variables
+
+function( ecbuild_debug_env_var )
+ foreach( VAR ${ARGV} )
+ ecbuild_log(DEBUG "ENV ${VAR} : $ENV{${VAR}}")
+ if( ECBUILD_LOG_LEVEL LESS 11)
+ message(STATUS "${Blue}DEBUG - ENV ${VAR} [$ENV{${VAR}}]${ColourReset}")
+ endif()
+ endforeach()
+endfunction()
+
+##############################################################################
+# macro for debugging a cmake variable
+
+macro( debug_var VAR )
+
+ message( WARNING "DEPRECATED debug_var() -- ${VAR} [${${VAR}}]" )
+
+endmacro()
+
+##############################################################################
+# macro for debugging a cmake list
+
+macro( debug_list VAR )
+
+ message( WARNING "DEPRECATED debug_list() -- ${VAR}:" )
+ foreach( _elem ${${VAR}} )
+ message( WARNING " ${_elem}" )
+ endforeach()
+
+endmacro()
+
+##############################################################################
+# macro for debugging a environment variable within cmake
+
+macro( debug_env_var VAR )
+
+ message( WARNING "DEPRECATED debug_env_var() -- ENV ${VAR} [$ENV{${VAR}}]" )
+
+endmacro()
diff --git a/cmake/ecbuild_pkgconfig.cmake b/cmake/ecbuild_pkgconfig.cmake
new file mode 100644
index 0000000..6f62977
--- /dev/null
+++ b/cmake/ecbuild_pkgconfig.cmake
@@ -0,0 +1,421 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+
+# Write transitive list of library dependencies of each library in ${libraries}
+# to CMake variable ${dependencies}
+function( ecbuild_library_dependencies dependencies libraries )
+
+ set( _libraries ${${libraries}} )
+
+ foreach( _lib ${_libraries})
+
+ unset( _location )
+
+ if( TARGET ${_lib} ) # check if this is an existing target
+
+ set( _imported 0 )
+ get_property( _imported TARGET ${_lib} PROPERTY IMPORTED )
+
+ unset( _deps )
+
+ if( _imported )
+
+ get_property( _location TARGET ${_lib} PROPERTY LOCATION )
+ get_property( _configs TARGET ${_lib} PROPERTY IMPORTED_CONFIGURATIONS )
+ list( REVERSE _configs )
+ list( GET _configs 0 _config)
+ get_property( _deps TARGET ${_lib} PROPERTY IMPORTED_LINK_INTERFACE_LIBRARIES_${_config} )
+ get_property( _locimp TARGET ${_lib} PROPERTY IMPORTED_LOCATION_${_config} )
+
+ else()
+
+ list( APPEND _location ${_lib} )
+ get_property( _deps TARGET ${_lib} PROPERTY LINK_LIBRARIES )
+
+ endif()
+
+ ecbuild_library_dependencies( _deps_location _deps )
+ list( APPEND _location ${_deps_location} )
+
+ else()
+
+ set( _location ${_lib} )
+
+ endif()
+
+ list( APPEND _dependencies ${_location} )
+
+ endforeach()
+
+ if( _dependencies )
+ list( REVERSE _dependencies )
+ list( REMOVE_DUPLICATES _dependencies )
+ list( REVERSE _dependencies )
+ set( ${dependencies} ${_dependencies} PARENT_SCOPE )
+ endif()
+
+endfunction(ecbuild_library_dependencies)
+
+##############################################################################
+
+# Write list of include directories of each library in ${libraries}
+# to CMake variable ${dependencies}
+function( ecbuild_include_dependencies dependencies libraries )
+
+ set( _libraries ${${libraries}} )
+
+ foreach( _lib ${_libraries})
+
+ if( TARGET ${_lib} ) # check if this is an existing target
+
+ get_property( _include_dirs TARGET ${_lib} PROPERTY INCLUDE_DIRECTORIES )
+ list( APPEND _dependencies ${_include_dirs} )
+
+ endif()
+
+ endforeach()
+
+ if( _dependencies )
+ list( REMOVE_DUPLICATES _dependencies )
+ set( ${dependencies} ${_dependencies} PARENT_SCOPE )
+ endif()
+
+endfunction(ecbuild_include_dependencies)
+
+##############################################################################
+
+# Transform list of libraries in ${libraries}, ignoring any in ${ignore_libs},
+# and write pkg-config compatible string to CMake variable ${pkgconfig_libs}
+function( ecbuild_pkgconfig_libs pkgconfig_libs libraries ignore_libs )
+
+ set( _libraries ${${libraries}} )
+ set( _ignore_libs ${${ignore_libs}} )
+
+ foreach( _lib ${_libraries} )
+
+ unset( _name )
+ unset( _dir )
+
+ if( ${_lib} MATCHES ".+/Frameworks/.+" )
+
+ get_filename_component( _name ${_lib} NAME_WE )
+ list( APPEND _pkgconfig_libs "-framework ${_name}" )
+
+ else()
+
+ if( ${_lib} MATCHES "-l.+" )
+
+ string( REGEX REPLACE "^-l" "" _name ${_lib} )
+
+ else()
+
+
+ get_filename_component( _name ${_lib} NAME_WE )
+ get_filename_component( _dir ${_lib} PATH )
+
+ if( TARGET ${_lib} )
+ get_target_property( _name ${_lib} OUTPUT_NAME )
+ endif()
+ if( NOT _name )
+ set( _name ${_lib} )
+ endif()
+
+ string( REGEX REPLACE "^lib" "" _name ${_name} )
+
+ if( "${_dir}" STREQUAL "/usr/lib" )
+ unset( _dir )
+ endif()
+ if( "${_dir}" STREQUAL "/usr/lib64" )
+ unset( _dir )
+ endif()
+
+ endif()
+
+ set( _set_append TRUE )
+ foreach( _ignore ${_ignore_libs} )
+ if( "${_name}" STREQUAL "${_ignore}" )
+ set( _set_append FALSE )
+ endif()
+ endforeach()
+
+ if( _set_append )
+
+ if( _dir )
+ list( APPEND _pkgconfig_libs "-L${_dir}" "-l${_name}" )
+ else()
+ list( APPEND _pkgconfig_libs "-l${_name}" )
+ endif()
+
+ endif()
+
+ endif( ${_lib} MATCHES ".+/Frameworks/.+" )
+
+ endforeach( _lib ${_libraries} )
+
+ if( _pkgconfig_libs )
+ list( REMOVE_DUPLICATES _pkgconfig_libs )
+ string( REPLACE ";" " " _pkgconfig_libs "${_pkgconfig_libs}" )
+
+ set( ${pkgconfig_libs} ${_pkgconfig_libs} PARENT_SCOPE )
+ endif()
+
+endfunction(ecbuild_pkgconfig_libs)
+
+##############################################################################
+
+# Transform list of include directories in ${INCLUDE_DIRS}, ignoring any in
+# ${ignore_includes} and ${${PNAME}_INCLUDE_DIRS}, and write pkg-config
+# compatible string to CMake variable ${INCLUDE}
+function( ecbuild_pkgconfig_include INCLUDE INCLUDE_DIRS ignore_includes )
+
+ string( TOUPPER ${PROJECT_NAME} PNAME )
+
+ set( _ignore_includes ${${ignore_includes}} )
+
+ list( APPEND ignore_include_dirs
+ "/usr/include"
+ ${${PNAME}_INCLUDE_DIRS} # These are build-directory includes
+ ${CMAKE_SOURCE_DIR} # Ignore private includes referencing source tree
+ ${CMAKE_BINARY_DIR} # Ignore private includes referencing build tree
+ ${_ignore_includes}
+ )
+
+ foreach( _incdir ${${INCLUDE_DIRS}} )
+
+ foreach( _ignore ${ignore_include_dirs} )
+ if( "${_incdir}" MATCHES "${_ignore}" )
+ unset( _incdir )
+ break()
+ endif()
+ endforeach()
+
+ if( _incdir )
+ list( APPEND _include "-I${_incdir}")
+ endif()
+
+ endforeach()
+
+ if( _include )
+ list( REMOVE_DUPLICATES _include)
+ string( REPLACE ";" " " _include "${_include}")
+ set( ${INCLUDE} ${_include} PARENT_SCOPE )
+ endif()
+
+endfunction(ecbuild_pkgconfig_include)
+
+##############################################################################
+#.rst:
+#
+# ecbuild_pkgconfig
+# =================
+#
+# Create a pkg-config file for the current project. ::
+#
+# ecbuild_pkgconfig( [ NAME <name> ]
+# [ FILENAME <filename> ]
+# [ TEMPLATE <template> ]
+# [ URL <url> ]
+# [ DESCRIPTION <description> ]
+# [ LIBRARIES <lib1> [ <lib2> ... ] ]
+# [ IGNORE_INCLUDE_DIRS <dir1> [ <dir2> ... ] ]
+# [ IGNORE_LIBRARIES <lib1> [ <lib2> ... ] ]
+# [ LANGUAGES <language1> [ <language2> ... ] ]
+# [ VARIABLES <variable1> [ <variable2> ... ] ]
+# [ NO_PRIVATE_INCLUDE_DIRS ] )
+#
+# Options
+# -------
+#
+# NAME : optional, defaults to lower case name of the project
+# name to be given to the package
+#
+# FILENAME : optional, defaults to ``<NAME>.pc``
+# file to be generated, including .pc extension
+#
+# TEMPLATE : optional, defaults to ``${ECBUILD_CMAKE_DIR}/pkg-config.pc.in``
+# template configuration file to use
+#
+# This is useful to create customised pkg-config files.
+#
+# URL : optional, defaults to ``${UPPERCASE_PROJECT_NAME}_URL``
+# url of the package
+#
+# DESCRIPTION : optional, defaults to ``${UPPERCASE_PROJECT_NAME}_DESCRIPTION``
+# description of the package
+#
+# LIBRARIES : optional, defaults to ``${UPPERCASE_PROJECT_NAME}_LIBRARIES``
+# list of package libraries
+#
+# IGNORE_INCLUDE_DIRS : optional
+# list of include directories to ignore
+#
+# IGNORE_LIBRARIES : optional
+# list of libraries to ignore i.e. those are removed from ``LIBRARIES``
+#
+# VARIABLES : optional
+# list of additional CMake variables to export to the pkg-config file
+#
+# LANGUAGES : optional, defaults to all loaded languages
+# list of languages to use. Accepted languages: C CXX Fortran
+#
+# NO_PRIVATE_INCLUDE_DIRS
+# do not add include directories of dependencies to Cflags
+#
+# This is mainly useful for Fortran only packages, when only modules need
+# to be added to Cflags.
+#
+# Input variables
+# ---------------
+#
+# The following CMake variables are used as default values for some of the
+# options listed above, where ``PNAME`` is the project name in upper case: ::
+#
+# :<PNAME>_LIBRARIES: list of libraries to export
+# :<PNAME>_DESCRIPTION: package description
+# :<PNAME>_URL: package URL
+# :<PNAME>_VERSION: package version
+# :<PNAME>_GIT_SHA1: Git revision
+#
+# Usage
+# -----
+#
+# It is good practice to provide a separate pkg-config file for each library a
+# package exports. This can be achieved as follows: ::
+#
+# foreach( _lib ${${PNAME}_LIBRARIES} )
+# if( TARGET ${_lib} )
+# ecbuild_pkgconfig( NAME ${_lib}
+# DESCRIPTION "..."
+# URL "..."
+# LIBRARIES ${_lib} )
+# endif()
+# endforeach()
+#
+##############################################################################
+
+function( ecbuild_pkgconfig )
+
+ set( options REQUIRES NO_PRIVATE_INCLUDE_DIRS )
+ set( single_value_args FILENAME NAME TEMPLATE URL DESCRIPTION )
+ set( multi_value_args LIBRARIES IGNORE_INCLUDE_DIRS IGNORE_LIBRARIES VARIABLES LANGUAGES )
+
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ string( TOUPPER ${PROJECT_NAME} PNAME )
+ string( TOLOWER ${PROJECT_NAME} LNAME )
+
+ if(_PAR_UNPARSED_ARGUMENTS)
+ ecbuild_critical("Unknown keywords given to ecbuild_add_executable(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ unset( PKGCONFIG_LANGUAGES )
+ if( NOT _PAR_LANGUAGES )
+ if( CMAKE_C_COMPILER_LOADED )
+ list( APPEND PKGCONFIG_LANGUAGES C )
+ endif()
+ if( CMAKE_CXX_COMPILER_LOADED )
+ list( APPEND PKGCONFIG_LANGUAGES CXX )
+ endif()
+ if( CMAKE_Fortran_COMPILER_LOADED )
+ list( APPEND PKGCONFIG_LANGUAGES Fortran )
+ endif()
+ else()
+ foreach( _lang ${_PAR_LANGUAGES} )
+ if( CMAKE_${_lang}_COMPILER_LOADED )
+ list( APPEND PKGCONFIG_LANGUAGES ${_lang} )
+ endif()
+ endforeach()
+ endif()
+
+ foreach( _lang ${PKGCONFIG_LANGUAGES} )
+ set( PKGCONFIG_HAVE_${_lang} 1 )
+ endforeach()
+
+ set( LIBRARIES ${${PNAME}_LIBRARIES} )
+ if( _PAR_LIBRARIES )
+ set( LIBRARIES ${_PAR_LIBRARIES} )
+ endif()
+
+ if( CMAKE_CXX_COMPILER_LOADED )
+ set( _linker_lang CXX )
+ elseif( CMAKE_C_COMPILER_LOADED )
+ set( _linker_lang C )
+ elseif( CMAKE_Fortran_COMPILER_LOADED )
+ set( _linker_lang Fortran )
+ endif()
+
+ set( RPATH_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_${_linker_lang}_FLAG} )
+
+ set( PKGCONFIG_MOD_FLAG ${CMAKE_Fortran_MODPATH_FLAG} )
+
+ if( NOT PKGCONFIG_MOD_FLAG )
+ set( PKGCONFIG_MOD_FLAG "-I" )
+ endif()
+
+ ecbuild_pkgconfig_libs( PKGCONFIG_LIBS LIBRARIES _PAR_IGNORE_LIBRARIES )
+
+ ecbuild_library_dependencies( _libraries LIBRARIES )
+ foreach( _lib ${LIBRARIES} )
+ list( REMOVE_ITEM _libraries ${_lib} )
+ endforeach()
+
+ ecbuild_pkgconfig_libs( PKGCONFIG_LIBS_PRIVATE _libraries _PAR_IGNORE_LIBRARIES )
+
+ if( NOT _PAR_NO_PRIVATE_INCLUDE_DIRS )
+ ecbuild_include_dependencies( _include_dirs LIBRARIES )
+ ecbuild_pkgconfig_include( PKGCONFIG_CFLAGS _include_dirs _PAR_IGNORE_INCLUDE_DIRS )
+ endif()
+
+ set( PKGCONFIG_INCLUDE "-I\${includedir}" )
+ if( PKGCONFIG_HAVE_Fortran )
+ set( PKGCONFIG_INCLUDE "${PKGCONFIG_INCLUDE} ${PKGCONFIG_MOD_FLAG}\${fmoddir}" )
+ endif()
+
+ if( NOT _PAR_TEMPLATE )
+ set( _PAR_TEMPLATE "${ECBUILD_MACROS_DIR}/pkg-config.pc.in" )
+ endif()
+
+ set( PKGCONFIG_NAME ${LNAME} )
+ if( _PAR_NAME )
+ set( PKGCONFIG_NAME ${_PAR_NAME} )
+ endif()
+
+ if( NOT _PAR_FILENAME )
+ set( _PAR_FILENAME "${PKGCONFIG_NAME}.pc" )
+ endif()
+
+ set( PKGCONFIG_DESCRIPTION ${${PNAME}_DESCRIPTION} )
+ if( _PAR_DESCRIPTION )
+ set( PKGCONFIG_DESCRIPTION ${_PAR_DESCRIPTION} )
+ endif()
+
+ set( PKGCONFIG_URL ${${PNAME}_URL} )
+ if( _PAR_URL )
+ set( PKGCONFIG_URL ${_PAR_URL} )
+ endif()
+
+ set( PKGCONFIG_VERSION ${${PNAME}_VERSION} )
+ set( PKGCONFIG_GIT_TAG ${${PNAME}_GIT_SHA1} ) # For now set it to a commit id
+
+ if( _PAR_VARIABLES )
+ set( PKGCONFIG_VARIABLES "\n### Features:\n\n")
+ foreach( _var ${_PAR_VARIABLES} )
+ set( PKGCONFIG_VARIABLES "${PKGCONFIG_VARIABLES}${_var}=${${_var}}\n" )
+ endforeach()
+ endif()
+
+ configure_file( ${_PAR_TEMPLATE} "${CMAKE_BINARY_DIR}/${_PAR_FILENAME}" @ONLY )
+ ecbuild_info( "pkg-config file created: ${_PAR_FILENAME}" )
+
+ install( FILES ${CMAKE_BINARY_DIR}/${_PAR_FILENAME}
+ DESTINATION ${CMAKE_INSTALL_PREFIX}/${INSTALL_LIB_DIR}/pkgconfig/
+ COMPONENT utilities )
+
+endfunction(ecbuild_pkgconfig)
diff --git a/cmake/ecbuild_policies.cmake b/cmake/ecbuild_policies.cmake
new file mode 100644
index 0000000..36ab7fe
--- /dev/null
+++ b/cmake/ecbuild_policies.cmake
@@ -0,0 +1,67 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+##############################################################################
+#
+# ecBuild Policies
+# ================
+#
+# NOTE: This file needs to be included with NO_POLICY_SCOPE or it will have no
+# effect!
+# NOTE: Policies 1 through 17 will be set to NEW by requiring CMake 2.8.4 i.e.
+# calling cmake_minimum_required( VERSION 2.8.4 FATAL_ERROR )
+#
+##############################################################################
+
+# allow for empty spaces around library names
+if( POLICY CMP0004 )
+ cmake_policy( SET CMP0004 OLD )
+endif()
+
+# Allow use of the LOCATION target property.
+if( POLICY CMP0026 )
+ cmake_policy( SET CMP0026 OLD )
+endif()
+
+# for macosx use @rpath in a target’s install name
+if( POLICY CMP0042 )
+ cmake_policy( SET CMP0042 NEW )
+ set( CMAKE_MACOSX_RPATH ON )
+endif()
+
+# Error on non-existent target in get_target_property
+if( POLICY CMP0045 )
+ cmake_policy( SET CMP0045 NEW )
+endif()
+
+# Error on non-existent dependency in add_dependencies
+if( POLICY CMP0046 )
+ cmake_policy( SET CMP0046 NEW )
+endif()
+
+# Do not manage VERSION variables in project command
+if( POLICY CMP0048 )
+ cmake_policy( SET CMP0048 OLD )
+endif()
+
+# Disallow add_custom_command SOURCE signatures
+if( POLICY CMP0050 )
+ cmake_policy( SET CMP0050 NEW )
+endif()
+
+# Reject source and build dirs in installed INTERFACE_INCLUDE_DIRECTORIES
+if( POLICY CMP0052 )
+ cmake_policy( SET CMP0052 NEW )
+endif()
+
+# inside if() don't dereference variables if they are quoted
+# e.g. "VAR" is not dereferenced
+# "${VAR}" is dereference only once
+if( POLICY CMP0054 )
+ cmake_policy( SET CMP0054 NEW )
+endif()
diff --git a/cmake/ecbuild_print_summary.cmake b/cmake/ecbuild_print_summary.cmake
new file mode 100644
index 0000000..4cf05cc
--- /dev/null
+++ b/cmake/ecbuild_print_summary.cmake
@@ -0,0 +1,104 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_print_summary
+# =====================
+#
+# Print a summary of the project, build environment and enabled features. ::
+#
+# ecbuild_print_summary()
+#
+# If ``project_summary.cmake`` exist in the source root directory, a project
+# summary is printed by including this file.
+#
+# For a top level project, a summary of the build environment and a feature
+# summary are also printed.
+#
+##############################################################################
+
+macro( ecbuild_print_summary )
+
+ if( EXISTS ${PROJECT_SOURCE_DIR}/project_summary.cmake )
+
+ ecbuild_info( "---------------------------------------------------------" )
+ ecbuild_info( "Project ${PROJECT_NAME} summary" )
+ ecbuild_info( "---------------------------------------------------------" )
+
+ include( ${PROJECT_SOURCE_DIR}/project_summary.cmake )
+
+ endif()
+
+ if( PROJECT_NAME STREQUAL CMAKE_PROJECT_NAME )
+
+ get_property( langs GLOBAL PROPERTY ENABLED_LANGUAGES )
+
+ ecbuild_info( "---------------------------------------------------------" )
+ if( NOT ${DEVELOPER_MODE} )
+ ecbuild_info( "Build summary" )
+ else()
+ ecbuild_info( "Build summary -- ( DEVELOPER_MODE )" )
+ endif()
+ ecbuild_info( "---------------------------------------------------------" )
+
+ ecbuild_info( "system : [${BUILD_SITE}] [${CMAKE_SYSTEM}] [${EC_OS_NAME}.${EC_OS_BITS}]" )
+ ecbuild_info( "processor : [${CMAKE_SYSTEM_PROCESSOR}]" )
+ if( EC_BIG_ENDIAN )
+ ecbuild_info( "endiness : Big Endian -- IEEE [${IEEE_BE}]" )
+ endif()
+ if( EC_LITTLE_ENDIAN )
+ ecbuild_info( "endiness : Little Endian -- IEEE [${IEEE_LE}]" )
+ endif()
+ ecbuild_info( "build type : [${CMAKE_BUILD_TYPE}]" )
+ ecbuild_info( "timestamp : [${EC_BUILD_TIMESTAMP}]" )
+ ecbuild_info( "install prefix : [${CMAKE_INSTALL_PREFIX}]" )
+ if( EC_LINK_DIR )
+ ecbuild_info( "links prefix : [${EC_LINK_DIR}]" )
+ endif()
+ ecbuild_info( "---------------------------------------------------------" )
+
+ foreach( lang ${langs} )
+ ecbuild_info( "${lang} -- ${CMAKE_${lang}_COMPILER_ID} ${CMAKE_${lang}_COMPILER_VERSION}" )
+ ecbuild_info( " compiler : ${CMAKE_${lang}_COMPILER} ${CMAKE_${lang}_FLAGS} ${CMAKE_${lang}_FLAGS_${CMAKE_BUILD_TYPE_CAPS}}" )
+ ecbuild_info( " link flags : ${CMAKE_${lang}_LINK_FLAGS}" )
+ endforeach()
+
+ ecbuild_info( "linker : ${CMAKE_LINKER}")
+ ecbuild_info( "ar : ${CMAKE_AR}")
+ ecbuild_info( "ranlib : ${CMAKE_RANLIB}")
+ ecbuild_info( "link flags" )
+ ecbuild_info( " executable [${CMAKE_EXE_LINKER_FLAGS} ${CMAKE_EXE_LINKER_FLAGS_${CMAKE_BUILD_TYPE_CAPS}}]" )
+ ecbuild_info( " shared lib [${CMAKE_SHARED_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS_${CMAKE_BUILD_TYPE_CAPS}}]" )
+ ecbuild_info( " static lib [${CMAKE_MODULE_LINKER_FLAGS} ${CMAKE_MODULE_LINKER_FLAGS_${CMAKE_BUILD_TYPE_CAPS}}]" )
+ ecbuild_info( "install rpath : ${CMAKE_INSTALL_RPATH}" )
+
+ get_directory_property( defs COMPILE_DEFINITIONS )
+
+ ecbuild_info( "common definitions: ${defs}" )
+
+ ecbuild_info( "---------------------------------------------------------" )
+
+ ### FEATURE SUMMARY
+
+ # ecbuild_debug_var( CMAKE_VERSION )
+ if( ${CMAKE_VERSION} VERSION_LESS "2.8.6" )
+ feature_summary( WHAT ALL )
+ else()
+ feature_summary( WHAT ALL INCLUDE_QUIET_PACKAGES )
+ endif()
+
+ ### WARNINGS
+
+ # issue warnings / errors in case there are unused project files
+ ecbuild_warn_unused_files()
+
+ endif()
+
+endmacro( ecbuild_print_summary )
diff --git a/cmake/ecbuild_project_files.cmake b/cmake/ecbuild_project_files.cmake
new file mode 100644
index 0000000..3e4b3d2
--- /dev/null
+++ b/cmake/ecbuild_project_files.cmake
@@ -0,0 +1,75 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+# resert the variable on each configure
+set( EC_UNUSED_FILES "" CACHE INTERNAL "unused files" )
+
+##############################################################################
+# finds project files and adds them to the passed variable
+
+macro( ecbuild_find_files_recursive aFileList )
+
+list( APPEND ecbuild_project_extensions c cc cpp cxx ) # for the moment skip ( h hh )
+
+foreach( aExt ${ecbuild_project_extensions} )
+ set( globPatterns ${globPatterns} *.${aExt} )
+endforeach()
+
+# This globs for only one pattern at a time
+# Shell extglob patterns are unfortunately not supported.
+file( GLOB_RECURSE ${aFileList} ${globPatterns} )
+
+endmacro()
+
+##############################################################################
+# finds the unused files on all the project
+function( ecbuild_find_project_files )
+
+ # Only do this if we actually care to warn about unused files
+ if( CHECK_UNUSED_FILES )
+ ecbuild_find_files_recursive( cwdFiles )
+
+ # this list will be kept
+ set( EC_PROJECT_FILES ${EC_PROJECT_FILES} ${cwdFiles} CACHE INTERNAL "" )
+ # this list will be progressevely emptied
+ set( EC_UNUSED_FILES ${EC_UNUSED_FILES} ${cwdFiles} CACHE INTERNAL "" )
+ endif()
+
+endfunction()
+
+##############################################################################
+# removed used files from unused list
+macro( ecbuild_declare_project_files )
+
+ # Only do this if we actually care to warn about unused files
+ if( CHECK_UNUSED_FILES )
+ foreach( _afile ${ARGV} )
+
+ # ecbuild_debug_var( _afile )
+
+ get_property( _src_gen SOURCE ${_afile} PROPERTY GENERATED )
+
+ if( NOT _src_gen )
+
+ get_filename_component( _abspath ${_afile} ABSOLUTE )
+
+ # check for existance of all declared files
+ if( EXISTS ${_abspath} )
+ list( REMOVE_ITEM EC_UNUSED_FILES ${_abspath} )
+ else()
+ ecbuild_critical( "In directory ${CMAKE_CURRENT_SOURCE_DIR} file ${_afile} was declared in CMakeLists.txt but not found" )
+ endif()
+ endif()
+
+ endforeach()
+
+ # rewrite the unused file list in cache
+ set( EC_UNUSED_FILES ${EC_UNUSED_FILES} CACHE INTERNAL "unused files" )
+ endif()
+
+endmacro()
diff --git a/cmake/ecbuild_remove_fortran_flags.cmake b/cmake/ecbuild_remove_fortran_flags.cmake
new file mode 100644
index 0000000..74c8832
--- /dev/null
+++ b/cmake/ecbuild_remove_fortran_flags.cmake
@@ -0,0 +1,61 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_remove_fortran_flags
+# =========================
+#
+# Remove Fortran compiler flags from CMAKE_Fortran_FLAGS. ::
+#
+# ecbuild_remove_fortran_flags( <flag1> [ <flag2> ... ] [ BUILD <build> ] )
+#
+# Options
+# -------
+#
+# BUILD : optional
+# remove flags from ``CMAKE_Fortran_FLAGS_<build>`` instead of
+# ``CMAKE_Fortran_FLAGS``
+#
+##############################################################################
+
+include( CheckFortranCompilerFlag )
+macro( ecbuild_remove_fortran_flags m_flags )
+
+ set( _flags ${m_flags} )
+ if( _flags AND CMAKE_Fortran_COMPILER_LOADED )
+
+ set( single_value_args BUILD )
+ set( multi_value_args )
+ cmake_parse_arguments( _PAR "" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ string( TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_CAPS )
+ string( TOUPPER ${_PAR_BUILD} _PAR_BUILD_CAPS )
+
+ if( _PAR_BUILD AND (CMAKE_BUILD_TYPE_CAPS MATCHES "${_PAR_BUILD_CAPS}") )
+
+ foreach( _flag ${_flags} )
+ string(REGEX REPLACE " *${_flag} *" " " CMAKE_Fortran_FLAGS_${_PAR_BUILD} ${CMAKE_Fortran_FLAGS_${_PAR_BUILD}})
+ ecbuild_debug( "Fortran FLAG [${_flag}] removed from build type ${_PAR_BUILD}" )
+ endforeach()
+
+ elseif( NOT _PAR_BUILD )
+
+ foreach( _flag ${_flags} )
+ string(REGEX REPLACE " *${_flag} *" " " CMAKE_Fortran_FLAGS ${CMAKE_Fortran_FLAGS} )
+ ecbuild_debug( "Fortran FLAG [${_flag}] removed" )
+ endforeach()
+
+ endif()
+
+ endif()
+ unset( _flags )
+
+endmacro()
+
diff --git a/cmake/ecbuild_requires_macro_version.cmake b/cmake/ecbuild_requires_macro_version.cmake
new file mode 100644
index 0000000..1603446
--- /dev/null
+++ b/cmake/ecbuild_requires_macro_version.cmake
@@ -0,0 +1,27 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_requires_macro_version
+# ==============================
+#
+# Check that the ecBuild version satisfied a given minimum version or fail. ::
+#
+# ecbuild_requires_macro_version( <minimum-version> )
+#
+##############################################################################
+
+macro( ecbuild_requires_macro_version req_vrs )
+
+ if( ECBUILD_MACRO_VERSION VERSION_LESS ${req_vrs} )
+ ecbuild_critical( "${PROJECT_NAME} needs ecbuild macro version >= ${req_vrs}" )
+ endif()
+
+endmacro()
diff --git a/cmake/ecbuild_separate_sources.cmake b/cmake/ecbuild_separate_sources.cmake
new file mode 100644
index 0000000..b56db63
--- /dev/null
+++ b/cmake/ecbuild_separate_sources.cmake
@@ -0,0 +1,91 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_separate_sources
+# ========================
+#
+# Separate a given list of sources according to language. ::
+#
+# ecbuild_separate_sources( TARGET <name>
+# SOURCES <source1> [ <source2> ... ] )
+#
+# Options
+# -------
+#
+# TARGET : required
+# base name for the CMake output variables to set
+#
+# SOURCES : required
+# list of source files to separate
+#
+# Output variables
+# ----------------
+#
+# If any file of the following group of extensions is present in the list of
+# sources, the corresponding CMake variable is set:
+#
+# :<target>_h_srcs: list of sources with extension .h, .hxx, .hh, .hpp, .H
+# :<target>_c_srcs: list of sources with extension .c
+# :<target>_cxx_srcs: list of sources with extension .cc, .cxx, .cpp, .C
+# :<target>_f_srcs: list of sources with extension .f, .F, .for, f77, .f90, .f95
+#
+##############################################################################
+
+macro( ecbuild_separate_sources )
+
+ set( options )
+ set( single_value_args TARGET )
+ set( multi_value_args SOURCES )
+
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_PAR_UNPARSED_ARGUMENTS)
+ ecbuild_critical("Unknown keywords given to ecbuild_separate_sources(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if( NOT _PAR_TARGET )
+ ecbuild_critical("The call to ecbuild_separate_sources() doesn't specify the TARGET.")
+ endif()
+
+ if( NOT _PAR_SOURCES )
+ ecbuild_critical("The call to ecbuild_separate_sources() doesn't specify the SOURCES.")
+ endif()
+
+ foreach( src ${_PAR_SOURCES} )
+ if(${src} MATCHES "(\\.h|\\.hxx|\\.hh|\\.hpp|\\.H)")
+ list( APPEND ${_PAR_TARGET}_h_srcs ${src} )
+ endif()
+ endforeach()
+
+ foreach( src ${_PAR_SOURCES} )
+ if(${src} MATCHES "(\\.c)")
+ list( APPEND ${_PAR_TARGET}_c_srcs ${src} )
+ endif()
+ endforeach()
+
+ foreach( src ${_PAR_SOURCES} )
+ if(${src} MATCHES "(\\.cc|\\.cxx|\\.cpp|\\.C)")
+ list( APPEND ${_PAR_TARGET}_cxx_srcs ${src} )
+ endif()
+ endforeach()
+
+ foreach( src ${_PAR_SOURCES} )
+ if(${src} MATCHES "(\\.f|\\.F|\\.for|\\.f77|\\.f90|\\.f95)")
+ list( APPEND ${_PAR_TARGET}_f_srcs ${src} )
+ endif()
+ endforeach()
+
+# ecbuild_debug_var( ${_PAR_TARGET}_h_srcs )
+# ecbuild_debug_var( ${_PAR_TARGET}_c_srcs )
+# ecbuild_debug_var( ${_PAR_TARGET}_cxx_srcs )
+# ecbuild_debug_var( ${_PAR_TARGET}_f_srcs )
+
+endmacro( ecbuild_separate_sources )
diff --git a/cmake/ecbuild_setup_test_framework.cmake b/cmake/ecbuild_setup_test_framework.cmake
new file mode 100644
index 0000000..c14b2f9
--- /dev/null
+++ b/cmake/ecbuild_setup_test_framework.cmake
@@ -0,0 +1,45 @@
+ecbuild_add_option( FEATURE TESTS
+ DEFAULT ON
+ DESCRIPTION "Enable the unit tests" )
+
+if( ENABLE_TESTS AND CMAKE_CXX_COMPILER_LOADED )
+
+ # Try to find compiled boost
+
+ # BOOST_ROOT or BOOSTROOT should take precedence on the search for location
+ if( BOOST_ROOT OR BOOSTROOT OR DEFINED ENV{BOOST_ROOT} OR DEFINED ENV{BOOSTROOT} )
+ set( CMAKE_PREFIX_PATH ${BOOST_ROOT} ${BOOSTROOT} $ENV{BOOST_ROOT} $ENV{BOOSTROOT} ${CMAKE_PREFIX_PATH} )
+ endif()
+
+ set( Boost_USE_MULTITHREADED ON )
+ # set( Boost_DEBUG ON )
+
+ find_package( Boost 1.47.0 COMPONENTS unit_test_framework )
+
+ set( ECBUILD_BOOST_HEADER_DIRS "${CMAKE_CURRENT_LIST_DIR}/include" )
+
+ if( Boost_FOUND AND Boost_UNIT_TEST_FRAMEWORK_LIBRARY )
+
+ set( HAVE_BOOST_UNIT_TEST 1 )
+ set( BOOST_UNIT_TEST_FRAMEWORK_LINKED 1 )
+
+ ecbuild_info( "Using Boost for unit tests:\n INC [${Boost_INCLUDE_DIRS}]\n LIB [${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}]" )
+
+ else()
+
+ ecbuild_info( "Boost unit test framework -- NOT FOUND" )
+
+ set( HAVE_BOOST_UNIT_TEST 0 )
+
+ # set( BOOST_UNIT_TEST_FRAMEWORK_HEADER_ONLY 1 )
+ # comment out this when ecbuild packs boost unit test inside...
+ # list( APPEND ECBUILD_BOOST_HEADER_DIRS "${CMAKE_CURRENT_LIST_DIR}/contrib/boost-1.55/include" )
+ # set( HAVE_BOOST_UNIT_TEST 1 )
+
+ endif()
+
+endif()
+
+if( NOT ENABLE_TESTS )
+ ecbuild_info("Tests have been disabled")
+endif()
diff --git a/cmake/ecbuild_source_flags.cmake b/cmake/ecbuild_source_flags.cmake
new file mode 100644
index 0000000..2414765
--- /dev/null
+++ b/cmake/ecbuild_source_flags.cmake
@@ -0,0 +1,30 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+set( __gen_source_flags ${CMAKE_CURRENT_LIST_DIR}/gen_source_flags.py )
+
+# Calls gen_source_flags.py to generate a CMake file with the per
+# source file flags for a given target.
+function( ecbuild_source_flags OUT TARGET DEFAULT_FLAGS SOURCES )
+
+ if( NOT PYTHONINTERP_FOUND OR PYTHON_VERSION VERSION_LESS 2.7 )
+ find_package( PythonInterp 2.7 REQUIRED )
+ endif()
+
+ set( OUTFILE ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_source_flags.cmake )
+
+ if( ECBUILD_LOG_LEVEL LESS 11)
+ set( __debug "--debug" )
+ endif()
+ execute_process( COMMAND ${PYTHON_EXECUTABLE} ${__gen_source_flags}
+ ${ECBUILD_SOURCE_FLAGS} ${OUTFILE} "${DEFAULT_FLAGS}"
+ ${SOURCES} "${__debug}" )
+
+ set( ${OUT} ${OUTFILE} PARENT_SCOPE )
+
+endfunction()
diff --git a/cmake/ecbuild_system.cmake b/cmake/ecbuild_system.cmake
new file mode 100644
index 0000000..a4361f7
--- /dev/null
+++ b/cmake/ecbuild_system.cmake
@@ -0,0 +1,266 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+########################################################################################################
+# disallow in-source build
+
+if( EXISTS ${CMAKE_SOURCE_DIR}/CMakeCache.txt ) # check for failed attempts to build within the source tree
+ message( FATAL_ERROR "Project ${PROJECT_NAME} contains a CMakeCache.txt inside source tree [${CMAKE_SOURCE_DIR}/CMakeCache.txt].\n Please remove it and
+ make sure that source tree is prestine and clean of unintended files, before retrying." )
+endif()
+
+get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH)
+get_filename_component(bindir "${CMAKE_BINARY_DIR}" REALPATH)
+
+if(${srcdir} STREQUAL ${bindir})
+ message("######################################################")
+ message("You are attempting to build in your source directory (${srcdir}).")
+ message("You must run cmake from a different build directory.")
+ message("######################################################")
+ message( FATAL_ERROR "${PROJECT_NAME} requires an out of source build.\n Please create a separate build directory and run 'cmake path/to/project [options]' from there.")
+endif()
+
+########################################################################################################
+# ecbuild versioning support
+
+set( ECBUILD_CMAKE_MINIMUM "2.8.10" )
+if( ${CMAKE_VERSION} VERSION_LESS ${ECBUILD_CMAKE_MINIMUM} )
+ message(FATAL_ERROR "${PROJECT_NAME} requires at least CMake ${ECBUILD_CMAKE_MINIMUM} -- you are using ${CMAKE_COMMAND} [${CMAKE_VERSION}]\n Please, get a newer version of CMake @ www.cmake.org" )
+endif()
+
+set( ECBUILD_MACROS_DIR "${CMAKE_CURRENT_LIST_DIR}" CACHE INTERNAL "where ecbuild system is" )
+
+include( "${ECBUILD_MACROS_DIR}/VERSION.cmake" )
+
+set( ecbuild_VERSION_STR "${ECBUILD_VERSION_STR}" )
+
+# Set policies
+include( ecbuild_policies NO_POLICY_SCOPE )
+
+# set capitalised project name
+
+string( TOUPPER ${PROJECT_NAME} PROJECT_NAME_CAPS )
+string( TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWCASE )
+
+########################################################################################################
+# include our cmake macros, but only do so if this is the top project
+if( PROJECT_NAME STREQUAL CMAKE_PROJECT_NAME )
+
+ # hostname of where we build
+
+ site_name( BUILD_SITE )
+ mark_as_advanced( BUILD_SITE )
+ mark_as_advanced( BUILD_TESTING )
+
+ set( ECBUILD_PROJECTS "" CACHE INTERNAL "list of ecbuild (sub)projects that use ecbuild" )
+
+ # Include log macros since these are used right away
+ include( ecbuild_log )
+
+ ecbuild_info( "ecbuild ${ecbuild_VERSION_STR}\t${ECBUILD_MACROS_DIR}" )
+ ecbuild_info( "cmake ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}\t${CMAKE_COMMAND}" )
+
+ if( CMAKE_TOOLCHAIN_FILE )
+ ecbuild_info( "toolchain ${CMAKE_TOOLCHAIN_FILE}" )
+ endif()
+
+ if( ECBUILD_CONFIG )
+ ecbuild_info( "config ${ECBUILD_CONFIG}" )
+ endif()
+
+ if( ECBUILD_CACHE )
+ include( ${ECBUILD_CACHE} )
+ ecbuild_info( "cache ${ECBUILD_CACHE}" )
+ endif()
+
+ message( STATUS "---------------------------------------------------------" )
+
+ # clear the build dir exported targets file (only on the top project)
+
+ set( TOP_PROJECT_TARGETS_FILE "${PROJECT_BINARY_DIR}/${CMAKE_PROJECT_NAME}-targets.cmake" CACHE INTERNAL "" )
+ file( REMOVE ${TOP_PROJECT_TARGETS_FILE} )
+
+ # add backport support for versions up too 2.8.4
+ if( ${CMAKE_VERSION} VERSION_LESS "2.8" )
+ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/2.8" ${CMAKE_MODULE_PATH} )
+ endif()
+
+ # add extra macros from external contributions
+ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/contrib" )
+
+ # would bring FindEigen in, so for the moment keep it out
+ # set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/contrib/GreatCMakeCookOff" )
+
+ include(CTest) # add cmake testing support
+ enable_testing()
+
+ # keep this until we modify the meaning to 'check' if installation worked
+ add_custom_target( check COMMAND ${CMAKE_CTEST_COMMAND} )
+
+ ############################################################################################
+ # define valid build types
+
+ include(ecbuild_define_build_types)
+
+ ############################################################################################
+ # add cmake macros
+
+ include(AddFileDependencies)
+
+ include(CheckTypeSize)
+ include(CheckIncludeFile)
+ include(CheckIncludeFiles)
+
+ include(CheckFunctionExists)
+ include(CheckSymbolExists)
+
+ include(CheckCCompilerFlag)
+ include(CheckCSourceCompiles)
+ include(CheckCSourceRuns)
+
+ include(CMakeParseArguments)
+
+ # include(CMakePrintSystemInformation) # available in cmake 2.8.4
+
+ if( CMAKE_CXX_COMPILER_LOADED )
+ include(CheckIncludeFileCXX)
+ include(CheckCXXCompilerFlag)
+ include(CheckCXXSourceCompiles)
+ include(CheckCXXSourceRuns)
+ endif()
+
+ if( CMAKE_Fortran_COMPILER_LOADED )
+ set( CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/module CACHE PATH "directory for all fortran modules." )
+ include(CheckFortranFunctionExists)
+ if( CMAKE_C_COMPILER_LOADED AND ENABLE_FORTRAN_C_INTERFACE )
+ include(FortranCInterface)
+ endif()
+ set( EC_HAVE_FORTRAN 1 )
+ endif()
+
+ include(FeatureSummary) # support features in cmake
+
+ include(TestBigEndian)
+
+ ############################################################################################
+ # backport of cmake > 2.8.4 functions
+
+ if( "${CMAKE_VERSION}" VERSION_LESS "2.8.6" )
+ include( ${CMAKE_CURRENT_LIST_DIR}/2.8/CMakePushCheckState.cmake )
+ else()
+ include(CMakePushCheckState)
+ endif()
+
+ ############################################################################################
+ # add our macros
+
+ include( ecbuild_list_macros )
+ include( ecbuild_list_add_pattern )
+ include( ecbuild_list_exclude_pattern )
+
+ include( ecbuild_check_c_source_return )
+ include( ecbuild_check_cxx_source_return )
+ include( ecbuild_check_cxx11 )
+ include( ecbuild_check_fortran_source_return )
+
+ include( ecbuild_requires_macro_version )
+ include( ecbuild_get_date )
+ include( ecbuild_add_persistent )
+ include( ecbuild_generate_config_headers )
+ include( ecbuild_generate_rpc )
+ include( ecbuild_generate_yy )
+ include( ecbuild_generate_fortran_interfaces )
+ include( ecbuild_echo_targets )
+ include( ecbuild_features )
+ include( ecbuild_add_option )
+ include( ecbuild_add_library )
+ include( ecbuild_add_executable )
+ include( ecbuild_append_to_rpath )
+ include( ecbuild_download_resource )
+ include( ecbuild_get_test_data )
+ include( ecbuild_add_c_flags )
+ include( ecbuild_add_cxx_flags )
+ include( ecbuild_add_cxx11_flags )
+ include( ecbuild_get_cxx11_flags )
+ include( ecbuild_add_fortran_flags )
+ include( ecbuild_add_test )
+ include( ecbuild_add_resources )
+ include( ecbuild_get_resources )
+ include( ecbuild_dont_pack )
+ include( ecbuild_project_files )
+ include( ecbuild_declare_project )
+ include( ecbuild_install_project )
+ include( ecbuild_separate_sources )
+ include( ecbuild_find_package )
+ include( ecbuild_use_package )
+ include( ecbuild_list_extra_search_paths )
+ include( ecbuild_add_extra_search_paths )
+ include( ecbuild_print_summary )
+ include( ecbuild_warn_unused_files )
+ include( ecbuild_find_mpi )
+ include( ecbuild_find_omp )
+ include( ecbuild_find_perl )
+ include( ecbuild_find_python )
+ include( ecbuild_find_lexyacc )
+ include( ecbuild_find_fortranlibs )
+ include( ecbuild_git )
+ include( ecbuild_enable_fortran )
+ include( ecbuild_source_flags )
+ include( ecbuild_bundle )
+ include( ecbuild_pkgconfig )
+ include( ecbuild_cache )
+ include( ecbuild_remove_fortran_flags )
+
+ include( ${CMAKE_CURRENT_LIST_DIR}/contrib/GetGitRevisionDescription.cmake )
+
+ ############################################################################################
+ # kickstart the build system
+
+ if( ECBUILD_CONFIG )
+ include( ${ECBUILD_CONFIG} )
+ endif()
+
+ ecbuild_prepare_cache()
+
+ include( ecbuild_define_options ) # define build options
+ include( ecbuild_compiler_flags ) # compiler flags
+ include( ecbuild_check_compiler ) # check for compiler characteristics
+ include( ecbuild_check_os ) # check for os characteristics
+ include( ecbuild_check_functions ) # check for available functions
+ include( ecbuild_define_paths ) # defines installation paths
+ include( ecbuild_define_libs_and_execs_target ) # defines the top level execs and libs
+ include( ecbuild_define_links_target ) # defines the links target
+ include( ecbuild_setup_test_framework ) # setup test framework
+ include( ecbuild_define_uninstall ) # define uninstall target
+
+ ecbuild_flush_cache()
+
+ ############################################################################################
+ # define the build timestamp, unless the user provided one via EC_BUILD_TIMESTAMP
+
+ if( NOT DEFINED EC_BUILD_TIMESTAMP )
+ ecbuild_get_timestamp( EC_BUILD_TIMESTAMP )
+ set( EC_BUILD_TIMESTAMP "${EC_BUILD_TIMESTAMP}" CACHE INTERNAL "Build timestamp" )
+ endif()
+
+ message( STATUS "---------------------------------------------------------" )
+
+else()
+
+ # Allow subprojects with different compilation flags. This could be done by defining
+ # set( ECBUILD_C_FLAGS_DEBUG "-O0" )
+ # or
+ # set( ECBUILD_CONFIG "<subproject-config>.cmake" )
+ if( ECBUILD_CONFIG )
+ message( STATUS "---------------------------------------------------------" )
+ ecbuild_info( "config ${ECBUILD_CONFIG}" )
+ include( ${ECBUILD_CONFIG} )
+ endif()
+ include( ecbuild_compiler_flags )
+
+endif()
diff --git a/cmake/ecbuild_uninstall.cmake.in b/cmake/ecbuild_uninstall.cmake.in
new file mode 100644
index 0000000..2037e36
--- /dev/null
+++ b/cmake/ecbuild_uninstall.cmake.in
@@ -0,0 +1,21 @@
+if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+ message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+
+file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
+string(REGEX REPLACE "\n" ";" files "${files}")
+foreach(file ${files})
+ message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
+ if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
+ exec_program(
+ "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
+ OUTPUT_VARIABLE rm_out
+ RETURN_VALUE rm_retval
+ )
+ if(NOT "${rm_retval}" STREQUAL 0)
+ message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
+ endif(NOT "${rm_retval}" STREQUAL 0)
+ else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
+ message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
+ endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
+endforeach(file)
diff --git a/cmake/ecbuild_use_package.cmake b/cmake/ecbuild_use_package.cmake
new file mode 100644
index 0000000..6bd2bed
--- /dev/null
+++ b/cmake/ecbuild_use_package.cmake
@@ -0,0 +1,289 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_use_package
+# ===================
+#
+# Add a project from a source directory, a subdirectory or search for it. ::
+#
+# ecbuild_use_package( PROJECT <name>
+# [ VERSION <version> [ EXACT ] ]
+# [ REQUIRED ]
+# [ QUIET ] )
+#
+# Options
+# -------
+#
+# NAME : required
+# package name (used as ``Find<name>.cmake`` and ``<name>-config.cmake``)
+#
+# VERSION : optional
+# minimum required package version
+#
+# EXACT : optional, requires VERSION
+# require the exact version rather than a minimum version
+#
+# REQUIRED : optional
+# fail if package cannot be found
+#
+# QUIET : optional
+# do not output package information if found
+#
+# Input variables
+# ---------------
+#
+# The following CMake variables influence the behaviour if set (``<name>``
+# is the package name as given, ``<NAME>`` is the capitalised version):
+#
+# :<NAME>_SOURCE: path to source directory for package
+# :SUBPROJECT_DIRS: list of additional paths to search for package source
+#
+# See also ``ecbuild_find_package`` for additional CMake variables relevant
+# when search for the package (step 6 below).
+#
+# Usage
+# -----
+#
+# Use another CMake project as a dependency by either building it from source
+# i.e. adding its source directory as a subdirectory or searching for it. This
+# transparently deals with the case where the project has already been included
+# e.g. because multiple projects with shared dependencies are built together.
+#
+# The search proceeds as follows:
+#
+# 1. If ``SUBPROJECT_DIRS`` is set, each directory in the list is searched
+# for a subdirectory <name> and ``<NAME>_SOURCE`` is set to the first one
+# found (if any).
+#
+# 2. If ``<NAME>_SOURCE`` is set, check if this directory is a CMake project
+# (contains ``CMakeLists.txt`` and fail if not.
+#
+# 3. Otherwise, check if the current directory has a ``<name>`` subdirectory.
+#
+# 4. If the project has not been previously marked as found or added as a
+# subdirectory and a project source directory has been found in steps 1-3
+# add this subdirectory.
+#
+# 5. If the project has been marked as found, check the version.
+#
+# 6. Otherwise, search for the project using ``ecbuild_find_package``.
+#
+##############################################################################
+
+macro( ecbuild_use_package )
+
+ set( options REQUIRED QUIET EXACT )
+ set( single_value_args PROJECT VERSION )
+ set( multi_value_args )
+
+ cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_p_UNPARSED_ARGUMENTS)
+ ecbuild_critical("Unknown keywords given to ecbuild_use_package(): \"${_p_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if( NOT _p_PROJECT )
+ ecbuild_critical("The call to ecbuild_use_package() doesn't specify the PROJECT.")
+ endif()
+
+ if( _p_EXACT AND NOT _p_VERSION )
+ ecbuild_critical("Call to ecbuild_use_package() requests EXACT but doesn't specify VERSION.")
+ endif()
+
+ # try to find the package as a subproject and build it
+
+ string( TOUPPER ${_p_PROJECT} pkgUPPER )
+
+ # user defined dir with subprojects
+
+ if( NOT DEFINED ${pkgUPPER}_SOURCE AND DEFINED SUBPROJECT_DIRS )
+ ecbuild_warn("ecbuild_use_package(): setting SUBPROJECT_DIRS is deprecated")
+ ecbuild_debug("ecbuild_use_package(${_p_PROJECT}): scanning subproject directories ${SUBPROJECT_DIRS}")
+ foreach( dir ${SUBPROJECT_DIRS} )
+ if( EXISTS ${dir}/${_p_PROJECT} AND EXISTS ${dir}/${_p_PROJECT}/CMakeLists.txt )
+ ecbuild_debug("ecbuild_use_package(${_p_PROJECT}): setting ${pkgUPPER}_SOURCE to ${dir}/${_p_PROJECT}")
+ set( ${pkgUPPER}_SOURCE "${dir}/${_p_PROJECT}" )
+ endif()
+ endforeach()
+ endif()
+
+ # user defined path to subproject
+
+ if( DEFINED ${pkgUPPER}_SOURCE )
+
+ if( NOT EXISTS ${${pkgUPPER}_SOURCE} OR NOT EXISTS ${${pkgUPPER}_SOURCE}/CMakeLists.txt )
+ ecbuild_critical("User defined source directory '${${pkgUPPER}_SOURCE}' for project '${_p_PROJECT}' does not exist or does not contain a CMakeLists.txt file.")
+ endif()
+
+ set( ${pkgUPPER}_subproj_dir_ "${${pkgUPPER}_SOURCE}" )
+
+ else() # default is 'dropped in' subdirectory named as project
+
+ if( EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${_p_PROJECT} AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${_p_PROJECT}/CMakeLists.txt )
+ ecbuild_debug("ecbuild_use_package(${_p_PROJECT}): found ${_p_PROJECT} in subdirectory ${CMAKE_CURRENT_SOURCE_DIR}/${_p_PROJECT}")
+ set( ${pkgUPPER}_subproj_dir_ "${CMAKE_CURRENT_SOURCE_DIR}/${_p_PROJECT}" )
+ endif()
+
+ endif()
+
+ # check if was already added as subproject ...
+
+ set( _just_added 0 )
+ set( _do_version_check 0 )
+ set( _source_description "" )
+
+ list( FIND ECBUILD_PROJECTS ${_p_PROJECT} _ecbuild_project_${pkgUPPER} )
+
+ if( NOT _ecbuild_project_${pkgUPPER} EQUAL "-1" )
+ ecbuild_debug("ecbuild_use_package(${_p_PROJECT}): ${_p_PROJECT} was previously added as a subproject")
+ set( ${pkgUPPER}_previous_subproj_ 1 )
+ else()
+ ecbuild_debug("ecbuild_use_package(${_p_PROJECT}): ${_p_PROJECT} was not previously added as a subproject")
+ set( ${pkgUPPER}_previous_subproj_ 0 )
+ endif()
+
+ # solve capitalization issues
+
+ if( ${_p_PROJECT}_FOUND AND NOT ${pkgUPPER}_FOUND )
+ set( ${pkgUPPER}_FOUND 1 )
+ endif()
+ if( ${pkgUPPER}_FOUND AND NOT ${_p_PROJECT}_FOUND )
+ set( ${_p_PROJECT}_FOUND 1 )
+ endif()
+
+ # Case 1) project was NOT previously added as subproject and is NOT already FOUND
+
+ if( NOT ${pkgUPPER}_FOUND AND NOT ${pkgUPPER}_previous_subproj_ )
+
+ # check if SUBPROJDIR is set
+
+ if( DEFINED ${pkgUPPER}_subproj_dir_ )
+
+ ecbuild_debug("ecbuild_use_package(${_p_PROJECT}): 1) project was NOT previously added as subproject and is NOT already FOUND")
+
+ # check version is acceptable
+ set( _just_added 1 )
+ set( _do_version_check 1 )
+ set( _source_description "sub-project ${_p_PROJECT} (sources)" )
+
+ # add as a subproject
+
+ set( ${pkgUPPER}_subproj_dir_ ${${pkgUPPER}_subproj_dir_} CACHE PATH "Path to ${_p_PROJECT} source directory" )
+
+ set( ECBUILD_PROJECTS ${ECBUILD_PROJECTS} ${_p_PROJECT} CACHE INTERNAL "" )
+
+ ecbuild_debug("ecbuild_use_package(${_p_PROJECT}): ${_p_PROJECT} found in subdirectory ${${pkgUPPER}_subproj_dir_}")
+ add_subdirectory( ${${pkgUPPER}_subproj_dir_} ${_p_PROJECT} )
+
+ set( ${_p_PROJECT}_BASE_DIR ${CMAKE_BINARY_DIR} )
+
+ set( ${pkgUPPER}_FOUND 1 )
+ set( ${_p_PROJECT}_VERSION ${${pkgUPPER}_VERSION} )
+
+ list( APPEND ${pkgUPPER}_INCLUDE_DIRS ${${pkgUPPER}_TPL_INCLUDE_DIRS} )
+
+ endif()
+
+ endif()
+
+ # Case 2) project was already added as subproject, so is already FOUND -- BUT must check version acceptable
+
+ if( ${pkgUPPER}_previous_subproj_ )
+
+ ecbuild_debug("ecbuild_use_package(${_p_PROJECT}): 2) project was already added as subproject, check version is acceptable")
+
+ if( NOT ${pkgUPPER}_FOUND )
+ ecbuild_critical( "${_p_PROJECT} was already included as sub-project but ${pkgUPPER}_FOUND isn't set -- this is likely a BUG in ecbuild" )
+ endif()
+
+ # check version is acceptable
+ set( _do_version_check 1 )
+ set( _source_description "already existing sub-project ${_p_PROJECT} (sources)" )
+
+ endif()
+
+ # Case 3) project was NOT added as subproject, but is FOUND -- so it was previously found as a binary ( either build or install tree )
+
+ if( ${pkgUPPER}_FOUND AND NOT ${pkgUPPER}_previous_subproj_ AND NOT _just_added )
+
+ ecbuild_debug("ecbuild_use_package(${_p_PROJECT}): 3) project was NOT previously added as subproject, but is FOUND")
+
+ # check version is acceptable
+ set( _do_version_check 1 )
+ set( _source_description "previously found package ${_p_PROJECT} (binaries)" )
+
+ endif()
+
+ # test version for Cases 1,2,3
+
+ # ecbuild_debug_var( _p_PROJECT )
+ # ecbuild_debug_var( _p_VERSION )
+ # ecbuild_debug_var( ${pkgUPPER}_VERSION )
+ # ecbuild_debug_var( ${_p_PROJECT}_VERSION )
+ # ecbuild_debug_var( _just_added )
+ # ecbuild_debug_var( _do_version_check )
+ # ecbuild_debug_var( _source_description )
+ # ecbuild_debug_var( ${pkgUPPER}_FOUND )
+ # ecbuild_debug_var( ${pkgUPPER}_previous_subproj_ )
+
+ if( _p_VERSION AND _do_version_check )
+ if( _p_EXACT )
+ if( NOT ${_p_PROJECT}_VERSION VERSION_EQUAL _p_VERSION )
+ ecbuild_critical( "${PROJECT_NAME} requires (exactly) ${_p_PROJECT} = ${_p_VERSION} -- detected as ${_source_description} ${${_p_PROJECT}_VERSION}" )
+ endif()
+ else()
+ if( _p_VERSION VERSION_LESS ${_p_PROJECT}_VERSION OR _p_VERSION VERSION_EQUAL ${_p_PROJECT}_VERSION )
+ ecbuild_info( "${PROJECT_NAME} requires ${_p_PROJECT} >= ${_p_VERSION} -- detected as ${_source_description} ${${_p_PROJECT}_VERSION}" )
+ else()
+ ecbuild_critical( "${PROJECT_NAME} requires ${_p_PROJECT} >= ${_p_VERSION} -- detected only ${_source_description} ${${_p_PROJECT}_VERSION}" )
+ endif()
+ endif()
+ endif()
+
+ # Case 4) is NOT FOUND so far, NOT as sub-project (now or before), and NOT as binary neither
+ # so try to find precompiled binaries or a build tree
+
+ if( NOT ${pkgUPPER}_FOUND )
+
+ ecbuild_debug("ecbuild_use_package(${_p_PROJECT}): 4) project has NOT been added as a subproject and is NOT already FOUND")
+
+ set( _opts )
+ if( _p_VERSION )
+ list( APPEND _opts VERSION ${_p_VERSION} )
+ endif()
+ if( _p_EXACT )
+ list( APPEND _opts EXACT )
+ endif()
+ if( _p_REQUIRED )
+ list( APPEND _opts REQUIRED )
+ endif()
+
+ ecbuild_find_package( NAME ${_p_PROJECT} ${_opts} )
+
+ if( ${_p_PROJECT}_FOUND )
+ set( ${pkgUPPER}_FOUND ${${_p_PROJECT}_FOUND} )
+ endif()
+
+ endif()
+
+ if( ${pkgUPPER}_FOUND )
+ list( APPEND ${PROJECT_NAME_CAPS}_TPLS ${_p_PROJECT} )
+ list( REMOVE_DUPLICATES ${PROJECT_NAME_CAPS}_TPLS )
+ endif()
+
+ ### for when we change this macro to a function()
+ # set_parent_scope( ${pkgUPPER}_FOUND )
+ # set_parent_scope( ${_p_PROJECT}_FOUND )
+ # set_parent_scope( ${pkgUPPER}_VERSION )
+ # set_parent_scope( ${_p_PROJECT}_VERSION )
+ # set_parent_scope( ${_p_PROJECT}_BINARY_DIR )
+
+endmacro()
diff --git a/cmake/ecbuild_version.h.in b/cmake/ecbuild_version.h.in
new file mode 100644
index 0000000..70c5f0a
--- /dev/null
+++ b/cmake/ecbuild_version.h.in
@@ -0,0 +1,20 @@
+/*
+ * (C) Copyright 1996-2016 ECMWF.
+ *
+ * This software is licensed under the terms of the Apache Licence Version 2.0
+ * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+ * In applying this licence, ECMWF does not waive the privileges and immunities
+ * granted to it by virtue of its status as an intergovernmental organisation nor
+ * does it submit to any jurisdiction.
+ */
+
+#ifndef ecbuild_version_h
+#define ecbuild_version_h
+
+#define ECBUILD_VERSION "@ECBUILD_VERSION@"
+
+#define ECBUILD_MAJOR_VERSION @ECBUILD_MAJOR_VERSION@
+#define ECBUILD_MINOR_VERSION @ECBUILD_MINOR_VERSION@
+#define ECBUILD_PATCH_VERSION @ECBUILD_PATCH_VERSION@
+
+#endif // ecbuild_version_h
diff --git a/cmake/ecbuild_warn_unused_files.cmake b/cmake/ecbuild_warn_unused_files.cmake
new file mode 100644
index 0000000..314a006
--- /dev/null
+++ b/cmake/ecbuild_warn_unused_files.cmake
@@ -0,0 +1,77 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_warn_unused_files
+# =========================
+#
+# Print warnings about unused source files in the project. ::
+#
+# ecbuild_warn_unused_files()
+#
+# If the CMake variable ``CHECK_UNUSED_FILES`` is set, ecBuild will keep track
+# of any source files (.c, .cc, .cpp, .cxx) which are not part of a CMake
+# target. If set, this macro reports unused files if any have been found. This
+# is considered a fatal error unless ``UNUSED_FILES_LEVEL`` is set to a value
+# different from ``ERROR``.
+#
+# .. note ::
+#
+# Enabling ``CHECK_UNUSED_FILES`` can slow down the CMake configure time
+# considerably!
+#
+##############################################################################
+
+macro( ecbuild_warn_unused_files )
+
+ if( PROJECT_NAME STREQUAL CMAKE_PROJECT_NAME ) # only for top level project
+
+ # if cache file with unused files exists remove it
+ set( UNUSED_FILE "${CMAKE_BINARY_DIR}/UnusedFiles.txt" )
+ if( EXISTS ${UNUSED_FILE} )
+ file( REMOVE ${UNUSED_FILE} )
+ endif()
+
+ if( CHECK_UNUSED_FILES ) # to check or not to check...
+
+ if( NOT DEFINED UNUSED_FILES_LEVEL ) # to err or not...
+ set( UNUSED_FILES_LEVEL "ERROR" )
+ endif()
+
+ # if unused files where found, put the list on the file
+ if( EC_UNUSED_FILES )
+
+ ecbuild_info("")
+ ecbuild_info(" !!!--- ${UNUSED_FILES_LEVEL} ---!!! ")
+ ecbuild_info(" !!!--- ${UNUSED_FILES_LEVEL} ---!!! ")
+ ecbuild_info("")
+ ecbuild_info(" Unused source files found:")
+ foreach( AFILE ${EC_UNUSED_FILES} )
+ ecbuild_info(" ${AFILE}")
+ file( APPEND ${UNUSED_FILE} "${AFILE}\n" )
+ endforeach()
+ ecbuild_info("")
+ ecbuild_info(" List dumped to ${UNUSED_FILE}")
+ ecbuild_info("")
+ ecbuild_info(" !!!--- ${UNUSED_FILES_LEVEL} ---!!! ")
+ ecbuild_info(" !!!--- ${UNUSED_FILES_LEVEL} ---!!! ")
+ ecbuild_info("")
+
+ if( UNUSED_FILES_LEVEL STREQUAL "ERROR" )
+ ecbuild_critical( "\n Aborted build system configuration. \n Add unused files to the build system or remove them." )
+ endif()
+
+ endif()
+
+ endif()
+
+ endif()
+
+endmacro( ecbuild_warn_unused_files )
diff --git a/cmake/fcm-make-interfaces.cfg b/cmake/fcm-make-interfaces.cfg
new file mode 100644
index 0000000..a73363a
--- /dev/null
+++ b/cmake/fcm-make-interfaces.cfg
@@ -0,0 +1,31 @@
+# FCM configuration file used to auto-generate interface files
+# for F77 and F90 files.
+# Interface files will have the extention ".intfb.h"
+# Results will be in a directory "interfaces/include" relative to cwd
+
+# Usage: fcm make --config-file=<path -to-this-file> \
+# interfaces.ns-incl="<space-sep-list-of-dirs>"
+
+$SRC{?} = $HERE
+
+step.class[interfaces] = build
+steps = interfaces
+
+interfaces.target{task} = ext-iface
+interfaces.target{category} = include
+
+interfaces.source = $SRC
+
+# Exclude all
+interfaces.ns-excl = /
+
+# Include some
+# interfaces.ns-incl = <list of dirs passed at command-line>
+
+# Extention of interface files
+interfaces.prop{file-ext.f90-interface} = .intfb.h
+
+# Do not follow includes
+interfaces.prop{no-dep.f.module} = *
+interfaces.prop{no-dep.include} = *
+
diff --git a/cmake/gen_source_flags.py b/cmake/gen_source_flags.py
new file mode 100644
index 0000000..b976d31
--- /dev/null
+++ b/cmake/gen_source_flags.py
@@ -0,0 +1,84 @@
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+"""
+Generate .cmake file to set source-file specific compiler flags based on
+rules defined in a JSON file.
+"""
+
+from argparse import ArgumentParser
+from fnmatch import fnmatch
+import logging
+from json import JSONDecoder
+from os import path
+
+log = logging.getLogger('gen_source_flags')
+
+
+def match(source, pattern, op, flags, indent=0):
+ if fnmatch(source, pattern):
+
+ suff = '' if op[0] in ('+', '=', '/') else ' (nested pattern)'
+ log.debug('%s-> pattern "%s" matches "%s"%s',
+ ' ' * (indent + 1), pattern, source, suff)
+
+ if op[0] == "+":
+ flags += [flag for flag in op[1:] if flag not in flags]
+ log.debug('%sappending %s --> flags: %s', ' ' * (indent + 2), op[1:], flags)
+
+ elif op[0] == "=":
+ flags = op[1:]
+ log.debug('%ssetting %s --> flags: %s', ' ' * (indent + 2), op[1:], flags)
+
+ elif op[0] == "/":
+ flags = [flag for flag in flags if flag not in op[1:]]
+ log.debug('%sremoving %s --> flags: %s', ' ' * (indent + 2), op[1:], flags)
+
+ else: # Nested rule
+ log.debug('%sapplying nested rules for "%s" (flags: %s)',
+ ' ' * (indent + 2), pattern, flags)
+ for nested_pattern, nested_op in op:
+ flags = match(source, nested_pattern, nested_op, flags, indent + 2)
+
+ return flags
+
+
+def generate(rules, out, default_flags, sources, debug=False):
+ logging.basicConfig(level=logging.DEBUG if debug else logging.INFO,
+ format='-- %(levelname)s - %(name)s: %(message)s')
+
+ with open(path.expanduser(rules)) as f:
+ rules = JSONDecoder(object_pairs_hook=list).decode(f.read())
+
+ with open(path.expanduser(out), 'w') as f:
+ for source in sources:
+ log.debug('%s (default flags: "%s")', source, default_flags)
+ flags = default_flags.split()
+ for pattern, op in rules:
+ flags = match(source, pattern, op, flags)
+
+ if flags:
+ log.debug(' ==> setting flags for %s to %s', source, ' '.join(flags))
+ f.write('set_source_files_properties(%s PROPERTIES COMPILE_FLAGS "%s")\n'
+ % (source, ' '.join(flags)))
+ else:
+ log.debug(' ==> flags for %s empty', source)
+
+
+def main():
+ """Parse arguments"""
+ parser = ArgumentParser(description=__doc__)
+ parser.add_argument('rules', metavar='RULES.json', help='JSON rules file')
+ parser.add_argument('out', metavar='OUT.cmake', help='CMake script to generate')
+ parser.add_argument('default_flags', help='Default compiler flags to use')
+ parser.add_argument('sources', metavar='file', nargs='+', help='Path to file to apply rules to')
+ parser.add_argument('--debug', '-d', action='store_true', help='Log debug messages')
+ generate(**vars(parser.parse_args()))
+
+if __name__ == '__main__':
+ main()
diff --git a/cmake/include/ecbuild/boost_test_framework.h b/cmake/include/ecbuild/boost_test_framework.h
new file mode 100644
index 0000000..f593b70
--- /dev/null
+++ b/cmake/include/ecbuild/boost_test_framework.h
@@ -0,0 +1,17 @@
+/*
+ * (C) Copyright 1996-2016 ECMWF.
+ *
+ * This software is licensed under the terms of the Apache Licence Version 2.0
+ * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+ * In applying this licence, ECMWF does not waive the privileges and immunities
+ * granted to it by virtue of its status as an intergovernmental organisation nor
+ * does it submit to any jurisdiction.
+ */
+
+#ifdef BOOST_UNIT_TEST_FRAMEWORK_HEADER_ONLY
+#include <boost/test/included/unit_test.hpp>
+#else
+#define BOOST_TEST_DYN_LINK
+#include <boost/test/unit_test.hpp>
+#endif
+
diff --git a/ecbuild/cmake/md5.in b/cmake/md5.in
similarity index 100%
rename from ecbuild/cmake/md5.in
rename to cmake/md5.in
diff --git a/cmake/pkg-config.pc.in b/cmake/pkg-config.pc.in
new file mode 100644
index 0000000..e6d903d
--- /dev/null
+++ b/cmake/pkg-config.pc.in
@@ -0,0 +1,35 @@
+# This pkg-config file is generated by ecbuild_pkgconfig()
+# with template ecbuild/cmake/pkg-config.pc.in
+
+git_tag=@PKGCONFIG_GIT_TAG@
+
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=${prefix}
+libdir=${prefix}/@INSTALL_LIB_DIR@
+includedir=${prefix}/@INSTALL_INCLUDE_DIR@
+bindir=${prefix}/@INSTALL_BIN_DIR@
+fmoddir=${prefix}/@INSTALL_INCLUDE_DIR@
+
+CC=@CMAKE_C_COMPILER@
+CXX=@CMAKE_CXX_COMPILER@
+FC=@CMAKE_Fortran_COMPILER@
+
+rpath=@RPATH_FLAG@${libdir}
+
+libs=-L${libdir} ${rpath} @PKGCONFIG_LIBS@
+
+libs_private=@PKGCONFIG_LIBS_PRIVATE@
+
+cflags=@PKGCONFIG_INCLUDE@ @PKGCONFIG_CFLAGS@
+ at PKGCONFIG_VARIABLES@
+#====================================================================
+Name: @PKGCONFIG_NAME@
+Description: @PKGCONFIG_DESCRIPTION@
+URL: @PKGCONFIG_URL@
+Version: @PKGCONFIG_VERSION@
+Libs: ${libs}
+Libs.private: ${libs_private}
+Requires: @PKGCONFIG_REQUIRES@
+Requires.private: @PKGCONFIG_REQUIRES_PRIVATE@
+Cflags: ${cflags}
+#====================================================================
diff --git a/ecbuild/cmake/project-config-version.cmake.in b/cmake/project-config-version.cmake.in
similarity index 100%
rename from ecbuild/cmake/project-config-version.cmake.in
rename to cmake/project-config-version.cmake.in
diff --git a/cmake/project-config.cmake.in b/cmake/project-config.cmake.in
new file mode 100644
index 0000000..6d48728
--- /dev/null
+++ b/cmake/project-config.cmake.in
@@ -0,0 +1,97 @@
+# Config file for the @PROJECT_NAME@ package
+# Defines the following variables:
+#
+# @PNAME at _INCLUDE_DIRS - include directories
+# @PNAME at _DEFINITIONS - preprocessor definitions
+# @PNAME at _LIBRARIES - libraries to link against
+# @PNAME at _FEATURES - list of enabled features
+# @PNAME at _VERSION - version of the package
+# @PNAME at _GIT_SHA1 - Git revision of the package
+# @PNAME at _GIT_SHA1_SHORT - short Git revision of the package
+#
+# Also defines @PROJECT_NAME@ third-party library dependencies:
+# @PNAME at _TPLS - package names of third-party library dependencies
+# @PNAME at _TPL_INCLUDE_DIRS - include directories
+# @PNAME at _TPL_DEFINITIONS - preprocessor definitions
+# @PNAME at _TPL_LIBRARIES - libraries to link against
+
+### compute paths
+
+get_filename_component(@PNAME at _CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
+
+set( @PNAME at _SELF_INCLUDE_DIRS "@CONF_INCLUDE_DIRS@" )
+set( @PNAME at _SELF_DEFINITIONS "@CONF_DEFINITIONS@" )
+set( @PNAME at _SELF_LIBRARIES "@CONF_LIBRARIES@" )
+
+set( @PNAME at _TPLS "@CONF_TPLS@" )
+set( @PNAME at _TPL_INCLUDE_DIRS "@CONF_TPL_INCLUDE_DIRS@" )
+set( @PNAME at _TPL_DEFINITIONS "@CONF_TPL_DEFINITIONS@" )
+set( @PNAME at _TPL_LIBRARIES "@CONF_TPL_LIBRARIES@" )
+
+set( @PNAME at _VERSION "@PACKAGE_VERSION@" )
+set( @PNAME at _GIT_SHA1 "@PACKAGE_GIT_SHA1@" )
+set( @PNAME at _GIT_SHA1_SHORT "@PACKAGE_GIT_SHA1_SHORT@" )
+
+### export include paths as absolute paths
+
+set( @PNAME at _INCLUDE_DIRS "" )
+foreach( path ${@PNAME at _SELF_INCLUDE_DIRS} )
+ get_filename_component( abspath ${path} ABSOLUTE )
+ list( APPEND @PNAME at _INCLUDE_DIRS ${abspath} )
+endforeach()
+list( APPEND @PNAME at _INCLUDE_DIRS ${@PNAME at _TPL_INCLUDE_DIRS} )
+
+### export definitions
+
+set( @PNAME at _DEFINITIONS ${@PNAME at _SELF_DEFINITIONS} ${@PNAME at _TPL_DEFINITIONS} )
+
+### export list of all libraries
+
+set( @PNAME at _LIBRARIES ${@PNAME at _SELF_LIBRARIES} ${@PNAME at _TPL_LIBRARIES} )
+
+### export the features provided by the package
+
+set( @PNAME at _FEATURES "@CONF_FEATURES@" )
+foreach( _f ${@PNAME at _FEATURES} )
+ set( @PNAME at _HAVE_${_f} 1 )
+endforeach()
+
+# Has this configuration been exported from a build tree?
+set( @PNAME at _IS_BUILD_DIR_EXPORT @_is_build_dir_export@ )
+
+if( EXISTS ${@PNAME at _CMAKE_DIR}/@CONF_IMPORT_FILE@ )
+ set( @PNAME at _IMPORT_FILE "${@PNAME at _CMAKE_DIR}/@CONF_IMPORT_FILE@" )
+ include( ${@PNAME at _IMPORT_FILE} )
+endif()
+
+# here goes the imports of the TPL's
+
+include( ${CMAKE_CURRENT_LIST_FILE}.tpls OPTIONAL )
+
+# insert definitions for IMPORTED targets
+
+if( NOT @PROJECT_NAME at _BINARY_DIR )
+
+ if( @PNAME at _IS_BUILD_DIR_EXPORT )
+ include( "@TOP_PROJECT_TARGETS_FILE@" OPTIONAL )
+ else()
+ include( "${@PNAME at _CMAKE_DIR}/@PROJECT_NAME at -targets.cmake" )
+ endif()
+
+endif()
+
+# publish this file as imported
+
+set( @PNAME at _IMPORT_FILE ${CMAKE_CURRENT_LIST_FILE} )
+mark_as_advanced( @PNAME at _IMPORT_FILE )
+
+# set @PROJECT_NAME at _BASE_DIR for final installations or build directories
+
+if( NOT @PROJECT_NAME@ )
+ if( @PNAME at _IS_BUILD_DIR_EXPORT )
+ set( @PROJECT_NAME at _BASE_DIR @CMAKE_BINARY_DIR@ )
+ else()
+ get_filename_component( abspath ${CMAKE_CURRENT_LIST_DIR}/../../.. ABSOLUTE )
+ set( @PROJECT_NAME at _BASE_DIR ${abspath} )
+ endif()
+endif()
diff --git a/cmake/pymain.c b/cmake/pymain.c
new file mode 100644
index 0000000..823d57d
--- /dev/null
+++ b/cmake/pymain.c
@@ -0,0 +1,5 @@
+#include <Python.h>
+
+int main() {
+ return 0;
+}
diff --git a/cmake/sg.pl b/cmake/sg.pl
new file mode 100644
index 0000000..6bce843
--- /dev/null
+++ b/cmake/sg.pl
@@ -0,0 +1,573 @@
+#!/usr/bin/perl
+#!/usr/local/share/perl56
+
+# (C) Copyright 1996-2016 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation nor
+# does it submit to any jurisdiction.
+
+use strict;
+
+#use Data::Dumper;
+use File::Basename;
+
+#$Data::Dumper::Indent = 1;
+# $ARGV[0] = "test.cc";
+# $ARGV[0] = "/usr/include/g++-3/stl_pair.h";
+# $ARGV[0] = "/usr/include/g++-3/stl_vector.h";
+# $ARGV[0] = "/usr/include/g++-3/stl_list.h";
+# $ARGV[0] = "/usr/include/g++-3/stl_map.h";
+# $ARGV[0] = "x.cc";
+# $ARGV[0] = "/usr/include/g++-3/std/bastring.h";
+
+# script takes 3 parameters:
+# (1) file to process
+my $file = $ARGV[0];
+# (2) [optional] directory to place the generated .b file
+my $base = $ARGV[1];
+# (3) [optional] c++ namespace
+my $namespace = $ARGV[2];
+
+# no argv[1] passed, take basedir from file
+if( $base eq "" )
+{
+ $base = dirname($file);
+}
+
+# no argv[1] passed, take basedir from file
+if( $namespace eq "" )
+{
+ $namespace = "eclib"
+}
+
+my @c = parser::parse($file);
+#print Dumper(\@c);
+
+
+foreach my $c ( @c )
+{
+ my $n = $c->name;
+ open(STDOUT,">$base/$n.b") || die "$base/$n.b: $!";
+
+ my @init1;
+ push @init1, map { "$_(b)" } $c->super;
+ push @init1, map { "$_(b(\&$_))" } $c->members;
+
+ my $col1;
+ $col1=":\n" if(@init1);
+ my $init1 = join(",\n",map {"\t$_"} @init1);
+
+ my @init2;
+ push @init2, map { "$_(b(\"$n\"))" } $c->super;
+ push @init2, map { "$_(b(\"$n\",\"$_\"))" } $c->members;
+
+ my $col2;
+ $col2=":\n" if(@init2);
+ my $init2 = join(",\n",map {"\t$_"} @init2);
+
+
+ my @s = map { "${_}::describe(s,depth+1)" } $c->super;
+ my @m = map { "${namespace}::_describe(s,depth+1,\"$_\",$_)" } $c->members;
+ my $d = join(";\n\t","${namespace}::_startClass(s,depth,specName())", at s, at m,"${namespace}::_endClass(s,depth,specName())");
+
+ my @s = map { "${_}::_export(h)" } $c->super;
+ my @m = map { "${namespace}::_export(h,\"$_\",$_)" } $c->members;
+ my $D = join(";\n\t","${namespace}::_startClass(h,\"$n\")", at s, at m,"${namespace}::_endClass(h,\"$n\")");
+
+ my $spec = "\"$n\"";
+ my @tmpl = $c->template;
+
+ my $spec_type = "const char*";
+
+ if(@tmpl)
+ {
+ $spec_type = "std::string";
+ my $x = join("+ ',' + ", map { "Traits<$_>::name()"; } @tmpl);
+ $spec = <<"EOS";
+ std::string("$n<\") + $x + ">"
+EOS
+ $spec =~ s/\n/ /g;
+ }
+
+ my $isa = "${namespace}::Isa::add(t,specName());";
+ foreach my $s ( $c->super )
+ {
+ $isa = "${s}::isa(t);$isa";
+ }
+
+ my $schema;
+ @s = map { "${_}::schema(s)" } $c->super;
+ @m = map { $a=$_->[0]; $b=$_->[1]; "s.member(\"$a\",member_size($n,$a),member_offset($n,$a),\"$b\")" } $c->members_types;
+ $schema = join(";\n\t","s.start(specName(),sizeof($n))", at s, at m,"s.end(specName())");
+
+ print <<"EOF";
+
+${n}(${namespace}::Bless& b)$col1$init1
+{
+}
+
+${n}(${namespace}::Evolve b)$col2$init2
+{
+}
+
+static ${spec_type} specName() { return ${spec}; }
+static void isa(TypeInfo* t) { ${isa} }
+static ${namespace}::Isa* isa() { return ${namespace}::Isa::get(specName()); }
+
+static void schema(${namespace}::Schema& s)
+{
+ $schema;
+}
+
+EOF
+
+if(!$c->has_method("describe"))
+{
+print <<"EOF";
+
+void describe(std::ostream& s,int depth = 0) const {
+ $d;
+}
+
+
+EOF
+}
+
+print <<"EOF";
+
+void _export(${namespace}::Exporter& h) const {
+ $D;
+}
+
+
+EOF
+
+}
+if(0)
+{
+foreach my $c ( @c )
+{
+ my $n = $c->name;
+ open(OUT,">${n}.b");
+ select OUT;
+ print "static void schema(${namespace}::Schema& s) {\n";
+ foreach my $x ( $c->super )
+ {
+ print "${x}::schema(s);\n";
+ #print "s(\"$x\", 0,sizeof($x));\n";
+ }
+ foreach my $x ( $c->members )
+ {
+ print "s(\"${n}::$x\",offsetof($n,$x),sizeof(&(($n*)0)->$x));\n";
+ }
+ print "}\n";
+}
+}
+package parser;
+use Carp;
+my @TOKENS;
+sub parse {
+ my ($file) = @_;
+ local $/ = undef;
+ open(IN,"<$file") || croak "$file: $!";
+ my $x = <IN>;
+ close(IN);
+ $x =~ s/^#.*$//mg;
+ $x =~ s/\/\/.*$//mg;
+ @TOKENS =
+ grep { length($_); }
+ map { /\W/ ? split('',$_) : $_; }
+ map { s/\s//g; $_; }
+ split(/\b/, $x );
+
+ my @c;
+ my $x;
+ while($x = consume_until("(typedef|template|class|struct)"))
+ {
+ if($x eq 'typedef')
+ {
+ consume_until(";");
+ next;
+ }
+
+ if($x eq 'template')
+ {
+ push @c, parse_template();
+ }
+ else
+ {
+ push @c, parse_class();
+ }
+ }
+ return grep { defined $_; } @c;
+}
+
+sub parse_template {
+ my @tmp = template_args();
+ return parse_class(@tmp) if(next_is("(class|struct)"));
+}
+sub template_args {
+ my @tmp;
+ expect_next("<");
+ for(;;)
+ {
+ expect_next("(class|bool|int)");
+ push @tmp, next_ident();
+ if(next_is("="))
+ {
+ my $x = consume_until('(,|\>|\<)');
+ unshift @TOKENS,$x;
+ while($x eq '<')
+ {
+ consume_block('<','>');
+ $x = consume_until('(,|\>|\<)');
+ unshift @TOKENS,$x;
+ }
+ }
+ last unless(next_is(","));
+ }
+ expect_next(">");
+ return @tmp;
+}
+sub parse_class {
+ my (@tmp) = @_;
+ my $self = {};
+ my $name = next_ident();
+ $self->{name} = $name;
+ $self->{template} = \@tmp if(@tmp);
+ # Foreward declaration
+ return if(next_is(";"));
+ if(next_is(":"))
+ {
+ for(;;)
+ {
+ ignore_while("(public|private|protected|virtual)");
+ push @{$self->{super}}, next_ident();
+ last unless(next_is(","));
+ }
+ }
+ expect_next('{');
+ while(!peek_next('}'))
+ {
+ # print "... : $TOKENS[0], $TOKENS[1], ... \n";
+ if(next_is('\/'))
+ {
+ if(next_is('\*'))
+ {
+ while(!next_is('\/'))
+ {
+ consume_until('\*');
+ }
+ next;
+ }
+ else
+ {
+ unshift @TOKENS, "/";
+ }
+
+ }
+
+ if(next_is("(public|private|protected)"))
+ {
+ expect_next(":");
+ next;
+ }
+
+ if(next_is("friend"))
+ {
+ my $x = consume_until("(;|{)");
+ if($x eq "{")
+ {
+ unshift @TOKENS, $x;
+ consume_block('{','}');
+ }
+ next;
+ }
+
+ # next_is("explicit");
+ if(next_is("(typedef|using|typename|enum)"))
+ {
+ consume_until(";");
+ next;
+ }
+ if(next_is("(class|struct)"))
+ {
+ push @{$self->{classes}}, parse_class();
+ next;
+ }
+ my %m;
+ while(next_is("template"))
+ {
+ push @{ $m{template} } , template_args();
+ }
+
+ my @x;
+# push @x,"~" while(next_is('\~'));
+
+ $m{explicit} = 1 if(next_is("explicit"));
+ $m{static} = 1 if(next_is("static"));
+ $m{virtual} = 1 if(next_is("virtual"));
+ my $x;
+ while($x = next_is_ident())
+ {
+ # print "--- : $x\n";
+ push @x, $x;
+ push @x,'*' while(next_is('\*'));
+ push @x,'&' while(next_is('\&'));
+ $m{name} = $x;
+ # int a,b,*c; does not work
+ my $s;
+ if($s = next_is('(,|;|=)'))
+ {
+ pop @x;
+ $m{type} = make_type(@x);
+ if(exists $m{static})
+ {
+ push @{$self->{class_members}}, \%m;
+ }
+ else
+ {
+ push @{$self->{members}}, \%m;
+ }
+ consume_until(";") if($s eq '=');
+ last;
+ }
+ if(peek_next('\('))
+ {
+ pop @x;
+ $m{type} = make_type(@x);
+ my @args = consume_block('(',')');
+ shift @args;
+ pop @args;
+ my @a;
+ my $n = 0;
+ my @z;
+ foreach my $a ( @args )
+ {
+ if($a eq ',' && $n == 0)
+ {
+ push @a, make_type(@z);
+ @z = ();
+ next;
+ }
+ $n++ if($a eq '<');
+ $n++ if($a eq '(');
+ $n-- if($a eq ')');
+ $n-- if($a eq '>');
+ push @z,$a;
+ }
+ push @a, make_type(@z) if(@z);
+ $m{const} = 1 if(next_is("const"));
+ $m{args} = \@a;
+ if(exists $m{static})
+ {
+ push @{$self->{class_methods}}, \%m;
+ }
+ else
+ {
+ push @{$self->{methods}}, \%m;
+ }
+ # print "f: $x\n";
+
+ if(next_is(':'))
+ {
+ # print "{: $TOKENS[0]\n";
+ consume_until('\{');
+ unshift @TOKENS, '{';
+ consume_block('{','}');
+ # print "}: $TOKENS[0]\n";
+ }
+ else
+ {
+ if(peek_next('\{'))
+ {
+ consume_block('{','}');
+ }
+ else
+ {
+ if(next_is("="))
+ {
+ expect_next("0");
+ $m{abstract} = 1;
+ }
+ expect_next(";");
+ }
+ }
+ last;
+ }
+ }
+
+ }
+ expect_next("}");
+ expect_next(";");
+ return bless($self,"class");
+}
+sub consume_until {
+ my ($r) = @_;
+ while(@TOKENS)
+ {
+ my $x = shift @TOKENS;
+ return $x if($x =~ /^$r$/);
+ }
+ return undef;
+}
+sub consume_block {
+ my ($bra,$ket) = @_;
+ my $n = 0;
+ my @x;
+ croak "@TOKENS" unless($bra eq $TOKENS[0]);
+ while(@TOKENS)
+ {
+ my $x = shift @TOKENS;
+ $n++ if($x eq $bra);
+ $n-- if($x eq $ket);
+ push @x,$x;
+ return @x if($n == 0);
+ }
+}
+sub ignore_while {
+ my ($r) = @_;
+ while(@TOKENS)
+ {
+ return unless($TOKENS[0] =~ /^$r$/);
+ shift @TOKENS;
+ }
+}
+sub expect_next {
+ my ($r) = @_;
+ my $ident = shift @TOKENS;
+ croak "$ident is not $r" unless($ident =~ /^$r$/);
+ return $ident;
+}
+sub next_ident {
+ my $x = next_is_ident();
+ croak "not an ident " unless($x);
+ return $x;
+}
+sub next_is {
+ my ($r) = @_;
+ if($TOKENS[0] =~ /^$r$/)
+ {
+ return shift @TOKENS;
+ }
+ return undef;
+}
+sub next_is_ident {
+ my $op = next_is("operator");
+ if($op)
+ {
+ my $x;
+ if($x = next_is("(new|delete)"))
+ {
+ $op .= " $x";
+ if(next_is('\['))
+ {
+ expect_next('\]');
+ $op .= "[]";
+ }
+ return $op;
+ }
+
+ if(next_is('\('))
+ {
+ expect_next('\)');
+ $op .= "()";
+ }
+ my $z;
+ while($z = next_is('[\-+/\*\[\]<>=!]'))
+ {
+ $op .= $z;
+ }
+ return $op;
+ }
+ my $y = next_is('\~');
+ my $x = next_is('\w+');
+ if($x)
+ {
+ $x = "$y$x";
+ if(peek_next("<"))
+ {
+ my @x = consume_block("<",">");
+ $x .= join("", at x);
+ }
+
+ if(next_is(":"))
+ {
+ if(next_is(":"))
+ {
+ my $z = next_is_ident();
+ return "${x}::${z}";
+ }
+ else
+ {
+ unshift @TOKENS, ":";
+ }
+ }
+ }
+ return $x;
+}
+sub peek_next {
+ my ($r) = @_;
+ if($TOKENS[0] =~ /^$r$/)
+ {
+ return 1;
+ }
+ return 0;
+}
+sub make_type {
+ my (@a) = @_;
+ my $p;
+ my @x;
+ foreach my $a ( @a )
+ {
+ push @x, " " if($p =~ /^(\w+|\&|\*)$/ && $a =~ /^\w+$/);
+ push @x, $a;
+ $p = $a;
+ }
+ my $s = join('', at x);
+ $s =~ s/>>/> >/g;
+ return $s;
+}
+package class;
+sub name {
+ my ($self) = @_;
+ return $self->{name};
+}
+sub super {
+ my ($self) = @_;
+ return $self->{super} ? @{$self->{super}} : ();
+}
+
+sub members {
+ my ($self) = @_;
+ my @x = $self->{members} ? @{$self->{members}} : ();
+ return map { $_->{name} } @x;
+}
+
+sub methods {
+ my ($self) = @_;
+ my @x = $self->{methods} ? @{$self->{methods}} : ();
+ return map { $_->{name} } @x;
+}
+
+sub has_method {
+ my ($self,$name) = @_;
+ return grep { $_ eq $name } $self->methods;
+}
+
+sub members_types {
+ my ($self) = @_;
+ my @x = $self->{members} ? @{$self->{members}} : ();
+ return map { [ $_->{name}, $_->{type} ] } @x;
+}
+
+sub template {
+ my ($self) = @_;
+ return $self->{template} ? @{$self->{template}} : ();
+}
+1;
+
+
diff --git a/ecbuild/cmake/sha1.in b/cmake/sha1.in
similarity index 100%
rename from ecbuild/cmake/sha1.in
rename to cmake/sha1.in
diff --git a/ecbuild/.cproject b/ecbuild/.cproject
deleted file mode 100644
index 18ccafc..0000000
--- a/ecbuild/.cproject
+++ /dev/null
@@ -1,66 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
- <storageModule moduleId="org.eclipse.cdt.core.settings">
- <cconfiguration id="cdt.managedbuild.toolchain.gnu.base.1298805696">
- <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.toolchain.gnu.base.1298805696" moduleId="org.eclipse.cdt.core.settings" name="Default">
- <externalSettings/>
- <extensions>
- <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
- <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
- <extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
- <extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
- <extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
- <extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
- </extensions>
- </storageModule>
- <storageModule moduleId="cdtBuildSystem" version="4.0.0">
- <configuration buildProperties="" id="cdt.managedbuild.toolchain.gnu.base.1298805696" name="Default" parent="org.eclipse.cdt.build.core.emptycfg">
- <folderInfo id="cdt.managedbuild.toolchain.gnu.base.1298805696.343791376" name="/" resourcePath="">
- <toolChain id="cdt.managedbuild.toolchain.gnu.base.222734635" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.base">
- <targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.target.gnu.platform.base.1421442229" name="Debug Platform" osList="linux,hpux,aix,qnx" superClass="cdt.managedbuild.target.gnu.platform.base"/>
- <builder id="cdt.managedbuild.target.gnu.builder.base.1628994041" managedBuildOn="false" name="Gnu Make Builder.Default" superClass="cdt.managedbuild.target.gnu.builder.base"/>
- <tool id="cdt.managedbuild.tool.gnu.archiver.base.284779640" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
- <tool id="cdt.managedbuild.tool.gnu.cpp.compiler.base.1978772046" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.base"/>
- <tool id="cdt.managedbuild.tool.gnu.c.compiler.base.2058316558" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.base"/>
- <tool id="cdt.managedbuild.tool.gnu.c.linker.base.1694186035" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.base"/>
- <tool id="cdt.managedbuild.tool.gnu.cpp.linker.base.616621355" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.base"/>
- <tool id="cdt.managedbuild.tool.gnu.assembler.base.1802178549" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.base"/>
- </toolChain>
- </folderInfo>
- </configuration>
- </storageModule>
- <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
- </cconfiguration>
- </storageModule>
- <storageModule moduleId="scannerConfiguration">
- <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
- <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.cross.exe.debug.1319857020;cdt.managedbuild.config.gnu.cross.exe.debug.1319857020.;cdt.managedbuild.tool.gnu.cross.cpp.compiler.411133180;cdt.managedbuild.tool.gnu.cpp.compiler.input.1649178953">
- <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
- </scannerConfigBuildInfo>
- <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.release.82906048;cdt.managedbuild.config.gnu.exe.release.82906048.;cdt.managedbuild.tool.gnu.cpp.compiler.exe.release.1671708469;cdt.managedbuild.tool.gnu.cpp.compiler.input.1921164278">
- <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
- </scannerConfigBuildInfo>
- <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.cross.exe.release.381634699;cdt.managedbuild.config.gnu.cross.exe.release.381634699.;cdt.managedbuild.tool.gnu.cross.cpp.compiler.425486738;cdt.managedbuild.tool.gnu.cpp.compiler.input.1810510997">
- <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
- </scannerConfigBuildInfo>
- <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.294858900;cdt.managedbuild.config.gnu.exe.debug.294858900.;cdt.managedbuild.tool.gnu.c.compiler.exe.debug.636062781;cdt.managedbuild.tool.gnu.c.compiler.input.540848204">
- <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
- </scannerConfigBuildInfo>
- <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.release.82906048;cdt.managedbuild.config.gnu.exe.release.82906048.;cdt.managedbuild.tool.gnu.c.compiler.exe.release.280707483;cdt.managedbuild.tool.gnu.c.compiler.input.1276186659">
- <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
- </scannerConfigBuildInfo>
- <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.294858900;cdt.managedbuild.config.gnu.exe.debug.294858900.;cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug.1253744786;cdt.managedbuild.tool.gnu.cpp.compiler.input.345025843">
- <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
- </scannerConfigBuildInfo>
- <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.cross.exe.debug.1319857020;cdt.managedbuild.config.gnu.cross.exe.debug.1319857020.;cdt.managedbuild.tool.gnu.cross.c.compiler.1274562050;cdt.managedbuild.tool.gnu.c.compiler.input.1990532997">
- <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
- </scannerConfigBuildInfo>
- <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.cross.exe.release.381634699;cdt.managedbuild.config.gnu.cross.exe.release.381634699.;cdt.managedbuild.tool.gnu.cross.c.compiler.1274373530;cdt.managedbuild.tool.gnu.c.compiler.input.1986827568">
- <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
- </scannerConfigBuildInfo>
- </storageModule>
- <storageModule moduleId="cdtBuildSystem" version="4.0.0">
- <project id="ecbuild.null.1331004306" name="ecbuild"/>
- </storageModule>
- <storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
-</cproject>
diff --git a/ecbuild/.gitignore b/ecbuild/.gitignore
deleted file mode 100644
index d8ceade..0000000
--- a/ecbuild/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-CMakeLists.txt.user*
-*.swp
diff --git a/ecbuild/.project b/ecbuild/.project
deleted file mode 100644
index 0dc07fa..0000000
--- a/ecbuild/.project
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
- <name>ecbuild</name>
- <comment></comment>
- <projects>
- </projects>
- <buildSpec>
- <buildCommand>
- <name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
- <triggers>clean,full,incremental,</triggers>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
- <triggers>full,incremental,</triggers>
- <arguments>
- </arguments>
- </buildCommand>
- </buildSpec>
- <natures>
- <nature>org.eclipse.cdt.core.cnature</nature>
- <nature>org.eclipse.cdt.core.ccnature</nature>
- <nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
- <nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
- </natures>
-</projectDescription>
diff --git a/ecbuild/.settings/language.settings.xml b/ecbuild/.settings/language.settings.xml
deleted file mode 100644
index 1bf0c88..0000000
--- a/ecbuild/.settings/language.settings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<project>
- <configuration id="cdt.managedbuild.config.gnu.cross.exe.debug.1319857020" name="Debug">
- <extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
- <provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
- <provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
- <provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
- <provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="37260238735818327" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true">
- <language-scope id="org.eclipse.cdt.core.gcc"/>
- <language-scope id="org.eclipse.cdt.core.g++"/>
- </provider>
- </extension>
- </configuration>
- <configuration id="cdt.managedbuild.config.gnu.cross.exe.release.381634699" name="Release">
- <extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
- <provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
- <provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
- <provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
- <provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="37260238735818327" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true">
- <language-scope id="org.eclipse.cdt.core.gcc"/>
- <language-scope id="org.eclipse.cdt.core.g++"/>
- </provider>
- </extension>
- </configuration>
-</project>
diff --git a/ecbuild/AUTHORS b/ecbuild/AUTHORS
deleted file mode 100644
index 6da9a73..0000000
--- a/ecbuild/AUTHORS
+++ /dev/null
@@ -1,12 +0,0 @@
-eckit Authors
-=============
-
-eckit is mainly developed at the "European Centre for Medium-Range Weather Forecasts" (ECMWF, http://www.ecmwf.int).
-See attached LICENSE file for copyright.
-
-Developers:
-===========
-
-Tiago Quintino
-Baudouin Raoult
-Willem Deconinck
diff --git a/ecbuild/CMakeLists.txt b/ecbuild/CMakeLists.txt
deleted file mode 100644
index f610f16..0000000
--- a/ecbuild/CMakeLists.txt
+++ /dev/null
@@ -1,48 +0,0 @@
-############################################################################################
-# cmake options:
-#
-# -DCMAKE_INSTALL_PREFIX=/path/to/install
-
-cmake_minimum_required( VERSION 2.8.4 FATAL_ERROR )
-
-project( ecbuild C )
-
-set( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH} )
-
-include( ecbuild_system )
-
-###############################################################################
-# local project
-
-ecbuild_declare_project()
-
-configure_file( cmake/ecbuild_version.h.in ${CMAKE_BINARY_DIR}/ecbuild_version.h )
-
-ecbuild_add_option( FEATURE INSTALL
- DEFAULT OFF
- DESCRIPTION "Wether to install ecbuild files" )
-# contents
-
-ecbuild_add_resources( TARGET ${PROJECT_NAME}_description_files
- SOURCES_PACK
- INSTALL
- AUTHORS
- NOTICE
- LICENSE
- COPYING
-)
-
-add_subdirectory( bin )
-add_subdirectory( share )
-add_subdirectory( cmake )
-
-if( ENABLE_INSTALL )
- install( DIRECTORY cmake DESTINATION ${INSTALL_DATA_DIR} PATTERN "CMakeLists.txt" EXCLUDE )
-endif()
-
-############################################################################################
-# finalize
-
-ecbuild_install_project( NAME ${PROJECT_NAME} )
-
-ecbuild_print_summary()
diff --git a/ecbuild/COPYING b/ecbuild/COPYING
deleted file mode 100644
index 457b4a0..0000000
--- a/ecbuild/COPYING
+++ /dev/null
@@ -1,201 +0,0 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright 2007-2013 European Centre for Medium-Range Weather Forecasts (ECMWF)
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/ecbuild/INSTALL b/ecbuild/INSTALL
deleted file mode 100644
index 7b9deb1..0000000
--- a/ecbuild/INSTALL
+++ /dev/null
@@ -1,19 +0,0 @@
-============================
-ecbuild - ECMWF build system
-============================
-
-Installation and usage instructions can be found at:
-
-https://software.ecmwf.int/wiki/display/ECbuild/ecBuild
-
-=============
-QUICK INSTALL
-=============
-
-1. Extract the source files
-
- tar zxvf ecbuild-1.0.4-Source.tar.gz -C /path/to/install
-
-2. Use cmake and point the module path to the installed source.
-
- cmake -DCMAKE_MODULE_PATH=/path/to/install [...]
diff --git a/ecbuild/LICENSE b/ecbuild/LICENSE
deleted file mode 100644
index a82f8ec..0000000
--- a/ecbuild/LICENSE
+++ /dev/null
@@ -1,190 +0,0 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- Copyright 1996-2014 ECMWF
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/ecbuild/NOTICE b/ecbuild/NOTICE
deleted file mode 100644
index 414151a..0000000
--- a/ecbuild/NOTICE
+++ /dev/null
@@ -1,10 +0,0 @@
-Notice
-------
-
-1. The files FindLex and FindYacc are based on the FindBison and FindFlex macros from the original CMake code base.
- As requested, the License text has been preserved. The modifications are governed by the Apache License as described in COPYING.
-
-2. GetGitRevisionDescription macros are based on the macro with smae name from Ryan Pavlik <rpavlik at iastate.edu> and Iowa State
-University, and distributed under Booy, and distributed under Booy, and distributed under Booy, and distributed under Boost license.
-
-3. FindNetCDF4 macro is based on the macro FindNetCDF from project UCLALES from Max-Planck-Institut für Meteorologie.
diff --git a/ecbuild/VERSION.cmake b/ecbuild/VERSION.cmake
deleted file mode 120000
index ef90430..0000000
--- a/ecbuild/VERSION.cmake
+++ /dev/null
@@ -1 +0,0 @@
-cmake/VERSION.cmake
\ No newline at end of file
diff --git a/ecbuild/bin/CMakeLists.txt b/ecbuild/bin/CMakeLists.txt
deleted file mode 100644
index 680b5f7..0000000
--- a/ecbuild/bin/CMakeLists.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-list( APPEND ecbuild_bin_files
-ecbuild
-git-meld
-git-mproj
-check_install.sh
-apply_license.sh
-license.pl )
-
-add_custom_target( ecbuild_bin SOURCES ${ecbuild_bin_files} )
-
-if( ENABLE_INSTALL )
-
- install( PROGRAMS ecbuild DESTINATION ${INSTALL_BIN_DIR} )
-
-# install( PROGRAMS ${ecbuild_bin_files} DESTINATION ${INSTALL_BIN_DIR} )
-
-endif()
diff --git a/ecbuild/bin/apply_license.sh b/ecbuild/bin/apply_license.sh
deleted file mode 100755
index 5e36ca4..0000000
--- a/ecbuild/bin/apply_license.sh
+++ /dev/null
@@ -1,55 +0,0 @@
-#!/bin/bash
-
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-if [ -z $1 ]
-then
- echo "apply_license.sh"
- echo "usage: $0 [dir] [dir] ... "
- echo "dir - directory where to search"
- exit 1
-fi
-
-for f in $( find $DIRS $* \( \
- -iname "*.java" \
- -or -iname "*.xml" \
- -or -iname "*.sh" \
- -or -iname "*.pl" \
- -or -iname "*.pm" \
- -or -iname "*.py" \
- -or -iname "*.js" \
- -or -iname "*.c" \
- -or -iname "*.cpp" \
- -or -iname "*.cxx" \
- -or -iname "*.cc" \
- -or -iname "*.h" \
- -or -iname "*.hh" \
- -or -iname "*.hpp" \
- -or -iname "*.l" \
- -or -iname "*.y" \
- -or -iname "*.f" \
- -or -iname "*.F" \
- -or -iname "*.for" \
- -or -iname "*.f77" \
- -or -iname "*.f90" \
- -or -iname "*.cmake" \
- -or -iname "*.css" \
- -or -iname "*.sql" \
- -or -iname "*.properties" \
- -or -iname "*.def" \
- \) -print -follow | grep -v "\.git/" | grep -v "\.svn/" )
-do
-# echo $f
- license.pl -u $f
-done
-
-#| sed "s/ /\\\ /g" | \
-#xargs echo
-
-exit
diff --git a/ecbuild/bin/check_install.sh b/ecbuild/bin/check_install.sh
deleted file mode 100755
index 4e5369c..0000000
--- a/ecbuild/bin/check_install.sh
+++ /dev/null
@@ -1,76 +0,0 @@
-#!/bin/bash
-
-chksm="md5sum"
-manifest_file="manifest.txt"
-install_proc="echo_install"
-
-#------------------------------------------------------------------------------
-
-function abspath {
- if [[ -d "$1" ]]
- then
- pushd "$1" >/dev/null
- pwd
- popd >/dev/null
- elif [[ -e $1 ]]
- then
- pushd $(dirname $1) >/dev/null
- echo $(pwd)/$(basename $1)
- popd >/dev/null
- else
- echo "error: path $1 does not exist!" >&2
- return 127
- fi
-}
-
-function echo_install {
- echo "$1 -> $2"
-}
-
-#------------------------------------------------------------------------------
-
-if [ -z $2 ]
-then
- echo "usage: $0 <src_dir> <target_dir>"
- exit 1
-fi
-
-[[ ! -z $3 ]] && install_proc="$3"
-
-SRC=$(abspath $1)
-TGT=$(abspath $2)
-
-manifest="$SRC/$manifest_file"
-
-#------------------------------------------------------------------------------
-
-[[ ! -f $manifest ]] && echo "error: cannot find manifest.txt in dir $SRC" && exit 1
-
-cd $SRC
-
-for f in $(cat $manifest )
-do
-
- [[ ! -f "$SRC/$f" ]] && echo "error: $SRC/$f does not exist" && exit 1
-
- install="no"
-
- if [[ ! -f "$TGT/$f" ]]
- then
- install="yes"
- else
- srcsum=$( $chksm "$SRC/$f" | cut -d" " -f1 )
- tgtsum=$( $chksm "$TGT/$f" | cut -d" " -f1 )
-
- if [ $srcsum != "$tgtsum" ]
- then
- install="yes"
- fi
- fi
-
- if [ $install == "yes" ]
- then
- $install_proc $SRC/$f $TGT/$f
- fi
-
-done
diff --git a/ecbuild/bin/ecbuild b/ecbuild/bin/ecbuild
deleted file mode 100755
index 53817b5..0000000
--- a/ecbuild/bin/ecbuild
+++ /dev/null
@@ -1,267 +0,0 @@
-#!/bin/bash
-
-usage()
-{
- echo "Usage: ecbuild [--help] [--version]"
- exit $1
-}
-
-help()
-{
- cat <<EOF
-USAGE:
-
- ecbuild [--help] [--version] [--toolchains]
- ecbuild [option...] [--] [cmake-argument...] <path-to-source>
- ecbuild [option...] [--] [cmake-argument...] <path-to-existing-build>
-
-DESCRIPTION:
-
- ecbuild is a build system based on CMake, but providing a lot of macro's
- to make it easier to work with. Upon execution,
- the equivalent cmake command is printed.
-
- ecbuild/cmake must be called from an out-of-source build directory and
- forbids in-source builds.
-
-SYNOPSIS:
-
- --help Display this help
- --version Display ecbuild version
- --toolchains Display list of pre-installed toolchains (see below)
-
-
-Available values for "option":
-
- --prefix=<prefix>
- Set the install path to <prefix>.
- Equivalent to cmake argument "-D CMAKE_INSTALL_PREFIX=<prefix>"
-
- --build=<build-type>
- Set the build-type to <build-type>.
- Equivalent to cmake argument "-D CMAKE_BUILD_TYPE=<build-type>"
- <build-type> can be any of:
- - debug : Lowest optimization level, useful for debugging
- - release : Highest optimization level, for best performance
- - bit : Highest optimization level while staying bit-reproducible
- - ...others depending on project
-
- --static
- Build static libraries.
- Equivalent to "-D BUILD_SHARED_LIBS=OFF"
-
- --dynamic
- Build dynamic libraries (usually the default).
- Equivalent to "-D BUILD_SHARED_LIBS=ON"
-
- --toolchain=<toolchain>
- Use a platform specific toolchain, containing settings such
- as compilation flags, locations of commonly used dependencies.
- <toolchain> can be the path to a custom toolchain file, or a
- pre-installed toolchain provided with ecbuild. For a list of
- pre-installed toolchains, run "ecbuild --toolchains".
- Equivalent to cmake argument "-D CMAKE_TOOLCHAIN_FILE=<toolchain-file>"
-
- --cache=<ecbuild-cache-file> (advanced)
- A file called "ecbuild-cache.cmake" is generated during configuration.
- This file can be moved to a safe location, and specified for future
- builds to speed up checking of compiler/platform capabilities. Note that
- this is only accelerating fresh builds, as cmake internally caches also.
- Therefore this option is *not* recommended.
-
-
-Available values for "cmake-argument":
-
- Any value that can be usually passed to cmake to (re)configure the build.
- Typically these values start with "-D".
- example: -D ENABLE_TESTS=ON -D ENABLE_MPI=OFF -D ECKIT_PATH=...
-
- They can be explicitly separated from [option...] with a "--", for the case
- there is a conflicting option with the "cmake" executable, and the latter's
- option is requested.
-
-------------------------------------------------------------------------
-
-NOTE: When reconfiguring a build, it is only necessary to change the relevant
-options, as everything stays cached. For example:
- > ecbuild --prefix=PREFIX .
- > ecbuild -D ENABLE_TESTS=ON .
-
-------------------------------------------------------------------------
-
-Compiling:
-
- To compile the project with <N> threads:
- > make -j<N>
-
- To get verbose compilation/linking output:
- > make VERBOSE=1
-
-Testing:
-
- To run the project's tests
- > ctest
-
- Also check the ctest manual/help for more options on running tests
-
-Installing:
-
- To install the project in location PREFIX with
- "--prefix=PREFIX" or
- "-D CMAKE_INSTALL_PREFIX=PREFIX"
- > make install
-
-------------------------------------------------------------------------
-ECMWF"
-
-EOF
- exit $1
-}
-
-
-INSTALL_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-ECBUILD_MODULE_PATH=$INSTALL_DIR/../share/ecbuild/cmake
-ECBUILD_MODULE_PATH=$(cd $(dirname "$ECBUILD_MODULE_PATH") && pwd -P)/$(basename "$ECBUILD_MODULE_PATH")
-ADD_ECBUILD_OPTIONS="-D CMAKE_MODULE_PATH=$ECBUILD_MODULE_PATH"
-
-version()
-{
- # todo: do some clever regex of the VERSION.cmake file
- echo "ecbuild version 1.6.0"
- command -v cmake >/dev/null 2>&1 || { exit 0; }
- cmake --version | head -1
- exit 0
-}
-
-toolchains()
-{
- toolchains_dir=$INSTALL_DIR/../share/ecbuild/toolchains/
- cd $toolchains_dir
- echo "Available toolchains:"
- ls | while read fname
- do
- echo " - ${fname%%.*}"
- done
- exit 0
-}
-
-prefix()
-{
- arg=$1
- path=$(cd $(dirname "$arg") && pwd -P)/$(basename "$arg")
- ADD_ECBUILD_OPTIONS="$ADD_ECBUILD_OPTIONS -D CMAKE_INSTALL_PREFIX=${path}"
-}
-
-toolchain()
-{
- arg=$1
- if [ -f $arg ]; then
- toolchain_file=$arg
- else
- if [ -f $INSTALL_DIR/../share/ecbuild/toolchains/$arg.cmake ]; then
- toolchain_file=$INSTALL_DIR/../share/ecbuild/toolchains/$arg.cmake
- fi
- fi
- if [ -z ${toolchain_file+x} ]; then
- toolchains_dir=$INSTALL_DIR/../share/ecbuild/toolchains/
- toolchains_dir=$(cd $(dirname "$toolchains_dir") && pwd -P)/$(basename "$toolchains_dir")
- echo "Error:"
- echo " Toolchain [$arg] is not valid: [$arg.cmake] cannot be"
- echo " found in [$toolchains_dir]"
- exit 1
- else
- toolchain_file=$(cd $(dirname "$toolchain_file") && pwd -P)/$(basename "$toolchain_file")
- ADD_ECBUILD_OPTIONS="$ADD_ECBUILD_OPTIONS -D CMAKE_TOOLCHAIN_FILE=${toolchain_file}"
- fi
-}
-
-cache()
-{
- arg=$1
- if [ -f $arg ]; then
- cache_file=$(cd $(dirname "$arg") && pwd -P)/$(basename "$arg")
- else
- echo "Error:"
- echo " Cache file [$arg] is not found."
- exit 1
- fi
- ADD_ECBUILD_OPTIONS="$ADD_ECBUILD_OPTIONS -D ECBUILD_CACHE=${cache_file}"
-}
-
-if test $# -eq 0; then
- usage 1
-fi
-
-while test $# -gt 0; do
- # Split --option=value in $opt="--option" and $val="value"
- case "$1" in
- --*=*)
- opt=`echo "$1" | sed 's/=.*//'`
- val=`echo "$1" | sed 's/--[_a-zA-Z0-9]*=//'`
- ;;
- --*)
- opt=$1
- ;;
- *)
- break
- ;;
- esac
- # Parse options
- case "$opt" in
- --help)
- help 0
- ;;
- --version)
- version
- ;;
- --toolchains)
- toolchains
- ;;
- --prefix)
- prefix $val
- ;;
- --build)
- ADD_ECBUILD_OPTIONS="$ADD_ECBUILD_OPTIONS -D CMAKE_BUILD_TYPE=$val"
- ;;
- --static)
- ADD_ECBUILD_OPTIONS="$ADD_ECBUILD_OPTIONS -D BUILD_SHARED_LIBS=OFF"
- ;;
- --dynamic)
- ADD_ECBUILD_OPTIONS="$ADD_ECBUILD_OPTIONS -D BUILD_SHARED_LIBS=ON"
- ;;
- --toolchain)
- toolchain $val
- ;;
- --cache)
- cache $val
- ;;
- --)
- shift
- break
- ;;
- *)
- echo "unknown option: $opt"
- usage 1
- ;;
- esac
- shift
-done
-
-# Check if cmake is available
-command -v cmake >/dev/null 2>&1 || {
- echo "cmake is required and cannot be found in the PATH." >&2
- echo " Try 'module load cmake'" >&2
- echo "PATH=$PATH" >&2
- exit 1;
-}
-
-# If no arguments remain, set SOURCE to "."
-if [ $# -eq 0 ]; then
- SOURCE="."
-fi
-
-COMMAND="cmake ${ADD_ECBUILD_OPTIONS} $@ $SOURCE"
-echo ""
-echo $COMMAND
-echo ""
-$COMMAND
diff --git a/ecbuild/bin/git-meld b/ecbuild/bin/git-meld
deleted file mode 100755
index 3f1e353..0000000
--- a/ecbuild/bin/git-meld
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-
-meld $2 $5
diff --git a/ecbuild/bin/git-mproj b/ecbuild/bin/git-mproj
deleted file mode 100755
index 7ec0e4b..0000000
--- a/ecbuild/bin/git-mproj
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/bin/bash
-#
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-#
-# git-proj: status, branch, checkout
-#
-
-txtbld=$(tput bold) # bold
-bldblu=${txtbld}$(tput setaf 6) # bold cyan
-txtrst=$(tput sgr0) # reset
-
-dashless=$(basename "$0" | sed -e 's/-/ /')
-USAGE="$dashless <command> [options...]"
-
-SUBDIRECTORY_OK="yes"
-
-PATH=$(git --exec-path):$PATH
-. git-sh-setup
-
-require_work_tree_exists
-
-# go to top
-
-cd_to_toplevel
-cd ..
-
-# check option for number of levels
-nlevels=$(git config --global --int --get mproj.levels)
-if [ "$nlevels" != "" ]
-then
- nlevels="-maxdepth $nlevels"
-fi
-
-# do it
-
-for d in $( find $PWD $nlevels -type d -iname ".git" )
-do
- gdir=$(dirname $d)
- proj=$(basename $gdir)
- pushd $gdir > /dev/null
- branch=$(git symbolic-ref --short HEAD)
- echo -e "${bldblu}---> $proj ($branch)${txtrst}"
- git "$@"
- popd > /dev/null
-done
-
-
diff --git a/ecbuild/bin/license.pl b/ecbuild/bin/license.pl
deleted file mode 100755
index 020af24..0000000
--- a/ecbuild/bin/license.pl
+++ /dev/null
@@ -1,150 +0,0 @@
-#!/usr/bin/perl
-
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-use strict;
-
-my $LICENSE = <<"EOF";
-(C) Copyright 1996-2014 ECMWF.
-
-This software is licensed under the terms of the Apache Licence Version 2.0
-which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-In applying this licence, ECMWF does not waive the privileges and immunities
-granted to it by virtue of its status as an intergovernmental organisation nor
-does it submit to any jurisdiction.
-EOF
-
-my %COMMENTS = (
-
- java => { start => "/*\n" , end => " */\n\n" , comment => " * " },
- xml => { start => "<!--\n", end => "-->\n\n" , after => "\<\?xml[^<]*\>" },
-# xsd => { start => "<!--\n", end => "-->\n\n" },
-# jsp => { start => "<!--\n", end => "-->\n\n" },
- sh => { comment => "# ", end => "\n", after => "^#!/.*\n" },
- pl => { comment => "# ", end => "\n", after => "^#!/.*\n" },
- pm => { comment => "# ", end => "\n", after => "^#!/.*\n" },
- py => { comment => "# ", end => "\n", after => "^#!/.*\n" },
- js => { start => "/*\n" , end => " */\n\n" , comment => " * " },
- c => { start => "/*\n" , end => " */\n\n" , comment => " * " },
- cc => { start => "/*\n" , end => " */\n\n" , comment => " * " },
- cpp => { start => "/*\n" , end => " */\n\n" , comment => " * " },
- cxx => { start => "/*\n" , end => " */\n\n" , comment => " * " },
- h => { start => "/*\n" , end => " */\n\n" , comment => " * " },
- hh => { start => "/*\n" , end => " */\n\n" , comment => " * " },
- hpp => { start => "/*\n" , end => " */\n\n" , comment => " * " },
- l => { start => "/*\n" , end => " */\n\n" , comment => " * " },
- 'y' => { start => "/*\n" , end => " */\n\n" , comment => " * " },
- 'f' => { comment => "C ", end => "C\n\n" }, # assume f77
- 'F' => { comment => "C ", end => "C\n\n" }, # assume f77
- 'for' => { comment => "C ", end => "C\n\n" }, # assume f77
- 'f77' => { comment => "C ", end => "C\n\n" },
- 'f90' => { comment => "! ", end => "!\n\n" },
- cmake => { end => "\n", comment => "# " },
- css => { start => "/*\n" , end => " */\n\n" , comment => " * " },
- sql => { comment => "-- ", end => "\n" },
- properties => { comment => "# ", end => "\n" },
- def => { comment => "# ", end => "\n" },
-
- );
-
-my %cmdargs = map { $_ => 1 } @ARGV;
-
-foreach my $file ( @ARGV )
-{
- next if( $file eq "-u" or $file eq "--update" );
-
-# my $doit=0;
- my $doit=1;
-
- $file =~ /\.(\w+)$/;
- my $ext = $1;
-
- my $c = $COMMENTS{$ext};
-
- unless($c)
- {
- print "$file: unsupported extension. File ignored\n";
- next;
- }
-
- open(IN,"<$file") or die "$file: $!";
- my @text = <IN>;
- close(IN);
-
- if(join("", at text) =~ /icensed under the/gs)
- {
- if( exists( $cmdargs{"-u"} ) or exists( $cmdargs{"--update"} ) )
- {
- # lets update the year if needed
- my $currentyear = (localtime)[5] + 1900;
- if($doit)
- {
- print("$file: updating license year to $currentyear\n");
- system("perl -pi -e 's/Copyright ([0-9]{4})-[0-9]{4} ECMWF/Copyright \$1-$currentyear ECMWF/' $file");
- }
- }
- else
- {
- print "$file: License already stated. File ignored\n";
- }
- next;
- }
-
- open(OUT,">$file.tmp") or die "$file.tmp: $!";
-
- if($c->{after})
- {
- my @x;
- my $re = $c->{after};
- loop: while(@text)
- {
- if($text[0] =~ m/$re/)
- {
- print OUT @x, shift @text;
- @x = ();
- last loop;
- }
- push @x,shift @text;
- }
- @text = (@x, at text);
- }
-
- print OUT $c->{start};
- foreach my $line ( split("\n",$LICENSE) )
- {
- print OUT $c->{comment}, $line,"\n";
- }
- print OUT $c->{end};
-
- print OUT @text;
- close(OUT) or die "$file: $!";
-
- if($doit)
- {
- use File::Copy qw(cp);
- use File::Compare qw(compare_text compare);
-
- if(compare_text("$file.tmp",$file))
- {
- print "UPDATING file $file\n";
- system("p4 edit $file") unless(-w $file);
-#s cp($file,"$file.old") or die "cp($file,$file.old): $!";
- cp("$file.tmp",$file) or die "cp($file.tmp,$file): $!";
- }
- }
- else
- {
- print "IGNORING file $file\n";
- }
-
- unlink("$file.tmp");
-
-
-}
-
diff --git a/ecbuild/cmake/CMakeLists.txt b/ecbuild/cmake/CMakeLists.txt
deleted file mode 100644
index d42a153..0000000
--- a/ecbuild/cmake/CMakeLists.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-file( GLOB_RECURSE ecbuild_support_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*" )
-
-ecbuild_add_resources( TARGET ${PROJECT_NAME}_ecbuild_support_files
- SOURCES_PACK
- ${ecbuild_support_files} )
diff --git a/ecbuild/cmake/CheckFortranSourceCompiles.cmake b/ecbuild/cmake/CheckFortranSourceCompiles.cmake
deleted file mode 100644
index ad4b91f..0000000
--- a/ecbuild/cmake/CheckFortranSourceCompiles.cmake
+++ /dev/null
@@ -1,94 +0,0 @@
-# - Check if given Fortran source compiles and links into an executable
-# CHECK_FORTRAN_SOURCE_COMPILES(<code> <var> [FAIL_REGEX <fail-regex>])
-# <code> - source code to try to compile, must define 'main'
-# <var> - variable to store whether the source code compiled
-# <fail-regex> - fail if test output matches this regex
-# The following variables may be set before calling this macro to
-# modify the way the check is run:
-#
-# CMAKE_REQUIRED_FLAGS = string of compile command line flags
-# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
-# CMAKE_REQUIRED_INCLUDES = list of include directories
-# CMAKE_REQUIRED_LIBRARIES = list of libraries to link
-
-#=============================================================================
-# Copyright 2005-2009 Kitware, Inc.
-# Fortran version, 2013, James Tappin
-#
-# Distributed under the OSI-approved BSD License (the "License");
-# see accompanying file Copyright.txt for details.
-#
-# This software is distributed WITHOUT ANY WARRANTY; without even the
-# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the License for more information.
-#=============================================================================
-# (To distribute this file outside of CMake, substitute the full
-# License text for the above reference.)
-
-
-
-macro(CHECK_FORTRAN_SOURCE_COMPILES SOURCE VAR)
-
-if("${VAR}" MATCHES "^${VAR}$")
- set(_FAIL_REGEX)
- set(_key)
- foreach(arg ${ARGN})
- if("${arg}" MATCHES "^(FAIL_REGEX)$")
- set(_key "${arg}")
- elseif(_key)
- list(APPEND _${_key} "${arg}")
- else()
- message(FATAL_ERROR "Unknown argument:\n ${arg}\n")
- endif()
- endforeach()
- set(MACRO_CHECK_FUNCTION_DEFINITIONS
- "-D${VAR} ${CMAKE_REQUIRED_FLAGS}")
- if(CMAKE_REQUIRED_LIBRARIES)
- set(CHECK_FORTRAN_SOURCE_COMPILES_ADD_LIBRARIES
- LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES})
- else()
- set(CHECK_FORTRAN_SOURCE_COMPILES_ADD_LIBRARIES)
- endif()
- if(CMAKE_REQUIRED_INCLUDES)
- set(CHECK_FORTRAN_SOURCE_COMPILES_ADD_INCLUDES
- "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}")
- else()
- set(CHECK_FORTRAN_SOURCE_COMPILES_ADD_INCLUDES)
- endif()
- file(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.f90"
- "${SOURCE}\n")
-
- message(STATUS "Performing Test ${VAR}")
- try_compile(${VAR}
- ${CMAKE_BINARY_DIR}
- ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.f90
- COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
- ${CHECK_FORTRAN_SOURCE_COMPILES_ADD_LIBRARIES}
- CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS}
- "${CHECK_FORTRAN_SOURCE_COMPILES_ADD_INCLUDES}"
- OUTPUT_VARIABLE OUTPUT)
-
- foreach(_regex ${_FAIL_REGEX})
- if("${OUTPUT}" MATCHES "${_regex}")
- set(${VAR} 0)
- endif()
- endforeach()
-
- if(${VAR})
- set(${VAR} 1 CACHE INTERNAL "Test ${VAR}")
- message(STATUS "Performing Test ${VAR} - Success")
- file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
- "Performing Fortran SOURCE FILE Test ${VAR} succeded with the following output:\n"
- "${OUTPUT}\n"
- "Source file was:\n${SOURCE}\n")
- else()
- message(STATUS "Performing Test ${VAR} - Failed")
- set(${VAR} "" CACHE INTERNAL "Test ${VAR}")
- file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
- "Performing Fortran SOURCE FILE Test ${VAR} failed with the following output:\n"
- "${OUTPUT}\n"
- "Source file was:\n${SOURCE}\n")
- endif()
- endif()
-endmacro()
-
diff --git a/ecbuild/cmake/FindADSM.cmake b/ecbuild/cmake/FindADSM.cmake
deleted file mode 100644
index 76140b6..0000000
--- a/ecbuild/cmake/FindADSM.cmake
+++ /dev/null
@@ -1,43 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-# - Try to find ADSM
-# Once done this will define
-# ADSM_FOUND - System has ADSM
-# ADSM_INCLUDE_DIRS - The ADSM include directories
-# ADSM_LIBRARIES - The libraries needed to use ADSM
-
-if( EC_OS_BITS EQUAL 32 )
- set( ADSM_LIBNAME ApiDS )
-endif()
-if( EC_OS_BITS EQUAL 64 )
- set( ADSM_LIBNAME ApiTSM64 )
-endif()
-if( NOT DEFINED ADSM_LIBNAME )
- message( STATUS "MARS only supports ADSM with 32 or 64 bits" )
-endif()
-
-if( DEFINED ADSM_PATH )
- find_path(ADSM_INCLUDE_DIR dsmapitd.h PATHS ${ADSM_PATH} ${ADSM_PATH}/include ${ADSM_PATH}/sample NO_DEFAULT_PATH )
- find_library(ADSM_LIBRARY ${ADSM_LIBNAME} PATHS ${ADSM_PATH} ${ADSM_PATH}/lib ${ADSM_PATH}/lib64 NO_DEFAULT_PATH )
-endif()
-
-find_path(ADSM_INCLUDE_DIR dsmapitd.h PATH_SUFFIXES bin64 )
-find_library( ADSM_LIBRARY ${ADSM_LIBNAME} PATH_SUFFIXES bin64 )
-
-set( ADSM_LIBRARIES ${ADSM_LIBRARY} )
-set( ADSM_INCLUDE_DIRS ${ADSM_INCLUDE_DIR} )
-
-include(FindPackageHandleStandardArgs)
-
-# handle the QUIETLY and REQUIRED arguments and set ADSM_FOUND to TRUE
-# if all listed variables are TRUE
-find_package_handle_standard_args(ADSM DEFAULT_MSG
- ADSM_LIBRARY ADSM_INCLUDE_DIR)
-
-mark_as_advanced(ADSM_INCLUDE_DIR ADSM_LIBRARY )
diff --git a/ecbuild/cmake/FindAEC.cmake b/ecbuild/cmake/FindAEC.cmake
deleted file mode 100644
index 70a63b1..0000000
--- a/ecbuild/cmake/FindAEC.cmake
+++ /dev/null
@@ -1,34 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-# - Try to find AEC (Adaptive Entropy Coding library)
-# See https://www.dkrz.de/redmine/projects/aec/wiki
-
-# Once done this will define
-# AEC_FOUND - System has AEC
-# AEC_INCLUDE_DIRS - The AEC include directories
-# AEC_LIBRARIES - The libraries needed to use AEC
-
-ecbuild_add_extra_search_paths( aec )
-
-if( DEFINED AEC_PATH )
- find_path( AEC_INCLUDE_DIR szlib.h PATHS ${AEC_PATH}/include PATH_SUFFIXES aec NO_DEFAULT_PATH )
- find_library( AEC_LIBRARY NAMES aec PATHS ${AEC_PATH}/lib PATH_SUFFIXES aec NO_DEFAULT_PATH )
-endif()
-
-find_path( AEC_INCLUDE_DIR szlib.h PATH_SUFFIXES aec )
-find_library( AEC_LIBRARY NAMES aec PATH_SUFFIXES aec )
-
-set( AEC_LIBRARIES ${AEC_LIBRARY} )
-set( AEC_INCLUDE_DIRS ${AEC_INCLUDE_DIR} )
-
-include(FindPackageHandleStandardArgs)
-
-find_package_handle_standard_args(AEC DEFAULT_MSG AEC_LIBRARY AEC_INCLUDE_DIR)
-
-mark_as_advanced(AEC_INCLUDE_DIR AEC_LIBRARY )
diff --git a/ecbuild/cmake/FindAIO.cmake b/ecbuild/cmake/FindAIO.cmake
deleted file mode 100644
index 61fdcc0..0000000
--- a/ecbuild/cmake/FindAIO.cmake
+++ /dev/null
@@ -1,66 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-# OUTPUT:
-# RT_LIB = the library to link against
-
-if( CMAKE_SYSTEM_NAME MATCHES "Linux" )
-
- find_package( Realtime )
-
- if( REALTIME_FOUND ) # check that aio needs realtime
- set( AIO_LIBRARIES ${RT_LIB} )
- endif()
-
-endif()
-
-find_path( AIO_INCLUDE_DIRS NAMES aio.h HINTS ENV AIO_PATH ${AIO_PATH} )
-
-mark_as_advanced( AIO_INCLUDE_DIRS )
-
-include(FindPackageHandleStandardArgs)
-
-find_package_handle_standard_args( AIO DEFAULT_MSG AIO_INCLUDE_DIRS )
-
-# checks for AIO64 vs AIO
-if( AIO_FOUND )
-
- include( CheckCSourceCompiles )
- include( CMakePushCheckState )
-
- cmake_push_check_state()
-
- set( CMAKE_REQUIRED_INCLUDES ${AIO_INCLUDE_DIRS} )
-
- if( AIO_LIBRARIES )
- set( CMAKE_REQUIRED_LIBRARIES ${AIO_LIBRARIES} )
- endif()
-
- check_c_source_compiles( "#include <aio.h>
- #include <fcntl.h>
- int main(){
- struct aiocb* aiocbp;
- int n = aio_write(aiocbp);
- n = aio_read(aiocbp);
- n = aio_fsync(O_SYNC,aiocbp);
- return 0; }"
- EC_HAVE_AIOCB )
-
- check_c_source_compiles( "#include <aio.h>
- #include <fcntl.h>
- int main(){
- struct aiocb64* aiocbp;
- int n = aio_write64(aiocbp);
- n = aio_read64(aiocbp);
- n = aio_fsync64(O_SYNC,aiocbp);
- return 0; }"
- EC_HAVE_AIOCB64 )
-
- cmake_pop_check_state()
-
-endif()
diff --git a/ecbuild/cmake/FindArmadillo.cmake b/ecbuild/cmake/FindArmadillo.cmake
deleted file mode 100644
index ba14e2e..0000000
--- a/ecbuild/cmake/FindArmadillo.cmake
+++ /dev/null
@@ -1,33 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-ecbuild_add_extra_search_paths( armadillo )
-
-IF( NOT DEFINED ARMADILLO_PATH AND NOT "$ENV{ARMADILLO_PATH}" STREQUAL "" )
- SET( ARMADILLO_PATH "$ENV{ARMADILLO_PATH}" )
-ENDIF()
-
-if( DEFINED ARMADILLO_PATH )
- find_path(ARMADILLO_INCLUDE_DIR ARMADILLO.h PATHS ${ARMADILLO_PATH}/include PATH_SUFFIXES ARMADILLO NO_DEFAULT_PATH)
- find_library(ARMADILLO_LIBRARY ARMADILLO PATHS ${ARMADILLO_PATH}/lib PATH_SUFFIXES ARMADILLO NO_DEFAULT_PATH)
-endif()
-
-find_path(ARMADILLO_INCLUDE_DIR armadillo PATH_SUFFIXES include )
-find_library( ARMADILLO_LIBRARY armadillo PATH_SUFFIXES lib )
-
-set( ARMADILLO_LIBRARIES ${ARMADILLO_LIBRARY} )
-set( ARMADILLO_INCLUDE_DIRS ${ARMADILLO_INCLUDE_DIR} )
-
-include(FindPackageHandleStandardArgs)
-
-# handle the QUIETLY and REQUIRED arguments and set ARMADILLO_FOUND to TRUE
-# if all listed variables are TRUE
-find_package_handle_standard_args(ARMADILLO DEFAULT_MSG
- ARMADILLO_LIBRARY ARMADILLO_INCLUDE_DIR)
-
-mark_as_advanced(ARMADILLO_INCLUDE_DIR ARMADILLO_LIBRARY )
diff --git a/ecbuild/cmake/FindCMath.cmake b/ecbuild/cmake/FindCMath.cmake
deleted file mode 100644
index 7cf6f58..0000000
--- a/ecbuild/cmake/FindCMath.cmake
+++ /dev/null
@@ -1,23 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-#Sets:
-# CMATH_LIBRARIES = the library to link against (RT etc)
-
-IF(UNIX)
- if( DEFINED CMATH_PATH )
- find_library(CMATH_LIBRARIES m PATHS ${CMATH_PATH}/lib NO_DEFAULT_PATH )
- endif()
-
- find_library(CMATH_LIBRARIES m )
-
- include(FindPackageHandleStandardArgs)
-
- find_package_handle_standard_args(CMATH DEFAULT_MSG CMATH_LIBRARIES )
-
-ENDIF(UNIX)
diff --git a/ecbuild/cmake/FindCairo.cmake b/ecbuild/cmake/FindCairo.cmake
deleted file mode 100644
index 7b3d47e..0000000
--- a/ecbuild/cmake/FindCairo.cmake
+++ /dev/null
@@ -1,58 +0,0 @@
-# - Try to find the cairo library
-# Once done this will define
-#
-# CAIRO_FOUND - system has cairo
-# CAIRO_INCLUDE_DIRS - the cairo include directory
-# CAIRO_LIBRARIES - Link these to use cairo
-#
-# Define CAIRO_MIN_VERSION for which version desired.
-
-
-if( NOT DEFINED CAIRO_PATH AND NOT "$ENV{CAIRO_PATH}" STREQUAL "" )
- set( APPEND CAIRO_PATH "$ENV{CAIRO_PATH}" )
-endif()
-
-if( NOT DEFINED CAIRO_PATH )
-
- include(FindPkgConfig)
-
- if(Cairo_FIND_REQUIRED)
- set(_pkgconfig_REQUIRED "REQUIRED")
- else()
- set(_pkgconfig_REQUIRED "")
- endif()
-
- if(CAIRO_MIN_VERSION)
- pkg_check_modules(PKCAIRO ${_pkgconfig_REQUIRED} cairo>=${CAIRO_MIN_VERSION})
- else()
- pkg_check_modules(PKCAIRO ${_pkgconfig_REQUIRED} cairo)
- endif()
-
- if( PKG_CONFIG_FOUND AND PKCAIRO_FOUND )
-
- find_path(CAIRO_INCLUDE_DIR cairo.h HINTS ${PKCAIRO_INCLUDEDIR} ${PKCAIRO_INCLUDE_DIRS} PATH_SUFFIXES cairo NO_DEFAULT_PATH )
- find_library(CAIRO_LIBRARY cairo HINTS ${PKCAIRO_LIBDIR} ${PKCAIRO_LIBRARY_DIRS} PATH_SUFFIXES cairo NO_DEFAULT_PATH )
-
- endif()
-
-else()
-
- find_path(CAIRO_INCLUDE_DIR cairo.h PATHS ${CAIRO_PATH}/include PATH_SUFFIXES cairo NO_DEFAULT_PATH )
- find_library(CAIRO_LIBRARY cairo PATHS ${CAIRO_PATH}/lib PATH_SUFFIXES cairo NO_DEFAULT_PATH )
-
-endif()
-
-find_path(CAIRO_INCLUDE_DIR cairo.h PATH_SUFFIXES cairo )
-find_library( CAIRO_LIBRARY cairo PATH_SUFFIXES cairo )
-
-set( CAIRO_LIBRARIES ${CAIRO_LIBRARY} )
-set( CAIRO_INCLUDE_DIRS ${CAIRO_INCLUDE_DIR} )
-
-include(FindPackageHandleStandardArgs)
-
-# handle the QUIETLY and REQUIRED arguments and set GRIBAPI_FOUND to TRUE
-# if all listed variables are TRUE
-find_package_handle_standard_args(CAIRO DEFAULT_MSG
- CAIRO_LIBRARY CAIRO_INCLUDE_DIR)
-
-mark_as_advanced( CAIRO_INCLUDE_DIR CAIRO_LIBRARY )
diff --git a/ecbuild/cmake/FindDl.cmake b/ecbuild/cmake/FindDl.cmake
deleted file mode 100644
index 305fff0..0000000
--- a/ecbuild/cmake/FindDl.cmake
+++ /dev/null
@@ -1,20 +0,0 @@
-# © Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-#Sets:
-# DL_LIBRARIES = the library to link against (RT etc)
-
-if( DEFINED DL_PATH )
- find_library(DL_LIBRARIES dl PATHS ${DL_PATH}/lib NO_DEFAULT_PATH )
-endif()
-
-find_library(DL_LIBRARIES dl )
-
-include(FindPackageHandleStandardArgs)
-
-find_package_handle_standard_args(DL DEFAULT_MSG DL_LIBRARIES )
diff --git a/ecbuild/cmake/FindEMOS.cmake b/ecbuild/cmake/FindEMOS.cmake
deleted file mode 100644
index 8472b0a..0000000
--- a/ecbuild/cmake/FindEMOS.cmake
+++ /dev/null
@@ -1,37 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-# - Try to find EMOS
-# Once done this will define
-# EMOS_FOUND - System has EMOS
-# EMOS_INCLUDE_DIRS - The EMOS include directories
-# EMOS_LIBRARIES - The libraries needed to use EMOS
-
-ecbuild_add_extra_search_paths( libemos )
-
-if( NOT DEFINED EMOS_PATH AND DEFINED $ENV{EMOS_PATH} )
- set( EMOS_PATH $ENV{EMOS_PATH} )
-endif()
-
-if( DEFINED EMOS_PATH )
- find_library( EMOS_LIBRARY NAMES emos.R64.D64.I32 emos.R64 emosR64 emos PATHS ${EMOS_PATH} PATH_SUFFIXES lib lib/emos NO_DEFAULT_PATH)
-endif()
-
-find_library( EMOS_LIBRARY NAMES emos.R64.D64.I32 emos.R64 emosR64 emos)
-
-ecbuild_find_fortranlibs()
-
-include(FindPackageHandleStandardArgs)
-
-find_package_handle_standard_args( EMOS DEFAULT_MSG EMOS_LIBRARY FORTRANLIBS_FOUND )
-
-mark_as_advanced(EMOS_LIBRARY)
-
-if( EMOS_FOUND )
- set( EMOS_LIBRARIES ${EMOS_LIBRARY} ${FORTRAN_LIBRARIES} )
-endif()
diff --git a/ecbuild/cmake/FindEcLib.cmake b/ecbuild/cmake/FindEcLib.cmake
deleted file mode 100644
index 5799c85..0000000
--- a/ecbuild/cmake/FindEcLib.cmake
+++ /dev/null
@@ -1,49 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-# - Try to find EcLib
-# Once done this will define
-# ECLIB_FOUND - System has ECLIB
-# ECLIB_INCLUDE_DIRS - The ECLIB include directories
-# ECLIB_LIBRARIES - The libraries needed to use ECLIB
-
-# skip if ECLIB is already found or if has is built inside
-
-if( NOT ECLIB_FOUND )
-
- # find external eclib
-
- set( _ENV_ECLIB_PATH "$ENV{ECLIB_PATH}" )
- if( NOT DEFINED ECLIB_PATH AND _ENV_ECLIB_PATH )
- set( ECLIB_PATH ${_ENV_ECLIB_PATH} )
- endif()
-
- if( DEFINED ECLIB_PATH )
- find_path(ECLIB_INCLUDE_DIR NAMES eclib_version.h PATHS ${ECLIB_PATH} ${ECLIB_PATH}/include PATH_SUFFIXES eclib NO_DEFAULT_PATH)
- find_library(ECLIB_LIBRARY NAMES Ec PATHS ${ECLIB_PATH} ${ECLIB_PATH}/lib PATH_SUFFIXES eclib NO_DEFAULT_PATH)
- endif()
-
- find_path(ECLIB_INCLUDE_DIR NAMES eclib_version.h PATH_SUFFIXES eclib )
- find_library( ECLIB_LIBRARY NAMES Ec PATH_SUFFIXES eclib )
-
- include(FindPackageHandleStandardArgs)
-
- # handle the QUIETLY and REQUIRED arguments and set ECLIB_FOUND to TRUE
- # if all listed variables are TRUE
- find_package_handle_standard_args(ECLIB DEFAULT_MSG
- ECLIB_LIBRARY ECLIB_INCLUDE_DIR )
-
- mark_as_advanced(ECLIB_INCLUDE_DIR ECLIB_LIBRARY )
-
- set( ECLIB_LIBRARIES ${ECLIB_LIBRARY} )
- set( ECLIB_INCLUDE_DIRS ${ECLIB_INCLUDE_DIR} )
-
- debug_var( ECLIB_LIBRARIES )
- debug_var( ECLIB_INCLUDE_DIRS )
-
-endif()
diff --git a/ecbuild/cmake/FindEcregrid.cmake b/ecbuild/cmake/FindEcregrid.cmake
deleted file mode 100644
index 3ddf732..0000000
--- a/ecbuild/cmake/FindEcregrid.cmake
+++ /dev/null
@@ -1,48 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-# - Try to find ECREGRID
-# Once done this will define
-# ECREGRID_FOUND - System has ECREGRID
-# ECREGRID_INCLUDE_DIRS - The ECREGRID include directories
-# ECREGRID_LIBRARIES - The libraries needed to use ECREGRID
-# ECREGRID_DEFINITIONS - Compiler switches required for using ECREGRID
-
-option( WITH_ECREGRID "try to find scin installation" ON )
-
-# skip if ECREGRID is already found or if has is built inside
-
-if( NOT ECREGRID_FOUND AND WITH_ECREGRID )
-
- if( NOT DEFINED ECREGRID_PATH AND NOT "$ENV{ECREGRID_PATH}" STREQUAL "" )
- list( APPEND ECREGRID_PATH "$ENV{ECREGRID_PATH}" )
- endif()
-
- if( DEFINED ECREGRID_PATH )
- find_path(ECREGRID_INCLUDE_DIR NAMES scin_api.h PATHS ${ECREGRID_PATH} ${ECREGRID_PATH}/include PATH_SUFFIXES scin_api NO_DEFAULT_PATH )
- find_library(ECREGRID_LIBRARY NAMES scin PATHS ${ECREGRID_PATH} ${ECREGRID_PATH}/lib PATH_SUFFIXES scin NO_DEFAULT_PATH )
- endif()
-
- find_path(ECREGRID_INCLUDE_DIR NAMES scin_api.h PATH_SUFFIXES scin_api )
- find_library( ECREGRID_LIBRARY NAMES scin PATH_SUFFIXES scin )
-
- include(FindPackageHandleStandardArgs)
-
- # handle the QUIETLY and REQUIRED arguments and set ECREGRID_FOUND to TRUE
- # if all listed variables are TRUE
- find_package_handle_standard_args(Scin DEFAULT_MSG
- ECREGRID_LIBRARY ECREGRID_INCLUDE_DIR)
-
- if( ECREGRID_FOUND )
- set( ECREGRID_LIBRARIES ${ECREGRID_LIBRARY} )
- set( ECREGRID_INCLUDE_DIRS ${ECREGRID_INCLUDE_DIR} )
- endif()
-
- mark_as_advanced(ECREGRID_INCLUDE_DIR ECREGRID_LIBRARY )
-
-endif()
diff --git a/ecbuild/cmake/FindFDB.cmake b/ecbuild/cmake/FindFDB.cmake
deleted file mode 100644
index 6624544..0000000
--- a/ecbuild/cmake/FindFDB.cmake
+++ /dev/null
@@ -1,35 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-# - Try to find FDB
-# Once done this will define
-# FDB_FOUND - System has FDB
-# FDB_INCLUDE_DIRS - The FDB include directories
-# FDB_LIBRARIES - The libraries needed to use FDB
-
-
-if( NOT FDB_FOUND )
-
- if( DEFINED FDB_PATH )
- find_library( FDB_LIBRARY NAMES fdb PATHS ${FDB_PATH} ${FDB_PATH}/lib NO_DEFAULT_PATH)
- endif()
-
- find_library( FDB_LIBRARY NAMES fdb )
-
- set( FDB_LIBRARIES ${FDB_LIBRARY} )
-
- include(FindPackageHandleStandardArgs)
-
- # handle the QUIETLY and REQUIRED arguments and set FDB_FOUND to TRUE
- # if all listed variables are TRUE
- find_package_handle_standard_args(FDB DEFAULT_MSG
- FDB_LIBRARY )
-
- mark_as_advanced(FDB_LIBRARY)
-
-endif()
diff --git a/ecbuild/cmake/FindGeoTIFF.cmake b/ecbuild/cmake/FindGeoTIFF.cmake
deleted file mode 100644
index f4f3b53..0000000
--- a/ecbuild/cmake/FindGeoTIFF.cmake
+++ /dev/null
@@ -1,37 +0,0 @@
-###############################################################################
-#
-# CMake module to search for GeoTIFF library
-#
-# On success, the macro sets the following variables:
-# GEOTIFF_FOUND = if the library found
-# GEOTIFF_LIBRARIES = full path to the library
-# GEOTIFF_INCLUDE_DIR = where to find the library headers
-# also defined, but not for general use are
-# GEOTIFF_LIBRARY, where to find the PROJ.4 library.
-#
-# Copyright (c) 2009 Mateusz Loskot <mateusz at loskot.net>
-#
-# Module source: http://github.com/mloskot/workshop/tree/master/cmake/
-#
-# Redistribution and use is allowed according to the terms of the BSD license.
-# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
-#
-###############################################################################
-
-SET(GEOTIFF_NAMES geotiff)
-
-
- FIND_PATH(GEOTIFF_INCLUDE_DIR geotiff.h PATH_PREFIXES geotiff
- PATHS /usr/local/include/libgeotiff /usr/include/libgeotiff)
-
- FIND_LIBRARY(GEOTIFF_LIBRARY NAMES ${GEOTIFF_NAMES})
-
-
-IF(GEOTIFF_FOUND)
- SET(GEOTIFF_LIBRARIES ${GEOTIFF_LIBRARY})
-ENDIF()
-
-# Handle the QUIETLY and REQUIRED arguments and set SPATIALINDEX_FOUND to TRUE
-# if all listed variables are TRUE
-INCLUDE(FindPackageHandleStandardArgs)
-FIND_PACKAGE_HANDLE_STANDARD_ARGS(GEOTIFF DEFAULT_MSG GEOTIFF_LIBRARY GEOTIFF_INCLUDE_DIR)
diff --git a/ecbuild/cmake/FindHPSS.cmake b/ecbuild/cmake/FindHPSS.cmake
deleted file mode 100644
index 50f95cc..0000000
--- a/ecbuild/cmake/FindHPSS.cmake
+++ /dev/null
@@ -1,39 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-# - Try to find HPSS
-# Once done this will define
-# HPSS_FOUND - System has HPSS
-# HPSS_INCLUDE_DIRS - The HPSS include directories
-# HPSS_LIBRARIES - The libraries needed to use HPSS
-# HPSS_DEFINITIONS - Compiler switches required for using HPSS
-
-if( DEFINED HPSS_PATH )
- find_path(HPSS_INCLUDE_DIR hpss_api.h PATHS ${HPSS_PATH}/include PATH_SUFFIXES hpss NO_DEFAULT_PATH)
- find_library(HPSS_LIBRARY hpss PATHS ${HPSS_PATH}/lib PATH_SUFFIXES hpss NO_DEFAULT_PATH)
-endif()
-
-find_path(HPSS_INCLUDE_DIR hpss_api.h PATH_SUFFIXES hpss )
-find_library( HPSS_LIBRARY hpss PATH_SUFFIXES hpss )
-
-include(FindPackageHandleStandardArgs)
-
-# handle the QUIETLY and REQUIRED arguments and set HPSS_FOUND to TRUE
-# if all listed variables are TRUE
-find_package_handle_standard_args(HPSS DEFAULT_MSG
- HPSS_LIBRARY HPSS_INCLUDE_DIR)
-
-mark_as_advanced(HPSS_INCLUDE_DIR HPSS_LIBRARY )
-
-if( HPSS_FOUND )
- set( HPSS_LIBRARIES ${HPSS_LIBRARY} )
- set( HPSS_INCLUDE_DIRS ${HPSS_INCLUDE_DIR} )
-else()
- set( HPSS_LIBRARIES "" )
- set( HPSS_INCLUDE_DIRS "" )
-endif()
diff --git a/ecbuild/cmake/FindLEX.cmake b/ecbuild/cmake/FindLEX.cmake
deleted file mode 100644
index 34ea36c..0000000
--- a/ecbuild/cmake/FindLEX.cmake
+++ /dev/null
@@ -1,129 +0,0 @@
-# - Find lex executable and provides a macro to generate custom build rules
-#
-# The module defines the following variables:
-# LEX_FOUND - true is lex executable is found
-# LEX_EXECUTABLE - the path to the lex executable
-# LEX_LIBRARIES - The lex libraries
-# LEX_INCLUDE_DIRS - The path to the lex headers
-#
-#
-# If lex is found on the system, the module provides the macro:
-# LEX_TARGET(Name LexInput LexOutput [COMPILE_FLAGS <string>])
-# which creates a custom command to generate the <LexOutput> file from
-# the <LexInput> file. If COMPILE_FLAGS option is specified, the next
-# parameter is added to the lex command line. Name is an alias used to
-# get details of this custom command. Indeed the macro defines the
-# following variables:
-# LEX_${Name}_DEFINED - true is the macro ran successfully
-# LEX_${Name}_OUTPUTS - the source file generated by the custom rule, an
-# alias for LexOutput
-# LEX_${Name}_INPUT - the lex source file, an alias for ${LexInput}
-#
-# Lex scanners oftenly use tokens defined by Yacc: the code generated
-# by Lex depends of the header generated by Yacc. This module also
-# defines a macro:
-# ADD_LEX_YACC_DEPENDENCY(LexTarget YaccTarget)
-# which adds the required dependency between a scanner and a parser
-# where <LexTarget> and <YaccTarget> are the first parameters of
-# respectively LEX_TARGET and YACC_TARGET macros.
-#
-# ====================================================================
-
-#=============================================================================
-# Copyright 2009 Kitware, Inc.
-# Copyright 2006 Tristan Carel
-#
-# Distributed under the OSI-approved BSD License (the "License");
-# see accompanying file Copyright.txt for details.
-#
-# This software is distributed WITHOUT ANY WARRANTY; without even the
-# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the License for more information.
-#=============================================================================
-
-# This file is based on the FindFLEX CMake macro, and adapted by ECMWF
-
-#=============================================================================
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-FIND_PROGRAM(LEX_EXECUTABLE lex DOC "path to the lex executable")
-MARK_AS_ADVANCED(LEX_EXECUTABLE)
-
-FIND_LIBRARY(FL_LIBRARY NAMES fl
- DOC "Path to the fl library")
-
-FIND_PATH(LEX_INCLUDE_DIR LexLexer.h
- DOC "Path to the lex headers")
-
-MARK_AS_ADVANCED(FL_LIBRARY LEX_INCLUDE_DIR)
-
-SET(LEX_INCLUDE_DIRS ${LEX_INCLUDE_DIR})
-SET(LEX_LIBRARIES ${FL_LIBRARY})
-
-IF(LEX_EXECUTABLE)
-
- #============================================================
- # LEX_TARGET (public macro)
- #============================================================
- #
- MACRO(LEX_TARGET Name Input Output)
- SET(LEX_TARGET_usage "LEX_TARGET(<Name> <Input> <Output> [COMPILE_FLAGS <string>]")
- IF(${ARGC} GREATER 3)
- IF(${ARGC} EQUAL 5)
- IF("${ARGV3}" STREQUAL "COMPILE_FLAGS")
- SET(LEX_EXECUTABLE_opts "${ARGV4}")
- SEPARATE_ARGUMENTS(LEX_EXECUTABLE_opts)
- ELSE()
- MESSAGE(SEND_ERROR ${LEX_TARGET_usage})
- ENDIF()
- ELSE()
- MESSAGE(SEND_ERROR ${LEX_TARGET_usage})
- ENDIF()
- ENDIF()
-
- message( STATUS "${LEX_EXECUTABLE} ${LEX_EXECUTABLE_opts} -t ${Input} > ${Output}" )
-
- ADD_CUSTOM_COMMAND(OUTPUT ${Output}
- COMMAND ${LEX_EXECUTABLE} ${LEX_EXECUTABLE_opts} -t ${Input} > ${Output}
- DEPENDS ${Input}
- COMMENT "[LEX][${Name}] Building scanner with lex ${LEX_VERSION}"
- WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
-
- SET(LEX_${Name}_DEFINED TRUE)
- SET(LEX_${Name}_OUTPUTS ${Output})
- SET(LEX_${Name}_INPUT ${Input})
- SET(LEX_${Name}_COMPILE_FLAGS ${LEX_EXECUTABLE_opts})
- ENDMACRO(LEX_TARGET)
- #============================================================
-
-
- #============================================================
- # ADD_LEX_YACC_DEPENDENCY (public macro)
- #============================================================
- #
- MACRO(ADD_LEX_YACC_DEPENDENCY LexTarget YaccTarget)
-
- IF(NOT LEX_${LexTarget}_OUTPUTS)
- MESSAGE(SEND_ERROR "Lex target `${LexTarget}' does not exists.")
- ENDIF()
-
- IF(NOT YACC_${YaccTarget}_OUTPUT_HEADER)
- MESSAGE(SEND_ERROR "Yacc target `${YaccTarget}' does not exists.")
- ENDIF()
-
- SET_SOURCE_FILES_PROPERTIES(${LEX_${LexTarget}_OUTPUTS}
- PROPERTIES OBJECT_DEPENDS ${YACC_${YaccTarget}_OUTPUT_HEADER})
- ENDMACRO(ADD_LEX_YACC_DEPENDENCY)
- #============================================================
-
-ENDIF(LEX_EXECUTABLE)
-
-FIND_PACKAGE_HANDLE_STANDARD_ARGS(LEX REQUIRED_VARS LEX_EXECUTABLE)
-
-# FindLEX.cmake ends here
diff --git a/ecbuild/cmake/FindLegacyFDB.cmake b/ecbuild/cmake/FindLegacyFDB.cmake
deleted file mode 100644
index 0136299..0000000
--- a/ecbuild/cmake/FindLegacyFDB.cmake
+++ /dev/null
@@ -1,35 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-# - Try to find FDB
-# Once done this will define
-# LEGACY_FDB_FOUND - System has FDB
-# LEGACY_FDB_INCLUDE_DIRS - The FDB include directories
-# LEGACY_FDB_LIBRARIES - The libraries needed to use FDB
-
-
-if( NOT LEGACY_FDB_FOUND )
-
- if( DEFINED LEGACY_FDB_PATH )
- find_library( LEGACY_FDB_LIBRARY NAMES fdb_legacy PATHS ${LEGACY_FDB_PATH} ${LEGACY_FDB_PATH}/lib NO_DEFAULT_PATH)
- endif()
-
- find_library( LEGACY_FDB_LIBRARY NAMES fdb_legacy )
-
- set( LEGACY_FDB_LIBRARIES ${LEGACY_FDB_LIBRARY} )
-
- include(FindPackageHandleStandardArgs)
-
- # handle the QUIETLY and REQUIRED arguments and set LEGACY_FDB_FOUND to TRUE
- # if all listed variables are TRUE
- find_package_handle_standard_args(LEGACY_FDB DEFAULT_MSG
- LEGACY_FDB_LIBRARY )
-
- mark_as_advanced(LEGACY_FDB_LIBRARY)
-
-endif()
diff --git a/ecbuild/cmake/FindLibGFortran.cmake b/ecbuild/cmake/FindLibGFortran.cmake
deleted file mode 100644
index bf9e168..0000000
--- a/ecbuild/cmake/FindLibGFortran.cmake
+++ /dev/null
@@ -1,52 +0,0 @@
-# © Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-###############################################################################
-# gfortran libs
-
-set( __libgfortran_names gfortran libgfortran.so.1 libgfortran.so.3 )
-
-# use gfortran to find the library
-
-find_program( GFORTRAN_EXECUTABLE gfortran )
-
-if( GFORTRAN_EXECUTABLE )
-
- execute_process(COMMAND ${GFORTRAN_EXECUTABLE} "-print-search-dirs"
- RESULT_VARIABLE _GFORTRAN_SEARCH_SUCCESS
- OUTPUT_VARIABLE _GFORTRAN_VALUES_OUTPUT
- ERROR_VARIABLE _GFORTRAN_ERROR_VALUE
- OUTPUT_STRIP_TRAILING_WHITESPACE)
-
-# debug_var(_GFORTRAN_SEARCH_SUCCESS)
-# debug_var(_GFORTRAN_VALUES_OUTPUT)
-# debug_var(_GFORTRAN_ERROR_VALUE)
-
- if(_GFORTRAN_SEARCH_SUCCESS MATCHES 0)
- string(REGEX REPLACE ".*libraries: =(.*)" "\\1" _result ${_GFORTRAN_VALUES_OUTPUT})
- string(REGEX REPLACE ":" ";" _gfortran_hints ${_result} )
- endif()
-
- debug_var( _gfortran_hints )
-
-endif()
-
-find_library( GFORTRAN_LIB NAMES ${__libgfortran_names} HINTS ${LIBGFORTRAN_PATH} ENV LIBGFORTRAN_PATH PATHS PATH_SUFFIXES lib64 lib NO_DEFAULT_PATH )
-find_library( GFORTRAN_LIB NAMES ${__libgfortran_names} HINTS ${_gfortran_hints} PATHS PATH_SUFFIXES lib64 lib )
-
-mark_as_advanced( GFORTRAN_LIB )
-
-if( GFORTRAN_LIB )
- set( GFORTRAN_LIBRARIES ${GFORTRAN_LIB} )
-endif()
-
-include(FindPackageHandleStandardArgs)
-
-find_package_handle_standard_args( LIBGFORTRAN DEFAULT_MSG GFORTRAN_LIBRARIES )
-
-
diff --git a/ecbuild/cmake/FindNDBM.cmake b/ecbuild/cmake/FindNDBM.cmake
deleted file mode 100644
index 21cf1cf..0000000
--- a/ecbuild/cmake/FindNDBM.cmake
+++ /dev/null
@@ -1,34 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-# - Try to find NetCDF
-# Once done this will define
-# NDBM_FOUND - System has NetCDF
-# NDBM_INCLUDE_DIRS - The NetCDF include directories
-# NDBM_LIBRARIES - The libraries needed to use NetCDF
-# NDBM_DEFINITIONS - Compiler switches required for using NetCDF
-
-if( DEFINED NDBM_PATH )
- find_path(NDBM_INCLUDE_DIR NAMES ndbm.h PATHS ${NDBM_PATH} ${NDBM_PATH}/include PATH_SUFFIXES ndbm NO_DEFAULT_PATH)
- find_library(NDBM_LIBRARY NAMES ndbm dbm PATHS ${NDBM_PATH} ${NDBM_PATH}/lib PATH_SUFFIXES ndbm NO_DEFAULT_PATH)
-endif()
-
-find_path(NDBM_INCLUDE_DIR NAMES ndbm.h PATH_SUFFIXES ndbm )
-find_library( NDBM_LIBRARY NAMES ndbm dbm PATH_SUFFIXES ndbm )
-
-set( NDBM_LIBRARIES ${NDBM_LIBRARY} )
-set( NDBM_INCLUDE_DIRS ${NDBM_INCLUDE_DIR} )
-
-include(FindPackageHandleStandardArgs)
-
-# handle the QUIETLY and REQUIRED arguments and set GRIBAPI_FOUND to TRUE
-# if all listed variables are TRUE
-find_package_handle_standard_args(NDBM DEFAULT_MSG
- NDBM_LIBRARY NDBM_INCLUDE_DIR)
-
-mark_as_advanced(NDBM_INCLUDE_DIR NDBM_LIBRARY )
diff --git a/ecbuild/cmake/FindNetCDF.cmake b/ecbuild/cmake/FindNetCDF.cmake
deleted file mode 100644
index 99ead8d..0000000
--- a/ecbuild/cmake/FindNetCDF.cmake
+++ /dev/null
@@ -1,167 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-# Try to find NetCDF3 or NetCDF4 -- default is 4
-#
-# find_package( NetCDF <version> COMPONENTS C CXX Fortran )
-#
-# Input:
-# * NETCDF_PATH - user defined path where to search for the library first
-# * NETCDF_DIR - user defined path where to search for the library first
-# * NETCDF_ROOT - user defined path where to search for the library first
-#
-# Output:
-# NETCDF_FOUND - System has NetCDF
-# NETCDF_DEFINITIONS
-# NETCDF_INCLUDE_DIRS - The NetCDF include directories
-# NETCDF_LIBRARIES - The libraries needed to use NetCDF
-
-# default is netcdf4
-if( NetCDF_FIND_VERSION STREQUAL "3" )
- set( PREFER_NETCDF3 1 )
-endif()
-
-if( NOT PREFER_NETCDF3 )
- set( PREFER_NETCDF4 1 )
-else()
- set( PREFER_NETCDF4 0 )
-endif()
-mark_as_advanced( PREFER_NETCDF4 PREFER_NETCDF3 )
-
-set( NETCDF_FIND_REQUIRED ${NetCDF_FIND_REQUIRED} )
-set( NETCDF_FIND_QUIETLY ${NetCDF_FIND_QUIETLY} )
-set( NETCDF_FIND_COMPONENTS ${NetCDF_FIND_COMPONENTS} )
-
-list( APPEND NETCDF_FIND_COMPONENTS C )
-
-if( NETCDF_CXX )
- list( APPEND NETCDF_FIND_COMPONENTS CXX )
-endif()
-
-if( NETCDF_Fortran OR NETCDF_FORTRAN OR NETCDF_F90 )
- list( APPEND NETCDF_FIND_COMPONENTS FORTRAN F90 )
-endif()
-
-list(FIND NETCDF_FIND_COMPONENTS "FORTRAN" _index)
-if(${_index} GREATER -1)
- list( APPEND NETCDF_FIND_COMPONENTS F90 )
-endif()
-
-list (FIND NETCDF_FIND_COMPONENTS "F90" _index)
-if(${_index} GREATER -1)
- list( APPEND NETCDF_FIND_COMPONENTS FORTRAN )
-endif()
-
-list(FIND NETCDF_FIND_COMPONENTS "Fortran" _index)
-if(${_index} GREATER -1)
- list( REMOVE_ITEM NETCDF_FIND_COMPONENTS Fortran )
- list( APPEND NETCDF_FIND_COMPONENTS FORTRAN F90 )
-endif()
-
-list( REMOVE_DUPLICATES NETCDF_FIND_COMPONENTS )
-
-### NetCDF4
-
-if( PREFER_NETCDF4 )
-
- ## hdf5
-
- ecbuild_add_extra_search_paths( hdf5 )
-
- # Note: Only the HDF5 C-library is required for NetCDF
- # ( even for Fortan and CXX bindings)
- find_package( HDF5 COMPONENTS C QUIET )
-
- ## netcdf4
-
- # CONFIGURE the NETCDF_FIND_COMPONENTS variable
-
- # Find NetCDF4
-
- ecbuild_add_extra_search_paths( netcdf4 )
-
- # message( "NETCDF CMAKE_PREFIX_PATH = [${CMAKE_PREFIX_PATH}]")
- # debug_var( NETCDF_ROOT )
- # debug_var( NETCDF_FIND_COMPONENTS )
- # debug_var( NETCDF_FIND_QUIETLY )
- # debug_var( NETCDF_FIND_REQUIRED )
- find_package( NetCDF4 )
- # debug_var( NETCDF4_FOUND )
- # debug_var( NETCDF_FOUND )
- # debug_var( NETCDF_LIBRARIES )
- # debug_var( NETCDF_INCLUDE_DIRS )
-
- list( APPEND NETCDF_Fortran_LIBRARIES ${NETCDF_FORTRAN_LIBRARIES} ${NETCDF_F90_LIBRARIES} )
- if( NETCDF_Fortran_LIBRARIES )
- list( REMOVE_DUPLICATES NETCDF_Fortran_LIBRARIES )
- endif()
-
- # debug_var( NETCDF_Fortran_LIBRARIES )
- # debug_var( NETCDF_C_LIBRARIES )
- # debug_var( NETCDF_CXX_LIBRARIES )
-
-
- set_package_properties( NetCDF4 PROPERTIES TYPE RECOMMENDED PURPOSE "support for NetCDF4 file format" )
-
- if( NETCDF_FOUND AND HDF5_FOUND )
- # list( APPEND NETCDF_DEFINITIONS ${HDF5_DEFINITIONS} )
- list( APPEND NETCDF_LIBRARIES ${HDF5_HL_LIBRARIES} ${HDF5_LIBRARIES} )
- list( APPEND NETCDF_INCLUDE_DIRS ${HDF5_INCLUDE_DIRS} )
- endif()
-
- #debug_var( NETCDF_FOUND )
- #debug_var( NETCDF_LIBRARIES )
- #debug_var( NETCDF_INCLUDE_DIRS )
- #debug_var( HDF5_FOUND )
- #debug_var( HDF5_INCLUDE_DIRS )
- #debug_var( HDF5_HL_LIBRARIES )
- #debug_var( HDF5_LIBRARIES )
-
-endif()
-
-### NetCDF3
-
-if( PREFER_NETCDF3 )
-
- # message( "LOOKING FOR NETCDF3" )
-
- # debug_var( NetCDF_FIND_COMPONENTS )
- # debug_var( NetCDF_FIND_QUIETLY )
- # debug_var( NetCDF_FIND_REQUIRED )
-
- list(FIND NetCDF_FIND_COMPONENTS "CXX" _index)
- if(${_index} GREATER -1)
- set( NETCDF_CXX 1 )
- endif()
-
- list(FIND NetCDF_FIND_COMPONENTS "Fortran" _index)
- if(${_index} GREATER -1)
- set( NETCDF_Fortran 1 )
- endif()
-
- list(FIND NetCDF_FIND_COMPONENTS "FORTRAN" _index)
- if(${_index} GREATER -1)
- set( NETCDF_Fortran 1 )
- endif()
-
- list(FIND NetCDF_FIND_COMPONENTS "F90" _index)
- if(${_index} GREATER -1)
- set( NETCDF_Fortran 1 )
- endif()
-
- ecbuild_add_extra_search_paths( netcdf3 )
-
- ecbuild_add_extra_search_paths( netcdf ) # fallback to netcdf search paths
-
- message( "NETCDF CMAKE_PREFIX_PATH = ${CMAKE_PREFIX_PATH}" )
-
- find_package( NetCDF3 )
-
- set_package_properties( NetCDF3 PROPERTIES TYPE RECOMMENDED PURPOSE "support for NetCDF3 file format" )
-
-endif()
diff --git a/ecbuild/cmake/FindNetCDF3.cmake b/ecbuild/cmake/FindNetCDF3.cmake
deleted file mode 100644
index 079e55e..0000000
--- a/ecbuild/cmake/FindNetCDF3.cmake
+++ /dev/null
@@ -1,129 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-# Try to find NetCDF
-#
-# Input:
-# * NETCDF_PATH - user defined path where to search for the library first
-# * NETCDF_DIR - user defined path where to search for the library first
-# * NETCDF_CXX - if to search also for netcdf_c++ wrapper library
-# * NETCDF_Fortran - if to search also for netcdff wrapper library
-#
-# Output:
-# NETCDF_FOUND - System has NetCDF
-# NETCDF_INCLUDE_DIRS - The NetCDF include directories
-# NETCDF_LIBRARIES - The libraries needed to use NetCDF
-
-### TODO: generalize this into a macro for all ecbuild
-
-if( DEFINED $ENV{NETCDF_PATH} )
- list( APPEND CMAKE_PREFIX_PATH $ENV{NETCDF_PATH} )
-endif()
-
-if( DEFINED $ENV{NETCDF_DIR} )
- list( APPEND CMAKE_PREFIX_PATH $ENV{NETCDF_DIR} )
-endif()
-
-if( DEFINED NETCDF_PATH )
- list( APPEND _netcdf_incs ${NETCDF_PATH} ${NETCDF_PATH}/include )
- list( APPEND _netcdf_libs ${NETCDF_PATH} ${NETCDF_PATH}/lib )
-endif()
-
-if( DEFINED NETCDF_DIR )
- list( APPEND _netcdf_incs ${NETCDF_DIR} ${NETCDF_DIR}/include )
- list( APPEND _netcdf_libs ${NETCDF_DIR} ${NETCDF_DIR}/lib )
-endif()
-
-foreach( _h /usr/local/apps/netcdf )
-
- if( EXISTS ${_h} )
-
- list( APPEND _netcdf_incs ${_h}/include ${_h}/current/include ${_h}/new/include ${_h}/stable/include )
- list( APPEND _netcdf_libs ${_h}/lib ${_h}/current/lib ${_h}/new/lib ${_h}/stable/lib )
-
- file(GLOB _hd ${_h}/*)
- foreach( d ${_hd} )
- if( IS_DIRECTORY ${d} )
- list( APPEND _netcdf_incs ${d}/include ${d}/LP64/include )
- list( APPEND _netcdf_libs ${d}/lib ${d}/LP64/lib )
- endif()
- endforeach()
- endif()
-
-endforeach()
-
-###
-
-set( _ncdf_sfx netcdf LP64 )
-
-find_path( NETCDF_INCLUDE_DIR netcdf.h PATHS ${_netcdf_incs} PATH_SUFFIXES ${_ncdf_sfx} NO_DEFAULT_PATH )
-find_path( NETCDF_INCLUDE_DIR netcdf.h PATHS ${_netcdf_incs} PATH_SUFFIXES ${_ncdf_sfx} )
-
-find_library( NETCDF_LIBRARY netcdf PATHS ${_netcdf_libs} PATH_SUFFIXES ${_ncdf_sfx} NO_DEFAULT_PATH )
-find_library( NETCDF_LIBRARY netcdf PATHS ${_netcdf_libs} PATH_SUFFIXES ${_ncdf_sfx} )
-
-set( NETCDF_LIBRARIES ${NETCDF_LIBRARY} )
-set( NETCDF_INCLUDE_DIRS ${NETCDF_INCLUDE_DIR} )
-
-mark_as_advanced(NETCDF_INCLUDE_DIR NETCDF_LIBRARY )
-
-list( APPEND NETCDF_REQUIRED_VARS NETCDF_LIBRARY NETCDF_INCLUDE_DIR )
-
-if( NETCDF_CXX )
-
- find_path( NETCDF_CXX_INCLUDE_DIR netcdfcpp.h PATHS ${_netcdf_incs} PATH_SUFFIXES ${_ncdf_sfx} NO_DEFAULT_PATH)
- find_path( NETCDF_CXX_INCLUDE_DIR netcdfcpp.h PATHS ${_netcdf_incs} PATH_SUFFIXES ${_ncdf_sfx} )
-
- set( _ncdf_cxx netcdf_c++ netcdf_c++ netcdf_c++4 )
-
- find_library( NETCDF_CXX_LIBRARY NAMES ${_ncdf_cxx} PATHS ${_netcdf_libs} PATH_SUFFIXES ${_ncdf_sfx} NO_DEFAULT_PATH )
- find_library( NETCDF_CXX_LIBRARY NAMES ${_ncdf_cxx} PATHS ${_netcdf_libs} PATH_SUFFIXES ${_ncdf_sfx} )
-
- list( APPEND NETCDF_INCLUDE_DIRS ${NETCDF_CXX_INCLUDE_DIR} )
- list( APPEND NETCDF_LIBRARIES ${NETCDF_CXX_LIBRARY} )
-
- list( APPEND NETCDF_REQUIRED_VARS NETCDF_CXX_INCLUDE_DIR NETCDF_CXX_LIBRARY )
-
- mark_as_advanced(NETCDF_CXX_INCLUDE_DIR NETCDF_CXX_LIBRARY )
-
-endif()
-
-if( NETCDF_Fortran )
-
- find_path( NETCDF_Fortran_INCLUDE_DIR netcdf.mod PATHS ${_netcdf_incs} PATH_SUFFIXES ${_ncdf_sfx} NO_DEFAULT_PATH)
- find_path( NETCDF_Fortran_INCLUDE_DIR netcdf.mod PATHS ${_netcdf_incs} PATH_SUFFIXES ${_ncdf_sfx} )
-
- set( _ncdf_fortran netcdff )
-
- find_library( NETCDF_Fortran_LIBRARY NAMES ${_ncdf_fortran} PATHS ${_netcdf_libs} PATH_SUFFIXES ${_ncdf_sfx} NO_DEFAULT_PATH )
- find_library( NETCDF_Fortran_LIBRARY NAMES ${_ncdf_fortran} PATHS ${_netcdf_libs} PATH_SUFFIXES ${_ncdf_sfx} )
-
- list( APPEND NETCDF_INCLUDE_DIRS ${NETCDF_Fortran_INCLUDE_DIR} )
- list( APPEND NETCDF_LIBRARIES ${NETCDF_Fortran_LIBRARY} )
-
- list( APPEND NETCDF_REQUIRED_VARS NETCDF_Fortran_INCLUDE_DIR NETCDF_Fortran_LIBRARY )
-
- mark_as_advanced(NETCDF_Fortran_INCLUDE_DIR NETCDF_Fortran_LIBRARY )
-
-endif()
-
-list( REMOVE_DUPLICATES NETCDF_INCLUDE_DIRS )
-
-include(FindPackageHandleStandardArgs)
-
-if( NETCDF_FIND_QUIETLY )
- set( NETCDF3_FIND_QUIETLY ${NETCDF_FIND_QUIETLY} )
-endif()
-if( NETCDF_FIND_REQUIRED )
- set( NETCDF3_FIND_REQUIRED ${NETCDF_FIND_REQUIRED} )
-endif()
-
-find_package_handle_standard_args( NETCDF3 DEFAULT_MSG ${NETCDF_REQUIRED_VARS} )
-
-set( NETCDF_FOUND ${NETCDF3_FOUND} )
-
diff --git a/ecbuild/cmake/FindODB.cmake b/ecbuild/cmake/FindODB.cmake
deleted file mode 100644
index bfa6905..0000000
--- a/ecbuild/cmake/FindODB.cmake
+++ /dev/null
@@ -1,53 +0,0 @@
-# © Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-# - Try to find ODB
-# Once done this will define
-# ODB_FOUND - System has ODB
-# ODB_INCLUDE_DIRS - The ODB include directories
-# ODB_LIBRARIES - The libraries needed to use ODB
-
-# /usr/local/apps/odb/CY37R3.001/pgf90/LP64/include/odbdump.h
-# /usr/local/apps/odb/CY37R3.001/pgf90/LP64/module/odb.mod
-
-# -lodb -lodbec -lifsaux -lmpi_serial -lodbdummy
-
-find_package( Dl ) # find the dynamic linker
-
-list( APPEND _odb_search_libs odb odbec ifsaux mpi_serial odbdummy )
-
-if( DEFINED ODB_PATH )
- find_path(ODB_INCLUDE_DIR odbdump.h PATHS ${ODB_ROOT} ${ODB_ROOT}/include ${ODB_PATH} ${ODB_PATH}/include PATH_SUFFIXES odb NO_DEFAULT_PATH)
- find_path(ODB_MODULE_DIR odb.mod PATHS ${ODB_ROOT} ${ODB_ROOT}/module ${ODB_PATH} ${ODB_PATH}/module PATH_SUFFIXES odb NO_DEFAULT_PATH)
- foreach( _lib ${_odb_search_libs} )
- find_library(ODB_LIBRARY_${_lib} ${_lib} PATHS ${ODB_ROOT} ${ODB_ROOT}/lib ${ODB_PATH} ${ODB_PATH}/lib PATH_SUFFIXES odb NO_DEFAULT_PATH)
- endforeach()
-endif()
-
-find_path(ODB_INCLUDE_DIR odbdump.h PATH_SUFFIXES odb )
-find_path(ODB_MODULE_DIR odb.mod PATH_SUFFIXES odb )
-foreach( _lib ${_odb_search_libs} )
- find_library( ODB_LIBRARY_${_lib} ${_lib} PATH_SUFFIXES odb )
-endforeach()
-
-foreach( _lib ${_odb_search_libs} )
- list( APPEND ODB_LIB_LIST ODB_LIBRARY_${_lib} )
- list( APPEND ODB_LIBRARIES ${ODB_LIBRARY_${_lib}} )
- mark_as_advanced(${ODB_LIBRARY_${_lib}})
-endforeach()
-
-set( ODB_INCLUDE_DIRS ${ODB_INCLUDE_DIR} ${ODB_MODULE_DIR})
-mark_as_advanced(ODB_INCLUDE_DIR )
-
-include(FindPackageHandleStandardArgs)
-
-# handle the QUIETLY and REQUIRED arguments and set GRIBAPI_FOUND to TRUE
-# if all listed variables are TRUE
-find_package_handle_standard_args(ODB DEFAULT_MSG
- ODB_INCLUDE_DIR ${ODB_LIB_LIST} )
-
diff --git a/ecbuild/cmake/FindOpenJPEG.cmake b/ecbuild/cmake/FindOpenJPEG.cmake
deleted file mode 100644
index 3e36954..0000000
--- a/ecbuild/cmake/FindOpenJPEG.cmake
+++ /dev/null
@@ -1,43 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-# - Try to find the OpenJPEG includes and library
-# This module defines
-# OPENJPEG_FOUND - System has OpenJPEG
-# OPENJPEG_INCLUDE_DIRS - the OpenJPEG include directories
-# OPENJPEG_LIBRARIES - the libraries needed to use OpenJPEG
-#
-# also defined internally:
-# OPENJPEG_LIBRARY, where to find the OpenJPEG library.
-# OPENJPEG_INCLUDE_DIR, where to find the openjpeg.h header
-
-ecbuild_add_extra_search_paths( openjpg )
-
-IF( NOT DEFINED OPENJPEG_PATH AND NOT "$ENV{OPENJPEG_PATH}" STREQUAL "" )
- SET( OPENJPEG_PATH "$ENV{OPENJPEG_PATH}" )
-ENDIF()
-
-if( DEFINED OPENJPEG_PATH )
- find_path(OPENJPEG_INCLUDE_DIR openjpeg.h PATHS ${OPENJPEG_PATH}/include PATH_SUFFIXES openjpeg NO_DEFAULT_PATH)
- find_library(OPENJPEG_LIBRARY openjpeg PATHS ${OPENJPEG_PATH}/lib PATH_SUFFIXES openjpeg NO_DEFAULT_PATH)
-endif()
-
-find_path(OPENJPEG_INCLUDE_DIR openjpeg.h PATH_SUFFIXES openjpeg )
-find_library( OPENJPEG_LIBRARY openjpeg PATH_SUFFIXES openjpeg )
-
-set( OPENJPEG_LIBRARIES ${OPENJPEG_LIBRARY} )
-set( OPENJPEG_INCLUDE_DIRS ${OPENJPEG_INCLUDE_DIR} )
-
-include(FindPackageHandleStandardArgs)
-
-# handle the QUIETLY and REQUIRED arguments and set OPENJPEG_FOUND to TRUE
-# if all listed variables are TRUE
-find_package_handle_standard_args(OpenJPEG DEFAULT_MSG
- OPENJPEG_LIBRARY OPENJPEG_INCLUDE_DIR)
-
-mark_as_advanced(OPENJPEG_INCLUDE_DIR OPENJPEG_LIBRARY )
diff --git a/ecbuild/cmake/FindPGIFortran.cmake b/ecbuild/cmake/FindPGIFortran.cmake
deleted file mode 100644
index ae2221b..0000000
--- a/ecbuild/cmake/FindPGIFortran.cmake
+++ /dev/null
@@ -1,46 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-###############################################################################
-# FORTRAN support
-
-# set( PGIFORTRAN_SEARCH_LIBS pgmp pgbind numa pgf90 pgf90_rpm1 pgf902 pgf90rtl pgftnrtl nspgc pgc rt pgsse1 pgsse2 ) # init
-# set( PGIFORTRAN_SEARCH_LIBS pgf90 pgf90_rpm1 pgf902 pgf90rtl pgftnrtl pghpf pgc pgf90 rt pgsse1 pgsse2 ) # mars client linux.2
-# set( PGIFORTRAN_SEARCH_LIBS pgftnrtl nspgc pgc rt pgsse1 pgsse2 ) # mars client linux.3
-
-if( NOT DEFINED PGIFORTRAN_SEARCH_LIBS )
- set( PGIFORTRAN_SEARCH_LIBS pgmp pgbind numa pgf90 pgf90_rpm1 pgf902 pgf90rtl pgftnrtl pghpf nspgc pgc pgf90 pgf902 pghpf_rpm1 pghpf2 pgsse1 pgsse2 ) # better ? #
-endif()
-
-set( pgi_fortran_all_libs_found 1 )
-
-foreach( pglib ${PGIFORTRAN_SEARCH_LIBS} )
-
- find_library( ${pglib}_lib ${pglib} PATHS ${PGI_PATH} PATH_SUFFIXES lib libso NO_DEFAULT_PATH )
-
- find_library( ${pglib}_lib ${pglib} HINTS /usr/local/apps/pgi/pgi-10.8/linux86-64/10.8 PATH PATH_SUFFIXES lib libso )
-
- if( ${pglib}_lib )
- list( APPEND PGIFORTRAN_LIBRARIES ${${pglib}_lib} )
-# else()
-# set( pgi_fortran_all_libs_found 0 )
- endif()
-
-endforeach()
-
-include(FindPackageHandleStandardArgs)
-
-find_package_handle_standard_args( LIBPGIFORTRAN DEFAULT_MSG pgi_fortran_all_libs_found PGIFORTRAN_LIBRARIES )
-
-if( LIBPGIFORTRAN_FOUND )
- find_package( Realtime )
-endif()
-
-if( REALTIME_FOUND )
- set( LIBPGIFORTRAN_LIBRARIES ${PGIFORTRAN_LIBRARIES} ${RT_LIB} )
-endif()
diff --git a/ecbuild/cmake/FindPango.cmake b/ecbuild/cmake/FindPango.cmake
deleted file mode 100644
index 81b55c0..0000000
--- a/ecbuild/cmake/FindPango.cmake
+++ /dev/null
@@ -1,33 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-# - Try to find Pango
-
-# Output:
-# PANGO_FOUND
-# PANGO_LIBRARIES
-# PANGO_INCLUDE_DIRS
-
-ecbuild_add_extra_search_paths( pango )
-
-find_package(PkgConfig)
-
-pkg_check_modules(PC_LIBPANGO QUIET pango)
-
-debug_var( PC_LIBPANGO_FOUND )
-debug_var( PC_LIBPANGO_VERSION )
-debug_var( PC_LIBPANGO_LIBRARIES )
-debug_var( PC_LIBPANGO_INCLUDE_DIRS )
-
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args( pango DEFAULT_MSG PC_LIBPANGO_LIBRARIES PC_LIBPANGO_INCLUDE_DIRS )
-
-set( PANGO_VERSION ${PC_LIBPANGO_VERSION} )
-set( PANGO_LIBRARIES ${PC_LIBPANGO_LIBRARIES} )
-set( PANGO_INCLUDE_DIRS ${PC_LIBPANGO_INCLUDE_DIRS} )
-
diff --git a/ecbuild/cmake/FindPangoCairo.cmake b/ecbuild/cmake/FindPangoCairo.cmake
deleted file mode 100644
index 4fb1fd2..0000000
--- a/ecbuild/cmake/FindPangoCairo.cmake
+++ /dev/null
@@ -1,91 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-# - Try to find PangoCairo
-
-# Output:
-# PANGOCAIRO_FOUND
-# PANGOCAIRO_LIBRARIES
-# PANGOCAIRO_INCLUDE_DIRS
-
-
-find_package(PkgConfig)
-
-pkg_check_modules(PC_LIBPANGOCAIRO QUIET pangocairo)
-
-#debug_var( PC_LIBPANGOCAIRO_FOUND )
-#debug_var( PC_LIBPANGOCAIRO_VERSION )
-#debug_var( PC_LIBPANGOCAIRO_LIBRARIES )
-#debug_var( PC_LIBPANGOCAIRO_INCLUDE_DIRS )
-
-
-if(PC_LIBPANGOCAIRO_FOUND)
- include(FindPackageHandleStandardArgs)
- find_package_handle_standard_args( pangocairo DEFAULT_MSG PC_LIBPANGOCAIRO_LIBRARIES PC_LIBPANGOCAIRO_INCLUDE_DIRS )
- set( PANGOCAIRO_VERSION ${PC_LIBPANGOCAIRO_VERSION} )
- set( PANGOCAIRO_LIBRARIES ${PC_LIBPANGOCAIRO_LIBRARIES} )
- set( PANGOCAIRO_INCLUDE_DIRS ${PC_LIBPANGOCAIRO_INCLUDE_DIRS} )
-else()
-
- # this is to get magics compiling on mac with macbrew
-
- include(FindPackageHandleStandardArgs)
-
- set(PANGO_VERSION 1.0)
- set(GLIB_VERSION 2.0)
-
- find_path( _PANGOCAIRO_INCLUDE_DIRS
- NAMES pango/pangocairo.h
- HINTS /usr/local/include PATH_SUFFIXES pango-${PANGO_VERSION})
-
- find_path( _CAIRO_INCLUDE_DIRS
- NAMES cairo.h
- HINTS /usr/local/include PATH_SUFFIXES cairo)
-
- find_path( _GLIB_INCLUDE_DIRS_1
- NAMES glib.h
- HINTS /usr/local/include PATH_SUFFIXES glib-${GLIB_VERSION})
-
- find_path( _GLIB_INCLUDE_DIRS_2
- NAMES glibconfig.h
- HINTS /usr/local/lib/glib-${GLIB_VERSION} PATH_SUFFIXES include)
-
-
- find_package(X11)
-
- set(PANGOCAIRO_INCLUDE_DIRS
- ${_PANGOCAIRO_INCLUDE_DIRS}
- ${_CAIRO_INCLUDE_DIRS}
- ${_GLIB_INCLUDE_DIRS_1}
- ${_GLIB_INCLUDE_DIRS_2}
- ${X11_INCLUDE_DIR}
- )
-
-#message(WARNING "===> ${PANGOCAIRO_INCLUDE_DIRS}")
-
- find_library( _PANGOCAIRO_LIBRARIES NAMES pangocairo pangocairo-${PANGO_VERSION})
- find_library( _PANGO_LIBRARIES NAMES pango pango-${PANGO_VERSION})
- find_library( _CAIRO_LIBRARIES NAMES cairo)
- find_library( _GLIB_LIBRARIES NAMES glib-${GLIB_VERSION})
-
- set(PANGOCAIRO_LIBRARIES
- ${_PANGOCAIRO_LIBRARIES}
- ${_PANGO_LIBRARIES}
- ${_CAIRO_LIBRARIES}
- ${_GLIB_LIBRARIES}
- ${X11_LIBRARIES}
- )
-
-#message(WARNING "===> ${PANGOCAIRO_LIBRARIES}")
-
- find_package_handle_standard_args( pangocairo DEFAULT_MSG
- PANGOCAIRO_LIBRARIES
- PANGOCAIRO_INCLUDE_DIRS )
-
-endif()
-
diff --git a/ecbuild/cmake/FindProj4.cmake b/ecbuild/cmake/FindProj4.cmake
deleted file mode 100644
index 6181ed0..0000000
--- a/ecbuild/cmake/FindProj4.cmake
+++ /dev/null
@@ -1,67 +0,0 @@
-# - Try to find the proj4 library
-# Once done this will define
-#
-# PROJ4_FOUND - system has proj4
-# PROJ4_INCLUDE_DIRS - the proj4 include directory
-# PROJ4_LIBRARIES - Link these to use proj4
-#
-# Define PROJ4_MIN_VERSION for which version desired.
-
-if( NOT PROJ4_PATH AND NOT "$ENV{PROJ4_PATH}" STREQUAL "" )
- set( PROJ4_PATH "$ENV{PROJ4_PATH}" )
-endif()
-
-ecbuild_add_extra_search_paths( proj4 )
-
-if( NOT PROJ4_PATH )
-
- include(FindPkgConfig)
-
-# if(Proj4_FIND_REQUIRED)
-# set(_pkgconfig_REQUIRED "REQUIRED")
-# else()
-# set(_pkgconfig_REQUIRED "")
-# endif()
-
- if(PROJ4_MIN_VERSION)
- pkg_check_modules(PKPROJ4 ${_pkgconfig_REQUIRED} QUIET proj4>=${PROJ4_MIN_VERSION})
- else()
- pkg_check_modules(PKPROJ4 ${_pkgconfig_REQUIRED} QUIET proj4)
- endif()
-
- if( PKG_CONFIG_FOUND AND PKPROJ4_FOUND )
-
- find_path(PROJ4_INCLUDE_DIR proj_api.h HINTS ${PKPROJ4_INCLUDEDIR} ${PKPROJ4_INCLUDE_DIRS} PATH_SUFFIXES proj4 NO_DEFAULT_PATH )
- find_library(PROJ4_LIBRARY proj HINTS ${PKPROJ4_LIBDIR} ${PKPROJ4_LIBRARY_DIRS} PATH_SUFFIXES proj4 NO_DEFAULT_PATH )
-
- endif()
-
-# debug_var( PKG_CONFIG_FOUND )
-# debug_var( PKPROJ4_FOUND )
-# debug_var( PROJ4_MIN_VERSION )
-
-endif()
-
-if( PROJ4_PATH )
-
- find_path(PROJ4_INCLUDE_DIR NAMES proj_api.h PATHS ${PROJ4_PATH} ${PROJ4_PATH}/include PATH_SUFFIXES proj4 NO_DEFAULT_PATH )
- find_library(PROJ4_LIBRARY NAMES proj PATHS ${PROJ4_PATH} ${PROJ4_PATH}/lib PATH_SUFFIXES proj4 NO_DEFAULT_PATH )
-
-endif()
-
-find_path(PROJ4_INCLUDE_DIR NAMES proj_api.h PATHS PATH_SUFFIXES proj4 )
-find_library( PROJ4_LIBRARY NAMES proj PATHS PATH_SUFFIXES proj4 )
-
-
-# debug_var( PROJ4_INCLUDE_DIR )
-# debug_var( PROJ4_LIBRARY )
-
-# handle the QUIETLY and REQUIRED arguments and set GRIBAPI_FOUND
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(PROJ4 DEFAULT_MSG
- PROJ4_LIBRARY PROJ4_INCLUDE_DIR)
-
-set( PROJ4_LIBRARIES ${PROJ4_LIBRARY} )
-set( PROJ4_INCLUDE_DIRS ${PROJ4_INCLUDE_DIR} )
-
-mark_as_advanced( PROJ4_INCLUDE_DIR PROJ4_LIBRARY )
diff --git a/ecbuild/cmake/FindREADLINE.cmake b/ecbuild/cmake/FindREADLINE.cmake
deleted file mode 100644
index 9477026..0000000
--- a/ecbuild/cmake/FindREADLINE.cmake
+++ /dev/null
@@ -1,87 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-# - Try to find READLINE
-# Once done this will define
-# READLINE_FOUND - System has READLINE
-# READLINE_INCLUDE_DIRS - The READLINE include directories
-# READLINE_LIBRARIES - The libraries needed to use READLINE
-# READLINE_DEFINITIONS - Compiler switches required for using READLINE
-
-if( DEFINED READLINE_PATH )
- find_path(READLINE_INCLUDE_DIR readline/readline.h PATHS ${READLINE_PATH}/include NO_DEFAULT_PATH)
- find_library(READLINE_LIBRARY readline PATHS ${READLINE_PATH}/lib PATH_SUFFIXES readline NO_DEFAULT_PATH)
-endif()
-
-find_path(READLINE_INCLUDE_DIR readline/readline.h )
-find_library( READLINE_LIBRARY readline PATH_SUFFIXES readline )
-
-# check what version we got
-cmake_push_check_state()
-
- set( CMAKE_REQUIRED_LIBRARIES ${READLINE_LIBRARY} )
- set( CMAKE_REQUIRED_INCLUDES ${READLINE_INCLUDE_DIR} )
-
- # sometimes the link might fail missing -ltermcap or -l(n)curses
- # if we searched before for Curses, then lets try to use it
- if(CURSES_FOUND)
- list( APPEND CMAKE_REQUIRED_LIBRARIES ${CURSES_LIBRARIES} )
- list( APPEND CMAKE_REQUIRED_INCLUDES ${CURSES_INCLUDE_DIR} )
- endif()
-
- ecbuild_check_cxx_source_return(
- "#include <stdio.h>
- #include <readline/readline.h>
- #include <iostream>
- int main() {
- std::cout << rl_library_version << std::flush;
- return 0;
- }"
- VAR readline_version
- OUTPUT __readline_version_out )
-
-cmake_pop_check_state()
-
-# debug_var( readline_version )
-# debug_var( __readline_version_out )
-
-set( __readline_fail 0 )
-if( __readline_version_out )
-
- if( "${__readline_version_out}" MATCHES "^EditLine" )
- message( STATUS "Found EditLine instead of Readline at '${READLINE_INCLUDE_DIR}'" )
- if( READLINE_WRAPPER_OK )
- set( READLINE_WRAPPER "EditLine" )
- set( __readline_fail 0 )
- else()
- message( STATUS "Readline wrapper not accepted -- rejecting Readline at '${READLINE_INCLUDE_DIR}'" )
- set( __readline_fail 1 )
- endif()
- endif()
-
-else()
- message( STATUS "Readline test run failed -- rejecting Readline at '${READLINE_INCLUDE_DIR}'" )
- set( __readline_fail 1 )
-endif()
-
-if( __readline_fail )
- set( READLINE_LIBRARY READLINE_LIBRARY-NOTFOUND )
- set( READLINE_INCLUDE_DIR READLINE_INCLUDE_DIR-NOTFOUND )
-endif()
-
-include(FindPackageHandleStandardArgs)
-
-find_package_handle_standard_args(READLINE DEFAULT_MSG READLINE_LIBRARY READLINE_INCLUDE_DIR)
-
-if( READLINE_FOUND )
- set( READLINE_VERSION ${__readline_version_out} )
- set( READLINE_LIBRARIES ${READLINE_LIBRARY} )
- set( READLINE_INCLUDE_DIRS ${READLINE_INCLUDE_DIR} )
-endif()
-
-mark_as_advanced(READLINE_INCLUDE_DIR READLINE_LIBRARY )
diff --git a/ecbuild/cmake/FindRPCGEN.cmake b/ecbuild/cmake/FindRPCGEN.cmake
deleted file mode 100644
index 98c4a98..0000000
--- a/ecbuild/cmake/FindRPCGEN.cmake
+++ /dev/null
@@ -1,20 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-#Sets:
-# RPCGEN_FOUND = prcgen was found
-# RPCGEN_EXECUTABLE = the executable rpcgen
-
-if( DEFINED RPCGEN_PATH )
- find_program( RPCGEN_EXECUTABLE NAMES rpcgen PATHS ${RPCGEN_PATH} PATH_SUFFIXES bin NO_DEFAULT_PATH )
-endif()
-find_program( RPCGEN_EXECUTABLE NAMES rpcgen )
-
-include(FindPackageHandleStandardArgs)
-
-find_package_handle_standard_args( RPCGEN DEFAULT_MSG RPCGEN_EXECUTABLE )
diff --git a/ecbuild/cmake/FindRealtime.cmake b/ecbuild/cmake/FindRealtime.cmake
deleted file mode 100644
index b46b9b7..0000000
--- a/ecbuild/cmake/FindRealtime.cmake
+++ /dev/null
@@ -1,22 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-#Sets:
-# RT_LIB = the library to link against
-
-if( DEFINED REALTIME_PATH )
- find_library(RT_LIB rt PATHS ${REALTIME_PATH}/lib NO_DEFAULT_PATH )
-endif()
-
-find_library( RT_LIB rt )
-
-mark_as_advanced( RT_LIB )
-
-include(FindPackageHandleStandardArgs)
-
-find_package_handle_standard_args(REALTIME DEFAULT_MSG RT_LIB )
diff --git a/ecbuild/cmake/FindSZip.cmake b/ecbuild/cmake/FindSZip.cmake
deleted file mode 100644
index 533df50..0000000
--- a/ecbuild/cmake/FindSZip.cmake
+++ /dev/null
@@ -1,32 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-# - Try to find SZip
-# Once done this will define
-# SZIP_FOUND - System has SZip
-# SZIP_INCLUDE_DIRS - The SZip include directories
-# SZIP_LIBRARIES - The libraries needed to use SZip
-
-ecbuild_add_extra_search_paths( szip )
-
-if( DEFINED SZIP_PATH )
- find_path( SZIP_INCLUDE_DIR szlib.h PATHS ${SZIP_PATH}/include PATH_SUFFIXES szip NO_DEFAULT_PATH )
- find_library( SZIP_LIBRARY NAMES szip sz PATHS ${SZIP_PATH}/lib PATH_SUFFIXES szip NO_DEFAULT_PATH )
-endif()
-
-find_path( SZIP_INCLUDE_DIR szlib.h PATH_SUFFIXES szip )
-find_library( SZIP_LIBRARY NAMES szip sz PATH_SUFFIXES szip )
-
-set( SZIP_LIBRARIES ${SZIP_LIBRARY} )
-set( SZIP_INCLUDE_DIRS ${SZIP_INCLUDE_DIR} )
-
-include(FindPackageHandleStandardArgs)
-
-find_package_handle_standard_args(SZip DEFAULT_MSG SZIP_LIBRARY SZIP_INCLUDE_DIR)
-
-mark_as_advanced(SZIP_INCLUDE_DIR SZIP_LIBRARY )
diff --git a/ecbuild/cmake/FindScin.cmake b/ecbuild/cmake/FindScin.cmake
deleted file mode 100644
index 3ddf732..0000000
--- a/ecbuild/cmake/FindScin.cmake
+++ /dev/null
@@ -1,48 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-# - Try to find ECREGRID
-# Once done this will define
-# ECREGRID_FOUND - System has ECREGRID
-# ECREGRID_INCLUDE_DIRS - The ECREGRID include directories
-# ECREGRID_LIBRARIES - The libraries needed to use ECREGRID
-# ECREGRID_DEFINITIONS - Compiler switches required for using ECREGRID
-
-option( WITH_ECREGRID "try to find scin installation" ON )
-
-# skip if ECREGRID is already found or if has is built inside
-
-if( NOT ECREGRID_FOUND AND WITH_ECREGRID )
-
- if( NOT DEFINED ECREGRID_PATH AND NOT "$ENV{ECREGRID_PATH}" STREQUAL "" )
- list( APPEND ECREGRID_PATH "$ENV{ECREGRID_PATH}" )
- endif()
-
- if( DEFINED ECREGRID_PATH )
- find_path(ECREGRID_INCLUDE_DIR NAMES scin_api.h PATHS ${ECREGRID_PATH} ${ECREGRID_PATH}/include PATH_SUFFIXES scin_api NO_DEFAULT_PATH )
- find_library(ECREGRID_LIBRARY NAMES scin PATHS ${ECREGRID_PATH} ${ECREGRID_PATH}/lib PATH_SUFFIXES scin NO_DEFAULT_PATH )
- endif()
-
- find_path(ECREGRID_INCLUDE_DIR NAMES scin_api.h PATH_SUFFIXES scin_api )
- find_library( ECREGRID_LIBRARY NAMES scin PATH_SUFFIXES scin )
-
- include(FindPackageHandleStandardArgs)
-
- # handle the QUIETLY and REQUIRED arguments and set ECREGRID_FOUND to TRUE
- # if all listed variables are TRUE
- find_package_handle_standard_args(Scin DEFAULT_MSG
- ECREGRID_LIBRARY ECREGRID_INCLUDE_DIR)
-
- if( ECREGRID_FOUND )
- set( ECREGRID_LIBRARIES ${ECREGRID_LIBRARY} )
- set( ECREGRID_INCLUDE_DIRS ${ECREGRID_INCLUDE_DIR} )
- endif()
-
- mark_as_advanced(ECREGRID_INCLUDE_DIR ECREGRID_LIBRARY )
-
-endif()
diff --git a/ecbuild/cmake/FindTrilinos.cmake b/ecbuild/cmake/FindTrilinos.cmake
deleted file mode 100644
index 717cca6..0000000
--- a/ecbuild/cmake/FindTrilinos.cmake
+++ /dev/null
@@ -1,52 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-# Try to find the Trilinos library
-#
-# Needs environmental variables
-# TRILINOS_PATH
-# Sets
-# TRILINOS_INCLUDE_DIRS
-# TRILINOS_LIBRARIES
-# TRILINOS_FOUND
-
-# Try to find Trilinos using Trilinos recommendations
-
-
-ecbuild_add_extra_search_paths( trilinos )
-
-if( DEFINED $ENV{TRILINOS_PATH} )
- find_package(Trilinos PATHS $ENV{TRILINOS_PATH}/lib/cmake/Trilinos $ENV{TRILINOS_PATH}/include )
-endif()
-
-if( TRILINOS_PATH )
- find_package(Trilinos PATHS ${TRILINOS_PATH}/lib/cmake/Trilinos ${TRILINOS_PATH}/include )
-endif()
-
-if( Trilinos_FOUND )
-
- set( TRILINOS_INCLUDE_DIRS "" )
-
- list( APPEND TRILINOS_INCLUDE_DIRS ${Trilinos_INCLUDE_DIRS} )
- list( APPEND TRILINOS_INCLUDE_DIRS ${Trilinos_TPL_INCLUDE_DIRS} )
-
- foreach( test_lib ${Trilinos_LIBRARIES} )
- if(NOT ${test_lib} STREQUAL "pytrilinos")
- find_library( ${test_lib}_lib ${test_lib} PATHS ${Trilinos_LIBRARY_DIRS} NO_DEFAULT_PATH)
- find_library( ${test_lib}_lib ${test_lib})
- mark_as_advanced( ${test_lib}_lib )
- list( APPEND TRILINOS_LIBRARIES ${${test_lib}_lib} )
- endif()
- endforeach()
-
- list( APPEND TRILINOS_LIBRARIES ${Trilinos_TPL_LIBRARIES} )
-
- set( TRILINOS_FOUND TRUE )
- set( TRILINOS_VERSION ${Trilinos_VERSION} )
-
-endif()
diff --git a/ecbuild/cmake/FindXLFortranLibs.cmake b/ecbuild/cmake/FindXLFortranLibs.cmake
deleted file mode 100644
index 7be0070..0000000
--- a/ecbuild/cmake/FindXLFortranLibs.cmake
+++ /dev/null
@@ -1,49 +0,0 @@
-# © Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-###############################################################################
-
-list( APPEND xl_libs xlf90 xlopt xlf xlsmp )
-
-set( xlf_all_libs_found 1 )
-
-foreach( lib ${xl_libs} )
-
- find_library( ${lib}_lib ${lib} PATHS ${XLF_PATH} PATH_SUFFIXES lib lib64 NO_DEFAULT_PATH )
-
- find_library( ${lib}_lib ${lib} )
-
- if( ${lib}_lib )
- list( APPEND XLFORTRAN_LIBRARIES ${${lib}_lib} )
- else()
- set( xlf_all_libs_found 0 )
- endif()
-
-endforeach()
-
-include(FindPackageHandleStandardArgs)
-
-find_package_handle_standard_args( LIBXLFORTRAN DEFAULT_MSG xlf_all_libs_found XLFORTRAN_LIBRARIES )
-
-# HACK for support libraries
-
-if( LIBXLFORTRAN_FOUND )
- list( APPEND xl_extra_libs pthreads m essl )
- foreach( lib ${xl_extra_libs} )
-
- find_library( ${lib}_lib ${lib} PATHS ${XLF_PATH} PATH_SUFFIXES lib lib64 NO_DEFAULT_PATH )
-
- find_library( ${lib}_lib ${lib} )
-
- if( ${lib}_lib )
- list( APPEND XLFORTRAN_LIBRARIES ${${lib}_lib} )
- endif()
-
- endforeach()
-endif()
-
diff --git a/ecbuild/cmake/FindYACC.cmake b/ecbuild/cmake/FindYACC.cmake
deleted file mode 100644
index dbdb191..0000000
--- a/ecbuild/cmake/FindYACC.cmake
+++ /dev/null
@@ -1,157 +0,0 @@
-# - Find yacc executable and provides macros to generate custom build rules
-# The module defines the following variables:
-#
-# YACC_EXECUTABLE - path to the yacc program
-# YACC_FOUND - true if the program was found
-#
-# The minimum required version of yacc can be specified using the
-# standard CMake syntax, e.g. find_package(YACC 2.1.3)
-#
-# If yacc is found, the module defines the macros:
-# YACC_TARGET(<Name> <YaccInput> <CodeOutput> [VERBOSE <file>]
-# [COMPILE_FLAGS <string>])
-# which will create a custom rule to generate a parser. <YaccInput> is
-# the path to a yacc file. <CodeOutput> is the name of the source file
-# generated by yacc. A header file is also be generated, and contains
-# the token list. If COMPILE_FLAGS option is specified, the next
-# parameter is added in the yacc command line. if VERBOSE option is
-# specified, <file> is created and contains verbose descriptions of the
-# grammar and parser. The macro defines a set of variables:
-# YACC_${Name}_DEFINED - true is the macro ran successfully
-# YACC_${Name}_INPUT - The input source file, an alias for <YaccInput>
-# YACC_${Name}_OUTPUT_SOURCE - The source file generated by yacc
-# YACC_${Name}_OUTPUT_HEADER - The header file generated by yacc
-# YACC_${Name}_OUTPUTS - The sources files generated by yacc
-# YACC_${Name}_COMPILE_FLAGS - Options used in the yacc command line
-#
-# ====================================================================
-
-#=============================================================================
-# Copyright 2009 Kitware, Inc.
-# Copyright 2006 Tristan Carel
-#
-# Distributed under the OSI-approved BSD License (the "License");
-# see accompanying file Copyright.txt for details.
-#
-# This software is distributed WITHOUT ANY WARRANTY; without even the
-# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the License for more information.
-#=============================================================================
-
-# This file is based on the FindFLEX CMake macro, and adapted by ECMWF
-
-#=============================================================================
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-FIND_PROGRAM(YACC_EXECUTABLE yacc DOC "path to the yacc/yacc executable")
-MARK_AS_ADVANCED(YACC_EXECUTABLE)
-
-IF(YACC_EXECUTABLE)
- # the yacc commands should be executed with the C locale, otherwise
- # the message (which are parsed) may be translated
- SET(_Yacc_SAVED_LC_ALL "$ENV{LC_ALL}")
- SET(ENV{LC_ALL} C)
-
- SET(ENV{LC_ALL} ${_Yacc_SAVED_LC_ALL})
-
- # internal macro
- MACRO(YACC_TARGET_option_verbose Name YaccOutput filename)
- LIST(APPEND YACC_TARGET_cmdopt "--verbose")
- GET_FILENAME_COMPONENT(YACC_TARGET_output_path "${YaccOutput}" PATH)
- GET_FILENAME_COMPONENT(YACC_TARGET_output_name "${YaccOutput}" NAME_WE)
- ADD_CUSTOM_COMMAND(OUTPUT ${filename}
- COMMAND ${CMAKE_COMMAND}
- ARGS -E copy
- "${YACC_TARGET_output_path}/${YACC_TARGET_output_name}.output"
- "${filename}"
- DEPENDS
- "${YACC_TARGET_output_path}/${YACC_TARGET_output_name}.output"
- COMMENT "[YACC][${Name}] Copying yacc verbose table to ${filename}"
- WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
- SET(YACC_${Name}_VERBOSE_FILE ${filename})
- LIST(APPEND YACC_TARGET_extraoutputs
- "${YACC_TARGET_output_path}/${YACC_TARGET_output_name}.output")
- ENDMACRO(YACC_TARGET_option_verbose)
-
- # internal macro
- MACRO(YACC_TARGET_option_extraopts Options)
- SET(YACC_TARGET_extraopts "${Options}")
- SEPARATE_ARGUMENTS(YACC_TARGET_extraopts)
- LIST(APPEND YACC_TARGET_cmdopt ${YACC_TARGET_extraopts})
- ENDMACRO(YACC_TARGET_option_extraopts)
-
- #============================================================
- # YACC_TARGET (public macro)
- #============================================================
- #
- MACRO(YACC_TARGET Name YaccInput YaccOutput)
- SET(YACC_TARGET_output_header "")
- SET(YACC_TARGET_cmdopt "")
- SET(YACC_TARGET_outputs "${YaccOutput}")
- IF(NOT ${ARGC} EQUAL 3 AND NOT ${ARGC} EQUAL 5 AND NOT ${ARGC} EQUAL 7)
- MESSAGE(SEND_ERROR "Usage")
- ELSE()
- # Parsing parameters
- IF(${ARGC} GREATER 5 OR ${ARGC} EQUAL 5)
- IF("${ARGV3}" STREQUAL "VERBOSE")
- YACC_TARGET_option_verbose(${Name} ${YaccOutput} "${ARGV4}")
- ENDIF()
- IF("${ARGV3}" STREQUAL "COMPILE_FLAGS")
- YACC_TARGET_option_extraopts("${ARGV4}")
- ENDIF()
- ENDIF()
-
- IF(${ARGC} EQUAL 7)
- IF("${ARGV5}" STREQUAL "VERBOSE")
- YACC_TARGET_option_verbose(${Name} ${YaccOutput} "${ARGV6}")
- ENDIF()
-
- IF("${ARGV5}" STREQUAL "COMPILE_FLAGS")
- YACC_TARGET_option_extraopts("${ARGV6}")
- ENDIF()
- ENDIF()
-
- # Header's name generated by yacc (see option -d)
- LIST(APPEND YACC_TARGET_cmdopt "-d")
- STRING(REGEX REPLACE "^(.*)(\\.[^.]*)$" "\\2" _fileext "${ARGV2}")
- STRING(REPLACE "c" "h" _fileext ${_fileext})
- STRING(REGEX REPLACE "^(.*)(\\.[^.]*)$" "\\1${_fileext}"
- YACC_${Name}_OUTPUT_HEADER "${ARGV2}")
- LIST(APPEND YACC_TARGET_outputs "${YACC_${Name}_OUTPUT_HEADER}")
-
-# message ( STATUS "${YACC_EXECUTABLE} ${YACC_TARGET_cmdopt} ${CMAKE_CURRENT_BINARY_DIR}/${ARGV1}" )
-# message ( STATUS "${CMAKE_COMMAND} -E rename ${CMAKE_CURRENT_BINARY_DIR}/y.tab.h ${YACC_${Name}_OUTPUT_HEADER}" )
-# message ( STATUS "${CMAKE_COMMAND} -E rename ${CMAKE_CURRENT_BINARY_DIR}/y.tab.c ${ARGV2}" )
-
- ADD_CUSTOM_COMMAND(OUTPUT ${YACC_TARGET_outputs} ${YACC_TARGET_extraoutputs}
- COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/${ARGV1} ${CMAKE_CURRENT_BINARY_DIR}
- COMMAND ${YACC_EXECUTABLE} ${YACC_TARGET_cmdopt} ${CMAKE_CURRENT_BINARY_DIR}/${ARGV1}
- COMMAND ${CMAKE_COMMAND} -E rename ${CMAKE_CURRENT_BINARY_DIR}/y.tab.h ${YACC_${Name}_OUTPUT_HEADER}
- COMMAND ${CMAKE_COMMAND} -E rename ${CMAKE_CURRENT_BINARY_DIR}/y.tab.c ${ARGV2}
- DEPENDS ${ARGV1}
- COMMENT "[YACC][${Name}] Building parser with yacc"
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
-
- # define target variables
- SET(YACC_${Name}_DEFINED TRUE)
- SET(YACC_${Name}_INPUT ${ARGV1})
- SET(YACC_${Name}_OUTPUTS ${YACC_TARGET_outputs})
- SET(YACC_${Name}_COMPILE_FLAGS ${YACC_TARGET_cmdopt})
- SET(YACC_${Name}_OUTPUT_SOURCE "${YaccOutput}")
-
- ENDIF(NOT ${ARGC} EQUAL 3 AND NOT ${ARGC} EQUAL 5 AND NOT ${ARGC} EQUAL 7)
- ENDMACRO(YACC_TARGET)
- #
- #============================================================
-
-ENDIF(YACC_EXECUTABLE)
-
-FIND_PACKAGE_HANDLE_STANDARD_ARGS(YACC REQUIRED_VARS YACC_EXECUTABLE )
-
-# FindYACC.cmake ends here
diff --git a/ecbuild/cmake/Findgrib_api.cmake b/ecbuild/cmake/Findgrib_api.cmake
deleted file mode 100644
index 55a7b19..0000000
--- a/ecbuild/cmake/Findgrib_api.cmake
+++ /dev/null
@@ -1,135 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-# - Try to find GRIB_API
-# Once done this will define
-# GRIB_API_FOUND - System has GRIB_API
-# GRIB_API_INCLUDE_DIRS - The GRIB_API include directories
-# GRIB_API_LIBRARIES - The libraries needed to use GRIB_API
-# GRIB_API_DEFINITIONS - Compiler switches required for using GRIB_API
-
-option( NO_GRIB_API_BINARIES "skip trying to find grib_api installed binaries" OFF )
-option( GRIB_API_PNG "use png with grib_api" ON )
-option( GRIB_API_JPG "use jpg with grib_api" ON )
-
-if( NOT grib_api_FOUND AND NOT NO_GRIB_API_BINARIES )
-
- ecbuild_add_extra_search_paths( grib_api )
-
- if( GRIB_API_JPG ) # jpeg support
-
- find_package( JPEG QUIET ) # grib_api might be a static .a library in which
-
- if( NOT "$ENV{JASPER_PATH}" STREQUAL "" )
- list( APPEND CMAKE_PREFIX_PATH "$ENV{JASPER_PATH}" )
- endif()
- find_package( Jasper QUIET ) # case we don't know if which jpeg library was used
-
- find_package( OpenJPEG QUIET ) # so we try to find all jpeg libs and link to them
-
- if(JPEG_FOUND)
- list( APPEND _grib_api_jpg_incs ${JPEG_INCLUDE_DIR} )
- list( APPEND _grib_api_jpg_libs ${JPEG_LIBRARIES} )
- endif()
- if(JASPER_FOUND)
- list( APPEND _grib_api_jpg_incs ${JASPER_INCLUDE_DIR} )
- list( APPEND _grib_api_jpg_libs ${JASPER_LIBRARIES} )
- endif()
- if(OPENJPEG_FOUND)
- list( APPEND _grib_api_jpg_incs ${OPENJPEG_INCLUDE_DIR} )
- list( APPEND _grib_api_jpg_libs ${OPENJPEG_LIBRARIES} )
- endif()
-
- endif()
-
- if( GRIB_API_PNG ) # png support
-
- find_package(PNG)
-
- if( DEFINED PNG_PNG_INCLUDE_DIR AND NOT DEFINED PNG_INCLUDE_DIRS )
- set( PNG_INCLUDE_DIRS ${PNG_PNG_INCLUDE_DIR} CACHE INTERNAL "PNG include dirs" )
- endif()
- if( DEFINED PNG_LIBRARY AND NOT DEFINED PNG_LIBRARIES )
- set( PNG_LIBRARIES ${PNG_LIBRARY} CACHE INTERNAL "PNG libraries" )
- endif()
-
- if(PNG_FOUND)
- list( APPEND _grib_api_png_defs ${PNG_DEFINITIONS} )
- list( APPEND _grib_api_png_incs ${PNG_INCLUDE_DIRS} )
- list( APPEND _grib_api_png_libs ${PNG_LIBRARIES} )
- endif()
-
- endif()
-
- # The grib_api on macos that comes with 'port' is linked against ghostscript
- if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
- find_library(GS_LIBRARIES NAMES gs)
- if( GS_LIBRARIES )
- list( APPEND GRIB_API_LIBRARIES ${GS_LIBRARIES} )
- endif()
- endif()
-
- # find external grib_api
-
- if( NOT DEFINED GRIB_API_PATH AND NOT "$ENV{GRIB_API_PATH}" STREQUAL "" )
- list( APPEND GRIB_API_PATH "$ENV{GRIB_API_PATH}" )
- endif()
-
- if( DEFINED GRIB_API_PATH )
- find_path(GRIB_API_INCLUDE_DIR NAMES grib_api.h PATHS ${GRIB_API_PATH} ${GRIB_API_PATH}/include PATH_SUFFIXES grib_api NO_DEFAULT_PATH)
- find_library(GRIB_API_LIBRARY NAMES grib_api PATHS ${GRIB_API_PATH} ${GRIB_API_PATH}/lib PATH_SUFFIXES grib_api NO_DEFAULT_PATH)
- find_library(GRIB_API_LIB_F90 NAMES grib_api_f90 PATHS ${GRIB_API_PATH} ${GRIB_API_PATH}/lib PATH_SUFFIXES grib_api NO_DEFAULT_PATH)
- find_library(GRIB_API_LIB_F77 NAMES grib_api_f77 PATHS ${GRIB_API_PATH} ${GRIB_API_PATH}/lib PATH_SUFFIXES grib_api NO_DEFAULT_PATH)
- find_program(GRIB_API_INFO NAMES grib_info PATHS ${GRIB_API_PATH} ${GRIB_API_PATH}/bin PATH_SUFFIXES grib_api NO_DEFAULT_PATH)
- endif()
-
- find_path(GRIB_API_INCLUDE_DIR NAMES grib_api.h PATHS PATH_SUFFIXES grib_api )
- find_library( GRIB_API_LIBRARY NAMES grib_api PATHS PATH_SUFFIXES grib_api )
- find_library( GRIB_API_LIB_F90 NAMES grib_api_f90 PATHS PATH_SUFFIXES grib_api )
- find_library( GRIB_API_LIB_F77 NAMES grib_api_f77 PATHS PATH_SUFFIXES grib_api )
- find_program(GRIB_API_INFO NAMES grib_info PATHS PATH_SUFFIXES grib_api )
-
- list( APPEND GRIB_API_LIBRARIES ${GRIB_API_LIBRARY} ${GRIB_API_LIB_F90} ${GRIB_API_LIB_F77} )
- set( GRIB_API_INCLUDE_DIRS ${GRIB_API_INCLUDE_DIR} )
-
- if( GRIB_API_INFO )
-
- execute_process( COMMAND ${GRIB_API_INFO} -v OUTPUT_VARIABLE _grib_info_out ERROR_VARIABLE _grib_info_err OUTPUT_STRIP_TRAILING_WHITESPACE )
-
- # debug_var( _grib_info_out )
-
- string( REPLACE "." " " _version_list ${_grib_info_out} ) # dots to spaces
- separate_arguments( _version_list )
-
- list( GET _version_list 0 GRIB_API_MAJOR_VERSION )
- list( GET _version_list 1 GRIB_API_MINOR_VERSION )
- list( GET _version_list 2 GRIB_API_PATCH_VERSION )
-
- set( GRIB_API_VERSION "${GRIB_API_MAJOR_VERSION}.${GRIB_API_MINOR_VERSION}.${GRIB_API_PATCH_VERSION}" )
- set( GRIB_API_VERSION_STR "${_grib_info_out}" )
-
- set( grib_api_VERSION "${GRIB_API_VERSION}" )
- set( grib_api_VERSION_STR "${GRIB_API_VERSION_STR}" )
-
- endif()
-
- include(FindPackageHandleStandardArgs)
-
- # handle the QUIETLY and REQUIRED arguments and set GRIB_API_FOUND to TRUE
- find_package_handle_standard_args( grib_api DEFAULT_MSG
- GRIB_API_LIBRARY GRIB_API_INCLUDE_DIR GRIB_API_INFO )
-
- mark_as_advanced( GRIB_API_INCLUDE_DIR GRIB_API_LIBRARY GRIB_API_INFO )
-
- list( APPEND GRIB_API_DEFINITIONS ${_grib_api_jpg_defs} ${_grib_api_png_defs} )
- list( APPEND GRIB_API_INCLUDE_DIRS ${_grib_api_jpg_incs} ${_grib_api_png_incs} )
- list( APPEND GRIB_API_LIBRARIES ${_grib_api_jpg_libs} ${_grib_api_png_libs} )
-
- set( grib_api_FOUND ${GRIB_API_FOUND} )
-
-endif()
diff --git a/ecbuild/cmake/Findodb_api.cmake b/ecbuild/cmake/Findodb_api.cmake
deleted file mode 100644
index c573d9b..0000000
--- a/ecbuild/cmake/Findodb_api.cmake
+++ /dev/null
@@ -1,99 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-# - Try to find ODB_API
-# Once done this will define
-# ODB_API_FOUND - System has ODB_API
-# ODB_API_INCLUDE_DIRS - The ODB_API include directories
-# ODB_API_LIBRARIES - The libraries needed to use ODB_API
-# ODB_API_DEFINITIONS - Compiler switches required for using ODB_API
-
-if( NOT odb_api_FOUND )
-
- ecbuild_add_extra_search_paths( odb_api )
-
- # find external odb_api
-
- if( NOT DEFINED ODB_API_PATH AND NOT "$ENV{ODB_API_PATH}" STREQUAL "" )
- list( APPEND ODB_API_PATH "$ENV{ODB_API_PATH}" )
- endif()
-
- if( DEFINED ODB_API_PATH )
-
- find_path( ODB_API_INCLUDE_DIR
- NAMES odb_api_config.h
- PATHS ${ODB_API_PATH} ${ODB_API_PATH}/include
- PATH_SUFFIXES odb_api
- NO_DEFAULT_PATH )
-
- find_library( ODB_API_LIBRARY NAMES Odb
- PATHS ${ODB_API_PATH} ${ODB_API_PATH}/lib
- PATH_SUFFIXES odb_api
- NO_DEFAULT_PATH )
-
- find_library( ODB_API_ECLIB_LIBRARY NAMES Ec
- PATHS ${ODB_API_PATH} ${ODB_API_PATH}/lib
- PATH_SUFFIXES odb_api
- NO_DEFAULT_PATH )
- endif()
-
- find_path( ODB_API_INCLUDE_DIR
- NAMES odb_api_config.h
- PATHS
- PATH_SUFFIXES odb_api )
-
- find_library( ODB_API_LIBRARY NAMES Odb
- PATHS
- PATH_SUFFIXES odb_api )
-
- find_library( ODB_API_ECLIB_LIBRARY NAMES Ec
- PATHS
- PATH_SUFFIXES odb_api )
-
-
- # get the version
-
- if( ODB_API_INCLUDE_DIR )
-
- set(_odb_api_VERSION_REGEX "([0-9]+)")
-
- foreach( v MAJOR MINOR PATCH )
-
- file(STRINGS "${ODB_API_INCLUDE_DIR}/odb_api_config.h" _odb_api_${v}_VERSION_CONTENTS REGEX "#define ODB_API_${v}_VERSION ")
-
- if( "${_odb_api_${v}_VERSION_CONTENTS}" MATCHES ".*#define ODB_API_${v}_VERSION ${_odb_api_VERSION_REGEX}.*")
-
- set( ODB_API_${v}_VERSION "${CMAKE_MATCH_1}" )
-
- endif()
-
- endforeach()
-
- endif()
-
- set( ODB_API_VERSION "${ODB_API_MAJOR_VERSION}.${ODB_API_MINOR_VERSION}.${ODB_API_PATCH_VERSION}" )
- set( ODB_API_VERSION_STR "${_odb_info_out}" )
-
- set( odb_api_VERSION "${ODB_API_VERSION}" )
- set( odb_api_VERSION_STR "${ODB_API_VERSION_STR}" )
-
- # handle the QUIETLY and REQUIRED arguments and set ODB_API_FOUND to TRUE
-
- include(FindPackageHandleStandardArgs)
-
- find_package_handle_standard_args( odb_api DEFAULT_MSG
- ODB_API_LIBRARY ODB_API_ECLIB_LIBRARY ODB_API_INCLUDE_DIR )
-
- set( ODB_API_LIBRARIES ${ODB_API_LIBRARY} ${ODB_API_ECLIB_LIBRARY} )
- set( ODB_API_INCLUDE_DIRS ${ODB_API_INCLUDE_DIR} )
-
- mark_as_advanced( ODB_API_INCLUDE_DIR ODB_API_LIBRARY ODB_API_ECLIB_LIBRARY )
-
- set( odb_api_FOUND ${ODB_API_FOUND} )
-
-endif()
diff --git a/ecbuild/cmake/Findspot.cmake b/ecbuild/cmake/Findspot.cmake
deleted file mode 100644
index 6396ef0..0000000
--- a/ecbuild/cmake/Findspot.cmake
+++ /dev/null
@@ -1,67 +0,0 @@
-# (C) Copyright 1996-2012 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-# - Try to find ODB_API
-# Once done this will define
-# ODB_API_FOUND - System has ODB_API
-# ODB_API_INCLUDE_DIRS - The ODB_API include directories
-# ODB_API_LIBRARIES - The libraries needed to use ODB_API
-# ODB_API_DEFINITIONS - Compiler switches required for using ODB_API
-
-if( NOT spot_FOUND )
-
- ecbuild_add_extra_search_paths( spot )
-
- # find external odb_api
-
- if( NOT DEFINED SPOT_PATH AND NOT "$ENV{SPOT_PATH}" STREQUAL "" )
- list( APPEND SPOT_PATH "$ENV{SPOT_PATH}" )
- endif()
-
- if( DEFINED SPOT_PATH )
-
- find_path( SPOT_INCLUDE_DIR
- NAMES spot_database.h
- PATHS ${SPOT_PATH} ${SPOT_PATH}/include
- NO_DEFAULT_PATH )
-
- find_library( SPOT_LIBRARY NAMES spot_database
- PATHS ${SPOT_PATH} ${SPOT_PATH}/lib
- NO_DEFAULT_PATH )
-
- endif()
-
- find_path( SPOT_INCLUDE_DIR
- NAMES spot_database.h
- PATHS
- PATH_SUFFIXES spot )
-
- find_library( SPOT_LIBRARY NAMES spot_database
- PATHS
- PATH_SUFFIXES odb_api )
-
- find_library( ODB_API_ECLIB_LIBRARY NAMES Ec
- PATHS
- PATH_SUFFIXES spot )
-
-
- # get the version
-
- include(FindPackageHandleStandardArgs)
-
- find_package_handle_standard_args( spot DEFAULT_MSG
- SPOT_LIBRARY SPOT_INCLUDE_DIR )
-
- set( SPOT_LIBRARIES ${SPOT_LIBRARY} )
- set( SPOT_INCLUDE_DIRS ${SPOT_INCLUDE_DIR} )
-
- mark_as_advanced( SPOT_INCLUDE_DIR SPOT_LIBRARY )
-
- set( spot_FOUND ${SPOT_FOUND} )
-
-endif()
diff --git a/ecbuild/cmake/VERSION.cmake b/ecbuild/cmake/VERSION.cmake
deleted file mode 100644
index 40762d8..0000000
--- a/ecbuild/cmake/VERSION.cmake
+++ /dev/null
@@ -1,7 +0,0 @@
-set( ECBUILD_MAJOR_VERSION "1" )
-set( ECBUILD_MINOR_VERSION "7" )
-set( ECBUILD_PATCH_VERSION "0" )
-
-set( ECBUILD_VERSION_STR "1.7.0" )
-
-set( ECBUILD_MACRO_VERSION "${ECBUILD_MAJOR_VERSION}.${ECBUILD_MINOR_VERSION}" )
diff --git a/ecbuild/cmake/contrib/FindEigen3.cmake b/ecbuild/cmake/contrib/FindEigen3.cmake
deleted file mode 100644
index 72d4a9d..0000000
--- a/ecbuild/cmake/contrib/FindEigen3.cmake
+++ /dev/null
@@ -1,93 +0,0 @@
-# - Try to find Eigen3 lib
-#
-# This module supports requiring a minimum version, e.g. you can do
-# find_package(Eigen3 3.1.2)
-# to require version 3.1.2 or newer of Eigen3.
-#
-# Once done this will define
-#
-# EIGEN3_FOUND - system has eigen lib with correct version
-# EIGEN3_INCLUDE_DIR - the eigen include directory
-# EIGEN3_VERSION - eigen version
-
-# Copyright (c) 2006, 2007 Montel Laurent, <montel at kde.org>
-# Copyright (c) 2008, 2009 Gael Guennebaud, <g.gael at free.fr>
-# Copyright (c) 2009 Benoit Jacob <jacob.benoit.1 at gmail.com>
-# Redistribution and use is allowed according to the terms of the 2-clause BSD license.
-
-ecbuild_add_extra_search_paths( eigen )
-
-if(NOT Eigen3_FIND_VERSION)
- if(NOT Eigen3_FIND_VERSION_MAJOR)
- set(Eigen3_FIND_VERSION_MAJOR 2)
- endif(NOT Eigen3_FIND_VERSION_MAJOR)
- if(NOT Eigen3_FIND_VERSION_MINOR)
- set(Eigen3_FIND_VERSION_MINOR 91)
- endif(NOT Eigen3_FIND_VERSION_MINOR)
- if(NOT Eigen3_FIND_VERSION_PATCH)
- set(Eigen3_FIND_VERSION_PATCH 0)
- endif(NOT Eigen3_FIND_VERSION_PATCH)
-
- set(Eigen3_FIND_VERSION "${Eigen3_FIND_VERSION_MAJOR}.${Eigen3_FIND_VERSION_MINOR}.${Eigen3_FIND_VERSION_PATCH}")
-endif(NOT Eigen3_FIND_VERSION)
-
-macro(_eigen3_check_version)
- file(READ "${EIGEN3_INCLUDE_DIR}/Eigen/src/Core/util/Macros.h" _eigen3_version_header)
-
- string(REGEX MATCH "define[ \t]+EIGEN_WORLD_VERSION[ \t]+([0-9]+)" _eigen3_world_version_match "${_eigen3_version_header}")
- set(EIGEN3_WORLD_VERSION "${CMAKE_MATCH_1}")
- string(REGEX MATCH "define[ \t]+EIGEN_MAJOR_VERSION[ \t]+([0-9]+)" _eigen3_major_version_match "${_eigen3_version_header}")
- set(EIGEN3_MAJOR_VERSION "${CMAKE_MATCH_1}")
- string(REGEX MATCH "define[ \t]+EIGEN_MINOR_VERSION[ \t]+([0-9]+)" _eigen3_minor_version_match "${_eigen3_version_header}")
- set(EIGEN3_MINOR_VERSION "${CMAKE_MATCH_1}")
-
- set(EIGEN3_VERSION ${EIGEN3_WORLD_VERSION}.${EIGEN3_MAJOR_VERSION}.${EIGEN3_MINOR_VERSION})
- if(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION})
- set(EIGEN3_VERSION_OK FALSE)
- else(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION})
- set(EIGEN3_VERSION_OK TRUE)
- endif(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION})
-
- if(NOT EIGEN3_VERSION_OK)
-
- message(STATUS "Eigen3 version ${EIGEN3_VERSION} found in ${EIGEN3_INCLUDE_DIR}, "
- "but at least version ${Eigen3_FIND_VERSION} is required")
- else()
- set( EIGEN3_VERSION ${EIGEN3_VERSION} CACHE INTERNAL "Eigen3 version" )
- endif()
-
-endmacro(_eigen3_check_version)
-
-if(EIGEN3_INCLUDE_DIR)
-
- # in cache already
- _eigen3_check_version()
- set(EIGEN3_FOUND ${EIGEN3_VERSION_OK})
-
-else(EIGEN3_INCLUDE_DIR)
-
- find_path(EIGEN3_INCLUDE_DIR NAMES signature_of_eigen3_matrix_library
- PATHS
- ${CMAKE_INSTALL_PREFIX}/include
- ${KDE4_INCLUDE_DIR}
- ${EIGEN3_PATH}/include
- ${EIGEN3_DIR}/include
- ${EIGEN3_ROOT}/include
- ${EIGEN_PATH}/include
- ${EIGEN_DIR}/include
- ${EIGEN_ROOT}/include
- PATH_SUFFIXES eigen3 eigen
- )
-
- if(EIGEN3_INCLUDE_DIR)
- _eigen3_check_version()
- endif(EIGEN3_INCLUDE_DIR)
-
- include(FindPackageHandleStandardArgs)
- find_package_handle_standard_args(Eigen3 DEFAULT_MSG EIGEN3_INCLUDE_DIR EIGEN3_VERSION_OK)
-
- mark_as_advanced(EIGEN3_INCLUDE_DIR)
-
-endif(EIGEN3_INCLUDE_DIR)
-
-set( EIGEN3_INCLUDE_DIRS ${EIGEN3_INCLUDE_DIR} )
diff --git a/ecbuild/cmake/contrib/FindFFTW.cmake b/ecbuild/cmake/contrib/FindFFTW.cmake
deleted file mode 100644
index 1ddaf4c..0000000
--- a/ecbuild/cmake/contrib/FindFFTW.cmake
+++ /dev/null
@@ -1,124 +0,0 @@
-# - Find the FFTW library
-#
-# Usage:
-# find_package(FFTW [REQUIRED] [QUIET] )
-#
-# It sets the following variables:
-# FFTW_FOUND ... true if fftw is found on the system
-# FFTW_LIBRARIES ... full path to fftw library
-# FFTW_INCLUDES ... fftw include directory
-#
-# The following variables will be checked by the function
-# FFTW_USE_STATIC_LIBS ... if true, only static libraries are found
-# FFTW_ROOT ... if set, the libraries are exclusively searched
-# under this path
-# FFTW_LIBRARY ... fftw library to use
-# FFTW_INCLUDE_DIR ... fftw include directory
-#
-
-#=======================#
-#
-# From Eigen3
-#
-#========================
-
-#If environment variable FFTWDIR is specified, it has same effect as FFTW_ROOT
-if( NOT FFTW_ROOT AND ENV{FFTWDIR} )
- set( FFTW_ROOT $ENV{FFTWDIR} )
-endif()
-
-# Check if we can use PkgConfig
-find_package(PkgConfig)
-
-#Determine from PKG
-if( PKG_CONFIG_FOUND AND NOT FFTW_ROOT )
- pkg_check_modules( PKG_FFTW QUIET "fftw3" )
-endif()
-
-#Check whether to search static or dynamic libs
-set( CMAKE_FIND_LIBRARY_SUFFIXES_SAV ${CMAKE_FIND_LIBRARY_SUFFIXES} )
-
-if( ${FFTW_USE_STATIC_LIBS} )
- set( CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX} )
-else()
- set( CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_SHARED_LIBRARY_SUFFIX} )
-endif()
-
-if( FFTW_ROOT )
-
- #find libs
- find_library(
- FFTW_LIB
- NAMES "fftw3"
- PATHS ${FFTW_ROOT}
- PATH_SUFFIXES "lib" "lib64"
- NO_DEFAULT_PATH
- )
-
- find_library(
- FFTWF_LIB
- NAMES "fftw3f"
- PATHS ${FFTW_ROOT}
- PATH_SUFFIXES "lib" "lib64"
- NO_DEFAULT_PATH
- )
-
- find_library(
- FFTWL_LIB
- NAMES "fftw3l"
- PATHS ${FFTW_ROOT}
- PATH_SUFFIXES "lib" "lib64"
- NO_DEFAULT_PATH
- )
-
- #find includes
- find_path(
- FFTW_INCLUDES
- NAMES "fftw3.h"
- PATHS ${FFTW_ROOT}
- PATH_SUFFIXES "include"
- NO_DEFAULT_PATH
- )
-
-else()
-
- find_library(
- FFTW_LIB
- NAMES "fftw3"
- PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR}
- )
-
- find_library(
- FFTWF_LIB
- NAMES "fftw3f"
- PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR}
- )
-
-
- find_library(
- FFTWL_LIB
- NAMES "fftw3l"
- PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR}
- )
-
- find_path(
- FFTW_INCLUDES
- NAMES "fftw3.h"
- PATHS ${PKG_FFTW_INCLUDE_DIRS} ${INCLUDE_INSTALL_DIR}
- )
-
-endif( FFTW_ROOT )
-
-set(FFTW_LIBRARIES ${FFTW_LIB} ${FFTWF_LIB})
-
-if(FFTWL_LIB)
- set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTWL_LIB})
-endif()
-
-set( CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_SAV} )
-
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(FFTW DEFAULT_MSG
- FFTW_INCLUDES FFTW_LIBRARIES)
-
-mark_as_advanced(FFTW_INCLUDES FFTW_LIBRARIES FFTW_LIB FFTWF_LIB FFTWL_LIB)
\ No newline at end of file
diff --git a/ecbuild/cmake/contrib/FindNetCDF4.cmake b/ecbuild/cmake/contrib/FindNetCDF4.cmake
deleted file mode 100644
index 33e7b36..0000000
--- a/ecbuild/cmake/contrib/FindNetCDF4.cmake
+++ /dev/null
@@ -1,314 +0,0 @@
-# Project uclales
-# http://gitorious.org/uclales
-# License: Academic Free License v3.0
-#
-# - Find NETCDF, a library for reading and writing self describing array data.
-#
-# This module invokes the NETCDF wrapper compiler that should be installed
-# alongside NETCDF. Depending upon the NETCDF Configuration, the wrapper compiler
-# is called either h5cc or h5pcc. If this succeeds, the module will then call
-# the compiler with the -show argument to see what flags are used when compiling
-# an NETCDF client application.
-#
-# The module will optionally accept the COMPONENTS argument. If no COMPONENTS
-# are specified, then the find module will default to finding only the NETCDF C
-# library. If one or more COMPONENTS are specified, the module will attempt to
-# find the language bindings for the specified components. Currently, the only
-# valid components are C, CXX, FORTRAN and F90.
-#
-# On UNIX systems, this module will read the variable NETCDF_USE_STATIC_LIBRARIES
-# to determine whether or not to prefer a static link to a dynamic link for NETCDF
-# and all of it's dependencies. To use this feature, make sure that the
-# NETCDF_USE_STATIC_LIBRARIES variable is set before the call to find_package.
-#
-# To provide the module with a hint about where to find your NETCDF installation,
-# you can set the environment variable NETCDF_ROOT. The Find module will then
-# look in this path when searching for NETCDF executables, paths, and libraries.
-#
-# In addition to finding the includes and libraries required to compile an NETCDF
-# client application, this module also makes an effort to find tools that come
-# with the NETCDF distribution that may be useful for regression testing.
-#
-# This module will define the following variables:
-# NETCDF_INCLUDE_DIRS - Location of the NETCDF includes
-# NETCDF_INCLUDE_DIR - Location of the NETCDF includes (deprecated)
-# NETCDF_DEFINITIONS - Required compiler definitions for NETCDF
-# NETCDF_C_LIBRARIES - Required libraries for the NETCDF C bindings.
-# NETCDF_CXX_LIBRARIES - Required libraries for the NETCDF C++ bindings
-# NETCDF_FORTRAN_LIBRARIES - Required libraries for the NETCDF FORTRAN bindings
-# NETCDF_F90_LIBRARIES - Required libraries for the NETCDF FORTRAN 90 bindings
-# NETCDF_LIBRARIES - Required libraries for all requested bindings
-# NETCDF_FOUND - true if NETCDF was found on the system
-# NETCDF_LIBRARY_DIRS - the full set of library directories
-# NETCDF_IS_PARALLEL - Whether or not NETCDF was found with parallel IO support
-# NETCDF_CONFIG_EXECUTABLE - the path to the NC-CONFIG tool
-
-#=============================================================================
-# Copyright 2009 Kitware, Inc.
-#
-# Distributed under the OSI-approved BSD License (the "License");
-# see accompanying file Copyright.txt for details.
-#
-# This software is distributed WITHOUT ANY WARRANTY; without even the
-# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the License for more information.
-#=============================================================================
-# (To distribute this file outside of CMake, substitute the full
-# License text for the above reference.)
-
-# This module is maintained by Thijs Heus <thijs.heus at zmaw.de>.
-
-include(SelectLibraryConfigurations)
-include(FindPackageHandleStandardArgs)
-
-# List of the valid NETCDF components
-set( NETCDF_VALID_COMPONENTS
- FORTRAN
- F90
- CXX
- C
-)
-
-# Invoke the NETCDF wrapper compiler. The compiler return value is stored to the
-# return_value argument, the text output is stored to the output variable.
-macro( _NETCDF_CONFIG flag output return_value )
- if( NETCDF_CONFIG_EXECUTABLE )
- exec_program( ${NETCDF_CONFIG_EXECUTABLE}
- ARGS ${flag}
- OUTPUT_VARIABLE ${output}
- RETURN_VALUE ${return_value}
- )
- if( ${${return_value}} EQUAL 0 )
- # do nothing
- else()
- message( STATUS
- "Unable to determine ${flag} from NC-CONFIG." )
- endif()
- endif()
-endmacro()
-#
-# try to find the NETCDF wrapper compilers
-find_program( NETCDF_CONFIG_EXECUTABLE
- NAMES nc-config
- HINTS ENV NETCDF_ROOT
- PATHS
- PATH_SUFFIXES bin Bin
- DOC "NETCDF CONFIG PROGRAM. Used only to detect NETCDF compile flags." )
-mark_as_advanced( NETCDF_CONFIG_EXECUTABLE )
-
-set(output "no")
-_NETCDF_CONFIG (--has-hdf5 output return)
-set(HAS_HDF5 FALSE)
-
-if(${output} STREQUAL yes)
- set(HAS_HDF5 TRUE)
- set(HDF5_FIND_QUIETLY ${NETCDF_FIND_QUIETLY})
- set(HDF5_FIND_REQUIRED ${NETCDF_FIND_REQUIRED})
- find_package(HDF5)
-# list( APPEND NETCDF_LIBRARIES_DEBUG
-# ${HDF5_LIBRARIES_DEBUG} )
-# list( APPEND NETCDF_LIBRARIES_RELEASE
-# ${HDF5_LIBRARIES_RELEASE} )
- set (NETCDF_IS_PARALLEL ${HDF5_IS_PARALLEL})
-endif()
-_NETCDF_CONFIG (--has-pnetcdf output return)
-if(${output} STREQUAL yes)
- set (NETCDF_IS_PARALLEL TRUE)
-else()
-# set(NETCDF_IS_PARALLEL FALSE)
-endif()
-set( NETCDF_IS_PARALLEL TRUE CACHE BOOL
- "NETCDF library compiled with parallel IO support" )
-
-
-if( NETCDF_INCLUDE_DIRS AND NETCDF_LIBRARIES )
- # Do nothing: we already have NETCDF_INCLUDE_PATH and NETCDF_LIBRARIES in the
- # cache, it would be a shame to override them
-else()
- if( NOT NETCDF_FIND_COMPONENTS )
- set( NETCDF_LANGUAGE_BINDINGS "C" )
- else()
- # add the extra specified components, ensuring that they are valid.
- foreach( component ${NETCDF_FIND_COMPONENTS} )
- list( FIND NETCDF_VALID_COMPONENTS ${component} component_location )
- if( ${component_location} EQUAL -1 )
- message( FATAL_ERROR
- "\"${component}\" is not a valid NETCDF component." )
- else()
- list( APPEND NETCDF_LANGUAGE_BINDINGS ${component} )
- endif()
- endforeach()
- endif()
-
- # seed the initial lists of libraries to find with items we know we need
- set( NETCDF_C_INCLUDE_NAMES netcdf.h )
- set( NETCDF_CXX_INCLUDE_NAMES netcdfcpp.h ${NETCDF_C_INCLUDE_NAMES} )
- set( NETCDF_FORTRAN_INCLUDE_NAMES ${NETCDF_C_INCLUDE_NAMES} )
- set( NETCDF_F90_INCLUDE_NAMES netcdf.mod typesizes.mod ${NETCDF_C_INCLUDE_NAMES} )
-
- set( NETCDF_C_LIBRARY_NAMES netcdf)
- set( NETCDF_CXX_LIBRARY_NAMES netcdf_c++ ${NETCDF_C_LIBRARY_NAMES} )
- set( NETCDF_FORTRAN_LIBRARY_NAMES netcdff ${NETCDF_C_LIBRARY_NAMES})
- set( NETCDF_F90_LIBRARY_NAMES ${NETCDF_FORTRAN_LIBRARY_NAMES} )
-
- set( NETCDF_REQUIRED netcdf.h netcdfcpp.h netcdf.mod typesizes.mod netcdf netcdff netcdf_c++)
-
- foreach( LANGUAGE ${NETCDF_LANGUAGE_BINDINGS} )
- # debug_var(LANGUAGE)
- set( NETCDF_${LANGUAGE}_FOUND 1 ) # disable this in following if necessary
-
- # find the NETCDF includes
- foreach( INC ${NETCDF_${LANGUAGE}_INCLUDE_NAMES} )
- find_path( NETCDF_${INC}_INCLUDE_DIR ${INC}
- HINTS
- ${NETCDF_${LANGUAGE}_INCLUDE_FLAGS}
- ENV NETCDF_ROOT
- PATHS
- PATH_SUFFIXES
- include
- Include
- )
- mark_as_advanced( NETCDF_${INC}_INCLUDE_DIR )
- # debug_var( NETCDF_${INC}_INCLUDE_DIR)
- if (NETCDF_${INC}_INCLUDE_DIR)
- list( APPEND NETCDF_INCLUDE_DIRS ${NETCDF_${INC}_INCLUDE_DIR} )
- else()
- list( FIND NETCDF_REQUIRED ${INC} location )
- if( ${location} EQUAL -1 )
- else()
- if(NETCDF_FIND_REQUIRED)
- message( SEND_ERROR "\"${INC}\" is not found for NetCDF component ${LANGUAGE}" )
- elseif( NOT NETCDF_FIND_QUIETLY )
- message( STATUS "\"${INC}\" is not found for NetCDF component ${LANGUAGE}" )
- endif()
- set( NETCDF_${LANGUAGE}_FOUND 0 )
- else()
- endif()
- endif()
- endforeach()
- # find the NETCDF libraries
- foreach( LIB ${NETCDF_${LANGUAGE}_LIBRARY_NAMES} )
- if( UNIX AND NETCDF_USE_STATIC_LIBRARIES )
- # According to bug 1643 on the CMake bug tracker, this is the
- # preferred method for searching for a static library.
- # See http://www.cmake.org/Bug/view.php?id=1643. We search
- # first for the full static library name, but fall back to a
- # generic search on the name if the static search fails.
- set( THIS_LIBRARY_SEARCH_DEBUG lib${LIB}d.a ${LIB}d )
- set( THIS_LIBRARY_SEARCH_RELEASE lib${LIB}.a ${LIB} )
- else()
- set( THIS_LIBRARY_SEARCH_DEBUG ${LIB}d )
- set( THIS_LIBRARY_SEARCH_RELEASE ${LIB} )
- endif()
- find_library( NETCDF_${LIB}_LIBRARY_DEBUG
- NAMES ${THIS_LIBRARY_SEARCH_DEBUG}
- HINTS ${NETCDF_${LANGUAGE}_LIBRARY_DIRS}
- ENV NETCDF_ROOT
- PATHS
- PATH_SUFFIXES lib64 Lib64 lib Lib)
- find_library( NETCDF_${LIB}_LIBRARY_RELEASE
- NAMES ${THIS_LIBRARY_SEARCH_RELEASE}
- HINTS ${NETCDF_${LANGUAGE}_LIBRARY_DIRS}
- ENV NETCDF_ROOT
- PATHS
- PATH_SUFFIXES lib64 Lib64 lib Lib )
- select_library_configurations( NETCDF_${LIB} )
- # even though we adjusted the individual library names in
- # select_library_configurations, we still need to distinguish
- # between debug and release variants because NETCDF_LIBRARIES will
- # need to specify different lists for debug and optimized builds.
- # We can't just use the NETCDF_${LIB}_LIBRARY variable (which was set
- # up by the selection macro above) because it may specify debug and
- # optimized variants for a particular library, but a list of
- # libraries is allowed to specify debug and optimized only once.
- if (NETCDF_${LIB}_LIBRARY_RELEASE)
- list( APPEND NETCDF_LIBRARIES_RELEASE ${NETCDF_${LIB}_LIBRARY_RELEASE} )
- list( APPEND NETCDF_${LANGUAGE}_LIBRARIES_RELEASE ${NETCDF_${LIB}_LIBRARY_RELEASE} )
- endif()
- if (NETCDF_${LIB}_LIBRARY_DEBUG)
- list( APPEND NETCDF_LIBRARIES_DEBUG ${NETCDF_${LIB}_LIBRARY_DEBUG} )
- list( APPEND NETCDF_${LANGUAGE}_LIBRARIES_DEBUG ${NETCDF_${LIB}_LIBRARY_DEBUG} )
- endif()
- if (NETCDF_${LIB}_LIBRARY_RELEASE OR NETCDF_${LIB}_LIBRARY_DEBUG )
- else()
- # message( STATUS "\"${LIB}\" is not found." )
- list( FIND NETCDF_REQUIRED ${LIB} location )
- if( ${location} EQUAL -1 )
- else()
- if(NETCDF_FIND_REQUIRED)
- message( SEND_ERROR "\"${LIB}\" is not found for NetCDF component ${LANGUAGE}." )
- elseif( NOT NETCDF_FIND_QUIETLY )
- message( STATUS "\"${LIB}\" is not found for NetCDF component ${LANGUAGE}." )
- else()
- set( NETCDF_${LANGUAGE}_FOUND 0 )
- endif()
- endif()
- endif()
- endforeach()
- list( APPEND NETCDF_LIBRARY_DIRS ${NETCDF_${LANGUAGE}_LIBRARY_DIRS} )
-
- # Append the libraries for this language binding to the list of all
- # required libraries.
-
- # debug_var( NETCDF_${LANGUAGE}_FOUND )
- if( NETCDF_${LANGUAGE}_FOUND )
- if( CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE )
- list( APPEND NETCDF_${LANGUAGE}_LIBRARIES
- debug ${NETCDF_${LANGUAGE}_LIBRARIES_DEBUG}
- optimized ${NETCDF_${LANGUAGE}_LIBRARIES_RELEASE} )
- else()
- list( APPEND NETCDF_${LANGUAGE}_LIBRARIES
- ${NETCDF_${LANGUAGE}_LIBRARIES_RELEASE} )
- endif()
- endif()
- # debug_var( NETCDF_${LANGUAGE}_LIBRARIES )
- list( APPEND NETCDF_FOUND_REQUIRED_VARS NETCDF_${LANGUAGE}_FOUND )
- endforeach()
-
- # We may have picked up some duplicates in various lists during the above
- # process for the language bindings (both the C and C++ bindings depend on
- # libz for example). Remove the duplicates.
- if( NETCDF_INCLUDE_DIRS )
- list( REMOVE_DUPLICATES NETCDF_INCLUDE_DIRS )
- endif()
- if( NETCDF_LIBRARIES_DEBUG )
- list( REMOVE_DUPLICATES NETCDF_LIBRARIES_DEBUG )
- endif()
- if( NETCDF_LIBRARIES_RELEASE )
- list( REMOVE_DUPLICATES NETCDF_LIBRARIES_RELEASE )
- endif()
- if( NETCDF_LIBRARY_DIRS )
- list( REMOVE_DUPLICATES NETCDF_LIBRARY_DIRS )
- endif()
-
- # Construct the complete list of NETCDF libraries with debug and optimized
- # variants when the generator supports them.
- if( CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE )
- set( NETCDF_LIBRARIES
- debug ${NETCDF_LIBRARIES_DEBUG}
- optimized ${NETCDF_LIBRARIES_RELEASE} )
- else()
- set( NETCDF_LIBRARIES ${NETCDF_LIBRARIES_RELEASE} )
- endif()
-endif()
-
-set( NETCDF4_FIND_QUIETLY ${NETCDF_FIND_QUIETLY} )
-set( NETCDF4_FIND_REQUIRED ${NETCDF_FIND_REQUIRED} )
-find_package_handle_standard_args( NETCDF4 DEFAULT_MSG
- ${NETCDF_FOUND_REQUIRED_VARS}
- NETCDF_LIBRARIES
- NETCDF_INCLUDE_DIRS
-)
-
-mark_as_advanced(
- NETCDF_INCLUDE_DIRS
- NETCDF_LIBRARIES
- NETCDF_LIBRARY_DIRS
-)
-
-set( NETCDF_FOUND ${NETCDF4_FOUND} )
-
-# For backwards compatibility we set NETCDF_INCLUDE_DIR to the value of
-# NETCDF_INCLUDE_DIRS
-set( NETCDF_INCLUDE_DIR "${NETCDF_INCLUDE_DIRS}" )
-
diff --git a/ecbuild/cmake/contrib/GetGitRevisionDescription.cmake.in b/ecbuild/cmake/contrib/GetGitRevisionDescription.cmake.in
deleted file mode 100644
index 7a3e42f..0000000
--- a/ecbuild/cmake/contrib/GetGitRevisionDescription.cmake.in
+++ /dev/null
@@ -1,38 +0,0 @@
-#
-# Internal file for GetGitRevisionDescription.cmake
-#
-# Requires CMake 2.6 or newer (uses the 'function' command)
-#
-# Original Author:
-# 2009-2010 Ryan Pavlik <rpavlik at iastate.edu> <abiryan at ryand.net>
-# http://academic.cleardefinition.com
-# Iowa State University HCI Graduate Program/VRAC
-#
-# Copyright Iowa State University 2009-2010.
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or copy at
-# http://www.boost.org/LICENSE_1_0.txt)
-
-set(HEAD_HASH)
-
-file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
-
-string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
-if(HEAD_CONTENTS MATCHES "ref")
- # named branch
- string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
- if(EXISTS "@GIT_DIR@/${HEAD_REF}")
- configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
- elseif(EXISTS "@GIT_DIR@/logs/${HEAD_REF}")
- configure_file("@GIT_DIR@/logs/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
- set(HEAD_HASH "${HEAD_REF}")
- endif()
-else()
- # detached HEAD
- configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
-endif()
-
-if(NOT HEAD_HASH)
- file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
- string(STRIP "${HEAD_HASH}" HEAD_HASH)
-endif()
\ No newline at end of file
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/tests/CMakeLists.txt b/ecbuild/cmake/contrib/GreatCMakeCookOff/tests/CMakeLists.txt
deleted file mode 100644
index f2eb4d0..0000000
--- a/ecbuild/cmake/contrib/GreatCMakeCookOff/tests/CMakeLists.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-cmake_minimum_required(VERSION 2.8.3 FATAL_ERROR)
-project(COOKOFF_TEST)
-
-enable_testing()
-
-include(${PROJECT_SOURCE_DIR}/../TestCMake.cmake)
-
-cmake_test(checkisnan SOURCE)
-cmake_test(checkcpp11flags)
-cmake_test(addgtest NOEXEC SOURCE --test-command ${CMAKE_MAKE_PROGRAM} test)
-
-add_subdirectory(cpp11)
diff --git a/ecbuild/cmake/contrib/GreatCMakeCookOff/tests/cpp11/CMakeLists.txt b/ecbuild/cmake/contrib/GreatCMakeCookOff/tests/cpp11/CMakeLists.txt
deleted file mode 100644
index 45d20a5..0000000
--- a/ecbuild/cmake/contrib/GreatCMakeCookOff/tests/cpp11/CMakeLists.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-cmake_test(allfeatures)
-cmake_test(parse_input_features)
-cmake_test(check_features)
diff --git a/ecbuild/cmake/ecbuild_add_cxx11_flags.cmake b/ecbuild/cmake/ecbuild_add_cxx11_flags.cmake
deleted file mode 100644
index 414f39f..0000000
--- a/ecbuild/cmake/ecbuild_add_cxx11_flags.cmake
+++ /dev/null
@@ -1,25 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-############################################################################################
-# macro to add cxx11 flags to compilation
-# uses macros from the project github.com/UCL/GreatCMakeCookOff
-
-macro( ecbuild_add_cxx11_flags )
-
- # if( CMAKE_COMPILER_IS_GNUCXX )
- # if( CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7 )
- # cmake_add_cxx_flags("-std=c++0x")
- # else()
- # cmake_add_cxx_flags("-std=c++11")
- # endif()
- # endif()
-
- include( ${ECBUILD_MACROS_DIR}/contrib/GreatCMakeCookOff/AddCPP11Flags.cmake )
-
-endmacro( ecbuild_add_cxx11_flags )
diff --git a/ecbuild/cmake/ecbuild_add_executable.cmake b/ecbuild/cmake/ecbuild_add_executable.cmake
deleted file mode 100644
index 389505a..0000000
--- a/ecbuild/cmake/ecbuild_add_executable.cmake
+++ /dev/null
@@ -1,197 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-##############################################################################
-# macro for adding a test
-##############################################################################
-
-macro( ecbuild_add_executable )
-
- set( options NOINSTALL AUTO_VERSION )
- set( single_value_args TARGET COMPONENT LINKER_LANGUAGE VERSION OUTPUT_NAME )
- set( multi_value_args SOURCES TEMPLATES LIBS INCLUDES DEPENDS PERSISTENT DEFINITIONS CFLAGS CXXFLAGS FFLAGS GENERATED CONDITION )
-
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_add_executable(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
-
- if( NOT _PAR_TARGET )
- message(FATAL_ERROR "The call to ecbuild_add_executable() doesn't specify the TARGET.")
- endif()
-
- if( NOT _PAR_SOURCES )
- message(FATAL_ERROR "The call to ecbuild_add_executable() doesn't specify the SOURCES.")
- endif()
-
- ### conditional build
-
- if( DEFINED _PAR_CONDITION )
- set(_target_condition_file "${CMAKE_CURRENT_BINARY_DIR}/set_${_PAR_TARGET}_condition.cmake")
- file( WRITE ${_target_condition_file} " if( ")
- foreach( term ${_PAR_CONDITION} )
- file( APPEND ${_target_condition_file} " ${term}")
- endforeach()
- file( APPEND ${_target_condition_file} " )\n set(_${_PAR_TARGET}_condition TRUE)\n else()\n set(_${_PAR_TARGET}_condition FALSE)\n endif()\n")
- include( ${_target_condition_file} )
- else()
- set( _${_PAR_TARGET}_condition TRUE )
- endif()
-
- if( _${_PAR_TARGET}_condition )
-
- # add include dirs if defined
- if( DEFINED _PAR_INCLUDES )
- list(REMOVE_DUPLICATES _PAR_INCLUDES )
- foreach( path ${_PAR_INCLUDES} ) # skip NOTFOUND
- if( path )
- include_directories( ${path} )
- # else()
- # message( WARNING "Path ${path} was skipped" )
- endif()
- endforeach()
- endif()
-
- # add persistent layer files
- if( DEFINED _PAR_PERSISTENT )
- if( DEFINED PERSISTENT_NAMESPACE )
- ecbuild_add_persistent( SRC_LIST _PAR_SOURCES FILES ${_PAR_PERSISTENT} NAMESPACE ${PERSISTENT_NAMESPACE} )
- else()
- ecbuild_add_persistent( SRC_LIST _PAR_SOURCES FILES ${_PAR_PERSISTENT} )
- endif()
- endif()
-
- # add templates to project files and remove from compilation sources
- if( DEFINED _PAR_TEMPLATES )
- list( REMOVE_ITEM _PAR_SOURCES ${_PAR_TEMPLATES} )
- ecbuild_declare_project_files( ${_PAR_TEMPLATES} )
- add_custom_target( ${_PAR_TARGET}_templates SOURCES ${_PAR_TEMPLATES} )
- endif()
-
- # add the executable target
- add_executable( ${_PAR_TARGET} ${_PAR_SOURCES} )
-
- # set OUTPUT_NAME
-
- if( DEFINED _PAR_OUTPUT_NAME )
- set_target_properties( ${_PAR_TARGET} PROPERTIES OUTPUT_NAME ${_PAR_OUTPUT_NAME} )
- endif()
-
- # add extra dependencies
- if( DEFINED _PAR_DEPENDS)
- add_dependencies( ${_PAR_TARGET} ${_PAR_DEPENDS} )
- endif()
-
- # add the link libraries
- if( DEFINED _PAR_LIBS )
- list(REMOVE_DUPLICATES _PAR_LIBS )
- list(REMOVE_ITEM _PAR_LIBS debug)
- list(REMOVE_ITEM _PAR_LIBS optimized)
- foreach( lib ${_PAR_LIBS} ) # skip NOTFOUND
- if( lib )
- target_link_libraries( ${_PAR_TARGET} ${lib} )
- else()
-# message( WARNING "Lib ${lib} was skipped" )
- endif()
- endforeach()
- endif()
-
- # add local flags
- if( DEFINED _PAR_CFLAGS )
- set_source_files_properties( ${${_PAR_TARGET}_c_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_CFLAGS}" )
- endif()
- if( DEFINED _PAR_CXXFLAGS )
- set_source_files_properties( ${${_PAR_TARGET}_cxx_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_CXXFLAGS}" )
- endif()
- if( DEFINED _PAR_FFLAGS )
- set_source_files_properties( ${${_PAR_TARGET}_f_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_FFLAGS}" )
- endif()
- if( DEFINED _PAR_GENERATED )
- set_source_files_properties( ${_PAR_GENERATED} PROPERTIES GENERATED 1 )
- endif()
-
- # define VERSION if requested
- if( DEFINED _PAR_VERSION )
- set_target_properties( ${_PAR_TARGET} PROPERTIES VERSION "${_PAR_VERSION}" )
- else()
- if( _PAR_AUTO_VERSION )
- set_target_properties( ${_PAR_TARGET} PROPERTIES VERSION "${${PNAME}_MAJOR_VERSION}.${${PNAME}_MINOR_VERSION}" )
- endif()
- endif()
-
- # filter sources
-
- ecbuild_separate_sources( TARGET ${_PAR_TARGET} SOURCES ${_PAR_SOURCES} )
-
-# debug_var( ${_PAR_TARGET}_h_srcs )
-# debug_var( ${_PAR_TARGET}_c_srcs )
-# debug_var( ${_PAR_TARGET}_cxx_srcs )
-# debug_var( ${_PAR_TARGET}_f_srcs )
-
- # installation
-
- if( NOT _PAR_NOINSTALL )
-
- # add installation paths and associate with defined component
-# if( DEFINED _PAR_COMPONENT )
-# set( COMPONENT_DIRECTIVE "${_PAR_COMPONENT}" )
-# else()
-# set( COMPONENT_DIRECTIVE "${PROJECT_NAME}" )
-# endif()
-
- install( TARGETS ${_PAR_TARGET}
- EXPORT ${CMAKE_PROJECT_NAME}-targets
- RUNTIME DESTINATION ${INSTALL_BIN_DIR}
- LIBRARY DESTINATION ${INSTALL_LIB_DIR}
- ARCHIVE DESTINATION ${INSTALL_LIB_DIR} )
-# COMPONENT ${COMPONENT_DIRECTIVE} )
-
- # set build location
-
- set_property( TARGET ${_PAR_TARGET} PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin )
-
- # export location of target to other projects -- must be exactly after setting the build location (see previous command)
-
- export( TARGETS ${_PAR_TARGET} APPEND FILE "${TOP_PROJECT_TARGETS_FILE}" )
-
- else()
- # NOINSTALL targets are always built the build_rpath, not the install_rpath
- set_property( TARGET ${_PAR_TARGET} PROPERTY SKIP_BUILD_RPATH FALSE )
- set_property( TARGET ${_PAR_TARGET} PROPERTY BUILD_WITH_INSTALL_RPATH FALSE )
- endif()
-
- # add definitions to compilation
- if( DEFINED _PAR_DEFINITIONS )
- get_property( _target_defs TARGET ${_PAR_TARGET} PROPERTY COMPILE_DEFINITIONS )
- list( APPEND _target_defs ${_PAR_DEFINITIONS} )
- set_property( TARGET ${_PAR_TARGET} PROPERTY COMPILE_DEFINITIONS ${_target_defs} )
- endif()
-
- # set linker language
- if( DEFINED _PAR_LINKER_LANGUAGE )
- set_property( TARGET ${_PAR_TARGET} PROPERTY LINKER_LANGUAGE ${_PAR_LINKER_LANGUAGE} )
- endif()
-
- # make sure target is removed before - some problems with AIX
- add_custom_command( TARGET ${_PAR_TARGET} PRE_BUILD COMMAND ${CMAKE_COMMAND} -E remove $<TARGET_FILE:${_PAR_TARGET}> )
-
- # for the links target
- if( NOT _PAR_NOINSTALL )
- ecbuild_link_exe( ${_PAR_TARGET} $<TARGET_FILE_NAME:${_PAR_TARGET}> $<TARGET_FILE:${_PAR_TARGET}> )
- endif()
-
- # append to the list of this project targets
- set( ${PROJECT_NAME}_ALL_EXES ${${PROJECT_NAME}_ALL_EXES} ${_PAR_TARGET} CACHE INTERNAL "" )
-
- endif()
-
- # mark project files
- ecbuild_declare_project_files( ${_PAR_SOURCES} )
-
-endmacro( ecbuild_add_executable )
diff --git a/ecbuild/cmake/ecbuild_add_extra_search_paths.cmake b/ecbuild/cmake/ecbuild_add_extra_search_paths.cmake
deleted file mode 100644
index 8e28091..0000000
--- a/ecbuild/cmake/ecbuild_add_extra_search_paths.cmake
+++ /dev/null
@@ -1,34 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-############################################################################################
-#
-# macro for adding search paths to CMAKE_PREFIX_PATH
-# for example the ECMWF /usr/local/apps paths
-#
-# usage: ecbuild_add_extra_search_paths( netcdf4 )
-
-function( ecbuild_add_extra_search_paths pkg )
-
-# debug_var( pkg )
-
- ecbuild_list_extra_search_paths( ${pkg} CMAKE_PREFIX_PATH )
-
- set( CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} PARENT_SCOPE )
-
- # fixes BOOST_ROOT taking precedence on the search for location
- if( ${pkg} STREQUAL "boost" )
- if( BOOST_ROOT OR BOOSTROOT OR DEFINED ENV{BOOST_ROOT} OR DEFINED ENV{BOOSTROOT} )
- set( CMAKE_PREFIX_PATH ${BOOST_ROOT} ${BOOSTROOT} $ENV{BOOST_ROOT} $ENV{BOOSTROOT} ${CMAKE_PREFIX_PATH} )
- endif()
- endif()
-
-# debug_var( CMAKE_PREFIX_PATH )
-
-endfunction()
-
diff --git a/ecbuild/cmake/ecbuild_add_library.cmake b/ecbuild/cmake/ecbuild_add_library.cmake
deleted file mode 100644
index a7e3dd2..0000000
--- a/ecbuild/cmake/ecbuild_add_library.cmake
+++ /dev/null
@@ -1,328 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-##############################################################################
-# auxiliary macro for adding a library
-##############################################################################
-
-function( ecbuild_add_library_impl )
-
- set( options NOINSTALL AUTO_VERSION )
- set( single_value_args TARGET TYPE COMPONENT INSTALL_HEADERS LINKER_LANGUAGE HEADER_DESTINATION VERSION OUTPUT_NAME )
- set( multi_value_args SOURCES TEMPLATES LIBS INCLUDES DEPENDS PERSISTENT DEFINITIONS CFLAGS CXXFLAGS FFLAGS GENERATED CONDITION )
-
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_add_library(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
-
- if( NOT _PAR_TARGET )
- message(FATAL_ERROR "The call to ecbuild_add_library() doesn't specify the TARGET.")
- endif()
-
- if( NOT _PAR_SOURCES )
- message(FATAL_ERROR "The call to ecbuild_add_library() doesn't specify the SOURCES.")
- endif()
-
- # get_filename_component( currdir ${CMAKE_CURRENT_SOURCE_DIR} NAME )
-
- # file(RELATIVE_PATH reldir ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR} )
-
- # debug_var( currdir )
- # debug_var( reldir )
-
- ### conditional build
-
- if( DEFINED _PAR_CONDITION )
- set(_target_condition_file "${CMAKE_CURRENT_BINARY_DIR}/set_${_PAR_TARGET}_condition.cmake")
- file( WRITE ${_target_condition_file} " if( ")
- foreach( term ${_PAR_CONDITION} )
- file( APPEND ${_target_condition_file} " ${term}")
- endforeach()
- file( APPEND ${_target_condition_file} " )\n set(_${_PAR_TARGET}_condition TRUE)\n else()\n set(_${_PAR_TARGET}_condition FALSE)\n endif()\n")
- include( ${_target_condition_file} )
- else()
- set( _${_PAR_TARGET}_condition TRUE )
- endif()
-
- if( _${_PAR_TARGET}_condition )
-
- # defines the type of library
- if( DEFINED _PAR_TYPE )
- # checks that is either SHARED or STATIC or MODULE
- if( NOT _PAR_TYPE MATCHES "STATIC" AND
- NOT _PAR_TYPE MATCHES "SHARED" AND
- NOT _PAR_TYPE MATCHES "MODULE" )
- message( FATAL_ERROR "library type must be one of [ STATIC | SHARED | MODULE ]" )
- endif()
- endif()
-
-
- # add persistent layer files
- if( DEFINED _PAR_PERSISTENT )
- if( DEFINED PERSISTENT_NAMESPACE )
- ecbuild_add_persistent( SRC_LIST _PAR_SOURCES FILES ${_PAR_PERSISTENT} NAMESPACE ${PERSISTENT_NAMESPACE} )
- else()
- ecbuild_add_persistent( SRC_LIST _PAR_SOURCES FILES ${_PAR_PERSISTENT} )
- endif()
- endif()
-
- # add templates to project files and remove from compilation sources
- if( DEFINED _PAR_TEMPLATES )
- list( REMOVE_ITEM _PAR_SOURCES ${_PAR_TEMPLATES} )
- ecbuild_declare_project_files( ${_PAR_TEMPLATES} )
- add_custom_target( ${_PAR_TARGET}_templates SOURCES ${_PAR_TEMPLATES} )
- endif()
-
- add_library( ${_PAR_TARGET} ${_PAR_TYPE} ${_PAR_SOURCES} )
-
- # set OUTPUT_NAME
-
- if( DEFINED _PAR_OUTPUT_NAME )
- set_target_properties( ${_PAR_TARGET} PROPERTIES OUTPUT_NAME ${_PAR_OUTPUT_NAME} )
- endif()
-
- # add extra dependencies
- if( DEFINED _PAR_DEPENDS)
- add_dependencies( ${_PAR_TARGET} ${_PAR_DEPENDS} )
- endif()
-
- # add the link libraries
- if( DEFINED _PAR_LIBS )
- list(REMOVE_DUPLICATES _PAR_LIBS )
- list(REMOVE_ITEM _PAR_LIBS debug)
- list(REMOVE_ITEM _PAR_LIBS optimized)
- foreach( lib ${_PAR_LIBS} ) # skip NOTFOUND
- if( lib )
- target_link_libraries( ${_PAR_TARGET} ${lib} )
- else()
-# message( WARNING "Lib ${lib} was skipped" )
- endif()
- endforeach()
- endif()
-
- # add include dirs if defined
- if( DEFINED _PAR_INCLUDES )
- list( REMOVE_DUPLICATES _PAR_INCLUDES )
- foreach( path ${_PAR_INCLUDES} ) # skip NOTFOUND
- if( path )
- if( "${CMAKE_VERSION}" VERSION_LESS "2.8.11" )
- include_directories( ${path} )
- else()
- target_include_directories( ${_PAR_TARGET} PUBLIC ${path} )
- endif()
- # else()
- # message( WARNING "Path ${path} was skipped" )
- endif()
- endforeach()
- endif()
-
- # FIX: Cray compiler PIC option is not detected by CMake
-
- get_property( _target_pic TARGET ${_PAR_TARGET} PROPERTY POSITION_INDEPENDENT_CODE )
- if( _target_pic )
- if( "${CMAKE_C_COMPILER_ID}" STREQUAL "Cray" )
- set( _PAR_CFLAGS "-fPIC -h PIC ${_PAR_CFLAGS}" )
- endif()
- if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Cray" )
- set( _PAR_CXXFLAGS "-fPIC -h PIC ${_PAR_CXXFLAGS}" )
- endif()
- if( "${CMAKE_Fortran_COMPILER_ID}" STREQUAL "Cray" )
- set( _PAR_FFLAGS "-fPIC -h PIC ${_PAR_FFLAGS}" )
- endif()
- endif()
-
- # define VERSION if requested
- if( DEFINED _PAR_VERSION )
- set_target_properties( ${_PAR_TARGET} PROPERTIES VERSION "${_PAR_VERSION}" )
- else()
- if( _PAR_AUTO_VERSION OR LIBS_VERSION MATCHES "[Aa][Uu][Tt][Oo]")
- set_target_properties( ${_PAR_TARGET} PROPERTIES VERSION "${${PNAME}_MAJOR_VERSION}.${${PNAME}_MINOR_VERSION}" )
- endif()
- if( LIBS_VERSION AND NOT LIBS_VERSION MATCHES "[Aa][Uu][Tt][Oo]" )
- set_target_properties( ${_PAR_TARGET} PROPERTIES VERSION "${LIBS_VERSION}" )
- endif()
- endif()
-
- # filter sources
-
- ecbuild_separate_sources( TARGET ${_PAR_TARGET} SOURCES ${_PAR_SOURCES} )
-
-# debug_var( ${_PAR_TARGET}_h_srcs )
-# debug_var( ${_PAR_TARGET}_c_srcs )
-# debug_var( ${_PAR_TARGET}_cxx_srcs )
-# debug_var( ${_PAR_TARGET}_f_srcs )
-
- # add local flags
-
- if( DEFINED _PAR_CFLAGS )
- set_source_files_properties( ${${_PAR_TARGET}_c_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_CFLAGS}" )
- endif()
- if( DEFINED _PAR_CXXFLAGS )
- set_source_files_properties( ${${_PAR_TARGET}_cxx_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_CXXFLAGS}" )
- endif()
- if( DEFINED _PAR_FFLAGS )
- set_source_files_properties( ${${_PAR_TARGET}_f_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_FFLAGS}" )
- endif()
- if( DEFINED _PAR_GENERATED )
- set_source_files_properties( ${_PAR_GENERATED} PROPERTIES GENERATED 1 )
- endif()
-
- # set linker language
- if( DEFINED _PAR_LINKER_LANGUAGE )
- set_property( TARGET ${_PAR_TARGET} PROPERTY LINKER_LANGUAGE ${_PAR_LINKER_LANGUAGE} )
- endif()
-
- # installation
-
- if( NOT _PAR_NOINSTALL )
-
- # and associate with defined component
-# if( DEFINED _PAR_COMPONENT )
-# set( COMPONENT_DIRECTIVE "${_PAR_COMPONENT}" )
-# else()
-# set( COMPONENT_DIRECTIVE "${PROJECT_NAME}" )
-# endif()
-
- install( TARGETS ${_PAR_TARGET}
- EXPORT ${CMAKE_PROJECT_NAME}-targets
- RUNTIME DESTINATION ${INSTALL_BIN_DIR}
- LIBRARY DESTINATION ${INSTALL_LIB_DIR}
- ARCHIVE DESTINATION ${INSTALL_LIB_DIR} )
-# COMPONENT ${COMPONENT_DIRECTIVE} )
-
- # install headers
- if( _PAR_HEADER_DESTINATION )
- set( _h_destination "${_PAR_HEADER_DESTINATION}" )
- else()
- set( _h_destination "${INSTALL_INCLUDE_DIR}" )
- endif()
-
- if( _PAR_INSTALL_HEADERS )
- if( _PAR_INSTALL_HEADERS MATCHES "LISTED" )
- foreach( file ${${_PAR_TARGET}_h_srcs} )
- get_filename_component( _file_dir ${file} PATH )
- install( FILES ${file} DESTINATION "${_h_destination}/${_file_dir}" )
- endforeach()
- if( DEFINED _PAR_TEMPLATES )
- foreach( file ${_PAR_TEMPLATES} )
- get_filename_component( _file_dir ${file} PATH )
- install( FILES ${file} DESTINATION "${_h_destination}/${_file_dir}" )
- endforeach()
- endif()
- if( DEFINED _PAR_PERSISTENT )
- foreach( file ${_PAR_PERSISTENT} )
- get_filename_component( _file_dir ${file} PATH )
- get_filename_component( _file_we ${file} NAME_WE )
- set( pfile "${CMAKE_CURRENT_BINARY_DIR}/${_file_dir}/${_file_we}.b" )
- install( FILES ${pfile} DESTINATION "${_h_destination}/${_file_dir}" )
- endforeach()
- endif()
- endif()
- if( _PAR_INSTALL_HEADERS MATCHES "ALL" ) # "(\\.h|\\.b|\\.hxx|\\.hh|\\.hpp|\\.H)" ????
- install( DIRECTORY ./ DESTINATION ${_h_destination} FILES_MATCHING PATTERN "*.h" )
- install( DIRECTORY ./ DESTINATION ${_h_destination} FILES_MATCHING PATTERN "*.hh" )
- install( DIRECTORY ./ DESTINATION ${_h_destination} FILES_MATCHING PATTERN "*.hpp" )
- install( DIRECTORY ./ DESTINATION ${_h_destination} FILES_MATCHING PATTERN "*.H" )
- endif()
- endif()
-
- if( DEFINED _PAR_INSTALL_HEADERS_LIST )
- install( FILES ${_PAR_INSTALL_HEADERS_LIST} DESTINATION ${_h_destination} )
- endif()
-
- if( DEFINED _PAR_INSTALL_HEADERS_REGEX )
- install( DIRECTORY ./ DESTINATION ${_h_destination} FILES_MATCHING PATTERN "${_PAR_INSTALL_HEADERS_REGEX}")
- endif()
-
- # set build location
-
- set_property( TARGET ${_PAR_TARGET} PROPERTY LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
- set_property( TARGET ${_PAR_TARGET} PROPERTY ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
-
- # export location of target to other projects -- must be exactly after setting the build location (see previous 2 commands)
-
- export( TARGETS ${_PAR_TARGET} APPEND FILE "${TOP_PROJECT_TARGETS_FILE}" )
-
- endif()
-
- # add definitions to compilation
- if( DEFINED _PAR_DEFINITIONS )
- get_property( _target_defs TARGET ${_PAR_TARGET} PROPERTY COMPILE_DEFINITIONS )
- list( APPEND _target_defs ${_PAR_DEFINITIONS} )
- set_property( TARGET ${_PAR_TARGET} PROPERTY COMPILE_DEFINITIONS ${_target_defs} )
- endif()
-
- # make sure target is removed before - some problems with AIX
- add_custom_command( TARGET ${_PAR_TARGET} PRE_BUILD COMMAND ${CMAKE_COMMAND} -E remove $<TARGET_FILE:${_PAR_TARGET}> )
-
- # for the links target
- if( NOT _PAR_NOINSTALL )
- ecbuild_link_lib( ${_PAR_TARGET} $<TARGET_FILE_NAME:${_PAR_TARGET}> $<TARGET_FILE:${_PAR_TARGET}> )
- endif()
-
- # append to the list of this project targets
- set( ${PROJECT_NAME}_ALL_LIBS ${${PROJECT_NAME}_ALL_LIBS} ${_PAR_TARGET} CACHE INTERNAL "" )
-
- endif()
-
- # mark project files
- ecbuild_declare_project_files( ${_PAR_SOURCES} )
-
-endfunction( ecbuild_add_library_impl )
-
-##############################################################################
-# auxiliary macro for adding a library
-##############################################################################
-
-macro( ecbuild_add_library )
-
- set( options )
- set( single_value_args TARGET TYPE )
- set( multi_value_args )
-
- cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if( DEFINED _p_TYPE ) # don't do anything if TYPE was specified
-
- if( _p_TYPE MATCHES "[Bb][Oo][Tt][Hh]" ) # build both types
-
- ecbuild_add_library_impl( TARGET ${_p_TARGET} TYPE SHARED ${_p_UNPARSED_ARGUMENTS} )
- ecbuild_add_library_impl( TARGET ${_p_TARGET}-static TYPE STATIC ${_p_UNPARSED_ARGUMENTS} OUTPUT_NAME ${_p_TARGET} DEPENDS ${_p_TARGET} )
-
- else()
-
- ecbuild_add_library_impl( ${ARGV} )
-
- endif()
-
- else()
-
- if( NOT DEFINED _p_TARGET )
- message(FATAL_ERROR "The call to ecbuild_add_library() doesn't specify the TARGET.")
- else()
-
- if( BUILD_SHARED_LIBS MATCHES "[Bb][Oo][Tt][Hh]" ) # build both types
-
- ecbuild_add_library_impl( TARGET ${_p_TARGET} TYPE SHARED ${_p_UNPARSED_ARGUMENTS} )
- ecbuild_add_library_impl( TARGET ${_p_TARGET}-static TYPE STATIC ${_p_UNPARSED_ARGUMENTS} DEPENDS ${_p_TARGET} )
-
- set_target_properties( ${_p_TARGET}-static PROPERTIES OUTPUT_NAME ${_p_TARGET} )
-
- else()
-
- ecbuild_add_library_impl( ${ARGV} )
-
- endif()
-
- endif()
-
- endif()
-
-endmacro( ecbuild_add_library )
diff --git a/ecbuild/cmake/ecbuild_add_option.cmake b/ecbuild/cmake/ecbuild_add_option.cmake
deleted file mode 100644
index 85417fa..0000000
--- a/ecbuild/cmake/ecbuild_add_option.cmake
+++ /dev/null
@@ -1,194 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-##############################################################################
-# macro for adding a test
-##############################################################################
-
-macro( ecbuild_add_option )
-
- set( options ADVANCED )
- set( single_value_args FEATURE DEFAULT DESCRIPTION )
- set( multi_value_args REQUIRED_PACKAGES CONDITION )
-
- cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if( _p_UNPARSED_ARGUMENTS )
- message(FATAL_ERROR "Unknown keywords given to ecbuild_add_option(): \"${_p_UNPARSED_ARGUMENTS}\"")
- endif()
-
- # check FEATURE parameter
-
- if( NOT _p_FEATURE )
- message(FATAL_ERROR "The call to ecbuild_add_option() doesn't specify the FEATURE.")
- endif()
-
- # check DEFAULT parameter
-
- if( NOT DEFINED _p_DEFAULT )
- set( _p_DEFAULT ON )
- else()
- if( NOT _p_DEFAULT MATCHES "[Oo][Nn]" AND NOT _p_DEFAULT MATCHES "[Oo][Ff][Ff]" )
- message(FATAL_ERROR "In macro ecbuild_add_option(), DEFAULT is either ON or OFF: \"${_p_DEFAULT}\"")
- endif()
- endif()
-
- # check CONDITION parameter
- if( DEFINED _p_CONDITION )
- set(_feature_condition_file "${CMAKE_CURRENT_BINARY_DIR}/set_${_p_FEATURE}_condition.cmake")
- file( WRITE ${_feature_condition_file} " if( ")
- foreach( term ${_p_CONDITION} )
- file( APPEND ${_feature_condition_file} " ${term}")
- endforeach()
- file( APPEND ${_feature_condition_file} " )\n set(_${_p_FEATURE}_condition TRUE)\n else()\n set(_${_p_FEATURE}_condition FALSE)\n endif()\n")
- include( ${_feature_condition_file} )
- else()
- set( _${_p_FEATURE}_condition TRUE )
- endif()
-
- # check if user provided value
-
- get_property( _in_cache CACHE ENABLE_${_p_FEATURE} PROPERTY VALUE )
-
- if( NOT "${ENABLE_${_p_FEATURE}}" STREQUAL "" AND _in_cache )
- set( ${_p_FEATURE}_user_provided_input 1 CACHE BOOL "" )
- else()
- set( ${_p_FEATURE}_user_provided_input 0 CACHE BOOL "" )
- endif()
-
- mark_as_advanced( ${_p_FEATURE}_user_provided_input )
-
-
- # define the option -- for cmake GUI
-
- option( ENABLE_${_p_FEATURE} "${_p_DESCRIPTION}" ${_p_DEFAULT} )
-
- set( _do_search ${ENABLE_${_p_FEATURE}} )
- if( _p_FEATURE STREQUAL "OMP" )
- set( _do_search TRUE )
- endif()
-
- if( _do_search )
-
- set( HAVE_${_p_FEATURE} 1 )
-
- if( _${_p_FEATURE}_condition )
-
- ### search for dependent packages
-
- foreach( pkg ${_p_REQUIRED_PACKAGES} )
-
- string(REPLACE " " ";" pkglist ${pkg}) # string to list
-
- list( GET pkglist 0 pkgname )
-
- if( pkgname STREQUAL "PROJECT" ) # if 1st entry is PROJECT, then we are looking for a ecbuild project
- set( pkgproject 1 )
- list( GET pkglist 1 pkgname )
- else() # else 1st entry is package name
- set( pkgproject 0 )
- endif()
-
- # debug_var( pkg )
- # debug_var( pkglist )
- # debug_var( pkgname )
-
- string( TOUPPER ${pkgname} pkgUPPER )
- string( TOLOWER ${pkgname} pkgLOWER )
-
- if( ${pkgname}_FOUND OR ${pkgUPPER}_FOUND OR ${pkgLOWER}_FOUND )
- set( ${pkgname}_already_found 1 )
- else()
-
- ecbuild_add_extra_search_paths( ${pkgLOWER} ) # adds search paths specific to ECMWF
-
- if( pkgproject )
- ecbuild_use_package( ${pkglist} )
- else()
- if( pkgname STREQUAL "MPI" )
- set( _find_args ${pkglist} )
- list( REMOVE_ITEM _find_args "MPI" )
- ecbuild_find_mpi( ${_find_args} )
- elseif( pkgname STREQUAL "OMP" )
- set( _find_args ${pkglist} )
- list( REMOVE_ITEM _find_args "OMP" )
- if( NOT ENABLE_${_p_FEATURE} )
- list( APPEND _find_args STUBS )
- endif()
- ecbuild_find_omp( ${_find_args} )
- else()
- find_package( ${pkglist} )
- endif()
- endif()
-
- # append to list of third-party libraries (to be forward to other packages )
- string( TOUPPER ${PROJECT_NAME} PNAME )
- list( APPEND ${PNAME}_TPLS ${pkgname} )
-
- endif()
-
- # debug_var( ${pkgname}_FOUND )
- # debug_var( ${pkgLOWER}_FOUND )
- # debug_var( ${pkgUPPER}_FOUND )
-
- # we have feature if all required packages were FOUND
-
- if( ${pkgname}_FOUND OR ${pkgUPPER}_FOUND OR ${pkgLOWER}_FOUND )
- message( STATUS "Found package ${pkgname} required for feature ${_p_FEATURE}" )
- else()
- message( STATUS "Could not find package ${pkgname} required for feature ${_p_FEATURE} -- Provide ${pkgname} location with -D${pkgUPPER}_PATH=/..." )
- set( HAVE_${_p_FEATURE} 0 )
- list( APPEND _failed_to_find_packages ${pkgname} )
- endif()
-
- endforeach()
- else()
- set( HAVE_${_p_FEATURE} 0 )
- endif()
-
- # FINAL CHECK
-
- if( HAVE_${_p_FEATURE} )
-
- message( STATUS "Feature ${_p_FEATURE} enabled" )
-
- else() # if user provided input and we cannot satisfy FAIL otherwise WARN
-
- if( ${_p_FEATURE}_user_provided_input )
- if( _${_p_FEATURE}_condition )
- message( FATAL_ERROR "Feature ${_p_FEATURE} cannot be enabled -- following required packages weren't found: ${_failed_to_find_packages}" )
- else()
- message( FATAL_ERROR "Feature ${_p_FEATURE} cannot be enabled -- following condition was not met: ${_p_CONDITION}" )
- endif()
- else()
- message( STATUS "Feature ${_p_FEATURE} was not enabled (also not requested) -- following required packages weren't found: ${_failed_to_find_packages}" )
- set( ENABLE_${_p_FEATURE} OFF )
- endif()
-
- endif()
-
- else( _do_search )
-
- set( HAVE_${_p_FEATURE} 0 )
-
- endif( _do_search )
-
-
- if( ${_p_ADVANCED} )
- mark_as_advanced( ENABLE_${_p_FEATURE} )
- else()
- add_feature_info( ${_p_FEATURE} ENABLE_${_p_FEATURE} "${_p_DESCRIPTION}")
- endif()
-
- if( HAVE_${_p_FEATURE} )
- string( TOUPPER PNAME ${PROJECT_NAME} )
- set( ${PNAME}_HAVE_${_p_FEATURE} 1 )
- set( ${PNAME}_FEATURES "${${PNAME}_FEATURES};${PNAME}_HAVE_${_p_FEATURE}" CACHE INTERNAL "" )
- endif()
-
-endmacro( ecbuild_add_option )
diff --git a/ecbuild/cmake/ecbuild_add_persistent.cmake b/ecbuild/cmake/ecbuild_add_persistent.cmake
deleted file mode 100644
index c8ef383..0000000
--- a/ecbuild/cmake/ecbuild_add_persistent.cmake
+++ /dev/null
@@ -1,61 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-##############################################################################
-# macro for adding persistent layer object classes
-##############################################################################
-
-# define the script to build the persistent class information
-set( sg_perl "${CMAKE_CURRENT_LIST_DIR}/sg.pl" CACHE INTERNAL "perl script to generate persistent objects" )
-
-macro( ecbuild_add_persistent )
-
- ecbuild_find_perl( REQUIRED )
-
- set( options )
- set( single_value_args SRC_LIST NAMESPACE )
- set( multi_value_args FILES )
-
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_add_persistent(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
-
- if( NOT _PAR_SRC_LIST )
- message(FATAL_ERROR "The call to ecbuild_add_persistent() doesn't specify the SRC_LIST.")
- endif()
-
- if( NOT _PAR_FILES )
- message(FATAL_ERROR "The call to ecbuild_add_persistent() doesn't specify the FILES.")
- endif()
-
- foreach( file ${_PAR_FILES} )
-
- get_filename_component( _file_dir ${file} PATH )
- get_filename_component( _file_we ${file} NAME_WE )
-
- set( file ${_file_we} )
- if( _file_dir )
- file( MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${_file_dir} )
- set( file ${_file_dir}/${_file_we} )
- endif()
-
- # debug_var(file)
-
- add_custom_command(
- OUTPUT ${file}.b
- COMMAND ${PERL_EXECUTABLE} ${sg_perl} ${CMAKE_CURRENT_SOURCE_DIR}/${file}.h ${CMAKE_CURRENT_BINARY_DIR}/${_file_dir} ${_PAR_NAMESPACE}
- DEPENDS ${sg_perl} ${file}.h
- )
- set_source_files_properties( ${file}.h PROPERTIES OBJECT_DEPENDS "${file}.b" )
- list( APPEND ${_PAR_SRC_LIST} ${CMAKE_CURRENT_BINARY_DIR}/${file}.b )
-
- endforeach()
-
-endmacro( ecbuild_add_persistent )
diff --git a/ecbuild/cmake/ecbuild_add_resources.cmake b/ecbuild/cmake/ecbuild_add_resources.cmake
deleted file mode 100644
index 12f47af..0000000
--- a/ecbuild/cmake/ecbuild_add_resources.cmake
+++ /dev/null
@@ -1,158 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-##############################################################################
-# macro for adding a resources
-##############################################################################
-
-macro( ecbuild_dont_pack )
-
- set( options )
- set( single_value_args REGEX )
- set( multi_value_args FILES DIRS )
-
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_add_resources(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
-
- if( NOT DEFINED _PAR_REGEX AND NOT DEFINED _PAR_FILES AND NOT DEFINED _PAR_DIRS )
- message(FATAL_ERROR "Call to ecbuild_dont_pack does not speficify any list to avoid packing.")
- endif()
-
- set( LOCAL_FILES_NOT_TO_PACK "" )
-
- # all recursive files are not to pack
- if( DEFINED _PAR_REGEX )
- file( GLOB_RECURSE all_files_in_subdirs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${_PAR_REGEX} )
- list( APPEND LOCAL_FILES_NOT_TO_PACK ${all_files_in_subdirs} )
- endif()
-
- # selected dirs not to pack
- if( DEFINED _PAR_DIRS )
- foreach( dir ${_PAR_DIRS} )
- list( APPEND LOCAL_FILES_NOT_TO_PACK ${dir}/ )
- endforeach()
- endif()
-
- # selected files not to pack
- if( DEFINED _PAR_FILES )
- list( APPEND LOCAL_FILES_NOT_TO_PACK ${_PAR_FILES} )
- endif()
-
- # transform the local files to full absolute paths
- # and place them in the global list of files not to pack
- foreach( file ${LOCAL_FILES_NOT_TO_PACK} )
- list( APPEND ECBUILD_DONT_PACK_FILES ${CMAKE_CURRENT_SOURCE_DIR}/${file} )
- endforeach()
-
- # save cache if we added any files not to pack
- if( LOCAL_FILES_NOT_TO_PACK )
- set( ECBUILD_DONT_PACK_FILES ${ECBUILD_DONT_PACK_FILES} CACHE INTERNAL "" )
- endif()
-
-endmacro()
-
-macro( ecbuild_add_resources )
-
- set( options )
- set( single_value_args TARGET )
- set( multi_value_args SOURCES SOURCES_PACK SOURCES_DONT_PACK PACK DONT_PACK DONT_PACK_DIRS DONT_PACK_REGEX )
-
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_add_resources(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
-
- if( NOT _PAR_TARGET )
- message(FATAL_ERROR "The call to ecbuild_add_resources() doesn't specify the TARGET.")
- endif()
-
- set( LOCAL_FILES_NOT_TO_PACK "" )
-
- # all recursive files are not to pack
- if( DEFINED _PAR_DONT_PACK_REGEX )
- foreach( exp ${_PAR_DONT_PACK_REGEX} )
- file( GLOB_RECURSE all_files_in_subdirs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${exp} )
- list( APPEND LOCAL_FILES_NOT_TO_PACK ${all_files_in_subdirs} )
- endforeach()
- endif()
-
- # selected dirs not to pack
- if( DEFINED _PAR_DONT_PACK_DIRS )
- foreach( dir ${_PAR_DONT_PACK_DIRS} )
- list( APPEND LOCAL_FILES_NOT_TO_PACK ${dir}/ )
- endforeach()
- endif()
-
- # selected files not to pack
- if( DEFINED _PAR_DONT_PACK )
- list( APPEND LOCAL_FILES_NOT_TO_PACK ${_PAR_DONT_PACK} )
- endif()
-
- # now lets remove files that we want to pack from the list
- # note that these have priority over the files not to pack
- # so we can GLOB_RECURSE * -> DONT_PACK and then select only the ones we pack
-
- # files to pack but are not project files
- if( DEFINED _PAR_PACK )
- foreach( file ${_PAR_PACK} )
- list( REMOVE_ITEM LOCAL_FILES_NOT_TO_PACK ${file} )
- endforeach()
- endif()
-
- # define as project files, but dont pack them
- if( DEFINED _PAR_SOURCES_DONT_PACK )
- list( APPEND LOCAL_FILES_NOT_TO_PACK ${_PAR_SOURCES_DONT_PACK} )
- foreach( sfile ${_PAR_SOURCES_DONT_PACK} )
- set( _full_sfile "${CMAKE_CURRENT_SOURCE_DIR}/${sfile}" )
- if( EXISTS ${_full_sfile} )
- list( APPEND ${_PAR_TARGET}_files ${_full_sfile} )
- endif()
- endforeach()
- endif()
-
- # define as project files and pack them
- # SOURCES_PACK is alias to SOURCES
- if( DEFINED _PAR_SOURCES_PACK )
- list( APPEND _PAR_SOURCES ${_PAR_SOURCES_PACK} )
- endif()
- if( DEFINED _PAR_SOURCES )
- list( APPEND ${_PAR_TARGET}_files ${_PAR_SOURCES} )
- foreach( file ${_PAR_SOURCES} )
- list( REMOVE_ITEM LOCAL_FILES_NOT_TO_PACK ${file} )
- endforeach()
- endif()
-
- # there are project files, so lets create the target
- if( DEFINED ${_PAR_TARGET}_files )
- add_custom_target( ${_PAR_TARGET} SOURCES ${${_PAR_TARGET}_files} )
- endif()
-
- # remove CMakeLists.txt
- foreach( file ${LOCAL_FILES_NOT_TO_PACK} )
- if( ${file} MATCHES "CMakeLists.txt" )
- list( REMOVE_ITEM LOCAL_FILES_NOT_TO_PACK ${file} )
- endif()
- endforeach()
-
- # transform the local files to full absolute paths
- # and place them in the global list of files not to pack
- foreach( file ${LOCAL_FILES_NOT_TO_PACK} )
- list( APPEND ECBUILD_DONT_PACK_FILES ${CMAKE_CURRENT_SOURCE_DIR}/${file} )
- endforeach()
-
- # save cache if we added any files not to pack
- if( LOCAL_FILES_NOT_TO_PACK )
- set( ECBUILD_DONT_PACK_FILES ${ECBUILD_DONT_PACK_FILES} CACHE INTERNAL "" )
- endif()
-
-endmacro( ecbuild_add_resources )
-
diff --git a/ecbuild/cmake/ecbuild_add_test.cmake b/ecbuild/cmake/ecbuild_add_test.cmake
deleted file mode 100644
index 44f850f..0000000
--- a/ecbuild/cmake/ecbuild_add_test.cmake
+++ /dev/null
@@ -1,315 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-##############################################################################
-# macro for adding a test
-##############################################################################
-
-# Arguments:
-# TARGET : name of test
-# ENABLED [optional]: (default ON)
-# COMMAND [optional]: Run command instead of executable
-# TYPE [optional]: EXE / SCRIPT / PYTHON (default EXE)
-# MPI [optional]: number of mpi-tasks to use. If greater than 1,
-# and MPI is not available, the test is disabled
-# SOURCES: sources to be compiled
-# LIBS: Libraries needed for linking
-# INCLUDES: Extra include directories
-# DEPENDS: Add explicit dependency to other targets (for building)
-# TEST_DEPENDS: add explicity dependency on another test running before
-# ARGS: Command-line arguments to COMMAND OR TARGET
-
-macro( ecbuild_add_test )
-
- set( options BOOST )
- set( single_value_args TARGET ENABLED COMMAND TYPE LINKER_LANGUAGE MPI WORKING_DIRECTORY )
- set( multi_value_args SOURCES LIBS INCLUDES TEST_DEPENDS DEPENDS ARGS PERSISTENT DEFINITIONS RESOURCES TEST_DATA CFLAGS CXXFLAGS FFLAGS GENERATED CONDITION ENVIRONMENT )
-
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_add_test(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
-
- set( _TEST_DIR ${CMAKE_CURRENT_BINARY_DIR} )
-
- # Check for MPI
- if(_PAR_MPI)
- if( (_PAR_MPI GREATER 1) AND ( (NOT HAVE_MPI) OR (NOT MPIEXEC) ) )
- set( _PAR_ENABLED 0 )
- endif()
- if( (_PAR_MPI EQUAL 1) AND (NOT HAVE_MPI) )
- set( _PAR_MPI 0 )
- endif()
- endif()
-
- # default is enabled
- if( NOT DEFINED _PAR_ENABLED )
- set( _PAR_ENABLED 1 )
- endif()
-
-
- ### check test type
-
- # command implies script
- if( DEFINED _PAR_COMMAND )
- set( _PAR_TYPE "SCRIPT" )
- endif()
-
- # default of TYPE
- if( NOT _PAR_TYPE AND DEFINED _PAR_TARGET )
- set( _PAR_TYPE "EXE" )
- if( NOT _PAR_SOURCES )
- message(FATAL_ERROR "The call to ecbuild_add_test() defines neither a TARGET without SOURCES.")
- endif()
- endif()
-
- if( _PAR_TYPE MATCHES "PYTHON" )
- if( PYTHONINTERP_FOUND )
- set( _PAR_COMMAND ${PYTHON_EXECUTABLE} )
- else()
- message( FATAL_ERROR "Requested a python test but python interpreter not found - PYTHON_EXECUTABLE: [${PYTHON_EXECUTABLE}]" )
- endif()
- endif()
-
- ### further checks
-
- if( NOT _PAR_TARGET AND NOT _PAR_COMMAND )
- message(FATAL_ERROR "The call to ecbuild_add_test() defines neither a TARGET nor a COMMAND.")
- endif()
-
- if( NOT _PAR_COMMAND AND NOT _PAR_SOURCES )
- message(FATAL_ERROR "The call to ecbuild_add_test() defines neither a COMMAND nor SOURCES, so no test can be defined or built.")
- endif()
-
- if( _PAR_TYPE MATCHES "SCRIPT" AND NOT _PAR_COMMAND )
- message(FATAL_ERROR "The call to ecbuild_add_test() defines a 'script' but doesn't specify the COMMAND.")
- endif()
-
- ### conditional build
-
- if( DEFINED _PAR_CONDITION )
- set(_target_condition_file "${CMAKE_CURRENT_BINARY_DIR}/set_${_PAR_TARGET}_condition.cmake")
- file( WRITE ${_target_condition_file} " if( ")
- foreach( term ${_PAR_CONDITION} )
- file( APPEND ${_target_condition_file} " ${term}")
- endforeach()
- file( APPEND ${_target_condition_file} " )\n set(_${_PAR_TARGET}_condition TRUE)\n else()\n set(_${_PAR_TARGET}_condition FALSE)\n endif()\n")
- include( ${_target_condition_file} )
- else()
- set( _${_PAR_TARGET}_condition TRUE )
- endif()
-
- # boost unit test linking to unit_test lib ?
-
- if( _PAR_BOOST AND ENABLE_TESTS AND _${_PAR_TARGET}_condition )
-
- if( HAVE_BOOST_UNIT_TEST )
- if( BOOST_UNIT_TEST_FRAMEWORK_HEADER_ONLY )
- include_directories( ${ECBUILD_BOOST_HEADER_DIRS} )
- else()
- include_directories( ${ECBUILD_BOOST_HEADER_DIRS} ${Boost_INCLUDE_DIRS} )
- endif()
- else()
- set( _${_PAR_TARGET}_condition FALSE )
- endif()
-
- endif()
-
- ### enable the tests
-
- if( ENABLE_TESTS AND _${_PAR_TARGET}_condition )
-
- # add resources
-
- if( DEFINED _PAR_RESOURCES )
- foreach( rfile ${_PAR_RESOURCES} )
- execute_process( COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/${rfile} ${CMAKE_CURRENT_BINARY_DIR} )
- endforeach()
- endif()
-
- # build executable
-
- if( DEFINED _PAR_SOURCES )
-
- # add include dirs if defined
- if( DEFINED _PAR_INCLUDES )
- list(REMOVE_DUPLICATES _PAR_INCLUDES )
- foreach( path ${_PAR_INCLUDES} ) # skip NOTFOUND
- if( path )
- include_directories( ${path} )
- endif()
- endforeach()
- endif()
-
- # add persistent layer files
- if( DEFINED _PAR_PERSISTENT )
- if( DEFINED PERSISTENT_NAMESPACE )
- ecbuild_add_persistent( SRC_LIST _PAR_SOURCES FILES ${_PAR_PERSISTENT} NAMESPACE ${PERSISTENT_NAMESPACE} )
- else()
- ecbuild_add_persistent( SRC_LIST _PAR_SOURCES FILES ${_PAR_PERSISTENT} )
- endif()
- endif()
-
- # add the test target
-
- add_executable( ${_PAR_TARGET} ${_PAR_SOURCES} )
-
- # add extra dependencies
- if( DEFINED _PAR_DEPENDS)
- add_dependencies( ${_PAR_TARGET} ${_PAR_DEPENDS} )
- endif()
-
- # add the link libraries
- if( DEFINED _PAR_LIBS )
- list(REMOVE_DUPLICATES _PAR_LIBS )
- list(REMOVE_ITEM _PAR_LIBS debug)
- list(REMOVE_ITEM _PAR_LIBS optimized)
- foreach( lib ${_PAR_LIBS} ) # skip NOTFOUND
- if( lib )
- target_link_libraries( ${_PAR_TARGET} ${lib} )
- else()
- message( WARNING "Lib ${lib} was skipped" )
- endif()
- endforeach()
- endif()
-
- # add test libraries
- if( _PAR_BOOST AND BOOST_UNIT_TEST_FRAMEWORK_LINKED AND HAVE_BOOST_UNIT_TEST )
- target_link_libraries( ${_PAR_TARGET} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} ${Boost_TEST_EXEC_MONITOR_LIBRARY} )
- endif()
-
- # add local flags
- if( DEFINED _PAR_CFLAGS )
- set_source_files_properties( ${${_PAR_TARGET}_c_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_CFLAGS}" )
- endif()
- if( DEFINED _PAR_CXXFLAGS )
- set_source_files_properties( ${${_PAR_TARGET}_cxx_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_CXXFLAGS}" )
- endif()
- if( DEFINED _PAR_FFLAGS )
- set_source_files_properties( ${${_PAR_TARGET}_f_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_FFLAGS}" )
- endif()
- if( DEFINED _PAR_GENERATED )
- set_source_files_properties( ${_PAR_GENERATED} PROPERTIES GENERATED 1 )
- endif()
-
-
- # modify definitions to compilation ( -D... )
- get_property( _target_defs TARGET ${_PAR_TARGET} PROPERTY COMPILE_DEFINITIONS )
-
- if( DEFINED _PAR_DEFINITIONS )
- list( APPEND _target_defs ${_PAR_DEFINITIONS} )
- endif()
-
- if( _PAR_BOOST AND BOOST_UNIT_TEST_FRAMEWORK_HEADER_ONLY )
- list( APPEND _target_defs BOOST_UNIT_TEST_FRAMEWORK_HEADER_ONLY )
- endif()
-
- set_property( TARGET ${_PAR_TARGET} PROPERTY COMPILE_DEFINITIONS ${_target_defs} )
-
- # set build location to local build dir
- # not the project base as defined for libs and execs
- set_property( TARGET ${_PAR_TARGET} PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} )
-
- # whatever project settings are, we always build tests with the build_rpath, not the install_rpath
- set_property( TARGET ${_PAR_TARGET} PROPERTY BUILD_WITH_INSTALL_RPATH FALSE )
- set_property( TARGET ${_PAR_TARGET} PROPERTY SKIP_BUILD_RPATH FALSE )
-
- # set linker language
- if( DEFINED _PAR_LINKER_LANGUAGE )
- set_property( TARGET ${_PAR_TARGET} PROPERTY LINKER_LANGUAGE ${_PAR_LINKER_LANGUAGE} )
- endif()
-
- # make sure target is removed before - some problems with AIX
- get_target_property(EXE_FILENAME ${_PAR_TARGET} OUTPUT_NAME)
- add_custom_command(
- TARGET ${_PAR_TARGET}
- PRE_BUILD
- COMMAND ${CMAKE_COMMAND} -E remove ${EXE_FILENAME}
- )
-
- set_property( TARGET ${_PAR_TARGET} PROPERTY SKIP_BUILD_RPATH FALSE )
- set_property( TARGET ${_PAR_TARGET} PROPERTY BUILD_WITH_INSTALL_RPATH FALSE )
-
- endif() # _PAR_SOURCES
-
- if( DEFINED _PAR_COMMAND AND NOT _PAR_TARGET ) # in the absence of target, we use the command as a name
- set( _PAR_TARGET ${_PAR_COMMAND} )
- endif()
-
- # scripts dont have actual build targets
- # we build a phony target to trigger the dependencies
- if( DEFINED _PAR_COMMAND AND DEFINED _PAR_DEPENDS )
-
- add_custom_target( ${_PAR_TARGET}.x ALL COMMAND ${CMAKE_COMMAND} -E touch ${_PAR_TARGET}.x )
-
- add_dependencies( ${_PAR_TARGET}.x ${_PAR_DEPENDS} )
-
- endif()
-
-
- # define the arguments
- set( TEST_ARGS "" )
- if( DEFINED _PAR_ARGS )
- list( APPEND TEST_ARGS ${_PAR_ARGS} )
- endif()
-
- # Wrap with MPIEXEC
- if( _PAR_MPI )
- if( DEFINED _PAR_COMMAND )
- set( _PAR_COMMAND ${MPIEXEC} -n ${_PAR_MPI} ${_PAR_COMMAND} )
- else()
- set( _PAR_COMMAND ${MPIEXEC} -n ${_PAR_MPI} ${_PAR_TARGET} )
- endif()
- endif()
-
- ### define the test
-
- if( _PAR_ENABLED ) # we can disable and still build it but not run it with 'make tests'
-
- if( DEFINED _PAR_COMMAND )
- add_test( ${_PAR_TARGET} ${_PAR_COMMAND} ${TEST_ARGS} ${_working_dir} ) # run a command as test
- else()
- add_test( ${_PAR_TARGET} ${_PAR_TARGET} ${TEST_ARGS} ${_working_dir} ) # run the test that was generated
- endif()
-
- # get test data
-
- if( _PAR_TEST_DATA )
-
- ecbuild_get_test_multidata( TARGET ${_PAR_TARGET}_data NAMES ${_PAR_TEST_DATA} )
-
- list( APPEND _PAR_TEST_DEPENDS ${_PAR_TARGET}_data )
-
- endif()
-
- if( DEFINED _PAR_ENVIRONMENT )
- set_property( TEST ${_PAR_TARGET} APPEND PROPERTY ENVIRONMENT "${_PAR_ENVIRONMENT}" )
- endif()
-
- if( DEFINED _PAR_WORKING_DIRECTORY )
- set_tests_properties( ${_PAR_TARGET} PROPERTIES WORKING_DIRECTORY "${_PAR_WORKING_DIRECTORY}")
- endif()
-
- if( DEFINED _PAR_TEST_DEPENDS )
- set_property( TEST ${_PAR_TARGET} APPEND PROPERTY DEPENDS "${_PAR_TEST_DEPENDS}" )
- endif()
-
- endif()
-
- # add to the overall list of tests
- list( APPEND ECBUILD_ALL_TESTS ${_PAR_TARGET} )
- list( REMOVE_DUPLICATES ECBUILD_ALL_TESTS )
- set( ECBUILD_ALL_TESTS ${ECBUILD_ALL_TESTS} CACHE INTERNAL "" )
-
- endif() # _condition
-
- # finally mark project files
- ecbuild_declare_project_files( ${_PAR_SOURCES} )
-
-endmacro( ecbuild_add_test )
diff --git a/ecbuild/cmake/ecbuild_append_to_rpath.cmake b/ecbuild/cmake/ecbuild_append_to_rpath.cmake
deleted file mode 100644
index 6868e50..0000000
--- a/ecbuild/cmake/ecbuild_append_to_rpath.cmake
+++ /dev/null
@@ -1,82 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-############################################################################################
-# macro to append paths to rpath
-
-# if dir is absolute, it simply appends
-# if dir is relative,
-# then it will try to make it relative to the executables
-# else it will fallback to making it absolute by prepending the install path
-
-function( _path_append var path )
- if( "${${var}}" STREQUAL "" )
- set( ${var} "${path}" PARENT_SCOPE )
- else()
- set( ${var} "${${var}}:${path}" PARENT_SCOPE )
- endif()
-endfunction()
-
-macro( ecbuild_append_to_rpath RPATH_DIRS )
-
- if( NOT ${ARGC} EQUAL 1 )
- message( SEND_ERROR "ecbuild_append_to_rpath takes 1 argument")
- endif()
-
- foreach( RPATH_DIR ${RPATH_DIRS} )
-
- if( NOT ${RPATH_DIR} STREQUAL "" )
-
- file( TO_CMAKE_PATH ${RPATH_DIR} RPATH_DIR ) # sanitize the path
-
- if( IS_ABSOLUTE ${RPATH_DIR} )
-
- _path_append( CMAKE_INSTALL_RPATH "${RPATH_DIR}" )
-
- else()
-
- set( _done 0 )
-
- if( EC_OS_NAME STREQUAL "macosx" )
-
- if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" VERSION_LESS 3.0) # cmake < 3.0
- set( CMAKE_INSTALL_NAME_DIR "@loader_path/${RPATH_DIR}" )
- endif()
- _path_append( CMAKE_INSTALL_RPATH "@loader_path/${RPATH_DIR}" )
- set( _done 1 )
-
- endif()
-
- if( EC_OS_NAME STREQUAL "linux" )
- _path_append( CMAKE_INSTALL_RPATH "$ORIGIN/${RPATH_DIR}" )
- set( _done 1 )
- endif()
-
- if( EC_OS_NAME STREQUAL "solaris" )
- _path_append( CMAKE_INSTALL_RPATH "$ORIGIN/${RPATH_DIR}" )
- set( _done 1 )
- endif()
-
- if( EC_OS_NAME STREQUAL "aix" ) # always relative to exectuable path
- _path_append( CMAKE_INSTALL_RPATH "${RPATH_DIR}" )
- set( _done 1 )
- endif()
-
- # fallback
-
- if( NOT _done )
- _path_append( CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${RPATH_DIR}" )
- endif()
-
- endif()
-
- endif()
-
- endforeach()
-
-endmacro( ecbuild_append_to_rpath )
diff --git a/ecbuild/cmake/ecbuild_bundle.cmake b/ecbuild/cmake/ecbuild_bundle.cmake
deleted file mode 100644
index 2a75e84..0000000
--- a/ecbuild/cmake/ecbuild_bundle.cmake
+++ /dev/null
@@ -1,284 +0,0 @@
-# Manages an external git repository
-# Usage:
-# git(DIR <directory> URL <giturl> [BRANCH <gitbranch>] [TAG <gittag>] [UPDATE] )
-#
-# Arguments:
-# - DIR: directory name where repo will be cloned to
-# - URL: location of origin git repository
-# - BRANCH (optional): Branch to clone
-# - TAG (optional): Tag or commit-id to checkout
-# - UPDATE (optional) : Option to try to update every cmake run
-# - NOREMOTE (optional) : Option to avoid remote operations that require network
-# changes to tags that havent been fetched might fail
-
-macro( debug_here VAR )
- message( STATUS " >>>>> ${VAR} [${${VAR}}]")
-endmacro()
-
-include(CMakeParseArguments)
-
-set( ECBUILD_GIT ON CACHE BOOL "Turn on/off ecbuild_git() function" )
-
-if( ECBUILD_GIT )
-
- find_package(Git)
-
- set( ECMWF_USER $ENV{USER} CACHE STRING "ECMWF git user" )
- set( ECMWF_GIT SSH CACHE STRING "ECMWF git protocol" )
-
- set( ECMWF_GIT_SSH "ssh://git@software.ecmwf.int:7999" CACHE INTERNAL "ECMWF ssh address" )
- set( ECMWF_GIT_HTTPS "https://${ECMWF_USER}@software.ecmwf.int/stash/scm" CACHE INTERNAL "ECMWF https address" )
-
- if( ECMWF_GIT MATCHES "[Ss][Ss][Hh]" )
- set( ECMWF_GIT_ADDRESS ${ECMWF_GIT_SSH} CACHE INTERNAL "" )
- else()
- set( ECMWF_GIT_ADDRESS ${ECMWF_GIT_HTTPS} CACHE INTERNAL "" )
- endif()
-
-endif()
-
-macro( ecbuild_git )
-
- set( options UPDATE NOREMOTE )
- set( single_value_args PROJECT DIR URL TAG BRANCH )
- set( multi_value_args )
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if( DEFINED _PAR_BRANCH AND DEFINED _PAR_TAG )
- message( FATAL_ERROR "Cannot defined both BRANCH and TAG in macro ecbuild_git" )
- endif()
-
- if( _PAR_UPDATE AND _PAR_NOREMOTE )
- message( FATAL_ERROR "Cannot pass both NOREMOTE and UPDATE in macro ecbuild_git" )
- endif()
-
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_git(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
-
- if( ECBUILD_GIT )
-
- set( _needs_switch 0 )
-
- get_filename_component( ABS_PAR_DIR "${_PAR_DIR}" ABSOLUTE )
- get_filename_component( PARENT_DIR "${_PAR_DIR}/.." ABSOLUTE )
-
- ### clone if no directory
-
- if( NOT EXISTS "${_PAR_DIR}" )
-
- message( STATUS "Cloning ${_PAR_PROJECT} from ${_PAR_URL} into ${_PAR_DIR}...")
- execute_process(
- COMMAND ${GIT_EXECUTABLE} "clone" ${_PAR_URL} ${clone_args} ${_PAR_DIR} "-q"
- RESULT_VARIABLE nok ERROR_VARIABLE error
- WORKING_DIRECTORY "${PARENT_DIR}")
- if(nok)
- message(FATAL_ERROR "${_PAR_DIR} git clone failed: ${error}\n")
- endif()
- message( STATUS "${_PAR_DIR} retrieved.")
- set( _needs_switch 1 )
-
- endif()
-
- ### check current tag and sha1
-
- if( IS_DIRECTORY "${_PAR_DIR}/.git" )
-
- execute_process(
- COMMAND ${GIT_EXECUTABLE} rev-parse HEAD
- OUTPUT_VARIABLE _sha1 RESULT_VARIABLE nok ERROR_VARIABLE error OUTPUT_STRIP_TRAILING_WHITESPACE
- WORKING_DIRECTORY "${ABS_PAR_DIR}" )
- if(nok)
- message(STATUS "git rev-parse HEAD on ${_PAR_DIR} failed:\n ${error}")
- endif()
-
- execute_process(
- COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD
- OUTPUT_VARIABLE _current_branch RESULT_VARIABLE nok ERROR_VARIABLE error OUTPUT_STRIP_TRAILING_WHITESPACE
- WORKING_DIRECTORY "${ABS_PAR_DIR}" )
- if( nok OR _current_branch STREQUAL "" )
- message(STATUS "git rev-parse --abbrev-ref HEAD on ${_PAR_DIR} failed:\n ${error}")
- endif()
-
- #message(STATUS "git describe --exact-match --abbrev=0 @ ${ABS_PAR_DIR}")
- execute_process(
- COMMAND ${GIT_EXECUTABLE} describe --exact-match --abbrev=0
- OUTPUT_VARIABLE _current_tag RESULT_VARIABLE nok ERROR_VARIABLE error
- OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_STRIP_TRAILING_WHITESPACE
- WORKING_DIRECTORY "${ABS_PAR_DIR}" )
-
- if( error MATCHES "no tag exactly matches" OR error MATCHES "No names found" )
- unset( _current_tag )
- else()
- if( nok )
- message(STATUS "git describe --exact-match --abbrev=0 on ${_PAR_DIR} failed:\n ${error}")
- endif()
- endif()
-
- if( NOT _current_tag ) # try nother method
- #message(STATUS "git name-rev --tags --name-only @ ${ABS_PAR_DIR}")
- execute_process(
- COMMAND ${GIT_EXECUTABLE} name-rev --tags --name-only ${_sha1}
- OUTPUT_VARIABLE _current_tag RESULT_VARIABLE nok ERROR_VARIABLE error OUTPUT_STRIP_TRAILING_WHITESPACE
- WORKING_DIRECTORY "${ABS_PAR_DIR}" )
- if( nok OR _current_tag STREQUAL "" )
- message(STATUS "git name-rev --tags --name-only on ${_PAR_DIR} failed:\n ${error}")
- endif()
- endif()
-
- endif()
-
- if( DEFINED _PAR_BRANCH AND NOT "${_current_branch}" STREQUAL "${_PAR_BRANCH}" )
- set( _needs_switch 1 )
- endif()
-
- if( DEFINED _PAR_TAG AND NOT "${_current_tag}" STREQUAL "${_PAR_TAG}" )
- set( _needs_switch 1 )
- endif()
-
- if( DEFINED _PAR_BRANCH AND _PAR_UPDATE AND NOT _PAR_NOREMOTE )
-
- add_custom_target( git_update_${_PAR_PROJECT}
- COMMAND "${GIT_EXECUTABLE}" pull -q
- WORKING_DIRECTORY "${ABS_PAR_DIR}"
- COMMENT "git pull of branch ${_PAR_BRANCH} on ${_PAR_DIR}" )
-
- set( git_update_targets "git_update_${_PAR_PROJECT};${git_update_targets}" )
-
- endif()
-
- ### updates
-
- if( _needs_switch AND IS_DIRECTORY "${_PAR_DIR}/.git" )
-
- # debug_here( ABS_PAR_DIR )
- # debug_here( _sha1 )
- # debug_here( _current_branch )
- # debug_here( _current_tag )
- # debug_here( _PAR_TAG )
- # debug_here( _PAR_BRANCH )
- # debug_here( _needs_switch )
- # debug_here( _PAR_UPDATE )
-
- if( DEFINED _PAR_BRANCH )
- set ( _gitref ${_PAR_BRANCH} )
- message(STATUS "Updating ${_PAR_PROJECT} to head of BRANCH ${_PAR_BRANCH}...")
- else()
- message(STATUS "Updating ${_PAR_PROJECT} to TAG ${_PAR_TAG}...")
- set ( _gitref ${_PAR_TAG} )
- endif()
-
- # fetching latest tags and branches
-
- if( NOT _PAR_NOREMOTE )
-
- message(STATUS "git fetch --all @ ${ABS_PAR_DIR}")
- execute_process(COMMAND "${GIT_EXECUTABLE}" fetch --all -q
- RESULT_VARIABLE nok ERROR_VARIABLE error
- WORKING_DIRECTORY "${ABS_PAR_DIR}")
- if(nok)
- message(STATUS "git fetch --all in ${_PAR_DIR} failed:\n ${error}")
- endif()
-
- message(STATUS "git fetch --all --tags @ ${ABS_PAR_DIR}")
- execute_process(COMMAND "${GIT_EXECUTABLE}" fetch --all --tags -q
- RESULT_VARIABLE nok ERROR_VARIABLE error
- WORKING_DIRECTORY "${ABS_PAR_DIR}")
- if(nok)
- message(STATUS "git fetch --all --tags in ${_PAR_DIR} failed:\n ${error}")
- endif()
-
- else()
- message(STATUS "${_PAR_DIR} marked NOREMOTE : Skipping git fetch")
- endif()
-
- # checking out gitref
-
- message(STATUS "git checkout ${_gitref} @ ${ABS_PAR_DIR}")
- execute_process(COMMAND "${GIT_EXECUTABLE}" checkout -q "${_gitref}"
- RESULT_VARIABLE nok ERROR_VARIABLE error
- WORKING_DIRECTORY "${ABS_PAR_DIR}")
- if(nok)
- message(FATAL_ERROR "git checkout ${_gitref} on ${_PAR_DIR} failed:\n ${error}")
- endif()
-
- if( DEFINED _PAR_BRANCH AND _PAR_UPDATE ) #############################################################################
-
- execute_process(COMMAND "${GIT_EXECUTABLE}" pull -q
- RESULT_VARIABLE nok ERROR_VARIABLE error
- WORKING_DIRECTORY "${ABS_PAR_DIR}")
- if(nok)
- message(STATUS "git pull of branch ${_PAR_BRANCH} on ${_PAR_DIR} failed:\n ${error}")
- endif()
-
- endif() ####################################################################################
-
- endif( _needs_switch AND IS_DIRECTORY "${_PAR_DIR}/.git" )
-
- endif( ECBUILD_GIT )
-
-endmacro()
-
-########################################################################################################################
-
-macro( ecmwf_stash )
-
- set( options )
- set( single_value_args STASH )
- set( multi_value_args )
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- ecbuild_git( URL "${ECMWF_GIT_ADDRESS}/${_PAR_STASH}.git" ${_PAR_UNPARSED_ARGUMENTS} )
-
-endmacro()
-
-########################################################################################################################
-
-macro( ecbuild_bundle_initialize )
-
- include( local-config.cmake OPTIONAL )
-
- # ecmwf_stash( PROJECT ecbuild DIR ${PROJECT_SOURCE_DIR}/ecbuild STASH "ecsdk/ecbuild" BRANCH develop )
-
- # set( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/ecbuild/cmake;${CMAKE_MODULE_PATH}" )
-
- include( ecbuild_system )
-
- ecbuild_requires_macro_version( 1.6 )
-
- ecbuild_declare_project()
-
- file( GLOB local_config_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *local-config.cmake )
-
- ecbuild_add_resources( TARGET ecbuild_bundle_dont_pack DONT_PACK "${local_config_files}" )
-
- if( EXISTS "${PROJECT_SOURCE_DIR}/README.md" )
- add_custom_target( ${PROJECT_NAME}_readme SOURCES "${PROJECT_SOURCE_DIR}/README.md" )
- endif()
-
-endmacro()
-
-########################################################################################################################
-
-macro( ecbuild_bundle )
-
- set( options )
- set( single_value_args PROJECT )
- set( multi_value_args )
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- ecmwf_stash( PROJECT ${_PAR_PROJECT} DIR ${PROJECT_SOURCE_DIR}/${_PAR_PROJECT} ${_PAR_UNPARSED_ARGUMENTS} )
-
- ecbuild_use_package( PROJECT ${_PAR_PROJECT} )
-
-endmacro()
-
-macro( ecbuild_bundle_finalize )
-
- add_custom_target( update DEPENDS ${git_update_targets} )
-
- ecbuild_install_project( NAME ${CMAKE_PROJECT_NAME} )
-
- ecbuild_print_summary()
-
-endmacro()
diff --git a/ecbuild/cmake/ecbuild_cache.cmake b/ecbuild/cmake/ecbuild_cache.cmake
deleted file mode 100644
index af12cf1..0000000
--- a/ecbuild/cmake/ecbuild_cache.cmake
+++ /dev/null
@@ -1,65 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-macro( ecbuild_prepare_cache )
- include( CheckSymbolExists )
- include( CheckIncludeFiles )
- include( CheckCSourceCompiles )
- include( CheckCXXSourceCompiles )
- include( CheckTypeSize )
- set( ecbuild_cache_file ${CMAKE_BINARY_DIR}/ecbuild-cache.cmake )
- file(WRITE ${ecbuild_cache_file} "# ecbuild cache file\n\n")
-endmacro()
-
-
-function( ecbuild_cache_var var )
- if( NOT ${var} )
- set( ${var} 0 )
- endif()
- set( ECBUILD_CACHE_BUFFER "${ECBUILD_CACHE_BUFFER}set( ${var} ${${var}} )\n" CACHE INTERNAL "Cache buffer" )
-endfunction()
-
-function( ecbuild_cache_check_symbol_exists symbol includes output )
- if( NOT DEFINED ${output} )
- check_symbol_exists( ${symbol} ${includes} ${output} )
- endif()
- ecbuild_cache_var( ${output} )
-endfunction()
-
-function( ecbuild_cache_check_include_files includes output )
- if( NOT DEFINED ${output} )
- check_include_files( ${includes} ${output} )
- endif()
- ecbuild_cache_var( ${output} )
-endfunction()
-
-function( ecbuild_cache_check_c_source_compiles source output )
- if( NOT DEFINED ${output} )
- check_c_source_compiles( "${source}" ${output} )
- endif()
- ecbuild_cache_var( ${output} )
-endfunction()
-
-function( ecbuild_cache_check_cxx_source_compiles source output )
- if( NOT DEFINED ${output} )
- check_cxx_source_compiles( "${source}" ${output} )
- endif()
- ecbuild_cache_var( ${output} )
-endfunction()
-
-function( ecbuild_cache_check_type_size type output )
- if( NOT DEFINED ${output} )
- check_type_size( "${type}" ${output} )
- endif()
- ecbuild_cache_var( ${output} )
-endfunction()
-
-function( ecbuild_flush_cache )
- file( APPEND ${ecbuild_cache_file} "${ECBUILD_CACHE_BUFFER}" )
- set( ECBUILD_CACHE_BUFFER "" CACHE INTERNAL "Cache buffer" )
-endfunction()
\ No newline at end of file
diff --git a/ecbuild/cmake/ecbuild_check_c_source.cmake b/ecbuild/cmake/ecbuild_check_c_source.cmake
deleted file mode 100644
index 12a26c1..0000000
--- a/ecbuild/cmake/ecbuild_check_c_source.cmake
+++ /dev/null
@@ -1,161 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-##############################################################################
-# macro that runs the given C code and returns its output
-
-macro( ecbuild_check_c_source_return SOURCE )
-
- set( options )
- set( single_value_args VAR OUTPUT )
- set( multi_value_args INCLUDES LIBS DEFINITIONS )
-
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_check_c_source_return(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
-
- if( NOT _PAR_VAR OR NOT _PAR_OUTPUT )
- message(FATAL_ERROR "The call to ecbuild_check_c_source_return() doesn't specify either SOURCE, VAR or OUTPUT")
- endif()
-
-
- if( NOT DEFINED ${_PAR_VAR} )
-
- set(MACRO_CHECK_FUNCTION_DEFINITIONS "-D${_PAR_VAR} ${CMAKE_REQUIRED_FLAGS}")
-
- set(CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES)
- if( CMAKE_REQUIRED_LIBRARIES )
- list( APPEND __add_libs ${CMAKE_REQUIRED_LIBRARIES} )
- endif()
- if( _PAR_LIBS )
- list( APPEND __add_libs ${_PAR_LIBS} )
- endif()
- if( __add_libs )
- set(CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES "-DLINK_LIBRARIES:STRING=${__add_libs}")
- endif()
-
- set(CHECK_C_SOURCE_COMPILES_ADD_INCLUDES)
- if( CMAKE_REQUIRED_INCLUDES )
- list( APPEND __add_incs ${CMAKE_REQUIRED_INCLUDES} )
- endif()
- if( _PAR_INCLUDES )
- list( APPEND __add_incs ${_PAR_INCLUDES} )
- endif()
- if( __add_incs )
- set(CHECK_C_SOURCE_COMPILES_ADD_INCLUDES "-DINCLUDE_DIRECTORIES:STRING=${__add_incs}")
- endif()
-
- # write the source file
-
- file( WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/test_${_PAR_VAR}.c" "${SOURCE}\n" )
-
- message( STATUS "Performing Test ${_PAR_VAR}" )
- try_run( ${_PAR_VAR}_EXITCODE ${_PAR_VAR}_COMPILED
- ${CMAKE_BINARY_DIR}
- ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/test_${_PAR_VAR}.c
- COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
- CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS}
- -DCMAKE_SKIP_RPATH:BOOL=${CMAKE_SKIP_RPATH}
- "${CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES}"
- "${CHECK_C_SOURCE_COMPILES_ADD_INCLUDES}"
- COMPILE_OUTPUT_VARIABLE compile_OUTPUT
- RUN_OUTPUT_VARIABLE run_OUTPUT )
-
- # if it did not compile make the return value fail code of 1
- if( NOT ${_PAR_VAR}_COMPILED )
- set( ${_PAR_VAR}_EXITCODE 1 )
- endif()
-
- # if the return value was 0 then it worked
- if("${${_PAR_VAR}_EXITCODE}" EQUAL 0)
-
- message(STATUS "Performing Test ${_PAR_VAR} - Success")
- file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
- "Performing C SOURCE FILE Test ${_PAR_VAR} succeded with the following compile output:\n"
- "${compile_OUTPUT}\n"
- "Performing C SOURCE FILE Run ${_PAR_VAR} succeded with the following run output:\n"
- "${run_OUTPUT}\n"
- "Return value: ${${_PAR_VAR}}\n"
- "Source file was:\n${SOURCE}\n")
-
- set( ${_PAR_VAR} 1 CACHE INTERNAL "Test ${_PAR_VAR}")
- set( ${_PAR_OUTPUT} "${run_OUTPUT}" CACHE INTERNAL "Test ${_PAR_VAR} output")
-
- else()
-
- if(CMAKE_CROSSCOMPILING AND "${${_PAR_VAR}_EXITCODE}" MATCHES "FAILED_TO_RUN")
- set(${_PAR_VAR} "${${_PAR_VAR}_EXITCODE}")
- set(${OUTPUT} "")
- else()
- set(${_PAR_VAR} "" CACHE INTERNAL "Test ${_PAR_VAR}")
- set(${_PAR_OUTPUT} "" CACHE INTERNAL "Test ${_PAR_VAR} output")
- endif()
-
- message(STATUS "Performing Test ${_PAR_VAR} - Failed")
- file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
- "Performing C SOURCE FILE Test ${_PAR_VAR} failed with the following compile output:\n"
- "${compile_OUTPUT}\n"
- "Performing C SOURCE FILE Run ${_PAR_VAR} failed with the following run output:\n"
- "${run_OUTPUT}\n"
- "Return value: ${${_PAR_VAR}_EXITCODE}\n"
- "Source file was:\n${SOURCE}\n")
- endif()
-
- endif()
-
-endmacro()
-
-##############################################################################
-# macro that only adds a c flag if compiler supports it
-
-macro( cmake_add_c_flags m_c_flags )
-
- set( _flags ${m_c_flags} )
-
- if( _flags AND CMAKE_C_COMPILER_LOADED )
- set( options )
- set( single_value_args BUILD NAME )
- set( multi_value_args )
-
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if( NOT DEFINED N_CFLAG )
- set( N_CFLAG 0 )
- endif()
-
- math( EXPR N_CFLAG '${N_CFLAG}+1' )
-
- if( NOT ECBUILD_TRUST_FLAGS )
- if( DEFINED _PAR_NAME )
- check_c_compiler_flag( ${_flags} ${_PAR_NAME} )
- set( _flag_ok ${${_PAR_NAME}} )
- else()
- check_c_compiler_flag( ${_flags} C_FLAG_TEST_${N_CFLAG} )
- set( _flag_ok ${C_FLAG_TEST_${N_CFLAG}} )
- endif()
- else()
- set( _flag_ok 1 )
- endif()
-
- if( _flag_ok )
- if( _PAR_BUILD )
- set( CMAKE_C_FLAGS_${_PAR_BUILD} "${CMAKE_C_FLAGS_${_PAR_BUILD}} ${_flags}" )
- else()
- set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_flags}" )
- # message( STATUS "C FLAG [${_flags}] added" )
- endif()
- else()
- message( WARNING "Unrecognised C flag [${_flags}] -- skipping" )
- endif()
- endif()
- unset( _flags )
- unset( _flag_ok )
-endmacro()
-
diff --git a/ecbuild/cmake/ecbuild_check_compiler.cmake b/ecbuild/cmake/ecbuild_check_compiler.cmake
deleted file mode 100644
index 406f1d2..0000000
--- a/ecbuild/cmake/ecbuild_check_compiler.cmake
+++ /dev/null
@@ -1,141 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-###################################################################################################
-# enable C to use in system introspection
-
-if( NOT CMAKE_C_COMPILER_LOADED AND ENABLE_OS_TESTS )
- enable_language( C )
-endif()
-
-############################################################################################
-# try to get compiler version if cmake did not
-
-if( NOT CMAKE_C_COMPILER_VERSION )
-
- set( EC_COMPILER_VERSION "?.?" )
-
- if( CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Intel" )
- exec_program( ${CMAKE_C_COMPILER}
- ARGS ${CMAKE_C_COMPILER_ARG1} -dumpversion
- OUTPUT_VARIABLE EC_COMPILER_VERSION )
-
- string(REGEX REPLACE "([0-9])\\.([0-9])(\\.([0-9]))?" "\\1.\\2" EC_COMPILER_VERSION ${EC_COMPILER_VERSION} )
- endif()
-
- if( CMAKE_C_COMPILER_ID MATCHES "Clang" )
- exec_program( ${CMAKE_C_COMPILER}
- ARGS ${CMAKE_C_COMPILER_ARG1} --version
- OUTPUT_VARIABLE EC_COMPILER_VERSION )
-
- string(REGEX REPLACE ".*clang version ([0-9])\\.([0-9])(\\.([0-9]))?.*" "\\1.\\2" EC_COMPILER_VERSION ${EC_COMPILER_VERSION} )
- endif()
-
- if( CMAKE_C_COMPILER_ID MATCHES "SunPro" )
- exec_program( ${CMAKE_C_COMPILER}
- ARGS ${CMAKE_C_COMPILER_ARG1} -V
- OUTPUT_VARIABLE EC_COMPILER_VERSION )
-
- string(REGEX REPLACE ".*([0-9]+)\\.([0-9]+).*" "\\1.\\2" EC_COMPILER_VERSION ${EC_COMPILER_VERSION} )
- endif()
-
- if( CMAKE_C_COMPILER_ID MATCHES "XL" )
- exec_program( ${CMAKE_C_COMPILER}
- ARGS ${CMAKE_C_COMPILER_ARG1} -qversion
- OUTPUT_VARIABLE EC_COMPILER_VERSION )
-
- string(REGEX REPLACE ".*V([0-9]+)\\.([0-9]+).*" "\\1.\\2" EC_COMPILER_VERSION ${EC_COMPILER_VERSION} )
-
- endif()
-
- if( NOT EC_COMPILER_VERSION STREQUAL "?.?" )
- set(CMAKE_C_COMPILER_VERSION "${EC_COMPILER_VERSION}" )
- endif()
-
-endif()
-
-############################################################################################
-# c compiler tests
-
-if( CMAKE_C_COMPILER_LOADED AND ENABLE_OS_TESTS )
-
- ecbuild_cache_check_c_source_compiles(
- " typedef int foo_t;
- static inline foo_t static_foo(){return 0;}
- foo_t foo(){return 0;}
- int main(int argc, char *argv[]){return 0;}
- " EC_HAVE_C_INLINE )
-
-endif()
-
-############################################################################################
-# c++ compiler tests
-
-if( CMAKE_CXX_COMPILER_LOADED AND ENABLE_OS_TESTS )
-
- # check for __FUNCTION__
- ecbuild_cache_check_cxx_source_compiles( "#include <iostream>\nint main(int argc, char* argv[]) { std::cout << __FUNCTION__ << std::endl; }"
- EC_HAVE_FUNCTION_DEF )
-
-
- # check for c++ abi, usually present in GNU compilers
- ecbuild_cache_check_cxx_source_compiles( "#include <cxxabi.h>\n int main() { char * type; int status; char * r = abi::__cxa_demangle(type, 0, 0, &status); }"
- EC_HAVE_CXXABI_H )
-
- # check for bool
- ecbuild_cache_check_cxx_source_compiles( "int main() { bool aflag = true; }"
- EC_HAVE_CXX_BOOL )
-
- # check for sstream
- ecbuild_cache_check_cxx_source_compiles( "#include <sstream>\nint main() { std::stringstream s; }"
- EC_HAVE_CXX_SSTREAM )
-
-endif()
-
-############################################################################################
-# enable warnings
-
-if( CMAKE_COMPILER_IS_GNUCC )
-
- cmake_add_c_flags("-pipe") # use pipe for faster compilation
-
- if( ENABLE_WARNINGS )
- cmake_add_c_flags("-Wall")
- cmake_add_c_flags("-pedantic")
- # cmake_add_c_flags("-Wextra")
- endif()
-
-endif()
-
-if( CMAKE_COMPILER_IS_GNUCXX )
-
- cmake_add_cxx_flags("-pipe") # use pipe for faster compilation
-
- if( ENABLE_WARNINGS )
- cmake_add_cxx_flags("-Wall")
- # cmake_add_cxx_flags("-Wextra")
- endif()
-
-endif()
-
-############################################################################################
-# compiler dependent fixes
-
-# For Cray compilers add "-Wl,-Bdynamic" at very end of linker commands, in order to produce dynamic executables by default
-
-if( "${CMAKE_C_COMPILER_ID}" STREQUAL "Cray" )
- set( CMAKE_C_LINK_EXECUTABLE "<CMAKE_C_COMPILER> <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Wl,-Bdynamic" )
-endif()
-
-if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Cray" )
- set( CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_CXX_COMPILER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Wl,-Bdynamic" )
-endif()
-
-if( "${CMAKE_Fortran_COMPILER_ID}" STREQUAL "Cray" )
- set(CMAKE_Fortran_LINK_EXECUTABLE "<CMAKE_Fortran_COMPILER> <CMAKE_Fortran_LINK_FLAGS> <LINK_FLAGS> <FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Wl,-Bdynamic" )
-endif()
diff --git a/ecbuild/cmake/ecbuild_check_cxx11.cmake b/ecbuild/cmake/ecbuild_check_cxx11.cmake
deleted file mode 100644
index ef1b24e..0000000
--- a/ecbuild/cmake/ecbuild_check_cxx11.cmake
+++ /dev/null
@@ -1,67 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-############################################################################################
-# macro to check for cxx11 features
-# uses macros from the project github.com/UCL/GreatCMakeCookOff
-
-function( ecbuild_check_cxx11 )
-
- # parse parameters
-
- set( options PRINT )
- set( single_value_args )
- set( multi_value_args FEATURES REQUIRED )
-
- cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_check_cxx11(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
-
- include( ${ECBUILD_MACROS_DIR}/contrib/GreatCMakeCookOff/CheckCXX11Features.cmake )
-
- cxx11_find_all_features( ALL_FEATURES ) # list all available features to check
-
- if( NOT _p_FEATURES AND NOT _p_REQUIRED ) # no input, then searhc for all features
-
- cxx11_feature_check()
-
- else()
-
- foreach( _f ${_p_FEATURES} )
- cxx11_feature_check( ${_f} )
- endforeach()
-
- foreach( _f ${_p_REQUIRED} )
- cxx11_feature_check( REQUIRED ${_f} )
- endforeach()
-
- endif()
-
- foreach( f ${ALL_FEATURES} )
- # message( "HAS_CXX11_${FEAT}" )
- string( TOUPPER ${f} FEAT )
- if( HAS_CXX11_${FEAT} )
- list( APPEND CXX11_SUPPORTED_FEATURES ${f} )
- else()
- list( APPEND CXX11_NOT_SUPPORTED_FEATURES ${f} )
- endif()
- endforeach()
-
- set( CXX11_SUPPORTED_FEATURES ${CXX11_SUPPORTED_FEATURES} PARENT_SCOPE )
- set( CXX11_NOT_SUPPORTED_FEATURES ${CXX11_NOT_SUPPORTED_FEATURES} PARENT_SCOPE )
-
- if( _p_PRINT )
- if( CXX11_SUPPORTED_FEATURES )
- join( CXX11_SUPPORTED_FEATURES " " CXX11_SUPPORTED_FEATURES_STR )
- message( STATUS "Found C++11 features: ${CXX11_SUPPORTED_FEATURES_STR}" )
- endif()
- endif()
-
-endfunction( ecbuild_check_cxx11 )
diff --git a/ecbuild/cmake/ecbuild_check_cxx_source.cmake b/ecbuild/cmake/ecbuild_check_cxx_source.cmake
deleted file mode 100644
index a48ae5a..0000000
--- a/ecbuild/cmake/ecbuild_check_cxx_source.cmake
+++ /dev/null
@@ -1,160 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-##############################################################################
-# macro that runs the given C++ code and returns its output
-
-macro( ecbuild_check_cxx_source_return SOURCE )
-
- set( options )
- set( single_value_args VAR OUTPUT )
- set( multi_value_args INCLUDES LIBS DEFINITIONS )
-
- cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if(_p_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_check_cxx_source_return(): \"${_p_UNPARSED_ARGUMENTS}\"")
- endif()
-
- if( NOT _p_VAR OR NOT _p_OUTPUT )
- message(FATAL_ERROR "The call to ecbuild_check_cxx_source_return() doesn't specify either SOURCE, VAR or OUTPUT")
- endif()
-
- set( _msg "Testing ${_p_VAR}:" )
-
- if( NOT DEFINED ${_p_VAR} )
-
- set(MACRO_CHECK_FUNCTION_DEFINITIONS "-D${_p_VAR} ${CMAKE_REQUIRED_FLAGS}")
-
- set(CHECK_CXX_SOURCE_COMPILES_ADD_LIBRARIES)
- if(CMAKE_REQUIRED_LIBRARIES)
- list( APPEND __add_libs ${CMAKE_REQUIRED_LIBRARIES} )
- endif()
- if( _p_LIBS )
- list( APPEND __add_libs ${_p_LIBS} )
- endif()
- if( __add_libs )
- set(CHECK_CXX_SOURCE_COMPILES_ADD_LIBRARIES "-DLINK_LIBRARIES:STRING=${__add_libs}")
- endif()
-
- set(CHECK_CXX_SOURCE_COMPILES_ADD_INCLUDES)
- if(CMAKE_REQUIRED_INCLUDES)
- list( APPEND __add_incs ${CMAKE_REQUIRED_INCLUDES} )
- endif()
- if( _p_INCLUDES )
- list( APPEND __add_incs ${_p_INCLUDES} )
- endif()
- if( __add_incs )
- set(CHECK_CXX_SOURCE_COMPILES_ADD_INCLUDES "-DINCLUDE_DIRECTORIES:STRING=${__add_incs}")
- endif()
-
- # write the source file
-
- file( WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/test_${_p_VAR}.cxx" "${SOURCE}\n" )
-
- message( STATUS "${_msg}" )
- try_run( ${_p_VAR}_EXITCODE ${_p_VAR}_COMPILED
- ${CMAKE_BINARY_DIR}
- ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/test_${_p_VAR}.cxx
- COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
- CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS}
- -DCMAKE_SKIP_RPATH:BOOL=${CMAKE_SKIP_RPATH}
- "${CHECK_CXX_SOURCE_COMPILES_ADD_LIBRARIES}"
- "${CHECK_CXX_SOURCE_COMPILES_ADD_INCLUDES}"
- COMPILE_OUTPUT_VARIABLE compile_OUTPUT
- RUN_OUTPUT_VARIABLE run_OUTPUT )
-
- # debug_var( ${_p_VAR}_COMPILED )
- # debug_var( ${_p_VAR}_EXITCODE )
-
- # if it did not compile make the return value fail code of 1
-
- if( NOT ${_p_VAR}_COMPILED )
- message( STATUS "${_msg} failed to compile" )
- endif()
-
- if( "${${_p_VAR}_EXITCODE}" MATCHES "FAILED_TO_RUN" )
- message( STATUS "${_msg} failed to run" )
- endif()
-
- # if the return value was 0 then it worked
- if( ${_p_VAR}_COMPILED AND "${${_p_VAR}_EXITCODE}" EQUAL 0 )
-
- message(STATUS "${_msg} Success")
- file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
- "Performing C++ SOURCE FILE Test ${_p_VAR} succeded with the following compile output:\n"
- "${compile_OUTPUT}\n"
- "Performing C++ SOURCE FILE Run ${_p_VAR} succeded with the following run output:\n"
- "${run_OUTPUT}\n"
- "Return value: ${${_p_VAR}}\n"
- "Source file was:\n${SOURCE}\n")
-
- set( ${_p_VAR} 1 CACHE INTERNAL "Test ${_p_VAR}")
- set( ${_p_OUTPUT} "${run_OUTPUT}" CACHE INTERNAL "Test ${_p_VAR} output")
-
- else()
-
- if(CMAKE_CROSSCOMPILING AND "${${_p_VAR}_EXITCODE}" MATCHES "FAILED_TO_RUN")
- set(${_p_VAR} "${${_p_VAR}_EXITCODE}")
- set(${OUTPUT} "")
- else()
- set(${_p_VAR} "" CACHE INTERNAL "Test ${_p_VAR}")
- set(${_p_OUTPUT} "" CACHE INTERNAL "Test ${_p_VAR} output")
- endif()
-
- message(STATUS "Test ${_p_VAR} - Failed")
- file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
- "Performing C++ SOURCE FILE Test ${_p_VAR} failed with the following compile output:\n"
- "${compile_OUTPUT}\n"
- "Performing C++ SOURCE FILE Run ${_p_VAR} failed with the following run output:\n"
- "${run_OUTPUT}\n"
- "Return value: ${${_p_VAR}_EXITCODE}\n"
- "Source file was:\n${SOURCE}\n")
- endif()
-
- endif()
-
-endmacro()
-
-##############################################################################
-# macro that only adds a cxx flag if compiler supports it
-
-macro( cmake_add_cxx_flags m_cxx_flags )
-
- set( _flags ${m_cxx_flags} )
- if( _flags AND CMAKE_CXX_COMPILER_LOADED )
- set( options )
- set( single_value_args BUILD )
- set( multi_value_args )
-
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if( NOT DEFINED N_CXXFLAG )
- set( N_CXXFLAG 0 )
- endif()
-
- math( EXPR N_CXXFLAG '${N_CXXFLAG}+1' )
-
- if( NOT ECBUILD_TRUST_FLAGS )
- check_cxx_compiler_flag( ${_flags} CXX_FLAG_TEST_${N_CXXFLAG} )
- endif()
-
- if( CXX_FLAG_TEST_${N_CXXFLAG} OR ECBUILD_TRUST_FLAGS )
- if( _PAR_BUILD )
- set( CMAKE_CXX_FLAGS_${_PAR_BUILD} "${CMAKE_CXX_FLAGS_${_PAR_BUILD}} ${_flags}" )
- else()
- set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${_flags}" )
- # message( STATUS "C++ FLAG [${_flags}] added" )
- endif()
- else()
- message( STATUS "Unrecognised CXX flag [${_flags}] -- skipping" )
- endif()
- endif()
- unset( _flags )
-
-endmacro()
diff --git a/ecbuild/cmake/ecbuild_check_fortran_source.cmake b/ecbuild/cmake/ecbuild_check_fortran_source.cmake
deleted file mode 100644
index da04a70..0000000
--- a/ecbuild/cmake/ecbuild_check_fortran_source.cmake
+++ /dev/null
@@ -1,157 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-##############################################################################
-# macro that runs the given Fortran code and returns its output
-
-macro( ecbuild_check_fortran_source_return SOURCE )
-
- message( WARNING "This macro ecbuild_check_fortran_source has never been tested" )
- set( options )
- set( single_value_args VAR OUTPUT )
- set( multi_value_args INCLUDES LIBS DEFINITIONS )
-
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_check_fortran_source_return(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
-
- if( NOT _PAR_VAR OR NOT _PAR_OUTPUT )
- message(FATAL_ERROR "The call to ecbuild_check_fortran_source_return() doesn't specify either SOURCE, VAR or OUTPUT")
- endif()
-
-
- if( NOT DEFINED ${_PAR_VAR} )
-
- set(MACRO_CHECK_FUNCTION_DEFINITIONS "-D${_PAR_VAR} ${CMAKE_REQUIRED_FLAGS}")
-
- set(CHECK_Fortran_SOURCE_COMPILES_ADD_LIBRARIES)
- if( CMAKE_REQUIRED_LIBRARIES )
- list( APPEND __add_libs ${CMAKE_REQUIRED_LIBRARIES} )
- endif()
- if( _PAR_LIBS )
- list( APPEND __add_libs ${_PAR_LIBS} )
- endif()
- if( __add_libs )
- set(CHECK_Fortran_SOURCE_COMPILES_ADD_LIBRARIES "-DLINK_LIBRARIES:STRING=${__add_libs}")
- endif()
-
- set(CHECK_Fortran_SOURCE_COMPILES_ADD_INCLUDES)
- if( CMAKE_REQUIRED_INCLUDES )
- list( APPEND __add_incs ${CMAKE_REQUIRED_INCLUDES} )
- endif()
- if( _PAR_INCLUDES )
- list( APPEND __add_incs ${_PAR_INCLUDES} )
- endif()
- if( __add_libs )
- set(CHECK_Fortran_SOURCE_COMPILES_ADD_INCLUDES "-DINCLUDE_DIRECTORIES:STRING=${__add_incs}")
- endif()
-
- # write the source file
-
- file( WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/test_${_PAR_VAR}.f" "${SOURCE}\n" )
-
- message( STATUS "Performing Test ${_PAR_VAR}" )
- try_run( ${_PAR_VAR}_EXITCODE ${_PAR_VAR}_COMPILED
- ${CMAKE_BINARY_DIR}
- ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/test_${_PAR_VAR}.f
- COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
- CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS}
- -DCMAKE_SKIP_RPATH:BOOL=${CMAKE_SKIP_RPATH}
- "${CHECK_Fortran_SOURCE_COMPILES_ADD_LIBRARIES}"
- "${CHECK_Fortran_SOURCE_COMPILES_ADD_INCLUDES}"
- COMPILE_OUTPUT_VARIABLE compile_OUTPUT
- RUN_OUTPUT_VARIABLE run_OUTPUT )
-
- # if it did not compile make the return value fail code of 1
- if( NOT ${_PAR_VAR}_COMPILED )
- set( ${_PAR_VAR}_EXITCODE 1 )
- endif()
-
- # if the return value was 0 then it worked
- if("${${_PAR_VAR}_EXITCODE}" EQUAL 0)
-
- message(STATUS "Performing Test ${_PAR_VAR} - Success")
- file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
- "Performing Fortran SOURCE FILE Test ${_PAR_VAR} succeded with the following compile output:\n"
- "${compile_OUTPUT}\n"
- "Performing Fortran SOURCE FILE Run ${_PAR_VAR} succeded with the following run output:\n"
- "${run_OUTPUT}\n"
- "Return value: ${${_PAR_VAR}}\n"
- "Source file was:\n${SOURCE}\n")
-
- set( ${_PAR_VAR} 1 CACHE INTERNAL "Test ${_PAR_VAR}")
- set( ${_PAR_OUTPUT} "${run_OUTPUT}" CACHE INTERNAL "Test ${_PAR_VAR} output")
-
- else()
-
- if(CMAKE_CROSSCOMPILING AND "${${_PAR_VAR}_EXITCODE}" MATCHES "FAILED_TO_RUN")
- set(${_PAR_VAR} "${${_PAR_VAR}_EXITCODE}")
- set(${OUTPUT} "")
- else()
- set(${_PAR_VAR} "" CACHE INTERNAL "Test ${_PAR_VAR}")
- set(${_PAR_OUTPUT} "" CACHE INTERNAL "Test ${_PAR_VAR} output")
- endif()
-
- message(STATUS "Performing Test ${_PAR_VAR} - Failed")
- file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
- "Performing C SOURCE FILE Test ${_PAR_VAR} failed with the following compile output:\n"
- "${compile_OUTPUT}\n"
- "Performing C SOURCE FILE Run ${_PAR_VAR} failed with the following run output:\n"
- "${run_OUTPUT}\n"
- "Return value: ${${_PAR_VAR}_EXITCODE}\n"
- "Source file was:\n${SOURCE}\n")
- endif()
-
- endif()
-
-endmacro()
-
-##############################################################################
-# macro that only adds a Fortran flag if compiler supports it
-
-include( CheckFortranCompilerFlag )
-macro( cmake_add_fortran_flags m_fortran_flags )
-
- set( _flags ${m_fortran_flags} )
-
- if( _flags AND CMAKE_Fortran_COMPILER_LOADED )
-
- set( options )
- set( single_value_args BUILD )
- set( multi_value_args )
-
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if( NOT DEFINED N_FortranFLAG )
- set( N_FortranFLAG 0 )
- endif()
-
- math( EXPR N_FortranFLAG '${N_FortranFLAG}+1' )
-
- if( NOT ECBUILD_TRUST_FLAGS )
- check_fortran_compiler_flag( ${_flags} Fortran_FLAG_TEST_${N_FortranFLAG} )
- endif()
-
- if( Fortran_FLAG_TEST_${N_FortranFLAG} OR ECBUILD_TRUST_FLAGS )
- if( _PAR_BUILD )
- set( CMAKE_Fortran_FLAGS_${_PAR_BUILD} "${CMAKE_Fortran_FLAGS_${_PAR_BUILD}} ${_flags}" )
- else()
- set( CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${_flags}" )
- # message( STATUS "Fortran FLAG [${_flags}] added" )
- endif()
- else()
- message( STATUS "Unrecognised Fortran flag [${_flags}] -- skipping" )
- endif()
- endif()
-
- unset( _flags )
-
-endmacro()
-
diff --git a/ecbuild/cmake/ecbuild_check_functions.cmake b/ecbuild/cmake/ecbuild_check_functions.cmake
deleted file mode 100644
index e859432..0000000
--- a/ecbuild/cmake/ecbuild_check_functions.cmake
+++ /dev/null
@@ -1,125 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-############################################################################################
-# os capability checks
-
-if( ENABLE_OS_FUNCTIONS_TEST )
-
- ### symbol checks ##################
-
- ecbuild_cache_check_symbol_exists( fseek "stdio.h" EC_HAVE_FSEEK )
- ecbuild_cache_check_symbol_exists( fseeko "stdio.h" EC_HAVE_FSEEKO )
- ecbuild_cache_check_symbol_exists( ftello "stdio.h" EC_HAVE_FTELLO )
- ecbuild_cache_check_symbol_exists( lseek "sys/types.h;unistd.h" EC_HAVE_LSEEK )
- ecbuild_cache_check_symbol_exists( ftruncate "sys/types.h;unistd.h" EC_HAVE_FTRUNCATE )
- ecbuild_cache_check_symbol_exists( open "sys/types.h;sys/stat.h;fcntl.h" EC_HAVE_OPEN )
- ecbuild_cache_check_symbol_exists( fopen "stdio.h" EC_HAVE_FOPEN )
- ecbuild_cache_check_symbol_exists( flock "sys/file.h" EC_HAVE_FLOCK )
- ecbuild_cache_check_symbol_exists( mmap "sys/mman.h" EC_HAVE_MMAP )
-
- ecbuild_cache_check_symbol_exists( posix_memalign "stdlib.h" EC_HAVE_POSIX_MEMALIGN )
-
- ecbuild_cache_check_symbol_exists( F_GETLK "fcntl.h" EC_HAVE_F_GETLK )
- ecbuild_cache_check_symbol_exists( F_SETLK "fcntl.h" EC_HAVE_F_SETLK )
- ecbuild_cache_check_symbol_exists( F_SETLKW "fcntl.h" EC_HAVE_F_SETLKW )
-
- ecbuild_cache_check_symbol_exists( F_GETLK64 "fcntl.h" EC_HAVE_F_GETLK64 )
- ecbuild_cache_check_symbol_exists( F_SETLK64 "fcntl.h" EC_HAVE_F_SETLK64 )
- ecbuild_cache_check_symbol_exists( F_SETLKW64 "fcntl.h" EC_HAVE_F_SETLKW64 )
-
- ecbuild_cache_check_symbol_exists( MAP_ANONYMOUS "sys/mman.h" EC_HAVE_MAP_ANONYMOUS )
- ecbuild_cache_check_symbol_exists( MAP_ANON "sys/mman.h" EC_HAVE_MAP_ANON )
-
- ### include files checks ##################
-
- ecbuild_cache_check_include_files( assert.h EC_HAVE_ASSERT_H )
- ecbuild_cache_check_include_files( stdlib.h EC_HAVE_STDLIB_H )
- ecbuild_cache_check_include_files( unistd.h EC_HAVE_UNISTD_H )
- ecbuild_cache_check_include_files( string.h EC_HAVE_STRING_H )
- ecbuild_cache_check_include_files( strings.h EC_HAVE_STRINGS_H )
- ecbuild_cache_check_include_files( sys/stat.h EC_HAVE_SYS_STAT_H )
- ecbuild_cache_check_include_files( sys/time.h EC_HAVE_SYS_TIME_H )
- ecbuild_cache_check_include_files( sys/types.h EC_HAVE_SYS_TYPES_H )
- ecbuild_cache_check_include_files( malloc.h EC_HAVE_MALLOC_H )
- ecbuild_cache_check_include_files( sys/malloc.h EC_HAVE_SYS_MALLOC_H )
-
- ecbuild_cache_check_include_files( sys/param.h EC_HAVE_SYS_PARAM_H )
- ecbuild_cache_check_include_files( sys/mount.h EC_HAVE_SYS_MOUNT_H )
- ecbuild_cache_check_include_files( sys/vfs.h EC_HAVE_SYS_VFS_H )
-
- ### capability checks ##################
-
- # test off_t
- ecbuild_cache_check_c_source_compiles( "#include <sys/types.h>\nint main(){ off_t l=0; return 0;}\n" EC_HAVE_OFFT )
- # test off64_t
- ecbuild_cache_check_c_source_compiles( "#define _LARGEFILE64_SOURCE\n#include <stdio.h>\n#include <sys/types.h>\nint main(){ off64_t l=0; return 0;}\n" EC_HAVE_OFF64T )
- # test struct stat
- ecbuild_cache_check_c_source_compiles( "#include <sys/stat.h>\nint main(){ struct stat s; return 0; }" EC_HAVE_STRUCT_STAT )
- # test struct stat64
- ecbuild_cache_check_c_source_compiles( "#define _LARGEFILE64_SOURCE\n#include <sys/stat.h>\nint main(){ struct stat64 s; return 0; }" EC_HAVE_STRUCT_STAT64 )
- # test stat
- ecbuild_cache_check_c_source_compiles( "#include <sys/stat.h>\nint main(){ struct stat s; stat(\"\",&s); return 0; }" EC_HAVE_STAT )
- # test stat64
- ecbuild_cache_check_c_source_compiles( "#define _LARGEFILE64_SOURCE\n#include <sys/stat.h>\nint main(){ struct stat64 s; stat64(\"\",&s); return 0; }" EC_HAVE_STAT64 )
- # test fstat
- ecbuild_cache_check_c_source_compiles( "#include <sys/stat.h>\nint main(){ struct stat s; fstat(1,&s); return 0; }" EC_HAVE_FSTAT )
- # test fstat64
- ecbuild_cache_check_c_source_compiles( "#define _LARGEFILE64_SOURCE\n#include <sys/stat.h>\nint main(){ struct stat64 s; fstat64(1,&s); return 0; }" EC_HAVE_FSTAT64 )
- # test fseeko64
- ecbuild_cache_check_c_source_compiles( "#define _LARGEFILE64_SOURCE\n#include <stdio.h>\n#include <sys/types.h>\nint main(){FILE* file;off64_t l=0;fseeko64(file,l,SEEK_CUR);return 0;}\n" EC_HAVE_FSEEKO64 )
-
- # test for ftello64
- ecbuild_cache_check_c_source_compiles( "#define _LARGEFILE64_SOURCE\n#include <stdio.h>\n#include <sys/types.h>\nint main(){FILE* file;off64_t l = ftello64(file);return 0;}\n" EC_HAVE_FTELLO64 )
-
- # test for lseek64
- ecbuild_cache_check_c_source_compiles( "#define _LARGEFILE64_SOURCE\n#include <sys/types.h>\n#include <unistd.h>\nint main(){off64_t h = lseek64(0,0,SEEK_SET);return 0;}\n" EC_HAVE_LSEEK64 )
- # test for open64
- ecbuild_cache_check_c_source_compiles( "#define _LARGEFILE64_SOURCE\n#include <fcntl.h>\nint main(){int fd = open64(\"name\",O_RDWR|O_CREAT,0777);return 0;}\n" EC_HAVE_OPEN64 )
- # test for fopen64
- ecbuild_cache_check_c_source_compiles( "#define _LARGEFILE64_SOURCE\n#include <stdio.h>\nint main(){FILE* file = fopen64(\"name\",\"w\");return 0;}\n" EC_HAVE_FOPEN64 )
- # test for ftruncate64
- ecbuild_cache_check_c_source_compiles( "#define _LARGEFILE64_SOURCE\n#include <unistd.h>\n#include <sys/types.h>\nint main(){ftruncate64(0,(off64_t)0);return 0;}\n" EC_HAVE_FTRUNCATE64 )
- # test for flock64
- ecbuild_cache_check_c_source_compiles( "#define _LARGEFILE64_SOURCE\n#include <fcntl.h>\nint main(){struct flock64 l;return 0;}\n" EC_HAVE_FLOCK64 )
- # test for mmap64
- ecbuild_cache_check_c_source_compiles( "#define _LARGEFILE64_SOURCE\n#include <sys/mman.h>\nint main(){void* addr = mmap64(0,10,PROT_READ|PROT_WRITE,MAP_PRIVATE,10,0); return 0;}\n" EC_HAVE_MMAP64 )
- # test for struct statvfs
- ecbuild_cache_check_c_source_compiles( "#include <sys/statvfs.h>\nint main(){ struct statvfs v; }" EC_HAVE_STRUCT_STATVFS )
- # test for struct statvfs64
- ecbuild_cache_check_c_source_compiles( "#define _LARGEFILE64_SOURCE\n#include <sys/statvfs.h>\nint main(){ struct statvfs64 v; }" EC_HAVE_STRUCT_STATVFS64 )
-
- # test for fsync
- ecbuild_cache_check_symbol_exists(fsync "unistd.h" EC_HAVE_FSYNC)
- # test for fdatasync
- ecbuild_cache_check_symbol_exists(fdatasync "unistd.h" EC_HAVE_FDATASYNC)
- # test for dirfd
- ecbuild_cache_check_c_source_compiles( "#include <sys/types.h>\n#include <dirent.h>\nint main(){ DIR *dirp; int i = dirfd(dirp); }\n" EC_HAVE_DIRFD )
- # test for sys/proc.h
- ecbuild_cache_check_c_source_compiles( "#include <sys/proc.h>\nint main(){ return 0; }\n" EC_HAVE_SYSPROC )
- # test for procfs
- ecbuild_cache_check_c_source_compiles( "#include <sys/procfs.h>\nint main(){ return 0; }\n" EC_HAVE_SYSPROCFS )
- # test for backtrace
- ecbuild_cache_check_c_source_compiles( "#include <unistd.h>\n#include <execinfo.h>\n int main(){ void ** buffer; int i = backtrace(buffer, 256); }\n" EC_HAVE_EXECINFO_BACKTRACE )
-
- #### reentrant funtions support #############
-
- # test for gmtime_r
- ecbuild_cache_check_c_source_compiles( "#include <time.h>\nint main(){ time_t now; time(&now); struct tm t; gmtime_r(&now,&t); }\n" EC_HAVE_GMTIME_R )
- # test for getpwuid_r
- ecbuild_cache_check_c_source_compiles( "#include <unistd.h>\n#include <sys/types.h>\n#include <pwd.h>\nint main(){ char buf[4096]; struct passwd pwbuf; struct passwd *pwbufp = 0; getpwuid_r(getuid(), &pwbuf, buf, sizeof(buf), &pwbufp); }\n" EC_HAVE_GETPWUID_R )
- # test for getpwnam_r
- ecbuild_cache_check_c_source_compiles( "#include <sys/types.h>\n#include <pwd.h>\nint main(){ struct passwd p; char line[1024]; int n = getpwnam_r(\"user\",&p,line,sizeof(line),0); }\n" EC_HAVE_GETPWNAM_R )
- # test for readdir_r
- ecbuild_cache_check_c_source_compiles( "#include <dirent.h>\nint main(){ DIR *dirp; struct dirent *entry; struct dirent **result; int i = readdir_r(dirp, entry, result); }\n" EC_HAVE_READDIR_R )
- # test for gethostbyname_r
- ecbuild_cache_check_c_source_compiles( "#include <netdb.h>\nint main(){ const char *name; struct hostent *ret; char *buf; struct hostent **result; size_t buflen; int *h_errnop; int i = gethostbyname_r(name,ret,buf,buflen,result,h_errnop); }\n" EC_HAVE_GETHOSTBYNAME_R )
-
-endif()
-
-
diff --git a/ecbuild/cmake/ecbuild_check_os.cmake b/ecbuild/cmake/ecbuild_check_os.cmake
deleted file mode 100644
index 8373c4a..0000000
--- a/ecbuild/cmake/ecbuild_check_os.cmake
+++ /dev/null
@@ -1,342 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-############################################################################################
-# check size of pointer
-
-ecbuild_cache_check_type_size( "void*" CMAKE_SIZEOF_VOID_P )
-
-math( EXPR EC_OS_BITS "${CMAKE_SIZEOF_VOID_P} * 8" )
-
-# we only support 32 and 64 bit operating systems
-if( NOT EC_OS_BITS EQUAL "32" AND NOT EC_OS_BITS EQUAL "64" )
- message( FATAL_ERROR "operating system ${CMAKE_SYSTEM} ${EC_OS_BITS} bits -- ecbuild only supports 32 or 64 bit OS's" )
-endif()
-ecbuild_cache_var( EC_OS_BITS )
-
-############################################################################################
-# For 64 bit architectures enable PIC (position-independent code)
-
-if( ${EC_OS_BITS} EQUAL 64 )
- set( CMAKE_POSITION_INDEPENDENT_CODE ON )
-endif()
-
-############################################################################################
-# check architecture
-
-if( ENABLE_OS_TYPES_TEST )
-
- set( EC_SIZEOF_PTR ${CMAKE_SIZEOF_VOID_P} )
- ecbuild_cache_var( EC_SIZEOF_PTR )
- ecbuild_cache_check_type_size( char EC_SIZEOF_CHAR )
- ecbuild_cache_check_type_size( short EC_SIZEOF_SHORT )
- ecbuild_cache_check_type_size( int EC_SIZEOF_INT )
- ecbuild_cache_check_type_size( long EC_SIZEOF_LONG )
- ecbuild_cache_check_type_size( "long long" EC_SIZEOF_LONG_LONG )
- ecbuild_cache_check_type_size( float EC_SIZEOF_FLOAT )
- ecbuild_cache_check_type_size( double EC_SIZEOF_DOUBLE )
- ecbuild_cache_check_type_size( "long double" EC_SIZEOF_LONG_DOUBLE )
- ecbuild_cache_check_type_size( size_t EC_SIZEOF_SIZE_T )
- ecbuild_cache_check_type_size( ssize_t EC_SIZEOF_SSIZE_T )
- ecbuild_cache_check_type_size( off_t EC_SIZEOF_OFF_T )
-
-# message( STATUS "sizeof void* [${EC_SIZEOF_PTR}]" )
-# message( STATUS "sizeof off_t [${EC_SIZEOF_OFF_T}]" )
-# message( STATUS "sizeof int [${EC_SIZEOF_INT}]" )
-# message( STATUS "sizeof short [${EC_SIZEOF_SHORT}]" )
-# message( STATUS "sizeof long [${EC_SIZEOF_LONG}]" )
-# message( STATUS "sizeof size_t [${EC_SIZEOF_SIZE_T}]" )
-# message( STATUS "sizeof float [${EC_SIZEOF_FLOAT}]" )
-# message( STATUS "sizeof double [${EC_SIZEOF_DOUBLE}]" )
-# message( STATUS "sizeof long long [${EC_SIZEOF_LONG_LONG}]" )
-# message( STATUS "sizeof long double [${EC_SIZEOF_LONG_DOUBLE}]" )
-
-# message( STATUS "system sizeof :" )
-# message( STATUS " void* [${EC_SIZEOF_PTR}] size_t [${EC_SIZEOF_SIZE_T}] off_t [${EC_SIZEOF_OFF_T}] short [${EC_SIZEOF_SHORT}]" )
-# message( STATUS " int [${EC_SIZEOF_INT}] long [${EC_SIZEOF_LONG}] long long [${EC_SIZEOF_LONG_LONG}]" )
-# message( STATUS " float [${EC_SIZEOF_FLOAT}] double [${EC_SIZEOF_DOUBLE}] long double [${EC_SIZEOF_LONG_DOUBLE}]" )
-
-endif()
-
-############################################################################################
-# check for large file support
-
-# ensure we use 64bit access to files even on 32bit os -- aka Large File Support
-# by making off_t 64bit and stat behave as stat64
-
-if( ENABLE_LARGE_FILE_SUPPORT )
-
- ecbuild_cache_check_type_size( off_t EC_SIZEOF_OFF_T )
-
- if( EC_SIZEOF_OFF_T LESS "8" )
-
- if( ${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "Darwin" )
- add_definitions( -D_FILE_OFFSET_BITS=64 )
- endif()
-
- if( ${CMAKE_SYSTEM_NAME} MATCHES "AIX" )
- add_definitions( -D_LARGE_FILES=64 )
- endif()
-
- get_directory_property( __compile_defs COMPILE_DEFINITIONS )
-
- if( __compile_defs )
- foreach( def ${__compile_defs} )
- list( APPEND CMAKE_REQUIRED_DEFINITIONS -D${def} )
- endforeach()
- endif()
-
- endif()
-
-endif()
-
-############################################################################################
-# check endiness
-
-if( ENABLE_OS_ENDINESS_TEST )
-
- if( NOT DEFINED EC_BIG_ENDIAN AND NOT DEFINED EC_LITTLE_ENDIAN )
- test_big_endian( _BIG_ENDIAN )
-
- if( _BIG_ENDIAN )
- set( EC_BIG_ENDIAN 1 )
- else()
- set( EC_LITTLE_ENDIAN 1 )
- endif()
- endif()
- ecbuild_cache_var( EC_BIG_ENDIAN )
- ecbuild_cache_var( EC_LITTLE_ENDIAN )
-
- if( NOT DEFINED IEEE_BE )
- check_c_source_runs(
- "int compare(unsigned char* a,unsigned char* b) {
- while(*a != 0) if (*(b++)!=*(a++)) return 1;
- return 0;
- }
- int main(int argc,char** argv) {
- unsigned char dc[]={0x30,0x61,0xDE,0x80,0x93,0x67,0xCC,0xD9,0};
- double da=1.23456789e-75;
- unsigned char* ca;
-
- unsigned char fc[]={0x05,0x83,0x48,0x22,0};
- float fa=1.23456789e-35;
-
- if (sizeof(double)!=8) return 1;
-
- ca=(unsigned char*)&da;
- if (compare(dc,ca)) return 1;
-
- if (sizeof(float)!=4) return 1;
-
- ca=(unsigned char*)&fa;
- if (compare(fc,ca)) return 1;
-
- return 0;
- }" IEEE_BE )
-
- if( "${IEEE_BE}" STREQUAL "" )
- set( IEEE_BE 0 CACHE INTERNAL "Test IEEE_BE")
- endif()
- endif()
- ecbuild_cache_var( IEEE_BE )
-
- if( NOT DEFINED IEEE_LE )
- check_c_source_runs(
- "int compare(unsigned char* a,unsigned char* b) {
- while(*a != 0) if (*(b++)!=*(a++)) return 1;
- return 0;
- }
- int main(int argc,char** argv) {
- unsigned char dc[]={0xD9,0xCC,0x67,0x93,0x80,0xDE,0x61,0x30,0};
- double da=1.23456789e-75;
- unsigned char* ca;
-
- unsigned char fc[]={0x22,0x48,0x83,0x05,0};
- float fa=1.23456789e-35;
-
- if (sizeof(double)!=8) return 1;
-
- ca=(unsigned char*)&da;
- if (compare(dc,ca)) return 1;
-
- if (sizeof(float)!=4) return 1;
-
- ca=(unsigned char*)&fa;
- if (compare(fc,ca)) return 1;
-
- return 0;
- }" IEEE_LE )
-
- if( "${IEEE_BE}" STREQUAL "" )
- set( IEEE_LE 0 CACHE INTERNAL "Test IEEE_LE")
- endif()
- endif()
- ecbuild_cache_var( IEEE_LE )
-
-endif()
-
-############################################################################################
-# check operating system
-
-set( EC_OS_NAME "UNKNOWN" )
-
-### Unix's -- Proper operating systems
-
-if( UNIX )
-
- ### APPLE ###
-
- if( APPLE AND ${CMAKE_SYSTEM_NAME} MATCHES "Darwin" )
- set( EC_OS_NAME "macosx" )
- endif()
-
- ### Linux ###
-
- if( ${CMAKE_SYSTEM_NAME} MATCHES "Linux" )
-
- set( EC_OS_NAME "linux" )
-
- # recent linkers default to --enable-new-dtags
- # which then adds both RPATH and RUNPATH to executables
- # thus invalidating RPATH setting, and making LD_LIBRARY_PATH take precedence
- # to be sure, use tool 'readelf -a <exe> | grep PATH' to see what paths are built-in
- # see:
- # * http://blog.qt.digia.com/blog/2011/10/28/rpath-and-runpath
- # * http://www.cmake.org/Wiki/CMake_RPATH_handling
- # * man ld
- # * http://blog.tremily.us/posts/rpath
- # * http://fwarmerdam.blogspot.co.uk/2010/12/rpath-runpath-and-ldlibrarypath.html
- set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--disable-new-dtags")
- set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--disable-new-dtags")
- set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--disable-new-dtags")
-
- endif()
-
- ### Solaris ###
-
- if( ${CMAKE_SYSTEM_NAME} MATCHES "SunOS" )
- set( EC_OS_NAME "solaris" )
- endif()
-
- ### AIX ###
-
- if( ${CMAKE_SYSTEM_NAME} MATCHES "AIX" )
-
- set( EC_OS_NAME "aix" )
-
- set( CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -bbigtoc" )
-
- if( CMAKE_C_COMPILER_ID MATCHES "GNU" )
- set( CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Xlinker" )
- endif()
-
- if( CMAKE_COMPILER_IS_GNUCC )
- if( EC_OS_BITS EQUAL "64" )
- cmake_add_c_flags("-maix64")
- endif()
- if( EC_OS_BITS EQUAL "32" )
- cmake_add_c_flags("-maix32")
- endif()
- endif()
-
- if( CMAKE_COMPILER_IS_GNUCXX )
- if( EC_OS_BITS EQUAL "64" )
- cmake_add_cxx_flags("-maix64")
- endif()
- if( EC_OS_BITS EQUAL "32" )
- cmake_add_cxx_flags("-maix32")
- endif()
- endif()
-
- if( CMAKE_C_COMPILER_ID MATCHES "XL" )
-
- cmake_add_c_flags("-qpic=large")
-# cmake_add_c_flags("-qweaksymbol")
-
- if(EC_OS_BITS EQUAL "32" )
- cmake_add_c_flags("-q32")
- endif()
-
- if(${CMAKE_BUILD_TYPE} MATCHES "Release" OR ${CMAKE_BUILD_TYPE} MATCHES "Production" )
- cmake_add_c_flags("-qstrict")
- cmake_add_c_flags("-qinline")
- endif()
-
- if(${CMAKE_BUILD_TYPE} MATCHES "Debug")
- cmake_add_c_flags("-qfullpath")
- cmake_add_c_flags("-qkeepparm")
- endif()
-
- endif()
-
- if( CMAKE_CXX_COMPILER_ID MATCHES "XL" )
-
- cmake_add_cxx_flags("-qpic=large")
- cmake_add_cxx_flags("-bmaxdata:0x40000000")
- cmake_add_cxx_flags("-qrtti")
- cmake_add_cxx_flags("-qfuncsect")
-
-# cmake_add_cxx_flags("-qweaksymbol")
-
- if(EC_OS_BITS EQUAL "32" )
- cmake_add_cxx_flags("-q32")
- endif()
-
- if(${CMAKE_BUILD_TYPE} MATCHES "Release" OR ${CMAKE_BUILD_TYPE} MATCHES "Production" )
- cmake_add_cxx_flags("-qstrict")
- cmake_add_cxx_flags("-qinline")
- endif()
-
- if(${CMAKE_BUILD_TYPE} MATCHES "Debug")
- cmake_add_cxx_flags("-qfullpath")
- cmake_add_cxx_flags("-qkeepparm")
- endif()
-
- endif()
-
- if( CMAKE_Fortran_COMPILER_ID MATCHES "XL" )
-
- cmake_add_fortran_flags("-qxflag=dealloc_cfptr")
- cmake_add_fortran_flags("-qextname")
- cmake_add_fortran_flags("-qdpc=e")
- cmake_add_fortran_flags("-bmaxdata:0x40000000")
- cmake_add_fortran_flags("-bloadmap:loadmap -bmap:loadmap")
-
- if(EC_OS_BITS EQUAL "32" )
- cmake_add_fortran_flags("-q32")
- endif()
- endif()
-
- endif()
-
-endif()
-
-### Cygwin
-
-if( ${CMAKE_SYSTEM_NAME} MATCHES "CYGWIN" )
-
- set( EC_OS_NAME "cygwin" )
- message( WARNING "Building on Cygwin should work but is untested" )
-
-endif()
-
-### final warning / error
-
-if( ${EC_OS_NAME} MATCHES "UNKNOWN" )
-
- if( DISABLE_OS_CHECK )
- message( WARNING "ecBuild is untested for this operating system: [${CMAKE_SYSTEM_NAME}]"
- " -- DISABLE_OS_CHECK is ON so proceeding at your own risk ..." )
- else()
- message( FATAL_ERROR "ecBuild is untested for this operating system: [${CMAKE_SYSTEM_NAME}]"
- " -- refusing to continue. Disable this check with -DDISABLE_OS_CHECK=ON" )
- endif()
-
-endif()
-
-
diff --git a/ecbuild/cmake/ecbuild_config.h.in b/ecbuild/cmake/ecbuild_config.h.in
deleted file mode 100644
index 8e68a8e..0000000
--- a/ecbuild/cmake/ecbuild_config.h.in
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * (C) Copyright 1996-2014 ECMWF.
- *
- * This software is licensed under the terms of the Apache Licence Version 2.0
- * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
- * In applying this licence, ECMWF does not waive the privileges and immunities
- * granted to it by virtue of its status as an intergovernmental organisation nor
- * does it submit to any jurisdiction.
- */
-
-#ifndef @PROJECT_NAME at _ecbuild_config_h
-#define @PROJECT_NAME at _ecbuild_config_h
-
-/* cpu arch info */
-
-#cmakedefine EC_BIG_ENDIAN @EC_BIG_ENDIAN@
-#cmakedefine EC_LITTLE_ENDIAN @EC_LITTLE_ENDIAN@
-
-/* compiler support */
-
-#cmakedefine EC_HAVE_FUNCTION_DEF
-
-/* os capability checks */
-
-/* --- symbols --- */
-
-#cmakedefine EC_HAVE_FSEEK
-#cmakedefine EC_HAVE_FSEEKO
-#cmakedefine EC_HAVE_FTELLO
-#cmakedefine EC_HAVE_LSEEK
-#cmakedefine EC_HAVE_FTRUNCATE
-#cmakedefine EC_HAVE_OPEN
-#cmakedefine EC_HAVE_FOPEN
-#cmakedefine EC_HAVE_FLOCK
-#cmakedefine EC_HAVE_MMAP
-
-#cmakedefine EC_HAVE_POSIX_MEMALIGN
-
-#cmakedefine EC_HAVE_F_GETLK
-#cmakedefine EC_HAVE_F_SETLKW
-#cmakedefine EC_HAVE_F_SETLK
-
-#cmakedefine EC_HAVE_F_GETLK64
-#cmakedefine EC_HAVE_F_SETLKW64
-#cmakedefine EC_HAVE_F_SETLK64
-
-#cmakedefine EC_HAVE_MAP_ANONYMOUS
-#cmakedefine EC_HAVE_MAP_ANON
-
-/* --- include files --- */
-
-#cmakedefine EC_HAVE_ASSERT_H
-#cmakedefine EC_HAVE_STDLIB_H
-#cmakedefine EC_HAVE_UNISTD_H
-#cmakedefine EC_HAVE_STRING_H
-#cmakedefine EC_HAVE_STRINGS_H
-#cmakedefine EC_HAVE_SYS_STAT_H
-#cmakedefine EC_HAVE_SYS_TIME_H
-#cmakedefine EC_HAVE_SYS_TYPES_H
-
-#cmakedefine EC_HAVE_MALLOC_H
-#cmakedefine EC_HAVE_SYS_MALLOC_H
-
-#cmakedefine EC_HAVE_SYS_PARAM_H
-#cmakedefine EC_HAVE_SYS_MOUNT_H
-#cmakedefine EC_HAVE_SYS_VFS_H
-
-/* --- capabilities --- */
-
-#cmakedefine EC_HAVE_OFFT
-#cmakedefine EC_HAVE_OFF64T
-
-#cmakedefine EC_HAVE_STRUCT_STAT
-#cmakedefine EC_HAVE_STRUCT_STAT64
-#cmakedefine EC_HAVE_STAT
-#cmakedefine EC_HAVE_STAT64
-#cmakedefine EC_HAVE_FSTAT
-#cmakedefine EC_HAVE_FSTAT64
-
-#cmakedefine EC_HAVE_FSEEKO64
-#cmakedefine EC_HAVE_FTELLO64
-#cmakedefine EC_HAVE_LSEEK64
-#cmakedefine EC_HAVE_OPEN64
-#cmakedefine EC_HAVE_FOPEN64
-#cmakedefine EC_HAVE_FTRUNCATE64
-#cmakedefine EC_HAVE_FLOCK64
-#cmakedefine EC_HAVE_MMAP64
-
-#cmakedefine EC_HAVE_STRUCT_STATVFS
-#cmakedefine EC_HAVE_STRUCT_STATVFS64
-#cmakedefine EC_HAVE_STATVFS
-#cmakedefine EC_HAVE_STATVFS64
-
-#cmakedefine EC_HAVE_FSYNC
-#cmakedefine EC_HAVE_FDATASYNC
-#cmakedefine EC_HAVE_DIRFD
-#cmakedefine EC_HAVE_SYSPROC
-#cmakedefine EC_HAVE_SYSPROCFS
-
-#cmakedefine EC_HAVE_EXECINFO_BACKTRACE
-
-/* --- asynchronous IO support --- */
-
-#cmakedefine EC_HAVE_AIOCB
-#cmakedefine EC_HAVE_AIO64CB
-
-/* --- reentrant funtions support --- */
-
-#cmakedefine EC_HAVE_GMTIME_R
-#cmakedefine EC_HAVE_GETPWUID_R
-#cmakedefine EC_HAVE_GETPWNAM_R
-#cmakedefine EC_HAVE_READDIR_R
-#cmakedefine EC_HAVE_GETHOSTBYNAME_R
-
-/* --- c compiler support --- */
-
-#cmakedefine EC_HAVE_C_INLINE
-
-/* --- c++ compiler support --- */
-
-#cmakedefine EC_HAVE_FUNCTION_DEF
-
-#cmakedefine EC_HAVE_CXXABI_H
-#cmakedefine EC_HAVE_CXX_BOOL
-
-#cmakedefine EC_HAVE_CXX_SSTREAM
-
-/* config info */
-
-#define @PNAME at _OS_NAME "@CMAKE_SYSTEM@"
-#define @PNAME at _OS_BITS @EC_OS_BITS@
-#define @PNAME at _OS_BITS_STR "@EC_OS_BITS@"
-#define @PNAME at _OS_STR "@EC_OS_NAME at .@EC_OS_BITS@"
-#define @PNAME at _OS_VERSION "@CMAKE_SYSTEM_VERSION@"
-#define @PNAME at _SYS_PROCESSOR "@CMAKE_SYSTEM_PROCESSOR@"
-
-#define @PNAME at _BUILD_TIMESTAMP "@EC_BUILD_TIMESTAMP@"
-#define @PNAME at _BUILD_TYPE "@CMAKE_BUILD_TYPE@"
-
-#define @PNAME at _C_COMPILER_ID "@CMAKE_C_COMPILER_ID@"
-#define @PNAME at _C_COMPILER_VERSION "@CMAKE_C_COMPILER_VERSION@"
-
-#define @PNAME at _CXX_COMPILER_ID "@CMAKE_CXX_COMPILER_ID@"
-#define @PNAME at _CXX_COMPILER_VERSION "@CMAKE_CXX_COMPILER_VERSION@"
-
-#define @PNAME at _C_COMPILER "@CMAKE_C_COMPILER@"
-#define @PNAME at _C_FLAGS "@EC_C_FLAGS@"
-
-#define @PNAME at _CXX_COMPILER "@CMAKE_CXX_COMPILER@"
-#define @PNAME at _CXX_FLAGS "@EC_CXX_FLAGS@"
-
-#cmakedefine EC_HAVE_FORTRAN
-
-#ifdef EC_HAVE_FORTRAN
-
-#define @PNAME at _Fortran_COMPILER_ID "@CMAKE_Fortran_COMPILER_ID@"
-#define @PNAME at _Fortran_COMPILER_VERSION "@CMAKE_Fortran_COMPILER_VERSION@"
-
-#define @PNAME at _Fortran_COMPILER "@CMAKE_Fortran_COMPILER@"
-#define @PNAME at _Fortran_FLAGS "@EC_Fortran_FLAGS@"
-
-#endif
-
-#cmakedefine BOOST_UNIT_TEST_FRAMEWORK_HEADER_ONLY
-#cmakedefine BOOST_UNIT_TEST_FRAMEWORK_LINKED
-
-#endif /* @PROJECT_NAME at _ecbuild_config_h */
diff --git a/ecbuild/cmake/ecbuild_debug_var.cmake b/ecbuild/cmake/ecbuild_debug_var.cmake
deleted file mode 100644
index 63a5104..0000000
--- a/ecbuild/cmake/ecbuild_debug_var.cmake
+++ /dev/null
@@ -1,35 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-##############################################################################
-# macro for exporting a variable to parent scope
-
-macro( set_parent_scope VAR )
-
- set( ${VAR} ${${VAR}} PARENT_SCOPE )
-
-endmacro( set_parent_scope )
-
-##############################################################################
-# macro for debugging a cmake variable
-
-macro( debug_var VAR )
-
- message( STATUS "${VAR} [${${VAR}}]" )
-
-endmacro( debug_var )
-
-##############################################################################
-# macro for debugging a environment variable within cmake
-
-macro( debug_env_var VAR )
-
- message( STATUS "ENV ${VAR} [$ENV{${VAR}}]" )
-
-endmacro( debug_env_var )
-
diff --git a/ecbuild/cmake/ecbuild_declare_project.cmake b/ecbuild/cmake/ecbuild_declare_project.cmake
deleted file mode 100644
index 57dd1b0..0000000
--- a/ecbuild/cmake/ecbuild_declare_project.cmake
+++ /dev/null
@@ -1,151 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-# macro to initialize a project
-
-macro( ecbuild_declare_project )
-
- string( TOUPPER ${PROJECT_NAME} PNAME )
-
- # reset the lists of targets (executables, libs, tests & resources)
-
- set( ${PROJECT_NAME}_ALL_EXES "" CACHE INTERNAL "" )
- set( ${PROJECT_NAME}_ALL_LIBS "" CACHE INTERNAL "" )
-
- # if git project get its HEAD SHA1
- # leave it here so we may use ${PNAME}_GIT_SHA1 on the version file
-
- if( EXISTS ${PROJECT_SOURCE_DIR}/.git )
- get_git_head_revision( GIT_REFSPEC ${PNAME}_GIT_SHA1 )
- if( ${PNAME}_GIT_SHA1 )
- string( SUBSTRING "${${PNAME}_GIT_SHA1}" 0 7 ${PNAME}_GIT_SHA1_SHORT )
-# debug_var( ${PNAME}_GIT_SHA1 )
-# debug_var( ${PNAME}_GIT_SHA1_SHORT )
- else()
- message( STATUS "Could not get git-sha1 for project ${PNAME}")
- endif()
- endif()
-
- # read and parse project version file
- if( EXISTS ${PROJECT_SOURCE_DIR}/VERSION.cmake )
- include( ${PROJECT_SOURCE_DIR}/VERSION.cmake )
- else()
- set( ${PROJECT_NAME}_VERSION_STR "0.0.0" )
- endif()
-
- string( REPLACE "." " " _version_list ${${PROJECT_NAME}_VERSION_STR} ) # dots to spaces
-
- separate_arguments( _version_list )
-
- list( GET _version_list 0 ${PNAME}_MAJOR_VERSION )
- list( GET _version_list 1 ${PNAME}_MINOR_VERSION )
- list( GET _version_list 2 ${PNAME}_PATCH_VERSION )
-
- # cleanup patch version of any extra qualifiers ( -dev -rc1 ... )
-
- string( REGEX REPLACE "^([0-9]+).*" "\\1" ${PNAME}_PATCH_VERSION "${${PNAME}_PATCH_VERSION}" )
-
- set( ${PNAME}_VERSION "${${PNAME}_MAJOR_VERSION}.${${PNAME}_MINOR_VERSION}.${${PNAME}_PATCH_VERSION}" CACHE INTERNAL "package ${PNAME} version" )
-
- set( ${PNAME}_VERSION_STR "${${PROJECT_NAME}_VERSION_STR}" CACHE INTERNAL "package ${PNAME} version string" ) # ignore caps
-
-# debug_var( ${PNAME}_VERSION )
-# debug_var( ${PNAME}_VERSION_STR )
-# debug_var( ${PNAME}_MAJOR_VERSION )
-# debug_var( ${PNAME}_MINOR_VERSION )
-# debug_var( ${PNAME}_PATCH_VERSION )
-
- # install dirs for this project
-
- if( NOT DEFINED INSTALL_BIN_DIR )
- set( INSTALL_BIN_DIR bin CACHE PATH "Installation directory for executables")
- endif()
-
- if( NOT DEFINED INSTALL_LIB_DIR )
- set( INSTALL_LIB_DIR lib CACHE PATH "Installation directory for libraries")
- endif()
-
- if( NOT DEFINED INSTALL_INCLUDE_DIR )
- set( INSTALL_INCLUDE_DIR include CACHE PATH "Installation directory for header files")
- endif()
-
- if( NOT DEFINED INSTALL_DATA_DIR )
- set( INSTALL_DATA_DIR share/${PROJECT_NAME} CACHE PATH "Installation directory for data files")
- endif()
-
- if( NOT DEFINED INSTALL_CMAKE_DIR )
- set( INSTALL_CMAKE_DIR share/${PROJECT_NAME}/cmake CACHE PATH "Installation directory for CMake files")
- endif()
-
- mark_as_advanced( INSTALL_BIN_DIR )
- mark_as_advanced( INSTALL_LIB_DIR )
- mark_as_advanced( INSTALL_INCLUDE_DIR )
- mark_as_advanced( INSTALL_DATA_DIR )
- mark_as_advanced( INSTALL_CMAKE_DIR )
-
- # warnings for non-relocatable projects
-
- foreach( p LIB BIN INCLUDE DATA CMAKE )
- if( IS_ABSOLUTE ${INSTALL_${p}_DIR} )
- message( WARNING "Defining INSTALL_${p}_DIR as absolute path '${INSTALL_${p}_DIR}' makes this build non-relocatable, possibly breaking the installation of RPMS and DEB packages" )
- endif()
- endforeach()
-
- # make relative paths absolute ( needed later on ) and cache them ...
- foreach( p LIB BIN INCLUDE DATA CMAKE )
-
- set( var INSTALL_${p}_DIR )
-
- if( NOT IS_ABSOLUTE "${${var}}" )
- set( ${PNAME}_FULL_INSTALL_${p}_DIR "${CMAKE_INSTALL_PREFIX}/${${var}}" CACHE INTERNAL "${PNAME} ${p} full install path" )
- else()
- message( WARNING "Setting an absolute path for ${VAR} in project ${PNAME}, breakes generation of relocatable binary packages (rpm,deb,...)" )
- set( ${PNAME}_FULL_INSTALL_${p}_DIR "${${var}}" CACHE INTERNAL "${PNAME} ${p} full install path" )
- endif()
-
-# debug_var( ${PNAME}_FULL_INSTALL_${p}_DIR )
-
- endforeach()
-
- # correctly set CMAKE_INSTALL_RPATH
-
- if( ENABLE_RPATHS )
-
- if( ENABLE_RELATIVE_RPATHS )
-
- file( RELATIVE_PATH relative_rpath ${${PNAME}_FULL_INSTALL_BIN_DIR} ${${PNAME}_FULL_INSTALL_LIB_DIR} )
- # debug_var( relative_rpath )
-
- ecbuild_append_to_rpath( ${relative_rpath} )
-
- else() # make rpaths absolute
-
- if( IS_ABSOLUTE ${INSTALL_LIB_DIR} )
- ecbuild_append_to_rpath( "${INSTALL_LIB_DIR}" )
- else()
- ecbuild_append_to_rpath( "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIB_DIR}" )
- endif()
-
- endif()
-
- endif()
-
- # debug_var( CMAKE_INSTALL_RPATH )
-
- # print project header
-
- message( STATUS "---------------------------------------------------------" )
-
- if( ${PNAME}_GIT_SHA1_SHORT )
- message( STATUS "[${PROJECT_NAME}] (${${PNAME}_VERSION_STR}) [${${PNAME}_GIT_SHA1_SHORT}]" )
- else()
- message( STATUS "[${PROJECT_NAME}] (${${PNAME}_VERSION_STR})" )
- endif()
-
-endmacro( ecbuild_declare_project )
-
diff --git a/ecbuild/cmake/ecbuild_define_build_types.cmake b/ecbuild/cmake/ecbuild_define_build_types.cmake
deleted file mode 100644
index 9ec2ef0..0000000
--- a/ecbuild/cmake/ecbuild_define_build_types.cmake
+++ /dev/null
@@ -1,110 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-############################################################################################
-# define a Production build type
-
-# NOTE: gcc does not guarrante that -O3 performs better than -O2
-# -- it can perform worse due to assembly code bloating.
-# Moreover for gcc 4.1.2 we found that -O3 remove the parser code generated from Lex/Yacc
-# and therefore in production mode we downgrade to -O2 if the compiler is GCC (for all versions).
-
-
-if(CMAKE_COMPILER_IS_GNUCXX)
- set( CMAKE_CXX_FLAGS_PRODUCTION "-O2 -g" CACHE STRING "Flags used by the C++ compiler during Production builds." FORCE )
-else()
- set( CMAKE_CXX_FLAGS_PRODUCTION "-O3 -g" CACHE STRING "Flags used by the C++ compiler during Production builds." FORCE )
-endif()
-
-if(CMAKE_COMPILER_IS_GNUCC)
- set( CMAKE_C_FLAGS_PRODUCTION "-O2 -g" CACHE STRING "Flags used by the C compiler during Production builds." FORCE )
-else()
- set( CMAKE_C_FLAGS_PRODUCTION "-O3 -g" CACHE STRING "Flags used by the C compiler during Production builds." FORCE )
-endif()
-
-set( CMAKE_EXE_LINKER_FLAGS_PRODUCTION "" CACHE STRING "Flags used for linking binaries during Production builds." FORCE )
-set( CMAKE_SHARED_LINKER_FLAGS_PRODUCTION "" CACHE STRING "Flags used by the shared libraries linker during Production builds." FORCE )
-set( CMAKE_MODULE_LINKER_FLAGS_PRODUCTION "" CACHE STRING "Flags used by the static libraries linker during Production builds." FORCE )
-
-mark_as_advanced(
- CMAKE_CXX_FLAGS_PRODUCTION
- CMAKE_C_FLAGS_PRODUCTION
- CMAKE_EXE_LINKER_FLAGS_PRODUCTION
- CMAKE_SHARED_LINKER_FLAGS_PRODUCTION
- CMAKE_MODULE_LINKER_FLAGS_PRODUCTION )
-
-############################################################################################
-# fixes for specific compilers
-
-### remove -Mipa=fast from PGI compilers in RELEASE mode
-
-if( CMAKE_C_COMPILER_ID STREQUAL "PGI" )
- set(CMAKE_C_FLAGS_RELEASE "-fast -O3")
-endif()
-
-if( CMAKE_CXX_COMPILER_ID STREQUAL "PGI" )
- set(CMAKE_CXX_FLAGS_RELEASE "-fast -O3")
-endif()
-
-if( CMAKE_Fortran_COMPILER_ID STREQUAL "PGI" )
- set(CMAKE_Fortran_FLAGS_RELEASE "-fast -O3")
-endif()
-
-############################################################################################
-# define default build type
-
-set( _BUILD_TYPE_MSG "Build type options are: [ None | Debug | Bit | Production | Release | RelWithDebInfo ]" )
-
-if( NOT ECBUILD_DEFAULT_BUILD_TYPE )
- set( ECBUILD_DEFAULT_BUILD_TYPE "RelWithDebInfo" )
-endif()
-
-if(NOT CMAKE_BUILD_TYPE)
- set(CMAKE_BUILD_TYPE ${ECBUILD_DEFAULT_BUILD_TYPE} CACHE STRING ${_BUILD_TYPE_MSG} FORCE )
-endif()
-
-# capitalize the build type for easy use with conditionals
-string( TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_CAPS )
-
-# correct capitatlization of the build type
-
-if( CMAKE_BUILD_TYPE_CAPS STREQUAL "NONE" )
- set(CMAKE_BUILD_TYPE None CACHE STRING ${_BUILD_TYPE_MSG} FORCE )
-endif()
-
-if( CMAKE_BUILD_TYPE_CAPS STREQUAL "DEBUG" )
- set(CMAKE_BUILD_TYPE Debug CACHE STRING ${_BUILD_TYPE_MSG} FORCE )
-endif()
-
-if( CMAKE_BUILD_TYPE_CAPS STREQUAL "BIT" )
- set(CMAKE_BUILD_TYPE Bit CACHE STRING ${_BUILD_TYPE_MSG} FORCE )
-endif()
-
-if( CMAKE_BUILD_TYPE_CAPS STREQUAL "PRODUCTION" )
- set(CMAKE_BUILD_TYPE Production CACHE STRING ${_BUILD_TYPE_MSG} FORCE )
-endif()
-
-if( CMAKE_BUILD_TYPE_CAPS STREQUAL "RELEASE" )
- set(CMAKE_BUILD_TYPE Release CACHE STRING ${_BUILD_TYPE_MSG} FORCE )
-endif()
-
-if( CMAKE_BUILD_TYPE_CAPS STREQUAL "RELWITHDEBINFO" )
- set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING ${_BUILD_TYPE_MSG} FORCE )
-endif()
-
-# fail if build type is not one of the defined ones
-if( NOT CMAKE_BUILD_TYPE MATCHES "None" AND
- NOT CMAKE_BUILD_TYPE MATCHES "Debug" AND
- NOT CMAKE_BUILD_TYPE MATCHES "Bit" AND
- NOT CMAKE_BUILD_TYPE MATCHES "Production" AND
- NOT CMAKE_BUILD_TYPE MATCHES "Release" AND
- NOT CMAKE_BUILD_TYPE MATCHES "RelWithDebInfo" )
- message( FATAL_ERROR "CMAKE_BUILD_TYPE is not recognized. ${_BUILD_TYPE_MSG}" )
-endif()
-
-
diff --git a/ecbuild/cmake/ecbuild_define_options.cmake b/ecbuild/cmake/ecbuild_define_options.cmake
deleted file mode 100644
index a79fcf3..0000000
--- a/ecbuild/cmake/ecbuild_define_options.cmake
+++ /dev/null
@@ -1,40 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-# general options
-
-option( BUILD_SHARED_LIBS "build shared libraries when possible" ON )
-
-option( ENABLE_RPATHS "when installing insert RPATHS into binaries" ON )
-option( ENABLE_RELATIVE_RPATHS "try to use relative RPATHS, including build dir" ON )
-option( ENABLE_WARNINGS "enable compiler warnings" OFF )
-
-option( ENABLE_LARGE_FILE_SUPPORT "build with large file support" ON )
-
-mark_as_advanced( ENABLE_LARGE_FILE_SUPPORT )
-
-option( ENABLE_OS_TESTS "Run all OS tests" ON )
-
-mark_as_advanced( ENABLE_OS_TESTS )
-
-option( ENABLE_FORTRAN_C_INTERFACE "Enable Fortran/C Interface" OFF )
-mark_as_advanced( ENABLE_FORTRAN_C_INTERFACE )
-
-option( DEVELOPER_MODE "activates developer mode" OFF )
-option( CHECK_UNUSED_FILES "check for unused project files" ON )
-
-mark_as_advanced( DEVELOPER_MODE )
-mark_as_advanced( CHECK_UNUSED_FILES )
-
-include( CMakeDependentOption ) # make options depend on one another
-
-cmake_dependent_option( ENABLE_OS_TYPES_TEST "Run sizeof tests on C types" ON "ENABLE_OS_TESTS" OFF)
-cmake_dependent_option( ENABLE_OS_ENDINESS_TEST "Run OS endiness tests" ON "ENABLE_OS_TESTS" OFF)
-cmake_dependent_option( ENABLE_OS_FUNCTIONS_TEST "Run OS functions tests" ON "ENABLE_OS_TESTS" OFF)
-
-mark_as_advanced( ENABLE_OS_TYPES_TEST ENABLE_OS_ENDINESS_TEST ENABLE_OS_FUNCTIONS_TEST )
diff --git a/ecbuild/cmake/ecbuild_define_paths.cmake b/ecbuild/cmake/ecbuild_define_paths.cmake
deleted file mode 100644
index 57a3f1a..0000000
--- a/ecbuild/cmake/ecbuild_define_paths.cmake
+++ /dev/null
@@ -1,41 +0,0 @@
-# (C) Copyright 1996-2012 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-# define project paths
-
-file( MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/bin )
-file( MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
-
-#######################################################################################################
-
-# setup library building rpaths (both in build dir and then when installed)
-
-set( CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE ) # add the automatic parts to RPATH which point to dirs outside build tree
-
-# use RPATHs for the build tree
-set( CMAKE_SKIP_BUILD_RPATH FALSE )
-
-if( ENABLE_RELATIVE_RPATHS )
- # when building, use the install RPATH immedietly
- set( CMAKE_BUILD_WITH_INSTALL_RPATH TRUE )
-else()
- # when building, don't use the install RPATH yet, but later on when installing
- set( CMAKE_BUILD_WITH_INSTALL_RPATH FALSE )
-endif()
-
-# Always include srcdir and builddir in include path
-# This saves typing ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}
-# in about every subdir
-
-set( CMAKE_INCLUDE_CURRENT_DIR OFF )
-
-# put the include dirs which are in the source or build tree
-# before all other include dirs, so the headers in the sources
-# are prefered over the already installed ones (since cmake 2.4.1)
-
-set(CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE ON)
diff --git a/ecbuild/cmake/ecbuild_echo_targets.cmake b/ecbuild/cmake/ecbuild_echo_targets.cmake
deleted file mode 100644
index 015192b..0000000
--- a/ecbuild/cmake/ecbuild_echo_targets.cmake
+++ /dev/null
@@ -1,198 +0,0 @@
-#
-#
-# FUNCTION ecbuild_echo_targets ( <list-of-targets> )
-#
-# Writes all possible target properties of the specified list-of-targets.
-# This is very useful for debugging
-#
-
-
-function(echo_target_property tgt prop)
-
- cmake_policy(PUSH)
-
- if( POLICY CMP0026 )
- cmake_policy( SET CMP0026 OLD)
- endif()
-
- # v for value, d for defined, s for set
- get_property(v TARGET ${tgt} PROPERTY ${prop})
- get_property(d TARGET ${tgt} PROPERTY ${prop} DEFINED)
- get_property(s TARGET ${tgt} PROPERTY ${prop} SET)
-
- # only produce output for values that are set
- #if(s)
- message("tgt='${tgt}' prop='${prop}'")
- message(" value='${v}'")
- message(" defined='${d}'")
- message(" set='${s}'")
- message("")
- #endif()
-
- cmake_policy(POP)
-
-endfunction()
-
-function(echo_target tgt)
- if(NOT TARGET ${tgt})
- message("There is no target named '${tgt}'")
- return()
- endif()
-
- set(props
-DEBUG_OUTPUT_NAME
-DEBUG_POSTFIX
-RELEASE_OUTPUT_NAME
-RELEASE_POSTFIX
-ARCHIVE_OUTPUT_DIRECTORY
-ARCHIVE_OUTPUT_DIRECTORY_DEBUG
-ARCHIVE_OUTPUT_DIRECTORY_RELEASE
-ARCHIVE_OUTPUT_NAME
-ARCHIVE_OUTPUT_NAME_DEBUG
-ARCHIVE_OUTPUT_NAME_RELEASE
-AUTOMOC
-AUTOMOC_MOC_OPTIONS
-BUILD_WITH_INSTALL_RPATH
-BUNDLE
-BUNDLE_EXTENSION
-COMPILE_DEFINITIONS
-COMPILE_DEFINITIONS_DEBUG
-COMPILE_DEFINITIONS_RELEASE
-COMPILE_FLAGS
-DEBUG_POSTFIX
-RELEASE_POSTFIX
-DEFINE_SYMBOL
-ENABLE_EXPORTS
-EXCLUDE_FROM_ALL
-EchoString
-FOLDER
-FRAMEWORK
-Fortran_FORMAT
-Fortran_MODULE_DIRECTORY
-GENERATOR_FILE_NAME
-GNUtoMS
-HAS_CXX
-IMPLICIT_DEPENDS_INCLUDE_TRANSFORM
-IMPORTED
-IMPORTED_CONFIGURATIONS
-IMPORTED_IMPLIB
-IMPORTED_IMPLIB_DEBUG
-IMPORTED_IMPLIB_RELEASE
-IMPORTED_LINK_DEPENDENT_LIBRARIES
-IMPORTED_LINK_DEPENDENT_LIBRARIES_DEBUG
-IMPORTED_LINK_DEPENDENT_LIBRARIES_RELEASE
-IMPORTED_LINK_INTERFACE_LANGUAGES
-IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG
-IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE
-IMPORTED_LINK_INTERFACE_LIBRARIES
-IMPORTED_LINK_INTERFACE_LIBRARIES_DEBUG
-IMPORTED_LINK_INTERFACE_LIBRARIES_RELEASE
-IMPORTED_LINK_INTERFACE_MULTIPLICITY
-IMPORTED_LINK_INTERFACE_MULTIPLICITY_DEBUG
-IMPORTED_LINK_INTERFACE_MULTIPLICITY_RELEASE
-IMPORTED_LOCATION
-IMPORTED_LOCATION_DEBUG
-IMPORTED_LOCATION_RELEASE
-IMPORTED_NO_SONAME
-IMPORTED_NO_SONAME_DEBUG
-IMPORTED_NO_SONAME_RELEASE
-IMPORTED_SONAME
-IMPORTED_SONAME_DEBUG
-IMPORTED_SONAME_RELEASE
-IMPORT_PREFIX
-IMPORT_SUFFIX
-INCLUDE_DIRECTORIES
-INSTALL_NAME_DIR
-INSTALL_RPATH
-INSTALL_RPATH_USE_LINK_PATH
-INTERPROCEDURAL_OPTIMIZATION
-INTERPROCEDURAL_OPTIMIZATION_DEBUG
-INTERPROCEDURAL_OPTIMIZATION_RELEASE
-LABELS
-LIBRARY_OUTPUT_DIRECTORY
-LIBRARY_OUTPUT_DIRECTORY_DEBUG
-LIBRARY_OUTPUT_DIRECTORY_RELEASE
-LIBRARY_OUTPUT_NAME
-LIBRARY_OUTPUT_NAME_DEBUG
-LIBRARY_OUTPUT_NAME_RELEASE
-LINKER_LANGUAGE
-LINK_DEPENDS
-LINK_FLAGS
-LINK_FLAGS_DEBUG
-LINK_FLAGS_RELEASE
-LINK_INTERFACE_LIBRARIES
-LINK_INTERFACE_LIBRARIES_DEBUG
-LINK_INTERFACE_LIBRARIES_RELEASE
-LINK_INTERFACE_MULTIPLICITY
-LINK_INTERFACE_MULTIPLICITY_DEBUG
-LINK_INTERFACE_MULTIPLICITY_RELEASE
-LINK_SEARCH_END_STATIC
-LINK_SEARCH_START_STATIC
-LOCATION
-LOCATION_DEBUG
-LOCATION_RELEASE
-MACOSX_BUNDLE
-MACOSX_BUNDLE_INFO_PLIST
-MACOSX_FRAMEWORK_INFO_PLIST
-MAP_IMPORTED_CONFIG_DEBUG
-MAP_IMPORTED_CONFIG_RELEASE
-OSX_ARCHITECTURES
-OSX_ARCHITECTURES_DEBUG
-OSX_ARCHITECTURES_RELEASE
-OUTPUT_NAME
-OUTPUT_NAME_DEBUG
-OUTPUT_NAME_RELEASE
-POST_INSTALL_SCRIPT
-PREFIX
-PRE_INSTALL_SCRIPT
-PRIVATE_HEADER
-PROJECT_LABEL
-PUBLIC_HEADER
-RESOURCE
-RULE_LAUNCH_COMPILE
-RULE_LAUNCH_CUSTOM
-RULE_LAUNCH_LINK
-RUNTIME_OUTPUT_DIRECTORY
-RUNTIME_OUTPUT_DIRECTORY_DEBUG
-RUNTIME_OUTPUT_DIRECTORY_RELEASE
-RUNTIME_OUTPUT_NAME
-RUNTIME_OUTPUT_NAME_DEBUG
-RUNTIME_OUTPUT_NAME_RELEASE
-SKIP_BUILD_RPATH
-SOURCES
-SOVERSION
-STATIC_LIBRARY_FLAGS
-STATIC_LIBRARY_FLAGS_DEBUG
-STATIC_LIBRARY_FLAGS_RELEASE
-SUFFIX
-TYPE
-VERSION
-VS_DOTNET_REFERENCES
-VS_GLOBAL_WHATEVER
-VS_GLOBAL_KEYWORD
-VS_GLOBAL_PROJECT_TYPES
-VS_KEYWORD
-VS_SCC_AUXPATH
-VS_SCC_LOCALPATH
-VS_SCC_PROJECTNAME
-VS_SCC_PROVIDER
-VS_WINRT_EXTENSIONS
-VS_WINRT_REFERENCES
-WIN32_EXECUTABLE
-XCODE_ATTRIBUTE_WHATEVER
-)
-
- message("======================== ${tgt} ========================")
- foreach(p ${props})
- echo_target_property("${t}" "${p}")
- endforeach()
- message("")
-endfunction()
-
-
-function(ecbuild_echo_targets)
- set(tgts ${ARGV})
- foreach(t ${tgts})
- echo_target("${t}")
- endforeach()
-endfunction()
\ No newline at end of file
diff --git a/ecbuild/cmake/ecbuild_enable_fortran.cmake b/ecbuild/cmake/ecbuild_enable_fortran.cmake
deleted file mode 100644
index dfb28d4..0000000
--- a/ecbuild/cmake/ecbuild_enable_fortran.cmake
+++ /dev/null
@@ -1,56 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-##############################################################################
-
-# macro for enabling the fortan language
-
-macro( ecbuild_enable_fortran )
-
- set( options REQUIRED )
- set( single_value_args MODULE_DIRECTORY )
- set( multi_value_args )
-
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_enable_fortran(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
-
- enable_language( Fortran )
-
- if( DEFINED _PAR_REQUIRED )
- if( CMAKE_Fortran_COMPILER_FORCED )
- set( CMAKE_Fortran_COMPILER_WORKS 1 )
- endif()
- if( NOT CMAKE_Fortran_COMPILER OR NOT CMAKE_Fortran_COMPILER_WORKS )
- message( FATAL_ERROR "Fortran compiler required by project ${PROJECT_NAME} but does not seem to work" )
- endif()
- endif()
-
- if( CMAKE_Fortran_COMPILER_LOADED )
- include(CheckFortranFunctionExists)
- if( CMAKE_C_COMPILER_LOADED AND ENABLE_FORTRAN_C_INTERFACE )
- include(FortranCInterface)
- endif()
- set( EC_HAVE_FORTRAN 1 )
- endif()
-
- if( DEFINED _PAR_MODULE_DIRECTORY )
- set( CMAKE_Fortran_MODULE_DIRECTORY ${_PAR_MODULE_DIRECTORY} )
- else()
- set( CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/module CACHE PATH "directory for all fortran modules." )
- endif()
-
- file( MAKE_DIRECTORY ${CMAKE_Fortran_MODULE_DIRECTORY} )
-
- include_directories( ${CMAKE_Fortran_MODULE_DIRECTORY} )
-
- install( CODE "EXECUTE_PROCESS (COMMAND \"${CMAKE_COMMAND}\" -E copy_directory \"${CMAKE_Fortran_MODULE_DIRECTORY}/\${BUILD_TYPE}\" \"${INSTALL_INCLUDE_DIR}\")" )
-
-endmacro( ecbuild_enable_fortran )
diff --git a/ecbuild/cmake/ecbuild_find_fortranlibs.cmake b/ecbuild/cmake/ecbuild_find_fortranlibs.cmake
deleted file mode 100644
index b40a5eb..0000000
--- a/ecbuild/cmake/ecbuild_find_fortranlibs.cmake
+++ /dev/null
@@ -1,131 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-############################################################################################
-# macro to find fortran (static) link libraries
-
-
-macro( ecbuild_find_fortranlibs )
-
- # parse parameters
-
- set( options REQUIRED )
- set( single_value_args COMPILER )
- set( multi_value_args )
-
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_find_python(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
-
- if( NOT FORTRANLIBS_FOUND ) # don't repeat search
-
- if( _PAR_COMPILER )
- set( __known_fcomp 0 )
- endif()
-
- if( _PAR_COMPILER MATCHES "gfortran" )
- set( WITH_LIBGFORTRAN 1 )
- set( __known_fcomp 1 )
- endif()
-
- if( _PAR_COMPILER MATCHES "pgi" )
- set( WITH_PGI_FORTRAN 1 )
- set( __known_fcomp 1 )
- endif()
-
- if( _PAR_COMPILER MATCHES "xlf" )
- set( WITH_XL_FORTRAN 1 )
- set( __known_fcomp 1 )
- endif()
-
- if( _PAR_COMPILER MATCHES "intel" )
- message( FATAL_ERROR "searching for intel libraries has not been implemented" )
- set( __known_fcomp 1 )
- endif()
-
- if( _PAR_COMPILER AND NOT __known_fcomp )
- message( FATAL_ERROR "unknown fortran compiler ${_PAR_COMPILER}" )
- endif()
-
- ### set path from environment variables
-
- foreach( _fortran_lib PGI XLF LIBGFORTRAN )
- if( NOT ${_fortran_lib}_PATH AND NOT "$ENV{${_fortran_lib}_PATH}" STREQUAL "" )
- set( ${_fortran_lib}_PATH "$ENV{${_fortran_lib}_PATH}" )
- endif()
- endforeach()
-
- set( _flibs_found 0 )
-
- ### default is to search for gfortran
-
- if( NOT WITH_PGI_FORTRAN AND NOT WITH_LIBGFORTRAN AND NOT WITH_XL_FORTRAN
- AND NOT DEFINED PGI_PATH AND NOT DEFINED LIBGFORTRAN_PATH AND NOT DEFINED XLF_PATH )
- message( WARNING "Finding fortran libs for unspecified Fortran compiler: default search [ gfortran ]" )
- set( WITH_LIBGFORTRAN 1 )
- endif()
-
- ### actual search ...
-
- if( WITH_PGI_FORTRAN OR DEFINED PGI_PATH )
-
- find_package(PGIFortran)
-
- if( LIBPGIFORTRAN_FOUND )
- set( FORTRAN_LIBRARIES ${PGIFORTRAN_LIBRARIES} )
- set( _flibs_found 1 )
- set( _flibs_txt "PGI" )
- endif()
-
- endif()
-
- if( WITH_LIBGFORTRAN OR DEFINED LIBGFORTRAN_PATH )
-
- find_package(LibGFortran)
-
- if( LIBGFORTRAN_FOUND )
- set( FORTRAN_LIBRARIES ${GFORTRAN_LIBRARIES} )
- set( _flibs_found 1 )
- set( _flibs_txt "gfortran" )
- endif()
-
- endif()
-
- if( WITH_XL_FORTRAN OR DEFINED XLF_PATH )
-
- find_package(XLFortranLibs)
-
- if( LIBXLFORTRAN_FOUND )
- set( FORTRAN_LIBRARIES ${XLFORTRAN_LIBRARIES} )
- set( _flibs_found 1 )
- set( _flibs_txt "XLF" )
- endif()
-
- endif()
-
- ### set found
-
- if( _flibs_found )
- set( FORTRANLIBS_FOUND 1 CACHE INTERNAL "Fortran libraries found" )
- set( FORTRANLIBS_NAME ${_flibs_txt} CACHE INTERNAL "Fortran library name" )
- set( FORTRAN_LIBRARIES ${FORTRAN_LIBRARIES} CACHE INTERNAL "Fortran libraries" )
- message( STATUS "Found Fortran libraries: ${_flibs_txt}" )
- else()
- set( FORTRANLIBS_FOUND 0 )
- if( _PAR_REQUIRED )
- message( FATAL_ERROR "Failed to find Fortran libraries" )
- else()
- message( STATUS "Failed to find Fortran libraries" )
- endif()
- endif()
-
- endif( NOT FORTRANLIBS_FOUND )
-
-endmacro( ecbuild_find_fortranlibs )
diff --git a/ecbuild/cmake/ecbuild_find_lexyacc.cmake b/ecbuild/cmake/ecbuild_find_lexyacc.cmake
deleted file mode 100644
index 373b81c..0000000
--- a/ecbuild/cmake/ecbuild_find_lexyacc.cmake
+++ /dev/null
@@ -1,60 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-############################################################################################
-# macro to find python
-
-# OUTPUT:
-#
-# BISON_FOUND or YACC_FOUND
-# FLEX_FOUND or LEX_FOUND
-#
-# BISON_EXECUTABLE or YACC_EXECUTABLE
-# FLEX_EXECUTABLE or LEX_EXECUTABLE
-
-macro( ecbuild_find_lexyacc )
-
- # find preferably bison or else yacc
-
- if( NOT SKIP_BISON )
-
- find_package( BISON 2.3 )
- find_package( FLEX )
-
- endif()
-
- if( NOT BISON_FOUND AND NOT SKIP_YACC )
-
- find_package( YACC )
- find_package( LEX )
-
- endif()
-
- if( NOT YACC_FOUND AND NOT BISON_FOUND ) # neither bison nor yacc were found
- message( FATAL_ERROR "neither bison or yacc were found - at least one is required (together with its lexical analyser" )
- endif()
-
- if( NOT YACC_FOUND ) # check for both bison & flex together
- if( BISON_FOUND AND NOT FLEX_FOUND )
- message( FATAL_ERROR "both bison and flex are required - flex not found" )
- endif()
- if( FLEX_FOUND AND NOT BISON_FOUND )
- message( FATAL_ERROR "both bison and flex are required - bison not found" )
- endif()
- endif()
-
- if( NOT BISON_FOUND ) # check for both yacc & lex together
- if( YACC_FOUND AND NOT LEX_FOUND )
- message( FATAL_ERROR "both yacc and lex are required - lex not found" )
- endif()
- if( LEX_FOUND AND NOT YACC_FOUND )
- message( FATAL_ERROR "both yacc and lex are required - yacc not found" )
- endif()
- endif()
-
-endmacro( ecbuild_find_lexyacc )
diff --git a/ecbuild/cmake/ecbuild_find_mpi.cmake b/ecbuild/cmake/ecbuild_find_mpi.cmake
deleted file mode 100644
index 9ed4b3c..0000000
--- a/ecbuild/cmake/ecbuild_find_mpi.cmake
+++ /dev/null
@@ -1,230 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-############################################################################################
-# macro to find MPI
-# uses the canonical find_package( MPI )
-# but does more checks
-
-macro( ecbuild_find_mpi )
-
- # parse parameters
-
- set( options REQUIRED )
- set( single_value_args )
- set( multi_value_args COMPONENTS )
-
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_find_mpi(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
-
- # if user defined compilers are MPI compliant, then we use them ...
- if( NOT DEFINED ECBUILD_FIND_MPI )
- set( ECBUILD_FIND_MPI TRUE )
- endif()
- if( ECBUILD_FIND_MPI )
-
- # C compiler
-
- if( CMAKE_C_COMPILER_LOADED AND NOT MPI_C_COMPILER )
-
- include(CheckCSourceCompiles)
-
- check_c_source_compiles("
- #include <mpi.h>
- int main(int argc, char* argv[])
- {
- int rank;
- MPI_Init(&argc, &argv);
- MPI_Comm_rank(MPI_COMM_WORLD, &rank);
- MPI_Finalize();
- return 0;
- }
- "
- C_COMPILER_SUPPORTS_MPI )
-
- if( C_COMPILER_SUPPORTS_MPI )
- message( STATUS "C compiler supports MPI -- ${CMAKE_C_COMPILER}" )
- set( MPI_C_COMPILER ${CMAKE_C_COMPILER} )
- endif()
-
- endif()
-
- # CXX compiler
-
- if( CMAKE_CXX_COMPILER_LOADED AND NOT MPI_CXX_COMPILER )
-
- include(CheckCXXSourceCompiles)
-
- check_cxx_source_compiles("
- #include <mpi.h>
- #include <iostream>
- int main(int argc, char* argv[])
- {
- MPI_Init(&argc, &argv); int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Finalize();
- return 0;
- }
- "
- CXX_COMPILER_SUPPORTS_MPI )
-
- if( CXX_COMPILER_SUPPORTS_MPI )
- message( STATUS "C++ compiler supports MPI -- ${CMAKE_CXX_COMPILER}" )
- set( MPI_CXX_COMPILER ${CMAKE_CXX_COMPILER} )
- endif()
-
- endif()
-
- # Fortran compiler
-
- if( CMAKE_Fortran_COMPILER_LOADED AND NOT MPI_Fortran_COMPILER )
-
- include(CheckFortranSourceCompiles)
-
- check_fortran_source_compiles("
- program main
- use MPI
- integer ierr
- call MPI_INIT( ierr )
- call MPI_FINALIZE( ierr )
- end
- "
- Fortran_COMPILER_SUPPORTS_MPI )
-
- if( Fortran_COMPILER_SUPPORTS_MPI )
- message( STATUS "Fortran compiler supports MPI (F90) -- ${CMAKE_Fortran_COMPILER}" )
- set( MPI_Fortran_COMPILER ${CMAKE_Fortran_COMPILER} )
- set( MPI_Fortran_FOUND TRUE )
- endif()
-
- endif()
-
- if( NOT _PAR_REQUIRED )
- find_package( MPI QUIET )
- else()
- find_package( MPI QUIET REQUIRED )
- endif()
-
- if( C_COMPILER_SUPPORTS_MPI )
- set( MPI_C_FOUND TRUE )
- endif()
- if( CXX_COMPILER_SUPPORTS_MPI )
- set( MPI_CXX_FOUND TRUE )
- endif()
- if( Fortran_COMPILER_SUPPORTS_MPI )
- set( MPI_Fortran_FOUND TRUE )
- endif()
-
- else()
-
- # find_package with Cray compiler did not send MPI_<lang>_FOUND
- if( CMAKE_C_COMPILER_LOADED )
- set( C_COMPILER_SUPPORTS_MPI TRUE )
- set( MPI_C_FOUND TRUE )
- endif()
- if( CMAKE_CXX_COMPILER_LOADED )
- set( CXX_COMPILER_SUPPORTS_MPI TRUE )
- set( MPI_CXX_FOUND TRUE )
- endif()
- if( CMAKE_Fortran_COMPILER_LOADED )
- set( Fortran_COMPILER_SUPPORTS_MPI TRUE )
- set( MPI_Fortran_FOUND TRUE )
- endif()
-
- endif( ECBUILD_FIND_MPI )
-
- # hide these variables from UI
-
- mark_as_advanced( MPI_LIBRARY MPI_EXTRA_LIBRARY )
-
- if( NOT _PAR_COMPONENTS )
- set( _PAR_COMPONENTS C )
- endif()
-
- set( MPI_FOUND TRUE )
- foreach( _lang ${_PAR_COMPONENTS} )
- if( NOT MPI_${_lang}_FOUND )
- set( MPI_FOUND FALSE )
- endif()
- endforeach()
-
-endmacro( ecbuild_find_mpi )
-
-
-macro( ecbuild_enable_mpi )
-
- set( options REQUIRED )
- set( single_value_args )
- set( multi_value_args COMPONENTS )
-
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_find_mpi(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
-
- if( NOT _PAR_COMPONENTS )
- set (_PAR_COMPONENTS C )
- endif()
-
- if( NOT _PAR_REQUIRED )
- ecbuild_find_mpi( COMPONENTS ${_PAR_COMPONENTS} )
- else()
- ecbuild_find_mpi( COMPONENTS ${_PAR_COMPONENTS} REQUIRED )
- endif()
-
- if( MPI_C_FOUND AND NOT C_COMPILER_SUPPORTS_MPI )
- cmake_add_c_flags("${MPI_C_COMPILE_FLAGS}")
- include_directories(${MPI_C_INCLUDE_PATH})
- endif()
-
- if( MPI_CXX_FOUND AND NOT CXX_COMPILER_SUPPORTS_MPI )
- cmake_add_cxx_flags("${MPI_CXX_COMPILE_FLAGS}")
- include_directories(${MPI_CXX_INCLUDE_PATH})
- endif()
-
- if( MPI_Fortran_FOUND AND NOT Fortran_COMPILER_SUPPORTS_MPI )
- include(ecbuild_check_fortran_source)
- cmake_add_fortran_flags("${MPI_Fortran_COMPILE_FLAGS}")
- include_directories(${MPI_Fortran_INCLUDE_PATH})
- endif()
-
-endmacro( ecbuild_enable_mpi )
-
-macro( ecbuild_include_mpi )
-
- set( options )
- set( single_value_args )
- set( multi_value_args )
-
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_find_mpi(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
-
- if( MPI_C_FOUND AND NOT C_COMPILER_SUPPORTS_MPI )
- include( ecbuild_check_c_source )
- cmake_add_c_flags("${MPI_C_COMPILE_FLAGS}")
- include_directories(${MPI_C_INCLUDE_PATH})
- endif()
-
- if( MPI_CXX_FOUND AND NOT CXX_COMPILER_SUPPORTS_MPI )
- include( ecbuild_check_cxx_source )
- cmake_add_cxx_flags("${MPI_CXX_COMPILE_FLAGS}")
- include_directories(${MPI_CXX_INCLUDE_PATH})
- endif()
-
- if( MPI_Fortran_FOUND AND NOT Fortran_COMPILER_SUPPORTS_MPI )
- include( ecbuild_check_fortran_source )
- cmake_add_fortran_flags("${MPI_Fortran_COMPILE_FLAGS}")
- include_directories(${MPI_Fortran_INCLUDE_PATH})
- endif()
-
-endmacro( ecbuild_include_mpi )
diff --git a/ecbuild/cmake/ecbuild_find_omp.cmake b/ecbuild/cmake/ecbuild_find_omp.cmake
deleted file mode 100644
index 86ab139..0000000
--- a/ecbuild/cmake/ecbuild_find_omp.cmake
+++ /dev/null
@@ -1,204 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-##############################################################################
-# macro for adding a test
-##############################################################################
-
-macro( lookup_omp_flags )
- set(_OMP_FLAG_GNU "-fopenmp")
- set(_OMPSTUBS_FLAG_GNU "-fno-openmp")
-
- set(_OMP_FLAG_Cray "-homp")
- set(_OMPSTUBS_FLAG_Cray "-hnoomp")
-
- set(_OMP_FLAG_XL "-qsmp=omp")
- set(_OMPSTUBS_FLAG_XL "-qsmp=noomp")
-
- set(_OMP_FLAG_Intel "-openmp")
- set(_OMPSTUBS_FLAG_Intel "-openmp-stubs")
-
- # sample C openmp source code to test
- set(_OMP_C_TEST_SOURCE
- "
- #include <omp.h>
- int main() {
- #ifdef _OPENMP
- #pragma omp parallel
- {
- int id = omp_get_thread_num();
- }
- return 0;
- #else
- breaks_on_purpose
- #endif
- }
- ")
- set( _OMP_CXX_TEST_SOURCE ${_OMP_C_TEST_SOURCE} )
-
-
- # sample C openmp source code to test
- set(_OMPSTUBS_C_TEST_SOURCE
- "
- // Include must be found
- #include <omp.h>
- int main() {
- #ifdef _OPENMP
- breaks_on_purpose
- #else
- #pragma omp parallel
- {
- // This pragma should have passed compilation
- int id = 0;
- }
- return 0;
- #endif
- }
- ")
- set( _OMPSTUBS_CXX_TEST_SOURCE ${_OMPSTUBS_C_TEST_SOURCE} )
-
-
- # sample Fortran openmp source code to test
- set(_OMP_Fortran_TEST_SOURCE
- "
- program main
- use omp_lib
- end program
- ")
- set( _OMPSTUBS_Fortran_TEST_SOURCE ${_OMP_Fortran_TEST_SOURCE} )
-
-endmacro()
-
-
-# MACRO ecbuild_find_omp
-#
-# ecbuild_find_omp( COMPONENTS C CXX Fortran
-# STUBS )
-# Sets following variables
-# - OMP_FOUND
-# - OMP_<lang>_FOUND
-# - OMP_<lang>_FLAGS
-#
-# If STUBS are available, above flags will still hold TRUE,
-# as OMP code will just work.
-#
-macro( ecbuild_find_omp )
-
- set( options REQUIRED STUBS )
- set( single_value_args )
- set( multi_value_args COMPONENTS )
-
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if( NOT _PAR_COMPONENTS )
- message( FATAL_ERROR "No COMPONENTS were specified, looking for OMP.\n Please find with COMPONENTS C CXX Fortran " )
- endif()
-
- set( _STUBS "" )
- if( _PAR_STUBS )
- set( _STUBS "STUBS" )
- endif()
-
- lookup_omp_flags()
-
- set( OMP${_STUBS}_FOUND TRUE )
-
- foreach( _LANG ${_PAR_COMPONENTS} )
-
- if( NOT OMP${_STUBS}_${_LANG}_FLAGS )
-
- if( DEFINED _OMP${_STUBS}_FLAG_${CMAKE_${_LANG}_COMPILER_ID} )
- set( _OMP${_STUBS}_${_LANG}_FLAG "${_OMP${_STUBS}_FLAG_${CMAKE_${_LANG}_COMPILER_ID}}" )
- endif()
- if( CMAKE_${_LANG}_COMPILER_LOADED AND _OMP${_STUBS}_${_LANG}_FLAG )
- set(SAVE_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
- set(CMAKE_REQUIRED_FLAGS "${_OMP${_STUBS}_${_LANG}_FLAG}")
- include(Check${_LANG}SourceCompiles)
- set( _SOURCE ${_OMP${_STUBS}_${_LANG}_TEST_SOURCE} )
- set( _FLAG ${_LANG}_COMPILER_SUPPORTS_OMP${_STUBS})
- if( _LANG STREQUAL "C" )
- check_c_source_compiles("${_SOURCE}" ${_FLAG} )
- endif()
- if( _LANG STREQUAL "CXX" )
- check_cxx_source_compiles("${_SOURCE}" ${_FLAG} )
- endif()
- if( _LANG STREQUAL "Fortran" )
- check_fortran_source_compiles("${_SOURCE}" ${_FLAG} )
- endif()
- set(CMAKE_REQUIRED_FLAGS "${SAVE_CMAKE_REQUIRED_FLAGS}")
- endif()
-
- if( ${_LANG}_COMPILER_SUPPORTS_OMP${_STUBS} )
- set( OMP${_STUBS}_${_LANG}_FLAGS ${_OMP${_STUBS}_${_LANG}_FLAG} )
- endif()
-
- else()
- set( ${_LANG}_COMPILER_SUPPORTS_OMP${_STUBS} TRUE )
- endif()
-
-
- set( OMP${_STUBS}_${_LANG}_FIND_QUIETLY TRUE )
- find_package_handle_standard_args( OMP${_STUBS}_${_LANG} REQUIRED_VARS ${_LANG}_COMPILER_SUPPORTS_OMP${_STUBS} )
-
- if( OMP${_STUBS}_FORTRAN_FOUND )
- set( OMP${_STUBS}_Fortran_FOUND TRUE )
- endif()
-
- if( NOT OMP${_STUBS}_${_LANG}_FOUND )
- set( OMP${_STUBS}_FOUND FALSE )
- endif()
-
- if( _PAR_STUBS )
- set( OMP_${_LANG}_FOUND ${OMPSTUBS_${_LANG}_FOUND} )
- set( OMP_${_LANG}_FLAGS ${OMPSTUBS_${_LANG}_FLAGS} )
- endif()
-
- endforeach()
-
- if( _PAR_STUBS )
- set( OMP_FOUND ${OMPSTUBS_FOUND} )
- endif()
-
-endmacro( ecbuild_find_omp )
-
-
-macro( ecbuild_enable_omp )
-
- ecbuild_find_omp( COMPONENTS C CXX Fortran )
-
- if( OMP_C_FOUND )
- set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OMP_C_FLAGS}" )
- endif()
-
- if( OMP_CXX_FOUND )
- set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OMP_CXX_FLAGS}" )
- endif()
-
- if( OMP_Fortran_FOUND )
- set( CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${OMP_Fortran_FLAGS}" )
- endif()
-
-endmacro( ecbuild_enable_omp )
-
-macro( ecbuild_enable_ompstubs )
-
- ecbuild_find_omp( COMPONENTS C CXX Fortran STUBS )
-
- if( OMPSTUBS_C_FOUND )
- set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OMPSTUBS_C_FLAGS}" )
- endif()
-
- if( OMPSTUBS_CXX_FOUND )
- set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OMPSTUBS_CXX_FLAGS}" )
- endif()
-
- if( OMPSTUBS_Fortran_FOUND )
- set( CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${OMPSTUBS_Fortran_FLAGS}" )
- endif()
-
-endmacro( ecbuild_enable_ompstubs )
diff --git a/ecbuild/cmake/ecbuild_find_package.cmake b/ecbuild/cmake/ecbuild_find_package.cmake
deleted file mode 100644
index e6cea19..0000000
--- a/ecbuild/cmake/ecbuild_find_package.cmake
+++ /dev/null
@@ -1,190 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-##############################################################################
-# macro for adding a subproject directory
-##############################################################################
-
-macro( ecbuild_find_package )
-
- set( options REQUIRED QUIET EXACT )
- set( single_value_args NAME VERSION )
- set( multi_value_args )
-
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_find_package(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
-
- if( NOT _PAR_NAME )
- message(FATAL_ERROR "The call to ecbuild_find_package() doesn't specify the NAME.")
- endif()
-
- if( _PAR_EXACT AND NOT _PAR_VERSION )
- message(FATAL_ERROR "Call to ecbuild_find_package() requests EXACT but doesn't specify VERSION.")
- endif()
-
- # debug_var( _PAR_NAME )
-
- string( TOUPPER ${_PAR_NAME} PNAME )
-
- set( _${PNAME}_version "" )
- if( _PAR_VERSION )
- set( _${PNAME}_version ${_PAR_VERSION} )
- if( _PAR_EXACT )
- set( _${PNAME}_version ${_PAR_VERSION} EXACT )
- endif()
- endif()
-
- # check developer mode (search in cmake cache )
-
- if( NOT ${DEVELOPER_MODE} )
- set( NO_DEV_BUILD_DIRS NO_CMAKE_PACKAGE_REGISTRY NO_CMAKE_BUILDS_PATH )
- endif()
-
- # search user defined paths first
-
- if( ${_PAR_NAME}_PATH OR ${PNAME}_PATH OR ${_PAR_NAME}_DIR OR ${PNAME}_DIR )
-
- # debug_var( ${_PAR_NAME}_PATH )
- # debug_var( ${PNAME}_PATH )
-
- # 1) search using CONFIG mode -- try to locate a configuration file provided by the package (package-config.cmake)
-
- if( NOT ${_PAR_NAME}_FOUND )
- find_package( ${_PAR_NAME} ${_${PNAME}_version} NO_MODULE QUIET
- HINTS ${${PNAME}_PATH} ${_PAR_NAME}_PATH ${${PNAME}_DIR} ${${_PAR_NAME}_DIR}
- NO_DEFAULT_PATH )
- endif()
-
- # 2) search using a file Find<package>.cmake if it exists ( macro should itself take *_PATH into account )
-
- if( NOT ${_PAR_NAME}_FOUND )
- find_package( ${_PAR_NAME} ${_${PNAME}_version} MODULE QUIET )
- endif()
-
- # is <package>_PATH was given and we don't find anything then we FAIL
-
- if( NOT ${_PAR_NAME}_FOUND )
- if( ${_PAR_NAME}_PATH )
- message( FATAL_ERROR "${_PAR_NAME}_PATH was provided by user but package ${_PAR_NAME} wasn't found" )
- endif()
- if( ${PNAME}_PATH )
- message( FATAL_ERROR "${PNAME}_PATH was provided by user but package ${_PAR_NAME} wasn't found" )
- endif()
- endif()
-
- endif()
-
- # 3) search developer cache and recently configured packages in the CMake GUI
-
- if( NOT ${_PAR_NAME}_FOUND )
-
- find_package( ${_PAR_NAME} ${_${PNAME}_version} QUIET NO_MODULE HINTS ENV ${PNAME}_PATH
- ${NO_DEV_BUILD_DIRS}
- NO_CMAKE_ENVIRONMENT_PATH
- NO_SYSTEM_ENVIRONMENT_PATH
- NO_CMAKE_SYSTEM_PATH
- NO_CMAKE_SYSTEM_PACKAGE_REGISTRY )
-
- endif()
-
- # 4) search special ECMWF paths
-
- if( NOT ${_PAR_NAME}_FOUND )
-
- set( _ecmwf_paths ) # clear variable
- ecbuild_list_extra_search_paths( ${_PAR_NAME} _ecmwf_paths )
-
- if( _ecmwf_paths )
- find_package( ${_PAR_NAME} ${_${PNAME}_version} QUIET NO_MODULE PATHS ${_ecmwf_paths} NO_DEFAULT_PATH )
- endif()
-
- endif()
-
- # 5) search system paths, for <package>-config.cmake
-
- if( NOT ${_PAR_NAME}_FOUND )
-
- find_package( ${_PAR_NAME} ${_${PNAME}_version} QUIET NO_MODULE ${NO_DEV_BUILD_DIRS} )
-
- endif()
-
- # 6) search system paths, using Find<package>.cmake if it exists
-
- if( NOT ${_PAR_NAME}_FOUND )
-
- find_package( ${_PAR_NAME} ${_${PNAME}_version} QUIET MODULE )
-
- endif()
-
- # check version found is acceptable
-
- if( ${_PAR_NAME}_FOUND )
- set( _version_acceptable 1 )
- if( _PAR_VERSION )
- if( ${_PAR_NAME}_VERSION )
- if( _PAR_EXACT )
- if( NOT ${_PAR_NAME}_VERSION VERSION_EQUAL _PAR_VERSION )
- message( WARNING "${PROJECT_NAME} requires (exactly) ${_PAR_NAME} = ${_PAR_VERSION} -- found ${${_PAR_NAME}_VERSION}" )
- set( _version_acceptable 0 )
- endif()
- else()
- if( _PAR_VERSION VERSION_LESS ${_PAR_NAME}_VERSION OR _PAR_VERSION VERSION_EQUAL ${_PAR_NAME}_VERSION )
- set( _version_acceptable 1 )
- else()
- if( NOT _PAR_QUIET )
- message( WARNING "${PROJECT_NAME} requires ${_PAR_NAME} >= ${_PAR_VERSION} -- found ${${_PAR_NAME}_VERSION}" )
- endif()
- set( _version_acceptable 0 )
- endif()
- endif()
- else()
- if( NOT _PAR_QUIET )
- message( WARNING "${PROJECT_NAME} found ${_PAR_NAME} but no version information, so cannot check if satisfies ${_PAR_VERSION}" )
- endif()
- set( _version_acceptable 0 )
- endif()
- endif()
- endif()
-
- if( ${_PAR_NAME}_FOUND )
-
- if( _version_acceptable )
- set( ${PNAME}_FOUND ${${_PAR_NAME}_FOUND} )
- else()
- if( NOT _PAR_QUIET )
- message( WARNING "${PROJECT_NAME} found ${_PAR_NAME} but with unsuitable version" )
- endif()
- set( ${PNAME}_FOUND 0 )
- set( ${_PAR_NAME}_FOUND 0 )
- endif()
-
- endif()
-
- ### final messages
-
- if( NOT ${_PAR_NAME}_FOUND )
- if( _PAR_REQUIRED )
- message( FATAL_ERROR
- " ${PROJECT_NAME} FAILED to find REQUIRED package ${_PAR_NAME}"
- " Provide location with \"-D ${PNAME}_DIR=/...\"\n"
- " or export ${PNAME}_DIR in environment"
- )
- else()
- if( NOT _PAR_QUIET )
- message( STATUS
- "${PROJECT_NAME} couldn't find package ${_PAR_NAME}.\n"
- " Provide location with \"-D ${PNAME}_DIR=/...\"\n"
- " or export ${PNAME}_DIR in environment" )
- endif()
- endif()
- endif()
-
-endmacro()
diff --git a/ecbuild/cmake/ecbuild_find_perl.cmake b/ecbuild/cmake/ecbuild_find_perl.cmake
deleted file mode 100644
index 2d0cd02..0000000
--- a/ecbuild/cmake/ecbuild_find_perl.cmake
+++ /dev/null
@@ -1,45 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-# OUTPUT:
-
-macro( ecbuild_find_perl )
-
- # parse parameters
-
- set( options REQUIRED )
- set( single_value_args )
- set( multi_value_args )
-
- cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if(_p_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_find_perl(): \"${_p_UNPARSED_ARGUMENTS}\"")
- endif()
-
- find_package( Perl )
-
- if( NOT PERL_EXECUTABLE AND _p_REQUIRED )
- message( FATAL_ERROR "Failed to find Perl (REQUIRED)" )
- endif()
-
- if( PERL_EXECUTABLE )
-
- execute_process( COMMAND ${PERL_EXECUTABLE} -V:version OUTPUT_VARIABLE perl_version_output_variable RESULT_VARIABLE perl_version_return )
- if( NOT perl_version_return )
- string(REGEX REPLACE "version='([^']+)'.*" "\\1" PERL_VERSION ${perl_version_output_variable})
- endif()
-
- # from cmake 2.8.8 onwards
- if( NOT PERL_VERSION_STRING )
- set( PERL_VERSION_STRING ${PERL_VERSION} )
- endif()
-
- endif()
-
-endmacro( ecbuild_find_perl )
\ No newline at end of file
diff --git a/ecbuild/cmake/ecbuild_find_python.cmake b/ecbuild/cmake/ecbuild_find_python.cmake
deleted file mode 100644
index d207ee8..0000000
--- a/ecbuild/cmake/ecbuild_find_python.cmake
+++ /dev/null
@@ -1,131 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-############################################################################################
-# macro to find python
-
-# OUTPUT:
-# PYTHONINTERP_FOUND
-# PYTHONLIBS_FOUND
-# PYTHON_INCLUDE_DIRS
-# PYTHON_LIBRARIES
-# PYTHON_SITE_PACKAGES
-
-macro( ecbuild_find_python )
-
- # parse parameters
-
- set( options REQUIRED )
- set( single_value_args VERSION )
- set( multi_value_args )
-
- cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if(_p_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_find_python(): \"${_p_UNPARSED_ARGUMENTS}\"")
- endif()
-
- # find python executable
-
- find_package( PythonInterp )
-
- if( NOT PYTHONINTERP_FOUND AND _p_REQUIRED )
- message( FATAL_ERROR "Failed to find any Python interpreter (REQUIRED)" )
- endif()
-
- # find python version
- # execute_process( COMMAND ${PYTHON_EXECUTABLE} -V ERROR_VARIABLE _version RESULT_VARIABLE _return ERROR_STRIP_TRAILING_WHITESPACE)
- # if( NOT _return )
- # string(REGEX REPLACE ".*([0-9]+)\\.([0-9]+)\\.([0-9]+)" "\\1.\\2.\\3" PYTHON_VERSION ${_version} )
- # endif()
- # endif()
-
- # message( STATUS "Python version ${PYTHON_VERSION_STRING}" )
- # debug_var(PYTHON_VERSION_MAJOR)
- # debug_var(PYTHON_VERSION_MINOR)
- # debug_var(PYTHON_VERSION_PATCH)
-
- if( PYTHONINTERP_FOUND AND DEFINED _p_VERSION )
- if( _p_VERSION VERSION_GREATER "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}.${PYTHON_VERSION_PATCH}" )
- set( PYTHONINTERP_FOUND 0 )
- set( PYTHON_EXECUTABLE "PYTHON_EXECUTABLE-NOTFOUND" )
- if( _p_REQUIRED )
- message( FATAL_ERROR "Required python version at least ${_p_VERSION} but found only ${PYTHON_VERSION_STRING}" )
- else()
- message( WARNING "Looking for python version at least ${_p_VERSION} but found only ${PYTHON_VERSION_STRING}\nMarking Python as NOTFOUND" )
- endif()
- endif()
- endif()
-
- if( PYTHONINTERP_FOUND )
-
- # find pythonn config
-
- if( PYTHON_EXECUTABLE AND EXISTS ${PYTHON_EXECUTABLE}-config )
- set(PYTHON_CONFIG ${PYTHON_EXECUTABLE}-config CACHE PATH "" FORCE)
- else()
- find_program( PYTHON_CONFIG NAMES python-config python-config${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR} )
- endif()
-
- # find python libs
-
- # The OpenBSD python packages have python-config's
- # that don't reliably report linking flags that will work.
-
- if( PYTHON_CONFIG AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD" )
-
- execute_process(COMMAND "${PYTHON_CONFIG}" --ldflags
- OUTPUT_VARIABLE PYTHON_LIBRARIES
- OUTPUT_STRIP_TRAILING_WHITESPACE
- ERROR_QUIET)
-
- execute_process(COMMAND "${PYTHON_CONFIG}" --includes
- OUTPUT_VARIABLE PYTHON_INCLUDE_DIR
- OUTPUT_STRIP_TRAILING_WHITESPACE
- ERROR_QUIET)
-
-# debug_var(PYTHON_LIBRARIES)
-# debug_var(PYTHON_INCLUDE_DIR)
-
- string(REGEX REPLACE "^[-I]" "" PYTHON_INCLUDE_DIR "${PYTHON_INCLUDE_DIR}")
- string(REGEX REPLACE "[ ]-I" " " PYTHON_INCLUDE_DIR "${PYTHON_INCLUDE_DIR}")
-
- separate_arguments(PYTHON_INCLUDE_DIR)
-
- else() # revert to finding pythonlibs the standard way (cmake macro)
-
- find_package(PythonLibs)
- if( PYTHON_INCLUDE_PATH AND NOT PYTHON_INCLUDE_DIR )
- set(PYTHON_INCLUDE_DIR "${PYTHON_INCLUDE_PATH}")
- endif()
-
- endif()
-
- # set output variables
-
- find_package_handle_standard_args( PythonLibs DEFAULT_MSG PYTHON_INCLUDE_DIR PYTHON_LIBRARIES )
-
- set( PYTHON_INCLUDE_DIRS ${PYTHON_INCLUDE_DIR} )
- set( PYTHON_INCLUDE_PATH ${PYTHON_INCLUDE_DIR} )
-
- list( REMOVE_DUPLICATES PYTHON_INCLUDE_DIRS )
-
- # find where python site-packages are ...
-
- execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()" OUTPUT_VARIABLE PYTHON_SITE_PACKAGES OUTPUT_STRIP_TRAILING_WHITESPACE)
-
- endif()
-
-# debug_var( PYTHONINTERP_FOUND )
-# debug_var( PYTHON_EXECUTABLE )
-# debug_var( PYTHONLIBS_FOUND )
-# debug_var( PYTHON_INCLUDE_DIRS )
-# debug_var( PYTHON_LIBRARIES )
-# debug_var( PYTHON_SITE_PACKAGES )
-
-endmacro( ecbuild_find_python )
diff --git a/ecbuild/cmake/ecbuild_generate_config_headers.cmake b/ecbuild/cmake/ecbuild_generate_config_headers.cmake
deleted file mode 100644
index abf9aac..0000000
--- a/ecbuild/cmake/ecbuild_generate_config_headers.cmake
+++ /dev/null
@@ -1,47 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-############################################################################################
-# generates the config header fot the project with the system introspection done by CMake
-
-function( ecbuild_generate_config_headers )
-
- # parse parameters
-
- set( options )
- set( single_value_args DESTINATION )
- set( multi_value_args )
-
- cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_generate_config_headers(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
-
- # generate list of compiler flags
-
- string( TOUPPER ${PROJECT_NAME} PNAME )
-
- get_property( langs GLOBAL PROPERTY ENABLED_LANGUAGES )
-
- foreach( lang ${langs} )
- set( EC_${lang}_FLAGS "${CMAKE_${lang}_FLAGS} ${CMAKE_${lang}_FLAGS_${CMAKE_BUILD_TYPE_CAPS}}" )
- endforeach()
-
- configure_file( ${ECBUILD_MACROS_DIR}/ecbuild_config.h.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}_ecbuild_config.h )
-
- # install ecbuild configuration
-
- set( _destination ${INSTALL_INCLUDE_DIR} )
- if( _p_DESTINATION )
- set( _destination ${_p_DESTINATION} )
- endif()
-
- install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}_ecbuild_config.h DESTINATION ${_destination} )
-
-endfunction( ecbuild_generate_config_headers )
diff --git a/ecbuild/cmake/ecbuild_generate_rpc.cmake b/ecbuild/cmake/ecbuild_generate_rpc.cmake
deleted file mode 100644
index 5bd4f76..0000000
--- a/ecbuild/cmake/ecbuild_generate_rpc.cmake
+++ /dev/null
@@ -1,73 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-############################################################################################
-# macro to process rpcgen files
-
-macro( ecbuild_generate_rpc )
-
- set( options )
- set( single_value_args SOURCE TARGET_H TARGET_C )
- set( multi_value_args DEPENDANT )
-
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_generate_rpc(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
-
- if( NOT _PAR_SOURCE )
- message(FATAL_ERROR "The call to ecbuild_generate_rpc() doesn't specify the SOURCE file.")
- endif()
-
-# optional
-# if( NOT _PAR_DEPENDANT )
-# message(FATAL_ERROR "The call to ecbuild_generate_rpc() doesn't specify the DEPENDANT files.")
-# endif()
-
- if( NOT DEFINED _PAR_TARGET_H AND NOT DEFINED _PAR_TARGET_C )
- message(FATAL_ERROR "The call to ecbuild_generate_rpc() doesn't specify the _PAR_TARGET_H or _PAR_TARGET_C files.")
- endif()
-
- find_package( RPCGEN REQUIRED )
-
- if( DEFINED _PAR_TARGET_H )
-
- add_custom_command(
- OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_TARGET_H}
- COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/${_PAR_SOURCE} ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_SOURCE}
- COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_TARGET_H}
- COMMAND ${RPCGEN_EXECUTABLE} -h -o ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_TARGET_H} ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_SOURCE}
- DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${_PAR_SOURCE} )
-
- if( DEFINED _PAR_DEPENDANT )
- foreach( file ${_PAR_DEPENDANT} )
- set_source_files_properties( ${file} PROPERTIES OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${_PAR_TARGET_H}" )
- endforeach()
- endif()
-
- endif()
-
- if( DEFINED _PAR_TARGET_C )
-
- add_custom_command(
- OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_TARGET_C}
- COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/${_PAR_SOURCE} ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_SOURCE}
- COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_TARGET_C}
- COMMAND ${RPCGEN_EXECUTABLE} -c -o ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_TARGET_C} ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_SOURCE}
- DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${_PAR_SOURCE} )
-
- if( DEFINED _PAR_DEPENDANT )
- foreach( file ${_PAR_DEPENDANT} )
- set_source_files_properties( ${file} PROPERTIES OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${_PAR_TARGET_C}" )
- endforeach()
- endif()
-
- endif()
-
-endmacro( ecbuild_generate_rpc )
diff --git a/ecbuild/cmake/ecbuild_generate_yy.cmake b/ecbuild/cmake/ecbuild_generate_yy.cmake
deleted file mode 100644
index 391bed1..0000000
--- a/ecbuild/cmake/ecbuild_generate_yy.cmake
+++ /dev/null
@@ -1,113 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-############################################################################################
-# macro to process lex/yacc files
-
-macro( ecbuild_generate_yy )
-
- ecbuild_find_lexyacc() # find [ yacc|byson ] and [ lex|flex ]
-
- ecbuild_find_perl( REQUIRED )
-
- set( options )
- set( single_value_args YYPREFIX YACC LEX LEX_FLAGS YACC_FLAGS FLEX_FLAGS BISON_FLAGS )
- set( multi_value_args DEPENDANT )
-
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_generate_yy(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
-
- if( NOT _PAR_YYPREFIX )
- message(FATAL_ERROR "The call to ecbuild_generate_yy() doesn't specify the YYPREFIX.")
- endif()
-
- if( NOT _PAR_YACC )
- message(FATAL_ERROR "The call to ecbuild_generate_yy() doesn't specify the YACC file.")
- endif()
-
- if( NOT _PAR_LEX )
- message(FATAL_ERROR "The call to ecbuild_generate_yy() doesn't specify the LEX file.")
- endif()
-
- if( NOT _PAR_DEPENDANT )
- message(FATAL_ERROR "The call to ecbuild_generate_yy() doesn't specify the DEPENDANT files.")
- endif()
-
- set( BASE ${_PAR_YYPREFIX}_${_PAR_YACC} )
-
- ## default flags
-
- if( NOT _PAR_LEX_FLAGS )
- set( _PAR_LEX_FLAGS "" )
- endif()
-
- if( NOT _PAR_FLEX_FLAGS )
- set( _PAR_FLEX_FLAGS "-l" )
- endif()
-
- if( NOT _PAR_YACC_FLAGS )
- set( _PAR_YACC_FLAGS "-t" )
- endif()
-
- if( NOT _PAR_BISON_FLAGS )
- set( _PAR_BISON_FLAGS "-t" )
- endif()
-
-# debug_var( BASE )
-
- set( ${BASE}yy_tmp_target ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_YACC}.tmp.c )
- set( ${BASE}yl_tmp_target ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_LEX}.tmp.c )
-
- set( ${BASE}yy_target ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_YACC}.c )
- set( ${BASE}yl_target ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_LEX}.c )
-
- add_custom_target( ${_PAR_YYPREFIX}_${DEPENDANT} SOURCES ${_PAR_YACC}.y ${_PAR_LEX}.l )
-
- if( BISON_FOUND )
- bison_target( ${BASE}_parser ${_PAR_YACC}.y ${${BASE}yy_tmp_target} COMPILE_FLAGS "${_PAR_BISON_FLAGS}" )
- else()
- yacc_target( ${BASE}_parser ${_PAR_YACC}.y ${${BASE}yy_tmp_target} COMPILE_FLAGS "${_PAR_YACC_FLAGS}" )
- endif()
-
- if( FLEX_FOUND )
- flex_target( ${BASE}_scanner ${_PAR_LEX}.l ${${BASE}yl_tmp_target} COMPILE_FLAGS "${_PAR_FLEX_FLAGS}" )
- add_flex_bison_dependency(${BASE}_scanner ${BASE}_parser)
- else()
- lex_target( ${BASE}_scanner ${_PAR_LEX}.l ${${BASE}yl_tmp_target} COMPILE_FLAGS "${_PAR_LEX_FLAGS}" )
- add_lex_yacc_dependency(${BASE}_scanner ${BASE}_parser)
- endif()
-
- set_source_files_properties(${${BASE}yy_tmp_target} GENERATED)
- set_source_files_properties(${${BASE}yl_tmp_target} GENERATED)
-
- add_custom_command(OUTPUT ${${BASE}yy_target}
- COMMAND ${CMAKE_COMMAND} -E copy ${${BASE}yy_tmp_target} ${${BASE}yy_target}
- COMMAND ${PERL_EXECUTABLE} -pi -e 's/yy/${_PAR_YYPREFIX}/g' ${${BASE}yy_target}
- COMMAND ${PERL_EXECUTABLE} -pi -e 's/\\.tmp\\.c/\\.c/g' ${${BASE}yy_target}
- DEPENDS ${${BASE}yy_tmp_target}
- )
-
- add_custom_command(OUTPUT ${${BASE}yl_target}
- COMMAND ${CMAKE_COMMAND} -E copy ${${BASE}yl_tmp_target} ${${BASE}yl_target}
- COMMAND ${PERL_EXECUTABLE} -pi -e 's/yy/${_PAR_YYPREFIX}/g' ${${BASE}yl_target}
- COMMAND ${PERL_EXECUTABLE} -pi -e 's/\\.tmp\\.c/\\.c/g' ${${BASE}yl_target}
- DEPENDS ${${BASE}yl_tmp_target}
- )
-
- set_source_files_properties(${${BASE}yy_target} GENERATED)
- set_source_files_properties(${${BASE}yl_target} GENERATED)
-
- foreach( file ${_PAR_DEPENDANT} )
- set_source_files_properties( ${file} PROPERTIES
- OBJECT_DEPENDS "${${BASE}yy_target};${${BASE}yl_target}" )
- endforeach()
-
-endmacro( ecbuild_generate_yy )
diff --git a/ecbuild/cmake/ecbuild_get_date.cmake b/ecbuild/cmake/ecbuild_get_date.cmake
deleted file mode 100644
index afe3d09..0000000
--- a/ecbuild/cmake/ecbuild_get_date.cmake
+++ /dev/null
@@ -1,32 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-############################################################################################
-# get date macro
-
-macro(ecbuild_get_date RESULT)
- if(UNIX)
- execute_process(COMMAND "date" "+%d/%m/%Y" OUTPUT_VARIABLE ${RESULT})
- string(REGEX REPLACE "(..)/(..)/(....).*" "\\3.\\2.\\1" ${RESULT} ${${RESULT}})
- else()
- message(SEND_ERROR "date not implemented")
- endif()
-endmacro(ecbuild_get_date)
-
-############################################################################################
-# get timestamp
-
-macro(ecbuild_get_timestamp RESULT)
- if(UNIX)
- execute_process(COMMAND "date" "+%Y/%m/%d/%H/%M/%S" OUTPUT_VARIABLE _timestamp)
- string(REGEX REPLACE "(....)/(..)/(..)/(..)/(..)/(..).*" "\\1\\2\\3\\4\\5\\6" ${RESULT} ${_timestamp})
- else()
- message(WARNING "This is NOT UNIX - timestamp not implemented")
- endif()
-endmacro(ecbuild_get_timestamp)
-
diff --git a/ecbuild/cmake/ecbuild_get_resources.cmake b/ecbuild/cmake/ecbuild_get_resources.cmake
deleted file mode 100644
index bf48ecf..0000000
--- a/ecbuild/cmake/ecbuild_get_resources.cmake
+++ /dev/null
@@ -1,52 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-##############################################################################
-# macro for adding a test
-##############################################################################
-
-macro( ecbuild_get_resources )
-
- set( options )
- set( single_value_args TO_DIR )
- set( multi_value_args LIST )
-
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_get_resources(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
-
- if( NOT _PAR_LIST )
- message( FATAL_ERROR "Missing parameter LIST of resources in macro ecbuild_get_resources()" )
- endif()
-
- if( NOT _PAR_TO_DIR )
- set( _PAR_TO_DIR ${CMAKE_CURRENT_BINARY_DIR} )
- endif()
-
- list( LENGTH _PAR_LIST _rsize )
- math( EXPR _max "${_rsize}-1" )
- foreach( i RANGE 0 ${_max} 2 )
-
- math( EXPR in "${i}+1" )
-
- list( GET _PAR_LIST ${i} r )
- list( GET _PAR_LIST ${in} rh )
-
-# debug_var( r )
-# debug_var( rh )
-
- get_filename_component( rf ${r} NAME )
-
- file( DOWNLOAD ${r} ${_PAR_TO_DIR}/${rf} EXPECTED_HASH SHA1=${rh} )
-
- endforeach()
-
-
-endmacro()
diff --git a/ecbuild/cmake/ecbuild_get_test_data.cmake b/ecbuild/cmake/ecbuild_get_test_data.cmake
deleted file mode 100644
index b617a7d..0000000
--- a/ecbuild/cmake/ecbuild_get_test_data.cmake
+++ /dev/null
@@ -1,271 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-##############################################################################
-# function for downloading test data
-
-function( _download_test_data _p_NAME _p_DIRNAME )
-
- # TODO: make that 'at ecmwf'
- #if(1)
- #unset(ENV{no_proxy})
- #unset(ENV{NO_PROXY})
- #set(ENV{http_proxy} "http://proxy.ecmwf.int:3333")
- #endif()
-
- find_program( CURL_PROGRAM curl )
-
- if( CURL_PROGRAM )
-
- add_custom_command( OUTPUT ${_p_NAME}
- COMMENT "(curl) downloading http://download.ecmwf.org/test-data/${_p_DIRNAME}/${_p_NAME}"
- COMMAND ${CURL_PROGRAM} --silent --show-error --fail --output ${_p_NAME} http://download.ecmwf.org/test-data/${_p_DIRNAME}/${_p_NAME} )
-
- else()
-
- find_program( WGET_PROGRAM wget )
-
- if( WGET_PROGRAM )
-
- add_custom_command( OUTPUT ${_p_NAME}
- COMMENT "(wget) downloading http://download.ecmwf.org/test-data/${_p_DIRNAME}/${_p_NAME}"
- COMMAND ${WGET_PROGRAM} -nv -O ${_p_NAME} http://download.ecmwf.org/test-data/${_p_DIRNAME}/${_p_NAME} )
-
- else()
-
- if( WARNING_CANNOT_DOWNLOAD_TEST_DATA )
- message( WARNING "Couldn't find curl neither wget -- cannot download test data from server.\nPlease obtain the test data by other means and pleace it in the build directory." )
- set( WARNING_CANNOT_DOWNLOAD_TEST_DATA 1 CACHE INTERNAL "Couldn't find curl neither wget -- cannot download test data from server" )
- mark_as_advanced( WARNING_CANNOT_DOWNLOAD_TEST_DATA )
- endif()
-
- endif()
-
- endif()
-
-endfunction()
-
-
-##############################################################################
-# function for getting test data
-#
-# examples:
-#
-## no check done
-# ecbuild_get_test_data( NAME msl.grib NOCHECK )
-#
-## checksum agains remote md5 file
-# ecbuild_get_test_data( NAME msl.grib )
-#
-## checksum agains local md5
-# ecbuild_get_test_data( NAME msl.grib MD5 f69ca0929d1122c7878d19f32401abe9 )
-#
-## (DEPRECATED) checksum agains local sha1
-# ecbuild_get_test_data( NAME msl.grib SHA1 5a8e8c57c510b64e31863ca47cfc3b65971089d9 )
-
-function( ecbuild_get_test_data )
-
- set( options NOCHECK )
- set( single_value_args TARGET URL NAME DIRNAME MD5 SHA1)
- set( multi_value_args )
-
- cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if(_p_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_get_test_data(): \"${_p_UNPARSED_ARGUMENTS}\"")
- endif()
-
- file( RELATIVE_PATH currdir ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR} )
-
- ### check parameters
-
- if( NOT _p_NAME )
- message(FATAL_ERROR "ecbuild_get_test_data() expects a NAME")
- endif()
-
- if( NOT _p_TARGET )
- string( REGEX REPLACE "[^A-Za-z0-9_]" "_" _p_TARGET "test_data_${_p_NAME}")
-# string( REGEX REPLACE "[^A-Za-z0-9_]" "_" _p_TARGET "${_p_NAME}")
-# set( _p_TARGET ${_p_NAME} )
- endif()
-
- if( NOT _p_DIRNAME )
- set( _p_DIRNAME ${PROJECT_NAME}/${currdir} )
- endif()
-
-# debug_var( _p_TARGET )
-# debug_var( _p_NAME )
-# debug_var( _p_URL )
-# debug_var( _p_DIRNAME )
-
- # download the data
-
- _download_test_data( ${_p_NAME} ${_p_DIRNAME} )
-
- # perform the checksum if requested
-
- set( _deps ${_p_NAME} )
-
- if( NOT _p_NOCHECK )
-
- find_program( MD5SUM md5sum )
-
- if( MD5SUM AND NOT _p_MD5 AND NOT _p_SHA1) # use remote md5
-
-# message( STATUS " --- getting MD5 sum " )
-
- add_custom_command( OUTPUT ${_p_NAME}.localmd5
- COMMAND ${MD5SUM} -t ${_p_NAME} > ${_p_NAME}.localmd5
- DEPENDS ${_p_NAME} )
-
- _download_test_data( ${_p_NAME}.md5 ${_p_DIRNAME} )
-
- add_custom_command( OUTPUT ${_p_NAME}.ok
- COMMAND diff ${_p_NAME}.md5 ${_p_NAME}.localmd5 && touch ${_p_NAME}.ok
- DEPENDS ${_p_NAME}.localmd5 ${_p_NAME}.md5 )
-
- list( APPEND _deps ${_p_NAME}.localmd5 ${_p_NAME}.ok )
-
- endif()
-
- if( MD5SUM AND _p_MD5 )
-
-# message( STATUS " --- computing MD5 sum [${_p_MD5}]" )
-
- add_custom_command( OUTPUT ${_p_NAME}.localmd5
- COMMAND ${MD5SUM} -t ${_p_NAME} > ${_p_NAME}.localmd5
- DEPENDS ${_p_NAME} )
-
- configure_file( "${ECBUILD_MACROS_DIR}/md5.in" ${_p_NAME}.md5 @ONLY )
-
- add_custom_command( OUTPUT ${_p_NAME}.ok
- COMMAND diff ${_p_NAME}.md5 ${_p_NAME}.localmd5 && touch ${_p_NAME}.ok
- DEPENDS ${_p_NAME}.localmd5 )
-
- list( APPEND _deps ${_p_NAME}.localmd5 ${_p_NAME}.ok )
-
- endif()
-
-# if( _p_SHA1 )
-
-## message( STATUS " --- computing SHA1 sum [${_p_SHA1}]" )
-
-# find_program( SHASUM NAMES sha1sum shasum )
-# if( SHASUM )
-# add_custom_command( OUTPUT ${_p_NAME}.localsha1
-# COMMAND ${SHASUM} ${_p_NAME} > ${_p_NAME}.localsha1 )
-
-# add_custom_command( OUTPUT ${_p_NAME}.ok
-# COMMAND diff ${_p_NAME}.sha1 ${_p_NAME}.localsha1 && touch ${_p_NAME}.ok )
-
-# configure_file( "${ECBUILD_MACROS_DIR}/sha1.in" ${_p_NAME}.sha1 @ONLY )
-
-# list( APPEND _deps ${_p_NAME}.localsha1 ${_p_NAME}.ok )
-# endif()
-
-# endif()
-
- endif()
-
- add_custom_target( ${_p_TARGET} DEPENDS ${_deps} )
-
-endfunction(ecbuild_get_test_data)
-
-##############################################################################
-# function for getting test data
-#
-# examples:
-#
-## no check done
-# ecbuild_get_test_multidata( TARGET get_foobar_data NAMES foo.grib bar.grib DIRNAME test/data/dir NOCHECK )
-#
-## check for remote md5
-# ecbuild_get_test_multidata( TARGET get_foobar_data NAMES foo.grib bar.grib DIRNAME test/data/dir )
-#
-
-function( ecbuild_get_test_multidata )
-
- set( options NOCHECK )
- set( single_value_args TARGET DIRNAME )
- set( multi_value_args NAMES )
-
- cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if(_p_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_get_test_data(): \"${_p_UNPARSED_ARGUMENTS}\"")
- endif()
-
- ### check parameters
-
- if( NOT _p_NAMES )
- message(FATAL_ERROR "ecbuild_get_test_data() expects a NAMES")
- endif()
-
- if( NOT _p_TARGET )
- message(FATAL_ERROR "ecbuild_get_test_data() expects a TARGET")
- endif()
-
-# debug_var( _p_TARGET )
-# debug_var( _p_NAME )
-# debug_var( _p_DIRNAME )
-
- if( _p_NOCHECK )
- set( _nocheck NOCHECK )
- endif()
-
- ### prepare file
-
- set( _script ${CMAKE_CURRENT_BINARY_DIR}/get_data_${_p_TARGET}.cmake )
-
- file( WRITE ${_script} "
-function(EXEC_CHECK)
- execute_process(COMMAND \${ARGV} RESULT_VARIABLE CMD_RESULT)
- if(CMD_RESULT)
- message(FATAL_ERROR \"Error running ${CMD}\")
- endif()
-endfunction()\n\n" )
-
- foreach( _d ${_p_NAMES} )
-
- string( REGEX MATCH "[^:]+" _f "${_d}" )
-
- get_filename_component( _file ${_f} NAME )
- get_filename_component( _dir ${_f} PATH )
-
- list( APPEND _path_comps ${_p_DIRNAME} ${_dir} )
-
- join( _path_comps "/" _dirname )
-
- if( _dirname )
- set( _dirname DIRNAME ${_dirname} )
- endif()
-
- string( REPLACE "." "_" _name "${_file}" )
- string( REGEX MATCH ":.*" _md5 "${_d}" )
- string( REPLACE ":" "" _md5 "${_md5}" )
-
- if( _md5 )
- set( _md5 MD5 ${_md5} )
- endif()
-
- #debug_var(_f)
- #debug_var(_file)
- #debug_var(_dirname)
- #debug_var(_name)
- #debug_var(_md5)
-
- ecbuild_get_test_data( TARGET __get_data_${_p_TARGET}_${_name} NAME ${_file} ${_dirname} ${_md5} ${_nocheck} )
-
- file( APPEND ${_script} "exec_check( ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target __get_data_${_p_TARGET}_${_name} )\n" )
-
- endforeach()
-
- add_test( NAME ${_p_TARGET} COMMAND ${CMAKE_COMMAND} -P ${_script} )
-
-endfunction(ecbuild_get_test_multidata)
-
diff --git a/ecbuild/cmake/ecbuild_install_package.cmake b/ecbuild/cmake/ecbuild_install_package.cmake
deleted file mode 100644
index dec046f..0000000
--- a/ecbuild/cmake/ecbuild_install_package.cmake
+++ /dev/null
@@ -1,286 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-###############################################################################
-
-macro( ecbuild_install_project )
-
-
- set( options )
- set( single_value_args NAME DESCRIPTION )
- set( multi_value_args COMPONENTS )
-
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_install_project(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
-
- if( NOT _PAR_NAME )
- message(FATAL_ERROR "The call to ecbuild_install_project() doesn't specify the NAME.")
- endif()
-
- ### PACKAGING ########################################################
-
- string( TOUPPER ${PROJECT_NAME} PNAME )
- string( TOLOWER ${PROJECT_NAME} LNAME )
-
- # components
-
- # if( DEFINED _PAR_COMPONENTS )
- # set(CPACK_COMPONENTS_ALL "${_PAR_COMPONENTS}")
- # else()
- # set(CPACK_COMPONENTS_ALL "${PROJECT_NAME}")
- # endif()
-
- # name, version, etc ...
-
- set(CPACK_PACKAGE_NAME "${_PAR_NAME}")
- set(CPACK_PACKAGE_VERSION "${${PNAME}_VERSION_STR}")
-
- set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}")
-
- set(CPACK_DEBIAN_PACKAGE_MAINTAINER "ECMWF") # required for DEB
-
- # set(CPACK_ARCHIVE_COMPONENT_INSTALL "ON")
- # set(CPACK_RPM_COMPONENT_INSTALL "ON")
-
- # set(CPACK_GENERATOR "TGZ;RPM;DEB")
- set(CPACK_GENERATOR "TGZ")
- set(CPACK_SOURCE_GENERATOR "TGZ")
- set(CPACK_PACKAGE_VENDOR "ECMWF")
-
- # short description
-
- if( _PAR_DESCRIPTION )
- set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${_PAR_DESCRIPTION}" )
- else()
- set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${_PAR_NAME} misses a description" )
- endif()
-
- # long description
-
- if( EXISTS ${PROJECT_SOURCE_DIR}/INSTALL )
- set(CPACK_PACKAGE_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/INSTALL")
- endif()
- if( EXISTS ${PROJECT_SOURCE_DIR}/LICENSE )
- set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE")
- endif()
-
- # set(CPACK_PACKAGE_EXECUTABLES ${ECBUILD_ALL_EXES})
-
- list( APPEND CPACK_SOURCE_INSTALLED_DIRECTORIES
- "${PROJECT_SOURCE_DIR}" "."
- "${ECBUILD_MACROS_DIR}" "cmake/" )
-
- # what to pack and not
-
- set(CPACK_SOURCE_IGNORE_FILES
- /build/
- /\\\\.git/
- /\\\\.svn/
- CMakeLists.txt.user
- \\\\.swp$
- p4config
- )
-
- # skip the files that were declared as DONT_PACK
-
- list( APPEND CPACK_SOURCE_IGNORE_FILES ${ECBUILD_DONT_PACK_FILES} )
-
- # cpack config file
-
- # set(CPACK_INSTALL_CMAKE_PROJECTS "${${PROJECT_NAME}_BINARY_DIR}" "${PROJECT_NAME}" "${CPACK_COMPONENTS_ALL}" "*" )
-
- include( CPack )
-
- ### EXPORTS ########################################################
-
-
- foreach( _tpl ${${PNAME}_TPLS} )
- string( TOUPPER ${_tpl} _TPL )
-
- if( ${_tpl}_INCLUDE_DIRS )
- list( APPEND ${PNAME}_TPL_INCLUDE_DIRS ${${_tpl}_INCLUDE_DIRS} )
- elseif( ${_tpl}_INCLUDE_DIR )
- list( APPEND ${PNAME}_TPL_INCLUDE_DIRS ${${_tpl}_INCLUDE_DIR} )
- elseif( ${_TPL}_INCLUDE_DIRS )
- list( APPEND ${PNAME}_TPL_INCLUDE_DIRS ${${_TPL}_INCLUDE_DIRS} )
- elseif( ${_TPL}_INCLUDE_DIR )
- list( APPEND ${PNAME}_TPL_INCLUDE_DIRS ${${_TPL}_INCLUDE_DIR} )
- endif()
-
- if( ${_tpl}_LIBRARIES )
- list( APPEND ${PNAME}_TPL_LIBRARIES ${${_tpl}_LIBRARIES} )
- elseif( ${_tpl}_LIBRARY )
- list( APPEND ${PNAME}_TPL_LIBRARIES ${${_tpl}_LIBRARY} )
- elseif( ${_TPL}_LIBRARIES )
- list( APPEND ${PNAME}_TPL_LIBRARIES ${${_TPL}_LIBRARIES} )
- elseif( ${_TPL}_LIBRARY )
- list( APPEND ${PNAME}_TPL_LIBRARIES ${${_TPL}_LIBRARY} )
- endif()
-
- if( ${_tpl}_DEFINITIONS )
- list( APPEND ${PNAME}_TPL_DEFINITIONS ${${_tpl}_DEFINITIONS} )
- elseif( ${_TPL}_DEFINITIONS )
- list( APPEND ${PNAME}_TPL_DEFINITIONS ${${_TPL}_DEFINITIONS} )
- endif()
- endforeach()
-
- # TOP-LEVEL PROJECT EXPORT
-
- if( PROJECT_NAME STREQUAL CMAKE_PROJECT_NAME )
-
- # exports the package for use from the build-tree -- inserts <package> into the CMake user package registry
-
- export( PACKAGE ${PROJECT_NAME} )
-
- set( _template_config "${ECBUILD_MACROS_DIR}/project-config.cmake.in" )
- if( EXISTS ${LNAME}-config.cmake.in )
- set( _template_config "${LNAME}-config.cmake.in" )
- endif()
-
- set( _template_config_version "${ECBUILD_MACROS_DIR}/project-config-version.cmake.in" )
- if( EXISTS ${LNAME}-config-version.cmake.in )
- set( _template_config_version "${LNAME}-config-version.cmake.in" )
- endif()
-
- # project-config-version.cmake -- format ([0-9]+).([0-9]+).([0-9]+)
-
- set( PACKAGE_VERSION "${${PNAME}_VERSION}" )
-
- configure_file( "${_template_config_version}" "${PROJECT_BINARY_DIR}/${LNAME}-config-version.cmake" @ONLY )
-
- install( FILES "${PROJECT_BINARY_DIR}/${LNAME}-config-version.cmake" DESTINATION "${INSTALL_CMAKE_DIR}" )
-
- # prepare imutable variables (don't depend on install path)
-
- set( CONF_FEATURES "" )
- if( ${PNAME}_FEATURES )
- set( CONF_FEATURES ${${PNAME}_FEATURES} )
- endif()
-
- set( CONF_LIBRARIES ${${PROJECT_NAME}_ALL_LIBS} )
- if( ${PNAME}_LIBRARIES )
- set( CONF_LIBRARIES ${${PNAME}_LIBRARIES} )
- endif()
-
- set( CONF_DEFINITIONS "" )
- if( ${PNAME}_DEFINITIONS )
- set( CONF_DEFINITIONS ${${PNAME}_DEFINITIONS} )
- endif()
-
- set( CONF_TPL_LIBRARIES "" )
- if( ${PNAME}_TPL_LIBRARIES )
- set( CONF_TPL_LIBRARIES ${${PNAME}_TPL_LIBRARIES} )
- endif()
-
- # project-config.cmake @ build tree
-
- set( CONF_TPLS ${${PNAME}_TPLS} )
-
- set( CONF_INCLUDE_DIRS "${PROJECT_SOURCE_DIR}" "${PROJECT_BINARY_DIR}" )
- if( ${PNAME}_INCLUDE_DIRS )
- set( CONF_INCLUDE_DIRS ${${PNAME}_INCLUDE_DIRS} )
- endif()
-
- set( CONF_TPL_INCLUDE_DIRS "" )
- foreach( _tpl ${${PNAME}_TPLS} )
- string( TOUPPER ${_tpl} TPL )
- if( ${_tpl}_INCLUDE_DIRS )
- list( APPEND CONF_TPL_INCLUDE_DIRS ${${_tpl}_INCLUDE_DIRS} )
- elseif( ${_tpl}_INCLUDE_DIR )
- list( APPEND CONF_TPL_INCLUDE_DIRS ${${_tpl}_INCLUDE_DIR} )
- elseif( ${TPL}_INCLUDE_DIRS )
- list( APPEND CONF_TPL_INCLUDE_DIRS ${${TPL}_INCLUDE_DIRS} )
- elseif( ${TPL}_INCLUDE_DIR )
- list( APPEND CONF_TPL_INCLUDE_DIRS ${${TPL}_INCLUDE_DIR} )
- endif()
- endforeach()
-
- set( CONF_IMPORT_FILE "${LNAME}-import.cmake" )
-
- if( EXISTS "${PROJECT_SOURCE_DIR}/${CONF_IMPORT_FILE}.in" )
- configure_file( "${PROJECT_SOURCE_DIR}/${CONF_IMPORT_FILE}.in"
- "${PROJECT_BINARY_DIR}/${CONF_IMPORT_FILE}" @ONLY )
- install( FILES "${PROJECT_BINARY_DIR}/${CONF_IMPORT_FILE}"
- DESTINATION "${INSTALL_CMAKE_DIR}" )
- endif()
-
- set( _lname_config "${PROJECT_BINARY_DIR}/${LNAME}-config.cmake")
-
- set( _is_build_dir_export ON )
- configure_file( "${_template_config}" "${_lname_config}" @ONLY )
-
- file( REMOVE ${_lname_config}.tpls.in )
-
- foreach( _tpl ${${PNAME}_TPLS} )
- string( TOUPPER ${_tpl} TPL )
- if( ${TPL}_IMPORT_FILE )
- set( __import_file "${${TPL}_IMPORT_FILE}" )
- file( APPEND "${_lname_config}.tpls.in" "if( NOT ${TPL}_IMPORT_FILE )\n" )
- file( APPEND "${_lname_config}.tpls.in" " include( \"${__import_file}\" OPTIONAL )\n" )
- file( APPEND "${_lname_config}.tpls.in" "endif()\n" )
- endif()
- endforeach()
-
- if( EXISTS "${_lname_config}.tpls.in" )
- configure_file( "${_lname_config}.tpls.in" "${_lname_config}.tpls" @ONLY )
- install( FILES "${_lname_config}.tpls" DESTINATION "${INSTALL_CMAKE_DIR}" )
- endif()
-
- # project-config.cmake @ install tree
-
- file( RELATIVE_PATH REL_INCLUDE_DIR "${${PNAME}_FULL_INSTALL_CMAKE_DIR}" "${${PNAME}_FULL_INSTALL_INCLUDE_DIR}" )
- set( CONF_INCLUDE_DIRS "\${${PNAME}_CMAKE_DIR}/${REL_INCLUDE_DIR}" )
-
- set( CONF_TPL_INCLUDE_DIRS "" )
- foreach( _tpl ${${PNAME}_TPLS} )
- string( TOUPPER ${_tpl} TPL )
- if( ${TPL}_FULL_INSTALL_INCLUDE_DIR )
- list( APPEND CONF_TPL_INCLUDE_DIRS "\${${PNAME}_CMAKE_DIR}/${REL_INCLUDE_DIR}" )
- endif()
- if( ${_tpl}_INCLUDE_DIRS )
- list( APPEND CONF_TPL_INCLUDE_DIRS ${${_tpl}_INCLUDE_DIRS} )
- elseif( ${_tpl}_INCLUDE_DIR )
- list( APPEND CONF_TPL_INCLUDE_DIRS ${${_tpl}_INCLUDE_DIR} )
- elseif( ${TPL}_INCLUDE_DIRS )
- list( APPEND CONF_TPL_INCLUDE_DIRS ${${TPL}_INCLUDE_DIRS} )
- elseif( ${TPL}_INCLUDE_DIR )
- list( APPEND CONF_TPL_INCLUDE_DIRS ${${TPL}_INCLUDE_DIR} )
- endif()
- endforeach()
-
- set( _is_build_dir_export OFF )
- configure_file( "${_template_config}" "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${LNAME}-config.cmake" @ONLY )
- install( FILES "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${LNAME}-config.cmake" DESTINATION "${INSTALL_CMAKE_DIR}" )
-
- # install the export
-
- if( ${PROJECT_NAME}_ALL_EXES OR ${PROJECT_NAME}_ALL_LIBS )
- install( EXPORT ${CMAKE_PROJECT_NAME}-targets DESTINATION "${INSTALL_CMAKE_DIR}" )
- endif()
-
- else()
-
- set( ${PNAME}_FOUND TRUE PARENT_SCOPE )
- set( ${PROJECT_NAME}_FOUND TRUE PARENT_SCOPE )
- set( ${PNAME}_VERSION ${${PNAME}_VERSION} PARENT_SCOPE )
- set( ${PROJECT_NAME}_VERSION ${${PNAME}_VERSION} PARENT_SCOPE )
- set( ${PNAME}_INCLUDE_DIRS ${${PNAME}_INCLUDE_DIRS} PARENT_SCOPE )
- set( ${PNAME}_LIBRARIES ${${PNAME}_LIBRARIES} PARENT_SCOPE )
- set( ${PNAME}_DEFINITIONS ${${PNAME}_DEFINITIONS} PARENT_SCOPE )
- set( ${PNAME}_PACKAGES ${${PNAME}_PACKAGES} PARENT_SCOPE )
- set( ${PNAME}_TPLS ${${PNAME}_TPLS} PARENT_SCOPE )
- set( ${PNAME}_TPL_LIBRARIES ${${PNAME}_TPL_LIBRARIES} PARENT_SCOPE )
- set( ${PNAME}_TPL_DEFINITIONS ${${PNAME}_TPL_DEFINITIONS} PARENT_SCOPE )
- set( ${PNAME}_TPL_INCLUDE_DIRS ${${PNAME}_TPL_INCLUDE_DIRS} PARENT_SCOPE )
-
- endif()
-
-endmacro( ecbuild_install_project )
diff --git a/ecbuild/cmake/ecbuild_links_target.cmake b/ecbuild/cmake/ecbuild_links_target.cmake
deleted file mode 100644
index 5dfacdc..0000000
--- a/ecbuild/cmake/ecbuild_links_target.cmake
+++ /dev/null
@@ -1,74 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-############################################################################################
-# macro for adding a link to library on a development system
-
-set( EC_ALL_EXES "" CACHE INTERNAL "" )
-set( EC_ALL_LIBS "" CACHE INTERNAL "" )
-
-macro( ecbuild_link_exe TARGET FILENAME FILEPATH )
-
- if( DEFINED EC_LINK_DIR )
- add_custom_target(${TARGET}_link
- COMMAND ${CMAKE_COMMAND} -E make_directory ${EC_LINK_DIR}
- COMMAND ${CMAKE_COMMAND} -E make_directory ${EC_LINK_DIR}/bin
- COMMAND ${CMAKE_COMMAND} -E remove ${EC_LINK_DIR}/bin/${FILENAME}
- COMMAND ${CMAKE_COMMAND} -E create_symlink ${FILEPATH} ${EC_LINK_DIR}/bin/${FILENAME}
- DEPENDS ${TARGET}
- COMMENT "link ${EC_LINK_DIR}/bin/${FILENAME}" )
- endif()
-
- set( EC_ALL_EXES ${EC_ALL_EXES} ${TARGET} CACHE INTERNAL "" )
-
-endmacro( ecbuild_link_exe )
-
-###############################################################################
-# macro for adding a link to library on a development system
-
-macro( ecbuild_link_lib TARGET FILENAME FILEPATH )
-
- if( DEFINED EC_LINK_DIR )
- add_custom_target(${TARGET}_link
- COMMAND ${CMAKE_COMMAND} -E make_directory ${EC_LINK_DIR}
- COMMAND ${CMAKE_COMMAND} -E make_directory ${EC_LINK_DIR}/lib
- COMMAND ${CMAKE_COMMAND} -E remove ${EC_LINK_DIR}/lib/${FILENAME}
- COMMAND ${CMAKE_COMMAND} -E create_symlink ${FILEPATH} ${EC_LINK_DIR}/lib/${FILENAME}
- DEPENDS ${TARGET}
- COMMENT "link ${EC_LINK_DIR}/lib/${FILENAME}" )
- endif()
-
- set( EC_ALL_LIBS ${EC_ALL_LIBS} ${TARGET} CACHE INTERNAL "" )
-
-endmacro( ecbuild_link_lib )
-
-############################################################################################
-# define make links target
-
-macro( ecbuild_define_links_target )
-
- if( DEFINED EC_LINK_DIR )
-
- foreach( lib ${EC_ALL_LIBS} )
- list( APPEND ec_link_libs ${lib}_link )
- endforeach()
- foreach( exe ${EC_ALL_EXES} )
- list( APPEND ec_link_exes ${exe}_link )
- endforeach()
-
- add_custom_target( links DEPENDS ${ec_link_libs} ${ec_link_exes} )
-
- # debug_var( EC_ALL_EXES )
- # debug_var( ec_link_exes )
-
- # debug_var( EC_ALL_LIBS )
- # debug_var( ec_link_libs )
-
- endif()
-
-endmacro(ecbuild_define_links_target)
diff --git a/ecbuild/cmake/ecbuild_list_extra_search_paths.cmake b/ecbuild/cmake/ecbuild_list_extra_search_paths.cmake
deleted file mode 100644
index 7373486..0000000
--- a/ecbuild/cmake/ecbuild_list_extra_search_paths.cmake
+++ /dev/null
@@ -1,108 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-############################################################################################
-#
-# macro for adding search paths to CMAKE_PREFIX_PATH
-# for example the ECMWF /usr/local/apps paths
-#
-# usage: ecbuild_list_extra_search_paths( netcdf4 VARIABLE )
-
-function( ecbuild_list_extra_search_paths pkg var )
-
- # debug_var( pkg )
- # debug_var( var )
-
- string( TOUPPER ${pkg} _PKG )
-
- # PKG_PATH (upper case)
-
- if( DEFINED ${_PKG}_PATH AND EXISTS ${${_PKG}_PATH} )
- message( "${_PKG}_PATH ${${_PKG}_PATH} exists " )
- list( APPEND ${var} ${${_PKG}_PATH} )
- endif()
-
- # ENV PKG_PATH (upper case)
-
- if( DEFINED ENV{${_PKG}_PATH} AND EXISTS $ENV{${_PKG}_PATH} )
- list( APPEND ${var} $ENV{${_PKG}_PATH} )
- endif()
-
- # pkg_PATH (lower case)
-
- if( DEFINED ${pkg}_PATH AND EXISTS ${${pkg}_PATH} )
- list( APPEND ${var} ${${pkg}_PATH} )
- endif()
-
- # ENV pkg_PATH (lower case)
-
- if( DEFINED ${pkg}_PATH AND EXISTS ${${pkg}_PATH} )
- list( APPEND ${var} ${${pkg}_PATH} )
- endif()
-
- # ENV PKG_DIR (upper case)
-
- if( DEFINED ENV{${_PKG}_DIR} AND EXISTS $ENV{${_PKG}_DIR} )
- list( APPEND ${var} $ENV{${_PKG}_DIR} )
- endif()
-
- # ENV pkg_DIR (lower case)
-
- if( DEFINED ENV{${pkg}_DIR} AND EXISTS $ENV{${pkg}_DIR} )
- list( APPEND ${var} $ENV{${pkg}_DIR} )
- endif()
-
- # directories under /usr/local/apps/${pkg}
-
- if( SEARCH_ECMWF_PATHS )
-
- foreach( _apps /usr/local/apps/${pkg} /usr/local/lib/metaps/lib/${pkg} )
-
- if( EXISTS ${_apps} )
-
- file( GLOB ps ${_apps}/[0-9]* )
- list( SORT ps )
- list( REVERSE ps ) # reversing will give us the newest versions first
- foreach( p ${ps} )
- if( IS_DIRECTORY ${p} )
- list( APPEND ${var} ${p} )
- if( EXISTS ${p}/LP64 )
- list( APPEND ${var} ${p}/LP64 )
- endif()
- endif()
- endforeach()
-
- foreach( p ${_apps} ${_apps}/current ${_apps}/stable ${_apps}/new ${_apps}/next ${_apps}/prev )
- if( EXISTS ${p} )
- list( APPEND ${var} ${p} )
- endif()
- if( EXISTS ${p}/LP64 )
- list( APPEND ${var} ${p}/LP64 )
- endif()
- endforeach()
-
- endif()
-
- endforeach()
-
- endif( SEARCH_ECMWF_PATHS )
-
- # sanitize the list
-
- if( ${var} )
- list( REMOVE_DUPLICATES ${var} )
- endif()
-
- # define it out of the function
-
- set( ${var} ${${var}} PARENT_SCOPE )
-
-# debug_var( ${var} )
-
-endfunction()
-
diff --git a/ecbuild/cmake/ecbuild_list_macros.cmake b/ecbuild/cmake/ecbuild_list_macros.cmake
deleted file mode 100644
index 5c10dd2..0000000
--- a/ecbuild/cmake/ecbuild_list_macros.cmake
+++ /dev/null
@@ -1,57 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-##############################################################################
-# function for concatenating list into a string
-#
-# examples:
-#
-# set( _paths "foo" "bar" )
-# join( _paths "/" _mypath )
-#
-# message( "${_mpath}" ) # produces "foo/bar"
-
-function( JOIN _listname _glue _output )
-
- set( _ret "" )
-
- foreach( _v ${${_listname}} )
- if( _ret )
- set(_ret "${_ret}${_glue}${_v}") # append
- else()
- set(_ret "${_v}") # init
- endif()
- endforeach()
-
- set(${_output} "${_ret}" PARENT_SCOPE)
-
-endfunction()
-
-##############################################################################
-# function for inserting a key / value into a map
-#
-# examples:
-#
-# map_insert( "mymap" "foo" "bar" )
-#
-
-function( MAP_INSERT _map _key _value )
- set( "_${_map}_${_key}" "${_value}" PARENT_SCOPE )
-endfunction(MAP_INSERT)
-
-##############################################################################
-# function for inserting a key / value into a map
-#
-# examples:
-#
-# map_get( "mymap" "foo" VAR )
-#
-
-function( MAP_GET _map _key _var )
- set( ${_var} "${_${_map}_${_key}}" PARENT_SCOPE )
-endfunction(MAP_GET)
diff --git a/ecbuild/cmake/ecbuild_pkgconfig.cmake b/ecbuild/cmake/ecbuild_pkgconfig.cmake
deleted file mode 100644
index 8549d46..0000000
--- a/ecbuild/cmake/ecbuild_pkgconfig.cmake
+++ /dev/null
@@ -1,365 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-#############################################################################################
-#
-# MACRO ecbuild_pkgconfig
-#
-# This macro creates a pkg-config file for the current project
-#
-# It takes following optional arguments:
-#
-# - FILENAME <filename>
-# The file that will be generated. Default value is the lowercase
-# name of the project with suffix ".pc" is used
-#
-# - NAME <name>
-# The name to be given to the package. Default value is the lowercase
-# name of the project
-#
-# - TEMPLATE <template>
-# The template configuration file to use. This is useful to create more
-# custom pkg-config files. Default is ${ECBUILD_CMAKE_DIR}/pkg-config.pc.in
-#
-# - URL <url>
-# The url of the package. Default is ${UPPERCASE_PROJECT_NAME}_URL
-#
-# - DESCRIPTION <description>
-# The description of the package. Default is ${UPPERCASE_PROJECT_NAME}_DESCRIPTION
-#
-# - LIBRARIES <libraries>
-# The package libraries. Default is ${UPPERCASE_PROJECT_NAME}_LIBRARIES
-# This is e.g. of the form "eckit;eckit_geometry"
-#
-# - IGNORE_INCLUDE_DIRS <include_dirs>
-# Ignore specified include directories
-#
-# - IGNORE_LIBRARIES <libraries>
-# Ignore specified libraries
-#
-# - LANGUAGES <languages>
-# List of languages used. If none given, all CMake_<lang>_COMPILER_LOAED languages
-# are added. Accepted languages: C CXX Fortran
-#
-# - NO_PRIVATE_INCLUDE_DIRS
-# Don't add include dirs of dependencies to Cflags. This is mainly useful
-# for Fortran only packages, when only the modules need to be added to Cflags
-#
-#############################################################################################
-
-function( ecbuild_library_dependencies dependencies libraries )
-
- set( _libraries ${${libraries}} )
-
- foreach( _lib ${_libraries})
-
- unset( _location )
-
- if( TARGET ${_lib} ) # check if this is an existing target
-
- set( _imported 0 )
- get_property( _imported TARGET ${_lib} PROPERTY IMPORTED )
-
- unset( _deps )
-
- if( _imported )
-
- get_property( _location TARGET ${_lib} PROPERTY LOCATION )
- get_property( _configs TARGET ${_lib} PROPERTY IMPORTED_CONFIGURATIONS )
- list( REVERSE _configs )
- list( GET _configs 0 _config)
- get_property( _deps TARGET ${_lib} PROPERTY IMPORTED_LINK_INTERFACE_LIBRARIES_${_config} )
- get_property( _locimp TARGET ${_lib} PROPERTY IMPORTED_LOCATION_${_config} )
-
- else()
-
- list( APPEND _location ${_lib} )
- get_property( _deps TARGET ${_lib} PROPERTY LINK_LIBRARIES )
-
- endif()
-
- ecbuild_library_dependencies( _deps_location _deps )
- list( APPEND _location ${_deps_location} )
-
- else()
-
- set( _location ${_lib} )
-
- endif()
-
- list( APPEND _dependencies ${_location} )
-
- endforeach()
-
- if( _dependencies )
- list( REVERSE _dependencies )
- list( REMOVE_DUPLICATES _dependencies )
- list( REVERSE _dependencies )
- set( ${dependencies} ${_dependencies} PARENT_SCOPE )
- endif()
-
-endfunction(ecbuild_library_dependencies)
-
-#############################################################################################
-
-function( ecbuild_include_dependencies dependencies libraries )
-
- set( _libraries ${${libraries}} )
-
- foreach( _lib ${_libraries})
-
- if( TARGET ${_lib} ) # check if this is an existing target
-
- get_property( _include_dirs TARGET ${_lib} PROPERTY INCLUDE_DIRECTORIES )
- list( APPEND _dependencies ${_include_dirs} )
-
- endif()
-
- endforeach()
-
- if( _dependencies )
- list( REMOVE_DUPLICATES _dependencies )
- set( ${dependencies} ${_dependencies} PARENT_SCOPE )
- endif()
-
-endfunction(ecbuild_include_dependencies)
-
-#############################################################################################
-
-function( ecbuild_pkgconfig_libs pkgconfig_libs libraries ignore_libs )
-
- set( _libraries ${${libraries}} )
- set( _ignore_libs ${${ignore_libs}} )
-
- foreach( _lib ${_libraries} )
-
- unset( _name )
- unset( _dir )
-
- if( ${_lib} MATCHES ".+/Frameworks/.+" )
-
- get_filename_component( _name ${_lib} NAME_WE )
- list( APPEND _pkgconfig_libs "-framework ${_name}" )
-
- else()
-
- if( ${_lib} MATCHES "-l.+" )
-
- string( REGEX REPLACE "^-l" "" _name ${_lib} )
-
- else()
-
-
- get_filename_component( _name ${_lib} NAME_WE )
- get_filename_component( _dir ${_lib} PATH )
-
- if( NOT _name )
- set( _name ${_lib} )
- endif()
-
- string( REGEX REPLACE "^lib" "" _name ${_name} )
-
- if( "${_dir}" STREQUAL "/usr/lib" )
- unset( _dir )
- endif()
- if( "${_dir}" STREQUAL "/usr/lib64" )
- unset( _dir )
- endif()
-
- endif()
-
- set( _set_append TRUE )
- foreach( _ignore ${_ignore_libs} )
- if( "${_name}" STREQUAL "${_ignore}" )
- set( _set_append FALSE )
- endif()
- endforeach()
-
- if( _set_append )
-
- if( _dir )
- list( APPEND _pkgconfig_libs "-L${_dir}" "-l${_name}" )
- else()
- list( APPEND _pkgconfig_libs "-l${_name}" )
- endif()
-
- endif()
-
- endif( ${_lib} MATCHES ".+/Frameworks/.+" )
-
- endforeach( _lib ${_libraries} )
-
- if( _pkgconfig_libs )
- list( REMOVE_DUPLICATES _pkgconfig_libs )
- string( REPLACE ";" " " _pkgconfig_libs "${_pkgconfig_libs}" )
-
- set( ${pkgconfig_libs} ${_pkgconfig_libs} PARENT_SCOPE )
- endif()
-
-endfunction(ecbuild_pkgconfig_libs)
-
-
-#############################################################################################
-
-
-function( ecbuild_pkgconfig_include INCLUDE INCLUDE_DIRS ignore_includes )
-
- string( TOUPPER ${PROJECT_NAME} PNAME )
-
- set( _ignore_includes ${${ignore_includes}} )
-
- list( APPEND ignore_include_dirs
- "/usr/include"
- ${${PNAME}_INCLUDE_DIRS} # These are build-directory includes
- ${_ignore_includes}
- )
-
- foreach( _incdir ${${INCLUDE_DIRS}} )
-
- foreach( _ignore ${ignore_include_dirs} )
- if( "${_incdir}" STREQUAL "${_ignore}" )
- unset( _incdir )
- endif()
- endforeach()
-
- if( _incdir )
- list( APPEND _include "-I${_incdir}")
- endif()
-
- endforeach()
-
- if( _include )
- list( REMOVE_DUPLICATES _include)
- string( REPLACE ";" " " _include "${_include}")
- set( ${INCLUDE} ${_include} PARENT_SCOPE )
- endif()
-
-endfunction(ecbuild_pkgconfig_include)
-
-
-#############################################################################################
-
-function( ecbuild_pkgconfig )
-
- set( options REQUIRES NO_PRIVATE_INCLUDE_DIRS )
- set( single_value_args FILEPATH NAME TEMPLATE URL DESCRIPTION )
- set( multi_value_args LIBRARIES IGNORE_INCLUDE_DIRS IGNORE_LIBRARIES VARIABLES LANGUAGES )
-
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- string( TOUPPER ${PROJECT_NAME} PNAME )
- string( TOLOWER ${PROJECT_NAME} LNAME )
-
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_add_executable(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
-
- unset( PKGCONFIG_LANGUAGES )
- if( NOT _PAR_LANGUAGES )
- if( CMAKE_C_COMPILER_LOADED )
- list( APPEND PKGCONFIG_LANGUAGES C )
- endif()
- if( CMAKE_CXX_COMPILER_LOADED )
- list( APPEND PKGCONFIG_LANGUAGES CXX )
- endif()
- if( CMAKE_Fortran_COMPILER_LOADED )
- list( APPEND PKGCONFIG_LANGUAGES Fortran )
- endif()
- else()
- foreach( _lang ${_PAR_LANGUAGES} )
- if( CMAKE_${_lang}_COMPILER_LOADED )
- list( APPEND PKGCONFIG_LANGUAGES ${_lang} )
- endif()
- endforeach()
- endif()
-
- foreach( _lang ${PKGCONFIG_LANGUAGES} )
- set( PKGCONFIG_HAVE_${_lang} 1 )
- endforeach()
-
- set( LIBRARIES ${${PNAME}_LIBRARIES} )
- if( _PAR_LIBRARIES )
- set( LIBRARIES ${_PAR_LIBRARIES} )
- endif()
-
- if( CMAKE_CXX_COMPILER_LOADED )
- set( _linker_lang CXX )
- elseif( CMAKE_C_COMPILER_LOADED )
- set( _linker_lang C )
- elseif( CMAKE_Fortran_COMPILER_LOADED )
- set( _linker_lang Fortran )
- endif()
-
- set( RPATH_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_${_linker_lang}_FLAG} )
-
- set( PKGCONFIG_MOD_FLAG ${CMAKE_Fortran_MODPATH_FLAG} )
-
- if( NOT PKGCONFIG_MOD_FLAG )
- set( PKGCONFIG_MOD_FLAG "-I" )
- endif()
-
- ecbuild_pkgconfig_libs( PKGCONFIG_LIBS LIBRARIES _PAR_IGNORE_LIBRARIES )
-
- ecbuild_library_dependencies( _libraries LIBRARIES )
- foreach( _lib ${LIBRARIES} )
- list( REMOVE_ITEM _libraries ${_lib} )
- endforeach()
-
- ecbuild_pkgconfig_libs( PKGCONFIG_LIBS_PRIVATE _libraries _PAR_IGNORE_LIBRARIES )
-
- if( NOT _PAR_NO_PRIVATE_INCLUDE_DIRS )
- ecbuild_include_dependencies( _include_dirs LIBRARIES )
- ecbuild_pkgconfig_include( PKGCONFIG_CFLAGS _include_dirs _PAR_IGNORE_INCLUDE_DIRS )
- endif()
-
- set( PKGCONFIG_INCLUDE "-I\${includedir}" )
- if( PKGCONFIG_HAVE_Fortran )
- set( PKGCONFIG_INCLUDE "${PKGCONFIG_INCLUDE} ${PKGCONFIG_MOD_FLAG}\${fmoddir}" )
- endif()
-
- if( NOT _PAR_TEMPLATE )
- set( _PAR_TEMPLATE "${ECBUILD_MACROS_DIR}/pkg-config.pc.in" )
- endif()
-
- set( PKGCONFIG_NAME ${LNAME} )
- if( _PAR_NAME )
- set( PKGCONFIG_NAME ${_PAR_NAME} )
- endif()
-
- if( NOT _PAR_FILEPATH )
- set( _PAR_FILEPATH "${PKGCONFIG_NAME}.pc" )
- endif()
-
- set( PKGCONFIG_DESCRIPTION ${${PNAME}_DESCRIPTION} )
- if( _PAR_DESCRIPTION )
- set( PKGCONFIG_DESCRIPTION ${_PAR_DESCRIPTION} )
- endif()
-
- set( PKGCONFIG_URL ${${PNAME}_URL} )
- if( _PAR_URL )
- set( PKGCONFIG_URL ${_PAR_URL} )
- endif()
-
- set( PKGCONFIG_VERSION ${${PNAME}_VERSION} )
- set( PKGCONFIG_GIT_TAG ${${PNAME}_GIT_SHA1} ) # For now set it to a commit id
-
- if( _PAR_VARIABLES )
- set( PKGCONFIG_VARIABLES "\n### Features:\n\n")
- foreach( _var ${_PAR_VARIABLES} )
- set( PKGCONFIG_VARIABLES "${PKGCONFIG_VARIABLES}${_var}=${${_var}}\n" )
- endforeach()
- endif()
-
- configure_file( ${_PAR_TEMPLATE} "${CMAKE_BINARY_DIR}/${_PAR_FILEPATH}" @ONLY )
- message( STATUS "pkg-config file created: ${_PAR_FILEPATH}" )
-
- install( FILES ${CMAKE_BINARY_DIR}/${_PAR_FILEPATH}
- DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/pkgconfig/
- COMPONENT utilities )
-
-endfunction(ecbuild_pkgconfig)
diff --git a/ecbuild/cmake/ecbuild_print_summary.cmake b/ecbuild/cmake/ecbuild_print_summary.cmake
deleted file mode 100644
index 193bf1f..0000000
--- a/ecbuild/cmake/ecbuild_print_summary.cmake
+++ /dev/null
@@ -1,115 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-macro( ecbuild_print_summary )
-
- if( EXISTS ${PROJECT_SOURCE_DIR}/project_summary.cmake )
-
- message( STATUS "---------------------------------------------------------" )
- message( STATUS "Project ${PROJECT_NAME} summary" )
- message( STATUS "---------------------------------------------------------" )
-
- include( ${PROJECT_SOURCE_DIR}/project_summary.cmake )
-
- endif()
-
- if( PROJECT_NAME STREQUAL CMAKE_PROJECT_NAME )
-
- ecbuild_define_links_target()
-
- get_property( langs GLOBAL PROPERTY ENABLED_LANGUAGES )
-
- message( STATUS "---------------------------------------------------------" )
- if( NOT ${DEVELOPER_MODE} )
- message( STATUS "Build summary" )
- else()
- message( STATUS "Build summary -- ( DEVELOPER_MODE )" )
- endif()
- message( STATUS "---------------------------------------------------------" )
-
- message( STATUS "system : [${BUILD_SITE}] [${CMAKE_SYSTEM}] [${EC_OS_NAME}.${EC_OS_BITS}]" )
- message( STATUS "processor : [${CMAKE_SYSTEM_PROCESSOR}]" )
- if( EC_BIG_ENDIAN )
- message( STATUS "endiness : Big Endian -- IEEE [${IEEE_BE}]" )
- endif()
- if( EC_LITTLE_ENDIAN )
- message( STATUS "endiness : Little Endian -- IEEE [${IEEE_LE}]" )
- endif()
- message( STATUS "build type : [${CMAKE_BUILD_TYPE}]" )
- message( STATUS "timestamp : [${EC_BUILD_TIMESTAMP}]" )
- message( STATUS "install prefix : [${CMAKE_INSTALL_PREFIX}]" )
- if( EC_LINK_DIR )
- message( STATUS "links prefix : [${EC_LINK_DIR}]" )
- endif()
- message( STATUS "---------------------------------------------------------" )
-
- foreach( lang ${langs} )
- message( STATUS "${lang} -- ${CMAKE_${lang}_COMPILER_ID} ${CMAKE_${lang}_COMPILER_VERSION}" )
- message( STATUS " compiler : ${CMAKE_${lang}_COMPILER} ${CMAKE_${lang}_FLAGS} ${CMAKE_${lang}_FLAGS_${CMAKE_BUILD_TYPE_CAPS}}" )
- message( STATUS " link flags : ${CMAKE_${lang}_LINK_FLAGS}" )
- endforeach()
-
- message( STATUS "linker : ${CMAKE_LINKER}")
- message( STATUS "ar : ${CMAKE_AR}")
- message( STATUS "ranlib : ${CMAKE_RANLIB}")
- message( STATUS "link flags" )
- message( STATUS " executable [${CMAKE_EXE_LINKER_FLAGS} ${CMAKE_EXEC_LINKER_FLAGS_${CMAKE_BUILD_TYPE_CAPS}}]" )
- message( STATUS " shared lib [${CMAKE_SHARED_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS_${CMAKE_BUILD_TYPE_CAPS}}]" )
- message( STATUS " static lib [${CMAKE_MODULE_LINKER_FLAGS} ${CMAKE_MODULE_LINKER_FLAGS_${CMAKE_BUILD_TYPE_CAPS}}]" )
- message( STATUS "install rpath : ${CMAKE_INSTALL_RPATH}" )
-
- get_directory_property( defs COMPILE_DEFINITIONS )
-
- message( STATUS "common definitions: ${defs}" )
-
- message( STATUS "---------------------------------------------------------" )
-
- ### FEATURE SUMMARY
-
- # debug_var( CMAKE_VERSION )
- if( ${CMAKE_VERSION} VERSION_LESS "2.8.6" )
- feature_summary( WHAT ALL )
- else()
- feature_summary( WHAT ALL INCLUDE_QUIET_PACKAGES )
- endif()
-
- ### WARNINGS
-
- # issue warnings / errors in case there are unused project files
- ecbuild_warn_unused_files()
-
- # issue a warning that 'make install' mighty be broken for old cmakes
- if( ${CMAKE_VERSION} VERSION_LESS "2.8.3" )
-
- message( STATUS " +++ WARNING +++ WARNING +++ WARNING +++" )
- message( STATUS " +++ " )
- message( STATUS " +++ This CMake version [${CMAKE_VERSION}] is rather OLD !!" )
- message( STATUS " +++ " )
- message( STATUS " +++ We work hard to keep CMake backward compatibility (support >= 2.6.4)" )
- message( STATUS " +++ but there are some limits inherent to older versions." )
- message( STATUS " +++ " )
- message( STATUS " +++ You will be able to build the software... " )
- message( STATUS " +++ " )
- message( STATUS " +++ But: " )
- message( STATUS " +++ * the 'make install' target most likely will NOT WORK" )
- message( STATUS " +++ * if you want to install these binaries you might need to copy them by yourself" )
- message( STATUS " +++ * the binaries are in '${CMAKE_BINARY_DIR}' /lib and /bin" )
- message( STATUS " +++ * copying headers will take substantially more work, and you might end up copying files that won't be needed" )
- message( STATUS " +++ " )
- message( STATUS " +++ Therefore, we recommend that you: " )
- message( STATUS " +++ * upgrade to a newer CMake with version at least >= 2.8.3" )
- message( STATUS " +++ * remove this build directory '${CMAKE_BINARY_DIR}'" )
- message( STATUS " +++ * rerun a newer cmake on an new empty build directory" )
- message( STATUS " +++ " )
- message( STATUS " +++ WARNING +++ WARNING +++ WARNING +++" )
-
- endif()
-
- endif( PROJECT_NAME STREQUAL CMAKE_PROJECT_NAME )
-
-endmacro( ecbuild_print_summary )
diff --git a/ecbuild/cmake/ecbuild_project_files.cmake b/ecbuild/cmake/ecbuild_project_files.cmake
deleted file mode 100644
index f304772..0000000
--- a/ecbuild/cmake/ecbuild_project_files.cmake
+++ /dev/null
@@ -1,73 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-# resert the variable on each configure
-set( EC_UNUSED_FILES "" CACHE INTERNAL "unused files" )
-
-##############################################################################
-# finds project files and adds them to the passed variable
-
-macro( ecbuild_find_files_recursive aFileList )
-
-list( APPEND ecbuild_project_extensions c cc cpp cxx ) # for the moment skip ( h hh )
-
-# first find all the files in the directory
-foreach( aExt ${ecbuild_project_extensions} )
-
- file( GLOB_RECURSE listFilesWithExt *.${aExt})
-
- list( LENGTH listFilesWithExt sizeFilesWithExt )
- if( sizeFilesWithExt GREATER 0 )
- set( ${aFileList} ${${aFileList}} ${listFilesWithExt} )
- endif()
-
-endforeach()
-
-endmacro()
-
-##############################################################################
-# finds the unused files on all the project
-function( ecbuild_find_project_files )
-
- ecbuild_find_files_recursive( cwdFiles )
-
- # this list will be kept
- set( EC_PROJECT_FILES ${EC_PROJECT_FILES} ${cwdFiles} CACHE INTERNAL "" )
- # this list will be progressevely emptied
- set( EC_UNUSED_FILES ${EC_UNUSED_FILES} ${cwdFiles} CACHE INTERNAL "" )
-
-endfunction()
-
-##############################################################################
-# removed used files from unused list
-macro( ecbuild_declare_project_files )
-
- foreach( _afile ${ARGV} )
-
- # debug_var( _afile )
-
- get_property( _src_gen SOURCE ${_afile} PROPERTY GENERATED )
-
- if( NOT _src_gen )
-
- get_filename_component( _abspath ${_afile} ABSOLUTE )
-
- # check for existance of all declared files
- if( EXISTS ${_abspath} )
- list( REMOVE_ITEM EC_UNUSED_FILES ${_abspath} )
- else()
- message( FATAL_ERROR "In directory ${CMAKE_CURRENT_SOURCE_DIR} file ${_afile} was declared in CMakeLists.txt but not found" )
- endif()
- endif()
-
- endforeach()
-
- # rewrite the unused file list in cache
- set( EC_UNUSED_FILES ${EC_UNUSED_FILES} CACHE INTERNAL "unused files" )
-
-endmacro()
diff --git a/ecbuild/cmake/ecbuild_requires_macro_version.cmake b/ecbuild/cmake/ecbuild_requires_macro_version.cmake
deleted file mode 100644
index dbdcc05..0000000
--- a/ecbuild/cmake/ecbuild_requires_macro_version.cmake
+++ /dev/null
@@ -1,15 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-macro( ecbuild_requires_macro_version req_vrs )
-
- if( ECBUILD_MACRO_VERSION VERSION_LESS ${req_vrs} )
- message( FATAL_ERROR "${PROJECT_NAME} needs ecbuild macro version >= ${req_vrs}" )
- endif()
-
-endmacro()
diff --git a/ecbuild/cmake/ecbuild_separate_sources.cmake b/ecbuild/cmake/ecbuild_separate_sources.cmake
deleted file mode 100644
index 71d56b3..0000000
--- a/ecbuild/cmake/ecbuild_separate_sources.cmake
+++ /dev/null
@@ -1,63 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-##############################################################################
-# macro for separating sources sccording to language
-##############################################################################
-
-macro( ecbuild_separate_sources )
-
- set( options )
- set( single_value_args TARGET )
- set( multi_value_args SOURCES )
-
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_separate_sources(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
-
- if( NOT _PAR_TARGET )
- message(FATAL_ERROR "The call to ecbuild_separate_sources() doesn't specify the TARGET.")
- endif()
-
- if( NOT _PAR_SOURCES )
- message(FATAL_ERROR "The call to ecbuild_separate_sources() doesn't specify the SOURCES.")
- endif()
-
- foreach( src ${_PAR_SOURCES} )
- if(${src} MATCHES "(\\.h|\\.hxx|\\.hh|\\.hpp|\\.H)")
- list( APPEND ${_PAR_TARGET}_h_srcs ${src} )
- endif()
- endforeach()
-
- foreach( src ${_PAR_SOURCES} )
- if(${src} MATCHES "(\\.c)")
- list( APPEND ${_PAR_TARGET}_c_srcs ${src} )
- endif()
- endforeach()
-
- foreach( src ${_PAR_SOURCES} )
- if(${src} MATCHES "(\\.cc|\\.cxx|\\.cpp|\\.C)")
- list( APPEND ${_PAR_TARGET}_cxx_srcs ${src} )
- endif()
- endforeach()
-
- foreach( src ${_PAR_SOURCES} )
- if(${src} MATCHES "(\\.f|\\.F|\\.for|\\.f77|\\.f90|\\.f95)")
- list( APPEND ${_PAR_TARGET}_f_srcs ${src} )
- endif()
- endforeach()
-
-# debug_var( ${_PAR_TARGET}_h_srcs )
-# debug_var( ${_PAR_TARGET}_c_srcs )
-# debug_var( ${_PAR_TARGET}_cxx_srcs )
-# debug_var( ${_PAR_TARGET}_f_srcs )
-
-endmacro( ecbuild_separate_sources )
-
diff --git a/ecbuild/cmake/ecbuild_setup_test_framework.cmake b/ecbuild/cmake/ecbuild_setup_test_framework.cmake
deleted file mode 100644
index 86f026e..0000000
--- a/ecbuild/cmake/ecbuild_setup_test_framework.cmake
+++ /dev/null
@@ -1,42 +0,0 @@
-ecbuild_add_option( FEATURE TESTS
- DEFAULT ON
- DESCRIPTION "Enable the unit tests" )
-
-if( ENABLE_TESTS )
-
- # Try to find compiled boost
-
- if( BOOST_ROOT OR BOOSTROOT OR DEFINED ENV{BOOST_ROOT} OR DEFINED ENV{BOOSTROOT} )
- set( CMAKE_PREFIX_PATH ${BOOST_ROOT} ${BOOSTROOT} $ENV{BOOST_ROOT} $ENV{BOOSTROOT} ${CMAKE_PREFIX_PATH} )
- endif()
-
- ecbuild_add_extra_search_paths( boost ) # also respects BOOST_ROOT
-
- set( Boost_USE_MULTITHREADED ON )
-# set( Boost_DEBUG ON )
-
- find_package( Boost 1.47.0 COMPONENTS unit_test_framework )
-
- set( ECBUILD_BOOST_HEADER_DIRS "${CMAKE_CURRENT_LIST_DIR}/include" )
-
- if( Boost_FOUND AND Boost_UNIT_TEST_FRAMEWORK_LIBRARY )
-
- set( HAVE_BOOST_UNIT_TEST 1 )
- set( BOOST_UNIT_TEST_FRAMEWORK_LINKED 1 )
-
- # message( STATUS "Boost unit test framework -- FOUND [${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}]" )
-
- else()
-
- message( STATUS "Boost unit test framework -- NOT FOUND" )
-
- set( HAVE_BOOST_UNIT_TEST 0 )
-
- # set( BOOST_UNIT_TEST_FRAMEWORK_HEADER_ONLY 1 )
- # comment out this when ecbuild packs boost unit test inside...
- # list( APPEND ECBUILD_BOOST_HEADER_DIRS "${CMAKE_CURRENT_LIST_DIR}/contrib/boost-1.55/include" )
- # set( HAVE_BOOST_UNIT_TEST 1 )
-
- endif()
-
-endif()
diff --git a/ecbuild/cmake/ecbuild_system.cmake b/ecbuild/cmake/ecbuild_system.cmake
deleted file mode 100644
index 939d92e..0000000
--- a/ecbuild/cmake/ecbuild_system.cmake
+++ /dev/null
@@ -1,281 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-########################################################################################################
-# disallow in-source build
-
-if( EXISTS ${CMAKE_SOURCE_DIR}/CMakeCache.txt ) # check for failed attempts to build within the source tree
- message( FATAL_ERROR "Project ${PROJECT_NAME} contains a CMakeCache.txt inside source tree [${CMAKE_SOURCE_DIR}/CMakeCache.txt].\n Please remove it and
- make sure that source tree is prestine and clean of unintended files, before retrying." )
-endif()
-
-get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH)
-get_filename_component(bindir "${CMAKE_BINARY_DIR}" REALPATH)
-
-if(${srcdir} STREQUAL ${bindir})
- message("######################################################")
- message("You are attempting to build in your source directory (${srcdir}).")
- message("You must run cmake from a different build directory.")
- message("######################################################")
- message( FATAL_ERROR "${PROJECT_NAME} requires an out of source build.\n Please create a separate build directory and run 'cmake path/to/project [options]' from there.")
-endif()
-
-########################################################################################################
-# ecbuild versioning support
-
-set( ECBUILD_CMAKE_MINIMUM "2.8.4" )
-if( ${CMAKE_VERSION} VERSION_LESS ${ECBUILD_CMAKE_MINIMUM} )
- message(FATAL_ERROR "${PROJECT_NAME} requires at least CMake ${ECBUILD_CMAKE_MINIMUM} -- you are using ${CMAKE_COMMAND} [${CMAKE_VERSION}]\n Please, get a newer version of CMake @ www.cmake.org" )
-endif()
-
-set( ECBUILD_MACROS_DIR "${CMAKE_CURRENT_LIST_DIR}" CACHE INTERNAL "where ecbuild system is" )
-
-include( "${ECBUILD_MACROS_DIR}/VERSION.cmake" )
-
-set( ecbuild_VERSION_STR "${ECBUILD_VERSION_STR}" )
-
-########################################################################################################
-# define cmake policies
-
-# Included scripts don't automatic cmake_policy PUSH and POP
-
-if( POLICY CMP0011 )
- cmake_policy( SET CMP0011 OLD )
-endif()
-
-# Allow use of the LOCATION target property.
-
-if( POLICY CMP0026 )
- cmake_policy( SET CMP0026 OLD )
-endif()
-
-# for macosx use @rpath in a target’s install name
-
-if( POLICY CMP0042 )
- cmake_policy( SET CMP0042 NEW )
- set( CMAKE_MACOSX_RPATH ON )
-endif()
-
-# Error on non-existent target in get_target_property
-
-if( POLICY CMP0045 )
- cmake_policy( SET CMP0045 NEW )
-endif()
-
-# Error on non-existent target in get_target_property
-
-if( POLICY CMP0046 )
- cmake_policy( SET CMP0046 NEW )
-endif()
-
-# Error on non-existent dependency in add_dependencies
-
-if( POLICY CMP0046 )
- cmake_policy( SET CMP0050 NEW )
-endif()
-
-# Reject source and build dirs in installed INTERFACE_INCLUDE_DIRECTORIES
-
-if( POLICY CMP0052 )
- cmake_policy( SET CMP0052 NEW )
-endif()
-
-# inside if() don't dereference variables if they are quoted
-# e.g. "VAR" is not dereferenced
-# "${VAR}" is dereference only once
-
-if( POLICY CMP0054 )
- cmake_policy( SET CMP0054 NEW )
-endif()
-
-########################################################################################################
-# include our cmake macros, but only do so if this is the top project
-if( PROJECT_NAME STREQUAL CMAKE_PROJECT_NAME )
-
- # hostname of where we build
-
- site_name( BUILD_SITE )
- mark_as_advanced( BUILD_SITE )
- mark_as_advanced( BUILD_TESTING )
-
- set( ECBUILD_PROJECTS "" CACHE INTERNAL "list of ecbuild (sub)projects that use ecbuild" )
-
- message( STATUS "ecbuild ${ecbuild_VERSION_STR}\t${ECBUILD_MACROS_DIR}" )
- message( STATUS "cmake ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}\t${CMAKE_COMMAND}" )
-
- if( CMAKE_TOOLCHAIN_FILE )
- message( STATUS "toolchain ${CMAKE_TOOLCHAIN_FILE}" )
- endif()
-
- if( ECBUILD_CACHE )
- include( ${ECBUILD_CACHE} )
- message( STATUS "cache ${ECBUILD_CACHE}" )
- endif()
-
- message( STATUS "---------------------------------------------------------" )
-
- # clear the build dir exported targets file (only on the top project)
-
- set( TOP_PROJECT_TARGETS_FILE "${PROJECT_BINARY_DIR}/${CMAKE_PROJECT_NAME}-targets.cmake" CACHE INTERNAL "" )
- file( REMOVE ${TOP_PROJECT_TARGETS_FILE} )
-
- # add backport support for versions up too 2.8.4
- if( ${CMAKE_VERSION} VERSION_LESS "2.8" )
- set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/2.8" ${CMAKE_MODULE_PATH} )
- endif()
-
- # add extra macros from external contributions
- set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/contrib" )
-
- # would bring FindEigen in, so for the moment keep it out
- # set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/contrib/GreatCMakeCookOff" )
-
- include(CTest) # add cmake testing support
- enable_testing()
-
- # keep this until we modify the meaning to 'check' if installation worked
- add_custom_target( check COMMAND ${CMAKE_CTEST_COMMAND} -V )
-
- ############################################################################################
- # define valid build types
-
- include(ecbuild_define_build_types)
-
- ############################################################################################
- # add cmake macros
-
- include(AddFileDependencies)
-
- include(CheckTypeSize)
- include(CheckIncludeFile)
- include(CheckIncludeFiles)
-
- include(CheckFunctionExists)
- include(CheckSymbolExists)
-
- include(CheckCCompilerFlag)
- include(CheckCSourceCompiles)
- include(CheckCSourceRuns)
-
- include(CMakeParseArguments)
-
- # include(CMakePrintSystemInformation) # available in cmake 2.8.4
-
- if( CMAKE_CXX_COMPILER_LOADED )
- include(CheckIncludeFileCXX)
- include(CheckCXXCompilerFlag)
- include(CheckCXXSourceCompiles)
- include(CheckCXXSourceRuns)
- endif()
-
- if( CMAKE_Fortran_COMPILER_LOADED )
- set( CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/module CACHE PATH "directory for all fortran modules." )
- include(CheckFortranFunctionExists)
- if( CMAKE_C_COMPILER_LOADED AND ENABLE_FORTRAN_C_INTERFACE )
- include(FortranCInterface)
- endif()
- set( EC_HAVE_FORTRAN 1 )
- endif()
-
- include(FeatureSummary) # support features in cmake
-
- include(TestBigEndian)
-
- ############################################################################################
- # backport of cmake > 2.8.4 functions
-
- if( "${CMAKE_VERSION}" VERSION_LESS "2.8.6" )
- include( ${CMAKE_CURRENT_LIST_DIR}/2.8/CMakePushCheckState.cmake )
- else()
- include(CMakePushCheckState)
- endif()
-
- ############################################################################################
- # add our macros
-
- include( ecbuild_debug_var )
- include( ecbuild_list_macros )
-
- include( ecbuild_check_c_source )
-
- if( CMAKE_CXX_COMPILER_LOADED )
- include( ecbuild_check_cxx_source )
- include( ecbuild_check_cxx11 )
- endif()
-
- if( CMAKE_Fortran_COMPILER_LOADED )
- include( ecbuild_check_fortran_source )
- endif()
-
- include( ecbuild_requires_macro_version )
- include( ecbuild_get_date )
- include( ecbuild_add_persistent )
- include( ecbuild_generate_config_headers )
- include( ecbuild_generate_rpc )
- include( ecbuild_generate_yy )
- include( ecbuild_echo_targets )
- include( ecbuild_add_option )
- include( ecbuild_add_library )
- include( ecbuild_add_executable )
- include( ecbuild_append_to_rpath )
- include( ecbuild_get_test_data )
- include( ecbuild_add_cxx11_flags )
- include( ecbuild_add_test )
- include( ecbuild_add_resources )
- include( ecbuild_get_resources )
- include( ecbuild_project_files )
- include( ecbuild_declare_project )
- include( ecbuild_install_package )
- include( ecbuild_separate_sources )
- include( ecbuild_find_package )
- include( ecbuild_use_package )
- include( ecbuild_list_extra_search_paths )
- include( ecbuild_add_extra_search_paths )
- include( ecbuild_print_summary )
- include( ecbuild_warn_unused_files )
- include( ecbuild_find_mpi )
- include( ecbuild_find_omp )
- include( ecbuild_find_perl )
- include( ecbuild_find_python )
- include( ecbuild_find_lexyacc )
- include( ecbuild_find_fortranlibs )
- include( ecbuild_enable_fortran )
- include( ecbuild_check_c_source )
- include( ecbuild_check_cxx_source )
- include( ecbuild_check_fortran_source )
- include( ecbuild_bundle )
- include( ecbuild_pkgconfig )
- include( ecbuild_cache )
-
- include( ${CMAKE_CURRENT_LIST_DIR}/contrib/GetGitRevisionDescription.cmake )
-
- ############################################################################################
- # kickstart the build system
-
- ecbuild_prepare_cache()
- include( ecbuild_define_options ) # define build options
- include( ecbuild_check_compiler ) # check for compiler characteristics
- include( ecbuild_check_os ) # check for os characteristics
- include( ecbuild_check_functions ) # check for available functions
- include( ecbuild_define_paths ) # define installation paths
- include( ecbuild_links_target ) # define the links target
- include( ecbuild_setup_test_framework ) # setup test framework
- ecbuild_flush_cache()
-
- ############################################################################################
- # define the build timestamp
-
- if( NOT DEFINED EC_BUILD_TIMESTAMP )
- ecbuild_get_timestamp( EC_BUILD_TIMESTAMP )
- set( EC_BUILD_TIMESTAMP "${EC_BUILD_TIMESTAMP}" CACHE INTERNAL "Build timestamp" )
- endif()
-
- message( STATUS "---------------------------------------------------------" )
-
-endif()
-
diff --git a/ecbuild/cmake/ecbuild_use_package.cmake b/ecbuild/cmake/ecbuild_use_package.cmake
deleted file mode 100644
index 3d77384..0000000
--- a/ecbuild/cmake/ecbuild_use_package.cmake
+++ /dev/null
@@ -1,206 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-##############################################################################
-# function for adding a subproject directory
-##############################################################################
-
-macro( ecbuild_use_package )
-
- set( options REQUIRED QUIET EXACT )
- set( single_value_args PROJECT VERSION )
- set( multi_value_args )
-
- cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if(_p_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_use_package(): \"${_p_UNPARSED_ARGUMENTS}\"")
- endif()
-
- if( NOT _p_PROJECT )
- message(FATAL_ERROR "The call to ecbuild_use_package() doesn't specify the PROJECT.")
- endif()
-
- if( _p_EXACT AND NOT _p_VERSION )
- message(FATAL_ERROR "Call to ecbuild_use_package() requests EXACT but doesn't specify VERSION.")
- endif()
-
- # try to find the package as a subproject and build it
-
- string( TOUPPER ${_p_PROJECT} PNAME )
-
- # user defined dir with subprojects
-
- if( NOT DEFINED ${PNAME}_SOURCE AND DEFINED SUBPROJECT_DIRS )
- foreach( dir ${SUBPROJECT_DIRS} )
- if( EXISTS ${dir}/${_p_PROJECT} AND EXISTS ${dir}/${_p_PROJECT}/CMakeLists.txt )
- set( ${PNAME}_SOURCE "${dir}/${_p_PROJECT}" )
- endif()
- endforeach()
- endif()
-
- # user defined path to subproject
-
- if( DEFINED ${PNAME}_SOURCE )
-
- if( NOT EXISTS ${${PNAME}_SOURCE} OR NOT EXISTS ${${PNAME}_SOURCE}/CMakeLists.txt )
- message( FATAL_ERROR "User defined source directory '${${PNAME}_SOURCE}' for project '${_p_PROJECT}' does not exist or does not contain a CMakeLists.txt file." )
- endif()
-
- set( ${PNAME}_subproj_dir_ "${${PNAME}_SOURCE}" )
-
- else() # default is 'dropped in' subdirectory named as project
-
- if( EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${_p_PROJECT} AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${_p_PROJECT}/CMakeLists.txt )
- set( ${PNAME}_subproj_dir_ "${CMAKE_CURRENT_SOURCE_DIR}/${_p_PROJECT}" )
- endif()
-
- endif()
-
- # check if was already added as subproject ...
-
- set( _just_added 0 )
- set( _do_version_check 0 )
- set( _source_description "" )
-
- list( FIND ECBUILD_PROJECTS ${_p_PROJECT} _ecbuild_project_${PNAME} )
-
- if( NOT _ecbuild_project_${PNAME} EQUAL "-1" )
- set( ${PNAME}_previous_subproj_ 1 )
- else()
- set( ${PNAME}_previous_subproj_ 0 )
- endif()
-
- # solve capitalization issues
-
- if( ${_p_PROJECT}_FOUND AND NOT ${PNAME}_FOUND )
- set( ${PNAME}_FOUND 1 )
- endif()
- if( ${PNAME}_FOUND AND NOT ${_p_PROJECT}_FOUND )
- set( ${_p_PROJECT}_FOUND 1 )
- endif()
-
- # Case 1) project was NOT added as subproject and is NOT FOUND
-
- if( NOT ${PNAME}_FOUND AND NOT ${PNAME}_previous_subproj_ )
-
- # check if SUBPROJDIR is set
-
- if( DEFINED ${PNAME}_subproj_dir_ )
-
- # check version is acceptable
- set( _just_added 1 )
- set( _do_version_check 1 )
- set( _source_description "sub-project ${_p_PROJECT} (sources)" )
-
- # add as a subproject
-
- set( ${PNAME}_subproj_dir_ ${${PNAME}_subproj_dir_} CACHE PATH "Path to ${_p_PROJECT} source directory" )
-
- set( ECBUILD_PROJECTS ${ECBUILD_PROJECTS} ${_p_PROJECT} CACHE INTERNAL "" )
-
- add_subdirectory( ${${PNAME}_subproj_dir_} ${_p_PROJECT} )
-
- set( ${PNAME}_FOUND 1 )
- set( ${_p_PROJECT}_VERSION ${${PNAME}_VERSION} )
-
- endif()
-
- endif()
-
- # Case 2) project was already added as subproject, so is already FOUND -- BUT must check version acceptable
-
- if( ${PNAME}_previous_subproj_ )
-
- if( NOT ${PNAME}_FOUND )
- message( FATAL_ERROR "${_p_PROJECT} was already included as sub-project but ${PNAME}_FOUND isn't set -- this is likely a BUG in ecbuild" )
- endif()
-
- # check version is acceptable
- set( _do_version_check 1 )
- set( _source_description "already existing sub-project ${_p_PROJECT} (sources)" )
-
- endif()
-
- # Case 3) project was NOT added as subproject, but is FOUND -- so it was previously found as a binary ( either build or install tree )
-
- if( ${PNAME}_FOUND AND NOT ${PNAME}_previous_subproj_ AND NOT _just_added )
-
- # check version is acceptable
- set( _do_version_check 1 )
- set( _source_description "previously found package ${_p_PROJECT} (binaries)" )
-
- endif()
-
- # test version for Cases 1,2,3
-
-# debug_var( _p_PROJECT )
-# debug_var( _p_VERSION )
-# debug_var( ${PNAME}_VERSION )
-# debug_var( ${_p_PROJECT}_VERSION )
-# debug_var( _just_added )
-# debug_var( _do_version_check )
-# debug_var( _source_description )
-# debug_var( ${PNAME}_FOUND )
-# debug_var( ${PNAME}_previous_subproj_ )
-
- if( _p_VERSION AND _do_version_check )
- if( _p_EXACT )
- if( NOT ${_p_PROJECT}_VERSION VERSION_EQUAL _p_VERSION )
- message( FATAL_ERROR "${PROJECT_NAME} requires (exactly) ${_p_PROJECT} = ${_p_VERSION} -- detected as ${_source_description} ${${_p_PROJECT}_VERSION}" )
- endif()
- else()
- if( _p_VERSION VERSION_LESS ${_p_PROJECT}_VERSION OR _p_VERSION VERSION_EQUAL ${_p_PROJECT}_VERSION )
- message( STATUS "${PROJECT_NAME} requires ${_p_PROJECT} >= ${_p_VERSION} -- detected as ${_source_description} ${${_p_PROJECT}_VERSION}" )
- else()
- message( FATAL_ERROR "${PROJECT_NAME} requires ${_p_PROJECT} >= ${_p_VERSION} -- detected only ${_source_description} ${${_p_PROJECT}_VERSION}" )
- endif()
- endif()
- endif()
-
- # Case 4) is NOT FOUND so far, NOT as sub-project (now or before), and NOT as binary neither
- # so try to find precompiled binaries or a build tree
-
- if( NOT ${PNAME}_FOUND )
-
- set( _opts )
- if( _p_VERSION )
- list( APPEND _opts VERSION ${_p_VERSION} )
- endif()
- if( _p_EXACT )
- list( APPEND _opts EXACT )
- endif()
- if( _p_REQUIRED )
- list( APPEND _opts REQUIRED )
- endif()
-
- ecbuild_find_package( NAME ${_p_PROJECT} ${_opts} )
-
- if( ${_p_PROJECT}_FOUND )
-
- set( ${PNAME}_FOUND ${${_p_PROJECT}_FOUND} )
-
- message( STATUS "[${_p_PROJECT}] (${${_p_PROJECT}_VERSION})" )
-
- message( STATUS " ${PNAME}_INCLUDE_DIRS : [${${PNAME}_INCLUDE_DIRS}]" )
- if( ${PNAME}_DEFINITIONS )
- message( STATUS " ${PNAME}_DEFINITIONS : [${${PNAME}_DEFINITIONS}]" )
- endif()
- message( STATUS " ${PNAME}_LIBRARIES : [${${PNAME}_LIBRARIES}]" )
-
- endif()
-
- endif()
-
-### for when we change this macro to a function()
-# set_parent_scope( ${PNAME}_FOUND )
-# set_parent_scope( ${_p_PROJECT}_FOUND )
-# set_parent_scope( ${PNAME}_VERSION )
-# set_parent_scope( ${_p_PROJECT}_VERSION )
-
-endmacro()
diff --git a/ecbuild/cmake/ecbuild_version.h.in b/ecbuild/cmake/ecbuild_version.h.in
deleted file mode 100644
index d274bf6..0000000
--- a/ecbuild/cmake/ecbuild_version.h.in
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * (C) Copyright 1996-2014 ECMWF.
- *
- * This software is licensed under the terms of the Apache Licence Version 2.0
- * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
- * In applying this licence, ECMWF does not waive the privileges and immunities
- * granted to it by virtue of its status as an intergovernmental organisation nor
- * does it submit to any jurisdiction.
- */
-
-#ifndef ecbuild_version_h
-#define ecbuild_version_h
-
-#define ECBUILD_VERSION "@ECBUILD_VERSION@"
-
-#define ECBUILD_MAJOR_VERSION @ECBUILD_MAJOR_VERSION@
-#define ECBUILD_MINOR_VERSION @ECBUILD_MINOR_VERSION@
-#define ECBUILD_PATCH_VERSION @ECBUILD_PATCH_VERSION@
-
-#endif // ecbuild_version_h
diff --git a/ecbuild/cmake/ecbuild_warn_unused_files.cmake b/ecbuild/cmake/ecbuild_warn_unused_files.cmake
deleted file mode 100644
index c3aa7d5..0000000
--- a/ecbuild/cmake/ecbuild_warn_unused_files.cmake
+++ /dev/null
@@ -1,58 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-############################################################################################
-# print warnings about unused files
-
-macro( ecbuild_warn_unused_files )
-
- if( PROJECT_NAME STREQUAL CMAKE_PROJECT_NAME ) # only for top level project
-
- # if cache file with unused files exists remove it
- set( UNUSED_FILE "${CMAKE_BINARY_DIR}/UnusedFiles.txt" )
- if( EXISTS ${UNUSED_FILE} )
- file( REMOVE ${UNUSED_FILE} )
- endif()
-
- if( CHECK_UNUSED_FILES ) # to check or not to check...
-
- if( NOT DEFINED UNUSED_FILES_LEVEL ) # to err or not...
- set( UNUSED_FILES_LEVEL "ERROR" )
- endif()
-
- # if unused files where found, put the list on the file
- list( LENGTH MARS_UNUSED_FILES MARS_LENGTH_UNUSED_FILES )
- if( MARS_LENGTH_UNUSED_FILES )
-
- message( STATUS "")
- message( STATUS " !!!--- ${UNUSED_FILES_LEVEL} ---!!! ")
- message( STATUS " !!!--- ${UNUSED_FILES_LEVEL} ---!!! ")
- message( STATUS "")
- message( STATUS " Unused source files found:")
- foreach( AFILE ${MARS_UNUSED_FILES} )
- message( STATUS " ${AFILE}")
- file( APPEND ${UNUSED_FILE} "${AFILE}\n" )
- endforeach()
- message( STATUS "")
- message( STATUS " List dumped to ${UNUSED_FILE}")
- message( STATUS "")
- message( STATUS " !!!--- ${UNUSED_FILES_LEVEL} ---!!! ")
- message( STATUS " !!!--- ${UNUSED_FILES_LEVEL} ---!!! ")
- message( STATUS "")
-
- if( UNUSED_FILES_LEVEL STREQUAL "ERROR" )
- message( FATAL_ERROR "\n Aborted build system configuration. \n Add unused files to the build system or remove them." )
- endif()
-
- endif()
-
- endif()
-
- endif()
-
-endmacro( ecbuild_warn_unused_files )
diff --git a/ecbuild/cmake/include/ecbuild/boost_test_framework.h b/ecbuild/cmake/include/ecbuild/boost_test_framework.h
deleted file mode 100644
index 09e61dd..0000000
--- a/ecbuild/cmake/include/ecbuild/boost_test_framework.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * (C) Copyright 1996-2014 ECMWF.
- *
- * This software is licensed under the terms of the Apache Licence Version 2.0
- * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
- * In applying this licence, ECMWF does not waive the privileges and immunities
- * granted to it by virtue of its status as an intergovernmental organisation nor
- * does it submit to any jurisdiction.
- */
-
-#ifdef BOOST_UNIT_TEST_FRAMEWORK_HEADER_ONLY
-#include <boost/test/included/unit_test.hpp>
-#else
-#define BOOST_TEST_DYN_LINK
-#include <boost/test/unit_test.hpp>
-#endif
-
diff --git a/ecbuild/cmake/pkg-config.pc.in b/ecbuild/cmake/pkg-config.pc.in
deleted file mode 100644
index 86031db..0000000
--- a/ecbuild/cmake/pkg-config.pc.in
+++ /dev/null
@@ -1,35 +0,0 @@
-# This pkg-config file is generated by ecbuild_pkgconfig()
-# with template ecbuild/cmake/pkg-config.pc.in
-
-git_tag=@PKGCONFIG_GIT_TAG@
-
-prefix=@CMAKE_INSTALL_PREFIX@
-exec_prefix=${prefix}
-libdir=${prefix}/lib
-includedir=${prefix}/include
-bindir=${prefix}/bin
-fmoddir=${prefix}/include
-
-CC=@CMAKE_C_COMPILER@
-CXX=@CMAKE_CXX_COMPILER@
-FC=@CMAKE_Fortran_COMPILER@
-
-rpath=@RPATH_FLAG@${libdir}
-
-libs=-L${libdir} ${rpath} @PKGCONFIG_LIBS@
-
-libs_private=@PKGCONFIG_LIBS_PRIVATE@
-
-cflags=@PKGCONFIG_INCLUDE@ @PKGCONFIG_CFLAGS@
- at PKGCONFIG_VARIABLES@
-#====================================================================
-Name: @PKGCONFIG_NAME@
-Description: @PKGCONFIG_DESCRIPTION@
-URL: @PKGCONFIG_URL@
-Version: @PKGCONFIG_VERSION@
-Libs: ${libs}
-Libs.private: ${libs_private}
-Requires: @PKGCONFIG_REQUIRES@
-Requires.private: @PKGCONFIG_REQUIRES_PRIVATE@
-Cflags: ${cflags}
-#====================================================================
diff --git a/ecbuild/cmake/project-config.cmake.in b/ecbuild/cmake/project-config.cmake.in
deleted file mode 100644
index dbb936f..0000000
--- a/ecbuild/cmake/project-config.cmake.in
+++ /dev/null
@@ -1,80 +0,0 @@
-# Config file for the @PROJECT_NAME@ package
-# Defines the following variables:
-#
-# @PNAME at _INCLUDE_DIRS - include directories
-# @PNAME at _DEFINITIONS - preprocessor definitions
-# @PNAME at _LIBRARIES - libraries to link against
-# @PNAME at _FEATURES - list of enabled features
-# @PNAME at _VERSION - version of the package
-#
-# Also defines @PROJECT_NAME@ third-party library dependencies:
-# @PNAME at _TPLS - package names of third-party library dependencies
-# @PNAME at _TPL_INCLUDE_DIRS - include directories
-# @PNAME at _TPL_DEFINITIONS - preprocessor definitions
-# @PNAME at _TPL_LIBRARIES - libraries to link against
-
-### compute paths
-
-get_filename_component(@PNAME at _CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
-
-set( @PNAME at _SELF_INCLUDE_DIRS "@CONF_INCLUDE_DIRS@" )
-set( @PNAME at _SELF_DEFINITIONS "@CONF_DEFINITIONS@" )
-set( @PNAME at _SELF_LIBRARIES "@CONF_LIBRARIES@" )
-
-set( @PNAME at _TPLS "@CONF_TPLS@" )
-set( @PNAME at _TPL_INCLUDE_DIRS "@CONF_TPL_INCLUDE_DIRS@" )
-set( @PNAME at _TPL_DEFINITIONS "@CONF_TPL_DEFINITIONS@" )
-set( @PNAME at _TPL_LIBRARIES "@CONF_TPL_LIBRARIES@" )
-
-### export include paths as absolute paths
-
-set( @PNAME at _INCLUDE_DIRS "" )
-foreach( path ${@PNAME at _SELF_INCLUDE_DIRS} )
- get_filename_component( abspath ${path} ABSOLUTE )
- list( APPEND @PNAME at _INCLUDE_DIRS ${abspath} )
-endforeach()
-list( APPEND @PNAME at _INCLUDE_DIRS ${@PNAME at _TPL_INCLUDE_DIRS} )
-
-### export definitions
-
-set( @PNAME at _DEFINITIONS ${@PNAME at _SELF_DEFINITIONS} ${@PNAME at _TPL_DEFINITIONS} )
-
-### export list of all libraries
-
-set( @PNAME at _LIBRARIES ${@PNAME at _SELF_LIBRARIES} ${@PNAME at _TPL_LIBRARIES} )
-
-### export the features provided by the package
-
-set( @PNAME at _FEATURES "@CONF_FEATURES@" )
-foreach( _f ${@PNAME at _FEATURES} )
- set( ${_f} 1 )
-endforeach()
-
-if( EXISTS ${@PNAME at _CMAKE_DIR}/@CONF_IMPORT_FILE@ )
- set( @PNAME at _IMPORT_FILE "${@PNAME at _CMAKE_DIR}/@CONF_IMPORT_FILE@" )
- include( ${@PNAME at _IMPORT_FILE} )
-endif()
-
-# insert definitions for IMPORTED targets
-
-if( NOT @PROJECT_NAME at _BINARY_DIR )
-
- set( IS_BUILD_DIR_EXPORT @_is_build_dir_export@ )
-
- if( IS_BUILD_DIR_EXPORT )
- include( "@TOP_PROJECT_TARGETS_FILE@" OPTIONAL )
- else()
- include( "${@PNAME at _CMAKE_DIR}/@CMAKE_PROJECT_NAME at -targets.cmake" )
- endif()
-
-endif()
-
-# here goes the imports of the TPL's
-
-include( ${CMAKE_CURRENT_LIST_FILE}.tpls OPTIONAL )
-
-# publish this file as imported
-
-set( @PNAME at _IMPORT_FILE ${CMAKE_CURRENT_LIST_FILE} )
-mark_as_advanced( @PNAME at _IMPORT_FILE )
-
diff --git a/ecbuild/cmake/sg.pl b/ecbuild/cmake/sg.pl
deleted file mode 100755
index 455161b..0000000
--- a/ecbuild/cmake/sg.pl
+++ /dev/null
@@ -1,573 +0,0 @@
-#!/usr/bin/perl
-#!/usr/local/share/perl56
-
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-use strict;
-
-#use Data::Dumper;
-use File::Basename;
-
-#$Data::Dumper::Indent = 1;
-# $ARGV[0] = "test.cc";
-# $ARGV[0] = "/usr/include/g++-3/stl_pair.h";
-# $ARGV[0] = "/usr/include/g++-3/stl_vector.h";
-# $ARGV[0] = "/usr/include/g++-3/stl_list.h";
-# $ARGV[0] = "/usr/include/g++-3/stl_map.h";
-# $ARGV[0] = "x.cc";
-# $ARGV[0] = "/usr/include/g++-3/std/bastring.h";
-
-# script takes 3 parameters:
-# (1) file to process
-my $file = $ARGV[0];
-# (2) [optional] directory to place the generated .b file
-my $base = $ARGV[1];
-# (3) [optional] c++ namespace
-my $namespace = $ARGV[2];
-
-# no argv[1] passed, take basedir from file
-if( $base eq "" )
-{
- $base = dirname($file);
-}
-
-# no argv[1] passed, take basedir from file
-if( $namespace eq "" )
-{
- $namespace = "eclib"
-}
-
-my @c = parser::parse($file);
-#print Dumper(\@c);
-
-
-foreach my $c ( @c )
-{
- my $n = $c->name;
- open(STDOUT,">$base/$n.b") || die "$base/$n.b: $!";
-
- my @init1;
- push @init1, map { "$_(b)" } $c->super;
- push @init1, map { "$_(b(\&$_))" } $c->members;
-
- my $col1;
- $col1=":\n" if(@init1);
- my $init1 = join(",\n",map {"\t$_"} @init1);
-
- my @init2;
- push @init2, map { "$_(b(\"$n\"))" } $c->super;
- push @init2, map { "$_(b(\"$n\",\"$_\"))" } $c->members;
-
- my $col2;
- $col2=":\n" if(@init2);
- my $init2 = join(",\n",map {"\t$_"} @init2);
-
-
- my @s = map { "${_}::describe(s,depth+1)" } $c->super;
- my @m = map { "${namespace}::_describe(s,depth+1,\"$_\",$_)" } $c->members;
- my $d = join(";\n\t","${namespace}::_startClass(s,depth,specName())", at s, at m,"${namespace}::_endClass(s,depth,specName())");
-
- my @s = map { "${_}::_export(h)" } $c->super;
- my @m = map { "${namespace}::_export(h,\"$_\",$_)" } $c->members;
- my $D = join(";\n\t","${namespace}::_startClass(h,\"$n\")", at s, at m,"${namespace}::_endClass(h,\"$n\")");
-
- my $spec = "\"$n\"";
- my @tmpl = $c->template;
-
- my $spec_type = "const char*";
-
- if(@tmpl)
- {
- $spec_type = "std::string";
- my $x = join("+ ',' + ", map { "Traits<$_>::name()"; } @tmpl);
- $spec = <<"EOS";
- std::string("$n<\") + $x + ">"
-EOS
- $spec =~ s/\n/ /g;
- }
-
- my $isa = "${namespace}::Isa::add(t,specName());";
- foreach my $s ( $c->super )
- {
- $isa = "${s}::isa(t);$isa";
- }
-
- my $schema;
- @s = map { "${_}::schema(s)" } $c->super;
- @m = map { $a=$_->[0]; $b=$_->[1]; "s.member(\"$a\",member_size($n,$a),member_offset($n,$a),\"$b\")" } $c->members_types;
- $schema = join(";\n\t","s.start(specName(),sizeof($n))", at s, at m,"s.end(specName())");
-
- print <<"EOF";
-
-${n}(${namespace}::Bless& b)$col1$init1
-{
-}
-
-${n}(${namespace}::Evolve b)$col2$init2
-{
-}
-
-static ${spec_type} specName() { return ${spec}; }
-static void isa(TypeInfo* t) { ${isa} }
-static ${namespace}::Isa* isa() { return ${namespace}::Isa::get(specName()); }
-
-static void schema(${namespace}::Schema& s)
-{
- $schema;
-}
-
-EOF
-
-if(!$c->has_method("describe"))
-{
-print <<"EOF";
-
-void describe(std::ostream& s,int depth = 0) const {
- $d;
-}
-
-
-EOF
-}
-
-print <<"EOF";
-
-void _export(${namespace}::Exporter& h) const {
- $D;
-}
-
-
-EOF
-
-}
-if(0)
-{
-foreach my $c ( @c )
-{
- my $n = $c->name;
- open(OUT,">${n}.b");
- select OUT;
- print "static void schema(${namespace}::Schema& s) {\n";
- foreach my $x ( $c->super )
- {
- print "${x}::schema(s);\n";
- #print "s(\"$x\", 0,sizeof($x));\n";
- }
- foreach my $x ( $c->members )
- {
- print "s(\"${n}::$x\",offsetof($n,$x),sizeof(&(($n*)0)->$x));\n";
- }
- print "}\n";
-}
-}
-package parser;
-use Carp;
-my @TOKENS;
-sub parse {
- my ($file) = @_;
- local $/ = undef;
- open(IN,"<$file") || croak "$file: $!";
- my $x = <IN>;
- close(IN);
- $x =~ s/^#.*$//mg;
- $x =~ s/\/\/.*$//mg;
- @TOKENS =
- grep { length($_); }
- map { /\W/ ? split('',$_) : $_; }
- map { s/\s//g; $_; }
- split(/\b/, $x );
-
- my @c;
- my $x;
- while($x = consume_until("(typedef|template|class|struct)"))
- {
- if($x eq 'typedef')
- {
- consume_until(";");
- next;
- }
-
- if($x eq 'template')
- {
- push @c, parse_template();
- }
- else
- {
- push @c, parse_class();
- }
- }
- return grep { defined $_; } @c;
-}
-
-sub parse_template {
- my @tmp = template_args();
- return parse_class(@tmp) if(next_is("(class|struct)"));
-}
-sub template_args {
- my @tmp;
- expect_next("<");
- for(;;)
- {
- expect_next("(class|bool|int)");
- push @tmp, next_ident();
- if(next_is("="))
- {
- my $x = consume_until('(,|\>|\<)');
- unshift @TOKENS,$x;
- while($x eq '<')
- {
- consume_block('<','>');
- $x = consume_until('(,|\>|\<)');
- unshift @TOKENS,$x;
- }
- }
- last unless(next_is(","));
- }
- expect_next(">");
- return @tmp;
-}
-sub parse_class {
- my (@tmp) = @_;
- my $self = {};
- my $name = next_ident();
- $self->{name} = $name;
- $self->{template} = \@tmp if(@tmp);
- # Foreward declaration
- return if(next_is(";"));
- if(next_is(":"))
- {
- for(;;)
- {
- ignore_while("(public|private|protected|virtual)");
- push @{$self->{super}}, next_ident();
- last unless(next_is(","));
- }
- }
- expect_next('{');
- while(!peek_next('}'))
- {
- # print "... : $TOKENS[0], $TOKENS[1], ... \n";
- if(next_is('\/'))
- {
- if(next_is('\*'))
- {
- while(!next_is('\/'))
- {
- consume_until('\*');
- }
- next;
- }
- else
- {
- unshift @TOKENS, "/";
- }
-
- }
-
- if(next_is("(public|private|protected)"))
- {
- expect_next(":");
- next;
- }
-
- if(next_is("friend"))
- {
- my $x = consume_until("(;|{)");
- if($x eq "{")
- {
- unshift @TOKENS, $x;
- consume_block('{','}');
- }
- next;
- }
-
- # next_is("explicit");
- if(next_is("(typedef|using|typename|enum)"))
- {
- consume_until(";");
- next;
- }
- if(next_is("(class|struct)"))
- {
- push @{$self->{classes}}, parse_class();
- next;
- }
- my %m;
- while(next_is("template"))
- {
- push @{ $m{template} } , template_args();
- }
-
- my @x;
-# push @x,"~" while(next_is('\~'));
-
- $m{explicit} = 1 if(next_is("explicit"));
- $m{static} = 1 if(next_is("static"));
- $m{virtual} = 1 if(next_is("virtual"));
- my $x;
- while($x = next_is_ident())
- {
- # print "--- : $x\n";
- push @x, $x;
- push @x,'*' while(next_is('\*'));
- push @x,'&' while(next_is('\&'));
- $m{name} = $x;
- # int a,b,*c; does not work
- my $s;
- if($s = next_is('(,|;|=)'))
- {
- pop @x;
- $m{type} = make_type(@x);
- if(exists $m{static})
- {
- push @{$self->{class_members}}, \%m;
- }
- else
- {
- push @{$self->{members}}, \%m;
- }
- consume_until(";") if($s eq '=');
- last;
- }
- if(peek_next('\('))
- {
- pop @x;
- $m{type} = make_type(@x);
- my @args = consume_block('(',')');
- shift @args;
- pop @args;
- my @a;
- my $n = 0;
- my @z;
- foreach my $a ( @args )
- {
- if($a eq ',' && $n == 0)
- {
- push @a, make_type(@z);
- @z = ();
- next;
- }
- $n++ if($a eq '<');
- $n++ if($a eq '(');
- $n-- if($a eq ')');
- $n-- if($a eq '>');
- push @z,$a;
- }
- push @a, make_type(@z) if(@z);
- $m{const} = 1 if(next_is("const"));
- $m{args} = \@a;
- if(exists $m{static})
- {
- push @{$self->{class_methods}}, \%m;
- }
- else
- {
- push @{$self->{methods}}, \%m;
- }
- # print "f: $x\n";
-
- if(next_is(':'))
- {
- # print "{: $TOKENS[0]\n";
- consume_until('\{');
- unshift @TOKENS, '{';
- consume_block('{','}');
- # print "}: $TOKENS[0]\n";
- }
- else
- {
- if(peek_next('\{'))
- {
- consume_block('{','}');
- }
- else
- {
- if(next_is("="))
- {
- expect_next("0");
- $m{abstract} = 1;
- }
- expect_next(";");
- }
- }
- last;
- }
- }
-
- }
- expect_next("}");
- expect_next(";");
- return bless($self,"class");
-}
-sub consume_until {
- my ($r) = @_;
- while(@TOKENS)
- {
- my $x = shift @TOKENS;
- return $x if($x =~ /^$r$/);
- }
- return undef;
-}
-sub consume_block {
- my ($bra,$ket) = @_;
- my $n = 0;
- my @x;
- croak "@TOKENS" unless($bra eq $TOKENS[0]);
- while(@TOKENS)
- {
- my $x = shift @TOKENS;
- $n++ if($x eq $bra);
- $n-- if($x eq $ket);
- push @x,$x;
- return @x if($n == 0);
- }
-}
-sub ignore_while {
- my ($r) = @_;
- while(@TOKENS)
- {
- return unless($TOKENS[0] =~ /^$r$/);
- shift @TOKENS;
- }
-}
-sub expect_next {
- my ($r) = @_;
- my $ident = shift @TOKENS;
- croak "$ident is not $r" unless($ident =~ /^$r$/);
- return $ident;
-}
-sub next_ident {
- my $x = next_is_ident();
- croak "not an ident " unless($x);
- return $x;
-}
-sub next_is {
- my ($r) = @_;
- if($TOKENS[0] =~ /^$r$/)
- {
- return shift @TOKENS;
- }
- return undef;
-}
-sub next_is_ident {
- my $op = next_is("operator");
- if($op)
- {
- my $x;
- if($x = next_is("(new|delete)"))
- {
- $op .= " $x";
- if(next_is('\['))
- {
- expect_next('\]');
- $op .= "[]";
- }
- return $op;
- }
-
- if(next_is('\('))
- {
- expect_next('\)');
- $op .= "()";
- }
- my $z;
- while($z = next_is('[\-+/\*\[\]<>=!]'))
- {
- $op .= $z;
- }
- return $op;
- }
- my $y = next_is('\~');
- my $x = next_is('\w+');
- if($x)
- {
- $x = "$y$x";
- if(peek_next("<"))
- {
- my @x = consume_block("<",">");
- $x .= join("", at x);
- }
-
- if(next_is(":"))
- {
- if(next_is(":"))
- {
- my $z = next_is_ident();
- return "${x}::${z}";
- }
- else
- {
- unshift @TOKENS, ":";
- }
- }
- }
- return $x;
-}
-sub peek_next {
- my ($r) = @_;
- if($TOKENS[0] =~ /^$r$/)
- {
- return 1;
- }
- return 0;
-}
-sub make_type {
- my (@a) = @_;
- my $p;
- my @x;
- foreach my $a ( @a )
- {
- push @x, " " if($p =~ /^(\w+|\&|\*)$/ && $a =~ /^\w+$/);
- push @x, $a;
- $p = $a;
- }
- my $s = join('', at x);
- $s =~ s/>>/> >/g;
- return $s;
-}
-package class;
-sub name {
- my ($self) = @_;
- return $self->{name};
-}
-sub super {
- my ($self) = @_;
- return $self->{super} ? @{$self->{super}} : ();
-}
-
-sub members {
- my ($self) = @_;
- my @x = $self->{members} ? @{$self->{members}} : ();
- return map { $_->{name} } @x;
-}
-
-sub methods {
- my ($self) = @_;
- my @x = $self->{methods} ? @{$self->{methods}} : ();
- return map { $_->{name} } @x;
-}
-
-sub has_method {
- my ($self,$name) = @_;
- return grep { $_ eq $name } $self->methods;
-}
-
-sub members_types {
- my ($self) = @_;
- my @x = $self->{members} ? @{$self->{members}} : ();
- return map { [ $_->{name}, $_->{type} ] } @x;
-}
-
-sub template {
- my ($self) = @_;
- return $self->{template} ? @{$self->{template}} : ();
-}
-1;
-
-
diff --git a/ecbuild/examples/cpp/bar/CMakeLists.txt b/ecbuild/examples/cpp/bar/CMakeLists.txt
deleted file mode 100644
index 9c65fc3..0000000
--- a/ecbuild/examples/cpp/bar/CMakeLists.txt
+++ /dev/null
@@ -1,60 +0,0 @@
-###############################################################################
-# cmake
-# options:
-# -DCMAKE_BUILD_TYPE=Debug|RelWithDebInfo|Release|Production
-# -DCMAKE_INSTALL_PREFIX=/path/to/install
-#
-# -DCMAKE_C_COMPILER=gcc
-# -DCMAKE_CXX_COMPILER=g++
-#
-# -DCMAKE_MODULE_PATH=/path/to/ecbase/cmake
-# -DCMAKE_PREFIX_PATH=/path/to/jasper:/path/to/any/package/out/of/place
-
-cmake_minimum_required( VERSION 2.6.4 FATAL_ERROR )
-
-project( bar )
-
-set( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH} )
-
-include( ecmwf_build_system )
-
-###############################################################################
-# local project
-
-ecmwf_declare_project()
-
-###############################################################################
-# some variables/options of this project
-
-###############################################################################
-# find extra packages
-
-###############################################################################
-# contents
-
-ecmwf_add_subproject( foo ON )
-
-ecmwf_add_library( TARGET bar
- INCLUDES ${FOO_INCLUDE_DIRS}
- LIBS ${FOO_LIBRARIES}
- SOURCES bar.h bar.c )
-
-ecmwf_add_executable( TARGET master_bar
- SOURCES main.cc
- LIBS bar )
-
-ecmwf_add_test( TARGET test_bar
- SOURCES test.cc
- LIBS bar )
-
-############################################################################################
-# installation
-
-ecmwf_install_project( NAME Bar )
-
-###############################################################################
-# summary
-
-# print the summary of the configuration
-include( ecmwf_print_summary )
-
diff --git a/ecbuild/examples/cpp/bar/VERSION.cmake b/ecbuild/examples/cpp/bar/VERSION.cmake
deleted file mode 100644
index e0959dc..0000000
--- a/ecbuild/examples/cpp/bar/VERSION.cmake
+++ /dev/null
@@ -1 +0,0 @@
-set( ${PROJECT_NAME}_VERSION_STR "1.0.0" )
diff --git a/ecbuild/examples/cpp/bar/bar.c b/ecbuild/examples/cpp/bar/bar.c
deleted file mode 100644
index 8e617da..0000000
--- a/ecbuild/examples/cpp/bar/bar.c
+++ /dev/null
@@ -1,6 +0,0 @@
-#include "foo.h"
-
-int bar()
-{
- return foo() * foo();
-}
\ No newline at end of file
diff --git a/ecbuild/examples/cpp/bar/bar.h b/ecbuild/examples/cpp/bar/bar.h
deleted file mode 100644
index bcffbba..0000000
--- a/ecbuild/examples/cpp/bar/bar.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef bar_h
-#define bar_h
-
-int bar();
-
-#endif
\ No newline at end of file
diff --git a/ecbuild/examples/cpp/bar/main.cc b/ecbuild/examples/cpp/bar/main.cc
deleted file mode 100644
index 5c22c41..0000000
--- a/ecbuild/examples/cpp/bar/main.cc
+++ /dev/null
@@ -1,10 +0,0 @@
-#include <iostream>
-
-extern "C" {
-#include "bar.h"
-}
-
-int main()
-{
- std::cout << "bar is " << bar() << std::endl;
-}
diff --git a/ecbuild/examples/cpp/bar/test.cc b/ecbuild/examples/cpp/bar/test.cc
deleted file mode 100644
index 10cb14b..0000000
--- a/ecbuild/examples/cpp/bar/test.cc
+++ /dev/null
@@ -1,13 +0,0 @@
-#include <iostream>
-
-extern "C" {
-#include "bar.h"
-}
-
-int main()
-{
- if( bar() == 42*42)
- std::cout << "ok" << std::endl;
- else
- std::cout << "failed" << std::endl;
-}
\ No newline at end of file
diff --git a/ecbuild/examples/cpp/boost-python-lib/CMakeLists.txt b/ecbuild/examples/cpp/boost-python-lib/CMakeLists.txt
deleted file mode 100644
index 95475bb..0000000
--- a/ecbuild/examples/cpp/boost-python-lib/CMakeLists.txt
+++ /dev/null
@@ -1,60 +0,0 @@
-
-cmake_minimum_required( VERSION 2.8.4 FATAL_ERROR )
-
-project( mypython CXX )
-
-set( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH} )
-
-include( ecbuild_system )
-
-ecbuild_declare_project()
-
-###############################################################################
-# find extra packages
-
-# Python
-# Can specify non-default distribution with CMake variable PYTHON_EXECUTABLE
-ecbuild_find_python()
-message( STATUS "PYTHON_EXECUTABLE : ${PYTHON_EXECUTABLE}")
-message( STATUS "PYTHON_INCLUDE_DIRS : ${PYTHON_INCLUDE_DIRS}")
-message( STATUS "PYTHON_LIBRARIES : ${PYTHON_LIBRARIES}")
-
-# Boost
-# Can specify non-default distribution with CMake variable BOOST_ROOT
-ecbuild_add_extra_search_paths( boost )
-set( Boost_MINIMUM_VERSION "1.47" )
-find_package( Boost ${Boost_MINIMUM_VERSION} REQUIRED
- COMPONENTS python )
-message( STATUS "Boost_LIBRARIES : ${Boost_LIBRARIES}" )
-
-###############################################################################
-# Contents
-
-ecbuild_add_library( TARGET mypython
- INCLUDES ${Boost_INCLUDE_DIR} ${PYTHON_INCLUDE_DIRS}
- LIBS ${Boost_LIBRARIES} ${PYTHON_LIBRARIES}
- SOURCES pythonlib.hpp pythonlib.cpp )
-configure_file( mypython.py ${CMAKE_BINARY_DIR}/lib COPYONLY )
-
-############################################################################################
-# Installation
-
-ecbuild_install_project( NAME python_project )
-
-###############################################################################
-# Summary
-
-ecbuild_print_summary()
-
-
-
-message( STATUS "" )
-message( STATUS "To test the library:" )
-message( STATUS "--------------------" )
-message( STATUS "make" )
-message( STATUS "cd ${CMAKE_CURRENT_BINARY_DIR}/lib" )
-message( STATUS "python" )
-message( STATUS ">>> import libmypython" )
-message( STATUS ">>> help(libmypython)" )
-message( STATUS "" )
-message( STATUS "---------------------------------------------------------" )
\ No newline at end of file
diff --git a/ecbuild/examples/cpp/boost-python-lib/mypython.py b/ecbuild/examples/cpp/boost-python-lib/mypython.py
deleted file mode 100644
index d6f6a1b..0000000
--- a/ecbuild/examples/cpp/boost-python-lib/mypython.py
+++ /dev/null
@@ -1,10 +0,0 @@
-"""
-API for the C++ module using boost::python
-
-mypython.py:
- This file can be used to do some python actions at import
-
-Module description:
- ...
-"""
-from libmypython import *
\ No newline at end of file
diff --git a/ecbuild/examples/cpp/boost-python-lib/pythonlib.cpp b/ecbuild/examples/cpp/boost-python-lib/pythonlib.cpp
deleted file mode 100644
index ba32ffb..0000000
--- a/ecbuild/examples/cpp/boost-python-lib/pythonlib.cpp
+++ /dev/null
@@ -1,6 +0,0 @@
-#include "pythonlib.hpp"
-
-BOOST_PYTHON_MODULE(libmypython)
-{
- boost::python::scope().attr("__doc__") = "Python API for my python project";
-}
diff --git a/ecbuild/examples/cpp/boost-python-lib/pythonlib.hpp b/ecbuild/examples/cpp/boost-python-lib/pythonlib.hpp
deleted file mode 100644
index 349d581..0000000
--- a/ecbuild/examples/cpp/boost-python-lib/pythonlib.hpp
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef pythonlib_hpp
-#define pythonlib_hpp
-
-#include <boost/python.hpp>
-
-#endif
\ No newline at end of file
diff --git a/ecbuild/examples/cpp/foo/CMakeLists.txt b/ecbuild/examples/cpp/foo/CMakeLists.txt
deleted file mode 100644
index c4080d2..0000000
--- a/ecbuild/examples/cpp/foo/CMakeLists.txt
+++ /dev/null
@@ -1,62 +0,0 @@
-###############################################################################
-# cmake
-# options:
-# -DCMAKE_BUILD_TYPE=Debug|RelWithDebInfo|Release|Production
-# -DCMAKE_INSTALL_PREFIX=/path/to/install
-#
-# -DCMAKE_C_COMPILER=gcc
-# -DCMAKE_CXX_COMPILER=g++
-#
-# -DCMAKE_MODULE_PATH=/path/to/ecbase/cmake
-# -DCMAKE_PREFIX_PATH=/path/to/jasper:/path/to/any/package/out/of/place
-
-cmake_minimum_required( VERSION 2.6.4 FATAL_ERROR )
-
-project( foo )
-
-set( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH} )
-
-include( ecmwf_build_system )
-
-###############################################################################
-# local project
-
-ecmwf_declare_project()
-
-###############################################################################
-# some variables/options of this project
-
-###############################################################################
-# find extra packages
-
-###############################################################################
-# contents
-
-ecmwf_add_library( TARGET foo
- SOURCES foo.h foo.c )
-
-ecmwf_add_executable( TARGET master_foo
- SOURCES main.cc
- LIBS foo )
-
-ecmwf_add_test( TARGET test_foo
- SOURCES test.cc
- LIBS foo )
-
-if( NOT PROJECT_NAME STREQUAL CMAKE_PROJECT_NAME )
- set( FOO_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} PARENT_SCOPE )
- set( FOO_LIBRARIES foo PARENT_SCOPE )
- set( FOO_FOUND TRUE PARENT_SCOPE )
-endif()
-
-############################################################################################
-# installation
-
-ecmwf_install_project( NAME Foo )
-
-###############################################################################
-# summary
-
-# print the summary of the configuration
-include( ecmwf_print_summary )
-
diff --git a/ecbuild/examples/cpp/foo/VERSION.cmake b/ecbuild/examples/cpp/foo/VERSION.cmake
deleted file mode 100644
index e0959dc..0000000
--- a/ecbuild/examples/cpp/foo/VERSION.cmake
+++ /dev/null
@@ -1 +0,0 @@
-set( ${PROJECT_NAME}_VERSION_STR "1.0.0" )
diff --git a/ecbuild/examples/cpp/foo/foo.c b/ecbuild/examples/cpp/foo/foo.c
deleted file mode 100644
index 88adcb5..0000000
--- a/ecbuild/examples/cpp/foo/foo.c
+++ /dev/null
@@ -1,4 +0,0 @@
-int foo()
-{
- return 42;
-}
\ No newline at end of file
diff --git a/ecbuild/examples/cpp/foo/foo.h b/ecbuild/examples/cpp/foo/foo.h
deleted file mode 100644
index 6b68dbb..0000000
--- a/ecbuild/examples/cpp/foo/foo.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef foo_h
-#define foo_h
-
-int foo();
-
-#endif
\ No newline at end of file
diff --git a/ecbuild/examples/cpp/foo/main.cc b/ecbuild/examples/cpp/foo/main.cc
deleted file mode 100644
index aec42da..0000000
--- a/ecbuild/examples/cpp/foo/main.cc
+++ /dev/null
@@ -1,10 +0,0 @@
-#include <iostream>
-
-extern "C" {
-#include "foo.h"
-}
-
-int main()
-{
- std::cout << "foo is " << foo() << std::endl;
-}
diff --git a/ecbuild/examples/cpp/foo/test.cc b/ecbuild/examples/cpp/foo/test.cc
deleted file mode 100644
index 946404d..0000000
--- a/ecbuild/examples/cpp/foo/test.cc
+++ /dev/null
@@ -1,13 +0,0 @@
-#include <iostream>
-
-extern "C" {
-#include "foo.h"
-}
-
-int main()
-{
- if( foo() == 42)
- std::cout << "ok" << std::endl;
- else
- std::cout << "failed" << std::endl;
-}
\ No newline at end of file
diff --git a/ecbuild/examples/fortran/CMakeLists.txt b/ecbuild/examples/fortran/CMakeLists.txt
deleted file mode 100644
index 91aeb75..0000000
--- a/ecbuild/examples/fortran/CMakeLists.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-cmake_minimum_required( VERSION 2.6.4 FATAL_ERROR )
-
-project( compute_circle Fortran )
-
-############################################################
-
-add_library( const STATIC constants.f90 )
-
-############################################################
-
-# file( GLOB area_srcs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*circle.f90" )
-
-add_library( area_circle SHARED ${area_srcs} )
-
-target_link_libraries( area_circle const )
-
-############################################################
-
-add_executable( compute_circle main.F90 )
-
-target_link_libraries( compute_circle area_circle )
\ No newline at end of file
diff --git a/ecbuild/examples/fortran/area_circle.f90 b/ecbuild/examples/fortran/area_circle.f90
deleted file mode 100644
index 744d6dc..0000000
--- a/ecbuild/examples/fortran/area_circle.f90
+++ /dev/null
@@ -1,15 +0,0 @@
-!-----Area_Circle----------------------------------------------------
-!
-! Function to compute the area of a circle of given radius
-!
-!---------------------------------------------------------------------
-FUNCTION Area_Circle(r)
-USE Circle, ONLY : Pi
-
-IMPLICIT NONE
-REAL :: Area_Circle
-REAL, INTENT(IN) :: r
-
-Area_Circle = Pi * r * r
-
-END FUNCTION Area_Circle
\ No newline at end of file
diff --git a/ecbuild/examples/fortran/area_circle.h b/ecbuild/examples/fortran/area_circle.h
deleted file mode 100644
index 0c43fac..0000000
--- a/ecbuild/examples/fortran/area_circle.h
+++ /dev/null
@@ -1,5 +0,0 @@
-INTERFACE
- FUNCTION Area_Circle (r)
- REAL, INTENT(IN) :: r
- END FUNCTION Area_Circle
-END INTERFACE
\ No newline at end of file
diff --git a/ecbuild/examples/fortran/circle.f90 b/ecbuild/examples/fortran/circle.f90
deleted file mode 100644
index 6069beb..0000000
--- a/ecbuild/examples/fortran/circle.f90
+++ /dev/null
@@ -1,11 +0,0 @@
-MODULE Circle
-USE Constants, ONLY : ZOOM
-!---------------------------------------------------------------------
-!
-! Module containing definitions of variables needed to
-! compute the area of a circle of radius r
-!
-!---------------------------------------------------------------------
- REAL, PARAMETER :: Pi = 3.1415927 * ZOOM
- REAL :: radius
-END MODULE Circle
\ No newline at end of file
diff --git a/ecbuild/examples/fortran/constants.f90 b/ecbuild/examples/fortran/constants.f90
deleted file mode 100644
index 857f752..0000000
--- a/ecbuild/examples/fortran/constants.f90
+++ /dev/null
@@ -1,12 +0,0 @@
-MODULE Constants
-!---------------------------------------------------------------------
-!
-! Module containing definitions of variables needed to
-! compute the area of a circle of radius r
-!
-!---------------------------------------------------------------------
- REAL, PARAMETER :: ZOOM = 1
-END MODULE Constants
-
-
-
diff --git a/ecbuild/examples/fortran/lolo_circle.f90 b/ecbuild/examples/fortran/lolo_circle.f90
deleted file mode 100644
index e69de29..0000000
diff --git a/ecbuild/examples/fortran/main.F90 b/ecbuild/examples/fortran/main.F90
deleted file mode 100644
index b84ead6..0000000
--- a/ecbuild/examples/fortran/main.F90
+++ /dev/null
@@ -1,25 +0,0 @@
-PROGRAM Area
-!---------------------------------------------------------------------
-!
-! This program computes the area of a circle given the input radius
-!
-! Uses: MODULE Circle
-! FUNCTION Area_Circle (r)
-!
-!---------------------------------------------------------------------
-
-USE Circle, ONLY : radius
-IMPLICIT NONE
-
-#include "area_circle.h"
-
-! Prompt user for radius of circle
-write(*, '(A)', ADVANCE = "NO") "Enter the radius of the circle: "
-read(*,*) radius
-
-! Write out area of circle using function call
-write(*,100) "Area of circle with radius", radius, " is", &
- Area_Circle(radius)
-100 format (A, 2x, F6.2, A, 2x, F11.2)
-
-END PROGRAM Area
\ No newline at end of file
diff --git a/ecbuild/project_summary.cmake b/ecbuild/project_summary.cmake
deleted file mode 100644
index 851ebf0..0000000
--- a/ecbuild/project_summary.cmake
+++ /dev/null
@@ -1,21 +0,0 @@
-message( STATUS "---------------------------------------------------------" )
-
-message( STATUS "[Generic]" )
-
-if( PERL_EXECUTABLE )
- message( STATUS " Perl : [${PERL_EXECUTABLE}] (${PERL_VERSION})" )
-endif()
-
-if(PYTHONINTERP_FOUND)
- message( STATUS " Python : [${PYTHON_EXECUTABLE}] (${PYTHON_VERSION})" )
-endif()
-
-if(PYTHONLIBS_FOUND)
- message( STATUS " Python include : [${PYTHON_INCLUDE_DIRS}]" )
- message( STATUS " libs : [${PYTHON_LIBRARIES}]" )
-endif()
-
-if( DEFINED FORTRAN_LIBRARIES )
- message( STATUS "Fortan libs : [${FORTRAN_LIBRARIES}]" )
-endif()
-
diff --git a/ecbuild/share/CMakeLists.txt b/ecbuild/share/CMakeLists.txt
deleted file mode 100644
index 84590fc..0000000
--- a/ecbuild/share/CMakeLists.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-# ecbuild_add_resources( TARGET ecbuild_share
-# SOURCE_PACK ecmwf_license_header.txt
-# DONT_PACK_DIRS ecbuild )
diff --git a/ecbuild/share/ecbuild/cmake b/ecbuild/share/ecbuild/cmake
deleted file mode 120000
index 745c85c..0000000
--- a/ecbuild/share/ecbuild/cmake
+++ /dev/null
@@ -1 +0,0 @@
-../../cmake
\ No newline at end of file
diff --git a/ecbuild/share/ecbuild/toolchains/ecmwf-XC30-Cray.cmake b/ecbuild/share/ecbuild/toolchains/ecmwf-XC30-Cray.cmake
deleted file mode 100644
index a633d5d..0000000
--- a/ecbuild/share/ecbuild/toolchains/ecmwf-XC30-Cray.cmake
+++ /dev/null
@@ -1,63 +0,0 @@
-####################################################################
-# COMPILER
-####################################################################
-
-include(CMakeForceCompiler)
-
-CMAKE_FORCE_C_COMPILER ( cc Cray )
-CMAKE_FORCE_CXX_COMPILER ( CC Cray )
-CMAKE_FORCE_Fortran_COMPILER ( ftn Cray )
-
-link_libraries("$ENV{CC_X86_64}/lib/x86-64/libcray-c++-rts.so")
-link_libraries("-lmpichf90_cray")
-link_libraries("-lmpichcxx_cray")
-
-set( ECBUILD_FIND_MPI OFF )
-set( ECBUILD_TRUST_FLAGS ON )
-
-####################################################################
-# FLAGS COMMON TO ALL BUILD TYPES
-####################################################################
-
-set( CMAKE_C_FLAGS_INIT "-lhugetlbfs" )
-set( CMAKE_CXX_FLAGS_INIT "-lhugetlbfs" )
-set( CMAKE_Fortran_FLAGS_INIT "-lhugetlbfs -emf -rmoid" )
-
-set( OMP_C_FLAGS "-homp" )
-set( OMP_CXX_FLAGS "-homp" )
-set( OMP_Fortran_FLAGS "-homp" )
-set( OMPSTUBS_C_FLAGS "-hnoomp" )
-set( OMPSTUBS_CXX_FLAGS "-hnoomp" )
-set( OMPSTUBS_Fortran_FLAGS "-hnoomp" )
-
-####################################################################
-# BIT REPRODUCIBLE FLAGS
-####################################################################
-
-set( CMAKE_C_FLAGS_BIT "-O2 -hflex_mp=conservative -hadd_paren -hfp1" )
-set( CMAKE_CXX_FLAGS_BIT "-O2 -hflex_mp=conservative -hadd_paren -hfp1" )
-set( CMAKE_Fortran_FLAGS_BIT "-O2 -hflex_mp=conservative -hadd_paren -hfp1" )
-
-####################################################################
-# RELEASE FLAGS
-####################################################################
-
-set( CMAKE_C_FLAGS_RELEASE "-O3 -hfp3 -hscalar3 -hvector3" )
-set( CMAKE_CXX_FLAGS_RELEASE "-O3 -hfp3 -hscalar3 -hvector3" )
-set( CMAKE_Fortran_FLAGS_RELEASE "-O3 -hfp3 -hscalar3 -hvector3" )
-
-####################################################################
-# DEBUG FLAGS
-####################################################################
-
-set( CMAKE_C_FLAGS_DEBUG "-O0 -Gfast -Ktrap=fp" )
-set( CMAKE_CXX_FLAGS_DEBUG "-O0 -Gfast -Ktrap=fp" )
-set( CMAKE_Fortran_FLAGS_DEBUG "-O0 -Gfast -Ktrap=fp" )
-
-####################################################################
-# LINK FLAGS
-####################################################################
-
-set( CMAKE_C_LINK_FLAGS "-Wl,-Map,loadmap -Wl,--as-needed" )
-set( CMAKE_CXX_LINK_FLAGS "-Wl,-Map,loadmap -Wl,--as-needed" )
-set( CMAKE_Fortran_LINK_FLAGS "-Wl,-Map,loadmap -Wl,--as-needed" )
diff --git a/ecbuild/share/ecmwf_license_header.txt b/ecbuild/share/ecmwf_license_header.txt
deleted file mode 100644
index 373e38a..0000000
--- a/ecbuild/share/ecmwf_license_header.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
- * (C) Copyright 1996-2014 ECMWF.
- *
- * This software is licensed under the terms of the Apache Licence Version 2.0
- * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. In applying
- * this licence, ECMWF does not waive the privileges and immunities granted to it by virtue
- * of its status as an intergovernmental organisation nor does it submit to any jurisdiction.
- */
diff --git a/ecflow_4_0_7/.gitignore b/ecflow_4_0_7/.gitignore
deleted file mode 100644
index ad6fc56..0000000
--- a/ecflow_4_0_7/.gitignore
+++ /dev/null
@@ -1,39 +0,0 @@
-# eclipse
-.settings/
-.pydevproject
-
-# cmake
-ecbuild/
-
-# ecflow
-bin/
-swap
-*.job0
-*.job1
-*.job2
-*.job3
-*.1
-*.dat
-*.def_log
-*.glog
-*.def.glog
-
-# hack to ignore naw.def.glog
-**/naw.def.glog
-
-*.lock
-*.log
-*.so
-*.pyc
-
-ECF_HOME_debug/
-ECF_HOME_release/
-
-gmon.out
-
-*.check
-*.b
-/eurydice.3141.ecf.check
-/eurydice.3141.ecf.log
-/eurydice.3141.ecf.check.b
-/gnuplot.script
diff --git a/ecflow_4_0_7/ACore/CMakeLists.txt b/ecflow_4_0_7/ACore/CMakeLists.txt
deleted file mode 100644
index 55c2d00..0000000
--- a/ecflow_4_0_7/ACore/CMakeLists.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-# Note:
-# If new src or test is added make sure you touch this file
-#
-
-# We place generated file in /ACore/src/ so that we can still use boost build
-configure_file( ecflow_version.h.in ${CMAKE_SOURCE_DIR}/ACore/src/ecflow_version.h )
-
-# Use transitive nature: i.e if any lib/exe uses lib core, they
-# will also inherit the boost libs.
-#
-file( GLOB srcs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp" )
-ecbuild_add_library( TARGET core
- NOINSTALL
- TYPE STATIC
- SOURCES ${srcs}
- INCLUDES src
- ${Boost_INCLUDE_DIRS}
- )
-
-# This ensures that for debug config, we only link with debug boost libs, for other configs, we link with optimised boost libs
-target_link_libraries(core debug ${Boost_SERIALIZATION_LIBRARY_DEBUG} ${Boost_SERIALIZATION_LIBRARY_RELEASE}
- debug ${Boost_SYSTEM_LIBRARY_DEBUG} ${Boost_SYSTEM_LIBRARY_RELEASE}
- debug ${Boost_FILESYSTEM_LIBRARY_DEBUG} ${Boost_FILESYSTEM_LIBRARY_RELEASE}
- debug ${Boost_DATE_TIME_LIBRARY_DEBUG} ${Boost_DATE_TIME_LIBRARY_RELEASE})
-
-#
-# By use'ing BOOST tag we indicate this test should link with boost test libs
-#
-file( GLOB test_srcs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "test/*.cpp" )
-ecbuild_add_test( TARGET u_acore
- BOOST
- SOURCES ${test_srcs}
- LIBS core
- )
diff --git a/ecflow_4_0_7/ACore/Jamfile.jam b/ecflow_4_0_7/ACore/Jamfile.jam
deleted file mode 100755
index b4df86f..0000000
--- a/ecflow_4_0_7/ACore/Jamfile.jam
+++ /dev/null
@@ -1,46 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-#
-# Core project. define project so that this project can be referenced
-# from other projects
-#
-project theCore ;
-
-# The <include> means we will automatically add this directory to the include path
-# of any other target that uses this lib.
-#
-# <use> does not mean dependency, it simply used to control the link order
-# in our case, we want all the boost libraries to appears after the core library
-# on the link line.
-#
-lib core : [ glob src/*.cpp ]
- : <link>static
- <variant>debug:<define>DEBUG
- <use>/site-config//boost_system
- <use>/site-config//boost_filesystem
- <use>/site-config//boost_test
- <use>/site-config//boost_serialization
- <use>/site-config//boost_datetime
- <use>/site-config//boost_program_options
- :
- : <include>../ACore/src
- ;
-
-#
-# boost_datetime is only required for formatting. i.e to call to_simple_string
-# cerr << to_simple_string(calendar.suiteTime()) << "\n";
-#
-exe u_acore : [ glob test/*.cpp ]
- core
- /site-config//boost_system
- /site-config//boost_filesystem
- /site-config//boost_serialization
- /site-config//boost_datetime
- /site-config//boost_test
- : <variant>debug:<define>DEBUG
- ;
diff --git a/ecflow_4_0_7/ACore/doc/File_r.cpp_old b/ecflow_4_0_7/ACore/doc/File_r.cpp_old
deleted file mode 100644
index ac2f1bb..0000000
--- a/ecflow_4_0_7/ACore/doc/File_r.cpp_old
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-File_r::File_r(const std::string& file_name) : file_name_(file_name),
- fp_( fopen(file_name.c_str(),"r") ),
- good_(true)
-{
-}
-
-File_r::~File_r()
-{
- fclose(fp_);
-}
-
-bool File_r::ok() const
-{
- if (fp_ == 0) return false;
- return true;
-}
-
-bool File_r::good() const
-{
- if (fp_ == 0) return false;
- return good_;
-}
-
-void File_r::getline(std::string& line)
-{
- line.erase();
- char buffer[4096] = { 0 } ;
- int c = 0;
- int i = 0;
- while ( (c = fgetc(fp_)) != EOF) {
- if (c == 10 /* new line */) {
- buffer[i] = '\0';
- break;
- }
- else {
- buffer[i] = c;
- }
- i++;
- }
- if (c == EOF) {
- good_ = false;
- }
- line = buffer;
-}
-
-}
diff --git a/ecflow_4_0_7/ACore/doc/StackTrace.cpp_old b/ecflow_4_0_7/ACore/doc/StackTrace.cpp_old
deleted file mode 100644
index fd2f79d..0000000
--- a/ecflow_4_0_7/ACore/doc/StackTrace.cpp_old
+++ /dev/null
@@ -1,107 +0,0 @@
-////============================================================================
-//// Name :
-//// Author : Avi
-//// Revision : $Revision: #7 $
-////
-//// Copyright 2009-2012 ECMWF.
-//// This software is licensed under the terms of the Apache Licence version 2.0
-//// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-//// In applying this licence, ECMWF does not waive the privileges and immunities
-//// granted to it by virtue of its status as an intergovernmental organisation
-//// nor does it submit to any jurisdiction.
-////
-//// Description :
-////============================================================================
-//
-//#include "StackTrace.hpp"
-//#include <sstream>
-//#include <iostream>
-//
-//#if defined(__GNUC__)
-//#include <execinfo.h>
-//#include <cxxabi.h>
-//#endif
-//
-////#define DEBUG_ME 1
-//
-//using namespace std;
-//
-//namespace ecf {
-//
-//std::string DeMangleCXXName( const std::string &stackString )
-//{
-//#ifdef DEBUG_ME
-// std::cout <<"DeMangleCXXName stackString " << stackString << "\n";
-//#endif
-// size_t start = stackString.find( '(' );
-// size_t end = stackString.find( '+' );
-// if( std::string::npos == start || std::string::npos == end ) return stackString;
-//
-// ++start; // puts us pass the '('
-// size_t n = end - start;
-// std::string mangled = stackString.substr( start, n );
-//
-// const size_t kMaxNameLen = 4096;
-// char function[kMaxNameLen];
-// int status;
-// size_t len;
-// char *ret = abi::__cxa_demangle( mangled.c_str(), function, &len, &status );
-// if (ret && ( 0 == status )) {// de-mangling successful
-// // status is set to one of the following values:
-// // 0: The de mangling operation succeeded.
-// // -1: A memory allocation failure occurred.
-// // -2: mangled_name is not a valid name under the C++ ABI mangling rules.
-// // -3: One of the arguments is invalid.
-//
-// // Can return the variable string(ret) or std::string( function )
-// // std::cout << ret << "\n";
-//
-// return std::string( function );
-// }
-//
-// // If de-mangling fails, returned mangled name with some parens
-// return mangled + "()";
-//}
-//
-//std::string StackTrace::dump( const std::string &file, int line, int depth )
-//{
-//#if defined(__GNUC__)
-//// This is not well-optimised, requires compilation with "-rdynamic" on linux
-//// and doesn't do a great job of demangling the symbol names. It is sufficient
-//// though to work out call trace.
-//
-//#ifdef DEBUG_ME
-// std::cout <<"MyStackTrace \n";
-//#endif
-//
-// std::stringstream result;
-// result << "Call Stack from " << file << Str::COLON() << line << "\n";
-//
-// // create a void* array to hold the function addresses. We will only go at most 50 deep
-// const size_t kMaxDepth = depth;
-// void *stackAddrs[kMaxDepth];
-// size_t stackDepth = backtrace( stackAddrs, kMaxDepth );
-//
-// // now get the function names associated with these symbols. This should work for elf
-// // binaries, though additional linker options may need to have been called
-// // (e.g. -rdynamic for GNU ld. See the glibc documentation for 'backtrace')
-// char** stackStrings = backtrace_symbols( stackAddrs, stackDepth );
-//
-//#ifdef DEBUG_ME
-// std::cout <<" MyStackTrace 6 \n";
-//#endif
-//
-// for( size_t i = 1; i < stackDepth; ++i ) {
-// result << " " << DeMangleCXXName( stackStrings[i] ) << "\n";
-// }
-//
-// // we now need to release the memory of the symbols array. Since it was allocated using
-// // malloc, we must release it using 'free'
-// std::free( stackStrings );
-// return result.str();
-//#else
-// return "Back trace no supported on this platform";
-//#endif
-//}
-//}
-//
diff --git a/ecflow_4_0_7/ACore/doc/StackTrace.hpp_old b/ecflow_4_0_7/ACore/doc/StackTrace.hpp_old
deleted file mode 100644
index ed720a7..0000000
--- a/ecflow_4_0_7/ACore/doc/StackTrace.hpp_old
+++ /dev/null
@@ -1,37 +0,0 @@
-//#ifndef STACKTRACE_HPP_
-//#define STACKTRACE_HPP_
-//
-////============================================================================
-//// Name :
-//// Author : Avi
-//// Revision : $Revision: #5 $
-////
-//// Copyright 2009-2012 ECMWF.
-//// This software is licensed under the terms of the Apache Licence version 2.0
-//// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-//// In applying this licence, ECMWF does not waive the privileges and immunities
-//// granted to it by virtue of its status as an intergovernmental organisation
-//// nor does it submit to any jurisdiction.
-////
-//// Description : This class is used dump the a stack trace at the point where its called
-//// At the moment only works on Linux
-////============================================================================
-//
-//#include <boost/noncopyable.hpp>
-//#include <string>
-//
-//namespace ecf {
-//
-//class StackTrace : private boost::noncopyable {
-//public:
-//
-// /// This function will produce a stack trace from where its called
-// static std::string dump( const std::string &file, int line, int depth = 50 );
-//
-//private:
-// StackTrace(){}
-//};
-//
-//}
-//
-//#endif
diff --git a/ecflow_4_0_7/ACore/fred.o b/ecflow_4_0_7/ACore/fred.o
deleted file mode 100644
index 6ad2818..0000000
Binary files a/ecflow_4_0_7/ACore/fred.o and /dev/null differ
diff --git a/ecflow_4_0_7/ACore/src/Archive.hpp b/ecflow_4_0_7/ACore/src/Archive.hpp
deleted file mode 100644
index 7059823..0000000
--- a/ecflow_4_0_7/ACore/src/Archive.hpp
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef ARCHIVE_HPP_
-#define ARCHIVE_HPP_
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #11 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <boost/noncopyable.hpp>
-
-namespace ecf {
-
-// This class allows multiple archives to be used
-// Since it will allow Archive::Type to be passed as a parameter, when multiple archives exist
-class Archive : private boost::noncopyable {
-public:
-
- enum Type {
- TEXT = 0,
- PORTABLE_BINARY = 1,
- BINARY = 2,
- EOS_PORTABLE_BINARY = 3
- };
-
- static Type default_archive() {
-
-#if defined(BINARY_ARCHIVE)
- return BINARY;
-#endif
-
-#if defined(PORTABLE_BINARY_ARCHIVE)
- return PORTABLE_BINARY;
-#endif
-
-#if defined(EOS_PORTABLE_BINARY_ARCHIVE)
- return EOS_PORTABLE_BINARY;
-#endif
-
- return TEXT;
- }
-
-private:
- Archive();
-};
-
-}
-#endif
diff --git a/ecflow_4_0_7/ACore/src/ArgvCreator.cpp b/ecflow_4_0_7/ACore/src/ArgvCreator.cpp
deleted file mode 100644
index e44bc73..0000000
--- a/ecflow_4_0_7/ACore/src/ArgvCreator.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "ArgvCreator.hpp"
-#include <sstream>
-#include <assert.h>
-#include <cstdlib> // for malloc/free and gcc 4.4.3, not required for gcc 4.2.1
-#include <cstring> // for strcpy and gcc 4.4.3, not required for gcc 4.2.1
-using namespace std;
-
-ArgvCreator::ArgvCreator( const std::vector<std::string>& theArgs)
-{
- // Create a Argv array
- argc_ = theArgs.size();
- argv_ = (char **) malloc ((argc_ + 1) * sizeof (char *));
-
- assert(argv_ != NULL);
-
- for(size_t i = 0; i < theArgs.size(); i++) {
- argv_[i] = (char*) malloc (sizeof (char *) * (theArgs[i].size() + 1)); // allow +1 for \0
- strcpy (argv_[i], theArgs[i].c_str() );
- }
- argv_[argc_] = NULL;
-}
-
-// Destroys argv array
-ArgvCreator::~ArgvCreator()
-{
- // remove argv array
- for (char** scan = argv_; *scan != NULL; scan++) { free (*scan);}
- free (argv_);
-}
-
-std::string ArgvCreator::toString() const
-{
- std::stringstream ss;
- for(int i=0; i < argc_; i++) { ss << " arg" << i << ":('" << argv_[i] << "')";}
- return ss.str();
-}
-
diff --git a/ecflow_4_0_7/ACore/src/ArgvCreator.hpp b/ecflow_4_0_7/ACore/src/ArgvCreator.hpp
deleted file mode 100644
index b5b5a83..0000000
--- a/ecflow_4_0_7/ACore/src/ArgvCreator.hpp
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef ARGVCREATOR_HPP_
-#define ARGVCREATOR_HPP_
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <boost/noncopyable.hpp>
-#include <vector>
-#include <string>
-
-class ArgvCreator : private boost::noncopyable {
-public:
- // Create argc/argv from a vector of strings
- ArgvCreator(const std::vector<std::string> & );
-
- // Destroys argv array
- ~ArgvCreator();
-
- int argc() const { return argc_;}
- char** argv() const { return argv_;}
-
- // for debug
- std::string toString() const;
-
-private:
- int argc_;
- char** argv_;
-};
-
-#endif
diff --git a/ecflow_4_0_7/ACore/src/AssertTimer.cpp b/ecflow_4_0_7/ACore/src/AssertTimer.cpp
deleted file mode 100644
index 4019c10..0000000
--- a/ecflow_4_0_7/ACore/src/AssertTimer.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-#
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Simple class the assert when time constraint not met
-//============================================================================
-#include "AssertTimer.hpp"
-#include "Log.hpp"
-#include <iostream>
-
-namespace ecf {
-
-AssertTimer::~AssertTimer()
-{
- if (doAssert_ && timeConstraint_ > 0) {
- int d = duration();
- if (d >= timeConstraint_) {
- std::cout << "AssertTimer::~AssertTimer() duration(" << d << ") >= timeConstraint(" << timeConstraint_ << ")\n";
- }
- LOG_ASSERT( d < timeConstraint_, "AssertTimer::~AssertTimer()");
- }
-}
-}
diff --git a/ecflow_4_0_7/ACore/src/AssertTimer.hpp b/ecflow_4_0_7/ACore/src/AssertTimer.hpp
deleted file mode 100644
index e777a65..0000000
--- a/ecflow_4_0_7/ACore/src/AssertTimer.hpp
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef ASSERTTIMER_HPP_
-#define ASSERTTIMER_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Simple class the assert when time constraint not met
-//============================================================================
-#include "Calendar.hpp"
-
-
-namespace ecf {
-
-// Local timer class used to ensure, job submission takes less than 60 seconds
-class AssertTimer {
-public:
- AssertTimer(int t, bool doAssert = true)
- : timeConstraint_(t), doAssert_(doAssert), start_time_(Calendar::second_clock_time()) {}
- ~AssertTimer();
-
- int timeConstraint() const { return timeConstraint_;}
-
- int duration() const {
- boost::posix_time::time_duration duration = Calendar::second_clock_time() - start_time_;
- return duration.total_seconds();
- }
-private:
- int timeConstraint_;
- bool doAssert_;
- boost::posix_time::ptime start_time_;
-};
-
-}
-#endif /* ASSERTTIMER_HPP_ */
diff --git a/ecflow_4_0_7/ACore/src/Calendar.cpp b/ecflow_4_0_7/ACore/src/Calendar.cpp
deleted file mode 100644
index 117de48..0000000
--- a/ecflow_4_0_7/ACore/src/Calendar.cpp
+++ /dev/null
@@ -1,383 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #65 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-//============================================================================
-
-#include <boost/date_time/posix_time/time_formatters.hpp> // requires boost date and time lib, for to_simple_string
-#include "Calendar.hpp"
-#include "CalendarUpdateParams.hpp"
-#include "Log.hpp"
-#include "Ecf.hpp"
-#include "Extract.hpp"
-
-using namespace std;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-
-//#define DEBUG_CALENDAR 1;
-
-namespace ecf {
-
-Calendar::Calendar()
-: ctype_(Calendar::REAL),
- dayChanged_(false),
- startStopWithServer_(false),
- day_of_week_(-1),
- day_of_year_(-1),
- day_of_month_(-1),
- month_(-1),
- year_(-1)
-{
-}
-
-Calendar::Calendar(const Calendar& rhs)
-{
- assign(rhs);
-}
-
-Calendar& Calendar::operator=( const Calendar& rhs)
-{
- assign(rhs);
- return *this;
-}
-
-bool Calendar::operator==( const Calendar& rhs) const
-{
- // Only used for testing the persistence of calendar
- // Note: We specifically ignore initLocalTime_ and lastTime_ since they are initialised with the current time.
- // Otherwise For migration testing, it will fail
-
- if (ctype_ != rhs.ctype_) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) std::cout << "Calendar::operator== ctypes don't match\n";
-#endif
- return false;
- }
- if (initTime_ !=rhs.initTime_) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) std::cout << "Calendar::operator== initTime_ don't match\n";
-#endif
- return false;
- }
- if (suiteTime_ !=rhs.suiteTime_) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) std::cout << "Calendar::operator== suiteTime_ don't match\n";
-#endif
- return false;
- }
- if (duration_ !=rhs.duration_) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) std::cout << "Calendar::operator== duration_ don't match\n";
-#endif
- return false;
- }
- if (dayChanged_ !=rhs.dayChanged_) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) std::cout << "Calendar::operator== dayChanged_ don't match\n";
-#endif
- return false;
- }
- if (startStopWithServer_ != rhs.startStopWithServer_) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) std::cout << "Calendar::operator== startStopWithServer_ don't match\n";
-#endif
- return false;
- }
- if (calendarIncrement_ !=rhs.calendarIncrement_) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) std::cout << "Calendar::operator== calendarIncrement_ don't match\n";
-#endif
- return false;
- }
-
- return true;
-}
-
-void Calendar::assign( const Calendar& rhs)
-{
- ctype_ = rhs.ctype_;
- initTime_ = rhs.initTime_;
- suiteTime_ = rhs.suiteTime_;
- duration_ = rhs.duration_;
- dayChanged_ = rhs.dayChanged_;
- startStopWithServer_ = rhs.startStopWithServer_;
- initLocalTime_ = rhs.initLocalTime_;
- lastTime_ = rhs.lastTime_;
- calendarIncrement_ = rhs.calendarIncrement_;
-
- day_of_week_ = rhs.day_of_week_; // Cache
- day_of_year_ = rhs.day_of_year_; // Cache
- day_of_month_ = rhs.day_of_month_; // Cache
- month_ = rhs.month_; // Cache
- year_ = rhs.year_; // Cache
-}
-
-void Calendar::init(Clock_t clock, bool startStopWithServer)
-{
- ctype_ = clock;
- startStopWithServer_ = startStopWithServer;
-}
-
-void Calendar::init(const boost::posix_time::ptime& time, Clock_t clock, bool startStopWithServer)
-{
- init(clock,startStopWithServer);
- begin(time);
-}
-
-/// Start the Calendar. Parameter time can include gain.
-void Calendar::begin(const boost::posix_time::ptime& the_time)
-{
- duration_ = time_duration(0,0,0,0);
- calendarIncrement_ = time_duration(0,1,0,0); // This will get overwritten on update
- // But allows some tests to run
- suiteTime_ = the_time; // includes gain _IF_ it was specified
- initTime_ = the_time; // includes gain
- dayChanged_ = false;
- initLocalTime_ = second_clock_time(); // for real time clock
- lastTime_ = initLocalTime_; // for real time clock
-
- // Cache the most common requests
- update_cache();
-}
-
-void Calendar::update( const ecf::CalendarUpdateParams & calUpdateParams )
-{
- assert(!suiteTime_.is_special()); // begin has not been called.
-
- // Get the day of week before we update calendar, then same after to determine if the day changed
- boost::gregorian::date currentdate = suiteTime_.date();
- int theDayOfWeek = currentdate.day_of_week().as_number();
-
- // However there are two ways of incremented/updating calendar.
- if ( !startStopWithServer_ && !calUpdateParams.forTest() ) {
-
- if (calUpdateParams.serverPollPeriod().total_seconds() < 60) {
- // 0/ We are still testing. User wants to speed up calendar.
- // i.e. if server poll period is 2 seconds, we increment calendar by 1 minute
-
- time_duration one_minute(0,1,0,0);
- duration_ += one_minute;
- suiteTime_ += one_minute;
- calendarIncrement_ = one_minute;
-
-#ifdef DEBUG_CALENDAR
- std::cout << "Calendar::update: if (calUpdateParams.serverPollPeriod().total_seconds() < 60) { \n";
-#endif
- }
- else {
- // 1. Always Maintain phase with system clock. The calUpdateParams.timeNow()
- // time was constructed from a system call in the server.
- //
- // Take a difference, which means we can ignore dates
- const ptime& time_now = calUpdateParams.timeNow();
- assert(!time_now.is_special()); // This should have been set
- duration_ = time_period( initLocalTime_, time_now ).length();
- calendarIncrement_ = time_now - lastTime_;
- suiteTime_ += calendarIncrement_;
- lastTime_ = time_now;
-#ifdef DEBUG_CALENDAR
- std::cout << "Calendar::update: if ( !startStopWithServer_ && !calUpdateParams.forTest() ) { \n";
-#endif
- }
- }
- else {
- // 2. Update calendar based on server poll period/ Job submission interval
- // _OR_ For TESTING allow calendar to be speeded up.
- // Note: for simulation serverPollPeriod could be 1 hour
- duration_ += calUpdateParams.serverPollPeriod();
- suiteTime_ += calUpdateParams.serverPollPeriod();
- calendarIncrement_ = calUpdateParams.serverPollPeriod();
-#ifdef DEBUG_CALENDAR
- std::cout << "Calendar::update: calUpdateParams.serverPollPeriod() = " << calUpdateParams.serverPollPeriod() << "\n";
-#endif
- }
-
- update_cache();
-
- // *This relies on update_cache() being called first, since it needs day_of_week_
- // Day change required for both REAL and HYBRID. See TimeDependencies.ddoc for reason
- if (theDayOfWeek != day_of_week_) dayChanged_ = true;
- else dayChanged_ = false;
-
- // With the hybrid calendar the date does not change
- if ( ctype_ == Calendar::HYBRID) {
- if (suiteTime_.date() != initTime_.date()) {
-
-#ifdef DEBUG_CALENDAR
- cout << "HYBRID: (suiteTime_.date() != initTime_.date()) suiteTime_ = " << to_simple_string(suiteTime_) << "\n";
-#endif
-
- time_duration td = suiteTime_.time_of_day();
-
- suiteTime_ = ptime( initTime_.date(), td);
-
-#ifdef DEBUG_CALENDAR
- cout << "suiteTime_ = " << to_simple_string(suiteTime_) << "\n";
-#endif
- }
- }
-
-#ifdef DEBUG_CALENDAR
- cout << " Calendar::update serverPollPeriod = " << to_simple_string(calUpdateParams.serverPollPeriod()) << " " << toString() << endl;
-#endif
-}
-
-void Calendar::update_cache() const
-{
- // begin() has not been called yet
- if (suiteTime_.is_special()) return;
-
- boost::gregorian::date newDate = suiteTime_.date();
- day_of_week_ = newDate.day_of_week().as_number();
- day_of_year_ = newDate.day_of_year();
- day_of_month_ = newDate.day();
- month_ = newDate.month();
- year_ = newDate.year();
-}
-int Calendar::day_of_week() const { if (day_of_week_ == -1) update_cache(); return day_of_week_;}
-int Calendar::day_of_year() const { if (day_of_week_ == -1) update_cache(); return day_of_year_;}
-int Calendar::day_of_month() const { if (day_of_week_ == -1) update_cache(); return day_of_month_;}
-int Calendar::month() const { if (day_of_week_ == -1) update_cache(); return month_;}
-int Calendar::year() const { if (day_of_week_ == -1) update_cache(); return year_;}
-
-
-void Calendar::update(const boost::posix_time::time_duration& serverPollPeriod)
-{
- CalendarUpdateParams p(serverPollPeriod);
- update( p );
-}
-
-void Calendar::update(const boost::posix_time::ptime& time_now)
-{
- // Used for test even though for_test is false, as we want to test that path in UNIT tests
- // Tests: path 1. shown above. Note: we pass minutes(1), to ensure path 1. is taken
- CalendarUpdateParams p( time_now, minutes(1), true /* server running */, false/* for Test*/ );
- update( p );
-}
-
-boost::gregorian::date Calendar::date() const
-{
- return suiteTime_.date();
-}
-
-/// for debug
-void Calendar::dump(const std::string& title) const
-{
- LOG(Log::LOG,title
- << " duration_(" << to_simple_string(duration_)
- << ") initTime_(" << to_simple_string(initTime_)
- << ") suiteTime_(" << to_simple_string(suiteTime_) << ")"
- );
-}
-
-std::string Calendar::toString() const
-{
- std::stringstream ss;
- ss << "hybrid(" << hybrid()
- << ") duration_(" << to_simple_string(duration_)
- << ") initTime_(" << to_simple_string(initTime_)
- << ") suiteTime_(" << to_simple_string(suiteTime_)
- << ") dayChanged_(" << dayChanged_ << ")";
- ss << " calendarIncrement_(" << to_simple_string(calendarIncrement_) << ")";
-
- if (day_of_week_ == 0) ss << " SUNDAY";
- else if (day_of_week_ == 1) ss << " MONDAY";
- else if (day_of_week_ == 2) ss << " TUESDAY";
- else if (day_of_week_ == 3) ss << " WEDNESDAY";
- else if (day_of_week_ == 4) ss << " THURSDAY";
- else if (day_of_week_ == 5) ss << " FRIDAY";
- else if (day_of_week_ == 6) ss << " SATURDAY";
-
- return ss.str();
-}
-
-
-std::string Calendar::write_state() const
-{
- if ( initTime_.is_special() ) return string();
-
- bool calendarIncrement__changed = (!calendarIncrement_.is_special() && calendarIncrement_.total_seconds() != 0);
-
- // cType is obtained from the suite clock attribute, and not persisted
- std::stringstream ss;
- ss << " initTime:" << to_simple_string(initTime_);
- ss << " suiteTime:" << to_simple_string(suiteTime_);
- ss << " duration:" << to_simple_string(duration_);
- ss << " initLocalTime:" << to_simple_string(initLocalTime_);
- ss << " lastTime:" << to_simple_string(lastTime_);
- if (calendarIncrement__changed) ss << " calendarIncrement:" << to_simple_string(calendarIncrement_);
-
- if (dayChanged_) ss << " dayChanged:" << dayChanged_;
- return ss.str();
-}
-
-void Calendar::read_state(const std::string& line,const std::vector<std::string>& lineTokens)
-{
- // initTime:2012-Jul-16 16:19:35 suiteTime:2012-Jul-16 16:19:35 duration:00:00:00 dayChanged:0 initLocalTime:2012-Jul-16 16:19:35 lastTime:2012-Jul-16 16:19:35 calendarIncrement:00:00:00
-// std::cout << "Calendar::read_state:" << line << "\n";
- std::string time;
- for(size_t i = 0; i < lineTokens.size(); i++) {
- time.clear();
- if (lineTokens[i].find("initTime:") != std::string::npos ) {
- if (!Extract::split_get_second(lineTokens[i],time)) throw std::runtime_error( "Calendar::read_state failed: (initTime)");
- if (i + 1 < lineTokens.size()) { time += " "; time += lineTokens[i+1]; }
- else throw std::runtime_error( "Calendar::read_state failed: 1");
- initTime_ = time_from_string(time);
- }
- else if (lineTokens[i].find("suiteTime:") != std::string::npos ) {
- if (!Extract::split_get_second(lineTokens[i],time)) throw std::runtime_error( "Calendar::read_state failed: (suiteTime)");
- if (i + 1 < lineTokens.size()) { time += " "; time += lineTokens[i+1]; }
- else throw std::runtime_error( "Calendar::read_state failed: 1");
- suiteTime_ = time_from_string(time);
- }
- else if (lineTokens[i].find("initLocalTime:") != std::string::npos ) {
- if (!Extract::split_get_second(lineTokens[i],time)) throw std::runtime_error( "Calendar::read_state failed: (initLocalTime)");
- if (i + 1 < lineTokens.size()) { time += " "; time += lineTokens[i+1]; }
- else throw std::runtime_error( "Calendar::read_state failed: 1");
- initLocalTime_ = time_from_string(time);
- }
- else if (lineTokens[i].find("lastTime:") != std::string::npos ) {
- if (!Extract::split_get_second(lineTokens[i],time)) throw std::runtime_error( "Calendar::read_state failed: (lastTime)");
- if (i + 1 < lineTokens.size()) { time += " "; time += lineTokens[i+1]; }
- else throw std::runtime_error( "Calendar::read_state failed: 1");
- lastTime_ = time_from_string(time);
- }
- else if (lineTokens[i].find("duration:") != std::string::npos ) {
- if (!Extract::split_get_second(lineTokens[i],time)) throw std::runtime_error( "Calendar::read_state failed: (duration)");
- duration_ = duration_from_string(time);
- }
- else if (lineTokens[i].find("calendarIncrement:") != std::string::npos ) {
- if (!Extract::split_get_second(lineTokens[i],time)) throw std::runtime_error( "Calendar::read_state failed: (calendarIncrement)");
- calendarIncrement_ = duration_from_string(time);
- }
- else if (lineTokens[i] == "dayChanged:1") dayChanged_ = true;
- }
-}
-
-bool Calendar::checkInvariants(std::string& errorMsg) const
-{
- if (!duration_.is_special()) {
- if (duration_.is_negative()) {
- errorMsg += "Calendar::checkInvariants duration is negative "+ toString() + "\n";
- return false;
- }
- }
- return true;
-}
-
-boost::posix_time::ptime Calendar::second_clock_time()
-{
- /// Chose UTC since it s compatible with boost deadline timer
- return second_clock::universal_time(); // UTC
-}
-
-}
diff --git a/ecflow_4_0_7/ACore/src/Calendar.hpp b/ecflow_4_0_7/ACore/src/Calendar.hpp
deleted file mode 100644
index 20b7675..0000000
--- a/ecflow_4_0_7/ACore/src/Calendar.hpp
+++ /dev/null
@@ -1,255 +0,0 @@
-#ifndef CALENDAR_HPP_
-#define CALENDAR_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #48 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : The calendar object is initialised when the suite begins.
-// The calendar encapsulates date and time. The date is derived from the time.
-//
-// After each update the calendar will store the time_duration between the init() function
-// call and the update() function call.
-// The calendar is to be used for all reference to time and date
-// This will stop different time functionality from getting out of step.
-//
-// Examples of Use of calendar are:
-// o Generated time variables
-// o Time dependent attributes: TimeAttr,TodaySeries,CronAttr,DateAttr,DayAttr
-// ****************************************************************************
-// ** A time attribute can have a +, which means time relative to suite start
-// ** This is stored on the TimeSeries, as it isNode/Attribute specific.
-// ** i.e repeated families will have its own relative start time.
-// *****************************************************************************
-//
-// DESIGN CONSIDERATIONS:
-// Real and Hybrid:
-// Real
-// calendar is like a normal calendar where time and date are related
-// and day/date changes at midnight.
-// Hybrid:
-// There is currently confusion about how this is supposed to work.
-// The date is not supposed to change. (According to John date updates at suite restart?)
-// This has important implications, i.e does the day change ?
-// If the day does not change, then many of suites will never complete.
-// i.e if we use repeat, with a single time series, "time 10:00"
-// *** This relies on a day change to reset time attribute at midnight. ****
-// Conclusion: Will support day change for both REAL and HYBRID (date does not change)
-//
-// Calendar Updates:
-// How and when should we update the calendar?
-// In both the approaches below we need to make a distinction/separation
-// between the server poll and calendar update. This is required for testing
-//
-// o Poll/Job submission interval in server is used to update calendar .
-// +: No time slots will be missed. even if server is suspended/restarted.
-// since suspending the server, also suspends the calendar updates
-// +: Suite relative times will continue to work even after server stopped/started
-// +: Avoids additional system call.
-// +: Lead's to more deterministic behaviour
-// -: If server is suspended and restarted the calendar will NOT be in
-// phase with system clock. (Its not clear to me why this should be an issue?)
-// ?: If the server is run for several days is there a possibility for the poll
-// update to get out of skew with real time. This is only possible if
-// job dependencies take more the 60 seconds to resolve.
-// *** THIS FUNCTIONALITY NEEDS TO BE ADVERTISED, SO THAT USERS ARE AWARE OF IT
-// *** THIS FUNCTIONALITY IS AVAILABLE VIA -s flag on the clock attribute .i.e
-// *** the -s stand's for stop start clock in line with the server
-// clock real 20.1.2007 +01:00 -s
-// clock hybrid -s
-//
-// o Poll/Job submission interval in server is used Initiate an update of calendar via a system call.
-// +: calendar is always in phase with system clock.
-// Many task job dependencies depend on ordering based on real time.
-// -: Requires additional system call for each poll in the server
-// -: Time slots can be missed. (i.e if server suspended/restarted).
-// There is no catch up. (?? See TimeDependencies.ddoc)
-// -: Relative times will not be adhered too, when server stopped/started.
-// -: Will require more manual intervention ?
-//
-// Conclusion:: The clock attribute will be changed to add both capabilities
-//
-// Resolution: Will support 1 minute resolution:
-//============================================================================
-
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-#include <boost/date_time/posix_time/conversion.hpp>
-#include <boost/date_time/posix_time/time_serialize.hpp>
-#include <boost/serialization/serialization.hpp>
-#include <boost/serialization/level.hpp>
-#include <boost/serialization/tracking.hpp>
-
-namespace ecf {
-
-class CalendarUpdateParams; // forward declare
-
-class Calendar {
-public:
- enum Clock_t {
- REAL, // like a normal clock
- HYBRID // date does not change, but will support day change. See Above.
- };
-
- /// Defaults to the REAL clock
- Calendar();
- Calendar(const Calendar&);
- Calendar& operator=( const Calendar&);
- bool operator==( const Calendar&) const;
-
- /// Initialise the Calendar.
- /// The boolean startStopWithServer allows us to choose how we update the calendar:
- // False: Use system time to update the calendar:
- // True : Use the server poll, to update the calendar
- void init(Clock_t clock, bool startStopWithServer = false);
-
- // for test init and begin calendar
- void init(const boost::posix_time::ptime& time, Clock_t clock = Calendar::REAL, bool startStopWithServer = false);
-
- /// Start the Calendar. Parameter time can include gain.
- void begin(const boost::posix_time::ptime& time);
-
- /// Update the calendar using the input. Will Store internally the time duration
- /// between the init() function call and the last update.
- /// The for_test parameter is *ONLY* used if we are using real time calendar
- void update(const ecf::CalendarUpdateParams &);
-
- // Used for test only, will call the function above
- void update(const boost::posix_time::time_duration&);
- void update(const boost::posix_time::ptime& time_now);
-
- // The following were added as a performance optimisation
- // Represent a day within a week (range 0==Sun to 6==Sat)
- int day_of_week() const; // same as suiteTime().date().day_of_week().as_number()
- int day_of_year() const; // same as suiteTime().date().day_of_year()
- int day_of_month() const; // same as suiteTime().date().day()
- int month() const; // same as suiteTime().date().month()
- int year() const; // same as suiteTime().date().year()
-
- /// returns true if the day changed, this will update for REAL and HYBRID .
- bool dayChanged() const { return dayChanged_;}
-
- /// returns the last calendar increment
- const boost::posix_time::time_duration& calendarIncrement() const { return calendarIncrement_;}
-
- /// return the init() time + the accumulated duration from calls to update(...)
- /// This should only be used when this calendar is real.
- const boost::posix_time::ptime& suiteTime() const { return suiteTime_;}
-
- // duration since last call to init, essentially suite duration
- const boost::posix_time::time_duration& duration() const { return duration_;}
-
- /// return real time, when the calendar was begun/initialised.
- /// This is used to update the duration_, which is recorded for each state change in the node
- /// Hence to when we can compute when a state change occurred by using:
- /// boost::posix_time::ptime time_of_state_change = begin_time() + node->get_state().second(duration)
- const boost::posix_time::ptime& begin_time() const { return initLocalTime_;}
-
- /// return the date, for real calendar this corresponds to the date on suiteTime_
- /// for hybrid, the date does not change, and hence we return date for initTime_
- boost::gregorian::date date() const;
-
- /// The calendar type. For hybrid clocks the date does not update.
- bool hybrid() const { return (ctype_ == Calendar::HYBRID) ? true : false; }
-
- /// for debug, must link with boost date and time library
- void dump(const std::string& title) const;
-
- /// for debug, must link with boost date and time library
- std::string toString() const;
-
- std::string write_state() const;
- void read_state(const std::string& line,const std::vector<std::string>& lineTokens);
-
- bool checkInvariants(std::string& errorMsg) const;
-
- // allow Suite memento to update calendar type
- void set_clock_type( Clock_t ct) { ctype_ = ct;}
-
- /// Will return either second_clock::universal_time()/UTC ( the other alternative is second_clock::local_time() )
- /// This is because boost deadline timer is based on UTC clock
- /// >>> The deadline_timer typedef is based on a UTC clock, and all operations (expires_at, expires_from_now) work in UTC time.
- /// >>> If you want it to use a different clock (such as the local time clock), you can use basic_deadline_timer<> with your own traits class.
- /// >>> Please see the "Timers" example.
- /// Taken from boost date/time doc
- /// If you want exact agreement with wall-clock time, you must use either UTC or local time. If you compute a duration
- // by subtracting one UTC time from another and you want an answer accurate to the second, the two times must not be
- // too far in the future because leap seconds affect the count but are only determined about 6 months in advance. With
- // local times a future duration calculation could be off by an entire hour, since legislatures can and do change DST
- // rules at will.
- // If you want to handle wall-clock times in the future, you won't be able (in the general case) to calculate exact durations,
- // for the same reasons described above.
- // If you want accurate calculations with future times, you will have to use TAI or an equivalent, but the mapping from
- // TAI to UTC or local time depends on leap seconds, so you will not have exact agreement with wall-clock time.
- static boost::posix_time::ptime second_clock_time();
-
-
-private:
- void assign( const Calendar& rhs);
-
- Clock_t ctype_; // *NOT* persisted: can be derived from suite clock attribute
- boost::posix_time::ptime initTime_; // When calendar was started, suite time(could be in the past OR real time)
- boost::posix_time::ptime suiteTime_; // The suite time for hybrid DATE does not change.
- boost::posix_time::time_duration duration_; // duration since last call to init/begin, used on Node for late and autocancel
- bool dayChanged_;
- bool startStopWithServer_; //*NOT* persisted: false means real time calendar, can be derived from suite clock attribute
-
- boost::posix_time::ptime initLocalTime_; // Real Time: When calendar was started, used to work out duration_
- boost::posix_time::ptime lastTime_; // Real Time: Used to calculate calendarIncrement
-
- boost::posix_time::time_duration calendarIncrement_;
-
-private:
- void update_cache() const;
- mutable int day_of_week_; // Cache
- mutable int day_of_year_; // Cache
- mutable int day_of_month_; // Cache
- mutable int month_; // Cache
- mutable int year_; // Cache
-
-private:
- // Note: The *only* reason to serialise the calendar is so that we can support
- // why() command on the client side. By default calendar is initialised in the *server*
- // at begin time, from the clock attribute
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/)
- {
- if (Archive::is_saving::value) {
- if ( initTime_.is_special() ) {
- // Initialise the ptimes to avoid serialisation exceptions
- // The serialisation of ptime makes use of exceptions, especially
- // when dealing with a date that has *not* been initialised.
- // To avoid this we take a small hit to initialise the calendar with
- // time now. This will get overriden with suite clock at begin
- begin(second_clock_time());
- }
- }
-
- ar & initTime_;
- ar & suiteTime_;
- ar & duration_;
- ar & dayChanged_;
- ar & initLocalTime_;
- ar & lastTime_;
- ar & calendarIncrement_;
- }
-};
-}
-
-
-// eliminate serialization overhead at the cost of
-// never being able to increase the version.
-BOOST_CLASS_IMPLEMENTATION(ecf::Calendar, boost::serialization::object_serializable)
-
-// eliminate object tracking (even if serialized through a pointer)
-// at the risk of a programming error creating duplicate objects.
-BOOST_CLASS_TRACKING(ecf::Calendar,boost::serialization::track_never);
-
-#endif
diff --git a/ecflow_4_0_7/ACore/src/CalendarUpdateParams.hpp b/ecflow_4_0_7/ACore/src/CalendarUpdateParams.hpp
deleted file mode 100644
index ab37454..0000000
--- a/ecflow_4_0_7/ACore/src/CalendarUpdateParams.hpp
+++ /dev/null
@@ -1,71 +0,0 @@
-#ifndef CALENDARUPDATEPARAMS_HPP_
-#define CALENDARUPDATEPARAMS_HPP_
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Collate Argument list to update calendar
-//
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-
-#include <boost/noncopyable.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-namespace ecf {
-
-class CalendarUpdateParams : private boost::noncopyable {
-public:
-
- // For use in the server
- CalendarUpdateParams(const boost::posix_time::ptime& time_now,
- const boost::posix_time::time_duration& serverPollPeriod,
- bool serverRunning)
- : timeNow_(time_now),
- serverPollPeriod_(serverPollPeriod),
- serverRunning_( serverRunning ),
- forTest_( false )
- {}
-
-
- // For use in the simulator/ unit tests
- CalendarUpdateParams(const boost::posix_time::time_duration& serverPollPeriod)
- : timeNow_( boost::date_time::not_a_date_time),
- serverPollPeriod_(serverPollPeriod),
- serverRunning_( true ),
- forTest_( true )
- {}
-
- // For use in test
- CalendarUpdateParams(const boost::posix_time::ptime& time_now,
- const boost::posix_time::time_duration& serverPollPeriod,
- bool serverRunning,
- bool forTest)
- : timeNow_(time_now),
- serverPollPeriod_(serverPollPeriod),
- serverRunning_( serverRunning ),
- forTest_( forTest )
- {}
-
- const boost::posix_time::ptime& timeNow() const { return timeNow_;}
- const boost::posix_time::time_duration& serverPollPeriod() const { return serverPollPeriod_;}
- bool serverRunning() const { return serverRunning_; }
- bool forTest() const { return forTest_;}
-
-private:
- boost::posix_time::ptime timeNow_; // Current time and date, not used in simulator
- boost::posix_time::time_duration serverPollPeriod_; // equivalent to calendar increment
- bool serverRunning_; // Is the server running or stopped
- bool forTest_; // Used with Simulator
-};
-}
-#endif /* CALENDARUPDATEPARAMS_HPP_ */
diff --git a/ecflow_4_0_7/ACore/src/CheckPt.hpp b/ecflow_4_0_7/ACore/src/CheckPt.hpp
deleted file mode 100644
index b7881a7..0000000
--- a/ecflow_4_0_7/ACore/src/CheckPt.hpp
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef CHECKPT_HPP_
-#define CHECKPT_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-// This class is used to ONLY serialise the edit history when check pointing
-// Also Provides enums for check pointing
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/noncopyable.hpp>
-
-namespace ecf {
-
-class CheckPt : private boost::noncopyable {
-public:
- /// NEVER - the check pt file is never saved
- /// ON_TIME - the check pt file is saved periodically. specified by checkPtInterval.
- /// ALWAYS - the check pt file is saved after any state change
- /// UNDEFINED - Internal use only
- enum Mode { NEVER, ON_TIME, ALWAYS, UNDEFINED};
-
- /// The interval between automatic saves of check point by server
- static int default_interval() { return 120;}
-
- /// If saving check point takes longer than the alarm time, raise late flag on the server
- static int default_save_time_alarm() { return 30;}
-
-private:
- CheckPt();
-};
-
-}
-#endif
diff --git a/ecflow_4_0_7/ACore/src/Child.cpp b/ecflow_4_0_7/ACore/src/Child.cpp
deleted file mode 100644
index 15f3060..0000000
--- a/ecflow_4_0_7/ACore/src/Child.cpp
+++ /dev/null
@@ -1,167 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Specifies the different kinds of child commands
-// These are specified in the job file, and communicate with the server
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <assert.h>
-
-#include "Child.hpp"
-#include "Str.hpp"
-
-namespace ecf {
-
-std::string Child::to_string(Child::ZombieType zt)
-{
- switch (zt) {
- case Child::USER: return "user"; break;
- case Child::PATH: return "path"; break;
- case Child::ECF: return "ecf"; break;
- case Child::NOT_SET: return "not_set"; break;
- }
- return std::string();
-}
-
-Child::ZombieType Child::zombie_type(const std::string& s)
-{
- if (s == "user") return Child::USER;
- if (s == "ecf") return Child::ECF;
- if (s == "path") return Child::PATH;
- return Child::NOT_SET;
-}
-
-bool Child::valid_zombie_type( const std::string& s)
-{
- if (s == "user") return true;
- if (s == "ecf") return true;
- if (s == "path") return true;
- return false;
-}
-
-std::string Child::to_string(const std::vector<Child::CmdType>& vec)
-{
- std::string ret;
- for(size_t i =0; i < vec.size(); ++i) {
- if (i == 0) ret += to_string(vec[i]);
- else {
- ret += ",";
- ret += to_string(vec[i]);
- }
- }
- return ret;
-}
-
-std::string Child::to_string( Child::CmdType ct)
-{
- switch (ct) {
- case Child::INIT: return "init"; break;
- case Child::EVENT: return "event"; break;
- case Child::METER: return "meter"; break;
- case Child::LABEL: return "label"; break;
- case Child::WAIT: return "wait"; break;
- case Child::ABORT: return "abort"; break;
- case Child::COMPLETE: return "complete"; break;
- }
- assert(false);
- return "init";
-}
-
-std::vector<Child::CmdType> Child::child_cmds(const std::string& s)
-{
- // expect single or , separated tokens
- std::vector<std::string> tokens;
- Str::split(s,tokens,",");
- std::vector<Child::CmdType> ret; ret.reserve(tokens.size());
- for(size_t i =0; i < tokens.size(); ++i) {
- ret.push_back(child_cmd(tokens[i]));
- }
- return ret;
-}
-
-Child::CmdType Child::child_cmd( const std::string& s)
-{
- if (s == "init") return Child::INIT;
- if (s == "event") return Child::EVENT;
- if (s == "meter") return Child::METER;
- if (s == "label") return Child::LABEL;
- if (s == "wait") return Child::WAIT;
- if (s == "abort") return Child::ABORT;
- if (s == "complete") return Child::COMPLETE;
- assert(false);
- return Child::INIT;
-}
-
-bool Child::valid_child_cmds( const std::string& s)
-{
- // empty means all children
- if (s.empty()) return true;
-
- // expect single or , separated tokens
- std::vector<std::string> tokens;
- Str::split(s,tokens,",");
- for(size_t i =0; i < tokens.size(); ++i) {
- if (!valid_child_cmd(tokens[i])) return false;
- }
- return true;
-}
-
-bool Child::valid_child_cmd( const std::string& s)
-{
- if (s == "init") return true;
- if (s == "event") return true;
- if (s == "meter") return true;
- if (s == "label") return true;
- if (s == "wait") return true;
- if (s == "abort") return true;
- if (s == "complete") return true;
- return false;
-}
-
-//=====================================================================
-
-bool User::valid_user_action( const std::string& s)
-{
- if (s == "fob") return true;
- if (s == "fail") return true;
- if (s == "adopt") return true;
- if (s == "remove") return true;
- if (s == "block") return true;
- if (s == "kill") return true;
- return false;
-}
-
-User::Action User::user_action( const std::string& s)
-{
- if (s == "fob") return User::FOB;
- if (s == "fail") return User::FAIL;
- if (s == "adopt") return User::ADOPT;
- if (s == "remove") return User::REMOVE;
- if (s == "block") return User::BLOCK;
- if (s == "kill") return User::KILL;
- return User::BLOCK;
-}
-
-std::string User::to_string(User::Action uc)
-{
- switch (uc) {
- case User::FOB: return "fob"; break;
- case User::FAIL: return "fail"; break;
- case User::ADOPT: return "adopt"; break;
- case User::REMOVE: return "remove"; break;
- case User::BLOCK: return "block"; break;
- case User::KILL: return "kill"; break;
- }
- assert(false);
- return std::string();
-}
-
-}
diff --git a/ecflow_4_0_7/ACore/src/Child.hpp b/ecflow_4_0_7/ACore/src/Child.hpp
deleted file mode 100644
index 0e27676..0000000
--- a/ecflow_4_0_7/ACore/src/Child.hpp
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef CHILD_HPP_
-#define CHILD_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Specifies the different kinds of child commands
-// These are specified in the job file, and communicate with the server
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <string>
-#include <vector>
-#include <boost/noncopyable.hpp>
-
-namespace ecf {
-
-class Child : private boost::noncopyable {
-public:
- enum CmdType { INIT, EVENT, METER, LABEL, WAIT, ABORT, COMPLETE };
-
- enum ZombieType { USER, ECF, PATH , NOT_SET };
-
- static std::string to_string(ZombieType);
- static bool valid_zombie_type( const std::string& );
- static ZombieType zombie_type( const std::string&);
-
- static std::string to_string(const std::vector<Child::CmdType>&);
- static std::string to_string( Child::CmdType );
- static std::vector<Child::CmdType> child_cmds(const std::string&);
- static Child::CmdType child_cmd(const std::string&);
-
- /// Expect a , separated string
- static bool valid_child_cmds( const std::string& );
- static bool valid_child_cmd( const std::string& );
-
-private:
- Child();
-};
-
-
-class User : private boost::noncopyable {
-public:
- enum Action { FOB, FAIL, ADOPT, REMOVE, BLOCK, KILL };
-
- static bool valid_user_action( const std::string& );
- static Action user_action( const std::string& );
- static std::string to_string(Action);
-
-private:
- User();
-};
-
-}
-#endif
diff --git a/ecflow_4_0_7/ACore/src/DState.cpp b/ecflow_4_0_7/ACore/src/DState.cpp
deleted file mode 100644
index d2e37d1..0000000
--- a/ecflow_4_0_7/ACore/src/DState.cpp
+++ /dev/null
@@ -1,136 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <assert.h>
-#include <iostream>
-#include "DState.hpp"
-#include "Ecf.hpp"
-
-void DState::setState( State s ) {
- state_= s;
- state_change_no_ = Ecf::incr_state_change_no();
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "DState::setState\n";
-#endif
-}
-
-NState::State DState::convert(DState::State display_state)
-{
- switch (display_state) {
- case DState::UNKNOWN: return NState::UNKNOWN; break;
- case DState::COMPLETE: return NState::COMPLETE; break;
- case DState::SUSPENDED: return NState::UNKNOWN; break;
- case DState::QUEUED: return NState::QUEUED; break;
- case DState::ABORTED: return NState::ABORTED; break;
- case DState::SUBMITTED: return NState::SUBMITTED; break;
- case DState::ACTIVE: return NState::ACTIVE; break;
- }
- return NState::UNKNOWN;
-}
-
-const char* DState::toString( DState::State s ) {
- switch ( s ) {
- case DState::UNKNOWN:
- return "unknown";
- break;
- case DState::COMPLETE:
- return "complete";
- break;
- case DState::QUEUED:
- return "queued";
- break;
- case DState::ABORTED:
- return "aborted";
- break;
- case DState::SUBMITTED:
- return "submitted";
- break;
- case DState::SUSPENDED:
- return "suspended";
- break;
- case DState::ACTIVE:
- return "active";
- break;
- default:
- assert(false);break;
- }
- assert(false);
- return NULL;
-}
-
-DState::State DState::toState( const std::string& str ) {
- if ( str == "complete" )
- return DState::COMPLETE;
- if ( str == "unknown" )
- return DState::UNKNOWN;
- if ( str == "queued" )
- return DState::QUEUED;
- if ( str == "aborted" )
- return DState::ABORTED;
- if ( str == "submitted" )
- return DState::SUBMITTED;
- if ( str == "suspended" )
- return DState::SUSPENDED;
- if ( str == "active" )
- return DState::ACTIVE;
- assert(false);
- return DState::UNKNOWN;
-}
-
-bool DState::isValid( const std::string& state ) {
- if ( state == "complete" )
- return true;
- if ( state == "suspended" )
- return true;
- if ( state == "unknown" )
- return true;
- if ( state == "aborted" )
- return true;
- if ( state == "submitted" )
- return true;
- if ( state == "active" )
- return true;
- if ( state == "queued" )
- return true;
- return false;
-}
-
-std::vector< std::string > DState::allStates() {
- std::vector< std::string > vec;
- vec.reserve( 7 );
- vec.push_back( "complete" );
- vec.push_back( "unknown" );
- vec.push_back( "queued" );
- vec.push_back( "aborted" );
- vec.push_back( "submitted" );
- vec.push_back( "suspended" );
- vec.push_back( "active" );
- return vec;
-}
-
-std::vector<DState::State> DState::states()
-{
- std::vector< DState::State > vec;
- vec.reserve( 7 );
- vec.push_back( DState::UNKNOWN );
- vec.push_back( DState::COMPLETE );
- vec.push_back( DState::QUEUED );
- vec.push_back( DState::ABORTED );
- vec.push_back( DState::SUBMITTED );
- vec.push_back( DState::ACTIVE );
- vec.push_back( DState::SUSPENDED );
- return vec;
-}
-
diff --git a/ecflow_4_0_7/ACore/src/DState.hpp b/ecflow_4_0_7/ACore/src/DState.hpp
deleted file mode 100644
index 2247b13..0000000
--- a/ecflow_4_0_7/ACore/src/DState.hpp
+++ /dev/null
@@ -1,72 +0,0 @@
-#ifndef DSTATE_HPP_
-#define DSTATE_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <string>
-#include <vector>
-#include <boost/serialization/serialization.hpp>
-#include <boost/serialization/level.hpp>
-#include <boost/serialization/tracking.hpp>
-#include "NState.hpp"
-
-// DState: stores the state of a node.
-// *The class DState just used to define the enum, however we also
-// needed to know when the state changed. Hence the use of state_change_no
-// Uses default copy constructor and destructor, and equality
-class DState {
-public:
- enum State { UNKNOWN =0, COMPLETE=1, QUEUED=2, ABORTED=3, SUBMITTED=4, ACTIVE=5, SUSPENDED=6};
- DState(State s): state_(s), state_change_no_(0) {}
- DState(): state_(QUEUED),state_change_no_(0) {}
-
- State state() const { return state_;}
- void setState(State);
-
- // The state_change_no is never reset. Must be incremented if it can affect equality
- unsigned int state_change_no() const { return state_change_no_; }
-
- bool operator==(const DState& rhs) const { return state_ == rhs.state_;}
- bool operator!=(const DState& rhs) const { return state_ != rhs.state_;}
- bool operator==(State s) const { return s == state_;}
- bool operator!=(State s) const { return s != state_;}
-
- static DState::State default_state() { return DState::QUEUED; }
- static NState::State convert(DState::State);
- static const char* toString(DState::State s);
- static const char* toString(const DState& ns) { return toString(ns.state());}
- static DState::State toState(const std::string& state);
- static bool isValid(const std::string& state);
- static std::vector<std::string> allStates();
- static std::vector<DState::State> states();
-
-private:
- State state_;
- unsigned int state_change_no_; // *not* persisted, only used on server side
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/)
- {
- ar & state_;
- }
-};
-
-// This should ONLY be added to objects that are *NOT* serialised through a pointer
-BOOST_CLASS_IMPLEMENTATION(DState, boost::serialization::object_serializable);
-BOOST_CLASS_TRACKING(DState,boost::serialization::track_never);
-
-#endif
diff --git a/ecflow_4_0_7/ACore/src/DurationTimer.hpp b/ecflow_4_0_7/ACore/src/DurationTimer.hpp
deleted file mode 100644
index 1680fc1..0000000
--- a/ecflow_4_0_7/ACore/src/DurationTimer.hpp
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef DURATIONTIMER_HPP_
-#define DURATIONTIMER_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Simple class the reports wall clock time duration
-//============================================================================
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-namespace ecf {
-
-class DurationTimer {
-public:
- DurationTimer() : start_time_(boost::posix_time::microsec_clock::universal_time()) {}
- ~DurationTimer() {}
-
- int duration() const {
- boost::posix_time::time_duration duration = boost::posix_time::microsec_clock::universal_time() - start_time_;
- return duration.total_seconds();
- }
-
- boost::posix_time::time_duration elapsed() const { return boost::posix_time::microsec_clock::universal_time() - start_time_;}
-
-private:
- boost::posix_time::ptime start_time_;
-};
-
-}
-#endif
diff --git a/ecflow_4_0_7/ACore/src/Ecf.cpp b/ecflow_4_0_7/ACore/src/Ecf.cpp
deleted file mode 100644
index be63d17..0000000
--- a/ecflow_4_0_7/ACore/src/Ecf.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #16 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Provides globals used by server
-//============================================================================
-
-#include "Ecf.hpp"
-
-bool Ecf::server_ = false;
-bool Ecf::debug_equality_ = false;
-unsigned int Ecf::debug_level_ = 0;
-unsigned int Ecf::state_change_no_ = 0;
-unsigned int Ecf::modify_change_no_ = 0;
-
-const char* Ecf::SERVER_NAME() { static const char* SERVER_NAME = "ecflow_server"; return SERVER_NAME;}
-const char* Ecf::CLIENT_NAME() { static const char* CLIENT_NAME = "ecflow_client"; return CLIENT_NAME;}
-
-const std::string& Ecf::LOG_FILE() { static const std::string LOG_FILE = "ecf.log"; return LOG_FILE;}
-const std::string& Ecf::CHECKPT() { static const std::string CHECKPT= "ecf.check"; return CHECKPT;}
-const std::string& Ecf::BACKUP_CHECKPT() { static const std::string BACKUP_CHECKPT= "ecf.check.b";return BACKUP_CHECKPT;}
-const std::string& Ecf::MICRO() { static const std::string MICRO= "%";return MICRO;}
-const std::string& Ecf::JOB_CMD() { static const std::string JOB_CMD= "%ECF_JOB% 1> %ECF_JOBOUT% 2>&1";return JOB_CMD;}
-const std::string& Ecf::KILL_CMD() { static const std::string KILL_CMD= "kill -15 %ECF_RID%";return KILL_CMD;} // "${ECF_KILL:=/home/ma/emos/bin/ecfkill} %USER% %HOST% %ECF_RID% %ECF_JOB% > %ECF_JOB%.kill 2>&1";
-const std::string& Ecf::STATUS_CMD() { static const std::string STATUS_CMD= "ps --sid %ECF_RID% -f";return STATUS_CMD;}// "${ECF_STAT:=/home/ma/emos/bin/ecfstatus} %USER% %HOST% %ECF_RID% %ECF_JOB% > %ECF_JOB%.stat 2>&1";
-const std::string& Ecf::URL_CMD() { static const std::string URL_CMD= "${BROWSER:=firefox} -remote 'openURL(%ECF_URL_BASE%/%ECF_URL%)'";return URL_CMD;}
-const std::string& Ecf::URL_BASE() { static const std::string URL_BASE= "https://software.ecmwf.int";return URL_BASE;}
-const std::string& Ecf::URL() { static const std::string URL = "wiki/display/ECFLOW/Home";return URL;}
-
-
-unsigned int Ecf::incr_state_change_no() {
- if ( server_ ) {
- return ++state_change_no_;
- }
- return state_change_no_;
-}
-
-unsigned int Ecf::incr_modify_change_no() {
-
- if ( server_ ) {
- return ++modify_change_no_;
- }
- return modify_change_no_;
-}
-
-// =======================================================
-
-EcfPreserveChangeNo::EcfPreserveChangeNo()
-: state_change_no_(Ecf::state_change_no()),
- modify_change_no_(Ecf::modify_change_no())
-{}
-
-EcfPreserveChangeNo::~EcfPreserveChangeNo()
-{
- Ecf::set_state_change_no(state_change_no_);
- Ecf::set_modify_change_no(modify_change_no_);
-}
-
diff --git a/ecflow_4_0_7/ACore/src/Ecf.hpp b/ecflow_4_0_7/ACore/src/Ecf.hpp
deleted file mode 100644
index 1338140..0000000
--- a/ecflow_4_0_7/ACore/src/Ecf.hpp
+++ /dev/null
@@ -1,92 +0,0 @@
-#ifndef ECF_HPP_
-#define ECF_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #13 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Provides globals used by server for determining change
-//============================================================================
-
-#include <boost/noncopyable.hpp>
-#include <string>
-
-// class Ecf: This class is used in the server to determine incremental changes
-// to the data model. Each Node/attribute stores a state change no
-// When ever there is a change, we increment local state change
-// number with this global.
-// When making large scale changes, ie nodes added or deleted we use modify change no
-// Note: The client will need to at some point copy over the full defs
-// at this point the state change no add modify number is also copied.
-// The client passes these two number back to server, the server then
-// uses these two numbers to determine what's changed.
-//
-class Ecf : private boost::noncopyable {
-public:
- /// Increment and then return state change no
- static unsigned int incr_state_change_no() ;
- static unsigned int state_change_no() { return state_change_no_; }
- static void set_state_change_no(unsigned int x) { state_change_no_ = x;}
-
- /// The modify_change_no_ is used for node addition and deletion and re-ordering
- static unsigned int incr_modify_change_no();
- static unsigned int modify_change_no() { return modify_change_no_; }
- static void set_modify_change_no(unsigned int x) { modify_change_no_ = x;}
-
- /// Returns true if we are on the server side.
- /// Only in server side do we increment state/modify numbers
- /// Also used in debug/test: Allows print to add know if in server/client
- static bool server() { return server_;}
-
- /// Should only be set by the server, made public so that testing can also set it
- /// Only in server side do we increment state/modify numbers
- static void set_server(bool f) { server_ = f;}
-
- static bool debug_equality() { return debug_equality_;}
- static void set_debug_equality(bool f) { debug_equality_ = f;}
-
- // ECFLOW-99
- static unsigned int debug_level() { return debug_level_;}
- static void set_debug_level(unsigned int level) { debug_level_ = level;}
-
- static const char* SERVER_NAME();
- static const char* CLIENT_NAME();
-
- static const std::string& LOG_FILE();
- static const std::string& CHECKPT();
- static const std::string& BACKUP_CHECKPT();
- static const std::string& MICRO();
- static const std::string& JOB_CMD();
- static const std::string& KILL_CMD();
- static const std::string& STATUS_CMD();
- static const std::string& URL_CMD();
- static const std::string& URL_BASE();
- static const std::string& URL();
-
-private:
-
- Ecf(){}
- static bool server_;
- static bool debug_equality_;
- static unsigned int debug_level_;
- static unsigned int state_change_no_;
- static unsigned int modify_change_no_;
-};
-
-/// Make sure the Ecf number don't change
-class EcfPreserveChangeNo {
-public:
- EcfPreserveChangeNo();
- ~EcfPreserveChangeNo();
-private:
- unsigned int state_change_no_;
- unsigned int modify_change_no_;
-};
-#endif
diff --git a/ecflow_4_0_7/ACore/src/Extract.cpp b/ecflow_4_0_7/ACore/src/Extract.cpp
deleted file mode 100644
index 26e2846..0000000
--- a/ecflow_4_0_7/ACore/src/Extract.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <boost/lexical_cast.hpp>
-#include <boost/date_time/posix_time/time_formatters.hpp> // requires boost date and time lib
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include "Extract.hpp"
-#include "Stl.hpp"
-#include "Str.hpp"
-
-#include <sstream>
-#include <fstream>
-
-//#define DEBUG_PARSER 1
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-using namespace boost::gregorian;
-
-template<class T>
-ostream& operator<<(ostream& os, const vector<T>& v) {
- copy(v.begin(), v.end(), ostream_iterator<T>(cout, ","));
- return os;
-}
-
-bool Extract::pathAndName(const std::string& token, std::string& path, std::string& name)
-{
-// cout << "Extract::pathAndName token = " << token << "\n";
- // can have:
- // /suite/family:obj path = /suite/family name = obj
- // /suite/family path = /suite/family name =
- // obj path = name = obj
- if (token.empty()) return false;
-
- size_t colonPos = token.find_first_of(':');
- if (colonPos == string::npos) {
- if (token[0] == '/') {
- path = token; // token of the form /a/b/c, ie no name
- }
- else {
- name = token;
- }
- }
- else {
- path = token.substr(0,colonPos);
- name = token.substr(colonPos+1);
- }
-
-// cout << "Extract::pathAndName token=" << token << " path= '" << path << "' name= '" << name << "'\n";
- return true;
-}
-
-bool Extract::split_get_second(const std::string& str, std::string& ret,char separator)
-{
- // HH:MM
- // return MM;
- size_t colonPos = str.find_first_of(separator);
- if (colonPos == string::npos) return false;
- ret = str.substr(colonPos+1);
- return true;
-}
-
-/// extract integer or throw an std::runtime exception on failure
-int Extract::theInt( const std::string& token, const std::string& errorMsg )
-{
- int the_int = -1;
- try {
- the_int = boost::lexical_cast< int >( token );
- }
- catch ( boost::bad_lexical_cast& e ) {
- throw std::runtime_error(errorMsg );
- }
- return the_int;
-}
-
-/// extract YMD, integer of the form yyyymmdd
-int Extract::ymd(const std::string& ymdToken, std::string& errorMsg)
-{
- if (ymdToken.size() != 8) throw std::runtime_error( errorMsg + " YMD must be 8 characters i.e yyyymmdd");
-
- // Use date lib to check YMD
- try { boost::gregorian::date(from_undelimited_string(ymdToken)); }
- catch (std::exception& e) {
- errorMsg += "\n";
- errorMsg += e.what();
- throw std::runtime_error( errorMsg + " YMD is not a valid date" );
- }
-
- return theInt(ymdToken,errorMsg);
-}
-
-int Extract::optionalInt( const std::vector<std::string>& lineTokens,
- int pos,
- int defaultValue,
- const std::string& errorMsg )
-{
- // token0 token1 token2 token3 size = 4
- // pos0 pos1 pos2 pos3
- //
- // could have line of the form
- // repeat integer variable 1 2 #a comment
- // repeat integer variable 3 4 # a comment
- // hence we must check the first character, and not the complete token
-
- int the_int = defaultValue;
- if (static_cast<int>(lineTokens.size()) >= pos+1 && lineTokens[pos][0] != '#' ) {
-
- the_int = theInt(lineTokens[pos],errorMsg);
- }
- return the_int;
-}
diff --git a/ecflow_4_0_7/ACore/src/Extract.hpp b/ecflow_4_0_7/ACore/src/Extract.hpp
deleted file mode 100644
index 0ce395f..0000000
--- a/ecflow_4_0_7/ACore/src/Extract.hpp
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef EXTRACT_HPP_
-#define EXTRACT_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <string>
-#include <vector>
-#include <boost/noncopyable.hpp>
-
-class Extract : private boost::noncopyable {
-public:
-
- // token if of the form:
- // /path/to/home:obj OR obj
- // path = /path/to/home path = ""
- // name = obj name = obj
- // return true for ok or false for error
- static bool pathAndName(const std::string& token, std::string& path, std::string& name);
-
- // Given str = HH:MM
- // return MM;
- static bool split_get_second(const std::string& str, std::string& ret,char separator = ':');
-
- /// extract integer or throw an std::runtime_error on failure,
- /// the error message passed in is used to configure the returned exception
- static int theInt(const std::string& token,const std::string& errorContext) ;
-
- /// extract YMD, integer of the form yyyymmdd, will throw std::runtime_error on failure
- /// the error message passed in is used to configure the returned exception
- static int ymd(const std::string& token, std::string& errorContext);
-
- /// extract optional int, else return -1
- /// the error message passed in is used to configure the returned exception
- // could have line of the form
- // repeat integer variable 1 2 #a comment
- // repeat integer variable 3 4 # a comment
- // hence we must check the first character, and not the complete token
- static int optionalInt(const std::vector<std::string>& lineTokens,
- int pos,int defaultvalue,const std::string& errorContext);
-private:
- Extract();
-};
-
-#endif
diff --git a/ecflow_4_0_7/ACore/src/File.cpp b/ecflow_4_0_7/ACore/src/File.cpp
deleted file mode 100644
index 53bc3cf..0000000
--- a/ecflow_4_0_7/ACore/src/File.cpp
+++ /dev/null
@@ -1,984 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #70 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : This class is used as a helper class
-//============================================================================
-
-#include <iostream>
-#include <fstream>
-#include <sstream>
-
-#include "boost/filesystem.hpp"
-#include "boost/filesystem/operations.hpp"
-#include <boost/token_functions.hpp>
-#include <boost/algorithm/string/trim.hpp>
-#include <boost/algorithm/string.hpp>
-#include <boost/foreach.hpp>
-#include <boost/tokenizer.hpp>
-
-
-#include "File.hpp"
-#include "File_r.hpp"
-#include "Log.hpp"
-#include "NodePath.hpp"
-#include "Str.hpp"
-#include "Ecf.hpp"
-
-using namespace std;
-using namespace boost;
-namespace fs = boost::filesystem;
-
-//#define DEBUG_SERVER_PATH 1
-//#define DEBUG_CLIENT_PATH 1
-
-static std::string workspace_dir()
-{
- // We need the *SAME* location so that different process find the same file. Get to the workspace directory
- boost::filesystem::path current_path = boost::filesystem::current_path();
- std::string stem = current_path.stem().string();
- int count = 0;
- while( stem.find("ecflow") == std::string::npos) {
- current_path = current_path.parent_path();
- stem = current_path.stem().string();
- count++;
- if (count == 10000) throw std::runtime_error("File::workspace_dir() failed to find ecflow in a directory name, up the directory tree");
- }
- std::string the_workspace_dir = current_path.string(); // cos string is returned by reference
- return the_workspace_dir;
-}
-
-
-namespace ecf {
-
-size_t File::MAX_LINES() { return 10000; }
-const std::string& File::JOB_EXTN() { static const std::string JOB_EXTN = ".job"; return JOB_EXTN; }
-const std::string& File::MAN_EXTN() { static const std::string MAN_EXTN = ".man"; return MAN_EXTN; }
-const std::string& File::USR_EXTN() { static const std::string USR_EXTN = ".usr"; return USR_EXTN; }
-const std::string& File::ECF_EXTN() { static const std::string ECF_EXTN = ".ecf"; return ECF_EXTN; }
-
-std::string File::getExt(const std::string& s)
-{
- size_t i = s.rfind('.',s.length());
- if (i != std::string::npos) {
- return s.substr(i+1);
- }
- return string();
-}
-
-void File::replaceExt(std::string& file, const std::string& newExt)
-{
- string::size_type i = file.rfind('.',file.length());
- if (i != string::npos) file.replace(i+1,newExt.length(), newExt);
-}
-
-bool File::splitFileIntoLines(const std::string& filename, std::vector<std::string>& lines,bool ignoreEmptyLine)
-{
- std::ifstream the_file(filename.c_str(),std::ios_base::in);
- if ( !the_file ) return false;
- lines.reserve(lines.size() + 100);
-
- // Note if we use: while( getline( theEcfFile, line)), then we will miss the *last* *empty* line
-
-// int i = 0;
- string line;
- while ( std::getline(the_file,line) ) {
-// i++;
-// cout << i << ": " << line << "\n";
- if (ignoreEmptyLine && line.empty()) continue;
- lines.push_back(line);
- }
-
-// METHOD1
-// Note Another way to split lines of a file was to use a tokenizer.
-// Much slower ~ 2.5 slower,
-// ifstream ifs(filename.c_str());
-// if (!ifs) return false;
-//
-// // Note: ss.str() returns a temporary std::string.
-// // boost::tokenizer stores a reference to the string.
-// // The temporary string is destroyed and tokenizer is left with a dangling reference.
-// // hence take a copy
-// std::stringstream ss; ss << ifs.rdbuf(); // Read the whole file into a string
-// std::string theFileAsString = ss.str(); // take a copy as ss.str() returns a temporary
-// // // while tokenizer stores a reference
-// if (ignoreEmptyLine) {
-// char_separator<char> sep("\n",0,boost::drop_empty_tokens);
-// typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
-// tokenizer tokens(theFileAsString, sep);
-// std::copy(tokens.begin(), tokens.end(), back_inserter(lines));
-// }
-// else {
-// char_separator<char> sep("\n",0,boost::keep_empty_tokens);
-// typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
-// tokenizer tokens(theFileAsString, sep);
-// std::copy(tokens.begin(), tokens.end(), back_inserter(lines));
-// }
-
- // METHOD 2:
- // Note: The implementation below is 2.5 times slower
- // std::ifstream ifs(filename.c_str());
- // if (!ifs) return false;
- //
- // std::istreambuf_iterator<char> file_iter(ifs);
- // std::istreambuf_iterator<char> end_of_stream;
- //
- // typedef boost::tokenizer<boost::char_separator<char>,
- // std::istreambuf_iterator<char> > tokenizer;
- //
- // boost::char_separator<char> sep("\n");
- // tokenizer tokens(file_iter,end_of_stream, sep);
- // std::copy(tokens.begin(), tokens.end(), back_inserter(lines));
-
- // The current implementation is 2.5 times faster then method 1, and ~4 times faster than method 2
- return true;
-}
-
-
-std::string File::get_last_n_lines(const std::string& filename,int last_n_lines, std::string& error_msg)
-{
- if ( last_n_lines <= 0 ) return string();
-
- std::ifstream source( filename.c_str(), std::ios_base::in );
- if (!source) {
- error_msg = "File::get_last_n_lines: Could not open file " + filename;
- return string();
- }
-
- size_t const granularity = 100 * last_n_lines;
- source.seekg( 0, std::ios_base::end );
- size_t size = static_cast<size_t>( source.tellg() );
- std::vector<char> buffer;
- int newlineCount = 0;
- while ( source
- && buffer.size() != size
- && newlineCount < last_n_lines ) {
- buffer.resize( std::min( buffer.size() + granularity, size ) );
- source.seekg( -static_cast<std::streamoff>( buffer.size() ),
- std::ios_base::end );
- source.read( buffer.data(), buffer.size() );
- newlineCount = std::count( buffer.begin(), buffer.end(), '\n');
- }
-
- std::vector<char>::iterator start = buffer.begin();
- while ( newlineCount > last_n_lines ) {
- start = std::find( start, buffer.end(), '\n' ) + 1;
- -- newlineCount;
- }
-
- //std::vector<char>::iterator end = remove( start, buffer.end(), '\r' ); // for windows
- return std::string( start, buffer.end() );
-}
-
-
-std::string File::get_first_n_lines(const std::string& filename,int n_lines, std::string& error_msg)
-{
- if ( n_lines <= 0 ) return string();
-
- std::ifstream source( filename.c_str(), std::ios_base::in );
- if (!source) {
- error_msg = "File::get_first_n_lines: Could not open file " + filename;
- return string();
- }
-
- std::string ret; ret.reserve(1024);
- std::string line;
-
- int count = 0;
- while ( std::getline(source,line) && count < n_lines) {
-
- ret += line;
- ret += "\n";
- count++;
- }
-
- return ret;
-}
-
-/// Opens the file and returns the contents
-bool File::open(const std::string& filePath, std::string& contents)
-{
- std::ifstream infile( filePath.c_str() , std::ios_base::in);
- if ( ! infile) return false;
-
- std::ostringstream temp;
- temp << infile.rdbuf();
- contents = temp.str();
- return true;
-}
-
-//std::string File::tmpFile(std::string& contents)
-//{
-//
-//}
-
-
-bool File::create(const std::string& filename,const std::vector<std::string>& lines, std::string& errorMsg)
-{
- // For very large file. This is about 1 second quicker. Than using streams
- // See Test: TestFile.cpp:test_file_create_perf
- FILE * theFile = fopen (filename.c_str(),"w");
- if (theFile==NULL) {
- std::stringstream ss;
- ss << "Could not create file '" << filename << "'\n";
- errorMsg += ss.str();
- return false;
- }
- size_t size = lines.size();
- for (size_t i = 0; i < size; ++i) {
- if (i != 0) {
- if (fputs("\n",theFile) == EOF) {
- std::stringstream ss;
- ss << "Could not write to file '" << filename << "'\n";
- errorMsg += ss.str();
- fclose (theFile);
- return false;
- }
- }
- if (fputs(lines[i].c_str(),theFile) == EOF) {
- std::stringstream ss;
- ss << "Could not write to file '" << filename << "'\n";
- errorMsg += ss.str();
- fclose (theFile);
- return false;
- }
- }
- fclose (theFile);
-
-// std::ofstream theFile( filename.c_str() );
-// if ( !theFile ) {
-// /// Could be: [ no permissions | file system full | locked by another process ]
-// std::stringstream ss;
-// ss << "Could not create file '" << filename << "'\n";
-// errorMsg += ss.str();
-// return false;
-// }
-// size_t size = lines.size();
-// for (size_t i = 0; i < size; ++i) {
-// if (i != 0) theFile << "\n";
-// theFile << lines[i];
-// }
-// if (!theFile.good()) {
-// std::stringstream ss;
-// ss << "Could not write to file '" << filename << "'\n";
-// errorMsg += ss.str();
-// theFile.close();
-// return false;
-// }
-// theFile.close();
-
- return true;
-}
-
-bool File::create(const std::string& filename, const std::string& contents, std::string& errorMsg)
-{
- std::ofstream theFile( filename.c_str() );
- if ( !theFile ) {
- std::stringstream ss;
- ss << "Could not create file '" << filename << "'\n";
- errorMsg += ss.str();
- return false;
- }
-
- theFile << contents;
- if (!theFile.good()) {
- std::stringstream ss;
- ss << "Could not write to file '" << filename << "'\n";
- errorMsg += ss.str();
- theFile.close();
- return false;
- }
- theFile.close();
-
- // This is actually 12% slower for large file:
-// FILE * theFile = fopen (filename.c_str(),"w");
-// if (theFile==NULL) {
-// std::stringstream ss;
-// ss << "Could not create file '" << filename << "'\n";
-// errorMsg += ss.str();
-// return false;
-// }
-// if (fputs(contents.c_str(),theFile) == EOF) {
-// std::stringstream ss;
-// ss << "Could not write to file '" << filename << "'\n";
-// errorMsg += ss.str();
-// fclose (theFile);
-// return false;
-// }
-// fclose (theFile);
- return true;
-}
-
-bool File::find(
- const boost::filesystem::path& dir_path, // from this directory downwards,
- const std::string& file_name, // search for this name,
- boost::filesystem::path& path_found // placing path here if found
- )
-{
-// std::cout << "Searching '" << dir_path << "' for " << file_name << "\n";
- if ( !fs::exists( dir_path ) )
- return false;
-
- fs::directory_iterator end_itr; // default construction yields past-the-end
- for (fs::directory_iterator itr( dir_path ); itr != end_itr; ++itr) {
-
- if ( fs::is_directory( itr->status() ) ) {
-
- if ( File::find( itr->path(), file_name, path_found ) )
- return true;
- }
- else if ( itr->path().filename() == file_name ) // see below
- {
- path_found = itr->path();
- return true;
- }
- }
- return false;
-}
-
-void File::findAll(
- const boost::filesystem::path& dir_path, // from this directory downwards
- const std::string& file_name, // search for this name,
- std::vector<boost::filesystem::path>& paths_found // placing path here if found
- )
-{
- if ( !fs::exists( dir_path ) ) return;
-
- fs::directory_iterator end_itr; // default construction yields past-the-end
- for (fs::directory_iterator itr( dir_path ); itr != end_itr; ++itr) {
-
- if ( fs::is_directory( itr->status() ) ) {
-
- findAll( itr->path(), file_name, paths_found ) ;
- }
- else if ( itr->path().filename() == file_name ) // see below
- {
- paths_found.push_back( itr->path() );
- }
- }
-}
-
-std::string File::findPath(
- const boost::filesystem::path& dir_path, // from this directory downwards
- const std::string& file_name, // search for this name,
- const std::string& leafDir // path must contain this string
- )
-{
- std::vector< fs::path > paths;
- File::findAll( dir_path, file_name, paths );
- if ( !paths.empty() ) {
-
- // find the path that has leafDir in it.
- BOOST_FOREACH(fs::path path, paths) {
- std::string thePath = path.string();
- if (thePath.rfind(leafDir) != std::string::npos) return thePath;
- }
- }
- return std::string();
-}
-
-
-std::string File::findPath(
- const boost::filesystem::path& dir_path, // from this directory downwards
- const std::string& file_name, // search for this name,
- const std::vector<std::string>& tokens // path must contain all these tokens
-)
-{
- std::vector< fs::path > paths;
- File::findAll( dir_path, file_name, paths );
- if ( !paths.empty() ) {
-
- // find the path that has all the tokens specified by the vector tokens
- BOOST_FOREACH(fs::path path, paths) {
- std::string thePath = path.string();
- size_t matches = 0;
- BOOST_FOREACH(const std::string& required_path_tokens, tokens) {
- if (thePath.rfind(required_path_tokens) != std::string::npos) matches++;
- }
- if (matches == tokens.size()) return thePath;
- }
- }
- return std::string();
-}
-
-//#define INTEL_DEBUG_ME 1
-bool File::createMissingDirectories(const std::string& pathToFileOrDir)
-{
-#ifdef INTEL_DEBUG_ME
- std::cout << "File::createMissingDirectories " << pathToFileOrDir << std::endl;
-#endif
- if (pathToFileOrDir.empty()) return false;
-
- // Avoid making unnecessary system calls, by checking to see if directory exists first
- fs::path fs_path(pathToFileOrDir);
- if (fs_path.extension().empty()) {
-
-#ifdef INTEL_DEBUG_ME
- std::cout << " pure directory no extension" << std::endl;
-#endif
- // pure directory
- if (fs::exists(pathToFileOrDir)) {
-
-#ifdef INTEL_DEBUG_ME
- std::cout << " " << pathToFileOrDir << " already exists " << std::endl;
-#endif
-
- return true;
- }
- }
- else {
-
-#ifdef INTEL_DEBUG_ME
- std::cout << " pure directory *has* extension" << std::endl;
-#endif
- // could be /tmp/fred/sms.job, see if /tmp/fred exists
- if (fs::exists(fs_path.parent_path())) {
-
-#ifdef INTEL_DEBUG_ME
- std::cout << " " << pathToFileOrDir << " already exists " << std::endl;
-#endif
- return true;
- }
- }
-
- std::vector<std::string> thePath;
- NodePath::split(pathToFileOrDir, thePath);
- try {
- if ( !thePath.empty() ) {
-
-#ifdef INTEL_DEBUG_ME
- std::cout << " last file " << thePath.back() << std::endl;
-#endif
-
- // pathToFileOrDir is of form: /tmp/fred/sms.job
- // we should only create directories for /tmp/fred
- if ( thePath.back().find( "." ) != std::string::npos ) {
- // assume the last token represents a file, hence dont create a directory
-#ifdef INTEL_DEBUG_ME
- std::cout << " last file " << thePath.back() << " has a *dot* ignoring "<< std::endl;
-#endif
- thePath.pop_back();
- }
-
- std::string pathToCreate;
-
- // if original path had leading slash then add it here, to preserve path
- if (pathToFileOrDir[0] == '/') pathToCreate += Str::PATH_SEPERATOR();
-
- for (size_t i = 0; i < thePath.size(); i++) {
- pathToCreate += thePath[i];
- if ( !fs::exists( pathToCreate ) ) {
-#ifdef INTEL_DEBUG_ME
- std::cout << " " << pathToCreate << " does not exist, creating directory " << std::endl;
-#endif
- fs::create_directory( pathToCreate );
- }
- pathToCreate += Str::PATH_SEPERATOR();
- }
- }
- else {
-#ifdef INTEL_DEBUG_ME
- std::cout << " NO path component in " << pathToFileOrDir << std::endl;
-#endif
-
- if ( pathToFileOrDir.find( "." ) != std::string::npos ) {
- // assume represents a file, hence don't create a directory fred.job1
-#ifdef INTEL_DEBUG_ME
- std::cout << " assuming " << pathToFileOrDir << " is a file, found a dot, returning without creating dir " << std::endl;
-#endif
- return true;
- }
-
- // assume is a dir
-#ifdef INTEL_DEBUG_ME
- std::cout << " about to create dir " << pathToFileOrDir << std::endl;
-#endif
-
- fs::create_directory( pathToFileOrDir );
- }
- }
- catch ( const std::exception & ex ) {
-#ifdef INTEL_DEBUG_ME
- std::cout << " Exception " << ex.what() << " could not create dir " << pathToFileOrDir << std::endl;
-#endif
- return false;
- }
- return true;
-}
-
-
-/// Create directories the boost way, with additional check to see if directories exist first
-bool File::createDirectories(const std::string& pathToDir)
-{
- if (pathToDir.empty()) return false;
- if (fs::exists(pathToDir)) return true;
-
- try {
- return fs::create_directories(pathToDir);
- }
- catch (std::exception&) {}
- return false;
-}
-
-/// Returns the difference between 2 files.
-std::string File::diff(const std::string& file,
- const std::string& file2,
- const std::vector<std::string>& ignoreVec,
- std::string& errorMsg,
- bool ignoreBlanksLine)
-{
- if (!fs::exists(file)) {
- errorMsg += "First argument File " + file + " does not exist";
- return std::string();
- }
- if (!fs::exists(file2)) {
- errorMsg += "Second argument File " + file2 + " does not exist";
- return std::string();
- }
-
- std::vector<std::string> fileLines;
- std::vector<std::string> file2Lines;
-
- if (!splitFileIntoLines(file, fileLines, ignoreBlanksLine)) {
- errorMsg += "First argument File " + file + " could not be opened";
- return std::string();
- }
- if (!splitFileIntoLines(file2, file2Lines, ignoreBlanksLine)) {
- errorMsg += "Second argument File " + file2 + " could not be opened";
- return std::string();
- }
-
- if ( fileLines != file2Lines) {
- std::stringstream ss;
- if (fileLines.size() != file2Lines.size()) ss << "Expected size " << file2Lines.size() << " but found " << fileLines.size() <<"\n";
-
- for(size_t i=0; i < fileLines.size() || i < file2Lines.size(); ++i) {
-
- if (i < fileLines.size() && i < file2Lines.size()) {
-
- if (fileLines[i] != file2Lines[i]) {
- bool doIgnore = false;
- BOOST_FOREACH(const std::string& ignore, ignoreVec) {
- if ( fileLines[i].find(ignore) != std::string::npos || file2Lines[i].find(ignore) != std::string::npos ) {
- doIgnore = true; break;
- }
- }
- if (doIgnore) continue;
- ss << "Mismatch at " << i << "(" << fileLines[i] << ") ----> (" << file2Lines[i] << ")\n";
- }
-// else {
-// ss << " " << i << " (" << fileLines[i] << ") ----> (" << file2Lines[i] << ")\n";
-// }
- }
- else {
- ss << "Mismatch at " << i ;
- if (i < fileLines.size() ) ss << " (" << fileLines[i] << ") ";
- else ss << " ( ---- ) ";
-
- if (i < file2Lines.size()) ss << "(" << file2Lines[i] << ")\n";
- else ss << "( --- )\n";
- }
- }
- return ss.str();
- }
- return std::string();
-}
-
-std::string File::backwardSearch( const std::string& rootPath, const std::string& nodePath, const std::string& fileExtn )
-{
- // Do a backward search of rootPath + nodePath
- // If task path if of the form /suite/family/family2/task, then we keep
- // on consuming the first path token this should leave:
- // <root-path>/suite/family/family2/task.ecf
- // <root-path>/family/family2/task.ecf
- // <root-path>/family2/task.ecf
- // <root-path>/task.ecf
- // See page 21 of SMS user guide
-
- vector<std::string> nodePathTokens;
- NodePath::split(nodePath, nodePathTokens);
- LOG_ASSERT(!nodePathTokens.empty(),"");
-
- std::string leafName; // i.e. task in the example above
- if ( !nodePathTokens.empty() ) leafName = nodePathTokens[ nodePathTokens.size() -1 ] ;
-
-#ifdef DEBUG_TASK_LOCATION
- cout << "backwardSearch Node " << nodePath << " using root path " << rootPath << " nodePathTokens.size() = " << nodePathTokens.size() << "\n";
-#endif
- while ( nodePathTokens.size() > 0 ) {
-
- // Reconstitute the path
- std::string path = NodePath::createPath( nodePathTokens ) ;
- path += fileExtn; // .ecf, .man , etc
-
- std::string combinedPath = rootPath;
- combinedPath += path;
-
- try {
- if ( fs::exists( combinedPath )) {
-#ifdef DEBUG_TASK_LOCATION
- cout << "backwardSearch Node " << nodePath << " the path " << combinedPath << " exists\n";
-#endif
- return combinedPath;
- }
-#ifdef DEBUG_TASK_LOCATION
- else cout << " backwardSearch Node " << nodePath << " the path " << combinedPath << " DOEST NOT EXIST\n";
-#endif
- }
- catch (fs::filesystem_error& e) {
-#ifdef DEBUG_TASK_LOCATION
- std::cout << "Task::backwardSearch Caught exception for fs::exists('" << combinedPath <<"')\n" << e.what() << "\n";
-#endif
- }
-
- nodePathTokens.erase(nodePathTokens.begin()); // consume first path token
- }
-
- // Look for file in the root path
- std::string ecf_file = leafName + fileExtn;
- fs::path ecf_filePath = fs::path( fs::path(rootPath) / ecf_file );
- if (fs::exists(ecf_filePath)) {
-#ifdef DEBUG_TASK_LOCATION
- std::cout << "backwardSearch Node " << leafName << " Found " << ecf_file << " in root path '" << rootPath << "'\n";
-#endif
- std::string result = ecf_filePath.string(); // is returned by reference hence must take a copy
- return result ;
- }
-
- // failed to find file via backward search
- return string();
-}
-
-// Remove a directory recursively ****
-bool File::removeDir( const boost::filesystem::path& p)
-{
- try {
- fs::directory_iterator end;
- for(fs::directory_iterator it(p); it != end; ++it) {
- if (fs::is_directory(*it)) {
- if (!removeDir(*it)) {
- return false;
- }
- }
- else {
- fs::remove(*it);
- }
- }
- }
- catch (fs::filesystem_error& e) {
- return false;
- }
-
- // Finally remove dir itself
- fs::remove(p);
-
- return true;
-}
-
-
-static std::string find_bjam_ecf_server_path()
-{
-#ifdef DEBUG_SERVER_PATH
- cout << " File::find_ecf_server_path() using bjam\n";
-#endif
-
- // bjam uses in source tree, for build, which is in the workspace dir
- std::string bin_dir = workspace_dir() + "/Server/bin/";
-
-#ifdef DEBUG_SERVER_PATH
- cout << " Searching under: " << bin_dir << "\n";
-#endif
-
- // We need to take into account that on linux, we may have the GNU and CLANG executables
- // Hence we need to distinguish between them.
- std::vector<std::string> required_path_tokens;
-
- // We have 3 variants debug,release,profile
-#ifdef DEBUG
-
- required_path_tokens.push_back(std::string("debug"));
-#if defined(__clang__)
- required_path_tokens.push_back(std::string("clang"));
-#endif
-
- return File::findPath( bin_dir, Ecf::SERVER_NAME(), required_path_tokens );
-
-#else
-
- required_path_tokens.push_back(std::string("release"));
-#if defined(__clang__)
- required_path_tokens.push_back(std::string("clang"));
-#endif
-
- std::string path = File::findPath( bin_dir, Ecf::SERVER_NAME(), required_path_tokens );
- if (path.empty()) {
-
- required_path_tokens.clear();
- required_path_tokens.push_back(std::string("profile"));
-#if defined(__clang__)
- required_path_tokens.push_back(std::string("clang"));
-#endif
-
- path = File::findPath( bin_dir, Ecf::SERVER_NAME(), required_path_tokens );
- }
- return path;
-#endif
-}
-
-
-std::string File::find_ecf_server_path()
-{
- if (File::cmake_build()) {
-
- std::string path = File::root_build_dir();
- path += "/bin/";
- path += Ecf::SERVER_NAME();
-
-#ifdef DEBUG_SERVER_PATH
- cout << " File::find_ecf_server_path() path = " << path << "\n";
-#endif
- return path;
- }
-
- return find_bjam_ecf_server_path();
-}
-
-
-static std::string find_bjam_ecf_client_path()
-{
-#ifdef DEBUG_CLIENT_PATH
- cout << " find_bjam_ecf_client_path \n";
-#endif
-
- // Bjam uses, in source build
- std::string binDir = workspace_dir() + "/Client/bin/";
-
- // We need to take into account that on linux, we may have the GNU and CLANG executables
- // Hence we need to distinguish between them.
- std::vector<std::string> required_path_tokens;
-
- // We have 3 variants debug,release,profile
-#ifdef DEBUG
-
- required_path_tokens.push_back(std::string("debug"));
-#if defined(__clang__)
- required_path_tokens.push_back(std::string("clang"));
-#endif
-
- return File::findPath( binDir, Ecf::CLIENT_NAME(), required_path_tokens );
-
-#else
-
- required_path_tokens.push_back(std::string("release"));
-#if defined(__clang__)
- required_path_tokens.push_back(std::string("clang"));
-#endif
-
- std::string path = File::findPath( binDir, Ecf::CLIENT_NAME(), required_path_tokens );
- if (path.empty()) {
-
- required_path_tokens.clear();
- required_path_tokens.push_back(std::string("profile"));
-#if defined(__clang__)
- required_path_tokens.push_back(std::string("clang"));
-#endif
-
- path = File::findPath( binDir, Ecf::CLIENT_NAME(), required_path_tokens );
- }
- return path;
-#endif
-}
-
-std::string File::find_ecf_client_path()
-{
- if (File::cmake_build()) {
-
- std::string path = File::root_build_dir();
- path += "/bin/";
- path += Ecf::CLIENT_NAME();
-
-#ifdef DEBUG_CLIENT_PATH
- cout << " File::find_ecf_client_path() returning path " << path << "\n";
-#endif
- return path;
- }
-
-#ifdef DEBUG_CLIENT_PATH
- cout << " File::find_ecf_server_path() using bjam\n";
-#endif
- return find_bjam_ecf_client_path();
-}
-
-
-std::string File::test_data(const std::string& rel_path, const std::string& dir)
-{
- std::string test_file;
- char* work_space = getenv("WK"); // for ecbuild
- if (work_space != NULL ) {
- test_file = std::string(work_space);
- if (!rel_path.empty() && rel_path[0] != '/' ) test_file += "/";
- test_file += rel_path;
- }
- else {
- std::string work_space = root_source_dir();
- if (!work_space.empty()) {
- test_file = work_space;
- if (!rel_path.empty() && rel_path[0] != '/' ) test_file += "/";
- test_file += rel_path;
- }
- else {
- fs::path current_path = fs::current_path();
- if (current_path.stem() == dir ) {
-
- // remove first path, expecting "dir/path/path1" remove dir
- std::string::size_type pos = rel_path.find("/",1); // skip over any leading /
- if (pos != std::string::npos) {
- test_file += rel_path.substr(pos+1); // skip over '/' to be left with path/path1, making it relative
- }
- else {
- test_file += rel_path;
- }
- }
- else {
- test_file += rel_path;
- }
- }
- }
- return test_file;
-}
-
-
-bool File::cmake_build()
-{
- fs::path current_path = fs::current_path();
- std::string the_current_path = current_path.string();
- std::string cmakecache_txt = the_current_path + "/CTestTestfile.cmake";
- if (fs::exists(cmakecache_txt)) {
- return true;
- }
- return false;
-}
-
-std::string File::root_source_dir()
-{
- // bjam
- fs::path current_path = fs::current_path();
- std::string the_current_path = current_path.string();
- std::string version_cmake = the_current_path + "/VERSION.cmake";
- if (fs::exists(version_cmake)) {
- return the_current_path;
- }
-
- std::string stem = current_path.stem().string();
- int count = 0;
- while( stem.find("ecflow") == std::string::npos) {
- current_path = current_path.parent_path();
-
- // bjam
- std::string version_cmake = std::string(current_path.string()) + "/VERSION.cmake";
- if (fs::exists(version_cmake)) {
- std::string the_root_source_dir = current_path.string(); // cos current_path.string() is returned by reference
- return the_root_source_dir;
- }
-
- stem = current_path.stem().string();
- count++;
- if (count == 10000) break;
- }
-
-
-
- // cmake, CTestTestfile.cmake exists in the sub-directories and root directories
- // File CTestTestfile.cmake, lists the source directory.
- std::string cmake_test_file = the_current_path + "/CTestTestfile.cmake";
- if (!fs::exists(cmake_test_file))
- throw std::runtime_error("File::root_source_dir(): could not find file CTestTestfile.cmake at path " + cmake_test_file);
-
- std::vector<std::string> lines;
- if (splitFileIntoLines(cmake_test_file,lines, true)) {
- for(size_t i = 0; i < lines.size(); i++) {
- if (lines[i].find("Source directory") != std::string::npos) {
-
- std::vector< std::string > lineTokens;
- Str::split( lines[i],lineTokens,":");
- if (lineTokens.size() != 2) throw std::runtime_error("File::root_source_dir(): could not parse CTestTestfile.cmake for source directory");
-
- // This may be of the form: # Source directory: /tmp/ma0/clientRoot/workspace/working-directory/ecflow/ACore
- std::string source_directory = lineTokens[1];
- boost::algorithm::trim(source_directory);
-
- std::vector< std::string > pathTokens;
- Str::split( source_directory,pathTokens,"/");
- if (pathTokens.empty()) throw std::runtime_error("File::root_source_dir(): could not extract source directory from " + source_directory);
-
- for(size_t i = pathTokens.size()-1; i > 0 ; i-- ) {
- if (pathTokens[i] != "ecflow") pathTokens.erase( pathTokens.begin() + i);
- else break;
- }
-
- std::string path;
- for(size_t i =0; i < pathTokens.size(); i++) {
- path += "/";
- path += pathTokens[i];
- }
- return path;
- }
- }
- throw std::runtime_error("File::root_source_dir(): could not find text 'Source directory' in " + cmake_test_file );
- }
- else {
- throw std::runtime_error("File::root_source_dir(): could not open file " + cmake_test_file );
- }
-
- return std::string();
-}
-
-std::string File::root_build_dir()
-{
- fs::path current_path = fs::current_path();
- std::string the_current_path = current_path.string();
-
- // bjam
- std::string version_cmake = the_current_path + "/VERSION.cmake";
- if (fs::exists(version_cmake)) return the_current_path;
-
- // cmake
- std::string cmake_cache = the_current_path + "/CMakeCache.txt";
- if (fs::exists(cmake_cache)) return the_current_path;
-
-
- // bjam or cmake
- std::string stem = current_path.stem().string();
- int count = 0;
- while( stem.find("ecflow") == std::string::npos) {
- current_path = current_path.parent_path();
-
- the_current_path = current_path.string(); // cos current_path.string() is returned by reference
-
- // bjam
- std::string version_cmake = the_current_path + "/VERSION.cmake";
- if (fs::exists(version_cmake)) return the_current_path;
-
- // cmake
- std::string cmake_cache = the_current_path + "/CMakeCache.txt";
- if (fs::exists(cmake_cache)) return the_current_path;
-
- stem = current_path.stem().string();
- count++;
- if (count == 1000) throw std::runtime_error("File::root_build_dir() failed to find ecflow in a directory name, up the directory tree");
- }
-
- throw std::runtime_error("File::root_build_dir() failed to find root build directory");
- return std::string();
-}
-
-
-}
diff --git a/ecflow_4_0_7/ACore/src/File.hpp b/ecflow_4_0_7/ACore/src/File.hpp
deleted file mode 100644
index bf6d2e5..0000000
--- a/ecflow_4_0_7/ACore/src/File.hpp
+++ /dev/null
@@ -1,152 +0,0 @@
-#ifndef FILE_HPP_
-#define FILE_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #41 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : This class is used as a helper class for file utilities
-//============================================================================
-
-#include <boost/noncopyable.hpp>
-#include <boost/filesystem/path.hpp>
-#include <string>
-#include <vector>
-
-
-namespace ecf {
-
-class File : private boost::noncopyable {
-public:
-
- static size_t MAX_LINES(); // max number of lines, default to 10000
- static const std::string& JOB_EXTN(); // ".job"
- static const std::string& MAN_EXTN(); // ".man"
- static const std::string& USR_EXTN(); // ".usr"
- static const std::string& ECF_EXTN(); // ".ecf"
-
- /// expect string of the form ".ecf" or ".sms"
- static void set_ecf_extn(const std::string&);
- static const std::string& ecf_extn(); // return ".ecf" | ".sms" | ".py"
-
- /// return the file extension
- static std::string getExt(const std::string& file);
-
- /// replace file extension with a new one
- static void replaceExt(std::string& file, const std::string& newExt);
-
- /// returns the input files, split into a vector of string, where each string
- /// represent a line in the file. returns true if file open ok , false otherwise
- /// The additional parameter ignoreEmptyLine can be used to ignore empty lines
- /// **Always reads _WHOLE_ file. Not suitable for very large files **
- static bool splitFileIntoLines(const std::string& filename, std::vector<std::string>& lines, bool ignoreEmptyLine = false);
-
- /// This is suitable for large files. > several gigabytes, since it does load the entire file
- static std::string get_last_n_lines(const std::string& filename,int last_n_lines, std::string& error_msg);
-
- /// returns the first n line of a file, does not read all the file, hence suitable for very large files
- static std::string get_first_n_lines(const std::string& filename,int n_lines, std::string& error_msg);
-
- /// Opens the file and returns the contents
- static bool open(const std::string& filePath, std::string& contents);
-
- /// Given a file spath, and a vector of lines, creates a file. returns true if success
- /// else returns false and an error message
- static bool create(const std::string& filename, const std::vector<std::string>& lines, std::string& errorMsg);
- static bool create(const std::string& filename, const std::string& contents, std::string& errorMsg);
-
- /// recursively look for a file, given a starting directory
- /// Return the first file that matches
- /// return true if file found false otherwise
- static bool find(
- const boost::filesystem::path& dir_path, // from this directory downwards
- const std::string& file_name, // search for this name,
- boost::filesystem::path& path_found // placing path here if found
- );
-
- /// recursively look for a file, given a starting directory
- /// Returns _ALL_ files that match
- static void findAll(
- const boost::filesystem::path& dir_path, // from this directory downwards
- const std::string& file_name, // search for this name,
- std::vector<boost::filesystem::path>& paths_found // placing path here if found
- );
-
-
- /// recursively look for a file, given a starting directory and path token
- /// Returns the first match found
- static std::string findPath(
- const boost::filesystem::path& dir_path, // from this directory downwards
- const std::string& file_name, // search for this name,
- const std::string& leafDir // path must contain this string
- );
-
- static std::string findPath(
- const boost::filesystem::path& dir_path, // from this directory downwards
- const std::string& file_name, // search for this name,
- const std::vector<std::string>& tokens // path must contain all these tokens
- );
-
- /// Create missing directories. This is *NOT* the same as boost::create_directories
- /// as that only works with directories. This function assumes that if a "." exist
- /// in the string it represents a file.
- /// Hence this function handles:
- /// /tmp/some/dir/fred.job // i.e the directories /tmp/some/dir/ will be created
- /// /tmp/some/dir
- /// fred // will create the directory fred
- /// fred.job // just return true
- static bool createMissingDirectories(const std::string& pathToFileOrDir);
-
- /// Create directories the boost way, with additional check to see if directories exist first
- static bool createDirectories(const std::string& pathToDir);
-
- /// Returns the difference between 2 files.
- /// Ignore lines that contain strings in the ignoreVec
- static std::string diff(const std::string& file,
- const std::string& file2,
- const std::vector<std::string>& ignoreVec,
- std::string& errorMsg,
- bool ignoreBlanksLine = true);
-
- /// Do a backward search of rootPath + nodePath + fileExtn
- /// If task path if of the form /suite/family/family2/task, then we keep
- /// on consuming the first path token this should leave:
- /// <root-path>/suite/family/family2/task.ecf
- /// <root-path>/family/family2/task.ecf
- /// <root-path>/family2/task.ecf
- /// <root-path>/task.ecf
- /// See page 21 of SMS user guide
- //
- /// Returns an empty string if file not found
- static std::string backwardSearch( const std::string& rootPath, const std::string& nodePath, const std::string& fileExtn );
-
- // Remove a directory recursively ****
- static bool removeDir( const boost::filesystem::path& p);
-
-
- // Locate the path to the server exe
- static std::string find_ecf_server_path();
-
- // Locate the path to the client exe
- static std::string find_ecf_client_path();
-
- // Locate test data
- static std::string test_data(const std::string& rel_path, const std::string& dir);
-
- // return root source
- static bool cmake_build();
- static std::string root_source_dir();
- static std::string root_build_dir();
-};
-
-}
-
-#endif /* FILE_HPP_ */
diff --git a/ecflow_4_0_7/ACore/src/File_r.cpp b/ecflow_4_0_7/ACore/src/File_r.cpp
deleted file mode 100644
index c7a37c3..0000000
--- a/ecflow_4_0_7/ACore/src/File_r.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : This class is used as a helper class
-//============================================================================
-
-#include <iostream>
-#include "File_r.hpp"
-
-using namespace std;
-using namespace ecf;
-
-File_r::File_r(const std::string& file_name) : file_name_(file_name), fp_(file_name.c_str(), std::ios_base::in) {}
-File_r::~File_r() { fp_.close(); }
-
diff --git a/ecflow_4_0_7/ACore/src/File_r.hpp b/ecflow_4_0_7/ACore/src/File_r.hpp
deleted file mode 100644
index ea776f9..0000000
--- a/ecflow_4_0_7/ACore/src/File_r.hpp
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef FILE_R_HPP_
-#define FILE_R_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : This class is used as a helper class for file utilities
-//============================================================================
-
-#include <boost/noncopyable.hpp>
-#include <string>
-#include <fstream>
-
-namespace ecf {
-
-class File_r : private boost::noncopyable {
-public:
- File_r(const std::string& file_name);
- ~File_r();
-
- bool ok() const { return (fp_) ? true : false; }
- bool good() const { return fp_.good(); }
- void getline(std::string& line) { std::getline(fp_,line); }
- const std::string& file_name() const { return file_name_; }
-
-private:
- std::string file_name_;
- std::ifstream fp_;
-};
-
-}
-
-#endif
diff --git a/ecflow_4_0_7/ACore/src/Host.cpp b/ecflow_4_0_7/ACore/src/Host.cpp
deleted file mode 100644
index c0ed91f..0000000
--- a/ecflow_4_0_7/ACore/src/Host.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #8 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : This class is used as a helper class
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <unistd.h> // for gethostname
-#include <stdexcept>
-#include "Host.hpp"
-#include "Str.hpp"
-#include "Ecf.hpp"
-
-using namespace std;
-
-namespace ecf {
-
-Host::Host() {
-
- char hostNameArray[255];
- if (gethostname(hostNameArray,255) != -1) {
- the_host_name_ = string(hostNameArray);
- }
- else {
- std::runtime_error("Host::Host() failed, could not get host name?\n");
- }
-}
-
-std::string Host::name() const { return the_host_name_; }
-
-std::string Host::ecf_log_file(const std::string& port) const
-{
- return prefix_host_and_port(port,Ecf::LOG_FILE());
-}
-
-std::string Host::ecf_checkpt_file(const std::string& port) const
-{
- return prefix_host_and_port(port,Ecf::CHECKPT());
-}
-
-std::string Host::ecf_backup_checkpt_file(const std::string& port) const
-{
- return prefix_host_and_port(port,Ecf::BACKUP_CHECKPT());
-}
-
-std::string Host::ecf_lists_file(const std::string& port) const
-{
- return prefix_host_and_port(port,Str::WHITE_LIST_FILE());
-}
-
-std::string Host::prefix_host_and_port( const std::string& port,const std::string& file_name ) const
-{
- // The file name may include a path. /user/avi/fred.log
- // fred.log -> <host>.<port>.fred.log
- // /user/avi/fred.log -> /user/avi/fred.log
- if (!file_name.empty() && file_name.find("/") != std::string::npos ) {
- return file_name;
- }
- std::string ret = host_port_prefix(port);
- ret += ".";
- ret += file_name;
- return ret;
-}
-
-std::string Host::host_port_prefix(const std::string& port) const {
- std::string ret = the_host_name_;
- if (!port.empty()) {
- ret += ".";
- ret += port;
- }
- return ret;
-}
-
-}
diff --git a/ecflow_4_0_7/ACore/src/Host.hpp b/ecflow_4_0_7/ACore/src/Host.hpp
deleted file mode 100644
index 593d522..0000000
--- a/ecflow_4_0_7/ACore/src/Host.hpp
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef HOST_HPP_
-#define HOST_HPP_
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <boost/noncopyable.hpp>
-#include <string>
-
-namespace ecf {
-
-class Host : private boost::noncopyable {
-public:
- /// can throw std::runtime_error if the gethostname fails
- Host();
-
- /// return the host name
- std::string name() const;
-
- /// returns the log file name
- std::string ecf_log_file(const std::string& port) const;
-
- /// return checkPoint file
- std::string ecf_checkpt_file(const std::string& port) const;
-
- /// return backup checkPoint file
- std::string ecf_backup_checkpt_file(const std::string& port) const;
-
- /// return ecf.list file. White list file used for authentication
- std::string ecf_lists_file(const std::string& port) const;
-
- /// Given a port and file name, will return <host>.<port>.file_name
- std::string prefix_host_and_port( const std::string& port,const std::string& list_file ) const;
-
-private:
- std::string host_port_prefix(const std::string& port) const;
- std::string the_host_name_;
-};
-}
-#endif
diff --git a/ecflow_4_0_7/ACore/src/Indentor.cpp b/ecflow_4_0_7/ACore/src/Indentor.cpp
deleted file mode 100644
index f4f65f9..0000000
--- a/ecflow_4_0_7/ACore/src/Indentor.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-//============================================================================
-// Name : Indentor
-// Author : Avi
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "Indentor.hpp"
-
-namespace ecf {
-
-int Indentor::index_ = 0;
-
-
-std::ostream& Indentor::indent( std::ostream& os, int char_spaces)
-{
- int spaces = index_ * char_spaces;
- for (int i = 0; i != spaces; i++)
- os << " ";
- return os;
-}
-
-}
diff --git a/ecflow_4_0_7/ACore/src/Indentor.hpp b/ecflow_4_0_7/ACore/src/Indentor.hpp
deleted file mode 100644
index 703fc5b..0000000
--- a/ecflow_4_0_7/ACore/src/Indentor.hpp
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef INDENTOR_HPP_
-#define INDENTOR_HPP_
-//============================================================================
-// Name : Indentor
-// Author : Avi
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : This class is used as a helper class to provide indented output
-//============================================================================
-#include <ostream>
-
-namespace ecf {
-
-class Indentor {
-public:
- Indentor() {
- ++index_;
- }
- ~Indentor() {
- --index_;
- }
-
- static std::ostream& indent( std::ostream& os , int char_spaces = 2);
-
-private:
- static int index_;
-};
-
-}
-#endif
diff --git a/ecflow_4_0_7/ACore/src/Log.cpp b/ecflow_4_0_7/ACore/src/Log.cpp
deleted file mode 100644
index b2aa39d..0000000
--- a/ecflow_4_0_7/ACore/src/Log.cpp
+++ /dev/null
@@ -1,343 +0,0 @@
-//============================================================================
-// Name : Log
-// Author : Avi
-// Revision : $Revision: #57 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Simple singleton implementation of log
-//============================================================================
-#include <assert.h>
-#include <vector>
-#include <iostream>
-
-#include "boost/filesystem/path.hpp"
-#include "boost/filesystem/operations.hpp"
-
-#include "Log.hpp"
-#include "File.hpp"
-#include "Str.hpp"
-#include "Indentor.hpp"
-#include "TimeStamp.hpp"
-
-//#define DEBUG_BLOCKING_DISK_IO 1
-//#if DEBUG_BLOCKING_DISK_IO
-//#include "DurationTimer.hpp"
-//#endif
-
-using namespace std;
-namespace fs = boost::filesystem;
-
-namespace ecf {
-
-Log* Log::instance_ = NULL;
-bool LogToCout::flag_ = false;
-
-void Log::create(const std::string& filename)
-{
- if ( instance_ == NULL) {
- instance_ = new Log(filename);
- }
-}
-
-void Log::destroy()
-{
- if (instance_) instance_->flush();
-
- delete instance_;
- instance_ = NULL;
-}
-
-Log::Log(const std::string& fileName)
-: fileName_(fileName), logImpl_( new LogImpl(fileName) )
-{
-}
-
-Log::~Log()
-{
- delete logImpl_;
- logImpl_ = NULL;
-}
-
-
-void Log::log(Log::LogType lt,const std::string& message)
-{
- if (!logImpl_) {
- logImpl_ = new LogImpl(fileName_) ;
- }
- logImpl_->log(lt,message);
-}
-
-void Log::log_no_newline(Log::LogType lt,const std::string& message)
-{
- if (!logImpl_) {
- logImpl_ = new LogImpl(fileName_) ;
- }
- logImpl_->log_no_newline(lt,message);
-}
-
-void Log::append(const std::string& message)
-{
- if (!logImpl_) {
- logImpl_ = new LogImpl(fileName_) ;
- }
- logImpl_->append(message);
-}
-
-void Log::cache_time_stamp()
-{
- if (!logImpl_) {
- logImpl_ = new LogImpl(fileName_) ;
- }
- logImpl_->create_time_stamp();
-}
-
-const std::string& Log::get_cached_time_stamp() const
-{
- if (!logImpl_) {
- return Str::EMPTY();
- }
- return logImpl_->get_cached_time_stamp();
-}
-
-void Log::flush()
-{
- // will close ofstream and force data to be written to disk.
- // Forcing writing to physical medium can't be guaranteed though!
- delete logImpl_;
- logImpl_ = NULL;
-}
-
-void Log::clear()
-{
- flush();
-
- // Open and truncate the file.
- std::ofstream logfile(fileName_.c_str(), ios::out | ios::trunc);
- if (logfile.is_open()) {
- logfile.close(); // force buffers to flush
- }
-}
-
-void Log::new_path(const std::string& the_new_path)
-{
- check_new_path(the_new_path);
-
- // flush and close log file
- flush();
-
- fileName_ = the_new_path;
-}
-
-void Log::check_new_path(const std::string& new_path)
-{
- if (new_path.empty()) {
- throw std::runtime_error("Log::check_new_path: No path name specified for the new log file");
- }
-
- fs::path the_new_path = new_path;
-
- // Allow paths like "fred.log"
- fs::path parent_path = the_new_path.parent_path();
- //std::cout << "the_new_path.parent_path() = " << parent_path << "\n";
- if (!parent_path.empty()) {
-
- if (!fs::exists(parent_path)) {
- std::stringstream ss;
- ss << "Log::check_new_path: Can not create new log file, since the directory part " << parent_path << " does not exist\n";
- throw std::runtime_error(ss.str());
- }
- }
-
- // Now check that path does not correspond to a directory, can't use that as the new log file location
- if (fs::is_directory(the_new_path)) {
- std::stringstream ss;
- ss << "LogCmd::LogCmd: Can not create new log file, since the path correspond to a directory " << the_new_path << "\n";
- throw std::runtime_error(ss.str());
- }
-}
-
-std::string Log::path() const
-{
- if (!fileName_.empty() && fileName_[0] == '/') {
- // Path is absolute return as is
- return fileName_;
- }
- std::string the_path = fs::current_path().string();
- the_path += "/";
- the_path += fileName_;
- return the_path;
-}
-
-std::string Log::contents(int get_last_n_lines)
-{
- if ( get_last_n_lines == 0 ) {
- return string();
- }
-
- // Close the file. Log file may be buffered, hence flush first
- flush();
-
- std::string error_msg;
- if (get_last_n_lines > 0 ) {
- return File::get_last_n_lines(fileName_,get_last_n_lines,error_msg);
- }
- return File::get_first_n_lines(fileName_,std::abs(get_last_n_lines),error_msg);
-}
-
-void log(Log::LogType lt,const std::string& message)
-{
- if (Log::instance()) {
- Log::instance()->log(lt,message);
- }
- else {
- if (LogToCout::ok()) {
- Indentor::indent(cout) << message << endl;
- }
- }
-}
-
-void log_no_newline(Log::LogType lt,const std::string& message)
-{
- if (Log::instance()) {
- Log::instance()->log_no_newline(lt,message);
- }
- else {
- if (LogToCout::ok()) {
- Indentor::indent(cout) << message << endl;
- }
- }
-}
-
-void log_append(const std::string& message)
-{
- if (Log::instance()) {
- Log::instance()->append(message);
- }
- else {
- if (LogToCout::ok()) {
- Indentor::indent(cout) << message << endl;
- }
- }
-}
-
-void log_assert(char const* expr,char const* file, long line, const std::string& message)
-{
- std::stringstream ss;
- ss << "ASSERT failure: " << expr << " at " << file << ":" << line << " " << message;
- std::string assert_msg = ss.str();
- cerr << assert_msg << "\n";
- if (Log::instance()) {
- Log::instance()->log(Log::ERR,assert_msg);
- exit(1);
- }
-}
-
-// returns vec = MSG, LOG, ERR, WAR, DBG, OTH
-void Log::get_log_types(std::vector<std::string>& vec)
-{
- vec.reserve(6);
- vec.push_back("MSG");
- vec.push_back("LOG");
- vec.push_back("ERR");
- vec.push_back("WAR");
- vec.push_back("DBG");
- vec.push_back("OTH");
-}
-
-//======================================================================================================
-LogImpl::LogImpl(const std::string& filename)
-: file_(filename.c_str(), ios::out | ios::app)
-{
- if (!file_.is_open()) {
- std::cerr << "LogImpl::LogImpl: Could not open log file '" << filename << "'\n";
- std::runtime_error("LogImpl::LogImpl: Could not open log file " + filename);
- }
-}
-
-LogImpl::~LogImpl() {}
-
-
-static void append_log_type(std::string& str, Log::LogType lt)
-{
- switch (lt) {
- case Log::MSG: str.append("MSG:"); break;
- case Log::LOG: str.append("LOG:"); break;
- case Log::ERR: str.append("ERR:"); break;
- case Log::WAR: str.append("WAR:"); break;
- case Log::DBG: str.append("DBG:"); break;
- case Log::OTH: str.append("OTH:"); break;
- default: assert(false); break;
- }
-}
-
-void LogImpl::do_log(Log::LogType lt,const std::string& message, bool newline)
-{
-//#if DEBUG_BLOCKING_DISK_IO
-// ecf::DurationTimer timer;
-//#endif
-
- // XXX:[HH:MM:SS D.M.YYYY] chd:fullname [+additional information]
- // XXX:[HH:MM:SS D.M.YYYY] --<user_cmd> [+additional information]
- if (time_stamp_.empty() || lt == Log::ERR || lt == Log::WAR || lt == Log::DBG ) create_time_stamp();
-
- // re-use memory allocated to log_type_and_time_stamp_
- log_type_and_time_stamp_.clear();
- append_log_type(log_type_and_time_stamp_,lt);
- log_type_and_time_stamp_ += time_stamp_;
-
- if (message.find("\n") == std::string::npos) {
- file_ << log_type_and_time_stamp_ << message;
- if (newline) file_ << endl;
- }
- else {
- // If message has \n then split into multiple lines
- std::vector< std::string > lines;
- Str::split(message,lines,"\n");
- size_t theSize = lines.size();
- for(size_t i = 0; i < theSize; ++i) {
- file_ << log_type_and_time_stamp_ << lines[i] << endl; // flush EACH line
- }
- }
-
- // Check to see, if writing to file was ok.
- check_file_write(message);
-
-//#if DEBUG_BLOCKING_DISK_IO
-// long total_seconds = timer.elapsed().total_seconds();
-// if (total_seconds >= 1) {
-// std::stringstream ss;
-// ss << " took " << total_seconds << " seconds **************************************************************";
-// std::string time_taken = ss.str();
-// file_ << log_type_and_time_stamp_ << message << time_taken << "\n";
-// cout << log_type_and_time_stamp_ << message << time_taken << "\n";
-// }
-//#endif
-}
-
-void LogImpl::append(const std::string& message)
-{
- file_ << message << endl;
- check_file_write(message);
-}
-
-void LogImpl::check_file_write(const std::string& message) const
-{
- bool file_is_good = file_.good();
- if (!file_is_good) cout << "LogImpl::append: Could not write to log file! File system full?" << endl;
- if (LogToCout::ok() || !file_is_good) {
- Indentor::indent(cout) << message << endl;
- }
-}
-
-void LogImpl::create_time_stamp()
-{
- TimeStamp::now(time_stamp_);
-}
-
-}
diff --git a/ecflow_4_0_7/ACore/src/Log.hpp b/ecflow_4_0_7/ACore/src/Log.hpp
deleted file mode 100644
index 0cbcbbf..0000000
--- a/ecflow_4_0_7/ACore/src/Log.hpp
+++ /dev/null
@@ -1,166 +0,0 @@
-#ifndef LOG_HPP_
-#define LOG_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name : Log
-// Author : Avi
-// Revision : $Revision: #31 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Simple singleton implementation of log
-//
-// Please note how do we guarantee that file is actually written to disk:
-// a/ Each log entry should call std::endl
-// b/ Call flush() on the ofstream
-// c/ The two methods will force ofstream buffer to be written to disk
-// Well NOT REALLY dues to file caching by the OS.
-// The strongest hint we can give th OS to actually write to the physical medium
-// is to close the file. (This does not guarantee it, but is the closest we can achieve)
-//
-// Why is this an issue ? Testing on cross platform HPUX/linux, requires that
-// testing has access to the ECF log file. Initially the log file held an
-// ofstream of log file as a data member. However this meant that flushing
-// did not guarantee writing ECF log file to disk. Testing requires that we
-// are able to clear and copy the log file for comparison.
-// Hence we use another level of indirection, so that we able to close the
-// log file, and hence can ensure that it gets written to disk
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <vector>
-#include <string>
-#include <fstream>
-#include <sstream>
-#include <boost/noncopyable.hpp>
-#include <boost/lambda/lambda.hpp>
-
-namespace ecf {
-
-class LogImpl;
-
-class Log : private boost::noncopyable {
-public:
- enum LogType { MSG, LOG, ERR, WAR, DBG, OTH };
- static void create(const std::string& filename);
- static void destroy();
- static Log* instance() { return instance_;}
-
- /// If file is closed will open it
- /// Outputs t the file a message of type XXX:[HH:MM:SS D.M.YYYY] message
- /// where XXX is one of the LogType
- ///
- /// If the message has multiple newlines these are split
- /// LogType ERR,WAR,DBG will create a time stamp, otherwise the last cached
- /// time stamp is used.
- void log(LogType,const std::string& message);
-
- /// Single line message is placed in log file without a newline
- void log_no_newline(LogType,const std::string& message);
-
- /// Append to log file file and add newline
- void append(const std::string& message);
-
- /// Set the time stamp once for each request.
- void cache_time_stamp();
-
- /// Return the last cached time stamp. Used for time stamping edit history
- const std::string& get_cached_time_stamp() const;
-
- /// returns the contents of the log file, or the last n lines
- /// Will throw an std::runtime_error if the log file can not be opened
- /// Will close the file.
- static int get_last_n_lines_default() { return 100;}
- std::string contents(int get_last_n_lines);
-
- /// Will call flush and close the file. See notes above
- void flush();
-
- /// clear the log file. Required for testing
- void clear();
-
- /// Close the existing log file, and new start writing to the new location
- void new_path(const std::string& the_path);
-
- /// Returns the current log file path name
- std::string path() const;
-
- // returns vec = MSG, LOG, ERR, WAR, DBG, OTH
- static void get_log_types(std::vector<std::string>&);
-
-private:
-
- /// make sure path is not a directory & path has a parent directory.
- /// Will throw std::runtime_error for errors
- static void check_new_path(const std::string& the_new_path);
-
-private:
- ~Log();
- Log(const std::string& filename);
- static Log* instance_;
-
- std::string fileName_;
- LogImpl* logImpl_;
-};
-
-/// The LogImpl allows the ofstream object to be closed, and so provide strongest
-/// hint to OS that we want file to be written to physical medium.
-/// This is required for testing purposes, as each test run needs to clear/copy
-/// the log file
-class LogImpl : private boost::noncopyable {
-public:
- LogImpl(const std::string& filename);
- ~LogImpl();
-
- void log(Log::LogType lt,const std::string& message) { do_log(lt,message,true); }
- void log_no_newline(Log::LogType lt,const std::string& message) { do_log(lt,message,false); }
- void append(const std::string& message);
-
- void create_time_stamp();
- const std::string& get_cached_time_stamp() const { return time_stamp_;}
-
-private:
- void do_log(Log::LogType,const std::string& message, bool newline);
- void check_file_write(const std::string& message) const;
-
-private:
- std::string time_stamp_;
- mutable std::ofstream file_;
-
- std::string log_type_and_time_stamp_; // re-use memory
-};
-
-/// Utility class used for debug. Enables log file messages to be written to standard out
-class LogToCout : private boost::noncopyable {
-public:
- LogToCout() { flag_ = true;}
- ~LogToCout() { flag_ = false;}
- static bool ok() { return flag_;}
-private:
- static bool flag_;
-};
-
-void log(Log::LogType,const std::string& message);
-void log_no_newline(Log::LogType,const std::string& message);
-void log_append(const std::string& message);
-void log_assert(char const* expr,char const* file, long line, const std::string& message);
-
-// allow user to do the following:
-// LOG(Log::WAR,"this is " << path << " ok ");
-//
-// helper, see STRINGIZE() macro
-template <typename Functor>
-std::string stringize_f(Functor const & f) {
- std::ostringstream out;
- f(out);
- return out.str();
-}
-#define STRINGIZE(EXPRESSION) (ecf::stringize_f(boost::lambda::_1 << EXPRESSION))
-#define LOG(level, EXPRESSION) ecf::log(level, STRINGIZE(EXPRESSION))
-#define LOG_ASSERT(expr,EXPRESSION) ((expr)? ((void)0): ecf::log_assert(#expr, __FILE__, __LINE__, STRINGIZE(EXPRESSION)))
-
-}
-
-#endif
diff --git a/ecflow_4_0_7/ACore/src/LogVerification.cpp b/ecflow_4_0_7/ACore/src/LogVerification.cpp
deleted file mode 100644
index f411127..0000000
--- a/ecflow_4_0_7/ACore/src/LogVerification.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <iostream>
-#include <sstream>
-
-#include "LogVerification.hpp"
-#include "File.hpp"
-#include "Str.hpp"
-#include "NState.hpp"
-
-using namespace std;
-
-namespace ecf {
-
-bool LogVerification::extractNodePathAndState( const std::string& logfile,
- std::vector< std::pair< std::string, std::string > >& pathStateVec,
- std::string& errorMsg )
-{
- // The log file format we are interested is :
- // 0 1 2 3
- // LOG:[14:37:00 20.5.2010] submitted: /test_abort_cmd/family0/abort duration_(00:00:00) initTime_(2010-May-20 14:37:00) suiteTime_(2010-May-20 14:37:00)
-
- // Open log file, and collate of the node paths and corresponding states
- std::vector<std::string> lines;
- if (!File::splitFileIntoLines(logfile,lines)) {
- errorMsg = "Could not open log file " + logfile + " for test verification";
- return false;
- }
-
- int line_number = 0;
- for(std::vector<std::string>::iterator i=lines.begin(); i!=lines.end(); ++i) {
-
- line_number++;
- if ((*i).find("LOG:") == std::string::npos) {
- continue; // State changes have type Log::LOG
- }
-
- std::vector< std::string > lineTokens;
- Str::split(*i, lineTokens);
- if (lineTokens.size() < 3) {
- continue;
- }
-
- std::string theState = lineTokens[2];
- theState.erase( theState.size() -1); // remove ':' at the end
- if (!NState::isValid( theState )) {
- continue;
- }
- // cout << line_number << Str::COLON() << *i << "\n";
-
- pathStateVec.push_back( std::make_pair(lineTokens[3], theState ) );
- }
- return true;
-}
-
-static bool searchVec(
- const std::vector< std::pair< std::string, std::string > >& goldenLines,
- const std::pair< std::string, std::string >& line,
- size_t start_index)
-{
- for(size_t i = start_index; i < goldenLines.size(); i++) {
- if ( goldenLines[i] == line) {
- return true;
- }
- }
- return false;
-}
-
-bool LogVerification::compareNodeStates( const std::string& logfile, const std::string& goldenRefLogFile, std::string& errorMsg)
-{
- // Open log files, and extract just the state changes
- std::vector< std::pair< std::string, std::string > > lines,goldenLines;
- if (!extractNodePathAndState(logfile,lines,errorMsg)) return false;
- if (!extractNodePathAndState(goldenRefLogFile,goldenLines,errorMsg)) return false;
-
- if ( lines != goldenLines) {
- std::stringstream ss;
- ss << "Log file " << logfile << " does not match golden reference file " << goldenRefLogFile << "\n";
- if (lines.size() != goldenLines.size()) ss << "Expected log file size " << goldenLines.size() << " but found " << lines.size() <<"\n";
-
- bool errorFnd = false;
- for(size_t i=0; i < lines.size() || i < goldenLines.size(); ++i) {
-
- std::string theLine,theGoldenLine;
- if (i < lines.size() ) theLine = lines[i].second + Str::COLON() + lines[i].first;
- if (i < goldenLines.size()) theGoldenLine = goldenLines[i].second + Str::COLON() + goldenLines[i].first;
-
- if (i < lines.size() && i < goldenLines.size()) {
-
- if (lines[i] != goldenLines[i]) {
- // Please note that we can't do an exact compare for certain state changes
- // submitted -->active
- // active -->complete
- // Since this can be OS/scheduler dependent and hence order dependent
- // To compensate look search Golden file
- if (lines[i].second == "submitted" || lines[i].second == "active" || lines[i].second == "complete") {
- // search for line in golden file
- if (searchVec(goldenLines,lines[i],0)) {
- continue;
- }
- }
-
- ss << "Mismatch at " << i << " log(" << theLine << ") golden(" << theGoldenLine << ")\n";
- errorFnd = true;
- }
- else {
- ss << " " << i << " log(" << theLine << ") golden(" << theGoldenLine << ")\n";
- }
- }
- else {
- errorFnd = true;
- ss << "Mismatch at " << i ;
- if (i < lines.size() ) ss << " log(" << theLine << ") ";
- else ss << " log( ---- ) ";
-
- if (i < goldenLines.size()) ss << "golden(" << theGoldenLine << ")\n";
- else ss << "golden( --- )\n";
- }
- }
- if (errorFnd) errorMsg = ss.str();
- }
-
- return errorMsg.empty();
-}
-
-}
diff --git a/ecflow_4_0_7/ACore/src/LogVerification.hpp b/ecflow_4_0_7/ACore/src/LogVerification.hpp
deleted file mode 100644
index 041cbed..0000000
--- a/ecflow_4_0_7/ACore/src/LogVerification.hpp
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef LOG_VERIFICATION_HPP_
-#define LOG_VERIFICATION_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <vector>
-#include <string>
-#include <boost/noncopyable.hpp>
-
-namespace ecf {
-
-class LogVerification : private boost::noncopyable {
-public:
-
- /// Given a log file, extract in order. The node_path and the state
- static bool extractNodePathAndState(const std::string& logfile,
- std::vector< std::pair<std::string,std::string> >& pathStateVec,
- std::string& errorMsg);
-
- /// Will compare the input log file, with gold reference.
- /// Will compare the node state changes only
- /// Compensate for states that are scheduler dependent
- static bool compareNodeStates( const std::string& logfile, const std::string& goldenRefLogFile, std::string& errormsg);
-
-private:
- LogVerification() {}
-};
-}
-#endif
diff --git a/ecflow_4_0_7/ACore/src/NOrder.cpp b/ecflow_4_0_7/ACore/src/NOrder.cpp
deleted file mode 100644
index 6dde47d..0000000
--- a/ecflow_4_0_7/ACore/src/NOrder.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "NOrder.hpp"
-#include <assert.h>
-
-std::string NOrder::toString(NOrder::Order s) {
- switch (s) {
- case NOrder::TOP: return "top"; break;
- case NOrder::BOTTOM: return "bottom"; break;
- case NOrder::ALPHA: return "alpha"; break;
- case NOrder::ORDER: return "order"; break;
- case NOrder::UP: return "up"; break;
- case NOrder::DOWN: return "down"; break;
- default: assert(false); break;
- }
- assert(false);
- return std::string();
-}
-
-NOrder::Order NOrder::toOrder(const std::string& str)
-{
- if (str == "top") return NOrder::TOP;
- if (str == "bottom") return NOrder::BOTTOM;
- if (str == "alpha") return NOrder::ALPHA;
- if (str == "order") return NOrder::ORDER;
- if (str == "up") return NOrder::UP;
- if (str == "down") return NOrder::DOWN;
- assert(false);
- return NOrder::TOP;
-}
-
-bool NOrder::isValid(const std::string& state)
-{
- if (state == "top") return true;
- if (state == "bottom") return true;
- if (state == "alpha") return true;
- if (state == "order") return true;
- if (state == "up") return true;
- if (state == "down") return true;
- return false;
-}
-
diff --git a/ecflow_4_0_7/ACore/src/NOrder.hpp b/ecflow_4_0_7/ACore/src/NOrder.hpp
deleted file mode 100644
index c69f0b7..0000000
--- a/ecflow_4_0_7/ACore/src/NOrder.hpp
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef NORDER_HPP_
-#define NORDER_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <string>
-
-class NOrder {
- NOrder() {}
-public:
- enum Order { TOP, BOTTOM, ALPHA, ORDER, UP, DOWN };
-
- static std::string toString(NOrder::Order);
- static NOrder::Order toOrder(const std::string&);
- static bool isValid(const std::string& order);
-};
-
-#endif
diff --git a/ecflow_4_0_7/ACore/src/NState.cpp b/ecflow_4_0_7/ACore/src/NState.cpp
deleted file mode 100644
index fda5716..0000000
--- a/ecflow_4_0_7/ACore/src/NState.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #20 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <assert.h>
-#include <iostream>
-#include "NState.hpp"
-#include "Ecf.hpp"
-
-void NState::setState( State s ) {
- state_= s;
- state_change_no_ = Ecf::incr_state_change_no();
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "NState::setState\n";
-#endif
-}
-
-const char* NState::toString( NState::State s ) {
- switch ( s ) {
- case NState::UNKNOWN:
- return "unknown";
- break;
- case NState::COMPLETE:
- return "complete";
- break;
- case NState::QUEUED:
- return "queued";
- break;
- case NState::ABORTED:
- return "aborted";
- break;
- case NState::SUBMITTED:
- return "submitted";
- break;
- case NState::ACTIVE:
- return "active";
- break;
- default:
- assert(false); break;
- }
- assert(false);
- return NULL;
-}
-
-NState::State NState::toState( const std::string& str ) {
- if ( str == "complete" )
- return NState::COMPLETE;
- if ( str == "unknown" )
- return NState::UNKNOWN;
- if ( str == "queued" )
- return NState::QUEUED;
- if ( str == "aborted" )
- return NState::ABORTED;
- if ( str == "submitted" )
- return NState::SUBMITTED;
- if ( str == "active" )
- return NState::ACTIVE;
- assert(false);
- return NState::UNKNOWN;
-}
-
-bool NState::isValid( const std::string& state ) {
- if ( state == "complete" )
- return true;
- if ( state == "unknown" )
- return true;
- if ( state == "queued" )
- return true;
- if ( state == "aborted" )
- return true;
- if ( state == "submitted" )
- return true;
- if ( state == "active" )
- return true;
- return false;
-}
-
-std::vector< std::string > NState::allStates() {
- std::vector< std::string > vec;
- vec.reserve( 6 );
- vec.push_back( "complete" );
- vec.push_back( "unknown" );
- vec.push_back( "queued" );
- vec.push_back( "aborted" );
- vec.push_back( "submitted" );
- vec.push_back( "active" );
- return vec;
-}
-
-std::vector<NState::State> NState::states()
-{
- std::vector< NState::State > vec;
- vec.reserve( 6 );
- vec.push_back( NState::UNKNOWN );
- vec.push_back( NState::COMPLETE );
- vec.push_back( NState::QUEUED );
- vec.push_back( NState::ABORTED );
- vec.push_back( NState::SUBMITTED );
- vec.push_back( NState::ACTIVE );
- return vec;
-}
diff --git a/ecflow_4_0_7/ACore/src/NState.hpp b/ecflow_4_0_7/ACore/src/NState.hpp
deleted file mode 100644
index fe856e5..0000000
--- a/ecflow_4_0_7/ACore/src/NState.hpp
+++ /dev/null
@@ -1,69 +0,0 @@
-#ifndef NSTATE_HPP_
-#define NSTATE_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #16 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <string>
-#include <vector>
-#include <boost/serialization/serialization.hpp>
-#include <boost/serialization/level.hpp>
-#include <boost/serialization/tracking.hpp>
-
-// NState: stores the state of a node.
-// *The class NState just used to define the enum, however we also
-// needed to know when the state changed. Hence the use of state_change_no
-// Uses default copy constructor and destructor, and equality
-class NState {
-public:
- enum State { UNKNOWN =0, COMPLETE=1, QUEUED=2, ABORTED=3, SUBMITTED=4, ACTIVE=5 };
- NState(State s): state_(s), state_change_no_(0) {}
- NState(): state_(UNKNOWN),state_change_no_(0) {}
-
- State state() const { return state_;}
- void setState(State);
-
- // The state_change_no is never reset. Must be incremented if it can affect equality
- unsigned int state_change_no() const { return state_change_no_; }
-
- bool operator==(const NState& rhs) const { return state_ == rhs.state_;}
- bool operator!=(const NState& rhs) const { return state_ != rhs.state_;}
- bool operator==(State s) const { return s == state_;}
- bool operator!=(State s) const { return s != state_;}
-
- static const char* toString(NState::State s);
- static const char* toString(const NState& ns) { return toString(ns.state());}
- static NState::State toState(const std::string& state);
- static bool isValid(const std::string& state);
- static std::vector<std::string> allStates();
- static std::vector<NState::State> states();
-
-private:
- State state_;
- unsigned int state_change_no_; // *not* persisted, only used on server side
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/)
- {
- ar & state_;
- }
-};
-
-// This should ONLY be added to objects that are *NOT* serialised through a pointer
-BOOST_CLASS_IMPLEMENTATION(NState, boost::serialization::object_serializable);
-BOOST_CLASS_TRACKING(NState,boost::serialization::track_never);
-
-#endif
diff --git a/ecflow_4_0_7/ACore/src/NodePath.cpp b/ecflow_4_0_7/ACore/src/NodePath.cpp
deleted file mode 100644
index f2710ab..0000000
--- a/ecflow_4_0_7/ACore/src/NodePath.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #9 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <iostream>
-#include <boost/algorithm/string/trim.hpp>
-
-#include "NodePath.hpp"
-#include "Str.hpp"
-
-using namespace ecf;
-
-void NodePath::split( const std::string& path, std::vector<std::string>& thePath)
-{
- /// The path is of the form "/suite/family/task"
- Str::split(path,thePath,Str::PATH_SEPERATOR());
-
- // This is the original implementation, found to be a lot slower
- // See timing tests at the end of TestNodePathextractor.cpp
- // typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
- // boost::char_separator<char> sep("/");
- // tokenizer tokens(path_, sep);
- // copy(tokens.begin(), tokens.end(), back_inserter(thePath));
-}
-
-bool NodePath::extractHostPort(const std::string& path,std::string& host, std::string& port)
-{
- if (path.empty()) return false;
-
- std::vector<std::string> thePath;
- NodePath::split(path,thePath);
-
- if (thePath.empty()) return false;
-
- //<host>:<port>/suite/family/task
- // first path should be of form <host>:<port>
- size_t colonPos = thePath[0].find_first_of(':');
- if (colonPos == std::string::npos) return false;
-
- host = thePath[0].substr(0,colonPos);
- port = thePath[0].substr(colonPos+1);
-
- boost::algorithm::trim(host);
- boost::algorithm::trim(port);
- if (host.empty()) return false;
- if (port.empty()) return false;
-
- return true;
-}
-
-
-std::string NodePath::createPath(const std::vector<std::string>& vec)
-{
- if (vec.empty()) return std::string();
-
- std::string ret;
- size_t size = vec.size();
- for(size_t i = 0; i < size; i++) {
- ret += Str::PATH_SEPERATOR();
- ret += vec[i];
- }
- return ret;
-}
-
-std::string NodePath::removeHostPortFromPath(const std::string& path)
-{
- std::vector<std::string> pathVec;
- NodePath::split(path,pathVec);
- pathVec.erase( pathVec.begin() );
- return NodePath::createPath(pathVec);
-}
-
diff --git a/ecflow_4_0_7/ACore/src/NodePath.hpp b/ecflow_4_0_7/ACore/src/NodePath.hpp
deleted file mode 100644
index 3d497c2..0000000
--- a/ecflow_4_0_7/ACore/src/NodePath.hpp
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef NODEPATH_HPP_
-#define NODEPATH_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <boost/noncopyable.hpp>
-#include <string>
-#include <vector>
-
-class NodePath : private boost::noncopyable {
-public:
- /// returns the path as a vector of strings, preserving the order
- /// Note: multiple path separator '/' are treated as one separator.
- /// Mimics unix path conventions. hence
- /// '/suite//family///task' will be extracted as 'suite','family','task'
- static void split(const std::string& path,std::vector<std::string>&);
-
- /// If the path name if form:
- /// //<host>:<port>/suite/family/task
- /// The extract the host and port, return OK if successful
- static bool extractHostPort(const std::string& path, std::string& host, std::string& port);
-
- /// Given a vector of strings , create a path. "suite","family", returns /suite/family
- static std::string createPath(const std::vector<std::string>&);
-
- /// Given a path like: //localhost:3141/suite/family/task
- /// returns /suite/family/task
- static std::string removeHostPortFromPath(const std::string& path);
-
-private:
- NodePath();
-
-};
-#endif
diff --git a/ecflow_4_0_7/ACore/src/Passwd.cpp b/ecflow_4_0_7/ACore/src/Passwd.cpp
deleted file mode 100644
index a135ceb..0000000
--- a/ecflow_4_0_7/ACore/src/Passwd.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-//============================================================================
-// Name : Passwd.hpp
-// Author : Avi
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "Passwd.hpp"
-#include <iostream>
-#include <sys/types.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-//extern char *crypt(const char *key, const char *salt);
-
-
-double ecf_drand48();
-
-
-std::string Passwd::generate()
-{
- char pw[9];
- for (int i = 0; i < 8; i++) { /* generate a random password */
-
- pw[i] = 64.0 * ecf_drand48() + '.'; /* Just crack this one! */
- if ( pw[i] > '9' ) pw[i] += 7;
- if ( pw[i] > 'Z' ) pw[i] += 6;
- }
- pw[8] = '\0';
- return std::string (pw);
-}
-
-//std::string Passwd::doCrypt( const std::string& passwd ) {
-// /**************************************************************************
-// ? Crypt the passwd.
-// = Crypted password in static area.
-// ************************************o*************************************/
-// char salt[3];
-//
-// for (int i = 0; i < 2; i++) {
-// salt[i] = 64.0 * ecf_drand48() + '.';
-// if ( salt[i] > '9' ) salt[i] += 7;
-// if ( salt[i] > 'Z' ) salt[i] += 6;
-// }
-// salt[2] = '\0';
-//
-// return std::string( crypt( passwd.c_str(), salt ));
-//}
-
-
-double ecf_drand48()
-/**************************************************************************
- ? Random number with time dependent seed.
- = [0.0 - 1.0)
- ~ drand48(3) srand48(3) rand(3)
- ************************************o*************************************/
-{
- // extern double drand48();
- // extern void srand48();
- static int been_here;
-
- if ( !been_here ) {
-#if defined(RAND_ONLY)
- srand( (int) time(NULL) + getpid() );
-#else
- srand48( (long) time( NULL ) + getpid() );
-#endif
- been_here = 1;
- }
-
-#if defined(RAND_ONLY)
- return (rand()&0xffff) / 65535.0001;
-#else
- return drand48();
-#endif
-}
diff --git a/ecflow_4_0_7/ACore/src/Passwd.hpp b/ecflow_4_0_7/ACore/src/Passwd.hpp
deleted file mode 100644
index 1f6400f..0000000
--- a/ecflow_4_0_7/ACore/src/Passwd.hpp
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef PASSWD_HPP_
-#define PASSWD_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-// The tasks send by the ECF will have GENERATED PASSWORD that is not
-// stored into the any file (except the job file). It only exist in the
-// ECF_server-memory. If the ECF server fails and a new one is started, it must be
-// told (by operator) to accept the messages from the unknown jobs.
-//
-// The GENERATED PASSWORDs are stored into the CHECKPOINT file. So if the
-// ECF fails and is RESTARTed from a valid CHECKPOINT file, the ECF gets
-// to know about the tasks.
-//
-// The user passwords are kept in a file. When ever an user logs into
-// the ECF or changes the "level" of privileges while already in the
-// file is consulted.
-//============================================================================
-
-#include <boost/noncopyable.hpp>
-#include <string>
-
-class Passwd : private boost::noncopyable {
-public:
-
- /// generate a random password
- static std::string generate();
-
- /// encrypt the password
-// static std::string doCrypt( const std::string& generated);
-
-private:
- Passwd();
-};
-
-#endif
diff --git a/ecflow_4_0_7/ACore/src/PrintStyle.cpp b/ecflow_4_0_7/ACore/src/PrintStyle.cpp
deleted file mode 100644
index 3461f0a..0000000
--- a/ecflow_4_0_7/ACore/src/PrintStyle.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "PrintStyle.hpp"
-#include <iostream>
-
-static PrintStyle::Type_t style_ = PrintStyle::NOTHING;
-
-PrintStyle::Type_t PrintStyle::getStyle()
-{
- return style_;
-}
-
-void PrintStyle::setStyle(PrintStyle::Type_t f)
-{
- style_ = f;
-}
-
-bool PrintStyle::defsStyle() {
- if (getStyle() == PrintStyle::DEFS || getStyle() == PrintStyle::NOTHING) {
- return true;
- }
- return false;
-}
-
-std::string PrintStyle::to_string()
-{
- return to_string(getStyle());
-}
-
-std::string PrintStyle::to_string(PrintStyle::Type_t t)
-{
- switch ( t ) {
- case PrintStyle::NOTHING: return "NOTHING";break;
- case PrintStyle::DEFS: return "DEFS";break;
- case PrintStyle::STATE: return "STATE";break;
- case PrintStyle::MIGRATE: return "MIGRATE";break;
- }
- return std::string();
-}
-
diff --git a/ecflow_4_0_7/ACore/src/PrintStyle.hpp b/ecflow_4_0_7/ACore/src/PrintStyle.hpp
deleted file mode 100644
index 043877c..0000000
--- a/ecflow_4_0_7/ACore/src/PrintStyle.hpp
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef PRINTSTYLE_HPP_
-#define PRINTSTYLE_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #12 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <boost/noncopyable.hpp>
-#include <string>
-
-class PrintStyle : private boost::noncopyable {
-public:
- // Used by the show Cmd
- enum Type_t {
- NOTHING = 0, // Does nothing
- DEFS = 1, // Output the definition that is fully parse-able
- STATE = 2, // Output definition that includes Node state, and AST, fully parseable
- MIGRATE = 3 // Output the definition that is fully parse-able & includes state
- };
-
- PrintStyle(Type_t t) : old_style_(getStyle()) { setStyle(t);}
- ~PrintStyle() { setStyle(old_style_); } // reset to old style on destruction
-
-
- /// We want to control the output, so that we can dump in old style defs format
- /// or choose to dump for debug.
- static Type_t getStyle() ;
- static void setStyle(Type_t) ;
-
- static bool defsStyle();
-
- // return current style as a string
- static std::string to_string();
- static std::string to_string(PrintStyle::Type_t);
-
-private:
- Type_t old_style_;
-};
-
-#endif
diff --git a/ecflow_4_0_7/ACore/src/SState.cpp b/ecflow_4_0_7/ACore/src/SState.cpp
deleted file mode 100644
index 8acbd04..0000000
--- a/ecflow_4_0_7/ACore/src/SState.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "SState.hpp"
-#include <assert.h>
-
-std::string SState::to_string(int status)
-{
- if (status == 0) return "HALTED";
- else if (status == 1) return "SHUTDOWN";
- else if (status == 2) return "RUNNING";
- return "UNKNOWN??";
-}
-
-std::string SState::to_string(SState::State state)
-{
- switch (state) {
- case SState::HALTED: return "HALTED"; break;
- case SState::SHUTDOWN: return "SHUTDOWN"; break;
- case SState::RUNNING: return "RUNNING"; break;
- }
- return "UNKNOWN??";
-}
-
-SState::State SState::toState( const std::string& str ) {
- if ( str == "HALTED" )
- return SState::HALTED;
- if ( str == "SHUTDOWN" )
- return SState::SHUTDOWN;
- if ( str == "RUNNING" )
- return SState::RUNNING;
- assert(false);
- return SState::HALTED;
-}
-
-bool SState::isValid( const std::string& state ) {
- if ( state == "HALTED" )
- return true;
- if ( state == "SHUTDOWN" )
- return true;
- if ( state == "queued" )
- return true;
- if ( state == "RUNNING" )
- return true;
- return false;
-}
diff --git a/ecflow_4_0_7/ACore/src/SState.hpp b/ecflow_4_0_7/ACore/src/SState.hpp
deleted file mode 100644
index 3ef9419..0000000
--- a/ecflow_4_0_7/ACore/src/SState.hpp
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef S_STATE_HPP_
-#define S_STATE_HPP_
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <string>
-#include <boost/noncopyable.hpp>
-
-class SState : private boost::noncopyable {
-public:
- /// The following table shows the effect of state, on server behaviour:
- ///
- /// User Request Task Request Job Scheduling Check-pointing
- /// RUNNING yes yes yes yes
- /// SHUTDOWN yes yes no yes
- /// HALTED yes no no no
- enum State {
- HALTED,
- SHUTDOWN,
- RUNNING
- };
-
- /// Given an integer return the server state as a string.
- /// if int is not 0,1,2 return "UNKNOWN
- static std::string to_string(int status);
- static std::string to_string(SState::State);
-
- static SState::State toState(const std::string& state);
- static bool isValid(const std::string& state);
-
-private:
- SState();
-};
-#endif
diff --git a/ecflow_4_0_7/ACore/src/Serialization.hpp b/ecflow_4_0_7/ACore/src/Serialization.hpp
deleted file mode 100644
index 18a494c..0000000
--- a/ecflow_4_0_7/ACore/src/Serialization.hpp
+++ /dev/null
@@ -1,135 +0,0 @@
-#ifndef SERIALIZATION_HPP_
-#define SERIALIZATION_HPP_
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #14 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Simple class that defines the Archive types used for
-// Serialisation
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <string>
-#include <iostream>
-#include <fstream>
-
-#include "boost_archive.hpp"
-#include "Archive.hpp"
-
-namespace ecf {
-
-/// These function do *NOT* trap boost::archive::archive_exception since we want it
-/// to propagate up.
-
-template< typename T >
-void save(const std::string& fileName, const T& ts, ecf::Archive::Type at = ecf::Archive::default_archive())
-{
- // Argument added if in future we want to allow multiple archives, so we can choose
-#if defined(BINARY_ARCHIVE)
- std::ofstream ofs( fileName.c_str(), std::ios::binary );
- boost::archive::binary_oarchive oa( ofs );
- oa << ts;
-#elif defined(PORTABLE_BINARY_ARCHIVE)
- std::ofstream ofs( fileName.c_str(), std::ios::binary );
- portable_binary_oarchive oa(ofs);
- oa << ts;
-#elif defined(EOS_PORTABLE_BINARY_ARCHIVE)
- std::ofstream ofs( fileName.c_str(), std::ios::binary );
- eos::portable_oarchive oa(ofs);
- oa << ts;
-#else
- std::ofstream ofs( fileName.c_str() );
- boost::archive::text_oarchive oa( ofs );
- oa << ts;
-#endif
-}
-
-template< typename T >
-void save_as_string(std::string& outbound_data, const T& t)
-{
- std::ostringstream archive_stream;
-
-#if defined(BINARY_ARCHIVE)
- boost::archive::binary_oarchive archive( archive_stream );
- archive << t;
- outbound_data = archive_stream.str();
- // std::cout << "save_as_string BINARY " << outbound_data_ << "\n";
-#elif defined(PORTABLE_BINARY_ARCHIVE)
- portable_binary_oarchive archive( archive_stream );
- archive << t;
- outbound_data = archive_stream.str();
- // std::cout << "save_as_string PORTABLE_BINARY " << outbound_data_ << "\n";
-#elif defined(EOS_PORTABLE_BINARY_ARCHIVE)
- eos::portable_oarchive archive( archive_stream );
- archive << t;
- outbound_data = archive_stream.str();
- // std::cout << "save_as_string EOS_PORTABLE_BINARY " << outbound_data_ << "\n";
-#else
- boost::archive::text_oarchive archive( archive_stream );
- archive << t;
- outbound_data = archive_stream.str();
-#endif
-}
-
-template< typename T >
-void restore_from_string(const std::string& archive_data, T& t)
-{
- std::istringstream archive_stream(archive_data);
-
-#if defined(BINARY_ARCHIVE)
- // std::cout << "restore_from_string Archive BINARY\n";
- boost::archive::binary_iarchive archive( archive_stream );
-
-#elif defined(PORTABLE_BINARY_ARCHIVE)
- // std::cout << "restore_from_string Archive PORTABLE_BINARY\n";
- portable_binary_iarchive archive( archive_stream );
-
-#elif defined(EOS_PORTABLE_BINARY_ARCHIVE)
- // std::cout << "restore_from_string Archive EOS_PORTABLE_BINARY\n";
- eos::portable_iarchive archive( archive_stream );
-
-#else
- // std::cout << "restore_from_string Archive TEXT\n";
- boost::archive::text_iarchive archive( archive_stream );
-
-#endif
-
- archive >> t;
-}
-
-
-
-template< typename T >
-void restore(const std::string& fileName, T& restored, ecf::Archive::Type at = ecf::Archive::default_archive())
-{
- // Argument added if in future we want to allow multiple archives, so we can choose
-
-#if defined(BINARY_ARCHIVE)
- std::ifstream ifs( fileName.c_str(), std::ios::binary );
- boost::archive::binary_iarchive ia( ifs );
- ia >> restored;
-#elif defined(PORTABLE_BINARY_ARCHIVE)
- std::ifstream ifs( fileName.c_str(), std::ios::binary );
- portable_binary_iarchive ia( ifs );
- ia >> restored;
-#elif defined(EOS_PORTABLE_BINARY_ARCHIVE)
- std::ifstream ifs( fileName.c_str(), std::ios::binary );
- eos::portable_iarchive ia( ifs );
- ia >> restored;
-#else
- std::ifstream ifs( fileName.c_str() );
- boost::archive::text_iarchive ia( ifs );
- ia >> restored;
-#endif
-}
-
-}
-#endif
diff --git a/ecflow_4_0_7/ACore/src/SerializationTest.hpp b/ecflow_4_0_7/ACore/src/SerializationTest.hpp
deleted file mode 100644
index 3bdf0cd..0000000
--- a/ecflow_4_0_7/ACore/src/SerializationTest.hpp
+++ /dev/null
@@ -1,71 +0,0 @@
-#ifndef SERIALIZATION_TEST_HPP_
-#define SERIALIZATION_TEST_HPP_
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #16 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Simple class that defines the Archive types used for
-// Serialisation
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "Serialization.hpp"
-
-namespace ecf {
-
-// The following template functions are used test/debug only
-template < typename T >
-void do_restore(const std::string& fileName, const T& saved)
-{
- T restored;
- try { ecf::restore(fileName,restored); }
- catch ( std::exception& e) { BOOST_CHECK_MESSAGE(false,"Restore failed because: " << e.what()); }
- BOOST_CHECK_MESSAGE(saved == restored,"save and restored don't match for " << fileName << "\n");
-// BOOST_CHECK_MESSAGE(saved == restored," save and restored don't match\n" << saved << "\n" << restored );
-}
-
-template < typename T >
-void doRestore(const std::string& fileName, const T& saved)
-{
- do_restore(fileName,saved);
- std::remove(fileName.c_str());
-}
-
-template < typename T >
-void doSave(const std::string& fileName, const T& saved)
-{
- try { ecf::save(fileName,saved); }
- catch ( std::exception& e) { BOOST_CHECK_MESSAGE(false,"Save failed because: " << e.what()); }
-}
-
-template < typename T >
-void doSave(const std::string& fileName)
-{
- T saved;
- doSave(fileName,saved);
-}
-
-template < typename T >
-void doSaveAndRestore(const std::string& fileName, const T& saved)
-{
- doSave(fileName,saved);
- doRestore(fileName,saved);
-}
-
-template < typename T >
-void doSaveAndRestore(const std::string& fileName)
-{
- T saved;
- doSaveAndRestore(fileName,saved);
-}
-
-}
-#endif
diff --git a/ecflow_4_0_7/ACore/src/Stl.hpp b/ecflow_4_0_7/ACore/src/Stl.hpp
deleted file mode 100644
index 86de2e7..0000000
--- a/ecflow_4_0_7/ACore/src/Stl.hpp
+++ /dev/null
@@ -1,71 +0,0 @@
-#ifndef STL_HPP_
-#define STL_HPP_
-//============================================================================
-// Name : stl
-// Author : Avi
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-/*****************************************************************************
- * Standard Library Include Files *
- *****************************************************************************/
-#include <algorithm> //for for_each()
-//#include <iostream>
-
-
-namespace ecf
-{
- /// Helper struct that will aid the deletion of Pointer from a container
- template <typename T> struct TSeqDeletor {
- void operator () (T pointer) {
- // std::cout << "Destroy of this pointer" << std::endl;
- delete pointer;
- pointer = 0;
- }
- };
- /// This function can be used to delete the pointers in a container
- /// i.e int main (int argc, char **argv) {
- /// std::vector <std::string *> vect;
- /// vect.push_back (new std::string ("Stephane"));
- /// DeletePtrs (vect);
- /// }
- template <typename Container> void DeletePtrs (Container& pContainer) {
- std::for_each( pContainer.begin (),
- pContainer.end (),
- TSeqDeletor<typename Container::value_type> ());
- pContainer.clear();
- }
-
-
- /// Helper struct that will aid the deletion of Pointer from a Associative container
- template <typename TPair> struct TAsoDeletor {
- void operator () (TPair& tElem) {
- if(tElem.second) {
- delete tElem.second;
- }
- }
- };
- /// This function can be used to delete the pointers in a Assoc container
- /// i.e int main (int argc, char **argv) {
- /// std::map <int,std::string *> theMap;
- /// theMap[0] = new std::string ("Stephane");
- /// AssoDeletePtrs(theMap);
- /// }
- template <typename Container> void AssoDeletePtrs (Container& pContainer) {
- std::for_each( pContainer.begin (),
- pContainer.end (),
- TAsoDeletor<typename Container::value_type> ());
- pContainer.clear();
- }
-}
-
-#endif /* STL_HPP_ */
diff --git a/ecflow_4_0_7/ACore/src/Str.cpp b/ecflow_4_0_7/ACore/src/Str.cpp
deleted file mode 100644
index 690f5a8..0000000
--- a/ecflow_4_0_7/ACore/src/Str.cpp
+++ /dev/null
@@ -1,346 +0,0 @@
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #49 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : This class is used as a helper class
-//============================================================================
-#include <boost/algorithm/string/replace.hpp>
-#include <boost/lexical_cast.hpp>
-
-#include "Str.hpp"
-
-using namespace std;
-
-namespace ecf {
-
-const char* VALID_NODE_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.";
-
-const char* Str::CHILD_CMD() { static const char* CHILD_CMD = "chd:"; return CHILD_CMD; }
-const char* Str::USER_CMD() { static const char* USER_CMD = "--"; return USER_CMD; }
-const char* Str::SVR_CMD() { static const char* SVR_CMD = "svr:"; return SVR_CMD; } // Only for automatic check_pt
-
-const std::string& Str::EMPTY() { static std::string empty = std::string(); return empty;}
-const std::string& Str::ROOT_PATH() { static std::string root_path = "/"; return root_path;}
-const std::string& Str::PATH_SEPERATOR() { static std::string path_sep = "/"; return path_sep;}
-const std::string& Str::COLON() { static std::string colon = ":"; return colon;}
-
-
-const std::string& Str::STATE_CHANGE() { static std::string state_change = " state change "; return state_change;}
-
-const std::string& Str::TASK() { static std::string task = "TASK"; return task; }
-const std::string& Str::FAMILY() { static std::string family = "FAMILY"; return family;}
-const std::string& Str::SUITE() { static std::string suite = "SUITE"; return suite;}
-const std::string& Str::ALIAS() { static std::string alias = "ALIAS"; return alias; }
-
-const std::string& Str::DEFAULT_PORT_NUMBER() { static std::string port_number = "3141"; return port_number;}
-const std::string& Str::LOCALHOST() { static std::string localhost = "localhost"; return localhost;}
-
-const std::string& Str::ECF_PORT() { static std::string ECF_PORT = "ECF_PORT"; return ECF_PORT;}
-const std::string& Str::ECF_RID() { static std::string ECF_RID = "ECF_RID"; return ECF_RID;}
-const std::string& Str::ECF_TRYNO() { static std::string ECF_TRYNO = "ECF_TRYNO"; return ECF_TRYNO;}
-const std::string& Str::ECF_TRIES() { static std::string ECF_TRIES = "ECF_TRIES"; return ECF_TRIES;}
-const std::string& Str::ECF_NAME() { static std::string ECF_NAME = "ECF_NAME"; return ECF_NAME; }
-const std::string& Str::ECF_NODE() { static std::string ECF_NODE = "ECF_NODE"; return ECF_NODE;}
-const std::string& Str::ECF_PASS() { static std::string ECF_PASS = "ECF_PASS";return ECF_PASS;}
-const std::string& Str::ECF_JOB() { static std::string ECF_JOB = "ECF_JOB"; return ECF_JOB;}
-const std::string& Str::ECF_JOBOUT() { static std::string ECF_JOBOUT = "ECF_JOBOUT"; return ECF_JOBOUT;}
-const std::string& Str::ECF_SCRIPT() { static std::string ECF_SCRIPT = "ECF_SCRIPT"; return ECF_SCRIPT;}
-const std::string& Str::ECF_DUMMY_TASK() { static std::string ECF_DUMMY_TASK = "ECF_DUMMY_TASK"; return ECF_DUMMY_TASK;}
-const std::string& Str::ECF_MICRO() { static std::string ECF_MICRO = "ECF_MICRO"; return ECF_MICRO;}
-const std::string& Str::ECF_FILES() { static std::string ECF_FILES = "ECF_FILES"; return ECF_FILES;}
-const std::string& Str::ECF_FETCH() { static std::string ECF_FETCH = "ECF_FETCH"; return ECF_FETCH;}
-const std::string& Str::ECF_KILL_CMD() { static std::string ECF_KILL_CMD = "ECF_KILL_CMD"; return ECF_KILL_CMD;}
-const std::string& Str::ECF_STATUS_CMD() { static std::string ECF_STATUS_CMD = "ECF_STATUS_CMD"; return ECF_STATUS_CMD;}
-
-const std::string& Str::ECF_HOME() { static std::string ECF_HOME = "ECF_HOME"; return ECF_HOME;}
-const std::string& Str::ECF_INCLUDE() { static std::string ECF_INCLUDE = "ECF_INCLUDE"; return ECF_INCLUDE;}
-const std::string& Str::ECF_JOB_CMD() { static std::string ECF_JOB_CMD = "ECF_JOB_CMD"; return ECF_JOB_CMD;}
-const std::string& Str::ECF_OUT() { static std::string ECF_OUT = "ECF_OUT"; return ECF_OUT;}
-const std::string& Str::ECF_EXTN() { static std::string ECF_EXTN = "ECF_EXTN"; return ECF_EXTN;}
-const std::string& Str::ECF_LOG() { static std::string ECF_LOG = "ECF_LOG"; return ECF_LOG;}
-
-
-const std::string& Str::WHITE_LIST_FILE() { static std::string WHITE_LIST_FILE = "ecf.lists"; return WHITE_LIST_FILE;}
-
-const std::string& Str::ALPHANUMERIC_UNDERSCORE()
-{
- static string ALPHANUMERIC_UNDERSCORE = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
- return ALPHANUMERIC_UNDERSCORE;
-}
-
-const std::string& Str::NUMERIC() { static string NUMERIC = "0123456789"; return NUMERIC; }
-
-void Str::removeQuotes(std::string& s)
-{
- if (!s.empty()) {
- if (s[0] == '"' && s[s.size()-1] == '"') {
- s.erase(s.begin());
- s.erase(s.begin() + s.size()-1);
- }
- }
-}
-// 047 is octal for '
-void Str::removeSingleQuotes(std::string& s)
-{
- if (!s.empty()) {
- if (s[0] == 047 && s[s.size()-1] == 047) {
- s.erase(s.begin());
- s.erase(s.begin() + s.size()-1);
- }
- }
-}
-
-bool Str::replace(std::string& jobLine, const std::string& stringToFind, const std::string& stringToRplace)
-{
- size_t pos = jobLine.find(stringToFind);
- if (pos != string::npos) {
- jobLine.replace(pos,stringToFind.length(),stringToRplace);
- return true;
- }
- return false;
-}
-
-bool Str::replace_all(std::string& subject, const std::string& search, const std::string& replace)
-{
- bool replaced = false ;
- size_t pos = 0;
- while ((pos = subject.find(search, pos)) != std::string::npos) {
- subject.replace(pos, search.length(), replace);
- pos += replace.length();
- replaced = true;
- }
- return replaced;
-}
-
-bool Str::extract_data_member_value(const std::string& str, const std::string& data_member_name, std::string& data_member_value)
-{
- // 012345678901234567,
- // str=cmd 1 user:mao
- // data_member_name=user:
- // data_member_value=ma0
- std::string::size_type start = str.find(data_member_name);
- if (start != std::string::npos) {
- start += data_member_name.size();
- data_member_value.clear();
- for(size_t i = start; i < str.size(); i++) {
- if (str[i] == ' ') break;
- data_member_value += str[i];
- }
- return true;
- }
- return false;
-}
-
-
-void Str::replaceall(std::string& subject, const std::string& search, const std::string& replace)
-{
- boost::replace_all(subject, search, replace);
-}
-
-void Str::split(const std::string& line, std::vector< std::string >& tokens,const std::string& delimiters )
-{
- // ***************************************************************************
- // Time for split 1000000 times = 5.81
-
- // Skip delimiters at beginning.
- string::size_type lastPos = line.find_first_not_of( delimiters, 0 );
-
- // Find first "non-delimiter".
- string::size_type pos = line.find_first_of( delimiters, lastPos );
-
- while ( string::npos != pos || string::npos != lastPos ) {
- tokens.push_back( line.substr( lastPos, pos - lastPos ) ); // Found a token, add it to the vector.
- lastPos = line.find_first_not_of( delimiters, pos ); // Skip delimiters. Note the "not_of"
- pos = line.find_first_of( delimiters, lastPos ); // Find next "non-delimiter"
- }
-
-// // ***************************************************************************
-// // Time for split 1000000 times = 11.66
-//
-// // FAILS: with line = "\n", since I expect at least one token of "\n"
-// int i = 0;
-// char ch;
-// string word;
-// while ( (ch = line[i++]) ) {
-// if ( isspace( ch ) ) {
-// if ( !word.empty() ) tokens.push_back( word );
-// word = "";
-// }
-// else word += ch;
-// }
-// if ( !word.empty() ) tokens.push_back( word );
-
-// // ******************************************************************************
-// // Time for boost split > 20 seconds, this
-// boost::algorithm::split(result, line, std::bind2nd(std::equal_to<char>(), ' '));
-//
-// // ***************************************************************************
-// // Time for split 1000000 times = 30.38
-//
-// // FAILS: with line = "\n", since I expect at least one token of "\n"
-// char_separator< char > sep( " ",0, boost::drop_empty_tokens );
-// typedef boost::tokenizer< boost::char_separator< char > > tokenizer;
-// tokenizer theTokenizer( line, sep );
-// // std::copy( theTokenizer.begin(), theTokenizer.end(), back_inserter( tokens ) );
-//
-// for(tokenizer::iterator beg=theTokenizer.begin(); beg!=theTokenizer.end();++beg){
-// string token = *beg;
-// boost::algorithm::trim(token);
-// if (token.empty()) continue;
-// tokens.push_back(token);
-// }
-}
-
-static bool caseInsCharCompare(char a, char b) { return (toupper(a) == toupper(b)); }
-
-bool Str::caseInsCompare( const std::string& s1, const std::string& s2)
-{
- return ( (s1.size() == s2.size()) && equal(s1.begin(),s1.end(), s2.begin(), caseInsCharCompare));
-}
-
-
-struct case_insensitive_less : public std::binary_function< char,char,bool >
-{
- bool operator () (char x, char y) const {
- if (toupper(x) == toupper(y)) {
- return x > y;
- }
- return toupper( static_cast< unsigned char >(x)) <
- toupper( static_cast< unsigned char >(y));
- }
-};
-bool Str::caseInsLess( const std::string& a, const std::string& b)
-{
- return std::lexicographical_compare( a.begin(),a.end(),
- b.begin(),b.end(), case_insensitive_less() );
-}
-
-
-struct case_insensitive_greater : public std::binary_function< char,char,bool >
-{
- bool operator () (char x, char y) const {
- if (toupper(x) == toupper(y)) {
- return x < y;
- }
- return toupper( static_cast< unsigned char >(x)) >
- toupper( static_cast< unsigned char >(y));
- }
-};
-bool Str::caseInsGreater( const std::string& a, const std::string& b)
-{
- return std::lexicographical_compare( a.begin(),a.end(),
- b.begin(),b.end(), case_insensitive_greater() );
-}
-
-
-bool Str::valid_name(const std::string& name, std::string &msg)
-{
- // valid names are alphabetic (alphanumeric | underscore | .)
- // however we can't have a leading '.' as that can interfere with trigger expressions
-
- // verify that the string is not empty
- if ( name.empty() ) {
- msg = "Invalid name. Empty string.";
- return false;
- }
-
- // verify that the first character is alphabetic or has underscore
- bool result = Str::ALPHANUMERIC_UNDERSCORE().find( name[0], 0 ) != string::npos;
- if ( !result ) {
- msg = "Valid names can only consist of alphanumeric characters "
- ",underscores and dots. The first character can not be a dot: ";
- msg += name;
- return false;
- }
-
- // verify that any other characters are alphanumeric or underscore
- if (name.size() > 1) {
- result = name.find_first_not_of(VALID_NODE_CHARS, 1) == string::npos;
- if ( !result ) {
- msg = "Valid names can only consist of alphanumeric characters "
- ",underscores and dots. The first character can not be a dot: ";
- msg += name;
- }
- }
-
- return result;
-}
-
-bool Str::valid_name(const std::string& name)
-{
- // valid names are alphabetic (alphanumeric | underscore | .)
- // however we can't have a leading '.' as that can interfere with trigger expressions
-
- // verify that the string is not empty
- if ( name.empty() ) {
- return false;
- }
-
- // verify that the first character is alphabetic or has underscore
- bool result = Str::ALPHANUMERIC_UNDERSCORE().find( name[0], 0 ) != string::npos;
- if ( !result ) {
- return false;
- }
-
- // verify that any other characters are alphanumeric or underscore
- if (name.size() > 1) {
- result = name.find_first_not_of(VALID_NODE_CHARS, 1) == string::npos;
- }
-
- return result;
-}
-
-int Str::to_int( const std::string& the_str, int error_return)
-{
- if ( the_str.find_first_of( Str::NUMERIC(), 0 ) != std::string::npos ) {
- try {
- return boost::lexical_cast< int >( the_str );
- }
- catch ( boost::bad_lexical_cast&) {}
- }
- return error_return;
-}
-
-bool Str::truncate_at_start( std::string& fileContents, size_t max_lines)
-{
- if (fileContents.empty()) return false;
-
- /// Truncate from the front
- size_t no_of_new_lines = 0;
- for(size_t i =fileContents.size()-1; i >0; --i) {
- if (fileContents[i] == '\n') no_of_new_lines++;
- if ( no_of_new_lines >= max_lines) {
- fileContents.erase(fileContents.begin(),fileContents.begin() + i +1); //skip new line at start of file
- return true;
- }
- }
- return false;
-}
-
-bool Str::truncate_at_end( std::string& fileContents, size_t max_lines)
-{
- if (fileContents.empty()) return false;
-
- /// Truncate from the back
- size_t no_of_new_lines = 0;
- size_t the_size = fileContents.size();
- for(size_t i =0; i < the_size; ++i) {
- if (fileContents[i] == '\n') no_of_new_lines++;
- if ( no_of_new_lines >= max_lines) {
- fileContents.erase(fileContents.begin()+i+1,fileContents.end()); //skip new line at end of file
- return true;
- }
- }
- return false;
-}
-
-}
diff --git a/ecflow_4_0_7/ACore/src/Str.hpp b/ecflow_4_0_7/ACore/src/Str.hpp
deleted file mode 100644
index f78b98f..0000000
--- a/ecflow_4_0_7/ACore/src/Str.hpp
+++ /dev/null
@@ -1,150 +0,0 @@
-#ifndef STR_HPP_
-#define STR_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #50 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : This class is used as a helper class
-//============================================================================
-#include <string.h> //for strcmp
-#include <string>
-#include <vector>
-#include <limits>
-#include <boost/noncopyable.hpp>
-
-namespace ecf {
-
-class Str : private boost::noncopyable {
-public:
- static int reserve_4() { return 4; }
- static int reserve_8() { return 8; }
- static int reserve_16() { return 17; }
- static int reserve_32() { return 32; }
- static int reserve_64() { return 64; }
-
- // remove any quotes on the string, else does nothing
- // "fred" -> fred
- // fred -> fred
- static void removeQuotes(std::string&);
-
- // remove any single quotes on the string, else does nothing
- // 'fred' -> fred
- // fred -> fred
- static void removeSingleQuotes(std::string&);
-
- /// Find 'stringToFind' in 'jobLine' and replace with string 'stringToRplace'
- /// return true if replace ok else returns false;
- static bool replace(std::string& jobLine, const std::string& stringToFind, const std::string& stringToRplace);
- static bool replace_all(std::string& jobLine, const std::string& stringToFind, const std::string& stringToRplace);
- static void replaceall(std::string& jobLine, const std::string& stringToFind, const std::string& stringToRplace);
-
- // extract data member value, ie given a string of the form:
- // str=cmd a b fred:value
- // data_member_name=fred:
- // extract value
- static bool extract_data_member_value(const std::string& str, const std::string& data_member_name, std::string& data_member_value);
-
- /// split string using default delimiters of space and tab as a separator;
- /// The split is based on *ANY* of the characters in the delimiters.
- /// **** Hence a delimiter of "==" will still split "a = complete"
- /// **** sequential delimiter character are ignored ****
- static void split(const std::string& str,
- std::vector< std::string >& lineTokens,
- const std::string& delimiters = " \t");
-
- /// case in sensitive string comparison
- static bool caseInsCompare( const std::string& str1, const std::string& str2);
-
- /// case insenstive less
- static bool caseInsLess( const std::string& str1, const std::string& str2);
-
- /// case insenstive Greater
- static bool caseInsGreater( const std::string& str1, const std::string& str2);
-
- /// Used for checking node names
- static bool valid_name(const std::string& name, std::string &msg);
- static bool valid_name(const std::string& name);
-
- /// Use this function when you are not sure if string is convertible to an integer.
- /// This function will check if string has a numeric first & hence faster than
- /// using boost::lexical_cast< int > alone. Will trap any exception
- /// will return numeric_limits<int>::max() for invalid conversions
- static int to_int( const std::string&, int error_return = std::numeric_limits<int>::max() );
-
- /// Truncate the input string at the start/end if exceeds max_lines_ newlines
- /// returns true if truncated false otherwise
- static bool truncate_at_start( std::string& fileContents, size_t max_lines_);
- static bool truncate_at_end( std::string& fileContents, size_t max_lines_);
-
- /// Only use strcmp if the first characters are the same
- static int local_strcmp(const char* s, const char* t)
- {
- return (*s != *t ? *s - *t : strcmp(s, t));
- }
-
- // returns a static string of alpha numerics and underscore
- static const std::string& ALPHANUMERIC_UNDERSCORE();
-
- // returns a static string of numerics chars
- static const std::string& NUMERIC();
-
- static const char* CHILD_CMD();
- static const char* USER_CMD();
- static const char* SVR_CMD(); // Only for automatic check_pt
-
- // Allows string to be returned by reference
- static const std::string& EMPTY() ;
- static const std::string& ROOT_PATH(); // "/"
- static const std::string& PATH_SEPERATOR() ; // "/"
- static const std::string& COLON() ; // ":"
-
- static const std::string& STATE_CHANGE();
-
- static const std::string& TASK();
- static const std::string& FAMILY();
- static const std::string& SUITE();
- static const std::string& ALIAS();
-
- static const std::string& DEFAULT_PORT_NUMBER(); // "3141"
- static const std::string& LOCALHOST();
-
- static const std::string& ECF_PORT();
- static const std::string& ECF_RID();
- static const std::string& ECF_TRYNO();
- static const std::string& ECF_TRIES();
- static const std::string& ECF_NAME();
- static const std::string& ECF_NODE();
- static const std::string& ECF_PASS();
- static const std::string& ECF_JOB();
- static const std::string& ECF_JOBOUT();
- static const std::string& ECF_SCRIPT();
- static const std::string& ECF_DUMMY_TASK();
- static const std::string& ECF_MICRO();
- static const std::string& ECF_FILES();
- static const std::string& ECF_FETCH();
- static const std::string& ECF_KILL_CMD();
- static const std::string& ECF_STATUS_CMD();
-
- static const std::string& ECF_HOME();
- static const std::string& ECF_INCLUDE();
- static const std::string& ECF_JOB_CMD();
- static const std::string& ECF_OUT();
- static const std::string& ECF_EXTN();
- static const std::string& ECF_LOG();
-
- static const std::string& WHITE_LIST_FILE();
-private:
- Str(){}
-};
-
-}
-
-#endif
diff --git a/ecflow_4_0_7/ACore/src/TimeSeries.cpp b/ecflow_4_0_7/ACore/src/TimeSeries.cpp
deleted file mode 100644
index 23ada0f..0000000
--- a/ecflow_4_0_7/ACore/src/TimeSeries.cpp
+++ /dev/null
@@ -1,836 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #78 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <boost/date_time/posix_time/time_formatters.hpp> // requires boost date and time lib
-#include "TimeSeries.hpp"
-#include "Indentor.hpp"
-#include "Calendar.hpp"
-#include "Log.hpp"
-#include "Str.hpp"
-#include "Ecf.hpp"
-#include "Extract.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-
-//#define DEBUG_TIME_SERIES 1
-//#define DEBUG_TIME_SERIES_IS_FREE 1
-
-static void testTimeSlot( const ecf::TimeSlot& ts)
-{
- if (ts.hour() < 0 || ts.hour() > 23) {
- std::stringstream ss; ss << "TimeSeries: time hour(" << ts.hour() << ") must be in range 0-23";
- throw std::out_of_range(ss.str());
- }
- if (ts.minute() < 0 || ts.minute() > 59) {
- std::stringstream ss; ss << "TimeSeries: time minute(" << ts.minute() << ") must be in range 0-59";
- throw std::out_of_range(ss.str());
- }
-}
-
-namespace ecf {
-
-TimeSeries::TimeSeries()
-: relativeToSuiteStart_(false),
- isValid_(true),
- relativeDuration_(0,0,0,0),
- lastTimeSlot_(0,0,0,0) {}
-
-TimeSeries::TimeSeries(int hour, int minute, bool relative)
-: relativeToSuiteStart_(relative),
- isValid_(true),
- start_(hour,minute),
- nextTimeSlot_(hour,minute),
- relativeDuration_(0,0,0,0),
- lastTimeSlot_(start_.duration())
-{
- testTimeSlot(start_);
-}
-
-TimeSeries::TimeSeries(const TimeSlot& t,bool relative)
-: relativeToSuiteStart_(relative),
- isValid_(true),
- start_(t),
- nextTimeSlot_(t),
- relativeDuration_(0,0,0,0),
- lastTimeSlot_(t.duration())
-{
- testTimeSlot(start_);
-}
-
-TimeSeries::TimeSeries(const TimeSlot& start, const TimeSlot& finish, const TimeSlot& incr,bool relative)
-: relativeToSuiteStart_(relative),
- isValid_(true),
- start_( start ),
- finish_( finish ),
- incr_( incr ),
- nextTimeSlot_( start ),
- relativeDuration_(0,0,0,0)
-{
- testTimeSlot(start);
- testTimeSlot(finish);
- testTimeSlot(incr);
-
- if (!finish_.isNULL()) {
- if (incr_.isNULL()) {
- std::stringstream ss;
- ss << "TimeSeries::TimeSeries: Invalid time series: Finish specified without an increment";
- throw std::out_of_range( ss.str() );
- }
- }
-
- if (start.duration() > finish.duration()) {
- std::stringstream ss;
- ss << "TimeSeries::TimeSeries: Invalid time series: Start time("
- << start.toString() << ") is greater than end time(" << finish.toString() << ")";
- throw std::out_of_range( ss.str() );
- }
- if ( incr.hour() == 0 && incr.minute() == 0 ) {
- throw std::out_of_range( "TimeSeries::TimeSeries Invalid time series: Increment must be greater than 0 minutes.");
- }
- boost::posix_time::time_duration diff = finish.duration() - start.duration();
- if ( incr.duration() > diff) {
- std::stringstream ss;
- ss << "TimeSeries::TimeSeries: Invalid time series: Increment(" << incr.toString() << ") is greater than duration "
- << to_simple_string(diff)
- << " between start(" << start.toString() << ") and finish(" << finish.toString() << ")";
- throw std::out_of_range(ss.str());
- }
-
- compute_last_time_slot();
-
-#ifdef DEBUG_TIME_SERIES
- cout << "TimeSeries::TimeSeries " << dump() << "\n";
-#endif
-}
-
-bool TimeSeries::operator<(const TimeSeries& rhs) const
-{
- return start_ < rhs.start_;
-}
-
-void TimeSeries::compute_last_time_slot()
-{
- if (!finish_.isNULL()) {
- lastTimeSlot_ = start_.duration();
- while ( lastTimeSlot_ <= finish_.duration()) lastTimeSlot_ += incr_.duration();
- lastTimeSlot_ -= incr_.duration();
- }
-}
-
-bool TimeSeries::calendarChanged( const ecf::Calendar& c )
-{
- if ( relativeToSuiteStart_ ) {
- relativeDuration_ += c.calendarIncrement();
- return true;
- }
- else if (c.dayChanged()) {
-
- // Clear expired flag and next slot. Needed since requue will expire flag when past time slot
- // Hence we need something to reset. Otherwise for next day isFree will always return false;
- isValid_ = true;
- nextTimeSlot_ = start_;
- return true;
- }
- return false;
-}
-
-bool TimeSeries::resetRelativeDuration()
-{
- if ( relativeToSuiteStart_ ) {
- relativeDuration_ = time_duration(0,0,0,0);
- return true;
- }
-#ifdef DEBUG_TIME_SERIES
- cout << "TimeSeries::resetRelativeDuration " << dump() << "\n";
-#endif
- return false;
-}
-
-void TimeSeries::reset(const ecf::Calendar& c)
-{
- isValid_ = true;
- nextTimeSlot_ = start_;
-
- (void)resetRelativeDuration();
-
- // Note: **difference between reset and re-queue,
- // Hence if at begin(), time slot same as current time, allow job to run.
- // reset : while( current_time > nextTimeSlot_.duration()) { // need for why command
- // if (current_time > start_.duration() ) {
- // requeue: while( current_time >= nextTimeSlot_.duration()) {
- // if (current_time >= start_.duration() ) {
-
- // Update nextTimeSlot_ so that why command works out of the box, when nodes have been begun.
- // *if* the current time is *AT* the start do *not* increment nextTimeSlot_, otherwise we will miss first time slot
- time_duration current_time = duration(c);
- if (hasIncrement()) {
-
- // only used when we have a series
- suiteTimeAtReque_ = TimeSlot(c.suiteTime().time_of_day());
- //cout << "TimeSeries::reset suiteTimeAtReque_: " << suiteTimeAtReque_ << " =====================================================\n";
-
- while( current_time > nextTimeSlot_.duration()) {
- time_duration value = nextTimeSlot_.duration();
- value += incr_.duration();
- nextTimeSlot_ = TimeSlot(value.hours(),value.minutes());
- }
- if (nextTimeSlot_ > finish_) {
- isValid_ = false; // time has expired
- }
- }
- else {
- if (current_time > start_.duration() ) {
- isValid_ = false; // time has expired
- }
- }
-
-#ifdef DEBUG_TIME_SERIES
- LogToCout toCoutAsWell;
- LOG(Log::DBG," TimeSeries::reset " << dump());
-#endif
-}
-
-void TimeSeries::requeue(const ecf::Calendar& c,bool reset_next_time_slot)
-{
- // cout << "TimeSeries::requeue " << c.toString() << "\n";
-
- // *RESET* to handle case where time slot has been advanced, but at requeue it must be reset
- // This is important otherwise user can never reset and time slot that had been advanced
- // by using miss_next_time_slot()
- if (reset_next_time_slot) {
- isValid_ = true;
- nextTimeSlot_ = start_;
- }
-
- // time 13:00 // nextTimeSlot_ is initialised to 13:00, on TimeSeries::requeue() invalidate time series
- // // to stop multiple job submissions on same time slot
- // -------------------- nextTimeSlot_
- // | -------------- isValid = false
- // V V
- // 10:00 11:00 12:00 13:00 14:00 15:00 16:00 17:00 18:00 19:00 20:00
- // | | | | | | | | | | |
- // ------time----------->
- //
- // TimeSeries::requeue(..) is called at the *re-queue* stage. *after*:
- // a/ task has completed
- // b/ checkForRequeue() has passed.
- // hence if we get here for a single slot time, where calendar time >= start time
- // then this time series is no longer valid. This will stop multiple job submission
- // for the same time slot
- time_duration current_time = duration(c);
- if (!hasIncrement()) {
- if (current_time >= start_.duration() ) {
- isValid_ = false; // time has expired
-#ifdef DEBUG_TIME_SERIES
- LOG(Log::DBG," TimeSeries::increment (duration(c) >= start_.duration() ) " << toString() << " duration=" << to_simple_string(duration(c)));
-#endif
- }
- return;
- }
-
- // only used when we have a series
- suiteTimeAtReque_ = TimeSlot(c.suiteTime().time_of_day());
-// cout << "TimeSeries::requeue suiteTimeAtReque_: " << suiteTimeAtReque_ << " =====================================================\n";
-
- // the nextTimeSlot_ needs to be set to a multiple of incr
- // However the nextTimeSlot_ can not just be incremented by incr
- // since we can't assume that a task completes within the given time slots
- // *hence increments to NEXT TIME SLOT large than calendar time.
- // time 10::00 20:00 01:00
- // --------------------------------------------------------nextTimeSlot_ must greater than current time.
- // | --------isValid = false
- // V V
- // 10:00 11:00 12:00 13:00 14:00 15:00 16:00 17:00 18:00 19:00 20:00 21:00
- // | | | | | | | | | | | |
- // ------time---->
- //
- while( current_time >= nextTimeSlot_.duration()) {
- time_duration value = nextTimeSlot_.duration();
- value += incr_.duration();
- nextTimeSlot_ = TimeSlot(value.hours(),value.minutes());
-#ifdef DEBUG_TIME_SERIES
- LOG(Log::DBG," TimeSeries::increment " << toString());
-#endif
- }
-
- if (nextTimeSlot_ > finish_) {
- isValid_ = false; // time has expired
- suiteTimeAtReque_ = TimeSlot(); // expire for new requeue
-#ifdef DEBUG_TIME_SERIES
- LOG(Log::DBG," TimeSeries::increment " << toString());
-#endif
- }
-}
-
-TimeSlot TimeSeries::compute_next_time_slot(const ecf::Calendar& c) const
-{
- // This functionality needs to mirror TimeSeries::requeue
- time_duration current_time = duration(c);
- if (!hasIncrement()) {
- if (current_time >= start_.duration() ) {
- return TimeSlot(); // time has expired
- }
- return start_;
- }
-
- TimeSlot nextTimeSlot = start_;
- while( current_time >= nextTimeSlot.duration()) {
- time_duration value = nextTimeSlot.duration();
- value += incr_.duration();
- nextTimeSlot = TimeSlot(value.hours(),value.minutes());
- }
-
- if (nextTimeSlot > finish_) {
- return TimeSlot(); // time has expired
- }
- return nextTimeSlot;
-}
-
-bool TimeSeries::requeueable(const ecf::Calendar& c) const
-{
- boost::posix_time::time_duration calendar_time = duration(c);
- if (calendar_time < start().duration()) return true;
- if (hasIncrement()) {
- if (calendar_time < finish().duration()) {
- return true;
- }
- }
- return false;
-}
-
-bool TimeSeries::isFree(const ecf::Calendar& calendar) const
-{
-#ifdef DEBUG_TIME_SERIES_IS_FREE
- LogToCout toCoutAsWell; Indentor indent;
-#endif
-
- if (!isValid_) {
- // time has expired, hence time is not free
-#ifdef DEBUG_TIME_SERIES_IS_FREE
- LOG(Log::DBG,"TimeSeries::isFree (!isValid_) HOLDING " << dump());
-#endif
- return false;
- }
-
- // Matched calendar duration with the current value of the time series
- // or match with one of time slots.
-
- // Note:: the definition file has time series format of hh:mm this
- // means we have a minute resolution. The clock/calendar
- // duration has seconds based resolution. hence we must
- // compensate for this.
- //
- // time 10:00 20:00 01:00
- // start
- // | ----- next time slot --- finish
- // | | |
- // V V V
- // 10:00 11:00 12:00 13:00 14:00 15:00 16:00 17:00 18:00 19:00 20:00
- // | | | | | | | | | | |
- // ------time---->
- //
- bool ret = match_duration_with_time_series(duration(calendar));
-// if (ret) {
-// std::cout << "TimeSeries::isFree " << dump() << " is free at calendar: " << calendar.toString() << "\n";
-// }
- return ret;
-}
-
-
-bool TimeSeries::match_duration_with_time_series(const boost::posix_time::time_duration& relative_or_real_td) const
-{
-#ifdef DEBUG_TIME_SERIES_IS_FREE
- Indentor ident;
-#endif
-
- if ( !hasIncrement() ) {
- // We ignore seconds, hence +00:02 will match 2.58 (two minutes 58 seconds) relative duration
- time_duration start_td = start_.duration();
- if ( relative_or_real_td.hours() == start_td.hours() && relative_or_real_td.minutes() == start_td.minutes()) {
-#ifdef DEBUG_TIME_SERIES_IS_FREE
- LOG(Log::DBG,"TimeSeries::match_duration_with_time_series " << dump() << " FREE at " << to_simple_string(relative_or_real_td));
-#endif
- return true;
- }
-
-#ifdef DEBUG_TIME_SERIES_IS_FREE
- LOG(Log::DBG,"TimeSeries::match_duration_with_time_series " << dump() << " HOLDING at " << to_simple_string(relative_or_real_td));
-#endif
- return false;
- }
-
- time_duration endDuration = finish_.duration();
- time_duration incrDuration = incr_.duration();
- time_duration nextTimeSlot_td = nextTimeSlot_.duration();
- long hours = relative_or_real_td.hours();
- long minutes = relative_or_real_td.minutes();
- while ( nextTimeSlot_td <= endDuration ) {
-
- if ( hours == nextTimeSlot_td.hours() && minutes == nextTimeSlot_td.minutes()) {
-#ifdef DEBUG_TIME_SERIES_IS_FREE
- LOG(Log::DBG,"TimeSeries::match_duration_with_time_series (nextTimeSlot_td == duration) " << dump()
- << " FREE at " << to_simple_string(relative_or_real_td));
-#endif
- return true;
- }
- nextTimeSlot_td += incrDuration;
- }
-
-#ifdef DEBUG_TIME_SERIES
- LOG(Log::DBG,"TimeSeries::matches HOLDING (nextTimeSlot_td > endDuration) " << dump() << " HOLDING at " << to_simple_string(relative_or_real_td));
-#endif
- return false;
-}
-
-void TimeSeries::miss_next_time_slot()
-{
- if ( !hasIncrement()) {
- // single slot, does not have a next time slot, hence expire time
- isValid_ = false;
- }
- else {
- time_duration value = nextTimeSlot_.duration();
- value += incr_.duration();
- nextTimeSlot_ = TimeSlot(value.hours(),value.minutes());
- if (nextTimeSlot_ > finish_) {
- // time has expired,
- isValid_ = false;
- }
- }
-}
-
-bool TimeSeries::checkForRequeue( const ecf::Calendar& calendar, const TimeSlot& the_min, const TimeSlot& the_max) const
-{
- // ************************************************************************
- // THIS IS CALLED IN THE CONTEXT WHERE NODE HAS COMPLETED. Hence ****asyncronous****
- // RETURNING TRUE FROM HERE WILL FORCE NODE TO QUEUED STATE
- // HENCE THIS FUNCTION MUST RETURN FALSE, WHEN END OF TIME SLOT HAS BEEN REACHED/expired
- // The resolution is in minutes
- // *************************************************************************
- //cout << "TimeSeries::checkForRequeue " << calendar.toString() << "\n";
-
- if (!isValid_) {
- // time has expired, hence can no longer re-queues, i.e no future time dependency
- return false;
- }
-
- if ( hasIncrement()) {
- // Note if we are equal to the finish and were called as part of completeCmd
- // then completeCmd will initiate a job submission immediately
- // start 00:01
- // finish 00:04 Node will be queued 4 times
- // incr 00:01
-
- // If the current value is greater that finish, then returning true would increment
- // value past the end, and force node state to be stuck in state queue.
- if ( nextTimeSlot_ > finish_ ) {
- return false;
- }
-
- // ECFLOW-130 jobs that start before midnight and finish after midnight should not requeue
- if (!suiteTimeAtReque_.isNULL()){
- TimeSlot suiteTimeNow(calendar.suiteTime().time_of_day());
- //cout << "TimeSeries::checkForRequeue suiteTimeNow = " << suiteTimeNow << " =====================================================\n";
- // we use >= specifically for unit test, to pass.
- if ( suiteTimeNow >= suiteTimeAtReque_) {
- // normal flow, i.e same day
- suiteTimeAtReque_ = TimeSlot(); // make NULL, allow reque to reset.
- }
- else {
- // The day changed between (requeue/reset):->queued->submitted->active->complete->(checkForRequeue)
- //cout << "TimeSeries::checkForRequeue day changed =====================================================\n";
- return false;
- }
- }
-
- time_duration calendar_duration = duration(calendar);
- if ( calendar_duration < lastTimeSlot_) {
- return true;
- }
- return false;
- }
-
- // *** When we have a single time slots we can not make a decision, whether
- // *** we should re-queue based on this attribute *alone*. (i.e when we have > 1 time/today attributes)
- // *** Hence we pass min and max time slots, over all the time bases attributes of the same kind.
- // *** In our case we only do this for Time and Today attributes.
- // *** The the_min/the_max have been computed for all attribute (i.e single time slots and ranges)
-
- // We have a single time slot, *OR* multiple with same time slot
- if (the_min == the_max) {
- return false;
- }
-
- // The the_min/the_max takes into account *all* start/finish Time and Today attributes
- time_duration calendar_duration = duration(calendar);
- if (calendar_duration < the_max.duration()) {
- return true;
- }
-
- return false;
-}
-
-
-void TimeSeries::min_max_time_slots(TimeSlot& the_min, TimeSlot& the_max) const
-{
- if (the_min.isNULL() || start_ < the_min) the_min = start_;
- if (the_max.isNULL() || start_ > the_max) the_max = start_;
- if (hasIncrement()) {
- if (finish_ < the_min) the_min = finish_;
- if (finish_ > the_max) the_max = finish_;
- }
-}
-
-
-void TimeSeries::why(const ecf::Calendar& c, std::string& theReasonWhy) const
-{
- std::stringstream ss;
- ss << " ( next run time is ";
- if (relativeToSuiteStart_) ss << "+";
- ss << nextTimeSlot_.toString();
-
-
- TimeSlot currentTime = TimeSlot(duration(c));
- ss << ", current suite time is ";
- if (relativeToSuiteStart_) ss << "+";
- ss << currentTime.toString() << " )";
- theReasonWhy += ss.str();
-}
-
-boost::posix_time::time_duration TimeSeries::duration(const ecf::Calendar& c ) const
-{
- // return with a minute resolution
- if ( relativeToSuiteStart_ ) {
-
- // relative to suite start only
- return boost::posix_time::time_duration( relativeDuration_.hours(), relativeDuration_.minutes(), 0, 0 );
- }
-
- LOG_ASSERT(!c.suiteTime().is_special(),"init has not been called on calendar. TimeSeries::duration");
- time_duration time_of_day = c.suiteTime().time_of_day();
- return boost::posix_time::time_duration( time_of_day.hours(), time_of_day.minutes(), 0, 0 );
-}
-
-
-void TimeSeries::free_slots(std::vector<boost::posix_time::time_duration>& vec) const
-{
- if (hasIncrement()) {
-
- time_duration i = start_.duration();
- time_duration endDuration = finish_.duration();
- time_duration incrDuration = incr_.duration();
- while ( i < endDuration ) {
- vec.push_back(i);
- i += incrDuration;
- }
- vec.push_back(finish_.duration());
- return;
- }
-
- vec.push_back(start_.duration());
-}
-
-bool TimeSeries::structureEquals(const TimeSeries& rhs) const
-{
- if (relativeToSuiteStart_ != rhs.relativeToSuiteStart_) return false;
- if ( start_ != rhs.start_) return false;
- if ( finish_ != rhs.finish_) return false;
- if ( incr_ != rhs.incr_) return false;
- return true;
-}
-
-bool TimeSeries::operator==(const TimeSeries& rhs) const
-{
- // additional state
- if (isValid_ != rhs.isValid_) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "TimeSeries::operator== ( isValid_ != rhs.isValid_) \n";
- }
-#endif
- return false;
- }
- if (nextTimeSlot_ != rhs.nextTimeSlot_) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "TimeSeries::operator== ( nextTimeSlot_ != rhs.nextTimeSlot_) \n";
- }
-#endif
- return false;
- }
- if (relativeDuration_ != rhs.relativeDuration_) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "TimeSeries::operator== ( relativeDuration_ != rhs.relativeDuration_) \n";
- }
-#endif
- return false;
- }
- return structureEquals(rhs);
-}
-
-std::ostream& TimeSeries::print(std::ostream& os) const
-{
- os << toString() << "\n";
- return os;
-}
-
-std::string TimeSeries::toString() const
-{
- std::string ret ;
- if (relativeToSuiteStart_) ret += "+";
- ret += start_.toString();
- if (!finish_.isNULL()) {
- ret += " ";
- ret += finish_.toString();
- ret += " ";
- ret += incr_.toString();
- }
- return ret;
-}
-
-std::string TimeSeries::dump() const
-{
- std::stringstream ss;
- ss << toString();
- ss << " isValid_(" << isValid_ << ")";
- ss << " value(" << nextTimeSlot_.toString() << ")";
- ss << " relativeDuration_(" << to_simple_string( relativeDuration_) << ")";
- ss << " lastTimeSlot_(" << to_simple_string(lastTimeSlot_) << ")";
- return ss.str();
-}
-
-bool TimeSeries::checkInvariants(std::string& errormsg) const
-{
- if (!finish_.isNULL()) {
- if (incr_.isNULL()) {
- errormsg += "TimeSeries::checkInvariants increment cannot be NULL when we have a time series";
- cout << errormsg << " " << toString() << "\n";
- return false;
- }
- if (incr_.hour() == 0 && incr_.minute() == 0) {
- errormsg += "TimeSeries::checkInvariants increment must greater than zero";
- cout << errormsg << " " << toString() << "\n";
- return false;
- }
-
- if (start_.duration() > finish_.duration() ) {
- errormsg += "TimeSeries::checkInvariants Invalid time series start() > finish()";
- cout << errormsg << " " << toString() << "\n";
- return false;
- }
-
- if (lastTimeSlot_ <= start_.duration() && lastTimeSlot_ > finish_.duration()) {
- errormsg += "TimeSeries::checkInvariants Invalid last time slot";
- cout << errormsg << " " << toString() << "\n";
- return false;
- }
- }
- if ( relativeDuration_.is_special()) {
- errormsg += "TimeSeries::checkInvariants relativeDuration_ should not be special";
- cout << errormsg << " " << toString() << "\n";
- return false;
- }
- if (relativeToSuiteStart_ && relativeDuration_.hours() > 99) {
- errormsg += "TimeSeries::checkInvariants. Max relative duration is 99 hours & 59 minutes";
- cout << errormsg << " " << toString() << "\n";
- return false;
- }
-
-
- if (!relativeToSuiteStart_ && relativeDuration_.total_seconds() > 0) {
- errormsg += "TimeSeries::checkInvariants Can only have RelativeDuration if relativeToSuiteStart_ flag is set";
- cout << errormsg << " " << toString() << "\n";
- return false;
- }
-
- return true;
-}
-
-std::ostream& operator<<(std::ostream& os, const TimeSeries* d) {
- if (d) return d->print(os);
- return os << "TimeSlot == NULL";
-}
-std::ostream& operator<<(std::ostream& os, const TimeSeries& d) { return d.print(os); }
-
-
-ecf::TimeSeries TimeSeries::create(const std::string& str)
-{
- std::vector<std::string> lineTokens;
- Str::split(str,lineTokens);
- size_t index = 0;
- return TimeSeries::create(index,lineTokens );
-}
-
-std::string TimeSeries::state_to_string(bool isFree) const
-{
- // *IMPORTANT* we *CANT* use ';' character, since is used in the parser, when we have
- // multiple statement on a single line i.e.
- // task a; task b;
- // Hence use of '/' character
- // time 10:30 # free isValid:false nextTimeSlot/10:30 relativeDuration/00:00:00
- std::string ret;
- bool next_time_slot_changed = ( nextTimeSlot_ != start_);
- bool relative_duration_changed = (!relativeDuration_.is_special() && relativeDuration_.total_seconds() != 0);
- if (isFree || !isValid_ || next_time_slot_changed || relative_duration_changed) {
- ret += " #";
- if (isFree) ret += " free";
- if (!isValid_) ret += " isValid:false";
- if (next_time_slot_changed) { ret += " nextTimeSlot/"; ret += nextTimeSlot_.toString(); }
- if (relative_duration_changed) { ret += " relativeDuration/"; ret += to_simple_string(relativeDuration_); }
- }
- return ret;
-}
-
-void TimeSeries::parse_state(size_t index,const std::vector<std::string>& lineTokens, ecf::TimeSeries& ts)
-{
- // *IMPORTANT* we *CANT* use ';' character, since is used in the parser, when we have
- // multiple statement on a single line i.e.
- // task a; task b;
- // Hence use of '/' character
- //
- // Here free is attribute state & not time series state hence ignore
- // time 10:30 # free isValid:false nextTimeSlot/10:30 relativeDuration/00:00:00
- // cron 10:00 20:00 01:00 # free isValid:false nextTimeSlot/10:30 relativeDuration/00:00:00
- bool comment_fnd = false;
- for(size_t i = index; i < lineTokens.size(); i++) {
- if (comment_fnd) {
- if (lineTokens[i] == "isValid:false") { ts.isValid_ = false; continue;}
- if (lineTokens[i].find("nextTimeSlot") != std::string::npos) {
- std::string nextTimeSlot;
- if (Extract::split_get_second(lineTokens[i],nextTimeSlot,'/')) {
- // Note: we do *not* check for valid time since nextTimeSlot, can be incremented past 24 hours, ie
- // cron 00:00 18:00 06:00 # isValid:false nextTimeSlot/24:00
- int startHour = -1;
- int startMin = -1;
- getTime( nextTimeSlot, startHour, startMin, false/*check_time*/);
- ts.nextTimeSlot_ = TimeSlot(startHour, startMin);
- }
- else throw std::runtime_error("TimeSeries::parse_state: could not extract state.");
- }
- if (lineTokens[i].find("relativeDuration") != std::string::npos) {
- std::string relativeDuration;
- if (Extract::split_get_second(lineTokens[i],relativeDuration,'/')) {
- ts.relativeDuration_ = time_duration(duration_from_string(relativeDuration));
- }
- else throw std::runtime_error("TimeSeries::parse_state: could not extract state.");
- }
- }
- if (lineTokens[i] == "#") comment_fnd = true;
- }
- ts.compute_last_time_slot();
-}
-
-ecf::TimeSeries TimeSeries::create( size_t& index,const std::vector<std::string>& lineTokens,bool read_state )
-{
- assert( index < lineTokens.size() );
- int startHour = -1;
- int startMin = -1;
-
- // cron 10:00 20:00 01:00
- // index is on 10:00, ie index should have value of 1 in this case
- string startStr = lineTokens[index];
- bool relative = false;
- if ( startStr[0] == '+' ) {
- relative = true;
- startStr.erase( startStr.begin() ); // remove leading +
- // string must be of form 12:00
- }
- getTime( startStr, startHour, startMin );
- TimeSlot start( startHour, startMin );
-
- index++; // on 20:00
- if ( index < lineTokens.size() && lineTokens[index][0] != '#' ) {
-
- // if third token is not a comment the time must be of the form
- // cron 10:00 20:00 01:00
- if ( index+1 >= lineTokens.size() ) throw std::runtime_error( "TimeSeries::create: Invalid time series :");
-
- int finishHour = -1;
- int finishMin = -1;
- getTime( lineTokens[index], finishHour, finishMin );
- TimeSlot finish( finishHour, finishMin );
-
- index++;
-
- int incrHour = -1;
- int incrMin = -1;
- getTime( lineTokens[index], incrHour, incrMin );
- TimeSlot incr( incrHour, incrMin );
-
-
- if (read_state) {
- TimeSeries ts(start,finish,incr,relative);
- parse_state(index,lineTokens,ts);
- return ts;
- }
- return TimeSeries(start,finish,incr,relative);
- }
-
- if (read_state) {
- TimeSeries ts(start,relative);
- parse_state(index,lineTokens,ts);
- return ts;
- }
- return TimeSeries(start,relative);
-}
-
-bool TimeSeries::getTime(const std::string& time, int& hour, int& min,bool check_time)
-{
- // HH:MM
- // +HH:MM for other clients
- size_t colonPos = time.find_first_of(':');
- if (colonPos == string::npos) throw std::runtime_error("TimeSeries::getTime: Invalid time :'" + time + "'");
-
- std::string theHour ;
- bool relative = false;
- if ( time[0] == '+') {
- relative = true;
- theHour = time.substr(1,colonPos-1);
- }
- else theHour = time.substr(0,colonPos);
-
- std::string theMin = time.substr(colonPos+1);
-
- if (theHour.size() != 2) throw std::runtime_error("TimeSeries::getTime: Invalid hour :" + theHour);
- if (theMin.size() != 2) throw std::runtime_error("TimeSeries::getTime: Invalid minute :" + theMin);
-
- hour = Extract::theInt(theHour,"TimeSeries::getTime: hour must be a integer : " + theHour);
- min = Extract::theInt(theMin,"TimeSeries::getTime: minute must be integer : " + theMin);
-
- if (check_time) testTime(hour,min);
- return relative;
-}
-
-void TimeSeries::testTime(int hour, int minute)
-{
- if (hour == -1 || minute == -1) {
- throw std::runtime_error("TimeSeries::testTime: Failed to extract time");
- }
- if (hour < 0 || hour > 23) {
- std::stringstream ss; ss << "TimeSeries::testTime: time hour(" << hour << ") must be in range 0-23";
- throw std::runtime_error(ss.str());
- }
- if (minute < 0 || minute > 59) {
- std::stringstream ss; ss << "TimeSeries::testTime: time minute(" << minute << ") must be in range 0-59";
- throw std::runtime_error(ss.str());
- }
-}
-
-}
-
diff --git a/ecflow_4_0_7/ACore/src/TimeSeries.hpp b/ecflow_4_0_7/ACore/src/TimeSeries.hpp
deleted file mode 100644
index 7bac42d..0000000
--- a/ecflow_4_0_7/ACore/src/TimeSeries.hpp
+++ /dev/null
@@ -1,215 +0,0 @@
-#ifndef TIMESERIES_HPP_
-#define TIMESERIES_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #57 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : A single or set of times
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "TimeSlot.hpp"
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-#include <boost/date_time/posix_time/time_serialize.hpp>
-#include <boost/serialization/serialization.hpp>
-#include <boost/serialization/level.hpp>
-#include <boost/serialization/tracking.hpp>
-
-namespace ecf { class Calendar;} // forward declare class
-
-namespace ecf {
-/// TimeSeries can have a single time slot or a series of time slots
-///
-///
-/// We need nextTimeSlot_ data member to record the next valid time slot, otherwise when
-/// we have a time series, all times within the time series would be valid for
-/// Job submission. We do not know how long a job will run, hence when incrementing
-/// the nextTimeSlot_, we need the *NEXT* available time slot *after* the current calendar time.
-///
-/// Usage pattern is :
-/// TimeSeries.calendarChanged() // Called every minute. Calls isFree(). Once free we stay free, until requeue.
-/// // At midnight clear time expiration and reset next time slot
-/// TimeSeries.isFree(..) // called when node is QUEUED:
-/// // during dependency evaluation, checks next time slot, against calendar time
-/// // Once free a node stays free, until requeue()
-/// TimeSeries.checkForRequeue(); // called when node is COMPLETE: Checks if next available time slot is valid
-/// // *Must* return false for last time slot
-/// // ECFLOW-130 jobs that start before midnight and finish after midnight should not requeue
-/// TimeSeries.requeue(); // called when node is re-queued.
-/// // Sets value to next valid time slot after calendar time.
-/// // Can *expire* the time, relies on TimeSeries.calendarChanged() to clear time expiration
-/// // after midnight
-/// ECFLOW-130 jobs that start before midnight and finish after midnight should not requeue
-
-// Use compiler, destructor, copy constructor and assignment operator
-class TimeSeries {
-public:
- TimeSeries();
- TimeSeries(int hour, int minute, bool relativeToSuiteStart = false );
- TimeSeries(const TimeSlot&, bool relativeToSuiteStart = false );
- TimeSeries(const TimeSlot& start, const TimeSlot& finish, const TimeSlot& incr,bool relativeToSuiteStart = false);
-
- bool operator<(const TimeSeries& rhs) const;
-
- // returns true if a state change is made
- // Will clear time expiration flag at midnight
- bool calendarChanged( const ecf::Calendar& c);
-
- // relative duration stored locally since it can be reset, when used with repeats
- // returns true if relative duration is reset/ i.e state change has been made
- bool resetRelativeDuration();
- void reset(const ecf::Calendar& c);
-
- // Increment time series. Will find the next time slot after current calendar
- // record the current suite time, to check of jobs finish after midnight
- void requeue(const ecf::Calendar& c,bool reset_next_time_slot = true);
-
- // Since we can miss next time slot , allow its computation for the
- // use with why command, returns a NULL timeslot if next time is invalid
- // This functionality will mirror the requeue(..) function
- TimeSlot compute_next_time_slot(const ecf::Calendar& c) const;
-
- // Return true calendar is before or within scheduled time
- bool requeueable(const ecf::Calendar& c) const;
-
- /// if relativeToSuiteStart returns the relative duration, else returns calendar suite time of day.
- /// The returned resolution is in minutes
- boost::posix_time::time_duration duration(const ecf::Calendar& calendar ) const;
-
- /// If time has expired, returns false
- /// Note: relative means relative to suite start, or relative to the beginning of repeated node.
- /// Is of the form hh:mm. This means relative has a range 00:00->99.59
- /// For a single slot time series, should not be re queued again, and hence
- /// should fail checkForRequeue. Likewise when the the current value is
- /// the finish, then node should also not be re queued, otherwise the
- /// node will be stuck in queued state.
- bool isFree(const ecf::Calendar& calendar) const;
-
- /// For single slot time based attributes we need additional context (i.e the_min,the_max parameter)
- /// in order to determine whether we should re-queue.
- /// Additionally when we have a time range, what if the last jobs runs over midnight. In this case
- /// we need to return false. i.e do not re-queue ECFLOW-130
- bool checkForRequeue( const ecf::Calendar& calendar, const TimeSlot& the_min, const TimeSlot& the_max) const;
-
- void min_max_time_slots(TimeSlot& the_min, TimeSlot& the_max) const;
-
- // Called when explicitly Free holding time dependency. via FreeDepCmd
- // We want to avoid the next time slot.
- void miss_next_time_slot();
-
- void why(const ecf::Calendar&, std::string& theReasonWhy) const;
-
- bool hasIncrement() const { return !finish_.isNULL();}
- const TimeSlot& start() const { return start_; }
- const TimeSlot& finish() const { return finish_;}
- const TimeSlot& incr() const { return incr_; }
- const TimeSlot& value() const { return nextTimeSlot_; }
- bool relative() const { return relativeToSuiteStart_; }
- void free_slots(std::vector<boost::posix_time::time_duration>& ) const;
-
- std::ostream& print(std::ostream&) const;
- bool operator==(const TimeSeries& rhs) const;
- bool operator!=(const TimeSeries& rhs) const { return !operator==(rhs);}
- bool structureEquals(const TimeSeries& rhs) const;
-
- /// returns true if no time specified
- bool isNULL() const { return start_.isNULL(); }
-
- std::string state_to_string(bool isFree) const;
- std::string toString() const;
- std::string dump() const;
- bool checkInvariants(std::string& errormsg) const;
-
- /// expects HH:MM or +HH:MM will throw std:runtime_error for errors,
- /// *if* hour not in range(0-24), minutes(0-59), *and* check_time parameter is enabled
- static bool getTime(const std::string& time, int& hour, int& min, bool check_time = true);
-
- /// extract string like
- /// time +00:00 20:00 00:10 # this is a comment which will be ignored. index = 1
- /// time +20:00 // index = 1
- /// today 20:00 // index = 1
- /// +00:00 20:00 00:10 // index = 0
- /// +20:00 // index = 0
- /// will throw std:runtime_error for errors
- /// will assert if index >= lineTokens.size()
- static ecf::TimeSeries create(size_t& index, // where we should start
- const std::vector<std::string>& lineTokens,
- bool read_state = false);
-
- // like above but string should not contain "time"
- static ecf::TimeSeries create(const std::string& str);
-
- // Parse state associated with the time series: Ignores attributes like free.
- static void parse_state(size_t index,const std::vector<std::string>& lineTokens, ecf::TimeSeries& ts);
- void set_isValid(bool b) { isValid_= b;} // for test only
- void set_next_time_slot( const TimeSlot& ts) { nextTimeSlot_ = ts; } // needed for test only
- const TimeSlot& get_next_time_slot() const { return nextTimeSlot_;}
-
- // Is the time still valid, return false means time has expired.
- bool is_valid() const { return isValid_;}
-private:
-
- static void testTime(int hour, int minute);
-
- // HANDLE CASE WHERE FINISH MINUTES IS NOT DIVISIBLE BY THE INCREMENT
- // time 00:00 23:59 00:10 last valid time is 23:50
- // time 00:30 23:59 04:00 last valid time is 20:30
- // The last valid time here is 23:50/20:30 must return false, to stop node being
- // stuck in queued mode In the case where the FINISH is NOT a multiple of the increment
- // Need a different mechanism to determine the end.
- void compute_last_time_slot(); // only call for series
-
- bool match_duration_with_time_series(const boost::posix_time::time_duration& relative_or_real_td) const;
- boost::posix_time::time_duration relativeDuration() const;
-
-private:
- bool relativeToSuiteStart_;
- bool isValid_; // Needed for single slot to avoid multiple jobs submissions
- TimeSlot start_;
- TimeSlot finish_;
- TimeSlot incr_;
- TimeSlot nextTimeSlot_; // nextTimeSlot_ >= start && is incremented by incr
- mutable TimeSlot suiteTimeAtReque_; // NOT persisted, check of day change, between requeue -> checkForRequeue, when we have series
- boost::posix_time::time_duration relativeDuration_;
- boost::posix_time::time_duration lastTimeSlot_; // Only used when we have a series, can be generated
-
-private:
- // Note: isValid_ is persisted for use by why() command on the client side.
- // Note: nextTimeSlot_ is persisted for use by why() command on the client side.
- // Note: relativeDuration_ is persisted for use by why() command on the client side.
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/)
- {
- ar & relativeToSuiteStart_;
- ar & isValid_;
- ar & start_;
- ar & finish_;
- ar & incr_;
- ar & nextTimeSlot_;
- ar & relativeDuration_;
-
- if (Archive::is_loading::value) {
- if (!finish_.isNULL()) {
- compute_last_time_slot();
- }
- }
- }
-};
-
-std::ostream& operator<<(std::ostream& os, const TimeSeries*);
-std::ostream& operator<<(std::ostream& os, const TimeSeries&);
-}
-
-// This should ONLY be added to objects that are *NOT* serialised through a pointer
-BOOST_CLASS_IMPLEMENTATION(ecf::TimeSeries, boost::serialization::object_serializable);
-BOOST_CLASS_TRACKING(ecf::TimeSeries,boost::serialization::track_never);
-
-#endif
diff --git a/ecflow_4_0_7/ACore/src/TimeSlot.cpp b/ecflow_4_0_7/ACore/src/TimeSlot.cpp
deleted file mode 100644
index 9f75a6a..0000000
--- a/ecflow_4_0_7/ACore/src/TimeSlot.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #16 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "TimeSlot.hpp"
-#include "Calendar.hpp"
-#include "Str.hpp"
-
-using namespace boost::posix_time;
-
-namespace ecf {
-
-///////////////////////////////////////////////////////////////////////////////////////////
-
-bool TimeSlot::operator<(const TimeSlot& rhs) const
-{
- if (hour_ < rhs.hour()) return true;
- if (hour_ == rhs.hour()) {
- return minute_ < rhs.minute();
- }
- return false;
-}
-
-bool TimeSlot::operator>(const TimeSlot& rhs) const
-{
- if (hour_ > rhs.hour()) return true;
- if (hour_ == rhs.hour()) {
- return minute_ > rhs.minute();
- }
- return false;
-}
-
-bool TimeSlot::operator<=( const TimeSlot& rhs ) const
-{
- if (operator<(rhs)) return true;
- return operator==(rhs);
-}
-
-
-bool TimeSlot::operator>=( const TimeSlot& rhs ) const
-{
- if (operator>(rhs)) return true;
- return operator==(rhs);
-}
-
-
-std::ostream& TimeSlot::print(std::ostream& os) const
-{
- os << toString();
- return os;
-}
-
-std::string TimeSlot::toString() const
-{
- std::stringstream ss;
- if (hour_ < 10) ss << "0" << hour_;
- else ss << hour_;
-
- ss << Str::COLON();
- if (minute_ < 10) ss << "0" << minute_;
- else ss << minute_;
- return ss.str();
-}
-
-boost::posix_time::time_duration TimeSlot::duration() const
-{
- assert(!isNULL());
- return boost::posix_time::time_duration( hours(hour_) + minutes(minute_) ) ;
-}
-
-
-std::ostream& operator<<(std::ostream& os, const TimeSlot* d) {
- if (d) return d->print(os);
- return os << "TimeSlot == NULL";
-}
-std::ostream& operator<<(std::ostream& os, const TimeSlot& d) { return d.print(os); }
-
-}
diff --git a/ecflow_4_0_7/ACore/src/TimeSlot.hpp b/ecflow_4_0_7/ACore/src/TimeSlot.hpp
deleted file mode 100644
index 47e09ad..0000000
--- a/ecflow_4_0_7/ACore/src/TimeSlot.hpp
+++ /dev/null
@@ -1,86 +0,0 @@
-#ifndef TIMESLOT_HPP_
-#define TIMESLOT_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #11 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "boost/date_time/posix_time/posix_time_types.hpp"
-#include <boost/serialization/serialization.hpp>
-#include <boost/serialization/level.hpp>
-#include <boost/serialization/tracking.hpp>
-#include <ostream>
-
-namespace ecf {
-
-// Use compiler , generated destructor, assignment, copy constructor
-// *relative* times can extend to a maximum of 99 hours and 59 seconds
-//
-// TimeSlot is used in many other attributes, i.e. like AutoCancelAttr
-// in this case user can specify days, which we convert to hours, hence it
-// is possible for a TimeSlot hour to have any integer value
-class TimeSlot {
-public:
- TimeSlot()
- : hour_(0), minute_(0),isNull_(true) {}
- TimeSlot(int hour, int min)
- : hour_(hour), minute_(min),isNull_(false)
- { assert(hour >= 0 && min >=0 ); }
- TimeSlot(const boost::posix_time::time_duration& td)
- : hour_(td.hours()), minute_(td.minutes()),isNull_(false)
- { assert( hour_ < 60 && minute_ < 60);}
-
- bool operator==(const TimeSlot& rhs) const
- { return ((hour_ == rhs.hour_) && (minute_ == rhs.minute_) && (isNull_ == rhs.isNull_));}
- bool operator!=(const TimeSlot& rhs) const
- { return !operator==(rhs);}
-
- bool operator<(const TimeSlot& rhs) const;
- bool operator>(const TimeSlot& rhs) const;
- bool operator<=(const TimeSlot& rhs) const;
- bool operator>=(const TimeSlot& rhs) const;
-
- int hour() const { return hour_;}
- int minute() const { return minute_;}
- bool isNULL() const { return isNull_; }
- std::ostream& print(std::ostream&) const;
-
- /// returns the corresponding duration.
- boost::posix_time::time_duration duration() const;
-
- // returns struct in the format hh:mm
- std::string toString() const;
-
-private:
- unsigned short hour_;
- unsigned short minute_;
- bool isNull_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/) {
- ar & hour_;
- ar & minute_;
- ar & isNull_;
- }
-};
-
-std::ostream& operator<<(std::ostream& os, const TimeSlot*);
-std::ostream& operator<<(std::ostream& os, const TimeSlot&);
-}
-
-// This should ONLY be added to objects that are *NOT* serialised through a pointer
-BOOST_CLASS_IMPLEMENTATION(ecf::TimeSlot, boost::serialization::object_serializable);
-BOOST_CLASS_TRACKING(ecf::TimeSlot,boost::serialization::track_never);
-
-#endif
diff --git a/ecflow_4_0_7/ACore/src/TimeStamp.cpp b/ecflow_4_0_7/ACore/src/TimeStamp.cpp
deleted file mode 100644
index 0fb7de4..0000000
--- a/ecflow_4_0_7/ACore/src/TimeStamp.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-//============================================================================
-// Name : Log
-// Author : Avi
-// Revision : $Revision: #57 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Simple singleton implementation of log
-//============================================================================
-#include "TimeStamp.hpp"
-#include <cstdio>
-
-using namespace std;
-
-namespace ecf {
-
-std::string TimeStamp::now()
-{
- std::string time_stamp;
- now(time_stamp);
- return time_stamp;
-}
-
-void TimeStamp::now(std::string& time_stamp)
-{
- char t_fmt[255];
- time_t stamp = time( NULL);
- struct tm *tod = localtime(&stamp);
- sprintf(t_fmt, "[%02d:%02d:%02d %d.%d.%d] ", tod->tm_hour, tod->tm_min, tod->tm_sec,
- tod->tm_mday, tod->tm_mon + 1, tod->tm_year + 1900);
-
- time_stamp = t_fmt;
-}
-
-}
diff --git a/ecflow_4_0_7/ACore/src/TimeStamp.hpp b/ecflow_4_0_7/ACore/src/TimeStamp.hpp
deleted file mode 100644
index fb9cb25..0000000
--- a/ecflow_4_0_7/ACore/src/TimeStamp.hpp
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef TIMESTAMP_HPP_
-#define TIMESTAMP_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name : Log
-// Author : Avi
-// Revision : $Revision: #31 $
-//
-// Copyright 2009-2015 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <string>
-#include <boost/noncopyable.hpp>
-
-namespace ecf {
-
-// returns a string of format : "[%02d:%02d:%02d %d.%d.%d] "
-// "[hour:min:sec day.month.year] "
-// i.e "[05:26:20 29.10.2014] "
-class TimeStamp : private boost::noncopyable {
-public:
- static std::string now();
- static void now(std::string&);
-private:
- TimeStamp();
-};
-
-}
-
-#endif
diff --git a/ecflow_4_0_7/ACore/src/Version.cpp b/ecflow_4_0_7/ACore/src/Version.cpp
deleted file mode 100644
index e71d037..0000000
--- a/ecflow_4_0_7/ACore/src/Version.cpp
+++ /dev/null
@@ -1,131 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #132 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <sstream>
-#include "Version.hpp"
-#include "ecflow_version.h"
-#include <boost/version.hpp>
-
-namespace ecf {
-
-// ********************************************************************
-// IMPORTANT:
-// The version number is extracted externally.
-// see ACore/doc/extracting_version_number.ddoc
-//
-// See ACore/src/ecflow_version.h"
-// This file is generated from $WK/VERSION.cmake when cmake is run, i.e
-// sh -x $WK/cmake.sh debug
-//
-// It is also extracted by python, from VERSION.CMAKE check build/nightly/build.py
-// This minimises the places where we have hard code the version number.
-//
-// When changing the version change remember to:
-// - re-login into remote system to update ECFLOW_INSTALL_DIR & ECFLOW_PYTHON_INSTALL_DIR
-// required for interactive install
-//
-// To Install a new version on all the different platforms:
-// . build/nightly/quick_install_.sh
-// This is because the definition hold's the last version.
-// Hence we must rerun to update the version.
-//
-// ************************************************************************************
-// Use <minor_number>rc<number> for release candidates, Once release we revert back:
-// 0rc1 -> 0
-// 10rc3 -> 10
-// ************************************************************************************
-//
-// **Please update file history.ddoc with the changed made for each release ***
-// ********************************************************************
-#ifdef DEBUG
-const std::string Version::TAG = " (debug)"; // Old tag: beta(debug)
-#else
-const std::string Version::TAG = ""; // Old tag: beta
-#endif
-
-
-// See: http://www.cmake.org/cmake/help/cmake_tutorial.html
-// For defining version numbers. This is done is a separate file
-// that is then included
-std::string Version::description()
-{
- std::stringstream ss;
- ss << "Ecflow" << Version::TAG << " version(" << ECFLOW_RELEASE << "." << ECFLOW_MAJOR << "." << ECFLOW_MINOR;
-
- ss << ") boost(" << Version::boost() << ")";
- std::string the_comp = compiler();
- if (!the_comp.empty()) ss << " compiler(" << the_comp << ")";
-
- ss << " protocol(";
-#if defined(BINARY_ARCHIVE)
- ss << "BINARY_ARCHIVE)";
-#elif defined(PORTABLE_BINARY_ARCHIVE)
- ss << "PORTABLE_BINARY_ARCHIVE)";
-#elif defined(EOS_PORTABLE_BINARY_ARCHIVE)
- ss << "EOS_PORTABLE_BINARY_ARCHIVE)";
-#else
- ss << "TEXT_ARCHIVE)";
-#endif
-
- ss << " Compiled on " << __DATE__ << " " << __TIME__;
- return ss.str();
-}
-
-std::string Version::version()
-{
- std::stringstream ss;
- ss << "ecflow_" << ECFLOW_RELEASE << "_" << ECFLOW_MAJOR << "_" << ECFLOW_MINOR;
- return ss.str();
-}
-
-std::string Version::raw()
-{
- std::stringstream ss;
- ss << ECFLOW_RELEASE << "." << ECFLOW_MAJOR << "." << ECFLOW_MINOR;
- return ss.str();
-}
-
-std::string Version::boost()
-{
- std::stringstream ss;
- ss << BOOST_VERSION / 100000 << "." // major version
- << BOOST_VERSION / 100 % 1000 << "." // minor version
- << BOOST_VERSION % 100; // patch level
- return ss.str();
-}
-
-std::string Version::compiler()
-{
- std::stringstream ss;
-#if defined(_AIX)
- ss << "aix " << __IBMCPP__ ;
-#elif defined(HPUX)
- ss << "aCC " << __HP_aCC ; // type aCC +help, this will show compiler manual, search for Predefined Macros
-#else
-#if defined(__clang__)
- // To find the list of defines for clang use:
- // echo | /usr/local/apps/clang/current/bin/clang++ -dM -E -
- ss << "clang " << __clang_major__ << "." << __clang_minor__ ;
-#elif defined(__INTEL_COMPILER)
- ss << "intel " << __INTEL_COMPILER;
-#elif defined(_CRAYC)
- ss << "cray " << _CRAYC;
-#else
- ss << "gcc " << __GNUC__ << "." << __GNUC_MINOR__ << "." << __GNUC_PATCHLEVEL__;
-#endif
-#endif
- return ss.str();
-}
-
-}
diff --git a/ecflow_4_0_7/ACore/src/Version.hpp b/ecflow_4_0_7/ACore/src/Version.hpp
deleted file mode 100644
index c70d2ba..0000000
--- a/ecflow_4_0_7/ACore/src/Version.hpp
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef VERSION_HPP_
-#define VERSION_HPP_
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #15 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Holds the version of ECFlow. Checked against definition file
-// For each major release the major number should be
-// incremented.
-// If the parsing comes across a construct it does not recognize, then
-// an exception is thrown. i.e if a construct added in release 2.0 of ECF
-// is read in by version 1.0 of ECF. The exception should indicate the
-// current release
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <boost/noncopyable.hpp>
-#include <string>
-
-namespace ecf {
-
-class Version : private boost::noncopyable {
-public:
- /// Outputs a string of the form:
- /// ECF <tag> version release_.major_.minor_
- static std::string description();
-
- /// Outputs string of form: ecflow_<release>_<major>_<minor>
- /// This could be used by install
- static std::string version();
-
- /// Outputs string of form: <release>.<major>.<minor>
- static std::string raw();
-
-private:
- Version();
-
- static const std::string TAG; // alpha, beta, release
-
-private:
- /// return version of the boost library
- static std::string boost();
-
- // Return the version of the compiler. Can return empty string
- static std::string compiler();
-};
-}
-#endif
diff --git a/ecflow_4_0_7/ACore/src/WhiteListFile.cpp b/ecflow_4_0_7/ACore/src/WhiteListFile.cpp
deleted file mode 100644
index 03b7066..0000000
--- a/ecflow_4_0_7/ACore/src/WhiteListFile.cpp
+++ /dev/null
@@ -1,163 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Parser for white list file
-//============================================================================
-#include <pwd.h> /* getpwuid */
-#include <vector>
-#include <boost/lexical_cast.hpp>
-#include <boost/algorithm/string/trim.hpp>
-
-#include "WhiteListFile.hpp"
-#include "File.hpp"
-#include "Str.hpp"
-#include "Log.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-
-bool WhiteListFile::parse( std::map<std::string,bool>& validUsers, std::string& errorMsg )
-{
- std::vector<std::string> lines;
- if (File::splitFileIntoLines(smsWhiteListFile_,lines,true /* ignore empty lines */)) {
-
- bool foundVersionNumber = false; // can read from version 4.4.5 onwards
- for(size_t i = 0; i < lines.size(); ++i) {
-
- if (lines[i].empty()) continue;
- if (lines[i][0] == '#') continue; // ignore comments
-
- std::string theLine = lines[i];
- boost::algorithm::trim(theLine); // don't know why we get leading/trailing spaces
-
- std::vector< std::string > lineTokens;
- Str::split( theLine, lineTokens );
- if ( lineTokens.empty() ) continue;
-
-
- // version should be at the start
- if (!foundVersionNumber) {
-
- if (!validateVersionNumber(lineTokens[0], errorMsg )) {
- std::stringstream ss;
- ss << " " << i + 1 << ": " << lines[i] << "\n";
- ss << "for ECF_LISTS file " << smsWhiteListFile_ << "\n";
- errorMsg += ss.str();
- return false;
- }
- foundVersionNumber = true;
- continue;
- }
- else {
-
- addUser(lineTokens[0], validUsers);
- }
- }
-
- return true;
- }
-
- errorMsg += "Could not open file specified by ECF_LISTS ";
- errorMsg += smsWhiteListFile_;
- errorMsg += "\n";
- return false;
-}
-
-
-bool WhiteListFile::validateVersionNumber(const std::string& line, std::string& errorMsg) const
-{
- // Expect 4.4.14, Current syntax in force after 4.4.5
- // If first character is NUMERIC and we have dots
- bool firstCharIsNumeric = Str::NUMERIC().find( line[0], 0 ) != string::npos;
- if ( firstCharIsNumeric && line.find( "." ) != string::npos) {
-
- std::vector< std::string > versionNumberTokens;
- Str::split( line, versionNumberTokens, "." );
- if ( versionNumberTokens.size() != 3 ) {
- std::stringstream ss;
- ss << "Expected version of the form <int>.<int>.<int> i.e 4.4.14. but found invalid version number\n";
- errorMsg += ss.str();
- return false;
- }
-
- try {
- int major = boost::lexical_cast< int >( versionNumberTokens[0] );
- int minor = boost::lexical_cast< int >( versionNumberTokens[1] );
- int part = boost::lexical_cast< int >( versionNumberTokens[2] );
- if ( major < 4 ) {
- errorMsg += "Only white list files with a version >= 4.4.5 is supported\n";
- return false;
- }
- if ( major == 4 && minor < 4 ) {
- errorMsg += "Only white list files with a version >= 4.4.5 is supported\n";
- return false;
- }
- if ( major == 4 && minor == 4 && part < 5) {
- errorMsg += "Only white list files with a version >= 4.4.5 is supported\n";
- return false;
- }
- }
- catch ( boost::bad_lexical_cast& ) {
- errorMsg += "Invalid version number \n";
- return false;
- }
-
- return true;
- }
-
- errorMsg +="The version number not found. The version number must appear before the users.\n";
- return false;
-}
-
-
-void WhiteListFile::addUser(const std::string& line, std::map<std::string,bool>& validUsers) const
-{
- LOG_ASSERT(!line.empty(), "");
- if (line[0] == '-') {
- std::string user = line;
- user.erase(user.begin());
- validUsers.insert(std::make_pair(user,false)); // Read access
- return;
- }
-
- validUsers.insert(std::make_pair(line,true)); // write access
-}
-
-bool WhiteListFile::createWithReadAccess( const std::string& pathToFile,std::string& errorMsg)
-{
- std::vector<std::string> lines; lines.reserve( 2 );
-
- lines.push_back("4.4.14");
-
- string user = "-";
- struct passwd * thePassWord = getpwuid ( getuid() );
- user += string( thePassWord->pw_name ) ; // equivalent to the login name
-
- lines.push_back(user);
-
- return File::create(pathToFile,lines,errorMsg);
-}
-
-bool WhiteListFile::createWithWriteAccess( const std::string& pathToFile , std::string& errorMsg)
-{
- std::vector<std::string> lines; lines.reserve( 2 );
-
- lines.push_back("4.4.14");
-
- struct passwd * thePassWord = getpwuid ( getuid() );
- string user( thePassWord->pw_name ) ; // equivalent to the login name
-
- lines.push_back(user);
-
- return File::create(pathToFile,lines,errorMsg);
-}
diff --git a/ecflow_4_0_7/ACore/src/WhiteListFile.hpp b/ecflow_4_0_7/ACore/src/WhiteListFile.hpp
deleted file mode 100644
index 708b1c0..0000000
--- a/ecflow_4_0_7/ACore/src/WhiteListFile.hpp
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef WHITELISTFILE_CPP_
-#define WHITELISTFILE_CPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Parser for while list file
-//============================================================================
-
-#include <boost/noncopyable.hpp>
-#include <string>
-#include <map>
-
-
-class WhiteListFile : private boost::noncopyable {
-public:
- WhiteListFile(const std::string& file) : smsWhiteListFile_(file) {}
- ~WhiteListFile() {}
-
- // Parse the file if any errors found raise a warning
- // The parser expects version number 4.4.5
- // first user name, second true is write access, false read access
- bool parse( std::map<std::string,bool>& validUsers, std::string& errorMsg );
-
- // Function used in test:
- // Will overwrite the existing file
- static bool createWithReadAccess( const std::string& pathToFile, std::string& errorMsg);
- static bool createWithWriteAccess( const std::string& pathToFile, std::string& errorMsg);
-
-private:
-
- bool validateVersionNumber(const std::string& line, std::string& errorMsg) const;
- void addUser(const std::string& token, std::map<std::string,bool>& validUsers) const;
-
- std::string smsWhiteListFile_;
-};
-
-#endif
-
diff --git a/ecflow_4_0_7/ACore/src/boost_archive.cpp b/ecflow_4_0_7/ACore/src/boost_archive.cpp
deleted file mode 100644
index 19b6d8b..0000000
--- a/ecflow_4_0_7/ACore/src/boost_archive.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #11 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <stdio.h>
-#include <sstream>
-#include <boost/lexical_cast.hpp>
-
-#include "Str.hpp"
-#include "boost_archive.hpp"
-
-using namespace ecf;
-
-// return the current archive version
-int boost_archive::version()
-{
- std::stringstream ss;
-
-#if defined(BINARY_ARCHIVE)
- boost::archive::binary_oarchive oa( ss );
-#elif defined(PORTABLE_BINARY_ARCHIVE)
- portable_binary_oarchive oa(ss);
-#elif defined(EOS_PORTABLE_BINARY_ARCHIVE)
- eos::portable_oarchive oa(ss);
-#else
- boost::archive::text_oarchive oa( ss );
-#endif
-
- return oa.get_library_version();
-}
-
-
-// extract the boost archive version
-int boost_archive::extract_version(const std::string& boost_serial_str)
-{
- int version = 0;
- sscanf(boost_serial_str.c_str(),"22 serialization::archive %d",&version);
- return version;
-}
-
-bool boost_archive::replace_version(std::string& boost_serial_str, int the_new_version)
-{
- int version = extract_version(boost_serial_str);
- std::string old_version = boost::lexical_cast<std::string>(version);
- std::string new_version = boost::lexical_cast<std::string>(the_new_version);
- return Str::replace(boost_serial_str,old_version,new_version);
-}
-
-
diff --git a/ecflow_4_0_7/ACore/src/boost_archive.hpp b/ecflow_4_0_7/ACore/src/boost_archive.hpp
deleted file mode 100644
index 3c4dd59..0000000
--- a/ecflow_4_0_7/ACore/src/boost_archive.hpp
+++ /dev/null
@@ -1,96 +0,0 @@
-#ifndef BOOST_ARCHIVE_HPP_
-#define BOOST_ARCHIVE_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : This class has come about due to a bug with boost archive
-// includes. i.e if the same set of includes are not defined
-// in different compilations units. Then _NO_ errors/warnings are
-// issued instead we get a crash at run time when serialising
-// via base pointer.
-//
-// To get round this code will use this include to collate the
-// archives used in a single place.
-//============================================================================
-
-#if defined(TEXT_ARCHIVE) || !defined(BINARY_ARCHIVE) && !defined(PORTABLE_BINARY_ARCHIVE) && !defined(EOS_PORTABLE_BINARY_ARCHIVE)
-#include <boost/archive/text_iarchive.hpp>
-#include <boost/archive/text_oarchive.hpp>
-#endif
-
-#if defined(BINARY_ARCHIVE)
-#include <boost/archive/binary_oarchive.hpp>
-#include <boost/archive/binary_iarchive.hpp>
-#endif
-
-#if defined(PORTABLE_BINARY_ARCHIVE)
-#include "portable_binary_oarchive.hpp"
-#include "portable_binary_iarchive.hpp"
-#endif
-
-#if defined(EOS_PORTABLE_BINARY_ARCHIVE)
-#include "portable_oarchive.hpp"
-#include "portable_iarchive.hpp"
-#endif
-
-#include <boost/noncopyable.hpp>
-
-namespace ecf {
-
-/// Utility class for boost archive version
-///
-/// Boost archive version is specified in: $BOOST_ROOT/libs/serialization/src/basic_archive.cpp
-///
-/// boost 1.47 serialisation library archive version = 9
-/// boost 1.53 serialisation library archive version = 10
-/// boost 1.56 serialisation library archive version = 11 // however no change in library ?
-/// boost 1.57 serialisation library archive version = 11
-///
-/// boost supports old -> new only. In our case typically new_client needs to talk to old server
-/// Hence if new client archive version is newer we need to set to archive version used by server.
-/// *providing* there are compatible.
-///
-/// To enable this, user can export variable ECF_ALLOW_NEW_CLIENT_OLD_SERVER:
-///
-/// We expect following syntax:
-/// option 1/ export ECF_ALLOW_NEW_CLIENT_OLD_SERVER=<int>
-/// This for use ecflow_client command line
-///
-/// option 2/ export ECF_ALLOW_NEW_CLIENT_OLD_SERVER=<host>:<port>:<int>,<host>:<port>:<int>,<host>:<port>:<int>
-/// This for use with ui/viewer where we can have multiple clients, each could
-/// connect to different server version and hence archive.
-///
-/// export ECF_ALLOW_NEW_CLIENT_OLD_SERVER=10, the number used, must be the archive version
-/// that the boost server was built with.
-///
-class boost_archive : private boost::noncopyable {
-public:
-
- // return the current archive version
- static int version();
-
- // extract the boost archive version, assumes text archive *****
- static int extract_version(const std::string&);
-
- // replace archive version, return true if replace worked.
- static bool replace_version(std::string&, int new_version);
-
- // avoid hard coding
- static int version_1_47() { return 9;}
-
-private:
- boost_archive();
-};
-
-}
-#endif
diff --git a/ecflow_4_0_7/ACore/src/ecflow_version.h b/ecflow_4_0_7/ACore/src/ecflow_version.h
deleted file mode 100644
index 57996b9..0000000
--- a/ecflow_4_0_7/ACore/src/ecflow_version.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef ecflow_version_config_h
-#define ecflow_version_config_h
-
-#define ECFLOW_VERSION "4.0.7"
-
-#define ECFLOW_RELEASE "4"
-#define ECFLOW_MAJOR "0"
-#define ECFLOW_MINOR "7"
-
-#endif
diff --git a/ecflow_4_0_7/ACore/test/TestArgvCreator.cpp b/ecflow_4_0_7/ACore/test/TestArgvCreator.cpp
deleted file mode 100644
index bf943d4..0000000
--- a/ecflow_4_0_7/ACore/test/TestArgvCreator.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <boost/test/unit_test.hpp>
-#include <boost/lexical_cast.hpp>
-
-#include <iostream>
-#include "ArgvCreator.hpp"
-
-using namespace boost;
-using namespace std;
-
-BOOST_AUTO_TEST_SUITE( CoreTestSuite )
-
-static void doCheck(const std::vector<std::string>& theArgs)
-{
- ArgvCreator argvCr(theArgs);
-// cout << argvCr.toSString() << "\n";
- BOOST_CHECK_MESSAGE(argvCr.argc() == static_cast<int>(theArgs.size()), " argc incorrect");
-
- char** argv = argvCr.argv();
- for(int i=0; i < argvCr.argc(); i++) {
- BOOST_CHECK_MESSAGE(string(argv[i]) == theArgs[i],"Mismatch in args expected " << theArgs[i] << " but found " << argv[i]);
-// cout << i << ": " << argv[i] << "\n";
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_ArgvCreator )
-{
- cout << "ACore:: ...test_ArgvCreator\n";
-
- // O args
- std::vector<std::string> theArgs;
- doCheck(theArgs);
-
- // 1 args
- theArgs.push_back("arg1");
- doCheck(theArgs);
-
- // 2 args
- theArgs.clear();
- theArgs.push_back("arg1");
- theArgs.push_back("arg2");
- doCheck(theArgs);
-
- // 10 args
- theArgs.clear();
- for(int i = 0; i < 10; i++) {
- string theArg("arg");
- theArg += lexical_cast<string>(i);
- theArgs.push_back(theArg );
- }
- doCheck(theArgs);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ACore/test/TestCalendar.cpp b/ecflow_4_0_7/ACore/test/TestCalendar.cpp
deleted file mode 100644
index a65f347..0000000
--- a/ecflow_4_0_7/ACore/test/TestCalendar.cpp
+++ /dev/null
@@ -1,454 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #20 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <string>
-#include <iostream>
-#include <fstream>
-#include <boost/test/unit_test.hpp>
-#include <boost/date_time/posix_time/time_formatters.hpp>
-
-#include "Calendar.hpp"
-#include "TimeSeries.hpp"
-#include "Str.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost::posix_time;
-using namespace boost::gregorian;
-
-BOOST_AUTO_TEST_SUITE( CoreTestSuite )
-
-
-//static boost::posix_time::time_duration diff_d(boost::posix_time::time_duration t1, boost::posix_time::time_duration t2)
-//{
-// // t2 > t1 otherwise assume we have gone over midnight
-// if (t2 > t1) return t2 - t1;
-//
-// boost::posix_time::time_duration midnight(24,0,0);
-// boost::posix_time::time_duration diff_from_midnight = midnight - t1;
-// std::cout << to_simple_string(diff_from_midnight) << "\n";
-//
-// return diff_from_midnight + t2;
-//}
-//
-//BOOST_AUTO_TEST_CASE( test_calendar_3 )
-//{
-// cout << "ACore:: ...test_calendar_3\n";
-//
-// Calendar calendar;
-// BOOST_CHECK_MESSAGE(calendar.hybrid(),"Default calendar type should be hybrid");
-//
-// // init the calendar to 2009, Feb, 10th, 15 minutes past midnight
-//
-// boost::posix_time::time_duration t1(23,0,0);
-// boost::posix_time::time_duration t2(1,0,0);
-// boost::posix_time::time_duration expected(2,0,0);
-//// std::cout << to_simple_string(t1) << "\n";
-//// std::cout << to_simple_string(t2) << "\n";
-//// std::cout << to_simple_string(t1 - t2) << "\n";
-//// std::cout << to_simple_string(t2 - t1) << "\n";
-//
-// BOOST_CHECK_MESSAGE(diff_d(t1,t2) == expected," Expected " << to_simple_string(expected) << " but found " << to_simple_string(diff_d(t1,t2)));
-//}
-
-
-
-BOOST_AUTO_TEST_CASE( test_calendar_state_parsing )
-{
- cout << "ACore:: ...test_calendar_state_parsing\n";
-
- Calendar calendar;
- BOOST_CHECK_MESSAGE(!calendar.hybrid(),"Default calendar type should be real");
-
- // init the calendar to 2009, Feb, 10th, then write out the state
- boost::gregorian::date theDate(2009,2,10);
- ptime time(theDate, hours(23) + minutes(59));
- calendar.init(time, Calendar::REAL);
- std::string calendar_state = calendar.write_state();
-
- // read the state, into a different calendar & compare
- std::vector<std::string> lineTokens;
- Str::split(calendar_state,lineTokens);
- Calendar calendar2;
- calendar2.read_state(calendar_state,lineTokens);
- BOOST_CHECK_MESSAGE(calendar == calendar2,"Calendar should be the same\n" << calendar.toString() << "\n" << calendar2.toString());
-
- // Update calendar.
- calendar.update(minutes(2));
- BOOST_CHECK_MESSAGE(!(calendar == calendar2),"Calendar should be different");
-
- // re-compare after reloading state
- lineTokens.clear();
- calendar_state = calendar.write_state();
- Str::split(calendar_state,lineTokens);
- calendar2.read_state(calendar_state,lineTokens);
- BOOST_CHECK_MESSAGE(calendar == calendar2,"Calendar should be the same");
-}
-
-BOOST_AUTO_TEST_CASE( test_calendar_1 )
-{
- cout << "ACore:: ...test_calendar_1\n";
-
- Calendar calendar;
- BOOST_CHECK_MESSAGE(!calendar.hybrid(),"Default calendar type should be real");
-
- // init the calendar to 2009, Feb, 10th, 15 minutes past midnight
- boost::gregorian::date theDate(2009,2,10);
- ptime time(theDate, hours(23) + minutes(59));
- calendar.init(time, Calendar::HYBRID);
- BOOST_CHECK_MESSAGE(calendar.hybrid(),"init failed to reset calendar type");
-
- calendar.update(minutes(2));
-}
-
-
-BOOST_AUTO_TEST_CASE( test_calendar )
-{
- cout << "ACore:: ...test_calendar_basic\n";
-
- Calendar calendar;
- BOOST_CHECK_MESSAGE(!calendar.hybrid(),"Default calendar type should be real");
-
- // init the calendar to 2009, Feb, 10th, 15 minutes past midnight
- boost::gregorian::date theDate(2009,2,10);
- ptime time(theDate, minutes(15));
- calendar.init(time, Calendar::REAL);
- BOOST_CHECK_MESSAGE(!calendar.hybrid(),"Calendar should now be REAL");
-
- std::string expectedTime = "2009-Feb-10 00:15:00";
- std::string actualTime = to_simple_string(calendar.suiteTime());
- BOOST_CHECK_MESSAGE( actualTime == expectedTime,"Expected '" << expectedTime << "' but found " << actualTime);
-
-
- time_duration td = hours(1) + minutes(10);
- calendar.update(td);
- expectedTime = "2009-Feb-10 01:25:00";
- actualTime = to_simple_string(calendar.suiteTime());
- BOOST_CHECK_MESSAGE( actualTime == expectedTime,"Expected '" << expectedTime << "' but found " << actualTime);
-
-
- // Increment by 24 hours
- calendar.update(hours(24));
- expectedTime = "2009-Feb-11 01:25:00";
- actualTime = to_simple_string(calendar.suiteTime());
- BOOST_CHECK_MESSAGE( actualTime == expectedTime,"Expected '" << expectedTime << "' but found " << actualTime);
-}
-
-BOOST_AUTO_TEST_CASE( test_calendar_time_series_relative )
-{
- cout << "ACore:: ...test_calendar_time_series_relative\n";
-
- // init the calendar to 2009, Feb, 10th, 0 minutes past midnight
- Calendar calendar;
- calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::HYBRID);
-
- std::string expectedTime = "2010-Feb-10 00:00:00";
- std::string actualTime = to_simple_string(calendar.suiteTime());
- BOOST_CHECK_MESSAGE( actualTime == expectedTime,"Expected '" << expectedTime << "' but found " << actualTime);
-
- // Create a test when we can match a time series. Need to sync hour with suite time
- // at hour 1, suite time should also be 01:00, for test to work
- //
- // Create the time series: start 10:00
- // finish 20:00
- // incr 1:00
- TimeSeries timeSeries(TimeSlot(10,0), TimeSlot(20,0), TimeSlot(1,0), true/*relative*/);
-
- for(int hour=1; hour < 24; hour++) {
- // Update calendar every hour, then see we can match time series, *RELATIVE* to suite start
- calendar.update( time_duration( hours(1) ) );
- timeSeries.calendarChanged( calendar );
-
-// cerr << "hour = " << hour << " suiteTime " << to_simple_string(calendar.suiteTime()) << "\n";
- if (hour >= timeSeries.start().hour() && hour <=timeSeries.finish().hour()) {
- BOOST_CHECK_MESSAGE(timeSeries.isFree(calendar),"Calendar should match relative time series at hour " << hour );
- }
- else {
- BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar),"Calendar should NOT match relative time series at hour " << hour );
- }
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_calendar_time_series_relative_complex )
-{
- cout << "ACore:: ...test_calendar_time_series_relative_complex\n";
-
- // init the calendar to 2009, Feb, 10th, 0 minutes past midnight
- Calendar calendar;
- calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::HYBRID);
-
- // Create a test when we can match a time series
- // Create the time series: start 10:00
- // finish 20:00
- // incr 00:15
- TimeSeries timeSeries(TimeSlot(10,0), TimeSlot(20,0), TimeSlot(0,15),true/*relative*/);
-
- for(int hour=0; hour < 24; hour++) {
- for( int minute=0; minute<60; minute++) {
-
- // Update calendar every hour, then see we can match time series, *RELATIVE* to suite start
- calendar.update( minutes(1) );
- timeSeries.calendarChanged( calendar );
-
- tm suiteTm = to_tm(calendar.suiteTime());
-
- bool matches = timeSeries.isFree(calendar);
-
- bool intersects = ( suiteTm.tm_hour >= timeSeries.start().hour() &&
- suiteTm.tm_hour <= timeSeries.finish().hour() &&
- (suiteTm.tm_min == 0 || suiteTm.tm_min % timeSeries.incr().minute() == 0)
- );
- // Ovoid overshooting past end of series
- bool boundaryOk = true;
- if ( suiteTm.tm_hour == timeSeries.finish().hour() ) {
- boundaryOk = (suiteTm.tm_min <= timeSeries.finish().minute());
- }
-
- if ( intersects && boundaryOk )
- {
- BOOST_CHECK_MESSAGE(matches,
- "Calendar should match relative time series at "
- << suiteTm.tm_hour << Str::COLON() << suiteTm.tm_min
- << " suite time = " << to_simple_string(calendar.suiteTime()));
- if (!matches) {
- cerr << "suiteTm.tm_hour =" << suiteTm.tm_hour << " suiteTm.tm_min = " << suiteTm.tm_min
- << " timeSeries.start().hour() " << timeSeries.start().hour()
- << " timeSeries.start().minute() " << timeSeries.start().minute()
- << " timeSeries.finish().hour() " << timeSeries.finish().hour()
- << " timeSeries.finish().minute() " << timeSeries.finish().minute()
- << " suiteTm.tm_min % 15 = " << suiteTm.tm_min % 15
- << "\n";
- }
- }
- else {
- BOOST_CHECK_MESSAGE(!matches,
- "Calendar should NOT match relative time series at "
- << suiteTm.tm_hour << Str::COLON() << suiteTm.tm_min
- << " suite time = " << to_simple_string(calendar.suiteTime()));
-
- if (matches) {
- cerr << "suiteTm.tm_hour =" << suiteTm.tm_hour << " suiteTm.tm_min = " << suiteTm.tm_min
- << " timeSeries.start().hour() " << timeSeries.start().hour()
- << " timeSeries.start().minute() " << timeSeries.start().minute()
- << " timeSeries.finish().hour() " << timeSeries.finish().hour()
- << " timeSeries.finish().minute() " << timeSeries.finish().minute()
- << " suiteTm.tm_min % 15 = " << suiteTm.tm_min % 15
- << "\n";
- }
- }
- }
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_calendar_time_series_real )
-{
- cout << "ACore:: ...test_calendar_time_series_real\n";
-
- // init the calendar to 2009, Feb, 10th, 0 minutes past midnight
- Calendar calendar;
- calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::REAL);
-
- std::string expectedTime = "2010-Feb-10 00:00:00";
- std::string actualTime = to_simple_string(calendar.suiteTime());
- BOOST_CHECK_MESSAGE( actualTime == expectedTime,"Expected '" << expectedTime << "' but found " << actualTime);
-
- // Create a test when we can match a time series
- // Create the time series: start 10:00
- // finish 20:00
- // incr 1:00
- TimeSeries timeSeries(TimeSlot(10,0), TimeSlot(20,0), TimeSlot(1,0));
-
- for(int hour=1; hour < 24; hour++) {
- // Update calendar every hour, then see we can match time series, in REAL
- // Update will set the local time from the computers system clock, however
- // for testing this will need to be overriden below.
- calendar.update( time_duration( hours(1) ) );
-
- // cerr << "hour = " << hour << " suiteTime " << to_simple_string(calendar.suiteTime()) << "\n";
- if (hour >= timeSeries.start().hour() && hour <=timeSeries.finish().hour()) {
- BOOST_CHECK_MESSAGE(timeSeries.isFree(calendar),"Calendar should match time series at hour " << hour );
- }
- else {
- BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar),"Calendar should NOT match time series at hour " << hour );
- }
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_calendar_time_series_real_complex )
-{
- cout << "ACore:: ...test_calendar_time_series_real_complex\n";
-
- // init the calendar to 2009, Feb, 10th, 0 minutes past midnight
- Calendar calendar;
- calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::REAL);
-
- // Create a test when we can match a time series
- // Create the time series: start 10:00
- // finish 20:00
- // incr 00:15
- TimeSeries timeSeries(TimeSlot(10,0), TimeSlot(20,0), TimeSlot(0,15));
-
- for(int hour=0; hour < 24; hour++) {
- for( int minute=0; minute<60; minute++) {
-
- // Update calendar every minute, then see we can match time series, *RELATIVE* to suite start
- calendar.update( minutes(1) );
-
- tm suiteTm = to_tm(calendar.suiteTime());
-
- bool matches = timeSeries.isFree(calendar);
-
- bool intersects = ( suiteTm.tm_hour >= timeSeries.start().hour() &&
- suiteTm.tm_hour <= timeSeries.finish().hour() &&
- (suiteTm.tm_min == 0 || suiteTm.tm_min % timeSeries.incr().minute() == 0)
- );
- // Ovoid overshooting past end of series
- bool boundaryOk = true;
- if ( suiteTm.tm_hour == timeSeries.finish().hour() ) {
- boundaryOk = (suiteTm.tm_min <= timeSeries.finish().minute());
- }
-
- if ( intersects && boundaryOk )
- {
- BOOST_CHECK_MESSAGE(matches,
- "Calendar should match relative time series at "
- << suiteTm.tm_hour <<":"<< suiteTm.tm_min
- << " suite time = " << to_simple_string(calendar.suiteTime()));
- if (!matches) {
- cerr << "suiteTm.tm_hour =" << suiteTm.tm_hour << " suiteTm.tm_min = " << suiteTm.tm_min
- << " timeSeries.start().hour() " << timeSeries.start().hour()
- << " timeSeries.start().minute() " << timeSeries.start().minute()
- << " timeSeries.finish().hour() " << timeSeries.finish().hour()
- << " timeSeries.finish().minute() " << timeSeries.finish().minute()
- << " suiteTm.tm_min % 15 = " << suiteTm.tm_min % 15
- << "\n";
- }
- }
- else {
- BOOST_CHECK_MESSAGE(!matches,
- "Calendar should NOT match relative time series at "
- << suiteTm.tm_hour <<":"<< suiteTm.tm_min
- << " suite time = " << to_simple_string(calendar.suiteTime()));
-
- if (matches) {
- cerr << "suiteTm.tm_hour =" << suiteTm.tm_hour << " suiteTm.tm_min = " << suiteTm.tm_min
- << " timeSeries.start().hour() " << timeSeries.start().hour()
- << " timeSeries.start().minute() " << timeSeries.start().minute()
- << " timeSeries.finish().hour() " << timeSeries.finish().hour()
- << " timeSeries.finish().minute() " << timeSeries.finish().minute()
- << " suiteTm.tm_min % 15 = " << suiteTm.tm_min % 15
- << "\n";
- }
- }
- }
- }
-}
-
-
-BOOST_AUTO_TEST_CASE( test_calendar_hybrid )
-{
- cout << "ACore:: ...test_calendar_hybrid\n";
-
- // The hybrid calendar should not change the suite date.
- // Test by updateing calendar by more than 24 hours
-
- // init the calendar to 2009, Feb, 10th, 0 minutes past midnight
- Calendar calendar;
- calendar.init(ptime(date(2010,2,10), minutes(0)),Calendar::HYBRID);
- BOOST_CHECK_MESSAGE(calendar.hybrid(),"calendar type should be hybrid");
-
-
- std::string expectedTime = "2010-Feb-10 00:00:00";
- std::string actualTime = to_simple_string(calendar.suiteTime());
- BOOST_CHECK_MESSAGE( actualTime == expectedTime,"Expected '" << expectedTime << "' but found " << actualTime);
-
- std::string expectedDate = "2010-Feb-10";
-
- for(int hour=1; hour < 60; hour++) {
- // Update calendar every hour, for 60 hours
- // the date should be the same, i.e 2009, Feb, 10th
-
- ptime timeBeforeUpdate = calendar.suiteTime();
-
- calendar.update( time_duration( hours(1) ) );
-
- ptime timeAfterUpdate = calendar.suiteTime();
-
-// cerr << "hour = " << hour << " timeBeforeUpdate " << to_simple_string(timeBeforeUpdate)
-// << " timeAfterUpdate = " << to_simple_string(timeAfterUpdate) << "\n";
-
- if (hour != 24 && hour != 48) {
- time_period diff(timeBeforeUpdate,timeAfterUpdate);
- time_duration gap = diff.length();
- BOOST_CHECK_MESSAGE( gap.hours() == 1,"Expected one hour difference but found " << gap.hours() << " at hour " << hour);
- }
-
- std::string actualDate = to_simple_string(calendar.suiteTime().date());
- BOOST_CHECK_MESSAGE( actualDate == expectedDate,"Expected '" << expectedDate << "' but found " << actualDate << " at hour " << hour);
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_day_changed_for_real )
-{
- cout << "ACore:: ...test_day_changed_for_real\n";
-
- // init the calendar to 2009, Feb, 10th, 0 minutes past midnight
- Calendar calendar;
- calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::REAL);
- BOOST_CHECK_MESSAGE(!calendar.hybrid(),"calendar type should be real");
-
- for(int hour=1; hour < 73; hour++) {
- // Update calendar every hour, for 72 hours
- calendar.update( time_duration( hours(1) ) );
-
- if (hour == 24 || hour == 48 || hour == 72) {
- BOOST_CHECK_MESSAGE( calendar.dayChanged(),"Expected day change at hour " << hour << " calendar " << calendar.toString());
- }
- else {
- BOOST_CHECK_MESSAGE( !calendar.dayChanged(),"Un-Expected day change at hour " << hour << " calendar " << calendar.toString());
- }
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_day_changed_for_hybrid )
-{
- cout << "ACore:: ...test_day_changed_for_hybrid\n";
-
- // init the calendar to 2009, Feb, 10th, 0 minutes past midnight
- Calendar calendar; // default clock is real
- calendar.init(ptime(date(2010,2,10), minutes(0)),Calendar::HYBRID);
- BOOST_CHECK_MESSAGE(calendar.hybrid(),"calendar type should be hybrid");
-
- // HYBRID calendars allow for day change but not date.
- std::string expected_date = to_simple_string(calendar.date());
-
- for(int hour=1; hour < 73; hour++) {
- // Update calendar every hour, for 72 hours
- calendar.update( time_duration( hours(1) ) );
-
- BOOST_CHECK_MESSAGE( expected_date == to_simple_string(calendar.date()) ,
- "Unexpected date change for hybrid calendar at hour " << hour);
-
- // Day should change even for hybrid calendar,
- if (hour == 24 || hour == 48 || hour == 72) {
- BOOST_CHECK_MESSAGE( calendar.dayChanged(),"Expected day change at hour " << hour << " calendar " << calendar.toString());
- }
- else {
- BOOST_CHECK_MESSAGE( !calendar.dayChanged(),"Un-Expected day change at hour " << hour << " calendar " << calendar.toString());
- }
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ACore/test/TestExceptionSafety.cpp b/ecflow_4_0_7/ACore/test/TestExceptionSafety.cpp
deleted file mode 100644
index 9a6f76f..0000000
--- a/ecflow_4_0_7/ACore/test/TestExceptionSafety.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-////============================================================================
-//// Name :
-//// Author : Avi
-//// Revision : $Revision: #5 $
-////
-//// Copyright 2009-2012 ECMWF.
-//// This software is licensed under the terms of the Apache Licence version 2.0
-//// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-//// In applying this licence, ECMWF does not waive the privileges and immunities
-//// granted to it by virtue of its status as an intergovernmental organisation
-//// nor does it submit to any jurisdiction.
-////
-//// Description :
-////============================================================================
-//#include <boost/test/unit_test.hpp>
-//#include <boost/bind.hpp>
-//
-//#include <boost/test/exception_safety.hpp>
-//#include <boost/test/mock_object.hpp>
-//#include <boost/make_shared.hpp>
-//#include <boost/shared_ptr.hpp>
-//
-//using namespace std;
-//using namespace boost::itest;
-//
-//BOOST_AUTO_TEST_SUITE( CoreTestSuite )
-//
-//// Example of how to check for for exception safety
-//// COMMENTED OUT SINCE THIS CAUSES THOUSANDS OF VALGRIND ERRORS
-//
-//template<class T1, class T2>
-//void algo(
-// boost::shared_ptr<T1> x,
-// boost::shared_ptr<T2> y) {}
-//
-//typedef mock_object<> Mock;
-//typedef boost::shared_ptr<Mock> SharedMock;
-//
-//BOOST_TEST_EXCEPTION_SAFETY( fail_test )
-//{
-// algo( SharedMock( new Mock() ),
-// SharedMock( new Mock() ));
-//}
-//
-//BOOST_TEST_EXCEPTION_SAFETY( success_test )
-//{
-// algo( boost::make_shared<Mock>(),
-// boost::make_shared<Mock>());
-//}
-//
-//BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ACore/test/TestFile.cpp b/ecflow_4_0_7/ACore/test/TestFile.cpp
deleted file mode 100644
index 216169c..0000000
--- a/ecflow_4_0_7/ACore/test/TestFile.cpp
+++ /dev/null
@@ -1,312 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #24 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/timer.hpp>
-#include <boost/foreach.hpp>
-#include <boost/lexical_cast.hpp>
-
-#include <string>
-#include <iostream>
-#include <fstream>
-#include <stdlib.h> // for getenv()
-
-#include "DurationTimer.hpp"
-#include "File.hpp"
-#include "NodePath.hpp"
-
-using namespace boost;
-using namespace std;
-using namespace ecf;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( CoreTestSuite )
-
-//#define FILE_PERF_CHECK_IMPLEMENTATIONS 1;
-
-BOOST_AUTO_TEST_CASE( test_splitFileIntoLines )
-{
- // This is sanity test for splitFileIntoLines used extensively
- cout << "ACore:: ...test_splitFileIntoLines\n";
-
- std::string path = File::test_data("ACore/test/data/test_splitFileIntoLines.txt","ACore");
-
- std::string theText = "This is a test string";
- {
- {
- std::ofstream file_with_one_line( path.c_str() );
- file_with_one_line << theText;
- }
-
- std::vector<std::string> lines;
- BOOST_CHECK_MESSAGE( File::splitFileIntoLines(path,lines)," Failed to open file " << path);
- BOOST_CHECK_MESSAGE( lines.size() == 1," Expected 1 line but found " << lines.size());
-
- fs::remove(path); // Remove the file. Comment out for debugging
- }
-
- {
- {
- std::ofstream file_with_one_line( path.c_str() );
- file_with_one_line << theText << "\n"; // addition of '/n' , should still be one line
- }
-
- std::vector<std::string> lines;
- BOOST_CHECK_MESSAGE( File::splitFileIntoLines(path,lines)," Failed to open file " << path);
- BOOST_CHECK_MESSAGE( lines.size() == 1," Expected 1 line but found " << lines.size());
-
- fs::remove(path); // Remove the file. Comment out for debugging
- }
-
- {
- {
- std::ofstream file_with_two_line( path.c_str() );
- file_with_two_line << theText << "\n";
- file_with_two_line << theText;
- }
-
- std::vector<std::string> lines;
- BOOST_CHECK_MESSAGE( File::splitFileIntoLines(path,lines)," Failed to open file " << path);
- BOOST_CHECK_MESSAGE( lines.size() == 2," Expected 2 line but found " << lines.size());
-
- fs::remove(path); // Remove the file. Comment out for debugging
- }
-
- {
- {
- std::ofstream file_with_three_line( path.c_str() );
- file_with_three_line << theText << "\n";
- file_with_three_line << theText << "\n";
- file_with_three_line << theText;
- }
-
- std::vector<std::string> lines;
- BOOST_CHECK_MESSAGE( File::splitFileIntoLines(path,lines)," Failed to open file " << path);
- BOOST_CHECK_MESSAGE( lines.size() == 3," Expected 3 line but found " << lines.size());
-
- fs::remove(path); // Remove the file. Comment out for debugging
- }
-
- {
- {
- std::ofstream file_with_three_line( path.c_str() );
- file_with_three_line << theText << "\n";
- file_with_three_line << theText << "\n";
- file_with_three_line << theText << "\n";
- }
-
- std::vector<std::string> lines;
- BOOST_CHECK_MESSAGE( File::splitFileIntoLines(path,lines)," Failed to open file " << path);
- BOOST_CHECK_MESSAGE( lines.size() == 3," Expected 3 line but found " << lines.size());
-
- fs::remove(path); // Remove the file. Comment out for debugging
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_file_tokenizer )
-{
- cout << "ACore:: ...test_file_tokenizer\n";
-
- std::string path = File::test_data("ACore/test/data/test_file_tokenizer.txt","ACore");
-
- size_t linesWithText = 100;
- size_t totalLines = 151;
- std::string theText = "This is a test string";
- {
- std::ofstream file( path.c_str() );
- for(size_t i =0; i < linesWithText; i++) {
- if (i % 2 == 0) file << "\n"; // 51 empty lines
- file << theText << "\n"; // 100 text lines
- }
- }
- {
- std::vector<std::string> lines;
- BOOST_CHECK_MESSAGE( File::splitFileIntoLines(path,lines,true/*ignore empty lines*/)," Failed to open file " << path);
- BOOST_CHECK_MESSAGE( lines.size() == linesWithText,"Expected " << linesWithText << " but found " << lines.size());
- BOOST_CHECK_MESSAGE( lines[0] == theText,"Expected '" << theText << "' but found " << lines[0]);
- BOOST_CHECK_MESSAGE( lines[linesWithText-1] == theText,"Expected '" << theText << "' but found " << lines[linesWithText-1]);
-
- lines.clear();
- BOOST_CHECK_MESSAGE( File::splitFileIntoLines(path,lines)," Failed to open file " << path);
- BOOST_CHECK_MESSAGE( lines.size() == totalLines-1,"Expected " << totalLines-1 << " but found " << lines.size());
- BOOST_CHECK_MESSAGE( lines[0] == "","Expected empty string but found " << lines[0]);
- BOOST_CHECK_MESSAGE( lines[1] == theText,"Expected '" << theText << "' but found " << lines[1]);
- BOOST_CHECK_MESSAGE( lines[2] == theText,"Expected '" << theText << "' but found " << lines[2]);
- BOOST_CHECK_MESSAGE( lines[3] == "","Expected empty string but found " << lines[3]);
- }
-
-#ifdef FILE_PERF_CHECK_IMPLEMENTATIONS
- {
- size_t openFileNTimes = 100000;
- boost::timer timer; // measures CPU, replace with cpu_timer with boost > 1.51, measures cpu & elapsed
- for (size_t i = 0; i < openFileNTimes; i++) {
- std::vector<std::string> lines;
- BOOST_CHECK_MESSAGE( File::splitFileIntoLines(path,lines)," Failed to open file " << path);
- }
- cout << "Time for opening file " << openFileNTimes << " times = " << timer.elapsed() << "\n";
- }
-#endif
-
- // Remove the file. Comment out for debugging
- fs::remove(path);
-}
-
-BOOST_AUTO_TEST_CASE( test_file_backwardSearch )
-{
- cout << "ACore:: ...test_file_backwardSearch\n";
-
- std::string nodePath = "dir0/dir1/dir2/dir3/dir4/dir5";
- std::string rootPath = File::test_data("ACore/test/data","ACore");
- std::string expected = File::test_data("ACore/test/data/","ACore") + nodePath;
-
- std::string path = rootPath;
- std::string dir = "dir";
- for(int i = 0; i < 6; i++) {
- path += "/" + dir + boost::lexical_cast<std::string>(i);
- }
- // Should have test/data/dir0/dir1/dir3/dir3/dir4/dir5
- // or ACore/test/data/dir0/dir1/dir3/dir3/dir4/dir5
- BOOST_REQUIRE_MESSAGE(path == expected," Error expected " << expected << " but found " << path);
-
- // Create the missing directories
- BOOST_REQUIRE_MESSAGE(File::createDirectories(path),"Failed to create dirs");
-
- // Create a file in each of the directories. See Page 21 SMS User Guide.
- std::vector<std::string> fileContents; fileContents.push_back("something");
- vector<std::string> nodePathTokens;
- NodePath::split(nodePath,nodePathTokens);
- while ( nodePathTokens.size() > 0 ) {
-
- // Reconstitute the path
- std::string path = NodePath::createPath(nodePathTokens);
- std::string combinedPath = rootPath + path;
-
- BOOST_REQUIRE_MESSAGE(File::createDirectories(combinedPath),"Failed to create dirs " << combinedPath);
-
- combinedPath += File::ECF_EXTN(); // .ecf, .man , etc
-
- //std::cout << "Creating file " << combinedPath << "\n";
- std::string errorMsg;
- BOOST_REQUIRE_MESSAGE(File::create(combinedPath,fileContents,errorMsg),"Failed to create " << combinedPath << " because " << errorMsg);
-
- nodePathTokens.erase(nodePathTokens.begin()); // consume first path token
- }
-
- // Now do a backward search for them
- int filesFound = 0;
- for(int i = 0; i < 6; i++) {
- std::string theFile = File::backwardSearch(rootPath,nodePath,File::ECF_EXTN() );
- BOOST_CHECK_MESSAGE( !theFile.empty(), i << ": Failed to find dir5.ecf with rootPath " << rootPath << " and node path " << nodePath);
- if (!theFile.empty()) {
- filesFound++;
-// std::cout << "About to remove file " << theFile << "\n";
- fs::remove(theFile); // remove it so we don't find it again.
- }
- }
- // Expect the following files to be found:
- // test/data/dir0/dir1/dir2/dir3/dir4/dir5.ecf
- // test/data/dir1/dir2/dir3/dir4/dir5.ecf
- // test/data/dir2/dir3/dir4/dir5.ecf
- // test/data/dir3/dir4/dir5.ecf
- // test/data/dir4/dir5.ecf
- // test/data/dir5.ecf
- BOOST_CHECK_MESSAGE( filesFound == 6 ," expect to find 6 files but found " << filesFound );
-
- // Remove the test dir. Comment out for debugging
- for(int i = 0; i < 6; i++) {
- path = rootPath + "/" + dir + boost::lexical_cast<std::string>(i);
- BOOST_CHECK_MESSAGE(File::removeDir( path ),"Failed to remove dir " << path);
- }
-}
-
-
-BOOST_AUTO_TEST_CASE( test_create_missing_directories )
-{
- cout << "ACore:: ...test_create_missing_directories";
-
- // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode.
- if (getenv("ECFLOW_CRAY_BATCH")) {
- cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n";
- return;
- }
- cout << "\n";
-
- std::string nodePath = "dir0/dir1/dir2/dir3/dir4/dir5";
- std::string rootPath = File::test_data("ACore/test/data","ACore");
- std::string expected = File::test_data("ACore/test/data/","ACore") + nodePath;
-
- std::string dir_remove = rootPath + "/dir0";
- {
- // Test basics first, expect "ACore/test/data/dir0/dir1/dir2/dir3/dir4/dir5" to be created
- BOOST_CHECK_MESSAGE(File::createMissingDirectories(expected),expected << " expected directories to be created");
- BOOST_CHECK_MESSAGE(fs::exists(expected),expected << " directory not created");
-
- // remove the directory
- BOOST_CHECK_MESSAGE(File::removeDir( dir_remove ),"Failed to remove dir " << dir_remove);
-
-// fs::path fs_path(expected);
-// std::cout << "parent path " << fs_path.parent_path() << "\n";
-// std::cout << "root path " << fs_path.root_path() << "\n";
-// std::cout << "root name " << fs_path.root_name() << "\n";
-// std::cout << "root directory " << fs_path.root_directory() << "\n";
-// std::cout << "relative_path " << fs_path.relative_path() << "\n";
-// std::cout << "filename " << fs_path.filename() << "\n";
-// std::cout << "stem " << fs_path.stem() << "\n";
-// std::cout << "extension " << fs_path.extension() << "\n";
- }
- {
- // Test "ACore/test/data/dir0/dir1/dir2/dir3/dir4/dir5/fred.ecf" to be created
- std::string dir_with_file = expected + "/fred.ecf";
- BOOST_CHECK_MESSAGE(File::createMissingDirectories(dir_with_file),"Expected '" << dir_with_file << "' to be created");
- BOOST_CHECK_MESSAGE(fs::exists(expected),expected << " directory not created");
-
- // remove the directory
- BOOST_CHECK_MESSAGE(File::removeDir( dir_remove ),"Failed to remove dir " << dir_remove);
-
-// fs::path fs_path(dir_with_file);
-// std::cout << "parent path " << fs_path.parent_path() << "\n";
-// std::cout << "root path " << fs_path.root_path() << "\n";
-// std::cout << "root name " << fs_path.root_name() << "\n";
-// std::cout << "root directory " << fs_path.root_directory() << "\n";
-// std::cout << "relative_path " << fs_path.relative_path() << "\n";
-// std::cout << "filename " << fs_path.filename() << "\n";
-// std::cout << "stem " << fs_path.stem() << "\n";
-// std::cout << "extension " << fs_path.extension() << "\n";
- }
-
- {
- // Create directories twice. Need to minimise call to fstat
- BOOST_CHECK_MESSAGE(File::createMissingDirectories(expected),"expected file to be created");
- BOOST_CHECK_MESSAGE(File::createMissingDirectories(expected),"expected file to be created");
- BOOST_CHECK_MESSAGE(fs::exists(expected),expected << " directory not created");
-
- // remove the directory
- BOOST_CHECK_MESSAGE(File::removeDir( dir_remove ),"Failed to remove dir " << dir_remove);
- }
-
- {
- // Create directories twice. Need to minimise call to fstat
- std::string dir_with_file = expected + "/fred.ecf";
- BOOST_CHECK_MESSAGE(File::createMissingDirectories(dir_with_file),"expected file to be created");
- BOOST_CHECK_MESSAGE(File::createMissingDirectories(dir_with_file),"expected file to be created");
- BOOST_CHECK_MESSAGE(fs::exists(expected),expected << " directory not created");
-
- // remove the directory
- BOOST_CHECK_MESSAGE(File::removeDir( dir_remove ),"Failed to remove dir " << dir_remove);
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ACore/test/TestGetUserDetails.cpp b/ecflow_4_0_7/ACore/test/TestGetUserDetails.cpp
deleted file mode 100644
index 7529d7a..0000000
--- a/ecflow_4_0_7/ACore/test/TestGetUserDetails.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-//#include <boost/test/unit_test.hpp>
-//#include <string>
-//#include <iostream>
-//
-//
-//#include <pwd.h> /* getpwdid */
-//#include <sys/types.h>
-//#include <unistd.h>
-//#include <stdio.h>
-//
-//using namespace std;
-//using namespace ecf;
-//
-//BOOST_AUTO_TEST_SUITE( CoreTestSuite )
-
-//BOOST_AUTO_TEST_CASE( test_get_user_details )
-//{
-// cout << "ACore:: ...test_get_user_details\n";
-//
-//
-// struct passwd *passwd; /* man getpwuid */
-//
-// passwd = getpwuid ( getuid()); /* Get the uid of the running processand use it to get a record from /etc/passwd */
-//
-// printf("\n The Real User Name is %s ", passwd->pw_gecos);
-//
-// printf("\n The Login Name is %s ", passwd->pw_name);
-//
-// printf("\n The Home Directory is %s", passwd->pw_dir);
-//
-// printf("\n The Login Shell is %s ", passwd->pw_shell);
-//
-// printf("\n The Passwd is %s ", getpwuid(getuid())->pw_passwd);
-//
-// printf("\n The uid is %lu ", (unsigned long) getpwuid(getuid())->pw_uid);
-//
-// printf("\n The gid is %lu \n\n", (unsigned long) getpwuid(getuid())->pw_gid);
-//}
-
-//BOOST_AUTO_TEST_SUITE_END()
-
-
diff --git a/ecflow_4_0_7/ACore/test/TestLog.cpp b/ecflow_4_0_7/ACore/test/TestLog.cpp
deleted file mode 100644
index 82c32a4..0000000
--- a/ecflow_4_0_7/ACore/test/TestLog.cpp
+++ /dev/null
@@ -1,365 +0,0 @@
-//============================================================================
-// Name : Request
-// Author : Avi
-// Revision : $Revision: #21 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <iostream>
-#include <fstream>
-#include <stdlib.h> // for getenv()
-#include <string>
-
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-
-#include "Log.hpp"
-#include "File.hpp"
-#include "DurationTimer.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( CoreTestSuite )
-
-static std::string getLogPath() {
-
- return File::test_data("ACore/test/logfile.txt","ACore");
-}
-
-BOOST_AUTO_TEST_CASE( test_log )
-{
- cout << "ACore:: ...test_log\n";
-
- std::string path = getLogPath();
-
- // delete the log file if it exists.
- fs::remove(path);
- BOOST_CHECK_MESSAGE(!fs::exists( path ), "log file not deleted " << path << " not created \n");
-
- Log::create(path);
- LOG(Log::MSG,"First Message");
- LOG(Log::LOG,"LOG");
- LOG(Log::ERR,"ERROR");
- LOG(Log::WAR,"WARNING");
- LOG(Log::DBG,"DEBUG");
- LOG(Log::OTH,"OTHER");
- log(Log::OTH,"test: void log(Log::LogType,const std::string& message)");
-
- LOG(Log::OTH,"test: LOG(level,path << path) " << path << " " << path);
-
- Log::instance()->log(Log::OTH,"OTHER2");
-
- BOOST_CHECK_MESSAGE(fs::exists( path ), "log file " << path << " not created \n");
-}
-
-BOOST_AUTO_TEST_CASE( test_log_append )
-{
- cout << "ACore:: ...test_log_append\n";
-
- std::string path = getLogPath();
-
- BOOST_CHECK_MESSAGE(fs::exists( path ), "log file " << path << " not created by previous test\n");
-
- LOG(Log::MSG,"Last Message");
-
- // Load the log file into a vector, of strings, and test content
- std::vector<std::string> lines;
- BOOST_REQUIRE_MESSAGE(File::splitFileIntoLines(path,lines,true/*IGNORE EMPTY LINE AT THE END*/),"Failed to open log file");
- BOOST_REQUIRE(lines.size() != 0);
- BOOST_CHECK_MESSAGE(lines.size() == 10," Expected 10 lines in log, but found " << lines.size() << "\n");
- BOOST_CHECK_MESSAGE(lines[0].find("First Message") != string::npos,"Expected first line to contain 'First Message' but found " << lines[0] << "\n");
- BOOST_CHECK_MESSAGE(lines.back().find("Last Message") != string::npos,"Expected last line to contain 'Last Message' but found " << lines.back() << "\n");
-
- // Clear the log file. Comment out for debugging
- Log::instance()->clear();
- BOOST_CHECK_MESSAGE(fs::file_size( path ) == 0, "Clear of log file failed\n");
-
- // Remove the log file. Comment out for debugging
- fs::remove(path);
-
- // Explicitly destroy log. To keep valgrind happy
- Log::destroy();
-}
-
-
-BOOST_AUTO_TEST_CASE( test_log_path )
-{
- cout << "ACore:: ...test_log_path\n";
-
- Log::create("test_log_path.log");
-
- // make sure path returned is absolute
- std::string path = Log::instance()->path();
- BOOST_REQUIRE_MESSAGE(path[0] == '/',"Expected absolute paths for log file but found " << path);
-
- // Remove the log file. Comment out for debugging
- fs::remove(path);
-
- // Explicitly destroy log. To keep valgrind happy
- Log::destroy();
-}
-
-BOOST_AUTO_TEST_CASE( test_log_new_path_errors )
-{
- cout << "ACore:: ...test_log_new_path_errors\n";
-
- // delete the log file if it exists.
- fs::remove(getLogPath());
-
- // create a now log file.
- Log::create(getLogPath());
- LOG(Log::MSG,"First Message");
- LOG(Log::LOG,"LOG");
-
- // Specify bad paths for new log file
- // First test empty path throws
- BOOST_REQUIRE_THROW(Log::instance()->new_path(""),std::runtime_error);
-
- // If a path is specified make sure parent directory exists
- fs::path current_path = fs::current_path();
- std::string path2 = current_path.string();
- path2 += "/a/made/up/path/fred.log";
- //cout << path2<< "\n";
- BOOST_REQUIRE_THROW(Log::instance()->new_path(path2),std::runtime_error);
-
- // Make sure path does not correspond to a directory
- // cout << "parent directory: " << current_path.parent_path() << "\n";
- BOOST_REQUIRE_THROW(Log::instance()->new_path( current_path.parent_path().string() ),std::runtime_error);
-
-// {
-// fs::path valid_path = getLogPath();
-// std::cout << "valid_path = " << valid_path << "\n";
-// std::cout << "valid_path.root_path(): " << valid_path.root_path() << "\n";
-// std::cout << "valid_path.root_name() : " << valid_path.root_name() << "\n";
-// std::cout << "valid_path.root_directory() : " << valid_path.root_directory() << "\n";
-// std::cout << "valid_path.relative_path() : " << valid_path.relative_path() << "\n";
-// std::cout << "valid_path.parent_path() : " << valid_path.parent_path() << "\n";
-// std::cout << "valid_path.filename() : " << valid_path.filename() << "\n";
-// std::cout << "valid_path.stem() : " << valid_path.stem() << "\n";
-// std::cout << "valid_path.extension() : " << valid_path.extension() << "\n";
-// }
-
- // Remove the log file. Comment out for debugging
- fs::remove(Log::instance()->path());
-
- // Explicitly destroy log. To keep valgrind happy
- Log::destroy();
-}
-
-
-BOOST_AUTO_TEST_CASE( test_log_new_path )
-{
- cout << "ACore:: ...test_log_new_path\n";
-
- // delete the log file if it exists.
- fs::remove(getLogPath());
-
- // create a new log file.
- Log::create(getLogPath());
- BOOST_CHECK_MESSAGE(fs::exists( Log::instance()->path() ), "Log file should be created after explicit call to Log::create()\n");
- LOG(Log::LOG,"LOG");
- fs::remove(Log::instance()->path());
-
-
- // Specify a new log path. Path could be a relative path like "test/logfile.log"
- std::string relative_path = File::test_data("ACore/test/logfile.log","ACore");
-
- BOOST_REQUIRE_NO_THROW(Log::instance()->new_path( relative_path ));
- BOOST_CHECK_MESSAGE(!fs::exists( Log::instance()->path() ), "Log file should *NOT* be created until first message is logged\n");
- LOG(Log::LOG,"LOG");
- BOOST_CHECK_MESSAGE(fs::exists( Log::instance()->path() ), "Log file should be created after first message is logged\n");
- fs::remove(Log::instance()->path());
-
-
- // Specify a new log path. This time we just specify a file name, without a path.
- BOOST_REQUIRE_NO_THROW(Log::instance()->new_path( "testlog.log" ));
- BOOST_CHECK_MESSAGE(!fs::exists( Log::instance()->path() ), "Log file should not be created until first message is logged\n");
- // File not created until a message is logged
- LOG(Log::LOG,"LOG");
- BOOST_CHECK_MESSAGE(fs::exists( Log::instance()->path() ), "Log file should be created after first message is logged\n");
- fs::remove(Log::instance()->path());
-
- // Explicitly destroy log. To keep valgrind happy
- Log::destroy();
-}
-
-BOOST_AUTO_TEST_CASE( test_get_last_n_lines_from_log )
-{
- cout << "ACore:: ...test_get_last_n_lines_from_log\n";
-
- // delete the log file if it exists.
- std::string path = getLogPath();
- fs::remove(path);
- BOOST_CHECK_MESSAGE(!fs::exists( path ), "log file not deleted " << path << " not created \n");
-
- // Create the log file;
- Log::create(path);
- BOOST_CHECK_MESSAGE(fs::exists( path ), "log file " << path << " not created \n");
-
- // Log file should be empty
- const int NO_OF_LINES_IN_LOG_FILE = 200;
- {
- for(int i =0; i < NO_OF_LINES_IN_LOG_FILE; i++) {
- std::string line = Log::instance()->contents(i);
- BOOST_CHECK_MESSAGE(line.empty(), "Expected empty string but found\n" << line);
- }
- }
-
- // Populate the log file
- std::string msg = "This is message ";
- for(int i = 0; i < NO_OF_LINES_IN_LOG_FILE; ++i) LOG(Log::MSG,msg << i);
-
- // Now check, getting the lines
- {
- std::string line = Log::instance()->contents(0);
- BOOST_CHECK_MESSAGE(line.empty(), "Expected empty string but found\n" << line);
- }
- {
- // Check we get back the number of line requested
- for(int i = 0; i< NO_OF_LINES_IN_LOG_FILE; i++) {
- std::string lines = Log::instance()->contents(i);
- int newlineCount = std::count( lines.begin(), lines.end(), '\n');
- BOOST_CHECK_MESSAGE(i == newlineCount, "expected to " << i << " newlines but found " << newlineCount);
- }
- }
- {
- // Check we get back *ALL* lines requested
- std::string lines = Log::instance()->contents(NO_OF_LINES_IN_LOG_FILE);
- for(int i = 0; i< NO_OF_LINES_IN_LOG_FILE; i++) {
- std::stringstream ss; ss << msg << i;
- std::string str_to_find = ss.str();
- BOOST_CHECK_MESSAGE(lines.find(str_to_find) != std::string::npos, "expected to find " << str_to_find << " in the log file");
- }
- }
-
- {
- // Request more than is available, should only get back whats there
- std::string lines = Log::instance()->contents(NO_OF_LINES_IN_LOG_FILE*2);
- int newlineCount = std::count( lines.begin(), lines.end(), '\n');
- BOOST_CHECK_MESSAGE(NO_OF_LINES_IN_LOG_FILE == newlineCount, "expected " << NO_OF_LINES_IN_LOG_FILE << " newlines but found " << newlineCount);
- }
-
- fs::remove(Log::instance()->path());
-
- // Explicitly destroy log. To keep valgrind happy
- Log::destroy();
-}
-
-BOOST_AUTO_TEST_CASE( test_get_first_n_lines_from_log )
-{
- cout << "ACore:: ...test_get_first_n_lines_from_log\n";
-
- // delete the log file if it exists.
- std::string path = getLogPath();
- fs::remove(path);
- BOOST_CHECK_MESSAGE(!fs::exists( path ), "log file not deleted " << path << " not created \n");
-
- // Create the log file;
- Log::create(path);
- BOOST_CHECK_MESSAGE(fs::exists( path ), "log file " << path << " not created \n");
-
- // Populate the log file
- const int NO_OF_LINES_IN_LOG_FILE = 200;
- std::string msg = "This is message ";
- for(int i = 0; i < NO_OF_LINES_IN_LOG_FILE; ++i) LOG(Log::MSG,msg << i);
-
- // Now check, getting the lines
- {
- // Get the first line
- std::string line = Log::instance()->contents(-1);
- std::string expected = msg + "0";
- BOOST_CHECK_MESSAGE(line.find(expected) != std::string::npos, "Expected '" << expected << "' but found\n" << line);
- }
- {
- // Get the first & second line
- std::string line = Log::instance()->contents(-2);
- std::string expected0 = msg + "0";
- std::string expected1 = msg + "1";
- BOOST_CHECK_MESSAGE(line.find(expected0) != std::string::npos, "Expected '" << expected0 << "' but found\n" << line);
- BOOST_CHECK_MESSAGE(line.find(expected1) != std::string::npos, "Expected '" << expected1 << "' but found\n" << line);
- }
- {
- // Check we get back the number of line requested
- for(int i = 0; i< NO_OF_LINES_IN_LOG_FILE; i++) {
- std::string lines = Log::instance()->contents(-i);
- int newlineCount = std::count( lines.begin(), lines.end(), '\n');
- BOOST_CHECK_MESSAGE(i == newlineCount, "expected to " << i << " newlines but found " << newlineCount);
- }
- }
- {
- std::string lines = Log::instance()->contents(-NO_OF_LINES_IN_LOG_FILE);
- for(int i = 0; i < NO_OF_LINES_IN_LOG_FILE; i++){
- std::stringstream ss; ss << msg << i;
- std::string expected = ss.str();
- BOOST_CHECK_MESSAGE(lines.find(expected) != std::string::npos, "Expected '" << expected << "' but found for i " << i);
- }
- }
-
- {
- // Request more than is available, should only get back whats there
- std::string lines = Log::instance()->contents(-NO_OF_LINES_IN_LOG_FILE*2);
- int newlineCount = std::count( lines.begin(), lines.end(), '\n');
- BOOST_CHECK_MESSAGE(NO_OF_LINES_IN_LOG_FILE == newlineCount, "expected " << NO_OF_LINES_IN_LOG_FILE << " newlines but found " << newlineCount);
- }
-
- fs::remove(Log::instance()->path());
-
- // Explicitly destroy log. To keep valgrind happy
- Log::destroy();
-}
-
-
-BOOST_AUTO_TEST_CASE( test_get_log_timing )
-{
- cout << "ACore:: ...test_get_log_timing: " << flush;
-
- // *************************************************************************************
- // This test was used with *DIFFERENT* implementations for Log::instance()->contents(1)
- // What is shows, is that for optimal performance we should *NOT* load the entire log file
- // This can be several giga bytes.
- // **************************************************************************************
-
- // delete the log file if it exists.
- std::string path = getLogPath();
- fs::remove(getLogPath());
- BOOST_CHECK_MESSAGE(!fs::exists( path ), "log file not deleted " << path << " not created \n");
-
- // Create the log file;
- Log::create(path);
- BOOST_CHECK_MESSAGE(fs::exists( path ), "log file " << path << " not created \n");
-
- // Populate the log file
- const int NO_OF_LINES_IN_LOG_FILE = 20000;
- std::string msg = "This is message ";
- for(int i = 0; i < NO_OF_LINES_IN_LOG_FILE; ++i) LOG(Log::MSG,msg << i);
-
- DurationTimer timer;
-
- {
- const int LOOP = 100;
- for(int i = 0; i< LOOP; i++) {
- std::string lines = Log::instance()->contents(1);
- BOOST_CHECK_MESSAGE(!lines.empty(), "expected entry");
- }
- }
-
- fs::remove(Log::instance()->path());
-
- // Explicitly destroy log. To keep valgrind happy
- Log::destroy();
-
- cout << timer.duration() << "s\n" << flush;
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ACore/test/TestMigration.cpp b/ecflow_4_0_7/ACore/test/TestMigration.cpp
deleted file mode 100644
index b801402..0000000
--- a/ecflow_4_0_7/ACore/test/TestMigration.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-#if defined(TEXT_ARCHIVE) || !defined(BINARY_ARCHIVE) && !defined(PORTABLE_BINARY_ARCHIVE) && !defined(EOS_PORTABLE_BINARY_ARCHIVE)
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <stdlib.h> // for getenv()
-
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-
-#include "TimeSeries.hpp"
-#include "SerializationTest.hpp"
-#include "Calendar.hpp"
-#include "File.hpp"
-#include "Ecf.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost::posix_time;
-using namespace boost::gregorian;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( CoreTestSuite )
-
-// If you are updating the tests, *MAKE SURE* to check out test/data/migration/* files
-//#define UPDATE_TESTS 1
-
-BOOST_AUTO_TEST_CASE( test_migration_restore_1_9 )
-{
- cout << "ACore:: ...test_migration_restore_1_9\n";
-
- std::string file_name = File::test_data("ACore/test/data/migration/","ACore");
-
- // Note: default calendar constructor will init with current time: Hence set for comparison
- Calendar calendar;
- boost::gregorian::date theDate(2011,2,10);
- ptime time(theDate, hours(23) + minutes(59));
- calendar.init(time, Calendar::REAL); // Calendar type is derived from the clock attribute & hence is not persisted
- Ecf::set_debug_equality(true);
-
-#ifdef UPDATE_TESTS
- doSave<TimeSlot>(file_name + "timeslot_default_constructor_v1.9");
- doSave<TimeSeries>(file_name + "timeseries_default_constructor_v1.9");
- doSave<Calendar>(file_name + "calendar_v1.9",calendar);
- doSave(file_name + "timeslot_1_1_v1_9",TimeSlot(1,1));
- doSave(file_name + "timeslot_99_59_v1_9",TimeSlot(99,59));
- doSave(file_name + "timeseries_10_10_v1_9",TimeSeries(TimeSlot(10,10)));
-#else
- do_restore<TimeSlot>(file_name + "timeslot_default_constructor_v1.9",TimeSlot());
- do_restore<TimeSeries>(file_name + "timeseries_default_constructor_v1.9",TimeSeries());
- do_restore<Calendar>(file_name + "calendar_v1.9",calendar);
- do_restore<TimeSlot>(file_name + "timeslot_1_1_v1_9",TimeSlot(1,1));
- do_restore<TimeSlot>(file_name + "timeslot_99_59_v1_9",TimeSlot(99,59));
- do_restore<TimeSeries>(file_name + "timeseries_10_10_v1_9",TimeSeries(TimeSlot(10,10)));
-#endif
- Ecf::set_debug_equality(false);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-#endif
diff --git a/ecflow_4_0_7/ACore/test/TestNodePath.cpp b/ecflow_4_0_7/ACore/test/TestNodePath.cpp
deleted file mode 100644
index 337fd3d..0000000
--- a/ecflow_4_0_7/ACore/test/TestNodePath.cpp
+++ /dev/null
@@ -1,148 +0,0 @@
-#define BOOST_TEST_MODULE TestCore
-//============================================================================
-// Name : Request
-// Author : Avi
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <string>
-#include <iostream>
-
-#include <boost/test/unit_test.hpp>
-#include <boost/timer.hpp>
-
-#include "NodePath.hpp"
-
-using namespace std;
-
-BOOST_AUTO_TEST_SUITE( CoreTestSuite )
-
-static void checkPath( const std::vector<std::string>& expectedPath, const std::string& path )
-{
- std::vector<std::string> thePath;
- NodePath::split(path,thePath);
- if ( thePath != expectedPath ) {
- BOOST_CHECK_MESSAGE(false,"Failed for " << path );
- std::cout << "Expected '";
- std::copy (expectedPath.begin(), expectedPath.end(), std::ostream_iterator <std::string> (std::cout, " "));
- std::cout << "'\nbut found '";
- std::copy (thePath.begin(), thePath.end(), std::ostream_iterator <std::string> (std::cout, " "));
- std::cout << "'\n";
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_path_extractor_constructor )
-{
- cout << "ACore:: ...test_path_extractor_constructor\n";
- BOOST_CHECK(true); // stop boost test from complaining about no checks
-
- std::vector<std::string> theExpectedPath;
- checkPath(theExpectedPath,"");
-
- theExpectedPath.push_back("suite");
- checkPath(theExpectedPath,"/suite");
- checkPath(theExpectedPath,"suite");
-}
-
-BOOST_AUTO_TEST_CASE( test_path_extractor )
-{
- cout << "ACore:: ...test_path_extractor\n";
- BOOST_CHECK(true); // stop boost test from complaining about no checks
-
- std::vector<std::string> theExpectedPath;
- theExpectedPath.push_back("suite");
- theExpectedPath.push_back("family");
- theExpectedPath.push_back("task");
-
- checkPath(theExpectedPath,"/suite/family/task");
- checkPath(theExpectedPath,"/suite/family/task/");
-}
-
-BOOST_AUTO_TEST_CASE( test_unix_path_extractor )
-{
- cout << "ACore:: ...test_unix_path_extractor\n";
- BOOST_CHECK(true); // stop boost test from complaining about no checks
-
- // On Unix multiple '/' are treated as one.
- std::vector<std::string> theExpectedPath;
- theExpectedPath.push_back("suite");
- theExpectedPath.push_back("family");
- theExpectedPath.push_back("task");
-
- checkPath(theExpectedPath,"/suite///family////task");
- checkPath(theExpectedPath,"/suite///family////task//");
- checkPath(theExpectedPath,"//suite///family////task//");
- checkPath(theExpectedPath,"///suite///family////task//");
- checkPath(theExpectedPath,"///suite///family////task///");
-}
-
-BOOST_AUTO_TEST_CASE( test_extractHostPort )
-{
- cout << "ACore:: ...test_extractHostPort\n";
-
- std::string path;
- std::string host;
- std::string port;
- BOOST_CHECK_MESSAGE(!NodePath::extractHostPort(path,host,port), "expected failure");
-
- path = "Apath";
- BOOST_CHECK_MESSAGE(!NodePath::extractHostPort(path,host,port), "expected failure");
-
- path = " : ";
- BOOST_CHECK_MESSAGE(!NodePath::extractHostPort(path,host,port), "expected failure");
-
- path = "host:";
- BOOST_CHECK_MESSAGE(!NodePath::extractHostPort(path,host,port), "expected failure");
-
- path = ":port";
- BOOST_CHECK_MESSAGE(!NodePath::extractHostPort(path,host,port), "expected failure");
-
- path = "host:port";
- BOOST_CHECK_MESSAGE(NodePath::extractHostPort(path,host,port), "expected success " << host << ":" << port);
- BOOST_CHECK_MESSAGE(host == "host" && port == "port", "expected 'host:port' found " << host << ":" << port);
-
- path = "//host:port";
- BOOST_CHECK_MESSAGE(NodePath::extractHostPort(path,host,port), "expected success " << host << ":" << port);
- BOOST_CHECK_MESSAGE(host == "host" && port == "port", "expected 'host:port' found " << host << ":" << port);
-
- path = "//host:port/";
- BOOST_CHECK_MESSAGE(NodePath::extractHostPort(path,host,port), "expected success " << host << ":" << port);
- BOOST_CHECK_MESSAGE(host == "host" && port == "port", "expected 'host:port' found " << host << ":" << port);
-
- path = "//host:port/suite";
- BOOST_CHECK_MESSAGE(NodePath::extractHostPort(path,host,port), "expected success " << host << ":" << port);
- BOOST_CHECK_MESSAGE(host == "host" && port == "port", "expected 'host:port' found " << host << ":" << port);
-
- path = "//host:port/suite/family/task";
- BOOST_CHECK_MESSAGE(NodePath::extractHostPort(path,host,port), "expected success " << host << ":" << port);
- BOOST_CHECK_MESSAGE(host == "host" && port == "port", "expected 'host:port' found " << host << ":" << port);
-}
-
-//BOOST_AUTO_TEST_CASE( test_NodePath_perf )
-//{
-// cout << "ACore:: ...test_NodePath_perf \n";
-//
-// // Using
-// // boost tokenizer timing: 9.73
-// // Str::split : 5.15
-// boost::timer timer; // measures CPU, replace with cpu_timer with boost > 1.51, measures cpu & elapsed
-// int n= 1000000 ;
-// for(int i = 0; i < n; i++) {
-// std::vector<std::string> thePath;
-// NodePath::split("/this/is/a/test/string/that/will/be/usedto/check/perf",thePath);
-// }
-//
-// cout << "Timing for " << n << " NodePath is " << timer.elapsed() << endl;
-//}
-
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ACore/test/TestRealCalendar.cpp b/ecflow_4_0_7/ACore/test/TestRealCalendar.cpp
deleted file mode 100644
index f5ccc75..0000000
--- a/ecflow_4_0_7/ACore/test/TestRealCalendar.cpp
+++ /dev/null
@@ -1,355 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <boost/test/unit_test.hpp>
-#include <string>
-#include <iostream>
-#include <fstream>
-
-#include "Calendar.hpp"
-#include "TimeSeries.hpp"
-#include <boost/date_time/posix_time/time_formatters.hpp>
-
-using namespace std;
-using namespace ecf;
-using namespace boost::posix_time;
-using namespace boost::gregorian;
-
-BOOST_AUTO_TEST_SUITE( CoreTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_REAL_calendar )
-{
- cout << "ACore:: ...test_REAL_calendar\n";
-
- // init the calendar to 2009, Feb, 10th,
- boost::gregorian::date theDate(2009,2,10);
- ptime time(theDate, hours(22) + minutes(10));
-
- Calendar calendar;
- calendar.init(time, Calendar::REAL);
-
- // record the time for the test
- boost::posix_time::ptime theSuiteTime = calendar.suiteTime();
- boost::posix_time::time_duration theDuration = calendar.duration();
-
- // Take time now and add 2 minutes, use this to update calendar by 2 minutes
- boost::posix_time::ptime time_now = Calendar::second_clock_time();
- time_now += minutes(2);
- theSuiteTime += minutes(2);
- theDuration += minutes(2);
-
- calendar.update(time_now);
-
- BOOST_CHECK_MESSAGE( calendar.suiteTime() == theSuiteTime," Expected " << to_simple_string(theSuiteTime) << " but found " << to_simple_string(calendar.suiteTime()) );
- BOOST_CHECK_MESSAGE( calendar.duration() == theDuration," Expected " << to_simple_string(theDuration) << " but found " << to_simple_string(calendar.duration()) );
-
- time_now += hours(24);
- theSuiteTime += hours(24);
- theDuration += hours(24);
-
- calendar.update(time_now);
-
- BOOST_CHECK_MESSAGE( calendar.suiteTime() == theSuiteTime," Expected " << to_simple_string(theSuiteTime) << " but found " << to_simple_string(calendar.suiteTime()) );
- BOOST_CHECK_MESSAGE( calendar.duration() == theDuration," Expected " << to_simple_string(theDuration) << " but found " << to_simple_string(calendar.duration()) );
-}
-
-
-BOOST_AUTO_TEST_CASE( test_REAL_calendar_time_series_relative_complex )
-{
- cout << "ACore:: ...test_REAL_calendar_time_series_relative_complex\n";
-
- // init the calendar to 2009, Feb, 10th, 0 minutes past midnight
- Calendar calendar;
- calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::HYBRID);
-
- // Create a test when we can match a time series
- // Create the time series: start 10:00
- // finish 20:00
- // incr 00:15
- TimeSeries timeSeries(TimeSlot(10,0), TimeSlot(20,0), TimeSlot(0,15),true/*relative*/);
-
- boost::posix_time::ptime time_now = Calendar::second_clock_time();
-
- for(int hour=0; hour < 24; hour++) {
- for( int minute=0; minute<60; minute++) {
-
- // Update calendar every hour, then see we can match time series, *RELATIVE* to suite start
- time_now += minutes(1);
-
- calendar.update(time_now);
-
- timeSeries.calendarChanged( calendar );
-
- tm suiteTm = to_tm(calendar.suiteTime());
-
- bool matches = timeSeries.isFree(calendar);
-
- bool intersects = ( suiteTm.tm_hour >= timeSeries.start().hour() &&
- suiteTm.tm_hour <= timeSeries.finish().hour() &&
- (suiteTm.tm_min == 0 || suiteTm.tm_min % timeSeries.incr().minute() == 0)
- );
- // Ovoid overshooting past end of series
- bool boundaryOk = true;
- if ( suiteTm.tm_hour == timeSeries.finish().hour() ) {
- boundaryOk = (suiteTm.tm_min <= timeSeries.finish().minute());
- }
-
- if ( intersects && boundaryOk )
- {
- BOOST_CHECK_MESSAGE(matches,
- "Calendar should match relative time series at "
- << suiteTm.tm_hour <<":"<< suiteTm.tm_min
- << " suite time = " << to_simple_string(calendar.suiteTime()));
- if (!matches) {
- cerr << "suiteTm.tm_hour =" << suiteTm.tm_hour << " suiteTm.tm_min = " << suiteTm.tm_min
- << " timeSeries.start().hour() " << timeSeries.start().hour()
- << " timeSeries.start().minute() " << timeSeries.start().minute()
- << " timeSeries.finish().hour() " << timeSeries.finish().hour()
- << " timeSeries.finish().minute() " << timeSeries.finish().minute()
- << " suiteTm.tm_min % 15 = " << suiteTm.tm_min % 15
- << "\n";
- }
- }
- else {
- BOOST_CHECK_MESSAGE(!matches,
- "Calendar should NOT match relative time series at "
- << suiteTm.tm_hour <<":"<< suiteTm.tm_min
- << " suite time = " << to_simple_string(calendar.suiteTime()));
-
- if (matches) {
- cerr << "suiteTm.tm_hour =" << suiteTm.tm_hour << " suiteTm.tm_min = " << suiteTm.tm_min
- << " timeSeries.start().hour() " << timeSeries.start().hour()
- << " timeSeries.start().minute() " << timeSeries.start().minute()
- << " timeSeries.finish().hour() " << timeSeries.finish().hour()
- << " timeSeries.finish().minute() " << timeSeries.finish().minute()
- << " suiteTm.tm_min % 15 = " << suiteTm.tm_min % 15
- << "\n";
- }
- }
- }
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_REAL_calendar_time_series)
-{
- cout << "ACore:: ...test_REAL_calendar_time_series\n";
-
- // init the calendar to 2009, Feb, 10th, 0 minutes past midnight
- Calendar calendar;
- calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::REAL);
-
- // Create a test when we can match a time series
- // Create the time series: start 10:00
- // finish 20:00
- // incr 1:00
- TimeSeries timeSeries(TimeSlot(10,0), TimeSlot(20,0), TimeSlot(1,0));
-
- boost::posix_time::ptime time_now = Calendar::second_clock_time();
-
- for(int hour=1; hour < 24; hour++) {
- // Update calendar every hour, then see we can match time series, in REAL
- // Update will set the local time from the computers system clock, however
- // for testing this will need to be overriden below.
-
- time_now += hours(1);
-
- calendar.update(time_now);
-
- // cerr << "hour = " << hour << " suiteTime " << to_simple_string(calendar.suiteTime()) << "\n";
- if (hour >= timeSeries.start().hour() && hour <=timeSeries.finish().hour()) {
- BOOST_CHECK_MESSAGE(timeSeries.isFree(calendar),"Calendar should match time series at hour " << hour );
- }
- else {
- BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar),"Calendar should NOT match time series at hour " << hour );
- }
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_REAL_calendar_time_series_complex )
-{
- cout << "ACore:: ...test_REAL_calendar_time_series_complex\n";
-
- // init the calendar to 2009, Feb, 10th, 0 minutes past midnight
- Calendar calendar;
- calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::REAL);
-
- // Create a test when we can match a time series
- // Create the time series: start 10:00
- // finish 20:00
- // incr 00:15
- TimeSeries timeSeries(TimeSlot(10,0), TimeSlot(20,0), TimeSlot(0,15));
-
- boost::posix_time::ptime time_now = Calendar::second_clock_time();
-
- for(int hour=0; hour < 24; hour++) {
- for( int minute=0; minute<60; minute++) {
-
- // Update calendar every minute, then see we can match time series, *RELATIVE* to suite start
- time_now += minutes(1);
- calendar.update(time_now);
-
- tm suiteTm = to_tm(calendar.suiteTime());
-
- bool matches = timeSeries.isFree(calendar);
-
- bool intersects = ( suiteTm.tm_hour >= timeSeries.start().hour() &&
- suiteTm.tm_hour <= timeSeries.finish().hour() &&
- (suiteTm.tm_min == 0 || suiteTm.tm_min % timeSeries.incr().minute() == 0)
- );
- // Ovoid overshooting past end of series
- bool boundaryOk = true;
- if ( suiteTm.tm_hour == timeSeries.finish().hour() ) {
- boundaryOk = (suiteTm.tm_min <= timeSeries.finish().minute());
- }
-
- if ( intersects && boundaryOk )
- {
- BOOST_CHECK_MESSAGE(matches,
- "Calendar should match relative time series at "
- << suiteTm.tm_hour <<":"<< suiteTm.tm_min
- << " suite time = " << to_simple_string(calendar.suiteTime()));
- if (!matches) {
- cerr << "suiteTm.tm_hour =" << suiteTm.tm_hour << " suiteTm.tm_min = " << suiteTm.tm_min
- << " timeSeries.start().hour() " << timeSeries.start().hour()
- << " timeSeries.start().minute() " << timeSeries.start().minute()
- << " timeSeries.finish().hour() " << timeSeries.finish().hour()
- << " timeSeries.finish().minute() " << timeSeries.finish().minute()
- << " suiteTm.tm_min % 15 = " << suiteTm.tm_min % 15
- << "\n";
- }
- }
- else {
- BOOST_CHECK_MESSAGE(!matches,
- "Calendar should NOT match relative time series at "
- << suiteTm.tm_hour <<":"<< suiteTm.tm_min
- << " suite time = " << to_simple_string(calendar.suiteTime()));
-
- if (matches) {
- cerr << "suiteTm.tm_hour =" << suiteTm.tm_hour << " suiteTm.tm_min = " << suiteTm.tm_min
- << " timeSeries.start().hour() " << timeSeries.start().hour()
- << " timeSeries.start().minute() " << timeSeries.start().minute()
- << " timeSeries.finish().hour() " << timeSeries.finish().hour()
- << " timeSeries.finish().minute() " << timeSeries.finish().minute()
- << " suiteTm.tm_min % 15 = " << suiteTm.tm_min % 15
- << "\n";
- }
- }
- }
- }
-}
-
-
-BOOST_AUTO_TEST_CASE( test_REAL_calendar_hybrid_date )
-{
- cout << "ACore:: ...test_REAL_calendar_hybrid_date\n";
-
- // The hybrid calendar should not change the suite date.
- // Test by updateing calendar by more than 24 hours
-
- // init the calendar to 2009, Feb, 10th, 0 minutes past midnight
- Calendar calendar;
- calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::HYBRID);
-
-
- std::string expectedDate = "2010-Feb-10";
- boost::posix_time::ptime time_now = Calendar::second_clock_time();
-
- for(int hour=1; hour < 60; hour++) {
- // Update calendar every hour, for 60 hours
- // the date should be the same, i.e 2009, Feb, 10th
-
- ptime timeBeforeUpdate = calendar.suiteTime();
-
- time_now += hours(1);
-
- calendar.update(time_now);
-
- ptime timeAfterUpdate = calendar.suiteTime();
-
-// cerr << "hour = " << hour << " timeBeforeUpdate " << to_simple_string(timeBeforeUpdate)
-// << " timeAfterUpdate = " << to_simple_string(timeAfterUpdate) << "\n";
-
- if (hour != 24 && hour != 48) {
- time_period diff(timeBeforeUpdate,timeAfterUpdate);
- time_duration gap = diff.length();
- BOOST_CHECK_MESSAGE( gap.hours() == 1,"Expected one hour difference but found " << gap.hours() << " at hour " << hour);
- }
-
- std::string actualDate = to_simple_string(calendar.suiteTime().date());
- BOOST_CHECK_MESSAGE( actualDate == expectedDate,"Expected '" << expectedDate << "' but found " << actualDate << " at hour " << hour);
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_REAL_day_changed )
-{
- cout << "ACore:: ...test_REAL_day_changed \n";
-
- // init the calendar to 2009, Feb, 10th, 0 minutes past midnight
- Calendar calendar;
- calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::REAL);
- BOOST_CHECK_MESSAGE(!calendar.hybrid(),"calendar type should be real");
-
- boost::posix_time::ptime time_now = Calendar::second_clock_time();
-
- for(int hour=1; hour < 73; hour++) {
- // Update calendar every hour, for 72 hours
-
- time_now += hours(1);
-
- calendar.update(time_now);
-
- if (hour == 24 || hour == 48 || hour == 72) {
- BOOST_CHECK_MESSAGE( calendar.dayChanged(),"Expected day change at hour " << hour << " calendar " << calendar.toString());
- }
- else {
- BOOST_CHECK_MESSAGE( !calendar.dayChanged(),"Un-Expected day change at hour " << hour << " calendar " << calendar.toString());
- }
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_REAL_day_changed_for_hybrid )
-{
- cout << "ACore:: ...test_REAL_day_changed_for_hybrid\n";
-
- // init the calendar to 2009, Feb, 10th, 0 minutes past midnight
- Calendar calendar;
- calendar.init(ptime(date(2010,2,10), minutes(0)),Calendar::HYBRID);
- BOOST_CHECK_MESSAGE(calendar.hybrid(),"calendar type should be real");
-
- // HYBRID calendars allow for day change but not date.
- std::string expected_date = to_simple_string(calendar.date());
-
- boost::posix_time::ptime time_now = Calendar::second_clock_time();
-
- for(int hour=1; hour < 73; hour++) {
- // Update calendar every hour, for 72 hours
-
- time_now += hours(1);
- calendar.update(time_now);
-
- BOOST_CHECK_MESSAGE( expected_date == to_simple_string(calendar.date()) ,
- "Unexpected date change for hybrid calendar at hour " << hour);
-
- // Day should change even for hybrid calendar,
- if (hour == 24 || hour == 48 || hour == 72) {
- BOOST_CHECK_MESSAGE( calendar.dayChanged(),"Expected day change at hour " << hour << " calendar " << calendar.toString());
- }
- else {
- BOOST_CHECK_MESSAGE( !calendar.dayChanged(),"Un-Expected day change at hour " << hour << " calendar " << calendar.toString());
- }
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ACore/test/TestSerialisation.cpp b/ecflow_4_0_7/ACore/test/TestSerialisation.cpp
deleted file mode 100644
index e0abf95..0000000
--- a/ecflow_4_0_7/ACore/test/TestSerialisation.cpp
+++ /dev/null
@@ -1,135 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #12 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <boost/test/unit_test.hpp>
-#include "TimeSeries.hpp"
-#include "SerializationTest.hpp"
-#include "Calendar.hpp"
-#include "boost_archive.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost::posix_time;
-using namespace boost::gregorian;
-
-static std::string fileName = "test.txt";
-
-BOOST_AUTO_TEST_SUITE( CoreTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_archive_version )
-{
- cout << "ACore:: ...test_archive_version: ";
- // Boost 1.47 archive version = 9
- // Bosst 1.53 archive version = 10
- BOOST_CHECK_MESSAGE(boost_archive::version() >= 9,"Expected boost archive version >= 9");
- std::cout << boost_archive::version() << "\n";
-}
-
-BOOST_AUTO_TEST_CASE( test_extract_archive_version )
-{
- cout << "ACore:: ...test_extract_archive_version\n";
-
- // get the archive version:
- std::string boost_serial_str = "22 serialization::archive 9 0 0 0 0 1 1 0";
- BOOST_CHECK_MESSAGE(boost_archive::extract_version(boost_serial_str) == 9,"Expected version to be 9 but found " << boost_archive::extract_version(boost_serial_str));
-
- boost_serial_str = "22 serialization::archive 10 0 0 0 0 1 1 0";
- BOOST_CHECK_MESSAGE(boost_archive::extract_version(boost_serial_str) == 10,"Expected version to be 10 but found " << boost_archive::extract_version(boost_serial_str));
-
- boost_serial_str = "22 serialization::archive 999 0 0 0 0 1 1 0";
- BOOST_CHECK_MESSAGE(boost_archive::extract_version(boost_serial_str) == 999,"Expected version to be 999 but found " << boost_archive::extract_version(boost_serial_str));
-
- // error
- boost_serial_str = "22 serialization::archive";
- BOOST_CHECK_MESSAGE(boost_archive::extract_version(boost_serial_str) == 0,"Expected version to be 0 but found " << boost_archive::extract_version(boost_serial_str));
-}
-
-
-BOOST_AUTO_TEST_CASE( test_replace_archive_version )
-{
- cout << "ACore:: ...test_replace_archive_version\n";
-
- std::string boost_serial_str = "22 serialization::archive 9 0 0 0 0 1 1 0";
- std::string expected = "22 serialization::archive 10 0 0 0 0 1 1 0";
- BOOST_CHECK(boost_archive::replace_version(boost_serial_str,10));
- BOOST_CHECK_MESSAGE(boost_serial_str == expected,"Expected '" << expected << "' but found '" << boost_serial_str << "'");
-
- boost_serial_str = "22 serialization::archive 10 0 0 0 0 1 1 0";
- expected = "22 serialization::archive 9 0 0 0 0 1 1 0";
- BOOST_CHECK(boost_archive::replace_version(boost_serial_str,9));
- BOOST_CHECK_MESSAGE(boost_serial_str == expected,"Expected '" << expected << "' but found '" << boost_serial_str << "'");
-
- boost_serial_str = "22 serialization::archive 10 10 10";
- expected = "22 serialization::archive 11 10 10";
- BOOST_CHECK(boost_archive::replace_version(boost_serial_str,11));
- BOOST_CHECK_MESSAGE(boost_serial_str == expected,"Expected '" << expected << "' but found '" << boost_serial_str << "'");
-
- boost_serial_str = "22 serialization::archive 10 10 10";
- expected = "22 serialization::archive 44444 10 10";
- BOOST_CHECK(boost_archive::replace_version(boost_serial_str,44444));
- BOOST_CHECK_MESSAGE(boost_serial_str == expected,"Expected '" << expected << "' but found '" << boost_serial_str << "'");
-
- // error
- boost_serial_str = "22 serialization::archive ";
- expected = "22 serialization::archive ";
- BOOST_CHECK(!boost_archive::replace_version(boost_serial_str,11));
- BOOST_CHECK_MESSAGE(boost_serial_str == expected,"Expected '" << expected << "' but found '" << boost_serial_str << "'");
-}
-
-BOOST_AUTO_TEST_CASE( test_calendar_serialisation )
-{
- cout << "ACore:: ...test_calendar_serialisation \n";
-
- Calendar cal;
- doSaveAndRestore(fileName,cal);
-}
-
-BOOST_AUTO_TEST_CASE( test_TimeSlot_serialisation )
-{
- cout << "ACore:: ...test_TimeSlot_serialisation \n";
-
- {
- doSaveAndRestore<TimeSlot>(fileName);
- }
-
- {
- TimeSlot saved(1,1);
- doSaveAndRestore(fileName,saved);
- }
-
- {
- TimeSlot saved(99,59);
- doSaveAndRestore(fileName,saved);
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_TimeSeries_serialisation )
-{
- cout << "ACore:: ...test_TimeSeries_serialisation \n";
-
- {
- doSaveAndRestore<TimeSeries>(fileName);
- }
- {
- TimeSeries saved = TimeSeries(TimeSlot(10,10));
- doSaveAndRestore(fileName,saved);
- }
- {
- TimeSeries saved = TimeSeries(TimeSlot(0,0),TimeSlot(10,10),TimeSlot(0,10));
- doSaveAndRestore(fileName,saved);
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ACore/test/TestStackTrace.cpp b/ecflow_4_0_7/ACore/test/TestStackTrace.cpp
deleted file mode 100644
index 336ac36..0000000
--- a/ecflow_4_0_7/ACore/test/TestStackTrace.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-////============================================================================
-//// Name :
-//// Author : Avi
-//// Revision : $Revision: #8 $
-////
-//// Copyright 2009-2012 ECMWF.
-//// This software is licensed under the terms of the Apache Licence version 2.0
-//// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-//// In applying this licence, ECMWF does not waive the privileges and immunities
-//// granted to it by virtue of its status as an intergovernmental organisation
-//// nor does it submit to any jurisdiction.
-////
-//// Description :
-////============================================================================
-//#include <boost/test/unit_test.hpp>
-//#include "boost/filesystem/operations.hpp"
-//#include "boost/filesystem/path.hpp"
-//#include <iostream>
-//#include <fstream>
-////#include "StackTrace.hpp"
-//
-//
-//using namespace boost;
-//using namespace std;
-//using namespace ecf;
-//namespace fs = boost::filesystem;
-//
-//BOOST_AUTO_TEST_SUITE( CoreTestSuite )
-//
-//class MyClass {
-//public:
-// std::string MemFunc( const std::string &someParam )
-// {
-// int depth = 5;
-// return StackTrace::dump( __FILE__, __LINE__, depth );
-// }
-//};
-//
-//std::string func2( const char *something )
-//{
-// MyClass a;
-// return a.MemFunc( something );
-//}
-//
-//std::string func1( int param1, const std::string ¶m2 )
-//{
-// return func2( param2.c_str() );
-//}
-//
-////BOOST_AUTO_TEST_CASE( test_stack_trace )
-////{
-////#if defined(__GNUC__)
-//// cout << "ACore:: ...test_stack_trace\n";
-//// std::string traceback = func1( 1, "TestString" );
-////
-//// std::string expected;
-//// fs::path current_path = fs::current_path();
-//// if (current_path.stem() == "ACore" ) {
-////// cout << "current_path.stem() == ACore )\n";
-//// expected = "Call Stack from test/TestStackTrace.cpp:28\n"
-//// " CoreTestSuite::MyClass::MemFunc(std::string const&)\n"
-//// " CoreTestSuite::func2(char const*)\n"
-//// " CoreTestSuite::func1(int, std::string const&)\n"
-//// " CoreTestSuite::test_stack_trace::test_method()\n";
-//// }
-//// else {
-////// cout << "current_path.stem() != ACore )\n";
-//// expected = "Call Stack from ACore/test/TestStackTrace.cpp:28\n"
-//// " CoreTestSuite::MyClass::MemFunc(std::string const&)\n"
-//// " CoreTestSuite::func2(char const*)\n"
-//// " CoreTestSuite::func1(int, std::string const&)\n"
-//// " CoreTestSuite::test_stack_trace::test_method()\n";
-//// }
-//// BOOST_CHECK_MESSAGE (traceback == expected,"Mismatch expected\n'" << expected << "'\n but found\n'" << traceback << "'");
-////#endif
-////}
-//
-//BOOST_AUTO_TEST_SUITE_END()
-//
-//
diff --git a/ecflow_4_0_7/ACore/test/TestStr.cpp b/ecflow_4_0_7/ACore/test/TestStr.cpp
deleted file mode 100644
index d39df8b..0000000
--- a/ecflow_4_0_7/ACore/test/TestStr.cpp
+++ /dev/null
@@ -1,694 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #24 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <string>
-#include <iostream>
-#include <fstream>
-
-#include <boost/test/unit_test.hpp>
-#include <boost/timer.hpp>
-#include <boost/foreach.hpp>
-#include <boost/lexical_cast.hpp>
-#include <boost/bind.hpp>
-#include <boost/algorithm/string/split.hpp>
-
-#include "Str.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost;
-
-//#define STRING_SPLIT_IMPLEMENTATIONS_PERF_CHECK_ 1;
-
-
-BOOST_AUTO_TEST_SUITE( CoreTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_str )
-{
- cout << "ACore:: ...test_str\n";
-
- {
- std::string str;
- std::string expected;
- Str::removeQuotes(str);
- BOOST_CHECK_MESSAGE(str == expected," Expected " << expected << " but found " << str);
-
- str = "\"\""; expected = "";
- Str::removeQuotes(str);
- BOOST_CHECK_MESSAGE(str == expected," Expected " << expected << " but found " << str);
-
- str = "fred"; expected = "fred";
- Str::removeQuotes(str);
- BOOST_CHECK_MESSAGE(str == expected," Expected " << expected << " but found " << str);
-
- str = "\"fred\""; expected = "fred";
- Str::removeQuotes(str);
- BOOST_CHECK_MESSAGE(str == expected," Expected " << expected << " but found " << str);
- }
- {
- std::string str;
- std::string expected;
- Str::removeSingleQuotes(str);
- BOOST_CHECK_MESSAGE(str == expected," Expected " << expected << " but found " << str);
-
- str = "''"; expected = "";
- Str::removeSingleQuotes(str);
- BOOST_CHECK_MESSAGE(str == expected," Expected " << expected << " but found " << str);
-
- str = "fred"; expected = "fred";
- Str::removeSingleQuotes(str);
- BOOST_CHECK_MESSAGE(str == expected," Expected " << expected << " but found " << str);
-
- str = "'fred'"; expected = "fred";
- Str::removeSingleQuotes(str);
- BOOST_CHECK_MESSAGE(str == expected," Expected " << expected << " but found " << str);
- }
- {
- string test;
- BOOST_CHECK_MESSAGE(!Str::truncate_at_start(test,7),"Empty sring should return false");
-
- test= "this\nis\na\nstring\nwith\nlots\nof\nnew\nline";
- string expected = "line";
- BOOST_CHECK_MESSAGE(Str::truncate_at_start(test,1) && test==expected,"Expected:\n" << expected << "\nbut found:\n" << test);
-
- test= "this\nis\na\nstring\nwith\nlots\nof\nnew\nline";
- expected = "a\nstring\nwith\nlots\nof\nnew\nline";
- BOOST_CHECK_MESSAGE(Str::truncate_at_start(test,7) && test==expected,"Expected:\n" << expected << "\nbut found:\n" << test);
-
- test= "this\nis\na\nstring\nwith\nlots\nof\nnew\nline";
- expected = test;
- BOOST_CHECK_MESSAGE(!Str::truncate_at_start(test,9) && test==expected,"Expected:\n" << expected << "\nbut found:\n" << test);
- }
- {
- string test;
- BOOST_CHECK_MESSAGE(!Str::truncate_at_end(test,7),"Empty string should return false");
-
- test= "this\nis\na\nstring\nwith\nlots\nof\nnew\nline";
- string expected = "this\n";
- BOOST_CHECK_MESSAGE(Str::truncate_at_end(test,1) && test==expected,"Expected:\n" << expected << "\nbut found:\n" << test);
-
- test= "this\nis\na\nstring\nwith\nlots\nof\nnew\nline";
- expected = "this\nis\n";
- BOOST_CHECK_MESSAGE(Str::truncate_at_end(test,2) && test==expected,"Expected:\n" << expected << "\nbut found:\n" << test);
-
- test= "this\nis\na\nstring\nwith\nlots\nof\nnew\nline";
- expected= "this\nis\na\nstring\nwith\nlots\nof\n";
- BOOST_CHECK_MESSAGE(Str::truncate_at_end(test,7) && test==expected,"Expected:\n" << expected << "\nbut found:\n" << test);
-
- test= "this\nis\na\nstring\nwith\nlots\nof\nnew\nline";
- expected = test;
- BOOST_CHECK_MESSAGE(!Str::truncate_at_end(test,9) && test==expected,"Expected:\n" << expected << "\nbut found:\n" << test);
- }
-}
-
-static void check(const std::string& line,
- const std::vector<std::string>& result,
- const std::vector<std::string>& expected )
-{
- BOOST_CHECK_MESSAGE(result.size() == expected.size(),"expected size " << expected.size() << " but found " << result.size() << " for '" << line << "'");
- BOOST_CHECK_MESSAGE(result == expected,"Str::split failed for '" << line << "'");
- if (result != expected) {
- cout << "Actual :"; BOOST_FOREACH(const string& t, result) { cout << "'" << t << "'"; } cout << "\n";
- cout << "Expected:"; BOOST_FOREACH(const string& t, expected) { cout << "'" << t << "'"; } cout << "\n";
- }
-}
-
-//BOOST_AUTO_TEST_CASE( test_boost_str_split )
-//{
-// cout << "ACore:: ...test_boost_str_split\n";
-//
-// std::string line = "This is a string ";
-// std::vector<std::string> expected;
-// expected.push_back("This"); expected.push_back("is"); expected.push_back("a"); expected.push_back("string");
-// expected.push_back(""); expected.push_back("");
-//
-// std::vector<std::string> result;
-// boost::algorithm::split(result, line, std::bind2nd(std::equal_to<char>(), ' ')); // default is compress off, preserve empty tokens
-// check(line,result,expected);
-//
-// expected.pop_back();
-// result.clear();
-// boost::algorithm::split(result, line, std::bind2nd(std::equal_to<char>(), ' '),boost::algorithm::token_compress_on);
-// check(line,result,expected);
-//
-// // boost::split(v, s, boost::lambda::_1 == ' ');
-//}
-
-
-BOOST_AUTO_TEST_CASE( test_str_split )
-{
- cout << "ACore:: ...test_str_split\n";
-
- std::string line = "This is a string";
- std::vector<std::string> expected;
- expected.push_back("This"); expected.push_back("is"); expected.push_back("a"); expected.push_back("string");
- std::vector<std::string> result;
- Str::split(line,result);
- check(line,result,expected);
-
-
- line.clear(); expected.clear(); result.clear();
- line = " ";
- Str::split(line,result);
- check(line,result,expected);
-
- line.clear(); expected.clear(); result.clear();
- line = "a";
- expected.push_back("a");
- Str::split(line,result);
- check(line,result,expected);
-
- // Some implementation fail this test
- line.clear(); expected.clear(); result.clear();
- line = "\n";
- expected.push_back("\n");
- Str::split(line,result);
- check(line,result,expected);
-
- line.clear(); expected.clear(); result.clear();
- line = "a ";
- expected.push_back("a");
- Str::split(line,result);
- check(line,result,expected);
-
- line.clear(); expected.clear(); result.clear();
- line = " a";
- expected.push_back("a");
- Str::split(line,result);
- check(line,result,expected);
-
- line.clear(); expected.clear(); result.clear();
- line = " a"; // check tabs
- expected.push_back("a");
- Str::split(line,result);
- check(line,result,expected);
-
- line.clear(); expected.clear(); result.clear();
- line = " a "; // check sequential tabs
- expected.push_back("a");
- Str::split(line,result);
- check(line,result,expected);
-
- line.clear(); expected.clear(); result.clear();
- line = " a ";
- expected.push_back("a");
- Str::split(line,result);
- check(line,result,expected);
-
- line.clear(); expected.clear(); result.clear();
- line = " a b c d ";
- expected.push_back("a"); expected.push_back("b"); expected.push_back("c"); expected.push_back("d");
- Str::split(line,result);
- check(line,result,expected);
-
- line.clear(); expected.clear(); result.clear();
- line = " - ! $ % ^ & * ( ) - + ?";
- expected.push_back("-"); expected.push_back("!"); expected.push_back("$");
- expected.push_back("%"); expected.push_back("^"); expected.push_back("&"); expected.push_back("*");
- expected.push_back("("); expected.push_back(")"); expected.push_back("-"); expected.push_back("+");
- expected.push_back("?");
- Str::split(line,result);
- check(line,result,expected);
-
- // Check tabs
- line.clear(); expected.clear(); result.clear();
- line = " verify complete:8 # 4 sundays in october hence expect 8 task completions";
- expected.push_back("verify");expected.push_back("complete:8");expected.push_back("#");expected.push_back("4");
- expected.push_back("sundays");expected.push_back("in");expected.push_back("october");expected.push_back("hence");
- expected.push_back("expect");expected.push_back("8");expected.push_back("task");expected.push_back("completions");
- Str::split(line,result);
- check(line,result,expected);
-
-#ifdef STRING_SPLIT_IMPLEMENTATIONS_PERF_CHECK_
- {
- line = "This is a long string that is going to be used to test the performance of splitting with different Implementations extra empty tokens ";
- size_t times = 1000000;
- boost::timer timer; // measures CPU, replace with cpu_timer with boost > 1.51, measures cpu & elapsed
- for (size_t i = 0; i < times; i++) {
- result.clear();
-// boost::algorithm::split(result, line, std::bind2nd(std::equal_to<char>(), ' '),boost::algorithm::token_compress_on); // 3.2 times slower, but preserves empty tokens
- Str::split(line,result);
- }
- cout << "Time for Str::split " << times << " times = " << timer.elapsed() << "\n";
- }
-#endif
-}
-
-
-static void test_replace( std::string& testStr, const std::string& find, const std::string& replace, const std::string& expected)
-{
- BOOST_CHECK_MESSAGE(Str::replace(testStr,find,replace), "Replace failed for " << testStr << " find(" << find << ") replace(" << replace << ")");
- BOOST_CHECK_MESSAGE(testStr == expected,"Expected '" << expected << "' but found '" << testStr <<"'");
-}
-
-static void test_replace_all( std::string& testStr, const std::string& find, const std::string& replace, const std::string& expected)
-{
- std::string testStrCopy = testStr;
-
- BOOST_CHECK_MESSAGE(Str::replace_all(testStr,find,replace), "Replace failed for " << testStr << " find(" << find << ") replace(" << replace << ")");
- BOOST_CHECK_MESSAGE(testStr == expected,"Expected '" << expected << "' but found '" << testStr <<"'");
-
- Str::replaceall(testStrCopy,find,replace);
- BOOST_CHECK_MESSAGE(testStr == testStrCopy,"Expected '" << testStrCopy << "' but found '" << testStr <<"'");
-}
-
-
-BOOST_AUTO_TEST_CASE( test_str_replace )
-{
- cout << "ACore:: ...test_str_replace\n";
-
- std::string testStr = "This is a string";
- test_replace(testStr,"This","That","That is a string");
-
- testStr = "This is a string";
- test_replace(testStr,"This is a string","","");
-
- testStr = "This is a string";
- test_replace(testStr,"is a","was a","This was a string");
-
- testStr = "This\n is a string";
- test_replace(testStr,"\n","\\n","This\\n is a string");
-
- testStr = "This\n is\n a\n string\n";
- test_replace_all(testStr,"\n","\\n","This\\n is\\n a\\n string\\n");
-
- // Test case insenstive string comparison
- BOOST_CHECK_MESSAGE(Str::caseInsCompare("","")," bug1");
- BOOST_CHECK_MESSAGE(!Str::caseInsCompare("Str","Str1")," bug1");
- BOOST_CHECK_MESSAGE(!Str::caseInsCompare("","Str1")," bug1");
- BOOST_CHECK_MESSAGE(Str::caseInsCompare("Str","STR")," bug1");
- BOOST_CHECK_MESSAGE(Str::caseInsCompare("Case","CaSE")," bug1");
-}
-
-BOOST_AUTO_TEST_CASE( test_str_replace_all )
-{
- cout << "ACore:: ...test_str_replace_all\n";
-
- std::string testStr = "This is a string";
- test_replace_all(testStr,"This","That","That is a string");
-
- testStr = "This is a string";
- test_replace_all(testStr,"This is a string","","");
-
- testStr = "This is a string";
- test_replace_all(testStr,"is a","was a","This was a string");
-
- testStr = "This\n is a string";
- test_replace_all(testStr,"\n","\\n","This\\n is a string");
-
- testStr = "This\n is\n a\n string\n";
- test_replace_all(testStr,"\n","\\n","This\\n is\\n a\\n string\\n");
-
- testStr = "This\n is\n a\n string\n";
- test_replace_all(testStr,"\n","","This is a string");
-}
-
-BOOST_AUTO_TEST_CASE( test_str_to_int )
-{
- cout << "ACore:: ...test_str(to_int)\n";
- BOOST_CHECK_MESSAGE(Str::to_int("0") == 0,"Expected 0");
- BOOST_CHECK_MESSAGE(Str::to_int("1") == 1,"Expected 1");
- BOOST_CHECK_MESSAGE(Str::to_int("-0") == 0,"Expected 0");
- BOOST_CHECK_MESSAGE(Str::to_int("-1") == -1,"Expected -1");
- BOOST_CHECK_MESSAGE(Str::to_int("") == std::numeric_limits<int>::max(),"Expected max int");
- BOOST_CHECK_MESSAGE(Str::to_int("-") == std::numeric_limits<int>::max(),"Expected max int");
- BOOST_CHECK_MESSAGE(Str::to_int(" ") == std::numeric_limits<int>::max(),"Expected max int");
- BOOST_CHECK_MESSAGE(Str::to_int("q") == std::numeric_limits<int>::max(),"Expected max int");
- BOOST_CHECK_MESSAGE(Str::to_int("q22") == std::numeric_limits<int>::max(),"Expected max int");
- BOOST_CHECK_MESSAGE(Str::to_int("q22",-1) == -1,"Expected -1 on failure");
- BOOST_CHECK_MESSAGE(Str::to_int("99 99") == std::numeric_limits<int>::max(),"Expected max int");
- BOOST_CHECK_MESSAGE(Str::to_int("99 99",0) == 0,"Expected 0 for failure");
-}
-
-BOOST_AUTO_TEST_CASE( test_extract_data_member_value )
-{
- cout << "ACore:: ...test_extract_data_member_value\n";
- std::string expected = "value";
- std::string actual;
- std::string str = "aa bb c fred:value";
- BOOST_CHECK_MESSAGE(Str::extract_data_member_value(str,"fred:",actual)," failed");
- BOOST_CHECK_MESSAGE(expected == actual,"expected '" << expected << "' but found '" << actual << "'");
-
-
- str = "fred:x bill:zzz jake:12345 1234:99 6677";
- expected = "x";
- BOOST_CHECK_MESSAGE(Str::extract_data_member_value(str,"fred:",actual)," failed");
- BOOST_CHECK_MESSAGE(expected == actual,"expected '" << expected << "' but found '" << actual << "'");
-
- expected = "zzz";
- BOOST_CHECK_MESSAGE(Str::extract_data_member_value(str,"bill:",actual)," failed");
- BOOST_CHECK_MESSAGE(expected == actual,"expected '" << expected << "' but found '" << actual << "'");
-
- expected = "12345";
- BOOST_CHECK_MESSAGE(Str::extract_data_member_value(str,"jake:",actual)," failed");
- BOOST_CHECK_MESSAGE(expected == actual,"expected '" << expected << "' but found '" << actual << "'");
-
- expected = "99";
- BOOST_CHECK_MESSAGE(Str::extract_data_member_value(str,"1234:",actual)," failed");
- BOOST_CHECK_MESSAGE(expected == actual,"expected '" << expected << "' but found '" << actual << "'");
-
- expected = "77";
- BOOST_CHECK_MESSAGE(Str::extract_data_member_value(str,"66",actual)," failed");
- BOOST_CHECK_MESSAGE(expected == actual,"expected '" << expected << "' but found '" << actual << "'");
-}
-
-
-std::string toString(const std::vector<std::string>& c)
-{
- std::stringstream ss;
- std::copy (c.begin(), c.end(), std::ostream_iterator <std::string> (ss, ", "));
- return ss.str();
-}
-
-BOOST_AUTO_TEST_CASE( test_str_less_greater)
-{
- cout << "ACore:: ...test_str_less_greater\n";
-
- std::vector<std::string> expected;
- expected.push_back("a1");
- expected.push_back("A2");
- expected.push_back("b1");
- expected.push_back("B2");
- expected.push_back("c");
-
- std::vector<std::string> expectedGreater;
- expectedGreater.push_back("c");
- expectedGreater.push_back("B2");
- expectedGreater.push_back("b1");
- expectedGreater.push_back("A2");
- expectedGreater.push_back("a1");
-
- std::vector<std::string> vec;
- vec.push_back("c");
- vec.push_back("A2");
- vec.push_back("a1");
- vec.push_back("b1");
- vec.push_back("B2");
-
- std::sort(vec.begin(),vec.end(),Str::caseInsLess);
- BOOST_REQUIRE_MESSAGE( vec == expected,"expected " << toString(expected) << " but found " << toString(vec) );
-
- std::sort(vec.begin(),vec.end(),Str::caseInsGreater);
- BOOST_REQUIRE_MESSAGE( vec == expectedGreater,"expected " << toString(expectedGreater) << " but found " << toString(vec) );
-
- // --------------------------------------------------------------------
-
- expected.clear();
- expected.push_back("a");
- expected.push_back("A");
- expected.push_back("b");
- expected.push_back("B");
- expected.push_back("c");
-
- expectedGreater.clear();
- expectedGreater.push_back("c");
- expectedGreater.push_back("B");
- expectedGreater.push_back("b");
- expectedGreater.push_back("A");
- expectedGreater.push_back("a");
-
- vec.clear();
- vec.push_back("c");
- vec.push_back("B");
- vec.push_back("A");
- vec.push_back("b");
- vec.push_back("a");
-
- std::sort(vec.begin(),vec.end(),Str::caseInsLess);
- BOOST_REQUIRE_MESSAGE( vec == expected,"expected " << toString(expected) << " but found " << toString(vec) );
-
- std::sort(vec.begin(),vec.end(),Str::caseInsGreater);
- BOOST_REQUIRE_MESSAGE( vec == expectedGreater,"expected " << toString(expectedGreater) << " but found " << toString(vec) );
-
- // --------------------------------------------------------------------
-
- expected.clear();
- expected.push_back("1234");
- expected.push_back("baSE");
- expected.push_back("Base");
- expected.push_back("case");
- expected.push_back("CaSe");
- expected.push_back("suite");
- expected.push_back("SUITE");
-
- expectedGreater.clear();
- expectedGreater.push_back("SUITE");
- expectedGreater.push_back("suite");
- expectedGreater.push_back("CaSe");
- expectedGreater.push_back("case");
- expectedGreater.push_back("Base");
- expectedGreater.push_back("baSE");
- expectedGreater.push_back("1234");
-
- vec.clear();
- vec.push_back("suite");
- vec.push_back("SUITE");
- vec.push_back("baSE");
- vec.push_back("Base");
- vec.push_back("case");
- vec.push_back("CaSe");
- vec.push_back("1234");
-
- std::sort(vec.begin(),vec.end(),Str::caseInsLess);
- BOOST_REQUIRE_MESSAGE( vec == expected,"expected " << toString(expected) << " but found " << toString(vec) );
-
- std::sort(vec.begin(),vec.end(),Str::caseInsGreater);
- BOOST_REQUIRE_MESSAGE( vec == expectedGreater,"expected " << toString(expectedGreater) << " but found " << toString(vec) );
-}
-
-
-//// ==============================================================
-//// Timing to find the fastest looping
-//// ==============================================================
-//class Fred {
-//public:
-// Fred(int i = 0) : i_(i) { /*std::cout << "Fred constructor\n"*/;}
-// Fred(const Fred& rhs) : i_(rhs.i_) { /*std::cout << "Fred copy constructor\n";*/ }
-// Fred& operator=(const Fred& rhs) { /*std::cout << "assignment operator\n";*/ i_ = rhs.i_; return *this;}
-// ~Fred() { /*std::cout << "Fred destructor\n";*/}
-//
-// void inc() { i_++;}
-//private:
-// int i_;
-//};
-//
-//BOOST_AUTO_TEST_CASE( test_loop )
-//{
-// // DEBUG release shows BOOST_FOREACH has worst perf, however in release mode its par with the fastest.
-// size_t vecSize = 20000000;
-// std::vector<Fred> vec;
-// vec.reserve(vecSize);
-// for (size_t i = 0; i < vecSize ; i++) { vec.push_back(Fred(i));}
-//
-// boost::timer timer; // measures CPU, replace with cpu_timer with boost > 1.51, measures cpu & elapsed
-// BOOST_FOREACH(Fred& fred, vec) { fred.inc(); }
-// cout << "Time: BOOST_FOREACH(Fred& fred, vec) { fred.inc(); } " << timer.elapsed() << "\n";
-//
-// timer.restart();
-// std::for_each(vec.begin(),vec.end(),boost::bind(&Fred::inc,_1) );
-// cout << "Time: std::for_each(vec.begin(),vec.end(),boost::bind(&Fred::inc,_1) ); " << timer.elapsed() << "\n";
-//
-// timer.restart();
-// std::vector<Fred>::iterator theEnd = vec.end();
-// for (std::vector<Fred>::iterator i = vec.begin(); i < theEnd ; i++) { (*i).inc(); }
-// cout << "Time: for (std::vector<Fred>::iterator i = vec.begin(); i < theEnd ; i++) { (*i).inc(); } " << timer.elapsed() << "\n";
-//
-// timer.restart();
-// std::for_each(vec.begin(),vec.end(),std::mem_fun_ref(&Fred::inc) );
-// cout << "Time: std::for_each(vec.begin();vec.end(),std::mem_fun_ref(&Fred::inc)) " << timer.elapsed() << "\n";
-//
-// timer.restart();
-// size_t theSize = vec.size();
-// for (size_t i = 0; i < theSize ; i++) { vec[i].inc(); }
-// cout << "Time: for (size_t i = 0; i < theSize ; i++) { vec[i].inc(); } " << timer.elapsed() << "\n";
-//}
-
-
-/// ==============================================================
-/// Timing to find the fastest conversion from string to int
-/// ==============================================================
-//static void methodX( const std::string& str,
-// std::vector<std::string>& stringRes,
-// std::vector<int>& numberRes)
-//{
-// // 0.81
-// // for bad conversion istringstream seems to return 0, hence add guard
-// if ( str.find_first_of( Str::NUMERIC(), 0 ) != std::string::npos ) {
-// int number = 0;
-// std::istringstream ( str ) >> number;
-// numberRes.push_back( number );
-// }
-// else {
-// stringRes.push_back( str );
-// }
-//}
-//
-//
-//static void method1( const std::string& str,
-// std::vector<std::string>& stringRes,
-// std::vector<int>& numberRes)
-//{
-// // 12.2
-// try {
-// int number = boost::lexical_cast< int >( str );
-// numberRes.push_back( number );
-// }
-// catch ( boost::bad_lexical_cast& ) {
-// stringRes.push_back( str );
-// }
-//}
-//
-//static void method2( const std::string& str,
-// std::vector<std::string>& stringRes,
-// std::vector<int>& numberRes)
-//{
-// // 0.6
-// if ( str.find_first_of( Str::NUMERIC(), 0 ) != std::string::npos ) {
-// try {
-// int number = boost::lexical_cast< int >( str );
-// numberRes.push_back( number );
-// }
-// catch ( boost::bad_lexical_cast& ) {
-// stringRes.push_back( str );
-// }
-// }
-// else {
-// stringRes.push_back( str );
-// }
-//}
-//
-//static void method3( const std::string& str,
-// std::vector<std::string>& stringRes,
-// std::vector<int>& numberRes)
-//{
-// // 0.14
-// // atoi return 0 for errors,
-// int number = atoi(str.c_str()); //does not handle errors
-// if (number == 0 && str.size() != 1) {
-// stringRes.push_back( str );
-// }
-// else {
-// numberRes.push_back( number );
-// }
-//}
-//
-//
-//BOOST_AUTO_TEST_CASE( test_lexical_cast_perf )
-//{
-// cout << "ACore:: ...test_string_to_int_conversion\n";
-//
-// size_t the_size = 1000000;
-// std::vector<std::string> stringTokens;
-// std::vector<std::string> numberTokens;
-// std::vector<int> expectedNumberRes;
-// for(size_t i=0; i < the_size; i++) { stringTokens.push_back("astring");}
-// for(size_t i=0; i < the_size; i++) {
-// numberTokens.push_back(boost::lexical_cast<string>(i));
-// expectedNumberRes.push_back(i);
-// }
-//
-// std::vector<std::string> stringRes; stringTokens.reserve(stringTokens.size());
-// std::vector<int> numberRes; numberRes.reserve(expectedNumberRes.size());
-//
-// {
-// boost::timer timer; // measures CPU, replace with cpu_timer with boost > 1.51, measures cpu & elapsed
-// for(size_t i =0; i < stringTokens.size(); i++) {
-// method1(stringTokens[i], stringRes, numberRes );
-// }
-// for(size_t i =0; i < numberTokens.size(); i++) {
-// method1(numberTokens[i], stringRes, numberRes );
-// }
-// cout << "Time for method1 elapsed time = " << timer.elapsed() << "\n";
-// BOOST_CHECK_MESSAGE(numberRes == expectedNumberRes," method 1 wrong");
-// BOOST_CHECK_MESSAGE(stringTokens == stringRes,"method 1 wrong");
-// numberRes.clear();
-// stringRes.clear();
-// }
-//
-// {
-// boost::timer timer; // measures CPU, replace with cpu_timer with boost > 1.51, measures cpu & elapsed
-// for(size_t i =0; i < stringTokens.size(); i++) {
-// methodX(stringTokens[i], stringRes, numberRes );
-// }
-// for(size_t i =0; i < numberTokens.size(); i++) {
-// methodX(numberTokens[i], stringRes, numberRes );
-// }
-// cout << "Time for methodX elapsed time = " << timer.elapsed() << "\n";
-// BOOST_CHECK_MESSAGE(numberRes == expectedNumberRes," method X wrong");
-// BOOST_CHECK_MESSAGE(stringTokens == stringRes,"method X wrong");
-// numberRes.clear();
-// stringRes.clear();
-// }
-//
-// {
-// boost::timer timer; // measures CPU, replace with cpu_timer with boost > 1.51, measures cpu & elapsed
-// for(size_t i =0; i < stringTokens.size(); i++) {
-// method2(stringTokens[i], stringRes, numberRes );
-// }
-// for(size_t i =0; i < numberTokens.size(); i++) {
-// method2(numberTokens[i], stringRes, numberRes );
-// }
-// cout << "Time for method2 elapsed time = " << timer.elapsed() << "\n";
-// BOOST_CHECK_MESSAGE(numberRes == expectedNumberRes,"method 2 wrong");
-// BOOST_CHECK_MESSAGE(stringTokens == stringRes,"method 2 wrong");
-// numberRes.clear();
-// stringRes.clear();
-// }
-//
-// {
-// boost::timer timer; // measures CPU, replace with cpu_timer with boost > 1.51, measures cpu & elapsed
-// for(size_t i =0; i < stringTokens.size(); i++) {
-// method3(stringTokens[i], stringRes, numberRes );
-// }
-// for(size_t i =0; i < numberTokens.size(); i++) {
-// method3(numberTokens[i], stringRes, numberRes );
-// }
-// cout << "Time for method3 elapsed time = " << timer.elapsed() << "\n";
-// BOOST_CHECK_MESSAGE(numberRes == expectedNumberRes," method3 wrong numberRes.size()=" << numberRes.size() << " expected size = " << expectedNumberRes.size());
-// BOOST_CHECK_MESSAGE(stringTokens == stringRes," method3 wrong stringRes.size()=" << stringRes.size() << " expected size = " << stringTokens.size());
-// numberRes.clear();
-// stringRes.clear();
-// }
-//}
-
-//BOOST_AUTO_TEST_CASE( test_int_to_str_perf )
-//{
-// cout << "ACore:: ...test_int_to_str_perf\n";
-//
-// // Lexical_cast is approx twice as fast as using streams
-// // time for ostream = 0.97
-// // time for lexical_cast = 0.45
-//
-// const int the_size = 1000000;
-// {
-// boost::timer timer; // measures CPU, replace with cpu_timer with boost > 1.51, measures cpu & elapsed
-// for(size_t i =0; i < the_size; i++) {
-// std::ostringstream st;
-// st << i;
-// std::string s = st.str();
-// }
-// cout << "Time for int to string using ostringstream elapsed time = " << timer.elapsed() << "\n";
-// }
-//
-//
-// {
-// boost::timer timer; // measures CPU, replace with cpu_timer with boost > 1.51, measures cpu & elapsed
-// for(size_t i =0; i < the_size; i++) {
-// std::string s = boost::lexical_cast<std::string>(i);
-// }
-// cout << "Time for int to string using boost::lexical_cast elapsed time = " << timer.elapsed() << "\n";
-// }
-//}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ACore/test/TestTimeSeries.cpp b/ecflow_4_0_7/ACore/test/TestTimeSeries.cpp
deleted file mode 100644
index 9e3a61b..0000000
--- a/ecflow_4_0_7/ACore/test/TestTimeSeries.cpp
+++ /dev/null
@@ -1,676 +0,0 @@
-//============================================================================
-// Name : Request
-// Author : Avi
-// Revision : $Revision: #32 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/date_time/posix_time/time_formatters.hpp>
-
-#include <string>
-#include <iostream>
-#include <fstream>
-#include "TimeSeries.hpp"
-#include "Calendar.hpp"
-#include "Str.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost::posix_time;
-using namespace boost::gregorian;
-
-using namespace boost;
-
-BOOST_AUTO_TEST_SUITE( CoreTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_time_series_min_max_time_slots )
-{
- cout << "ACore:: ...test_time_series_min_max_time_slots\n";
-
- TimeSlot the_min;
- TimeSlot the_max;
-
- TimeSeries a(9,0,true);
- a.min_max_time_slots(the_min,the_max);
- BOOST_CHECK_MESSAGE( the_min == TimeSlot(9,0),"Max min time slot failed");
- BOOST_CHECK_MESSAGE( the_max == TimeSlot(9,0),"Max min time slot failed");
-
- TimeSeries b(TimeSlot(10,12),false);
- b.min_max_time_slots(the_min,the_max);
- BOOST_CHECK_MESSAGE( the_min == TimeSlot(9,0),"Max min time slot failed");
- BOOST_CHECK_MESSAGE( the_max == TimeSlot(10,12),"Max min time slot failed");
-
- TimeSeries c(TimeSlot(0,10), TimeSlot(10,13), TimeSlot(0,1));
- c.min_max_time_slots(the_min,the_max);
- BOOST_CHECK_MESSAGE( the_min == TimeSlot(0,10),"Max min time slot failed");
- BOOST_CHECK_MESSAGE( the_max == TimeSlot(10,13),"Max min time slot failed");
-
- TimeSeries x;
- x.min_max_time_slots(the_min,the_max);
- BOOST_CHECK_MESSAGE( the_min == TimeSlot(),"Max min time slot failed");
- BOOST_CHECK_MESSAGE( the_max == TimeSlot(10,13),"Max min time slot failed");
-
-}
-
-
-BOOST_AUTO_TEST_CASE( test_time_series_constrcution )
-{
- cout << "ACore:: ...test_time_series_constrcution\n";
-
- {
- TimeSeries x;
- TimeSeries y;
- BOOST_CHECK_MESSAGE( x == y,"Equality operator expected to succeed");
-
- TimeSeries a(10,12,true);
- TimeSeries b(10,12,true);
- BOOST_CHECK_MESSAGE( a == b,"Equality operator expected to succeed");
-
- TimeSeries c(10,12,false);
- TimeSeries d(10,12,false);
- BOOST_CHECK_MESSAGE( c == d,"Equality operator expected to succeed");
-
- TimeSeries e(TimeSlot(14,59),false);
- TimeSeries f(TimeSlot(14,59),false);
- BOOST_CHECK_MESSAGE( e == f,"Equality operator expected to succeed");
-
- TimeSeries g(TimeSlot(0,10), TimeSlot(10,4), TimeSlot(0,1));
- TimeSeries h(TimeSlot(0,10), TimeSlot(10,4), TimeSlot(0,1));
- BOOST_CHECK_MESSAGE( g == h,"Equality operator expected to succeed");
- }
- {
- TimeSeries a(10,12,false);
- TimeSeries b(10,12,true);
- BOOST_CHECK_MESSAGE( a != b,"Equality operator expected to fail");
-
- TimeSeries c(10,13,false);
- TimeSeries d(10,12,false);
- BOOST_CHECK_MESSAGE( c != d,"Equality operator expected to fail");
-
- TimeSeries e(TimeSlot(14,59),false);
- TimeSeries f(TimeSlot(14,10),false);
- BOOST_CHECK_MESSAGE( e != f,"Equality operator expected to fail");
-
- TimeSeries g(TimeSlot(0,10), TimeSlot(10,4), TimeSlot(0,1), true);
- TimeSeries h(TimeSlot(0,10), TimeSlot(10,4), TimeSlot(0,1), false);
- BOOST_CHECK_MESSAGE( g != h,"Equality operator expected to fail");
- }
-
- /// Basic test for time series of getters and setters
- TimeSeries timeSeries(TimeSlot(0,1), TimeSlot(0,4), TimeSlot(0,1));
- BOOST_CHECK_MESSAGE(timeSeries.hasIncrement(),"expected increment");
- std::string errMsg; BOOST_CHECK_MESSAGE(timeSeries.checkInvariants(errMsg),errMsg);
-
- TimeSeries another = timeSeries;
- BOOST_CHECK_MESSAGE(another == timeSeries,"copy constructor failed for TimeSeries ");
- BOOST_CHECK_MESSAGE(another.checkInvariants(errMsg),errMsg);
- BOOST_CHECK_MESSAGE(timeSeries.checkInvariants(errMsg),errMsg);
-
- TimeSeries timeSeries2(TimeSlot(0,1), TimeSlot(0,4), TimeSlot(0,1));
- BOOST_CHECK_MESSAGE(timeSeries2.checkInvariants(errMsg),errMsg);
- another = timeSeries2;
- BOOST_CHECK_MESSAGE(another == timeSeries2,"assignment operator failed for TimeSeries ");
- BOOST_CHECK_MESSAGE(another.checkInvariants(errMsg),errMsg);
-
- TimeSeries timeSeries3(TimeSlot(0,1));
- BOOST_CHECK_MESSAGE(timeSeries3.checkInvariants(errMsg),errMsg);
-}
-
-BOOST_AUTO_TEST_CASE( test_time_series )
-{
- cout << "ACore:: ...test_time_series\n";
-
- /// Basic test for time series of getters and setters
- TimeSeries timeSeries(TimeSlot(0,1), TimeSlot(0,4), TimeSlot(0,1));
- BOOST_CHECK_MESSAGE(timeSeries.hasIncrement(),"expected increment");
-
- std::string expected = "00:01:00";
- std::string actual = to_simple_string(timeSeries.start().duration());
- BOOST_CHECK_MESSAGE(expected == actual," expected " << expected << " but found " << actual );
-
- expected = "00:04:00";
- actual = to_simple_string(timeSeries.finish().duration());
- BOOST_CHECK_MESSAGE(expected == actual," expected " << expected << " but found " << actual );
-
- expected = "00:01:00";
- actual = to_simple_string(timeSeries.incr().duration());
- BOOST_CHECK_MESSAGE(expected == actual," expected " << expected << " but found " << actual );
-
-
- TimeSeries timeSeries2(TimeSlot(0,1));
- BOOST_CHECK_MESSAGE(!timeSeries2.hasIncrement(),"Not expecting time series");
-}
-
-BOOST_AUTO_TEST_CASE( test_time_series_increment_real )
-{
- cout << "ACore:: ...test_time_series_increment_real\n";
-
- // Test time series with a calendar, we update calendar then
- // test time series isFree(), and checkForRequeue
- Calendar c;
- c.init(ptime(date(2010,2,10), minutes(0)), Calendar::REAL);
-
-
- // Create a test when we can match a time series. Need to sync hour with suite time
- // at hour 1, suite time should also be 01:00, for test to work
- //
- // Create the time series: start 10:00
- // finish 20:00
- // incr 1:00
- TimeSeries timeSeries(TimeSlot(10,0), TimeSlot(20,0), TimeSlot(1,0), true/* relative */);
- TimeSeries timeSeries2(TimeSlot(11,0), TimeSlot(15,0), TimeSlot(1,0), true/* relative */);
- TimeSeries timeSeries3(TimeSlot(15,0), true/* relative */);
-
- TimeSlot t1_min, t1_max,t2_min,t2_max,t3_min,t3_max;
- timeSeries.min_max_time_slots(t1_min, t1_max);
- timeSeries2.min_max_time_slots(t2_min, t2_max);
- timeSeries3.min_max_time_slots(t3_min, t3_max);
- BOOST_CHECK_MESSAGE(t1_min == TimeSlot(10,0) && t1_max == TimeSlot(20,0),"Not as expected");
- BOOST_CHECK_MESSAGE(t2_min == TimeSlot(11,0) && t2_max == TimeSlot(15,0),"Not as expected");
- BOOST_CHECK_MESSAGE(t3_min == TimeSlot(15,0) && t3_max == TimeSlot(15,0),"Not as expected");
-
- // Follow normal process
- timeSeries.reset( c );
- timeSeries2.reset( c );
- timeSeries3.reset( c );
-
- for(int hour=1; hour < 24; hour++) {
- // Update calendar every hour, then see we can match time series, *RELATIVE* to suite start
- c.update( time_duration( hours(1) ) );
- timeSeries.calendarChanged( c );
- timeSeries2.calendarChanged( c );
- timeSeries3.calendarChanged( c );
-
-// cerr << "hour = " << hour << " calendar_duration " << to_simple_string(timeSeries.duration(c))
-// << " timeSeries=" << timeSeries.toString() << " timeSeries2=" << timeSeries2.toString() << " timeSeries3=" << timeSeries3.toString() << "\n";
- if (hour < timeSeries.start().hour()) {
- BOOST_CHECK_MESSAGE(timeSeries.checkForRequeue(c,t1_min,t1_max)," Time series " << timeSeries.toString() << "checkForRequeue should pass at " << hour );
- BOOST_CHECK_MESSAGE(!timeSeries.isFree(c),"Time series " << timeSeries.toString() << " should NOT be free at hour " << hour );
- }
- else if (hour >= timeSeries.start().hour() && hour <= timeSeries.finish().hour()) {
- BOOST_CHECK_MESSAGE(timeSeries.isFree(c),"Time series " << timeSeries.toString() << " should be free at hour " << hour );
-
- /// At the last hour checkForRequeue should return false; This ensures that value will
- /// not get incremented and so, should leave node in the complete state.
- if ( hour < timeSeries.finish().hour()) {
- BOOST_CHECK_MESSAGE(timeSeries.checkForRequeue(c,t1_min,t1_max),"Time series " << timeSeries.toString() << " checkForRequeue should be free at hour " << hour );
- }
- else {
- BOOST_CHECK_MESSAGE(!timeSeries.checkForRequeue(c,t1_min,t1_max),"Time series " << timeSeries.toString() << "checkForRequeue should Not free at hour " << hour );
- }
- }
- else {
- BOOST_CHECK_MESSAGE(!timeSeries.isFree(c),"Time series " << timeSeries.toString() << " should NOT be free at hour " << hour );
- BOOST_CHECK_MESSAGE(!timeSeries.checkForRequeue(c,t1_min,t1_max)," Time series " << timeSeries.toString() << " should fail at " << hour );
- }
-
-
- if (hour < timeSeries2.start().hour()) {
- BOOST_CHECK_MESSAGE(timeSeries2.checkForRequeue(c,t1_min,t1_max)," Time series " << timeSeries2.toString() << "checkForRequeue should pass at " << hour );
- BOOST_CHECK_MESSAGE(!timeSeries2.isFree(c),"Time series " << timeSeries2.toString() << " should NOT be free at hour " << hour );
- }
- else if (hour >= timeSeries2.start().hour() && hour <=timeSeries2.finish().hour()) {
- BOOST_CHECK_MESSAGE(timeSeries2.isFree(c),"Time series " << timeSeries2.toString() << " should be free at hour " << hour );
-
- /// At the last hour checkForRequeue should return false;
- if ( hour < timeSeries2.finish().hour()) {
- BOOST_CHECK_MESSAGE(timeSeries2.checkForRequeue(c,t2_min,t2_max),"Time series " << timeSeries2.toString() << " checkForRequeue should be free at hour " << hour );
- }
- else {
- BOOST_CHECK_MESSAGE(!timeSeries2.checkForRequeue(c,t2_min,t2_max),"Time series " << timeSeries2.toString() << "checkForRequeue should Not free at hour " << hour );
- }
- }
- else {
- BOOST_CHECK_MESSAGE(!timeSeries2.isFree(c),"Time series " << timeSeries2.toString() << " not be free at hour " << hour );
- BOOST_CHECK_MESSAGE(!timeSeries2.checkForRequeue(c,t2_min,t2_max)," Time series " << timeSeries2.toString() << " should fail at " << hour );
- }
-
-
- if (hour == timeSeries3.start().hour() ) {
- BOOST_CHECK_MESSAGE(timeSeries3.isFree(c),"Time series " << timeSeries3.toString() << " should be free at hour " << hour );
- }
- else if (hour < timeSeries3.start().hour()) {
- BOOST_CHECK_MESSAGE(!timeSeries3.isFree(c),"Time series " << timeSeries3.toString() << " isFree should fail at hour " << hour );
- }
- else if (hour > timeSeries3.start().hour()) {
- BOOST_CHECK_MESSAGE(!timeSeries3.isFree(c),"Time series " << timeSeries3.toString() << " is Free should fail at hour " << hour );
- }
- BOOST_CHECK_MESSAGE(!timeSeries3.checkForRequeue(c,t3_min,t3_max)," Time series " << timeSeries3.toString() << " checkForRequeue should fail at " << hour );
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_time_series_requeueable_and_compute_next_time_slot )
-{
- cout << "ACore:: ...test_time_series_requeueable_and_compute_next_time_slot\n";
-
- // Test time series with a calendar, we update calendar then
- // test time series requeueable(), and compute_next_time_slot
- // This are used with the WHY command
- Calendar c;
- c.init(ptime(date(2010,2,10), minutes(0)), Calendar::REAL);
-
-
- // Create a test when we can match a time series. Need to sync hour with suite time
- // at hour 1, suite time should also be 01:00, for test to work
- //
- // Create the time series: start 10:00
- // finish 20:00
- // incr 1:00
- TimeSeries timeSeries(TimeSlot(10,0), TimeSlot(20,0), TimeSlot(1,0), true/* relative */);
- TimeSeries timeSeries2(TimeSlot(11,0), TimeSlot(15,0), TimeSlot(1,0), true/* relative */);
- TimeSeries timeSeries3(TimeSlot(15,0), true/* relative */);
-
- for(int hour=1; hour < 24; hour++) {
- // Update calendar every hour, then see we can match time series,
- c.update( time_duration( hours(1) ) );
- timeSeries.calendarChanged( c );
- timeSeries2.calendarChanged( c );
- timeSeries3.calendarChanged( c );
-
-// cerr << "hour = " << hour << " calendar_duration " << to_simple_string(timeSeries.duration(c))
-// << " timeSeries=" << timeSeries.toString() << " timeSeries2=" << timeSeries2.toString() << " timeSeries3=" << timeSeries3.toString() << "\n";
- if (hour < timeSeries.start().hour()) {
- TimeSlot next_time_slot = timeSeries.compute_next_time_slot(c);
- TimeSlot expected(10,0);
- BOOST_CHECK_MESSAGE(next_time_slot ==expected," Time series " << timeSeries.toString() << " at " << hour << " expected next time slot at " << expected.toString() << " but found " << next_time_slot.toString());
- BOOST_CHECK_MESSAGE(timeSeries.requeueable(c),"Time series " << timeSeries.toString() << " should be requeueable at hour " << hour );
- }
- else if (hour == timeSeries.start().hour() ) {
- TimeSlot next_time_slot = timeSeries.compute_next_time_slot(c);
- TimeSlot expected(11,0);
- BOOST_CHECK_MESSAGE(next_time_slot == expected," Time series " << timeSeries.toString() << " at " << hour << " expected next time slot at " << expected.toString() << " but found " << next_time_slot.toString());
- BOOST_CHECK_MESSAGE(timeSeries.requeueable(c),"Time series " << timeSeries.toString() << " should be requeueable at hour " << hour );
- }
- else if (hour > timeSeries.start().hour() && hour < timeSeries.finish().hour()) {
- TimeSlot next_time_slot = timeSeries.compute_next_time_slot(c);
- TimeSlot expected(hour+1,0);
- BOOST_CHECK_MESSAGE(next_time_slot == expected," Time series " << timeSeries.toString() << " at " << hour << " expected next time slot at " << expected.toString() << " but found " << next_time_slot.toString());
- BOOST_CHECK_MESSAGE(timeSeries.requeueable(c),"Time series " << timeSeries.toString() << " should be requeueable at hour " << hour );
- }
- else if (hour == timeSeries.finish().hour()) {
- TimeSlot next_time_slot = timeSeries.compute_next_time_slot(c);
- BOOST_CHECK_MESSAGE(next_time_slot.isNULL()," Time series " << timeSeries.toString() << " at " << hour << " expected next time slot to be NULL");
- BOOST_CHECK_MESSAGE(!timeSeries.requeueable(c),"Time series " << timeSeries.toString() << " should NOT be requeueable at hour " << hour );
- }
- else if (hour > timeSeries.finish().hour()) {
- TimeSlot next_time_slot = timeSeries.compute_next_time_slot(c);
- BOOST_CHECK_MESSAGE(next_time_slot.isNULL()," Time series " << timeSeries.toString() << " at " << hour << " expected next time slot to be NULL");
- BOOST_CHECK_MESSAGE(!timeSeries.requeueable(c),"Time series " << timeSeries.toString() << " should NOT be requeueable at hour " << hour );
- }
-
-
- if (hour < timeSeries2.start().hour()) {
- TimeSlot next_time_slot = timeSeries2.compute_next_time_slot(c);
- TimeSlot expected(11,0);
- BOOST_CHECK_MESSAGE(next_time_slot ==expected," Time series " << timeSeries2.toString() << " at " << hour << " expected next time slot at " << expected.toString() << " but found " << next_time_slot.toString());
- BOOST_CHECK_MESSAGE(timeSeries2.requeueable(c),"Time series " << timeSeries2.toString() << " should be requeueable at hour " << hour );
- }
- else if (hour == timeSeries2.start().hour() ) {
- TimeSlot next_time_slot = timeSeries2.compute_next_time_slot(c);
- TimeSlot expected(12,0);
- BOOST_CHECK_MESSAGE(next_time_slot == expected," Time series " << timeSeries2.toString() << " at " << hour << " expected next time slot at " << expected.toString() << " but found " << next_time_slot.toString());
- BOOST_CHECK_MESSAGE(timeSeries2.requeueable(c),"Time series " << timeSeries2.toString() << " should NOT be requeueable at hour " << hour );
- }
- else if (hour > timeSeries2.start().hour() && hour < timeSeries2.finish().hour()) {
- TimeSlot next_time_slot = timeSeries2.compute_next_time_slot(c);
- TimeSlot expected(hour+1,0);
- BOOST_CHECK_MESSAGE(next_time_slot == expected," Time series " << timeSeries2.toString() << " at " << hour << " expected next time slot at " << expected.toString() << " but found " << next_time_slot.toString());
- BOOST_CHECK_MESSAGE(timeSeries2.requeueable(c),"Time series " << timeSeries2.toString() << " should be requeueable at hour " << hour );
- }
- else if (hour == timeSeries2.finish().hour()) {
- TimeSlot next_time_slot = timeSeries2.compute_next_time_slot(c);
- BOOST_CHECK_MESSAGE(next_time_slot.isNULL()," Time series " << timeSeries2.toString() << " at " << hour << " expected next time slot to be NULL");
- BOOST_CHECK_MESSAGE(!timeSeries2.requeueable(c),"Time series " << timeSeries2.toString() << " should NOT be requeueable at hour " << hour );
- }
- else if (hour > timeSeries2.finish().hour()) {
- TimeSlot next_time_slot = timeSeries2.compute_next_time_slot(c);
- BOOST_CHECK_MESSAGE(next_time_slot.isNULL()," Time series " << timeSeries2.toString() << " at " << hour << " expected next time slot to be NULL");
- BOOST_CHECK_MESSAGE(!timeSeries2.requeueable(c),"Time series " << timeSeries2.toString() << " should NOT be requeueable at hour " << hour );
- }
-
-
- if (hour < timeSeries3.start().hour()) {
- TimeSlot next_time_slot = timeSeries3.compute_next_time_slot(c);
- TimeSlot expected(15,0);
- BOOST_CHECK_MESSAGE(next_time_slot ==expected," Time series " << timeSeries3.toString() << " at " << hour << " expected next time slot at " << expected.toString() << " but found " << next_time_slot.toString());
- BOOST_CHECK_MESSAGE(timeSeries3.requeueable(c),"Time series " << timeSeries3.toString() << " should be requeueable at hour " << hour );
- }
- else if (hour == timeSeries3.start().hour() ) {
- TimeSlot next_time_slot = timeSeries3.compute_next_time_slot(c);
- BOOST_CHECK_MESSAGE(next_time_slot.isNULL()," Time series " << timeSeries3.toString() << " at " << hour << " expected next time slot to be NULL");
- BOOST_CHECK_MESSAGE(!timeSeries3.requeueable(c),"Time series " << timeSeries3.toString() << " should NOT be requeueable at hour " << hour );
- }
- else if (hour > timeSeries3.start().hour()) {
- TimeSlot next_time_slot = timeSeries3.compute_next_time_slot(c);
- BOOST_CHECK_MESSAGE(next_time_slot.isNULL()," Time series " << timeSeries3.toString() << " at " << hour << " expected next time slot to be NULL");
- BOOST_CHECK_MESSAGE(!timeSeries3.requeueable(c),"Time series " << timeSeries3.toString() << " should NOT be requeueable at hour " << hour );
- }
- }
-}
-
-
-BOOST_AUTO_TEST_CASE( test_time_series_finish_not_divisble_by_increment )
-{
- cout << "ACore:: ...test_time_series_finish_not_divisble_by_increment\n";
-
- // HANDLE CASE WHERE FINISH MINUTES IS NOT DIVISIBLE BY THE INCREMENT
-
- // Test time series with a calendar, we update calendar then
- // test time series isFree(), and checkForRequeue
- Calendar calendar;
- calendar.init(ptime(date(2008,10,8), hours(0) ), Calendar::REAL);
-
- // Create a test when we can match a time series.
- // NOTE: Finish minute is not a multiple of INCREMENT hence last valid time slot is 23:50
- //
- // Create the time series: start 00:00
- // finish 23:59
- // incr 00:10
- TimeSeries timeSeries(TimeSlot(0,0), TimeSlot(23,59), TimeSlot(0,10), false/* relative */);
- TimeSeries timeSeries2(TimeSlot(0,30), TimeSlot(23,59), TimeSlot(4,0), false/* relative */);
-
- TimeSlot t1_min, t1_max,t2_min,t2_max;
- timeSeries.min_max_time_slots(t1_min, t1_max);
- timeSeries2.min_max_time_slots(t2_min, t2_max);
- BOOST_CHECK_MESSAGE(t1_min == TimeSlot(0,0) && t1_max == TimeSlot(23,59),"Not as expected");
- BOOST_CHECK_MESSAGE(t2_min == TimeSlot(0,30) && t2_max == TimeSlot(23,59),"Not as expected");
-
- time_duration last = hours(23) + minutes(50); // last valid time is 23:50
- time_duration last2 = hours(20) + minutes(30); // last valid time is 20:30
-
- // follow normal process
- timeSeries.reset(calendar);
- timeSeries2.reset(calendar);
-
- for(int hour=0; hour < 24; hour++) {
- for( int minute=0; minute<60; minute++) {
-
- calendar.update( minutes(1) );
- timeSeries.calendarChanged(calendar);
- timeSeries2.calendarChanged(calendar);
-
- //cout << to_simple_string(calendar.suiteTime()) << "\n";
-
- if (calendar.dayChanged()) {
- BOOST_CHECK_MESSAGE(timeSeries.checkForRequeue(calendar,t1_min,t1_max)," expected " << timeSeries.toString() << " checkForRequeue to pass at " << to_simple_string(calendar.suiteTime()));
- }
- else if ( calendar.suiteTime().time_of_day() < timeSeries.start().duration()) {
- BOOST_CHECK_MESSAGE(timeSeries.checkForRequeue(calendar,t1_min,t1_max)," expected " << timeSeries.toString() << " checkForRequeue to pass at " << to_simple_string(calendar.suiteTime()) );
- }
- else if ( calendar.suiteTime().time_of_day() >= timeSeries.start().duration() && calendar.suiteTime().time_of_day() < last ) {
- BOOST_CHECK_MESSAGE(timeSeries.checkForRequeue(calendar,t1_min,t1_max)," expected " << timeSeries.toString() << " checkForRequeue to pass at " << to_simple_string(calendar.suiteTime()) );
- }
- else {
- BOOST_CHECK_MESSAGE(!timeSeries.checkForRequeue(calendar,t1_min,t1_max)," expected " << timeSeries.toString() << " checkForRequeue to fail at " << to_simple_string(calendar.suiteTime()) );
- }
-
- if (calendar.dayChanged()) {
- BOOST_CHECK_MESSAGE(timeSeries2.checkForRequeue(calendar,t2_min,t2_max)," expected " << timeSeries2.toString() << " checkForRequeue to pass at " << to_simple_string(calendar.suiteTime()));
- }
- else if ( calendar.suiteTime().time_of_day() < timeSeries2.start().duration()) {
- BOOST_CHECK_MESSAGE(timeSeries2.checkForRequeue(calendar,t2_min,t2_max)," expected " << timeSeries2.toString() << " checkForRequeue to pass at " << to_simple_string(calendar.suiteTime()) );
- }
- else if ( calendar.suiteTime().time_of_day() >= timeSeries2.start().duration() && calendar.suiteTime().time_of_day() < last2 ) {
- BOOST_CHECK_MESSAGE(timeSeries2.checkForRequeue(calendar,t2_min,t2_max)," expected " << timeSeries2.toString() << " checkForRequeue to pass at " << to_simple_string(calendar.suiteTime()));
- }
- else {
- BOOST_CHECK_MESSAGE(!timeSeries2.checkForRequeue(calendar,t2_min,t2_max)," expected " << timeSeries2.toString() << " checkForRequeue to fail at " << to_simple_string(calendar.suiteTime()));
- }
-
-// if (calendar.dayChanged()) {
-// timeSeries.reset(calendar);
-// timeSeries2.reset(calendar);
-// }
- }
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_time_series_miss_time_slot )
-{
- cout << "ACore:: ...test_time_series_miss_time_slot\n";
-
- Calendar calendar;
- calendar.init(ptime(date(2008,10,8), hours(10) ), Calendar::REAL);
-
- // Create a test when we can match a time series.
- // NOTE: Finish minute is not a multiple of INCREMENT hence last valid time slot is 23:50
- //
- // Create the time series: start 10:00
- // finish 23:59
- // incr 00:10
- TimeSeries timeSeries(TimeSlot(10,0), TimeSlot(23,59), TimeSlot(0,10), false/* relative */);
- timeSeries.miss_next_time_slot(); // will increment next_time_slot
- BOOST_CHECK_MESSAGE(timeSeries.value() == TimeSlot(10,10), "miss time slot not working ");
-
- timeSeries.miss_next_time_slot(); // will increment next_time_slot
- BOOST_CHECK_MESSAGE(timeSeries.value() == TimeSlot(10,20), "miss time slot not working ");
-
- // requeue time series,
- timeSeries.requeue(calendar); // calendar time is at midnight 10:00
- BOOST_CHECK_MESSAGE(timeSeries.value() == TimeSlot(10,10),"Expected requeue to reset time series");
-}
-
-BOOST_AUTO_TEST_CASE( test_time_series_miss_time_slot_1 )
-{
- cout << "ACore:: ...test_time_series_miss_time_slot_1\n";
-
- // Create calendar before time series
- {
- Calendar calendar;
- calendar.init(ptime(date(2008,10,8), hours(9) ), Calendar::REAL); // 09:00
-
- TimeSeries timeSeries(10,0, false/* relative */); // 10:00
-
- TimeSlot t1_min, t1_max;
- timeSeries.min_max_time_slots(t1_min, t1_max);
- BOOST_CHECK_MESSAGE(t1_min == TimeSlot(10,0) && t1_max == TimeSlot(10,0),"Not as expected");
-
-
- BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar), "Expected time holding at 10:00 since calendar is 09:00");
- BOOST_CHECK_MESSAGE(!timeSeries.checkForRequeue(calendar,t1_min,t1_max), "Expected checkForRequeue to return false always");
-
- timeSeries.miss_next_time_slot();
- BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar), "Expected time to hold");
- BOOST_CHECK_MESSAGE(!timeSeries.checkForRequeue(calendar,t1_min,t1_max), "Expected checkForRequeue to return false");
-
- timeSeries.requeue(calendar);
- BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar), "Expected time holding at 10:00 since calendar is 09:00");
- BOOST_CHECK_MESSAGE(!timeSeries.checkForRequeue(calendar,t1_min,t1_max), "Expected checkForRequeue to return false after Requeue");
- }
- {
- // Create a time after the time series
- Calendar calendar;
- calendar.init(ptime(date(2008,10,8), hours(11) ), Calendar::REAL); // 11:00
-
- TimeSeries timeSeries(10,0, false/* relative */); // 10:00
-
- TimeSlot t1_min, t1_max;
- timeSeries.min_max_time_slots(t1_min, t1_max);
- BOOST_CHECK_MESSAGE(t1_min == TimeSlot(10,0) && t1_max == TimeSlot(10,0),"Not as expected");
-
-
- BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar), "Expected time NOT to be free, since calendar time is after time slot");
- BOOST_CHECK_MESSAGE(!timeSeries.checkForRequeue(calendar,t1_min,t1_max), "Expected checkForRequeue to return false, since calendar time > slot time");
-
- timeSeries.miss_next_time_slot();
- BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar), "Expected time to hold");
- BOOST_CHECK_MESSAGE(!timeSeries.checkForRequeue(calendar,t1_min,t1_max), "Expected checkForRequeue to return false");
-
- timeSeries.requeue(calendar);
- BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar), "Expected time to hold, since calendar time is after time slot");
- BOOST_CHECK_MESSAGE(!timeSeries.checkForRequeue(calendar,t1_min,t1_max), "Expected checkForRequeue to return false,since calendar time is after time slot");
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_time_series_reset )
-{
- cout << "ACore:: ...test_time_series_reset\n";
-
-
- // Create a test when we can match a time series.
- // NOTE: Finish minute is not a multiple of INCREMENT hence last valid time slot is 23:50
- //
- // Create the time series: start 10:00
- // finish 23:59
- // incr 00:10
- TimeSeries timeSeries(TimeSlot(10,0), TimeSlot(23,59), TimeSlot(0,10), false/* relative */);
- BOOST_CHECK_MESSAGE(timeSeries.value() == TimeSlot(10,0), "defaults not correct");
-
- { // set calendar before time series start & then reset
-
- Calendar calendar;
- calendar.init(ptime(date(2008,10,8), hours(9) ), Calendar::REAL);
- timeSeries.reset(calendar);
- BOOST_CHECK_MESSAGE(timeSeries.value() == TimeSlot(10,0), "Reset should set value(next_valid_time_slot) to start." << timeSeries.dump());
-
- timeSeries.miss_next_time_slot();
-
- timeSeries.requeue(calendar);
- BOOST_CHECK_MESSAGE(timeSeries.value() == TimeSlot(10,0), "requeue should set value(next_valid_time_slot) to start."<< timeSeries.dump());
- }
- { // set calendar at time series start & then reset
-
- Calendar calendar;
- calendar.init(ptime(date(2008,10,8), hours(10) ), Calendar::REAL);
- timeSeries.reset(calendar);
- BOOST_CHECK_MESSAGE(timeSeries.value() == TimeSlot(10,0), "Reset should set value(next_valid_time_slot) to start."<< timeSeries.dump());
-
- timeSeries.miss_next_time_slot();
-
- timeSeries.requeue(calendar);
- BOOST_CHECK_MESSAGE(timeSeries.value() == TimeSlot(10,10), "requeue should set value(next_valid_time_slot) to start."<< timeSeries.dump());
- }
- { // set calendar after time series start & before time series end, then reset
-
- Calendar calendar;
- calendar.init(ptime(date(2008,10,8), hours(11) ), Calendar::REAL);
- timeSeries.reset(calendar);
- BOOST_CHECK_MESSAGE(timeSeries.value() == TimeSlot(11,0), "Reset should update free slot."<< timeSeries.dump());
-
- timeSeries.miss_next_time_slot();
-
- timeSeries.requeue(calendar);
- BOOST_CHECK_MESSAGE(timeSeries.value() == TimeSlot(11,10), "requeue should update to first time slot."<< timeSeries.dump());
- }
-}
-
-
-BOOST_AUTO_TEST_CASE( test_time_series_parsing )
-{
- cout << "ACore:: ...test_time_series_parsing\n";
-
- BOOST_CHECK_MESSAGE(TimeSeries::create("00:30") == ecf::TimeSeries(0,30), "Error ");
- BOOST_CHECK_MESSAGE(TimeSeries::create("+00:30") == ecf::TimeSeries(0,30,true), "Error ");
-
- ecf::TimeSlot start(0,30);
- ecf::TimeSlot finish(21,03);
- ecf::TimeSlot incr(1,30);
- BOOST_CHECK_MESSAGE(TimeSeries::create("00:30 21:03 01:30") == ecf::TimeSeries(start,finish,incr), "Error");
- BOOST_CHECK_MESSAGE(TimeSeries::create("+00:30 21:03 01:30") == ecf::TimeSeries(start,finish,incr,true), "Error");
-}
-
-BOOST_AUTO_TEST_CASE( test_time_series_state_parsing )
-{
- cout << "ACore:: ...test_time_series_state_parsing\n";
-
- /// extract string like
- /// time +00:00 20:00 00:10 # this is a comment which will be ignored. index = 1
- /// time +20:00 // index = 1
- /// today 20:00 // index = 1
- /// +00:00 20:00 00:10 // index = 0
- /// +20:00 // index = 0
- /// will throw std:runtime_error for errors
- /// will assert if index >= lineTokens.size()
- {
- size_t index = 0;
- std::string the_time = "+00:00 20:00 00:10";
- std::vector<std::string> lineTokens;
- Str::split(the_time,lineTokens);
- BOOST_CHECK_MESSAGE(TimeSeries::create(index,lineTokens) == ecf::TimeSeries(TimeSlot(0,0),TimeSlot(20,0),TimeSlot(0,10),true), "Error");
- }
- {
- size_t index = 0;
- std::string the_time = "+10:10";
- std::vector<std::string> lineTokens;
- Str::split(the_time,lineTokens);
- BOOST_CHECK_MESSAGE(TimeSeries::create(index,lineTokens) == ecf::TimeSeries(TimeSlot(10,10),true), "Error");
- }
- {
- size_t index = 0;
- std::string the_time = "+10:10 # free isValid:false";
- ecf::TimeSeries expected(TimeSlot(10,10),true);
- expected.set_isValid(false);
-
- std::vector<std::string> lineTokens;
- Str::split(the_time,lineTokens);
- ecf::TimeSeries parsed_ts = TimeSeries::create(index,lineTokens,true);
- BOOST_CHECK_MESSAGE(parsed_ts == expected,
- "Expected \n'" << expected.toString() << expected.state_to_string(false) << "'" <<
- " But found \n'" << parsed_ts.toString() << parsed_ts.state_to_string(false) << "'");
- }
- {
- size_t index = 0;
- std::string the_time = "+10:10 # free isValid:false nextTimeSlot/10:10 relativeDuration/00:00:00";
- ecf::TimeSeries expected(TimeSlot(10,10),true);
- expected.set_isValid(false);
-
- std::vector<std::string> lineTokens;
- Str::split(the_time,lineTokens);
- ecf::TimeSeries parsed_ts = TimeSeries::create(index,lineTokens,true);
- BOOST_CHECK_MESSAGE(parsed_ts == expected,
- "Expected \n'" << expected.toString() << expected.state_to_string(false) << "'" <<
- " But found\n'" << parsed_ts.toString() << parsed_ts.state_to_string(false) << "'");
- }
- {
- // Update relative duration
- size_t index = 0;
- std::string the_time = "+10:10 # free isValid:false nextTimeSlot/10:10 relativeDuration/01:00:00";
- ecf::TimeSeries expected(TimeSlot(10,10),true);
- expected.set_isValid(false);
-
- Calendar calendar;
- calendar.init(ptime(date(2008,10,8), hours(0) ), Calendar::REAL);
- calendar.update( time_duration( hours(1) ) );
- expected.calendarChanged( calendar );
-
- std::vector<std::string> lineTokens;
- Str::split(the_time,lineTokens);
- ecf::TimeSeries parsed_ts = TimeSeries::create(index,lineTokens,true);
- BOOST_CHECK_MESSAGE(parsed_ts == expected,
- "Expected \n'" << expected.toString() << expected.state_to_string(false) << "'" <<
- " But found\n'" << parsed_ts.toString() << parsed_ts.state_to_string(false) << "'");
- }
-
- {
- // Update nextTimeSlot, create calendar at 09:00 and increment time series.
- std::string the_time = "09:00 12:00 01:00 # isValid:false nextTimeSlot/10:00 relativeDuration/00:00:00";
- ecf::TimeSeries expected(TimeSlot(9,0),TimeSlot(12,0),TimeSlot(1,0),false);
- expected.set_isValid(false);
-
- Calendar calendar;
- calendar.init(ptime(date(2008,10,8), hours(9) ), Calendar::REAL);
- expected.requeue( calendar ); // this will reset isValid to true
- expected.set_isValid(false);
-
- std::vector<std::string> lineTokens;
- Str::split(the_time,lineTokens);
- size_t index = 0;
- ecf::TimeSeries parsed_ts = TimeSeries::create(index,lineTokens,true);
-
- BOOST_CHECK_MESSAGE(parsed_ts == expected,
- "Expected \n'" << expected.dump() << expected.state_to_string(false) << "'" <<
- " But found\n'" << parsed_ts.dump() << parsed_ts.state_to_string(false) << "'");
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ACore/test/TestTimeSlot.cpp b/ecflow_4_0_7/ACore/test/TestTimeSlot.cpp
deleted file mode 100644
index b155b76..0000000
--- a/ecflow_4_0_7/ACore/test/TestTimeSlot.cpp
+++ /dev/null
@@ -1,109 +0,0 @@
-//============================================================================
-// Name : Request
-// Author : Avi
-// Revision : $Revision: #29 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/date_time/posix_time/time_formatters.hpp>
-
-#include <string>
-#include <iostream>
-#include <fstream>
-#include "TimeSeries.hpp"
-#include "Calendar.hpp"
-#include "Str.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost::posix_time;
-using namespace boost::gregorian;
-
-using namespace boost;
-
-BOOST_AUTO_TEST_SUITE( CoreTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_time_slot )
-{
- cout << "ACore:: ...test_time_slot\n";
-
- // test timeslot operator
- {
- TimeSlot x;
- TimeSlot y;
- BOOST_CHECK_MESSAGE( x.isNULL(),"Expected NULL");
- BOOST_CHECK_MESSAGE( y.isNULL(),"Expected NULL");
- BOOST_CHECK_MESSAGE( x == y,"Equality operator expected to succeed");
- BOOST_CHECK_MESSAGE( !(x < y),"Less than operator expected to fail");
- BOOST_CHECK_MESSAGE( !(x > y),"Greater than operator expected to fail");
- BOOST_CHECK_MESSAGE( x <= y,"<= operator expected to succeed");
- BOOST_CHECK_MESSAGE( x >= y,">= operator expected to succeed");
- BOOST_CHECK_MESSAGE( y <= x,"<= operator expected to succeed");
- BOOST_CHECK_MESSAGE( y >= x,">= operator expected to succeed");
-
- TimeSlot a(10,12);
- TimeSlot b(10,12);
- BOOST_CHECK_MESSAGE( !a.isNULL(),"Expected NOT NULL");
- BOOST_CHECK_MESSAGE( !b.isNULL(),"Expected NOT NULL");
- BOOST_CHECK_MESSAGE( a == b,"Equality operator expected to succeed");
- BOOST_CHECK_MESSAGE( !(a < b),"Less than operator expected to fail");
- BOOST_CHECK_MESSAGE( !(a > b),"Greater than operator expected to fail");
- BOOST_CHECK_MESSAGE( a <= b,"<= operator expected to succeed");
- BOOST_CHECK_MESSAGE( a >= b,">= operator expected to succeed");
- BOOST_CHECK_MESSAGE( b <= a,"<= operator expected to succeed");
- BOOST_CHECK_MESSAGE( b >= a,">= operator expected to succeed");
-
- TimeSlot c(0,0);
- TimeSlot d(0,0);
- BOOST_CHECK_MESSAGE( !c.isNULL(),"Expected NOT NULL");
- BOOST_CHECK_MESSAGE( !d.isNULL(),"Expected NOT NULL");
- BOOST_CHECK_MESSAGE( c == d,"Equality operator expected to succeed");
- BOOST_CHECK_MESSAGE( !(c < d),"Less than operator expected to fail");
- BOOST_CHECK_MESSAGE( !(c > d),"Greater than operator expected to fail");
- BOOST_CHECK_MESSAGE( c <= d,"<= operator expected to succeed");
- BOOST_CHECK_MESSAGE( c >= d,">= operator expected to succeed");
- BOOST_CHECK_MESSAGE( d <= c,"<= operator expected to succeed");
- BOOST_CHECK_MESSAGE( d >= c,">= operator expected to succeed");
-
- TimeSlot a1(10,1);
- TimeSlot b1(10,12);
- BOOST_CHECK_MESSAGE( !a1.isNULL(),"Expected NOT NULL");
- BOOST_CHECK_MESSAGE( !b1.isNULL(),"Expected NOT NULL");
- BOOST_CHECK_MESSAGE( a1 != b1,"Equality operator expected to fail");
- BOOST_CHECK_MESSAGE( a1 < b1,"Less than operator expected to succeed");
- BOOST_CHECK_MESSAGE( !(a1 > b1),"Greater than operator expected to fail");
- BOOST_CHECK_MESSAGE( !(a1 >= b1),">= than operator expected to fail");
- BOOST_CHECK_MESSAGE( b1 > a1,"Greater than operator expected to succeed");
- BOOST_CHECK_MESSAGE( b1 >= a1,">= expected to succeed");
-
- TimeSlot xx(10,1);
- TimeSlot yy(23,12);
- BOOST_CHECK_MESSAGE( xx != yy,"Equality operator expected to fail");
- BOOST_CHECK_MESSAGE( xx < yy,"Less than operator expected to succeed");
- BOOST_CHECK_MESSAGE( xx <= yy,"<= operator expected to succeed");
- BOOST_CHECK_MESSAGE( yy > xx,"Greater than operator expected to succeed");
- BOOST_CHECK_MESSAGE( yy >= xx,">= operator expected to succeed");
- BOOST_CHECK_MESSAGE( !(xx > yy),"Greater than operator expected to fail");
- BOOST_CHECK_MESSAGE( !(xx >= yy),">= operator expected to fail");
-
- TimeSlot x1(11,0);
- TimeSlot y1(10,0);
- BOOST_CHECK_MESSAGE( x1 != y1,"Equality operator expected to fail");
- BOOST_CHECK_MESSAGE( !(x1 < y1),"Less than operator expected to fail");
- BOOST_CHECK_MESSAGE( !(x1 <= y1),"<= operator expected to fail");
- BOOST_CHECK_MESSAGE( x1 > y1,"Greater than operator expected to succced");
- BOOST_CHECK_MESSAGE( x1 >= y1,">= operator expected to succced");
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ACore/test/TestVersion.cpp b/ecflow_4_0_7/ACore/test/TestVersion.cpp
deleted file mode 100644
index e412b4c..0000000
--- a/ecflow_4_0_7/ACore/test/TestVersion.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #23 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <string>
-#include <iostream>
-#include <boost/test/unit_test.hpp>
-#include "Version.hpp"
-#include "boost_archive.hpp"
-#include "File.hpp"
-#include "Str.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost;
-
-BOOST_AUTO_TEST_SUITE( CoreTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_version )
-{
- std::string desc = Version::description();
- BOOST_CHECK_MESSAGE(!desc.empty(),"Expected version");
- cout << "ACore:: ...test_version:" << desc << endl;
-}
-
-BOOST_AUTO_TEST_CASE( boost_serialisation_archive_version )
-{
- cout << "ACore:: ...boost_serialisation_archive_version: " << ecf::boost_archive::version() << endl;
- BOOST_REQUIRE_MESSAGE(ecf::boost_archive::version() != 0,"keep boost from complaining");
-}
-
-
-BOOST_AUTO_TEST_CASE( test_version_against_VERSION_cmake )
-{
- cout << "ACore:: ...test_version_against_VERSION_cmake" << endl;
-
- // Open the file VERSION.cmake
- std::string version_cmake_file = File::root_source_dir() + "/VERSION.cmake";
- std::vector<std::string> lines;
- BOOST_REQUIRE_MESSAGE(File::splitFileIntoLines(version_cmake_file,lines,true/* impore empty lines */),"Failed to open file " << version_cmake_file);
- BOOST_REQUIRE_MESSAGE(!lines.empty(),"File " << version_cmake_file << " does not contain version info ??");
-
- // Expecting lines like:
- // set( ECFLOW_RELEASE "4" )
- // set( ECFLOW_MAJOR "0" )
- // set( ECFLOW_MINOR "4" )
- // set( ${PROJECT_NAME}_VERSION_STR "${ECFLOW_RELEASE}.${ECFLOW_MAJOR}.${ECFLOW_MINOR}" )
- // Compare against VERSION
- std::string ecflow_release,ecflow_major,ecflow_minor;
- for(size_t i =0; i < lines.size(); ++i) {
- std::vector<std::string> tokens;
- Str::split(lines[i],tokens);
-
- // expecting third token to contain version data
- if (lines[i].find("set( ECFLOW_RELEASE") != std::string::npos && tokens.size() >= 3) {
- ecflow_release = tokens[2];
- Str::removeQuotes(ecflow_release);
- }
- if (lines[i].find("set( ECFLOW_MAJOR") != std::string::npos && tokens.size() >= 3) {
- ecflow_major = tokens[2];
- Str::removeQuotes(ecflow_major);
- }
- if (lines[i].find("set( ECFLOW_MINOR") != std::string::npos && tokens.size() >= 3) {
- ecflow_minor = tokens[2];
- Str::removeQuotes(ecflow_minor);
- }
- }
-
- std::string extracted_version = ecflow_release + "." + ecflow_major + "." + ecflow_minor;
-
- // The if they don't match, we have failed to regenrate and check in ecflow_version.h
- BOOST_REQUIRE_MESSAGE(Version::raw() == extracted_version,"\n Expected " << extracted_version << " but found " << Version::raw() << ", Please regenerate file $WK/ACore/src/ecflow_version.h by calling 'sh -x $WK/cmake.sh debug'");
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ACore/test/TestVersioning.cpp b/ecflow_4_0_7/ACore/test/TestVersioning.cpp
deleted file mode 100644
index e7ee912..0000000
--- a/ecflow_4_0_7/ACore/test/TestVersioning.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-//============================================================================
-// Name : Request
-// Author : Avi
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <fstream>
-#include <boost/test/unit_test.hpp>
-#include <boost/serialization/serialization.hpp>
-#include <boost/serialization/version.hpp>
-#include "boost/filesystem/operations.hpp"
-
-#include "TestVersioning.hpp"
-#include "Serialization.hpp"
-
-using namespace std;
-using namespace boost;
-
-BOOST_AUTO_TEST_SUITE( CoreTestSuite )
-
-// This class will create a Class X. This is serialised.
-// This class is then reloaded, with different kinds of version changes, to base version 0;
-// Note: we simulate different release of class X, by using name spaces
-// This is possible since the name space is not written.
-BOOST_AUTO_TEST_CASE( test_versioning )
-{
- cout << "ACore:: ...test_versioning\n";
- {
- // write out version 0; This will be reloaded with different version of X
- const version0::X t = version0::X(10);
- ecf::save("version0",t);
- }
-
- {
- // Version 1 adds a new data member: i.e min_
- version_new_data_member::X t;
- ecf::restore("version0",t);
- BOOST_CHECK_MESSAGE(t == version_new_data_member::X(10,0),"Should be the same");
- }
-
- {
- // Version 1 change data member name: from hour_ -> hours_:
- // This required no change at all. Since serialisation relies on order.
- version_change_dm_name::X t;
- ecf::restore("version0",t);
- BOOST_CHECK_MESSAGE(t == version_change_dm_name::X(10),"Should be the same");
- }
-
- {
- // Version 1 change data member type: from int -> string :
- version_change_dm_type::X t;
- ecf::restore("version0",t);
- BOOST_CHECK_MESSAGE(t == version_change_dm_type::X("10"),"Reading integer as string expected '10', but found string " << t.str());
- }
-
- // remove the generate file
- boost::filesystem::remove("version0");
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ACore/test/TestVersioning.hpp b/ecflow_4_0_7/ACore/test/TestVersioning.hpp
deleted file mode 100644
index 182a4f9..0000000
--- a/ecflow_4_0_7/ACore/test/TestVersioning.hpp
+++ /dev/null
@@ -1,97 +0,0 @@
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-#include <boost/serialization/string.hpp>
-#include <boost/serialization/version.hpp>
-#include <boost/lexical_cast.hpp>
-#include <iostream>
-
-
-/// To simulate changing of data model over time, we will
-/// namespace's. The actual serialisation does not appears to
-/// persist the name space
-
-namespace version0 {
-class X {
-public:
- X(int h = 0) : hour_(h) {}
- bool operator==(const X& rhs) const { return hour_ == rhs.hour_; }
-private:
- int hour_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int version) {
- ar & hour_;
- }
-};
-}
-
-namespace version_new_data_member {
-class X {
-public:
- X(int h = 0, int m =0) : hour_(h),min_(m) {}
- bool operator==(const X& rhs) const { return hour_ == rhs.hour_ && min_ == rhs.min_; }
-private:
- int hour_;
- int min_;
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int version) {
- // When *loading* the version pertains to loaded version in the data
- // When *saving* the version always pertains to the latest version
- ar & hour_;
- if (version > 0) ar & min_;
- }
-};
-}
-BOOST_CLASS_VERSION(version_new_data_member::X, 1)
-
-namespace version_change_dm_name {
-class X {
-public:
- X(int h = 0) : hours_(h) {}
- bool operator==(const X& rhs) const { return hours_ == rhs.hours_; }
-private:
- int hours_;
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int version) {
- ar & hours_;
- }
-};
-}
-BOOST_CLASS_VERSION(version_change_dm_name::X, 1)
-
-namespace version_change_dm_type {
-class X {
-public:
- X(const std::string& h = "") : hour_(h) {}
- bool operator==(const X& rhs) const { return hour_ == rhs.hour_; }
- std::string str() const { return hour_; }
-private:
- std::string hour_;
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int version) {
- // When *loading* the version pertains to loaded version in the data
- // When *saving* the version always pertains to the latest version
- if (version == 0) {
- // Change data member type: int(version0)--->string(version1)
- int the_old_hour = 0;
- ar & the_old_hour;
- hour_ = boost::lexical_cast<std::string>(the_old_hour);
- }
- else {
- ar & hour_;
- }
- }
-};
-}
-BOOST_CLASS_VERSION(version_change_dm_type::X, 1)
diff --git a/ecflow_4_0_7/ACore/test/TestWhiteListFile.cpp b/ecflow_4_0_7/ACore/test/TestWhiteListFile.cpp
deleted file mode 100644
index ad7e5be..0000000
--- a/ecflow_4_0_7/ACore/test/TestWhiteListFile.cpp
+++ /dev/null
@@ -1,148 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #11 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <boost/test/unit_test.hpp>
-#include <boost/lexical_cast.hpp>
-#include <boost/archive/tmpdir.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/foreach.hpp>
-#include "boost/progress.hpp"
-
-#include <iostream>
-#include <fstream>
-
-#include "WhiteListFile.hpp"
-#include "File.hpp"
-
-namespace fs = boost::filesystem;
-using namespace std;
-using namespace ecf;
-
-//#define DEBUG_ME 1
-
-BOOST_AUTO_TEST_SUITE( CoreTestSuite )
-
-void test_white_list_files(const std::string& directory, bool pass)
-{
- fs::path full_path( fs::initial_path<fs::path>() );
- full_path = fs::system_complete( fs::path( directory ) );
-
- BOOST_CHECK(fs::exists( full_path ));
- BOOST_CHECK(fs::is_directory( full_path ));
-
- //std::cout << "\nIn directory: " << full_path.directory_string() << "\n\n";
- fs::directory_iterator end_iter;
- for ( fs::directory_iterator dir_itr( full_path ); dir_itr != end_iter; ++dir_itr )
- {
- try
- {
- fs::path relPath(directory + "/" + dir_itr->path().filename().string());
-
- // recurse down directories
- if ( fs::is_directory(dir_itr->status()) ) {
- test_white_list_files(relPath.string(),pass);
- continue;
- }
-
-#if DEBUG_ME
- std::cout << "......Parsing file " << relPath.string() << "\n";
-#endif
-
- WhiteListFile theFile(relPath.string());
-
- std::map<std::string,bool> validUsers;
- std::string errorMsg;
-
- bool parsedOk = theFile.parse(validUsers, errorMsg);
- if (pass) {
- // Test expected to pass
- BOOST_CHECK_MESSAGE(parsedOk,"Failed to parse file " << relPath << "\n" << errorMsg);
- }
- else {
- // test expected to fail
- BOOST_CHECK_MESSAGE(!parsedOk,"Parse expected to fail for " << relPath << "\n" << errorMsg);
-#if DEBUG_ME
- cout << "\n" << errorMsg << "\n";
-#endif
- }
- }
- catch ( const std::exception & ex )
- {
- std::cout << dir_itr->path().filename() << " " << ex.what() << std::endl;
- }
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_parsing_for_good_white_list_files )
-{
- cout << "ACore:: ...test_parsing_for_good_white_list_files\n";
-
- std::string path = File::test_data("ACore/test/data/goodWhiteListFiles","ACore");
-
- // All the files in this directory are expected to pass
- test_white_list_files(path, true);
-}
-
-BOOST_AUTO_TEST_CASE( test_parsing_for_bad_white_list_files )
-{
- cout << "ACore:: ...test_parsing_for_bad_white_list_files\n";
-
- std::string path = File::test_data("ACore/test/data/badWhiteListFiles","ACore");
-
- // All the files in this directory are expected to fail
- test_white_list_files(path, false);
-}
-
-
-BOOST_AUTO_TEST_CASE( test_white_list )
-{
- cout << "ACore:: ...test_white_list\n";
-
- std::string path = File::test_data("ACore/test/data/goodWhiteListFiles/good1.lists","ACore");
-
- WhiteListFile theFile(path);
- std::map<std::string,bool> validUsers;
- std::string errorMsg;
- BOOST_CHECK_MESSAGE(theFile.parse(validUsers, errorMsg),"Failed to parse file " << path << "\n" << errorMsg);
-
- // make sure we find all the users and the access right are correct
-// uid1 # a comment
-// uid2 # a comment
-// cog # a comment
-//
-// #
-// # Read only uisers
-// #
-// -fred # a comment
-// -bill # a comment
-// -jake # a comment
- std::vector< std::pair<std::string,bool> > expected;
- expected.push_back(std::make_pair(std::string("uid1"), true));
- expected.push_back(std::make_pair(std::string("uid2"), true));
- expected.push_back(std::make_pair(std::string("cog"), true));
- expected.push_back(std::make_pair(std::string("fred"), false));
- expected.push_back(std::make_pair(std::string("bill"), false));
- expected.push_back(std::make_pair(std::string("jake"), false));
-
- BOOST_REQUIRE_MESSAGE(expected.size() == validUsers.size(), " expected " << expected.size() << " users but found " << validUsers.size() );
- std::vector< std::pair<std::string,bool> >::const_iterator i;
- for(i=expected.begin(); i!= expected.end(); ++i) {
- std::map<std::string,bool>::const_iterator it = validUsers.find( (*i).first );
- BOOST_REQUIRE_MESSAGE(it != validUsers.end(),"Failed to find user " << (*i).first);
- BOOST_REQUIRE_MESSAGE((*it).second == (*i).second ,"For user " << (*i).first << " expected " << (*i).second << " but found " << (*it).second);
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ACore/test/data/goodWhiteListFiles/good1.lists b/ecflow_4_0_7/ACore/test/data/goodWhiteListFiles/good1.lists
deleted file mode 100644
index 7451d5f..0000000
--- a/ecflow_4_0_7/ACore/test/data/goodWhiteListFiles/good1.lists
+++ /dev/null
@@ -1,22 +0,0 @@
-#
-4.4.14 # comment
-
-#
-# These user have read and write access to the server
-#
-uid1 # a comment
-uid2 # a comment
-cog # a comment
-
-#
-# Read only uisers
-#
--fred # a comment
--bill # a comment
--jake # a comment
-
-
-# a comment
-# a comment
-# a comment
-# a comment
diff --git a/ecflow_4_0_7/ACore/test/data/goodWhiteListFiles/goodsms.lists b/ecflow_4_0_7/ACore/test/data/goodWhiteListFiles/goodsms.lists
deleted file mode 100644
index c274d5b..0000000
--- a/ecflow_4_0_7/ACore/test/data/goodWhiteListFiles/goodsms.lists
+++ /dev/null
@@ -1,7 +0,0 @@
-
-4.4.14 # comment
-
-uid1
-uid2
-cog
-
diff --git a/ecflow_4_0_7/ANattr/jamfile.jam b/ecflow_4_0_7/ANattr/jamfile.jam
deleted file mode 100644
index 82d90bf..0000000
--- a/ecflow_4_0_7/ANattr/jamfile.jam
+++ /dev/null
@@ -1,44 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-#
-# Node attribute project
-#
-project theNodeAttr ;
-
-use-project theCore : ../ACore ;
-
-# The <include> means we will automatically add this directory to the include path
-# of any other target that uses this lib
-#
-lib nodeattr : [ glob src/*.cpp ]
- : <link>static
- <variant>debug:<define>DEBUG
- <use>/theCore//core
- <use>/site-config//boost_system
- <use>/site-config//boost_serialization
- <use>/site-config//boost_filesystem
- <use>/site-config//boost_datetime
- <use>/site-config//boost_test
- :
- : <include>../ANattr/src
- ;
-
-#
-# boost_datetime is only required for formatting. i.e to call to_simple_string
-# cerr << to_simple_string(calendar.suiteTime()) << "\n";
-#
-exe u_anattr : [ glob test/*.cpp ]
- /theCore//core
- nodeattr
- /site-config//boost_system
- /site-config//boost_filesystem
- /site-config//boost_serialization
- /site-config//boost_datetime
- /site-config//boost_test
- : <variant>debug:<define>DEBUG
- ;
\ No newline at end of file
diff --git a/ecflow_4_0_7/ANattr/src/AutoCancelAttr.cpp b/ecflow_4_0_7/ANattr/src/AutoCancelAttr.cpp
deleted file mode 100644
index b065dc6..0000000
--- a/ecflow_4_0_7/ANattr/src/AutoCancelAttr.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #9 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <sstream>
-
-#include "AutoCancelAttr.hpp"
-#include "Calendar.hpp"
-#include "Indentor.hpp"
-#include "Log.hpp"
-
-#ifdef DEBUG
-#include <boost/date_time/posix_time/time_formatters.hpp>
-#endif
-
-using namespace std;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-
-namespace ecf {
-
-std::ostream& AutoCancelAttr::print(std::ostream& os) const
-{
- Indentor in;
- Indentor::indent(os) << "autocancel ";
- if (days_) {
- os << timeStruct_.hour()/24 << "\n";
- return os;
- }
-
- if (relative_) os << "+";
- timeStruct_.print(os);
- os << "\n";
- return os;
-}
-
-std::string AutoCancelAttr::toString() const
-{
- std::stringstream ss;
- ss << "autocancel ";
- if (days_) {
- ss << timeStruct_.hour()/24;
- return ss.str();
- }
-
- if (relative_) ss << "+";
- ss << timeStruct_.toString();
- return ss.str();
-}
-
-
-bool AutoCancelAttr::operator==(const AutoCancelAttr& rhs) const
-{
- if (relative_ != rhs.relative_) return false;
- if (days_ != rhs.days_) return false;
- return timeStruct_.operator==(rhs.timeStruct_);
-}
-
-bool AutoCancelAttr::isFree(const ecf::Calendar& calendar,const boost::posix_time::time_duration& suiteDurationAtComplete) const
-{
- // suiteTime()
- // suiteDurationAtComplete autocancel time calendar duration
- // | | |
- // V V V
- // ----------------------------------------------------------------------------------> time
- // ^ ^
- // |--------elapsed time---------------------------------------|
- //
- //
-
- if ( relative_ ) {
- time_duration timeElapsedAfterComplete = calendar.duration() - suiteDurationAtComplete;
- LOG_ASSERT(!timeElapsedAfterComplete.is_negative(),"should always be positive or some things gone wrong");
- if (timeElapsedAfterComplete >= timeStruct_.duration()) {
- return true;
- }
- }
- else {
- // real time
-//#ifdef DEBUG
-// cout << "real time timeStruct_(" << to_simple_string(timeStruct_.duration())
-// << ") calendar.suiteTime().time_of_day(" << to_simple_string(calendar.suiteTime().time_of_day()) << ")\n";
-//#endif
- if (calendar.suiteTime().time_of_day() >= timeStruct_.duration()) {
- return true;
- }
- }
-
- return false;
-}
-
-}
diff --git a/ecflow_4_0_7/ANattr/src/AutoCancelAttr.hpp b/ecflow_4_0_7/ANattr/src/AutoCancelAttr.hpp
deleted file mode 100644
index 2102e5d..0000000
--- a/ecflow_4_0_7/ANattr/src/AutoCancelAttr.hpp
+++ /dev/null
@@ -1,59 +0,0 @@
-#ifndef AUTOCANCELATTR_HPP_
-#define AUTOCANCELATTR_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #9 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "TimeSlot.hpp"
-
-namespace ecf { class Calendar;} // forward declare class
-
-namespace ecf {
-
-// Use compiler , destructor, assignment, copy constructor
-class AutoCancelAttr {
-public:
- AutoCancelAttr() : relative_(true),days_(false) {}
- AutoCancelAttr(int hour, int minute, bool relative ) : timeStruct_(hour, minute), relative_(relative), days_(false) {}
- AutoCancelAttr(const TimeSlot& ts, bool relative ) : timeStruct_(ts), relative_(relative), days_(false) {}
- AutoCancelAttr(int days) : timeStruct_( TimeSlot(days*24,0) ), relative_(true), days_(true) {}
-
- std::ostream& print(std::ostream&) const;
- bool operator==(const AutoCancelAttr& rhs) const;
- bool isFree(const ecf::Calendar&, const boost::posix_time::time_duration& suiteDurationAtComplete) const;
-
- std::string toString() const;
-
- const TimeSlot& time() const { return timeStruct_;}
- bool relative() const { return relative_; }
- bool days() const { return days_; }
-
-private:
- TimeSlot timeStruct_;
- bool relative_;
- bool days_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/)
- {
- ar & timeStruct_;
- ar & relative_;
- ar & days_;
- }
-};
-
-}
-#endif
-
diff --git a/ecflow_4_0_7/ANattr/src/ClockAttr.cpp b/ecflow_4_0_7/ANattr/src/ClockAttr.cpp
deleted file mode 100644
index 47970ea..0000000
--- a/ecflow_4_0_7/ANattr/src/ClockAttr.cpp
+++ /dev/null
@@ -1,169 +0,0 @@
-//============================================================================
-// Name : NodeTree.cpp
-// Author : Avi
-// Revision : $Revision: #21 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "ClockAttr.hpp"
-#include "DateAttr.hpp"
-#include "Indentor.hpp"
-#include "Calendar.hpp"
-#include "Ecf.hpp"
-
-#include <boost/foreach.hpp>
-#include <assert.h>
-#include <sstream>
-
-using namespace std;
-using namespace ecf;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-
-//==========================================================================================
-
-ClockAttr::ClockAttr(const boost::posix_time::ptime& time, bool hybrid,bool positiveGain)
-: hybrid_(hybrid), positiveGain_(positiveGain), startStopWithServer_(false),
- gain_(0), day_(0),month_(0),year_(0),
- state_change_no_(Ecf::incr_state_change_no())
-{
- boost::gregorian::date theDate = time.date();
- day_ = theDate.day();
- month_ = theDate.month();
- year_ = theDate.year();
-
- tm t = to_tm(time);
- gain_ = t.tm_hour *3600 + t.tm_min*60 + t.tm_sec;
-}
-
-ClockAttr::ClockAttr(int day, int month, int year, bool hybrid )
-: hybrid_(hybrid), positiveGain_(false), startStopWithServer_(false),
- gain_(0), day_(day),month_(month),year_(year),
- state_change_no_(Ecf::incr_state_change_no())
-{
- // Will throw std::out_of_range exception
- DateAttr::checkDate(day,month,year,false /* for calendars we don't allow wild carding */);
-}
-
-ClockAttr::ClockAttr(bool hybrid)
-: hybrid_(hybrid), positiveGain_(false), startStopWithServer_(false),
- gain_(0), day_(0),month_(0),year_(0),
- state_change_no_(Ecf::incr_state_change_no()) {}
-
-std::ostream& ClockAttr::print(std::ostream& os) const
-{
- Indentor in;
- Indentor::indent(os) << toString() << "\n";
- return os;
-}
-
-std::string ClockAttr::toString() const
-{
- std::stringstream ss;
- ss << "clock ";
- if (hybrid_) ss << "hybrid ";
- else ss << "real ";
-
- if (day_ != 0) ss << day_ << "." << month_ << "." << year_ << " ";
-
- if (gain_ != 0) {
- if (positiveGain_) ss << "+";
- ss << gain_;
- }
-
- if ( startStopWithServer_) ss << " -s";
-
- return ss.str();
-}
-
-bool ClockAttr::operator==(const ClockAttr& rhs) const
-{
- if (hybrid_ != rhs.hybrid_) return false;
- if (positiveGain_ != rhs.positiveGain_) return false;
- if (startStopWithServer_ != rhs.startStopWithServer_) return false;
-
- if (day_ != rhs.day_) return false;
- if (month_ != rhs.month_) return false;
- if (year_ != rhs.year_) return false;
-
- if (gain_ != rhs.gain_) return false;
-
- return true;
-}
-
-void ClockAttr::date(int day, int month, int year)
-{
- // Will throw std::out_of_range exception
- DateAttr::checkDate(day,month,year,false /* for calendars we don't allow wild carding */);
- day_ = day;
- month_ = month;
- year_ = year;
- state_change_no_ = Ecf::incr_state_change_no();
-}
-
-void ClockAttr::set_gain(int hour,int min,bool positiveGain)
-{
- positiveGain_ = positiveGain;
- gain_ = (hour * 3600) + min *60;
- state_change_no_ = Ecf::incr_state_change_no();
-}
-
-void ClockAttr::set_gain_in_seconds(long theGain,bool positiveGain)
-{
- positiveGain_ = positiveGain;
- gain_ = theGain;
- state_change_no_ = Ecf::incr_state_change_no();
-}
-
-void ClockAttr::startStopWithServer(bool f) {
- startStopWithServer_ = f;
- state_change_no_ = Ecf::incr_state_change_no();
-}
-
-void ClockAttr::hybrid( bool f ) {
- hybrid_ = f;
- state_change_no_ = Ecf::incr_state_change_no();
-}
-
-void ClockAttr::sync() {
- // When begin_calendar() is called we will sync with computer clock.
- gain_ = 0;
- day_ = 0;
- month_ = 0 ;
- year_ = 0;
- state_change_no_ = Ecf::incr_state_change_no();
-}
-
-void ClockAttr::init_calendar(ecf::Calendar& calendar)
-{
- Calendar::Clock_t clockType = (hybrid_) ? Calendar::HYBRID : Calendar::REAL;
- calendar.init(clockType, startStopWithServer_);
-}
-
-void ClockAttr::begin_calendar(ecf::Calendar& calendar)
-{
- using namespace boost::posix_time;
- using namespace boost::gregorian;
-
- if (day_ != 0) {
- // Use the date given. ie we start from midnight on the given day + gain.
- boost::gregorian::date theDate(year_,month_,day_);
- ptime the_time(theDate, seconds(gain_));
- calendar.begin(the_time);
- }
- else {
- // Get the local time, second level resolution, based on the time zone settings of the computer.
- ptime the_time(Calendar::second_clock_time());
- the_time += seconds(gain_);
- calendar.begin(the_time);
- }
-}
-
diff --git a/ecflow_4_0_7/ANattr/src/ClockAttr.hpp b/ecflow_4_0_7/ANattr/src/ClockAttr.hpp
deleted file mode 100644
index 0be3454..0000000
--- a/ecflow_4_0_7/ANattr/src/ClockAttr.hpp
+++ /dev/null
@@ -1,100 +0,0 @@
-#ifndef CLOCKATTR_HPP_
-#define CLOCKATTR_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #18 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <ostream>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-#include <boost/serialization/serialization.hpp>
-
-namespace ecf { class Calendar;} // forward declare class that is in a namesapce
-
-/// The clock attribute is defined on the suite ONLY
-/// Use default copy constructor and assignment operator, destructor
-/// The clock attribute is used to initialise the calendar object
-/// **********************************************************************
-/// In the OLD sms the date is actually used as a gain factor(well at least
-/// according to the user/reference manual), in the ec-flow
-/// a date, is a date. i.e. it allows us to start a suite in the past.
-///
-/// The Constructor will update the State change number, since it can be added
-/// by the AlterCmd. in the Client Context, state change number is not incremented
-/// ************************************************************************
-///
-class ClockAttr {
-public:
- /// The following constructor is used for test only. It allows us to
- /// create a clock attribute initialised with given date and time
- ClockAttr(const boost::posix_time::ptime&, bool hybrid = false, bool positiveGain = true);
- ClockAttr(int day, int month, int year, bool hybrid = false );
- ClockAttr(bool hybrid = false);
-
- std::ostream& print(std::ostream&) const;
- bool operator==(const ClockAttr& rhs) const;
-
- void date(int day, int month, int year);
- void set_gain(int hour,int min,bool positiveGain = true);
- void set_gain_in_seconds(long theGain,bool positiveGain = true);
-
- void startStopWithServer(bool f);
- bool startStopWithServer() const { return startStopWithServer_; }
- void hybrid( bool f );
-
- // clear local attributes so, than when we re-queue suite, we sync with computer clock
- void sync();
-
- void init_calendar(ecf::Calendar&);
- void begin_calendar(ecf::Calendar&);
-
- // The state_change_no is never reset. Must be incremented if it can affect equality
- unsigned int state_change_no() const { return state_change_no_; }
-
- // access
- int day() const { return day_; }
- int month() const { return month_; }
- int year() const { return year_; }
- long gain() const { return gain_;}
- bool positive_gain() const { return positiveGain_;}
- bool hybrid() const { return hybrid_;}
- bool is_virtual() const { return startStopWithServer_;}
- std::string toString() const;
-
-private:
- bool hybrid_;
- bool positiveGain_;
- bool startStopWithServer_; // see Calendar.hpp for more details
- long gain_; // in seconds
- int day_;
- int month_;
- int year_;
-
- unsigned int state_change_no_; // *not* persisted, only used on server side
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/)
- {
- ar & hybrid_;
- ar & positiveGain_;
- ar & startStopWithServer_;
- ar & gain_;
- ar & day_;
- ar & month_;
- ar & year_;
- }
-};
-
-#endif
diff --git a/ecflow_4_0_7/ANattr/src/CronAttr.cpp b/ecflow_4_0_7/ANattr/src/CronAttr.cpp
deleted file mode 100644
index e520d38..0000000
--- a/ecflow_4_0_7/ANattr/src/CronAttr.cpp
+++ /dev/null
@@ -1,724 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #59 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <sstream>
-
-#include <boost/foreach.hpp>
-#include <boost/date_time/posix_time/time_formatters.hpp> // requires boost date and time lib
-#include <boost/algorithm/string/trim.hpp>
-#include <boost/tokenizer.hpp>
-#include <boost/token_functions.hpp>
-#include <boost/lexical_cast.hpp>
-
-#include "CronAttr.hpp"
-#include "Indentor.hpp"
-#include "Calendar.hpp"
-#include "PrintStyle.hpp"
-#include "Str.hpp"
-#include "Ecf.hpp"
-#include "Log.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-
-//#define DEBUG_CRON_ATTR 1
-//#define DEBUG_CRON_PARSING 1
-
-namespace ecf {
-
-CronAttr::CronAttr() : makeFree_(false),state_change_no_(0) {}
-
-void CronAttr::addWeekDays( const std::vector<int>& w)
-{
- weekDays_ = w;
- BOOST_FOREACH(int day,weekDays_) {
- if (day < 0 || day > 6) {
- std::stringstream ss; ss << "Invalid range for day(" << day << ") of the week expected range is 0==Sun to 6==Sat";
- throw std::out_of_range(ss.str());
- }
- }
-}
-void CronAttr::addDaysOfMonth( const std::vector<int>& d)
-{
- daysOfMonth_ = d;
- BOOST_FOREACH(int day_of_month,daysOfMonth_) {
- if (day_of_month < 1 || day_of_month > 31) {
- std::stringstream ss; ss << "Invalid range for day of month(" << day_of_month << ") expected range is 1-31";
- throw std::out_of_range(ss.str());
- }
- }
-}
-
-void CronAttr::addMonths( const std::vector<int>& m)
-{
- months_ = m;
- BOOST_FOREACH(int month,months_) {
- if (month < 1 || month > 12) {
- std::stringstream ss; ss << "Invalid range for month(" << month << ") expected range is 1==Jan to 12==Dec";
- throw std::out_of_range(ss.str());
- }
- }
-}
-
-std::ostream& CronAttr::print(std::ostream& os) const
-{
- Indentor in;
- Indentor::indent(os) << toString();
- if (!PrintStyle::defsStyle()) {
- os << timeSeries_.state_to_string(makeFree_);
- }
- os << "\n";
- return os;
-}
-
-std::string CronAttr::toString() const
-{
- std::stringstream ss;
- ss << "cron ";
- if (!weekDays_.empty()) {
- ss << "-w ";
- for(size_t i=0; i<weekDays_.size();++i) {
- ss << weekDays_[i];
- if (i !=weekDays_.size()-1) ss << ",";
- }
- ss << " ";
- }
- if (!daysOfMonth_.empty()) {
- ss << "-d ";
- for(size_t i=0; i<daysOfMonth_.size();++i) {
- ss << daysOfMonth_[i];
- if (i !=daysOfMonth_.size()-1) ss << ",";
- }
- ss << " ";
- }
- if (!months_.empty()) {
- ss << "-m ";
- for(size_t i=0; i<months_.size();++i) {
- ss << months_[i];
- if (i !=months_.size()-1) ss << ",";
- }
- ss << " ";
- }
-
- ss << timeSeries_.toString(); // no new line added, up to caller
- return ss.str();
-}
-
-std::string CronAttr::dump() const
-{
- std::stringstream ss; ss << toString();
- if (makeFree_) ss << " (free)";
- else ss << " (holding)";
- return ss.str();
-}
-
-bool CronAttr::operator==(const CronAttr& rhs) const
-{
- if (makeFree_ != rhs.makeFree_) {
- return false;
- }
-
- if (weekDays_ != rhs.weekDays_) return false;
- if (daysOfMonth_ != rhs.daysOfMonth_) return false;
- if (months_ != rhs.months_) return false;
- return timeSeries_.operator==(rhs.timeSeries_);
-}
-bool CronAttr::structureEquals(const CronAttr& rhs) const
-{
- if (weekDays_ != rhs.weekDays_) return false;
- if (daysOfMonth_ != rhs.daysOfMonth_) return false;
- if (months_ != rhs.months_) return false;
- return timeSeries_.structureEquals(rhs.timeSeries_);
-}
-
-void CronAttr::calendarChanged( const ecf::Calendar& c )
-{
- if ( makeFree_ ) {
- return;
- }
-
- // This assumes that calendarChanged will set TimeSeries::isValid = true, at day change
- if (timeSeries_.calendarChanged(c)) {
- state_change_no_ = Ecf::incr_state_change_no();
- }
-
- // Once a cron is free, it stays free until re-queue
- if (isFree(c)) {
- setFree();
- }
- // A cron is always re-queable, hence we use isFree to control when it can actually run.
-}
-
-void CronAttr::resetRelativeDuration()
-{
- if (timeSeries_.resetRelativeDuration()) {
- state_change_no_ = Ecf::incr_state_change_no();
- }
-}
-
-void CronAttr::setFree() {
- makeFree_ = true;
- state_change_no_ = Ecf::incr_state_change_no();
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "CronAttr::setFree()\n";
-#endif
-}
-
-void CronAttr::clearFree() {
- makeFree_ = false;
- state_change_no_ = Ecf::incr_state_change_no();
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "CronAttr::clearFree()\n";
-#endif
-}
-
-void CronAttr::miss_next_time_slot()
-{
- // A cron attribute with a single time slot is repeated indefinitely hence always re-queues
- timeSeries_.miss_next_time_slot();
- state_change_no_ = Ecf::incr_state_change_no();
-}
-
-// **************************************************************************************
-// FOR DEBUG THIS IS THE MAIN FUNCTION, AS THIS DECIDES WHETHER WE CONTINE OR STOP
-// **************************************************************************************
-bool CronAttr::checkForRequeue( const ecf::Calendar& calendar) const
-{
- // checkForRequeue is called when a task/family has reach the complete state
- // This simple checks if node should be put in re-queued state
- // A cron is always re-queable
-
- // Hence: In order to use this it should be used in conjunction with a
- // with a parent node that has complete expression, (& maybe a dummy task)
- // This will allow its use with a parent repeat somewhere in the hierarchy
- return true;
-}
-
-bool CronAttr::validForHybrid(const ecf::Calendar& calendar) const
-{
- if (timeSeries_.hasIncrement()) {
- if (!months_.empty() ) return false; // relies on day change
- if (!daysOfMonth_.empty() ) return false; // relies on day change
- if (!weekDays_.empty() ) {
- if ( weekDays_.size() != 1) return false; // relies on day change
-
- return ( weekDays_[0] == calendar.day_of_week() );
- }
-
- // cron 10:00 20:00 01:00 // valid for hybrid ?
- return true;
- }
-
- // A time series that does not have an increment runs indefinitely and hence relies on day change
- // cron 23:00
- return false;
-}
-
-bool CronAttr::why(const ecf::Calendar& c, std::string& theReasonWhy) const
-{
- // This will logically AND all the times
- if (isFree(c)) return false;
-
- // We are here because:
- // 1/ Not on a valid time slot in the time series
- // *OR*
- // 2/ Logical *AND* of day of week, day of month, or month returned false
- theReasonWhy += "is cron dependent";
-
- // Lets say that the time series was NOT free.
- // First check if week day, day of month, month, matches
- if ( is_day_of_week_day_of_month_and_month_free(c)) {
-
- if (timeSeries_.is_valid()) {
-
- // This can apply to single and series
- boost::posix_time::time_duration calendar_time = timeSeries_.duration(c);
- if (calendar_time < timeSeries_.start().duration()) {
- timeSeries_.why(c, theReasonWhy);
- return true;
- }
-
- // calendar_time >= timeSeries_.start().duration()
- if (timeSeries_.hasIncrement()) {
- if (calendar_time < timeSeries_.finish().duration()) {
- timeSeries_.why(c, theReasonWhy);
- return true;
- }
- }
- }
- // calendar_time >= timeSeries_.start().duration() && calendar_time >= timeSeries_.finish().duration()
- // past the end of time slot, find next valid date
- }
-
- // take into account, user can use run/force complete to miss time slots
- bool do_a_requeue = timeSeries_.requeueable(c);
- if (do_a_requeue && weekDays_.empty() && daysOfMonth_.empty() && months_.empty()) {
- TimeSlot the_next_time_slot = timeSeries_.compute_next_time_slot(c);
- if (the_next_time_slot.isNULL() ) {
- theReasonWhy += " ( *re-queue* to run at this time ";
- }
- else {
- theReasonWhy += " ( *re-queue* to run at ";
- theReasonWhy += the_next_time_slot.toString() ;
- }
-
- theReasonWhy += ", otherwise next run is at ";
- }
- else {
- theReasonWhy += " ( next run is at ";
- }
-
- // Find the *NEXT* date that matches, and use the first time slot
- boost::gregorian::date the_next_date = next_date(c);
- theReasonWhy += timeSeries_.start().toString();
- theReasonWhy += " ";
- theReasonWhy += to_simple_string( the_next_date );
-
- std::stringstream ss;
- TimeSlot currentTime = TimeSlot(timeSeries_.duration(c));
- ss << ", current time ";
- if (timeSeries_.relative()) ss << "+";
- ss << currentTime.toString() << " " << to_simple_string(c.date()) << " )";
- theReasonWhy += ss.str();
- return true;
-}
-
-void CronAttr::reset(const ecf::Calendar& c)
-{
- clearFree();
- timeSeries_.reset(c);
-}
-
-void CronAttr::requeue(const ecf::Calendar& c, bool reset_next_time_slot)
-{
- clearFree();
- timeSeries_.requeue(c,reset_next_time_slot);
-}
-
-bool CronAttr::isFree(const ecf::Calendar& c) const
-{
- // The FreeDepCmd can be used to free the crons,
- if (makeFree_) {
- return true;
- }
-
- if (!timeSeries_.isFree(c)) return false;
-
- // Ok time series is Free
-
- // ********************************************************************
- // IMPORTANT: when we have multiple week days, days of month and months
- // Then we are *ONLY* free, if *ALL* are free, i.e we need AND behaviour
- // ********************************************************************
- return is_day_of_week_day_of_month_and_month_free(c);
-}
-
-
-bool CronAttr::is_day_of_week_day_of_month_and_month_free( const ecf::Calendar& c) const
-{
- bool the_week_day_matches = weekDays_.empty(); // week day matches if no week days
- bool the_day_of_month_matches = daysOfMonth_.empty(); // day of month if no days of month
- bool the_month_matches = months_.empty(); // month matches if no months
-
- if ( !weekDays_.empty()) the_week_day_matches = week_day_matches(c.day_of_week());
- if ( !daysOfMonth_.empty()) the_day_of_month_matches = day_of_month_matches(c.day_of_month());
- if ( !months_.empty() ) the_month_matches = month_matches(c.month());
-
- return ( the_week_day_matches && the_day_of_month_matches && the_month_matches) ;
-}
-
-bool CronAttr::week_day_matches( int theDayOfWeek ) const
-{
- BOOST_FOREACH(int theWeekDay, weekDays_) {
- if ( theDayOfWeek == theWeekDay) return true;
- }
- return false;
-}
-
-bool CronAttr::day_of_month_matches(int theDayOfMonth) const
-{
- BOOST_FOREACH(int dayOfMonth, daysOfMonth_) {
- if ( theDayOfMonth == dayOfMonth) return true;
- }
- return false;
-}
-
-bool CronAttr::month_matches(int theMonth) const
-{
- BOOST_FOREACH(int month, months_) {
- if ( theMonth == month) return true;
- }
- return false;
-}
-
-//------------------------------------------------------------------
-//int CronAttr::max_month() const {
-// int max = -1;
-// BOOST_FOREACH(int month, months_) {
-// max = std::max(month,max);
-// }
-// return max;
-//}
-
-//int CronAttr::max_day_of_month() const
-//{
-// int max = -1;
-// BOOST_FOREACH(int dayOfMonth, daysOfMonth_) {
-// max = std::max(dayOfMonth,max);
-// }
-// return max;
-//}
-
-//int CronAttr::max_day_of_week() const
-//{
-// int max = -1;
-// BOOST_FOREACH(int theWeekDay, weekDays_) {
-// max = std::max(theWeekDay,max);
-// }
-// return max;
-//}
-
-//-------------------------------------------------------------------------------
-//int CronAttr::min_month() const{
-// int min = std::numeric_limits<int>::max();
-// BOOST_FOREACH(int month, months_) {
-// min = std::min(month,min);
-// }
-// return min;
-//}
-
-//int CronAttr::min_day_of_month() const
-//{
-// int min = std::numeric_limits<int>::max();
-// BOOST_FOREACH(int dayOfMonth, daysOfMonth_) {
-// min = std::min(dayOfMonth,min);
-// }
-// return min;
-//}
-//
-//int CronAttr::min_day_of_week() const
-//{
-// int min = std::numeric_limits<int>::max();
-// BOOST_FOREACH(int theWeekDay, weekDays_) {
-// min = std::min(theWeekDay,min);
-// }
-// return min;
-//}
-//------------------------------------------------------------
-
-
-bool CronAttr::checkInvariants(std::string& errormsg) const
-{
- return timeSeries_.checkInvariants(errormsg);
-}
-
-
-//--------------------------------------------------------------
-
-boost::gregorian::date CronAttr::last_day_of_month(const ecf::Calendar& calendar) const
-{
- boost::gregorian::date todays_date = calendar.date();
- boost::gregorian::date lastdayOfMonth = todays_date.end_of_month();
- boost::gregorian::date_duration one_day(1);
-
-// cout << "CronAttr::last_day_of_month " << calendar.toString() << " \n";
-
- boost::gregorian::date max_date(neg_infin);
- while ( todays_date <= lastdayOfMonth ) {
-
- // deal with case where we have:
- // cron -w 0,1 -m 5,6,7,8
- // Find the last Sunday/Monday for *THIS* month
- for (size_t i = 0; i < weekDays_.size(); ++i) {
- if ( todays_date.day_of_week().as_number() == weekDays_[i] ) {
-// cout << "CronAttr::last_day_of_month ( todays_date.day_of_week().as_number() == weekDays_[i] ) " << weekDays_[i] << "\n";
- if ( todays_date > max_date ) {
- max_date = todays_date;
-// cout << "CronAttr::last_day_of_month max_date = " << to_simple_string(max_date) << "\n";
- }
-
- // The day of week MAY NOT MATCH the day of month
- // deal with case where we have:
- // cron -w 0,1 -d 14,15,16
- // Find the last date for *THIS* month
- for (size_t d = 0; d < daysOfMonth_.size(); ++d) {
- if ( todays_date.day() == daysOfMonth_[d] ) {
-// cout << "CronAttr::last_day_of_month **( todays_date.day() == daysOfMonth_[d] ) " << daysOfMonth_[d] << "\n";
- if ( todays_date > max_date ) {
- max_date = todays_date;
-// cout << "CronAttr::last_day_of_month max_date = " << to_simple_string(max_date) << "\n";
- }
- }
- }
- }
- }
-
- // deal with case where we have:
- // cron -d 14,15,16 -m 5,6,7,8
- // Find the last date for *THIS* month
- for (size_t d = 0; d < daysOfMonth_.size(); ++d) {
- if ( todays_date.day() == daysOfMonth_[d] ) {
-// cout << "CronAttr::last_day_of_month ( todays_date.day() == daysOfMonth_[d] ) " << daysOfMonth_[d] << "\n";
- if ( todays_date > max_date ) {
- max_date = todays_date;
-// cout << "CronAttr::last_day_of_month max_date = " << to_simple_string(max_date) << "\n";
- }
- }
- }
-
- todays_date += one_day;
- }
- return max_date;
-}
-
-boost::gregorian::date CronAttr::next_date(const ecf::Calendar& calendar) const
-{
- // Find the next date that matches, day of week, day of year, and month
- // that is greater than todays date. This *ASSUMES* day of week, day of month,
- // and month is *ANDED* together
-
- boost::gregorian::date_duration one_day(1);
- boost::gregorian::date future_date = calendar.date(); // todays date
- future_date += one_day; // add one day, so its in the future
-
- while ( 1 ) {
-
- bool week_day_matches = weekDays_.empty(); // week day matches if no week days
- bool day_of_month_matches = daysOfMonth_.empty(); // day of month if no days of month
- bool month_matches = months_.empty(); // month matches if no months
-
- // deal with case where we have: cron -w 0,1
- for (size_t i = 0; i < weekDays_.size(); ++i) {
- if ( future_date.day_of_week().as_number() == weekDays_[i] ) {
- week_day_matches = true;
- break;
- }
- }
-
- // deal with case where we have: cron -w 0,1 -d 14,15,16
- for (size_t d = 0; d < daysOfMonth_.size(); ++d) {
- if ( future_date.day() == daysOfMonth_[d] ) {
- day_of_month_matches = true;
- break;
- }
- }
-
- // deal with case where we have: cron -w 0,1 -d 14,15,16 -m 8, 9
- for (size_t m = 0; m < months_.size(); ++m) {
- if ( future_date.month() == months_[m] ) {
- month_matches = true;
- break;
- }
- }
-
- // if it all matches, then return the future day
- if ( week_day_matches && day_of_month_matches && month_matches) {
- break; // return future_date, replaced with break to keep HPUX compiler happy
- // otherwise it complains that return at the end of the function is
- // unreachable
- }
-
- future_date += one_day;
- }
- return future_date; // should never happen, i.e we can find future date that matches
-}
-
-
-//=========================================================================================================
-// code for parsing a cron:
-
-static bool isComment(const std::string& token)
-{
- if (token.find("#") == std::string::npos) return false;
- return true;
-}
-
-static bool isTimeSpec(const std::string& token)
-{
- if (token.find(Str::COLON()) == std::string::npos) return false;
- return true;
-}
-
-static bool isOption(const std::string& token)
-{
- if (token.find("-w") != std::string::npos) return true;
- if (token.find("-d") != std::string::npos) return true;
- if (token.find("-m") != std::string::npos) return true;
- return false;
-}
-
-static std::string nextToken( size_t& index, const std::vector<std::string >& lineTokens)
-{
- assert(index < lineTokens.size());
- index++;
- if (index < lineTokens.size()) {
-#ifdef DEBUG_CRON_PARSING
- cerr << "nextToken lineTokens[" << index << "] = " << lineTokens[index] << "\n";
-#endif
- return lineTokens[index];
- }
-#ifdef DEBUG_CRON_PARSING
- cerr << "nextToken empty \n";
-#endif
- return string();
-}
-
-std::vector<int> extractOption(
- size_t& index,
- const std::vector<std::string >& lineTokens,
- const std::string& option)
-{
- // cron -w 0 -m 5,6,7,8 10:00 20:00 01:00
- assert(index < lineTokens.size());
-
- // Collate the list of integers, these may have been separated by spaces
- // since we stop on option or time spec, the top level code should decrement index
- std::string theIntList;
- while ( index < lineTokens.size() && ( !isOption(lineTokens[index]) || !isTimeSpec(lineTokens[index]) )) {
- string theNextToken = nextToken(index,lineTokens);
- if (theNextToken.empty()) break;
- if (isOption( theNextToken )) break;
- if (isTimeSpec( theNextToken )) break;
- theIntList += theNextToken;
- }
-#ifdef DEBUG_CRON_PARSING
- cerr << "theIntList = " << theIntList << "\n";
-#endif
-
- // should have 0,1,2,3
- std::vector< int > theIntVec;
- char_separator< char > sep( ",", 0, boost::drop_empty_tokens );
- typedef boost::tokenizer< boost::char_separator< char > > tokenizer;
- tokenizer theTokenizer( theIntList, sep );
-
- for (tokenizer::iterator beg = theTokenizer.begin(); beg != theTokenizer.end(); ++beg) {
- string theIntToken = *beg;
- boost::algorithm::trim( theIntToken );
- if ( theIntToken.empty() ) continue;
-
- try {
- int theInt = boost::lexical_cast< int >( theIntToken );
- theIntVec.push_back( theInt );
- }
- catch ( boost::bad_lexical_cast& ) {
- std::stringstream ss; ss << "Invalid cron option: " << option ;
- throw std::runtime_error( ss.str() );
- }
- }
- return theIntVec;
-}
-
-void extractOption(CronAttr& cronAttr, size_t& index, const std::vector<std::string >& lineTokens)
-{
- assert(index < lineTokens.size());
- if (lineTokens[index] == "-w") {
- cronAttr.addWeekDays( extractOption(index, lineTokens, "week days" ) );
- }
- else if (lineTokens[index] == "-d") {
- cronAttr.addDaysOfMonth( extractOption(index, lineTokens, "Days of the month" ) );
- }
- else if (lineTokens[index] == "-m") {
- cronAttr.addMonths( extractOption(index, lineTokens,"Months" ) );
- }
- else throw std::runtime_error( "extractOption: Invalid cron option :" + lineTokens[index] );
-}
-
-void CronAttr::parse( CronAttr& cronAttr, const std::vector<std::string>& lineTokens, size_t index, bool parse_state )
-{
- // cron 23:00 # run every day at 23:00
- // cron 10:00 20:00 01:00 # run every hour between 10am and 8pm
- // cron -w 0,1 10:00 # run every sunday and monday at 10am
- // cron -d 10,11,12 12:00 # run 10th, 11th and 12th of each month at noon
- // cron -m 1,2,3 12:00 # run on Jan,Feb and March every day at noon.
- // cron -w 0 -m 5,6,7,8 10:00 20:00 01:00 # run every sunday, between May-Aug, every hour between 10am and 8pm
-
- // make *sure* a time spec is specified
- bool time_spec_specified = false;
- while (index < lineTokens.size() ) {
-
- std::string token = lineTokens[index];
-#ifdef DEBUG_CRON_PARSING
- cerr << "CronAttr::doParse " << token << "\n";
-#endif
- if (isOption(token)) {
-#ifdef DEBUG_CRON_PARSING
- cerr << "CronAttr::doParse isOption \n";
-#endif
- extractOption(cronAttr,index,lineTokens);
- index--; // since we did a look ahead
- }
- else if (!time_spec_specified && isTimeSpec(token)) {
-#ifdef DEBUG_CRON_PARSING
- cerr << "CronAttr::doParse isTimeSpec \n";
-#endif
- // index is passed by *reference*, and used skip over time series
- cronAttr.addTimeSeries( TimeSeries::create(index,lineTokens, parse_state) );
- time_spec_specified = true;
- if (parse_state) {
- // if index is on the comment, back track, so that we can add cron state( free)
- if (index < lineTokens.size() && lineTokens[index] == "#") {
- index--;
- }
- }
- else break; // need to read state after comment
- }
- else if (isComment(token)) {
- // cron -m 1,2,3 12:00 # free
- if (parse_state && index+1 < lineTokens.size()) {
- if ( lineTokens[index+1] == "free") {
- cronAttr.setFree();
- }
- }
- break;
- }
- index++;
- }
-
- if (!time_spec_specified) {
- throw std::runtime_error( "Invalid cron, no time specified");
- }
-
-#ifdef DEBUG_CRON_PARSING
- cronAttr.print(cerr); cerr <<"\n";
-#endif
-}
-
-CronAttr CronAttr::create(const std::string& cronString)
-{
- std::vector<std::string> lineTokens;
- Str::split(cronString,lineTokens);
-
- CronAttr theCronAttr;
- if ( lineTokens.empty() ) {
- return theCronAttr;
- }
-
- // adjust the index
- size_t index = 0;
- if ( lineTokens[0] == "cron") {
- index = 1;
- }
-
- parse(theCronAttr,lineTokens,index);
- return theCronAttr;
-}
-
-
-}
-
diff --git a/ecflow_4_0_7/ANattr/src/CronAttr.hpp b/ecflow_4_0_7/ANattr/src/CronAttr.hpp
deleted file mode 100644
index 882b3af..0000000
--- a/ecflow_4_0_7/ANattr/src/CronAttr.hpp
+++ /dev/null
@@ -1,140 +0,0 @@
-#ifndef CRONATTR_HPP_
-#define CRONATTR_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #32 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "TimeSeries.hpp"
-#include <boost/serialization/vector.hpp> // no need to include <vector>
-#include <boost/serialization/level.hpp>
-#include <boost/serialization/tracking.hpp>
-
-namespace ecf { class Calendar;} // forward declare class
-
-namespace ecf {
-
-// *****************************************************************
-// A cron attribute with a single time slot is repeated indefinitely
-// ******************************************************************
-// Use compiler , destructor, assignment, copy constructor,
-class CronAttr {
-public:
- CronAttr();
-
- std::ostream& print(std::ostream&) const;
- bool operator==(const CronAttr& rhs) const;
- bool operator<(const CronAttr& rhs) const { return timeSeries_ < rhs.timeSeries_; }
- bool structureEquals(const CronAttr& rhs) const;
-
- void addWeekDays( const std::vector<int>& w);
- void addDaysOfMonth( const std::vector<int>& d);
- void addMonths( const std::vector<int>& m);
-
- void addTimeSeries( const TimeSlot& s, const TimeSlot& f, const TimeSlot& i) { timeSeries_ = TimeSeries(s,f,i);}
- void addTimeSeries( const TimeSeries& ts ) { timeSeries_ = ts;}
- void add_time_series( int h, int m, bool relative = false ) { timeSeries_ = TimeSeries(h,m,relative);}
-
- // Once a cron is free its stays free, until re-queue is called
- void calendarChanged( const ecf::Calendar& c ); // can set attribute free
- void resetRelativeDuration();
-
- void reset(const ecf::Calendar& c);
- void requeue(const ecf::Calendar& c,bool reset_next_time_slot = true);
-
- void miss_next_time_slot();
- void setFree(); // ensures that isFree() always returns true
- bool isSetFree() const { return makeFree_; }
- bool isFree( const ecf::Calendar&) const;
- bool checkForRequeue( const ecf::Calendar&) const;
- bool validForHybrid(const ecf::Calendar&) const;
- bool why(const ecf::Calendar&, std::string& theReasonWhy) const;
-
- // The state_change_no is never reset. Must be incremented if it can affect equality
- // Note: changes in state of timeSeries_, i.e affect the equality operator (used in test)
- // must be captured. i.e things like relative duration & next_time_slot are
- // reported by the Why command, & hence need to be synced.
- unsigned int state_change_no() const { return state_change_no_; }
-
- bool checkInvariants(std::string& errormsg) const;
-
- //Query:
- const TimeSeries& time() const { return timeSeries_;}
- const TimeSeries& time_series() const { return timeSeries_;}
- std::vector<int>::const_iterator week_days_begin() const { return weekDays_.begin();}
- std::vector<int>::const_iterator week_days_end() const { return weekDays_.end(); }
- std::vector<int>::const_iterator days_of_month_begin() const { return daysOfMonth_.begin();}
- std::vector<int>::const_iterator days_of_month_end() const { return daysOfMonth_.end(); }
- std::vector<int>::const_iterator months_begin() const { return months_.begin();}
- std::vector<int>::const_iterator months_end() const { return months_.end(); }
-
- std::string name() const { return toString(); } /* ABO */
- std::string toString() const;
- std::string dump() const;
-
- /// parse the line tokens an create a cron attribute. Can throw std::runtime_error
- /// The index parameter allows us to parse:
- /// cron -w 0,1 10:00 // index = 1
- /// -w 0,1 10:00 // index = 0
- /// Expect to parse:
- /// cron 23:00 # run every day at 23:00
- /// cron 10:00 20:00 01:00 # run every hour between 10am and 8pm
- /// cron -w 0,1 10:00 # run every sunday and monday at 10am
- /// cron -d 10,11,12 12:00 # run 10th, 11th and 12th of each month at noon
- /// cron -m 1,2,3 12:00 # run on Jan,Feb and March every day at noon.
- /// cron -w 0 -m 5,6,7,8 10:00 20:00 01:00 # run every sunday, between May-Aug, every hour between 10am and 8pm
- static void parse( CronAttr&, const std::vector<std::string >& lineTokens, size_t index, bool parse_state = false );
- static CronAttr create(const std::string& cronString);
-
-private:
- void clearFree(); // resets the free flag
- bool is_day_of_week_day_of_month_and_month_free( const ecf::Calendar&) const;
-
- bool week_day_matches(int) const;
- bool day_of_month_matches(int) const;
- bool month_matches(int) const;
-
-// int max_month() const;
-// int max_day_of_month() const;
-// int max_day_of_week() const;
-// int min_month() const;
-// int min_day_of_month() const;
-// int min_day_of_week() const;
-
- boost::gregorian::date last_day_of_month(const ecf::Calendar& calendar) const;
- boost::gregorian::date next_date(const ecf::Calendar& calendar) const;
-
- TimeSeries timeSeries_;
- std::vector<int> weekDays_;
- std::vector<int> daysOfMonth_;
- std::vector<int> months_;
- bool makeFree_; // persisted for use by why() on client side
- unsigned int state_change_no_; // *not* persisted, only used on server side
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/) {
- ar & timeSeries_;
- ar & weekDays_;
- ar & daysOfMonth_;
- ar & months_;
- ar & makeFree_;
- }
-};
-}
-
-// This should ONLY be added to objects that are *NOT* serialised through a pointer
-BOOST_CLASS_IMPLEMENTATION(ecf::CronAttr, boost::serialization::object_serializable);
-BOOST_CLASS_TRACKING(ecf::CronAttr,boost::serialization::track_never);
-
-#endif /* CRONATTR_HPP_ */
diff --git a/ecflow_4_0_7/ANattr/src/DateAttr.cpp b/ecflow_4_0_7/ANattr/src/DateAttr.cpp
deleted file mode 100644
index 5eb7679..0000000
--- a/ecflow_4_0_7/ANattr/src/DateAttr.cpp
+++ /dev/null
@@ -1,293 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #31 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <assert.h>
-#include <sstream>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include "DateAttr.hpp"
-#include "Extract.hpp"
-#include "Indentor.hpp"
-#include "Calendar.hpp"
-#include "PrintStyle.hpp"
-#include "Ecf.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-
-//==========================================================================================
-
-DateAttr::DateAttr( int day, int month, int year )
-: day_( day ), month_( month ), year_( year ), makeFree_( false ), state_change_no_(0)
-{
- checkDate(day_,month_,year_,true /* allow wild cards */);
-}
-
-bool DateAttr::operator<(const DateAttr& rhs) const {
- if (year_ < rhs.year_) return true;
- if (year_ == rhs.year_) {
- if (month_ < rhs.month_ ) return true;
- if (month_ == rhs.month_) {
- return day_ < rhs.day_;
- }
- }
- return false;
-}
-
-void DateAttr::checkDate(int day, int month, int year, bool allow_wild_cards)
-{
- if (allow_wild_cards) {
- if (day != 0 && (day < 1 || day > 31 )) {
- throw std::out_of_range( "Invalid Date(day,month,year) : the day >= 0 and day < 31, where 0 means wild card ");
- }
- if (month !=0 && ( month < 1 || month > 12 )) {
- throw std::out_of_range( "Invalid Date(day,month,year): the month >=0 and month <= 12, where 0 means wild card");
- }
- if (year < 0) {
- throw std::out_of_range( "Invalid Date(day,month,year): the year >=0, where 0 means wild card");
- }
- }
- else {
- if (day < 1 || day > 31 ) {
- throw std::out_of_range( "Invalid date attribute : the day >= 1 and day < 31");
- }
- if (month < 1 || month > 12 ) {
- throw std::out_of_range( "Invalid date attribute: the month >=1 and month <= 12");
- }
- if (year <= 0) {
- throw std::out_of_range( "Invalid date attribute: the year >0");
- }
- }
-
- if ( day != 0 && month != 0 && year != 0 ) {
-
- // let boost validate the date
- boost::gregorian::date theDate( year, month, day );
- }
-}
-
-void DateAttr::calendarChanged( const ecf::Calendar& c )
-{
- if (makeFree_) {
- return;
- }
- else if (isFree(c)) {
- setFree();
- }
-}
-
-void DateAttr::setFree() {
- makeFree_ = true;
- state_change_no_ = Ecf::incr_state_change_no();
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "DateAttr::setFree()\n";
-#endif
-}
-
-void DateAttr::clearFree() {
- makeFree_ = false;
- state_change_no_ = Ecf::incr_state_change_no();
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "DateAttr::clearFree()\n";
-#endif
-}
-
-bool DateAttr::isFree(const ecf::Calendar& calendar) const
-{
- // The FreeDepCmd can be used to free the dates,
- if (makeFree_) {
- return true;
- }
- return is_free(calendar);
-}
-
-bool DateAttr::is_free(const ecf::Calendar& calendar) const
-{
- bool dayMatches = true;
- bool monthMatches = true;
- bool yearMatches = true;
- if (day_ != 0) dayMatches = calendar.day_of_month() == day_;
- if (month_ != 0) monthMatches = calendar.month() == month_;
- if (year_ != 0) yearMatches = calendar.year() == year_;
-
- return ( dayMatches && monthMatches && yearMatches);
-}
-
-bool DateAttr::checkForRequeue( const ecf::Calendar& calendar) const
-{
- // if calendar is hybrid, we can't re-queue
- if (calendar.hybrid()) {
- return false;
- }
-
- // checkForRequeue is called when we are deciding whether to re-queue the node.
- // If this date is in the future, they we should re-queue
- if ( day_ != 0 && month_ != 0 && year_ != 0) {
- date theDate(year_,month_,day_);
- if (theDate > calendar.date()) {
-//#ifdef DEBUG
-// cout << toString() << " > " << " calendar date " << to_simple_string( calendar.date()) << "\n";
-//#endif
- return true;
- }
- return false;
- }
-
- bool futureDayMatches = true;
- bool futureMonthMatches = true;
- bool futureYearMatches = true;
- if (day_ != 0) futureDayMatches = day_ > calendar.day_of_month() ;
- if (month_ != 0) futureMonthMatches = month_ > calendar.month() ;
- if (year_ != 0) futureYearMatches = year_ > calendar.year() ;
-
-//#ifdef DEBUG
-// if ( futureDayMatches ) {
-// cout << "futureDayMatches " << toString() << " > " << calendar.day_of_month() << "\n";
-// }
-// if ( futureMonthMatches ) {
-// cout << "futureMonthMatches " << toString() << " > " << calendar.month() << "\n";
-// }
-// if ( futureYearMatches ) {
-// cout << "futureYearMatches " << toString() << " > " << calendar.year() << "\n";
-// }
-//#endif
-
- return ( futureDayMatches || futureMonthMatches || futureYearMatches);
-}
-
-bool DateAttr::validForHybrid(const ecf::Calendar& calendar) const
-{
- if (day_ == 0) return false; // relies on day change i.e. date *.10.2009
- if (month_ == 0) return false; // relies on day change i.e. date 12.*.2009
- if (year_ == 0) return false; // relies on day change i.e. date 12.10.*
-
- // if the date matches exactly for today
- return (day_ == calendar.day_of_month() && month_ == calendar.month() && year_ == calendar.year() );
-}
-
-bool DateAttr::why(const ecf::Calendar& c, std::string& theReasonWhy) const
-{
- if (isFree(c)) return false;
-
- std::stringstream ss;
- ss << " is date dependent ( next run on " << toString() << " the current date is ";
- ss << c.day_of_month() << "/" << c.month() << "/" << c.year() << " )";
- theReasonWhy += ss.str();
- return true;
-}
-
-std::ostream& DateAttr::print(std::ostream& os) const
-{
- Indentor in;
- Indentor::indent(os) << toString();
- if (!PrintStyle::defsStyle()) {
- if (makeFree_) os << " # free";
- }
- os << "\n";
- return os;
-}
-
-std::string DateAttr::toString() const
-{
- std::stringstream ss;
- ss << "date ";
- if (day_ == 0) ss << "*.";
- else ss << day_ << ".";
-
- if (month_ == 0) ss << "*.";
- else ss << month_ << ".";
-
- if (year_ == 0) ss << "*";
- else ss << year_;
-
- return ss.str();
-}
-
-std::string DateAttr::dump() const
-{
- std::stringstream ss; ss << toString();
- if (makeFree_) ss << " (free)";
- else ss << " (holding)";
- return ss.str();
-}
-
-
-bool DateAttr::operator==(const DateAttr& rhs) const
-{
- if (makeFree_ != rhs.makeFree_) {
- return false;
- }
- return structureEquals(rhs);
-}
-bool DateAttr::structureEquals(const DateAttr& rhs) const
-{
- if (day_ != rhs.day_) return false;
- if (month_ != rhs.month_) return false;
- if (year_ != rhs.year_) return false;
- return true;
-}
-
-DateAttr DateAttr::create(const std::string& dateString)
-{
- int day = -1,month = -1,year = -1;
- getDate(dateString,day,month,year);
- return DateAttr(day,month,year);
-}
-
-void DateAttr::getDate(const std::string& date,int& day,int& month,int& year)
-{
- size_t firstDotPos = date.find_first_of('.');
- size_t lastDotPos = date.find_first_of('.',firstDotPos+1);
- if (firstDotPos == std::string::npos) throw std::runtime_error( "DateAttr::getDate Invalid date missing first dot :" + date );
- if (lastDotPos == std::string::npos) throw std::runtime_error( "DateAttr::getDate: Invalid date missing second dot :" + date );
- if (firstDotPos == lastDotPos) throw std::runtime_error( "DateAttr::getDate: Invalid date :" + date );
-
-
- std::string theDay = date.substr(0,firstDotPos);
- std::string theMonth = date.substr(firstDotPos+1, (lastDotPos-firstDotPos)-1);
- std::string theYear = date.substr(lastDotPos+1);
-
- if (theDay == "*") day = 0;
- else {
- day = Extract::theInt(theDay,"DateAttr::getDate: Invalid day :" + date);
- if (day < 1 || day > 31) throw std::runtime_error("DateAttr::getDate: Invalid clock date: " + date );
- }
-
-
- if (theMonth == "*") month = 0;
- else {
- month = Extract::theInt(theMonth,"DateAttr::getDate: Invalid month :" + date);
- if (month < 1 || month > 12) throw std::runtime_error("DateAttr::getDate Invalid clock date: " + date );
- }
-
- if (theYear == "*") year = 0;
- else year = Extract::theInt(theYear,"DateAttr::getDate: Invalid year :" + date);
-
-
- if (day == -1 || month == -1 || year == -1) throw std::runtime_error("DateAttr::getDate: Invalid clock date:" + date );
-
- // let boost validate the date
- if ( day != 0 && month != 0 && year != 0) {
-
- boost::gregorian::date theDate(year,month,day);
- }
-
-// cerr << " DateParser::getDate date=" << date << " day=" << day << " month=" << month << " year=" << year << "\n";
-}
-
diff --git a/ecflow_4_0_7/ANattr/src/DateAttr.hpp b/ecflow_4_0_7/ANattr/src/DateAttr.hpp
deleted file mode 100644
index db61e05..0000000
--- a/ecflow_4_0_7/ANattr/src/DateAttr.hpp
+++ /dev/null
@@ -1,102 +0,0 @@
-#ifndef DATEATTR_HPP_
-#define DATEATTR_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #24 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Note: calendarChanged() once a Date is free, it stays free
-// It relies on parent cron/repeat to re-queue
-//============================================================================
-
-#include <ostream>
-#include <boost/serialization/serialization.hpp>
-#include <boost/serialization/level.hpp>
-#include <boost/serialization/tracking.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-namespace ecf { class Calendar;} // forward declare class that is in a name space
-
-// Use default copy constructor, assignment operator, destructor
-// Value of 0 for day,month,year means *, i.e. means any value
-class DateAttr {
-public:
- DateAttr(int day, int month, int year); // will throw std::out_of_range for if invalid date
- DateAttr()
- : day_(0), month_(0), year_(0), makeFree_(false),
- state_change_no_(0) {} // for serialisation
- DateAttr(const boost::gregorian::date& date)
- : day_(date.day()), month_(date.month()), year_(date.year()), makeFree_(false),
- state_change_no_(0) {} // for test
-
- std::ostream& print(std::ostream&) const;
- bool operator==(const DateAttr& rhs) const;
- bool operator<(const DateAttr& rhs) const;
- bool structureEquals(const DateAttr& rhs) const;
-
- void setFree(); // ensures that isFree() always returns true
- void clearFree(); // resets the free flag
- bool isSetFree() const { return makeFree_; }
- void calendarChanged( const ecf::Calendar& c ); // can set attribute free
- bool isFree(const ecf::Calendar&) const;
- bool checkForRequeue( const ecf::Calendar&) const;
- bool validForHybrid(const ecf::Calendar&) const;
- bool why(const ecf::Calendar&, std::string& theReasonWhy) const;
-
- // The state_change_no is never reset. Must be incremented if it can affect equality
- unsigned int state_change_no() const { return state_change_no_; }
-
- std::string name() const { return toString(); } /* ABO */
- std::string toString() const;
- std::string dump() const;
-
- /// Check the date, will throw std::out_of_range or derivative if invalid
- static void checkDate(int day, int month, int year, bool allow_wild_cards);
-
- /// Extract the date, if return integer is zero, date was of the *, i.e. any day,month,year
- /// will throw std::runtime_error for parse errors
- /// expect:
- /// 15.11.2009
- /// 15.*.*
- /// *.1.*
- static void getDate(const std::string& date,int& day,int& month,int& year);
- static DateAttr create(const std::string& dateString);
-
- // access
- int day() const { return day_; }
- int month() const { return month_; }
- int year() const { return year_; }
-
-private:
- bool is_free(const ecf::Calendar&) const; // ignores makeFree_
-
-private:
- int day_;
- int month_;
- int year_;
- bool makeFree_; // persisted for use by why() on client side
- unsigned int state_change_no_; // *not* persisted, only used on server side
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/)
- {
- ar & day_;
- ar & month_;
- ar & year_;
- ar & makeFree_;
- }
-};
-
-// This should ONLY be added to objects that are *NOT* serialised through a pointer
-BOOST_CLASS_IMPLEMENTATION(DateAttr, boost::serialization::object_serializable);
-BOOST_CLASS_TRACKING(DateAttr,boost::serialization::track_never);
-
-#endif
diff --git a/ecflow_4_0_7/ANattr/src/DayAttr.cpp b/ecflow_4_0_7/ANattr/src/DayAttr.cpp
deleted file mode 100644
index ce0192c..0000000
--- a/ecflow_4_0_7/ANattr/src/DayAttr.cpp
+++ /dev/null
@@ -1,192 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #32 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <assert.h>
-#include <sstream>
-
-#include "DayAttr.hpp"
-#include "Indentor.hpp"
-#include "Calendar.hpp"
-#include "PrintStyle.hpp"
-#include "Ecf.hpp"
-
-using namespace std;
-using namespace ecf;
-
-//===============================================================================
-
-static std::string theDay(DayAttr::Day_t day)
-{
- switch (day) {
- case DayAttr::SUNDAY: return "sunday"; break;
- case DayAttr::MONDAY: return "monday"; break;
- case DayAttr::TUESDAY: return "tuesday"; break;
- case DayAttr::WEDNESDAY: return "wednesday"; break;
- case DayAttr::THURSDAY: return "thursday"; break;
- case DayAttr::FRIDAY: return "friday"; break;
- case DayAttr::SATURDAY: return "saturday"; break;
- default: assert(false);break;
- }
- return std::string();
-}
-
-//===============================================================================
-
-void DayAttr::calendarChanged( const ecf::Calendar& c )
-{
- if (makeFree_) {
- return;
- }
- else if (isFree(c)) {
- setFree();
- }
-}
-
-bool DayAttr::isFree(const ecf::Calendar& calendar) const
-{
- // The FreeDepCmd can be used to free the dates,
- if (makeFree_) {
- return true;
- }
- return is_free(calendar);
-}
-
-bool DayAttr::is_free(const ecf::Calendar& calendar) const
-{
- return (calendar.day_of_week() == day_);
-}
-
-void DayAttr::setFree() {
- makeFree_ = true;
- state_change_no_ = Ecf::incr_state_change_no();
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "DayAttr::setFree()\n";
-#endif
-}
-
-void DayAttr::clearFree() {
- makeFree_ = false;
- state_change_no_ = Ecf::incr_state_change_no();
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "DayAttr::clearFree()\n";
-#endif
-}
-
-bool DayAttr::checkForRequeue( const ecf::Calendar& calendar) const
-{
- // if calendar is hybrid, we can't requeue
- if (calendar.hybrid()) {
- return false;
- }
-
- // checkForRequeue is called when we are deciding whether to re-queue the node.
- // If this date is in the future, they we should re-queue
- return (day_ > calendar.day_of_week() );
-}
-
-bool DayAttr::validForHybrid(const ecf::Calendar& calendar) const
-{
- return isFree(calendar);
-}
-
-bool DayAttr::why(const ecf::Calendar& c, std::string& theReasonWhy) const
-{
- if (isFree(c)) return false;
-
- theReasonWhy += " is day dependent ( next run on ";
- theReasonWhy += theDay(day_);
- theReasonWhy += " the current day is ";
- theReasonWhy += theDay(static_cast<DayAttr::Day_t>(c.day_of_week()));
- theReasonWhy += " )";
- return true;
-}
-
-std::ostream& DayAttr::print(std::ostream& os) const
-{
- Indentor in;
- Indentor::indent(os) << toString();
- if (!PrintStyle::defsStyle()) {
- if (makeFree_) os << " # free";
- }
- os << "\n";
- return os;
-}
-
-std::string DayAttr::toString() const
-{
- std::string ret = "day ";
- ret += theDay(day_);
- return ret;
-}
-
-std::string DayAttr::dump() const
-{
- std::stringstream ss;
- ss << toString();
- if (makeFree_) ss << " (free)";
- else ss << " (holding)";
- return ss.str();
-}
-
-bool DayAttr::operator==(const DayAttr& rhs) const
-{
- if (makeFree_ != rhs.makeFree_) {
- return false;
- }
- return structureEquals(rhs);
-}
-
-bool DayAttr::structureEquals(const DayAttr& rhs) const
-{
- return (day_ == rhs.day_);
-}
-
-
-DayAttr DayAttr::create(const std::string& dayStr)
-{
- return DayAttr( getDay(dayStr) );
-}
-
-DayAttr::Day_t DayAttr::getDay(const std::string& day)
-{
- if (day == "monday") return DayAttr::MONDAY;
- if (day == "tuesday") return DayAttr::TUESDAY;
- if (day == "wednesday") return DayAttr::WEDNESDAY;
- if (day == "thursday") return DayAttr::THURSDAY;
- if (day == "friday") return DayAttr::FRIDAY;
- if (day == "saturday") return DayAttr::SATURDAY;
- if (day == "sunday") return DayAttr::SUNDAY;
-
- std::stringstream ss;
- ss << "Invalid day(" << day << ") specification expected one of [monday,tuesday,wednesday,thursday,friday,saturday,sunday]: ";
- throw std::runtime_error(ss.str());
-
- return DayAttr::SUNDAY;
-}
-
-std::vector< std::string > DayAttr::allDays() {
- std::vector< std::string > vec;
- vec.reserve( 7 );
- vec.push_back("monday");
- vec.push_back("tuesday");
- vec.push_back("wednesday");
- vec.push_back("thursday");
- vec.push_back("friday");
- vec.push_back("saturday");
- vec.push_back("sunday");
- return vec;
-}
-
diff --git a/ecflow_4_0_7/ANattr/src/DayAttr.hpp b/ecflow_4_0_7/ANattr/src/DayAttr.hpp
deleted file mode 100644
index 38dc408..0000000
--- a/ecflow_4_0_7/ANattr/src/DayAttr.hpp
+++ /dev/null
@@ -1,90 +0,0 @@
-#ifndef DAYATTR_HPP_
-#define DAYATTR_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #27 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Note: calendarChanged() once a day is free, it stays free
-// It relies on parent cron/repeat to re-queue
-//============================================================================
-
-#include <ostream>
-#include <vector>
-#include <string>
-#include <boost/serialization/serialization.hpp>
-#include <boost/serialization/level.hpp>
-#include <boost/serialization/tracking.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-namespace ecf { class Calendar;} // forward declare class that is in a name space
-
-// Use default copy constructor, assignment operator, destructor
-class DayAttr {
-public:
- enum Day_t { SUNDAY=0, MONDAY=1, TUESDAY=2, WEDNESDAY=3, THURSDAY=4, FRIDAY=5, SATURDAY=6 };
- DayAttr() : day_(DayAttr::SUNDAY), makeFree_(false),state_change_no_(0) {}
- DayAttr(Day_t day) : day_(day), makeFree_(false),state_change_no_(0) {}
- DayAttr(const boost::gregorian::date& date)
- : day_(static_cast<DayAttr::Day_t>(date.day_of_week().as_number())), makeFree_(false),state_change_no_(0) {}
-
- std::ostream& print(std::ostream&) const;
- bool operator==(const DayAttr& rhs) const;
- bool operator<(const DayAttr& rhs) const { return day_ < rhs.day_; }
- bool structureEquals(const DayAttr& rhs) const;
-
- void setFree(); // ensures that isFree() always returns true
- void clearFree(); // resets the free flag
- bool isSetFree() const { return makeFree_; }
- void calendarChanged( const ecf::Calendar& c ) ; // can set attribute free
- bool isFree(const ecf::Calendar&) const;
- bool checkForRequeue( const ecf::Calendar&) const;
- bool validForHybrid(const ecf::Calendar&) const;
- bool why(const ecf::Calendar&, std::string& theReasonWhy) const;
-
- // The state_change_no is never reset. Must be incremented if it can affect equality
- unsigned int state_change_no() const { return state_change_no_; }
-
- std::string name() const { return toString(); } /* ABO */
- std::string toString() const;
- std::string dump() const;
-
- // return the days, if input is not valid will throw a runtime_error
- static DayAttr create(const std::string& dayStr);
- static DayAttr::Day_t getDay(const std::string&);
-
- static std::vector<std::string> allDays();
-
- // access
- DayAttr::Day_t day() const { return day_;}
-
-private:
- bool is_free(const ecf::Calendar&) const; // ignores makeFree_
-
-private:
- DayAttr::Day_t day_;
- bool makeFree_; // persisted for use by why() on client side
- unsigned int state_change_no_; // *not* persisted, only used on server side
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/)
- {
- ar & day_;
- ar & makeFree_;
- }
-};
-
-// This should ONLY be added to objects that are *NOT* serialised through a pointer
-BOOST_CLASS_IMPLEMENTATION(DayAttr, boost::serialization::object_serializable);
-BOOST_CLASS_TRACKING(DayAttr,boost::serialization::track_never);
-
-
-#endif
diff --git a/ecflow_4_0_7/ANattr/src/LateAttr.cpp b/ecflow_4_0_7/ANattr/src/LateAttr.cpp
deleted file mode 100644
index 0c97d48..0000000
--- a/ecflow_4_0_7/ANattr/src/LateAttr.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #16 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <sstream>
-#include <boost/foreach.hpp>
-
-#include "LateAttr.hpp"
-#include "Indentor.hpp"
-#include "Calendar.hpp"
-#include "Ecf.hpp"
-#include "PrintStyle.hpp"
-
-using namespace std;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-
-namespace ecf {
-
-LateAttr::LateAttr() : completeIsRelative_(false),isLate_(false),state_change_no_(0) {}
-
-std::ostream& LateAttr::print(std::ostream& os) const
-{
- Indentor in;
- Indentor::indent(os) << toString();
- if (!PrintStyle::defsStyle()) {
- if (isLate_) os << " # late";
- }
- os << "\n";
- return os;
-}
-
-std::string LateAttr::toString() const
-{
- std::string ret = "late";
- if (!submitted_.isNULL()) {
- ret += " -s +";
- ret += submitted_.toString();
- }
- if (!active_.isNULL()) {
- ret += " -a ";
- ret += active_.toString();
- }
- if (!complete_.isNULL()) {
- ret += " -c ";
- if (completeIsRelative_) ret += "+";
- ret += complete_.toString();
- }
- return ret;
-}
-
-bool LateAttr::operator==(const LateAttr& rhs) const
-{
- if ( completeIsRelative_ != rhs.completeIsRelative_) return false;
- if ( submitted_ != rhs.submitted_) return false;
- if ( active_ != rhs.active_) return false;
- if ( complete_ != rhs.complete_) return false;
- if ( isLate_ != rhs.isLate_) return false;
- return true;
-}
-
-bool LateAttr::isNull() const
-{
- return ( submitted_.isNULL() && active_.isNULL() && complete_.isNULL());
-}
-
-void LateAttr::checkForLateness( const std::pair<NState,boost::posix_time::time_duration>& state,
- const ecf::Calendar& calendar )
-{
- if (isLate_ || isNull()) {
- return;
- }
-
- if (state.first == NState::SUBMITTED || state.first == NState::QUEUED) {
- // Submitted is always relative, ASSUME this means relative to suite start
- if (state.first == NState::SUBMITTED && !submitted_.isNULL()) {
- if ( calendar.duration() >= submitted_.duration() ) {
- setLate(true);
- return;
- }
- }
-
- // In Submitted or queued state, check for active, in REAL time
- if (!active_.isNULL() && calendar.suiteTime().time_of_day() >= active_.duration()) {
- setLate(true);
- }
- }
- else if ( state.first == NState::ACTIVE && !complete_.isNULL()) {
- if ( completeIsRelative_) {
- // to check for complete, we need the duration when state went into active state
- // state.second is when state went ACTIVE, relative to suite start
- boost::posix_time::time_duration runtime = calendar.duration() - state.second ;
- if ( runtime >= complete_.duration()) {
- setLate(true);
- }
- }
- else {
- // Real time
- if (calendar.suiteTime().time_of_day() >= complete_.duration()) {
- setLate(true);
- }
- }
- }
-}
-
-void LateAttr::setLate(bool f)
-{
- isLate_ = f;
- state_change_no_ = Ecf::incr_state_change_no();
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "LateAttr::setLate\n";
-#endif
-}
-
-}
diff --git a/ecflow_4_0_7/ANattr/src/LateAttr.hpp b/ecflow_4_0_7/ANattr/src/LateAttr.hpp
deleted file mode 100644
index e9255b0..0000000
--- a/ecflow_4_0_7/ANattr/src/LateAttr.hpp
+++ /dev/null
@@ -1,105 +0,0 @@
-#ifndef LATEATTR_HPP_
-#define LATEATTR_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #13 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include "TimeSlot.hpp"
-#include "NState.hpp"
-
-namespace ecf { class Calendar;} // forward declare class
-
-namespace ecf {
-/// ========================================================================
-/// Use compiler , destructor, assignment, copy constructor,
-///
-/// The late late attribute will not work correctly when the suites clock
-/// start and stops with the server. Since the late relies on real time
-/// for some of its functionality.
-/// -s submitted: The time node can stay submitted (format [+]hh:mm). submitted is always
-/// relative, so + is simple ignored, if present. If the node stays submitted
-/// longer than the time specified, the late flag is set
-/// -a Active : The time of day the node must have become active (format hh:mm). If the node
-/// is still queued or submitted, the late flag is set
-/// -a Complete : The time node must become complete (format {+}hh:mm). If relative, time is
-/// taken form the time the node became actice, otherwise node must be complete by
-/// the time given.
-/// ===========================================================================
-class LateAttr {
-public:
- LateAttr();
-
- std::ostream& print(std::ostream&) const;
- bool operator==(const LateAttr& rhs) const;
-
- void addSubmitted( const TimeSlot& s) { submitted_ = s; }
- void add_submitted(int hour, int minute) { submitted_ = TimeSlot(hour,minute); }
- void addActive( const TimeSlot& s ) { active_ = s; }
- void add_active(int hour, int minute) { active_ = TimeSlot(hour,minute); }
- void addComplete( const TimeSlot& s, bool relative) { complete_ = s; completeIsRelative_ = relative;}
- void add_complete(int hour, int minute,bool relative) { complete_ = TimeSlot(hour,minute); completeIsRelative_ = relative; }
-
- const TimeSlot& submitted() const { return submitted_; }
- const TimeSlot& active() const { return active_; }
- const TimeSlot& complete() const { return complete_; }
- bool complete_is_relative() const { return completeIsRelative_; }
-
- /// i.e no time structs specified
- bool isNull() const;
-
- /// Given the state and time of state change, and calendar work out if we are late
- /// if we are sets the late flag
- void checkForLateness( const std::pair<NState,boost::posix_time::time_duration>& state, const ecf::Calendar& c );
-
- /// To be used by GUI to inform used that a node is late
- bool isLate() const { return isLate_;}
-
- /// To be called at begin and re-queue time
- void reset() { setLate(false); }
-
- // The state_change_no is never reset. Must be incremented if it can affect equality
- unsigned int state_change_no() const { return state_change_no_; }
-
- /// set flag to be late
- void setLate(bool f);
-
- std::string toString() const;
- std::string name() const { return toString(); }
-
-private:
-
- TimeSlot submitted_; // relative by default
- TimeSlot active_;
- TimeSlot complete_;
-
- bool completeIsRelative_;
- bool isLate_;
-
- unsigned int state_change_no_; // *not* persisted, only used on server side
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/) {
- ar & submitted_;
- ar & active_;
- ar & complete_;
- ar & completeIsRelative_;
- ar & isLate_;
- }
-};
-
-}
-#endif
diff --git a/ecflow_4_0_7/ANattr/src/NodeAttr.cpp b/ecflow_4_0_7/ANattr/src/NodeAttr.cpp
deleted file mode 100644
index 606d1b5..0000000
--- a/ecflow_4_0_7/ANattr/src/NodeAttr.cpp
+++ /dev/null
@@ -1,366 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #67 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <assert.h>
-#include <sstream>
-
-#include <boost/foreach.hpp>
-#include <boost/lexical_cast.hpp>
-
-#include "NodeAttr.hpp"
-#include "Indentor.hpp"
-#include "Calendar.hpp"
-#include "PrintStyle.hpp"
-#include "Str.hpp"
-#include "Ecf.hpp"
-
-using namespace std;
-using namespace ecf;
-
-const std::string& Event::SET() { static const std::string SET = "set"; return SET; }
-const std::string& Event::CLEAR() { static const std::string CLEAR = "clear"; return CLEAR; }
-const Event& Event::EMPTY() { static const Event EVENT = Event(); return EVENT ; }
-const Meter& Meter::EMPTY() { static const Meter METER = Meter(); return METER ; }
-const Label& Label::EMPTY() { static const Label LABEL = Label(); return LABEL ; }
-
-////////////////////////////////////////////////////////////////////////////////////////////
-
-Event::Event( int number, const std::string& eventName )
-: value_( false ), number_( number ), name_( eventName ), used_( false ), state_change_no_( 0 )
-{
- if ( !eventName.empty() ) {
- string msg;
- if ( !Str::valid_name( eventName, msg ) ) {
- throw std::runtime_error( "Event::Event: Invalid event name : " + msg );
- }
- }
-}
-
-Event::Event( const std::string& eventName )
-: value_( false ), number_( std::numeric_limits<int>::max() ), name_( eventName ), used_( false ), state_change_no_( 0 )
-{
- if ( eventName.empty() ) {
- throw std::runtime_error( "Event::Event: Invalid event name : name must be specified if no number supplied");
- }
-
- // If the eventName is a integer, then treat it as such, by setting number_ and clearing name_
- // This was added after migration failed, since *python* api allowed:
- // ta.add_event(1);
- // ta.add_event("1");
- // and when we called ecflow_client --migrate/--get it generated
- // event 1
- // event 1
- // which then did *not* load.
- //
- // Test for numeric, and then casting, is ****faster***** than relying on exception alone
- if ( eventName.find_first_of( Str::NUMERIC() ) != std::string::npos ) {
- try {
- number_ = boost::lexical_cast< int >( eventName );
- name_.clear();
- return;
- }
- catch ( boost::bad_lexical_cast& ) {
- // cast failed, a real string, carry on
- }
- }
-
- string msg;
- if ( !Str::valid_name( eventName, msg ) ) {
- throw std::runtime_error( "Event::Event: Invalid event name : " + msg );
- }
-}
-
-void Event::set_value( bool b ) {
- value_ = b;
- state_change_no_ = Ecf::incr_state_change_no();
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Event::set_value\n";
-#endif
-}
-
-std::string Event::name_or_number() const {
- if ( name_.empty() ) {
- std::stringstream ss;
- ss << number_;
- return ss.str();
- }
- return name_;
-}
-
-bool Event::operator==( const Event& rhs ) const {
- if ( value_ != rhs.value_ ) {
- return false;
- }
- if ( number_ != rhs.number_ ) {
- return false;
- }
- if ( name_ != rhs.name_ ) {
- return false;
- }
- return true;
-}
-
-std::ostream& Event::print( std::ostream& os ) const {
- Indentor in;
- Indentor::indent( os ) << toString();
- if ( !PrintStyle::defsStyle() ) {
- if (value_) os << " # " << Event::SET();
- }
- os << "\n";
- return os;
-}
-
-std::string Event::toString() const {
- std::stringstream ss;
- if ( number_ == std::numeric_limits< int >::max() )
- ss << "event " << name_;
- else ss << "event " << number_ << " " << name_;
- return ss.str();
-}
-
-std::string Event::dump() const {
- std::stringstream ss;
- ss << toString() << " value(" << value_ << ") used(" << used_ << ")";
- return ss.str();
-}
-
-bool Event::isValidState( const std::string& state ) {
- if ( state == Event::SET() )
- return true;
- if ( state == Event::CLEAR() )
- return true;
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////
-
-Meter::Meter( const std::string& name, int min, int max, int colorChange ) :
- min_( min ), max_( max ), value_( min ), colorChange_( colorChange ),
- name_( name ), used_( false ), state_change_no_( 0 )
-{
- if ( !Str::valid_name( name ) ) {
- throw std::runtime_error("Meter::Meter: Invalid Meter name: " + name);
- }
-
- if ( min > max )
- throw std::out_of_range( "Meter::Meter: Invalid Meter(name,min,max,color_change) : min must be less than max" );
-
- if (colorChange == std::numeric_limits<int>::max()) {
- colorChange_ = max_;
- }
-
- if ( colorChange_ < min || colorChange_ > max ) {
- std::stringstream ss;
- ss << "Meter::Meter: Invalid Meter(name,min,max,color_change) color_change(" << colorChange_ << ") must be between min(" << min_ << ") and max(" << max_ << ")";
- throw std::out_of_range( ss.str() );
- }
-}
-
-void Meter::set_value( int v ) {
-
- if (!isValidValue( v )) {
- std::stringstream ss;
- ss << "Meter::set_value(int): The meter(" << name_ << ") value must be in the range[" << min() << "-" << max() << "] but found '" << v << "'";
- throw std::runtime_error( ss.str() );
- }
-
- value_ = v;
- state_change_no_ = Ecf::incr_state_change_no();
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Meter::set_value\n";
-#endif
-}
-
-bool Meter::operator==( const Meter& rhs ) const {
- if ( value_ != rhs.value_ ) {
- return false;
- }
- if ( min_ != rhs.min_ ) {
- return false;
- }
- if ( max_ != rhs.max_ ) {
- return false;
- }
- if ( colorChange_ != rhs.colorChange_ ) {
- return false;
- }
- if ( name_ != rhs.name_ ) {
- return false;
- }
- return true;
-}
-
-std::ostream& Meter::print( std::ostream& os ) const {
- Indentor in;
- Indentor::indent( os ) << toString();
- if ( !PrintStyle::defsStyle() ) {
- if (value_ != min_) os << " # " << value_;
- }
- os << "\n";
- return os;
-}
-
-std::string Meter::toString() const {
- std::stringstream ss;
- ss << "meter " << name_ << " " << min_ << " " << max_ << " " << colorChange_;
- return ss.str();
-}
-
-std::string Meter::dump() const {
- std::stringstream ss;
- ss << "meter " << name_ << " min(" << min_ << ") max (" << max_
- << ") colorChange(" << colorChange_ << ") value(" << value_
- << ") used(" << used_ << ")";
- return ss.str();
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////////
-
-Label::Label(const std::string& name, const std::string& l)
-: name_(name),value_(l),state_change_no_(0)
-{
- if ( !Str::valid_name( name ) ) {
- throw std::runtime_error("Label::Label: Invalid Label name :" + name);
- }
-}
-
-
-std::ostream& Label::print( std::ostream& os ) const {
-
- Indentor in;
- Indentor::indent( os ) << toString();
- if (!PrintStyle::defsStyle()) {
- if (!new_value_.empty()) {
- if (new_value_.find("\n") == std::string::npos) {
- os << " # \"" << new_value_ << "\"";
- }
- else {
- std::string value = new_value_;
- Str::replaceall(value,"\n","\\n");
- os << " # \"" << value << "\"";
- }
- }
- }
- os << "\n";
- return os;
-}
-
-std::string Label::toString() const {
- // parsing always STRIPS the quotes, hence add them back
- std::string ret; ret.reserve(name_.size() + value_.size() + 10);
- ret += "label ";
- ret += name_;
- ret += " \"";
- if (value_.find("\n") == std::string::npos) ret += value_;
- else {
- // replace \n, otherwise re-parse will fail
- std::string value = value_;
- Str::replaceall(value,"\n","\\n");
- ret += value;
- }
- ret += "\"";
- return ret;
-}
-
-std::string Label::dump() const {
- std::stringstream ss;
- ss << toString() << " : \"" << new_value_ << "\"";
- return ss.str();
-}
-
-void Label::set_new_value( const std::string& l ) {
- new_value_ = l;
- state_change_no_ = Ecf::incr_state_change_no();
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Label::set_new_value\n";
-#endif
-}
-
-void Label::reset() {
- new_value_.clear();
- state_change_no_ = Ecf::incr_state_change_no();
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Label::reset()\n";
-#endif
-}
-
-
-void Label::parse(const std::string& line, std::vector<std::string >& lineTokens, bool parse_state)
-{
- if ( lineTokens.size() < 3 )
- throw std::runtime_error( "Label::parse: Invalid label :" + line );
-
- name_ = lineTokens[1];
-
- // parsing will always STRIP single or double quotes, print will add double quotes
- // label simple_label 'ecgems'
- if ( lineTokens.size() == 3 ) {
- Str::removeQuotes(lineTokens[2]);
- Str::removeSingleQuotes(lineTokens[2]);
- value_ = lineTokens[2];
- if (value_.find("\\n") != std::string::npos) {
- Str::replaceall(value_,"\\n","\n");
- }
- }
- else {
-
- // label complex_label "smsfetch -F %ECF_FILES% -I %ECF_INCLUDE%" # fred
- // label simple_label "fred" # "smsfetch -F %ECF_FILES% -I %ECF_INCLUDE%"
- std::string value; value.reserve(line.size());
- size_t line_token_size = lineTokens.size();
- for (size_t i = 2; i < line_token_size; ++i) {
- if ( lineTokens[i].at( 0 ) == '#' ) break;
- if ( i != 2 ) value += " ";
- value += lineTokens[i];
- }
-
- Str::removeQuotes(value);
- Str::removeSingleQuotes(value);
- value_ = value;
- if (value_.find("\\n") != std::string::npos) {
- Str::replaceall(value_,"\\n","\n");
- }
-
-
- // state
- if (parse_state) {
- // label name "value" # "new value"
- bool comment_fnd = false;
- size_t first_quote_after_comment = 0;
- size_t last_quote_after_comment = 0;
- for(size_t i = line.size()-1; i > 0; i--) {
- if (line[i] == '#') { comment_fnd = true; break; }
- if (line[i] == '"') {
- if (last_quote_after_comment == 0) last_quote_after_comment = i;
- first_quote_after_comment = i;
- }
- }
- if (comment_fnd && first_quote_after_comment != last_quote_after_comment) {
- std::string new_value = line.substr(first_quote_after_comment+1,last_quote_after_comment-first_quote_after_comment-1);
- //std::cout << "new label = '" << new_value << "'\n";
- new_value_ = new_value;
-
- if (new_value_.find("\\n") != std::string::npos) {
- Str::replaceall(new_value_,"\\n","\n");
- }
- }
- }
- }
-}
-
diff --git a/ecflow_4_0_7/ANattr/src/NodeAttr.hpp b/ecflow_4_0_7/ANattr/src/NodeAttr.hpp
deleted file mode 100644
index f2fe7bf..0000000
--- a/ecflow_4_0_7/ANattr/src/NodeAttr.hpp
+++ /dev/null
@@ -1,211 +0,0 @@
-#ifndef NODEATTR_HPP_
-#define NODEATTR_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #61 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <ostream>
-#include <vector>
-#include <limits> // for std::numeric_limits<int>::max()
-
-#include <boost/operators.hpp>
-#include <boost/utility.hpp>
-
-#include <boost/serialization/serialization.hpp>
-#include <boost/serialization/set.hpp> // no need to include <set>
-#include <boost/serialization/string.hpp> // no need to include <string>
-#include <boost/serialization/level.hpp>
-#include <boost/serialization/tracking.hpp>
-
-////////////////////////////////////////////////////////////////////////////////////////
-// Class Label:
-// Use compiler , generated destructor, assignment, copy constructor
-class Label : public boost::equality_comparable<Label> {
-public:
- Label(const std::string& name, const std::string& l);
- Label() : state_change_no_(0) {}
-
- std::ostream& print(std::ostream&) const;
- const std::string& name() const { return name_;}
- const std::string& value() const { return value_;}
- const std::string& new_value() const { return new_value_;}
- void set_new_value(const std::string& new_label);
- void reset();
- bool empty() const { return name_.empty(); }
-
- // The state_change_no is never reset. Must be incremented if it can affect equality
- unsigned int state_change_no() const { return state_change_no_; }
-
- // 2 kinds of equality, structure and state
- friend bool operator==(const Label& lhs,const Label& rhs) {
- if (lhs.name_ != rhs.name_ ) {
- //std::cout << "lhs.name_ '" << lhs.name_ << "' != rhs.name_ '" << rhs.name_ << "'\n";
- return false;
- }
- if (lhs.new_value_ != rhs.new_value_) {
- //std::cout << "lhs.new_value_ '" << lhs.new_value_ << "' != rhs.new_value_ '" << rhs.new_value_ << "'\n";
- return false;
- }
- if ( lhs.value_ != rhs.value_ ) {
- //std::cout << "lhs.value_ '" << lhs.value_ << "' != rhs.value_ '" << rhs.value_ << "'\n";
- return false;
- }
- return true;
- }
-
- std::string toString() const;
- std::string dump() const;
-
- void parse(const std::string& line, std::vector<std::string >& lineTokens, bool parse_state);
- static const Label& EMPTY(); // Added to support return by reference
-
-private:
- std::string name_;
- std::string value_;
- std::string new_value_;
- unsigned int state_change_no_; // *not* persisted, only used on server side
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/)
- {
- ar & name_;
- ar & value_;
- ar & new_value_;
- }
-};
-
-
-// Class Event:
-// events with the number 007 are the same as 7.
-// Use compiler , generated destructor, assignment, copy constructor
-//
-// Don't use -1, to represent that no number was specified, as on
-// AIX portable binary archive can't cope with this
-// use std::numeric_limits<int>::max()
-class Event {
-public:
- Event(int number, const std::string& eventName = "");
- Event(const std::string& eventName);
- Event()
- : value_(false),
- number_(std::numeric_limits<int>::max()),
- used_(false),
- state_change_no_(0){}
-
- std::string name_or_number() const; // if name present return, else return number
- const std::string& name() const { return name_;}
- std::ostream& print(std::ostream&) const;
- bool value() const { return value_;}
- void reset() { set_value(false);}
- bool empty() const { return (name_.empty() && number_ == std::numeric_limits<int>::max()); }
-
- int number() const { return number_;}
- bool operator==(const Event& rhs) const;
- void set_value(bool b); // updates state_change_no_
- bool usedInTrigger() const { return used_;}
- void usedInTrigger(bool b) { used_ = b;}
-
- unsigned int state_change_no() const { return state_change_no_;}
-
- std::string toString() const;
- std::string dump() const;
-
- static bool isValidState(const std::string&); // return true for "set" | "clear"
- static const std::string& SET();
- static const std::string& CLEAR();
- static const Event& EMPTY(); // Added to support return by reference
-
-private:
- bool value_;
- int number_;
- std::string name_;
- bool used_; // used by the simulator not persisted
- unsigned int state_change_no_; // *not* persisted, only used on server side
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/)
- {
- ar & value_;
- ar & number_;
- ar & name_;
- }
-};
-
-// Class Meter:
-// Use compiler , generated destructor, assignment, copy constructor
-// For this class we don't check the value member for the equality functionality
-// Can have negative min/max however max >= min, and color change should be in the
-// range min-max
-class Meter {
-public:
- Meter(const std::string& name,int min, int max, int colorChange = std::numeric_limits<int>::max());
- Meter() : min_(0),max_(0), value_(0),colorChange_(0),used_(false), state_change_no_(0){}
-
- std::ostream& print(std::ostream&) const;
- void reset() { set_value(min_);}
- void set_value(int v); // can throw throw std::runtime_error if out of range
- bool empty() const { return name_.empty(); }
-
- const std::string& name() const { return name_;}
- int value() const { return value_;}
- int min() const { return min_;}
- int max() const { return max_;}
- int colorChange() const { return colorChange_;}
-
- // The state_change_no is never reset. Must be incremented if it can affect equality
- unsigned int state_change_no() const { return state_change_no_; }
-
- bool operator==(const Meter& rhs) const;
-
- bool usedInTrigger() const { return used_;}
- void usedInTrigger(bool b) { used_ = b;}
- std::string toString() const;
- std::string dump() const;
-
- static const Meter& EMPTY(); // Added to support return by reference
-
-private:
-
- bool isValidValue(int v) const { return (v >= min_ && v <= max_); }
-
- int min_;
- int max_;
- int value_;
- int colorChange_;
- std::string name_;
- bool used_; // used by the simulator not persisted
- unsigned int state_change_no_; // *not* persisted, only used on server side
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/)
- {
- ar & min_;
- ar & max_;
- ar & value_;
- ar & colorChange_;
- ar & name_;
- }
-};
-
-// This should ONLY be added to objects that are *NOT* serialised through a pointer
-BOOST_CLASS_IMPLEMENTATION(Meter, boost::serialization::object_serializable);
-BOOST_CLASS_IMPLEMENTATION(Event, boost::serialization::object_serializable);
-BOOST_CLASS_IMPLEMENTATION(Label, boost::serialization::object_serializable);
-BOOST_CLASS_TRACKING(Meter,boost::serialization::track_never);
-BOOST_CLASS_TRACKING(Event,boost::serialization::track_never);
-BOOST_CLASS_TRACKING(Label,boost::serialization::track_never);
-#endif
diff --git a/ecflow_4_0_7/ANattr/src/RepeatAttr.cpp b/ecflow_4_0_7/ANattr/src/RepeatAttr.cpp
deleted file mode 100644
index 0fdc5d6..0000000
--- a/ecflow_4_0_7/ANattr/src/RepeatAttr.cpp
+++ /dev/null
@@ -1,957 +0,0 @@
-//============================================================================
-// Name : NodeTree.cpp
-// Author : Avi
-// Revision : $Revision: #57 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <assert.h>
-#include <sstream>
-
-#include <boost/foreach.hpp>
-#include <boost/lexical_cast.hpp>
-#include <boost/date_time/posix_time/time_formatters.hpp> // requires boost date and time lib
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include "RepeatAttr.hpp"
-#include "Indentor.hpp"
-#include "Ecf.hpp"
-#include "Log.hpp"
-#include "Str.hpp"
-#include "PrintStyle.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-
-const Repeat& Repeat::EMPTY() { static const Repeat REPEAT = Repeat(); return REPEAT; }
-
-//=========================================================================
-
-Repeat::Repeat() : repeatType_(NULL) {}
-Repeat::Repeat( const RepeatDate& r) : repeatType_(new RepeatDate(r)) {}
-Repeat::Repeat( const RepeatInteger& r) : repeatType_(new RepeatInteger(r)) {}
-Repeat::Repeat( const RepeatEnumerated& r) : repeatType_(new RepeatEnumerated(r)) {}
-Repeat::Repeat( const RepeatString& r) : repeatType_(new RepeatString(r)) {}
-Repeat::Repeat( const RepeatDay& r) : repeatType_(new RepeatDay(r)) {}
-
-Repeat::~Repeat() { delete repeatType_;}
-
-Repeat::Repeat( const Repeat& rhs) : repeatType_(NULL)
-{
- // Do stuff that could throw exception first
- RepeatBase* clone = NULL;
- if ( rhs.repeatType_) {
- clone = rhs.repeatType_->clone();
- }
-
- // Change state
- repeatType_ = clone;
-}
-
-Repeat& Repeat::operator=(const Repeat& rhs)
-{
- // Do stuff that could throw exception first
- RepeatBase* clone = NULL;
- if ( rhs.repeatType_) {
- clone = rhs.repeatType_->clone();
- }
-
- // Change state
- delete repeatType_; repeatType_ = NULL;
- repeatType_ = clone;
-
- return *this;
-}
-
-bool Repeat::operator==(const Repeat& rhs) const
-{
- if (!repeatType_ && rhs.repeatType_) return false;
- if (repeatType_ && !rhs.repeatType_) return false;
- if (!repeatType_ && !rhs.repeatType_) return true ;
- return repeatType_->compare(rhs.repeatType_);
-}
-
-const std::string& Repeat::name() const {
- return (repeatType_) ? repeatType_->name() : Str::EMPTY();
-}
-
-const Variable& Repeat::gen_variable() const
-{
- return (repeatType_) ? repeatType_->gen_variable() : Variable::EMPTY();
-}
-
-void Repeat::update_repeat_genvar() const
-{
- if (repeatType_) {
- // **** reset name since generated variables are not persisted
- repeatType_->set_gen_variable().set_name( repeatType_->name() );
-
- // valueAsString() use the last_valid_value() which should always be in range.
- // Note repeat::value() can be on e past the last valid value, at expiration of Repeat loop
- // However Repeat::last_valid_value() will just return the last valid value.
- repeatType_->set_gen_variable().set_value( repeatType_->valueAsString() );
- }
-}
-
-
-std::ostream& Repeat::print( std::ostream& os ) const {
- if (repeatType_) {
- Indentor in;
- Indentor::indent(os) << toString() << "\n";
- }
- return os;
-}
-
-// =========================================================================
-RepeatBase::~RepeatBase() {}
-
-void RepeatBase::incr_state_change_no()
-{
- state_change_no_ = Ecf::incr_state_change_no();
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "RepeatBase::incr_state_change_no()\n";
-#endif
-}
-
-// =========================================================================
-
-long sms_repeat_julian_to_date(long jdate)
-{
- long x,y,d,m,e;
- long day,month,year;
-
- x = 4 * jdate - 6884477;
- y = (x / 146097) * 100;
- e = x % 146097;
- d = e / 4;
-
- x = 4 * d + 3;
- y = (x / 1461) + y;
- e = x % 1461;
- d = e / 4 + 1;
-
- x = 5 * d - 3;
- m = x / 153 + 1;
- e = x % 153;
- d = e / 5 + 1;
-
- if( m < 11 )
- month = m + 2;
- else
- month = m - 10;
-
-
- day = d;
- year = y + m / 11;
-
- return year * 10000 + month * 100 + day;
-}
-
-long sms_repeat_date_to_julian(long ddate)
-{
- long m1,y1,a,b,c,d,j1;
- long month,day,year;
-
- year = ddate / 10000;
- ddate %= 10000;
- month = ddate / 100;
- ddate %= 100;
- day = ddate;
-
- if (month > 2)
- {
- m1 = month - 3;
- y1 = year;
- }
- else
- {
- m1 = month + 9;
- y1 = year - 1;
- }
- a = 146097*(y1/100)/4;
- d = y1 % 100;
- b = 1461*d/4;
- c = (153*m1+2)/5+day+1721119;
- j1 = a+b+c;
-
- return(j1);
-}
-
-RepeatDate::RepeatDate( const std::string& variable,
- int start,
- int end,
- int delta /* always in days*/
-) : RepeatBase(variable), start_(start), end_(end), delta_(delta), value_(start)
-{
- if ( !Str::valid_name( variable ) ) {
- throw std::runtime_error("RepeatDate::RepeatDate: Invalid name: " + variable);
- }
- if (start > end) {
- std::stringstream ss; ss << "repeat " << variable << " " << start << " " << end << " " << delta;
- throw std::runtime_error("Invalid Repeat date: The end must be greater than the start date" + ss.str());
- }
- std::string theStart = boost::lexical_cast< std::string >(start);
- if (theStart.size() != 8) {
- std::stringstream ss; ss << "repeat " << variable << " " << start << " " << end << " " << delta;
- throw std::runtime_error("Invalid Repeat date: The start is not a valid date. Please use yyyymmdd format." + ss.str());
- }
- std::string theEnd = boost::lexical_cast< std::string >(end);
- if (theEnd.size() != 8) {
- std::stringstream ss; ss << "repeat " << variable << " " << start << " " << end << " " << delta;
- throw std::runtime_error("Invalid Repeat date: The end is not a valid date. Please use yyyymmdd format." + ss.str());
- }
-
- // Use date lib to check YMD
- try {
- boost::gregorian::date(from_undelimited_string(theStart));
- boost::gregorian::date(from_undelimited_string(theEnd));
- }
- catch (std::exception& e) {
- std::stringstream ss; ss << "repeat " << variable << " " << start << " " << end << " " << delta;
- throw std::runtime_error("Invalid Repeat date: The start/end is not a valid date." + ss.str());
- }
-}
-
-bool RepeatDate::compare(RepeatBase* rb) const
-{
- RepeatDate* rhs = dynamic_cast<RepeatDate*>(rb);
- if(!rhs) return false;
- return operator==(*rhs);
-}
-
-void RepeatDate::setToLastValue()
-{
- value_ = end_;
- incr_state_change_no();
-}
-
-long RepeatDate::last_valid_value() const
-{
- if (delta_ > 0) {
- if (value_ < start_) return start_;
- if (value_ > end_) return end_;
- return value_;
- }
- if (value_ > start_) return start_;
- if (value_ < end_) return end_;
- return value_;
-}
-
-long RepeatDate::last_valid_value_minus(int val) const
-{
- long last_value = last_valid_value();
- long julian = sms_repeat_date_to_julian(last_value - val);
- return sms_repeat_julian_to_date(julian);
-}
-
-long RepeatDate::last_valid_value_plus(int val) const
-{
- long last_value = last_valid_value();
- long julian = sms_repeat_date_to_julian(last_value + val);
- return sms_repeat_julian_to_date(julian);
-}
-
-void RepeatDate::reset() {
- value_ = start_;
- incr_state_change_no();
-}
-
-std::string RepeatDate::toString() const
-{
- std::stringstream ss;
- ss << "repeat date " << name_ << " " << start_ << " " << end_ << " " << delta_;
- if (!PrintStyle::defsStyle() && (value_ != start_)) {
- ss << " # " << value_;
- }
- return ss.str();
-}
-std::string RepeatDate::dump() const
-{
- std::stringstream ss;
- ss << toString() << " value(" << value_ << ")";
- return ss.str();
-}
-
-bool RepeatDate::operator==(const RepeatDate& rhs) const
-{
- if (name_ != rhs.name_) {
- return false;
- }
- if (start_ != rhs.start_) {
- return false;
- }
- if (end_ != rhs.end_) {
- return false;
- }
- if (delta_ != rhs.delta_) {
- return false;
- }
- if (value_ != rhs.value_) {
- return false;
- }
- return true;
-}
-
-std::string RepeatDate::valueAsString() const
-{
- /// will throw a boost::bad_lexical_cast& if value is not convertible to a string
- try {
- return boost::lexical_cast< std::string >( last_valid_value() );
- }
- catch ( boost::bad_lexical_cast& ) {
- LOG_ASSERT(false,"RepeatDate::valueAsString(): could not convert value " << value_ << " to a string");
- }
- return string();
-}
-
-std::string RepeatDate::value_as_string(int index) const
-{
- /// will throw a boost::bad_lexical_cast& if value is not convertible to a string
- try {
- return boost::lexical_cast< std::string >( index );
- }
- catch ( boost::bad_lexical_cast& ) {}
- return string();
-}
-
-void RepeatDate::increment()
-{
- long julian = sms_repeat_date_to_julian(value_ + delta_);
- value_ = sms_repeat_julian_to_date(julian);
- incr_state_change_no();
-}
-
-void RepeatDate::change( const std::string& newdate)
-{
- if (newdate.size() != 8) {
- std::stringstream ss;
- ss << "RepeatDate::change: " << toString() << " The new date is not valid, expected 8 characters in yyyymmdd format but found " << newdate;
- throw std::runtime_error(ss.str());
- }
-
- long the_new_date = 0;
- try {
- the_new_date = boost::lexical_cast< long >( newdate );
- }
- catch ( boost::bad_lexical_cast& ) {
- std::stringstream ss;
- ss << "RepeatDate::change: " << toString() << " The new date(" << newdate << ") is not convertible to an long";
- throw std::runtime_error(ss.str());
- }
-
- // Use date lib to check YMD
- try { boost::gregorian::date(from_undelimited_string(newdate));}
- catch (std::exception& e) {
- std::stringstream ss;
- ss << "RepeatDate::change: " << toString() << " The new date(" << newdate << ") is not valid";
- throw std::runtime_error(ss.str());
- }
-
- changeValue(the_new_date);
-}
-
-void RepeatDate::changeValue(long the_new_date)
-{
- if (the_new_date < start_ || the_new_date > end_) {
- std::stringstream ss;
- ss << "RepeatDate::changeValue: " << toString() << "\nThe new date should be in the range[" << start_ << " : " << end_ << "] but found " << the_new_date;
- throw std::runtime_error(ss.str());
- }
- set_value(the_new_date);
-}
-
-void RepeatDate::set_value(long the_new_date)
-{
- // Note: the node is incremented one past, the last value
- // In Node we increment() then check for validity
- // hence the_new_value may be outside of the valid range.
- // This can be seen when do a incremental sync,
- // *hence* allow memento to copy the value as is.
- value_ = the_new_date;
- incr_state_change_no();
-}
-
-//int RepeatDate::length() const
-//{
-// std::string start = boost::lexical_cast<std::string>(start_);
-// std::string end = boost::lexical_cast<std::string>(end_);
-// date startDate(from_undelimited_string(start));
-// date endDate(from_undelimited_string(end));
-// date_period period(startDate,endDate);
-// return ( period.length().days() / delta_);
-//}
-
-//void RepeatDate::truncate(int theLength)
-//{
-// LOG_ASSERT(theLength < length(),"RepeatDate::truncate");
-//// cout << " RepeatDate::truncate by " << theLength << " BEFORE " << toString();
-//
-// long julian = 0;
-// if (delta_ > 0) julian = sms_repeat_date_to_julian(start_ + theLength);
-// else julian = sms_repeat_date_to_julian(start_ - theLength);
-//
-// end_ = sms_repeat_julian_to_date(julian);
-//
-//// cout << " AFTER " << toString() << "\n";
-//}
-
-
-//======================================================================================
-
-RepeatInteger::RepeatInteger( const std::string& variable, int start, int end, int delta ) :
- RepeatBase( variable ), start_( start ), end_( end ), delta_( delta ), value_( start )
-{
-// cout << toString() << "\n";
- if ( !Str::valid_name( variable ) ) {
- throw std::runtime_error("RepeatInteger: Invalid name: " + variable);
- }
-}
-RepeatInteger::RepeatInteger() : start_( 0 ), end_( 0 ), delta_( 0 ), value_( 0 ) {}
-
-bool RepeatInteger::compare(RepeatBase* rb) const
-{
- RepeatInteger* rhs = dynamic_cast<RepeatInteger*>(rb);
- if(!rhs) return false;
- return operator==(*rhs);
-}
-
-void RepeatInteger::reset() {
- value_ = start_;
- incr_state_change_no();
-}
-
-long RepeatInteger::last_valid_value() const
-{
- if (delta_ > 0) {
- if (value_ < start_) return start_;
- if (value_ > end_) return end_;
- return value_;
- }
- if (value_ > start_) return start_;
- if (value_ < end_) return end_;
- return value_;
-}
-
-void RepeatInteger::increment() {
- value_ += delta_;
- incr_state_change_no();
-}
-
-void RepeatInteger::change( const std::string& newValue)
-{
- long the_new_value = 0;
- try {
- the_new_value = boost::lexical_cast< long >( newValue );
- }
- catch ( boost::bad_lexical_cast& ) {
- std::stringstream ss;
- ss << "RepeatInteger::change:" << toString() << " The new value(" << newValue << ") is not convertible to an long";
- throw std::runtime_error( ss.str() );
- }
- changeValue(the_new_value);
-}
-
-void RepeatInteger::changeValue(long the_new_value)
-{
- if (delta_ > 0) {
- if (the_new_value < start_ || the_new_value > end_ ) {
- std::stringstream ss;
- ss << "RepeatInteger::changeValue:" << toString() << ". The new value should be in the range[" << start_ << "-" << end_ << "] but found " << the_new_value;
- throw std::runtime_error(ss.str());
- }
- }
- else {
- if (the_new_value > start_ || the_new_value < end_ ) {
- std::stringstream ss;
- ss << "RepeatInteger::changeValue:" << toString() << ". The new value should be in the range[" << start_ << "-" << end_ << "] but found " << the_new_value;
- throw std::runtime_error(ss.str());
- }
- }
- set_value(the_new_value);
-}
-
-void RepeatInteger::set_value(long the_new_value)
-{
- // To be used by Memento only. as it does no checking
- // Note: the node is incremented one past, the last value
- // In Node we increment() then check for validity
- // hence the_new_value may be outside of the valid range.
- // This can be seen when do a incremental sync,
- // *hence* allow memento to copy the value as is.
- value_ = the_new_value;
- incr_state_change_no();
-}
-
-void RepeatInteger::setToLastValue()
-{
- value_ = end_;
- incr_state_change_no();
-}
-
-std::string RepeatInteger::toString() const
-{
- std::stringstream ss;
- ss << "repeat integer " << name_ << " " << start_ << " " << end_;
- if (delta_ != 1) ss << " " << delta_;
- if (!PrintStyle::defsStyle() && (value_ != start_)) {
- ss << " # " << value_;
- }
- return ss.str();
-}
-std::string RepeatInteger::dump() const
-{
- std::stringstream ss;
- ss << toString() << " value(" << value_ << ")";
- return ss.str();
-}
-
-bool RepeatInteger::operator==(const RepeatInteger& rhs) const
-{
- if (name_ != rhs.name_) {
- return false;
- }
- if (start_ != rhs.start_) {
- return false;
- }
- if (end_ != rhs.end_) {
- return false;
- }
- if (delta_ != rhs.delta_) {
- return false;
- }
- if (value_ != rhs.value_) {
- return false;
- }
- return true;
-}
-
-std::string RepeatInteger::valueAsString() const
-{
- /// will throw a boost::bad_lexical_cast& if value is not convertible to a string
- try {
- return boost::lexical_cast< std::string >( last_valid_value() );
- }
- catch ( boost::bad_lexical_cast& ) { LOG_ASSERT(false,"");}
- return string();
-}
-
-std::string RepeatInteger::value_as_string(int index) const
-{
- /// will throw a boost::bad_lexical_cast& if value is not convertible to a string
- try {
- return boost::lexical_cast< std::string >( index );
- }
- catch ( boost::bad_lexical_cast& ) {}
- return string();
-}
-
-//void RepeatInteger::truncate(int theLength)
-//{
-//// cout << " RepeatInteger::truncate by " << theLength << " BEFORE " << toString();
-//
-// LOG_ASSERT(theLength < length(),"");
-// end_ = start_ + (theLength * delta_);
-//
-//// cout << " AFTER " << toString() << "\n";
-//}
-
-//======================================================================================
-
-RepeatEnumerated::RepeatEnumerated( const std::string& variable, const std::vector<std::string>& theEnums)
-: RepeatBase(variable), theEnums_(theEnums), currentIndex_(0)
-{
- if ( !Str::valid_name( variable ) ) {
- throw std::runtime_error("RepeatEnumerated: Invalid name: " + variable);
- }
-}
-
-int RepeatEnumerated::end() const {
- if ( theEnums_.empty() ) return 0;
- return static_cast<int>(theEnums_.size()-1);
-}
-
-bool RepeatEnumerated::compare(RepeatBase* rb) const
-{
- RepeatEnumerated* rhs = dynamic_cast<RepeatEnumerated*>(rb);
- if(!rhs) return false;
- return operator==(*rhs);
-}
-
-std::string RepeatEnumerated::toString() const
-{
- std::stringstream ss;
- ss << "repeat enumerated " << name_;
- BOOST_FOREACH(const string& s, theEnums_) { ss << " \"" << s << "\""; }
- if (!PrintStyle::defsStyle() && (currentIndex_ != 0)) {
- ss << " # " << currentIndex_;
- }
- return ss.str();
-}
-std::string RepeatEnumerated::dump() const
-{
- std::stringstream ss;
- ss << toString() << " ordinal-value(" << value() << ") value-as-string(" << valueAsString() << ")";
- return ss.str();
-}
-
-void RepeatEnumerated::reset() {
- currentIndex_ = 0;
- incr_state_change_no();
-}
-
-void RepeatEnumerated::increment() {
- currentIndex_++;
- incr_state_change_no();
-}
-
-long RepeatEnumerated::value() const
-{
- if (currentIndex_ >= 0 && currentIndex_ < static_cast<int>(theEnums_.size()) ) {
- try {
- return boost::lexical_cast<int>( theEnums_[currentIndex_] );
- }
- catch ( boost::bad_lexical_cast& ) {
- // Ignore and return currentIndex_
- }
- }
- return currentIndex_;
-}
-
-long RepeatEnumerated::last_valid_value() const
-{
- if (!theEnums_.empty()) {
- if (currentIndex_ < 0) {
- try { return boost::lexical_cast<int>( theEnums_[0] ); }
- catch ( boost::bad_lexical_cast& ) { /* Ignore and return first index */ }
- return 0;
- }
- if (currentIndex_ >= static_cast<int>(theEnums_.size())) {
-
- try { return boost::lexical_cast<int>( theEnums_[theEnums_.size()-1] ); }
- catch ( boost::bad_lexical_cast& ) { /* Ignore and return last index */ }
- return static_cast<long>(theEnums_.size()-1);
- }
-
- // return current value as integer or as index
- return value();
- }
- return 0;
-}
-
-void RepeatEnumerated::setToLastValue()
-{
- currentIndex_ = static_cast< int > ( theEnums_.size() - 1);
- if (currentIndex_ < 0) currentIndex_ = 0;
- incr_state_change_no();
-}
-
-std::string RepeatEnumerated::valueAsString() const
-{
- // This must always return a valid value
- if (!theEnums_.empty()) {
-
- // Returns the last valid value
- if (currentIndex_ < 0)
- return theEnums_[0]; // return first
-
- if (currentIndex_ >= static_cast<int>(theEnums_.size())) {
- return theEnums_[theEnums_.size()-1]; // return last
- }
-
- return theEnums_[currentIndex_];
- }
- return std::string();
-}
-
-std::string RepeatEnumerated::value_as_string(int index) const
-{
- if (index >= 0 && index < static_cast<int>(theEnums_.size())) {
- return theEnums_[index];
- }
- return std::string();
-}
-
-void RepeatEnumerated::change( const std::string& newValue)
-{
- // See if if matches one of the enums
- for(size_t i = 0; i < theEnums_.size(); i++) {
- if ( theEnums_[i] == newValue) {
- currentIndex_ = i;
- incr_state_change_no();
- return;
- }
- }
-
- // If the value is convertible to an integer, treat as an index
- try {
- long the_new_value = boost::lexical_cast< long >( newValue );
- changeValue(the_new_value); // can throw if out of range
- return;
- }
- catch ( boost::bad_lexical_cast& ) {}
-
-
- std::stringstream ss;
- ss << "RepeatEnumerated::change:" << toString() << "\nThe new value " << newValue << " is not a valid index or a member of the enumerated list\n";
- throw std::runtime_error(ss.str());
-}
-
-void RepeatEnumerated::changeValue( long the_new_value)
-{
- if ( the_new_value < 0 || the_new_value >= static_cast<int>(theEnums_.size())) {
- std::stringstream ss;
- ss << "RepeatEnumerated::changeValue:" << toString() << "\nThe new value '" << the_new_value << "' is not a valid index ";
- ss << "expected range[0-" << theEnums_.size()-1 << "] but found '" << the_new_value << "'";
- throw std::runtime_error( ss.str() );
- }
- set_value(the_new_value);
-}
-
-void RepeatEnumerated::set_value(long the_new_value)
-{
- // Note: the node is incremented one past, the last value
- // In Node we increment() then check for validity
- // hence the_new_value may be outside of the valid range.
- // This can be seen when do a incremental sync,
- // *hence* allow memento to copy the value as is.
- currentIndex_ = the_new_value;
- incr_state_change_no();
-}
-
-bool RepeatEnumerated::operator==(const RepeatEnumerated& rhs) const
-{
- if (name_ != rhs.name_) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "RepeatEnumerated::operator==( name_(" << name_ << ") != rhs.name_(" << rhs.name_ << "))\n";
- }
-#endif
- return false;
- }
- if (theEnums_ != rhs.theEnums_) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "RepeatEnumerated::operator==( theEnums_ != rhs.theEnums_ )\n";
- }
-#endif
- return false;
- }
- if (currentIndex_ != rhs.currentIndex_) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "RepeatEnumerated::operator==( currentIndex_(" << currentIndex_ << ") != rhs.currentIndex_(" << rhs.currentIndex_ << "))\n";
- }
-#endif
- return false;
- }
- return true;
-}
-
-//void RepeatEnumerated::truncate(int theLength)
-//{
-//// cout << " RepeatEnumerated::truncate by " << theLength << " BEFORE " << toString();
-//
-// LOG_ASSERT(theLength < length(),"");
-// while ( static_cast<int>(theEnums_.size()) > theLength) {
-// theEnums_.pop_back();
-// }
-//
-//// cout << " AFTER " << toString() << "\n";
-//}
-
-//======================================================================================
-
-RepeatString::RepeatString( const std::string& variable, const std::vector<std::string>& theEnums)
-: RepeatBase(variable), theStrings_(theEnums), currentIndex_(0)
-{
- if ( !Str::valid_name( variable ) ) {
- throw std::runtime_error("RepeatString:: Invalid name: " + variable);
- }
-}
-
-int RepeatString::end() const {
- if ( theStrings_.empty() ) return 0;
- return static_cast<int>(theStrings_.size()-1);
-}
-
-bool RepeatString::compare(RepeatBase* rb) const
-{
- RepeatString* rhs = dynamic_cast<RepeatString*>(rb);
- if(!rhs) return false;
- return operator==(*rhs);
-}
-
-std::string RepeatString::toString() const
-{
- std::stringstream ss;
- ss << "repeat string " << name_;
- BOOST_FOREACH(const string& s, theStrings_) { ss << " \"" << s << "\""; }
- if (!PrintStyle::defsStyle() && (currentIndex_ != 0)) {
- ss << " # " << value();
- }
- return ss.str();
-}
-std::string RepeatString::dump() const
-{
- std::stringstream ss;
- ss << toString() << " ordinal-value(" << value() << ") value-as-string(" << valueAsString() << ")";
- return ss.str();
-}
-
-void RepeatString::reset() {
- currentIndex_ = 0;
- incr_state_change_no();
-}
-
-long RepeatString::last_valid_value() const
-{
- if (!theStrings_.empty()) {
- if (currentIndex_ < 0) return 0;
- if (currentIndex_ >= static_cast<int>(theStrings_.size())) return static_cast<long>(theStrings_.size()-1);
- return currentIndex_;
- }
- return 0;
-}
-
-void RepeatString::increment() {
- currentIndex_++;
- incr_state_change_no();
-}
-
-void RepeatString::setToLastValue() {
- currentIndex_ = static_cast<int>(theStrings_.size()-1);
- if (currentIndex_ < 0) currentIndex_ = 0;
- incr_state_change_no();
-}
-
-std::string RepeatString::valueAsString() const
-{
- if (!theStrings_.empty()) return theStrings_[last_valid_value()];
- return std::string();
-}
-
-std::string RepeatString::value_as_string(int index) const
-{
- if (index >= 0 && index < static_cast<int>(theStrings_.size())) {
- return theStrings_[index];
- }
- return std::string();
-}
-
-void RepeatString::change( const std::string& newValue)
-{
- // See if if matches one of the strings
- for(size_t i = 0; i < theStrings_.size(); i++) {
- if ( theStrings_[i] == newValue) {
- currentIndex_ = i;
- incr_state_change_no();
- return;
- }
- }
-
- // If the value is convertible to an integer, treat as an index
- try {
- long the_new_value = boost::lexical_cast< int >( newValue );
- changeValue(the_new_value);
- return;
- }
- catch ( boost::bad_lexical_cast& ) {}
-
- std::stringstream ss;
- ss << "RepeatString::change: " << toString() << "\nThe new value " << newValue << " is not a valid index or member of the string list";
- throw std::runtime_error(ss.str());
-}
-
-void RepeatString::changeValue( long the_new_value)
-{
- if ( the_new_value < 0 || the_new_value >= static_cast<int>(theStrings_.size())) {
- std::stringstream ss;
- ss << "RepeatString::change: " << toString() << " The new the integer " << the_new_value << " is not a valid index ";
- ss << "expected range[0-" << theStrings_.size()-1 << "]'";
- throw std::runtime_error( ss.str() );
- }
- set_value(the_new_value);
-}
-
-void RepeatString::set_value(long the_new_value)
-{
- // Note: the node is incremented one past, the last value
- // In Node we increment() then check for validity
- // hence the_new_value may be outside of the valid range.
- // This can be seen when do a incremental sync,
- // *hence* allow memento to copy the value as is.
- currentIndex_ = the_new_value;
- incr_state_change_no();
-}
-
-bool RepeatString::operator==(const RepeatString& rhs) const
-{
- if (name_ != rhs.name_) {
- return false;
- }
- if (theStrings_ != rhs.theStrings_) {
- return false;
- }
- if (currentIndex_ != rhs.currentIndex_) {
- return false;
- }
- return true;
-}
-
-//void RepeatString::truncate(int theLength)
-//{
-//// cout << " RepeatString::truncate by " << theLength << " BEFORE " << toString();
-//
-// LOG_ASSERT(theLength < length(),"");
-// while ( static_cast<int>(theStrings_.size()) > theLength) {
-// theStrings_.pop_back();
-// }
-//
-//// cout << " AFTER " << toString() << "\n";
-//}
-
-//=======================================================================================
-
-bool RepeatDay::compare(RepeatBase* rb) const
-{
- RepeatDay* rhs = dynamic_cast<RepeatDay*>(rb);
- if(!rhs) return false;
- return operator==(*rhs);
-}
-
-std::string RepeatDay::toString() const
-{
- std::stringstream ss;
- ss << "repeat day " << step_;
- return ss.str();
-}
-
-std::string RepeatDay::dump() const
-{
- return toString();
-}
-
-bool RepeatDay::operator==(const RepeatDay& rhs) const
-{
- if (step_ != rhs.step_) {
- return false;
- }
- return true;
-}
-
-BOOST_CLASS_EXPORT_IMPLEMENT(RepeatDate);
-BOOST_CLASS_EXPORT_IMPLEMENT(RepeatInteger);
-BOOST_CLASS_EXPORT_IMPLEMENT(RepeatEnumerated);
-BOOST_CLASS_EXPORT_IMPLEMENT(RepeatString);
-BOOST_CLASS_EXPORT_IMPLEMENT(RepeatDay);
diff --git a/ecflow_4_0_7/ANattr/src/RepeatAttr.hpp b/ecflow_4_0_7/ANattr/src/RepeatAttr.hpp
deleted file mode 100644
index 811f85c..0000000
--- a/ecflow_4_0_7/ANattr/src/RepeatAttr.hpp
+++ /dev/null
@@ -1,479 +0,0 @@
-#ifndef REPEATATTR_HPP_
-#define REPEATATTR_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #51 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Repeat Attribute. Please note that for repeat string, enumeration
-// the positional index is used for evaluation.
-//
-// Simulation: Simulation must not affect the real job submission in the server.
-// o Infinite repeats cause problems with simulation, hence we have
-// a mechanism to stop this, when reset is called, via server this is disabled
-// o The other problem is long repeats. The current solution truncates the
-// repeats. However this is not acceptable and has been commented out,
-// until we can find a better way. (i.e need a simulation mode, where
-// we can truncate a length, this would be ignored in the server)
-//============================================================================
-
-#include <ostream>
-#include "boost_archive.hpp" // collates boost archive includes
-
-#include <boost/serialization/base_object.hpp>
-#include <boost/serialization/serialization.hpp>
-#include <boost/serialization/vector.hpp> // no need to include <vector>
-#include <boost/serialization/string.hpp> // no need to include <string>
-#include <boost/serialization/assume_abstract.hpp>
-#include <boost/serialization/export.hpp> // explicit code for exports (place last) , needed for BOOST_CLASS_EXPORT
-
-#include <boost/utility.hpp>
-
-#include "Variable.hpp"
-
-/////////////////////////////////////////////////////////////////////////
-// Node can only have one repeat.
-//
-class RepeatBase {
-public:
- RepeatBase(const std::string& name) : state_change_no_(0), name_(name) {}
- RepeatBase() : state_change_no_(0) {}
- virtual ~RepeatBase();
-
- /// make non virtual so that it can be in-lined. Called millions of times
- const std::string& name() const { return name_; }
- const Variable& gen_variable() const { return var_; }
- Variable& set_gen_variable() const { return var_; }
-
- virtual int start() const = 0;
- virtual int end() const = 0;
- virtual int step() const = 0;
-
- // After Repeat expiration the last call to increment() can cause
- // value to be beyond the last valid value
- // Depending on the kind of repeat the returned can be value or the current index
- // RepeatDate -> value
- // RepeatString -> index into array of strings
- // RepeatInteger -> value
- // RepeatEnumerated -> index | value return value at index if cast-able to integer, otherwise return index ******
- // RepeatDay -> value
- virtual long value() const = 0;
-
- // Depending on the kind of repeat the returned can be value or *current* index
- // RepeatDate -> value
- // RepeatString -> index ( will always return a index)
- // RepeatInteger -> value
- // RepeatEnumerated -> index ( will always return a index)
- // RepeatDay -> value
- virtual long index_or_value() const = 0;
- virtual void increment() = 0;
-
- // returns a value with in the range start/end
- // Hence at Repeat expiration will return value associated with end()
- virtual long last_valid_value() const = 0;
- virtual long last_valid_value_minus(int val) const { return last_valid_value() - val;}
- virtual long last_valid_value_plus(int val) const { return last_valid_value() + val;}
-
- virtual RepeatBase* clone() const = 0;
- virtual bool compare(RepeatBase*) const = 0;
- virtual bool valid() const = 0;
- virtual void setToLastValue() = 0;
- virtual std::string valueAsString() const = 0; // uses last_valid_value
- virtual std::string value_as_string(int index) const = 0;// used in test only
- virtual void reset() = 0;
- virtual void change(const std::string& newValue) = 0; // can throw std::runtime_error
- virtual void changeValue(long newValue) = 0; // can throw std::runtime_error
- virtual void set_value(long new_value_or_index) = 0; // will NOT throw, allows any value
- virtual std::string toString() const = 0;
- virtual std::string dump() const = 0;
-
- unsigned int state_change_no() const { return state_change_no_;}
-
- /// Simulator functions:
- virtual bool isInfinite() const = 0;
- virtual bool makeInfiniteInValid() { return false;}
- // virtual int length() const = 0;
- // virtual void truncate(int length) = 0;
-
-protected:
- void incr_state_change_no();
-
- unsigned int state_change_no_; // *not* persisted, only used on server side
- std::string name_;
- mutable Variable var_; // *not* persisted
-
-private:
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive& ar, const unsigned int /*version*/)
- {
- ar & name_;
- }
-};
-
-///
-/// The date has no meaning in a physical sense, only used as a for loop over dates
-class RepeatDate : public RepeatBase {
-public:
- RepeatDate( const std::string& variable, int start, int end, int delta = 1/* always in days*/);
- RepeatDate() : start_(0), end_(0), delta_(0), value_(0) {}
-
- virtual int start() const { return start_; }
- virtual int end() const { return end_; }
- virtual int step() const { return delta_; }
- virtual long value() const { return value_; }
- virtual long index_or_value() const { return value_;}
- virtual long last_valid_value() const;
- virtual long last_valid_value_minus(int value) const;
- virtual long last_valid_value_plus(int value) const;
-
- void delta(int d) { delta_ = d;}
- bool operator==(const RepeatDate& rhs) const;
-
- virtual RepeatDate* clone() const { return new RepeatDate(name_, start_, end_, delta_, value_) ; }
- virtual bool compare(RepeatBase*) const;
- virtual bool valid() const { return (delta_ > 0) ? ( value_ <= end_) : (value_ >= end_); }
- virtual std::string valueAsString() const;
- virtual std::string value_as_string(int index) const;
- virtual void setToLastValue();
- virtual void reset();
- virtual void increment();
- virtual void change(const std::string& newValue); // can throw std::runtime_error
- virtual void changeValue(long newValue); // can throw std::runtime_error
- virtual void set_value(long newValue); // will NOT throw, allows any value
-
- virtual std::string toString() const;
- virtual std::string dump() const;
-
- /// Simulator functions:
- virtual bool isInfinite() const { return false;}
- // virtual int length() const; // for use by simulator
- // virtual void truncate(int); // for use by simulator
-
-private:
- RepeatDate( const std::string& name, int start, int end, int delta, long value)
- : RepeatBase(name),start_(start),end_(end),delta_(delta),value_(value) {}
-
-private:
- int start_;
- int end_;
- int delta_;
- long value_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/) {
- ar & boost::serialization::base_object<RepeatBase>(*this);
- ar & start_;
- ar & end_;
- ar & delta_;
- ar & value_;
- }
-};
-
-class RepeatInteger : public RepeatBase {
-public:
- RepeatInteger( const std::string& variable, int start, int end, int delta = 1);
- RepeatInteger();
-
- bool operator==(const RepeatInteger& rhs) const;
-
- virtual int start() const { return start_; }
- virtual int end() const { return end_; }
- virtual int step() const { return delta_;}
- virtual long value() const { return value_;}
- virtual long index_or_value() const { return value_;}
- virtual long last_valid_value() const;
-
- virtual RepeatInteger* clone() const { return new RepeatInteger(name_, start_, end_, delta_, value_); }
- virtual bool compare(RepeatBase*) const;
- virtual bool valid() const { return (delta_ > 0) ? ( value_ <= end_) : (value_ >= end_); }
- virtual std::string valueAsString() const;
- virtual std::string value_as_string(int index) const;
- virtual void setToLastValue();
- virtual void reset();
- virtual void increment();
- virtual void change(const std::string& newValue); // can throw std::runtime_error
- virtual void changeValue(long newValue); // can throw std::runtime_error
- virtual void set_value(long newValue); // will NOT throw, allows any value
- virtual std::string toString() const;
- virtual std::string dump() const;
-
- /// Simulator functions:
- virtual bool isInfinite() const { return false;}
- // virtual int length() const { return std::abs( (end_-start_)+1/delta_ ) ;}
- // virtual void truncate(int);
-
-private:
- RepeatInteger( const std::string& name, int start, int end, int delta, long value)
- : RepeatBase(name), start_(start), end_(end), delta_(delta), value_(value) {}
-
-private:
- int start_;
- int end_;
- int delta_;
- long value_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/) {
- ar & boost::serialization::base_object<RepeatBase>(*this);
- ar & start_;
- ar & end_;
- ar & delta_;
- ar & value_;
- }
-};
-
-
-class RepeatEnumerated : public RepeatBase {
-public:
- RepeatEnumerated( const std::string& variable, const std::vector<std::string>& theEnums);
- RepeatEnumerated() : currentIndex_(0) {}
-
- bool operator==(const RepeatEnumerated& rhs) const;
-
- virtual int start() const { return 0; }
- virtual int end() const;
- virtual int step() const { return 1 ;}
- virtual long value() const; // return value at index if cast-able to integer, otherwise return index
- virtual long index_or_value() const { return currentIndex_;}
- virtual long last_valid_value() const;
-
- virtual RepeatBase* clone() const { return new RepeatEnumerated(name_,theEnums_,currentIndex_); }
- virtual bool compare(RepeatBase*) const;
- virtual bool valid() const { return (currentIndex_ >=0 && currentIndex_ < static_cast<int>(theEnums_.size())); }
- virtual std::string valueAsString() const;
- virtual std::string value_as_string(int index) const;
- virtual void setToLastValue();
- virtual void reset();
- virtual void increment();
- virtual void change(const std::string& newValue); // can throw std::runtime_error
- virtual void changeValue(long newValue); // can throw std::runtime_error
- virtual void set_value(long newValue); // will NOT throw, allows any value
- virtual std::string toString() const;
- virtual std::string dump() const;
-
- /// Simulator functions:
- virtual bool isInfinite() const { return false;}
- // virtual int length() const { return static_cast<int>(theEnums_.size());} // for use by simulator
- // virtual void truncate(int); // for use by simulator
-
-private:
- RepeatEnumerated( const std::string& variable, const std::vector<std::string>& theEnums, int index)
- : RepeatBase(variable), theEnums_(theEnums), currentIndex_(index) {}
-
-private:
- std::vector<std::string> theEnums_;
- int currentIndex_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/) {
- ar & boost::serialization::base_object<RepeatBase>(*this);
- ar & theEnums_;
- ar & currentIndex_;
- }
-};
-
-class RepeatString : public RepeatBase {
-public:
- RepeatString( const std::string& variable, const std::vector<std::string>& theEnums);
- RepeatString() : currentIndex_(0) {}
-
- bool operator==(const RepeatString& rhs) const;
-
- virtual int start() const { return 0; }
- virtual int end() const;
- virtual int step() const { return 1;}
- virtual long value() const { return currentIndex_;}
- virtual long index_or_value() const { return currentIndex_;}
- virtual long last_valid_value() const; // returns the index
-
- virtual RepeatBase* clone() const { return new RepeatString(name_,theStrings_,currentIndex_); }
- virtual bool compare(RepeatBase*) const;
- virtual bool valid() const { return (currentIndex_ >=0 && currentIndex_ < static_cast<int>(theStrings_.size())); }
- virtual std::string valueAsString() const;
- virtual std::string value_as_string(int index) const;
- virtual void setToLastValue();
- virtual void reset();
- virtual void increment();
- virtual void change(const std::string& newValue); // can throw std::runtime_error
- virtual void changeValue(long newValue); // can throw std::runtime_error
- virtual void set_value(long newValue); // will NOT throw, allows any value
- virtual std::string toString() const;
- virtual std::string dump() const;
-
- /// Simulator functions:
- virtual bool isInfinite() const { return false;}
- // virtual int length() const { return static_cast<int>(theStrings_.size());}
- // virtual void truncate(int);
-
-private:
- RepeatString( const std::string& variable, const std::vector<std::string>& theEnums, int index)
- : RepeatBase(variable), theStrings_(theEnums), currentIndex_(index) {}
-
-private:
- std::vector<std::string> theStrings_;
- int currentIndex_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/) {
- ar & boost::serialization::base_object<RepeatBase>(*this);
- ar & theStrings_;
- ar & currentIndex_;
- }
-};
-
-/// The current repeat day is not that well defined or deterministic.
-/// **** Currently I have not come across any suites that use an end-date ****
-/// o If the suite has defined a real clock
-/// then number of repeats is deterministic
-/// However if the end-date is less than suite clock this should be reported as error
-/// o Currently under the hybrid clock the date is not updated, this raises
-/// a whole lot of issues. (We don't wont a separate calendar, just for this).
-/// o If there is _no_ suite clock, then we must use the current day
-/// now the number of repeats varies, and if end-date is less than the current
-/// day we need to report an error
-/// Its not clear what behaviour is required here, hence I will not implement
-/// the end-date functionality. Until there is clear requirement is this area.
-/// end-date will be treated as a parser error.
-/// The minimum deterministic functionality here is to implement the infinite
-/// repeat that has no end date
-///
-/// RepeatDay do not really have a name: However we need maintain invariant that all NON-empty repeats
-/// have a name. Hence the name will be as day
-/// Note: this applies to the clone as well
-class RepeatDay : public RepeatBase {
-public:
- RepeatDay( int step ) : RepeatBase("day"), step_(step),valid_(true) {}
- RepeatDay() : step_(1),valid_(true) {}
-
- bool operator==(const RepeatDay& rhs) const;
-
- virtual int start() const { return 0; }
- virtual int end() const { return 0; }
- virtual int step() const { return step_;}
- virtual void increment() { /* do nothing */ }
- virtual long value() const { return step_;}
- virtual long index_or_value() const { return step_;}
- virtual long last_valid_value() const { return step_;}
-
- virtual RepeatBase* clone() const { return new RepeatDay(step_,valid_); }
- virtual bool compare(RepeatBase*) const;
- virtual bool valid() const { return valid_;}
- virtual std::string valueAsString() const { return std::string(); } ;
- virtual std::string value_as_string(int index) const { return std::string(); }
- virtual void setToLastValue() { /* do nothing ?? */ }
- virtual void reset() { valid_ = true; }
- virtual void change(const std::string& /*newValue*/) { /* do nothing */ }
- virtual void changeValue( long /*newValue*/) { /* do nothing */ }
- virtual void set_value(long /*newValue*/) { /* do nothing */ }
- virtual std::string toString() const;
- virtual std::string dump() const;
-
- /// Simulator functions:
- virtual bool isInfinite() const { return true;}
- virtual bool makeInfiniteInValid() { valid_ = false; return true;}
- // virtual int length() const { return 0;} // because its infinite for use by simulator
- // virtual void truncate(int) {}
-
-private:
- RepeatDay( int step, bool valid) : RepeatBase("day"), step_(step),valid_(valid) {}
-
-private:
- int step_;
- bool valid_; // not persisted since only used in simulator
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/) {
- ar & boost::serialization::base_object<RepeatBase>(*this);
- ar & step_;
- }
-};
-
-class Repeat {
-public:
- Repeat(); // for serialisation
- Repeat( const RepeatDate& );
- Repeat( const RepeatInteger& );
- Repeat( const RepeatEnumerated& );
- Repeat( const RepeatString& );
- Repeat( const RepeatDay& );
- Repeat( const Repeat& );
- ~Repeat();
- Repeat& operator=(const Repeat& rhs);
- bool operator==(const Repeat& rhs) const;
-
- bool empty() const { return (repeatType_) ? false : true; }
- void clear() { delete repeatType_; repeatType_ = 0;}
-
- const std::string& name() const;
- const Variable& gen_variable() const;
- void update_repeat_genvar() const;
-
- int start() const { return (repeatType_) ? repeatType_->start() : 0;}
- int end() const { return (repeatType_) ? repeatType_->end() : 0;}
- int step() const { return (repeatType_) ? repeatType_->step() : 0;}
- long value() const { return (repeatType_) ? repeatType_->value() : 0;}
- long index_or_value() const { return (repeatType_) ? repeatType_->index_or_value() : 0;}
- long last_valid_value() const { return (repeatType_) ? repeatType_->last_valid_value() : 0;}
- long last_valid_value_minus(int val) const { return (repeatType_) ? repeatType_->last_valid_value_minus(val) : -val;}
- long last_valid_value_plus(int val) const { return (repeatType_) ? repeatType_->last_valid_value_plus(val) : val;}
-
- std::ostream& print(std::ostream& os) const;
- bool valid() const { return (repeatType_) ? repeatType_->valid() : false;}
- void setToLastValue() { if (repeatType_) repeatType_->setToLastValue() ; }
- std::string valueAsString() const { return (repeatType_) ? repeatType_->valueAsString() : std::string(); }
- std::string value_as_string(int index) const { return (repeatType_) ? repeatType_->value_as_string(index) : std::string(); }
- void reset() { if (repeatType_) repeatType_->reset();}
- void increment() { if (repeatType_) repeatType_->increment();}
- void change( const std::string& newValue ) { if (repeatType_) repeatType_->change(newValue); }
- void changeValue( long newValue ) { if (repeatType_) repeatType_->changeValue(newValue); }
- void set_value( long newValue ) { if (repeatType_) repeatType_->set_value(newValue); }
- std::string toString() const { return (repeatType_) ? repeatType_->toString() : std::string();}
- std::string dump() const { return (repeatType_) ? repeatType_->dump() : std::string();} // additional state
- unsigned int state_change_no() const { return (repeatType_) ? repeatType_->state_change_no() : 0; }
-
- /// simulator functions: Note: any flags set by makeInfiniteInValid() are reset by reset()
- bool isInfinite() const { return (repeatType_) ? repeatType_->isInfinite() : false;}
- bool makeInfiniteInValid() { return (repeatType_) ? repeatType_->makeInfiniteInValid() : false; } // for simulator only
- // int length() const { return (repeatType_) ? repeatType_->length() : 0;} // for simulator only
- // void truncate(int length) { if (repeatType_) repeatType_->truncate(length);} // for simulator only
-
- // Allows Repeat's to be returned by reference
- static const Repeat& EMPTY();
-
- /// Expose base for the GUI only, use with caution
- RepeatBase* repeatBase() const { return repeatType_;}
-
-private:
- RepeatBase* repeatType_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/) {
- ar & repeatType_;
- }
-};
-
-BOOST_CLASS_EXPORT_KEY(RepeatDate)
-BOOST_CLASS_EXPORT_KEY(RepeatInteger)
-BOOST_CLASS_EXPORT_KEY(RepeatEnumerated)
-BOOST_CLASS_EXPORT_KEY(RepeatString)
-BOOST_CLASS_EXPORT_KEY(RepeatDay)
-
-// This should ONLY be added to objects that are *NOT* serialised through a pointer
-BOOST_CLASS_IMPLEMENTATION(Repeat, boost::serialization::object_serializable)
-BOOST_CLASS_TRACKING(Repeat,boost::serialization::track_never);
-
-#endif
diff --git a/ecflow_4_0_7/ANattr/src/TimeAttr.cpp b/ecflow_4_0_7/ANattr/src/TimeAttr.cpp
deleted file mode 100644
index 65ffac8..0000000
--- a/ecflow_4_0_7/ANattr/src/TimeAttr.cpp
+++ /dev/null
@@ -1,188 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #40 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <sstream>
-
-#include "TimeAttr.hpp"
-#include "Indentor.hpp"
-#include "Calendar.hpp"
-#include "PrintStyle.hpp"
-#include "Ecf.hpp"
-
-namespace ecf {
-
-void TimeAttr::calendarChanged( const ecf::Calendar& c )
-{
- if ( makeFree_ ) {
- return;
- }
-
- if (timeSeries_.calendarChanged(c)) {
- state_change_no_ = Ecf::incr_state_change_no();
- }
-
- // For a time series, we rely on the re queue to reset makeFree
- if (isFree(c)) {
- setFree();
- }
-}
-
-void TimeAttr::resetRelativeDuration()
-{
- if (timeSeries_.resetRelativeDuration()) {
- state_change_no_ = Ecf::incr_state_change_no();
- }
-}
-
-std::ostream& TimeAttr::print(std::ostream& os) const
-{
- Indentor in;
- Indentor::indent(os) << toString();
- if (!PrintStyle::defsStyle()) {
- os << timeSeries_.state_to_string(makeFree_);
- }
- os << "\n";
- return os;
-}
-
-std::string TimeAttr::toString() const
-{
- std::string ret = "time ";
- ret += timeSeries_.toString();
- return ret;
-}
-
-std::string TimeAttr::dump() const
-{
- std::stringstream ss;
- ss << "time ";
-
- if (makeFree_) ss << "(free) ";
- else ss << "(holding) ";
-
- ss << timeSeries_.dump();
-
- return ss.str();
-}
-
-bool TimeAttr::operator==(const TimeAttr& rhs) const
-{
- if (makeFree_ != rhs.makeFree_) {
- return false;
- }
- return timeSeries_.operator==(rhs.timeSeries_);
-}
-
-bool TimeAttr::structureEquals(const TimeAttr& rhs) const
-{
- return timeSeries_.structureEquals(rhs.timeSeries_);
-}
-
-bool TimeAttr::isFree(const ecf::Calendar& calendar) const
-{
- // The FreeDepCmd can be used to free the time,
- if (makeFree_) {
- return true;
- }
- return is_free(calendar);
-}
-
-bool TimeAttr::is_free(const ecf::Calendar& calendar) const
-{
- return timeSeries_.isFree(calendar);
-}
-
-void TimeAttr::setFree() {
- makeFree_ = true;
- state_change_no_ = Ecf::incr_state_change_no();
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "TimeAttr::setFree()\n";
-#endif
-}
-
-void TimeAttr::clearFree() {
- makeFree_ = false;
- state_change_no_ = Ecf::incr_state_change_no();
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "TimeAttr::clearFree()\n";
-#endif
-}
-
-void TimeAttr::miss_next_time_slot()
-{
- timeSeries_.miss_next_time_slot();
- state_change_no_ = Ecf::incr_state_change_no();
-}
-
-
-bool TimeAttr::why(const ecf::Calendar& c, std::string& theReasonWhy) const
-{
- if (isFree(c)) return false;
- theReasonWhy += "is time dependent";
-
- // Check to see if time has expired, if has not, then report why
- if (timeSeries_.is_valid()) {
- // This can apply to single and series
- boost::posix_time::time_duration calendar_time = timeSeries_.duration(c);
- if (calendar_time < timeSeries_.start().duration()) {
- timeSeries_.why(c, theReasonWhy);
- return true;
- }
-
- // calendar_time >= timeSeries_.start().duration()
- if (timeSeries_.hasIncrement()) {
- if (calendar_time < timeSeries_.finish().duration()) {
- timeSeries_.why(c, theReasonWhy);
- return true;
- }
- }
- // calendar_time >= timeSeries_.start().duration() && calendar_time >= timeSeries_.finish().duration()
- // past the end of time slot, hence this should not hold job generation,
- }
-
- // the time has expired
- theReasonWhy += " ( '";
- theReasonWhy += toString();
- theReasonWhy += "' has expired,";
-
- // take into account, user can use run/force complete to miss time slots
- bool do_a_requeue = timeSeries_.requeueable(c);
- if (do_a_requeue) {
- TimeSlot the_next_time_slot = timeSeries_.compute_next_time_slot(c);
- if (the_next_time_slot.isNULL() || !timeSeries_.hasIncrement() ) {
- theReasonWhy += " *re-queue* to run at this time";
- }
- else {
- theReasonWhy += " *re-queue* to run at ";
- theReasonWhy += the_next_time_slot.toString() ;
- }
- }
- else {
- boost::gregorian::date_duration one_day(1);
- boost::gregorian::date the_next_date = c.date(); // todays date
- the_next_date += one_day; // add one day, so its in the future
-
- theReasonWhy += " next run tomorrow at ";
- theReasonWhy += timeSeries_.start().toString();
- theReasonWhy += " ";
- theReasonWhy += to_simple_string( the_next_date );
- }
- theReasonWhy += " )";
-
- return true;
-}
-}
diff --git a/ecflow_4_0_7/ANattr/src/TimeAttr.hpp b/ecflow_4_0_7/ANattr/src/TimeAttr.hpp
deleted file mode 100644
index 165a740..0000000
--- a/ecflow_4_0_7/ANattr/src/TimeAttr.hpp
+++ /dev/null
@@ -1,134 +0,0 @@
-#ifndef TIMEATTR_HPP_
-#define TIMEATTR_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #32 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//
-/// isFree is called when a node is queued.If it returns true, Task can be submitted
-/// checkForReque: is called when a node has completed, and need to determine if it should run again.
-/// These are different/orthogonal concerns.
-/// There is a *separate* issue of whether nodes should be queued when a node is *manually*
-/// a/ Set complete
-/// b/ Runs and then completes
-///
-/// For a *single* time slot we can't requeue.
-/// Hence we checkForReque that takes as parameters max/min time slots, so we **treat**
-/// Multiple single slot as a series.
-///
-/// isFree:hhhhhhhhhhhhhhhhh
-/// Begin:
-/// V
-///checkForReque:rrrrrrrrrrrrrrrrhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh 10:00
-///checkForReque:rrrrrrrrrrrrrrrrrrrrrrrrrrrrrhhhhhhhhhhhhhhhhhhhhhhh 11:00
-///checkForReque:rrrrrrrrrrrrrrrrrrrrrrrrrrrrrhhhhhhhhhhhhhhhhhhhhhhh for both 10:00 and 11:000 together
-/// isFree:hhhhhhhhhhhhhhhhffffffffffffffffffffffffffffffffffff *once* free we stay free (single slot *only*)
-/// begin : | |
-/// V | |
-/// Time ======================0============0==============0=============
-/// 10:00 11:00 Midnight
-//
-/// isFree:hhhhhhhhhhhhhhhhhh
-/// V
-/// CheckForReque:rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
-/// isFree:hhhhhhhFhhhhFhhhhFhhhhFhhhhFhhhhFhhhhhhhhhhhhhhhhhhhhhhhhhhhh
-/// V | | | | | | |
-/// Time ================o====|====|====|====|====0========0====================
-/// 10:00 1 2 3 4 15:00 Midnight
-///
-/// If the job starts at 10:00 but takes more than 1 hour, then it will miss the 11:00 slot
-/// and will have to start at 12:00
-//============================================================================
-#include <boost/serialization/tracking.hpp>
-#include <boost/serialization/level.hpp>
-#include "TimeSeries.hpp"
-
-namespace ecf { class Calendar;} // forward declare class
-
-namespace ecf {
-
-// Use compiler , destructor, assignment, copy constructor,
-class TimeAttr {
-public:
- TimeAttr() : makeFree_(false), state_change_no_(0) {}
- TimeAttr(int hour, int minute, bool relative = false )
- : timeSeries_(hour, minute,relative), makeFree_(false),state_change_no_(0) {}
- TimeAttr(const TimeSlot& t, bool relative = false )
- : timeSeries_(t,relative), makeFree_(false),state_change_no_(0) {}
- TimeAttr(const TimeSeries& ts)
- : timeSeries_(ts), makeFree_(false),state_change_no_(0) {}
- TimeAttr(const TimeSlot& start, const TimeSlot& finish, const TimeSlot& incr, bool relative = false)
- : timeSeries_(start,finish,incr,relative), makeFree_(false),state_change_no_(0) {}
-
- std::ostream& print(std::ostream&) const;
- bool operator==(const TimeAttr& rhs) const;
- bool operator<(const TimeAttr& rhs) const { return timeSeries_ < rhs.timeSeries_; }
- bool structureEquals(const TimeAttr& rhs) const;
-
- /// This can set attribute as free, once free its stays free, until re-queue/reset
- void calendarChanged( const ecf::Calendar& c ); // can set attribute free
- void resetRelativeDuration();
-
- void reset(const ecf::Calendar& c)
- { clearFree(); timeSeries_.reset(c); } // updates state_change_no_
- void requeue(const ecf::Calendar& c,bool reset_next_time_slot = true)
- { clearFree(); timeSeries_.requeue(c,reset_next_time_slot);} // updates state_change_no_
-
- void miss_next_time_slot(); // updates state_change_no_
- void setFree(); // ensures that isFree() always returns true, updates state_change_no_
- bool isSetFree() const { return makeFree_; }
- bool isFree(const ecf::Calendar&) const;
- bool checkForRequeue( const ecf::Calendar& c,const TimeSlot& the_min,const TimeSlot& the_max) const
- { return timeSeries_.checkForRequeue(c,the_min,the_max);}
- void min_max_time_slots(TimeSlot& the_min, TimeSlot& the_max) const {timeSeries_.min_max_time_slots(the_min,the_max);}
- bool why(const ecf::Calendar&, std::string& theReasonWhy) const;
-
- bool checkInvariants(std::string& errormsg) const { return timeSeries_.checkInvariants(errormsg);}
-
- // The state_change_no is never reset. Must be incremented if it can affect equality
- // Note: changes in state of timeSeries_, i.e affect the equality operator (used in test)
- // must be captured. i.e things like relative duration & next_time_slot are
- // reported by the Why command, & hence need to be synced.
- unsigned int state_change_no() const { return state_change_no_; }
-
- std::string name() const { return toString(); } /* ABO */
- std::string toString() const;
- std::string dump() const;
-
- // access
- const TimeSeries& time_series() const { return timeSeries_; }
-
-private:
- void clearFree(); // resets the free flag, updates state_change_no_
- bool is_free(const ecf::Calendar&) const; // ignores makeFree_
-
-private:
- TimeSeries timeSeries_;
- bool makeFree_;
- unsigned int state_change_no_; // *not* persisted, only used on server side
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/)
- {
- ar & timeSeries_;
- ar & makeFree_; // Only persisted for testing, see usage of isSetFree()
- }
-};
-
-}
-
-// This should ONLY be added to objects that are *NOT* serialised through a pointer
-BOOST_CLASS_IMPLEMENTATION(ecf::TimeAttr, boost::serialization::object_serializable);
-BOOST_CLASS_TRACKING(ecf::TimeAttr,boost::serialization::track_never);
-
-#endif
diff --git a/ecflow_4_0_7/ANattr/src/TodayAttr.cpp b/ecflow_4_0_7/ANattr/src/TodayAttr.cpp
deleted file mode 100644
index e75a26b..0000000
--- a/ecflow_4_0_7/ANattr/src/TodayAttr.cpp
+++ /dev/null
@@ -1,193 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #38 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <sstream>
-
-#include "TodayAttr.hpp"
-#include "Calendar.hpp"
-#include "Indentor.hpp"
-#include "Log.hpp"
-#include "PrintStyle.hpp"
-#include "Ecf.hpp"
-
-using namespace std;
-
-namespace ecf {
-
-std::ostream& TodayAttr::print(std::ostream& os) const
-{
- Indentor in;
- Indentor::indent(os) << toString();
- if (!PrintStyle::defsStyle()) {
- os << timeSeries_.state_to_string(makeFree_);
- }
- os << "\n";
- return os;
-}
-
-std::string TodayAttr::toString() const
-{
- std::string ret = "today ";
- ret += timeSeries_.toString();
- return ret;
-}
-
-std::string TodayAttr::dump() const
-{
- std::stringstream ss;
- ss << "today ";
-
- if (PrintStyle::getStyle() == PrintStyle::STATE) {
- if (makeFree_) ss << "(free) ";
- else ss << "(holding) ";
- }
-
- ss << timeSeries_.toString();
-
- return ss.str();
-}
-
-bool TodayAttr::operator==(const TodayAttr& rhs) const
-{
- if (makeFree_ != rhs.makeFree_) {
- return false;
- }
- return timeSeries_.operator==(rhs.timeSeries_);
-}
-
-bool TodayAttr::structureEquals(const TodayAttr& rhs) const
-{
- return timeSeries_.structureEquals(rhs.timeSeries_);
-}
-
-void TodayAttr::miss_next_time_slot()
-{
- timeSeries_.miss_next_time_slot();
- state_change_no_ = Ecf::incr_state_change_no();
-}
-
-void TodayAttr::setFree()
-{
- makeFree_ = true;
- state_change_no_ = Ecf::incr_state_change_no();
-}
-
-void TodayAttr::clearFree() {
- makeFree_ = false;
- state_change_no_ = Ecf::incr_state_change_no();
-}
-
-void TodayAttr::calendarChanged( const ecf::Calendar& c )
-{
- if ( makeFree_ ) {
- return;
- }
-
- if (timeSeries_.calendarChanged(c)) {
- state_change_no_ = Ecf::incr_state_change_no();
- }
-
- // For a time series, we rely on the re queue to reset makeFree
- if (isFree(c)) {
- setFree();
- }
-}
-
-void TodayAttr::resetRelativeDuration() {
- if (timeSeries_.resetRelativeDuration()) {
- state_change_no_ = Ecf::incr_state_change_no();
- }
-}
-
-bool TodayAttr::isFree(const ecf::Calendar& calendar) const
-{
- // The FreeDepCmd can be used to free the today,
- if (makeFree_) {
-// LOG(Log::DBG," TodayAttr::isFree makeFree_");
- return true;
- }
- return is_free(calendar);
-}
-
-bool TodayAttr::is_free(const ecf::Calendar& calendar) const
-{
- if (!timeSeries_.hasIncrement()) {
- if (timeSeries_.duration(calendar) > timeSeries_.start().duration() ) {
- return true;
- }
- }
-
- // For time series(/range), this is already handle by timeSeries_
- // If timer expired return false. otherwise must match one time slot in the range/series
- return timeSeries_.isFree(calendar);
-}
-
-bool TodayAttr::why(const ecf::Calendar& c, std::string& theReasonWhy) const
-{
- if (isFree(c)) return false;
- theReasonWhy += "is today dependent";
-
- // Check to see if time has expired, if has not, then report why
- if (timeSeries_.is_valid()) {
- // This can apply to single and series
- boost::posix_time::time_duration calendar_time = timeSeries_.duration(c);
- if (calendar_time < timeSeries_.start().duration()) {
- timeSeries_.why(c, theReasonWhy);
- return true;
- }
-
- // calendar_time >= timeSeries_.start().duration()
- if (timeSeries_.hasIncrement()) {
- if (calendar_time < timeSeries_.finish().duration()) {
- timeSeries_.why(c, theReasonWhy);
- return true;
- }
- }
- // calendar_time >= timeSeries_.start().duration() && calendar_time >= timeSeries_.finish().duration()
- // past the end of time slot, hence this should not hold job generation,
- }
-
- // the today has expired,
- theReasonWhy += " ( '";
- theReasonWhy += toString();
- theReasonWhy += "' has expired,";
-
- // take into account, user can use run/force complete to miss time slots
- bool do_a_requeue = timeSeries_.requeueable(c);
- if (do_a_requeue) {
- TimeSlot the_next_time_slot = timeSeries_.compute_next_time_slot(c);
- if (the_next_time_slot.isNULL() || !timeSeries_.hasIncrement() ) {
- theReasonWhy += " *re-queue* to run at this time";
- }
- else {
- theReasonWhy += " *re-queue* to run at";
- theReasonWhy += the_next_time_slot.toString() ;
- }
- }
- else {
- boost::gregorian::date_duration one_day(1);
- boost::gregorian::date the_next_date = c.date(); // todays date
- the_next_date += one_day; // add one day, so its in the future
-
- theReasonWhy += " next run tomorrow at ";
- theReasonWhy += timeSeries_.start().toString();
- theReasonWhy += " ";
- theReasonWhy += to_simple_string( the_next_date );
- }
- theReasonWhy += " )";
-
- return true;
-}
-
-}
diff --git a/ecflow_4_0_7/ANattr/src/TodayAttr.hpp b/ecflow_4_0_7/ANattr/src/TodayAttr.hpp
deleted file mode 100644
index 7866880..0000000
--- a/ecflow_4_0_7/ANattr/src/TodayAttr.hpp
+++ /dev/null
@@ -1,185 +0,0 @@
-#ifndef TODAYATTR_HPP_
-#define TODAYATTR_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #30 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : The Today attribute is heavily tied to the begin command
-// Real Clock:
-// 1/ Suite Begin time > Today time
-// If the suite 'begin' time is past the time given for today
-// the node is free to run.
-// 2/ Suite Begin time < Today Time
-// The node will 'hold' until current time > today time
-// 3/ Suite time, has passed midnight(next day)
-// then today command will permanently hold the node
-// 4/ Under Real/hybrid clocks today will hold node after
-// current is past last today time.
-//
-// take following example when we have a single time slot:
-// today 10:00
-// isFree:-----free-----
-// begin:
-// V
-// checkForReque:rrrrrrrrrrrrrrrrhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
-// isFree:hhhhhhhhhhhhhhhh|fffffffffffffffffffffffffffffffffffffff *once* free we stay free (single slot *only*)
-// begin:
-// V
-// Today ======================0=====================0=================
-// 10:00 Midnight
-//
-// Difference between time and today. If begin is started after the time slot
-// then the node is free to re-run
-//
-// When we have a today time series:
-// today 10:00 20:00 01:00
-//
-// *** If the begin time is past 10:00 in the case above then the
-// *** node should is free to run once. However for a range its different
-// *** if suite begin time is past 20:00 then the node is held.
-//.
-// At 10am the Node is free, when node completes, it is re-queued
-// At 11am the Node is free, when node completes, it is re-queued
-// ....
-// At 20pm the Node is free, when node completes, it is *NOT* re-queued.
-//--------------------------------------------------------------------------------
-/// isFree is called when a node is queued. if it returns true, Task can be submitted
-/// checkForReque: is called when a node has completed, and need to determine if it should run again.
-/// These are different/orthogonal concerns.
-/// There is a *separate* issue of whether nodes should be queued when a node is *manually*
-/// a/ Set complete
-/// b/ Runs and then completes
-///
-/// For a *single* time slot we can't requeue.
-/// ****However we could have a set of time slots *****
-///
-/// isFree:ffffffffffffffff
-/// Begin:
-/// V
-///checkForReque:hhhhhhhhhhhhhhhhhrrrrrrrrhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
-/// isFree:hhhhhhhhhhhhhhhh|fffffffffffffffffffffffffffffffffffffff
-/// begin :
-/// V
-/// Today ======================0========0===========0====================
-/// 10:00 11:00 Midnight
-/// isFree:hhhhhhhhhhhhhhhhhh
-/// V
-/// CheckForReque:hhhhhhhrrrrrrrrrrrrrrrrrrrrrrrrrhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
-/// isFree:hhhhhhhFhhhhFhhhhFhhhhFhhhhFhhhhFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
-/// V | | | | | | |
-/// Today ================o====|====|====|====|====0========0====================
-/// 10:00 1 2 3 4 15:00 Midnight
-///
-/// If the job starts at 10:00 but takes more than 1 hour, then it will miss the 11:00 slot
-/// and will have to start at 12:00
-//============================================================================
-
-#include <boost/serialization/level.hpp>
-#include <boost/serialization/tracking.hpp>
-
-#include "TimeSeries.hpp"
-
-
-namespace ecf { class Calendar;} // forward declare class
-
-namespace ecf {
-
-// Use compiler , destructor, assignment, copy constructor
-class TodayAttr {
-public:
- TodayAttr() : makeFree_(false), state_change_no_(0) {}
- TodayAttr(int hour, int minute, bool relative = false )
- : timeSeries_(hour, minute,relative), makeFree_(false),state_change_no_(0) {}
- TodayAttr(const TimeSlot& t, bool relative = false )
- : timeSeries_(t,relative), makeFree_(false),state_change_no_(0) {}
- TodayAttr(const TimeSeries& ts)
- : timeSeries_(ts), makeFree_(false),state_change_no_(0) {}
- TodayAttr(const TimeSlot& start, const TimeSlot& finish, const TimeSlot& incr,bool relative = false)
- : timeSeries_(start,finish,incr,relative), makeFree_(false),state_change_no_(0) {}
-
- std::ostream& print(std::ostream&) const;
- bool operator==(const TodayAttr& rhs) const;
- bool operator<(const TodayAttr& rhs) const { return timeSeries_ < rhs.timeSeries_; }
- bool structureEquals(const TodayAttr& rhs) const;
-
- /// This can set attribute as free, once free its stays free, until re-queue/reset
- void calendarChanged( const ecf::Calendar& c );
- void resetRelativeDuration();
-
- void reset(const ecf::Calendar& c) { clearFree(); timeSeries_.reset(c);} // updates state_change_no_
- void requeue(const ecf::Calendar& c,bool reset_next_time_slot = true)
- { clearFree(); timeSeries_.requeue(c,reset_next_time_slot);} // updates state_change_no_
-
- void miss_next_time_slot(); // updates state_change_no_
- void setFree(); // ensures that isFree() always returns true, updates state_change_no_
- bool isSetFree() const { return makeFree_; }
-
- // This is used when we have a *single* today attribute
- // single-slot is free, if calendar time >= today_time
- // (range) is free, if calendar time == (one of the time ranges)
- bool isFree(const ecf::Calendar&) const;
-
- // This is used when we have a *multiple* today attribute
- // (single | range) is free, if calendar time == (one of the time ranges)
- // if timer *expired* returns false
- // task t1
- // today 09:00
- // today 10:00
- // If current times is 11:00, then we will return false.
- // since both 09:00 and 10:00 have expired
- // Multiple single today, should behave like a today with a range.
- bool isFreeMultipleContext(const ecf::Calendar& c) const { return timeSeries_.isFree(c); }
-
-
- bool checkForRequeue( const ecf::Calendar& c,const TimeSlot& the_min,const TimeSlot& the_max) const
- { return timeSeries_.checkForRequeue(c,the_min,the_max);}
- void min_max_time_slots(TimeSlot& the_min, TimeSlot& the_max) const {timeSeries_.min_max_time_slots(the_min,the_max);}
- bool why(const ecf::Calendar&, std::string& theReasonWhy) const;
- bool checkInvariants(std::string& errormsg) const { return timeSeries_.checkInvariants(errormsg);}
-
- // The state_change_no is never reset. Must be incremented if it can affect equality
- // Note: changes in state of timeSeries_, i.e affect the equality operator (used in test)
- // must be captured. i.e things like relative duration & next_time_slot are
- // reported by the Why command, & hence need to be synced.
- unsigned int state_change_no() const { return state_change_no_; }
-
- std::string name() const { return toString(); } /* ABO */
- std::string toString() const;
- std::string dump() const;
-
- // access
- const TimeSeries& time_series() const { return timeSeries_; }
-
-private:
- void clearFree(); // resets the free flag, updates state_change_no_
- bool is_free(const ecf::Calendar&) const; // ignores makeFree_
-
-private:
- TimeSeries timeSeries_;
- bool makeFree_; // persisted for use by why() on client side && for state changes
- unsigned int state_change_no_; // *not* persisted, only used on server side
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/)
- {
- ar & timeSeries_;
- ar & makeFree_;
- }
-};
-
-}
-
-// This should ONLY be added to objects that are *NOT* serialised through a pointer
-BOOST_CLASS_IMPLEMENTATION(ecf::TodayAttr, boost::serialization::object_serializable);
-BOOST_CLASS_TRACKING(ecf::TodayAttr,boost::serialization::track_never);
-
-#endif
diff --git a/ecflow_4_0_7/ANattr/src/Variable.cpp b/ecflow_4_0_7/ANattr/src/Variable.cpp
deleted file mode 100644
index e5f9654..0000000
--- a/ecflow_4_0_7/ANattr/src/Variable.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #56 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <sstream>
-#include <stdexcept>
-
-#include "Variable.hpp"
-#include "Indentor.hpp"
-#include "Str.hpp"
-
-using namespace std;
-using namespace ecf;
-
-// init static's
-const Variable& Variable::EMPTY() { static const Variable VARIABLE = Variable(); return VARIABLE; }
-
-////////////////////////////////////////////////////////////////////////////////////////////
-
-Variable::Variable(const std::string& name, const std::string& value)
-: name_(name), value_(value)
-{
- std::string msg;
- if ( !Str::valid_name( name,msg ) ) {
- throw std::runtime_error("Variable::Variable: Invalid Variable name: " + msg);
- }
-}
-
-int Variable::value() const
-{
- // see if the value is convertible to a integer
- return Str::to_int( value_, 0/* value to return if conversion fails*/);
-}
-
-bool Variable::operator==( const Variable& rhs ) const {
- if ( value_ != rhs.value_ )
- return false;
- if ( name_ != rhs.name_ )
- return false;
- return true;
-}
-
-std::ostream& Variable::print( std::ostream& os ) const {
- // see notes in VariableParser.h
- // Hence we do the following:
- // a/ On parsing always remove quotes ie single or double
- // b/ On serialising always add single quotes
- Indentor in;
- return Indentor::indent( os ) << toString() << "\n";
-}
-
-std::string Variable::toString() const
-{
- std::string ret; ret.reserve(name_.size() + value_.size() + 8);
- ret += "edit ";
- ret += name_;
- ret += " '";
- if (value_.find("\n") == std::string::npos) ret += value_;
- else {
- // replace \n, otherwise re-parse will fail
- std::string value = value_;
- Str::replaceall(value,"\n","\\n");
- ret += value;
- }
- ret += "'";
- return ret;
-}
-
-
-std::string Variable::dump() const
-{
- std::stringstream ss;
- ss << toString() << " value(" << value() << ")";
- return ss.str();
-}
-
diff --git a/ecflow_4_0_7/ANattr/src/Variable.hpp b/ecflow_4_0_7/ANattr/src/Variable.hpp
deleted file mode 100644
index d92f4d0..0000000
--- a/ecflow_4_0_7/ANattr/src/Variable.hpp
+++ /dev/null
@@ -1,74 +0,0 @@
-#ifndef VARIABLE_HPP_
-#define VARIABLE_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #56 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <ostream>
-
-#include <boost/serialization/serialization.hpp>
-#include <boost/serialization/string.hpp> // no need to include <string>
-#include <boost/serialization/tracking.hpp>
-#include <boost/serialization/level.hpp>
-
-////////////////////////////////////////////////////////////////////////////////////////
-// Class Variable:
-// Use compiler , generated destructor, assignment, copy constructor
-class Variable {
-public:
- // This constructor added as an optimisation to avoid, checking variable names.
- // i.e the generated variables, and created by the default constructors of Suite/Family/Task etc
- // These are called during serialisation, hence to avoid checking generated names, we know are valid
- // use this constructor. The bool is used as a dummy argument, so that we call the right constructor
- Variable(const std::string& name, const std::string& value, bool /*check_names_dummy*/)
- : name_(name), value_(value) {}
- Variable(const std::string& name, const std::string& value);
- Variable() {}
-
- const std::string& name() const { return name_;}
- std::ostream& print(std::ostream&) const;
- bool empty() const { return name_.empty(); }
-
- void set_value(const std::string& v) { value_ = v; }
- const std::string& theValue() const { return value_;}
- int value() const;
-
- void set_name(const std::string& v) { name_ = v; }
- std::string& value_by_ref() { return value_;}
-
- bool operator==(const Variable& rhs) const;
- std::string toString() const;
- std::string dump() const;
-
- // Added to support return by reference
- static const Variable& EMPTY();
-
-private:
- std::string name_;
- std::string value_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/)
- {
- ar & name_;
- ar & value_;
- }
-};
-
-// This should ONLY be added to objects that are *NOT* serialised through a pointer
-BOOST_CLASS_IMPLEMENTATION(Variable, boost::serialization::object_serializable)
-BOOST_CLASS_TRACKING(Variable,boost::serialization::track_never);
-
-#endif
diff --git a/ecflow_4_0_7/ANattr/src/VerifyAttr.cpp b/ecflow_4_0_7/ANattr/src/VerifyAttr.cpp
deleted file mode 100644
index 589cd9d..0000000
--- a/ecflow_4_0_7/ANattr/src/VerifyAttr.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-//============================================================================
-// Name : NodeTree.cpp
-// Author : Avi
-// Revision : $Revision: #19 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <sstream>
-#include <iostream>
-
-#include "VerifyAttr.hpp"
-#include "PrintStyle.hpp"
-#include "Indentor.hpp"
-#include "NState.hpp"
-#include "Ecf.hpp"
-#include "Str.hpp"
-
-using namespace ecf;
-
-bool VerifyAttr::operator==(const VerifyAttr& rhs) const
-{
- if (state_ != rhs.state_) return false;
- if (expected_ != rhs.expected_) return false;
- return true;
-}
-
-std::ostream& VerifyAttr::print(std::ostream& os) const
-{
- Indentor in;
- Indentor::indent(os) << toString();
- if (!PrintStyle::defsStyle()) {
- os << " # " << actual_;
- }
- os << "\n";
- return os;
-}
-
-void VerifyAttr::incrementActual() {
- actual_++;
- state_change_no_ = Ecf::incr_state_change_no();
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "VerifyAttr::incrementActual()\n";
-#endif
-}
-
-void VerifyAttr::reset() {
- actual_ = 0;
- state_change_no_ = Ecf::incr_state_change_no();
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "VerifyAttr::reset()\n";
-#endif
-}
-
-std::string VerifyAttr::toString() const
-{
- std::stringstream ss;
- ss << "verify " << NState::toString(state_) << Str::COLON() << expected_;
- return ss.str();
-}
-
-std::string VerifyAttr::dump() const
-{
- std::stringstream ss;
- ss << "verify " << NState::toString(state_) << Str::COLON() << expected_;
- ss << " actual(" << actual_ << ")";
- return ss.str();
-}
-
diff --git a/ecflow_4_0_7/ANattr/src/VerifyAttr.hpp b/ecflow_4_0_7/ANattr/src/VerifyAttr.hpp
deleted file mode 100644
index 0acdc5c..0000000
--- a/ecflow_4_0_7/ANattr/src/VerifyAttr.hpp
+++ /dev/null
@@ -1,73 +0,0 @@
-#ifndef VERIFYATTR_HPP_
-#define VERIFYATTR_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <ostream>
-
-#include <boost/operators.hpp>
-#include <boost/serialization/serialization.hpp>
-#include <boost/serialization/level.hpp>
-#include <boost/serialization/tracking.hpp>
-
-#include "NState.hpp"
-
-
-// Class VerifyAttr:
-// This class is only used for testing/verification purposes. It allows us to
-// embed expected number of states, within the definition file and so
-// reduce the need for golden log files.
-// Use compiler , generated destructor, assignment, copy constructor
-class VerifyAttr {
-public:
- VerifyAttr(NState::State state,int expected)
- : state_(state), expected_(expected), actual_(0), state_change_no_(0) {}
- VerifyAttr()
- : state_(NState::UNKNOWN), expected_(0), actual_(0),state_change_no_(0) {}
-
- bool operator==(const VerifyAttr& rhs) const;
- std::ostream& print(std::ostream&) const;
-
- NState::State state() const { return state_;}
- int expected() const { return expected_;}
- int actual() const { return actual_;}
- void incrementActual();
- void reset();
-
- // The state_change_no is never reset. Must be incremented if it can affect equality
- unsigned int state_change_no() const { return state_change_no_; }
-
- std::string toString() const;
- std::string dump() const;
-
-private:
- NState::State state_;
- int expected_;
- int actual_;
- unsigned int state_change_no_; // *not* persisted, only used on server side
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/) {
- ar & state_;
- ar & expected_;
- ar & actual_;
- }
-};
-
-// This should ONLY be added to objects that are *NOT* serialised through a pointer
-BOOST_CLASS_IMPLEMENTATION(VerifyAttr, boost::serialization::object_serializable)
-BOOST_CLASS_TRACKING(VerifyAttr,boost::serialization::track_never);
-
-#endif
diff --git a/ecflow_4_0_7/ANattr/src/Zombie.cpp b/ecflow_4_0_7/ANattr/src/Zombie.cpp
deleted file mode 100644
index 4c89306..0000000
--- a/ecflow_4_0_7/ANattr/src/Zombie.cpp
+++ /dev/null
@@ -1,216 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #15 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Holds the zombie structure
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/foreach.hpp>
-
-#include "Zombie.hpp"
-#include "Calendar.hpp"
-
-using namespace ecf;
-using namespace std;
-
-// support return by reference
-const Zombie& Zombie::EMPTY() { static const Zombie ZOMBIE = Zombie(); return ZOMBIE; }
-Zombie& Zombie::EMPTY_() { static Zombie ZOMBIE = Zombie(); return ZOMBIE; }
-
-Zombie::Zombie( ecf::Child::ZombieType zombie_type,
- ecf::Child::CmdType cmd,
- const ZombieAttr& attr,
- const std::string& pathToTask,
- const std::string& jobsPassword,
- const std::string& process_or_remote_id,
- int try_no
-)
-: user_action_(User::BLOCK),
- try_no_(try_no),
- duration_(0),
- calls_(1),
- zombie_type_(zombie_type),
- last_child_cmd_(cmd),
- path_to_task_(pathToTask),
- jobs_password_(jobsPassword),
- process_or_remote_id_(process_or_remote_id),
- user_action_set_(false),
- attr_(attr),
- creation_time_( Calendar::second_clock_time() )
-{}
-
-Zombie::Zombie()
-: user_action_(User::BLOCK),
- try_no_(0),
- duration_(0),
- calls_(1),
- zombie_type_(Child::USER),
- last_child_cmd_(Child::INIT),
- user_action_set_(false)
-{}
-
-std::string Zombie::type_str() const
-{
- return Child::to_string(zombie_type_);
-}
-
-ecf::User::Action Zombie::user_action() const
-{
- // User action needs to take into account, last child command and setting on attr_
- if (fob()) return User::FOB;
- else if (block()) return User::BLOCK;
- else if (fail()) return User::FAIL;
- else if (remove()) return User::REMOVE;
- else if (kill()) return User::KILL;
- else if (adopt()) return User::ADOPT;
-
- return User::BLOCK; // the default action
-}
-
-std::string Zombie::user_action_str() const {
- std::string ret;
- if (manual_user_action()) ret = "manual-";
- else ret = "auto-";
- ret += User::to_string(user_action());
- return ret;
-}
-
-/// accessors
-bool Zombie::fob() const {
- if (user_action_set_) return user_action_ == User::FOB;
- return attr_.fob(last_child_cmd_);
-}
-bool Zombie::fail() const {
- if (user_action_set_) return user_action_ == User::FAIL;
- return attr_.fail(last_child_cmd_);
-}
-bool Zombie::adopt() const {
- if (user_action_set_) return user_action_ == User::ADOPT;
- return attr_.adopt(last_child_cmd_);
-}
-bool Zombie::block() const {
- if (user_action_set_) return user_action_ == User::BLOCK;
- return attr_.block(last_child_cmd_);
-}
-bool Zombie::remove() const {
- if (user_action_set_) return user_action_ == User::REMOVE;
- return attr_.remove(last_child_cmd_);
-}
-bool Zombie::kill() const {
- if (user_action_set_) return user_action_ == User::KILL;
- return attr_.kill(last_child_cmd_);
-}
-
-int Zombie::allowed_age() const
-{
- return attr_.zombie_lifetime();
-}
-
-void Zombie::set_fob() { user_action_ = User::FOB; user_action_set_ = true;}
-void Zombie::set_fail() { user_action_ = User::FAIL; user_action_set_ = true;}
-void Zombie::set_adopt() { user_action_ = User::ADOPT; user_action_set_ = true;}
-void Zombie::set_block() { user_action_ = User::BLOCK; user_action_set_ = true;}
-void Zombie::set_kill() { user_action_ = User::KILL; user_action_set_ = true;}
-
-
-std::ostream& operator<<(std::ostream& os, const Zombie& z)
-{
- os << z.path_to_task() << " ";
- os << z.type_str() << " ";
- os << z.duration() << " ";
- os << z.jobs_password() << " ";
- os << z.process_or_remote_id() << "<pid> ";
- os << z.try_no() << " ";
- os << "calls(" << z.calls() << ") ";
- os << z.user_action_str();
- os << " ";
- os << Child::to_string(z.last_child_cmd());
- return os;
-}
-
-
-std::string Zombie::pretty_print(const std::vector<Zombie>& zombies,int indent)
-{
- std::stringstream ss;
- std::vector<std::string> list;
- pretty_print(zombies, list, indent);
- for (size_t i=0; i<list.size(); ++i) {
- ss << list[i] << "\n";
- }
- return ss.str();
-}
-
-void Zombie::pretty_print(const std::vector<Zombie>& zombies,
- std::vector<std::string>& list,
- int indent)
-{
- string path("task-path");
- string type("type");
- string password("password");
- string rid("process-id");
- string duration("duration");
- string calls("calls");
- string try_no("try_no");
- string user_action("action");
- string child_type("child");
-
- size_t path_width = path.size();
- size_t type_width = type.size();
- size_t duration_width = duration.size();
- size_t password_width = password.size();
- size_t tryno_width = try_no.size();
- size_t rid_width = rid.size();
- size_t user_action_width = 13; // max of FOB,FAIL,ADOPT,BLOCK,REMOVE + (manual- | auto- )
- size_t child_type_width = 8; // max of INIT,COMPLETE,EVENT,METER,LABEL,WAIT,ABORT
- size_t calls_width = calls.size();
-
- BOOST_FOREACH(const Zombie& z, zombies) {
- path_width = std::max(path_width,z.path_to_task().size());
- type_width = std::max(type_width,z.type_str().size());
- password_width = std::max(password_width,z.jobs_password().size());
- rid_width = std::max(rid_width,z.process_or_remote_id().size());
- std::string no_of_calls = boost::lexical_cast<std::string>(z.calls());
- calls_width = std::max(calls_width,no_of_calls.size());
-
- std::string try_no_int = boost::lexical_cast<std::string>(z.try_no());
- tryno_width = std::max(tryno_width,try_no_int.size());
- }
-
- std::stringstream ss;
- if (indent != 0) for(int i = 0; i < indent; i++) ss << " ";
- ss << left << setw(path_width) << path << " "
- << setw(type_width) << type << " "
- << setw(duration_width) << duration << " "
- << setw(password_width) << password << " "
- << setw(rid_width) << rid << " "
- << setw(tryno_width) << try_no << " "
- << setw(user_action_width) << user_action << " "
- << setw(child_type_width) << child_type << " "
- << setw(calls_width) << calls
- ;
-
- list.push_back(ss.str());
-
- BOOST_FOREACH(const Zombie& z, zombies) {
- std::stringstream ss;
- if (indent != 0) for(int i = 0; i < indent; i++) ss << " ";
- ss << left << setw(path_width) << z.path_to_task() << " "
- << setw(type_width) << z.type_str() << " "
- << setw(duration_width) << z.duration() << " "
- << setw(password_width) << z.jobs_password() << " "
- << setw(rid_width) << z.process_or_remote_id() << " "
- << setw(tryno_width) << z.try_no() << " "
- << setw(user_action_width) << z.user_action_str() << " "
- << setw(child_type_width) << Child::to_string(z.last_child_cmd()) << " "
- << setw(calls_width) << z.calls()
- ;
- list.push_back(ss.str());
- }
-}
diff --git a/ecflow_4_0_7/ANattr/src/Zombie.hpp b/ecflow_4_0_7/ANattr/src/Zombie.hpp
deleted file mode 100644
index 7518200..0000000
--- a/ecflow_4_0_7/ANattr/src/Zombie.hpp
+++ /dev/null
@@ -1,166 +0,0 @@
-#ifndef ZOMBIE_HPP_
-#define ZOMBIE_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #15 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Holds the zombie structure
-// WE have 3 structures:
-// Jobs(path,password,process_id)
-// Complications ONLY init command provides process_id.
-// Task(path,password,process_id)
-// Zombie(path,password,process_id)
-// Issues:
-// At the extreme we can have *2* Jobs running at one go. Typically user commands
-// that have a force parameter, will create 'user' zombies.
-// ** the command can be invoked at any time, i.e we could invoke
-// ** the user command, whilst the task is in SUBMITTED state
-// ** This will go through and create user zombie. However at this stage we have *NO* process_id
-// ** since the job has not started. Zombie(path,password)
-// When the Task init command is called, we get given a process_id.
-// ** HOWEVER ** need to determine if this is from the real child cmd or from the zombie
-// ** We search zombie list, and compare zombies, by path and password
-// ** if a match is found, we update the zombie id.
-//
-// IMPORTANT:: Automated test:
-// If a child command provides just path and password, this is *NOT*
-// enough information to disambiguate a zombie from a real job.
-// To work around this the job file has been updated to add ECF_RID=$$
-//
-// IMPORTANT:: For command line interface we just have the task path.
-// i,e we don't want to expose password, and user will not easily
-// know the process or remote id. Hence we will make do with the
-// task path. We just find the first zombie, and act up on it
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <string>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-#include <boost/serialization/serialization.hpp>
-#include <boost/serialization/level.hpp>
-#include <boost/serialization/tracking.hpp>
-#include "Child.hpp"
-#include "ZombieAttr.hpp"
-
-/// Use default copy constructor ,assignment operator and destructor
-class Zombie {
-public:
- Zombie( ecf::Child::ZombieType zombie_type, // The kind of zombie
- ecf::Child::CmdType child_cmd, // The Child command, that lead to this zombie
- const ZombieAttr& attr, // will hold Action if set on node tree
- const std::string& pathToTask, // from child ipc
- const std::string& jobsPassword, // from child ipc
- const std::string& process_or_remote_id,// from child ipc
- int try_no
- );
- Zombie();
-
-/// accessors
- // distinguish between manual and automatic user action. manual take precedence
- bool manual_user_action() const { return user_action_set_;}
- bool fob() const;
- bool fail() const ;
- bool adopt() const;
- bool block() const;
- bool remove() const;
- bool kill() const;
-
- ecf::Child::ZombieType type() const { return zombie_type_;}
- ecf::Child::CmdType last_child_cmd() const { return last_child_cmd_; }
- const ZombieAttr& attr() const { return attr_;}
- int calls() const { return calls_;}
-
- std::string type_str() const;
- const std::string& jobs_password() const { return jobs_password_; }
- const std::string& path_to_task() const { return path_to_task_; }
- const std::string& process_or_remote_id() const { return process_or_remote_id_; }
- int try_no() const { return try_no_; }
- int duration() const { return duration_; }
- ecf::User::Action user_action() const;
- std::string user_action_str() const;
-
-
- const boost::posix_time::ptime& creation_time() const { return creation_time_; }
-
- bool empty() const { return path_to_task_.empty(); }
-
- /// returns in seconds the age the zombie is allowed to live
- int allowed_age() const;
-
-/// mutators
- void set_attr( const ZombieAttr& attr) { attr_ = attr;}
- void set_process_or_remote_id( const std::string& s) { process_or_remote_id_ = s;}
- void set_last_child_cmd( ecf::Child::CmdType c) { last_child_cmd_ = c;}
- void set_type(ecf::Child::ZombieType zt) { zombie_type_ = zt; }
-
- /// User action must take precedence over Zombie attribute settings on node tree
- ///
- /// Note: user_action to remove zombie is immediate hence no need to for set_remove()
- /// Whereas for the other we want to store the action so that when next child
- /// command communicate with the server, the action is applied.
- void set_duration(int d) { duration_ = d;}
- void set_fob();
- void set_fail();
- void set_adopt();
- void set_block();
- void set_kill();
-
- void increment_calls() { calls_++;}
-
- // write to standard out a title and list of zombies
- static std::string pretty_print(const std::vector<Zombie>& zombies, int indent = 0);
- static void pretty_print(const std::vector<Zombie>& zombies,
- std::vector<std::string>& list,
- int indent = 0);
-
-// MISC:
- // Added to support return by reference
- static const Zombie& EMPTY() ;
- static Zombie& EMPTY_();
-
-private:
-
- ecf::User::Action user_action_; // [ fob, fail, remove, adopt, block ]
- int try_no_; // task try number, set on construction
- int duration_; // How long zombie been alive
- int calls_; // Number of times we have communicated with server.
- ecf::Child::ZombieType zombie_type_; // [ ecf, path, user ]
- ecf::Child::CmdType last_child_cmd_; // [ init | event | meter | label | wait | abort | complete ]
- std::string path_to_task_; // set on construction
- std::string jobs_password_; // set on construction
- std::string process_or_remote_id_; // set on construction
-
- bool user_action_set_; // Differentiate manual from automated, response, manual take precedence
- ZombieAttr attr_; // Default or attribute obtained from node tree.
- boost::posix_time::ptime creation_time_;// When zombie was created. Needed to control lifetime
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
-
- ar & user_action_;
- ar & try_no_;
- ar & duration_;
- ar & calls_;
- ar & zombie_type_;
- ar & last_child_cmd_;
- ar & path_to_task_;
- ar & jobs_password_;
- ar & process_or_remote_id_;
- ar & user_action_set_;
- ar & attr_;
- }
-};
-
-std::ostream& operator<<(std::ostream& os, const Zombie&);
-
-// This should ONLY be added to objects that are *NOT* serialised through a pointer
-BOOST_CLASS_IMPLEMENTATION(Zombie, boost::serialization::object_serializable)
-BOOST_CLASS_TRACKING(Zombie,boost::serialization::track_never);
-#endif
diff --git a/ecflow_4_0_7/ANattr/src/ZombieAttr.cpp b/ecflow_4_0_7/ANattr/src/ZombieAttr.cpp
deleted file mode 100644
index b340bff..0000000
--- a/ecflow_4_0_7/ANattr/src/ZombieAttr.cpp
+++ /dev/null
@@ -1,240 +0,0 @@
-//============================================================================
-// Name : NodeTree.cpp
-// Author : Avi
-// Revision : $Revision: #13 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <sstream>
-#include <iostream>
-#include <assert.h>
-#include <boost/tokenizer.hpp>
-#include <boost/token_functions.hpp>
-#include <boost/lexical_cast.hpp>
-
-#include "ZombieAttr.hpp"
-#include "Indentor.hpp"
-#include "Str.hpp"
-
-using namespace ecf;
-using namespace boost;
-using namespace std;
-
-/// int statics
-static int ecf_zombie_life_time = 3600;
-static int user_zombie_life_time = 300;
-static int path_zombie_life_time = 900;
-
-const ZombieAttr& ZombieAttr::EMPTY() { static const ZombieAttr ZOMBIEATTR = ZombieAttr(); return ZOMBIEATTR; }
-
-// Constructor ==============================================================================
-ZombieAttr::ZombieAttr(ecf::Child::ZombieType t, const std::vector<ecf::Child::CmdType>& c, ecf::User::Action a, int zombie_lifetime)
- : zombie_type_(t), action_(a), zombie_lifetime_(zombie_lifetime), child_cmds_(c)
-{
- if ( zombie_lifetime_ == -1) {
- switch (zombie_type_) {
- case Child::USER: zombie_lifetime_ = user_zombie_life_time; break;
- case Child::PATH: zombie_lifetime_ = path_zombie_life_time; break;
- case Child::ECF: zombie_lifetime_ = ecf_zombie_life_time; break;
- case Child::NOT_SET: assert(false); break;
- }
- }
-}
-
-bool ZombieAttr::operator==(const ZombieAttr& rhs) const
-{
- if (zombie_type_ != rhs.zombie_type_) return false;
- if (action_ != rhs.action_) return false;
- if (zombie_lifetime_ != rhs.zombie_lifetime_) return false;
- if (child_cmds_ != rhs.child_cmds_) return false;
- return true;
-}
-
-std::ostream& ZombieAttr::print(std::ostream& os) const
-{
- Indentor in;
- Indentor::indent(os) << toString();
- os << "\n";
- return os;
-}
-
-std::string ZombieAttr::toString() const
-{
- /// format is zombie_type : child_cmds(optional) : action : zombie_lifetime_(optional)
- std::stringstream ss;
- ss << "zombie " << Child::to_string(zombie_type_)
- << Str::COLON()
- << User::to_string(action_)
- << Str::COLON()
- << Child::to_string(child_cmds_)
- << Str::COLON()
- << zombie_lifetime_
- ;
-
- return ss.str();
-}
-
-bool ZombieAttr::fob( ecf::Child::CmdType child_cmd) const
-{
- if ( action_ != User::FOB) return false;
- if ( child_cmds_.empty()) return true;
-
- // If we have child commands specified, then the action is only applicable for that child cmd
- // for all other child cmds we block
- for(size_t i = 0; i < child_cmds_.size(); i++) {
- if (child_cmds_[i] == child_cmd ) {
- return true;
- }
- }
- return false;
-}
-
-bool ZombieAttr::fail( ecf::Child::CmdType child_cmd) const
-{
- if ( action_ != User::FAIL) return false;
- if ( child_cmds_.empty()) return true;
-
- // If we have child commands specified, then the action is only applicable for that child cmd
- // for all other child cmds we block
- for(size_t i = 0; i < child_cmds_.size(); i++) {
- if (child_cmds_[i] == child_cmd ) {
- return true;
- }
- }
- return false;
-}
-
-bool ZombieAttr::adopt( ecf::Child::CmdType child_cmd) const
-{
- if ( action_ != User::ADOPT) return false;
- if ( child_cmds_.empty()) return true;
-
- // If we have child commands specified, then the action is only applicable for that child cmd
- // for all other child cmds we block
- for(size_t i = 0; i < child_cmds_.size(); i++) {
- if (child_cmds_[i] == child_cmd ) {
- return true;
- }
- }
- return false;
-}
-
-bool ZombieAttr::remove( ecf::Child::CmdType child_cmd) const
-{
- if ( action_ != User::REMOVE) return false;
- if ( child_cmds_.empty()) return true;
-
- // If we have child commands specified, then the action is only applicable for that child cmd
- // for all other child cmds we block
- for(size_t i = 0; i < child_cmds_.size(); i++) {
- if (child_cmds_[i] == child_cmd ) {
- return true;
- }
- }
- return false;
-}
-
-bool ZombieAttr::block( ecf::Child::CmdType child_cmd) const
-{
- if ( action_ != User::BLOCK) return false;
- if ( child_cmds_.empty()) return true;
-
- // If we have child commands specified, then the action is only applicable for that child cmd
- // for all other child cmds we block
- for(size_t i = 0; i < child_cmds_.size(); i++) {
- if (child_cmds_[i] == child_cmd ) {
- return true;
- }
- }
- return false;
-}
-
-bool ZombieAttr::kill( ecf::Child::CmdType child_cmd) const
-{
- if ( action_ != User::KILL) return false;
- if ( child_cmds_.empty()) return true;
-
- // If we have child commands specified, then the action is only applicable for that child cmd
- // for all other child cmds we block
- for(size_t i = 0; i < child_cmds_.size(); i++) {
- if (child_cmds_[i] == child_cmd ) {
- return true;
- }
- }
- return false;
-}
-
-ZombieAttr ZombieAttr::create(const std::string& string_to_parse)
-{
- /// Use boost tokenizer instead of Str::split, as it allows preservation of empty tokens
- char_separator<char> sep(":","",boost::keep_empty_tokens);
- typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
- tokenizer tokenise(string_to_parse, sep);
- std::vector<std::string> tokens;
- std::copy(tokenise.begin(), tokenise.end(), back_inserter(tokens));
- if (tokens.size() < 2) throw std::runtime_error("ZombieAttr::create failed: Invalid zombie type " + string_to_parse);
-
- /// expects <zombie_type>:<user_action>:child_cmds:zombie_lifetime
- string str_zombie_type;
- string action_str;
- string child_cmds;
- string lifetime;
- size_t tokens_size = tokens.size() ;
- for(size_t i =0; i < tokens_size ; i++) {
- // cout << " token " << i << ": '" << tokens[i] << "'\n";
- if (i == 0) { str_zombie_type = tokens[i]; continue;}
- if (i == 1) { action_str = tokens[i]; continue;}
- if (i == 2) { child_cmds = tokens[i]; continue;}
- if (i == 3) { lifetime = tokens[i]; continue;}
- throw std::runtime_error("ZombieAttr::create failed: Invalid zombie tokens " + string_to_parse);
- }
- //std::cout << " zombie_type = " << str_zombie_type << " user_action = " << action_str << " child_cmds = " << child_cmds<< " zombie_lifetime = " << lifetime << "\n";
-
- if (!Child::valid_zombie_type(str_zombie_type))
- throw std::runtime_error("ZombieAttr::create failed: Invalid zombie type, expected one of [ user | ecf | path ] but found " + str_zombie_type + string(":") + string_to_parse);
-
- if ( !action_str.empty() && !User::valid_user_action(action_str)) {
- throw std::runtime_error("ZombieAttr::create failed: Invalid user action, expected one of [ fob | fail | remove | block | adopt | kill ] but found " + action_str + string(":") + string_to_parse);
- }
-
- if ( !child_cmds.empty() && !Child::valid_child_cmds(child_cmds)) {
- throw std::runtime_error("ZombieAttr::create failed: Invalid child type, expected one or more of [ init,event,meter,label,wait,abort,complete] but found " + tokens[2] + string(":") + string_to_parse);
- }
-
- int zombie_lifetime = -1;
- if ( !lifetime.empty() ) {
- try { zombie_lifetime = boost::lexical_cast<int>(lifetime);}
- catch ( boost::bad_lexical_cast& ) {
- throw std::runtime_error("ZombieAttr::create failed: Zombie life time must be convertible to an integer " + lifetime + string(":") + string_to_parse);
- }
- }
-
- if (action_str.empty() && zombie_lifetime == -1)
- throw std::runtime_error("ZombieAttr::create failed: User Action(fob,fail,remove,adopt,block) or lifetime must be specified: " + string_to_parse);
-
- Child::ZombieType zombie_type = Child::zombie_type(str_zombie_type);
- User::Action action = User::user_action(action_str);
- vector<Child::CmdType> childVec = Child::child_cmds(child_cmds);
-
- /// If zombie_lifetime is still -1 constructor will reset to standard defaults
- return ZombieAttr(zombie_type,childVec,action,zombie_lifetime) ;
-}
-
-ZombieAttr ZombieAttr::get_default_attr(ecf::Child::ZombieType zt)
-{
- switch (zt) {
- case Child::USER: return ZombieAttr(Child::USER,std::vector<ecf::Child::CmdType>(), User::BLOCK, user_zombie_life_time); break;
- case Child::PATH: return ZombieAttr(Child::PATH,std::vector<ecf::Child::CmdType>(), User::BLOCK, path_zombie_life_time); break;
- case Child::ECF: return ZombieAttr(Child::ECF, std::vector<ecf::Child::CmdType>(), User::BLOCK, ecf_zombie_life_time); break;
- case Child::NOT_SET: break;
- }
- return ZombieAttr(Child::ECF, std::vector<ecf::Child::CmdType>(), User::BLOCK, ecf_zombie_life_time);
-}
-
diff --git a/ecflow_4_0_7/ANattr/src/ZombieAttr.hpp b/ecflow_4_0_7/ANattr/src/ZombieAttr.hpp
deleted file mode 100644
index 8a53a26..0000000
--- a/ecflow_4_0_7/ANattr/src/ZombieAttr.hpp
+++ /dev/null
@@ -1,82 +0,0 @@
-#ifndef ZOMBIE_ATTR_HPP_
-#define ZOMBIE_ATTR_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #9 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <ostream>
-#include <boost/serialization/serialization.hpp>
-#include <boost/serialization/level.hpp>
-#include <boost/serialization/tracking.hpp>
-#include "Child.hpp"
-
-// Class ZombieAttr:
-// Use compiler , generated destructor, assignment, copy constructor
-// ZombieAttr does *not* have any changeable state
-class ZombieAttr {
-public:
- ZombieAttr(ecf::Child::ZombieType t, const std::vector<ecf::Child::CmdType>& c, ecf::User::Action a, int zombie_lifetime);
- ZombieAttr() : zombie_type_(ecf::Child::NOT_SET), action_(ecf::User::BLOCK), zombie_lifetime_(0) {}
-
- bool operator==(const ZombieAttr& rhs) const;
- std::ostream& print(std::ostream&) const;
- bool empty() const { return zombie_type_ == ecf::Child::NOT_SET; }
-
- ecf::Child::ZombieType zombie_type() const { return zombie_type_;}
- ecf::User::Action action() const { return action_; }
- int zombie_lifetime() const { return zombie_lifetime_; }
- const std::vector<ecf::Child::CmdType>& child_cmds() const { return child_cmds_; }
-
- std::vector<ecf::Child::CmdType>::const_iterator child_begin() const { return child_cmds_.begin();} // for python
- std::vector<ecf::Child::CmdType>::const_iterator child_end() const { return child_cmds_.end(); } // for python
-
- std::string toString() const;
-
- bool fob( ecf::Child::CmdType ) const;
- bool fail( ecf::Child::CmdType ) const;
- bool adopt( ecf::Child::CmdType ) const;
- bool block( ecf::Child::CmdType ) const;
- bool remove( ecf::Child::CmdType ) const;
- bool kill( ecf::Child::CmdType ) const;
-
- /// Create from a string. Will throw std::runtime_error of parse errors
- /// expects <zombie_type>:<user_action>:child_cmds:zombie_lifetime
- static ZombieAttr create(const std::string& str);
-
- // Added to support return by reference
- static const ZombieAttr& EMPTY();
-
- // Provide the default behaviour
- static ZombieAttr get_default_attr(ecf::Child::ZombieType);
-
-private:
- ecf::Child::ZombieType zombie_type_; // User,path or ecf
- ecf::User::Action action_; // fob, fail,remove, adopt, block, kill
- int zombie_lifetime_; // How long zombie lives in server
- std::vector<ecf::Child::CmdType> child_cmds_; // init, event, meter,label, complete
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/) {
- ar & zombie_type_;
- ar & action_;
- ar & zombie_lifetime_;
- ar & child_cmds_;
- }
-};
-
-// This should ONLY be added to objects that are *NOT* serialised through a pointer
-BOOST_CLASS_IMPLEMENTATION(ZombieAttr, boost::serialization::object_serializable)
-BOOST_CLASS_TRACKING(ZombieAttr,boost::serialization::track_never);
-
-#endif
diff --git a/ecflow_4_0_7/ANattr/test/TestAttrSerialization.cpp b/ecflow_4_0_7/ANattr/test/TestAttrSerialization.cpp
deleted file mode 100644
index 521c1dc..0000000
--- a/ecflow_4_0_7/ANattr/test/TestAttrSerialization.cpp
+++ /dev/null
@@ -1,297 +0,0 @@
-#define BOOST_TEST_MODULE TestANattr
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #24 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <boost/test/unit_test.hpp>
-#include <boost/make_shared.hpp>
-
-#include "TodayAttr.hpp"
-#include "TimeAttr.hpp"
-#include "VerifyAttr.hpp"
-#include "RepeatAttr.hpp"
-#include "LateAttr.hpp"
-#include "DayAttr.hpp"
-#include "DateAttr.hpp"
-#include "CronAttr.hpp"
-#include "ClockAttr.hpp"
-#include "AutoCancelAttr.hpp"
-#include "NodeAttr.hpp"
-#include "Variable.hpp"
-#include "ZombieAttr.hpp"
-#include "Calendar.hpp"
-#include "SerializationTest.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-
-// Globals used throughout the test
-static std::string fileName = "test.txt";
-
-BOOST_AUTO_TEST_SUITE( ANattrTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_AttrDefaultConstructor_serialisation )
-{
- cout << "ANattr:: ...test_AttrDefaultConstructor_serialisation \n";
-
- doSaveAndRestore<VerifyAttr>(fileName);
- doSaveAndRestore<TodayAttr>(fileName);
- doSaveAndRestore<TimeAttr>(fileName);
- doSaveAndRestore<RepeatDate>(fileName);
- doSaveAndRestore<RepeatInteger>(fileName);
- doSaveAndRestore<RepeatEnumerated>(fileName);
- doSaveAndRestore<RepeatString>(fileName);
- doSaveAndRestore<LateAttr>(fileName);
- doSaveAndRestore<DayAttr>(fileName);
- doSaveAndRestore<DateAttr>(fileName);
- doSaveAndRestore<CronAttr>(fileName);
- doSaveAndRestore<ClockAttr>(fileName);
- doSaveAndRestore<AutoCancelAttr>(fileName);
- doSaveAndRestore<Label>(fileName);
- doSaveAndRestore<Variable>(fileName);
- doSaveAndRestore<Event>(fileName);
- doSaveAndRestore<Meter>(fileName);
- doSaveAndRestore<ZombieAttr>(fileName);
-}
-
-BOOST_AUTO_TEST_CASE( test_VerifyAttr_serialisation )
-{
- cout << "ANattr:: ...test_VerifyAttr_serialisation \n";
- VerifyAttr saved(NState::COMPLETE,10);
- doSaveAndRestore(fileName,saved);
-}
-
-BOOST_AUTO_TEST_CASE( test_TodayAttr_serialisation )
-{
- cout << "ANattr:: ...test_TodayAttr_serialisation \n";
- {
- TodayAttr saved(TimeSlot(10,12));
- doSaveAndRestore(fileName,saved);
- }
- {
- TodayAttr saved(TimeSlot(0,0),TimeSlot(10,12),TimeSlot(1,0));
- doSaveAndRestore(fileName,saved);
- }
- {
- TodayAttr saved(TimeSeries(TimeSlot(10,12)));
- doSaveAndRestore(fileName,saved);
- }
- {
- TodayAttr saved(TimeSeries(TimeSlot(10,12)));
- doSaveAndRestore(fileName,saved);
- }
-}
-
-
-BOOST_AUTO_TEST_CASE( test_TimeAttr_serialisation )
-{
- cout << "ANattr:: ...test_TimeAttr_serialisation \n";
- {
- TimeAttr saved(TimeSlot(10,12));
- doSaveAndRestore(fileName,saved);
- }
- {
- TimeAttr saved(TimeSlot(0,0),TimeSlot(10,12),TimeSlot(1,0));
- doSaveAndRestore(fileName,saved);
- }
- {
- TimeAttr saved(TimeSeries(TimeSlot(10,12)));
- doSaveAndRestore(fileName,saved);
- }
-}
-
-
-BOOST_AUTO_TEST_CASE( test_RepeatAttr_serialisation )
-{
- cout << "ANattr:: ...test_RepeatAttr_serialisation \n";
- {
- RepeatDate saved("varname",20101210,20101230,3);
- doSaveAndRestore(fileName,saved);
- }
- {
- RepeatInteger saved("varname",0,10,1);
- doSaveAndRestore(fileName,saved);
- }
- {
- std::vector<std::string> theVec; theVec.push_back("a"); theVec.push_back("b");
- RepeatEnumerated saved = RepeatEnumerated("varname",theVec);
- doSaveAndRestore(fileName,saved);
- }
- {
- std::vector<std::string> theVec; theVec.push_back("a");
- RepeatString saved = RepeatString("varname",theVec);
- doSaveAndRestore(fileName,saved);
- }
-
-
- {
- Repeat saved(RepeatDate("varname",20101210,20101230,3));
- doSaveAndRestore(fileName,saved);
- }
- {
- Repeat saved(RepeatInteger("varname",0,10,1));
- doSaveAndRestore(fileName,saved);
- }
- {
- std::vector<std::string> theVec; theVec.push_back("a"); theVec.push_back("b");
- Repeat saved(RepeatEnumerated("varname",theVec));
- doSaveAndRestore(fileName,saved);
- }
- {
- std::vector<std::string> theVec; theVec.push_back("a");
- Repeat saved(RepeatString("varname",theVec));
- doSaveAndRestore(fileName,saved);
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_LateAttr_serialisation )
-{
- cout << "ANattr:: ...test_LateAttr_serialisation \n";
- LateAttr saved;
- saved.addSubmitted(TimeSlot(10,12));
- saved.addActive(TimeSlot(10,12));
- saved.addComplete(TimeSlot(10,12),true);
- doSaveAndRestore(fileName,saved);
-
-}
-
-BOOST_AUTO_TEST_CASE( test_DayAttr_serialisation )
-{
- cout << "ANattr:: ...test_DayAttr_serialisation\n";
- std::vector< DayAttr::Day_t > dvec;
- dvec.push_back(DayAttr::SUNDAY);
- dvec.push_back(DayAttr::MONDAY);
- dvec.push_back(DayAttr::TUESDAY);
- dvec.push_back(DayAttr::WEDNESDAY);
- dvec.push_back(DayAttr::THURSDAY);
- dvec.push_back(DayAttr::FRIDAY);
- dvec.push_back(DayAttr::SATURDAY);
- for(size_t d = 0; d < dvec.size(); d++) {
- DayAttr saved(dvec[d]);
- doSaveAndRestore(fileName,saved);
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_DateAttr_serialisation )
-{
- cout << "ANattr:: ...test_DateAttr_serialisation\n";
- DateAttr saved(1,1,2010);
- doSaveAndRestore(fileName,saved);
-}
-
-BOOST_AUTO_TEST_CASE( test_CronAttr_serialisation )
-{
- cout << "ANattr:: ...test_CronAttr_serialisation\n";
- CronAttr saved;
- std::vector<int> weekDays; weekDays.push_back(1); weekDays.push_back(2);
- std::vector<int> daysOfMonth; daysOfMonth.push_back(1); daysOfMonth.push_back(2);
- std::vector<int> months; months.push_back(1); months.push_back(2);
- saved.addWeekDays(weekDays);
- saved.addDaysOfMonth(daysOfMonth);
- saved.addMonths(months);
- saved.addTimeSeries(TimeSlot(0,0),TimeSlot(20,0),TimeSlot(0,1));
-
- doSaveAndRestore(fileName,saved);
-}
-
-BOOST_AUTO_TEST_CASE( test_ClockAttr_serialisation )
-{
- cout << "ANattr:: ...test_ClockAttr_serialisation\n";
- {
- ClockAttr saved(false);
- saved.date(1,1,2009);
- saved.set_gain_in_seconds(3600);
- saved.startStopWithServer(true);
-
- doSaveAndRestore(fileName,saved);
- }
- {
- ClockAttr saved(Calendar::second_clock_time());
- doSaveAndRestore(fileName,saved);
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_AutoCancelAttr_serialisation )
-{
- cout << "ANattr:: ...test_AutoCancelAttr_serialisation\n";
- {
- AutoCancelAttr saved(100);
- doSaveAndRestore(fileName,saved);
- }
- {
- AutoCancelAttr saved( TimeSlot(12,10), true) ;
- doSaveAndRestore(fileName,saved);
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_Label_serialisation )
-{
- cout << "ANattr:: ...test_Label_serialisation\n";
- {
- Label saved("labelName","some text");
- doSaveAndRestore(fileName,saved);
- }
-}
-
-
-BOOST_AUTO_TEST_CASE( test_Variable_serialisation )
-{
- cout << "ANattr:: ...test_Variable_serialisation\n";
- Variable saved("varname","var value 123 12 =");
- doSaveAndRestore(fileName,saved);
-}
-
-BOOST_AUTO_TEST_CASE( test_Event_serialisation )
-{
- cout << "ANattr:: ...test_Event_serialisation\n";
- {
- Event saved(3);
- doSaveAndRestore(fileName,saved);
- }
- {
- Event saved(10+1,"event_name");
- doSaveAndRestore(fileName,saved);
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_Meter_serialisation )
-{
- cout << "ANattr:: ...test_Meter_serialisation\n";
- Meter saved("meter",0,20,20);
- doSaveAndRestore(fileName,saved);
-}
-
-
-BOOST_AUTO_TEST_CASE( test_zombie_attr_serialisation )
-{
- cout << "ANattr:: ...test_zombie_attr_serialisation\n";
-
- std::vector<ecf::Child::CmdType> child_cmds;
- child_cmds.push_back(ecf::Child::INIT);
- child_cmds.push_back(ecf::Child::EVENT);
- child_cmds.push_back(ecf::Child::METER);
- child_cmds.push_back(ecf::Child::LABEL);
- child_cmds.push_back(ecf::Child::WAIT);
- child_cmds.push_back(ecf::Child::ABORT);
- child_cmds.push_back(ecf::Child::COMPLETE);
-
- doSaveAndRestore(fileName,ZombieAttr(ecf::Child::USER, child_cmds, ecf::User::FOB,10));
- doSaveAndRestore(fileName,ZombieAttr(ecf::Child::PATH, child_cmds, ecf::User::FAIL,10));
- doSaveAndRestore(fileName,ZombieAttr(ecf::Child::ECF, child_cmds, ecf::User::BLOCK,10));
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ANattr/test/TestCron.cpp b/ecflow_4_0_7/ANattr/test/TestCron.cpp
deleted file mode 100644
index 0d3fb2f..0000000
--- a/ecflow_4_0_7/ANattr/test/TestCron.cpp
+++ /dev/null
@@ -1,439 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #14 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <string>
-#include <iostream>
-#include <fstream>
-#include <boost/test/unit_test.hpp>
-#include <boost/date_time/posix_time/time_formatters.hpp>
-
-#include "CronAttr.hpp"
-#include "TimeSeries.hpp"
-#include "Calendar.hpp"
-#include "Str.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost::posix_time;
-using namespace boost::gregorian;
-
-BOOST_AUTO_TEST_SUITE( ANattrTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_cron_parsing )
-{
- cout << "ANattr:: ...test_cron_parsing\n";
- TimeSlot start(10,10);
- TimeSlot finish(23,10);
- TimeSlot incr(0,1);
-
- {
- CronAttr cron;
- CronAttr parsedCron;
- BOOST_CHECK_MESSAGE(parsedCron.structureEquals(cron),"Expected " << cron.toString() << " but found " << parsedCron.toString());
- }
- {
- CronAttr cron; cron.add_time_series(10,10,false);
- CronAttr parsedCron = CronAttr::create("cron 10:10");
- BOOST_CHECK_MESSAGE(parsedCron.structureEquals(cron),"Expected " << cron.toString() << " but found " << parsedCron.toString());
- }
- {
- CronAttr cron; cron.add_time_series(10,10,true);
- CronAttr parsedCron = CronAttr::create("cron +10:10");
- BOOST_CHECK_MESSAGE(parsedCron.structureEquals(cron),"Expected " << cron.toString() << " but found " << parsedCron.toString());
- }
- {
- CronAttr cron; cron.addTimeSeries(start,finish,incr);
- CronAttr parsedCron = CronAttr::create("cron 10:10 23:10 00:01");
- BOOST_CHECK_MESSAGE(parsedCron.structureEquals(cron),"Expected " << cron.toString() << " but found " << parsedCron.toString());
- }
-
- std::vector<int> week_days;
- week_days.push_back(0);
- week_days.push_back(1);
- week_days.push_back(2);
- week_days.push_back(3);
- week_days.push_back(4);
- week_days.push_back(5);
- week_days.push_back(6);
- {
- CronAttr cron;
- cron.addWeekDays(week_days);
- cron.add_time_series(10,10,true);
- CronAttr parsedCron = CronAttr::create("cron -w 0,1,2,3,4,5,6 +10:10");
- BOOST_CHECK_MESSAGE(parsedCron.structureEquals(cron),"Expected " << cron.toString() << " but found " << parsedCron.toString());
- }
-
- std::vector<int> days_of_month;
- days_of_month.push_back(1);
- days_of_month.push_back(3);
- days_of_month.push_back(4);
- days_of_month.push_back(5);
- days_of_month.push_back(6);
- days_of_month.push_back(24);
- days_of_month.push_back(25);
- {
- CronAttr cron;
- cron.addDaysOfMonth(days_of_month);
- cron.add_time_series(10,10,true);
- CronAttr parsedCron = CronAttr::create("cron -d 1,3,4,5,6,24,25 +10:10");
- BOOST_CHECK_MESSAGE(parsedCron.structureEquals(cron),"Expected " << cron.toString() << " but found " << parsedCron.toString());
- }
-
- std::vector<int> months;
- months.push_back(1);
- months.push_back(2);
- months.push_back(3);
- months.push_back(4);
- months.push_back(5);
- months.push_back(6);
- months.push_back(7);
- months.push_back(8);
- months.push_back(9);
- months.push_back(10);
- months.push_back(11);
- months.push_back(12);
- {
- CronAttr cron;
- cron.addMonths(months);
- cron.add_time_series(10,10,true);
- CronAttr parsedCron = CronAttr::create("cron -m 1,2,3,4,5,6,7,8,9,10,11,12 +10:10");
- BOOST_CHECK_MESSAGE(parsedCron.structureEquals(cron),"Expected " << cron.toString() << " but found " << parsedCron.toString());
- }
-
- {
- CronAttr cron;
- cron.addWeekDays(week_days);
- cron.addDaysOfMonth(days_of_month);
- cron.addMonths(months);
- cron.addTimeSeries(start,finish,incr);
- CronAttr parsedCron = CronAttr::create("cron -w 0,1,2,3,4,5,6 -d 1,3,4,5,6,24,25 -m 1,2,3,4,5,6,7,8,9,10,11,12 10:10 23:10 00:01");
- BOOST_CHECK_MESSAGE(parsedCron.structureEquals(cron),"Expected " << cron.toString() << " but found " << parsedCron.toString());
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_cron_state_parsing )
-{
- cout << "ANattr:: ...test_cron_state_parsing\n";
-
- size_t index = 1; // to get over the cron
- {
- std::string line = "cron 04:30 # isValid:false";
- std::vector<std::string> lineTokens;
- Str::split(line,lineTokens);
- bool parse_state = true;
- CronAttr parsed_cronAttr;
- CronAttr::parse( parsed_cronAttr,lineTokens, index, parse_state);
-
- CronAttr expected;
- TimeSeries series(4,30);
- series.set_isValid(false); // to match isValid:false
- expected.addTimeSeries(series);
- BOOST_CHECK_MESSAGE(parsed_cronAttr == expected,"Expected " << expected.dump() << " : " << expected.time().dump()
- << " but found " << parsed_cronAttr.dump() << " : " << parsed_cronAttr.time().dump());
- }
-
- {
- std::string line = "cron 04:30 # free isValid:false";
- std::vector<std::string> lineTokens;
- Str::split(line,lineTokens);
- bool parse_state = true;
- CronAttr parsed_cronAttr;
- CronAttr::parse( parsed_cronAttr,lineTokens, index, parse_state);
-
- CronAttr expected;
- TimeSeries series(4,30);
- series.set_isValid(false); // to match isValid:false
- expected.addTimeSeries(series);
- expected.setFree();
- BOOST_CHECK_MESSAGE(parsed_cronAttr == expected,"Expected " << expected.dump() << " : " << expected.time().dump()
- << " but found " << parsed_cronAttr.dump() << " : " << parsed_cronAttr.time().dump());
- }
-
- {
- std::string line = "cron 00:01 23:59 01:00 # nextTimeSlot/12:01";
- std::vector<std::string> lineTokens;
- Str::split(line,lineTokens);
- bool parse_state = true;
- CronAttr parsed_cronAttr;
- CronAttr::parse( parsed_cronAttr,lineTokens, index, parse_state);
-
- CronAttr expected;
- TimeSlot start(0,1);
- TimeSlot finish(23,59);
- TimeSlot incr(1,0);
- TimeSeries series(start, finish,incr);
- series.set_next_time_slot(TimeSlot(12,1));
- expected.addTimeSeries(series);
- BOOST_CHECK_MESSAGE(parsed_cronAttr == expected,"Expected " << expected.dump() << " : " << expected.time().dump()
- << " but found " << parsed_cronAttr.dump() << " : " << parsed_cronAttr.time().dump());
- }
-
- {
- std::string line = "cron 00:01 23:59 01:00 # free nextTimeSlot/12:01";
- std::vector<std::string> lineTokens;
- Str::split(line,lineTokens);
- bool parse_state = true;
- CronAttr parsed_cronAttr;
- CronAttr::parse( parsed_cronAttr,lineTokens, index, parse_state);
-
- CronAttr expected;
- TimeSlot start(0,1);
- TimeSlot finish(23,59);
- TimeSlot incr(1,0);
- TimeSeries series(start, finish,incr);
- series.set_next_time_slot(TimeSlot(12,1));
- expected.addTimeSeries(series);
- expected.setFree();
- BOOST_CHECK_MESSAGE(parsed_cronAttr == expected,"Expected " << expected.dump() << " : " << expected.time().dump()
- << " but found " << parsed_cronAttr.dump() << " : " << parsed_cronAttr.time().dump());
- }
- {
- std::string line = "cron 00:00 18:00 06:00 # isValid:false nextTimeSlot/24:00";
- std::vector<std::string> lineTokens;
- Str::split(line,lineTokens);
- bool parse_state = true;
- CronAttr parsed_cronAttr;
- CronAttr::parse( parsed_cronAttr,lineTokens, index, parse_state);
-
- CronAttr expected;
- TimeSlot start(0,0);
- TimeSlot finish(18,0);
- TimeSlot incr(6,0);
- TimeSeries series(start, finish,incr);
- series.set_next_time_slot(TimeSlot(24,0));
- series.set_isValid(false); // to match isValid:false
- expected.addTimeSeries(series);
- BOOST_CHECK_MESSAGE(parsed_cronAttr == expected,"Expected " << expected.dump() << " : " << expected.time().dump()
- << " but found " << parsed_cronAttr.dump() << " : " << parsed_cronAttr.time().dump());
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_cron_once_free_stays_free)
-{
- cout << "ANattr:: ...test_cron_once_free_stays_free\n";
-
- Calendar calendar;
- calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::REAL);
-
- TimeSeries timeSeriesX(TimeSlot(10,0), TimeSlot(20,0), TimeSlot(1,0), false/* relative */);
- TimeSeries timeSeries2X(TimeSlot(11,0), TimeSlot(15,0), TimeSlot(1,0), false/* relative */);
- TimeSeries timeSeries3X(TimeSlot(15,0), false/* relative */);
- TimeSeries timeSeries4X(TimeSlot(0,0), false/* relative */);
-
- CronAttr timeSeries; timeSeries.addTimeSeries(timeSeriesX );
- CronAttr timeSeries2; timeSeries2.addTimeSeries(timeSeries2X );
- CronAttr timeSeries3; timeSeries3.addTimeSeries(timeSeries3X );
- CronAttr timeSeries4; timeSeries4.addTimeSeries(timeSeries4X );
-
- std::vector<boost::posix_time::time_duration> timeSeries_free_slots;
- std::vector<boost::posix_time::time_duration> timeSeries2_free_slots;
- timeSeries.time_series().free_slots(timeSeries_free_slots);
- timeSeries2.time_series().free_slots(timeSeries2_free_slots);
- BOOST_CHECK_MESSAGE(timeSeries_free_slots.size() == 11,"Expected 11 free slots for " << timeSeries.toString() << " but found " << timeSeries_free_slots.size());
- BOOST_CHECK_MESSAGE(timeSeries2_free_slots.size() == 5,"Expected 5 free slots for " << timeSeries2.toString() << " but found " << timeSeries_free_slots.size());
-
- bool day_changed = false; // after midnight make sure we keep day_changed
- for(int m=1; m < 96; m++) {
- calendar.update( time_duration( minutes(30) ) );
- if (!day_changed) {
- day_changed = calendar.dayChanged();
- }
- boost::posix_time::time_duration time = calendar.suiteTime().time_of_day();
- // cout << time << " day_changed(" << day_changed << ")\n";
-
- timeSeries.calendarChanged( calendar );
- timeSeries2.calendarChanged( calendar );
- timeSeries3.calendarChanged( calendar );
- timeSeries4.calendarChanged( calendar );
-
- // cron should always reque regardless of time series
- BOOST_CHECK_MESSAGE(timeSeries.checkForRequeue(calendar),timeSeries.toString() << " checkForRequeue should be true at time " << time );
- BOOST_CHECK_MESSAGE(timeSeries2.checkForRequeue(calendar),timeSeries2.toString() << " checkForRequeue should be true at time " << time );
- BOOST_CHECK_MESSAGE(timeSeries3.checkForRequeue(calendar),timeSeries3.toString() << " checkForRequeue should be true at time " << time );
- BOOST_CHECK_MESSAGE(timeSeries4.checkForRequeue(calendar),timeSeries4.toString() << " checkForRequeue should be true at time " << time );
-
- // **********************************************************************************
- // When a cron (regardless of whether its single slot or time series) is free, it stays free,
- // until explicitly re-queued,
- // ***********************************************************************************
-
- if (time < timeSeries.time_series().start().duration()) {
- if (!day_changed) BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar),timeSeries.toString() << " should NOT be free at time " << time );
- else BOOST_CHECK_MESSAGE(timeSeries.isFree(calendar),timeSeries.toString() << " should be free at time " << time );
- }
- else if (time >= timeSeries.time_series().start().duration()) {
- BOOST_CHECK_MESSAGE(timeSeries.isFree(calendar),timeSeries.toString() << " should be free at time " << time );
- }
-
-
- if (time < timeSeries2.time_series().start().duration()) {
- if (!day_changed) BOOST_CHECK_MESSAGE(!timeSeries2.isFree(calendar),timeSeries2.toString() << " should NOT be free at time " << time );
- else BOOST_CHECK_MESSAGE(timeSeries.isFree(calendar),timeSeries.toString() << " should be free at time " << time );
- }
- else if (time >= timeSeries2.time_series().start().duration()) {
- BOOST_CHECK_MESSAGE(timeSeries2.isFree(calendar),timeSeries2.toString() << " should be free at time " << time );
- }
-
- if (!day_changed) {
- if (time == timeSeries3.time_series().start().duration() ) {
- BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries3.toString() << " should be free at time " << time );
- }
- else if (time > timeSeries3.time_series().start().duration()) {
- BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries3.toString() << " isFree, once free should stay free at time " << time );
- }
- }
- else {
- BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries3.toString() << " should be free at time after day change " << time );
- }
-
-
- // single slot at midnight, Once a single slot if Free it *stays* free until explicitly requeued, (i.e by parent repeat/cron)
- if (!day_changed) {
- if (time == timeSeries4.time_series().start().duration() ) {
- BOOST_CHECK_MESSAGE(timeSeries4.isFree(calendar),timeSeries4.toString() << " should be free at time " << time );
- }
- else {
- BOOST_CHECK_MESSAGE(!timeSeries4.isFree(calendar),timeSeries4.toString() << " day_changed(" << day_changed << ") isFree should fail at time " << time );
- }
- }
- else {
- BOOST_CHECK_MESSAGE(timeSeries4.isFree(calendar),timeSeries4.toString() << " day_changed(" << day_changed << ") isFree should pass at time " << time );
- }
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_cron_time_series)
-{
- cout << "ANattr:: ...test_cron_time_series\n";
-
- // See TimeAttr.hpp for rules concerning isFree() and checkForReque()
- // test time attr isFree(), and checkForRequeue
- Calendar calendar;
- calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::REAL);
-
- TimeSeries timeSeriesX(TimeSlot(10,0), TimeSlot(20,0), TimeSlot(1,0), false/* relative */);
- TimeSeries timeSeries2X(TimeSlot(11,0), TimeSlot(15,0), TimeSlot(1,0), false/* relative */);
- TimeSeries timeSeries3X(TimeSlot(15,0), false/* relative */);
- TimeSeries timeSeries4X(TimeSlot(0,0), false/* relative */);
-
- CronAttr timeSeries; timeSeries.addTimeSeries(timeSeriesX );
- CronAttr timeSeries2; timeSeries2.addTimeSeries(timeSeries2X );
- CronAttr timeSeries3; timeSeries3.addTimeSeries(timeSeries3X );
- CronAttr timeSeries4; timeSeries4.addTimeSeries(timeSeries4X );
-
- std::vector<boost::posix_time::time_duration> timeSeries_free_slots;
- std::vector<boost::posix_time::time_duration> timeSeries2_free_slots;
- timeSeries.time_series().free_slots(timeSeries_free_slots);
- timeSeries2.time_series().free_slots(timeSeries2_free_slots);
- BOOST_CHECK_MESSAGE(timeSeries_free_slots.size() == 11,"Expected 11 free slots for " << timeSeries.toString() << " but found " << timeSeries_free_slots.size());
- BOOST_CHECK_MESSAGE(timeSeries2_free_slots.size() == 5,"Expected 5 free slots for " << timeSeries2.toString() << " but found " << timeSeries_free_slots.size());
-
- bool day_changed = false; // after midnight make sure we keep day_changed
- for(int m=1; m < 96; m++) {
- calendar.update( time_duration( minutes(30) ) );
- if (!day_changed) {
- day_changed = calendar.dayChanged();
- }
- boost::posix_time::time_duration time = calendar.suiteTime().time_of_day();
-// cout << time << " day_changed(" << day_changed << ")\n";
-
- timeSeries.calendarChanged( calendar );
- timeSeries2.calendarChanged( calendar );
- timeSeries3.calendarChanged( calendar );
- timeSeries4.calendarChanged( calendar );
-
- // cron should always reque regardless of time series
- BOOST_CHECK_MESSAGE(timeSeries.checkForRequeue(calendar),timeSeries.toString() << " checkForRequeue should be true at time " << time );
- BOOST_CHECK_MESSAGE(timeSeries2.checkForRequeue(calendar),timeSeries2.toString() << " checkForRequeue should be true at time " << time );
- BOOST_CHECK_MESSAGE(timeSeries3.checkForRequeue(calendar),timeSeries3.toString() << " checkForRequeue should be true at time " << time );
- BOOST_CHECK_MESSAGE(timeSeries4.checkForRequeue(calendar),timeSeries4.toString() << " checkForRequeue should be true at time " << time );
-
- // **********************************************************************************
- // When a cron (regardless of whether its single slot or time series) is free, it stays free
- // However in order to test crons with time series, we will re-queue ate the end of this loop
- // ***********************************************************************************
-
- if (time < timeSeries.time_series().start().duration()) {
- BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar),timeSeries.toString() << " should NOT be free at time " << time );
- }
- else if (time >= timeSeries.time_series().start().duration() && time <=timeSeries.time_series().finish().duration()) {
-
- bool matches_free_slot = false;
- for(size_t i = 0; i < timeSeries_free_slots.size(); i++) {
- if (time == timeSeries_free_slots[i]) { matches_free_slot = true; break; }
- }
- if (matches_free_slot) BOOST_CHECK_MESSAGE(timeSeries.isFree(calendar),timeSeries.toString() << " should be free at time " << time );
- else BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar),timeSeries.toString() << " should be fail at time " << time );
- }
- else {
- BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar),timeSeries.toString() << " should be holding at time " << time );
- }
-
-
- if (time < timeSeries2.time_series().start().duration()) {
- BOOST_CHECK_MESSAGE(!timeSeries2.isFree(calendar),timeSeries2.toString() << " should NOT be free at time " << time );
- }
- else if (time >= timeSeries2.time_series().start().duration() && time <=timeSeries2.time_series().finish().duration()) {
-
- bool matches_free_slot = false;
- for(size_t i = 0; i < timeSeries2_free_slots.size(); i++) {
- if (time == timeSeries2_free_slots[i]) { matches_free_slot = true; break;}
- }
- if (matches_free_slot) BOOST_CHECK_MESSAGE(timeSeries2.isFree(calendar),timeSeries2.toString() << " should be free at time " << time );
- else BOOST_CHECK_MESSAGE(!timeSeries2.isFree(calendar),timeSeries2.toString() << " should be fail at time " << time );
- }
- else {
- BOOST_CHECK_MESSAGE(!timeSeries2.isFree(calendar),timeSeries2.toString() << " should be holding at time " << time );
- }
-
-
- // Single slot, Once a single slot if Free it *stays* free until explicitly requeued, (i.e by parent repeat/cron)
- if (!day_changed) {
- if (time == timeSeries3.time_series().start().duration() ) {
- BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries3.toString() << " should be free at time " << time );
- }
- else if (time > timeSeries3.time_series().start().duration()) {
- BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries3.toString() << " isFree, once free should stay free at time " << time );
- }
- }
- else {
- BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries3.toString() << " should be free at time after day change " << time );
- }
-
-
- // single slot at midnight, Once a single slot if Free it *stays* free until explicitly requeued, (i.e by parent repeat/cron)
- if (!day_changed) {
- if (time == timeSeries4.time_series().start().duration() ) {
- BOOST_CHECK_MESSAGE(timeSeries4.isFree(calendar),timeSeries4.toString() << " should be free at time " << time );
- }
- else {
- BOOST_CHECK_MESSAGE(!timeSeries4.isFree(calendar),timeSeries4.toString() << " day_changed(" << day_changed << ") isFree should fail at time " << time );
- }
- }
- else {
- BOOST_CHECK_MESSAGE(timeSeries4.isFree(calendar),timeSeries4.toString() << " day_changed(" << day_changed << ") isFree should pass at time " << time );
- }
-
- // Typically when a cron is free, it stays free, until it is re-queued
- // However in order to test isFree for cron with time inetrvals, we need to re-queue
- timeSeries.requeue( calendar );
- timeSeries2.requeue( calendar );
-
- // Do not requeue cron 00, and cron 15, so that we can check for free
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/ANattr/test/TestDayAttr.cpp b/ecflow_4_0_7/ANattr/test/TestDayAttr.cpp
deleted file mode 100644
index 0f00de3..0000000
--- a/ecflow_4_0_7/ANattr/test/TestDayAttr.cpp
+++ /dev/null
@@ -1,78 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #14 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <string>
-#include <iostream>
-#include <fstream>
-#include <boost/test/unit_test.hpp>
-#include <boost/date_time/posix_time/time_formatters.hpp>
-
-#include "DayAttr.hpp"
-#include "Calendar.hpp"
-#include "Str.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost::posix_time;
-using namespace boost::gregorian;
-
-BOOST_AUTO_TEST_SUITE( ANattrTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_day_attr)
-{
- cout << "ANattr:: ...test_day_attr\n";
-
- // See TimeAttr.hpp for rules concerning isFree() and checkForReque()
- // test time attr isFree(), and checkForRequeue
- Calendar calendar;
- calendar.init(ptime(date(2013,7,9), minutes(0)), Calendar::REAL); // tuesday
-
- // Represent a day within a week (range 0==Sun to 6==Sat)
- BOOST_CHECK_MESSAGE(calendar.day_of_week() == 2 ," Expected tuesday(2) but found " << calendar.day_of_week() );
-
- DayAttr day(DayAttr::WEDNESDAY);
-
- int day_changed = 0; // after midnight make sure we keep day_changed
- // day_changed = 0; tuesday
- // day_changed = 1; wednesday
- // day_changed = 3; thursday
- for(int m=1; m < 96; m++) {
- calendar.update( time_duration( hours(1) ) );
- if (calendar.dayChanged()) day_changed++;
-
- // cout << " day_changed(" << day_changed << ") calendar.day_of_week() = " << calendar.day_of_week() << "\n";
-
- day.calendarChanged( calendar );
-
- if ( calendar.day_of_week() < day.day() ) {
- BOOST_CHECK_MESSAGE(!day.isFree(calendar),day.toString() << " is free should fail at day " << calendar.day_of_week() );
- BOOST_CHECK_MESSAGE(day.checkForRequeue(calendar),day.toString() << " checkForRequeue should pass at " << calendar.day_of_week() );
- }
- else if (calendar.day_of_week() == day.day() ) {
- BOOST_CHECK_MESSAGE(day.isFree(calendar),day.toString() << " is free should pass at day " << calendar.day_of_week() );
- BOOST_CHECK_MESSAGE(!day.checkForRequeue(calendar),day.toString() << " checkForRequeue should fail at " << calendar.day_of_week() );
- }
- else {
- BOOST_CHECK_MESSAGE(calendar.day_of_week() > day.day(),"");
- // *** once free , should *stay* free, until explicitly re-queued
- BOOST_CHECK_MESSAGE(day.isFree(calendar),day.toString() << " is free should pass at day " << calendar.day_of_week() );
- BOOST_CHECK_MESSAGE(!day.checkForRequeue(calendar),day.toString() << " checkForRequeue should fail at " << calendar.day_of_week() );
- }
- }
-}
-
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/ANattr/test/TestLabel.cpp b/ecflow_4_0_7/ANattr/test/TestLabel.cpp
deleted file mode 100644
index 8c69de1..0000000
--- a/ecflow_4_0_7/ANattr/test/TestLabel.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #14 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <string>
-#include <iostream>
-#include <fstream>
-#include <boost/test/unit_test.hpp>
-
-#include "NodeAttr.hpp"
-#include "Str.hpp"
-
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( ANattrTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_label_parsing )
-{
- cout << "ANattr:: ...test_label_parsing\n";
- {
- std::string line = "label name \"value\"";
- std::vector<string> linetokens;
- Str::split(line,linetokens);
-
- Label label;
- label.parse(line,linetokens, false);
-
- Label expected("name","value");
- BOOST_CHECK_MESSAGE(label == expected,"Expected " << expected.toString() << " but found " << label.toString());
- BOOST_CHECK_MESSAGE(label.dump() == expected.dump(),"Expected " << expected.dump() << " but found " << label.dump());
- }
- {
- std::string line = "label name \"value\\nvalue\"";
- std::vector<string> linetokens;
- Str::split(line,linetokens);
-
- Label label;
- label.parse(line,linetokens, false);
-
- Label expected("name","value\nvalue");
- BOOST_CHECK_MESSAGE(label == expected,"Expected " << expected.toString() << " but found " << label.toString());
- BOOST_CHECK_MESSAGE(label.dump() == expected.dump(),"Expected " << expected.dump() << " but found " << label.dump());
- }
- {
- std::string line = "label name \"value that is multiple token !!!! 23445 !^ & * ( )\"";
- std::vector<string> linetokens;
- Str::split(line,linetokens);
-
- Label label;
- label.parse(line,linetokens, false);
-
- Label expected("name","value that is multiple token !!!! 23445 !^ & * ( )");
- BOOST_CHECK_MESSAGE(label == expected,"Expected " << expected.toString() << " but found " << label.toString());
- BOOST_CHECK_MESSAGE(label.dump() == expected.dump(),"Expected " << expected.dump() << " but found " << label.dump());
- }
- {
- std::string line = "label name \"value\\n that\\n is\\n multiple\\n token\\n and\\n new\\n \\nlines\"";
- std::vector<string> linetokens;
- Str::split(line,linetokens);
-
- Label label;
- label.parse(line,linetokens, false);
-
- Label expected("name","value\n that\n is\n multiple\n token\n and\n new\n \nlines");
- BOOST_CHECK_MESSAGE(label == expected,"Expected " << expected.toString() << " but found " << label.toString());
- BOOST_CHECK_MESSAGE(label.dump() == expected.dump(),"Expected " << expected.dump() << " but found " << label.dump());
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/ANattr/test/TestMigration.cpp b/ecflow_4_0_7/ANattr/test/TestMigration.cpp
deleted file mode 100644
index 6c6e14e..0000000
--- a/ecflow_4_0_7/ANattr/test/TestMigration.cpp
+++ /dev/null
@@ -1,185 +0,0 @@
-#if defined(TEXT_ARCHIVE) || !defined(BINARY_ARCHIVE) && !defined(PORTABLE_BINARY_ARCHIVE) && !defined(EOS_PORTABLE_BINARY_ARCHIVE)
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #13 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <boost/test/unit_test.hpp>
-
-#include "TodayAttr.hpp"
-#include "TimeAttr.hpp"
-#include "VerifyAttr.hpp"
-#include "RepeatAttr.hpp"
-#include "LateAttr.hpp"
-#include "DayAttr.hpp"
-#include "DateAttr.hpp"
-#include "CronAttr.hpp"
-#include "ClockAttr.hpp"
-#include "AutoCancelAttr.hpp"
-#include "NodeAttr.hpp"
-#include "Variable.hpp"
-#include "ZombieAttr.hpp"
-#include "Calendar.hpp"
-#include "SerializationTest.hpp"
-#include "TimeSeries.hpp"
-#include "File.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost::posix_time;
-using namespace boost::gregorian;
-namespace fs = boost::filesystem;
-
-//#define UPDATE_TESTS 1
-
-
-BOOST_AUTO_TEST_SUITE( ANattrTestSuite )
-
-// These test are used for future release. They help to ensure that we have
-// backward compatibility.i.e future release can open file, created by an earlier release
-//
-BOOST_AUTO_TEST_CASE( test_migration_restore_def_con )
-{
- cout << "ANattr:: ...test_migration_restore_def_con\n";
-
- std::string file_name = File::test_data("ANattr/test/data/migration/default_constructor_v1_9/","ANattr");
-
- // Create migration data
-#ifdef UPDATE_TESTS
- doSave(file_name + "VerifyAttr",VerifyAttr());
- doSave(file_name + "TodayAttr",TodayAttr());
- doSave(file_name + "TimeAttr",TimeAttr());
- doSave(file_name + "RepeatDate",RepeatDate());
- doSave(file_name + "RepeatInteger",RepeatInteger());
- doSave(file_name + "RepeatEnumerated",RepeatEnumerated());
- doSave(file_name + "RepeatString",RepeatString());
- doSave(file_name + "LateAttr",LateAttr());
- doSave(file_name + "DayAttr",DayAttr());
- doSave(file_name + "DateAttr",DateAttr());
- doSave(file_name + "CronAttr",CronAttr());
- doSave(file_name + "ClockAttr",ClockAttr());
- doSave(file_name + "AutoCancelAttr",AutoCancelAttr());
- doSave(file_name + "Label",Label());
- doSave(file_name + "Variable",Variable());
- doSave(file_name + "Event",Event());
- doSave(file_name + "Meter",Meter());
- doSave(file_name + "ZombieAttr",ZombieAttr());
-#endif
-
- do_restore<VerifyAttr>(file_name + "VerifyAttr",VerifyAttr());
- do_restore<TodayAttr>(file_name + "TodayAttr",TodayAttr());
- do_restore<TimeAttr>(file_name + "TimeAttr",TimeAttr());
- do_restore<RepeatDate>(file_name + "RepeatDate",RepeatDate());
- do_restore<RepeatInteger>(file_name + "RepeatInteger",RepeatInteger());
- do_restore<RepeatEnumerated>(file_name + "RepeatEnumerated",RepeatEnumerated());
- do_restore<RepeatString>(file_name + "RepeatString",RepeatString());
- do_restore<LateAttr>(file_name + "LateAttr",LateAttr());
- do_restore<DayAttr>(file_name + "DayAttr",DayAttr());
- do_restore<DateAttr>(file_name + "DateAttr",DateAttr());
- do_restore<CronAttr>(file_name + "CronAttr",CronAttr());
- do_restore<AutoCancelAttr>(file_name + "AutoCancelAttr",AutoCancelAttr());
- do_restore<Label>(file_name + "Label",Label());
- do_restore<Variable>(file_name + "Variable",Variable());
- do_restore<Event>(file_name + "Event",Event());
- do_restore<Meter>(file_name + "Meter",Meter());
- do_restore<ZombieAttr>(file_name + "ZombieAttr",ZombieAttr());
-}
-
-BOOST_AUTO_TEST_CASE( test_migration_restore )
-{
- cout << "ANattr:: ...test_migration_restore\n";
-
- std::string file_name = File::test_data("ANattr/test/data/migration/v1_9/","ANattr");
-
- std::vector<std::string> theVec; theVec.push_back("a"); theVec.push_back("b");
- LateAttr lateattr;
- lateattr.addSubmitted(TimeSlot(10,12));
- lateattr.addActive(TimeSlot(10,12));
- lateattr.addComplete(TimeSlot(10,12),true);
-
- CronAttr cron_attr;
- std::vector<int> weekDays; weekDays.push_back(1); weekDays.push_back(2);
- std::vector<int> daysOfMonth; daysOfMonth.push_back(1); daysOfMonth.push_back(2);
- std::vector<int> months; months.push_back(1); months.push_back(2);
- cron_attr.addWeekDays(weekDays);
- cron_attr.addDaysOfMonth(daysOfMonth);
- cron_attr.addMonths(months);
- cron_attr.addTimeSeries(TimeSlot(0,0),TimeSlot(20,0),TimeSlot(0,1));
-
- ClockAttr clock_attr(false);
- clock_attr.date(1,1,2009);
- clock_attr.set_gain_in_seconds(3600);
- clock_attr.startStopWithServer(true);
-
- std::vector<ecf::Child::CmdType> child_cmds;
- child_cmds.push_back(ecf::Child::INIT);
- child_cmds.push_back(ecf::Child::EVENT);
- child_cmds.push_back(ecf::Child::METER);
- child_cmds.push_back(ecf::Child::LABEL);
- child_cmds.push_back(ecf::Child::WAIT);
- child_cmds.push_back(ecf::Child::ABORT);
- child_cmds.push_back(ecf::Child::COMPLETE);
-
- Label label("name","value");
- label.set_new_value("new_value");
-
-#ifdef UPDATE_TESTS
- // Create migration data
- doSave(file_name + "VerifyAttr",VerifyAttr(NState::COMPLETE,3));
- doSave(file_name + "TodayAttr",TodayAttr(10,12));
- doSave(file_name + "TimeAttr",TimeAttr(10,12));
- doSave(file_name + "RepeatDate",RepeatDate("date",20110112,20110115));
- doSave(file_name + "RepeatInteger",RepeatInteger("integer",0,100,2));
- doSave(file_name + "RepeatEnumerated",RepeatEnumerated("enum",theVec));
- doSave(file_name + "RepeatString",RepeatString("string",theVec));
- doSave(file_name + "LateAttr",lateattr);
- doSave(file_name + "DayAttr",DayAttr(DayAttr::MONDAY));
- doSave(file_name + "DateAttr",DateAttr(12,12,2012));
- doSave(file_name + "CronAttr",cron_attr);
- doSave(file_name + "ClockAttr",clock_attr);
- doSave(file_name + "AutoCancelAttr",AutoCancelAttr(100));
- doSave(file_name + "AutoCancelAttr_1",AutoCancelAttr(TimeSlot(10,12),true));
- doSave(file_name + "Label",label);
-// doSave(file_name + "Limit",limit);
- doSave(file_name + "Variable",Variable("var_name","var_value"));
- doSave(file_name + "Event_1",Event(1));
- doSave(file_name + "Event_2",Event("event"));
- doSave(file_name + "Meter",Meter("meter",10,100,100));
- doSave(file_name + "ZombieAttr",ZombieAttr(ecf::Child::USER, child_cmds, ecf::User::FOB,10));
-#endif
-
- do_restore<VerifyAttr>(file_name + "VerifyAttr",VerifyAttr(NState::COMPLETE,3));
- do_restore<TodayAttr>(file_name + "TodayAttr",TodayAttr(10,12));
- do_restore<TimeAttr>(file_name + "TimeAttr",TimeAttr(10,12));
- do_restore<RepeatDate>(file_name + "RepeatDate",RepeatDate("date",20110112,20110115));
- do_restore<RepeatInteger>(file_name + "RepeatInteger",RepeatInteger("integer",0,100,2));
- do_restore<RepeatEnumerated>(file_name + "RepeatEnumerated",RepeatEnumerated("enum",theVec));
- do_restore<RepeatString>(file_name + "RepeatString",RepeatString("string",theVec));
- do_restore<LateAttr>(file_name + "LateAttr",lateattr);
- do_restore<DayAttr>(file_name + "DayAttr",DayAttr(DayAttr::MONDAY));
- do_restore<DateAttr>(file_name + "DateAttr",DateAttr(12,12,2012));
- do_restore<CronAttr>(file_name + "CronAttr",cron_attr);
- do_restore<ClockAttr>(file_name + "ClockAttr",clock_attr);
- do_restore<AutoCancelAttr>(file_name + "AutoCancelAttr",AutoCancelAttr(100));
- do_restore<AutoCancelAttr>(file_name + "AutoCancelAttr_1",AutoCancelAttr(TimeSlot(10,12),true));
- do_restore<Label>(file_name + "Label",label);
- do_restore<Variable>(file_name + "Variable",Variable("var_name","var_value"));
- do_restore<Event>(file_name + "Event_1",Event(1));
- do_restore<Event>(file_name + "Event_2",Event("event"));
- do_restore<Meter>(file_name + "Meter",Meter("meter",10,100,100));
- do_restore<ZombieAttr>(file_name + "ZombieAttr",ZombieAttr(ecf::Child::USER, child_cmds, ecf::User::FOB,10));
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-#endif
diff --git a/ecflow_4_0_7/ANattr/test/TestRepeat.cpp b/ecflow_4_0_7/ANattr/test/TestRepeat.cpp
deleted file mode 100644
index 3018fb0..0000000
--- a/ecflow_4_0_7/ANattr/test/TestRepeat.cpp
+++ /dev/null
@@ -1,425 +0,0 @@
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #16 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <boost/test/unit_test.hpp>
-
-#include "RepeatAttr.hpp"
-
-using namespace std;
-
-BOOST_AUTO_TEST_SUITE( ANattrTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_repeat_invariants )
-{
- cout << "ANattr:: ...test_repeat_invariants\n";
-
- std::vector<std::string> stringList; stringList.reserve(3);
- stringList.push_back("a");
- stringList.push_back("b");
- stringList.push_back("c");
-
- // Test the invariant that Non empty repeat must have a name
- {
- Repeat empty;
- Repeat empty2;
- BOOST_CHECK_MESSAGE(empty.empty(),"Construction");
- BOOST_CHECK_MESSAGE(empty.name().empty(),"Construction");
- BOOST_CHECK_MESSAGE(empty == empty2,"Equality failed");
- }
- {
- Repeat rep(RepeatDate("YMD",20090916,20090930,1));
- BOOST_CHECK_MESSAGE(!rep.empty()," Repeat should not be empty");
- BOOST_CHECK_MESSAGE(!rep.name().empty(),"name should not be empty");
- BOOST_CHECK_MESSAGE(rep.name() == "YMD","name not as expected");
- BOOST_CHECK_MESSAGE(rep.start() == 20090916,"Start should be 20090916");
- BOOST_CHECK_MESSAGE(rep.end() == 20090930,"end should be 20090930");
- BOOST_CHECK_MESSAGE(rep.step() == 1,"step should be 1");
- BOOST_CHECK_MESSAGE(rep.value() == 20090916,"value should be 20090916");
- BOOST_CHECK_MESSAGE(rep.last_valid_value() == 20090916,"last_valid_value should be 20090916");
-
- Repeat cloned = Repeat(rep);
- BOOST_CHECK_MESSAGE(cloned == rep,"Equality failed");
- BOOST_CHECK_MESSAGE(cloned.name() == "YMD","not as expected");
- BOOST_CHECK_MESSAGE(cloned.start() == 20090916,"not as expected");
- BOOST_CHECK_MESSAGE(cloned.end() == 20090930,"not as expected");
- BOOST_CHECK_MESSAGE(cloned.step() == 1,"not as expected");
- BOOST_CHECK_MESSAGE(cloned.value() == 20090916,"not as expected");
- BOOST_CHECK_MESSAGE(cloned.valueAsString() == "20090916","not as expected");
- BOOST_CHECK_MESSAGE(cloned.last_valid_value() == 20090916,"last_valid_value should be 20090916");
-
- RepeatDate empty;
- BOOST_CHECK_MESSAGE(empty.start() == 0,"Start should be 0");
- BOOST_CHECK_MESSAGE(empty.end() == 0,"end should be 0");
- BOOST_CHECK_MESSAGE(empty.step() == 0,"step should be 0");
- BOOST_CHECK_MESSAGE(empty.value() == 0,"delta should be 0");
- BOOST_CHECK_MESSAGE(empty.name().empty(),"name should be empty");
- BOOST_CHECK_MESSAGE(empty.name() == "","name not as expected");
- }
- {
- Repeat rep(RepeatDate("YMD",20090916,20090916,1));
- BOOST_CHECK_MESSAGE(rep.start() == 20090916,"Start should be 20090916");
- BOOST_CHECK_MESSAGE(rep.end() == 20090916,"end should be 20090916");
- BOOST_CHECK_MESSAGE(rep.step() == 1,"step should be 1");
- BOOST_CHECK_MESSAGE(rep.value() == 20090916,"value should be 20090916");
- BOOST_CHECK_MESSAGE(rep.last_valid_value() == 20090916,"delta should be 20090916");
- rep.increment();
- BOOST_CHECK_MESSAGE(!rep.valid(),"RepeatDate should not be valid");
- BOOST_CHECK_MESSAGE(rep.value() == 20090917,"value should be 20090916");
- BOOST_CHECK_MESSAGE(rep.last_valid_value() == 20090916,"last_valid_value should be 20090916");
- }
-
-
- {
- Repeat rep(RepeatEnumerated("AEnum",stringList));
- BOOST_CHECK_MESSAGE(!rep.empty()," Repeat should not be empty");
- BOOST_CHECK_MESSAGE(!rep.name().empty(),"name should not be empty");
- BOOST_CHECK_MESSAGE(rep.name() == "AEnum","name not as expected");
-
- Repeat cloned = Repeat(rep);
- BOOST_CHECK_MESSAGE(cloned == rep,"Equality failed");
- BOOST_CHECK_MESSAGE(cloned.name() == "AEnum","not as expected");
- BOOST_CHECK_MESSAGE(cloned.start() == 0,"not as expected");
- BOOST_CHECK_MESSAGE(cloned.step() == 1,"not as expected");
- BOOST_CHECK_MESSAGE(cloned.value() == 0,"not as expected");
- BOOST_CHECK_MESSAGE(cloned.valueAsString() == "a","not as expected");
-
- RepeatEnumerated empty;
- BOOST_CHECK_MESSAGE(empty.start() == 0,"Start should be 0");
- BOOST_CHECK_MESSAGE(empty.end() == 0,"end should be 0");
- BOOST_CHECK_MESSAGE(empty.step() == 1,"default step should be 1");
- BOOST_CHECK_MESSAGE(empty.value() == 0,"delta should be 0");
- BOOST_CHECK_MESSAGE(empty.name().empty(),"name should be empty");
- BOOST_CHECK_MESSAGE(empty.name() == "","name not as expected");
- }
- {
- Repeat rep(RepeatInteger("rep",0,100,1));
- BOOST_CHECK_MESSAGE(!rep.empty()," Repeat should not be empty");
- BOOST_CHECK_MESSAGE(!rep.name().empty(),"name should not be empty");
- BOOST_CHECK_MESSAGE(rep.name() == "rep","name not as expected");
-
- Repeat cloned = Repeat(rep);
- BOOST_CHECK_MESSAGE(cloned == rep,"Equality failed");
- BOOST_CHECK_MESSAGE(cloned.name() == "rep","not as expected");
- BOOST_CHECK_MESSAGE(cloned.start() == 0,"not as expected");
- BOOST_CHECK_MESSAGE(cloned.end() == 100,"not as expected");
- BOOST_CHECK_MESSAGE(cloned.step() == 1,"not as expected");
- BOOST_CHECK_MESSAGE(cloned.value() == 0,"not as expected");
-
- RepeatInteger empty;
- BOOST_CHECK_MESSAGE(empty.start() == 0,"Start should be 0");
- BOOST_CHECK_MESSAGE(empty.end() == 0,"end should be 0");
- BOOST_CHECK_MESSAGE(empty.step() == 0,"default step should be 0 but found" << empty.step());
- BOOST_CHECK_MESSAGE(empty.value() == 0,"delta should be 0");
- BOOST_CHECK_MESSAGE(empty.name().empty(),"name should be empty");
- BOOST_CHECK_MESSAGE(empty.name() == "","name not as expected");
- }
- {
- Repeat rep(RepeatDay(2));
- BOOST_CHECK_MESSAGE(!rep.empty()," Repeat should not be empty");
- BOOST_CHECK_MESSAGE(!rep.name().empty(),"name should not be empty");
- BOOST_CHECK_MESSAGE(rep.name() == "day","name not as expected");
-
- Repeat cloned = Repeat(rep);
- BOOST_CHECK_MESSAGE(cloned == rep,"Equality failed");
- BOOST_CHECK_MESSAGE(cloned.name() == "day","name not as expected");
- BOOST_CHECK_MESSAGE(cloned.step() == 2,"step not as expected");
-
- RepeatDay empty;
- BOOST_CHECK_MESSAGE(empty.start() == 0,"Start should be 0");
- BOOST_CHECK_MESSAGE(empty.end() == 0,"end should be 0");
- BOOST_CHECK_MESSAGE(empty.step() == 1,"default step should be 0 but found " << empty.step());
- BOOST_CHECK_MESSAGE(empty.value() == 1,"value should be 0 but found " << empty.value());
- BOOST_CHECK_MESSAGE(empty.name().empty(),"name should be empty");
- BOOST_CHECK_MESSAGE(empty.name() == "","name not as expected");
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_repeat )
-{
- cout << "ANattr:: ...test_repeat \n";
-
- std::vector<std::string> stringList; stringList.reserve(3);
- stringList.push_back("a");
- stringList.push_back("b");
- stringList.push_back("c");
-
- Repeat empty;
- Repeat empty2;
-
- {
- Repeat l1(RepeatDate("YMD",20090916,20090930,1));
- Repeat l2(RepeatDate("YMD",20090916,20090930,1));
- BOOST_CHECK_MESSAGE(!l1.empty(),"Construction failed");
- BOOST_CHECK_MESSAGE(!l2.empty(),"Construction failed");
- BOOST_CHECK_MESSAGE(l1 == l2,"Equality failed");
- BOOST_CHECK_MESSAGE(!(l1 == empty),"Equality failed");
-
- Repeat la(RepeatEnumerated("AEnum",stringList));
- Repeat lb(RepeatEnumerated("AEnum",stringList));
- BOOST_CHECK_MESSAGE(!la.empty(),"Construction failed");
- BOOST_CHECK_MESSAGE(!lb.empty(),"Construction failed");
- BOOST_CHECK_MESSAGE(la == lb,"Equality failed");
- BOOST_CHECK_MESSAGE(!(la == empty),"Equality failed");
-
- Repeat lc(RepeatString("RepeatString",stringList));
- Repeat ld(RepeatString("RepeatString",stringList));
- BOOST_CHECK_MESSAGE(!lc.empty(),"Construction failed");
- BOOST_CHECK_MESSAGE(!ld.empty(),"Construction failed");
- BOOST_CHECK_MESSAGE(lc == lc,"Equality failed");
- BOOST_CHECK_MESSAGE(!(lc == empty),"Equality failed");
-
- Repeat le(RepeatInteger("rep",0,100,1));
- Repeat lf(RepeatInteger("rep",0,100,1));
- BOOST_CHECK_MESSAGE(!le.empty(),"Construction failed");
- BOOST_CHECK_MESSAGE(!lf.empty(),"Construction failed");
- BOOST_CHECK_MESSAGE(le == lf,"Equality failed");
- BOOST_CHECK_MESSAGE(!(le == empty),"Equality failed");
-
- l1.clear();
- l2.clear();
- la.clear();
- lb.clear();
- lc.clear();
- ld.clear();
- le.clear();
- lf.clear();
- BOOST_CHECK_MESSAGE(l1 == empty,"Clear failed");
- BOOST_CHECK_MESSAGE(l2 == empty,"Clear failed");
- BOOST_CHECK_MESSAGE(la == empty,"Clear failed");
- BOOST_CHECK_MESSAGE(lb == empty,"Clear failed");
- BOOST_CHECK_MESSAGE(lc == empty,"Clear failed");
- BOOST_CHECK_MESSAGE(ld == empty,"Clear failed");
- BOOST_CHECK_MESSAGE(le == empty,"Clear failed");
- BOOST_CHECK_MESSAGE(lf == empty,"Clear failed");
- }
-
- {
- Repeat l1(RepeatDate("YMD",20090916,20090930,1));
- Repeat l2;
- l2 = l1;
- BOOST_CHECK_MESSAGE(l1 == l2,"Assignment failed");
-
- l2 = empty;
- BOOST_CHECK_MESSAGE(l2 == empty,"Assignment failed");
-
- Repeat la(RepeatEnumerated("AEnum",stringList));
- Repeat lb;
- lb = la;
- BOOST_CHECK_MESSAGE(la == lb,"Assignment failed");
-
- Repeat lc(RepeatString("RepeatString",stringList));
- Repeat ld;
- ld = lc;
- BOOST_CHECK_MESSAGE(lc == ld,"Assignment failed");
-
- Repeat le(RepeatInteger("rep",0,100,1));
- Repeat lf;
- lf = le;
- BOOST_CHECK_MESSAGE(le == lf,"Assignment failed");
- }
-
- {
- Repeat l1(RepeatDate("YMD",20090916,20090930,1));
-
- Repeat l2 = l1;
- BOOST_CHECK_MESSAGE(l1 == l2,"Copy construction failed");
-
- Repeat la(RepeatEnumerated("AEnum",stringList));
- Repeat lb = la;
- BOOST_CHECK_MESSAGE(la == lb,"Copy construction failed");
-
- Repeat lc(RepeatString("RepeatString",stringList));
- Repeat ld = lc;
- BOOST_CHECK_MESSAGE(lc == ld,"Copy construction failed");
-
- Repeat le(RepeatInteger("rep",0,100,1));
- Repeat lf = le;
- BOOST_CHECK_MESSAGE(le == lf,"Copy construction failed");
-
- Repeat empty_1( empty );
- BOOST_CHECK_MESSAGE(empty_1 == empty,"Copy construction failed");
- }
-
- {
- BOOST_CHECK_MESSAGE(empty.name() == string()," empty failed");
- BOOST_CHECK_MESSAGE(empty.valid() == false," empty failed");
- BOOST_CHECK_MESSAGE(empty.value() == 0," empty failed");
- empty.setToLastValue();
- BOOST_CHECK_MESSAGE(empty.valueAsString() == string()," empty failed");
- empty.reset();
- empty.increment();
- empty.change("fred");
- BOOST_CHECK_MESSAGE(empty.valueAsString() == string()," empty failed");
- empty.changeValue(10);
- BOOST_CHECK_MESSAGE(empty.valueAsString() == string()," empty failed");
- BOOST_CHECK_MESSAGE(empty.isInfinite() == false," empty failed");
- BOOST_CHECK_MESSAGE(empty.toString() == string()," empty failed");
- BOOST_CHECK_MESSAGE(empty.state_change_no() ==0," empty failed");
- }
-
- {
- Repeat day(RepeatDay(2));
- Repeat day2 = day;
- BOOST_CHECK_MESSAGE(day == day2,"Copy construction failed");
-
- BOOST_CHECK_MESSAGE(day.makeInfiniteInValid(),"Should return true");
- BOOST_CHECK_MESSAGE(!day.valid(),"Should return false after makeInfiniteInValid");
- day.reset();
- BOOST_CHECK_MESSAGE(day.valid(),"Should return true after reset");
- }
-}
-
-
-BOOST_AUTO_TEST_CASE( test_repeat_last_value )
-{
- cout << "ANattr:: ...test_repeat_last_value \n";
-
- {
- Repeat rep(RepeatDate("YMD",20090916,20090930,1));
- rep.setToLastValue();
- BOOST_CHECK_MESSAGE(rep.value() == 20090930,"Set to last value did not work, expected 20090930 but found " << rep.value());
- }
-
-
- std::vector<std::string> stringList; stringList.reserve(3);
- stringList.push_back("a");
- stringList.push_back("b");
- stringList.push_back("c");
- {
- Repeat rep(RepeatEnumerated("AEnum",stringList));
- rep.setToLastValue();
- BOOST_CHECK_MESSAGE(rep.value() == 2,"Set to last value did not work, expected 2 but found " << rep.value());
- BOOST_CHECK_MESSAGE(rep.valueAsString() == "c","Set to last value did not work, expected 'c' but found " << rep.valueAsString());
- BOOST_CHECK_MESSAGE(rep.value_as_string(0) == "a"," Expected 'a' but found " << rep.value_as_string(0));
- BOOST_CHECK_MESSAGE(rep.value_as_string(1) == "b"," Expected 'b' but found " << rep.value_as_string(1));
- BOOST_CHECK_MESSAGE(rep.value_as_string(2) == "c"," Expected 'c' but found " << rep.value_as_string(2));
- }
- {
- Repeat rep(RepeatString("Str",stringList));
- rep.setToLastValue();
- BOOST_CHECK_MESSAGE(rep.value() == 2,"Set to last value did not work, expected 2 but found " << rep.value());
- BOOST_CHECK_MESSAGE(rep.valueAsString() == "c","Set to last value did not work, expected 'c' but found " << rep.valueAsString());
- BOOST_CHECK_MESSAGE(rep.value_as_string(0) == "a"," Expected 'a' but found " << rep.value_as_string(0));
- BOOST_CHECK_MESSAGE(rep.value_as_string(1) == "b"," Expected 'b' but found " << rep.value_as_string(1));
- BOOST_CHECK_MESSAGE(rep.value_as_string(2) == "c"," Expected 'c' but found " << rep.value_as_string(2));
- }
-
- {
- Repeat rep(RepeatInteger("integer",0,10,1));
- rep.setToLastValue();
- BOOST_CHECK_MESSAGE(rep.value() == 10,"Set to last value did not work, expected 10 but found " << rep.value());
- BOOST_CHECK_MESSAGE(rep.value_as_string(0) == "0"," Expected '0' but found " << rep.value_as_string(0));
- BOOST_CHECK_MESSAGE(rep.value_as_string(1) == "1"," Expected '1' but found " << rep.value_as_string(1));
- BOOST_CHECK_MESSAGE(rep.value_as_string(2) == "2"," Expected '2' but found " << rep.value_as_string(2));
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_repeat_enumerated_as_string_integers )
-{
- cout << "ANattr:: ...test_repeat_enumerated_as_string_integers\n";
-
- std::vector<std::string> stringList; stringList.reserve(3);
- stringList.push_back("20130101");
- stringList.push_back("20130102");
- stringList.push_back("20130103");
- {
- Repeat rep(RepeatEnumerated("AEnum",stringList));
- // Note: valueAsString should return string at the last valid index
-
- BOOST_CHECK_MESSAGE(rep.valid(),"Expected rep to be valid");
- BOOST_CHECK_MESSAGE(rep.value() == 20130101," Expected 20130101 but found " << rep.value());
- BOOST_CHECK_MESSAGE(rep.last_valid_value() == 20130101," Expected 20130101 but found " << rep.last_valid_value());
- BOOST_CHECK_MESSAGE(rep.valueAsString() == "20130101"," Expected '20130101' but found " << rep.valueAsString());
- BOOST_CHECK_MESSAGE(rep.value_as_string(0) == "20130101"," Expected '20130101' but found " << rep.value_as_string(0));
-
- rep.increment();
- BOOST_CHECK_MESSAGE(rep.valid(),"Expected rep to be valid");
- BOOST_CHECK_MESSAGE(rep.value() == 20130102," Expected 20130102 but found " << rep.value());
- BOOST_CHECK_MESSAGE(rep.last_valid_value() == 20130102," Expected 20130102 but found " << rep.last_valid_value());
- BOOST_CHECK_MESSAGE(rep.valueAsString() == "20130102"," Expected '20130102' but found " << rep.valueAsString());
- BOOST_CHECK_MESSAGE(rep.value_as_string(1) == "20130102"," Expected '20130102' but found " << rep.value_as_string(1));
-
- rep.increment();
- BOOST_CHECK_MESSAGE(rep.value() == 20130103," Expected 20130103 but found " << rep.value());
- BOOST_CHECK_MESSAGE(rep.last_valid_value() == 20130103," Expected 20130103 but found " << rep.last_valid_value());
- BOOST_CHECK_MESSAGE(rep.valueAsString() == "20130103"," Expected '20130103' but found " << rep.valueAsString());
- BOOST_CHECK_MESSAGE(rep.value_as_string(2) == "20130103"," Expected '20130103' but found " << rep.value_as_string(2));
-
- rep.increment();
- BOOST_CHECK_MESSAGE(!rep.valid(),"Expected rep to be in-valid");
- BOOST_CHECK_MESSAGE(rep.last_valid_value() == 20130103," Expected 20130103 but found " << rep.last_valid_value());
- BOOST_CHECK_MESSAGE(rep.valueAsString() == "20130103"," Expected '20130103' but found " << rep.valueAsString());
-
- rep.increment();
- BOOST_CHECK_MESSAGE(!rep.valid(),"Expected rep to be in-valid");
- BOOST_CHECK_MESSAGE(rep.last_valid_value() == 20130103," Expected 20130103 but found " << rep.last_valid_value());
- BOOST_CHECK_MESSAGE(rep.valueAsString() == "20130103"," Expected '20130103' but found " << rep.valueAsString());
- }
-}
-
-
-BOOST_AUTO_TEST_CASE( test_repeat_increment )
-{
- cout << "ANattr:: ...test_repeat_increment \n";
-
- {
- Repeat rep(RepeatDate("YMD",20090916,20090920,1));
- while( rep.valid()) { rep.increment(); }
- BOOST_CHECK_MESSAGE(rep.value() == 20090921,"expected 20090921 but found " << rep.value());
- BOOST_CHECK_MESSAGE(rep.last_valid_value() == 20090920,"expected 20090920 but found " << rep.last_valid_value());
- }
-
-
- std::vector<std::string> stringList; stringList.reserve(3);
- stringList.push_back("a");
- stringList.push_back("b");
- stringList.push_back("c");
- {
- Repeat rep(RepeatEnumerated("AEnum",stringList));
- while( rep.valid()) { rep.increment(); }
- BOOST_CHECK_MESSAGE(rep.value() == 3," Expected 3 but found " << rep.value());
- BOOST_CHECK_MESSAGE(rep.last_valid_value() == 2," Expected 2 but found " << rep.last_valid_value());
- }
- {
- Repeat rep(RepeatString("Str",stringList));
- while( rep.valid()) { rep.increment(); }
- BOOST_CHECK_MESSAGE(rep.value() == 3," Expected 3 but found " << rep.value());
- BOOST_CHECK_MESSAGE(rep.last_valid_value() == 2," Expected 2 but found " << rep.last_valid_value());
- }
- {
- Repeat rep(RepeatInteger("integer",0,10,1));
- while( rep.valid()) { rep.increment(); }
- BOOST_CHECK_MESSAGE(rep.value() == 11," Expected 11 but found " << rep.value());
- BOOST_CHECK_MESSAGE(rep.last_valid_value() == 10," Expected 10 but found " << rep.last_valid_value());
- }
-}
-
-
-BOOST_AUTO_TEST_CASE( test_repeat_date_errors )
-{
- cout << "ANattr:: ...test_repeat_date_errors \n";
-
- BOOST_REQUIRE_THROW( RepeatDate("",20090916,20090920,1),std::runtime_error);
- BOOST_REQUIRE_THROW( RepeatDate("YMD",200909161,20090920,1),std::runtime_error); // start > 8
- BOOST_REQUIRE_THROW( RepeatDate("YMD",20090916,200909201,1),std::runtime_error); // end > 8
- BOOST_REQUIRE_THROW( RepeatDate("YMD",20090016,200909201,1),std::runtime_error); // invalid start month
- BOOST_REQUIRE_THROW( RepeatDate("YMD",20090900,20090920,1),std::runtime_error); // invalid start day
- BOOST_REQUIRE_THROW( RepeatDate("YMD",20090916,20090020,1),std::runtime_error); // invalid end month
- BOOST_REQUIRE_THROW( RepeatDate("YMD",20090916,20090900,1),std::runtime_error); // invalid end day
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/ANattr/test/TestTimeAttr.cpp b/ecflow_4_0_7/ANattr/test/TestTimeAttr.cpp
deleted file mode 100644
index 5fa2e30..0000000
--- a/ecflow_4_0_7/ANattr/test/TestTimeAttr.cpp
+++ /dev/null
@@ -1,345 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #14 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <string>
-#include <iostream>
-#include <fstream>
-#include <boost/test/unit_test.hpp>
-#include <boost/date_time/posix_time/time_formatters.hpp>
-
-#include "TimeAttr.hpp"
-#include "TimeSeries.hpp"
-#include "Calendar.hpp"
-#include "Str.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost::posix_time;
-using namespace boost::gregorian;
-
-BOOST_AUTO_TEST_SUITE( ANattrTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_time_attr)
-{
- cout << "ANattr:: ...test_time_attr\n";
-
- // See TimeAttr.hpp for rules concerning isFree() and checkForReque()
- // test time attr isFree(), and checkForRequeue
- Calendar calendar;
- calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::REAL);
-
- // Create a test when we can match a time series. Need to sync hour with suite time
- // at hour 1, suite time should also be 01:00, for test to work
- //
- // Create the time series: start 10:00
- // finish 20:00
- // incr 1:00
- TimeSeries timeSeriesX(TimeSlot(10,0), TimeSlot(20,0), TimeSlot(1,0), false/* relative */);
- TimeSeries timeSeries2X(TimeSlot(11,0), TimeSlot(15,0), TimeSlot(1,0), false/* relative */);
- TimeSeries timeSeries3X(TimeSlot(15,0), false/* relative */);
- TimeSeries timeSeries4X(TimeSlot(0,0), false/* relative */);
-
- TimeSlot t1_min, t1_max,t2_min,t2_max,t3_min,t3_max,t4_min,t4_max;
- timeSeriesX.min_max_time_slots(t1_min, t1_max);
- timeSeries2X.min_max_time_slots(t2_min, t2_max);
- timeSeries3X.min_max_time_slots(t3_min, t3_max);
- timeSeries4X.min_max_time_slots(t4_min, t4_max);
- BOOST_CHECK_MESSAGE(t1_min == TimeSlot(10,0) && t1_max == TimeSlot(20,0),"Not as expected");
- BOOST_CHECK_MESSAGE(t2_min == TimeSlot(11,0) && t2_max == TimeSlot(15,0),"Not as expected");
- BOOST_CHECK_MESSAGE(t3_min == TimeSlot(15,0) && t3_max == TimeSlot(15,0),"Not as expected");
- BOOST_CHECK_MESSAGE(t4_min == TimeSlot(0,0) && t4_max == TimeSlot(0,0),"Not as expected");
-
- TimeAttr timeSeries(timeSeriesX);
- TimeAttr timeSeries2(timeSeries2X);
- TimeAttr timeSeries3(timeSeries3X);
- TimeAttr timeSeries4(timeSeries4X);
-
- std::vector<boost::posix_time::time_duration> timeSeries_free_slots;
- std::vector<boost::posix_time::time_duration> timeSeries2_free_slots;
- timeSeries.time_series().free_slots(timeSeries_free_slots);
- timeSeries2.time_series().free_slots(timeSeries2_free_slots);
- BOOST_CHECK_MESSAGE(timeSeries_free_slots.size() == 11,"Expected 11 free slots for " << timeSeries.toString() << " but found " << timeSeries_free_slots.size());
- BOOST_CHECK_MESSAGE(timeSeries2_free_slots.size() == 5,"Expected 5 free slots for " << timeSeries2.toString() << " but found " << timeSeries_free_slots.size());
-// cout << "time " << timeSeries.toString() << " free slots:";
-// for(size_t i = 0; i < timeSeries_free_slots.size(); i++) cout << timeSeries_free_slots[i] << " ";
-// cout << "\n";
-
- // follow normal process
- timeSeries.reset( calendar );
- timeSeries2.reset( calendar );
- timeSeries3.reset( calendar );
- timeSeries4.reset( calendar );
-
- bool day_changed = false; // after midnight make sure we keep day_changed
- for(int m=1; m < 96; m++) {
- calendar.update( time_duration( minutes(30) ) );
- if (!day_changed) day_changed = calendar.dayChanged();
-
- boost::posix_time::time_duration time = calendar.suiteTime().time_of_day();
- //cout << time << " day_changed(" << day_changed << ")\n";
-
- timeSeries.calendarChanged( calendar );
- timeSeries2.calendarChanged( calendar );
- timeSeries3.calendarChanged( calendar );
- timeSeries4.calendarChanged( calendar );
-
- //cout << to_simple_string(calendar.suiteTime()) << "\n";
-
- if (calendar.dayChanged()) {
- BOOST_CHECK_MESSAGE(timeSeries.checkForRequeue(calendar,t1_min,t1_max)," expected " << timeSeries.toString() << " checkForRequeue to pass at " << to_simple_string(calendar.suiteTime()));
- }
- else if (time < timeSeries.time_series().start().duration()) {
- BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar),timeSeries.toString() << " should NOT be free at time " << time );
- BOOST_CHECK_MESSAGE(timeSeries.checkForRequeue(calendar,t1_min,t1_max),timeSeries.toString() << " checkForRequeue should pass at " << time );
- }
- else if (time >= timeSeries.time_series().start().duration() && time <=timeSeries.time_series().finish().duration()) {
-
- bool matches_free_slot = false;
- for(size_t i = 0; i < timeSeries_free_slots.size(); i++) {
- if (time == timeSeries_free_slots[i]) { matches_free_slot = true; break; }
- }
- if (matches_free_slot) BOOST_CHECK_MESSAGE(timeSeries.isFree(calendar),timeSeries.toString() << " should be free at time " << time );
- else BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar),timeSeries.toString() << " should be fail at time " << time );
-
- /// At the last hour checkForRequeue should return false; This ensures that value will
- /// not get incremented and so, should leave node in the complete state.
- if ( time < timeSeries.time_series().finish().duration()) {
- BOOST_CHECK_MESSAGE(timeSeries.checkForRequeue(calendar,t1_min,t1_max),timeSeries.toString() << " checkForRequeue should be free at time " << time );
- }
- else {
- BOOST_CHECK_MESSAGE(!timeSeries.checkForRequeue(calendar,t1_min,t1_max),timeSeries.toString() << "checkForRequeue should Not free at time " << time );
- }
- }
- else {
- BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar),timeSeries.toString() << " should be holding at time " << time );
- BOOST_CHECK_MESSAGE(!timeSeries.checkForRequeue(calendar,t1_min,t1_max),timeSeries.toString() << " should fail at " << time );
- }
-
-
- if (calendar.dayChanged()) {
- BOOST_CHECK_MESSAGE(timeSeries2.checkForRequeue(calendar,t2_min,t2_max)," expected " << timeSeries2.toString() << " checkForRequeue to pass at " << to_simple_string(calendar.suiteTime()));
- }
- else if (time < timeSeries2.time_series().start().duration()) {
- BOOST_CHECK_MESSAGE(!timeSeries2.isFree(calendar),timeSeries2.toString() << " should NOT be free at time " << time );
- BOOST_CHECK_MESSAGE(timeSeries2.checkForRequeue(calendar,t2_min,t2_max),timeSeries2.toString() << " checkForRequeue should pass at " << time );
- }
- else if (time >= timeSeries2.time_series().start().duration() && time <=timeSeries2.time_series().finish().duration()) {
-
- bool matches_free_slot = false;
- for(size_t i = 0; i < timeSeries2_free_slots.size(); i++) {
- if (time == timeSeries2_free_slots[i]) { matches_free_slot = true; break;}
- }
- if (matches_free_slot) BOOST_CHECK_MESSAGE(timeSeries2.isFree(calendar),timeSeries2.toString() << " should be free at time " << time );
- else BOOST_CHECK_MESSAGE(!timeSeries2.isFree(calendar),timeSeries2.toString() << " should be fail at time " << time );
-
-
- /// At the last time checkForRequeue should return false; This ensures that value will
- /// not get incremented and so, should leave node in the complete state.
- if ( time < timeSeries2.time_series().finish().duration()) {
- BOOST_CHECK_MESSAGE(timeSeries2.checkForRequeue(calendar,t2_min,t2_max),timeSeries2.toString() << " checkForRequeue should be free at time " << time );
- }
- else {
- BOOST_CHECK_MESSAGE(!timeSeries2.checkForRequeue(calendar,t2_min,t2_max),timeSeries2.toString() << "checkForRequeue should Not free at time " << time );
- }
- }
- else {
- BOOST_CHECK_MESSAGE(!timeSeries2.isFree(calendar),timeSeries2.toString() << " should be holding at time " << time );
- BOOST_CHECK_MESSAGE(!timeSeries2.checkForRequeue(calendar,t2_min,t2_max),timeSeries2.toString() << " should fail at " << time );
- }
-
-
- // Single slot, Once a single slot is Free it *stays* free until explicitly requeued, (i.e by parent repeat/cron)
- if (!day_changed) {
- if (time < timeSeries3.time_series().start().duration()) {
- BOOST_CHECK_MESSAGE(!timeSeries3.isFree(calendar),timeSeries3.toString() << " should be fail at time " << time );
- }
- else if (time == timeSeries3.time_series().start().duration() ) {
- BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries3.toString() << " should be free at time " << time );
- }
- else if (time > timeSeries3.time_series().start().duration()) {
- BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries3.toString() << " isFree should pass at time " << time );
- }
- }
- else {
- BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries3.toString() << " should be free at time after day change" << time );
- }
- BOOST_CHECK_MESSAGE(!timeSeries3.checkForRequeue(calendar,t3_min,t3_max),timeSeries3.toString() << " checkForRequeue should fail at " << time );
-
-
- // single slot at midnight, Once a single slot if Free it *stays* free until explicitly requeued, (i.e by parent repeat/cron)
- if (!day_changed) {
- if (time == timeSeries4.time_series().start().duration() ) {
- BOOST_CHECK_MESSAGE(timeSeries4.isFree(calendar),timeSeries4.toString() << " should be free at time " << time );
- }
- else {
- BOOST_CHECK_MESSAGE(!timeSeries4.isFree(calendar),timeSeries4.toString() << " day_changed(" << day_changed << ") isFree should fail at time " << time );
- }
- }
- else {
- BOOST_CHECK_MESSAGE(timeSeries4.isFree(calendar),timeSeries4.toString() << " day_changed(" << day_changed << ") isFree should pass at time " << time );
- }
- BOOST_CHECK_MESSAGE(!timeSeries4.checkForRequeue(calendar,t4_min,t4_max),timeSeries4.toString() << " checkForRequeue should fail at " << time );
-
-
- // Typically when a time is free, it stays free, until it is re-queued
- // However in order to test isFree for time with time intervals, we need to re-queue
- timeSeries.requeue( calendar );
- timeSeries2.requeue( calendar );
-
- // Do not requeue time 00, and time 15, so that we can check for free
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_time_once_free_stays_free)
-{
- cout << "ANattr:: ...test_time_once_free_stays_free\n";
-
- Calendar calendar;
- calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::REAL);
-
- TimeSeries timeSeriesX(TimeSlot(10,0), TimeSlot(20,0), TimeSlot(1,0), false/* relative */);
- TimeSeries timeSeries2X(TimeSlot(11,0), TimeSlot(15,0), TimeSlot(1,0), false/* relative */);
- TimeSeries timeSeries3X(TimeSlot(15,0), false/* relative */);
- TimeSeries timeSeries4X(TimeSlot(0,0), false/* relative */);
-
- TimeAttr timeSeries(timeSeriesX );
- TimeAttr timeSeries2(timeSeries2X );
- TimeAttr timeSeries3(timeSeries3X );
- TimeAttr timeSeries4(timeSeries4X );
-
- bool day_changed = false; // after midnight make sure we keep day_changed
- for(int m=1; m < 96; m++) {
- calendar.update( time_duration( minutes(30) ) );
- if (!day_changed) {
- day_changed = calendar.dayChanged();
- }
- boost::posix_time::time_duration time = calendar.suiteTime().time_of_day();
- // cout << time << " day_changed(" << day_changed << ")\n";
-
- timeSeries.calendarChanged( calendar );
- timeSeries2.calendarChanged( calendar );
- timeSeries3.calendarChanged( calendar );
- timeSeries4.calendarChanged( calendar );
-
- // **********************************************************************************
- // When a time (regardless of whether its single slot or time series) is free, it stays free,
- // until explicitly re-queued,
- // ***********************************************************************************
-
- if (time < timeSeries.time_series().start().duration()) {
- if (!day_changed) BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar),timeSeries.toString() << " should NOT be free at time " << time );
- else BOOST_CHECK_MESSAGE(timeSeries.isFree(calendar),timeSeries.toString() << " should be free at time " << time );
- }
- else if (time >= timeSeries.time_series().start().duration()) {
- BOOST_CHECK_MESSAGE(timeSeries.isFree(calendar),timeSeries.toString() << " should be free at time " << time );
- }
-
-
- if (time < timeSeries2.time_series().start().duration()) {
- if (!day_changed) BOOST_CHECK_MESSAGE(!timeSeries2.isFree(calendar),timeSeries2.toString() << " should NOT be free at time " << time );
- else BOOST_CHECK_MESSAGE(timeSeries.isFree(calendar),timeSeries.toString() << " should be free at time " << time );
- }
- else if (time >= timeSeries2.time_series().start().duration()) {
- BOOST_CHECK_MESSAGE(timeSeries2.isFree(calendar),timeSeries2.toString() << " should be free at time " << time );
- }
-
- if (!day_changed) {
- if (time == timeSeries3.time_series().start().duration() ) {
- BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries3.toString() << " should be free at time " << time );
- }
- else if (time > timeSeries3.time_series().start().duration()) {
- BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries3.toString() << " isFree, once free should stay free at time " << time );
- }
- }
- else {
- BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries3.toString() << " should be free at time after day change " << time );
- }
-
-
- // single slot at midnight, Once a single slot if Free it *stays* free until explicitly requeued, (i.e by parent repeat/cron)
- if (!day_changed) {
- if (time == timeSeries4.time_series().start().duration() ) {
- BOOST_CHECK_MESSAGE(timeSeries4.isFree(calendar),timeSeries4.toString() << " should be free at time " << time );
- }
- else {
- BOOST_CHECK_MESSAGE(!timeSeries4.isFree(calendar),timeSeries4.toString() << " day_changed(" << day_changed << ") isFree should fail at time " << time );
- }
- }
- else {
- BOOST_CHECK_MESSAGE(timeSeries4.isFree(calendar),timeSeries4.toString() << " day_changed(" << day_changed << ") isFree should pass at time " << time );
- }
- }
-}
-
-
-BOOST_AUTO_TEST_CASE( test_time_attr_multiples )
-{
- cout << "ANattr:: ...test_time_attr_multiples\n";
-
- // See TimeAttr.hpp for rules concerning isFree() and checkForReque()
- // test time attr isFree(), and checkForRequeue
- Calendar calendar;
- calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::REAL);
-
- TimeSeries timeSeries1530(TimeSlot(15,30), false/* relative */);
- TimeSeries timeSeries1630(TimeSlot(16,30), false/* relative */);
- TimeSeries timeSeries2030(TimeSlot(20,30), false/* relative */);
-
- TimeSlot t1_min, t1_max;
- timeSeries1530.min_max_time_slots(t1_min, t1_max);
- timeSeries1630.min_max_time_slots(t1_min, t1_max);
- timeSeries2030.min_max_time_slots(t1_min, t1_max);
- BOOST_CHECK_MESSAGE(t1_min == TimeSlot(15,30) && t1_max == TimeSlot(20,30),"Not as expected");
-
- TimeAttr timeSeries(timeSeries1530);
- TimeAttr timeSeries2(timeSeries1630);
- TimeAttr timeSeries3(timeSeries2030);
-
- bool day_changed = false; // after midnight make sure we keep day_changed
- for(int m=1; m < 96; m++) {
- calendar.update( time_duration( minutes(30) ) );
- if (!day_changed) {
- day_changed = calendar.dayChanged();
- }
- boost::posix_time::time_duration time = calendar.suiteTime().time_of_day();
- // cout << time << " day_changed(" << day_changed << ")\n";
-
- timeSeries.calendarChanged( calendar );
- timeSeries2.calendarChanged( calendar );
- timeSeries3.calendarChanged( calendar );
-
- if (!day_changed) {
- if ( time < t1_max.duration()) {
- BOOST_CHECK_MESSAGE(timeSeries.checkForRequeue(calendar,t1_min,t1_max),timeSeries.toString() << " checkForRequeue should pass at " << time );
- BOOST_CHECK_MESSAGE(timeSeries2.checkForRequeue(calendar,t1_min,t1_max),timeSeries2.toString() << " checkForRequeue should pass at " << time );
- BOOST_CHECK_MESSAGE(timeSeries3.checkForRequeue(calendar,t1_min,t1_max),timeSeries3.toString() << " checkForRequeue should pass at " << time );
- }
- else {
- BOOST_CHECK_MESSAGE(!timeSeries.checkForRequeue(calendar,t1_min,t1_max),timeSeries.toString() << " checkForRequeue should fail at " << time );
- BOOST_CHECK_MESSAGE(!timeSeries2.checkForRequeue(calendar,t1_min,t1_max),timeSeries2.toString() << " checkForRequeue should fail at " << time );
- BOOST_CHECK_MESSAGE(!timeSeries3.checkForRequeue(calendar,t1_min,t1_max),timeSeries3.toString() << " checkForRequeue should fail at " << time );
- }
- }
- else {
- // Once a single slot if Free it *stays* free until explicitly requeued, (i.e by parent repeat/cron)
- BOOST_CHECK_MESSAGE(timeSeries.isFree(calendar),timeSeries.toString() << " day_changed(" << day_changed << ") isFree should pass at time " << time );
- BOOST_CHECK_MESSAGE(timeSeries2.isFree(calendar),timeSeries2.toString() << " day_changed(" << day_changed << ") isFree should pass at time " << time );
- BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries2.toString() << " day_changed(" << day_changed << ") isFree should pass at time " << time );
- }
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/ANattr/test/TestTodayAttr.cpp b/ecflow_4_0_7/ANattr/test/TestTodayAttr.cpp
deleted file mode 100644
index 39c4e19..0000000
--- a/ecflow_4_0_7/ANattr/test/TestTodayAttr.cpp
+++ /dev/null
@@ -1,181 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #14 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <string>
-#include <iostream>
-#include <fstream>
-#include <boost/test/unit_test.hpp>
-#include <boost/date_time/posix_time/time_formatters.hpp>
-
-#include "TodayAttr.hpp"
-#include "TimeSeries.hpp"
-#include "Calendar.hpp"
-#include "Str.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost::posix_time;
-using namespace boost::gregorian;
-
-BOOST_AUTO_TEST_SUITE( ANattrTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_today_attr)
-{
- cout << "ANattr:: ...test_today_attr\n";
-
- // See TodayAttr.hpp for rules concerning isFree() and checkForReque()
- // test today attr isFree(), and checkForRequeue
- Calendar calendar;
- calendar.init(ptime(date(2010,2,10), minutes(0)), Calendar::REAL);
-
- // Create a test when we can match a time series. Need to sync hour with suite time
- // at hour 1, suite time should also be 01:00, for test to work
- //
- // Create the time series: start 10:00
- // finish 20:00
- // incr 1:00
- TimeSeries timeSeriesX(TimeSlot(10,0), TimeSlot(20,0), TimeSlot(1,0), false/* relative */);
- TimeSeries timeSeries2X(TimeSlot(11,0), TimeSlot(15,0), TimeSlot(1,0), false/* relative */);
- TimeSeries timeSeries3X(TimeSlot(15,0), false/* relative */);
-
- TimeSlot t1_min, t1_max,t2_min,t2_max,t3_min,t3_max;
- timeSeriesX.min_max_time_slots(t1_min, t1_max);
- timeSeries2X.min_max_time_slots(t2_min, t2_max);
- timeSeries3X.min_max_time_slots(t3_min, t3_max);
- BOOST_CHECK_MESSAGE(t1_min == TimeSlot(10,0) && t1_max == TimeSlot(20,0),"Not as expected");
- BOOST_CHECK_MESSAGE(t2_min == TimeSlot(11,0) && t2_max == TimeSlot(15,0),"Not as expected");
- BOOST_CHECK_MESSAGE(t3_min == TimeSlot(15,0) && t3_max == TimeSlot(15,0),"Not as expected");
-
-
- TodayAttr timeSeries(timeSeriesX);
- TodayAttr timeSeries2(timeSeries2X);
- TodayAttr timeSeries3(timeSeries3X);
-
- std::vector<boost::posix_time::time_duration> timeSeries_free_slots;
- std::vector<boost::posix_time::time_duration> timeSeries2_free_slots;
- timeSeries.time_series().free_slots(timeSeries_free_slots);
- timeSeries2.time_series().free_slots(timeSeries2_free_slots);
- BOOST_CHECK_MESSAGE(timeSeries_free_slots.size() == 11,"Expected 11 free slots for " << timeSeries.toString() << " but found " << timeSeries_free_slots.size());
- BOOST_CHECK_MESSAGE(timeSeries2_free_slots.size() == 5,"Expected 5 free slots for " << timeSeries2.toString() << " but found " << timeSeries_free_slots.size());
-
- // follow normal process
- timeSeries.reset( calendar );
- timeSeries2.reset( calendar );
- timeSeries3.reset( calendar );
-
- bool day_changed = false; // after midnight make sure we keep day_changed
- for(int m=1; m < 96; m++) {
- calendar.update( time_duration( minutes(30) ) );
- if (!day_changed) {
- day_changed = calendar.dayChanged();
- }
- boost::posix_time::time_duration time = calendar.suiteTime().time_of_day();
-// cout << time << " day_changed(" << day_changed << ")\n";
-
- timeSeries.calendarChanged( calendar );
- timeSeries2.calendarChanged( calendar );
- timeSeries3.calendarChanged( calendar );
-
- if (!day_changed) {
-
- if (time < timeSeries.time_series().start().duration()) {
- BOOST_CHECK_MESSAGE(!timeSeries.isFree(calendar),timeSeries.toString() << " should NOT be free at time " << time );
- BOOST_CHECK_MESSAGE(timeSeries.checkForRequeue(calendar,t1_min,t1_max),timeSeries.toString() << " should pass at " << time );
- }
- else if (time >= timeSeries.time_series().start().duration() && time <=timeSeries.time_series().finish().duration()) {
-
- bool matches_free_slot = false;
- for(size_t i = 0; i < timeSeries_free_slots.size(); i++) {
- if (time == timeSeries_free_slots[i]) { matches_free_slot = true; break; }
- }
- // no else branch since once today is free it stays free, unti re-queue
- if (matches_free_slot) BOOST_CHECK_MESSAGE(timeSeries.isFree(calendar),timeSeries.toString() << " should be free at time " << time );
-
- /// At the last time checkForRequeue should return false; This ensures that value will
- /// not get incremented and so, should leave node in the complete state.
- if ( time < timeSeries.time_series().finish().duration()) {
- BOOST_CHECK_MESSAGE(timeSeries.checkForRequeue(calendar,t1_min,t1_max),timeSeries.toString() << " checkForRequeue should be free at time " << time );
- }
- else {
- BOOST_CHECK_MESSAGE(!timeSeries.checkForRequeue(calendar,t1_min,t1_max),timeSeries.toString() << "checkForRequeue should Not free at time " << time );
- }
- }
- else {
- // After end time, a Today Attr should be free to run.
- BOOST_CHECK_MESSAGE(timeSeries.isFree(calendar),timeSeries.toString() << " should be free at time " << time );
- BOOST_CHECK_MESSAGE(!timeSeries.checkForRequeue(calendar,t1_min,t1_max),timeSeries.toString() << " should fail at " << time );
- }
- }
- else {
- // Once a today time series is free, it stays free
- BOOST_CHECK_MESSAGE(timeSeries.isFree(calendar),timeSeries.toString() << " should be free at time " << time );
- }
-
-
- if (!day_changed) {
- if (time < timeSeries2.time_series().start().duration()) {
- BOOST_CHECK_MESSAGE(!timeSeries2.isFree(calendar),timeSeries2.toString() << " should NOT be free at time " << time );
- BOOST_CHECK_MESSAGE(timeSeries2.checkForRequeue(calendar,t2_min,t2_max),timeSeries2.toString() << " should pass at " << time );
- }
- else if (time >= timeSeries2.time_series().start().duration() && time <=timeSeries2.time_series().finish().duration()) {
-
- bool matches_free_slot = false;
- for(size_t i = 0; i < timeSeries2_free_slots.size(); i++) {
- if (time == timeSeries2_free_slots[i]) { matches_free_slot = true; break; }
- }
- if (matches_free_slot) BOOST_CHECK_MESSAGE(timeSeries2.isFree(calendar),timeSeries2.toString() << " should be free at time " << time );
-
- /// At the last time checkForRequeue should return false; This ensures that value will
- /// not get incremented and so, should leave node in the complete state.
- if ( time < timeSeries2.time_series().finish().duration()) {
- BOOST_CHECK_MESSAGE(timeSeries2.checkForRequeue(calendar,t2_min,t2_max),timeSeries2.toString() << " checkForRequeue should be free at time " << time );
- }
- else {
- BOOST_CHECK_MESSAGE(!timeSeries2.checkForRequeue(calendar,t2_min,t2_max),timeSeries2.toString() << "checkForRequeue should Not free at time " << time );
- }
- }
- else {
- // After end time, a Today Attr should be free to run.
- BOOST_CHECK_MESSAGE(timeSeries2.isFree(calendar),timeSeries2.toString() << " should be holding at time " << time );
- BOOST_CHECK_MESSAGE(!timeSeries2.checkForRequeue(calendar,t2_min,t2_max),timeSeries2.toString() << " should fail at " << time );
- }
- }
- else {
- // Once a today time series is free, it stays free
- BOOST_CHECK_MESSAGE(timeSeries2.isFree(calendar),timeSeries2.toString() << " should be holding at time " << time );
- }
-
- // Single slot
- if (!day_changed) {
- if (time == timeSeries3.time_series().start().duration() ) {
- BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries3.toString() << " should be free at time " << time );
- }
- else if (time < timeSeries3.time_series().start().duration()) {
- BOOST_CHECK_MESSAGE(!timeSeries3.isFree(calendar),timeSeries3.toString() << " isFree should fail at time " << time );
- }
- else if (time > timeSeries3.time_series().start().duration()) {
- BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries3.toString() << " isFree should fail at time " << time );
- }
- }
- else {
- // Once a single slot if Free it *stays* free until explicitly requeued, (i.e by parent repeat/cron)
- BOOST_CHECK_MESSAGE(timeSeries3.isFree(calendar),timeSeries3.toString() << " isFree should fail at time " << time );
- }
- BOOST_CHECK_MESSAGE(!timeSeries3.checkForRequeue(calendar,t3_min,t3_max),timeSeries3.toString() << " checkForRequeue should fail at " << time );
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/ANattr/test/TestVariable.cpp b/ecflow_4_0_7/ANattr/test/TestVariable.cpp
deleted file mode 100644
index 204e7aa..0000000
--- a/ecflow_4_0_7/ANattr/test/TestVariable.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #14 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <iostream>
-#include <boost/test/unit_test.hpp>
-
-#include "Variable.hpp"
-#include "Str.hpp"
-
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( ANattrTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_multi_line_variable_values )
-{
- cout << "ANattr:: ...test_multi_line_variable_values\n";
-
- {
- Variable var("name","value");
- BOOST_CHECK_MESSAGE(var.name() == "name","name not as expected");
- BOOST_CHECK_MESSAGE(var.theValue() == "value","value not as expected");
-
- std::string expected = "edit name 'value'";
- BOOST_CHECK_MESSAGE(var.toString() == expected,"expected " << expected << " but found " << var.toString());
- }
- {
- Variable var("name","");
- std::string expected = "edit name ''";
- BOOST_CHECK_MESSAGE(var.toString() == expected,"expected " << expected << " but found " << var.toString());
- }
- {
- Variable var("name","value\n");
- std::string expected = "edit name 'value\\n'";
- BOOST_CHECK_MESSAGE(var.toString() == expected,"expected " << expected << " but found " << var.toString());
- }
- {
- Variable var("name","val1\nxxx\nval2");
- std::string expected = "edit name 'val1\\nxxx\\nval2'";
- BOOST_CHECK_MESSAGE(var.toString() == expected,"expected " << expected << " but found " << var.toString());
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/AutoCancelAttr b/ecflow_4_0_7/ANattr/test/data/migration/v1_9/AutoCancelAttr
deleted file mode 100644
index 0dd98c9..0000000
--- a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/AutoCancelAttr
+++ /dev/null
@@ -1 +0,0 @@
-22 serialization::archive 9 0 0 2400 0 0 1 1
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/AutoCancelAttr_1 b/ecflow_4_0_7/ANattr/test/data/migration/v1_9/AutoCancelAttr_1
deleted file mode 100644
index de65b95..0000000
--- a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/AutoCancelAttr_1
+++ /dev/null
@@ -1 +0,0 @@
-22 serialization::archive 9 0 0 10 12 0 1 0
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/ClockAttr b/ecflow_4_0_7/ANattr/test/data/migration/v1_9/ClockAttr
deleted file mode 100644
index b278964..0000000
--- a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/ClockAttr
+++ /dev/null
@@ -1 +0,0 @@
-22 serialization::archive 9 0 0 0 1 1 3600 1 1 2009
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/CronAttr b/ecflow_4_0_7/ANattr/test/data/migration/v1_9/CronAttr
deleted file mode 100644
index 2014d93..0000000
--- a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/CronAttr
+++ /dev/null
@@ -1 +0,0 @@
-22 serialization::archive 9 0 1 0 0 0 20 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 2 0 1 2 2 0 1 2 2 0 1 2 0
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/DateAttr b/ecflow_4_0_7/ANattr/test/data/migration/v1_9/DateAttr
deleted file mode 100644
index 4e95053..0000000
--- a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/DateAttr
+++ /dev/null
@@ -1 +0,0 @@
-22 serialization::archive 9 12 12 2012 0
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/DayAttr b/ecflow_4_0_7/ANattr/test/data/migration/v1_9/DayAttr
deleted file mode 100644
index fdfa265..0000000
--- a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/DayAttr
+++ /dev/null
@@ -1 +0,0 @@
-22 serialization::archive 9 1 0
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/Event_1 b/ecflow_4_0_7/ANattr/test/data/migration/v1_9/Event_1
deleted file mode 100644
index ebf94db..0000000
--- a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/Event_1
+++ /dev/null
@@ -1 +0,0 @@
-22 serialization::archive 9 0 1 0
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/Event_2 b/ecflow_4_0_7/ANattr/test/data/migration/v1_9/Event_2
deleted file mode 100644
index 8ca0e9e..0000000
--- a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/Event_2
+++ /dev/null
@@ -1 +0,0 @@
-22 serialization::archive 9 0 2147483647 5 event
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/Label b/ecflow_4_0_7/ANattr/test/data/migration/v1_9/Label
deleted file mode 100644
index 3b62664..0000000
--- a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/Label
+++ /dev/null
@@ -1 +0,0 @@
-22 serialization::archive 9 4 name 5 value 9 new_value
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/LateAttr b/ecflow_4_0_7/ANattr/test/data/migration/v1_9/LateAttr
deleted file mode 100644
index 5187f0e..0000000
--- a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/LateAttr
+++ /dev/null
@@ -1 +0,0 @@
-22 serialization::archive 9 0 0 10 12 0 10 12 0 10 12 0 1 0
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/Meter b/ecflow_4_0_7/ANattr/test/data/migration/v1_9/Meter
deleted file mode 100644
index 910c844..0000000
--- a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/Meter
+++ /dev/null
@@ -1 +0,0 @@
-22 serialization::archive 9 10 100 10 100 5 meter
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/RepeatDate b/ecflow_4_0_7/ANattr/test/data/migration/v1_9/RepeatDate
deleted file mode 100644
index 256d8b8..0000000
--- a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/RepeatDate
+++ /dev/null
@@ -1,2 +0,0 @@
-22 serialization::archive 9 1 0
-0 0 0 4 date 20110112 20110115 1 20110112
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/RepeatEnumerated b/ecflow_4_0_7/ANattr/test/data/migration/v1_9/RepeatEnumerated
deleted file mode 100644
index 407f353..0000000
--- a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/RepeatEnumerated
+++ /dev/null
@@ -1,2 +0,0 @@
-22 serialization::archive 9 1 0
-0 0 0 4 enum 0 0 2 0 1 a 1 b 0
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/RepeatInteger b/ecflow_4_0_7/ANattr/test/data/migration/v1_9/RepeatInteger
deleted file mode 100644
index 121d4b6..0000000
--- a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/RepeatInteger
+++ /dev/null
@@ -1,2 +0,0 @@
-22 serialization::archive 9 1 0
-0 0 0 7 integer 0 100 2 0
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/RepeatString b/ecflow_4_0_7/ANattr/test/data/migration/v1_9/RepeatString
deleted file mode 100644
index 295abe6..0000000
--- a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/RepeatString
+++ /dev/null
@@ -1,2 +0,0 @@
-22 serialization::archive 9 1 0
-0 0 0 6 string 0 0 2 0 1 a 1 b 0
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/TimeAttr b/ecflow_4_0_7/ANattr/test/data/migration/v1_9/TimeAttr
deleted file mode 100644
index 8715b1c..0000000
--- a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/TimeAttr
+++ /dev/null
@@ -1 +0,0 @@
-22 serialization::archive 9 0 1 10 12 0 0 0 1 0 0 1 10 12 0 0 0 0 0 0 0 0 0
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/TodayAttr b/ecflow_4_0_7/ANattr/test/data/migration/v1_9/TodayAttr
deleted file mode 100644
index 8715b1c..0000000
--- a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/TodayAttr
+++ /dev/null
@@ -1 +0,0 @@
-22 serialization::archive 9 0 1 10 12 0 0 0 1 0 0 1 10 12 0 0 0 0 0 0 0 0 0
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/Variable b/ecflow_4_0_7/ANattr/test/data/migration/v1_9/Variable
deleted file mode 100644
index 21e055c..0000000
--- a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/Variable
+++ /dev/null
@@ -1 +0,0 @@
-22 serialization::archive 9 8 var_name 9 var_value
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/VerifyAttr b/ecflow_4_0_7/ANattr/test/data/migration/v1_9/VerifyAttr
deleted file mode 100644
index dcf1ef0..0000000
--- a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/VerifyAttr
+++ /dev/null
@@ -1 +0,0 @@
-22 serialization::archive 9 1 3 0
diff --git a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/ZombieAttr b/ecflow_4_0_7/ANattr/test/data/migration/v1_9/ZombieAttr
deleted file mode 100644
index ad2b73b..0000000
--- a/ecflow_4_0_7/ANattr/test/data/migration/v1_9/ZombieAttr
+++ /dev/null
@@ -1 +0,0 @@
-22 serialization::archive 9 0 0 10 0 0 7 0 0 1 2 3 4 5 6
diff --git a/ecflow_4_0_7/ANode/CMakeLists.txt b/ecflow_4_0_7/ANode/CMakeLists.txt
deleted file mode 100644
index 618ff5e..0000000
--- a/ecflow_4_0_7/ANode/CMakeLists.txt
+++ /dev/null
@@ -1,72 +0,0 @@
-# Note:
-# If new src or test cpp files are added make sure you touch this file
-#
-
-file( GLOB srcs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp" )
-
-ecbuild_add_library( TARGET node
- NOINSTALL
- TYPE STATIC
- SOURCES ${srcs}
- LIBS nodeattr core
- INCLUDES src
- ../ACore/src
- ../ANattr/src
- )
-
-# Use following to populate list:
-# cd $WK/ANode
-# find test -name \*.cpp | sort
-
-# no way to exclude file ?
-#file( GLOB test_srcs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "test/*.cpp" )
-
-list( APPEND test_srcs
- test/Test_ECFLOW-195.cpp
- test/TestAdd.cpp
- test/TestAlias.cpp
- test/TestDefs.cpp
- test/TestDefStatus.cpp
- test/TestEcfFile.cpp
- test/TestEnviromentSubstitution.cpp
- test/TestExprParser.cpp
- test/TestExprRepeatDateArithmetic.cpp
- test/TestFindAbsNodePath.cpp
- test/TestFlag.cpp
- test/TestHistoryParser.cpp
- test/TestInLimit.cpp
- test/TestJobCreator.cpp
- test/TestJobProfiler.cpp
- test/TestLimit.cpp
- test/TestMigration.cpp
- test/TestMissNextTimeSlot.cpp
- test/TestOrder.cpp
- test/TestPersistence.cpp
- test/TestPreProcessing.cpp
- test/TestReplace.cpp
- test/TestSetState.cpp
- test/TestSmsLocator.cpp
- test/TestTaskScriptGenerator.cpp
- test/TestVariableGeneration.cpp
- test/TestVariableInheritance.cpp
- test/TestVariableSubstitution.cpp
- test/TestVariableSubstitutionDefs.cpp
- test/TestZombies.cpp
-)
-
-ecbuild_add_test(TARGET u_anode
- BOOST
- SOURCES ${test_srcs}
- LIBS node
- TEST_DEPENDS u_anattr
- )
-
-
-list( APPEND stest_srcs test/TestSingleExprParse.cpp )
-ecbuild_add_test( TARGET u_anode_stest
- BOOST
- SOURCES ${stest_srcs}
- LIBS node
- TEST_DEPENDS u_anattr
- )
-
diff --git a/ecflow_4_0_7/ANode/jamfile.jam b/ecflow_4_0_7/ANode/jamfile.jam
deleted file mode 100644
index 64cdb76..0000000
--- a/ecflow_4_0_7/ANode/jamfile.jam
+++ /dev/null
@@ -1,64 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-#
-# Node project
-#
-project theNode ;
-
-use-project theCore : ../ACore ;
-use-project theNodeAttr : ../ANattr ;
-
-
-# The <include> means we will automatically add this directory to the include path
-# of any other target that uses this lib
-#
-lib node : [ glob src/*.cpp ]
- : <link>static
- <variant>debug:<define>DEBUG
- <use>/theCore//core
- <use>/theNodeAttr//nodeattr
- <use>/site-config//boost_system
- <use>/site-config//boost_serialization
- <use>/site-config//boost_filesystem
- <use>/site-config//boost_datetime
- <use>/site-config//boost_test
- :
- : <include>../ANode/src
- ;
-
-
-#
-# This is *ONLY* required when the define ECFLOW_MT is used, (used by Signal.cpp)
-lib pthread ;
-
-exe u_anode : [ glob test/*.cpp : test/TestSingleExprParse.cpp ]
- pthread
- /theCore//core
- /theNodeAttr//nodeattr
- node
- /site-config//boost_system
- /site-config//boost_serialization
- /site-config//boost_filesystem
- /site-config//boost_datetime
- /site-config//boost_test
- : <variant>debug:<define>DEBUG
- ;
-
-
-exe u_anode_stest : test/TestSingleExprParse.cpp
- pthread
- /theCore//core
- /theNodeAttr//nodeattr
- node
- /site-config//boost_system
- /site-config//boost_serialization
- /site-config//boost_filesystem
- /site-config//boost_datetime
- /site-config//boost_test
- : <variant>debug:<define>DEBUG
- ;
diff --git a/ecflow_4_0_7/ANode/src/AbstractObserver.hpp b/ecflow_4_0_7/ANode/src/AbstractObserver.hpp
deleted file mode 100644
index c4edb4a..0000000
--- a/ecflow_4_0_7/ANode/src/AbstractObserver.hpp
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef ABSTRACT_OBSERVER_HPP_
-#define ABSTRACT_OBSERVER_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <vector>
-#include "Aspect.hpp"
-class Node;
-class Defs;
-
-class AbstractObserver {
-public:
- virtual ~AbstractObserver() {}
-
- virtual void update(const Node*, const std::vector<ecf::Aspect::Type>&) = 0;
- virtual void update(const Defs*, const std::vector<ecf::Aspect::Type>&) = 0;
-
- /// After this call, the node will be deleted, hence observers must *NOT* use the pointers
- virtual void update_delete(const Node*) {}
- virtual void update_delete(const Defs*) {}
-};
-
-#endif
diff --git a/ecflow_4_0_7/ANode/src/Alias.cpp b/ecflow_4_0_7/ANode/src/Alias.cpp
deleted file mode 100644
index 6d060b1..0000000
--- a/ecflow_4_0_7/ANode/src/Alias.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #19 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <assert.h>
-#include <sstream>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include "boost/filesystem/exception.hpp"
-#include <boost/lexical_cast.hpp>
-#include <boost/make_shared.hpp>
-
-#include "Alias.hpp"
-#include "Defs.hpp"
-#include "Ecf.hpp"
-#include "Log.hpp"
-#include "Stl.hpp"
-#include "Str.hpp"
-#include "File.hpp"
-#include "Indentor.hpp"
-#include "ChangeMgrSingleton.hpp"
-#include "PrintStyle.hpp"
-
-namespace fs = boost::filesystem;
-using namespace ecf;
-using namespace std;
-using namespace boost;
-
-//==================================================================================
-Alias::Alias( const std::string& name )
-: Submittable(name)
-{
- set_state_only(NState::QUEUED);
-}
-
-Alias::Alias()
-{
- set_state_only(NState::QUEUED);
-}
-
-Alias::~Alias()
-{
- // Don't create the ChangeMgrSingleton during destruct sequence. (i.e in unit cases)
- // Since that will cause a memory leak
- if (!Ecf::server() && ChangeMgrSingleton::exists()) {
- ChangeMgrSingleton::instance()->notify_delete( this );
- }
-}
-
-alias_ptr Alias::create(const std::string& name)
-{
- return boost::make_shared<Alias>( name );
-}
-
-bool Alias::operator==(const Alias& rhs) const
-{
- return Submittable::operator==(rhs);
-}
-
-std::ostream& Alias::print(std::ostream& os) const
-{
- Indentor in;
- Indentor::indent(os) << "alias " << name();
- if (!PrintStyle::defsStyle()) {
- std::string st = write_state();
- if (!st.empty()) os << " #" << st;
- }
- os << "\n";
-
- Node::print(os);
-
- // Generated variable are not persisted since they are created on demand
- // There *NO* point in printing them they will always be empty
- return os;
-}
-std::ostream& operator<<(std::ostream& os, const Alias& d) { return d.print(os); }
-
-void Alias::begin()
-{
- Submittable::begin();
-}
-
-void Alias::requeue(bool resetRepeats, int clear_suspended_in_child_nodes,bool reset_next_time_slot)
-{
- Submittable::requeue(resetRepeats,clear_suspended_in_child_nodes,reset_next_time_slot);
-}
-
-const std::string& Alias::debugType() const { return ecf::Str::ALIAS();}
-
-node_ptr Alias::removeChild(Node*)
-{
- LOG_ASSERT(false,"");
- return node_ptr();
-}
-
-bool Alias::addChild( node_ptr , size_t )
-{
- LOG_ASSERT(false,"");
- return false;
-}
-
-size_t Alias::child_position(const Node*) const
-{
- return std::numeric_limits<std::size_t>::max();
-}
-
-bool Alias::isAddChildOk( Node* alias, std::string& errorMsg) const
-{
- errorMsg += "Can not add children to a Alias";
- return false;
-}
-
-void Alias::handleStateChange()
-{
- /// Increment/decrement limits based on the current state
- update_limits();
-
- // Aliases are stand alone, they do no requeue or bubble up/down state changes
- // i.e no requeue since they have no time dependencies, or repeat
-}
-
-const std::string& Alias::script_extension() const
-{
- return File::USR_EXTN();
-}
-
-void Alias::collateChanges(DefsDelta& changes) const
-{
- /// All changes to Alias should be on ONE compound_memento_ptr
- compound_memento_ptr comp;
- Submittable::incremental_changes(changes, comp);
-}
-
-void Alias::get_all_nodes(std::vector<node_ptr>& nodes) const
-{
- nodes.push_back(non_const_this());
-}
-
-// Functions unique to aliases
-void Alias::add_alias_variable(const std::string& name, const std::string& value)
-{
- if (name.empty()) {
- throw std::runtime_error("Alias::add_alias_variable: Variable with empty name");
- }
-
- // The bool argument to variable, allows addition of Variable without name checking
- addVariable( Variable(name,value,false));
-}
-
-node_ptr Alias::find_node_up_the_tree(const std::string& name) const
-{
- Node* the_parent = parent();
- if (the_parent) return the_parent->find_node_up_the_tree(name);
- return node_ptr();
-}
-
diff --git a/ecflow_4_0_7/ANode/src/Alias.hpp b/ecflow_4_0_7/ANode/src/Alias.hpp
deleted file mode 100644
index 0b83d4a..0000000
--- a/ecflow_4_0_7/ANode/src/Alias.hpp
+++ /dev/null
@@ -1,94 +0,0 @@
-#ifndef ALIAS_HPP_
-#define ALIAS_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #17 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include "Submittable.hpp"
-
-class Alias : public Submittable {
-public:
- Alias(const std::string& name);
- Alias();
- virtual ~Alias();
-
- static alias_ptr create(const std::string& name);
-
- std::ostream& print(std::ostream&) const;
- bool operator==(const Alias& rhs) const;
-
- /// Overridden to reset the try number
- /// The tasks job can be invoked multiple times. For each invocation we want to preserve
- /// the output. The try number is used in SMSJOB/SMSJOBOUT to preserve the output when
- /// there are multiple runs. re-queue/begin() resets the try Number
- virtual void begin();
- virtual void requeue(bool resetRepeats, int clear_suspended_in_child_nodes, bool reset_next_time_slot);
-
- virtual Suite* suite() const { return parent()->suite(); }
- virtual Defs* defs() const { return (parent()) ? parent()->defs() : NULL;} // exposed to python hence check for NULL first
- virtual Alias* isAlias() const { return const_cast<Alias*>(this);}
- virtual Submittable* isSubmittable() const { return const_cast<Alias*>(this); }
-
- virtual const std::string& debugType() const;
-
- virtual node_ptr removeChild( Node* child);
- virtual bool addChild( node_ptr child, size_t position = std::numeric_limits<std::size_t>::max());
- virtual bool isAddChildOk( Node* child, std::string& errorMsg) const;
-
- virtual const std::string& script_extension() const;
-
- virtual void collateChanges(DefsDelta&) const;
- void set_memento(const SubmittableMemento* m) { Submittable::set_memento(m); }
-
- virtual node_ptr find_node_up_the_tree(const std::string& name) const;
-
- // Pure node Functions that are not implemented for aliases
- virtual node_ptr find_relative_node(const std::vector<std::string>&) {return node_ptr();}
-
- virtual void get_all_nodes(std::vector<node_ptr>& nodes) const;
-
-// Functions unique to aliases
- // Alias variable names by pass checking of valid names, allowing anything
- void add_alias_variable(const std::string& name, const std::string& value);
-
-private:
- virtual size_t child_position(const Node*) const;
-
- /// Job creation checking is typically called from python API
- /// This has been disabled for Aliases
- virtual void check_job_creation( job_creation_ctrl_ptr) {}
-
- // Overridden from Node to increment/decrement limits only
- // i.e we do not update parent computed states for aliases
- virtual void handleStateChange();
-
- // Pure node Functions that are not implemented for aliases
- virtual void accept(ecf::NodeTreeVisitor&){}
- virtual void acceptVisitTraversor(ecf::NodeTreeVisitor&){}
- virtual void get_all_tasks(std::vector<task_ptr>&) const {}
- virtual void get_all_aliases(std::vector<alias_ptr>&) const {}
- virtual void getAllNodes(std::vector<Node*>&) const {}
- virtual void getAllTasks(std::vector<Task*>&) const {}
- virtual void getAllSubmittables(std::vector<Submittable*>&) const {}
- virtual void get_all_active_submittables(std::vector<Submittable*>&) const {}
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/) {
- ar & boost::serialization::base_object<Submittable>(*this); // Serialise base class information
- }
-};
-
-std::ostream& operator<<(std::ostream& os, const Alias&);
-
-#endif
diff --git a/ecflow_4_0_7/ANode/src/Aspect.hpp b/ecflow_4_0_7/ANode/src/Aspect.hpp
deleted file mode 100644
index e7569da..0000000
--- a/ecflow_4_0_7/ANode/src/Aspect.hpp
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef ASPECT_HPP_
-#define ASPECT_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//
-// This class is used to provide observers with more info regarding
-// whats changed. used as a part of the observer pattern
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-
-#include <boost/noncopyable.hpp>
-
-namespace ecf {
-
-class Aspect : private boost::noncopyable {
-public:
- enum Type { NOT_DEFINED, ORDER, ADD_REMOVE_NODE, ADD_REMOVE_ATTR,
- METER, EVENT, LABEL, LIMIT, STATE, DEFSTATUS, SUSPENDED,
- SERVER_STATE, SERVER_VARIABLE, EXPR_TRIGGER, EXPR_COMPLETE, REPEAT,
- NODE_VARIABLE, LATE, TODAY, TIME,DAY, CRON, DATE,
- FLAG, SUBMITTABLE, SUITE_CLOCK, SUITE_BEGIN, SUITE_CALENDAR,
- ALIAS_NUMBER
- };
-
-private:
- Aspect();
-};
-
-}
-
-#endif
diff --git a/ecflow_4_0_7/ANode/src/ChangeMgrSingleton.cpp b/ecflow_4_0_7/ANode/src/ChangeMgrSingleton.cpp
deleted file mode 100644
index 9a58449..0000000
--- a/ecflow_4_0_7/ANode/src/ChangeMgrSingleton.cpp
+++ /dev/null
@@ -1,253 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #14 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <iostream>
-#include "ChangeMgrSingleton.hpp"
-#include "AbstractObserver.hpp"
-#include "Node.hpp"
-#include "Defs.hpp"
-
-using namespace std;
-//#define DEBUG_DEFS 1
-//#define DEBUG_NODE 1
-
-ChangeMgrSingleton* ChangeMgrSingleton::instance_ = NULL;
-
-ChangeMgrSingleton* ChangeMgrSingleton::instance()
-{
- if (instance_ == NULL) instance_ = new ChangeMgrSingleton();
- return instance_;
-}
-
-ChangeMgrSingleton* ChangeMgrSingleton::exists() { return instance_; }
-
-
-void ChangeMgrSingleton::attach(Node* n,AbstractObserver* a)
-{
- assert( n != NULL);
- assert( a != NULL);
- map_.insert( std::make_pair(n,a) );
-
-#ifdef DEBUG_NODE
- cout << "ChangeMgrSingleton::attach(Node*,AbstractObserver*) " << n->absNodePath() << " obs " << a << " map_.size() " << map_.size() << "\n";
-#endif
-}
-
-void ChangeMgrSingleton::attach(Defs* n,AbstractObserver* a)
-{
- assert( n != NULL);
- assert( a != NULL);
- defs_map_.insert( std::make_pair(n,a) );
-
-#ifdef DEBUG_DEFS
- cout << "ChangeMgrSingleton::attach(Defs*,AbstractObserver*) obs " << a << " defs_map_.size() " << defs_map_.size() << "\n";
-#endif
-}
-
-void ChangeMgrSingleton::detach(Node* n,AbstractObserver* a)
-{
- assert( n != NULL);
-#ifdef DEBUG_NODE
- cout << "ChangeMgrSingleton::detach(Node*) observer=" << a;
- if (n) cout << " node " << n->absNodePath() << "\n";
- else cout << " **NULL** node\n";
-#endif
-
-
- NodeObserverMap_t::iterator i = map_.find(n);
- if (i != map_.end()) {
- map_.erase(i);
- return;
- }
-
-#ifdef DEBUG_NODE
- if (!map_.empty()) {
- if (n) std::cout << "ChangeMgrSingleton::detach could not detach node " << n->debugNodePath() << "\n";
- else std::cout << "ChangeMgrSingleton::detach given a NULL Node\n";
- }
-#endif
-}
-
-void ChangeMgrSingleton::detach(Defs* n,AbstractObserver* a)
-{
-#ifdef DEBUG_DEFS
- cout << "ChangeMgrSingleton::detach(Defs*,AbstractObserver*) obs " << a << "\n";
-#endif
-
- assert( n != NULL);
- DefsObserverMap_t::iterator i = defs_map_.find(n);
- if (i != defs_map_.end()) {
- defs_map_.erase(i);
-
-#ifdef DEBUG_DEFS
- cout << "ChangeMgrSingleton::detach(Defs*,AbstractObserver*) defs_map_.size()= " << defs_map_.size() << "\n";
-#endif
- return;
- }
-}
-
-//static void dump_aspect_vec(std::vector<ecf::Aspect::Type>& aspects_vec, const std::string& desc)
-//{
-// cout << desc;
-// for(size_t i = 0; i < aspects_vec.size(); i++) {
-// switch (aspects_vec[i]) {
-// case ecf::Aspect::NOT_DEFINED: cout << "NOT_DEFINED "; break;
-// case ecf::Aspect::ORDER: cout << "ORDER "; break;
-// case ecf::Aspect::ADD_REMOVE_NODE: cout << "ADD_REMOVE_NODE "; break;
-// case ecf::Aspect::ADD_REMOVE_ATTR:cout << "ADD_REMOVE_ATTR "; break;
-// case ecf::Aspect::METER:cout << "METER "; break;
-// case ecf::Aspect::EVENT:cout << "EVENT "; break;
-// case ecf::Aspect::LABEL:cout << "LABEL "; break;
-// case ecf::Aspect::LIMIT:cout << "LIMIT "; break;
-// case ecf::Aspect::STATE:cout << "STATE "; break;
-// case ecf::Aspect::DEFSTATUS:cout << "DEFSTATUS "; break;
-// case ecf::Aspect::SUSPENDED:cout << "SUSPENDED "; break;
-// case ecf::Aspect::SERVER_STATE:cout << "SERVER_STATE "; break;
-// case ecf::Aspect::SERVER_VARIABLE:cout << "SERVER_VARIABLE "; break;
-// case ecf::Aspect::EXPR_TRIGGER:cout << "EXPR_TRIGGER "; break;
-// case ecf::Aspect::EXPR_COMPLETE:cout << "EXPR_COMPLETE "; break;
-// case ecf::Aspect::REPEAT:cout << "REPEAT "; break;
-// case ecf::Aspect::NODE_VARIABLE:cout << "NODE_VARIABLE "; break;
-// case ecf::Aspect::LATE:cout << "LATE "; break;
-// case ecf::Aspect::TODAY:cout << "TODAY "; break;
-// case ecf::Aspect::TIME:cout << "TIME "; break;
-// case ecf::Aspect::DAY:cout << "DAY "; break;
-// case ecf::Aspect::CRON:cout << "CRON "; break;
-// case ecf::Aspect::DATE:cout << "DATE "; break;
-// case ecf::Aspect::FLAG:cout << "FLAG "; break;
-// case ecf::Aspect::SUBMITTABLE:cout << "SUBMITTABLE "; break;
-// case ecf::Aspect::SUITE_CLOCK:cout << "SUITE_CLOCK "; break;
-// case ecf::Aspect::SUITE_BEGIN:cout << "SUITE_BEGIN "; break;
-// case ecf::Aspect::SUITE_CALENDAR:cout << "SUITE_CALENDAR "; break;
-// case ecf::Aspect::ALIAS_NUMBER:cout << "ALIAS_NUMBER "; break;
-// default: cout << "OOPS-unknown!! "; break;
-// }
-// }
-// cout << "\n";
-//}
-
-void ChangeMgrSingleton::notify(node_ptr n)
-{
- NodeObserverMap_t::iterator i = map_.find(n.get());
- if (i != map_.end()) {
-//#ifdef DEBUG
-// dump_aspect_vec(aspects_vec_,"ChangeMgrSingleton::notify(node_ptr n)******************************\n");
-//#endif
-
- (*i).second->update(n.get(),aspects_vec_);
- return;
- }
- // ************************************************************************
- // The GUI only attach's to nodes that are displayed. WE may well get
- // notification to nodes that are not attached. Hence this is not an error
- // ************************************************************************
-
-#ifdef DEBUG_NODE
- if (!map_.empty()) {
- /// Note: we don't deference the pointer, it may be corrupted ???
- if (n.get()) std::cout << "ChangeMgrSingleton::notify : received notification for node " << n->debugNodePath() << " thats not being observed\n";
- else std::cout << "ChangeMgrSingleton::notify : Error: given a NULL Node\n";
- }
-#endif
-}
-
-void ChangeMgrSingleton::notify(defs_ptr defs)
-{
- DefsObserverMap_t::iterator i = defs_map_.find(defs.get());
- if (i != defs_map_.end()) {
-//#ifdef DEBUG
-// dump_aspect_vec(aspects_vec_,"ChangeMgrSingleton::notify(defs_ptr defs)******************************\n");
-//#endif
-
- (*i).second->update(defs.get(),aspects_vec_);
- return;
- }
-
-#ifdef DEBUG_ME
- if (!defs_map_.empty()) {
- if (defs.get()) std::cout << "ChangeMgrSingleton::notify could not notify Defs that is not being observed\n";
- else std::cout << "ChangeMgrSingleton::notify given a NULL defs\n";
- }
-#endif
-}
-
-void ChangeMgrSingleton::notify_delete(Node* n)
-{
-#ifdef DEBUG_NODE
- cout << "ChangeMgrSingleton::notify_delete(Node*) node " << n->absNodePath() << "\n";
-#endif
-
- NodeObserverMap_t::iterator i = map_.find(n);
- if (i != map_.end()) {
-
- /// This must call detach(Node*)
- (*i).second->update_delete(n);
-
- /// Check to make sure that the Observer called detach
- /// We can not call detach ourselves, since the the client needs to
- /// call detach in the case where the graphical tree is destroyed by user
- /// In this case the Subject/Node is being deleted.
- assert(map_.find(n) == map_.end());
-
- return;
- }
-
-#ifdef DEBUG_NODE
- if (!map_.empty()) {
- /// Its not safe to call debugNodePath()/absNodePath() since that will traverse the parent
- /// This may not be safe during a delete.
- if (n) std::cout << "ChangeMgrSingleton::notify_delete : Node is not observed : " << n->name() << "\n";
- else std::cout << "ChangeMgrSingleton::notify_delete : Error: given a NULL Node\n";
- }
-#endif
-}
-
-void ChangeMgrSingleton::notify_delete(Defs* defs)
-{
-#ifdef DEBUG_DEFS
- cout << "ChangeMgrSingleton::notify_delete(Defs*)\n";
-#endif
- assert(defs);
-
- DefsObserverMap_t::iterator i = defs_map_.find(defs);
- if (i != defs_map_.end()) {
-
- /// This must call detach(Defs*)
- (*i).second->update_delete(defs);
-
- /// Check to make sure that the Observer called detach
- /// We can not call detach ourselves, since the the client needs to
- /// call detach in the case where the graphical tree is destroyed by user
- /// In this case the Subject/Node is being deleted.
- assert(defs_map_.find(defs) == defs_map_.end());
-
- return;
- }
-
-#ifdef DEBUG_DEFS
- if (!defs_map_.empty()) {
- if (defs) std::cout << "ChangeMgrSingleton::notify_delete: Defs is not being observed:\n";
- else std::cout << "ChangeMgrSingleton::notify_delete given a NULL defs\n";
- }
-#endif
-}
-
-void ChangeMgrSingleton::destroy()
-{
- delete instance_;
- instance_ = NULL;
-}
-
-ChangeMgrSingleton::ChangeMgrSingleton() : in_notification_(false) {}
-ChangeMgrSingleton::~ChangeMgrSingleton() {}
diff --git a/ecflow_4_0_7/ANode/src/ChangeMgrSingleton.hpp b/ecflow_4_0_7/ANode/src/ChangeMgrSingleton.hpp
deleted file mode 100644
index 0ecc440..0000000
--- a/ecflow_4_0_7/ANode/src/ChangeMgrSingleton.hpp
+++ /dev/null
@@ -1,107 +0,0 @@
-#ifndef CHANGE_MGR_SINGLETON_HPP_
-#define CHANGE_MGR_SINGLETON_HPP_
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-// Used on the client side, to notify any registered observers of
-// *incremental* changes to the node tree.
-// This is a variation of the observer pattern. In that we have avoided added
-// the observers directly to the Node. This was done because the observer
-// mechanism is only required by the client side, plus it avoids bloating the
-// Node with data members that are only used on the client side.
-// The disadvantage of this approach is it requires a look up for the Node:
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <map>
-#include <boost/noncopyable.hpp>
-#include "NodeFwd.hpp"
-#include "Aspect.hpp"
-
-class ChangeMgrSingleton : private boost::noncopyable {
-public:
- static ChangeMgrSingleton* instance();
-
- // Returns the ChangeMgr singleton without creating it
- static ChangeMgrSingleton* exists();
-
- /// Attach/detach interest in incremental change to the node
- void attach(Node*,AbstractObserver*);
- void attach(Defs*,AbstractObserver*);
- void detach(Node*,AbstractObserver*);
- void detach(Defs*,AbstractObserver*);
-
- /// Used in debug:
- size_t no_of_node_observers() const { return map_.size(); }
- size_t no_of_def_observers() const { return defs_map_.size(); }
-
- /// Detach interest in incremental changes to the node
- void detach(Node*);
- void detach(Defs*);
-
- /// returns true if we are in a notification. Help client code to avoid infinite cycles
- bool in_notification() const { return in_notification_;}
-
- /// The cumulated aspect are sent, when we do a the real notification
- void add_aspect(ecf::Aspect::Type aspect) { aspects_vec_.push_back(aspect) ;}
- void clear_aspects() { aspects_vec_.clear(); }
-
- /// Notify observer of a incremental change to Node
- /// Will return true for in_notification()
- void notify(node_ptr);
-
- /// Notify observer of a incremental change to Defs,
- /// Currently state or suspended attribute changes
- /// Will return true for in_notification()
- void notify(defs_ptr);
-
- /// Inform observers when the subject is about to be deleted
- /// The Observers *MUST* remember to call detach
- void notify_delete(Node*);
- void notify_delete(Defs*);
-
- static void destroy();
-
-private:
-
- ChangeMgrSingleton();
- ~ChangeMgrSingleton();
-
- /// Start of notifications:
- /// Aspect sent upon notify(node_ptr); notify(defs_ptr);
- void notify_start() { in_notification_ = true; }
- void notify_end() { in_notification_ = false; }
-
-private:
- std::map<Node*,AbstractObserver*> map_;
- typedef std::map<Node*,AbstractObserver*> NodeObserverMap_t;
-
- std::map<Defs*,AbstractObserver*> defs_map_;
- typedef std::map<Defs*,AbstractObserver*> DefsObserverMap_t;
-
- std::vector<ecf::Aspect::Type> aspects_vec_;
- static ChangeMgrSingleton* instance_;
-
- bool in_notification_;
- friend class ChangeMgrStartNotification;
-};
-
-// Start notification. End notification automatically signalled, Even if exception raised.
-// Note: notify_end() is also called in notify(node_ptr), notify(defs_ptr)
-class ChangeMgrStartNotification : private boost::noncopyable {
-public:
- ChangeMgrStartNotification() { ChangeMgrSingleton::instance()->notify_start();}
- ~ChangeMgrStartNotification() { ChangeMgrSingleton::instance()->notify_end();}
-};
-
-#endif
diff --git a/ecflow_4_0_7/ANode/src/ChildAttrs.cpp b/ecflow_4_0_7/ANode/src/ChildAttrs.cpp
deleted file mode 100644
index aaf3712..0000000
--- a/ecflow_4_0_7/ANode/src/ChildAttrs.cpp
+++ /dev/null
@@ -1,545 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #285 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <assert.h>
-
-#include "ChildAttrs.hpp"
-#include "Str.hpp"
-#include "Ecf.hpp"
-#include "Memento.hpp"
-#include "ChangeMgrSingleton.hpp"
-
-using namespace ecf;
-using namespace std;
-
-///////////////////////////////////////////////////////////////////////////////////////////
-void ChildAttrs::begin()
-{
- for(size_t i = 0; i < meters_.size(); i++) { meters_[i].reset(); }
- for(size_t i = 0; i < events_.size(); i++) { events_[i].reset(); }
- for(size_t i = 0; i < labels_.size(); i++) { labels_[i].reset(); }
-}
-
-void ChildAttrs::requeue()
-{
- for(size_t i = 0; i < meters_.size(); i++) { meters_[i].reset(); }
- for(size_t i = 0; i < events_.size(); i++) { events_[i].reset(); }
-
- // ECFLOW-195, only clear labels, if they are on Suites/Family not tasks(typically only specified on tasks)
- if (node_ && node_->isNodeContainer()) {
- for(size_t i = 0; i < labels_.size(); i++) { labels_[i].reset(); }
- }
-}
-
-void ChildAttrs::requeue_labels()
-{
- // ECFLOW-195, clear labels before a task is run.
- for(size_t i = 0; i < labels_.size(); i++) { labels_[i].reset(); }
-}
-
-void ChildAttrs::clear()
-{
- meters_.clear();
- events_.clear();
- labels_.clear();
-}
-
-bool ChildAttrs::set_event_used_in_trigger(const std::string& event_name_or_number)
-{
- if (events_.empty()) {
- return false;
- }
-
- // find by name first
- size_t theSize = events_.size();
- for(size_t i = 0; i < theSize; i++) {
- if (events_[i].name() == event_name_or_number) {
- events_[i].usedInTrigger( true );
- return true;
- }
- }
-
- // Test for numeric, and then casting, is ****faster***** than relying on exception alone
- if ( event_name_or_number.find_first_of( Str::NUMERIC(), 0 ) != std::string::npos ) {
- try {
- int eventNumber = boost::lexical_cast< int >( event_name_or_number );
- for(size_t i = 0; i < theSize; i++) {
- if (events_[i].number() == eventNumber) {
- events_[i].usedInTrigger( true );
- return true;;
- }
- }
- }
- catch ( boost::bad_lexical_cast&) {}
- }
- return false;
-}
-
-bool ChildAttrs::set_meter_used_in_trigger(const std::string& meter_name)
-{
- size_t the_meter_size = meters_.size();
- for(size_t i = 0; i < the_meter_size ; ++i) {
- if (meters_[i].name() == meter_name ) {
- meters_[i].usedInTrigger( true );
- return true;
- }
- }
- return false;
-}
-
-bool ChildAttrs::set_event( const std::string& event_name_or_number) {
- BOOST_FOREACH(Event& e, events_) {
- if (e.name_or_number() == event_name_or_number) {
- e.set_value( true );
- return true;
- }
- }
- return false;
-}
-bool ChildAttrs::set_event(const std::string& event_name_or_number ,bool value)
-{
- if (events_.empty()) {
- return false;
- }
-
- // find by name first
- size_t theSize = events_.size();
- for(size_t i = 0; i < theSize; i++) {
- if (events_[i].name() == event_name_or_number) {
- events_[i].set_value( value );
- return true;
- }
- }
-
- // Test for numeric, and then casting, is ****faster***** than relying on exception alone
- if ( event_name_or_number.find_first_of( Str::NUMERIC(), 0 ) != std::string::npos ) {
- try {
- int eventNumber = boost::lexical_cast< int >( event_name_or_number );
- for(size_t i = 0; i < theSize; i++) {
- if (events_[i].number() == eventNumber) {
- events_[i].set_value( value );
- return true;;
- }
- }
- }
- catch ( boost::bad_lexical_cast&) {}
- }
- return false;
-}
-
-bool ChildAttrs::set_meter(const std::string& meter_name,int value)
-{
- size_t the_meter_size = meters_.size();
- for(size_t i = 0; i < the_meter_size ; ++i) {
- if (meters_[i].name() == meter_name) {
- meters_[i].set_value( value);
- return true;
- }
- }
- return false;
-}
-
-bool ChildAttrs::clear_event(const std::string& event_name_or_number ){
- BOOST_FOREACH(Event& e, events_) {
- if (e.name_or_number() == event_name_or_number) {
- e.set_value( false );
- return true;
- }
- }
- return false;
-}
-
-void ChildAttrs::changeLabel(const std::string& name,const std::string& value)
-{
- size_t theSize = labels_.size();
- for(size_t i = 0; i < theSize; i++) {
- if (labels_[i].name() == name) {
- labels_[i].set_new_value( value );
- return;
- }
- }
- throw std::runtime_error("ChildAttrs::changeLabel: Could not find label " + name);
-}
-
-void ChildAttrs::changeEvent(const std::string& event_name_or_number,const std::string& setOrClear)
-{
- bool value;
- if (!setOrClear.empty()) {
- if (setOrClear != Event::SET() && setOrClear != Event::CLEAR() ) {
- throw std::runtime_error("ChildAttrs::changeEvent: Expected empty string, 'set' or 'clear' but found " + setOrClear + " for event " + event_name_or_number);
- }
- value = (setOrClear == Event::SET());
- }
- else value = true;
-
- changeEvent(event_name_or_number,value);
-}
-void ChildAttrs::changeEvent(const std::string& event_name_or_number,bool value)
-{
- if (set_event(event_name_or_number,value)) return;
- throw std::runtime_error("ChildAttrs::changeEvent: Could not find event " + event_name_or_number);
-}
-
-void ChildAttrs::changeMeter(const std::string& meter_name,const std::string& value)
-{
- int theValue = 0;
- try {
- theValue = boost::lexical_cast< int >( value );
- }
- catch ( boost::bad_lexical_cast& ) {
- throw std::runtime_error( "ChildAttrs::changeMeter expected integer value but found " + value);
- }
- changeMeter(meter_name,theValue);
-}
-void ChildAttrs::changeMeter(const std::string& meter_name,int value)
-{
- if (set_meter(meter_name,value)) return;
- throw std::runtime_error("ChildAttrs::changeMeter: Could not find meter " + meter_name);
-}
-
-std::ostream& ChildAttrs::print(std::ostream& os) const
-{
- BOOST_FOREACH(const Label& la, labels_ ) { la.print(os); }
- BOOST_FOREACH(const Meter& m, meters_ ) { m.print(os); }
- BOOST_FOREACH(const Event& e, events_ ) { e.print(os); }
- return os;
-}
-
-bool ChildAttrs::operator==(const ChildAttrs& rhs) const
-{
- if (labels_.size() != rhs.labels_.size()) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "ChildAttrs::operator== (labels_.size() != rhs.labels_.size()) " << node_->debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- for(unsigned i = 0; i < labels_.size(); ++i) {
- if (labels_[i] != rhs.labels_[i]) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "ChildAttrs::operator== (labels_[i] != rhs.labels_[i]) " << node_->debugNodePath() << "\n";
- std::cout << " lhs = " << labels_[i].dump() << "\n";
- std::cout << " rhs = " << rhs.labels_[i].dump() << "\n";
- }
-#endif
- return false;
- }
- }
-
- if (meters_.size() != rhs.meters_.size()) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "ChildAttrs::operator== (meters_.size() != rhs.meters_.size()) " << node_->debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- for(size_t i = 0; i < meters_.size(); ++i) {
- if (!(meters_[i] == rhs.meters_[i] )) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "ChildAttrs::operator== (!(meters_[i] == rhs.meters_[i] )) " << node_->debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- }
- if (events_.size() != rhs.events_.size()) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "ChildAttrs::operator== (events_.size() != rhs.events_.size()) " << node_->debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- for(size_t i = 0; i < events_.size(); ++i) {
- if (!(events_[i] == rhs.events_[i] )) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "ChildAttrs::operator== (!(events_[i] == rhs.events_[i] )) " << node_->debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- }
- return true;
-}
-
-bool ChildAttrs::getLabelValue(const std::string& labelName, std::string& value) const
-{
- size_t theSize = labels_.size();
- for(size_t i = 0; i < theSize; i++) {
- if (labels_[i].name() == labelName) {
- if (!(labels_[i].new_value().empty())) value = labels_[i].new_value();
- else value = labels_[i].value();
- return true;
- }
- }
- return false;
-}
-
-void ChildAttrs::addLabel( const Label& l)
-{
- if (findLabel(l.name())) {
- std::stringstream ss;
- ss << "Add Label failed: Duplicate label of name '" << l.name() << "' already exist for node " << node_->debugNodePath();
- throw std::runtime_error( ss.str() );
- }
- labels_.push_back( l );
- node_->state_change_no_ = Ecf::incr_state_change_no();
-}
-
-void ChildAttrs::addMeter( const Meter& m)
-{
- const Meter& meter = findMeter(m.name());
- if (!meter.empty()) {
- std::stringstream ss;
- ss << "Add Meter failed: Duplicate Meter of name '" << m.name() << "' already exist for node " << node_->debugNodePath();
- throw std::runtime_error( ss.str() );
- }
- meters_.push_back( m );
- node_->state_change_no_ = Ecf::incr_state_change_no();
-}
-
-void ChildAttrs::addEvent( const Event& e)
-{
- const Event& event = findEvent(e);
- if (!event.empty()) {
- std::stringstream ss;
- ss << "Add Event failed: Duplicate Event of name '" << e.name_or_number() << "' already exist for node " << node_->debugNodePath();
- throw std::runtime_error( ss.str() );
- }
- events_.push_back( e );
- node_->state_change_no_ = Ecf::incr_state_change_no();
-}
-
-
-void ChildAttrs::deleteEvent(const std::string& name)
-{
- if (name.empty()) {
- events_.clear();
- node_->state_change_no_ = Ecf::incr_state_change_no();
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "ChildAttrs::deleteEvent\n";
-#endif
- return;
- }
-
- size_t theSize = events_.size();
- for(size_t i = 0; i < theSize; i++) {
- if (events_[i].name_or_number() == name) {
- events_.erase( events_.begin() + i );
- node_->state_change_no_ = Ecf::incr_state_change_no();
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "ChildAttrs::deleteEvent\n";
-#endif
- return;
- }
- }
- throw std::runtime_error("ChildAttrs::deleteEvent: Can not find event: " + name);
-}
-
-void ChildAttrs::deleteMeter(const std::string& name)
-{
- if (name.empty()) {
- meters_.clear();
- node_->state_change_no_ = Ecf::incr_state_change_no();
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Expression::clearFree()\n";
-#endif
- return;
- }
-
- size_t theSize = meters_.size();
- for(size_t i = 0; i < theSize; i++) {
- if (meters_[i].name() == name) {
- meters_.erase( meters_.begin() + i );
- node_->state_change_no_ = Ecf::incr_state_change_no();
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Expression::clearFree()\n";
-#endif
- return;
- }
- }
- throw std::runtime_error("ChildAttrs::deleteMeter: Can not find meter: " + name);
-}
-
-void ChildAttrs::deleteLabel(const std::string& name)
-{
- if (name.empty()) {
- labels_.clear();
- node_->state_change_no_ = Ecf::incr_state_change_no();
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "ChildAttrs::deleteLabel\n";
-#endif
- return;
- }
-
- size_t theSize = labels_.size();
- for(size_t i = 0; i < theSize; i++) {
- if (labels_[i].name() == name) {
- labels_.erase( labels_.begin() + i );
- node_->state_change_no_ = Ecf::incr_state_change_no();
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "ChildAttrs::deleteLabel\n";
-#endif
- return;
- }
- }
- throw std::runtime_error("ChildAttrs::deleteLabel: Can not find label: " + name);
-}
-
-
-const Event& ChildAttrs::findEvent(const Event& theEvent) const
-{
- size_t theSize = events_.size();
- for(size_t i = 0; i < theSize; i++) {
- if (events_[i] == theEvent) {
- return events_[i];
- }
- }
- return Event::EMPTY();
-}
-
-const Event& ChildAttrs::findEventByNumber(int number) const
-{
- size_t theSize = events_.size();
- for(size_t i = 0; i < theSize; i++) {
- if (events_[i].number() == number) {
- return events_[i];
- }
- }
- return Event::EMPTY();
-}
-
-const Event& ChildAttrs::findEventByName( const std::string& event_name) const
-{
- size_t theSize = events_.size();
- for(size_t i = 0; i < theSize; i++) {
- if (events_[i].name() == event_name) {
- return events_[i];
- }
- }
- return Event::EMPTY();
-}
-
-const Event& ChildAttrs::findEventByNameOrNumber( const std::string& theName) const
-{
- const Event& event = findEventByName(theName);
- if (!event.empty()) {
- return event;
- }
-
- // Test for numeric, and then casting, is ****faster***** than relying on exception alone
- if ( theName.find_first_of( Str::NUMERIC(), 0 ) != std::string::npos ) {
- try {
- int eventNumber = boost::lexical_cast< int >( theName );
- return findEventByNumber(eventNumber);
- }
- catch ( boost::bad_lexical_cast&) {}
- }
- return Event::EMPTY();
-}
-
-
-
-const Meter& ChildAttrs::findMeter(const std::string& name) const
-{
- size_t theSize = meters_.size();
- for(size_t i = 0; i < theSize; i++) {
- if (meters_[i].name() == name) {
- return meters_[i];
- }
- }
- return Meter::EMPTY();
-}
-
-Meter& ChildAttrs::find_meter(const std::string& name)
-{
- size_t theSize = meters_.size();
- for(size_t i = 0; i < theSize; i++) {
- if (meters_[i].name() == name) {
- return meters_[i];
- }
- }
- return const_cast<Meter&>(Meter::EMPTY());
-}
-
-bool ChildAttrs::findLabel(const std::string& name) const
-{
- size_t theSize = labels_.size();
- for(size_t i = 0; i < theSize; i++) {
- if (labels_[i].name() == name) {
- return true;
- }
- }
- return false;
-}
-
-const Label& ChildAttrs::find_label(const std::string& name) const
-{
- size_t theSize = labels_.size();
- for(size_t i = 0; i < theSize; i++) {
- if (labels_[i].name() == name) {
- return labels_[i];
- }
- }
- return Label::EMPTY();
-}
-
-
-void ChildAttrs::set_memento( const NodeEventMemento* memento ) {
-
-#ifdef DEBUG_MEMENTO
- std::cout << "ChildAttrs::set_memento(const NodeEventMemento* memento) " << node_->debugNodePath() << "\n";
-#endif
-
- if (set_event(memento->event_.name_or_number(), memento->event_.value())) {
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::EVENT);
- return;
- }
- addEvent( memento->event_);
-}
-
-void ChildAttrs::set_memento( const NodeMeterMemento* memento ) {
-
-#ifdef DEBUG_MEMENTO
- std::cout << "ChildAttrs::set_memento(const NodeMeterMemento* memento) " << node_->debugNodePath() << "\n";
-#endif
-
- if (set_meter(memento->meter_.name(), memento->meter_.value())) {
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::METER);
- return;
- }
- addMeter(memento->meter_);
-}
-
-void ChildAttrs::set_memento( const NodeLabelMemento* memento ) {
-
-#ifdef DEBUG_MEMENTO
- std::cout << "ChildAttrs::set_memento(const NodeLabelMemento* memento) " << node_->debugNodePath() << "\n";
-#endif
-
- size_t theSize = labels_.size();
- for(size_t i = 0; i < theSize; i++) {
- if (labels_[i].name() == memento->label_.name()) {
- labels_[i] = memento->label_;
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::LABEL);
- return;
- }
- }
- addLabel(memento->label_);
-}
diff --git a/ecflow_4_0_7/ANode/src/ChildAttrs.hpp b/ecflow_4_0_7/ANode/src/ChildAttrs.hpp
deleted file mode 100644
index 1c15d52..0000000
--- a/ecflow_4_0_7/ANode/src/ChildAttrs.hpp
+++ /dev/null
@@ -1,132 +0,0 @@
-#ifndef CHILD_ATTRS_HPP_
-#define CHILD_ATTRS_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #234 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <ostream>
-
-#include <boost/noncopyable.hpp>
-#include <boost/serialization/base_object.hpp>
-#include <boost/serialization/utility.hpp>
-
-#include "NodeAttr.hpp"
-#include "NodeFwd.hpp"
-
-class ChildAttrs : private boost::noncopyable {
-public:
- ChildAttrs(Node* node) : node_(node) {}
- ChildAttrs() : node_(NULL) {}
- ~ChildAttrs() {}
-
- // needed by node serialisation
- void set_node(Node* n) { node_ = n; }
-
- void begin();
- void requeue();
- void requeue_labels();
-
- // standard functions: ==============================================
- std::ostream& print(std::ostream&) const;
- bool operator==(const ChildAttrs& rhs) const;
-
-// state related functions: ========================================
-
- // Access functions: ======================================================
- const std::vector<Meter>& meters() const { return meters_;}
- const std::vector<Event>& events() const { return events_;}
- const std::vector<Label>& labels() const { return labels_;}
-
- // Add functions: ===============================================================
- void addEvent( const Event& ); // will throw std::runtime_error if duplicate
- void addMeter( const Meter& ); // will throw std::runtime_error if duplicate
- void addLabel( const Label& ); // will throw std::runtime_error if duplicate
-
- // Delete functions: can throw std::runtime_error ===================================
- // if name argument is empty, delete all attributes of that type
- // Can throw std::runtime_error of the attribute can not be found
- void deleteEvent(const std::string& name);
- void deleteMeter(const std::string& name);
- void deleteLabel(const std::string& name);
-
- // Change functions: ================================================================
- /// returns true the change was made else false, Can throw std::runtime_error for parse errors
- void changeEvent(const std::string& name,const std::string& setOrClear = "");
- void changeEvent(const std::string& name,bool value);
- void changeMeter(const std::string& name,const std::string& value);
- void changeMeter(const std::string& name,int value);
- void changeLabel(const std::string& name,const std::string& value);
-
- bool set_meter(const std::string& name,int value); // does not throw if meter not found
- bool set_event(const std::string& name,bool value); // does not throw if event not found
-
- // Used in the force cmd
- bool set_event( const std::string& event_name_or_number);
- bool clear_event( const std::string& event_name_or_number);
-
- // mementos functions:
- void set_memento(const NodeEventMemento* );
- void set_memento(const NodeMeterMemento* );
- void set_memento(const NodeLabelMemento* );
-
- // Find functions: ============================================================
- bool findLabel(const std::string& name) const;
- const Label& find_label(const std::string& name) const;
- const Meter& findMeter(const std::string& name) const;
- Meter& find_meter(const std::string& name);
- const Event& findEvent(const Event&) const;
- const Event& findEventByNameOrNumber( const std::string& name) const;
- bool getLabelValue(const std::string& labelName, std::string& value) const;
-
-private:
-
- const Event& findEventByNumber(int number) const;
- const Event& findEventByName( const std::string& name) const;
- bool set_meter_used_in_trigger(const std::string& name);
- bool set_event_used_in_trigger(const std::string& name);
-
-private: // allow simulator access
- std::vector<Meter>& ref_meters() { return meters_;} // allow simulator set meter value
- std::vector<Event>& ref_events() { return events_;} // allow simulator set event value
-
-private: // All mementos access
- void clear(); /// Clear *ALL* internal attributes
-
-private: /// For use by python interface,
- friend class Node;
- std::vector<Meter>::const_iterator meter_begin() const { return meters_.begin();}
- std::vector<Meter>::const_iterator meter_end() const { return meters_.end();}
- std::vector<Event>::const_iterator event_begin() const { return events_.begin();}
- std::vector<Event>::const_iterator event_end() const { return events_.end();}
- std::vector<Label>::const_iterator label_begin() const { return labels_.begin();}
- std::vector<Label>::const_iterator label_end() const { return labels_.end();}
-
-private:
- std::vector<Meter> meters_;
- std::vector<Event> events_;
- std::vector<Label> labels_;
-
-private:
- Node* node_; // *NOT* persisted must be set by the parent class
-
-private:
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/) {
- ar & meters_;
- ar & events_;
- ar & labels_;
- }
-};
-#endif
diff --git a/ecflow_4_0_7/ANode/src/ClientSuiteMgr.cpp b/ecflow_4_0_7/ANode/src/ClientSuiteMgr.cpp
deleted file mode 100644
index afc208e..0000000
--- a/ecflow_4_0_7/ANode/src/ClientSuiteMgr.cpp
+++ /dev/null
@@ -1,280 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #23 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/bind.hpp>
-
-#include "ClientSuiteMgr.hpp"
-#include "Defs.hpp"
-#include "DefsDelta.hpp"
-#include "Ecf.hpp"
-
-using namespace ecf;
-using namespace std;
-
-//#define DEBUG_HANDLE 1
-
-ClientSuiteMgr::ClientSuiteMgr(Defs* defs) : defs_(defs) {}
-
-unsigned int ClientSuiteMgr::create_client_suite(bool auto_add_new_suites, const std::vector<std::string>& suites, const std::string& the_user)
-{
- // The handle must be unique. If there are holes, re-use them, i.e
- // 1,2,3,4,5 user deletes handle 3 ===> 1,2,4,5
- // Hence re-use handle 3
- bool found_hole = false;
- unsigned int new_handle = 1;
- for(size_t i = 0; i < clientSuites_.size(); i++) {
- if (clientSuites_[i].handle() == new_handle) {
- new_handle++;
- }
- else {
- found_hole = true;
- break;
- }
- }
- if (!found_hole) new_handle = clientSuites_.size() + 1;
-
- clientSuites_.push_back( ClientSuites(defs_,new_handle,auto_add_new_suites,suites,the_user) );
-
- // aesthetics only
- std::sort(clientSuites_.begin(),clientSuites_.end(),
- boost::bind(std::less<unsigned int>(),
- boost::bind(&ClientSuites::handle,_1),
- boost::bind(&ClientSuites::handle,_2)));
-
- // make sure all suites in ClientSuites are in same order as Defs suites
- update_suite_order();
-
-#ifdef DEBUG_HANDLE
- std::cout << "ClientSuiteMgr::create_client_suite: " << dump() << "\n";
-#endif
- return new_handle;
-}
-
-void ClientSuiteMgr::remove_client_suite(unsigned int client_handle)
-{
- size_t client_suites_size = clientSuites_.size();
- for(size_t i = 0; i < client_suites_size; i++) {
- if (clientSuites_[i].handle() == client_handle) {
- clientSuites_.erase( clientSuites_.begin() + i);
-#ifdef DEBUG_HANDLE
- std::cout << "ClientSuiteMgr::remove_client_suite: handle(" << client_handle << ") " << dump() << "\n";
-#endif
- return;
- }
- }
- std::stringstream ss; ss << "ClientSuiteMgr::remove_registered_suite: handle(" << client_handle << ") does not exist";
- throw std::runtime_error(ss.str());
-}
-
-void ClientSuiteMgr::remove_client_suites(const std::string& user_to_drop)
-{
- bool did_drop = false;
- for(std::vector<ecf::ClientSuites>::iterator i = clientSuites_.begin(); i!= clientSuites_.end(); ++i) {
- if ((*i).user() == user_to_drop) {
- did_drop = true;
- clientSuites_.erase(i--);
- }
- }
-
- if (!did_drop) {
- std::stringstream ss; ss << "ClientSuiteMgr::remove_registered_suites: user(" << user_to_drop << ") has no registered handles";
- throw std::runtime_error(ss.str());
- }
-
-#ifdef DEBUG_HANDLE
- std::cout << "ClientSuiteMgr::remove_client_suites: user_to_drop(" << user_to_drop << ") " << dump() << "\n";
-#endif
-}
-
-void ClientSuiteMgr::add_suites(unsigned int client_handle, const std::vector<std::string>& suites)
-{
- size_t client_suites_size = clientSuites_.size();
- for(size_t i = 0; i < client_suites_size; i++) {
- if (clientSuites_[i].handle() == client_handle) {
- for(size_t s = 0; s < suites.size(); s++) {
- clientSuites_[i].add_suite(suites[s]);
- }
-#ifdef DEBUG_HANDLE
- std::cout << "ClientSuiteMgr::add_suites: client_handle(" << client_handle << ") " << dump() << "\n";
-#endif
- update_suite_order();
- return;
- }
- }
- std::stringstream ss; ss << "ClientSuiteMgr::add_suites: handle(" << client_handle << ") does not exist";
- throw std::runtime_error(ss.str());
-}
-
-
-void ClientSuiteMgr::remove_suites(unsigned int client_handle, const std::vector<std::string>& suites)
-{
- size_t client_suites_size = clientSuites_.size();
- for(size_t i = 0; i < client_suites_size; i++) {
- if (clientSuites_[i].handle() == client_handle) {
- for(size_t s = 0; s < suites.size(); s++) {
- clientSuites_[i].remove_suite(suites[s]);
- }
-#ifdef DEBUG_HANDLE
- std::cout << "ClientSuiteMgr::remove_suites: client_handle(" << client_handle << ") " << dump() << "\n";
-#endif
- return;
- }
- }
- std::stringstream ss; ss << "ClientSuiteMgr::remove_suites: handle(" << client_handle << ") does not exist";
- throw std::runtime_error(ss.str());
-}
-
-
-void ClientSuiteMgr::auto_add_new_suites(unsigned int client_handle, bool auto_add_new_suites)
-{
- size_t client_suites_size = clientSuites_.size();
- for(size_t i = 0; i < client_suites_size; i++) {
- if (clientSuites_[i].handle() == client_handle) {
- clientSuites_[i].add_new_suite(auto_add_new_suites);
-
-#ifdef DEBUG_HANDLE
- std::cout << "ClientSuiteMgr::auto_add_new_suites: client_handle(" << client_handle << ") auto_add_new_suites(" << auto_add_new_suites << ") " << dump() << "\n";
-#endif
- return;
- }
- }
- std::stringstream ss; ss << "ClientSuiteMgr::auto_add_new_suites: handle(" << client_handle << ") does not exist";
- throw std::runtime_error(ss.str());
-}
-
-bool ClientSuiteMgr::valid_handle(unsigned int client_handle) const
-{
- size_t client_suites_size = clientSuites_.size();
- for(size_t i = 0; i < client_suites_size; i++) {
- if (clientSuites_[i].handle() == client_handle) {
- return true;
- }
- }
- return false;
-}
-
-/// returns true if the handle was created, or suites added or removed from it
-bool ClientSuiteMgr::handle_changed( unsigned int client_handle )
-{
- size_t client_suites_size = clientSuites_.size();
- for(size_t i = 0; i < client_suites_size; i++) {
- if (clientSuites_[i].handle() == client_handle) {
- return clientSuites_[i].handle_changed();
- }
- }
- return false;
-}
-
-void ClientSuiteMgr::collateChanges(unsigned int client_handle, DefsDelta& changes) const
-{
- // collate changes over the suites that match the client handle
- size_t client_suites_size = clientSuites_.size();
- for(size_t i = 0; i < client_suites_size; i++) {
- if ( clientSuites_[i].handle() == client_handle) {
- clientSuites_[i].collateChanges(changes);
- return;
- }
- }
-}
-
-void ClientSuiteMgr::suites(unsigned int client_handle, std::vector<std::string>& names) const
-{
- size_t client_suites_size = clientSuites_.size();
- for(size_t i = 0; i < client_suites_size; i++) {
- if ( clientSuites_[i].handle() == client_handle) {
- clientSuites_[i].suites(names);
- return;
- }
- }
-}
-
-defs_ptr ClientSuiteMgr::create_defs(unsigned int client_handle, defs_ptr server_defs) const
-{
- size_t client_suites_size = clientSuites_.size();
- for(size_t i = 0; i < client_suites_size; i++) {
- if (clientSuites_[i].handle() == client_handle) {
- return clientSuites_[i].create_defs(server_defs);
- }
- }
- return defs_ptr();
-}
-
-void ClientSuiteMgr::max_change_no(
- unsigned int client_handle,
- unsigned int& max_state_change_no ,
- unsigned int& max_modify_change_no)
-{
- size_t client_suites_size = clientSuites_.size();
- for(size_t i = 0; i < client_suites_size; i++) {
- if (clientSuites_[i].handle() == client_handle) {
- clientSuites_[i].max_change_no(max_state_change_no,max_modify_change_no);
- return;
- }
- }
- std::stringstream ss; ss << "ClientSuiteMgr::max_change_no: handle(" << client_handle << ") does not exist in server. Server may have died? Please re-register suites";
- throw std::runtime_error(ss.str());
-}
-
-
-void ClientSuiteMgr::suite_added_in_defs(suite_ptr suite)
-{
- size_t client_suites_size = clientSuites_.size();
- for(size_t i = 0; i < client_suites_size; i++) {
- clientSuites_[i].suite_added_in_defs(suite);
- clientSuites_[i].update_suite_order();
- }
-}
-
-void ClientSuiteMgr::suite_deleted_in_defs(suite_ptr suite)
-{
- size_t client_suites_size = clientSuites_.size();
- for(size_t i = 0; i < client_suites_size; i++) {
- clientSuites_[i].suite_deleted_in_defs(suite);
- }
-}
-
-void ClientSuiteMgr::update_suite_order()
-{
- size_t client_suites_size = clientSuites_.size();
- for(size_t i = 0; i < client_suites_size; i++) {
- clientSuites_[i].update_suite_order();
- }
-}
-
-
-std::string ClientSuiteMgr::dump_max_change_no() const
-{
- std::stringstream ss;
- ss << "ClientSuiteMgr::dump_max_change_no: ECF:(" << Ecf::state_change_no() << "," << Ecf::modify_change_no() << ")\n";
- size_t client_suites_size = clientSuites_.size();
- for(size_t i = 0; i < client_suites_size; i++) {
- unsigned int max_state_change_no = 0;
- unsigned int max_modify_change_no = 0;
- clientSuites_[i].max_change_no(max_state_change_no,max_modify_change_no);
- ss << "handle: " << clientSuites_[i].handle() << " max(" << max_state_change_no << "," << max_modify_change_no << ")\n";
- }
- return ss.str();
-}
-
-/// For debug dumps
-std::string ClientSuiteMgr::dump() const
-{
- size_t client_suites_size = clientSuites_.size();
- std::stringstream ss;
- ss << "ECF:(" << Ecf::state_change_no() << "," << Ecf::modify_change_no() << ") clientSuites_.size(" << client_suites_size << ")\n";
- for(size_t i = 0; i < client_suites_size; i++) {
- ss << clientSuites_[i].dump() << "\n";
- }
- return ss.str();
-}
diff --git a/ecflow_4_0_7/ANode/src/ClientSuiteMgr.hpp b/ecflow_4_0_7/ANode/src/ClientSuiteMgr.hpp
deleted file mode 100644
index a2f9255..0000000
--- a/ecflow_4_0_7/ANode/src/ClientSuiteMgr.hpp
+++ /dev/null
@@ -1,118 +0,0 @@
-#ifndef CLIENT_SUITES_MGR_HPP_
-#define CLIENT_SUITES_MGR_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #24 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//
-// The client may only want to view a small subset of the suites available
-// in a defs file. This class manages the client handles
-//
-// Users are allowed to register interest in suite that have not yet been added
-// This will only work provided we have a definition
-//
-// Only handle with value > 0 are valid. This is because sync() and news() command
-// take a client_handle. By reserving a client handle of zero, we can sync with the
-// full defs.
-//
-// ***************************************************************************
-// Note: Change of suite order is handled by OrderMemento
-// and *NOT* by the ClientSuiteMgr, however whenever suites are
-// registered and added/deleted:
-// then:
-// defs_ptr create_defs(unsigned int client_handle) const;
-//
-// Will return the suites in the same order as the defs
-// ****************************************************************************
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <boost/noncopyable.hpp>
-#include "ClientSuites.hpp"
-class DefsDelta;
-
-class ClientSuiteMgr : private boost::noncopyable {
-public:
- ClientSuiteMgr(Defs*);
-
- /// Create a client suite, and return the handle associated with the created object
- unsigned int create_client_suite(bool auto_add_new_suites, const std::vector<std::string>& suites, const std::string& user);
-
-
- /// These function can throw std::runtime_error if the handle can not be found
- void remove_client_suite(unsigned int client_handle);
- void remove_client_suites(const std::string& user_to_drop);
- void add_suites(unsigned int client_handle, const std::vector<std::string>& suites);
- void remove_suites(unsigned int client_handle, const std::vector<std::string>& suites);
- void auto_add_new_suites(unsigned int client_handle, bool auto_add_new_suites);
-
- /// Return true if the input handle is valid
- bool valid_handle(unsigned int client_handle) const;
-
- /// returns true if the handle was created, or suites added or removed from it
- /// The handle change flag is reset when create_defs is called
- bool handle_changed( unsigned int client_handle );
-
-
- /// Collect all the state changes, so that only small subset is returned to client
- /// When nodes are added/deleted we use the modify_change_no_, in this case
- /// the whole defs is returned. Both integers are returned back to the client
- /// so that, the client then sends the integers back to server, so we can determine
- /// what's changed.
- void collateChanges(unsigned int client_handle,DefsDelta&) const;
-
-
- // Only return the defs state and suites that the client has registered in the client handle
- // *HOWEVER* if the client has registered all the suites, just return the server defs
- // *with* the updated change numbers
- // *OTHERWISE*
- /// This will also compute the **maximum** state and modify change numbers over
- /// the suites managed by the client handle.
- /// and then set it on the newly created defs.
- /// It also takes special precaution *NOT* to change Ecf::state_change_no() and Ecf::modify_change_no()
- /// This will clear the handle_changed flag
- defs_ptr create_defs(unsigned int client_handle, defs_ptr server_defs) const;
-
- /// Used to determine the change, will throw if handle not found
- void max_change_no(unsigned int client_handle,unsigned int& max_state_change_no , unsigned int& max_modify_change_no);
-
- /// Accessor
- const std::vector<ecf::ClientSuites>& clientSuites() const { return clientSuites_;}
-
- /// returns the list of suites associated with a handle, Used by ecFlowview
- void suites(unsigned int client_handle, std::vector<std::string>& names) const;
-
- /// A suite is being added in the definition.
- /// If the suite was previously registered *UPDATE* its suite_ptr
- /// Otherwise if any ClientSuites registered for automatic inclusion of new suite, add them in
- void suite_added_in_defs(suite_ptr);
-
- /// The suite is being deleted in the definition, reset the suite_ptr
- /// Deleted suites STAY registered, until explicitly dropped.
- void suite_deleted_in_defs(suite_ptr);
-
- /// Update suites to be in same order as Defs.
- void update_suite_order();
-
- /// remove all client Suites
- void clear() { clientSuites_.clear(); }
-
- /// Returns a string which has the max state change and modify numbers for each handle
- std::string dump_max_change_no() const;
-
- /// For debug dumps
- std::string dump() const;
-
-private:
- std::vector<ecf::ClientSuites> clientSuites_;
- Defs* defs_;
-};
-#endif
diff --git a/ecflow_4_0_7/ANode/src/ClientSuites.cpp b/ecflow_4_0_7/ANode/src/ClientSuites.cpp
deleted file mode 100644
index cb10c51..0000000
--- a/ecflow_4_0_7/ANode/src/ClientSuites.cpp
+++ /dev/null
@@ -1,332 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #35 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <boost/bind.hpp>
-
-#include "ClientSuites.hpp"
-#include "Suite.hpp"
-#include "Defs.hpp"
-#include "DefsDelta.hpp"
-#include "Ecf.hpp"
-
-//#define DEBUG_ME 1
-
-namespace ecf {
-
-ClientSuites::ClientSuites(Defs* defs,unsigned int handle, bool auto_add_new_suites, const std::vector<std::string>& suites,const std::string& user)
-: defs_(defs),
- handle_(handle),
- state_change_no_(0),
- modify_change_no_(0),
- auto_add_new_suites_(auto_add_new_suites),
- handle_changed_(false),
- user_(user)
-{
- BOOST_FOREACH(const std::string& s, suites) {
- add_suite(s);
- }
-}
-
-void ClientSuites::add_suite(const std::string& s)
-{
- suite_ptr suite = defs_->findSuite(s);
- if (suite.get()) {
- add_suite(suite);
- }
- else {
- std::vector<HSuite>::iterator i = find_suite(s);
- if (i != suites_.end()) {
- (*i).weak_suite_ptr_ = weak_suite_ptr();
- }
- else {
- suites_.push_back( HSuite(s) );
- }
- }
-}
-
-void ClientSuites::add_suite(suite_ptr suite)
-{
- if (suite.get()) {
-
- // *IMPORTANT* update weak_suite_ptr_
- std::vector<HSuite>::iterator i = find_suite(suite->name());
- if (i != suites_.end()) {
- (*i).weak_suite_ptr_ = weak_suite_ptr(suite);
- }
- else {
- suites_.push_back( HSuite(suite->name(),weak_suite_ptr(suite)) );
- }
- handle_changed_ = true;
-
-#ifdef DEBUG_ME
- i = suites_.find_suite(suite->name());
- assert(i != suites_.end());
- assert((*i).weak_suite_ptr_.lock().get());
-#endif
- }
-}
-
-void ClientSuites::remove_suite(const std::string& s)
-{
- std::vector<HSuite>::iterator i = find_suite(s);
- if (i != suites_.end()) {
- if ( (*i).weak_suite_ptr_.lock().get() ) {
- handle_changed_ = true;
- }
- suites_.erase(i);
- }
-}
-
-bool ClientSuites::remove_suite(suite_ptr suite)
-{
- if (suite.get()) {
- std::vector<HSuite>::iterator i = find_suite(suite->name());
- if (i != suites_.end()) {
- handle_changed_ = true;
- suites_.erase(i);
- return true;
- }
- }
- return false;
-}
-
-
-void ClientSuites::suite_added_in_defs(suite_ptr suite)
-{
- if (auto_add_new_suites_) add_suite(suite);
- else {
- // *IF* and *ONLY IF* the suite was previously registered added, *UPDATE* its suite_ptr
- std::vector<HSuite>::iterator i = find_suite(suite->name());
- if (i != suites_.end()) {
- // previously registered suite, update
- add_suite(suite);
- }
- }
-}
-
-void ClientSuites::suite_deleted_in_defs(suite_ptr suite)
-{
- // Deleted suites are *NOT* automatically removed
- // They have to be moved explicitly by the user. Reset to weak ptr
- if (suite.get()) {
- std::vector<HSuite>::iterator i = find_suite(suite->name());
- if (i != suites_.end()) {
- handle_changed_ = true;
- modify_change_no_ = Ecf::modify_change_no(); // need to pass back to client
- (*i).weak_suite_ptr_ = weak_suite_ptr(); // reset suite ptr, not strictly necessary
- }
- }
-}
-
-void ClientSuites::collateChanges(DefsDelta& changes) const
-{
- BOOST_FOREACH(const HSuite& s, suites_) {
- suite_ptr suite = s.weak_suite_ptr_.lock();
- if (suite.get()) {
- if (suite->state_change_no() > changes.client_state_change_no()) {
- suite->collateChanges( changes );
- }
- }
- }
-}
-
-defs_ptr ClientSuites::create_defs(defs_ptr server_defs) const
-{
- /// Clear handle changed, so we can detect suites added or removed for this handle
- handle_changed_ = false;
-
- // If the user has registered *ALL* the suites just return the server defs
- std::vector<HSuite>::const_iterator suites_end = suites_.end();
- if (suites_.size() == server_defs->suiteVec().size()) {
- size_t real_suite_count = 0;
- for(std::vector<HSuite>::const_iterator i = suites_.begin(); i != suites_end; ++i) {
- suite_ptr suite = (*i).weak_suite_ptr_.lock();
- if (suite.get()) real_suite_count++;
- }
- if ( real_suite_count == server_defs->suiteVec().size()) {
-
- server_defs->set_state_change_no( Ecf::state_change_no() );
- server_defs->set_modify_change_no( Ecf::modify_change_no() );
-
- // Update local modify_change_no_ *AND* state_change_no_
- // ***** Note: Otherwise NewsCmd which computes change numbers over
- // ***** registered suites will not be correct. causing unnecessary sync's
- modify_change_no_ = Ecf::modify_change_no();
- state_change_no_ = Ecf::state_change_no();
- return server_defs;
- }
- }
-
-
- // CREATE NEW DEFS, using the registered suites
- //
- // *** We do not use local state_change_no_. That is used ONLY when all suites ***
- // *** are registered. ***
- //
- // add_suite() below will incremented the modify_change_no.
- // We don't want to do this, as change for suites *not in* the our handle will get skewed
- // This class ensure that any changes made are reset to their original values
- EcfPreserveChangeNo preserveChangeNo;
-
- // Create defs to be sent to the client, with the registered suites.
- defs_ptr newly_created_defs = Defs::create();
- {
- // Initialise the defs state. We need to reflect the real state.
- newly_created_defs->set_state( server_defs->state() );
-
- // Initialise the server state
- newly_created_defs->set_server().set_state( server_defs->server().get_state() );
- newly_created_defs->set_server().set_user_variables( server_defs->server().user_variables() );
- newly_created_defs->set_server().set_server_variables( server_defs->server().server_variables() );
- }
-
-
- // Store the state/modify change number to the newly created defs *over* the objects that have changed
- unsigned int the_max_state_change_no = server_defs->defs_only_max_state_change_no();
- unsigned int the_max_modify_change_no = 0;
-
- // Handle suites that get deleted. Need a full sync
- the_max_modify_change_no = std::max( the_max_modify_change_no, modify_change_no_ );
-
- // Suites should already be in order
- for(std::vector<HSuite>::const_iterator i = suites_.begin(); i != suites_end; ++i) {
- suite_ptr suite = (*i).weak_suite_ptr_.lock();
- if (suite.get()) {
-
- // Preserve the change/modify numbers, as these will updated on the suite, by addSuite() below
- unsigned int suite_state_change_no = suite->state_change_no();
- unsigned int suite_modify_change_no = suite->modify_change_no();
-
- the_max_state_change_no = std::max( the_max_state_change_no, suite_state_change_no );
- the_max_modify_change_no = std::max( the_max_modify_change_no, suite_modify_change_no );
-
- // To avoid copying the suites, we will just add the suites, to the newly created defs
- // However this presents a problem with the suites defs pointer. To avoid corrupting
- // the server, we must reset the defs pointer.
- // The newly_created_defs/Defs serialisation will re-adjust the suites defs pointer
- Defs* old_defs = suite->defs();
-
- // This will end up setting the suite's defs pointer to 'newly_created_defs'.
- // This is wrong, since we only have a single suite
- suite->set_defs(NULL); // otherwise addSuite, will complain
- newly_created_defs->addSuite(suite); // will update modify_change_no, see comment at top
-
- suite->set_defs(old_defs); // reset the defs, since addSuite() changed defs ptr
- suite->set_state_change_no(suite_state_change_no); // reset in case addSuite() changed this
- suite->set_modify_change_no(suite_modify_change_no); // reset in case addSuite() changed this
- }
- }
-
- // Store the max in the defs, for transmission to client. The client uses this for syncing
- newly_created_defs->set_state_change_no(the_max_state_change_no);
- newly_created_defs->set_modify_change_no(the_max_modify_change_no);
- return newly_created_defs;
-}
-
-
-void ClientSuites::max_change_no(unsigned int& the_max_state_change_no,unsigned int& the_max_modify_change_no ) const
-{
- /// get the max state change_no due to:
- /// o Defs state changed
- /// o Suite order changed
- /// o Defs flag changed
- /// o Defs server state changed.
- /// o Defs server variables changed
- the_max_state_change_no = defs_->defs_only_max_state_change_no();
-
- // Take into account case where all suites are registered
- the_max_state_change_no = std::max( the_max_state_change_no, state_change_no_ );
-
- // Take into account registered suites that get deleted, and where all suites registered
- the_max_modify_change_no = 0;
- the_max_modify_change_no = std::max( the_max_modify_change_no, modify_change_no_ );
-
- BOOST_FOREACH(const HSuite& p, suites_) {
- suite_ptr suite = p.weak_suite_ptr_.lock();
- if (suite.get()) {
- the_max_modify_change_no = std::max( the_max_modify_change_no, suite->modify_change_no() );
- the_max_state_change_no = std::max( the_max_state_change_no, suite->state_change_no() );
- }
- }
-}
-
-void ClientSuites::suites(std::vector<std::string>& names) const
-{
- names.reserve(suites_.size());
- std::vector<HSuite>::const_iterator suites_end = suites_.end();
- for(std::vector<HSuite>::const_iterator i = suites_.begin(); i != suites_end; ++i) {
- names.push_back( (*i).name_ );
- }
-}
-
-std::string ClientSuites::dump() const
-{
- unsigned int maxstatechangeno = 0;
- unsigned int maxmodifychangeno = 0;
- max_change_no(maxstatechangeno,maxmodifychangeno);
-
- std::stringstream ss;
- ss << " handle(" << handle() << ") user(" << user_ << ") auto_add_new_suites(" << auto_add_new_suites_
- << ") suites_.size(" << suites_.size() << ") suites(";
-
- std::vector<HSuite>::const_iterator suites_end = suites_.end();
- for(std::vector<HSuite>::const_iterator i = suites_.begin(); i != suites_end; ++i) {
- suite_ptr suite = (*i).weak_suite_ptr_.lock();
- if (suite.get()) {
- ss << " " << suite->name();
- }
- else {
- ss << " " << (*i).name_ << ":NULL";
- }
- }
- ss << ") max(" << maxstatechangeno << "," << maxmodifychangeno << ")";
- return ss.str();
-}
-
-
-void ClientSuites::update_suite_order()
-{
- const std::vector<suite_ptr>& server_suite_vec = defs_->suiteVec();
- size_t server_suite_vec_size = server_suite_vec.size();
-
- std::vector<HSuite>::iterator suites_end = suites_.end();
- for(std::vector<HSuite>::iterator i = suites_.begin(); i != suites_end; ++i) {
- for(size_t s = 0; s < server_suite_vec_size; s++) {
- if ((*i).name_ == server_suite_vec[s]->name()) {
- (*i).index_ = static_cast<int>(s);
- break;
- }
- }
- }
-
- std::sort(suites_.begin(),suites_.end(),
- boost::bind(std::less<int>(),
- boost::bind(&HSuite::index_,_1),
- boost::bind(&HSuite::index_,_2)));
-
-}
-
-std::vector<HSuite>::iterator ClientSuites::find_suite(const std::string& name)
-{
- std::vector<HSuite>::iterator suites_end = suites_.end();
- for(std::vector<HSuite>::iterator i = suites_.begin(); i != suites_end; ++i) {
- if ((*i).name_ == name) {
- return i;
- }
- }
- return suites_end;
-}
-
-}
diff --git a/ecflow_4_0_7/ANode/src/ClientSuites.hpp b/ecflow_4_0_7/ANode/src/ClientSuites.hpp
deleted file mode 100644
index 15ba795..0000000
--- a/ecflow_4_0_7/ANode/src/ClientSuites.hpp
+++ /dev/null
@@ -1,145 +0,0 @@
-#ifndef CLIENT_SUITES_HPP_
-#define CLIENT_SUITES_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #26 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-// The definition file could hold hundreds of suites, however the client
-// may only be interested in a small subset. By allowing the client to register
-// the suites they are interested in, we can reduce the network traffic
-// when they ask for updates.(ie via sync or news)
-// When the Client registers an interest in suites it is returned a handle,
-// this handle must is passed back to the server as a reference, with the sync'ing commands
-//
-// Users are allowed to register interest in suite that have not yet been added
-// This will only work provided we have a definition
-//
-// ***************************************************************************
-// Note: Change of suite order is handled by OrderMemento
-// and *NOT* by the ClientSuites, however whenever suites are:
-// registered and added/deleted:
-// then:
-// defs_ptr create_defs(Defs* server_defs) const;
-//
-// Will return the suites in the same order as the defs
-// ****************************************************************************
-//
-// Uses compiler generated copy constructor and destructor
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <string>
-#include <vector>
-#include <limits>
-#include "NodeFwd.hpp"
-
-namespace ecf {
-
-struct HSuite {
- HSuite(const std::string& name, weak_suite_ptr p, int index = std::numeric_limits<int>::max())
- : name_(name), weak_suite_ptr_(p),index_(index) {}
-
- HSuite(const std::string& name )
- : name_(name),index_(std::numeric_limits<int>::max()) {}
-
- std::string name_; // suite name
- weak_suite_ptr weak_suite_ptr_; // does suite exist in defs, need to lock, to find out
- int index_; // suites in handles must be in same order as defs
-};
-
-class ClientSuites {
-public:
- /// Will automatically create a unique handle
- ClientSuites(Defs*,unsigned int handle, bool auto_add_new_suites, const std::vector<std::string>& suites , const std::string& user);
-
- /// Return the handle, returned to the client, and required for all correspondence
- /// between client server. This value is always > 0
- unsigned int handle() const { return handle_;}
-
- /// return the user who requested this handle
- const std::string& user() const { return user_; }
-
- /// The handle changed flag is set to true whenever a ClinetSuites is created
- /// or when suites are added/removed from it. The alternative way would have
- /// been to update the modify change number, but this would have affected all handles
- bool handle_changed() const { return handle_changed_; }
-
- /// Add an interest to this suite
- void add_suite(const std::string&);
- void add_suite(suite_ptr);
-
- /// no longer interested in this suite. Explicit remove
- void remove_suite(const std::string&);
- bool remove_suite(suite_ptr);
-
- /// A new suite is being added in the definition.
- /// If it was already registered update the suite ptr
- /// If auto add new suite enabled,register it
- void suite_added_in_defs(suite_ptr);
-
- /// The suite is being deleted, update modify_change_no. So we do a full sync
- /// RESETs suite ptr. Deleted suites are *NOT* automatically removed
- void suite_deleted_in_defs(suite_ptr);
-
- /// Collate the incremental changes, made to my suites
- void collateChanges(DefsDelta& changes) const;
-
- // Only return the defs state and suites that the client has registered in this suite
- // *HOWEVER* if the client has registered all the suites, just return the server defs
- // *with* the updated change numbers
- // *OTHERWISE*
- /// Creates a new defs, by adding the suites to the defs
- /// The defs is to be transferred to the client
- /// Suites are returned in the same order as the defs
- /// We avoid copying, but need to adjust suites defs pointer
- /// This will clear the handle_changed_ flag
- defs_ptr create_defs(defs_ptr server_defs) const;
-
- // iterates overs its suites and return max state and modify change numbers
- void max_change_no(unsigned int& state_change_no,unsigned int& modify_change_no ) const;
-
- /// Enable/disable interest in new suites.
- /// if the flag is true, when ever new suites are added to the defs
- /// The internal list is updated.
- void add_new_suite( bool flag ) { auto_add_new_suites_ = flag;}
- bool auto_add_new_suites() const { return auto_add_new_suites_;}
-
- /// returns the list of suites
- void suites(std::vector<std::string>& names) const;
-
- /// Update suites to be in same order as Defs.
- /// This should be done externally to avoid update after individual add
- void update_suite_order();
-
- /// For debug dumps
- std::string dump() const;
-
-private:
- std::vector<HSuite>::iterator find_suite(const std::string& name);
-
-private:
- Defs* defs_;
- unsigned int handle_; // This must be unique
-
- // The modify_change_no_ is required specifically when a registered suite is deleted
- // Both modify_change_no_ & state_change_no_ are required when user has registered
- // with *ALL* the suites. In this case we need to ensure that after a SYNC/create_defs
- // the NewsCmd call to max_change_no() is in sync with global change numbers.
- mutable unsigned int state_change_no_;
- mutable unsigned int modify_change_no_;
-
- bool auto_add_new_suites_;
- mutable bool handle_changed_; // set when handle created, or when suites added/removed
- std::string user_; // user who create this handle
- std::vector<HSuite> suites_;
-};
-}
-#endif
diff --git a/ecflow_4_0_7/ANode/src/CmdContext.cpp b/ecflow_4_0_7/ANode/src/CmdContext.cpp
deleted file mode 100644
index 4e32b61..0000000
--- a/ecflow_4_0_7/ANode/src/CmdContext.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #16 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//============================================================================
-
-#include "CmdContext.hpp"
-
-namespace ecf {
-bool CmdContext::in_command_ = false;
-
-CmdContext::CmdContext()
-{
- in_command_ = true;
-}
-
-CmdContext::~CmdContext()
-{
- in_command_ = false;
-}
-
-}
diff --git a/ecflow_4_0_7/ANode/src/CmdContext.hpp b/ecflow_4_0_7/ANode/src/CmdContext.hpp
deleted file mode 100644
index 877f8fd..0000000
--- a/ecflow_4_0_7/ANode/src/CmdContext.hpp
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef CMD_CONTEXT_HPP_
-#define CMD_CONTEXT_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #14 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-// This class allow client to determine whether they are in a middle
-// of a command.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <boost/noncopyable.hpp>
-
-namespace ecf {
-
-class CmdContext : private boost::noncopyable {
-public:
- CmdContext();
- ~CmdContext();
-
- static bool in_command() { return in_command_; }
-
-private:
- static bool in_command_;
-};
-}
-
-#endif
diff --git a/ecflow_4_0_7/ANode/src/Defs.cpp b/ecflow_4_0_7/ANode/src/Defs.cpp
deleted file mode 100644
index bd42768..0000000
--- a/ecflow_4_0_7/ANode/src/Defs.cpp
+++ /dev/null
@@ -1,1468 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #270 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <assert.h>
-#include <sstream>
-#include <fstream>
-#include <boost/bind.hpp>
-#include <boost/make_shared.hpp>
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "Log.hpp"
-#include "PrintStyle.hpp"
-#include "NodeTreeVisitor.hpp"
-#include "Str.hpp"
-#include "Extract.hpp"
-#include "NodePath.hpp"
-#include "Stl.hpp"
-#include "Ecf.hpp"
-#include "NodeState.hpp"
-#include "ExprAst.hpp" // required for persistence
-#include "Serialization.hpp" // collates boost archive includes
-#include "JobCreationCtrl.hpp"
-#include "ResolveExternsVisitor.hpp"
-#include "DefsDelta.hpp"
-#include "ChangeMgrSingleton.hpp"
-#include "ExprDuplicate.hpp"
-#include "Version.hpp"
-#include "Indentor.hpp"
-
-using namespace ecf;
-using namespace std;
-
-//#define DEBUG_JOB_SUBMISSION 1
-//#define DEBUG_MEMENTO 1
-
-Defs::Defs() :
- state_change_no_(0),
- modify_change_no_( 0 ),
- updateCalendarCount_(0),
- order_state_change_no_(0),
- save_edit_history_(false),
- client_suite_mgr_(this)
-{
-}
-
-defs_ptr Defs::create()
-{
- return boost::make_shared<Defs>();
-}
-
-Defs::~Defs()
-{
-// cout << " Deleting defs "\n";
- // Don't create the ChangeMgrSingleton during destruct sequence. (i.e in unit cases)
- // Since that will cause a memory leak
- if (!Ecf::server() && ChangeMgrSingleton::exists()) {
- ChangeMgrSingleton::instance()->notify_delete( this );
- }
-
- // Duplicate AST are held in a static map. Delete them, to avoid valgrind complaining
- ExprDuplicate reclaim_cloned_ast_memory;
-}
-
-///// State relation functions: ==================================================
-NState::State Defs::state() const
-{
- return state_.state();
-}
-
-void Defs::set_state_only(NState::State the_new_state)
-{
- state_.setState( the_new_state ); // this will update state_change_no
-}
-
-void Defs::set_state(NState::State the_new_state)
-{
- set_state_only( the_new_state ); // this will update state_change_no
-
- // Log the state change
- // " " + submitted(max) + ": /"
- // reserve : 1 + 9 + 3 = 13
- std::string log_state_change; log_state_change.reserve(13);
- log_state_change += " ";
- log_state_change += NState::toString(the_new_state);
- log_state_change += ": /";
- ecf::log(Log::LOG,log_state_change);
-}
-
-void Defs::set_most_significant_state()
-{
- NState::State computedStateOfImmediateChildren = ecf::theComputedNodeState(suiteVec_, true /* immediate children only */ );
- if (computedStateOfImmediateChildren != state_.state() )
- set_state( computedStateOfImmediateChildren );
-}
-
-/// Others ======================================================================
-void Defs::check_job_creation( job_creation_ctrl_ptr jobCtrl )
-{
- /// Job generation checking. is done via the python API
- /// As such it done directly on the Defs.
- /// However Job generation checking will end up changing the states of the DEFS
- /// If this defs is loaded into the server the state of each node may be surprising. (i.e submitted)
- /// Hence we need to reset the state.
-
- if (!jobCtrl.get()) {
- throw std::runtime_error("Defs::check_job_creation: NULL JobCreationCtrl passed");
- }
-
- // This function should NOT really change the data model
- // The changed state is reset, hence we need to preserve change and modify numbers
- EcfPreserveChangeNo preserveChangeNo;
-
- // Do *not* modify suspended state of child nodes
- int clear_suspended_in_child_nodes = -1;
-
- if (jobCtrl->node_path().empty()) {
-
- size_t theSize = suiteVec_.size();
- for(size_t s = 0; s < theSize; s++) {
- /// begin will cause creation of generated variables. The generated variables
- /// are use in client scripts and used to locate the ecf files
- suiteVec_[s]->begin();
- suiteVec_[s]->check_job_creation( jobCtrl ) ;
-
- /// reset the state
- suiteVec_[s]->requeue(true,clear_suspended_in_child_nodes,true);
- suiteVec_[s]->reset_begin();
- suiteVec_[s]->setStateOnlyHierarchically( NState::UNKNOWN );
- }
- }
- else {
-
- node_ptr node = findAbsNode( jobCtrl->node_path() );
- if (node.get()) {
- /// begin will cause creation of generated variables. The generated variables
- /// are use in client scripts and used to locate the ecf files
- node->suite()->begin();
- node->check_job_creation( jobCtrl );
-
- /// reset the state
- node->requeue(true,clear_suspended_in_child_nodes,true);
- node->suite()->reset_begin();
- node->setStateOnlyHierarchically( NState::UNKNOWN );
- }
- else {
- std::stringstream ss;
- ss << "Defs::check_job_creation: failed as node path '" << jobCtrl->node_path() << "' does not exist.\n";
- jobCtrl->error_msg() = ss.str();
- }
- }
-}
-
-void Defs::do_generate_scripts( const std::map<std::string,std::string>& override) const
-{
- size_t theSize = suiteVec_.size();
- for(size_t s = 0; s < theSize; s++) {
- suiteVec_[s]->generate_scripts(override);
- }
-}
-void Defs::generate_scripts() const
-{
- std::map<std::string,std::string> override;
- do_generate_scripts(override);
-}
-
-
-void Defs::updateCalendar( const ecf::CalendarUpdateParams & calUpdateParams)
-{
- /// Collate any auto cancelled nodes as a result of calendar update
- std::vector<node_ptr> auto_cancelled_nodes;
-
- // updateCalendarCount_ is only used in *test*
- updateCalendarCount_++;
-
- size_t theSize = suiteVec_.size();
- for(size_t s = 0; s < theSize; s++) {
- suiteVec_[s]->updateCalendar( calUpdateParams, auto_cancelled_nodes);
- }
-
- // Permanently remove any auto-cancelled nodes.
- if ( !auto_cancelled_nodes.empty() ) {
- std::vector<node_ptr>::iterator theNodeEnd = auto_cancelled_nodes.end();
- string msg;
- for(std::vector<node_ptr>::iterator n = auto_cancelled_nodes.begin(); n != theNodeEnd; ++n) {
- msg.clear(); msg = "autocancel "; msg += (*n)->debugNodePath();
- ecf::log(Log::MSG,msg);
- (*n)->remove();
- }
- }
-}
-
-
-void Defs::absorb(Defs* input_defs, bool force)
-{
- // Dont absorb myself.
- if (input_defs == this) {
- return;
- }
-
- // updateCalendarCount_ is *only* used in test, reset whenever a new defs is loaded
- updateCalendarCount_ = 0;
-
- // We must make a copy, otherwise we are iterating over a vector that is being deleted
- std::vector<suite_ptr> suiteVecCopy = input_defs->suiteVec();
- size_t theSize = suiteVecCopy.size();
- for(size_t s = 0; s < theSize; s++) {
-
- /// regardless remove the suite from the input defs
- suite_ptr the_input_suite = input_defs->removeSuite(suiteVecCopy[s]);
-
- if (force) {
- /// The suite of the same name exists. remove it from *existing* defs
- suite_ptr existing_suite = findSuite( the_input_suite->name() );
- if (existing_suite.get()) {
- removeSuite( existing_suite );
- }
- }
-
- /// Add the suite. Will throw if suite of same name already exists.
- /// This stops accidental overwrite
- addSuite( the_input_suite );
- }
- LOG_ASSERT( input_defs->suiteVec().empty(),"Defs::absorb");
-
- // Copy over server user variables
- set_server().add_or_update_user_variables( input_defs->server().user_variables() );
-
- // This only works on the client side. since server does not store externs
- const set<string>& ex = input_defs->externs();
- for(set<string>::const_iterator i = ex.begin(); i != ex.end(); ++i) {
- add_extern(*i);
- }
-}
-
-void Defs::accept(ecf::NodeTreeVisitor& v)
-{
- v.visitDefs(this);
- size_t theSuiteVecSize = suiteVec_.size();
- for(size_t i = 0; i < theSuiteVecSize; i++) { suiteVec_[i]->accept(v); }
-}
-
-void Defs::acceptVisitTraversor(ecf::NodeTreeVisitor& v)
-{
- LOG_ASSERT(v.traverseObjectStructureViaVisitors(),"");
- v.visitDefs(this);
-}
-
-bool Defs::verification(std::string& errorMsg) const
-{
- size_t theSuiteVecSize = suiteVec_.size();
- for(size_t i = 0; i < theSuiteVecSize; i++) { suiteVec_[i]->verification(errorMsg); }
- return errorMsg.empty();
-}
-
-suite_ptr Defs::add_suite(const std::string& name)
-{
- if (findSuite(name).get()) {
- std::stringstream ss;
- ss << "Add Suite failed: A Suite of name '" << name << "' already exist";
- throw std::runtime_error( ss.str() );
- }
- suite_ptr the_suite = Suite::create(name);
- add_suite_only( the_suite , std::numeric_limits<std::size_t>::max());
- return the_suite;
-}
-
-void Defs::addSuite(suite_ptr s, size_t position)
-{
- if (findSuite(s->name()).get()) {
- std::stringstream ss;
- ss << "Add Suite failed: A Suite of name '" << s->name() << "' already exist";
- throw std::runtime_error( ss.str() );
- }
- add_suite_only( s , position);
-}
-
-void Defs::add_suite_only(suite_ptr s, size_t position)
-{
- if (s->defs()) {
- std::stringstream ss;
- ss << "Add Suite failed: The suite of name '" << s->name() << "' already owned by another Defs ";
- throw std::runtime_error( ss.str() );
- }
-
- s->set_defs(this);
- if (position >= suiteVec_.size()) {
- suiteVec_.push_back(s);
- }
- else {
- suiteVec_.insert( suiteVec_.begin() + position, s);
- }
- Ecf::incr_modify_change_no();
- client_suite_mgr_.suite_added_in_defs(s);
-}
-
-suite_ptr Defs::removeSuite(suite_ptr s)
-{
- std::vector<suite_ptr>::iterator i = std::find(suiteVec_.begin(), suiteVec_.end(),s);
- if ( i != suiteVec_.end()) {
- s->set_defs(NULL); // allows suite to added to different defs
- suiteVec_.erase(i); // iterator invalidated
- Ecf::incr_modify_change_no();
- client_suite_mgr_.suite_deleted_in_defs(s); // must be after Ecf::incr_modify_change_no();
- return s; // transfer ownership of suite
- }
-
- // Something serious has gone wrong. Can not find the suite
- cout << "Defs::removeSuite: assert failure: suite '" << s->name() << "' suiteVec_.size() = " << suiteVec_.size() << "\n";
- for(unsigned i = 0; i < suiteVec_.size(); ++i) { cout << i << " " << suiteVec_[i]->name() << "\n";}
- LOG_ASSERT(false,"Defs::removeSuite the suite not found");
- return suite_ptr();
-}
-
-size_t Defs::child_position(const Node* child) const
-{
- size_t vecSize = suiteVec_.size();
- for(size_t t = 0; t < vecSize; t++) {
- if (suiteVec_[t].get() == child) {
- return t;
- }
- }
- return std::numeric_limits<std::size_t>::max();
-}
-
-node_ptr Defs::removeChild(Node* child)
-{
- size_t vecSize = suiteVec_.size();
- for(size_t t = 0; t < vecSize; t++) {
- if (suiteVec_[t].get() == child) {
- Ecf::incr_modify_change_no();
- suiteVec_[t]->set_defs(NULL); // Must be set to NULL, allows suite to be added to different defs
- client_suite_mgr_.suite_deleted_in_defs(suiteVec_[t]); // must be after Ecf::incr_modify_change_no();
- node_ptr node = boost::dynamic_pointer_cast<Node>(suiteVec_[t]);
- suiteVec_.erase( suiteVec_.begin() + t);
- return node ;
- }
- }
-
- // Something has gone wrong.
- cout << "Defs::removeChild: assert failed: suite '" << child->name() << "' suiteVec_.size() = " << suiteVec_.size() << "\n";
- for(unsigned i = 0; i < suiteVec_.size(); ++i) { cout << i << " " << suiteVec_[i]->name() << "\n";}
- LOG_ASSERT(false,"Defs::removeChild,the suite not found");
- return node_ptr();
-}
-
-bool Defs::addChild( node_ptr child, size_t position)
-{
- LOG_ASSERT(child.get(),"");
- LOG_ASSERT(child->isSuite(),"");
-
- // *** CANT construct shared_ptr from a raw pointer, must use dynamic_pointer_cast,
- // *** otherwise the reference counts will get messed up.
- // If the suite of the same exists, it is deleted first
- addSuite( boost::dynamic_pointer_cast<Suite>( child ), position );
- return true;
-}
-
-void Defs::add_extern(const std::string& ex )
-{
- if (ex.empty()) {
- throw std::runtime_error("Defs::add_extern: Can not add empty extern");
- }
- externs_.insert(ex);
-}
-
-void Defs::auto_add_externs(bool remove_existing_externs_first)
-{
- if (remove_existing_externs_first) {
- externs_.clear();
- }
- /// Automatically add externs
- ResolveExternsVisitor visitor(this);
- acceptVisitTraversor(visitor);
-}
-
-void Defs::beginSuite(suite_ptr suite)
-{
- if (!suite.get()) throw std::runtime_error( "Defs::beginSuite: Begin failed as suite is not loaded" );
-
- if (!suite->begun()) {
- // Hierarchical set the state. Handle case where we have children that are all defstatus complete
- // and hence needs parent set to complete. See Simulator/good_defs/operations/naw.def
- // family naw
- // family general
- // time 06:00
- // task metgrams
- // defstatus complete
- // task equipot
- // defstatus complete
- // endfamily
- suite->begin();
-
- set_most_significant_state();
- }
- else {
- LOG(Log::WAR,"Suite " << suite->name() << " has already begun");
- }
-}
-
-void Defs::beginAll()
-{
- bool at_least_one_suite_begun = false;
- size_t theSuiteVecSize = suiteVec_.size();
- for(size_t s = 0; s < theSuiteVecSize; s++) {
- if ( !suiteVec_[s]->begun() ) {
- suiteVec_[s]->begin();
- at_least_one_suite_begun = true;
- }
- }
-
- if ( at_least_one_suite_begun ) {
- set_most_significant_state();
- }
-}
-
-void Defs::reset_begin()
-{
- std::for_each(suiteVec_.begin(),suiteVec_.end(),boost::bind(&Suite::reset_begin,_1));
-}
-
-void Defs::requeue()
-{
- bool edit_history_set = flag().is_set(ecf::Flag::MESSAGE);
- flag_.reset();
- if (edit_history_set) flag().set(ecf::Flag::MESSAGE);
-
- int clear_suspended_in_child_nodes = 0;
- size_t theSuiteVecSize = suiteVec_.size();
- for(size_t s = 0; s < theSuiteVecSize; s++) {
- suiteVec_[s]->requeue( true /* reset repeats */,
- clear_suspended_in_child_nodes,
- true /* reset_next_time_slot */);
- }
-
- set_most_significant_state();
-}
-
-
-void Defs::check_suite_can_begin(suite_ptr suite) const
-{
- NState::State suiteState = suite->state();
- if (!suite->begun() && suiteState != NState::UNKNOWN && suiteState != NState::COMPLETE) {
- int count = 0;
- std::vector<Task*> tasks;
- getAllTasks(tasks);
- std::stringstream ts;
- for(size_t i =0; i < tasks.size(); i++) {
- if (tasks[i]->state() == NState::ACTIVE || tasks[i]->state() == NState::SUBMITTED) {
- ts << " " << tasks[i]->absNodePath() << "\n";
- count++;
- }
- }
- /// allow suite to begin even its aborted provide no tasks in active or submitted states
- if (count > 0) {
- std::stringstream ss;
- ss << "Begin failed as suite "
- << suite->name() << "(computed state=" << NState::toString(suiteState)
- << ") can only begin if its in UNKNOWN or COMPLETE state\n";
- ss << "Found " << count << " tasks with state 'active' or 'submitted'\n";
- ss << ts.str();
- ss << "Use the force argument to bypass this check, at the risk of creating zombies\n";
- throw std::runtime_error( ss.str() );
- }
- }
-}
-
-bool Defs::hasTimeDependencies() const
-{
- size_t theSuiteVecSize = suiteVec_.size();
- for(size_t s = 0; s < theSuiteVecSize; s++) {
- if ( suiteVec_[s]->hasTimeDependencies() ) return true;
- }
- return false;
-}
-
-std::ostream& Defs::print(std::ostream& os) const
-{
- os << "# " << ecf::Version::raw() << "\n";
- if (!PrintStyle::defsStyle()) {
- os << write_state();
- }
-
- set<string>::const_iterator extern_end = externs_.end();
- for(set<string>::const_iterator i = externs_.begin(); i != extern_end; ++i) {
- os << "extern " << *i << "\n";
- }
- size_t the_size = suiteVec_.size();
- for(size_t s = 0; s < the_size; s++) {
- os << *suiteVec_[s];
- }
- return os;
-}
-
-std::string Defs::write_state() const
-{
- // *IMPORTANT* we *CANT* use ';' character, since is used in the parser, when we have
- // multiple statement on a single line i.e.
- // task a; task b;
- // *IMPORTANT* make sure name are unique, i.e can't have state: and server_state:
- // Otherwise read_state() will mess up
- std::stringstream os;
- os << "defs_state";
- os << " " << PrintStyle::to_string();
- if (state_ != NState::UNKNOWN) os << " state>:" << NState::toString(state_); // make <state> is unique
- if (flag_.flag() != 0) os << " flag:" << flag_.to_string();
- if (state_change_no_ != 0) os << " state_change:" << state_change_no_;
- if (modify_change_no_ != 0) os << " modify_change:" << modify_change_no_;
- if (server().get_state() != ServerState::default_state()) os << " server_state:" << SState::to_string(server().get_state());
- os << "\n";
-
- // This read by the DefsStateParser
- const std::vector<Variable>& theServerEnv = server().user_variables();
- for(size_t i = 0; i < theServerEnv.size(); ++i) {
- theServerEnv[i].print(os);
- }
-
- // READ by Defs::read_history()
- // We need to define a separator for the message, will to allow it to be re-read
- // This separator can not be :
- // ' ' space, used in the messages
- // % Used in job submission
- // : Used in time, and name (:ma0)
- // [] Used in time
- // integers used in the time.
- // - Used in commands
- if (PrintStyle::getStyle() == PrintStyle::MIGRATE || save_edit_history_) {
- Indentor in;
- std::map<std::string, std::deque<std::string> >::const_iterator i;
- for(i=edit_history_.begin(); i != edit_history_.end(); ++i) {
- Indentor::indent( os ) << "history " << (*i).first << " ";// node path
- const std::deque<std::string>& vec = (*i).second; // list of requests
- for(std::deque<std::string>::const_iterator c = vec.begin(); c != vec.end(); ++c) {
-
- // We expect to output a single newline, hence if there are additional new lines
- // It can mess up, re-parse. i.e during alter change label/value, user could have added newlines
- if ((*c).find("\n") == std::string::npos) os << "\b" << *c;
- else {
- std::string h = *c;
- Str::replaceall(h,"\n","\\n");
- os << "\b" << h;
- }
- }
- os << "\n";
- }
- save_edit_history_ = false;
- }
- return os.str();
-}
-
-void Defs::read_state(const std::string& line,const std::vector<std::string>& lineTokens)
-{
-// cout << "line = " << line << "\n";
- std::string token;
- for(size_t i = 2; i < lineTokens.size(); i++) {
- token.clear();
- if (lineTokens[i].find("state>:") != std::string::npos) {
- if (!Extract::split_get_second(lineTokens[i],token)) throw std::runtime_error( "Defs::read_state: state extraction failed : " + lineTokens[i] );
- if (!NState::isValid(token)) throw std::runtime_error( "Defs::read_state: invalid state specified : " + token );
- set_state_only(NState::toState(token));
- }
- else if (lineTokens[i].find("flag:") != std::string::npos) {
- if (!Extract::split_get_second(lineTokens[i],token))throw std::runtime_error( "Defs::read_state: Invalid flag specified : " + line );
- flag().set_flag(token); // this can throw
- }
- else if (lineTokens[i].find("state_change:") != std::string::npos) {
- if (!Extract::split_get_second(lineTokens[i],token)) throw std::runtime_error( "Defs::read_state: Invalid state_change specified : " + line );
- int sc = Extract::theInt(token,"Defs::read_state: invalid state_change specified : " + line);
- set_state_change_no(sc);
- }
- else if (lineTokens[i].find("modify_change:") != std::string::npos) {
- if (!Extract::split_get_second(lineTokens[i],token)) throw std::runtime_error( "Defs::read_state: Invalid modify_change specified : " + line );
- int mc = Extract::theInt(token,"Defs::read_state: invalid state_change specified : " + line);
- set_modify_change_no(mc);
- }
- else if (lineTokens[i].find("server_state:") != std::string::npos) {
- if (!Extract::split_get_second(lineTokens[i],token)) throw std::runtime_error( "Defs::read_state: Invalid server_state specified : " + line );
- if (!SState::isValid(token)) throw std::runtime_error( "Defs::read_state: Invalid server_state specified : " + line );
- set_server().set_state(SState::toState(token));
- }
- }
-}
-
-void Defs::read_history(const std::string& line,const std::vector<std::string>& lineTokens)
-{
- // expect:
- // history <node_path> \bmsg1\bmsg2
- // The message can contain spaces,
- // Multiple spaces will be lost !!
- if ( lineTokens.size() < 2 ) throw std::runtime_error( "Defs::read_history: Invalid history " + line );
-
- DefsHistoryParser parser;
- parser.parse(line);
-
- const std::vector<std::string>& parsed_messages = parser.parsed_messages();
- for(size_t i = 0; i < parsed_messages.size(); i++) {
- add_edit_history(lineTokens[1],parsed_messages[i]);
- }
-}
-
-bool Defs::compare_edit_history(const Defs& rhs) const
-{
- if (edit_history_ != rhs.edit_history_) return false;
- return true;
-}
-
-
-bool Defs::operator==(const Defs& rhs) const
-{
- if ( state() != rhs.state()) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Defs::operator== state(" << NState::toString(state()) << ") != rhs.state(" << NState::toString(rhs.state()) << ")) \n";
- }
-#endif
- return false;
- }
-
- if ( server_ != rhs.server() ) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Defs::operator== server_ != rhs.server())\n";
- }
-#endif
- return false;
- }
-
- if ( flag_ != rhs.flag_) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Defs::operator== ( flag_ != rhs.flag_) : '" << flag_.to_string() << "' != '" << rhs.flag_.to_string() << "'\n";
- }
-#endif
- return false;
- }
-
- /// Note:: WE specifically exclude testing of externs.
- /// Externs are not persisted, hence can not take part in comparison
- /// Externs only live on the client side.
-
- if ( suiteVec_.size() != rhs.suiteVec_.size()) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Defs::operator== suiteVec_.size(" << suiteVec_.size() << ") != rhs.suiteVec_.size( " << rhs.suiteVec_.size() << ") \n";
- }
-#endif
- return false;
- }
- for(unsigned i =0; i < suiteVec_.size(); ++i) {
- if ( !( *(suiteVec_[i]) == *(rhs.suiteVec_[i]) )) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Defs::operator== !( *(suiteVec_[i]) == *(rhs.suiteVec_[i]) )\n";
- }
-#endif
- return false;
- }
- }
- return true;
-}
-
-node_ptr Defs::findAbsNode(const std::string& pathToNode) const
-{
-// std::cout << "Defs::findAbsNode " << pathToNode << "\n";
- // The pathToNode is of the form:
- // /suite
- // /suite/family
- // /suite/family/task
- // /suite/family/family/family/task
-
- std::vector<std::string> theNodeNames; theNodeNames.reserve(4);
- NodePath::split(pathToNode,theNodeNames);
- if ( theNodeNames.empty() ) {
- return node_ptr();
- }
-
-
- size_t child_pos = 0 ; // unused
- size_t pathSize = theNodeNames.size();
- size_t theSuiteVecSize = suiteVec_.size();
- for(size_t s = 0; s < theSuiteVecSize; s++) {
-
- size_t index = 0;
- if (theNodeNames[index] == suiteVec_[s]->name()) {
-
- node_ptr the_node = suiteVec_[s];
- if (pathSize == 1) return the_node;
- index++; // skip over suite,
-
- while (index < pathSize) {
- the_node = the_node->findImmediateChild(theNodeNames[index],child_pos);
- if (the_node) {
- if (index == pathSize - 1) return the_node;
- index++;
- }
- else {
- return node_ptr();
- }
- }
- return node_ptr();
- }
- }
-
- return node_ptr();
-}
-
-node_ptr Defs::find_closest_matching_node(const std::string& pathToNode) const
-{
- std::vector<std::string> theNodeNames;
- NodePath::split(pathToNode,theNodeNames);
- if ( theNodeNames.empty() ) return node_ptr();
-
- node_ptr closest_matching_node;
- int index = 0;
- size_t theSuiteVecSize = suiteVec_.size();
- for(size_t s = 0; s < theSuiteVecSize; s++) {
- suiteVec_[s]->find_closest_matching_node(theNodeNames,index,closest_matching_node);
- if (closest_matching_node.get()) return closest_matching_node;
- }
- return node_ptr();
-}
-
-
-bool Defs::find_extern( const std::string& pathToNode , const std::string& node_attr_name ) const
-{
- if (externs_.empty()) {
- return false;
- }
-
- if (node_attr_name.empty()) {
- if (externs_.find(pathToNode) != externs_.end()) {
- return true;
- }
- return false;
- }
-
- std::string extern_path = pathToNode;
- extern_path += Str::COLON();
- extern_path += node_attr_name;
-
- if (externs_.find(extern_path) != externs_.end()) {
- return true;
- }
- return false;
-}
-
-
-suite_ptr Defs::findSuite(const std::string& name) const
-{
- size_t theSuiteVecSize = suiteVec_.size();
- for(size_t s = 0; s < theSuiteVecSize; s++) {
- if (suiteVec_[s]->name() == name) {
- return suiteVec_[s];
- }
- }
- return suite_ptr();
-}
-
-bool Defs::check(std::string& errorMsg,std::string& warningMsg) const
-{
- size_t theSuiteVecSize = suiteVec_.size();
- for(size_t s = 0; s < theSuiteVecSize; s++) { suiteVec_[s]->check(errorMsg,warningMsg); }
- return errorMsg.empty();
-}
-
-void Defs::getAllTasks(std::vector<Task*>& tasks) const
-{
- size_t theSuiteVecSize = suiteVec_.size();
- for(size_t s = 0; s < theSuiteVecSize; s++) { suiteVec_[s]->getAllTasks(tasks);}
-}
-
-void Defs::getAllSubmittables(std::vector<Submittable*>& tasks) const
-{
- size_t theSuiteVecSize = suiteVec_.size();
- for(size_t s = 0; s < theSuiteVecSize; s++) { suiteVec_[s]->getAllSubmittables(tasks);}
-}
-
-void Defs::get_all_active_submittables(std::vector<Submittable*>& tasks) const
-{
- size_t theSuiteVecSize = suiteVec_.size();
- for(size_t s = 0; s < theSuiteVecSize; s++) { suiteVec_[s]->get_all_active_submittables(tasks);}
-}
-
-void Defs::get_all_tasks(std::vector<task_ptr>& tasks) const
-{
- size_t theSuiteVecSize = suiteVec_.size();
- for(size_t s = 0; s < theSuiteVecSize; s++) { suiteVec_[s]->get_all_tasks(tasks);}
-}
-
-void Defs::get_all_nodes(std::vector<node_ptr>& nodes) const
-{
- size_t theSuiteVecSize = suiteVec_.size();
- for(size_t s = 0; s < theSuiteVecSize; s++) { suiteVec_[s]->get_all_nodes(nodes);}
-}
-
-void Defs::get_all_aliases(std::vector<alias_ptr>& aliases) const
-{
- size_t theSuiteVecSize = suiteVec_.size();
- for(size_t s = 0; s < theSuiteVecSize; s++) { suiteVec_[s]->get_all_aliases(aliases);}
-}
-
-void Defs::getAllFamilies(std::vector<Family*>& vec) const
-{
- size_t theSuiteVecSize = suiteVec_.size();
- for(size_t s = 0; s < theSuiteVecSize; s++) { suiteVec_[s]->getAllFamilies(vec);}
-}
-
-void Defs::getAllNodes(std::vector<Node*>& vec) const
-{
- size_t theSuiteVecSize = suiteVec_.size();
- vec.reserve(vec.size() + theSuiteVecSize);
- for(size_t s = 0; s < theSuiteVecSize; s++) {
- vec.push_back(suiteVec_[s].get());
- suiteVec_[s]->getAllNodes(vec);
- }
-}
-
-void Defs::getAllAstNodes(std::set<Node*>& theSet) const
-{
- size_t theSuiteVecSize = suiteVec_.size();
- for(size_t s = 0; s < theSuiteVecSize; s++) { suiteVec_[s]->getAllAstNodes(theSet);}
-}
-
-bool Defs::deleteChild(Node* nodeToBeDeleted)
-{
- Node* parent = nodeToBeDeleted->parent();
- if (parent) return parent->doDeleteChild(nodeToBeDeleted);
- return doDeleteChild(nodeToBeDeleted);
-}
-
-bool Defs::doDeleteChild(Node* nodeToBeDeleted)
-{
-// std::cout << "Defs::doDeleteChild nodeToBeDeleted = " << nodeToBeDeleted->debugNodePath() << "\n";
-
- std::vector<suite_ptr>::iterator theSuiteEnd = suiteVec_.end();
- for(std::vector<suite_ptr>::iterator s = suiteVec_.begin(); s!=theSuiteEnd; ++s) {
- if ( (*s).get() == nodeToBeDeleted) {
- Ecf::incr_modify_change_no();
- client_suite_mgr_.suite_deleted_in_defs(*s); // must be after Ecf::incr_modify_change_no();
- (*s)->set_defs(NULL); // Must be set to NULL, allows re-added to a different defs
- suiteVec_.erase(s);
- set_most_significant_state(); // must be after suiteVec_.erase(s);
- return true;
- }
- }
-
- // recurse down only if we did not remove the suite
- for(std::vector<suite_ptr>::iterator s = suiteVec_.begin(); s!=theSuiteEnd; ++s) {
- // SuiteChanged is called within doDeleteChild
- if ((*s)->doDeleteChild(nodeToBeDeleted)) {
- return true;
- }
- }
- return false;
-}
-
-bool Defs::replaceChild(const std::string& path,
- const defs_ptr& clientDefs,
- bool createNodesAsNeeded,
- bool force,
- std::string& errorMsg)
-{
- node_ptr clientNode = clientDefs->findAbsNode( path );
- if (! clientNode.get() ) {
- errorMsg = "Can not replace node since path "; errorMsg += path;
- errorMsg += " does not exist on the client definition";
- return false;
- }
-
- node_ptr serverNode = findAbsNode( path ) ;
- if (!force && serverNode.get()) {
- // Check if serverNode has child tasks in submitted or active states
- vector<Task*> taskVec;
- serverNode->getAllTasks(taskVec); // taskVec will be empty if serverNode is a task
- int count = 0;
- BOOST_FOREACH(Task* t, taskVec) { if (t->state() == NState::ACTIVE || t->state() == NState::SUBMITTED) count++;}
- if (count != 0) {
- std::stringstream ss;
- ss << "Can not replace node " << serverNode->debugNodePath() << " because it has " << count << " tasks which are active or submitted\n";
- ss << "Please use the 'force' option to bypass this check, at the expense of creating zombies\n";
- errorMsg += ss.str();
- return false;
- }
- }
-
- /// REPLACE ===========================================================
- if (!createNodesAsNeeded || serverNode.get()) {
- // Then the child must exist in the server defs (i.e. this)
- if (! serverNode.get() ) {
- errorMsg = "Can not replace child since path "; errorMsg += path;
- errorMsg += " does not exist on the server definition. Please use <parent> option";
- return false;
- }
- // HAVE a FULL match in the server
-
- // Copy over begun and suspended states
- if (serverNode->suite()->begun()) clientNode->begin();
- if (serverNode->isSuspended()) clientNode->suspend();
-
- // Find the position of the server node relative to its peers
- // We use this to re-add client node at the same position
- size_t child_pos = serverNode->position();
-
- // Delete node on the server, Must recurse down
- Node* parentNodeOnServer = serverNode->parent();
- deleteChild(serverNode.get());
-
- // Remove reference in the client defs to clientNode and detach from its parent
- // transfer ownership to the server
- bool addOk = false;
- node_ptr client_node_to_add = clientNode->remove();
- if ( parentNodeOnServer ) addOk = parentNodeOnServer->addChild( client_node_to_add , child_pos);
- else addOk = addChild( client_node_to_add , child_pos);
- LOG_ASSERT(addOk,"");
-
- client_node_to_add->set_most_significant_state_up_node_tree();
-
- // The changes have been made, do a sanity test, check trigger expressions
- std::string warning_msg;
- return client_node_to_add->suite()->check(errorMsg,warning_msg);
- }
-
-
- // ADD ======================================================================
- // Create/Add nodes as needed for a *PARTIAL* match
- // If the path is /a/b/c/d/e/f it may be that path /a/b already exists
- // hence we need only create the missing nodes c, d, e, f
- LOG_ASSERT( serverNode == NULL, "" );
- node_ptr server_parent;
- Node* last_client_child = clientNode.get(); // remember the last child
- Node* client_parent = clientNode->parent();
- while (client_parent) {
- server_parent = findAbsNode( client_parent->absNodePath() );
- if (server_parent ) {
- break;
- }
- last_client_child = client_parent;
- client_parent = client_parent->parent();
- }
- if (server_parent.get() == NULL) {
- // NOT EVEN A PARTIAL path match, hence move over WHOLE suite, detach from client and add to server
- node_ptr client_suite_to_add = clientNode->suite()->remove();
- bool addOk = addChild( client_suite_to_add );
- LOG_ASSERT( addOk ,"");
- client_suite_to_add->set_most_significant_state_up_node_tree();
-
- // The changes have been made, do a sanity test, check trigger expressions
- std::string warning_msg;
- return client_suite_to_add->suite()->check(errorMsg,warning_msg);
- }
-
-
- // PARTIAL PATH MATCH,
- LOG_ASSERT( last_client_child ,"");
- LOG_ASSERT( client_parent ,"");
- LOG_ASSERT( last_client_child->parent() == client_parent ,"");
- LOG_ASSERT( client_parent->absNodePath() == server_parent->absNodePath() ,"");
-
- /// If the child of same name exist we *replace* at the same position otherwise we *add* it to the end
- size_t client_child_pos = last_client_child->position();
-
- size_t server_child_pos; // will be set to std::numeric_limits<std::size_t>::max(), if child not found
- node_ptr server_child = server_parent->findImmediateChild(last_client_child->name(),server_child_pos);
- if (server_child.get()) {
-
- // Copy over suspended state
- if (server_child->isSuspended()) {
- last_client_child->suspend();
- }
-
- // Child of same name exist on the server, hence remove it
- deleteChild(server_child.get());
- }
-
- /// copy over begin/queued status
- if (server_parent->suite()->begun()) {
- last_client_child->begin();
- }
-
- node_ptr client_node_to_add = last_client_child->remove();
- bool addOk = server_parent->addChild( client_node_to_add , client_child_pos);
- LOG_ASSERT( addOk,"" );
- client_node_to_add->set_most_significant_state_up_node_tree();
-
- // The changes have been made, do a sanity test, check trigger expressions
- std::string warning_msg;
- return client_node_to_add->suite()->check(errorMsg,warning_msg);
-}
-
-void Defs::save_as_checkpt(const std::string& the_fileName,ecf::Archive::Type at) const
-{
- // only_save_edit_history_when_check_pointing or if explicitly requested
- save_edit_history_ = true; // this is reset after edit_history is saved
-
- /// Can throw archive exception
- ecf::save(the_fileName,*this,at);
-}
-
-void Defs::save_checkpt_as_string(std::string& output) const
-{
- // only_save_edit_history_when_check_pointing or if explicitly requested
- save_edit_history_ = true; // this is reset after edit_history is saved
-
- ecf::save_as_string(output,*this);
-}
-
-void Defs::restore_from_checkpt(const std::string& the_fileName,ecf::Archive::Type at)
-{
-// cout << "Defs::restore_from_checkpt " << the_fileName << "\n";
-
- if (the_fileName.empty()) return;
-
- // deleting existing content first. *** Note: Server environment left as is ****
- clear();
-
- ecf::restore(the_fileName, (*this), at);
-
- // Reset the state and modify numbers, **After the restore**
- state_change_no_ = Ecf::state_change_no();
- modify_change_no_ = Ecf::modify_change_no();
-
-// cout << "Restored: " << suiteVec_.size() << " suites\n";
-}
-
-void Defs::clear()
-{
- // Duplicate AST are held in a static map.
- ExprDuplicate reclaim_cloned_ast_memory;
-
- // *** Note: Server environment left as is ****
- suiteVec_.clear();
- externs_.clear();
- client_suite_mgr_.clear();
- state_.setState(NState::UNKNOWN);
- edit_history_.clear();
- save_edit_history_ = false;
- Ecf::incr_modify_change_no();
-}
-
-bool Defs::checkInvariants(std::string& errorMsg) const
-{
- size_t vecSize = suiteVec_.size();
- for(size_t s = 0; s < vecSize; s++) {
- if (suiteVec_[s]->defs() != this) {
- std::stringstream ss;
- ss << "Defs::checkInvariants suite->defs() function not correct. Child suite parent ptr not correct\n";
- ss << "For suite " << suiteVec_[s]->name();
- errorMsg += ss.str();
- return false;
- }
- if (!suiteVec_[s]->checkInvariants(errorMsg)) {
- return false;
- }
- }
-
- if (Ecf::server()) {
- /// The change no should NOT be greater than Ecf::state_change_no()
-
- if (state_change_no_ > Ecf::state_change_no() ) {
- std::stringstream ss;
- ss << "Defs::checkInvariants: state_change_no(" << state_.state_change_no() << ") > Ecf::state_change_no(" << Ecf::state_change_no() << ")\n";
- errorMsg += ss.str();
- return false;
- }
- if (modify_change_no_ > Ecf::modify_change_no() ) {
- std::stringstream ss;
- ss << "Defs::checkInvariants: modify_change_no_(" << modify_change_no_ << ") > Ecf::modify_change_no(" << Ecf::modify_change_no() << ")\n";
- errorMsg += ss.str();
- return false;
- }
-
- if (flag_.state_change_no() > Ecf::state_change_no() ) {
- std::stringstream ss;
- ss << "Defs::checkInvariants: flag.state_change_no()(" << flag_.state_change_no() << ") > Ecf::state_change_no(" << Ecf::state_change_no() << ")\n";
- errorMsg += ss.str();
- return false;
- }
-
-
- if (state_.state_change_no() > Ecf::state_change_no() ) {
- std::stringstream ss;
- ss << "Defs::checkInvariants: state_.state_change_no()(" << state_.state_change_no() << ") > Ecf::state_change_no(" << Ecf::state_change_no() << ")\n";
- errorMsg += ss.str();
- return false;
- }
-
- if (server_.state_change_no() > Ecf::state_change_no() ) {
- std::stringstream ss;
- ss << "Defs::checkInvariants: server_.state_change_no()(" << server_.state_change_no() << ") > Ecf::state_change_no(" << Ecf::state_change_no() << ")\n";
- errorMsg += ss.str();
- return false;
- }
- }
- return true;
-}
-
-void Defs::order(Node* immediateChild, NOrder::Order ord)
-{
- switch (ord) {
- case NOrder::TOP: {
- for(std::vector<suite_ptr>::iterator i = suiteVec_.begin(); i != suiteVec_.end(); ++i) {
- suite_ptr s = (*i);
- if (s.get() == immediateChild) {
- suiteVec_.erase(i);
- suiteVec_.insert(suiteVec_.begin(),s);
- client_suite_mgr_.update_suite_order();
- order_state_change_no_ = Ecf::incr_state_change_no();
- return;
- }
- }
- throw std::runtime_error("Defs::order: TOP, immediate child suite not found");
- }
- case NOrder::BOTTOM: {
- for(std::vector<suite_ptr>::iterator i = suiteVec_.begin(); i != suiteVec_.end(); ++i) {
- suite_ptr s = (*i);
- if (s.get() == immediateChild) {
- suiteVec_.erase(i);
- suiteVec_.push_back(s);
- order_state_change_no_ = Ecf::incr_state_change_no();
- client_suite_mgr_.update_suite_order();
- return;
- }
- }
- throw std::runtime_error("Defs::order: BOTTOM, immediate child suite not found");
- }
- case NOrder::ALPHA: {
- std::sort(suiteVec_.begin(),suiteVec_.end(),
- boost::bind(Str::caseInsLess,
- boost::bind(&Node::name,_1),
- boost::bind(&Node::name,_2)));
- order_state_change_no_ = Ecf::incr_state_change_no();
- client_suite_mgr_.update_suite_order();
- break;
- }
- case NOrder::ORDER: {
- std::sort(suiteVec_.begin(),suiteVec_.end(),
- boost::bind(Str::caseInsGreater,
- boost::bind(&Node::name,_1),
- boost::bind(&Node::name,_2)));
- order_state_change_no_ = Ecf::incr_state_change_no();
- client_suite_mgr_.update_suite_order();
- break;
- }
- case NOrder::UP: {
- for(size_t t = 0; t < suiteVec_.size();t++) {
- if ( suiteVec_[t].get() == immediateChild) {
- if (t != 0) {
- suite_ptr s = suiteVec_[t];
- suiteVec_.erase(suiteVec_.begin()+t);
- t--;
- suiteVec_.insert(suiteVec_.begin()+t,s);
- order_state_change_no_ = Ecf::incr_state_change_no();
- }
- client_suite_mgr_.update_suite_order();
- return;
- }
- }
- throw std::runtime_error("Defs::order: UP, immediate child suite not found");
- }
- case NOrder::DOWN: {
- for(size_t t = 0; t < suiteVec_.size();t++) {
- if ( suiteVec_[t].get() == immediateChild) {
- if (t != suiteVec_.size()-1) {
- suite_ptr s = suiteVec_[t];
- suiteVec_.erase(suiteVec_.begin()+t);
- t++;
- suiteVec_.insert(suiteVec_.begin()+t,s);
- order_state_change_no_ = Ecf::incr_state_change_no();
- }
- client_suite_mgr_.update_suite_order();
- return;
- }
- }
- throw std::runtime_error("Defs::order: DOWN, immediate child suite not found");
- }
- }
-}
-
-void Defs::top_down_why(std::vector<std::string>& theReasonWhy) const
-{
- why(theReasonWhy);
- size_t theSuiteVecSize = suiteVec_.size();
- for(size_t s = 0; s < theSuiteVecSize; s++) { suiteVec_[s]->top_down_why(theReasonWhy);}
-}
-
-void Defs::why(std::vector<std::string>& theReasonWhy) const
-{
- if (isSuspended()) {
- std::string the_reason = "The server is *not* RUNNING.";
- theReasonWhy.push_back(the_reason);
- }
- else if (state() != NState::QUEUED && state() != NState::ABORTED) {
- std::stringstream ss;
- ss << "The definition state(" << NState::toString(state()) << ") is not queued or aborted.";
- theReasonWhy.push_back(ss.str());
- }
- server_.why(theReasonWhy);
-}
-
-std::string Defs::toString() const
-{
- // Let the Client control the print style
- std::stringstream ss;
- ss << this;
- return ss.str();
-}
-
-// Memento functions
-void Defs::collateChanges(unsigned int client_handle, DefsDelta& incremental_changes) const
-{
- // Collate any small scale changes to the defs
- collate_defs_changes_only(incremental_changes);
-
- if (0 == client_handle) {
- // small scale changes. Collate changes over all suites.
- // Suite stores the maximum state change, over *all* its children, this is used by client handle mechanism
- // and here to avoid traversing down the hierarchy.
- // ******** We must trap all child changes under the suite. See class SuiteChanged
- // ******** otherwise some attribute sync's will be missed
- size_t theSuiteVecSize = suiteVec_.size();
- for(size_t s = 0; s < theSuiteVecSize; s++) {
- if (suiteVec_[s]->state_change_no() > incremental_changes.client_state_change_no() ) {
- // *IF* node/attribute change no > client_state_change_no
- // *THEN*
- // Create a memento, and store in incremental_changes_
- suiteVec_[s]->collateChanges(incremental_changes);
- }
- }
- }
- else {
-
- // small scale changes over the suites in our handle, determine what's changed,
- // relative to each node and attributes client_state_change_no.
- // *IF* node/attribute change no > client_state_change_no
- // *THEN*
- // Create a memento, and store in incremental_changes_
- client_suite_mgr_.collateChanges(client_handle,incremental_changes);
- }
-}
-
-void Defs::collate_defs_changes_only(DefsDelta& incremental_changes) const
-{
- // ************************************************************************************************
- // determine if defs state changed. make sure this is in sync with defs_only_max_state_change_no()
- // ************************************************************************************************
- compound_memento_ptr comp;
- if (state_.state_change_no() > incremental_changes.client_state_change_no()) {
- if (!comp.get()) comp = boost::make_shared<CompoundMemento>(Str::ROOT_PATH());
- comp->add( boost::make_shared<StateMemento>( state_.state()) );
- }
- if (order_state_change_no_ > incremental_changes.client_state_change_no()) {
- if (!comp.get()) comp = boost::make_shared<CompoundMemento>(Str::ROOT_PATH());
- std::vector<std::string> order; order.reserve(suiteVec_.size());
- for(size_t i =0; i < suiteVec_.size(); i++) order.push_back( suiteVec_[i]->name());
- comp->add( boost::make_shared<OrderMemento>( order ) );
- }
-
- // Determine if the flag changed
- if (flag_.state_change_no() > incremental_changes.client_state_change_no()) {
- if (!comp.get()) comp = boost::make_shared<CompoundMemento>(Str::ROOT_PATH());
- comp->add( boost::make_shared<FlagMemento>( flag_ ) );
- }
-
- // determine if defs server state, currently only watch server state. i.e HALTED, SHUTDOWN, RUNNING
- if (server_.state_change_no() > incremental_changes.client_state_change_no()) {
- if (!comp.get()) comp = boost::make_shared<CompoundMemento>(Str::ROOT_PATH());
- comp->add( boost::make_shared<ServerStateMemento>( server_.get_state() ) );
- }
- if (server_.variable_state_change_no() > incremental_changes.client_state_change_no()) {
- if (!comp.get()) comp = boost::make_shared<CompoundMemento>(Str::ROOT_PATH());
- comp->add( boost::make_shared<ServerVariableMemento>( server_.user_variables() ) );
- }
-
- if (comp.get() ) {
- incremental_changes.add( comp );
- }
-}
-
-unsigned int Defs::defs_only_max_state_change_no() const
-{
- // ************************************************************************************************
- // make sure this is in sync with collate_defs_changes_only()
- // ************************************************************************************************
- unsigned int max_change_no = 0;
- max_change_no = std::max( max_change_no, state_.state_change_no());
- max_change_no = std::max( max_change_no, order_state_change_no_);
- max_change_no = std::max( max_change_no, flag_.state_change_no());
- max_change_no = std::max( max_change_no, server_.state_change_no());
- max_change_no = std::max( max_change_no, server_.variable_state_change_no());
- return max_change_no;
-}
-
-void Defs::set_memento(const StateMemento* memento) {
-
-#ifdef DEBUG_MEMENTO
- std::cout << "Defs::set_memento(const StateMemento* memento)\n";
-#endif
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::STATE);
- set_state( memento->state_ );
-}
-
-void Defs::set_memento( const ServerStateMemento* memento ) {
-#ifdef DEBUG_MEMENTO
- std::cout << "Defs::set_memento(const ServerStateMemento* memento)\n";
-#endif
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::SERVER_STATE);
- server_.set_state( memento->state_ );
-}
-
-void Defs::set_memento( const ServerVariableMemento* memento ) {
-#ifdef DEBUG_MEMENTO
- std::cout << "Defs::set_memento(const ServerVariableMemento* memento)\n";
-#endif
-
- if (server_.user_variables().size() != memento->serverEnv_.size()) {
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::ADD_REMOVE_ATTR);
- }
-
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::SERVER_VARIABLE);
-
- server_.set_user_variables( memento->serverEnv_);
-}
-
-void Defs::set_memento( const OrderMemento* memento ) {
-#ifdef DEBUG_MEMENTO
- std::cout << "Defs::set_memento(const OrderMemento* memento)\n";
-#endif
- // Order the suites
-
- // Order nodeVec_ according to memento ordering
- const std::vector<std::string>& order = memento->order_;
-
- // NOTE: When we have handles only a small subset of the suites, are returned
- // Whereas order will always contain all the suites.
- // Hence we need to handle the case where: order.size() != suiteVec_.size()
-
- std::vector<suite_ptr> vec; vec.reserve(suiteVec_.size());
- size_t node_vec_size = suiteVec_.size();
- for(size_t i = 0; i < order.size(); i++) {
- for(size_t t = 0; t < node_vec_size; t++) {
- if (order[i] == suiteVec_[t]->name()) {
- vec.push_back(suiteVec_[t]);
- break;
- }
- }
- }
- if (vec.size() != suiteVec_.size()) {
- std::cout << "Defs::set_memento could not find all the names\n";
- return;
- }
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::ORDER);
- suiteVec_ = vec;
-}
-
-
-void Defs::set_memento( const FlagMemento* memento ) {
-
-#ifdef DEBUG_MEMENTO
- std::cout << "Defs::set_memento(const FlagMemento* memento)\n";
-#endif
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::FLAG);
- flag_.set_flag( memento->flag_.flag() );
-}
-
-// =====================================================================
-
-void Defs::add_edit_history(const std::string& path, const std::string& request)
-{
- std::map<std::string, std::deque<std::string> >::iterator i = edit_history_.find(path);
- if (i == edit_history_.end()) {
- std::deque<std::string> vec; vec.push_back(request);
- edit_history_.insert( std::make_pair(path,vec) );
- }
- else {
- (*i).second.push_back(request);
- if ((*i).second.size() > 20) {
- (*i).second.pop_front();
- }
- }
-}
-
-const std::deque<std::string>& Defs::get_edit_history(const std::string& path) const
-{
- std::map<std::string, std::deque<std::string> >::const_iterator i = edit_history_.find(path);
- if (i != edit_history_.end()) {
- return (*i).second;
- }
- return empty_edit_history();
-}
-
-const std::deque<std::string>& Defs::empty_edit_history()
-{
- static std::deque<std::string> static_edit_history;
- return static_edit_history;
-}
-
-// =====================================================================================
-
-std::ostream& operator<<(std::ostream& os, const Defs* d)
-{
- if (d) return d->print(os);
- return os << "DEFS == NULL\n";
-}
-std::ostream& operator<<(std::ostream& os, const Defs& d) { return d.print(os); }
-
-// =========================================================================
-
-DefsHistoryParser::DefsHistoryParser() {
- Log::get_log_types(log_types_);
-}
-
-void DefsHistoryParser::parse(const std::string& line)
-{
- size_t pos = line.find("\b");
- if (pos != std::string::npos) {
- // keep compatibility with current way of writing history
- std::string requests = line.substr(pos);
- Str::split(requests,parsed_messages_,"\b");
- return;
- }
-
- // fallback, split line based on looking for logType like 'MSG:[' | 'LOG:['
- string::size_type first = find_log(line,0);
- if (first == std::string::npos) return;
-
- string::size_type next = find_log(line,first + 4);
- if (next == std::string::npos ) {
- parsed_messages_.push_back( line.substr( first ) );
- return;
- }
-
- while (next != std::string::npos) {
- parsed_messages_.push_back( line.substr( first, next - first ) );
- first = next;
- next = find_log(line,first + 4);
-
- if (next == std::string::npos ) {
- parsed_messages_.push_back( line.substr( first ) );
- return;
- }
- }
-}
-
-string::size_type DefsHistoryParser::find_log(const std::string& line, string::size_type pos) const
-{
- for(size_t i = 0; i < log_types_.size(); i++) {
- std::string log_type = log_types_[i];
- log_type += ":[";
- string::size_type log_type_pos = line.find( log_type, pos );
- if (log_type_pos != std::string::npos) {
- return log_type_pos;
- }
- }
- return std::string::npos;
-}
diff --git a/ecflow_4_0_7/ANode/src/Defs.hpp b/ecflow_4_0_7/ANode/src/Defs.hpp
deleted file mode 100644
index 0ab9c19..0000000
--- a/ecflow_4_0_7/ANode/src/Defs.hpp
+++ /dev/null
@@ -1,399 +0,0 @@
-#ifndef DEFS_HPP_
-#define DEFS_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #165 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-// class defs: The root of the node tree. Holds all the suites:
-// Externs are not persisted, why ?:
-// o Externs are un-resolved references to node paths in trigger expressions and inlimits
-// These references can be dynamically generated.
-// o Saves on network bandwidth and checkpoint file size
-//
-// Hence externs are *ONLY* used on the client side.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <ostream>
-#include <set>
-
-#include <boost/noncopyable.hpp>
-#include "boost/date_time/posix_time/posix_time_types.hpp"
-#include <boost/serialization/serialization.hpp>
-#include <boost/serialization/utility.hpp>
-#include <boost/serialization/vector.hpp> // no need to include <vector>
-#include <boost/serialization/deque.hpp> // no need to include <deque>
-#include <boost/serialization/map.hpp> // no need to include <map>
-#include <boost/serialization/string.hpp> // no need to include <string>
-#include <boost/serialization/shared_ptr.hpp> // no need to include shared_ptr
-#include <boost/foreach.hpp> // used so often just placed here for convenience
-
-#include "ServerState.hpp"
-#include "ClientSuiteMgr.hpp"
-#include "NState.hpp"
-#include "NOrder.hpp"
-#include "NodeFwd.hpp"
-#include "JobCreationCtrl.hpp"
-#include "Suite.hpp"
-#include "CheckPt.hpp"
-#include "Archive.hpp"
-
-class Limit;
-namespace ecf { class NodeTreeVisitor; class CalendarUpdateParams; } // forward declare
-
-class Defs : private boost::noncopyable {
-public:
- static defs_ptr create();
- Defs();
- ~Defs();
-
- bool operator==(const Defs& rhs) const;
- std::ostream& print(std::ostream&) const ;
-
- /// State related functions:
- /// Defs acts like the root node.
- void set_state(NState::State);
- void set_state_only(NState::State);
- NState::State state() const;
- void set_most_significant_state();
-
- // The defs does not need suspend()/resume() as this is controlled by the server states
- // The defs can not schedule jobs when HALTED or SHUTDOWN, i.e. not RUNNING, this is same as suspended
- bool isSuspended() const { return (server().get_state() != SState::RUNNING); }
-
- /// Python based checking
- /// Will create a temporary variable ECF_JOB so the job generation is done to a temporary directory
- /// For TEST ONLY. Will generated jobs from the given node path
- /// if the no path defined will generate jobs for all tasks
- /// Job generation here is INDEPENDENT of the dependencies
- /// Will call begin(). this updated generated variables which are used
- /// **during variable substitution in job generation.
- /// Note: All Tasks that fail to create jobs are returned in jobCtrl
- /// This is because some Tasks are dummy, they have no associated ecf.
- /// since they will never be run. This can be determined if they have
- /// trigger expression like "1 == 0"
- void check_job_creation( job_creation_ctrl_ptr jobCtrl);
-
- /// Automatically generated '.ecf' scripts for this definition
- /// It uses the contents of the definition to parameterise what gets
- /// generated, and the location of the files. Will throw std::runtime_error for errors
- /// Assumes: ECF_HOME specified and accessible for all Tasks, otherwise std::runtime_error is raised
- /// If ECF_FILES is specified, then scripts are generated under this directory
- /// otherwise ECF_HOME is used. The missing directories are automatically added.
- /// IF ECF_INCLUDE must be specified.The head.h and tail.h includes will
- /// use angle brackets, i.e %include <head.h>.
- /// If ECF_CLIENT_EXE_PATH variable is added, child command will use this, otherwise
- /// will use ecflow_client, and assume this accessible on the path.
- /// Will not generated scripts for tasks with ECF_DUMMY_TASK specified.
- void generate_scripts() const;
-
- /// Update calendar and time dependent variables. This must be called by the polling mechanism,
- /// This will *ONLY* have an effect after begin() command has been called
- ///
- /// Some suites can elect to ignore calendar updates when the server is not running
- /// This allows normal and relative time dependencies to be honoured, even if the
- /// server is started/stopped many times.
- /// Updating the calendar can lead to state changes in the server. i.e when time related
- /// dependencies are free'd
- void updateCalendar( const ecf::CalendarUpdateParams &);
-
- /// returns the number of times the calendar has been updated. For DEBUG
- unsigned int updateCalendarCount() const { return updateCalendarCount_;}
-
- // Implements visitor pattern
- void accept(ecf::NodeTreeVisitor&); // Node Tree structure does the traversal
- void acceptVisitTraversor(ecf::NodeTreeVisitor& v); // visitor does traversal
-
- /// Moves all the data from input defs into this definition. By default
- /// suite of the same name, are left alone, unless the force option is used.
- /// i.e with force any suites of the same name will overwrite the suite of
- /// the same name in this definition.
- /// externs and server user variables are appended to.
- /// The input defs will be left with NO suites
- void absorb(Defs*, bool force);
-
- std::string name() const { return "/";} /* ABO */
-
- /// Add a suite to the definition, will throw std::runtime_error if duplicate
- suite_ptr add_suite(const std::string& name);
- void addSuite(suite_ptr,size_t position = std::numeric_limits<std::size_t>::max());
- size_t child_position(const Node*) const;
-
- /// Externs refer to Nodes or, variable, events, meter, repeat, or generated variable
- /// not currently defined. If the object(variable, event,meter, repeat, or generate variable name)
- /// is empty the path can refer to a Task, Family of Suite
- /// extern can have absolute and relative paths
- /// Typically used in a trigger or complete expression
- /// Path can be off the form:
- /// extern /suite/family
- /// extern /suite/family:repeat_name
- /// extern ../family:repeat_name
- void add_extern(const std::string& nodePath );
-
- /// Scan the trigger and complete expressions, and automatically add extern's
- /// i.e where the node paths, and references, to event, meters, edit and repeat variables,
- /// don't exist, in this defs.
- void auto_add_externs(bool remove_existing_externs_first = true);
-
-
- /// Flag the chosen suite, so that it can resolve dependencies. This also
- /// changes the state of all children to QUEUED/defstatus and initialise the node attributes
- /// Once a suite is begun, it stays in that state
- void beginSuite(suite_ptr);
-
- /// Enables all suites to resolve dependencies
- /// Once a suite is begun, it stays in that state
- void beginAll();
-
- /// Reset the begin state. **** ONLY to be used for test ********
- void reset_begin();
-
- /// throws runtime_error if suite cant begin
- void check_suite_can_begin(suite_ptr) const;
-
- /// Will requeue all suites. Current used in test only
- void requeue();
-
- /// returns true if defs has cron,time,day,date or today time dependencies
- bool hasTimeDependencies() const;
-
- /// This function is called when ALL definition has been parsed successfully
- /// Client Side:: The client side has externs, hence any references to node paths
- /// in the triggers expression, that are un-resolved and not in
- /// the extern;s are reported as errors/warnings
- /// Likewise for inlimit references to Limits
- /// Server Side:: There are no externs hence, check will report all unresolved
- /// references as errors.
- /// Note the AST will be demand loaded in the server. Since they are not persisted.
- /// we will also resolve inLimit references to Limits. Note inlimit may also
- /// reference paths, which are externs::
- // ****** Spirit based AST construction is very expensive ********
- // ****** Need to replace at some point in future ********
- bool check(std::string& errorMsg,std::string& warningMsg) const;
-
- /// Assumes input argument is of the form /suite/family/task, /suite/family/family/task
- node_ptr findAbsNode(const std::string& pathToNode) const;
- bool find_extern( const std::string& pathToNode,const std::string& node_attr_name) const;
- suite_ptr findSuite(const std::string& name) const;
- const std::vector<suite_ptr>& suiteVec() const { return suiteVec_;}
-
- /// Given a path, /suite/family/task, find node which is the closest
- node_ptr find_closest_matching_node(const std::string& pathToNode) const;
-
- void getAllFamilies(std::vector<Family*>&) const;
- void getAllNodes(std::vector<Node*>&) const;
- void getAllTasks(std::vector<Task*>&) const;
- void getAllSubmittables(std::vector<Submittable*>&) const;
- void get_all_active_submittables(std::vector<Submittable*>&) const;
- void get_all_nodes(std::vector<node_ptr>&) const;
- void get_all_tasks(std::vector<task_ptr>&) const;
- void get_all_aliases(std::vector<alias_ptr>&) const;
- void getAllAstNodes(std::set<Node*>&) const;
- const std::set<std::string>& externs() const { return externs_; }
-
- /// Get/set for server state.
- const ServerState& server() const { return server_;}
- ServerState& set_server() { return server_;}
-
- /// find all %VAR% and replaces with variable values, returns false on the
- /// first variable that can't be found, cmd will be left half processed.
- /// Will search for ECF_MICRO, if not found assumes % as the micro char
- bool variableSubsitution(std::string& cmd) const { return server_.variableSubsitution(cmd);}
-
- /// returns true if definition file passes its verification
- /// If the definition file contains verify attribute, this function will check
- /// expected number of state changes corresponds to the actual number of state changes
- bool verification(std::string& errorMsg) const;
-
- /// generic way of deleting a Node.
- /// This should always succeed else something is seriously wrong
- bool deleteChild(Node*);
-
- /// Adopt the child specified by 'path' from the clientDef.
- /// If node at path already exists in this instance, it is replaced.
- /// if createNodesAsNeeded = false, then the path must exist on this defs
- /// otherwise an error message is issued.
- /// if createNodesAsNeeded = true, and the path does not exist on this defs
- /// then the missing path nodes are created.
- /// In both the client and this defs the trigger references and cleared first.
- bool replaceChild(const std::string& path,
- const defs_ptr& clientDef,
- bool createNodesAsNeeded,
- bool force,
- std::string& errormsg);
-
- // Order the suite
- void order(Node* immediateChild, NOrder::Order);
-
- /// determines why the node is not running.
- void top_down_why(std::vector<std::string>& theReasonWhy) const;
- void why(std::vector<std::string>& theReasonWhy) const;
-
- /// Function to save the defs as a checkpoint file. File saved to the file name
- /// Can throw exception
- void save_as_checkpt(const std::string& fileName,ecf::Archive::Type = ecf::Archive::default_archive()) const;
- void save_checkpt_as_string(std::string& check_pt) const;
-
- /// Function to restore the defs from a check point file.
- /// If the Defs file has content, this is deleted first, i.e. suites, externs,
- /// Can throw an exception
- void restore_from_checkpt(const std::string& fileName,ecf::Archive::Type = ecf::Archive::default_archive());
-
- /// Delete suites, externs, client handles, reset suspended, and locate state
- /// etc but Server environment left as is:
- void clear();
-
- ecf::Flag& flag() { return flag_;}
- const ecf::Flag& get_flag() const { return flag_;}
-
- void add_edit_history(const std::string& path, const std::string& request);
- const std::deque<std::string>& get_edit_history(const std::string& path) const;
- void save_edit_history(bool f) const { save_edit_history_ = f ;}
- static const std::deque<std::string>& empty_edit_history();
-
- /// Memento functions:
- void collateChanges(unsigned int client_handle,DefsDelta&) const;
- void set_memento(const StateMemento* );
- void set_memento(const ServerStateMemento* );
- void set_memento(const ServerVariableMemento* );
- void set_memento(const OrderMemento* );
- void set_memento(const FlagMemento* );
-
- /// Find the max state change number for defs only. This includes:
- /// o the Defs state.
- /// o the Defs suspend state
- /// o the Defs server state.
- unsigned int defs_only_max_state_change_no() const;
-
- /// Change functions, used for *transferring* change number, from server to client
- void set_state_change_no( unsigned int x ) { state_change_no_ = x;}
- unsigned int state_change_no() const { return state_change_no_; }
- void set_modify_change_no( unsigned int x ) { modify_change_no_ = x;}
- unsigned int modify_change_no() const { return modify_change_no_; }
-
- ClientSuiteMgr& client_suite_mgr() { return client_suite_mgr_;}
-
- // Provided for python interface
- std::string toString() const;
-
- // Will recurse down.
- bool doDeleteChild(Node* nodeToBeDeleted);
-
- bool checkInvariants(std::string& errorMsg) const;
-
- void read_state(const std::string& line,const std::vector<std::string>& lineTokens);
- void read_history(const std::string& line,const std::vector<std::string>& lineTokens);
- bool compare_edit_history(const Defs&) const;
-private:
- void do_generate_scripts( const std::map<std::string,std::string>& override) const;
- std::string write_state() const;
- void collate_defs_changes_only(DefsDelta&) const;
- void setupDefaultEnv();
- void add_suite_only(suite_ptr, size_t position);
-
- /// Removes the suite, from defs returned as auto_ptr, asserts if suite does not exist
- suite_ptr removeSuite(suite_ptr);
- node_ptr removeChild(Node*);
- bool addChild( node_ptr, size_t position = std::numeric_limits<std::size_t>::max());
- friend class Node;
-
- /// For use by python interface,
- std::vector<suite_ptr>::const_iterator suite_begin() const { return suiteVec_.begin();}
- std::vector<suite_ptr>::const_iterator suite_end() const { return suiteVec_.end();}
- std::set<std::string>::const_iterator extern_begin() const { return externs_.begin();}
- std::set<std::string>::const_iterator extern_end() const { return externs_.end();}
- std::vector<Variable>::const_iterator user_variables_begin() const { return server_.user_variables().begin();}
- std::vector<Variable>::const_iterator user_variables_end() const { return server_.user_variables().end();}
- std::vector<Variable>::const_iterator server_variables_begin() const { return server_.server_variables().begin();}
- std::vector<Variable>::const_iterator server_variables_end() const { return server_.server_variables().end();}
-
- friend void export_Defs();
-
-private:
- /// Note: restoring form a check point file will reset, defs state and modify numbers
- unsigned int state_change_no_; // persisted since passed to client, however side effect, is it will be in checkpoint file
- unsigned int modify_change_no_; // persisted since passed to client, however side effect, is it will be in checkpoint file
- unsigned int updateCalendarCount_;
- unsigned int order_state_change_no_; // *NOT* persisted
- NState state_; // state & change_no, i,e attribute changed
- ServerState server_;
- std::vector<suite_ptr> suiteVec_;
- std::map<std::string, std::deque<std::string> > edit_history_; // path,request
- mutable bool save_edit_history_; // NOT persisted
- ecf::Flag flag_;
-
- ClientSuiteMgr client_suite_mgr_; // NOT persisted
-
- /// Externs are *NEVER* loaded in the server, since they can be computed and
- /// save on network band with, and check point file size.
- std::set<std::string> externs_; // NOT persisted
-
- friend class SaveEditHistoryWhenCheckPointing;
-private:
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/)
- {
- ar & state_change_no_;
- ar & modify_change_no_;
- ar & updateCalendarCount_;
- ar & state_;
- ar & server_;
- ar & suiteVec_;
- ar & flag_;
-
- // only save the edit history when check pointing.
- if (Archive::is_saving::value) {
- if (save_edit_history_) {
- ar & edit_history_;
- save_edit_history_ = false; // reset
- }
- else {
- std::map<std::string, std::deque<std::string> > empty_edit_history;
- ar & empty_edit_history;
- }
- }
- else {
- ar & edit_history_;
- }
-
- if (Archive::is_loading::value) {
- size_t vec_size = suiteVec_.size();
- for(size_t i = 0; i < vec_size; i++) {
- suiteVec_[i]->set_defs(this);
- }
- }
- }
-};
-
-std::ostream& operator<<(std::ostream& os, const Defs*);
-std::ostream& operator<<(std::ostream& os, const Defs&);
-
-// =====================================================================
-// This class is used to read the History
-class DefsHistoryParser : private boost::noncopyable {
-public:
- DefsHistoryParser();
-
- void parse(const std::string& line);
- const std::vector<std::string>& parsed_messages() const { return parsed_messages_;}
-
-private:
-
- std::string::size_type find_log(const std::string& line, std::string::size_type pos) const;
-
-private:
- std::vector<std::string> log_types_;
- std::vector<std::string> parsed_messages_;
-};
-
-
-#endif /* DEFS_HPP_ */
diff --git a/ecflow_4_0_7/ANode/src/DefsDelta.cpp b/ecflow_4_0_7/ANode/src/DefsDelta.cpp
deleted file mode 100644
index a68474e..0000000
--- a/ecflow_4_0_7/ANode/src/DefsDelta.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #23 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/bind.hpp>
-#include "DefsDelta.hpp"
-#include "ChangeMgrSingleton.hpp"
-using namespace std;
-
-//#define DEBUG_MEMENTO 1
-
-//===============================================================
-// DefsDelta
-
-/// Defs delta can be re-used. reset all data members
-void DefsDelta::init(unsigned int client_state_change_no)
-{
- client_state_change_no_ = client_state_change_no;
-
- server_state_change_no_ = 0;
- server_modify_change_no_ = 0;
- compound_mementos_.clear();
-}
-
-
-bool DefsDelta::incremental_sync(defs_ptr client_def, std::vector<std::string>& changed_nodes) const
-{
- if (!client_def.get()) return false;
-
- if (ChangeMgrSingleton::exists() && ChangeMgrSingleton::instance()->in_notification()) {
- // For debug: place a break point here: It appear as Change manager observers, has called another client to server command
- std::cout << "ecflow:ClientInvoker::incremental_sync() called in the middle of ChangeMgrSingleton::notification.\n";
- std::cout << "It appears that change observer have called *ANOTHER* client->server command in the middle syncronising client definition\n";
- }
-
- /// - Sets notification flag, so that observers can also query if they are in
- /// the middle of notification.
- ChangeMgrStartNotification start_notification;
-
- // Update the client defs with latest server *handle* based state change/modify number
- // to keep pace with the state changes. Passed back later on, to get further changes
- client_def->set_state_change_no( server_state_change_no_);
- client_def->set_modify_change_no( server_modify_change_no_ );
-
- try {
-#ifdef DEBUG_MEMENTO
- std::cout << "DefsDelta::incremental_sync compound_mementos_.size() = " << compound_mementos_.size() << "\n";
-#endif
- std::for_each(compound_mementos_.begin(),compound_mementos_.end(),
- boost::bind(&CompoundMemento::incremental_sync,_1,client_def,boost::ref(changed_nodes)));
- }
- catch ( std::exception& e) {
- throw std::runtime_error("Could not apply incremental server changes to client defs, because: " + string(e.what()));
- }
-
- // For each compound memento, we should have change node.
- //if ( compound_mementos_.size() != changed_nodes.size()) {
- // std::cout << "**** compound_mementos_.size() " << compound_mementos_.size() << " changed_nodes.size(): " << changed_nodes.size() << "\n";
- //}
- // assert( compound_mementos_.size() == changed_nodes.size()); // FIXME restore for long term GUI test
-
- // return true if there were any changes made
- return !compound_mementos_.empty();
-}
-
-void DefsDelta::add(compound_memento_ptr memento)
-{
- compound_mementos_.push_back(memento);
-}
-
diff --git a/ecflow_4_0_7/ANode/src/DefsDelta.hpp b/ecflow_4_0_7/ANode/src/DefsDelta.hpp
deleted file mode 100644
index de58bd7..0000000
--- a/ecflow_4_0_7/ANode/src/DefsDelta.hpp
+++ /dev/null
@@ -1,88 +0,0 @@
-#ifndef DEFS_DELTA_HPP_
-#define DEFS_DELTA_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #23 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-// class DefsDelta: holds a list of incremental changes made in the server.
-// This class is created in the server, and transferred to the client
-// The client use it to syncronize with the server, without the need
-// for asking for the full defs.
-//
-// When the client request the incremental changes, it also passes its client_state_change_no.
-// The client_state_change number is used in the server side to determine what's changed.
-// These changes are collated with add() and transferred to the client.
-// The client then calls incremental_sync() which will apply the changes to the client defs
-// so bringing it in sync with the server defs.
-//
-// Note:: updating state_change_no() on the *client side* a no-op() it has no effect
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/serialization/level.hpp>
-#include <boost/serialization/tracking.hpp>
-#include "Memento.hpp"
-
-class DefsDelta : private boost::noncopyable {
-public:
- ///=========================================================================
- /// *Server side*
- DefsDelta(unsigned int client_state_change_no)
- : client_state_change_no_(client_state_change_no),
- server_state_change_no_(0),
- server_modify_change_no_(0) {}
-
- /// This class can be re-used hence init() should reset all data members
- void init(unsigned int client_state_change_no);
-
- /// Add the compound memento, ie. store all memento's for a *given* node.
- void add(compound_memento_ptr);
-
- void set_server_state_change_no( unsigned int s) { server_state_change_no_ = s ; }
- void set_server_modify_change_no( unsigned int s) { server_modify_change_no_ = s ; }
- unsigned int get_server_state_change_no() const { return server_state_change_no_; }
- unsigned int get_server_modify_change_no() const { return server_modify_change_no_; }
-
- ///=========================================================================
- /// *Client side*
- /// Applies the mementos to the client defs and record all changed nodes.
- /// Can raise std::runtime_error.
- /// Note:: updating state_change_no() on the *client side* has *no effect*
- bool incremental_sync(defs_ptr client_def, std::vector<std::string>& changed_nodes) const;
-
-
- /// =========================================================================
- // The client state change number. Used to determine what's changed
- unsigned int client_state_change_no() const { return client_state_change_no_;}
-
- /// return the number of compound mementos
- size_t size() const { return compound_mementos_.size(); }
-
-private:
- unsigned int client_state_change_no_; // *no* need to persist since only used on server side
-
- unsigned int server_state_change_no_;
- unsigned int server_modify_change_no_;
- std::vector<compound_memento_ptr> compound_mementos_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & server_state_change_no_;
- ar & server_modify_change_no_;
- ar & compound_mementos_;
- }
-};
-
-// This should ONLY be added to objects that are *NOT* serialised through a pointer
-BOOST_CLASS_IMPLEMENTATION(DefsDelta, boost::serialization::object_serializable)
-BOOST_CLASS_TRACKING(DefsDelta,boost::serialization::track_never);
-
-#endif
diff --git a/ecflow_4_0_7/ANode/src/EcfFile.cpp b/ecflow_4_0_7/ANode/src/EcfFile.cpp
deleted file mode 100644
index 9c342e1..0000000
--- a/ecflow_4_0_7/ANode/src/EcfFile.cpp
+++ /dev/null
@@ -1,1348 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #66 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <set>
-#include <sstream>
-#include <sys/stat.h>
-
-#include "boost/foreach.hpp"
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/algorithm/string/trim.hpp>
-
-#include "EcfFile.hpp"
-#include "Log.hpp"
-#include "Str.hpp"
-#include "Ecf.hpp"
-#include "File.hpp"
-#include "Task.hpp"
-#include "JobsParam.hpp"
-
-namespace fs = boost::filesystem;
-using namespace std;
-using namespace ecf;
-using namespace boost;
-
-//#define DEBUG_ECF_ 1
-//#define DEBUG_PRE_PROCESS 1
-//#define DEBUG_PRE_PROCESS_INCLUDES 1 // be careful with this as it will skew the diffs in test code
-//#define DEBUG_MIGRATE 1 // for TEST ONLY
-
-//#define DEBUG_PRE_PROCESS_OUTPUT 1
-//#define DEBUG_VAR_SUB_OUTPUT 1
-//#define DEBUG_MAN_FILE 1
-
-static const char* T_NOOP = "nopp";
-static const char* T_COMMENT = "comment";
-static const char* T_MANUAL = "manual";
-static const char* T_END = "end";
-static const char* T_ECFMICRO = "ecfmicro";
-static const char* T_INCLUDE = "include";
-static const char* T_INCLUDENOPP = "includenopp";
-
-static void vector_to_string(const std::vector<std::string>& vec, std::string& str)
-{
- // Determine size of string, to avoid reallocation
- size_t the_string_size = 0;
- size_t theSize = vec.size();
- for(size_t i = 0; i < theSize; i++) { the_string_size += vec[i].size() + 1; } // +1 is for "\n";
- str.reserve( str.size() + the_string_size);
-
- // populate string using the vector
- for(size_t i = 0; i < theSize; i++) {
- str += vec[i];
- str += "\n";
- }
-}
-
-// ==================================================================================
-// Avoid making any data model/defs state changes. Changes like:
-// node_->flag().set(ecf::Flag::NO_SCRIPT);
-// Which will cause a state change.
-// If the script fails then it is up to the calling Task to set this flag
-// This class is also used to extract the scripts/manual, etc form
-// a read only command. hence this class can not make state changes
-// ===================================================================================
-EcfFile::EcfFile( Node* t,
- const std::string& pathToEcfFileOrCommand,
- bool fetchCommand
-)
-: node_( t ),
- script_path_or_cmd_( pathToEcfFileOrCommand )
- /*,fetchCommand_( fetchCommand ) */
-{
- node_->findParentUserVariableValue(Str::ECF_MICRO(),ecfMicroCache_);
- if ( ecfMicroCache_.empty() || ecfMicroCache_.size() != 1) {
- std::stringstream ss;
- ss << "EcfFile::EcfFile: Node " << t->absNodePath() << " is referencing a invalid ECF_MICRO variable(' " << ecfMicroCache_ << "). ECF_MICRO when overridden, must be a single character.";
- throw std::runtime_error(ss.str());
- }
-
-#ifdef DEBUG_ECF_
- cout << " EcfFile::EcfFile pathToEcfFileOrCommand = " << script_path_or_cmd_ << " fetchCommand = " << fetchCommand << "\n";
-#endif
-}
-
-void EcfFile::manual(std::string& theManual)
-{
- /// Pre-process the file accessible from the server
- std::vector<std::string> lines;
- std::string error_msg;
- EcfFile::Type file_type = (node_->isSubmittable()) ? EcfFile::SCRIPT : EcfFile::MANUAL ;
- if (!open_script_file(script_path_or_cmd_, file_type, lines, error_msg)) {
- std::stringstream ss; ss << "EcfFile::manual: For node " << node_->debugNodePath() << ", failed to open file " << script_path_or_cmd_ << " : " << error_msg;
- throw std::runtime_error(ss.str());
- }
-
- // expand all %includes this will expand %includenopp by enclosing in %nopp %end, will populate jobLines_
- if (!preProcess(lines,error_msg)) {
- std::stringstream ss; ss << "EcfFile::manual: For node " << node_->debugNodePath() << ", failed to pre-process file " << script_path_or_cmd_ << " : " << error_msg;
- throw std::runtime_error(ss.str());
- }
-
- // perform variable sub's but don't error if failure
- try {
- JobsParam dummy; // create jobs = false, spawn jobs = false
- variableSubstituition(dummy);
- }
- catch (...) {}
-
- vector<string> theManualLines;
- if (!extractManual(jobLines_,theManualLines,error_msg)) {
- std::stringstream ss;
- ss << "EcfFile::manual: extraction failed for task " << node_->absNodePath() << " " << error_msg;
- throw std::runtime_error(ss.str());
- }
-
- if (theManualLines.empty()) {
- // There is no %manual -> %end in the file. However this may be .man file for Suites/Family
- // For this case just include the pre-processed contents as is, ie since the whole file
- // is the manual
- if (node_->isNodeContainer()) {
- vector_to_string(jobLines_,theManual);
- return;
- }
- }
-
- vector_to_string(theManualLines,theManual);
-}
-
-void EcfFile::script(std::string& theScript) const
-{
- if (!File::open(script_path_or_cmd_,theScript)) {
- std::stringstream ss;
- ss << "EcfFile::script: Could not open script for task/alias " << node_->absNodePath() << " at path " << script_path_or_cmd_;
- throw std::runtime_error(ss.str());
- }
-}
-
-void EcfFile::pre_process(std::vector<std::string>& user_edit_file, std::string& pre_processed_file)
-{
- // expand all %includes this will expand %includenopp by enclosing in %nopp %end, will populate jobLines_
- std::string errormsg;
- if (!preProcess(user_edit_file,errormsg)) {
- throw std::runtime_error("EcfFile::pre_process: Failed to pre_process user edit file " + errormsg);
- }
-
- vector_to_string(jobLines_,pre_processed_file);
-}
-
-void EcfFile::pre_process(std::string& pre_processed_file)
-{
- /// Pre-process the ECF file accessible from the server
- std::vector<std::string> lines;
- std::string error_msg;
- if (!open_script_file(script_path_or_cmd_, EcfFile::SCRIPT, lines, error_msg)) {
- std::stringstream ss;
- ss << "EcfFile::pre_process: Failed to open file " << script_path_or_cmd_ << " : " << error_msg;
- throw std::runtime_error(ss.str());
- }
-
- // expand all %includes this will expand %includenopp by enclosing in %nopp %end, will populate jobLines_
- if (!preProcess(lines,error_msg)) {
- throw std::runtime_error("EcfFile::pre_process: Failed to pre_process: " + error_msg);
- }
-
- /// Find Used variables, *after* all %includes expanded, can throw std::runtime_error
- get_used_variables(pre_processed_file);
-
- /// Add pre-processed content
- vector_to_string(jobLines_,pre_processed_file);
-}
-
-void EcfFile::edit_used_variables(std::string& return_script_with_used_variables)
-{
- std::string errorMsg;
- std::vector<std::string> lines;
- if (!open_script_file(script_path_or_cmd_, EcfFile::SCRIPT, lines, errorMsg)) {
- throw std::runtime_error( "EcfFile::edit_used_variables: Open script failed : " + errorMsg ) ;
- }
-
- // Copy the script file, *BEFORE* expanding the includes
- std::string script;
- vector_to_string(lines,script);
-
- // expand all %includes
- if (!preProcess(lines, errorMsg)) {
- throw std::runtime_error( "EcfFile::edit_used_variables: PreProcess script failed : " + errorMsg ) ;
- }
-
- /// Find Used variables, *after* all %includes expanded, Can throw std::runtime_error
- get_used_variables(return_script_with_used_variables);
-
- /// Return Used variables and SCRIPT before pre-processing
- return_script_with_used_variables += script;
-}
-
-
-const std::string& EcfFile::create_job( JobsParam& jobsParam)
-{
-#ifdef DEBUG_ECF_
- cout << "EcfFile::createJob task " << node_->absNodePath() << " script_path_or_cmd_ = " << script_path_or_cmd_ << "\n";
-#endif
-
- // NOTE: When editing pure python jobs, we may have *NO* variable specified, but only user_edit_file
- // hence whenever we have user_edit_file, we should follow the else part below
- std::string error_msg;
- std::vector<std::string> lines;
- if (jobsParam.user_edit_variables().empty() && jobsParam.user_edit_file().empty()) {
- /// The typical *NORMAL* path
- if (!open_script_file(script_path_or_cmd_, EcfFile::SCRIPT, lines, error_msg)) {
- throw std::runtime_error("EcfFile::create_job: failed " + error_msg );
- }
- }
- else {
- // *USER* edit, two kinds
- if (jobsParam.user_edit_file().empty()) {
- // *USE* user variables, but ECF file accessible from the server
- if (!open_script_file(script_path_or_cmd_, EcfFile::SCRIPT, lines, jobsParam.errorMsg())) {
- throw std::runtime_error("EcfFile::create_job: User variables, Could not open script: " + error_msg );
- }
- }
- else {
- // *USE* the user supplied ECF file *AND* user variables
- lines = jobsParam.user_edit_file();
- }
- }
-
- // expand all %includes this will expand %includenopp by enclosing in %nopp %end
- if (!preProcess(lines,error_msg)) {
- throw std::runtime_error("EcfFile::create_job: pre process failed " + error_msg );
- }
-
-#ifdef DEBUG_PRE_PROCESS_OUTPUT
- std::string err;
- File::create("preProcess" + get_extn(),jobLines_,err);
-#endif
-
- // _IF_ ECF_CLIENT is specified provide Special support for migration.
- // The variable ECF_CLIENT is used to specify the path to client exe.
- // This is then used to replace smsinit,smscomplete, smsevent,smsmeter.smslabel,smsabort
- std::string clientPath;
- if (node_->findParentUserVariableValue("ECF_CLIENT", clientPath)) {
- if (!replaceSmsChildCmdsWithEcf(clientPath,error_msg) ) {
- throw std::runtime_error("EcfFile::create_job: ECF_CLIENT replacement failed " + error_msg );
- }
-#ifdef DEBUG_MIGRATE
- std::string err;
- File::create("migrate" + get_extn(),jobLines_,err);
-#endif
- }
-
- /// Will use *USER* supplied edit variables in preference to node tree variable *IF* supplied
- /// expand %VAR% or %VAR:sub% & replace %% with %
- // Allow variable substitution in comment and manual blocks. But if it fails, don't report as an error
- variableSubstituition(jobsParam);
-
-#ifdef DEBUG_VAR_SUB_OUTPUT
- std::string err1;
- File::create("variableSub" + get_extn(),jobLines_,err1);
-#endif
-
-#ifdef DEBUG_MAN_FILE
- if (!doCreateManFile(error_msg)) {
- throw std::runtime_error("EcfFile::create_job: manual file creation failed " + error_msg );
- }
-#endif
-
- /// Create the user file for tasks, when submitting without aliases, before removing comments
- if (node_->isTask() && !jobsParam.user_edit_variables().empty()) {
- doCreateUsrFile();
- }
-
- removeCommentAndManual();
- remove_nopp_end_tokens();
-
- return doCreateJobFile(jobsParam/* this is only past in for profiling */); // create job on disk
-}
-
-void EcfFile::extract_used_variables(NameValueMap& used_variables_as_map,const std::vector<std::string> &script_lines)
-{
- // we only process the contents of the FIRST %comment %end
- bool comment = false;
- size_t theSize = script_lines.size();
- for(size_t i=0; i < theSize; ++i) {
-
- // std::cout << "EcfFile::extract_used_variables found:'" << script_lines[i] << "\n";
- if (script_lines[i].empty()) continue;
-
- // take into account micro char during variable substitution
- string::size_type ecfmicro_pos = script_lines[i].find(Ecf::MICRO());
- if ( ecfmicro_pos == 0) {
-
- // We can not do variable substitution between %nopp/%end
- if (script_lines[i].find(T_COMMENT) == 1) { comment = true; continue;}
- if (script_lines[i].find(T_NOOP) == 1) { return;}
- if (script_lines[i].find(T_MANUAL) == 1) { return;}
- if (script_lines[i].find(T_END) == 1) { return; }
- }
-
- if (comment) {
-
- // expect name = value
- string::size_type equal_pos = script_lines[i].find("=");
- if ( equal_pos == string::npos) continue;
- string name = script_lines[i].substr(0,equal_pos);
- string value = script_lines[i].substr(equal_pos+1);
- boost::algorithm::trim(name);
- boost::algorithm::trim(value);
-
- //std::cout << " extracted as '" << name << "' = '" << value << "'\n";
- used_variables_as_map.insert( std::make_pair(name, value) );
- }
- }
-}
-
-bool EcfFile::preProcess(std::vector<std::string>& script_lines, std::string& errormsg)
-{
- /// Clear existing jobLines
- jobLines_.clear();
- jobLines_.reserve(512); // estimate for includes
-
- // get the cached ECF_MICRO variable, typically its one char.
- string ecfMicro = ecfMicroCache_;
-
-#ifdef DEBUG_PRE_PROCESS
- cout << " EcfFile::preProcess task:" << node_->absNodePath() << " script_path_or_cmd_=" << script_path_or_cmd_ << " ecfMicro = " << ecfMicro << "\n";
- for(size_t i=0; i < script_lines.size(); ++i) { cerr << " script_lines[i] = " << i << " " << script_lines[i] << "\n"; }
-#endif
-
- // include pre-processing on the included file.
- // Note: include directives _in_ manual/comment should he handled.
- // only include directives in %nopp/%end are ignored
- std::set<std::string> globalIncludedFileSet; // test for recursive includes
- int recursive_count = 0;
- std::vector<std::string> tokens; // re-use to save memory
- std::vector<std::string> includeLines; // re-use to save memory
-
- // constant until ecfmicro changes, then reset
- string pp_nopp = ecfMicro; pp_nopp += T_NOOP;
- string pp_comment = ecfMicro; pp_comment += T_COMMENT;
- string pp_manual = ecfMicro; pp_manual += T_MANUAL;
- string pp_end = ecfMicro; pp_end += T_END;
-
- while (1) {
-
- std::set<std::string> localIncludedFileSet;
- bool filesToInclude = false;
- bool nopp = false; bool comment = false; bool manual = false;
- for(size_t i=0; i < script_lines.size(); ++i) {
- jobLines_.push_back(script_lines[i]); // copy line
-
- // For variable substitution % can occur anywhere on the line, for pre -processing of
- // %ecfmicro,%manual,%comment,%end,%include,%includenopp it must be the very *first* character
- string::size_type ecfmicro_pos = script_lines[i].find(ecfMicro);
- if (ecfmicro_pos == string::npos) continue;
-
- if (!nopp && !comment && !manual) {
- // For variable substitution '%' can occur anywhere on the line.
- // Check for Mismatched micro i.e %FRED or %FRED%%
- if (ecfmicro_pos != 0) {
- int ecfMicroCount = countEcfMicro( script_lines[i], ecfMicro );
- if (ecfMicroCount % 2 != 0 ) {
- std::stringstream ss;
- ss << "Mismatched ecfmicro(" << ecfMicro << ") count(" << ecfMicroCount << ") '" << script_lines[i] << "' in " << path();
- errormsg += ss.str();
- dump_expanded_script_file(i,script_lines);
- return false;
- }
- }
- }
-
- // %ecfmicro,%manual,%comment,%end,%include,%includenopp it must be the very *first* character
- if (ecfmicro_pos != 0) continue; //handle 'garbage%include'
-
-#ifdef DEBUG_PRE_PROCESS
- std::cout << i << ": " << script_lines[i] << "\n";
-#endif
- if (script_lines[i].find(pp_manual) == 0) {
- if (comment || manual) {
- std::stringstream ss; ss << "Embedded comments/manuals not supported '" << script_lines[i] << "' at " << path();
- errormsg += ss.str();
- dump_expanded_script_file(i,script_lines);
- return false;
- }
- manual = true ; continue;
- }
- if (script_lines[i].find(pp_comment) == 0) {
- if (comment || manual) {
- std::stringstream ss; ss << "Embedded comments/manuals not supported '" << script_lines[i] << "' at " << path();
- errormsg += ss.str();
- dump_expanded_script_file(i,script_lines);
- return false;
- }
- comment = true ; continue;
- }
- if (script_lines[i].find(pp_nopp) == 0) {
- if (nopp) {
- std::stringstream ss; ss << "Embedded nopp not supported '" << script_lines[i] << "' in " << path();
- errormsg += ss.str();
- dump_expanded_script_file(i,script_lines);
- return false;
- }
- nopp = true ; continue;
- }
- if (script_lines[i].find(pp_end) == 0) {
- if (comment) { comment = false; continue;}
- if (manual) { manual = false; continue;}
- if (nopp) { nopp = false; continue;}
- std::stringstream ss;
- ss << pp_end << " found with no matching %comment | %manual | %nopp at '" << script_lines[i]<< "' at path " << path();
- errormsg += ss.str();
- dump_expanded_script_file(i,script_lines);
- return false;
- }
- if (nopp) continue;
-
- tokens.clear();
- Str::split( script_lines[i], tokens );
-
- // Handle ecfmicro replacement ================================================================================
- if (script_lines[i].find(T_ECFMICRO) == 1) { // %ecfmicro #
- // keep %ecfmicro in jobs file later processing, i.e for comments/manuals
-
- if (tokens.size() < 2) {
- std::stringstream ss;
- ss << "ecfmicro does not have a replacement character, in " << script_path_or_cmd_;
- errormsg += ss.str();
- return false;
- }
-
- // This is typically a single character, however $/£ will be multi-character i.e size 2
- ecfMicro = tokens[1];
- if (ecfMicro.size() > 2) {
- std::stringstream ss;
- ss << "Expected ecfmicro replacement to be a single character, but found '" << ecfMicro << "' " << ecfMicro.size() << " in file : " << script_path_or_cmd_;
- errormsg += ss.str();
- return false;
- }
-
- pp_nopp = ecfMicro; pp_nopp += T_NOOP;
- pp_comment = ecfMicro; pp_comment += T_COMMENT;
- pp_manual = ecfMicro; pp_manual += T_MANUAL;
- pp_end = ecfMicro; pp_end += T_END;
-
- continue;
- }
-
- // Handle the includes ===================================================================================
- if (tokens.size() < 2) continue;
-
- bool includenopp = (script_lines[i].find(T_INCLUDENOPP) == 1);
- if (!includenopp) {
- // Notice we only do recursive includes for %include
- filesToInclude = (script_lines[i].find(T_INCLUDE) != string::npos);
- }
- if (!filesToInclude && !includenopp) continue;
-
- // remove %include since were going to expand it.
- jobLines_.pop_back();
-
-#ifdef DEBUG_PRE_PROCESS_INCLUDES
- // Output the includes for debug purposes. Will appear in preProcess.ecf
- // Note: Will interfere with diff
- jobLines_.push_back("========== include of " + tokens[1] + " ===========================");
-#endif
-
- std::string includedFile = getIncludedFilePath(tokens[1], script_lines[i], errormsg);
- if (!errormsg.empty()) return false;
- localIncludedFileSet.insert(includedFile);
-#ifdef DEBUG_PRE_PROCESS
- cout << "EcfFile::preProcess processing " << includedFile << "\n";
-#endif
-
- includeLines.clear();
- if (!open_script_file(includedFile, EcfFile::INCLUDE, includeLines, errormsg)) {
- return false;
- }
-
- // append included script_lines to jobsLines
- if (includenopp) jobLines_.push_back(ecfMicro + T_NOOP);
- std::copy( includeLines.begin(), includeLines.end(), std::back_inserter( jobLines_ ) );
- if (includenopp) jobLines_.push_back(ecfMicro + T_END);
- }
-
-
- if (nopp) {
- std::stringstream ss;
- ss << "Unterminated nopp, matching 'end' is missing for " << path();
- errormsg += ss.str();
- dump_expanded_script_file(1,script_lines);
- return false;
- }
-
- // Check for recursive includes. some includes like %include <endt.h>
- // are included many times, but the include is not recursive.
- // To get round this will use a simple count.
- BOOST_FOREACH(const string& theInclude, localIncludedFileSet) {
-
- if (globalIncludedFileSet.find(theInclude) != globalIncludedFileSet.end()) {
-
- if ( recursive_count > 10) {
- std::stringstream ss;
- ss << "Recursive include of file " << theInclude << " for " << path();
- errormsg += ss.str();
- return false;
- }
- recursive_count++;
- }
- else globalIncludedFileSet.insert(theInclude);
- }
-
- if (!filesToInclude) break;
- else {
- // repeat until no %include left
- script_lines = jobLines_;
- jobLines_.clear();
- }
- }
- return true;
-}
-
-bool EcfFile::open_script_file(
- const std::string& file,
- EcfFile::Type type,
- std::vector<std::string>& lines,
- std::string& errormsg) const
-{
-#ifdef DEBUG_ECF_
- std::cout << "EcfFile::open_script_file file(" << file << ") type(" << fileType(type) << ")\n";
-#endif
- if (file.empty()) {
- std::stringstream ss;
- ss << "EcfFile::open_script_file: Could not open ecf " << fileType(type) << " file. Input File/cmd string is empty.";
- errormsg += ss.str();
- return false;
- }
-
- // if (fetchCommand_) {
- // // SMSFETCH is not used in operation or research. I think this is how it should work
- // // But not tested. Commented out until demand for it.
- // string theFile = file;
- // string theCommand = script_path_or_cmd_; // variables have already been substituted
- // switch (type) {
- // case EcfFile::SCRIPT: { theCommand += " -s "; theFile = node_->name() + get_extn(); break;}
- // case EcfFile::INCLUDE: theCommand += " -i "; break;
- // case EcfFile::MANUAL: { theCommand += " -m "; theFile = node_->name() + get_extn(); break;}
- // case EcfFile::COMMENT: { theCommand += " -c "; theFile = node_->name() + get_extn(); break;}
- // }
- // theCommand += theFile;
- // FILE *fp = popen(theCommand.c_str(),"r");
- // //cout << " " << theCommand << "\n";
- // if (!fp) {
- // std::stringstream ss;
- // ss << "Could not open " << fileType(type) << " via cmd " << theCommand << " for task " << node_->absNodePath() << " ";
- // errormsg += ss.str();
- // return false;
- // }
- // char line[LINE_MAX];
- // while( fgets(line,LINE_MAX,fp) ) {
- // lines.push_back(line);
- // }
- // pclose(fp);
- // }
- // else {
- if ( ! File::splitFileIntoLines(file, lines) ) {
- std::stringstream ss;
- ss << "Could not open " << fileType(type) << " file:" << file;
- errormsg += ss.str();
- return false;
- }
- // }
-
- return true;
-}
-
-std::string EcfFile::fileType(EcfFile::Type t)
-{
- switch (t) {
- case EcfFile::SCRIPT: return "script"; break;
- case EcfFile::INCLUDE: return "include"; break;
- case EcfFile::MANUAL: return "manual"; break;
- case EcfFile::COMMENT: return "comment"; break;
- }
- assert(false);
- return string();
-}
-
-
-static void replace( string::size_type commentPos,
- std::string& jobLine,
- const std::string& smsChildCmd,
- const std::string& ecfEquiv,
- const std::string& clientPath)
-{
- string::size_type childPos = jobLine.find(smsChildCmd);
- if ( childPos != std::string::npos ) {
- if ( commentPos == std::string::npos) {
- std::string replace = clientPath;
- replace += ecfEquiv;
- Str::replace(jobLine,smsChildCmd,replace);
- }
- else if ( childPos < commentPos) {
- std::string replace = clientPath;
- replace += ecfEquiv;
- Str::replace(jobLine,smsChildCmd,replace);
- }
- }
-}
-
-bool EcfFile::replaceSmsChildCmdsWithEcf(const std::string& clientPath, std::string& errormsg)
-{
- // smsinit $$ ---> ECF_CLIENT(value) --init $$
- // smscomplete ---> ECF_CLIENT(value)
- // smsevent eventname ---> ECF_CLIENT(value) --event eventname
- // smsmeter metername value ---> ECF_CLIENT(value) --meter metername value
- // smslabel value ---> ECF_CLIENT(value) --label value
- // smswait expr ---> ECF_CLIENT(value) --wait expr
- // smsabort ---> ECF_CLIENT(value) --abort
- size_t jobLines_size = jobLines_.size();
- for(size_t i=0; i < jobLines_size; ++i) {
-
- // ONLY do the replacement if there is no leading comment
- string::size_type commentPos = jobLines_[i].find("#");
- replace(commentPos, jobLines_[i], "smsinit", " --init ", clientPath);
- replace(commentPos, jobLines_[i], "smscomplete"," --complete ", clientPath);
- replace(commentPos, jobLines_[i], "smsabort", " --abort ", clientPath);
- replace(commentPos, jobLines_[i], "smsevent", " --event ", clientPath);
- replace(commentPos, jobLines_[i], "smsmeter", " --meter ", clientPath);
- replace(commentPos, jobLines_[i], "smslabel", " --label ", clientPath);
- replace(commentPos, jobLines_[i], "smswait", " --wait ", clientPath);
- }
- return true;
-}
-
-void EcfFile::variableSubstituition(JobsParam& jobsParam)
-{
- // Allow variable substitution in comment and manual blocks.
- // But if it fails, don't report as an error
-
- // get the cached ECF_MICRO variable, typically its one char.
- string ecfMicro = ecfMicroCache_;
- char microChar = ecfMicro[0];
-
- // We need a stack to properly implement nopp. This is required since we need to pair
- // the %end, with nopp. i.e need to handle
- // %nopp
- // %comment
- // %end // this is paired with comment
- // %end // This is paired with nopp
- const int NOPP = 0;
- const int COMMENT = 1;
- const int MANUAL = 2;
- std::vector<int> pp_stack;
- std::vector<std::string> tokens;
-
- bool nopp = false;
- size_t jobLines_size = jobLines_.size();
- for(size_t i=0; i < jobLines_size; ++i) {
-
- if (jobLines_[i].empty()) continue;
-
- // take into account micro char during variable substitution
- string::size_type ecfmicro_pos = jobLines_[i].find(ecfMicro);
- if (ecfmicro_pos == 0) {
-
- // We can not do variable substitution between %nopp/%end
- if (jobLines_[i].find(T_MANUAL) == 1) { pp_stack.push_back(MANUAL); continue; }
- if (jobLines_[i].find(T_COMMENT) == 1) { pp_stack.push_back(COMMENT); continue; }
- if (jobLines_[i].find(T_NOOP) == 1) { pp_stack.push_back(NOPP); nopp = true; continue; }
- if (jobLines_[i].find(T_END) == 1) {
- if (pp_stack.empty()) throw std::runtime_error("EcfFile::variableSubstituition: failed unpaired %end");
- int last_directive = pp_stack.back(); pp_stack.pop_back();
- if (last_directive == NOPP) nopp = false;
- continue;
- }
-
- if (jobLines_[i].find(T_ECFMICRO) == 1) { // %ecfmicro #
-
- tokens.clear();
- Str::split( jobLines_[i], tokens );
- if (tokens.size() < 2) {
- std::stringstream ss; ss << "ecfmicro does not have a replacement character, in " << script_path_or_cmd_;
- throw std::runtime_error("EcfFile::variableSubstituition: failed : " + ss.str());
- }
- ecfMicro = tokens[1];
- microChar = ecfMicro[0];
- continue; // no point in doing variable subs on %ecfmicro ^
- }
- }
- if ( nopp ) continue;
-
-
- /// For variable substitution % can occur anywhere on the line
- if (ecfmicro_pos != string::npos) {
-
- /// In the *NORMAL* flow jobsParam.user_edit_variables() will be EMPTY
- if ( !node_->variable_substitution( jobLines_[i], jobsParam.user_edit_variables(), microChar ) ) {
-
- // Allow variable substitution in comment and manual blocks.
- // But if it fails, don't report as an error
- int last_directive = -1;
- if (!pp_stack.empty()) last_directive = pp_stack.back();
- if ( last_directive == COMMENT || last_directive == MANUAL) continue;
-
- std::stringstream ss; ss << "EcfFile::variableSubstituition: failed : '" << jobLines_[i] << "'";
- dump_expanded_script_file( i, jobLines_ );
- throw std::runtime_error(ss.str());
- }
- }
- }
-}
-
-
-void EcfFile::get_used_variables(std::string& used_variables) const
-{
- /// Find Used variables, *after* all %includes expanded
- NameValueMap used_variables_map;
- std::string errorMsg;
- if (!get_used_variables(used_variables_map, errorMsg) ) {
- throw std::runtime_error( "EcfFile::get_used_variables: Extract used variables failed : " + errorMsg ) ;
- }
-
- if (!used_variables_map.empty()) {
-
- // add %comment - edit user variable, %end - ecf user variable
- used_variables = ecfMicroCache_;
- used_variables += "comment - ecf user variables\n";
-
- // ***************************************************************************************
- // Custom handling of dynamic variables, i.e ECF_TRYNO, ECF_PASS and
- // any variable that embeds a try number, i.e. ECF_JOB, ECF_JOBOUT
- // This is required since the try number is *always* incremented *before* job submission,
- // hence the value extracted from the job file will *not* be accurate, hence we exclude it.
- // This way at job submission we use the latest/correct value, which is in-sync with JOB OUTPUT
- // Note: Otherwise the job output will not be in sync
- //
- // Custom handling of ECF_PORT,ECF_NODE,ECF_NAME do not show these variables, these variables
- // including ECF_PASS appear in the script. If the user accidentally edits them,
- // Child communication with the server will be broken. Hence not shown
- //
- // All the above are examples of generated variables, which should not really be edited
- // The used variables are typically *user* variable *in* the scripts, that user may need
- // to modify. Hence we have also excluded generated variables SUITE, FAMILY, TASK
- // ****************************************************************************************
- std::pair<std::string, std::string> item;
- BOOST_FOREACH(item, used_variables_map) {
- if ( item.first.find(Str::ECF_TRYNO()) != std::string::npos) continue;
- if ( item.first.find(Str::ECF_JOB()) != std::string::npos) continue;
- if ( item.first.find(Str::ECF_JOBOUT()) != std::string::npos) continue;
- if ( item.first.find(Str::ECF_PASS()) != std::string::npos) continue;
- if ( item.first.find(Str::ECF_PORT()) != std::string::npos) continue;
- if ( item.first.find(Str::ECF_NODE()) != std::string::npos) continue;
- if ( item.first.find(Str::ECF_NAME()) != std::string::npos) continue;
-
- // We must use exact match, to avoid user variables like ESUITE,EFAMILY,ETASK
- if ( item.first == Str::TASK()) continue;
- if ( item.first == Str::FAMILY()) continue;
- if ( item.first == "FAMILY1") continue;
- if ( item.first == Str::SUITE()) continue;
- used_variables += item.first;
- used_variables += " = ";
- used_variables += item.second;
- used_variables += "\n";
- }
-
- used_variables += ecfMicroCache_;
- used_variables += "end - ecf user variables\n";
- }
-}
-
-bool EcfFile::get_used_variables(NameValueMap& used_variables, std::string& errormsg) const
-{
- // get the cached ECF_MICRO variable, typically its one char.
- string ecfMicro = ecfMicroCache_;
-
- char microChar = ecfMicro[0];
-
- // We need a stack to properly implement nopp. This is required since we need to pair
- // the %end, with nopp. i.e need to handle
- // %nopp
- // %comment
- // %end // this is paired with comment
- // %end // This is paired with nopp
- const int NOPP = 0;
- const int COMMENT = 1;
- const int MANUAL = 2;
- std::vector<int> pp_stack;
-
- bool nopp = false;
- std::stringstream ss;
- std::vector<std::string> tokens;
-
- size_t job_lines_size = jobLines_.size();
- for(size_t i=0; i < job_lines_size; ++i) {
-
- if (jobLines_[i].empty()) continue;
-
- // take into account micro char during variable substitution
- string::size_type ecfmicro_pos = jobLines_[i].find(ecfMicro);
- if (ecfmicro_pos == 0) {
-
- // We can not do variable substitution between %nopp/%end
- if (jobLines_[i].find(T_MANUAL) == 1) { pp_stack.push_back(MANUAL); continue; }
- if (jobLines_[i].find(T_COMMENT) == 1) { pp_stack.push_back(COMMENT); continue; }
- if (jobLines_[i].find(T_NOOP) == 1) { pp_stack.push_back(NOPP); nopp = true; continue; }
- if (jobLines_[i].find(T_END) == 1) {
- if (pp_stack.empty()) throw std::runtime_error("EcfFile::get_used_variables: failed unpaired %end");
- int last_directive = pp_stack.back(); pp_stack.pop_back();
- if (last_directive == NOPP) nopp = false;
- continue;
- }
-
- if (!nopp && jobLines_[i].find(T_ECFMICRO) == 1) { // %ecfmicro #
-
- tokens.clear();
- Str::split( jobLines_[i], tokens );
- if (tokens.size() < 2) {
- std::stringstream ss; ss << "ecfmicro does not have a replacement character, in " << script_path_or_cmd_;
- throw std::runtime_error("EcfFile::get_used_variables: failed : " + ss.str());
- }
- ecfMicro = tokens[1];
- microChar = ecfMicro[0];
- continue;
- }
- }
- if ( nopp ) continue;
-
-
- if (ecfmicro_pos != string::npos) {
-
- /// *Note:* currently this modifies jobLines_[i]
- std::string line_copy = jobLines_[i]; // avoid modifying the jobs Lines, end up doing variable substitution
- if ( !node_->find_all_used_variables( line_copy, used_variables, microChar ) ) {
-
- // Allow variable substitution in comment and manual blocks.
- // But if it fails, dont report as an error
- int last_directive = -1;
- if (!pp_stack.empty()) last_directive = pp_stack.back();
- if ( last_directive == COMMENT || last_directive == MANUAL) continue;
-
- ss << "Variable find failed for '" << jobLines_[i] << "' microChar='" << microChar << "' ";
- dump_expanded_script_file( i, jobLines_ );
- }
- }
- }
-
- // Append to error message if any
- errormsg += ss.str();
-
- return errormsg.empty();
-}
-
-
-const std::string& EcfFile::doCreateJobFile(JobsParam& jobsParam) const
-{
- if ( jobLines_.size() > 1 ) {
- // Guard against ecf file that exist's but is empty,
- // no point in creating empty job files for them
-
- // ECF_JOB is used with ECF_JOB_CMD when submitting a job.
- // First look for a user variable of name ECF_JOB, otherwise look for
- // the generated variable, hence this should never fail.
- // *This* assumes that:
- // a/ if the user has overiden ECF_JOB then it has been specified at the task level
- // Otherwise findParentVariableValue will find the generated ECF_JOB on the task
- // b/ The value of the user variable has a valid directory paths and job file name
- // c/ The user will lose the try number.
- std::string ecf_job;
- if (!node_->findParentVariableValue(Str::ECF_JOB(), ecf_job)) {
- LOG_ASSERT( !ecf_job.empty() ,"ECF_JOB should have been generated, program error");
- }
-
- // *** The location of the ECF_ file may not always be the same as the location
- // *** of the job file. Job file location is specified by ECF_JOB
- // Locate the directory where we found the ecf file.
- fs::path script_file_path( script_path_or_cmd_ );
- fs::path parent_path = script_file_path.parent_path();
- if ( fs::is_directory( parent_path ) ) {
-
- // cout << "EcfFile::createJob ecf " << path() << " ECF_JOB(" << ecf_job << ")\n";
- if (!File::createMissingDirectories(ecf_job)) {
- std::stringstream ss;
- ss << "EcfFile::doCreateJobFile: Could not create missing directories for ECF_JOB " << ecf_job << " File system full?";
- throw std::runtime_error(ss.str());
- }
-
- // Create the jobs file.
- std::string error_msg;
- if (!File::create(ecf_job, jobLines_,error_msg)) {
- std::stringstream ss;
- ss << "EcfFile::doCreateJobFile: Could not create job file " << ecf_job << " " << error_msg << " File system full?";
- throw std::runtime_error(ss.str());
- }
-
- // make the job file executable
- if ( chmod( ecf_job.c_str(), 0755 ) != 0 ) {
- std::stringstream ss;
- ss << "EcfFile::doCreateJobFile: Could not make job file " << ecf_job << " executable by using chmod";
- throw std::runtime_error(ss.str());
- }
-
- // record job size, for placement into log files
- size_t job_output_size = 0;
- size_t jobLines_size = jobLines_.size();
- for(size_t i = 0; i < jobLines_size; ++i) job_output_size += jobLines_[i].size();
- job_output_size += jobLines_size; // take into account new lines for each line of output
- job_size_ = "job_size:";
- job_size_ += boost::lexical_cast<std::string>(job_output_size);
- return job_size_;
- }
- else {
- std::stringstream ss;
- ss << "EcfFile::doCreateJobFile: The path '" << script_file_path.parent_path() << "' is not a directory";
- throw std::runtime_error(ss.str());
- }
- }
-
- std::stringstream ss;
- ss << "EcfFile::doCreateJobFile: The ecf file '" << path() << "' that is associated with task '" << node_->absNodePath() << "' is empty";
- throw std::runtime_error(ss.str());
-}
-
-bool EcfFile::doCreateManFile( std::string& errormsg)
-{
- vector<string> manFile;
- if (!extractManual(jobLines_,manFile,errormsg)) {
- return false;
- }
- if ( !manFile.empty() ) {
-
- // find the directory associated with ecf file and place Man file there.
- fs::path script_file_path( script_path_or_cmd_ );
- fs::path parent_path = script_file_path.parent_path();
- if ( fs::is_directory( parent_path ) ) {
-
- fs::path theManFilePath( parent_path.string() + '/' + node_->name() + File::MAN_EXTN() );
-
- // cout << "EcfFile::doCreateManFile job " << manFile.string() << "\n";
- if (!File::create(theManFilePath.string(),manFile,errormsg)) return false;
- }
- else {
- std::stringstream ss;
- ss << "man file creation failed. The path '" << script_file_path.parent_path() << "' is not a directory";
- errormsg += ss.str();
- return false;
- }
- }
- return true;
-}
-
-
-void EcfFile::doCreateUsrFile() const
-{
- // find the directory associated with ecf file and place .usr file there.
- fs::path script_file_path( script_path_or_cmd_ );
- fs::path parent_path = script_file_path.parent_path();
- if ( fs::is_directory( parent_path ) ) {
-
- fs::path theUsrFilePath( parent_path.string() + '/' + node_->name() + File::USR_EXTN() );
-
- // cout << "EcfFile::doCreateUsrFile job " << theUsrFilePath.string() << "\n";
- std::string error_msg;
- if (!File::create(theUsrFilePath.string(),jobLines_,error_msg)) {
- throw std::runtime_error("EcfFile::doCreateUsrFile: file creation failed : " + error_msg);
- }
- }
- else {
- std::stringstream ss;
- ss << "EcfFile::doCreateUsrFile: file creation failed. The path '" << script_file_path.parent_path() << "' is not a directory";
- throw std::runtime_error(ss.str());
- }
-}
-
-
-bool EcfFile::extractManual(const std::vector< std::string >& lines,
- std::vector< std::string >& theManualLines,
- std::string& errormsg) const
-{
- // Note: we have already done pre-processing, ie since the manual is obtained after
- // all the includes have been pre-procssed, hence most errors should have been caught
- // get the cached ECF_MICRO variable, typically its one char.
- string ecfMicro = ecfMicroCache_;
- std::vector<std::string> tokens;
-
- bool add = false;
- for (std::vector< std::string >::const_iterator i = lines.begin(); i!= lines.end(); ++i){
- if ( (*i).find(ecfMicro) == 0) {
- if ( (*i).find( T_MANUAL ) == 1 ) { add = true; continue; }
- if ( add && (*i).find( T_END ) == 1 ) { add = false; continue; }
-
- if ((*i).find(T_ECFMICRO) == 1) { // %ecfmicro #
- tokens.clear();
- Str::split( (*i), tokens );
- if (tokens.size() < 2) {
- std::stringstream ss; ss << "ecfmicro does not have a replacement character, in " << script_path_or_cmd_;
- errormsg += ss.str();
- return false;
- }
- ecfMicro = tokens[1];
- if (ecfMicro.size() > 2) {
- std::stringstream ss; ss << "Expected ecfmicro replacement to be a single character, but found '" << ecfMicro << "' " << ecfMicro.size() << " in file : " << script_path_or_cmd_;
- errormsg += ss.str();
- return false;
- }
- continue;
- }
- }
- if (add) { theManualLines.push_back(*i); }
- }
- if (add) {
- std::stringstream ss; ss << "Unterminated manual. Matching 'end' is missing, for file " << script_path_or_cmd_;
- errormsg += ss.str();
- dump_expanded_script_file(1,lines);
- return false;
- }
- return true;
-}
-
-std::string EcfFile::getIncludedFilePath( const std::string& includedFile,
- const std::string& line,
- std::string& errormsg)
-{
- // Include can have following format:
- // %include /tmp/file.name -> /tmp/filename
- // %include file.name -> filename
- // %include "../file.name" -> script_file_path/../file.name
- // %include "file.name" -> %ECF_HOME%/%SUITE%/%FAMILY%/filename
- // %include <file.name> -> %ECF_INCLUDE%/filename
- // %include <file.name> -> ECF_HOME/filename
-
-
- if ( includedFile.size() >=2 && includedFile[1] == '/') {
- // filename starts with /, no interpretation return as in
- // %include </home/sms/fred.ecf>
- // %include "/home/sms/fred.ecf"
- return includedFile.substr( 1, includedFile.size() - 2 );
- }
-
- std::stringstream ss;
- if ( includedFile[0] == '<' ) {
- // include <filename>
- // include contents of %ECF_INCLUDE%/filename
- // include contents of ECF_HOME/filename
- std::string ecf_include;
- if (node_->findParentUserVariableValue( Str::ECF_INCLUDE() , ecf_include ) && !ecf_include.empty() ) {
-
- ecf_include += '/';
- ecf_include += includedFile.substr( 1, includedFile.size() - 2 );
-
- // Don't rely on hard coded paths. Added for testing, but could be generally useful
- // since in test scenario ECF_INCLUDE is defined relative to $ECF_HOME
- node_->enviromentSubsitution(ecf_include);
-
- if (fs::exists(ecf_include)) return ecf_include;
-
- // ECF_INCLUDE is specified *BUT* the file does *NOT* exist, Look in ECF_HOME
- }
-
- // WE get HERE *if* ECF_INCLUDE not specified, or if specified but file *not found*
- ecf_include.clear();
- node_->findParentVariableValue( Str::ECF_HOME() , ecf_include );
- if (ecf_include.empty()) {
- ss << "ECF_INCLUDE/ECF_HOME not specified, for task " << node_->absNodePath() << " at " << line;
- errormsg += ss.str();
- return string();
- }
-
- ecf_include += '/';
- ecf_include += includedFile.substr( 1, includedFile.size() - 2 );
-
- return ecf_include;
- }
- else if ( includedFile[0] == '"' ) {
-
- // we have two forms: "head.h" & "../head.h"
-
- std::string path;
- if ( includedFile.find("../") == 1) {
- // Find the include file relative to the ecf file. "../head.h"
- // remove the leading and trailing '"'
- std::string the_included_file = includedFile;
- Str::removeQuotes(the_included_file);
-
- // Get the root path, i.e. script_path_or_cmd_ is of the form "/user/home/ma/mao/course/t1.ecf"
- // we need "/user/home/ma/mao/course/"
- std::string::size_type last_slash = script_path_or_cmd_.rfind("/");
- if (last_slash != std::string::npos) {
- path = script_path_or_cmd_.substr( 0, last_slash + 1 );
- path += the_included_file;
- // std::cout << "path == " << path << "\n";
- return path;
- }
- }
-
- // include contents of %ECF_HOME%/%SUITE%/%FAMILY%/filename
- node_->findParentUserVariableValue( Str::ECF_HOME() , path);
- if ( path.empty() ) {
- ss << "ECF_HOME not specified, for include " << line;
- errormsg += ss.str();
- return string();
- }
- path += '/';
- std::string suite;
- node_->findParentVariableValue( "SUITE" , suite); // SUITE is a generated variable
- if ( suite.empty() ) {
- ss << "SUITE not specified, for include " << line;
- errormsg += ss.str();
- return string();
- }
- path += suite;
- path += '/';
- std::string family;
- node_->findParentVariableValue( "FAMILY" , family); // FAMILY is a generated variable
- if ( family.empty() ) {
- ss << "FAMILY not specified, for include " << line;
- errormsg += ss.str();
- return string();
- }
- path += family;
- path += '/';
- path += includedFile.substr( 1, includedFile.size() - 2 ); // "filename"
- return path;
- }
-
- // File either has an absolute pathname or is in the current working dir.
- // include file name as is, from current working directory
- return includedFile;
-}
-
-void EcfFile::removeCommentAndManual()
-{
- // get the cached ECF_MICRO variable, typically its one char.
- string ecfMicro = ecfMicroCache_;
-
- // We need a stack to properly implement nopp. This is required since we need to pair
- // the %end, with nopp. i.e need to handle
- // %nopp
- // %comment
- // %end // this is paired with comment
- // %end // This is paired with nopp
- const int NOPP = 0;
- const int COMMENT = 1;
- const int MANUAL = 2;
- bool nopp = false;
- bool erase = false;
- std::vector<int> pp_stack;
- std::vector<std::string> tokens;
-
- for(std::vector<std::string>::iterator i=jobLines_.begin(); i!=jobLines_.end(); ++i) {
-
- // take into account micro char during removal of comment/manual
- string::size_type ecfmicro_pos = (*i).find(ecfMicro);
- if (ecfmicro_pos == 0) {
-
- // We can not remove comments/manuals between %nopp/%end
- if ((*i).find(T_MANUAL) == 1) {
- pp_stack.push_back(MANUAL);
- if (nopp) continue;
-
- // cerr << "EcfFile::removeCommentAndManual erase = " << erase << " " << *i << "\n";
- jobLines_.erase( i-- ); // remove %manual
- if (erase) {
- std::stringstream ss; ss << "EcfFile::removeCommentAndManual: Embedded manuals are not allowed in " << script_path_or_cmd_;
- throw std::runtime_error( ss.str() );
- }
- erase = true;
- continue;
- }
-
- if ((*i).find(T_COMMENT) == 1) {
- pp_stack.push_back(COMMENT);
- if (nopp) continue;
-
- // cerr << "EcfFile::removeCommentAndManual erase = " << erase << " " << *i << "\n";
- jobLines_.erase( i-- ); // remove %comment
- if (erase) {
- std::stringstream ss; ss << "EcfFile::removeCommentAndManual: Embedded comments are not allowed in " << script_path_or_cmd_;
- throw std::runtime_error( ss.str() );
- }
- erase = true;
- continue;
- }
-
- if ((*i).find(T_NOOP) == 1) { pp_stack.push_back(NOPP); nopp = true; continue; }
-
- if ((*i).find(T_END) == 1) {
- if (pp_stack.empty()) throw std::runtime_error("EcfFile::removeCommentAndManual: failed unpaired %end");
- int last_directive = pp_stack.back(); pp_stack.pop_back();
- if (last_directive == NOPP) nopp = false;
- else {
-// cerr << "EcfFile::removeCommentAndManual erase = " << erase << " " << *i << "\n";
- if (erase) {
- jobLines_.erase( i-- ); // remove %end associated with %comment and %manual
- erase = false;
- }
- }
- continue;
- }
-
- if (!nopp && (*i).find(T_ECFMICRO) == 1) {
-
- tokens.clear();
- Str::split( (*i), tokens );
- if (tokens.size() < 2) {
- std::stringstream ss; ss << "ecfmicro does not have a replacement character, in " << script_path_or_cmd_;
- throw std::runtime_error("EcfFile::removeCommentAndManual: failed " + ss.str());
- }
- ecfMicro = tokens[1];
- }
- }
- if ( nopp ) continue;
-
- // remove all line between %comment and %end | %manual and %end
- if (erase) {
- jobLines_.erase( i-- );
- }
- }
-
- if (erase) {
- std::stringstream ss;
- ss << "Unterminated comment/manual. Matching 'end' is missing, in " << script_path_or_cmd_;
- throw std::runtime_error("EcfFile::removeCommentAndManual: failed " + ss.str());
- }
-}
-
-void EcfFile::remove_nopp_end_tokens()
-{
- // get the cached ECF_MICRO variable, typically its one char.
- string ecfMicro = ecfMicroCache_;
-
- // We need a stack to properly implement nopp. This is required since we need to pair
- // the %end, with nopp. i.e need to handle
- // %nopp
- // %comment
- // %end // this is paired with comment **** this should stay ****
- // %end // This is paired with nopp **** this should be deleted ****
- const int NOPP = 0;
- const int COMMENT = 1;
- const int MANUAL = 2;
- std::vector<int> pp_stack;
- std::vector< std::string > tokens;
- bool nopp = false;
- bool erase = false;
-
- for(std::vector<std::string>::iterator i=jobLines_.begin(); i!=jobLines_.end(); ++i) {
-
- string::size_type ecfmicro_pos = (*i).find(ecfMicro);
- if ( ecfmicro_pos == 0) {
-
- if ((*i).find(T_MANUAL) == 1) { pp_stack.push_back(MANUAL); continue; }
- if ((*i).find(T_COMMENT) == 1) { pp_stack.push_back(COMMENT); continue; }
- if ((*i).find(T_END) == 1) {
- if (pp_stack.empty()) throw std::runtime_error("EcfFile::remove_nopp_end_tokens: failed unpaired %end");
- int last_directive = pp_stack.back(); pp_stack.pop_back();
- if (last_directive == NOPP) {
- nopp = false;
- jobLines_.erase( i-- ); // remove %end associated with %nopp
- erase = false;
- }
- continue;
- }
- if ((*i).find(T_NOOP) == 1) {
- pp_stack.push_back(NOPP); nopp = true;
- jobLines_.erase( i-- ); // remove %nopp
- if (erase) {
- std::stringstream ss; ss << "Embedded nopp are not allowed " << script_path_or_cmd_;
- throw std::runtime_error("EcfFile::remove_nopp_end_tokens: failed " + ss.str());
- }
- erase = true;
- continue;
- }
- if (!nopp && (*i).find(T_ECFMICRO) == 1) { // %ecfmicro #
-
- tokens.clear();
- Str::split( *i, tokens );
- if (tokens.size() < 2) {
- std::stringstream ss;
- ss << "ecfmicro does not have a replacement character, in " << script_path_or_cmd_;
- throw std::runtime_error("EcfFile::remove_nopp_end_tokens: failed " + ss.str());
- }
-
- ecfMicro = tokens[1]; // override ecfMicro char
- jobLines_.erase( i-- ); // remove %ecfmicro &
- continue;
- }
- }
- }
-
- if (erase) {
- std::stringstream ss;
- ss << "Unterminated nopp. Matching 'end' is missing, in " << script_path_or_cmd_;
- throw std::runtime_error("EcfFile::remove_nopp_end_tokens: failed " + ss.str());
- }
-}
-
-int EcfFile::countEcfMicro(const std::string& line, const std::string& ecfMicro)
-{
- if (line.find("#") != string::npos) {
- // ignore ecfmicro character in comments
- return 0;
- }
-
- /// Pound char could be more than one char ?
- int count = 0;
- if ( !ecfMicro.empty()) {
- const char theChar = ecfMicro[0];
- size_t end = line.size();
- for(size_t i = 0; i < end; ++i) {
- if (line[i] == theChar) {
- count++;
- }
- }
- }
- // cerr << "line " << line << " count = " << count << "\n";
- return count;
-}
-
-void EcfFile::dump_expanded_script_file(size_t i, const std::vector<std::string>& lines)
-{
-#ifdef DEBUG_PRE_PROCESS
- if (i != 0) std::cout << "\nSee file tmp.ecf around line number " << i-1 << "\n";
- std::string err;
- if (!File::create("tmp" + get_extn(),lines,err)) std::cout << "Could not create file tmp.ecf\n";
-#endif
-}
-
-/// returns the extension, i.e for task->.ecf for alias->.usr
-const std::string& EcfFile::get_extn() const
-{
- Submittable* task_or_alias = node_->isSubmittable();
- if (task_or_alias) return task_or_alias->script_extension();
- else {
- std::stringstream ss; ss << "EcfFile::get_extn(): Can only return extension for task/alias but found " << node_->debugNodePath();
- throw std::runtime_error(ss.str());
- }
- return Str::EMPTY();
-}
diff --git a/ecflow_4_0_7/ANode/src/EcfFile.hpp b/ecflow_4_0_7/ANode/src/EcfFile.hpp
deleted file mode 100644
index 2f3b002..0000000
--- a/ecflow_4_0_7/ANode/src/EcfFile.hpp
+++ /dev/null
@@ -1,107 +0,0 @@
-#ifndef ECF_FILE_HPP_
-#define ECF_FILE_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #23 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include "NodeFwd.hpp"
-
-/// This class is used in the pre-processing of files( .ecf or .usr or .man typically)
-/// It is used to to create the job file.
-///
-/// Please note the %manual is only created on request from the file cmd.
-/// Even then it is extracted as a string. i.e. no .man file is
-/// created. This is left to the client.
-/// When returning the manual we pre-process the files first
-///
-/// However for testing purpose this capability may be retained.
-class EcfFile {
-public:
- /// use default copy constructor, assignment, destructor
- /// ECF_FETCH/SMSFETCH is mainly used by research. i.e to obtain scripts and includes
- /// from the version control system. This has not been implemented yet.
- EcfFile(Node*, const std::string& path_to_script_or_fetch_cmd, bool fetchCommand = false);
-
- // The path to the ecf file, empty path means that ecf file could not be located
- const std::string& path() const { return script_path_or_cmd_;}
-
- /// This function will return the contents of %manual -> %end for the input file
- /// It will pre-process the file, then extract the manual form all the pre-processed files
- /// Will throw std::runtime_error for errors
- void manual(std::string& theManual);
-
- /// returns the script
- /// Will throw std::runtime_error for errors
- void script(std::string& theScript) const;
-
- /// Create the job file from with script of a task or alias.
- /// Note: the location of the ecf file may not be the same as the job file
- /// For creating the job we must use ECF_JOB
- ///
- /// _IF_ ECF_CLIENT is specified provide Special support for migration. TEST ONLY
- /// The variable ECF_CLIENT is used to specify the path to client exe.
- /// This is then used to replace smsinit,smscomplete, smsevent,smsmeter.smslabel,smsabort
- /// This function will start the pre processing
- /// Will throw std::runtime_error for errors
- const std::string& create_job( JobsParam&);
-
- /// Process the script file, to add all the used variables, add the start of the file
- /// between %comment %end, The augmented script is returned in file_with_used_variables
- /// Will throw std::runtime_error for errors
- void edit_used_variables(std::string& file_with_used_variables);
-
- /// Pre-processing involves include expansion and variable substitution
- /// Will throw std::runtime_error if pre processing fails
- void pre_process(std::string& pre_processed_file);
- void pre_process(std::vector<std::string> & user_edit_file, std::string& pre_processed_file);
-
- /// Searches for the first %comment, then extracts all variables of the form
- /// <name> = <value>
- /// and places into map
- static void extract_used_variables(NameValueMap& used_variables_as_map,const std::vector<std::string> &script_lines);
-
-private:
- enum Type { SCRIPT, INCLUDE, MANUAL, COMMENT };
- static std::string fileType(Type);
-
- bool open_script_file(const std::string& file, Type, std::vector<std::string>& lines, std::string& errormsg) const;
- bool preProcess(std::vector<std::string>& script_lines, std::string& errormsg);
- bool replaceSmsChildCmdsWithEcf(const std::string& clientPath, std::string& errormsg);
- std::string getIncludedFilePath( const std::string& include, const std::string& line, std::string& errormsg);
- void variableSubstituition(JobsParam&);
- const std::string& doCreateJobFile(JobsParam&) const;
- bool doCreateManFile(std::string& errormsg);
- bool extractManual(const std::vector< std::string >& lines, std::vector< std::string >& theManualLines, std::string& errormsg) const;
- void removeCommentAndManual();
- void remove_nopp_end_tokens();
-
- static int countEcfMicro(const std::string& line, const std::string& ecfMicro);
- static void dump_expanded_script_file(size_t i, const std::vector<std::string>& lines); // for DEBUG
-
- /// returns the extension, i.e for task->.ecf for alias->.usr, will throw if node_ is not task or alias
- const std::string& get_extn() const;
-
-/// User edit functions:
- void get_used_variables(std::string& used_variables) const;
- bool get_used_variables(NameValueMap& used_variables, std::string& errorMsg) const;
- void doCreateUsrFile() const;
-
- Node* node_; // Task or Alias or Container when pre-processing the man files
- std::string ecfMicroCache_; // cache value of ECF_MICRO
- std::string script_path_or_cmd_; // path to .ecf, .usr file or command
- mutable std::string job_size_; // to be placed in log file during job submission
- //bool fetchCommand_; // script is to be extracted form version management repository. Not used !!!
- std::vector<std::string> jobLines_; // Lines that will form the job file.
-};
-
-#endif
diff --git a/ecflow_4_0_7/ANode/src/ExprAst.cpp b/ecflow_4_0_7/ANode/src/ExprAst.cpp
deleted file mode 100644
index 387e8fa..0000000
--- a/ecflow_4_0_7/ANode/src/ExprAst.cpp
+++ /dev/null
@@ -1,1238 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #57 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <vector>
-#include <boost/foreach.hpp>
-
-#include "ExprAst.hpp"
-#include "Indentor.hpp"
-#include "ExprAstVisitor.hpp"
-#include "Node.hpp"
-#include "Log.hpp"
-#include "Str.hpp"
-
-using namespace ecf;
-using namespace std;
-
-////////////////////////////////////////////////////////////////////////////////////
-
-Ast::~Ast() {}
-
-////////////////////////////////////////////////////////////////////////////////////
-
-AstTop::~AstTop() { delete root_;}
-
-void AstTop::accept(ExprAstVisitor& v)
-{
- v.visitTop(this);
- root_->accept(v);
-}
-
-AstTop* AstTop::clone() const
-{
- AstTop* top = new AstTop();
- top->addChild( root_->clone() );
- return top;
-}
-
-bool AstTop::evaluate() const
-{
- if (root_) {
- return root_->evaluate();
- }
-
- LOG_ASSERT(false,"AstTop::evaluate(): assert failed, AST top has no root/children");
- return false;
-}
-
-bool AstTop::check(std::string& error_msg) const
-{
- if (root_) {
- return root_->check(error_msg);
- }
- return true;
-}
-
-std::ostream& AstTop::print(std::ostream& os) const
-{
- Indentor in;
- Indentor::indent(os) << "# AST\n";
- if (root_) {
- Indentor in;
- return root_->print(os);
- }
- return os;
-}
-
-void AstTop::print_flat(std::ostream& os,bool add_bracket) const
-{
- if (root_) {
- root_->print_flat(os,add_bracket);
- }
-}
-
-//#define DEBUG_WHY 1
-bool AstTop::why(std::string& theReasonWhy) const
-{
- if (evaluate()) {
-#ifdef DEBUG_WHY
- std::cout << " AstTop::why evaluate returning\n";
-#endif
- return false;
- }
- return root_->why(theReasonWhy);
-}
-
-std::string AstTop::expression(bool why) const
-{
- std::string ret = exprType_;
- if (root_) {
- ret += " ";
- ret += root_->expression(why);
- }
- return ret;
-}
-
-void AstTop::setParentNode(Node* p)
-{
- if (root_) root_->setParentNode(p);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////
-
-AstRoot::~AstRoot() {
- delete left_;
- delete right_;
- left_ = 0;
- right_ = 0;
-}
-
-void AstRoot::accept(ExprAstVisitor& v)
-{
- v.visitRoot(this);
- left_->accept(v);
- if (right_) right_->accept(v); // right_ is empty for Not
-}
-
-bool AstRoot::check(std::string& error_msg) const
-{
- if (left_ && !left_->check(error_msg)) return false;
- if (right_ && !right_->check(error_msg)) return false;
- return true;
-}
-
-void AstRoot::addChild( Ast* n )
-{
- LOG_ASSERT(n,"");
-
- if ( !left_ ) {
- left_ = n;
- return;
- }
- if ( !right_ ) {
- right_ = n;
- return;
- }
-
- LOG_ASSERT(false,"AstRoot::addChild: assert failed: root already has left and right children\n");
-}
-
-std::ostream& AstRoot::print( std::ostream& os ) const {
- if (left_->isRoot()) {
- Indentor in;
- left_->print( os );
- }
- else left_->print( os );
-
- if (right_) { // right_ is empty for Not
- if (right_->isRoot()) {
- Indentor in;
- right_->print( os );
- }
- else right_->print( os ); ;
- }
- return os;
-}
-
-bool AstRoot::why(std::string& theReasonWhy) const
-{
- if (evaluate()) {
-#ifdef DEBUG_WHY
- std::cout << " AstRoot::why evaluates returning\n";
-#endif
- return false;
- }
-
- theReasonWhy = "expression ";
- theReasonWhy += expression(true); // provide additional state
- theReasonWhy += " does not evaluate";
-#ifdef DEBUG_WHY
- std::cout << " AstRoot::why reason = " << theReasonWhy << "\n";
-#endif
- return true;
-}
-
-void AstRoot::setParentNode(Node* p)
-{
- if (left_) left_->setParentNode(p);
- if (right_) right_->setParentNode(p);
-}
-
-////////////////////////////////////////////////////////////////////////////////////
-
-void AstNot::accept(ExprAstVisitor& v)
-{
- AstRoot::accept(v);
- v.visitNot(this);
-}
-
-AstNot* AstNot::clone() const
-{
- AstNot* ast = new AstNot();
- if (left_) ast->addChild( left_->clone() );
- return ast;
-}
-
-std::ostream& AstNot::print( std::ostream& os ) const {
- Indentor::indent( os ) << "# NOT evaluate(" << evaluate() << ")";
- if (right_) os << " # ERROR has right_";
- os << "\n";
- return AstRoot::print( os );
-}
-
-void AstNot::print_flat( std::ostream& os,bool add_bracket) const {
- os << "! ";
- if (left_) {
- if (add_bracket) os << "(";
- left_->print_flat(os,add_bracket);
- if (add_bracket) os << ")";
- }
-}
-
-std::string AstNot::expression(bool why) const
-{
- std::string ret = "NOT ";
- ret += left_->expression(why);
- return ret;
-}
-////////////////////////////////////////////////////////////////////////////////////
-
-void AstPlus::accept(ExprAstVisitor& v)
-{
- AstRoot::accept(v);
- v.visitPlus(this);
-}
-
-AstPlus* AstPlus::clone() const
-{
- AstPlus* ast = new AstPlus();
- if (left_) ast->addChild( left_->clone() );
- if (right_) ast->addChild( right_->clone() );
- return ast;
-}
-
-std::ostream& AstPlus::print( std::ostream& os ) const {
- Indentor::indent( os ) << "# PLUS value(" << value() << ")";
- if (!left_) os << " # ERROR has no left_";
- if (!right_) os << " # ERROR has no right_";
- os << "\n";
- return AstRoot::print( os );
-}
-
-void AstPlus::print_flat(std::ostream& os,bool add_bracket) const {
- if (add_bracket) os << "(";
- if (left_) left_->print_flat(os,add_bracket);
- os << " + ";
- if (right_) right_->print_flat(os,add_bracket);
- if (add_bracket) os << ")";
-}
-
-std::string AstPlus::expression(bool why) const
-{
- std::string ret;
- if (left_) ret += left_->expression(why);
- ret += " + ";
- if (right_) ret += right_->expression(why);
- return ret;
-}
-
-////////////////////////////////////////////////////////////////////////////////////
-
-void AstMinus::accept(ExprAstVisitor& v)
-{
- AstRoot::accept(v);
- v.visitMinus(this);
-}
-
-AstMinus* AstMinus::clone() const
-{
- AstMinus* ast = new AstMinus();
- if (left_) ast->addChild( left_->clone() );
- if (right_) ast->addChild( right_->clone() );
- return ast;
-}
-
-std::ostream& AstMinus::print( std::ostream& os ) const {
- Indentor::indent( os ) << "# MINUS value(" << value() << ")";
- if (!left_) os << " # ERROR has no left_";
- if (!right_) os << " # ERROR has no right_";
- os << "\n";
- return AstRoot::print( os );
-}
-
-void AstMinus::print_flat(std::ostream& os,bool add_bracket) const {
- if (add_bracket) os << "(";
- if (left_) left_->print_flat(os,add_bracket);
- os << " - ";
- if (right_) right_->print_flat(os,add_bracket);
- if (add_bracket) os << ")";
-}
-
-std::string AstMinus::expression(bool why) const
-{
- std::string ret;
- if (left_) ret += left_->expression(why);
- ret += " - ";
- if (right_) ret += right_->expression(why);
- return ret;
-}
-
-////////////////////////////////////////////////////////////////////////////////////
-
-void AstDivide::accept(ExprAstVisitor& v)
-{
- AstRoot::accept(v);
- v.visitDivide(this);
-}
-
-AstDivide* AstDivide::clone() const
-{
- AstDivide* ast = new AstDivide();
- if (left_) ast->addChild( left_->clone() );
- if (right_) ast->addChild( right_->clone() );
- return ast;
-}
-
-bool AstDivide::check(std::string& error_msg) const
-{
- if (right_ && right_->value() == 0) {
- error_msg = "Divide by zero in trigger expression";
- return false;
- }
- return true;
-}
-
-int AstDivide::value() const {
- if (right_->value() == 0) {
- log(Log::ERR,"Divide by zero in trigger/complete expression");
- return 0;
- }
- return (left_->value() / right_->value()) ;
-}
-
-std::ostream& AstDivide::print( std::ostream& os ) const {
- Indentor::indent( os ) << "# DIVIDE value(" << value() << ")";
- if (!left_) os << " # ERROR has no left_";
- if (!right_) os << " # ERROR has no right_";
- os << "\n";
- return AstRoot::print( os );
-}
-
-void AstDivide::print_flat(std::ostream& os,bool add_bracket) const {
- if (add_bracket) os << "(";
- if (left_) left_->print_flat(os,add_bracket);
- os << " / ";
- if (right_) right_->print_flat(os,add_bracket);
- if (add_bracket) os << ")";
-}
-
-std::string AstDivide::expression(bool why) const
-{
- std::string ret;
- if (left_) ret += left_->expression(why);
- ret += " / ";
- if (right_) ret += right_->expression(why);
- return ret;
-}
-
-////////////////////////////////////////////////////////////////////////////////////
-
-void AstMultiply::accept(ExprAstVisitor& v)
-{
- AstRoot::accept(v);
- v.visitMultiply(this);
-}
-
-AstMultiply* AstMultiply::clone() const
-{
- AstMultiply* ast = new AstMultiply();
- if (left_) ast->addChild( left_->clone() );
- if (right_) ast->addChild( right_->clone() );
- return ast;
-}
-
-std::ostream& AstMultiply::print( std::ostream& os ) const {
- Indentor::indent( os ) << "# MULTIPLY value(" << value() << ")";
- if (!left_) os << " # ERROR has no left_";
- if (!right_) os << " # ERROR has no right_";
- os << "\n";
- return AstRoot::print( os );
-}
-
-void AstMultiply::print_flat(std::ostream& os,bool add_bracket) const {
- if (add_bracket) os << "(";
- if (left_) left_->print_flat(os,add_bracket);
- os << " * ";
- if (right_) right_->print_flat(os,add_bracket);
- if (add_bracket) os << ")";
-}
-
-std::string AstMultiply::expression(bool why) const
-{
- std::string ret;
- if (left_) ret += left_->expression(why);
- ret += " * ";
- if (right_) ret += right_->expression(why);
- return ret;
-}
-
-////////////////////////////////////////////////////////////////////////////////////
-
-void AstModulo::accept(ExprAstVisitor& v)
-{
- AstRoot::accept(v);
- v.visitModulo(this);
-}
-
-AstModulo* AstModulo::clone() const
-{
- AstModulo* ast = new AstModulo();
- if (left_) ast->addChild( left_->clone() );
- if (right_) ast->addChild( right_->clone() );
- return ast;
-}
-
-bool AstModulo::check(std::string& error_msg) const
-{
- if (right_ && right_->value() == 0) {
- error_msg = "Modulo by zero in trigger expression";
- return false;
- }
- return true;
-}
-
-int AstModulo::value() const
-{
- if (right_->value() == 0) {
- log(Log::ERR,"Modulo by zero in trigger/complete expression");
- return 0;
- }
- return (left_->value() % right_->value());
-}
-
-std::ostream& AstModulo::print( std::ostream& os ) const {
- Indentor::indent( os ) << "# Modulo value(" << value() << ")";
- if (!left_) os << " # ERROR has no left_";
- if (!right_) os << " # ERROR has no right_";
- os << "\n";
- return AstRoot::print( os );
-}
-
-void AstModulo::print_flat(std::ostream& os,bool add_bracket) const {
- if (add_bracket) os << "(";
- if (left_) left_->print_flat(os,add_bracket);
- os << " % ";
- if (right_) right_->print_flat(os,add_bracket);
- if (add_bracket) os << ")";
-}
-
-std::string AstModulo::expression(bool why) const
-{
- std::string ret;
- if (left_) ret += left_->expression(why);
- ret += " % ";
- if (right_) ret += right_->expression(why);
- return ret;
-}
-
-////////////////////////////////////////////////////////////////////////////////////
-
-void AstAnd::accept(ExprAstVisitor& v)
-{
- AstRoot::accept(v);
- v.visitAnd(this);
-}
-
-AstAnd* AstAnd::clone() const
-{
- AstAnd* ast = new AstAnd();
- if (left_) ast->addChild( left_->clone() );
- if (right_) ast->addChild( right_->clone() );
- return ast;
-}
-
-std::ostream& AstAnd::print( std::ostream& os ) const {
- Indentor::indent( os ) << "# AND evaluate(" << evaluate() << ")";
- if (!left_) os << " # ERROR has no left_";
- if (!right_) os << " # ERROR has no right_";
- os << "\n";
- return AstRoot::print( os );
-}
-
-void AstAnd::print_flat(std::ostream& os,bool add_bracket) const {
- if (add_bracket) os << "(";
- if (left_) left_->print_flat(os,add_bracket);
- os << " and ";
- if (right_) right_->print_flat(os,add_bracket);
- if (add_bracket) os << ")";
-}
-
-std::string AstAnd::expression(bool why) const
-{
- std::string ret("(");
- if (left_) ret += left_->expression(why);
- ret += " AND ";
- if (right_) ret += right_->expression(why);
- ret += ")";
- return ret;
-}
-
-////////////////////////////////////////////////////////////////////////////////////
-
-void AstOr::accept(ExprAstVisitor& v)
-{
- AstRoot::accept(v);
- v.visitOr(this);
-}
-
-AstOr* AstOr::clone() const
-{
- AstOr* ast = new AstOr();
- if (left_) ast->addChild( left_->clone() );
- if (right_) ast->addChild( right_->clone() );
- return ast;
-}
-
-std::ostream& AstOr::print( std::ostream& os ) const {
- Indentor::indent( os ) << "# OR evaluate(" << evaluate() << ")";
- if (!left_) os << " # ERROR has no left_";
- if (!right_) os << " # ERROR has no right_";
- os << "\n";
- return AstRoot::print( os );
-}
-
-void AstOr::print_flat(std::ostream& os,bool add_bracket) const {
- if (add_bracket) os << "(";
- if (left_) left_->print_flat(os,add_bracket);
- os << " or ";
- if (right_) right_->print_flat(os,add_bracket);
- if (add_bracket) os << ")";
-}
-
-std::string AstOr::expression(bool why) const
-{
- std::string ret("(");
- if (left_) ret += left_->expression(why);
- ret += " OR ";
- if (right_) ret += right_->expression(why);
- ret += ")";
- return ret;
-}
-
-////////////////////////////////////////////////////////////////////////////////////
-
-void AstEqual::accept(ExprAstVisitor& v)
-{
- AstRoot::accept(v);
- v.visitEqual(this);
-}
-
-AstEqual* AstEqual::clone() const
-{
- AstEqual* ast = new AstEqual();
- if (left_) ast->addChild( left_->clone() );
- if (right_) ast->addChild( right_->clone() );
- return ast;
-}
-
-std::ostream& AstEqual::print( std::ostream& os ) const {
- Indentor::indent( os ) << "# EQUAL evaluate(" << evaluate() << ")";
- if (!left_) os << " # ERROR has no left_";
- if (!right_) os << " # ERROR has no right_";
- os << "\n";
- return AstRoot::print( os );
-}
-
-void AstEqual::print_flat(std::ostream& os,bool add_bracket) const {
- if (add_bracket) os << "(";
- if (left_) left_->print_flat(os,add_bracket);
- os << " == ";
- if (right_) right_->print_flat(os,add_bracket);
- if (add_bracket) os << ")";
-}
-
-std::string AstEqual::expression(bool why) const
-{
- std::string ret("(");
- if (left_) ret += left_->expression(why);
- ret += " == ";
- if (right_) ret += right_->expression(why);
- ret += ")";
- return ret;
-}
-
-////////////////////////////////////////////////////////////////////////////////////
-
-void AstNotEqual::accept(ExprAstVisitor& v)
-{
- AstRoot::accept(v);
- v.visitNotEqual(this);
-}
-AstNotEqual* AstNotEqual::clone() const
-{
- AstNotEqual* ast = new AstNotEqual();
- if (left_) ast->addChild( left_->clone() );
- if (right_) ast->addChild( right_->clone() );
- return ast;
-}
-
-std::ostream& AstNotEqual::print( std::ostream& os ) const {
- Indentor::indent( os ) << "# NOT_EQUAL evaluate(" << evaluate() << ")";
- if (!left_) os << " # ERROR has no left_";
- if (!right_) os << " # ERROR has no right_";
- os << "\n";
- return AstRoot::print( os );
-}
-
-void AstNotEqual::print_flat(std::ostream& os,bool add_bracket) const {
- if (add_bracket) os << "(";
- if (left_) left_->print_flat(os,add_bracket);
- os << " != ";
- if (right_) right_->print_flat(os,add_bracket);
- if (add_bracket) os << ")";
-}
-
-std::string AstNotEqual::expression(bool why) const
-{
- std::string ret("(");
- if (left_) ret += left_->expression(why);
- ret += " != ";
- if (right_) ret += right_->expression(why);
- ret += ")";
- return ret;
-}
-
-////////////////////////////////////////////////////////////////////////////////////
-
-void AstLessEqual::accept(ExprAstVisitor& v)
-{
- AstRoot::accept(v);
- v.visitLessEqual(this);
-}
-AstLessEqual* AstLessEqual::clone() const
-{
- AstLessEqual* ast = new AstLessEqual();
- if (left_) ast->addChild( left_->clone() );
- if (right_) ast->addChild( right_->clone() );
- return ast;
-}
-
-std::ostream& AstLessEqual::print( std::ostream& os ) const {
- Indentor::indent( os ) << "# LESS_EQUAL evaluate(" << evaluate() << ")";
- if (!left_) os << " # ERROR has no left_";
- if (!right_) os << " # ERROR has no right_";
- os << "\n";
- return AstRoot::print( os );
-}
-void AstLessEqual::print_flat(std::ostream& os,bool add_bracket) const {
- if (add_bracket) os << "(";
- if (left_) left_->print_flat(os,add_bracket);
- os << " <= ";
- if (right_) right_->print_flat(os,add_bracket);
- if (add_bracket) os << ")";
-}
-std::string AstLessEqual::expression(bool why) const
-{
- std::string ret("(");
- if (left_) ret += left_->expression(why);
- ret += " <= ";
- if (right_) ret += right_->expression(why);
- ret += ")";
- return ret;
-}
-
-////////////////////////////////////////////////////////////////////////////////////
-
-void AstGreaterEqual::accept(ExprAstVisitor& v)
-{
- AstRoot::accept(v);
- v.visitGreaterEqual(this);
-}
-AstGreaterEqual* AstGreaterEqual::clone() const
-{
- AstGreaterEqual* ast = new AstGreaterEqual();
- if (left_) ast->addChild( left_->clone() );
- if (right_) ast->addChild( right_->clone() );
- return ast;
-}
-
-std::ostream& AstGreaterEqual::print( std::ostream& os ) const {
- Indentor::indent( os ) << "# GREATER_EQUAL evaluate(" << evaluate() << ")";
- if (!left_) os << " # ERROR has no left_";
- if (!right_) os << " # ERROR has no right_";
- os << "\n";
- return AstRoot::print( os );
-}
-void AstGreaterEqual::print_flat(std::ostream& os,bool add_bracket) const {
- if (add_bracket) os << "(";
- if (left_) left_->print_flat(os,add_bracket);
- os << " >= ";
- if (right_) right_->print_flat(os,add_bracket);
- if (add_bracket) os << ")";
-}
-
-std::string AstGreaterEqual::expression(bool why) const
-{
- std::string ret("(");
- if (left_) ret += left_->expression(why);
- ret += " >= ";
- if (right_) ret += right_->expression(why);
- ret += ")";
- return ret;
-}
-
-////////////////////////////////////////////////////////////////////////////////////
-
-void AstGreaterThan::accept(ExprAstVisitor& v)
-{
- AstRoot::accept(v);
- v.visitGreaterThan(this);
-}
-AstGreaterThan* AstGreaterThan::clone() const
-{
- AstGreaterThan* ast = new AstGreaterThan();
- if (left_) ast->addChild( left_->clone() );
- if (right_) ast->addChild( right_->clone() );
- return ast;
-}
-
-std::ostream& AstGreaterThan::print( std::ostream& os ) const {
- Indentor::indent( os ) << "# GREATER_THAN evaluate(" << evaluate() << ")";
- if (!left_) os << " # ERROR has no left_";
- if (!right_) os << " # ERROR has no right_";
- os << "\n";
- return AstRoot::print( os );
-}
-void AstGreaterThan::print_flat(std::ostream& os,bool add_bracket) const {
- if (add_bracket) os << "(";
- if (left_) left_->print_flat(os,add_bracket);
- os << " > ";
- if (right_) right_->print_flat(os,add_bracket);
- if (add_bracket) os << ")";
-}
-
-std::string AstGreaterThan::expression(bool why) const
-{
- std::string ret("(");
- if (left_) ret += left_->expression(why);
- ret += " > ";
- if (right_) ret += right_->expression(why);
- ret += ")";
- return ret;
-}
-
-////////////////////////////////////////////////////////////////////////////////////
-
-void AstLessThan::accept(ExprAstVisitor& v)
-{
- AstRoot::accept(v);
- v.visitLessThan(this);
-}
-
-AstLessThan* AstLessThan::clone() const
-{
- AstLessThan* ast = new AstLessThan();
- if (left_) ast->addChild( left_->clone() );
- if (right_) ast->addChild( right_->clone() );
- return ast;
-}
-
-std::ostream& AstLessThan::print( std::ostream& os ) const {
- Indentor::indent( os ) << "# LESS_THAN evaluate(" << evaluate() << ")";
- if (!left_) os << " # ERROR has no left_";
- if (!right_) os << " # ERROR has no right_";
- os << "\n";
- return AstRoot::print( os );
-}
-void AstLessThan::print_flat(std::ostream& os,bool add_bracket) const {
- if (add_bracket) os << "(";
- if (left_) left_->print_flat(os,add_bracket);
- os << " < ";
- if (right_) right_->print_flat(os,add_bracket);
- if (add_bracket) os << ")";
-}
-std::string AstLessThan::expression(bool why) const
-{
- std::string ret("(");
- if (left_) ret += left_->expression(why);
- ret += " < ";
- if (right_) ret += right_->expression(why);
- ret += ")";
- return ret;
-}
-
-////////////////////////////////////////////////////////////////////////////////////
-
-void AstLeaf::accept(ExprAstVisitor& v)
-{
- v.visitLeaf(this);
-}
-
-///////////////////////////////////////////////////////////////////////////////////
-void AstInteger::accept(ExprAstVisitor& v)
-{
- v.visitInteger(this); // Not calling base
-}
-
-AstInteger* AstInteger::clone() const
-{
- AstInteger* ast = new AstInteger(value_);
- return ast;
-}
-
-std::ostream& AstInteger::print( std::ostream& os ) const {
- Indentor in;
- return Indentor::indent( os ) << "# LEAF_INTEGER " << value() << "\n";
-}
-
-void AstInteger::print_flat(std::ostream& os,bool /*add_bracket*/) const {
- os << value_;
-}
-
-std::string AstInteger::expression(bool /*why*/) const
-{
- std::stringstream ss;
- ss << value();
- return ss.str();
-}
-
-//////////////////////////////////////////////////////////////////////////////////
-
-void AstString::accept(ExprAstVisitor& v)
-{
- v.visitString(this); // Not calling base
-}
-
-AstString* AstString::clone() const
-{
- return new AstString(value_);
-}
-
-std::ostream& AstString::print( std::ostream& os ) const {
- Indentor in;
- return Indentor::indent( os ) << "# LEAF_STRING " << value_ << " value() = " << value() << "\n";
-}
-void AstString::print_flat(std::ostream& os,bool /*add_bracket*/) const {
- os << value_;
-}
-
-std::string AstString::expression(bool /*why*/) const
-{
- return value_;
-}
-
-int AstString::value() const
-{
- if (value_ == Event::SET()) { // allow us to compare with a event and a string
- return 1;
- }
- if (value_ == Event::CLEAR()) { // allow us to compare with a event and a string
- return 0;
- }
- // see if the value is convertible to a integer
- return Str::to_int( value_, 0/* value to return if conversion fails*/);
-}
-
-////////////////////////////////////////////////////////////////////////////////////
-
-void AstNodeState::accept(ExprAstVisitor& v)
-{
- v.visitNodeState(this); // Not calling base
-}
-
-AstNodeState* AstNodeState::clone() const
-{
- return new AstNodeState(state_);
-}
-
-std::ostream& AstNodeState::print( std::ostream& os ) const {
- Indentor in;
- return Indentor::indent( os ) << "# LEAF_NODE_STATE "
- << DState::toString( state_ ) << "(" << value() << ")\n";
-}
-
-void AstNodeState::print_flat(std::ostream& os,bool /*add_bracket*/) const {
- os << DState::toString( state_ ) ;
-}
-
-std::string AstNodeState::expression(bool why) const
-{
- return DState::toString(state_);
-}
-
-////////////////////////////////////////////////////////////////////////////////////
-
-void AstEventState::accept(ExprAstVisitor& v)
-{
- v.visitEventState(this); // Not calling base
-}
-
-AstEventState* AstEventState::clone() const
-{
- return new AstEventState(state_);
-}
-
-std::ostream& AstEventState::print( std::ostream& os ) const {
- Indentor in;
- return Indentor::indent( os ) << "# LEAF_EVENT_STATE " << state_ << "\n";
-}
-
-void AstEventState::print_flat(std::ostream& os,bool /*add_bracket*/) const {
- if (state_) os << Event::SET();
- else os << Event::CLEAR();
-}
-
-std::string AstEventState::expression(bool /*why*/) const
-{
- if (state_) return Event::SET();
- return Event::CLEAR();
-}
-
-////////////////////////////////////////////////////////////////////////////////////
-
-void AstNode::accept(ExprAstVisitor& v)
-{
- v.visitNode(this); // Not calling base
-}
-
-AstNode* AstNode::clone() const
-{
- return new AstNode(nodePath_);
-}
-
-DState::State AstNode::state() const
-{
- // This function is called hundreds of millions of times
- Node* refNode = referencedNode(); // call once, could be expensive
- if (refNode) return refNode->dstate();
- return DState::UNKNOWN;
-}
-
-Node* AstNode::referencedNode() const
-{
- // This function is called hundreds of millions of times
- // One of the server CPU **bottleneck's** is weak ptr locking
- // Note: gprof does not report on in-lined functions ?
- Node* ref = get_ref_node();
- if ( ref ) {
- return ref;
- }
- if ( parentNode_ ) {
- std::string errorMsg;
- ref_node_ = parentNode_->findReferencedNode( nodePath_, errorMsg );
- return get_ref_node(); // can be NULL
- }
- return NULL;
-}
-
-Node* AstNode::referencedNode(std::string& errorMsg) const
-{
- Node* ref = get_ref_node();
- if ( ref ) {
- return ref;
- }
- if ( parentNode_ ) {
- ref_node_ = parentNode_->findReferencedNode( nodePath_, errorMsg );
- return get_ref_node(); // can be NULL
- }
- return NULL;
-}
-
-std::ostream& AstNode::print( std::ostream& os ) const {
-
- Node* refNode = referencedNode(); // Only call once
- Indentor in;
-
- if ( refNode ) {
- Indentor::indent( os ) << "# LEAF_NODE node_(Found) nodePath_('" << nodePath_ << "') ";
- os << DState::toString( refNode->dstate() ) << "(" << static_cast<int>( refNode->dstate()) << ")\n";
- }
- else {
- Indentor::indent( os ) << "# LEAF_NODE node_(NULL) nodePath_('" << nodePath_ << "') ";
- os << DState::toString( DState::UNKNOWN ) << "(" << static_cast<int>(DState::UNKNOWN) << ")\n";
- }
- return os;
-}
-
-void AstNode::print_flat(std::ostream& os,bool /*add_bracket*/) const {
- os << nodePath_;
-}
-
-std::string AstNode::expression(bool why) const
-{
- if (why) {
- Node* refNode = referencedNode(); // Only call once
- std::string ret = nodePath_;
- if ( refNode ) {
- ret += "(";
- ret += DState::toString( refNode->dstate() );
- ret += ")";
- return ret;
- }
- else {
- ret += "(?";
- ret += DState::toString( DState::UNKNOWN );
- ret += ")";
- }
- return ret;
- }
- return nodePath_;
-}
-
-
-
-////////////////////////////////////////////////////////////////////////////////////
-
-void AstVariable::accept(ExprAstVisitor& v)
-{
- v.visitVariable(this); // Not calling base
-}
-
-AstVariable* AstVariable::clone() const
-{
- return new AstVariable(nodePath_,name_);
-}
-
-int AstVariable::value() const
-{
- VariableHelper varHelper(this);
- return varHelper.value();
-}
-
-int AstVariable::minus(Ast* right) const
-{
- VariableHelper varHelper(this);
- return varHelper.minus(right->value());
-}
-
-int AstVariable::plus(Ast* right) const
-{
- VariableHelper varHelper(this);
- return varHelper.plus(right->value());
-}
-
-std::ostream& AstVariable::print( std::ostream& os ) const
-{
- VariableHelper varHelper(this);
- return varHelper.print(os);
-}
-
-void AstVariable::print_flat(std::ostream& os,bool /*add_bracket*/) const
-{
- os << nodePath_ << Str::COLON() << name_;
-}
-
-std::string AstVariable::expression(bool why) const
-{
- if (why) {
- VariableHelper varHelper(this);
- std::string ret = nodePath_;
- if ( !varHelper.theReferenceNode() ) ret += "(?)";
- ret += Str::COLON();
- ret += name_;
- ret += "(";
-
- std::string varType;
- int theValue;
- varHelper.varTypeAndValue(varType,theValue);
-
- std::stringstream ss; ss << "<type=" << varType << "> <value=" << theValue << ">";
- ret += ss.str();
-
- ret += ")";
- return ret;
- }
- return nodePath_ + Str::COLON() + name_;
-}
-
-Node* AstVariable::referencedNode() const
-{
- Node* ref = get_ref_node();
- if ( ref ) {
- return ref;
- }
- if ( parentNode_ ) {
- std::string ignoredErrorMsg;
- ref_node_ = parentNode_->findReferencedNode( nodePath_, name_, ignoredErrorMsg );
- return get_ref_node(); // can be NULL
- }
- return NULL;
-}
-
-Node* AstVariable::referencedNode(std::string& errorMsg) const
-{
- Node* ref = get_ref_node();
- if ( ref ) {
- return ref;
- }
- if ( parentNode_ ) {
- ref_node_ = parentNode_->findReferencedNode( nodePath_, name_, errorMsg );
- return get_ref_node(); // can be NULL
- }
- return NULL;
-}
-
-
-// ===============================================================================
-// class VariableHelper:
-// ===============================================================================
-VariableHelper::VariableHelper(const AstVariable* astVariable)
-: astVariable_(astVariable), theReferenceNode_(NULL)
-{
- // For *this* constructor we don't care about errors'
- std::string errorMsg;
- theReferenceNode_ = astVariable_->referencedNode( errorMsg );
- if ( !theReferenceNode_ ) {
- // A node can be NULL if :
- // 1/ parentNode is NOT set
- // 2/ when its a extern path. i.e corresponding suite not loaded yet
- return;
- }
- LOG_ASSERT(errorMsg.empty(),""); // when a reference node is found, the error msg should be empty
-}
-
-// ***NOTE*** This constructor is called during AST construction***. i.e AstResolveVisitor
-// ********** It is used to report errors and to Flag whether meter or event is used
-// ********** in a trigger expression for the simulator
-VariableHelper::VariableHelper(const AstVariable* astVariable, std::string& errorMsg)
-: astVariable_(astVariable), theReferenceNode_(NULL)
-{
- // for *this* constructor we want to report errors
- theReferenceNode_ = astVariable_->referencedNode( errorMsg );
- if ( !theReferenceNode_ ) {
- // A node can be NULL if :
- // 1/ parentNode is NOT set
- // 2/ when its a extern path. i.e corresponding suite not loaded yet
- return;
- }
- LOG_ASSERT(errorMsg.empty(),""); // when a reference node is found, the error msg should be empty
-
- // Find in order, event, meter, user variable, repeat, generated variable
- // ALSO: if meter or event mark as used in trigger, for simulator
- if (theReferenceNode_->findExprVariable( astVariable_->name() ) ) {
- return;
- }
-
- std::stringstream ss;
- ss << "From expression Variable " << astVariable_->nodePath() << Str::COLON() << astVariable_->name() ;
- ss << " the referenced node is " << theReferenceNode_->debugNodePath() << "\n";
- errorMsg += ss.str();
- errorMsg += "Could not find event, meter, variable, repeat, or generated variable of name('";
- errorMsg += astVariable_->name();
- errorMsg += "') on node ";
- errorMsg += theReferenceNode_->debugNodePath();
- errorMsg += "\n";
-
- // FAILED to find astVar->name(), for node theReferenceNode on event, meter,
- // user variable, repeat, generated variable
- // SET theReferenceNode_ to NULL, since it does nor reference the Expression variable
- theReferenceNode_ = NULL;
-}
-
-int VariableHelper::value() const
-{
- if ( theReferenceNode_ ) {
- return theReferenceNode_->findExprVariableValue(astVariable_->name());
- }
- return 0;
-}
-
-int VariableHelper::plus(int val) const
-{
- if ( theReferenceNode_ ) {
- return theReferenceNode_->findExprVariableValueAndPlus(astVariable_->name(),val);
- }
- return val;
-}
-
- int VariableHelper::minus(int val) const
- {
- if ( theReferenceNode_ ) {
- return theReferenceNode_->findExprVariableValueAndMinus(astVariable_->name(),val);
- }
- return -val;
- }
-
-void VariableHelper::varTypeAndValue(std::string& varType, int & theValue) const
-{
- if ( theReferenceNode_ ) {
- theValue = theReferenceNode_->findExprVariableValueAndType( astVariable_->name(), varType );
- return;
- }
- varType = "variable-not-found";
- theValue = 0;
-}
-
-std::ostream& VariableHelper::print( std::ostream& os ) const
-{
- Indentor in;
- Indentor::indent( os ) << "# " << astVariable_->nodePath() << Str::COLON() << astVariable_->name();
-
- if ( theReferenceNode_ ) {
- os << " (";
- theReferenceNode_->findExprVariableAndPrint(astVariable_->name(), os);
- os << ")";
- }
- else {
- os << " referencedNode(NULL) nodePath_('" << astVariable_->nodePath() << "') value(0)";
- }
- os << "\n";
- return os;
-}
-
-std::ostream& operator<<( std::ostream& os, const Ast& d){return d.print( os );}
-std::ostream& operator<<( std::ostream& os, const AstTop& d){return d.print( os );}
-std::ostream& operator<<( std::ostream& os, const AstRoot& d ) {return d.print( os );}
-std::ostream& operator<<( std::ostream& os, const AstNot& d ) {return d.print( os );}
-std::ostream& operator<<( std::ostream& os, const AstPlus& d ) {return d.print( os );}
-std::ostream& operator<<( std::ostream& os, const AstMinus& d ) {return d.print( os );}
-std::ostream& operator<<( std::ostream& os, const AstDivide& d ) {return d.print( os );}
-std::ostream& operator<<( std::ostream& os, const AstMultiply& d ) {return d.print( os );}
-std::ostream& operator<<( std::ostream& os, const AstModulo& d ) {return d.print( os );}
-std::ostream& operator<<( std::ostream& os, const AstAnd& d ) {return d.print( os );}
-std::ostream& operator<<( std::ostream& os, const AstOr& d ) {return d.print( os );}
-std::ostream& operator<<( std::ostream& os, const AstEqual& d ) {return d.print( os );}
-std::ostream& operator<<( std::ostream& os, const AstNotEqual& d ) {return d.print( os );}
-std::ostream& operator<<( std::ostream& os, const AstLessEqual& d ) {return d.print( os );}
-std::ostream& operator<<( std::ostream& os, const AstGreaterEqual& d ) {return d.print( os );}
-std::ostream& operator<<( std::ostream& os, const AstGreaterThan& d ) {return d.print( os );}
-std::ostream& operator<<( std::ostream& os, const AstLessThan& d ) {return d.print( os );}
-std::ostream& operator<<( std::ostream& os, const AstLeaf& d ) {return d.print( os );}
-std::ostream& operator<<( std::ostream& os, const AstInteger& d) {return d.print( os );}
-std::ostream& operator<<( std::ostream& os, const AstString& d) {return d.print( os );}
-std::ostream& operator<<( std::ostream& os, const AstNodeState& d) {return d.print( os );}
-std::ostream& operator<<( std::ostream& os, const AstEventState& d) {return d.print( os );}
-std::ostream& operator<<( std::ostream& os, const AstNode& d ) {return d.print( os );}
-std::ostream& operator<<( std::ostream& os, const AstVariable& d ) {return d.print( os );}
diff --git a/ecflow_4_0_7/ANode/src/ExprAst.hpp b/ecflow_4_0_7/ANode/src/ExprAst.hpp
deleted file mode 100644
index fd5fbbf..0000000
--- a/ecflow_4_0_7/ANode/src/ExprAst.hpp
+++ /dev/null
@@ -1,516 +0,0 @@
-#ifndef EXPRAST_HPP_
-#define EXPRAST_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #42 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-// The AST is now demand created, and hence we no longer need to persist it
-
-#include <vector>
-#include <assert.h>
-#include <iostream>
-#include <boost/noncopyable.hpp>
-
-#include "DState.hpp"
-#include "NodeFwd.hpp"
-namespace ecf { class ExprAstVisitor;} // forward declare class
-
-//////////////////////////////////////////////////////////////////////////////////
-class Ast {
-public:
- Ast() {}
- virtual ~Ast();
-
- virtual void accept(ecf::ExprAstVisitor&) = 0;
- virtual Ast* clone() const = 0;
-
- virtual void addChild(Ast*) {}
- virtual Ast* left() const { return NULL;}
- virtual Ast* right() const { return NULL;}
- virtual bool evaluate() const { assert(false); return false;}
- virtual bool isleaf() const { return false; }
- virtual bool isRoot() const { return false; }
- virtual AstTop* isTop() const { return NULL; }
- virtual bool empty() const { return true; }
- virtual int value() const { assert(false); return 0;} // only valid for leaf or operators
- virtual bool check(std::string& error_msg) const { return true; } // check divide or modulo by zero
-
- virtual std::ostream& print(std::ostream&) const = 0;
- virtual void print_flat(std::ostream&,bool add_brackets = false) const = 0; // used for test
- virtual bool why(std::string& /*theReasonWhy*/) const { return false;}
- virtual std::string type() const = 0;
- virtual void exprType(const std::string&) {}
- std::string name() { return expression(false); } /* ABO */
- virtual std::string expression(bool why = false) const = 0; // recreate expression from AST, if why show additional state
-
- // Use for data arithmetic for REPEAT Date, Use default implementation for others
- // Currently *ONLY* works if repeat variable in on LHS
- virtual int minus(Ast* right) const { return (value() - right->value());}
- virtual int plus(Ast* right) const { return (value() + right->value());}
-
- virtual void setParentNode(Node*){} // traverse and set for interested nodes
-};
-
-class AstTop : public Ast {
-public:
- AstTop() : root_(NULL) {}
- virtual ~AstTop();
-
- virtual void accept(ecf::ExprAstVisitor&);
- virtual AstTop* clone() const;
-
- virtual Ast* left() const { return root_;}
- virtual void addChild(Ast* r) { root_ = r;}
- virtual AstTop* isTop() const { return const_cast<AstTop*>(this); }
- virtual bool evaluate() const;
- virtual bool check(std::string& error_msg) const;
-
- virtual bool empty() const { return (root_) ? false : true ; }
- virtual std::ostream& print(std::ostream&) const ;
- virtual void print_flat(std::ostream&,bool add_brackets = false) const;
- virtual bool why(std::string& theReasonWhy) const;
- virtual std::string type() const { return stype();}
- virtual void exprType(const std::string& s) { exprType_ = s;}
- static std::string stype() { return "top";}
- virtual std::string expression(bool why = false) const;
- virtual void setParentNode(Node*);
-
-private:
- Ast* root_;
- std::string exprType_; // trigger or complete
-};
-
-// This if one of AND, OR, == != <= >=
-class AstRoot : public Ast {
-public:
- AstRoot() :left_(NULL), right_(NULL) {}
- virtual ~AstRoot();
-
- virtual bool check(std::string& error_msg) const;
- virtual void accept(ecf::ExprAstVisitor&);
- virtual void addChild(Ast* n);
- virtual Ast* left() const { return left_;}
- virtual Ast* right() const { return right_;}
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool why(std::string& theReasonWhy) const;
- virtual bool isRoot() const { return true;}
- virtual bool empty() const { return (left_ && right_) ? false : true ; }
- virtual void setParentNode(Node*);
-
-protected:
- Ast* left_;
- Ast* right_;
-};
-
-class AstNot : public AstRoot {
-public:
- AstNot() {}
- virtual void accept(ecf::ExprAstVisitor&);
- virtual AstNot* clone() const;
-
- virtual bool evaluate() const { assert(!right_); return ! left_->evaluate();}
- virtual int value() const { assert(!right_); return ! left_->value();}
- virtual std::ostream& print(std::ostream& os) const;
- virtual void print_flat(std::ostream&,bool add_brackets = false) const;
- virtual std::string type() const { return stype();}
- virtual std::string expression(bool why = false) const;
- static std::string stype() { return "not";}
-};
-
-
-class AstPlus : public AstRoot {
-public:
- AstPlus() {}
- virtual void accept(ecf::ExprAstVisitor&);
- virtual AstPlus* clone() const;
-
- virtual bool evaluate() const { return true;}
- virtual int value() const { return left_->plus(right_);}
- virtual std::ostream& print(std::ostream& os) const;
- virtual void print_flat(std::ostream&,bool add_brackets = false) const;
- virtual std::string type() const { return stype();}
- virtual std::string expression(bool why = false) const;
- static std::string stype() { return "plus";}
-};
-
-class AstMinus : public AstRoot {
-public:
- AstMinus() {}
- virtual void accept(ecf::ExprAstVisitor&);
- virtual AstMinus* clone() const;
-
- virtual bool evaluate() const { return true;}
- virtual int value() const { return left_->minus(right_); }
- virtual std::ostream& print(std::ostream& os) const;
- virtual void print_flat(std::ostream&,bool add_brackets = false) const;
- virtual std::string type() const { return stype();}
- virtual std::string expression(bool why = false) const;
- static std::string stype() { return "minus";}
-};
-
-class AstDivide : public AstRoot {
-public:
- AstDivide() {}
- virtual void accept(ecf::ExprAstVisitor&);
- virtual AstDivide* clone() const;
- virtual bool evaluate() const { return true;}
- virtual bool check(std::string& error_msg) const;
- virtual int value() const; // Log error if right hand side has value of zero
- virtual std::ostream& print(std::ostream& os) const;
- virtual void print_flat(std::ostream&,bool add_brackets = false) const;
- virtual std::string type() const { return stype();}
- virtual std::string expression(bool why = false) const;
- static std::string stype() { return "divide";}
-};
-
-class AstMultiply : public AstRoot {
-public:
- AstMultiply() {}
- virtual void accept(ecf::ExprAstVisitor&);
- virtual AstMultiply* clone() const;
- virtual bool evaluate() const { return true;}
- virtual int value() const { return (left_->value() * right_->value());}
- virtual std::ostream& print(std::ostream& os) const;
- virtual void print_flat(std::ostream&,bool add_brackets = false) const;
- virtual std::string type() const { return stype();}
- virtual std::string expression(bool why = false) const;
- static std::string stype() { return "multiply";}
-};
-
-class AstModulo : public AstRoot {
-public:
- AstModulo(){}
- virtual void accept(ecf::ExprAstVisitor&);
- virtual AstModulo* clone() const;
- virtual bool check(std::string& error_msg) const;
- virtual bool evaluate() const { return true;}
- virtual int value() const; // Log error if right hand side has value of zero
- virtual std::ostream& print(std::ostream& os) const;
- virtual void print_flat(std::ostream&,bool add_brackets = false) const;
- virtual std::string type() const { return stype();}
- virtual std::string expression(bool why = false) const;
- static std::string stype() { return "modulo";}
-};
-
-
-class AstAnd : public AstRoot {
-public:
- AstAnd() {}
- virtual void accept(ecf::ExprAstVisitor&);
- virtual AstAnd* clone() const;
- virtual bool evaluate() const { return (left_->evaluate() && right_->evaluate());}
- virtual std::ostream& print(std::ostream& os) const;
- virtual void print_flat(std::ostream&,bool add_brackets = false) const;
- virtual std::string type() const { return stype();}
- virtual std::string expression(bool why = false) const;
- static std::string stype() { return "and";}
-};
-
-class AstOr : public AstRoot {
-public:
- AstOr() {}
- virtual void accept(ecf::ExprAstVisitor&);
- virtual AstOr* clone() const;
- virtual bool evaluate() const { return (left_->evaluate() || right_->evaluate());}
- virtual std::ostream& print(std::ostream& os) const;
- virtual void print_flat(std::ostream&,bool add_brackets = false) const;
- virtual std::string type() const { return stype();}
- virtual std::string expression(bool why = false) const;
- static std::string stype() { return "or";}
-};
-
-class AstEqual : public AstRoot {
-public:
- AstEqual() {}
- virtual void accept(ecf::ExprAstVisitor&);
- virtual AstEqual* clone() const;
- virtual bool evaluate() const { return (left_->value() == right_->value()); }
- virtual std::ostream& print(std::ostream& os) const;
- virtual void print_flat(std::ostream&,bool add_brackets = false) const;
- virtual std::string type() const { return stype();}
- virtual std::string expression(bool why = false) const;
- static std::string stype() { return "equal";}
-};
-
-class AstNotEqual : public AstRoot {
-public:
- AstNotEqual() {}
- virtual void accept(ecf::ExprAstVisitor&);
- virtual AstNotEqual* clone() const;
- virtual bool evaluate() const { return (left_->value() != right_->value()); }
- virtual std::ostream& print(std::ostream& os) const;
- virtual void print_flat(std::ostream&,bool add_brackets = false) const;
- virtual std::string type() const { return stype();}
- virtual std::string expression(bool why = false) const;
- static std::string stype() { return "not-equal";}
-};
-
-class AstLessEqual : public AstRoot {
-public:
- AstLessEqual() {}
- virtual void accept(ecf::ExprAstVisitor&);
- virtual AstLessEqual* clone() const;
- virtual bool evaluate() const { return (left_->value() <= right_->value()); }
- virtual std::ostream& print(std::ostream& os) const;
- virtual void print_flat(std::ostream&,bool add_brackets = false) const;
- virtual std::string type() const { return stype();}
- virtual std::string expression(bool why = false) const;
- static std::string stype() { return "less-equal";}
-};
-
-class AstGreaterEqual : public AstRoot {
-public:
- AstGreaterEqual() {}
- virtual bool evaluate() const { return (left_->value() >= right_->value()); }
- virtual void accept(ecf::ExprAstVisitor&);
- virtual AstGreaterEqual* clone() const;
- virtual std::ostream& print(std::ostream& os) const;
- virtual void print_flat(std::ostream&,bool add_brackets = false) const;
- virtual std::string type() const { return stype();}
- virtual std::string expression(bool why = false) const;
- static std::string stype() { return "greater-equal";}
-};
-
-
-class AstGreaterThan : public AstRoot {
-public:
- AstGreaterThan() {}
-
- virtual bool evaluate() const { return (left_->value() > right_->value()); }
- virtual void accept(ecf::ExprAstVisitor&);
- virtual AstGreaterThan* clone() const;
- virtual std::ostream& print(std::ostream& os) const;
- virtual void print_flat(std::ostream&,bool add_brackets = false) const;
- virtual std::string type() const { return stype();}
- virtual std::string expression(bool why = false) const;
- static std::string stype() { return "greater-than";}
-};
-
-
-class AstLessThan : public AstRoot {
-public:
- AstLessThan() {}
-
- virtual bool evaluate() const { return (left_->value() < right_->value()); }
- virtual void accept(ecf::ExprAstVisitor&);
- virtual AstLessThan* clone() const;
- virtual std::ostream& print(std::ostream& os) const;
- virtual void print_flat(std::ostream&,bool add_brackets = false) const;
- virtual std::string type() const { return stype();}
- virtual std::string expression(bool why = false) const;
- static std::string stype() { return "less-than";}
-};
-
-//=============================================================================================
-/// class AstLeaf
-/// represents Integer, String, Node State, event State, Node, variable
-/// These always represent the right side of the tree
-class AstLeaf : public Ast {
-public:
- AstLeaf() {}
- virtual void accept(ecf::ExprAstVisitor&);
- virtual bool isleaf() const { return true; }
-};
-
-class AstInteger : public AstLeaf {
-public:
- AstInteger(int value) : value_(value) {}
-
- virtual bool evaluate() const { return value_; } // -1 -2 1 2 3 evaluates to true, 0 returns false
- virtual void accept(ecf::ExprAstVisitor&);
- virtual AstInteger* clone() const;
- virtual int value() const { return value_;}
- virtual std::ostream& print(std::ostream& os) const;
- virtual void print_flat(std::ostream&,bool add_brackets = false) const;
- virtual std::string type() const { return stype();}
- virtual std::string expression(bool why = false) const;
- static std::string stype() { return "integer";}
-private:
- int value_;
-};
-
-class AstString : public AstLeaf {
-public:
- AstString(const std::string& s) : value_(s) {}
-
- virtual void accept(ecf::ExprAstVisitor&);
- virtual AstString* clone() const;
- virtual int value() const;
- virtual std::ostream& print(std::ostream& os) const;
- virtual void print_flat(std::ostream&,bool add_brackets = false) const;
- virtual std::string type() const { return stype();}
- virtual std::string expression(bool why = false) const;
- static std::string stype() { return "string";}
-private:
- std::string value_;
-};
-
-
-class AstNodeState : public AstLeaf {
-public:
- AstNodeState(DState::State s) : state_(s) {}
-
- virtual void accept(ecf::ExprAstVisitor&);
- virtual AstNodeState* clone() const;
- virtual int value() const { return static_cast<int>(state_);}
- virtual std::ostream& print(std::ostream& os) const;
- virtual void print_flat(std::ostream&,bool add_brackets = false) const;
- virtual std::string type() const { return stype();}
- virtual std::string expression(bool why = false) const;
- static std::string stype() { return "node-state";}
-private:
- DState::State state_;
-};
-
-class AstEventState : public AstLeaf {
-public:
- AstEventState(bool b) : state_(b) {}
-
- virtual void accept(ecf::ExprAstVisitor&);
- virtual AstEventState* clone() const;
- virtual int value() const { return state_;}
- virtual std::ostream& print(std::ostream& os) const;
- virtual void print_flat(std::ostream&,bool add_brackets = false) const;
- virtual std::string type() const { return stype();}
- virtual std::string expression(bool why = false) const;
- static std::string stype() { return "event-state";}
-private:
- bool state_;
-};
-
-
-/// This class will need to determine the corresponding node pointer
-/// This is required so that during evaluation we don't need to search for the Node.
-/// represent nodeName(a), dotPath(./a), dot dot path(../a/b)
-///
-/// A Node without a corresponding Node* will return the integer value of
-/// DState::UNKNOWN for the value() function. This will allow for trigger
-/// of the form: trigger a == complete or a == unknown
-/// to be evaluated.
-
-class AstNode : public AstLeaf {
-public:
- AstNode(const std::string& n) : parentNode_(NULL), nodePath_(n) {}
-
- virtual void accept(ecf::ExprAstVisitor&);
- virtual AstNode* clone() const;
- virtual int value() const { return static_cast<int>(state());}
- virtual std::ostream& print(std::ostream& os) const;
- virtual void print_flat(std::ostream&,bool add_brackets = false) const;
- virtual std::string type() const { return stype();}
- virtual std::string expression(bool why = false) const;
- virtual void setParentNode(Node* n) { parentNode_ = n; }
- static std::string stype() { return "node";}
-
- const std::string& nodePath() const { return nodePath_;}
- Node* referencedNode() const;
- Node* referencedNode(std::string& errorMsg) const;
- Node* parentNode() const { return parentNode_; }
- DState::State state() const;
-
-private:
- Node* get_ref_node() const { return ref_node_.lock().get(); }
- Node* parentNode_; // should always be non null, before evaluate.
- std::string nodePath_;
- mutable weak_node_ptr ref_node_;
-};
-
-/// A variable: This can reference in the CURRENT order:
-/// event,
-/// meter,
-/// user variable,
-/// repeat variable, for enumerated/string we use the positional value
-/// generated variable
-class AstVariable : public AstLeaf {
-public:
- AstVariable(const std::string& nodePath, const std::string& variablename)
- : parentNode_(NULL), nodePath_(nodePath), name_(variablename) {}
-
- virtual void accept(ecf::ExprAstVisitor&);
- virtual AstVariable* clone() const;
- virtual int value() const;
- virtual std::ostream& print(std::ostream& os) const;
- virtual void print_flat(std::ostream&,bool add_brackets = false) const;
- virtual std::string type() const { return stype();}
- virtual std::string expression(bool why = false) const;
- virtual void setParentNode(Node* n) { parentNode_ = n; }
-
- virtual int minus(Ast* right) const;
- virtual int plus(Ast* right) const;
-
- Node* parentNode() const { return parentNode_; }
- Node* referencedNode() const;
- Node* referencedNode(std::string& errorMsg) const;
-
- static std::string stype() { return "variable";}
- const std::string& nodePath() const { return nodePath_;}
- const std::string& name() const { return name_;}
-
-private:
- Node* get_ref_node() const { return ref_node_.lock().get(); }
-
- Node* parentNode_;
- std::string nodePath_;
- std::string name_;
- mutable weak_node_ptr ref_node_;
-};
-
-// Helper class
-class VariableHelper : private boost::noncopyable {
-public:
- VariableHelper(const AstVariable* astVariable);
- VariableHelper(const AstVariable* astVariable, std::string& errorMsg);
-
- int value() const;
- int plus(int)const;
- int minus(int)const;
-
- std::ostream& print(std::ostream& os) const;
- Node* theReferenceNode() const { return theReferenceNode_;}
-
- void varTypeAndValue(std::string& varType, int & value) const;
-
-private:
- const AstVariable* astVariable_;
- Node* theReferenceNode_;
-};
-
-
-//17
-std::ostream& operator<<(std::ostream& os, const Ast&);
-std::ostream& operator<<(std::ostream& os, const AstTop&);
-std::ostream& operator<<(std::ostream& os, const AstRoot&);
-std::ostream& operator<<(std::ostream& os, const AstNot&);
-std::ostream& operator<<(std::ostream& os, const AstPlus&);
-std::ostream& operator<<(std::ostream& os, const AstMinus&);
-std::ostream& operator<<(std::ostream& os, const AstMultiply&);
-std::ostream& operator<<(std::ostream& os, const AstDivide&);
-std::ostream& operator<<(std::ostream& os, const AstModulo&);
-std::ostream& operator<<(std::ostream& os, const AstAnd&);
-std::ostream& operator<<(std::ostream& os, const AstOr&);
-std::ostream& operator<<(std::ostream& os, const AstEqual&);
-std::ostream& operator<<(std::ostream& os, const AstNotEqual&);
-std::ostream& operator<<(std::ostream& os, const AstLessEqual&);
-std::ostream& operator<<(std::ostream& os, const AstGreaterEqual&);
-std::ostream& operator<<(std::ostream& os, const AstGreaterThan&);
-std::ostream& operator<<(std::ostream& os, const AstLessThan&);
-std::ostream& operator<<(std::ostream& os, const AstLeaf&);
-std::ostream& operator<<(std::ostream& os, const AstInteger&);
-std::ostream& operator<<(std::ostream& os, const AstString&);
-std::ostream& operator<<(std::ostream& os, const AstNodeState&);
-std::ostream& operator<<(std::ostream& os, const AstEventState&);
-std::ostream& operator<<(std::ostream& os, const AstNode&);
-std::ostream& operator<<(std::ostream& os, const AstVariable&);
-
-#endif
diff --git a/ecflow_4_0_7/ANode/src/ExprAstVisitor.cpp b/ecflow_4_0_7/ANode/src/ExprAstVisitor.cpp
deleted file mode 100644
index 83939e7..0000000
--- a/ecflow_4_0_7/ANode/src/ExprAstVisitor.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #9 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "ExprAstVisitor.hpp"
-#include "ExprAst.hpp"
-#include "Node.hpp"
-#include "Log.hpp"
-
-namespace ecf {
-
-//======================================================================================
-
-ExprAstVisitor::~ExprAstVisitor(){}
-
-//======================================================================================
-AstResolveVisitor::AstResolveVisitor(const Node* node) : triggerNode_(node) {}
-AstResolveVisitor::~AstResolveVisitor() {}
-
-void AstResolveVisitor::visitNode(AstNode* astNode)
-{
- //std::cout << "AstResolveVisitor::visitNode errorMsg = " << errorMsg_ << "\n";
- if ( errorMsg_.empty()) {
-
- astNode->setParentNode(const_cast<Node*>(triggerNode_));
- Node* node = astNode->referencedNode( errorMsg_ );
- if ( !node ) {
- // A node can be NULL when its a extern path. In this case errorMsg should be empty
- return ;
- }
- LOG_ASSERT(errorMsg_.empty(),""); // found Node, make sure errorMsg is empty
- }
-}
-
-void AstResolveVisitor::visitVariable(AstVariable* astVar)
-{
- if ( errorMsg_.empty() ) {
-
- astVar->setParentNode(const_cast<Node*>(triggerNode_));
-
- /// Use VariableHelper to populate errorMsg_
- VariableHelper varHelper(astVar,errorMsg_);
- }
-}
-
-//===========================================================================================================
-
-AstCollateNodesVisitor::AstCollateNodesVisitor( std::set<Node*>& s) : theSet_(s) {}
-AstCollateNodesVisitor::~AstCollateNodesVisitor() {}
-
-void AstCollateNodesVisitor::visitNode(AstNode* astNode)
-{
- Node* referencedNode = astNode->referencedNode(); // could be expensive, hence don't call twice
- if ( referencedNode ) theSet_.insert(referencedNode);
-}
-
-void AstCollateNodesVisitor::visitVariable(AstVariable* astVar)
-{
- Node* referencedNode = astVar->referencedNode(); // could be expensive, hence don't call twice
- if ( referencedNode ) theSet_.insert(referencedNode);
-}
-
-}
diff --git a/ecflow_4_0_7/ANode/src/ExprAstVisitor.hpp b/ecflow_4_0_7/ANode/src/ExprAstVisitor.hpp
deleted file mode 100644
index dcfc6ed..0000000
--- a/ecflow_4_0_7/ANode/src/ExprAstVisitor.hpp
+++ /dev/null
@@ -1,148 +0,0 @@
-#ifndef EXPRASTVISITOR_HPP_
-#define EXPRASTVISITOR_HPP_
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <set>
-#include <string>
-class Node;
-
-class Ast;
-class AstTop;
-class AstRoot;
-class AstAnd;
-class AstNot;
-class AstPlus;
-class AstMinus;
-class AstDivide;
-class AstMultiply;
-class AstModulo;
-class AstOr;
-class AstEqual;
-class AstNotEqual;
-class AstLessEqual;
-class AstGreaterEqual;
-class AstLessThan;
-class AstGreaterThan;
-class AstLeaf;
-class AstInteger;
-class AstString;
-class AstNodeState;
-class AstEventState;
-class AstNode;
-class AstVariable;
-
-namespace ecf {
-
-class ExprAstVisitor {
-public:
- virtual ~ExprAstVisitor();
-
- virtual void visitTop(AstTop*) = 0;
- virtual void visitRoot(AstRoot*) = 0;
- virtual void visitAnd(AstAnd*) = 0;
- virtual void visitNot(AstNot*) = 0;
- virtual void visitPlus(AstPlus*) = 0;
- virtual void visitMinus(AstMinus*) = 0;
- virtual void visitDivide(AstDivide*) = 0;
- virtual void visitMultiply(AstMultiply*) = 0;
- virtual void visitModulo(AstModulo*) = 0;
- virtual void visitOr(AstOr*) = 0;
- virtual void visitEqual(AstEqual*) = 0;
- virtual void visitNotEqual(AstNotEqual*) = 0;
- virtual void visitLessEqual(AstLessEqual*) = 0;
- virtual void visitGreaterEqual(AstGreaterEqual*) = 0;
- virtual void visitGreaterThan(AstGreaterThan*) = 0;
- virtual void visitLessThan(AstLessThan*) = 0;
- virtual void visitLeaf(AstLeaf*) = 0;
- virtual void visitInteger(AstInteger*) = 0;
- virtual void visitString(AstString*) = 0;
- virtual void visitNodeState(AstNodeState*) = 0;
- virtual void visitEventState(AstEventState*) = 0;
- virtual void visitNode(AstNode*) = 0;
- virtual void visitVariable(AstVariable*) = 0;
-};
-
-class AstResolveVisitor : public ExprAstVisitor {
-public:
- AstResolveVisitor(const Node* );
- virtual ~AstResolveVisitor();
-
- const std::string& errorMsg() const { return errorMsg_;}
-
- virtual void visitTop(AstTop*){}
- virtual void visitRoot(AstRoot*){}
- virtual void visitAnd(AstAnd*){}
- virtual void visitNot(AstNot*){}
- virtual void visitPlus(AstPlus*){}
- virtual void visitMinus(AstMinus*){}
- virtual void visitDivide(AstDivide*){}
- virtual void visitMultiply(AstMultiply*){}
- virtual void visitModulo(AstModulo*){}
- virtual void visitOr(AstOr*){}
- virtual void visitEqual(AstEqual*){}
- virtual void visitNotEqual(AstNotEqual*){}
- virtual void visitLessEqual(AstLessEqual*){}
- virtual void visitGreaterEqual(AstGreaterEqual*){}
- virtual void visitGreaterThan(AstGreaterThan*){}
- virtual void visitLessThan(AstLessThan*){}
- virtual void visitLeaf(AstLeaf*){}
- virtual void visitInteger(AstInteger*){}
- virtual void visitString(AstString*){}
- virtual void visitNodeState(AstNodeState*){}
- virtual void visitEventState(AstEventState*){}
- virtual void visitNode(AstNode*);
- virtual void visitVariable(AstVariable*);
-
-private:
- const Node* triggerNode_;
- std::string errorMsg_;
-};
-
-class AstCollateNodesVisitor : public ExprAstVisitor {
-public:
- AstCollateNodesVisitor( std::set<Node*>& );
- virtual ~AstCollateNodesVisitor();
-
- virtual void visitTop(AstTop*){}
- virtual void visitRoot(AstRoot*){}
- virtual void visitAnd(AstAnd*){}
- virtual void visitNot(AstNot*){}
- virtual void visitPlus(AstPlus*){}
- virtual void visitMinus(AstMinus*){}
- virtual void visitDivide(AstDivide*){}
- virtual void visitMultiply(AstMultiply*){}
- virtual void visitModulo(AstModulo*){}
- virtual void visitOr(AstOr*){}
- virtual void visitEqual(AstEqual*){}
- virtual void visitNotEqual(AstNotEqual*){}
- virtual void visitLessEqual(AstLessEqual*){}
- virtual void visitGreaterEqual(AstGreaterEqual*){}
- virtual void visitGreaterThan(AstGreaterThan*){}
- virtual void visitLessThan(AstLessThan*){}
- virtual void visitLeaf(AstLeaf*){}
- virtual void visitInteger(AstInteger*){}
- virtual void visitString(AstString*){}
- virtual void visitNodeState(AstNodeState*){}
- virtual void visitEventState(AstEventState*){}
- virtual void visitNode(AstNode*);
- virtual void visitVariable(AstVariable*);
-
-private:
- std::set<Node*>& theSet_;
-};
-}
-#endif /* EXPRASTVISITOR_HPP_ */
diff --git a/ecflow_4_0_7/ANode/src/ExprDuplicate.cpp b/ecflow_4_0_7/ANode/src/ExprDuplicate.cpp
deleted file mode 100644
index 02127a5..0000000
--- a/ecflow_4_0_7/ANode/src/ExprDuplicate.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #23 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#if defined(HPUX)
-#include <map>
-#else
-#include <boost/unordered_map.hpp>
-#endif
-#include <boost/foreach.hpp>
-
-#include "ExprDuplicate.hpp"
-#include "ExprAst.hpp"
-
-////////////////////////////////////////////////////////////////////////////
-using namespace std;
-
-#if defined(HPUX)
-// boost 1.51 HPUX has problems with boost::unordered_map
-static std::map< std::string, AstTop* > duplicate_expr;
-typedef std::map< std::string, AstTop* > my_map;
-#else
-static boost::unordered_map< std::string, AstTop* > duplicate_expr;
-typedef boost::unordered_map< std::string, AstTop* > my_map;
-#endif
-
-
-ExprDuplicate::~ExprDuplicate()
-{
-// cout << "ExprDuplicate::~ExprDuplicate()\n";
- BOOST_FOREACH(my_map::value_type i, duplicate_expr) {
- AstTop* top = i.second;
- delete top;
- }
- duplicate_expr.clear();
-}
-
-std::auto_ptr<AstTop> ExprDuplicate::find(const std::string& expr)
-{
- my_map::const_iterator it = duplicate_expr.find(expr);
- if (it != duplicate_expr.end()) {
- return std::auto_ptr<AstTop>((*it).second->clone());
- }
- return std::auto_ptr<AstTop>();
-}
-
-void ExprDuplicate::add(const std::string& expr,AstTop* ast)
-{
- assert(!expr.empty() && ast);
- duplicate_expr.insert( std::make_pair(expr,ast->clone()));
-}
diff --git a/ecflow_4_0_7/ANode/src/ExprDuplicate.hpp b/ecflow_4_0_7/ANode/src/ExprDuplicate.hpp
deleted file mode 100644
index b54565b..0000000
--- a/ecflow_4_0_7/ANode/src/ExprDuplicate.hpp
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef EXPR_DUPLICATE_
-#define EXPR_DUPLICATE_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #11 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-// =========================================================================
-// For large designs > 90% of triggers are identical.
-// We take advantage of this by using a map to store a *CLONED* ast
-// This saves a huge amount on re-parsing using spirit classic.
-//
-// This cloned AST is maintained in a static map, hence we need to
-// manage the lifetime, to avoid valgrind complaining.
-// =========================================================================
-
-#include <string>
-#include <memory> // for auto_ptr
-#include <boost/noncopyable.hpp>
-class AstTop;
-
-// reclaim memory allocated in map, Avoid valgrind errors
-class ExprDuplicate : private boost::noncopyable {
-public:
- ExprDuplicate() {}
- ~ExprDuplicate();
-
- // Find the expr in the map, if found returns a CLONED ast, else NULL
- static std::auto_ptr<AstTop> find(const std::string& expr);
-
- // Add the expr to the map, the ast is cloned.
- static void add(const std::string& expr,AstTop*);
-};
-
-#endif
diff --git a/ecflow_4_0_7/ANode/src/ExprParser.cpp b/ecflow_4_0_7/ANode/src/ExprParser.cpp
deleted file mode 100644
index 68fcb29..0000000
--- a/ecflow_4_0_7/ANode/src/ExprParser.cpp
+++ /dev/null
@@ -1,933 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #30 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-// Un-comment these for selective for debugging. At the moment because we have added
-// ast generation BOOST_SPIRIT_DEBUG is to verbose, making debugging a pain.
-// Tpyically I will comment out ONLY BOOST_SPIRIT_DEBUG and enable all the others
-//#define BOOST_SPIRIT_DEBUG
-//#define BOOST_SPIRIT_DUMP_PARSETREE_AS_XML
-//#define PRINT_TREE
-//#define PRINT_AST_TRAVERSAL
-//#define PRINT_AST
-
-#include <boost/spirit/include/classic.hpp>
-#include <boost/spirit/include/classic_core.hpp>
-#include <boost/spirit/include/classic_actor.hpp>
-#include <boost/spirit/include/classic_attribute.hpp>
-#include <boost/spirit/include/classic_confix.hpp>
-#include <boost/spirit/include/phoenix1_binders.hpp>
-#include <boost/spirit/include/classic_ast.hpp>
-#include <boost/spirit/include/classic_tree_to_xml.hpp>
-
-#include "boost/lambda/lambda.hpp"
-#include "boost/lambda/bind.hpp"
-#include "boost/cast.hpp"
-#include <boost/foreach.hpp>
-#include <boost/lexical_cast.hpp>
-#include <boost/algorithm/string/trim.hpp>
-
-#include <iostream>
-#include <string>
-#include <utility>
-#include <stack>
-#include <sstream>
-#include <map>
-
-#include "ExprParser.hpp"
-#include "ExprAst.hpp"
-#include "ExprDuplicate.hpp"
-#include "Indentor.hpp"
-#include "Log.hpp"
-#include "Str.hpp"
-
-// Reference
-//‘*’ Zero or more
-//‘!’ Zero or one
-//‘+’ One or more
-//‘>>’ Sequence/concatenation
-//‘|’ alternate
-//‘-‘ not
-
-////////////////////////////////////////////////////////////////////////////
-using namespace ecf;
-using namespace std;
-using namespace boost::spirit;
-using namespace phoenix;
-using namespace BOOST_SPIRIT_CLASSIC_NS;
-
-/////////////////////////////////////////////////////////////////////////////
-typedef tree_match<const char*> treematch_t;
-typedef treematch_t::tree_iterator tree_iter_t;
-
-//////////////////////////////////////////////////////////////////////////////
-
-struct ExpressionGrammer : public grammar<ExpressionGrammer>
-{
- // The parser object is copied a lot, so only use reference/pointer variables as data members
- ExpressionGrammer(){}
- ~ExpressionGrammer(){}
-
- static const int integer_ID = 1;
- static const int dot_path_ID = 2;
- static const int equal_1_ID = 3;
- static const int equal_2_ID = 4;
- static const int not_equal_1_ID = 5;
- static const int not_equal_2_ID = 6;
- static const int node_name_ID = 7;
- static const int greater_equals_1_ID = 8;
- static const int greater_equals_2_ID = 9;
- static const int less_equals_1_ID = 10;
- static const int less_equals_2_ID = 11;
- static const int less_than_1_ID = 12;
- static const int less_than_2_ID = 13;
- static const int greater_than_1_ID = 14;
- static const int greater_than_2_ID = 15;
- static const int node_state_unknown_ID = 16;
-
- static const int node_state_complete_ID = 18;
- static const int node_state_queued_ID = 19;
- static const int node_state_submitted_ID = 20;
- static const int node_state_active_ID = 21;
- static const int node_state_aborted_ID = 22;
- static const int not1_ID = 23;
- static const int not2_ID = 24;
- static const int and_ID = 25;
- static const int or_ID = 26;
- static const int event_ID = 27;
- static const int dot_dot_path_ID = 28;
- static const int event_name_ID = 29;
- static const int base_trigger_ID = 30;
- static const int sub_expression_ID = 31;
- static const int grouping_ID = 32;
- static const int node_path_state_ID = 33;
- static const int absolute_path_ID = 34;
- static const int some_string_ID = 35;
- static const int variable_ID = 36;
- static const int variable_path_ID = 37;
- static const int normal_variable_path_ID = 38;
- static const int grouped_variable_path_ID = 39;
- static const int variable_expression_ID = 40;
- static const int plus_ID = 41;
- static const int minus_ID = 42;
- static const int multiply_ID = 43;
- static const int divide_ID = 44;
- static const int modulo_ID = 45;
-
- template <typename ScannerT>
- struct definition {
- rule<ScannerT,parser_tag<integer_ID> > integer;
- rule<ScannerT,parser_tag<plus_ID> > plus;
- rule<ScannerT,parser_tag<minus_ID> > minus;
- rule<ScannerT,parser_tag<multiply_ID> > multiply;
- rule<ScannerT,parser_tag<divide_ID> > divide;
- rule<ScannerT,parser_tag<modulo_ID> > modulo;
-
- rule<ScannerT,parser_tag<equal_1_ID> > equal_1;
- rule<ScannerT,parser_tag<equal_2_ID> > equal_2;
- rule<ScannerT,parser_tag<not_equal_1_ID> > not_equal_1;
- rule<ScannerT,parser_tag<not_equal_2_ID> > not_equal_2;
- rule<ScannerT,parser_tag<node_name_ID> > nodename;
-
- rule<ScannerT,parser_tag<greater_equals_1_ID> > greater_equals_1;
- rule<ScannerT,parser_tag<greater_equals_2_ID> > greater_equals_2;
- rule<ScannerT,parser_tag<less_equals_1_ID> > less_equals_1;
- rule<ScannerT,parser_tag<less_equals_2_ID> > less_equals_2;
-
- rule<ScannerT,parser_tag<less_than_1_ID> > less_than_1;
- rule<ScannerT,parser_tag<less_than_2_ID> > less_than_2;
- rule<ScannerT,parser_tag<greater_than_1_ID> > greater_than_1;
- rule<ScannerT,parser_tag<greater_than_2_ID> > greater_than_2;
-
- rule<ScannerT,parser_tag<node_state_unknown_ID> > node_state_unknown;
- rule<ScannerT,parser_tag<node_state_complete_ID> > node_state_complete;
- rule<ScannerT,parser_tag<node_state_queued_ID> > node_state_queued;
- rule<ScannerT,parser_tag<node_state_submitted_ID> > node_state_submitted;
- rule<ScannerT,parser_tag<node_state_active_ID> > node_state_active;
- rule<ScannerT,parser_tag<node_state_aborted_ID> > node_state_aborted;
-
- rule<ScannerT,parser_tag<not1_ID> > not1_r;
- rule<ScannerT,parser_tag<not2_ID> > not2_r;
- rule<ScannerT,parser_tag<not2_ID> > not3_r;
- rule<ScannerT,parser_tag<and_ID> > and_r;
- rule<ScannerT,parser_tag<or_ID> > or_r;
- rule<ScannerT,parser_tag<event_ID> > event;
-
- rule<ScannerT,parser_tag<dot_path_ID> > dotpath;
- rule<ScannerT,parser_tag<dot_dot_path_ID> > dotdotpath;
- rule<ScannerT,parser_tag<absolute_path_ID> > absolutepath;
- rule<ScannerT,parser_tag<event_name_ID> > eventname;
-
- rule<ScannerT,parser_tag<base_trigger_ID> > baseTrigger;
- rule<ScannerT,parser_tag<sub_expression_ID> > subexpression;
- rule<ScannerT,parser_tag<grouping_ID> > grouping;
- rule<ScannerT,parser_tag<node_path_state_ID> > nodepathstate;
-
- rule<ScannerT,parser_tag<some_string_ID> > some_string;
- rule<ScannerT,parser_tag<variable_ID> > variable;
- rule<ScannerT,parser_tag<variable_path_ID> > variable_path;
- rule<ScannerT,parser_tag<normal_variable_path_ID> > normal_variable_path;
- rule<ScannerT,parser_tag<grouped_variable_path_ID> > grouped_variable_path;
- rule<ScannerT,parser_tag<variable_expression_ID> > variable_expression;
-
- rule<ScannerT> not_r,less_than_comparable,expression,andExpr,orExpr,operators;
- rule<ScannerT> nodestate, equality_comparible, and_or, nodepath ;
- rule<ScannerT> andsubexpression, orsubexpression,integerComparison,notGrouping ;
-
- // ‘*’ Zero or more
- // ‘!’ Zero or one
- // ‘+’ One or more
- // ‘>>’ Sequence/concatenation
- // ‘|’ alternate
- // ‘-‘ not
- definition(ExpressionGrammer const& /*self*/)
- {
- nodename
- = leaf_node_d[
- lexeme_d [ (alnum_p || ch_p('_')) >> *(alnum_p || ch_p('_')) ]
- ]
- ;
-
- // Can be /suite/family/task
- // family/task
- // family
- absolutepath
- = leaf_node_d[
- !(str_p("/")) >> nodename
- >> *(
- + str_p("/") >> nodename
- )
- ]
- ;
- dotdotpath // a kind of relative path
- = leaf_node_d[
- str_p("..")
- >> *(
- + str_p("/") >> str_p("..")
- )
- >> +(
- + str_p("/") >> nodename
- )
- ]
- ;
- dotpath = leaf_node_d[ str_p(".") >> +( str_p("/") >> nodename) ];
- nodepath = absolutepath | dotdotpath | dotpath ;
-
- // Integer is distinct from task/family names that are integers, since nodes with integer
- // names that occur in trigger/complete expression must have path ./0 ./1
- integer = leaf_node_d[ uint_p ];
- plus = root_node_d [ str_p("+") ];
- minus = root_node_d [ str_p("-") ];
- divide = root_node_d [ str_p("/") ];
- multiply = root_node_d [ str_p("*") ];
- modulo = root_node_d [ str_p("%") ];
- operators = plus | minus | divide | multiply | modulo ;
-
- equal_1 = root_node_d [ str_p("==") ];
- equal_2 = root_node_d [ str_p("eq") ];
- not_equal_1 = root_node_d [ str_p("!=") ];
- not_equal_2 = root_node_d [ str_p("ne") ];
- equality_comparible = equal_1 | equal_2 | not_equal_2 | not_equal_1;
-
- greater_equals_1 = root_node_d [ str_p(">=") ];
- greater_equals_2 = root_node_d [ str_p("ge") ];
- less_equals_1 = root_node_d [ str_p("<=") ];
- less_equals_2 = root_node_d [ str_p("le") ];
- less_than_1 = root_node_d [ str_p("<") ];
- less_than_2 = root_node_d [ str_p("lt") ];
- greater_than_1 = root_node_d [ str_p(">") ];
- greater_than_2 = root_node_d [ str_p("gt") ];
- // Prioritise to most common first, to speed up parsing
- less_than_comparable
- = greater_equals_2
- | less_equals_2
- | greater_than_2
- | less_than_2
- | greater_equals_1
- | less_equals_1
- | less_than_1
- | greater_than_1
- ;
-
- not1_r = root_node_d [ str_p("not") ];
- not2_r = root_node_d [ str_p("~") ];
- not3_r = root_node_d [ str_p("!") ];
- not_r = not1_r | not3_r | not2_r;
-
- and_r = root_node_d [ str_p("and") ] || root_node_d [ str_p("&&") ] ;
- or_r = root_node_d [ str_p("or") ] || root_node_d [ str_p("||") ] ;
- and_or = and_r | or_r;
-
-
- eventname = leaf_node_d [ nodename ];
- event
- = nodepath
- >> discard_node_d[ ch_p(':') ]
- >> eventname
- ;
-
- some_string = leaf_node_d[ str_p("set") ] || leaf_node_d[ str_p("clear")] ;
-
- variable = leaf_node_d [ nodename ];
- normal_variable_path
- = nodepath
- >> discard_node_d[ ch_p(':') ]
- >> variable
- >> !(operators >> (integer | normal_variable_path))
- ;
- grouped_variable_path
- = discard_node_d[ ch_p('(') ]
- >> normal_variable_path
- >> discard_node_d[ ch_p(')') ]
- ;
- variable_path = grouped_variable_path | normal_variable_path ;
-
- variable_expression
- = variable_path
- >> ( less_than_comparable | equality_comparible )
- >> !not_r
- >> ( variable_path | integer | some_string )
- ;
-
-
- node_state_unknown = root_node_d [ str_p("unknown") ];
- node_state_complete = root_node_d [ str_p("complete") ];
- node_state_queued = root_node_d [ str_p("queued") ];
- node_state_submitted = root_node_d [ str_p("submitted") ];
- node_state_active = root_node_d [ str_p("active") ];
- node_state_aborted = root_node_d [ str_p("aborted") ];
- nodestate
- = node_state_complete
- | node_state_aborted
- | node_state_active
- | node_state_queued
- | node_state_submitted
- | node_state_unknown
- ;
- nodepathstate = nodepath >> equality_comparible >> nodestate;
-
- integerComparison = integer >> ( less_than_comparable | equality_comparible) >> ( integer | variable_path );
-
- baseTrigger
- = !not_r
- >> (
- nodepathstate
- | variable_expression
- | event // event if of the form 'a:name'
- | integerComparison // 1 eq 1
- )
- ;
- andExpr = baseTrigger >> and_r >> baseTrigger;
- orExpr = baseTrigger >> or_r >> baseTrigger;
-
- // We need to take special care so that 'and' has a higher priority then 'or'
- andsubexpression = andExpr >> *(and_or >> subexpression);
-
- orsubexpression = baseTrigger >> +(or_r >> subexpression);
-
- subexpression = (andsubexpression | orsubexpression | baseTrigger | notGrouping | integer)
- >> *(and_or >> subexpression );
-
- grouping
- = discard_node_d[ ch_p('(') ]
- >> subexpression
- >> discard_node_d[ ch_p(')') ]
- ;
-
- notGrouping = !not_r >> grouping >> *(and_or >> subexpression);
- expression = ( notGrouping | subexpression ) >> end_p;
-
- BOOST_SPIRIT_DEBUG_NODE(notGrouping);
- BOOST_SPIRIT_DEBUG_NODE(expression);
- BOOST_SPIRIT_DEBUG_NODE(andExpr);
- BOOST_SPIRIT_DEBUG_NODE(not_r);
- BOOST_SPIRIT_DEBUG_NODE(not1_r);
- BOOST_SPIRIT_DEBUG_NODE(not2_r);
- BOOST_SPIRIT_DEBUG_NODE(orExpr);
- BOOST_SPIRIT_DEBUG_NODE(expression);
- BOOST_SPIRIT_DEBUG_NODE(nodename);
- BOOST_SPIRIT_DEBUG_NODE(nodepath);
- BOOST_SPIRIT_DEBUG_NODE(dotdotpath);
- BOOST_SPIRIT_DEBUG_NODE(dotpath);
- BOOST_SPIRIT_DEBUG_NODE(absolutepath);
- BOOST_SPIRIT_DEBUG_NODE(event);
- BOOST_SPIRIT_DEBUG_NODE(less_than_comparable);
- BOOST_SPIRIT_DEBUG_NODE(nodestate);
- BOOST_SPIRIT_DEBUG_NODE(equality_comparible);
- BOOST_SPIRIT_DEBUG_NODE(equal_1);
- BOOST_SPIRIT_DEBUG_NODE(equal_2);
- BOOST_SPIRIT_DEBUG_NODE(not_equal_1);
- BOOST_SPIRIT_DEBUG_NODE(not_equal_2);
- BOOST_SPIRIT_DEBUG_NODE(and_or);
- BOOST_SPIRIT_DEBUG_NODE(operators);
- BOOST_SPIRIT_DEBUG_NODE(baseTrigger);
- BOOST_SPIRIT_DEBUG_NODE(subexpression);
- BOOST_SPIRIT_DEBUG_NODE(andsubexpression);
- BOOST_SPIRIT_DEBUG_NODE(orsubexpression);
- BOOST_SPIRIT_DEBUG_NODE(grouping);
- BOOST_SPIRIT_DEBUG_NODE(nodepathstate);
- BOOST_SPIRIT_DEBUG_NODE(integer);
- BOOST_SPIRIT_DEBUG_NODE(some_string);
- BOOST_SPIRIT_DEBUG_NODE(variable);
- BOOST_SPIRIT_DEBUG_NODE(variable_path);
- BOOST_SPIRIT_DEBUG_NODE(variable_expression);
- BOOST_SPIRIT_DEBUG_NODE(integerComparison);
- };
-
- rule<ScannerT> const& start() const { return expression; }
- };
-};
-
-/////////////////////////////////////////////////////////////////////////////////////////////
-
-void print(tree_parse_info<> info,
- const std::string& expr,
- const std::map< parser_id, std::string >& rule_names);
-
-AstTop* createAst( tree_parse_info< > info,
- const std::string& expr,
- const std::map< parser_id, std::string >& rule_names );
-
-/////////////////////////////////////////////////////////////////////////////////////////////
-
-ExprParser::ExprParser( const std::string& expression ): expr_(expression) {}
-
-static std::map< parser_id, std::string > rule_names;
-static void populate_rule_names()
-{
- if (rule_names.empty()) {
- rule_names[ExpressionGrammer::equal_1_ID] = "EQUALS";
- rule_names[ExpressionGrammer::equal_2_ID] = "EQUALS";
- rule_names[ExpressionGrammer::not_equal_1_ID] = "NOT_EQUAL";
- rule_names[ExpressionGrammer::not_equal_2_ID] = "NOT_EQUAL";
- rule_names[ExpressionGrammer::greater_equals_1_ID] = "GREATER_THAN_OR_EQUALS";
- rule_names[ExpressionGrammer::greater_equals_2_ID] = "GREATER_THAN_OR_EQUALS";
- rule_names[ExpressionGrammer::less_equals_1_ID] = "LESS_THAN_OR_EQUALS";
- rule_names[ExpressionGrammer::less_equals_2_ID] = "LESS_THAN_OR_EQUALS";
- rule_names[ExpressionGrammer::less_than_1_ID] = "LESS_THAN";
- rule_names[ExpressionGrammer::less_than_2_ID] = "LESS_THAN";
- rule_names[ExpressionGrammer::greater_than_1_ID] = "GREATER_THAN";
- rule_names[ExpressionGrammer::greater_than_2_ID] = "GREATER_THAN";
- rule_names[ExpressionGrammer::not1_ID ] = "NOT";
- rule_names[ExpressionGrammer::not2_ID ] = "NOT";
- rule_names[ExpressionGrammer::and_ID ] = "AND";
- rule_names[ExpressionGrammer::or_ID ] = "OR";
- rule_names[ExpressionGrammer::node_name_ID] = "NODE_NAME";
- rule_names[ExpressionGrammer::node_state_unknown_ID ] = "UNKNOWN";
- rule_names[ExpressionGrammer::node_state_complete_ID ] = "COMPLETE";
- rule_names[ExpressionGrammer::node_state_queued_ID ] = "QUEUED";
- rule_names[ExpressionGrammer::node_state_submitted_ID ] = "SUBMITTED";
- rule_names[ExpressionGrammer::node_state_active_ID ] = "ACTIVE";
- rule_names[ExpressionGrammer::node_state_aborted_ID ] = "ABORTED";
- rule_names[ExpressionGrammer::integer_ID] = "INTEGER";
- rule_names[ExpressionGrammer::event_ID ] = "EVENT";
- rule_names[ExpressionGrammer::dot_path_ID ] = "DOT_PATH";
- rule_names[ExpressionGrammer::dot_dot_path_ID ] = "DOT_DOT_PATH";
- rule_names[ExpressionGrammer::absolute_path_ID ] = "ABSOLUTE_PATH";
- rule_names[ExpressionGrammer::event_name_ID ] = "EVENT_NAME";
-
- rule_names[ExpressionGrammer::base_trigger_ID ] = "BASE_TRIGGER";
- rule_names[ExpressionGrammer::sub_expression_ID ] = "SUB_EXPRESSION";
- rule_names[ExpressionGrammer::grouping_ID ] = "GROUPING";
- rule_names[ExpressionGrammer::node_path_state_ID ] = "NODE_PATH_STATE";
-
- rule_names[ExpressionGrammer::some_string_ID ] = "STRING";
- rule_names[ExpressionGrammer::variable_ID ] = "VARIABLE";
- rule_names[ExpressionGrammer::variable_path_ID ] = "VARIABLE_PATH";
- rule_names[ExpressionGrammer::grouped_variable_path_ID ] = "GROUPED_VARIABLE_PATH";
- rule_names[ExpressionGrammer::normal_variable_path_ID ] = "NORMAL_VARIABLE_PATH";
- rule_names[ExpressionGrammer::variable_expression_ID ] = "VARIABLE_EXPRESSION";
- }
-}
-
-bool ExprParser::doParse(std::string& errorMsg)
-{
- if (expr_.empty()) {
- errorMsg = "Expression is empty";
- return false;
- }
-
- // =========================================================================
- // For large designs > 90% of triggers are identical.
- // We take advantage of this by only parsing the expression once
- // and storing then Abstract Syntax tree( via cloning ) using a map
- // This saves a huge amount of CPU time in re-parsing using spirit classic.
- // =========================================================================
- ast_ = ExprDuplicate::find(expr_);
- if (ast_.get()) {
- return true;
- }
-
- SimpleExprParser simpleParser(expr_);
- if (simpleParser.doParse()) {
- ast_ = simpleParser.ast();
- ExprDuplicate::add(expr_,ast_.get()); // bypass spirit if same expression used
- return true;
- }
-
- // SPIRIT CLASSIC parsing: very slooooow....
- ExpressionGrammer grammer;
- BOOST_SPIRIT_DEBUG_NODE(grammer);
-
- // Use parser that generates a abstract syntax tree
- tree_parse_info<> info = ast_parse( expr_.c_str(), grammer, space_p);
- if (info.full) {
-
- populate_rule_names();
-
-#if defined(BOOST_SPIRIT_DUMP_PARSETREE_AS_XML)
- tree_to_xml( cout, info.trees, expr_.c_str(), rule_names );
-#endif
-#if defined(PRINT_TREE)
- print(info,expr_,rule_names);
-#endif
- // Spirit has created a AST for us. However it is not use able as is
- // we will traverse the AST and create our OWN persist-able AST.
- ast_.reset( createAst(info,expr_,rule_names) );
- if (ast_->empty()) errorMsg = "Abstract syntax tree creation failed";
- else {
- ExprDuplicate::add(expr_,ast_.get());
- }
- return errorMsg.empty();
- }
- else {
- std::stringstream ss;
- ss << "Parsing failed\n";
- ss << "length = " << std::dec << info.length << "\n";
- ss << "stopped at: \": " << info.stop << "\"\n";
- errorMsg = ss.str();
- }
- return false;
-}
-
-
-// The evaluation function for the AST
-void do_print(const tree_iter_t& i, const std::map< parser_id, std::string >& rule_names)
-{
- Indentor in;
- std::map< parser_id, std::string >::const_iterator iter = rule_names.find(i->value.id());
- if (iter != rule_names.end()) {
- Indentor::indent(cout) << "Rule " << (*iter).second
- << " " << string( i->value.begin(), i->value.end() ) << endl;
- }
- else {
- Indentor::indent(cout) << "Unknown rule "
- << " " << string( i->value.begin(), i->value.end() ) << endl;
- }
-
- Indentor in2;
- for (tree_iter_t t = i->children.begin(); t != i->children.end(); ++t) {
- do_print( t, rule_names );
- }
-}
-
-void print(tree_parse_info<> info,
- const std::string& expr,
- const std::map< parser_id, std::string >& rule_names)
-{
- std::cout << "\nPRINT_TREE " << expr << "\n";
- do_print(info.trees.begin(),rule_names);
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////
-
-AstRoot* createRootNode(const tree_iter_t& i, const std::map< parser_id, std::string >& rule_names)
-{
-#if defined(PRINT_AST_TRAVERSAL)
- Indentor in;
- std::map< parser_id, std::string >::const_iterator iter = rule_names.find(i->value.id());
- if (iter != rule_names.end()) {
- Indentor::indent(cout) << "Root Rule " << (*iter).second
- << " " << string( i->value.begin(), i->value.end() ) << endl;
- }
- else {
- Indentor::indent(cout) << "Unknown root rule "
- << " " << string( i->value.begin(), i->value.end() ) << endl;
- }
-#endif
-
- if ( i->value.id() == ExpressionGrammer::equal_1_ID ) return new AstEqual();
- if ( i->value.id() == ExpressionGrammer::equal_2_ID ) return new AstEqual();
- if ( i->value.id() == ExpressionGrammer::and_ID ) return new AstAnd();
- if ( i->value.id() == ExpressionGrammer::or_ID ) return new AstOr();
- if ( i->value.id() == ExpressionGrammer::not1_ID ) return new AstNot();
- if ( i->value.id() == ExpressionGrammer::not2_ID ) return new AstNot();
- if ( i->value.id() == ExpressionGrammer::plus_ID ) return new AstPlus();
-
- if ( i->value.id() == ExpressionGrammer::not_equal_1_ID ) return new AstNotEqual();
- if ( i->value.id() == ExpressionGrammer::not_equal_2_ID ) return new AstNotEqual();
- if ( i->value.id() == ExpressionGrammer::greater_equals_1_ID ) return new AstGreaterEqual();
- if ( i->value.id() == ExpressionGrammer::greater_equals_2_ID ) return new AstGreaterEqual();
- if ( i->value.id() == ExpressionGrammer::less_equals_1_ID ) return new AstLessEqual();
- if ( i->value.id() == ExpressionGrammer::less_equals_2_ID ) return new AstLessEqual();
- if ( i->value.id() == ExpressionGrammer::less_than_1_ID ) return new AstLessThan();
- if ( i->value.id() == ExpressionGrammer::less_than_2_ID ) return new AstLessThan();
- if ( i->value.id() == ExpressionGrammer::greater_than_1_ID ) return new AstGreaterThan();
- if ( i->value.id() == ExpressionGrammer::greater_than_2_ID ) return new AstGreaterThan();
-
- if ( i->value.id() == ExpressionGrammer::minus_ID ) return new AstMinus();
- if ( i->value.id() == ExpressionGrammer::multiply_ID ) return new AstMultiply();
- if ( i->value.id() == ExpressionGrammer::divide_ID ) return new AstDivide();
- if ( i->value.id() == ExpressionGrammer::modulo_ID ) return new AstModulo();
- LOG_ASSERT(false,"");
- return NULL;
-}
-
-Ast* createAst( const tree_iter_t& i, const std::map< parser_id, std::string >& rule_names ) {
-#if defined(PRINT_AST_TRAVERSAL)
- Indentor in;
- std::map< parser_id, std::string >::const_iterator iter = rule_names.find(i->value.id());
- if (iter != rule_names.end()) {
- Indentor::indent(cout) << "Create AST Rule " << (*iter).second
- << " '" << string( i->value.begin(), i->value.end() ) << "'\n";
- }
- else {
- Indentor::indent(cout) << "Create AST Unknown rule "
- << " '" << string( i->value.begin(), i->value.end() ) << "'\n";
- }
-#endif
-
-
- if ( i->value.id() == ExpressionGrammer::node_name_ID) {
-
- string thevalue( i->value.begin(), i->value.end() );
- boost::algorithm::trim(thevalue); // don't know why we get leading/trailing spaces
- LOG_ASSERT( !thevalue.empty(), "" );
- return new AstNode( thevalue );
- }
- else if ( i->value.id() == ExpressionGrammer::node_state_complete_ID) {
-
- return new AstNodeState( DState::COMPLETE );
- }
- else if ( i->value.id() == ExpressionGrammer::normal_variable_path_ID) {
-
- LOG_ASSERT((i->children.size() == 2 || i->children.size() == 4), "");
- tree_iter_t theNodePathIter = i->children.begin();
- tree_iter_t theNameIter = i->children.begin()+1;
-
- string nodePath( theNodePathIter->value.begin(), theNodePathIter->value.end() );
- string name( theNameIter->value.begin(), theNameIter->value.end() );
- boost::algorithm::trim(nodePath); // don't know why we get leading/trailing spaces
- boost::algorithm::trim(name); // don't know why we get leading/trailing spaces
-
- if ( i->children.size() == 4) {
- AstRoot* operatorRoot = createRootNode( i->children.begin()+2, rule_names );
- Ast* astInteger = createAst(i->children.begin()+3, rule_names);
-
- operatorRoot->addChild( new AstVariable( nodePath, name ));
- operatorRoot->addChild(astInteger);
- return operatorRoot;
- }
-
- return new AstVariable( nodePath, name );
- }
- else if ( i->value.id() == ExpressionGrammer::dot_dot_path_ID) {
-
- string thevalue( i->value.begin(), i->value.end() );
- boost::algorithm::trim(thevalue); // don't know why we get leading/trailing spaces
- LOG_ASSERT( !thevalue.empty() , "");
- return new AstNode( thevalue );
- }
- if ( i->value.id() == ExpressionGrammer::absolute_path_ID) {
-
- string thevalue( i->value.begin(), i->value.end() );
- boost::algorithm::trim(thevalue); // don't know why we get leading/trailing spaces
- LOG_ASSERT( !thevalue.empty() ,"");
- return new AstNode( thevalue );
- }
- else if ( i->value.id() == ExpressionGrammer::dot_path_ID) {
-
- string thevalue( i->value.begin(), i->value.end() );
- boost::algorithm::trim(thevalue); // don't know why we get leading/trailing spaces
- LOG_ASSERT( !thevalue.empty() , "");
- return new AstNode( thevalue );
- }
- else if ( i->value.id() == ExpressionGrammer::event_ID) {
-
- LOG_ASSERT(i->children.size() >= 2, "");
- tree_iter_t theNodePathIter = i->children.begin();
- tree_iter_t theEventNameIter = i->children.begin()+1;
-
- string nodePath( theNodePathIter->value.begin(), theNodePathIter->value.end() );
- string eventName( theEventNameIter->value.begin(), theEventNameIter->value.end() );
- boost::algorithm::trim(nodePath); // don't know why we get leading/trailing spaces
- boost::algorithm::trim(eventName); // don't know why we get leading/trailing spaces
-
- return new AstVariable( nodePath, eventName );
- }
- else if ( i->value.id() == ExpressionGrammer::some_string_ID) {
-
- string thevalue( i->value.begin(), i->value.end() );
- boost::algorithm::trim(thevalue); // don't know why we get leading/trailing spaces
- return new AstString(thevalue);
- }
- else if ( i->value.id() == ExpressionGrammer::integer_ID) {
-
- string thevalue( i->value.begin(), i->value.end() );
- boost::algorithm::trim(thevalue); // don't know why we get leading/trailing spaces
- int theInt = boost::lexical_cast<int>(thevalue);
- return new AstInteger(theInt);
- }
- else if ( i->value.id() == ExpressionGrammer::node_state_aborted_ID) {
-
- return new AstNodeState( DState::ABORTED );
- }
- else if ( i->value.id() == ExpressionGrammer::node_state_active_ID) {
-
- return new AstNodeState( DState::ACTIVE );
- }
- else if ( i->value.id() == ExpressionGrammer::node_state_queued_ID) {
-
- return new AstNodeState( DState::QUEUED );
- }
- else if ( i->value.id() == ExpressionGrammer::node_state_submitted_ID) {
-
- return new AstNodeState( DState::SUBMITTED );
- }
- else if ( i->value.id() == ExpressionGrammer::node_state_unknown_ID) {
-
- return new AstNodeState( DState::UNKNOWN );
- }
-
- return NULL;
-}
-
-
-
-// The evaluation function for the AST
-Ast* doCreateAst( const tree_iter_t& i,
- const std::map< parser_id, std::string >& rule_names,
- Ast* top)
-{
-#if defined(PRINT_AST_TRAVERSAL)
- Indentor in;
- std::map< parser_id, std::string >::const_iterator iter = rule_names.find(i->value.id());
- if (iter != rule_names.end()) {
- Indentor::indent(cout) << "Rule " << (*iter).second
- << " " << string( i->value.begin(), i->value.end() ) << endl;
- }
- else {
- Indentor::indent(cout) << "Unknown rule "
- << " " << string( i->value.begin(), i->value.end() ) << endl;
- }
-#endif
-
- Indentor in2;
- if ( i->value.id() == ExpressionGrammer::event_ID ) {
- // Event need to handled in a custom way
- LOG_ASSERT(i->children.size() == 2,"");
- if (i->children.size() == 2) {
- // a:eventname || ../a/b:eventname
- // child 1: path a || ../a/b
- // child 2: event name
- // WE add an event state so that when the event is evaluated it is compared to true
- Ast* someRoot = new AstEqual();
- Ast* leftEvent = createAst(i, rule_names);
- Ast* rightEvent = new AstEventState( true );
- someRoot->addChild(leftEvent);
- someRoot->addChild(rightEvent);
- top->addChild(someRoot);
- }
- }
- else if (i->children.size() == 4 &&
- (i->children.begin()->value.id() == ExpressionGrammer::not1_ID ||
- i->children.begin()->value.id() == ExpressionGrammer::not2_ID)
- ) {
- // child 0: notRoot 0
- // child 1: notChild +1
- // child 2: someRoot(i.e ==,!=) +2
- // child 3: right +3
- // Create as: someRoot
- // notRoot right
- // notChild
- LOG_ASSERT((i->children.begin()->value.id() == ExpressionGrammer::not1_ID || i->children.begin()->value.id() == ExpressionGrammer::not2_ID),"");
- AstRoot* notRoot = createRootNode( i->children.begin(), rule_names );
- Ast* notChild = doCreateAst( i->children.begin() + 1, rule_names, notRoot/*top*/ );
- if (notChild) notRoot->addChild(notChild);
-
- AstRoot* someRoot = createRootNode( i->children.begin() + 2, rule_names );
- someRoot->addChild(notRoot); //left
-
- Ast* right = doCreateAst( i->children.begin() + 3, rule_names, someRoot/* top*/ );
- if (right) someRoot->addChild(right);
- top->addChild(someRoot);
- }
- else if (i->children.size() == 4 && i->value.id() == ExpressionGrammer::variable_expression_ID ) {
- LOG_ASSERT((i->children.begin()->value.id() == ExpressionGrammer::normal_variable_path_ID), "");
- // child 0: NORMAL_VARIABLE_PATH 0
- // child 1: someRoot(i.e ==,!=) +1
- // child 2: NOT +2
- // child 3: integer | variable +3
- //
- // Create as: someRoot
- // varPath notRoot
- // notChild
- AstRoot* someRoot = createRootNode( i->children.begin()+1, rule_names );
- Ast* varPath = doCreateAst( i->children.begin(), rule_names, someRoot/*top*/ );
-
- AstRoot* notRoot = createRootNode( i->children.begin()+2, rule_names );
- Ast* notChild = doCreateAst( i->children.begin() + 3, rule_names, notRoot/*top*/ );
-
- notRoot->addChild(notChild);
-
- someRoot->addChild(varPath); //left
- someRoot->addChild(notRoot); //right
- top->addChild(someRoot);
- }
- else if (i->children.size() == 3) {
- // child 1: left 0
- // child 2: root(i.e ==,!=) +1
- // child 3: right +2
- AstRoot* someRoot = createRootNode( i->children.begin() + 1, rule_names );
- Ast* left = doCreateAst( i->children.begin(), rule_names, someRoot );
- Ast* right = doCreateAst( i->children.begin() + 2, rule_names, someRoot );
- if (left) someRoot->addChild(left);
- if (right) someRoot->addChild(right);
- top->addChild(someRoot);
- }
- else if (i->children.size() == 2 &&
- (i->children.begin()->value.id() == ExpressionGrammer::not1_ID ||
- i->children.begin()->value.id() == ExpressionGrammer::not2_ID)
- ) {
- // child 1: not 0
- // child 2: left +1
- AstRoot* someRoot = createRootNode( i->children.begin(), rule_names );
- Ast* left = doCreateAst( i->children.begin() + 1, rule_names, someRoot );
- if (left) someRoot->addChild(left);
- top->addChild(someRoot);
- }
- else {
- return createAst(i,rule_names);
- }
- return NULL;
-}
-
-AstTop* createAst( tree_parse_info< > info,
- const std::string& expr,
- const std::map< parser_id, std::string >& rule_names
-)
-{
-#if defined(PRINT_AST_TRAVERSAL)
- std::cout << "\nPRINT_AST_TRAVERSAL " << expr << "\n";
-#endif
-
- std::auto_ptr<AstTop> ast(new AstTop);
- (void)doCreateAst(info.trees.begin(),rule_names,ast.get());
-
-#if defined(PRINT_AST)
- if (ast.get()) {
- std::cout << "\nPRINT_AST " << expr << "\n";
- std::cout << *ast.get();
- }
-#endif
- return ast.release();
-}
-
-///////////////////////////////////////////////////////////////////////////
-// SimpleExprParser
-//////////////////////////////////////////////////////////////////////////
-
-bool has_complex_expressions(const std::string& expr)
-{
- // we allow . and /
- if (expr.find('(') != string::npos) return true;
- if (expr.find(':') != string::npos) return true;
- if (expr.find('.') != string::npos) return true;
- if (expr.find('/') != string::npos) return true;
- if (expr.find(" not ") != string::npos) return true;
- if (expr.find(" and ") != string::npos) return true;
- if (expr.find(" or ") != string::npos) return true;
- if (expr.find('!') != string::npos) return true;
- if (expr.find("&&") != string::npos) return true;
- if (expr.find("||") != string::npos) return true;
- if (expr.find('<') != string::npos) return true;
- if (expr.find('>') != string::npos) return true;
- if (expr.find('+') != string::npos) return true;
- if (expr.find('-') != string::npos) return true;
- if (expr.find('*') != string::npos) return true;
- if (expr.find('~') != string::npos) return true;
- if (expr.find(" ne ") != string::npos) return true;
- if (expr.find(" ge ") != string::npos) return true;
- if (expr.find("<=") != string::npos) return true;
- if (expr.find(">=") != string::npos) return true;
- if (expr.find(" le ") != string::npos) return true;
- if (expr.find(" gt ") != string::npos) return true;
- if (expr.find(" lt ") != string::npos) return true;
- return false;
-}
-
-bool SimpleExprParser::doParse()
-{
- // 3199.def 57Mg
- // a == b, || a eq b i.e simple 76940
- // complex 39240
- if (has_complex_expressions(expr_)) {
- return false;
- }
-
- // look for path == <state> || path eq state
- // This gets round issue with Str::split:
- // "a = complete" will be split
- // since will split on *ANY* of character, and hence this would not be reported as an error
- std::vector<std::string> tokens;
- if (expr_.find("==") != string::npos) {
- Str::split(expr_, tokens, "==");
- }
- else if (expr_.find(" eq ") != string::npos) {
- Str::split(expr_, tokens, " eq ");
- }
- else {
- return false;
- }
-
- if (tokens.size() == 2) {
-
- boost::algorithm::trim(tokens[0]);
- boost::algorithm::trim(tokens[1]);
-
- if (tokens[0].find(' ') != string::npos) {
-// cout << "Found space " << expr_ << "\n";
- return false;
- }
-
- if (DState::isValid(tokens[1])) {
-
- ast_.reset(new AstTop);
- Ast* someRoot = new AstEqual();
- someRoot->addChild(new AstNode(tokens[0]));
- someRoot->addChild(new AstNodeState(DState::toState(tokens[1])));
- ast_->addChild(someRoot);
-// cout << "simple expr : " << expr_ << " `" << tokens[0] << "' = '" << tokens[1] << "'\n";
- return true;
- }
- else {
- try {
- int left = boost::lexical_cast<int>(tokens[0]);
- int right = boost::lexical_cast<int>(tokens[1]);
- ast_.reset(new AstTop);
- Ast* someRoot = new AstEqual();
- someRoot->addChild(new AstInteger(left));
- someRoot->addChild(new AstInteger(right));
- ast_->addChild(someRoot);
-// cout << "simple INT expr : " << expr_ << " `" << tokens[0] << "' = '" << tokens[1] << "'\n";
- return true;
- }
- catch ( boost::bad_lexical_cast& e ) {
-// cout << "simple INT FAILED expr : " << expr_ << " `" << tokens[0] << "' = '"
-// << tokens[1] << "'\n";
- }
- }
- }
- return false;
-}
diff --git a/ecflow_4_0_7/ANode/src/ExprParser.hpp b/ecflow_4_0_7/ANode/src/ExprParser.hpp
deleted file mode 100644
index a8e0f92..0000000
--- a/ecflow_4_0_7/ANode/src/ExprParser.hpp
+++ /dev/null
@@ -1,64 +0,0 @@
-#ifndef EXPRPARSER_HPP_
-#define EXPRPARSER_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #12 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <string>
-#include <memory> // for auto_ptr
-#include <boost/noncopyable.hpp>
-#include "ExprAst.hpp"
-
-
-/// This class will parse a expression and create the abstract syntax tree
-/// It will own the AST unless specifically released calling ast();
-class ExprParser : private boost::noncopyable {
-public:
- ExprParser(const std::string& expression);
-
- /// Parse the expression, return true if parse OK false otherwise
- /// if false is returned, and error message is returned
- bool doParse(std::string& errorMsg);
-
- /// return the Abstract syntax tree, and release memory
- std::auto_ptr<AstTop> ast() { return ast_;}
-
- /// return the Abstract syntax tree, without release memory
- AstTop* getAst() const { return ast_.get();}
-
-private:
- std::auto_ptr<AstTop> ast_;
- std::string expr_;
-};
-
-// This class was added to mitigate the slowness of the boost classic spirit parser
-// we will recognise very simple expression, and bypass spirit. Very limited
-// But the simple expression do form a very large subset
-class SimpleExprParser : private boost::noncopyable {
-public:
- SimpleExprParser(const std::string& expression) : expr_(expression) {}
-
- /// Parse the expression, return true if parse OK false otherwise
- bool doParse();
-
- /// return the Abstract syntax tree, and release memory
- std::auto_ptr<AstTop> ast() { return ast_;}
-
-private:
- const std::string& expr_;
- std::auto_ptr<AstTop> ast_;
-};
-
-#endif
diff --git a/ecflow_4_0_7/ANode/src/Expression.cpp b/ecflow_4_0_7/ANode/src/Expression.cpp
deleted file mode 100644
index 8d8c5b0..0000000
--- a/ecflow_4_0_7/ANode/src/Expression.cpp
+++ /dev/null
@@ -1,237 +0,0 @@
-//============================================================================
-// Name : NodeTree.cpp
-// Author : Avi
-// Revision : $Revision: #18 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <assert.h>
-#include <sstream>
-
-#include "Expression.hpp"
-#include "Indentor.hpp"
-#include "ExprParser.hpp"
-#include "Ecf.hpp"
-#include "ExprAstVisitor.hpp"
-#include "Node.hpp"
-#include "Log.hpp"
-#include "PrintStyle.hpp"
-
-using namespace std;
-using namespace ecf;
-
-///////////////////////////////////////////////////////////////////////////////////////////
-
-std::string PartExpression::toString(const std::string& exprType) const
-{
- std::stringstream ss;
- ss << exprType; // trigger or complete
- switch (exp_type_) {
- case PartExpression::FIRST: ss << " ";break;
- case PartExpression::AND: ss << " -a ";break;
- case PartExpression::OR: ss << " -o ";break;
- default: assert(false); break;
- }
- ss << exp_ << "\n";
- return ss.str();
-}
-
-std::ostream& PartExpression::print(std::ostream& os,const std::string& exprType, bool isFree) const
-{
- Indentor in;
- Indentor::indent(os) << exprType;
- switch (exp_type_) {
- case PartExpression::FIRST: os << " ";break;
- case PartExpression::AND: os << " -a ";break;
- case PartExpression::OR: os << " -o ";break;
- default: assert(false); break;
- }
- os << exp_;
-
- if ( !PrintStyle::defsStyle()) {
- if (exp_type_ == PartExpression::FIRST) {
- if (isFree) os << " # free";
- }
- }
- os << "\n";
- return os;
-}
-
-std::auto_ptr<AstTop> PartExpression::parseExpressions(std::string& errorMsg) const
-{
- //#ifdef DEBUG
- // cout << "PartExpression::parseExpressions '" << exp_ << "'\n";
- //#endif
- if (!exp_.empty()) {
- ExprParser expressionParser(exp_);
- if (expressionParser.doParse( errorMsg)) {
-
- // returns new allocated memory, if no errors
- std::auto_ptr<AstTop> ast = expressionParser.ast();
-
- if (errorMsg.empty()) LOG_ASSERT(ast.get(),"");
- else LOG_ASSERT(!ast.get(), "");
-
- return ast;
- }
- }
- return std::auto_ptr<AstTop>();
-}
-
-//===========================================================================
-
-Expression::Expression(const std::string& expression)
-: makeFree_(false), state_change_no_(0), theCombinedAst_(0)
-{
- add(PartExpression(expression));
-}
-
-Expression::Expression(const PartExpression& exp)
-: makeFree_(false), state_change_no_(0),theCombinedAst_(0)
-{
- add(exp);
-}
-
-Expression::Expression()
-: makeFree_(false), state_change_no_(0), theCombinedAst_(0) {}
-
-Expression::Expression(const Expression& rhs)
-: vec_(rhs.vec_), makeFree_(rhs.makeFree_), state_change_no_(0),theCombinedAst_(0) {}
-
-std::ostream& Expression::print(std::ostream& os, const std::string& exprType) const
-{
- BOOST_FOREACH(const PartExpression& expr, vec_ ) {
- expr.print(os,exprType,makeFree_);
- }
- return os;
-}
-
-std::string Expression::expression() const
-{
- string ret;
- std::vector<PartExpression>::const_iterator theEnd = vec_.end();
- for(std::vector<PartExpression>::const_iterator expr = vec_.begin(); expr!= theEnd; ++expr) {
- if ( (*expr).andExpr() ) ret += " AND ";
- else if ( (*expr).orExpr() ) ret += " OR ";
- ret += (*expr).expression();
- }
- return ret;
-}
-
-void Expression::add(const PartExpression& t)
-{
- if (vec_.empty()) {
- // The first expression should not have AND or OR
- if (t.andExpr() || t.orExpr()) {
- std::stringstream ss;
- ss << "Expression::add: expression " << t.expression() << " failed: The first expression should not have AND or OR set";
- throw std::runtime_error( ss.str() );
- }
- }
- else {
- // Subsequent expression must be AND or OR expressions
- if (!t.andExpr() && !t.orExpr()) {
- std::stringstream ss;
- ss << "Expression::add: expression " << t.expression() << " failed: Subsequent expression must have AND or OR set";
- throw std::runtime_error( ss.str() );
- }
- }
- vec_.push_back(t);
- // cout << "Expression::add " << expression() << "\n";
-}
-
-// ============================================================================
-// CREATE AST tree for each expression, and COMBINE AST for each expression into a single AST.
-// ============================================================================
-void Expression::createAST( Node* node, const std::string& exprType, std::string& errorMsg ) const
-{
- size_t theSize = vec_.size();
- for(size_t i = 0; i < theSize; i++) {
- std::string localErrorMsg;
- std::auto_ptr<AstTop> ast = vec_[i].parseExpressions( localErrorMsg );
- if ( ast.get() ) {
-
- // We can have multiple trigger/complete expression, combine to a single AST tree
- if (theCombinedAst_.get()) {
- // Must be trigger with -a(and) or -o(or) option's
- LOG_ASSERT(theCombinedAst_->isTop(),"");
- LOG_ASSERT(ast->isTop(),"");
- /* Combine AST tree
- top top2 (this top needs to be deleted) top top2
- | | ===> | |
- root1 root2 newRoot NULL;
- / \
- root1 root2
- */
- Ast* newRoot = NULL;
- if ( vec_[i].andExpr() ) newRoot = new AstAnd();
- else if ( vec_[i].orExpr() ) newRoot = new AstOr();
- else LOG_ASSERT(false,""); // what else can it be.
-
- if ( newRoot ) {
- newRoot->addChild(theCombinedAst_->left());
- newRoot->addChild(ast->left());
- theCombinedAst_->addChild(newRoot); // will overwrite
-
- // Since we have transferred over root2 it must be set to NULL for top2,
- // to avoid its child destruction
- ast->addChild(NULL); // since its an auto_ptr, no need for explicit delete
- }
- }
- else {
- // The very first expression should _NOT_ be AND/OR trigger. (i.e no -o | -a)
- LOG_ASSERT((!vec_[i].andExpr()) && (!vec_[i].orExpr()), "");
- theCombinedAst_ = ast; // transfer ownership
- theCombinedAst_->exprType(exprType);
- }
- // cout << "****************************************************************\n";
- // cout << theCombinedAst->expression() << "\n";
- // cout << *theCombinedAst << "\n";
- }
- else {
- std::stringstream ss;
- ss << "Failed to parse " << vec_[i].toString(exprType) << " at " << node->debugNodePath()
- << " because " << localErrorMsg << "\n\n";
- errorMsg += ss.str();
- }
- }
-
- if ( theCombinedAst_.get() ) {
- theCombinedAst_->setParentNode(node);
- }
-}
-
-void Expression::setFree()
-{
- // Only update for a real change
- if (!makeFree_) {
- state_change_no_ = Ecf::incr_state_change_no();
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Expression::setFree()\n";
-#endif
- }
- makeFree_ = true;
-}
-
-void Expression::clearFree()
-{
- // Only update for a real change
- if (makeFree_) {
- state_change_no_ = Ecf::incr_state_change_no();
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Expression::clearFree()\n";
-#endif
- }
- makeFree_ = false;
-}
-
diff --git a/ecflow_4_0_7/ANode/src/Expression.hpp b/ecflow_4_0_7/ANode/src/Expression.hpp
deleted file mode 100644
index 4bb1f77..0000000
--- a/ecflow_4_0_7/ANode/src/Expression.hpp
+++ /dev/null
@@ -1,153 +0,0 @@
-#ifndef EXPRESSION_HPP_
-#define EXPRESSION_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #20 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <ostream>
-#include <memory> // for auto_ptr
-
-#include <boost/serialization/serialization.hpp>
-#include <boost/serialization/vector.hpp> // no need to include <vector>
-#include <boost/serialization/string.hpp> // no need to include <string>
-
-#include "ExprAst.hpp"
-class Node;
-
-/// class PartExpression:
-/// Hold a single expression, optional can specify whether it is to be And' or
-/// 'Ored' when used as a part of a larger expression.
-/// Uses compiler , generated destructor, assignment, copy constructor
-class PartExpression {
-public:
- enum ExprType { FIRST, AND, OR };
-
- PartExpression(const std::string& expression)
- : exp_(expression), exp_type_(FIRST) {}
-
- PartExpression(const std::string& expression, bool and_type)
- : exp_(expression), exp_type_( (and_type) ? AND : OR) {}
-
- PartExpression()
- : exp_type_(FIRST) {}
-
- const std::string& expression() const { return exp_;}
- bool andExpr() const { return (exp_type_ == AND) ? true : false ;}
- bool orExpr() const { return (exp_type_ == OR) ? true : false ;}
-
- std::string toString(const std::string& exprType) const;
- std::ostream& print(std::ostream&,const std::string& exprType,bool isFree) const;
-
- bool operator==(const PartExpression& rhs) const {
- return exp_type_ == rhs.exp_type_ && exp_ == rhs.exp_;
- }
- bool operator!=(const PartExpression& rhs) const { return !operator==(rhs); }
-
- /// Parse the expression and create the abstract syntax tree
- std::auto_ptr<AstTop> parseExpressions(std::string& errorMsg) const;
-
-private:
- std::string exp_;
- ExprType exp_type_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/)
- {
- ar & exp_;
- ar & exp_type_;
- }
-};
-
-////////////////////////////////////////////////////////////////////////////////////////
-// Class Expression:
-// A Expression occur in a Trigger or Complete statement
-// This class hold a number of part expression.
-// It can also create a single AST from the part expressions
-// NOTE: Distinguish between parser errors, and node path resolution
-// Here we are only concerned with parser errors.
-// Use compiler , generated destructor, assignment, copy constructor
-class Expression {
-public:
- Expression(const std::string& expression);
- Expression(const PartExpression& );
- Expression();
- Expression(const Expression& rhs);
-
- bool operator==( const Expression& rhs) const{
- if (makeFree_ != rhs.makeFree_) return false;
- return vec_ == rhs.vec_;
- }
- bool operator!=( const Expression& rhs) const {
- return !operator==(rhs);
- }
-
- /// User should add "trigger" or "complete" at the start.
- /// The part expression's are combined and returned as a single string
- std::string expression() const;
-
- /// Need to pass in trigger tag, since expression may be split over multiple lines
- /// trigger "a == complete"
- /// trigger -a "b == complete"
- std::ostream& print(std::ostream&,const std::string& exprType) const;
-
- /// Use when we want to add compose a large expression form a set of smaller ones
- void add( const PartExpression& t );
-
- // ==============================================================================================
- // CREATE AST tree for each expression and COMBINE AST for each expression into a single AST.
- // ==============================================================================================
- void createAST( Node* parent_node, const std::string& exprType, std::string& errorMsg ) const;
- AstTop* get_ast() const { return theCombinedAst_.get(); } // can return NULL
-
- /// Placed here rather than the expression tree. Since the expression
- /// tree is created on demand, and is not persisted
- void setFree(); // hence must be used before evaluate
- void clearFree(); // resets the free flag
- bool isFree() const { return makeFree_;}
-
- // The state_change_no is never reset. Must be incremented if it can affect equality
- unsigned int state_change_no() const { return state_change_no_; }
-
-private: /// For use by python interface,
- friend void export_Node();
- std::vector<PartExpression>::const_iterator part_begin() const { return vec_.begin();}
- std::vector<PartExpression>::const_iterator part_end() const { return vec_.end();}
-
-private:
- std::vector<PartExpression> vec_;
- bool makeFree_;
-
- unsigned int state_change_no_; // *not* persisted, only used on server side
-
- // They are created on demand. reasons:
- // 1/ Help with AIX serialisation
- // 2/ Help to reduce network traffic
- mutable std::auto_ptr< AstTop > theCombinedAst_; // *not* persisted, demand created
-
-private:
- // prevent assignment since we have an auto_ptr
- Expression& operator=(Expression const& f);
-
-private:
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/)
- {
- ar & vec_;
- ar & makeFree_;
- }
-};
-#endif
diff --git a/ecflow_4_0_7/ANode/src/Family.cpp b/ecflow_4_0_7/ANode/src/Family.cpp
deleted file mode 100644
index 800bd30..0000000
--- a/ecflow_4_0_7/ANode/src/Family.cpp
+++ /dev/null
@@ -1,202 +0,0 @@
-//============================================================================
-// Name : NodeTree.cpp
-// Author : Avi
-// Revision : $Revision: #64 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <assert.h>
-#include <sstream>
-#include <boost/make_shared.hpp>
-
-#include "Family.hpp"
-#include "Log.hpp"
-#include "PrintStyle.hpp"
-#include "NodeTreeVisitor.hpp"
-#include "ChangeMgrSingleton.hpp"
-#include "Ecf.hpp"
-
-#include "Stl.hpp"
-#include "Str.hpp"
-#include "Indentor.hpp"
-#include "DefsDelta.hpp"
-#include "JobProfiler.hpp"
-#include "JobsParam.hpp"
-
-using namespace ecf;
-using namespace std;
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// The false below is used as a dummy argument to call the Variable constructor that does not
-// Check the variable names. i.e we know they are valid
-Family::~Family()
-{
- // Don't create the ChangeMgrSingleton during destruct sequence. (i.e in unit cases)
- // Since that will cause a memory leak
- if (!Ecf::server() && ChangeMgrSingleton::exists()) {
- ChangeMgrSingleton::instance()->notify_delete( this );
- }
-
- delete fam_gen_variables_;
-}
-
-family_ptr Family::create(const std::string& name)
-{
- return boost::make_shared<Family>( name );
-}
-
-void Family::accept(ecf::NodeTreeVisitor& v)
-{
- v.visitFamily(this);
- NodeContainer::accept(v);
-}
-
-void Family::acceptVisitTraversor(ecf::NodeTreeVisitor& v)
-{
- v.visitFamily(this);
-}
-
-void Family::begin()
-{
- NodeContainer::begin();
- update_generated_variables();
-}
-
-bool Family::resolveDependencies(JobsParam& jobsParam)
-{
- if (jobsParam.timed_out_of_job_generation()) return false;
- JobProfiler profile_me(jobsParam);
- if (jobsParam.timed_out_of_job_generation()) return false;
-
- return NodeContainer::resolveDependencies(jobsParam);
-}
-
-void Family::requeue(bool resetRepeats, int clear_suspended_in_child_nodes, bool reset_next_time_slot)
-{
- NodeContainer::requeue(resetRepeats,clear_suspended_in_child_nodes,reset_next_time_slot);
- update_generated_variables();
-}
-
-bool Family::operator==(const Family& rhs) const
-{
- return NodeContainer::operator==(rhs);
-}
-
-std::ostream& Family::print(std::ostream& os) const
-{
- // Generated variable are not persisted since they are created on demand
- // There *NO* point in printing them they will always be empty
-
- Indentor in;
- Indentor::indent(os) << "family " << name();
- if (!PrintStyle::defsStyle()) {
- std::string st = write_state();
- if (!st.empty()) os << " #" << st;
- }
- os << "\n";
-
- Node::print(os);
- NodeContainer::print(os);
- Indentor::indent(os) << "endfamily\n";
- return os;
-}
-
-std::string Family::write_state() const
-{
- return NodeContainer::write_state();
-}
-void Family::read_state(const std::string& line,const std::vector<std::string>& lineTokens)
-{
- NodeContainer::read_state(line,lineTokens);
-}
-
-const std::string& Family::debugType() const { return ecf::Str::FAMILY();}
-
-std::ostream& operator<<(std::ostream& os, const Family& d) { return d.print(os); }
-
-void Family::collateChanges(DefsDelta& changes) const
-{
- /// All changes to family should be on ONE compound_memento_ptr
- compound_memento_ptr compound;
- NodeContainer::incremental_changes(changes, compound);
-
- // Traversal
- NodeContainer::collateChanges(changes);
-}
-
-// generated variables --------------------------------------------------------------------------
-
-void Family::update_generated_variables() const
-{
- if (!fam_gen_variables_) fam_gen_variables_ = new FamGenVariables(this);
- fam_gen_variables_->update_generated_variables();
- update_repeat_genvar();
-}
-
-const Variable& Family::findGenVariable(const std::string& name) const
-{
- // Generally it should be never the case that the values are empty
- // Since the user is assumed to have called begin(), which force
- // the generation of generated variables
-
- // AST can reference generated variables. Currently integer based values
- // The family names can be integers
-
- if (!fam_gen_variables_) update_generated_variables();
- const Variable& gen_var = fam_gen_variables_->findGenVariable(name);
- if (!gen_var.empty()) return gen_var;
-
- return NodeContainer::findGenVariable(name);
-}
-
-void Family::gen_variables(std::vector<Variable>& vec) const
-{
- if (!fam_gen_variables_) update_generated_variables();
-
- vec.reserve(vec.size() + 3);
- fam_gen_variables_->gen_variables(vec);
- NodeContainer::gen_variables(vec);
-}
-
-// ================================================================
-
-FamGenVariables::FamGenVariables(const Family* f)
- : family_(f),
- genvar_family_("FAMILY", "", false),
- genvar_family1_("FAMILY1", "", false) {}
-
-void FamGenVariables::update_generated_variables() const
-{
- // This function is called during:
- // o begin()
- // o requeue()
- // Since family generated not persisted, allow for demand creation by client
- genvar_family1_.set_value(family_->name());
-
- // FAMILY is the full path excluding the suite, there is *NO* leading slash
- std::string path = family_->absNodePath();
- string::size_type secondSlash = path.find('/',1);
- path.erase(0,secondSlash+1);
- genvar_family_.set_value(path);
-}
-
-const Variable& FamGenVariables::findGenVariable(const std::string& name) const
-{
- if (genvar_family_.name() == name) return genvar_family_;
- if (genvar_family1_.name() == name) return genvar_family1_;
- return Variable::EMPTY();
-}
-
-void FamGenVariables::gen_variables(std::vector<Variable>& vec) const
-{
- vec.push_back(genvar_family_);
- vec.push_back(genvar_family1_);
-}
diff --git a/ecflow_4_0_7/ANode/src/Family.hpp b/ecflow_4_0_7/ANode/src/Family.hpp
deleted file mode 100644
index ee389ce..0000000
--- a/ecflow_4_0_7/ANode/src/Family.hpp
+++ /dev/null
@@ -1,86 +0,0 @@
-#ifndef FAMILY_HPP_
-#define FAMILY_HPP_
-
-//============================================================================
-// Name : NodeTree.hpp
-// Author : Avi
-// Revision : $Revision: #37 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "NodeContainer.hpp"
-class FamGenVariables;
-
-class Family : public NodeContainer {
-public:
- Family( const std::string& name ) : NodeContainer(name),fam_gen_variables_(NULL) {}
- Family() : fam_gen_variables_(NULL) {}
- virtual ~Family();
-
- static family_ptr create(const std::string& name);
-
- virtual Suite* suite() const { return parent()->suite(); }
- virtual Defs* defs() const { return (parent()) ? parent()->defs() : NULL;} // exposed to python hence check for NULL first
- virtual Family* isFamily() const { return const_cast<Family*>(this);}
- virtual NodeContainer* isNodeContainer() const { return const_cast<Family*>(this); }
-
- virtual void begin();
- virtual bool resolveDependencies(JobsParam& ); // overriden to speicy family for job profiler
- virtual void requeue(bool resetRepeats, int clear_suspended_in_child_nodes, bool reset_next_time_slot);
- virtual void accept(ecf::NodeTreeVisitor&);
- virtual void acceptVisitTraversor(ecf::NodeTreeVisitor& v);
- virtual void update_generated_variables() const;
- virtual const Variable& findGenVariable(const std::string& name) const;
- virtual void gen_variables(std::vector<Variable>&) const;
-
- virtual const std::string& debugType() const;
-
- std::ostream& print(std::ostream&) const;
- bool operator==(const Family& rhs) const;
-
- virtual void collateChanges(DefsDelta&) const;
- void set_memento(const OrderMemento* m) { NodeContainer::set_memento(m); }
- void set_memento(const ChildrenMemento* m) { NodeContainer::set_memento(m); }
-
- virtual void read_state(const std::string& line,const std::vector<std::string>& lineTokens);
-private:
- virtual std::string write_state() const;
-
- mutable FamGenVariables* fam_gen_variables_;
-
-private:
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/) {
- ar & boost::serialization::base_object<NodeContainer>(*this);
- }
-};
-
-std::ostream& operator<<(std::ostream& os, const Family&);
-
-
-// We can have several thousands Families. This class helps in avoiding
-// the creation of generated variables until required.
-// This improves client->server down load times by avoiding thousands of string constructions
-class FamGenVariables : private boost::noncopyable {
-public:
- FamGenVariables(const Family*);
-
- void update_generated_variables() const;
- const Variable& findGenVariable(const std::string& name) const;
- void gen_variables(std::vector<Variable>& vec) const;
-
-private:
- const Family* family_;
- mutable Variable genvar_family_;
- mutable Variable genvar_family1_;
-};
-#endif
diff --git a/ecflow_4_0_7/ANode/src/Flag.cpp b/ecflow_4_0_7/ANode/src/Flag.cpp
deleted file mode 100644
index b40d1d7..0000000
--- a/ecflow_4_0_7/ANode/src/Flag.cpp
+++ /dev/null
@@ -1,164 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #12 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <stdexcept>
-#include <iostream>
-#include "Flag.hpp"
-#include "Ecf.hpp"
-#include "Str.hpp"
-
-namespace ecf {
-
-void Flag::set(Flag::Type flag)
-{
- if (!is_set(flag)) {
- // minimize changes to state_change_no_
- flag_ |= (1<<flag);
- state_change_no_ = Ecf::incr_state_change_no();
- }
-}
-
-void Flag::clear(Flag::Type flag )
-{
- if (is_set(flag)) {
- // minimize changes to state_change_no_
- flag_ &= ~(1<<flag);
- state_change_no_ = Ecf::incr_state_change_no();
- }
-}
-
-void Flag::reset() {
- flag_ = 0;
- state_change_no_ = Ecf::incr_state_change_no();
-}
-
-std::vector<Flag::Type> Flag::list()
-{
- std::vector<Flag::Type> ret; ret.reserve(15);
- ret.push_back(Flag::FORCE_ABORT);
- ret.push_back(Flag::USER_EDIT);
- ret.push_back(Flag::TASK_ABORTED);
- ret.push_back(Flag::JOBCMD_FAILED);
- ret.push_back(Flag::NO_SCRIPT);
- ret.push_back(Flag::KILLED);
- ret.push_back(Flag::MIGRATED);
- ret.push_back(Flag::LATE);
- ret.push_back(Flag::MESSAGE);
- ret.push_back(Flag::BYRULE);
- ret.push_back(Flag::QUEUELIMIT);
- ret.push_back(Flag::WAIT);
- ret.push_back(Flag::LOCKED);
- ret.push_back(Flag::ZOMBIE);
- ret.push_back(Flag::NO_REQUE_IF_SINGLE_TIME_DEP);
- return ret;
-}
-
-std::string Flag::enum_to_string(Flag::Type flag) {
-
- switch ( flag ) {
- case Flag::FORCE_ABORT: return "force_aborted"; break;
- case Flag::USER_EDIT : return "user_edit"; break;
- case Flag::TASK_ABORTED: return "task_aborted"; break;
- case Flag::EDIT_FAILED: return "edit_failed"; break;
- case Flag::JOBCMD_FAILED:return "ecfcmd_failed"; break;
- case Flag::NO_SCRIPT: return "no_script"; break;
- case Flag::KILLED: return "killed"; break;
- case Flag::MIGRATED: return "migrated"; break;
- case Flag::LATE: return "late"; break;
- case Flag::MESSAGE: return "message"; break;
- case Flag::BYRULE: return "by_rule"; break;
- case Flag::QUEUELIMIT: return "queue_limit"; break;
- case Flag::WAIT: return "task_waiting"; break;
- case Flag::LOCKED: return "locked"; break;
- case Flag::ZOMBIE: return "zombie"; break;
- case Flag::NO_REQUE_IF_SINGLE_TIME_DEP: return "no_reque"; break;
- case Flag::NOT_SET: return "not_set"; break;
- default: break;
- };
- return std::string();
-}
-
-
-Flag::Type Flag::string_to_flag_type(const std::string& s)
-{
- if (s == "force_aborted") return Flag::FORCE_ABORT;
- if (s == "user_edit") return Flag::USER_EDIT;
- if (s == "task_aborted") return Flag::TASK_ABORTED;
- if (s == "edit_failed") return Flag::EDIT_FAILED;
- if (s == "ecfcmd_failed") return Flag::JOBCMD_FAILED;
- if (s == "no_script") return Flag::NO_SCRIPT;
- if (s == "killed") return Flag::KILLED;
- if (s == "migrated") return Flag::MIGRATED;
- if (s == "late") return Flag::LATE;
- if (s == "message") return Flag::MESSAGE;
- if (s == "by_rule") return Flag::BYRULE;
- if (s == "queue_limit") return Flag::QUEUELIMIT;
- if (s == "task_waiting") return Flag::WAIT;
- if (s == "locked") return Flag::LOCKED;
- if (s == "zombie") return Flag::ZOMBIE;
- if (s == "no_reque") return Flag::NO_REQUE_IF_SINGLE_TIME_DEP;
- return Flag::NOT_SET;
-}
-
-void Flag::valid_flag_type(std::vector<std::string>& vec)
-{
- vec.reserve(15);
- vec.push_back("force_aborted");
- vec.push_back("user_edit");
- vec.push_back("task_aborted");
- vec.push_back("edit_failed");
- vec.push_back("ecfcmd_failed");
- vec.push_back("no_script");
- vec.push_back("killed");
- vec.push_back("migrated");
- vec.push_back("late");
- vec.push_back("message");
- vec.push_back("by_rule");
- vec.push_back("queue_limit");
- vec.push_back("task_waiting");
- vec.push_back("locked");
- vec.push_back("zombie");
- vec.push_back("no_reque");
-}
-
-std::string Flag::to_string() const
-{
- std::string ret;
- std::vector<Flag::Type> flag_list = Flag::list();
- for (size_t i = 0; i < flag_list.size(); ++i) {
- if ( is_set( flag_list[i] ) ) {
- if (!ret.empty()) ret += ',';
- ret += enum_to_string( flag_list[i]);
- }
- }
- return ret;
-}
-
-void Flag::set_flag(const std::string& flags)
-{
- std::vector< std::string > the_flags_vec;
- Str::split(flags,the_flags_vec,",");
-
- for(size_t i =0; i < the_flags_vec.size(); i++) {
- Flag::Type ft = string_to_flag_type(the_flags_vec[i]);
- if (ft == Flag::NOT_SET) {
- throw std::runtime_error("Flag::set_flag: Unknown flag types found: " + the_flags_vec[i]);
- }
- set(ft);
- }
-}
-
-
-}
diff --git a/ecflow_4_0_7/ANode/src/Flag.hpp b/ecflow_4_0_7/ANode/src/Flag.hpp
deleted file mode 100644
index d1e5bfc..0000000
--- a/ecflow_4_0_7/ANode/src/Flag.hpp
+++ /dev/null
@@ -1,119 +0,0 @@
-#ifndef FLAG_HPP_
-#define FLAG_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #15 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <vector>
-#include <string>
-#include <boost/serialization/serialization.hpp>
-#include <boost/serialization/level.hpp>
-#include <boost/serialization/tracking.hpp>
-
-namespace ecf {
-
-/// Flag are used store what has happened to a node. These are shown as icon in ecFlowview
-/// Uses compiler generated copy constructor, assignment operator and destructor
-
-/// During interactive use. A Node can be *forced to complete*, or forced to *run*
-/// Typically the user may want to force a node to complete, if they are trying
-/// to update the repeat variable.
-///
-/// In either case we need to miss a time slot, this is done by setting the
-/// NO_REQUE_IF_SINGLE_TIME_DEP, then at REQUE time we query the flag, if it was set
-/// we avoid resetting the time slots. effectively missing the next time slot.
-///
-/// This functionality is only required during interactive force or run
-/// However if the job aborted, we need to clear NO_REQUE_IF_SINGLE_TIME_DEP, i.e
-/// time 10:00
-/// time 11:00
-/// If at 9.00am use the run command, we want to miss the 10:00 time slot.
-/// However if the run at 9.00 fails, and we run again, we also miss 11:00 time slot
-/// to avoid this if the job aborts, we clear NO_REQUE_IF_SINGLE_TIME_DEP flag.
-
-class Flag {
-public:
- Flag() : flag_(0),state_change_no_(0) {}
-
- /// The BYRULE is used to distinguish between tasks that have RUN and completed
- /// and those that have completed by complete expression.
- enum Type {
- FORCE_ABORT = 0, // Node*
- USER_EDIT = 1, // task
- TASK_ABORTED = 2, // task*
- EDIT_FAILED = 3, // task*
- JOBCMD_FAILED = 4, // task*
- NO_SCRIPT = 5, // task*
- KILLED = 6, // task*
- MIGRATED = 7, // Node ( NOT USED currently)
- LATE = 8, // Node attribute, Task is late, or Defs checkpt takes to long
- MESSAGE = 9, // Node
- BYRULE = 10, // Node*, set if node is set to complete by complete trigger expression
- QUEUELIMIT = 11, // Node attribute, ???? change this to propagate to node
- WAIT = 12, // task*
- LOCKED = 13, // Server
- ZOMBIE = 14, // task*
- NO_REQUE_IF_SINGLE_TIME_DEP = 15, //
- NOT_SET = 16
- };
-
- bool operator==(const Flag& rhs) const { return flag_ == rhs.flag_; }
- bool operator!=(const Flag& rhs) const { return !operator==(rhs); }
-
-
- // Flag functions:
- void set(Type flag);
- void clear(Type flag );
- bool is_set(Type flag) const { return ( flag_ & (1 << flag)); }
-
- void reset();
- int flag() const { return flag_;}
- void set_flag(int f) { flag_ = f; }
- void set_flag(const std::string& flags); // these are comma seperated
-
- /// returns a comma separated list of all flags set
- std::string to_string() const;
-
- /// returns the string equivalent
- static std::string enum_to_string(Flag::Type flag);
-
- /// Used to determine change in state relative to client
- unsigned int state_change_no() const { return state_change_no_; }
-
- /// returns the list of all flag types
- static std::vector<Flag::Type> list();
-
- /// Converts from string to flag types.
- static Flag::Type string_to_flag_type(const std::string& s);
-
- /// valid flag types, than can be used in AlterCmd
- static void valid_flag_type(std::vector<std::string>& vec);
-
-private:
- int flag_;
- unsigned int state_change_no_; // *not* persisted, only used on server side
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/) {
- ar & flag_;
- }
-};
-}
-
-// This should ONLY be added to objects that are *NOT* serialised through a pointer
-BOOST_CLASS_IMPLEMENTATION(ecf::Flag, boost::serialization::object_serializable)
-BOOST_CLASS_TRACKING(ecf::Flag,boost::serialization::track_never);
-
-#endif
diff --git a/ecflow_4_0_7/ANode/src/InLimit.cpp b/ecflow_4_0_7/ANode/src/InLimit.cpp
deleted file mode 100644
index e09065b..0000000
--- a/ecflow_4_0_7/ANode/src/InLimit.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #64 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <assert.h>
-#include <sstream>
-#include <stdexcept>
-
-#include "InLimit.hpp"
-#include "Limit.hpp"
-#include "Indentor.hpp"
-#include "PrintStyle.hpp"
-#include "Str.hpp"
-#include "Ecf.hpp"
-
-using namespace std;
-using namespace ecf;
-
-/////////////////////////////////////////////////////////////////////////////////////////////
-
-InLimit::InLimit(const std::string& name, const std::string& pathToNode, int tokens)
-: name_(name),pathToNode_(pathToNode),tokens_(tokens)
-{
- if ( !Str::valid_name( name ) ) {
- throw std::runtime_error("InLimit::InLimit: Invalid InLimit name: " + name);
- }
-}
-
-bool InLimit::operator==( const InLimit& rhs ) const
-{
- if ( pathToNode_ != rhs.pathToNode_ ) {
- //#ifdef DEBUG
- // std::cout << "InLimit::operator== pathToNode_ != rhs.pathToNode_\n";
- //#endif
- return false;
- }
- if ( name_ != rhs.name_ ) {
- //#ifdef DEBUG
- // std::cout << "InLimit::operator== name_ != rhs.name_\n";
- //#endif
- return false;
- }
- if ( tokens_ != rhs.tokens_ ) {
- //#ifdef DEBUG
- // std::cout << "InLimit::operator== tokens_(" << tokens_ << ") != rhs.tokens_(" << rhs.tokens_ << ") \n";
- //#endif
- return false;
- }
-
- // Note: comparison does not look at Limit pointers
- return true;
-}
-
-std::ostream& InLimit::print( std::ostream& os ) const {
- Indentor in;
- Indentor::indent( os ) << toString();
- if ( PrintStyle::getStyle() == PrintStyle::STATE) {
- if ( limit() )
- os << " # referenced limit(value) " << limit()->theLimit() << "(" << limit()->value() << ")";
- }
- os << "\n";
- return os;
-}
-
-std::string InLimit::toString() const {
- std::stringstream ss;
- if ( pathToNode_.empty() ) ss << "inlimit " << name_;
- else ss << "inlimit " << pathToNode_ << Str::COLON() << name_;
- if ( tokens_ != 1 ) ss << " " << tokens_;
- return ss.str();
-}
-
diff --git a/ecflow_4_0_7/ANode/src/InLimit.hpp b/ecflow_4_0_7/ANode/src/InLimit.hpp
deleted file mode 100644
index 761240c..0000000
--- a/ecflow_4_0_7/ANode/src/InLimit.hpp
+++ /dev/null
@@ -1,72 +0,0 @@
-#ifndef INLIMIT_HPP_
-#define INLIMIT_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #61 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <ostream>
-
-#include <boost/serialization/serialization.hpp>
-#include <boost/serialization/string.hpp> // no need to include <string>
-#include <boost/serialization/weak_ptr.hpp>
-
-#include "LimitFwd.hpp"
-
-
-// Inlimit. Multiple inlimits on same Node are logically ANDED
-// inlimit limitName // This will consume one token in the limit <limitName>
-// inlimit limitName 10 // This will consume 10 tokens in the limit <limitName>
-// inlimit -n limitName // Only applicable to a family, does not matter how many tasks
-// // the family has, will only consume one token in the family
-// // This is like showing that family is active/ has at least
-// // one task that is submitted <<<<NOT SUPPORTED YET>>>>>>
-//
-// Inlimit of the same name specified on a task take priority over the family
-class InLimit {
-public:
- InLimit(const std::string& name,
- const std::string& pathToNode = std::string(),
- int tokens = 1);
- InLimit() : tokens_(1) {}
-
- std::ostream& print(std::ostream&) const;
- bool operator==(const InLimit& rhs) const;
-
- const std::string& name() const { return name_;} // must be defined
- const std::string& pathToNode() const { return pathToNode_;} // can be empty,the node referenced by the In-Limit, this should hold the Limit.
- int tokens() const { return tokens_;}
-
- std::string toString() const;
-
-private:
- void limit( limit_ptr l) { limit_ = boost::weak_ptr<Limit>(l);}
- Limit* limit() const { return limit_.lock().get();} // can return NULL
- friend class InLimitMgr;
-
-private:
- std::string name_;
- std::string pathToNode_;
- int tokens_;
- boost::weak_ptr<Limit> limit_; // NOT persisted since computed on the fly
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/) {
- ar & name_;
- ar & pathToNode_; // can be empty
- ar & tokens_;
- }
-};
-
-#endif
diff --git a/ecflow_4_0_7/ANode/src/InLimitMgr.cpp b/ecflow_4_0_7/ANode/src/InLimitMgr.cpp
deleted file mode 100644
index c759153..0000000
--- a/ecflow_4_0_7/ANode/src/InLimitMgr.cpp
+++ /dev/null
@@ -1,436 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #28 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <assert.h>
-#include <boost/foreach.hpp>
-#include <boost/make_shared.hpp>
-
-#include "InLimitMgr.hpp"
-#include "Limit.hpp"
-#include "Node.hpp"
-#include "Memento.hpp"
-#include "Ecf.hpp"
-#include "Str.hpp"
-
-using namespace ecf;
-using namespace std;
-
-///////////////////////////////////////////////////////////////////////////////////////////
-
-std::ostream& InLimitMgr::print(std::ostream& os) const
-{
- BOOST_FOREACH(const InLimit& i, inLimitVec_) { i.print(os); }
- return os;
-}
-
-bool InLimitMgr::operator==(const InLimitMgr& rhs) const
-{
- if (inLimitVec_.size() != rhs.inLimitVec_.size()) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "InLimitMgr::operator== inLimitVec_.size() != rhs.inLimitVec_.size() " << node_->debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- for(size_t i = 0; i < inLimitVec_.size(); ++i) {
- if (!(inLimitVec_[i] == rhs.inLimitVec_[i] )) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "InLimitMgr::operator== (!(inLimitVec_[i] == rhs.inLimitVec_[i] )) " << node_->debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- }
- return true;
-}
-
-void InLimitMgr::addInLimit(const InLimit& l )
-{
- if (!findInLimitByNameAndPath(l)) {
- inLimitVec_.push_back( l );
- return;
- }
- throw std::runtime_error( "Add InLimit failed: Duplicate InLimit see node " + node_->debugNodePath() );
-}
-
-bool InLimitMgr::deleteInlimit(const std::string& name)
-{
- if (name.empty()) {
- inLimitVec_.clear();
- return true;
- }
-
- for(size_t i = 0; i < inLimitVec_.size(); i++) {
- if (inLimitVec_[i].name() == name) {
- inLimitVec_.erase( inLimitVec_.begin() + i );
- return true;
- }
- }
- throw std::runtime_error("InLimitMgr::deleteInlimit: Can not find inlimit: " + name);
-}
-
-Limit* InLimitMgr::findLimitViaInLimit(const InLimit& theInLimit) const
-{
- // Use in *test* only
- size_t theSize = inLimitVec_.size();
- for(size_t i = 0; i < theSize; i++) {
- if (inLimitVec_[i].name() == theInLimit.name() && inLimitVec_[i].pathToNode() == theInLimit.pathToNode()) {
- resolveInLimit(inLimitVec_[i]);
- return inLimitVec_[i].limit() ;
- }
- }
- return NULL;
-}
-
-bool InLimitMgr::findInLimitByNameAndPath(const InLimit& theInLimit) const
-{
- size_t theSize = inLimitVec_.size();
- for(size_t i = 0; i < theSize; i++) {
- if (inLimitVec_[i].name() == theInLimit.name() && inLimitVec_[i].pathToNode() == theInLimit.pathToNode()) {
- return true;
- }
- }
- return false;
-}
-
-void InLimitMgr::get_memento( compound_memento_ptr& comp) const
-{
-#ifdef DEBUG_MEMENTO
- std::cout << "InLimitMgr::get_memento " << node_->debugNodePath() << "\n";
-#endif
-
- BOOST_FOREACH(const InLimit& l, inLimitVec_ ) { comp->add( boost::make_shared<NodeInLimitMemento>( l) ); }
-}
-
-
-bool InLimitMgr::inLimit() const
-{
- // Check in we are in limit.
- // ** WE need to do a lookahead. hence we pass down inlimit tokens **
- // In the case we have multiple inlimits
- // then we are only in limit if _ALL_ are in limit. This is like
- // a logical AND.
- if (!inLimitVec_.empty()) {
-
- resolveInLimitReferences();
-
- int inlimitsWithLimits = 0;
- int inlimitCount = 0;
- size_t theSize = inLimitVec_.size();
- for(size_t i = 0; i < theSize; i++ ) {
- Limit* limit = inLimitVec_[i].limit();
- if (limit) {
- inlimitsWithLimits++;
- if (limit->inLimit( inLimitVec_[i].tokens() )) {
- inlimitCount++;
- }
- }
- }
-
- return (inlimitsWithLimits == inlimitCount ) ;
- }
-
- return true;
-}
-
-void InLimitMgr::incrementInLimit( std::set<Limit*>& limitSet,const std::string& task_path) const
-{
-// cout << "InLimitMgr::incrementInLimit " << node_->absNodePath() << endl;
-
- // *NOTE* each limit is incremented if within LIMIT, and that
- // has not previously been updated.
- // we could have the same in limit at the task and family level.
- // in this case the task takes priority.
- // suite suite
- // family family
- // inlimit limitname 12
- // task t1
- // inlimit limitname 4
- // endfamily
- // endsuite
- //
- // In this case the limit <limitname> is incremented by 4 _only_
- //
- // Note: It is illegal for a node to have the same inlimit but with
- // different tokens:
- //
- // task t1
- // inlimit limitname 4
- // inlimit limitname 2 // illegal and trapped by parser
-
- resolveInLimitReferences();
-
- BOOST_FOREACH(const InLimit& inlimit, inLimitVec_) {
- Limit* limit = inlimit.limit();
- if (limit && limitSet.find(limit) == limitSet.end()) {
- limitSet.insert(limit);
- // cout << "InLimitMgr::incrementInLimit " << node_->absNodePath() << " LIMIT incremented " << endl;
- limit->increment( inlimit.tokens(), task_path);
- }
- }
-}
-
-void InLimitMgr::decrementInLimit( std::set<Limit*>& limitSet,const std::string& task_path) const
-{
- // *NOTE* each limit is incremented if within LIMIT, and that
- // has not previously been updated.
- // we could have the same in limit at the task and family level.
- // in this case the task takes priority.
- // suite suite
- // family family
- // inlimit limitname 12
- // task t1
- // inlimit limitname 4
- // endfamily
- // endsuite
- //
- // In this case the limit <limitname> is incremented by 4 _only_
- //
- // Note: It is illegal for a node to have the same inlimit but with
- // different tokens:
- //
- // task t1
- // inlimit limitname 4
- // inlimit limitname 2 // illegal and trapped by parser
- resolveInLimitReferences();
-
- BOOST_FOREACH(const InLimit& inlimit, inLimitVec_) {
- Limit* limit = inlimit.limit();
- if (limit && limitSet.find(limit) == limitSet.end()) {
- limitSet.insert(limit);
- // cout << "InLimitMgr::incrementInLimit " << node_->absNodePath() << " LIMIT incremented " << endl;
- limit->decrement( inlimit.tokens(), task_path);
- }
- }
-}
-
-
-//#define DEBUG_WHY 1
-
-static void add_consumed_paths(Limit* limit, std::stringstream& ss)
-{
- ss << "(";
- const std::set<std::string>& consumed_paths = limit->paths();
- int count = 0;
- for (std::set<std::string>::const_iterator i = consumed_paths.begin(); i!=consumed_paths.end(); ++i) {
- if ( 4 == count) { ss << "..."; break; }
- ss << (*i) << ",";
- count++;
- }
- ss << ")";
-}
-
-void InLimitMgr::why(std::vector<std::string>& vec) const
-{
-#ifdef DEBUG_WHY
- std::cout << "InLimitMgr::why " << node_->debugNodePath() << "\n";
-#endif
-
- // Note: if this correspond to a leaf node, like a task. Then it may not be
- // sufficient to just check in limits at this level. Will need to look up hierarchy.
- if (inLimit()) {
-#ifdef DEBUG_WHY
- std::cout << " Node " << node_->debugNodePath() << " is *in limit*, checking parent\n";
-#endif
- Node* theParent = node_->parent();
- while( theParent ) {
-
- if (theParent->check_in_limit()) {
-// std::cout << " Parent " << theParent->debugNodePath() << " is *in limit* \n";
- theParent = theParent->parent();
- }
- else {
-// std::cout << " Parent " << theParent->debugNodePath() << " Not in limit \n";
- for(size_t i = 0; i < theParent->inlimits().size(); i++ ) {
- Limit* limit = theParent->inlimits()[i].limit();
- if (limit && !limit->inLimit( theParent->inlimits()[i].tokens() )) {
- std::stringstream ss;
- if ( theParent->inlimits()[i].pathToNode().empty())
- ss << "limit " << limit->name() << " is full";
- else
- ss << "limit " << theParent->inlimits()[i].pathToNode() << Str::COLON() << limit->name() << " is full";
-
- // show node paths that have consumed a limit, Only show first 5, Otherwise string may be too long
- add_consumed_paths(limit,ss);
-
- vec.push_back(ss.str());
- }
- }
- break;
- }
- }
- }
- else {
-#ifdef DEBUG_WHY
- std::cout << " InLimitMgr::why " << node_->debugNodePath() << " NOT in limit\n";
-#endif
- for(size_t i = 0; i < inLimitVec_.size(); i++ ) {
- Limit* limit = inLimitVec_[i].limit();
- if (limit && !limit->inLimit(inLimitVec_[i].tokens())) {
- std::stringstream ss;
- if ( inLimitVec_[i].pathToNode().empty())
- ss << "limit " << limit->name() << " is full";
- else
- ss << "limit " << inLimitVec_[i].pathToNode() << Str::COLON() << limit->name() << " is full";
-
- // show node paths that have consumed a limit, Only show first 5, Otherwise string may be too long
- add_consumed_paths(limit,ss);
-
- vec.push_back(ss.str());
- }
- }
- }
-}
-
-void InLimitMgr::check(std::string& errorMsg, std::string& warningMsg,bool reportErrors, bool reportWarnings) const
-{
- size_t theSize = inLimitVec_.size();
- for(size_t i = 0; i < theSize; i++) {
- (void)find_limit(inLimitVec_[i], errorMsg, warningMsg, reportErrors, reportWarnings) ;
- }
-}
-
-void InLimitMgr::resolveInLimit(InLimit& inLimit,std::string& errorMsg, std::string& warningMsg,bool reportErrors, bool reportWarnings) const
-{
-// cout << "Inlimit " << inLimit.toString() << "\n";
-
- /// if limit pointer already setup use them. These are shared ptr backed, Hence if deleted beneath use should return 0;
- if (inLimit.limit()) {
-// cout << "InLimitMgr::resolveInLimit " << inLimit.toString() << " Reusing limit ptr \n";
- return;
- }
-
- /// Find the limit referenced by the InLimit. i.e. Link inLimit to its LIMIT
- /// The return value can be NULL
- limit_ptr referencedLimit = find_limit(inLimit,errorMsg,warningMsg,reportErrors,reportWarnings);
- inLimit.limit( referencedLimit );
-}
-
-void InLimitMgr::auto_add_inlimit_externs(Defs* defs) const
-{
- std::string errorMsg;
- std::string warningMsg;
- size_t theSize = inLimitVec_.size();
- for(size_t i = 0; i < theSize; i++) {
- limit_ptr referencedLimit = find_limit(inLimitVec_[i],errorMsg,warningMsg,false,false);
- if (!referencedLimit.get()) {
- if (inLimitVec_[i].pathToNode().empty()) defs->add_extern( inLimitVec_[i].name() );
- else defs->add_extern( inLimitVec_[i].pathToNode() + ":" + inLimitVec_[i].name());
- }
- }
-}
-
-limit_ptr InLimitMgr::find_limit(const InLimit& inLimit, std::string& errorMsg, std::string& warningMsg,bool reportErrors, bool reportWarnings) const
-{
- if (inLimit.pathToNode().empty()) {
-
- // cout << "inLimit.pathToNode().empty() search " << debugType() << " " << node_->absNodePath() << "\n";
- limit_ptr referencedLimit = node_->findLimitUpNodeTree( inLimit.name() );
- if ( referencedLimit.get() ) return referencedLimit;
-
- if (reportWarnings) {
-
- // See if the name is defined, as an extern, in which case *DONT* warn:
- // This is client side specific, since server does not have externs.
- if (node_->defs()->find_extern(inLimit.name(),Str::EMPTY())) {
- return referencedLimit; // this is empty/NULL
- }
-
- std::stringstream ss;
- ss << "Warning: ";
- ss << node_->debugType() << " " << node_->absNodePath() << " has a " << inLimit.toString() << ", which can not be found on the parent nodes\n";
- warningMsg += ss.str();
- }
- return referencedLimit; // this is empty/NULL
- }
-
- // *FIND* the node referenced by the In-Limit, this should hold the Limit.
- // cout << "Inlimit path not empty \n";
- string warning_message;
- node_ptr referenceNode = node_->findReferencedNode( inLimit.pathToNode(), inLimit.name(), warning_message);
- if (!referenceNode.get()) {
- /// Could not find the node which *HOLDS* the limit
- if (reportWarnings) {
-
- // OK a little bit of duplication, since findReferencedNode, will also look for externs
- // See if the Path:name is defined as an extern, in which case *DONT* warn:
- // This is client side specific, since server does not have externs.
- if (node_->defs()->find_extern(inLimit.pathToNode(),inLimit.name())) {
- return limit_ptr();
- }
-
- std::stringstream ss;
- ss << "Warning: " << node_->debugType() << " " << node_->absNodePath() << " has a " << inLimit.toString() << ", which can not be found\n";
- warningMsg += ss.str();
- }
- return limit_ptr();
- }
-
- // *FOUND* the node which should hold the Limit.
- limit_ptr referencedLimit = referenceNode->find_limit( inLimit.name() );
- if (!referencedLimit.get()) {
-
- // See if the name is defined, as an extern, in which case *DONT* warn:
- // This is client side specific, since server does not have externs.
- if (node_->defs()->find_extern(inLimit.pathToNode(),inLimit.name())) {
- return limit_ptr();
- }
-
- if (reportWarnings) {
- std::stringstream ss;
- ss << node_->debugType() << " " << node_->absNodePath() << " has a " << inLimit.toString() << " :";
- ss << "The referenced " << referenceNode->debugType() << " '" << referenceNode->absNodePath() << "' does not define the limit " << inLimit.name() << "\n";
- warning_message += ss.str();
- warningMsg += "Warning: ";
- warningMsg += warning_message;
- warningMsg += "\n";
- }
- return referencedLimit; // this is empty/NULL
- }
-
- // *FOUND* the referenced LIMIT. inlimit tokens must be less than limit.
- if ( inLimit.tokens() > referencedLimit->theLimit() ) {
- if (reportErrors) {
- // in limit exceeds the LIMIT value
- std::stringstream ss;
- ss << node_->debugType() << " " << node_->absNodePath() << " has a " << inLimit.toString() << " reference\n";
- ss << " with value '" << inLimit.tokens() << "' which exceeds '" << referencedLimit->theLimit() << "' defined on the Limit\n";
- errorMsg += ss.str();
- }
- }
- return referencedLimit;
-}
-
-void InLimitMgr::resolveInLimit(InLimit& inLimit) const
-{
- // Used in *test* only
- std::string errorMsg;
- std::string warningMsg;
- resolveInLimit(inLimit, errorMsg, warningMsg, false, false );
-}
-
-void InLimitMgr::resolveInLimitReferences() const
-{
- size_t theSize = inLimitVec_.size();
- if (theSize > 0) {
- std::string warningMsg;
- std::string errorMsg;
- for(size_t i = 0; i < theSize; i++) {
- resolveInLimit(inLimitVec_[i], errorMsg, warningMsg, false, false) ;
- }
- }
-}
-
diff --git a/ecflow_4_0_7/ANode/src/InLimitMgr.hpp b/ecflow_4_0_7/ANode/src/InLimitMgr.hpp
deleted file mode 100644
index 89eec05..0000000
--- a/ecflow_4_0_7/ANode/src/InLimitMgr.hpp
+++ /dev/null
@@ -1,131 +0,0 @@
-#ifndef IN_LIMIT_MGR_HPP_
-#define IN_LIMIT_MGR_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #16 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <ostream>
-#include <set>
-
-#include <boost/noncopyable.hpp>
-#include <boost/serialization/utility.hpp>
-#include <boost/serialization/vector.hpp> // no need to include <vector>
-#include <boost/serialization/level.hpp>
-#include <boost/serialization/tracking.hpp>
-
-#include "InLimit.hpp"
-#include "LimitFwd.hpp"
-#include "NodeFwd.hpp"
-
-// class InLimitMgr:
-// Design notes:
-// Please note: when ever we want access the inlimits, limit ptrs we
-// must resolve(/compute them first). This save on client code which
-// modifies the node tree from having handle it.
-// If this proves to be a bottle next. We could add a caching mechanism
-// base on the Ecf class,so that we need only update the pointers
-// when a structural modification is made.
-//
-class InLimitMgr : private boost::noncopyable {
-public:
- InLimitMgr(Node* n) : node_(n) {}
- InLimitMgr() : node_(NULL) {}
-
-// standard functions: ==============================================
- std::ostream& print(std::ostream&) const;
- bool operator==(const InLimitMgr& rhs) const;
- void clear() { inLimitVec_.clear(); }
-
-// Access functions: ======================================================
- const std::vector<InLimit>& inlimits() const { return inLimitVec_; }
-
-// Add functions: ===============================================================
- void addInLimit(const InLimit& ); // will throw std::runtime_error if duplicate
-
-// Delete functions: can throw std::runtime_error ===================================
- // if name argument is empty, delete all attributes of that type
- // if delete was successful return true, else return false.
- // Can throw std::runtime_error if the attribute can not be found
- bool deleteInlimit(const std::string& name);
-
-// mementos functions:
- void get_memento(compound_memento_ptr& comp) const;
-
-// Find functions: ============================================================
- /// *** This will resolve the in limits first ***
- /// Used in *test* only
- Limit* findLimitViaInLimit(const InLimit& ) const;
-
- bool findInLimitByNameAndPath(const InLimit& ) const; // use name,path,token,
-
-// Why:
- void why(std::vector<std::string>& vec) const;
-
-// Limit functions:
-
- /// Are the in limits pointers to the Limits in limit.
- /// This is a very heavily used function. *******
- /// *** This will resolve the in limits first ***
- bool inLimit() const;
-
- /// After job submission we need to increment the in limit, to indicate that a
- /// resource is consumed.
- /// *** This will resolve the in limits first ***
- void incrementInLimit(
- std::set<Limit*>& limitSet, // The set ensure we only update once
- const std::string& task_path // The task that was submitted, and hence caused Limit to increment
- ) const;
-
- /// After job aborts or completes we need to decrement the in limit, to indicate that
- /// additional resource is available.
- /// *** This will resolve the in limits first ***
- void decrementInLimit(
- std::set<Limit*>& limitSet, // The set ensure we only update once
- const std::string& task_path // The task that completed or aborted. Gives up the token
- ) const;
-
- /// Check to see if inlimit's can reference their Limits
- void check(std::string& errorMsg, std::string& warningMsg,bool reportErrors, bool reportWarnings) const;
-
- /// Add externs where the inlimit reference to limits can not be resolved
- void auto_add_inlimit_externs(Defs*) const;
-
- /// Needed by python interface
- std::vector<InLimit>::const_iterator inlimit_begin() const { return inLimitVec_.begin();}
- std::vector<InLimit>::const_iterator inlimit_end() const { return inLimitVec_.end();}
-
-private:
- /// Setup in-limits, to point to their limits,
- void resolveInLimitReferences() const;
- void resolveInLimit(InLimit&,std::string& errorMsg, std::string& warningMsg,bool reportErrors, bool reportWarnings) const;
- void resolveInLimit(InLimit&) const;
-
- limit_ptr find_limit(const InLimit&, std::string& errorMsg, std::string& warningMsg,bool reportErrors, bool reportWarnings) const;
-
-private:
- Node* node_; // Not persisted, constructor will always set this up.
-
- mutable std::vector<InLimit> inLimitVec_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/) {
- ar & inLimitVec_;
- }
-};
-
-// This should ONLY be added to objects that are *NOT* serialised through a pointer
-BOOST_CLASS_IMPLEMENTATION(InLimitMgr, boost::serialization::object_serializable)
-BOOST_CLASS_TRACKING(InLimitMgr,boost::serialization::track_never);
-
-#endif
diff --git a/ecflow_4_0_7/ANode/src/JobCreationCtrl.cpp b/ecflow_4_0_7/ANode/src/JobCreationCtrl.cpp
deleted file mode 100644
index e14ba0c..0000000
--- a/ecflow_4_0_7/ANode/src/JobCreationCtrl.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <iostream>
-#include <stdlib.h> // for getenv()
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include "JobCreationCtrl.hpp"
-
-namespace fs = boost::filesystem;
-
-void JobCreationCtrl::generate_temp_dir()
-{
- if (!getenv("TMPDIR")) throw std::runtime_error("JobCreationCtrl::generate_temp_dir(), The environment variable TMPDIR is not defined");
- tempDirForJobGeneration_ = getenv("TMPDIR");
- tempDirForJobGeneration_ += "/ecf_check_job_creation";
- if (fs::exists(tempDirForJobGeneration_)) fs::remove_all(tempDirForJobGeneration_);
- std::cout << "JobCreationCtrl::generate_temp_dir() " << tempDirForJobGeneration_ << "\n";
-}
diff --git a/ecflow_4_0_7/ANode/src/JobCreationCtrl.hpp b/ecflow_4_0_7/ANode/src/JobCreationCtrl.hpp
deleted file mode 100644
index b634b5e..0000000
--- a/ecflow_4_0_7/ANode/src/JobCreationCtrl.hpp
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef JOBS_GEN_CTRL_HPP_
-#define JOBS_GEN_CTRL_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <string>
-#include <vector>
-
-#include <boost/enable_shared_from_this.hpp>
-#include <boost/noncopyable.hpp>
-
-#include "NodeFwd.hpp"
-
-// Used as a utility class for testing Job creation
-// Collates data during the node tree traversal
-// Note: For testing purposes we do not always want to create jobs
-class JobCreationCtrl : public boost::enable_shared_from_this<JobCreationCtrl>, private boost::noncopyable {
-public:
- JobCreationCtrl() {}
-
- void set_node_path( const std::string& absNodePath ) { absNodePath_ = absNodePath;}
- const std::string& node_path() const { return absNodePath_;}
-
- void generate_temp_dir();
- void set_dir_for_job_creation( const std::string& tempDirForJobGeneration ) { tempDirForJobGeneration_ = tempDirForJobGeneration; }
- const std::string& dir_for_job_creation() { return tempDirForJobGeneration_;}
-
- std::string& error_msg() { return errorMsg_;}
- const std::string& get_error_msg() const { return errorMsg_;}
-
- void push_back_failing_submittable(submittable_ptr t) { fail_submittables_.push_back(t); }
- const std::vector<weak_submittable_ptr>& fail_submittables() const { return fail_submittables_;}
-
-private:
- std::string absNodePath_;
- std::string tempDirForJobGeneration_;
- std::string errorMsg_;
- std::vector<weak_submittable_ptr> fail_submittables_;
-};
-#endif
diff --git a/ecflow_4_0_7/ANode/src/JobProfiler.cpp b/ecflow_4_0_7/ANode/src/JobProfiler.cpp
deleted file mode 100644
index 961b79e..0000000
--- a/ecflow_4_0_7/ANode/src/JobProfiler.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #18 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <boost/lexical_cast.hpp>
-#include "JobProfiler.hpp"
-#include "JobsParam.hpp"
-#include "Task.hpp"
-#include "Str.hpp"
-#include "Log.hpp"
-
-using namespace ecf;
-using namespace std;
-
-// Connection and client timeout issues can be replicated by adding
-// - sleep(1) in EcfFile , i.e when creating the job output
-//
-
-static size_t task_threshold_ = 4000;
-
-namespace ecf {
-
-int JobProfiler::task_threshold_default() { return 4000;}
-
-// =================================================================================
-JobProfiler::JobProfiler(Task* node,JobsParam& jobsParam, size_t threshold)
-: node_(node),
- jobsParam_(jobsParam),
- start_time_(boost::posix_time::microsec_clock::universal_time()),
- threshold_(threshold)
-{
- if (!jobsParam_.next_poll_time().is_special() && start_time_ >= jobsParam_.next_poll_time()) {
- jobsParam_.set_timed_out_of_job_generation(start_time_);
- }
-}
-
-JobProfiler::JobProfiler( JobsParam& jobsParam)
-: node_(0),
- jobsParam_(jobsParam),
- start_time_(boost::posix_time::microsec_clock::universal_time()),
- threshold_(0)
-{
- if (!jobsParam_.next_poll_time().is_special() && start_time_ >= jobsParam_.next_poll_time()) {
- jobsParam_.set_timed_out_of_job_generation(start_time_);
- }
-}
-
-JobProfiler::~JobProfiler()
-{
- if (node_) {
- boost::posix_time::time_duration duration = boost::posix_time::microsec_clock::universal_time() - start_time_;
- size_t time_taken = duration.total_milliseconds();
-
- // When testing we set submitJobsInterval to < 0
- if (jobsParam_.submitJobsInterval() < 0 ) {
- time_taken = threshold_ + 1;
- }
-
- if ( time_taken > threshold_) {
- std::stringstream ss;
- ss << "Job generation for task " << node_->absNodePath() << " took " << time_taken << "ms, Exceeds ECF_TASK_THRESHOLD(" << threshold_ << "ms)";
- log(Log::WAR,ss.str());
- }
- }
-}
-
-void JobProfiler::set_task_threshold(size_t threshold){task_threshold_ = threshold;}
-size_t JobProfiler::task_threshold() { return task_threshold_; }
-
-}
diff --git a/ecflow_4_0_7/ANode/src/JobProfiler.hpp b/ecflow_4_0_7/ANode/src/JobProfiler.hpp
deleted file mode 100644
index cfce85c..0000000
--- a/ecflow_4_0_7/ANode/src/JobProfiler.hpp
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef JOB_PROFILER_HPP_
-#define JOB_PROFILER_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-// This class is used to aid profiling of the job generation step.
-// This will be used to identify those suite/familiy/tasks that take the most
-// amount of time, *when* we exceed the jobs generation interval.
-// In particular if we have output that is many megabtyes, it can affect
-// the performance of the server, especially when the server is running
-// on virtual machines
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/noncopyable.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include "NodeFwd.hpp"
-class JobsParam;
-
-namespace ecf {
-
-class JobProfiler : private boost::noncopyable {
-public:
- // Note: 1000 milliseconds = 1 second
- JobProfiler(Task*,JobsParam&,size_t threshold /* expected to be milli seconds */);
- JobProfiler( JobsParam&);
- ~JobProfiler();
-
- static void set_task_threshold(size_t threshold);
- static size_t task_threshold();
-
- static int task_threshold_default();
-
-private:
- Task* node_;
- JobsParam& jobsParam_;
- boost::posix_time::ptime start_time_;
- size_t threshold_;
-};
-
-}
-
-
-#endif
diff --git a/ecflow_4_0_7/ANode/src/Jobs.cpp b/ecflow_4_0_7/ANode/src/Jobs.cpp
deleted file mode 100644
index 9de994f..0000000
--- a/ecflow_4_0_7/ANode/src/Jobs.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #18 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <assert.h>
-
-#include "Jobs.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "Log.hpp"
-#include "DurationTimer.hpp"
-#include "JobsParam.hpp"
-#include "Signal.hpp"
-#include "System.hpp"
-#include "SuiteChanged.hpp"
-#include "JobProfiler.hpp"
-
-using namespace ecf;
-using namespace std;
-
-//#define DEBUG_JOB_SUBMISSION 1
-
-bool Jobs::generate( JobsParam& jobsParam) const
-{
-#ifdef DEBUG_JOB_SUBMISSION
- cout << "\n" << "Jobs::generate (" << jobsParam.logDebugMessage() << ") create jobs(" << jobsParam.createJobs() << ")";
- if (defs_) cout << " server_state(" << SState::to_string(defs_->server().get_state()) << ")\n";
-#endif
-
- // dependency resolving and job submission must be less than submitJobsInterval seconds
- // Note: Duration timer makes a system call
- DurationTimer durationTimer;
-
-#ifdef DEBUG_JOB_SUBMISSION
- LogToCout toCoutAsWell;
- LOG(Log::DBG,"-->Job submission start " << jobsParam.logDebugMessage());
-#endif
- {
- // Constructor does nothing, destructor will un-block SIGCHLD
- // This will allow child process termination to handled by the signal handler in System
- // The desctructor will then re-block SIGCHLD
- Signal unblock_on_desctruction_then_reblock;
-
- // *******************************************************************
- // **** JOB submission *MUST* be done sequentially, as each task could
- // **** be affected by a resource/limit, and hence affect subsequent
- // **** job submission
- // *******************************************************************
-
- if (defs_) {
- if (defs_->server().get_state() == SState::RUNNING) {
- const std::vector<suite_ptr>& suiteVec = defs_->suiteVec();
- size_t theSize = suiteVec.size();
- for(size_t i = 0; i < theSize; i++) {
- // SuiteChanged moved internal to Suite::resolveDependencies. i.e on fast path
- // and when suites not begun we save a constructor/destructor calls
- (void)suiteVec[i]->resolveDependencies(jobsParam);
- }
- }
- }
- else {
- if (!node_->isParentSuspended()) {
- // suite, family, task
- SuiteChanged1 changed(node_->suite());
- (void)node_->resolveDependencies( jobsParam );
- }
- }
-
- // *****************************************************************
- // Should end up calling signal handler here for any pending SIGCHLD
- // *****************************************************************
- }
-
- // Process children that have terminated
- System::instance()->processTerminatedChildren();
-
-#ifdef DEBUG_JOB_SUBMISSION
- LOG(Log::DBG,"-->Job submission finish interval = "
- << jobsParam.submitJobsInterval()
- << " time taken = " << durationTimer.duration()
- << " Tasks/Aliases submitted " << jobsParam.submitted().size()
- << " " << jobsParam.getErrorMsg()
- );
-#endif
-
- if (durationTimer.duration() > jobsParam.submitJobsInterval()) {
- LOG(Log::ERR,"Jobs::generate: job generation time(" << durationTimer.duration() << " seconds) is greater than job submission interval of " << jobsParam.submitJobsInterval() << " seconds!!");
- }
- return jobsParam.getErrorMsg().empty();
-}
-
-bool Jobs::generate() const
-{
- Defs* defs = NULL;
- if (defs_) {
- defs = defs_;
- LOG_ASSERT( defs != NULL ,"defs_ == NULL");
- }
- else {
- defs = node_->defs();
- LOG_ASSERT( defs != NULL ,"node_->defs() == NULL");
- }
-
- if (defs->server().get_state() == SState::RUNNING) {
- LOG_ASSERT( defs->server().jobSubmissionInterval() != 0 ,"");
- JobsParam jobsParam( defs->server().jobSubmissionInterval(), defs->server().jobGeneration() );
-#ifdef DEBUG_JOB_SUBMISSION
- jobsParam.logDebugMessage(" from Jobs::generate()/Server");
-#endif
-
- return generate( jobsParam );
- }
- return false;
-}
diff --git a/ecflow_4_0_7/ANode/src/Jobs.hpp b/ecflow_4_0_7/ANode/src/Jobs.hpp
deleted file mode 100644
index 2f87a34..0000000
--- a/ecflow_4_0_7/ANode/src/Jobs.hpp
+++ /dev/null
@@ -1,69 +0,0 @@
-#ifndef JOBS_HPP_
-#define JOBS_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/noncopyable.hpp>
-#include "NodeFwd.hpp"
-
-/// Job generation involves:
-/// 1/ resolving dependencies. This means we look at day,date,time and triggers,
-/// and check to to see if a node is free or still holding.
-/// When a node is free of its dependencies, a job can be created.
-/// Note: for a node that is suspended, job generation is disabled.
-/// In this case the time dependencies are still checked.
-/// and if free are marked as such. later on if the node is resumed
-/// we check dependencies and create the jobs
-/// 2/ Creating jobs. Pre processing and variable substitution
-/// 3/ Changing state of task to submitted.
-/// 4/ Increment the inlimit references, for successful job submission
-/// 5/ Error/Complete must decrement limits
-/// 6/ Set up signal handlers to monitor child job, so that on failure
-// Change state to ABORTED and decrement limit references
-///
-/// Job submission *MUST* be done sequentially,as each job submission could
-/// consume a resource(i.e like a limit), which can affect subsequent jobs.
-///
-/// The process of resolving dependencies and submitting all the tasks, must take
-/// less than 60 seconds. As this is resolution of the clock.
-/// For testing purposes this can be changed and also we do not always want
-/// to create jobs.
-///
-/// Return true, if job submission ok, else false and error message in JobsParam
-///
-/// The jobs file are shell scripts, which have IPC(child commands) which talk to
-/// to the server. Since the scripts are user created, they can include, errors:
-/// o multiple call to complete
-/// To guard against this, we should *not* clear reset password in the complete
-/// Otherwise we will registered as a zombie.
-/// o Failure to call complete (maybe due to early exit in the job file)
-/// There is not much we can do here, the job will stay active.
-/// o Path do not match, since the node tree, in the server has been deleted
-/// Typically the job will hold on the child commands.
-///
-/// Note: in real life test 99% of job generation is done after child command
-class Jobs : private boost::noncopyable {
-public:
- Jobs(const defs_ptr& d) : defs_(d.get()), node_(NULL) {}
- Jobs(Defs* d) : defs_(d), node_(NULL) {}
- Jobs(Node* d) : defs_(NULL), node_(d) {}
-
- bool generate( JobsParam& ) const;
- bool generate() const;
-
-private:
- Defs* defs_;
- Node* node_;
-};
-#endif
diff --git a/ecflow_4_0_7/ANode/src/JobsParam.hpp b/ecflow_4_0_7/ANode/src/JobsParam.hpp
deleted file mode 100644
index 55df9c4..0000000
--- a/ecflow_4_0_7/ANode/src/JobsParam.hpp
+++ /dev/null
@@ -1,81 +0,0 @@
-#ifndef JOBSPARAM_HPP_
-#define JOBSPARAM_HPP_
-//============================================================================
-// Name : time
-// Author : Avi
-// Revision : $Revision: #14 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-#include <boost/noncopyable.hpp>
-#include "NodeFwd.hpp"
-
-// Used as a utility class for controlling job creation.
-// Collates data during the node tree traversal
-// Note: For testing purposes we do not always want to create jobs or spawn jobs
-class JobsParam : private boost::noncopyable {
-public:
- // This constructor is used in test
- JobsParam(bool createJobs = false)
- : timed_out_of_job_generation_(false),
- createJobs_(createJobs), spawnJobs_(false), submitJobsInterval_(60){}
-
- JobsParam(int submitJobsInterval, bool createJobs, bool spawn_jobs = true)
- : timed_out_of_job_generation_(false),
- createJobs_(createJobs),spawnJobs_(spawn_jobs), submitJobsInterval_(submitJobsInterval)
- { if (!createJobs_) spawnJobs_ = false;}
-
- std::string& errorMsg() { return errorMsg_;}
- const std::string& getErrorMsg() const { return errorMsg_;}
-
- void push_back_submittable(Submittable* t) { submitted_.push_back(t); }
- const std::vector<Submittable*>& submitted() const { return submitted_;}
-
- bool createJobs() const { return createJobs_;}
- bool spawnJobs() const { return spawnJobs_;}
-
- /// returns the number of seconds at which we should check time dependencies
- /// this includes evaluating trigger dependencies and submit the corresponding jobs.
- /// This is set at 60 seconds. But will vary for debug purposes only.
- int submitJobsInterval() const { return submitJobsInterval_;}
-
- /// Allow user to set the debug message that appears in log file when job submission starts
- void logDebugMessage(const std::string& s) { debugMsg_ = s;}
- const std::string& logDebugMessage() const { return debugMsg_;}
-
- void set_user_edit_variables(const NameValueMap& v) { user_edit_variables_ = v;}
- const NameValueMap& user_edit_variables() const { return user_edit_variables_;}
-
- void set_user_edit_file(const std::vector<std::string>& file) { user_edit_file_ = file;}
- const std::vector<std::string>& user_edit_file() const { return user_edit_file_; }
-
- // Functions to aid timing of job generation
- void set_next_poll_time(const boost::posix_time::ptime& next_poll_time) { next_poll_time_ = next_poll_time;}
- const boost::posix_time::ptime& next_poll_time() const { return next_poll_time_;}
- const boost::posix_time::ptime& time_out_time() const { return time_out_time_;}
- void set_timed_out_of_job_generation(const boost::posix_time::ptime& t) { time_out_time_ = t; timed_out_of_job_generation_ = true;}
- bool timed_out_of_job_generation() const { return timed_out_of_job_generation_; }
-
-private:
- bool timed_out_of_job_generation_;
- bool createJobs_;
- bool spawnJobs_;
- int submitJobsInterval_;
- std::string errorMsg_;
- std::string debugMsg_;
- std::vector<Submittable*> submitted_;
- std::vector<std::string> user_edit_file_;
- NameValueMap user_edit_variables_; // Used for User edit
- boost::posix_time::ptime next_poll_time_; // Aid early exit from job generation, if it takes to long
- boost::posix_time::ptime time_out_time_; // When we actually timed out must >= next_poll_time_
-};
-#endif
diff --git a/ecflow_4_0_7/ANode/src/Limit.cpp b/ecflow_4_0_7/ANode/src/Limit.cpp
deleted file mode 100644
index 8dad850..0000000
--- a/ecflow_4_0_7/ANode/src/Limit.cpp
+++ /dev/null
@@ -1,209 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #64 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <assert.h>
-#include <sstream>
-
-#include "Limit.hpp"
-#include "Indentor.hpp"
-#include "PrintStyle.hpp"
-#include "Str.hpp"
-#include "Ecf.hpp"
-#include "Suite.hpp"
-
-using namespace std;
-using namespace ecf;
-
-/////////////////////////////////////////////////////////////////////////////////////////////
-
-Limit::Limit(const std::string& name,int limit)
-: state_change_no_(0),name_(name),theLimit_(limit),value_(0),node_(0)
-{
- if ( !Str::valid_name( name ) ) {
- throw std::runtime_error("Limit::Limit: Invalid Limit name: " + name);
- }
-}
-
-Limit::Limit(const std::string& name,int limit, int value, const std::set<std::string>& paths)
-: state_change_no_(0),name_(name),theLimit_(limit),value_(value),paths_(paths),node_(0)
-{
- if ( !Str::valid_name( name ) ) {
- throw std::runtime_error("Limit::Limit: Invalid Limit name: " + name);
- }
-}
-
-Limit::Limit(const Limit& rhs)
-: state_change_no_(0), name_(rhs.name_),theLimit_(rhs.theLimit_),value_(rhs.value_),paths_(rhs.paths_),node_(0)
-{
-}
-
-bool Limit::operator==( const Limit& rhs ) const {
- if ( value_ != rhs.value_ ) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Limit::operator==value_(" << value_ << ") != rhs.value_(" << rhs.value_ << ") " << toString() << " rhs(" << rhs.toString() << ")\n";
- }
-#endif
- return false;
- }
- if ( theLimit_ != rhs.theLimit_ ) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Limit::operator==( theLimit_ != rhs.theLimit_) " << toString() << " rhs(" << rhs.toString() << ")\n";
- }
-#endif
- return false;
- }
- if ( name_ != rhs.name_ ) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Limit::operator==( name_ != rhs.name_ ) " << toString() << " rhs(" << rhs.toString() << ")\n";
- }
-#endif
- return false;
- }
- if ( paths_ != rhs.paths_ ) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Limit::operator==( paths_ != rhs.paths_ ) " << toString() << " rhs(" << rhs.toString() << ")\n";
- }
-#endif
- return false;
- }
- return true;
-}
-
-std::ostream& Limit::print( std::ostream& os ) const {
- Indentor in;
- Indentor::indent( os ) << toString();
- if (!PrintStyle::defsStyle()) {
- if (value_ != 0) {
- os << " # " << value_;
- for(std::set<std::string>::const_iterator i = paths_.begin(); i != paths_.end(); ++i) {
- os << " " << (*i);
- }
- }
- }
- os << "\n";
- return os;
-}
-
-std::string Limit::toString() const {
- std::stringstream ss;
- ss << "limit " << name_ << " " << theLimit_;
- return ss.str();
-}
-
-void Limit::decrement( int tokens , const std::string& abs_node_path) {
-
- // cout << "Limit::decrement name = " << name_ << " current value_ = " << value_ << " limit = " << theLimit_ << " consume tokens = " << tokens << "\n";
- // Note: we previously had 'if (value_ > 0) {
- // However if the user had manually changed the value_, then we could be left with paths_, that would never have been cleared
- if (delete_path(abs_node_path)) {
- // delete_path() will increment state_change_no
- value_ -= tokens;
- if ( value_ < 0 ) {
- value_ = 0;
- paths_.clear();
- }
- }
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Limit::decrement\n";
-#endif
- // cout << "Limit::decrement name = " << name_ << " current value_ = " << value_ << "\n";
-}
-
-void Limit::increment( int tokens , const std::string& abs_node_path) {
- // cout << "Limit::increment name = " << name_ << " current value_ = " << value_ << " limit = " << theLimit_ << " consume tokens = " << tokens << "\n";
-
- if ( value_ < theLimit_ ) {
-
- std::set<std::string>::iterator i = paths_.find(abs_node_path);
- if (i == paths_.end()) {
-
- paths_.insert( abs_node_path );
- value_ += tokens;
- update_change_no();
- }
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Limit::increment\n";
-#endif
- }
- // cout << "Limit::increment name = " << name_ << " current value_ = " << value_ << "\n";
-}
-
-void Limit::setValue( int v )
-{
- value_ = v;
- update_change_no();
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << " Limit::setValue() value_ = " << value_ << "\n";
-#endif
-}
-
-void Limit::setLimit(int v)
-{
- theLimit_ = v;
- update_change_no();
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << " Limit::setLimit() theLimit_ = " << value_ << "\n";
-#endif
-}
-
-void Limit::set_paths(const std::set<std::string>& paths)
-{
- paths_ = paths;
- update_change_no();
-}
-
-void Limit::set_state(int limit, int value, const std::set<std::string>& paths)
-{
- value_ = value;
- theLimit_ = limit;
- paths_ = paths;
- update_change_no();
-}
-
-bool Limit::delete_path( const std::string& abs_node_path)
-{
- std::set<std::string>::iterator i = paths_.find(abs_node_path);
- if (i != paths_.end()) {
- paths_.erase(i);
- update_change_no();
- return true;
- }
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Limit::delete_path() \n";
-#endif
- return false;
-}
-
-void Limit::reset() {
- paths_.clear();
- setValue(0); // will increment state_change_no_
-}
-
-void Limit::update_change_no()
-{
- state_change_no_ = Ecf::incr_state_change_no();
- if (node_) {
- Suite* suite = node_->suite();
- if (suite) suite->set_state_change_no(state_change_no_);
- }
-}
diff --git a/ecflow_4_0_7/ANode/src/Limit.hpp b/ecflow_4_0_7/ANode/src/Limit.hpp
deleted file mode 100644
index 84c9450..0000000
--- a/ecflow_4_0_7/ANode/src/Limit.hpp
+++ /dev/null
@@ -1,89 +0,0 @@
-#ifndef LIMIT_HPP_
-#define LIMIT_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #61 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Limit was placed in the ANode category because inlimit
-// can reference Limit on *ANOTHER* suite. This presents
-// A problem with incremental sync, since that requires
-// access to a parent/suite, to mark the suite as changed.
-// To get round this issue the Node will set the
-// parent pointer on the Limit this then makes it easy
-// for incremental sync, since we directly access the parent suite
-//============================================================================
-
-#include <ostream>
-
-#include <boost/serialization/serialization.hpp>
-#include <boost/serialization/set.hpp> // no need to include <set>
-#include <boost/serialization/string.hpp> // no need to include <string>
-class Node;
-
-// Class Limit: The limit is zero based, hence if limit is 10, increment must use < 10
-class Limit {
-public:
- Limit(const std::string& name,int limit);
- Limit(const std::string& name,int limit, int value, const std::set<std::string>& paths);
- Limit() : state_change_no_(0), theLimit_(0), value_(0),node_(0) {}
- Limit(const Limit& rhs);
-
- std::ostream& print(std::ostream&) const;
- bool operator==(const Limit& rhs) const;
- const std::string& name() const { return name_;}
-
- void set_node(Node* n) { node_ = n; }
-
- void setValue(int v);
- void setLimit(int v);
- void set_state(int limit, int value,const std::set<std::string>& p); // for use by memento
- void set_paths(const std::set<std::string>& p);
-
- bool delete_path( const std::string& abs_node_path); // for use by AlterCmd
- const std::set<std::string>& paths() const { return paths_;}
-
- int value() const { return value_;}
- bool inLimit(int inlimit_tokens) const { return ((value_ + inlimit_tokens) <= theLimit_);}
- int theLimit() const { return theLimit_;}
- void increment(int tokens, const std::string& abs_node_path);
- void decrement(int tokens, const std::string& abs_node_path);
- void reset();
-
- // The state_change_no is never reset. Must be incremented if it can affect equality
- unsigned int state_change_no() const { return state_change_no_; }
-
- // for python interface
- std::string toString() const;
- std::set<std::string>::const_iterator paths_begin() const { return paths_.begin();}
- std::set<std::string>::const_iterator paths_end() const { return paths_.end();}
-
-private:
- void update_change_no();
-
-private:
- unsigned int state_change_no_; // *not* persisted, only used on server side
- std::string name_;
- int theLimit_;
- int value_;
- std::set<std::string> paths_; // Updated via increment()/decrement()/reset(). Typically task paths
- Node* node_ ; // The parent NOT persisted
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/) {
- ar & name_;
- ar & theLimit_;
- ar & value_;
- ar & paths_;
- }
-};
-
-#endif
diff --git a/ecflow_4_0_7/ANode/src/LimitFwd.hpp b/ecflow_4_0_7/ANode/src/LimitFwd.hpp
deleted file mode 100644
index d2d6af3..0000000
--- a/ecflow_4_0_7/ANode/src/LimitFwd.hpp
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef LIMIT_FWD_HPP_
-#define LIMIT_FWD_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/shared_ptr.hpp>
-
-class Limit;
-typedef boost::shared_ptr<Limit> limit_ptr;
-
-#endif
diff --git a/ecflow_4_0_7/ANode/src/Memento.cpp b/ecflow_4_0_7/ANode/src/Memento.cpp
deleted file mode 100644
index d54bd7c..0000000
--- a/ecflow_4_0_7/ANode/src/Memento.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #32 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "Memento.hpp"
-#include "ChangeMgrSingleton.hpp"
-#include "Str.hpp"
-
-using namespace std;
-using namespace ecf;
-
-//#define DEBUG_MEMENTO 1
-
-// ===============================================================
-Memento::~Memento() {}
-
-// ===============================================================
-void CompoundMemento::incremental_sync(defs_ptr client_def,std::vector<std::string>& changed_nodes) const
-{
- /// Clear out aspects, for this Memento.
- /// Aspects are added to ChangeMgrSingleton, via do_incremental_* functions
- /// AND in *this* function when node attributes have been added or deleted.
- ChangeMgrSingleton::instance()->clear_aspects();
-
- // Record changes nodes for the python interface
- changed_nodes.push_back(absNodePath_);
-
- node_ptr node = client_def->findAbsNode(absNodePath_);
- if (!node.get()) {
- if ( absNodePath_ != Str::ROOT_PATH()) throw std::runtime_error("CompoundMemento::incremental_sync: could not find path " + absNodePath_ );
-
-#ifdef DEBUG_MEMENTO
- cout << "CompoundMemento::incremental_sync: ROOT_PATH changed_nodes.size()=" << changed_nodes.size() << "\n";
-#endif
- BOOST_FOREACH(memento_ptr m, vec_) {
- m->do_incremental_defs_sync( client_def.get() );
- }
-
- /// Notify any interested parties incremental changes
- ChangeMgrSingleton::instance()->notify(client_def);
- }
- else {
-
-#ifdef DEBUG_MEMENTO
- cout << "CompoundMemento::incremental_sync: " << node->debugNodePath() << " changed_nodes.size()=" << changed_nodes.size() << "\n";
-#endif
-
- if (clear_attributes_) {
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::ADD_REMOVE_ATTR);
- node->clear();
- }
-
- Task* task = node->isTask();
- Alias* alias = node->isAlias();
- Suite* suite = node->isSuite();
- Family* family = node->isFamily();
-
- BOOST_FOREACH(memento_ptr m, vec_) {
-// std::cout << "memento = " << typeid(*m.get()).name() << "\n";
- if (task) m->do_incremental_task_sync( task );
- else if (alias) m->do_incremental_alias_sync( alias );
- else if (suite) m->do_incremental_suite_sync( suite );
- else if (family) m->do_incremental_family_sync( family );
- m->do_incremental_node_sync( node.get() );
- }
-
- /// Notify any interested parties that Node has made incremental changes
- ChangeMgrSingleton::instance()->notify(node);
- }
-}
-
-BOOST_CLASS_EXPORT_IMPLEMENT(StateMemento);
-BOOST_CLASS_EXPORT_IMPLEMENT(NodeDefStatusDeltaMemento);
-BOOST_CLASS_EXPORT_IMPLEMENT(SuspendedMemento);
-BOOST_CLASS_EXPORT_IMPLEMENT(ServerStateMemento);
-BOOST_CLASS_EXPORT_IMPLEMENT(ServerVariableMemento);
-BOOST_CLASS_EXPORT_IMPLEMENT(NodeEventMemento);
-BOOST_CLASS_EXPORT_IMPLEMENT(NodeMeterMemento);
-BOOST_CLASS_EXPORT_IMPLEMENT(NodeLabelMemento);
-BOOST_CLASS_EXPORT_IMPLEMENT(NodeTriggerMemento);
-BOOST_CLASS_EXPORT_IMPLEMENT(NodeCompleteMemento);
-BOOST_CLASS_EXPORT_IMPLEMENT(NodeRepeatMemento);
-BOOST_CLASS_EXPORT_IMPLEMENT(NodeLimitMemento);
-BOOST_CLASS_EXPORT_IMPLEMENT(NodeInLimitMemento);
-BOOST_CLASS_EXPORT_IMPLEMENT(NodeVariableMemento);
-BOOST_CLASS_EXPORT_IMPLEMENT(NodeLateMemento);
-BOOST_CLASS_EXPORT_IMPLEMENT(NodeTodayMemento);
-BOOST_CLASS_EXPORT_IMPLEMENT(NodeTimeMemento);
-BOOST_CLASS_EXPORT_IMPLEMENT(NodeDayMemento);
-BOOST_CLASS_EXPORT_IMPLEMENT(NodeCronMemento);
-BOOST_CLASS_EXPORT_IMPLEMENT(NodeDateMemento);
-BOOST_CLASS_EXPORT_IMPLEMENT(NodeZombieMemento);
-BOOST_CLASS_EXPORT_IMPLEMENT(NodeVerifyMemento);
-BOOST_CLASS_EXPORT_IMPLEMENT(FlagMemento);
-BOOST_CLASS_EXPORT_IMPLEMENT(SubmittableMemento);
-BOOST_CLASS_EXPORT_IMPLEMENT(SuiteClockMemento);
-BOOST_CLASS_EXPORT_IMPLEMENT(SuiteBeginDeltaMemento);
-BOOST_CLASS_EXPORT_IMPLEMENT(SuiteCalendarMemento);
-BOOST_CLASS_EXPORT_IMPLEMENT(OrderMemento);
-BOOST_CLASS_EXPORT_IMPLEMENT(ChildrenMemento);
-BOOST_CLASS_EXPORT_IMPLEMENT(AliasChildrenMemento);
-BOOST_CLASS_EXPORT_IMPLEMENT(AliasNumberMemento);
diff --git a/ecflow_4_0_7/ANode/src/Memento.hpp b/ecflow_4_0_7/ANode/src/Memento.hpp
deleted file mode 100644
index 9c88800..0000000
--- a/ecflow_4_0_7/ANode/src/Memento.hpp
+++ /dev/null
@@ -1,742 +0,0 @@
-#ifndef MEMENTO_HPP_
-#define MEMENTO_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #41 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : class Memento
-// Class's derived from Memento are stored on DefsDelta.
-// DefsDelta is transferred from Server to Client during a sync
-// See SSyncCmd.hpp
-//
-// Are created in the server, but used by the client to sync.
-//
-// Used to capture incremental change of state, to node, and node attributes
-// Serve as a base class of all memento's
-// Later on the client side, the changes can be applied. via incremental_sync()
-// The are several kind of changes that we can capture:
-// a/ simple state changes,
-// b/ Change in attribute structure
-// c/ Deletion of attribute
-// d/ Addition of an attribute
-// e/ Add/delete of a Family/task
-// f/ Add/Delete of suite
-//
-// The main emphasis here is to capture a,b,c,d,e. This is easily handled by state_change_no.
-// option f/ is handled via a full update and hence does not use mementos
-//
-// ISSUES: AIX has issues with TOC(table of contents) overflow. This is heavily
-// influenced by the number of global symbols. Unfortunately each boost serializiable
-// type, greatly increases the number of globals.
-// Hence we need to ensure we use the minimum number of serializable types.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "Alias.hpp"
-
-#include "boost_archive.hpp" // collates boost archive includes
-#include <boost/serialization/export.hpp>
-#include <boost/serialization/deque.hpp> // no need to include <deque>
-
-//#define DEBUG_MEMENTO 1
-
-class Memento : private boost::noncopyable {
-public:
- virtual ~Memento();
-private:
- /// Applies the mementos to the client side defs. Can raise std::runtime_error
- virtual void do_incremental_node_sync(Node*) const {}
- virtual void do_incremental_task_sync(Task*) const {}
- virtual void do_incremental_alias_sync(Alias*) const {}
- virtual void do_incremental_suite_sync(Suite*) const {}
- virtual void do_incremental_family_sync(Family*) const {}
- virtual void do_incremental_defs_sync(Defs*) const {}
- friend class CompoundMemento;
-
-private:
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {}
-};
-BOOST_SERIALIZATION_ASSUME_ABSTRACT(Memento)
-
-
-// Used for storing all the memento's associated with a single node
-// This allow us to make only *ONE* call to find the node.
-// The mementos are then applied to this single node.
-class CompoundMemento {
-public:
- CompoundMemento(const std::string& absNodePath)
- : clear_attributes_(false),absNodePath_(absNodePath) {}
-
- CompoundMemento() : clear_attributes_(false) {} // for serialization
-
- void incremental_sync(defs_ptr client_def, std::vector<std::string>& changed_nodes) const;
- void add(memento_ptr m) { vec_.push_back(m); }
- void clear_attributes() { clear_attributes_ = true;}
-
-private:
-
- bool clear_attributes_;
- std::string absNodePath_;
- std::vector<memento_ptr> vec_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & clear_attributes_;
- ar & absNodePath_;
- ar & vec_;
- }
-};
-
-
-class StateMemento : public Memento {
-public:
- StateMemento(NState::State state) : state_(state) {}
- StateMemento() : state_(NState::UNKNOWN) {}
-private:
- virtual void do_incremental_node_sync(Node* n) const { n->set_memento(this);}
- virtual void do_incremental_defs_sync(Defs* defs) const { defs->set_memento(this);}
-
- NState::State state_;
- friend class Node;
- friend class Defs;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object<Memento>(*this);
- ar & state_;
- }
-};
-
-class OrderMemento : public Memento {
-public:
- OrderMemento(const std::vector<std::string>& order) : order_(order) {}
- OrderMemento() {}
-private:
- virtual void do_incremental_defs_sync(Defs* defs) const { defs->set_memento(this);}
- virtual void do_incremental_suite_sync(Suite* s) const { s->set_memento(this);}
- virtual void do_incremental_family_sync(Family* f) const { f->set_memento(this);}
- virtual void do_incremental_task_sync(Task* t) const { t->set_memento(this);}
-
- std::vector<std::string> order_;
- friend class NodeContainer;
- friend class Task;
- friend class Defs;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object<Memento>(*this);
- ar & order_;
- }
-};
-
-class ChildrenMemento : public Memento {
-public:
- ChildrenMemento(const std::vector<node_ptr>& children) : children_(children) {}
- ChildrenMemento() {}
-private:
- virtual void do_incremental_suite_sync(Suite* s) const { s->set_memento(this);}
- virtual void do_incremental_family_sync(Family* f) const { f->set_memento(this);}
-
- std::vector<node_ptr> children_;
- friend class NodeContainer;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
-
- ar.register_type(static_cast<Task *>(NULL));
- ar.register_type(static_cast<Family *>(NULL));
-
- ar & boost::serialization::base_object<Memento>(*this);
- ar & children_;
- }
-};
-
-class AliasChildrenMemento : public Memento {
-public:
- AliasChildrenMemento(const std::vector<alias_ptr>& children) : children_(children) {}
- AliasChildrenMemento() {}
-private:
- virtual void do_incremental_task_sync(Task* t) const { t->set_memento(this);}
-
- std::vector<alias_ptr> children_;
- friend class Task;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
-
- ar.register_type(static_cast<Alias *>(NULL));
-
- ar & boost::serialization::base_object<Memento>(*this);
- ar & children_;
- }
-};
-
-class AliasNumberMemento : public Memento {
-public:
- AliasNumberMemento(unsigned int alias_no ) : alias_no_(alias_no) {}
- AliasNumberMemento() : alias_no_(0) {}
-private:
- virtual void do_incremental_task_sync(Task* t) const { t->set_memento(this);}
-
- unsigned int alias_no_;
- friend class Task;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object<Memento>(*this);
- ar & alias_no_;
- }
-};
-
-
-class SuspendedMemento : public Memento {
-public:
- SuspendedMemento(bool suspended) : suspended_(suspended) {}
- SuspendedMemento() : suspended_(false) {}
-private:
- virtual void do_incremental_node_sync(Node* n) const { n->set_memento(this);}
-
- bool suspended_;
- friend class Node;
- friend class Defs;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object<Memento>(*this);
- ar & suspended_;
- }
-};
-
-class ServerStateMemento : public Memento {
-public:
- ServerStateMemento(SState::State s) : state_(s) {}
- ServerStateMemento() : state_(SState::HALTED) {}
-private:
- virtual void do_incremental_defs_sync(Defs* defs) const { defs->set_memento(this);}
-
- SState::State state_;
- friend class Defs;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object<Memento>(*this);
- ar & state_;
- }
-};
-
-class ServerVariableMemento : public Memento {
-public:
- ServerVariableMemento(const std::vector<Variable>& vec) : serverEnv_(vec) {}
- ServerVariableMemento() {}
-private:
- virtual void do_incremental_defs_sync(Defs* defs) const { defs->set_memento(this);}
-
- std::vector<Variable> serverEnv_;
- friend class Defs;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object<Memento>(*this);
- ar & serverEnv_;
- }
-};
-
-class NodeDefStatusDeltaMemento : public Memento {
-public:
- NodeDefStatusDeltaMemento(DState::State state) : state_(state) {}
- NodeDefStatusDeltaMemento() : state_(DState::UNKNOWN) {}
-private:
- virtual void do_incremental_node_sync(Node* n) const { n->set_memento(this);}
-
- DState::State state_;
- friend class Node;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object<Memento>(*this);
- ar & state_;
- }
-};
-
-class NodeEventMemento : public Memento {
-public:
- NodeEventMemento( const Event& e) : event_(e) {}
- NodeEventMemento(){}
-private:
- virtual void do_incremental_node_sync(Node* n) const { n->set_memento(this);}
-
- Event event_;
- friend class Node;
- friend class ChildAttrs;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object<Memento>(*this);
- ar & event_;
- }
-};
-
-class NodeMeterMemento : public Memento {
-public:
- NodeMeterMemento(const Meter& e) : meter_(e) {}
- NodeMeterMemento() {}
-private:
- virtual void do_incremental_node_sync(Node* n) const { n->set_memento(this);}
-
- Meter meter_;
- friend class Node;
- friend class ChildAttrs;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object<Memento>(*this);
- ar & meter_;
- }
-};
-
-class NodeLabelMemento : public Memento {
-public:
- NodeLabelMemento( const Label& e) : label_(e) {}
- NodeLabelMemento(){}
-private:
- virtual void do_incremental_node_sync(Node* n) const { n->set_memento(this);}
-
- Label label_;
- friend class Node;
- friend class ChildAttrs;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object<Memento>(*this);
- ar & label_;
- }
-};
-
-
-class NodeTriggerMemento : public Memento {
-public:
- NodeTriggerMemento(const Expression& e) : exp_(e) {}
- NodeTriggerMemento() {}
-private:
- virtual void do_incremental_node_sync(Node* n) const { n->set_memento(this);}
-
- Expression exp_;
- friend class Node;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object<Memento>(*this);
- ar & exp_;
- }
-};
-
-class NodeCompleteMemento : public Memento {
-public:
- NodeCompleteMemento(const Expression& e) : exp_(e) {}
- NodeCompleteMemento() {}
-private:
- virtual void do_incremental_node_sync(Node* n) const { n->set_memento(this);}
-
- Expression exp_;
- friend class Node;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object<Memento>(*this);
- ar & exp_;
- }
-};
-
-class NodeRepeatMemento : public Memento {
-public:
- NodeRepeatMemento( const Repeat& e ) : repeat_(e) {}
- NodeRepeatMemento() {}
-private:
- virtual void do_incremental_node_sync(Node* n) const { n->set_memento(this);}
-
- Repeat repeat_;
- friend class Node;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object<Memento>(*this);
- ar & repeat_;
- }
-};
-
-class NodeLimitMemento : public Memento {
-public:
- NodeLimitMemento( const Limit& e) : limit_( e ) {}
- NodeLimitMemento() {}
-private:
- virtual void do_incremental_node_sync(Node* n) const { n->set_memento(this);}
-
- Limit limit_;
- friend class Node;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object<Memento>(*this);
- ar & limit_;
- }
-};
-
-class NodeInLimitMemento : public Memento {
-public:
- NodeInLimitMemento( const InLimit& e) : inlimit_( e ) {}
- NodeInLimitMemento() {}
-private:
- virtual void do_incremental_node_sync(Node* n) const { n->set_memento(this);}
-
- InLimit inlimit_;
- friend class Node;
- friend class InLimitMgr;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object<Memento>(*this);
- ar & inlimit_;
- }
-};
-
-class NodeVariableMemento : public Memento {
-public:
- NodeVariableMemento( const Variable& e) : var_(e) {}
- NodeVariableMemento(){}
-private:
- virtual void do_incremental_node_sync(Node* n) const { n->set_memento(this);}
-
- Variable var_;
- friend class Node;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object<Memento>(*this);
- ar & var_;
- }
-};
-
-class NodeLateMemento : public Memento {
-public:
- NodeLateMemento( const ecf::LateAttr& e) : late_(e) {}
- NodeLateMemento() {}
-private:
- virtual void do_incremental_node_sync(Node* n) const { n->set_memento(this);}
-
- ecf::LateAttr late_;
- friend class Node;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object<Memento>(*this);
- ar & late_;
- }
-};
-
-class FlagMemento : public Memento {
-public:
- FlagMemento( const ecf::Flag& e) : flag_(e) {}
- FlagMemento() {}
-private:
- virtual void do_incremental_node_sync(Node* n) const { n->set_memento(this);}
- virtual void do_incremental_defs_sync(Defs* defs) const { defs->set_memento(this);}
-
- ecf::Flag flag_;
- friend class Node;
- friend class Defs;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object<Memento>(*this);
- ar & flag_;
- }
-};
-
-class NodeTodayMemento : public Memento {
-public:
- NodeTodayMemento( const ecf::TodayAttr& attr) : attr_(attr) {}
- NodeTodayMemento() {}
-private:
- virtual void do_incremental_node_sync(Node* n) const { n->set_memento(this);}
-
- ecf::TodayAttr attr_;
- friend class Node;
- friend class TimeDepAttrs;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object<Memento>(*this);
- ar & attr_;
- }
-};
-
-class NodeTimeMemento : public Memento {
-public:
- NodeTimeMemento( const ecf::TimeAttr& attr) : attr_(attr) {}
- NodeTimeMemento() {}
-private:
- virtual void do_incremental_node_sync(Node* n) const { n->set_memento(this);}
-
- ecf::TimeAttr attr_;
- friend class Node;
- friend class TimeDepAttrs;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object<Memento>(*this);
- ar & attr_;
- }
-};
-
-class NodeDayMemento : public Memento {
-public:
- NodeDayMemento( const DayAttr& attr) : attr_(attr) {}
- NodeDayMemento(){}
-private:
- virtual void do_incremental_node_sync(Node* n) const { n->set_memento(this);}
-
- DayAttr attr_;
- friend class Node;
- friend class TimeDepAttrs;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object<Memento>(*this);
- ar & attr_;
- }
-};
-
-class NodeCronMemento : public Memento {
-public:
- NodeCronMemento( const ecf::CronAttr& attr) : attr_(attr) {}
- NodeCronMemento() {}
-private:
- virtual void do_incremental_node_sync(Node* n) const { n->set_memento(this);}
-
- ecf::CronAttr attr_;
- friend class Node;
- friend class TimeDepAttrs;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object<Memento>(*this);
- ar & attr_;
- }
-};
-
-class NodeDateMemento : public Memento {
-public:
- NodeDateMemento( const DateAttr& attr) : attr_(attr) {}
- NodeDateMemento() {}
-private:
- virtual void do_incremental_node_sync(Node* n) const { n->set_memento(this);}
-
- DateAttr attr_;
- friend class Node;
- friend class TimeDepAttrs;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object<Memento>(*this);
- ar & attr_;
- }
-};
-
-class NodeZombieMemento : public Memento {
-public:
- NodeZombieMemento(const ZombieAttr& attr) : attr_(attr) {}
- NodeZombieMemento() {}
-private:
- virtual void do_incremental_node_sync(Node* n) const { n->set_memento(this);}
-
- ZombieAttr attr_;
- friend class Node;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object<Memento>(*this);
- ar & attr_;
- }
-};
-
-
-class NodeVerifyMemento : public Memento {
-public:
- NodeVerifyMemento(const std::vector<VerifyAttr>& attr) : verifys_(attr) {}
- NodeVerifyMemento() {}
-private:
- virtual void do_incremental_node_sync(Node* n) const { n->set_memento(this);}
-
- std::vector<VerifyAttr> verifys_;
- friend class Node;
- friend class MiscAttrs;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object<Memento>(*this);
- ar & verifys_;
- }
-};
-
-class SubmittableMemento : public Memento {
-public:
- SubmittableMemento( const std::string& jobsPassword,
- const std::string& process_or_remote_id,
- const std::string& abortedReason,
- int tryNo
- ) :
- jobsPassword_( jobsPassword ),
- process_or_remote_id_( process_or_remote_id ),
- abortedReason_( abortedReason ),
- tryNo_( tryNo ) {}
- SubmittableMemento() : tryNo_(0) {}
-private:
- virtual void do_incremental_task_sync(Task* n) const { n->set_memento(this);}
- virtual void do_incremental_alias_sync(Alias* n) const { n->set_memento(this);}
-
- std::string jobsPassword_;
- std::string process_or_remote_id_;
- std::string abortedReason_;
- int tryNo_;
- friend class Submittable;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object<Memento>(*this);
- ar & jobsPassword_;
- ar & process_or_remote_id_;
- ar & abortedReason_;
- ar & tryNo_;
- }
-};
-
-class SuiteClockMemento : public Memento {
-public:
- SuiteClockMemento( const ClockAttr& c ) : clockAttr_(c) {}
- SuiteClockMemento() {}
-private:
- virtual void do_incremental_suite_sync(Suite* n) const { n->set_memento(this);}
-
- ClockAttr clockAttr_;
- friend class Suite;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object<Memento>(*this);
- ar & clockAttr_;
- }
-};
-
-class SuiteBeginDeltaMemento : public Memento {
-public:
- SuiteBeginDeltaMemento(bool begun) : begun_(begun) {}
- SuiteBeginDeltaMemento() : begun_(false) {}
-private:
- virtual void do_incremental_suite_sync(Suite* n) const { n->set_memento(this);}
-
- bool begun_;
- friend class Suite;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object<Memento>(*this);
- ar & begun_;
- }
-};
-
-class SuiteCalendarMemento : public Memento {
-public:
- SuiteCalendarMemento(const ecf::Calendar& cal) : calendar_(cal) {}
- SuiteCalendarMemento() {}
-private:
- virtual void do_incremental_suite_sync(Suite* n) const { n->set_memento(this);}
-
- ecf::Calendar calendar_; // *Only* persisted since used by the why() on client side
- friend class Suite;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object<Memento>(*this);
- ar & calendar_;
- }
-};
-
-
-BOOST_CLASS_EXPORT_KEY(StateMemento);
-BOOST_CLASS_EXPORT_KEY(NodeDefStatusDeltaMemento);
-BOOST_CLASS_EXPORT_KEY(SuspendedMemento);
-BOOST_CLASS_EXPORT_KEY(ServerStateMemento);
-BOOST_CLASS_EXPORT_KEY(ServerVariableMemento);
-BOOST_CLASS_EXPORT_KEY(NodeEventMemento);
-BOOST_CLASS_EXPORT_KEY(NodeMeterMemento);
-BOOST_CLASS_EXPORT_KEY(NodeLabelMemento);
-BOOST_CLASS_EXPORT_KEY(NodeTriggerMemento);
-BOOST_CLASS_EXPORT_KEY(NodeCompleteMemento);
-BOOST_CLASS_EXPORT_KEY(NodeRepeatMemento);
-BOOST_CLASS_EXPORT_KEY(NodeLimitMemento);
-BOOST_CLASS_EXPORT_KEY(NodeInLimitMemento);
-BOOST_CLASS_EXPORT_KEY(NodeVariableMemento);
-BOOST_CLASS_EXPORT_KEY(NodeLateMemento);
-BOOST_CLASS_EXPORT_KEY(NodeTodayMemento);
-BOOST_CLASS_EXPORT_KEY(NodeTimeMemento);
-BOOST_CLASS_EXPORT_KEY(NodeDayMemento);
-BOOST_CLASS_EXPORT_KEY(NodeCronMemento);
-BOOST_CLASS_EXPORT_KEY(NodeDateMemento);
-BOOST_CLASS_EXPORT_KEY(NodeZombieMemento);
-BOOST_CLASS_EXPORT_KEY(FlagMemento);
-BOOST_CLASS_EXPORT_KEY(NodeVerifyMemento);
-BOOST_CLASS_EXPORT_KEY(SubmittableMemento);
-BOOST_CLASS_EXPORT_KEY(SuiteClockMemento);
-BOOST_CLASS_EXPORT_KEY(SuiteBeginDeltaMemento);
-BOOST_CLASS_EXPORT_KEY(SuiteCalendarMemento);
-BOOST_CLASS_EXPORT_KEY(OrderMemento);
-BOOST_CLASS_EXPORT_KEY(ChildrenMemento);
-BOOST_CLASS_EXPORT_KEY(AliasChildrenMemento);
-BOOST_CLASS_EXPORT_KEY(AliasNumberMemento);
-
-#endif
diff --git a/ecflow_4_0_7/ANode/src/MiscAttrs.cpp b/ecflow_4_0_7/ANode/src/MiscAttrs.cpp
deleted file mode 100644
index d86b586..0000000
--- a/ecflow_4_0_7/ANode/src/MiscAttrs.cpp
+++ /dev/null
@@ -1,178 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #286 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <assert.h>
-#include "Defs.hpp"
-#include "Suite.hpp"
-
-#include "MiscAttrs.hpp"
-#include "Str.hpp"
-#include "Log.hpp"
-#include "Ecf.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-
-///////////////////////////////////////////////////////////////////////////////////////////
-
-void MiscAttrs::begin()
-{
- // reset verification
- for(size_t i = 0; i < verifys_.size(); i++) { verifys_[i].reset(); }
-}
-
-std::ostream& MiscAttrs::print(std::ostream& os) const
-{
- BOOST_FOREACH(const ZombieAttr& z, zombies_) { z.print(os); }
- BOOST_FOREACH(const VerifyAttr& v, verifys_ ) { v.print(os); }
- return os;
-}
-
-bool MiscAttrs::operator==(const MiscAttrs& rhs) const
-{
- if (zombies_.size() != rhs.zombies_.size()) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "MiscAttrs::operator== (zombies_.size() != rhs.zombies_.size()) " << node_->debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- for(unsigned i = 0; i < zombies_.size(); ++i) {
- if (!(zombies_[i] == rhs.zombies_[i]) ) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "MiscAttrs::operator== (!(zombies_[i] == rhs.zombies_[i]) " << node_->debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- }
-
- if (verifys_.size() != rhs.verifys_.size()) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "MiscAttrs::operator== (verifys_.size() != rhs.verifys_.size()) " << node_->debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- for(unsigned i = 0; i < verifys_.size(); ++i) {
- if (!(verifys_[i] == rhs.verifys_[i] )) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "MiscAttrs::operator== (!(verifys_[i] == rhs.verifys_[i] )) " << node_->debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- }
- return true;
-}
-
-
-void MiscAttrs::verification(std::string& errorMsg) const
-{
- BOOST_FOREACH(const VerifyAttr& v, verifys_) {
- if (v.expected() != v.actual()) {
- std::stringstream ss;
- ss << node_->debugNodePath() << " expected " << v.expected() << " " << NState::toString(v.state()) << " but found " << v.actual() << "\n";
- errorMsg += ss.str();
- }
- }
-}
-
-void MiscAttrs::addZombie( const ZombieAttr& z)
-{
- const ZombieAttr& theFndOne = findZombie( z.zombie_type() );
- if (!theFndOne.empty()) {
- std::stringstream ss;
- ss << "MiscAttrs::addZombie: Node " << node_->absNodePath() << " already has a zombie attribute of type " << Child::to_string(theFndOne.zombie_type()) << "\n";
- throw std::runtime_error(ss.str());
- }
- zombies_.push_back( z );
- node_->state_change_no_ = Ecf::incr_state_change_no(); // Only add where used in AlterCmd
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "MiscAttrs::addZombie()\n";
-#endif
-}
-
-
-void MiscAttrs::deleteZombie(const std::string& zombie_type)
-{
- if (zombie_type.empty()) {
- zombies_.clear();
- node_->state_change_no_ = Ecf::incr_state_change_no();
- return;
- }
-
- if (!Child::valid_zombie_type(zombie_type)) {
- throw std::runtime_error("MiscAttrs::deleteZombie failed: Expected one of [ ecf | path | user ] or empty string but found " + zombie_type);
- }
- delete_zombie( Child::zombie_type(zombie_type) );
-}
-
-void MiscAttrs::delete_zombie(Child::ZombieType zt)
-{
- for(size_t i = 0; i < zombies_.size(); ++i) {
- if (zombies_[i].zombie_type() == zt) {
- zombies_.erase( zombies_.begin() + i );
- node_->state_change_no_ = Ecf::incr_state_change_no();
- return;
- }
- }
-}
-
-
-const ZombieAttr& MiscAttrs::findZombie( ecf::Child::ZombieType zombie_type) const
-{
- /// There should only be one of each type
- for(size_t i = 0; i < zombies_.size(); i++) {
- if ( zombies_[i].zombie_type() == zombie_type ) {
- return zombies_[i];
- }
- }
- return ZombieAttr::EMPTY();
-}
-
-void MiscAttrs::addVerify( const VerifyAttr& v )
-{
- if (findVerify(v)) {
- std::stringstream ss;
- ss << "Add Verify failed: Duplicate '" << v.toString() << "' already exist for node " << node_->debugNodePath();
- throw std::runtime_error( ss.str() );
- }
- verifys_.push_back(v);
- node_->state_change_no_ = Ecf::incr_state_change_no();
-}
-
-bool MiscAttrs::findVerify(const VerifyAttr& v) const
-{
- size_t theSize = verifys_.size();
- for(size_t i = 0; i < theSize; i++) {
- if (verifys_[i].state() == v.state() ) {
- return true;
- }
- }
- return false;
-}
-
-void MiscAttrs::clear()
-{
- zombies_.clear(); // can be added/removed via AlterCmd
- verifys_.clear();
-}
diff --git a/ecflow_4_0_7/ANode/src/MiscAttrs.hpp b/ecflow_4_0_7/ANode/src/MiscAttrs.hpp
deleted file mode 100644
index ac27d2d..0000000
--- a/ecflow_4_0_7/ANode/src/MiscAttrs.hpp
+++ /dev/null
@@ -1,89 +0,0 @@
-#ifndef MISC_ATTRS_HPP_
-#define MISC_ATTRS_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #235 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <ostream>
-
-#include <boost/noncopyable.hpp>
-#include <boost/serialization/base_object.hpp>
-#include <boost/serialization/utility.hpp>
-#include <boost/serialization/vector.hpp> // no need to include <vector>
-
-#include "ZombieAttr.hpp"
-#include "VerifyAttr.hpp"
-#include "NodeFwd.hpp"
-
-class MiscAttrs : private boost::noncopyable {
-public:
- MiscAttrs(Node* node) : node_(node) {}
- MiscAttrs() : node_(NULL) {}
-
- // needed by node serialisation
- void set_node(Node* n) { node_ = n; }
-
- void begin();
-
- // standard functions: ==============================================
- std::ostream& print(std::ostream&) const;
- bool operator==(const MiscAttrs& ) const;
-
- // Access functions: ======================================================
- const std::vector<VerifyAttr>& verifys() const { return verifys_;}
- const std::vector<ZombieAttr>& zombies() const { return zombies_; }
-
- // Add functions: ===============================================================
- void addVerify( const VerifyAttr& ); // for testing and verification Can throw std::runtime_error
- void addZombie( const ZombieAttr& ); // will throw std::runtime_error if duplicate
-
- // Delete functions: can throw std::runtime_error ===================================
- // if name argument is empty, delete all attributes of that type
- // Can throw std::runtime_error of the attribute can not be found
- void delete_zombie(const ecf::Child::ZombieType);
- void deleteZombie(const std::string& type); // string must be one of [ user | ecf | path ]
-
- // Change functions: ================================================================
- /// returns true the change was made else false, Can throw std::runtime_error for parse errors
-
- // Find functions: ============================================================
- bool findVerify(const VerifyAttr& ) const;
- const ZombieAttr& findZombie( ecf::Child::ZombieType ) const;
-
- void verification(std::string& errorMsg) const;
-
-private:
- void clear(); /// Clear *ALL* internal attributes
-
- std::vector<ZombieAttr>::const_iterator zombie_begin() const { return zombies_.begin();}
- std::vector<ZombieAttr>::const_iterator zombie_end() const { return zombies_.end();}
- std::vector<VerifyAttr>::const_iterator verify_begin() const { return verifys_.begin();}
- std::vector<VerifyAttr>::const_iterator verify_end() const { return verifys_.end();}
-
-private:
- Node* node_; // *NOT* persisted must be set by the parent class
- friend class Node;
-
-private:
- std::vector<ZombieAttr> zombies_;
- std::vector<VerifyAttr> verifys_; // used for statistics and test verification
-
-private:
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/) {
- ar & zombies_;
- ar & verifys_;
- }
-};
-#endif
diff --git a/ecflow_4_0_7/ANode/src/Node.cpp b/ecflow_4_0_7/ANode/src/Node.cpp
deleted file mode 100644
index 60c32c1..0000000
--- a/ecflow_4_0_7/ANode/src/Node.cpp
+++ /dev/null
@@ -1,1870 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #305 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <assert.h>
-#include <deque>
-
-#include <boost/bind.hpp>
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Task.hpp"
-#include "Extract.hpp"
-
-#include "NodeState.hpp"
-#include "NodePath.hpp"
-#include "Stl.hpp"
-#include "Str.hpp"
-#include "Indentor.hpp"
-#include "ExprAst.hpp"
-#include "Log.hpp"
-#include "PrintStyle.hpp"
-#include "JobsParam.hpp"
-#include "ExprAstVisitor.hpp"
-#include "Ecf.hpp"
-#include "SuiteChanged.hpp"
-#include "CmdContext.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-
-///////////////////////////////////////////////////////////////////////////////////////////
-//#define DEBUG_DEPENDENCIES 1
-//#define DEBUG_REQUEUE 1
-//#define DEBUG_FIND_REFERENCED_NODE 1
-
-Node::Node(const std::string& n)
-: parent_(NULL),name_(n),
- suspended_(false),
- state_( std::make_pair(NState(),time_duration(0,0,0,0)) ),
- completeExpr_(NULL),
- triggerExpr_(NULL),
- lateAttr_(NULL),
- autoCancel_(NULL),
- time_dep_attrs_(NULL),
- child_attrs_(NULL),
- misc_attrs_(NULL),
- inLimitMgr_(this),
- state_change_no_(0),variable_change_no_(0),suspended_change_no_(0),
- graphic_ptr_(0)
-{
- string msg;
- if (!Str::valid_name(n, msg)) {
- throw std::runtime_error("Invalid node name : " + msg);
- }
-}
-
-Node::Node()
-: parent_(NULL),
- suspended_(false),
- state_( std::make_pair(NState(),time_duration(0,0,0,0)) ),
- completeExpr_(NULL),
- triggerExpr_(NULL),
- lateAttr_(NULL),
- autoCancel_(NULL),
- time_dep_attrs_(NULL),
- child_attrs_(NULL),
- misc_attrs_(NULL),
- inLimitMgr_(this),
- state_change_no_(0),variable_change_no_(0),suspended_change_no_(0),
- graphic_ptr_(0)
-{}
-
-Node::~Node() {
- delete completeExpr_;
- delete triggerExpr_;
- delete lateAttr_;
- delete autoCancel_;
- delete time_dep_attrs_;
- delete child_attrs_;
- delete misc_attrs_;
-}
-
-bool Node::isParentSuspended() const
-{
- Node* theParent = parent();
- if (theParent) {
- if (theParent->isSuspended()) return true;
- return theParent->isParentSuspended();
- }
- return defs()->isSuspended(); // obtained from the server states
-}
-
-void Node::resume()
-{
- if ( suspended_) {
- clearSuspended();
- }
-}
-
-void Node::clearSuspended()
-{
- /// Guard against unnecessary creation of memento's
- if (suspended_) {
- suspended_ = false;
- suspended_change_no_ = Ecf::incr_state_change_no();
- }
-}
-
-void Node::suspend()
-{
- // Typically called via user action or via defstatus
- suspended_ = true;
- suspended_change_no_ = Ecf::incr_state_change_no();
-}
-
-void Node::begin()
-{
- // Set the state without causing any side effects
- initState(0);
-
- clearTrigger();
- clearComplete();
-
- flag_.reset();
- repeat_.reset(); // if repeat is empty reset() does nothing
-
- if (lateAttr_) lateAttr_->reset();
- if (child_attrs_) child_attrs_->begin();
- if (misc_attrs_) misc_attrs_->begin();
- for(size_t i = 0; i < limitVec_.size(); i++) { limitVec_[i]->reset(); }
-
- // Let time base attributes use, relative duration if applicable
- if (time_dep_attrs_) {
- time_dep_attrs_->begin();
- time_dep_attrs_->markHybridTimeDependentsAsComplete();
- }
-
- // DO *NOT* call update_generated_variables(). Called on a type specific bases, for begin
- // Typically we need only call update_generated_variables() for a task, at job creation time.
- // so that ECF_OUT, ECF_TRYNO, ECF_JOBOUT, ECF_PASS(jobsPassword_) can be updated.
- // However the generated variables are used when within job generation and can be referenced by AST
- // Hence to avoid excessive memory consumption, they are created on demand
-}
-
-void Node::requeue(
- bool resetRepeats,
- int clear_suspended_in_child_nodes,
- bool do_reset_next_time_slot)
-{
-#ifdef DEBUG_REQUEUE
- LOG(Log::DBG," Node::requeue() " << absNodePath() << " resetRepeats = " << resetRepeats);
-#endif
- /// Note: we don't reset verify attributes as they record state stat's
-
- // Set the state without causing any side effects
- initState(clear_suspended_in_child_nodes);
-
- clearTrigger();
- clearComplete();
-
- if (resetRepeats) repeat_.reset(); // if repeat is empty reset() does nothing
-
-
- /// If a job takes longer than it slots, then that slot is missed, and next slot is used
- /// Note we do *NOT* reset for requeue as we want to advance the valid time slots.
- /// *NOTE* Update calendar will *free* time dependencies *even* time series. They rely
- /// on this function to clear the time dependencies so they *HOLD* the task.
- if ( time_dep_attrs_ ) {
-
- /// Requeue has several contexts:
- /// 1/ manual requeue
- /// 2/ automated requeue due to repeats
- /// 3/ automated requeue due to time dependencies
- /// For manual and automated reueue due to repeat's we always clear Flag::NO_REQUE_IF_SINGLE_TIME_DEP
- /// since in those context we do NOT want miss any time slots
- bool reset_next_time_slot = true;
- if (do_reset_next_time_slot) {
- reset_next_time_slot = true;
- }
- else {
- if (flag().is_set(Flag::NO_REQUE_IF_SINGLE_TIME_DEP)) {
- /// If we have done an interactive run or complete, *dont* increment next_time_slot_
- /// allow next time on time based attributes to be incremented and *not* reset,
- /// when force and run commands used
- reset_next_time_slot = false;
- }
- }
-
- time_dep_attrs_->requeue(reset_next_time_slot);
- time_dep_attrs_->markHybridTimeDependentsAsComplete();
- }
-
-
- // reset the flags, however remember if edit were made
- bool edit_history_set = flag().is_set(ecf::Flag::MESSAGE);
- flag_.reset(); // will CLEAR NO_REQUE_IF_SINGLE_TIME_DEP
- if (edit_history_set) flag().set(ecf::Flag::MESSAGE);
-
-
- if (lateAttr_) lateAttr_->reset();
- if (child_attrs_) child_attrs_->requeue();
-
- for(size_t i = 0; i < limitVec_.size(); i++) { limitVec_[i]->reset(); }
-
- // ECFLOW-196, ensure the re-queue release tokens held by Limits higher up the tree.
- // Note: Its safe to call decrementInLimit, even when no limit consumed
- std::set<Limit*> limitSet; // ensure local limit have preference over parent
- decrementInLimit(limitSet); // will recurse up, expensive but needed
-}
-
-
-void Node::requeue_time_attrs()
-{
- // Note: we *dont* mark hybrid time dependencies as complete.
- // i.e. since this is called during alter command, it could be that
- // the task is in a submitted or active state.
- if (time_dep_attrs_) time_dep_attrs_->requeue(true);
-}
-
-void Node::requeue_labels()
-{
- if (child_attrs_) child_attrs_->requeue_labels();
-}
-
-void Node::miss_next_time_slot()
-{
- // Why do we need to set NO_REQUE_IF_SINGLE_TIME_DEP flag ?
- // This is required when we have time based attributes, which we want to miss.
- // time 10:00
- // time 12:00
- // Essentially this avoids an automated job run, *IF* the job was run manually for a given time slot.
- // If we call this function before 10:00, we want to miss the next time slot (i.e. 10:00)
- // and want to *requeue*, for 12:00 time slot. However at re-queue, we need to ensure
- // we do *not* reset the 10:00 time slot. hence by setting NO_REQUE_IF_SINGLE_TIME_DEP
- // we allow requeue to query this flag, and hence avoid resetting the time based attribute
- // Note: requeue will *always* clear NO_REQUE_IF_SINGLE_TIME_DEP afterwards.
- //
- // In the case above when we reach the last time slot, there is *NO* automatic requeue, and
- // hence, *no* clearing of NO_REQUE_IF_SINGLE_TIME_DEP flag.
- // This will then be up to any top level parent that has a Repeat/cron to force a requeue
- // when all the children are complete. *or* user does a manual re-queue
- //
- // Additionally if the job *aborts*, we clear NO_REQUE_IF_SINGLE_TIME_DEP if it was set.
- // Otherwise if manually run again, we will miss further time slots.
- if ( time_dep_attrs_) {
-
- /// Handle abort
- /// The flag: NO_REQUE_IF_SINGLE_TIME_DEP is *only* set when doing an interactive force complete or run command.
- /// What happens if the job aborts during the run command ?
- /// time 10:00
- /// time 11:00
- /// If at 9.00am we used the run command, we want to miss the 10:00 time slot.
- /// However if the run at 9.00 fails, and we run again, we also miss 11:00 time slot.
- /// During the run the flag is still set.
- /// Hence *ONLY* miss the next time slot *IF* Flag::NO_REQUE_IF_SINGLE_TIME_DEP is NOT set
- if (!flag().is_set(Flag::NO_REQUE_IF_SINGLE_TIME_DEP)) {
-
- SuiteChanged0 changed(shared_from_this());
- flag().set(Flag::NO_REQUE_IF_SINGLE_TIME_DEP);
-
- time_dep_attrs_->miss_next_time_slot();
- }
- }
-}
-
-void Node::calendarChanged(
- const ecf::Calendar& c,
- std::vector<node_ptr>& auto_cancelled_nodes)
-{
- if (time_dep_attrs_) {
- time_dep_attrs_->calendarChanged(c);
- }
-
- checkForLateness(c);
-
- if (checkForAutoCancel(c)) {
- auto_cancelled_nodes.push_back(shared_from_this());
- }
-}
-
-void Node::checkForLateness(const ecf::Calendar& c)
-{
- if (lateAttr_) {
- lateAttr_->checkForLateness(state_, c);
- if (lateAttr_->isLate()) {
- flag().set(ecf::Flag::LATE);
- }
- }
-}
-
-void Node::initState(int clear_suspended_in_child_nodes)
-{
- if (defStatus_ == DState::SUSPENDED) {
- /// Note: DState::SUSPENDED is not a real state, its really a user interaction
- /// Replace with suspend, and set underlying state as queued
- suspend();
- setStateOnly( NState::QUEUED );
- }
- else {
-
- if (clear_suspended_in_child_nodes > 0) {
- clearSuspended();
- }
-
- // convert DState --> NState.
- // NOTE:: NState does *NOT* have SUSPENDED
- setStateOnly( DState::convert( defStatus_.state()) );
- }
-}
-
-void Node::requeueOrSetMostSignificantStateUpNodeTree()
-{
- // Get the computed state of my immediate children
- // *** A family can be marked as complete, via complete trigger when not all its children
- // *** are complete, hence computedState() *MUST* first check the immediate state ,
- // *** before considering its immediate children
- NState::State computedStateOfImmediateChildren = computedState(Node::IMMEDIATE_CHILDREN);
-
-#ifdef DEBUG_REQUEUE
- LogToCout toCoutAsWell; cout << "\n";
- Indentor indent;
- LOG(Log::DBG,"requeueOrSetMostSignificantStateUpNodeTree() " << debugNodePath() << "(" << NState::toString(state()) << ") computed(" << NState::toString(computedStateOfImmediateChildren) << ")");
-#endif
-
- if (computedStateOfImmediateChildren == NState::COMPLETE ) {
-
- // set most significant state of my immediate children
- // Record: That Suite/Family completed.
- if ( computedStateOfImmediateChildren != state() ) {
- setStateOnly( computedStateOfImmediateChildren );
- }
-
- // For automated re-queue do *not* clear suspended state in *child* nodes
- int clear_suspended_in_child_nodes = -1;
-
- if (!repeat_.empty()) {
-
- repeat_.increment();
-
- // If the repeat is still valid, re-queue the node
-#ifdef DEBUG_REQUEUE
- LOG(Log::DBG,"requeueOrSetMostSignificantStateUpNodeTree " << debugNodePath() << " for repeat " << repeat_.toString());
-#endif
- if ( repeat_.valid() ) {
-#ifdef DEBUG_REQUEUE
- LOG(Log::DBG,"requeueOrSetMostSignificantStateUpNodeTree() VALID for requeue " << debugNodePath() << " for repeat at " << repeat_.toString());
-#endif
-
- /// reset relative duration down the hierarchy from this point. Only valid when we have repeats
- /// Note: Going down hierarchy is wasted if there are no relative time attributes
- resetRelativeDuration();
-
- // Remove effects of RUN and Force complete interactive commands
- // For automated re-queue *DUE* to Repeats, *CLEAR* any user interaction that would miss the next time slots. *Down* the hierarchy
- // This handles the case where a user, has manually intervened (i.e via run or complete) and we had a time attribute
- // That time attribute will have expired, typically we show next day. In the case where we have a parent repeat
- // we need to clear the flag, otherwise the task/family with time based attribute would wait for next day.
- requeue( false /* don't reset repeats */,
- clear_suspended_in_child_nodes,
- true /* reset_next_time_slot */ );
- set_most_significant_state_up_node_tree();
- return;
- }
- }
-
- /// If user has *INTERACTIVLY* forced changed in state to complete *OR* run the job.
- /// This would cause Node to miss the next time slot. i.e expire the time slot
- /// In which case testTimeDependenciesForRequeue should return false for a single time/today dependency
- /// and not requeue the node.
- if (time_dep_attrs_ && time_dep_attrs_->testTimeDependenciesForRequeue()) {
-
- // This is the only place we do not explicitly reset_next_time_slot
- bool reset_next_time_slot = false;
-
- // Remove effects of RUN and Force complete interactive commands, *BUT* only if *not* applied to this cron
- if (!time_dep_attrs_->crons().empty()) {
- if (!flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP)) {
- reset_next_time_slot = true ;
- }
- }
-
- requeue( false /* don't reset repeats */,
- clear_suspended_in_child_nodes,
- reset_next_time_slot );
- set_most_significant_state_up_node_tree();
- return;
- }
- }
-
- // In case compute state is other that COMPLETE, update. i,e for Family/Suite
- if ( computedStateOfImmediateChildren != state() ) {
- setStateOnly( computedStateOfImmediateChildren );
- }
-
-
- // recurse up the node tree
- Node* theParentNode = parent();
- if (theParentNode) {
- theParentNode->requeueOrSetMostSignificantStateUpNodeTree();
- }
- else {
- // No parent, hence next level is the root, ie the Defs
- // Reflect the status of all the suite's
- // **** This should not recurse down, just reflect status of suites
- defs()->set_most_significant_state();
- }
-}
-
-void Node::set_most_significant_state_up_node_tree()
-{
- if (isTask()) {
- parent()->set_most_significant_state_up_node_tree();
- return;
- }
-
- // set most significant state of my immediate children
- NState::State computedStateOfImmediateChildren = computedState(Node::IMMEDIATE_CHILDREN);
- if ( computedStateOfImmediateChildren != state() ) {
- setStateOnly( computedStateOfImmediateChildren );
- }
-
- // recurse up the node tree
- Node* theParentNode = parent();
- if (theParentNode) {
- theParentNode->set_most_significant_state_up_node_tree();
- }
- else {
- // No parent, hence next level is the root, ie the Defs
- // Reflect the status of all the suite's
- // **** This should not recurse down, just reflect status of suites
- defs()->set_most_significant_state();
- }
-}
-void Node::resetRelativeDuration()
-{
- if (time_dep_attrs_) time_dep_attrs_->resetRelativeDuration();
-}
-
-
-// Returning false, *STOPS* further traversal *DOWN* the node tree
-bool Node::resolveDependencies(JobsParam& jobsParam)
-{
- // This function is called:
- // a/ Periodically by the server, i.e every minute
- // b/ Asyncrousnly, after child command, via job submission
-#ifdef DEBUG_DEPENDENCIES
- LogToCout toCoutAsWell; cout << "\n";
- LOG(Log::DBG," " << debugNodePath() << "::resolveDependencies " << NState::toString(state()) << " AT " << suite()->calendar().toString());
-#endif
-
- // Improve the granularity for the check for lateness (during job submission). See SUP-873 "late" functionality
- if (lateAttr_) {
- // since the suite() traverse up the tree, only call when have a late attribute
- checkForLateness(suite()->calendar());
- }
-
- if (isSuspended()) {
-#ifdef DEBUG_DEPENDENCIES
- LOG(Log::DBG," Node::resolveDependencies() " << absNodePath() << " HOLDING as node state " << NState::toString(state()) << " is SUSPENDED " );
-#endif
- return false;
- }
-
- if (state() == NState::COMPLETE) {
-#ifdef DEBUG_DEPENDENCIES
- LOG(Log::DBG," Node::resolveDependencies() " << absNodePath() << " HOLDING as node state " << NState::toString(state()) << " is not valid for job submission" );
-#endif
- return false;
- }
-
- if (time_dep_attrs_ && !time_dep_attrs_->timeDependenciesFree()) {
-#ifdef DEBUG_DEPENDENCIES
- const Calendar& calendar = suite()->calendar();
- LOG(Log::DBG," Node::resolveDependencies() " << absNodePath() << " HOLDING due to time dependencies at " << calendar.toString());
-#endif
- return false;
- }
-
- // Complete *MUST* be evaluated before trigger. As it can affect the other
- // i.e A state change to COMPLETE, in which case no need to submit tasks
- // However if the complete does *not* evaluate it should *NOT* hold the node.
- if ( evaluateComplete() ) {
- if (completeAst()) {
-
- flag().set(ecf::Flag::BYRULE);
-
- // If we are a parent sets the state first. then set state on all the children
- set_state_hierarchically( NState::COMPLETE,false); // reset try no and decrement inlimit resources & update repeats
-
-#ifdef DEBUG_DEPENDENCIES
- LOG(Log::DBG," Node::resolveDependencies() " << absNodePath() << " HOLDING since evaluation of COMPLETE");
-#endif
- // We have a complete By returning false here, we stop dependency evaluation for any children
- return false;
- }
- }
- // No complete, or we have a complete that does not evaluate.(this should not hold the node)
-
-
- if ( evaluateTrigger() ) {
- // WE only get here **IF** :
- // 1/ There is no trigger
- // 2/ WE have a trigger and it evaluates to true
-#ifdef DEBUG_DEPENDENCIES
- LOG(Log::DBG," Node::resolveDependencies() " << absNodePath() << " FREE of TRIGGER");
-#endif
- return true;
- }
-
- // We *have* a trigger and it does not evaluate, hold the node
-#ifdef DEBUG_DEPENDENCIES
- LOG(Log::DBG," Node::resolveDependencies() " << absNodePath() << " HOLDING due to TRIGGER");
-#endif
- return false;
-}
-
-void Node::freeTrigger() const
-{
- if (triggerExpr_) triggerExpr_->setFree();
-}
-
-void Node::clearTrigger() const
-{
- if (triggerExpr_) triggerExpr_->clearFree();
-}
-
-void Node::freeComplete() const
-{
- if (completeExpr_) completeExpr_->setFree();
-}
-
-void Node::clearComplete() const
-{
- if (completeExpr_) completeExpr_->clearFree();
-}
-
-void Node::freeHoldingDateDependencies()
-{
- if (time_dep_attrs_) time_dep_attrs_->freeHoldingDateDependencies();
-}
-
-void Node::freeHoldingTimeDependencies()
-{
- if (time_dep_attrs_) time_dep_attrs_->freeHoldingTimeDependencies();
-}
-
-bool Node::checkForAutoCancel(const ecf::Calendar& calendar) const
-{
- if ( autoCancel_ && state() == NState::COMPLETE) {
- if (autoCancel_->isFree(calendar,state_.second)) {
-
- /// *Only* delete this node if we don't create zombies
- /// anywhere for our children
- vector<Task*> taskVec;
- getAllTasks(taskVec);
- BOOST_FOREACH(Task* t, taskVec) {
- if (t->state() == NState::ACTIVE || t->state() == NState::SUBMITTED) {
- return false;
- }
- }
- return true;
- }
- }
- return false;
-}
-
-bool Node::evaluateComplete() const
-{
- // Complete *MUST* be evaluate before trigger. As it can affect the other
- AstTop* theCompeteAst = completeAst();
- if (theCompeteAst) {
- // *NOTE* if we have a non NULL complete ast, we must have complete expression
- // The freed state is stored on the expression ( i.e not on the ast)
- // ISSUE: Complete expression can not be by-passed in the GUI
- if (completeExpr_->isFree() || theCompeteAst->evaluate()) {
-
- // Note: if a task has been set complete, the use may decide to place into queued state( via GUI)
- // In which case, we *want* this complete expression to be re-evaluated.
- // Hence the old code below has been commented out.
- // >>old: Set the complete as free, until begin()/requeue, // Only update state change no, if state has changed.
- // >>old:if (!completeExpr_->isFree()) freeComplete();
-
- // If we have **any** children that are in STATE ACTIVE or SUMBMITTED the don't bother
- // changing state to complete. Otherwise zombies will be created.
- NState::State theComputedState = computedState(Node::HIERARCHICAL);
- if ( theComputedState == NState::ACTIVE || theComputedState == NState::SUBMITTED) {
-#ifdef DEBUG_DEPENDENCIES
- LOG(Log::DBG," Node::evaluateComplete() " << absNodePath() << " AST evaluation succeeded *BUT* " << debugType() << " has children in ACTIVE or SUBMITTED States" );
-#endif
- return false;
- }
-
-#ifdef DEBUG_DEPENDENCIES
- LOG(Log::DBG," Node::evaluateComplete() " << debugNodePath() << " FREE, COMPLETE AST evaluation succeeded " );
-#endif
- return true;
- }
- else {
- /// *IMPORTANT* When a complete does not evaluate, it should *NOT* stop further tree walking
-#ifdef DEBUG_DEPENDENCIES
- LOG(Log::DBG," Node::evaluateComplete() " << debugNodePath() << " HOLDING, COMPLETE AST evaluation failed" );
-#endif
- return false;
- }
- }
- return true;
-}
-
-bool Node::evaluateTrigger() const
-{
- AstTop* theTriggerAst = triggerAst();
- if (theTriggerAst) {
-
- // Note 1: A trigger can be freed by the ForceCmd
- // Note 2: if we have a non NULL trigger ast, we must have trigger expression
- // Note 3: The freed state is stored on the expression ( i.e *NOT* on the ast (abstract syntax tree) )
- if (triggerExpr_->isFree() || theTriggerAst->evaluate()) {
-
- // *ALWAYS* evaluate trigger expression unless user has forcibly removed trigger dependencies
- // ******** This allows force queued functionality, to work as expected, since trigger's will be honoured
- // The old code below has been commented out.
- // >> old: Set the trigger as free, until begin()/requeue. Only update state change no, when required
- // >> old: if (!triggerExpr_->isFree()) freeTrigger();
-
-#ifdef DEBUG_DEPENDENCIES
- LOG(Log::DBG," Node::evaluateTrigger() " << debugNodePath() << " FREE, TRIGGER AST evaluation succeeded" );
-#endif
- return true;
- }
-
-#ifdef DEBUG_DEPENDENCIES
- LOG(Log::DBG," Node::evaluateTrigger() " << debugNodePath() << " HOLDING TRIGGER AST evaluation failed" );
-#endif
- return false; // evaluation failed. this Node holds
- }
-
-#ifdef DEBUG_DEPENDENCIES
- LOG(Log::DBG," Node::evaluateTrigger() " << debugNodePath() << " FREE NO TRIGGER defined" );
-#endif
- return true;
-}
-
-const std::string& Node::abortedReason() const { return Str::EMPTY(); }
-
-void Node::set_state(NState::State s, bool force, const std::string& additional_info_to_log)
-{
- setStateOnly(s,false,additional_info_to_log);
-
- // Handle any state change specific functionality. This will update any repeats
- // This is a virtual function, since we want different behaviour during state change
- handleStateChange();
-}
-
-void Node::setStateOnly(NState::State newState, bool force, const std::string& additional_info_to_log)
-{
- Suite* theSuite = suite();
- const Calendar& calendar = theSuite->calendar();
-
-#ifdef DEBUG_JOB_SUBMISSION_INTERVAL
- // check sub submission interval/calendar increment for tasks only
- // The job submission interval is set/obtained from the server environment and
- // is configurable for testing.
- // **** This is only used when jobSubmissionInterval is less than 60 ****
- // We are attempting to refine job submission interval such that it is just
- // greater than time taken for state change from submit->active->complete
- // There by speeding up the test where we generate .ecf
-
- // Ignore this during simulation, ie defs()->server().jobSubmissionInterval() = 0; for simulation
- int jobSubmissionInterval = theSuite->defs()->server().jobSubmissionInterval();
- if (isSubmittable() && jobSubmissionInterval != 0 && jobSubmissionInterval < 60) {
-
- if (newState == NState::SUBMITTED) submit_to_complete_duration_ = Calendar::second_clock_time();
- else if (newState == NState::COMPLETE && !submit_to_complete_duration_.is_special()) {
-
- // Under HYBRID we can go from UNKNOWN->COMPLETE, missing out SUBMITTED
- // hence: submit_to_complete_duration_ is never initialised
- // ie when we have a,date,cron dependency that relies on a day change
-
- time_duration td = (Calendar::second_clock_time() - submit_to_complete_duration_);
- // cout << debugNodePath() << " submit->active->complete time = " << td.total_seconds() << " seconds.\n";
-
- // Avoid this check if we have meters. as we wait a second between each meter update
- if ( td.total_seconds() >= jobSubmissionInterval && ((!child_attrs_) || child_attrs_->meters().empty())) {
-
- const Variable& do_check = theSuite->findVariable("CHECK_TASK_DURATION_LESS_THAN_SERVER_POLL");
- if (!do_check.empty()) {
- // cout << "Calendar::second_clock_time() = " << to_simple_string(Calendar::second_clock_time()) << "\n";
- // cout << "submit_to_complete_duration_ = " << to_simple_string(submit_to_complete_duration_) << "\n";
- // cout << "(Calendar::second_clock_time() - submit_to_complete_duration_) = " << to_simple_string(td) << "\n";
- cout << "Testing::" << debugNodePath() << " For each job submission interval of " << jobSubmissionInterval
- << " seconds, the calendar is increment by 60 seconds.\n"
- << " The job submission interval is too small as it takes " << td.total_seconds()
- << " seconds for state change of submit->active->complete, for an empty job.\n"
- << " Please increase the job submission interval to at least " << (td.total_seconds() + 1) << " seconds.\n";
- }
- }
- }
- }
-#endif
-
- // Change format is significant it is used in verification of log files
- // Please change/update LogVerification::extractNodePathAndState() all verification relies on this one function
- // " " + submitted(max) + ": " + path(estimate) + " try-no: " + try_no(estimate) + " reason: " + reason(estimate)
- // reserve : 1 + 9 + 2 + 100 + 9 + 3 + 9 + 12 = 145
- std::string log_state_change; log_state_change.reserve(145 + additional_info_to_log.size());
- log_state_change += " ";
- log_state_change += NState::toString(newState);
- log_state_change += ": ";
- log_state_change += absNodePath();
- if (!additional_info_to_log.empty()) {
- log_state_change += " ";
- log_state_change += additional_info_to_log;
- }
-
- if ( newState == NState::ABORTED) {
- if (force) flag().set(ecf::Flag::FORCE_ABORT);
- Submittable* submittable = isSubmittable();
- if ( submittable ) {
- flag().set(ecf::Flag::TASK_ABORTED);
- log_state_change += " try-no: ";
- log_state_change += submittable->tryNo();
- log_state_change += " reason: ";
- log_state_change += abortedReason();
- }
- }
- else {
- flag().clear(ecf::Flag::TASK_ABORTED);
- flag().clear(ecf::Flag::FORCE_ABORT);
- }
-
- // SUP-408 what does submitted mean in log?
- // We want to mimimize calls to create a new time stamp in the log file.
- // A time stamp is automatically created, whenever a *new* client request is received, & then cached
- // However we can get a change in state, during tree traversal, when a node is free of its dependencies
- // If we were to just log the message it would use the last cached time stamp. Giving misleading info:
- // Since state changes are bubbled up, we need only update the time stamp for tasks, when not in a command
- if (!CmdContext::in_command() && isTask() && Log::instance()) {
- //std::cout << "!!!!! NOT in cmd context updating time stamp before logging\n";
- Log::instance()->cache_time_stamp();
- }
-
- ecf::log(Log::LOG,log_state_change); // Note: log type, must be same for debug & release for test, i.e for log file verification
-
- state_.first.setState(newState); // this will update state_change_no
- state_.second = calendar.duration(); // record state change duration for late, autocancel,etc
-
- // Record state changes for verification
- if (misc_attrs_) {
- size_t theSize = misc_attrs_->verifys_.size();
- for(size_t i = 0; i < theSize; i++ ) {
- if (misc_attrs_->verifys_[i].state() == newState) misc_attrs_->verifys_[i].incrementActual();
- }
- }
-}
-
-boost::posix_time::ptime Node::state_change_time() const
-{
- const Calendar& calendar = suite()->calendar();
- boost::posix_time::ptime the_state_change_time = calendar.begin_time();
- the_state_change_time += state_.second; // state_.second is calendar duration relative to calendar begin_time
- return the_state_change_time;
-}
-
-
-DState::State Node::dstate() const {
-
- // ECFLOW-139, check for suspended must be done first
- if (isSuspended()) return DState::SUSPENDED;
-
- switch ( state() ) {
- case NState::COMPLETE: return DState::COMPLETE; break;
- case NState::ABORTED: return DState::ABORTED; break;
- case NState::ACTIVE: return DState::ACTIVE; break;
- case NState::SUBMITTED: return DState::SUBMITTED; break;
- case NState::QUEUED: return DState::QUEUED; break;
- case NState::UNKNOWN: return DState::UNKNOWN; break;
- }
- return DState::UNKNOWN;
-}
-
-bool Node::set_event( const std::string& event_name_or_number) {
- if (child_attrs_) return child_attrs_->set_event(event_name_or_number);
- return false;
-}
-bool Node::clear_event(const std::string& event_name_or_number ){
- if (child_attrs_) return child_attrs_->clear_event(event_name_or_number);
- return false;
-}
-
-void Node::setRepeatToLastValue()
-{
- repeat_.setToLastValue(); // no op for empty repeat
- repeat_.increment(); // make repeat invalid
-}
-
-bool Node::check_in_limit_up_node_tree() const
-{
- if (!inLimitMgr_.inLimit()) return false;
-
- Node* theParent = parent();
- while (theParent) {
- if (!theParent->inLimitMgr_.inLimit()) return false;
- theParent = theParent->parent();
- }
- return true;
-}
-
-void Node::incrementInLimit(std::set<Limit*>& limitSet) const
-{
- // cout << "Node::incrementInLimit " << absNodePath() << endl;
- std::string the_abs_node_path = absNodePath();
- inLimitMgr_.incrementInLimit(limitSet,the_abs_node_path);
-
- Node* theParent = parent();
- while (theParent) {
- theParent->inLimitMgr_.incrementInLimit(limitSet,the_abs_node_path);
- theParent = theParent->parent();
- }
-}
-
-void Node::decrementInLimit(std::set<Limit*>& limitSet) const
-{
- // cout << "Node::decrementInLimit " << absNodePath() << endl;
- std::string the_abs_node_path = absNodePath();
- inLimitMgr_.decrementInLimit(limitSet,the_abs_node_path);
-
- Node* theParent = parent();
- while (theParent) {
- theParent->inLimitMgr_.decrementInLimit(limitSet,the_abs_node_path);
- theParent = theParent->parent();
- }
-}
-
-static bool search_user_edit_variables( const std::string& name, std::string& value, const NameValueMap& user_edit_variables )
-{
- NameValueMap::const_iterator i = user_edit_variables.find(name);
- if (i != user_edit_variables.end()) {
- if (((*i).second).empty()) {
- // when we call --edit_script submit file, before a job is submitted the values
- // of generated variables like ECF_RID, ECF_TRYNO, ECF_NAME, ECF_PASS, ECF_JOB, ECF_JOBOUT, ECF_SCRIPT
- // will be empty. In this case return false, so that we pick up the values from the node.
- return false;
- }
- value = (*i).second;
- return true;
- }
- return false;
-}
-
-//#define DEBUG_S 1
-bool Node::variableSubsitution(std::string& cmd) const
-{
- char micro = '%';
- std::string micro_char;
- findParentUserVariableValue(Str::ECF_MICRO(),micro_char);
- if (!micro_char.empty() && micro_char.size() == 1) {
- micro = micro_char[0];
- }
-
- NameValueMap user_edit_variables;
- return variable_substitution(cmd,user_edit_variables,micro);
-}
-
-bool Node::variable_substitution(std::string& cmd, const NameValueMap& user_edit_variables, char micro) const
-{
- // scan the command for variables, and substitute
- // edit ECF_FETCH "/home/ma/map/sms/smsfectch -F %ECF_FILES% -I %ECF_INCLUDE%"
- // We can also have
- //
- // "%<VAR>:<substitute>% i.e if VAR exist use it, else use substitute
- //
- // ************************************************************************************************************
- // Special case handling for user variables, and generated variables, which take precedence over node variables
- // ************************************************************************************************************
- //
- // i.e VAR is defined as BILL
- // %VAR:fred --f% will either be "BILL" or if VAR is not defined "fred --f"
- //
- // Infinite recursion. Its possible to end up with infinite recursion:
- // edit hello '%hello%' # string like %hello% will cause infinite recursion
- // edit fred '%bill%'
- // edit bill '%fred%' # should be 10
- // To prevent this we will use a simple count
-#ifdef DEBUG_S
- cout << "cmd = " << cmd << "\n";
-#endif
- bool double_micro_found = false;
- std::string::size_type pos = 0;
- int count = 0;
- while ( 1 ) {
- // A while loop here is used to:
- // a/ Allow for multiple substitution on a single line. i.e %ECF_FILES% -I %ECF_INCLUDE%"
- // b/ Allow for recursive substitution. %fred% -> %bill%--> 10
-
- size_t firstPercentPos = cmd.find( micro, pos );
- if ( firstPercentPos == string::npos ) break;
-
- size_t secondPercentPos = cmd.find( micro, firstPercentPos + 1 );
- if ( secondPercentPos == string::npos ) break;
-
- if ( secondPercentPos - firstPercentPos <= 1 ) {
- // handle %% with no characters in between, skip over
- // i.e to handle "printf %%02d %HOUR:00%" --> "printf %02d 00" i.e if HOUR not defined
- pos = secondPercentPos + 1;
- double_micro_found = true;
- continue;
- }
- else pos = 0;
-
- string percentVar( cmd.begin() + firstPercentPos+1, cmd.begin() + secondPercentPos );
-#ifdef DEBUG_S
- cout << " Found percentVar " << percentVar << "\n";
-#endif
-
-
- // ****************************************************************************************
- // Look for generated variables first:
- // Variable like ECF_PASS can be overridden, i.e. with FREE_JOBS_PASSWORD
- // However for job file generation we should use use the generated variables first.
- // if the user removes ECF_PASS then we are stuck with the wrong value in the script file
- // FREE_JOBS_PASSWORD is left for the server to deal with
- bool generated_variable = false;
- if ( percentVar.find("ECF_") != std::string::npos) {
- if ( percentVar.find(Str::ECF_PASS()) != std::string::npos) generated_variable = true;
- else if ( percentVar.find(Str::ECF_TRYNO()) != std::string::npos) generated_variable = true;
- else if ( percentVar.find(Str::ECF_JOB()) != std::string::npos) generated_variable = true;
- else if ( percentVar.find(Str::ECF_JOBOUT()) != std::string::npos) generated_variable = true;
- else if ( percentVar.find(Str::ECF_PORT()) != std::string::npos) generated_variable = true;
- else if ( percentVar.find(Str::ECF_NODE()) != std::string::npos) generated_variable = true;
- else if ( percentVar.find(Str::ECF_NAME()) != std::string::npos) generated_variable = true;
- }
-
- // First search user variable (*ONLY* set when doing user edit's the script)
- // Handle case: cmd = "%fred:bill% and where we have user variable "fred:bill"
- // Handle case: cmd = "%fred% and where we have user variable "fred"
- // If we fail to find the variable we return false.
- // Note: When a variable is found, it can have an empty value which is still valid
- std::string varValue;
- if (search_user_edit_variables(percentVar,varValue,user_edit_variables)) {
- cmd.replace( firstPercentPos, secondPercentPos - firstPercentPos + 1, varValue );
- }
- else if (generated_variable && find_parent_gen_variable_value(percentVar,varValue)) {
-
- cmd.replace( firstPercentPos, secondPercentPos - firstPercentPos + 1, varValue );
- }
- else if (findParentVariableValue( percentVar ,varValue)) {
- // For alias we could have added variables with %A:0%, %A:1%. Aliases allow variables with ':' in the name
- cmd.replace( firstPercentPos, secondPercentPos - firstPercentPos + 1, varValue );
- }
- else {
-
- size_t firstColon = percentVar.find( ':' );
- if (firstColon != string::npos) {
-
- string var(percentVar.begin(), percentVar.begin() + firstColon);
-#ifdef DEBUG_S
- cout << " var " << var << "\n";
-#endif
-
- if (search_user_edit_variables(var,varValue,user_edit_variables)) {
-#ifdef DEBUG_S
- cout << " user var value = " << varValue << "\n";
-#endif
- cmd.replace(firstPercentPos,secondPercentPos-firstPercentPos+1,varValue);
- }
- else if (generated_variable && find_parent_gen_variable_value(var,varValue)) {
-#ifdef DEBUG_S
- cout << " generated var value = " << varValue << "\n";
-#endif
- cmd.replace( firstPercentPos, secondPercentPos - firstPercentPos + 1, varValue );
- }
- else if (findParentVariableValue( var, varValue )) {
- // Note: variable can exist, but have an empty value
-#ifdef DEBUG_S
- cout << " var value = " << varValue << "\n";
-#endif
- // replace the "%VAR:fred --f%" with var
- cmd.replace(firstPercentPos,secondPercentPos-firstPercentPos+1,varValue);
- }
- else {
- string substitute (percentVar.begin()+ firstColon+1, percentVar.end());
-#ifdef DEBUG_S
- cout << " substitute value = " << substitute << "\n";
-#endif
- cmd.replace(firstPercentPos,secondPercentPos-firstPercentPos+1,substitute);
- }
-#ifdef DEBUG_S
- cout << " cmd = " << cmd << "\n";
-#endif
- }
- else {
- // No Colon, Can't find in user variables, or node variable, hence can't go any further
- return false;
- }
- }
-
- // Simple Check for infinite recursion
- if (count > 100) return false;
- count++;
- }
-
- if (double_micro_found) {
- // replace all double micro with a single micro, this must be a single parse
- // date +%%Y%%m%%d" ==> date +%Y%m%d
- // %%%% ==> %% // i.e single parse
- std::string doubleEcfMicro;
- doubleEcfMicro += micro;
- doubleEcfMicro += micro;
- size_t last_pos = 0;
- while ( 1 ) {
- string::size_type ecf_double_micro_pos = cmd.find( doubleEcfMicro , last_pos);
- if ( ecf_double_micro_pos != std::string::npos ) {
- cmd.erase( cmd.begin() + ecf_double_micro_pos );
- last_pos = ecf_double_micro_pos + 1;
- }
- else break;
- }
- }
-
- return true;
-}
-
-bool Node::find_all_used_variables(std::string& cmd, NameValueMap& used_variables, char micro) const
-{
-#ifdef DEBUG_S
- cout << "cmd = " << cmd << "\n";
-#endif
- int count = 0;
- while ( 1 ) {
- // A while loop here is used to:
- // a/ Allow for multiple substitution on a single line. i.e %ECF_FILES% -I %ECF_INCLUDE%"
- // b/ Allow for recursive substitution. %fred% -> %bill%--> 10
-
- size_t firstPercentPos = cmd.find( micro );
- if ( firstPercentPos == string::npos ) break;
- size_t secondPercentPos = cmd.find( micro, firstPercentPos + 1 );
- if ( secondPercentPos == string::npos ) break;
- if ( secondPercentPos - firstPercentPos <= 1 ) break; // handle %% with no characters in between
-
-
- string percentVar( cmd.begin() + firstPercentPos+1, cmd.begin() + secondPercentPos );
-#ifdef DEBUG_S
- cout << " Found percentVar " << percentVar << "\n";
-#endif
-
- size_t firstColon = percentVar.find( ':' );
- if (firstColon != string::npos) {
-
- string var (percentVar.begin(), percentVar.begin() + firstColon);
-#ifdef DEBUG_S
- cout << " var " << var << "\n";
-#endif
-
- std::string varValue;
- if (findParentVariableValue( var, varValue )) {
- // Note: variable can exist, but have an empty value
-#ifdef DEBUG_S
- cout << " var value = " << theFoundVariable.value() << "\n";
-#endif
- // %VAR:fred% ---> name("VAR:fred") value(theFoundVariable.value())
- used_variables.insert( std::make_pair(percentVar,varValue) );
-
- // replace the "%VAR:fred --f%" with variable value, so that we dont process it again
- cmd.replace(firstPercentPos,secondPercentPos-firstPercentPos+1,varValue);
- }
- else {
- string substitute (percentVar.begin()+ firstColon+1, percentVar.end());
-#ifdef DEBUG_S
- cout << " substitute value = " << substitute << "\n";
-#endif
-
- // %VAR:fred% ---> name("VAR:fred") value(fred)
- used_variables.insert( std::make_pair(percentVar,substitute));
-
- cmd.replace(firstPercentPos,secondPercentPos-firstPercentPos+1,substitute);
- }
-#ifdef DEBUG_S
- cout << " cmd = " << cmd << "\n";
-#endif
- }
- else {
-
- // If we fail to find the variable we return false.
- // Note: When a variable is found, it can have an empty value
- // which is still valid
- std::string varValue;
- if (!findParentVariableValue( percentVar ,varValue)) return false;
-
- used_variables.insert( std::make_pair(percentVar,varValue) );
- cmd.replace( firstPercentPos, secondPercentPos - firstPercentPos + 1, varValue );
- }
-
- // Simple Check for infinite recursion
- if (count > 100) return false;
- count++;
- }
- return true;
-}
-
-
-bool Node::enviromentSubsitution(std::string& cmd)
-{
- // scan command for environment variables, and substitute
- // edit ECF_INCLUDE $ECF_HOME/include
-
- while ( 1 ) {
- size_t firstPos = cmd.find( '$' );
- if ( firstPos == string::npos ) break;
-
- size_t secondPos = cmd.find_first_not_of( Str::ALPHANUMERIC_UNDERSCORE(), firstPos + 1 );
- if ( secondPos == string::npos ) secondPos = cmd.size();
- if ( secondPos - firstPos <= 1 ) break; // handle $/ with no characters in between
-
- string env( cmd.begin() + firstPos+1, cmd.begin() + secondPos );
- //cout << "find env " << env << "\n";
-
- std::string envValue;
- if (! findParentVariableValue( env,envValue )) {
- //cout << " could not find " << env << "\n";
- return false;
- }
-
- cmd.replace( firstPos, secondPos - firstPos , envValue );
- }
- return true;
-}
-
-
-std::string Node::completeExpression() const
-{
- if (completeExpr_) {
- string ret = "complete ";
- ret += completeExpr_->expression();
- return ret;
- }
- return string();
-}
-
-std::string Node::triggerExpression() const
-{
- if (triggerExpr_) {
- string ret = "trigger ";
- ret += triggerExpr_->expression();
- return ret;
- }
- return string();
-}
-
-
-static void check_expressions(const Node* node, bool trigger, std::string& errorMsg)
-{
- Ast* ast = NULL;
- if (trigger) ast = node->triggerAst();
- else ast = node->completeAst();
- if ( ast ) {
- // The expression have been parsed and we have created the abstract syntax tree
- // Try to resolve the path/node references in the expressions
- // Also resolve references to events,meter,repeats variables.
- AstResolveVisitor astVisitor(node);
- ast->accept(astVisitor);
-
- if ( !astVisitor.errorMsg().empty() ) {
- errorMsg += "Expression node tree references failed for ";
- if ( trigger ) errorMsg += node->triggerExpression();
- else errorMsg += node->completeExpression();
- errorMsg += "' at ";
- errorMsg += node->absNodePath();
- errorMsg += "\n ";
- errorMsg += astVisitor.errorMsg();
- }
- }
-}
-
-bool Node::check(std::string& errorMsg, std::string& warningMsg) const
-{
- //#ifdef DEBUG
- // cout << "Node::check " << debugNodePath() << " complete and trigger\n";
- //#endif
-
- /// ************************************************************************************
- /// *IMPORTANT side effec: *
- /// The simulator relies AstResolveVisitor to set usedInTriggger() for events and meters
- /// *************************************************************************************
-
- /// Make Sure: To sure capture parser errors:
- /// defs which fail parse errors should not be allowed to be loaded into the server
- /// Even if the code parses, check the expression for divide by zero, for divide and modulo operators
- AstTop* ctop = completeAst(errorMsg);
- if (ctop && !ctop->check(errorMsg)) {
- errorMsg += " ";
- if (completeExpr_) errorMsg += completeExpr_->expression();
- errorMsg += " on ";
- errorMsg += debugNodePath();
- }
- AstTop* ttop = triggerAst(errorMsg);
- if (ttop && !ttop->check(errorMsg)) {
- errorMsg += " ";
- if (triggerExpr_) errorMsg += triggerExpr_->expression();
- errorMsg += " on ";
- errorMsg += debugNodePath();
- }
-
-
- // capture node path resolve errors
- check_expressions(this, true,errorMsg);
- check_expressions(this, false,errorMsg);
-
- // check inLimit references to limits.
- // Client: Unresolved references, which are not in the externs reported as errors/warnings
- // Server: There are no exerns, all unresolved references reported as errors
- bool reportErrors = true;
- bool reportWarnings = true;
- inLimitMgr_.check(errorMsg,warningMsg,reportErrors, reportWarnings);
-
- return errorMsg.empty();
-}
-
-std::string Node::write_state() const
-{
- // *IMPORTANT* we *CANT* use ';' character, since is used in the parser, when we have
- // multiple statement on a single line i.e.
- // task a; task b;
- // If attribute correspond to the defaults don't write then out
- std::string ret;
- if (state() != NState::UNKNOWN) {
- ret += " state:";
- ret += NState::toString(state());
- }
- if (state_.second.total_seconds() != 0) {
- ret += " dur:";
- ret += to_simple_string(state_.second);
- }
- if (flag_.flag() != 0) {
- ret += " flag:";
- ret += flag_.to_string();
- }
- if (suspended_) {
- ret += " suspended:1";
- }
- return ret;
-}
-
-void Node::read_state(const std::string& line,const std::vector<std::string>& lineTokens)
-{
- std::string token;
- for(size_t i = 0; i < lineTokens.size(); i++) {
- token.clear();
- if (lineTokens[i].find("state:") != std::string::npos ) {
- if (!Extract::split_get_second(lineTokens[i],token)) throw std::runtime_error( "Node::read_state Invalid state specified for suite " + name());
- if (!NState::isValid(token)) throw std::runtime_error( "Node::read_state Invalid state specified for node : " + name() );
- set_state_only(NState::toState(token));
- }
- else if (lineTokens[i].find("flag:") != std::string::npos ) {
- if (!Extract::split_get_second(lineTokens[i],token)) throw std::runtime_error( "Node::read_state invalid flags for node " + name());
- flag().set_flag(token); // this can throw
- }
- else if (lineTokens[i].find("dur:") != std::string::npos ) {
- if (!Extract::split_get_second(lineTokens[i],token)) throw std::runtime_error( "Node::read_state invalid duration for node: " + name());
- state_.second = duration_from_string(token);
- }
- else if (lineTokens[i] == "suspended:1") suspend();
- }
-}
-
-std::ostream& Node::print(std::ostream& os) const
-{
- if ( defStatus_ != DState::default_state() ) {
- Indentor in;
- Indentor::indent(os) << "defstatus " << DState::toString(defStatus_) << "\n";
- }
-
- if (lateAttr_) lateAttr_->print(os);
-
- if (completeExpr_) {
- completeExpr_-> print(os,"complete");
- if ( PrintStyle::getStyle() == PrintStyle::STATE ) {
- Indentor in;
- if (completeExpr_->isFree()) Indentor::indent(os) << "# (free)\n";
- else Indentor::indent(os) << "# (holding)\n";
- if ( completeAst() ) {
- if (!defs()) {
- // Full defs is required for extern checking, and finding absolute node paths
- // Hence print will with no defs can give in-accurate information
- Indentor in;
- Indentor::indent(os) << "# Warning: Full/correct AST evaluation requires the definition\n";
- }
- completeAst()->print(os);
- }
- }
- }
- if (triggerExpr_) {
- triggerExpr_->print(os,"trigger");
- if ( PrintStyle::getStyle() == PrintStyle::STATE ) {
- Indentor in;
- if (triggerExpr_->isFree()) Indentor::indent(os) << "# (free)\n";
- else Indentor::indent(os) << "# (holding)\n";
- if ( triggerAst() ) {
- if (!defs()) {
- Indentor in;
- Indentor::indent(os) << "# Warning: Full/correct AST evaluation requires the definition\n";
- }
- triggerAst()->print(os);
- }
- }
- }
- repeat_.print(os);
-
- BOOST_FOREACH(const Variable& v, varVec_ ) { v.print(os); }
- BOOST_FOREACH(limit_ptr l, limitVec_) { l->print(os); }
- inLimitMgr_.print(os);
- if (child_attrs_) child_attrs_->print(os);
- if (time_dep_attrs_) time_dep_attrs_->print(os);
- if (misc_attrs_) misc_attrs_->print(os);
- if (autoCancel_) autoCancel_->print(os);
-
- return os;
-}
-
-std::string Node::to_string() const
-{
- std::stringstream ss;
- print(ss);
- return ss.str();
-}
-
-bool Node::operator==(const Node& rhs) const
-{
- if ( name_ != rhs.name_) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Node::operator==( name_(" << name_ << ") != rhs.name_(" << rhs.name_ << ")) for: " << debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- if ( state() != rhs.state()) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Node::operator== state(" << NState::toString(state()) << ") != rhs.state(" << NState::toString(rhs.state()) << ")) " << debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- if ( defStatus_ != rhs.defStatus_) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Node::operator== ( defStatus_ != rhs.defStatus_) " << debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- if ( suspended_ != rhs.suspended_) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Node::operator== suspended_ != rhs.suspended_ " << debugNodePath() << "\n";
- }
-#endif
- return false;
- }
-
- if ( flag_ != rhs.flag_) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Node::operator== ( flag_ != rhs.flag_) : '" << flag_.to_string() << "' != '" << rhs.flag_.to_string() << "' : " << debugNodePath() << "\n";
- }
-#endif
- return false;
- }
-
- if ( (triggerExpr_ && !rhs.triggerExpr_) || (!triggerExpr_ && rhs.triggerExpr_) ) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Node::operator== (triggerExpr_ && !rhs.triggerExpr_) || (!triggerExpr_&& rhs.triggerExpr_) " << debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- if ( triggerExpr_ && rhs.triggerExpr_ && (*triggerExpr_ != *rhs.triggerExpr_) ) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Node::operator== triggerExpr_ && rhs.triggerExpr_ && (*triggerExpr_ != *rhs.triggerExpr_) " << debugNodePath() << "\n";
- }
-#endif
- return false;
- }
-
- if ( (completeExpr_ && !rhs.completeExpr_) || (!completeExpr_ && rhs.completeExpr_) ) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Node::operator== (completeExpr_ && !rhs.completeExpr_) || (!completeExpr_&& rhs.completeExpr_) " << debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- if ( completeExpr_ && rhs.completeExpr_ && (*completeExpr_ != *rhs.completeExpr_) ) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Node::operator== completeExpr_ && rhs.completeExpr_ && (*completeExpr_ != *rhs.completeExpr_) " << debugNodePath() << "\n";
- }
-#endif
- return false;
- }
-
-
- if (varVec_.size() != rhs.varVec_.size()) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Node::operator== (varVec_.size() != rhs.varVec_.size()) " << debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- for(unsigned i = 0; i < varVec_.size(); ++i) {
- if (!(varVec_[i] == rhs.varVec_[i] )) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Node::operator== (!(varVec_[i] == rhs.varVec_[i] )) " << debugNodePath() << "\n";
- std::cout << " varVec_[i] name = '" << varVec_[i].name() << "' value = '" << varVec_[i].theValue() << "'\n";
- std::cout << " rhs.varVec_[i] name = '" << rhs.varVec_[i].name() << "' value = '" << rhs.varVec_[i].theValue() << "'\n";
- }
-#endif
- return false;
- }
- }
- // We dont compare genvar as this is only used in server environment
-
- if (!(inLimitMgr_ == rhs.inLimitMgr_)) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Node::operator== (!(inLimitMgr == rhs.inLimitMgr)) " << debugNodePath() << "\n";
- }
-#endif
- return false;
- }
-
- if (limitVec_.size() != rhs.limitVec_.size()) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Node::operator== (limitVec_.size() != rhs.limitVec_.size()) " << debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- for(unsigned i = 0; i < limitVec_.size(); ++i) {
- if (!(*limitVec_[i] == *rhs.limitVec_[i] )) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Node::operator== (!(*limitVec_[i] == *rhs.limitVec_[i] )) " << debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- }
-
- if (( time_dep_attrs_ && !rhs.time_dep_attrs_) || ( !time_dep_attrs_ && rhs.time_dep_attrs_)){
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Node::operator== (( time_dep_attrs_ && !rhs.time_dep_attrs_) || ( !time_dep_attrs_ && rhs.time_dep_attrs_)) " << debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- if ( time_dep_attrs_ && rhs.time_dep_attrs_ && !(*time_dep_attrs_ == *rhs.time_dep_attrs_)) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Node::operator== ( time_dep_attrs_ && rhs.time_dep_attrs_ && !(*time_dep_attrs_ == *(rhs.time_dep_attrs_))) " << debugNodePath() << "\n";
- }
-#endif
- return false;
- }
-
- if (( child_attrs_ && !rhs.child_attrs_) || ( !child_attrs_ && rhs.child_attrs_)){
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Node::operator== (( child_attrs_ && !rhs.child_attrs_) || ( !child_attrs_ && rhs.child_attrs_)) " << debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- if ( child_attrs_ && rhs.child_attrs_ && !(*child_attrs_ == *rhs.child_attrs_)) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Node::operator== ( child_attrs_ && rhs.child_attrs_ && !(*child_attrs_ == *(rhs.child_attrs_))) " << debugNodePath() << "\n";
- }
-#endif
- return false;
- }
-
- if (( misc_attrs_ && !rhs.misc_attrs_) || ( !misc_attrs_ && rhs.misc_attrs_)){
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Node::operator== (( misc_attrs_ && !rhs.misc_attrs_) || ( !misc_attrs_ && rhs.misc_attrs_)) " << debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- if ( misc_attrs_ && rhs.misc_attrs_ && !(*misc_attrs_ == *rhs.misc_attrs_)) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Node::operator== ( misc_attrs_ && rhs.misc_attrs_ && !(*misc_attrs_ == *(rhs.misc_attrs_))) " << debugNodePath() << "\n";
- }
-#endif
- return false;
- }
-
- if (autoCancel_ && !rhs.autoCancel_) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Node::operator== if (autoCancel_ && !rhs.autoCancel_) " << debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- if (!autoCancel_ && rhs.autoCancel_) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Node::operator== if (!autoCancel_ && rhs.autoCancel_) " << debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- if (autoCancel_ && rhs.autoCancel_ && !(*autoCancel_ == *rhs.autoCancel_)) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Node::operator== (autoCancel_ && rhs.autoCancel_ && !(*autoCancel_ == *rhs.autoCancel_)) " << debugNodePath() << "\n";
- }
-#endif
- return false;
- }
-
-
- if (!(repeat_ == rhs.repeat_)) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Node::operator== if (!(repeat_ == rhs.repeat_)) " << debugNodePath() << "\n";
- }
-#endif
- return false;
- }
-
-
- if (( lateAttr_ && !rhs.lateAttr_) || ( !lateAttr_ && rhs.lateAttr_)){
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Node::operator== (( lateAttr_ && !rhs.lateAttr_) || ( !lateAttr_ && rhs.lateAttr_)) " << debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- if ( lateAttr_ && rhs.lateAttr_ && !(*lateAttr_ == *rhs.lateAttr_)) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Node::operator== ( lateAttr_ && rhs.lateAttr_ && !(*lateAttr_ == *(rhs.lateAttr_))) " << debugNodePath() << "\n";
- }
-#endif
- return false;
- }
-
- return true;
-}
-
-
-//#define DEBUG_WHY 1
-
-void Node::top_down_why(std::vector<std::string>& theReasonWhy) const
-{
- why(theReasonWhy);
-}
-
-void Node::bottom_up_why(std::vector<std::string>& theReasonWhy) const
-{
- defs()->why(theReasonWhy);
-
- std::vector<Node*> vec;
- vec.push_back(const_cast<Node*>(this));
- Node* theParent = parent();
- while (theParent) {
- vec.push_back(theParent);
- theParent = theParent->parent();
- }
- vector<Node*>::reverse_iterator r_end = vec.rend();
- for(vector<Node*>::reverse_iterator r = vec.rbegin(); r!=r_end; ++r) {
- (*r)->why(theReasonWhy);
- }
-}
-
-void Node::why(std::vector<std::string>& vec) const
-{
-#ifdef DEBUG_WHY
- std::cout << "Node::why " << debugNodePath() << " (" << NState::toString(state()) << ")\n";
-#endif
- if (isSuspended()) {
- std::string theReasonWhy = "The node '";
- theReasonWhy += debugNodePath();
- theReasonWhy += "' is suspended.";
- vec.push_back(theReasonWhy);
- }
- else if (state() != NState::QUEUED && state() != NState::ABORTED) {
- std::stringstream ss;
- ss << "The node '" << debugNodePath() << "' (" << NState::toString(state()) << ") is not queued or aborted.";
- vec.push_back(ss.str());
-
- // When task is active/submitted no point, going any further.
- // However for FAMILY/SUITE we still need to proceed
- if (isTask()) return;
- }
-
- // Check limits using in limit manager
- inLimitMgr_.why(vec);
-
- // Prefix <node-type> <path> <state>
- std::string prefix = debugType();
- prefix += " ";
- prefix += absNodePath();
- prefix += " (";
- prefix += NState::toString(state());
- prefix += ") ";
-
- if (time_dep_attrs_) {
-#ifdef DEBUG_WHY
- std::cout << " Node::why " << debugNodePath() << " checking time dependencies\n";
-#endif
- // postfix = <attr-type dependent> <next run time > < optional current state>
- time_dep_attrs_->why(vec,prefix);
- }
-
- // **************************************************************************************
- // If we have a complete expression that does not evaluate then it should *NOT* hold the node.
- // The complete expression is used to set node to complete, when it evaluates and hence
- // should not prevent further tree walking. evaluate each leaf branch
- // **************************************************************************************
- AstTop* theTriggerAst = triggerAst();
- if (theTriggerAst) {
- // Note 1: A trigger can be freed by the ForceCmd
- // Note 2: if we have a non NULL trigger ast, we must have trigger expression
- // Note 3: The freed state is stored on the expression ( i.e *NOT* on the ast (abstract syntax tree) )
- if (!triggerExpr_->isFree() ) {
-
-#ifdef DEBUG_WHY
- std::cout << " Node::why " << debugNodePath() << " checking trigger dependencies\n";
-#endif
- std::string postFix;
- if (theTriggerAst->why(postFix)) { vec.push_back(prefix + postFix); }
- }
- }
-}
-
-bool Node::checkInvariants(std::string& errorMsg) const
-{
- if (time_dep_attrs_) {
- if (!time_dep_attrs_->checkInvariants(errorMsg)) {
- return false;
- }
- }
- if (!repeat_.empty()) {
- if (repeat_.name().empty()) {
- errorMsg += "Repeat name empty ???";
- return false;
- }
- }
- return true;
-}
-
-std::string Node::absNodePath() const
-{
- std::vector<std::string> vec; vec.reserve(Str::reserve_16());
- vec.push_back(name());
- Node* theParent = parent();
- while (theParent) {
- vec.push_back(theParent->name());
- theParent = theParent->parent();
- }
- std::string ret; ret.reserve(Str::reserve_64());
- vector<string>::reverse_iterator r_end = vec.rend();
- for(vector<string>::reverse_iterator r = vec.rbegin(); r!=r_end; ++r) {
- ret += '/';
- ret += *r;
- }
-
- // // Another algorithm broadly similar results
- // std::string ret; ret.reserve(Str::reserve_64());
- // ret += '/';
- // ret += name();
- // Node* theParent = parent();
- // while (theParent) {
- // ret.insert(0,"/");
- // ret.insert(1,theParent->name());
- // theParent = theParent->parent();
- // }
-
- return ret;
-}
-
-std::string Node::debugNodePath() const
-{
- std::string ret = debugType();
- ret += Str::COLON();
- ret += absNodePath();
- return ret;
-}
-
-void Node::verification(std::string& errorMsg) const
-{
- if (misc_attrs_) misc_attrs_->verification(errorMsg);
-}
-
-void Node::getAllAstNodes(std::set<Node*>& theSet) const
-{
- if ( completeAst() ) {
- AstCollateNodesVisitor astVisitor(theSet);
- completeAst()->accept(astVisitor);
- }
- if ( triggerAst() ) {
- AstCollateNodesVisitor astVisitor(theSet);
- triggerAst()->accept(astVisitor);
- }
-}
-
-AstTop* Node::completeAst() const
-{
- if (completeExpr_) {
- std::string ignoredErrorMsg;
- (void) completeAst(ignoredErrorMsg);
- return completeExpr_->get_ast();
- }
- return NULL;
-}
-
-AstTop* Node::triggerAst() const
-{
- if (triggerExpr_) {
- std::string ignoredErrorMsg;
- (void) triggerAst(ignoredErrorMsg);
- return triggerExpr_->get_ast();
- }
- return NULL;
-}
-
-AstTop* Node::completeAst(std::string& errorMsg) const
-{
- if (completeExpr_ && completeExpr_->get_ast() == NULL) {
- completeExpr_->createAST(const_cast<Node*>(this),"complete",errorMsg);
-#ifdef DEBUG
- if (errorMsg.empty()) LOG_ASSERT(completeExpr_->get_ast(),"");
-#endif
- return completeExpr_->get_ast();
- }
- return NULL;
-}
-
-AstTop* Node::triggerAst(std::string& errorMsg) const
-{
- if (triggerExpr_ && triggerExpr_->get_ast() == NULL) {
- triggerExpr_->createAST(const_cast<Node*>(this),"trigger",errorMsg);
-#ifdef DEBUG
- if (errorMsg.empty()) LOG_ASSERT(triggerExpr_->get_ast(),"");
-#endif
- return triggerExpr_->get_ast();
- }
- return NULL;
-}
-
-node_ptr Node::remove()
-{
- SuiteChanged0 changed(shared_from_this());
-
- Node* theParent = parent();
- if ( theParent ) return theParent->removeChild( this );
- return defs()->removeChild( this );
-}
-
-bool Node::getLabelValue(const std::string& labelName, std::string& value) const
-{
- if (child_attrs_) return child_attrs_->getLabelValue(labelName,value);
- return false;
-}
-
-size_t Node::position() const
-{
- Node* theParent = parent();
- if (theParent) {
- return theParent->child_position(this);
- }
- else {
- Defs* theDefs = defs();
- if (theDefs) {
- return theDefs->child_position(this);
- }
- }
- return std::numeric_limits<std::size_t>::max();
-}
-
-
-void Node::gen_variables(std::vector<Variable>& vec) const
-{
- if (!repeat_.empty()) {
- vec.push_back(repeat_.gen_variable());
- }
-}
-
-const Variable& Node::findGenVariable(const std::string& name) const
-{
- if (!repeat_.empty() && repeat_.name() == name) return repeat_.gen_variable();
- return Variable::EMPTY();
-}
-
-void Node::update_repeat_genvar() const
-{
- if (!repeat_.empty()) {
- repeat_.update_repeat_genvar();
- }
-}
-
-static std::vector<ecf::TimeAttr> timeVec_;
-static std::vector<ecf::TodayAttr> todayVec_;
-static std::vector<DateAttr> dates_;
-static std::vector<DayAttr> days_;
-static std::vector<ecf::CronAttr> crons_;
-const std::vector<ecf::TimeAttr>& Node::timeVec() const { if (time_dep_attrs_) return time_dep_attrs_->timeVec(); return timeVec_; }
-const std::vector<ecf::TodayAttr>& Node::todayVec() const { if (time_dep_attrs_) return time_dep_attrs_->todayVec();return todayVec_; }
-const std::vector<DateAttr>& Node::dates() const { if (time_dep_attrs_) return time_dep_attrs_->dates(); return dates_; }
-const std::vector<DayAttr>& Node::days() const { if (time_dep_attrs_) return time_dep_attrs_->days(); return days_; }
-const std::vector<ecf::CronAttr>& Node::crons() const { if (time_dep_attrs_) return time_dep_attrs_->crons(); return crons_; }
-std::vector<ecf::TimeAttr>::const_iterator Node::time_begin() const { if (time_dep_attrs_) return time_dep_attrs_->time_begin(); return timeVec_.begin();}
-std::vector<ecf::TimeAttr>::const_iterator Node::time_end() const { if (time_dep_attrs_) return time_dep_attrs_->time_end(); return timeVec_.end();}
-std::vector<ecf::TodayAttr>::const_iterator Node::today_begin() const { if (time_dep_attrs_) return time_dep_attrs_->today_begin(); return todayVec_.begin();}
-std::vector<ecf::TodayAttr>::const_iterator Node::today_end() const { if (time_dep_attrs_) return time_dep_attrs_->today_end(); return todayVec_.end();}
-std::vector<DateAttr>::const_iterator Node::date_begin() const { if (time_dep_attrs_) return time_dep_attrs_->date_begin(); return dates_.begin();}
-std::vector<DateAttr>::const_iterator Node::date_end() const { if (time_dep_attrs_) return time_dep_attrs_->date_end(); return dates_.end();}
-std::vector<DayAttr>::const_iterator Node::day_begin() const { if (time_dep_attrs_) return time_dep_attrs_->day_begin(); return days_.begin();}
-std::vector<DayAttr>::const_iterator Node::day_end() const { if (time_dep_attrs_) return time_dep_attrs_->day_end(); return days_.end();}
-std::vector<ecf::CronAttr>::const_iterator Node::cron_begin() const { if (time_dep_attrs_) return time_dep_attrs_->cron_begin(); return crons_.begin();}
-std::vector<ecf::CronAttr>::const_iterator Node::cron_end() const { if (time_dep_attrs_) return time_dep_attrs_->cron_end(); return crons_.end();}
-
-static std::vector<Meter> meters_;
-static std::vector<Event> events_;
-static std::vector<Label> labels_;
-const std::vector<Meter>& Node::meters() const { if (child_attrs_) return child_attrs_->meters(); return meters_;}
-const std::vector<Event>& Node::events() const { if (child_attrs_) return child_attrs_->events(); return events_;}
-const std::vector<Label>& Node::labels() const { if (child_attrs_) return child_attrs_->labels(); return labels_;}
-std::vector<Meter>& Node::ref_meters() { if (child_attrs_) return child_attrs_->ref_meters(); return meters_;} // allow simulator set meter value
-std::vector<Event>& Node::ref_events() { if (child_attrs_) return child_attrs_->ref_events(); return events_;} // allow simulator set event value
-std::vector<Meter>::const_iterator Node::meter_begin() const { if (child_attrs_) return child_attrs_->meter_begin(); return meters_.begin();}
-std::vector<Meter>::const_iterator Node::meter_end() const { if (child_attrs_) return child_attrs_->meter_end(); return meters_.end();}
-std::vector<Event>::const_iterator Node::event_begin() const { if (child_attrs_) return child_attrs_->event_begin(); return events_.begin();}
-std::vector<Event>::const_iterator Node::event_end() const { if (child_attrs_) return child_attrs_->event_end(); return events_.end();}
-std::vector<Label>::const_iterator Node::label_begin() const { if (child_attrs_) return child_attrs_->label_begin(); return labels_.begin();}
-std::vector<Label>::const_iterator Node::label_end() const { if (child_attrs_) return child_attrs_->label_end(); return labels_.end();}
-
-static std::vector<VerifyAttr> verifys_;
-static std::vector<ZombieAttr> zombies_;
-const std::vector<VerifyAttr>& Node::verifys() const { if (misc_attrs_) return misc_attrs_->verifys(); return verifys_;}
-const std::vector<ZombieAttr>& Node::zombies() const { if (misc_attrs_) return misc_attrs_->zombies(); return zombies_; }
-std::vector<ZombieAttr>::const_iterator Node::zombie_begin() const { if (misc_attrs_) return misc_attrs_->zombie_begin(); return zombies_.begin();}
-std::vector<ZombieAttr>::const_iterator Node::zombie_end() const { if (misc_attrs_) return misc_attrs_->zombie_end(); return zombies_.end();}
-std::vector<VerifyAttr>::const_iterator Node::verify_begin() const { if (misc_attrs_) return misc_attrs_->verify_begin(); return verifys_.begin();}
-std::vector<VerifyAttr>::const_iterator Node::verify_end() const { if (misc_attrs_) return misc_attrs_->verify_end(); return verifys_.end();}
diff --git a/ecflow_4_0_7/ANode/src/Node.hpp b/ecflow_4_0_7/ANode/src/Node.hpp
deleted file mode 100644
index 9c2bdad..0000000
--- a/ecflow_4_0_7/ANode/src/Node.hpp
+++ /dev/null
@@ -1,748 +0,0 @@
-#ifndef NODE_HPP_
-#define NODE_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #251 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//
-// Node: The node class does NOT serialise the triggers and complete.
-// These are created on demand in the server.
-// However when the client code loads the definition file, the Defs::check
-// will create AST for trigger and complete expressions.
-// Because:
-// 1/ the AST are created, so that any parser errors can be _reported_ to the user
-// 2/ References in the AST expressions are resolved, and errors flagged.
-// This information could have been saved, however was _not_.
-// Because:
-// 1/ problems on AIX
-// 2/ Cut down on IPC load between client/server
-//
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <ostream>
-#include <set>
-#include <limits>
-
-#include <boost/enable_shared_from_this.hpp>
-#include <boost/noncopyable.hpp>
-#include <boost/serialization/base_object.hpp>
-#include <boost/serialization/utility.hpp>
-#include <boost/serialization/vector.hpp> // no need to include <vector>
-#include <boost/serialization/string.hpp> // no need to include <string>
-#include <boost/serialization/shared_ptr.hpp> // no need to include shared_ptr
-#include <boost/foreach.hpp> // used so often just placed here for convenience
-
-#include "DState.hpp"
-#include "NOrder.hpp"
-#include "NodeAttr.hpp"
-#include "Limit.hpp"
-#include "InLimit.hpp"
-#include "Variable.hpp"
-#include "LateAttr.hpp"
-#include "RepeatAttr.hpp"
-#include "AutoCancelAttr.hpp"
-#include "Expression.hpp"
-#include "InLimitMgr.hpp"
-#include "TimeDepAttrs.hpp"
-#include "ChildAttrs.hpp"
-#include "MiscAttrs.hpp"
-#include "NodeFwd.hpp"
-#include "Flag.hpp"
-
-namespace ecf { class Simulator; class SimulatorVisitor; class DefsAnalyserVisitor; class FlatAnalyserVisitor; } // forward declare for friendship
-namespace ecf { class Calendar; class NodeTreeVisitor; } // forward declare class
-
-class Node : public boost::enable_shared_from_this<Node>, private boost::noncopyable {
-protected:
- Node(const std::string& name);
- Node();
-public:
- virtual ~Node();
-
- /// The Parent Must set the parent pointer. For a Suite however this will be NULL
- void set_parent(Node* p) { parent_ = p; }
-
- // Server called functions:
- /// Required when we have time attributes, when time related attribute are free they stay free
- virtual void calendarChanged(const ecf::Calendar&, std::vector<node_ptr>& auto_cancelled_nodes);
-
- /// resolving dependencies means we look at day,date,time and triggers and check to
- /// to see if a node is free or still holding. When a node if free of its dependencies and limits
- /// Its state is changed to submitted. When a task is in a the submitted state its
- /// associated ecf file can be submitted.
- /// ************************************************************************************
- /// There is no point in resolving child dependencies if the parent is not FREE
- // We will return a bool, true means we are free, false for holding
- // *************************************************************************************
- virtual bool resolveDependencies(JobsParam& jobsParam);
-
- /// Command related functions:
- /// suspend generation of jobs. Below this node.
- /// Note: When a node is suspended. time/date dependencies are still handled
- /// A node which is free of time is marked.
- /// Note: suspended is *NOT* a node state. It just an *attribute*. NState::State
- /// represents all the life cycle change a Node can go through. Suspended does
- /// not real fit into this and has been separated out.
- bool isSuspended() const { return suspended_; }
- bool isParentSuspended() const;
- void suspend();
-
- /// resume generation of jobs, and kick of an immediate job generation
- /// If not previously suspended does nothing
- void resume();
-
- /// Kill the task if it is active. For NodeContainers do it hierarchically
- /// will throw std::runtime_error for any errors
- virtual void kill(const std::string& zombie_pid = "") = 0;
-
- /// Show status of a node. For NodeContainers do it hierarchically
- /// will throw std::runtime_error for any errors
- virtual void status() = 0;
-
- /// Order the node using the second parameter
- virtual void order(Node*/*immediateChild*/, NOrder::Order) {}
-
- /// For suites it allows dependencies to be resolved, and changes state to defStatus
- virtual void begin();
-
- /// re queue this node. States are reset to defStatus
- /// Typically resetRepeats is set to true, when called from user command
- /// or when re-queue is called from NodeContainer/parent
- ///
- /// With user interaction : we need to clear the suspended state for *child* nodes
- /// To distinguish between child and parent, we use a integer 'level'
- /// This was done so that if user had suspended a task deep in the hierarchy. (which is then
- /// not displayed in the GUI), and then chooses to re-queue at a *high* level,
- /// we need to clear child suspended state.(Principle of least surprise)
- /// However we will preserve def status.
- /// If a user re-queues a node that is suspended then it stays suspended
- /// We use -1 to mean leave suspended state as is
- ///
- /// When the user issues force-complete or run interactive commands, we want to miss
- /// the next-time slot. (i.e to avoid running the job again).
- /// This is done by using NO_REQUE_IF_SINGLE_TIME_DEP flag.
- /// The flag remain set until we get to *this* function. We use it to avoid
- /// resetting the time slots, effectively missing the next time slot. we then clear the flag.
- /// However if the JOB *abort* we clear NO_REQUE_IF_SINGLE_TIME_DEP
- /// Otherwise if we run again, we miss additional time slots necessarily
- virtual void requeue(bool resetRepeats,
- int clear_suspended_in_child_nodes,
- bool reset_next_time_slot);
-
- /// Re queue the time based attributes only.
- /// Used as a part of Alter (clock) functionality.
- /// Note: Under the hybrid clock this will not mark node as complete, (if we have day,date,cron attributes)
- /// Since alter clock, should not change node state. This is left for user to re-queue the suite
- virtual void requeue_time_attrs();
-
- /// Previously < 4.0.6 requeue always reset the labels on requeue.
- /// However ECFLOW-195 suggest some user prefer to see the last label value.
- /// hence we will only reset the labels on the tasks when task is being run.
- void requeue_labels();
-
- /// This functionality is only required during interactive force or run
- /// Avoid running the task on the same time slot, by missing the next time slot.
- /// Requires we set a flag, to avoid the requeue resetting the time slots
- void miss_next_time_slot();
-
- /// Recursively run the tasks under this node, ignore suspend,limits,triggers, and time dependencies
- /// if force is set, run even if task is submitted or active. (will create zombies)
- virtual bool run(JobsParam& jobsParam, bool force) = 0;
-
- /// Recursively determines why the node is not running.
- virtual void top_down_why(std::vector<std::string>& theReasonWhy) const;
- void bottom_up_why(std::vector<std::string>& theReasonWhy) const;
-
- void freeTrigger() const;
- void clearTrigger() const;
- void freeComplete() const;
- void clearComplete() const;
- void freeHoldingDateDependencies();
- void freeHoldingTimeDependencies();
-
- // Used in the force cmd
- bool set_event( const std::string& event_name_or_number);
- bool clear_event( const std::string& event_name_or_number);
- void setRepeatToLastValue();
- virtual void setRepeatToLastValueHierarchically() { setRepeatToLastValue(); }
-
- /// find all %VAR% and replaces with variable values, returns false on the
- /// first variable that can't be found, cmd will be left half processed.
- /// Will search for ECF_MICRO, if not found assumes % as the micro char
- bool variableSubsitution(std::string& cmd) const;
-
- bool variable_substitution(std::string& cmd, const NameValueMap& user_edit_variables, char micro = '%') const;
-
- /// Find all %VAR% and add to the list, there can be more than one. i.e %ECF_FILES% -I %ECF_INCLUDE%"
- bool find_all_used_variables(std::string& cmd, NameValueMap& used_variables, char micro = '%') const;
-
- /// Find all environment variables, in the input string and substitute.
- /// with correspondingly named variable value.
- /// i.e search for ${ENV} and replace
- bool enviromentSubsitution(std::string& cmd);
-
- /// Resolve inlimit references to limits, and check trigger and complete expression
- virtual bool check(std::string& errorMsg,std::string& warningMsg) const;
-
- /// Generated variables. Suites can have thousands of tasks. If the generated variables associated with
- /// tasks are sent to the client, it can amount to a very large network traffic.
- /// To minimise this bandwidth the generated variables for tasks/families are not persisted.
- /// However client can demand create the generated variable by calling this function.
- virtual void update_generated_variables() const = 0;
-
- /// generates job file independent of dependencies
- virtual void check_job_creation( job_creation_ctrl_ptr jobCtrl) = 0;
-
- node_ptr remove(); // gets the parent then calls removeChild
- virtual node_ptr removeChild( Node* child) = 0;
- virtual bool addChild( node_ptr child,size_t position = std::numeric_limits<std::size_t>::max()) = 0; // return false if child of same name exist, leak!!!
- virtual bool isAddChildOk( Node* child, std::string& errorMsg) const = 0; // return false if child of same name
-
- virtual void verification(std::string& errorMsg) const;
-
- /// See defs.hpp
- virtual void generate_scripts( const std::map<std::string,std::string>& override) const = 0;
-
- // standard functions: ==============================================
- virtual std::ostream& print(std::ostream&) const;
- bool operator==(const Node& rhs) const;
- virtual bool checkInvariants(std::string& errorMsg) const;
-
- /// Implements the visitor pattren
- virtual void accept(ecf::NodeTreeVisitor&) = 0;
- virtual void acceptVisitTraversor(ecf::NodeTreeVisitor&) = 0; // Visitor does the traversal
-
-// state related functions: ========================================
-
- /// If the task was aborted provide the reason, default returns empty string
- /// Only the task will return the reason for abort.
- virtual const std::string& abortedReason() const;
-
- /// This state added as an convenience, it includes Suspended attribute returned as enum
- DState:: State dstate() const;
-
- /// This represents the persisted/saved state // First = NState, Second = time_duration
- /// The State represent the life cycle changes of a node.
- NState::State state() const { return state_.first.state(); }
-
- /// return the state and duration time(relative to when suite was begun) when the state change happened
- std::pair<NState,boost::posix_time::time_duration> get_state() const { return state_;}
-
- /// Set the state, this can have side affects. To handle state changes
- /// Should family triggers use saved state, or computed state.
- /// *** If we use computed state, this may be wrong, since computed state
- /// *** does not take repeats, or time dependencies into account
- /// *** Hence after each state change, we bubble up node tree, work out if
- /// *** Node is free of repeat, and time dependencies,
- /// ** Every time we set the state on a nodecontainer, we call handleStateChange
- /// ** This by default works out the most significant state of the children
- /// ** ie. the computed state. Hence setting the state on Suite/Family is really
- /// ** meaningless, since it will always be the computed state.
- void set_state(NState::State s, bool force = false, const std::string& additional_info_to_log = "");
- virtual void set_state_hierarchically(NState::State s, bool force) { set_state(s,force); }
-
- /// Set state only, has no side effects
- void setStateOnly(NState::State s, bool force = false, const std::string& additional_info_to_log = "");
- virtual void setStateOnlyHierarchically(NState::State s, bool force = false) { setStateOnly(s,force); }
-
- /// This returns the time of state change: (relative to real time when the suite calendar was begun)
- /// The returned time is *real time/computer UTC time* and *not* suite real time.
- boost::posix_time::ptime state_change_time() const;
-
- /// Sets the default status the node should have when the begin/re-queue is called
- /// *Distinguish* between adding a def status and changing it.
- /// Changing via defStatus_.setState(s); should alter state_change_no
- void addDefStatus(DState::State s ) { defStatus_ = DState(s); }
- DState::State defStatus() const { return defStatus_.state(); }
-
- // Query functions: =========================================================
- /// returns my parent, for suite will return NULL;
- Node* parent() const { return parent_;}
- virtual Suite* suite() const = 0;
- virtual Defs* defs() const = 0;
-
- // Performance hack, to avoid casts
- virtual Task* isTask() const { return NULL;}
- virtual Alias* isAlias() const { return NULL;}
- virtual Submittable* isSubmittable() const { return NULL;}
- virtual NodeContainer* isNodeContainer() const { return NULL;}
- virtual Family* isFamily() const { return NULL;}
- virtual Suite* isSuite() const { return NULL;}
-
- /// returns the absolute node path
- std::string absNodePath() const;
- virtual const std::string& debugType() const = 0;
-
- /// returns abs node path preceded by the type of the node
- std::string debugNodePath() const;
-
- /// returns true if this node OR any of its children
- /// has cron,time,day,date or today time dependencies
- virtual bool hasTimeDependencies() const { return (time_dep_attrs_) ? true : false; }
- bool isTimeFree() const { return (time_dep_attrs_) ? time_dep_attrs_->timeDependenciesFree() : false;}
-
-
- /// A hierarchical function
- virtual bool hasAutoCancel() const { return (autoCancel_) ? true : false;}
-
-
- // Access functions: ======================================================
- const std::string& name() const { return name_; }
- std::string toString() const { return name_; } // keep ecflowview/ecf_node.h happy
- const Repeat& repeat() const { return repeat_;} // can be empty()
- const std::vector<Variable>& variables()const { return varVec_;}
- const std::vector<limit_ptr>& limits() const { return limitVec_;}
- const std::vector<InLimit>& inlimits() const { return inLimitMgr_.inlimits(); }
- const std::vector<Meter>& meters() const;
- const std::vector<Event>& events() const;
- const std::vector<Label>& labels() const;
- const std::vector<ecf::TimeAttr>& timeVec() const;
- const std::vector<ecf::TodayAttr>& todayVec() const;
- const std::vector<DateAttr>& dates() const;
- const std::vector<DayAttr>& days() const;
- const std::vector<ecf::CronAttr>& crons() const;
- const std::vector<VerifyAttr>& verifys() const;
- const std::vector<ZombieAttr>& zombies() const;
- TimeDepAttrs* get_time_dep_attrs() const { return time_dep_attrs_;} // can be NULL
- ecf::LateAttr* get_late() const { return lateAttr_;}
- ecf::AutoCancelAttr* get_autocancel() const { return autoCancel_;}
- ecf::Flag& flag() { return flag_;}
- const ecf::Flag& get_flag() const { return flag_;}
-
- virtual void gen_variables(std::vector<Variable>&) const;
- bool getLabelValue(const std::string& name, std::string& value) const;
-
- // Use get_trigger()/get_complete() for determining if we have trigger
- // and complete expressions. This is many times faster than calling
- // triggerAst()/completeAst() as this will force a parse and construction
- // of Abstract syntax tree, first time it is called.
- Expression* get_trigger() const { return triggerExpr_;}
- Expression* get_complete() const { return completeExpr_;}
- AstTop* completeAst() const; // Will create AST on demand
- AstTop* triggerAst() const; // Will create AST on demand
- std::string completeExpression() const;
- std::string triggerExpression() const;
-
- virtual void get_all_tasks(std::vector<task_ptr>&) const = 0;
- virtual void get_all_nodes(std::vector<node_ptr>&) const = 0;
- virtual void get_all_aliases(std::vector<alias_ptr>&) const = 0;
- virtual void getAllTasks(std::vector<Task*>&) const = 0;
- virtual void getAllSubmittables(std::vector<Submittable*>&) const = 0;
- virtual void get_all_active_submittables(std::vector<Submittable*>&) const = 0;
- virtual void getAllNodes(std::vector<Node*>&) const = 0;
- virtual void getAllAstNodes(std::set<Node*>&) const;
-
- /// returns the immediate children
- virtual void immediateChildren(std::vector<node_ptr>&) const {}
-
- /// retrieve _ALL_ children by hierarchically traversing down the node tree
- virtual void allChildren(std::set<Node*>&) const {}
-
- // Add functions: ===============================================================
- void addVerify( const VerifyAttr& ); // for testing and verification Can throw std::runtime_error
- void addVariable(const Variable& ); // will throw std::runtime_error if duplicate
- void add_variable(const std::string& name, const std::string& value );// will write to std:out if duplicates
- void add_variable_int(const std::string& name, int);// will throw std::runtime_error if duplicate
-
- void add_trigger(const std::string&); // use for short complete expressions,Can throw std::runtime_error
- void add_complete(const std::string&); // use for short complete expressions,Can throw std::runtime_error
- void add_trigger_expr(const Expression&); // Can throw std::runtime_error
- void add_complete_expr(const Expression&); // Can throw std::runtime_error
- void add_part_trigger(const PartExpression& ); // for adding multiple and/or expression,Can throw std::runtime_error
- void add_part_complete(const PartExpression& ); // for adding multiple and/or expression,Can throw std::runtime_error
-
- void addTime( const ecf::TimeAttr& );
- void addToday( const ecf::TodayAttr& );
- void addDate( const DateAttr& );
- void addDay( const DayAttr& );
- void addCron( const ecf::CronAttr& );
-
- void addLimit(const Limit& ); // will throw std::runtime_error if duplicate
- void addInLimit(const InLimit& l) { inLimitMgr_.addInLimit(l);} // will throw std::runtime_error if duplicate
- void auto_add_inlimit_externs(Defs* defs) { inLimitMgr_.auto_add_inlimit_externs(defs);}
- void addEvent( const Event& ); // will throw std::runtime_error if duplicate
- void addMeter( const Meter& ); // will throw std::runtime_error if duplicate
- void addLabel( const Label& ); // will throw std::runtime_error if duplicate
- void addAutoCancel( const ecf::AutoCancelAttr& );
- void addLate( const ecf::LateAttr& );
- void addRepeat( const Repeat& ); // will throw std::runtime_error if duplicate
- void addZombie( const ZombieAttr& ); // will throw std::runtime_error if duplicate
-
-
- // Delete functions: can throw std::runtime_error ===================================
- // if name argument is empty, delete all attributes of that type
- // Can throw std::runtime_error of the attribute can not be found
- void deleteTime(const std::string& name );
- void delete_time( const ecf::TimeAttr& );
- void deleteToday(const std::string& name);
- void delete_today(const ecf::TodayAttr&);
- void deleteDate(const std::string& name);
- void delete_date(const DateAttr&);
- void deleteDay(const std::string& name);
- void delete_day(const DayAttr&);
- void deleteCron(const std::string& name);
- void delete_cron(const ecf::CronAttr&);
-
- void delete_zombie(const ecf::Child::ZombieType);
- void deleteVariable( const std::string& name);
- void deleteEvent(const std::string& name);
- void deleteMeter(const std::string& name);
- void deleteLabel(const std::string& name);
- void deleteTrigger();
- void deleteComplete();
- void deleteRepeat();
- void deleteLimit(const std::string& name);
- void delete_limit_path(const std::string& limit_name, const std::string& limit_path);
- void deleteInlimit(const std::string& name);
- void deleteZombie(const std::string& type); // string must be one of [ user | ecf | path ]
-
- // Change functions: ================================================================
- /// returns true the change was made else false, Can throw std::runtime_error for parse errors
- void changeVariable(const std::string& name,const std::string& value);
- void changeEvent(const std::string& name,const std::string& setOrClear = "");
- void changeEvent(const std::string& name,bool value);
- void changeMeter(const std::string& name,const std::string& value);
- void changeMeter(const std::string& name,int value);
- void changeLabel(const std::string& name,const std::string& value);
- void changeTrigger(const std::string& expression);
- void changeComplete(const std::string& expression);
- void changeRepeat(const std::string& value);
- void changeLimitMax(const std::string& name,const std::string& maxValue);
- void changeLimitMax(const std::string& name,int maxValue);
- void changeLimitValue(const std::string& name,const std::string& value);
- void changeLimitValue(const std::string& name,int value);
- void changeDefstatus(const std::string& state);
-
- bool set_meter(const std::string& name,int value); // does not throw if meter not found
- bool set_event(const std::string& name,bool value); // does not throw if event not found
-
- void increment_repeat(); // used in test only
-
- // mementos functions:
- /// Collect all the state changes, so that only small subset is returned to client
- virtual void collateChanges(DefsDelta& ) const = 0;
- void incremental_changes(DefsDelta&, compound_memento_ptr& comp) const;
-
- void set_memento(const StateMemento* );
- void set_memento(const NodeDefStatusDeltaMemento* );
- void set_memento(const SuspendedMemento* );
- void set_memento(const NodeEventMemento* );
- void set_memento(const NodeMeterMemento* );
- void set_memento(const NodeLabelMemento* );
- void set_memento(const NodeTriggerMemento* );
- void set_memento(const NodeCompleteMemento* );
- void set_memento(const NodeRepeatMemento* );
- void set_memento(const NodeLimitMemento* );
- void set_memento(const NodeInLimitMemento* );
- void set_memento(const NodeVariableMemento* );
- void set_memento(const NodeLateMemento* );
- void set_memento(const NodeTodayMemento* );
- void set_memento(const NodeTimeMemento* );
- void set_memento(const NodeDayMemento* );
- void set_memento(const NodeCronMemento* );
- void set_memento(const NodeDateMemento* );
- void set_memento(const NodeZombieMemento* );
- void set_memento(const NodeVerifyMemento* );
- void set_memento(const FlagMemento* );
-
- // Find functions: ============================================================
- // Will search for a node by name(ie not a path) first on siblings, then on a parent
- // then up the node tree, will stop at the suite .
- virtual node_ptr find_node_up_the_tree(const std::string& name) const = 0;
-
- // This is used to find relative nodes.
- virtual node_ptr find_relative_node(const std::vector<std::string>& pathToNode) = 0;
-
- /// Look for user,generated and repeat variables
- /// Find variable corresponding to the given name, by search up the parent hierarchy
- /// ** We need to distinguish between a variable the exists, but has an empty value
- /// ** hence we return true if variable is found, and false otherwise
- bool findParentVariableValue(const std::string& name, std::string& theValue) const;
-
- /// Look for the parent generated variable only
- bool find_parent_gen_variable_value(const std::string& name, std::string& theValue) const;
-
- /// Only looks at user variables
- /// Find variable corresponding to the given name, by search up the parent hierarchy
- /// Use when we know that variable is user defined. This is more efficient than
- /// calling findParentVariableValue.
- /// *** We need to distinguish between a variable the exists, but has an empty value
- /// *** hence we return true if variable is found, and false otherwise
- bool findParentUserVariableValue(const std::string& name, std::string& theValue) const;
-
- /// This function should be used, when we don't care about the distinctions between
- /// a variable that exist but has a empty value, and variable not found.(still return empty string)
- /// Useful when we want to return by reference
- const std::string& find_parent_user_variable_value(const std::string& name) const;
-
- /// Search up the hierarchy, simply checks for existence independent of variable vlaue
- bool user_variable_exists(const std::string& name) const;
-
- virtual node_ptr findImmediateChild(const std::string& /*name*/, size_t& /*child_pos*/) const { return node_ptr();}
- const Variable& findVariable(const std::string& name) const;
- virtual const Variable& findGenVariable(const std::string& name) const;
- bool findVariableValue( const std::string& name, std::string& returnedValue) const;
- bool findGenVariableValue( const std::string& name, std::string& returnedValue) const;
-
- bool findVerify(const VerifyAttr& ) const;
- bool findLimit(const Limit& ) const;
- bool findLabel(const std::string& name) const;
- const Label& find_label(const std::string& name) const;
- limit_ptr find_limit(const std::string& name) const;
- limit_ptr findLimitUpNodeTree(const std::string& name) const;
- Limit* findLimitViaInLimit(const InLimit& l) const { return inLimitMgr_.findLimitViaInLimit(l); } // used in *test* only
- bool findInLimitByNameAndPath(const InLimit& l) const { return inLimitMgr_.findInLimitByNameAndPath(l); } // use name,path,token,
- const Repeat& findRepeat(const std::string& name) const;
- const Meter& findMeter(const std::string& name) const;
- Meter& find_meter(const std::string& name);
- const Event& findEvent(const Event&) const;
- const Event& findEventByNameOrNumber( const std::string& name) const;
-
- const ZombieAttr& findZombie( ecf::Child::ZombieType ) const;
- bool findParentZombie(ecf::Child::ZombieType, ZombieAttr&) const;
-
- /// Finds the referenced node. The node path can be relative or absolute or a extern path
- /// however if its an extern path, and corresponding suite is loaded, but we still
- /// can't find the path, then an error is returned
- node_ptr findReferencedNode(const std::string& nodePath, std::string& errorMsg) const;
- node_ptr findReferencedNode(const std::string& nodePath, const std::string& externObj, std::string& errorMsg) const;
-
- /// return true if we can find a event, meter, user, repeat or generated variable with the given name
- bool findExprVariable( const std::string& name); // update event & meter as used in trigger for simulator
-
- /// The status of family/suite is the inherited most significant status of all its children
- enum TraverseType { IMMEDIATE_CHILDREN, HIERARCHICAL };
- virtual NState::State computedState(Node::TraverseType) const = 0;
-
- /// Sets the most significant state up the node tree. Ignores tasks
- void set_most_significant_state_up_node_tree();
-
- /// For use with GUI only
- void set_graphic_ptr(void* p) { graphic_ptr_ = p; }
- void* graphic_ptr() const { return graphic_ptr_;}
-
- /// returns the position of this node relative to its peers
- /// If not attached to parent returns std::numeric_limits<std::size_t>::max();
- size_t position() const;
-
-protected:
- /// Used in conjunction with Node::position()
- /// returns std::numeric_limits<std::size_t>::max() if child not found
- virtual size_t child_position(const Node*) const = 0;
-
- /// The set_state_only() requires a correctly formed tree, ie since it needs suite()/calendar
- /// to initialise the duration. We need a way set the state directly. For initialization
- void set_state_only(NState::State s) { state_.first.setState(s);}
-
- /// based on the *current* state increment or decrements the limits
- /// Should *only* be called within a task
- virtual void update_limits() = 0;
-
- /// After job submission we need to increment the in limit, to indicate that a
- /// resource is consumed. The set ensure we only update once during a traversal
- void incrementInLimit(std::set<Limit*>& limitSet) const;
-
- /// After job aborts or completes we need to decrement the in limit, to indicate that
- /// additional resource is available. The set ensure we only update once during a traversal
- void decrementInLimit(std::set<Limit*>& limitSet) const;
-
- friend class InLimitMgr;
- bool check_in_limit() const { return inLimitMgr_.inLimit(); }
- bool check_in_limit_up_node_tree() const;
-
-
- friend class Defs;
- friend class Family;
- friend class NodeContainer;
- virtual bool doDeleteChild(Node* child) { return false;}
-
- /// called at the end of state change function
- /// ** Every time we set the state on a nodecontainer, we call handleStateChange
- /// ** This by default works out the most significant state of the children
- /// ** ie. the computed state. Hence setting the state on Suite/Family is really
- /// ** meaningless, since it will always be the computed state.
- /// ** For Aliases we only update the limits, and do not bubble up state changes
- virtual void handleStateChange() = 0; // can end up changing state
-
- /// This function is called as a part of handling state change.
- /// When a suite completes it can be re-queued due to:
- /// o repeat attribute
- /// When going up the hierarchy we should not reset Repeats
- /// The inner repeat must complete before parent repeat (if any) is incremented
- /// (i.e Mimics a nested loops)
- /// o Time, Today, cron attributes
- ///
- /// Otherwise we need to traverse up the node tree and set the most significant state
- void requeueOrSetMostSignificantStateUpNodeTree();
- virtual void resetRelativeDuration();
-
- node_ptr non_const_this() const;
-
- void update_repeat_genvar() const;
-
- // returns node state without trailing new lines
- virtual std::string write_state() const;
- virtual void read_state(const std::string& line,const std::vector<std::string>& lineTokens);
-
-private:
- void why(std::vector<std::string>& theReasonWhy) const;
- /// Function used as a part of trigger and complete expressions.
- /// The search pattern is event,meter,user-variable,repeat, generated-variable
- int findExprVariableValue( const std::string& name) const;
- int findExprVariableValueAndPlus(const std::string& name, int val) const;
- int findExprVariableValueAndMinus(const std::string& name, int val) const;
- int findExprVariableValueAndType( const std::string& name, std::string& varType) const;
- void findExprVariableAndPrint( const std::string& name, std::ostream& os) const;
- friend class VariableHelper;
-
-private:
- bool checkForAutoCancel(const ecf::Calendar& c) const;
-
- void add_trigger_expression(const Expression&); // Can throw std::runtime_error
- void add_complete_expression(const Expression&); // Can throw std::runtime_error
- const Event& findEventByNumber(int number) const;
- const Event& findEventByName( const std::string& name) const;
- bool set_meter_used_in_trigger(const std::string& name);
- bool set_event_used_in_trigger(const std::string& name);
-
-
- /// When the begin/re-queue is called this function will initialise the state
- /// on the node. If node has a default state this is applied to the node, and
- /// hierarchically to all the children
- /// Can also clear suspended see re-queue()
- void initState(int clear_suspended_in_child_nodes);
-
- // Clear the node suspended and update state change number, no other side effects
- void clearSuspended();
-
-private: // alow simulator access
- friend class ecf::DefsAnalyserVisitor;
- friend class ecf::FlatAnalyserVisitor;
- friend class ecf::SimulatorVisitor;
- friend class ecf::Simulator;
- std::vector<Meter>& ref_meters();// allow simulator set meter value
- std::vector<Event>& ref_events();// allow simulator set event value
- Repeat& ref_repeat() { return repeat_;} // allow simulator to modify repeat
-
- /// Note: If the complete expression evaluation fails. we should continue resolving dependencies
- /// If the complete expression evaluation evaluates, then we set node to complete
- bool evaluateComplete() const;
- bool evaluateTrigger() const;
- bool timeDependenciesFree() const;
-
- AstTop* completeAst(std::string& errorMsg) const; // Will create AST on demand
- AstTop* triggerAst(std::string& errorMsg) const; // Will create AST on demand
-
- void checkForLateness( const ecf::Calendar& );
-
-private: // All mementos access
- friend class CompoundMemento;
- void clear(); /// Clear *ALL* internal attributes
-
-private: /// For use by python interface,
- friend void export_Node();
- friend void export_Task();
- friend void export_SuiteAndFamily();
- std::vector<Meter>::const_iterator meter_begin() const;
- std::vector<Meter>::const_iterator meter_end() const;
- std::vector<Event>::const_iterator event_begin() const;
- std::vector<Event>::const_iterator event_end() const;
- std::vector<Label>::const_iterator label_begin() const;
- std::vector<Label>::const_iterator label_end() const;
- std::vector<ecf::TimeAttr>::const_iterator time_begin() const;
- std::vector<ecf::TimeAttr>::const_iterator time_end() const;
- std::vector<ecf::TodayAttr>::const_iterator today_begin() const;
- std::vector<ecf::TodayAttr>::const_iterator today_end() const ;
- std::vector<DateAttr>::const_iterator date_begin() const ;
- std::vector<DateAttr>::const_iterator date_end() const;
- std::vector<DayAttr>::const_iterator day_begin() const ;
- std::vector<DayAttr>::const_iterator day_end() const;
- std::vector<ecf::CronAttr>::const_iterator cron_begin() const ;
- std::vector<ecf::CronAttr>::const_iterator cron_end() const;
- std::vector<ZombieAttr>::const_iterator zombie_begin() const;
- std::vector<ZombieAttr>::const_iterator zombie_end() const;
- std::vector<VerifyAttr>::const_iterator verify_begin() const;
- std::vector<VerifyAttr>::const_iterator verify_end() const;
- std::vector<Variable>::const_iterator variable_begin() const { return varVec_.begin();}
- std::vector<Variable>::const_iterator variable_end() const { return varVec_.end();}
- std::vector<limit_ptr>::const_iterator limit_begin() const { return limitVec_.begin();}
- std::vector<limit_ptr>::const_iterator limit_end() const { return limitVec_.end();}
- std::vector<InLimit>::const_iterator inlimit_begin() const { return inLimitMgr_.inlimit_begin();}
- std::vector<InLimit>::const_iterator inlimit_end() const { return inLimitMgr_.inlimit_end();}
- std::string to_string() const; // For python interface
-
-private:
- Node* parent_; // *NOT* persisted must be set by the parent class
- std::string name_;
- bool suspended_;
- std::pair<NState,boost::posix_time::time_duration> state_; // state and duration since suite start when state changed
- DState defStatus_; // default value is QUEUED
-
- mutable Expression* completeExpr_; // can only have one complete expression
- mutable Expression* triggerExpr_; // can only have one trigger expression
-
- ecf::LateAttr* lateAttr_; // Can only have one late attribute per node
- ecf::AutoCancelAttr* autoCancel_; // Can only have 1 auto cancel per node
- TimeDepAttrs* time_dep_attrs_;
- ChildAttrs* child_attrs_; // event meter & lables
- MiscAttrs* misc_attrs_; // VerifyAttr(used for statistics and test verification) & Zombies
- Repeat repeat_; // each node can only have one repeat. By value, since has pimpl
-
- std::vector<Variable> varVec_;
- std::vector<limit_ptr> limitVec_; // Ptrs since many in-limits can point to a single limit
- InLimitMgr inLimitMgr_; // manages the inlimit
-
- ecf::Flag flag_;
-
- unsigned int state_change_no_; // *not* persisted, only used on server side,Used to indicate addition or deletion of attribute
- unsigned int variable_change_no_; // *not* persisted, placed here rather than Variable, to save memory
- unsigned int suspended_change_no_; // *not* persisted,
-
-#ifdef DEBUG
- boost::posix_time::ptime submit_to_complete_duration_; // *not* persisted
-#endif
-
- void* graphic_ptr_; // for use with the gui only
-
- friend class TimeDepAttrs;
- friend class ChildAttrs;
- friend class MiscAttrs;
-
-private:
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/) {
- ar & name_;
- ar & state_;
- ar & suspended_;
- ar & defStatus_;
- ar & completeExpr_;
- ar & triggerExpr_;
- ar & lateAttr_;
- ar & autoCancel_;
- ar & time_dep_attrs_;
- ar & child_attrs_;
- ar & misc_attrs_; // VerifyAttr & Zombies
- ar & repeat_;
- ar & varVec_;
- ar & limitVec_;
- ar & inLimitMgr_;
- ar & flag_;
-
- if (Archive::is_loading::value) {
- if (time_dep_attrs_) time_dep_attrs_->set_node(this);
- if (child_attrs_) child_attrs_->set_node(this);
- if (misc_attrs_) misc_attrs_->set_node(this);
- for(std::vector<limit_ptr>::iterator i = limitVec_.begin(); i!= limitVec_.end(); ++i) (*i)->set_node(this);
- }
- }
-};
-#endif
diff --git a/ecflow_4_0_7/ANode/src/NodeAdd.cpp b/ecflow_4_0_7/ANode/src/NodeAdd.cpp
deleted file mode 100644
index 1d1fcc0..0000000
--- a/ecflow_4_0_7/ANode/src/NodeAdd.cpp
+++ /dev/null
@@ -1,299 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #50 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/make_shared.hpp>
-#include <boost/lexical_cast.hpp>
-#include "Node.hpp"
-#include "Ecf.hpp"
-
-using namespace ecf;
-using namespace std;
-
-void Node::addVariable(const Variable& v )
-{
- state_change_no_ = Ecf::incr_state_change_no();
-
- const std::string& variable_name = v.name();
- size_t theSize = varVec_.size();
- for(size_t i = 0; i < theSize; i++) {
- if (varVec_[i].name() == variable_name) {
- // Variable already exist, *UPDATE* its value
- varVec_[i].set_value(v.theValue());
- if (0 == Ecf::debug_level())
- std::cout << "Node::addVariable: Variable of name '" << v.name() << "' already exist for node " << debugNodePath() << " updating with value '" << v.theValue() << "'\n";
- return;
- }
- }
-
- if (varVec_.capacity() == 0) varVec_.reserve(5);
- varVec_.push_back( v );
-}
-
-void Node::add_variable(const std::string& name, const std::string& value )
-{
- addVariable( Variable(name, value) );
-}
-
-void Node::add_variable_int(const std::string& name, int some_int )
-{
- std::string value = boost::lexical_cast<std::string>(some_int);
- addVariable( Variable(name, value) );
-}
-
-void Node::add_trigger(const std::string& string_expression)
-{
- add_trigger_expression(Expression(string_expression));
-}
-void Node::add_complete(const std::string& string_expression)
-{
- add_complete_expression(Expression(string_expression));
-}
-void Node::add_trigger_expr(const Expression& expr)
-{
- add_trigger_expression(expr);
-}
-void Node::add_complete_expr(const Expression& expr)
-{
- add_complete_expression(expr);
-}
-void Node::add_trigger_expression(const Expression& t)
-{
- if ( triggerExpr_ ) {
- std::stringstream ss;
- ss << "Node::add_trigger_expression. A Node(" << absNodePath() << " can only have one trigger ";
- ss << "to add large triggers use multiple calls to Node::add_part_trigger( PartExpression('t1 == complete') )";
- throw std::runtime_error( ss.str() );
- }
- triggerExpr_ = new Expression(t);
- state_change_no_ = Ecf::incr_state_change_no();
-}
-
-void Node::add_complete_expression(const Expression& t)
-{
- if ( completeExpr_ ) {
- std::stringstream ss;
- ss << "Node::add_complete_expression. A Node(" << absNodePath() << " can only have one complete expression ";
- ss << "to add large complete expressions use multiple calls to Node::add_part_complete( PartExpression('t1 == complete') )";
- throw std::runtime_error( ss.str() );
- }
- completeExpr_ = new Expression(t);
- state_change_no_ = Ecf::incr_state_change_no();
-}
-
-void Node::add_part_trigger(const PartExpression& part)
-{
- if (!triggerExpr_) triggerExpr_ = new Expression();
- triggerExpr_->add( part );
- state_change_no_ = Ecf::incr_state_change_no();
-}
-void Node::add_part_complete(const PartExpression& part)
-{
- if (!completeExpr_) completeExpr_ = new Expression();
- completeExpr_->add( part );
- state_change_no_ = Ecf::incr_state_change_no();
-}
-
-
-void Node::addTime(const ecf::TimeAttr& t)
-{
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Node::addTime\n";
-#endif
-
- if (isSuite()) {
- throw std::runtime_error("Can not add time based dependency on a suite");
- }
-
- if (!time_dep_attrs_) time_dep_attrs_ = new TimeDepAttrs(this);
- time_dep_attrs_->addTime(t); // will call Ecf::incr_state_change_no();
-}
-
-void Node::addToday(const ecf::TodayAttr& t)
-{
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Node::addToday()\n";
-#endif
-
- if (isSuite()) {
- throw std::runtime_error("Can not add time based dependency on a suite");
- }
-
- if (!time_dep_attrs_) time_dep_attrs_ = new TimeDepAttrs(this);
- time_dep_attrs_->addToday(t); // will call Ecf::incr_state_change_no();
-}
-
-void Node::addDate( const DateAttr& d)
-{
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Node::addDate()\n";
-#endif
-
- // By disallowing what effect would if have on existing suites ?
- if (isSuite()) {
- throw std::runtime_error("Can not add time based dependency on a suite"); // Added at 4.0.2
- }
-
- if (!time_dep_attrs_) time_dep_attrs_ = new TimeDepAttrs(this);
- time_dep_attrs_->addDate(d); // will call Ecf::incr_state_change_no();
-}
-
-void Node::addDay( const DayAttr& d)
-{
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Node::addDay\n";
-#endif
-
- // By disallowing what effect would if have on existing suites ?
- if (isSuite()) {
- throw std::runtime_error("Can not add time based dependency on a suite"); // Added at 4.0.2
- }
-
- if (!time_dep_attrs_) time_dep_attrs_ = new TimeDepAttrs(this);
- time_dep_attrs_->addDay(d); // will call Ecf::incr_state_change_no();
-}
-
-void Node::addCron( const CronAttr& d)
-{
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Node::addCron()\n";
-#endif
-
- if (d.time().isNULL()) {
- throw std::runtime_error("Node::addCron: The cron is in-complete, no time specified");
- }
- if (d.time().hasIncrement() && !repeat_.empty()) {
- std::stringstream ss;
- ss << "Node::addCron: Node " << absNodePath() << " already has a repeat. Inappropriate to add two looping structures at the same level\n";
- throw std::runtime_error(ss.str());
- }
-
- if (!time_dep_attrs_) time_dep_attrs_ = new TimeDepAttrs(this);
- time_dep_attrs_->addCron(d); // will call Ecf::incr_state_change_no();
-}
-
-
-void Node::addLabel( const Label& l)
-{
- if (child_attrs_) {
- child_attrs_->addLabel(l); // can throw
- return;
- }
- child_attrs_ = new ChildAttrs(this);
- child_attrs_->addLabel(l);
-}
-
-void Node::addMeter( const Meter& m)
-{
-// if ( isSuite() ) {
-// throw std::runtime_error("Node::addMeter: Can not add meter to a Suite");
-// }
-
- if (child_attrs_) {
- child_attrs_->addMeter(m); // can throw
- return;
- }
- child_attrs_ = new ChildAttrs(this);
- child_attrs_->addMeter(m);
-}
-
-void Node::addEvent( const Event& e)
-{
- if (child_attrs_) {
- child_attrs_->addEvent(e); // can throw
- return;
- }
- child_attrs_ = new ChildAttrs(this);
- child_attrs_->addEvent(e);
-}
-
-void Node::addLimit(const Limit& l )
-{
- if (findLimit(l)) {
- std::stringstream ss;
- ss << "Add Limit failed: Duplicate Limit of name '" << l.name() << "' already exist for node " << debugNodePath();
- throw std::runtime_error( ss.str() );
- }
- limit_ptr the_limit = boost::make_shared<Limit>(l);
- the_limit->set_node(this);
- limitVec_.push_back( the_limit );
- state_change_no_ = Ecf::incr_state_change_no();
-}
-
-static void throwIfRepeatAllreadyExists(Node* node)
-{
- if (!node->repeat().empty()) {
- std::stringstream ss;
- ss << "Add Repeat failed: Repeat of name '" << node->repeat().name() << "' already exist for node " << node->debugNodePath();
- throw std::runtime_error( ss.str() );
- }
-
- if (!node->crons().empty()) {
- std::stringstream ss;
- ss << "Node::addRepeat: Node " << node->absNodePath() << " already has a cron. Inappropriate to add two looping structures at the same level\n";
- throw std::runtime_error(ss.str());
- }
-}
-void Node::addRepeat( const Repeat& r ){
- throwIfRepeatAllreadyExists(this);
- repeat_ = Repeat(r);
- repeat_.update_repeat_genvar();
- state_change_no_ = Ecf::incr_state_change_no();
-}
-
-void Node::addAutoCancel( const AutoCancelAttr& ac)
-{
- if (autoCancel_) {
- std::stringstream ss;
- ss << "Node::addAutoCancel: A node can only have one Autocancel, see node " << debugNodePath();
- throw std::runtime_error( ss.str() );
- }
- autoCancel_ = new ecf::AutoCancelAttr(ac);
- state_change_no_ = Ecf::incr_state_change_no();
-}
-
-void Node::addLate( const ecf::LateAttr& l )
-{
- if (! lateAttr_) {
- lateAttr_ = new ecf::LateAttr(l);
- state_change_no_ = Ecf::incr_state_change_no();
- return;
- }
- throw std::runtime_error("Add Late failed: A node can only have one Late attribute, see node " + debugNodePath() );
-}
-
-
-void Node::addVerify( const VerifyAttr& v )
-{
- if (misc_attrs_) {
- misc_attrs_->addVerify(v); // can throw
- return;
- }
- misc_attrs_ = new MiscAttrs(this);
- misc_attrs_->addVerify(v);
-}
-
-void Node::addZombie( const ZombieAttr& z)
-{
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Node::addZombie()\n";
-#endif
-
- if (misc_attrs_) {
- misc_attrs_->addZombie(z); // can throw
- return;
- }
- misc_attrs_ = new MiscAttrs(this);
- misc_attrs_->addZombie(z);
-
-}
diff --git a/ecflow_4_0_7/ANode/src/NodeChange.cpp b/ecflow_4_0_7/ANode/src/NodeChange.cpp
deleted file mode 100644
index 251ec8a..0000000
--- a/ecflow_4_0_7/ANode/src/NodeChange.cpp
+++ /dev/null
@@ -1,188 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #33 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <boost/lexical_cast.hpp>
-
-#include "Node.hpp"
-#include "ExprAst.hpp"
-#include "Stl.hpp"
-#include "NState.hpp"
-#include "Ecf.hpp"
-#include "Str.hpp"
-
-using namespace ecf;
-using namespace std;
-
-void Node::changeVariable(const std::string& name,const std::string& value)
-{
- size_t theSize = varVec_.size();
- for(size_t i = 0; i < theSize; i++) {
- if (varVec_[i].name() == name) {
- varVec_[i].set_value( value );
- variable_change_no_ = Ecf::incr_state_change_no();
- return;
- }
- }
- throw std::runtime_error("Node::changeVariable: Could not find variable " + name);
-}
-
-bool Node::set_event(const std::string& event_name_or_number ,bool value)
-{
- if (child_attrs_) return child_attrs_->set_event(event_name_or_number,value);
- return false;
-}
-
-bool Node::set_event_used_in_trigger(const std::string& event_name_or_number)
-{
- if (child_attrs_) return child_attrs_->set_event_used_in_trigger(event_name_or_number);
- return false;
-}
-void Node::changeEvent(const std::string& event_name_or_number,const std::string& setOrClear)
-{
- if (child_attrs_) return child_attrs_->changeEvent(event_name_or_number,setOrClear);
-}
-void Node::changeEvent(const std::string& event_name_or_number,bool value)
-{
- if (child_attrs_) {
- child_attrs_->changeEvent(event_name_or_number,value);
- return;
- }
- throw std::runtime_error("Node::changeEvent: Could not find event " + event_name_or_number);
-}
-
-bool Node::set_meter(const std::string& meter_name,int value)
-{
- if (child_attrs_) return child_attrs_->set_meter(meter_name,value);
- return false;
-}
-bool Node::set_meter_used_in_trigger(const std::string& meter_name)
-{
- if (child_attrs_) return child_attrs_->set_meter_used_in_trigger(meter_name);
- return false;
-}
-void Node::changeMeter(const std::string& meter_name,const std::string& value)
-{
- if (child_attrs_) {
- child_attrs_->changeMeter(meter_name,value);
- return;
- }
- throw std::runtime_error("Node::changeMeter: Could not find meter " + meter_name);
-}
-void Node::changeMeter(const std::string& meter_name,int value)
-{
- if (child_attrs_) {
- child_attrs_->changeMeter(meter_name,value);
- return;
- }
- throw std::runtime_error("Node::changeMeter: Could not find meter " + meter_name);
-}
-
-void Node::changeLabel(const std::string& name,const std::string& value)
-{
- if (child_attrs_) {
- child_attrs_->changeLabel(name,value);
- return;
- }
- throw std::runtime_error("Node::changeLabel: Could not find label " + name);
-}
-
-void Node::changeTrigger(const std::string& expression)
-{
- PartExpression part(expression);
- string parseErrorMsg;
- std::auto_ptr<AstTop> ast = part.parseExpressions( parseErrorMsg );
- if (!ast.get()) {
- std::stringstream ss;
- ss << "Node::changeTrigger: Failed to parse expression '" << expression << "'. " << parseErrorMsg;
- throw std::runtime_error( ss.str() );
- }
-
- deleteTrigger();
- add_trigger( expression );
-}
-
-void Node::changeComplete(const std::string& expression)
-{
- PartExpression part(expression);
- string parseErrorMsg;
- std::auto_ptr<AstTop> ast = part.parseExpressions( parseErrorMsg );
- if (!ast.get()) {
- std::stringstream ss;
- ss << "Node::changeComplete: Failed to parse expression '" << expression << "'. " << parseErrorMsg;
- throw std::runtime_error( ss.str() );
- }
-
- deleteComplete();
- add_complete( expression );
-}
-
-void Node::changeRepeat(const std::string& value)
-{
- if (repeat_.empty()) throw std::runtime_error("Node::changeRepeat: Could not find repeat on " + absNodePath());
- repeat_.change( value ); // this can throw std::runtime_error
-}
-
-void Node::increment_repeat()
-{
- if (repeat_.empty()) throw std::runtime_error("Node::increment_repeat: Could not find repeat on " + absNodePath());
- repeat_.increment();
-}
-
-void Node::changeLimitMax(const std::string& name,const std::string& maxValue)
-{
- int theValue = 0;
- try {
- theValue = boost::lexical_cast< int >( maxValue );
- }
- catch ( boost::bad_lexical_cast& ) {
- throw std::runtime_error( "Node::changeLimitMax expected integer value but found " + maxValue);
- }
- changeLimitMax(name, theValue);
-}
-
-void Node::changeLimitMax(const std::string& name,int maxValue)
-{
- limit_ptr limit = find_limit(name);
- if (!limit.get()) throw std::runtime_error("Node::changeLimitMax: Could not find limit " + name);
- limit->setLimit( maxValue );
-}
-
-void Node::changeLimitValue(const std::string& name,const std::string& value)
-{
- int theValue = 0;
- try {
- theValue = boost::lexical_cast< int >( value );
- }
- catch ( boost::bad_lexical_cast& ) {
- throw std::runtime_error( "Node::changeLimitValue expected integer value but found " + value);
- }
- changeLimitValue(name,theValue);
-}
-
-void Node::changeLimitValue(const std::string& name,int value)
-{
- limit_ptr limit = find_limit(name);
- if (!limit.get()) throw std::runtime_error("Node::changeLimitValue: Could not find limit " + name);
- limit->setValue( value );
-}
-
-void Node::changeDefstatus(const std::string& theState)
-{
- if (!DState::isValid(theState)) {
- throw std::runtime_error( "Node::changeDefstatus expected a state but found " + theState);
- }
-
- // Updates state_change_no on the defStatus
- defStatus_.setState( DState::toState(theState) );
-}
diff --git a/ecflow_4_0_7/ANode/src/NodeContainer.cpp b/ecflow_4_0_7/ANode/src/NodeContainer.cpp
deleted file mode 100644
index 6798ced..0000000
--- a/ecflow_4_0_7/ANode/src/NodeContainer.cpp
+++ /dev/null
@@ -1,1000 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #135 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <limits>
-#include <assert.h>
-#include <sstream>
-#include <boost/bind.hpp>
-#include <boost/make_shared.hpp>
-
-#include "NodeContainer.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "Defs.hpp"
-#include "Log.hpp"
-#include "JobsParam.hpp"
-#include "NodeTreeVisitor.hpp"
-
-#include "Stl.hpp"
-#include "Indentor.hpp"
-#include "ExprAst.hpp"
-#include "NodeState.hpp"
-#include "Ecf.hpp"
-#include "NodeState.hpp"
-#include "SuiteChanged.hpp"
-#include "DefsDelta.hpp"
-#include "ChangeMgrSingleton.hpp"
-#include "Str.hpp"
-
-using namespace ecf;
-using namespace std;
-
-///////////////////////////////////////////////////////////////////////////////////////////
-//#define DEBUG_FIND_NODE 1
-//#define DEBUG_JOB_SUBMISSION 1
-
-/////////////////////////////////////////////////////////////////////////////////////////
-NodeContainer::NodeContainer( const std::string& name )
-: Node(name),order_state_change_no_(0), add_remove_state_change_no_(0) {}
-NodeContainer::NodeContainer()
-: order_state_change_no_(0),add_remove_state_change_no_(0) {}
-NodeContainer::~NodeContainer() {}
-
-void NodeContainer::accept(ecf::NodeTreeVisitor& v)
-{
- v.visitNodeContainer(this);
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) { nodeVec_[t]->accept(v); }
-}
-
-void NodeContainer::acceptVisitTraversor(ecf::NodeTreeVisitor& v)
-{
- v.visitNodeContainer(this);
-}
-
-void NodeContainer::begin()
-{
- Node::begin();
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) { nodeVec_[t]->begin(); }
- handle_defstatus_propagation();
-}
-
-void NodeContainer::requeue(
- bool resetRepeats,
- int clear_suspended_in_child_nodes,
- bool reset_next_time_slot
- )
-{
-// LOG(Log::DBG," " << debugType() << "::requeue() " << absNodePath() << " resetRepeats = " << resetRepeats);
- Node::requeue(resetRepeats,clear_suspended_in_child_nodes,reset_next_time_slot);
-
- // For negative numbers, do nothing, i.e do not clear
- if (clear_suspended_in_child_nodes >=0) clear_suspended_in_child_nodes++;
-
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) {
- nodeVec_[t]->requeue(true /*reset child repeats. Moot for tasks*/,
- clear_suspended_in_child_nodes,
- reset_next_time_slot);
- }
- handle_defstatus_propagation();
-}
-
-void NodeContainer::requeue_time_attrs()
-{
- Node::requeue_time_attrs();
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) {
- nodeVec_[t]->requeue_time_attrs();
- }
-}
-
-void NodeContainer::handle_defstatus_propagation()
-{
- if ( defStatus_ == DState::COMPLETE ) {
- /// A defstatus of complete and *ONLY* complete should always be applied
- /// hierarchically downwards
- setStateOnlyHierarchically(NState::COMPLETE);
- }
- else if ( defStatus_ == DState::default_state() ) {
- /// Reflect that the status of the children.
- /// *However* do NOT override the defstatus setting
- NState::State theSignificantStateOfImmediateChildren = computedState( Node::IMMEDIATE_CHILDREN );
- if ( theSignificantStateOfImmediateChildren != state()) {
- setStateOnly( theSignificantStateOfImmediateChildren );
- }
- }
-}
-
-void NodeContainer::resetRelativeDuration()
-{
- Node::resetRelativeDuration();
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) { nodeVec_[t]->resetRelativeDuration(); }
-}
-
-bool NodeContainer::run(JobsParam& jobsParam, bool force)
-{
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) { (void) nodeVec_[t]->run(jobsParam,force); }
- return jobsParam.getErrorMsg().empty();
-}
-
-void NodeContainer::kill(const std::string& /* zombie_pid, only valid for single task */)
-{
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) { nodeVec_[t]->kill(); }
-}
-
-void NodeContainer::status()
-{
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) { nodeVec_[t]->status(); }
-}
-
-void NodeContainer::top_down_why(std::vector<std::string>& theReasonWhy) const
-{
- Node::why(theReasonWhy);
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) { nodeVec_[t]->top_down_why(theReasonWhy); }
-}
-
-void NodeContainer::incremental_changes( DefsDelta& changes, compound_memento_ptr& comp) const
-{
- /// There no point doing a OrderMemento if children have been added/delete
- if (add_remove_state_change_no_ > changes.client_state_change_no()) {
- if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
- comp->add( boost::make_shared<ChildrenMemento>( nodeVec_ ) );
- }
- else if (order_state_change_no_ > changes.client_state_change_no()) {
- if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
- std::vector<std::string> order_vec; order_vec.reserve(nodeVec_.size());
- size_t node_vec_size = nodeVec_.size();
- for(size_t i =0; i < node_vec_size; i++) order_vec.push_back( nodeVec_[i]->name());
- comp->add( boost::make_shared<OrderMemento>( order_vec ) );
- }
-
- Node::incremental_changes(changes, comp);
-}
-
-void NodeContainer::set_memento( const OrderMemento* memento ) {
-#ifdef DEBUG_MEMENTO
- std::cout << "NodeContainer::set_memento( const OrderMemento* ) " << debugNodePath() << "\n";
-#endif
-
- // Order nodeVec_ according to memento ordering
- const std::vector<std::string>& order = memento->order_;
- if (order.size() != nodeVec_.size()) {
- // something gone wrong.
- std::cout << "NodeContainer::set_memento OrderMemento, memento.size() " << order.size() << " Not the same as nodeVec_size() " << nodeVec_.size() << "\n";
- return;
- }
-
- std::vector<node_ptr> vec; vec.reserve(nodeVec_.size());
- size_t node_vec_size = nodeVec_.size();
- for(size_t i = 0; i < order.size(); i++) {
- for(size_t t = 0; t < node_vec_size; t++) {
- if (order[i] == nodeVec_[t]->name()) {
- vec.push_back(nodeVec_[t]);
- break;
- }
- }
- }
- if (vec.size() != nodeVec_.size()) {
- std::cout << "NodeContainer::set_memento could not find all the names\n";
- return;
- }
-
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::ORDER);
- nodeVec_ = vec;
-}
-
-void NodeContainer::set_memento( const ChildrenMemento* memento ) {
-#ifdef DEBUG_MEMENTO
- std::cout << "NodeContainer::set_memento( const OrderMemento* ) " << debugNodePath() << "\n";
-#endif
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::ADD_REMOVE_NODE);
- nodeVec_ = memento->children_;
-
- // setup child parent pointers
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) {
- nodeVec_[t]->set_parent(this);
- }
-}
-
-
-void NodeContainer::collateChanges(DefsDelta& changes) const
-{
- /// There no point in traversing children of we have added/removed children
- /// since ChildrenMemento will copy all children.
- if (add_remove_state_change_no_ > changes.client_state_change_no()) {
- return;
- }
-
- // Traversal to children
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) { nodeVec_[t]->collateChanges(changes); }
-}
-
-void NodeContainer::order(Node* immediateChild, NOrder::Order ord)
-{
- SuiteChanged1 changed(suite());
- switch (ord) {
- case NOrder::TOP: {
- for(std::vector<node_ptr>::iterator i = nodeVec_.begin(); i != nodeVec_.end(); ++i) {
- if ((*i).get() == immediateChild) {
- node_ptr node = (*i);
- nodeVec_.erase(i);
- nodeVec_.insert(nodeVec_.begin(),node);
- order_state_change_no_ = Ecf::incr_state_change_no();
- return;
- }
- }
- throw std::runtime_error("NodeContainer::order TOP, immediate child not found");
- }
- case NOrder::BOTTOM: {
- for(std::vector<node_ptr>::iterator i = nodeVec_.begin(); i != nodeVec_.end(); ++i) {
- if ((*i).get() == immediateChild) {
- node_ptr node = (*i);
- nodeVec_.erase(i);
- nodeVec_.push_back(node);
- order_state_change_no_ = Ecf::incr_state_change_no();
- return;
- }
- }
- throw std::runtime_error("NodeContainer::order BOTTOM, immediate child not found");
- }
- case NOrder::ALPHA: {
- std::sort(nodeVec_.begin(),nodeVec_.end(),
- boost::bind(Str::caseInsLess,
- boost::bind(&Node::name,_1),
- boost::bind(&Node::name,_2)));
- order_state_change_no_ = Ecf::incr_state_change_no();
- break;
- }
- case NOrder::ORDER: {
- std::sort(nodeVec_.begin(),nodeVec_.end(),
- boost::bind(Str::caseInsGreater,
- boost::bind(&Node::name,_1),
- boost::bind(&Node::name,_2)));
- order_state_change_no_ = Ecf::incr_state_change_no();
- break;
- }
- case NOrder::UP: {
- for(size_t t = 0; t < nodeVec_.size();t++) {
- if ( nodeVec_[t].get() == immediateChild) {
- if (t != 0) {
- node_ptr node = nodeVec_[t];
- nodeVec_.erase(nodeVec_.begin()+t);
- t--;
- nodeVec_.insert(nodeVec_.begin()+t,node);
- order_state_change_no_ = Ecf::incr_state_change_no();
- }
- return;
- }
- }
- throw std::runtime_error("NodeContainer::order UP, immediate child not found");
- }
- case NOrder::DOWN: {
- for(size_t t = 0; t < nodeVec_.size();t++) {
- if ( nodeVec_[t].get() == immediateChild) {
- if (t != nodeVec_.size()-1) {
- node_ptr node = nodeVec_[t];
- nodeVec_.erase(nodeVec_.begin()+t);
- t++;
- nodeVec_.insert(nodeVec_.begin()+t,node);
- order_state_change_no_ = Ecf::incr_state_change_no();
- }
- return;
- }
- }
- throw std::runtime_error("NodeContainer::order DOWN, immediate child not found");
- }
- }
-}
-
-void NodeContainer::calendarChanged(
- const ecf::Calendar& c,
- std::vector<node_ptr>& auto_cancelled_nodes)
-{
- Node::calendarChanged(c,auto_cancelled_nodes);
-
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) { nodeVec_[t]->calendarChanged(c,auto_cancelled_nodes); }
-}
-
-bool NodeContainer::hasAutoCancel() const
-{
- if (Node::hasAutoCancel()) return true;
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) { if (nodeVec_[t]->hasAutoCancel()) return true; }
- return false;
-}
-
-bool NodeContainer::resolveDependencies(JobsParam& jobsParam)
-{
- // Don't evaluate children unless parent is free. BOMB out early for this case.
- // Note:: Task::resolveDependencies() will check inLimit up front. *** THIS CHECKS UP THE HIERARCHY ***
- // Note:: Node::resolveDependencies() may have forced family node to complete, should have have
- // returned false in this case, to stop any job submission
- if ( ! Node::resolveDependencies(jobsParam) ) {
-
-#ifdef DEBUG_JOB_SUBMISSION
- LOG(Log::DBG, " NodeContainer::resolveDependencies " << absNodePath() << " could not resolve dependencies, may have completed");
- cout << "NodeContainer::resolveDependencies " << absNodePath() << " could not resolve dependencies may have completed" << endl;
-#endif
- return false;
- }
-
- /// During *top down* traversal we check in limits at this level. Done here rather than
- /// in Node::resolveDependencies(). Otherwise this particular check will get duplicated
- /// since the task, will do *bottom up* traversal.
- if (!check_in_limit()) {
-#ifdef DEBUG_DEPENDENCIES
- LOG(Log::DBG," NodeContainer::resolveDependencies() " << absNodePath() << " HOLDING due to inLIMIT");
-#endif
- return false;
- }
-
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) {
- // Note: we don't bomb out early here. Since a later child could be free. i.e f1/ty or t4
- // child t1 holding
- // child t2 holding
- // child f1 free
- // child tx holding
- // child ty free
- // child t3 holding
- // child t4 free
- (void) nodeVec_[t]->resolveDependencies(jobsParam) ;
- }
- return true;
-}
-
-NState::State NodeContainer::computedState(Node::TraverseType traverseType) const
-{
- if (nodeVec_.empty()) {
- /// Note: theComputedNodeState will return unknown if no children, in this
- /// case just return the current state.
- return state();
- }
-
- // returns the computed state depending on traverseType
- // If not IMMEDIATE_CHILDREN, will recurse down calling each child's computedState() function
- return ecf::theComputedNodeState(nodeVec_, (traverseType == Node::IMMEDIATE_CHILDREN) );
-}
-
-node_ptr NodeContainer::removeChild(Node* child)
-{
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) {
- if (nodeVec_[t].get() == child) {
- node_ptr node = boost::dynamic_pointer_cast<Node>(nodeVec_[t]);
- child->set_parent(NULL); // must set to NULL, allows it to be re-added to different parent
- nodeVec_.erase( nodeVec_.begin() + t);
- add_remove_state_change_no_ = Ecf::incr_state_change_no();
- return node ;
- }
- }
- // Should never happen
- LOG_ASSERT(false,"NodeContainer::removeChild: Could not remove child");
- return node_ptr();
-}
-
-bool NodeContainer::addChild( node_ptr child, size_t position)
-{
- // *** CANT construct shared_ptr from a raw pointer, must use dynamic_pointer_cast,
- // *** otherwise the reference counts will get messed up.
- try {
- if ( child->isTask() ) {
- // can throw if duplicate names
- addTask( boost::dynamic_pointer_cast<Task>(child), position );
- return true;
- }
-
- if ( child->isFamily() ) {
- // can throw if duplicate names
- addFamily( boost::dynamic_pointer_cast<Family>(child), position );
- return true;
- }
- }
- catch ( std::runtime_error &e) {}
-
- // Duplicate names, or trying to add a Suite?
- return false;
-}
-
-bool NodeContainer::isAddChildOk( Node* theChild, std::string& errorMsg) const
-{
- Task* theTaskChild = theChild->isTask();
- if ( theTaskChild ) {
-
- task_ptr theTask = findTask(theChild->name());
- if (!theTask.get()) return true;
-
- std::stringstream ss;
- ss << "Task of name " << theChild->name() << " already exist in container node " << name() ;
- errorMsg += ss.str();
- return false;
- }
-
- Family* theFamilyChild = theChild->isFamily();
- if ( theFamilyChild ) {
-
- family_ptr theFamily = findFamily(theChild->name());
- if (!theFamily.get()) return true;
-
- std::stringstream ss;
- ss << "Family of name " << theChild->name() << " already exist in container node " << name() ;
- errorMsg += ss.str();
- return false;
- }
-
- Suite* theSuite = theChild->isSuite();
- if ( theSuite ) {
- errorMsg += "Can not add a suite as child.";
- return false;
- }
-
- errorMsg += "Unknown node type";
- return false;
-}
-
-void NodeContainer::handleStateChange()
-{
- // Increment any repeats & requeue
- requeueOrSetMostSignificantStateUpNodeTree();
-}
-
-size_t NodeContainer::child_position(const Node* child) const
-{
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) {
- if (nodeVec_[t].get() == child) {
- return t;
- }
- }
- return std::numeric_limits<std::size_t>::max();
-}
-
-task_ptr NodeContainer::add_task(const std::string& task_name)
-{
- if (findTask(task_name).get()) {
- std::stringstream ss;
- ss << "Add Task failed: A task of name '" << task_name << "' already exist on node " << debugNodePath();
- throw std::runtime_error( ss.str() );
- }
- task_ptr the_task = Task::create(task_name);
- add_task_only(the_task);
- return the_task;
-}
-
-family_ptr NodeContainer::add_family(const std::string& family_name)
-{
- if (findFamily(family_name).get()) {
- std::stringstream ss;
- ss << "Add Family failed: A Family of name '" << family_name << "' already exist on node " << debugNodePath();
- throw std::runtime_error( ss.str() );
- }
- family_ptr the_family = Family::create(family_name);
- add_family_only( the_family );
- return the_family;
-}
-
-void NodeContainer::addTask(task_ptr t,size_t position)
-{
- if (findTask(t->name()).get()) {
- std::stringstream ss;
- ss << "Add Task failed: A task of name '" << t->name() << "' already exist on node " << debugNodePath();
- throw std::runtime_error( ss.str() );
- }
- add_task_only( t, position);
-}
-
-void NodeContainer::add_task_only( task_ptr t, size_t position)
-{
- if (t->parent()) {
- std::stringstream ss;
- ss << debugNodePath() << ": Add Task failed: A task of name '" << t->name() << "' is already owned by another node" ;
- throw std::runtime_error( ss.str() );
- }
-
- t->set_parent(this);
- if (position >= nodeVec_.size()) {
- nodeVec_.push_back( t );
- }
- else {
- nodeVec_.insert( nodeVec_.begin() + position, t);
- }
- add_remove_state_change_no_ = Ecf::incr_state_change_no();
-}
-
-void NodeContainer::add_family_only( family_ptr f, size_t position)
-{
- if (f->parent()) {
- std::stringstream ss;
- ss << debugNodePath() << ": Add Family failed: A family of name '" << f->name() << "' is already owned by another node";
- throw std::runtime_error( ss.str() );
- }
-
- f->set_parent(this);
- if (position >= nodeVec_.size()) {
- nodeVec_.push_back( f );
- }
- else {
- nodeVec_.insert( nodeVec_.begin() + position, f);
- }
- add_remove_state_change_no_ = Ecf::incr_state_change_no();
-}
-
-
-void NodeContainer::addFamily(family_ptr f,size_t position)
-{
- if (findFamily(f->name()).get()) {
- std::stringstream ss;
- ss << "Add Family failed: A Family of name '" << f->name() << "' already exist on node " << debugNodePath();
- throw std::runtime_error( ss.str() );
- }
- add_family_only( f, position );
-}
-
-node_ptr NodeContainer::findImmediateChild(const std::string& theName, size_t& child_pos) const
-{
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) {
- if (nodeVec_[t]->name() == theName) {
- child_pos = t;
- return nodeVec_[t];
- }
- }
- child_pos = std::numeric_limits<std::size_t>::max();
- return node_ptr();
-}
-
-node_ptr NodeContainer::find_node_up_the_tree(const std::string& the_name) const
-{
- if (name() == the_name) {
- return non_const_this();
- }
-
- size_t not_used;
- node_ptr fnd_node = findImmediateChild(the_name,not_used);
- if (fnd_node) return fnd_node;
-
- Node* the_parent = parent();
- if (the_parent) return the_parent->find_node_up_the_tree(the_name);
- return node_ptr();
-}
-
-
-node_ptr NodeContainer::find_relative_node( const std::vector< std::string >& pathToNode)
-{
-//#ifdef DEBUG_FIND_NODE
-// cout << "NodeContainer::find_relative_node for '" << name()
-// << "' path = '" << pathToNode << "\n";
-// cout << " tasks = "; BOOST_FOREACH(task_ptr t, nodeVec_ ) { cout << " " << t->name(); } cout << "\n";
-// cout << " family = "; BOOST_FOREACH(family_ptr f, familyVec_ ) { cout << " " << f->name();} cout << "\n";
-//#endif
- if (pathToNode.empty()) return node_ptr();
- int pathSize = static_cast<int>(pathToNode.size());
-
-#ifdef DEBUG_FIND_NODE
- cout << "NodeContainer::find_relative_node name = '" << name() << "' pathToNode[0] = '" << pathToNode[0] << "'\n";
-#endif
-
- if (pathSize == 1 && name() == pathToNode[0]) {
- // Match the Container i.e family or suite
- return shared_from_this();
- }
-
- // Must match all children
- int index = 0;
- size_t child_pos = 0 ; // unused
- node_ptr the_node = shared_from_this();
- while (index < pathSize) {
- the_node = the_node->findImmediateChild(pathToNode[index],child_pos);
- if (the_node) {
- if (index == pathSize - 1) return the_node;
- index++;
- }
- else {
- return node_ptr();
- }
- }
- return node_ptr();
-}
-
-void NodeContainer::find_closest_matching_node( const std::vector< std::string >& pathToNode, int indexIntoPathNode, node_ptr& closest_matching_node )
-{
- int pathSize = static_cast<int>(pathToNode.size());
- if (indexIntoPathNode >= pathSize) return;
-
- int index = indexIntoPathNode;
- if (name() == pathToNode[indexIntoPathNode]) {
-
- closest_matching_node = shared_from_this();
-
- // Match the Container i.e family or suite
- bool lastIndex = ( indexIntoPathNode == pathSize - 1);
- if ( lastIndex ) {
- return;
- }
-
- // Match the Children, i.e. go down the hierarchy
- index++;
- match_closest_children(pathToNode,index,closest_matching_node);
- }
-}
-
-void NodeContainer::match_closest_children(const std::vector<std::string>& pathToNode, int indexIntoPathNode, node_ptr& closest_matching_node)
-{
- int pathSize = static_cast<int>(pathToNode.size());
- if (indexIntoPathNode >= pathSize) return;
-
- bool lastIndex = ( indexIntoPathNode == pathSize - 1);
- if ( lastIndex ) {
- // even if the name matches, its only valid if the index is the last index
- // i.e if we have a suite like /a/b/c/d/e
- // and a path like /a/b/c/d/e/f/g
- // In this we will match with e but it not valid since its not the last index
- size_t task_vec_size = nodeVec_.size();
- for(size_t t = 0; t < task_vec_size; t++) {
- if (nodeVec_[t]->name() == pathToNode[indexIntoPathNode]) {
- closest_matching_node = nodeVec_[t];
- return;
- }
- }
- }
- else {
- // Path to node is of the form "/family/task" or "/family/family/task"
- // Path to node is of the form "/suite/task" or "/suite/family/task"
- size_t family_vec_size = nodeVec_.size();
- for(size_t f = 0; f < family_vec_size; f++) {
- Family* family = nodeVec_[f]->isFamily();
- if (family) {
- node_ptr matching_node;
- family->find_closest_matching_node(pathToNode, indexIntoPathNode,matching_node);
- if (matching_node.get()) {
- closest_matching_node = matching_node;
- return;
- }
- }
- }
- }
-}
-
-family_ptr NodeContainer::findFamily(const std::string& familyName) const
-{
- size_t node_vec_size = nodeVec_.size();
- for(size_t f = 0; f < node_vec_size; f++) {
- if (nodeVec_[f]->name() == familyName && nodeVec_[f]->isFamily()) {
- return boost::dynamic_pointer_cast<Family>(nodeVec_[f]);
- }
- }
- return family_ptr();
-}
-
-task_ptr NodeContainer::findTask(const std::string& taskName) const
-{
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) {
- if (nodeVec_[t]->name() == taskName && nodeVec_[t]->isTask()) {
- return boost::dynamic_pointer_cast<Task>(nodeVec_[t]);
- }
- }
- return task_ptr();
-}
-
-bool NodeContainer::hasTimeDependencies() const
-{
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) { if (nodeVec_[t]->hasTimeDependencies()) return true;}
- return false;
-}
-
-void NodeContainer::immediateChildren(std::vector<node_ptr>& theChildren) const
-{
- size_t task_vec_size = nodeVec_.size();
- theChildren.reserve( theChildren.size() + task_vec_size);
- for(size_t t = 0; t < task_vec_size; t++) {
- theChildren.push_back( nodeVec_[t] );
- }
-}
-
-void NodeContainer::allChildren(std::set<Node*>& theSet) const
-{
- size_t node_vec_size = nodeVec_.size();
- for(size_t f = 0; f < node_vec_size; f++) {
- theSet.insert(nodeVec_[f].get());
- nodeVec_[f]->allChildren(theSet);
- }
-}
-
-void NodeContainer::getAllFamilies(std::vector<Family*>& vec) const
-{
- size_t node_vec_size = nodeVec_.size();
- for(size_t f = 0; f < node_vec_size; f++) {
- Family* family = nodeVec_[f]->isFamily();
- if ( family ) {
- vec.push_back(family);
- family->getAllFamilies(vec);
- }
- }
-}
-
-void NodeContainer::getAllNodes(std::vector<Node*>& vec) const
-{
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) {
- vec.push_back(nodeVec_[t].get());
- nodeVec_[t]->getAllNodes(vec);
- }
-}
-
-void NodeContainer::getAllTasks(std::vector<Task*>& tasks) const
-{
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) {
- nodeVec_[t]->getAllTasks(tasks);
- }
-}
-
-void NodeContainer::getAllSubmittables(std::vector<Submittable*>& tasks) const
-{
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) {
- nodeVec_[t]->getAllSubmittables(tasks);
- }
-}
-
-void NodeContainer::get_all_active_submittables(std::vector<Submittable*>& tasks) const
-{
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) {
- nodeVec_[t]->get_all_active_submittables(tasks);
- }
-}
-
-void NodeContainer::get_all_tasks(std::vector<task_ptr>& tasks) const
-{
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) {
- nodeVec_[t]->get_all_tasks(tasks);
- }
-}
-
-void NodeContainer::get_all_nodes(std::vector<node_ptr>& nodes) const
-{
- nodes.push_back(non_const_this());
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) {
- nodeVec_[t]->get_all_nodes(nodes);
- }
-}
-
-void NodeContainer::get_all_aliases(std::vector<alias_ptr>& aliases) const
-{
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) {
- nodeVec_[t]->get_all_aliases(aliases);
- }
-}
-
-void NodeContainer::getAllAstNodes(std::set<Node*>& vec) const
-{
- Node::getAllAstNodes(vec);
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) { nodeVec_[t]->getAllAstNodes(vec); }
-}
-
-bool NodeContainer::check(std::string& errorMsg, std::string& warningMsg) const
-{
- Node::check(errorMsg, warningMsg);
-
- // recursive to handle hierarchical families
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) {
- nodeVec_[t]->check(errorMsg,warningMsg);
- // if (!errorMsg.empty()) break;
- }
-
- return errorMsg.empty();
-}
-
-std::vector<task_ptr> NodeContainer::taskVec() const
-{
- size_t node_vec_size = nodeVec_.size();
- std::vector<task_ptr> vec; vec.reserve(node_vec_size);
- for(size_t t = 0; t < node_vec_size; t++) {
- if (nodeVec_[t]->isTask()) {
- vec.push_back( boost::dynamic_pointer_cast<Task>(nodeVec_[t]) );
- }
- }
- return vec;
-}
-
-std::vector<family_ptr> NodeContainer::familyVec() const
-{
- std::vector<family_ptr> vec;
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) {
- if (nodeVec_[t]->isFamily()) {
- vec.push_back( boost::dynamic_pointer_cast<Family>(nodeVec_[t]) );
- }
- }
- return vec;
-}
-
-bool NodeContainer::operator==(const NodeContainer& rhs) const
-{
- size_t node_vec_size = nodeVec_.size();
- if ( node_vec_size != rhs.nodeVec_.size()) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "NodeContainer::operator== node_vec_size != rhs.nodeVec_.size() " << absNodePath() << "\n";
- std::cout << " nodeVec_.size() = " << node_vec_size << " rhs.nodeVec_.size() = " << rhs.nodeVec_.size() << "\n";
- }
-#endif
- return false;
- }
-
- for(size_t i =0; i < node_vec_size; ++i) {
-
- Task* task = nodeVec_[i]->isTask();
- if (task) {
- Task* rhs_task = rhs.nodeVec_[i]->isTask();
- if ( !rhs_task ) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "NodeContainer::operator== if ( !rhs_task ) " << absNodePath() << "\n";
- }
-#endif
- return false;
- }
-
- if ( !( *task == *rhs_task )) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "NodeContainer::operator== if ( !( *task == *rhs_task )) " << absNodePath() << "\n";
- }
-#endif
- return false;
- }
- }
- else {
- Family* rhs_family = rhs.nodeVec_[i]->isFamily();
- if ( !rhs_family ) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "NodeContainer::operator== if ( !rhs_family ) " << absNodePath() << "\n";
- }
-#endif
- return false;
- }
-
- Family* family = nodeVec_[i]->isFamily(); LOG_ASSERT( family, "" );
- if ( !( *family == *rhs_family )) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "NodeContainer::operator== if ( !( *family == *rhs_family )) " << absNodePath() << "\n";
- }
-#endif
- return false;
- }
- }
- }
-
- return Node::operator==(rhs);
-}
-
-std::ostream& NodeContainer::print(std::ostream& os) const
-{
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) { nodeVec_[t]->print( os ); }
- return os;
-}
-
-bool NodeContainer::checkInvariants(std::string& errorMsg) const
-{
- if (!Node::checkInvariants(errorMsg)) return false;
-
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) {
- if (nodeVec_[t]->parent() != this) {
- errorMsg += "NodeContainer::checkInvariants family/task parent() not correct";
- return false;
- }
- if (!nodeVec_[t]->checkInvariants(errorMsg)) {
- return false;
- }
- }
- return true;
-}
-
-void NodeContainer::verification(std::string& errorMsg) const
-{
- Node::verification(errorMsg);
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) { nodeVec_[t]->verification(errorMsg); }
-}
-
-void NodeContainer::setRepeatToLastValueHierarchically()
-{
- setRepeatToLastValue();
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) { nodeVec_[t]->setRepeatToLastValueHierarchically(); }
-}
-
-void NodeContainer::setStateOnlyHierarchically(NState::State s,bool force)
-{
- setStateOnly(s,force);
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) { nodeVec_[t]->setStateOnlyHierarchically(s,force); }
-}
-
-void NodeContainer::set_state_hierarchically(NState::State s, bool force)
-{
- setStateOnlyHierarchically(s,force);
- if (force) {
- // *force* is only set via ForceCmd.
- update_limits(); // hierarchical
- }
- handleStateChange(); // non-hierarchical
-}
-
-void NodeContainer::update_limits()
-{
- /// Only tasks can affect the limits, hence no point calling locally
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) { nodeVec_[t]->update_limits(); }
-}
-
-bool NodeContainer::doDeleteChild(Node* child)
-{
- SuiteChanged1 changed(suite());
- std::vector<node_ptr>::iterator theTaskEnd = nodeVec_.end();
- for(std::vector<node_ptr>::iterator t = nodeVec_.begin(); t!=theTaskEnd; ++t) {
- if ( (*t).get() == child) {
- child->set_parent(NULL); // must set to NULL, allow it to be re-added to different parent
- nodeVec_.erase(t);
- add_remove_state_change_no_ = Ecf::incr_state_change_no();
- set_most_significant_state_up_node_tree();
- return true;
- }
- if ((*t)->doDeleteChild(child)) {
- return true;
- }
- }
-
- return false;
-}
-
-void NodeContainer::check_job_creation( job_creation_ctrl_ptr jobCtrl) {
-
- if (defStatus() != DState::COMPLETE) {
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) { nodeVec_[t]->check_job_creation( jobCtrl ); }
- }
-}
-
-void NodeContainer::generate_scripts( const std::map<std::string,std::string>& override) const
-{
- size_t node_vec_size = nodeVec_.size();
- for(size_t t = 0; t < node_vec_size; t++) {
- nodeVec_[t]->generate_scripts( override );
- }
-}
diff --git a/ecflow_4_0_7/ANode/src/NodeContainer.hpp b/ecflow_4_0_7/ANode/src/NodeContainer.hpp
deleted file mode 100644
index 59bf464..0000000
--- a/ecflow_4_0_7/ANode/src/NodeContainer.hpp
+++ /dev/null
@@ -1,151 +0,0 @@
-#ifndef NODE_CONTAINER_HPP_
-#define NODE_CONTAINER_HPP_
-
-//============================================================================
-// Name : NodeContainer.hpp
-// Author : Avi
-// Revision : $Revision: #88 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : A class that holds families and tasks
-//============================================================================
-
-#include <limits>
-#include "Node.hpp"
-
-class NodeContainer : public Node {
-public:
- NodeContainer ( const std::string& name );
- NodeContainer();
- virtual ~NodeContainer();
-
- virtual void accept(ecf::NodeTreeVisitor&);
- virtual void acceptVisitTraversor(ecf::NodeTreeVisitor& v);
- virtual void begin();
- virtual void requeue( bool resetRepeats,
- int clear_suspended_in_child_nodes,
- bool reset_next_time_slot);
- virtual void requeue_time_attrs();
- virtual void resetRelativeDuration();
- virtual bool run(JobsParam& jobsParam, bool force);
- virtual void kill(const std::string& zombie_pid = "");
- virtual void status();
- virtual void top_down_why(std::vector<std::string>& theReasonWhy) const;
- virtual void collateChanges(DefsDelta&) const;
- void set_memento(const OrderMemento* );
- void set_memento(const ChildrenMemento* );
- virtual void order(Node* immediateChild, NOrder::Order);
-
- virtual bool hasAutoCancel() const;
- virtual void calendarChanged(const ecf::Calendar&,std::vector<node_ptr>& auto_cancelled_nodes);
- virtual bool resolveDependencies(JobsParam& );
- virtual bool check(std::string& errorMsg, std::string& warningMsg) const;
-
- task_ptr add_task(const std::string& task_name);
- family_ptr add_family(const std::string& family_name);
- void addTask( task_ptr , size_t position = std::numeric_limits<std::size_t>::max());
- void addFamily( family_ptr, size_t position = std::numeric_limits<std::size_t>::max());
-
- virtual void immediateChildren(std::vector<node_ptr>&) const;
- virtual void allChildren(std::set<Node*>&) const;
-
- virtual node_ptr findImmediateChild(const std::string& name,size_t& child_pos) const;
- virtual node_ptr find_node_up_the_tree(const std::string& name) const;
-
- virtual node_ptr find_relative_node(const std::vector<std::string>& pathToNode);
- void find_closest_matching_node( const std::vector< std::string >& pathToNode, int indexIntoPathNode, node_ptr& closest_matching_node );
-
- family_ptr findFamily(const std::string& familyName) const;
- task_ptr findTask(const std::string& taskName) const;
- void getAllFamilies(std::vector<Family*>&) const;
- virtual void getAllNodes(std::vector<Node*>&) const;
- virtual void getAllTasks(std::vector<Task*>&) const;
- virtual void getAllSubmittables(std::vector<Submittable*>&) const;
- virtual void get_all_active_submittables(std::vector<Submittable*>&) const;
- virtual void get_all_tasks(std::vector<task_ptr>&) const;
- virtual void get_all_nodes(std::vector<node_ptr>&) const;
- virtual void get_all_aliases(std::vector<alias_ptr>&) const;
- virtual void getAllAstNodes(std::set<Node*>&) const;
- const std::vector<node_ptr>& nodeVec() const { return nodeVec_;}
- std::vector<task_ptr> taskVec() const;
- std::vector<family_ptr> familyVec() const;
-
- std::ostream& print(std::ostream&) const;
- bool operator==(const NodeContainer& rhs) const;
-
- virtual bool hasTimeDependencies() const;
-
- virtual void check_job_creation( job_creation_ctrl_ptr jobCtrl);
- virtual void generate_scripts( const std::map<std::string,std::string>& override) const;
-
- virtual bool checkInvariants(std::string& errorMsg) const;
- virtual void verification(std::string& errorMsg) const;
-
- virtual NState::State computedState(Node::TraverseType) const;
-
- virtual node_ptr removeChild( Node* child);
- virtual bool addChild( node_ptr child,size_t position = std::numeric_limits<std::size_t>::max());
- virtual bool isAddChildOk( Node* child, std::string& errorMsg) const;
-
- virtual void setRepeatToLastValueHierarchically();
- virtual void setStateOnlyHierarchically(NState::State s,bool force = false);
- virtual void set_state_hierarchically(NState::State s, bool force);
- virtual void update_limits();
-
-private:
- virtual size_t child_position(const Node*) const;
- void add_task_only( task_ptr ,size_t position = std::numeric_limits<std::size_t>::max());
- void add_family_only( family_ptr ,size_t position = std::numeric_limits<std::size_t>::max());
-
- void handle_defstatus_propagation();
- void match_closest_children(const std::vector<std::string>& pathToNode, int indexIntoPathToNode,node_ptr& closest_matching_node);
-
- virtual void handleStateChange(); // called when a state change happens
-
- friend class Defs;
- friend class Family;
- virtual bool doDeleteChild(Node* child);
-
- /// For use by python interface,
- std::vector<node_ptr>::const_iterator node_begin() const { return nodeVec_.begin();}
- std::vector<node_ptr>::const_iterator node_end() const { return nodeVec_.end();}
- friend void export_SuiteAndFamily();
-
-protected:
- unsigned int order_state_change_no_; // no need to persist
- unsigned int add_remove_state_change_no_;// no need to persist
-
- void incremental_changes( DefsDelta& changes, compound_memento_ptr& comp) const;
-
-private:
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/)
- {
- ar.register_type(static_cast<Task *>(NULL));
- ar.register_type(static_cast<Family *>(NULL));
-
- // serialise base class information
- ar & boost::serialization::base_object<Node>(*this);
- ar & nodeVec_;
-
- // Setup the parent pointers. Since they are not serialised
- if (Archive::is_loading::value) {
- size_t vec_size = nodeVec_.size();
- for(size_t i = 0; i < vec_size; i++) {
- nodeVec_[i]->set_parent(this);
- }
- }
- }
-
-private:
- std::vector<node_ptr> nodeVec_;
-};
-
-#endif
diff --git a/ecflow_4_0_7/ANode/src/NodeDelete.cpp b/ecflow_4_0_7/ANode/src/NodeDelete.cpp
deleted file mode 100644
index c54c3f0..0000000
--- a/ecflow_4_0_7/ANode/src/NodeDelete.cpp
+++ /dev/null
@@ -1,263 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #26 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include "Node.hpp"
-#include "ExprAst.hpp"
-#include "Stl.hpp"
-#include "Ecf.hpp"
-
-using namespace ecf;
-using namespace std;
-
-void Node::deleteTime(const std::string& name )
-{
- if (time_dep_attrs_) {
- time_dep_attrs_->deleteTime(name);
- return;
- }
- throw std::runtime_error("Node::delete_time: Can not find time attribute: ");
-}
-
-void Node::delete_time( const ecf::TimeAttr& attr )
-{
- if (time_dep_attrs_) {
- time_dep_attrs_->delete_time(attr);
- return;
- }
- throw std::runtime_error("Node::delete_time: Can not find time attribute: ");
-}
-
-void Node::deleteToday(const std::string& name)
-{
- if (time_dep_attrs_) {
- time_dep_attrs_->deleteToday(name);
- return;
- }
- throw std::runtime_error("Node::delete_today: Can not find today attribute: ");
-}
-
-void Node::delete_today(const ecf::TodayAttr& attr)
-{
- if (time_dep_attrs_) {
- time_dep_attrs_->delete_today(attr);
- return;
- }
- throw std::runtime_error("Node::delete_today: Can not find today attribute: " + attr.toString());
-}
-
-void Node::deleteDate(const std::string& name)
-{
- if (time_dep_attrs_) {
- time_dep_attrs_->deleteDate(name);
- return;
- }
- throw std::runtime_error("Node::delete_date: Can not find date attribute: ");
-}
-
-void Node::delete_date(const DateAttr& attr)
-{
- if (time_dep_attrs_) {
- time_dep_attrs_->delete_date(attr);
- return;
- }
- throw std::runtime_error("Node::delete_date: Can not find date attribute: " + attr.toString());
-}
-
-void Node::deleteDay(const std::string& name)
-{
- if (time_dep_attrs_) {
- time_dep_attrs_->deleteDay(name);
- return;
- }
- throw std::runtime_error("Node::delete_day: Can not find day attribute: ");
-}
-
-void Node::delete_day(const DayAttr& attr)
-{
- if (time_dep_attrs_) {
- time_dep_attrs_->delete_day(attr);
- return;
- }
- throw std::runtime_error("Node::delete_day: Can not find day attribute: " + attr.toString());
-}
-
-void Node::deleteCron(const std::string& name)
-{
- if (time_dep_attrs_) {
- time_dep_attrs_->deleteCron(name);
- return;
- }
- throw std::runtime_error("Node::delete_cron: Can not find cron attribute: ");
-}
-
-void Node::delete_cron(const ecf::CronAttr& attr)
-{
- if (time_dep_attrs_) {
- time_dep_attrs_->delete_cron(attr);
- return;
- }
- throw std::runtime_error("Node::delete_cron: Can not find cron attribute: " + attr.toString());
-}
-
-void Node::deleteVariable( const std::string& name)
-{
- if (name.empty()) {
- varVec_.clear(); // delete all
- state_change_no_ = Ecf::incr_state_change_no();
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Node::deleteVariable\n";
-#endif
- return;
- }
-
- size_t theSize = varVec_.size();
- for(size_t i = 0; i < theSize; i++) {
- if (varVec_[i].name() == name) {
- varVec_.erase( varVec_.begin() + i );
- state_change_no_ = Ecf::incr_state_change_no();
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Node::deleteVariable\n";
-#endif
- return;
- }
- }
- throw std::runtime_error("Node::deleteVariable: Can not find variable of name " + name);
-}
-
-void Node::deleteEvent(const std::string& name)
-{
- if (child_attrs_) {
- child_attrs_->deleteEvent(name);
- return;
- }
- throw std::runtime_error("Node::deleteEvent: Can not find event: " + name);
-}
-
-void Node::deleteMeter(const std::string& name)
-{
- if (child_attrs_) {
- child_attrs_->deleteMeter(name);
- return;
- }
- throw std::runtime_error("Node::deleteMeter: Can not find meter: " + name);
-}
-
-void Node::deleteLabel(const std::string& name)
-{
- if (child_attrs_) {
- child_attrs_->deleteLabel(name);
- return;
- }
- throw std::runtime_error("Node::deleteLabel: Can not find label: " + name);
-}
-
-void Node::deleteTrigger()
-{
- if (triggerExpr_) {
- delete triggerExpr_; triggerExpr_ = NULL;
- state_change_no_ = Ecf::incr_state_change_no();
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Node::deleteTrigger()\n";
-#endif
- }
-}
-
-void Node::deleteComplete()
-{
- if (completeExpr_) {
- delete completeExpr_; completeExpr_ = NULL;
- state_change_no_ = Ecf::incr_state_change_no();
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Node::deleteComplete()\n";
-#endif
- }
-}
-
-void Node::deleteRepeat()
-{
- if (!repeat_.empty()) {
- repeat_.clear(); // will delete the pimple
- state_change_no_ = Ecf::incr_state_change_no();
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Node::deleteRepeat())\n";
-#endif
- }
-}
-
-void Node::deleteLimit(const std::string& name)
-{
- if (name.empty()) {
- limitVec_.clear();
- state_change_no_ = Ecf::incr_state_change_no();
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Node::deleteLimit\n";
-#endif
- return;
- }
-
- size_t theSize = limitVec_.size();
- for(size_t i = 0; i < theSize; i++) {
- if (limitVec_[i]->name() == name) {
- limitVec_.erase( limitVec_.begin() + i );
- state_change_no_ = Ecf::incr_state_change_no();
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Node::deleteLimit\n";
-#endif
- return;
- }
- }
- throw std::runtime_error("Node::deleteLimit: Can not find limit: " + name);
-}
-
-void Node::delete_limit_path(const std::string& name,const std::string& path)
-{
- if (name.empty()) {
- throw std::runtime_error("Node::delete_limit_path: the limit name must be provided");
- }
- if (path.empty()) {
- throw std::runtime_error("Node::delete_limit_path: the limit path must be provided");
- }
-
- size_t theSize = limitVec_.size();
- for(size_t i = 0; i < theSize; i++) {
- if (limitVec_[i]->name() == name) {
- limitVec_[i]->delete_path(path); // will update state change no
- return;
- }
- }
- throw std::runtime_error("Node::delete_limit_path: Can not find limit: " + name);
-}
-
-void Node::deleteInlimit(const std::string& name)
-{
- // if name exists but no corresponding in limit found raises an exception
- if (inLimitMgr_.deleteInlimit(name)) {
- state_change_no_ = Ecf::incr_state_change_no();
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Node::deleteInlimit\n";
-#endif
- }
-}
-
-void Node::deleteZombie(const std::string& zombie_type)
-{
- if (misc_attrs_) misc_attrs_->deleteZombie(zombie_type);
-}
-
-void Node::delete_zombie(Child::ZombieType zt)
-{
- if (misc_attrs_) misc_attrs_->delete_zombie(zt);
-}
diff --git a/ecflow_4_0_7/ANode/src/NodeFind.cpp b/ecflow_4_0_7/ANode/src/NodeFind.cpp
deleted file mode 100644
index 3371344..0000000
--- a/ecflow_4_0_7/ANode/src/NodeFind.cpp
+++ /dev/null
@@ -1,738 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #53 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "Node.hpp"
-#include "Str.hpp"
-#include "NodePath.hpp"
-#include "Defs.hpp"
-#include "Log.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-
-/// Output a vector to cout
-template<class T>
-ostream& operator<<(ostream& os, const vector<T>& v)
-{
- copy(v.begin(), v.end(), ostream_iterator<T>(cout, " "));
- return os;
-}
-
-bool Node::findParentVariableValue(const std::string& name, std::string& theValue) const
-{
- if (findVariableValue(name,theValue)) return true;
- const Repeat& repeat = findRepeat(name);
- if (!repeat.empty()) { theValue = repeat.valueAsString(); return true; }
- if (findGenVariableValue(name,theValue)) return true;
-
-
- Node* theParent = parent();
- while (theParent) {
-
- if (theParent->findVariableValue(name,theValue)) return true;
- const Repeat& repeatVar = theParent->findRepeat(name);
- if (!repeatVar.empty()) { theValue = repeatVar.valueAsString(); return true; }
- if (theParent->findGenVariableValue(name,theValue)) return true;
-
- theParent = theParent->parent();
- }
-
- // If all else fails search defs environment, returns empty string if match not found
- // The defs environment is constructed via:
- // o/ default settings for ECF_HOME,ECF_LOG, ECF_CHECK,ECF_CHECKOLD,ECF_CHECKINTERVAL
- // ECF_INTERVAL ECF_CHECKMODE ECF_JOB_CMD ECF_MICRO ECF_TRIES ECF_PORT, ECF_NODE
- // o/ These values are updated from the server environment when the BEGIN cmd is called.
- theValue = defs()->server().find_variable(name);
- if ( !theValue.empty() ) return true;
- return false; // the variable can not be found
-}
-
-bool Node::find_parent_gen_variable_value(const std::string& name, std::string& theValue) const
-{
- if (findGenVariableValue(name,theValue)) return true;
-
- Node* theParent = parent();
- while (theParent) {
- if (theParent->findGenVariableValue(name,theValue)) return true;
- theParent = theParent->parent();
- }
-
- // If all else fails search defs environment, returns empty string if match not found
- // The defs environment is constructed via:
- // o/ default settings for ECF_HOME,ECF_LOG, ECF_CHECK,ECF_CHECKOLD,ECF_CHECKINTERVAL
- // ECF_INTERVAL ECF_CHECKMODE ECF_JOB_CMD ECF_MICRO ECF_TRIES ECF_PORT, ECF_NODE
- // o/ These values are updated from the server environment when the BEGIN cmd is called.
- theValue = defs()->server().find_variable(name);
- if ( !theValue.empty() ) return true;
- return false; // the variable can not be found
-}
-
-bool Node::findParentUserVariableValue(const std::string& name, std::string& theValue) const
-{
- if (findVariableValue(name,theValue)) return true;
-
- Node* theParent = parent();
- while (theParent) {
- if (theParent->findVariableValue(name,theValue)) return true;
- theParent = theParent->parent();
- }
-
- // If all else fails search defs environment, returns empty string if match not found
- theValue = defs()->server().find_variable(name);
- if ( !theValue.empty() ) return true;
- return false; // the variable can not be found
-}
-
-const std::string& Node::find_parent_user_variable_value(const std::string& name) const
-{
- const Variable& var = findVariable(name);
- if (!var.empty()) return var.theValue();
-
- Node* theParent = parent();
- while (theParent) {
- const Variable& pvar = theParent->findVariable(name);
- if (!pvar.empty()) return pvar.theValue();
- theParent = theParent->parent();
- }
-
- // If all else fails search defs environment, returns empty string if match not found
- return defs()->server().find_variable(name);
-}
-
-bool Node::user_variable_exists(const std::string& name) const
-{
- const Variable& var = findVariable(name);
- if (!var.empty()) return true;
-
- Node* theParent = parent();
- while (theParent) {
- const Variable& pvar = theParent->findVariable(name);
- if (!pvar.empty()) return true;
- theParent = theParent->parent();
- }
-
- // If all else fails search defs environment, returns empty string if match not found
- return defs()->server().variable_exists(name);
-}
-
-const Variable& Node::findVariable(const std::string& name) const
-{
- size_t theSize = varVec_.size();
- for(size_t i = 0; i < theSize; i++) {
- if (varVec_[i].name() == name) {
- return varVec_[i];
- }
- }
- return Variable::EMPTY();
-}
-
-bool Node::findVariableValue( const std::string& name, std::string& returnedValue) const
-{
- const Variable& var = findVariable(name);
- if (!var.empty()) {
- returnedValue = var.theValue();
- return true;
- }
- return false;
-}
-
-bool Node::findGenVariableValue( const std::string& name, std::string& returnedValue) const
-{
- const Variable& genVar = findGenVariable(name);
- if (!genVar.empty()) {
- returnedValue = genVar.theValue();
- return true;
- }
- return false;
-}
-
-
-bool Node::findLimit(const Limit& theLimit) const
-{
- size_t theSize = limitVec_.size();
- for(size_t i = 0; i < theSize; i++) {
- if (limitVec_[i]->name() == theLimit.name()) {
- return true;
- }
- }
- return false;
-}
-
-limit_ptr Node::find_limit(const std::string& theName) const
-{
- size_t theSize = limitVec_.size();
- for(size_t i = 0; i < theSize; i++) {
- if (limitVec_[i]->name() == theName) {
- return limitVec_[i];
- }
- }
- return limit_ptr();
-}
-
-limit_ptr Node::findLimitUpNodeTree(const std::string& name) const
-{
- limit_ptr theFndLimit = find_limit(name);
- if (theFndLimit.get()) return theFndLimit;
-
- Node* theParent = parent();
- while (theParent != NULL) {
-
- limit_ptr theFndLimit = theParent->find_limit(name);
- if (theFndLimit.get()) return theFndLimit;
-
- theParent = theParent->parent();
- }
- return limit_ptr();
-}
-
-
-const Event& Node::findEvent(const Event& theEvent) const
-{
- if (child_attrs_) return child_attrs_->findEvent(theEvent);
- return Event::EMPTY();
-}
-
-const Event& Node::findEventByNumber(int number) const
-{
- if (child_attrs_) return child_attrs_->findEventByNumber(number);
- return Event::EMPTY();
-}
-
-const Event& Node::findEventByName( const std::string& event_name) const
-{
- if (child_attrs_) return child_attrs_->findEventByName(event_name);
- return Event::EMPTY();
-}
-
-const Event& Node::findEventByNameOrNumber( const std::string& theName) const
-{
- if (child_attrs_) return child_attrs_->findEventByNameOrNumber(theName);
- return Event::EMPTY();
-}
-const Meter& Node::findMeter(const std::string& name) const
-{
- if (child_attrs_) return child_attrs_->findMeter(name);
- return Meter::EMPTY();
-}
-
-Meter& Node::find_meter(const std::string& name)
-{
- if (child_attrs_) return child_attrs_->find_meter(name);
- return const_cast<Meter&>(Meter::EMPTY());
-}
-
-bool Node::findLabel(const std::string& name) const
-{
- if (child_attrs_) return child_attrs_->findLabel(name);
- return false;
-}
-
-const Label& Node::find_label(const std::string& name) const
-{
- if (child_attrs_) return child_attrs_->find_label(name);
- return Label::EMPTY();
-}
-
-bool Node::findVerify(const VerifyAttr& v) const
-{
- if (misc_attrs_) return misc_attrs_->findVerify(v);
- return false;
-}
-
-const Repeat& Node::findRepeat(const std::string& name) const
-{
- if (!repeat_.empty() && repeat_.name() == name) {
- return repeat_;
- }
- return Repeat::EMPTY();
-}
-
-
-bool Node::findExprVariable( const std::string& name)
-{
- // if event found return true. also mark this event so simulator know its used in a trigger
- if ( set_event_used_in_trigger(name) ) {
- return true;
- }
-
- // if meter found mark as used in trigger for simulator and return
- if ( set_meter_used_in_trigger(name) ) {
- return true;
- }
-
- const Variable& user_variable = findVariable( name );
- if (!user_variable.empty()) return true;
-
- const Repeat& repeat = findRepeat( name );
- if (!repeat.empty()) return true;
-
- const Variable& gen_variable = findGenVariable( name );
- if (!gen_variable.empty()) return true;
-
- return false;
-}
-
-int Node::findExprVariableValue( const std::string& name) const
-{
- const Event& event = findEventByNameOrNumber( name );
- if ( !event.empty() ) return (event.value() ? 1 : 0);
-
- const Meter& meter = findMeter( name );
- if ( !meter.empty() ) return meter.value();
-
- const Variable& variable = findVariable( name );
- if ( !variable.empty() ) return variable.value();
-
- const Repeat& repeat = findRepeat( name );
- if ( !repeat.empty() ) {
- // RepeatDate last_valid_value() returns the date by its real value as a long
- // RepeatInteger last_valid_value() returns the value, by the current value of integer
- // RepeatEnumerated last_valid_value() returns the current value if cast-able to integer otherwise position/index,
- // (i.e. since enum can be anything)
- // RepeatString last_valid_value() returns the current position/index ( Alternatives ? )
- // RepeatDay last_valid_value() returns the current step
- // Note: At Repeat expiration Repeat::value() may be out of range of start-end
- // But Repeat::last_valid_value() should always be in range, hence at Repeat expiration
- // will return the last valid value.
- return repeat.last_valid_value();
- }
-
- const Variable& gen_variable = findGenVariable( name );
- if ( !gen_variable.empty() ) return gen_variable.value();
- return 0;
-}
-
-int Node::findExprVariableValueAndPlus(const std::string& name, int val) const
-{
- const Event& event = findEventByNameOrNumber( name );
- if ( !event.empty() ) return ((event.value() ? 1 : 0) + val);
-
- const Meter& meter = findMeter( name );
- if ( !meter.empty() ) return (meter.value() + val);
-
- const Variable& variable = findVariable( name );
- if ( !variable.empty() ) return (variable.value() + val);
-
- const Repeat& repeat = findRepeat( name );
- if ( !repeat.empty() ) {
- // RepeatDate last_valid_value() returns the date by its real value as a long
- // RepeatInteger last_valid_value() returns the value, by the current value of integer
- // RepeatEnumerated last_valid_value() returns the current value if cast-able as integer otherwise position/index,
- // (i.e. since enum can be anything)
- // RepeatString last_valid_value() returns the current position/index ( Alternatives ? )
- // RepeatDay last_valid_value() returns the current step
- // Note: At Repeat expiration Repeat::value() may be out of range of start-end
- // But Repeat::last_valid_value() should always be in range, hence at Repeat expiration
- // will return the last valid value.
- return repeat.last_valid_value_plus(val);
- }
-
- const Variable& gen_variable = findGenVariable( name );
- if ( !gen_variable.empty() ) return (gen_variable.value()+val);
- return val;
-}
-
-int Node::findExprVariableValueAndMinus(const std::string& name, int val) const
-{
- const Event& event = findEventByNameOrNumber( name );
- if ( !event.empty() ) return ( (event.value() ? 1 : 0) - val);
-
- const Meter& meter = findMeter( name );
- if ( !meter.empty() ) return (meter.value() - val );
-
- const Variable& variable = findVariable( name );
- if ( !variable.empty() ) return (variable.value() - val);
-
- const Repeat& repeat = findRepeat( name );
- if ( !repeat.empty() ) {
- // RepeatDate last_valid_value() returns the date by its real value as a long
- // RepeatInteger last_valid_value() returns the value, by the current value of integer
- // RepeatEnumerated last_valid_value() returns the current value if cast-able as integer, else position/index, (
- // i.e. since enum can be anything)
- // RepeatString last_valid_value() returns the current position/index ( Alternatives ? )
- // RepeatDay last_valid_value() returns the current step
- // Note: At Repeat expiration Repeat::value() may be out of range of start-end
- // But Repeat::last_valid_value() should always be in range, hence at Repeat expiration
- // will return the last valid value.
- return repeat.last_valid_value_minus(val);
- }
-
- const Variable& gen_variable = findGenVariable( name );
- if ( !gen_variable.empty() ) return (gen_variable.value() - val);
- return -val;
-}
-
-int Node::findExprVariableValueAndType( const std::string& name, std::string& varType) const
-{
- const Event& event = findEventByNameOrNumber( name );
- if ( !event.empty() ) {
- varType = "event";
- return (event.value() ? 1 : 0);
- }
- const Meter& meter = findMeter( name );
- if ( !meter.empty() ) {
- varType = "meter";
- return meter.value();
- }
- const Variable& variable = findVariable( name );
- if ( !variable.empty() ) {
- varType = "user-variable";
- return variable.value();
- }
- const Repeat& repeat = findRepeat( name );
- if ( !repeat.empty() ) {
- varType = "repeat";
- return repeat.last_valid_value();
- }
- const Variable& gen_variable = findGenVariable( name );
- if ( !gen_variable.empty() ) {
- varType = "gen-variable";
- return gen_variable.value();
- }
- varType = "variable-not-found";
- return 0;
-}
-
-void Node::findExprVariableAndPrint( const std::string& name, ostream& os) const
-{
- const Event& event = findEventByNameOrNumber( name );
- if ( !event.empty() ) {
- os << event.dump();
- return;
- }
- const Meter& meter = findMeter( name );
- if ( !meter.empty() ) {
- os << meter.dump();
- return;
- }
- const Variable& variable = findVariable( name );
- if ( !variable.empty() ) {
- os << "USER-VARIABLE " << variable.dump();
- return;
- }
- const Repeat& repeat = findRepeat( name );
- if ( !repeat.empty() ) {
- os << repeat.dump();
- return;
- }
- const Variable& gen_variable = findGenVariable( name );
- if ( !gen_variable.empty() ) {
- os << "GEN-VARIABLE " << gen_variable.dump();
- return;
- }
-}
-
-
-node_ptr findRelativeNode( const vector<std::string>& theExtractedPath,node_ptr triggerNode, std::string& errorMsg )
-{
- // The referenced node could be itself(error) or most likely a sibling node.
- int extractedPathSize = static_cast<int>(theExtractedPath.size());
- if (extractedPathSize == 1 && triggerNode->name() == theExtractedPath[0]) {
- // self referencing node ?
- return triggerNode;
- }
-
- // Can only find *sibling* if triggerNode has a parent
- if (!triggerNode->parent()) {
- errorMsg = "Parent empty. Could not find referenced node\n";
- return node_ptr();
- }
- if (extractedPathSize == 1) {
- size_t child_pos; // not used
- node_ptr theNode = triggerNode->parent()->findImmediateChild(theExtractedPath[0],child_pos);
- if ( theNode.get() ) {
- return theNode;
- }
- }
-
- node_ptr constNode = triggerNode->parent()->find_relative_node(theExtractedPath);
- if (constNode.get()) {
- return constNode;
- }
-
- errorMsg = "Could not find node '";
- if (extractedPathSize == 1) errorMsg += theExtractedPath[0];
- else { BOOST_FOREACH(const string& s, theExtractedPath) { errorMsg += s; errorMsg += Str::PATH_SEPERATOR();} }
- errorMsg += "' from node ";
- errorMsg += triggerNode->absNodePath();
- if (extractedPathSize == 1) {
- errorMsg += " . Expected '";
- errorMsg += theExtractedPath[0];
- errorMsg += "' to be a sibling.";
- }
- errorMsg += "\n";
- return node_ptr();
-}
-
-
-node_ptr Node::non_const_this() const {
- return const_pointer_cast<Node>(shared_from_this());
-}
-
-node_ptr Node::findReferencedNode(const std::string& nodePath, std::string& errorMsg) const
-{
- return findReferencedNode(nodePath,Str::EMPTY(),errorMsg);
-}
-node_ptr Node::findReferencedNode(const std::string& nodePath, const std::string& extern_obj, std::string& errorMsg) const
-{
- Defs* theDefs = defs();
- if (!theDefs) {
- // In the case where we have a stand alone Node. i.e no parent set. The Defs will be NULL.
- // Take the case where we want to dump the state of a single node.
- // ecflow_client --get_state /test/f2 --port=4141
- // Here we are printing the state of the Node only, *NO* defs is returned.
- // The print will cause the AST to be evaluated. The trigger evaluation will required chasing
- // down reference nodes. Hence we will end up here. Rather than crashing, just return a NULL Pointer.
- return node_ptr();
- }
-
- /// findReferencedNode:: is used to locate references:
- /// a/ Trigger & complete expressions, this is where extern_obj is used.
- /// b/ Inlimit nodepaths.
- /// In *both* the case above, the node path may not exist, in the definition. Hence::
- /// On client side:: references not defined in externs are considered errors
- /// On server side:: No extern's are stored, hence for unresolved node paths, we return NULL
-
-#ifdef DEBUG_FIND_REFERENCED_NODE
- string debug_path = "Searching for path " + nodePath + " from " + debugType() + Str::COLON() + absNodePath() + "\n";
-#endif
-
- // if an absolute path cut in early
- if (!nodePath.empty() && nodePath[0] == '/') {
-
-#ifdef DEBUG_FIND_REFERENCED_NODE
- debug_path += "(!nodePath.empty() && nodePath[0] == '/') \n";
-#endif
-
- // Must be a absolute path. i.e /suite/family/path
- node_ptr constNode = theDefs->findAbsNode(nodePath);
- if (constNode.get()) {
- return constNode;
- }
-
- // *NOTE*: The server does *NOT* store externs, hence the check below, will always return false, for the server:
- // Must be an extern:
- // extern /referenceSuite/family/task:obj
- // extern /referenceSuite/family/task
- if (theDefs->find_extern(nodePath,extern_obj)) {
-
- // =================================================================
- // **Client side* specific: Only client side defs, stores extrens
- // =================================================================
-#ifdef DEBUG_FIND_REFERENCED_NODE
- debug_path += "theDefs->find_extern(nodePath) \n";
-#endif
-
- // return NULL *without* setting an error message as node path is defined as an extern
-
- // OK: the node path appears in the extern list. This may be because that suite has not been loaded.
- // *** If the suite is loaded, then its an error that we did not
- // *** locate the node. i.e in the previous call to defs->findAbsNode(nodePath);
- vector<string> theExtractedPath;
- NodePath::split(nodePath, theExtractedPath );
-
- std::string referenceSuite = theExtractedPath[0];
- if (theDefs->findSuite(referenceSuite)) {
- // The suite referenced in the extern is LOADED, but path did not resolve,
- // in previous call to defs->findAbsNode(nodePath);
- errorMsg = "Extern path ";
- errorMsg += nodePath;
- errorMsg += " does not exist on suite ";
- errorMsg += referenceSuite;
- errorMsg += "\n";
-#ifdef DEBUG_FIND_REFERENCED_NODE
- errorMsg += debug_path;
-#endif
- }
-
- // Its an extern path that references a suite thats NOT loaded yet
- return node_ptr();
- }
-
- errorMsg = ": Could not find referenced node, using absolute path '";
- errorMsg += nodePath;
- errorMsg += "\n";
- return node_ptr();
- }
-
- /// =============================================================================
- /// Path is something other than ABSOLUTE path
- /// =============================================================================
- vector<string> theExtractedPath;
- NodePath::split( nodePath, theExtractedPath );
-
-#ifdef DEBUG_FIND_REFERENCED_NODE
- debug_path += "extracted path = ";
- BOOST_FOREACH(const string& s, theExtractedPath) { debug_path += ",";debug_path += s;}
- debug_path += "\n";
-#endif
-
- if ( theExtractedPath.empty() ) {
- std::stringstream ss;
- ss << ": Could not find referenced node '" << nodePath << "' from node " << absNodePath() << "\n";
- errorMsg = ss.str();
-#ifdef DEBUG_FIND_REFERENCED_NODE
- errorMsg += debug_path;
-#endif
- return node_ptr();
- }
-
-
- // i.e " a == complete" =====> nodePath = a
- if ( theExtractedPath.size() == 1) {
-#ifdef DEBUG_FIND_REFERENCED_NODE
- debug_path += "( theExtractedPath.size() == 1)\n";
-#endif
- // Search for a relative node first
- string localErrorMsg;
- node_ptr res = findRelativeNode(theExtractedPath,non_const_this(),localErrorMsg);
-#ifdef DEBUG_FIND_REFERENCED_NODE
- if (!localErrorMsg.empty()) {
- debug_path += localErrorMsg;
- localErrorMsg = debug_path;
- }
-#endif
-
- if (!res.get()) {
- // lets see if its in an extern Node. extern can have absolute and relative paths
- // In this case it will be a relative path, hence no point trying to see if suite
- // is loaded
- if (theDefs->find_extern(nodePath,extern_obj)) {
- // =================================================================
- // **Client side* specific: Only client side defs, stores externs
- // =================================================================
- // The path exist in the extern and we know its relative
- return node_ptr();
- }
- }
-
- errorMsg += localErrorMsg;
- return res;
- }
-
- // handle Node path of type a/b/c
- if (theExtractedPath.size() >= 2 && theExtractedPath[0] != "." && theExtractedPath[0] != "..") {
-#ifdef DEBUG_FIND_REFERENCED_NODE
- debug_path += "(theExtractedPath.size() >= 2 && theExtractedPath[0] != \".\") && theExtractedPath[0] != \"..\"\n";
-#endif
- // First check to see see if its in the externs
- if (theDefs->find_extern(nodePath,extern_obj)) {
- // =================================================================
- // **Client side* specific: Only client side defs, stores externs
- // =================================================================
- // The path a/b/c exist in the extern and we know its relative
- // Again no point in checking to see if suite is loaded if path is relative
- return node_ptr();
- }
-
- // In this case its equivalent to: ./a/b/c
- theExtractedPath.insert(theExtractedPath.begin(),".");
- }
-
- // node path == "./a"
- if ( theExtractedPath.size() >= 2 && theExtractedPath[0] == ".") {
-#ifdef DEBUG_FIND_REFERENCED_NODE
- debug_path += "theExtractedPath.size() == 2 && theExtractedPath[0] == \".\" \n";
-#endif
- theExtractedPath.erase( theExtractedPath.begin() + 0);
- node_ptr res = findRelativeNode(theExtractedPath,non_const_this(),errorMsg);
-#ifdef DEBUG_FIND_REFERENCED_NODE
- if (!errorMsg.empty()) {
- debug_path += errorMsg;
- errorMsg = debug_path;
- }
-#endif
- return res;
- }
-
- // ********************************************************************
- // Note ./ This means go to the parent, then search down, i.e sibling
- // ../ This means go to the parents parent
- // This may be confusing, but this is how Axel expects it, hence I will use
- // the same understanding
- // **********************************************************************
- // Handle node path of the type "../a/b/c" "../../a/b/c"
- if ( theExtractedPath.size() >= 2 && theExtractedPath[0] == "..") {
-
-#ifdef DEBUG_FIND_REFERENCED_NODE
- debug_path += "( theExtractedPath.size() >= 2 && theExtractedPath[0] == \"..\")\n";
-#endif
-
- Node* theParent = parent(); // get past the first parent
- while ( static_cast<int>(theExtractedPath.size()) &&
- theParent &&
- theExtractedPath[0] == ".." )
- {
- theExtractedPath.erase( theExtractedPath.begin() + 0);
- theParent = theParent->parent(); // for each .. go up a parent
-#ifdef DEBUG_FIND_REFERENCED_NODE
- debug_path += "..: thepParent = ";
- if (theParent) debug_path += theParent->absNodePath();
- else debug_path += "NULL";
-#endif
- }
-
- if ( theParent ) {
-
-#ifdef DEBUG_FIND_REFERENCED_NODE
- debug_path += "searching = " + theParent->name() + "\n";
- BOOST_FOREACH(const std::string& s , theExtractedPath) { debug_path += Str::PATH_SEPERATOR() + s; }
- debug_path += "\n";
-#endif
-
- node_ptr constNode = theParent->find_relative_node(theExtractedPath);
- if (constNode) {
- return constNode;
- }
- }
- }
-
- errorMsg = "Unrecognised path ";
- errorMsg += nodePath;
- errorMsg += " for Node ";
- errorMsg += absNodePath();
- errorMsg += "\n";
-#ifdef DEBUG_FIND_REFERENCED_NODE
- errorMsg += debug_path;
-#endif
- return node_ptr();
-}
-
-const ZombieAttr& Node::findZombie( ecf::Child::ZombieType zombie_type) const
-{
- if (misc_attrs_) return misc_attrs_->findZombie(zombie_type);
- return ZombieAttr::EMPTY();
-}
-
-bool Node::findParentZombie(ecf::Child::ZombieType z_type, ZombieAttr& z) const
-{
- const ZombieAttr& the_zombie = findZombie(z_type);
- if ( !the_zombie.empty() ) {
- z = the_zombie;
- return true;
- }
-
- Node* theParent = parent();
- while (theParent) {
- const ZombieAttr& the_zombie = theParent->findZombie(z_type);
- if ( !the_zombie.empty() ) {
- z = the_zombie;
- return true;
- }
- theParent = theParent->parent();
- }
- return false;
-}
diff --git a/ecflow_4_0_7/ANode/src/NodeFwd.hpp b/ecflow_4_0_7/ANode/src/NodeFwd.hpp
deleted file mode 100644
index 3aae9de..0000000
--- a/ecflow_4_0_7/ANode/src/NodeFwd.hpp
+++ /dev/null
@@ -1,107 +0,0 @@
-#ifndef NODE_FWD_HPP_
-#define NODE_FWD_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #44 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/shared_ptr.hpp>
-#include <boost/weak_ptr.hpp>
-#include <vector>
-#include <string>
-#include <map>
-
-class AbstractObserver;
-class Suite;
-class Family;
-class Task;
-class Alias;
-class Submittable;
-class Node;
-class Defs;
-class Repeat;
-class Expression;
-class Memento;
-class CompoundMemento;
-class ClockAttr;
-class JobCreationCtrl;
-class Event;
-class Meter;
-class Repeat;
-class Variable;
-
-namespace ecf { class LateAttr; class AutoCancelAttr; } // forward declare class
-
-typedef boost::shared_ptr<Memento> memento_ptr;
-typedef boost::shared_ptr<CompoundMemento> compound_memento_ptr;
-typedef boost::shared_ptr<ClockAttr> clock_ptr;
-
-typedef boost::shared_ptr<JobCreationCtrl> job_creation_ctrl_ptr;
-typedef boost::shared_ptr<Node> node_ptr;
-typedef boost::shared_ptr<Task> task_ptr;
-typedef boost::shared_ptr<Alias> alias_ptr;
-typedef boost::shared_ptr<Submittable> submittable_ptr;
-typedef boost::shared_ptr<Family> family_ptr;
-typedef boost::shared_ptr<Suite> suite_ptr;
-typedef boost::shared_ptr<Defs> defs_ptr;
-
-typedef boost::weak_ptr<Defs> weak_defs_ptr;
-typedef boost::weak_ptr<Suite> weak_suite_ptr;
-typedef boost::weak_ptr<Task> weak_task_ptr;
-typedef boost::weak_ptr<Alias> weak_alias_ptr;
-typedef boost::weak_ptr<Submittable> weak_submittable_ptr;
-typedef boost::weak_ptr<Node> weak_node_ptr;
-
-typedef std::map<std::string,std::string> NameValueMap;
-
-typedef std::vector< std::pair< std::string,std::string> > NameValueVec;
-
-
-class NodeContainer;
-class DefsDelta;
-class JobsParam;
-class JobCreationCtrl;
-class AstTop;
-
-class StateMemento;
-class NodeDefStatusDeltaMemento;
-class SuspendedMemento;
-class ServerStateMemento;
-class ServerVariableMemento;
-class NodeEventMemento;
-class NodeMeterMemento;
-class NodeLabelMemento;
-class NodeTriggerMemento;
-class NodeCompleteMemento;
-class NodeRepeatMemento;
-class NodeLimitMemento;
-class NodeInLimitMemento;
-class NodeVariableMemento;
-class NodeLateMemento;
-class NodeTodayMemento;
-class NodeTimeMemento;
-class NodeDayMemento;
-class NodeCronMemento;
-class NodeDateMemento;
-class NodeZombieMemento;
-class NodeVerifyMemento;
-class FlagMemento;
-class SubmittableMemento;
-class SuiteClockMemento;
-class SuiteBeginDeltaMemento;
-class SuiteCalendarMemento;
-class OrderMemento;
-class ChildrenMemento;
-class AliasChildrenMemento;
-class AliasNumberMemento;
-
-#endif
diff --git a/ecflow_4_0_7/ANode/src/NodeMemento.cpp b/ecflow_4_0_7/ANode/src/NodeMemento.cpp
deleted file mode 100644
index 430c941..0000000
--- a/ecflow_4_0_7/ANode/src/NodeMemento.cpp
+++ /dev/null
@@ -1,585 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #48 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/make_shared.hpp>
-
-#include "Suite.hpp"
-#include "Ecf.hpp"
-#include "DefsDelta.hpp"
-#include "ExprAst.hpp"
-#include "Stl.hpp"
-#include "ChangeMgrSingleton.hpp"
-
-using namespace ecf;
-using namespace std;
-
-//#define DEBUG_MEMENTO 1
-
-/// CompoundMemento relies all clearing all attributes
-void Node::clear()
-{
- delete lateAttr_; lateAttr_ = NULL;
- delete completeExpr_; completeExpr_ = NULL;
- delete triggerExpr_; triggerExpr_ = NULL;
-
- // ************************************************************
- // Note: auto cancel does not have any changeable state
- // Hence it is not cleared. Hence no need for memento
- // ************************************************************
-
- if (time_dep_attrs_) time_dep_attrs_->clear();
- if (child_attrs_) child_attrs_->clear();
- if (misc_attrs_) misc_attrs_->clear(); // zombies can be added/removed via AlterCmd
- repeat_.clear();
- varVec_.clear();
- limitVec_.clear();
- inLimitMgr_.clear();
-}
-
-void Node::incremental_changes( DefsDelta& changes, compound_memento_ptr& comp) const
-{
-#ifdef DEBUG_MEMENTO
- std::cout << "Node::incremental_changes(DefsDelta& changes) " << debugNodePath() << "\n";
-#endif
-
- unsigned int client_state_change_no = changes.client_state_change_no();
-
- // determine if state changed
- if (state_.first.state_change_no() > client_state_change_no) {
- if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
- comp->add( boost::make_shared<StateMemento>( state_.first.state()) );
- }
-
- // determine if def status changed
- if (defStatus_.state_change_no() > client_state_change_no) {
- if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
- comp->add( boost::make_shared<NodeDefStatusDeltaMemento>( defStatus_.state()) );
- }
-
- // determine if node suspend changed
- if (suspended_change_no_ > client_state_change_no) {
- if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
- comp->add( boost::make_shared<SuspendedMemento>( suspended_) );
- }
-
- // Determine if node attributes DELETED or ADDED, We copy **all** internal state
- // When applying on the client side, we clear all node attributes( ie Node::clear())
- // and re-add
- if (state_change_no_ > client_state_change_no) {
-
- /// *****************************************************************************************
- /// Node attributes DELETED or ADDED, i.e we call comp->clear_attributes()
- /// *****************************************************************************************
-
-#ifdef DEBUG_MEMENTO
- std::cout << " Node::incremental_changes() Attributes added or deleted\n";
-#endif
- // Note: auto-cancel does not have any alterable state hence, *NO* memento
-
- if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
- comp->clear_attributes();
-
- if (child_attrs_) {
- const std::vector<Meter>& meter_attrs = child_attrs_->meters();
- BOOST_FOREACH(const Meter& m, meter_attrs ) { comp->add( boost::make_shared<NodeMeterMemento>( m) ); }
-
- const std::vector<Event>& event_attrs = child_attrs_->events();
- BOOST_FOREACH(const Event& e, event_attrs ) { comp->add( boost::make_shared<NodeEventMemento>( e) ); }
-
- const std::vector<Label>& label_attrs = child_attrs_->labels();
- BOOST_FOREACH(const Label& l, label_attrs ) { comp->add( boost::make_shared<NodeLabelMemento>( l) ); }
- }
- if (time_dep_attrs_) {
- const std::vector<ecf::TodayAttr>& today_attrs = time_dep_attrs_->todayVec();
- BOOST_FOREACH(const ecf::TodayAttr& attr, today_attrs){ comp->add( boost::make_shared<NodeTodayMemento>( attr) ); }
-
- const std::vector<ecf::TimeAttr>& time_attrs = time_dep_attrs_->timeVec();
- BOOST_FOREACH(const ecf::TimeAttr& attr, time_attrs ) { comp->add( boost::make_shared<NodeTimeMemento>( attr) ); }
-
- const std::vector<DayAttr>& day_attrs = time_dep_attrs_->days();
- BOOST_FOREACH(const DayAttr& attr, day_attrs ) { comp->add( boost::make_shared<NodeDayMemento>( attr) ); }
-
- const std::vector<DateAttr>& dates_attrs = time_dep_attrs_->dates();
- BOOST_FOREACH(const DateAttr& attr, dates_attrs ) { comp->add( boost::make_shared<NodeDateMemento>( attr) ); }
-
- const std::vector<ecf::CronAttr>& cron_attrs = time_dep_attrs_->crons();
- BOOST_FOREACH(const CronAttr& attr, cron_attrs ) { comp->add( boost::make_shared<NodeCronMemento>( attr) ); }
- }
- if (misc_attrs_) {
- const std::vector<VerifyAttr>& verify_attrs = misc_attrs_->verifys();
- if (!verify_attrs.empty()) comp->add( boost::make_shared<NodeVerifyMemento>( verify_attrs) );
-
- const std::vector<ZombieAttr>& zombie_attrs = misc_attrs_->zombies();
- BOOST_FOREACH(const ZombieAttr& attr, zombie_attrs){ comp->add( boost::make_shared<NodeZombieMemento>( attr) ); }
- }
-
- BOOST_FOREACH(limit_ptr l, limitVec_ ) { comp->add( boost::make_shared<NodeLimitMemento>( *l) ); }
- BOOST_FOREACH(const Variable& v, varVec_ ) { comp->add( boost::make_shared<NodeVariableMemento>( v) ); }
-
- inLimitMgr_.get_memento(comp);
-
- if (triggerExpr_) comp->add( boost::make_shared<NodeTriggerMemento>( *triggerExpr_) );
- if (completeExpr_) comp->add( boost::make_shared<NodeCompleteMemento>( *completeExpr_ ) );
- if (!repeat_.empty()) comp->add( boost::make_shared<NodeRepeatMemento>( repeat_) );
- if (lateAttr_) comp->add( boost::make_shared<NodeLateMemento>( *lateAttr_) );
-
- changes.add( comp );
- return;
- }
-
- /// *****************************************************************************************
- /// Node attributes CHANGED
- /// *****************************************************************************************
-
- // ** if start to Change ZombieAttr then it needs to be added here, currently we only add/delete.
-
- if (child_attrs_) {
-
- // determine if event value changed.
- const std::vector<Event>& event_attrs = child_attrs_->events();
- BOOST_FOREACH(const Event& e, event_attrs ) {
- if (e.state_change_no() > client_state_change_no) {
- if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
- comp->add( boost::make_shared<NodeEventMemento>(e) );
- }
- }
-
- // determine if Meter changed.
- const std::vector<Meter>& meter_attrs = child_attrs_->meters();
- BOOST_FOREACH(const Meter& m, meter_attrs ) {
- if (m.state_change_no() > client_state_change_no) {
- if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
- comp->add( boost::make_shared<NodeMeterMemento>( m) );
- }
- }
-
- // determine if labels changed.
- const std::vector<Label>& label_attrs = child_attrs_->labels();
- BOOST_FOREACH(const Label& l, label_attrs ) {
- if (l.state_change_no() > client_state_change_no) {
- if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
- comp->add( boost::make_shared<NodeLabelMemento>( l) );
- }
- }
- }
-
- // Determine if the time related dependency changed
- if (time_dep_attrs_) {
-
- const std::vector<ecf::TodayAttr>& today_attrs = time_dep_attrs_->todayVec();
- BOOST_FOREACH(const TodayAttr& attr, today_attrs ) {
- if (attr.state_change_no() > client_state_change_no) {
- if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
- comp->add( boost::make_shared<NodeTodayMemento>( attr) );
- }
- }
-
- const std::vector<ecf::TimeAttr>& time_attrs = time_dep_attrs_->timeVec();
- BOOST_FOREACH(const TimeAttr& attr, time_attrs ) {
- if (attr.state_change_no() > client_state_change_no) {
- if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
- comp->add( boost::make_shared<NodeTimeMemento>( attr) );
- }
- }
-
- const std::vector<DayAttr>& day_attrs = time_dep_attrs_->days();
- BOOST_FOREACH(const DayAttr& attr, day_attrs ) {
- if (attr.state_change_no() > client_state_change_no) {
- if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
- comp->add( boost::make_shared<NodeDayMemento>( attr) );
- }
- }
-
- const std::vector<DateAttr>& dates_attrs = time_dep_attrs_->dates();
- BOOST_FOREACH(const DateAttr& attr, dates_attrs ) {
- if (attr.state_change_no() > client_state_change_no) {
- if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
- comp->add( boost::make_shared<NodeDateMemento>( attr) );
- }
- }
-
- const std::vector<ecf::CronAttr>& cron_attrs = time_dep_attrs_->crons();
- BOOST_FOREACH(const CronAttr& attr, cron_attrs ) {
- if (attr.state_change_no() > client_state_change_no) {
- if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
- comp->add( boost::make_shared<NodeCronMemento>( attr) );
- }
- }
- }
-
- if (misc_attrs_) {
- // zombies have no state that changes
- // If one verify changes then copy all. Avoids having to work out which one changed
- const std::vector<VerifyAttr>& verify_attrs = misc_attrs_->verifys();
- BOOST_FOREACH(const VerifyAttr& v, verify_attrs ) {
- if (v.state_change_no() > client_state_change_no) {
- if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
- comp->add( boost::make_shared<NodeVerifyMemento>( verify_attrs) );
- break;
- }
- }
- }
-
- // determine if the trigger or complete changed
- if (triggerExpr_ && triggerExpr_->state_change_no() > client_state_change_no) {
- if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
- comp->add( boost::make_shared<NodeTriggerMemento>( *triggerExpr_) );
- }
- if (completeExpr_ && completeExpr_->state_change_no() > client_state_change_no) {
- if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
- comp->add( boost::make_shared<NodeCompleteMemento>( *completeExpr_) );
- }
-
- // determine if the repeat changed
- if (!repeat_.empty() && repeat_.state_change_no() > client_state_change_no) {
- if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
- comp->add( boost::make_shared<NodeRepeatMemento>( repeat_) );
- }
-
- // determine if limits changed.
- BOOST_FOREACH(limit_ptr l, limitVec_ ) {
- if (l->state_change_no() > client_state_change_no) {
- if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
- comp->add( boost::make_shared<NodeLimitMemento>( *l) );
- }
- }
-
- // determine if variable values changed. Copy all variables. Save on having variable_change_no_ per variable
- if (variable_change_no_ > client_state_change_no) {
- if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
- BOOST_FOREACH(const Variable& v, varVec_ ) { comp->add( boost::make_shared<NodeVariableMemento>( v) ); }
- }
-
- // Determine if the late attribute has changed
- if (lateAttr_ && lateAttr_->state_change_no() > client_state_change_no) {
- if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
- comp->add( boost::make_shared<NodeLateMemento>( *lateAttr_) );
- }
-
- // Determine if the flag changed
- if (flag_.state_change_no() > client_state_change_no) {
- if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
- comp->add( boost::make_shared<FlagMemento>( flag_ ) );
- }
-
-
- if (comp.get() ) {
- changes.add( comp );
- }
-}
-
-
-void Node::set_memento(const StateMemento* memento) {
-
-#ifdef DEBUG_MEMENTO
- std::cout << "Node::set_memento(const StateMemento* memento) " << debugNodePath() << " " << NState::toString(memento->state_) << "\n";
-#endif
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::STATE);
- setStateOnly( memento->state_ );
-}
-
-
-void Node::set_memento( const NodeDefStatusDeltaMemento* memento ) {
-#ifdef DEBUG_MEMENTO
- std::cout << "Node::set_memento(const NodeDefStatusDeltaMemento* memento) " << debugNodePath() << "\n";
-#endif
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::DEFSTATUS);
- defStatus_.setState( memento->state_ );
-}
-
-
-void Node::set_memento( const SuspendedMemento* memento ) {
-#ifdef DEBUG_MEMENTO
- std::cout << "Node::set_memento(const SuspendedMemento* memento) " << debugNodePath() << "\n";
-#endif
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::SUSPENDED);
- if (memento->suspended_) suspend();
- else clearSuspended();
-}
-
-
-void Node::set_memento( const NodeEventMemento* memento ) {
-
-#ifdef DEBUG_MEMENTO
- std::cout << "Node::set_memento(const NodeEventMemento* memento) " << debugNodePath() << "\n";
-#endif
- if (child_attrs_) {
- child_attrs_->set_memento(memento);
- return;
- }
- addEvent( memento->event_);
-}
-
-void Node::set_memento( const NodeMeterMemento* memento ) {
-
-#ifdef DEBUG_MEMENTO
- std::cout << "Node::set_memento(const NodeMeterMemento* memento) " << debugNodePath() << "\n";
-#endif
- if (child_attrs_) {
- child_attrs_->set_memento(memento);
- return;
- }
- addMeter(memento->meter_);
-}
-
-void Node::set_memento( const NodeLabelMemento* memento ) {
-
-#ifdef DEBUG_MEMENTO
- std::cout << "Node::set_memento(const NodeLabelMemento* memento) " << debugNodePath() << "\n";
-#endif
- if (child_attrs_) {
- child_attrs_->set_memento(memento);
- return;
- }
- addLabel(memento->label_);
-}
-
-void Node::set_memento( const NodeTriggerMemento* memento ) {
-
-#ifdef DEBUG_MEMENTO
- std::cout << "Node::set_memento(const NodeTriggerMemento* memento) " << debugNodePath() << "\n";
-#endif
-
- if (triggerExpr_) {
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::EXPR_TRIGGER);
- if (memento->exp_.isFree()) freeTrigger();
- else clearTrigger();
- return;
- }
-
- // ADD_REMOVE_ATTR aspect
- add_trigger_expression( memento->exp_);
-}
-
-void Node::set_memento( const NodeCompleteMemento* memento ) {
-
-#ifdef DEBUG_MEMENTO
- std::cout << "Node::set_memento(const NodeCompleteMemento* memento) " << debugNodePath() << "\n";
-#endif
-
- if (completeExpr_) {
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::EXPR_COMPLETE);
- if (memento->exp_.isFree()) freeComplete();
- else clearComplete();
- return;
- }
-
- // ADD_REMOVE_ATTR aspect
- add_complete_expression( memento->exp_);
-}
-
-void Node::set_memento( const NodeRepeatMemento* memento ) {
-
-#ifdef DEBUG_MEMENTO
- std::cout << "Node::set_memento(const NodeRepeatMemento* memento) " << debugNodePath() << "\n";
-#endif
-
- if (!repeat_.empty()) {
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::REPEAT);
-
- // Note: the node is incremented one past, the last value
- // In Node we increment() then check for validity
- // hence the_new_value may be outside of the valid range.
- // This can be seen when do a incremental sync,
- // *hence* allow memento to copy the value as is.
- repeat_.set_value(memento->repeat_.index_or_value());
-
- // Alternative, but expensive since relies on cloning and coping potentially very large vectors
- // repeat_ = memento->repeat_;
- return;
- }
-
- // ADD_REMOVE_ATTR aspect
- addRepeat(memento->repeat_);
-}
-
-void Node::set_memento( const NodeLimitMemento* memento ) {
-
-#ifdef DEBUG_MEMENTO
- std::cout << "Node::set_memento(const NodeLimitMemento* memento) " << debugNodePath() << " " << memento->limit_.toString() << "\n";
-#endif
-
- limit_ptr limit = find_limit(memento->limit_.name());
- if (limit.get()) {
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::LIMIT);
- limit->set_state( memento->limit_.theLimit(), memento->limit_.value(), memento->limit_.paths() );
- return;
- }
-
- // ADD_REMOVE_ATTR aspect
- addLimit(memento->limit_);
-}
-
-void Node::set_memento( const NodeInLimitMemento* memento ) {
-
-#ifdef DEBUG_MEMENTO
- std::cout << "Node::set_memento(const NodeInLimitMemento* memento) " << debugNodePath() << "\n";
-#endif
-
- // ADD_REMOVE_ATTR aspect only, since no state
-
- addInLimit(memento->inlimit_);
-}
-
-void Node::set_memento( const NodeVariableMemento* memento ) {
-
-#ifdef DEBUG_MEMENTO
- std::cout << "Node::set_memento(const NodeVariableMemento* memento) " << debugNodePath() << "\n";
-#endif
-
-
- size_t theSize = varVec_.size();
- for(size_t i = 0; i < theSize; i++) {
- if (varVec_[i].name() == memento->var_.name()) {
- varVec_[i].set_value( memento->var_.theValue() );
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::NODE_VARIABLE);
- return;
- }
- }
-
- // ADD_REMOVE_ATTR aspect
- addVariable(memento->var_);
-}
-
-void Node::set_memento( const NodeLateMemento* memento ) {
-
-#ifdef DEBUG_MEMENTO
- std::cout << "Node::set_memento(const NodeLateMemento* memento) " << debugNodePath() << "\n";
-#endif
-
- if (lateAttr_) {
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::LATE);
- lateAttr_->setLate(memento->late_.isLate());
- return;
- }
-
- // ADD_REMOVE_ATTR aspect
- addLate(memento->late_);
-}
-
-void Node::set_memento( const NodeTodayMemento* memento ) {
-
-#ifdef DEBUG_MEMENTO
- std::cout << "Node::set_memento(const NodeTodayMemento* memento) " << debugNodePath() << "\n";
-#endif
-
- if (time_dep_attrs_ && time_dep_attrs_->set_memento(memento) ) {
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::TODAY);
- return;
- }
-
- // ADD_REMOVE_ATTR aspect
- addToday(memento->attr_);
-}
-
-void Node::set_memento( const NodeTimeMemento* memento ) {
-
-#ifdef DEBUG_MEMENTO
- std::cout << "Node::set_memento(const NodeTimeMemento* memento) " << debugNodePath() << "\n";
-#endif
-
- if (time_dep_attrs_ && time_dep_attrs_->set_memento(memento) ) {
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::TIME);
- return;
- }
-
- // ADD_REMOVE_ATTR aspect
- addTime(memento->attr_);
-}
-
-void Node::set_memento( const NodeDayMemento* memento ) {
-
-#ifdef DEBUG_MEMENTO
- std::cout << "Node::set_memento(const NodeDayMemento* memento) " << debugNodePath() << "\n";
-#endif
-
-
- if (time_dep_attrs_ && time_dep_attrs_->set_memento(memento) ) {
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::DAY);
- return;
- }
-
- // ADD_REMOVE_ATTR aspect
- addDay(memento->attr_);
-}
-
-void Node::set_memento( const NodeDateMemento* memento ) {
-
-#ifdef DEBUG_MEMENTO
- std::cout << "Node::set_memento(const NodeDateMemento* memento) " << debugNodePath() << "\n";
-#endif
-
- if (time_dep_attrs_ && time_dep_attrs_->set_memento(memento) ) {
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::DATE);
- return;
- }
-
- // ADD_REMOVE_ATTR aspect
- addDate(memento->attr_);
-}
-
-void Node::set_memento( const NodeCronMemento* memento ) {
-
-#ifdef DEBUG_MEMENTO
- std::cout << "Node::set_memento(const NodeCronMemento* memento) " << debugNodePath() << "\n";
-#endif
-
-
- if (time_dep_attrs_ && time_dep_attrs_->set_memento(memento) ) {
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::CRON);
- return;
- }
-
- // ADD_REMOVE_ATTR aspect
- addCron(memento->attr_);
-}
-
-void Node::set_memento( const FlagMemento* memento ) {
-
-#ifdef DEBUG_MEMENTO
- std::cout << "Node::set_memento(const FlagMemento* memento) " << debugNodePath() << "\n";
-#endif
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::FLAG);
-
- flag_.set_flag( memento->flag_.flag() );
-}
-
-void Node::set_memento( const NodeZombieMemento* memento ) {
-
-#ifdef DEBUG_MEMENTO
- std::cout << "Node::set_memento(const NodeZombieMemento* memento) " << debugNodePath() << "\n";
-#endif
-
- // Zombie attributes should always be via ADD_REMOVE_ATTR
- // See Node::incremental_changes
- // Since there is no state to change
-
- /// remove existing attribute of same type, as duplicate of same type not allowed
- delete_zombie( memento->attr_.zombie_type());
- addZombie(memento->attr_);
-}
-
-void Node::set_memento( const NodeVerifyMemento* memento ) {
-
-#ifdef DEBUG_MEMENTO
- std::cout << "Node::set_memento(const NodeVerifyMemento* memento) " << debugNodePath() << "\n";
-#endif
- if (misc_attrs_) {
- misc_attrs_->verifys_.clear();
- misc_attrs_->verifys_ = memento->verifys_;
- return;
- }
- misc_attrs_ = new MiscAttrs(this);
- misc_attrs_->verifys_ = memento->verifys_;
-}
diff --git a/ecflow_4_0_7/ANode/src/NodeState.hpp b/ecflow_4_0_7/ANode/src/NodeState.hpp
deleted file mode 100644
index 35b479f..0000000
--- a/ecflow_4_0_7/ANode/src/NodeState.hpp
+++ /dev/null
@@ -1,70 +0,0 @@
-#ifndef NODESTATE_HPP_
-#define NODESTATE_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #9 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "NState.hpp"
-
-//
-// Given a set of nodes, return the the most significant state
-// Depend on the Node::computedState, hence include after Node.hpp
-// This will recurse down ****
-//
-namespace ecf {
-
-template < class T >
-NState::State theComputedNodeState( const std::vector<T>& nodeVec, bool immediate)
-{
- // std::cout << "theComputedNodeState vec size = " << nodeVec.size() << " immediate = " << immediate << "\n";
- int unknownCount = 0;
- int completeCount = 0;
- int queuedCount = 0;
- int submittedCount = 0;
- int activeCount = 0;
- int abortedCount = 0;
-
- // We don't know the order, hence we must collate first
- size_t theVecSize = nodeVec.size();
- for(size_t n =0; n < theVecSize; n++) {
- NState::State theState;
- if (immediate) theState = nodeVec[n]->state();
- else theState = nodeVec[n]->computedState( Node::HIERARCHICAL );
-
- // std::cout << "the computed state for " << nodeVec[n]->debugNodePath() << " is " << NState::toString(theState) << "\n";
-
- switch ( theState ) {
- case NState::ABORTED: abortedCount++; break;
- case NState::ACTIVE: activeCount++; break;
- case NState::SUBMITTED: submittedCount++; break;
- case NState::QUEUED: queuedCount++; break;
- case NState::COMPLETE: completeCount++; break;
- case NState::UNKNOWN: unknownCount++; break;
- default : assert(false); break;
- }
- }
- if (abortedCount > 0) return NState::ABORTED;
- if (activeCount > 0) return NState::ACTIVE;
- if (submittedCount > 0) return NState::SUBMITTED;
- if (queuedCount > 0) return NState::QUEUED;
- if (completeCount > 0 && completeCount == static_cast<int>(theVecSize)) {
- return NState::COMPLETE;
- }
- if (completeCount > 0) {
- return NState::QUEUED;
- }
- return NState::UNKNOWN;
-}
-}
-#endif
diff --git a/ecflow_4_0_7/ANode/src/NodeTreeVisitor.cpp b/ecflow_4_0_7/ANode/src/NodeTreeVisitor.cpp
deleted file mode 100644
index f51657a..0000000
--- a/ecflow_4_0_7/ANode/src/NodeTreeVisitor.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
- //============================================================================
-// Name : Cmd
-// Author : Avi
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-
-#include "NodeTreeVisitor.hpp"
-
-namespace ecf {
-
-NodeTreeVisitor::~NodeTreeVisitor() {}
-
-} // namespace ecf
diff --git a/ecflow_4_0_7/ANode/src/NodeTreeVisitor.hpp b/ecflow_4_0_7/ANode/src/NodeTreeVisitor.hpp
deleted file mode 100644
index 96c05bd..0000000
--- a/ecflow_4_0_7/ANode/src/NodeTreeVisitor.hpp
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef NODETREEVISITOR_HPP_
-#define NODETREEVISITOR_HPP_
-//============================================================================
-// Name : Cmd
-// Author : Avi
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-class Defs;
-class Suite;
-class Family;
-class Task;
-class NodeContainer;
-
-namespace ecf {
-
-class NodeTreeVisitor {
-public:
- virtual ~NodeTreeVisitor();
-
- virtual bool traverseObjectStructureViaVisitors() const { return false;}
- virtual void visitDefs(Defs*) = 0;
- virtual void visitSuite(Suite*) = 0;
- virtual void visitFamily(Family*) = 0;
- virtual void visitNodeContainer(NodeContainer*) = 0;
- virtual void visitTask(Task*) = 0;
-};
-
-}
-
-#endif
diff --git a/ecflow_4_0_7/ANode/src/ResolveExternsVisitor.cpp b/ecflow_4_0_7/ANode/src/ResolveExternsVisitor.cpp
deleted file mode 100644
index 537b6ac..0000000
--- a/ecflow_4_0_7/ANode/src/ResolveExternsVisitor.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #8 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "ResolveExternsVisitor.hpp"
-#include "ExprAstVisitor.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "ExprAst.hpp"
-#include "Log.hpp"
-#include "Str.hpp"
-
-using namespace std;
-
-namespace ecf {
-
-///////////////////////////////////////////////////////////////////////////////
-// ResolveExternsVisitor: Will traverse node tree hierarchy
-ResolveExternsVisitor::ResolveExternsVisitor(Defs* defs) : defs_(defs) {}
-
-void ResolveExternsVisitor::visitDefs( Defs* d) {
- BOOST_FOREACH(suite_ptr s, d->suiteVec()) { s->acceptVisitTraversor(*this); }
-}
-
-void ResolveExternsVisitor::visitSuite( Suite* s) { visitNodeContainer(s);}
-void ResolveExternsVisitor::visitFamily( Family* f) { visitNodeContainer(f); }
-
-void ResolveExternsVisitor::visitNodeContainer(NodeContainer* nc){
-
- setup(nc);
-
- BOOST_FOREACH(node_ptr t, nc->nodeVec()) {
- t->acceptVisitTraversor(*this);
- }
-}
-
-void ResolveExternsVisitor::visitTask( Task* t) { setup(t);}
-
-void ResolveExternsVisitor::setup(Node* n)
-{
- // Defs passed in to avoid, traversing up the node tree
- n->auto_add_inlimit_externs(defs_);
- doSetup(n,n->completeAst());
- doSetup(n,n->triggerAst());
-}
-
-void ResolveExternsVisitor::doSetup(Node* node,Ast* ast)
-{
- if ( ast ) {
- // The complete expression have been parsed and we have created the abstract syntax tree
- AstResolveExternVisitor astVisitor(node,defs_);
- ast->accept(astVisitor);
- }
-}
-
-//======================================================================================
-// AstResolveExternVisitor: Will traverse ASR tree hierarchy
-AstResolveExternVisitor::AstResolveExternVisitor(Node* node,Defs* defs)
-: triggerNode_(node), defs_(defs) {}
-
-AstResolveExternVisitor::~AstResolveExternVisitor() {}
-
-void AstResolveExternVisitor::visitNode(AstNode* astNode)
-{
- //std::cout << "AstResolveExternVisitor::visitNode " << triggerNode_->debugNodePath() << "\n";
-
- astNode->setParentNode(triggerNode_);
-
- // See if can reference the path, on the AstNode, if we cant, it should be added as an extern
- std::string errorMsg;
- Node* node = astNode->referencedNode( errorMsg );
- if ( !node ) {
- /// Add this path to the extern's. Avoid adding duplicates
- addExtern(astNode->nodePath());
- }
-}
-
-void AstResolveExternVisitor::visitVariable(AstVariable* astVar)
-{
- //std::cout << "AstResolveExternVisitor::visitNode " << triggerNode_->debugNodePath() << "\n";
-
- astVar->setParentNode(triggerNode_);
-
- // See if can reference the path, on the AstVariable, if we can't, it should be added as an extern
- std::string errorMsg;
- Node* theReferencedNode = astVar->referencedNode( errorMsg );
- if ( !theReferencedNode ) {
- addExtern(astVar->nodePath(),astVar->name());
- return;
- }
- LOG_ASSERT(errorMsg.empty(),"");
-
- // Ok,we found the referenced, node, now see if we can reference the attribute name
- // Find in order, event, meter, user variable, repeat, generated variable
- if (theReferencedNode->findExprVariable( astVar->name() ) ) {
- return;
- }
-
- // Can't find name, in event, meter, user variable, repeat, generated variable, add as extern
- addExtern(astVar->nodePath(),astVar->name());
-}
-
-void AstResolveExternVisitor::addExtern(const std::string& absNodePath, const std::string& var)
-{
- string ext = absNodePath;
- if (!var.empty()) {
- ext += Str::COLON();
- ext += var;
- }
- defs_->add_extern(ext); // stored in a set:
-}
-}
diff --git a/ecflow_4_0_7/ANode/src/ResolveExternsVisitor.hpp b/ecflow_4_0_7/ANode/src/ResolveExternsVisitor.hpp
deleted file mode 100644
index 14c3b1c..0000000
--- a/ecflow_4_0_7/ANode/src/ResolveExternsVisitor.hpp
+++ /dev/null
@@ -1,81 +0,0 @@
-#ifndef RESOLVE_EXTERNS_VISITOR_HPP_
-#define RESOLVE_EXTERNS_VISITOR_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "NodeTreeVisitor.hpp"
-#include "ExprAstVisitor.hpp"
-#include <string>
-#include <set>
-class Node;
-class Ast;
-
-namespace ecf {
-
-class ResolveExternsVisitor : public NodeTreeVisitor {
-public:
- ResolveExternsVisitor(Defs*);
-
- virtual bool traverseObjectStructureViaVisitors() const { return true;}
- virtual void visitDefs(Defs*);
- virtual void visitSuite(Suite*);
- virtual void visitFamily(Family*);
- virtual void visitNodeContainer(NodeContainer*);
- virtual void visitTask(Task*);
-
-private:
- void setup(Node*);
- void doSetup( Node* node, Ast* ast) ;
-
- Defs* defs_;
-};
-
-class AstResolveExternVisitor : public ExprAstVisitor {
-public:
- AstResolveExternVisitor( Node*, Defs*);
- virtual ~AstResolveExternVisitor();
-
- virtual void visitTop(AstTop*){}
- virtual void visitRoot(AstRoot*){}
- virtual void visitAnd(AstAnd*){}
- virtual void visitNot(AstNot*){}
- virtual void visitPlus(AstPlus*){}
- virtual void visitMinus(AstMinus*){}
- virtual void visitDivide(AstDivide*){}
- virtual void visitMultiply(AstMultiply*){}
- virtual void visitModulo(AstModulo*){}
- virtual void visitOr(AstOr*){}
- virtual void visitEqual(AstEqual*){}
- virtual void visitNotEqual(AstNotEqual*){}
- virtual void visitLessEqual(AstLessEqual*){}
- virtual void visitGreaterEqual(AstGreaterEqual*){}
- virtual void visitGreaterThan(AstGreaterThan*){}
- virtual void visitLessThan(AstLessThan*){}
- virtual void visitLeaf(AstLeaf*){}
- virtual void visitInteger(AstInteger*){}
- virtual void visitString(AstString*){}
- virtual void visitNodeState(AstNodeState*){}
- virtual void visitEventState(AstEventState*){}
- virtual void visitNode(AstNode*);
- virtual void visitVariable(AstVariable*);
-
-private:
- void addExtern(const std::string& absNodePath, const std::string& var = "");
- Node* triggerNode_;
- Defs* defs_;
-};
-
-}
-#endif
diff --git a/ecflow_4_0_7/ANode/src/ServerState.cpp b/ecflow_4_0_7/ANode/src/ServerState.cpp
deleted file mode 100644
index e1e2201..0000000
--- a/ecflow_4_0_7/ANode/src/ServerState.cpp
+++ /dev/null
@@ -1,455 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #29 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <assert.h>
-#include <iostream>
-#include "ServerState.hpp"
-#include "Str.hpp"
-#include "Log.hpp"
-#include "Host.hpp"
-#include "Ecf.hpp"
-#include "Version.hpp"
-
-using namespace ecf;
-using namespace std;
-
-// When a Defs is loaded into a server:
-// o the jobSubmissionInterval_ is set
-// o the jobGeneration_ is set
-ServerState::ServerState() :
- state_change_no_(0),
- variable_state_change_no_(0),
- server_state_( default_state() ),
- jobSubmissionInterval_( 60 ),
- jobGeneration_( true )
-{
- setup_default_env();
-}
-
-bool ServerState::operator==(const ServerState& rhs) const
-{
- if ( get_state() != rhs.get_state()) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "ServerState::operator== get_state(" << SState::to_string(get_state()) << ") != rhs.get_state(" << SState::to_string(rhs.get_state()) << ")\n";
- }
-#endif
- return false;
- }
-
- if ( user_variables_ != rhs.user_variables_) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "ServerState::compare user_variables_ != rhs.user_variables_\n";
- std::cout << "user_variables_:\n";
- for(std::vector<Variable>::const_iterator i = user_variables_.begin(); i!=user_variables_.end(); ++i) {
- std::cout << " " << (*i).name() << " " << (*i).theValue() << "\n";
- }
- std::cout << "rhs.user_variables_:\n";
- for(std::vector<Variable>::const_iterator i = rhs.user_variables_.begin(); i!=rhs.user_variables_.end(); ++i) {
- std::cout << " " << (*i).name() << " " << (*i).theValue() << "\n";
- }
- }
-#endif
- return false;
- }
-
- /// Check pointing, SAVES server variables, since they are visualised by client like ecflowview
- /// HOWEVER PrintStyle::MIGRATE does not save the server variables, since they should
- /// not take part in migration. However the testing compares migration files with check point files
- /// This would always fail. Hence we do not compare server variables.
-
- return true;
-}
-
-bool ServerState::compare(const ServerState& rhs) const
-{
- if ( get_state() != rhs.get_state()) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "ServerState::compare get_state(" << SState::to_string(get_state()) << ") != rhs.get_state(" << SState::to_string(rhs.get_state()) << ")\n";
- }
-#endif
- return false;
- }
-
- if ( user_variables_ != rhs.user_variables_) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "ServerState::compare user_variables_ != rhs.user_variables_\n";
- std::cout << "user_variables_:\n";
- for(std::vector<Variable>::const_iterator i = user_variables_.begin(); i!=user_variables_.end(); ++i) {
- std::cout << " " << (*i).name() << " " << (*i).theValue() << "\n";
- }
- std::cout << "rhs.user_variables_:\n";
- for(std::vector<Variable>::const_iterator i = rhs.user_variables_.begin(); i!=rhs.user_variables_.end(); ++i) {
- std::cout << " " << (*i).name() << " " << (*i).theValue() << "\n";
- }
- }
-#endif
- return false;
- }
-
- if ( server_variables_ != rhs.server_variables_) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "ServerState::compare server_variables_ != rhs.server_variables_\n";
- std::cout << "server_variables_:\n";
- for(std::vector<Variable>::const_iterator i = server_variables_.begin(); i!=server_variables_.end(); ++i) {
- std::cout << " " << (*i).name() << " " << (*i).theValue() << "\n";
- }
- std::cout << "rhs.server_variables_:\n";
- for(std::vector<Variable>::const_iterator i = rhs.server_variables_.begin(); i!=rhs.server_variables_.end(); ++i) {
- std::cout << " " << (*i).name() << " " << (*i).theValue() << "\n";
- }
- }
-#endif
- return false;
- }
- return true;
-}
-
-// server variable can NOT be modified or deleted, only overridden
-void ServerState::add_or_update_server_variables( const NameValueVec& env)
-{
- // n2 could use map to speed things up.
- NameValueVec::const_iterator i;
- NameValueVec::const_iterator theEnd = env.end();
- for(i = env.begin(); i!=theEnd; ++i) {
- add_or_update_server_variables((*i).first, (*i).second);
- }
-}
-void ServerState::add_or_update_server_variables( const std::string& name, const std::string& value)
-{
- std::vector<Variable>::iterator var_end = server_variables_.end();
- for(std::vector<Variable>::iterator i = server_variables_.begin(); i!=var_end; ++i) {
- if ((*i).name() == name) {
- (*i).set_value( value );
-// std::cout << " Server Variables: Updating " << name << " " << value << "\n";
- return;
- }
- }
-// std::cout << " Server Variables: Adding " << name << " " << value << "\n";
- server_variables_.push_back( Variable(name, value) );
-}
-
-void ServerState::set_server_variables(const std::vector<Variable>& e)
-{
- server_variables_ = e;
-}
-
-void ServerState::delete_server_variable( const std::string& var)
-{
- std::vector<Variable>::iterator var_end = server_variables_.end();
- for(std::vector<Variable>::iterator i = server_variables_.begin(); i!=var_end; ++i) {
- if ((*i).name() == var) {
- server_variables_.erase(i);
- break;
- }
- }
-}
-
-// ================================================================================
-
-void ServerState::add_or_update_user_variables( const NameValueVec& env)
-{
- // n2 could use map to speed things up.
- NameValueVec::const_iterator i;
- NameValueVec::const_iterator theEnd = env.end();
- for(i = env.begin(); i!=theEnd; ++i) {
- add_or_update_user_variables((*i).first, (*i).second);
- }
-}
-
-void ServerState::add_or_update_user_variables( const std::vector<Variable>& env)
-{
- std::vector<Variable>::const_iterator var_end = env.end();
- for(std::vector<Variable>::const_iterator i = env.begin(); i!=var_end; ++i) {
- add_or_update_user_variables( (*i).name(), (*i).theValue());
- }
-}
-
-void ServerState::add_or_update_user_variables( const std::string& name, const std::string& value)
-{
- std::vector<Variable>::iterator var_end = user_variables_.end();
- for(std::vector<Variable>::iterator i = user_variables_.begin(); i!=var_end; ++i) {
- if ((*i).name() == name) {
- (*i).set_value( value );
- variable_state_change_no_ = Ecf::incr_state_change_no();
-// std::cout << " ServerState::add_or_update_user_variables: Updating " << name << " " << value << "\n";
- return;
- }
- }
-
-// std::cout << " ServerState::add_or_update_user_variables: Adding " << name << " " << value << "\n";
- user_variables_.push_back( Variable(name, value) );
- variable_state_change_no_ = Ecf::incr_state_change_no();
-}
-
-void ServerState::delete_user_variable( const std::string& var)
-{
- if (var.empty()) {
- // delete all user variables
- user_variables_.clear();
- variable_state_change_no_ = Ecf::incr_state_change_no();
- return;
- }
-
- std::vector<Variable>::iterator var_end = user_variables_.end();
- for(std::vector<Variable>::iterator i = user_variables_.begin(); i!=var_end; ++i) {
- if ((*i).name() == var) {
- user_variables_.erase(i);
- variable_state_change_no_ = Ecf::incr_state_change_no();
- break;
- }
- }
-}
-
-const std::string& ServerState::find_variable(const std::string& theVarName) const
-{
- // SEARCH USER variables FIRST
- std::vector<Variable>::const_iterator user_var_end = user_variables_.end();
- for(std::vector<Variable>::const_iterator i = user_variables_.begin(); i!=user_var_end; ++i) {
- if ((*i).name() == theVarName) {
-// cerr << "FOUND '" << (*i).first << "' '" << (*i).second << "'\n";
- LOG_ASSERT(!(*i).theValue().empty(),"");
- return (*i).theValue();
- }
- }
-
- // NOW search server variables
- std::vector<Variable>::const_iterator ser_var_end = server_variables_.end();
- for(std::vector<Variable>::const_iterator i = server_variables_.begin(); i!=ser_var_end; ++i) {
- if ((*i).name() == theVarName) {
-// cerr << "FOUND '" << (*i).first << "' '" << (*i).second << "'\n";
- LOG_ASSERT(!(*i).theValue().empty(),"");
- return (*i).theValue();
- }
- }
-
-// cerr << "FAILED to FIND '" << theVarName << "'\n";
- return Str::EMPTY();
-}
-
-const Variable& ServerState::findVariable(const std::string& name) const
-{
- // SEARCH USER variables FIRST
- std::vector<Variable>::const_iterator var_end = user_variables_.end();
- for(std::vector<Variable>::const_iterator i = user_variables_.begin(); i!=var_end; ++i) {
- if ((*i).name() == name) {
- LOG_ASSERT(!(*i).theValue().empty(),"");
- // if ((*i).theValue().empty() ) std::cout << (*i).name() << " has a empty value\n";
- return (*i);
- }
- }
-
- // NOW search server variables
- std::vector<Variable>::const_iterator ser_var_end = server_variables_.end();
- for(std::vector<Variable>::const_iterator i = server_variables_.begin(); i!=ser_var_end; ++i) {
- if ((*i).name() == name) {
- LOG_ASSERT(!(*i).theValue().empty(),"");
- // if ((*i).theValue().empty() ) std::cout << (*i).name() << " has a empty value\n";
- return (*i);
- }
- }
-
-// cerr << "FAILED to FIND '" << theVarName << "'\n";
- return Variable::EMPTY();
-}
-
-bool ServerState::variable_exists(const std::string& name) const
-{
- // SEARCH USER variables FIRST
- std::vector<Variable>::const_iterator var_end = user_variables_.end();
- for(std::vector<Variable>::const_iterator i = user_variables_.begin(); i!=var_end; ++i) {
- if ((*i).name() == name) return true;
- }
-
- // NOW search server variables
- std::vector<Variable>::const_iterator ser_var_end = server_variables_.end();
- for(std::vector<Variable>::const_iterator i = server_variables_.begin(); i!=ser_var_end; ++i) {
- if ((*i).name() == name) return true;
- }
-
- return false;
-}
-
-bool ServerState::variableSubsitution(std::string& cmd) const
-{
- // scan the command for variables, and substitute
- // We can also have
- //
- // "%<VAR>:<substitute>% i.e if VAR exist use it, else use substitute
- //
- // ************************************************************************************************************
- // Special case handling for user variables, and generated variables, which take precedence over node variables
- // ************************************************************************************************************
- //
- // i.e VAR is defined as BILL
- // %VAR:fred --f% will either be "BILL" or if VAR is not defined "fred --f"
- //
- // Infinite recursion. Its possible to end up with infinite recursion:
- // edit hello '%hello%' # string like %hello% will cause infinite recursion
- // edit fred '%bill%'
- // edit bill '%fred%' # should be 10
- // To prevent this we will use a simple count
- char micro = '%';
- const Variable& micro_var = findVariable(Str::ECF_MICRO());
- if (!micro_var.empty() && !micro_var.theValue().empty() ) micro = micro_var.theValue()[0];
-
- bool double_micro_found = false;
- std::string::size_type pos = 0;
- int count = 0;
- while ( 1 ) {
- // A while loop here is used to:
- // a/ Allow for multiple substitution on a single line. i.e %ECF_FILES% -I %ECF_INCLUDE%"
- // b/ Allow for recursive substitution. %fred% -> %bill%--> 10
-
- size_t firstPercentPos = cmd.find( micro, pos );
- if ( firstPercentPos == string::npos ) break;
-
- size_t secondPercentPos = cmd.find( micro, firstPercentPos + 1 );
- if ( secondPercentPos == string::npos ) break;
-
- if ( secondPercentPos - firstPercentPos <= 1 ) {
- // handle %% with no characters in between, skip over
- // i.e to handle "printf %%02d %HOUR:00%" --> "printf %02d 00" i.e if HOUR not defined
- pos = secondPercentPos + 1;
- double_micro_found = true;
- continue;
- }
- else pos = 0;
-
- string percentVar( cmd.begin() + firstPercentPos+1, cmd.begin() + secondPercentPos );
-
- // First search user variable (*ONLY* set when doing user edit's the script)
- // Handle case: cmd = "%fred:bill% and where we have user variable "fred:bill"
- // Handle case: cmd = "%fred% and where we have user variable "fred"
- // If we fail to find the variable we return false.
- // Note: When a variable is found, it can have an empty value which is still valid
- const Variable& variable = findVariable( percentVar );
- if (!variable.empty() ) {
- std::string varValue = variable.theValue();
- cmd.replace( firstPercentPos, secondPercentPos - firstPercentPos + 1, varValue );
- }
- else {
-
- size_t firstColon = percentVar.find( ':' );
- if (firstColon != string::npos) {
-
- string var(percentVar.begin(), percentVar.begin() + firstColon);
-
- const Variable& variable2 = findVariable( var );
- if (!variable2.empty() ) {
- std::string varValue = variable2.theValue();
- cmd.replace( firstPercentPos, secondPercentPos - firstPercentPos + 1, varValue );
- }
- else {
- string substitute (percentVar.begin()+ firstColon+1, percentVar.end());
- cmd.replace(firstPercentPos,secondPercentPos-firstPercentPos+1,substitute);
- }
- }
- else {
- // No Colon, Can't find in user variables, or node variable, hence can't go any further
- return false;
- }
- }
-
- // Simple Check for infinite recursion
- if (count > 100) return false;
- count++;
- }
-
- if (double_micro_found) {
- // replace all double micro with a single micro, this must be a single parse
- // date +%%Y%%m%%d" ==> date +%Y%m%d
- // %%%% ==> %% // i.e single parse
- std::string doubleEcfMicro;
- doubleEcfMicro += micro;
- doubleEcfMicro += micro;
- size_t last_pos = 0;
- while ( 1 ) {
- string::size_type ecf_double_micro_pos = cmd.find( doubleEcfMicro , last_pos);
- if ( ecf_double_micro_pos != std::string::npos ) {
- cmd.erase( cmd.begin() + ecf_double_micro_pos );
- last_pos = ecf_double_micro_pos + 1;
- }
- else break;
- }
- }
-
- return true;
-}
-
-void ServerState::set_user_variables(const std::vector<Variable>& e)
-{
- user_variables_ = e;
- variable_state_change_no_ = Ecf::incr_state_change_no();
-}
-
-void ServerState::set_state(SState::State s) {
- server_state_ = s;
- state_change_no_ = Ecf::incr_state_change_no();
-}
-
-
-void ServerState::setup_default_env()
-{
- // This environment is required for testing in the absence of the server.
- // When the defs file is begun in the server this environment get *overridden*
- hostPort_ = std::make_pair(Str::LOCALHOST(),Str::DEFAULT_PORT_NUMBER());
-
- setup_default_server_variables(server_variables_,Str::DEFAULT_PORT_NUMBER());
-}
-
-void ServerState::setup_default_server_variables(std::vector<Variable>& server_variables, const std::string& port)
-{
- Host host;
- server_variables.push_back( Variable(Str::ECF_MICRO(), Ecf::MICRO() )); //Preprocessor character for variable substitution and including files
- server_variables.push_back( Variable(Str::ECF_HOME(), string(".")) );
- server_variables.push_back( Variable(string("ECF_JOB_CMD"), Ecf::JOB_CMD() )); //Command to be executed to submit a job
- server_variables.push_back( Variable(string("ECF_KILL_CMD"), Ecf::KILL_CMD() )); // Command to be executed to kill a job
- server_variables.push_back( Variable(string("ECF_STATUS_CMD"), Ecf::STATUS_CMD() )); // Command to be executed to kill a job
- server_variables.push_back( Variable(string("ECF_URL_CMD"), Ecf::URL_CMD() ));
- server_variables.push_back( Variable(string("ECF_URL_BASE"), Ecf::URL_BASE() ));
- server_variables.push_back( Variable(string("ECF_URL"), Ecf::URL() ));
- server_variables.push_back( Variable(string("ECF_LOG"), host.ecf_log_file(port) ));
- server_variables.push_back( Variable(string("ECF_INTERVAL"), string("60") )); // Check time dependencies and submit any jobs
- server_variables.push_back( Variable(string("ECF_LISTS"), host.ecf_lists_file(port) ));
- server_variables.push_back( Variable(string("ECF_CHECK"), host.ecf_checkpt_file(port) ));
- server_variables.push_back( Variable(string("ECF_CHECKOLD"), host.ecf_backup_checkpt_file(port)));
- server_variables.push_back( Variable(string("ECF_CHECKINTERVAL"), string("120") )); //The interval in seconds to save check point file
- server_variables.push_back( Variable(string("ECF_CHECKMODE"), string("CHECK_ON_TIME")) );//The check mode, must be one of NEVER, ON_TIME, ALWAYS
-
- // Number of times a job should rerun if it aborts. If more than one and
- // job aborts, the job is automatically re-run. Useful when jobs are run in
- // an unreliable environments. For example using using commands like ftp(1)
- // in a job can fail easily, but re-running the job will often work
- server_variables.push_back( Variable(Str::ECF_TRIES(), string("2")) );
-
- server_variables.push_back( Variable(string("ECF_VERSION"),Version::raw()) );// server version
-
- // Needed to setup client environment.
- // The server sets these variable for use by the client. i.e when creating the jobs
- // The clients then uses them to communicate with the server.
- server_variables.push_back( Variable(Str::ECF_PORT(),port) );
- server_variables.push_back( Variable(Str::ECF_NODE(),Str::LOCALHOST()) );
-}
-
-/// determines why the node is not running.
-void ServerState::why(std::vector<std::string>& theReasonWhy) const
-{
- if (server_state_ == SState::HALTED) theReasonWhy.push_back("The server is halted");
- if (server_state_ == SState::SHUTDOWN) theReasonWhy.push_back("The server is shutdown");
-}
diff --git a/ecflow_4_0_7/ANode/src/ServerState.hpp b/ecflow_4_0_7/ANode/src/ServerState.hpp
deleted file mode 100644
index fd522e5..0000000
--- a/ecflow_4_0_7/ANode/src/ServerState.hpp
+++ /dev/null
@@ -1,139 +0,0 @@
-#ifndef SERVER_STATE_HPP_
-#define SERVER_STATE_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #18 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <boost/noncopyable.hpp>
-#include <boost/serialization/serialization.hpp>
-#include <boost/serialization/string.hpp> // no need to include <string>
-
-#include "SState.hpp"
-#include "NodeFwd.hpp"
-#include "Variable.hpp"
-
-/// This class stores the server state, so that it is accessible by the node tree
-///
-/// The server variables could have been added/deleted or changed, hence these
-/// variables are serialised, also: it has proved useful i.e for
-/// a/ Client to visualise the server environment during a call like -group="get; show state"
-/// b/ Allows the test code to update environment. ie. use ECF_CLIENT
-//// allows us to replace smsinit, smscomplete,etc, with the ECF client exe
-//
-// Note The default state here is RUNNING while in the server the default state is HALTED
-// By choosing RUNNING, it allows the Defs related test, to run without explicitly setting the state
-class ServerState : private boost::noncopyable {
-public:
- ServerState();
-
- /// Check pointing, SAVES server variables, since they are visualised by client like ecflowview
- /// HOWEVER PrintStyle::MIGRATE does not save the server variables, since they should
- /// not take part in migration. However the testing compares migration files with check point files
- /// This would always fail. Hence we do not compare server variables.
- /// This does not compare server variables
- bool operator==(const ServerState& rhs) const;
- bool operator!=(const ServerState& rhs) const { return !operator==(rhs);}
-
- /// This does compare server variables. Used in testing
- bool compare(const ServerState& rhs) const;
-
- /// The server variable: are automatically added by the server
- /// on STARTUP and when a checkpoint file is reloaded.
- /// The variable are required by Job creation & needed in creation of generated variables
- /// The variables should NOT be modified.
- ///
- /// However user variables can be freely added,deleted and modified
- /// They will override server variables of the same name
-
- void add_or_update_server_variables( const NameValueVec& env);
- void delete_server_variable( const std::string&); // should only be used by test
- void set_server_variables(const std::vector<Variable>& e);
- const std::vector<Variable>& server_variables() const { return server_variables_; }
-
- void add_or_update_user_variables( const NameValueVec& env);
- void add_or_update_user_variables( const std::vector<Variable>& env);
- void add_or_update_user_variables( const std::string&, const std::string&);
- void delete_user_variable( const std::string&);
-
- void set_user_variables(const std::vector<Variable>& e);
- const std::vector<Variable>& user_variables() const { return user_variables_; }
-
- // Search user variables, and then server variables
- const std::string& find_variable(const std::string& name) const;
- const Variable& findVariable(const std::string& name) const;
- bool variable_exists(const std::string& name) const;
-
- /// find all %VAR% and replaces with variable values, returns false on the
- /// first variable that can't be found, cmd will be left half processed.
- /// Will search for ECF_MICRO, if not found assumes % as the micro char
- bool variableSubsitution(std::string& cmd) const;
-
- // These functions/data are used to during job generation
- void jobSubmissionInterval(int s) { jobSubmissionInterval_ = s;}
- int jobSubmissionInterval() const { return jobSubmissionInterval_;}
- bool jobGeneration() const { return jobGeneration_;} // testing may disable job generation
- void jobGeneration(bool f) { jobGeneration_ = f;}
-
- void set_state(SState::State s);
- SState::State get_state() const { return server_state_; }
- static SState::State default_state() { return SState::RUNNING; }
-
- // set by the server hence no need persist
- void hostPort( const std::pair<std::string,std::string>& hostPort ) { hostPort_ = hostPort;}
- std::pair<std::string,std::string> hostPort() const { return hostPort_; }
-
- /// Currently only SState::State server_state_ recorded
- unsigned int state_change_no() const { return state_change_no_; }
- unsigned int variable_state_change_no() const { return variable_state_change_no_; }
-
- /// determines why the node is not running.
- void why(std::vector<std::string>& theReasonWhy) const;
-
- /// Used in test
- static void setup_default_server_variables(std::vector<Variable>& server_variables, const std::string& port);
-
-private:
- void setup_default_env();
-
- void add_or_update_server_variables( const std::string&, const std::string&);
-
-private:
-
- unsigned int state_change_no_; // *not* persisted, only used on server side
- unsigned int variable_state_change_no_; // *not* persisted, only used on server side
-
- SState::State server_state_;
- std::vector<Variable> server_variables_;
- std::vector<Variable> user_variables_;
-
- int jobSubmissionInterval_; // NOT persisted, since set in the server
- bool jobGeneration_; // NOT persisted, since set in the server
- std::pair<std::string,std::string> hostPort_; // NOT persisted, set by server hence no need to persist
-
-private:
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/)
- {
- ar & server_state_;
- ar & user_variables_;
- ar & server_variables_;
- }
-};
-
-// This should ONLY be added to objects that are *NOT* serialised through a pointer
-BOOST_CLASS_IMPLEMENTATION(ServerState, boost::serialization::object_serializable)
-BOOST_CLASS_TRACKING(ServerState,boost::serialization::track_never);
-
-#endif
diff --git a/ecflow_4_0_7/ANode/src/Signal.cpp b/ecflow_4_0_7/ANode/src/Signal.cpp
deleted file mode 100644
index 7a57b51..0000000
--- a/ecflow_4_0_7/ANode/src/Signal.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-//============================================================================
-// Name : Signal
-// Author : Avi
-// Revision : $Revision: #8 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "Signal.hpp"
-#include <signal.h>
-#include <iostream>
-
-namespace ecf {
-
-// SIGCHLD : Child status has changed (POSIX)
-// Signal sent to parent process whenever one of its child processes terminates or stops.
-
-Signal::Signal() {}
-
-Signal::~Signal()
-{
- // Unblock SIGCHLD. This will call the signal-handler in System.cpp,
- // *IF* we have pending SIGCHLD
- // This will not return until we have handled all the pending SIGCHLD signal
- unblock_sigchild();
-
- // Once the signals are processed, block them until we come in here again
- // Now block again.
- block_sigchild();
-}
-
-void Signal::block_sigchild()
-{
- // Now block again.
- sigset_t set;
- sigemptyset( &set );
- sigaddset( &set, SIGCHLD );
-#ifdef ECFLOW_MT
- rc = pthread_sigmask(SIG_BLOCK, &set, 0 ); // not tested
- if (rc != 0) std::cerr << "Signal::~Signal(): pthread_sigmask(SIG_UNBLOCK, &set, 0) returned " << rc << "\n";
-#else
- sigprocmask( SIG_BLOCK, &set, 0 );
-#endif
-}
-
-void Signal::unblock_sigchild()
-{
- sigset_t set;
- sigemptyset( &set );
- sigaddset( &set, SIGCHLD );
-#ifdef ECFLOW_MT
- int rc = pthread_sigmask(SIG_UNBLOCK, &set, 0 ); // not tested
- if (rc != 0) std::cerr << "Signal::~Signal(): pthread_sigmask(SIG_UNBLOCK, &set, 0) returned " << rc << "\n";
-#else
- sigprocmask( SIG_UNBLOCK, &set, 0 );
-#endif
-}
-
-}
diff --git a/ecflow_4_0_7/ANode/src/Signal.hpp b/ecflow_4_0_7/ANode/src/Signal.hpp
deleted file mode 100644
index 1dddc74..0000000
--- a/ecflow_4_0_7/ANode/src/Signal.hpp
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef SIGNAL_HPP_
-#define SIGNAL_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : During destruction will un-block SIGCHILD and then reblock
-// During job generation we want to avoid being notified of
-// of child process termination.
-// We want to control when child process termination is handled
-// Collaboration: System.hpp
-//============================================================================
-#include <boost/noncopyable.hpp>
-
-namespace ecf {
-
-class Signal : private boost::noncopyable {
-public:
- Signal();
-
- /// UNBLOCK SIGCHLD at start of destructor
- /// BLOCK SIGCHLD and the end of the destructor
- /// During the gap in between handle process termination
- ~Signal();
-
- static void block_sigchild();
- static void unblock_sigchild();
-};
-}
-#endif
diff --git a/ecflow_4_0_7/ANode/src/Submittable.cpp b/ecflow_4_0_7/ANode/src/Submittable.cpp
deleted file mode 100644
index 7eab59f..0000000
--- a/ecflow_4_0_7/ANode/src/Submittable.cpp
+++ /dev/null
@@ -1,906 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #37 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <assert.h>
-#include <sstream>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include "boost/filesystem/exception.hpp"
-#include <boost/lexical_cast.hpp>
-#include <boost/make_shared.hpp>
-
-#include "Submittable.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "File.hpp"
-#include "Passwd.hpp"
-#include "Stl.hpp"
-#include "Str.hpp"
-#include "Indentor.hpp"
-#include "Log.hpp"
-#include "System.hpp"
-#include "JobsParam.hpp"
-#include "EcfFile.hpp"
-#include "Ecf.hpp"
-#include "DefsDelta.hpp"
-#include "Extract.hpp"
-#include "ChangeMgrSingleton.hpp"
-
-namespace fs = boost::filesystem;
-using namespace ecf;
-using namespace std;
-using namespace boost;
-
-//#define DEBUG_TASK_LOCATION 1
-
-/////////////////////////////////////////////////////////////////////////////////////////////////////
-// init static
-const std::string& Submittable::DUMMY_JOBS_PASSWORD() { static const std::string DUMMY_JOBS_PASSWORD = "_DJP_"; return DUMMY_JOBS_PASSWORD;}
-const std::string& Submittable::FREE_JOBS_PASSWORD() { static const std::string FREE_JOBS_PASSWORD = "FREE"; return FREE_JOBS_PASSWORD;}
-const std::string& Submittable::DUMMY_PROCESS_OR_REMOTE_ID() { static const std::string DUMMY_PROCESS_OR_REMOTE_ID = "_RID_"; return DUMMY_PROCESS_OR_REMOTE_ID;}
-
-Submittable::~Submittable()
-{
- delete sub_gen_variables_;
-}
-
-void Submittable::init( const std::string& the_process_or_remote_id)
-{
- set_state( NState::ACTIVE );
- set_process_or_remote_id(the_process_or_remote_id);
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Submittable::init\n";
-#endif
-}
-
-void Submittable::complete()
-{
-// cout << "Completed " << debugNodePath() << " at " << suite()->calendar().toString() << "\n";
- set_state( NState::COMPLETE );
- flag().clear(ecf::Flag::ZOMBIE);
-
- /// Should we clear jobsPassword_ & process_id? It can be argued that
- /// we should keep this. In case it is needed. i.e The job may not really be
- /// complete. However keeping, this means the memory usage will continue to rise
- /// Dependent on number of tasks. This can affect network bandwidth as well.
- /// Hence to reduce network bandwidth we chose to clear the strings
- clear(); // jobs password, process_id, aborted_reason
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Submittable::complete()\n";
-#endif
-}
-
-void Submittable::aborted(const std::string& reason)
-{
- // Called during *abnormal* child termination
- // This will bubble the state, and decrement any limits
- set_aborted_only(reason);
-}
-
-void Submittable::set_process_or_remote_id(const std::string& id)
-{
- process_or_remote_id_ = id;
- set_genvar_ecfrid(process_or_remote_id_);
- state_change_no_ = Ecf::incr_state_change_no();
-
-#ifdef DEBUG
- if (tryNo_ == 0 && process_or_remote_id_ != Submittable::DUMMY_PROCESS_OR_REMOTE_ID()) {
- LogToCout logToCout;
- LOG(Log::ERR,"Submittable::set_process_or_remote_id: " << absNodePath() << " process_id(" << id << ") tryNo == 0, how can this be ???");
- }
-#endif
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Submittable::set_process_or_remote_id\n";
-#endif
-}
-
-void Submittable::begin()
-{
- /// It is *very* important that we reset the passwords. This allows us to detect zombies.
- tryNo_ = 0; // reset try number
- clear(); // jobs password, process_id, aborted_reason
-
- Node::begin(); // see Notes in: Node::begin() about update_generated_variables()
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Submittable::begin()\n";
-#endif
-}
-
-void Submittable::requeue(bool resetRepeats, int clear_suspended_in_child_nodes, bool reset_next_time_slot)
-{
- /// It is *very* important that we reset the passwords. This allows us to detect zombies.
- tryNo_ = 0; // reset try number
- clear(); // jobs password, process_id, aborted_reason
-
- Node::requeue(resetRepeats,clear_suspended_in_child_nodes,reset_next_time_slot);
- update_generated_variables();
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Submittable::requeue\n";
-#endif
-}
-
-std::string Submittable::write_state() const
-{
- // *IMPORTANT* we *CANT* use ';' character, since is used in the parser, when we have
- // multiple statement on a single line i.e.
- // task a; task b;
- std::stringstream ss;
- if ( !jobsPassword_.empty() && jobsPassword_!= Submittable::DUMMY_JOBS_PASSWORD()) ss << " passwd:" << jobsPassword_;
- if ( !process_or_remote_id_.empty() ) ss << " rid:" << process_or_remote_id_;
-
- // The abortedReason_, can contain user generated messages, including \n and ;, hence remove these
- // as they can mess up the parsing on reload.
- if ( !abortedReason_.empty() ) {
- std::string the_abort_reason = abortedReason_;
- Str::replaceall(the_abort_reason,"\n","\\n");
- Str::replaceall(the_abort_reason,";"," ");
- ss << " abort<:" << the_abort_reason << ">abort";
- }
- if ( tryNo_ != 0) ss << " try:" << tryNo_;
- ss << Node::write_state();
- return ss.str();
-}
-
-void Submittable::read_state(const std::string& line,const std::vector<std::string>& lineTokens)
-{
- // 0 1 2
- // task name #
- for(size_t i = 3; i < lineTokens.size(); i++) {
- if (lineTokens[i].find("passwd:") != std::string::npos ) {
- if (!Extract::split_get_second(lineTokens[i],jobsPassword_))
- throw std::runtime_error( "Submittable::read_state failed for jobs password : " + name());
- }
- else if (lineTokens[i].find("rid:") != std::string::npos ) {
- if (!Extract::split_get_second(lineTokens[i],process_or_remote_id_))
- throw std::runtime_error( "Submittable::read_state failed for rid : " + name());
- }
- else if (lineTokens[i].find("try:") != std::string::npos ) {
- std::string try_number;
- if (!Extract::split_get_second(lineTokens[i],try_number))
- throw std::runtime_error( "Submittable::read_state failed for try number : " + name());
- tryNo_ = Extract::theInt(try_number,"Submittable::read_state failed for try number");
- }
- }
-
- // extract aborted reason
- // The line tokens will truncate multiple spaces into a single space chars
- // Hence use the line to extract the abort reason: This will preserve spaces
- size_t first_pos = line.find("abort<:");
- size_t last_pos = line.find(">abort");
- if (first_pos != std::string::npos) {
- if ( last_pos != std::string::npos) {
- abortedReason_ = line.substr(first_pos+7, (last_pos-first_pos-7) );
- }
- else {
- throw std::runtime_error("Submittable::read_state failed for abort reason. Expected abort reason to on single line;");
- }
- }
-
- Node::read_state(line,lineTokens);
-}
-
-
-bool Submittable::operator==(const Submittable& rhs) const
-{
- if ( jobsPassword_ != rhs.jobsPassword_ ) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Submittable::operator== jobsPassword_(" << jobsPassword_ << ") != rhs.jobsPassword_(" << rhs.jobsPassword_ << ") " << debugNodePath() << "\n";
- std::cout << "Submittable::operator== state(" << NState::toString(state()) << ") rhs.state(" << NState::toString(rhs.state()) << ") \n";
- // No point dumping out change numbers, since we don't persist them, hence values will always be zero on client side.
- }
-#endif
- return false;
- }
-
- if ( process_or_remote_id_ != rhs.process_or_remote_id_ ) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Submittable::operator== process_or_remote_id_(" << process_or_remote_id_ << ") != rhs.process_or_remote_id_(" << rhs.process_or_remote_id_ << ") " << debugNodePath() << "\n";
- }
-#endif
- return false;
- }
-
- if ( tryNo_ != rhs.tryNo_ ) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Submittable::operator== tryNo_(" << tryNo_ << ") != rhs.tryNo_(" << rhs.tryNo_ << ") " << debugNodePath() << "\n";
- }
-#endif
- return false;
- }
-
- if ( abortedReason_ != rhs.abortedReason_ ) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Submittable::operator== abortedReason_(" << abortedReason_ << ") != rhs.abortedReason_(" << rhs.abortedReason_ << ") " << debugNodePath() << "\n";
- }
-#endif
- return false;
- }
-
- return Node::operator==(rhs);
-}
-
-string Submittable::tryNo() const
-{
- try {
- return boost::lexical_cast< string >( tryNo_ );
- }
- catch ( boost::bad_lexical_cast& e ) {}
-
- LOG_ASSERT(false,"Submittable::tryNo() corrupt?");
- return string();
-}
-
-
-EcfFile Submittable::locatedEcfFile() const
-{
- // Look for scripts file(Task->.ecf | Alias->.usr) in the following order
- // o/ ECF_SCRIPT Generated VARIABLE absolute path, check if files exists
- // The variable MUST exist, but the file may not
- // o/ ECF_FETCH (user variable)
- // if this variable exist, we need to flag it, somehow
- // So that when we open the sms file, we use popen.
- // o/ ECF_FILES (Typically in the definition file, defines a directory)
- // o/ ECF_HOME
- std::string reasonEcfFileNotFound;
- std::string theAbsNodePath = absNodePath();
- std::string ecf_home;
- findParentUserVariableValue( Str::ECF_HOME(), ecf_home);
-
- /// Update local ECF_SCRIPT variable, ECF_SCRIPT is a generated variable. IT *MUST* exist
- const Variable& genvar_ecfscript = update_genvar_ecfscript(ecf_home,theAbsNodePath);
-
-#ifdef DEBUG_TASK_LOCATION
- std::cout << "Submittable::locatedEcfFile() Submittable " << name() << " searching ECF_SCRIPT = '" << genvar_ecfscript.theValue() << "'\n";
-#endif
- if ( fs::exists( genvar_ecfscript.theValue() ) ) {
-#ifdef DEBUG_TASK_LOCATION
- std::cout << "Submittable::locatedEcfFile() Submittable " << name() << " ECF_SCRIPT = '" << genvar_ecfscript.theValue() << "' exists\n";
-#endif
- return EcfFile( const_cast<Submittable*>(this), genvar_ecfscript.theValue() );
- }
- else {
- std::stringstream ss; ss << " ECF_SCRIPT(" << genvar_ecfscript.theValue() << ") does not exist:\n";
- reasonEcfFileNotFound += ss.str();
- }
-
- // Caution: This is not used in operations or research, equally is has not been tested.
- // Need to test or remove.
- std::string smsFetchCmd;
- findParentVariableValue( Str::ECF_FETCH(), smsFetchCmd );
- if ( !smsFetchCmd.empty() ) {
-#ifdef DEBUG_TASK_LOCATION
- std::cout << "Submittable::locatedEcfFile() Submittable " << name() << " ECF_FETCH = '" << smsFetchCmd << "' variable exists\n";
-#endif
- if (variableSubsitution(smsFetchCmd)) {
- return EcfFile( const_cast<Submittable*>(this), smsFetchCmd, true/*is a command*/);
- }
- else {
- std::stringstream ss; ss << " Variable ECF_FETCH(" << smsFetchCmd << ") defined, but variable substitution has failed:\n";
- reasonEcfFileNotFound += ss.str();
- throw std::runtime_error( reasonEcfFileNotFound ) ;
- }
- }
- else {
- reasonEcfFileNotFound += " Variable ECF_FETCH not defined:\n";
- }
-
-
- std::string ecf_filesDirectory ;
- if (findParentUserVariableValue( Str::ECF_FILES() , ecf_filesDirectory)) {
-#ifdef DEBUG_TASK_LOCATION
- std::cout << "Submittable::locatedEcfFile() Submittable " << name() << " searching ECF_FILES = '" << ecf_filesDirectory << "' backwards\n";
-#endif
- if ( !ecf_filesDirectory.empty() && fs::exists( ecf_filesDirectory ) && fs::is_directory( ecf_filesDirectory ) )
- {
- // If File::backwardSearch fails it returns an empty string, i.e failure to locate script (Task/.ecf || Alias/.usr) file
- std::string searchResult = File::backwardSearch( ecf_filesDirectory, theAbsNodePath, script_extension() );
- if ( searchResult.empty()) {
- std::stringstream ss; ss << " Search of directory ECF_FILES(" << ecf_filesDirectory << ") failed:\n";
- reasonEcfFileNotFound += ss.str();
- }
- else {
- return EcfFile(const_cast<Submittable*>(this), searchResult);
- }
- }
- else {
- std::stringstream ss; ss << " Directory ECF_FILES(" << ecf_filesDirectory << ") does not exist:\n";
- reasonEcfFileNotFound += ss.str();
- }
- }
- else {
- reasonEcfFileNotFound += " Variable ECF_FILES not defined:\n";
- }
-
-
-#ifdef DEBUG_TASK_LOCATION
- std::cout << "Submittable::locatedEcfFile() Submittable " << name() << " searching ECF_HOME = '" << ecf_home << "' backwards\n";
-#endif
- if ( !ecf_home.empty() && fs::exists( ecf_home ) && fs::is_directory( ecf_home ) )
- {
- // If File::backwardSearch fails it returns an empty string, i.e failure to locate script (Task/.ecf || Alias/.usr) file
- std::string searchResult = File::backwardSearch( ecf_home, theAbsNodePath, script_extension() );
- if ( searchResult.empty()) {
- std::stringstream ss; ss << " Search of directory ECF_HOME(" << ecf_home << ") failed:\n";
- reasonEcfFileNotFound += ss.str();
- }
- else {
- return EcfFile(const_cast<Submittable*>(this), searchResult);
- }
- }
- else {
- std::stringstream ss; ss << " Directory ECF_HOME(" << ecf_home << ") does not exist:\n";
- reasonEcfFileNotFound += ss.str();
- }
-
- // failed to find .ecf file
- std::stringstream ss;
- ss << " Script for " << theAbsNodePath << " can not be found:\n" << reasonEcfFileNotFound;
- throw std::runtime_error( ss.str() ) ;
-}
-
-void Submittable::set_jobs_password(const std::string& p)
-{
- jobsPassword_ = p;
- state_change_no_ = Ecf::incr_state_change_no();
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Submittable::set_jobs_password\n";
-#endif
-}
-
-void Submittable::increment_try_no()
-{
- // EVERY time we SUBMIT a job we must:
- // o generate a password, and hence updated generated variable ECF_PASS
- // o increment the try number
- // This means we also need to regenerate the variables
- // since ECF_TRYNO , ECF_JOB, ECF_JOBOUT depend on the try number.
- // ALSO ECF_RID is updated with empty string
- // o Clear the process/remote id. These will be reset by the child commands
- // *** This MUST be done before pre-processing as it uses these variables ***
- tryNo_++;
- process_or_remote_id_.clear();
- abortedReason_.clear();
- jobsPassword_ = Passwd::generate();
- state_change_no_ = Ecf::incr_state_change_no();
- update_generated_variables();
-}
-
-void Submittable::clear()
-{
- abortedReason_.clear(); // reset reason aborted
- jobsPassword_.clear(); // reset password, it will be regenerated before submission
- process_or_remote_id_.clear();// reset process id
- state_change_no_ = Ecf::incr_state_change_no();
-}
-
-bool Submittable::submitJob( JobsParam& jobsParam)
-{
- increment_try_no();
-
- return submit_job_only(jobsParam);
-}
-
-bool Submittable::submit_job_only( JobsParam& jobsParam)
-{
-#ifdef DEBUG_JOB_SUBMISSION
- cerr << "Submittable::submit_job_only for task " << name() << endl;
-#endif
-
- if (state() == NState::ACTIVE || state() == NState::SUBMITTED ) {
- std::stringstream ss;
- ss << "Submittable::submit_job_only: failed: Submittable " << absNodePath() << " is already " << NState::toString(state()) << " : ";
- jobsParam.errorMsg() += ss.str();
- flag().set(ecf::Flag::EDIT_FAILED);
- return false;
- }
-
- // If the task is a dummy task, return true
- std::string theValue;
- if (findParentUserVariableValue(Str::ECF_DUMMY_TASK(),theValue)) {
- return true;
- }
-
- // state change
- flag().clear(ecf::Flag::NO_SCRIPT);
- flag().clear(ecf::Flag::EDIT_FAILED);
- flag().clear(ecf::Flag::JOBCMD_FAILED);
- requeue_labels(); // ECFLOW-195, requeue no longer resets labels on tasks, hence we do it at task run time.
-
- try {
- // Locate the ecf files corresponding to the jobs.
- EcfFile ecf_file = locatedEcfFile();
-
- // Pre-process sms file (i.e expand includes, remove comments,manual) and perform
- // variable substitution. This will then form the '.job' files.
- // If the job file already exist it is overridden
- try {
- const std::string& job_size = ecf_file.create_job( jobsParam );
-
- //... make sure ECF_PASS is set on the task, This is substituted in <head.h> file
- //... and hence must be done before variable substitution in ECF_/JOB file
- //... This is used by client->server authentication
- if (createChildProcess(jobsParam)) {
- set_state(NState::SUBMITTED, false, job_size );
- return true;
- }
-
- // Fall through job submission failed.
- }
- catch ( std::exception& e) {
- flag().set(ecf::Flag::EDIT_FAILED);
- std::string reason = "Submittable::submit_job_only: Job creation failed for task ";
- reason += absNodePath();
- reason += " : \n ";
- reason += e.what();
- reason += "\n";
- jobsParam.errorMsg() += reason;
- set_aborted_only( reason );
- return false;
- }
- }
- catch (std::exception& e) {
-
- flag().set(ecf::Flag::NO_SCRIPT);
- std::stringstream ss; ss << "Submittable::submit_job_only: Script location failed for task " << absNodePath() << " :\n" << e.what() << "\n";
- jobsParam.errorMsg() += ss.str();
- set_aborted_only( e.what() ); // remember jobsParam.errorMsg() is accumulated
- return false;
- }
-
- flag().set(ecf::Flag::JOBCMD_FAILED);
- std::string reason = " Job creation failed for task ";
- reason += absNodePath();
- reason += " could not create child process.";
- jobsParam.errorMsg() += reason;
- set_aborted_only( reason );
- return false;
-}
-
-
-void Submittable::check_job_creation( job_creation_ctrl_ptr jobCtrl)
-{
- // Typically a valid try number is >=1.
- // Since check_job_creation is only used for testing/python, we will initialise tryNum to -1
- // so than when it is incremented it will by a try_no of zero. *zero is an invalid try_no *
- tryNo_ = -1;
-
- /// call just before job submission, reset data members, update try_no, and *** generate variable ***
- increment_try_no();
-
- if ( !jobCtrl->dir_for_job_creation().empty() ) {
- /// Override ECF_JOB, can be done by either adding a new user variable of same name
- /// or the generated variable. We choose generated, since this is automatically reset.
- /// before a real job submission
- std::string tmpLocationForJob = jobCtrl->dir_for_job_creation();
- tmpLocationForJob += absNodePath();
- tmpLocationForJob += File::JOB_EXTN();
- tmpLocationForJob += "0"; // try number of zero ( i.e an invalid try number)
- set_genvar_ecfjob(tmpLocationForJob);
- }
-
- JobsParam jobsParam; // create jobs = false, spawn jobs = false
- if ( submit_job_only(jobsParam) ) {
- return;
- }
-
- std::string errorMsg = jobsParam.getErrorMsg();
- LOG_ASSERT( !errorMsg.empty(), "failing to submit must raise an error message" );
-
- jobCtrl->error_msg() += errorMsg;
- jobCtrl->push_back_failing_submittable( dynamic_pointer_cast<Submittable>(shared_from_this()) );
-}
-
-bool Submittable::run(JobsParam& jobsParam, bool force)
-{
- if (force || ((state() != NState::SUBMITTED) && (state() != NState::ACTIVE))) {
-
- if ( jobsParam.createJobs() ) {
-
- return submitJob(jobsParam);
- }
- else {
- /// This is only for test path. Just return true
- return true;
- }
- }
- std::stringstream ss;
- ss << "Submittable::run: Aborted for task " << absNodePath() << " because state is " << NState::toString(state()) << " and force not set\n";
- jobsParam.errorMsg() += ss.str();
- return false;
-}
-
-void Submittable::kill(const std::string& zombie_pid)
-{
- std::string ecf_kill_cmd;
- if ( zombie_pid.empty() ) {
- if (state() != NState::ACTIVE && state() != NState::SUBMITTED) {
- return;
- }
-
- // *** Generated variables are *NOT* persisted. ***
- // *** Hence if we have recovered from a check point file, then they will be empty. ***
- // *** i.e terminate server with active jobs, restart from saved check_pt file
- // *** and then try to kill the active job, will get an exception( see below) since
- // *** Generated variable ECF_RID will be empty.
- if (!sub_gen_variables_) {
- // std::cout << "Generated variables empty, regenerating !!!!!\n";
- update_generated_variables();
- }
-
- /// If we are in active state, then ECF_RID must have been setup
- /// This is typically used in the KILL CMD, make sure its there
- if (state() == NState::ACTIVE && genvar_ecfrid().theValue().empty() ) {
- std::stringstream ss;
- ss << "Submittable::kill: Generated variable ECF_RID is empty for task " << absNodePath();
- throw std::runtime_error( ss.str() );
- }
-
- if (!findParentUserVariableValue( Str::ECF_KILL_CMD(), ecf_kill_cmd ) || ecf_kill_cmd.empty() ) {
- std::stringstream ss;
- ss << "Submittable::kill: ECF_KILL_CMD not defined, for task " << absNodePath() << "\n";
- throw std::runtime_error( ss.str() );
- }
- }
- else {
- // Use input
- if (!findParentUserVariableValue( Str::ECF_KILL_CMD(), ecf_kill_cmd ) || ecf_kill_cmd.empty() ) {
- std::stringstream ss;
- ss << "Submittable::kill: ECF_KILL_CMD not defined, for task " << absNodePath() << "\n";
- throw std::runtime_error( ss.str() );
- }
-
- // replace %ECF_RID% with the input args
- Str::replace(ecf_kill_cmd,"%ECF_RID%", zombie_pid);
- }
-
- if (!variableSubsitution(ecf_kill_cmd)) {
- std::stringstream ss;
- ss << "Submittable::kill: Variable substitution failed for ECF_KILL_CMD(" << ecf_kill_cmd << ") on task " << absNodePath() << "\n";
- throw std::runtime_error( ss.str() );
- }
-
- // Please note: this is *non blocking* the output of the command(ECF_KILL_CMD) should be written to %ECF_JOB%.kill
- // The output is accessible via the --file cmd
- // Done as two separate steps as kill command is not blocking on the server
-// LOG(Log::DBG,"Submittable::kill " << absNodePath() << " " << ecf_kill_cmd );
- std::string errorMsg;
- if (!System::instance()->spawn(ecf_kill_cmd,"", errorMsg)) {
- throw std::runtime_error( errorMsg );
- }
- flag().set(ecf::Flag::KILLED);
-}
-
-void Submittable::status()
-{
- if (state() != NState::ACTIVE && state() != NState::SUBMITTED) {
- return;
- }
-
- // *** Generated variables are *NOT* persisted. ***
- // *** Hence if we have recovered from a check point file, then they will be empty. ***
- // *** i.e terminate server with active jobs, restart from saved check_pt file
- // *** and then try to kill/status the active job, will get an exception(see below) since
- // *** Generated variable ECF_RID will be empty.
- if (!sub_gen_variables_) {
- //std::cout << "Generated variables empty, regenerating !!!!!\n";
- update_generated_variables();
- }
-
- /// If we are in active state, then ECF_RID must have been setup
- if (state() == NState::ACTIVE && genvar_ecfrid().theValue().empty()) {
- std::stringstream ss;
- ss << "Submittable::status: Generated variable ECF_RID is empty for task " << absNodePath();
- throw std::runtime_error( ss.str() );
- }
-
- std::string ecf_status_cmd;
- if (!findParentUserVariableValue( Str::ECF_STATUS_CMD(), ecf_status_cmd ) || ecf_status_cmd.empty() ) {
- std::stringstream ss;
- ss << "Submittable::status: ECF_STATUS_CMD not defined, for task " << absNodePath() << "\n";
- throw std::runtime_error( ss.str() );
- }
-
- if (!variableSubsitution(ecf_status_cmd)) {
- std::stringstream ss;
- ss << "Submittable::status: Variable substitution failed for ECF_STATUS_CMD(" << ecf_status_cmd << ") on task " << absNodePath() << "\n";
- throw std::runtime_error( ss.str() );
- }
-
- // Please note: this is *non blocking* the output of the command(ECF_STATUS_CMD) should be written to %ECF_JOB%.stat
- // SPAWN process, attach signal to monitor process. returns true
- std::string errorMsg;
- if (!System::instance()->spawn(ecf_status_cmd,"", errorMsg)) {
- throw std::runtime_error( errorMsg );
- }
-
-// flag().set(ecf::Flag::STATUS);
-}
-
-
-bool Submittable::createChildProcess(JobsParam& jobsParam)
-{
-#ifdef DEBUG_JOB_SUBMISSION
- cout << "Submittable::createChildProcess for task " << name() << endl;
-#endif
- std::string ecf_job_cmd;
- findParentUserVariableValue( Str::ECF_JOB_CMD(), ecf_job_cmd );
- if (ecf_job_cmd.empty()) {
- jobsParam.errorMsg() += "Submittable::createChildProcess: Could not find ECF_JOB_CMD : ";
- return false;
- }
-
- if (!variableSubsitution(ecf_job_cmd)) {
- jobsParam.errorMsg() += "Submittable::createChildProcess: Variable substitution failed for ECF_JOB_CMD(" + ecf_job_cmd + ") :";
- return false;
- }
-
- // Keep tabs on what was submitted for testing purposes
- jobsParam.push_back_submittable( this );
-
- if ( jobsParam.spawnJobs() ) {
-
- // SPAWN process, attach signal to monitor process. returns true
- return System::instance()->spawn(ecf_job_cmd,absNodePath(),jobsParam.errorMsg());
- }
-
- // Test path ONLY
- return true;
-}
-
-
-void Submittable::set_aborted_only(const std::string& reason)
-{
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Submittable::set_aborted_only\n";
-#endif
-
- abortedReason_ = reason;
- state_change_no_ = Ecf::incr_state_change_no();
-
- // Do not use "\n" | ';' in abortedReason_, as this can mess up, --migrate output
- // Which would then affect --load.
- Str::replace(abortedReason_,"\n","");
- Str::replace(abortedReason_,";"," ");
-
- // This will set the state and bubble up the most significant state
- set_state(NState::ABORTED);
-}
-
-
-void Submittable::update_limits()
-{
- NState::State task_state = state();
- std::set<Limit*> limitSet; // ensure local limit have preference over parent
- if (task_state == NState::COMPLETE) {
- decrementInLimit(limitSet); // will recurse up
- }
- else if (task_state == NState::ABORTED) {
- decrementInLimit(limitSet); // will recurse up
- }
- else if (task_state == NState::SUBMITTED) {
- incrementInLimit(limitSet); // will recurse up
- }
- else if (task_state == NState::ACTIVE) {
- // *** Don't change limits in this state ***
- }
- else {
- // UNKNOWN, QUEUED
- // For all other states, this task should NOT be consuming a limit token.
- // During interactive use a Submittable may get re-queued. In case its consuming
- // a limit token, we decrement the limit. If the we are NOT consuming
- // a token, its still *SAFE* to call decrementInLimit
- decrementInLimit(limitSet); // will recurse up
- }
-}
-
-// Memento ==========================================================
-void Submittable::incremental_changes(DefsDelta& changes, compound_memento_ptr& comp) const
-{
-#ifdef DEBUG_MEMENTO
- std::cout << "Submittable::incremental_changes() " << debugNodePath() << "\n";
-#endif
-
- if (state_change_no_ > changes.client_state_change_no()) {
- if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
- comp->add( boost::make_shared<SubmittableMemento>( jobsPassword_,process_or_remote_id_,abortedReason_,tryNo_) );
- }
-
- // ** if compound memento has children base class, will add it to DefsDelta
- Node::incremental_changes(changes,comp);
-}
-
-void Submittable::set_memento(const SubmittableMemento* memento)
-{
-#ifdef DEBUG_MEMENTO
- std::cout << "Submittable::set_memento(const SubmittableMemento*) " << debugNodePath() << "\n";
-#endif
-
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::SUBMITTABLE);
-
- jobsPassword_ = memento->jobsPassword_;
- process_or_remote_id_ = memento->process_or_remote_id_;
- abortedReason_ = memento->abortedReason_;
- tryNo_ = memento->tryNo_;
-}
-
-// Generated variables ---------------------------------------------------------------------------------
-
-void Submittable::update_generated_variables() const
-{
- if (!sub_gen_variables_) sub_gen_variables_ = new SubGenVariables(this);
- sub_gen_variables_->update_generated_variables();
- update_repeat_genvar();
-}
-
-const Variable& Submittable::update_genvar_ecfscript( const std::string& ecf_home, const std::string& theAbsNodePath) const
-{
- if (!sub_gen_variables_) sub_gen_variables_ = new SubGenVariables(this);
- return sub_gen_variables_->update_genvar_ecfscript(ecf_home,theAbsNodePath);
-}
-
-const Variable& Submittable::findGenVariable(const std::string& name) const
-{
- // AST can reference generated variables. Currently integer based values
- // The task names can be integers, other valid option is try_no
- if (!sub_gen_variables_) update_generated_variables();
-
- const Variable& gen_var = sub_gen_variables_->findGenVariable(name);
- if (!gen_var.empty()) return gen_var;
-
- return Node::findGenVariable(name);
-}
-
-void Submittable::gen_variables(std::vector<Variable>& vec) const
-{
- if (!sub_gen_variables_) update_generated_variables();
-
- vec.reserve(vec.size() + 9);
- sub_gen_variables_->gen_variables(vec);
- Node::gen_variables(vec);
-}
-
-const Variable& Submittable::genvar_ecfrid() const
-{
- if (!sub_gen_variables_) return Variable::EMPTY();
- return sub_gen_variables_->genvar_ecfrid();
-}
-
-void Submittable::set_genvar_ecfjob(const std::string& value)
-{
- if (!sub_gen_variables_) sub_gen_variables_ = new SubGenVariables(this);
- sub_gen_variables_->set_genvar_ecfjob(value);
-}
-
-void Submittable::set_genvar_ecfrid(const std::string& value)
-{
- if (!sub_gen_variables_) sub_gen_variables_ = new SubGenVariables(this);
- sub_gen_variables_->set_genvar_ecfrid(value);
-}
-
-// Generated Variables ================================================================================================
-// The false below is used as a dummy argument to call the Variable constructor that does not
-// Check the variable names. i.e we know they are valid
-SubGenVariables::SubGenVariables(const Submittable* sub)
-: submittable_(sub),
- genvar_task_("TASK", "", false),
- genvar_ecfrid_(Str::ECF_RID(), "", false),
- genvar_ecftryno_(Str::ECF_TRYNO(), "", false),
- genvar_ecfname_(Str::ECF_NAME(), "", false),
- genvar_ecfpass_(Str::ECF_PASS(), "", false),
- genvar_ecfjob_(Str::ECF_JOB(), "", false),
- genvar_ecfjobout_(Str::ECF_JOBOUT(), "", false),
- genvar_ecfscript_(Str::ECF_SCRIPT(), "", false) {}
-
-void SubGenVariables::update_generated_variables() const
-{
- // cache strings that are used in many variables
- std::string theAbsNodePath = submittable_->absNodePath();
- std::string the_try_no = submittable_->tryNo();
-
- if (submittable_->isAlias() && submittable_->parent())
- genvar_task_.set_value(submittable_->parent()->name()); // does *not* modify Variable::state_change_no
- else
- genvar_task_.set_value(submittable_->name());
-
- genvar_ecfrid_.set_value(submittable_->process_or_remote_id_); // does *not* modify Variable::state_change_no
- genvar_ecftryno_.set_value(the_try_no); // does *not* modify Variable::state_change_no
- genvar_ecfname_.set_value(theAbsNodePath); // does *not* modify Variable::state_change_no
- genvar_ecfpass_.set_value(submittable_->jobsPassword_); // does *not* modify Variable::state_change_no
-
- std::string ecf_home;
- submittable_->findParentUserVariableValue(Str::ECF_HOME(), ecf_home);
-
- /// The directory associated with ECF_JOB is automatically created if it does not exist.
- /// This is Done during Job generation. See EcfFile::doCreateJobFile()
- if (genvar_ecfjob_.value_by_ref().capacity() == 0) {
- genvar_ecfjob_.value_by_ref().reserve( ecf_home.size() + theAbsNodePath.size() + File::JOB_EXTN().size() + the_try_no.size());
- }
- genvar_ecfjob_.value_by_ref() = ecf_home; // does *not* modify Variable::state_change_no
- genvar_ecfjob_.value_by_ref() += theAbsNodePath;
- genvar_ecfjob_.value_by_ref() += File::JOB_EXTN();
- genvar_ecfjob_.value_by_ref() += the_try_no;
-
-
- /// If ECF_OUT is specified the user must ensure the directory exists, along with directories
- /// associated with Suites/Families nodes.
- /// Bottom up. Can be expensive when we have thousands of tasks.
- std::string ecf_out;
- submittable_->findParentUserVariableValue(Str::ECF_OUT(), ecf_out);
-
- if (ecf_out.empty()) {
- genvar_ecfjobout_.value_by_ref().reserve( ecf_home.size() + theAbsNodePath.size() + 1 + the_try_no.size());
- genvar_ecfjobout_.value_by_ref() = ecf_home;
- }
- else {
- // For metabuilder, where we use %ECF_HOME% for ECF_OUT
- char micro = '%';
- if (ecf_out.find(micro) != std::string::npos) {
- NameValueMap user_edit_variables;
- submittable_->variable_substitution(ecf_out,user_edit_variables,micro);
- }
- genvar_ecfjobout_.value_by_ref().reserve( ecf_out.size() + theAbsNodePath.size() + 1 + the_try_no.size());
- genvar_ecfjobout_.value_by_ref() = ecf_out;
- }
- genvar_ecfjobout_.value_by_ref() += theAbsNodePath;
- genvar_ecfjobout_.value_by_ref() += ".";
- genvar_ecfjobout_.value_by_ref() += the_try_no;
-
- (void)update_genvar_ecfscript(ecf_home,theAbsNodePath);
-}
-
-const Variable& SubGenVariables::update_genvar_ecfscript( const std::string& ecf_home, const std::string& theAbsNodePath) const
-{
- genvar_ecfscript_.value_by_ref().reserve( ecf_home.size() + theAbsNodePath.size() + 4 );
- genvar_ecfscript_.value_by_ref() = ecf_home; // does *not* modify Variable::state_change_no
- genvar_ecfscript_.value_by_ref() += theAbsNodePath;
- genvar_ecfscript_.value_by_ref() += submittable_->script_extension();
- return genvar_ecfscript_;
-}
-
-const Variable& SubGenVariables::findGenVariable(const std::string& name) const
-{
- if (genvar_task_.name() == name) return genvar_task_;
- if (genvar_ecftryno_.name() == name) return genvar_ecftryno_;
- if (genvar_ecfjob_.name() == name) return genvar_ecfjob_;
- if (genvar_ecfscript_.name() == name) return genvar_ecfscript_;
- if (genvar_ecfjobout_.name() == name) return genvar_ecfjobout_;
- if (genvar_ecfrid_.name() == name) return genvar_ecfrid_;
- if (genvar_ecfname_.name() == name) return genvar_ecfname_;
- if (genvar_ecfpass_.name() == name) return genvar_ecfpass_;
- return Variable::EMPTY();
-}
-
-void SubGenVariables::gen_variables(std::vector<Variable>& vec) const
-{
- vec.push_back(genvar_task_);
- vec.push_back(genvar_ecfjob_);
- vec.push_back(genvar_ecfscript_);
- vec.push_back(genvar_ecfjobout_);
- vec.push_back(genvar_ecftryno_);
- vec.push_back(genvar_ecfrid_);
- vec.push_back(genvar_ecfname_);
- vec.push_back(genvar_ecfpass_);
-}
diff --git a/ecflow_4_0_7/ANode/src/Submittable.hpp b/ecflow_4_0_7/ANode/src/Submittable.hpp
deleted file mode 100644
index 917bbc3..0000000
--- a/ecflow_4_0_7/ANode/src/Submittable.hpp
+++ /dev/null
@@ -1,196 +0,0 @@
-#ifndef SUBMITTABLE_HPP_
-#define SUBMITTABLE_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #16 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <boost/noncopyable.hpp>
-#include "Node.hpp"
-class EcfFile;
-class SubGenVariables;
-
-class Submittable : public Node {
-protected:
- Submittable( const std::string& name )
- : Node(name),
- jobsPassword_(Submittable::DUMMY_JOBS_PASSWORD()),
- tryNo_(0),
- state_change_no_(0),
- sub_gen_variables_(NULL) {}
-
- Submittable()
- : jobsPassword_(Submittable::DUMMY_JOBS_PASSWORD()),
- tryNo_(0),
- state_change_no_(0),
- sub_gen_variables_(NULL) {}
-
- bool operator==(const Submittable& rhs) const;
-
-public:
- virtual ~Submittable();
-
- /// Initialise the task. will set the state to NState::ACTIVE
- void init(const std::string& processId);
-
- /// complete the task. Will set the state to NState::COMPLETE
- /// However if there is a valid Repeat or time dependencies then
- /// task will be re-queued afterwards
- void complete();
-
- /// Overridden to reset the try number
- /// The tasks job can be invoked multiple times. For each invocation we want to preserve
- /// the output. The try number is used in SMSJOB/SMSJOBOUT to preserve the output when
- /// there are multiple runs. re-queue/begin() resets the try Number
- virtual void begin();
- virtual void requeue( bool resetRepeats,
- int clear_suspended_in_child_nodes,
- bool reset_next_time_slot);
- virtual bool run(JobsParam& jobsParam, bool force);
- virtual void kill(const std::string& zombie_pid = "");
- virtual void status();
-
- virtual void update_generated_variables() const;
- virtual const Variable& findGenVariable(const std::string& name) const;
- virtual void gen_variables(std::vector<Variable>& vec) const;
-
-
- static const std::string& DUMMY_JOBS_PASSWORD();
- static const std::string& FREE_JOBS_PASSWORD();
- static const std::string& DUMMY_PROCESS_OR_REMOTE_ID();
-
- // returns the corresponding .ecf file.
- // i.e if the ecf file is missing or empty std::runtime_error is thrown
- // For dummy tasks, i.e tasks with no .ecf file user should add ECF_DUMMY_TASK variable
- EcfFile locatedEcfFile() const;
- virtual const std::string& script_extension() const = 0;
-
- /// Spawn of a child process. Clear process and remote id before jobs is spawned
- /// Will increment try no first, and then update generated varaibles
- bool submitJob( JobsParam& ) ;
-
- /// generates job file independent of dependencies, resets the try Number
- virtual void check_job_creation( job_creation_ctrl_ptr jobCtrl);
-
- /// See Defs.hpp
- virtual void generate_scripts( const std::map<std::string,std::string>&) const {}
-
- virtual NState::State computedState(Node::TraverseType) const { return state();}
-
-/// data members accessor's and mutators:
- /// return the current try number as a string, and int
- std::string tryNo() const;
- int try_no() const { return tryNo_;}
-
- const std::string& jobsPassword() const { return jobsPassword_;}
-
- /// The remote id (ECF_RID) allows a jobs to be killed when added via a queueing system
- /// in which case the remote id is really the queueing id.
- const std::string& process_or_remote_id() const { return process_or_remote_id_;}
-
- /// Set the task to aborted, providing a reason. Will set the state to NState::ABORTED
- /// This should only be called in two context's:
- /// 1/ Called via Child Cmd (AbortCmd) i.e job raised a trap,
- /// 2/ Abnormal process termination. i.e job killed by signal
- /// *IMPORTANT* If task try number is less than ECF_TRIES then we should
- /// resubmit the job. However we *should* not do this immediately here, instead we
- /// wait of *next* call to resolveDependencies, as that will check if we are *inlimit*
- void aborted(const std::string& reason);
- virtual const std::string& abortedReason() const { return abortedReason_;}
-
-// Memento functions:
- void incremental_changes(DefsDelta&, compound_memento_ptr& comp) const;
- void set_memento(const SubmittableMemento* );
-
- virtual void read_state(const std::string& line,const std::vector<std::string>& lineTokens);
-protected:
-
- virtual std::string write_state() const;
- /// call just before job submission, reset data members, update try_no, and generate variable
- void increment_try_no(); // will increment state_change_no
-
- /// Submits the job *WITHOUT* incrementing the try number
- bool submit_job_only( JobsParam& );
-
- // Overridden from Node to increment/decrement limits
- virtual void update_limits();
-
-private:
- friend class ZombieCtrl;
- friend class AlterCmd;
-
- void set_jobs_password(const std::string& p);
-
- void set_process_or_remote_id(const std::string&);
-
- // Use when we _only_ want to set the state,
- void set_aborted_only(const std::string& reason);
-
- bool createChildProcess(JobsParam& jobsParam);
-
- void clear(); // process_id password and aborted reason
-
- const Variable& update_genvar_ecfscript( const std::string& ecf_home,const std::string& theAbsNodePath) const;
- const Variable& genvar_ecfrid() const;
- void set_genvar_ecfjob(const std::string& value);
- void set_genvar_ecfrid(const std::string& value);
-
-private:
- std::string jobsPassword_;
- std::string process_or_remote_id_;
- std::string abortedReason_;
- int tryNo_;
- unsigned int state_change_no_; // *not* persisted, only used on server side
- mutable SubGenVariables* sub_gen_variables_; // *not* persisted since they can be generated
- friend class SubGenVariables;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/) {
- ar & boost::serialization::base_object<Node>(*this); // Serialise base class information
- ar & jobsPassword_;
- ar & process_or_remote_id_;
- ar & abortedReason_;
- ar & tryNo_;
- }
-};
-
-// We can have several thousands Submittables. This class helps in avoiding
-// the creation of generated variables until required.
-// This improves client->server down load times by avoiding thousands of string constructions
-class SubGenVariables : private boost::noncopyable {
-public:
- SubGenVariables(const Submittable*);
-
- void update_generated_variables() const;
- const Variable& findGenVariable(const std::string& name) const;
- void gen_variables(std::vector<Variable>& vec) const;
- const Variable& update_genvar_ecfscript( const std::string& ecf_home, const std::string& theAbsNodePath) const;
-
- const Variable& genvar_ecfrid() const { return genvar_ecfrid_;}
-
- void set_genvar_ecfjob(const std::string& value) { genvar_ecfjob_.set_value(value); }
- void set_genvar_ecfrid(const std::string& value) { genvar_ecfrid_.set_value(value); }
-
-private:
- const Submittable* submittable_;
- mutable Variable genvar_task_;
- mutable Variable genvar_ecfrid_;
- mutable Variable genvar_ecftryno_;
- mutable Variable genvar_ecfname_;
- mutable Variable genvar_ecfpass_;
- mutable Variable genvar_ecfjob_;
- mutable Variable genvar_ecfjobout_;
- mutable Variable genvar_ecfscript_;
-};
-
-#endif
diff --git a/ecflow_4_0_7/ANode/src/Suite.cpp b/ecflow_4_0_7/ANode/src/Suite.cpp
deleted file mode 100644
index 87c6cd1..0000000
--- a/ecflow_4_0_7/ANode/src/Suite.cpp
+++ /dev/null
@@ -1,727 +0,0 @@
-//============================================================================
-// Name : NodeTree.cpp
-// Author : Avi
-// Revision : $Revision: #128 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <assert.h>
-#include <sstream>
-#include <boost/lexical_cast.hpp>
-#include <boost/make_shared.hpp>
-
-#include "Suite.hpp"
-#include "Defs.hpp"
-#include "PrintStyle.hpp"
-#include "NodeTreeVisitor.hpp"
-#include "DefsDelta.hpp"
-
-#include "Stl.hpp"
-#include "Str.hpp"
-#include "Ecf.hpp"
-#include "Indentor.hpp"
-#include "ExprAst.hpp"
-#include "Log.hpp"
-#include "CalendarUpdateParams.hpp"
-#include "SuiteChanged.hpp"
-#include "ChangeMgrSingleton.hpp"
-#include "JobProfiler.hpp"
-#include "JobsParam.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost::posix_time;
-
-///////////////////////////////////////////////////////////////////////////////////////////
-//#define DEBUG_FIND_NODE 1
-
-// Create the generated variable up-front. This allows them to be referenced
-// is abstract syntax tree during the post process call
-
-
-Suite::~Suite()
-{
-// std::cout << "Suite::~Suite() " << debugNodePath() << "\n";
- // Don't create the ChangeMgrSingleton during destruct sequence. (i.e in unit cases)
- // Since that will cause a memory leak
- if (!Ecf::server() && ChangeMgrSingleton::exists()) {
- ChangeMgrSingleton::instance()->notify_delete( this );
- }
- delete suite_gen_variables_;
-}
-
-suite_ptr Suite::create(const std::string& name)
-{
- return boost::make_shared<Suite>( name );
-}
-
-void Suite::accept(ecf::NodeTreeVisitor& v)
-{
- SuiteChanged1 changed(this);
- v.visitSuite(this);
- NodeContainer::accept(v);
-}
-
-void Suite::acceptVisitTraversor(ecf::NodeTreeVisitor& v)
-{
- SuiteChanged1 changed(this);
- v.visitSuite(this);
-}
-
-void Suite::begin()
-{
- if (false == begun_ ) {
-
- // begin will change all the states of all child nodes, reset all attributes
- SuiteChanged1 changed(this);
-
- // begin can cause thousands of mementos to be created, to avoid this we
- // update the modify change number.
- Ecf::incr_modify_change_no();
-
- begun_ = true;
- begun_change_no_ = Ecf::incr_state_change_no();
-
- begin_calendar();
-
- NodeContainer::begin();
-
- update_generated_variables();
- }
-}
-
-void Suite::requeue(
- bool resetRepeats,
- int clear_suspended_in_child_nodes,
- bool reset_next_time_slot)
-{
- if (false == begun_) {
- std::stringstream ss; ss << "Suite::requeue: The suite " << name() << " must be 'begun' first\n";
- throw std::runtime_error( ss.str() ) ;
- }
-
- // This is more efficient than: since no locking is required
- // SuiteChanged changed(boost::dynamic_pointer_cast<Suite>(shared_from_this()));
- // since no locking is required in SuiteChanged
- SuiteChanged1 changed(this); //
-
- // requeue can cause thousands of mementos to be created, to avoid this we
- // update the modify change number.
- Ecf::incr_modify_change_no();
-
- begin_calendar();
-
- NodeContainer::requeue(resetRepeats,
- clear_suspended_in_child_nodes,
- reset_next_time_slot);
-
- update_generated_variables();
-}
-
-void Suite::reset_begin() {
- SuiteChanged1 changed(this);
- begun_ = false;
- begun_change_no_ = Ecf::incr_state_change_no();
-}
-
-void Suite::begin_calendar()
-{
- // Begin the calendar, from the clock attribute _ELSE_
- // Get the local time, second level resolution, based on the
- // time zone settings of the computer.
- if (clockAttr_.get()) {
- clockAttr_->init_calendar(calendar_); // *IF* AlterCmd was used, wait till Suite is requed
- clockAttr_->begin_calendar(calendar_);
- }
- else {
- calendar_.begin(Calendar::second_clock_time());
- }
-}
-
-void Suite::updateCalendar( const ecf::CalendarUpdateParams & calParams, std::vector<node_ptr>& auto_cancelled_nodes )
-{
- if (begun_) {
-
-// cout << "Suite::updateCalendar " << debugNodePath() << " serverRunning = " << calParams.serverRunning() << " jobSubInterval = " << to_simple_string(calParams.serverPollPeriod());
-// if ( clockAttr_ ) cout << " clockAttr_->startStopWithServer() = " << clockAttr_->startStopWithServer();
-// cout << "\n";
-
- /// Some suite can elect to avoid updating the calendar when the server is stopped.
- /// This allows normal and relative time dependencies to be honoured even
- /// if the server is started/stopped many times.
- if ( clockAttr_.get() && clockAttr_->startStopWithServer() && !calParams.serverRunning()) {
- return;
- }
-
- SuiteChanged1 changed(this);
-
- /// The calendar_ will cache server poll period/job submission interval, as calendar increment for easy access
- calendar_.update( calParams );
- calendar_change_no_ = Ecf::state_change_no() + 1; // ** See: collateChanges **
-
- update_generated_variables();
-
- calendarChanged(calendar_,auto_cancelled_nodes);
- }
-}
-
-bool Suite::resolveDependencies(JobsParam& jobsParam)
-{
- if (begun_) {
-
- if (jobsParam.timed_out_of_job_generation()) return false;
- JobProfiler profile_me(jobsParam);
- if (jobsParam.timed_out_of_job_generation()) return false;
-
- SuiteChanged1 changed(this);
- return NodeContainer::resolveDependencies(jobsParam);
- }
- return true;
-}
-
-bool Suite::operator==(const Suite& rhs) const
-{
- if (begun_ != rhs.begun_) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Suite::operator== (begun_(" << begun_ << ") != rhs.begun_(" << rhs.begun_ << ")) " << debugNodePath() << "\n";
- }
-#endif
- return false;
- }
-
- if ((clockAttr_.get() && !rhs.clockAttr_.get()) || (!clockAttr_.get() && rhs.clockAttr_.get()) ){
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Suite::operator== (clockAttr_ && !rhs.clockAttr_) " << debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- if (clockAttr_.get() && rhs.clockAttr_.get() && !(*clockAttr_ == *rhs.clockAttr_)) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Suite::operator== (clockAttr_ && rhs.clockAttr_ && !(*clockAttr_ == *rhs.clockAttr_)) " << debugNodePath() << "\n";
- }
-#endif
- return false;
- }
-
- return NodeContainer::operator==(rhs);
-}
-
-std::ostream& Suite::print(std::ostream& os) const
-{
- Indentor::indent(os) << "suite " << name();
- if (!PrintStyle::defsStyle()) {
- std::string st = write_state();
- if (!st.empty()) os << " #" << st;
- }
- os << "\n";
-
- Node::print(os);
-
- // make sure clock attribute is written before
- if (clockAttr_.get()) clockAttr_->print(os);
- if (!PrintStyle::defsStyle()) {
- std::string calendar_state = calendar_.write_state();
- if (!calendar_state.empty()) {
- Indentor indent;
- Indentor::indent(os) << "calendar" << calendar_state << "\n";
- }
- }
-
- NodeContainer::print(os);
- Indentor::indent(os) << "endsuite\n";
-
- return os;
-}
-
-std::string Suite::write_state() const
-{
- // *IMPORTANT* we *CANT* use ';' character, since is used in the parser, when we have
- // multiple statement on a single line i.e.
- // task a; task b;
- std::string ret;
- if (begun_) ret += " begun:1";
- ret += NodeContainer::write_state();
- return ret;
-}
-void Suite::read_state(const std::string& line,const std::vector<std::string>& lineTokens) {
-
- // suite s1 # begun:1 state:queued flag:edit_failed suspended:1
- if (lineTokens.size() >= 4 && lineTokens[3] == "begun:1") begun_ = true;
- NodeContainer::read_state(line,lineTokens);
-}
-
-const std::string& Suite::debugType() const { return ecf::Str::SUITE();}
-
-std::ostream& operator<<(std::ostream& os, const Suite& d) { return d.print(os); }
-
-void Suite::addClock( const ClockAttr& c,bool initialize_calendar)
-{
- if ( clockAttr_.get()) {
- throw std::runtime_error("Add Clock failed: Suite can only have one clock " + absNodePath());
- }
- clockAttr_ = boost::make_shared<ClockAttr>(c);
- if (initialize_calendar) clockAttr_->init_calendar(calendar_);
-}
-
-void Suite::changeClock( const ClockAttr& c)
-{
- // When changing the clock, *WAIT* till requeue/begin to init the calendar
- clockAttr_.reset();
- addClock( c , false);
-}
-
-void Suite::changeClockType(const std::string& clockType)
-{
- // ISSUES:
- // Whenever the user *alters* the clock attributes, it needs to be followed by a re-queue of the suite, because:
- // o/ if we change from real ->hybrid, then we need to set cron, etc time based nodes to complete
- // Since we could have running tasks, it is up to user to decide when.
- // o/ If we change from hybrid ->real, then Node with cron attributes etc, need to be requeued.
- // o/ Any relative times are no longer valid
- // o/ Time attributes will be incorrect, and hence may fail/pass incorrectly during dependency evaluation.
- // o/ Why command may be wrong
- //
- //
- // *IF* the user *forgets* to do this, it can cause spurious errors, hence to *minimise* these
- // the best we can do is to :
- // o/ re-sync suite calendar for clock attribute
- // o/ re-queue all time based attributes, *avoiding*
- // change of state when switching to hybrid clock (i.e due to day,date,cron time attrs)
- // This is handled in handle_clock_attribute_change()
- //
-
- if (clockType != "hybrid" && clockType != "real") {
- throw std::runtime_error("Suite::changeClockType: expected clock type to be 'hybrid' or 'real' but found " + clockType);
- }
-
- SuiteChanged1 changed(this);
- if (clockAttr_.get()) {
- clockAttr_->hybrid( clockType == "hybrid" ); // will update state change_no
- }
- else {
- addClock( ClockAttr( clockType == "hybrid") ); // will update state change_no
- }
-
- // re-sync suite calendar for clock attribute, re-queue all time based attributes
- handle_clock_attribute_change();
-}
-
-void Suite::changeClockDate(const std::string& theDate)
-{
- // See ISSUES: Suite::changeClockType
- int day,month,year;
- DateAttr::getDate(theDate,day,month,year);
- if (day == 0 || month == 0 || year == 0) throw std::runtime_error("Suite::changeClockDate Invalid clock date:" + theDate );
-
- SuiteChanged1 changed(this);
- if (clockAttr_.get()) {
- clockAttr_->date(day,month,year); // this will check the date and update state change_no
- }
- else {
- addClock( ClockAttr(day,month,year) ); // will update state change_no
- }
-
- handle_clock_attribute_change();
-}
-
-void Suite::changeClockGain(const std::string& gain)
-{
- // See: ISSUES on Suite::changeClockType
- long theGain = 0;
- try { theGain = boost::lexical_cast< long >( gain ); }
- catch ( boost::bad_lexical_cast& ) {
- throw std::runtime_error( "Suite::changeClockGain: value '" + gain + "' is not convertible to an long, for suite " + name());
- }
-
- SuiteChanged1 changed(this);
- if (!clockAttr_.get()) {
- addClock( ClockAttr() ); // will update state change_no
- }
-
- if (theGain > 0) {
- clockAttr_->set_gain_in_seconds( theGain, true); // will update state change_no
- }
- else {
- clockAttr_->set_gain_in_seconds( theGain, false); // will update state change_no
- }
-
- handle_clock_attribute_change();
-}
-
-void Suite::changeClockSync()
-{
- // See: ISSUES on Suite::changeClockType
- SuiteChanged1 changed(this);
- if (clockAttr_.get()) {
- clockAttr_->sync(); // clear so that on re-queue we sync with computer, + will update state change_no
- }
- else {
- addClock( ClockAttr() ); // will update state change_no
- }
-
- handle_clock_attribute_change();
-}
-
-void Suite::handle_clock_attribute_change()
-{
- // re-queue time could cause thousands of mementos to be created, to avoid this we
- // update the modify change number.
- Ecf::incr_modify_change_no();
-
- // Since the suite clock attribute has changed, re-sync the suite calendar
- begin_calendar();
-
- // re-queue all the time attributes, since clock attribute has changed, avoid changing node state.
- // Note: when switching to hybrid clock the re-queue of time dependencies will
- // *not* mark hybrid (day,date,cron) as complete
- // since these nodes could be in a active/submitted state.
- NodeContainer::requeue_time_attrs();
-
- update_generated_variables();
-}
-
-
-bool Suite::checkInvariants(std::string& errorMsg) const
-{
- if (!calendar_.checkInvariants(errorMsg)) {
- return false;
- }
- if (clockAttr_.get()) {
- if ( calendar().hybrid() != clockAttr_->hybrid()) {
- std::stringstream ss;
- ss << "Suite:" << name() << " Calendar(hybrid(" << calendar().hybrid() << ")) and Clock attribute(hybrid(" << clockAttr_->hybrid() << ")) must be in sync, clock types differs";
- errorMsg += ss.str();
- return false;
- }
- }
-
- if (Ecf::server()) {
- if (state_change_no_ > Ecf::state_change_no() ) {
- std::stringstream ss;
- ss << "Suite::checkInvariants: suite_change_no(" << state_change_no_ << ") > Ecf::state_change_no(" << Ecf::state_change_no() << ")\n";
- errorMsg += ss.str();
- return false;
- }
- if (begun_change_no_ > Ecf::state_change_no() ) {
- std::stringstream ss;
- ss << "Suite::checkInvariants: begun_change_no_(" << begun_change_no_ << ") > Ecf::state_change_no(" << Ecf::state_change_no() << ")\n";
- errorMsg += ss.str();
- return false;
- }
- if (calendar_change_no_ > Ecf::state_change_no() ) {
- std::stringstream ss;
- ss << "Suite::checkInvariants: calendar_change_no_(" << calendar_change_no_ << ") > Ecf::state_change_no(" << Ecf::state_change_no() << ")\n";
- errorMsg += ss.str();
- return false;
- }
- if (modify_change_no_ > Ecf::modify_change_no() ) {
- std::stringstream ss;
- ss << "Suite::checkInvariants: modify_change_no_(" << modify_change_no_ << ") > Ecf::modify_change_no(" << Ecf::modify_change_no() << ")\n";
- errorMsg += ss.str();
- return false;
- }
- }
- return NodeContainer::checkInvariants(errorMsg);
-}
-
-void Suite::collateChanges(DefsDelta& changes) const
-{
- /// The suite hold the max state change no, for all its children and attributes
-#ifdef DEBUG_MEMENTO
- std::cout << "Suite::collateChanges() changes.client_state_change_no("
- << changes.client_state_change_no() << ") state_change_no("
- << state_change_no() << ") "
- << debugNodePath() << "\n";
-#endif
- // Optimising updates:
- // Problem:
- // User has requested 1 second updated in the viewer. We used add SuiteCalendarMemento
- // when ever there were changes in the suite. However this causes the suite in the
- // viewer to *refresh* to often.
- //
- // Soln 1:
- // Use:
- // calendar_change_no_ = Ecf::incr_state_change_no();
- //
- // plus only create SuiteCalendarMemento, where are suite changes *AND*
- // calendar has actually changed.
- // - This fixes the problem, at the expense of *always* creating a SuiteCalendarMemento
- // every 60 seconds. Thus adding to network traffic.
- // - The regression tests will fail, since a change is made in the server,
- // for which the sync does nothing. *************************************
- // This could be fixed only creating a SuiteCalendarMemento when calendar changes
- // However we then go back always creating SuiteCalendarMemento every 60 seconds
- // even when there are **no other** changes
- //
- // Soln 2:
- // Use:
- // calendar_change_no_ = Ecf::state_change_no() + 1
- //
- // We mimick updating Ecf::state_change_no(), thus we can create memento when required
- // They should however not be recognised as state change.
- // + This fixes the problem, and the regression test will also work
- // This is the solution that has been implemented
-
- // ********************************************************************
- // Note: we separate determining incremental changes from the traversal
- // ********************************************************************
-
- // *TREAT* All changes to *a* Node, in a single compound_memento_ptr
- size_t before = changes.size();
-
- compound_memento_ptr suite_compound_mememto;
- if (clockAttr_.get() && clockAttr_->state_change_no() > changes.client_state_change_no()) {
- if (!suite_compound_mememto.get()) suite_compound_mememto = boost::make_shared<CompoundMemento>(absNodePath());
- suite_compound_mememto->add( boost::make_shared<SuiteClockMemento>( *clockAttr_ ) );
- }
- if (begun_change_no_ > changes.client_state_change_no()) {
- if (!suite_compound_mememto.get()) suite_compound_mememto = boost::make_shared<CompoundMemento>(absNodePath());
- suite_compound_mememto->add( boost::make_shared<SuiteBeginDeltaMemento>( begun_) );
- }
-
- /// Collate NodeContainer and Node changes into *SAME* compound_memento_ptr
- NodeContainer::incremental_changes(changes, suite_compound_mememto);
-
- // Traversal, we have finished with this node:
- // Traverse children : *SEPARATE* compound_memento_ptr created on demand
- NodeContainer::collateChanges(changes);
-
- /// *ONLY* create SuiteCalendarMemento, if something changed in the suite.
- /// Additionally calendar_change_no_ updates should not register as a state change, i.e for tests
- /// SuiteCalendarMemento is need so that WhyCmd can work on the client side.
- /// Need to use new compound since the suite may not have change, but it children may have.
- /// Hence as side affect why command with reference to time will only be accurate
- /// after some kind of state change. Discussed with Axel, who was happy with this.
- size_t after = changes.size();
- if (before != after && calendar_change_no_ > changes.client_state_change_no()) {
- compound_memento_ptr compound_ptr = boost::make_shared<CompoundMemento>(absNodePath());
- compound_ptr->add( boost::make_shared<SuiteCalendarMemento>( calendar_ ) );
- changes.add( compound_ptr );
- }
-}
-
-void Suite::set_memento( const SuiteClockMemento* memento ) {
-#ifdef DEBUG_MEMENTO
- std::cout << "Suite::set_memento( const SuiteClockMemento*) " << debugNodePath() << "\n";
-#endif
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::SUITE_CLOCK);
-
- changeClock(memento->clockAttr_);
-}
-
-void Suite::set_memento( const SuiteBeginDeltaMemento* memento ) {
-#ifdef DEBUG_MEMENTO
- std::cout << "Suite::set_memento( const SuiteBeginDeltaMemento* ) " << debugNodePath() << "\n";
-#endif
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::SUITE_BEGIN);
-
- begun_ = memento->begun_;
-}
-
-void Suite::set_memento( const SuiteCalendarMemento* memento ) {
-#ifdef DEBUG_MEMENTO
- std::cout << "Suite::set_memento( const SuiteCalendarMemento* ) " << debugNodePath() << "\n";
-#endif
-
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::SUITE_CALENDAR);
-
- // The calendar does *NOT* persist the calendar type (hybrid/real) since we can derive this for clock attribute
- // Hence make sure calendar/clock are in sync. part of the suite invariants
- calendar_ = memento->calendar_;
- if (clockAttr_.get()) {
- if (clockAttr_->hybrid()) calendar_.set_clock_type(ecf::Calendar::HYBRID);
- else calendar_.set_clock_type(ecf::Calendar::REAL);
- }
-}
-
-// generated variables ---------------------------------------------------------------------
-void Suite::update_generated_variables() const
-{
- // This function is called during:
- // o begin()
- // o requeue()
- // o when calendar changes
- if (!suite_gen_variables_) suite_gen_variables_ = new SuiteGenVariables(this);
- suite_gen_variables_->update_generated_variables();
- update_repeat_genvar();
-}
-
-const Variable& Suite::findGenVariable(const std::string& name) const
-{
- if (!suite_gen_variables_) update_generated_variables();
-
- const Variable& gen_var = suite_gen_variables_->findGenVariable(name);
- if (!gen_var.empty()) return gen_var;
- return NodeContainer::findGenVariable(name);
-}
-
-void Suite::gen_variables(std::vector<Variable>& vec) const
-{
- if (!suite_gen_variables_) update_generated_variables();
-
- vec.reserve(vec.size() + 13);
- NodeContainer::gen_variables(vec);
- suite_gen_variables_->gen_variables(vec);
-}
-
-// =======================================================================================
-
-// The false below is used as a dummy argument to call the Variable constructor that does not
-// check the variable names. i.e we know they are valid
-SuiteGenVariables::SuiteGenVariables(const Suite* s)
-: suite_(s),
- genvar_suite_("SUITE", "", false),
- genvar_yyyy_("YYYY","", false),
- genvar_dow_("DOW", "", false),
- genvar_doy_("DOY", "", false),
- genvar_date_("DATE", "", false),
- genvar_day_("DAY", "", false),
- genvar_dd_("DD", "", false ),
- genvar_mm_("MM", "", false ),
- genvar_month_("MONTH", "", false ),
- genvar_smsdate_("ECF_DATE", "", false ),
- genvar_clock_("ECF_CLOCK", "", false ),
- genvar_time_("ECF_TIME", "", false ){}
-
-void SuiteGenVariables::update_generated_variables() const
-{
- genvar_suite_.set_value(suite_->name());
-
- // The calendar_ is only initialised once the suite has begun
- if (!suite_->begun_) {
- return;
- }
-
- // The code below ASSUMES calendar has been initialised
- boost::posix_time::time_duration time_of_day = suite_->calendar_.suiteTime().time_of_day();
-
- //#ifdef DEBUG
- // using namespace boost::gregorian;
- // tm t = to_tm(suite_->calendar_.suiteTime()); // to_tm can be a bit of a performance hog
- //// cerr << "\ntm_year = " << t.tm_year << "\n"; /* year - 1900 */
- //// cerr << "tm_mon = " << t.tm_mon << "\n"; /* month of year (0 - 11) */
- //// cerr << "tm_mday = " << t.tm_mday << "\n"; /* day of month (1 - 31) */
- //// cerr << "tm_wday = " << t.tm_wday << "\n"; /* day of week (Sunday = 0) */
- //// cerr << "tm_yday = " << t.tm_yday << "\n"; /* day of year (0 - 365) */
- //// cerr << "tm_hour = " << t.tm_hour << "\n"; /* hours (0 - 23) */
- //// cerr << "tm_min = " << t.tm_min << "\n"; /* minutes (0 - 59) */
- //// cerr << "tm_sec = " << t.tm_sec << "\n"; /* seconds (0 - 59) */
- //
- // // ***IMPORTANT*** suiteTime is only valid for real clock, note that
- // // *************** for hybrid the day does not change. hence assertion
- // // *************** needs to take into account calendar type
- // if (!suite_->calendar_.hybrid()) {
- // assert( t.tm_wday == calendar_.day_of_week());
- // assert( t.tm_mday == calendar_.day_of_month());
- // assert( t.tm_yday+1 == calendar_.day_of_year());
- // assert( t.tm_mon+1 == calendar_.month());
- // }
- // assert( time_of_day.hours() == t.tm_hour);
- // assert( time_of_day.minutes() == t.tm_min);
- // assert( t.tm_year + 1900 == calendar_.year());
- //#endif
-
- char smstime[255];
- sprintf(smstime,"%02d:%02d", time_of_day.hours(),time_of_day.minutes());
- genvar_time_.set_value( smstime );
-
- // **********************************************************************
- // The following generated variable need only be updated if NULL or if day changed
- // Under: HYBRID the day will never change, hence a one time update
- // **********************************************************************
- if (genvar_yyyy_.theValue().empty() || suite_->calendar_.dayChanged()) {
-
- genvar_yyyy_.set_value(boost::lexical_cast<std::string>(suite_->calendar_.year()));
- genvar_dow_.set_value( boost::lexical_cast<std::string>(suite_->calendar_.day_of_week()) );
- genvar_doy_.set_value( boost::lexical_cast<std::string>(suite_->calendar_.day_of_year()) );
- //cout << "genvar_yyyy_ = " << genvar_yyyy_->theValue() << "\n";
- //cout << "genvar_dow_ = " << genvar_dow_->theValue() << "\n";
- //cout << "genvar_doy_ = " << genvar_doy_->theValue() << "\n";
-
- char ddmmyyyyBuffer[255];
- sprintf(ddmmyyyyBuffer,"%02d.%02d.%04d", suite_->calendar_.day_of_month(), suite_->calendar_.month(), suite_->calendar_.year());
- genvar_date_.set_value( ddmmyyyyBuffer );
- //cout << "genvar_date_ = " << genvar_date_->theValue() << "\n";
-
- char *day_name[]= { const_cast<char*>("sunday"), const_cast<char*>("monday"),
- const_cast<char*>("tuesday"), const_cast<char*>("wednesday"),
- const_cast<char*>("thursday"), const_cast<char*>("friday"),
- const_cast<char*>("saturday"), NULL };
- genvar_day_.set_value( day_name[suite_->calendar_.day_of_week()] );
- //cout << "genvar_day_ = " << genvar_day_->theValue() << "\n";
-
- char dd[255];
- sprintf(dd,"%02d",suite_->calendar_.day_of_month());
- genvar_dd_.set_value( dd );
- //cout << "genvar_dd_ = " << genvar_dd_->theValue() << "\n";
-
- char mm[255];
- sprintf(mm,"%02d",suite_->calendar_.month());
- genvar_mm_.set_value( mm );
- //cout << "genvar_mm_ = " << genvar_mm_->theValue() << "\n";
-
- char *month_name[]
- = { const_cast<char*>("january"), const_cast<char*>("february"), const_cast<char*>("march"),
- const_cast<char*>("april"), const_cast<char*>("may"), const_cast<char*>("june"),
- const_cast<char*>("july"), const_cast<char*>("august"), const_cast<char*>("september"),
- const_cast<char*>("october"), const_cast<char*>("november"), const_cast<char*>("december"),
- NULL } ;
- genvar_month_.set_value( month_name[suite_->calendar_.month()-1] );
- //cout << "genvar_month_ = " << genvar_month_->theValue() << "\n";
-
- char smsdate[255];
- sprintf(smsdate,"%04d%02d%02d", suite_->calendar_.year(), suite_->calendar_.month() , suite_->calendar_.day_of_month());
- genvar_smsdate_.set_value( smsdate );
- //cout << "genvar_smsdate_ = " << genvar_smsdate_->theValue() << "\n";
-
- char smsclock[255];
- sprintf(smsclock,"%s:%s:%d:%d", day_name[suite_->calendar_.day_of_week()], month_name[suite_->calendar_.month()-1],suite_->calendar_.day_of_week(),suite_->calendar_.day_of_year());
- genvar_clock_.set_value( smsclock );
- //cout << "genvar_clock_ = " << genvar_clock_->theValue() << "\n";
- }
-}
-
-const Variable& SuiteGenVariables::findGenVariable(const std::string& name) const
-{
- if (genvar_suite_.name() == name) return genvar_suite_;
- if (genvar_smsdate_.name() == name) return genvar_smsdate_;
- if (genvar_yyyy_.name() == name) return genvar_yyyy_;
- if (genvar_dow_.name() == name) return genvar_dow_;
- if (genvar_doy_.name() == name) return genvar_doy_;
- if (genvar_date_.name() == name) return genvar_date_;
- if (genvar_day_.name() == name) return genvar_day_;
- if (genvar_dd_.name() == name) return genvar_dd_;
- if (genvar_mm_.name() == name) return genvar_mm_;
- if (genvar_month_.name() == name) return genvar_month_;
- if (genvar_clock_.name() == name) return genvar_clock_;
- if (genvar_time_.name() == name) return genvar_time_;
- return Variable::EMPTY();
-}
-
-void SuiteGenVariables::gen_variables(std::vector<Variable>& vec) const
-{
- vec.push_back(genvar_suite_);
- vec.push_back(genvar_smsdate_);
- vec.push_back(genvar_yyyy_);
- vec.push_back(genvar_dow_);
- vec.push_back(genvar_doy_);
- vec.push_back(genvar_date_);
- vec.push_back(genvar_day_);
- vec.push_back(genvar_dd_);
- vec.push_back(genvar_mm_);
- vec.push_back(genvar_month_);
- vec.push_back(genvar_clock_);
- vec.push_back(genvar_time_);
-}
diff --git a/ecflow_4_0_7/ANode/src/Suite.hpp b/ecflow_4_0_7/ANode/src/Suite.hpp
deleted file mode 100644
index 6f523ef..0000000
--- a/ecflow_4_0_7/ANode/src/Suite.hpp
+++ /dev/null
@@ -1,175 +0,0 @@
-#ifndef SUITE_HPP_
-#define SUITE_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #73 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "NodeContainer.hpp"
-#include "Calendar.hpp"
-#include "ClockAttr.hpp"
-class SuiteGenVariables;
-namespace ecf { class CalendarUpdateParams; } // forward declare
-
-
-class Suite : public NodeContainer {
-public:
- Suite( const std::string& name )
- : NodeContainer(name),
- defs_(NULL),
- begun_(false),
- state_change_no_(0),
- modify_change_no_(0),
- begun_change_no_(0),
- calendar_change_no_(0),
- suite_gen_variables_(NULL)
- {}
-
- Suite()
- : defs_(NULL),
- begun_(false),
- state_change_no_(0),
- modify_change_no_(0),
- begun_change_no_(0),
- calendar_change_no_(0),
- suite_gen_variables_(NULL)
- {}
-
- virtual ~Suite();
-
- static suite_ptr create(const std::string& name);
-
- virtual Suite* suite() const { return const_cast<Suite*>(this); }
- virtual Defs* defs() const { return defs_;}
- void set_defs(Defs* d) { defs_ = d;}
- virtual Suite* isSuite() const { return const_cast<Suite*>(this); }
- virtual NodeContainer* isNodeContainer() const { return const_cast<Suite*>(this); }
-
- /// Overridden to take into account begin()
- virtual bool resolveDependencies(JobsParam& );
-
- virtual void accept(ecf::NodeTreeVisitor&);
- virtual void acceptVisitTraversor(ecf::NodeTreeVisitor& v);
- virtual void begin();
- virtual void requeue(
- bool resetRepeats,
- int clear_suspended_in_child_nodes,
- bool reset_next_time_slot);
- bool begun() const { return begun_; }
- void reset_begin();
- virtual void update_generated_variables() const;
-
- virtual const Variable& findGenVariable(const std::string& name) const;
- virtual void gen_variables(std::vector<Variable>&) const;
-
- void updateCalendar( const ecf::CalendarUpdateParams &, std::vector<node_ptr>& auto_cancelled_nodes);
-
- virtual const std::string& debugType() const;
-
- bool operator==(const Suite& rhs) const;
- std::ostream& print(std::ostream&) const;
-
- void addClock( const ClockAttr& , bool initialize_calendar = true); // throw std::run_time if more than one clock is added
- void changeClock( const ClockAttr& );
- void changeClockType(const std::string& theType);
- void changeClockDate(const std::string& theDate);
- void changeClockGain(const std::string& theIntGain);
- void changeClockSync();
-
- /// return the suites calendar
- const ecf::Calendar& calendar() const { return calendar_;}
- ecf::Calendar& set_calendar() { return calendar_;}
- clock_ptr clockAttr() const { return clockAttr_;}
-
- virtual bool checkInvariants(std::string& errorMsg) const;
-
- // Memento functions
- virtual void collateChanges(DefsDelta&) const;
- void set_memento(const SuiteClockMemento* );
- void set_memento(const SuiteBeginDeltaMemento* );
- void set_memento(const SuiteCalendarMemento* );
- void set_memento(const OrderMemento* m) { NodeContainer::set_memento(m); }
- void set_memento(const ChildrenMemento* m) { NodeContainer::set_memento(m); }
-
- void set_state_change_no( unsigned int x ) { state_change_no_ = x;}
- unsigned int state_change_no() const { return state_change_no_; }
- void set_modify_change_no( unsigned int x ) { modify_change_no_ = x;}
- unsigned int modify_change_no() const { return modify_change_no_; }
-
- virtual void read_state(const std::string& line,const std::vector<std::string>& lineTokens);
-
-private:
- void begin_calendar();
- void handle_clock_attribute_change();
- virtual std::string write_state() const;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/)
- {
- // serialise base class information
- ar & boost::serialization::base_object<NodeContainer>(*this);
- ar & begun_;
- ar & clockAttr_;
- ar & calendar_;
-
- // The calendar does not persist the clock type or start stop with server since
- // that is persisted with the clock attribute
- if (Archive::is_loading::value) {
- if (clockAttr_.get()) clockAttr_->init_calendar(calendar_);
- }
- }
-
-private:
- Defs* defs_; // *NOT* persisted, set by parent Defs
- bool begun_;
- clock_ptr clockAttr_;
- ecf::Calendar calendar_; // *Only* persisted since used by the why() on client side
- unsigned int state_change_no_; // no need to persist
- unsigned int modify_change_no_; // no need to persist
- unsigned int begun_change_no_; // no need to persist, record changes to begun_. Needed for SSyncCmd
- unsigned int calendar_change_no_; // no need to persist,
- mutable SuiteGenVariables* suite_gen_variables_; // NOT persisted can be generated by calling update_generated_variables()
- friend class SuiteGenVariables;
-};
-
-std::ostream& operator<<(std::ostream& os, const Suite&);
-
-
-// This class helps in avoiding the creation of generated variables until required.
-// This improves client->server down load times by avoiding thousands of string constructions
-class SuiteGenVariables : private boost::noncopyable {
-public:
- SuiteGenVariables(const Suite*);
-
- void update_generated_variables() const;
- const Variable& findGenVariable(const std::string& name) const;
- void gen_variables(std::vector<Variable>& vec) const;
-
-private:
- const Suite* suite_;
- mutable Variable genvar_suite_; // *NOT* persisted, can be generated by calling update_generated_variables()
- mutable Variable genvar_yyyy_; // *NOT* persisted, can be generated by calling update_generated_variables()
- mutable Variable genvar_dow_; // *NOT* persisted, can be generated by calling update_generated_variables()
- mutable Variable genvar_doy_; // *NOT* persisted, can be generated by calling update_generated_variables()
- mutable Variable genvar_date_; // *NOT* persisted, can be generated by calling update_generated_variables()
- mutable Variable genvar_day_; // *NOT* persisted, can be generated by calling update_generated_variables()
- mutable Variable genvar_dd_; // *NOT* persisted, can be generated by calling update_generated_variables()
- mutable Variable genvar_mm_; // *NOT* persisted, can be generated by calling update_generated_variables()
- mutable Variable genvar_month_; // *NOT* persisted, can be generated by calling update_generated_variables()
- mutable Variable genvar_smsdate_; // *NOT* persisted, can be generated by calling update_generated_variables()
- mutable Variable genvar_clock_; // *NOT* persisted, can be generated by calling update_generated_variables()
- mutable Variable genvar_time_; // *NOT* persisted, can be generated by calling update_generated_variables()
-};
-
-#endif
diff --git a/ecflow_4_0_7/ANode/src/SuiteChanged.cpp b/ecflow_4_0_7/ANode/src/SuiteChanged.cpp
deleted file mode 100644
index 9d04483..0000000
--- a/ecflow_4_0_7/ANode/src/SuiteChanged.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#ifdef DEBUG
-#include <iostream>
-#endif
-
-#include "SuiteChanged.hpp"
-#include "Suite.hpp"
-#include "Ecf.hpp"
-
-namespace ecf {
-
-SuiteChanged::SuiteChanged(suite_ptr s)
-: suite_(s),
- state_change_no_(Ecf::state_change_no()),
- modify_change_no_(Ecf::modify_change_no())
- {}
-
-SuiteChanged::~SuiteChanged()
-{
- suite_ptr suite = suite_.lock();
- if (suite.get()) {
- if ( modify_change_no_ != Ecf::modify_change_no() ) {
- suite->set_modify_change_no(Ecf::modify_change_no());
- }
- if ( state_change_no_ != Ecf::state_change_no() ) {
- suite->set_state_change_no(Ecf::state_change_no());
- }
- }
-}
-
-// ============================================================================
-SuiteChanged0::SuiteChanged0(node_ptr s)
-: node_(s),
- suite_(s->suite()),
- state_change_no_(Ecf::state_change_no()),
- modify_change_no_(Ecf::modify_change_no())
- {}
-
-SuiteChanged0::~SuiteChanged0()
-{
- node_ptr node = node_.lock();
- if (node.get() && suite_) {
- if ( modify_change_no_ != Ecf::modify_change_no() ) {
- suite_->set_modify_change_no(Ecf::modify_change_no());
- //std::cout << "SuiteChanged0::~SuiteChanged0() modify_ changed \n";
- }
- if ( state_change_no_ != Ecf::state_change_no() ) {
- suite_->set_state_change_no(Ecf::state_change_no());
- //std::cout << "SuiteChanged0::~SuiteChanged0() state changed \n";
- }
- }
-}
-
-//================================================================
-
-SuiteChanged1::SuiteChanged1(Suite* s)
-: suite_(s),
- state_change_no_(Ecf::state_change_no()),
- modify_change_no_(Ecf::modify_change_no())
- {}
-
-SuiteChanged1::~SuiteChanged1()
-{
- if ( modify_change_no_ != Ecf::modify_change_no() ) {
- suite_->set_modify_change_no(Ecf::modify_change_no());
- //std::cout << "SuiteChanged1::~SuiteChanged0() modify_ changed \n";
- }
- if ( state_change_no_ != Ecf::state_change_no() ) {
- suite_->set_state_change_no(Ecf::state_change_no());
- //std::cout << "SuiteChanged1::~SuiteChanged0() modify_ changed \n";
- }
-}
-
-}
diff --git a/ecflow_4_0_7/ANode/src/SuiteChanged.hpp b/ecflow_4_0_7/ANode/src/SuiteChanged.hpp
deleted file mode 100644
index e02e34c..0000000
--- a/ecflow_4_0_7/ANode/src/SuiteChanged.hpp
+++ /dev/null
@@ -1,68 +0,0 @@
-#ifndef SUITE_CHANGED_HPP_
-#define SUITE_CHANGED_HPP_
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <boost/noncopyable.hpp>
-#include "NodeFwd.hpp"
-
-namespace ecf {
-
-// Determine if suite was changed or modified if so, update suite change no
-// This mechanism was used because, when changing some attributes, we can not
-// immediately access the parent suites, to update the change numbers.
-//
-// When given a choice between where to add SuiteChanged, i.e in Node Tree or Commands
-// Generally favour commands, as it will require less maintenance over time.
-//
-// This mechanism was added specifically to support changes over client handles
-// i.e suites are added to handles, hence we need a way to determine which
-// suites (and hence handle) changed, and hence minimise the need for updates.
-
-class SuiteChanged : private boost::noncopyable {
-public:
- SuiteChanged(suite_ptr s);
- ~SuiteChanged();
-private:
- weak_suite_ptr suite_;
- unsigned int state_change_no_;
- unsigned int modify_change_no_;
-};
-
-class SuiteChanged0 : private boost::noncopyable {
-public:
- SuiteChanged0(node_ptr s);
- ~SuiteChanged0();
-private:
- weak_node_ptr node_;
- Suite* suite_; // if node is removed suite pointer is not accessible, hence store first
- unsigned int state_change_no_;
- unsigned int modify_change_no_;
-};
-
-
-class SuiteChanged1 : private boost::noncopyable {
-public:
- SuiteChanged1(Suite* s);
- ~SuiteChanged1();
-private:
- Suite* suite_;
- unsigned int state_change_no_;
- unsigned int modify_change_no_;
-};
-
-}
-#endif
diff --git a/ecflow_4_0_7/ANode/src/System.cpp b/ecflow_4_0_7/ANode/src/System.cpp
deleted file mode 100644
index 4310d96..0000000
--- a/ecflow_4_0_7/ANode/src/System.cpp
+++ /dev/null
@@ -1,411 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #39 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <assert.h>
-#include <iostream>
-#include <signal.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <errno.h>
-
-#ifndef O_WRONLY
-#include <fcntl.h>
-#endif
-
-#include "System.hpp"
-#include "Signal.hpp"
-#include "Defs.hpp"
-#include "Submittable.hpp"
-#include "SuiteChanged.hpp"
-#include "Log.hpp"
-
-//#define DEBUG_FORK 1
-//#define DEBUG_CATCH_CHILD 1
-//#define DEBUG_TERMINATED_CHILD 1
-//#define DEBUG_CHILD_ABORT 1
-
-using namespace std;
-
-namespace ecf {
-
-// ===========================================================================
-// Process
-// ===========================================================================
-struct Process {
-public:
- Process(const std::string& absPath,const std::string& cmdToSpawn, pid_t pid)
- : absNodePath_(absPath), cmd_(cmdToSpawn),have_status_(0), pid_(pid), status_(0) {}
-
- std::string absNodePath_; // Path to Task(ECF_JOB_CMD), empty for ECF_KILL_CMD & ECF_STATUS_CMD
- std::string cmd_; // the command that was spawned
- sig_atomic_t have_status_;// Nonzero if this process has stopped or terminated. */
- pid_t pid_; // The process ID of this child.
- int status_; // The status of this child; 0 if running,
- // otherwise a status value from waitpid
-};
-std::vector<Process> processVec_;
-
-/* Nonzero means some child's status has changed
- so look at process_list for the details. */
-volatile int process_status_change_ = 0;
-
-
-// ===========================================================================
-// System
-// ===========================================================================
-System* System::instance_ = NULL;
-
-System* System::instance()
-{
- if ( instance_ == NULL) {
-
- // Block SIGCHLD so that we control, when child process termination is handled
- ecf::Signal::block_sigchild();
-
- // install signal handler, that will catch Child process termination
- // The install function can be called asynchronously, and hence deserves
- // special consideration. Currently we temporarily unblock pending
- // SIGCHLD signals at the end of Job generation, and then block them again.
- // During the brief moment between unblock/block we expect
- // the handler to be called.
- catchChildProcessTermination();
-
- instance_ = new System();
- }
- return instance_;
-}
-
-void System::destroy()
-{
- delete instance_;
- instance_ = NULL;
-}
-
-System::System() {}
-System::~System(){}
-
-bool System::spawn(const std::string& cmdToSpawn,const std::string& absPath,std::string& errorMsg)
-{
-#ifdef DEBUG_FORK
- std::cout << " System::spawn path(" << absPath << ") cmd(" << cmdToSpawn << ")\n";
-#endif
-
- int rc = 1; /* Not a zero */
- int tryi = 1; /* Currently hardcoded */
-
- for (rc = 1; tryi && rc; tryi--) {
- rc = sys(cmdToSpawn,absPath,errorMsg);
- if ( rc ) sleep( 1 ); /* May be 2 many processes */
- }
-
- if ( rc ) {
- std::stringstream ss;
- ss << "Child process creation failed for command " << cmdToSpawn;
- if ( !absPath.empty() ) ss << " at path(" << absPath << ")";
- errorMsg = ss.str();
-#ifdef DEBUG_FORK
- std::cout << " System::spawn returning false " << endl;
-#endif
- return false;
- }
- return true;
-}
-
-int System::sys(const std::string& cmdToSpawn,const std::string& absPath,std::string& errorMsg)
-{
-#ifdef DEBUG_FORK
- std::cout << " System::sys path(" << absPath << ") cmd(" << cmdToSpawn << ")\n";
-#endif
- /**************************************************************************
- ? Execute the command (cmdToSpawn) and return, DO NOT WAIT for the termination
- | of the children.
- | The stdin, stdout and stderr are closed (or redirected to /dev/null)
- = PID in case of success or 0 in case of errors.
- ************************************o*************************************/
- pid_t child_pid;
- if ( (child_pid = fork()) == 0 ) { /* The child */
-
- int f;
- close( 2 );
- if ( (f = open( "/dev/null", O_WRONLY )) != 2 ) close( f );
-
- close( 1 );
- if ( (f = open( "/dev/null", O_WRONLY )) != 1 ) close( f );
-
- close( 0 );
- if ( (f = open( "/dev/null", O_RDONLY )) != 0 ) close( f );
-
- // ==============================================================================
- // Ideally we should close all open file descriptors in the child process
- // On Linux: sysconf(_SC_OPEN_MAX); returns 1024
- // This means making 1024 - 3 system calls
- // This is especially import for socket descriptors, since if the server goes down
- // The children/zombies will prevent the server restart on the same port.
- // i.e the classic Address in use
- // Its not clear how big a performance issue this, an alternative would be, to only close
- // open socket file descriptors. But this will require a singleton of some sort
- // ===============================================================================
- int fd_limit = sysconf(_SC_OPEN_MAX);
- for (int i=3; i<fd_limit; i++) close(i);
-
- execl( "/bin/sh", "sh", "-c", cmdToSpawn.c_str(), (char *)NULL );
- /*
- * Maybe the file protection failed (no executable bit set)
- * or the shell couldn't be found. Look at man execve(2).
- */
- _exit( 127 );
- }
-
- if ( child_pid == -1 ) {
- std::stringstream ss;
- ss << " ECF-PROCESS-SYS: FORK error for " << cmdToSpawn;
- if (!absPath.empty()) ss << " and task " << absPath;
- errorMsg = ss.str();
- return 1;
- }
-
- // Store the process pid, so that we can wait for it. ho ho.
- processVec_.push_back(Process(absPath,cmdToSpawn,child_pid));
-
-#ifdef DEBUG_FORK
- //LogToCout logToCoutAsWell;
- LOG( Log::DBG," submit: Path(" << absPath << ") child_pid(" << child_pid << ") cmd(" << cmdToSpawn << ")");
-#endif
- return 0;
-}
-
-
-static void catch_child(int sig)
-/**************************************************************************
-? Catch the death of the child process
-| This function can be called asynchronously hence it could interfere
- with the rest of program. Hence this function does not allocate or
- free memory. We simply store the status, for later processing
-************************************o*************************************/
-{
-#ifdef DEBUG_CATCH_CHILD
- std::cout << " catch_child (process death) sig = " << sig << endl;
-#endif
-
- int saved_errno = errno; // save error number since waitpid can change this
- int status;
- pid_t child_pid;
-
- // waitpid returns:
- // - on success, returns the process ID of the child whose state has changed
- // - if WNOHANG was specified and one or more child(ren) specified by pid exist,
- // but have *NOT* yet changed state, then *0* is returned
- // *** hence we MUST check for 0, other wise we will end up in an infinite loop **
- // - returns -1 on error
- while ( (child_pid = waitpid( -1, &status, WNOHANG )) != -1 && child_pid != 0) {
-
- std::vector<Process>::iterator theEnd = processVec_.end();
- for(std::vector<Process>::iterator i = processVec_.begin(); i!= theEnd; ++i) {
- if ((*i).pid_ == child_pid) {
-
-#ifdef DEBUG_CATCH_CHILD
- std::cout << " catch_child Found pid " << child_pid << endl;
-#endif
- // Indicate that the status field
- // has data to look at. We do this only after storing it.
- (*i).have_status_ = 1;
-
- // store the status
- (*i).status_ = status;
-
- // The program should check this flag from time to time
- // to see if there is any news in processVec_.
- process_status_change_++;
- break;
- }
- }
- }
-
- // restore error number
- errno = saved_errno ;
-}
-
-void System::processTerminatedChildren()
-{
-#ifdef DEBUG_TERMINATED_CHILD
- std::cout << "System::processTerminatedChildren() process_status_change_ = " << process_status_change_
- << " processVec_.size() = " << processVec_.size() << endl;
- LogToCout logToCoutAsWell;
-#endif
- if ( process_status_change_ == 0) {
- return;
- }
-
- // Must be the first thing we do.
- process_status_change_ = 0;
-
- std::vector<Process>::iterator i;
- for(i = processVec_.begin(); i!= processVec_.end(); ++i) {
-
- if ((*i).have_status_) {
-
-#ifdef DEBUG_TERMINATED_CHILD
- std::cout << "System::processTerminatedChildren() path(" << (*i).absNodePath_ << ") pid(" << (*i).pid_ << ") has status " << endl;
-#endif
- // exit status is one of mutually exclusive [ WIFEXITED | WIFSIGNALED | WIFSTOPPED | WIFCONTINUED ]
- if (WIFEXITED((*i).status_)) {
-
- // *Normal* termination via exit
- if ( WEXITSTATUS( (*i).status_ )) {
- // exit is non zero.
- std::stringstream ss; ss << " PID(" << (*i).pid_ << ") path(" << (*i).absNodePath_ << ") exited with status " << WEXITSTATUS((*i).status_)<< " [ " << (*i).cmd_ << " ]";
- died( (*i).absNodePath_, ss.str());
- }
- else {
- // exit(0) child terminated normally
-#ifdef DEBUG_TERMINATED_CHILD
- LOG( Log::DBG, "PID " << (*i).pid_ << " exited normally [ " << (*i).cmd_ << " ]" );
-#endif
- }
-
- // remove the process since it has terminated
- processVec_.erase(i--);
- }
- else if ( WIFSIGNALED( (*i).status_) ) {
-
- // *abnormal* child process terminated by a signal
- std::stringstream ss; ss << " ECF-PROCESS-CHILD:PID(" << (*i).pid_ << ") path(" << (*i).absNodePath_ << ") died of signal " << WTERMSIG((*i).status_) << " [ " << (*i).cmd_ << " ]";
- died( (*i).absNodePath_, ss.str());
-
- // remove the process since it has terminated
- processVec_.erase(i--);
- }
- else if ( WIFSTOPPED( (*i).status_) ) {
-
- LOG( Log::WAR, " ECF-PROCESS-CHILD:PID " << (*i).pid_ << " STOPPED? [ " << (*i).absNodePath_ << " ] [ " << (*i).cmd_ << " ]");
- }
- else {
-
- // Can only be WIFCONTINUED. (XSI extension to POSIX)
- LOG( Log::WAR, " ECF-PROCESS-CHILD:PID " << (*i).pid_ << " CONTINUED? [ " << (*i).absNodePath_ << " ] [ " << (*i).cmd_ << " ]");
- }
- }
- else {
-#ifdef DEBUG_TERMINATED_CHILD
- LOG( Log::DBG, " ECF-PROCESS-CHILD:stray PID " << (*i).pid_ << " (ignored) [ " << (*i).cmd_ << " ]" );
-#endif
- }
- }
-
-#ifdef DEBUG_TERMINATED_CHILD
- std::cout << "System::processTerminatedChildren() process size = " << processVec_.size() << endl;
-#endif
-}
-
-int System::process() const
-{
- return static_cast<int>(processVec_.size());
-}
-
-// ============================================================================
-// See: Advanced programming in the UNIX environment: Page 328
-// Note: with sigaction the handle stays installed, until changed
-// this is different to the signal(..) which on some system needs
-// to be reinstalled at start/end of SignalFunction.
-// ============================================================================
-typedef void SignalFunction(int);
-SignalFunction* signal_(int signo, SignalFunction* func)
-{
- struct sigaction act, oact;
- act.sa_handler = func;
- sigemptyset(&act.sa_mask);
- act.sa_flags = 0;
- if (signo == SIGALRM) {
-#ifdef SA_INTERRUPT
- act.sa_flags |= SA_INTERRUPT;
-#endif
- }
- else {
- // We intentionally try to set the SA_RESTART flag for all signals other than SIGALRM
- // so that any system call interrupted by these other signals in automatically restarted
-#ifdef SA_RESTART
- act.sa_flags |= SA_RESTART;
-#endif
- }
-
- if (sigaction(signo, &act, &oact) < 0)
- return (SIG_ERR);
-
- // Return the old handler
- return oact.sa_handler;
-}
-
-void System::catchChildProcessTermination()
-{
- // Call our local version (which uses sigaction) rather than the out date signal(..)
- signal_( SIGCHLD, catch_child );
-}
-
-void System::died( const std::string& absNodePath, const std::string& reason)
-/**************************************************************************
- ? Process the death of the process. This is most unwanted and implies
- | that the shell died abnormally.
- ************************************o*************************************/
-{
-#ifdef DEBUG_CHILD_ABORT
- std::cout << "System::died path = '" << absNodePath << "'" << endl;
-#endif
-
- /// always write to log, before returning
- ecf::log(Log::ERR,reason);
-
- /// If the Path is empty, then this could be something *OTHER THAN* job submission
- /// that has failed. i.e kill cmd, or any other command, so don;t assert
- if ( absNodePath.empty() ) {
- return;
- }
-
- defs_ptr defs = defs_.lock();
- if ( !defs.get() ) {
- LOG_ASSERT(defs.get(),"System::died, defs not defined ???");
- return;
- }
-
- node_ptr node = defs->findAbsNode( absNodePath );
- if ( !node.get() ) {
-#ifdef DEBUG_CHILD_ABORT
- std::cout << "System::died " << absNodePath << " could not be found in defs \n";
-#endif
- return;
- }
-
- Submittable* submittable = node->isSubmittable();
- if ( !submittable ) {
-#ifdef DEBUG_CHILD_ABORT
- std::cout << "System::died " << absNodePath << " path is NOT a Task or Alias \n";
-#endif
- return;
- }
-
- // This function can get called at any time.
- // AND out of context of any command, hence we must handle case where Suite handles are used.
- // Otherwise the view will not know about aborted states.
- // ECFLOW-104 aborted state for a task following an error at submission
- SuiteChanged1 changed(submittable->suite());
-
- submittable->flag().set(ecf::Flag::JOBCMD_FAILED);
-
-#ifdef DEBUG_CHILD_ABORT
- std::cout << "System::died aborting task " << absNodePath << "\n";
-#endif
- // Set state aborted since the job terminated abnormally, and provide a reason
- submittable->aborted(reason);
-}
-
-}
diff --git a/ecflow_4_0_7/ANode/src/System.hpp b/ecflow_4_0_7/ANode/src/System.hpp
deleted file mode 100644
index c396bf2..0000000
--- a/ecflow_4_0_7/ANode/src/System.hpp
+++ /dev/null
@@ -1,89 +0,0 @@
-#ifndef SYSTEM_HPP_
-#define SYSTEM_HPP_
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #18 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Works with class Signal
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <string>
-#include <boost/noncopyable.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/weak_ptr.hpp>
-
-#include "NodeFwd.hpp"
-
-namespace ecf {
-
-/// Job submission in ECF is a two phase step.
-/// phase 1: Spawn of ECF_JOB_CMD
-/// phase 2: Invocation of ECF_JOB_CMD, this creates the *real* job which communicates with the server
-/// For TEST :ECF_JOB_CMD = "%ECF_JOB% 1> %ECF_JOBOUT% 2>&1
-/// this collapses phase 1 and 2, to a single step
-/// For Operation:ECF_JOB_CMD = ecf_submit %USER% %SCHOST% %ECFJOB% %ECFJOBOUT%'
-/// This uses ecf_submit,This spawns the process to the different load levellers depending on OS, etc.
-/// and hence involves at least 2 process.
-/// This class handles phase 1, we capture the death of the child process
-/// and hence this class will not in operations handle the death of the real job
-/// created by ecf_submit.
-
-class System : private boost::noncopyable {
-public:
- static System* instance();
-
- /// Destroy the singleton. used in test only, to avoid valgrind issues
- static void destroy();
-
- /// Let the server set this. Typically only set once, however in test can be many times
- /// Note:: In test the Defs file in the server can be cleared, i.e. for each new test
- /// Hence we maintain a weak_ptr to the Defs.
- void setDefs(const defs_ptr& defs) { defs_ = defs;}
-
- // return true, if command can be spawned, else false.
- // For jobs, We can't store reference to Task*, as future functionality like
- // auto-migrate, etc, means we may end up pointing to garbage.
- // so instead we will store absNodePath. For other commands this can be empty
- bool spawn(const std::string& cmdToSpawn,const std::string& absPath,std::string& errorMsg);
-
- // Handle children that have stopped,aborted or terminated, etc
- // The signal handler is kept as light as possible, since it is re-entrant.
- // So Signal handles stores the termination state which handled later
- // by processTerminatedChildren. Typically when we un-block SIGCHILD
- void processTerminatedChildren();
-
- /// returns the number of active process.
- /// for debug only
- int process() const;
-
-private:
- ~System();
- System();
-
- /// Install signals that can catch signal from child process termination
- static void catchChildProcessTermination();
-
- // When a process terminates abnormally. This function is used to find the
- // associated task, and set it to the abort state.
- // Relies on the stored Defs ptr. which was set in the server
- void died( const std::string& absNodePath, const std::string& reason);
-
- /// Does the real work of spawning children
- int sys(const std::string& cmdToSpawn,const std::string& absPath,std::string& errorMsg);
-
-private:
- weak_defs_ptr defs_; // weak_ptr is an observer of a shared_ptr
- static System* instance_;
-};
-
-}
-#endif
diff --git a/ecflow_4_0_7/ANode/src/Task.cpp b/ecflow_4_0_7/ANode/src/Task.cpp
deleted file mode 100644
index e8aaedd..0000000
--- a/ecflow_4_0_7/ANode/src/Task.cpp
+++ /dev/null
@@ -1,804 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #204 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <assert.h>
-#include <sstream>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include "boost/filesystem/exception.hpp"
-#include <boost/bind.hpp>
-#include <boost/lexical_cast.hpp>
-#include <boost/make_shared.hpp>
-
-#include "Task.hpp"
-#include "Defs.hpp"
-#include "PrintStyle.hpp"
-#include "Suite.hpp"
-#include "SuiteChanged.hpp"
-#include "NodeTreeVisitor.hpp"
-#include "File.hpp"
-#include "Stl.hpp"
-#include "Str.hpp"
-#include "Indentor.hpp"
-#include "Log.hpp"
-#include "ExprAst.hpp"
-#include "JobsParam.hpp"
-#include "Ecf.hpp"
-#include "DefsDelta.hpp"
-#include "TaskScriptGenerator.hpp"
-#include "ChangeMgrSingleton.hpp"
-#include "Extract.hpp"
-#include "JobProfiler.hpp"
-
-namespace fs = boost::filesystem;
-using namespace ecf;
-using namespace std;
-using namespace boost;
-
-//#define DEBUG_TASK_LOCATION 1
-
-Task::~Task()
-{
- // Don't create the ChangeMgrSingleton during destruct sequence. (i.e in unit cases)
- // Since that will cause a memory leak
- if (!Ecf::server() && ChangeMgrSingleton::exists()) {
- ChangeMgrSingleton::instance()->notify_delete( this );
- }
-}
-
-task_ptr Task::create(const std::string& name)
-{
- return boost::make_shared<Task>( name );
-}
-
-std::ostream& Task::print(std::ostream& os) const
-{
- Indentor in;
- Indentor::indent(os) << "task " << name();
- if (!PrintStyle::defsStyle()) {
- std::string st = write_state();
- if (!st.empty()) os << " #" << st;
- }
- os << "\n";
-
- Node::print(os);
-
- // Generated variable are not persisted since they are created on demand
- // There *NO* point in printing them they will always be empty
-
- // Alias are not printed, but are check point able.
- if (!PrintStyle::defsStyle()) {
- Indentor in2;
- size_t node_vec_size = aliases_.size();
- for(size_t t = 0; t < node_vec_size; t++) { aliases_[t]->print( os ); }
- if (node_vec_size != 0) {
- Indentor in3;
- Indentor::indent(os) << "endalias\n";
- }
- }
-
- // if ( PrintStyle::defsStyle() ) Indentor::indent(os) << "endtask\n";
- return os;
-}
-
-std::string Task::write_state() const
-{
- // *IMPORTANT* we *CANT* use ';' character, since is used in the parser, when we have
- // multiple statement on a single line i.e.
- // task a; task b;
- std::stringstream ss;
- if (alias_no_ != 0) ss << " alias_no:" << alias_no_;
- ss << Submittable::write_state();
- return ss.str();
-}
-
-void Task::read_state(const std::string& line, const std::vector<std::string>& lineTokens) {
-
- // task t1 # alias_no:0 passwd:_DJP_
- std::string token;
- for(size_t i = 3; i < lineTokens.size(); i++) {
- token.clear();
- if (lineTokens[i].find("alias_no:") != std::string::npos ) {
- if (!Extract::split_get_second(lineTokens[i],token)) throw std::runtime_error( "Task::read_state could not read alias_no for task " + name());
- alias_no_ = Extract::theInt(token,"Task::read_state: invalid alias_no specified : " + line);
- break;
- }
- }
- Submittable::read_state(line,lineTokens);
-}
-
-std::ostream& operator<<(std::ostream& os, const Task& d) { return d.print(os); }
-
-bool Task::operator==(const Task& rhs) const
-{
- if (alias_no_ != rhs.alias_no_) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Task::operator== alias_no_(" << alias_no_ << ") != rhs.alias_no_(" << rhs.alias_no_ << ") : " << absNodePath() << "\n";
- }
-#endif
- return false;
- }
-
- size_t vec_size = aliases_.size();
- if ( vec_size != rhs.aliases_.size()) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Task::operator== aliases_.size() != rhs.aliases_.size() " << absNodePath() << "\n";
- std::cout << " aliases_.size() = " << vec_size << " rhs.aliases_.size() = " << rhs.aliases_.size() << "\n";
- }
-#endif
- return false;
- }
-
- for(size_t i =0; i < vec_size; ++i) {
-
- if ( !( *aliases_[i] == *rhs.aliases_[i] )) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "Task::operator== !( *aliases_[i] == *rhs.aliases_[i] : " << absNodePath() << "\n";
- }
-#endif
- return false;
- }
- }
-
- return Submittable::operator==(rhs);
-}
-
-alias_ptr Task::add_alias(std::vector<std::string>& user_file_contents,const NameValueVec& user_variables,bool create_directory)
-{
- // Create directory
- std::string dir_to_create;
- if (create_directory) {
-
- if (user_file_contents.empty()) {
- std::stringstream ss;
- ss << "Task::add_alias: No .usr file contents specified. Alias creation failed for task " << absNodePath();
- throw std::runtime_error(ss.str());
- }
-
- findParentUserVariableValue( Str::ECF_HOME(), dir_to_create);
- dir_to_create += absNodePath();
- if (!File::createDirectories(dir_to_create)) {
- throw std::runtime_error("Task::add_alias: could not create directory " + dir_to_create);
- }
- }
-
- // create alias
- std::string alias_name = "alias" + boost::lexical_cast<std::string>(alias_no_);
- alias_ptr alias = Alias::create( alias_name );
- alias->set_parent(this);
-
- // create .usr file
- if (create_directory) {
- std::string file_path = dir_to_create + "/" + alias_name + alias->script_extension();
- std::string error_msg;
- if (!File::create(file_path,user_file_contents,error_msg)) {
- std::stringstream ss; ss << "Task::add_alias: could not create .usr file at path(" << file_path <<"): " << error_msg.c_str();
- throw std::runtime_error(ss.str());
- }
- }
-
- // copy over events, meters, labels
- BOOST_FOREACH(const Meter& meter, meters()) { alias->addMeter(meter); }
- BOOST_FOREACH(const Event& event, events()) { alias->addEvent(event); }
- BOOST_FOREACH(const Label& label, labels()) { alias->addLabel(label); }
-
- // Add user_variables as variables. Note: to reduce memory we could choose
- // to only add those variable that have been changed/added. However this
- // would mean an alias could be affected by changed to an inherited variable.
- // Hence kept as existing sms functionality
- //
- // The variables may be **different** to normal variables in that they may contain a ":" & $
- // This is **not** allowed in normal variables.
- // i.e it allows for %A:1%, %A:2%, %A:3%
- // This is not really recommended but its what the old system supported.
- // **** Hence add_alias_variable by passes variable name checking ***
- NameValueVec::const_iterator theEnd = user_variables.end();
- for(NameValueVec::const_iterator i = user_variables.begin(); i!=theEnd; ++i) {
- alias->add_alias_variable((*i).first, (*i).second);
- }
-
- // increment alias number and store, alias in vector
- alias_no_++; // Alias number must be set to next valid alias number
- aliases_.push_back(alias);
-
- alias_change_no_ = Ecf::incr_state_change_no();
- add_remove_state_change_no_ = alias_change_no_;
- return alias;
-}
-
-alias_ptr Task::add_alias_only()
-{
- std::vector<std::string> empty_user_file_contents;
- NameValueVec empty_user_variables;
- return add_alias(empty_user_file_contents,empty_user_variables,false/* don't create directory or .usr file*/);
-}
-
-alias_ptr Task::add_alias(const std::string& name)
-{
- // Do not update alias_no, since that will be read in
- alias_ptr alias = Alias::create( name );
- alias->set_parent(this);
- aliases_.push_back(alias);
- return alias;
-}
-
-alias_ptr Task::find_alias(const std::string& name) const
-{
- size_t vec_size = aliases_.size();
- for(size_t i = 0; i < vec_size; i++) {
- if (aliases_[i]->name() == name) {
- return aliases_[i];
- }
- }
- return alias_ptr();
-}
-
-void Task::reset_alias_number()
-{
- alias_no_ = 0;
- alias_change_no_ = Ecf::incr_state_change_no();
-}
-
-node_ptr Task::findImmediateChild(const std::string& name, size_t& child_pos) const
-{
- child_pos = std::numeric_limits<std::size_t>::max();
- size_t vec_size = aliases_.size();
- for(size_t i = 0; i < vec_size; i++) {
- if (aliases_[i]->name() == name) {
- child_pos = i;
- return aliases_[i];
- }
- }
- return node_ptr();
-}
-
-void Task::begin()
-{
- if (aliases_.empty()) {
- if (alias_no_ != 0) {
- reset_alias_number();
- }
- }
-
- Submittable::begin();
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Task::begin()\n";
-#endif
-}
-
-void Task::requeue(
- bool resetRepeats,
- int clear_suspended_in_child_nodes,
- bool reset_next_time_slot)
-{
- if (aliases_.empty()) {
- if (alias_no_ != 0) {
- reset_alias_number();
- }
- }
-
- Submittable::requeue(resetRepeats,
- clear_suspended_in_child_nodes,
- reset_next_time_slot);
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "Task::requeue\n";
-#endif
-}
-
-void Task::accept(ecf::NodeTreeVisitor& v)
-{
- v.visitTask(this);
-}
-
-void Task::acceptVisitTraversor(ecf::NodeTreeVisitor& v)
-{
- v.visitTask(this);
-}
-
-const std::string& Task::debugType() const { return ecf::Str::TASK();}
-
-void Task::getAllNodes(std::vector<Node*>& vec) const
-{
- // See notes: getAllSubmittables, about reserve
- size_t vec_size = aliases_.size();
- for(size_t i = 0; i < vec_size; i++) {
- vec.push_back( aliases_[i].get() );
- }
-}
-
-void Task::immediateChildren(std::vector<node_ptr>& vec) const
-{
- size_t vec_size = aliases_.size();
- vec.reserve(vec.size() + vec_size);
- for(size_t i = 0; i < vec_size; i++) {
- vec.push_back( boost::dynamic_pointer_cast<Node>(aliases_[i]) );
- }
-}
-
-void Task::getAllTasks(std::vector<Task*>& vec) const
-{
- vec.push_back(const_cast<Task*>(this));
-}
-
-void Task::getAllSubmittables(std::vector<Submittable*>& vec) const
-{
- // *DO NOT reserve here, as it dominate time , for very large defs */
- // * Previously we had::
- // vec.reserve(vec.size() + vec_size + 1);
- // * This took 47 seconds when delete the full defs, i.e when check for active tasks
-
- vec.push_back(const_cast<Task*>(this));
- size_t vec_size = aliases_.size();
- for(size_t i = 0; i < vec_size; i++) {
- vec.push_back( aliases_[i].get() );
- }
-}
-
-node_ptr Task::find_node_up_the_tree(const std::string& name) const
-{
- size_t vec_size = aliases_.size();
- for(size_t i = 0; i < vec_size; i++) {
- if (aliases_[i]->name() == name ) {
- return aliases_[i];
- }
- }
- Node* the_parent = parent();
- if (the_parent) return the_parent->find_node_up_the_tree(name);
- return node_ptr();
-}
-
-void Task::get_all_active_submittables(std::vector<Submittable*>& vec) const
-{
- // See notes: getAllSubmittables, about reserve
- if (state() == NState::ACTIVE || state() == NState::SUBMITTED) {
- vec.push_back(const_cast<Task*>(this));
- }
- size_t vec_size = aliases_.size();
- for(size_t i = 0; i < vec_size; i++) {
- if (aliases_[i]->state() == NState::ACTIVE || aliases_[i]->state() == NState::SUBMITTED) {
- vec.push_back( aliases_[i].get() );
- }
- }
-}
-
-void Task::get_all_tasks(std::vector<task_ptr>& vec) const
-{
- vec.push_back(boost::dynamic_pointer_cast<Task>(non_const_this()));
-}
-
-void Task::get_all_nodes(std::vector<node_ptr>& nodes) const
-{
- nodes.push_back( non_const_this() );
- size_t vec_size = aliases_.size();
- for(size_t i = 0; i < vec_size; i++) {
- aliases_[i]->get_all_nodes(nodes);
- }
-}
-
-void Task::get_all_aliases(std::vector<alias_ptr>& destinationVec) const
-{
- destinationVec.reserve(destinationVec.size() + aliases_.size());
- std::copy(aliases_.begin(),aliases_.end(),std::back_inserter(destinationVec));
-}
-
-bool Task::resolveDependencies(JobsParam& jobsParam)
-{
- if (jobsParam.timed_out_of_job_generation()) return false;
- JobProfiler profile_me(this,jobsParam,JobProfiler::task_threshold());
- if (jobsParam.timed_out_of_job_generation()) return false;
-
-
- // Calling Submittable::resolveDependencies(jobsParam) up front can be expensive.
- // Due to trigger and complete evaluations. Hence low cost state checks first
-
- // Do state checking for tasks only. Note: container nodes inherit the most significant state
- // from the children, hence we can't use the same same algorithm for containers nodes and leaf
- // nodes like task.
- NState::State task_state = state();
- if ( task_state == NState::ACTIVE || task_state == NState::SUBMITTED || task_state == NState::UNKNOWN || task_state == NState::COMPLETE) {
-#ifdef DEBUG_DEPENDENCIES
- LOG(Log::DBG," Task::resolveDependencies() " << absNodePath() << " HOLDING as task state " << NState::toString(state()) << " is not valid for job submission" );
-#endif
- return false;
- }
- else if (task_state == NState::ABORTED) {
- // If the task was aborted, and we have not exceeded ECF_TRIES, then resubmit
- // otherwise ONLY in state QUEUED can we submit jobs
- // The Node could have been placed into SUSPENDED state
-
- /// If we have been killed by the user. Do not resubmit jobs, until begin or re-queue FLAG_ISSET
- if (flag().is_set(ecf::Flag::KILLED)) {
-#ifdef DEBUG_DEPENDENCIES
- LOG(Log::DBG," Task::resolveDependencies() " << absNodePath() << " HOLDING as task state " << NState::toString(state()) << " has been killed." );
-#endif
- return false;
- }
-
- std::string varValue;
- if (findParentUserVariableValue( Str::ECF_TRIES(), varValue )) {
- // std::cout << "tryNo_ = " << tryNo_ << " ECF_TRIES = " << varValue << "\n";
- try {
- int ecf_tries = boost::lexical_cast< int > (varValue);
- if ( try_no() >= ecf_tries ) {
-#ifdef DEBUG_DEPENDENCIES
- LOG(Log::DBG," Task::resolveDependencies() " << absNodePath() << " HOLDING as tryNo_(" << tryNo_ ") >= ECF_TRIES(" << ecf_tries << ") state = " << NState::toString(state()));
-#endif
- return false;
- }
- }
- catch ( boost::bad_lexical_cast& ) {
- LOG(Log::ERR,"Variable ECF_TRIES must be convertible to an integer. Can not resubmit job for task:" << absNodePath());
- return false;
- }
- }
- }
-#ifdef DEBUG
- else {
- /// Only one state left
- assert(task_state == NState::QUEUED);
- }
-#endif
-
- /// If we have been forcibly aborted by the user. Do not resubmit jobs, until *begin* or *re-queue*
- if (flag().is_set(ecf::Flag::FORCE_ABORT)) {
-#ifdef DEBUG_DEPENDENCIES
- LOG(Log::DBG," Task::resolveDependencies() " << absNodePath() << " HOLDING as task state " << NState::toString(state()) << " has been forcibly aborted." );
-#endif
- return false;
- }
-
-
- if ( ! Node::resolveDependencies(jobsParam) ) {
-
-#ifdef DEBUG_JOB_SUBMISSION
- LOG(Log::DBG, " Task::resolveDependencies " << absNodePath() << " could not resolve dependencies, may have completed");
- cout << "Task::resolveDependencies " << absNodePath() << " could not resolve dependencies may have completed" << endl;
-#endif
- return false;
- }
-
- /// By default node tree traversal is top down. hence we only check in limits, at *that* level.
- /// However *EACH* job submission can *affect* the in limits, hence we *must* check we are in
- /// limit *up* the node tree. Done last and only in this function (as opposed to Node) as an optimisation
- if (!check_in_limit_up_node_tree()) {
-#ifdef DEBUG_DEPENDENCIES
- LOG(Log::DBG," Task::resolveDependencies() " << absNodePath() << " FREE of TRIGGER and inLIMIT");
-#endif
- return false;
- }
-
- // call just before job submission, reset data members, update try_no, and generate variable
- // *PLACED* outside of submitJob() so that we can configure job generation file ECF_JOB for test/python
- increment_try_no(); // will increment state_change_no
-
- if ( jobsParam.createJobs() ) {
- // The task are ready for job submission.Clear process id and remote id (ECF_RID)
- // Locate the ecf files corresponding to the task. Pre-process
- // them(i.e expand includes, remove comments,manual) and perform
- // variable substitution. This will then form the jobs file.
- // If the job file already exist it is overridden
- submit_job_only( jobsParam );
- }
- else {
- // *************************************************************************************
- // Debug/test path only... Enabled for testing when we don't want to create/spawn jobs
- // ** Simulate ** job submission as closely as possible. For testing
- // *************************************************************************************
- jobsParam.push_back_submittable( this );
-
- // follow normal life cycle queued->submitted->active. In real life there may be a noticeable
- // time delay between process creation (via a user command, which could do anything)
- // and when created process start talking back to the server.
- // *** Setting state to SUBMITTED will increment any inlimit/Limit via handleStateChange
- set_state( NState::SUBMITTED );
-
- // The spawned process will typically call this, via client api. Set task into active state
- // *** Test path, we take the hit of calling handleStateChange again.
- init(Submittable::DUMMY_PROCESS_OR_REMOTE_ID());
- }
- return true;
-}
-
-void Task::generate_scripts( const std::map<std::string,std::string>& override) const
-{
- TaskScriptGenerator ecf(this);
- ecf.generate(override);
-}
-
-node_ptr Task::removeChild(Node* child)
-{
-#ifdef DEBUG
- assert(child);
- assert(child->isAlias());
-#endif
- SuiteChanged1 changed(suite());
- size_t node_vec_size = aliases_.size();
- for(size_t t = 0; t < node_vec_size; t++) {
- if (aliases_[t].get() == child) {
- child->set_parent(NULL);
- node_ptr node = boost::dynamic_pointer_cast<Alias>(aliases_[t]);
- aliases_.erase( aliases_.begin() + t);
- add_remove_state_change_no_ = Ecf::incr_state_change_no();
- return node ;
- }
- }
- // Should never happen
- LOG_ASSERT(false,"Task::removeChild: Could not remove child");
- return node_ptr();
-}
-
-bool Task::doDeleteChild(Node* child)
-{
- SuiteChanged1 changed(suite());
- std::vector<alias_ptr>::iterator the_end = aliases_.end();
- for(std::vector<alias_ptr>::iterator t = aliases_.begin(); t!=the_end; ++t) {
- if ( (*t).get() == child) {
- if (child && child->parent()) child->set_parent(NULL);
- aliases_.erase(t);
- add_remove_state_change_no_ = Ecf::incr_state_change_no();
- return true;
- }
- }
- return false;
-}
-
-bool Task::addChild( node_ptr, size_t)
-{
- // Only used during PLUG: aliases can't be plugged.
- LOG_ASSERT(false,"");
- return false;
-}
-
-bool Task::isAddChildOk( Node*, std::string& errorMsg) const
-{
- // Only used during PLUG: aliases can't be plugged.
- errorMsg += "Can not add children to a task node.";
- return false;
-}
-
-size_t Task::child_position(const Node* child) const
-{
- size_t vec_size = aliases_.size();
- for(size_t t = 0; t < vec_size; t++) {
- if (aliases_[t].get() == child) {
- return t;
- }
- }
- return std::numeric_limits<std::size_t>::max();
-}
-
-void Task::order(Node* immediateChild, NOrder::Order ord)
-{
- SuiteChanged1 changed(suite());
- switch (ord) {
- case NOrder::TOP: {
- for(std::vector<alias_ptr>::iterator i = aliases_.begin(); i != aliases_.end(); ++i) {
- if ((*i).get() == immediateChild) {
- alias_ptr node = (*i);
- aliases_.erase(i);
- aliases_.insert(aliases_.begin(),node);
- order_state_change_no_ = Ecf::incr_state_change_no();
- return;
- }
- }
- throw std::runtime_error("Task::order TOP, immediate child not found");
- }
- case NOrder::BOTTOM: {
- for(std::vector<alias_ptr>::iterator i = aliases_.begin(); i != aliases_.end(); ++i) {
- if ((*i).get() == immediateChild) {
- alias_ptr node = (*i);
- aliases_.erase(i);
- aliases_.push_back(node);
- order_state_change_no_ = Ecf::incr_state_change_no();
- return;
- }
- }
- throw std::runtime_error("Task::order BOTTOM, immediate child not found");
- }
- case NOrder::ALPHA: {
- std::sort(aliases_.begin(),aliases_.end(),
- boost::bind(Str::caseInsLess,
- boost::bind(&Node::name,_1),
- boost::bind(&Node::name,_2)));
- order_state_change_no_ = Ecf::incr_state_change_no();
- break;
- }
- case NOrder::ORDER: {
- std::sort(aliases_.begin(),aliases_.end(),
- boost::bind(Str::caseInsGreater,
- boost::bind(&Node::name,_1),
- boost::bind(&Node::name,_2)));
- order_state_change_no_ = Ecf::incr_state_change_no();
- break;
- }
- case NOrder::UP: {
- for(size_t t = 0; t < aliases_.size();t++) {
- if ( aliases_[t].get() == immediateChild) {
- if (t != 0) {
- alias_ptr node = aliases_[t];
- aliases_.erase(aliases_.begin()+t);
- t--;
- aliases_.insert(aliases_.begin()+t,node);
- order_state_change_no_ = Ecf::incr_state_change_no();
- }
- return;
- }
- }
- throw std::runtime_error("Task::order UP, immediate child not found");
- }
- case NOrder::DOWN: {
- for(size_t t = 0; t < aliases_.size();t++) {
- if ( aliases_[t].get() == immediateChild) {
- if (t != aliases_.size()-1) {
- alias_ptr node = aliases_[t];
- aliases_.erase(aliases_.begin()+t);
- t++;
- aliases_.insert(aliases_.begin()+t,node);
- order_state_change_no_ = Ecf::incr_state_change_no();
- }
- return;
- }
- }
- throw std::runtime_error("Task::order DOWN, immediate child not found");
- }
- }
-}
-
-bool Task::checkInvariants(std::string& errorMsg) const
-{
- if (!Node::checkInvariants(errorMsg)) return false;
-
- size_t vec_size = aliases_.size();
- for(size_t t = 0; t < vec_size; t++) {
- if (aliases_[t]->parent() != this) {
- std::stringstream ss;
- ss << "Task::checkInvariants alias(" << aliases_[t]->name() << ") parent() not correct. See task : " << absNodePath();
- errorMsg += ss.str();
- return false;
- }
- if (!aliases_[t]->checkInvariants(errorMsg)) {
- return false;
- }
- }
- if ( vec_size > alias_no_ ) {
- std::stringstream ss;
- ss << "Task::checkInvariants: alias vector size " << vec_size << " should be less or equal to alias_no_ " << alias_no_ << " for task " << absNodePath() << "\n";
- errorMsg += ss.str();
- return false;
- }
- return true;
-}
-
-void Task::handleStateChange()
-{
- /// Increment/decrement limits based on the current state
- update_limits();
-
- // Check if a re queue is required, then can eventually change the state, if
- // repeats, time,today, or cron are involved, hence must be done last
- // This will recurse up the node tree, causing repeats to increment, at the parent
- // level and resetting repeats in the children. To mimic nested loops.
- requeueOrSetMostSignificantStateUpNodeTree();
-}
-
-const std::string& Task::script_extension() const
-{
- // Migration support, allow user to specify extension. This allows users to use '.sms'
- // Note: This should be removed in the future since there is performance hit.
- // searching up the node tree, when most of the time we are using .ecf
- const std::string& ecf_extn = find_parent_user_variable_value(Str::ECF_EXTN());
- if (!ecf_extn.empty()) return ecf_extn;
- return File::ECF_EXTN(); // ".ecf"
-}
-
-void Task::collateChanges(DefsDelta& changes) const
-{
-// std::cout << "Task::collateChanges " << debugNodePath()
-// << " changes.client_state_change_no() = " << changes.client_state_change_no()
-// << " add_remove_state_change_no_ = " << add_remove_state_change_no_
-// << " order_state_change_no_ = " << order_state_change_no_
-// << " alias_change_no_ " << alias_change_no_
-// << "\n";
-
- /// All changes to Task should be on ONE compound_memento_ptr
- compound_memento_ptr comp;
-
- /// There no point doing a OrderMemento if children have been added/delete
- if (add_remove_state_change_no_ > changes.client_state_change_no()) {
- if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
- comp->add( boost::make_shared<AliasChildrenMemento>( aliases_ ) );
- }
- else if (order_state_change_no_ > changes.client_state_change_no()) {
- if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
- std::vector<std::string> order_vec; order_vec.reserve(aliases_.size());
- size_t node_vec_size = aliases_.size();
- for(size_t i =0; i < node_vec_size; i++) order_vec.push_back( aliases_[i]->name());
- comp->add( boost::make_shared<OrderMemento>( order_vec ) );
- }
-
- if (alias_change_no_ > changes.client_state_change_no()) {
- if (!comp.get()) comp = boost::make_shared<CompoundMemento>(absNodePath());
- comp->add( boost::make_shared<AliasNumberMemento>( alias_no_ ) );
- }
-
- // ** base class will add compound memento into changes.
- Submittable::incremental_changes(changes, comp);
-
- // Traversal to children
- size_t vec_size = aliases_.size();
- for(size_t t = 0; t < vec_size; t++) { aliases_[t]->collateChanges(changes); }
-}
-
-void Task::set_memento( const OrderMemento* memento ) {
-#ifdef DEBUG_MEMENTO
- std::cout << "Task::set_memento( const OrderMemento* ) " << debugNodePath() << "\n";
-#endif
-
- // Order aliases_ according to memento ordering
- const std::vector<std::string>& order = memento->order_;
- if (order.size() != aliases_.size()) {
- // something gone wrong.
- std::cout << "Task::set_memento OrderMemento, memento.size() " << order.size() << " Not the same as aliases_size() " << aliases_.size() << "\n";
- return;
- }
-
- std::vector<alias_ptr> vec; vec.reserve(aliases_.size());
- size_t node_vec_size = aliases_.size();
- for(size_t i = 0; i < order.size(); i++) {
- for(size_t t = 0; t < node_vec_size; t++) {
- if (order[i] == aliases_[t]->name()) {
- vec.push_back(aliases_[t]);
- break;
- }
- }
- }
- if (vec.size() != aliases_.size()) {
- std::cout << "Task::set_memento(const OrderMemento* memento) could not find all the names\n";
- return;
- }
-
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::ORDER);
- aliases_ = vec;
-}
-
-void Task::set_memento( const AliasChildrenMemento* memento ) {
-#ifdef DEBUG_MEMENTO
- std::cout << "Task::set_memento( const AliasChildrenMemento* ) " << debugNodePath() << "\n";
-#endif
-
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::ADD_REMOVE_NODE);
- aliases_ = memento->children_;
-
- // set up alias parent pointers. since they are *NOT* serialised.
- size_t vec_size = aliases_.size();
- for(size_t i = 0; i < vec_size; i++) {
- aliases_[i]->set_parent(this);
- }
-}
-
-void Task::set_memento( const AliasNumberMemento* memento ) {
-#ifdef DEBUG_MEMENTO
- std::cout << "Task::set_memento( const AliasNumberMemento* ) " << debugNodePath() << "\n";
-#endif
-
- ChangeMgrSingleton::instance()->add_aspect(ecf::Aspect::ALIAS_NUMBER);
- alias_no_ = memento->alias_no_;
-}
diff --git a/ecflow_4_0_7/ANode/src/Task.hpp b/ecflow_4_0_7/ANode/src/Task.hpp
deleted file mode 100644
index 8058f82..0000000
--- a/ecflow_4_0_7/ANode/src/Task.hpp
+++ /dev/null
@@ -1,172 +0,0 @@
-#ifndef TASK_HPP_
-#define TASK_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #108 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include "Alias.hpp"
-
-class Task : public Submittable {
-public:
- Task( const std::string& name )
- : Submittable(name),
- order_state_change_no_(0),
- add_remove_state_change_no_(0),
- alias_change_no_(0),
- alias_no_(0)
- {}
-
- Task()
- : order_state_change_no_(0),
- add_remove_state_change_no_(0),
- alias_change_no_(0),
- alias_no_(0)
- {}
-
- virtual ~Task();
-
- static task_ptr create(const std::string& name);
-
- std::ostream& print(std::ostream&) const;
- bool operator==(const Task& rhs) const;
-
- /// Add an alias. The .usr is populated with contents of user_file_contents
- /// If create_directory is unset we create the alias with creating directory or .usr file
- alias_ptr add_alias(std::vector<std::string>& user_file_contents,const NameValueVec& user_variables,bool create_directory = true);
-
- /// Add alias without creating directory & user file
- alias_ptr add_alias_only();
-
- /// For Addition of alias via Defs Files
- alias_ptr add_alias(const std::string& name);
-
- /// Given a name find the alias.
- alias_ptr find_alias(const std::string& name) const;
-
- /// Reset alias number. Used in testing
- void reset_alias_number();
-
- /// return list of aliases held by this task
- const std::vector<alias_ptr>& aliases() { return aliases_; }
- virtual void immediateChildren(std::vector<node_ptr>&) const;
-
- /// Overidden from Submittable
- virtual const std::string& script_extension() const;
-
- virtual node_ptr find_node_up_the_tree(const std::string& name) const;
-
- /// Added for consistency, really used to find relative nodes, aliases should never, be in referenced nodes
- virtual node_ptr find_relative_node(const std::vector<std::string>& pathToNode) { return node_ptr();}
-
- /// Overridden to reset the try number
- /// The tasks job can be invoked multiple times. For each invocation we want to preserve
- /// the output. The try number is used in SMSJOB/SMSJOBOUT to preserve the output when
- /// there are multiple runs. re-queue/begin() resets the try Number
- virtual void begin();
- virtual void requeue( bool resetRepeats,
- int clear_suspended_in_child_nodes,
- bool reset_next_time_slot);
-
- virtual Suite* suite() const { return parent()->suite(); }
- virtual Defs* defs() const { return (parent()) ? parent()->defs() : NULL;} // exposed to python hence check for NULL first
- virtual Task* isTask() const { return const_cast<Task*>(this);}
- virtual Submittable* isSubmittable() const { return const_cast<Task*>(this); }
-
- virtual void accept(ecf::NodeTreeVisitor&);
- virtual void acceptVisitTraversor(ecf::NodeTreeVisitor& v);
-
- virtual void getAllNodes(std::vector<Node*>&) const;
- virtual void getAllTasks(std::vector<Task*>&) const;
- virtual void getAllSubmittables(std::vector<Submittable*>&) const;
- virtual void get_all_active_submittables(std::vector<Submittable*>&) const;
- virtual void get_all_tasks(std::vector<task_ptr>&) const;
- virtual void get_all_nodes(std::vector<node_ptr>&) const;
- virtual void get_all_aliases(std::vector<alias_ptr>&) const;
-
- virtual const std::string& debugType() const;
-
- /// submits the jobs of the dependencies resolve
- virtual bool resolveDependencies(JobsParam& jobsParam);
-
- virtual node_ptr removeChild( Node* child);
- virtual bool addChild( node_ptr child,size_t position = std::numeric_limits<std::size_t>::max());
- virtual bool isAddChildOk( Node* child, std::string& errorMsg) const;
-
- virtual void order(Node* immediateChild, NOrder::Order);
- virtual void generate_scripts( const std::map<std::string,std::string>& override) const;
-
- virtual bool checkInvariants(std::string& errorMsg) const;
-
- virtual void collateChanges(DefsDelta&) const;
- void set_memento(const OrderMemento* m);
- void set_memento(const AliasChildrenMemento* m);
- void set_memento(const AliasNumberMemento* m);
- void set_memento(const SubmittableMemento* m) { Submittable::set_memento(m); }
-
- virtual void read_state(const std::string& line,const std::vector<std::string>& lineTokens);
-private:
- virtual size_t child_position(const Node*) const;
- virtual std::string write_state() const;
-
-private:
- /// For use by python interface,
- std::vector<alias_ptr>::const_iterator alias_begin() const { return aliases_.begin();}
- std::vector<alias_ptr>::const_iterator alias_end() const { return aliases_.end();}
- friend void export_Task();
-
-private:
- // Overridden from Node to increment/decrement limits
- virtual void handleStateChange();
- virtual bool doDeleteChild(Node* child);
-
- // Overridden to locate alias's
- virtual node_ptr findImmediateChild(const std::string& name, size_t& child_pos) const;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/) {
- ar & boost::serialization::base_object<Submittable>(*this); // Serialise base class information
- ar & alias_no_;
- ar & aliases_;
-
- // Setup the alias parent pointers. Since they are not serialised
- // ********************************************************************
- // WE do not serialise the Alias parent pointer:
- // WHY: AliasChildrenMenento saves a vector of aliases, had we serialised
- // the parent, it would also serialise the parent pointer(Task)
- // i.e the ENTIRE task, and then Task parent, and so on, up the parent hierarchy.
- // In our case it lead to unregistered class exception when trying to
- // serialise the Task's parent.
- // SOLN: WE will not serialise the alias parent pointer. This will be left to
- // Parent task.
- // ********************************************************************
- if (Archive::is_loading::value) {
- size_t vec_size = aliases_.size();
- for(size_t i = 0; i < vec_size; i++) {
- aliases_[i]->set_parent(this);
- }
- }
- }
-
-private:
- unsigned int order_state_change_no_; // no need to persist
- unsigned int add_remove_state_change_no_;// no need to persist
-
- unsigned int alias_change_no_; // no need to persist, for alias number only
- unsigned int alias_no_;
- std::vector<alias_ptr> aliases_;
-};
-
-std::ostream& operator<<(std::ostream& os, const Task&);
-
-#endif
diff --git a/ecflow_4_0_7/ANode/src/TaskScriptGenerator.cpp b/ecflow_4_0_7/ANode/src/TaskScriptGenerator.cpp
deleted file mode 100644
index 1ad0db8..0000000
--- a/ecflow_4_0_7/ANode/src/TaskScriptGenerator.cpp
+++ /dev/null
@@ -1,263 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #14 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <boost/filesystem.hpp>
-
-#include "TaskScriptGenerator.hpp"
-#include "Task.hpp"
-#include "File.hpp"
-#include "Ecf.hpp"
-#include "Str.hpp"
-
-using namespace std;
-using namespace boost;
-namespace fs = boost::filesystem;
-
-namespace ecf {
-
-TaskScriptGenerator::TaskScriptGenerator(const Task* task)
-: task_(task), is_dummy_task_(false)
-{
- /// if ECF_DUMMY_TASK specified ignore
- std::string theValue;
- is_dummy_task_ = task_->findParentUserVariableValue(Str::ECF_DUMMY_TASK(), theValue);
- if (is_dummy_task_) return;
-
- /// if ECF_FILES specified use this before ECF_HOME
- if (task_->findParentUserVariableValue( Str::ECF_FILES(),ecf_files_)) {
- // Create any missing directories if ECF_FILES is specified
- try { fs::create_directories(ecf_files_); }
- catch ( std::exception& e) {
- std::stringstream ss;
- ss << "TaskScriptGenerator: Could not create directories for ECF_FILES " << ecf_files_ << " " << e.what();
- throw std::runtime_error(ss.str());
- }
- }
-
- /// Find ECF_HOME and ECF_INCLUDE
- if (!task_->findParentUserVariableValue( Str::ECF_HOME(),ecf_home_)) {
- std::stringstream ss;
- ss << "TaskScriptGenerator: Could not generate scripts for task " << task_->absNodePath() << " no ECF_HOME specified\n";
- throw std::runtime_error(ss.str());
- }
- if (!task_->findParentUserVariableValue( Str::ECF_INCLUDE(),ecf_include_)) {
- std::stringstream ss;
- ss << "TaskScriptGenerator: Could not generate scripts for task " << task_->absNodePath() << " no ECF_INCLUDE specified\n";
- throw std::runtime_error(ss.str());
- }
-
- // Create any missing directories,
- try { fs::create_directories(ecf_home_); }
- catch ( std::exception& e) {
- std::stringstream ss;
- ss << "TaskScriptGenerator: Could not create directories for ECF_HOME " << ecf_home_ << " " << e.what();
- throw std::runtime_error(ss.str());
- }
-
- try { fs::create_directories(ecf_include_); }
- catch ( std::exception& e) {
- std::stringstream ss;
- ss << "TaskScriptGenerator: Could not create directories for ECF_INCLUDE " << ecf_include_ << " " << e.what();
- throw std::runtime_error(ss.str());
- }
-}
-
-void TaskScriptGenerator::generate(const std::map<std::string,std::string>& override)
-{
- // Ignore generation for dummy tasks
- if (is_dummy_task_) return;
-
- // If ECF_FILES was specified use that in preference to ECF_HOME for the ecf files.
- std::string root_directory_for_ecf_files;
- if (!ecf_files_.empty()) root_directory_for_ecf_files = ecf_files_;
- else root_directory_for_ecf_files = ecf_home_;
-
- // Note: task_->absNodePath() starts with /.
- std::string ecf_file_path = root_directory_for_ecf_files + task_->absNodePath() + task_->script_extension();
- if (fs::exists(ecf_file_path)) {
- std::cout << "Can not generate. Script file " << ecf_file_path << " already exists\n";
- return;
- }
-
- if (!File::createMissingDirectories(ecf_file_path)) {
- std::stringstream ss;
- ss << "TaskScriptGenerator::generate: Could not create missing directories '" << ecf_file_path << "' for task " << task_->absNodePath();
- throw std::runtime_error(ss.str());
- }
-
- // Create file head.h and tail.h in directory ECF_INCLUDE, check to see if they exist first
- // If the variable ECF_CLIENT_EXE_PATH is specified use it
- generate_head_file();
- generate_tail_file();
-
-
- // Create ECF file with default template or custom file.
- //cout << "creating ecf file " << ecf_file_path << "\n";
- std::string contents;
- std::map<std::string,std::string>::const_iterator it = override.find(task_->absNodePath());
- if (it == override.end()) {
- contents = getDefaultTemplateEcfFile();
- }
- else {
- contents = (*it).second;
- }
-
- std::string errorMsg;
- if (!File::create(ecf_file_path,contents,errorMsg)) {
- std::stringstream ss;
- ss << "TaskScriptGenerator::generate: Could not create '.ecf' script for task " << task_->absNodePath() << " " << errorMsg;
- throw std::runtime_error(ss.str());
- }
- std::cout << "Generated script file " << ecf_file_path << "\n";
-}
-
-std::string TaskScriptGenerator::getDefaultTemplateEcfFile() const
-{
- std::string content;
-
- std::string sleep,var_sleep;
- if (task_->findParentUserVariableValue("SLEEP",var_sleep)) sleep = "sleep %SLEEP%\n";
- else sleep = "sleep 1\n";
-
- std::string client_exe = "%ECF_CLIENT_EXE_PATH:";
- client_exe += Ecf::CLIENT_NAME();
- client_exe += "% ";
-
- content += "%include <head.h>\n";
- content += "%manual\n";
- content += "This is the default **generated** ecf script file\n";
- content += "If the task has events, meters or labels then the associated client\n";
- content += "to server commands are automatically generated.\n";
- content += "Will default to sleep for one second in between calls to the events, meters & labels,\n";
- content += "this can be overridden by adding a variable SLEEP\n";
- content += "%end\n";
- content += "\n";
- content += "%comment\n";
- content += "#============================================================\n";
- content += "# Using angle brackets means we look in directory ECF_INCLUDE\n";
- content += "# and then ECF_HOME\n";
- content += "#============================================================\n";
- content += "%end\n";
- content += "\n";
- content += "echo do some work\n";
- BOOST_FOREACH(const Event& e, task_->events()) {
- content += client_exe + "--event=" + e.name_or_number() + "\n";
- content += sleep;
- }
-
- content += "\n";
- BOOST_FOREACH(const Meter& m, task_->meters()) {
- content += "for i in";
- for(int i = m.min(); i <= m.max(); i = i + 1) {
- content += " ";
- content += boost::lexical_cast<std::string>(i);
- }
- content += "\n";
- content += "do\n";
- content += " " + client_exe + "--meter=" + m.name() + " $i\n";
- content += " " + sleep;
- content += "done\n";
- }
- content += "\n";
-
- /// labels require at least 2 arguments,
- BOOST_FOREACH(const Label& label, task_->labels()) {
-
- if (!label.new_value().empty()) {
- content += client_exe + "--label=" + label.name() + " " + label.new_value() + "\n";
- }
- else if (!label.value().empty()) {
- content += client_exe + "--label=" + label.name() + " " + label.value() + "\n";
- }
- content += sleep;
- }
-
- content += "\n";
- if (task_->events().empty() && task_->meters().empty()) {
- content += sleep;
- }
- content += "\necho end of job\n";
- content += "\n%include <tail.h>\n";
- return content;
-}
-
-void TaskScriptGenerator::generate_head_file() const
-{
- std::string path = ecf_include_ + "/head.h";
- if (fs::exists(path)) return;
-
- std::string client_exe = "%ECF_CLIENT_EXE_PATH:";
- client_exe += Ecf::CLIENT_NAME();
- client_exe += "% ";
-
- std::string contents;
- contents += "#!/bin/ksh\n";
- contents += "set -e # stop the shell on first error\n";
- contents += "set -u # fail when using an undefined variable\n";
- contents += "set -x # echo script lines as they are executed\n";
- contents += "\n";
- contents += "# Defines the variables that are needed for any communication with ECF\n";
- contents += "export ECF_PORT=%ECF_PORT% # The server port number\n";
- contents += "export ECF_NODE=%ECF_NODE% # The name of ecf host that issued this task\n";
- contents += "export ECF_NAME=%ECF_NAME% # The name of this current task\n";
- contents += "export ECF_PASS=%ECF_PASS% # A unique password\n";
- contents += "export ECF_TRYNO=%ECF_TRYNO% # Current try number of the task\n";
- contents += "export ECF_RID=$$\n";
- contents += "\n";
- contents += "# Tell ecFlow we have started\n";
- contents += client_exe + "--init=$$\n";
- contents += "\n";
- contents += "# Defined a error handler\n";
- contents += "ERROR() {\n";
- contents += " set +e # Clear -e flag, so we don't fail\n";
- contents += " " + client_exe + "--abort=trap # Notify ecFlow that something went wrong, using 'trap' as the reason\n";
- contents += " trap 0 # Remove the trap\n";
- contents += " exit 0 # End the script\n";
- contents += "}\n";
- contents += "\n";
- contents += "# Trap any calls to exit and errors caught by the -e flag\n";
- contents += "trap ERROR 0\n";
- contents += "\n";
- contents += "# Trap any signal that may cause the script to fail\n";
- contents += "trap '{ echo \"Killed by a signal\"; ERROR ; }' 1 2 3 4 5 6 7 8 10 12 13 15\n";
-
- std::string errorMsg;
- if (!File::create(path,contents,errorMsg)) {
- std::stringstream ss;
- ss << "TaskScriptGenerator::generate_tail_file: Could not create head.h " << path << " " << errorMsg;
- throw std::runtime_error(ss.str());
- }
-}
-
-void TaskScriptGenerator::generate_tail_file() const
-{
- std::string path = ecf_include_ + "/tail.h";
- if (fs::exists(path)) return;
-
- std::string contents = "%ECF_CLIENT_EXE_PATH:";
- contents += Ecf::CLIENT_NAME();
- contents +="% --complete # Notify ecFlow of a normal end\n";
-
- contents += "trap 0 # Remove all traps\n";
- contents += "exit 0 # End the shell\n";
-
- std::string errorMsg;
- if (!File::create(path,contents,errorMsg)) {
- std::stringstream ss;
- ss << "TaskScriptGenerator::generate_tail_file: Could not create tail.h " << path << " " << errorMsg;
- throw std::runtime_error(ss.str());
- }
-}
-}
diff --git a/ecflow_4_0_7/ANode/src/TaskScriptGenerator.hpp b/ecflow_4_0_7/ANode/src/TaskScriptGenerator.hpp
deleted file mode 100644
index a37f4f5..0000000
--- a/ecflow_4_0_7/ANode/src/TaskScriptGenerator.hpp
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef TASKSCRIPTGENERATOR_HPP_
-#define TASKSCRIPTGENERATOR_HPP_
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <string>
-#include <map>
-#include <boost/noncopyable.hpp>
-class Task;
-
-namespace ecf {
-
-class TaskScriptGenerator : private boost::noncopyable {
-public:
- TaskScriptGenerator(const Task*);
-
- void generate(const std::map<std::string,std::string>& override);
-
-private:
- void generate_head_file() const;
- void generate_tail_file() const;
- std::string getDefaultTemplateEcfFile() const;
-
-private:
- const Task* task_;
- bool is_dummy_task_;
- std::string ecf_files_;
- std::string ecf_home_;
- std::string ecf_include_;
-};
-
-}
-#endif
diff --git a/ecflow_4_0_7/ANode/src/TimeDepAttrs.cpp b/ecflow_4_0_7/ANode/src/TimeDepAttrs.cpp
deleted file mode 100644
index 712b598..0000000
--- a/ecflow_4_0_7/ANode/src/TimeDepAttrs.cpp
+++ /dev/null
@@ -1,872 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #281 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <assert.h>
-#include <boost/foreach.hpp>
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-
-#include "TimeDepAttrs.hpp"
-#include "Str.hpp"
-#include "Log.hpp"
-#include "Ecf.hpp"
-#include "Memento.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-
-///////////////////////////////////////////////////////////////////////////////////////////
-
-void TimeDepAttrs::begin()
-{
- // Let time base attributes use, relative duration if applicable
- // reset requires calendar, to update next time slot, which is used in why command
- const Calendar& calendar = node_->suite()->calendar();
- for(size_t i = 0; i < todayVec_.size(); i++) { todayVec_[i].reset(calendar);}
- for(size_t i = 0; i < timeVec_.size(); i++) { timeVec_[i].reset(calendar);}
- for(size_t i = 0; i < crons_.size(); i++) { crons_[i].reset(calendar);}
-
- for(size_t i = 0; i < days_.size(); i++) { days_[i].clearFree(); }
- for(size_t i = 0; i < dates_.size(); i++) { dates_[i].clearFree(); }
-}
-
-void TimeDepAttrs::requeue(bool reset_next_time_slot) {
-
- /// If a job takes longer than it slots, then that slot is missed, and next slot is used
- /// Note we do *NOT* reset for requeue as we want to advance to the next time slot
- /// *NOTE* Update calendar will *free* time dependencies *even* time series. They rely
- /// on this function to clear the time dependencies so they *HOLD* the task.
- const Calendar& calendar = node_->suite()->calendar();
- for(size_t i = 0; i < todayVec_.size(); i++) { todayVec_[i].requeue(calendar,reset_next_time_slot);}
- for(size_t i = 0; i < timeVec_.size(); i++) { timeVec_[i].requeue(calendar,reset_next_time_slot);}
- for(size_t i = 0; i < crons_.size(); i++) { crons_[i].requeue(calendar,reset_next_time_slot);}
-
- for(size_t i = 0; i < days_.size(); i++) { days_[i].clearFree(); }
- for(size_t i = 0; i < dates_.size(); i++) { dates_[i].clearFree(); }
-}
-
-void TimeDepAttrs::calendarChanged(const ecf::Calendar& c )
-{
- // For time/today/cron attributes if the time is free, it *remains* free until re-queued
- // However if we have day/date dependencies, that do NOT match, then we should *NOT* free
- // any time/today/cron attributes.
- //
- // task t
- // day Monday
- // time 10:00
- //
- // Hence if we are on Sunday we do *NOT* want to free the time on SUNDAY
- // (Otherwise we will end up running the task at Monday Midnight
- // and not Monday at 10.00)
- //
- bool have_day = false;
- bool at_least_one_day_free = false;
- for(size_t i = 0; i < days_.size(); i++){
- have_day = true;
- days_[i].calendarChanged(c);
- if (!at_least_one_day_free) at_least_one_day_free = days_[i].isFree(c);
- }
-
- bool have_date = false;
- bool at_least_one_date_free = false;
- for(size_t i = 0; i < dates_.size(); i++) {
- have_date = true;
- dates_[i].calendarChanged(c);
- if (!at_least_one_date_free) at_least_one_date_free = dates_[i].isFree(c);
- }
-
- if (have_day || have_date ) {
- if ( at_least_one_day_free || at_least_one_date_free) {
- for(size_t i = 0; i < crons_.size(); i++) { crons_[i].calendarChanged(c); }
- for(size_t i = 0; i < todayVec_.size(); i++) { todayVec_[i].calendarChanged(c); }
- for(size_t i = 0; i < timeVec_.size(); i++) { timeVec_[i].calendarChanged(c); }
- }
- }
- else {
- // No Day or Date, If time matches calendarChanged(c) will free time dependencies
- for(size_t i = 0; i < crons_.size(); i++) { crons_[i].calendarChanged(c); }
- for(size_t i = 0; i < todayVec_.size(); i++) { todayVec_[i].calendarChanged(c); }
- for(size_t i = 0; i < timeVec_.size(); i++) { timeVec_[i].calendarChanged(c); }
- }
-}
-
-void TimeDepAttrs::markHybridTimeDependentsAsComplete()
-{
- // If hybrid clock and then we may have day/date/cron time dependencies
- // which mean that node will be stuck in the QUEUED state, i.e since the
- // date/day does not change with the hybrid clock.
- // hence Mark these Nodes as complete
- const Calendar& calendar = node_->suite()->calendar();
- if (node_->state() != NState::COMPLETE && calendar.hybrid()) {
- if ( !dates_.empty() || !days_.empty() || !crons_.empty()) {
-
- int noOfTimeDependencies = 0;
- if (!dates_.empty()) noOfTimeDependencies++;
- if (!days_.empty()) noOfTimeDependencies++;
- if (!crons_.empty()) noOfTimeDependencies++;
-
- bool oneDateIsFree = false;
- bool oneDayIsFree = false;
- bool oneCronIsFree = false;
-
- for(size_t i=0;i<dates_.size();i++) { if (dates_[i].validForHybrid(calendar)) { if (noOfTimeDependencies == 1) { node_->setStateOnly(NState::QUEUED); return;}oneDateIsFree = true;break;}}
- for(size_t i=0;i<days_.size();i++) { if (days_[i].validForHybrid(calendar)) { if (noOfTimeDependencies == 1) { node_->setStateOnly(NState::QUEUED); return;}oneDayIsFree = true;break;}}
- for(size_t i=0;i<crons_.size();i++) { if (crons_[i].validForHybrid(calendar)) { if (noOfTimeDependencies == 1) { node_->setStateOnly(NState::QUEUED); return;}oneCronIsFree = true;break;}}
-
- if ( oneDateIsFree || oneDayIsFree || oneCronIsFree) {
- if ( noOfTimeDependencies > 1 ) {
- // when we have multiple time dependencies they results *MUST* be anded for the node to be free.
- if (!dates_.empty() && !oneDateIsFree) { node_->setStateOnly(NState::COMPLETE); return;}
- if (!days_.empty() && !oneDayIsFree) { node_->setStateOnly(NState::COMPLETE); return;}
- if (!crons_.empty() && !oneCronIsFree) { node_->setStateOnly(NState::COMPLETE); return;}
-
- // We will only get here, if we have a multiple time dependencies any there is one free in each category
- node_->setStateOnly(NState::QUEUED);
- return;
- }
- }
-
- node_->setStateOnly(NState::COMPLETE);
- }
- }
-}
-
-void TimeDepAttrs::resetRelativeDuration()
-{
- for(size_t i = 0; i < crons_.size(); i++) { crons_[i].resetRelativeDuration(); }
- for(size_t i = 0; i < todayVec_.size(); i++) { todayVec_[i].resetRelativeDuration();}
- for(size_t i = 0; i < timeVec_.size(); i++) { timeVec_[i].resetRelativeDuration(); }
-}
-
-// #define DEBUG_REQUEUE 1
-bool TimeDepAttrs::testTimeDependenciesForRequeue() const
-{
- // Check for re-queue required for all time related attributes
- const Calendar& calendar = node_->suite()->calendar();
-
-#ifdef DEBUG_REQUEUE
- LogToCout logtocout;
- LOG(Log::DBG,"TimeDepAttrs::testTimeDependenciesForRequeue() " << node_->debugNodePath() << " calendar " << calendar.toString());
-#endif
-
-
- // When we have a mixture of cron *with* other time based attributes
- // The cron *takes* priority. Crons should always return true, for checkForRequeue
- BOOST_FOREACH(const CronAttr& cron, crons_ ) {
- if (cron.checkForRequeue(calendar)) { // will always return true
-#ifdef DEBUG_REQUEUE
- LOG(Log::DBG," TimeDepAttrs::testTimeDependenciesForRequeue() " << node_->debugNodePath() << " for cron");
-#endif
- return true;
- }
- }
-
-
- if (!timeVec_.empty()) {
- TimeSlot the_min,the_max; // Needs to handle multiple single slot time attributes
- BOOST_FOREACH(const ecf::TimeAttr& time, timeVec_) { time.min_max_time_slots(the_min,the_max);}
- BOOST_FOREACH(const ecf::TimeAttr& time, timeVec_) {
- if (time.checkForRequeue(calendar,the_min,the_max)) {
-#ifdef DEBUG_REQUEUE
- LOG(Log::DBG," TimeDepAttrs::testTimeDependenciesForRequeue() " << node_->debugNodePath() << " for time " << time.toString());
-#endif
- return true;
- }
- }
- }
-
-
- if (!todayVec_.empty()) {
- TimeSlot the_min,the_max; // Needs to handle multiple single slot today attributes
- BOOST_FOREACH(const ecf::TodayAttr& today,todayVec_) { today.min_max_time_slots(the_min,the_max);}
- BOOST_FOREACH(const ecf::TodayAttr& today,todayVec_) {
- if (today.checkForRequeue(calendar,the_min,the_max)) {
-#ifdef DEBUG_REQUEUE
- LOG(Log::DBG," TimeDepAttrs::testTimeDependenciesForRequeue() " << node_->debugNodePath() << " for today " << today.toString());
-#endif
- return true;;
- }
- }
- }
-
-
- // **********************************************************************
- // If we get here there are **NO** time/today/cron dependencies which are free
- // We now need to determine if this node has a future time dependency which
- // should re-queue this node
- // *********************************************************************
- BOOST_FOREACH(const DateAttr& date, dates_ ) {
- if (date.checkForRequeue(calendar)) {
-#ifdef DEBUG_REQUEUE
- LOG(Log::DBG," TimeDepAttrs::testTimeDependenciesForRequeue() " << node_->debugNodePath() << " for date " << date.toString());
-#endif
- return true;
- }
- }
-
- BOOST_FOREACH(const DayAttr& day, days_ ) {
- if (day.checkForRequeue(calendar)) {
-#ifdef DEBUG_REQUEUE
- LOG(Log::DBG," TimeDepAttrs::testTimeDependenciesForRequeue() " << node_->debugNodePath() << " for day " << day.toString());
-#endif
- return true;
- }
- }
-
-#ifdef DEBUG_REQUEUE
- LOG(Log::DBG," TimeDepAttrs::testTimeDependenciesForRequeue() " << node_->debugNodePath() << " HOLDING ");
-#endif
- return false;
-}
-
-
-void TimeDepAttrs::miss_next_time_slot()
-{
- // Note: when we have multiple time dependencies.
- // We need find valid next time dependency:
- // time 10:00
- // time 11:00
- // time 12:00 14:00 00:30
- // Also we could have a mix:
- // time 10:00
- // today 10:30
- // time 11:00
- // time 12:00 14:00 00:30
-
- // for the moment assume, they have been added sequentially,
- // hence only first non expired time is updated to miss next time slot
- for(size_t i=0;i<timeVec_.size();i++) {
- if (timeVec_[i].time_series().is_valid()) {
- timeVec_[i].miss_next_time_slot();
- break;
- }
- }
- for(size_t i=0;i<todayVec_.size();i++){
- if (todayVec_[i].time_series().is_valid()) {
- todayVec_[i].miss_next_time_slot();
- break;
- }
- }
- for(size_t i=0;i<crons_.size();i++) {
- if (crons_[i].time_series().is_valid()) {
- crons_[i].miss_next_time_slot();
- break;
- }
- }
-}
-
-
-void TimeDepAttrs::freeHoldingDateDependencies()
-{
- // Multiple time dependencies of the same type are *ORed*
- // Multiple time dependencies of different types are *ANDed*
- //
- // Hence since we have multiple time dependencies of the same
- // type here, we need free only one of them
- const Calendar& calendar = node_->suite()->calendar();
- for(size_t i=0;i<dates_.size();i++) {
- if (!dates_[i].isFree(calendar)) {
- dates_[i].setFree();
- break;
- }
- }
-}
-
-void TimeDepAttrs::freeHoldingTimeDependencies()
-{
- // Multiple time dependencies of the same type are *ORed*
- // Multiple time dependencies of different types are *ANDed*
- //
- // If we have multiple time dependencies of different types
- // we need only free one in each category
- const Calendar& calendar = node_->suite()->calendar();
- for(size_t i=0;i<timeVec_.size();i++) {
- if (!timeVec_[i].isFree(calendar)) {
- timeVec_[i].setFree();
- timeVec_[i].miss_next_time_slot();
- break;
- }
- }
- for(size_t i=0;i<todayVec_.size();i++) {
- if (!todayVec_[i].isFree(calendar)) {
- todayVec_[i].setFree();
- todayVec_[i].miss_next_time_slot();
- break;
- }
- }
- for(size_t i=0;i<days_.size();i++) {
- if (!days_[i].isFree(calendar)) {
- days_[i].setFree();
- break;
- }
- }
- for(size_t i=0;i<crons_.size();i++) {
- if (!crons_[i].isFree(calendar)) {
- crons_[i].setFree();
- crons_[i].miss_next_time_slot();
- break;
- }
- }
-}
-
-
-bool TimeDepAttrs::timeDependenciesFree() const
-{
- if (!timeVec_.empty() || !todayVec_.empty() || !dates_.empty() || !days_.empty() || !crons_.empty()) {
-
- int noOfTimeDependencies = 0;
- if (!timeVec_.empty()) noOfTimeDependencies++;
- if (!todayVec_.empty()) noOfTimeDependencies++;
- if (!dates_.empty()) noOfTimeDependencies++;
- if (!days_.empty()) noOfTimeDependencies++;
- if (!crons_.empty()) noOfTimeDependencies++;
-
- bool oneDateIsFree = false;
- bool oneDayIsFree = false;
- bool oneTodayIsFree = false;
- bool oneTimeIsFree = false;
- bool oneCronIsFree = false;
-
- const Calendar& calendar = node_->suite()->calendar();
- for(size_t i=0;i<timeVec_.size();i++) { if (timeVec_[i].isFree(calendar)) {if ( noOfTimeDependencies == 1) return true;oneTimeIsFree = true;break;}}
- for(size_t i=0;i<crons_.size();i++) { if (crons_[i].isFree(calendar)) {if ( noOfTimeDependencies == 1) return true;oneCronIsFree = true;break;}}
- for(size_t i=0;i<dates_.size();i++) { if (dates_[i].isFree(calendar)) {if ( noOfTimeDependencies == 1) return true;oneDateIsFree = true;break;}}
- for(size_t i=0;i<days_.size();i++) { if (days_[i].isFree(calendar)) {if ( noOfTimeDependencies == 1) return true;oneDayIsFree = true;break;}}
-
- if (!todayVec_.empty()) {
- // : single Today: (single-time) is free, if calendar time >= today_time
- // : single Today: (range) is free, if calendar time == (one of the time ranges)
- // : multi Today : (single | range)is free, if calendar time == (one of the time ranges | tody_time)
- if (todayVec_.size() == 1 ) {
- // Single Today Attribute: could be single slot or range
- if (todayVec_[0].isFree(calendar)) { if ( noOfTimeDependencies == 1) return true;oneTodayIsFree = true;}
- }
- else {
- // Multiple Today Attributes, each could single, or range
- for(size_t i=0;i<todayVec_.size();i++) {
- if (todayVec_[i].isFreeMultipleContext(calendar)) {if ( noOfTimeDependencies == 1) return true;oneTodayIsFree = true;break;}
- }
- }
- }
-
-
- if ( oneDateIsFree || oneDayIsFree || oneTodayIsFree || oneTimeIsFree || oneCronIsFree) {
- if ( noOfTimeDependencies > 1 ) {
- // *When* we have multiple time dependencies of *different types* then the results
- // *MUST* be anded for the node to be free.
- if (!dates_.empty() && !oneDateIsFree) return false;
- if (!days_.empty() && !oneDayIsFree) return false;
- if (!todayVec_.empty() && !oneTodayIsFree) return false;
- if (!timeVec_.empty() && !oneTimeIsFree) return false;
- if (!crons_.empty() && !oneCronIsFree) return false;
-
- // We will only get here, if we have a multiple time dependencies and they are free
- return true;
- }
- }
- }
-
- return false;
-}
-
-bool TimeDepAttrs::time_today_cron_is_free() const
-{
- if (!timeVec_.empty() || !todayVec_.empty() || !crons_.empty()) {
-
- int noOfTimeDependencies = 0;
- if (!timeVec_.empty()) noOfTimeDependencies++;
- if (!todayVec_.empty()) noOfTimeDependencies++;
- if (!crons_.empty()) noOfTimeDependencies++;
-
- bool oneTodayIsFree = false;
- bool oneTimeIsFree = false;
- bool oneCronIsFree = false;
-
- const Calendar& calendar = node_->suite()->calendar();
- for(size_t i=0;i<timeVec_.size();i++) { if (timeVec_[i].isFree(calendar)) {if ( noOfTimeDependencies == 1) return true;oneTimeIsFree = true;break;}}
- for(size_t i=0;i<crons_.size();i++) { if (crons_[i].isFree(calendar)) {if ( noOfTimeDependencies == 1) return true;oneCronIsFree = true;break;}}
-
- if (!todayVec_.empty()) {
- // : single Today: (single-time) is free, if calendar time >= today_time
- // : single Today: (range) is free, if calendar time == (one of the time ranges)
- // : multi Today : (single | range)is free, if calendar time == (one of the time ranges | tody_time)
- if (todayVec_.size() == 1 ) {
- // Single Today Attribute: could be single slot or range
- if (todayVec_[0].isFree(calendar)) { if ( noOfTimeDependencies == 1) return true;oneTodayIsFree = true;}
- }
- else {
- // Multiple Today Attributes, each could single, or range
- for(size_t i=0;i<todayVec_.size();i++) {
- if (todayVec_[i].isFreeMultipleContext(calendar)) {if ( noOfTimeDependencies == 1) return true;oneTodayIsFree = true;break;}
- }
- }
- }
-
-
- if ( oneTodayIsFree || oneTimeIsFree || oneCronIsFree) {
- if ( noOfTimeDependencies > 1 ) {
- // *When* we have multiple time dependencies of *different types* then the results
- // *MUST* be anded for the node to be free.
- if (!todayVec_.empty() && !oneTodayIsFree) return false;
- if (!timeVec_.empty() && !oneTimeIsFree) return false;
- if (!crons_.empty() && !oneCronIsFree) return false;
-
- // We will only get here, if we have a multiple time dependencies and they are free
- return true;
- }
- }
- }
-
- return false;
-}
-
-std::ostream& TimeDepAttrs::print(std::ostream& os) const
-{
- BOOST_FOREACH(const ecf::TimeAttr& t, timeVec_) { t.print(os); }
- BOOST_FOREACH(const ecf::TodayAttr& t,todayVec_) { t.print(os); }
- BOOST_FOREACH(const DateAttr& date, dates_) { date.print(os); }
- BOOST_FOREACH(const DayAttr& day, days_) { day.print(os); }
- BOOST_FOREACH(const CronAttr& cron, crons_) { cron.print(os); }
- return os;
-}
-
-bool TimeDepAttrs::operator==(const TimeDepAttrs& rhs) const
-{
- if (timeVec_.size() != rhs.timeVec_.size()) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "TimeDepAttrs::operator== (timeVec_.size() != rhs.timeVec_.size()) " << node_->debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- for(unsigned i = 0; i < timeVec_.size(); ++i) {
- if (!(timeVec_[i] == rhs.timeVec_[i] )) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "TimeDepAttrs::operator== (!(timeVec_[i] == rhs.timeVec_[i] )) " << node_->debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- }
-
- if (todayVec_.size() != rhs.todayVec_.size()) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "TimeDepAttrs::operator== (todayVec_.size() != rhs.todayVec_.size()) " << node_->debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- for(unsigned i = 0; i < todayVec_.size(); ++i) {
- if (!(todayVec_[i] == rhs.todayVec_[i] )) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "TimeDepAttrs::operator== (!(todayVec_[i] == rhs.todayVec_[i] )) " << node_->debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- }
-
- if (dates_.size() != rhs.dates_.size()) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "TimeDepAttrs::operator== (dates_.size() != rhs.dates_.size()) " << node_->debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- for(unsigned i = 0; i < dates_.size(); ++i) {
- if (!(dates_[i] == rhs.dates_[i]) ) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "TimeDepAttrs::operator== (!(dates_[i] == rhs.dates_[i]) " << node_->debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- }
-
- if (days_.size() != rhs.days_.size()) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "TimeDepAttrs::operator== (days_.size() != rhs.days_.size()) " << node_->debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- for(unsigned i = 0; i < days_.size(); ++i) {
- if (!(days_[i] == rhs.days_[i]) ) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "TimeDepAttrs::operator== (!(days_[i] == rhs.days_[i]) " << node_->debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- }
-
- if (crons_.size() != rhs.crons_.size()) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "TimeDepAttrs::operator== (crons_.size() != rhs.crons_.size()) " << node_->debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- for(unsigned i = 0; i < crons_.size(); ++i) {
- if (!(crons_[i] == rhs.crons_[i]) ) {
-#ifdef DEBUG
- if (Ecf::debug_equality()) {
- std::cout << "TimeDepAttrs::operator== (!(crons_[i] == rhs.crons_[i]) " << node_->debugNodePath() << "\n";
- }
-#endif
- return false;
- }
- }
-
- return true;
-}
-
-
-//#define DEBUG_WHY 1
-void TimeDepAttrs::why(std::vector<std::string>& vec,const std::string& prefix) const
-{
-#ifdef DEBUG_WHY
- std::cout << " TimeDepAttrs::why " << node_->debugNodePath() << " checking time dependencies\n";
-#endif
- // postfix = <attr-type dependent> <next run time > < optional current state>
- std::string postFix;
- const Calendar& c = node_->suite()->calendar();
- for(size_t i = 0; i < days_.size(); i++) { postFix.clear(); if (days_[i].why(c,postFix)) { vec.push_back(prefix + postFix); }}
- for(size_t i = 0; i < dates_.size(); i++) { postFix.clear(); if (dates_[i].why(c,postFix)) { vec.push_back(prefix + postFix); }}
- for(size_t i = 0; i < todayVec_.size(); i++){ postFix.clear(); if (todayVec_[i].why(c,postFix)){ vec.push_back(prefix + postFix); }}
- for(size_t i = 0; i < timeVec_.size(); i++) { postFix.clear(); if (timeVec_[i].why(c,postFix)) { vec.push_back(prefix + postFix); }}
- for(size_t i = 0; i < crons_.size(); i++) { postFix.clear(); if (crons_[i].why(c,postFix)) { vec.push_back(prefix + postFix); }}
-
-}
-
-bool TimeDepAttrs::checkInvariants(std::string& errorMsg) const
-{
- if (node_ == NULL) {
- errorMsg +="TimeDepAttrs::checkInvariants node_ not set";
- return false;
- }
- BOOST_FOREACH(const ecf::TimeAttr& t, timeVec_) { if (!t.checkInvariants(errorMsg)) return false; }
- BOOST_FOREACH(const ecf::TodayAttr& t,todayVec_) { if (!t.checkInvariants(errorMsg)) return false; }
- BOOST_FOREACH(const CronAttr& cron, crons_ ) { if (!cron.checkInvariants(errorMsg)) return false; }
- return true;
-}
-
-
-void TimeDepAttrs::clear()
-{
- timeVec_.clear();
- todayVec_.clear();
- dates_.clear();
- days_.clear();
- crons_.clear();
-}
-
-
-void TimeDepAttrs::addTime(const ecf::TimeAttr& t)
-{
- timeVec_.push_back(t);
- node_->state_change_no_ = Ecf::incr_state_change_no();
-}
-
-void TimeDepAttrs::addToday(const ecf::TodayAttr& t)
-{
- todayVec_.push_back(t);
- node_->state_change_no_ = Ecf::incr_state_change_no();
-}
-
-void TimeDepAttrs::addDate( const DateAttr& d)
-{
- dates_.push_back( d );
- node_->state_change_no_ = Ecf::incr_state_change_no();
-}
-
-void TimeDepAttrs::addDay( const DayAttr& d)
-{
- days_.push_back( d );
- node_->state_change_no_ = Ecf::incr_state_change_no();
-}
-
-void TimeDepAttrs::addCron( const CronAttr& d)
-{
- if (d.time().isNULL()) {
- throw std::runtime_error("TimeDepAttrs::addCron: The cron is in-complete, no time specified");
- }
- if (d.time().hasIncrement() && !node_->repeat_.empty()) {
- std::stringstream ss;
- ss << "TimeDepAttrs::addCron: Node " << node_->absNodePath() << " already has a repeat. Inappropriate to add two looping structures at the same level\n";
- throw std::runtime_error(ss.str());
- }
- crons_.push_back( d );
- node_->state_change_no_ = Ecf::incr_state_change_no();
-}
-
-
-void TimeDepAttrs::deleteTime(const std::string& name )
-{
- if (name.empty()) {
- timeVec_.clear(); // delete all
- node_->state_change_no_ = Ecf::incr_state_change_no();
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "TimeDepAttrs::deleteTime\n";
-#endif
- return;
- }
- TimeAttr attr( TimeSeries::create(name) ); // can throw if parse fails
- delete_time(attr); // can throw if search fails
-}
-void TimeDepAttrs::delete_time( const ecf::TimeAttr& attr )
-{
- size_t theSize = timeVec_.size();
- for(size_t i = 0; i < theSize; i++) {
- // Dont use '==' since that compares additional state like makeFree_
- if (timeVec_[i].structureEquals(attr)) {
- timeVec_.erase( timeVec_.begin() + i );
- node_->state_change_no_ = Ecf::incr_state_change_no();
-
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "TimeDepAttrs::delete_time\n";
-#endif
- return;
- }
- }
- throw std::runtime_error("TimeDepAttrs::delete_time: Can not find time attribute: ");
-}
-
-
-void TimeDepAttrs::deleteToday(const std::string& name)
-{
- if (name.empty()) {
- todayVec_.clear();
- node_->state_change_no_ = Ecf::incr_state_change_no();
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "TimeDepAttrs::deleteToday\n";
-#endif
- return;
- }
-
- TodayAttr attr( TimeSeries::create(name) ); // can throw if parse fails
- delete_today(attr); // can throw if search fails
-}
-void TimeDepAttrs::delete_today(const ecf::TodayAttr& attr)
-{
- size_t theSize = todayVec_.size();
- for(size_t i = 0; i < theSize; i++) {
- // Dont use '==' since that compares additional state like makeFree_
- if (todayVec_[i].structureEquals(attr)) {
- todayVec_.erase( todayVec_.begin() + i );
- node_->state_change_no_ = Ecf::incr_state_change_no();
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "TimeDepAttrs::delete_today\n";
-#endif
- return;
- }
- }
- throw std::runtime_error("TimeDepAttrs::delete_today: Can not find today attribute: " + attr.toString());
-}
-
-void TimeDepAttrs::deleteDate(const std::string& name)
-{
- if (name.empty()) {
- dates_.clear();
- node_->state_change_no_ = Ecf::incr_state_change_no();
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "TimeDepAttrs::deleteDate\n";
-#endif
- return;
- }
-
- DateAttr attr( DateAttr::create(name) ); // can throw if parse fails
- delete_date(attr); // can throw if search fails
-}
-void TimeDepAttrs::delete_date(const DateAttr& attr)
-{
- for(size_t i = 0; i < dates_.size(); i++) {
- // Dont use '==' since that compares additional state like makeFree_
- if (attr.structureEquals(dates_[i]) ) {
- dates_.erase( dates_.begin() + i );
- node_->state_change_no_ = Ecf::incr_state_change_no();
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "TimeDepAttrs::delete_date\n";
-#endif
- return;
- }
- }
- throw std::runtime_error("TimeDepAttrs::delete_date: Can not find date attribute: " + attr.toString());
-}
-
-
-void TimeDepAttrs::deleteDay(const std::string& name)
-{
- if (name.empty()) {
- days_.clear();
- node_->state_change_no_ = Ecf::incr_state_change_no();
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "TimeDepAttrs::deleteDay\n";
-#endif
- return;
- }
-
- DayAttr attr( DayAttr::create(name) ); // can throw if parse fails.
- delete_day(attr); // can throw if search fails
-}
-void TimeDepAttrs::delete_day(const DayAttr& attr)
-{
- for(size_t i = 0; i < days_.size(); i++) {
- // Dont use '==' since that compares additional state like makeFree_
- if (attr.structureEquals(days_[i]) ) {
- days_.erase( days_.begin() + i );
- node_->state_change_no_ = Ecf::incr_state_change_no();
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "TimeDepAttrs::delete_day\n";
-#endif
- return;
- }
- }
- throw std::runtime_error("TimeDepAttrs::delete_day: Can not find day attribute: " + attr.toString());
-}
-
-void TimeDepAttrs::deleteCron(const std::string& name)
-{
- if (name.empty()) {
- crons_.clear();
- node_->state_change_no_ = Ecf::incr_state_change_no();
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "TimeDepAttrs::deleteCron\n";
-#endif
- return;
- }
-
- CronAttr attr = CronAttr::create(name); // can throw if parse fails
- delete_cron(attr); // can throw if search fails
-}
-
-void TimeDepAttrs::delete_cron(const ecf::CronAttr& attr)
-{
- for(size_t i = 0; i < crons_.size(); i++) {
- // Dont use '==' since that compares additional state like makeFree_
- if (attr.structureEquals(crons_[i]) ) {
- crons_.erase( crons_.begin() + i );
- node_->state_change_no_ = Ecf::incr_state_change_no();
-#ifdef DEBUG_STATE_CHANGE_NO
- std::cout << "TimeDepAttrs::deleteCron\n";
-#endif
- return ;
- }
- }
- throw std::runtime_error("TimeDepAttrs::delete_cron: Can not find cron attribute: " + attr.toString());
-}
-
-// =================================================================================
-
-
-bool TimeDepAttrs::set_memento( const NodeTodayMemento* memento ) {
-
-#ifdef DEBUG_MEMENTO
- std::cout << "TimeDepAttrs::set_memento(const NodeTodayMemento* memento) " << node_->debugNodePath() << "\n";
-#endif
-
- for(size_t i = 0; i < todayVec_.size(); ++i) {
- // We need to ignore state changes in TodayAttr, (ie we don't use equality operator)
- // otherwise today will never compare
- if ( todayVec_[i].structureEquals(memento->attr_) ) {
- todayVec_[i] = memento->attr_; // need to copy over time series state
- return true;
- }
- }
- return false;
-}
-
-bool TimeDepAttrs::set_memento( const NodeTimeMemento* memento ) {
-
-#ifdef DEBUG_MEMENTO
- std::cout << "TimeDepAttrs::set_memento(const NodeTimeMemento* memento) " << node_->debugNodePath() << "\n";
-#endif
-
- for(size_t i = 0; i < timeVec_.size(); ++i) {
- // We need to ignore state changes in TimeAttr, (ie we don't use equality operator)
- // otherwise time will never compare
- if ( timeVec_[i].structureEquals(memento->attr_) ) {
- timeVec_[i] = memento->attr_; // need to copy over time series state
- return true;
- }
- }
- return false;
-}
-
-bool TimeDepAttrs::set_memento( const NodeCronMemento* memento ) {
-
-#ifdef DEBUG_MEMENTO
- std::cout << "TimeDepAttrs::set_memento(const NodeCronMemento* memento) " << node_->debugNodePath() << "\n";
-#endif
-
- for(size_t i = 0; i < crons_.size(); ++i) {
- // We need to ignore state changes (ie we don't use equality operator)
- // otherwise attributes will never compare
- if ( crons_[i].structureEquals(memento->attr_) ) {
- crons_[i] = memento->attr_; // need to copy over time series state
- return true;
- }
- }
- return false;
-}
-
-bool TimeDepAttrs::set_memento( const NodeDayMemento* memento ) {
-
-#ifdef DEBUG_MEMENTO
- std::cout << "TimeDepAttrs::set_memento(const NodeDayMemento* memento) " << node_->debugNodePath() << "\n";
-#endif
-
- for(size_t i = 0; i < days_.size(); ++i) {
- // We need to ignore state changes (ie we don't use equality operator)
- // otherwise attributes will never compare
- if ( days_[i].structureEquals(memento->attr_) ) {
- if (memento->attr_.isSetFree()) days_[i].setFree();
- else days_[i].clearFree();
- return true;
- }
- }
- return false;
-}
-
-bool TimeDepAttrs::set_memento( const NodeDateMemento* memento ) {
-
-#ifdef DEBUG_MEMENTO
- std::cout << "TimeDepAttrs::set_memento(const NodeDateMemento* memento) " << node_->debugNodePath() << "\n";
-#endif
-
- for(size_t i = 0; i < dates_.size(); ++i) {
- // We need to ignore state changes (ie we don't use equality operator)
- // otherwise attributes will never compare
- if ( dates_[i].structureEquals(memento->attr_) ) {
- if (memento->attr_.isSetFree()) dates_[i].setFree();
- else dates_[i].clearFree();
- return true;
- }
- }
- return false;
-}
-
diff --git a/ecflow_4_0_7/ANode/src/TimeDepAttrs.hpp b/ecflow_4_0_7/ANode/src/TimeDepAttrs.hpp
deleted file mode 100644
index 674413c..0000000
--- a/ecflow_4_0_7/ANode/src/TimeDepAttrs.hpp
+++ /dev/null
@@ -1,148 +0,0 @@
-#ifndef TIME_DEP_ATTRS_HPP_
-#define TIME_DEP_ATTRS_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #231 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <ostream>
-
-#include <boost/serialization/base_object.hpp>
-#include <boost/serialization/utility.hpp>
-#include <boost/serialization/vector.hpp> // no need to include <vector>
-
-#include "TimeAttr.hpp"
-#include "TodayAttr.hpp"
-#include "DateAttr.hpp"
-#include "DayAttr.hpp"
-#include "CronAttr.hpp"
-#include "NodeFwd.hpp"
-
-class TimeDepAttrs {
-public:
- TimeDepAttrs(Node* node) : node_(node) {}
- TimeDepAttrs() : node_(NULL) {}
-
- // needed by node serialisation
- void set_node(Node* n) { node_ = n; }
-
- void begin();
-
- /// If a job takes longer than it slots, then that slot is missed, and next slot is used
- /// Note we do *NOT* reset for requeue as we want to advance the valid time slots.
- /// *NOTE* Update calendar will *free* time dependencies *even* time series. They rely
- /// on this function to clear the time dependencies so they *HOLD* the task.
- ///
- /// If we have done an interactive run or complete, *dont* increment next_time_slot_
- void requeue(bool reset_next_time_slot);
-
- void miss_next_time_slot();
- void freeHoldingDateDependencies();
- void freeHoldingTimeDependencies();
-
- void calendarChanged(const ecf::Calendar& c);
-
- // standard functions: ==============================================
- std::ostream& print(std::ostream&) const;
- bool operator==(const TimeDepAttrs& rhs) const;
- bool checkInvariants(std::string& errorMsg) const;
-
- bool timeDependenciesFree() const;
- bool time_today_cron_is_free() const; /* used by viewer */
-
- // Access functions: ======================================================
- const std::vector<ecf::TimeAttr>& timeVec() const { return timeVec_; }
- const std::vector<ecf::TodayAttr>& todayVec() const { return todayVec_; }
- const std::vector<DateAttr>& dates() const { return dates_; }
- const std::vector<DayAttr>& days() const { return days_; }
- const std::vector<ecf::CronAttr>& crons() const { return crons_; }
-
- // Add functions: ===============================================================
- void addTime( const ecf::TimeAttr& );
- void addToday( const ecf::TodayAttr& );
- void addDate( const DateAttr& );
- void addDay( const DayAttr& );
- void addCron( const ecf::CronAttr& );
-
- // Delete functions: can throw std::runtime_error ===================================
- // if name argument is empty, delete all attributes of that type
- // Can throw std::runtime_error of the attribute can not be found
- void deleteTime(const std::string& name );
- void delete_time( const ecf::TimeAttr& );
- void deleteToday(const std::string& name);
- void delete_today(const ecf::TodayAttr&);
- void deleteDate(const std::string& name);
- void delete_date(const DateAttr&);
- void deleteDay(const std::string& name);
- void delete_day(const DayAttr&);
- void deleteCron(const std::string& name);
- void delete_cron(const ecf::CronAttr&);
-
- // Change functions: ================================================================
- /// returns true the change was made else false, Can throw std::runtime_error for parse errors
-
- // mementos functions:
- /// Collect all the state changes, so that only small subset is returned to client
- bool set_memento(const NodeTodayMemento* );
- bool set_memento(const NodeTimeMemento* );
- bool set_memento(const NodeDayMemento* );
- bool set_memento(const NodeCronMemento* );
- bool set_memento(const NodeDateMemento* );
-
- void why(std::vector<std::string>& theReasonWhy,const std::string& prefix) const;
- bool testTimeDependenciesForRequeue() const;
- void resetRelativeDuration();
-
-
-/// For use by python interface,
- std::vector<ecf::TimeAttr>::const_iterator time_begin() const { return timeVec_.begin();}
- std::vector<ecf::TimeAttr>::const_iterator time_end() const { return timeVec_.end();}
- std::vector<ecf::TodayAttr>::const_iterator today_begin() const { return todayVec_.begin();}
- std::vector<ecf::TodayAttr>::const_iterator today_end() const { return todayVec_.end();}
- std::vector<DateAttr>::const_iterator date_begin() const { return dates_.begin();}
- std::vector<DateAttr>::const_iterator date_end() const { return dates_.end();}
- std::vector<DayAttr>::const_iterator day_begin() const { return days_.begin();}
- std::vector<DayAttr>::const_iterator day_end() const { return days_.end();}
- std::vector<ecf::CronAttr>::const_iterator cron_begin() const { return crons_.begin();}
- std::vector<ecf::CronAttr>::const_iterator cron_end() const { return crons_.end();}
-
-
- void clear(); /// Clear *ALL* internal attributes
-
-
- /// Under the hybrid calendar some time dependent attributes may not be applicable
- /// i.e if day,date,cron attributes does correspond to 24 hours of today, then we
- /// need make them as complete.
- void markHybridTimeDependentsAsComplete();
-
-private:
- Node* node_; // *NOT* persisted must be set by the parent class
-
- std::vector<ecf::TimeAttr> timeVec_;
- std::vector<ecf::TodayAttr> todayVec_;
- std::vector<DateAttr> dates_;
- std::vector<DayAttr> days_;
- std::vector<ecf::CronAttr> crons_;
-
-private:
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/) {
- ar & timeVec_;
- ar & todayVec_;
- ar & dates_;
- ar & days_;
- ar & crons_;
- }
-};
-
-#endif
diff --git a/ecflow_4_0_7/ANode/test/MyDefsFixture.hpp b/ecflow_4_0_7/ANode/test/MyDefsFixture.hpp
deleted file mode 100644
index f7bc3b4..0000000
--- a/ecflow_4_0_7/ANode/test/MyDefsFixture.hpp
+++ /dev/null
@@ -1,249 +0,0 @@
-#ifndef MYDEFSFIXTURE_HPP_
-#define MYDEFSFIXTURE_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Description : The structure ONLY used to test the persistence/migration
-// as each new object is created we add it here, to test
-// Serialisation read/write and migration of previous fixtures
-//============================================================================
-#include <boost/lexical_cast.hpp>
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "Alias.hpp"
-#include <algorithm> //for for_each()
-// =======================================================================
-// This struct is used in the node migration tests.
-// If we ever add to this , then update TestMigration.cpp
-// **Ensure** that we keep old fixture.def file, to test that future ecflow
-// versions can migrate old data.
-// =======================================================================
-struct MyDefsFixture {
-
- MyDefsFixture(const std::string& fileName = "defsfile.txt") : defsfile_()
- {
- suite_ptr suite = create_suite();
-
- // Must be done last
- defsfile_.addSuite( suite );
- defsfile_.add_extern("/limits:event");
- defsfile_.add_extern("/a/b/c:meter");
- defsfile_.add_extern("/a/b/c/d");
-
- // add an empty suite. Needed for CHECK_JOB_GEN_ONLY cmd
- defsfile_.addSuite( Suite::create("EmptySuite" ) );
-
- // Check expression parse
- std::string errorMsg, warningMsg;
- bool result = defsfile_.check(errorMsg,warningMsg);
- if (!result || !errorMsg.empty()) {
- std::cout << errorMsg;
- assert(false);
- }
- }
- ~MyDefsFixture() {}
-
- const Defs& fixtureDefsFile() const { return defsfile_; }
-
- void remove_host_depedent_server_variables()
- {
- // Allow test data to be used on other platforms
- defsfile_.set_server().delete_server_variable("ECF_LOG");
- defsfile_.set_server().delete_server_variable("ECF_CHECK");
- defsfile_.set_server().delete_server_variable("ECF_CHECKOLD");
- }
-
-
- defs_ptr create_defs() const {
-
- defs_ptr defs = Defs::create();
-
- defs->addSuite( create_suite() );
- defs->add_extern("/limits:event");
- defs->add_extern("/a/b/c:meter");
- defs->add_extern("/a/b/c/d");
- defs->set_server().add_or_update_user_variables("MyDefsFixture_user_variable","This is a user variable added to server");
-
- // add an empty suite. Needed for CHECK_JOB_GEN_ONLY cmd
- defs->addSuite( Suite::create("EmptySuite" ) );
-
- // Check expression parse
- std::string errorMsg, warningMsg;
- bool result = defs->check(errorMsg,warningMsg);
- if (!result || !errorMsg.empty()) {
- std::cout << errorMsg;
- assert(false);
- }
- return defs;
- }
-
- Defs defsfile_;
-
-private:
- suite_ptr create_suite() const {
- std::string sname = "suiteName";
- suite_ptr suite = Suite::create( sname );
-
- ClockAttr clockAttr(false);
- clockAttr.date(1,1,2009);
- clockAttr.set_gain_in_seconds(3600);
- clockAttr.startStopWithServer(true);
- suite->addClock( clockAttr );
-
- suite->addAutoCancel( ecf::AutoCancelAttr(2) );
- suite->addVariable( Variable("VAR","value") );
- suite->addVariable( Variable("VAR1","\"value\"") );
- suite->addVariable( Variable("ECF_FETCH","\"smsfetch -F %ECF_FILES% -I %ECF_INCLUDE%\"") );
-
- suite->add_task( "t1" );
- suite->add_task( "t2" );
- task_ptr suiteTask = suite->add_task( "t3" );
- suiteTask->add_part_trigger( PartExpression("t1 == complete") );
- suiteTask->add_part_trigger( PartExpression("t2 == complete",false) );
- suiteTask->add_part_complete( PartExpression("t1 == complete") );
- suiteTask->add_part_complete( PartExpression("t2 == complete",true) );
-
- std::vector<ecf::Child::CmdType> child_cmds;
- child_cmds.push_back(ecf::Child::INIT);
- child_cmds.push_back(ecf::Child::EVENT);
- child_cmds.push_back(ecf::Child::METER);
- child_cmds.push_back(ecf::Child::LABEL);
- child_cmds.push_back(ecf::Child::WAIT);
- child_cmds.push_back(ecf::Child::ABORT);
- child_cmds.push_back(ecf::Child::COMPLETE);
- suiteTask->addZombie( ZombieAttr(ecf::Child::USER, child_cmds, ecf::User::FOB,10) );
- suiteTask->addZombie( ZombieAttr(ecf::Child::ECF, child_cmds, ecf::User::FAIL,100) );
- suiteTask->addZombie( ZombieAttr(ecf::Child::PATH, child_cmds, ecf::User::BLOCK,100) );
-
-
- task_ptr suiteTask4 = suite->add_task( "t4" );
- suiteTask4->addZombie( ZombieAttr(ecf::Child::USER, child_cmds, ecf::User::ADOPT,10) );
- suiteTask4->addZombie( ZombieAttr(ecf::Child::ECF, child_cmds, ecf::User::REMOVE,100) );
- suiteTask4->addZombie( ZombieAttr(ecf::Child::PATH, child_cmds, ecf::User::BLOCK,100) );
-
-
- ecf::CronAttr cronAttr;
- ecf::TimeSlot start( 0, 0 );
- ecf::TimeSlot finish( 10, 0 );
- ecf::TimeSlot incr( 0, 5 );
- std::vector<int> weekdays; for(int i=0;i<7;++i) weekdays.push_back(i);
- std::vector<int> daysOfMonth;for(int i=1;i<32;++i) daysOfMonth.push_back(i);
- std::vector<int> months; for(int i=1;i<13;++i) months.push_back(i);
- cronAttr.addTimeSeries(start,finish,incr);
- cronAttr.addWeekDays( weekdays );
- cronAttr.addDaysOfMonth(daysOfMonth);
- cronAttr.addMonths( months );
- suite->addCron( cronAttr );
-
- ecf::LateAttr lateAttr;
- lateAttr.addSubmitted( ecf::TimeSlot(3,12) );
- lateAttr.addActive( ecf::TimeSlot(3,12) );
- lateAttr.addComplete( ecf::TimeSlot(4,12), true);
-
- std::string suiteLimit = "suiteLimit";
- suite->addLimit( Limit(suiteLimit,10) );
-
- std::vector<std::string> stringList; stringList.reserve(3);
- stringList.push_back("10");
- stringList.push_back("20");
- stringList.push_back("30");
-
- // Add tasks with all the repeat variants
- task_ptr t5 = suite->add_task( "t5" );
- t5->addRepeat( RepeatEnumerated("AEnum",stringList));
-
- task_ptr t6 = suite->add_task( "t6" );
- t6->addRepeat( RepeatString("aString",stringList));
-
- task_ptr t7 = suite->add_task( "t7" );
- t7->addRepeat( RepeatInteger("rep",0,100,1) );
-
- task_ptr t8 = suite->add_task( "t8" );
- t8->addRepeat( RepeatDate("YMD",20090916,20090916,1) );
-
- task_ptr t9 = suite->add_task( "t9" );
- t9->addRepeat( RepeatDay(2) );
-
-
- for (int i = 0; i < 3; ++i) {
- std::string fname = "familyName";
- std::string tname = "taskName";
- std::string eventName = "eventName";
- std::string labelName = "labelName";
- std::string limitName = "limitName";
- if ( i != 0 ) {
- fname += boost::lexical_cast< std::string >( i );
- tname += boost::lexical_cast< std::string >( i );
- labelName += boost::lexical_cast< std::string >( i );
- }
-
- family_ptr fam = suite->add_family( fname );
- fam->addDate( DateAttr(0,0,2009) ); // 0 is equivalent to a *
- fam->addRepeat( RepeatEnumerated("AEnum",stringList));
- fam->addAutoCancel( ecf::AutoCancelAttr( ecf::TimeSlot(1,0), true));
- fam->addVariable( Variable("VAR","value") );
- fam->addTime( ecf::TimeAttr(ecf::TimeSlot(0,0),ecf::TimeSlot(10,1),ecf::TimeSlot(0,1),true) );
- fam->addLimit( Limit(limitName,20) );
- fam->addLate( lateAttr );
-
- task_ptr task = fam->add_task( tname );
- task->addDate( DateAttr(1,2,2009) );
- task->addDay( DayAttr(DayAttr::MONDAY) );
- task->addVariable( Variable("VAR1","\"value\"") );
- task->addEvent( Event(i) );
- task->addEvent( Event(i+1, eventName ) );
- task->addMeter( Meter("myMeter",0,100,100) );
- task->addLabel( Label(labelName,"\"labelValue\"") );
- task->addTime( ecf::TimeAttr(ecf::TimeSlot(10,10),true) );
- task->addToday( ecf::TodayAttr(ecf::TimeSlot(10,12)) );
- task->addToday( ecf::TodayAttr(ecf::TimeSlot(0,1),ecf::TimeSlot(0,3),ecf::TimeSlot(0,1),true) );
- task->addDefStatus( DState::COMPLETE );
- task->addInLimit( InLimit(suiteLimit,"/" + sname ));
- task->addVerify( VerifyAttr(NState::COMPLETE,3) );
- task->addLate( lateAttr );
- if (i == 2) {
- std::string compExpr = "../familyName" + boost::lexical_cast< std::string >( i-1 );
- compExpr += "/taskName" + boost::lexical_cast< std::string >( i-1 );
- compExpr += ":myMeter ge 10";
- task->add_complete( compExpr );
-
- std::string expression = "../familyName" + boost::lexical_cast< std::string >( i-1 );
- expression += "/taskName" + boost::lexical_cast< std::string >( i-1 );
- expression += " == complete";
- task->add_trigger( expression );
- }
- task->add_alias_only(); //add alias without creating dir & .usr file
- task->add_alias_only();
-
-
- // Add a hierarchical family to the first family
- if (i == 0) {
- std::string heirFamily = "heir_" + fname;
- family_ptr hierFam = fam->add_family( heirFamily );
- hierFam->addVariable( Variable("VAR1","value") );
- hierFam->addRepeat( RepeatString("aString",stringList));
-
- task_ptr task1 = hierFam->add_task( tname );
- task1->addVariable( Variable("VAR1","value") );
- task1->addEvent( Event(i) );
- task1->addEvent( Event(i+1, eventName ) );
- task1->addMeter( Meter("myMeter",0,100,100) );
- task1->addAutoCancel( ecf::AutoCancelAttr( ecf::TimeSlot(0,1), false));
- }
- }
- return suite;
- }
-};
-#endif
diff --git a/ecflow_4_0_7/ANode/test/TestAdd.cpp b/ecflow_4_0_7/ANode/test/TestAdd.cpp
deleted file mode 100644
index 951c77c..0000000
--- a/ecflow_4_0_7/ANode/test/TestAdd.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-
-#include <boost/test/unit_test.hpp>
-#include <iostream>
-#include <stdlib.h>
-
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_add )
-{
- cout << "ANode:: ...test_add\n";
-
- defs_ptr defs = Defs::create();
- task_ptr t1 = Task::create("t1");
- family_ptr f1 = Family::create("f1");
- suite_ptr s1 = Suite::create("s1");
-
- defs->addSuite(s1);
- s1->addFamily(f1);
- f1->addTask(t1);
-
- defs_ptr defs2 = Defs::create();
- suite_ptr s2 = Suite::create("s2");
- family_ptr f2 = Family::create("f2");
-
- // This should all fail since, they are already owned.
- // Otherwise we end up with two different container owning the same object
- BOOST_CHECK_THROW( s2->addFamily(f1),std::runtime_error);
- BOOST_CHECK_THROW( f2->addTask(t1),std::runtime_error);
- BOOST_CHECK_THROW( defs2->addSuite(s1),std::runtime_error);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ANode/test/TestAlias.cpp b/ecflow_4_0_7/ANode/test/TestAlias.cpp
deleted file mode 100644
index 76a8314..0000000
--- a/ecflow_4_0_7/ANode/test/TestAlias.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <iostream>
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "Alias.hpp"
-#include "Str.hpp"
-#include "File.hpp"
-
-namespace fs = boost::filesystem;
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_alias_create )
-{
- cout << "ANode:: ...test_alias_create\n";
- std::string ecf_home = File::test_data("ANode/test/data/alias","ANode");
-
- task_ptr t ;
- Defs theDefs;
- {
- suite_ptr s = theDefs.add_suite("test_alias_create");
- family_ptr f = s->add_family("f");
- t = f->add_task("t");
- t->addMeter(Meter("meter",0,100,100));
- t->addMeter(Meter("meter1",0,100,100));
- t->addEvent(Event(1,"event1"));
- t->addEvent(Event(2,"event2"));
- t->addLabel(Label("label_name","value"));
- t->addLabel(Label("label_name1","value"));
- s->add_variable(Str::ECF_HOME(),ecf_home);
- }
-
- // Create .usr file content
- std::vector<std::string> usr_file_vec;
- usr_file_vec.push_back("#This is a .usr file.");
-
- // Create list of variables
- NameValueVec used_variables;
- used_variables.push_back( std::make_pair(std::string("a"),std::string("a_value")));
- used_variables.push_back( std::make_pair(std::string("b"),std::string("b_value")));
-
- // Finally create the alias.
- alias_ptr alias = t->add_alias(usr_file_vec,used_variables);
-
- // Test that default node state is QUEUED
- BOOST_CHECK_MESSAGE(alias->state() == NState::QUEUED,"Expected initial state of QUEUED");
-
- // Test that CHILD specific attributes event, meter, labels are copied over from the task.
- BOOST_CHECK_MESSAGE(alias->meters().size() == 2,"Expected 2 meter to be copied from task but found " << alias->meters().size());
- BOOST_CHECK_MESSAGE(alias->events().size() == 2,"Expected 2 events to be copied from task but found " << alias->events().size());
- BOOST_CHECK_MESSAGE(alias->labels().size() == 2,"Expected 2 labels to be copied from task but found " << alias->labels().size());
-
- // test that user variables passed in got added as Variables
- BOOST_CHECK_MESSAGE(alias->variables().size() == 2,"Expected 2 variables to be create from input args but found " << alias->variables().size());
-
- // Test directory creation
- fs::path dir(ecf_home + "/" + t->absNodePath());
- BOOST_CHECK_MESSAGE(fs::exists(dir),"Expected directory to be created " + dir.string());
-
- // Test alias0.usr file creation
- fs::path usr_file(ecf_home + "/" + t->absNodePath() + "/" + "alias0.usr");
- BOOST_CHECK_MESSAGE(fs::exists(usr_file),"Expected alias0.usr file to be created " + usr_file.string());
-
- // Create another alias. This should get created as alias1.usr
- alias_ptr alias1 = t->add_alias(usr_file_vec,used_variables);
- fs::path usr_file1(ecf_home + "/" + t->absNodePath() + "/" + "alias1.usr");
- BOOST_CHECK_MESSAGE(fs::exists(usr_file1),"Expected alias1.usr file to be created " + usr_file1.string());
-
- // Test Defs::get_all_aliases()
- std::vector<alias_ptr> alias_vec;
- theDefs.get_all_aliases(alias_vec);
- BOOST_CHECK_MESSAGE(alias_vec.size() == 2,"Expected 2 aliases but found " << alias_vec.size());
-
- // Check alias remove
- BOOST_FOREACH(alias_ptr al,alias_vec) { al->remove();}
- alias_vec.clear();
- theDefs.get_all_aliases(alias_vec);
- BOOST_CHECK_MESSAGE(alias_vec.empty(),"Expected no aliases but found " << alias_vec.size());
-
- // Cleanup by removing the created directory
- fs::remove_all(ecf_home);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ANode/test/TestChangeMgrSingleton.cpp b/ecflow_4_0_7/ANode/test/TestChangeMgrSingleton.cpp
deleted file mode 100644
index 396efe7..0000000
--- a/ecflow_4_0_7/ANode/test/TestChangeMgrSingleton.cpp
+++ /dev/null
@@ -1,130 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <stdlib.h>
-#include <iostream>
-#include <boost/test/unit_test.hpp>
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "ChangeMgrSingleton.hpp"
-#include "AbstractObserver.hpp"
-
-using namespace std;
-using namespace ecf;
-
-class MyObserver : public AbstractObserver {
-public:
- MyObserver(Defs* defs) : update_count_(0) { ChangeMgrSingleton::instance()->attach(defs,this); }
- MyObserver(Node* node) : update_count_(0) { ChangeMgrSingleton::instance()->attach(node,this); }
-
- virtual ~MyObserver() {/* std::cout << "~MyObserver()\n"; */ }
-
- virtual void update(const Node*, const std::vector<ecf::Aspect::Type>&){update_count_++;}
- virtual void update(const Defs*, const std::vector<ecf::Aspect::Type>&){update_count_++;}
-
- /// After this call, the node will be deleted, hence observers must *NOT* use the pointers
- virtual void update_delete(const Node* node) {
- //std::cout << "update_delete(const Node* node)\n";
- ChangeMgrSingleton::instance()->detach(const_cast<Node*>(node),this);
- }
- virtual void update_delete(const Defs* defs) {
- //std::cout << "update_delete(const Defs* node)\n";
- ChangeMgrSingleton::instance()->detach(const_cast<Defs*>(defs),this);
- }
-
- int update_count() const { return update_count_;}
-private:
- int update_count_;
-};
-
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_change_mgr_singleton )
-{
- cout << "ANode:: ...test_change_mgr_singleton\n";
- {
- defs_ptr theDefs = Defs::create();
-
- MyObserver defs_obs(theDefs.get());
- BOOST_CHECK_MESSAGE(ChangeMgrSingleton::instance()->no_of_def_observers() == 1,"Expected one observer");
-
-// MyObserver defs_obs2(theDefs.get());
-// MyObserver defs_obs3(theDefs.get());
-// BOOST_CHECK_MESSAGE(ChangeMgrSingleton::instance()->no_of_def_observers() == 3,"Expected 3 observer");
-
- ChangeMgrSingleton::instance()->notify(theDefs);
- ChangeMgrSingleton::instance()->notify(theDefs);
- ChangeMgrSingleton::instance()->notify(theDefs);
- ChangeMgrSingleton::instance()->notify(theDefs);
- ChangeMgrSingleton::instance()->notify(theDefs);
- BOOST_CHECK_MESSAGE( defs_obs.update_count() == 5,"Expected 5 update");
-// BOOST_CHECK_MESSAGE( defs_obs2.update_count() == 5,"Expected 5 update");
-// BOOST_CHECK_MESSAGE( defs_obs3.update_count() == 5,"Expected 5 update");
-
- theDefs.reset();
- BOOST_CHECK_MESSAGE(ChangeMgrSingleton::instance()->no_of_def_observers() == 0,"Expected no observer");
- }
-
- {
- // **** Note using node_ptr can extend the life of the Node, hence we use scoping ***
- Defs* theDefs = new Defs;
- std::vector<MyObserver*> obs_vec;
- {
- {
- suite_ptr suite = theDefs->add_suite( "suite1" );
- family_ptr fam = suite->add_family( "family" );
- task_ptr t1 = fam->add_task( "t1" );
- }
-
- // get all nodes and observer them.
- std::vector<node_ptr> node_vec; theDefs->get_all_nodes(node_vec);
-
- // Need to make sure life time of observer is greater than Node tree
- for(size_t i = 0; i < node_vec.size(); ++i) {
- obs_vec.push_back( new MyObserver( node_vec[i].get() ) );
- }
- BOOST_CHECK_MESSAGE(ChangeMgrSingleton::instance()->no_of_node_observers() == 3,"Expected 3 observer");
-
-// // Now add another set of observers
-// for(size_t i = 0; i < node_vec.size(); ++i) {
-// obs_vec.push_back( new MyObserver( node_vec[i].get() ) );
-// }
-// BOOST_CHECK_MESSAGE(ChangeMgrSingleton::instance()->no_of_node_observers() == 6,"Expected 6 observer");
-
- // Do some updates
- for(size_t i = 0; i < node_vec.size(); ++i) {
- ChangeMgrSingleton::instance()->notify(node_vec[i]);
- ChangeMgrSingleton::instance()->notify(node_vec[i]);
- }
- for(size_t i = 0; i < obs_vec.size(); ++i) {
- BOOST_CHECK_MESSAGE( obs_vec[i]->update_count() == 2,"Expected 2 updates");
- }
- }
-
- // make sure no node_ptr are in scope as they can *delay*
- // the destructor to the end of the scope, and hence affect this test
- delete theDefs;
- BOOST_CHECK_MESSAGE(ChangeMgrSingleton::instance()->no_of_node_observers() == 0,"Expected no observer but found " << ChangeMgrSingleton::instance()->no_of_node_observers());
-
- for(size_t i = 0; i < obs_vec.size(); ++i) { delete obs_vec[i]; }
- }
-
- // keep valgrind happy
- ChangeMgrSingleton::destroy();
-}
-
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ANode/test/TestDefStatus.cpp b/ecflow_4_0_7/ANode/test/TestDefStatus.cpp
deleted file mode 100644
index d90e8fb..0000000
--- a/ecflow_4_0_7/ANode/test/TestDefStatus.cpp
+++ /dev/null
@@ -1,154 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-
-#include <boost/test/unit_test.hpp>
-#include <iostream>
-#include <stdlib.h>
-
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_defstatus )
-{
- cout << "ANode:: ...test_defstatus\n";
-
- // Create a defs file corresponding to:
- //suite suite1
- // family f1
- // task t1
- // task t2
- // family f2
- // task t1
- // task t2
- Defs theDefs;
- suite_ptr suite = theDefs.add_suite( "suite1" );
- family_ptr f1 = suite->add_family( "f1" );
- task_ptr t1 = f1->add_task( "t1" );
- task_ptr t2 = f1->add_task( "t2" );
-
- family_ptr f2 = suite->add_family( "f2" );
- task_ptr f2_t1 = f2->add_task( "t1" );
- task_ptr f2_t2 = f2->add_task( "t2" );
-
- // Get all nodes and tasks for ease of test
- vector<Node*> nodes;
- vector<Task*> tasks;
- theDefs.getAllNodes(nodes);
- theDefs.getAllTasks(tasks);
-
- /// It should be noted that once a suite has begun, it stays begun, however for test purposes we had
- /// added ability to reset the begin state.
-
- /// Test 1: with no defstatus. All nodes should be set to NState::QUEUED
- theDefs.beginAll();
- BOOST_FOREACH(Node* n,nodes) { BOOST_CHECK_MESSAGE(n->state() == NState::QUEUED,"Expected queued but found " << NState::toString(n->state())); }
-
- theDefs.requeue();
- BOOST_FOREACH(Node* n,nodes) { BOOST_CHECK_MESSAGE(n->state() == NState::QUEUED,"Expected queued but found " << NState::toString(n->state())); }
-
-
- /// Test 2: with defstatus on suite. With complete the status should have been propagated down
- suite->addDefStatus(DState::COMPLETE);
- theDefs.reset_begin(); // for test purposes only
- theDefs.beginAll();
- BOOST_FOREACH(Node* n,nodes) {
- BOOST_CHECK_MESSAGE(n->state() == NState::COMPLETE,"Expected complete but found " << NState::toString(n->state()));
- }
-
- theDefs.requeue();
- BOOST_FOREACH(Node* n,nodes) {
- BOOST_CHECK_MESSAGE(n->state() == NState::COMPLETE,"Expected complete but found " << NState::toString(n->state()));
- }
-
- /// Test 3: defstatus of family f1 and f2. The parent node(suite) should reflect status of children
- /// Also setting defstatus complete on a family should have propagated it downwards to tasks
- suite->addDefStatus(DState::default_state()); // reset defstatus
- f1->addDefStatus(DState::COMPLETE);
- f2->addDefStatus(DState::COMPLETE);
- theDefs.reset_begin(); // for test purposes only
- theDefs.beginAll();
- BOOST_FOREACH(Node* n,nodes) {
- BOOST_CHECK_MESSAGE(n->state() == NState::COMPLETE,"Expected complete but found " << NState::toString(n->state()));
- }
-
- theDefs.requeue();
- BOOST_FOREACH(Node* n,nodes) {
- BOOST_CHECK_MESSAGE(n->state() == NState::COMPLETE,"Expected complete but found " << NState::toString(n->state()));
- }
-
-
- // Suspend is really a user interaction the real state suould be queued
- f1->addDefStatus(DState::default_state()); // reset defstatus
- f2->addDefStatus(DState::default_state()); // reset defstatus
- suite->addDefStatus(DState::SUSPENDED); // reset defstatus
- theDefs.reset_begin(); // for test purposes only
- theDefs.beginAll();
- BOOST_FOREACH(Node* n,nodes) { BOOST_CHECK_MESSAGE(n->state() == NState::QUEUED,"Expected queued but found " << NState::toString(n->state())); }
-
- theDefs.requeue();
- BOOST_FOREACH(Node* n,nodes) { BOOST_CHECK_MESSAGE(n->state() == NState::QUEUED,"Expected queued but found " << NState::toString(n->state())); }
-}
-
-BOOST_AUTO_TEST_CASE( test_ECFLOW_139 )
-{
- cout << "ANode:: ...test_ECFLOW_139\n";
-
- // Create a defs file corresponding to:
- //suite suite1
- // family f1
- // task t1; defstatus suspended
- // task t2; defstatus suspended
- // family f2
- // task t1; defstatus suspended
- // task t2; defstatus suspended
- Defs theDefs;
- suite_ptr suite = theDefs.add_suite( "suite1" );
- family_ptr f1 = suite->add_family( "f1" );
- task_ptr t1 = f1->add_task( "t1" );
- task_ptr t2 = f1->add_task( "t2" );
- t1->addDefStatus(DState::SUSPENDED);
- t2->addDefStatus(DState::SUSPENDED);
-
- family_ptr f2 = suite->add_family( "f2" );
- task_ptr f2_t1 = f2->add_task( "t1" );
- task_ptr f2_t2 = f2->add_task( "t2" );
- f2_t1->addDefStatus(DState::SUSPENDED);
- f2_t2->addDefStatus(DState::SUSPENDED);
-
- // Get all nodes and tasks for ease of test
- vector<Task*> tasks;
- theDefs.getAllTasks(tasks);
-
- /// It should be noted that once a suite has begun, it stays begun, however for test purposes we had
- /// added ability to reset the begin state.
-
- /// Test 1: Check NODE state All nodes should be set to NState::QUEUED
- theDefs.beginAll();
- BOOST_FOREACH(Task* n,tasks) { BOOST_CHECK_MESSAGE(n->state() == NState::QUEUED,"Expected queued but found " << NState::toString(n->state())); }
-
- /// Check: DSTATE
- BOOST_FOREACH(Task* n,tasks) { BOOST_CHECK_MESSAGE(n->dstate() == DState::SUSPENDED,"Expected suspended but found " << DState::toString(n->dstate())); }
-
- theDefs.requeue();
- BOOST_FOREACH(Task* n,tasks) { BOOST_CHECK_MESSAGE(n->state() == NState::QUEUED,"Expected queued but found " << NState::toString(n->state())); }
- BOOST_FOREACH(Task* n,tasks) { BOOST_CHECK_MESSAGE(n->dstate() == DState::SUSPENDED,"Expected suspended but found " << DState::toString(n->dstate())); }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ANode/test/TestDefs.cpp b/ecflow_4_0_7/ANode/test/TestDefs.cpp
deleted file mode 100644
index 9c55639..0000000
--- a/ecflow_4_0_7/ANode/test/TestDefs.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-
-#include <boost/test/unit_test.hpp>
-#include <iostream>
-#include <stdlib.h>
-
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_defs_absorb )
-{
- cout << "ANode:: ...test_defs_absorb\n";
-
- // Create a defs file corresponding to:
- //suite suite1
- // family family
- // task t1
- // endfamily
- //endsuite
- Defs theDefs;
- {
- suite_ptr suite = theDefs.add_suite( "suite1" );
- family_ptr fam = suite->add_family( "family" );
- fam->add_task( "t1" );
- }
- // Then ABSORB a new def
- //suite suite1-n
- // family family
- // task suite1_task1
- // endfamily
- //endsuite
- Defs otherDefs;
- {
- for(int i = 0; i < 14; ++i) {
- suite_ptr suite1 = otherDefs.add_suite( "suite" + boost::lexical_cast<std::string>(i) );
- family_ptr fam = suite1->add_family( "family" );
- fam->add_task("suite1_task1");
- }
- }
-
- theDefs.absorb(&otherDefs, true);
- BOOST_CHECK_MESSAGE(otherDefs.suiteVec().empty(),"absorb failed");
-}
-
-BOOST_AUTO_TEST_CASE( test_defs_absorb_server_user_variables )
-{
- cout << "ANode:: ...test_defs_absorb_server_user_variables\n";
-
- Defs theDefs;
- Defs otherDefs;
- {
- otherDefs.set_server().add_or_update_user_variables("VAR1","VAL");
- otherDefs.set_server().add_or_update_user_variables("VAR2","VAL");
- otherDefs.set_server().add_or_update_user_variables("VAR3","VAL");
- otherDefs.add_suite("suite");
- }
-
- BOOST_CHECK_MESSAGE(theDefs.server().user_variables().empty(),"Expected no server user variables");
-
- theDefs.absorb(&otherDefs, true);
-
- BOOST_CHECK_MESSAGE(otherDefs.suiteVec().empty(),"absorb failed");
- BOOST_CHECK_MESSAGE(theDefs.suiteVec().size() == 1,"absorb failed");
- BOOST_CHECK_MESSAGE(theDefs.server().user_variables().size() == 3,"Expected 3 server user variables");
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ANode/test/TestEcfFile.cpp b/ecflow_4_0_7/ANode/test/TestEcfFile.cpp
deleted file mode 100644
index 309ddc5..0000000
--- a/ecflow_4_0_7/ANode/test/TestEcfFile.cpp
+++ /dev/null
@@ -1,857 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <iostream>
-#include <fstream>
-#include <stdlib.h>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/test/unit_test.hpp>
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "EcfFile.hpp"
-#include "JobsParam.hpp"
-#include "Jobs.hpp"
-#include "System.hpp"
-#include "File.hpp"
-#include "Str.hpp"
-#include "Ecf.hpp"
-#include "PrintStyle.hpp"
-
-using namespace std;
-using namespace ecf;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_ecf_file_with_bad_ECF_MICRO )
-{
- cout << "ANode:: ...test_ecf_file_with_bad_ECF_MICRO\n";
-
- // Create the defs file corresponding to the text below
- //suite suite
- // task t1
- // ECF_MICRO "" # can not be empty if overridden
- // task t2
- // ECF_MICRO "ss" # must be a single char
- //endsuite
-
- task_ptr task_t1;
- task_ptr task_t2;
- Defs theDefs; {
- suite_ptr suite = theDefs.add_suite("suite");
- task_t1 = suite->add_task( "t1" ); task_t1->add_variable("ECF_MICRO","");
- task_t2 = suite->add_task( "t2" ); task_t2->add_variable("ECF_MICRO","ss");
- }
-
- // Check we throw for bad ECF_MICRO chars
- std::string ecf_file_location;
- BOOST_REQUIRE_THROW(EcfFile ecfFile(task_t1.get(),ecf_file_location),std::runtime_error);
- BOOST_REQUIRE_THROW(EcfFile ecfFile(task_t2.get(),ecf_file_location),std::runtime_error);
-}
-
-BOOST_AUTO_TEST_CASE( test_ecf_simple_include_file )
-{
- // The specific files are specified in ECF_INCLUDE and common files
- // are specified in ECF_HOME. This test will ensure that if the file common.h
- // is not found in ECF_INCLUDE we then look at ECF_HOME
- cout << "ANode:: ...test_ecf_simple_include_file";
-
- // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode.
- if (getenv("ECFLOW_CRAY_BATCH")) {
- cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n";
- return;
- }
- cout << "\n";
-
- // Create the defs file corresponding to the text below
- //suite suite
- // edit ECF_INCLUDE $ECF_HOME/includes
- // task t1
- //endsuite
-
- // Create a defs file, where the task name mirrors the ecf files in the given directory
- task_ptr task_t1 = Task::create( "t1" );
- suite_ptr suite = Suite::create( "suite" );
- Defs theDefs; {
- suite->addVariable( Variable( Str::ECF_INCLUDE(), "$ECF_HOME/includes" ) );
- suite->addTask( task_t1 );
- theDefs.addSuite( suite );
- }
-
- // Override ECF_HOME. ECF_HOME is as default location for .ecf files, when ECF_INCLUDE not specified
- // or when file does not exist in ECF_INCLUDE
- std::string ecf_home = File::test_data("ANode/test/data","ANode");
- theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(),ecf_home);
-
- /// begin , will cause creation of generated variables. The generated variables
- /// are use in client scripts and used to locate the sms files
- theDefs.beginAll();
-
- // generate the ecf file;
- string header = "%include <simple_head.h>\n";
- string body = "#body\n";
- string tail = "%include <simple_tail.h>\n";
- string ecf_file = header;
- ecf_file += body;
- ecf_file += tail;
-
- string ecf_file_location = ecf_home + task_t1->absNodePath() + File::ECF_EXTN();
- // cout << "file_location = " << ecf_file_location << "\n";
- BOOST_CHECK_MESSAGE(File::createMissingDirectories(ecf_file_location),"Could not create missing dir\n");
-
- string errormsg;
- BOOST_CHECK_MESSAGE(File::create(ecf_file_location, ecf_file, errormsg), errormsg);
- BOOST_CHECK_MESSAGE(fs::exists(ecf_file_location), "Expected File " << ecf_file_location << " to exist");
-
- // Create the generated variables
- task_t1->update_generated_variables();
-
- /// Now finally the test
- EcfFile ecfFile(task_t1.get(),ecf_file_location);
-
- /// Check generation of '.usr' and job files
- JobsParam jobsParam(true); // spawn_jobs = false
- try { ecfFile.create_job(jobsParam); }
- catch ( std::exception& e) { BOOST_CHECK_MESSAGE(false,"Expected job creation to succeed " << e.what());}
-
- string job_file_location = ecf_home + task_t1->absNodePath() + File::JOB_EXTN() + task_t1->tryNo();
- BOOST_CHECK_MESSAGE(fs::exists(job_file_location), "Expected File " << job_file_location << " to exist");
-
- // Open the job file/
- std::string job_file_contents;
- BOOST_CHECK_MESSAGE(File::open(job_file_location,job_file_contents),"Could not open job file " << job_file_location);
-
- std::string expected_job_file_contents = "#head.h\n#body\n#tail.h";
- BOOST_CHECK_MESSAGE(job_file_contents == expected_job_file_contents ,"Expected\n" <<expected_job_file_contents << "' but found \n" << job_file_contents << "'");
-
- /// Remove all the generated files
- boost::filesystem::remove_all( ecf_home + suite->absNodePath() );
-}
-
-BOOST_AUTO_TEST_CASE( test_ecf_simple_used_variables )
-{
- // Test that used variables are as expected
- // This should PRUNE the generated variables from the used variables list
- // Additionally it should NOT affect variables like ESUITE but should ignore generated variable SUITE
- // See File: ANode/test/data/includes/used_variables.h
- cout << "ANode:: ...test_ecf_simple_used_variables";
-
- // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode.
- if (getenv("ECFLOW_CRAY_BATCH")) {
- cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n";
- return;
- }
- cout << "\n";
-
-
- // Create the defs file corresponding to the text below
- //suite suite
- // edit ECF_INCLUDE $ECF_HOME/includes
- // task t1
- //endsuite
-
- // Create a defs file, where the task name mirrors the ecf files in the given directory
- task_ptr task_t1;
- suite_ptr suite;
- Defs theDefs; {
- suite = theDefs.add_suite("suite");
- suite->addVariable( Variable( Str::ECF_INCLUDE(), "$ECF_HOME/includes" ) );
- suite->add_variable("ESUITE","suite");
- task_t1 = suite->add_family("f1")->add_task( "t1" );
- }
-
- // Override ECF_HOME. ECF_HOME is as default location for .ecf files, when ECF_INCLUDE not specified
- // or when file does not exist in ECF_INCLUDE
- std::string ecf_home = File::test_data("ANode/test/data","ANode");
- theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(),ecf_home);
-
- /// begin , will cause creation of generated variables. The generated variables
- /// are use in client scripts and used to locate the sms files
- theDefs.beginAll();
-
- // generate the ecf file;
- string ecf_file = "%include <used_variables.h>\n";
- string ecf_file_location = ecf_home + task_t1->absNodePath() + File::ECF_EXTN();
- // cout << "file_location = " << ecf_file_location << "\n";
- BOOST_CHECK_MESSAGE(File::createMissingDirectories(ecf_file_location),"Could not create missing dir\n");
-
- string errormsg;
- BOOST_CHECK_MESSAGE(File::create(ecf_file_location, ecf_file, errormsg), errormsg);
- BOOST_CHECK_MESSAGE(fs::exists(ecf_file_location), "Expected File " << ecf_file_location << " to exist");
-
- // Create the generated variables
- task_t1->update_generated_variables();
-
- /// Now finally the test
- EcfFile ecfFile(task_t1.get(),ecf_file_location);
-
- string file_with_used_variables;
- ecfFile.edit_used_variables(file_with_used_variables);
- string expected_used_variables = "%comment - ecf user variables\nESUITE = suite\n%end - ecf user variables\n%include <used_variables.h>\n";
- BOOST_CHECK_MESSAGE(file_with_used_variables==expected_used_variables,"Expected\n" << expected_used_variables << "\nBut found:\n" << file_with_used_variables);
-
- /// Remove all the generated files
- boost::filesystem::remove_all( ecf_home + suite->absNodePath() );
-}
-
-BOOST_AUTO_TEST_CASE( test_ecf_simple_used_variables_with_comments )
-{
- // Test that used variables are as expected
- // This should PRUNE the generated variables from the used variables list
- // Additionally it should NOT affect variables like ETASK but should ignore generated variable TASK
- // See File: ANode/test/data/includes/used_variables_with_comments.h
- //
- // This WILL test that when we have user comment and manuals, we can still extract user variables
- // Those variable defined within comments and manuals that are not defined should be ignored
- cout << "ANode:: ...test_ecf_simple_used_variables_with_comments";
-
- // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode.
- if (getenv("ECFLOW_CRAY_BATCH")) {
- cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n";
- return;
- }
- cout << "\n";
-
- // SET ECF_HOME
- std::string ecf_home = File::test_data("ANode/test/data","ANode");
-
- // Create the defs file corresponding to the text below
- //suite suite
- // edit ECF_INCLUDE $ECF_HOME/includes
- // task t1
- //endsuite
-
- // Create a defs file, where the task name mirrors the ecf files in the given directory
- task_ptr task_t1;
- suite_ptr suite;
- Defs theDefs; {
- suite = theDefs.add_suite("suite");
- suite->addVariable( Variable( Str::ECF_INCLUDE(), "$ECF_HOME/includes" ) );
- suite->add_variable("ETASK","suite");
- suite->add_variable("FRED","fred");
- task_t1 = suite->add_family("f1")->add_task( "t1" );
- }
-
- // Override ECF_HOME. ECF_HOME is as default location for .ecf files, when ECF_INCLUDE not specified
- // or when file does not exist in ECF_INCLUDE
- theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(),ecf_home);
-
- /// begin , will cause creation of generated variables. The generated variables
- /// are use in client scripts and used to locate the sms files
- theDefs.beginAll();
-
- // generate the ecf file;
- string ecf_file = "%include <used_variables_with_comments.h>\n";
- string ecf_file_location = ecf_home + task_t1->absNodePath() + File::ECF_EXTN();
- // cout << "file_location = " << ecf_file_location << "\n";
- BOOST_CHECK_MESSAGE(File::createMissingDirectories(ecf_file_location),"Could not create missing dir\n");
-
- string errormsg;
- BOOST_CHECK_MESSAGE(File::create(ecf_file_location, ecf_file, errormsg), errormsg);
- BOOST_CHECK_MESSAGE(fs::exists(ecf_file_location), "Expected File " << ecf_file_location << " to exist");
-
- // Create the generated variables
- task_t1->update_generated_variables();
-
- /// Now finally the test
- EcfFile ecfFile(task_t1.get(),ecf_file_location);
-
- string file_with_used_variables;
- ecfFile.edit_used_variables(file_with_used_variables);
- string expected_used_variables = "%comment - ecf user variables\nETASK = suite\nFRED = fred\n%end - ecf user variables\n%include <used_variables_with_comments.h>\n";
- BOOST_CHECK_MESSAGE(file_with_used_variables==expected_used_variables,"Expected\n" << expected_used_variables << "\nBut found:\n" << file_with_used_variables);
-
- /// Remove all the generated files
- boost::filesystem::remove_all( ecf_home + suite->absNodePath() );
-}
-
-
-BOOST_AUTO_TEST_CASE( test_ecf_simple_used_variables_errors )
-{
- // Test that used variables are as expected
- // This is similar to test_ecf_simple_used_variables_with_comments
- // BUT we DO NOT define variable FRED, hence we expect failure
- cout << "ANode:: ...test_ecf_simple_used_variables_errors";
-
- // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode.
- if (getenv("ECFLOW_CRAY_BATCH")) {
- cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n";
- return;
- }
- cout << "\n";
-
-
- // SET ECF_HOME
- std::string ecf_home = File::test_data("ANode/test/data","ANode");
-
- // Create the defs file corresponding to the text below
- //suite suite
- // edit ECF_INCLUDE $ECF_HOME/includes
- // task t1
- //endsuite
-
- // Create a defs file, where the task name mirrors the ecf files in the given directory
- task_ptr task_t1;
- suite_ptr suite;
- Defs theDefs; {
- suite = theDefs.add_suite("suite");
- suite->addVariable( Variable( Str::ECF_INCLUDE(), "$ECF_HOME/includes" ) );
- suite->add_variable("ETASK","suite");
- task_t1 = suite->add_family("f1")->add_task( "t1" );
- }
-
- // Override ECF_HOME. ECF_HOME is as default location for .ecf files, when ECF_INCLUDE not specified
- // or when file does not exist in ECF_INCLUDE
- theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(),ecf_home);
-
- /// begin , will cause creation of generated variables. The generated variables
- /// are use in client scripts and used to locate the sms files
- theDefs.beginAll();
-
- // generate the ecf file;
- string ecf_file = "%include <used_variables_with_comments.h>\n";
- string ecf_file_location = ecf_home + task_t1->absNodePath() + File::ECF_EXTN();
- // cout << "file_location = " << ecf_file_location << "\n";
- BOOST_CHECK_MESSAGE(File::createMissingDirectories(ecf_file_location),"Could not create missing dir\n");
-
- string errormsg;
- BOOST_CHECK_MESSAGE(File::create(ecf_file_location, ecf_file, errormsg), errormsg);
- BOOST_CHECK_MESSAGE(fs::exists(ecf_file_location), "Expected File " << ecf_file_location << " to exist");
-
- // Create the generated variables
- task_t1->update_generated_variables();
-
- /// Now finally the test
- EcfFile ecfFile(task_t1.get(),ecf_file_location);
-
- // Expect a throw since %FRED% is not defined, on the suite, but exists in used_variables_with_comments.h
- string file_with_used_variables;
- BOOST_REQUIRE_THROW(ecfFile.edit_used_variables(file_with_used_variables),std::runtime_error);
-
- /// Remove all the generated files
- boost::filesystem::remove_all( ecf_home + suite->absNodePath() );
-}
-
-BOOST_AUTO_TEST_CASE( test_ecf_include_file )
-{
- // The specific files are specified in ECF_INCLUDE and common files
- // are specified in ECF_HOME. This test will ensure that if the file common.h
- // is not found in ECF_INCLUDE we then look at ECF_HOME
- cout << "ANode:: ...test_ecf_include_file";
-
- // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode.
- if (getenv("ECFLOW_CRAY_BATCH")) {
- cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n";
- return;
- }
- cout << "\n";
-
- // SET ECF_HOME
- std::string ecf_home = File::test_data("ANode/test/data","ANode");
-
- // Create the defs file corresponding to the text below
- //suite suite
- // edit SLEEPTIME 10
- // edit ECF_INCLUDE $ECF_HOME/includes
- // task t1
- //endsuite
-
- // Create a defs file, where the task name mirrors the ecf files in the given directory
- task_ptr task_t1 = Task::create( "t1" );
- suite_ptr suite = Suite::create( "suite" );
- Defs theDefs; {
- suite->addVariable( Variable( Str::ECF_INCLUDE(), "$ECF_HOME/includes" ) );
- suite->addVariable( Variable( "SLEEPTIME", "1" ) );
- suite->addVariable( Variable( "ECF_CLIENT_EXE_PATH", "a/made/up/path" ) );
- suite->addTask( task_t1 );
- theDefs.addSuite( suite );
- }
-
- // Override ECF_HOME. ECF_HOME is as default location for .ecf files, when ECF_INCLUDE not specified
- // or when file does not exist in ECF_INCLUDE
- theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(),ecf_home);
-
- /// begin , will cause creation of generated variables. The generated variables
- /// are use in client scripts and used to locate the sms files
- theDefs.beginAll();
-
- // generate the ecf file;
- string header = "%include <head.h>\n\n";
- string body = "%include <common.h>\n\n";
- string tail = "%include <tail.h>\n# ===================================";
- string ecf_file = header;
- ecf_file += body;
- ecf_file += tail;
-
- string ecf_file_location = ecf_home + task_t1->absNodePath() + File::ECF_EXTN();
- // cout << "file_location = " << ecf_file_location << "\n";
- BOOST_CHECK_MESSAGE(File::createMissingDirectories(ecf_file_location),"Could not create missing dir\n");
-
- string errormsg;
- BOOST_CHECK_MESSAGE(File::create(ecf_file_location, ecf_file, errormsg), errormsg);
- BOOST_CHECK_MESSAGE(fs::exists(ecf_file_location), "Expected File " << ecf_file_location << " to exist");
-
- // Create the generated variables
- task_t1->update_generated_variables();
-
- /// Now finally the test
- EcfFile ecfFile(task_t1.get(),ecf_file_location);
-
- /// Check generation of '.usr' and job files
- string job_file_location = ecf_home + task_t1->absNodePath() + File::JOB_EXTN() + task_t1->tryNo();
- JobsParam jobsParam(true); // spawn_jobs = false
- try { ecfFile.create_job(jobsParam); }
- catch ( std::exception& e) { BOOST_CHECK_MESSAGE(false,"Expected job creation to succeed " << e.what());}
- BOOST_CHECK_MESSAGE(fs::exists(job_file_location), "Expected File " << job_file_location << " to exist");
-
- // Open the job file/
- std::string job_file_contents;
- BOOST_CHECK_MESSAGE(File::open(job_file_location,job_file_contents),"Could not open job file " << job_file_location);
-
- /// Remove all the generated files
- boost::filesystem::remove_all( ecf_home + suite->absNodePath() );
-}
-
-
-BOOST_AUTO_TEST_CASE( test_ecf_file )
-{
- cout << "ANode:: ...test_ecf_file";
-
- // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode.
- if (getenv("ECFLOW_CRAY_BATCH")) {
- cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n";
- return;
- }
- cout << "\n";
-
- // SET ECF_HOME
- std::string ecf_home = File::test_data("ANode/test/data","ANode");
-
- // Create the defs file corresponding to the text below
- //# Test the sms file can be found via ECF_SCRIPT
- //# Note: we have to use relative paths, since these tests are relocatable
- //#
- //suite suite
- // edit SLEEPTIME 10
- // edit ECF_INCLUDE $ECF_HOME/includes
- // task t1
- //endsuite
-
- NameValueMap expected_used_variables;
- expected_used_variables.insert( std::make_pair(string("VAR1"),string("_val1_")) );
- expected_used_variables.insert( std::make_pair(string("VAR2"),string("_val2_")) );
- expected_used_variables.insert( std::make_pair(string("VAR2_fred"),string("<ignored>")) );
-
- // Create a defs file, where the task name mirrors the sms files in the given directory
- task_ptr task_t1 = Task::create( "t1" );
- suite_ptr suite = Suite::create( "suite" );
- std::pair<std::string,std::string> p;
- Defs theDefs; {
- suite->addVariable( Variable( Str::ECF_INCLUDE(), "$ECF_HOME/includes" ) );
- suite->addVariable( Variable( "SLEEPTIME", "1" ) );
- suite->addVariable( Variable( "ECF_CLIENT_EXE_PATH", "a/made/up/path" ) );
- BOOST_FOREACH(p,expected_used_variables) { task_t1->addVariable( Variable( p.first, p.second) );}
- suite->addTask( task_t1 );
- theDefs.addSuite( suite );
- }
-
-
- // Override ECF_HOME. ECF_HOME is need to locate to the .ecf files
- theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(),ecf_home);
-
- /// begin , will cause creation of generated variables. The generated variables
- /// are use in client scripts and used to locate the sms files
- theDefs.beginAll();
-
- // generate the ecf file;
- string header = "%include <head.h>\n\n";
- string manual_head = "%manual\n";
- string manual_body = " manual. The contents of the manual\n";
- manual_body += " end.\n";
- string manual_tail = "%end\n\n";
- string comment_head = "%comment\n";
- string comment_body = " comment. The contents of the comment\n";
- comment_body += " end.\n";
- string comment_tail ="%end\n\n";
- string ecf_body; {
- std::pair<std::string,std::string> p;
- BOOST_FOREACH(p,expected_used_variables) { ecf_body += Ecf::MICRO() + p.first + Ecf::MICRO() + "\n";}
- ecf_body +="%VAR3:substitute_var%\n";
- }
- string tail = "\n%include <tail.h>\n# ===================================";
-
- string ecf_file = header;
- ecf_file += manual_head;
- ecf_file += manual_body;
- ecf_file += manual_tail;
- ecf_file += comment_head;
- ecf_file += comment_body;
- ecf_file += comment_tail;
- ecf_file += ecf_body;
- ecf_file += tail;
-
- string ecf_file_location = ecf_home + task_t1->absNodePath() + File::ECF_EXTN();
- // cout << "file_location = " << ecf_file_location << "\n";
- BOOST_CHECK_MESSAGE(File::createMissingDirectories(ecf_file_location),"Could not create missing dir\n");
-
- string errormsg;
- BOOST_CHECK_MESSAGE(File::create(ecf_file_location, ecf_file, errormsg), errormsg);
- BOOST_CHECK_MESSAGE(fs::exists(ecf_file_location), "Expected File " << ecf_file_location << " to exist");
-
- // Create the generated variables
- task_t1->update_generated_variables();
-
- /// Now finally the test
- EcfFile ecfFile(task_t1.get(),ecf_file_location);
-
- /// Test manual extraction
- /// The manual is manual of all the pre-processed includes
- /// Test: SUP-762 Lines starting with "manually" are not shown in manual
- std::string expected_manual = "#This is the manual from the head.h file\n manual. The contents of the manual\n end.\n#This is the manual from the tail.h file\n";
-
- string theExtractedManual;
- try { ecfFile.manual(theExtractedManual); }
- catch (std::exception &e) { BOOST_CHECK_MESSAGE(false,e.what()); }
- BOOST_CHECK_MESSAGE( theExtractedManual == expected_manual, "Expected \n'" << expected_manual << "' but found \n'" << theExtractedManual << "'");
-
-
- /// Test script extraction
- string theExtractedScript;
- try { ecfFile.script(theExtractedScript); }
- catch (std::exception &e) { BOOST_CHECK_MESSAGE(false,e.what()); }
- BOOST_CHECK_MESSAGE( theExtractedScript == ecf_file, "\nExpected\n" << ecf_file
- << "\nsize = " << ecf_file.size() << " but found-----------------\n"
- << theExtractedScript << "\nsize = " << theExtractedScript.size() );
-
-
- /// Test User edit script, this should return all the used variables, between %comment -%end
- string file_with_used_variables;
- ecfFile.edit_used_variables(file_with_used_variables);
- // std::cout << "file_with_used_variables:----------------------------------------------------------------\n" << file_with_used_variables << "\n";
- BOOST_CHECK_MESSAGE(file_with_used_variables.find("%comment") == 0, "Expected to find variable %comment on the very first line: but found at: " << file_with_used_variables.find("%comment"));
- BOOST_FOREACH(p,expected_used_variables) {
- BOOST_CHECK_MESSAGE(file_with_used_variables.find(p.first) != string::npos, "Expected to find variable" << p.first);
- }
-
- /// Test extraction of all the used variables
- std::vector<string> script_lines;
- Str::split(file_with_used_variables,script_lines,"\n"); // will ignore empty lines, but will do for this case
- NameValueMap extracted_used_variables;
- EcfFile::extract_used_variables( extracted_used_variables, script_lines );
- BOOST_FOREACH(p,expected_used_variables) {
- BOOST_CHECK_MESSAGE( extracted_used_variables.find(p.first) != extracted_used_variables.end()," expected to find variable " << p.first << " in the extracted variables\n");
- }
- // cout << "Expected:----\n"; BOOST_FOREACH(p,expected_used_variables) { cout << p.first << " " << p.second << "\n";}
- // cout << "Actual:------\n"; BOOST_FOREACH(p,extracted_used_variables) { cout << p.first << " " << p.second << "\n";}
-
-
- /// Test pre-processing
- string pre_processed_file;
- ecfFile.pre_process(pre_processed_file);
- // cout << "pre_processed_file\n" << pre_processed_file << "\n";
- BOOST_CHECK_MESSAGE(!pre_processed_file.empty(),"Expected file not to be empty");
- BOOST_CHECK_MESSAGE(pre_processed_file.find("%include") == string::npos,"Expected all includes to be removed");
-
- /// Check generation of '.usr' and job files
- string man_file_location = ecf_home + task_t1->absNodePath() + File::MAN_EXTN();
- string usr_file_location = ecf_home + task_t1->absNodePath() + File::USR_EXTN();
- string job_file_location = ecf_home + task_t1->absNodePath() + File::JOB_EXTN() + task_t1->tryNo();
- JobsParam jobsParam(true); // spawn_jobs = false
- jobsParam.set_user_edit_variables( extracted_used_variables );
- jobsParam.set_user_edit_file( script_lines );
- try { ecfFile.create_job(jobsParam); }
- catch ( std::exception& e) { BOOST_CHECK_MESSAGE(false,"Expected job creation to succeed " << e.what());}
- BOOST_CHECK_MESSAGE(fs::exists(usr_file_location), "Expected File " << usr_file_location << " to exist");
- BOOST_CHECK_MESSAGE(fs::exists(job_file_location), "Expected File " << job_file_location << " to exist");
-
- // Open the job file/
- std::string job_file_contents;
- BOOST_CHECK_MESSAGE(File::open(job_file_location,job_file_contents),"Could not open job file " << job_file_location);
-
- // Test the contents of the job file.
-// cout << "\n" << job_file_contents << "\n";
- BOOST_CHECK_MESSAGE(job_file_contents.find("%ECF_PORT%") == string::npos,"Expected variables to be substituted:");
- BOOST_CHECK_MESSAGE(job_file_contents.find("%ECF_NODE%") == string::npos,"Expected variables to be substituted:");
- BOOST_CHECK_MESSAGE(job_file_contents.find("%ECF_NAME%") == string::npos,"Expected variables to be substituted:");
- BOOST_CHECK_MESSAGE(job_file_contents.find("%ECF_PASS%") == string::npos,"Expected variables to be substituted");
- BOOST_CHECK_MESSAGE(job_file_contents.find("%ECF_TRYNO%") == string::npos,"Expected variables to be substituted");
- BOOST_CHECK_MESSAGE(job_file_contents.find("%include") == string::npos,"Expected all includes to be expanded");
- BOOST_CHECK_MESSAGE(job_file_contents.find("%manual") == string::npos,"%manual should have been removed");
- BOOST_CHECK_MESSAGE(job_file_contents.find("%comment") == string::npos,"%comment should have been removed:");
- BOOST_CHECK_MESSAGE(job_file_contents.find("%end") == string::npos,"%end should have been removed:");
- BOOST_CHECK_MESSAGE(job_file_contents.find("%ecfmicro") == string::npos,"%ecfmicro should have been removed:");
-
-
- /// Remove all the generated files
- boost::filesystem::remove( man_file_location );
- boost::filesystem::remove( ecf_file_location );
- boost::filesystem::remove( usr_file_location );
- boost::filesystem::remove( job_file_location );
- boost::filesystem::remove( ecf_home + suite->absNodePath() );
-}
-
-
-BOOST_AUTO_TEST_CASE( test_ecf_file_includenoop )
-{
- cout << "ANode:: ...test_ecf_file_includenopp";
-
- // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode.
- if (getenv("ECFLOW_CRAY_BATCH")) {
- cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n";
- return;
- }
- cout << "\n";
-
-
- // This test is used to check that %includenopp are expanded only.
- // There should be NO variable substitution, or removal of comments/manual
-
- // SET ECF_HOME
- std::string ecf_home = File::test_data("ANode/test/data","ANode");
-
- // Create a defs file, where the task name mirrors the ecf files in the given directory
- task_ptr task_t1 = Task::create( "t1" );
- suite_ptr suite = Suite::create( "suite_test_ecf_file_includenopp" );
- std::pair<std::string,std::string> p;
- Defs theDefs; {
- suite->addVariable( Variable( Str::ECF_INCLUDE(), "$ECF_HOME/includes" ) );
- suite->addVariable( Variable( "SLEEPTIME", "1" ) );
- suite->addVariable( Variable( "ECF_CLIENT_EXE_PATH", "a/made/up/path" ) );
- suite->addTask( task_t1 );
- theDefs.addSuite( suite );
- }
- //cout << theDefs << "\n";
-
- // Override ECF_HOME. ECF_HOME is need to locate to the .ecf files
- theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(),ecf_home);
-
- /// begin , will cause creation of generated variables. The generated variables
- /// are use in client scripts and used to locate the ecf files
- theDefs.beginAll();
-
- // generate the ecf file;
- string header = "%includenopp <head.h>\n";
- string tail = "%includenopp <tail.h>";
- string ecf_file = header;
- ecf_file += tail;
-
- string ecf_file_location = ecf_home + task_t1->absNodePath() + File::ECF_EXTN();
- BOOST_CHECK_MESSAGE(File::createMissingDirectories(ecf_file_location),"Could not create missing dir " << ecf_file_location << "\n");
-
- string errormsg;
- BOOST_CHECK_MESSAGE(File::create(ecf_file_location, ecf_file, errormsg), errormsg);
- BOOST_CHECK_MESSAGE(fs::exists(ecf_file_location), "Expected File " << ecf_file_location << " to exist");
-
- // Create the generated variables. Then EcfFile
- task_t1->update_generated_variables();
- EcfFile ecfFile(task_t1.get(),ecf_file_location);
-
- /// Check generation of job files
- string man_file_location = ecf_home + task_t1->absNodePath() + File::MAN_EXTN();
- string job_file_location = ecf_home + task_t1->absNodePath() + File::JOB_EXTN() + task_t1->tryNo();
- JobsParam jobsParam(true); // spawn_jobs = false
- try { ecfFile.create_job(jobsParam); }
- catch ( std::exception& e) { BOOST_CHECK_MESSAGE(false,"Expected job creation to succeed " << e.what());}
-
- // Open the job file and check the contents
- BOOST_CHECK_MESSAGE(fs::exists(job_file_location), "Expected job File " << job_file_location << " to exist");
- std::string job_file_contents;
- BOOST_CHECK_MESSAGE(File::open(job_file_location,job_file_contents),"Could not open job file " << job_file_location);
-
- // Test the contents of the job file. We expect includenopp to be expanded
- // The contents should be left as is: i.e no pre_processing,hence expect to find %manual %comment, %VARIABLES%
- //cout << "\n" << job_file_contents << "\n";
- BOOST_CHECK_MESSAGE(job_file_contents.find("%includenopp") == string::npos,"Expected all includes to be removed");
- BOOST_CHECK_MESSAGE(job_file_contents.find("%ECF_PORT%") != string::npos,"Expected variables as is:");
- BOOST_CHECK_MESSAGE(job_file_contents.find("%ECF_NODE%") != string::npos,"Expected variables as is:");
- BOOST_CHECK_MESSAGE(job_file_contents.find("%ECF_NAME%") != string::npos,"Expected variables as is:");
- BOOST_CHECK_MESSAGE(job_file_contents.find("%ECF_PASS%") != string::npos,"Expected variables as is:");
- BOOST_CHECK_MESSAGE(job_file_contents.find("%ECF_TRYNO%") != string::npos,"Expected variables as is:");
- BOOST_CHECK_MESSAGE(job_file_contents.find("%manual") != string::npos,"%manual should exist inside %nopp/%end pair:");
- BOOST_CHECK_MESSAGE(job_file_contents.find("%comment") != string::npos,"%comment should exist inside %nopp/%end pair:");
- BOOST_CHECK_MESSAGE(job_file_contents.find("%end") != string::npos,"%end associated with comment and manual should exist:");
-
-
- // Remove all the generated files
- boost::filesystem::remove( ecf_file_location );
- boost::filesystem::remove( man_file_location );
- boost::filesystem::remove( job_file_location );
- boost::filesystem::remove( ecf_home + suite->absNodePath() );
-}
-
-
-BOOST_AUTO_TEST_CASE( test_ecf_file_override_ECF_JOB )
-{
- cout << "ANode:: ...test_ecf_file_override_ECF_JOB";
-
- // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode.
- if (getenv("ECFLOW_CRAY_BATCH")) {
- cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n";
- return;
- }
- cout << "\n";
-
- // This test is used to check that when user has added a variable ECF_JOB
- // to specify the location of the job file, we use that, in preference
- // to generated ECF_JOB for the location of the job file.
- // Note: The directories to the job file should be created by EcfFile
-
- // SET ECF_HOME
- std::string ecf_home = File::test_data("ANode/test/data","ANode");
- std::string job_file_location = ecf_home + "/a/made/up/path/t1.job";
-
- // Create a defs file, where the task name mirrors the ecf files in the given directory
- task_ptr task_t1 = Task::create( "t1" );
- task_t1->addVariable( Variable( "ECF_JOB", job_file_location ) );
- suite_ptr suite = Suite::create( "test_ecf_file_override_ECF_JOB" );
- std::pair<std::string,std::string> p;
- Defs theDefs; {
- suite->addVariable( Variable( Str::ECF_INCLUDE(), "$ECF_HOME/includes" ) );
- suite->addVariable( Variable( "SLEEPTIME", "1" ) );
- suite->addVariable( Variable( "ECF_CLIENT_EXE_PATH", "a/made/up/path" ) );
- suite->addTask( task_t1 );
- theDefs.addSuite( suite );
- }
- //cout << theDefs << "\n";
-
- // Override ECF_HOME. ECF_HOME is need to locate to the .ecf files
- theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(),ecf_home);
-
- /// begin , will cause creation of generated variables. The generated variables
- /// are use in client scripts and used to locate the ecf files
- theDefs.beginAll();
-
- // generate the dummy ecf file;
- string header = "%include <head.h>\n";
- string tail = "%include <tail.h>";
- string ecf_file = header;
- ecf_file += "# ";
- ecf_file += tail;
-
- string ecf_file_location = ecf_home + task_t1->absNodePath() + File::ECF_EXTN();
- BOOST_CHECK_MESSAGE(File::createMissingDirectories(ecf_file_location),"Could not create missing dir " << ecf_file_location << "\n");
-
- string errormsg;
- BOOST_CHECK_MESSAGE(File::create(ecf_file_location, ecf_file, errormsg), errormsg);
- BOOST_CHECK_MESSAGE(fs::exists(ecf_file_location), "Expected File " << ecf_file_location << " to exist");
-
- // Create the generated variables. Then EcfFile
- task_t1->update_generated_variables();
- EcfFile ecfFile(task_t1.get(),ecf_file_location);
-
- /// Check generation of job files
- JobsParam jobsParam(true); // spawn_jobs = false
- try { ecfFile.create_job(jobsParam); }
- catch ( std::exception& e) { BOOST_CHECK_MESSAGE(false,"Expected job creation to succeed " << e.what());}
-
- // Open the job file and check the contents
- BOOST_CHECK_MESSAGE(fs::exists(job_file_location), "Expected job File " << job_file_location << " to exist");
- std::string job_file_contents;
- BOOST_CHECK_MESSAGE(File::open(job_file_location,job_file_contents),"Could not open job file " << job_file_location);
- BOOST_CHECK_MESSAGE( !job_file_contents.empty(),"Job should not be empty");
-
- // Remove all the generated files
- boost::filesystem::remove_all( ecf_home + suite->absNodePath() );
- boost::filesystem::remove_all( ecf_home + "/a" );
-
- /// Destroy System singleton to avoid valgrind from complaining
- System::destroy();
-}
-
-BOOST_AUTO_TEST_CASE( test_manual_files )
-{
- // The specific files are specified in ECF_INCLUDE and common files are specified in ECF_HOME.
- cout << "ANode:: ...test_manual_files\n";
-
- // SET ECF_HOME
- std::string ecf_home = File::test_data("ANode/test/data/SMSHOME","ANode");
-
-
- // Create the defs file corresponding to the text below
- //suite suite
- // edit SLEEPTIME 10
- // edit ECF_INCLUDE $ECF_HOME/includes
- // family
- // task t1
- //endsuite
-
- // Create a defs file, where the task name mirrors the ecf files in the given directory
- Defs theDefs;
- suite_ptr suite = theDefs.add_suite( "suite" );
- suite->addVariable( Variable( Str::ECF_INCLUDE(), "$ECF_HOME/../includes" ) );
- family_ptr family = suite->add_family("family");
- task_ptr task_t1 = family->add_task("t1");
-
-
- // Override ECF_HOME. ECF_HOME is as default location for .ecf files, when ECF_INCLUDE not specified
- // or when file does not exist in ECF_INCLUDE
- theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(),ecf_home);
-
- /// begin , will cause creation of generated variables. The generated variables
- /// are use in client scripts and used to locate the sms files
- theDefs.beginAll();
-
- // Create the generated variables
- task_t1->update_generated_variables();
-
-// PrintStyle style(PrintStyle::STATE);
-// std::cout << theDefs << "\n";
-
- /// Now finally the test
-
- // Task
- {
- std::string manual;
- EcfFile ecf_file = task_t1->locatedEcfFile(); // will throw std::runtime_error for errors
- ecf_file.manual(manual); // will throw std::runtime_error for errors
- BOOST_REQUIRE_MESSAGE(!manual.empty(),"Manual not found");
- BOOST_CHECK_MESSAGE(manual.find("ECF_MICRO=%") != std::string::npos,"Variable pre-processing failed during manual extraction");
- BOOST_CHECK_MESSAGE(manual.find("manual-1") != std::string::npos,"Pre-processing of ecfmicro in manuals failed, expected to find string 'manual-1'\n" << manual);
- BOOST_CHECK_MESSAGE(manual.find("end-1") != std::string::npos,"Pre-processing of ecfmicro in manuals failed, expected to find string 'end-1'\n" << manual);
- BOOST_CHECK_MESSAGE(manual.find("Test manual files are pre-processed") != std::string::npos,"%include <manual.h> pre-processing failed inside manual->end\n" << manual);
- }
-
- {
- // Family, Check the suite manuals are pre-processed. i.e %includes are expanded
- // When the node container manual(family or suite) '.man' file, has content but *NO* %manual->%end directives
- // Just pre-process and return file as is. Since the whole file is a manual.
- std::string man_file = ecf_home + family->absNodePath() + File::MAN_EXTN();
- EcfFile ecf_file(family.get(), man_file);
-
- std::string manual;
- ecf_file.manual(manual);
- //cout << manual << "\n";
- BOOST_CHECK_MESSAGE(!manual.empty(),"Manual not found");
- BOOST_CHECK_MESSAGE(manual.find("Test manual files are pre-processed") != std::string::npos,"Pre-processing in manual failed");
- BOOST_CHECK_MESSAGE(manual.find("Special case where there are no manual directives") != std::string::npos,"family manual extraction failed");
- }
-
- {
- // Suite, Check the suite manuals are pre-processed. i.e %includes are expanded
- std::string man_file = ecf_home + suite->absNodePath() + File::MAN_EXTN();
- EcfFile ecf_file(suite.get(), man_file);
-
- std::string manual;
- ecf_file.manual(manual);
- // cout << manual << "\n";
- BOOST_CHECK_MESSAGE(!manual.empty(),"Manual not found");
- BOOST_CHECK_MESSAGE(manual.find("Test manual files are pre-processed") != std::string::npos,"Pre-processing in manual failed");
- BOOST_CHECK_MESSAGE(manual.find("suite manual") != std::string::npos,"Suite manual extraction failed");
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ANode/test/TestEnviromentSubstitution.cpp b/ecflow_4_0_7/ANode/test/TestEnviromentSubstitution.cpp
deleted file mode 100644
index 9b8424e..0000000
--- a/ecflow_4_0_7/ANode/test/TestEnviromentSubstitution.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "Str.hpp"
-
-#include <boost/test/unit_test.hpp>
-#include <boost/foreach.hpp>
-#include <string>
-#include <map>
-#include <iostream>
-#include <fstream>
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_environment_substitution )
-{
- std::cout << "ANode:: ...test_environment_substitution\n";
-
- Defs defs;
- Suite* s = NULL;
- {
- suite_ptr suite = defs.add_suite( "suite" ); s = suite.get();
- suite->addVariable(Variable("AVI","avi"));
-
- std::vector<std::pair<std::string,std::string> > env;
- env.push_back( std::make_pair(Str::ECF_HOME(), string("/home/smshome")) );
- env.push_back( std::make_pair(string("FRED"), string("/home/fred")) );
- env.push_back( std::make_pair(string("BILL"), string("/home/bill")) );
- env.push_back( std::make_pair(string("JANE"), string("/home/jane")) );
- defs.set_server().add_or_update_user_variables( env );
- }
-
- // See page 31, section 5.1 variable inheritance, of SMS users guide
- string expected = "/home/smshome";
- std::string cmd = "$ECF_HOME";
- BOOST_REQUIRE_MESSAGE(s->enviromentSubsitution(cmd)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "$ECF_HOME/include"; expected = "/home/smshome/include";
- BOOST_REQUIRE_MESSAGE(s->enviromentSubsitution(cmd)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "$ECF_HOME$FRED$BILL$JANE"; expected = "/home/smshome/home/fred/home/bill/home/jane";
- BOOST_REQUIRE_MESSAGE(s->enviromentSubsitution(cmd)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
-
- cmd = "$ECF_HOME/$FRED/$BILL/$JANE"; expected = "/home/smshome//home/fred//home/bill//home/jane";
- BOOST_CHECK_MESSAGE(s->enviromentSubsitution(cmd)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%PATH"; expected = "%PATH";
- BOOST_CHECK_MESSAGE(s->enviromentSubsitution(cmd)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "$$"; expected = "$$";
- BOOST_CHECK_MESSAGE(s->enviromentSubsitution(cmd)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "$ERROR$"; expected = "$ERROR$";
- BOOST_CHECK_MESSAGE(!s->enviromentSubsitution(cmd)," substitution expected to fail since ERROR does not exist");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = ""; expected = "";
- BOOST_CHECK_MESSAGE(s->enviromentSubsitution(cmd)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/ANode/test/TestExprParser.cpp b/ecflow_4_0_7/ANode/test/TestExprParser.cpp
deleted file mode 100644
index 295c376..0000000
--- a/ecflow_4_0_7/ANode/test/TestExprParser.cpp
+++ /dev/null
@@ -1,393 +0,0 @@
-#define BOOST_TEST_MODULE TestNode
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include "ExprParser.hpp"
-#include "ExprAst.hpp"
-#include "Expression.hpp"
-
-#include <boost/test/unit_test.hpp>
-#include <boost/foreach.hpp>
-#include <string>
-#include <map>
-#include <iostream>
-#include <fstream>
-using namespace std;
-
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-
-BOOST_AUTO_TEST_CASE( test_expression_parser_basic )
-{
- std::cout << "ANode:: ...test_expression_parser_basic\n";
-
- // This must be nicely formatted, i.e. AST is nicely space formatted otherwise it will fail the test
- // This test ENSURES the the AST matches the expression. (i.e by getting AST to print the expression)
- // Note: we can use NOT,eq,ne,le,ge, or brackets
- // we can't use a:event_name ==> a:event_name == set
- std::vector<std::string> vec;
- vec.push_back("a == complete");
- vec.push_back("a != complete");
- vec.push_back("a:value == 10");
- vec.push_back("a:value != 10");
- vec.push_back("a:value >= 10");
- vec.push_back("a:value <= 10");
- vec.push_back("a:value > 10");
- vec.push_back("a:value < 10");
- vec.push_back("1 == 1");
- vec.push_back("a:event_name == set");
- vec.push_back("a:event_name != set");
- vec.push_back("a:event_name == clear");
- vec.push_back("a:event_name != clear");
- vec.push_back("../a/b:eventname == set");
- vec.push_back("../a/b:eventname == clear");
- vec.push_back("../a/b:eventname != clear");
- vec.push_back("../a:event_name >= 10");
- vec.push_back("a == unknown and b != complete");
- vec.push_back("a == unknown or b != complete");
- vec.push_back("a == complete and b == complete or c == complete");
- vec.push_back("! a == unknown");
- vec.push_back("/mc/main:YMD <= /mc/main/ref:MC_STOP");
- vec.push_back("! ../../../prod2diss/operation_is_late:yes == set or ! a == complete");
- vec.push_back("./a:YMD - ./b:YMD < 5");
- vec.push_back("./a:YMD + ./b:YMD < 5");
- vec.push_back("./a:YMD / ./b:YMD < 5");
- vec.push_back("./a:YMD * ./b:YMD < 5");
- vec.push_back("./a:YMD % ./b:YMD < 5");
- vec.push_back("inigroup:YMD == ! 1");
- vec.push_back("inigroup:YMD == ! 0");
-
- for(size_t i = 0; i < vec.size(); i++) {
-
- PartExpression part(vec[i]);
- string parseErrorMsg;
- std::auto_ptr<AstTop> ast = part.parseExpressions( parseErrorMsg );
- BOOST_REQUIRE_MESSAGE(ast.get(),"Failed to parse " << vec[i] << " " << parseErrorMsg);
-
- std::stringstream s2;
- ast->print_flat(s2);
- std::string ast_expr = s2.str();
- BOOST_CHECK_MESSAGE(vec[i]==ast_expr," Failed '" << vec[i] << "' != '" << ast_expr << "'" );
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_expression_parser_basic_with_brackets )
-{
- std::cout << "ANode:: ...test_expression_parser_basic_with_brackets\n";
-
- // This must be nicely formatted, i.e. AST is nicely space formatted otherwise it will fail the test
- // This test ENSURES the the AST matches the expression. (i.e by getting AST to print the expression)
- // Note: we can use NOT,eq,ne,le,ge,
- // we can't use a:event_name ==> a:event_name == set
- std::vector<std::string> vec;
- vec.push_back("((a == complete) and (b == complete))");
- vec.push_back("(((a == complete) or (b == complete)) and (c == complete))");
- vec.push_back("((a == complete) and ((b == complete) or (nodepath:eventname == set)))");
- vec.push_back("((a == complete) and ((b == complete) or ((a == complete) and (b == complete))))");
- vec.push_back("! ((a == unknown))");
- vec.push_back("((t:step + 20) >= (t:step1 - 20))");
- vec.push_back("(((/o/main/12/an/slwet == complete) and ((/o/main/12/an/4dvar/ifstraj:finalwave == set) or (/o/main/12/an/4dvar == complete))) or (/o/main/12/an == complete))");
- vec.push_back("((obs:YMD <= (main:YMD + 1)) and ((../make/setup == complete) and (obs:YMD <= /o/lag:YMD)))");
- vec.push_back("(((stage == complete) or (./stage:YMD > ./retrieve:YMD)) and ((./retrieve:YMD - ./load:YMD) < 5))");
- vec.push_back("((./a:YMD - ./b:YMD) < 5)");
-
- for(size_t i = 0; i < vec.size(); i++) {
-
- PartExpression part(vec[i]);
- string parseErrorMsg;
- std::auto_ptr<AstTop> ast = part.parseExpressions( parseErrorMsg );
- BOOST_REQUIRE_MESSAGE(ast.get(),"Failed to parse " << vec[i] << " " << parseErrorMsg);
-
- std::stringstream s2;
- ast->print_flat(s2,true/*add_brackets*/);
- std::string ast_expr = s2.str();
- BOOST_CHECK_MESSAGE(vec[i]==ast_expr," Failed '" << vec[i] << "' != '" << ast_expr << "'" );
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_parser_good_expressions )
-{
- std::cout << "ANode:: ...test_parser_good_expressions\n";
-
- // The map key = trigger expression,
- // value.first = type of the expected root abstract syntax tree
- // value.second = result of expected evaluation
- map<string,std::pair<string,bool> > exprMap;
-
- exprMap["a:value == 0"] = std::make_pair(AstEqual::stype(),true);
- exprMap["a:value == 10"] = std::make_pair(AstEqual::stype(),false);
- exprMap["a:value eq 10"] = std::make_pair(AstEqual::stype(),false);
- exprMap["a:value != 10"] = std::make_pair(AstNotEqual::stype(),true);
- exprMap["a:value ne 10"] = std::make_pair(AstNotEqual::stype(),true);
- exprMap["a:value > 10"] = std::make_pair(AstGreaterThan::stype(),false);
- exprMap["a:value gt 10"] = std::make_pair(AstGreaterThan::stype(),false);
- exprMap["a:value >= 10"] = std::make_pair(AstGreaterEqual::stype(),false);
- exprMap["a:value ge 10"] = std::make_pair(AstGreaterEqual::stype(),false);
- exprMap["a:value < 10"] = std::make_pair(AstLessThan::stype(),true);
- exprMap["a:value lt 10"] = std::make_pair(AstLessThan::stype(),true);
- exprMap["a:value <= 10"] = std::make_pair(AstLessEqual::stype(),true);
- exprMap["a:value le 10"] = std::make_pair(AstLessEqual::stype(),true);
-
- exprMap["0 == a:value"] = std::make_pair(AstEqual::stype(),true);
- exprMap["10 == a:value"] = std::make_pair(AstEqual::stype(),false);
- exprMap["10 eq a:value"] = std::make_pair(AstEqual::stype(),false);
- exprMap["10 != a:value"] = std::make_pair(AstNotEqual::stype(),true);
- exprMap["10 ne a:value"] = std::make_pair(AstNotEqual::stype(),true);
- exprMap["10 > a:value"] = std::make_pair(AstGreaterThan::stype(),true);
- exprMap["10 gt a:value"] = std::make_pair(AstGreaterThan::stype(),true);
- exprMap["10 >= a:value"] = std::make_pair(AstGreaterEqual::stype(),true);
- exprMap["10 < a:value"] = std::make_pair(AstLessThan::stype(),false);
- exprMap["10 lt a:value"] = std::make_pair(AstLessThan::stype(),false);
- exprMap["10 <= a:value"] = std::make_pair(AstLessEqual::stype(),false);
- exprMap["10 le a:value"] = std::make_pair(AstLessEqual::stype(),false);
-
- exprMap["a == complete"] = std::make_pair(AstEqual::stype(),false);
- exprMap["a==complete"] = std::make_pair(AstEqual::stype(),false);
- exprMap["a eq complete"] = std::make_pair(AstEqual::stype(),false);
- exprMap["a ne complete"] = std::make_pair(AstNotEqual::stype(),true);
-
- exprMap["0 eq 1"] = std::make_pair(AstEqual::stype(),false);
- exprMap["1000 eq 9"] = std::make_pair(AstEqual::stype(),false);
- exprMap["10 eq 10"] = std::make_pair(AstEqual::stype(),true);
- exprMap["10 ge 4"] = std::make_pair(AstGreaterEqual::stype(),true);
- exprMap["10 le 4"] = std::make_pair(AstLessEqual::stype(),false);
-
- exprMap["0 == 1"] = std::make_pair(AstEqual::stype(),false);
- exprMap["0 != 1"] = std::make_pair(AstNotEqual::stype(),true);
- exprMap["0 < 1"] = std::make_pair(AstLessThan::stype(),true);
- exprMap["10 < 1"] = std::make_pair(AstLessThan::stype(),false);
- exprMap["1000 == 9"] = std::make_pair(AstEqual::stype(),false);
- exprMap["10 == 10"] = std::make_pair(AstEqual::stype(),true);
- exprMap["10 >= 4"] = std::make_pair(AstGreaterEqual::stype(),true);
- exprMap["10 <= 4"] = std::make_pair(AstLessEqual::stype(),false);
- exprMap["0 > 1"] = std::make_pair(AstGreaterThan::stype(),false);
- exprMap["10 > 1"] = std::make_pair(AstGreaterThan::stype(),true);
-
- exprMap["a:eventname"] = std::make_pair(AstEqual::stype(),false);
- exprMap["./a/b:eventname"] = std::make_pair(AstEqual::stype(),false);
- exprMap["/a/b:eventname"] = std::make_pair(AstEqual::stype(),false);
- exprMap["../a/b:eventname == set"] = std::make_pair(AstEqual::stype(),false);
- exprMap["../a/b:eventname == clear"] = std::make_pair(AstEqual::stype(),true);
- exprMap["../a/b:eventname != clear"] = std::make_pair(AstNotEqual::stype(),false);
- exprMap["a:eventname == set"] = std::make_pair(AstEqual::stype(),false);
- exprMap["a:eventname != set"] = std::make_pair(AstNotEqual::stype(),true);
- exprMap["a:eventname == clear"] = std::make_pair(AstEqual::stype(),true);
-
- exprMap["a:metername >= 100"] = std::make_pair(AstGreaterEqual::stype(),false);
- exprMap["b:metername le 100"] = std::make_pair(AstLessEqual::stype(),true);
- exprMap["./b:metername <= 100"] = std::make_pair(AstLessEqual::stype(),true);
- exprMap["../a/b:metername ge 100"] = std::make_pair(AstGreaterEqual::stype(),false);
- exprMap["../a/b/c:metername >= 100"] = std::make_pair(AstGreaterEqual::stype(),false);
-
- exprMap["./a == unknown"] = std::make_pair(AstEqual::stype(),true);
- exprMap["./a/b != queued"] = std::make_pair(AstNotEqual::stype(),true);
- exprMap["../a == complete"] = std::make_pair(AstEqual::stype(),false);
- exprMap["../a/b == aborted"] = std::make_pair(AstEqual::stype(),false);
- exprMap["../a/b/c != aborted"] = std::make_pair(AstNotEqual::stype(),true);
-
- exprMap["a eq unknown and b ne complete"] = std::make_pair(AstAnd::stype(),true);
- exprMap["a eq complete or b eq complete"] = std::make_pair(AstOr::stype(),false);
- exprMap["a eq complete or b eq unknown"] = std::make_pair(AstOr::stype(),true);
- exprMap["a eq complete and b eq complete"] = std::make_pair(AstAnd::stype(),false);
- exprMap["(a eq complete and b == complete)"] = std::make_pair(AstAnd::stype(),false);
-
- exprMap["a == unknown && b != complete"] = std::make_pair(AstAnd::stype(),true);
- exprMap["a == complete || b == complete"] = std::make_pair(AstOr::stype(),false);
- exprMap["a == complete || b == unknown"] = std::make_pair(AstOr::stype(),true);
- exprMap["a eq complete && b eq complete"] = std::make_pair(AstAnd::stype(),false);
- exprMap["(a == complete && b == complete)"] = std::make_pair(AstAnd::stype(),false);
-
- // This should be interpreted as '(a == complete and b == complete) or c == complete'
- // because 'and' has a higher priority than the 'or'. Hence 'OR' must be at the root.
- exprMap["a == complete and b == complete or c == complete"] = std::make_pair(AstOr::stype(),false);
- exprMap["a == complete && b == complete || c == complete"] = std::make_pair(AstOr::stype(),false);
- exprMap["a == complete and b == complete or c == unknown"] = std::make_pair(AstOr::stype(),true);
- exprMap["a == complete and (b == complete or c == complete)"] = std::make_pair(AstAnd::stype(),false);
- exprMap["a == complete or b == complete and c == complete"] = std::make_pair(AstOr::stype(),false);
- exprMap["((a == complete or b == complete)) and c == complete"] = std::make_pair(AstAnd::stype(),false);
-
- exprMap["(a != aborted and b == unknown or c != queued)"] = std::make_pair(AstOr::stype(),true);
- exprMap["(a == complete and b == complete) or nodepath:eventname"] = std::make_pair(AstOr::stype(),false);
- exprMap["(a == complete and b == complete) or (a == complete and b == complete)"] = std::make_pair(AstOr::stype(),false);
- exprMap["a == complete and (b == complete or a == complete) and b == complete"] = std::make_pair(AstAnd::stype(),false);
-
- // Expression that initially fail to parse for the operational suites
- exprMap["(/skull/consumer/admin/leader:1 and (0 le /skull/consumer/produce1/produce:STEP)) or (not /skull/consumer/admin/leader:1)"] = std::make_pair(AstOr::stype(),true);
- exprMap["./pdb eq complete and ( not ../../../prod2diss/operation_is_late:yes or ../000/q2diss eq complete)"] = std::make_pair(AstAnd::stype(),false);
- exprMap["! ../../../prod2diss//operation_is_late:yes"] = std::make_pair(AstNot::stype(),true);
- exprMap["not ../../../prod2diss//operation_is_late:yes"] = std::make_pair(AstNot::stype(),true);
- exprMap["not ../../../prod2diss/operation_is_late:yes"] = std::make_pair(AstNot::stype(),true);
- exprMap["not ../../../prod2diss/operation_is_late:yes or a == complete "] = std::make_pair(AstOr::stype(),true);
- exprMap["not ../../../prod2diss/operation_is_late:yes or not a == complete "] = std::make_pair(AstOr::stype(),true);
- exprMap["not ( a == complete )"] = std::make_pair(AstNot::stype(),true);
- exprMap["not ( a == unknown )"] = std::make_pair(AstNot::stype(),false);
- exprMap["~ ( a == unknown )"] = std::make_pair(AstNot::stype(),false);
- exprMap["~ ( a != unknown )"] = std::make_pair(AstNot::stype(),true);
- exprMap["! ( a == unknown )"] = std::make_pair(AstNot::stype(),false);
- exprMap["!( a == unknown )"] = std::make_pair(AstNot::stype(),false);
- exprMap["inigroup:YMD eq ~ 1"] = std::make_pair(AstEqual::stype(),true);
- exprMap["inigroup:YMD eq ~ 0"] = std::make_pair(AstEqual::stype(),false);
- exprMap["inigroup:YMD eq ! 0"] = std::make_pair(AstEqual::stype(),false);
- exprMap["/net/main:YMD le /net/cleanplus1:YMD and 1"] = std::make_pair(AstAnd::stype(),true);
-
- exprMap["bins/wamabs eq complete and links eq complete"] = std::make_pair(AstAnd::stype(),false);
- exprMap["/mc/main:YMD le /mc/main/ref:MC_STOP"] = std::make_pair(AstLessEqual::stype(),true);
- exprMap["/mc//main:YMD le /mc/main//ref:MC_STOP"] = std::make_pair(AstLessEqual::stype(),true);
- exprMap["( ( /o/main/12/an/slwet eq complete and ( /o/main/12/an/4dvar/ifstraj:finalwave or /o/main/12/an/4dvar eq complete)) or /o/main/12/an eq complete)"] = std::make_pair(AstOr::stype(),false);
- exprMap["../../sv/getsvs eq complete and ( getae:1 or getae eq complete)"] = std::make_pair(AstAnd::stype(),false);
- exprMap["( ( /o/lag:YMD gt /sync/o/o/lag:YMD) or ( /o/main:YMD gt /sync/o/o/main:YMD) or 1 eq 0) and /sync/o ne active and /sync/o ne submitted"] = std::make_pair(AstAnd::stype(),false);
-
-
- exprMap["t:step + 20 le 19"] = std::make_pair(AstLessEqual::stype(),false);
- exprMap["(t:step + 20) le 19"] = std::make_pair(AstLessEqual::stype(),false);
- exprMap["t:step + 20 ge 120"] = std::make_pair(AstGreaterEqual::stype(),false);
- exprMap["t:step - 20 ge 120"] = std::make_pair(AstGreaterEqual::stype(),false);
- exprMap["t:step + 20 ge t:step1 - 20"] = std::make_pair(AstGreaterEqual::stype(),true);
- exprMap["(t:step + 20) ge (t:step1 - 20)"] = std::make_pair(AstGreaterEqual::stype(),true);
-
- // Note: t:step will evaluate to 0, 0 % number == 0, however 20 % 0 is a runtime error, same as divide by zero
- exprMap["t:step % 20 < 19"] = std::make_pair(AstLessThan::stype(),true);
- exprMap["t:step % 10 == 0"] = std::make_pair(AstEqual::stype(),true);
- exprMap["t:step % 20 ge 19"] = std::make_pair(AstGreaterEqual::stype(),false);
- exprMap["(t:step % 20) ge 19"] = std::make_pair(AstGreaterEqual::stype(),false);
- exprMap["t:step % 20 ge 120"] = std::make_pair(AstGreaterEqual::stype(),false);
- exprMap["t:step % 20 ge 120"] = std::make_pair(AstGreaterEqual::stype(),false);
- exprMap["t:step % 20 ge t:step1 - 20"] = std::make_pair(AstGreaterEqual::stype(),true);
- exprMap["(t:step % 20) ge (t:step1 - 20)"] = std::make_pair(AstGreaterEqual::stype(),true);
- exprMap["(t:step % 20) == (t:step1 % 10)"] = std::make_pair(AstEqual::stype(),true);
-
- exprMap["( obs:YMD le ( main:YMD + 1)) and ../make/setup eq complete and ( obs:YMD le /o/lag:YMD)"] = std::make_pair(AstAnd::stype(),false);
- exprMap["( stage eq complete or ./stage:YMD gt ./retrieve:YMD) and ( ./retrieve:YMD - ./load:YMD lt 5)"] = std::make_pair(AstAnd::stype(),false);
- exprMap["./a:YMD - ./b:YMD lt 5"] = std::make_pair(AstLessThan::stype(),true);
-
-
- std::pair<string, std::pair<string,bool> > p;
- BOOST_FOREACH(p, exprMap ) {
-
- ExprParser theExprParser(p.first);
- std::string errorMsg;
- bool ok = theExprParser.doParse(errorMsg);
- BOOST_REQUIRE_MESSAGE(ok,errorMsg);
-
- string expectedRootType = p.second.first;
- bool expectedEvaluationResult = p.second.second;
-
- Ast* top = theExprParser.getAst();
- BOOST_REQUIRE_MESSAGE( top ,"No abstract syntax tree");
- BOOST_CHECK_MESSAGE( top->left() ,"No root created");
- BOOST_CHECK_MESSAGE( top->left()->isRoot() ,"First child of top should be a root");
- BOOST_CHECK_MESSAGE( top->left()->type() == expectedRootType,"expected root type " << expectedRootType << " but found " << top->left()->type());
- BOOST_CHECK_MESSAGE( expectedEvaluationResult == top->evaluate(),"evaluation not as expected for " << *top);
-
- std::string error_msg;
- BOOST_CHECK_MESSAGE( top->check(error_msg),error_msg << ": Check failed for " << *top);
- }
-}
-
-
-BOOST_AUTO_TEST_CASE( test_trigger_expression_divide_by_zero )
-{
- std::cout << "ANode:: ...test_trigger_expression_divide_by_zero\n";
-
- // The map key = trigger expression,
- // value.first = type of the expected root abstract syntax tree
- // value.second = result of expected evaluation
- map<string,std::pair<string,bool> > exprMap;
-
- // Divide by zero or modulo by zero would lead to run-time crash
- // However the Ast::evaluate() checks for this, and return zero for the whole expression i.e ./a:YMD % 0 returns 0
- exprMap["./a:YMD % 0 == 0"] = std::make_pair(AstEqual::stype(),true);
- exprMap["./a:YMD / 0 == 0"] = std::make_pair(AstEqual::stype(),true);
-
-
- std::pair<string, std::pair<string,bool> > p;
- BOOST_FOREACH(p, exprMap ) {
-
- ExprParser theExprParser(p.first);
- std::string errorMsg;
- bool ok = theExprParser.doParse(errorMsg);
- BOOST_REQUIRE_MESSAGE(ok,errorMsg);
-
- string expectedRootType = p.second.first;
- bool expectedEvaluationResult = p.second.second;
-
- Ast* top = theExprParser.getAst();
- BOOST_REQUIRE_MESSAGE( top ,"No abstract syntax tree");
- BOOST_CHECK_MESSAGE( top->left() ,"No root created");
- BOOST_CHECK_MESSAGE( top->left()->isRoot() ,"First child of top should be a root");
- BOOST_CHECK_MESSAGE( top->left()->type() == expectedRootType,"expected root type " << expectedRootType << " but found " << top->left()->type());
- BOOST_CHECK_MESSAGE( expectedEvaluationResult == top->evaluate(),"evaluation not as expected for " << *top);
-
- // expect check to fail, due to divide/modulo by zero
- std::string error_msg;
- BOOST_CHECK_MESSAGE( !top->check(error_msg),error_msg << ": Check failed for " << *top);
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_parser_bad_expressions )
-{
- std::cout << "ANode:: ...test_parser_bad_expressions\n";
- vector<string> exprvec;
- exprvec.push_back("a = complete");
- exprvec.push_back("a e complete");
- exprvec.push_back("a=complete");
- exprvec.push_back("a ! complete");
- exprvec.push_back("a==complet e");
- exprvec.push_back("a eq complet e");
- exprvec.push_back("a::eventname");
- exprvec.push_back("a:eventname = set");
- exprvec.push_back("a:eventname == ");
- exprvec.push_back("a:eventname ! set");
- exprvec.push_back("a:eventname ! = set");
- exprvec.push_back("a:eventname %");
- exprvec.push_back("a:metername 100");
- exprvec.push_back(". == complete");
- exprvec.push_back("/ == complete");
- exprvec.push_back(". == error");
- exprvec.push_back("./ == error");
- exprvec.push_back(".a == error");
- exprvec.push_back(".a == unknown");
- exprvec.push_back(".a/. == unknown");
- exprvec.push_back(".. == unknown");
- exprvec.push_back(".a/b == queued");
- exprvec.push_back("./a/b/ == active");
- exprvec.push_back("..a == complete");
- exprvec.push_back(".../a == complete");
- exprvec.push_back("../.../a == complete");
- exprvec.push_back(".. /a == complete");
- exprvec.push_back("../.. /a == complete");
- exprvec.push_back("../../.a == complete");
- exprvec.push_back("..a/b == aborted");
- exprvec.push_back("..a/b/c == aborted");
- exprvec.push_back("a == complete and");
- exprvec.push_back("a %");
- exprvec.push_back("(a == complete b == complete)");
- exprvec.push_back("a == complete and b == complete)");
- exprvec.push_back("(a == complete and b == complete");
- exprvec.push_back("(a = complete and b = complete or c = complete)");
- exprvec.push_back("(a erro complete and b == complete) or nodepath:eventname");
- exprvec.push_back("(a == complete and b == complete or (a == complete and b == complete)");
- // triggers that dont make sense in the operational suites.
- exprvec.push_back("../../../legA/fc/pf/01 eq complete eq complete");
-
- BOOST_FOREACH(const string& expr, exprvec ) {
-
- //std::cout << "parsing expression " << expr << "\n";
- ExprParser theExprParser(expr);
- std::string errorMsg;
- BOOST_CHECK_MESSAGE( !theExprParser.doParse( errorMsg), expr << " expected to fail " );
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/ANode/test/TestExprRepeatDateArithmetic.cpp b/ecflow_4_0_7/ANode/test/TestExprRepeatDateArithmetic.cpp
deleted file mode 100644
index f7aab10..0000000
--- a/ecflow_4_0_7/ANode/test/TestExprRepeatDateArithmetic.cpp
+++ /dev/null
@@ -1,216 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/test/unit_test.hpp>
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_repeat_data_arithmetic )
-{
- cout << "ANode:: ...test_repeat_data_arithmetic\n" ;
-
- Defs theDefs;
- task_ptr t2,t1;
- {
- suite_ptr s1 = theDefs.add_suite("s1");
- t1 = s1->add_task("t1"); t1->addRepeat( RepeatDate("YMD",20090101,20091231,1));
- t2 = s1->add_task("t2"); t2->add_trigger("t1:YMD ge 20080601");
- }
- theDefs.beginAll();
-
- // Check trigger expressions
- std::string errorMsg, warningMsg;
- BOOST_REQUIRE_MESSAGE(theDefs.check(errorMsg,warningMsg),"Expected triggers expressions to parse " << errorMsg);
-
- // Get the trigger AST
- Ast* trigger = t2->triggerAst();
- BOOST_REQUIRE_MESSAGE(trigger,"Expected trigger");
-
- // check evaluation
- BOOST_CHECK_MESSAGE(trigger->evaluate(),"Expected trigger to evaluate i.e 20090101 >= 20080601");
-
- // Check date arithmetic. Basics, end of months
- t2->changeTrigger("t1:YMD - 1 eq 20081231"); // 20090101 - 1 == 20081231
- BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic for evaluation");
-
- t2->changeTrigger("t1:YMD + 1 eq 20090102"); // 20090101 + 1 == 20090102
- BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic for evaluation");
-}
-
-BOOST_AUTO_TEST_CASE( test_repeat_data_arithmetic_add_to_end_of_month )
-{
- cout << "ANode:: ...test_repeat_data_arithmetic_add_to_end_of_month\n" ;
-
- Defs theDefs;
- task_ptr t2,t1;
- {
- suite_ptr s1 = theDefs.add_suite("s1");
- t1 = s1->add_task("t1"); t1->addRepeat( RepeatDate("YMD",20090101,20091231,1));
- t2 = s1->add_task("t2"); t2->add_trigger("t1:YMD ge 20080601");
- }
- theDefs.beginAll();
-
- // Check trigger expressions
- std::string errorMsg, warningMsg;
- BOOST_REQUIRE_MESSAGE(theDefs.check(errorMsg,warningMsg),"Expected triggers expressions to parse " << errorMsg);
-
- // Check the end of each month + 1
- t1->deleteRepeat();
- t1->addRepeat( RepeatDate("YMD",20090131,20101231,1)); // jan
- t2->changeTrigger("t1:YMD + 1 eq 20090201"); // 20090131 + 1 == 20090201
- BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
-
- t1->deleteRepeat();
- t1->addRepeat( RepeatDate("YMD",20090228,20101231,1)); // feb
- t2->changeTrigger("t1:YMD + 1 eq 20090301");
- BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
-
- t1->deleteRepeat();
- t1->addRepeat( RepeatDate("YMD",20090331,20101231,1)); // mar
- t2->changeTrigger("t1:YMD + 1 eq 20090401");
- BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
-
- t1->deleteRepeat();
- t1->addRepeat( RepeatDate("YMD",20090430,20101231,1)); // apr
- t2->changeTrigger("t1:YMD + 1 eq 20090501");
- BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
-
- t1->deleteRepeat();
- t1->addRepeat( RepeatDate("YMD",20090531,20101231,1)); // may
- t2->changeTrigger("t1:YMD + 1 eq 20090601");
- BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
-
- t1->deleteRepeat();
- t1->addRepeat( RepeatDate("YMD",20090630,20101231,1)); // June
- t2->changeTrigger("t1:YMD + 1 eq 20090701");
- BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
-
- t1->deleteRepeat();
- t1->addRepeat( RepeatDate("YMD",20090731,20101231,1)); // July
- t2->changeTrigger("t1:YMD + 1 eq 20090801");
- BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
-
- t1->deleteRepeat();
- t1->addRepeat( RepeatDate("YMD",20090831,20101231,1)); // Aug
- t2->changeTrigger("t1:YMD + 1 eq 20090901");
- BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
-
- t1->deleteRepeat();
- t1->addRepeat( RepeatDate("YMD",20090930,20101231,1)); // Sept
- t2->changeTrigger("t1:YMD + 1 eq 20091001");
- BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
-
- t1->deleteRepeat();
- t1->addRepeat( RepeatDate("YMD",20091031,20101231,1)); // Oct
- t2->changeTrigger("t1:YMD + 1 eq 20091101");
- BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
-
- t1->deleteRepeat();
- t1->addRepeat( RepeatDate("YMD",20091130,20101231,1)); // Nov
- t2->changeTrigger("t1:YMD + 1 eq 20091201");
- BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
-
- t1->deleteRepeat();
- t1->addRepeat( RepeatDate("YMD",20091231,20101231,1)); // Dec
- t2->changeTrigger("t1:YMD + 1 eq 20100101");
- BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
-}
-
-
-BOOST_AUTO_TEST_CASE( test_repeat_data_arithmetic_take_from_end_of_month )
-{
- cout << "ANode:: ...test_repeat_data_arithmetic_take_from_end_of_month\n" ;
-
- Defs theDefs;
- task_ptr t2,t1;
- {
- suite_ptr s1 = theDefs.add_suite("s1");
- t1 = s1->add_task("t1"); t1->addRepeat( RepeatDate("YMD",20090101,20091231,1));
- t2 = s1->add_task("t2"); t2->add_trigger("t1:YMD ge 20080601");
- }
- theDefs.beginAll();
-
- // Check trigger expressions
- std::string errorMsg, warningMsg;
- BOOST_REQUIRE_MESSAGE(theDefs.check(errorMsg,warningMsg),"Expected triggers expressions to parse " << errorMsg);
-
- // Check the end of each month - 1
- t1->deleteRepeat();
- t1->addRepeat( RepeatDate("YMD",20090201,20101231,1)); // jan
- t2->changeTrigger("t1:YMD - 1 eq 20090131");
- BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
-
- t1->deleteRepeat();
- t1->addRepeat( RepeatDate("YMD",20090301,20101231,1)); // feb
- t2->changeTrigger("t1:YMD - 1 eq 20090228");
- BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
-
- t1->deleteRepeat();
- t1->addRepeat( RepeatDate("YMD",20090401,20101231,1)); // mar
- t2->changeTrigger("t1:YMD - 1 eq 20090331");
- BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
-
- t1->deleteRepeat();
- t1->addRepeat( RepeatDate("YMD",20090501,20101231,1)); // apr
- t2->changeTrigger("t1:YMD - 1 eq 20090430");
- BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
-
- t1->deleteRepeat();
- t1->addRepeat( RepeatDate("YMD",20090601,20101231,1)); // may
- t2->changeTrigger("t1:YMD - 1 eq 20090531");
- BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
-
- t1->deleteRepeat();
- t1->addRepeat( RepeatDate("YMD",20090701,20101231,1)); // June
- t2->changeTrigger("t1:YMD - 1 eq 20090630");
- BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
-
- t1->deleteRepeat();
- t1->addRepeat( RepeatDate("YMD",20090801,20101231,1)); // July
- t2->changeTrigger("t1:YMD - 1 eq 20090731");
- BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
-
- t1->deleteRepeat();
- t1->addRepeat( RepeatDate("YMD",20090901,20101231,1)); // Aug
- t2->changeTrigger("t1:YMD - 1 eq 20090831");
- BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
-
- t1->deleteRepeat();
- t1->addRepeat( RepeatDate("YMD",20091001 ,20101231,1)); // Sept
- t2->changeTrigger("t1:YMD - 1 eq 20090930");
- BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
-
- t1->deleteRepeat();
- t1->addRepeat( RepeatDate("YMD",20091101 ,20101231,1)); // Oct
- t2->changeTrigger("t1:YMD - 1 eq 20091031");
- BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
-
- t1->deleteRepeat();
- t1->addRepeat( RepeatDate("YMD",20091201 ,20101231,1)); // Nov
- t2->changeTrigger("t1:YMD - 1 eq 20091130");
- BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
-
- t1->deleteRepeat();
- t1->addRepeat( RepeatDate("YMD",20100101 ,20101231,1)); // Dec
- t2->changeTrigger("t1:YMD - 1 eq 20091231");
- BOOST_CHECK_MESSAGE(t2->triggerAst()->evaluate(),"Expected trigger to use date arithmetic");
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ANode/test/TestFindAbsNodePath.cpp b/ecflow_4_0_7/ANode/test/TestFindAbsNodePath.cpp
deleted file mode 100644
index 74c889f..0000000
--- a/ecflow_4_0_7/ANode/test/TestFindAbsNodePath.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "Alias.hpp"
-#include "PrintStyle.hpp"
-
-#include <boost/test/unit_test.hpp>
-#include <iostream>
-#include <stdlib.h>
-
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_find_abs_node_path )
-{
- cout << "ANode:: ...test_find_abs_node_path\n";
-
- size_t no_of_nodes = 0;
- size_t no_of_alias = 0;
- Defs theDefs;
- {
- for(int s = 0; s < 3; s++) {
- suite_ptr suite = theDefs.add_suite( "suite" + boost::lexical_cast<std::string>(s)); no_of_nodes++;
- for(int f = 0; f < 3; f++) {
- family_ptr fam = suite->add_family( "family" + boost::lexical_cast<std::string>(f)); no_of_nodes++;
- for(int ff = 0; ff < 3; ff++) {
- family_ptr hfam = fam->add_family( "family" + boost::lexical_cast<std::string>(ff)); no_of_nodes++;
- for(int t = 0; t < 3; t++) {
- task_ptr task = hfam->add_task( "t1" + boost::lexical_cast<std::string>(t)); no_of_nodes++;
- for(int a = 0; a < 3; a++) {
- task->add_alias_only(); no_of_nodes++; no_of_alias++;
- }
- }
- }
- }
- }
- }
-
- // Test Defs::getAllNodes()
- std::vector<Node*> all_nodes;
- theDefs.getAllNodes(all_nodes);
- BOOST_CHECK_MESSAGE(all_nodes.size() == no_of_nodes,"Expected theDefs.getAllNodes() to return " << no_of_nodes << " node, but found " << all_nodes.size());
-
- // Test Defs::get_all_aliases()
- std::vector<alias_ptr> alias_vec;
- theDefs.get_all_aliases(alias_vec);
- BOOST_CHECK_MESSAGE(alias_vec.size() == no_of_alias,"Expected theDefs.get_all_aliases() to return " << no_of_alias << " node, but found " << alias_vec.size());
-
- // Test Defs::findAbsNode()
-// PrintStyle::setStyle(PrintStyle::STATE);
-// std::cout << theDefs;
- for(size_t i= 0; i < all_nodes.size(); i++) {
- Node* node = all_nodes[i];
- node_ptr found_node = theDefs.findAbsNode(node->absNodePath());
- BOOST_CHECK_MESSAGE(found_node.get(),"Could not find node " << node->debugNodePath());
- BOOST_CHECK_MESSAGE(found_node.get() == node," Expected to find " << node->debugNodePath() << " but found " << found_node->debugNodePath());
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ANode/test/TestFlag.cpp b/ecflow_4_0_7/ANode/test/TestFlag.cpp
deleted file mode 100644
index 69374a8..0000000
--- a/ecflow_4_0_7/ANode/test/TestFlag.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <iostream>
-#include <boost/test/unit_test.hpp>
-
-#include "Flag.hpp"
-#include "Str.hpp"
-
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_node_flags )
-{
- cout << "ANode:: ...test_node_flags\n";
-
- Flag flag;
- std::string expected_flags = "force_aborted,user_edit,task_aborted,ecfcmd_failed,no_script,killed,migrated,late,message,by_rule,queue_limit,task_waiting,locked,zombie,no_reque";
-
- /// Set the flags
- std::vector<Flag::Type> flag_list = Flag::list();
- for (size_t i = 0; i < flag_list.size(); ++i) {
- flag.set( flag_list[i] );
- BOOST_REQUIRE_MESSAGE(flag.is_set( flag_list[i] ), "Expected flag to be set");
- }
- BOOST_REQUIRE_MESSAGE(flag.to_string() == expected_flags, "Expected string '" << expected_flags << "' but found '" << flag.to_string() << "'");
- for (size_t i = 0; i < flag_list.size(); ++i) {
- BOOST_REQUIRE_MESSAGE(flag.is_set( flag_list[i] ), "Expected flag to be set");
- }
-
- /// clears the flags
- for (size_t i = 0; i < flag_list.size(); ++i) {
- flag.clear( flag_list[i] );
- BOOST_REQUIRE_MESSAGE(!flag.is_set( flag_list[i] ), "Expected flag to be clear");
- }
- for (size_t i = 0; i < flag_list.size(); ++i) {
- BOOST_REQUIRE_MESSAGE(!flag.is_set( flag_list[i] ), "Expected flag to be clear");
- }
-
- /// set all flags
- for (size_t i = 0; i < flag_list.size(); ++i) { flag.set( flag_list[i] );}
-
- // reset, all flags should be clear
- flag.reset();
- for (size_t i = 0; i < flag_list.size(); ++i) {
- BOOST_REQUIRE_MESSAGE(!flag.is_set( flag_list[i] ), "Expected flag to be clear");
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_node_flags_parsing )
-{
- cout << "ANode:: ...test_node_flags_parsing\n";
-
- /// Set the flags
- Flag flag;
- std::vector<Flag::Type> flag_list = Flag::list();
- for (size_t i = 0; i < flag_list.size(); ++i) flag.set( flag_list[i] );
-
- Flag flag2;
- flag2.set_flag(flag.to_string());
- BOOST_REQUIRE_MESSAGE(flag == flag2, "Flags should be equal.\nflag1:" << flag.to_string() << "\nflag2:" << flag2.to_string());
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ANode/test/TestHistoryParser.cpp b/ecflow_4_0_7/ANode/test/TestHistoryParser.cpp
deleted file mode 100644
index 4e27c8a..0000000
--- a/ecflow_4_0_7/ANode/test/TestHistoryParser.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #24 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <string>
-#include <iostream>
-#include <fstream>
-
-#include <boost/test/unit_test.hpp>
-
-#include "Defs.hpp"
-#include "Log.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost;
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-static std::string dump(const std::vector<std::string>& vec)
-{
- std::stringstream ss;
- std::copy (vec.begin(), vec.end(), std::ostream_iterator<std::string> (ss, "\n"));
- return ss.str();
-}
-
-BOOST_AUTO_TEST_CASE( test_defs_history_parser )
-{
- cout << "ACore:: ...test_defs_history_parser\n";
-
- {
- string str1("MSG:[12:03:55 21.8.2013] --shutdown=yes :map");
- DefsHistoryParser parser;
- parser.parse(str1);
-
- std::vector<std::string> expected_messages;
- expected_messages.push_back("MSG:[12:03:55 21.8.2013] --shutdown=yes :map");
-
- BOOST_CHECK_MESSAGE(parser.parsed_messages() == expected_messages,"Expected:\n" << dump(expected_messages) << "but found:\n" << dump(parser.parsed_messages()));
- }
- {
- string str1("MSG:[12:03:55 21.8.2013] --shutdown=yes :mapMSG:[12:34:08 21.8.2013] --restart :map");
- DefsHistoryParser parser;
- parser.parse(str1);
-
- std::vector<std::string> expected_messages;
- expected_messages.push_back("MSG:[12:03:55 21.8.2013] --shutdown=yes :map");
- expected_messages.push_back("MSG:[12:34:08 21.8.2013] --restart :map");
- BOOST_CHECK_MESSAGE(parser.parsed_messages() == expected_messages,"Expected:\n" << dump(expected_messages) << "but found:\n" << dump(parser.parsed_messages()));
- }
- {
- string str1("MSG:[12:03:55 21.8.2013] --shutdown=yes :mapMSG:[12:34:08 21.8.2013] --restart :mapMSG:[12:47:22 21.8.2013] --alter add variable SMSNODE 0 / :mapMSG:[13:38:45 21.8.2013] --alter add variable SMSTRYNO 0 / :mapMSG:[13:44:09 21.8.2013] --alter add variable SMSHOME /vol/emos/output / :mapMSG:[15:36:14 21.8.2013] --shutdown=yes :mapMSG:[16:04:26 21.8.2013] --alter add variable SMSNODE 0 / :map");
- DefsHistoryParser parser;
- parser.parse(str1);
-
- std::vector<std::string> expected_messages;
- expected_messages.push_back("MSG:[12:03:55 21.8.2013] --shutdown=yes :map");
- expected_messages.push_back("MSG:[12:34:08 21.8.2013] --restart :map");
- expected_messages.push_back("MSG:[12:47:22 21.8.2013] --alter add variable SMSNODE 0 / :map");
- expected_messages.push_back("MSG:[13:38:45 21.8.2013] --alter add variable SMSTRYNO 0 / :map");
- expected_messages.push_back("MSG:[13:44:09 21.8.2013] --alter add variable SMSHOME /vol/emos/output / :map");
- expected_messages.push_back("MSG:[15:36:14 21.8.2013] --shutdown=yes :map");
- expected_messages.push_back("MSG:[16:04:26 21.8.2013] --alter add variable SMSNODE 0 / :map");
- BOOST_CHECK_MESSAGE(parser.parsed_messages() == expected_messages,"Expected:\n" << dump(expected_messages) << "but found:\n" << dump(parser.parsed_messages()));
- }
- {
- string str1("MSG:[12:03:55 21.8.2013] --shutdown=yes :mapLOG:[12:34:08 21.8.2013] --restart :mapERR:[12:47:22 21.8.2013] --alter add variable SMSNODE 0 / :mapWAR:[13:38:45 21.8.2013] --alter add variable SMSTRYNO 0 / :mapDBG:[13:44:09 21.8.2013] --alter add variable SMSHOME /vol/emos/output / :mapOTH:[15:36:14 21.8.2013] --shutdown=yes :mapOTH:[16:04:26 21.8.2013] --alter add variable SMSNODE 0 / :map");
- DefsHistoryParser parser;
- parser.parse(str1);
-
- std::vector<std::string> expected_messages;
- expected_messages.push_back("MSG:[12:03:55 21.8.2013] --shutdown=yes :map");
- expected_messages.push_back("LOG:[12:34:08 21.8.2013] --restart :map");
- expected_messages.push_back("ERR:[12:47:22 21.8.2013] --alter add variable SMSNODE 0 / :map");
- expected_messages.push_back("WAR:[13:38:45 21.8.2013] --alter add variable SMSTRYNO 0 / :map");
- expected_messages.push_back("DBG:[13:44:09 21.8.2013] --alter add variable SMSHOME /vol/emos/output / :map");
- expected_messages.push_back("OTH:[15:36:14 21.8.2013] --shutdown=yes :map");
- expected_messages.push_back("OTH:[16:04:26 21.8.2013] --alter add variable SMSNODE 0 / :map");
- BOOST_CHECK_MESSAGE(parser.parsed_messages() == expected_messages,"Expected:\n" << dump(expected_messages) << "but found:\n" << dump(parser.parsed_messages()));
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ANode/test/TestInLimit.cpp b/ecflow_4_0_7/ANode/test/TestInLimit.cpp
deleted file mode 100644
index 8d52932..0000000
--- a/ecflow_4_0_7/ANode/test/TestInLimit.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #1 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <iostream>
-#include <boost/test/unit_test.hpp>
-
-#include "SerializationTest.hpp"
-#include "InLimit.hpp"
-
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_inlimit_basics )
-{
- cout << "ANode:: ...test_inlimit_basics \n";
-
- {
- InLimit empty;
- InLimit empty2;
- BOOST_CHECK_MESSAGE(empty == empty2,"Equality failed");
-
- InLimit l1("name","path");
- InLimit l2("name","path");
- BOOST_CHECK_MESSAGE(l1 == l2,"Equality failed");
-
- InLimit a("name","path",10);
- InLimit b("name","path");
- BOOST_CHECK_MESSAGE(!(a == b),"Equality passed when should fail");
- }
-
- InLimit inlim("fred","/path/to/node");
- {
- InLimit testCopy = inlim;
- BOOST_CHECK_MESSAGE(testCopy == inlim,"Copy constructor failed");
- }
- {
- InLimit testCopy;
- testCopy = inlim;
- BOOST_CHECK_MESSAGE(testCopy == inlim,"Assignment failed");
- }
-}
-
-
-// Globals used throughout the test
-static std::string fileName = "test.txt";
-BOOST_AUTO_TEST_CASE( test_InLimit_serialisation )
-{
- cout << "ANode:: ...test_InLimit_serialisation\n";
-
- doSaveAndRestore<InLimit>(fileName);
-
- InLimit saved("limitName","/path/to/some/node",20);
- save(fileName,saved);
-
- InLimit restored; restore(fileName,restored);
- BOOST_CHECK_MESSAGE(saved == restored," save and restored don't match");
- std::remove(fileName.c_str());
-}
-
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/ANode/test/TestJobCreator.cpp b/ecflow_4_0_7/ANode/test/TestJobCreator.cpp
deleted file mode 100644
index 8dbf55a..0000000
--- a/ecflow_4_0_7/ANode/test/TestJobCreator.cpp
+++ /dev/null
@@ -1,121 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <iostream>
-#include <fstream>
-#include <stdlib.h>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/test/unit_test.hpp>
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "EcfFile.hpp"
-#include "JobsParam.hpp"
-#include "Jobs.hpp"
-#include "System.hpp"
-#include "Str.hpp"
-#include "File.hpp"
-
-using namespace std;
-using namespace ecf;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_job_creator )
-{
- cout << "ANode:: ...test_job_creator\n";
-
- // SET SMSHOME
- std::string ecf_home = File::test_data("ANode/test/data/SMSHOME","ANode");
-
- // Create the defs file corresponding to the text below
- //# Test the sms file can be found via ECF_SCRIPT
- //# Note: we have to use relative paths, since these tests are relocatable
- //#
- //suite suite
- // edit SLEEPTIME 10
- // edit ECF_INCLUDE $ECF_HOME/includes
- // family family
- // task t1
- // task t2
- // task t3
- // endfamily
- //endsuite
- //#
- //# This test suite should force a backwards search since the sms files
- //# are located in SMSHOME
- //suite suite1
- // family family
- // task suite1_task1
- // task suite1_task2
- // task suite1_task3
- // endfamily
- //endsuite
- // Create a defs file, where the task name mirrors the sms files in the given directory
- Defs theDefs;
- {
- suite_ptr suite = Suite::create( "suite" );
- family_ptr fam = Family::create( "family" );
- suite->addVariable( Variable( Str::ECF_INCLUDE(), "$ECF_HOME/../includes" ) );
- suite->addVariable( Variable( "SLEEPTIME", "1" ) );
- suite->addVariable( Variable( "ECF_CLIENT_EXE_PATH", "a/made/up/path" ) );
- fam->addTask( Task::create( "t1" ) );
- fam->addTask( Task::create( "t2" ) );
- fam->addTask( Task::create( "t3" ) );
- suite->addFamily( fam );
- theDefs.addSuite( suite );
- }
- {
- suite_ptr suite1( new Suite( "suite1" ) );
- family_ptr fam( new Family( "family" ) );
- fam->addTask( Task::create( "suite1_task1" ) );
- fam->addTask( Task::create( "suite1_task2" ) );
- fam->addTask( Task::create( "suite1_task3" ) );
- suite1->addFamily( fam );
- theDefs.addSuite( suite1 );
- }
-// cerr << theDefs << "\n";
-
- // get all the task, assume non hierarchical families
- std::vector<Task*> theTasks;
- theDefs.getAllTasks(theTasks);
- BOOST_REQUIRE_MESSAGE(theTasks.size() == 6, "Expected 6 tasks but found, " << theTasks.size());
-
-
- // Override ECF_HOME. ECF_HOME is need to locate to the .ecf files
- theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(),ecf_home);
-
-
- /// begin , will cause creation of generated variables. The generated variables
- /// are use in client scripts and used to locate the ecf files
- theDefs.beginAll();
-
- // Test Job creator. The job creation should succeed 3 times only, since
- // the sms file suite1_task1, suite1_task2,suite1_task3 are empty.
- JobsParam jobsParam(true/*create jobs*/); // spawn_jobs = false
- Jobs jobs(&theDefs);
- jobs.generate(jobsParam);
- BOOST_REQUIRE_MESSAGE( jobsParam.submitted().size() == 3 , "expected 3 jobs but found " << jobsParam.submitted().size() << "\n" << jobsParam.errorMsg());
-
- // Expect error message complaining about sms file suite1_task1, suite1_task2,suite1_task3 being empty
- BOOST_REQUIRE_MESSAGE( !jobsParam.errorMsg().empty(), "expected error message about empty ecf files");
-
- /// Destroy System singleton to avoid valgrind from complaining
- System::destroy();
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ANode/test/TestJobProfiler.cpp b/ecflow_4_0_7/ANode/test/TestJobProfiler.cpp
deleted file mode 100644
index 136aa29..0000000
--- a/ecflow_4_0_7/ANode/test/TestJobProfiler.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <iostream>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/test/unit_test.hpp>
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "Str.hpp"
-#include "File.hpp"
-#include "Log.hpp"
-#include "Jobs.hpp"
-#include "JobsParam.hpp"
-#include "System.hpp"
-
-using namespace std;
-using namespace ecf;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_job_profiler )
-{
- cout << "ANode:: ...test_job_profiler\n";
-
- // delete the log file if it exists.
- std::string log_path = File::test_data("ANode/test/logfile.txt","ANode");
- fs::remove(log_path);
- BOOST_CHECK_MESSAGE(!fs::exists( log_path ), "log file " << log_path << " not deleted ");
-
- // Create a new log, file, we will look in here to see if job profiling is working
- Log::create(log_path);
-
-
- // SET ECF_HOME, re-use exist test of directory and scripts
- Defs theDefs;
- {
- suite_ptr suite = theDefs.add_suite("suite");
- suite->addVariable( Variable( Str::ECF_INCLUDE(), File::test_data("ANode/test/data/includes","ANode") ) );
- suite->addVariable( Variable( "ECF_HOME", File::test_data("ANode/test/data/SMSHOME","ANode") ) );
- suite->addVariable( Variable( "SLEEPTIME", "10" ) );
- family_ptr fam = suite->add_family( "family" );
- fam->add_task( "t1" );
- }
- // cerr << theDefs << "\n";
-
- // begin , will cause creation of generated variables. The generated variables
- // are use in client scripts and used to locate the ecf files
- theDefs.beginAll();
-
- // By setting submitJobsInterval to -1, we enable the jobs profiling testing
- // createJobs enables us to ensure job size is profiled
- // spawn jobs set to false, do not create a separate process to spawn jobs
- JobsParam jobParam(-1 /*submitJobsInterval*/, true /*createJobs*/, false/* spawn jobs */);
- Jobs job(&theDefs);
- bool ok = job.generate( jobParam );
- BOOST_CHECK_MESSAGE(ok,"generate failed: " << jobParam.getErrorMsg());
-
- // Check the log file, has the profiling
- std::string log_file_contents;
- BOOST_CHECK_MESSAGE(File::open(log_path,log_file_contents), "Could not open log file at " << log_path);
- BOOST_CHECK_MESSAGE(!log_file_contents.empty(),"log file is is empty ?");
- BOOST_CHECK_MESSAGE(log_file_contents.find("Exceeds ECF_TASK_THRESHOLD") != std::string::npos, "Exceeds ECF_TASK_THRESHOLD not in profile");
-
- // Remove the log file. Comment out for debugging
- fs::remove(log_path);
-
- // Explicitly destroy log. To keep valgrind happy
- Log::destroy();
-
- /// Destroy System singleton to avoid valgrind from complaining
- System::destroy();
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ANode/test/TestLimit.cpp b/ecflow_4_0_7/ANode/test/TestLimit.cpp
deleted file mode 100644
index 35a9c9b..0000000
--- a/ecflow_4_0_7/ANode/test/TestLimit.cpp
+++ /dev/null
@@ -1,157 +0,0 @@
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #1 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <iostream>
-
-#include <boost/test/unit_test.hpp>
-#include <boost/lexical_cast.hpp>
-#include "SerializationTest.hpp"
-
-#include "Limit.hpp"
-#include "Ecf.hpp"
-
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_limit_basics )
-{
- cout << "ANode:: ...test_limit_basics \n";
-
- {
- Limit empty;
- Limit empty2;
- BOOST_CHECK_MESSAGE(empty == empty2,"Equality failed");
-
- Limit l1("name",2);
- Limit l2("name",2);
- BOOST_CHECK_MESSAGE(l1 == l2,"Equality failed");
-
- Limit l3("name",2);
- Limit l4("name",4);
- BOOST_CHECK_MESSAGE(!(l3 == l4),"Equality failed");
- }
-
- std::set<std::string> expected_empty_paths;
- std::set<std::string> expected_paths;
-
- Limit l1("name",100);
- for(int i = 1; i < 10; i++) {
- std::string path = boost::lexical_cast<std::string>(i);
- expected_paths.insert(path);
- l1.increment(1,path);
- BOOST_CHECK_MESSAGE(l1.paths() == expected_paths,"Expected paths not the same at " << i);
- }
-
- for(int i = 9; i >= 1; i--) {
- std::string path = boost::lexical_cast<std::string>(i);
- l1.decrement(1,path);
- std::set<std::string>::iterator iter = expected_paths.find(path); expected_paths.erase(iter);
-
- if (l1.paths() != expected_paths) {
- std::cout << " Expected:";
- std::copy (expected_paths.begin(), expected_paths.end(), std::ostream_iterator <std::string> (std::cout, " "));
- std::cout << " Found:";
- std::copy (l1.paths().begin(), l1.paths().end(), std::ostream_iterator <std::string> (std::cout, " "));
- }
- BOOST_CHECK_MESSAGE(l1.paths() == expected_paths,"Expected paths not the same at " << i);
- }
-
- expected_paths.insert("/a/b/c");
- l1.increment(1,"/a/b/c");
- BOOST_CHECK_MESSAGE(l1.paths() == expected_paths,"Expected paths not the same");
-
- l1.decrement(1,"/a/b/c");
- BOOST_CHECK_MESSAGE(l1.paths() == expected_empty_paths,"Expected paths not the same");
-}
-
-
-BOOST_AUTO_TEST_CASE( test_limit_increment )
-{
- cout << "ANode:: ...test_limit_increment\n";
-
- Limit limit("name",10); // Limit of 10
- limit.increment(1,"path"); // consume 1 token
-
- BOOST_CHECK_MESSAGE(limit.value() == 1,"Expected increment to consume 1 token but it has consumed " << limit.value());
- BOOST_CHECK_MESSAGE(limit.paths().size() == 1,"Expected 1 task path but found " << limit.paths().size());
-
- limit.increment(1,"path"); // Increment with same path, should *NOT* consume a token
-
- BOOST_CHECK_MESSAGE(limit.value() == 1,"Expected 1 token but it has consumed " << limit.value());
- BOOST_CHECK_MESSAGE(limit.paths().size() == 1,"Expected 1 task path but found " << limit.paths().size());
-}
-
-BOOST_AUTO_TEST_CASE( test_limit_decrement )
-{
- cout << "ANode:: ...test_limit_decrement\n";
-
- Ecf::set_server(true); // needed to test state_change_numbers
-
- Limit limit("name",10); // Limit of 10
- unsigned int expected_state_change_no = limit.state_change_no();
-
- limit.increment(1,"path"); expected_state_change_no++; // consume 1 token, should increment state change no
- BOOST_CHECK_MESSAGE(limit.value() == 1,"Expected limit of value 1 but found " << limit.value());
- BOOST_CHECK_MESSAGE(limit.paths().size() == 1,"Expected 1 task path but found " << limit.paths().size());
- BOOST_CHECK_MESSAGE( limit.state_change_no() == expected_state_change_no,"Expected increment to increase state change no, expected " << expected_state_change_no << " but found " << limit.state_change_no());
-
- // Since 'path_x' is NOT in the list of paths stored by the limit, there should be NO change to state_change_no
- limit.decrement(1,"path_x");
- BOOST_CHECK_MESSAGE(limit.value() == 1," decrement of path that does not exist, should not affect the Limit: Expected limit of value 1 but found " << limit.value());
- BOOST_CHECK_MESSAGE(limit.paths().size() == 1," decrement of path that does not exist, should not affect the Limit : Expected 1 task path but found " << limit.paths().size());
- BOOST_CHECK_MESSAGE( limit.state_change_no() == expected_state_change_no,"Expected no change in state change no, expected " << expected_state_change_no << " but found " << limit.state_change_no());
-
- // Multiple decrements should leave Limit of value = 0, and not a negative number
- limit.decrement(1,"path"); expected_state_change_no++;
- BOOST_CHECK_MESSAGE( limit.state_change_no() == expected_state_change_no,"Expected decrement to increase state change no, expected " << expected_state_change_no << " but found " << limit.state_change_no());
-
- // Since we have removed 'path' from the limit expect no further state changes
- limit.decrement(1,"path");
- limit.decrement(1,"path");
- limit.decrement(1,"path");
- BOOST_CHECK_MESSAGE(limit.value() == 0,"Expected limit of value 0 but found " << limit.value());
- BOOST_CHECK_MESSAGE(limit.paths().size() == 0,"Expected no task paths but found " << limit.paths().size());
- BOOST_CHECK_MESSAGE( limit.state_change_no() == expected_state_change_no,"Expected no change to state change no, expected " << expected_state_change_no << " but found " << limit.state_change_no());
-
- Ecf::set_server(false); // needed to test state_change_numbers
-}
-
-
-// Globals used throughout the test
-static std::string fileName = "testLimit.txt";
-BOOST_AUTO_TEST_CASE( test_LimitDefaultConstructor_serialisation )
-{
- cout << "ANode:: ...test_LimitDefaultConstructor_serialisation \n";
-
- doSaveAndRestore<Limit>(fileName);
-}
-
-BOOST_AUTO_TEST_CASE( test_Limit_serialisation )
-{
- cout << "ANode:: ...test_Limit_serialisation\n";
- Limit saved1("limitName",100 );
- doSaveAndRestore(fileName,saved1);
-
- std::set<std::string> paths; paths.insert("path1"); paths.insert("path2");
- Limit saved2("limitName",100,10,paths );
- doSaveAndRestore(fileName,saved2);
-}
-
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/ANode/test/TestMigration.cpp b/ecflow_4_0_7/ANode/test/TestMigration.cpp
deleted file mode 100644
index 89179d7..0000000
--- a/ecflow_4_0_7/ANode/test/TestMigration.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-#if defined(TEXT_ARCHIVE) || !defined(BINARY_ARCHIVE) && !defined(PORTABLE_BINARY_ARCHIVE) && !defined(EOS_PORTABLE_BINARY_ARCHIVE)
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/test/unit_test.hpp>
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "Alias.hpp"
-#include "Ecf.hpp"
-#include "SerializationTest.hpp"
-#include "MyDefsFixture.hpp"
-#include "File.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost::posix_time;
-using namespace boost::gregorian;
-namespace fs = boost::filesystem;
-
-// If you are updating the tests, *MAKE SURE* to check out test/data/migration/* files
-//#define UPDATE_TESTS 1
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-//
-// These test are used for future release. They help to ensure that we have
-// backward compatibility.i.e future release can open file, created by an earlier release
-//
-BOOST_AUTO_TEST_CASE( test_migration_restore_def_con_3_0_1 )
-{
- cout << "ANode:: ...test_migration_restore_def_con_3_0_1\n";
-
- std::string file_name = File::test_data("ANode/test/data/migration/default_constructor/","ANode");
-
- // Create migration data
- Defs defs;
- Suite suite;
- Family family;
- Task task;
-
- // Remove host dependent variables from server state, so that we can run on other platforms
- defs.set_server().delete_server_variable("ECF_LOG");
- defs.set_server().delete_server_variable("ECF_CHECK");
- defs.set_server().delete_server_variable("ECF_CHECKOLD");
-
- // We use .def extension so that we copy over writable files with extension .def to
- // other platforms during incremental build's
-#ifdef UPDATE_TESTS
- // remember to check out data
- doSave(file_name + "Defs.def",defs);
- doSave(file_name + "Suite.def",suite);
- doSave(file_name + "Family.def",family);
- doSave(file_name + "Task.def",task);
- doSave(file_name + "Limit.def",Limit());
-#else
- Ecf::set_debug_equality(true);
- do_restore<Defs>(file_name + "Defs.def",defs);
- do_restore<Suite>(file_name + "Suite.def",suite);
- do_restore<Family>(file_name + "Family.def",family);
- do_restore<Task>(file_name + "Task.def",task);
- do_restore<Limit>(file_name + "Limit.def",Limit());
- Ecf::set_debug_equality(false);
-#endif
-}
-
-//#define UPDATE_TESTS 1
-
-BOOST_AUTO_TEST_CASE( test_migration_restore_boost_1_47_checkpt_file )
-{
- cout << "ANode:: ...test_migration_restore_boost_1_47_checkpt_file\n";
-
- std::string file_name = File::test_data("ANode/test/data/migration/fixture/","ANode");
-
- // Create migration data
- // This will create a pre-built definition.
- // If the definition is changed we will need to update this test.
- // **Keep*** old checkpt test data, to ensure future ecflow versions can be migrated
- // **Update** here for future boost updates
- // **IF MyDefsFixture is changed, we need to ensure we can migrate it to future versions
- MyDefsFixture fixture("boost_1_47.checkpt");
-
- // Allow the test data, to be used on other platforms
- fixture.remove_host_depedent_server_variables();
-
-#ifdef UPDATE_TESTS
- // remember to check out data
- doSave(file_name + "boost_1_47.checkpt",fixture.fixtureDefsFile());
-#else
- Ecf::set_debug_equality(true);
- do_restore<Defs>(file_name + "boost_1_47.checkpt",fixture.fixtureDefsFile());
- Ecf::set_debug_equality(false);
-#endif
-}
-
-
-BOOST_AUTO_TEST_SUITE_END()
-
-#endif
diff --git a/ecflow_4_0_7/ANode/test/TestMissNextTimeSlot.cpp b/ecflow_4_0_7/ANode/test/TestMissNextTimeSlot.cpp
deleted file mode 100644
index dfc71f0..0000000
--- a/ecflow_4_0_7/ANode/test/TestMissNextTimeSlot.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #22 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <boost/test/unit_test.hpp>
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Task.hpp"
-
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_miss_next_time_slot )
-{
- cout << "ANode:: ...test_miss_next_time_slot\n";
-
- // Start TIME at 9:30
- // This test is custom. When the user interactively forces a node to the complete state,
- // But where the user set of time slots. In this case the node should complete and then
- // requee and miss the next time. If this is repeated, eventually we should reach the
- // end of the time slot. In which case the node should *not* re-queue and stay complete
- //
- // When the node is then re-queued check that the time has been correctly reset.
-
- // suite s1
- // task t1
- // time 10:00
- // time 11:00
- // time 12:00
- // time 13:00
- // endsuite
- Defs the_defs;
- suite_ptr suite = the_defs.add_suite("s1");
- task_ptr t1 = suite->add_task("t1");
- t1->addTime( TimeAttr(10,0) );
- t1->addTime( TimeAttr(11,0) );
- t1->addTime( TimeAttr(12,0) );
- t1->addTime( TimeAttr(13,0) );
- ClockAttr clockAttr(15,12,2010,false);
- clockAttr.set_gain(9/*hour*/,30/*minutes*/); // *start* at 9:30
- suite->addClock( clockAttr );
-
- suite->begin();
-
- // get all the time attributes
- const TimeSeries& ts_10 = t1->timeVec()[0].time_series();
- const TimeSeries& ts_11 = t1->timeVec()[1].time_series();
- const TimeSeries& ts_12 = t1->timeVec()[2].time_series();
- const TimeSeries& ts_13 = t1->timeVec()[3].time_series();
- BOOST_CHECK_MESSAGE( ts_10.is_valid(), "Expected time 10 to be valid since we started at 9:30 ");
- BOOST_CHECK_MESSAGE( ts_11.is_valid(), "Expected time 11 to be valid since we started at 9:30");
- BOOST_CHECK_MESSAGE( ts_12.is_valid(), "Expected time 12 to be valid since we started at 9:30");
- BOOST_CHECK_MESSAGE( ts_13.is_valid(), "Expected time 13 to be valid since we started at 9:30");
-
- const TimeSlot& time_10 = t1->timeVec()[0].time_series().get_next_time_slot();
- const TimeSlot& time_11 = t1->timeVec()[1].time_series().get_next_time_slot();
- const TimeSlot& time_12 = t1->timeVec()[2].time_series().get_next_time_slot();
- const TimeSlot& time_13 = t1->timeVec()[3].time_series().get_next_time_slot();
- BOOST_CHECK_MESSAGE( time_10 == TimeSlot(10,0),"Expected next time slot of 10:00 but found " << time_10.toString());
- BOOST_CHECK_MESSAGE( time_11 == TimeSlot(11,0),"Expected next time slot of 11:00 but found " << time_11.toString());
- BOOST_CHECK_MESSAGE( time_12 == TimeSlot(12,0),"Expected next time slot of 12:00 but found " << time_12.toString());
- BOOST_CHECK_MESSAGE( time_13 == TimeSlot(13,0),"Expected next time slot of 13:00 but found " << time_13.toString());
-
- // before test flags should be clear
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear,before test");
-
- t1->miss_next_time_slot();
- BOOST_CHECK_MESSAGE(t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be set,");
- BOOST_CHECK_MESSAGE( !ts_10.is_valid(), "Expected time 10 to be expired");
- BOOST_CHECK_MESSAGE( ts_11.is_valid(), "Expected time 11 to be valid since we started at 9:30");
- BOOST_CHECK_MESSAGE( ts_12.is_valid(), "Expected time 12 to be valid since we started at 9:30");
- BOOST_CHECK_MESSAGE( ts_13.is_valid(), "Expected time 13 to be valid since we started at 9:30");
-
- // Calling miss_next_time_slot again, should have *NO* effect, since its only takes affect when NO_REQUE_IF_SINGLE_TIME_DEP is clear
- t1->miss_next_time_slot();
- BOOST_CHECK_MESSAGE(t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be set,");
- BOOST_CHECK_MESSAGE( !ts_10.is_valid(), "Expected time 10 to be expired");
- BOOST_CHECK_MESSAGE( ts_11.is_valid(), "Expected time 11 to be valid since we started at 9:30");
- BOOST_CHECK_MESSAGE( ts_12.is_valid(), "Expected time 12 to be valid since we started at 9:30");
- BOOST_CHECK_MESSAGE( ts_13.is_valid(), "Expected time 13 to be valid since we started at 9:30");
-
- // Clear the flag and call miss_next_time_slot, this time an additional time slot should have expired
- t1->flag().clear(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP);
- t1->miss_next_time_slot();
- BOOST_CHECK_MESSAGE( !ts_10.is_valid(), "Expected time 10 to be expired");
- BOOST_CHECK_MESSAGE( !ts_11.is_valid(), "Expected time 11 to be expired");
- BOOST_CHECK_MESSAGE( ts_12.is_valid(), "Expected time 12 to be valid since we started at 9:30");
- BOOST_CHECK_MESSAGE( ts_13.is_valid(), "Expected time 13 to be valid since we started at 9:30");
-
- // call twice more, to expire all time slots
- t1->flag().clear(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP);
- t1->miss_next_time_slot();
- t1->flag().clear(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP);
- t1->miss_next_time_slot();
- BOOST_CHECK_MESSAGE( !ts_10.is_valid(), "Expected time 10 to be expired");
- BOOST_CHECK_MESSAGE( !ts_11.is_valid(), "Expected time 11 to be expired");
- BOOST_CHECK_MESSAGE( !ts_12.is_valid(), "Expected time 12 to be expired");
- BOOST_CHECK_MESSAGE( !ts_13.is_valid(), "Expected time 13 to be expired");
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ANode/test/TestNodeBeginReque.cpp b/ecflow_4_0_7/ANode/test/TestNodeBeginReque.cpp
deleted file mode 100644
index aaaf02d..0000000
--- a/ecflow_4_0_7/ANode/test/TestNodeBeginReque.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #22 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <boost/test/unit_test.hpp>
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_node_begin_reque_hybrid )
-{
- cout << "ANode:: ...test_node_begin_reque_hybrid\n";
-
- // Create a suite with a *HYBRID* clock, and tasks with day,date and cron time attributes
- defs_ptr the_defs = Defs::create();
- suite_ptr s1 = the_defs->add_suite( "s1" ) ;
- s1->addClock( ClockAttr(true) );
- family_ptr f1 = s1->add_family( "f1" ) ;
-
- CronAttr cron;
- std::vector<int> week_days; week_days.push_back(0); week_days.push_back(1);
- cron.addWeekDays(week_days);
- cron.add_time_series(10,10,true);
-
- // For task t1 which has day attribute. For this test to succeed the day must not match today day.
- // So that under the hybrid clock, its is set to complete
- boost::gregorian::date todays_date = Calendar::second_clock_time().date();
- int todays_day_as_number = todays_date.day_of_week().as_number();
- int tommorrow = todays_day_as_number + 1;
- if (tommorrow > 6) tommorrow = 0;
-
- task_ptr t1 = f1->add_task("t1"); t1->addDay( DayAttr( DayAttr::Day_t(tommorrow) ));
- task_ptr t2 = f1->add_task("t2"); t2->addDate( DateAttr(0,0,2014));
- task_ptr t3 = f1->add_task("t3"); t3->addCron( cron );
-
- // begin the suite, Under hybrid clock, nodes with day,date and cron attributes should be marked as complete
- the_defs->beginAll();
- BOOST_CHECK_MESSAGE(t1->state() == NState::COMPLETE,"Expected node to be complete");
- BOOST_CHECK_MESSAGE(t2->state() == NState::COMPLETE,"Expected node to be complete");
- BOOST_CHECK_MESSAGE(t3->state() == NState::COMPLETE,"Expected node to be complete");
-
- // Change the node state, so that we can test re-queue
- t1->set_state(NState::QUEUED);
- t2->set_state(NState::QUEUED);
- t3->set_state(NState::QUEUED);
- BOOST_CHECK_MESSAGE(t1->state() == NState::QUEUED,"Expected node to be QUEUED");
- BOOST_CHECK_MESSAGE(t2->state() == NState::QUEUED,"Expected node to be QUEUED");
- BOOST_CHECK_MESSAGE(t3->state() == NState::QUEUED,"Expected node to be QUEUED");
-
- // Now re-queue all and make sure re-queue also Under hybrid clock, nodes with day,date and cron
- // attributes should be marked as complete
- the_defs->requeue();
- BOOST_CHECK_MESSAGE(t1->state() == NState::COMPLETE,"Expected node to be complete");
- BOOST_CHECK_MESSAGE(t2->state() == NState::COMPLETE,"Expected node to be complete");
- BOOST_CHECK_MESSAGE(t3->state() == NState::COMPLETE,"Expected node to be complete");
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ANode/test/TestOrder.cpp b/ecflow_4_0_7/ANode/test/TestOrder.cpp
deleted file mode 100644
index a5d7dc8..0000000
--- a/ecflow_4_0_7/ANode/test/TestOrder.cpp
+++ /dev/null
@@ -1,336 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/test/unit_test.hpp>
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-template <typename T>
-static std::vector<std::string> toStrVec(const std::vector<T>& vec)
-{
- std::vector<std::string> retVec; retVec.reserve(vec.size());
- BOOST_FOREACH(T s, vec) { retVec.push_back(s->name()); }
- return retVec;
-}
-
-std::string toString(const std::vector<std::string>& c)
-{
- std::stringstream ss;
- std::copy (c.begin(), c.end(), std::ostream_iterator <std::string> (ss, ", "));
- return ss.str();
-}
-
-static void test_invariants(Defs& the_defs, int line) {
- std::string errorMsg;
- bool passed = the_defs.checkInvariants(errorMsg);
- BOOST_REQUIRE_MESSAGE( passed,"Invariants failed " << errorMsg << " at line " << line);
-}
-
-
-BOOST_AUTO_TEST_CASE( test_order )
-{
- cout << "ANode:: ...test_order\n" ;
- std::vector<std::string> vec; vec.reserve(5);
- vec.push_back("a");
- vec.push_back("A");
- vec.push_back("b");
- vec.push_back("B");
- vec.push_back("c");
- Defs theDefs; {
- for(size_t s = 0; s < vec.size(); s++) {
- suite_ptr suite = theDefs.add_suite( vec[s] ) ;
- for(size_t f = 0; f < vec.size(); f++) {
- family_ptr fam = suite->add_family( vec[f] ) ;
- for(size_t t = 0; t < vec.size(); t++) {
- fam->add_task( vec[t] );
- }
- }
- }
- }
-
- std::vector<std::string> alpha;
- alpha.push_back("a");
- alpha.push_back("A");
- alpha.push_back("b");
- alpha.push_back("B");
- alpha.push_back("c");
-
- std::vector<std::string> order;
- order.push_back("c");
- order.push_back("B");
- order.push_back("b");
- order.push_back("A");
- order.push_back("a");
-
- // Test suite ordering ==========================================================================
- // In init state all suite should be in alpha order
- theDefs.order(theDefs.findAbsNode("/A").get(), NOrder::ALPHA);
- test_invariants(theDefs,__LINE__);
- BOOST_REQUIRE_MESSAGE( toStrVec(theDefs.suiteVec()) == alpha,"NOrder::ALPHA expected " << toString(alpha) << " but found " << toString(toStrVec(theDefs.suiteVec())) );
-
- // sort in reverse order
- theDefs.order(theDefs.findAbsNode("/a").get(), NOrder::ORDER);
- test_invariants(theDefs,__LINE__);
- BOOST_REQUIRE_MESSAGE( toStrVec(theDefs.suiteVec()) == order,"NOrder::ORDER expected " << toString(order) << " but found " << toString(toStrVec(theDefs.suiteVec())) );
-
- // Change back to alpha, then move suite 'c' to the top
- theDefs.order(theDefs.findAbsNode("/A").get(), NOrder::ALPHA);
- BOOST_REQUIRE_MESSAGE( toStrVec(theDefs.suiteVec()) == alpha,"NOrder::ALPHA expected " << toString(alpha) << " but found " << toString(toStrVec(theDefs.suiteVec())) );
- test_invariants(theDefs,__LINE__);
-
- std::vector<std::string> expected;
- expected.push_back("c");
- expected.push_back("a");
- expected.push_back("A");
- expected.push_back("b");
- expected.push_back("B");
- theDefs.order(theDefs.findAbsNode("/c").get(), NOrder::TOP);
- test_invariants(theDefs,__LINE__);
- BOOST_REQUIRE_MESSAGE( toStrVec(theDefs.suiteVec()) == expected,"NOrder::TOP expected " << toString(expected) << " but found " << toString(toStrVec(theDefs.suiteVec())) );
-
- // move suite 'c' back to the bottom
- theDefs.order(theDefs.findAbsNode("/c").get(), NOrder::BOTTOM);
- test_invariants(theDefs,__LINE__);
- BOOST_REQUIRE_MESSAGE( toStrVec(theDefs.suiteVec()) == alpha,"NOrder::BOTTOM order not as expected" );
-
- // move suite 'a' up one place. Should be no change, since its already at the top
- theDefs.order(theDefs.findAbsNode("/a").get(), NOrder::UP);
- test_invariants(theDefs,__LINE__);
- BOOST_REQUIRE_MESSAGE( toStrVec(theDefs.suiteVec()) == alpha,"NOrder::UP order not as expected" );
-
- // move suite 'c' down one place. Should be no change, since its already at the bottom
- theDefs.order(theDefs.findAbsNode("/c").get(), NOrder::DOWN);
- test_invariants(theDefs,__LINE__);
- BOOST_REQUIRE_MESSAGE( toStrVec(theDefs.suiteVec()) == alpha,"NOrder::DOWN order not as expected" );
-
- // Move suite 'a' down by one place
- expected.clear();
- expected.push_back("A");
- expected.push_back("a");
- expected.push_back("b");
- expected.push_back("B");
- expected.push_back("c");
- theDefs.order(theDefs.findAbsNode("/a").get(), NOrder::DOWN);
- test_invariants(theDefs,__LINE__);
- BOOST_REQUIRE_MESSAGE( toStrVec(theDefs.suiteVec()) == expected,"NOrder::DOWN order not as expected" );
-
- // Move suite 'b' up by one place
- expected.clear();
- expected.push_back("A");
- expected.push_back("b");
- expected.push_back("a");
- expected.push_back("B");
- expected.push_back("c");
- theDefs.order(theDefs.findAbsNode("/b").get(), NOrder::UP);
- test_invariants(theDefs,__LINE__);
- BOOST_REQUIRE_MESSAGE( toStrVec(theDefs.suiteVec()) == expected,"NOrder::UP order not as expected" );
-
-
- // Test family ordering ==========================================================================
- // In init state all suite should be in alpha order
- suite_ptr suite = theDefs.findSuite("a");
- BOOST_REQUIRE_MESSAGE( suite.get() ,"Expected suite /a to exist " );
-
- theDefs.order(theDefs.findAbsNode("/a/a").get(), NOrder::ALPHA);
- test_invariants(theDefs,__LINE__);
- BOOST_REQUIRE_MESSAGE( toStrVec(suite->nodeVec()) == alpha,"NOrder::ALPHA Init order " << toString(toStrVec(suite->nodeVec())) << " not as expected " << toString(alpha));
-
- // sort in reverse order
- std::sort(expected.begin(),expected.end(),std::greater<std::string>());
- suite->order(theDefs.findAbsNode("/a/a").get(), NOrder::ORDER);
- test_invariants(theDefs,__LINE__);
- BOOST_REQUIRE_MESSAGE( toStrVec(suite->nodeVec()) == order,"NOrder::ORDER order " << toString(toStrVec(suite->nodeVec())) << " not as expected " << toString(order));
-
- // Change back to alpha, then move family 'e' to the top
- suite->order(theDefs.findAbsNode("/a/a").get(), NOrder::ALPHA);
- BOOST_REQUIRE_MESSAGE( toStrVec(suite->nodeVec()) == alpha,"NOrder::ALPHA expected " << toString(alpha) << " but found " << toString(toStrVec(suite->nodeVec())) );
- test_invariants(theDefs,__LINE__);
- expected.clear();
- expected.push_back("c");
- expected.push_back("a");
- expected.push_back("A");
- expected.push_back("b");
- expected.push_back("B");
- suite->order(theDefs.findAbsNode("/a/c").get(), NOrder::TOP);
- BOOST_REQUIRE_MESSAGE( toStrVec(suite->nodeVec()) == expected,"NOrder::TOP order " << toString(toStrVec(suite->nodeVec())) << " not as expected " << toString(expected));
-
- // move family 'c' back to the bottom
- suite->order(theDefs.findAbsNode("/a/c").get(), NOrder::BOTTOM);
- test_invariants(theDefs,__LINE__);
- BOOST_REQUIRE_MESSAGE( toStrVec(suite->nodeVec()) == alpha,"NOrder::BOTTOM order " << toString(toStrVec(suite->nodeVec())) << " not as expected " << toString(alpha));
-
- // move family 'a' up one place. Should be no change, since its already at the top
- suite->order(theDefs.findAbsNode("/a/a").get(), NOrder::UP);
- test_invariants(theDefs,__LINE__);
- BOOST_REQUIRE_MESSAGE( toStrVec(suite->nodeVec()) == alpha,"NOrder::UP order " << toString(toStrVec(suite->nodeVec())) << " not as expected " << toString(alpha));
-
- // move family 'c' down one place. Should be no change, since its already at the bottom
- suite->order(theDefs.findAbsNode("/a/c").get(), NOrder::DOWN);
- test_invariants(theDefs,__LINE__);
- BOOST_REQUIRE_MESSAGE( toStrVec(suite->nodeVec()) == alpha,"NOrder::DOWN order " << toString(toStrVec(suite->nodeVec())) << " not as expected " << toString(alpha));
-
- // Move family 'a' down by one place
- expected.clear();
- expected.push_back("A");
- expected.push_back("a");
- expected.push_back("b");
- expected.push_back("B");
- expected.push_back("c");
- suite->order(theDefs.findAbsNode("/a/a").get(), NOrder::DOWN);
- test_invariants(theDefs,__LINE__);
- BOOST_REQUIRE_MESSAGE( toStrVec(suite->nodeVec()) == expected,"NOrder::DOWN order " << toString(toStrVec(suite->nodeVec())) << " not as expected " << toString(expected));
-
- // Move family 'b' up by one place
- suite->order(theDefs.findAbsNode("/a/a").get(), NOrder::ALPHA); // reset
- test_invariants(theDefs,__LINE__);
- expected.clear();
- expected.push_back("a");
- expected.push_back("b");
- expected.push_back("A");
- expected.push_back("B");
- expected.push_back("c");
- suite->order(theDefs.findAbsNode("/a/b").get(), NOrder::UP);
- BOOST_REQUIRE_MESSAGE( toStrVec(suite->nodeVec()) == expected,"NOrder::UP order " << toString(toStrVec(suite->nodeVec())) << " not as expected " << toString(expected));
-
-
- // Test Task ordering ==========================================================================
- // In init state all tasks should be in alpha order
- Family* family = theDefs.findAbsNode("/a/a")->isFamily();
- BOOST_REQUIRE_MESSAGE( family ,"Expected family /a/a to exist " );
-
- family->order(theDefs.findAbsNode("/a/a/a").get(), NOrder::ALPHA);
- test_invariants(theDefs,__LINE__);
- BOOST_REQUIRE_MESSAGE( toStrVec(family->nodeVec()) == alpha,"NOrder::ALPHA Init state " << toString(toStrVec(family->nodeVec())) << " not as expected " << toString(alpha));
-
- // sort in reverse order
- family->order(theDefs.findAbsNode("/a/a/a").get(), NOrder::ORDER);
- test_invariants(theDefs,__LINE__);
- BOOST_REQUIRE_MESSAGE( toStrVec(family->nodeVec()) == order,"NOrder::ORDER " << toString(toStrVec(family->nodeVec())) << " not as expected " << toString(order));
-
- // Change back to alpha, then move task 'c' to the top
- family->order(theDefs.findAbsNode("/a/a/a").get(), NOrder::ALPHA); // reset
- expected.clear();
- expected.push_back("c");
- expected.push_back("a");
- expected.push_back("A");
- expected.push_back("b");
- expected.push_back("B");
- family->order(theDefs.findAbsNode("/a/a/c").get(), NOrder::TOP);
- test_invariants(theDefs,__LINE__);
- BOOST_REQUIRE_MESSAGE( toStrVec(family->nodeVec()) == expected,"NOrder::TOP order " << toString(toStrVec(family->nodeVec())) << " not as expected " << toString(expected));
-
- // move task 'c' back to the bottom
- family->order(theDefs.findAbsNode("/a/a/c").get(), NOrder::BOTTOM);
- test_invariants(theDefs,__LINE__);
- BOOST_REQUIRE_MESSAGE( toStrVec(family->nodeVec()) == alpha,"NOrder::BOTTOM order " << toString(toStrVec(family->nodeVec())) << " not as expected " << toString(alpha));
-
- // move task 'a' up one place. Should be no change, since its already at the top
- family->order(theDefs.findAbsNode("/a/a/a").get(), NOrder::UP);
- test_invariants(theDefs,__LINE__);
- BOOST_REQUIRE_MESSAGE( toStrVec(family->nodeVec()) == alpha,"NOrder::UP order " << toString(toStrVec(family->nodeVec())) << " not as expected " << toString(alpha));
-
- // move task 'e' down one place. Should be no change, since its already at the bottom
- family->order(theDefs.findAbsNode("/a/a/c").get(), NOrder::DOWN);
- test_invariants(theDefs,__LINE__);
- BOOST_REQUIRE_MESSAGE( toStrVec(family->nodeVec()) == alpha,"NOrder::DOWN order " << toString(toStrVec(family->nodeVec())) << " not as expected " << toString(alpha));
-
- // Move task 'a' down by one place
- expected.clear();
- expected.push_back("A");
- expected.push_back("a");
- expected.push_back("b");
- expected.push_back("B");
- expected.push_back("c");
- family->order(theDefs.findAbsNode("/a/a/a").get(), NOrder::DOWN);
- test_invariants(theDefs,__LINE__);
- BOOST_REQUIRE_MESSAGE( toStrVec(family->nodeVec()) == expected,"NOrder::DOWN order " << toString(toStrVec(family->nodeVec())) << " not as expected " << toString(expected));
-
- // Move task 'b' up by one place
- family->order(theDefs.findAbsNode("/a/a/b").get(), NOrder::DOWN);
- expected.clear();
- expected.push_back("A");
- expected.push_back("a");
- expected.push_back("B");
- expected.push_back("b");
- expected.push_back("c");
- test_invariants(theDefs,__LINE__);
- BOOST_REQUIRE_MESSAGE( toStrVec(family->nodeVec()) == expected,"NOrder::UP order " << toString(toStrVec(family->nodeVec())) << " not as expected " << toString(expected));
-}
-
-BOOST_AUTO_TEST_CASE( test_alias_order )
-{
- cout << "ANode:: ...test_alias_order\n" ;
- task_ptr task;
- Defs theDefs; {
- suite_ptr s = theDefs.add_suite("s");
- task = s->add_task("t");
- task->add_alias_only(); // alias0
- task->add_alias_only(); // alias1
- task->add_alias_only(); // alias2
- task->add_alias_only(); // alias3
- }
-
- // Test alias ordering ==========================================================================
- // In init state all suite should be in alpha order
- alias_ptr alias0 = task->find_alias("alias0");
- BOOST_REQUIRE_MESSAGE( alias0,"expected to find alias0");
-
- std::vector<std::string> expected;
- expected.push_back("alias1");
- expected.push_back("alias0");
- expected.push_back("alias2");
- expected.push_back("alias3");
- task->order(alias0.get(), NOrder::DOWN);
- test_invariants(theDefs,__LINE__);
- BOOST_REQUIRE_MESSAGE( toStrVec(task->aliases()) == expected,"NOrder::DOWN expected " << toString(expected) << " but found " << toString(toStrVec(task->aliases())) );
-
-
- task->order(alias0.get(), NOrder::ALPHA);
- test_invariants(theDefs,__LINE__);
- expected.clear();
- expected.push_back("alias0");
- expected.push_back("alias1");
- expected.push_back("alias2");
- expected.push_back("alias3");
- BOOST_REQUIRE_MESSAGE( toStrVec(task->aliases()) == expected,"NOrder::ALPHA expectex " << toString(expected) << " but found " << toString(toStrVec(task->aliases())) );
-
-
- task->order(task->find_alias("alias3").get(), NOrder::UP);
- test_invariants(theDefs,__LINE__);
- expected.clear();
- expected.push_back("alias0");
- expected.push_back("alias1");
- expected.push_back("alias3");
- expected.push_back("alias2");
- BOOST_REQUIRE_MESSAGE( toStrVec(task->aliases()) == expected,"NOrder::UP expected " << toString(expected) << " but found " << toString(toStrVec(task->aliases())) );
-
- // sort in reverse order
- std::sort(expected.begin(),expected.end(),std::greater<std::string>());
- task->order(alias0.get(), NOrder::ORDER);
- test_invariants(theDefs,__LINE__);
- expected.clear();
- expected.push_back("alias3");
- expected.push_back("alias2");
- expected.push_back("alias1");
- expected.push_back("alias0");
- BOOST_REQUIRE_MESSAGE( toStrVec(task->aliases()) == expected,"NOrder::ORDER expected " << toString(expected) << " but found " << toString(toStrVec(task->aliases())) );
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ANode/test/TestPersistence.cpp b/ecflow_4_0_7/ANode/test/TestPersistence.cpp
deleted file mode 100644
index 2ae72be..0000000
--- a/ecflow_4_0_7/ANode/test/TestPersistence.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-
-#include "MyDefsFixture.hpp"
-
-using namespace std;
-using namespace ecf;
-namespace fs = boost::filesystem;
-
-BOOST_FIXTURE_TEST_SUITE( NodeTestSuite, MyDefsFixture )
-
-// Allow for multiple archives
-static void testPersistence(const Defs& fixtureDefs,ecf::Archive::Type at)
-{
- std::string check_pt_file = "fixture_defs.check";
- fixtureDefs.save_as_checkpt(check_pt_file,at);
-
- Defs restoredDefs;
- restoredDefs.restore_from_checkpt(check_pt_file,at);
-
- bool theyCompare = (restoredDefs == fixtureDefs);
- if (!theyCompare) {
-
- std::cout << "Dump restored defs\n" << restoredDefs << "\n";
- std::cout << "Dump fixture defs\n" << fixtureDefs << "\n";
-
- BOOST_CHECK_MESSAGE(theyCompare,"restored defs file is not same as fixtureDefs defs file");
- }
-
- cout << " check pt file_size: " << fs::file_size(check_pt_file) << "\n";
-
- // Uncomment if you want see what this file looks like
- fs::remove(check_pt_file);
-}
-
-#if defined(BINARY_ARCHIVE)
-BOOST_AUTO_TEST_CASE( test_node_tree_persistence_binary )
-{
- cout << left << setw(54) << "ANode:: ...test_node_tree_persistence_binary";
- BOOST_CHECK_MESSAGE(true,""); // stop boost complaining about no assertions
- testPersistence(fixtureDefsFile(),ecf::Archive::BINARY);
-}
-#elif defined(PORTABLE_BINARY_ARCHIVE)
-BOOST_AUTO_TEST_CASE( test_node_tree_persistence_portable_binary )
-{
- cout << left << setw(54) << "ANode:: ...test_node_tree_persistence_portable_binary";
- BOOST_CHECK_MESSAGE(true,""); // stop boost complaining about no assertions
- testPersistence(fixtureDefsFile(),ecf::Archive::PORTABLE_BINARY);
-}
-#elif defined(EOS_PORTABLE_BINARY_ARCHIVE)
-BOOST_AUTO_TEST_CASE( test_node_tree_persistence_eos_portable_binary )
-{
- cout << left << setw(54) << "ANode:: ...test_node_tree_persistence_eos_portable_binary";
- BOOST_CHECK_MESSAGE(true,""); // stop boost complaining about no assertions
- testPersistence(fixtureDefsFile(),ecf::Archive::EOS_PORTABLE_BINARY);
-}
-#else
-BOOST_AUTO_TEST_CASE( test_node_tree_persistence_text )
-{
- cout << left << setw(54) << "ANode:: ...test_node_tree_persistence_text" ;
- BOOST_CHECK_MESSAGE(true,""); // stop boost complaining about no assertions
- testPersistence(fixtureDefsFile(),ecf::Archive::TEXT);
-}
-#endif
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ANode/test/TestPreProcessing.cpp b/ecflow_4_0_7/ANode/test/TestPreProcessing.cpp
deleted file mode 100644
index 8b6c3bd..0000000
--- a/ecflow_4_0_7/ANode/test/TestPreProcessing.cpp
+++ /dev/null
@@ -1,232 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <iostream>
-#include <fstream>
-#include <stdlib.h>
-#include <set>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/test/unit_test.hpp>
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "EcfFile.hpp"
-#include "File.hpp"
-#include "JobsParam.hpp"
-#include "Str.hpp"
-#include "Ecf.hpp"
-#include "System.hpp"
-
-using namespace std;
-using namespace ecf;
-namespace fs = boost::filesystem;
-
-void findVariable(std::string& line, std::set<std::string>& variables)
-{
- // scan for variables
- // edit SMSFETCH "/home/ma/map/sms/smsfectch -F %ECF_FILES% -I %ECF_INCLUDE%"
- // We can also have
- //
- // "%<VAR>:<substitute>% i.e if VAR exist use it, else use substitute
- //
- // i.e VAR is defined as BILL
- // %VAR:fred --f% will either be "BILL" or if VAR is not defined "fred --f"
- while ( 1 ) {
- size_t firstPercentPos = line.find( Ecf::MICRO() );
- if ( firstPercentPos == string::npos ) break;
- size_t secondPercentPos = line.find( Ecf::MICRO(), firstPercentPos + 1 );
- if ( secondPercentPos == string::npos ) break;
- if ( secondPercentPos - firstPercentPos <= 1 ) break; // handle %% with no characters in between
-
- string percentVar( line.begin() + firstPercentPos+1, line.begin() + secondPercentPos );
-
- size_t firstColon = percentVar.find( ':' );
- if ( firstColon != string::npos ) {
- string var( percentVar.begin(), percentVar.begin() + firstColon );
- percentVar = var;
- }
-
- // Ignore auto-generated variables
- if ( percentVar.find("ECF_") == string::npos &&
- percentVar != "DATE" &&
- percentVar != "DAY" &&
- percentVar != "DD" &&
- percentVar != "DOW" &&
- percentVar != "DOY" &&
- percentVar != "MM" &&
- percentVar != "MONTH" &&
- percentVar != "YYYY" &&
- percentVar != "TASK" &&
- percentVar != "FAMILY" &&
- percentVar != "FAMILY1" &&
- percentVar != "SUITE"
- ) {
- variables.insert( percentVar );
- }
-
- //std::cerr << "line before delete " << line << "\n";
- line.erase(firstPercentPos, secondPercentPos - firstPercentPos + 1);
- //std::cerr << "line after delete " << line << "\n";
- }
-}
-
-void autoDiscoverVariables(const std::string& directory, std::set<std::string>& variables)
-{
- fs::path full_path( fs::initial_path<fs::path>() );
- full_path = fs::system_complete( fs::path( directory ) );
-
- BOOST_CHECK(fs::exists( full_path ));
- BOOST_CHECK(fs::is_directory( full_path ));
-
- //std::cout << "\nIn directory: " << full_path.directory_string() << "\n\n";
- fs::directory_iterator end_iter;
- for ( fs::directory_iterator dir_itr( full_path ); dir_itr != end_iter; ++dir_itr ) {
- try {
- fs::path relPath(directory + "/" + dir_itr->path().filename().string());
-
- // recurse down directories
- if ( fs::is_directory(dir_itr->status()) ) {
- autoDiscoverVariables(relPath.string(),variables);
- continue;
- }
- // std::cout << "......autoDiscoverVariables for file " << relPath.string() << "\n";
- if (relPath.extension() != ".h") continue; // Only look at .h files
-
- // open the file, and find variables.
- std::vector<std::string> lines;
- if ( File::splitFileIntoLines(relPath.string(), lines) ) {
- for(size_t i = 0; i < lines.size(); ++i) {
- findVariable(lines[i], variables);
- }
- }
- }
- catch ( const std::exception & ex ) {
- std::cout << "Exception::" << dir_itr->path().filename() << " " << ex.what() << std::endl;
- }
- }
-}
-
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-// *Auto* discover the good/bad sms files
-void test_sms_preprocessing(const std::string& directory, bool pass)
-{
-// cerr << " directory = " << directory << "\n";
-
- // SET ECF_HOME
- std::string smshome = directory;
-
- fs::path full_path( fs::initial_path<fs::path>() );
- full_path = fs::system_complete( fs::path( directory ) );
- BOOST_CHECK(fs::exists( full_path ));
- BOOST_CHECK(fs::is_directory( full_path ));
-
- // Create a defs file, where the task name mirrors the sms files in the given directory
- Defs theDefs;
- {
- suite_ptr suite = theDefs.add_suite("suite");
- suite->addVariable( Variable( Str::ECF_INCLUDE(), "$ECF_HOME/includes" ) );
- suite->addVariable( Variable( Str::ECF_OUT(), "$ECF_HOME" ) );
- suite->addVariable( Variable( "SLEEPTIME", "10" ) );
- family_ptr fam = suite->add_family( "family" );
-
- // for operations auto discover the variables used in the header files and give
- // them a dummy value. This would allow the test to pass when doing
- // variable substitution. hence if variable substitution fails its likely to be
- // a bug in autoDiscoverVariables
- std::set<std::string> discoveredVariables;
- autoDiscoverVariables(smshome + "/includes", discoveredVariables );
- BOOST_FOREACH(const string& var, discoveredVariables) {
-// cerr << "autoDiscoverVariables = " << var << "\n";
- suite->addVariable( Variable( var, "gobblygook" ) );
- }
-
- //std::cout << "\nIn directory: " << full_path.directory_string() << "\n\n";
- fs::directory_iterator end_iter;
- for (fs::directory_iterator dir_itr( full_path ); dir_itr != end_iter; ++dir_itr) {
- try {
- fs::path relPath( directory + "/" + dir_itr->path().filename().string());
-
- // Ignore directores were only interested in .ecf files.
- if (fs::is_directory(relPath)) continue;
- if (File::getExt(relPath.filename().string()) != "ecf" ) continue; // ignore other files
-
- //std::cout << "......Parsing file " << relPath.string() << "\n";
- //std::cout << "adding task name " << relPath.leaf() << "\n";
- fam->add_task( relPath.stem().string() );
- }
- catch ( const std::exception & ex ) {
- std::cout << "Exception " << dir_itr->path().filename() << " " << ex.what() << std::endl;
- }
- }
- //cerr << "The defs\n" << theDefs << "\n";
- }
-
- // get all the task
- std::vector<Task*> theTasks;
- theDefs.getAllTasks(theTasks);
-
- // Override ECF_HOME. ECF_HOME is need to locate to the ecf files
- theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(),smshome);
-
- /// begin , will cause creation of generated variables. The generated variables
- /// are used in client scripts(sms) and used to locate the sms files
- theDefs.beginAll();
-
- // Test Job creator, this will pre-process and perform variable substitution on sms files
- BOOST_FOREACH(Task* t, theTasks) {
-
- //cout << "task " << t->absNodePath() << "\n";
- JobsParam jobsParam; // create jobs = false, spawn_jobs = false
- bool ok = t-> submitJob( jobsParam ) ;
-
- if ( pass ) { // Test expected to pass
- BOOST_CHECK_MESSAGE(ok,"Failed to create jobs. " << jobsParam.getErrorMsg() );
- }
- else { // test expected to fail
- BOOST_CHECK_MESSAGE(!ok,"Expected failure " << jobsParam.getErrorMsg() );
- BOOST_CHECK_MESSAGE(!ok,"expected no passes but found " << t->absNodePath() << " passes");
- // cerr << "\n" << jobsParam.getErrorMsg() << " \n"; // un-comment to ensure correct error message
- }
- }
-}
-
-
-BOOST_AUTO_TEST_CASE( test_good_sms )
-{
- cout << "ANode:: ...test_good_ecf\n";
-
- std::string path = File::test_data("ANode/test/data/SMSHOME2/good","ANode");
-
- // All the sms in this directory are expected to pass
- test_sms_preprocessing(path, true);
-}
-
-BOOST_AUTO_TEST_CASE( test_bad_sms )
-{
- cout << "ANode:: ...test_bad_ecf\n";
-
- std::string path = File::test_data("ANode/test/data/SMSHOME2/bad","ANode");
-
- // All the sms in this directory are expected to fail
- test_sms_preprocessing(path, false);
-
- /// Destroy System singleton to avoid valgrind from complaining
- System::destroy();
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ANode/test/TestReplace.cpp b/ecflow_4_0_7/ANode/test/TestReplace.cpp
deleted file mode 100644
index 0b9a38c..0000000
--- a/ecflow_4_0_7/ANode/test/TestReplace.cpp
+++ /dev/null
@@ -1,575 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/make_shared.hpp>
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "Ecf.hpp"
-
-using namespace std;
-using namespace ecf;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_replace_add_task )
-{
- cout << "ANode:: ...test_replace_add_task\n" ;
- defs_ptr clientDef = Defs::create(); {
- suite_ptr suite = Suite::create( "suite1" ) ;
- family_ptr fam = suite->add_family("family" ) ;
- fam->add_task( "t2" );
- clientDef->addSuite( suite );
- }
-
- // add Child t2 to the server defs
- Defs serverDefs; {
- suite_ptr suite = Suite::create( "suite1" ) ;
- family_ptr fam = suite->add_family("family" ) ;
- fam->add_task( "t1" );
- serverDefs.addSuite( suite );
- }
-
- Defs expectedDefs; {
- suite_ptr suite = Suite::create( "suite1" ) ;
- family_ptr fam = suite->add_family("family" ) ;
- fam->add_task( "t2" ); // notice we preserve client position, and not server position
- fam->add_task( "t1" );
- expectedDefs.addSuite( suite );
- }
-
- std::string errorMsg;
- BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/suite1/family/t2",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
- BOOST_CHECK_MESSAGE(expectedDefs == serverDefs,"expectedDefs and servers defs should be the same");
-}
-
-BOOST_AUTO_TEST_CASE( test_replace_add_suite )
-{
- cout << "ANode:: ...test_replace_add_suite\n";
- // In this test the server defs is *EMPTY* hence we should copy/move over the whole suite
- // provided the a/ Path to node exists in the client def, b/ create nodes as needed is TRUE
- Defs expectedDefs; {
- suite_ptr suite = expectedDefs.add_suite( "suite1" ) ;
- family_ptr fam = suite->add_family("family" ) ;
- fam->add_task( "t1" );
- fam->add_task( "t2" );
- }
-
- {
- // The whole suite should get *MOVED* from clientDef to the *EMPTY* server def. i.e add
- defs_ptr clientDef = Defs::create(); {
- suite_ptr suite = clientDef->add_suite( "suite1" ) ;
- family_ptr fam = suite->add_family("family" ) ;
- fam->add_task( "t1" );
- fam->add_task( "t2" );
- }
-
- // Server defs is empty
- Defs serverDefs;
-
- std::string errorMsg;
- BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/suite1/family/t2",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
- BOOST_CHECK_MESSAGE(expectedDefs == serverDefs,"expectedDefs and servers defs should be the same");
- }
-
- {
- // The whole suite should get *MOVED* from clientDef to the *EMPTY* server def. i.e add
- defs_ptr clientDef = Defs::create(); {
- suite_ptr suite = clientDef->add_suite( "suite1" ) ;
- family_ptr fam = suite->add_family("family" ) ;
- fam->add_task( "t1" );
- fam->add_task( "t2" );
- }
-
- // Server defs is empty
- Defs serverDefs;
-
- std::string errorMsg;
- BOOST_REQUIRE_MESSAGE(serverDefs.replaceChild("/suite1/family",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
- BOOST_CHECK_MESSAGE(expectedDefs == serverDefs,"expectedDefs and servers defs should be the same");
- }
-
- {
- // The whole suite should get *MOVED* from clientDef to the *EMPTY* server def. i.e add
- defs_ptr clientDef = Defs::create(); {
- suite_ptr suite = clientDef->add_suite( "suite1" ) ;
- family_ptr fam = suite->add_family("family" ) ;
- fam->add_task( "t1" );
- fam->add_task( "t2" );
- }
-
- // Server defs is empty
- Defs serverDefs;
-
- std::string errorMsg;
- BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/suite1",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
- BOOST_CHECK_MESSAGE(expectedDefs == serverDefs,"expectedDefs and servers defs should be the same");
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_replace_child )
-{
- cout << "ANode:: ...test_replace_child\n" ;
- defs_ptr clientDef = Defs::create(); {
- suite_ptr suite = Suite::create( "suite1" ) ;
- family_ptr fam = Family::create( "family" ) ;
- fam->addTask( Task::create( "t1" ) );
- suite->addFamily( fam );
- clientDef->addSuite( suite );
- }
- Defs comparisonDef; {
- suite_ptr suite = Suite::create( "suite1" ) ;
- family_ptr fam = Family::create( "family" ) ;
- fam->addTask( Task::create( "t1" ) );
- suite->addFamily( fam );
- comparisonDef.addSuite( suite );
- }
- BOOST_CHECK_MESSAGE(comparisonDef == *clientDef,"client and comparisonDef should be the same");
-
- std::string errorMsg;
- Defs serverDefs;
- BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/suite1",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
- BOOST_CHECK_MESSAGE(comparisonDef == serverDefs,"comparisonDef and servers defs should be the same");
-}
-
-BOOST_AUTO_TEST_CASE( test_replace_add_preserves_states )
-{
- cout << "ANode:: ...test_replace_add_preserves_states\n" ;
- defs_ptr clientDef = Defs::create(); {
- suite_ptr suite = clientDef->add_suite( "suite1" ) ;
- family_ptr fam = suite->add_family("family" ) ;
- fam->add_task( "t1" );
- fam->add_task( "t2" );
- fam->add_task( "t3" );
- fam->add_task( "t4" );
- }
-
- // add Child t4 to the server defs, the states on t1->t3 should be preserved
- // The abort should be progagated up the node tree
- family_ptr fam;
- suite_ptr suite;
- Defs serverDefs; {
- suite = serverDefs.add_suite( "suite1" ) ;
- fam = suite->add_family("family" ) ;
- task_ptr t1 = fam->add_task( "t1" );
- task_ptr t2 = fam->add_task( "t2" );
- task_ptr t3 = fam->add_task( "t3" );
- serverDefs.beginAll();
- t1->set_state(NState::COMPLETE);
- t2->set_state(NState::ABORTED);
- t3->set_state(NState::ACTIVE);
- }
-
- //cout << serverDefs;
- std::string errorMsg;
- BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/suite1/family/t4",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
-
- /// The Nodes t1,t2,t3 may have been replaced hence we must get Nodes again
- node_ptr st1 = serverDefs.findAbsNode("/suite1/family/t1");
- node_ptr st2 = serverDefs.findAbsNode("/suite1/family/t2");
- node_ptr st3 = serverDefs.findAbsNode("/suite1/family/t3");
- node_ptr st4 = serverDefs.findAbsNode("/suite1/family/t4");
- BOOST_REQUIRE_MESSAGE(st1,"Expected to find task t1");
- BOOST_REQUIRE_MESSAGE(st2,"Expected to find task t2");
- BOOST_REQUIRE_MESSAGE(st3,"Expected to find task t3");
- BOOST_REQUIRE_MESSAGE(st4,"Expected to find task t4");
- BOOST_REQUIRE_MESSAGE(st1->state() == NState::COMPLETE," state on task t1 not preserved after replace");
- BOOST_REQUIRE_MESSAGE(st2->state() == NState::ABORTED," state on task t2 not preserved after replace");
- BOOST_REQUIRE_MESSAGE(st3->state() == NState::ACTIVE," state on task t3 not preserved after replace");
- BOOST_REQUIRE_MESSAGE(st4->state() == NState::QUEUED," state on task t4 to be queued");
- BOOST_REQUIRE_MESSAGE(fam->state() == NState::ABORTED,"Aborted should have propagated to family");
- BOOST_REQUIRE_MESSAGE(suite->state() == NState::ABORTED,"Aborted should have propagated to suite");
- BOOST_REQUIRE_MESSAGE(serverDefs.state() == NState::ABORTED,"Aborted should have propagated to Defs");
-}
-
-BOOST_AUTO_TEST_CASE( test_replace_preserves_sibling_states )
-{
- cout << "ANode:: ...test_replace_preserves_sibling_states\n" ;
- defs_ptr clientDef = Defs::create(); {
- suite_ptr suite = Suite::create( "suite1" ) ;
- family_ptr fam = suite->add_family("family" ) ;
- fam->add_task( "t4" );
- clientDef->addSuite( suite );
- }
-
- // add Child t4 to the server defs, the states on t1->t4 should be preserved
- task_ptr t1,t2,t3;
- Defs serverDefs; {
- suite_ptr suite = serverDefs.add_suite( "suite1" ) ;
- family_ptr fam = suite->add_family("family" ) ;
- t1 = fam->add_task( "t1" ); t1->set_state(NState::COMPLETE);
- t2 = fam->add_task( "t2" ); t2->set_state(NState::ABORTED);
- t3 = fam->add_task( "t3" ); t3->set_state(NState::ACTIVE);
- fam->add_task( "t4" );
- }
-
- std::string errorMsg;
- BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/suite1/family/t4",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
- BOOST_REQUIRE_MESSAGE(t1->state() == NState::COMPLETE," state on task t1 not preserved after replace");
- BOOST_REQUIRE_MESSAGE(t2->state() == NState::ABORTED," state on task t2 not preserved after replace");
- BOOST_REQUIRE_MESSAGE(t3->state() == NState::ACTIVE," state on task t3 not preserved after replace");
-}
-
-BOOST_AUTO_TEST_CASE( test_replace_preserves_begun_status )
-{
- cout << "ANode:: ...test_replace_preserves_begun_status\n" ;
- defs_ptr clientDef = Defs::create(); {
- suite_ptr suite = clientDef->add_suite( "suite1" ) ;
- family_ptr fam = suite->add_family( "family" ) ;
- fam->addTask( Task::create( "t1" ) );
- }
- Defs comparisonDef; {
- suite_ptr suite = comparisonDef.add_suite( "suite1" ) ;
- family_ptr fam = suite->add_family( "family" ) ;
- fam->addTask( Task::create( "t1" ) );
- }
- BOOST_CHECK_MESSAGE(comparisonDef == *clientDef,"client and comparisonDef should be the same");
- comparisonDef.beginAll();
-
- defs_ptr serverDefs = Defs::create(); {
- suite_ptr suite = serverDefs->add_suite( "suite1" ) ;
- family_ptr fam = suite->add_family( "family" ) ;
- fam->addTask( Task::create( "t1" ) );
- }
- serverDefs->beginAll();
-
- std::string errorMsg;
- BOOST_REQUIRE_MESSAGE( serverDefs->replaceChild("/suite1",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
- BOOST_REQUIRE_MESSAGE( serverDefs->findSuite("suite1"),"Can't find suite1");
- BOOST_REQUIRE_MESSAGE( serverDefs->findSuite("suite1")->begun(),"Expected replaced suite to preserve begun status");
- Ecf::set_debug_equality(true); // only has affect in DEBUG build
- BOOST_CHECK_MESSAGE(comparisonDef == *serverDefs,"comparisonDef and servers defs should be the same");
- Ecf::set_debug_equality(false);
-}
-
-BOOST_AUTO_TEST_CASE( test_replace_add_node )
-{
- cout << "ANode:: ...test_replace_add_node\n" ;
- defs_ptr clientDef = Defs::create(); {
- suite_ptr suite = Suite::create( "suite1" ) ;
- family_ptr fam = Family::create( "family" ) ;
- fam->addTask( Task::create( "t1" ) );
- suite->addFamily( fam );
- suite->addTask( Task::create( "t2" ) );
- clientDef->addSuite( suite );
- }
- Defs comparisonDef; {
- suite_ptr suite = Suite::create( "suite1" ) ;
- family_ptr fam = Family::create( "family" ) ;
- fam->addTask( Task::create( "t1" ) );
- suite->addFamily( fam );
- suite->addTask( Task::create( "t2" ) );
- comparisonDef.addSuite( suite );
- }
- BOOST_CHECK_MESSAGE(comparisonDef == *clientDef,"client and comparisonDef should be the same");
-
-
- // Here /suite1/t2 does not exist in the server. Moved from client defs to server
- Defs serverDefs; {
- suite_ptr suite = Suite::create( "suite1" ) ;
- family_ptr fam = Family::create( "family" ) ;
- fam->addTask( Task::create( "t1" ) );
- suite->addFamily( fam );
- serverDefs.addSuite( suite );
- }
- std::string errorMsg;
- BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/suite1/t2",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
- BOOST_CHECK_MESSAGE(comparisonDef == serverDefs,"comparisonDef and servers defs should be the same");
-}
-
-BOOST_AUTO_TEST_CASE( test_replace_add_hierarchy )
-{
- cout << "ANode:: ...test_replace_add_hierarchy\n" ;
- defs_ptr clientDef = Defs::create(); {
- suite_ptr suite = Suite::create( "suite1" ) ;
- family_ptr fa = Family::create( "fa" ) ;
- family_ptr fb = Family::create( "fb" ) ;
- family_ptr fc = Family::create( "fc" ) ;
- family_ptr fd = Family::create( "fd" ) ;
- fa->addFamily( fb );
- fb->addFamily( fc );
- fc->addFamily( fd );
- fd->addTask( Task::create( "t1" ) );
- suite->addFamily( fa );
- clientDef->addSuite( suite );
- }
- Defs comparisonDef; {
- suite_ptr suite = Suite::create( "suite1" ) ;
- family_ptr fa = Family::create( "fa" ) ;
- family_ptr fb = Family::create( "fb" ) ;
- family_ptr fc = Family::create( "fc" ) ;
- family_ptr fd = Family::create( "fd" ) ;
- fa->addFamily( fb );
- fb->addFamily( fc );
- fc->addFamily( fd );
- fd->addTask( Task::create( "t1" ) );
- suite->addFamily( fa );
- comparisonDef.addSuite( suite );
- }
- BOOST_CHECK_MESSAGE(comparisonDef == *clientDef,"client and comparisonDef should be the same");
-
-
- // Here /suite1/fa/fb/fc/fd/t1 does not exist in the server. These should be created.
- // by adding family "fa" as a child of suite1
- Defs serverDefs; {
- suite_ptr suite = Suite::create( "suite1" ) ;
- serverDefs.addSuite( suite );
- }
- std::string errorMsg;
- BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/suite1/fa/fb/fc/fd/t1",clientDef,true/*create nodes as needed*/, false/*force*/,errorMsg), errorMsg );
- BOOST_CHECK_MESSAGE(comparisonDef == serverDefs,"comparisonDef and servers defs should be the same");
-}
-
-
-BOOST_AUTO_TEST_CASE( test_replace_order_preserved_for_suite )
-{
- cout << "ANode:: ...test_replace_order_preserved_for_suite\n" ;
- // Test that when we replace a suite, its order is preserved,
- // See ECFLOW-23 - When replacing a node the order is changed.
- defs_ptr clientDef = Defs::create(); {
- clientDef->add_suite( "s1" ) ;
- clientDef->add_suite( "s2" ) ;
- clientDef->add_suite( "s3" ) ;
- }
-
- // Replace suite s1 with another suite s1 check order is preserved
- Defs serverDefs; {
- serverDefs.add_suite( "s1" ) ;
- serverDefs.add_suite( "s2" ) ;
- serverDefs.add_suite( "s3" ) ;
- }
-
- Defs expectedDefs; {
- expectedDefs.add_suite( "s1" ) ;
- expectedDefs.add_suite( "s2" ) ;
- expectedDefs.add_suite( "s3" ) ;
- }
-
- std::string errorMsg;
- BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/s1",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
- BOOST_CHECK_MESSAGE(expectedDefs == serverDefs,"expectedDefs and servers defs should be the same");
-
- BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/s2",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
- BOOST_CHECK_MESSAGE(expectedDefs == serverDefs,"expectedDefs and servers defs should be the same");
-
- BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/s3",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
- BOOST_CHECK_MESSAGE(expectedDefs == serverDefs,"expectedDefs and servers defs should be the same");
-}
-
-
-BOOST_AUTO_TEST_CASE( test_replace_order_preserved_for_family )
-{
- cout << "ANode:: ...test_replace_order_preserved_for_family\n" ;
- // Test that when we replace a family, its order is preserved,
- // See ECFLOW-23 - When replacing a node the order is changed.
- defs_ptr clientDef = Defs::create(); {
- suite_ptr suite = clientDef->add_suite( "suite1" ) ;
- suite->add_family("f1" ) ;
- suite->add_family("f2" ) ;
- suite->add_family("f3" ) ;
- }
-
- // Replace family f1 with another family f1 check order is preserved
- Defs serverDefs; {
- suite_ptr suite = serverDefs.add_suite( "suite1" ) ;
- suite->add_family("f1" ) ;
- suite->add_family("f2" ) ;
- suite->add_family("f3" ) ;
- }
-
- Defs expectedDefs; {
- suite_ptr suite = expectedDefs.add_suite( "suite1" ) ;
- suite->add_family("f1" ) ;
- suite->add_family("f2" ) ;
- suite->add_family("f3" ) ;
- }
-
- std::string errorMsg;
- Ecf::set_debug_equality(true); // only has affect in DEBUG build
- BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/suite1/f1",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
- BOOST_CHECK_MESSAGE(expectedDefs == serverDefs,"expectedDefs and servers defs should be the same");
- BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/suite1/f2",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
- BOOST_CHECK_MESSAGE(expectedDefs == serverDefs,"expectedDefs and servers defs should be the same");
- BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/suite1/f3",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
- BOOST_CHECK_MESSAGE(expectedDefs == serverDefs,"expectedDefs and servers defs should be the same");
- Ecf::set_debug_equality(false);
-}
-
-BOOST_AUTO_TEST_CASE( test_replace_order_preserved_for_task )
-{
- cout << "ANode:: ...test_replace_order_preserved_for_task\n" ;
- // Test that when we replace a family, its order is preserved,
- // See ECFLOW-23 - When replacing a node the order is changed.
- defs_ptr clientDef = Defs::create(); {
- suite_ptr suite = clientDef->add_suite( "suite1" ) ;
- family_ptr f1 = suite->add_family("f1" ) ;
- f1->add_task("t1");
- f1->add_task("t2");
- f1->add_task("t3");
- }
-
- // Replace task t1 with another task t1, check order is preserved
- Defs serverDefs; {
- suite_ptr suite = serverDefs.add_suite( "suite1" ) ;
- family_ptr f1 = suite->add_family("f1" ) ;
- f1->add_task("t1");
- f1->add_task("t2");
- f1->add_task("t3");
- }
-
- Defs expectedDefs; {
- suite_ptr suite = expectedDefs.add_suite( "suite1" ) ;
- family_ptr f1 = suite->add_family("f1" ) ;
- f1->add_task("t1");
- f1->add_task("t2");
- f1->add_task("t3");
- }
-
- std::string errorMsg;
- Ecf::set_debug_equality(true); // only has affect in DEBUG build
- BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/suite1/f1/t1",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
- BOOST_CHECK_MESSAGE(expectedDefs == serverDefs,"expectedDefs and servers defs should be the same");
- BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/suite1/f1/t2",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
- BOOST_CHECK_MESSAGE(expectedDefs == serverDefs,"expectedDefs and servers defs should be the same");
- BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/suite1/f1/t3",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
- BOOST_CHECK_MESSAGE(expectedDefs == serverDefs,"expectedDefs and servers defs should be the same");
- Ecf::set_debug_equality(false);
-}
-
-BOOST_AUTO_TEST_CASE( test_replace_child_errors )
-{
- cout << "ANode:: ...test_replace_child_errors\n" ;
- defs_ptr clientDef = Defs::create(); {
- suite_ptr suite = Suite::create( "suite1" ) ;
- family_ptr fam = Family::create( "family" ) ;
- fam->addTask( Task::create( "t1" ) );
- suite->addFamily( fam );
- suite->addTask( Task::create( "t2" ) );
- clientDef->addSuite( suite );
- }
- Defs serverDefs;
- std::string errorMsg;
- BOOST_REQUIRE_MESSAGE(!serverDefs.replaceChild("/suite1/i/dont/exist", clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), "Expected failure" );
-}
-
-BOOST_AUTO_TEST_CASE( test_replace_child_errors_2 )
-{
- cout << "ANode:: ...test_replace_child_errors_2\n" ;
- defs_ptr clientDef = Defs::create(); {
- suite_ptr suite = Suite::create( "suite1" ) ;
- family_ptr fam = Family::create( "family" ) ;
- fam->addTask( Task::create( "t1" ) );
- suite->addFamily( fam );
- suite->addTask( Task::create( "t2" ) );
- clientDef->addSuite( suite );
- }
- Defs serverDefs; {
- suite_ptr suite = Suite::create( "suite1" ) ;
- family_ptr fam = Family::create( "family" ) ;
- fam->addTask( Task::create( "t1" ) );
- suite->addFamily( fam );
- serverDefs.addSuite( suite );
- }
-
- // because createNodesAsNeeded is false, child adoption should fail since /suite1/t2
- // does not exist on the server
- std::string errorMsg;
- BOOST_REQUIRE_MESSAGE(!serverDefs.replaceChild("/suite1/t2", clientDef , false/*create nodes as needed*/, false, errorMsg), "Expected failure");
-
- // With flag now set, we will create any missing nodes even if they dont exist in the server
- errorMsg.clear();
- BOOST_REQUIRE_MESSAGE(serverDefs.replaceChild("/suite1/t2", clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), "Expected success " << errorMsg );
-}
-
-
-BOOST_AUTO_TEST_CASE( test_replace_child_errors_3 )
-{
- // test force option
- cout << "ANode:: ...test_replace_child_errors_3\n" ;
- defs_ptr clientDef = Defs::create(); {
- suite_ptr suite = Suite::create( "suite1" ) ;
- family_ptr fam = Family::create( "family" ) ;
- fam->addTask( Task::create( "t1" ) );
- suite->addFamily( fam );
- suite->addTask( Task::create( "t2" ) );
- clientDef->addSuite( suite );
- }
-
- Defs serverDefs; {
- suite_ptr suite = Suite::create( "suite1" ) ;
- family_ptr fam = Family::create( "family" ) ;
- fam->addTask( Task::create( "t1" ) );
- suite->addFamily( fam );
- task_ptr t2 = Task::create( "t2" );
- suite->addTask( t2 );
- serverDefs.addSuite( suite );
-
- t2->set_state( NState::ACTIVE ); // Must be done after parent has been setup
- }
- std::string errorMsg;
- BOOST_REQUIRE_MESSAGE( !serverDefs.replaceChild("/suite1/t2", clientDef, true/*create nodes as needed*/, false/*force*/, errorMsg), "Expected failure since server task t2 is active, and force not used");
- errorMsg.clear();
- BOOST_REQUIRE_MESSAGE( serverDefs.replaceChild("/suite1/t2", clientDef, true/*create nodes as needed*/, true/*force*/, errorMsg), errorMsg);
-}
-
-
-BOOST_AUTO_TEST_CASE( test_replace_add_task_with_bad_trigger )
-{
- cout << "ANode:: ...test_replace_add_task_with_bad_trigger\n" ;
- defs_ptr clientDef = Defs::create(); {
- suite_ptr suite = clientDef->add_suite( "suite1" ) ;
- family_ptr fam = suite->add_family("family" ) ;
- task_ptr task = fam->add_task( "t2" );
- task->add_trigger("txx eq complete");
- }
-
- // add Child t2 to the server defs
- Defs serverDefs; {
- suite_ptr suite = serverDefs.add_suite( "suite1" ) ;
- family_ptr fam = suite->add_family("family" ) ;
- fam->add_task( "t1" );
- }
-
- // expect to fail since trigger expression on added task, should not resolve
- std::string errorMsg;
- BOOST_REQUIRE_MESSAGE( !serverDefs.replaceChild("/suite1/family/t2",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
-}
-
-BOOST_AUTO_TEST_CASE( test_replace_add_suite_with_bad_triggers )
-{
- cout << "ANode:: ...test_replace_add_suite_with_bad_triggers\n";
-
- // The whole suite should get *MOVED* from clientDef to the *EMPTY* server def. i.e add
- defs_ptr clientDef = Defs::create(); {
- suite_ptr suite = clientDef->add_suite( "suite1" ) ;
- family_ptr fam = suite->add_family("family" ) ;
- fam->add_task( "t1" );
- fam->add_task( "t2" );
- task_ptr t3 = fam->add_task("t3");
- t3->add_trigger("txxxxx eq complete");
- }
-
- // Server defs is empty
- Defs serverDefs;
-
- // expect failure since trigger expression should not resolve
- std::string errorMsg;
- BOOST_REQUIRE_MESSAGE( !serverDefs.replaceChild("/suite1/family/t2",clientDef,true/*create nodes as needed*/, false/*force*/, errorMsg), errorMsg );
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ANode/test/TestSetState.cpp b/ecflow_4_0_7/ANode/test/TestSetState.cpp
deleted file mode 100644
index b0fa265..0000000
--- a/ecflow_4_0_7/ANode/test/TestSetState.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "EcfFile.hpp"
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-
-#include <boost/test/unit_test.hpp>
-#include <iostream>
-#include <stdlib.h>
-
-using namespace std;
-using namespace ecf;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-static void set_state(node_ptr n,NState::State set,NState::State expected)
-{
- n->set_state(set);
- BOOST_REQUIRE_MESSAGE(n->state() == expected,"Expected state " << NState::toString(expected) << " but found " << NState::toString(n->state()) << " for " << n->debugNodePath());
-}
-
-static void test_state(node_ptr n,NState::State expected)
-{
- BOOST_REQUIRE_MESSAGE(n->state() == expected,"Expected state " << NState::toString(expected) << " but found " << NState::toString(n->state()) << " for " << n->debugNodePath());
-}
-
-BOOST_AUTO_TEST_CASE( test_set_state )
-{
- cout << "ANode:: ...test_set_state\n";
- std::vector<NState::State> stateVec = NState::states();
-
-// cout << "Defs setState\n";
- Defs theDefs;
- BOOST_FOREACH(NState::State state, stateVec) {
- theDefs.set_state(state);
- BOOST_REQUIRE_MESSAGE(theDefs.state() == state,"Expected defs state " << NState::toString(state) << " but found " << NState::toString(theDefs.state()));
- }
-// theDefs.resume(); // unset the suspended state. Start with default, for next set of test
- theDefs.set_state(NState::UNKNOWN); // Start with default, for next set of test
-
-
-// cout << "Suite setState\n";
- suite_ptr s = Suite::create("s");
- theDefs.addSuite(s);
- BOOST_FOREACH(NState::State state, stateVec) {
- set_state(s,state,state); // suite with no children, state should be what was set
- }
- s->resume(); // unset the suspended state. Start with default, for next set of test
- s->set_state(NState::UNKNOWN); // Start with default, for next set of test
-
-
-// cout << "family setState\n";
- family_ptr f = Family::create("f");
- s->addFamily(f);
- BOOST_FOREACH(NState::State state, stateVec) {
- set_state(f,state,state); // family with no children, state should be what was set
- }
- f->resume(); // unset the suspended state. Start with default, for next set of test
- f->set_state(NState::UNKNOWN); // Start with default, for next set of test
-
-
-// cout << "task setState\n";
- task_ptr t = Task::create("t");
- f->addTask(t);
-
- BOOST_FOREACH(NState::State state, stateVec) {
- f->setStateOnly(NState::UNKNOWN); // reset family state
- s->setStateOnly(NState::UNKNOWN); // reset suite state
- set_state(t,state,state); // task state should be what was set
-
- test_state(f,state); // family state should be computed state
- test_state(s,state); // suite state should be computed state
- }
-
- /// Everytime we set the state on a nodecontainer, we call handleStateChange
- /// This by default works out the most significant state of the children
- /// ie. the computed state. Hence setting the state on Suite/Family is really
- /// meaningless, since it will always be the computed state.
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ANode/test/TestSingleExprParse.cpp b/ecflow_4_0_7/ANode/test/TestSingleExprParse.cpp
deleted file mode 100644
index 85fbacd..0000000
--- a/ecflow_4_0_7/ANode/test/TestSingleExprParse.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-#define BOOST_TEST_MODULE TestSingle
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include "ExprParser.hpp"
-#include "ExprAst.hpp"
-
-#include <boost/test/unit_test.hpp>
-#include <boost/foreach.hpp>
-#include <string>
-#include <map>
-#include <iostream>
-#include <fstream>
-using namespace std;
-
-
-// DEBUG AID: to see the expression tree, invert the expected evaluation
-// so that test fail's
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_single_expression )
-{
- std::cout << "ANode:: ...test_single_expression\n";
-
- // The map key = trigger expression,
- // value.first = type of expected root abstract syntax tree
- // value.second = result of expected evaluation
- map<string,std::pair<string,bool> > exprMap;
-
-// exprMap["inigroup:YMD eq not 1"] = std::make_pair(AstEqual::stype(),true);
-// exprMap["/net/main:YMD le /net/cleanplus1:YMD and 1"] = std::make_pair(AstAnd::stype(),true);
- exprMap["!../../../prod2diss//operation_is_late:yes"] = std::make_pair(AstNot::stype(),true);
-// exprMap["../obs:YMD ge ( 19720101 + 6576 - 1)"] = std::make_pair(AstGreaterEqual::stype(),true);
-// exprMap["../obs:YMD ge ( (19720101 + 6576) - (12 + 1) )"] = std::make_pair(AstGreaterEqual::stype(),true);
-
- std::pair<string, std::pair<string,bool> > p;
- BOOST_FOREACH(p, exprMap ) {
-
- ExprParser theExprParser(p.first);
- std::string errorMsg;
- bool ok = theExprParser.doParse(errorMsg);
- BOOST_REQUIRE_MESSAGE(ok,errorMsg);
-
- string expectedRootType = p.second.first;
- bool expectedEvaluationResult = p.second.second;
-
- Ast* top = theExprParser.getAst();
- BOOST_REQUIRE_MESSAGE( top ,"No abstract syntax tree");
- BOOST_REQUIRE_MESSAGE( top->left() ,"No root created");
- BOOST_REQUIRE_MESSAGE( top->left()->isRoot() ,"First child of top should be a root");
- BOOST_REQUIRE_MESSAGE( top->left()->type() == expectedRootType,"expected root type " << expectedRootType << " but found " << top->left()->type());
- BOOST_REQUIRE_MESSAGE( expectedEvaluationResult == top->evaluate(),"evaluation not as expected for " << *top);
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/ANode/test/TestSmsLocator.cpp b/ecflow_4_0_7/ANode/test/TestSmsLocator.cpp
deleted file mode 100644
index 19b92d2..0000000
--- a/ecflow_4_0_7/ANode/test/TestSmsLocator.cpp
+++ /dev/null
@@ -1,128 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <iostream>
-#include <stdlib.h>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/test/unit_test.hpp>
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "EcfFile.hpp"
-#include "Str.hpp"
-#include "File.hpp"
-
-using namespace std;
-using namespace ecf;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_sms_file_locator )
-{
- cout << "ANode:: ...test_sms_file_locator\n";
-
- // SET ECF_HOME
- std::string smshome = File::test_data("ANode/test/data/SMSHOME","ANode");
-
- // Create a defs file corresponding to:
- //# Test the sms file can be found via ECF_SCRIPT
- //#
- //suite suite
- // edit ECF_INCLUDE $ECF_HOME/includes
- // edit SLEEPTIME 10
- // family family
- // task t1
- // task t2
- // task t3
- // endfamily
- //endsuite
- //
- //#
- //# This test suite should force a backwards search since the ecf files
- //# are located in ECF_HOME
- //suite suite1
- // family family
- // task suite1_task1
- // task suite1_task2
- // task suite1_task3
- // endfamily
- //endsuite
- //
- //#
- //# This suite is used to test command substition with ECF_FETCH command
- //#
- //suite suite2
- // edit ECF_INCLUDE $ECF_HOME/includes
- // edit ECF_FILES $ECF_HOME
- // family family
- // edit SMSFETCH "smsfetch -F %ECF_FILES% -I %ECF_INCLUDE%"
- // task t2
- // endfamily
- //endsuite
- Defs theDefs;
- {
- suite_ptr suite = theDefs.add_suite("suite");
- suite->addVariable( Variable( Str::ECF_INCLUDE(), "$ECF_HOME/includes" ) );
- suite->addVariable( Variable( "SLEEPTIME", "10" ) );
- family_ptr fam = suite->add_family( "family" );
- fam->add_task( "t1" );
- fam->add_task( "t2" );
- fam->add_task( "t3" );
- }
- {
- suite_ptr suite = theDefs.add_suite("suite1");
- family_ptr fam = suite->add_family( "family" );
- fam->add_task( "suite1_task1" );
- fam->add_task( "suite1_task2" );
- fam->add_task( "suite1_task3" );
- }
- {
- suite_ptr suite2 = theDefs.add_suite("suite2");
- suite2->addVariable( Variable( Str::ECF_INCLUDE(), "$ECF_HOME/includes" ) );
- suite2->addVariable( Variable( Str::ECF_FILES(), "$ECF_HOME" ) );
- family_ptr fam = suite2->add_family( "family" );
- fam->addVariable( Variable( Str::ECF_FETCH(), "smsfetch -F %ECF_FILES% -I %ECF_INCLUDE%" ) );
- fam->add_task( "t2" );
- }
-// cerr << theDefs << "\n";
-
- // get all the task, assume non hierarchical families
- std::vector<Task*> theTasks;
- theDefs.getAllTasks(theTasks);
- BOOST_REQUIRE_MESSAGE(theTasks.size() == 7, "Expected 7 tasks but found, " << theTasks.size());
-
- // Override ECF_HOME. ECF_HOME is need to locate to the ecf files
- theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(),smshome);
-
-
- /// begin , will cause creation of generated variables. The generated variables
- /// are use in client scripts and used to locate the sms files
- theDefs.beginAll();
-
- // Test for ECF_ file location
- BOOST_FOREACH(Task* t, theTasks) {
- try {
- EcfFile ecf_file = t->locatedEcfFile();
- BOOST_REQUIRE_MESSAGE( !ecf_file.path().empty(), "Could not locate ecf file for task ");
- }
- catch (std::exception& e) {
- BOOST_REQUIRE_MESSAGE(false,"Could not locate ecf file for task " << e.what());
- }
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ANode/test/TestTaskScriptGenerator.cpp b/ecflow_4_0_7/ANode/test/TestTaskScriptGenerator.cpp
deleted file mode 100644
index 41c8aed..0000000
--- a/ecflow_4_0_7/ANode/test/TestTaskScriptGenerator.cpp
+++ /dev/null
@@ -1,205 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <iostream>
-#include <stdlib.h>
-
-#include "boost/make_shared.hpp"
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/test/unit_test.hpp>
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "EcfFile.hpp"
-#include "Str.hpp"
-#include "File.hpp"
-
-using namespace std;
-using namespace ecf;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_task_script_generator )
-{
- cout << "ANode:: ...test_task_script_generator\n";
-
- // SET ECF_HOME
- std::string ecf_home = File::test_data("ANode/test/data/TaskScriptGenerator","ANode");
-
- std::string head = ecf_home + "/head.h";
- std::string tail = ecf_home + "/tail.h";
- fs::remove_all(ecf_home);
- BOOST_REQUIRE_MESSAGE( !fs::exists(head), "Remove of head file failed");
- BOOST_REQUIRE_MESSAGE( !fs::exists(tail), "Remove of tail file failed");
-
-
- // Create a defs file corresponding to:
- //suite suite
- // edit ECF_INCLUDE $ECF_HOME/includes
- // edit SLEEP 10
- // task t1
- // family f1
- // task t1
- // task t2
- // endfamily
- //endsuite
- Defs theDefs;
- {
- suite_ptr suite = theDefs.add_suite("suite");
- suite->add_variable( Str::ECF_INCLUDE(),ecf_home );
- suite->add_variable( Str::ECF_HOME(), ecf_home );
- suite->add_variable( "SLEEP","10" );
- task_ptr t1 = suite->add_task("t1");
- t1->addEvent( Event("event1") );
- t1->addEvent( Event("event2") );
- t1->addEvent( Event("event4") );
- t1->addMeter( Meter("meter1",1,100,90));
- t1->addMeter( Meter("meter2",1,100,90));
- t1->addLabel( Label("label","label value"));
- family_ptr fam = suite->add_family("f1");
- fam->add_task("t1");
- fam->add_task("t2");
-// cerr << theDefs << "\n";
- }
-
- /// generate the scripts and head.h and tail.h
- theDefs.generate_scripts();
-
- /// Test the ecf file were created, by doing job creation
- /// JobCreationCtrl is used control what node we generate the jobs for:
- /// Since we have not set the node on it, we force job generation for all tasks
- job_creation_ctrl_ptr jobCtrl = boost::make_shared<JobCreationCtrl>();
- theDefs.check_job_creation(jobCtrl);
- BOOST_REQUIRE_MESSAGE(jobCtrl->get_error_msg().empty(), jobCtrl->get_error_msg());
- BOOST_REQUIRE_MESSAGE(jobCtrl->fail_submittables().empty(),"Expected no failing tasks");
-
- /// Additional sanity tests #######################################################
-
- /// test that header and tail file were created
- BOOST_REQUIRE_MESSAGE( fs::exists(head), "Head file " << head << " not created");
- BOOST_REQUIRE_MESSAGE( fs::exists(tail), "Tail file " << tail << " not created");
-
- // get all the task, assume non hierarchical families
- std::vector<Task*> theTasks;
- theDefs.getAllTasks(theTasks);
-
- /// begin , will cause creation of generated variables. The generated variables
- /// are use in client scripts and used to locate the sms files
- theDefs.beginAll();
-
- // Test for ECF_ file location
- BOOST_FOREACH(Task* t, theTasks) {
- try {
- EcfFile ecf_file = t->locatedEcfFile();
- BOOST_REQUIRE_MESSAGE( !ecf_file.path().empty(), "Could not locate ecf file for task ");
- }
- catch (std::exception& e) {
- BOOST_REQUIRE_MESSAGE(false,"Could not locate ecf file for task " << e.what());
- }
- }
-
- // Remove the directories that were generated
- fs::remove_all(ecf_home);
-}
-
-
-BOOST_AUTO_TEST_CASE( test_task_script_generator_with_dummy_tasks )
-{
- cout << "ANode:: ...test_task_script_generator_with_dummy_tasks\n";
-
- // SET ECF_HOME
- std::string ecf_home = File::test_data("ANode/test/data/TaskScriptGenerator","ANode");
-
- std::string head = ecf_home + "/head.h";
- std::string tail = ecf_home + "/tail.h";
- fs::remove_all(ecf_home);
- BOOST_REQUIRE_MESSAGE( !fs::exists(head), "Remove of head file failed");
- BOOST_REQUIRE_MESSAGE( !fs::exists(tail), "Remove of tail file failed");
-
-
- // Create a defs file corresponding to:
- // suite suite
- // edit ECF_INCLUDE $ECF_HOME/includes
- // edit ECF_HOME $ECF_HOME/includes
- // edit SLEEP 10
- // family f1
- // task t1
- // task t2
- // endfamily
- // family f2
- // edit ECF_DUMMY_TASK ''
- // task t1
- // task t2
- // endfamily
- // endsuite
- std::vector<task_ptr> tasks_with_scripts,tasks_without_scripts;
- Defs theDefs;
- {
- suite_ptr suite = theDefs.add_suite("suite");
- suite->add_variable( Str::ECF_INCLUDE(),ecf_home );
- suite->add_variable( Str::ECF_HOME(), ecf_home );
- suite->add_variable( "SLEEP","10" );
- family_ptr f1 = suite->add_family("f1");
- tasks_with_scripts.push_back(f1->add_task("t1"));
- family_ptr f2 = suite->add_family("f2");
- f2->add_variable( "ECF_DUMMY_TASK", "" );
- tasks_without_scripts.push_back(f2->add_task("t1"));
- tasks_without_scripts.push_back(f2->add_task("t2"));
-// cout << theDefs << "\n";
- }
-
- /// generate the scripts and head.h and tail.h
- theDefs.generate_scripts();
-
- /// Test the ecf file were created, by doing job creation
- /// JobCreationCtrl is used control what node we generate the jobs for:
- /// Since we have *NOT* set the node on it, we force job generation for all tasks
- job_creation_ctrl_ptr jobCtrl = boost::make_shared<JobCreationCtrl>();
- theDefs.check_job_creation(jobCtrl);
- BOOST_REQUIRE_MESSAGE(jobCtrl->get_error_msg().empty(), jobCtrl->get_error_msg());
- BOOST_REQUIRE_MESSAGE(jobCtrl->fail_submittables().empty(),"Expected no failing tasks");
-
- /// Additional sanity tests #######################################################
-
- /// test that header and tail file were created
- BOOST_REQUIRE_MESSAGE( fs::exists(head), "Head file " << head << " not created");
- BOOST_REQUIRE_MESSAGE( fs::exists(tail), "Tail file " << tail << " not created");
-
- /// begin , will cause creation of generated variables. The generated variables
- /// are use in client scripts and used to locate the ecf files
- theDefs.beginAll();
-
- // Test for script generation
- BOOST_FOREACH(task_ptr t, tasks_with_scripts) {
- try {
- EcfFile ecf_file = t->locatedEcfFile();
- BOOST_REQUIRE_MESSAGE( !ecf_file.path().empty(), "Could not locate ecf file for task ");
- }
- catch (std::exception& e) {
- BOOST_REQUIRE_MESSAGE(false,"Could not locate ecf file for task " << e.what());
- }
- }
-
- // Test that no scripts are generated when ECF_DUMMY_TASK is used
- BOOST_FOREACH(task_ptr t, tasks_without_scripts) {
- BOOST_REQUIRE_THROW(t->locatedEcfFile(),std::runtime_error);
- }
-
- // Remove the directories that were generated
- fs::remove_all(ecf_home);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ANode/test/TestVariableGeneration.cpp b/ecflow_4_0_7/ANode/test/TestVariableGeneration.cpp
deleted file mode 100644
index ebc0c6e..0000000
--- a/ecflow_4_0_7/ANode/test/TestVariableGeneration.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/test/unit_test.hpp>
-#include <iostream>
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "Str.hpp"
-
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-static void findParentVariableValue(task_ptr t, const std::string& name, const std::string& expected)
-{
- std::string value;
- BOOST_CHECK_MESSAGE(t->findParentVariableValue(name,value), "Task " << t->debugNodePath() << " could not find variable of name " << name );
-// if (expected.empty()) std::cout << name << " = " << value << "\n";
- if (!expected.empty())
- BOOST_CHECK_MESSAGE( value == expected , "From task " << t->debugNodePath() << " for variable " << name << " expected value " << expected << " but found " << value );
-}
-
-BOOST_AUTO_TEST_CASE( test_generated_variables )
-{
- std::cout << "ANode:: ...test_generated_variables\n";
-
- task_ptr t;
-
- Defs defs; {
-
- suite_ptr suite = defs.add_suite("suite");
- suite->addRepeat( RepeatInteger("RepeatInteger",10,20,1));
-
- family_ptr fam = suite->add_family("f" );
- fam->addRepeat( RepeatDate("YMD",20090101,20091231,1));
-
- t = fam->add_family("f2")->add_task("t");
- std::vector<std::string> stringList; stringList.reserve(3);
- stringList.push_back("AA"); stringList.push_back("BB"); stringList.push_back("CC");
- t->addRepeat( RepeatEnumerated("AEnum",stringList));
- }
-
- // Generate variables, needed since,findParentVariableValue also serach's the generated variables
- defs.beginAll();
-
- // Check Submittable generated variables
- findParentVariableValue(t,"TASK","t");
- findParentVariableValue(t,Str::ECF_RID(),"");
- findParentVariableValue(t,Str::ECF_TRYNO(),"0");
- findParentVariableValue(t,Str::ECF_NAME(),"/suite/f/f2/t");
- findParentVariableValue(t,Str::ECF_PASS(),"");
- findParentVariableValue(t,Str::ECF_JOB(),"./suite/f/f2/t.job0");
- findParentVariableValue(t,Str::ECF_JOBOUT(),"./suite/f/f2/t.0");
- findParentVariableValue(t,Str::ECF_SCRIPT(),"./suite/f/f2/t.ecf");
-
- // Check Family generated variables
- findParentVariableValue(t,"FAMILY","f/f2");
- findParentVariableValue(t,"FAMILY1","f2");
-
- // Check Suite generated variables
- findParentVariableValue(t,"SUITE","suite");
- findParentVariableValue(t,"YYYY","");
- findParentVariableValue(t,"DOW","");
- findParentVariableValue(t,"DOY","");
- findParentVariableValue(t,"DATE","");
- findParentVariableValue(t,"DAY","");
- findParentVariableValue(t,"DD","");
- findParentVariableValue(t,"MM","");
- findParentVariableValue(t,"MONTH","");
- findParentVariableValue(t,"ECF_DATE","");
- findParentVariableValue(t,"ECF_CLOCK","");
- findParentVariableValue(t,"ECF_TIME","");
-
- // Test repeat generated variables
- findParentVariableValue(t,"AEnum","AA");
- findParentVariableValue(t,"YMD","20090101");
- findParentVariableValue(t,"RepeatInteger","10");
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ANode/test/TestVariableInheritance.cpp b/ecflow_4_0_7/ANode/test/TestVariableInheritance.cpp
deleted file mode 100644
index 46eb82c..0000000
--- a/ecflow_4_0_7/ANode/test/TestVariableInheritance.cpp
+++ /dev/null
@@ -1,78 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-
-#include <boost/test/unit_test.hpp>
-#include <map>
-#include <iostream>
-#include <fstream>
-using namespace std;
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-static void findParentVariableValue(task_ptr t, const std::string& name, const std::string& expected)
-{
- std::string value;
- BOOST_CHECK_MESSAGE(t->findParentVariableValue(name,value), "Task " << t->debugNodePath() << " could not find variable of name " << name );
- BOOST_CHECK_MESSAGE( value == expected , "From task " << t->debugNodePath() << " for variable " << name << " expected value " << expected << " but found " << value );
-}
-
-BOOST_AUTO_TEST_CASE( test_variable_inheritance )
-{
- std::cout << "ANode:: ...test_variable_inheritance\n";
-
- // See page 31, section 5.1 variable inheritance, of SMS users guide
- task_ptr t;
- task_ptr t2 ;
- task_ptr z;
-
- Defs defs; {
- suite_ptr suite = defs.add_suite("suite");
- suite->addVariable(Variable("TOPLEVEL","10"));
- suite->addVariable(Variable("MIDDLE","10"));
- suite->addVariable(Variable("LOWER","10"));
-
- family_ptr fam = suite->add_family("f" );
- fam->addVariable( Variable("MIDDLE","20") );
- t = fam->add_task("t");
- t->addVariable( Variable("LOWER","abc") );
- t2 = fam->add_task("t2");
-
- family_ptr fam2 = suite->add_family("f2" );
- fam2->addVariable( Variable("TOPLEVEL","40") );
- z = fam2->add_task("z");
- }
-
- // Generate variables, needed since,findParentVariableValue also serach's the generated variables
- defs.beginAll();
-
- // See page 31, section 5.1 variable inheritance, of SMS users guide
- findParentVariableValue(t,"TOPLEVEL","10");
- findParentVariableValue(t2, "TOPLEVEL","10");
- findParentVariableValue(z,"TOPLEVEL","40");
-
- findParentVariableValue(t,"MIDDLE","20");
- findParentVariableValue(t2, "MIDDLE","20");
- findParentVariableValue(z,"MIDDLE","10");
-
- findParentVariableValue(t, "LOWER","abc");
- findParentVariableValue(t2, "LOWER","10");
- findParentVariableValue(z, "LOWER","10");
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/ANode/test/TestVariableSubstitution.cpp b/ecflow_4_0_7/ANode/test/TestVariableSubstitution.cpp
deleted file mode 100644
index c71c726..0000000
--- a/ecflow_4_0_7/ANode/test/TestVariableSubstitution.cpp
+++ /dev/null
@@ -1,438 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <string>
-#include <map>
-#include <iostream>
-#include <fstream>
-
-#include <boost/test/unit_test.hpp>
-#include <boost/foreach.hpp>
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "Str.hpp"
-#include "Ecf.hpp"
-#include "Version.hpp"
-
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_variable_substitution )
-{
- std::cout << "ANode:: ...test_variable_substitution\n";
-
- Defs defs;
- suite_ptr s = defs.add_suite("suite");
- {
- s->addVariable(Variable("AVI","avi"));
- s->addVariable(Variable("BAHRA","bahra"));
- s->addVariable(Variable("LOWER","10"));
- s->addVariable(Variable("PATH","/fred/bill/joe"));
- s->addVariable(Variable("EMPTY_VARIABLE",""));
- s->addVariable(Variable("fred","%bill%"));
- s->addVariable(Variable("bill","%fred%"));
- s->addVariable(Variable("hello","%hello%"));
- s->addVariable(Variable("mary","%jane%"));
- s->addVariable(Variable("jane","10"));
- }
-
-
- // See page 31, section 5.1 variable inheritance, of SMS users guide
- std::string cmd = "%AVI%-%BAHRA%-%LOWER%-%AVI%";
- string expected = "avi-bahra-10-avi";
- BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd),"substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%ECF_VERSION%";
- expected = Version::raw();
- BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd),"substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%PATH%"; expected = "/fred/bill/joe";
- BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "/%AVI%/%BAHRA%/%LOWER%%PATH%"; expected = "/avi/bahra/10/fred/bill/joe";
- BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%EMPTY_VARIABLE%"; expected = "";
- BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%mary%"; expected = "10"; // double substitution
- BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%fred%"; expected = "%fred%"; // infinite substitution
- BOOST_CHECK_MESSAGE(!s->variableSubsitution(cmd)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%hello%"; expected = "%hello%"; // infinite substitution
- BOOST_CHECK_MESSAGE(!s->variableSubsitution(cmd)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = Ecf::MICRO(); expected = Ecf::MICRO();
- BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%PATH"; expected = "%PATH";
- BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%%"; expected = "%";
- BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%ERROR%"; expected = "%ERROR%";
- BOOST_CHECK_MESSAGE(!s->variableSubsitution(cmd)," substitution expected to fail since ERROR does not exist");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = ""; expected = "";
- BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
-
- // new rules
- // %<VAR>:substitute %
- // If we find VAR, then use it, else use substitute
- cmd = "%AVI:goblly gook%"; expected = "avi";
- BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%PATH:goblly::: gook%"; expected = "/fred/bill/joe";
- BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%LOWER:fred% %AVI:fred2%"; expected = "10 avi";
- BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%LOWER:fred% %AVI:fred2"; expected = "10 %AVI:fred2";
- BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%EMPTY_VARIABLE::goblly gook%"; expected = "";
- BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%NULL:goblly gook%"; expected = "goblly gook";
- BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%NULL::goblly gook%"; expected = ":goblly gook";
- BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%NULL:%"; expected = "";
- BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%:%"; expected = "";
- BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-}
-
-BOOST_AUTO_TEST_CASE( test_variable_substitution_double_micro )
-{
- std::cout << "ANode:: ...test_variable_substitution_double_micro\n";
-
- Defs defs;
- suite_ptr s = defs.add_suite("suite");
-
- std::string cmd = "%%"; std::string expected = "%";
- BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%%%"; expected = "%%";
- BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%%%%"; expected = "%%";
- BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%%%%%"; expected = "%%%";
- BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "date +%%Y.%%m.%%d"; expected = "date +%Y.%m.%d";
- BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd),"substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "printf %%02d %HOUR:00%"; expected = "printf %02d 00";
- BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd),"substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- s->addVariable(Variable("HOUR","hammer time"));
- cmd = "printf %%02d %HOUR:00%"; expected = "printf %02d hammer time";
- BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd),"substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-}
-
-BOOST_AUTO_TEST_CASE( test_user_variable_substitution )
-{
- std::cout << "ANode:: ...test_user_variable_substitution\n";
-
- Defs defs;
- suite_ptr s = defs.add_suite("suite");
- {
- s->addVariable(Variable("AVI","avi"));
- s->addVariable(Variable("BAHRA","bahra"));
- s->addVariable(Variable("LOWER","10"));
- s->addVariable(Variable("PATH","/fred/bill/joe"));
- s->addVariable(Variable("EMPTY_VARIABLE",""));
- s->addVariable(Variable("fred","%bill%"));
- s->addVariable(Variable("bill","%fred%"));
- s->addVariable(Variable("hello","%hello%"));
- s->addVariable(Variable("mary","%jane%"));
- s->addVariable(Variable("jane","10"));
- }
-
- NameValueMap user_variables;
- user_variables.insert( std::make_pair(string("AVI"),string("_avi")) );
- user_variables.insert( std::make_pair(string("BAHRA"),string("_bahra")) );
- user_variables.insert( std::make_pair(string("LOWER"),string("_10")) );
- user_variables.insert( std::make_pair(string("PATH"),string("_/fred/bill/joe")) );
- user_variables.insert( std::make_pair(string("EMPTY_VARIABLE"),string("_")) );
- user_variables.insert( std::make_pair(string("fred"),string("%bill%")) );
- user_variables.insert( std::make_pair(string("bill"),string("%fred%")) );
- user_variables.insert( std::make_pair(string("hello"),string("%hello%")) );
- user_variables.insert( std::make_pair(string("mary"),string("%jane%")) );
- user_variables.insert( std::make_pair(string("jane"),string("_10")) );
-
- // See page 31, section 5.1 variable inheritance, of SMS users guide
- std::string cmd = "%AVI%-%BAHRA%-%LOWER%-%AVI%"; string expected = "_avi-_bahra-_10-_avi";
- BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables),"substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%PATH%"; expected = "_/fred/bill/joe";
- BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "/%AVI%/%BAHRA%/%LOWER%%PATH%"; expected = "/_avi/_bahra/_10_/fred/bill/joe";
- BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%EMPTY_VARIABLE%"; expected = "_";
- BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%mary%"; expected = "_10"; // double substitution
- BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%fred%"; expected = "%fred%"; // infinite substitution
- BOOST_CHECK_MESSAGE(!s->variable_substitution(cmd,user_variables)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%hello%"; expected = "%hello%"; // infinite substitution
- BOOST_CHECK_MESSAGE(!s->variable_substitution(cmd,user_variables)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = Ecf::MICRO(); expected = Ecf::MICRO();
- BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%PATH"; expected = "%PATH";
- BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
-
- cmd = "%%"; expected = "%";
- BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%ERROR%"; expected = "%ERROR%";
- BOOST_CHECK_MESSAGE(!s->variable_substitution(cmd,user_variables)," substitution expected to fail since ERROR does not exist");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = ""; expected = "";
- BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
-
- // new rules
- // %<VAR>:substitute %
- // If we find VAR, then use it, else use substitute
- cmd = "%AVI:goblly gook%"; expected = "_avi";
- BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%PATH:goblly::: gook%"; expected = "_/fred/bill/joe";
- BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%LOWER:fred% %AVI:fred2%"; expected = "_10 _avi";
- BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%LOWER:fred% %AVI:fred2"; expected = "_10 %AVI:fred2";
- BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%EMPTY_VARIABLE::goblly gook%"; expected = "_";
- BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%NULL:goblly gook%"; expected = "goblly gook";
- BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%NULL::goblly gook%"; expected = ":goblly gook";
- BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%NULL:%"; expected = "";
- BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%:%"; expected = "";
- BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-}
-
-
-BOOST_AUTO_TEST_CASE( test_user_variable_substitution_1 )
-{
- std::cout << "ANode:: ...test_user_variable_substitution_1\n";
-
- Defs defs;
- suite_ptr s = defs.add_suite("suite");
- s->addVariable(Variable("AVI","avi"));
-
- NameValueMap user_variables;
- user_variables.insert( std::make_pair(string("AVI:goblly gook"),string("avtar")) );
-
- // new rules
- // %<VAR>:substitute %
- // If we find VAR, then use it, else use substitute
- // However when we have user_variables if we find the complete string
- // in the user variable list, we use user veriable value:
- // cmd = %FRED:BILL%" and user_variable = "FRED:BILL","Joe90" ===> cmd = "Joe90"
- std::string cmd = "%AVI:goblly gook%"; std::string expected = "avtar";
- BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%AVI:goblly%"; expected = "avi";
- BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%FRED:goblly%"; expected = "goblly";
- BOOST_CHECK_MESSAGE(s->variable_substitution(cmd,user_variables)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-}
-
-
-static std::vector<std::string> required_server_variables()
-{
- std::vector<std::string> required_server_variables;
- required_server_variables.push_back( Str::ECF_PORT() );
- required_server_variables.push_back( std::string("ECF_NODE") );
-
- required_server_variables.push_back( Str::ECF_HOME() );
- required_server_variables.push_back( std::string("ECF_LOG") );
- required_server_variables.push_back( std::string("ECF_CHECK") );
- required_server_variables.push_back( std::string("ECF_CHECKOLD") );
-
- // These variable are read in from the environment, but are not exposed
- // since they only affect the server
- // ECF_CHECKINTERVAL
- // ECF_LISTS
-
- // variables that can be overridden, in the suite definition
- required_server_variables.push_back( std::string("ECF_JOB_CMD") );
- required_server_variables.push_back( std::string("ECF_KILL_CMD") );
- required_server_variables.push_back( std::string("ECF_STATUS_CMD") );
- required_server_variables.push_back( std::string("ECF_URL_CMD") );
- required_server_variables.push_back( std::string("ECF_URL_BASE") );
- required_server_variables.push_back( std::string("ECF_URL") );
- required_server_variables.push_back( std::string("ECF_MICRO") );
-
- // Reference variable, these should be read only
- required_server_variables.push_back( std::string("ECF_PID") ); // server PID
- required_server_variables.push_back( std::string("ECF_VERSION") );// server version
- return required_server_variables;
-}
-
-BOOST_AUTO_TEST_CASE( test_server_variable_substitution )
-{
- std::cout << "ANode:: ...test_server_variable_substitution\n";
-
- Defs defs;
- suite_ptr s = defs.add_suite("suite");
-
- std::vector<std::string> vec = required_server_variables();
- for(size_t i = 0; i < vec.size(); i++) {
- if (vec[i] == "ECF_PID") continue; // CANT test since, this is process ID of server
- std::string value;
- BOOST_CHECK_MESSAGE(s->findParentVariableValue(vec[i],value),"Could not find Server variable " << vec[i]);
- BOOST_CHECK_MESSAGE(!value.empty(),"Empty server variable value for " << vec[i]);
- }
-
- for(size_t i = 0; i < vec.size(); i++) {
- if (vec[i] == "ECF_JOB_CMD") continue; // CANT test since it requires %ECF_JOB% and %ECF_JOBOUT%
- if (vec[i] == "ECF_KILL_CMD") continue; // CANT test since it requires %ECF_PID%
- if (vec[i] == "ECF_STATUS_CMD") continue; // CANT test since it requires %ECF_RID%
- if (vec[i] == "ECF_PID") continue; // CANT test since, this is process ID of server
- std::string cmd = "%";
- cmd += vec[i];
- cmd += "%";
- BOOST_CHECK_MESSAGE(s->variableSubsitution(cmd)," substitution failed for " << vec[i] << " : " << cmd);
- if (vec[i] == "ECF_VERSION") {
- BOOST_CHECK_MESSAGE( cmd == Version::raw(), "expected '" << Version::raw() << "' but found '" << cmd << "'");
- }
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_generated_variable_substitution_of_ECF_OUT )
-{
- // test that if ECF_OUT is defined using %, then we perform variable substitution
- std::cout << "ANode:: ...test_generated_variable_substitution_of_ECF_OUT\n";
-
- Defs defs;
- suite_ptr s = defs.add_suite("suite");
- s->addVariable(Variable("PATH","/fred/bill/joe"));
- s->addVariable(Variable("ECF_HOME","/ecf_home"));
- family_ptr f = s->add_family("f");
- task_ptr t = f->add_task("t");
- t->addVariable(Variable("ECF_OUT","%PATH%"));
- family_ptr f1 = s->add_family("f1");
- f1->addVariable(Variable("PATH2","/fred/bill/joe2"));
- task_ptr t1 = f1->add_task("t1");
- t1->addVariable(Variable("ECF_OUT","%PATH2%"));
-
- // begin_all
- defs.beginAll();
- t->update_generated_variables();
- t1->update_generated_variables();
-
- // cout << defs;
-
- string value;
- value.clear();
- t->findParentVariableValue(Str::ECF_JOBOUT(),value);
- BOOST_CHECK_MESSAGE(value == "/fred/bill/joe/suite/f/t.0","ECF_JOBOUT expected /fred/bill/joe/suite/f/t.0, but found " << value);
-
- value.clear();
- t1->findParentVariableValue(Str::ECF_JOBOUT(),value);
- BOOST_CHECK_MESSAGE(value == "/fred/bill/joe2/suite/f1/t1.0","ECF_JOBOUT expected /fred/bill/joe/suite/f/t.0, but found " << value);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/ANode/test/TestVariableSubstitutionDefs.cpp b/ecflow_4_0_7/ANode/test/TestVariableSubstitutionDefs.cpp
deleted file mode 100644
index 9dbb074..0000000
--- a/ecflow_4_0_7/ANode/test/TestVariableSubstitutionDefs.cpp
+++ /dev/null
@@ -1,174 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2015 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <string>
-#include <map>
-#include <iostream>
-#include <fstream>
-
-#include <boost/test/unit_test.hpp>
-#include <boost/foreach.hpp>
-
-#include "Defs.hpp"
-#include "Str.hpp"
-#include "Version.hpp"
-#include "Ecf.hpp"
-
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_defs_variable_substitution )
-{
- std::cout << "ANode:: ...test_defs_variable_substitution\n";
-
- Defs defs;
- {
- std::vector<Variable> vec;
- vec.push_back(Variable("AVI","avi"));
- vec.push_back(Variable("BAHRA","bahra"));
- vec.push_back(Variable("LOWER","10"));
- vec.push_back(Variable("PATH","/fred/bill/joe"));
- vec.push_back(Variable("fred","%bill%"));
- vec.push_back(Variable("bill","%fred%"));
- vec.push_back(Variable("hello","%hello%"));
- vec.push_back(Variable("mary","%jane%"));
- vec.push_back(Variable("jane","10"));
- defs.set_server().add_or_update_user_variables(vec);
- }
-
- // See page 31, section 5.1 variable inheritance, of SMS users guide
- std::string cmd = "%AVI%-%BAHRA%-%LOWER%-%AVI%";
- string expected = "avi-bahra-10-avi";
- BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd),"substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%ECF_VERSION%"; expected = Version::raw();
- BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd),"substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%PATH%"; expected = "/fred/bill/joe";
- BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "/%AVI%/%BAHRA%/%LOWER%%PATH%"; expected = "/avi/bahra/10/fred/bill/joe";
- BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%mary%"; expected = "10"; // double substitution
- BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%fred%"; expected = "%fred%"; // infinite substitution
- BOOST_CHECK_MESSAGE(!defs.variableSubsitution(cmd)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%hello%"; expected = "%hello%"; // infinite substitution
- BOOST_CHECK_MESSAGE(!defs.variableSubsitution(cmd)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = Ecf::MICRO(); expected = Ecf::MICRO();
- BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%PATH"; expected = "%PATH";
- BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%%"; expected = "%";
- BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%ERROR%"; expected = "%ERROR%";
- BOOST_CHECK_MESSAGE(!defs.variableSubsitution(cmd)," substitution expected to fail since ERROR does not exist");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = ""; expected = "";
- BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
-
- // new rules
- // %<VAR>:substitute %
- // If we find VAR, then use it, else use substitute
- cmd = "%AVI:goblly gook%"; expected = "avi";
- BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%PATH:goblly::: gook%"; expected = "/fred/bill/joe";
- BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%LOWER:fred% %AVI:fred2%"; expected = "10 avi";
- BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%LOWER:fred% %AVI:fred2"; expected = "10 %AVI:fred2";
- BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%NULL:goblly gook%"; expected = "goblly gook";
- BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%NULL::goblly gook%"; expected = ":goblly gook";
- BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%NULL:%"; expected = "";
- BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%:%"; expected = "";
- BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed ");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-}
-
-BOOST_AUTO_TEST_CASE( test_defs_variable_substitution_double_micro )
-{
- std::cout << "ANode:: ...test_defs_variable_substitution_double_micro\n";
-
- Defs defs;
-
- std::string cmd = "%%"; std::string expected = "%";
- BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%%%"; expected = "%%";
- BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%%%%"; expected = "%%";
- BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "%%%%%"; expected = "%%%";
- BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd)," substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "date +%%Y.%%m.%%d"; expected = "date +%Y.%m.%d";
- BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd),"substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- cmd = "printf %%02d %HOUR:00%"; expected = "printf %02d 00";
- BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd),"substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-
- defs.set_server().add_or_update_user_variables("HOUR","hammer time");
- cmd = "printf %%02d %HOUR:00%"; expected = "printf %02d hammer time";
- BOOST_CHECK_MESSAGE(defs.variableSubsitution(cmd),"substitution failed");
- BOOST_CHECK_MESSAGE( cmd == expected, "expected '" << expected << "' but found '" << cmd << "'");
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ANode/test/TestZombies.cpp b/ecflow_4_0_7/ANode/test/TestZombies.cpp
deleted file mode 100644
index 96a9302..0000000
--- a/ecflow_4_0_7/ANode/test/TestZombies.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <iostream>
-#include <stdlib.h>
-
-#include <boost/test/unit_test.hpp>
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_zombies )
-{
- cout << "ANode:: ...test_zombies\n";
- Defs theDefs;
- suite_ptr s = theDefs.add_suite("s");
- task_ptr t = s->add_family("f")->add_task("t");
-
- // SANITY
- {
- BOOST_REQUIRE_MESSAGE(s->zombies().size() == 0, "Expected 0 zombies but found " << s->zombies().size());
- BOOST_REQUIRE_MESSAGE(s->findZombie(ecf::Child::USER).empty(), "Expected no zombies");
- BOOST_REQUIRE_MESSAGE(s->findZombie(ecf::Child::ECF).empty(), "Expected no zombies");
- BOOST_REQUIRE_MESSAGE(s->findZombie(ecf::Child::PATH).empty(), "Expected no zombies");
- ZombieAttr attr;
- BOOST_REQUIRE_MESSAGE(!t->findParentZombie(ecf::Child::PATH,attr) && attr.empty(), "Expected to NOT find PATH zombies on parent");
- }
-
- // ADD
- std::vector<ecf::Child::CmdType> child_cmds;
- child_cmds.push_back(ecf::Child::INIT);
- child_cmds.push_back(ecf::Child::EVENT);
- child_cmds.push_back(ecf::Child::METER);
- child_cmds.push_back(ecf::Child::LABEL);
- child_cmds.push_back(ecf::Child::WAIT);
- child_cmds.push_back(ecf::Child::ABORT);
- child_cmds.push_back(ecf::Child::COMPLETE);
- {
- s->addZombie( ZombieAttr(ecf::Child::USER, child_cmds, ecf::User::FOB,10) );
- BOOST_REQUIRE_MESSAGE(s->zombies().size() == 1, "Expected 1 zombie but found " << s->zombies().size());
- s->addZombie( ZombieAttr(ecf::Child::ECF, child_cmds, ecf::User::FAIL,100) );
- BOOST_REQUIRE_MESSAGE(s->zombies().size() == 2, "Expected 2 zombie but found " << s->zombies().size());
- s->addZombie( ZombieAttr(ecf::Child::PATH, child_cmds, ecf::User::BLOCK,100) );
- BOOST_REQUIRE_MESSAGE(s->zombies().size() == 3, "Expected 3 zombie but found " << s->zombies().size());
- }
-
- // FIND
- BOOST_REQUIRE_MESSAGE(!s->findZombie(ecf::Child::USER).empty(), "Expected to find USER zombies");
- BOOST_REQUIRE_MESSAGE(!s->findZombie(ecf::Child::ECF).empty(), "Expected to find ECF zombies");
- BOOST_REQUIRE_MESSAGE(!s->findZombie(ecf::Child::PATH).empty(), "Expected to find PATH zombies");
-
- // FIND on parent
- {
- ZombieAttr path_z,ecf_z,user_z;
- BOOST_REQUIRE_MESSAGE(t->findParentZombie(ecf::Child::PATH,path_z) && !path_z.empty(), "Expected to find PATH zombies on parent");
- BOOST_REQUIRE_MESSAGE(t->findParentZombie(ecf::Child::ECF,ecf_z) && !ecf_z.empty(), "Expected to find ECF zombies on parent");
- BOOST_REQUIRE_MESSAGE(t->findParentZombie(ecf::Child::USER,user_z) && !user_z.empty(), "Expected to find USER zombies on parent");
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ANode/test/Test_ECFLOW-195.cpp b/ecflow_4_0_7/ANode/test/Test_ECFLOW-195.cpp
deleted file mode 100644
index 20a3215..0000000
--- a/ecflow_4_0_7/ANode/test/Test_ECFLOW-195.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2015 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-
-#include <boost/test/unit_test.hpp>
-#include <iostream>
-#include <stdlib.h>
-
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( NodeTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_ECFLOW_195 )
-{
- cout << "ANode:: ...test_ECFLOW_195 re-queue on task should retain label value\n";
-
- defs_ptr defs = Defs::create();
- suite_ptr s1 = defs->add_suite("s1");
- family_ptr f1 = s1->add_family("f1");
- task_ptr t1 = f1->add_task("t1");
-
- s1->addLabel( Label("s1","s1"));
- f1->addLabel( Label("f1","f1"));
- t1->addLabel( Label("t1","t1"));
-
- defs->beginAll();
-
- // Set the labels, with new values
- s1->changeLabel("s1","xx");
- f1->changeLabel("f1","xx");
- t1->changeLabel("t1","xx");
-
- { // Check new values have not changed
- Label s1_label = s1->find_label("s1");
- BOOST_CHECK_MESSAGE(!s1_label.empty(),"expected to find label 's1'");
- BOOST_CHECK_MESSAGE(s1_label.new_value() == "xx","expected xx but found " << s1_label.new_value());
-
- Label f1_label = f1->find_label("f1");
- BOOST_CHECK_MESSAGE(!f1_label.empty(),"expected to find label 'f1'");
- BOOST_CHECK_MESSAGE(f1_label.new_value() == "xx","expected xx but found " << f1_label.new_value());
-
- Label t1_label = t1->find_label("t1");
- BOOST_CHECK_MESSAGE(!t1_label.empty(),"expected to find label 't1'");
- BOOST_CHECK_MESSAGE(t1_label.new_value() == "xx","expected xx but found " << t1_label.new_value());
- }
-
- // Now requee. the suite and family should be cleared and task label should remain.
- defs->requeue();
-
- { // Suite and Family labels should be reset, and task labels should retain their values
- Label s1_label = s1->find_label("s1");
- BOOST_CHECK_MESSAGE(!s1_label.empty(),"expected to find label 's1'");
- BOOST_CHECK_MESSAGE(s1_label.new_value().empty(),"expected empty string for suite label value after re-queue, but found " << s1_label.new_value());
-
- Label f1_label = f1->find_label("f1");
- BOOST_CHECK_MESSAGE(!f1_label.empty(),"expected to find label 'f1'");
- BOOST_CHECK_MESSAGE(f1_label.new_value().empty(),"expected empty string for family label value after re-queue, but found " << f1_label.new_value());
-
- Label t1_label = t1->find_label("t1");
- BOOST_CHECK_MESSAGE(!t1_label.empty(),"expected to find label 't1'");
- BOOST_CHECK_MESSAGE(t1_label.new_value() == "xx","Expected task label to remain unchanged after re-queue but found " << t1_label.new_value());
- }
-
- // After explicit re-queue expect new labels to be empty
- s1->requeue_labels();
- f1->requeue_labels();
- t1->requeue_labels();
- {
- Label s1_label = s1->find_label("s1");
- BOOST_CHECK_MESSAGE(!s1_label.empty(),"expected to find label 's1'");
- BOOST_CHECK_MESSAGE(s1_label.new_value().empty(),"expected empty string for suite label value after explicit re-queue, but found " << s1_label.new_value());
-
- Label f1_label = f1->find_label("f1");
- BOOST_CHECK_MESSAGE(!f1_label.empty(),"expected to find label 'f1'");
- BOOST_CHECK_MESSAGE(f1_label.new_value().empty(),"expected empty string for family label value after explicit re-queue, but found " << f1_label.new_value());
-
- Label t1_label = t1->find_label("t1");
- BOOST_CHECK_MESSAGE(!t1_label.empty(),"expected to find label 't1'");
- BOOST_CHECK_MESSAGE(t1_label.new_value().empty(),"expected empty string for task label value after explicit re-queue, but found " << t1_label.new_value());
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME/suite/family/head.h b/ecflow_4_0_7/ANode/test/data/SMSHOME/suite/family/head.h
deleted file mode 100644
index b93927a..0000000
--- a/ecflow_4_0_7/ANode/test/data/SMSHOME/suite/family/head.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/bin/ksh
-
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-set -e # stop the shell on first error
-set -u # fail when using an undefined variable
-set -x # echo script lines as they are executed
-
-# Defines the three variables that are needed for any
-# communication with ECF_
-
-export ECF_PORT=%ECF_PORT% # ECF_ port numner
-export ECF_NODE=%ECF_NODE% # The name ecf server that issued this task
-export ECF_NAME=%ECF_NAME% # The name of this current task
-export ECF_PASS=%ECF_PASS% # A unique password
-export ECF_TRYNO=%ECF_TRYNO% # Current try number of the task
-
-# Tell ECF_ we have stated
-# The ECF_ variable ECF_RID will be set to parameter of smsinit
-# Here we give the current PID.
-
-#smsinit $$
-
-# Defined a error hanlder
-
-ERROR() {
- set +e # Clear -e flag, so we don't fail
- #smsabort # Notify ECF_ that something went wrong
- trap 0 # Remove the trap
- exit 0 # End the script
-}
-
-# Trap any calls to exit and errors caught by the -e flag
-
-trap ERROR 0
-
-# Trap any signal that may cause the script to fail
-
-trap '{ echo "Killed by a signal"; ERROR ; }' 1 2 3 4 5 6 7 8 10 12 13 15
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME/suite/family/tail.h b/ecflow_4_0_7/ANode/test/data/SMSHOME/suite/family/tail.h
deleted file mode 100644
index eb7f7a0..0000000
--- a/ecflow_4_0_7/ANode/test/data/SMSHOME/suite/family/tail.h
+++ /dev/null
@@ -1,10 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-#smscomplete # Notify SMS of a normal end
-trap 0 # Remove all traps
-exit 0 # End the shell
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/bad/includes/recursive_head.h b/ecflow_4_0_7/ANode/test/data/SMSHOME2/bad/includes/recursive_head.h
deleted file mode 100644
index 3640d36..0000000
--- a/ecflow_4_0_7/ANode/test/data/SMSHOME2/bad/includes/recursive_head.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/ksh
-
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-#
-# test recursive include
-#
-%include <recursive_head.h>
-
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/config.h b/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/config.h
deleted file mode 100644
index cd29553..0000000
--- a/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/config.h
+++ /dev/null
@@ -1,1527 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-#=======================================================================
-# config.h
-#=======================================================================
-banner config.h
-
-if [[ "$ARCH" != "linux" ]] ;then
- typeset -l ARCH
-fi
-
-export SCRATCHDIR=${SCRATCHDIR:-UNDEFINED}
-export ARCH=${ARCH:-sgimips}
-export TMPDIR=${TMPDIR:-UNDEFINED}
-export HOST=${HOST:-`hostname`}
-export NPES=${NPES:-0}
-
-if [[ $ARCH = linux ]] ; then
- export EMOS_TMPDIR=/var/tmp/tmpdir/%TASK%_%ECF_TRYNO%.$$
- export TMPDIR=$EMOS_TMPDIR
- [[ -d $TMPDIR ]] || mkdir -p $TMPDIR
- export USE_EMOS_TMP="true"
- cd $TMPDIR
-else
- EMOS_TMPDIR=""
-fi
-
-if [[ "$TMPDIR" = "UNDEFINED" ]] ; then
- TMPDIR="$TEMP/NQS_tmpdir.$$" export TMPDIR
- export USE_EMOS_TMP="true"
- [[ -d $TMPDIR ]] || mkdir $TMPDIR
- if [[ $? -ne 0 ]] ; then
- echo "####### CANNOT CREATE TMPDIR #######" >&2
- exit 1
- fi
-fi
-
-PS4="+ "
-
-echo "\
- This is the config.h file and\n\
- System variables used were:\n\
- USER $USER\n\
- TMPDIR $TMPDIR\n\
- HOME $HOME\n\
- HOST $HOST\n\
- ARCH $ARCH\n\
- PATH $PATH\n\
-"
-set -xa
-
-#=======================================================================
-# Experiment version and initial data origin (default values)
-#=======================================================================
-
-EXPVER=%VERSION:0001%
-GRIBCLASS=1
-BASEVER=0001
-BASETIME=1996072200
-
-#=======================================================================
-# Software configuration (library cycles etc)
-#=======================================================================
-
-IFSMASTER=ifsMASTER
-#####################################
-IFS_CYCLE=35r3
-#####################################
-
-
-SUITE_TYPE=%SUITE_TYPE:"undef"%
-NEWSTREAM=none
-EMOS_CYCLE=000370
-VIEW_IFS=
-VIEW_IFSAUX=
-VIEW_OBSPROC=
-VIEW_OBSORT=
-VIEW_TOVSCODE=
-VIEW_SSMICODE=
-VIEW_BL=
-VIEW_SSA=
-VIEW_SST=
-VIEW_WAM=
-MAKE_LIBS=yes
-
-GRIB_API_VERSION=1.8.0
-GRIB_API_INCLUDE="-I/usr/local/lib/metaps/lib/grib_api/jasper/include -I/usr/local/lib/metaps/lib/grib_api/$GRIB_API_VERSION/include"
-GRIB_API_LIB="-L/usr/local/lib/metaps/lib/grib_api/jasper/lib -ljasper -L/usr/local/lib/metaps/lib/grib_api/$GRIB_API_VERSION/lib -lgrib_api_f90 -lgrib_api"
-export GRIB_API=/usr/local/lib/metaps/lib/grib_api/$GRIB_API_VERSION/bin # change to fixed version
-export PATH=$GRIB_API:$PATH
-
-#=======================================================================
-# Model configuration
-#=======================================================================
-
-RESOL=799
-LEVELS=91
-GTYPE=l_2
-FCLENGTH=%FCLENGTH:6%
-FCLENGTH0N=$FCLENGTH
-RUN_GFC=no
-
-#=======================================================================
-# Analysis parameters
-#=======================================================================
-
-IFSMODE=early_delivery
-PERIOD=6
-TSTEP=720
-
-if [[ "%STREAM%" = SCDA ]] && [[ %MXUP_TRAJ:3% = 1 ]] ; then
- RESOLINC_0=255 # HR:255, LR:159
- TSTEP_INC_0=1800
-else
- RESOLINC_0=95
- TSTEP_INC_0=3600
-fi
-
-RESOLINC_1=159 # 255 32r1
-RESOLINC_2=255 # 159 32r1
-TSTEP_INC_1=1800
-TSTEP_INC_2=1800
-
-LFG=.false.
-
-ITER_MIN_0=70
-ITER_MIN_1=50
-ITER_MIN_2=50
-MXUP_TRAJ=%MXUP_TRAJ:3%
-NMINSIMPHY=1
-LINCNMI=false
-LVERIFY_SCREEN=true
-SCRANA=active
-
-RESOLFCE=42
-ITER_FCE=150
-NWRIEVEC=25
-
-OBPATH=ops
-BLACK_DS=ops
-BLACK_MM=ops
-BLACK_EX=ops
-
-LOZONE=true
-LOZONECH=true
-ANEMOM_HT=true
-LISENTRPP=true
-LESUITE=false
-
-OBNLAT=90.00
-OBSLAT=-90.00
-OBWLON=-180.00
-OBELON=180.00
-
-MPLARGS="check=0"
-
-#================================
-# New for 25r3
-
-LINRADEX=true
-LREDUCOB=false
-TSLOTSEC=1800
-UPTRAJ_FCE=0
-LAMV_REASSIGN=false
-
-#================================
-# New for 25r4
-
-BRANCH=""
-BRF=0
-LAIRS=true
-PARALLEL=4
-PROJECTS="none"
-
-#================================
-# New for 26r3
-
-if [[ "%SUITE%" = o || "%SUITE%" = e_* ]] ; then
- LARCHINCR=true
-else
- LARCHINCR=false
-fi
-
-#================================
-# New for 28r1
-
-FPOSCLD=%FPOSCLD:false% # should be true for 4dvar, false for 3d_fgat
-PROFILE=%PROFILE:0% # for diagnostic purposes
-LANOBSENS=false
-
-#================================
-# New for 28r2
-#==========================================================
-# Variables configuring testOfAnalysis
-#==========================================================
-LTESTVAR=false
-NTESTVAR=0
-LCVTEST=false
-LTLTEST=false
-LADTEST=false
-LGRTEST=false
-LTESTINC=false # should be set to false and will turn off other testing
-
-#==========================================================
-# New for 28r3
-#==========================================================
-REINIHOUR=%REINIHOUR:0%
-ED_PERIOD=%ED_PERIOD:12%
-ED_ONLY=%ED_ONLY:false%
-REINICLASS=%REINICLASS:od%
-REINI_NOT_ED=%REINI_NOT_ED:false%
-OBSTREAM=%STREAM%
-
-#==========================================================
-# New for 29r1
-#==========================================================
-set -a
-LOBREALTIME=%OBREALTIME:false% ; # false in catchup mode, true in rt
-LCALC_PSBIAS=%CALC_PSBIAS:true%
-LUSE_PSBIAS=%USE_PSBIAS:true%
-INIPSBIAS=%INIPSBIAS:true%
-INIVARBC=%INIVARBC:false%
-
-NTYPE_MODERR=2
-NCOMP_MODERR=1
-LFGMODERR=true
-ALPHAQ=0.3 # 31r2
-NSERR=-1
-LINITCV=true
-LMODERRFC=false
-LBGMODERR=false
-
-LPROPTL=false
-LINTEST=false
-
-SAVINI=false
-
-EPSROTPATH=""
-
-#==========================================================
-# New for 29r2
-#==========================================================
-set -a
-LTWINTRUTH=false
-LTWINEXP=false
-TRUTHEXP="none"
-LCO2=false
-LCO2ANER=false
-INICO2=false
-LERA40_PREODB=false
-Q2CREATE_NEWSTREAM=false
-Q2USE=false
-Q2CHANGELIST=0
-
-# EPS
-NSVET=50
-NITERLET=120
-EPSBASIS=50 # number of tropical singular vectors used in
- # Gaussian sampling
-EPSBASIST=5 # number of tropical singular vectors used in
-
- # in order to startup emc suite this might be set to 25
- # for the first 2 way. Then make_sv would not be used.
-
-EPSEVO_NORMALIZE=true
-ICPEXPVER=%ICPEXPVER:0001%
-EPSGAMMA_TC2INI=1.5
-EPSGAMMA_EVO2INI=1.0 # 1.5 for 29r2
-EPSGAMMA=0.014
-EPSSIMPL=5 # Gaussian sampling for all singular vectors
-#==========================================================
-# New for 29r3
-#==========================================================
-
-LGPINNER=true
-NFRDHP=3
-
-#==========================================================
-# New for 30r1
-#==========================================================
-FILTERRESOL=255
-FILTERFACTOR=5
-FILTEREXPONENT=4
-EC_FILL_NANS=false
-USE_SMT=%USE_SMT:true%
-
-if [[ "%EC_SMT:yes%" = yes ]] ; then
- USE_SMT=true
-else
- USE_SMT=false
-fi
-
-#==========================================================
-# New for 30r2
-#==========================================================
-LUSE_RSTBIAS=%USE_RSTBIAS:true%
-ERA_MODE=false
-
-#==========================================================
-# New for 31r1
-#==========================================================
-DOFDBK=true # ie true
-LCALC_RSTBIAS=%CALC_RSTBIAS:false%
-VARBC_PATH=%VARBC_PATH:standard%
-NCS_CONFIG=2 # 31r2
-USE_SMT=%USE_SMT:true%
-LPML=%PRODUCE_EPS_ML:0%
-
-if [[ %EC_SMT:yes% = yes ]] && [[ %USE_SMT:true% = false ]] ; then
- echo "ECF_ variable EC_SMT and USE_SMT are not compatible"
- exit 1
-elif [[ %EC_SMT:yes% = no ]] && [[ %USE_SMT:true% = true ]] ; then
- echo "ECF_ variable EC_SMT and USE_SMT are not compatible"
- exit 1
-fi
-#==========================================================
-# New for 31r2
-#==========================================================
-LRAIN4D=true
-LNMPHYS=true #32r1
-ENDANENS=0
-ENDANENSODB=0
-
-P4CLIENT=0 #32r1 not used in operations
-
-#==========================================================
-# New for 32r1
-#==========================================================
-LCONSTANT_VARBC=false
-
-#==========================================================
-# New for 32r2
-#==========================================================
-LIASI=true
-
-INIMODISALB=true # if intial data was run with 32r1 or later
-VARBC_ARCHIVE_EVOLVE=false
-
-#==========================================================
-# New for 32r3
-#==========================================================
-LFULL_IASI=%LFULL_IASI:true% # true = use full iasi data and screen: false use screened data
-LGEMS=false # run with gems parameters
-GHGVAR=
-GRGVAR=
-AEROVAR=
-TRACVAR=
-INIGHG=false
-INIGRG=false
-INIAERO=false
-INITRAC=false
-LEVGEN=true # Use van Genuchten hydrology
-INIHTESSEL=true # if starteding from experiment where LEVGEN=true
-LCALC_RSTRHBIAS=%CALC_RSTRHBIAS:true%
-LUSE_RSTRHBIAS=%LUSE_RSTRHBIAS:true%
-LSSMI1D=true
-LSSMIS1D=true
-LAMSRE1D=true
-LTMI1D=true
-LAMSRE1D=true
-ODB_IO_OPENMP=1
-
-#==========================================================
-# New for 33r2
-#==========================================================
-LOBSCOR=false
-
-#==========================================================
-# New for 35r2
-#==========================================================
-
-LECURR=false
-INIECURR=false
-LSCATT_NEUTRAL=false
-D3GGFIELDSSTEND="0"
-LFSOBS=false
-LSEKF=false
-
-#==========================================================
-# New for 35r3
-#==========================================================
-# if EPS or associated then LEMISKF & LWEAK4DVAR=false
-INIOZONE=true
-
-WEAK4D_INTERV=0.0
-LMODERR_PERIODIC=false
-NSPLIT4DWIN=0
-LBALSTRATO=false
-AMSU_LAND=Dynamic_emis
-EMISKF_PATH=standard
-INIEMISKF=true
-INIMODERR=true
-LDUCTDIA=false
-LASCATSM=true
-if [[ %SUITE% = "e_*" ]] ; then LANOBSENS=true; fi
-
-#==========================================================
-# Variables configuring ifs_ctm
-#==========================================================
-LCOUPLO4=false
-CTM_MODEL=mozart
-NFRCOUPLO4=1
-NFRCOUPLO4_FB=1
-LGLOBALGP=true
-LGLOBALSP=true
-MPROCGPG=1
-MPROCSPG=1
-LOUT_SPC=false
-LOUT_FLUX=true
-LOUT_COOR=false
-LIN_GRG=true
-LIN_COOR=false
-LCOUPLO4_CTM=true
-LOUT_GRG=false
-LOUT_CO=false
-LOUT_SO2=false
-LOUT_NOX=false
-LOUT_NO2=false
-LOUT_GO3=false
-LOUT_HCHO=false
-LNOX2NO2=false
-INTERP2D=bilinear
-PARA_SEARCH=global
-IF_MASKED=novalue
-LGRG_CYCLE=true
-LDIFF_GRG=false
-LCONV_GRG=false
-LDIA_GRG=false
-NPROC_CTM=8
-NPROC_CTM_AN=8
-NPROC_DRV=1
-CTM_THREADS=4
-CTM_THREADS_AN=4
-DRV_THREADS=1
-DRV_THREADS_AN=1
-IFS_THREADS_AN=6
-LSTATS=true
-
-#==========================================================
-# Variables configuring Gems
-#==========================================================
-LGEMS=false
-GHGVAR=""
-INIGHG=false
-GRGVAR=""
-INIGRG=false
-AEROVAR=""
-INIAERO=false
-TRACVAR=""
-INITRAC=false
-
-#=======================================================================
-# DR_HOOK
-#=======================================================================
-DR_HOOK=true # 30r1 was false
-DR_HOOK_OPT="none" # 30r1 was "prof"
-DR_HOOK_PROFILE_LIMIT=-10
-DR_HOOK_HASHBITS=15
-DR_HOOK_CATCH_SIGNALS=false
-DR_HOOK_IGNORE_SIGNALS=false
-
-LIBHPM=""
-if [[ $DR_HOOK = true ]] ; then
- DR_HOOK_OPT=`echo $DR_HOOK_OPT | sed -e 's/\// /g'`
- if [[ $ARCH = ibm_power4 ]] ; then
- LIBHPM="-L/usr/pmapi/lib -lpmapi"
- fi
-fi
-
-#=======================================================================
-# BC project setup for analysis (only those that are different)
-#=======================================================================
-
-if [[ "%STREAM%" = SCDA ]] ; then
- PERIOD_4D=6 ;
- WINDOW_LENGTH_4D=%WINDOW_LENGTH_4D:12%
- WINDOW_OFFSET_4D=%WINDOW_OFFSET_4D:9%
-
- if [[ %MXUP_TRAJ:3% = 3 ]] ; then
-
- IFSMODE=4d_inc
-
- else
-
- IFSMODE=3d_fgat
- ITER_MIN=70
- ITER_MIN_1=0
- SIMUL_MIN=80
- SIMUL_MIN_1=0
- LISENTRPP=false
- LVERIFY_SCREEN=false
-
- fi
-else
- # PERIOD_4D=6 ; # 20040423 should stay 12 by default (for SCDA reinit), then SMS variable is set to 12, this variable is considered for reinit = false (vardata.sms)
-if [[ `echo %FAMILY:NOT_DEF% | cut -d / -f 1` = "main" ]] ; then
- ## RD behaviour : default is constant 12,
- ## if SMS variable is changed, task should consider it specifically
- ## some tasks (vardata, fetcherr) may want this default and not SMS
- ## variable for REINITIALIZE state
- PERIOD_4D=12
- WINDOW_LENGTH_4D=12
- WINDOW_OFFSET_4D=3
-
-else # SMS variable IS the environment variable for other families
- PERIOD_4D=%PERIOD_4D:12%
- WINDOW_LENGTH_4D=%WINDOW_LENGTH_4D:12%
- WINDOW_OFFSET_4D=%WINDOW_OFFSET_4D:3%
-fi
-fi
-
-#=================================================
-# Simplified Kalman filter parameters
-#=================================================
-
-TSTEP_SV=1200
-RESOLSV=42
-NLANTYPE=6
-NJDSTOP=48
-NITERL=60
-NINNER=30
-NEIGEVO=60
-HESSTYPE=3d
-SVPPFRQ=6
-
-
-################### New for 23r1 #############
-LATE4DSTART=true
-FPOSINC=false
-INICLOUDAN=true
-
-
-#=======================================================================
-# Satellite parameters
-#=======================================================================
-
-LTOVS=.false.
-LATOVS=true
-LAIRS=true # 31r1
-LSSMI=true # 33r1
-LSCAT=.true.
-LGEOS=true
-LRAIN1D=false # 35r2
-LSSMIRAIN=true # 33r2
-LSSMISRAIN=true # 35r3
-LTMIRAIN=true # 35r3
-LAMSRERAIN=true # 33r2
-LPRERAD1C=false
-LREO3=true
-LAEOLUS=false # 31r1
-LSSMIS=true # 31r2
-LAMSRE=true # 31r2
-LMERIS=true # 20080714 until which was false # 33r2
-LTMI=true # 31r2
-LGPSRO=true # 31r2
-
-BIAS_PATH_AMV=none
-BIAS_PATH_REO3=none
-LREO3_BCOR=false
-
-BIASCOLD=yes
-BIASDAYS=14
-BIASMISS=7
-BIAS_ARCHIVE=1
-
-if [[ "%SUITE%" = o || "%SUITE%" = e_* ]] ; then
- export FDB_NOF_BUFF=4
- export FDB_BUF_SECT_SIZE=25165824
-elif [[ "%SUITE%" = bc || "%SUITE%" = ebc_* ]] ; then
- export FDB_NOF_BUFF=3
- export FDB_BUF_SECT_SIZE=33554432
-else
- export FDB_NOF_BUFF=4
- export FDB_BUF_SECT_SIZE=4194304
-fi
-
-# 23r4
-RSTBIAS=true
-
-# 24r2
-ERAFS=false
-
-# SATMON parameters
-SMON_OPT_DIR=""
-SMON_OPT_GEOS=ops
-SMON_OPT_NOAA=ops
-SMON_OPT_DMSP=ops
-SMON_OPT_O3=ops
-SMON_OPT_O3KNMI=ops
-SMON_OPT_O3MSG=ops
-SMON_OPT_TEMP=ops
-SMON_OPT_PWC=ops
-SMON_OPT_AMV=ops
-SMON_OPT_DBAMV=ops # 33r1
-SMON_OPT_AIRS=ops
-SMON_OPT_IASI=ops # 32r3
-SMON_OPT_EARS=ops
-SMON_OPT_PACRARS=ops # 33r1
-SMON_OPT_MERIS=ops # 33r2
-SMON_OPT_SSMIS=ops # 31r2
-SMON_OPT_AMSRE=ops # 31r2
-SMON_OPT_TMI=ops # 31r2
-SMON_OPT_GPSRO=ops # 31r2
-SMON_OPT_SCATT=ops # 35r3
-SMON_OPT_SLMOIST=ops # 35r3
-
-
-SATROOT=/od_archive/data/satmon
-
-#==========================================================
-# Variables configuring Reanalysis
-#==========================================================
-MEANS=true
-MOMENTS=true
-INTEGRALS=true
-INCREMENTS=true
-PLOTS=true
-RSTBIAS_TS=false
-RSTBIAS_SE=true
-ERAPRODUCTS="/era/intprod/data/monitor"
-
-#=======================================================================
-# Coupled wave model parameters
-#=======================================================================
-
-WAVE=yes
-WAM2WAY=yes
-WAMNSTPW=1
- if [[ "%FSFAMILY%" = @(mc|refc|assim) ]] ; then
-WAMRESOL=global100
-else
-WAMRESOL=global36 # HR global50
-fi
-WAMALT=yes
-WAMSAR=yes
-WAMSARASS=true
-
-if [[ "%FSFAMILY%" = "euroshelf" || $SUITE_TYPE = "law" ]] ; then # law suites
- WAMNFRE=30 # 36 future 0044
- WAMNANG=24 # 36 future 0044
-else
- WAMNFRE=30
- WAMNANG=24
-fi
-
-date_ers1_wave=1994010100
-
-if [[ $BASETIME -lt $date_ers1_wave || $WAMALT != yes ]] ; then
- WAMANPARAM_DYN="215/216/220/221/222/223/224/225/226/227/228/229/230/231/232/233/234/235/236/237/238/239/244/245/249"
-else
- WAMANPARAM_DYN="215/216/217/218/220/221/222/223/224/225/226/227/228/229/230/231/232/233/234/235/236/237/238/239/244/245/246/247/248/249/252/253/254"
-fi
-
-WAMANPARAM_STAT="219"
-WAMANPARAM=$WAMANPARAM_STAT/$WAMANPARAM_DYN
-
-WAMFCPARAM_STAT="219"
-WAMFCPARAM_DYN="215/216/217/218/220/221/222/223/224/225/226/227/228/229/230/231/232/233/234/235/236/237/238/239/244/245/249/252/253/254"
-WAMFCPARAM=$WAMFCPARAM_STAT/$WAMFCPARAM_DYN
-
-INIWAVE=yes
-WAMCOLDLENGTH=240
-WAMSTREAM=0
-# Many of these values are overridden for
-# local area model in law.h
-
-if [[ "%STREAM%" = SCDA ]] ; then
- WAMSTREAM=1027
-elif [[ "%STREAM%" = DCDA ]] ; then
- WAMSTREAM=1029
-fi
-
-#=======================================================================
-# Initial data parameters
-#=======================================================================
-
-
-INITIME=%INITIME:2001042900%
-INICLASS=%INICLASS:od%
-INISTREAM=%INISTREAM:da%
-# da : early delivery suite initialised from standard suite
-# dcda : early delivery suite initialised from another delayed cutoff suite
-INITYPE=4v
-INIEXPVER=%INIEXPVER:0001%
-INILEVELS=%INILEVELS:60%
-INISTEP=%INISTEP:0%
-# size of the 4dvar window
-
-# offset from the beginning of the 4V for FC
-INIOFFSET_4D=%INIOFFSET_4D:3%
-# 9 : early delivery suite initialised from standard suite
-# 3 : early delivery suite initialised from another ealry delivery suite
-INITILES=true
-INIRESOL=799 # was 511
-INICI=true
-FORCE_FP=no
-
-if [[ "%FAMILY1:NOT_DEF%" = sv || "%FAMILY1:NOT_DEF%" = m2_12 || "%FAMILY1:NOT_DEF%" = m2_00 || "%FAMILY1:NOT_DEF%" = m1_12 || "%FAMILY1:NOT_DEF%" = m1_00 ]] ; then
- INITYPE=fc
-# ------- vv
-# INISTEP=12 # for 00,12 UTC forecasts
-# ------- ^^
- INISTEP=6 # for 06,18 UTC forecasts
- INISTREAM=dcda
- INISUFFIX="_sv"
-else
- INISUFFIX=
-fi
-
-if [[ "$ARCH" != "linux" ]];then
- typeset -l REINITIALIZE
-fi
-REINITIALIZE=%REINITIALIZE:false%
-REINIEXPVER=%REINIEXPVER:0001%
-REINISTREAM=%REINISTREAM:da%
-REINIPERIOD_4D=%REINIPERIOD_4D:12%
-REINIOFFSET=%REINIOFFSET:12%
-ED_CUTOFF=%ED_CUTOFF:4%
-
-#=================================================
-# PE settings
-#=================================================
-NPES_MKCMA=%MKCMANPES:1%
-NPES_AN=%ANNPES:1%
-NPES_FC=%FCNPES:1%
-NPES_SV=%FCNPES:1%
-#=================================================
-# PREPAN parameters
-#=================================================
-
-OWNER=emos
-AMASTER=/ws/home/ma/emos/amaster/xxxx
-RUN_PARALLEL=true
-
-#=======================================================================
-# Sami's variables + ODB
-#=======================================================================
-
-CONCAT=1
-PMETHOD=2
-FSODB=/emos_backup
-
-ODB_CTX_DEBUG=0
-ODB_MAXHANDLE=5
-ODB_STATIC_LINKING=1
-ODB_UNDEF=2146959359
-ODB_CCMA_CREATE_DIRECT=1
-ODBSAVE_ODBCMP=true #31r2
-ODB_FROM_FB=false
-if [[ "%STREAM%" = SCDA ]] ; then
- ODBSAVE_CCMA=false
- ODBSAVE_ECMA=false
-else
- ODBSAVE_CCMA=true
- ODBSAVE_ECMA=true
-fi
-ODB_CATCH_SIGNALS=0
-ODB_CCMA_IGNORE_TSLOTS=0
-ODB_CCMA_OBS_RANDOMIZE=0
-ODB_CCMA_WTMETHOD=107
-ODB_ERRTRA=1
-ODB_FLPCHECK=0
-ODB_INTCHECK=0
-ODB_IO_METHOD=4
-ODB_IO_FILESIZE=128
-ODB_PACKING=-1
-ODB_REPRODUCIBLE_SEQNO=4
-ODB_TEST_INDEX_RANGE=0
-ODB_WRITE_EMPTY_FILES=0
-
-MANPATH=""
-#=======================================================================
-# Coupled wave variables
-#=======================================================================
-
-WGRIBIN=yes
-
-#================================
-# New for 19r1, should be put in correct place.
-
-HESS3D=3d
-PPFRQ=12
-LINCNMI=false
-NEIGEVO=60
-#================================
-# New for 24r4
-
-LMAPSOP=false
-MPP_TYPE=1
-if [[ "%STREAM%" = SCDA ]] && [[ %MXUP_TRAJ:3% = 1 ]] ; then
- LTRAJHR=false
-else
- LTRAJHR=true
-fi
-
-#================================
-# New for 26r3
-
-LMODERR=false
-
-#=======================================================================
-# Plot control
-#=======================================================================
-
-PLOT_RMS=true
-
-#=======================================================================
-# Standard libraries
-#=======================================================================
-
-SCHOST=%SCHOST%
-SCHOST_BKUP=%SCHOST_BKUP:not_set%
-# storage host
-STHOST=%STHOST:%
-STHOST_BKUP=%STHOST_BKUP%
-WSHOST=%WSHOST%
-
-LIBRESOL=.R64.D64.I32
-ELIB=/usr/local/lib/metaps/lib/${EMOS_CYCLE}
-
-if [[ $ARCH = ibm_power* ]] ; then
- SLIB=/usr/local/lib
-###########################################
-#temporary setting: A.Hofstadler, 200200821
- EMOSLIB="-lemos.R64.D64.I32"
- ECLIB="-L $SLIB "
- FDBLIB="-L $SLIB -lfdb"
-#temporary setting:
-###########################################
- EMOSLIB="-L $ELIB $EMOSLIB"
- OBJECT_MODE=64
- XLFRTEOPTS=err_recovery=no
-else
-###########################################
-#temporary setting: A.Hofstadler, 200200821
-# EMOSLIB="-lemos.R64.D64.I32"
- EMOSLIB="-lemos.R32.D64.I32" # or single???
-#temporary setting:
-###########################################
- SLIB=/usr/local/lib
- EMOSLIB="-L $ELIB $EMOSLIB"
-fi
-
-emosbin=/home/ma/emos/bin/${EMOS_CYCLE}/$ARCH
-#=======================================================================
-# Singular vector configuration
-# NSVHEM=1 for SVs over NH only
-# 2 " SH only
-# 3 " NH+SH
-#=======================================================================
-
-EPSSVPATH=
-EPSSVROTPATH=
-EPSFCRES=%EPSFCRES:399% # HR 255
-
-# VAREPS 30r2
-EPSFCRES_A=%EPSFCRES_A:399% # HR 255
-EPSFCRES_B=%EPSFCRES_B:255% # HR 255
-EPSFCRES_C=%EPSFCRES_C:255% # HR 255
-
-EPSFCLENGTH_A=%EPSFCLENGTH_A:240%
-EPSFCLENGTH_B=%EPSFCLENGTH_B:144%
-EPSFCLENGTH_C=%EPSFCLENGTH_C:408%
-
-EPSINISTEP_B=%EPSINISTEP_B:216%
-EPSINISTEP_C=%EPSINISTEP_C:360%
-
-EPSFCGTYPE=%EPSFCGTYPE:l_2%
-EPSFCGTYPE_A=%EPSFCGTYPE_A:l_2%
-EPSFCGTYPE_B=%EPSFCGTYPE_B:l_2%
-EPSFCGTYPE_C=%EPSFCGTYPE_C:l_2%
-
-EPSVARHDIF=false
-EPSVARHDIFT=24
-
-EPS_USE_ICP=0
-# /VAREPS
-
-EPSFCLEV=%EPSFCLEV:62% # HR 40
-EPSSVRES=%EPSSVRES:42%
-EPSSVGTYPE=_full
-EPSSVLEV=%EPSSVLEV:62% # HR 40
-EPSMEMBERS=`echo "%ENSEMBLES:50% + 1" | bc`
-EPSNENS=%ENSEMBLES:50%
-EPSEVO=1
-EPSHEM=%EPSHEM:3%
-EPSEVOTIME=48
-
-EPSWAMRESOL=%EPSWAMRESOL:global100%
-EPSWAMNSTPW=%EPSWAMSTPW:1%
-EPSTSTEP=%TSTEP:1800% # HR 2700
-EPSSVTSTEP=%EPSSVTSTEP:900%
-
-if [[ %STREAM% = MAED ]] ; then
- INIMODISALB=false
-TSTEP=$EPSTSTEP
-fi
-
-EPSTSTEP_SV=900 # HR 1200
-EPSWAMALT=no
-EPSTYPE=%EPSTYPE%
-EPSMEMBER=%MEMBER%
-FCTOTAL=$EPSMEMBERS
-NTOTAL=$EPSNENS
-EPSSVDIAB=%EPSSVDIAB:false%
-EPSSVNUM=%EPSSVNUM:0%
-
-# 28r3
-DELTAHH_TC_TRACKS=12 # 12h lag from previous TC used in targets task
-EPSSV_TOPT=48 # optimization time for the tropical singular vectors
- # targets
-
-TC_TRACKS_EXPVER=%VERSION:0001% # ???TDB
-
-if [[ %VERSION:0001% = 0020 ]] ; then
- TC_TRACKS_EXPVER=0001
-fi
-
-OD_PROJ=%OD_PROJ:od%
-
-if [[ "%SUITE%" = emc* ]] && [[ %IS_REAL_TIME:false% = false ]] ; then
- TC_TRACKS_PATH=/emos/tc/0001
-elif [[ $REINITIALIZE = true ]] ; then
- TC_TRACKS_PATH=/emos/tc/$REINIEXPVER
-elif [[ %FIRST_DAY% = 1 ]] ; then
- TC_TRACKS_PATH=/emos/tc/$INIEXPVER
- TC_TRACKS_EXPVER=0001
-elif [[ ! "$OD_PROJ" = "od" ]] ; then
-# || [[ %IS_REAL_TIME:false% = false ]] ; then
- ## MC_NO and other MS suites
- ## and catchup mode running 12 cycle only
- TC_TRACKS_PATH=/emos/tc/0001
-else
- TC_TRACKS_PATH=/emos/tc/%VERSION%
-fi
-
-TC_TRACKS_FROM_MARS=true
-TC_TRACKS_CLASS=od
-
-EPSSVTCSUB=%EPSSVTCSUB:0%
-EPSTCBB=%EPSTCBB:1% # use TC tracks to define optimization regions
-EPSSVOP=%EPSSVOP:0% # not required to set sms variable in OD
-EPSSVTC_ORTHONORM=1 # ortho-normalize tropical SVs
-
-RUNHINDCAST=%RUNHINDCAST:0% # 1 for back loop and 0 for realtime
-
-#=======================================================================
-# EFI PATHS:
-#=======================================================================
-EFI_WS_CACHE=/efi_clim/data/cache
-EFI_WS_SCRATCH=/efi_clim/data/scratch
-EFI_ECFS_PATH=ec:/emos/efi_clim
-EFI_HPCF_PATH=/home/ma/emos/data/efi_clim
-#=======================================================================
-# Ocean model configuration
-#=======================================================================
-
-OCVER=h2e2
-ASVER=cy2r3
-
-#=======================================================================
-# Configuration for sensitivity suite
-#=======================================================================
-
-SENSFCRES=255
-SENSFCLEV=60
-SENSADJRES=63
-SENSADJLEV=60
-SENSADJGTYPE=_2
-SENSFCGTYPE=l_2
-SENSADJSTEP=48
-SENSADJTSTEP=600.0
-SENSRUNFC=yes
-INISPQ=no
-
-#new for 25r1
-SENSADJADVEC=euler
-SENSFORCE=false
-SENSDIAB=true
-SENSITER=6
-
-#=======================================================================
-# The disk configuration
-# Look at e-suite configuration below also
-#=======================================================================
-
-if [[ $ARCH = ibm_power* ]] ; then
- if [[ "%SUITE%" = mc_no ]] ; then
- TROOT=$STHOST/ms_crit/teps
- WROOT=$STHOST/ms_crit/teps
- OROOT=$STHOST/emos_data
- FDB_ROOT=$STHOST/ms_crit/fdb
- FDB_IROOT=$STHOST/ms_crit/fdb
- WAVEEPS_ROOT=$FDB_ROOT
- WAVEEPS_IROOT=$FDB_IROOT
- elif [[ "%SUITE%" = e*35r3* || "%SUITE%" = "e_sync" || "%SUITE%" = "emc_no*" ]] ; then
- TROOT=$STHOST/emos_esuite/emos_data
- WROOT=$STHOST/emos_esuite/emos_data
- OROOT=$STHOST/emos_data
- WBASE=/
- FDB_ROOT=$STHOST/emos_esuite/ma_fdb
- FDB_ROOT_BKUP=$STHOST_BKUP/emos_esuite/ma_fdb
- FDB_IROOT=$STHOST/emos_esuite/ma_fdb
- WAVEEPS_ROOT=$FDB_ROOT
- WAVEEPS_IROOT=$FDB_IROOT
- else
- TROOT=$STHOST/emos_data
- WROOT=$STHOST/emos_data
- OROOT=$STHOST/emos_data
- FDB_ROOT=$STHOST/ma_fdb
- FDB_ROOT_BKUP=$STHOST_BKUP/ma_fdb
- FDB_IROOT=$STHOST/ma_fdb
- WAVEEPS_ROOT=$STHOST$FDB_ROOT
- WAVEEPS_IROOT=$STHOST$FDB_IROOT
- fi
- if [[ "%FSFAMILY%" = mars ]] ; then
- WROOT=/od_archive/data
- fi
-elif [[ $ARCH = linux ]] ; then
- TROOT=/var/tmp/tmpdir/emos
- WROOT=/var/tmp/tmpdir/emos
- OROOT=/var/tmp/tmpdir/emos
- FDB_ROOT=""
- FDB_IROOT=""
-else
- TROOT=/var/tmp/emos
- WROOT=/var/tmp/emos
- OROOT=/var/tmp/emos
- FDB_ROOT=""
- FDB_IROOT=""
-fi
-
-WBASE=${WROOT}/${EXPVER}
-
-XROOT=/home/ma/emos
-XLIB=$XROOT/lib/${IFS_CYCLE}
-XDATA=$XROOT/data
-XBINS=$XROOT/bin
-XMOD=/cc/rd/module/frt
-XSRC=$XROOT/src
-ODATA=/home/ma/emos/data
-SCRATCH=/ws/scratch/ma/emos
-
-FSROOT=/$USER
-FSOROOT=/emos
-FSFAMILY=""
-FSXDATA=/emos/data
-FSXBINS=/emos/$ARCH/bin
-
-#=======================================================================
-#
-# The following is the configuration filled in by the SMS
-#
-#=======================================================================
-
-#EXPVER=%VERSION% # done further up...
-
-if [[ "%USE_YMD:false%" = true ]] ; then
- BASETIME=%YMD%%EMOS_BASE%
-else
- BASETIME=%YYYY%%MM%%DD%%EMOS_BASE%
-fi
-
-FSFAMILY=%FSFAMILY%
-
-ECF_PASS=%ECF_PASS%
-ECF_NODE=%ECF_NODE%
-ECF_NAME=%ECF_NAME%
-ECF_TRYNO=%ECF_TRYNO%
-
-ECF_HOSTFILE=$HOME/.smshostfile
-ECF_PORT=%ECF_PORT%
-ECF_JOBOUT=%ECF_JOBOUT%
-
-
-SUITE=%SUITE%
-FAMILY=%FAMILY:NOT_DEF%
-TASK=%TASK%
-
-DEBUG=0
-DISPLAY=0
-
-# INFORM_EMOS_AUTORESOL=1
-
-#
-# For e-suites only
-#
-if [[ $EXPVER -eq 2 ]] ; then
- BASEVER=0002
-fi
-
-#Multianalysis
-INIMA="%INIMA:ecmwf%"
-INIMACONS=%INIMACONS:0%
-INIORIG=mars
-MANNCEP=0
-MANMFR=0
-MANDWD=0
-MANUKM=0
-
-INIORIGIN=OFF
-MAORIGINS="CONS"
-MAMISSING="%MAMISSING:%"
-
-if [[ %STREAM% = "MAED" || %STREAM% = MAWV ]] ; then
- WAMRESOL=global100
- WAMNFRE=30
- WAMNANG=24
- INIOZONE=false
- LOZONE=false
- LOZONECH=false
- RESOL=399
- LEVELS=62
-
- for xxx in $INIMA ; do
- if [[ "$xxx" = ncep ]] ; then
- MANNCEP=1
- MAORIGINS="$MAORIGINS KWBC"
- elif [[ "$xxx" = mfr ]] ; then
- MANMFR=1
- MAORIGINS="$MAORIGINS LFPW"
- elif [[ "$xxx" = ukm ]] ; then
- MANUKM=1
- MAORIGINS="$MAORIGINS EGRR"
- elif [[ "$xxx" = dwd ]] ; then
- MANDWD=1
- MAORIGINS="$MAORIGINS EDZW"
- fi
- done
-
-
- # Find WMO centre number. Do this more cleverly
- if [[ $INIMACONS -eq 1 ]] ; then
- INIORIGIN=CONS
- elif [[ $INIMA = mfr ]] ; then
- INIORIGIN=LFPW
- elif [[ $INIMA = ncep ]] ; then
- INIORIGIN=KWBC
- elif [[ $INIMA = ukm ]] ; then
- INIORIGIN=EGRR
- elif [[ $INIMA = dwd ]] ; then
- INIORIGIN=EDZW
- fi
-
-fi
-
-#=================================================
-# For mars compute. This will use model number found.
-# If not set, model number will be 255.
-export MARS_COMPUTE_FLAG=0
-
-# User for e-suite plots
-EPLOT_USER=mos
-
-set +a
-
-if [[ %DELTA_DAY% -ne 0 ]] ; then
- delta=`expr %DELTA_DAY% \* 24`
- BASETIME=`newdate $BASETIME $delta`
-fi
-
-if [[ $FSFAMILY = "refc" ]] ; then
- HC_REFDATE=`echo $BASETIME | cut -c 1-8`
- EPSTYPE=fc
-
- export HC_REFDATE EPSTYPE
-
- if [[ %YEAR:0% -ne 0 ]] ; then
- YEAR=%YEAR:0%
- YYYY=`echo $BASETIME | cut -c 1-4`
- MM=`echo $BASETIME | cut -c 5-6`
- DDHH=`echo $BASETIME | cut -c 7-10`
- if [[ $MM$DDHH = 0229* ]] ; then
- BASETIME=`newdate $(( $YEAR$MM$DDHH - 100 )) 24 `
- else
- BASETIME=$YEAR$MM$DDHH
- fi
- fi
-fi
-
-DELTA_YEAR=%DELTA_YEAR:0%
-YYYY=`echo $BASETIME | cut -c 1-4`
-YYYY=$(( $DELTA_YEAR + $YYYY ))
-if [[ $DELTA_YEAR -ne 0 ]] ; then
- YYYY=`echo $BASETIME | cut -c 1-4`
- DELTA_YEAR=%DELTA_YEAR:0%
- MMDDHH=`echo $BASETIME | cut -c 5-10`
- YYYY=$(( $DELTA_YEAR + $YYYY ))
- BASETIME=$YYYY$MMDDHH
- YMD=$(substring $BASETIME 1 8)
-fi
-
-DELTA_HOUR=%DELTA_HOUR:0%
-if [[ $DELTA_HOUR -ne 0 ]] ; then
- BASETIME=`newdate $BASETIME $DELTA_HOUR`
-fi
-
-# remove when hpcf gone
-if [[ $HOST = hpc* ]] ; then
- EMOSLIB="-qextname $EMOSLIB"
-fi
-
-if [[ $ARCH = linux ]] ; then
- export LINK_C="pgf90 -tp k8-32 -g"
- export LINK_F="pgf90 -tp k8-32 -g"
-fi
-
-if [[ "%OD_PROJ:od%" = no ]] ; then
- ### TEPS project
- EPSHEM=1
- EPSGAMMA=0.016
- EPSBASIS=10
- EPSMEMBERS=21
- EPSNENS=20
- GRIBCLASS=113 # from http://www.ecmwf.int/publications/manuals/libraries/gribex/gribClass.html
-fi
-
-#=====================================================================
-# ocean model configuration
-#======================================================================
-export RUNVARFC=%RUNVARFC:0%
-export EPSLEG=%EPSLEG:1%
-if [[ $RUNHINDCAST = 1 ]] ; then
- # export HC_REFDATE=%YMD%
- export HC_REFDATE=$((YYYY -(DELTA_YEAR)))`echo $BASETIME | cut -c 5-8`
-
-INIMODISALB=false # if intial data was run with 32r1 or later
-
-#==========================================================
-# Variables configuring inidata
-#==========================================================
-INIPATH="/net/fujitsu/ifs/initial/t95r/ic_19r1_%YMD%"
-INISTREAM=DA
-INITYPE=an
-INISTEP=0
-INISPQ=no
-LFG=.true.
-INIOFFSET=0
-INISCHEME=lslag
-SAVINI=""
-SVRF=no
-IFRF=no
-FORCE_FP=no
-
-INICLASS=`oper_model -b $BASETIME -c`
-INIRESOL=`oper_model -b $BASETIME -r`
-INILEVELS=`oper_model -b $BASETIME -l`
-INIGTYPE=`oper_model -b $BASETIME -t`
-INIEXPVER=`oper_model -b $BASETIME -e`
-INITILES=`oper_model -b $BASETIME -T`
-INICLOUDAN=`oper_model -b $BASETIME -C`
-
-if [[ %RUNHINDCAST:0% = 0 ]] ; then
- INILEVELS=91
- INIRESOL=799
-
-if [[ $BASETIME -le %ERA40END:2002073100% ]] ; then
- INICLASS=e4
- INILEVELS=60
- INIEXPVER=0001
- INITILES=true
- INICLOUDAN=true
- INIMODISALB=false
- EPSGAMMA=0.018
-fi
-
-else # HINDCAST mode
- INICLASS=ei
- INILEVELS=60
-
- if [[ $BASETIME -lt 2008010100 ]] ; then
- INIEXPVER=0001
- else
- INIEXPVER=1112 # temporary while Manuel is changing 1112 to 0001
- fi
- EPSGAMMA=0.016 # to be updated according to Martin Leutbecher
- INIRESOL=255
- INIMODISALB=true
- INIHTESSEL=false
- INITILES=true
-fi
-
-fi
-
-export MARS_CMD='mars'
-
-if [[ %RUNHINDCAST:0% = 1 ]] ; then
- INIHTESSEL=`oper_model -b $BASETIME -I ${CLASSORIG:="er_ops"} -H`
-fi
-
-### check if MOFC-VarEps is to run
- sim=`newdate -d -D $BASETIME`
- real=`date +'%%Y%%m%%d'`
- real=`newdate -d -D $real`
- dow=`date +'%%u'`
- res=$((($sim - $real + $dow) %% 7))
-
- if [[ $((res)) -lt 0 ]] ; then res=$((res+7)); fi
-
- RUN_VAREPS=0
- if [[ $res = 4 ]] ; then # Thursday MOFC
- RUN_VAREPS=1
- fi
- export EPSNLEGS=$((2+$RUN_VAREPS)) # do not refer to sms variables while this changes
- # 35r2
- export EPSCOUPL_A=no # 35r2
- export EPSCOUPLE_A=0 # 35r2
- CC=`substring $BASETIME 9 10` # later EMOS_BASE
- export EPSCOUPLE_B=$((CC == 00)) # 35r2
- export EPSCOUPLE_C=$RUN_VAREPS # 35r2
-
-
-export RUN_VAREPS
-###########
-export OCNINDAT=$(substring $BASETIME 1 8) # 19900101
-
-if [[ $EPSLEG != 1 ]] || [[ $RUNVARFC = 1 ]] ; then
-set -a
-
-
-ENAMELIST=general
-FULL_POS=yes
-LPPL=1
-LPSU=1
-LPPV=0
-LPTH=0
-LPGZ=0
-PPSTEPS="0"
-ERF=408
-FRQRF=-1
-DATE_BRANCH=2005112409
-USEDATE_BRANCH=no
-VIEW=""
-VIEW_HOPE="hope_h2e20"
-OCEPS=no
-OCUSESV=no
-EPSLROT=no
-OCPATM=yes
-OCFCRESOL=255
-OCFCLEVELS=62
-OCFCGTYPE=l_2
-OCFCTSTEP=%TSTEP:1800%.0
-FCCHUNKTOT=1
-NEWSTREAMLIB=none
-SAVLIB=false
-OCEAN_BRANCH="neh_h2e20_enfo"
-OCEAN_CYCLE="h2e20"
-OCIAUFR=2
-if [[ $RUNHINDCAST = 1 ]] ; then
-
-GRIB_API_VERSION=1.7.0
-GRIB_API_INCLUDE="-I/usr/local/lib/metaps/lib/grib_api/jasper/include -I/usr/local/lib/metaps/lib/grib_api/$GRIB_API_VERSION/include"
-GRIB_API_LIB="-L/usr/local/lib/metaps/lib/grib_api/jasper/lib -ljasper -L/usr/local/lib/metaps/lib/grib_api/$GRIB_API_VERSION/lib -lgrib_api_f90 -lgrib_api"
-export GRIB_API=/usr/local/lib/metaps/lib/grib_api/$GRIB_API_VERSION/bin # change to fixed version
-export PATH=$GRIB_API:$PATH
-
- if [[ $HC_REFDATE -lt 20080605 ]] ; then
- OCINI="seas_0001_01_NN_${OCNINDAT}_od_02"
- else
- OCINI="ocea_0001_01_NN_$(substring $BASETIME 1 8)_od_03"
- fi
-else
- OCINI="ocea_0001_01_NN_$(substring $BASETIME 1 8)_od_03"
-fi
-OCNEWREST=false
-OCNMINI="00"
-CLASSORIG=e4_ops
-
-OCRUNCTRLAN=no
-OCRUNCTRLAC=no
-OCRUNCTRLFC=no
-OCRUNASSIMAN=no
-OCRUNASSIMAC=yes
-OCRUNASSIMFC=yes
-MEMBERSTATE=no
-%include <config.oc.h>
-
- OCINPUT=mars
- OCSUITE=vareps
- if [[ -n $OCINI ]] ;then
- OCINPUT=$(substring $OCINI 1 4)
- fi
-
- if [[ $OCINPUT != 'ecfs' ]] ; then
- OCSTREAM_INI=$OCINPUT
- if [[ $OCINPUT = 'mars' ]];then
- OCSTREAM_INI='ocea' # 'seas'
- fi
- if [[ $OCINPUT = 'seas' ]];then
- OCINPUT='mars'
- fi
- if [[ $OCINPUT = 'mofc' ]];then
- OCINPUT='mars'
- fi
- OCEXPVER_INI=0001 # $(substring $OCINI 6 9 )
- OCMETHOD_INI=$(substring $OCINI 11 12 )
- OCNUMBER_INI=$(substring $OCINI 14 15 )
- OCDATE_INI=$(substring $OCINI 17 24 )
- OCCLASS_INI=$(substring $OCINI 26 27 )
- OCSYST_INI=$(substring $OCINI 29 30 )
- fi
-
-# For EPS runs only. Change of EPSNORM
-#
- LASTERA40=%ERA40END:2000070100%
-
- if [[ $OCEPS = "yes" ]] ; then
- if [[ $BASETIME -le 2001031400 ]] || [[ $BASETIME -le $LASTERA40 ]] ;
- then
- EPSNORM=2.0
- EPSNORMT=2.0
- fi
- EPSTROP=%EPSTROP:$EPSTROP%
- EPSSVDIAB=%EPSSVDIAB:$EPSSVDIAB%
- EPSSVNUM=%EPSSVNUM:$EPSSVNUM%
- fi
-
-#=======================================================================
-# special mofc variables
-#=======================================================================
-
-# pop/web/mofc
-
-MOFC_PROCESS=$WROOT/data/%SUITE%_process
-MOFC_PROCESS=`echo $MOFC_PROCESS | sed -e 's/var\/tmp\/tmpdir\/emos\/data/emos_data/'`
-Y=`echo $BASETIME | cut -c 1-4`
-STREAM=EF
-CLIMYEAR1=$((Y + - %NH_YEARS:18%))
-CLIMYEAR2=$((Y - 1))
-OCUTILS=$XBINS/$STREAM/$EXPVER
-
-export NH_ENSEMBLES=%NH_ENSEMBLES:4%
-export MOFC_PROCESS
-
-if [[ %RUNHINDCAST:0% = 1 ]] ; then
- MOFCCLIM_VERIF=$WROOT/data/%SUITE%_clim
- [[ -d $MOFCCLIM_VERIF ]] || mkdir -p $MOFCCLIM_VERIF
- MOFC_VERIFY=/gpfs1/emos_verify/data/%SUITE%_verify
- export PATH=$PATH:$HOME/bin/EF/verify
- [[ -d $MOFC_VERIFY ]] || mkdir -p $MOFC_VERIFY
-
- INIHTESSEL=`oper_model -b $BASETIME -I ${CLASSORIG:="er_ops"} -H`
-fi
-
-fi
-
-set -a
-
-if [[ %EPSTYPE:cf% = sv ]] ; then
- INIMODISALB=false
-fi
-
-if [[ "%STREAM%" = EF ]] ; then
- INIPERIOD_4D=%INIPERIOD_4D:12%
-else
- INIPERIOD_4D=12
-fi
-
-if [[ "%FSFAMILY:0%" != refc ]] && [[ %RUNHINDCAST:0% != 1 ]] ; then
- LVARBC=true
-else
- LVARBC=false
- INIMODISALB=false # if intial data was run with 32r1 or later
-
- date4v12h=2000091200
- # CHANGE date_dcda=2004062900
- date_dcda=2004062912
- if [ $BASETIME -ge $date4v12h ] ; then
- INIPERIOD_4D=12
- fi
- if [ $BASETIME -ge $date_dcda ] ; then
- INIPERIOD_4D=6
- fi
-fi
-
-inidate=`echo $BASETIME | cut -c 1-8`
-if [ ${inidate} -ge 19971125 ] && [ $INICLASS = od ] && [ $INIPERIOD_4D = 6 ] ; then
- INIOFFSET_4D=3
-elif [ $INICLASS = ei ] ; then
- INIOFFSET_4D=9
-elif [ $INICLASS = e4 ] ; then
- INIOFFSET_4D=3
-elif [ $INIPERIOD_4D = 12 ] ; then
- if [[ %RUNHINDCAST:0% = 1 ]] || [[ %STREAM:UNDEF% = EF ]] ; then
- INIOFFSET_4D=9
- else
- INIOFFSET_4D=3
- fi
-elif [ $INIPERIOD_4D = 6 ] ; then
- INIOFFSET_4D=3
-else
- INIOFFSET_4D=0
-fi
-
-### SST ###
-CLMSST=no
-PERSST=%PERSST:false%
-FORCE_SST=no
-SSTLEN=%SSTLEN:240%
-SSTINT=%SSTINT:1%
-LOSTIA=%LOSTIA:true% # 33r2
-
-NUMBER=%FCTOTAL:NOT_SET%
-VAR=%VAR:NOT_SET%
-CNUMBER=5
-
-if [[ "%SUITE%" = @(mc*|emc*|mofc*|emofc*|ma|tparc*|dts*) || $SUITE_TYPE = "eps" ]] ; then
- LWEAK4DVAR=false
- LEMISKF=false
- LOZONE=false
- INIOZONE=false
- LOZONECH=false
- LVARBC=false
-else
- LWEAK4DVAR=true
- LEMISKF=true
-fi
-
-
-set +a
-
-
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/config.oc.h b/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/config.oc.h
deleted file mode 100644
index 6cee2ef..0000000
--- a/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/config.oc.h
+++ /dev/null
@@ -1,197 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-# EXPVER=et34
-#==========================================================
-# Variables configuring emptyNamelist
-#==========================================================
-ENAMELIST=general
-#
-#==========================================================
-# Variables configuring wsconfig
-#==========================================================
-
-# WSHOST=metis
-# SCRATCH="/scratch/rd/rdx"
-#
-#==========================================================
-# Variables configuring ppgeneral
-#==========================================================
-
-IFSMODE=fc
-#PERIOD=6
-#PERIOD_4D=12
-
-FULL_POS=yes
-LPPL=1
-LPSU=1
-LPML=0
-LPPV=0
-LPTH=0
-LPGZ=0
-#PPFRQ=24
-PPSTEPS="0"
-#BRF=0
-ERF=408
-FRQRF=-1
-#
-#==========================================================
-# Variables configuring Ozone
-#==========================================================
-LOZONE=false
-LOZONECH=false
-#
-#==========================================================
-# Variables configuring clearcase
-#==========================================================
-#PROJECTS="none"
-DATE_BRANCH=2005112409
-USEDATE_BRANCH=no
-VIEW=""
-VIEW_HOPE="hope_h2e20"
-#
-#==========================================================
-# Variables configuring eps_svect
-#==========================================================
-OCEPS=no
-OCUSESV=no
-EPSLROT=no
-EPSNLEGS=%EPSNLEGS:3%
-EPSFCLEV_A=40
-EPSTSTEP_A=1800
-EPSFCLEV_B=40
-EPSTSTEP_B=%TSTEP:2700% # 2700
-EPSFCLEV_C=40
-EPSTSTEP_C=%TSTEP:2700% # 2700
-
-#
-#==========================================================
-# Variables configuring Dr_Hook
-#==========================================================
-#DR_HOOK=true
-#DR_HOOK_OPT="none"
-#DR_HOOK_PROFILE_LIMIT=-10
-#DR_HOOK_HASHBITS=15
-#DR_HOOK_CATCH_SIGNALS=0
-#DR_HOOK_IGNORE_SIGNALS=0
-#
-#==========================================================
-# Variables configuring wavgeneral
-#==========================================================
-#WAVE=yes
-#INIWAVE=yes
-#WAM2WAY=yes
-#WAMALT=no
-#WAMSAR=no
-#WAMSARASS=false
-#WGRIBIN=yes
-#WAMNSTPW=1
-#WAMRESOL=global100
-#WAMCOLDLENGTH=240
-WAMNFRE=%EPSWAMNFRE:25%
-WAMNANG=%EPSWAMNANG:12%
-#WAMFCPARAM="229/230/231/232/220/221/244/233/245"
-#
-#==========================================================
-# Variables configuring compile
-#==========================================================
-OCPATM=yes
-#LD="mpxlf90_r"
-#LDCC="xlc_r"
-#USE=standard
-#USECC=vac_6000
-#PARALLEL=4
-#NATIVE=true
-#F90_DEBUG=0
-#RUN_PARALLEL=true
-#EC_FILL_NANS=false
-#
-#==========================================================
-# Variables configuring system
-#==========================================================
-# ABO all comments
-#FSROOT="/RDX/prepIFS"
-#FSOROOT="/emos"
-#ABO FSXDATA="/ocx/data"
-#ABO FSXBINS="/ocx/$ARCH/bin"
-#ACCOUNT=ecrmoc
-#USER=ocx
-#GROUP=rd
-#FDB_GROUP=ecmwf
-#BASEVER=0001
-#CLASS=rd
-#GRIBCLASS=2
-#NOW=2005112409
-#MEMBERSTATE=no
-#
-#==========================================================
-# Variables configuring submit
-#==========================================================
-#SMS_NAME=ocx-prod
-#
-#==========================================================
-# Variables configuring general
-#==========================================================
-OCFCRESOL=255
-OCFCLEVELS=62
-OCFCGTYPE=l_2
-OCFCTSTEP=%TSTEP:1800%.0
-FCCHUNKTOT=1
-VERSION="fc"
-LESUITE=false
-#
-#==========================================================
-# Variables configuring libraries
-#==========================================================
-# IFS_CYCLE="31r1"
-# Q2USE=true
-# EMOS_CYCLE="000281"
-# Q2CREATE_NEWSTREAM=false
-# NEWSTREAM=none
-NEWSTREAMLIB=none
-# LIBRESOL=".R64.D64.I32"
-SAVLIB=false
-#GETLIB=false
-# MAKE_LIBS=yes
-# Q2CHANGELIST=0
-OCEAN_BRANCH="neh_h2e20_enfo"
-OCEAN_CYCLE="h2e20"
-#
-#==========================================================
-# Variables configuring inidata
-#==========================================================
-#OCNINDAT=$(substring $BASETIME 1 8) # 19900101
-#OCIAUFR=2
-#if [[ $RUNHINDCAST = 1 ]] ; then
-#OCINI="seas_0001_01_NN_${OCNINDAT}_od_02"
-#else
-#OCINI="ocea_0001_01_NN_$(substring $BASETIME 1 8)_od_03"
-## "seas_0001_01_NN_${OCNINDAT}_od_02"
-#fi
-#OCNEWREST=false
-#OCNMINI="00"
-#INIORIG=mars
-#CLASSORIG=e4_ops
-#INISCHEME=lslag
-SVRF=no
-IFRF=no
-#
-#==========================================================
-# Variables configuring ocgeneral
-#==========================================================
-OCRUNCTRLAN=no
-OCRUNCTRLAC=no
-OCRUNCTRLFC=no
-OCRUNASSIMAN=no
-OCRUNASSIMAC=yes
-OCRUNASSIMFC=yes
-#
-MEMBERSTATE=no
-#if [ $RUNVARFC -eq 1 ] ; then
-# OCSUITE=vareps
-#fi
-
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/endt.h b/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/endt.h
deleted file mode 100644
index cbbfbd9..0000000
--- a/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/endt.h
+++ /dev/null
@@ -1,13 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-#==========================================================================
-# End task (complete -> SMS)
-# Clean up and exit
-#==========================================================================
-
-smscomplete ; trap 0 ; exit
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/head.h b/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/head.h
deleted file mode 100644
index 2560d19..0000000
--- a/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/head.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/bin/ksh
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-set -e # stop the shell on first error
-set -u # fail when using an undefined variable
-set -x # echo script lines as they are executed
-
-# Defines the three variables that are needed for any
-# communication with ECF_
-
-export ECF_PORT=%ECF_PORT% # ECF_ Remote Procedure Call number
-export ECF_NODE=%ECF_NODE% # The name sms that issued this task
-export ECF_NAME=%ECF_NAME% # The name of this current task
-export ECF_PASS=%ECF_PASS% # A unique password
-export ECF_TRYNO=%ECF_TRYNO% # Current try number of the task
-
-# Tell ECF_ we have stated
-# The ECF_ variable ECF_RID will be set to parameter of smsinit
-# Here we give the current PID.
-
-#smsinit $$
-
-# Defined a error hanlder
-
-ERROR() {
- set +e # Clear -e flag, so we don't fail
- #smsabort # Notify ECF_ that something went wrong
- trap 0 # Remove the trap
- exit 0 # End the script
-}
-
-# Trap any calls to exit and errors caught by the -e flag
-
-trap ERROR 0
-
-# Trap any signal that may cause the script to fail
-
-trap '{ echo "Killed by a signal"; ERROR ; }' 1 2 3 4 5 6 7 8 10 12 13 15
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/law.h b/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/law.h
deleted file mode 100644
index 9033f8e..0000000
--- a/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/law.h
+++ /dev/null
@@ -1,43 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-### start of law.h, normally included from config.h ####################
-
-# Override for local area wave model
-if [[ "%FSFAMILY%" = "euroshelf" ]] ; then
- set -a
- PPFRQ=6
- WAMRESOL=medite10
- WAMANLEN=12
- WAMFCLEN=120
- WAMSAR=yes
- WAMIDELRES=6
- INIWDEXPVER=%INIWDEXPVER:0001% # expver for wind forcing
- INIWDCLASS=%INIWDCLASS:od%
- INIWDSTREAM=DA
- WGRIBIN=yes
- gflag=T
- nsysnb=-1
- nmetnb=-1
-
- ALTIMETER=ers2
- SAR=ers2
- ERS=`echo $SAR | cut -c4`
-
- model=medite
- FSALT=$FSBASE/${ALTIMETER}/alt/$model
- FSALT_B=$FSBASE/${ALTIMETER}_b/alt/$model
- FSALT_S=$FSBASE/${ALTIMETER}_s/alt/$model
- FSSAR=$FSBASE/${SAR}/sar/$model
- FSSAR_B=$FSBASE/${SAR}_b/sar/$model
- FSSAR_S=$FSBASE/${SAR}_s/sar/$model
-
- WAVE_ROOT=$FDB_ROOT
- WAVE_IROOT=$FDB_IROOT
-
-fi
-# end of law.h #################################
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/rcp.h b/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/rcp.h
deleted file mode 100644
index 061c1cb..0000000
--- a/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/rcp.h
+++ /dev/null
@@ -1,41 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-# rcp.h
-
-SMSRCP() {
- set -x
- set +e
- if [[ "${ARCH:=UNDEF}" = hppa || "${ARCH:=UNDEF}" = hpia64 ]] ; then
- if [[ $PBS_JOBID = NOT_SET ]] ; then
- rcp %LOGDIR%%SMSNAME%.%SMSTRYNO% \
- emos@%SMSNODE%:%SMSOUT%%SMSNAME%.%SMSTRYNO%
- else
- rm -f %SMSJOBOUT% || : # remove link
-
- # hardcoded to hanfs2 then mordred to release load on ablamor
- rcp /var/spool/PBS/spool/${PBS_JOBID}.OU \
- emos at hanfs2:/hanfs%SMSHOME%%SMSNAME%.%SMSTRYNO% || \
- rcp /var/spool/PBS/spool/${PBS_JOBID}.OU \
- emos at mordred:%SMSHOME%%SMSNAME%.%SMSTRYNO% || \
- rcp /var/spool/PBS/spool/${PBS_JOBID}.OU \
- emos@%SMSNODE%:%SMSHOME%%SMSNAME%.%SMSTRYNO%
-
- link_name=`~emos/bin/subs_path.pl -f %SMSOUT% -t $TOPATH -n %SMSJOBOUT%`
- rm -f $link_name || :
-
- fi
- fi
-
- if [[ ${ARCH:=UNDEF} = ibm_power* ]] ; then
- rcp %LOGDIR%%SMSNAME%.%SMSTRYNO% %SMSNODE%:%SMSHOME%%SMSNAME%.%SMSTRYNO%
- fi
-
-}
-typeset -fx SMSRCP
-
-# end of rcp.h
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/set_traps.h b/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/set_traps.h
deleted file mode 100644
index d2bbcba..0000000
--- a/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/set_traps.h
+++ /dev/null
@@ -1,6 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/setup.h b/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/setup.h
deleted file mode 100644
index 056b7d8..0000000
--- a/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/setup.h
+++ /dev/null
@@ -1,535 +0,0 @@
-banner setup.h
-#=======================================================================
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-USER=${USER:=$LOGNAME}
-
-set -a
-
-#=======================================================================
-# Get the prompt PS4 to be ok with -u option
-#=======================================================================
-
-typeset -Z2 _h _m _s
-if [[ $ARCH != linux ]] ; then
-SECONDS="$(date '+3600*%%H+60*%%M+%%S')"
-_x=""
-_time='${_x[(_h=(SECONDS/3600)%%24)==(_m=SECONDS/60%%60)==(_s=SECONDS%%60)]}$_h:$_m:$_s'
-PS4="$_time + "
-elif [[ $ARCH = linux ]] ; then
- set +e
- LKSH93=`isksh93 && echo "true" || echo "false"`
- set -e
- if [[ $ARCH = linux ]] && [[ "$LKSH93" = "true" ]] ; then
-# ksh93 syntax
- _time='$((_h=(SECONDS/3600)%%24)):$((_m=(SECONDS/60)%%60)):$((_s=SECONDS%%60))'
- PS4="$_time + "
- fi
-fi
-
-unset _hh _mm || true
-#=======================================================================
-#
-# Distinguish between OD and RD
-#
-#=======================================================================
-
-STREAM=%STREAM:DA%
-if [[ $STREAM = DA ]] ; then
- stream=""
-else
- stream="/${STREAM}"
-fi
-
- # OD_MODE is set to false (default) for rd, e4 projects
- # true for od and all od projects
- OD_MODE=true
- CLASS=%OD_PROJ:od%
- OD_PROJ=%OD_PROJ:od%
-
- #---------------------------------------------------------------------
- # EMOS specific setup
- #---------------------------------------------------------------------
-
- EMOS_YEAR=`substring $BASETIME 1 4`
- EMOS_MONTH=`substring $BASETIME 5 6`
- EMOS_DAY=`substring $BASETIME 7 8`
- EMOS_BASE=`substring $BASETIME 9 10`
- EMOS_VERSION=$EXPVER
- EMOS_TIME_STEP_H=%EMOS_TIME_STEP_H%
- EMOS_STREAM=$STREAM
-
- if [[ $EXPVER -ne 1 && $EXPVER -ne 2 ]] ; then
- alias -x gksplot="gksplot -u $EPLOT_USER"
- alias -x magplot="magplot -u $EPLOT_USER"
- fi
-
-#=======================================================================
-#
-# Derive the disk variables
-#
-#=======================================================================
-
-export FWROOT=$FSROOT/${EXPVER} # this variable for similar path WITHOUT stream
-export FWBASE=$FSROOT/${EXPVER} # this variable for similar path WITHOUT stream
-
-if [[ %OD_PROJ:od% != od ]] ; then
- BASE=$TROOT/$CLASS/$EXPVER
- WORK=$WROOT/$CLASS/$EXPVER
- LIBS=$BASE/lib
- BINS=$BASE/bin
- DATA=$BASE/data
-
-elif [[ $STREAM = MAED ]] ; then
- TROOT=${TROOT}/${STREAM}
- WROOT=${WROOT}/${STREAM}
- FSROOT=${FSROOT}/${STREAM}
- BASE=$TROOT/$EXPVER
- WORK=$WROOT/$EXPVER
- LIBS=$BASE/lib
- BINS=$BASE/bin
- DATA=$BASE/data
-
-elif [[ $STREAM = DCDA ]] ; then
- # TBD TBD TBD ODIR configuration for operational mode
-
- BASE=$TROOT/$EXPVER
- LIBS=$BASE/lib
- BINS=$BASE/bin
- DATA=$BASE/data
- TROOT=${TROOT}/${STREAM}
- BASE=$TROOT/$EXPVER
- WROOT=${WROOT}/${STREAM}
- WORK=$WROOT/$EXPVER
- FSROOT=${FSROOT}/${STREAM}
- FSODB=${FSODB}/${STREAM}
-
-else
- BASE=$TROOT/$EXPVER
- WORK=$WROOT/$EXPVER
- LIBS=$BASE/lib
- BINS=$BASE/bin
- DATA=$BASE/data
-fi
-
-
-if [[ $OD_MODE = true ]] ; then
- LOGS=%LOGDIR%/$SUITE/$FAMILY
-else
- LOGS=$TROOT/log/$SUITE/$FAMILY
-fi
-
-if [ "$FSFAMILY" != "" ] ; then
- PATH=${XBINS}/${ARCH}/${IFS_CYCLE}/${FSFAMILY}:${XBINS}/${ARCH}/${IFS_CYCLE}:${XBINS}/${ARCH}/${IFS_CYCLE}/an:/${BINS}/${FSFAMILY}:${HOME}/bin/${FSFAMILY}:${XBINS}/${IFS_CYCLE}:${XBINS}/an:$PATH:$emosbin:${HOME}/bin/${ARCH}
- FSFAMILY=/$FSFAMILY
-fi
-
-SUBFSFAMILY=%SUBFSFAMILY:""%
-
-XDIR=$XROOT/bin
-ADIR=$BASE/${BASETIME}${FSFAMILY}$SUBFSFAMILY
-WDIR=$WORK/${BASETIME}${FSFAMILY}$SUBFSFAMILY
-ODIR=$OROOT/0001/${BASETIME}
-
-
-if [[ "$STREAM" = MAED ]] ; then
- if [[ "$FSFAMILY" = "/fc" ]] ; then
- if [[ $INIMACONS -eq 1 ]] ; then
- ADIR="${ADIR}_cons"
- WDIR="${WDIR}_cons"
- elif [[ "$INIMA" != "" ]] ; then
- ADIR="${ADIR}_$INIMA"
- WDIR="${WDIR}_$INIMA"
- fi
- fi
-fi
-
-PATH=$HOME/bin/ppdi:$TMPDIR:$BINS:$BINS/$WAMRESOL:$XROOT/bin/$EMOS_CYCLE:$PATH
-
-if [[ "$FSFAMILY" = /mc ]] && [[ $RUNHINDCAST != 1 ]] ; then
- EMOS_STREAM=EF
- STREAM=EF
-fi
-
-#=======================================================================
-#
-# Suite specific fdb settings
-#
-#=======================================================================
-#=======================================================================
-#
-# Derive the FileServer variables
-#
-#=======================================================================
-
-if [[ %OD_PROJ:od% = od ]] ; then
- FSBASE=${FSROOT}${FSFAMILY}/${EXPVER}
-else
- FSBASE=${FSROOT}${FSFAMILY}/${CLASS}/${EXPVER}
-fi
-
-FDBASE=$FSBASE
-
-FSHOST=${FSBASE}/${ARCH}
-
-FSLIBS=${FSHOST}/lib
-FSBINS=${FSHOST}/bin
-FSDATA=${FSHOST}/data
-FSODIR=${FSROOT}/0001/$(substring $BASETIME 1 6)/$(substring $BASETIME 7 10)
-
-DHSWAVE=${FSROOT}/${EXPVER}/wave
-
-if [[ "$FSFAMILY" = /euroshelf ]] ; then
- DHSWAVE=${FSROOT}/${EXPVER}/euroshelf
-fi
-
-if [[ $OD_MODE = true ]] ; then
- FSDIR=${FSBASE}/${BASETIME}
- FSLOG=${FSBASE}/log
-
- DHSTIME=$(substring $BASETIME 1 6)/$(substring $BASETIME 7 10)
-
- FSBDIR=$FSOROOT/$EXPVER/$DHSTIME
-else
- FSDIR=$FSROOT/${EXPVER}/${BASETIME}
- FSLOG=$FSROOT/${EXPVER}/log
-
- DHSTIME=${BASETIME}
-fi
-FODBDIR=${FSODB}${FSFAMILY}/${EXPVER}${stream}/${BASETIME}
-
-PSDIR=/ws/scratch/ma/emos/ps
-
-#=======================================================================
-# Set variable to run metview macros on a different fs from normal users
-# Please see comments in web.h if you want to change it.
-#
-# On linux cluster we use the default one
-#=======================================================================
-
-
-
-#=======================================================================
-# Model variables that depend on configuration
-#=======================================================================
-
-VPP_MBX_SIZE=1000000
-MBX_SIZE=1000000
-MPP_TYPE=2
-if [[ $ARCH = @(ibm_power*) ]] ; then
- MBX_SIZE=64000000
-fi
-
-[[ $RESOL = 213 || $RESOL = 319 ]] && NRESOL=160
-[[ $RESOL = 106 || $RESOL = 159 ]] && NRESOL=80
-[[ $RESOL = 511 ]] && NRESOL=256
-[[ $RESOL = 799 ]] && NRESOL=400
-[[ $RESOL = 255 ]] && NRESOL=160
-[[ $RESOL = 399 ]] && NRESOL=200
-
-
-if [[ $ARCH = @(ibm_power*) ]] ; then
- CC=xlc_r
- FRT=xlf90
- FRT77=xlf
- LD=mpxlf90_r
- LDCC=xlc_r
- BUILDWS=true
- WSUSE=xlf_7112
- PARALLEL=4
- NATIVE=true
- F90_DEBUG=0
- RUN_PARALLEL=true
-fi
-#==========================================================
-# New for 33r1
-#==========================================================
-
-if [[ $ARCH = ibm_power4 ]] ; then
- USE=xlf_11102
-elif [[ $ARCH = @(ibm_power6) ]] ; then
- USE=standard
-fi
-
-if [[ $TASK != exp_setup ]] ; then
- USE=${USE:-standard}
-
- if [[ $USE != standard ]] && [[ $ARCH = ibm_power* ]] ; then
- use $USE
-# addon1=`echo $PATH | cut -d: -f1`
-# addon2=`echo $PATH | cut -d: -f2`
-# REDUCED_PATH=$addon1:$addon2:$REDUCED_PATH
- fi
-fi
-
-set +a
-
-#=======================================================================
-#
-# Functions to manipulate the variables
-#
-#=======================================================================
-
-NEWADIR() {
- set -xe
- if [ $# -lt 1 ] ; then echo $0: error; return 1 ; fi
- echo $BASE/$(newdate $BASETIME $1)/$(basename $ADIR)
-}
-
-NEWWDIR() {
- set -xe
- if [ $# -lt 1 ] ; then echo $0: error; return 1 ; fi
- # echo $WORK/$(newdate $BASETIME $1)/$(basename $WDIR) # 29r2 TBD
- echo `echo $WDIR | sed -e "s/$BASETIME/$(newdate $BASETIME $1)/g"`
-}
-
-NEWFSBDIR() {
- set -x
- if [ $# -lt 1 ] ; then echo $0: error; return 1 ; fi;
- XX=`newdate ${BASETIME} $1`;
- # used to define the location for PS_BIAS file
- # shall contain DCDA stream within the path _but_ this would mean
- # modifying FSBDIR variable. However, too many script use already
- # this variable.
- echo $FSOROOT/$EXPVER/$(substring $XX 1 6)/$(substring $XX 7 10);
-# ${FSBASE}/$STREAM/$(substring $XX 1 6)/$(substring $XX 7 10)
-}
-
-NEWFDIR() {
- set -xe
- if [ $# -lt 1 ] ; then echo $0: error; return 1 ; fi;
- XX=`newdate ${BASETIME} $1`;
- echo $FSBASE/$(substring $XX 1 6)/$(substring $XX 7 10)
-}
-
-CHECK_DIR(){
- if [[ $ARCH = ibm_power* ]] ; then
- trap '{ echo "Error in function"; exit 1; }' 0 $SMS_SIGNAL_LIST
- fi
- set -xeu
- if [[ ! "$ARCH" = "linux" ]] ; then
- trap '{ echo "Error in function"; exit 1; }' 0 $SMS_SIGNAL_LIST
- fi
- if [[ $# -eq 0 ]]; then
- return 1
- fi
-
- if [[ $ARCH = ibm_power* ]] then
- (umask 022;pmkdir $1 || exit )
- else
- mkdir -p -m 755 $1 || exit
- fi
- if [[ ! "$ARCH" = "linux" ]] ; then
- trap 0
- fi
-
- return 0
-}
-
-
-PUT() {
- set -xe
- Ecp -o $1 ec:$FSDIR/$1 || return 1
-}
-
-GET() {
- set -xe
- Ecp ec:$FSDIR/$1 $1 || return 1
-}
-
-if [[ $OD_MODE = true ]] ; then
-
- GETSV() {
- set -xe
- file=$(basename $2)
- Ecp ec:$1/$file $2 || return 1
- }
-
-else
- GETSV() {
- set -xe
- Ecp ec:$1/$2 $2 || return 1
- }
-
-fi
-
-typeset -fx NEWADIR NEWWDIR NEWFDIR CHECK_DIR PUT GET GETSV NEWFSBDIR
-
-if [[ $ARCH != fujitsu ]] ; then
- function libselect { echo WARNING - dummy command : libselect $1 ;}
- typeset -fx libselect
-fi
-
-export OLDADIR=`NEWADIR -$PERIOD`
-export OLDWDIR=`NEWWDIR -$PERIOD`
-export YESTERDIR=`NEWWDIR -24`
-
-#==========================================================================
-# Copy postscript file into a scratch directory;
-#
-# PSFILE [filename [countem [rename]]]
-#
-# Default filename is "ps"
-#
-# countem (set but can contain anything) means that there is more than
-# one file from this task in which case the files are numbered.
-#
-# If only one file is produced it is copied as
-# ${_PSDIR}/${SUITE}${EMOS_BASE}${TASK}.ps
-# otherwise it is copied as
-# ${_PSDIR}/${SUITE}${EMOS_BASE}${TASK}.fileno.ps
-# where fileno is counted automatically
-#
-# If the third parameter is given the naming convention is not followed
-# except that the file numbering is still being done (stupid if there's
-# only one file, but what the hell...)
-#
-# Old file is not saved
-#==========================================================================
-
-PSFILE() {
- set +exv
- if [ $# -ge 1 ] ; then _psfile="$1" ; else _psfile="ps" ; fi
- if [ ! -f $_psfile ] ; then return 1; fi
- if [ $# -ge 2 ] ; then _fileno=`expr ${_fileno:-0} + 1`; else _fileno=0; fi
- if [ $# -ge 3 ] ; then _name=$3; else _name=${SUITE}${EMOS_BASE}${TASK}; fi
-
- if [ ${_fileno} -gt 0 ] ; then
- /bin/rm -f ${PSDIR}/${_name}.${_fileno}.ps
- cp $_psfile ${PSDIR}/${_name}.${_fileno}.ps
- else
- /bin/rm -f ${PSDIR}/${_name}.ps
- cp $_psfile ${PSDIR}/${_name}.ps
- fi
-
- set -ex
-}
-
-typeset -fx PSFILE
-
-#=======================================================================
-# For FDB we need a different stream. Oh why can they not be the same?
-#=======================================================================
-
-set -a
-[[ $STREAM = DA ]] && { WSTREAM=WV; FDB_STREAM=oper; FDB_WSTREAM=wave; }
-[[ $STREAM = EF ]] && { WSTREAM=WAEF; FDB_STREAM=enfo; FDB_WSTREAM=waef; }
-[[ $STREAM = SCDA ]] && { WSTREAM=SCWV; FDB_STREAM=scda; FDB_WSTREAM=scwv; }
-[[ $STREAM = MAED ]] && { WSTREAM=MAWV; FDB_STREAM=maed; FDB_WSTREAM=mawv; }
-[[ $STREAM = sens ]] && { WSTREAM=sens; FDB_STREAM=sens; FDB_WSTREAM=sens; }
-[[ $STREAM = SCDA ]] && unset FDB_SERVER_HOST || true
-[[ $STREAM = DCDA ]] && { WSTREAM=DCWV ; FDB_STREAM=dcda ; FDB_WSTREAM=dcwv; }
-[[ $STREAM = EFHC ]] && { WSTREAM=EWHC ; FDB_STREAM=efhc ; FDB_WSTREAM=ewhc; } # MC HINDCAST
-[[ $STREAM = ENFH ]] && { WSTREAM=ENWH; FDB_STREAM=enfh ; FDB_WSTREAM=enwh; } # MC HINDCAST
-[[ $STREAM = DAHC ]] && { WSTREAM=WVHC ; FDB_STREAM=dahc ; FDB_WSTREAM=wvhc; } # MC HINDCAST
-
-set +a
-
-#=======================================================================
-# Check for day and date mask
-#=======================================================================
-
-echo checking for date mask
-
-datemask=$(echo '%DATEMASK%' | cut -f1 -d.)
-day=$(substring $BASETIME 7 8)
-weekday=%WEEKDAY:none%
-
-if [[ $weekday != "none" ]] ; then
- jday=$(newdate -d $BASETIME)
- jday=$(expr $jday %% 7) || true
- if [[ $jday -eq 0 ]] ; then
- dow=monday
- elif [[ $jday -eq 1 ]] ; then
- dow=tuesday
- elif [[ $jday -eq 2 ]] ; then
- dow=wednesday
- elif [[ $jday -eq 3 ]] ; then
- dow=thursday
- elif [[ $jday -eq 4 ]] ; then
- dow=friday
- elif [[ $jday -eq 5 ]] ; then
- dow=saturday
- elif [[ $jday -eq 6 ]] ; then
- dow=sunday
- fi
-fi
-
-if [[ $datemask != "*" && $day -ne $datemask ]] || [[ $weekday != "none" && $weekday != $dow ]] ; then
-echo job should not run today ... setting it complete
-%include <endt.h>
-fi
-
-#=======================================================================
-#
-# Check the directories
-#
-#=======================================================================
-
-CHECK_DIR $ADIR
-CHECK_DIR $WDIR
-
-if [[ $ARCH = ibm_power* ]];then
- export PBIO_BUFSIZE=1048576
-fi
-
-#=======================================================================
-#
-# Suite stopper
-#
-#=======================================================================
-
-if [[ %SUITE% = "e_35r3" && $BASETIME = "2012120500" ]] ; then
- echo "ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR"
- echo "Suite e_35r3 has been set up to stop now"
- echo "Operators You can suspend this suite and requeue failed tasks if you like!"
- echo "ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR"
- exit 1
-elif [[ %SUITE% = "emc_35r3" && $BASETIME = "2012022600" ]] ; then
- echo "ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR"
- echo "Suite emc_35r3 has been set up to stop now"
- echo "Operators You can suspend this suite and requeue failed tasks if you like!"
- echo "ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR"
- exit 1
-fi
-
-#=======================================================================
-# We use an operation only Magics version to be on the safe side.
-# This is of course only on the servers
-#=======================================================================
-MAGICS=%MAGICS:magics_emos%
-
-#=======================================================================
-# We use an operation only Metview version to be on the safe side.
-#=======================================================================
-
-if [[ $ARCH = linux ]] ; then
- metview_cmd=%METVIEW:metview_emos%
-
-elif [[ $ARCH = ibm_power4 ]] ; then
- METVIEW_TMPDIR=/home/ma/emos/metview/metview_tmpdir
- metview_cmd=%METVIEW:/home/ma/emos/metview/MvRun_3.9.3%
-elif [[ $ARCH = ibm_power6 ]] ; then
- METVIEW_TMPDIR=/home/ma/emos/metview/metview_tmpdir
- metview_cmd=%METVIEW:/home/ma/emos/metview/MvRun_3.10%
-fi
-
-#=======================================================================
-# We use an operation only metpy version to be on the safe side.
-#=======================================================================
-metpy_cmd=%METPY:metpy_emos%
-
-echo setup complete
-
-# 20040720 add /home/rd/rdx/bin/filter/bufr_filter from hpcd
-#
-%include <law.h>
-
-export LEDFAMILY=%EDFAMILY:false%
-
-banner end setup.h
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/sms.h b/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/sms.h
deleted file mode 100644
index 34cd64b..0000000
--- a/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/sms.h
+++ /dev/null
@@ -1,55 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-#==========================================================================
-# Define environment variables and export them.
-#==========================================================================
-
-set -a
-
-ECF_PASS=%ECF_PASS%
-ECF_NODE=%ECF_NODE%
-ECF_NAME=%ECF_NAME%
-ECF_TRYNO=%ECF_TRYNO%
-ECF_RID=$(echo $QSUB_REQID | cut -f1 -d.)
-ECF_HOSTFILE=$HOME/.smshostfile
-ECF_PORT=%ECF_PORT%
-ECF_JOBOUT=%ECF_JOBOUT%
-
-SUITE=%SUITE%
-FAMILY=%FAMILY%
-TASK=%TASK%
-
-DEBUG=0
-DISPLAY=0
-
-#==========================================================================
-# Initialize sms.
-# Trap handling.
-# Modify the ERROR function what to do in case of any error.
-#==========================================================================
-
-#if [[ $ARCH = sgimips && -f /usr/local/ecfs/prodn/.ecfs_k_env ]] ; then
-if [[ -f /usr/local/ecfs/prodn/.ecfs_k_env ]] ; then
- . /usr/local/ecfs/prodn/.ecfs_k_env
-fi
-
-smsinit $ECF_RID &
-
-ERROR() {
- smsabort; printenv; trap 0; exit
-}
-
-trap ERROR 0
-trap '{ echo "Killed by a signal"; ERROR ; }' 1 2 3 4 5 6 7 8 10 12 13 15
-
-set -ex
-
-if [[ $ARCH = sgimips && -f /usr/local/ecfs/prodn/.ecfs_k_env ]] ; then
- . /usr/local/ecfs/prodn/.ecfs_k_env
-fi
-
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/tail.h b/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/tail.h
deleted file mode 100644
index eb7f7a0..0000000
--- a/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/tail.h
+++ /dev/null
@@ -1,10 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-#smscomplete # Notify SMS of a normal end
-trap 0 # Remove all traps
-exit 0 # End the shell
diff --git a/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/trap.h b/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/trap.h
deleted file mode 100644
index bfdc421..0000000
--- a/ecflow_4_0_7/ANode/test/data/SMSHOME2/good/includes/trap.h
+++ /dev/null
@@ -1,137 +0,0 @@
-banner trap.h
-
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-
-#==========================================================================
-# Trap handling and ECF_ initialisation
-#
-# Write into the ERROR function what to do in case of any error.
-#==========================================================================
-
-typeset -l ARCH
-
-if [[ "$ARCH" = hpia64 ]] ; then
- rcp /home/ma/emos/data/dummy.output emos@%ECF_NODE%:%ECF_JOBOUT% || true
-fi
-
-set -a
-LOADL_STEP_ID=${LOADL_STEP_ID:=NOT_SET}
-QSUB_REQID=${QSUB_REQID:=NOT_SET}
-PBS_JOBID=${PBS_JOBID:=NOT_SET}
-
-if [[ $LOADL_STEP_ID != NOT_SET ]] ; then
- ECF_RID=$(echo $LOADL_STEP_ID | cut -f1 -d.)
- ECF_RID=$(substring $ECF_RID 6 8 )
- ECF_RID=$(echo $LOADL_STEP_ID | cut -f2 -d.)${ECF_RID}
- JOB_ID=$LOADL_STEP_ID
-elif [[ $QSUB_REQID != NOT_SET ]] ; then
- ECF_RID=$(echo $QSUB_REQID | cut -f1 -d.)
- JOB_ID=$QSUB_REQID
-elif [[ $PBS_JOBID != NOT_SET ]] ; then
- ECF_RID=$(echo $PBS_JOBID | cut -f1 -d.)
- JOB_ID=$PBS_JOBID
-
- TOPATH=%TOPATH:/tmp/output%
- link_name=`~emos/bin/subs_path.pl -f %ECF_OUT% -t $TOPATH -n %ECF_JOBOUT%`
- mkdir -p `dirname $link_name` || :
- ln -sf /var/spool/PBS/spool/${PBS_JOBID}.OU $link_name || :
- rm -f %ECF_JOBOUT% || :
- ln -sf /var/spool/PBS/spool/${PBS_JOBID}.OU %ECF_JOBOUT%
-else
- ECF_RID=$$
- JOB_ID=$ECF_RID
-fi
-
-ECF_PASS=%ECF_PASS%
-ECF_NODE=%ECF_NODE%
-ECF_NAME=%ECF_NAME%
-ECF_TRYNO=%ECF_TRYNO%
-ECF_HOSTFILE=$HOME/.smshostfile
-ECF_JOBOUT=%ECF_JOBOUT%
-
-set +a
-ARCHWDIR=${ARCHWDIR:=""}
-
-SMSCLEAN() {
- set -x
- set +e
- STREAM=${STREAM:=""}
- if [[ "$STREAM" = @(SEAS|MOFC|OCEA|mnfc|mnfh) ]] ; then
- if [[ "%TASK%" = logfiles ]] ; then
- n=0
- while [[ -d $WDIR ]] ; do
- # Forked processes could still be around, and 'rm -rf' fails
- rm -rf $WDIR || true
- ls -l $WDIR && sleep 2 || true
- n=$((n+1))
- [[ $n -gt 5 ]] && break
- done || true
- fi
- fi
- FSFAMILY=${FSFAMILY:=""}
- if [[ "$FSFAMILY" = /mars || "%FAMILY1%" = archive ]] ; then
- cd $TMPDIR
- n=0
- while [[ -d ${WDIR}$ECF_NAME ]] ; do
- # Forked processes could still be around, and 'rm -rf' fails
- rm -rf ${WDIR}$ECF_NAME || true
- ls -l ${WDIR}$ECF_NAME && sleep 2 || true
- n=$((n+1))
- [[ $n -gt 5 ]] && break
- done || true
- fi
-
- if [[ $ARCH = linux ]] ; then
- . /usr/local/share/ecmwf/share/.epilog
- fi
-}
-typeset -fx SMSCLEAN
-
-%include <rcp.h>
-
-ERROR() {
- set -x
- set +e
- wait
- smsabort
- trap 0
- date
- times
- echo "environment was:"
- printenv | sort
-
- SMSCLEAN
-
- if [[ $$ARCH != "ibm_power*" ]] ; then
- SMSRCP || :
- fi
- exit 1
-}
-
-if [[ $ARCH == hpia64 ]]; then
- export SMS_SIGNAL_LIST='1 2 3 4 5 6 7 8 10 12 13 15 24 30 33'
-elif [[ $ARCH == ibm_power* ]]; then
- export SMS_SIGNAL_LIST='1 2 3 4 5 6 7 8 10 12 13 15 24 30'
-elif [[ $ARCH == linux ]]; then
- export SMS_SIGNAL_LIST='1 2 3 4 5 6 7 8 13 15 24 31'
-else
- export SMS_SIGNAL_LIST='1 2 3 4 5 6 7 8 13 15 24 31'
-fi
-
-%include <set_traps.h>
-trap
-set -exu
-
-[[ -d $TMPDIR ]] && cd $TMPDIR
-
-smsinit $ECF_RID &
-smsmsg "#ID ECF_NAME=%ECF_NAME%;ECF_JOBOUT=%ECF_JOBOUT%;ECF_HOME=%ECF_HOME%;JOB_ID=${JOB_ID:-}"
-
-date
-
diff --git a/ecflow_4_0_7/ANode/test/data/includes/head.h b/ecflow_4_0_7/ANode/test/data/includes/head.h
deleted file mode 100644
index e49b80e..0000000
--- a/ecflow_4_0_7/ANode/test/data/includes/head.h
+++ /dev/null
@@ -1,65 +0,0 @@
-#!/bin/ksh
-# ================================== start of head.h ================================
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-%manual
-#This is the manual from the head.h file
-%end
-
-%comment
-#This is the comment from the head.h file
-%end
-
-set -e # stop the shell on first error
-set -u # fail when using an undefined variable
-set -x # echo script lines as they are executed
-
-# Defines the three variables that are needed for any
-# communication with ECF
-
-export ECF_PORT=%ECF_PORT% # ECF_ Remote Procedure Call number
-export ECF_NODE=%ECF_NODE% # The name sms that issued this task
-export ECF_NAME=%ECF_NAME% # The name of this current task
-export ECF_PASS=%ECF_PASS% # A unique password
-export ECF_TRYNO=%ECF_TRYNO% # Current try number of the task
-
-# to debug client communication with the server, enable this environment
-#export ECF_DEBUG_CLIENT=
-
-# Typically we dont set this, however the zombie automated test require this.
-# it allows us to disambiguate a zomie from a real job.
-export ECF_RID=$$
-
-# Tell ECF_ we have stated
-# The ECF_ variable ECF_RID will be set to parameter of smsinit
-# Here we give the current PID.
-
-
-# Defined a error hanlder
-ERROR() {
- echo "ERROR called"
- set +e # Clear -e flag, so we don't fail
- #smsabort # Notify ECF_ that something went wrong
- %ECF_CLIENT_EXE_PATH:ecflow_client% --abort
- trap 0 # Remove the trap
- exit 0 # End the script
-}
-
-# Trap any calls to exit and errors caught by the -e flag
-
-trap ERROR 0
-
-# Trap any signal that may cause the script to fail
-
-trap '{ echo "Killed by a signal"; ERROR ; }' 1 2 3 4 5 6 7 8 10 12 13 15
-
-
-#smsinit $$
-%ECF_CLIENT_EXE_PATH:ecflow_client% --init=$$
-echo $?
-# ================================== end of head.h ================================
diff --git a/ecflow_4_0_7/ANode/test/data/includes/tail.h b/ecflow_4_0_7/ANode/test/data/includes/tail.h
deleted file mode 100644
index 6405e61..0000000
--- a/ecflow_4_0_7/ANode/test/data/includes/tail.h
+++ /dev/null
@@ -1,19 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-# ================================== start of tail.h ================================
-#smscomplete # Notify ECF of a normal end
-%ECF_CLIENT_EXE_PATH:ecflow_client% --complete
-trap 0 # Remove all traps
-exit 0 # End the shell
-%manual
-#This is the manual from the tail.h file
-%end
-%comment
-#This is the comment from the tail.h file
-%end
-# ================================== end of tail.h ================================
diff --git a/ecflow_4_0_7/ANode/test/data/migration/fixture/boost_1_47.checkpt b/ecflow_4_0_7/ANode/test/data/migration/fixture/boost_1_47.checkpt
deleted file mode 100644
index e22b3da..0000000
--- a/ecflow_4_0_7/ANode/test/data/migration/fixture/boost_1_47.checkpt
+++ /dev/null
@@ -1,77 +0,0 @@
-22 serialization::archive 9 0 0 0 0 0 0 2 0 0 0 0 15 0 9 ECF_MICRO 1 % 8 ECF_HOME 1 . 11 ECF_JOB_CMD 30 %ECF_JOB% 1> %ECF_JOBOUT% 2>&1 12 ECF_KILL_CMD 18 kill -15 %ECF_RID% 14 ECF_STATUS_CMD 21 ps --sid %ECF_RID% -f 11 ECF_URL_CMD 63 ${BROWSER:=firefox} -remote 'openURL(%ECF_URL_BASE%/%ECF_URL%)' 12 ECF_URL_BASE 26 https://software.ecmwf.int 7 ECF_URL 24 wiki/display/ECFLOW/Home 12 ECF_INTERVAL 2 60 17 ECF_CHECKINTERVAL 3 120 13 ECF_CHECKMODE 13 CHECK_ON_TIME 9 ECF_TRIES 1 2 11 ECF_VERSI [...]
-0 0 0 0 0 9 suiteName 0 0 0 0 0 0 0 0 0 0 0 2 -1 -1 -1 13 1 0
-1 48 0 0 1 1 14 1 0
-2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 10 0 0 0 5 0 0 0 0 0 0 0 0 0 7 0 0 1 2 3 4 5 6 31 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 12 0 1 2 3 4 5 6 7 8 9 10 11 12 0 -1 -1 -1 3 0 3 VAR 5 value 4 VAR1 7 "value" 9 ECF_FETCH 42 "smsfetch -F %ECF_FILES% -I %ECF_INCLUDE%" 0 0 1 1 0 1 25 1 0
-3 10 suiteLimit 10 0 0 0 0 0 0 0 0 0 0 0 0 12 1 0 1 6 1 0
-4 0 0 2 t1 0 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 -1 -1 -1 0 0 0 1 0 0 0 5 _DJP_ 0 0 0 0 0 0 0 1 6
-5 2 t2 0 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 -1 -1 -1 0 0 0 1 0 0 0 5 _DJP_ 0 0 0 0 0 1 6
-6 2 t3 0 0 0 0 0 0 0 2 11 1 0
-7 0 0 2 0 0 0 14 t1 == complete 0 14 t2 == complete 1 0 11
-8 2 0 14 t1 == complete 0 14 t2 == complete 2 0 -1 -1 -1 -1 22 1 0
-9 0 0 3 0 0 0 10 0 0 7 0 0 1 2 3 4 5 6 1 1 100 7 0 0 1 2 3 4 5 6 2 4 100 7 0 0 1 2 3 4 5 6 0 0 0 0 -1 0 0 0 1 0 0 0 5 _DJP_ 0 0 0 0 0 1 6
-10 2 t4 0 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 -1 22
-11 3 0 0 2 10 7 0 0 1 2 3 4 5 6 1 3 100 7 0 0 1 2 3 4 5 6 2 4 100 7 0 0 1 2 3 4 5 6 0 0 -1 0 0 0 1 0 0 0 5 _DJP_ 0 0 0 0 0 1 6
-12 2 t5 0 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 -1 -1 37 16 RepeatEnumerated 1 0
-13 0 0 5 AEnum 0 0 3 0 2 10 2 20 2 30 0 0 0 0 1 0 0 0 5 _DJP_ 0 0 0 0 0 1 6
-14 2 t6 0 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 -1 -1 40 12 RepeatString 1 0
-15 7 aString 3 0 2 10 2 20 2 30 0 0 0 0 1 0 0 0 5 _DJP_ 0 0 0 0 0 1 6
-16 2 t7 0 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 -1 -1 41 13 RepeatInteger 1 0
-17 3 rep 0 100 1 0 0 0 0 1 0 0 0 5 _DJP_ 0 0 0 0 0 1 6
-18 2 t8 0 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 -1 -1 42 10 RepeatDate 1 0
-19 3 YMD 20090916 20090916 1 20090916 0 0 0 1 0 0 0 5 _DJP_ 0 0 0 0 0 1 6
-20 2 t9 0 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 -1 -1 43 9 RepeatDay 1 0
-21 3 day 2 0 0 0 1 0 0 0 5 _DJP_ 0 0 0 0 0 1 7 1 0
-22 10 familyName 0 0 0 0 0 0 0 2 -1 -1 12 1 0
-23 3 12 0 3 12 0 4 12 0 1 0 13
-24 1 0 0 1 0 14
-25 1 0 1 1 0 0 0 10 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 2009 0 0 0 0 0 -1 -1 37
-26 5 AEnum 3 0 2 10 2 20 2 30 0 1 0 3 VAR 5 value 1 1 25
-27 9 limitName 20 0 0 0 0 0 0 2 1 6
-28 8 taskName 0 0 0 0 0 0 0 1 -1 -1 12
-29 3 12 0 3 12 0 4 12 0 1 0 -1 14
-30 1 0 1 1 10 10 0 0 0 1 0 0 1 10 10 0 0 0 0 0 0 0 2 0 0 1 10 12 0 0 0 1 0 0 1 10 12 0 0 0 0 0 0 0 1 1 0 1 0 0 3 0 0 1 0 0 1 0 0 0 0 0 0 0 1 0 1 2 2009 0 1 0 1 0 0 0 21 1 0
-31 0 0 1 0 0 100 0 100 7 myMeter 0 0 2 0 0 0 0 0 1 9 eventName 0 0 1 0 9 labelName 12 "labelValue" 0 22
-32 0 0 1 0 1 3 0 -1 1 0 4 VAR1 7 "value" 0 1 1 0 0 0 10 suiteLimit 10 /suiteName 1 0 5 _DJP_ 0 0 0 2 2 1 0 1 49 1 0
-33 6 alias0 2 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 21
-34 1 0 0 100 0 100 7 myMeter 2 0 0 0 0 0 1 9 eventName 1 0 9 labelName 12 "labelValue" 0 -1 -1 0 0 0 1 0 0 0 5 _DJP_ 0 0 0 49
-35 6 alias1 2 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 21
-36 1 0 0 100 0 100 7 myMeter 2 0 0 0 0 0 1 9 eventName 1 0 9 labelName 12 "labelValue" 0 -1 -1 0 0 0 1 0 0 0 5 _DJP_ 0 0 0 7
-37 15 heir_familyName 0 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 -1 -1 40
-38 7 aString 3 0 2 10 2 20 2 30 0 1 0 4 VAR1 5 value 0 1 0 0 0 1 1 6
-39 8 taskName 0 0 0 0 0 0 0 2 -1 -1 -1 13
-40 0 1 0 0 0 -1 21
-41 1 0 0 100 0 100 7 myMeter 2 0 0 0 0 0 1 9 eventName 0 0 -1 -1 1 0 4 VAR1 5 value 0 1 0 0 0 5 _DJP_ 0 0 0 0 0 1 7
-42 11 familyName1 0 0 0 0 0 0 0 2 -1 -1 12
-43 3 12 0 3 12 0 4 12 0 1 0 13
-44 1 0 0 1 0 14
-45 1 0 1 1 0 0 0 10 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 2009 0 0 0 0 0 -1 -1 37
-46 5 AEnum 3 0 2 10 2 20 2 30 0 1 0 3 VAR 5 value 1 1 25
-47 9 limitName 20 0 0 0 0 0 0 1 1 6
-48 9 taskName1 0 0 0 0 0 0 0 1 -1 -1 12
-49 3 12 0 3 12 0 4 12 0 1 0 -1 14
-50 1 0 1 1 10 10 0 0 0 1 0 0 1 10 10 0 0 0 0 0 0 0 2 0 0 1 10 12 0 0 0 1 0 0 1 10 12 0 0 0 0 0 0 0 1 1 0 1 0 0 3 0 0 1 0 0 1 0 0 0 0 0 0 0 1 0 1 2 2009 0 1 0 1 0 0 0 21
-51 1 0 0 100 0 100 7 myMeter 2 0 0 1 0 0 2 9 eventName 1 0 10 labelName1 12 "labelValue" 0 22
-52 0 0 1 0 1 3 0 -1 1 0 4 VAR1 7 "value" 0 1 1 0 10 suiteLimit 10 /suiteName 1 0 5 _DJP_ 0 0 0 2 2 1 49
-53 6 alias0 2 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 21
-54 1 0 0 100 0 100 7 myMeter 2 0 0 1 0 0 2 9 eventName 1 0 10 labelName1 12 "labelValue" 0 -1 -1 0 0 0 1 0 0 0 5 _DJP_ 0 0 0 49
-55 6 alias1 2 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 21
-56 1 0 0 100 0 100 7 myMeter 2 0 0 1 0 0 2 9 eventName 1 0 10 labelName1 12 "labelValue" 0 -1 -1 0 0 0 1 0 0 0 5 _DJP_ 0 0 0 7
-57 11 familyName2 0 0 0 0 0 0 0 2 -1 -1 12
-58 3 12 0 3 12 0 4 12 0 1 0 13
-59 1 0 0 1 0 14
-60 1 0 1 1 0 0 0 10 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 2009 0 0 0 0 0 -1 -1 37
-61 5 AEnum 3 0 2 10 2 20 2 30 0 1 0 3 VAR 5 value 1 1 25
-62 9 limitName 20 0 0 0 0 0 0 1 1 6
-63 9 taskName2 0 0 0 0 0 0 0 1 11
-64 1 0 38 ../familyName1/taskName1:myMeter ge 10 0 0 11
-65 1 0 36 ../familyName1/taskName1 == complete 0 0 12
-66 3 12 0 3 12 0 4 12 0 1 0 -1 14
-67 1 0 1 1 10 10 0 0 0 1 0 0 1 10 10 0 0 0 0 0 0 0 2 0 0 1 10 12 0 0 0 1 0 0 1 10 12 0 0 0 0 0 0 0 1 1 0 1 0 0 3 0 0 1 0 0 1 0 0 0 0 0 0 0 1 0 1 2 2009 0 1 0 1 0 0 0 21
-68 1 0 0 100 0 100 7 myMeter 2 0 0 2 0 0 3 9 eventName 1 0 10 labelName2 12 "labelValue" 0 22
-69 0 0 1 0 1 3 0 -1 1 0 4 VAR1 7 "value" 0 1 1 0 10 suiteLimit 10 /suiteName 1 0 5 _DJP_ 0 0 0 2 2 1 49
-70 6 alias0 2 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 21
-71 1 0 0 100 0 100 7 myMeter 2 0 0 2 0 0 3 9 eventName 1 0 10 labelName2 12 "labelValue" 0 -1 -1 0 0 0 1 0 0 0 5 _DJP_ 0 0 0 49
-72 6 alias1 2 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 21
-73 1 0 0 100 0 100 7 myMeter 2 0 0 2 0 0 3 9 eventName 1 0 10 labelName2 12 "labelValue" 0 -1 -1 0 0 0 1 0 0 0 5 _DJP_ 0 0 0 0 0 1 51 1 0
-74 0 1 1 3600 1 1 2009 0 0 0 0 8 20130822 0 8 46 24 0 8 20130822 0 8 46 24 0 0 0 0 0 0 0 8 20130822 0 8 46 24 0 8 20130822 0 8 46 24 0 0 0 1 0 0 4
-75 10 EmptySuite 0 0 0 0 0 0 0 2 -1 -1 -1 -1 -1 -1 -1 -1 0 0 0 1 0 0 0 0 1 0 -1 8 20130822 0 8 46 24 0 8 20130822 0 8 46 24 0 0 0 0 0 0 0 8 20130822 0 8 46 24 0 8 20130822 0 8 46 24 0 0 0 1 0 0 0 0 0 0 0
diff --git a/ecflow_4_0_7/AParser/CMakeLists.txt b/ecflow_4_0_7/AParser/CMakeLists.txt
deleted file mode 100644
index e2f0022..0000000
--- a/ecflow_4_0_7/AParser/CMakeLists.txt
+++ /dev/null
@@ -1,71 +0,0 @@
-# Note:
-# If new src or test cpp files are added make sure you touch this file
-#
-
-file( GLOB srcs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp" )
-
-ecbuild_add_library( TARGET libparser
- NOINSTALL
- TYPE STATIC
- SOURCES ${srcs}
- LIBS node nodeattr core
- INCLUDES src
- ../ACore/src
- ../ANattr/src
- ../ANode/src
- )
-
-# ===================================================================
-# Use following to populate list:
-# cd $WK/AParser
-# find test -name \*.cpp | sort
-list( APPEND test_srcs
- test/PersistHelper.cpp
- test/TestAutoAddExterns.cpp
- test/TestDefsStructurePersistAndReload.cpp
- test/TestMigration.cpp
- test/TestParser.cpp
- test/TestVariableParsing.cpp
-)
-ecbuild_add_test( TARGET u_aparser
- BOOST
- SOURCES ${test_srcs}
- LIBS libparser
- TEST_DEPENDS u_anode
- )
-
-
-#
-# Tests parser for a single defs file but with a range of tests
-#
-list( APPEND t2_src test/TestSingleDefsFile.cpp test/PersistHelper.cpp )
-ecbuild_add_test( TARGET perf_aparser
- BOOST
- SOURCES ${t2_src}
- LIBS libparser
- )
-
-#
-# Timer for arbitary defs file,
-#
-list( APPEND t3_src test/ParseTimer.cpp test/PersistHelper.cpp )
-ecbuild_add_test( TARGET perf_aparser_timer
- ARGS ${CMAKE_CURRENT_SOURCE_DIR}/test/data/single_defs/mega.def
- SOURCES ${t3_src}
- LIBS libparser
- INCLUDES ../ANode/test
- ${Boost_INCLUDE_DIRS}
- )
-
-
-#
-# Tests parser for a single defs file.
-#
-list( APPEND t4_src test/ParseOnly.cpp )
-ecbuild_add_test( TARGET perf_aparser_only
- ARGS ${CMAKE_CURRENT_SOURCE_DIR}/test/data/single_defs/mega.def
- SOURCES ${t4_src}
- LIBS libparser
- INCLUDES ../ANode/test
- ${Boost_INCLUDE_DIRS}
- )
diff --git a/ecflow_4_0_7/AParser/Jamfile.jam b/ecflow_4_0_7/AParser/Jamfile.jam
deleted file mode 100644
index d4dd8a2..0000000
--- a/ecflow_4_0_7/AParser/Jamfile.jam
+++ /dev/null
@@ -1,126 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-#
-# Parser
-#
-project theParser ;
-
-use-project theCore : ../ACore ;
-use-project theNodeAttr : ../ANattr ;
-use-project theNode : ../ANode ;
-
-#
-# Having a library avoid compile objects shared between client and test having
-# differing compilation properties
-#
-lib libparser : [ glob src/*.cpp ]
- : <include>../ACore/src
- <include>../ANattr/src
- <include>../ANode/src
- <variant>debug:<define>DEBUG
- <link>static
- :
- : <include>../AParser/src
- ;
-
-#
-# This is *ONLY* required when the define ECFLOW_MT is used,(used by Signal.cpp)
-lib pthread ;
-
-#
-# Tests for parser. Exclude file test/TestSingleDefsFile.cpp, test/ParseOnly.cpp test/ParseTimer.cpp
-# test/TestJobGenPerf.cpp
-#
-exe u_aparser : [ glob test/*.cpp :
- test/TestSingleDefsFile.cpp
- test/ParseOnly.cpp test/ParseTimer.cpp
- test/TestJobGenPerf.cpp
- ]
- pthread
- /theCore//core
- /theNodeAttr//nodeattr
- /theNode//node
- libparser
- /site-config//boost_system
- /site-config//boost_serialization
- /site-config//boost_filesystem
- /site-config//boost_datetime
- /site-config//boost_test
- : <include>../ANode/test
- <variant>debug:<define>DEBUG
- ;
-
-#
-# Tests parser for a single defs file.
-#
-exe perf_aparser : test/TestSingleDefsFile.cpp test/PersistHelper.cpp
- pthread
- /theCore//core
- /theNodeAttr//nodeattr
- /theNode//node
- libparser
- /site-config//boost_system
- /site-config//boost_serialization
- /site-config//boost_filesystem
- /site-config//boost_datetime
- /site-config//boost_test
- : <include>../ANode/test
- <variant>debug:<define>DEBUG
- ;
-
-#
-# Timer for arbitary defs file,
-#
-exe perf_aparser_timer : test/ParseTimer.cpp test/PersistHelper.cpp
- pthread
- /theCore//core
- /theNodeAttr//nodeattr
- /theNode//node
- libparser
- /site-config//boost_system
- /site-config//boost_serialization
- /site-config//boost_filesystem
- /site-config//boost_datetime
- : <include>../ANode/test
- <variant>debug:<define>DEBUG
- ;
-
-#
-# Tests parser for a single defs file.
-#
-exe perf_aparser_only : test/ParseOnly.cpp
- pthread
- /theCore//core
- /theNodeAttr//nodeattr
- /theNode//node
- libparser
- /site-config//boost_system
- /site-config//boost_serialization
- /site-config//boost_filesystem
- /site-config//boost_datetime
- : <include>../ANode/test
- <variant>debug:<define>DEBUG
- ;
-
-#
-# Tests job generation performance, relies on python (Pyext/samples/TestJobGenPerf.py) to setup data
-#
-exe perf_job_gen : test/TestJobGenPerf.cpp
- pthread
- /theCore//core
- /theNodeAttr//nodeattr
- /theNode//node
- libparser
- /site-config//boost_system
- /site-config//boost_serialization
- /site-config//boost_filesystem
- /site-config//boost_datetime
- : <include>../ANode/test
- <variant>debug:<define>DEBUG
- ;
-
\ No newline at end of file
diff --git a/ecflow_4_0_7/AParser/src/AutoCancelParser.cpp b/ecflow_4_0_7/AParser/src/AutoCancelParser.cpp
deleted file mode 100644
index d7cad2c..0000000
--- a/ecflow_4_0_7/AParser/src/AutoCancelParser.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #11 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "AutoCancelParser.hpp"
-#include "TimeSeries.hpp"
-#include "Extract.hpp"
-#include "Node.hpp"
-
-using namespace ecf;
-using namespace std;
-
-bool AutoCancelParser::doParse( const std::string& line, std::vector<std::string >& lineTokens )
-{
- // autocancel +01:00 # cancel one hour after complete
- // autocancel 01:00 # cancel at 1 am in morning after complete
- // autocancel 10 # cancel 10 days after complete
- // autocancel 0 # cancel immediately after complete
-
- if ( lineTokens.size() < 2 ) throw std::runtime_error( "AutoCancelParser::doParse: Invalid autocancel :" + line );
- if ( nodeStack().empty() ) throw std::runtime_error("AutoCancelParser::doParse: Could not add autocancel as node stack is empty at line: " + line );
-
- if (lineTokens[1].find_first_of(':') == string::npos) {
- // Must be of the form:
- // autocancel 10 # cancel 10 days after complete
- // autocancel 0 # cancel immediately after complete
- int days = Extract::theInt(lineTokens[1],"invalid autocancel " + line) ;
-
- nodeStack_top()->addAutoCancel( AutoCancelAttr( days ) ) ;
- }
- else {
- // Must be of the form:
- // autocancel +01:00 # cancel one hour after complete
- // autocancel 01:00 # cancel at 1 am in morning after complete
- int hour = 0;
- int min = 0;
- bool relative = TimeSeries::getTime(lineTokens[1],hour,min);
-
- nodeStack_top()->addAutoCancel( AutoCancelAttr( TimeSlot( hour, min), relative ) ) ;
- }
- return true;
-}
-
-
diff --git a/ecflow_4_0_7/AParser/src/AutoCancelParser.hpp b/ecflow_4_0_7/AParser/src/AutoCancelParser.hpp
deleted file mode 100644
index 230f85e..0000000
--- a/ecflow_4_0_7/AParser/src/AutoCancelParser.hpp
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef AUTOCANCELPARSER_HPP_
-#define AUTOCANCELPARSER_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "Parser.hpp"
-
-class AutoCancelParser : public Parser {
-public:
- AutoCancelParser(DefsStructureParser* p) : Parser(p) {}
- virtual const char* keyword() const { return "autocancel"; }
- virtual bool doParse(const std::string& line,std::vector<std::string>& lineTokens);
-};
-#endif
diff --git a/ecflow_4_0_7/AParser/src/CalendarParser.cpp b/ecflow_4_0_7/AParser/src/CalendarParser.cpp
deleted file mode 100644
index 490ce14..0000000
--- a/ecflow_4_0_7/AParser/src/CalendarParser.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #21 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <stdexcept>
-
-#include "CalendarParser.hpp"
-#include "Str.hpp"
-#include "Suite.hpp"
-
-using namespace ecf;
-using namespace std;
-
-bool CalendarParser::doParse( const std::string& line, std::vector<std::string >& lineTokens )
-{
- if ( lineTokens.size() < 2 ) {
- throw std::runtime_error( "CalendarParser::doParse: Invalid calendar :" + line );
- }
- if ( nodeStack().empty() ) {
- throw std::runtime_error("CalendarParser::doParse: Could not add calendar as node stack is empty at line: " + line );
- }
-
- Suite* suite = nodeStack_top()->isSuite();
- if (!suite) throw std::runtime_error("Calendar can only be added to suites and not " + nodeStack_top()->debugType() );
- suite->set_calendar().read_state(line,lineTokens);
-
- return true;
-}
-
diff --git a/ecflow_4_0_7/AParser/src/CalendarParser.hpp b/ecflow_4_0_7/AParser/src/CalendarParser.hpp
deleted file mode 100644
index 60c6557..0000000
--- a/ecflow_4_0_7/AParser/src/CalendarParser.hpp
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef CALENDAR_PARSER_HPP_
-#define CALENDAR_PARSER_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "Parser.hpp"
-
-class CalendarParser : public Parser {
-public:
- CalendarParser(DefsStructureParser* p) : Parser(p) {}
- virtual const char* keyword() const { return "calendar"; }
- virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens);
-};
-
-#endif
diff --git a/ecflow_4_0_7/AParser/src/ClockParser.cpp b/ecflow_4_0_7/AParser/src/ClockParser.cpp
deleted file mode 100644
index 162f4db..0000000
--- a/ecflow_4_0_7/AParser/src/ClockParser.cpp
+++ /dev/null
@@ -1,143 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #22 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <stdexcept>
-
-#include "ClockParser.hpp"
-#include "DateParser.hpp"
-#include "TimeSeries.hpp"
-#include "Extract.hpp"
-#include "Str.hpp"
-#include "Suite.hpp"
-
-using namespace ecf;
-using namespace std;
-
-static void extractTheGain(const std::string& theGainToken, ClockAttr& clockAttr)
-{
- if ( theGainToken.find(Str::COLON()) != std::string::npos ) {
- // clock real +01:00
- // clock real 01:36
- int hour,min ;
- bool positiveGain = TimeSeries::getTime(theGainToken,hour,min);
- clockAttr.set_gain(hour,min,positiveGain);
- return;
- }
-
- long theGain = 0;
- std::string theGainStr = theGainToken;
- bool positiveGain = false;
- if ( theGainStr[0] == '+') {
- positiveGain = true;
- theGainStr.erase(theGainStr.begin());
- }
- theGain = Extract::theInt(theGainStr,"Invalid clock gain:" + theGainToken);
- clockAttr.set_gain_in_seconds(theGain,positiveGain);
-}
-
-
-bool ClockParser::doParse( const std::string& line,
- std::vector<std::string >& lineTokens )
-{
- // clock hybrid # a comment
- // clock hybrid
- // clock real #a comment
- // clock real 300
- // clock real +01:00
- // clock real 20.1.2007
- // clock real 20.1.2007 +01:00
-
- // For Testing we allow calendar increment to be change on a per suite basis
- // -c is optional
- // clock real 20.1.2007 +01:00
- // clock hybrid
-
- // Allow clock to be stopped/started when the server is stopped/started
- // and hence always honour time dependencies. See Calendar.h for more details
- // This is optional.( Need to advertise this functionality)
- // clock real 20.1.2007 +01:00 -s
- // clock hybrid -s
- if ( lineTokens.size() < 2 ) {
- throw std::runtime_error( "ClockParser::doParse: Invalid clock :" + line );
- }
- if ( nodeStack().empty() ) {
- throw std::runtime_error("ClockParser::doParse: Could not add clock as node stack is empty at line: " + line );
- }
-
- bool hybrid = true ;
- if ( lineTokens[1] == "real" ) hybrid = false ;
- else if ( lineTokens[1] == "hybrid" ) hybrid = true;
- else throw std::runtime_error( "Invalid clock :" + line );
-
-
- ClockAttr clockAttr(hybrid);
-
- if ( lineTokens.size() >= 3 && lineTokens[2][0] != '#' ) {
- // if third token is not a comment the time must be of the form
- // clock real 300
- // clock real +01:00
- // clock real 20.1.2007
- // clock real 20.1.2007
-
- if ( lineTokens[2].find(".") != std::string::npos ) {
- // clock real 20.1.2007
-
- // If 0 returned then day,month,year is of form *, and not valid
- int day,month,year;
- DateAttr::getDate(lineTokens[2],day,month,year);
-
- // This will throw std::aout_of_range for an invalid clock date. Note no wild carding allowed.
- clockAttr.date(day,month,year); // this will check the date
-
- if ( lineTokens.size() >= 4 && lineTokens[3][0] != '#' ) {
- // clock real 20.1.2007 +01:00
- // clock real 20.1.2007 +300
- // clock real 20.1.2007 350
- extractTheGain(lineTokens[3], clockAttr);
- }
- }
- else {
- // clock real 300
- // clock real +01:00
- extractTheGain(lineTokens[2], clockAttr);
- }
- }
-
- // Look for the optional -s , i.e start/stop calendar when the server starts/stops
- // clock real 20.1.2007 +01:00 -s
- // clock hybrid -s
- size_t line_token_size = lineTokens.size();
- for(size_t i = 2; i < line_token_size; i++ ) {
- if (lineTokens[i] == "-s") {
- clockAttr.startStopWithServer(true);
- break;
- }
- // Reached the comment, no more valid tokens possible
- if (lineTokens[i][0] == '#') {
- // handles comments of the form:
- // # comment
- // #comment
- // since we check the first character
- break;
- }
- }
-
- Suite* suite = nodeStack_top()->isSuite();
- if (!suite) throw std::runtime_error("Clock can only be added to suites and not " + nodeStack_top()->debugType() );
-
- suite->addClock(clockAttr);
-
- return true;
-}
-
diff --git a/ecflow_4_0_7/AParser/src/ClockParser.hpp b/ecflow_4_0_7/AParser/src/ClockParser.hpp
deleted file mode 100644
index e996b95..0000000
--- a/ecflow_4_0_7/AParser/src/ClockParser.hpp
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef CLOCKPARSER_HPP_
-#define CLOCKPARSER_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "Parser.hpp"
-class ClockAttr;
-
-class ClockParser : public Parser {
-public:
- ClockParser(DefsStructureParser* p) : Parser(p) {}
- virtual const char* keyword() const { return "clock"; }
- virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens);
-};
-
-#endif
diff --git a/ecflow_4_0_7/AParser/src/CronParser.cpp b/ecflow_4_0_7/AParser/src/CronParser.cpp
deleted file mode 100644
index 9f2ff39..0000000
--- a/ecflow_4_0_7/AParser/src/CronParser.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #13 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include "CronParser.hpp"
-#include "Node.hpp"
-#include "DefsStructureParser.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-
-//#define DEBUG_CRON 1
-
-bool CronParser::doParse( const std::string& line, std::vector<std::string >& lineTokens )
-{
- // cron 23:00 # run every day at 23:00
- // cron 10:00 20:00 01:00 # run every hour between 10am and 8pm
- // cron -w 0,1 10:00 # run every sunday and monday at 10am
- // cron -d 10,11,12 12:00 # run 10th, 11th and 12th of each month at noon
- // cron -m 1,2,3 12:00 # run on Jan,Feb and March every day at noon.
- // cron -w 0 -m 5,6,7,8 10:00 20:00 01:00 # run every sunday, between May-Aug, every hour between 10am and 8pm
- if ( lineTokens.size() < 2 ) throw std::runtime_error( "CronParser::doParse: Invalid cron: " + line );
-
-#ifdef DEBUG_CRON
- cerr << "CronParser::doParse " << line << "\n";
-#endif
-
- bool parse_state = (rootParser()->get_file_type() != PrintStyle::DEFS);
-
- size_t index = 1; // to get over the cron
- CronAttr cronAttr;
- CronAttr::parse( cronAttr,lineTokens, index, parse_state);
-
- nodeStack_top()->addCron( cronAttr );
- return true;
-}
diff --git a/ecflow_4_0_7/AParser/src/CronParser.hpp b/ecflow_4_0_7/AParser/src/CronParser.hpp
deleted file mode 100644
index baadf7c..0000000
--- a/ecflow_4_0_7/AParser/src/CronParser.hpp
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef CRONPARSER_HPP_
-#define CRONPARSER_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "Parser.hpp"
-
-class CronParser : public Parser {
-public:
- CronParser(DefsStructureParser* p) : Parser(p) {}
- virtual const char* keyword() const { return "cron"; }
- virtual bool doParse(const std::string& line,std::vector<std::string>& lineTokens);
-};
-
-#endif
-
-
diff --git a/ecflow_4_0_7/AParser/src/DateParser.cpp b/ecflow_4_0_7/AParser/src/DateParser.cpp
deleted file mode 100644
index b3a4c9d..0000000
--- a/ecflow_4_0_7/AParser/src/DateParser.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #14 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <iostream>
-#include "DefsStructureParser.hpp"
-#include "DateParser.hpp"
-#include "Node.hpp"
-
-using namespace ecf;
-using namespace std;
-
-bool DateParser::doParse( const std::string& line,
- std::vector<std::string >& lineTokens )
-{
- // date 15.11.2009 # <value> // with PersistStyle::STATE & MIGRATE
- // date 15.*.*
- // date *.1.*
- if ( lineTokens.size() < 2 ) {
- throw std::runtime_error( "DateParser::doParse: Invalid date :" + line );
- }
-
- if ( nodeStack().empty() ) {
- throw std::runtime_error("DateParser::doParse: Could not add date as node stack is empty at line: " + line );
- }
-
- // DateAttr::create can throw for invalid dates
- DateAttr date = DateAttr::create( lineTokens[1]) ;
-
- // state
- if (lineTokens.size() == 4 && rootParser()->get_file_type() != PrintStyle::DEFS) {
- if (lineTokens[3] == "free") {
- date.setFree();
- }
- }
-
- nodeStack_top()->addDate( date );
-
- return true;
-}
diff --git a/ecflow_4_0_7/AParser/src/DateParser.hpp b/ecflow_4_0_7/AParser/src/DateParser.hpp
deleted file mode 100644
index 9616f70..0000000
--- a/ecflow_4_0_7/AParser/src/DateParser.hpp
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef DATEPARSER_HPP_
-#define DATEPARSER_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "Parser.hpp"
-
-class DateParser : public Parser {
-public:
- DateParser(DefsStructureParser* p) : Parser(p) {}
- virtual const char* keyword() const { return "date"; }
- virtual bool doParse(const std::string& /*line*/, std::vector<std::string>& lineTokens);
-};
-
-#endif
diff --git a/ecflow_4_0_7/AParser/src/DayParser.cpp b/ecflow_4_0_7/AParser/src/DayParser.cpp
deleted file mode 100644
index 18b0e6f..0000000
--- a/ecflow_4_0_7/AParser/src/DayParser.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #11 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <stdexcept>
-#include "DayParser.hpp"
-#include "DefsStructureParser.hpp"
-#include "Node.hpp"
-
-using namespace std;
-
-bool DayParser::doParse( const std::string& line, std::vector<std::string >& lineTokens )
-{
- // day monday # free
- // day tuesday
- if ( lineTokens.size() < 2 ) {
- throw std::runtime_error( "DayParser::doParse: Invalid day :" + line );
- }
- if ( nodeStack().empty() ) {
- throw std::runtime_error("DayParser::doParse: Could not add day as node stack is empty at line: " + line );
- }
-
- DayAttr day = DayAttr::create( lineTokens[1] );
-
- // state
- if (lineTokens.size() == 4 && rootParser()->get_file_type() != PrintStyle::DEFS) {
- if (lineTokens[3] == "free") {
- day.setFree();
- }
- }
-
- nodeStack_top()->addDay( day );
-
- return true;
-}
diff --git a/ecflow_4_0_7/AParser/src/DayParser.hpp b/ecflow_4_0_7/AParser/src/DayParser.hpp
deleted file mode 100644
index 5708c57..0000000
--- a/ecflow_4_0_7/AParser/src/DayParser.hpp
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef DAYPARSER_HPP_
-#define DAYPARSER_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #8 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "Parser.hpp"
-
-class DayParser : public Parser {
-public:
- DayParser(DefsStructureParser* p) : Parser(p) {}
- virtual const char* keyword() const { return "day"; }
- virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens);
-};
-#endif
diff --git a/ecflow_4_0_7/AParser/src/DefsParser.cpp b/ecflow_4_0_7/AParser/src/DefsParser.cpp
deleted file mode 100644
index 313a57a..0000000
--- a/ecflow_4_0_7/AParser/src/DefsParser.cpp
+++ /dev/null
@@ -1,425 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #47 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <sstream>
-#include <fstream>
-
-#include "DefsParser.hpp"
-#include "ExternParser.hpp"
-#include "AutoCancelParser.hpp"
-#include "RepeatParser.hpp"
-#include "ClockParser.hpp"
-#include "CalendarParser.hpp"
-#include "VariableParser.hpp"
-#include "InlimitParser.hpp"
-#include "LimitParser.hpp"
-#include "TimeParser.hpp"
-#include "TodayParser.hpp"
-#include "CronParser.hpp"
-#include "MeterParser.hpp"
-#include "DefsStatusParser.hpp"
-#include "EventParser.hpp"
-#include "LabelParser.hpp"
-#include "TriggerParser.hpp"
-#include "DefsStructureParser.hpp"
-#include "DateParser.hpp"
-#include "DayParser.hpp"
-#include "VerifyParser.hpp"
-#include "ZombieAttrParser.hpp"
-#include "LateParser.hpp"
-#include "DefsStateParser.hpp"
-#include "Stl.hpp"
-#include "Str.hpp"
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-
-#include <boost/token_functions.hpp>
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-
-//#define DEBUG_PARSER 1
-
-template<class T>
-ostream& operator<<(ostream& os, const vector<T>& v) {
- copy(v.begin(), v.end(), ostream_iterator<T>(cout, ","));
- return os;
-}
-
-
-class TextParser : public Parser {
-public:
- TextParser(DefsStructureParser* p) : Parser(p) {}
-
- virtual const char* keyword() const { return "text"; }
-
- virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens) {
-#ifdef DEBUG
- assert(*lineTokens.begin() == keyword());
-#endif
- return true;
- }
-};
-
-class AliasParser : public Parser {
-public:
- AliasParser(DefsStructureParser* p, Parser* parentParser) : Parser(p) {
- reserve_vec(19);
- addParser( new VariableParser(p) );
- addParser( new LabelParser(p) );
- addParser( new MeterParser(p) );
- addParser( new EventParser(p) );
- addParser( new TriggerParser(p) );
- addParser( new InlimitParser(p) );
- addParser( new LateParser(p) );
- addParser( new DefsStatusParser(p) );
- addParser( new CompleteParser(p) );
- addParser( new TimeParser(p) );
- addParser( new RepeatParser(p) );
- addParser( new TodayParser(p) );
- addParser( new CronParser(p) );
- addParser( new LimitParser(p) );
- addParser( new DateParser(p) );
- addParser( new DayParser(p) );
- addParser( new AutoCancelParser(p) );
- addParser( new VerifyParser(p) );
- addParser( new ZombieAttrParser(p) );
- }
-
- virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens) {
-
- const char* first_token = lineTokens[0].c_str();
- if (Str::local_strcmp(first_token,keyword()) == 0) {
-
- if (lineTokens.size() < 2) throw std::runtime_error("Alias name missing.");
-
- addAlias(line,lineTokens);
-
- return true;
- }
- else if (Str::local_strcmp(first_token,"endalias") == 0) { // required at the end
- popNode();
- return true;
- }
- return Parser::doParse(line,lineTokens);
- }
-
- virtual const char* keyword() const { return "alias"; }
-
-private:
-
- void addAlias(const std::string& line,std::vector<std::string>& lineTokens) const
- {
- // bad test data can mean that last node is not a suite family or task, will fail parse
- if (nodeStack().empty() ) throw std::runtime_error("Add alias failed empty node stack");
-
- // alias can only be added to tasks
- Task* lastAddedTask = nodeStack_top()->isTask();
- if ( lastAddedTask ) {
-
- alias_ptr alias = lastAddedTask->add_alias(lineTokens[1]);
- alias->read_state(line,lineTokens);
- nodeStack().push( std::make_pair(alias.get(),this) );
- }
- else {
- if ( nodeStack_top()->isAlias() ) {
-
- // Alias can _only_ be added to tasks pop the top Node to get to the task
- popNode();
- addAlias(line, lineTokens );
- }
- else throw std::runtime_error("Add alias failed, expected task on node stack");
- }
- }
-};
-
-//================================================================================
-
-class TaskParser : public Parser {
-public:
- TaskParser(DefsStructureParser* p, Parser* parentParser) : Parser(p) {
- reserve_vec(21);
- addParser( new VariableParser(p) );
- addParser( new TriggerParser(p) );
- addParser( new LabelParser(p) );
- addParser( new InlimitParser(p) );
- addParser( new EventParser(p) );
- addParser( new LateParser(p) );
- addParser( new MeterParser(p) );
- addParser( new DefsStatusParser(p) );
- addParser( new CompleteParser(p) );
- addParser( new TimeParser(p) );
- addParser( new RepeatParser(p) );
- addParser( new TodayParser(p) );
- addParser( new CronParser(p) );
- addParser( new LimitParser(p) );
- addParser( new DateParser(p) );
- addParser( new DayParser(p) );
- addParser( new AutoCancelParser(p) );
- addParser( new VerifyParser(p) );
- addParser( new ZombieAttrParser(p) );
- addParser( new AliasParser(p,this) );
- addParser( new TextParser(p) );
- }
-
- virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens) {
-
- const char* first_token = lineTokens[0].c_str();
- if (Str::local_strcmp(first_token,keyword()) == 0) {
-
- if (lineTokens.size() < 2) throw std::runtime_error("Task name missing.");
-
- // end task is optional, so if we get another task, whilst in a task pop the parser
- if ( nodeStack_top()->isTask()) {
- popToContainerNode(); // pop the node stack
- }
-
- addTask(line,lineTokens);
-
- return true;
- }
- else if (Str::local_strcmp(first_token,"endtask") == 0) { // optional
- popToContainerNode();
- return true;
- }
- return Parser::doParse(line,lineTokens);
- }
-
- virtual const char* keyword() const { return "task"; }
-
-private:
-
- void addTask(const std::string& line,std::vector<std::string>& lineTokens) const
- {
- // bad test data can mean that last node is not a suite family or task, will fail parse
- if (nodeStack().empty() ) throw std::runtime_error("Add task failed empty node stack");
-
- NodeContainer* lastAddedContainer = nodeStack_top()->isNodeContainer();
- if ( lastAddedContainer ) {
-
- task_ptr task = Task::create(lineTokens[1]);
- if (rootParser()->get_file_type() != PrintStyle::DEFS) task->read_state(line,lineTokens);
- nodeStack().push( std::make_pair(task.get(),this) );
- lastAddedContainer->addTask( task );
- }
- else {
- if ( nodeStack_top()->isTask() ) {
-
- // Task can _only_ be added to suite and families.
- // pop the top Node to get to the Container(suite or family), then call recursively to add task
- popNode();
- addTask(line, lineTokens );
- }
- }
- }
-};
-
-//================================================================================
-
-class FamilyParser : public Parser {
-public:
- FamilyParser(DefsStructureParser* p) : Parser(p)
- {
- reserve_vec(21);
- addParser( new VariableParser(p) );
- addParser( new TaskParser(p,this) );
- addParser( new TriggerParser(p) );
- addParser( new InlimitParser(p) );
- addParser( new DefsStatusParser(p) );
- addParser( new LimitParser(p) );
- addParser( new CompleteParser(p) );
- addParser( new MeterParser(p) );
- addParser( new TimeParser(p) );
- addParser( new LabelParser(p) );
- addParser( new RepeatParser(p) );
- addParser( new LateParser(p) );
- addParser( new EventParser(p) );
- addParser( new TodayParser(p) );
- addParser( new CronParser(p) );
- addParser( new DateParser(p) );
- addParser( new DayParser(p) );
- addParser( new AutoCancelParser(p) );
- addParser( new VerifyParser(p) );
- addParser( new ZombieAttrParser(p) );
- addParser( new TextParser(p) );
- }
-
- virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens) {
-
- const char* first_token = lineTokens[0].c_str();
- if (Str::local_strcmp(first_token,keyword()) == 0) {
-
- if (lineTokens.size() < 2) throw std::runtime_error("Family name missing.");
-
- addFamily(line,lineTokens);
-
- return true;
- }
- else if (Str::local_strcmp(first_token,"endfamily") == 0) {
-
- popFamily();
- return true;
- }
- else if (Str::local_strcmp(first_token,"endtask") == 0) { // optional
- popNode();
- return true;
- }
- return Parser::doParse(line,lineTokens);
- }
-
- virtual const char* keyword() const { return "family"; }
-
-private:
-
- void addFamily(const std::string& line,const std::vector<std::string>& lineTokens) const
- {
- assert( !nodeStack().empty() );
- Suite* lastAddedSuite = nodeStack_top()->isSuite();
- if (lastAddedSuite ) {
-
- family_ptr family = Family::create(lineTokens[1]);
- if (rootParser()->get_file_type() != PrintStyle::DEFS) family->read_state(line,lineTokens);
-
- nodeStack().push( std::make_pair(family.get(),this) );
- lastAddedSuite->addFamily( family );
- }
- else {
- // support hierarchical families
- Family* lastAddedFamily = nodeStack_top()->isFamily();
- if ( lastAddedFamily ) {
-
- family_ptr family = Family::create(lineTokens[1]);
- if (rootParser()->get_file_type() != PrintStyle::DEFS) family->read_state(line,lineTokens);
-
- nodeStack().push( std::make_pair(family.get(),this));
- lastAddedFamily->addFamily( family );
- }
- else {
- Task* lastAddedTask = nodeStack_top()->isTask();
- if ( lastAddedTask ) {
- // Pop the node, since tasks don't always have end task
- popNode();
- addFamily(line,lineTokens);
- }
- }
- }
- }
-
- void popFamily() const
- {
- // Compensate for the fact that Task don't have endtask, hence when we pop for a
- // family, the top should be a suite/family
- if ( nodeStack_top()->isTask()) {
- nodeStack().pop(); // pop the task
- nodeStack().pop(); // pop the family to get to suite/family
- }
- else {
- nodeStack().pop(); // pop the family to get to suite/family
- }
- }
-};
-
-//================================================================================
-
-// See ECFLOW-106, and SUP-1198, why we don't allow time,today,date,day ate the suite level.
-class SuiteParser : public Parser {
-public:
- SuiteParser(DefsStructureParser* p) : Parser(p), started_(false)
- {
- reserve_vec(17);
- addParser( new VariableParser(p) );
- addParser( new FamilyParser(p) );
- addParser( new TaskParser(p,this) );
- addParser( new LimitParser(p) );
- addParser( new DefsStatusParser(p) );
- addParser( new ClockParser(p) );
- addParser( new InlimitParser(p) );
- addParser( new RepeatParser(p) );
- addParser( new LateParser(p) );
- addParser( new CronParser(p) );
- addParser( new AutoCancelParser(p) );
- addParser( new VerifyParser(p) );
- addParser( new ZombieAttrParser(p) );
- addParser( new EventParser(p) );
- addParser( new LabelParser(p) );
- addParser( new CalendarParser(p) );
- addParser( new MeterParser(p) );
- }
-
- virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens) {
-
- const char* first_token = lineTokens[0].c_str();
- if (Str::local_strcmp(first_token,keyword()) == 0) {
-
- if (started_) throw std::runtime_error("Can't have hierarchical suites.");
- if (lineTokens.size() < 2) throw std::runtime_error("Suite name missing.");
- started_ = true;
-
- addSuite(line,lineTokens);
-
- return true;
- }
- else if (Str::local_strcmp(first_token,"endsuite") == 0) {
-
- if (!started_) {
- throw std::runtime_error("Misplaced endsuite..");
- }
-
- // ... process end suite
- while ( !nodeStack().empty() ) nodeStack().pop();
- started_ = false; // since this parser is reused
- return true;
- }
- return Parser::doParse(line,lineTokens);
- }
-
- virtual const char* keyword() const { return "suite"; }
-
-private:
-
- void addSuite(const std::string& line,std::vector<std::string>& lineTokens) const {
-
- if ( !nodeStack().empty() ) {
- throw std::runtime_error("SuiteParser::addSuite node stack should be empty");
- }
-
- suite_ptr suite = Suite::create(lineTokens[1]);
- if (rootParser()->get_file_type() != PrintStyle::DEFS) suite->read_state(line,lineTokens);
-
- nodeStack().push( std::make_pair(suite.get(),this) );
- defsfile()->addSuite( suite );
- }
-
- bool started_;
-};
-
-//================================================================================
-
-DefsParser::DefsParser(DefsStructureParser* p) : Parser(p)
-{
- reserve_vec(5);
- addParser( new ExternParser(p) );
- addParser( new SuiteParser(p) );
-
- // for defs stat only
- addParser( new DefsStateParser(p) );
- addParser( new VariableParser(p,true) );
- addParser( new HistoryParser(p) );
-}
-
diff --git a/ecflow_4_0_7/AParser/src/DefsParser.hpp b/ecflow_4_0_7/AParser/src/DefsParser.hpp
deleted file mode 100644
index 546ba6d..0000000
--- a/ecflow_4_0_7/AParser/src/DefsParser.hpp
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef DEFSPARSER_HPP_
-#define DEFSPARSER_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "Parser.hpp"
-
-class DefsParser : public Parser {
-public:
- DefsParser(DefsStructureParser* p);
- virtual const char* keyword() const { return "DEFS" ;}
-};
-
-#endif
diff --git a/ecflow_4_0_7/AParser/src/DefsStateParser.cpp b/ecflow_4_0_7/AParser/src/DefsStateParser.cpp
deleted file mode 100644
index 216aacc..0000000
--- a/ecflow_4_0_7/AParser/src/DefsStateParser.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "DefsStateParser.hpp"
-#include "Defs.hpp"
-#include "DefsStructureParser.hpp"
-
-using namespace std;
-using namespace boost;
-
-
-bool DefsStateParser::doParse( const std::string& line, std::vector<std::string >& lineTokens )
-{
-// cout << "line = " << line << "\n";
- if ( lineTokens.size() < 2 ) throw std::runtime_error( "DefsStateParser::doParse Invalid defs_state " + line );
-
- if (lineTokens[1] == PrintStyle::to_string(PrintStyle::STATE)) rootParser()->set_file_type( PrintStyle::STATE );
- else if (lineTokens[1] == PrintStyle::to_string(PrintStyle::MIGRATE)) rootParser()->set_file_type( PrintStyle::MIGRATE );
- else throw std::runtime_error( "DefsStateParser::doParse: file type not specified : " + line );
-
- defsfile()->read_state(line,lineTokens); // this can throw
- return true;
-}
-
-bool HistoryParser::doParse( const std::string& line, std::vector<std::string >& lineTokens )
-{
-// cout << "line = " << line << "\n";
- defsfile()->read_history(line,lineTokens); // this can throw
- return true;
-}
diff --git a/ecflow_4_0_7/AParser/src/DefsStateParser.hpp b/ecflow_4_0_7/AParser/src/DefsStateParser.hpp
deleted file mode 100644
index a158bab..0000000
--- a/ecflow_4_0_7/AParser/src/DefsStateParser.hpp
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef DEFS_STATE_PARSER_HPP_
-#define DEFS_STATE_PARSER_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #9 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "Parser.hpp"
-
-class DefsStateParser : public Parser {
-public:
- DefsStateParser(DefsStructureParser* p) : Parser(p){}
- virtual bool doParse(const std::string& line,std::vector<std::string>& lineTokens);
- virtual const char* keyword() const { return "defs_state"; }
-};
-
-class HistoryParser : public Parser {
-public:
- HistoryParser(DefsStructureParser* p) : Parser(p){}
- virtual bool doParse(const std::string& line,std::vector<std::string>& lineTokens);
- virtual const char* keyword() const { return "history"; }
-};
-
-#endif
diff --git a/ecflow_4_0_7/AParser/src/DefsStatusParser.cpp b/ecflow_4_0_7/AParser/src/DefsStatusParser.cpp
deleted file mode 100644
index 5c269d9..0000000
--- a/ecflow_4_0_7/AParser/src/DefsStatusParser.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #11 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <sstream>
-#include "DefsStatusParser.hpp"
-#include "DState.hpp"
-#include "Node.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-
-bool DefsStatusParser::doParse(
- const std::string& line,
- std::vector<std::string >& lineTokens )
-{
- if ( lineTokens.size() < 2 ) throw std::runtime_error( "DefsStatusParser::doParse: Invalid defstatus :" + line );
-
- if ( ! DState::isValid(lineTokens[1]) ) {
- throw std::runtime_error( "DefsStatusParser::doParse: Invalid defstatus state :" + line );
- }
-
- if ( !nodeStack().empty() ) {
- Node* node = nodeStack_top();
-
- // Check default status not already defined for this node.
- std::map< Node*, bool >::const_iterator it = defStatusMap().find( node );
- if ( it != defStatusMap().end() ) {
- if ( (*it).second ) {
- std::stringstream ss;
- ss << "DefsStatusParser::doParse: " << node->debugType() << " " << node->name() << " already has a default status\n";
- throw std::runtime_error( ss.str() );
- }
- }
- defStatusMap()[node] = true;
- node->addDefStatus( DState::toState( lineTokens[1] ) );
- }
-
- return true;
-}
diff --git a/ecflow_4_0_7/AParser/src/DefsStatusParser.hpp b/ecflow_4_0_7/AParser/src/DefsStatusParser.hpp
deleted file mode 100644
index b8b78c7..0000000
--- a/ecflow_4_0_7/AParser/src/DefsStatusParser.hpp
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef DEFSSTATUSPARSER_HPP_
-#define DEFSSTATUSPARSER_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "Parser.hpp"
-
-class DefsStatusParser : public Parser {
-public:
- DefsStatusParser(DefsStructureParser* p) : Parser(p) {}
- virtual const char* keyword() const { return "defstatus"; }
- virtual bool doParse(const std::string& line,std::vector<std::string>& lineTokens);
-};
-
-#endif /* DEFSSTATUSPARSER_HPP_ */
diff --git a/ecflow_4_0_7/AParser/src/DefsStructureParser.cpp b/ecflow_4_0_7/AParser/src/DefsStructureParser.cpp
deleted file mode 100644
index b97e77d..0000000
--- a/ecflow_4_0_7/AParser/src/DefsStructureParser.cpp
+++ /dev/null
@@ -1,220 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #26 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <sstream>
-
-#include <boost/algorithm/string/trim.hpp>
-#include <boost/tokenizer.hpp>
-#include <boost/token_functions.hpp>
-
-#include "DefsStructureParser.hpp"
-#include "DefsParser.hpp"
-#include "Defs.hpp"
-#include "Version.hpp"
-#include "Str.hpp"
-
-//#define DEBUG_PARSER 1
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-
-/////////////////////////////////////////////////////////////////////////////////////
-DefsStructureParser::DefsStructureParser(Defs* defsfile,const std::string& file_name)
-: defsfile_(defsfile),defsParser_(new DefsParser(this)),
- infile_(file_name),
- lineNumber_(0),
- file_type_(PrintStyle::DEFS)
-{
-}
-
-DefsStructureParser::~DefsStructureParser()
-{
-#ifdef SHOW_PARSER_STATS
- defsParser_->printStats();
-#endif
-}
-
-bool DefsStructureParser::doParse(std::string& errorMsg,std::string& warningMsg)
-{
- if (!do_parse_only(errorMsg)) {
- return false;
- }
-
- if (file_type_ == PrintStyle::MIGRATE) {
- return true;
- }
-
- // Now parse the trigger/complete expressions and resolve in-limits
- return defsfile_->check(errorMsg,warningMsg);
-}
-
-//#define DO_STATS 1
-bool DefsStructureParser::do_parse_only(std::string& errorMsg)
-{
- if ( !infile_.ok() ) {
- std::stringstream ss;
- ss << "Unable to open file! " << infile_.file_name() << "\n\n";
- ss << Version::description() << "\n";
- errorMsg = ss.str();
- return false;
- }
-
- std::vector< std::string > lineTokens; lineTokens.reserve(30); // derived from 3199.def & DO_STATS
- string line; line.reserve(350); // derived from 3199.def & DO_STATS
-#ifdef DO_STATS
- size_t max_line_size = 0; max_no_of_tokens = 0;
-#endif
- while ( infile_.good() ) {
-
- getNextLine( line ); // will increment lineNumer_
-#ifdef DO_STATS
- max_line_size = std::max(max_line_size,line.size());
-#endif
-
- lineTokens.clear(); // This is re-used, hence clear up front
- Str::split(line, lineTokens);
- if (lineTokens.empty()) continue; // ignore empty lines
-#ifdef DO_STATS
- max_no_of_tokens = std::max(max_no_of_tokens,lineTokens.size());
-#endif
-
- // Process each line, according to the parser which is on *top* of the stack
- // If the *top* of the stack is empty use the DefsParser
- Parser* theCurrentParser = (nodeStack_.empty()) ? defsParser_.get() : const_cast<Parser*>(nodeStack_.top().second) ;
- if ( theCurrentParser == NULL ) {
- std::stringstream ss;
- ss << "No parser found: Could not parse '" << line << "' around line number " << lineNumber_ << "\n";
- ss << Version::description() << "\n\n";
- errorMsg = ss.str();
- return false;
- }
-
- try {
- // Note: if the chosen parser does not recognise first token then the parent parser has a go at parsing.
- // If first token begins with '#' it is ignored
- // cout << "DefsStructureParser::currentParser() = " << theCurrentParser->keyword() << "\n";
- theCurrentParser->doParse(line,lineTokens);
- }
- catch ( std::exception& e) {
- std::stringstream ss;
- ss << e.what() << "\n";
- ss << "Could not parse '" << line << "' around line number " << lineNumber_ << "\n";
- ss << Version::description() << "\n\n";
- errorMsg = ss.str();
- return false;
- }
- }
-#ifdef DO_STATS
- cout << "max line size = " << max_line_size << "\n";
- cout << "max token size = " << max_no_of_tokens << "\n";
-#endif
- return true;
-}
-
-void DefsStructureParser::getNextLine(std::string& line)
-{
- // *ALL* the handling of multiple statements per line are handled in this function
- // The presence of ';' signals multiple statements per line.
- if (multi_statements_per_line_vec_.empty()) {
- infile_.getline(line);
- lineNumber_++;
- if (file_type_ == PrintStyle::MIGRATE) {
- // ignore multiline for migrate, *BECAUSE* *history* for group command uses ';'
- return;
- }
-
-
- if (!line.empty()) {
-
- // See if there are multi statements per line, ie task a; task b; task b # comment
- if (line.find(';') != std::string::npos) {
-
- // ignore lines which have ';' but start with a comment. i.e.
- // # task a, task b
- /// calling trim can be very expensive, hence avoid if possible
- std::string::size_type first_non_space_char_pos = line.find_first_not_of(' ');
- if (first_non_space_char_pos != std::string::npos && line[first_non_space_char_pos] == '#') {
- // found leading_comment can ignore this line
- return;
- }
-
-
- // Handle multiple statement with # comment at the end
- // suite fred; task a; task b; endsuite # suite fred; task a; task b; endsuite
- // Remove comment at the end, to avoid adding to list of tokens
- std::string::size_type commentPos = line.find('#');
- if ( commentPos != std::string::npos) line = line.substr(0,commentPos);
-
- char_separator<char> sep(";");
- typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
- tokenizer tokens(line, sep);
- std::copy(tokens.begin(), tokens.end(), back_inserter(multi_statements_per_line_vec_));
- assert( !multi_statements_per_line_vec_.empty());
-
- if ( semiColonInEditVariable() ) {
- // clear multi_statements_per_line_vec_ since we can't cope with ';' in variable value
- // hence edit VAR1 'A;B'; edit VAR2 "b;C"
- // will be treated as one variable and not two
- // TODO need more sophisticated parsing
- multi_statements_per_line_vec_.clear();
- }
- else {
- line = *(multi_statements_per_line_vec_.begin());
- multi_statements_per_line_vec_.erase( multi_statements_per_line_vec_.begin() );
- }
- }
- }
- }
- else {
- line = *(multi_statements_per_line_vec_.begin());
- multi_statements_per_line_vec_.erase( multi_statements_per_line_vec_.begin() );
- }
-
-#ifdef DEBUG_PARSER
- Parser* theParser = currentParser();
- if ( theParser == NULL) {
- cout << lineNumber_ << ": '" << line
- << "' parser( NULL ) node(";
- }
- else {
- cout << lineNumber_ << ": '" << line
- << "' parser(" << theParser->keyword() << ") ";
- if (theParser->parent()) cout << " parent_parser(" << theParser->parent()->keyword() << ")";
- cout << " node(";
- }
-
- if (!nodeStack_.empty())
- cout << nodeStack_top()->debugType() << " : " << nodeStack_top()->name() << ")\n";
- else
- cout << "NULL)\n";
-#endif
-}
-
-bool DefsStructureParser::semiColonInEditVariable()
-{
- if ( multi_statements_per_line_vec_[0].find("edit") != std::string::npos) {
- // all statements must start with a edit, else we have a semi colon inside variable
- // edit A fred; edit B bill # valid
- // edit A 'fred;bill'; edit B 'bill;bill' # Can't cope with this, will be ONE variable !!!!
- for(size_t i = 0; i < multi_statements_per_line_vec_.size(); i++) {
- boost::algorithm::trim(multi_statements_per_line_vec_[i]);
- if (multi_statements_per_line_vec_[i].find("edit") != 0) {
- return true;
- }
- }
- }
- return false;
-}
-
diff --git a/ecflow_4_0_7/AParser/src/DefsStructureParser.hpp b/ecflow_4_0_7/AParser/src/DefsStructureParser.hpp
deleted file mode 100644
index c02e20d..0000000
--- a/ecflow_4_0_7/AParser/src/DefsStructureParser.hpp
+++ /dev/null
@@ -1,79 +0,0 @@
-#ifndef DEFS_STRUCTURE_PARSER_HPP_
-#define DEFS_STRUCTURE_PARSER_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #12 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <string>
-#include <stack>
-#include <map>
-#include <vector>
-#include <fstream>
-
-#include "boost/utility.hpp"
-#include "boost/scoped_ptr.hpp"
-
-#include "File_r.hpp"
-#include "PrintStyle.hpp"
-
-class Defs;
-class Node;
-class Parser;
-
-// This class is used to parse the DEFS file.
-class DefsStructureParser : private boost::noncopyable {
-public:
-
- DefsStructureParser(Defs* defsfile, const std::string& file_name);
- ~DefsStructureParser();
-
- /// Parse the definition file, *AND* check expressions and limits
- /// return true if parse and check are OK, false otherwise
- /// if false is returned, and error message is also returned
- bool doParse(std::string& errorMsg,std::string& warningMsg);
-
- // The file can be of different styles:
- // DEFS: This is the structure only (default)
- // STATE: structure + state
- // MIGRATE: structure + state (No checking, and no externs )
- void set_file_type(PrintStyle::Type_t t) { file_type_ = t; }
- PrintStyle::Type_t get_file_type() const { return file_type_; }
-
-protected: // allow test code access
- bool do_parse_only(std::string& errorMsg);
-
-private:
-
- std::stack< std::pair<Node*,const Parser*> > nodeStack_; // stack of nodes used in parsing
- std::map<Node*,bool> defStatusMap_; // check for duplicates
-
- Defs* defsfile_;
- boost::scoped_ptr<Parser> defsParser_; // Child parsers will be deleted as well
- friend class Parser;
-
- ecf::File_r infile_;
- int lineNumber_;
-
- std::vector<std::string> multi_statements_per_line_vec_;
- PrintStyle::Type_t file_type_;
-
-private:
- // read in the next line form the defs file
- void getNextLine(std::string& line);
- bool semiColonInEditVariable();
- friend class TriggerCompleteParser;
-};
-
-#endif
diff --git a/ecflow_4_0_7/AParser/src/EventParser.cpp b/ecflow_4_0_7/AParser/src/EventParser.cpp
deleted file mode 100644
index c809f7f..0000000
--- a/ecflow_4_0_7/AParser/src/EventParser.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #17 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <stdexcept>
-#include <boost/lexical_cast.hpp>
-#include "EventParser.hpp"
-#include "DefsStructureParser.hpp"
-#include "Str.hpp"
-#include "Node.hpp"
-
-using namespace std;
-using namespace ecf;
-
-bool EventParser::doParse( const std::string& line,
- std::vector<std::string >& lineTokens )
-{
- if ( lineTokens.size() < 2 ) throw std::runtime_error( "EventParser::doParse: Invalid event : " + line );
-
- // Events added to suite/family can not be signaled by child command
- // However alter/force should allow events to set/cleared on Family/suite
- if ( nodeStack().empty() ) {
- throw std::runtime_error("EventParser::doParse: Could not add event as node stack is empty at line: " + line );
- }
-
-
- // ===============================================================
- // Don't use -1, to represent that no number was specified, as on
- // AIX portable binary archive can't cope with this
- // use std::numeric_limits<int>::max()
- // THIS HAS TO BE THE SAME AS THE Event() constructor
- // ================================================================
- string name;
- int number = std::numeric_limits<int>::max();
-
- // Test for numeric, and then casting, is ****faster***** than relying on exception alone
- if ( lineTokens[1].find_first_of( Str::NUMERIC() ) != std::string::npos ) {
- try {
- number = boost::lexical_cast< int >( lineTokens[1] );
- if ( lineTokens.size() >= 3 && lineTokens[2][0] != '#' ) {
- name = lineTokens[2];
- }
- }
- catch ( boost::bad_lexical_cast& ) {
- name = lineTokens[1];
- }
- }
- else {
- name = lineTokens[1];
- }
-
- Event event( number, name );
-
- // state
- if (rootParser()->get_file_type() != PrintStyle::DEFS) {
- if (lineTokens[lineTokens.size()-1] == Event::SET()) {
- event.set_value(true);
- }
- }
-
- nodeStack_top()->addEvent( event ) ;
-
- return true;
-}
diff --git a/ecflow_4_0_7/AParser/src/EventParser.hpp b/ecflow_4_0_7/AParser/src/EventParser.hpp
deleted file mode 100644
index b4fc04c..0000000
--- a/ecflow_4_0_7/AParser/src/EventParser.hpp
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef EVENTPARSER_HPP_
-#define EVENTPARSER_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #8 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "Parser.hpp"
-
-class EventParser : public Parser {
-public:
- EventParser(DefsStructureParser* p) : Parser(p) {}
- virtual const char* keyword() const { return "event"; }
- virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens);
-};
-
-#endif
diff --git a/ecflow_4_0_7/AParser/src/ExternParser.cpp b/ecflow_4_0_7/AParser/src/ExternParser.cpp
deleted file mode 100644
index 6e17d0f..0000000
--- a/ecflow_4_0_7/AParser/src/ExternParser.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "ExternParser.hpp"
-#include "Extract.hpp"
-#include "Defs.hpp"
-
-using namespace std;
-using namespace boost;
-
-bool ExternParser::doParse( const std::string& line,
- std::vector<std::string >& lineTokens )
-{
-// cout << "line = " << line << "\n";
- if ( lineTokens.size() < 2 )
- throw std::runtime_error( "ExternParser::doParse Invalid extern " + line );
-
- // Guard against
- // extern # empty extern with a comment
- // extern #empty extern with a comment
- if (lineTokens[1][0] == '#') {
- throw std::runtime_error( "ExternParser::doParse Invalid extern paths." + line );
- }
-
- // Expecting:
- // extern <path>
- // extern <path>:<attr>
- // where attr is the name of [ event, meter, repeat, variable, generated variable ]
- //
- // We will not split it up:
-
-// cout << "add extern = '" << lineTokens[1] << "'\n";
- defsfile()->add_extern( lineTokens[1]);
-
- return true;
-}
diff --git a/ecflow_4_0_7/AParser/src/ExternParser.hpp b/ecflow_4_0_7/AParser/src/ExternParser.hpp
deleted file mode 100644
index 93f12f1..0000000
--- a/ecflow_4_0_7/AParser/src/ExternParser.hpp
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef EXTERNPARSER_HPP_
-#define EXTERNPARSER_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #9 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "Parser.hpp"
-//
-// Externs: will typically have a absolute path, however sometimes when
-// suite are generated incrementally relative paths can be added
-// extern a path = a
-// extern /a/b/c path = /a/b/c
-// extern a/b/c path = a/b/c
-// extern /a/b/c:YMD path = /a/b/c variable:YMD (i.e event, meter, variable, repeat, generated variable)
-//
-// Externs are not persisted, why ?:
-// o Externs are un-resolved references to node paths in trigger expressions and inlimits
-// These references could be dynamically generated.
-// o Saves on network bandwidth and checkpoint file size.
-// Hence externs are *ONLY* used on the client side.
-//
-class ExternParser : public Parser {
-public:
- ExternParser(DefsStructureParser* p) : Parser(p) {}
- virtual bool doParse(const std::string& line,std::vector<std::string>& lineTokens);
- virtual const char* keyword() const { return "extern"; }
-};
-
-#endif
diff --git a/ecflow_4_0_7/AParser/src/InlimitParser.cpp b/ecflow_4_0_7/AParser/src/InlimitParser.cpp
deleted file mode 100644
index 88b60c2..0000000
--- a/ecflow_4_0_7/AParser/src/InlimitParser.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "InlimitParser.hpp"
-#include "Extract.hpp"
-#include "Node.hpp"
-
-using namespace std;
-
-bool InlimitParser::doParse(
- const std::string& line,
- std::vector<std::string >& lineTokens )
-{
- if ( lineTokens.size() < 2 )
- throw std::runtime_error( "InlimitParser::doParse: Invalid inlimit :" + line );
-
- string path;
- string limitName;
- if ( !Extract::pathAndName( lineTokens[1], path, limitName ) ) {
- throw std::runtime_error( "InlimitParser::doParse: Invalid inlimit : " + line );
- }
-
- //extract priority, if third token is not a comment it must be a priority
- int tokens = Extract::optionalInt( lineTokens, 2, 1, "Invalid in limit : " + line );
-
- if ( !nodeStack().empty() ) {
- Node* node = nodeStack_top();
-
- // cerr << "limitName=" << limitName << " path=" << path << "\n";
- node->addInLimit( InLimit( limitName, path, tokens ) ) ;
- }
- return true;
-}
diff --git a/ecflow_4_0_7/AParser/src/InlimitParser.hpp b/ecflow_4_0_7/AParser/src/InlimitParser.hpp
deleted file mode 100644
index 3d905e5..0000000
--- a/ecflow_4_0_7/AParser/src/InlimitParser.hpp
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef INLIMITPARSER_HPP_
-#define INLIMITPARSER_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "Parser.hpp"
-
-class InlimitParser : public Parser {
-public:
- InlimitParser(DefsStructureParser* p) : Parser(p) {}
- virtual const char* keyword() const { return "inlimit"; }
- virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens) ;
-};
-
-#endif /* INLIMITPARSER_HPP_ */
diff --git a/ecflow_4_0_7/AParser/src/LabelParser.cpp b/ecflow_4_0_7/AParser/src/LabelParser.cpp
deleted file mode 100644
index f6516e8..0000000
--- a/ecflow_4_0_7/AParser/src/LabelParser.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #14 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "LabelParser.hpp"
-#include "Node.hpp"
-#include "DefsStructureParser.hpp"
-
-using namespace std;
-using namespace ecf;
-
-bool LabelParser::doParse( const std::string& line,
- std::vector<std::string >& lineTokens )
-{
- if ( nodeStack().empty() ) {
- throw std::runtime_error("LabelParser::doParse: Could not add label as node stack is empty at line: " + line );
- }
-
- Label label;
- label.parse(line,lineTokens,rootParser()->get_file_type() != PrintStyle::DEFS);
- nodeStack_top()->addLabel( label );
-
- return true;
-}
diff --git a/ecflow_4_0_7/AParser/src/LabelParser.hpp b/ecflow_4_0_7/AParser/src/LabelParser.hpp
deleted file mode 100644
index a7cced7..0000000
--- a/ecflow_4_0_7/AParser/src/LabelParser.hpp
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef LABELPARSER_HPP_
-#define LABELPARSER_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "Parser.hpp"
-
-class LabelParser : public Parser {
-public:
- LabelParser(DefsStructureParser* p) : Parser(p) {}
- virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens);
- virtual const char* keyword() const { return "label"; }
-};
-
-#endif /* LABELPARSER_HPP_ */
diff --git a/ecflow_4_0_7/AParser/src/LateParser.cpp b/ecflow_4_0_7/AParser/src/LateParser.cpp
deleted file mode 100644
index b9c1fa0..0000000
--- a/ecflow_4_0_7/AParser/src/LateParser.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #13 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "LateParser.hpp"
-#include "TimeSeries.hpp"
-#include "LateAttr.hpp"
-#include "DefsStructureParser.hpp"
-#include "Node.hpp"
-
-using namespace ecf;
-using namespace std;
-
-bool LateParser::doParse( const std::string& line, std::vector<std::string >& lineTokens )
-{
- if ( lineTokens.size() < 3 ) throw std::runtime_error( "LateParser::doParse: Invalid late :" + line );
-
- // late -s +00:15 -a 20:00 -c +02:00 #The option can be in any order
- // 0 1 2 3 4 5 6 7 8 9 10 11 12 13
- // late -s +00:15 -c +02:00 # not all options are needed
- // 0 1 2 3 4 5
-
- LateAttr lateAttr; // lateAttr.isNull() will return true;
- assert(lateAttr.isNull());
-
- size_t line_token_size = lineTokens.size();
- for(size_t i = 1; i+1 < line_token_size; i += 2) {
- if (lineTokens[i][0] == '#') break;
-
- if ( lineTokens[i] == "-s") {
- if ( !lateAttr.submitted().isNULL() ) throw std::runtime_error( "LateParser::doParse:2: Invalid late :" + line );
- int hour = -1; int min = -1;
- TimeSeries::getTime(lineTokens[i+1],hour,min);
- lateAttr.addSubmitted( TimeSlot(hour,min) );
- }
- else if ( lineTokens[i] == "-a") {
- if ( !lateAttr.active().isNULL() ) throw std::runtime_error( "LateParser::doParse:3: Invalid late :" + line );
- int hour = -1; int min = -1;
- TimeSeries::getTime(lineTokens[i+1],hour,min);
- lateAttr.addActive( TimeSlot(hour,min) );
- }
- else if ( lineTokens[i] == "-c") {
- if ( !lateAttr.complete().isNULL() ) throw std::runtime_error( "LateParser::doParse:4: Invalid late :" + line );
- int hour = -1; int min = -1;
- bool relative = TimeSeries::getTime(lineTokens[i+1],hour,min);
- lateAttr.addComplete( TimeSlot(hour,min), relative );
- }
- else throw std::runtime_error( "LateParser::doParse:5: Invalid late :" + line );
- }
-
- if (lateAttr.isNull()) {
- throw std::runtime_error( "LateParser::doParse:6: Invalid late :" + line );
- }
-
- // state
- if (rootParser()->get_file_type() != PrintStyle::DEFS && lineTokens[line_token_size-1] == "late") {
- lateAttr.setLate(true);
- }
-
- nodeStack_top()->addLate( lateAttr ) ;
- return true;
-}
diff --git a/ecflow_4_0_7/AParser/src/LateParser.hpp b/ecflow_4_0_7/AParser/src/LateParser.hpp
deleted file mode 100644
index 2cdb6d6..0000000
--- a/ecflow_4_0_7/AParser/src/LateParser.hpp
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef LATEPARSER_HPP_
-#define LATEPARSER_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "Parser.hpp"
-
-class LateParser : public Parser {
-public:
- LateParser(DefsStructureParser* p) : Parser(p) {}
- virtual const char* keyword() const { return "late"; }
- virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens);
-};
-#endif
diff --git a/ecflow_4_0_7/AParser/src/LimitParser.cpp b/ecflow_4_0_7/AParser/src/LimitParser.cpp
deleted file mode 100644
index 95517b1..0000000
--- a/ecflow_4_0_7/AParser/src/LimitParser.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #11 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "LimitParser.hpp"
-#include "Extract.hpp"
-#include "Node.hpp"
-#include "DefsStructureParser.hpp"
-
-using namespace std;
-
-bool LimitParser::doParse(
- const std::string& line,
- std::vector<std::string >& lineTokens )
-{
- // limit name the_limit # value path1 path2
- if ( lineTokens.size() < 3 )
- throw std::runtime_error( "LimitParser::doParse: Invalid limit " + line );
-
- if ( nodeStack().empty() )
- throw std::runtime_error("LimitParser::doParse: Could not add limit as node stack is empty at line: " + line );
-
- int limitValue = Extract::theInt( lineTokens[2], "LimitParser::doParse: Invalid limit value: " + line );
-
- Node* node = nodeStack_top();
-
- if (rootParser()->get_file_type() != PrintStyle::DEFS) {
- // state
- int value = 0;
- std::set<std::string> paths;
- bool comment_fnd = false;
- bool value_processed = false;
- for(size_t i = 3; i < lineTokens.size(); i++) {
- if (comment_fnd) {
- if (!value_processed) {
- value = Extract::theInt(lineTokens[i],"LimitParser::doParse: Could not extract limit value: " + lineTokens[i]);
- value_processed = true;
- }
- else {
- paths.insert(lineTokens[i]);
- }
- }
- if (lineTokens[i] == "#") comment_fnd = true;
- }
-
- node->addLimit( Limit( lineTokens[1], limitValue, value, paths ) ) ;
- }
- else {
- // structure
- node->addLimit( Limit( lineTokens[1], limitValue ) ) ;
- }
- return true;
-}
diff --git a/ecflow_4_0_7/AParser/src/LimitParser.hpp b/ecflow_4_0_7/AParser/src/LimitParser.hpp
deleted file mode 100644
index 503b18b..0000000
--- a/ecflow_4_0_7/AParser/src/LimitParser.hpp
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef LIMITPARSER_HPP_
-#define LIMITPARSER_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "Parser.hpp"
-
-class LimitParser : public Parser {
-public:
- LimitParser(DefsStructureParser* p) : Parser(p) {}
- virtual const char* keyword() const { return "limit"; }
- virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens);
-};
-
-#endif /* LIMITPARSER_HPP_ */
diff --git a/ecflow_4_0_7/AParser/src/MeterParser.cpp b/ecflow_4_0_7/AParser/src/MeterParser.cpp
deleted file mode 100644
index 70024e2..0000000
--- a/ecflow_4_0_7/AParser/src/MeterParser.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #14 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include "MeterParser.hpp"
-#include "Extract.hpp"
-#include "Node.hpp"
-#include "DefsStructureParser.hpp"
-
-using namespace ecf;
-using namespace std;
-
-bool MeterParser::doParse( const std::string& line, std::vector<std::string >& lineTokens )
-{
- // meter 0 100 100 # value
- if ( lineTokens.size() < 4 )
- throw std::runtime_error("MeterParser::doParse: Invalid meter :" + line );
-
- if ( nodeStack().empty() ) {
- throw std::runtime_error("MeterParser::doParse: Could not add meter as node stack is empty at line: " + line );
- }
-
- int min = Extract::theInt( lineTokens[2], "Invalid meter : " + line );
- int max = Extract::theInt( lineTokens[3], "Invalid meter : " + line );
- int colorChange = Extract::optionalInt( lineTokens, 4, 0, "Invalid meter : " + line );
- Meter meter(lineTokens[1], min, max, colorChange );
-
- // state
- if (rootParser()->get_file_type() != PrintStyle::DEFS) {
- bool comment_fnd = false;
- for(size_t i = 2; i < lineTokens.size(); i++) {
- if (comment_fnd) {
- // token after comment is the value
- int value = Extract::theInt(lineTokens[i],"MeterParser::doParse, could not extract meter value");
- meter.set_value(value); // can throw if value not in range
- }
- if (lineTokens[i] == "#") comment_fnd = true;
- }
- }
-
- nodeStack_top()->addMeter( meter ) ;
-
- return true;
-}
diff --git a/ecflow_4_0_7/AParser/src/MeterParser.hpp b/ecflow_4_0_7/AParser/src/MeterParser.hpp
deleted file mode 100644
index d7aa14c..0000000
--- a/ecflow_4_0_7/AParser/src/MeterParser.hpp
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef METERPARSER_HPP_
-#define METERPARSER_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "Parser.hpp"
-
-class MeterParser : public Parser {
-public:
- MeterParser(DefsStructureParser* p) : Parser(p) {}
- virtual const char* keyword() const { return "meter"; }
- virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens);
-};
-
-#endif /* METERPARSER_HPP_ */
diff --git a/ecflow_4_0_7/AParser/src/Parser.cpp b/ecflow_4_0_7/AParser/src/Parser.cpp
deleted file mode 100644
index 169f954..0000000
--- a/ecflow_4_0_7/AParser/src/Parser.cpp
+++ /dev/null
@@ -1,167 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #34 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <sstream>
-#include <fstream>
-#include <boost/foreach.hpp>
-
-#include "Parser.hpp"
-#include "DefsStructureParser.hpp"
-#include "Stl.hpp"
-#include "Str.hpp"
-#include "Indentor.hpp"
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-using namespace boost::gregorian;
-
-//#define DEBUG_PARSER 1
-
-template<class T>
-ostream& operator<<(ostream& os, const vector<T>& v) {
- copy(v.begin(), v.end(), ostream_iterator<T>(cout, ","));
- return os;
-}
-
-
-
-// ===============================================================================
-
-Parser::Parser( DefsStructureParser* p )
-: parent_(NULL),
- rootParser_( p )
-#ifdef SHOW_PARSER_STATS
- ,parserCount_(0)
-#endif
-{}
-
-Parser::~Parser() {
- DeletePtrs( expectedParsers_ );
-}
-
-bool Parser::doParse(const std::string& line, std::vector<std::string>& lineTokens)
-{
- const char *first_token = lineTokens[0].c_str();
- size_t theSize = expectedParsers_.size();
- for(size_t i = 0; i < theSize; ++i) {
- Parser* p = expectedParsers_[i];
-
- if (Str::local_strcmp(first_token,p->keyword()) == 0) {
-
-#ifdef SHOW_PARSER_STATS
- p->incrementParserCount(); // used for stats
-#endif
-
- return p->doParse(line,lineTokens);
- }
- }
-
-#ifdef DEBUG_PARSER
- cerr << "Parser::" << keyword() << " token = '" << *lineTokens.begin() << "' did not match parsers(";
- BOOST_FOREACH(Parser* p, expectedParsers_) { cerr << " " << p->keyword() ; }
- cerr << ") Trying parent ";
- if (parent()) cout << "Parser::" << parent()->keyword();
- cerr << "\n";
-#endif
-
- // Parent should handle "endfamily", "family" and "endsuite" for hierarchical families
- if (parent() && ((Str::local_strcmp(first_token,"endfamily") == 0) ||
- (Str::local_strcmp(first_token,"family") == 0) ||
- (Str::local_strcmp(first_token,"endsuite") == 0))) {
- return parent()->doParse(line,lineTokens);
- }
-
- // Check if first token is '#' comment character
- // very first non space character is # comment, hence ignore this line
- if (*first_token == '#') {
- // std::cout << "Ignoring line with leading comment : " << line << "\n";
- return true;
- }
-
- // Does not match any parser, or leading comment
- std::string errorMsg = "Unexpected keyword ";
- errorMsg += *lineTokens.begin();
- errorMsg += " found whilst parsing ";
- errorMsg += keyword();
- if ( !nodeStack().empty() ) {
- errorMsg += " ";
- errorMsg += nodeStack_top()->name();
- }
- throw std::runtime_error( errorMsg );
- return false;
-}
-
-
-Defs* Parser::defsfile() const { return rootParser_->defsfile_ ;}
-std::stack< std::pair<Node*,const Parser*> >& Parser::nodeStack() const { return rootParser_->nodeStack_;}
-Node* Parser::nodeStack_top() const { return rootParser_->nodeStack_.top().first;}
-std::map<Node*,bool>& Parser::defStatusMap() const { return rootParser_->defStatusMap_; }
-
-void Parser::dumpStackTop(const std::string& msg, const std::string& msg2) const
-{
- std::cout << msg << " '" << msg2 << "' ++++++++++++++++++++++++++++++++++++++++++++++++++\n";
- if (rootParser_->nodeStack_.empty()) std::cout << "nodeStack_ is EMPTY\n";
- else std::cout << "TOP = " << rootParser_->nodeStack_.top().first->debugType()
- << " '" << rootParser_->nodeStack_.top().first->name() << "'\n";
-}
-
-void Parser::addParser(Parser* p)
-{
- p->parent(this);
- expectedParsers_.push_back(p);
-}
-
-void Parser::popNode() const { nodeStack().pop();}
-
-
-void Parser::popToContainerNode() const
-{
- while ( !nodeStack().empty() && !nodeStack_top()->isNodeContainer() ) {
- nodeStack().pop(); // keep poping till we get to family or suite
- }
-}
-
-void Parser::dump(const std::vector<std::string>& lineTokens)
-{
- cout << "tokens:";
- for(unsigned i=0; i < lineTokens.size(); i++) {
- cout << " '" << lineTokens[i] << "' ";
- }
- cout << "\n";
-}
-
-
-#ifdef SHOW_PARSER_STATS
-void Parser::printStats()
-{
- Indentor::indent( std::cout ) << "Parser::" << keyword() << "\n";
- BOOST_FOREACH(Parser* p, expectedParsers_) {
- Indentor::indent( std::cout ) << p->keyword() << " " << p->parserCount() << "\n";
- }
-
- Indentor in;
- BOOST_FOREACH(Parser* p, expectedParsers_) {
- if (p->hasChildren()) {
- p->printStats();
- }
- }
-}
-#endif
-
diff --git a/ecflow_4_0_7/AParser/src/Parser.hpp b/ecflow_4_0_7/AParser/src/Parser.hpp
deleted file mode 100644
index cafb833..0000000
--- a/ecflow_4_0_7/AParser/src/Parser.hpp
+++ /dev/null
@@ -1,80 +0,0 @@
-#ifndef PARSER_HPP_
-#define PARSER_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #23 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <string>
-#include <vector>
-#include <stack>
-#include <map>
-
-class DefsStructureParser;
-class Node;
-class Defs;
-
-//#define SHOW_PARSER_STATS 1
-
-class Parser {
-public:
- Parser(DefsStructureParser* p);
- virtual ~Parser();
-
- // if child does not recognise token try the parent
- virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens);
- Parser* parent() const { return parent_;}
- void parent(Parser* p) { parent_ = p;}
-
- virtual const char* keyword() const = 0;
-
- DefsStructureParser* rootParser() const { return rootParser_;}
-
- // convenience function that access DefsStructureParser
- std::stack< std::pair<Node*,const Parser*> >& nodeStack() const;
- Node* nodeStack_top() const;
- std::map<Node*,bool >& defStatusMap() const;
-
-#ifdef SHOW_PARSER_STATS
- // The following function used in parser stats only
- void printStats();
-#endif
-
-protected:
-
- Defs* defsfile() const;
- void dumpStackTop(const std::string& msg, const std::string& msg2 = "") const;
- void addParser(Parser* p);
- void popNode() const;
- void popToContainerNode() const;
- static void dump(const std::vector<std::string>& lineTokens);
- void reserve_vec(int res) { expectedParsers_.reserve(res); }
-
-private:
-
- bool hasChildren() const { return !expectedParsers_.empty();}
-
- Parser* parent_;
- DefsStructureParser* rootParser_;
- std::vector<Parser*> expectedParsers_;
-
-#ifdef SHOW_PARSER_STATS
- // The following function used in parser stats only
- void incrementParserCount() { parserCount_++;}
- int parserCount() const { return parserCount_;}
- int parserCount_;
-#endif
-};
-
-#endif
diff --git a/ecflow_4_0_7/AParser/src/RepeatParser.cpp b/ecflow_4_0_7/AParser/src/RepeatParser.cpp
deleted file mode 100644
index f6cc351..0000000
--- a/ecflow_4_0_7/AParser/src/RepeatParser.cpp
+++ /dev/null
@@ -1,178 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #31 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "RepeatParser.hpp"
-#include "Extract.hpp"
-#include "Str.hpp"
-#include "Node.hpp"
-#include "DefsStructureParser.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-
-
-bool RepeatParser::doParse( const std::string& line,
- std::vector<std::string >& lineTokens )
-{
- size_t line_token_size = lineTokens.size();
- if ( line_token_size < 3 ) throw std::runtime_error( "RepeatParser::doParse: Invalid repeat " + line );
- if ( nodeStack().empty() ) throw std::runtime_error("RepeatParser::doParse: Could not add repeat as node stack is empty at line: " + line );
-
- string errorMsg = "Invalid repeat : ";
- errorMsg += line;
-
- if ( lineTokens[1] == "date" ) {
- // repeat date VARIABLE yyyymmdd yyyymmdd [delta]
- if ( line_token_size < 5 ) throw std::runtime_error( errorMsg );
-
- string name = lineTokens[2];
- int startYMD = Extract::ymd( lineTokens[3], errorMsg );
- int endYMD = Extract::ymd( lineTokens[4], errorMsg );
- int delta = Extract::optionalInt( lineTokens, 5, 1, errorMsg );
- RepeatDate rep( name, startYMD, endYMD, delta );
- int value = 0;
- if (get_value(lineTokens,value)) rep.set_value(value);
-
- nodeStack_top()->addRepeat( Repeat( rep ) ) ;
- }
- else if ( lineTokens[1] == "enumerated" ) {
-
- if ( line_token_size < 4 ) throw std::runtime_error( errorMsg );
-
- // repeat enumerated VARIABLE "first" "second" "last" # comment
- string name = lineTokens[2];
- std::vector<std::string> theEnums; theEnums.reserve(line_token_size);
- for(size_t i = 3; i < line_token_size; i++) {
- std::string theEnum = lineTokens[i];
- if (theEnum[0] == '#') break;
- Str::removeSingleQuotes(theEnum);// remove quotes, they get added back when we persist
- Str::removeQuotes(theEnum); // remove quotes, they get added back when we persist
- theEnums.push_back(theEnum);
- }
- if ( theEnums.empty() ) throw std::runtime_error( errorMsg );
-
- RepeatEnumerated rep( name, theEnums) ;
- int index = 0; // This is *assumed to be the index* and not the value
- if (get_value(lineTokens,index)) rep.set_value(index);
-
- nodeStack_top()->addRepeat( Repeat( rep ) ) ;
- }
- else if ( lineTokens[1] == "integer" ) {
- // repeat integer VARIABLE start end [step]
- if ( line_token_size < 5 ) throw std::runtime_error( errorMsg );
-
- string name = lineTokens[2];
- int start = Extract::theInt(lineTokens[3],errorMsg);
- int end = Extract::theInt(lineTokens[4],errorMsg);
- int step = Extract::optionalInt(lineTokens,5, 1,errorMsg );
- RepeatInteger rep( name, start, end, step );
- int value = 0;
- if (get_value(lineTokens,value)) rep.set_value(value);
-
- nodeStack_top()->addRepeat( Repeat( rep ) ) ;
- }
- else if ( lineTokens[1] == "day" ) {
- // repeat day step [ yyyymmdd ] # the step can be positive or negative
- // *** See RepeatAttr.h ***
- // *** We will not support end date until there is a clear requirement for this
- int step = Extract::theInt(lineTokens[2],"Invalid repeat day:");
-
- // report end date as a parser error
- if ( line_token_size >= 4 && lineTokens[3][0] != '#') {
- throw std::runtime_error( "RepeatParser::doParse: repeat day, <end-date> not supported: " + line );
- }
- // day has no state
- nodeStack_top()->addRepeat( Repeat( RepeatDay( step ) ) ) ;
- }
- else if ( lineTokens[1] == "string" ) {
-
- if ( line_token_size < 4 ) throw std::runtime_error( errorMsg );
-
- string name = lineTokens[2];
- std::vector<std::string> theEnums; theEnums.reserve(line_token_size);
- for(size_t i = 3; i < line_token_size; i++) {
- std::string theEnum = lineTokens[i];
- if (theEnum[0] == '#') break;
- Str::removeSingleQuotes(theEnum);// remove quotes, they get added back when we persist
- Str::removeQuotes(theEnum); // remove quotes, they get added back when we persist
- theEnums.push_back(theEnum);
- }
- if ( theEnums.empty() ) throw std::runtime_error( errorMsg );
-
- RepeatString rep( name, theEnums) ;
- int index = 0;
- if (get_value(lineTokens,index)) rep.set_value(index);
-
- nodeStack_top()->addRepeat( Repeat( rep ) ) ;
- }
- else if ( lineTokens[1] == "month" ) {
- // repeat month step [ yyyymmdd ] # the step can be positive or negative
- throw std::runtime_error( "RepeatParser::doParse: repeat month not supported: " + line );
-
-// int endDate = 0;
-// int step = 0;
-// extractDayMonthYear( lineTokens, step, endDate );
-// nodeStack_top()->addRepeat( Repeat( RepeatMonth( step, endDate ) ) );
- }
- else if ( lineTokens[1] == "year" ) {
- // repeat year step [ yyyymmdd ] # the step can be positive or negative
- throw std::runtime_error( "RepeatParser::doParse: repeat year not supported: " + line );
-// int endDate = 0;
-// int step = 0;
-// extractDayMonthYear( lineTokens, step, endDate );
-// nodeStack_top()->addRepeat( Repeat( RepeatYear( step, endDate ) ) );
- }
- else if ( lineTokens[1] == "file" ) {
- // NOT SUPPORTED
- }
- else {
- throw std::runtime_error( "RepeatParser::doParse: Invalid repeat " + line );
- }
- return true;
-}
-
-//void RepeatParser::extractDayMonthYear( const std::vector< std::string >& lineTokens,
-// int& x,
-// int& endDate )
-//{
-// x = Extract::theInt( lineTokens[2], "invalid repeat" );
-// if ( lineTokens.size() >= 4 && lineTokens[3][0] != '#') {
-// std::string errorMsg = "Invalid repeat";
-// endDate = Extract::ymd( lineTokens[3], errorMsg );
-// }
-// if ( ! nodeStack_top()->isSuite() ) {
-// throw std::runtime_error( "RepeatParser::doParse: Invalid repeat day/month/year only valid for suite " );
-// }
-//}
-
-bool RepeatParser::get_value(const std::vector< std::string >& lineTokens, int& value) const
-{
- // state
- if (rootParser()->get_file_type() != PrintStyle::DEFS) {
- // search back for comment
- // repeat integer VARIABLE start end [step] # value
- std::string token_after_comment;
- for(size_t i = lineTokens.size()-1; i > 3; i--) {
- if (lineTokens[i] == "#") {
- // token after comment is the value
- value = Extract::theInt(token_after_comment,"RepeatParser::doParse, could not extract repeat value");
- return true;
- }
- else token_after_comment = lineTokens[i];
- }
- }
- return false;
-}
diff --git a/ecflow_4_0_7/AParser/src/RepeatParser.hpp b/ecflow_4_0_7/AParser/src/RepeatParser.hpp
deleted file mode 100644
index b946019..0000000
--- a/ecflow_4_0_7/AParser/src/RepeatParser.hpp
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef REPEATPARSER_HPP_
-#define REPEATPARSER_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #8 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "Parser.hpp"
-
-class RepeatParser : public Parser {
-public:
- RepeatParser(DefsStructureParser* p) : Parser(p) {}
-
- virtual const char* keyword() const { return "repeat"; }
- virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens);
-
-private:
-// void extractDayMonthYear(const std::vector<std::string>& lineTokens,int& x, int& endDate);
- bool get_value(const std::vector< std::string >& lineTokens, int& value) const;
-};
-
-#endif
diff --git a/ecflow_4_0_7/AParser/src/TimeParser.cpp b/ecflow_4_0_7/AParser/src/TimeParser.cpp
deleted file mode 100644
index 146a06d..0000000
--- a/ecflow_4_0_7/AParser/src/TimeParser.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #17 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "TimeParser.hpp"
-#include "TimeSeries.hpp"
-#include "Node.hpp"
-#include "DefsStructureParser.hpp"
-
-
-using namespace ecf;
-using namespace std;
-
-bool TimeParser::doParse( const std::string& line, std::vector<std::string >& lineTokens )
-{
- if ( lineTokens.size() < 2 )
- throw std::runtime_error( "TimeParser::doParse: Invalid time :" + line );
-
- bool parse_state = false;
- bool isFree = false;
- if (rootParser()->get_file_type() != PrintStyle::DEFS) {
- parse_state = true;
- bool comment_fnd = false;
- for(size_t i = 2; i < lineTokens.size(); i++) {
- if (comment_fnd && lineTokens[i] == "free") isFree = true;
- if (lineTokens[i] == "#") comment_fnd = true;
- }
- }
-
- size_t index = 1;
- TimeAttr attr( TimeSeries::create(index,lineTokens,parse_state) );
- if (isFree) attr.setFree();
-
- nodeStack_top()->addTime( attr );
- return true;
-}
-
diff --git a/ecflow_4_0_7/AParser/src/TimeParser.hpp b/ecflow_4_0_7/AParser/src/TimeParser.hpp
deleted file mode 100644
index c559430..0000000
--- a/ecflow_4_0_7/AParser/src/TimeParser.hpp
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef TIMEPARSER_HPP_
-#define TIMEPARSER_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "Parser.hpp"
-
-class TimeParser : public Parser {
-public:
- TimeParser(DefsStructureParser* p) : Parser(p) {}
- virtual const char* keyword() const { return "time"; }
- virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens);
-};
-
-#endif /* TIMEPARSER_HPP_ */
diff --git a/ecflow_4_0_7/AParser/src/TodayParser.cpp b/ecflow_4_0_7/AParser/src/TodayParser.cpp
deleted file mode 100644
index 89a3275..0000000
--- a/ecflow_4_0_7/AParser/src/TodayParser.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #13 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "TodayParser.hpp"
-#include "TodayAttr.hpp"
-#include "Node.hpp"
-#include "DefsStructureParser.hpp"
-
-using namespace ecf;
-using namespace std;
-
-bool TodayParser::doParse( const std::string& line, std::vector<std::string >& lineTokens )
-{
- if ( lineTokens.size() < 2 ) throw std::runtime_error( "TodayParser::doParse: Invalid today :" + line );
-
- bool parse_state = false;
- bool isFree = false;
- if (rootParser()->get_file_type() != PrintStyle::DEFS) {
- parse_state = true;
- bool comment_fnd = false;
- for(size_t i = 2; i < lineTokens.size(); i++) {
- if (comment_fnd && lineTokens[i] == "free") isFree = true;
- if (lineTokens[i] == "#") comment_fnd = true;
- }
- }
-
- size_t index = 1;
- TodayAttr attr( TimeSeries::create(index,lineTokens,parse_state) );
- if (isFree) attr.setFree();
-
- nodeStack_top()->addToday( attr );
- return true;
-}
diff --git a/ecflow_4_0_7/AParser/src/TodayParser.hpp b/ecflow_4_0_7/AParser/src/TodayParser.hpp
deleted file mode 100644
index 5444f13..0000000
--- a/ecflow_4_0_7/AParser/src/TodayParser.hpp
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef TODAYPARSER_HPP_
-#define TODAYPARSER_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "Parser.hpp"
-
-class TodayParser : public Parser {
-public:
- TodayParser(DefsStructureParser* p) : Parser(p) {}
- virtual const char* keyword() const { return "today"; }
- virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens);
-};
-
-#endif
diff --git a/ecflow_4_0_7/AParser/src/TriggerParser.cpp b/ecflow_4_0_7/AParser/src/TriggerParser.cpp
deleted file mode 100644
index f646b7b..0000000
--- a/ecflow_4_0_7/AParser/src/TriggerParser.cpp
+++ /dev/null
@@ -1,180 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #17 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <stdexcept>
-#include <sstream>
-
-#include "TriggerParser.hpp"
-#include "Str.hpp"
-#include "DefsStructureParser.hpp"
-#include "Node.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-
-
-static bool hasExtension( const std::string& line, const std::vector< std::string >& lineTokens )
-{
- // cout << "hasExtension = ";
- if ( line[line.size() - 1] == '\\' ) {
- // cout << "true\n";
- return true;
- }
- const std::string& lastToken = lineTokens.back();
- if ( lastToken == "\\" || lastToken[lastToken.size() - 1] == '\\' ) {
- // cout << "true\n";
- return true;
- }
- // cout << "false\n";
- return false;
-}
-
-// ===============================================================================
-
-void TriggerCompleteParser::getExpression(
- const std::string& line,
- std::vector< std::string >& theLineTokens,
- std::string& expression,
- bool& andExp,
- bool& orExp,
- bool& isFree) const
-{
- assert( *theLineTokens.begin() == keyword() );
- if ( theLineTokens.size() < 2 ) throw std::runtime_error( "Invalid " + std::string(keyword()) + " " + line );
-
- // trigger -a n == complete
- // complete -o n == complete
- if (theLineTokens[1] == "-a") {
- andExp = true;
- theLineTokens.erase(theLineTokens.begin() + 1);
- }
- else if (theLineTokens[1] == "-o") {
- orExp = true;
- theLineTokens.erase(theLineTokens.begin() + 1);
- }
-
-
- // Handle continuations, by removing them and adding to expression
- if ( hasExtension( line, theLineTokens ) ) {
- /*
- trigger a == complete and /
- b == complete
- */
- std::vector< std::string > accumalatedTokens = theLineTokens;
- while ( true ) {
-
- std::string line2;
- rootParser()->getNextLine( line2 );
-
- std::vector< std::string > lineTokens2;
- Str::split( line2, lineTokens2 );
-
- std::copy( lineTokens2.begin(), lineTokens2.end(),
- std::back_inserter( accumalatedTokens ) );
-
- if ( !hasExtension( line2, lineTokens2 ) ) {
- break;
- }
-
- if ( accumalatedTokens.back() == "\\" ) { // remove continuation
- accumalatedTokens.pop_back();
- }
- }
-
- size_t accumalated_tokens_size = accumalatedTokens.size();
- for (size_t i = 1; i < accumalated_tokens_size; i++) {
- std::string token = accumalatedTokens[i];
- if ( token[token.size() - 1] == '\\' ) {
- token.erase( token.begin() + token.size() - 1 );
- }
- if ( token.empty() )
- continue;
- if ( token.at( 0 ) == '#' )
- break;
- if ( i != 1 )
- expression += " ";
- expression += token;
- }
- }
- else {
-
- // lineTokens[0] == "trigger";/ "complete"
- size_t line_token_size = theLineTokens.size();
- expression.reserve(line.size());
- for (size_t i = 1; i < line_token_size; i++) {
- if ( theLineTokens[i].at( 0 ) == '#' ) break;
- if ( i != 1 ) expression += " ";
- expression += theLineTokens[i];
- }
-
- // state
- if (rootParser()->get_file_type() != PrintStyle::DEFS) {
- bool comment_fnd = false;
- for(size_t i = 3; i < line_token_size; i++) {
- if (comment_fnd) {
- if (theLineTokens[i] == "free") {
- isFree = true;
- break;
- }
- }
- if (theLineTokens[i] == "#") comment_fnd = true;
- }
- }
- }
-
-// cout << "expression = '" << expression << "'\n";
- if ( expression.empty() ) throw std::runtime_error( "Invalid trigger " + line );
-}
-
-
-bool TriggerParser::doParse( const std::string& line, std::vector<std::string >& lineTokens )
-{
- bool andExp = false;
- bool orExp = false;
- bool isFree = false;
- std::string expression;
- getExpression( line, lineTokens, expression, andExp , orExp, isFree);
-
- if ( !nodeStack().empty() ) {
- Node* node = nodeStack_top();
- if (!andExp && !orExp) node->add_part_trigger( PartExpression( expression )) ;
- else if (andExp) node->add_part_trigger( PartExpression( expression, true)) ;
- else if (orExp) node->add_part_trigger( PartExpression( expression, false)) ;
- else throw std::runtime_error( "Invalid trigger " + line );
- if (isFree) node->freeTrigger();
- }
-
- return true;
-}
-
-bool CompleteParser::doParse( const std::string& line, std::vector<std::string >& lineTokens )
-{
- bool andExp = false;
- bool orExp = false;
- bool isFree = false;
- std::string expression;
- getExpression( line, lineTokens, expression, andExp , orExp, isFree);
-
- if ( !nodeStack().empty() ) {
- Node* node = nodeStack_top();
- if (!andExp && !orExp) node->add_part_complete( PartExpression( expression )) ;
- else if (andExp) node->add_part_complete( PartExpression( expression, true)) ;
- else if (orExp) node->add_part_complete( PartExpression( expression, false)) ;
- else throw std::runtime_error( "Invalid complete trigger " + line );
- if (isFree) node->freeComplete();
- }
- return true;
-}
diff --git a/ecflow_4_0_7/AParser/src/TriggerParser.hpp b/ecflow_4_0_7/AParser/src/TriggerParser.hpp
deleted file mode 100644
index 39d7add..0000000
--- a/ecflow_4_0_7/AParser/src/TriggerParser.hpp
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef TRIGGERPARSER_HPP_
-#define TRIGGERPARSER_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #8 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "Parser.hpp"
-
-class TriggerCompleteParser : public Parser {
-protected:
- TriggerCompleteParser(DefsStructureParser* p) : Parser(p) {}
- void getExpression(const std::string& line,
- std::vector<std::string>& lineTokens,
- std::string& expression,
- bool& andExr,
- bool& orExpr,
- bool& isFree) const;
-};
-
-class TriggerParser : public TriggerCompleteParser {
-public:
- TriggerParser(DefsStructureParser* p) : TriggerCompleteParser(p) {}
- virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens);
- virtual const char* keyword() const { return "trigger"; }
-};
-
-class CompleteParser : public TriggerCompleteParser {
-public:
- CompleteParser(DefsStructureParser* p) : TriggerCompleteParser(p) {}
- virtual bool doParse(const std::string& line, std::vector<std::string>& lineTokens) ;
- virtual const char* keyword() const { return "complete"; }
-};
-
-#endif
diff --git a/ecflow_4_0_7/AParser/src/VariableParser.cpp b/ecflow_4_0_7/AParser/src/VariableParser.cpp
deleted file mode 100644
index 4ee7bc5..0000000
--- a/ecflow_4_0_7/AParser/src/VariableParser.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #23 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "VariableParser.hpp"
-#include "Node.hpp"
-#include "Str.hpp"
-#include "Defs.hpp"
-
-using namespace ecf;
-using namespace std;
-
-bool VariableParser::doParse(
- const std::string& line,
- std::vector<std::string >& lineTokens )
-{
- // Note: For migrate the defs can have variables
- Node* node = NULL;
- if ( nodeStack().empty()) {
- if (!parsing_defs_) throw std::runtime_error("VariableParser::doParse: Could not add variable, as node stack is empty at line: " + line );
- }
- else node = nodeStack_top();
-
- size_t line_tokens_size = lineTokens.size();
- if ( line_tokens_size < 3 ) {
- std::stringstream ss;
- ss << "VariableParser::doParse: expected at least 3 tokens, found " << line_tokens_size << " on line:" << line << "\n";
- if (node) ss << "At node: " << node->debugNodePath() << "\n";
- throw std::runtime_error(ss.str());
- }
-
- // There is no need check for '#' comment character in variable name
- // since the variable constructor will check for this
- // i.e edit #var value
- // edit var# value
-
- // Make sure value does not begin with '#' comment character
- if ( lineTokens[2][0] == '#') {
- // edit fred #comment
- // edit fred #
- std::stringstream ss;
- ss << "VariableParser::doParse: Expected value but found comment at line:" << line << "\n";
- if (node) ss << "At node: " << node->debugNodePath() << "\n";
- throw std::runtime_error(ss.str());
- }
-
-
- // ** For aliases, the variables may be **different** to normal variables in that they may contain a ":" & $
- // ** This is **not** allowed in normal variables.
- // ** i.e it allows for %A:1%, %A:2%, %A:3%
- // ** This is not really recommended but its what the old system supported.
- // ** Hence the variable construction by-passes variable name checking ***
-
- // Note:
- // edit OWNER 'fred' => value = fred
- // edit OWNER 'fred and "ginger"' => value = fred and "ginger"
- // edit OWNER "" => value =
- // edit OWNER '' => value =
- // edit OWNER '"fred"' => value = "fred" * quotes are preserved *
- // edit OWNER "'fred'" => value = fred * tick are not preserved *
- if ( line_tokens_size == 3 ) {
- // The order of removing double quotes and then single quotes is significant here
- Str::removeQuotes(lineTokens[2]); // if first *and* last character is "
- Str::removeSingleQuotes(lineTokens[2]); // if first *and* last character is '
- if (node) {
- if (node->isAlias()) node->addVariable( Variable( lineTokens[1], lineTokens[2],false )); // bypass name checking
- else node->addVariable( Variable( lineTokens[1], lineTokens[2] ));
- }
- else defsfile()->set_server().add_or_update_user_variables(lineTokens[1], lineTokens[2]);
- return true;
- }
-
- // i.e
- // 0 1 2
- // edit ECF_FETCH "smsfetch -F %ECF_FILES% -I %ECF_INCLUDE%" #fred
- std::string value; value.reserve(line.size()-4);
- for (size_t i = 2; i < line_tokens_size; ++i) {
- if ( lineTokens[i].at( 0 ) == '#' ) break;
- if ( i != 2 ) value += " ";
- value += lineTokens[i];
- }
-
- Str::removeQuotes(value);
- Str::removeSingleQuotes(value);
- if (node) {
- if (node->isAlias()) node->addVariable( Variable( lineTokens[1], value, false )); // bypass name checking
- else node->addVariable( Variable( lineTokens[1], value )) ;
- }
- else defsfile()->set_server().add_or_update_user_variables(lineTokens[1], value);
-
- return true;
-}
diff --git a/ecflow_4_0_7/AParser/src/VariableParser.hpp b/ecflow_4_0_7/AParser/src/VariableParser.hpp
deleted file mode 100644
index 7a94db6..0000000
--- a/ecflow_4_0_7/AParser/src/VariableParser.hpp
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef VARIABLEPARSER_HPP_
-#define VARIABLEPARSER_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-// edit fred 'val'
-// edit FRED "smscheck %WSHOST% %EXPVER% %ECF_JOB%"
-//
-// In the old SMS single quotes are used if no interpretation
-// is required and double quotes to allow variable substitution
-// However this is ONLY a requirement for CDP.
-// Note when OLD SMS uses the show command it always outputs with single quotes
-//
-// Do we remove the quotes when we store internally ?
-// i.e if we have :
-// edit YMD '20090901'
-// Then the value '20090901' is not immediately convertible to an integer
-// *************************************************************
-// This is required for evaluation in the abstract syntax tree
-// *************************************************************
-//
-// Hence we will do the following:
-// a/ On parsing always remove quotes ie single or double
-// b/ On serialising always add single quotes
-//============================================================================
-
-#include "Parser.hpp"
-
-class VariableParser : public Parser {
-public:
- VariableParser(DefsStructureParser* p, bool parsing_defs = false) : Parser(p), parsing_defs_(parsing_defs) {}
- virtual const char* keyword() const { return "edit"; }
- virtual bool doParse( const std::string& line, std::vector<std::string >& lineTokens );
-private:
- bool parsing_defs_;
-};
-
-#endif
diff --git a/ecflow_4_0_7/AParser/src/VerifyParser.cpp b/ecflow_4_0_7/AParser/src/VerifyParser.cpp
deleted file mode 100644
index c9938c5..0000000
--- a/ecflow_4_0_7/AParser/src/VerifyParser.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #11 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "VerifyParser.hpp"
-#include "Node.hpp"
-#include "Extract.hpp"
-
-using namespace ecf;
-using namespace std;
-
-bool VerifyParser::doParse( const std::string& line, std::vector<std::string >& lineTokens )
-{
- // expect:
- // verify <state>:int i.e
- // verify complete:3
- if ( lineTokens.size() < 2 ) throw std::runtime_error( "VerifyParser::doParse: Invalid verify :" + line );
-
- if ( !nodeStack().empty() ) {
- Node* node = nodeStack_top();
-
- std::string stateInt = lineTokens[1];
-
- size_t colonPos = stateInt.find_first_of(':');
- if (colonPos == std::string::npos) throw std::runtime_error( "Invalid verify :" + line );
-
- std::string state = stateInt.substr(0,colonPos);
- std::string expected = stateInt.substr(colonPos+1);
-// cout << "state = " << state << "\n";
-// cout << "expected = " << expected << "\n";
-
- if (!NState::isValid(state)) {
- throw std::runtime_error( "VerifyParser::doParse: Invalid state :" + line );
- }
-
- NState::State theState = NState::toState(state);
- int theExpectedStateCnt = Extract::theInt(expected,"Invalid verify" );
-
- node->addVerify( VerifyAttr(theState,theExpectedStateCnt) ) ;
- }
- return true;
-}
diff --git a/ecflow_4_0_7/AParser/src/VerifyParser.hpp b/ecflow_4_0_7/AParser/src/VerifyParser.hpp
deleted file mode 100644
index 26309fe..0000000
--- a/ecflow_4_0_7/AParser/src/VerifyParser.hpp
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef VERIFYPARSER_HPP_
-#define VERIFYPARSER_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : A verify attribute parser. Note verify are only used for verification
-// and do not constitute to the structure of a definition file
-//
-//============================================================================
-
-#include "Parser.hpp"
-
-class VerifyParser : public Parser {
-public:
- VerifyParser(DefsStructureParser* p) : Parser(p) {}
- virtual const char* keyword() const { return "verify"; }
- virtual bool doParse( const std::string& line, std::vector<std::string >& lineTokens );
-};
-
-#endif
diff --git a/ecflow_4_0_7/AParser/src/ZombieAttrParser.cpp b/ecflow_4_0_7/AParser/src/ZombieAttrParser.cpp
deleted file mode 100644
index a832080..0000000
--- a/ecflow_4_0_7/AParser/src/ZombieAttrParser.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "ZombieAttrParser.hpp"
-#include "Node.hpp"
-
-using namespace ecf;
-using namespace std;
-
-bool ZombieAttrParser::doParse( const std::string& line, std::vector<std::string >& lineTokens )
-{
- // expect: tokenizer
- // zombie <zombie_type>: action : child_cmds : lifetime
- // zombie_type = [ user | ecf | path ] # can only have one
- // action = [ fob | fail | block | remove | adopt ] # can only have one
- // child_cmd = [ init, event, meter, label, wait, abort, complete ] # can have mutiple
- // zombie ecf:fob:: # fob all child commands
- // zombie ecf:fail:event,meter:200 # fail child command event,meter and block other children
- if ( lineTokens.size() < 2 ) throw std::runtime_error( "ZombieAttrParser::doParse: Invalid zombie :" + line );
- if (nodeStack().empty() ) throw std::runtime_error("Add zombie failed empty node stack");
-
- //cout << "ZombieAttrParser::doParse: " << lineTokens[1] << "\n";
-
- nodeStack_top()->addZombie( ZombieAttr::create(lineTokens[1]) ) ;
-
- return true;
-}
diff --git a/ecflow_4_0_7/AParser/src/ZombieAttrParser.hpp b/ecflow_4_0_7/AParser/src/ZombieAttrParser.hpp
deleted file mode 100644
index 8a9a55d..0000000
--- a/ecflow_4_0_7/AParser/src/ZombieAttrParser.hpp
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef ZOMBIE_ATTR_PARSER_HPP_
-#define ZOMBIE_ATTR_PARSER_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "Parser.hpp"
-
-class ZombieAttrParser : public Parser {
-public:
- ZombieAttrParser(DefsStructureParser* p) : Parser(p) {}
- virtual const char* keyword() const { return "zombie"; }
- virtual bool doParse( const std::string& line, std::vector<std::string >& lineTokens );
-};
-
-#endif
diff --git a/ecflow_4_0_7/AParser/test/ParseOnly.cpp b/ecflow_4_0_7/AParser/test/ParseOnly.cpp
deleted file mode 100644
index 57c3427..0000000
--- a/ecflow_4_0_7/AParser/test/ParseOnly.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <string>
-#include <iostream>
-#include <fstream>
-
-#include "DefsStructureParser.hpp"
-#include "Defs.hpp"
-#include "PrintStyle.hpp"
-
-using namespace std;
-using namespace ecf;
-
-int main(int argc, char* argv[])
-{
-// cout << "argc = " << argc << "\n";
-// for(int i = 0; i < argc; i++) {
-// cout << "arg " << i << ":" << argv[i] << "\n";
-// }
-
- if (argc != 2) {
- cout << "Expect single argument which is path to a defs file\n";
- return 1;
- }
-
- std::string path = argv[1];
-
- Defs defs;
- DefsStructureParser checkPtParser( &defs, path);
- std::string errorMsg,warningMsg;
- if (!checkPtParser.doParse(errorMsg,warningMsg)) {
- cout << errorMsg << "\n";
- cout << warningMsg << "\n";
- return 1;
- }
-// PrintStyle::setStyle(PrintStyle::MIGRATE);
-// cout << defs;
- return 0;
-}
diff --git a/ecflow_4_0_7/AParser/test/ParseTimer.cpp b/ecflow_4_0_7/AParser/test/ParseTimer.cpp
deleted file mode 100644
index 2a337fc..0000000
--- a/ecflow_4_0_7/AParser/test/ParseTimer.cpp
+++ /dev/null
@@ -1,224 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <string>
-#include <iostream>
-#include <fstream>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include "boost/progress.hpp"
-#include <boost/timer.hpp>
-#include "boost/date_time/posix_time/posix_time_types.hpp"
-
-#include "DefsStructureParser.hpp"
-#include "Defs.hpp"
-#include "NodeContainer.hpp"
-#include "Suite.hpp"
-#include "Task.hpp"
-#include "Family.hpp"
-#include "PrintStyle.hpp"
-#include "PersistHelper.hpp"
-#include "JobsParam.hpp"
-#include "Jobs.hpp"
-#include "DurationTimer.hpp"
-#include "Log.hpp"
-#include "System.hpp"
-
-using namespace std;
-using namespace ecf;
-
-// This test is used to find a task given a path of the form:
-// suite/family/task
-// suite/family/family/task
-void test_find_task_using_path( NodeContainer* f,const Defs& defs )
-{
- if (f != defs.findAbsNode(f->absNodePath()).get() ) cout << "Could not find path " << f->absNodePath() << "\n";
-
- BOOST_FOREACH(node_ptr t, f->nodeVec()) {
- if (t.get() != defs.findAbsNode(t->absNodePath()).get()) cout << "Could not find path " << t->absNodePath() << "\n";
- Family* family = t->isFamily();
- if (family) {
- test_find_task_using_path(family, defs);
- }
- }
-}
-
-// Create derived class, so that we can time the parse only
-// i.e ignore expression build/checking and limit checking
-class TestDefsStructureParser : public DefsStructureParser {
-public:
- TestDefsStructureParser(Defs* defsfile, const std::string& file_name) : DefsStructureParser(defsfile,file_name) {}
- bool do_parse_only(std::string& errorMsg) { return DefsStructureParser::do_parse_only(errorMsg); }
-};
-
-
-int main(int argc, char* argv[])
-{
-// cout << "argc = " << argc << "\n";
-// for(int i = 0; i < argc; i++) {
-// cout << "arg " << i << ":" << argv[i] << "\n";
-// }
-
- if (argc != 2) {
- cout << "Expect single argument which is path to a defs file\n";
- return 1;
- }
-
- std::string path = argv[1];
-
- DurationTimer duration_timer;
- boost::timer timer; // measures CPU, replace with cpu_timer with boost > 1.51, measures cpu & elapsed
-
- /// If this is moved below, we get some caching affect, with the persist and reload timing
- Defs defs;
- {
- timer.restart();
- DefsStructureParser checkPtParser( &defs, path);
- std::string errorMsg,warningMsg;
- bool result = checkPtParser.doParse(errorMsg,warningMsg);
- std::cout << " Parsing Node tree and AST creation time = " << timer.elapsed() << " parse(" << result << ")" << endl;
- }
-
- // {
- // Defs local_defs;
- // timer.restart();
- // TestDefsStructureParser checkPtParser( &local_defs, path);
- // std::string errorMsg;
- // bool result = checkPtParser.do_parse_only(errorMsg);
- // std::cout << " Parsing Node tree *only* time = " << timer.elapsed() << " parse(" << result << ")" << endl;
- // }
-
-
- // {
- // timer.restart();
- // BOOST_FOREACH(suite_ptr s, defs.suiteVec()) { test_find_task_using_path(s.get(),defs); }
- // cout << " Test all paths can be found. time taken = " << timer.elapsed() << endl;
- // }
- //
- // {
- // // Test time for persisting to defs file only
- // std::string tmpFilename = "tmp.def";
- //
- // timer.restart();
- // PrintStyle style(PrintStyle::DEFS);
- // std::ofstream ofs( tmpFilename.c_str() ); ofs << defs;
- // cout << " Persist only, time taken = " << timer.elapsed() << endl;
- //
- // std::remove(tmpFilename.c_str());
- // }
-
- // {
- // // may need to comment out output for large differences. Will double the time.
- // timer.restart();
- // PersistHelper helper;
- // bool result = helper.test_persist_and_reload(defs);
- // cout << " Persist and reload(DEFS) and compare, time taken = "
- // << timer.elapsed() << " file_size(" << helper.file_size() << ") result(" << result << ") msg(" << helper.errorMsg() << ")" << endl;
- // }
-
-#if defined(BINARY_ARCHIVE)
- {
- bool do_compare = false;
- timer.restart();
- PersistHelper helper;
- bool result = helper.test_checkpt_and_reload(defs, do_compare,ecf::Archive::BINARY);
- cout << " Checkpt(BINARY_ARCHIVE) and reload , time taken = ";
- cout << timer.elapsed() << " file_size(" << helper.file_size() << ") result(" << result << ") msg(" << helper.errorMsg() << ")" << endl;
- }
-#elif defined(PORTABLE_BINARY_ARCHIVE)
- {
- bool do_compare = false;
- timer.restart();
- PersistHelper helper;
- bool result = helper.test_checkpt_and_reload(defs, do_compare, ecf::Archive::PORTABLE_BINARY);
- cout << " Checkpt(PORTABLE_BINARY_ARCHIVE) and reload , time taken = ";
- cout << timer.elapsed() << " file_size(" << helper.file_size() << ") result(" << result << ") msg(" << helper.errorMsg() << ")" << endl;
- }
-#elif defined(EOS_PORTABLE_BINARY_ARCHIVE)
- {
- bool do_compare = false;
- timer.restart();
- PersistHelper helper;
- bool result = helper.test_checkpt_and_reload(defs, do_compare, ecf::Archive::EOS_PORTABLE_BINARY);
- cout << " Checkpt(EOS_PORTABLE_BINARY_ARCHIVE) and reload , time taken = ";
- cout << timer.elapsed() << " file_size(" << helper.file_size() << ") result(" << result << ") msg(" << helper.errorMsg() << ")" << endl;
- }
-#else
- {
- bool do_compare = false;
- timer.restart();
- PersistHelper helper;
- bool result = helper.test_checkpt_and_reload(defs, do_compare, ecf::Archive::TEXT);
- cout << " Checkpt(TEXT_ARCHIVE) and reload , time taken = ";
- cout << timer.elapsed() << " file_size(" << helper.file_size() << ") result(" << result << ") msg(" << helper.errorMsg() << ")" << endl;
- }
-// {
-// bool do_compare = false;
-// timer.restart();
-// PersistHelper helper;
-// for(int i = 0; i < 5; i++) {
-// bool result = helper.test_checkpt_and_reload(defs, do_compare, ecf::Archive::TEXT);
-// if (!helper.errorMsg().empty()) cout << " result(" << result << ") msg(" << helper.errorMsg() << ")\n";
-// }
-// cout << " Checkpt(TEXT_ARCHIVE) and reload 5 times: Average time taken = ";
-// cout << timer.elapsed()/5 << " : file_size(" << helper.file_size() << ")\n";
-// }
-#endif
-
-// {
-// // Time how long it takes for job submission. Must call begin on all suites first.
-// timer.restart();
-// defs.beginAll();
-// int count = 10;
-// JobsParam jobsParam; // default is not to create jobs, hence only used in testing
-// Jobs jobs(&defs);
-// for (int i = 0; i < count; i++) {jobs.generate(jobsParam);}
-// cout << " time for " << count << " jobSubmissions:" << timer.elapsed() << "s jobs:" << jobsParam.submitted().size() << endl;
-// }
-//
-// {
-// // Time how long it takes for post process
-// timer.restart();
-// string errorMsg,warningMsg;
-// bool result = defs.check(errorMsg,warningMsg);
-// cout << " time for Defs::check ( inlimit resolution) = " << timer.elapsed() << " result(" << result << ") msg(" << errorMsg << ")" << endl;
-// }
-
-// {
-// // Time how long it takes to delete all nodes/ references. Delete all tasks and then suites/families.
-// timer.restart();
-// std::vector<Task*> tasks;
-// defs.getAllTasks(tasks);
-// BOOST_FOREACH(Task* t, tasks) {
-// if (!defs.deleteChild(t)) cout << "Failed to delete task\n";
-// }
-// tasks.clear(); defs.getAllTasks(tasks);
-// if (!tasks.empty()) cout << "Expected all tasks to be deleted but found " << tasks.size() << "\n";
-//
-// std::vector<suite_ptr> vec = defs.suiteVec(); // make a copy, to avoid invalidating iterators
-// BOOST_FOREACH(suite_ptr s, vec) {
-// std::vector<node_ptr> familyVec = s->nodeVec(); // make a copy, to avoid invalidating iterators
-// BOOST_FOREACH(node_ptr f, familyVec) {
-// if (!defs.deleteChild(f.get())) cout << "Failed to delete family\n";
-// }
-// if (!s->nodeVec().empty()) cout << "Expected all Families to be deleted but found " << s->nodeVec().size() << "\n";
-// if (!defs.deleteChild(s.get())) cout << "Failed to delete suite\n";
-// }
-// if (!defs.suiteVec().empty()) cout << "Expected all Suites to be deleted but found " << defs.suiteVec().size() << "\n";
-//
-// cout << " time for deleting all nodes = " << timer.elapsed() << endl;
-// }
- cout << " Total elapsed time = " << duration_timer.duration() << " seconds\n";
-}
diff --git a/ecflow_4_0_7/AParser/test/PersistHelper.cpp b/ecflow_4_0_7/AParser/test/PersistHelper.cpp
deleted file mode 100644
index 184471e..0000000
--- a/ecflow_4_0_7/AParser/test/PersistHelper.cpp
+++ /dev/null
@@ -1,237 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <boost/archive/tmpdir.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <iostream>
-#include <fstream>
-
-#include "PersistHelper.hpp"
-#include "DefsStructureParser.hpp"
-#include "PrintStyle.hpp"
-#include "Defs.hpp"
-#include "Ecf.hpp"
-
-namespace fs = boost::filesystem;
-using namespace std;
-using namespace ecf;
-
-bool PersistHelper::test_persist_and_reload( const Defs& theInMemoryDefs, PrintStyle::Type_t file_type_on_disk)
-{
- // Write parsed file to disk, and reload, then compare defs, they should be the same
- errorMsg_.clear();
- file_size_ = 0;
-
-#ifdef DEBUG
- std::string tmpFilename = "tmp_d.def";
-#else
- std::string tmpFilename = "tmp.def";
-#endif
- {
- // The file MUST be written in the *SAME* form that it was read
- // Otherwise they will not compare:
- PrintStyle style(file_type_on_disk);
- std::ofstream ofs( tmpFilename.c_str() );
- ofs << theInMemoryDefs;
- }
-
- // Reload the file we just persisted and compare with in memory defs
- Defs savedDef;
- return reload_from_defs_file(theInMemoryDefs,savedDef,tmpFilename);
-}
-
-
-bool PersistHelper::test_checkpt_and_reload( const Defs& theInMemoryDefs, bool do_compare, ecf::Archive::Type at)
-{
- errorMsg_.clear();
- file_size_ = 0;
-
- // Save in memory defs as a check pt file, then restore and compare
- Defs reloaded_defs;
- return reload_from_checkpt_file(theInMemoryDefs,reloaded_defs,do_compare,at);
-}
-
-
-bool PersistHelper::test_state_persist_and_reload_with_checkpt(const Defs& theInMemoryDefs )
-{
- // Write Defs to disk, and reload, then compare defs relaoded checkpt file, they should be the same
- errorMsg_.clear();
- file_size_ = 0;
-
-#ifdef DEBUG
- std::string tmpFilename = "tmp_d.def";
-#else
- std::string tmpFilename = "tmp.def";
-#endif
- {
- // The file MUST be written in the *SAME* form that it was read
- // Otherwise they will not compare:
- PrintStyle style(PrintStyle::MIGRATE); // will save edit history
- std::ofstream ofs( tmpFilename.c_str() );
- ofs << theInMemoryDefs;
- }
-
- // Reload the file we just persisted and compare with in memory defs
- Defs reloaded_defs;
- if (!reload_from_defs_file(theInMemoryDefs,reloaded_defs,tmpFilename)) {
- return false;
- }
-
- // Save in memory defs as a check pt file, then restore and compare
- Defs reloaded_checkPt_defs;
- if (!reload_from_checkpt_file(theInMemoryDefs,reloaded_checkPt_defs,true,ecf::Archive::default_archive())) {
- return false;
- }
-
- // Make sure reloading def's file with state is same as the checkpt file
- Ecf::set_debug_equality(true);
- bool match = reloaded_defs == reloaded_checkPt_defs;
- Ecf::set_debug_equality(false);
-
- if (!match) {
- std::stringstream ss;
- ss << "\nPersistHelper::test_state_persist_and_reload_with_checkpt\n";
- ss << "In reloaded_defs_file and reloaded_checkPt_defs don't match\n";
- ss << "+++++++++++++ in memory defs ++++++++++++++++++++++++++++\n";
- PrintStyle style(PrintStyle::MIGRATE); // will save edit history
- ss << theInMemoryDefs;
- ss << "+++++++++++++ reloaded_defs ++++++++++++++++++++++++++++\n";
- ss << reloaded_defs;
- ss << "++++++++++++++ reloaded_checkPt_defs ++++++++++++++++++++++++++++\n";
- ss << reloaded_checkPt_defs;
- errorMsg_ += ss.str();
- }
- else {
- if (compare_edit_history_ && !reloaded_defs.compare_edit_history(reloaded_checkPt_defs)) {
- std::stringstream ss;
- ss << "\nPersistHelper::test_state_persist_and_reload_with_checkpt compare_edit_history_\n";
- ss << "In reloaded_defs_file and reloaded_checkPt_defs edit history don't match\n";
- ss << "+++++++++++++ in memory defs ++++++++++++++++++++++++++++\n";
- PrintStyle style(PrintStyle::MIGRATE); // will save edit history
- ss << theInMemoryDefs;
- ss << "+++++++++++++ reloaded_defs ++++++++++++++++++++++++++++\n";
- ss << reloaded_defs;
- ss << "++++++++++++++ reloaded_checkPt_defs ++++++++++++++++++++++++++++\n";
- ss << reloaded_checkPt_defs;
- errorMsg_ += ss.str();
- }
- }
- return errorMsg_.empty();
-}
-
-
-bool PersistHelper::reload_from_defs_file(const Defs& theInMemoryDefs, Defs& reloaded_defs, const std::string& tmpFilename )
-{
- std::string warningMsg;
- DefsStructureParser defsParser( &reloaded_defs, tmpFilename );
- bool theParse = defsParser.doParse(errorMsg_,warningMsg);
- if (!theParse) {
- std::stringstream ss;
- ss << "RE-PARSE failed for " << tmpFilename << "\n";
- errorMsg_ += ss.str();
- return false;
- }
-
- // Make sure the file we just parsed match's the one we persisted
- Ecf::set_debug_equality(true);
- bool match = reloaded_defs == theInMemoryDefs;
- Ecf::set_debug_equality(false);
-
- if (!match) {
- std::stringstream ss;
- ss << "\nPersistHelper::reload_from_defs_file\n";
- ss << "In memory and reloaded def's don't match\n";
- ss << "+++++++++++++ Saved/reloaded_defs ++++++++++++++++++++++++++++\n";
- PrintStyle style(PrintStyle::STATE);
- ss << reloaded_defs;
- ss << "++++++++++++++ In memory def ++++++++++++++++++++++++++++\n";
- ss << theInMemoryDefs;
- errorMsg_ += ss.str();
- }
- else {
- if (compare_edit_history_ && !reloaded_defs.compare_edit_history(theInMemoryDefs)) {
- std::stringstream ss;
- ss << "\nPersistHelper::reload_from_defs_file compare_edit_history_\n";
- ss << "In memory and reloaded def's don't match\n";
- ss << "+++++++++++++ Saved/reloaded_defs ++++++++++++++++++++++++++++\n";
- PrintStyle style(PrintStyle::MIGRATE);
- ss << reloaded_defs;
- ss << "++++++++++++++ In memory def ++++++++++++++++++++++++++++\n";
- ss << theInMemoryDefs;
- errorMsg_ += ss.str();
- }
- }
-
- file_size_ = fs::file_size(tmpFilename);
- std::remove(tmpFilename.c_str());
- return errorMsg_.empty();
-}
-
-
-bool PersistHelper::reload_from_checkpt_file(const Defs& theInMemoryDefs,
- Defs& reloaded_defs,
- bool do_compare ,
- ecf::Archive::Type at)
-{
- // make sure edit history is saved
-#ifdef DEBUG
- std::string tmpCheckPt_file = "tmp.check_debug";
-#else
- std::string tmpCheckPt_file = "tmp.check";
-#endif
- theInMemoryDefs.save_as_checkpt(tmpCheckPt_file,at);
-
- try {
- // Parse the file we just persisted and load the defs file into memory.
- reloaded_defs.restore_from_checkpt(tmpCheckPt_file,at);
-
- if (do_compare ) {
- // Make sure the checkpoint file file we just parsed match's the one we persisted
- bool match = reloaded_defs == theInMemoryDefs;
- if (!match) {
- std::stringstream ss;
- ss << "\nPersistHelper::reload_from_checkpt_file\n";
- ss << "In memory and reloaded def's don't match\n";
- ss << "+++++++++++++ Saved/reloaded check pt file ++++++++++++++++++++++++++++\n";
- PrintStyle style(PrintStyle::STATE);
- ss << reloaded_defs;
- ss << "++++++++++++++ In memory def ++++++++++++++++++++++++++++\n";
- ss << theInMemoryDefs;
- errorMsg_ += ss.str();
- }
- else {
- if (compare_edit_history_ && !reloaded_defs.compare_edit_history(theInMemoryDefs)) {
- std::stringstream ss;
- ss << "\nPersistHelper::reload_from_checkpt_file compare_edit_history_\n";
- ss << "In reloaded_defs_file and reloaded_checkPt_defs edit history don't match\n";
- ss << "+++++++++++++ Saved/reloaded check pt file ++++++++++++++++++++++++++++\n";
- PrintStyle style(PrintStyle::MIGRATE);
- ss << reloaded_defs;
- ss << "++++++++++++++ theInMemoryDefs ++++++++++++++++++++++++++++\n";
- ss << theInMemoryDefs;
- errorMsg_ += ss.str();
- }
- }
- }
- }
- catch (std::exception& e) {
- errorMsg_ = "PersistHelper::reload_from_checkpt_file: " + string(e.what());
- }
-
- file_size_ = fs::file_size(tmpCheckPt_file);
- std::remove(tmpCheckPt_file.c_str());
-
- return errorMsg_.empty();
-}
diff --git a/ecflow_4_0_7/AParser/test/PersistHelper.hpp b/ecflow_4_0_7/AParser/test/PersistHelper.hpp
deleted file mode 100644
index 02b607d..0000000
--- a/ecflow_4_0_7/AParser/test/PersistHelper.hpp
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef PERSISTHELPER_HPP_
-#define PERSISTHELPER_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-
-#include <boost/noncopyable.hpp>
-#include <string>
-#include "Archive.hpp"
-#include "PrintStyle.hpp"
-class Defs;
-
-/// Given a in memory defs file, this class will write it to disk
-/// and reload the definition file structure and will then make a comparison
-/// to ensure they are the same
-class PersistHelper : private boost::noncopyable {
-public:
- PersistHelper(bool compare_edit_history = false) : file_size_(0),compare_edit_history_(compare_edit_history) {}
-
- bool test_persist_and_reload( const Defs& theInMemoryDefs, PrintStyle::Type_t file_type_on_disk);
- bool test_checkpt_and_reload( const Defs& theInMemoryDefs, bool do_compare = true,ecf::Archive::Type at = ecf::Archive::default_archive());
- bool test_state_persist_and_reload_with_checkpt( const Defs& theInMemoryDefs );
- const std::string& errorMsg() const { return errorMsg_;}
-
- /// returns the file size of the temporary file created by:
- /// test_persist_and_reload(..) or test_checkpt_and_reload(..)
- size_t file_size() const { return file_size_;}
-
-private:
-
- bool reload_from_defs_file( const Defs& theInMemoryDefs, Defs& reloaded_defs, const std::string& filename );
- bool reload_from_checkpt_file(const Defs& theInMemoryDefs,
- Defs& reloaded_defs,
- bool do_compare = true,
- ecf::Archive::Type at = ecf::Archive::default_archive() );
-
-private:
-
- std::string errorMsg_;
- size_t file_size_;
- bool compare_edit_history_;
-};
-#endif
-
-
-
diff --git a/ecflow_4_0_7/AParser/test/TestAutoAddExterns.cpp b/ecflow_4_0_7/AParser/test/TestAutoAddExterns.cpp
deleted file mode 100644
index 80a9000..0000000
--- a/ecflow_4_0_7/AParser/test/TestAutoAddExterns.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <string>
-#include <iostream>
-#include <fstream>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/timer.hpp>
-#include "boost/date_time/posix_time/posix_time_types.hpp"
-#include <boost/test/unit_test.hpp>
-
-#include "DefsStructureParser.hpp"
-#include "Defs.hpp"
-#include "NodeContainer.hpp"
-#include "Suite.hpp"
-#include "Task.hpp"
-#include "Family.hpp"
-#include "Log.hpp"
-#include "File.hpp"
-
-namespace fs = boost::filesystem;
-using namespace std;
-using namespace ecf;
-using namespace boost::posix_time;
-
-BOOST_AUTO_TEST_SUITE( ParserTestSuite )
-
-// Test that automatic add of externs
-BOOST_AUTO_TEST_CASE( test_auto_add_externs )
-{
- std::string path = File::test_data("AParser/test/data/single_defs/test_auto_add_extern.def","AParser");
-
- size_t mega_file_size = fs::file_size(path);
- cout << "AParser:: ...test_auto_add_externs " << path << " file_size(" << mega_file_size << ")\n";
-
- Defs defs;
- DefsStructureParser checkPtParser( &defs, path);
- std::string errorMsg,warningMsg;
- BOOST_REQUIRE_MESSAGE(checkPtParser.doParse(errorMsg,warningMsg),errorMsg);
- BOOST_REQUIRE_MESSAGE(warningMsg.empty(),"Expected no warnings but found:\n" << warningMsg);
-
- // Check number of extrens read in: Duplicate should be ignore
- BOOST_REQUIRE_MESSAGE(defs.externs().size() == 9 ,"Expected 9 externs as starting point but found " << defs.externs().size() << "\n");
-
- // Test auto extern generation. Don't remove existing extern's
- defs.auto_add_externs(false/* remove_existing_externs_first*/);
- BOOST_REQUIRE_MESSAGE(defs.externs().size() == 9 ,"Expected 9, auto_add_extern(false) gave: " << defs.externs().size() << "\n" << defs << "\n");
-
- // By removing the externs read, in we can determine the real number of extern;s from
- // parsing all the trigger expressions, and inlimit references
- defs.auto_add_externs(true/* remove_existing_externs_first*/);
- BOOST_REQUIRE_MESSAGE(defs.externs().size() == 8 ,"Expected 8 externs, since redundant externs removed, auto_add_extern(true) gave: " << defs.externs().size() << "\n"<< defs << "\n");
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/AParser/test/TestDefsStructurePersistAndReload.cpp b/ecflow_4_0_7/AParser/test/TestDefsStructurePersistAndReload.cpp
deleted file mode 100644
index 4b21b56..0000000
--- a/ecflow_4_0_7/AParser/test/TestDefsStructurePersistAndReload.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <string>
-#include <iostream>
-#include <fstream>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/test/unit_test.hpp>
-#include <boost/foreach.hpp>
-
-#include "PersistHelper.hpp"
-#include "DefsStructureParser.hpp"
-#include "PrintStyle.hpp"
-#include "MyDefsFixture.hpp"
-#include "File.hpp"
-
-namespace fs = boost::filesystem;
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( ParserTestSuite )
-
-//=============================================================================
-// This test case will save the defs file in old style format
-// and the parse it back in. As we add different types to our defs fixture
-// we can automatically check that what we save can be parsed back in.
-// Specifically written to test the parser.
-// Note: Aliases are *NOT* written in the defs file.
-BOOST_AUTO_TEST_CASE( test_defs_structure_persistence_and_reload )
-{
- cout << "AParser:: ...test_defs_structure_persistence_and_reload\n";
-
- std::string checkPtFile = File::test_data("AParser/test/generated_defs_file.txt","AParser");
-
- MyDefsFixture theDefsFixture(checkPtFile);
-
- PersistHelper helper;
- BOOST_CHECK_MESSAGE( helper.test_checkpt_and_reload(theDefsFixture.defsfile_), helper.errorMsg());
-
- // Note: Aliases are *NOT* written in the defs file.
- // Hence in order for this test to pass, we must delete the alias first & reset task alias_no
- std::vector<alias_ptr> alias_vec;
- theDefsFixture.defsfile_.get_all_aliases(alias_vec);
- BOOST_FOREACH(alias_ptr al,alias_vec) {
- al->parent()->isTask()->reset_alias_number();
- al->remove();
- }
- BOOST_CHECK_MESSAGE( helper.test_persist_and_reload(theDefsFixture.defsfile_, PrintStyle::DEFS), helper.errorMsg());
-}
-
-
-// This test is used to find a task given a path of the form:
-// suite/family/task
-// suite/family/family/task
-//
-void test_find_task_using_path( NodeContainer* f,const Defs& defs )
-{
- BOOST_CHECK_MESSAGE(f == defs.findAbsNode(f->absNodePath()).get(), "Could not find path " << f->absNodePath() << "\n");
-
- BOOST_FOREACH(node_ptr t, f->nodeVec()) {
- BOOST_CHECK_MESSAGE( t.get() == defs.findAbsNode(t->absNodePath()).get(), "Could not find path " << t->absNodePath() << "\n");
- Family* family = t->isFamily();
- if (family) {
- test_find_task_using_path(family, defs);
- }
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_find_task_using_paths )
-{
- cout << "AParser:: ...test_find_task_using_paths\n";
-
- MyDefsFixture theDefsFixture;
-
- const std::vector<suite_ptr>& suiteVec = theDefsFixture.defsfile_.suiteVec();
- BOOST_FOREACH(suite_ptr s, suiteVec) {
- test_find_task_using_path(s.get(),theDefsFixture.defsfile_);
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-
diff --git a/ecflow_4_0_7/AParser/test/TestJobGenPerf.cpp b/ecflow_4_0_7/AParser/test/TestJobGenPerf.cpp
deleted file mode 100644
index 422dbef..0000000
--- a/ecflow_4_0_7/AParser/test/TestJobGenPerf.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <iostream>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-
-#include "Defs.hpp"
-#include "Str.hpp"
-#include "File.hpp"
-#include "Log.hpp"
-#include "Jobs.hpp"
-#include "JobsParam.hpp"
-#include "DefsStructureParser.hpp"
-#include "JobProfiler.hpp"
-
-using namespace std;
-using namespace ecf;
-namespace fs = boost::filesystem;
-
-
-// This relies on Pyext/samples/TestJobGenPerf.py to make any defs amenable
-// for this test program.
-//
-// The defs is in /var/tmp/ma0/ECFLOW_TEST/TestJobGenPerf
-//
-int main(int argc, char* argv[])
-{
- if (argc != 2) {
- cout << "Expect single argument which is path to a defs file\n";
- return 1;
- }
-
- // delete the log file if it exists.
- std::string log_path = File::test_data("AParser/test/TestJobGenPerf.log","AParser");
- fs::remove(log_path);
-
-
- std::string path = argv[1];
-
- Defs defs;
- DefsStructureParser checkPtParser( &defs, path);
- std::string errorMsg,warningMsg;
- if (!checkPtParser.doParse(errorMsg,warningMsg)) {
- cout << errorMsg << "\n";
- cout << warningMsg << "\n";
- return 1;
- }
-
- // Check number of tasks, if the submitted output below is too low
- // Then remove, limits,triggers,time,cron so more jobs can be generated.
- std::vector<Task*> tasks;
- defs.getAllTasks(tasks);
- cout << "Tasks = " << tasks.size() << "\n";
-
- defs.beginAll();
-
-
- // Create a new log, file, place after begin to avoid queued state
- Log::create(log_path);
-
- // This controls the log output when job generation > submitJobsInterval
- JobProfiler::set_task_threshold(0);
-
- JobsParam jobParam(20 /*submitJobsInterval*/, true /*createJobs*/, false/* spawn jobs */);
- Jobs job(&defs);
- bool ok = job.generate( jobParam );
- if (!ok) cout << " generate failed: " << jobParam.getErrorMsg();
- cout << "submitted " << jobParam.submitted().size() << "\n";
-
- // fs::remove(log_path);
-
- return 0;
-}
diff --git a/ecflow_4_0_7/AParser/test/TestMigration.cpp b/ecflow_4_0_7/AParser/test/TestMigration.cpp
deleted file mode 100644
index 351b958..0000000
--- a/ecflow_4_0_7/AParser/test/TestMigration.cpp
+++ /dev/null
@@ -1,427 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name : Request
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <string>
-#include <iostream>
-#include <fstream>
-
-#include <boost/archive/tmpdir.hpp>
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include "boost/progress.hpp"
-
-#include "DefsStructureParser.hpp"
-#include "Defs.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "PrintStyle.hpp"
-#include "PersistHelper.hpp"
-#include "Flag.hpp"
-#include "Memento.hpp"
-#include "MyDefsFixture.hpp"
-
-namespace fs = boost::filesystem;
-using namespace std;
-using namespace ecf;
-
-// ********************************************************************
-// These test are used to check that MIGRATE is equivalent to check pt
-// MIGRATE will be used for migration from old to new release
-// MIGRATE is essentially the defs structure with state.
-// The state is written out as comments
-// It is loaded like a normal Defs, the parser detects MIGRATE
-// and loads the state in.
-//
-// By default persistence/MIGRATE *ONLY* writes the state when it not the default.
-// Hence the defaults should *NOT* change. These test will change the state
-// to a non default value.
-//
-// Write the Defs with state and the compare with in memory defs
-// Write the Defs as check pt an then compare with in memory defs
-// Finally compare the two *RELOADED* defs file.
-// ********************************************************************
-
-BOOST_AUTO_TEST_SUITE( ParserTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_state_parser )
-{
- cout << "AParser:: ...test_state_parser\n";
- // **** The persistence will NOT write the defaults, hence we need to change the states
- // **** to test the persistence
- PersistHelper helper;
- std::vector<Flag::Type> flag_list = Flag::list();
- {
- Defs defs;
- BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Empty Defs failed: " << helper.errorMsg());
- }
- {
- Defs defs;
- suite_ptr suite = defs.add_suite("s1");
-
- // Change state other the default
- defs.beginAll();
- suite->set_state(NState::ABORTED);
- for (size_t i = 0; i < flag_list.size(); ++i) suite->flag().set( flag_list[i] );
- suite->suspend();
- BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs),"Add one suite failed: " << helper.errorMsg());
- }
- {
- Defs defs;
- suite_ptr suite = defs.add_suite("s1");
- family_ptr f1 = suite->add_family("f1");
-
- // Change state other the default
- f1->set_state(NState::COMPLETE);
- for (size_t i = 0; i < flag_list.size(); ++i) f1->flag().set( flag_list[i] );
- f1->suspend();
- BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs),"Add one family failed: " << helper.errorMsg());
-
- // Test multiple
- suite->add_family("f2");
- suite->add_family("f3");
- BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs),"Add one family failed: " << helper.errorMsg());
- }
- {
- Defs defs;
- family_ptr f1 = defs.add_suite("s1")->add_family("f1");
- task_ptr t1 = f1->add_task("t1");
-
- for (size_t i = 0; i < flag_list.size(); ++i) t1->flag().set( flag_list[i] );
- t1->suspend();
- t1->set_state(NState::COMPLETE);
-
- // Use memento to modify task state
- SubmittableMemento memento( "Jobs_password","the_rid","the abort reason with spaces",12);
- t1->set_memento(&memento);
-
- BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Add one task failed: " << helper.errorMsg());
-
- // Test multiple
- f1->add_task("t2");
- f1->add_task("t3");
- BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Add one task failed: " << helper.errorMsg());
- }
- {
- Defs defs;
- task_ptr task = defs.add_suite("s1")->add_family("f1")->add_task("t1");
- alias_ptr t1 = task->add_alias_only();
- for (size_t i = 0; i < flag_list.size(); ++i) t1->flag().set( flag_list[i] );
- t1->suspend();
- t1->set_state(NState::COMPLETE);
- // Use memento to modify alias state
- SubmittableMemento memento( "Jobs_password","the_rid","the abort reason with spaces",12);
- t1->set_memento(&memento);
- BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Add one alias failed: " << helper.errorMsg());
-
- // Test multiple
- task->add_alias_only();
- task->add_alias_only();
- // PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
- BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Add multiple alias failed: " << helper.errorMsg());
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_state_node_attributes )
-{
- cout << "AParser:: ...test_state_node_attributes\n";
- PersistHelper helper;
- {
- Defs defs;
- suite_ptr suite = defs.add_suite("s1");
- task_ptr task = suite->add_task("t1");
- ecf::LateAttr lateAttr;
- lateAttr.addSubmitted( ecf::TimeSlot(3,12) );
- lateAttr.addActive( ecf::TimeSlot(3,12) );
- lateAttr.addComplete( ecf::TimeSlot(4,12), true);
- lateAttr.setLate(true);
- task->addLate(lateAttr);
-
- ecf::LateAttr lateAttr1;
- lateAttr1.addSubmitted( ecf::TimeSlot(3,12) );
- lateAttr1.addActive( ecf::TimeSlot(3,12) );
- lateAttr1.addComplete( ecf::TimeSlot(4,12), false);
- lateAttr1.setLate(true);
- task_ptr task1 = suite->add_task("t2");
- task1->addLate(lateAttr1);
-
-// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
- BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Late state: failed: " << helper.errorMsg());
- }
- {
- Defs defs;
- task_ptr task = defs.add_suite("s1")->add_task("t1");
- Meter meter("meter",0,100,100); meter.set_value(10);
- task->addMeter(meter);
-// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
- BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Meter state: failed: " << helper.errorMsg());
- }
- {
- Defs defs;
- task_ptr task = defs.add_suite("s1")->add_task("t1");
- Event event("event"); event.set_value(true);
- Event event2(10,"event"); event2.set_value(true);
- Event event3(10); event3.set_value(true);
- task->addEvent(event);
- task->addEvent(event2);
- task->addEvent(event3);
-// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
- BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Event state: failed: " << helper.errorMsg());
- }
- {
- {
- Defs defs;
- task_ptr task = defs.add_suite("s1")->add_task("t1");
- Label label("name","value"); label.set_new_value("new value");
- task->addLabel(label);
- // PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
- BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Label state: failed: " << helper.errorMsg());
- }
- {
- Defs defs;
- suite_ptr suite = defs.add_suite("s1");
- Label label("name","value"); label.set_new_value("new value");
- suite->addLabel(label);
-// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
- BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Label state: failed: " << helper.errorMsg());
- }
- {
- Defs defs;
- suite_ptr suite = defs.add_suite("s1");
- Label label("name","value\nvalue");
- suite->addLabel(label);
-// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
- BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Label state: failed: " << helper.errorMsg());
- }
- {
- Defs defs;
- suite_ptr suite = defs.add_suite("s1");
- Label label("name","value\nvalue"); label.set_new_value("value\nwith\nmany\nnewlines");
- suite->addLabel(label);
-// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
- BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Label state: failed: " << helper.errorMsg());
- }
- }
- {
- Defs defs;
- suite_ptr suite = defs.add_suite("s1");
- task_ptr t1 = suite->add_task("t1");
- task_ptr t2 = suite->add_task("t2");
- task_ptr t3 = suite->add_task("t3");
- task_ptr t4 = suite->add_task("t4");
- Limit limit("limit",10);
- limit.increment(1,t1->absNodePath());
- limit.increment(1,t2->absNodePath());
- limit.increment(1,t3->absNodePath());
- limit.increment(1,t4->absNodePath());
- suite->addLimit(limit);
-// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
- BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Limit state: failed: " << helper.errorMsg());
- }
-
- // **** Note InLimit does not have any changeable state
-
- {
- Defs defs;
- suite_ptr suite = defs.add_suite("s1");
- task_ptr t1 = suite->add_task("t1");
- task_ptr t2 = suite->add_task("t2");
- task_ptr t3 = suite->add_task("t3");
- task_ptr t4 = suite->add_task("t4");
- task_ptr t5 = suite->add_task("t5");
- task_ptr t6 = suite->add_task("t6");
-
- std::vector<std::string> stringList; stringList.reserve(3);
- stringList.push_back("20130101");
- stringList.push_back("20130201");
- stringList.push_back("20130301");
-
- RepeatEnumerated rep("AEnum",stringList);
- rep.increment();
- t1->addRepeat( rep );
-
- RepeatString rep2("AEnum",stringList);
- rep2.increment();
- t2->addRepeat( rep2 );
-
- RepeatDate rep3("YMD",20090916,20090916,1);
- rep3.increment();
- t3->addRepeat( rep3 );
-
- RepeatInteger rep4("rep",0,100,1);
- rep4.increment();
- t4->addRepeat( rep4 );
- t4->increment_repeat();
-
- RepeatDay rep5(2);
- rep5.increment();
- t5->addRepeat( rep5 );
-
-// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
- BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Repeat state: failed: " << helper.errorMsg());
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_state_time_attributes )
-{
- cout << "AParser:: ...test_state_time_attributes\n";
- PersistHelper helper;
- {
- Defs defs;
- suite_ptr suite = defs.add_suite("s1"); suite->begin();
- task_ptr task = suite->add_task("t1");
- TimeAttr time(10,10); time.setFree(); time.miss_next_time_slot();
- TimeAttr time2(10,10,true); time2.calendarChanged(suite->calendar()); time2.setFree(); time2.miss_next_time_slot();
- TimeAttr time3(TimeSlot(10,10),TimeSlot(12,10),TimeSlot(0,10),true); time3.calendarChanged(suite->calendar());time3.setFree(); time3.miss_next_time_slot();
-
- task->addTime(time);
- task->addTime(time2);
- task->addTime(time3);
-// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
- BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Time state: failed: " << helper.errorMsg());
- }
- {
- Defs defs;
- suite_ptr suite = defs.add_suite("s1"); suite->begin();
- task_ptr task = suite->add_task("t1");
- TodayAttr time(10,10); time.setFree(); time.miss_next_time_slot();
- TodayAttr time2(10,10,true); time2.calendarChanged(suite->calendar()); time2.setFree(); time2.miss_next_time_slot();
- TodayAttr time3(TimeSlot(10,10),TimeSlot(12,10),TimeSlot(0,10),true); time3.calendarChanged(suite->calendar());time3.setFree(); time3.miss_next_time_slot();
- task->addToday(time);
- task->addToday(time2);
- task->addToday(time3);
-// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
- BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Today state: failed: " << helper.errorMsg());
- }
- {
- Defs defs;
- task_ptr task = defs.add_suite("s1")->add_task("t1");
- DayAttr day;
- DayAttr day1; day1.setFree();
- DayAttr day2(DayAttr::FRIDAY); day2.setFree();
- task->addDay(day);
- task->addDay(day1);
- task->addDay(day2);
-// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
- BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Day state: failed: " << helper.errorMsg());
- }
- {
- Defs defs;
- task_ptr task = defs.add_suite("s1")->add_task("t1");
- DateAttr d;
- DateAttr d1; d1.setFree();
- DateAttr d2(1,1,2012); d2.setFree();
- DateAttr d3(0,0,2012); d3.setFree();
- task->addDate(d);
- task->addDate(d1);
- task->addDate(d2);
- task->addDate(d3);
-// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
- BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Date state: failed: " << helper.errorMsg());
- }
- {
- Defs defs;
- suite_ptr suite = defs.add_suite("s1"); suite->begin();
- task_ptr task = suite->add_task("t1");
- task_ptr task2 = suite->add_task("t2");
-
- ecf::CronAttr cronAttr;
- ecf::TimeSlot start( 0, 0 );
- ecf::TimeSlot finish( 10, 0 );
- ecf::TimeSlot incr( 0, 5 );
- std::vector<int> weekdays; for(int i=0;i<7;++i) weekdays.push_back(i);
- std::vector<int> daysOfMonth;for(int i=1;i<32;++i) daysOfMonth.push_back(i);
- std::vector<int> months; for(int i=1;i<13;++i) months.push_back(i);
- cronAttr.addTimeSeries(start,finish,incr);
- cronAttr.addWeekDays( weekdays );
- cronAttr.addDaysOfMonth(daysOfMonth);
- cronAttr.addMonths( months );
- cronAttr.setFree();
- task->addCron(cronAttr);
-
- // Change TimeSeries state
- TimeSeries ts(start,finish,incr,true);
- ts.calendarChanged(suite->calendar());
- ts.miss_next_time_slot();
- cronAttr.addTimeSeries(ts);
- task2->addCron(cronAttr);
-
-// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
- BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Date state: failed: " << helper.errorMsg());
- }
-
- // ZombieAttr do not have any changeable state
-}
-
-BOOST_AUTO_TEST_CASE( test_state_edit_history )
-{
- cout << "AParser:: ...test_state_edit_history\n";
- PersistHelper helper(true /* compare edit History */);
- Defs defs;
- suite_ptr suite = defs.add_suite("s1");
- defs.add_edit_history(suite->absNodePath(),"request1 with single spaces");
- defs.add_edit_history(suite->absNodePath(),"request2 with double spaces");
- defs.add_edit_history(suite->absNodePath(),"request3_with_no_spaces!|?<>$%^&*()_{}:@<>?");
- suite_ptr suite2 = defs.add_suite("s2");
- defs.add_edit_history(suite2->absNodePath(),"request1 with single spaces");
- defs.add_edit_history(suite2->absNodePath(),"request2 with double spaces");
- defs.add_edit_history(suite2->absNodePath(),"request3_with_no_spaces!|?<>$%^&*()_{}:@<>?");
-// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
- BOOST_REQUIRE_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Edit history failed: " << helper.errorMsg());
-}
-
-BOOST_AUTO_TEST_CASE( test_server_state )
-{
- cout << "AParser:: ...test_server_state\n";
- PersistHelper helper(true /* compare edit History */);
- {
- Defs defs;
- defs.set_server().set_state(SState::HALTED);
-// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
- BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Set server state failed " << helper.errorMsg());
- }
- {
- Defs defs;
- defs.set_server().set_state(SState::RUNNING);
-// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
- BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Set server state failed " << helper.errorMsg());
- }
- {
- Defs defs;
- defs.set_server().set_state(SState::SHUTDOWN);
-// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
- BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Set server state failed " << helper.errorMsg());
- }
- {
- Defs defs;
- std::vector<Variable> vec;
- vec.push_back(Variable("name","value1"));
- vec.push_back(Variable("name2","val with 'spaces' "));
- vec.push_back(Variable("name3",""));
- defs.set_server().set_user_variables(vec);
-// PrintStyle::setStyle(PrintStyle::MIGRATE); std::cout << defs;
- BOOST_CHECK_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(defs), "Set server variables failed " << helper.errorMsg());
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_state_fixture_defs )
-{
- cout << "AParser:: ...test_state_fixture_defs\n";
- PersistHelper helper;
- MyDefsFixture theDefsFixture;
- BOOST_REQUIRE_MESSAGE( helper.test_state_persist_and_reload_with_checkpt(theDefsFixture.defsfile_), "Fixture failed: " << helper.errorMsg());
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/AParser/test/TestParser.cpp b/ecflow_4_0_7/AParser/test/TestParser.cpp
deleted file mode 100644
index e214433..0000000
--- a/ecflow_4_0_7/AParser/test/TestParser.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-#define BOOST_TEST_MODULE TestParser
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name : Request
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <string>
-#include <iostream>
-#include <fstream>
-
-#include <boost/archive/tmpdir.hpp>
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include "boost/progress.hpp"
-
-#include "DefsStructureParser.hpp"
-#include "Defs.hpp"
-#include "PrintStyle.hpp"
-#include "PersistHelper.hpp"
-#include "File.hpp"
-#include "ChangeMgrSingleton.hpp"
-
-namespace fs = boost::filesystem;
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( ParserTestSuite )
-
-void test_defs(const std::string& directory, bool pass)
-{
- fs::path full_path( fs::initial_path<fs::path>() );
- full_path = fs::system_complete( fs::path( directory ) );
-
- BOOST_CHECK(fs::exists( full_path ));
- BOOST_CHECK(fs::is_directory( full_path ));
-
- //std::cout << "\nIn directory: " << full_path.directory_string() << "\n\n";
- fs::directory_iterator end_iter;
- for ( fs::directory_iterator dir_itr( full_path ); dir_itr != end_iter; ++dir_itr )
- {
- try
- {
- fs::path relPath(directory + "/" + dir_itr->path().filename().string());
-
- // recurse down directories
- if ( fs::is_directory(dir_itr->status()) ) {
- test_defs(relPath.string(),pass);
- continue;
- }
-
- //std::cout << "......Parsing file " << relPath.string() << "\n";
-
- Defs defs;
- DefsStructureParser parser( &defs , relPath.string() );
-
- std::string errorMsg,warningMsg;
- bool parsedOk = parser.doParse(errorMsg,warningMsg);
- if (pass) {
- // Test expected to pass
- BOOST_CHECK_MESSAGE(parsedOk,"Failed to parse file " << relPath << "\n" << errorMsg);
-
- if (parsedOk) {
- // Write parsed file to a temporary file on disk, and reload, then compare defs, should be the same
- PersistHelper helper;
- BOOST_CHECK_MESSAGE( helper.test_persist_and_reload(defs,parser.get_file_type()), relPath.string() << " " << helper.errorMsg());
- BOOST_CHECK_MESSAGE( helper.test_checkpt_and_reload(defs), relPath.string() << " " << helper.errorMsg());
- }
- }
- else {
- // test expected to fail
- //std::cout << errorMsg << "\n";
- BOOST_CHECK_MESSAGE(!parsedOk,"Parse expected to fail for " << relPath << "\n" << errorMsg);
- }
- }
- catch ( const std::exception & ex )
- {
- std::cout << dir_itr->path().filename() << " " << ex.what() << std::endl;
- }
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_parsing_for_good_defs )
-{
- cout << "AParser:: ...test_parsing_for_good_defs\n";
-
- std::string path = File::test_data("AParser/test/data/good_defs","AParser");
-
- // All the defs in this directory are expected to pass
- test_defs(path, true);
-}
-
-BOOST_AUTO_TEST_CASE( test_parsing_for_bad_defs )
-{
- cout << "AParser:: ...test_parsing_for_bad_defs\n";
-
- std::string path = File::test_data("AParser/test/data/bad_defs","AParser");
-
- // All the defs in this directory are expected to fail
- test_defs(path, false);
-}
-
-BOOST_AUTO_TEST_CASE( test_parsing_for_good_defs_state )
-{
- cout << "AParser:: ...test_parsing_for_good_defs_state\n";
-
- std::string path = File::test_data("AParser/test/data/good_defs_state","AParser");
-
- // All the defs in this directory are expected to pass
- test_defs(path, true);
-
- // Fix memory leaks
- ChangeMgrSingleton::destroy();
-}
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/AParser/test/TestSingleDefsFile.cpp b/ecflow_4_0_7/AParser/test/TestSingleDefsFile.cpp
deleted file mode 100644
index 365d504..0000000
--- a/ecflow_4_0_7/AParser/test/TestSingleDefsFile.cpp
+++ /dev/null
@@ -1,304 +0,0 @@
-#define BOOST_TEST_MODULE TestParser
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <string>
-#include <iostream>
-#include <fstream>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include "boost/progress.hpp"
-#include <boost/timer.hpp>
-#include "boost/date_time/posix_time/posix_time_types.hpp"
-#include <boost/test/unit_test.hpp>
-
-#include "DefsStructureParser.hpp"
-#include "Defs.hpp"
-#include "NodeContainer.hpp"
-#include "Suite.hpp"
-#include "Task.hpp"
-#include "Family.hpp"
-#include "PrintStyle.hpp"
-#include "PersistHelper.hpp"
-#include "JobsParam.hpp"
-#include "Jobs.hpp"
-#include "DurationTimer.hpp"
-#include "Log.hpp"
-#include "System.hpp"
-#include "File.hpp"
-
-namespace fs = boost::filesystem;
-using namespace std;
-using namespace ecf;
-using namespace boost::posix_time;
-
-BOOST_AUTO_TEST_SUITE( ParserTestSuite )
-
-// This test is used to find a task given a path of the form:
-// suite/family/task
-// suite/family/family/task
-void test_find_task_using_path( NodeContainer* f,const Defs& defs )
-{
- BOOST_CHECK_MESSAGE(f == defs.findAbsNode(f->absNodePath()).get(), "Could not find path " << f->absNodePath() << "\n");
-
- BOOST_FOREACH(node_ptr t, f->nodeVec()) {
- BOOST_CHECK_MESSAGE(t.get() == defs.findAbsNode(t->absNodePath()).get(), "Could not find path " << t->absNodePath() << "\n");
- Family* family = t->isFamily();
- if (family) {
- test_find_task_using_path(family, defs);
- }
- }
-}
-
-// Create derived class, so that we can time the parse only
-// i.e ignore expression build/checking and limit checking
-class TestDefsStructureParser : public DefsStructureParser {
-public:
- TestDefsStructureParser(Defs* defsfile, const std::string& file_name) : DefsStructureParser(defsfile,file_name) {}
- bool do_parse_only(std::string& errorMsg) { return DefsStructureParser::do_parse_only(errorMsg); }
-};
-
-BOOST_AUTO_TEST_CASE( test_single_defs )
-{
- DurationTimer duration_timer;
-
- std::string path = File::test_data("AParser/test/data/single_defs/mega.def","AParser");
- size_t mega_file_size = fs::file_size(path);
- cout << "AParser:: ...test_single_defs " << path << " file_size(" << mega_file_size << ")\n";
-
- // Time parse/resolve dependencies: This will need to be #defined depending on the platform
- // Change for file_iterator to plain string halved the time taken to load operation suite
- boost::timer timer; // measures CPU, replace with cpu_timer with boost > 1.51, measures cpu & elapsed
-#ifdef DEBUG
-#if defined(HPUX) || defined(_AIX)
- double expectedTimeForParse = 15.0;
- double expectedTimeForParseOnly = 10.0;
- double expectedTimeForResolveDependencies = 3.5; // this is time for 10 job submissions
- double checkExprAndLimits = 1.0;
- double expectedTimeForFindAllPaths = 7.2;
- double expectedTimeForDefsPersistOnly = 6 ;
- double expectedTimeForDefsPersistAndReload = 24;
- double expectedTimeForCheckPtPersistAndReload = 27;
-#else
- double expectedTimeForParse = 4.5;
- double expectedTimeForParseOnly = 2.0;
- double expectedTimeForResolveDependencies = 0.5 ; // this is time for 10 job submissions
- double checkExprAndLimits = 0.5;
- double expectedTimeForFindAllPaths = 1.2;
- double expectedTimeForDefsPersistOnly = 2 ;
- double expectedTimeForDefsPersistAndReload = 4.5;
- double expectedTimeForCheckPtPersistAndReload = 8.0;
-#endif
-#else
-#if defined(HPUX) || defined(_AIX)
- double expectedTimeForParse = 7.8;
- double expectedTimeForParseOnly = 5.0;
- double expectedTimeForResolveDependencies = 3.5; // this is time for 10 job submissions
- double checkExprAndLimits = 1.0;
- double expectedTimeForFindAllPaths = 4.5;
- double expectedTimeForDefsPersistOnly = 3.5 ;
- double expectedTimeForDefsPersistAndReload = 9.5;
- double expectedTimeForCheckPtPersistAndReload = 11.5;
-#else
- double expectedTimeForParse = 1.2;
- double expectedTimeForParseOnly = 0.6;
- double expectedTimeForResolveDependencies = 0.2 ; // this is time for 10 job submissions
- double checkExprAndLimits = 0.1;
- double expectedTimeForFindAllPaths = 0.58;
- double expectedTimeForDefsPersistOnly = 0.5 ;
- double expectedTimeForDefsPersistAndReload = 1.5;
- double expectedTimeForCheckPtPersistAndReload = 1.6;
-#endif
-#endif
- // ****************************************************************************************
- // Please note: that for Parsing: that the predominate time is taken in creating the AST/ and checking
-
- /// If this is moved below, we get some caching affect, with the persist and reload timing
- Defs defs;
- {
- timer.restart();
- DefsStructureParser checkPtParser( &defs, path);
- std::string errorMsg,warningMsg;
- BOOST_REQUIRE_MESSAGE(checkPtParser.doParse(errorMsg,warningMsg),errorMsg);
- BOOST_CHECK_MESSAGE(timer.elapsed() < expectedTimeForParse,"Performance regression, expected < " << expectedTimeForParse << " seconds for parse/node tree creation but found " << timer.elapsed());
- std::cout << " Parsing Node tree and AST creation time = " << timer.elapsed() << " < limit(" << expectedTimeForParse << ")" << endl;
- }
-
- {
- Defs local_defs;
- timer.restart();
- TestDefsStructureParser checkPtParser( &local_defs, path);
- std::string errorMsg;
- BOOST_REQUIRE_MESSAGE(checkPtParser.do_parse_only(errorMsg),errorMsg);
- BOOST_CHECK_MESSAGE(timer.elapsed() < expectedTimeForParse,"Performance regression, expected < " << expectedTimeForParseOnly << " seconds for parse/node tree creation but found " << timer.elapsed());
- std::cout << " Parsing Node tree *only* time = " << timer.elapsed() << " < limit(" << expectedTimeForParseOnly << ")" << endl;
- }
-
-
- {
- timer.restart();
- BOOST_FOREACH(suite_ptr s, defs.suiteVec()) { test_find_task_using_path(s.get(),defs); }
- BOOST_CHECK_MESSAGE(timer.elapsed() < expectedTimeForFindAllPaths,"Performance regression, expected < " << expectedTimeForFindAllPaths << " seconds to find all paths, but found " << timer.elapsed());
- cout << " Test all paths can be found. time taken = " << timer.elapsed() << " < limit(" << expectedTimeForFindAllPaths << ")" << endl;
- }
-
- {
- // Test time for persisting to defs file only
-#ifdef DEBUG
- std::string tmpFilename = "tmp_d.def";
-#else
- std::string tmpFilename = "tmp.def";
-#endif
-
- timer.restart();
- PrintStyle style(PrintStyle::DEFS);
- std::ofstream ofs( tmpFilename.c_str() ); ofs << defs;
- BOOST_CHECK_MESSAGE(timer.elapsed() < expectedTimeForDefsPersistOnly,"Performance regression, expected < " << expectedTimeForDefsPersistOnly << " to persist defs file, but found " << timer.elapsed());
- cout << " Persist only, time taken = " << timer.elapsed() << " < limit(" << expectedTimeForDefsPersistOnly << ")" << endl;
-
- std::remove(tmpFilename.c_str());
- }
-
- {
- // may need to comment out output for large differences. Will double the time.
- timer.restart();
- PersistHelper helper;
- BOOST_CHECK_MESSAGE( helper.test_persist_and_reload(defs,PrintStyle::DEFS), helper.errorMsg());
- BOOST_CHECK_MESSAGE(timer.elapsed() < expectedTimeForDefsPersistAndReload,"Performance regression, expected < " << expectedTimeForDefsPersistAndReload << " seconds to persist and reload, but found " << timer.elapsed());
- cout << " Persist and reload(DEFS) and compare, time taken = "
- << timer.elapsed() << " < limit(" << expectedTimeForDefsPersistAndReload << ")"
- << " file_size(" << helper.file_size() << ")" << endl;
- }
- {
- timer.restart();
- PersistHelper helper;
- BOOST_CHECK_MESSAGE( helper.test_persist_and_reload(defs,PrintStyle::STATE), helper.errorMsg());
- cout << " Persist and reload(STATE) and compare, time taken = " << timer.elapsed()
- << " file_size(" << helper.file_size() << ")" << endl;
- }
- {
- timer.restart();
- PersistHelper helper;
- BOOST_CHECK_MESSAGE( helper.test_persist_and_reload(defs,PrintStyle::MIGRATE), helper.errorMsg());
- BOOST_CHECK_MESSAGE(timer.elapsed() < expectedTimeForDefsPersistAndReload,"Performance regression, expected < " << expectedTimeForDefsPersistAndReload << " seconds to persist and reload *state*, but found " << timer.elapsed());
- cout << " Persist and reload(MIGRATE) and compare, time taken = "
- << timer.elapsed() << " < limit(" << expectedTimeForDefsPersistAndReload << ")"
- << " file_size(" << helper.file_size() << ")" << endl;
-
- // each platform will have a slightly different size, since the server environment variables
- // will be different, i.e host, pid, i.e check point etc, encompasses the host name, which will be different
- BOOST_CHECK_MESSAGE(helper.file_size() <= 6679000 ,"File size regression expected <= 6679000 but found " << helper.file_size());
- }
-
-#if defined(BINARY_ARCHIVE)
- {
- timer.restart();
- PersistHelper helper;
- BOOST_CHECK_MESSAGE( helper.test_checkpt_and_reload(defs,true,ecf::Archive::BINARY), helper.errorMsg());
- BOOST_CHECK_MESSAGE(timer.elapsed() < expectedTimeForCheckPtPersistAndReload,"Performance regression, expected < " << expectedTimeForCheckPtPersistAndReload << " seconds to persist and reload, but found " << timer.elapsed());
- cout << " Checkpt(BINARY_ARCHIVE) and reload and compare, time taken = ";
- cout << timer.elapsed() << " < limit(" << expectedTimeForCheckPtPersistAndReload << ")" << " file_size(" << helper.file_size() << ")" << endl;
- }
-#elif defined(PORTABLE_BINARY_ARCHIVE)
- {
- timer.restart();
- PersistHelper helper;
- BOOST_CHECK_MESSAGE( helper.test_checkpt_and_reload(defs,true,ecf::Archive::PORTABLE_BINARY), helper.errorMsg());
- BOOST_CHECK_MESSAGE(timer.elapsed() < expectedTimeForCheckPtPersistAndReload,"Performance regression, expected < " << expectedTimeForCheckPtPersistAndReload << " seconds to persist and reload, but found " << timer.elapsed());
- cout << " Checkpt(PORTABLE_BINARY) and reload and compare, time taken = ";
- cout << timer.elapsed() << " < limit(" << expectedTimeForCheckPtPersistAndReload << ")" << " file_size(" << helper.file_size() << ")" << endl;
- }
-#elif defined(EOS_PORTABLE_BINARY_ARCHIVE)
- {
- timer.restart();
- PersistHelper helper;
- BOOST_CHECK_MESSAGE( helper.test_checkpt_and_reload(defs,true,ecf::Archive::EOS_PORTABLE_BINARY), helper.errorMsg());
- BOOST_CHECK_MESSAGE(timer.elapsed() < expectedTimeForCheckPtPersistAndReload,"Performance regression, expected < " << expectedTimeForCheckPtPersistAndReload << " seconds to persist and reload, but found " << timer.elapsed());
- cout << " Checkpt(EOS_PORTABLE_BINARY) and reload and compare, time taken = ";
- cout << timer.elapsed() << " < limit(" << expectedTimeForCheckPtPersistAndReload << ")" << " file_size(" << helper.file_size() << ")" << endl;
- }
-#else
- {
- timer.restart();
- PersistHelper helper;
- BOOST_CHECK_MESSAGE( helper.test_checkpt_and_reload(defs,true,ecf::Archive::TEXT), helper.errorMsg());
- BOOST_CHECK_MESSAGE(timer.elapsed() < expectedTimeForCheckPtPersistAndReload,"Performance regression, expected < " << expectedTimeForCheckPtPersistAndReload << " seconds to persist and reload, but found " << timer.elapsed());
- cout << " Checkpt(TEXT_ARCHIVE) and reload and compare, time taken = ";
- cout << timer.elapsed() << " < limit(" << expectedTimeForCheckPtPersistAndReload << ")" << " file_size(" << helper.file_size() << ")" << endl;
- }
-#endif
-
- {
- // Time how long it takes for job submission. Must call begin on all suites first.
- timer.restart();
- defs.beginAll();
- int count = 10;
- JobsParam jobsParam; // default is *not* to create jobs, and *not* to spawn jobs, hence only used in testing
- Jobs jobs(&defs);
- for (int i = 0; i < count; i++) {jobs.generate(jobsParam);}
- cout << " time for " << count << " jobSubmissions:" << timer.elapsed() << "s jobs:" << jobsParam.submitted().size() << " < limit(" << expectedTimeForResolveDependencies << ")" << endl;
- BOOST_CHECK_MESSAGE(timer.elapsed() < expectedTimeForResolveDependencies,
- "jobSubmission Performance regression, expected < " << expectedTimeForResolveDependencies << " seconds for resolving dependencies but found " << timer.elapsed() );
- }
-
- {
- // Time how long it takes for post process
- timer.restart();
- string errorMsg,warningMsg;
- BOOST_CHECK(defs.check(errorMsg,warningMsg));
- cout << " time for Defs::check ( inlimit resolution) = " << timer.elapsed() << " < limit(" << checkExprAndLimits << ")" << endl;
- BOOST_CHECK_MESSAGE(timer.elapsed() < checkExprAndLimits,
- "Defs::check Performance regression, expected < " << checkExprAndLimits << " seconds for resolving dependencies but found " << timer.elapsed() );
- }
-
- {
- // Time how long it takes to delete all nodes/ references. Delete all tasks and then suites/families.
- timer.restart();
- std::vector<Task*> tasks;
- defs.getAllTasks(tasks);
- BOOST_CHECK_MESSAGE( tasks.size() > 0,"Expected > 0 tasks but found " << tasks.size());
- BOOST_FOREACH(Task* t, tasks) {
- BOOST_REQUIRE_MESSAGE(defs.deleteChild(t)," Failed to delete task");
- }
- tasks.clear(); defs.getAllTasks(tasks);
- BOOST_REQUIRE_MESSAGE( tasks.empty(),"Expected all tasks to be deleted but found " << tasks.size());
-
- std::vector<suite_ptr> vec = defs.suiteVec(); // make a copy, to avoid invalidating iterators
- BOOST_CHECK_MESSAGE( vec.size() > 0,"Expected > 0 Suites but found " << vec.size());
- BOOST_FOREACH(suite_ptr s, vec) {
- std::vector<node_ptr> familyVec = s->nodeVec(); // make a copy, to avoid invalidating iterators
- BOOST_FOREACH(node_ptr f, familyVec) {
- BOOST_REQUIRE_MESSAGE(defs.deleteChild(f.get())," Failed to delete family");
- }
- BOOST_REQUIRE_MESSAGE( s->nodeVec().empty(),"Expected all Families to be deleted but found " << s->nodeVec().size());
- BOOST_REQUIRE_MESSAGE(defs.deleteChild(s.get())," Failed to delete suite");
- }
- BOOST_REQUIRE_MESSAGE( defs.suiteVec().empty(),"Expected all Suites to be deleted but found " << defs.suiteVec().size());
-
- cout << " time for deleting all nodes = " << timer.elapsed() << endl;
- }
-
- // Explicitly destroy, To keep valgrind happy
- Log::destroy();
- System::destroy();
-
- // cout << "Printing Defs \n";
- // PrintStyle style(PrintStyle::DEFS);
- // std::cout << defs;
- cout << " Total elapsed time = " << duration_timer.duration() << " seconds\n";
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/AParser/test/TestVariableParsing.cpp b/ecflow_4_0_7/AParser/test/TestVariableParsing.cpp
deleted file mode 100644
index 316e297..0000000
--- a/ecflow_4_0_7/AParser/test/TestVariableParsing.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
- //============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <string>
-#include <iostream>
-#include <fstream>
-
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-
-#include "DefsStructureParser.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "File.hpp"
-
-namespace fs = boost::filesystem;
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( ParserTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_single_defs ) {
-
- cout << "AParser:: ...test_variable \n";
-
- std::string path = File::test_data("AParser/test/data/good_defs/edit/edit.def","AParser");
-
- Defs defs;
- DefsStructureParser checkPtParser( &defs, path );
- std::string errorMsg,warningMsg;
- BOOST_REQUIRE_MESSAGE(checkPtParser.doParse(errorMsg,warningMsg),errorMsg);
-
-// suite edit
-// edit ECF_INCLUDE /home/ma/map/sms/example/x # comment line
-// edit ECF_FILES /home/ma/map/sms/example/x #comment line
-// edit EXPVER 'f8na' #
-// edit USER 'ecgems' #comment
-// edit USER2 "ecgems" # comment
-// edit INT1 "10" # comment
-// edit INT2 '11' # comment
-// edit YMD '20091012' # comment
-// family family
-// edit ECF_FETCH "smsfetch -F %ECF_FILES% -I %ECF_INCLUDE%" # comment line
-// edit ECF_FETCH2 'smsfetch -F %ECF_FILES% -I %ECF_INCLUDE%' #comment line
-// task t2
-// endfamily
-// endsuite
- suite_ptr editSuite = defs.findSuite("edit");
- BOOST_REQUIRE_MESSAGE(editSuite,"Could not find the edit suite");
-
- const Variable& int1 = editSuite->findVariable("INT1");
- BOOST_REQUIRE_MESSAGE(!int1.empty(),"Could not find variable INT1");
- BOOST_REQUIRE_MESSAGE(int1.value() == 10,"Expected INT1 to have a value of 10, but found " << int1.value());
-
- const Variable& int2 = editSuite->findVariable("INT2");
- BOOST_REQUIRE_MESSAGE(!int2.empty(),"Could not find variable INT2");
- BOOST_REQUIRE_MESSAGE(int2.value() == 11,"Expected INT2 to have a value of 11, but found " << int2.value());
-
- const Variable& ymd = editSuite->findVariable("YMD");
- BOOST_REQUIRE_MESSAGE(!ymd.empty(),"Could not find variable YMD");
- BOOST_REQUIRE_MESSAGE(ymd.value() == 20091012,"Expected YMD to have a value of 20091012, but found " << ymd.value());
-
- const Variable& user = editSuite->findVariable("USER");
- BOOST_REQUIRE_MESSAGE(!user.empty(),"Could not find variable USER");
- BOOST_REQUIRE_MESSAGE(user.value() == 0,"Expected user to have a value of 0, but found " << user.value());
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/repeat/date_missing_name.def b/ecflow_4_0_7/AParser/test/data/bad_defs/repeat/date_missing_name.def
deleted file mode 100644
index c9c8a81..0000000
--- a/ecflow_4_0_7/AParser/test/data/bad_defs/repeat/date_missing_name.def
+++ /dev/null
@@ -1,3 +0,0 @@
-suite suiteName
- repeat date 20090331 20121212 1
-endsuite
\ No newline at end of file
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/repeat/duplicate_repeats_per_node.def b/ecflow_4_0_7/AParser/test/data/bad_defs/repeat/duplicate_repeats_per_node.def
deleted file mode 100644
index 5228092..0000000
--- a/ecflow_4_0_7/AParser/test/data/bad_defs/repeat/duplicate_repeats_per_node.def
+++ /dev/null
@@ -1,4 +0,0 @@
-suite suiteName
- repeat date YMD 20090331 20121212 1 # status 0
- repeat date YMD1 20090331 20121212 1 # status 0
-endsuite
\ No newline at end of file
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/repeat/invalid_dates.def b/ecflow_4_0_7/AParser/test/data/bad_defs/repeat/invalid_dates.def
deleted file mode 100644
index 74a426f..0000000
--- a/ecflow_4_0_7/AParser/test/data/bad_defs/repeat/invalid_dates.def
+++ /dev/null
@@ -1,5 +0,0 @@
-suite suiteName
-
- repeat date YMD 20091901 20091501 # should have format yyyymmdd 19 and 15 ar not valid months
-
-endsuite
\ No newline at end of file
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/repeat/invalid_dates_2.def b/ecflow_4_0_7/AParser/test/data/bad_defs/repeat/invalid_dates_2.def
deleted file mode 100644
index fa09982..0000000
--- a/ecflow_4_0_7/AParser/test/data/bad_defs/repeat/invalid_dates_2.def
+++ /dev/null
@@ -1,5 +0,0 @@
-suite suiteName
-
- repeat date YMD 20091099 20091501 # should have format yyyymmdd invalid day of month
-
-endsuite
\ No newline at end of file
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/repeat/repeat_integer.def b/ecflow_4_0_7/AParser/test/data/bad_defs/repeat/repeat_integer.def
deleted file mode 100644
index 89724b6..0000000
--- a/ecflow_4_0_7/AParser/test/data/bad_defs/repeat/repeat_integer.def
+++ /dev/null
@@ -1,7 +0,0 @@
-suite suiteName
-
- repeat integer VARIABLE 0 10 2 # comment
- repeat integer VARIABLE 0 10 # duplicate variable name
- repeat integer VARIABLE 0 10 # duplicate variable name
-
-endsuite
\ No newline at end of file
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/repeat/repeat_month.def b/ecflow_4_0_7/AParser/test/data/bad_defs/repeat/repeat_month.def
deleted file mode 100644
index d1f0670..0000000
--- a/ecflow_4_0_7/AParser/test/data/bad_defs/repeat/repeat_month.def
+++ /dev/null
@@ -1,4 +0,0 @@
-suite suiteName
- repeat month 2 #111
-endsuite
-
\ No newline at end of file
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/repeat/repeat_with_cron.def b/ecflow_4_0_7/AParser/test/data/bad_defs/repeat/repeat_with_cron.def
deleted file mode 100644
index c03a13a..0000000
--- a/ecflow_4_0_7/AParser/test/data/bad_defs/repeat/repeat_with_cron.def
+++ /dev/null
@@ -1,5 +0,0 @@
-suite suiteName
- repeat date YMD 20090331 20121212 1 # status 0
- cron 10:00 23:00 00:10 # cant have repeat & cron time series at same level
-endsuite
-
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/repeat/repeat_year.def b/ecflow_4_0_7/AParser/test/data/bad_defs/repeat/repeat_year.def
deleted file mode 100644
index f803915..0000000
--- a/ecflow_4_0_7/AParser/test/data/bad_defs/repeat/repeat_year.def
+++ /dev/null
@@ -1,4 +0,0 @@
-suite suiteName
-
- repeat year 3 20090331 20121212 1 # status 0
-endsuite
\ No newline at end of file
diff --git a/ecflow_4_0_7/AParser/test/data/bad_defs/repeat/string_missing_name.def b/ecflow_4_0_7/AParser/test/data/bad_defs/repeat/string_missing_name.def
deleted file mode 100644
index 743f645..0000000
--- a/ecflow_4_0_7/AParser/test/data/bad_defs/repeat/string_missing_name.def
+++ /dev/null
@@ -1,4 +0,0 @@
-suite suiteName
-
- repeat string
-endsuite
\ No newline at end of file
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs/repeat/repeat_date.def b/ecflow_4_0_7/AParser/test/data/good_defs/repeat/repeat_date.def
deleted file mode 100644
index 94be19e..0000000
--- a/ecflow_4_0_7/AParser/test/data/good_defs/repeat/repeat_date.def
+++ /dev/null
@@ -1,6 +0,0 @@
-suite suiteName
- repeat date YMD 20090331 20121212 1 # status 0
-endsuite
-
-suite s1; repeat date YMD 20090331 20121212 1 # status 0
-endsuite
\ No newline at end of file
diff --git a/ecflow_4_0_7/AParser/test/data/good_defs_state/defs/defs_state.def b/ecflow_4_0_7/AParser/test/data/good_defs_state/defs/defs_state.def
deleted file mode 100644
index 767c651..0000000
--- a/ecflow_4_0_7/AParser/test/data/good_defs_state/defs/defs_state.def
+++ /dev/null
@@ -1,4 +0,0 @@
-# 2.0.31
-defs_state STATE state:unknown flag: state_change:17 modify_change:0 server_state:SHUTDOWN
- edit ECF_MICRO '%'
- edit ECF_HOME '/var/tmp/ma0/clientRoot/workspace/MyProject'
diff --git a/ecflow_4_0_7/Base/CMakeLists.txt b/ecflow_4_0_7/Base/CMakeLists.txt
deleted file mode 100644
index ac22bcb..0000000
--- a/ecflow_4_0_7/Base/CMakeLists.txt
+++ /dev/null
@@ -1,108 +0,0 @@
- # =======================================================
- # to list all sources to build use:
- # cd $WK/Base
- # find src -name \*.cpp >> CMakeLists.txt
- # =======================================================
- list( APPEND srcs
- src/ZombieCtrl.cpp
- src/Stats.cpp
- src/Client.cpp
- src/ServerReply.cpp
- src/stc/DefsCmd.cpp
- src/stc/PreAllocatedReply.cpp
- src/stc/SStringVecCmd.cpp
- src/stc/StcCmd.cpp
- src/stc/SSuitesCmd.cpp
- src/stc/SClientHandleCmd.cpp
- src/stc/SStringCmd.cpp
- src/stc/ServerToClientCmd.cpp
- src/stc/SClientHandleSuitesCmd.cpp
- src/stc/SServerLoadCmd.cpp
- src/stc/SNodeCmd.cpp
- src/stc/SStatsCmd.cpp
- src/stc/SSyncCmd.cpp
- src/stc/SNewsCmd.cpp
- src/stc/ErrorCmd.cpp
- src/stc/GroupSTCCmd.cpp
- src/stc/ZombieGetCmd.cpp
- src/ClientToServerRequest.cpp
- src/Gnuplot.cpp
- src/WhyCmd.cpp
- src/ServerToClientResponse.cpp
- src/cts/CSyncCmd.cpp
- src/cts/ZombieCmd.cpp
- src/cts/OrderNodeCmd.cpp
- src/cts/CheckPtCmd.cpp
- src/cts/CtsNodeCmd.cpp
- src/cts/GroupCTSCmd.cpp
- src/cts/UserCmd.cpp
- src/cts/ClientHandleCmd.cpp
- src/cts/PlugCmd.cpp
- src/cts/ForceCmd.cpp
- src/cts/LoadDefsCmd.cpp
- src/cts/CFileCmd.cpp
- src/cts/ShowCmd.cpp
- src/cts/CtsCmd.cpp
- src/cts/TaskApi.cpp
- src/cts/EditScriptCmd.cpp
- src/cts/FreeDepCmd.cpp
- src/cts/PathsCmd.cpp
- src/cts/EditHistoryMgr.cpp
- src/cts/LogMessageCmd.cpp
- src/cts/CtsApi.cpp
- src/cts/ReplaceNodeCmd.cpp
- src/cts/RequeueNodeCmd.cpp
- src/cts/BeginCmd.cpp
- src/cts/LogCmd.cpp
- src/cts/AlterCmd.cpp
- src/cts/TaskCmds.cpp
- src/cts/CtsCmdRegistry.cpp
- src/cts/RunNodeCmd.cpp
- src/cts/ClientToServerCmd.cpp
- src/cts/ServerVersionCmd.cpp
-)
-
-ecbuild_add_library( TARGET base
- NOINSTALL
- TYPE STATIC
- SOURCES ${srcs}
- LIBS libparser node nodeattr core
- INCLUDES src
- ../ACore/src
- ../ANattr/src
- ../ANode/src
- ../AParser/src
- ../Base/src
- ../Base/src/cts
- ../Base/src/stc
- )
-
-# This ensures that for debug config, we only link with debug boost libs, for other configs, we link with optimised boost libs
-target_link_libraries(base debug ${Boost_PROGRAM_OPTIONS_LIBRARY_DEBUG} ${Boost_PROGRAM_OPTIONS_LIBRARY_RELEASE})
-
-list( APPEND test_srcs
- test/TestAlterCmd.cpp
- test/TestClientHandleCmd.cpp
- test/TestCmd.cpp
- test/TestDeleteNodeCmd.cpp
- test/TestECFLOW-189.cpp
- test/TestForceCmd.cpp
- test/TestFreeDepCmd.cpp
- test/TestLimit.cpp
- test/TestMeterCmd.cpp
- test/TestRequest.cpp
- test/TestRequeueNodeCmd.cpp
- test/TestResolveDependencies.cpp
- test/TestSSyncCmd_CH1.cpp
- test/TestSSyncCmd.cpp
- test/TestSSyncCmdOrder.cpp
-)
-ecbuild_add_test( TARGET u_base
- BOOST
- SOURCES ${test_srcs}
- LIBS base
- pthread
- INCLUDES ../ANode/test
- TEST_DEPENDS u_aparser
- )
-
\ No newline at end of file
diff --git a/ecflow_4_0_7/Base/Jamfile.jam b/ecflow_4_0_7/Base/Jamfile.jam
deleted file mode 100644
index c81830f..0000000
--- a/ecflow_4_0_7/Base/Jamfile.jam
+++ /dev/null
@@ -1,70 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-#
-# Base project
-#
-project theBase ;
-
-
-use-project theCore : ../ACore ;
-use-project theNodeAttr : ../ANattr ;
-use-project theNode : ../ANode ;
-use-project theParser : ../AParser ;
-
-# The <include> means we will automatically add this directory to the include path
-# of any other target that uses this lib
-#
-lib base : [ glob src/*.cpp ] [ glob src/cts/*.cpp ] [ glob src/stc/*.cpp ]
- : <include>../ACore/src
- <include>../ANattr/src
- <include>../AParser/src
- <include>../ANode/src
- <include>../Base/src
- <include>../Base/src/cts
- <include>../Base/src/stc
- <link>static
- <variant>debug:<define>DEBUG
- <use>/theCore//core
- <use>/theNodeAttr//nodeattr
- <use>/theParser//libparser
- <use>/theNode//node
- <use>/site-config//boost_system
- <use>/site-config//boost_serialization
- <use>/site-config//boost_filesystem
- <use>/site-config//boost_datetime
- <use>/site-config//boost_program_options
- <use>/site-config//boost_test
- :
- : <include>../Base/src
- <include>../Base/src/cts
- <include>../Base/src/stc
- ;
-
-#
-# This should be in the site-config.jam file as a project wide requirement
-# however if this is done, it will not link since, lpthread appears twice
-# on the link line
-#
-lib pthread ;
-
-exe u_base : [ glob test/*.cpp ]
- /theCore//core
- /theNodeAttr//nodeattr
- /theNode//node
- /theParser//libparser
- base
- /site-config//boost_system
- /site-config//boost_serialization
- /site-config//boost_filesystem
- /site-config//boost_datetime
- /site-config//boost_program_options
- /site-config//boost_test
- pthread
- : <include>../ANode/test
- <variant>debug:<define>DEBUG
- ;
diff --git a/ecflow_4_0_7/Base/src/AbstractClientEnv.hpp b/ecflow_4_0_7/Base/src/AbstractClientEnv.hpp
deleted file mode 100644
index 6af6499..0000000
--- a/ecflow_4_0_7/Base/src/AbstractClientEnv.hpp
+++ /dev/null
@@ -1,66 +0,0 @@
-#ifndef ABSTRACT_CLIENT_ENV__HPP_
-#define ABSTRACT_CLIENT_ENV__HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #14 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : This class is used to represent the client environment to the cmds
-//
-// This abstraction ONLY covers aspects that are required, to _CREATE_
-// the client command/request that is to be sent to the server
-// The key theme is that we can define a new client to server command
-// in one place. i.e it allows the functionality, command line arguments,
-// parsing of the arguments, can all be done in the command class itself
-// If the command requires any additional arguments from the client environment
-// they should be added to this class, and the implementation in the derived class
-//============================================================================
-
-#include <boost/noncopyable.hpp>
-#include <string>
-#include <vector>
-
-class AbstractClientEnv : private boost::noncopyable {
-protected:
- AbstractClientEnv() {}
-public:
- virtual ~AbstractClientEnv() {}
-
- /// For all tasks/child based commands we require taskPath and password and optional Remote ID
- /// When the jobs use a queueing system the remote id (ECF_RID) is used to
- /// aid killing of jobs.(typically zombies)
- virtual bool checkTaskPathAndPassword(std::string& errorMsg) const = 0;
- virtual const std::string& task_path() const = 0;
- virtual int task_try_no() const = 0;
- virtual const std::string& jobs_password() const = 0;
- virtual const std::string& process_or_remote_id() const = 0;
-
- /// For test allow env variable to be set on defs, i.e. allow us to inject ECF_CLIENT to defs
- virtual const std::vector<std::pair<std::string,std::string> >& env() const = 0;
-
- /// Allow ping to set the host:port
- virtual void set_host_port(const std::string& host, const std::string& port) = 0;
-
- /// return the current host
- virtual const std::string& host() const = 0;
-
- /// returns the port number
- virtual const std::string& port() const = 0;
-
- /// debug client, when environment variable ECF_CLIENT_DEBUG is set.
- virtual bool debug() const = 0 ;
-
- /// Some commands work on construction. to avoid this under test. Call set_test
- /// i.e Command like CtsCmd::SERVER_LOAD can be client side only, in which case
- /// when testing the client interface we want to avoid opening the log file.
- virtual void set_test() = 0;
- virtual bool under_test() const = 0;
-};
-#endif
diff --git a/ecflow_4_0_7/Base/src/AbstractServer.hpp b/ecflow_4_0_7/Base/src/AbstractServer.hpp
deleted file mode 100644
index 51b9bba..0000000
--- a/ecflow_4_0_7/Base/src/AbstractServer.hpp
+++ /dev/null
@@ -1,193 +0,0 @@
-#ifndef ABSTRACTSERVER_HPP_
-#define ABSTRACTSERVER_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #45 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-#include <boost/shared_ptr.hpp>
-
-#include "Stats.hpp"
-#include "ZombieCtrl.hpp"
-#include "SState.hpp"
-#include "CheckPt.hpp"
-
-class Defs;
-
-/// This class is provided so that the cmd can issue requests to the server
-/// without depending on the server implementation
-///
-class AbstractServer {
-public:
- virtual ~AbstractServer() {}
-
- /// returns the current state of the server
- /// The following table shows the effect of state, on server behaviour:
- ///
- /// User Request Task Request Job Scheduling Check-pointing
- /// RUNNING yes yes yes yes
- /// SHUTDOWN yes yes no yes
- /// HALTED yes no no no
- virtual SState::State state() const = 0;
-
- /// returns the server host and port number
- virtual std::pair<std::string,std::string> hostPort() const = 0;
-
- /// returns the defs held by the server. This should always exist. ECFLOW-182
- virtual defs_ptr defs() const = 0;
-
- /// Update the defs help by the server. This allows multiple suites to loaded
- /// into the server. Note the input defs will be drained of its suites/externs as they
- /// will get transferred to the server. If the server already has suites of the same
- /// name, then an error message is created. This can be overridden with the force option
- virtual void updateDefs(defs_ptr, bool force) = 0;
-
- /// Remove all suites,externs,client handles, ready for a new start
- virtual void clear_defs() = 0;
-
- /// Forces the defs file in the server to be written to disk *IF* no args provided.
- /// Otherwise updated mode OR check_pt interval OR check pt alarm
- virtual void checkPtDefs(ecf::CheckPt::Mode m = ecf::CheckPt::UNDEFINED,
- int check_pt_interval = 0,
- int check_pt_save_time_alarm = 0) = 0;
-
- /// Ask the server to restore the defs from the checkpt file. If that fails the back check pt is tried
- virtual void restore_defs_from_checkpt() = 0;
-
- /// This function should be called, when the node tree changes state
- virtual void nodeTreeStateChanged() = 0;
-
- /// returns true if the server allows task communication
- /// Task-->server communication is stopped by halted()
- virtual bool allowTaskCommunication() const = 0;
-
- /// Stops job scheduling. Check point is enabled. (i,e if we were previously halted)
- /// However any client request can still communicate with the server
- /// Does NOT affect check pointing. Since any request can make changes to node tree
- /// Places server in SHUTDOWN state.
- /// User Request Task Request Job Scheduling Check-pointing
- /// RUNNING yes yes yes yes
- /// SHUTDOWN yes yes no yes
- /// HALTED yes no no no
- virtual void shutdown() = 0;
-
- /// Stop job scheduling *AND* task communication with server. Failed task request are logged
- /// Hence nodes can be stuck in submitted/active states.
- /// Task based command will continue attempting, communication with the server for up to 24hrs.
- ///
- /// When the server is halted, we do *NOT* do any further check pointing
- /// In a typical operational scenario where we have a home, and backup servers.
- /// The checkpoint file is copied to the backup servers periodically (via a task)
- /// hence we want to preserve the state of the last checkpoint. By prevent any state
- /// changes to the node tree.
- ///
- /// Hence halted(), will completely stop the server. Server will only respond
- /// to user requests. (tasks requests are blocked)
- /// Places server in HALTED state.
- /// User Request Task Request Job Scheduling Check-pointing
- /// RUNNING yes yes yes yes
- /// SHUTDOWN yes yes no yes
- /// HALTED yes no no no
- virtual void halted() = 0;
-
- /// Start scheduling tasks and respond to all requests. Check pointing is enabled
- /// Places server in RUNNING state.
- /// User Request Task Request Job Scheduling Check-pointing
- /// RUNNING yes yes yes yes
- /// SHUTDOWN yes yes no yes
- /// HALTED yes no no no
- virtual void restart() = 0;
-
- /// Ask the server to reload file the hold list of users and their access rights
- /// The white list file is specified by the environment variable ECF_LISTS
- /// This allows/disallows user access on the live server
- /// Return true if file is reloaded ok, else false and error message if:
- /// a/ File does not exist
- /// b/ File is empty
- /// c/ Errors in parsing file
- /// If errors arise the exist user still stay in affect
- virtual bool reloadWhiteListFile(std::string& errorMsg) = 0;
-
- /// There are several kinds of authentifications:
- /// a/ None
- /// b/ List mode. ASCII file based on ECF_LISTS is defined. referred as white list file
- /// c/ Secure mode. binary file based ECF_PASSWD is defined. Referred to as black list file
- /// At the moment we will only implement options a/ and b/
- //
- /// Returns true if the given user has access to the server, false otherwise
- virtual bool authenticateUser(const std::string& user) = 0;
-
- /// Returns true if user has matching write access privileges.
- virtual bool authenticateWriteAccess(const std::string& user, bool client_request_can_change_server_state) = 0;
-
- /// Shutdown the server and let 'user' has have exclusive lock on it.
- /// If the lock succeeds return true, (This will end up calling the shutdown()
- /// command on the server). If already locked does nothing and return's false
- virtual bool lock(const std::string& user) = 0;
-
- /// Unlock's the server., and restarts job scheduling
- virtual void unlock() = 0;
-
- /// Return the user that has exclusive lock, else an empty string
- virtual const std::string& lockedUser() const = 0;
-
- /// Return Controller for zombies
- ZombieCtrl& zombie_ctrl() { return zombie_ctrl_; }
-
- /// returns the statistical class
- Stats& stats() { return stats_;}
-
- /// Call to update the number of request, & returns stats
- Stats& update_stats() { stats_.update(); return stats_; }
-
- /// Update for number of requests per second
- void update_stats(int poll_interval) { stats_.update_stats(poll_interval); }
-
- // Instead of immediate node tree traversal at the end of child command
- // we use 'increment_job_generation_count' to defer job generation to server
- // The server will will check job generation count at poll time.
- // This approach radically reduces the number of times we traverse the node tree
- // and hence improves server throughput.
- void increment_job_generation_count() { job_gen_count_++;}
- void reset_job_generation_count() { job_gen_count_ = 0; }
- int get_job_generation_count() const { return job_gen_count_; }
-
- /// This job generation is special, in that it will time out, job generation time >= next poll.
- /// This can be called at the end of a *USER* command(force,alter,requeue,etc), hence time_now may be >= next_poll_time
- /// If this is the case, we will defer job generation
- virtual void traverse_node_tree_and_job_generate(const boost::posix_time::ptime& time_now,bool user_cmd_context) const = 0;
-
- /// returns the number of seconds at which we should check time dependencies
- /// this includes evaluating trigger dependencies and submit the corresponding jobs.
- /// This is set at 60 seconds. But will vary for debug/test purposes only.
- /// For Testing the state change queued->submitted->active duration < submitJobsInterval
- /// If this state change happens at the job submission boundary then
- /// time series can get a skew.
- virtual int poll_interval() const = 0;
-
- /// enable and disable debug output from the server
- virtual void debug_server_on() = 0;
- virtual void debug_server_off() = 0;
- virtual bool debug() const = 0;
-
-protected:
- AbstractServer() : job_gen_count_(0) {}
-
-private:
- int job_gen_count_;
- ZombieCtrl zombie_ctrl_;
- Stats stats_;
-};
-
-#endif
diff --git a/ecflow_4_0_7/Base/src/Client.cpp b/ecflow_4_0_7/Base/src/Client.cpp
deleted file mode 100644
index f8b7db0..0000000
--- a/ecflow_4_0_7/Base/src/Client.cpp
+++ /dev/null
@@ -1,342 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name : Client
-// Author : Avi
-// Revision : $Revision: #33 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <fstream>
-#include <iostream>
-#include <sstream>
-#include <assert.h>
-
-#include <boost/bind.hpp>
-
-#include "Client.hpp"
-#include "StcCmd.hpp"
-
-//#define DEBUG_CLIENT 1;
-
-#ifdef DEBUG_CLIENT
-#include <boost/date_time/posix_time/time_formatters.hpp> // requires boost date and time lib, for to_simple_string
-#endif
-
-/// The timeout will typically happen when the server has died, but socket is still open
-/// If we do not have a timeout, it will hang indefinitely
-
-/// Constructor starts the asynchronous connect operation.
-Client::Client( boost::asio::io_service& io_service,
- Cmd_ptr cmd_ptr,
- const std::string& host,
- const std::string& port,
- int timeout
- )
-: stopped_(false),host_( host ), port_( port ), connection_( io_service ),deadline_(io_service),timeout_(timeout)
-{
- /// Avoid sending a NULL request to the server
- if (!cmd_ptr.get()) throw std::runtime_error("Client::Client: No request specified !");
-
- // The timeout can be set externally for testing, however when its not set the timeout is obtained from the command
- // Vary the timeout, according to the command, hence loading the definition has longer timeout than ping
- if (0 == timeout_) {
- timeout_ = cmd_ptr->timeout();
- }
-
-#ifdef DEBUG_CLIENT
- std::cout << " Client::Client() timeout(" << timeout_ << ") " << host_ << ":" << port_ << " "; cmd_ptr->print(std::cout); std::cout << std::endl;
-#endif
-
- outbound_request_.set_cmd( cmd_ptr );
-
- // Host name resolution is performed using a resolver, where host and service
- // names(or ports) are looked up and converted into one or more end points
- boost::asio::ip::tcp::resolver resolver( io_service );
- boost::asio::ip::tcp::resolver::query query( host_, port_ );
- boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve( query );
-
- // The list of end points obtained could contain both IPv4 and IPv6 end points,
- // so a program may try each of them until it finds one that works.
- // This keeps the Client program independent of a specific IP version.
- start(endpoint_iterator);
-}
-
-Client::~Client() {
-#ifdef DEBUG_CLIENT
- std::cout << " Client::~Client(): connection_.socket().is_open()=" << connection_.socket().is_open() << std::endl;
-#endif
-}
-
-/// Private ==============================================================================
-
-// This function terminates all the actors to shut down the connection. It
-// may be called by the user of the client class, or by the class itself in
-// response to graceful termination or an unrecoverable error.
-void Client::start(boost::asio::ip::tcp::resolver::iterator endpoint_iter)
-{
- // Start the connect actor.
- start_connect(endpoint_iter);
-
- // Start the deadline actor. You will note that we're not setting any
- // particular deadline here. Instead, the connect and input actors will
- // update the deadline prior to each asynchronous operation.
- deadline_.async_wait(boost::bind(&Client::check_deadline, this));
-}
-
-bool Client::start_connect(boost::asio::ip::tcp::resolver::iterator endpoint_iterator )
-{
- if ( endpoint_iterator != boost::asio::ip::tcp::resolver::iterator() )
- {
-#ifdef DEBUG_CLIENT
- std::cout << " Client::start_connect: Trying " << endpoint_iterator->endpoint() << "..." << std::endl;
-#endif
-
- // expires_from_now cancels any pending asynchronous waits, and returns the number of asynchronous waits that were cancelled.
- // If it returns 0 then you were too late and the wait handler has already been executed, or will soon be executed.
- // If it returns 1 then the wait handler was successfully cancelled.
-
- // Set a deadline for the connect operation.
- deadline_.expires_from_now(boost::posix_time::seconds(timeout_));
-
- boost::asio::ip::tcp::endpoint endpoint = *endpoint_iterator;
- connection_.socket().async_connect(
- endpoint,
- boost::bind(
- &Client::handle_connect,
- this,
- boost::asio::placeholders::error,
- endpoint_iterator ) );
- }
- else {
- // ran out of end points
- return false;
- }
- return true;
-}
-
-void Client::handle_connect( const boost::system::error_code& e,
- boost::asio::ip::tcp::resolver::iterator endpoint_iterator )
-{
-#ifdef DEBUG_CLIENT
- std::cout << " Client::handle_connect stopped_=" << stopped_ << std::endl;
-#endif
-
- if (stopped_)
- return;
-
- // The async_connect() function automatically opens the socket at the start
- // of the asynchronous operation. If the socket is closed at this time then
- // the timeout handler must have run first.
- if (!connection_.socket().is_open())
- {
-#ifdef DEBUG_CLIENT
- std::cout << " Client::handle_connect: *Connect timeout*: Trying next end point" << std::endl;
-#endif
- // Try the next available end point.
- if (!start_connect( ++endpoint_iterator)) {
- // Ran out of end points, An error occurred
- stop();
- std::stringstream ss;
- if (e) ss << "Client::handle_connect: Ran out of end points : connection error( " << e.message() << " ) for request( " << outbound_request_ << " ) on " << host_ << ":" << port_;
- else ss << "Client::handle_connect: Ran out of end points : connection error for request( " << outbound_request_ << " ) on " << host_ << ":" << port_;
- throw std::runtime_error(ss.str());
- }
- }
- else if (e) {
-
-#ifdef DEBUG_CLIENT
- std::cout << " Client::handle_connect Connect error: " << e.message() << " . Trying next end point" << std::endl;
-#endif
-
- // Some kind of error. We need to close the socket used in the previous connection attempt
- // before starting a new one.
- connection_.socket().close();
-
- // Try the next end point.
- if (!start_connect( ++endpoint_iterator)) {
- // Ran out of end points. An error occurred.
- stop();
- std::stringstream ss; ss << "Client::handle_connect: Ran out of end points: connection error( " << e.message() << " ) for request( " << outbound_request_ << " ) on " << host_ << ":" << port_;
- throw std::runtime_error(ss.str());
- }
- }
- else {
-#ifdef DEBUG_CLIENT
- std::cout << " Client::handle_connect **Successfully** established connection to the server: Sending Out bound request = " << outbound_request_ << std::endl;
-#endif
- // **Successfully** established connection to the server
- // Start operation to *SEND* a request to the server
- start_write();
- }
-}
-
-void Client::start_write()
-{
- // expires_from_now cancels any pending asynchronous waits, and returns the number of asynchronous waits that were cancelled.
- // If it returns 0 then you were too late and the wait handler has already been executed, or will soon be executed.
- // If it returns 1 then the wait handler was successfully cancelled.
-
- // Set a deadline for the write operation.
- deadline_.expires_from_now(boost::posix_time::seconds(timeout_));
-
- connection_.async_write(
- outbound_request_,
- boost::bind(
- &Client::handle_write,
- this,
- boost::asio::placeholders::error ) );
-}
-
-void Client::handle_write( const boost::system::error_code& e )
-{
-#ifdef DEBUG_CLIENT
- std::cout << " Client::handle_write stopped_ = " << stopped_ << std::endl;
-#endif
- if (stopped_)
- return;
-
- if ( !e ) {
-
-#ifdef DEBUG_CLIENT
- std::cout << " Client::handle_write OK: Check for server reply" << std::endl;
-#endif
- // Check to see if the server was happy with our request.
- // If all is OK, the server may choose not to reply(cuts down on network traffic)
- // In which case handle_read will get a End of File error.
- start_read();
- }
- else {
-
- // An error occurred.
- stop();
-
- std::stringstream ss; ss << "Client::handle_write: error (" << e.message() << " ) for request( " << outbound_request_ << " ) on " << host_ << ":" << port_;
- throw std::runtime_error(ss.str());
- }
-
- // Nothing to do. The socket will be closed automatically when the last
- // reference to the connection object goes away.
-}
-
-void Client::start_read()
-{
- // expires_from_now cancels any pending asynchronous waits, and returns the number of asynchronous waits that were cancelled.
- // If it returns 0 then you were too late and the wait handler has already been executed, or will soon be executed.
- // If it returns 1 then the wait handler was successfully cancelled.
-
- // Set a deadline for the read operation.
- deadline_.expires_from_now(boost::posix_time::seconds(timeout_));
-
- connection_.async_read(
- inbound_response_,
- boost::bind(
- &Client::handle_read,
- this,
- boost::asio::placeholders::error ) );
-}
-
-
-void Client::handle_read( const boost::system::error_code& e )
-{
-#ifdef DEBUG_CLIENT
- std::cout << " Client::handle_read stopped_ = " << stopped_ << std::endl;
-#endif
- if (stopped_)
- return;
-
- // close socket, & cancel timer.
- stop();
-
- if ( !e ) {
-#ifdef DEBUG_CLIENT
- std::cout << " Client::handle_read OK \n";
- std::cout << " outbound_request_ = " << outbound_request_ << "\n";
- std::cout << " inbound_response_ = " << inbound_response_ << "\n";
-#endif
- /// ***********************************************************
- /// ClientInvoker will call back, to handle_server_response.
- /// ***********************************************************
- // Successfully handled request
- }
- else {
- //
- // A connection error occurred.
- // In cases where ( to cut down network traffic), the server does a shutdown/closes
- // the socket without replying we will get End of File error.
- //
- // i.e. client requests a response from the server, and it does not reply(or replies with shutdown/close)
- //
-
- // This code will handle a no reply from the server & hence reduce network traffic
- // Server has shutdown and closed the socket.
- // See void Server::handle_read(...)
- if (e.value() == boost::asio::error::eof) {
- // Treat a *no* reply as OK, so that handle_server_response() returns OK
-#ifdef DEBUG_CLIENT
- std::cout << " Client::handle_read: No reply from server: Treat as OK" << std::endl;
-#endif
- inbound_response_.set_cmd( STC_Cmd_ptr(new StcCmd(StcCmd::OK)) );
- return;
- }
-
- std::stringstream ss;
- ss << "Client::handle_read: connection error( " << e.message() << " ) for request( " << outbound_request_ << " ) on " << host_ << ":" << port_;
- throw std::runtime_error(ss.str());
- }
-
- // Since we are not starting a new operation the io_service will run out of
- // work to do and the Client will exit.
-}
-
-void Client::stop()
-{
- stopped_ = true;
- connection_.socket().close();
- deadline_.cancel();
-}
-
-/// Handle completion of a write operation.
-/// Handle completion of a read operation.
-bool Client::handle_server_response( ServerReply& server_reply, bool debug ) const
-{
- if (debug) std::cout << " Client::handle_server_response" << std::endl;
- return inbound_response_.handle_server_response(server_reply, outbound_request_.get_cmd(), debug);
-}
-
-void Client::check_deadline()
-{
-#ifdef DEBUG_CLIENT
- std::cout << " Client::check_deadline stopped_=" << stopped_
- << " expires(" << to_simple_string(deadline_.expires_at())
- << ") time now(" << to_simple_string(boost::asio::deadline_timer::traits_type::now()) << ")" << std::endl;
-#endif
- if (stopped_)
- return;
-
- // Check whether the deadline has passed. We compare the deadline against
- // the current time since a new asynchronous operation may have moved the
- // deadline before this actor had a chance to run.
- if (deadline_.expires_at() <= boost::asio::deadline_timer::traits_type::now())
- {
-#ifdef DEBUG_CLIENT
- std::cout << " Client::check_deadline timed out" << std::endl;
-#endif
-
- // The deadline has passed. The socket is closed so that any outstanding
- // asynchronous operations are cancelled.
- stop();
-
- std::stringstream ss;
- ss << "Client::check_deadline: timed out after " << timeout_ << " seconds for request( " << outbound_request_ << " ) on " << host_ << ":" << port_;
- throw std::runtime_error(ss.str());
- }
-
- // Put the actor back to sleep.
- deadline_.async_wait(boost::bind(&Client::check_deadline, this));
-}
diff --git a/ecflow_4_0_7/Base/src/Client.hpp b/ecflow_4_0_7/Base/src/Client.hpp
deleted file mode 100644
index 80b97a2..0000000
--- a/ecflow_4_0_7/Base/src/Client.hpp
+++ /dev/null
@@ -1,83 +0,0 @@
-#ifndef CLIENT_HPP_
-#define CLIENT_HPP_
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name : Client
-// Author : Avi
-// Revision : $Revision: #18 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-// Client : Acts as the client part. ( in client/server architecture)
-// Note: The plug command can move a node to another server
-// hence the server itself will NEED to ACT as a client.
-// This is why client lives in Base and not the Client project
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/asio.hpp>
-
-#include "Connection.hpp" // Must come before boost/serialization headers.
-#include "ClientToServerRequest.hpp"
-#include "ServerToClientResponse.hpp"
-
-class Client {
-public:
- /// Constructor starts the asynchronous connect operation.
- Client( boost::asio::io_service& io_service, Cmd_ptr cmd_ptr, const std::string& host, const std::string& port , int timout = 0);
- ~Client();
-
- /// Client side, get the server response, handles reply from server
- /// Returns true if all is ok, else false if further client action is required
- /// will throw std::runtime_error for errors
- bool handle_server_response( ServerReply&, bool debug ) const;
-
-
- // support for forward compatibility, by changing boost archive version
- // By default 0 means, and need to be explicitly enabled. The integer must correspond with
- // the archive version of the old server. for boost 1.47 this was 9
- // Chosen to change client side only
- void allow_new_client_old_server(int f) { connection_.allow_new_client_old_server(f);}
-
-private:
-
- void start(boost::asio::ip::tcp::resolver::iterator);
- void stop();
- void check_deadline();
-
- bool start_connect(boost::asio::ip::tcp::resolver::iterator);
- void start_write();
- void start_read();
-
- /// Handle completion of a connect operation.
- void handle_connect( const boost::system::error_code& e,
- boost::asio::ip::tcp::resolver::iterator endpoint_iterator );
-
- /// Handle completion of a read operation.
- void handle_read( const boost::system::error_code& e );
-
- /// Handle completion of a write operation
- void handle_write( const boost::system::error_code& e );
-
-private:
- bool stopped_;
- std::string host_; /// the servers name
- std::string port_; /// the port on the server
- connection connection_; /// The connection to the server.
- ClientToServerRequest outbound_request_; /// The request we will send to the server
- ServerToClientResponse inbound_response_; /// The response we get back from the server
-
- std::string error_msg_;
- boost::asio::deadline_timer deadline_;
-
- // connect : timeout_ second
- // send request : timeout_ second
- // receive reply : timeout_ second
- // Default value of 0 means take the timeout from the command
- int timeout_;
-};
-#endif
diff --git a/ecflow_4_0_7/Base/src/ClientToServerRequest.cpp b/ecflow_4_0_7/Base/src/ClientToServerRequest.cpp
deleted file mode 100644
index 48c516d..0000000
--- a/ecflow_4_0_7/Base/src/ClientToServerRequest.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-//============================================================================
-// Name : Request
-// Author : Avi
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <assert.h>
-#include <fstream>
-
-#include "ClientToServerRequest.hpp"
-#include "AbstractServer.hpp"
-
-using namespace std;
-
-STC_Cmd_ptr ClientToServerRequest::handleRequest(AbstractServer* as) const
-{
- if (cmd_.get()) {
- return cmd_->handleRequest(as);
- }
-
- /// means programming error somewhere
- std::stringstream ss;
- ss << "ClientToServerRequest::handleRequest: Can not send a NULL request to the server !";
- throw std::runtime_error(ss.str());
-}
-
-std::ostream& ClientToServerRequest::print( std::ostream& os ) const {
- if (cmd_.get()) {
- return cmd_->print(os);
- }
- return os << "NULL request";
-}
-
-bool ClientToServerRequest::operator==(const ClientToServerRequest& rhs) const
-{
- if (!cmd_.get() && !rhs.cmd_.get()) {
- return true;
- }
- if (cmd_.get() && !rhs.cmd_.get()) {
- return false;
- }
- if (!cmd_.get() && rhs.cmd_.get()) {
- return false;
- }
- return (cmd_->equals(rhs.cmd_.get()));
-}
-
-std::ostream& operator<<( std::ostream& os, const ClientToServerRequest& d ) {
- return d.print( os );
-}
diff --git a/ecflow_4_0_7/Base/src/ClientToServerRequest.hpp b/ecflow_4_0_7/Base/src/ClientToServerRequest.hpp
deleted file mode 100644
index f56f5f0..0000000
--- a/ecflow_4_0_7/Base/src/ClientToServerRequest.hpp
+++ /dev/null
@@ -1,67 +0,0 @@
-#ifndef CLIENT_TO_SERVER_REQUEST_HPP_
-#define CLIENT_TO_SERVER_REQUEST_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #32 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <boost/noncopyable.hpp>
-#include <boost/serialization/tracking.hpp>
-#include "ClientToServerCmd.hpp"
-
-// Base class for client to server requesting.
-// This class is used in the IPC messaging from client to server.
-class ClientToServerRequest : private boost::noncopyable {
-public:
-
- ClientToServerRequest() {}
- ClientToServerRequest(const Cmd_ptr& cmd) : cmd_(cmd) { cmd_->setup_user_authentification();}
- ~ClientToServerRequest() {}
-
- void set_cmd(const Cmd_ptr& cmd) { cmd_ = cmd; cmd_->setup_user_authentification(); }
- Cmd_ptr get_cmd() const { return cmd_;}
-
- /// This is called in the server only, to handle the quest.
- STC_Cmd_ptr handleRequest(AbstractServer*) const;
-
- std::ostream& print(std::ostream& os) const;
-
- bool getRequest() const { return (cmd_.get()) ? cmd_->get_cmd() : false; }
- bool terminateRequest() const { return (cmd_.get()) ? cmd_->terminate_cmd() : false; }
- bool groupRequest() const { return (cmd_.get()) ? cmd_->group_cmd() : false; }
-
- /// Used by boost test, to verify persistence
- bool operator==(const ClientToServerRequest& rhs) const;
-
-private:
- Cmd_ptr cmd_;
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/) {
- ar & cmd_;
- }
-};
-
-std::ostream& operator<<(std::ostream& os, const ClientToServerRequest& d);
-
-// Do NOT use
-// BOOST_CLASS_IMPLEMENTATION(ClientToServerRequest, boost::serialization::object_serializable)
-// i.e eliminate serialisation overhead at the cost of never being able to increase the version.
-// Since we may need use version ing in the future
-
-// This should ONLY be added to objects that are *NOT* serialised through a pointer
-// Eliminate object tracking (even if serialised through a pointer)
-// at the risk of a programming error creating duplicate objects.
-BOOST_CLASS_TRACKING(ClientToServerRequest,boost::serialization::track_never);
-
-#endif
diff --git a/ecflow_4_0_7/Base/src/Cmd.hpp b/ecflow_4_0_7/Base/src/Cmd.hpp
deleted file mode 100644
index bd7dd17..0000000
--- a/ecflow_4_0_7/Base/src/Cmd.hpp
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef CMD_HPP_
-#define CMD_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name : Cmd
-// Author : Avi
-// Revision : $Revision: #84 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <boost/shared_ptr.hpp>
-
-class ClientToServerCmd;
-class ServerToClientCmd;
-class ServerReply;
-
-typedef boost::shared_ptr<ClientToServerCmd> Cmd_ptr;
-typedef boost::shared_ptr<ServerToClientCmd> STC_Cmd_ptr;
-
-#endif
diff --git a/ecflow_4_0_7/Base/src/Connection.hpp b/ecflow_4_0_7/Base/src/Connection.hpp
deleted file mode 100644
index ebe0c7d..0000000
--- a/ecflow_4_0_7/Base/src/Connection.hpp
+++ /dev/null
@@ -1,315 +0,0 @@
-#ifndef CONNECTION_HPP_
-#define CONNECTION_HPP_
-//============================================================================
-// Name : Connection.cpp
-// Author : Avi
-// Revision : $Revision: #26 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Serves as the connection between client server
-//============================================================================
-
-#if defined(HPUX)
-#include <sys/select.h> // hp-ux uses pselect
-#endif
-
-#include <iomanip>
-#include <string>
-#include <sstream>
-#include <vector>
-
-#include <boost/asio.hpp>
-#include <boost/bind.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/tuple/tuple.hpp>
-
-#include "Log.hpp"
-#include "Str.hpp"
-#include "Ecf.hpp"
-#include "Serialization.hpp"
-
-#ifdef DEBUG
-//#define DEBUG_CONNECTION 1
-//#define DEBUG_CONNECTION_MEMORY 1
-#endif
-
-/// The connection class provides serialisation primitives on top of a socket.
-/// ISSUES
-/// ======
-/// When the test are run with different configuration
-/// TEXT,BINARY, PORTABLE_BINARY there was _no_ discernible difference in the
-/// run times? I would have expected client->server communication via binary
-/// to be faster. However the definition file we are using are relatively small!
-///
-/// See: ACore/src/boost_archive.hpp for details about serialisation migration issues
-///
-/**
- * Each message sent using this class consists of:
- * @li An 8-byte header containing the length of the serialized data in
- * hexadecimal.
- * @li The serialized data.
- */
-class connection {
-public:
- /// Allow tentative support for new client to talk to old server
- /// by changing the boost serialisation archive version, hence tentative
- connection(boost::asio::io_service& io_service)
- : allow_new_client_old_server_(0),
- allow_old_client_new_server_(0),
- socket_(io_service)
- {
-#ifdef DEBUG_CONNECTION
- std::cout << "Connection::connection\n";
-#endif
- }
-
- ~connection() {
-#ifdef DEBUG_CONNECTION
- std::cout << "Connection::~connection socket_.is_open() = " << socket_.is_open() << "\n\n";
-#endif
- }
-
- /// Get the underlying socket. Used for making a connection or for accepting
- /// an incoming connection.
- boost::asio::ip::tcp::socket& socket() {
- return socket_;
- }
-
- // support for forward compatibility, by changing boost archive version, used in client context
- // See: ACore/src/boost_archive.hpp for details about serialisation migration issues
- void allow_new_client_old_server(int f) { allow_new_client_old_server_ = f;}
-
- // support for forward compatibility, by changing boost archive version, used in server context
- void allow_old_client_new_server(int f) { allow_old_client_new_server_ = f;}
-
-
- /// Asynchronously write a data structure to the socket.
- template<typename T, typename Handler>
- void async_write(const T& t, Handler handler) {
-
-#ifdef DEBUG_CONNECTION
- std::cout << "Connection::async_write, Serialise the data first so we know how large it is\n";
-#endif
- // Serialise the data first so we know how large it is.
- try {
- ecf::save_as_string(outbound_data_,t);
-
- if (allow_new_client_old_server_ != 0 && !Ecf::server()) {
- // Client context, forward compatibility, new client -> old server
- ecf::boost_archive::replace_version(outbound_data_,allow_new_client_old_server_);
- }
-
- // Server context: To allow build of ecflow, i.e old clients 3.0.x, installed on machines hpux,aix,etc
- // need to communicate to *new* server 4.0.0, new server (boost 1.53:10) ) --> (old_client:boost_1.47:9)
- // Note: the read below, will have determined the actual archive version used.
- if (Ecf::server() && allow_old_client_new_server_ != 0 ) {
- ecf::boost_archive::replace_version(outbound_data_,allow_old_client_new_server_);
- }
-
- } catch (const boost::archive::archive_exception& ae ) {
- // Unable to decode data. Something went wrong, inform the caller.
- log_archive_error("Connection::async_write, boost::archive::archive_exception ",ae);
- boost::system::error_code error(boost::asio::error::invalid_argument);
- socket_.get_io_service().post(boost::bind(handler, error));
- return;
- }
-
-#ifdef DEBUG_CONNECTION
- std::cout << "Connection::async_write Format the header \n";
-#endif
- // Format the header.
- std::ostringstream header_stream;
- header_stream << std::setw(header_length) << std::hex << outbound_data_.size();
- if (!header_stream || header_stream.str().size() != header_length) {
- // Something went wrong, inform the caller.
- log_error("Connection::async_write, could not format header");
- boost::system::error_code error(boost::asio::error::invalid_argument);
- socket_.get_io_service().post(boost::bind(handler, error));
- return;
- }
- outbound_header_ = header_stream.str();
-
-
-#ifdef DEBUG_CONNECTION_MEMORY
- if (Ecf::server()) std::cout << "server::";
- else std::cout << "client::";
- std::cout << "async_write outbound_header_.size(" << outbound_header_.size() << ") outbound_data_.size(" << outbound_data_.size() << ")\n";
-#endif
-
-#ifdef DEBUG_CONNECTION
- std::cout << "Connection::async_write Write the serialized data to the socket. \n";
-#endif
- // Write the serialized data to the socket. We use "gather-write" to send
- // both the header and the data in a single write operation.
- std::vector<boost::asio::const_buffer> buffers; buffers.reserve(2);
- buffers.push_back(boost::asio::buffer(outbound_header_));
- buffers.push_back(boost::asio::buffer(outbound_data_));
- boost::asio::async_write(socket_, buffers, handler);
-
-#ifdef DEBUG_CONNECTION
- std::cout << "Connection::async_write END \n";
-#endif
- }
-
- /// Asynchronously read a data structure from the socket.
- template<typename T, typename Handler>
- void async_read(T& t, Handler handler) {
-
-#ifdef DEBUG_CONNECTION
- std::cout << "Connection::async_read\n";
-#endif
-
- // Issue a read operation to read exactly the number of bytes in a header.
- void (connection::*f)(const boost::system::error_code&, T&,boost::tuple<Handler>)
- = &connection::handle_read_header<T, Handler>;
-
- boost::asio::async_read(socket_, boost::asio::buffer(inbound_header_),
- boost::bind(f, this, boost::asio::placeholders::error,
- boost::ref(t), boost::make_tuple(handler)));
- }
-
-private:
- /// Handle a completed read of a message header. The handler is passed using
- /// a tuple since boost::bind seems to have trouble binding a function object
- /// created using boost::bind as a parameter.
- template<typename T, typename Handler>
- void handle_read_header(const boost::system::error_code& e, T& t,boost::tuple<Handler> handler)
- {
- if (e) {
- boost::get<0>(handler)(e);
- } else {
- // Determine the length of the serialized data.
- std::istringstream is(std::string(inbound_header_, header_length));
- std::size_t inbound_data_size = 0;
- if (!(is >> std::hex >> inbound_data_size)) {
-
- // Header doesn't seem to be valid. Inform the caller.
- boost::system::error_code error(boost::asio::error::invalid_argument);
- boost::get<0>(handler)(error);
- return;
- }
-
- // Start an asynchronous call to receive the data.
- inbound_data_.resize(inbound_data_size);
- void (connection::*f)(const boost::system::error_code&, T&,boost::tuple<Handler>)
- = &connection::handle_read_data<T, Handler>;
-
- boost::asio::async_read(socket_,
- boost::asio::buffer(inbound_data_), boost::bind(f, this,
- boost::asio::placeholders::error, boost::ref(t),
- handler));
- }
- }
-
- /// Handle a completed read of message data.
- template<typename T, typename Handler>
- void handle_read_data(const boost::system::error_code& e, T& t, boost::tuple<Handler> handler)
- {
- if (e) {
- boost::get<0>(handler)(e);
- } else {
- // Extract the data structure from the data just received.
- try {
- std::string archive_data(&inbound_data_[0], inbound_data_.size());
-
-#ifdef DEBUG_CONNECTION_MEMORY
- if (Ecf::server()) std::cout << "server::";
- else std::cout << "client::";
- std::cout << "handle_read_data inbound_data_.size(" << inbound_data_.size() << ")\n";
-#endif
-
- ecf::restore_from_string(archive_data,t);
-
- // Server context: To allow build of ecflow, i.e old clients 3.0.x, installed on machines hpux,aix,etc
- // need to communicate to *new* server 4.0.0, new server (boost 1.53:10) ) --> (old_client:boost_1.47:9)
- if (Ecf::server() && allow_old_client_new_server_ != 0 ) {
- // get the actual version used, and *re-use* when replying back to *old* client
- int archive_version_in_data = ecf::boost_archive::extract_version(archive_data);
- int current_archive_version = ecf::boost_archive::version();
- if ( current_archive_version != archive_version_in_data ) {
- allow_old_client_new_server_ = archive_version_in_data;
- }
- else {
- // compatible, don't bother changing the write format
- allow_old_client_new_server_ = 0;
- }
- }
- }
- catch (const boost::archive::archive_exception& ae ) {
-
- // Log anyway so we know client <--> server incompatible
- log_archive_error("Connection::handle_read_data, boost::archive::archive_exception ",ae);
-
- // two context, client code or server, before giving up, try
- // - Client context, new server -> old client (* assumes old client updated, with this code *)
- // - Server context, new client -> old server (* assumes old server updated, with this code *)
- // Match up the boost archive version in the string archive_data with current version
- std::string archive_data(&inbound_data_[0], inbound_data_.size());
- int current_archive_version = ecf::boost_archive::version();
- int archive_version_in_data = ecf::boost_archive::extract_version(archive_data);
- if (current_archive_version != archive_version_in_data ) {
- if (ecf::boost_archive::replace_version(archive_data,current_archive_version)) {
-
- try {
- ecf::restore_from_string(archive_data,t);
- // It worked
- boost::get<0>(handler)(e);
- return;
- }
- catch (...) {} // fall through and return error code
- }
- }
-
- // Unable to decode data.
- boost::system::error_code error( boost::asio::error::invalid_argument);
- boost::get<0>(handler)(error);
- return;
- }
- catch (std::exception& ) {
- log_error("Connection::handle_read_data, Unable to decode data");
- boost::system::error_code error( boost::asio::error::invalid_argument);
- boost::get<0>(handler)(error);
- return;
- }
-
- // Inform caller that data has been received ok.
- boost::get<0>(handler)(e);
- }
- }
-
-private:
-
- void log_error(const char* msg) {
- const char* in_context = ", in client";
- if (Ecf::server()) in_context = ", in server";
- ecf::LogToCout logToCout;
- LOG(ecf::Log::ERR, msg << in_context);
- }
-
- void log_archive_error(const char* msg,const boost::archive::archive_exception& ae) {
- const char* in_context = ", in client";
- if (Ecf::server()) in_context = ", in server";
- ecf::LogToCout logToCout;
- LOG(ecf::Log::ERR, msg << ae.what() << in_context);
- }
-
-private:
- int allow_new_client_old_server_;
- int allow_old_client_new_server_;
- boost::asio::ip::tcp::socket socket_;/// The underlying socket.
- std::string outbound_header_; /// Holds an out-bound header.
- std::string outbound_data_; /// Holds the out-bound data.
- enum { header_length = 8 }; /// The size of a fixed length header.
- char inbound_header_[header_length]; /// Holds an in-bound header.
- std::vector<char> inbound_data_; /// Holds the in-bound data.
-};
-
-typedef boost::shared_ptr<connection> connection_ptr;
-
-#endif /* CONNECTION_HPP_ */
diff --git a/ecflow_4_0_7/Base/src/Gnuplot.cpp b/ecflow_4_0_7/Base/src/Gnuplot.cpp
deleted file mode 100644
index 21ca8e9..0000000
--- a/ecflow_4_0_7/Base/src/Gnuplot.cpp
+++ /dev/null
@@ -1,358 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Encompasses functionality for plotting server load
-//============================================================================
-#include <assert.h>
-#include <vector>
-#include <iostream>
-#include <sstream>
-#include <fstream>
-#include <sys/stat.h> // for chmod
-#include <boost/bind.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-
-#include "Gnuplot.hpp"
-#include "File_r.hpp"
-#include "Str.hpp"
-#include "NodePath.hpp"
-
-using namespace std;
-namespace fs = boost::filesystem;
-
-
-namespace ecf {
-
-void Gnuplot::show_server_load(const std::string& log_file,size_t no_of_suites_to_plot)
-{
- if (!fs::exists(log_file)) {
- std::stringstream ss;
- ss << "Gnuplot::show_server_load: The log file " << log_file << " does not exist\n";
- throw std::runtime_error( ss.str() );
- }
-
- // The vector index is the order in which suites are found, this will be used to place the suite in the correct column
- std::vector<SuiteLoad> suite_vec;
- std::string gnuplot_file = create_gnuplot_file(log_file,suite_vec);
- std::string gnuplot_script = create_gnuplot_script(gnuplot_file,suite_vec,no_of_suites_to_plot);
-
-
- // make the gnuplot_script file executable
- if ( chmod( gnuplot_script.c_str(), 0755 ) != 0 ) {
- std::stringstream ss;
- ss << "Gnuplot::show_server_load: Could not make gnu script file " << gnuplot_script << " executable by using chmod";
- throw std::runtime_error(ss.str());
- }
-
- std::string execute_gnuplot = "gnuplot " + gnuplot_script;
- ::system(execute_gnuplot.c_str());
-}
-
-
-std::string Gnuplot::create_gnuplot_file(
- const std::string& the_log_file,
- std::vector<SuiteLoad>& suite_vec,
- const std::string& temp_file )
-{
- /// Will read the log file and create a new file that can be used as input to gnuplot
- /// We will collate each request/cmd to the server made over a second.
- /// There are two kinds of commands:
- /// o User Commands: these start with --
- /// o Child Command: these start with chd:
- /// All child commands specify a path and hence suite, whereas for user commands this is optional
- /// We will trap all use of paths, so that we can show which suites are contributing to the server load
- /// This will be done for 4 suites
- ///
- /// Will convert: FROM:
- /// XXX:[HH:MM:SS D.M.YYYY] chd:init [+additional information]
- /// XXX:[HH:MM:SS D.M.YYYY] --begin [+additional information]
- /// -------------: TO:
- /// 1 2 3 4 5 6 7 8 9 10
- /// HH:MM:SS D.M.YYYY request/sec child_request users_requests suite_0 suite_1 suite_2 suite_3 suite_n
-
- /// The log file can be massive > 50Mb
- File_r log_file( the_log_file);
- if ( !log_file.ok() ) throw std::runtime_error( "Gnuplot::prepare_for_gnuplot: Could not open log file " + the_log_file );
-
-
- /// Create a new file that can be used with gnuplot. This has to be column based
- std::ofstream gnuplot_file( temp_file.c_str() );
- if ( !gnuplot_file ) {
- throw std::runtime_error( "Gnuplot::prepare_for_gnuplot: Could not open output file: " + temp_file);
- }
-
- gnuplot_file << "#time date total-request child user suite_0 suite_1 suite_2 suite_3 suite_n\n";
-
- std::vector< std::string > new_time_stamp;
- std::vector< std::string > old_time_stamp;
- size_t child_requests_per_second = 0;
- size_t user_request_per_second = 0;
- unsigned int plot_data_line_number = 0;
- string line;
- while ( log_file.good() ) {
- log_file.getline( line); // default delimiter is /n
-
- // The log file format we are interested is :
- // 0 1 2 3
- // MSG:[HH:MM:SS D.M.YYYY] chd:fullname [path +additional information]
- // MSG:[HH:MM:SS D.M.YYYY] --begin [args | path(optional) ] :<user>
-
- /// We are only interested in Commands (i.e MSG:), and not state changes
- if (line.empty()) continue;
- if (line[0] != 'M') continue;
- std::string::size_type msg_pos = line.find("MSG:");
- if (msg_pos != 0) continue;
-
- bool child_cmd = false;
- bool user_cmd = false;
- if (line.find(Str::CHILD_CMD()) != std::string::npos) child_cmd = true;
- else if (line.find(Str::USER_CMD()) != std::string::npos) user_cmd = true;
- if (!child_cmd && !user_cmd) continue;
-
- new_time_stamp.clear();
- {
- /// MSG:[HH:MM:SS D.M.YYYY] chd:fullname [+additional information] ---> HH:MM:SS D.M.YYYY
- /// EXTRACT the date
- string::size_type first_open_bracket = line.find('[');
- if ( first_open_bracket == std::string::npos) { std::cout << line << "\n"; assert(false); continue;}
- line.erase(0,first_open_bracket+1);
-
- string::size_type first_closed_bracket = line.find(']');
- if ( first_closed_bracket == std::string::npos) { std::cout << line << "\n"; assert(false); continue;}
- std::string time_stamp = line.substr(0, first_closed_bracket);
-
- Str::split(time_stamp, new_time_stamp);
- if (new_time_stamp.size() != 2) continue;
-
- line.erase(0,first_closed_bracket+1);
- }
-
- // Should be just left with " chd:<child command> " or " --<user command>, since we have remove time stamp
-//#ifdef DEBUG
-// std::cout << line << "\n";
-//#endif
-
- if (old_time_stamp.empty()) {
- if (child_cmd) child_requests_per_second++;
- else user_request_per_second++;
-
- // Extract path if any, to determine the suite most contributing to server load
- size_t column_index = 0;
- bool suite_path_found = extract_suite_path(line,child_cmd,suite_vec,column_index);
- if ( suite_path_found ) assert(suite_vec[column_index].request_per_second_ <= (child_requests_per_second + user_request_per_second) );
- }
- else if (old_time_stamp[0] == new_time_stamp[0]) { // HH:MM:SS == HH:MM:SS
- if (child_cmd) child_requests_per_second++;
- else user_request_per_second++;
-
- size_t column_index = 0;
- bool suite_path_found = extract_suite_path(line,child_cmd,suite_vec,column_index);
- if ( suite_path_found ) assert(suite_vec[column_index].request_per_second_ <= (child_requests_per_second + user_request_per_second) );
- }
- else {
- /// Start of *NEW* time,
- /// write the *OLD* time line should contain time date without []
- /// 1 2 3 4 5 6 7 8 9 10
- /// HH:MM:SS D.M.YYYY total_request child_request users_requests suite_0 suite_1 suite_2 suite_3 suite_n
- plot_data_line_number++;
- gnuplot_file << old_time_stamp[0] << " "
- << old_time_stamp[1] << " "
- << (child_requests_per_second + user_request_per_second) << " "
- << child_requests_per_second << " "
- << user_request_per_second << " ";
- for(size_t i = 0; i < suite_vec.size(); i++) { gnuplot_file << suite_vec[i].request_per_second_ << " ";}
- gnuplot_file << "\n";
-
-
- // clear request per second
- child_requests_per_second = 0;
- user_request_per_second = 0;
- for(size_t i= 0; i < suite_vec.size();i++) { suite_vec[i].request_per_second_ = 0; }
-
- // start of *new* time
- if (child_cmd) child_requests_per_second++;
- else user_request_per_second++;
-
- size_t column_index = 0;
- bool suite_path_found = extract_suite_path(line,child_cmd,suite_vec,column_index);
- if ( suite_path_found ) assert(suite_vec[column_index].request_per_second_ <= (child_requests_per_second + user_request_per_second) );
- }
-
- old_time_stamp = new_time_stamp;
- }
-
- if (plot_data_line_number < 3) {
- throw std::runtime_error( "Gnuplot::prepare_for_gnuplot: Log file empty or not enough data for plot\n");
- }
- return temp_file;
-}
-
-std::string Gnuplot::create_gnuplot_script(
- const std::string& path_to_file,
- const std::vector<SuiteLoad>& suite_vec,
- size_t no_of_suites_to_plot,
- const std::string& script)
-{
- /// Create the gnuplot script file for rendering the graph
- std::ofstream gnuplot_script( script.c_str() );
- if ( !gnuplot_script ) {
- throw std::runtime_error( "Gnuplot::create_gnuplot_script: Could not open output file: " + script);
- }
-
-
- gnuplot_script << "set autoscale # scale axes automatically\n";
- gnuplot_script << "set xtic auto rotate # set xtics automatically\n";
- gnuplot_script << "set ytic auto # set ytics automatically\n";
-// gnuplot_script << "set origin 0,0.08 # offset y, so that rotated xtics don't truncate, However cause title to disappear\n";
- gnuplot_script << "set title \"Server request per second\"\n";
- gnuplot_script << "set x2label \"time/min\" textcolor lt 3\n";
- gnuplot_script << "set ylabel \"requests\"\n";
- gnuplot_script << "set xdata time\n";
- gnuplot_script << "set grid # show grid\n";
- gnuplot_script << "set timefmt \"%H:%M:%S %d.%m.%Y\"\n";
-
- //# LINE COLORS, STYLES
- //# type 'test' to see the colors and point types available.
- //# Differs from x11 to postscript
- //# lt chooses a particular line type: -1=black 1=red 2=grn 3=blue 4=purple 5=aqua 6=brn 7=orange 8=light-brn
- //# lt must be specified before pt for colored points
- //# for postscipt -1=normal, 1=grey, 2=dashed, 3=hashed, 4=dot, 5=dot-dash
- //# lw chooses a line width 1=normal, can use 0.8, 0.3, 1.5, 3, etc.
- //# ls chooses a line style
-
- /// 1 2 3 4 5 6 7 8 9 n
- /// HH:MM:SS D.M.YYYY total_request child_request users_requests suite_0 suite_1 suite_2 suite_3 suite_n
-
- // determine which suite columns to plot based on server load
- std::vector<SuiteLoad> suite_vec_copy = suite_vec;
-
-// cout << "sort vector according to load\n";
- std::sort(suite_vec_copy.begin(),suite_vec_copy.end(),
- boost::bind(std::greater<int>(),
- boost::bind(&SuiteLoad::total_request_per_second_, _1),
- boost::bind(&SuiteLoad::total_request_per_second_, _2)));
-// for(size_t i = 0; i < suite_vec_copy.size(); i++) {
-// cout << " " << suite_vec_copy[i].first << " " << suite_vec_copy[i].second << "\n";
-// }
-
-// cout << "get top loaded suites\n";
- std::vector<std::string> suites;
- for(size_t i = 0; i < suite_vec_copy.size() && i < no_of_suites_to_plot; i++) {
- suites.push_back(suite_vec_copy[i].suite_name_);
- }
-// std::copy(suites.begin(), suites.end(), std::ostream_iterator <std::string> (std::cout, "\n"));
-
-
-// cout << "now determine which columns the top suites belong to, **THIS** time <int> indicates column\n";
- std::vector< std::pair<std::string,int> > ordered_suites;
- for(size_t column = 0; column < suite_vec.size(); column++) {
- for(size_t j = 0; j < suites.size(); j++) {
- if (suites[j] == suite_vec[column].suite_name_) {
- ordered_suites.push_back ( std::make_pair(suites[j], column));
- }
- }
- }
-// for(size_t i = 0; i < ordered_suites.size(); i++) {
-// cout << " " << ordered_suites[i].first << " " << ordered_suites[i].second << "\n";
-// }
-
-
- gnuplot_script << "plot \""
- << path_to_file << "\" using 1:4 title \"child\" with lines, \""
- << path_to_file << "\" using 1:5 title \"user\" with lines, \""
- << path_to_file << "\" using 1:3 smooth bezier title \"total-load\" with lines lt 3";
- if (!ordered_suites.empty()) gnuplot_script << ",";
- else gnuplot_script << "\n";
- for(size_t i = 0; i < ordered_suites.size(); i++) {
- gnuplot_script << "\""
- << path_to_file
- << "\" using 1:" << (6 + ordered_suites[i].second)
- << " smooth bezier title \"" << ordered_suites[i].first << "\" with lines";
- if (i == ordered_suites.size() -1) gnuplot_script << "\n";
- else gnuplot_script << ",";
- }
-
- gnuplot_script << "pause -1 \"Hit any key to continue\"\n\n";
-
- return script;
-}
-
-
-bool Gnuplot::extract_suite_path(
- const std::string& line,
- bool child_cmd,
- std::vector<SuiteLoad>& suite_vec,
- size_t& column_index // 0 based
- )
-{
- // line should either
- // chd:<childcommand> path
- // --<user command) path<optional> :<user>
- size_t forward_slash = line.find('/');
- if ( forward_slash != std::string::npos) {
-
- std::string path;
- if (child_cmd) {
-
- // For labels ignore paths in the label part
- // MSG:[14:55:04 17.10.2013] chd:label progress 'core/nodeattr/nodeAParser' /suite/build/cray/cray_gnu/build_release/test
- if (line.find("chd:label") != std::string::npos) {
- size_t last_tick = line.rfind("'");
- if ( last_tick != std::string::npos ) {
- size_t the_forward_slash = line.find('/',last_tick);
- if (the_forward_slash != std::string::npos) {
- forward_slash = the_forward_slash;
- }
- }
- }
- path = line.substr(forward_slash);
- }
- else {
- // Ignore the --news command, they dont have a path, hence i.e to ignore line like:
- // MSG:[09:36:05 22.10.2013] --news=1 36506 6 :ma0 [server handle(36508,7) server(36508,7)
- // : *Large* scale changes (new handle or suites added/removed) :NEWS]
- // the /removed was being interpreted as a suite
- if (line.find("--news") != std::string::npos) return false;
- }
-
- // find the space after the path
- size_t space_pos = line.find(" ",forward_slash);
- if (space_pos != std::string::npos && space_pos > forward_slash) {
- path = line.substr(forward_slash,space_pos-forward_slash);
- }
-
- if (!path.empty()) {
-
- std::vector<std::string> theNodeNames; theNodeNames.reserve(4);
- NodePath::split(path,theNodeNames);
- if (!theNodeNames.empty()) {
- for(size_t n = 0; n < suite_vec.size(); n++) {
- if (suite_vec[n].suite_name_ == theNodeNames[0] ) {
- suite_vec[n].request_per_second_++;
- suite_vec[n].total_request_per_second_++;
- column_index = n;
- return true;
- }
- }
-
- suite_vec.push_back( SuiteLoad(theNodeNames[0]) );
- column_index = suite_vec.size() - 1;
- return true;
- }
- }
- }
- return false;
-}
-
-
-}
diff --git a/ecflow_4_0_7/Base/src/Gnuplot.hpp b/ecflow_4_0_7/Base/src/Gnuplot.hpp
deleted file mode 100644
index 2ea9dce..0000000
--- a/ecflow_4_0_7/Base/src/Gnuplot.hpp
+++ /dev/null
@@ -1,69 +0,0 @@
-#ifndef GNUPLOT_HPP_
-#define GNUPLOT_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name : Log
-// Author : Avi
-// Revision : $Revision: #2 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <string>
-#include <boost/noncopyable.hpp>
-
-namespace ecf {
-
-class Gnuplot : private boost::noncopyable {
-public:
-
- /// parse the log file and show gnuplot of server load
- /// Include the suite most contributing to the load
- /// Assumes that gnuplot is available on $PATH
- static void show_server_load(const std::string& log_file, size_t no_of_suites_to_plot = 5);
-
-private:
-
- struct SuiteLoad {
- SuiteLoad(const std::string& name) : suite_name_(name), request_per_second_(1), total_request_per_second_(1) {}
-
- std::string suite_name_;
- size_t request_per_second_;
- size_t total_request_per_second_;
- };
-
- /// Returns that path to file created by this function.
- /// The create file is to be used by gnuplot to show the server load.
- /// Can throw exceptions
- static std::string create_gnuplot_file(
- const std::string& log_file,
- std::vector<SuiteLoad>& suite_vec,
- const std::string& input_data = "gnuplot.dat");
-
- /// returns the path to the gnuplot script
- static std::string create_gnuplot_script(
- const std::string& path_to_file,
- const std::vector<SuiteLoad>& suite_vec,
- size_t no_of_suites_to_plot,
- const std::string& script = "gnuplot.script");
-
- static bool extract_suite_path(
- const std::string& line,
- bool child_cmd,
- std::vector<SuiteLoad>& suite_vec,
- size_t& column_index // 0 based
- );
-
-private:
-
- ~Gnuplot();
- Gnuplot();
-};
-}
-
-#endif
diff --git a/ecflow_4_0_7/Base/src/ServerReply.cpp b/ecflow_4_0_7/Base/src/ServerReply.cpp
deleted file mode 100644
index d295e57..0000000
--- a/ecflow_4_0_7/Base/src/ServerReply.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-//#include <iostream>
-#include "ServerReply.hpp"
-
-/// *Note* server_reply_.client_handle_ is kept until the next call to register a new client_handle
-/// The client invoker can be used multiple times, hence keep value of defs, and client handle in server reply
-void ServerReply::clear_for_invoke(bool command_line_interface)
-{
- //std::cout << "ServerReply::clear_for_invoke\n";
- cli_ = command_line_interface;
- in_sync_ = false;
- full_sync_ = false;
- news_ = ServerReply::NO_NEWS;
- block_client_on_home_server_ = false;
- block_client_server_halted_ = false;
- block_client_zombie_detected_ = false;
- error_msg_.clear();
- str_.clear();
- zombies_.clear();
- str_vec_.clear();
- client_handle_suites_.clear();
- changed_nodes_.clear();
-}
diff --git a/ecflow_4_0_7/Base/src/ServerReply.hpp b/ecflow_4_0_7/Base/src/ServerReply.hpp
deleted file mode 100644
index d565b28..0000000
--- a/ecflow_4_0_7/Base/src/ServerReply.hpp
+++ /dev/null
@@ -1,138 +0,0 @@
-#ifndef SERVER_REPLY_HPP_
-#define SERVER_REPLY_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #18 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <string>
-#include <vector>
-#include <boost/noncopyable.hpp>
-#include "NodeFwd.hpp"
-#include "Zombie.hpp"
-#include "Stats.hpp"
-
-/// This class is used to hold the replies back from the server
-/// *Note* server_reply_.client_handle_ is kept until the next call to register a new client_handle
-/// The client invoker can be used multiple times, hence keep value of defs, and client handle in server reply
-
-class ServerReply : private boost::noncopyable {
-public:
- // After ECFLOW-182, NO_DEFS no longer used, however kept, to ensure client/server compatibility
- // ie. for new client(viewer) must process this from old server, which could return NO_DEFS
- enum News_t { NO_NEWS, NEWS, DO_FULL_SYNC, NO_DEFS };
- ServerReply()
- : cli_(false), in_sync_(false), full_sync_(false), news_(NO_NEWS),
- block_client_on_home_server_(false),block_client_server_halted_(false),block_client_zombie_detected_(false),
- client_handle_(0) {}
-
- /// *Note* server_reply_.client_handle_ is kept until the next call to register a new client_handle
- /// The client invoker can be used multiple times, hence keep value of defs, and client handle in server reply
- /// and reset everything else
- void clear_for_invoke(bool command_line_interface); // true if calling from command line
-
- /// task based replies
- bool block_client_on_home_server() const { return block_client_on_home_server_;}
- void set_block_client_on_home_server() { block_client_on_home_server_ = true;}
-
- bool block_client_server_halted() const { return block_client_server_halted_;}
- void set_block_client_server_halted() { block_client_server_halted_ = true;}
-
- bool block_client_zombie_detected() const { return block_client_zombie_detected_;}
- void set_block_client_zombie_detected() { block_client_zombie_detected_ = true;}
-
- bool client_request_failed() const { return !error_msg_.empty(); }
- void set_error_msg(const std::string& e) { error_msg_ = e;}
- const std::string& error_msg() const { return error_msg_; }
- std::string& get_error_msg() { return error_msg_; }
-
- const std::vector<Zombie>& zombies() const { return zombies_; }
- void set_zombies( const std::vector<Zombie>& z) { zombies_ = z;}
-
- /// For uses with the suites cmd, or any other command that needs a vector of strings form server
- const std::vector<std::string>& get_string_vec() const { return str_vec_; }
- void set_string_vec( const std::vector<std::string>& z) { str_vec_ = z;}
-
- const std::vector<std::pair<unsigned int, std::vector<std::string> > >& get_client_handle_suites() const { return client_handle_suites_; }
- void set_client_handle_suites(const std::vector<std::pair<unsigned int, std::vector<std::string> > >& s) { client_handle_suites_ = s; }
-
- /// Only valid when the client requested the CFileCmd or log file from the server
- /// Other times this will be empty.
- const std::string& get_string() const { return str_; }
- void set_string( const std::string& f) { str_ = f;}
-
- /// Only valid when Stats command called.
- const Stats& stats() const { return stats_; }
- void set_stats( const Stats& s) { stats_ = s;}
-
- /// Return true if client is using Command Level Interface. Set via clear_for_invoke()
- bool cli() const { return cli_; }
-
- /// Only valid after a call to sync()
- /// in_sync() should be called after call to sync() Returns true if client defs is now in_sync with server
- bool in_sync() const { return in_sync_;}
- void set_sync(bool b) { in_sync_ = b;}
-
- /// The SSyncCmd will set if we have a full sync(ie retrieved full node tree from server) or incremental sync
- bool full_sync() const { return full_sync_; }
- void set_full_sync(bool f) { full_sync_ = f; }
-
- /// Only valid after a call to news()
- /// return true if the server has changed
- News_t get_news() const { return news_; }
- void set_news(News_t n) { news_ = n;}
-
-
- /// Only valid when the client requested the defs node tree from the server
- /// The defs *WILL* be retained until the next call to get the server defs
- /// **Hence is NOT reset in clear_for_invoke()
- defs_ptr client_defs() const { return client_defs_; }
- void set_client_defs(defs_ptr d) { client_defs_ = d;}
-
- /// Only valid when the client requested the node from the server
- /// The node *WILL* be retained until the next call to get the node
- /// **Hence is NOT reset in clear_for_invoke()
- node_ptr client_node() const { return client_node_; }
- void set_client_node(node_ptr d) { client_node_ = d;}
-
- /// A client handle of value 0 is not valid. Created in the server
- /// We should keep a reference to the client handle, for use with client handle commands
- /// **Hence is NOT reset in clear_for_invoke()
- void set_client_handle(int handle) { client_handle_ = handle;}
- int client_handle() const { return client_handle_;}
-
- // During incremental sync, record list of changed nodes, used by python api
- std::vector<std::string>& changed_nodes() { return changed_nodes_; }
-
-private:
- friend class SSyncCmd;
- bool cli_;
- bool in_sync_; // clear at the start of invoke
- bool full_sync_; // clear at the start of invoke
- News_t news_; // clear at the start of invoke
- bool block_client_on_home_server_; // clear at the start of invoke
- bool block_client_server_halted_; // clear at the start of invoke
- bool block_client_zombie_detected_; // clear at the start of invoke
- std::string str_; // clear at the start of invoke
- std::string error_msg_; // clear at the start of invoke
- std::vector<Zombie> zombies_; // clear at the start of invoke
- std::vector<std::string> str_vec_; // clear at the start of invoke
- std::vector<std::string> changed_nodes_;// clear at the start of invoke
- std::vector<std::pair<unsigned int, std::vector<std::string> > > client_handle_suites_; // clear at the start of invoke
- Stats stats_; // Used for test only, ideally need to clear
-
- int client_handle_; // set locally when suites are registered, and kept for reference
- defs_ptr client_defs_; // server reply stored as the client side defs, kept locally
- node_ptr client_node_; // server reply stored as the client side node, kept locally
-};
-#endif
diff --git a/ecflow_4_0_7/Base/src/ServerToClientResponse.cpp b/ecflow_4_0_7/Base/src/ServerToClientResponse.cpp
deleted file mode 100644
index b530956..0000000
--- a/ecflow_4_0_7/Base/src/ServerToClientResponse.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #13 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <assert.h>
-#include <fstream>
-#include <sstream>
-#include <stdexcept>
-
-#include "ServerToClientResponse.hpp"
-#include "ClientToServerRequest.hpp" // for throw
-#include "AbstractServer.hpp"
-
-using namespace std;
-using namespace ecf;
-
-bool ServerToClientResponse::handle_server_response( ServerReply& r, Cmd_ptr cts_cmd, bool debug ) const
-{
- /// Called in client context: see ClientInvoker
- if (stc_cmd_.get()) {
- return stc_cmd_->handle_server_response(r,cts_cmd,debug);
- }
-
- /// ClientToServerRequest::handleRequest returned a NULL pointer stc_cmd_.
- std::stringstream ss;
- ss << "ServerToClientResponse::handle_server_response: ";
- if (cts_cmd.get()) {
- ss << "Client request ";
- cts_cmd->print(ss);
- ss << " failed. ";
- }
- ss << "Server replied with a NULL message\n";
- throw std::runtime_error(ss.str());
-}
-
-std::ostream& ServerToClientResponse::print( std::ostream& os ) const
-{
- if (stc_cmd_.get()) {
- return stc_cmd_->print(os);
- }
- return os << "NULL ServerToClientResponse";
-}
-
-bool ServerToClientResponse::operator==(const ServerToClientResponse& rhs) const
-{
- if (!stc_cmd_.get() && !rhs.stc_cmd_.get()) {
- return true;
- }
- if (stc_cmd_.get() && !rhs.stc_cmd_.get()) {
- return false;
- }
- if (!stc_cmd_.get() && rhs.stc_cmd_.get()) {
- return false;
- }
- return (stc_cmd_->equals(rhs.stc_cmd_.get()));
-}
-
-std::ostream& operator<<( std::ostream& os, const ServerToClientResponse& d ) {
- return d.print( os );
-}
diff --git a/ecflow_4_0_7/Base/src/ServerToClientResponse.hpp b/ecflow_4_0_7/Base/src/ServerToClientResponse.hpp
deleted file mode 100644
index 2ed2e26..0000000
--- a/ecflow_4_0_7/Base/src/ServerToClientResponse.hpp
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef SERVERTOCLIENTREQUEST_HPP_
-#define SERVERTOCLIENTREQUEST_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #30 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <boost/noncopyable.hpp>
-#include <boost/serialization/tracking.hpp>
-#include "ServerToClientCmd.hpp"
-
-// Base class for server to client requesting. This class is used in the IPC messaging between
-// server and client
-class ServerToClientResponse : private boost::noncopyable {
-public:
- ServerToClientResponse() {}
- ServerToClientResponse(const STC_Cmd_ptr& cmd) : stc_cmd_(cmd) {}
- ~ServerToClientResponse() {}
-
- STC_Cmd_ptr get_cmd() const { return stc_cmd_; }
- void set_cmd(const STC_Cmd_ptr& cmd) { stc_cmd_ = cmd;}
-
- std::ostream& print(std::ostream& os) const;
-
- /// Handle the response from the server. On the client side
- /// return true IF and ONLY IF client response was ok, if further client action required return false
- bool handle_server_response( ServerReply&, Cmd_ptr cts_cmd, bool debug ) const;
-
- /// Used by boost test, to verify persistence
- bool operator==(const ServerToClientResponse& rhs) const;
-
-private:
- STC_Cmd_ptr stc_cmd_;
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int /*version*/) {
- ar & stc_cmd_;
- }
-};
-
-std::ostream& operator<<(std::ostream& os, const ServerToClientResponse& d);
-
-// Do NOT use
-// BOOST_CLASS_IMPLEMENTATION(ecf::ServerToClientResponse, boost::serialization::object_serializable)
-// i.e eliminate serialisation overhead at the cost of never being able to increase the version.
-// Since we may need use version ing in the future
-
-// This should ONLY be added to objects that are *NOT* serialised through a pointer
-// Eliminate object tracking (even if serialised through a pointer)
-// at the risk of a programming error creating duplicate objects.
-BOOST_CLASS_TRACKING(ServerToClientResponse,boost::serialization::track_never);
-
-#endif
diff --git a/ecflow_4_0_7/Base/src/Stats.cpp b/ecflow_4_0_7/Base/src/Stats.cpp
deleted file mode 100644
index b1ef076..0000000
--- a/ecflow_4_0_7/Base/src/Stats.cpp
+++ /dev/null
@@ -1,333 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #35 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <iostream>
-#include <sstream>
-#include <iomanip>
-#include <string>
-#include "Stats.hpp"
-#include "SState.hpp"
-
-using namespace std;
-
-Stats::Stats() :
-
- status_(0),
- request_count_(0),
- job_sub_interval_(0),
- checkpt_interval_(0),
- checkpt_save_time_alarm_(0),
- checkpt_mode_(ecf::CheckPt::UNDEFINED),
- no_of_suites_(0),
-
- checkpt_(0),
- restore_defs_from_checkpt_(0),
-
- server_version_(0),
- restart_server_(0),
- shutdown_server_(0),
- halt_server_(0),
- reload_white_list_file_(0),
- ping_(0),
- debug_server_on_(0),
- debug_server_off_(0),
- get_defs_(0),
- sync_(0),
- news_(0),
-
- node_job_gen_(0),
- node_check_job_gen_only_(0),
- node_delete_(0),
- node_suspend_(0),
- node_resume_(0),
- node_kill_(0),
- node_status_(0),
- node_edit_history_(0),
-
- log_cmd_(0),
- log_msg_cmd_(0),
- begin_cmd_(0),
-
- task_init_(0),
- task_complete_(0),
- task_wait_(0),
- task_abort_(0),
- task_event_(0),
- task_meter_(0),
- task_label_(0),
-
- zombie_fob_(0),
- zombie_fail_(0),
- zombie_adopt_(0),
- zombie_remove_(0),
- zombie_get_(0),
- zombie_block_(0),
- zombie_kill_(0),
-
- requeue_node_(0),
- order_node_(0),
- run_node_(0),
- load_defs_(0),
- replace_(0),
- force_(0),
- free_dep_(0),
- suites_(0),
- edit_script_(0),
-
- alter_cmd_(0),
- ch_cmd_(0),
- file_ecf_(0),
- file_job_(0),
- file_jobout_(0),
- file_cmdout_(0),
- file_manual_(0),
-
- plug_(0),
- move_(0),
- group_cmd_(0),
- server_load_cmd_(0),
- stats_(0),
- check_(0)
-{
-}
-
-void Stats::update_stats(int poll_interval)
-{
- // Called at poll time, ie just before node tree traversal
- request_vec_.push_back( std::make_pair(request_count_,poll_interval) );
- request_count_ = 0;
- request_stats_.clear();
-
- // To stop excessive memory usage , we will only store, request per poll period, for 1 hour
- if (request_vec_.size() > 60) {
- request_vec_.pop_front();
- }
-}
-
-void Stats::update_for_serialisation()
-{
- /// This *ONLY* compute the data when this function is called
- /// >>> Hence the server load is only valid for last hour <<<
- no_of_suites_ = 0;
- if (request_vec_.empty()) return;
-
- std::stringstream ss;
- int count = 0;
- int request = 0;
- int seconds = 0;
- std::deque<std::pair<int,int> >::reverse_iterator rend = request_vec_.rend();
- for(std::deque<std::pair<int,int> >::reverse_iterator i = request_vec_.rbegin(); i != rend; ++i) {
- count++;
- request += (*i).first;
- seconds += (*i).second;
- double request_per_second = (double)request/seconds;
-
- if (count == 1) {
- ss << setiosflags(ios::fixed) << setprecision(2) << request_per_second;
- }
- else if (count == 5) {
- ss << " " << request_per_second;
- }
- else if (count == 15) {
- ss << " " << request_per_second;
- }
- else if (count == 30) {
- ss << " " << request_per_second ;
- }
- else if (count == 60) {
- ss << " " << request_per_second;
- }
- }
- request_stats_ = ss.str();
-}
-
-void Stats::reset()
-{
- checkpt_ = 0;
- restore_defs_from_checkpt_ = 0;
-
- server_version_ = 0;
- restart_server_ = 0;
- shutdown_server_ = 0;
- halt_server_ = 0;
- reload_white_list_file_ = 0;
- ping_ = 0;
- debug_server_on_ = 0;
- debug_server_off_ = 0;
- get_defs_ = 0;
- sync_ = 0;
- news_ = 0;
-
- node_job_gen_ = 0;
- node_check_job_gen_only_ = 0;
- node_delete_ = 0;
- node_suspend_ = 0;
- node_resume_ = 0;
- node_kill_ = 0;
- node_status_ = 0;
- node_edit_history_ = 0;
-
- log_cmd_ = 0;
- log_msg_cmd_ = 0;
- begin_cmd_ = 0;
-
- task_init_ = 0;
- task_complete_ = 0;
- task_wait_ = 0;
- task_abort_ = 0;
- task_event_ = 0;
- task_meter_ = 0;
- task_label_ = 0;
-
- zombie_fob_ = 0;
- zombie_fail_ = 0;
- zombie_adopt_ = 0;
- zombie_remove_ = 0;
- zombie_get_ = 0;
- zombie_block_ = 0;
- zombie_kill_ = 0;
-
- requeue_node_ = 0;
- order_node_ = 0;
- run_node_ = 0;
- load_defs_ = 0;
- replace_ = 0;
- force_ = 0;
- free_dep_ = 0;
- suites_ = 0;
- edit_script_ = 0;
-
- alter_cmd_ = 0;
- ch_cmd_ = 0;
- file_ecf_ = 0;
- file_job_ = 0;
- file_jobout_ = 0;
- file_cmdout_ = 0;
- file_manual_ = 0;
-
- plug_ = 0;
- move_ = 0;
- group_cmd_ = 0;
- server_load_cmd_ = 0;
- stats_ = 0;
- check_ = 0;
-}
-
-static string show_checkpt_mode(ecf::CheckPt::Mode m){
- switch (m) {
- case ecf::CheckPt::NEVER: return "CHECK_NEVER"; break;
- case ecf::CheckPt::ON_TIME: return "CHECK_ON_TIME"; break;
- case ecf::CheckPt::ALWAYS: return "CHECK_ON_ALWAYS"; break;
- case ecf::CheckPt::UNDEFINED: return "UNDEFINED"; break;
- }
- return std::string();
-}
-
-void Stats::show(std::ostream& os) const
-{
- int width = 35;
- os << "Server statistics\n";
- os << left << setw(width) << " Version " << version_ << "\n";
- os << left << setw(width) << " Status " << SState::to_string(status_) << "\n";
- os << left << setw(width) << " Host " << host_ << "\n";
- os << left << setw(width) << " Port " << port_ << "\n";
- os << left << setw(width) << " Up since " << up_since_ << "\n";
- os << left << setw(width) << " Job sub' interval " << job_sub_interval_ << "s\n";
- os << left << setw(width) << " ECF_HOME " << ECF_HOME_ << "\n";
- os << left << setw(width) << " ECF_LOG " << ECF_LOG_ << "\n";
- os << left << setw(width) << " ECF_CHECK " << ECF_CHECK_ << "\n";
- os << left << setw(width) << " Check pt interval " << checkpt_interval_ << "s\n";
- os << left << setw(width) << " Check pt mode " << show_checkpt_mode(checkpt_mode_) << "\n";
- os << left << setw(width) << " Check pt save time alarm " << checkpt_save_time_alarm_ << "s\n";
- os << left << setw(width) << " Number of Suites " << no_of_suites_ << "\n";
- os << left << setw(width) << " Request's per 1,5,15,30,60 min " << request_stats_ << "\n";
-
- if (checkpt_ || restore_defs_from_checkpt_ || server_version_ || restart_server_ || shutdown_server_ || halt_server_ ||
- ping_ || debug_server_on_ || debug_server_off_ || get_defs_ || sync_ || news_) os << "\n";
- if (!locked_by_user_.empty()) os << left << setw(width) << " Locked by user " << locked_by_user_ << "\n";
- if (checkpt_ != 0) os << left << setw(width) << " Check points " << checkpt_ << "\n";
- if (restore_defs_from_checkpt_ != 0) os << left << setw(width) << " Restore from Check point " << restore_defs_from_checkpt_ << "\n";
- if (restart_server_ != 0) os << left << setw(width) << " Restart server " << restart_server_ << "\n";
- if (shutdown_server_ != 0) os << left << setw(width) << " Shutdown server " << shutdown_server_ << "\n";
- if (halt_server_ != 0) os << left << setw(width) << " Halt server " << halt_server_ << "\n";
- if (ping_ != 0) os << left << setw(width) << " Ping " << ping_ << "\n";
- if (debug_server_on_ != 0) os << left << setw(width) << " debug server on " << debug_server_on_ << "\n";
- if (debug_server_off_ != 0) os << left << setw(width) << " debug server off " << debug_server_off_ << "\n";
- if (get_defs_ != 0) os << left << setw(width) << " Get full definition " << get_defs_ << "\n";
- if (server_version_ != 0) os << left << setw(width) << " Server version " << server_version_ << "\n";
- if (sync_ != 0) os << left << setw(width) << " Sync " << sync_ << "\n";
- if (news_ != 0) os << left << setw(width) << " News " << news_ << "\n";
-
- if (task_init_ || task_complete_ || task_wait_ || task_abort_ || task_event_ || task_meter_ || task_label_) os << "\n";
- if (task_init_ != 0) os << left << setw(width) << " Task init " << task_init_ << "\n";
- if (task_complete_ != 0) os << left << setw(width) << " Task complete " << task_complete_ << "\n";
- if (task_wait_ != 0) os << left << setw(width) << " Task wait " << task_wait_ << "\n";
- if (task_abort_ != 0) os << left << setw(width) << " Task abort " << task_abort_ << "\n";
- if (task_event_ != 0) os << left << setw(width) << " Task event " << task_event_ << "\n";
- if (task_meter_ != 0) os << left << setw(width) << " Task meter " << task_meter_ << "\n";
- if (task_label_ != 0) os << left << setw(width) << " Task label " << task_label_ << "\n";
-
- if (zombie_fob_ || zombie_fail_ || zombie_adopt_ || zombie_remove_ || zombie_get_ || zombie_block_ || zombie_kill_) os << "\n";
- if (zombie_fob_ != 0) os << left << setw(width) << " Zombie fob " << zombie_fob_ << "\n";
- if (zombie_fail_ != 0) os << left << setw(width) << " Zombie fail " << zombie_fail_ << "\n";
- if (zombie_adopt_ != 0) os << left << setw(width) << " Zombie adopt " << zombie_adopt_ << "\n";
- if (zombie_remove_ != 0) os << left << setw(width) << " Zombie remove " << zombie_remove_ << "\n";
- if (zombie_get_ != 0) os << left << setw(width) << " Zombie get " << zombie_get_ << "\n";
- if (zombie_block_ != 0) os << left << setw(width) << " Zombie block " << zombie_block_ << "\n";
- if (zombie_kill_ != 0) os << left << setw(width) << " Zombie kill " << zombie_kill_ << "\n";
-
- if (load_defs_ || begin_cmd_ || requeue_node_ || node_job_gen_ || node_check_job_gen_only_ || node_delete_ || node_suspend_ ||
- node_resume_ || node_kill_ || node_status_ || node_edit_history_ || log_cmd_ || log_msg_cmd_ || order_node_ || run_node_ || replace_ ||
- force_ || free_dep_ || suites_ || edit_script_ || alter_cmd_ || ch_cmd_ || plug_ || move_ || group_cmd_ ||
- reload_white_list_file_ || server_load_cmd_ || stats_ || check_
- ) os << "\n";
- if (load_defs_ != 0) os << left << setw(width) << " Load definition " << load_defs_ << "\n";
- if (begin_cmd_ != 0) os << left << setw(width) << " Begin " << begin_cmd_ << "\n";
- if (requeue_node_ != 0) os << left << setw(width) << " Requeue " << requeue_node_ << "\n";
- if (node_job_gen_ != 0) os << left << setw(width) << " Job generation " << node_job_gen_ << "\n";
- if (node_check_job_gen_only_ != 0) os << left << setw(width) << " Check Job generation " << node_check_job_gen_only_ << "\n";
- if (node_delete_ != 0) os << left << setw(width) << " Node delete " << node_delete_ << "\n";
- if (node_suspend_ != 0) os << left << setw(width) << " Node suspend " << node_suspend_ << "\n";
- if (node_resume_ != 0) os << left << setw(width) << " Node resume " << node_resume_ << "\n";
- if (node_kill_ != 0) os << left << setw(width) << " Node kill " << node_kill_ << "\n";
- if (node_status_ != 0) os << left << setw(width) << " Node status " << node_status_ << "\n";
- if (node_edit_history_ != 0) os << left << setw(width) << " Node edit history " << node_edit_history_ << "\n";
- if (log_cmd_ != 0) os << left << setw(width) << " Log cmd " << log_cmd_ << "\n";
- if (log_msg_cmd_ != 0) os << left << setw(width) << " Log message " << log_msg_cmd_ << "\n";
- if (order_node_ != 0) os << left << setw(width) << " Order " << order_node_ << "\n";
- if (run_node_ != 0) os << left << setw(width) << " Run " << run_node_ << "\n";
- if (replace_ != 0) os << left << setw(width) << " Replace " << replace_ << "\n";
- if (force_ != 0) os << left << setw(width) << " Force " << force_ << "\n";
- if (free_dep_ != 0) os << left << setw(width) << " Free dependencies " << free_dep_ << "\n";
- if (suites_ != 0) os << left << setw(width) << " Suites " << suites_ << "\n";
- if (edit_script_ != 0) os << left << setw(width) << " Edit script " << edit_script_ << "\n";
- if (alter_cmd_ != 0) os << left << setw(width) << " Alter " << alter_cmd_ << "\n";
- if (ch_cmd_ != 0) os << left << setw(width) << " Client handle " << ch_cmd_ << "\n";
- if (plug_ != 0) os << left << setw(width) << " Plug " << plug_ << "\n";
- if (move_ != 0) os << left << setw(width) << " Move " << move_ << "\n";
- if (group_cmd_ != 0) os << left << setw(width) << " Group " << group_cmd_ << "\n";
- if (server_load_cmd_ != 0) os << left << setw(width) << " Server load cmd " << server_load_cmd_ << "\n";
- if (stats_ != 0) os << left << setw(width) << " stats cmd " << stats_ << "\n";
- if (check_ != 0) os << left << setw(width) << " checks " << check_ << "\n";
- if (reload_white_list_file_ != 0) os << left << setw(width) << " Reload white list file " << reload_white_list_file_ << "\n";
-
- if (file_ecf_ || file_job_ || file_jobout_ || file_manual_ || file_cmdout_) os << "\n";
- if (file_ecf_ != 0) os << left << setw(width) << " File ECF " << file_ecf_ << "\n";
- if (file_job_ != 0) os << left << setw(width) << " File job " << file_job_ << "\n";
- if (file_jobout_ != 0) os << left << setw(width) << " File Job out " << file_jobout_ << "\n";
- if (file_cmdout_ != 0) os << left << setw(width) << " File Cmd out " << file_cmdout_ << "\n";
- if (file_manual_ != 0) os << left << setw(width) << " File manual " << file_manual_ << "\n";
- os << flush;
-}
diff --git a/ecflow_4_0_7/Base/src/Stats.hpp b/ecflow_4_0_7/Base/src/Stats.hpp
deleted file mode 100644
index 6e3b4d0..0000000
--- a/ecflow_4_0_7/Base/src/Stats.hpp
+++ /dev/null
@@ -1,216 +0,0 @@
-#ifndef STATS_HPP_
-#define STATS_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #31 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <boost/serialization/serialization.hpp>
-#include <deque>
-#include <iostream>
-#include <sstream>
-#include "CheckPt.hpp"
-
-/// This class is used to store all statistical data about all the
-/// commands processed by the server. Uses default copy constructor
-struct Stats {
-
- Stats();
- void show(std::ostream& os = std::cout) const;
-
- void update() { request_count_++; }
- void update_stats(int poll_interval);
- void update_for_serialisation();
- void reset();
-
- int status_; // 0 HALTED, 1 SHUTDOWN, 2 RUNNING
- std::string locked_by_user_;
- std::string host_;
- std::string port_;
- std::string up_since_;
- std::string version_;
- std::string request_stats_;
- std::string ECF_HOME_;
- std::string ECF_CHECK_;
- std::string ECF_LOG_;
-
- int request_count_;
- int job_sub_interval_;
- int checkpt_interval_;
- int checkpt_save_time_alarm_;
- ecf::CheckPt::Mode checkpt_mode_;
- int no_of_suites_;
-
- unsigned int checkpt_;
- unsigned int restore_defs_from_checkpt_;
-
- unsigned int server_version_;
- unsigned int restart_server_;
- unsigned int shutdown_server_;
- unsigned int halt_server_;
- unsigned int reload_white_list_file_;
- unsigned int ping_;
- unsigned int debug_server_on_;
- unsigned int debug_server_off_;
- unsigned int get_defs_;
- unsigned int sync_;
- unsigned int news_;
-
- unsigned int node_job_gen_;
- unsigned int node_check_job_gen_only_;
- unsigned int node_delete_;
- unsigned int node_suspend_;
- unsigned int node_resume_;
- unsigned int node_kill_;
- unsigned int node_status_;
- unsigned int node_edit_history_;
-
- unsigned int log_cmd_;
- unsigned int log_msg_cmd_;
- unsigned int begin_cmd_;
-
- unsigned int task_init_;
- unsigned int task_complete_;
- unsigned int task_wait_;
- unsigned int task_abort_;
- unsigned int task_event_;
- unsigned int task_meter_;
- unsigned int task_label_;
-
- unsigned int zombie_fob_;
- unsigned int zombie_fail_;
- unsigned int zombie_adopt_;
- unsigned int zombie_remove_;
- unsigned int zombie_get_;
- unsigned int zombie_block_;
- unsigned int zombie_kill_;
-
- unsigned int requeue_node_;
- unsigned int order_node_;
- unsigned int run_node_;
- unsigned int load_defs_;
- unsigned int replace_;
- unsigned int force_;
- unsigned int free_dep_;
- unsigned int suites_;
- unsigned int edit_script_;
-
- unsigned int alter_cmd_;
- unsigned int ch_cmd_;
- unsigned int file_ecf_;
- unsigned int file_job_;
- unsigned int file_jobout_;
- unsigned int file_cmdout_;
- unsigned int file_manual_;
-
- unsigned int plug_;
- unsigned int move_;
- unsigned int group_cmd_;
- unsigned int server_load_cmd_;
- unsigned int stats_;
- unsigned int check_;
-
-private:
-
- std::deque< std::pair<int,int> > request_vec_; // pair.first = number of requests, pair.second = poll interval
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
-
- ar & status_;
- ar & locked_by_user_;
- ar & host_;
- ar & port_;
- ar & up_since_;
- ar & version_;
- ar & job_sub_interval_;
- ar & checkpt_interval_;
- ar & checkpt_save_time_alarm_;
- ar & checkpt_mode_;
- ar & no_of_suites_;
- ar & request_stats_;
- ar & ECF_HOME_;
- ar & ECF_CHECK_;
- ar & ECF_LOG_;
-
- ar & checkpt_;
-
- ar & server_version_;
- ar & restart_server_;
- ar & shutdown_server_;
- ar & halt_server_;
- ar & reload_white_list_file_;
- ar & ping_;
- ar & debug_server_on_;
- ar & debug_server_off_;
-
- ar & get_defs_;
- ar & sync_;
- ar & news_;
-
- ar & node_job_gen_;
- ar & node_check_job_gen_only_;
- ar & node_delete_;
- ar & node_suspend_;
- ar & node_resume_;
- ar & node_kill_;
- ar & node_status_;
- ar & node_edit_history_;
-
- ar & log_cmd_;
- ar & log_msg_cmd_;
- ar & begin_cmd_;
-
- ar & task_init_;
- ar & task_complete_;
- ar & task_wait_;
- ar & task_abort_;
- ar & task_event_;
- ar & task_meter_;
- ar & task_label_;
-
- ar & zombie_fob_;
- ar & zombie_fail_;
- ar & zombie_adopt_;
- ar & zombie_remove_;
- ar & zombie_get_;
- ar & zombie_block_;
- ar & zombie_kill_;
-
- ar & requeue_node_;
- ar & order_node_;
- ar & run_node_;
- ar & load_defs_;
- ar & replace_;
- ar & force_;
- ar & free_dep_;
- ar & suites_;
- ar & edit_script_;
-
- ar & alter_cmd_;
- ar & ch_cmd_;
- ar & file_ecf_;
- ar & file_job_;
- ar & file_jobout_;
- ar & file_cmdout_;
- ar & file_manual_;
-
- ar & plug_;
- ar & move_;
- ar & group_cmd_;
- ar & server_load_cmd_;
- ar & stats_;
- ar & check_;
- }
-};
-#endif
diff --git a/ecflow_4_0_7/Base/src/WhyCmd.cpp b/ecflow_4_0_7/Base/src/WhyCmd.cpp
deleted file mode 100644
index c06602d..0000000
--- a/ecflow_4_0_7/Base/src/WhyCmd.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Client side command only.
-// Placed in this category, since the server does not need to link
-// with it.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/foreach.hpp>
-#include "WhyCmd.hpp"
-#include "Defs.hpp"
-#include "Node.hpp"
-
-WhyCmd::WhyCmd(defs_ptr defs, const std::string& absNodePath)
-: defs_(defs)
-{
- if (!defs_.get()) {
- throw std::runtime_error("WhyCmd: The definition parameter is empty");
- }
-
- if (! absNodePath.empty() ) {
- node_ = defs_->findAbsNode(absNodePath);
- if ( ! node_.get() ) {
- std::string errorMsg = "WhyCmd: The node path parameter '";
- errorMsg += absNodePath;
- errorMsg += "' can not be found.";
- throw std::runtime_error(errorMsg);
- }
- }
-}
-
-std::string WhyCmd::why() const
-{
- std::vector<std::string> theReasonWhy;
- if (node_.get()) {
- node_->bottom_up_why(theReasonWhy);
- }
- else {
- defs_->top_down_why(theReasonWhy);
- }
-
- // Don't add /n on very last item
- std::string reason;
- for(size_t i = 0; i < theReasonWhy.size(); ++i) {
- reason += theReasonWhy[i];
- if (i != theReasonWhy.size()-1) reason += "\n";
- }
- return reason;
-}
-
diff --git a/ecflow_4_0_7/Base/src/WhyCmd.hpp b/ecflow_4_0_7/Base/src/WhyCmd.hpp
deleted file mode 100644
index 69ab13d..0000000
--- a/ecflow_4_0_7/Base/src/WhyCmd.hpp
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef WHY_CMD_HPP_
-#define WHY_CMD_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Client side command only.
-// Placed in this category, since the server does not need to link
-// with it.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <string>
-#include <boost/noncopyable.hpp>
-#include "NodeFwd.hpp"
-
-class WhyCmd : private boost::noncopyable {
-public:
- WhyCmd(defs_ptr defs, const std::string& absNodePath);
-
- /// Why the node is not running
- /// Return a '/n' separated string which lists the reasons why
- /// the provided node is not active.
- std::string why() const;
-
-private:
- defs_ptr defs_;
- node_ptr node_;
-};
-
-#endif
diff --git a/ecflow_4_0_7/Base/src/ZombieCtrl.cpp b/ecflow_4_0_7/Base/src/ZombieCtrl.cpp
deleted file mode 100644
index 0e43bfd..0000000
--- a/ecflow_4_0_7/Base/src/ZombieCtrl.cpp
+++ /dev/null
@@ -1,772 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #41 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : manages the zombies
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include "ZombieCtrl.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Submittable.hpp"
-#include "ClientToServerCmd.hpp"
-#include "AbstractServer.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost::posix_time;
-
-//#define DEBUG_ZOMBIE 1
-
-/// Zombie creation:
-/// *** ECF *** Zombies is created with: process(node path, password, pid/rid , try_no) ***
-/// *** PATH *** Zombies is created with: process(node path, password, pid/rid , try_no) ***
-/// *** USER *** Zombies is created with: TASK(node path, password, pid/rid , try_no) ***
-///
-/// There are several places where we hold path,password,pid/rid,etc
-/// Task Cmd/
-/// Node Tree Process(n) USER Zombie PATH/ECF Zombie
-/// Path same as node tree same as process
-/// password same as node tree same as process
-/// pid/rid same as node tree same as process
-/// try no same as node tree same as process
-/// ^ |
-/// | ----adopt-----------
-///
-/// Zombie Finding:
-/// For a given Task, we could have multiple zombie process, i.e. with different password/process id
-/// We can't assume that there is only one zombie process. Hence search/zombie matching
-/// should involve matching with password/process id first and then resort to path matching
-///
-/// Note: Only the init child command is required pass the process id. The other child command may
-// or may *not* provide this. In the test scenario we do.
-static bool match(const Zombie& z, const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password);
-
-
-bool ZombieCtrl::handle_path_zombie(
- AbstractServer* as,
- const TaskCmd* task_cmd, // The child command
- std::string& action_taken,
- STC_Cmd_ptr& theReply // Reply varies according to User Action
-)
-{
-#ifdef DEBUG_ZOMBIE
- std::cout << " ZombieCtrl::handle_path_zombie:";
-#endif
- const std::string& path_to_task = task_cmd->path_to_node();
- const std::string& jobs_password = task_cmd->jobs_password();
- const std::string& process_or_remote_id = task_cmd->process_or_remote_id();
-
-
- /// *** The ZombieAttr may have added/ deleted via AlterCmd. This allows for dynamic changes
- /// *no* task, find the closest Zombie attribute up the Node tree, ie attribute could be on family/suite even though task has been deleted
- /// If none found we resort to default behaviour
- node_ptr closest_matching_node = as->defs()->find_closest_matching_node(path_to_task);
-#ifdef DEBUG_ZOMBIE
- if (closest_matching_node.get()) std::cout << " closest node found: ";
-#endif
-
-
-#ifdef DEBUG_ZOMBIE
- std::cout << " Searching for match over " << zombies_.size() << " zombies :";
-#endif
- Zombie& theExistingZombie = find_zombie(path_to_task, process_or_remote_id, jobs_password );
- if(!theExistingZombie.empty() ) {
- // When NULL is passed for task, we change existing zombie to be of type PATH
- return handle_existing_zombie(theExistingZombie,NULL/*task*/,closest_matching_node,task_cmd,action_taken,theReply);
- }
-
- /// Create a zombie,
- /// *** PATH *** Zombies is created with: process path, process password, and process id/rid , process try_no ***
-#ifdef DEBUG_ZOMBIE
- std::cout << " No matching zombie fnd: Creating Path Zombie: ";
-#endif
-
- ZombieAttr attr = ZombieAttr::get_default_attr(Child::PATH);
- if (closest_matching_node.get()) {
- closest_matching_node->findParentZombie(Child::PATH, attr ); // Override default from node tree
- }
-
- Zombie new_zombie(Child::PATH,task_cmd->child_type(),attr,path_to_task,jobs_password,process_or_remote_id,task_cmd->try_no());
- zombies_.push_back( new_zombie );
-
- /// The user action may end deleting the zombie just added. Depends on ZombieAttribute settings
- return handle_user_actions(new_zombie,NULL /*task*/,task_cmd,action_taken,theReply);
-}
-
-
-bool ZombieCtrl::handle_zombie(
- Submittable* task, // This NULL for path zombies
- const TaskCmd* task_cmd, // The child command
- std::string& action_taken,
- STC_Cmd_ptr& theReply // Reply varies according to User Action
-)
-{
-#ifdef DEBUG_ZOMBIE
- std::cout << " ZombieCtrl::handle_zombie:";
-#endif
- const std::string& path_to_task = task_cmd->path_to_node();
- const std::string& jobs_password = task_cmd->jobs_password();
- const std::string& process_or_remote_id = task_cmd->process_or_remote_id();
-
- Zombie& theExistingZombie = find_zombie(path_to_task, process_or_remote_id, jobs_password );
- if(!theExistingZombie.empty() ) {
- return handle_existing_zombie(theExistingZombie,task,node_ptr(),task_cmd,action_taken,theReply);
- }
-
- /// Create Zombie:
- /// *** ECF *** Zombies is created with: process path, process password, and process id/rid , process try_no ***
- Child::ZombieType zombie_type = Child::ECF;
- ZombieAttr attr = ZombieAttr::get_default_attr( zombie_type );
-
- /// Look for any Zombie attribute up node tree, use this to construct & configure zombie
- task->findParentZombie(zombie_type, attr );
-
- /// Handle corner case ,where we have two jobs with different process id, but same password
- /// Can happen if jobs is started externally, or via test, occasionally
- ecf::Child::CmdType child_type = task_cmd->child_type();
- if (child_type == Child::INIT && task->state() == NState::ACTIVE) {
-
- /// Find zombie by path only, and remove it. Re-added again below. With updated, data<<<<
-#ifdef DEBUG_ZOMBIE
- cout << " >TASK already active:< ";
-#endif
- size_t zombieVecSize = zombies_.size();
- for(size_t i = 0 ; i < zombieVecSize; i++) {
- if (zombies_[i].path_to_task() == path_to_task) {
- zombie_type = zombies_[i].type(); // recover the original zombie type
- zombies_.erase( zombies_.begin() + i);
-#ifdef DEBUG_ZOMBIE
- cout << " Removing: ";
-#endif
- break;
- }
- }
- }
-
-
-#ifdef DEBUG_ZOMBIE
- std::cout << " Creating ECF Zombie:";
-#endif
- Zombie new_zombie(zombie_type,child_type,attr,path_to_task,jobs_password,process_or_remote_id,task_cmd->try_no());
- zombies_.push_back( new_zombie );
-
- /// Mark task as zombie for xcdp
- task->flag().set(ecf::Flag::ZOMBIE);
-
- return handle_user_actions(new_zombie,task,task_cmd,action_taken,theReply);
-}
-
-bool ZombieCtrl::handle_existing_zombie(
- Zombie& theExistingZombie, // The server already knows about the zombie
- Submittable* task, // This NULL for path zombies
- node_ptr closest_matching_node, // only defined for path zombies
- const TaskCmd* task_cmd, // The child command
- std::string& action_taken, // User action taken
- STC_Cmd_ptr& theReply // Reply varies according to User Action
-)
-{
-#ifdef DEBUG_ZOMBIE
- std::cout << " handle_existing_zombie: Updating child_type: ";
-#endif
- // If we have no task, then change the zombie type to PATH
- if (!task) {
-#ifdef DEBUG_ZOMBIE
- std::cout << " : updating zombie type to PATH: ";
-#endif
- theExistingZombie.set_type( ecf::Child::PATH );
- }
-
- /// *** The ZombieAttr may have added/ deleted via AlterCmd. This allows for dynamic changes
- ZombieAttr attr = ZombieAttr::get_default_attr(theExistingZombie.type());
- if (closest_matching_node.get()) {
-#ifdef DEBUG_ZOMBIE
- cout << " Attr found for path zombie(" << attr.toString() << "): ";
-#endif
- closest_matching_node->findParentZombie(theExistingZombie.type(), attr ); // Override default from node tree
- }
-
- if (task && task->findParentZombie(theExistingZombie.type(), attr )) { // Override default from node tree
-#ifdef DEBUG_ZOMBIE
- cout << " Attr found(" << attr.toString() << "): ";
-#endif
- }
- theExistingZombie.set_attr( attr ); // Update attribute stored on the zombie
- theExistingZombie.set_last_child_cmd( task_cmd->child_type() );// The zombie stores the last child command.
- theExistingZombie.increment_calls(); // record how times server handled with zombie
-
-
- /// Update the process id, if it is empty on the existing zombie
- /// *** NOTE**** can not update process id from task, as that could be an ID from a different JOB,
- /// ************ Hence zombie matching resorts to path and password matching
- const std::string& process_or_remote_id = task_cmd->process_or_remote_id();
- if (theExistingZombie.process_or_remote_id().empty() && !process_or_remote_id.empty()) {
-#ifdef DEBUG_ZOMBIE
- std::cout << "Updating process id(" << process_or_remote_id << "): ";
-#endif
- theExistingZombie.set_process_or_remote_id( process_or_remote_id );
- }
-
- return handle_user_actions(theExistingZombie,task,task_cmd,action_taken,theReply);
-}
-
-bool ZombieCtrl::handle_user_actions(
- Zombie& theZombie, // Existing or one we just created
- Submittable* task, // This is NULL for path zombies
- const TaskCmd* task_cmd, // The child command
- std::string& action_taken,// User action taken
- STC_Cmd_ptr& theReply // Reply varies according to User Action
-)
-{
- const std::string& path_to_task = task_cmd->path_to_node();
- const std::string& process_password = task_cmd->jobs_password();
- const std::string& process_or_remote_id = task_cmd->process_or_remote_id();
-
- if (theZombie.manual_user_action()) action_taken = "manual-";
- else action_taken = "automatic-";
-
- // *ADOPT* If zombie is set to adopt, copy over password and carry on as >NORMAL< , i.e. we return true
- if ( task && theZombie.adopt()) {
-
- action_taken += "adopt";
- /// Zombie was marked to adopt. password copied over, and zombie removed
- /// *MUST* use the password of the process, and *NOT* the zombie
- /// Since next time process communicates, it will be *WITH* the process password
- task->set_jobs_password( process_password );
- task->set_process_or_remote_id( process_or_remote_id );
-
- /// Remove the zombie, as its been adopted
- /// matching by password/process id may fail, hence remove by path
- bool remove_ok = remove(path_to_task, process_or_remote_id, process_password );
- if (!remove_ok) {
- (void) remove_by_path(path_to_task);
- }
-
- /// Clear the zombie flag
- task->flag().clear(ecf::Flag::ZOMBIE);
-
-#ifdef DEBUG_ZOMBIE
- std::cout << " >>>ADOPT<<< then remove(" << remove_ok <<") ";
- if (!remove_ok) std::cout << " >>>ERROR<<<< Remove failed ";
- std::cout << " zombies_.size(" << zombies_.size() << ")\n";
-#endif
- return true;
- }
-
- // *FOB*
- if (theZombie.fob()) {
- /// Means return as if everything is OK. hence ClientInvoker will *NOT* block, and job can continue.
- action_taken += "fob";
-
- /// On the child COMPLETE/ABORT cmd, remove the zombie:
- /// *****************************************************************************************
- /// Since we are returning false, The Task Cmd complete/abort **wont** be able to remove the zombie
- /// i.e since we want job to continue, *WITHOUT* invoking the dohandeRequest
- /// *****************************************************************************************
- if (task_cmd->child_type() == Child::COMPLETE || task_cmd->child_type() == Child::ABORT ) {
-
- bool remove_ok = remove(path_to_task, process_or_remote_id, process_password );
- if (!remove_ok) {
- (void)remove_by_path(path_to_task);
- }
-
- /// Clear the zombie flag
- if (task) task->flag().clear(ecf::Flag::ZOMBIE);
-
-#ifdef DEBUG_ZOMBIE
- std::cout << " child == COMPLETE remove zombie ";
- if (!remove_ok) std::cout << " >>>ERROR<<<< Remove failed ";
-#endif
- }
-
-#ifdef DEBUG_ZOMBIE
- std::cout << " >>>FOB<<< zombies_.size(" << zombies_.size() << ")\n";
-#endif
- theReply = PreAllocatedReply::ok_cmd();
- return false;
- }
-
- // *FAIL* Ask ClientInvoker *NOT* to block, *fail* with an error.
- if (theZombie.fail()) {
-#ifdef DEBUG_ZOMBIE
- std::cout << " >>>FAIL<<< zombies_.size(" << zombies_.size() << ")\n";
-#endif
- action_taken += "fail";
- theReply = PreAllocatedReply::error_cmd("[ authentication failed ] Request set to FAIL via zombie setting");
- return false;
- }
-
- // *KILL* Typically kill is immediate(i.e. via ZombieCmd), However this could have been set via ZombieAttribute
- if (theZombie.kill()) {
- // when a task a script is killed(i,e with kill -15), it will typically be trapped
- // This will then typically call abort. We have a choice:
- // a/ If we remove the zombie, the action taken will be lost, when the abort arises, hence default action is block
- // b/ Change the action type to be fob, so that the abort does not block
- // c/ Continue killing until process terminate. Up to use to remove zombies
- // Opted for option b/ however we do *NOT* change action type, we just fob
- if (task) {
- if (!task->flag().is_set(ecf::Flag::KILLED)) {
-
- action_taken += "kill & fob";
-
- // Kill the task, separate process, will typically send kill -15 to script.
- task->kill(theZombie.process_or_remote_id());
- }
- else {
- action_taken += "kill(already killed, fobing instead)";
- }
- }
- else {
- action_taken += "kill(no task, fobing instead)";
- }
-#ifdef DEBUG_ZOMBIE
- std::cout << " >>>KILL<<< zombies_.size(" << zombies_.size() << ")\n";
-#endif
- theReply = PreAllocatedReply::ok_cmd(); // do not block the script, fob
- return false;
- }
-
- // *REMOVE* Typically Removal is immediate(i.e. via ZombieCmd), However this could have been set via ZombieAttribute
- if (theZombie.remove()) {
- /// Ask ClientInvoker to continue blocking, Zombie may re-appear
- action_taken += "remove";
- bool remove_ok = remove(path_to_task, process_or_remote_id, process_password);
- if (!remove_ok) (void)remove_by_path(path_to_task);
-
-#ifdef DEBUG_ZOMBIE
- std::cout << " >>>REMOVE<<< zombies_.size(" << zombies_.size() << ") : BLOCKING ";
- if (!remove_ok) std::cout << " >>>ERROR<<<< Remove failed ";
-#endif
- theReply = PreAllocatedReply::block_client_zombie_cmd();
- return false;
- }
-
- // *DEFAULT*:
- // Label,event,meter : fob
- // init,complete,abort,wait: block
- if (task_cmd->child_type() == Child::LABEL ||
- task_cmd->child_type() == Child::EVENT ||
- task_cmd->child_type() == Child::METER) {
-
- /// Means return as if everything is OK. hence ClientInvoker will *NOT* block, and job can continue.
-#ifdef DEBUG_ZOMBIE
- std::cout << ": FOB\n";
-#endif
- action_taken += "fob";
- theReply = PreAllocatedReply::ok_cmd();
- return false;
- }
-
-#ifdef DEBUG_ZOMBIE
- std::cout << ": BLOCKING\n";
-#endif
- // i.e it will make several attempts , and then start contacting servers in the hosts file.
- action_taken += "block";
- theReply = PreAllocatedReply::block_client_zombie_cmd();
- return false;
-}
-
-
-void ZombieCtrl::do_add_user_zombies(const std::vector<Submittable*>& tasks)
-{
- size_t taskVecSize = tasks.size();
- for(size_t i = 0; i < taskVecSize; i++) {
- Submittable* t = tasks[i];
- if (t->state() == NState::ACTIVE || t->state() == NState::SUBMITTED) {
-
- Zombie& theExistingZombie = find( t );
- if (theExistingZombie.empty() ) {
-
-#ifdef DEBUG_ZOMBIE
- std::cout << " ZombieCtrl::do_add_user_zombies " << t->absNodePath() << " " << t->process_or_remote_id() << " " << t->jobsPassword() << "\n";
-#endif
-
- ZombieAttr attr = ZombieAttr::get_default_attr(Child::USER); // get the default USER zombie attribute
- t->findParentZombie(Child::USER, attr ); // Override default from the node tree
-
- zombies_.push_back(Zombie(Child::USER,Child::INIT,attr,t->absNodePath(),t->jobsPassword(),t->process_or_remote_id(),t->try_no()));
-
- /// Mark task as zombie for xcdp
- t->flag().set(ecf::Flag::ZOMBIE);
- }
- }
- }
-}
-
-void ZombieCtrl::add_user_zombies( node_ptr node)
-{
- if (!node.get()) return;
- std::vector<Submittable*> tasks;
- node->get_all_active_submittables(tasks);
- do_add_user_zombies(tasks);
-}
-
-void ZombieCtrl::add_user_zombies( suite_ptr suite)
-{
- if (!suite.get()) return;
- std::vector<Submittable*> tasks;
- suite->get_all_active_submittables(tasks);
- do_add_user_zombies(tasks);
-}
-
-void ZombieCtrl::add_user_zombies( defs_ptr defs)
-{
- if (!defs.get()) return;
- std::vector<Submittable*> tasks;
- defs->get_all_active_submittables(tasks);
- do_add_user_zombies(tasks);
-}
-
-/// Returns the list of zombies, **updated** with seconds since creation
-void ZombieCtrl::get( std::vector< Zombie >& ret) {
-
- boost::posix_time::ptime time_now = Calendar::second_clock_time();
-
- size_t zombieVecSize = zombies_.size(); ret.reserve(zombieVecSize);
- for(size_t i = 0 ; i < zombieVecSize; i++) {
-
- time_duration duration = time_now - zombies_[i].creation_time();
- zombies_[i].set_duration( duration.total_seconds() );
-
- ret.push_back(zombies_[i]);
- }
-}
-
-void ZombieCtrl::remove_stale_zombies( const boost::posix_time::ptime& time_now )
-{
- for(std::vector<Zombie>::iterator i = zombies_.begin(); i != zombies_.end(); ++i) {
- time_duration duration = time_now - (*i).creation_time();
- if ( duration.total_seconds() > (*i).allowed_age()) {
-#ifdef DEBUG_ZOMBIE
- std::cout << " ZombieCtrl::remove_stale_zombies " << (*i) << "\n";
-#endif
- zombies_.erase(i--);
- }
- }
-}
-
-void ZombieCtrl::fob( const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password) {
-
- Zombie& theExistingZombie = find_zombie(path_to_task, process_or_remote_id, password );
- if( theExistingZombie.empty() ) return;
- theExistingZombie.set_fob();
-}
-
-void ZombieCtrl::fobCli( const std::string& path_to_task, Submittable* task) {
-
- if (task) {
- /// Try to determine the real zombie. (not 100% precise) by comparing its password with zombie
- /// If zombie password does *NOT* match then this is the real zombie.
- size_t zombieVecSize = zombies_.size();
- for(size_t i = 0 ; i < zombieVecSize; i++) {
- if (zombies_[i].path_to_task() == path_to_task && zombies_[i].jobs_password() != task->jobsPassword()) {
- zombies_[i].set_fob();
- return;
- }
- }
- for(size_t i = 0 ; i < zombieVecSize; i++) {
- if (zombies_[i].path_to_task() == path_to_task && zombies_[i].process_or_remote_id() != task->process_or_remote_id()) {
- zombies_[i].set_fob();
- return;
- }
- }
- }
-
- /// The best we can do
- Zombie& theExistingZombie = find_by_path( path_to_task );
- if ( theExistingZombie.empty() ) return;
- theExistingZombie.set_fob();
-}
-
-void ZombieCtrl::fail(const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password) {
-
- Zombie& theExistingZombie = find_zombie(path_to_task, process_or_remote_id, password );
- if( theExistingZombie.empty() ) return;
- theExistingZombie.set_fail();
-}
-
-void ZombieCtrl::failCli( const std::string& path_to_task, Submittable* task) {
-
- if (task) {
- /// Try to determine the real zombie. (not 100% precise) by comparing its password with zombie
- /// If zombie password does *NOT* match then this is the real zombie.
- size_t zombieVecSize = zombies_.size();
- for(size_t i = 0 ; i < zombieVecSize; i++) {
- if (zombies_[i].path_to_task() == path_to_task && zombies_[i].jobs_password() != task->jobsPassword()) {
- zombies_[i].set_fail();
- return;
- }
- }
- for(size_t i = 0 ; i < zombieVecSize; i++) {
- if (zombies_[i].path_to_task() == path_to_task && zombies_[i].process_or_remote_id() != task->process_or_remote_id()) {
- zombies_[i].set_fail();
- return;
- }
- }
- }
-
- /// The best we can do
- Zombie& theExistingZombie = find_by_path( path_to_task );
- if ( theExistingZombie.empty() ) return;
- theExistingZombie.set_fail();
-}
-
-void ZombieCtrl::adopt( const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password ) {
-
- Zombie& theExistingZombie = find_zombie(path_to_task, process_or_remote_id, password );
- if ( theExistingZombie.empty() ) return;
- theExistingZombie.set_adopt();
-}
-
-void ZombieCtrl::adoptCli( const std::string& path_to_task, Submittable* task) {
-
- if (!task) {
- throw std::runtime_error("ZombieCtrl::adoptCli: Can't adopt zombie, there is no corresponding task!");
- }
-
- /// Try to determine the real zombie. (not 100% precise) by comparing its password with zombie
- /// If zombie password does *NOT* match then this is the real zombie.
- size_t zombieVecSize = zombies_.size();
- for(size_t i = 0 ; i < zombieVecSize; i++) {
- if (zombies_[i].path_to_task() == path_to_task && zombies_[i].jobs_password() != task->jobsPassword()) {
- zombies_[i].set_adopt();
- return;
- }
- }
-
- /// ***************************************************************************************
- /// IMPORTANT: We should *NEVER* adopt a zombie, when the process id are different
- /// This can end up, with two process running, Will mess up job output, as well as corruption caused
- /// but running the same job twice. Better to kill both and re-queue.
- /// Note: PBS can create two process, i.e same password, different PID's
- /// ***************************************************************************************
- for(size_t i = 0 ; i < zombieVecSize; i++) {
- if (zombies_[i].path_to_task() == path_to_task && zombies_[i].process_or_remote_id() != task->process_or_remote_id()) {
- std::stringstream ss;
- ss << "ZombieCtrl::adoptCli: Can *not* adopt zombies, where process id are different. Task("
- << task->process_or_remote_id() << ") zombie(" << zombies_[i].process_or_remote_id()
- << "). Please kill both process, and re-queue";
- throw std::runtime_error(ss.str());
- }
- }
-}
-
-void ZombieCtrl::block( const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password ) {
-
- Zombie& theExistingZombie = find_zombie(path_to_task, process_or_remote_id, password );
- if ( theExistingZombie.empty() ) return;
- theExistingZombie.set_block();
-}
-
-void ZombieCtrl::blockCli( const std::string& path_to_task, Submittable* task) {
-
- if (!task) {
- throw std::runtime_error("ZombieCtrl::blockCli: Can't block zombie, there is no corresponding task for path " + path_to_task );
- }
- else {
- /// Try to determine the real zombie. (not 100% precise) by comparing its password with zombie
- /// If zombie password does *NOT* match then this is the real zombie.
- size_t zombieVecSize = zombies_.size();
- for(size_t i = 0 ; i < zombieVecSize; i++) {
- if (zombies_[i].path_to_task() == path_to_task && zombies_[i].jobs_password() != task->jobsPassword()) {
- zombies_[i].set_block();
- return;
- }
- }
- }
-}
-
-void ZombieCtrl::kill( const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password ) {
-
- Zombie& theExistingZombie = find_zombie(path_to_task, process_or_remote_id, password );
- if ( theExistingZombie.empty() ) return;
- theExistingZombie.set_kill();
-}
-
-void ZombieCtrl::killCli( const std::string& path_to_task, Submittable* task) {
-
- if (!task) {
- throw std::runtime_error("ZombieCtrl::killCli: Can't kill zombie, there is no corresponding task for path " + path_to_task );
- }
-
- /// Try to determine the real zombie. (not 100% precise) by comparing its password with zombie
- /// If zombie password does *NOT* match then this is the real zombie.
- size_t zombieVecSize = zombies_.size();
- for(size_t i = 0 ; i < zombieVecSize; i++) {
- if (zombies_[i].path_to_task() == path_to_task && zombies_[i].jobs_password() != task->jobsPassword()) {
- task->kill(zombies_[i].process_or_remote_id());
- zombies_[i].set_kill();
- return;
- }
- }
- for(size_t i = 0 ; i < zombieVecSize; i++) {
- if ( zombies_[i].path_to_task() == path_to_task && zombies_[i].process_or_remote_id() != task->process_or_remote_id()) {
- task->kill(zombies_[i].process_or_remote_id());
- zombies_[i].set_kill();
- return ;
- }
- }
- /// The best we can do
- Zombie& theExistingZombie = find_by_path( path_to_task );
- if ( theExistingZombie.empty() ) {
- throw std::runtime_error("ZombieCtrl::killCli: Can't kill, could not locate zombie(and hence pid) for path: " + path_to_task );
- }
- task->kill(theExistingZombie.process_or_remote_id());
- theExistingZombie.set_kill();
- remove_by_path(path_to_task);
-}
-
-/// Called by the child commands, ie complete and abort
-/// Hence remove zombie with matching password/process id ?
-bool ZombieCtrl::remove( Submittable* t)
-{
- if (t) {
- return remove(t->absNodePath(), t->process_or_remote_id(), t->jobsPassword() );
- }
- return false;
-}
-
-bool ZombieCtrl::remove( const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password ) {
-
- /// Note: Its possible for two separate jobs to have the same password. (submit 1, submit 2) before job1 active, password overridden by submit 2
- /// Hence remove needs to at least match process_id
- size_t zombieVecSize = zombies_.size();
- for(size_t i = 0 ; i < zombieVecSize; i++) {
- if (match(zombies_[i],path_to_task,process_or_remote_id,password)) {
-//#ifdef DEBUG_ZOMBIE
-// std::cout << " ZombieCtrl::remove " << zombies_[i] << " \n";
-//#endif
- zombies_.erase( zombies_.begin() + i);
- return true;
- }
- }
- return false;
-}
-
-void ZombieCtrl::removeCli( const std::string& path_to_task, Submittable* task) {
-
- if (task) {
- /// Try to determine the real zombie. (not 100% precise) by comparing its password with zombie
- /// If zombie password does *NOT* match then this is the real zombie.
- size_t zombieVecSize = zombies_.size();
- for(size_t i = 0 ; i < zombieVecSize; i++) {
- if ( zombies_[i].path_to_task() == path_to_task && zombies_[i].jobs_password() != task->jobsPassword()) {
-#ifdef DEBUG_ZOMBIE
- std::cout << " ZombieCtrl::removeCli " << zombies_[i] << " \n";
-#endif
- zombies_.erase( zombies_.begin() + i);
- return ;
- }
- }
- for(size_t i = 0 ; i < zombieVecSize; i++) {
- if ( zombies_[i].path_to_task() == path_to_task && zombies_[i].process_or_remote_id() != task->process_or_remote_id()) {
-#ifdef DEBUG_ZOMBIE
- std::cout << " ZombieCtrl::removeCli " << zombies_[i] << " \n";
-#endif
- zombies_.erase( zombies_.begin() + i);
- return ;
- }
- }
- }
-
- /// The best we can do
- (void)remove_by_path(path_to_task);
-}
-
-bool ZombieCtrl::remove_by_path(const std::string& path_to_task)
-{
- size_t zombieVecSize = zombies_.size();
- for(size_t i = 0 ; i < zombieVecSize; i++) {
- if ( zombies_[i].path_to_task() == path_to_task) {
-#ifdef DEBUG_ZOMBIE
- std::cout << " ZombieCtrl::remove_by_path : " << zombies_[i] << " \n";
-#endif
- zombies_.erase( zombies_.begin() + i);
- return true;
- }
- }
- return false;
-}
-
-/// Query
-const Zombie& ZombieCtrl::find(const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password) const
-{
- size_t zombieVecSize = zombies_.size();
- for(size_t i = 0 ; i < zombieVecSize; i++) {
- if (match(zombies_[i],path_to_task,process_or_remote_id,password)) {
- return zombies_[i];
- }
- }
- return Zombie::EMPTY();
-}
-
-//================= private ===================================================================
-
-Zombie& ZombieCtrl::find(Submittable* task)
-{
- if (task) return find_zombie(task->absNodePath(),task->process_or_remote_id(),task->jobsPassword());
- return Zombie::EMPTY_();
-}
-
-const Zombie& ZombieCtrl::find(Submittable* task) const
-{
- if (task) return find(task->absNodePath(),task->process_or_remote_id(),task->jobsPassword());
- return Zombie::EMPTY();
-}
-
-Zombie& ZombieCtrl::find_zombie(const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password)
-{
- size_t zombieVecSize = zombies_.size();
- for(size_t i = 0 ; i < zombieVecSize; i++) {
- if (match(zombies_[i],path_to_task,process_or_remote_id,password)) {
- return zombies_[i];
- }
- }
- return find_by_path(path_to_task);
-}
-
-
-bool match(const Zombie& z, const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password)
-{
- /// Process/remote id only created when task becomes active.
- if (z.path_to_task() == path_to_task) {
- if (process_or_remote_id.empty() || z.process_or_remote_id().empty()) {
- if (z.jobs_password() == password) {
- return true;
- }
- }
- else if ( z.process_or_remote_id() == process_or_remote_id ) {
- return true;
- }
- }
- return false;
-}
-
-Zombie& ZombieCtrl::find_by_path(const std::string& path_to_task)
-{
- size_t zombieVecSize = zombies_.size();
- for(size_t i = 0 ; i < zombieVecSize; i++) {
- if (zombies_[i].path_to_task() == path_to_task) {
- return zombies_[i];
- }
- }
- return Zombie::EMPTY_();
-}
-
-const Zombie& ZombieCtrl::find_by_path_only(const std::string& path_to_task) const
-{
- size_t zombieVecSize = zombies_.size();
- for(size_t i = 0 ; i < zombieVecSize; i++) {
- if (zombies_[i].path_to_task() == path_to_task) {
- return zombies_[i];
- }
- }
- return Zombie::EMPTY();
-}
diff --git a/ecflow_4_0_7/Base/src/ZombieCtrl.hpp b/ecflow_4_0_7/Base/src/ZombieCtrl.hpp
deleted file mode 100644
index 0c2d73c..0000000
--- a/ecflow_4_0_7/Base/src/ZombieCtrl.hpp
+++ /dev/null
@@ -1,142 +0,0 @@
-#ifndef ZOMBIE_CTRL_HPP_
-#define ZOMBIE_CTRL_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #23 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : manages the zombies
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <string>
-#include <vector>
-#include <boost/noncopyable.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-#include "Zombie.hpp"
-#include "NodeFwd.hpp"
-#include "Cmd.hpp"
-class TaskCmd;
-class AbstractServer;
-
-/// All zombies are auto deleted after a period of time. See Zombie::allowed_age()
-class ZombieCtrl : private boost::noncopyable {
-public:
- ZombieCtrl() {}
-
- /// Handle the zombie, and return back to the client
- bool handle_zombie(
- Submittable*, // Must be NON NULL
- const TaskCmd* task_cmd, // The child command
- std::string& action_taken,// action taken
- STC_Cmd_ptr& theReply // Reply varies according to User Action
- );
-
- bool handle_path_zombie(
- AbstractServer* as, // Find closest matching node
- const TaskCmd* task_cmd, // The child command
- std::string& action_taken,// action taken
- STC_Cmd_ptr& theReply // Reply varies according to User Action
- );
-
-
- /// Find all *Tasks* beneath the input Node, that are in active or submitted states
- /// We deliberately ignore aliases (This was requested by Axel)
- /// Then add as 'USER' zombies. This should be called when commands like, delete, requeue,
- /// run, are using the force option, and will create zombies.
- void add_user_zombies(node_ptr);
- void add_user_zombies(suite_ptr);
- void add_user_zombies(defs_ptr);
-
- /// Returns the list of zombies, **updated** with seconds since creation
- /// To avoid sending attr to client, we copy over its setting, if in effect
- void get(std::vector<Zombie>&) ;
-
-
- /// remove all zombies, older than their allowed age
- void remove_stale_zombies(const boost::posix_time::ptime& time_now);
-
-
- /// Will ask the child command to terminate, *without* the child command raising any errors
- /// Since we can have many child commands(init,event,meter, label,complete) in a job
- /// This fob must stay around, since we don't know how long the job will last for.
- /// Will override, fail,recover,remove
- /// For Command Line Interface only the task_path is provided. Just have to make do.
- void fob(const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password);
- void fobCli(const std::string& path_to_task, Submittable*);
-
-
- /// Similar to a fob, But will ask the child command to terminate, with an error.
- /// Typically this will raise a trap in the job file, and hence raise an abort
- /// However the abort will also be a zombie, and will also be auto-terminated
- /// Hence the job file must be careful to use 'set -e' to avoid infinite recursion
- /// Since we can have many child commands(init,event,meter, label,complete) in a job
- /// This fob must stay around, since we don't know how long the job will last for.
- /// Will override, fob,recover,remove
- /// For Command Line Interface only the task_path is provided. Just have to make do.
- void fail( const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password);
- void failCli(const std::string& path_to_task, Submittable*);
-
-
- /// Find the task node, corresponding to the zombie, and copy over
- /// the password. Then remove the zombie. Next time the child commands
- /// communicate with the server, all will be ok
- /// Will override, fail,fob,remove
- /// For Command Line Interface only the task_path is provided. Just have to make do.
- void adopt(const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password);
- void adoptCli(const std::string& path_to_task, Submittable*);
- void block(const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password);
- void blockCli(const std::string& path_to_task, Submittable*);
- void kill(const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password);
- void killCli(const std::string& path_to_task, Submittable*);
-
-
- /// Remove the zombie corresponding to the Task path. Should only be one
- /// Since we can have many child commands(init,event,meter, label,complete) in a job
- /// the zombies may get re-added, should we rember this.
- /// If path not found does nothing.
- /// For Command Line Interface only the task_path is provided. Just have to make do.
- bool remove(Submittable*);
- bool remove(const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password);
- void removeCli(const std::string& path_to_task, Submittable*);
-
- /// Query
- const Zombie& find(const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password) const;
- const Zombie& find_by_path_only(const std::string& path_to_task) const;
-
-private:
-
- bool handle_existing_zombie(
- Zombie &, // The server already knows about the zombie
- Submittable*, // This NULL for path zombies
- node_ptr closest_matching_node, // only set for path zombies
- const TaskCmd* task_cmd, // The child command
- std::string& action_taken,// User action taken
- STC_Cmd_ptr& theReply // Reply varies according to User Action
- );
-
- bool handle_user_actions(
- Zombie &, // The server already knows about the zombie
- Submittable*, // This NULL for path zombies
- const TaskCmd* task_cmd, // The child command
- std::string& action_taken,// User action taken
- STC_Cmd_ptr& theReply // Reply varies according to User Action
- );
-
- Zombie& find_zombie(const std::string& path_to_task, const std::string& process_or_remote_id, const std::string& password);
- Zombie& find(Submittable*);
- const Zombie& find(Submittable*) const;
- void do_add_user_zombies(const std::vector<Submittable*>& tasks);
- Zombie& find_by_path(const std::string& path_to_task);
-
- bool remove_by_path(const std::string& path_to_task);
-private:
- std::vector<Zombie> zombies_;
-};
-#endif
diff --git a/ecflow_4_0_7/Base/src/cts/AlterCmd.cpp b/ecflow_4_0_7/Base/src/cts/AlterCmd.cpp
deleted file mode 100644
index 5d2386a..0000000
--- a/ecflow_4_0_7/Base/src/cts/AlterCmd.cpp
+++ /dev/null
@@ -1,977 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #62 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <boost/lexical_cast.hpp>
-
-#include "ClientToServerCmd.hpp"
-#include "AbstractServer.hpp"
-#include "AbstractClientEnv.hpp"
-#include "CtsApi.hpp"
-#include "Defs.hpp"
-#include "Task.hpp"
-#include "Str.hpp"
-#include "ExprAst.hpp"
-#include "SuiteChanged.hpp"
-#include "Log.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-namespace po = boost::program_options;
-
-static std::string dump_args(const std::vector<std::string>& options, const std::vector<std::string>& paths )
-{
- std::string the_args;
- for(size_t i = 0; i < options.size(); i++) {
- the_args += options[i];
- the_args += " ";
- }
- for(size_t i = 0; i < paths.size(); i++) {
- the_args += paths[i];
- the_args += " ";
- }
- return the_args;
-}
-
-static AlterCmd::Delete_attr_type deleteAttrType(const std::string& s)
-{
- if (s == "variable") return AlterCmd::DEL_VARIABLE;
- if (s == "time") return AlterCmd::DEL_TIME;
- if (s == "today") return AlterCmd::DEL_TODAY;
- if (s == "date") return AlterCmd::DEL_DATE;
- if (s == "day") return AlterCmd::DEL_DAY;
- if (s == "cron") return AlterCmd::DEL_CRON;
- if (s == "event") return AlterCmd::DEL_EVENT;
- if (s == "meter") return AlterCmd::DEL_METER;
- if (s == "label") return AlterCmd::DEL_LABEL;
- if (s == "trigger") return AlterCmd::DEL_TRIGGER;
- if (s == "complete") return AlterCmd::DEL_COMPLETE;
- if (s == "repeat") return AlterCmd::DEL_REPEAT;
- if (s == "limit") return AlterCmd::DEL_LIMIT;
- if (s == "limit_path") return AlterCmd::DEL_LIMIT_PATH;
- if (s == "inlimit") return AlterCmd::DEL_INLIMIT;
- if (s == "zombie") return AlterCmd::DEL_ZOMBIE;
- return AlterCmd::DELETE_ATTR_ND;
-}
-static std::string to_string(AlterCmd::Delete_attr_type d)
-{
- switch (d) {
- case AlterCmd::DEL_VARIABLE: return "variable"; break;
- case AlterCmd::DEL_TIME: return "time"; break;
- case AlterCmd::DEL_TODAY: return "today"; break;
- case AlterCmd::DEL_DATE: return "date"; break;
- case AlterCmd::DEL_DAY: return "day"; break;
- case AlterCmd::DEL_CRON: return "cron"; break;
- case AlterCmd::DEL_EVENT: return "event"; break;
- case AlterCmd::DEL_METER: return "meter"; break;
- case AlterCmd::DEL_LABEL: return "label"; break;
- case AlterCmd::DEL_TRIGGER: return "trigger"; break;
- case AlterCmd::DEL_COMPLETE: return "complete"; break;
- case AlterCmd::DEL_REPEAT: return "repeat"; break;
- case AlterCmd::DEL_LIMIT: return "limit"; break;
- case AlterCmd::DEL_LIMIT_PATH:return "limit_path"; break;
- case AlterCmd::DEL_INLIMIT: return "inlimit"; break;
- case AlterCmd::DEL_ZOMBIE: return "zombie"; break;
- case AlterCmd::DELETE_ATTR_ND: break;
- default: break;
- }
- return string();
-}
-static void validDeleteAttr(std::vector<std::string>& vec)
-{
- vec.reserve(16);
- vec.push_back("variable");
- vec.push_back("time");
- vec.push_back("today");
- vec.push_back("date");
- vec.push_back("day");
- vec.push_back("cron");
- vec.push_back("event");
- vec.push_back("meter");
- vec.push_back("label");
- vec.push_back("trigger");
- vec.push_back("complete");
- vec.push_back("repeat");
- vec.push_back("limit");
- vec.push_back("limit_path");
- vec.push_back("inlimit");
- vec.push_back("zombie");
-}
-
-
-static AlterCmd::Add_attr_type addAttrType(const std::string& s)
-{
- if (s == "time") return AlterCmd::ADD_TIME;
- if (s == "today") return AlterCmd::ADD_TODAY;
- if (s == "date") return AlterCmd::ADD_DATE;
- if (s == "day") return AlterCmd::ADD_DAY;
- if (s == "zombie") return AlterCmd::ADD_ZOMBIE;
- if (s == "variable") return AlterCmd::ADD_VARIABLE;
- return AlterCmd::ADD_ATTR_ND;
-}
-static std::string to_string(AlterCmd::Add_attr_type a) {
- switch (a) {
- case AlterCmd::ADD_TIME: return "time;"; break;
- case AlterCmd::ADD_TODAY: return "today"; break;
- case AlterCmd::ADD_DATE: return "date"; break;
- case AlterCmd::ADD_DAY: return "day"; break;
- case AlterCmd::ADD_ZOMBIE: return "zombie"; break;
- case AlterCmd::ADD_VARIABLE:return "variable"; break;
- case AlterCmd::ADD_ATTR_ND: break;
- }
- return string();
-}
-static void validAddAttr(std::vector<std::string>& vec)
-{
- vec.reserve(6);
- vec.push_back("time");
- vec.push_back("today");
- vec.push_back("date");
- vec.push_back("day");
- vec.push_back("zombie");
- vec.push_back("variable");
-}
-
-
-static AlterCmd::Change_attr_type changeAttrType(const std::string& s)
-{
- if (s == "variable") return AlterCmd::VARIABLE;
- if (s == "clock_type") return AlterCmd::CLOCK_TYPE;
- if (s == "clock_date") return AlterCmd::CLOCK_DATE;
- if (s == "clock_gain") return AlterCmd::CLOCK_GAIN;
- if (s == "clock_sync") return AlterCmd::CLOCK_SYNC;
- if (s == "event") return AlterCmd::EVENT;
- if (s == "meter") return AlterCmd::METER;
- if (s == "label") return AlterCmd::LABEL;
- if (s == "trigger") return AlterCmd::TRIGGER;
- if (s == "complete") return AlterCmd::COMPLETE;
- if (s == "repeat") return AlterCmd::REPEAT;
- if (s == "limit_max") return AlterCmd::LIMIT_MAX;
- if (s == "limit_value") return AlterCmd::LIMIT_VAL;
- if (s == "defstatus") return AlterCmd::DEFSTATUS;
- return AlterCmd::CHANGE_ATTR_ND;
-}
-static std::string to_string(AlterCmd::Change_attr_type c)
-{
- switch (c) {
- case AlterCmd::VARIABLE: return "variable"; break;
- case AlterCmd::CLOCK_TYPE: return "clock_type"; break;
- case AlterCmd::CLOCK_DATE: return "clock_date"; break;
- case AlterCmd::CLOCK_GAIN: return "clock_gain"; break;
- case AlterCmd::CLOCK_SYNC: return "clock_sync"; break;
- case AlterCmd::EVENT: return "event"; break;
- case AlterCmd::METER: return "meter"; break;
- case AlterCmd::LABEL: return "label"; break;
- case AlterCmd::TRIGGER: return "trigger"; break;
- case AlterCmd::COMPLETE: return "complete"; break;
- case AlterCmd::REPEAT: return "repeat"; break;
- case AlterCmd::LIMIT_MAX: return "limit_max"; break;
- case AlterCmd::LIMIT_VAL: return "limit_value"; break;
- case AlterCmd::DEFSTATUS: return "defstatus"; break;
- case AlterCmd::CHANGE_ATTR_ND: break;
- default: break;
- }
- return string();
-}
-static void validChangeAttr(std::vector<std::string>& vec)
-{
- vec.reserve(15);
- vec.push_back("variable");
- vec.push_back("clock_type");
- vec.push_back("clock_gain");
- vec.push_back("clock_date");
- vec.push_back("clock_sync");
- vec.push_back("event");
- vec.push_back("meter");
- vec.push_back("label");
- vec.push_back("trigger");
- vec.push_back("complete");
- vec.push_back("repeat");
- vec.push_back("limit_max");
- vec.push_back("limit_value");
- vec.push_back("defstatus");
- vec.push_back("free_password");
-}
-
-//=======================================================================================
-
-bool AlterCmd::equals(ClientToServerCmd* rhs) const
-{
- AlterCmd* the_rhs = dynamic_cast<AlterCmd*>(rhs);
- if (!the_rhs) return false;
- if ( paths_ != the_rhs->paths()) { return false; }
- if ( name_ != the_rhs->name()) { return false; }
- if ( value_ != the_rhs->value()) { return false; }
- if ( del_attr_type_ != the_rhs->delete_attr_type()) { return false; }
- if ( change_attr_type_ != the_rhs->change_attr_type()) { return false; }
- if ( add_attr_type_ != the_rhs->add_attr_type()) { return false; }
- if ( flag_type_ != the_rhs->flag_type()) { return false; }
- if ( flag_ != the_rhs->flag()) { return false; }
- return UserCmd::equals(rhs);
-}
-
-std::ostream& AlterCmd::print(std::ostream& os) const
-{
- std::string alter_type,attr_type;
- if (del_attr_type_ != AlterCmd::DELETE_ATTR_ND) {
- alter_type = "delete";
- attr_type = to_string(del_attr_type_);
- }
- else if (change_attr_type_ != AlterCmd::CHANGE_ATTR_ND) {
- alter_type = "change";
- attr_type = to_string(change_attr_type_);
- }
- else if (add_attr_type_ != AlterCmd::ADD_ATTR_ND) {
- alter_type = "add";
- attr_type = to_string(add_attr_type_);
- }
- else if (flag_type_ != Flag::NOT_SET) {
- if (flag_) alter_type = "set_flag";
- else alter_type = "clear_flag";
- attr_type = Flag::enum_to_string(flag_type_);
- }
-
- return user_cmd(os,CtsApi::to_string(CtsApi::alter(paths_,alter_type,attr_type,name_,value_)));
-}
-
-STC_Cmd_ptr AlterCmd::alter_server_state(AbstractServer* as) const
-{
- if ( del_attr_type_ == AlterCmd::DEL_VARIABLE) {
- as->defs()->set_server().delete_user_variable(name_);
- }
- else if ( change_attr_type_ == AlterCmd::VARIABLE ) {
- as->defs()->set_server().add_or_update_user_variables(name_,value_);
- }
- else if (add_attr_type_ == AlterCmd::ADD_VARIABLE) {
- as->defs()->set_server().add_or_update_user_variables(name_,value_);
- }
-
- // Update defs flag state
- if (flag_type_ != Flag::NOT_SET) {
- if (flag_) as->defs()->flag().set(flag_type_);
- else as->defs()->flag().clear(flag_type_);
- }
-
- return doJobSubmission( as );
-}
-
-
-STC_Cmd_ptr AlterCmd::doHandleRequest(AbstractServer* as) const
-{
- as->update_stats().alter_cmd_++;
-
- std::stringstream ss;
- size_t vec_size = paths_.size();
- for(size_t i= 0; i < vec_size; i++) {
-
- /// For root node user means to change server state
- if (paths_[i] == "/") {
- return alter_server_state(as);
- }
-
- node_ptr node = find_node_for_edit_no_throw(as,paths_[i]);
- if (!node.get()) {
- ss << "AlterCmd: Could not find node at path " << paths_[i] << "\n";
- LOG(Log::ERR,"AlterCmd: Failed: Could not find node at path " << paths_[i]);
- continue;
- }
-
- SuiteChanged0 changed(node);
- try {
- switch (del_attr_type_) {
- case AlterCmd::DEL_VARIABLE: node->deleteVariable(name_); break;
- case AlterCmd::DEL_TIME: node->deleteTime(name_); break;
- case AlterCmd::DEL_TODAY: node->deleteToday(name_); break;
- case AlterCmd::DEL_DATE: node->deleteDate(name_); break;
- case AlterCmd::DEL_DAY: node->deleteDay(name_);break;
- case AlterCmd::DEL_CRON: node->deleteCron(name_);break;
- case AlterCmd::DEL_EVENT: node->deleteEvent(name_);break;
- case AlterCmd::DEL_METER: node->deleteMeter(name_); break;
- case AlterCmd::DEL_LABEL: node->deleteLabel(name_); break;
- case AlterCmd::DEL_TRIGGER: node->deleteTrigger(); break;
- case AlterCmd::DEL_COMPLETE: node->deleteComplete(); break;
- case AlterCmd::DEL_REPEAT: node->deleteRepeat(); break;
- case AlterCmd::DEL_LIMIT: node->deleteLimit(name_);break;
- case AlterCmd::DEL_LIMIT_PATH:node->delete_limit_path(name_,value_);break;
- case AlterCmd::DEL_INLIMIT: node->deleteInlimit(name_); break;
- case AlterCmd::DEL_ZOMBIE: node->deleteZombie(name_); break;
- case AlterCmd::DELETE_ATTR_ND: break;
- default: break;
- }
- }
- catch ( std::exception& e) {
- ss << "Alter (delete) failed for " << paths_[i] << " : " << e.what() << "\n";
- }
-
- try {
- switch (change_attr_type_) {
- case AlterCmd::VARIABLE: node->changeVariable(name_,value_); break;
- case AlterCmd::CLOCK_TYPE: node->suite()->changeClockType(name_); break; // node must be a suite, value must [hybrid|real| virtual]
- case AlterCmd::CLOCK_DATE: node->suite()->changeClockDate(name_); break; // Expecting day.month.year: node must be a suite, value must [hybrid|real| virtual]
- case AlterCmd::CLOCK_GAIN: node->suite()->changeClockGain(name_); break; // node must be a suite, value must be int
- case AlterCmd::CLOCK_SYNC: node->suite()->changeClockSync(); break; // node must be a suite, sync clock with computer
- case AlterCmd::EVENT: node->changeEvent(name_,value_);break; // if value is empty just set, [1|0] or name [set | clear]
- case AlterCmd::METER: node->changeMeter(name_,value_); break;
- case AlterCmd::LABEL: node->changeLabel(name_,value_); break;
- case AlterCmd::TRIGGER: node->changeTrigger(name_); break; // expression must parse
- case AlterCmd::COMPLETE: node->changeComplete(name_); break; // expression must parse
- case AlterCmd::REPEAT: node->changeRepeat(name_); break; //
- case AlterCmd::LIMIT_MAX: node->changeLimitMax(name_,value_);break; // value must be convertible to int
- case AlterCmd::LIMIT_VAL: node->changeLimitValue(name_,value_); break; // value < limit max, & value must be convertible to an int
- case AlterCmd::DEFSTATUS: node->changeDefstatus(name_); break; // must be a valid state
- case AlterCmd::CHANGE_ATTR_ND: break;
- default: break;
- }
- }
- catch ( std::exception& e) {
- ss << "Alter (change) failed for " << paths_[i] << " : " << e.what() << "\n";
- }
-
- try {
- switch (add_attr_type_) {
- case AlterCmd::ADD_TIME: node->addTime( TimeSeries::create(name_ ) ); break;
- case AlterCmd::ADD_TODAY: node->addToday( TimeSeries::create(name_) ); break;
- case AlterCmd::ADD_DATE: node->addDate( DateAttr::create(name_) ); break;
- case AlterCmd::ADD_DAY: node->addDay( DayAttr::create(name_) ); break;
- case AlterCmd::ADD_ZOMBIE: node->addZombie( ZombieAttr::create(name_) ); break;
- case AlterCmd::ADD_VARIABLE:node->add_variable( name_, value_); break;
- case AlterCmd::ADD_ATTR_ND: break;
- }
- }
- catch ( std::exception& e) {
- ss << "Alter (add) failed for " << paths_[i] << ": Could not parse " << name_ << " : " << e.what() << "\n";
- }
-
- // Change flags
- if (flag_type_ != Flag::NOT_SET) {
- if (flag_) node->flag().set(flag_type_);
- else node->flag().clear(flag_type_);
- }
- }
-
- // Clear up memory allocated to path.
- // When dealing with several thousands paths, this makes a *HUGE* difference
- vector<string>().swap(paths_); // clear paths_ and minimise its capacity
-
- std::string error_msg = ss.str();
- if (!error_msg.empty()) {
- throw std::runtime_error( error_msg ) ;
- }
-
- return doJobSubmission( as );
-}
-
-const char* AlterCmd::arg() { return CtsApi::alterArg();}
-const char* AlterCmd::desc() {
- /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
- return "Alter the node according to the options.\n"
- "To add/delete/change server variables use '/' for the path.\n"
- " arg1 = [ delete | change | add | set_flag | clear_flag]\n"
- " one option must be specified\n"
- " arg2 = For delete:\n"
- " [ variable | time | today | date | day | cron | event | meter |\n"
- " label | trigger | complete | repeat | limit | inlimit | limit_path | zombie ]\n"
- " For change:\n"
- " [ variable | clock_type | clock_gain | clock_date | clock_sync | event | meter | label |\n"
- " trigger | complete | repeat | limit_max | limit_value | defstatus ]\n"
- " *NOTE* If the clock is changed, then the suite will need to be re-queued in order for\n"
- " the change to take effect fully.\n"
- " For add:\n"
- " [ variable | time | today | date | day | zombie ]\n"
- " For set_flag and clear_flag:\n"
- " [ force_aborted | user_edit | task_aborted | edit_failed |\n"
- " ecfcmd_failed | no_script | killed | migrated | late |\n"
- " message | complete | queue_limit | task_waiting | locked | zombie ]\n"
- " arg3 = name/value\n"
- " when changing, attributes like variable,meter,event,label,limits\n"
- " we expect arguments to be quoted\n"
- " arg4 = new_value\n"
- " specifies the new value only used for 'change'\n"
- " values with spaces must be quoted\n"
- " arg5 = paths : At lease one path required. The paths must start with a leading '/' character\n\n"
- ;
-}
-
-void AlterCmd::addOption(boost::program_options::options_description& desc) const {
- desc.add_options()( AlterCmd::arg(),po::value< vector<string> >()->multitoken(), AlterCmd::desc() );
-}
-void AlterCmd::create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* ac) const
-{
- vector<string> args = vm[ arg() ].as< vector<string> >();
-
- if (ac->debug()) dumpVecArgs(AlterCmd::arg(),args);
-
- std::vector<std::string> options,paths;
- split_args_to_options_and_paths(args,options,paths); // relative order is still preserved
- if (paths.empty()) {
- std::stringstream ss;
- ss << "AlterCmd: No paths specified. Paths must begin with a leading '/' character\n" << dump_args(options,paths) << "\n";
- throw std::runtime_error( ss.str() );
- }
- if (options.empty()) {
- std::stringstream ss;
- ss << "AlterCmd: Invalid argument list:\n" << dump_args(options,paths) << "\n";
- throw std::runtime_error( ss.str() );
- }
- if (options.size() < 2 ) {
- std::stringstream ss;
- ss << "Alter: At least three arguments expected. Found " << args.size() << "\n" << dump_args(options,paths) << "\n";
- throw std::runtime_error( ss.str() );
- }
-
- // arg[0] should one of [ add | delete | change | set_flag | clear_flag ]
- std::string alterType = options[0];
-
- if ( alterType == "add") {
-
- createAdd(cmd,options,paths);
- return;
- }
- else if ( alterType == "change") {
-
- createChange(cmd,options,paths);
- return;
- }
- else if ( alterType == "delete") {
-
- createDelete(cmd,options,paths);
- return;
- }
- else if ( alterType == "set_flag") {
-
- create_flag(cmd,options,paths, true /*set */);
- return;
- }
- else if ( alterType == "clear_flag") {
-
- create_flag(cmd,options,paths, false /*clear */);
- return;
- }
-
- std::stringstream ss;
- ss << "Alter: The first argument must be one of [ change | delete | add | set_flag | clear_flag ] but found '"
- << alterType << "'\n" << dump_args(options,paths) << "\n";
- throw std::runtime_error( ss.str() );
-}
-
-void AlterCmd::createAdd( Cmd_ptr& cmd, std::vector<std::string>& options, std::vector<std::string>& paths ) const
-{
- // options[0] - add
- // options[1] - [ time | date | day | zombie | variable ]
- // options[2] - [ time_string | date_string | day_string | zombie_string | variable_name ]
- // options[3] - variable_value
- std::stringstream ss;
-
- AlterCmd::Add_attr_type theAttrType = addAttrType(options[1]);
- if (theAttrType == AlterCmd::ADD_ATTR_ND) {
- ss << "AlterCmd: add: The second argument must be one of [ ";
- std::vector<std::string> valid;
- validAddAttr(valid);
- for(size_t i = 0; i < valid.size(); ++i) {
- if (i != 0) ss << " | ";
- ss << valid[i];
- }
- ss << "] but found " << options[1] << "\n" << AlterCmd::desc();
- throw std::runtime_error( ss.str() );
- }
-
- if (options.size() < 3 ) {
- ss << "AlterCmd: add: At least four arguments expected. Found " << (options.size() + paths.size()) << "\n" << dump_args(options,paths) << "\n";
- throw std::runtime_error( ss.str() );
- }
-
- // **** parse and check format, expect this argument to be single or double tick quoted ****
- // **** for time,date,day or zombie
- std::string name = options[2];
- std::string value;
- try {
- switch (theAttrType) {
- case AlterCmd::ADD_TIME: (void) TimeSeries::create(name); break;
- case AlterCmd::ADD_TODAY: (void) TimeSeries::create(name); break;
- case AlterCmd::ADD_DATE: (void) DateAttr::create(name); break;
- case AlterCmd::ADD_DAY: (void) DayAttr::create(name); break;
- case AlterCmd::ADD_ZOMBIE:(void) ZombieAttr::create(name); break;
- case AlterCmd::ADD_VARIABLE: {
- if (options.size() == 3 && paths.size() > 1) {
- // variable value may be a path, hence it will be in the paths parameter
- options.push_back(paths[0] );
- paths.erase( paths.begin() );
- }
- if (options.size() < 4 ) {
- ss << "AlterCmd: add: Expected 'add variable <name> <value> <paths>. Not enough arguments\n" << dump_args(options,paths) << "\n";
- throw std::runtime_error( ss.str() );
- }
- value = options[3];
-
- // Create a Variable to check valid names
- Variable check(name,value);
- break;
- }
- case AlterCmd::ADD_ATTR_ND:break;
- }
- }
- catch ( std::exception& e) {
- ss << "AlterCmd: add: Could not parse " << name << ". Error: " << e.what()
- << "\n for time,today and date the new value should be a quoted string "
- << "\n for add expected: --alter add variable <name> <value> <paths>\n" << dump_args(options,paths) << "\n";
- throw std::runtime_error( ss.str() );
- }
-
- cmd = Cmd_ptr( new AlterCmd(paths,theAttrType, name, value) );
-}
-
-
-void AlterCmd::createDelete( Cmd_ptr& cmd, const std::vector<std::string>& options, const std::vector<std::string>& paths) const
-{
- // options[0] = delete
- // options[1] = variable | time | today | date | day | cron | event | meter | label | trigger | complete | repeat | limit | limit_path | inlimit | zombie
- // options[2] = name ( of object to be delete ) optional
- // options[3] = limit_path (optional *ONLY* applicable for limit_path, specifies the path to be deleted
- AlterCmd::Delete_attr_type theAttrType = deleteAttrType(options[1]);
- if (theAttrType == AlterCmd::DELETE_ATTR_ND) {
- std::stringstream ss;
- ss << "Alter: delete: The second argument must be one of [ ";
- std::vector<std::string> valid;
- validDeleteAttr(valid);
- for(size_t i = 0; i < valid.size(); ++i) {
- if (i != 0) ss << " | ";
- ss << valid[i];
- }
- ss << "] but found " << options[1] << "\n" << AlterCmd::desc();
- throw std::runtime_error( ss.str() );
- }
-
- // Generally an empty third argument means delete all attributes, otherwise delete the specific one.
- std::string name;
- if (options.size() >= 3 ) name = options[2];
-
- // Deleting the limit path requires an additional arg
- std::string path_value;
-
- // if specified make sure its parses
- try {
- switch (theAttrType) {
- case AlterCmd::DEL_VARIABLE: {
- if (!name.empty()) Variable check(name,""); // Create a Variable to check valid names
- break;
- }
- case AlterCmd::DEL_TIME: {
- if (!name.empty()) (void) TimeSeries::create(name) ; // will throw if not valid
- break;
- }
- case AlterCmd::DEL_TODAY: {
- if (!name.empty()) (void) TimeSeries::create(name) ; // will throw if not valid
- break;
- }
- case AlterCmd::DEL_DATE: {
- if (!name.empty()) (void) DateAttr::create(name); // will throw if not valid
- break;
- }
- case AlterCmd::DEL_DAY: {
- if (!name.empty()) (void)DayAttr::create(name); // will throw if not valid
- break;
- }
- case AlterCmd::DEL_CRON:{
- if (!name.empty()) {
- CronAttr parsedCron = CronAttr::create(name); // will throw if not valid
-
- // additional check since parsing is very forgiving. if parsed string is same as default
- // then no cron was specified.
- CronAttr emptyCron;
- if ( emptyCron.structureEquals(parsedCron)) {
- throw std::runtime_error("Delete cron Attribute failed. Check cron " + name);
- }
- }
- break;
- }
- case AlterCmd::DEL_EVENT: {
- if (!name.empty()) {
- Event check(name); // will throw if not valid
- }
- break;
- }
- case AlterCmd::DEL_METER: {
- if (!name.empty()) Meter check(name,0,100); // will throw if not valid
- break;
- }
- case AlterCmd::DEL_LABEL: {
- if (!name.empty()) Label check(name,"value"); // will throw if not valid
- break;
- }
- case AlterCmd::DEL_TRIGGER: break; // there can only be on trigger per node, so we delete by path
- case AlterCmd::DEL_COMPLETE: break; // there can only be on complete per node, so we delete by path
- case AlterCmd::DEL_REPEAT: break; // there can only be on repeat per node, so we delete by path
- case AlterCmd::DEL_LIMIT: {
- if (!name.empty()) Limit check(name,10); // will throw if not valid
- break;
- }
- case AlterCmd::DEL_INLIMIT: {
- if (!name.empty()) InLimit check(name); // will throw if not valid
- break;
- }
- case AlterCmd::DEL_ZOMBIE: {
- if (!Child::valid_zombie_type(name)) {
- throw std::runtime_error("Delete Zombie Attribute failed. Expected one of [ ecf | path | user ] but found " + name);
- }
- break;
- }
- case AlterCmd::DEL_LIMIT_PATH: {
- if (name.empty()) {
- std::stringstream ss;
- ss << "Delete limit_path failed. No limit name provided. Expected 5 args: delete limit_path <limit_name> <path-to-limit> <path_to_node>\n";
- ss << dump_args(options,paths) << "\n";
- throw std::runtime_error(ss.str());
- }
-
- std::vector<std::string> altered_path = paths;
- if (options.size() == 4) {
- // User has provide a limit path which does not start with '/'. Go with flow
- path_value = options[3];
- }
- else {
- // Since we have a limit path(i.e begins with'/') it will appear in the paths, as the first path
- if (paths.size() <= 1) {
- std::stringstream ss;
- ss << "Delete limit_path failed: No path to limit provided. Expected 5 args: delete limit_path <limit_name> <path-to-limit> <path_to_node>\n"
- << dump_args(options,paths) << "\n";
- throw std::runtime_error(ss.str());
- }
- path_value = paths[0];
-
- // Change paths to remove the limit path.
- altered_path.erase(altered_path.begin());
- }
- cmd = Cmd_ptr( new AlterCmd(altered_path,theAttrType, name, path_value ) );
- return;
- }
- case AlterCmd::DELETE_ATTR_ND: break;
- }
- }
- catch ( std::exception& e) {
- std::stringstream ss;
- ss << "AlterCmd: delete: Could not parse " << name << ". Error: " << e.what()
- << "\n for time,today and date the new value should be a quoted string\n" << dump_args(options,paths) << "\n";
- throw std::runtime_error( ss.str() );
- }
-
- cmd = Cmd_ptr( new AlterCmd(paths,theAttrType, name, path_value ) );
-}
-
-void AlterCmd::createChange( Cmd_ptr& cmd, std::vector<std::string>& options, std::vector<std::string>& paths) const
-{
- // options[0] = change
- // options[1] = variable | clock_type | clock_gain | clock_date | clock_sync | event | meter | label | trigger | complete | repeat | limit_max | limit_value | defstatus ]
- // options[2] = name
- // options[3] = value
-
- std::stringstream ss;
-
- AlterCmd::Change_attr_type theAttrType = changeAttrType(options[1]);
- if (theAttrType == AlterCmd::CHANGE_ATTR_ND) {
- ss << "AlterCmd: change: The third argument(" << options[1] << ") must be one of [ ";
- std::vector<std::string> valid;
- validChangeAttr(valid);
- for(size_t i = 0; i < valid.size(); ++i) {
- if (i != 0) ss << " | ";
- ss << valid[i];
- }
- ss << "]\n" << AlterCmd::desc();
- throw std::runtime_error( ss.str() );
- }
-
- std::string name, value;
- switch (theAttrType) {
- case AlterCmd::VARIABLE: {
- if (options.size() == 3 && paths.size() > 1) {
- // The variable value may be a path, and hence it will be paths and not options parameter
- options.push_back(paths[0]);
- paths.erase(paths.begin()); // remove first path, since it has been added to options
- }
- if (options.size() != 4 ) {
- ss << "AlterCmd: change: expected 5 args : change variable <variable_name> <new_value> <path_to_node>";
- ss << " but found only " << (options.size() + paths.size()) << " arguments. The value should be quoted if there are spaces\n";
- ss << dump_args(options,paths) << "\n";
- throw std::runtime_error( ss.str() );
- }
- name = options[2];
- value = options[3];
- break;}
-
- case AlterCmd::CLOCK_TYPE: {
- if (options.size() != 3) {
- ss << "AlterCmd: change: expected at least four args i.e. change clock_type [ hybrid | real ] <path_to_suite>";
- ss << " but found only " << (options.size() + paths.size()) << " arguments\n"
- << dump_args(options,paths) << "\n";
- throw std::runtime_error( ss.str() );
- }
- name = options[2];
- if (name != "hybrid" && name != "real") {
- ss << "AlterCmd: change clock_type: expected third argument to be one of [ hybrid | real ]";
- ss << " but found " << name << "\n" << dump_args(options,paths) << "\n";
- throw std::runtime_error( ss.str() );
- }
- break;}
-
- case AlterCmd::CLOCK_DATE: {
- if (options.size() != 3) {
- ss << "AlterCmd: change clock_date : expected at least four args : change clock_date day.month.year <path_to_suite>";
- ss << " but found only " << (options.size() + paths.size()) << " arguments\n" << dump_args(options,paths) << "\n";
- throw std::runtime_error( ss.str() );
- }
- name = options[2];
-
- // Check date is in correct format:
- try {
- int day,month,year;
- DateAttr::getDate(name,day,month,year);
- DateAttr::checkDate(day,month,year,false /* for clocks we don't allow wild carding */);
- }
- catch ( std::exception& e) {
- ss << "AlterCmd:change clock_date " << name << " is not valid. " << e.what();
- throw std::runtime_error( ss.str() );
- }
- break;}
-
- case AlterCmd::CLOCK_GAIN: {
- if (options.size() != 3) {
- ss << "AlterCmd: change clock_gain : expected four args i.e. change clock_gain <int> <path_to_suite> ";
- ss << " but found " << (options.size() + paths.size()) << " arguments. The actual gain must be convertible to an integer\n";
- ss << dump_args(options,paths) << "\n";
- throw std::runtime_error( ss.str() );
- }
- name = options[2];
- try { boost::lexical_cast< int >( name ); }
- catch ( boost::bad_lexical_cast& ) {
- ss << "AlterCmd: " << options[0] << " " << options[1] << " " << options[2] << " " << paths[0];
- ss << " expected '" << name << "' to be convertible to an integer\n";
- ss << dump_args(options,paths) << "\n";
- throw std::runtime_error( ss.str() );
- }
- break; }
-
- case AlterCmd::CLOCK_SYNC: {
- if (options.size() != 2) {
- ss << "AlterCmd: change clock_sync : expected three args i.e. change clock_sync <path_to_suite> ";
- ss << " but found " << (options.size() + paths.size()) << " arguments.\n";
- ss << dump_args(options,paths) << "\n";
- throw std::runtime_error( ss.str() );
- }
- break; }
-
- case AlterCmd::EVENT: {
- if (options.size() != 3 && options.size() != 4) {
- ss << "AlterCmd: Change event : expected four/five args: change event <name_or_number> <[set | clear | <nothing>]> <path_to_node>";
- ss << " but found only " << (options.size() + paths.size()) << " arguments\n";
- ss << dump_args(options,paths) << "\n";
- throw std::runtime_error( ss.str() );
- }
- name = options[2];
- if ( options.size() == 4) {
- value = options[3];
- if (value != Event::SET() && value != Event::CLEAR()) {
- ss << "AlterCmd: Change event : expected four/five args: change event <name_or_number> <[set | clear | <nothing>]> <path_to_node>";
- ss << " but found only " << (options.size() + paths.size()) << " arguments\n";
- ss << dump_args(options,paths) << "\n";
- throw std::runtime_error( ss.str() );
- }
- }
- // The name could be an integer
- try { boost::lexical_cast< int >( name ); }
- catch ( boost::bad_lexical_cast& ) {
- // name is not an integer, check name is valid
- Event check_name(name); // will throw if name is not valid
- }
- break; }
-
- case AlterCmd::METER: {
- if (options.size() != 4) {
- ss << "AlterCmd: change: expected five args: change meter meter_name meter_value <path_to_node>";
- ss << " but found only " << (options.size() + paths.size()) << " arguments. The meter value must be convertible to an integer\n";
- ss << dump_args(options,paths) << "\n";
- throw std::runtime_error( ss.str() );
- }
- name = options[2];
- Meter check(name,0,100); // Check meter name , by creating a meter
-
- value = options[3];
- try { boost::lexical_cast< int >( value );}
- catch ( boost::bad_lexical_cast& ) {
- ss << "AlterCmd: " << options[0] << " " << options[1] << " " << options[2] << " " << options[3] << " " << paths[0]
- << " expected " << value << " to be convertible to an integer\n";
- throw std::runtime_error( ss.str() );
- }
-
- break; }
-
- case AlterCmd::LABEL: {
- if (options.size() != 4) {
- ss << "AlterCmd: change label expected at least five args : change label <label_name> <value> <path_to_node> ";
- ss << " but found " << (options.size() + paths.size()) << " arguments. the label value should be quoted\n";
- ss << dump_args(options,paths) << "\n";
- throw std::runtime_error( ss.str() );
- }
- name = options[2];
- value = options[3];
- Label check(name,value); // Check name , by creating
- break; }
-
- case AlterCmd::TRIGGER: {
- // ECFLOW-137, if the expression contains a leading '/' and *no* spaces,
- // then it will get treated as a path and not an option
- // i.e change trigger 'expression' <path_to_node>
- // change trigger "/suite/task:a" /path/to/a/node
- // Note boost program options will remove the quotes around the expression
- // hence its difficult to say what is an option and what is a path.
- // However since we expect 3 options, work around the problem
- if (options.size() == 2 && paths.size() == 2) {
- options.push_back(paths[0]);
- paths.erase(paths.begin()); // remove first path, since it has been added to options
- }
- if (options.size() != 3) {
- ss << "AlterCmd: change: expected four args : change trigger 'expression' <path_to_node>";
- ss << " but found " << (options.size() + paths.size()) << " arguments. The trigger expression must be quoted\n";
- ss << dump_args(options,paths) << "\n";
- throw std::runtime_error( ss.str() );
- }
- name = options[2];
-
- // Parse the expression
- PartExpression exp(name);
- string parseErrorMsg;
- std::auto_ptr<AstTop> ast = exp.parseExpressions( parseErrorMsg );
- if (!ast.get()) {
- ss << "AlterCmd: change trigger: Failed to parse expression '" << name << "'. " << parseErrorMsg << "\n";
- ss << dump_args(options,paths) << "\n";
- throw std::runtime_error( ss.str() );
- }
- break; }
-
- case AlterCmd::COMPLETE: {
- if (options.size() == 2 && paths.size() == 2) {
- options.push_back(paths[0]);
- paths.erase(paths.begin()); // remove first path, since it has been added to options
- }
- if (options.size() != 3) {
- ss << "AlterCmd: change complete: expected four args: change complete 'expression' <path_to_node> ";
- ss << " but found " << (options.size() + paths.size()) << " arguments. The expression must be quoted\n";
- ss << dump_args(options,paths) << "\n";
- throw std::runtime_error( ss.str() );
- }
- name = options[2];
-
- // Parse the expression
- PartExpression exp(name);
- string parseErrorMsg;
- std::auto_ptr<AstTop> ast = exp.parseExpressions( parseErrorMsg );
- if (!ast.get()) {
- ss << "AlterCmd: change complete: Failed to parse expression '" << name << "'. " << parseErrorMsg << "\n";
- ss << dump_args(options,paths) << "\n";
- throw std::runtime_error( ss.str() );
- }
- break;}
-
- case AlterCmd::REPEAT: {
- // *NOTE* a Node can only have *ONE* repeat, hence no need to provide name
- if (options.size() != 3) {
- ss << "AlterCmd: change repeat: expected four arg's : change repeat [ integer | string ] <path_to_node>";
- ss << " but found only " << (options.size() + paths.size()) << " arguments.\n";
- ss << dump_args(options,paths) << "\n";
- throw std::runtime_error( ss.str() );
- }
- name = options[2];
- break; }
-
- case AlterCmd::LIMIT_MAX: {
- if (options.size() != 4) {
- ss << "AlterCmd: change: limit_max: : expected five arguments : change limit_max <limit_name> <int> <path_to_node>";
- ss << " but found " << (options.size() + paths.size()) << " arguments.\n";
- ss << dump_args(options,paths) << "\n";
- throw std::runtime_error( ss.str() );
- }
- name = options[2];
- value = options[3];
- int limit = 0;
- try { limit = boost::lexical_cast< int >( value );}
- catch ( boost::bad_lexical_cast& ) {
- ss << "AlterCmd: change: limit-max: " << options[0] << " " << options[1] << " " << options[2] << " " << options[3] << " " << paths[0]
- << " expected " << value << " to be convertible to an integer\n";
- throw std::runtime_error( ss.str() );
- }
- Limit check(name,limit); // Check name , by creating
- break; }
-
- case AlterCmd::LIMIT_VAL: {
- if (options.size() != 4) {
- ss << "AlterCmd: change: limit-value: expected five arguments : change limit_value <limit_name> <int> <path_to_node>";
- ss << " but found " << (options.size() + paths.size()) << " arguments.\n";
- ss << dump_args(options,paths) << "\n";
- throw std::runtime_error( ss.str() );
- }
- name = options[2];
- value = options[3];
- try { boost::lexical_cast< int >( value );}
- catch ( boost::bad_lexical_cast& ) {
- ss << "AlterCmd: change: limit_value: " << options[0] << " " << options[1] << " " << options[2] << " " << options[3] << " " << paths[0]
- << " expected " << value << " to be convertible to an integer\n";
- ss << dump_args(options,paths) << "\n";
- throw std::runtime_error( ss.str() );
- }
- Limit check(name,10); // Check name, by creating
- break;}
-
- case AlterCmd::DEFSTATUS: {
- if (options.size() != 3) {
- ss << "AlterCmd: change defstatus expected four args : change defstatus [ queued | complete | unknown | aborted | suspended ] <path_to_node>";
- ss << " but found " << (options.size() + paths.size()) << " arguments.\n";
- ss << dump_args(options,paths) << "\n";
- throw std::runtime_error( ss.str() );
- }
- name = options[2];
- if (!DState::isValid(name)) {
- ss << "AlterCmd: " << options[0] << " " << options[1] << " " << options[2] << " " << paths[0]
- << "an expected " << name << " to be a valid state, i.e one of [ queued | complete | unknown | aborted | suspended ]\n";
- throw std::runtime_error( ss.str() );
- }
- break; }
-
- case AlterCmd::CHANGE_ATTR_ND: break;
- default: break;
- }
-
- cmd = Cmd_ptr( new AlterCmd(paths,theAttrType, name, value ) );
-}
-
-void AlterCmd::create_flag( Cmd_ptr& cmd, const std::vector<std::string>& options, const std::vector<std::string>& paths, bool flag) const
-{
- // options[0] = set_flag | clear_flag
- // options[1] = [ force_aborted | user_edit | task_aborted | edit_failed | ecfcmd_failed | no_script | killed | migrated | late | message | complete | queue_limit | task_waiting | locked | zombie ]
-
- Flag::Type theFlagType = Flag::string_to_flag_type(options[1]);
- if (theFlagType == Flag::NOT_SET) {
- std::stringstream ss;
- ss << "AlterCmd: set/clear_flag: The second argument(" << options[1] << ") must be one of [ ";
- std::vector<std::string> valid;
- Flag::valid_flag_type(valid);
- for(size_t i = 0; i < valid.size(); ++i) { if (i != 0) ss << " | "; ss << valid[i]; }
- ss << "]\n" << AlterCmd::desc();
- throw std::runtime_error( ss.str() );
- }
-
- cmd = Cmd_ptr( new AlterCmd(paths,theFlagType, flag ) );
-}
-
-std::ostream& operator<<(std::ostream& os, const AlterCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/cts/BeginCmd.cpp b/ecflow_4_0_7/Base/src/cts/BeginCmd.cpp
deleted file mode 100644
index 313a0f1..0000000
--- a/ecflow_4_0_7/Base/src/cts/BeginCmd.cpp
+++ /dev/null
@@ -1,177 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #23 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include "ClientToServerCmd.hpp"
-#include "AbstractServer.hpp"
-#include "CtsApi.hpp"
-#include "AbstractClientEnv.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Str.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-namespace po = boost::program_options;
-
-
-BeginCmd::BeginCmd(const std::string& suiteName, bool force)
-: suiteName_(suiteName), force_(force)
-{
- // The begin command actually requires the suite name without the lead '/'
- // i.e if we provide /suite --> change to suite
- if (!suiteName_.empty() && suiteName_[0] == '/') {
- suiteName_.erase(0,1); // delete first character
- }
-}
-
-std::ostream& BeginCmd::print(std::ostream& os) const
-{
- return user_cmd(os,CtsApi::begin(suiteName_,force_));
-}
-
-bool BeginCmd::equals(ClientToServerCmd* rhs) const
-{
- BeginCmd* the_rhs = dynamic_cast< BeginCmd* > ( rhs );
- if ( !the_rhs ) return false;
- if (suiteName_ != the_rhs->suiteName()) return false;
- if (force_ != the_rhs->force()) return false;
- return UserCmd::equals(rhs);
-}
-
-STC_Cmd_ptr BeginCmd::doHandleRequest(AbstractServer* as) const
-{
- as->update_stats().begin_cmd_++;
- defs_ptr defs = as->defs();
-
- // If no suite name begin all suites, else begin the the specific suite
- if ( suiteName_.empty()) {
-
- const std::vector<suite_ptr>& suiteVec = defs->suiteVec();
- size_t theSuiteVecSize = suiteVec.size();
- if (!force_) {
- for(size_t s = 0; s < theSuiteVecSize; s++) {
- /// check_suite_can_begin will throw if suite can't begin
- defs->check_suite_can_begin(suiteVec[s]);
- }
- }
- else {
- for(size_t s = 0; s < theSuiteVecSize; s++) {
- as->zombie_ctrl().add_user_zombies(suiteVec[s]);
- }
-
- // Force should *only* be used for test
- defs->reset_begin();
- }
-
- defs->beginAll();
- }
- else {
-
- suite_ptr suite = defs->findSuite(suiteName_);
- if (!suite.get()) {
- std::stringstream ss;
- ss << "BeginCmd::doHandleRequest: Begin failed as suite '" << suiteName_ << "' is not loaded.\n";
- throw std::runtime_error( ss.str() );
- }
-
- /// check_suite_can_begin will throw if suite can't begin
- if (!force_) defs->check_suite_can_begin(suite);
- else {
- as->zombie_ctrl().add_user_zombies(suite);
-
- // Force should *only* be used for test
- suite->reset_begin();
- }
-
-
- defs->beginSuite(suite);
- }
-
- // After begin do the first Job submission. This will kick of those
- // jobs that have no dependencies, or relative time of +00:00
- return doJobSubmission(as);
-}
-
-const char* BeginCmd::arg() { return CtsApi::beginArg();}
-const char* BeginCmd::desc() {
- /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
- return
- "Begin playing the definition in the server.\n"
- "Expects zero or a single quoted string.\n"
- " arg1 = suite-name | Nothing | force\n"
- " play the chosen suite, if no arg specified, play all suites, in the definition\n"
- " force means reset the begin status on the suites and bypass checks.\n"
- " This is only required if suite-name is provide as the first argument\n"
- " Using force can cause the creation of zombies\n"
- "Usage:\n"
- "--begin # will begin all suites\n"
- "--begin=\"--force\" # reset and then begin all suites, bypassing any checks. Note: string must be quoted\n"
- "--begin=\"mySuite\" # begin playing suite of name 'mySuite'\n"
- "--begin=\"mySuite --force\" # reset and begin playing suite 'mySuite', bypass check"
- ;
-}
-
-void BeginCmd::addOption(boost::program_options::options_description& desc) const
-{
- // allow options like
- // client --begin=suitename // begin <suitename>
- // client --begin // means begin all suites
- desc.add_options()( BeginCmd::arg(),po::value< string >()->implicit_value( string("") ), BeginCmd::desc() );
-}
-void BeginCmd::create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* ace ) const
-{
- std::string beginArg = vm[ arg() ].as< std::string > ();
-
- if (ace->debug()) {
- cout << " BeginCmd::create arg = " << beginArg << "\n";
- }
-
- std::string suiteName;
- bool force = false;
-
- if (!beginArg.empty()) {
- std::vector< std::string > lineTokens;
- Str::split(beginArg,lineTokens);
- if (lineTokens.size() == 1) {
- if (lineTokens[0] == "--force") force = true;
- else suiteName = lineTokens[0];
- }
- else if (lineTokens.size() == 2) {
- suiteName = lineTokens[0];
- if (lineTokens[1] != "--force") {
- std::stringstream ss;
- ss << "BeginCmd: Expected second argument to be '--force' but found " << lineTokens[1] << "\n";
- throw std::runtime_error( ss.str() );
- }
- force = true;
- }
- else {
- std::stringstream ss;
- ss << "BeginCmd: Expect zero, one or 2 arguments, but found " << lineTokens.size() << " arguments\n" << BeginCmd::desc() << "\n";
- throw std::runtime_error( ss.str() );
- }
- }
-
- if (ace->debug()) {
- std::cout << " BeginCmd::create suiteName = " << suiteName << "\n";
- std::cout << " BeginCmd::create force = " << force << "\n";
- }
-
- cmd = Cmd_ptr(new BeginCmd( suiteName, force ));
-}
-
-std::ostream& operator<<(std::ostream& os, const BeginCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/cts/CFileCmd.cpp b/ecflow_4_0_7/Base/src/cts/CFileCmd.cpp
deleted file mode 100644
index 9596021..0000000
--- a/ecflow_4_0_7/Base/src/cts/CFileCmd.cpp
+++ /dev/null
@@ -1,309 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #42 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <sstream>
-#include "boost/filesystem/operations.hpp"
-#include <boost/lexical_cast.hpp>
-
-#include "ClientToServerCmd.hpp"
-#include "AbstractServer.hpp"
-#include "AbstractClientEnv.hpp"
-#include "File.hpp"
-#include "CtsApi.hpp"
-#include "Defs.hpp"
-#include "Task.hpp"
-#include "EcfFile.hpp"
-#include "Str.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-namespace po = boost::program_options;
-namespace fs = boost::filesystem;
-
-CFileCmd::CFileCmd(const std::string& pathToNode, const std::string& file_type, const std::string& input_max_lines)
-: file_(ECF), pathToNode_(pathToNode), max_lines_(File::MAX_LINES())
-{
- // std::cout << "CFileCmd::CFileCmd the_max_lines " << the_max_lines << "\n";
-
- if (file_type == "script") file_ = CFileCmd::ECF;
- else if (file_type == "job") file_ = CFileCmd::JOB;
- else if (file_type == "jobout") file_ = CFileCmd::JOBOUT;
- else if (file_type == "manual") file_ = CFileCmd::MANUAL;
- else if (file_type == "kill") file_ = CFileCmd::KILL;
- else if (file_type == "stat") file_ = CFileCmd::STAT;
- else {
- std::stringstream ss;
- ss << "CFileCmd::CFileCmd: Unrecognised file type " << file_type << " expected one of [script | job | jobout | manual | kill | stat] \n";
- throw std::runtime_error( ss.str() );
- }
-
- if (!input_max_lines.empty()){
- try {
- // Note: max_lines_ if type size_t, hence we cast to int to check for negative numbers
- int the_max_lines = boost::lexical_cast<int>( input_max_lines );
- if (the_max_lines <= 0) the_max_lines = File::MAX_LINES();
- max_lines_ = the_max_lines;
- }
- catch ( boost::bad_lexical_cast& e) {
- std::stringstream ss;
- ss << "CFileCmd::CFileCmd: The third argument(" << input_max_lines << ") must be convertible to an integer\n";
- throw std::runtime_error(ss.str());
- }
- }
-}
-
-
-std::vector<CFileCmd::File_t> CFileCmd::fileTypesVec()
-{
- std::vector<CFileCmd::File_t> vec; vec.reserve(5);
- vec.push_back(CFileCmd::ECF);
- vec.push_back(CFileCmd::JOB);
- vec.push_back(CFileCmd::JOBOUT);
- vec.push_back(CFileCmd::MANUAL);
- vec.push_back(CFileCmd::KILL);
- vec.push_back(CFileCmd::STAT);
- return vec;
-}
-
-std::string CFileCmd::toString(CFileCmd::File_t ft)
-{
- switch (ft) {
- case CFileCmd::ECF: return "script"; break;
- case CFileCmd::MANUAL: return "manual"; break;
- case CFileCmd::JOB: return "job"; break;
- case CFileCmd::JOBOUT: return "jobout"; break;
- case CFileCmd::KILL: return "kill"; break;
- case CFileCmd::STAT: return "stat"; break;
- default : break;
- }
- return "script";
-}
-
-bool CFileCmd::equals(ClientToServerCmd* rhs) const
-{
- CFileCmd* the_rhs = dynamic_cast<CFileCmd*>(rhs);
- if (!the_rhs) return false;
- if ( file_ != the_rhs->fileType()) { return false; }
- if ( max_lines_ != the_rhs->max_lines()) { return false; }
- if ( pathToNode_ != the_rhs->pathToNode()) { return false; }
- return UserCmd::equals(rhs);
-}
-
-std::ostream& CFileCmd::print(std::ostream& os) const
-{
- return user_cmd(os,CtsApi::to_string(CtsApi::file(pathToNode_,toString(file_),boost::lexical_cast<std::string>(max_lines_))));
-}
-
-STC_Cmd_ptr CFileCmd::doHandleRequest(AbstractServer* as) const
-{
- // cout << "CFileCmd::doHandleRequest " << toString(file_) << " =======================================\n";
- switch (file_) {
- case CFileCmd::ECF: as->update_stats().file_ecf_++; break;
- case CFileCmd::MANUAL: as->update_stats().file_manual_++; break;
- case CFileCmd::JOB: as->update_stats().file_job_++; break;
- case CFileCmd::JOBOUT: as->update_stats().file_jobout_++; break;
- case CFileCmd::KILL: as->update_stats().file_cmdout_++; break;
- case CFileCmd::STAT: as->update_stats().file_cmdout_++; break;
- }
-
- node_ptr node = find_node(as,pathToNode_); // will throw if defs not defined, or node not found
-
- std::string fileContents;
- Submittable* submittable = node->isSubmittable();
- if ( submittable ) {
-
- switch (file_) {
- case CFileCmd::ECF: {
- EcfFile ecf_file = submittable->locatedEcfFile(); // will throw std::runtime_error for errors
- ecf_file.script(fileContents); // will throw std::runtime_error for errors
- break;}
-
- case CFileCmd::MANUAL: {
- EcfFile ecf_file = submittable->locatedEcfFile(); // will throw std::runtime_error for errors
- ecf_file.manual(fileContents); // will throw std::runtime_error for errors
- break;}
-
- case CFileCmd::JOB: {
- std::string ecf_job_file;
- submittable->findParentVariableValue(Str::ECF_JOB(), ecf_job_file);
- if (!File::open(ecf_job_file,fileContents)) {
- std::stringstream ss;
- ss << "CFileCmd::doHandleRequest: Failed to open the job file('" << ecf_job_file << "') for task " << pathToNode_;
- throw std::runtime_error( ss.str() ) ;
- }
- break;}
-
- case CFileCmd::JOBOUT: {
-
- // ECF_JOBOUT is either constructed from ECF_OUT *OR* ECF_HOME/ECF_NAME.ECF_TRYNO
- // See: Submittable.cpp: SubGenVariables::update_generated_variables()
- //
- // Typically if ECF_OUT is specified, we should only look at that location
- // however SMS also looked at the alternate location (and RD relied on this ECFLOW-177 )
-
- const Variable& ecf_jobout_gen_var = submittable->findGenVariable(Str::ECF_JOBOUT());
- if (!File::open(ecf_jobout_gen_var.theValue(),fileContents)) {
-
- // If that fails as a backup, look under ECF_HOME/ECF_NAME.ECF_TRYNO, ECFLOW-177 preserve old SMS behaviour
- std::string backup_jobout;
- submittable->findParentUserVariableValue(Str::ECF_HOME(), backup_jobout);
- backup_jobout += submittable->absNodePath();
- backup_jobout += ".";
- backup_jobout += submittable->tryNo();
-
- if ( backup_jobout != ecf_jobout_gen_var.theValue()) {
- // Implies ECF_OUT was specified, hence *ALSO* look in ECF_HOME/ECF_NAME.ECF_TRYNO
- if (!File::open(backup_jobout,fileContents)) {
- std::stringstream ss;
- ss << "CFileCmd::doHandleRequest: Failed to open the job-out(ECF_JOBOUT=ECF_OUT/ECF_NAME.ECF_TRYNO) file('"
- << ecf_jobout_gen_var.theValue() << "') *AND* at location (ECF_JOBOUT=ECF_HOME/ECF_NAME.ECF_TRYNO)('"
- << backup_jobout << "') for task " << pathToNode_;
- throw std::runtime_error( ss.str() ) ;
- }
- }
- else {
- // ECF_OUT *not* specified implies ECF_JOBOUT = ECF_HOME/ECF_NAME.ECF_TRYNO
- std::stringstream ss;
- ss << "CFileCmd::doHandleRequest: Failed to open the job-out(ECF_JOBOUT=ECF_HOME/ECF_NAME.ECF_TRYNO) file('"
- << ecf_jobout_gen_var.theValue() << "') for task " << pathToNode_;
- throw std::runtime_error( ss.str() ) ;
- }
- }
-
- break; }
-
- case CFileCmd::KILL: {
- std::string ecf_job_file;
- submittable->findParentVariableValue(Str::ECF_JOB(), ecf_job_file);
- std::string file = ecf_job_file + ".kill";
- if (!File::open(file,fileContents)) {
- std::stringstream ss;
- ss << "CFileCmd::doHandleRequest: Failed to open the kill output file('" << file << "') for task " << pathToNode_;
- throw std::runtime_error( ss.str() ) ;
- }
- break; }
-
- case CFileCmd::STAT: {
- std::string ecf_job_file;
- submittable->findParentVariableValue(Str::ECF_JOB(), ecf_job_file);
- std::string file = ecf_job_file + ".stat";
- if (!File::open(file,fileContents)) {
- std::stringstream ss;
- ss << "CFileCmd::doHandleRequest: Failed to open the status output file('" << file << "') for task " << pathToNode_;
- throw std::runtime_error( ss.str() ) ;
- }
- break; }
-
- default : assert(false); break;
- }
- }
- else {
-
- if (file_ == CFileCmd::MANUAL) {
- // The only valid option for Suite or Family is Manual
-
- // First look for .man files in ECF_FILES and then ECF_HOME
- std::string ecf_files;
- node->findParentUserVariableValue( Str::ECF_FILES(), ecf_files);
- if ( !ecf_files.empty() && fs::exists( ecf_files ) && fs::is_directory( ecf_files ) ) {
-
- std::string manFile = File::backwardSearch( ecf_files, node->absNodePath(), File::MAN_EXTN());
- if (!manFile.empty()) {
- EcfFile the_file(node.get(), manFile);
- the_file.manual(fileContents); // pre-process & extract manual: will throw std::runtime_error for errors
- }
- }
-
- if ( fileContents.empty() ) {
- // Try under ECF_HOME
- std::string ecf_home;
- node->findParentUserVariableValue( Str::ECF_HOME(), ecf_home);
- if ( !ecf_home.empty() && fs::exists( ecf_home ) && fs::is_directory( ecf_home ) ) {
-
- std::string manFile = File::backwardSearch( ecf_home, node->absNodePath(), File::MAN_EXTN());
- EcfFile the_file(node.get(), manFile);
- the_file.manual(fileContents); // pre-process & extract manual: will throw std::runtime_error for errors
- }
- else {
- std::string errorMsg = "Failed to find the manual for Suite/Family "; errorMsg += pathToNode_;
- errorMsg += " ECF_HOME directory does not exist and/or ECF_FILES not defined or directory does not exist.";
- throw std::runtime_error( errorMsg ) ;
- }
- }
- }
- else {
- std::stringstream ss; ss << "Option " << CFileCmd::toString(file_) << " is only valid for tasks. ";
- throw std::runtime_error( ss.str() ) ;
- }
- }
-
- /// The file could get very large, hence truncate at the start
- if (Str::truncate_at_start(fileContents, max_lines_)) {
- std::stringstream ss;
- ss << "\n# >>>>>>>> File truncated down to " << max_lines_ << ". Truncated from the start <<<<<<<<<\n";
- fileContents += ss.str();
- }
-
- return PreAllocatedReply::string_cmd(fileContents);
-}
-
-const char* CFileCmd::arg() { return CtsApi::fileArg();}
-const char* CFileCmd::desc() {
- /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
- return "Return the chosen file. Select from [ script<default> | job | jobout | manual | kill | stat ]\n"
- "By default will return the script.\n"
- " arg1 = path to node\n"
- " arg2 = (optional) [ script<default> | job | jobout | manual | kill | stat ]\n"
- " kill will attempt to return output of ECF_KILL_CMD, i.e the file %ECF_JOB%.kill\n"
- " stat will attempt to return output of ECF_STATUS_CMD, i.e the file %ECF_JOB%.stat\n"
- " arg3 = (optional) max_lines = 10000 <default>"
- ;
-}
-
-void CFileCmd::addOption(boost::program_options::options_description& desc) const {
- desc.add_options()( CFileCmd::arg(),po::value< vector<string> >()->multitoken(), CFileCmd::desc() );
-}
-void CFileCmd::create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* ac) const
-{
- vector<string> args = vm[ arg() ].as< vector<string> >();
-
- if (ac->debug()) dumpVecArgs(CFileCmd::arg(),args);
-
- if (args.size() < 1 ) {
- std::stringstream ss;
- ss << "CFileCmd: At least one arguments expected for File. Found " << args.size() << "\n" << CFileCmd::desc() << "\n";
- throw std::runtime_error( ss.str() );
- }
-
- std::string pathToNode = args[0];
-
- std::string file_type = "script";
- if (args.size() >= 2) {
- file_type = args[1];
- }
-
- std::string max_lines;
- if (args.size() == 3) {
- max_lines = args[2];
- }
-
- cmd = Cmd_ptr( new CFileCmd(pathToNode, file_type, max_lines) );
-}
-
-std::ostream& operator<<(std::ostream& os, const CFileCmd& c) { return c.print(os); }
-
diff --git a/ecflow_4_0_7/Base/src/cts/CSyncCmd.cpp b/ecflow_4_0_7/Base/src/cts/CSyncCmd.cpp
deleted file mode 100644
index 2112d4f..0000000
--- a/ecflow_4_0_7/Base/src/cts/CSyncCmd.cpp
+++ /dev/null
@@ -1,156 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #22 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include "ClientToServerCmd.hpp"
-#include "AbstractServer.hpp"
-#include "AbstractClientEnv.hpp"
-#include "CtsApi.hpp"
-#include "Defs.hpp"
-#include "Log.hpp"
-#include "Ecf.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-namespace po = boost::program_options;
-
-std::ostream& CSyncCmd::print(std::ostream& os) const
-{
- /// Note: Be careful how the *debug* output is interpreted, since the:
- /// client_handle_ > 0 state/modify numbers will be for a set of registered suites,
- /// client_handle_ == 0 state/modify numbers is global i.e. for all suites.
- std::stringstream ss;
- if (api_ == CSyncCmd::NEWS) {
- ss << CtsApi::to_string(CtsApi::news(client_handle_,client_state_change_no_,client_modify_change_no_));
- return user_cmd(os,ss.str());
- }
-
- if (api_ == CSyncCmd::SYNC) {
- ss << CtsApi::to_string(CtsApi::sync(client_handle_,client_state_change_no_,client_modify_change_no_));
- return user_cmd(os,ss.str());
- }
-
- ss << CtsApi::sync_full(client_handle_);
- return user_cmd(os,ss.str());
-}
-
-bool CSyncCmd::equals(ClientToServerCmd* rhs) const
-{
- CSyncCmd* the_rhs = dynamic_cast< CSyncCmd* > ( rhs );
- if ( !the_rhs ) return false;
- if (api_ != the_rhs->api()) return false;
- if (client_handle_ != the_rhs->client_handle()) return false;
- if (client_state_change_no_ != the_rhs->client_state_change_no()) return false;
- if (client_modify_change_no_ != the_rhs->client_modify_change_no()) return false;
- return UserCmd::equals(rhs);
-}
-
-const char* CSyncCmd::theArg() const
-{
- if (api_ == CSyncCmd::NEWS) return CtsApi::newsArg();
- if (api_ == CSyncCmd::SYNC) return CtsApi::syncArg();
- return CtsApi::sync_full_arg();
-}
-
-int CSyncCmd::timeout() const
-{
- if (api_ == CSyncCmd::SYNC || api_ == CSyncCmd::SYNC_FULL) {
- return time_out_for_load_sync_and_get();
- }
- return 20; // CSyncCmd::NEWS
-}
-
-void CSyncCmd::do_log() const
-{
- if (api_ == CSyncCmd::NEWS) {
-
- /// Log without adding a new line, to the log file
- /// The SNewsCmd will append additional debug and then add new line
- std::stringstream ss;
- print(ss); // Populate the stream with command details:
- log_no_newline(Log::MSG,ss.str()); // log command without adding newline
- return;
- }
-
- ClientToServerCmd::do_log();
-}
-
-STC_Cmd_ptr CSyncCmd::doHandleRequest(AbstractServer* as) const
-{
- // If no defs not loaded, SSyncCmd and SNewsCmd do nothing. This is a valid state, hence don't error for this request
- if (api_ == CSyncCmd::NEWS) {
- as->update_stats().news_++;
- return PreAllocatedReply::news_cmd(client_handle_, client_state_change_no_, client_modify_change_no_,as);
- }
- if (api_ == CSyncCmd::SYNC) {
- as->update_stats().sync_++;
- return PreAllocatedReply::sync_cmd(client_handle_, client_state_change_no_, client_modify_change_no_,as);
- }
- as->update_stats().sync_++;
- return PreAllocatedReply::sync_full_cmd(client_handle_,as);
-}
-
-void CSyncCmd::addOption(boost::program_options::options_description& desc) const
-{
- if (api_ == CSyncCmd::NEWS) {
- desc.add_options()(CtsApi::newsArg(),po::value< vector<unsigned int> >()->multitoken(),
- "Returns true if state of server definition changed.\n"
- "*Important* for use with c++/python interface only.\n"
- "Requires Given a client handle, change and modify number determine if server changed since last call\n"
- "This relies on user calling sync after news to update the locally stored modify and change numbers.\n"
- "These numbers are then used in the next call to news."
- );
- return;
- }
-
- if (api_ == CSyncCmd::SYNC) {
- desc.add_options()(CtsApi::syncArg(),po::value< vector<unsigned int> >()->multitoken(),
- "Incrementally synchronise the local definition with the one in the server.\n"
- "*Important* for use with c++/python interface only.\n"
- "Preference should be given to this method as only the changes are returned.\n"
- "This reduces the network bandwidth required to keep in sync with the server\n"
- "Requires a client handle, change and modify number, to get the incremental changes from server.\n"
- "The change in server state is then and merged with the client definition."
- );
- return;
- }
-
- desc.add_options()(CtsApi::sync_full_arg(),po::value< unsigned int >(),
- "Returns the full definition from the server.\n"
- "*Important* for use with c++/python interface only.\n"
- "Requires a client_handle. The returned definition is stored on the client."
- );
-}
-
-void CSyncCmd::create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* ac ) const
-{
- if (ac->debug()) cout << "CSyncCmd::create api = '" << api_ << "'.\n";
-
- if (api_ == CSyncCmd::NEWS || api_ == CSyncCmd::SYNC){
- vector<unsigned int> args = vm[ theArg() ].as< vector<unsigned int> >();
- if (args.size() != 3) throw std::runtime_error("CSyncCmd::create(SYNC/NEWS) expects 3 integer arguments, Client handle, state change number, and modify change number");
- unsigned int client_handle = args[0];
- unsigned int state_change_no = args[1];
- unsigned int modify_change_no = args[2];
- cmd = Cmd_ptr(new CSyncCmd( api_,client_handle,state_change_no,modify_change_no));
- return;
- }
-
- unsigned int client_handle = vm[ theArg() ].as< unsigned int >();
- cmd = Cmd_ptr(new CSyncCmd(client_handle)); // FULL_SYNC
-}
-
-std::ostream& operator<<(std::ostream& os, const CSyncCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/cts/CheckPtCmd.cpp b/ecflow_4_0_7/Base/src/cts/CheckPtCmd.cpp
deleted file mode 100644
index 9050681..0000000
--- a/ecflow_4_0_7/Base/src/cts/CheckPtCmd.cpp
+++ /dev/null
@@ -1,202 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/lexical_cast.hpp>
-
-#include "ClientToServerCmd.hpp"
-#include "AbstractServer.hpp"
-#include "AbstractClientEnv.hpp"
-#include "CtsApi.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-namespace po = boost::program_options;
-
-std::ostream& CheckPtCmd::print(std::ostream& os) const
-{
- return user_cmd(os,CtsApi::checkPtDefs(mode_,check_pt_interval_,check_pt_save_time_alarm_));
-}
-
-bool CheckPtCmd::equals(ClientToServerCmd* rhs) const
-{
- CheckPtCmd* the_rhs = dynamic_cast< CheckPtCmd* > ( rhs );
- if ( !the_rhs ) return false;
- if (mode_ != the_rhs->mode()) return false;
- if (check_pt_interval_ != the_rhs->check_pt_interval()) return false;
- if (check_pt_save_time_alarm_ != the_rhs->check_pt_save_time_alarm()) return false;
- return UserCmd::equals(rhs);
-}
-
-bool CheckPtCmd::isWrite() const
-{
- if (mode_ != ecf::CheckPt::UNDEFINED) return true;
- if (check_pt_interval_ != 0) return true;
- if (check_pt_save_time_alarm_ != 0) return true;
- return false;
-}
-
-const char* CheckPtCmd::theArg() const
-{
- return CtsApi::checkPtDefsArg();
-}
-
-STC_Cmd_ptr CheckPtCmd::doHandleRequest(AbstractServer* as) const
-{
- // Placed here rather than in server. Since we want to record explicit request to check pt
- // The update_stats() is used to record the number of requests per second, hence we do not
- // want to skew this, and hence we ignore implicit request's via signal handling,
- // or when server terminates( does implicit check pt also)
- as->update_stats().checkpt_++;
- as->checkPtDefs(mode_,check_pt_interval_,check_pt_save_time_alarm_);
- return PreAllocatedReply::ok_cmd();
-}
-
-static const char* arg_desc()
-{
- /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
- return
- "Forces the definition file in the server to be written to disk *or* allow mode,\n"
- "interval and alarm to be changed.\n"
- "Whenever the check pt file is written to disk, it is measured.\n"
- "If the time to save to disk is greater than the default of 30 seconds,\n"
- "then an alarm is raised. This can be seen in the GUI as a late flag on the server.\n"
- "Once the late flag has been set it will need to manually cleared in the GUI\n"
- "or by using --alter functionality\n"
- "Note excessive save times can interfere with job scheduling.\n"
- "The alarm threshold can be changed. See below.\n"
- " arg1 = (optional) mode [ never | on_time | on_time:<integer> | always | <integer>]\n"
- " never : Never check point the definition in the server\n"
- " on_time : Turn on automatic check pointing at interval stored on server\n"
- " on_time<integer> : Turn on automatic check point, with the specified interval in seconds\n"
- " alarm<integer> : Modify the alarm notification time for check pt saving to disk\n"
- " always : Check point at any change in node tree, *NOT* recommended for large definitions\n"
- " <integer> : This specifies the interval in seconds when server should automatically check pt.\n"
- " This will only take effect of mode is on_time/CHECK_ON_TIME\n"
- " Should ideally be a value greater than 60 seconds, default is 120 seconds\n"
- "Usage:\n"
- " --check_pt\n"
- " Immediately check point the definition held in the server\n"
- " --check_pt never\n"
- " Switch off check pointing\n"
- " --check_pt on_time\n"
- " Start automatic check pointing at the interval stored in the server\n"
- " --check_pt 180\n"
- " Change the check pt interval to 180 seconds\n"
- " --check_pt on_time:90\n"
- " Change mode and interval, to automatic check pointing every 90 seconds\n"
- " --check_pt alarm:35\n"
- " Change the alarm time for check pt saves. i.e if saving the check pt takes longer than 35 seconds\n"
- " set the late flag on the server."
- ;
-}
-
-void CheckPtCmd::addOption(boost::program_options::options_description& desc) const
-{
- desc.add_options()(CtsApi::checkPtDefsArg(),po::value< string >()->implicit_value( string("") ),arg_desc());
-}
-
-static int parse_check_pt_interval( const std::string& the_arg)
-{
- int check_pt_interval = 0;
- try { check_pt_interval = boost::lexical_cast<int>(the_arg); }
- catch (...) {
- std::stringstream ss;
- ss << "check_pt: Illegal argument(" << the_arg << "), expected [ never | on_time | on_time:<integer> | always | <integer>]\n" << arg_desc();
- throw std::runtime_error(ss.str());
- }
- if (check_pt_interval <= 0) {
- std::stringstream ss;
- ss << "check_pt: interval(" << check_pt_interval << ") must be greater than zero :\n" << arg_desc();
- throw std::runtime_error(ss.str());
- }
- return check_pt_interval;
-}
-
-static int parse_check_pt_alarm_time( const std::string& the_arg, int colon_pos)
-{
- std::string alarm_time = the_arg.substr(colon_pos+1);
-
- int check_pt_alarm_time = 0;
- try { check_pt_alarm_time = boost::lexical_cast<int>(alarm_time); }
- catch (...) {
- std::stringstream ss;
- ss << "check_pt: Illegal argument(" << the_arg << "), expected [ never | on_time | on_time:<integer> | alarm::integer> | always | <integer>]\n" << arg_desc();
- throw std::runtime_error(ss.str());
- }
- if (check_pt_alarm_time <= 0) {
- std::stringstream ss;
- ss << "check_pt: alarm time(" << check_pt_alarm_time << ") must be greater than zero :\n" << arg_desc();
- throw std::runtime_error(ss.str());
- }
- return check_pt_alarm_time;
-}
-
-
-void CheckPtCmd::create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* ace ) const
-{
- if (ace->debug()) cout << "CheckPtCmd::create\n";
-
- std::string the_arg = vm[ theArg() ].as< std::string > ();
-
- if (ace->debug()) cout << " CheckPtCmd::create arg = " << the_arg << "\n";
-
- ecf::CheckPt::Mode m = ecf::CheckPt::UNDEFINED;
- int check_pt_interval = 0;
- int check_pt_save_time_alarm = 0;
-
- if (!the_arg.empty()) {
- size_t colon_pos = the_arg.find(":");
- if (colon_pos != std::string::npos) {
- // could be mode:interval or alarm:integer
- if (the_arg.find("alarm") != std::string::npos) {
- check_pt_save_time_alarm = parse_check_pt_alarm_time(the_arg,colon_pos);
- }
- else {
- std::string mode = the_arg.substr(0,colon_pos);
- std::string interval = the_arg.substr(colon_pos+1);
-
- if (mode == "never") m = ecf::CheckPt::NEVER;
- else if (mode == "on_time") m = ecf::CheckPt::ON_TIME;
- else if (mode == "always") m = ecf::CheckPt::ALWAYS;
- else {
- std::stringstream ss;
- ss << "check_pt: Illegal argument(" << the_arg << "), expected [ never | on_time | on_time:<integer> | alarm:<integer> | always | <integer>]\n" << arg_desc();
- throw std::runtime_error(ss.str());
- }
- check_pt_interval = parse_check_pt_interval(interval);
- }
- }
- else {
- if (the_arg == "never") m = ecf::CheckPt::NEVER;
- else if (the_arg == "on_time") m = ecf::CheckPt::ON_TIME;
- else if (the_arg == "always") m = ecf::CheckPt::ALWAYS;
- else {
- check_pt_interval = parse_check_pt_interval(the_arg);
- }
- }
- }
-
- // testing client interface
- if (ace->under_test()) return;
-
- if (ace->debug()) cout << " CheckPtCmd::create mode = " << m << " check_pt_interval = " << check_pt_interval << "\n";
-
- cmd = Cmd_ptr(new CheckPtCmd(m,check_pt_interval,check_pt_save_time_alarm));
-}
-
-std::ostream& operator<<(std::ostream& os, const CheckPtCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/cts/ClientHandleCmd.cpp b/ecflow_4_0_7/Base/src/cts/ClientHandleCmd.cpp
deleted file mode 100644
index 1603f06..0000000
--- a/ecflow_4_0_7/Base/src/cts/ClientHandleCmd.cpp
+++ /dev/null
@@ -1,336 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #31 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/lexical_cast.hpp>
-
-#include "ClientToServerCmd.hpp"
-#include "AbstractServer.hpp"
-#include "AbstractClientEnv.hpp"
-#include "CtsApi.hpp"
-#include "Defs.hpp"
-#include "Log.hpp"
-#include "Ecf.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-namespace po = boost::program_options;
-
-/// *****************************************************************************
-/// Note: The Client Handle commands, change the server,
-/// However the changes cant really be considered as incremental
-/// Hence for all handle command, we will do a FULL SYNC
-/// Relying on the modify_change_no is to CRUDE, as it affects all handles
-/// Instead we will use a simple flag to indicate that a FULL sync is required
-/// *****************************************************************************
-
-std::ostream& ClientHandleCmd::print(std::ostream& os) const
-{
- switch (api_) {
- case ClientHandleCmd::REGISTER: return user_cmd(os,CtsApi::to_string(CtsApi::ch_register(auto_add_new_suites_,suites_))); break;
- case ClientHandleCmd::DROP: return user_cmd(os,CtsApi::ch_drop(client_handle_)); break;
- case ClientHandleCmd::DROP_USER:{
- if (drop_user_.empty()) return user_cmd(os,CtsApi::ch_drop_user(user()));
- return user_cmd(os,CtsApi::ch_drop_user(drop_user_));
- break;
- }
- case ClientHandleCmd::ADD: return user_cmd(os,CtsApi::to_string(CtsApi::ch_add(client_handle_,suites_))); break;
- case ClientHandleCmd::REMOVE: return user_cmd(os,CtsApi::to_string(CtsApi::ch_remove(client_handle_,suites_))); break;
- case ClientHandleCmd::AUTO_ADD: return user_cmd(os,CtsApi::to_string(CtsApi::ch_auto_add(client_handle_,auto_add_new_suites_))); break;
- case ClientHandleCmd::SUITES: return user_cmd(os,CtsApi::ch_suites()); break;
- default: assert(false); break;
- }
- return os;
-}
-
-bool ClientHandleCmd::equals(ClientToServerCmd* rhs) const
-{
- ClientHandleCmd* the_rhs = dynamic_cast< ClientHandleCmd* > ( rhs );
- if ( !the_rhs ) return false;
- if (api_ != the_rhs->api()) return false;
- if (drop_user_ != the_rhs->drop_user()) return false;
- return UserCmd::equals(rhs);
-}
-
-const char* ClientHandleCmd::theArg() const
-{
- switch (api_) {
- case ClientHandleCmd::REGISTER: return CtsApi::ch_register_arg(); break;
- case ClientHandleCmd::DROP: return CtsApi::ch_drop_arg(); break;
- case ClientHandleCmd::DROP_USER: return CtsApi::ch_drop_user_arg(); break;
- case ClientHandleCmd::ADD: return CtsApi::ch_add_arg(); break;
- case ClientHandleCmd::REMOVE: return CtsApi::ch_remove_arg(); break;
- case ClientHandleCmd::AUTO_ADD: return CtsApi::ch_auto_add_arg(); break;
- case ClientHandleCmd::SUITES: return CtsApi::ch_suites_arg(); break;
- }
- assert(false);
- return NULL;
-}
-
-bool ClientHandleCmd::isWrite() const {
- if (api_ == ClientHandleCmd::SUITES) return false;
- return true;
-}
-
-STC_Cmd_ptr ClientHandleCmd::doHandleRequest(AbstractServer* as) const
-{
- as->update_stats().ch_cmd_++;
-
- switch (api_) {
- case ClientHandleCmd::REGISTER: {
-
- unsigned int client_handle = as->defs()->client_suite_mgr().create_client_suite(auto_add_new_suites_,suites_,user());
-//#ifdef DEBUG
-// LOG(Log::DBG,as->defs()->client_suite_mgr().dump_max_change_no());
-//#endif
- // return the handle to the client
- return PreAllocatedReply::client_handle_cmd(client_handle) ;
- }
-
- case ClientHandleCmd::DROP: {
- as->defs()->client_suite_mgr().remove_client_suite(client_handle_); // will throw if handle not found
-
- // return the 0 handle to the client. The client stores the handle locally. Reset to zero.
- return PreAllocatedReply::client_handle_cmd(0) ;
- }
-
- case ClientHandleCmd::DROP_USER: {
- // will throw if no users handles dropped
- if (drop_user_.empty()) as->defs()->client_suite_mgr().remove_client_suites(user());
- else as->defs()->client_suite_mgr().remove_client_suites(drop_user_);
-
- if (drop_user_.empty() || drop_user_ == user()) {
- // return the 0 handle to the client. The client stores the handle locally. Reset to zero.
- return PreAllocatedReply::client_handle_cmd(0) ;
- }
- break;
- }
-
- case ClientHandleCmd::ADD: {
- as->defs()->client_suite_mgr().add_suites(client_handle_,suites_); // will throw if handle not found
- break;
- }
-
- case ClientHandleCmd::REMOVE: {
- as->defs()->client_suite_mgr().remove_suites(client_handle_,suites_); // will throw if handle not found
- break;
- }
-
- case ClientHandleCmd::AUTO_ADD: {
- as->defs()->client_suite_mgr().auto_add_new_suites(client_handle_,auto_add_new_suites_); // will throw if handle not found
- break;
- }
-
- case ClientHandleCmd::SUITES: {
- return PreAllocatedReply::client_handle_suites_cmd(as) ;
- break;
- }
-
- default: assert(false); break;
-
- }
- return PreAllocatedReply::ok_cmd();
-}
-
-void ClientHandleCmd::addOption(boost::program_options::options_description& desc) const
-{
- switch (api_) {
- case ClientHandleCmd::REGISTER:{
- desc.add_options()(CtsApi::ch_register_arg(), po::value< vector<string> >()->multitoken(),
- "Register interest in a set of suites.\n"
- "If a definition has lots of suites, but the client. is only interested in a small subset,\n"
- "Then using this command can reduce network bandwidth and synchronisation will be quicker.\n"
- "This command will create a client handle, which must be used for any other changes.\n"
- "The newly created handle can be shown with the --suites command\n"
- "Deleted suites will stay registered, and must be explicitly removed/dropped.\n"
- "Note: Suites can be registered before they are loaded into the server\n"
- "This option affects news() and sync() commands\n"
- " arg1 = true | false # true means add new suites to my list, when they are created\n"
- " arg2 = names # should be a list of suite names, names not in the definition are ignored\n"
- "Usage:\n"
- " --ch_register=true s1 s2 s3 # register interest in suites s1,s2,s3 and any new suites\n"
- " --ch_register=false s1 s2 s3 # register interest in suites s1,s2,s3 only\n"
- " --ch_register=false # register handle, suites will be added later on\n"
- "To list all suites and handles use --suites"
- );
- break;
- }
-
- case ClientHandleCmd::DROP:{
- desc.add_options()(CtsApi::ch_drop_arg(), po::value< int >(),
- "Drop/de-register the client handle.\n"
- "Un-used handle should be dropped otherwise they will stay, in the server.\n"
- " arg1 = handle(integer) # The handle must be an integer that is > 0\n"
- "Usage:\n"
- " --ch_drop=10 # drop the client handle 10\n"
- "An error is returned if the handle had not previously been registered\n"
- "The handle stored on the local client is set to zero\n"
- "To list all suites and handles use --suites"
- );
- break;
- }
-
- case ClientHandleCmd::DROP_USER:{
- desc.add_options()(CtsApi::ch_drop_user_arg(), po::value<std::string >()->implicit_value( string("")),
- "Drop/de-register all handles associated with the given user.\n"
- "If no user provided will drop for current user. Client must ensure un-used handle are dropped\n"
- "otherwise they will stay, in the server.\n"
- " arg1 = user # The user to be drooped, if left empty drop current user \n"
- "Usage:\n"
- " --ch_drop_user=ma0 # drop all handles associated with user ma0\n"
- " --ch_drop_user # drop all handles associated with current user\n"
- "An error is returned if no registered handles\n"
- "To list all suites and handles use --suites"
- );
- break;
- }
-
- case ClientHandleCmd::ADD:{
- desc.add_options()( CtsApi::ch_add_arg(), po::value< vector<string> >()->multitoken(),
- "Add a set of suites, to an existing handle.\n"
- " arg1 = handle(integer) # The handle must be an integer that is > 0\n"
- " arg2 = names # should be a list of suite names, names not in the definition are ignored\n"
- "Usage:\n"
- " --ch_add=10 s2 s3 s4 # add suites s2 s3,s4 to handle 10\n"
- "An error is returned if the handle had not previously been registered\n"
- "The handle is created with --ch_register command\n"
- "To list all suites and handles use --suites"
- );
- break;
- }
-
- case ClientHandleCmd::REMOVE:{
- desc.add_options()( CtsApi::ch_remove_arg(), po::value< vector<string> >()->multitoken(),
- "Remove a set of suites, from an existing handle.\n"
- " arg1 = handle(integer) # The handle must be an integer that is > 0\n"
- " arg2 = names # should be a list of suite names, names not in the definition are ignored\n"
- "Usage:\n"
- " --ch_rem=10 s2 s3 s4 # remove suites s2 s3,s4 from handle 10\n"
- "The handle is created with --ch_register command\n"
- "To list all suites and handles use --suites"
- );
- break;
- }
-
- case ClientHandleCmd::AUTO_ADD: {
- desc.add_options()( CtsApi::ch_auto_add_arg(), po::value< vector<string> >()->multitoken(),
- "Change an existing handle so that new suites can be added automatically.\n"
- " arg1 = handle(integer) # The handle must be an integer that is > 0\n"
- " arg2 = true | false # true means add new suites to my list, when they are created\n"
- "Usage:\n"
- " --ch_auto_add=10 true # modify handle 10 so that new suites, get added automatically to it\n"
- " --ch_auto_add=10 false # modify handle 10 so that no new suites are added\n"
- "The handle is created with --ch_register command\n"
- "To list all suites and handles use --suites"
- );
- break;
- }
-
- case ClientHandleCmd::SUITES:{
- desc.add_options()(CtsApi::ch_suites_arg(),
- "Shows all the client handles, and the suites they reference"
- );
- break;
- }
- default: assert(false); break;
- }
-}
-
-void ClientHandleCmd::create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* ac ) const
-{
- if (ac->debug()) cout << "ClientHandleCmd::create api = '" << api_ << "'.\n";
-
- switch (api_) {
-
- case ClientHandleCmd::REGISTER: {
- vector<string> args = vm[ theArg() ].as< vector<string> >();
- // args can be empty, otherwise first arg must be bool, true or false, subsequent args represent suite names
- bool auto_add_new_suites = false;
- std::vector<std::string> suite_names; suite_names.reserve( args.size() );
- if (!args.empty()) {
- if (args[0] == "true") auto_add_new_suites = true;
- else if (args[0] == "false") auto_add_new_suites = false;
- else throw std::runtime_error("ClientHandleCmd::create: First argument should be true | false. See help");
- for(size_t i = 1; i < args.size(); i++) { suite_names.push_back( args[i] ); }
- }
- cmd = Cmd_ptr(new ClientHandleCmd( suite_names, auto_add_new_suites ));
- break;
- }
-
- case ClientHandleCmd::DROP: {
- int client_handle = vm[ theArg() ].as< int >();
- if ( 0 == client_handle) throw std::runtime_error("ClientHandleCmd::create: handles must have a value > 0");
- cmd = Cmd_ptr(new ClientHandleCmd( client_handle ));
- break;
- }
-
- case ClientHandleCmd::DROP_USER: {
- std::string the_user_to_drop = vm[ theArg() ].as< std::string >();
- cmd = Cmd_ptr(new ClientHandleCmd( the_user_to_drop ));
- break;
- }
-
- case ClientHandleCmd::ADD: {
- vector<string> args = vm[ theArg() ].as< vector<string> >();
- if (args.size() < 2) throw std::runtime_error("To few arguments. First arg should be a integer handle, then a list of suite names. See help");
- int client_handle = 0;
- try { client_handle = boost::lexical_cast<int>( args[0]); }
- catch (std::exception& ) { throw std::runtime_error("The first argument must be an integer. See help"); }
- if (0 == client_handle) throw std::runtime_error("ClientHandleCmd::create: handles must have a value > 0");
- std::vector<std::string> suite_names; suite_names.reserve( args.size() );
- for(size_t i = 1; i < args.size(); i++) { suite_names.push_back( args[i] ); }
- cmd = Cmd_ptr(new ClientHandleCmd(client_handle, suite_names, ClientHandleCmd::ADD ));
- break;
- }
-
- case ClientHandleCmd::REMOVE: {
- vector<string> args = vm[ theArg() ].as< vector<string> >();
- if (args.size() < 2) throw std::runtime_error("To few arguments. First arg should be a integer handle, then a list of suite names. See help");
- int client_handle = 0;
- try { client_handle = boost::lexical_cast<int>( args[0]); }
- catch (std::exception& ) { throw std::runtime_error("ClientHandleCmd::create: The first argument must be an integer. See help"); }
- if ( 0 == client_handle ) throw std::runtime_error("ClientHandleCmd::create: handles must have a value > 0");
- std::vector<std::string> suite_names; suite_names.reserve( args.size() );
- for(size_t i = 1; i < args.size(); i++) { suite_names.push_back( args[i] ); }
- cmd = Cmd_ptr(new ClientHandleCmd(client_handle, suite_names, ClientHandleCmd::REMOVE ));
- break;
- }
-
- case ClientHandleCmd::AUTO_ADD: {
- vector<string> args = vm[ theArg() ].as< vector<string> >();
- if (args.size() != 2) throw std::runtime_error("Two argument expected. First arg should be a integer handle, second should be true or false. See help");
- int client_handle = 0;
- try { client_handle = boost::lexical_cast<int>( args[0]); }
- catch (std::exception& ) { throw std::runtime_error("ClientHandleCmd::create: The first argument must be an integer. See help"); }
- if ( 0 == client_handle ) throw std::runtime_error("ClientHandleCmd::create: handles must have a value > 0");
- bool auto_add_new_suites = false;
- if (args[1] == "true") auto_add_new_suites = true;
- else if (args[1] == "false") auto_add_new_suites = false;
- else throw std::runtime_error("ClientHandleCmd::create: First argument should be true | false. See help");
- cmd = Cmd_ptr(new ClientHandleCmd(client_handle, auto_add_new_suites ));
- break;
- }
-
- case ClientHandleCmd::SUITES: {
- cmd = Cmd_ptr(new ClientHandleCmd( ClientHandleCmd::SUITES ));
- break;
- }
-
- default: assert(false); break;
- }
-}
-
-std::ostream& operator<<(std::ostream& os, const ClientHandleCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/cts/ClientToServerCmd.cpp b/ecflow_4_0_7/Base/src/cts/ClientToServerCmd.cpp
deleted file mode 100644
index a436142..0000000
--- a/ecflow_4_0_7/Base/src/cts/ClientToServerCmd.cpp
+++ /dev/null
@@ -1,194 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #67 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <iostream>
-#include <sstream>
-
-#include "ClientToServerCmd.hpp"
-#include "ServerToClientCmd.hpp"
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "Alias.hpp"
-
-#include "JobsParam.hpp"
-#include "Jobs.hpp"
-#include "AbstractServer.hpp"
-#include "Log.hpp"
-#include "Str.hpp"
-#include "CmdContext.hpp"
-#include "EditHistoryMgr.hpp"
-
-using namespace std;
-using namespace boost;
-using namespace ecf;
-
-//#define DEBUG_INVARIANTS 1
-
-ClientToServerCmd::~ClientToServerCmd(){}
-
-STC_Cmd_ptr ClientToServerCmd::handleRequest(AbstractServer* as) const
-{
- // Allow creating of new time stamp, when *not* in a command. i.e during node tree traversal in server
- CmdContext cmdContext;
-
- // Create the log time stamp once for a given request
- if (Log::instance()) Log::instance()->cache_time_stamp();
-
- // LOG the command, *BEFORE* invoking it. (i.e in case server hangs/crashes)
- // Allow override in the rare cases, where we want to output additional debug
- do_log();
-
-#ifdef DEBUG_INVARIANTS
- LOG_ASSERT( as->defs() , "ClientToServerCmd::handleRequest: Start: No defs? ");
- std::string errmsg;
- if (!as->defs()->checkInvariants(errmsg)) {
- LOG(Log::ERR,"ClientToServerCmd::handleRequest: PreCondition: Failed invariant checking:" << errmsg);
- }
-#endif
-
-
- STC_Cmd_ptr halted;
- if (! authenticate(as,halted)) {
- assert (halted.get());
- return halted;
- }
-
- // mark edited nodes, with edit history
- EditHistoryMgr edit_history_mgr(this,as);
-
- // Handle the request, and return the reply back to the client
- STC_Cmd_ptr server_to_client_ptr = doHandleRequest(as);
- if ( isWrite() && server_to_client_ptr->ok()) {
-
- // This can end up, check pointing the defs file
- as->nodeTreeStateChanged();
- }
-
-#ifdef DEBUG_INVARIANTS
- LOG_ASSERT( as->defs() , "ClientToServerCmd::handleRequest: End: No defs? ");
- std::string errmsg;
- if (!as->defs()->checkInvariants(errmsg)) {
- LOG(Log::ERR,"ClientToServerCmd::handleRequest: PostCondition: Failed invariant checking:" << errmsg);
- }
-#endif
-
- return server_to_client_ptr;
-}
-
-void ClientToServerCmd::do_log() const
-{
- std::stringstream ss;
- print(ss); // Populate the stream with command details:
- log(Log::MSG,ss.str()); // will automatically add end of line
-}
-
-STC_Cmd_ptr ClientToServerCmd::doJobSubmission(AbstractServer* as)
-{
- // This function could be called at the end of *USER* command that can change state.
- //
- // We could have other tasks/jobs dependent on the state change. i.e end of time series
- // This will traverse the node tree and resolve dependencies and may force
- // Other jobs to be generated, due to the state change.
- // However *** errors in job submission ***, should *NOT* typically abort the command.
- // Since we will typically just set task to aborted state
-
- // This job generation will timeout if job generation takes longer than next poll time.
- as->traverse_node_tree_and_job_generate(Calendar::second_clock_time(), true /* user cmd context */);
-
- return PreAllocatedReply::ok_cmd();
-}
-
-node_ptr ClientToServerCmd::find_node(AbstractServer* as, const std::string& absNodepath) const
-{
- node_ptr theNode = as->defs()->findAbsNode(absNodepath);
- if ( !theNode.get() ) {
-
- std::stringstream ss;
- print(ss);
-
- std::string errorMsg = "Can not find node at path '";
- errorMsg += absNodepath;
- errorMsg += "' ";
- errorMsg += ss.str();
- errorMsg += " failed";
- throw std::runtime_error( errorMsg) ;
- }
- return theNode;
-}
-
-
-void ClientToServerCmd::dumpVecArgs(const char* argOption, const std::vector<std::string>& args) {
- cout << argOption;
- for(size_t i= 0; i < args.size(); i++) { cout << " args[" << i << "]='" << args[i] << "'";} cout << "\n";
-}
-
-node_ptr ClientToServerCmd::find_node_for_edit(AbstractServer* as, const std::string& absNodepath) const
-{
- node_ptr theNode = find_node(as, absNodepath);
- add_node_for_edit_history(theNode);
- return theNode;
-}
-
-node_ptr ClientToServerCmd::find_node_for_edit_no_throw(AbstractServer* as, const std::string& absNodepath) const
-{
- node_ptr theNode = as->defs()->findAbsNode(absNodepath);
- add_node_for_edit_history(theNode);
- return theNode;
-}
-
-void ClientToServerCmd::add_node_for_edit_history(AbstractServer* as,const std::string& absNodepath) const
-{
- add_node_for_edit_history(as->defs()->findAbsNode(absNodepath));
-}
-
-void ClientToServerCmd::add_node_for_edit_history(node_ptr the_node) const
-{
- if (the_node.get()) edit_history_nodes_.push_back(the_node);
-}
-
-BOOST_CLASS_EXPORT_IMPLEMENT(ServerVersionCmd)
-BOOST_CLASS_EXPORT_IMPLEMENT(CtsCmd)
-BOOST_CLASS_EXPORT_IMPLEMENT(CSyncCmd)
-BOOST_CLASS_EXPORT_IMPLEMENT(ClientHandleCmd)
-BOOST_CLASS_EXPORT_IMPLEMENT(CtsNodeCmd)
-BOOST_CLASS_EXPORT_IMPLEMENT(PathsCmd)
-BOOST_CLASS_EXPORT_IMPLEMENT(CheckPtCmd)
-BOOST_CLASS_EXPORT_IMPLEMENT(LoadDefsCmd)
-BOOST_CLASS_EXPORT_IMPLEMENT(LogCmd)
-BOOST_CLASS_EXPORT_IMPLEMENT(LogMessageCmd)
-BOOST_CLASS_EXPORT_IMPLEMENT(BeginCmd)
-BOOST_CLASS_EXPORT_IMPLEMENT(ZombieCmd)
-BOOST_CLASS_EXPORT_IMPLEMENT(InitCmd)
-BOOST_CLASS_EXPORT_IMPLEMENT(EventCmd)
-BOOST_CLASS_EXPORT_IMPLEMENT(MeterCmd)
-BOOST_CLASS_EXPORT_IMPLEMENT(LabelCmd)
-BOOST_CLASS_EXPORT_IMPLEMENT(AbortCmd)
-BOOST_CLASS_EXPORT_IMPLEMENT(CtsWaitCmd)
-BOOST_CLASS_EXPORT_IMPLEMENT(CompleteCmd)
-BOOST_CLASS_EXPORT_IMPLEMENT(RequeueNodeCmd)
-BOOST_CLASS_EXPORT_IMPLEMENT(OrderNodeCmd)
-BOOST_CLASS_EXPORT_IMPLEMENT(RunNodeCmd)
-BOOST_CLASS_EXPORT_IMPLEMENT(ReplaceNodeCmd)
-BOOST_CLASS_EXPORT_IMPLEMENT(ForceCmd)
-BOOST_CLASS_EXPORT_IMPLEMENT(FreeDepCmd)
-BOOST_CLASS_EXPORT_IMPLEMENT(CFileCmd)
-BOOST_CLASS_EXPORT_IMPLEMENT(EditScriptCmd)
-BOOST_CLASS_EXPORT_IMPLEMENT(PlugCmd)
-BOOST_CLASS_EXPORT_IMPLEMENT(AlterCmd)
-BOOST_CLASS_EXPORT_IMPLEMENT(MoveCmd)
-BOOST_CLASS_EXPORT_IMPLEMENT(GroupCTSCmd)
-BOOST_CLASS_EXPORT_IMPLEMENT(ShowCmd)
diff --git a/ecflow_4_0_7/Base/src/cts/ClientToServerCmd.hpp b/ecflow_4_0_7/Base/src/cts/ClientToServerCmd.hpp
deleted file mode 100644
index 5cbb820..0000000
--- a/ecflow_4_0_7/Base/src/cts/ClientToServerCmd.hpp
+++ /dev/null
@@ -1,1828 +0,0 @@
-#ifndef CLIENT_TO_SERVER_CMD_HPP_
-#define CLIENT_TO_SERVER_CMD_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name : Cmd
-// Author : Avi
-// Revision : $Revision: #143 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <string>
-#include <vector>
-
-#include <boost/program_options.hpp>
-#include <boost/serialization/base_object.hpp> // base class serialization
-#include <boost/serialization/serialization.hpp>
-#include <boost/serialization/assume_abstract.hpp>
-#include <boost/serialization/shared_ptr.hpp>
-#include <boost/serialization/export.hpp> // explicit code for exports (place last) , needed for BOOST_CLASS_EXPORT
-
-#include "PrintStyle.hpp"
-#include "Cmd.hpp"
-#include "NodeFwd.hpp"
-#include "NOrder.hpp"
-#include "Zombie.hpp"
-#include "Flag.hpp"
-#include "Child.hpp"
-#include "CheckPt.hpp"
-#include "PreAllocatedReply.hpp"
-
-#if defined(_AIX) && !defined(DEBUG)
-// Required for MoveCmd for release mode of v11.1 compiler
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#endif
-
-class AbstractServer;
-class AbstractClientEnv;
-
-///////////////////////////////////////////////////////////////////////////////////
-// Client->Server cmd's
-///////////////////////////////////////////////////////////////////////////////////
-class ClientToServerCmd {
-public:
- virtual ~ClientToServerCmd();
-
- virtual std::ostream& print(std::ostream& os) const = 0;
- virtual bool equals(ClientToServerCmd* rhs) const = 0;
-
- /// Called by the _server_ to service the client depending on the Command
- /// The server will pass itself down via the AbstractServer
- /// The returned Server to Client command is sent back to the client
- /// Uses template pattern, it first authenticates request and then calls
- /// doHandleRequest. This function can throw exceptions. std::runtime_error
- STC_Cmd_ptr handleRequest(AbstractServer*) const;
-
- /// Returns true if handleRequest is testable. Only used in TEST
- virtual bool handleRequestIsTestable() const { return true ;}
-
- /// How long in seconds the client to attempt to send request and get a reply back
- /// before the request fails. This timeout affects the wait for the outward request
- /// and inward reply.
- ///
- /// The timeout feature allow the client to fail gracefully in the case
- /// where the server has died/crashed. The timeout will ensure the socket is closed.
- /// allowing the server to be restarted without getting the address is use error.
- ///
- /// NOTE: We also have a timeout in ClientInvoker/ClientEnvironment, *that* is different,
- /// as that applies to CHILD/task commands, and control how long we continue
- /// to iterate over the hosts files
- virtual int timeout() const { return 60; }
-
- /// A command can be read only command or write only command
- /// A read only command will not change the state of the suites in the server
- /// A write only command can modify the statue of suite in the server
- /// Used by the server for authentication since only write only users are allowed to edit.
- virtual bool isWrite() const { return false; /* returning false means read only */ }
-
- /// This Must be called for client->server commands.As this is required
- /// for authentication. *However* task based commands have their own authentication
- /// mechanism, and don't need setup_user_authentification().
- virtual void setup_user_authentification() = 0;
-
- /// Allow control over connection to different servers/hosts if the main server is down
- /// i.e for a getCmd, we do not want to wait 24 hours, trying all the servers
- /// However for Task based commands like , init,abort,event, meter,complete we
- /// want this behaviour as it can alter Node tree state and thus affect dependent nodes
- virtual bool connect_to_different_servers() const { return false; }
-
- /// The show occurs on the client side
- virtual PrintStyle::Type_t show_style() const { return PrintStyle::NOTHING;}
-
- // Other commands
- virtual bool get_cmd() const { return false; }
- virtual bool task_cmd() const { return false; }
- virtual bool terminate_cmd() const { return false; }
- virtual bool group_cmd() const { return false; }
- virtual bool ping_cmd() const { return false;}
- virtual bool why_cmd( std::string& ) const { return false;}
- virtual bool show_cmd() const { return false ;}
- virtual bool delete_all_cmd() const { return false ;}
-
- // CLIENT side Parse and command construction, create can throw std::runtime_error for errors
- virtual const char* theArg() const = 0; // used for argument parsing
- virtual void addOption(boost::program_options::options_description& desc) const = 0;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv) const = 0;
-protected:
- ClientToServerCmd() {}
-
- /// called by handleRequest, part of the template pattern
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const = 0;
-
- /// return true if authentication succeeds, false and STC_Cmd_ptr to return otherwise
- /// This function is called from doHandleRequest and hence is called
- /// from within the server. The default implementation will get the current
- /// user and authenticate with reference to the white list file
- virtual bool authenticate(AbstractServer*, STC_Cmd_ptr&) const = 0;
-
- /// Log the command. Must typically be done before call doHandleRequest(), in case of crash/exception
- /// In rare case allow override. (i.e for additional debug)
- /// called by handleRequest, part of the template pattern
- virtual void do_log() const;
-
- /// Some commands which cause a change in state, should force an immediate job submission.
- /// Providing the server is *NOT* shutdown
- static STC_Cmd_ptr doJobSubmission(AbstractServer* as);
-
- static void dumpVecArgs(const char* argOption, const std::vector<std::string>& args);
-
- /// Find the node otherwise throw std:::runtime_error
- node_ptr find_node(AbstractServer* as, const std::string& absNodepath) const;
-
- /// Find The node for edit, otherwise throw std:::runtime_error
- /// Will add the node edit history collection
- node_ptr find_node_for_edit(AbstractServer* as, const std::string& absNodepath) const;
-
- /// Find The node for edit, otherwise return a NULL pointer
- /// Will add the node edit history collection
- node_ptr find_node_for_edit_no_throw(AbstractServer* as, const std::string& absNodepath) const;
-
- /// finds the associated node and adds to edit history nodes
- void add_node_for_edit_history(AbstractServer* as, const std::string& absNodepath) const;
- void add_node_for_edit_history(node_ptr) const;
-
-private:
- friend class GroupCTSCmd;
- friend class EditHistoryMgr;
- mutable std::vector<weak_node_ptr> edit_history_nodes_; // NOT persisted
-
-private:
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive &ar, const unsigned int /*version*/) {}
-};
-BOOST_SERIALIZATION_ASSUME_ABSTRACT(ClientToServerCmd)
-
-//=================================================================================
-// Task Commands
-// ================================================================================
-class TaskCmd : public ClientToServerCmd {
-protected:
- TaskCmd( const std::string& pathToSubmittable,
- const std::string& jobsPassword,
- const std::string& process_or_remote_id,
- int try_no)
- : submittable_(0),path_to_submittable_(pathToSubmittable),
- jobs_password_(jobsPassword),process_or_remote_id_(process_or_remote_id), try_no_(try_no){}
- TaskCmd() : submittable_(0),try_no_(0) {}
-public:
-
- virtual bool isWrite() const { return true; }
- virtual int timeout() const { return 190; } // ECFLOW-157 80 -> 190
-
- const std::string& path_to_node() const { return path_to_submittable_;}
- const std::string& jobs_password() const { return jobs_password_;}
- const std::string& process_or_remote_id() const { return process_or_remote_id_;}
- int try_no() const { return try_no_;}
- virtual ecf::Child::CmdType child_type() const = 0;
-
- virtual bool equals(ClientToServerCmd*) const;
- virtual bool task_cmd() const { return true; }
- virtual bool connect_to_different_servers() const { return true; }
-
-protected:
- /// Overridden to do nothing since Task based commands don't need _user_
- /// based authentification
- virtual void setup_user_authentification(){}
- virtual bool authenticate(AbstractServer*, STC_Cmd_ptr&) const; /// Task have their own mechanism,can throw std::runtime_error
- Submittable* get_submittable(AbstractServer* as) const ; // can throw std::runtime_error
-
-protected:
- mutable Submittable* submittable_; // stored during authentication and re-used handle request, not persisted, server side only
-
-private:
- std::string path_to_submittable_;
- std::string jobs_password_;
- std::string process_or_remote_id_;
- int try_no_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< ClientToServerCmd >( *this );
- ar & path_to_submittable_;
- ar & jobs_password_;
- ar & process_or_remote_id_;
- ar & try_no_;
- }
-};
-
-class InitCmd : public TaskCmd {
-public:
- InitCmd(const std::string& pathToTask,
- const std::string& jobsPassword,
- const std::string& process_or_remote_id,
- int try_no )
- : TaskCmd(pathToTask,jobsPassword,process_or_remote_id,try_no) {}
-
- InitCmd() : TaskCmd() {}
-
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
-
- virtual const char* theArg() const { return arg();}
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-private:
- static const char* arg(); // used for argument parsing
- static const char* desc(); // The description of the argument as provided to user
-
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
- virtual ecf::Child::CmdType child_type() const { return ecf::Child::INIT; }
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< TaskCmd >( *this );
- }
-};
-
-class CompleteCmd : public TaskCmd {
-public:
- CompleteCmd(const std::string& pathToTask,
- const std::string& jobsPassword,
- const std::string& process_or_remote_id = "",
- int try_no = 1)
- : TaskCmd(pathToTask,jobsPassword,process_or_remote_id,try_no) {}
- CompleteCmd() : TaskCmd() {}
-
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
-
- virtual const char* theArg() const { return arg();}
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-private:
- static const char* arg(); // used for argument parsing
- static const char* desc(); // The description of the argument as provided to user
-
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
- virtual ecf::Child::CmdType child_type() const { return ecf::Child::COMPLETE; }
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< TaskCmd >( *this );
- }
-};
-
-/// A child command that evaluates a expression. If the expression is false.
-/// Then client invoker will block.
-class CtsWaitCmd : public TaskCmd {
-public:
- CtsWaitCmd(const std::string& pathToTask,
- const std::string& jobsPassword,
- const std::string& process_or_remote_id,
- int try_no,
- const std::string& expression);
- CtsWaitCmd() : TaskCmd() {}
-
- const std::string& expression() const { return expression_;}
-
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
-
- virtual const char* theArg() const { return arg();}
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-private:
-
- static const char* arg(); // used for argument parsing
- static const char* desc(); // The description of the argument as provided to user
-
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
- virtual ecf::Child::CmdType child_type() const { return ecf::Child::WAIT; }
-
- std::string expression_;
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< TaskCmd >( *this );
- ar & expression_;
- }
-};
-
-class AbortCmd : public TaskCmd {
-public:
- AbortCmd(const std::string& pathToTask,
- const std::string& jobsPassword,
- const std::string& process_or_remote_id,
- int try_no = 1,
- const std::string& reason = "");
- AbortCmd() : TaskCmd() {}
-
- const std::string& reason() const {return reason_; }
-
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
-
- virtual const char* theArg() const { return arg();}
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-private:
- static const char* arg(); // used for argument parsing
- static const char* desc(); // The description of the argument as provided to user
-
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
- virtual ecf::Child::CmdType child_type() const { return ecf::Child::ABORT; }
-
- std::string reason_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< TaskCmd >( *this );
- ar & reason_;
- }
-};
-
-class EventCmd : public TaskCmd {
-public:
- EventCmd(const std::string& pathToTask,
- const std::string& jobsPassword,
- const std::string& process_or_remote_id,
- int try_no,
- const std::string& eventName )
- : TaskCmd(pathToTask,jobsPassword,process_or_remote_id,try_no), name_(eventName) {}
- EventCmd() : TaskCmd() {}
-
- const std::string& name() const { return name_; }
-
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
-
- virtual const char* theArg() const { return arg();}
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-private:
- static const char* arg(); // used for argument parsing
- static const char* desc(); // The description of the argument as provided to user
-
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
- virtual ecf::Child::CmdType child_type() const { return ecf::Child::EVENT; }
-
-private:
- std::string name_; // the events name
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< TaskCmd >( *this );
- ar & name_;
- }
-};
-
-class MeterCmd : public TaskCmd {
-public:
- MeterCmd(const std::string& pathToTask,
- const std::string& jobsPassword,
- const std::string& process_or_remote_id,
- int try_no,
- const std::string& meterName,
- int meterValue)
- : TaskCmd(pathToTask,jobsPassword,process_or_remote_id,try_no), name_(meterName), value_(meterValue) {}
- MeterCmd() : TaskCmd(), value_(0) {}
-
- const std::string& name() const { return name_; }
- int value() const { return value_; }
-
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
-
- virtual const char* theArg() const { return arg();}
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-private:
- static const char* arg(); // used for argument parsing
- static const char* desc(); // The description of the argument as provided to user
-
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
- virtual ecf::Child::CmdType child_type() const { return ecf::Child::METER; }
-
-private:
- std::string name_; // the meters name
- int value_; // the meters value
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< TaskCmd >( *this );
- ar & name_;
- ar & value_;
- }
-};
-
-class LabelCmd : public TaskCmd {
-public:
- LabelCmd(const std::string& pathToTask,
- const std::string& jobsPassword,
- const std::string& process_or_remote_id,
- int try_no,
- const std::string& name,
- const std::string& label)
- : TaskCmd(pathToTask,jobsPassword,process_or_remote_id,try_no), name_(name), label_(label) {}
- LabelCmd() : TaskCmd() {}
-
- const std::string& name() const { return name_; }
- const std::string& label() const { return label_;}
-
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
-
- virtual const char* theArg() const { return arg();}
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-private:
- static const char* arg(); // used for argument parsing
- static const char* desc(); // The description of the argument as provided to user
-
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
- virtual ecf::Child::CmdType child_type() const { return ecf::Child::LABEL; }
-
-private:
- std::string name_; // the label name
- std::string label_; // a single label, or multi-line label
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< TaskCmd >( *this );
- ar & name_;
- ar & label_;
- }
-};
-
-//=================================================================================
-// User Commands
-// ================================================================================
-class UserCmd : public ClientToServerCmd {
-public:
- UserCmd(){}
-
- const std::string& user() const { return user_;}
- virtual void setup_user_authentification();
-
-protected:
-
- virtual bool equals(ClientToServerCmd*) const;
- virtual bool authenticate(AbstractServer*, STC_Cmd_ptr&) const;
-
- /// Prompt the user for confirmation: If user responds with no, will exit client
- static void prompt_for_confirmation(const std::string& prompt);
-
- /// All user commands will be pre_fixed with "--" and post_fixed with :user.
- std::ostream& user_cmd(std::ostream& os, const std::string& the_cmd) const;
-
- static int time_out_for_load_sync_and_get();
-
- // The order is preserved during the split. Paths assumed to start with '/' char
- static void split_args_to_options_and_paths(
- const std::vector<std::string>& args,
- std::vector<std::string>& options,
- std::vector<std::string>& paths);
-
-
-private:
- std::string user_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< ClientToServerCmd >( *this );
- ar & user_;
- }
-};
-
-
-// ========================================================================
-// This Command should NEVER be changed
-// This will allow new client to ask OLD server about its version
-// ========================================================================
-class ServerVersionCmd : public UserCmd {
-public:
- ServerVersionCmd(){}
-
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
- virtual const char* theArg() const;
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-private:
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< UserCmd >( *this );
- }
-};
-
-
-// This command is used to encapsulate all commands that are
-// simple signals to the server. This helps to cut down on the
-// number of global symbols used by boost serialisation.
-// =========================================================================
-// *** IMPORTANT ***: If any of these commands in the future need arguments,
-// *** then ensure to place a DUMMY enum in its place.
-// *** This will allow a *newer* development client to still send message to a older server.
-// *** i.e like terminating the server
-// *** IMPORTANT: For any new commands, must be added to the end.
-// *** - STATS_RESET was introduced in release 4.0.5
-// =========================================================================
-class CtsCmd : public UserCmd {
-public:
- enum Api { NO_CMD, RESTORE_DEFS_FROM_CHECKPT,
- RESTART_SERVER, SHUTDOWN_SERVER, HALT_SERVER, TERMINATE_SERVER,
- RELOAD_WHITE_LIST_FILE,
- FORCE_DEP_EVAL,
- PING, GET_ZOMBIES, STATS, SUITES,
- DEBUG_SERVER_ON, DEBUG_SERVER_OFF,
- SERVER_LOAD, STATS_RESET
- };
-
- CtsCmd(Api a) : api_(a) {}
- CtsCmd() : api_(NO_CMD) {}
-
- Api api() const { return api_;}
-
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
-
- virtual bool isWrite() const;
- virtual bool terminate_cmd() const { return api_ == TERMINATE_SERVER; }
- virtual bool ping_cmd() const { return api_ == PING; }
- virtual int timeout() const;
-
- virtual bool handleRequestIsTestable() const;
-
- virtual const char* theArg() const;
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-private:
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
-
- Api api_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< UserCmd >( *this );
- ar & api_;
- }
-};
-
-class CheckPtCmd : public UserCmd {
-public:
- CheckPtCmd(ecf::CheckPt::Mode m, int interval,int checkpt_save_time_alarm)
- : mode_(m), check_pt_interval_(interval),check_pt_save_time_alarm_(checkpt_save_time_alarm) {}
- CheckPtCmd() : mode_(ecf::CheckPt::UNDEFINED), check_pt_interval_(0),check_pt_save_time_alarm_(0) {}
-
- ecf::CheckPt::Mode mode() const { return mode_;}
- int check_pt_interval() const { return check_pt_interval_;}
- int check_pt_save_time_alarm() const { return check_pt_save_time_alarm_;}
-
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
- virtual bool isWrite() const;
- virtual const char* theArg() const;
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-private:
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
-
- ecf::CheckPt::Mode mode_;
- int check_pt_interval_;
- int check_pt_save_time_alarm_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< UserCmd >( *this );
- ar & mode_;
- ar & check_pt_interval_;
- ar & check_pt_save_time_alarm_;
- }
-};
-
-
-// Client---(CSyncCmd::SYNC_FULL)---->Server-----(SSyncCmd)--->client:
-// Client---(CSyncCmd::SYNC)--------->Server-----(SSyncCmd)--->client:
-// Client---(CSyncCmd::NEWS)--------->Server-----(SNewsCmd)--->client:
-class CSyncCmd : public UserCmd {
-public:
- enum Api { NEWS, SYNC , SYNC_FULL};
-
- CSyncCmd(Api a, unsigned int client_handle,unsigned int client_state_change_no, unsigned int client_modify_change_no)
- : api_(a),
- client_handle_(client_handle),
- client_state_change_no_(client_state_change_no),
- client_modify_change_no_(client_modify_change_no) {}
- CSyncCmd(unsigned int client_handle)
- : api_(SYNC_FULL),
- client_handle_(client_handle),
- client_state_change_no_(0),
- client_modify_change_no_(0) {}
- CSyncCmd()
- : api_(SYNC),
- client_handle_(0),
- client_state_change_no_(0),
- client_modify_change_no_(0) {}
-
- Api api() const { return api_;}
- int client_state_change_no() const { return client_state_change_no_;}
- int client_modify_change_no() const { return client_modify_change_no_;}
- int client_handle() const { return client_handle_;}
-
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
- virtual int timeout() const;
-
- virtual const char* theArg() const;
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-private:
-
- /// Custom handling of command logging to add additional debug on same line
- /// makes it easier to debug errors in syncing.
- virtual void do_log() const;
-
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
-
- Api api_;
- int client_handle_;
- int client_state_change_no_;
- int client_modify_change_no_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< UserCmd >( *this );
- ar & api_;
- ar & client_handle_;
- ar & client_state_change_no_;
- ar & client_modify_change_no_;
- }
-};
-
-class ClientHandleCmd : public UserCmd {
-public:
- enum Api { REGISTER, DROP, DROP_USER, ADD, REMOVE, AUTO_ADD , SUITES };
-
- ClientHandleCmd(Api api = AUTO_ADD)
- : api_(api),
- client_handle_(0),
- auto_add_new_suites_(false) {}
-
- ClientHandleCmd(const std::vector<std::string>& suites, bool add_add_new_suites)
- : api_(REGISTER),
- client_handle_(0),
- auto_add_new_suites_(add_add_new_suites),
- suites_(suites) {}
-
- ClientHandleCmd(int client_handle)
- : api_(DROP),
- client_handle_(client_handle),
- auto_add_new_suites_(false) {}
-
- ClientHandleCmd(const std::string& drop_user)
- : api_(DROP_USER),
- client_handle_(0),
- auto_add_new_suites_(false),
- drop_user_(drop_user){}
-
- ClientHandleCmd(int client_handle, const std::vector<std::string>& suites, Api api)
- : api_(api), // Must be ADD or REMOVE
- client_handle_(client_handle),
- auto_add_new_suites_(false),
- suites_(suites){}
-
- ClientHandleCmd(int client_handle, bool add_add_new_suites)
- : api_(AUTO_ADD),
- client_handle_(client_handle),
- auto_add_new_suites_(add_add_new_suites) {}
-
- Api api() const { return api_;}
- const std::string& drop_user() const { return drop_user_;}
-
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
- virtual bool isWrite() const;
-
- virtual const char* theArg() const;
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-private:
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
-
- Api api_;
- int client_handle_;
- bool auto_add_new_suites_;
- std::string drop_user_;
- std::vector<std::string> suites_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< UserCmd >( *this );
- ar & api_;
- ar & client_handle_;
- ar & auto_add_new_suites_;
- ar & drop_user_;
- ar & suites_;
- }
-};
-
-// Collection of commands, that all take a abs node path as their only arg
-// Reduce number of global symbols caused by boost serialisation
-// Previously they were all separate commands
-//
-// Client---(CtsNodeCmd(GET))---->Server-----(DefsCmd | SNodeCmd )--->client:
-// When doHandleRequest is called in the server it will return DefsCmd
-// The DefsCmd is used to transport the node tree hierarchy to/from the server
-//
-// CHECK_JOB_GEN_ONLY command will traverse hierarchically from the given node path
-// and force generation of jobs. (i.e independently of dependencies).
-// This is used in *testing* only, so that we can compare/test/verify
-// job generation with the old version.
-// if absNodepath is empty we will generate jobs for all tasks
-class CtsNodeCmd : public UserCmd {
-public:
- enum Api { NO_CMD, JOB_GEN, CHECK_JOB_GEN_ONLY, GET, WHY, GET_STATE, MIGRATE };
- CtsNodeCmd(Api a, const std::string& absNodePath) : api_(a),absNodePath_(absNodePath) {}
- CtsNodeCmd(Api a) : api_(a) { assert(a != NO_CMD); }
- CtsNodeCmd() : api_(NO_CMD) {}
-
- Api api() const { return api_;}
- const std::string& absNodePath() const { return absNodePath_;}
-
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
-
- virtual PrintStyle::Type_t show_style() const;
-
- virtual int timeout() const;
- virtual bool isWrite() const;
- virtual bool handleRequestIsTestable() const { return !terminate_cmd();}
- virtual bool why_cmd( std::string& nodePath) const;
- virtual bool get_cmd() const { return api_ == GET; }
-
- virtual const char* theArg() const;
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-private:
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
-
-private:
- Api api_;
- std::string absNodePath_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< UserCmd >( *this );
- ar & api_;
- ar & absNodePath_;
- }
-};
-
-// DELETE If paths_ empty will delete all suites (beware) else will delete the chosen nodes.
-class PathsCmd : public UserCmd {
-public:
- enum Api { NO_CMD, DELETE, SUSPEND, RESUME, KILL, STATUS, CHECK, EDIT_HISTORY };
-
- PathsCmd(Api api,const std::vector<std::string>& paths, bool force = false)
- : api_(api),force_(force),paths_(paths){}
- PathsCmd(Api api,const std::string& absNodePath, bool force = false);
- PathsCmd(Api api)
- : api_(api), force_(false) { assert(api != NO_CMD); }
- PathsCmd()
- : api_(NO_CMD),force_(false) {}
-
- Api api() const { return api_; }
- const std::vector<std::string>& paths() const { return paths_;}
- bool force() const { return force_;}
-
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
- virtual bool isWrite() const;
- virtual bool delete_all_cmd() const;
-
- virtual const char* theArg() const;
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-private:
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
-
-private:
- Api api_;
- bool force_;
- mutable std::vector<std::string> paths_; // mutable to allow swap to clear & reclaim memory, as soon as possible
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< UserCmd >( *this );
- ar & api_;
- ar & force_;
- ar & paths_;
- }
-};
-
-
-/// The LogCmd is paired with SStringCmd
-/// Client---(LogCmd)---->Server-----(SStringCmd)--->client:
-/// When doHandleRequest is called in the server it will return SStringCmd
-/// The SStringCmd is used to transport the log file contents to the client
-class LogCmd : public UserCmd {
-public:
- enum LogApi { GET, CLEAR, FLUSH, NEW , PATH};
- LogCmd(LogApi a, int get_last_n_lines = 0); // for zero we take default from log. Avoid adding dependency on log.hpp
- LogCmd(const std::string& path); // NEW
- LogCmd();
-
- LogApi api() const { return api_;}
- int get_last_n_lines() const { return get_last_n_lines_;}
- const std::string& new_path() const { return new_path_;}
-
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
-
- virtual const char* theArg() const { return arg();}
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-private:
- static const char* arg(); // used for argument parsing
- static const char* desc(); // The description of the argument as provided to user
-
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
-
- LogApi api_;
- int get_last_n_lines_; // default to 100 -> ECFLOW-174
- std::string new_path_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< UserCmd >( *this );
- ar & api_;
- ar & get_last_n_lines_;
- ar & new_path_;
- }
-};
-
-/// Simply writes the message to the log file
-class LogMessageCmd : public UserCmd {
-public:
- LogMessageCmd(const std::string& msg) : msg_(msg) {}
- LogMessageCmd() {}
-
- const std::string& msg() const { return msg_;}
-
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
-
- virtual const char* theArg() const { return arg();}
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-private:
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
- static const char* arg(); // used for argument parsing
- static const char* desc(); // The description of the argument as provided to user
-
- std::string msg_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< UserCmd >( *this );
- ar & msg_;
- }
-};
-
-
-// class Begin: if suiteName is empty we will begin all suites
-class BeginCmd : public UserCmd {
-public:
- BeginCmd(const std::string& suiteName, bool force = false);
- BeginCmd() : force_(false) {}
-
- const std::string& suiteName() const { return suiteName_;}
- bool force() const { return force_;}
-
- virtual int timeout() const { return 80; }
-
- virtual bool isWrite() const { return true; }
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
-
- virtual const char* theArg() const { return arg();}
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-private:
- static const char* arg(); // used for argument parsing
- static const char* desc(); // The description of the argument as provided to user
-
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
-
- std::string suiteName_;
- bool force_; // reset begin status on suites & bypass checks, can create zombies, used in test only
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< UserCmd >( *this );
- ar & suiteName_;
- ar & force_;
- }
-};
-
-class ZombieCmd : public UserCmd {
-public:
- ZombieCmd(ecf::User::Action uc, const std::string& path, const std::string& process_id, const std::string& password)
- : user_action_(uc), path_(path), process_id_(process_id), password_(password) {}
- ZombieCmd(ecf::User::Action uc = ecf::User::BLOCK) : user_action_(uc) {}
-
- const std::string& path_to_task() const { return path_;}
- const std::string& process_or_remote_id() const { return process_id_;}
- const std::string& password() const { return password_;}
-
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
-
- virtual const char* theArg() const;
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-private:
-
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
-
- ecf::User::Action user_action_;
- std::string path_;
- std::string process_id_;
- std::string password_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< UserCmd >( *this );
- ar & user_action_;
- ar & path_;
- ar & process_id_;
- ar & password_;
- }
-};
-
-class RequeueNodeCmd : public UserCmd {
-public:
- enum Option { NO_OPTION, ABORT, FORCE };
-
- RequeueNodeCmd(const std::vector<std::string>& paths, Option op = NO_OPTION)
- : paths_(paths), option_(op) {}
-
- RequeueNodeCmd(const std::string& absNodepath, Option op = NO_OPTION)
- : paths_(std::vector<std::string>(1,absNodepath)), option_(op) {}
-
- RequeueNodeCmd() : option_(NO_OPTION) {}
-
- const std::vector<std::string>& paths() const { return paths_;}
- Option option() const { return option_;}
-
- virtual bool isWrite() const { return true; }
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
-
- virtual const char* theArg() const { return arg();}
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-private:
- static const char* arg(); // used for argument parsing
- static const char* desc(); // The description of the argument as provided to user
-
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
-
-private:
- mutable std::vector<std::string> paths_; // mutable to allow swap to clear & reclaim memory, as soon as possible
- Option option_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< UserCmd >( *this );
- ar & paths_;
- ar & option_;
- }
-};
-
-class OrderNodeCmd : public UserCmd {
-public:
- OrderNodeCmd(const std::string& absNodepath, NOrder::Order op)
- : absNodepath_(absNodepath), option_(op) {}
- OrderNodeCmd() : option_(NOrder::TOP) {}
-
- const std::string& absNodepath() const { return absNodepath_;}
- NOrder::Order option() const { return option_;}
-
- virtual bool isWrite() const { return true; }
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
-
- virtual const char* theArg() const { return arg();}
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-private:
- static const char* arg(); // used for argument parsing
- static const char* desc(); // The description of the argument as provided to user
-
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
-
- std::string absNodepath_;
- NOrder::Order option_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< UserCmd >( *this );
- ar & absNodepath_;
- ar & option_;
- }
-};
-
-
-// The absNodepath must be provided
-class RunNodeCmd : public UserCmd {
-public:
- RunNodeCmd(const std::string& absNodepath, bool force, bool test = false)
- : paths_(std::vector<std::string>(1,absNodepath)), force_(force), test_(test) {}
-
- RunNodeCmd(const std::vector<std::string>& paths, bool force, bool test = false)
- : paths_(paths), force_(force), test_(test) {}
-
- RunNodeCmd() : force_(false), test_(false) {}
-
- const std::vector<std::string>& paths() const { return paths_;}
- bool force() const { return force_;}
-
- virtual bool isWrite() const { return true; }
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
-
- virtual const char* theArg() const { return arg();}
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-private:
- static const char* arg(); // used for argument parsing
- static const char* desc(); // The description of the argument as provided to user
-
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
-
-private:
- mutable std::vector<std::string> paths_; // mutable to allow swap to clear & reclaim memory, as soon as possible
- bool force_;
- bool test_; // only for test, hence we don't serialise this
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< UserCmd >( *this );
- ar & paths_;
- ar & force_;
- }
-};
-
-
-// Does Nothing in the server, however allows client code to display the
-// returned Defs in different showStyles
-// This class has no need for persistence, i.e client side only
-class ShowCmd : public UserCmd {
-public:
- ShowCmd(PrintStyle::Type_t s = PrintStyle::DEFS) : style_(s) {}
-
- // returns the showStyle
- virtual bool show_cmd() const { return true ;}
- virtual PrintStyle::Type_t show_style() const { return style_;}
-
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
-
- virtual const char* theArg() const { return arg();}
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-private:
- static const char* arg(); // used for argument parsing
- static const char* desc(); // The description of the argument as provided to user
-
- // The Show Cmd is processed on the client side,
- // Likewise the doHandleRequest does nothing,
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
-
- PrintStyle::Type_t style_;
-
- // Persistence is still required since show command can be *USED* in a *GROUP* command
- // However its ONLY used on the client side, hence no need to serialise data members
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< UserCmd >( *this );
- }
-};
-
-// Will *load* the suites, into the server.
-// Additionally the server will try to resolve extern's. The extern are references
-// to Node, events, meters, limits, variables defined on another suite.
-class LoadDefsCmd : public UserCmd {
-public:
- LoadDefsCmd(const std::string& defs_filename, bool force = false);
-
- LoadDefsCmd(const defs_ptr& defs, bool force = false)
- : force_(force), defs_(defs) {}
-
- LoadDefsCmd() : force_(false) {}
-
- // Uses by equals only
- const defs_ptr& theDefs() const { return defs_; }
-
- virtual bool isWrite() const { return true; }
- virtual int timeout() const { return time_out_for_load_sync_and_get(); }
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
-
- virtual const char* theArg() const { return arg();}
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
- static Cmd_ptr create(const std::string& defs_filename, bool force, bool check_only, AbstractClientEnv* clientEnv);
-
-private:
- static const char* arg(); // used for argument parsing
- static const char* desc(); // The description of the command as provided to user
-
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
-
- bool force_;
- defs_ptr defs_;
- std::string defs_filename_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< UserCmd >( *this );
- ar & force_;
- ar & defs_;
- ar & defs_filename_;
- }
-};
-
-class ReplaceNodeCmd : public UserCmd {
-public:
- ReplaceNodeCmd(const std::string& node_path, bool createNodesAsNeeded, defs_ptr defs, bool force );
- ReplaceNodeCmd(const std::string& node_path, bool createNodesAsNeeded, const std::string& path_to_defs, bool force );
- ReplaceNodeCmd() : createNodesAsNeeded_(false), force_(false) {}
-
- defs_ptr theDefs() const { return clientDefs_; }
- const std::string& pathToNode() const { return pathToNode_; }
- const std::string& path_to_defs() const { return path_to_defs_;}
- bool createNodesAsNeeded() const { return createNodesAsNeeded_;}
- bool force() const { return force_;}
-
- virtual bool isWrite() const { return true; }
- virtual int timeout() const { return 300; }
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
-
- virtual const char* theArg() const { return arg();}
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-private:
- static const char* arg(); // used for argument parsing
- static const char* desc(); // The description of the argument as provided to user
-
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
-
- bool createNodesAsNeeded_;
- bool force_;
- std::string pathToNode_;
- std::string path_to_defs_; // Can be empty if defs loaded in memory via python api
- defs_ptr clientDefs_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< UserCmd >( *this );
- ar & createNodesAsNeeded_;
- ar & force_;
- ar & pathToNode_;
- ar & path_to_defs_;
- ar & clientDefs_;
- }
-};
-
-// Set the state on the affected node ONLY.
-// If recursive is used set the state, on node and _ALL_ nodes _beneath
-// setRepeatToLastValue set, only make sense when used with recursive.
-// stateOrEvent, string is one of:
-// < unknown | suspended | complete | queued | submitted | active | aborted | clear | set >
-class ForceCmd : public UserCmd {
-public:
- ForceCmd(const std::vector<std::string>& paths,
- const std::string& stateOrEvent,
- bool recursive,
- bool setRepeatToLastValue)
- : paths_(paths), stateOrEvent_(stateOrEvent),
- recursive_(recursive), setRepeatToLastValue_(setRepeatToLastValue) {}
- ForceCmd(const std::string& path,
- const std::string& stateOrEvent,
- bool recursive,
- bool setRepeatToLastValue)
- : paths_(std::vector<std::string>(1,path)), stateOrEvent_(stateOrEvent),
- recursive_(recursive), setRepeatToLastValue_(setRepeatToLastValue) {}
- ForceCmd() : recursive_(false), setRepeatToLastValue_(false) {}
-
- // Uses by equals only
- const std::vector<std::string> paths() const { return paths_; }
- const std::string& stateOrEvent() const { return stateOrEvent_;}
- bool recursive() const { return recursive_;}
- bool setRepeatToLastValue() const { return setRepeatToLastValue_;}
-
- virtual bool isWrite() const { return true; }
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
-
- virtual const char* theArg() const { return arg();}
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-private:
- static const char* arg(); // used for argument parsing
- static const char* desc(); // The description of the argument as provided to user
-
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
-
-private:
- mutable std::vector<std::string> paths_; // mutable to allow swap to clear & reclaim memory, as soon as possible
- std::string stateOrEvent_;
- bool recursive_;
- bool setRepeatToLastValue_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< UserCmd >( *this );
- ar & paths_;
- ar & stateOrEvent_;
- ar & recursive_;
- ar & setRepeatToLastValue_;
- }
-};
-
-// Free Dependencies
-class FreeDepCmd : public UserCmd {
-public:
- FreeDepCmd(const std::vector<std::string>& paths,
- bool trigger = true,
- bool all = false, // day, date, time, today, trigger, cron
- bool date = false,
- bool time = false // includes time, day, date, today, cron
- )
- : paths_(paths), trigger_(trigger), all_(all), date_(date), time_(time) {}
-
- FreeDepCmd(const std::string& path,
- bool trigger = true,
- bool all = false, // day, date, time, today, trigger, cron
- bool date = false,
- bool time = false // includes time, day, date, today, cron
- )
- : paths_(std::vector<std::string>(1,path)), trigger_(trigger), all_(all), date_(date), time_(time) {}
-
- FreeDepCmd() : trigger_(true), all_(false), date_(false), time_(false){}
-
- // Uses by equals only
- const std::vector<std::string>& paths() const { return paths_; }
- bool trigger() const { return trigger_;}
- bool all() const { return all_;}
- bool date() const { return date_;}
- bool time() const { return time_;}
-
- virtual bool isWrite() const { return true; }
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
-
- virtual const char* theArg() const { return arg();}
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-private:
- static const char* arg(); // used for argument parsing
- static const char* desc(); // The description of the argument as provided to user
-
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
-
-private:
- mutable std::vector<std::string> paths_; // mutable to allow swap to clear & reclaim memory, as soon as possible
- bool trigger_;
- bool all_;
- bool date_;
- bool time_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< UserCmd >( *this );
- ar & paths_;
- ar & trigger_;
- ar & all_;
- ar & date_;
- ar & time_;
- }
-};
-
-class AlterCmd : public UserCmd {
-public:
- enum Delete_attr_type { DEL_VARIABLE, DEL_TIME, DEL_TODAY, DEL_DATE, DEL_DAY,
- DEL_CRON, DEL_EVENT, DEL_METER, DEL_LABEL,
- DEL_TRIGGER, DEL_COMPLETE, DEL_REPEAT, DEL_LIMIT, DEL_LIMIT_PATH,
- DEL_INLIMIT, DEL_ZOMBIE, DELETE_ATTR_ND };
-
- enum Change_attr_type { VARIABLE, CLOCK_TYPE, CLOCK_DATE, CLOCK_GAIN, EVENT, METER, LABEL,
- TRIGGER, COMPLETE, REPEAT, LIMIT_MAX, LIMIT_VAL, DEFSTATUS, CHANGE_ATTR_ND, CLOCK_SYNC };
-
- enum Add_attr_type { ADD_TIME, ADD_TODAY, ADD_DATE, ADD_DAY, ADD_ZOMBIE, ADD_VARIABLE, ADD_ATTR_ND };
-
- AlterCmd(const std::string& path, Add_attr_type attr, const std::string& name, const std::string& value = "" )
- : paths_(std::vector<std::string>(1,path)), name_(name), value_(value), add_attr_type_(attr),
- del_attr_type_(DELETE_ATTR_ND), change_attr_type_(CHANGE_ATTR_ND),flag_type_(ecf::Flag::NOT_SET), flag_(false) {}
- AlterCmd(const std::vector<std::string>& paths, Add_attr_type attr, const std::string& name, const std::string& value = "" )
- : paths_(paths), name_(name), value_(value), add_attr_type_(attr),
- del_attr_type_(DELETE_ATTR_ND), change_attr_type_(CHANGE_ATTR_ND),flag_type_(ecf::Flag::NOT_SET), flag_(false) {}
-
- AlterCmd(const std::string& path, Delete_attr_type del, const std::string& name = "" , const std::string& value = "")
- : paths_(std::vector<std::string>(1,path)), name_(name), value_(value), add_attr_type_(ADD_ATTR_ND),
- del_attr_type_(del), change_attr_type_(CHANGE_ATTR_ND),flag_type_(ecf::Flag::NOT_SET), flag_(false) {}
- AlterCmd(const std::vector<std::string>& paths, Delete_attr_type del, const std::string& name = "" , const std::string& value = "")
- : paths_(paths), name_(name), value_(value), add_attr_type_(ADD_ATTR_ND),
- del_attr_type_(del), change_attr_type_(CHANGE_ATTR_ND),flag_type_(ecf::Flag::NOT_SET), flag_(false) {}
-
- AlterCmd(const std::string& path, Change_attr_type attr, const std::string& name, const std::string& value = "")
- : paths_(std::vector<std::string>(1,path)), name_(name), value_(value), add_attr_type_(ADD_ATTR_ND),
- del_attr_type_(DELETE_ATTR_ND), change_attr_type_(attr),flag_type_(ecf::Flag::NOT_SET), flag_(false) {}
- AlterCmd(const std::vector<std::string>& paths, Change_attr_type attr, const std::string& name, const std::string& value = "")
- : paths_(paths), name_(name), value_(value), add_attr_type_(ADD_ATTR_ND),
- del_attr_type_(DELETE_ATTR_ND), change_attr_type_(attr),flag_type_(ecf::Flag::NOT_SET), flag_(false) {}
-
- AlterCmd(const std::string& path, ecf::Flag::Type ft, bool flag)
- : paths_(std::vector<std::string>(1,path)), add_attr_type_(ADD_ATTR_ND),
- del_attr_type_(DELETE_ATTR_ND), change_attr_type_(CHANGE_ATTR_ND),flag_type_(ft), flag_(flag) {}
- AlterCmd(const std::vector<std::string>& paths, ecf::Flag::Type ft, bool flag)
- : paths_(paths), add_attr_type_(ADD_ATTR_ND),
- del_attr_type_(DELETE_ATTR_ND), change_attr_type_(CHANGE_ATTR_ND),flag_type_(ft), flag_(flag) {}
-
- AlterCmd()
- : add_attr_type_(ADD_ATTR_ND), del_attr_type_(DELETE_ATTR_ND),
- change_attr_type_(CHANGE_ATTR_ND),flag_type_(ecf::Flag::NOT_SET), flag_(false) {}
-
- // Uses by equals only
- const std::vector<std::string>& paths() const { return paths_; }
- const std::string& name() const { return name_; }
- const std::string& value() const { return value_; }
- Delete_attr_type delete_attr_type() const { return del_attr_type_;}
- Change_attr_type change_attr_type() const { return change_attr_type_;}
- Add_attr_type add_attr_type() const { return add_attr_type_;}
- ecf::Flag::Type flag_type() const { return flag_type_;}
- bool flag() const { return flag_;}
-
- virtual bool isWrite() const { return true; }
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
-
- virtual const char* theArg() const { return arg();}
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-private:
- static const char* arg(); // used for argument parsing
- static const char* desc(); // The description of the argument as provided to user
-
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
- STC_Cmd_ptr alter_server_state(AbstractServer*) const;
-
- void createAdd( Cmd_ptr& cmd, std::vector<std::string>& options, std::vector<std::string>& paths) const;
- void createDelete( Cmd_ptr& cmd, const std::vector<std::string>& options, const std::vector<std::string>& paths) const;
- void createChange( Cmd_ptr& cmd, std::vector<std::string>& options, std::vector<std::string>& paths) const;
- void create_flag( Cmd_ptr& cmd, const std::vector<std::string>& options, const std::vector<std::string>& paths, bool flag) const;
-
-private:
- mutable std::vector<std::string> paths_; // mutable to allow swap to clear & reclaim memory, as soon as possible
- std::string name_;
- std::string value_;
- Add_attr_type add_attr_type_;
- Delete_attr_type del_attr_type_;
- Change_attr_type change_attr_type_;
- ecf::Flag::Type flag_type_;
- bool flag_; // true means set false means clear
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< UserCmd >( *this );
- ar & paths_;
- ar & name_;
- ar & value_;
- ar & add_attr_type_;
- ar & del_attr_type_;
- ar & change_attr_type_;
- ar & flag_type_;
- ar & flag_;
- }
-};
-
-//================================================================================
-// Paired with SStringCmd
-// Client---(CFileCmd)---->Server-----(SStringCmd)--->client:
-//================================================================================
-class CFileCmd : public UserCmd {
-public:
- enum File_t { ECF, JOB, JOBOUT, MANUAL, KILL, STAT };
- CFileCmd(const std::string& pathToNode, File_t file, size_t max_lines)
- : file_(file), pathToNode_(pathToNode), max_lines_(max_lines) {}
- CFileCmd(const std::string& pathToNode, const std::string& file_type, const std::string& max_lines);
-
- CFileCmd() : file_(ECF),max_lines_(0) {}
-
- // Uses by equals only
- const std::string& pathToNode() const { return pathToNode_; }
- File_t fileType() const { return file_;}
- size_t max_lines() const { return max_lines_;}
-
- static std::vector<CFileCmd::File_t> fileTypesVec();
- static std::string toString(File_t);
-
- virtual bool handleRequestIsTestable() const { return false ;}
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
-
- virtual const char* theArg() const { return arg();}
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-private:
- static const char* arg(); // used for argument parsing
- static const char* desc(); // The description of the argument as provided to user
-
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
-
- File_t file_;
- std::string pathToNode_;
- size_t max_lines_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< UserCmd >( *this );
- ar & file_;
- ar & pathToNode_;
- ar & max_lines_;
- }
-};
-
-//================================================================================
-// Paired with SStringCmd
-// Client---(EditScriptCmd)---->Server-----(SStringCmd)--->client:
-//================================================================================
-class EditScriptCmd : public UserCmd {
-public:
- enum EditType { EDIT, PREPROCESS, SUBMIT, PREPROCESS_USER_FILE, SUBMIT_USER_FILE };
- EditScriptCmd(const std::string& path_to_node,EditType et) // EDIT or PREPROCESS
- : edit_type_(et), path_to_node_(path_to_node),
- alias_(false),run_(false)
- {}
-
- EditScriptCmd(const std::string& path_to_node, const NameValueVec& user_variables)
- : edit_type_(SUBMIT), path_to_node_(path_to_node), user_variables_(user_variables),
- alias_(false),run_(false)
- {}
-
- EditScriptCmd(const std::string& path_to_node, const std::vector<std::string>& user_file_contents)
- : edit_type_(PREPROCESS_USER_FILE), path_to_node_(path_to_node), user_file_contents_(user_file_contents),
- alias_(false),run_(false)
- {}
-
- EditScriptCmd( const std::string& path_to_node,
- const NameValueVec& user_variables,
- const std::vector<std::string>& user_file_contents,
- bool create_alias,
- bool run_alias
- )
- : edit_type_(SUBMIT_USER_FILE), path_to_node_(path_to_node), user_file_contents_(user_file_contents),user_variables_(user_variables),
- alias_(create_alias),run_(run_alias)
- {}
-
- EditScriptCmd() : edit_type_(EDIT),alias_(false),run_(false) {}
-
- // Uses by equals only
- const std::string& path_to_node() const { return path_to_node_; }
- EditType edit_type() const { return edit_type_;}
- bool alias() const { return alias_;}
- bool run() const { return run_;}
-
- virtual bool handleRequestIsTestable() const { return false ;}
- virtual bool isWrite() const;
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
-
- virtual const char* theArg() const { return arg();}
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-private:
- static const char* arg(); // used for argument parsing
- static const char* desc(); // The description of the argument as provided to user
-
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
-
- EditType edit_type_;
- std::string path_to_node_;
- mutable std::vector<std::string> user_file_contents_;
- NameValueVec user_variables_;
- bool alias_;
- bool run_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< UserCmd >( *this );
- ar & edit_type_;
- ar & path_to_node_;
- ar & user_file_contents_;
- ar & user_variables_;
- ar & alias_;
- ar & run_;
- }
-};
-
-class PlugCmd : public UserCmd {
-public:
- PlugCmd(const std::string& source, const std::string& dest) : source_(source), dest_(dest) {}
- PlugCmd() {}
-
- // Uses by equals only
- const std::string& source() const { return source_; }
- const std::string& dest() const { return dest_; }
-
- virtual int timeout() const { return 120; }
- virtual bool handleRequestIsTestable() const { return false ;}
- virtual bool isWrite() const { return true; }
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
-
- virtual const char* theArg() const { return arg();}
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-private:
- static const char* arg(); // used for argument parsing
- static const char* desc(); // The description of the argument as provided to user
-
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
-
-private:
- std::string source_;
- std::string dest_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< UserCmd >( *this );
- ar & source_;
- ar & dest_;
- }
-};
-
-class MoveCmd : public UserCmd {
-public:
- MoveCmd(const std::pair<std::string,std::string>& host_port, Node* src, const std::string& dest);
- MoveCmd();
- virtual ~MoveCmd();
-
- Node* source() const;
- const std::string& dest() const { return dest_; }
-
- virtual bool handleRequestIsTestable() const { return false ;}
- virtual bool isWrite() const { return true; }
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
-
- virtual const char* theArg() const { return arg();}
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-private:
- static const char* arg(); // used for argument parsing
- static const char* desc(); // The description of the argument as provided to user
-
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
-
- bool check_source() const;
-
-private:
- mutable Suite* sourceSuite_; // only one is set, gets round un-registered class exception
- mutable Family* sourceFamily_;// only one is set, gets round un-registered class exception
- mutable Task* sourceTask_; // only one is set, gets round un-registered class exception
- std::string src_host_;
- std::string src_port_;
- std::string src_path_;
- std::string dest_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< UserCmd >( *this );
- ar & sourceSuite_; // only one is serialised
- ar & sourceFamily_; // only one is serialised
- ar & sourceTask_; // only one is serialised
- ar & src_host_;
- ar & src_port_;
- ar & src_path_;
- ar & dest_;
- }
-};
-
-// The group command allows a series of commands to be be executed:
-//
-// Client---(GroupCTSCmd)---->Server-----(GroupSTCCmd | StcCmd(OK) | Error )--->client:
-//
-// If client->server contains GetDefs cmd and log file commands, then a group
-// command will be created for returning to the client
-//
-// If group command contains multiple [ CtsNodeCmd(GET) | LogCmd --get ] commands then
-// all the results are returned back to the client, HOWEVER when client calls
-// Cmd::defs() | Cmd::get_string() only the first data is returned.
-//
-class GroupCTSCmd : public UserCmd {
-public:
- GroupCTSCmd(const std::string& list_of_commands,AbstractClientEnv* clientEnv);
- GroupCTSCmd(){}
-
- virtual bool isWrite() const;
- virtual PrintStyle::Type_t show_style() const;
- virtual bool get_cmd() const;
- virtual bool task_cmd() const;
- virtual bool terminate_cmd() const;
- virtual bool why_cmd( std::string& ) const;
- virtual bool group_cmd() const { return true; }
-
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ClientToServerCmd*) const;
-
- void addChild(Cmd_ptr childCmd);
- const std::vector<Cmd_ptr>& cmdVec() const { return cmdVec_;}
-
- virtual const char* theArg() const { return arg();}
- virtual void addOption(boost::program_options::options_description& desc) const;
- virtual void create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-private:
- static const char* arg(); // used for argument parsing
- static const char* desc(); // The description of the argument as provided to user
-
- virtual void setup_user_authentification();
- virtual bool authenticate(AbstractServer*, STC_Cmd_ptr&) const;
- virtual STC_Cmd_ptr doHandleRequest(AbstractServer*) const;
-
- std::vector<Cmd_ptr> cmdVec_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< UserCmd >( *this );
- ar & cmdVec_;
- }
-};
-
-std::ostream& operator<<(std::ostream& os, const ServerVersionCmd&);
-std::ostream& operator<<(std::ostream& os, const CtsCmd&);
-std::ostream& operator<<(std::ostream& os, const CtsNodeCmd&);
-std::ostream& operator<<(std::ostream& os, const PathsCmd&);
-std::ostream& operator<<(std::ostream& os, const CheckPtCmd&);
-std::ostream& operator<<(std::ostream& os, const LoadDefsCmd&);
-std::ostream& operator<<(std::ostream& os, const LogCmd&);
-std::ostream& operator<<(std::ostream& os, const LogMessageCmd&);
-std::ostream& operator<<(std::ostream& os, const BeginCmd&);
-std::ostream& operator<<(std::ostream& os, const ZombieCmd&);
-std::ostream& operator<<(std::ostream& os, const InitCmd&);
-std::ostream& operator<<(std::ostream& os, const EventCmd&);
-std::ostream& operator<<(std::ostream& os, const MeterCmd&);
-std::ostream& operator<<(std::ostream& os, const LabelCmd&);
-std::ostream& operator<<(std::ostream& os, const CompleteCmd&);
-std::ostream& operator<<(std::ostream& os, const CtsWaitCmd&);
-std::ostream& operator<<(std::ostream& os, const AbortCmd&);
-std::ostream& operator<<(std::ostream& os, const RequeueNodeCmd&);
-std::ostream& operator<<(std::ostream& os, const OrderNodeCmd&);
-std::ostream& operator<<(std::ostream& os, const RunNodeCmd&);
-std::ostream& operator<<(std::ostream& os, const ReplaceNodeCmd&);
-std::ostream& operator<<(std::ostream& os, const ForceCmd&);
-std::ostream& operator<<(std::ostream& os, const FreeDepCmd&);
-std::ostream& operator<<(std::ostream& os, const CFileCmd&);
-std::ostream& operator<<(std::ostream& os, const PlugCmd&);
-std::ostream& operator<<(std::ostream& os, const AlterCmd&);
-std::ostream& operator<<(std::ostream& os, const MoveCmd&);
-std::ostream& operator<<(std::ostream& os, const GroupCTSCmd&);
-
-BOOST_CLASS_EXPORT_KEY(ServerVersionCmd)
-BOOST_CLASS_EXPORT_KEY(CtsCmd)
-BOOST_CLASS_EXPORT_KEY(CSyncCmd)
-BOOST_CLASS_EXPORT_KEY(ClientHandleCmd)
-BOOST_CLASS_EXPORT_KEY(CtsNodeCmd)
-BOOST_CLASS_EXPORT_KEY(PathsCmd)
-BOOST_CLASS_EXPORT_KEY(CheckPtCmd)
-BOOST_CLASS_EXPORT_KEY(LoadDefsCmd)
-BOOST_CLASS_EXPORT_KEY(LogCmd)
-BOOST_CLASS_EXPORT_KEY(LogMessageCmd)
-BOOST_CLASS_EXPORT_KEY(BeginCmd)
-BOOST_CLASS_EXPORT_KEY(ZombieCmd)
-BOOST_CLASS_EXPORT_KEY(InitCmd)
-BOOST_CLASS_EXPORT_KEY(EventCmd)
-BOOST_CLASS_EXPORT_KEY(MeterCmd)
-BOOST_CLASS_EXPORT_KEY(LabelCmd)
-BOOST_CLASS_EXPORT_KEY(AbortCmd)
-BOOST_CLASS_EXPORT_KEY(CtsWaitCmd)
-BOOST_CLASS_EXPORT_KEY(CompleteCmd)
-BOOST_CLASS_EXPORT_KEY(RequeueNodeCmd)
-BOOST_CLASS_EXPORT_KEY(OrderNodeCmd)
-BOOST_CLASS_EXPORT_KEY(RunNodeCmd)
-BOOST_CLASS_EXPORT_KEY(ReplaceNodeCmd)
-BOOST_CLASS_EXPORT_KEY(ForceCmd)
-BOOST_CLASS_EXPORT_KEY(FreeDepCmd)
-BOOST_CLASS_EXPORT_KEY(CFileCmd)
-BOOST_CLASS_EXPORT_KEY(EditScriptCmd)
-BOOST_CLASS_EXPORT_KEY(PlugCmd)
-BOOST_CLASS_EXPORT_KEY(AlterCmd)
-BOOST_CLASS_EXPORT_KEY(MoveCmd)
-BOOST_CLASS_EXPORT_KEY(GroupCTSCmd)
-BOOST_CLASS_EXPORT_KEY(ShowCmd)
-#endif
diff --git a/ecflow_4_0_7/Base/src/cts/CtsApi.cpp b/ecflow_4_0_7/Base/src/cts/CtsApi.cpp
deleted file mode 100644
index 7b19272..0000000
--- a/ecflow_4_0_7/Base/src/cts/CtsApi.cpp
+++ /dev/null
@@ -1,710 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #76 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : (C)lient (t)o (s)erver API
-//============================================================================
-
-#include <sstream>
-#include <boost/algorithm/string/trim.hpp>
-#include <boost/lexical_cast.hpp>
-
-#include "CtsApi.hpp"
-
-std::string CtsApi::to_string(const std::vector<std::string>& vec) {
- std::string ret;
- for(size_t i = 0; i < vec.size(); i++) { ret += vec[i]; ret += " "; }
- return ret;
-}
-
-std::string CtsApi::server_version() { return std::string("--server_version");}
-const char* CtsApi::server_version_arg() { return "server_version"; }
-
-std::string CtsApi::get(const std::string& absNodePath) {
- std::string ret = "--get";
- if (!absNodePath.empty()) {
- ret += "=";
- ret += absNodePath;
- }
- return ret;
-}
-const char* CtsApi::getArg() { return "get"; }
-
-std::string CtsApi::get_state(const std::string& absNodePath) {
- std::string ret = "--get_state";
- if (!absNodePath.empty()) {
- ret += "=";
- ret += absNodePath;
- }
- return ret;
-}
-const char* CtsApi::get_state_arg() { return "get_state"; }
-
-std::string CtsApi::migrate(const std::string& absNodePath) {
- std::string ret = "--migrate";
- if (!absNodePath.empty()) {
- ret += "=";
- ret += absNodePath;
- }
- return ret;
-}
-const char* CtsApi::migrate_arg() { return "migrate"; }
-
-std::string CtsApi::stats() { return "--stats"; }
-const char* CtsApi::statsArg() { return "stats"; }
-
-std::string CtsApi::stats_reset() { return "--stats_reset"; }
-const char* CtsApi::stats_reset_arg() { return "stats_reset"; }
-
-
-std::string CtsApi::suites() { return "--suites"; }
-const char* CtsApi::suitesArg() { return "suites"; }
-
-std::vector<std::string> CtsApi::ch_register( bool auto_add_new_suites , const std::vector<std::string>& suites )
-{
- std::vector<std::string> retVec; retVec.reserve(suites.size() +1);
- std::string ret = "--ch_register=";
- if ( auto_add_new_suites ) ret += "true";
- else ret += "false";
- retVec.push_back(ret);
- for(size_t i = 0; i < suites.size(); i++) { retVec.push_back(suites[i]);}
- return retVec;
-}
-const char* CtsApi::ch_register_arg() { return "ch_register"; }
-
-std::string CtsApi::ch_suites() { return "--ch_suites";}
-const char* CtsApi::ch_suites_arg() { return "ch_suites"; }
-
-std::string CtsApi::ch_drop(int client_handle)
-{
- std::string ret = "--ch_drop=";
- ret += boost::lexical_cast<std::string>(client_handle);
- return ret;
-}
-const char* CtsApi::ch_drop_arg() { return "ch_drop"; }
-
-std::string CtsApi::ch_drop_user(const std::string& user)
-{
- std::string ret = "--ch_drop_user";
- if (!user.empty()) {
- ret += "=";
- ret += user;
- }
- return ret;
-}
-const char* CtsApi::ch_drop_user_arg() { return "ch_drop_user"; }
-
-std::vector<std::string> CtsApi::ch_add( int client_handle, const std::vector<std::string>& suites )
-{
- std::vector<std::string> retVec; retVec.reserve(suites.size() +1);
- std::string ret = "--ch_add=";
- ret += boost::lexical_cast<std::string>(client_handle);
- retVec.push_back(ret);
- for(size_t i = 0; i < suites.size(); i++) { retVec.push_back(suites[i]);}
- return retVec;
-}
-const char* CtsApi::ch_add_arg() { return "ch_add"; }
-
-std::vector<std::string> CtsApi::ch_remove( int client_handle, const std::vector<std::string>& suites )
-{
- std::vector<std::string> retVec; retVec.reserve(suites.size() +1);
- std::string ret = "--ch_rem=";
- ret += boost::lexical_cast<std::string>(client_handle);
- retVec.push_back(ret);
- for(size_t i = 0; i < suites.size(); i++) { retVec.push_back(suites[i]); }
- return retVec;
-}
-const char* CtsApi::ch_remove_arg() { return "ch_rem"; }
-
-std::vector<std::string> CtsApi::ch_auto_add( int client_handle, bool auto_add_new_suites )
-{
- std::vector<std::string> retVec; retVec.reserve(2);
- std::string ret = "--ch_auto_add=";
- ret += boost::lexical_cast<std::string>(client_handle);
- retVec.push_back(ret);
- if ( auto_add_new_suites ) retVec.push_back("true");
- else retVec.push_back("false");
- return retVec;
-}
-const char* CtsApi::ch_auto_add_arg() { return "ch_auto_add"; }
-
-
-std::vector<std::string> CtsApi::sync(unsigned int client_handle,unsigned int state_change_no, unsigned int modify_change_no )
-{
- std::vector<std::string> retVec; retVec.reserve(3);
- std::string ret = "--sync=";
- ret += boost::lexical_cast<std::string>( client_handle );
- retVec.push_back(ret);
- retVec.push_back(boost::lexical_cast<std::string>( state_change_no ));
- retVec.push_back(boost::lexical_cast<std::string>( modify_change_no ));
- return retVec;
-}
-const char* CtsApi::syncArg() { return "sync"; }
-
-std::string CtsApi::sync_full(unsigned int client_handle) {
- std::string ret = "--sync_full=";
- ret += boost::lexical_cast<std::string>( client_handle );
- return ret;
-}
-const char* CtsApi::sync_full_arg() { return "sync_full";}
-
-std::vector<std::string> CtsApi::news(unsigned int client_handle, unsigned int state_change_no, unsigned int modify_change_no )
-{
- std::vector<std::string> retVec; retVec.reserve(3);
- std::string ret = "--news=";
- ret += boost::lexical_cast<std::string>( client_handle );
- retVec.push_back(ret);
- retVec.push_back(boost::lexical_cast<std::string>( state_change_no ));
- retVec.push_back(boost::lexical_cast<std::string>( modify_change_no ));
- return retVec;
-}
-const char* CtsApi::newsArg() { return "news"; }
-
-std::vector<std::string> CtsApi::loadDefs(const std::string& filePath, bool force, bool check_only) {
-
- std::string ret = "--load="; ret += filePath;
-
- std::vector<std::string> retVec; retVec.reserve(3);
- retVec.push_back(ret);
- if (force) retVec.push_back("force");
- if (check_only) retVec.push_back("check_only");
- return retVec;
-}
-const char* CtsApi::loadDefsArg() { return "load"; }
-
-std::string CtsApi::restartServer() { return "--restart";}
-const char* CtsApi::restartServerArg() { return "restart";}
-
-std::string CtsApi::haltServer(bool auto_confirm) { return (auto_confirm) ? "--halt=yes" : "--halt"; }
-const char* CtsApi::haltServerArg() { return "halt"; }
-
-std::string CtsApi::shutdownServer(bool auto_confirm) { return (auto_confirm) ? "--shutdown=yes" : "--shutdown"; }
-const char* CtsApi::shutdownServerArg() { return "shutdown"; }
-
-std::string CtsApi::terminateServer(bool auto_confirm) { return (auto_confirm) ? "--terminate=yes" : "--terminate";}
-const char* CtsApi::terminateServerArg() { return "terminate";}
-
-std::string CtsApi::pingServer() { return "--ping"; }
-const char* CtsApi::pingServerArg() { return "ping"; }
-
-std::string CtsApi::server_load(const std::string& path_to_log_file)
-{
- std::string ret = "--server_load";
- if (!path_to_log_file.empty()) {
- ret += "=";
- ret += path_to_log_file;
- }
- return ret;
-}
-const char* CtsApi::server_load_arg() { return "server_load"; }
-
-
-std::string CtsApi::debug_server_on() { return "--debug_server_on"; }
-const char* CtsApi::debug_server_on_arg() { return "debug_server_on"; }
-std::string CtsApi::debug_server_off() { return "--debug_server_off"; }
-const char* CtsApi::debug_server_off_arg() { return "debug_server_off"; }
-
-
-std::string CtsApi::begin(const std::string& suiteName, bool force) {
-
- // *both* are optional
- std::string ret = "--begin";
- if (suiteName.empty() && !force) {
- return ret;
- }
- if (!suiteName.empty()) {
- ret += "=";
- ret += suiteName;
- }
- if (force) {
- if (suiteName.empty()) {
- ret += "=--force";
- }
- else {
- ret += " --force"; // note the space separator
- }
- }
- return ret;
-}
-const char* CtsApi::beginArg() { return "begin"; }
-
-
-std::string CtsApi::checkJobGenOnly(const std::string& absNodePath)
-{
- std::string ret = "--checkJobGenOnly";
- if (!absNodePath.empty()) {
- ret += "=";
- ret += absNodePath;
- }
- return ret;
-}
-const char* CtsApi::checkJobGenOnlyArg() { return "checkJobGenOnly";}
-
-
-std::string CtsApi::job_gen(const std::string& absNodePath)
-{
- std::string ret = "--job_gen";
- if (!absNodePath.empty()) {
- ret += "=";
- ret += absNodePath;
- }
- return ret;
-}
-const char* CtsApi::job_genArg() { return "job_gen";}
-
-
-std::vector<std::string> CtsApi::check(const std::vector<std::string>& paths)
-{
- std::vector<std::string> retVec; retVec.reserve(2 + paths.size());
- retVec.push_back("--check");
- if (paths.empty()) retVec.push_back("_all_");
- std::copy(paths.begin(),paths.end(),std::back_inserter(retVec));
- return retVec;
-}
-std::vector<std::string> CtsApi::check(const std::string& path)
-{
- if (path.empty()) {
- return CtsApi::check(std::vector<std::string>());
- }
- return CtsApi::check(std::vector<std::string>(1,path));
-}
-const char* CtsApi::check_arg() { return "check";}
-
-std::vector<std::string> CtsApi::delete_node(const std::vector<std::string>& paths, bool force, bool auto_confirm )
-{
- std::vector<std::string> retVec; retVec.reserve(4 + paths.size());
- retVec.push_back("--delete");
- if (paths.empty()) {
- retVec.push_back("_all_");
- }
- if (force) {
- retVec.push_back("force");
- }
- if (auto_confirm) { // By default delete prompts
- retVec.push_back("yes"); // yes means we don't prompt, and have automatically confirmed the delete
- }
- std::copy(paths.begin(),paths.end(),std::back_inserter(retVec));
- return retVec;
-}
-std::vector<std::string> CtsApi::delete_node(const std::string& absNodePath, bool force, bool auto_confirm )
-{
- if (absNodePath.empty()) return CtsApi::delete_node(std::vector<std::string>(),force,auto_confirm);
- return CtsApi::delete_node(std::vector<std::string>(1,absNodePath),force,auto_confirm);
-}
-const char* CtsApi::delete_node_arg() { return "delete";}
-
-
-std::vector<std::string> CtsApi::suspend(const std::vector<std::string>& paths)
-{
- std::vector<std::string> retVec; retVec.reserve(1 + paths.size());
- retVec.push_back("--suspend");
- std::copy(paths.begin(),paths.end(),std::back_inserter(retVec));
- return retVec;
-}
-std::vector<std::string> CtsApi::suspend(const std::string& path)
-{
- return CtsApi::suspend(std::vector<std::string>(1,path));
-}
-const char* CtsApi::suspend_arg() { return "suspend";}
-
-
-std::vector<std::string> CtsApi::resume(const std::vector<std::string>& paths)
-{
- std::vector<std::string> retVec; retVec.reserve(1 + paths.size());
- retVec.push_back("--resume");
- std::copy(paths.begin(),paths.end(),std::back_inserter(retVec));
- return retVec;
-}
-std::vector<std::string> CtsApi::resume(const std::string& path)
-{
- return CtsApi::resume(std::vector<std::string>(1,path));
-}
-const char* CtsApi::resume_arg() { return "resume";}
-
-
-std::vector<std::string> CtsApi::kill(const std::vector<std::string>& paths)
-{
- std::vector<std::string> retVec; retVec.reserve(1 + paths.size());
- retVec.push_back("--kill");
- std::copy(paths.begin(),paths.end(),std::back_inserter(retVec));
- return retVec;
-}
-std::vector<std::string> CtsApi::kill(const std::string& path)
-{
- return CtsApi::kill(std::vector<std::string>(1,path));
-}
-const char* CtsApi::kill_arg() { return "kill";}
-
-
-std::vector<std::string> CtsApi::status(const std::vector<std::string>& paths)
-{
- std::vector<std::string> retVec; retVec.reserve(1 + paths.size());
- retVec.push_back("--status");
- std::copy(paths.begin(),paths.end(),std::back_inserter(retVec));
- return retVec;
-}
-std::vector<std::string> CtsApi::status(const std::string& path)
-{
- return CtsApi::status(std::vector<std::string>(1,path));
-}
-const char* CtsApi::statusArg() { return "status";}
-
-
-std::vector<std::string> CtsApi::edit_history(const std::vector<std::string>& paths)
-{
- std::vector<std::string> retVec; retVec.reserve(1 + paths.size());
- retVec.push_back("--edit_history");
- std::copy(paths.begin(),paths.end(),std::back_inserter(retVec));
- return retVec;
-}
-std::vector<std::string> CtsApi::edit_history(const std::string& path)
-{
- return CtsApi::edit_history(std::vector<std::string>(1,path));
-}
-const char* CtsApi::edit_history_arg() { return "edit_history";}
-
-
-std::string CtsApi::why(const std::string& absNodePath)
-{
- if ( absNodePath.empty()) return "--why";
- std::string ret = "--why=";
- ret += absNodePath;
- return ret;
-}
-const char* CtsApi::whyArg() { return "why";}
-
-std::string CtsApi::zombieGet() { return "--zombie_get"; }
-const char* CtsApi::zombieGetArg() { return "zombie_get"; }
-
-std::vector<std::string> CtsApi::zombieFob(const std::string& task_path,const std::string& process_id, const std::string& password)
-{
- std::vector<std::string> retVec; retVec.reserve(3);
- std::string ret = "--zombie_fob="; ret += task_path;
- retVec.push_back(ret);
- retVec.push_back(process_id); // Note: order is important, even if empty
- retVec.push_back(password); // Note: order is important, even if empty
- return retVec;
-}
-std::string CtsApi::zombieFobCli(const std::string& path) { std::string ret = "--zombie_fob="; ret += path; return ret;}
-const char* CtsApi::zombieFobArg() { return "zombie_fob";}
-
-std::vector<std::string> CtsApi::zombieFail(const std::string& task_path,const std::string& process_id, const std::string& password)
-{
- std::vector<std::string> retVec; retVec.reserve(3);
- std::string ret = "--zombie_fail="; ret += task_path;
- retVec.push_back(ret);
- retVec.push_back(process_id); // Note: order is important, even if empty
- retVec.push_back(password); // Note: order is important, even if empty
- return retVec;
-}
-std::string CtsApi::zombieFailCli(const std::string& path) { std::string ret = "--zombie_fail="; ret += path; return ret;}
-const char* CtsApi::zombieFailArg() { return "zombie_fail";}
-
-std::vector<std::string> CtsApi::zombieAdopt(const std::string& task_path,const std::string& process_id, const std::string& password)
-{
- std::vector<std::string> retVec; retVec.reserve(3);
- std::string ret = "--zombie_adopt="; ret += task_path;
- retVec.push_back(ret);
- retVec.push_back(process_id); // Note: order is important, even if empty
- retVec.push_back(password); // Note: order is important, even if empty
- return retVec;
-}
-std::string CtsApi::zombieAdoptCli(const std::string& path) { std::string ret = "--zombie_adopt="; ret += path; return ret;}
-const char* CtsApi::zombieAdoptArg() { return "zombie_adopt";}
-
-std::vector<std::string> CtsApi::zombieRemove(const std::string& task_path,const std::string& process_id, const std::string& password)
-{
- std::vector<std::string> retVec; retVec.reserve(3);
- std::string ret = "--zombie_remove="; ret += task_path;
- retVec.push_back(ret);
- retVec.push_back(process_id); // Note: order is important, even if empty
- retVec.push_back(password); // Note: order is important, even if empty
- return retVec;
-}
-std::string CtsApi::zombieRemoveCli(const std::string& path) { std::string ret = "--zombie_remove="; ret += path; return ret;}
-const char* CtsApi::zombieRemoveArg() { return "zombie_remove";}
-
-std::vector<std::string> CtsApi::zombieBlock(const std::string& task_path,const std::string& process_id, const std::string& password)
-{
- std::vector<std::string> retVec; retVec.reserve(3);
- std::string ret = "--zombie_block="; ret += task_path;
- retVec.push_back(ret);
- retVec.push_back(process_id); // Note: order is important, even if empty
- retVec.push_back(password); // Note: order is important, even if empty
- return retVec;
-}
-std::string CtsApi::zombieBlockCli(const std::string& path) { std::string ret = "--zombie_block="; ret += path; return ret;}
-const char* CtsApi::zombieBlockArg() { return "zombie_block";}
-
-
-std::vector<std::string> CtsApi::zombieKill(const std::string& task_path,const std::string& process_id, const std::string& password)
-{
- std::vector<std::string> retVec; retVec.reserve(3);
- std::string ret = "--zombie_kill="; ret += task_path;
- retVec.push_back(ret);
- retVec.push_back(process_id); // Note: order is important, even if empty
- retVec.push_back(password); // Note: order is important, even if empty
- return retVec;
-}
-std::string CtsApi::zombieKillCli(const std::string& path) { std::string ret = "--zombie_kill="; ret += path; return ret;}
-const char* CtsApi::zombieKillArg() { return "zombie_kill";}
-
-
-std::vector<std::string> CtsApi::requeue(const std::vector<std::string>& paths, const std::string& option)
-{
- std::vector<std::string> retVec; retVec.reserve(2 + paths.size());
- retVec.push_back("--requeue");
- if (!option.empty()) retVec.push_back(option);
- std::copy(paths.begin(),paths.end(),std::back_inserter(retVec));
- return retVec;
-}
-std::vector<std::string> CtsApi::requeue(const std::string& absNodePath, const std::string& option)
-{
- return CtsApi::requeue(std::vector<std::string>(1,absNodePath),option);
-}
-const char* CtsApi::requeueArg() { return "requeue"; }
-
-std::vector<std::string> CtsApi::run(const std::vector<std::string>& paths, bool force)
-{
- std::vector<std::string> retVec; retVec.reserve(paths.size()+2);
- retVec.push_back("--run");
- if (force) retVec.push_back("force");
- std::copy(paths.begin(),paths.end(),std::back_inserter(retVec));
- return retVec;
-}
-std::vector<std::string> CtsApi::run(const std::string& absNodePath, bool force)
-{
- return CtsApi::run(std::vector<std::string>(1,absNodePath),force);
-}
-const char* CtsApi::runArg() { return "run"; }
-
-
-std::vector<std::string> CtsApi::order(const std::string& absNodePath,const std::string& orderType)
-{
- std::vector<std::string> retVec; retVec.reserve(2);
- std::string ret = "--order="; ret += absNodePath;
- retVec.push_back(ret);
- retVec.push_back(orderType);
- return retVec;
-}
-const char* CtsApi::orderArg() { return "order"; }
-
-
-std::vector<std::string> CtsApi::replace( const std::string& absNodePath,
- const std::string& path_to_client_defs,
- bool create_parents_as_required,
- bool force)
-{
- std::vector<std::string> retVec; retVec.reserve(3);
-
- std::string ret = "--replace="; ret += absNodePath;
- retVec.push_back(ret);
- retVec.push_back(path_to_client_defs);
- if (create_parents_as_required) retVec.push_back("parent");
- if (force) retVec.push_back("force");
-
- return retVec;
-}
-const char* CtsApi::replace_arg() { return "replace"; }
-
-
-std::string CtsApi::checkPtDefs(ecf::CheckPt::Mode m, int check_pt_interval, int check_pt_save_time_alarm)
-{
- std::string ret = "--check_pt";
- if (m != ecf::CheckPt::UNDEFINED || check_pt_interval != 0 || check_pt_save_time_alarm != 0) ret += "=";
-
- switch (m) {
- case ecf::CheckPt::NEVER: ret += "never"; break;
- case ecf::CheckPt::ON_TIME: ret += "on_time"; break;
- case ecf::CheckPt::ALWAYS: ret += "always"; break;
- case ecf::CheckPt::UNDEFINED: break; // leave empty
- default: assert(false); break;
- }
-
- if (check_pt_interval != 0) {
- if (m != ecf::CheckPt::UNDEFINED) ret += ":";
- ret += boost::lexical_cast<std::string>(check_pt_interval);
- }
- else {
- if (m == ecf::CheckPt::UNDEFINED && check_pt_save_time_alarm != 0) {
- ret += "alarm:";
- ret += boost::lexical_cast<std::string>(check_pt_save_time_alarm);
- }
- }
- return ret;
-}
-const char* CtsApi::checkPtDefsArg() { return "check_pt"; }
-
-std::string CtsApi::restoreDefsFromCheckPt() { return "--restore_from_checkpt"; }
-const char* CtsApi::restoreDefsFromCheckPtArg(){ return "restore_from_checkpt"; }
-
-
-std::string CtsApi::logMsg(const std::string& theMsgToLog) {
- std::string ret = "--msg=";
- ret += theMsgToLog;
- return ret;
-}
-const char* CtsApi::logMsgArg() { return "msg"; }
-
-
-std::vector<std::string> CtsApi::force( const std::vector<std::string>& paths,
- const std::string& state_or_event,
- bool recursive,
- bool set_repeats_to_last_value)
-{
- std::vector<std::string> retVec; retVec.reserve(paths.size() + 3);
-
- std::string ret = "--force="; ret += state_or_event;
- retVec.push_back(ret);
- if (recursive) retVec.push_back("recursive");
- if (set_repeats_to_last_value) retVec.push_back("full");
- std::copy(paths.begin(),paths.end(),std::back_inserter(retVec));
- return retVec;
-}
-
-std::vector<std::string> CtsApi::force( const std::string& path,
- const std::string& state_or_event,
- bool recursive,
- bool set_repeats_to_last_value)
-{
- return CtsApi::force(std::vector<std::string>(1,path),state_or_event,recursive,set_repeats_to_last_value);
-}
-const char* CtsApi::forceArg() { return "force"; }
-
-
-std::vector<std::string> CtsApi::freeDep(const std::vector<std::string>& paths,bool trigger, bool all, bool date, bool time) {
-
- std::vector<std::string> retVec; retVec.reserve(paths.size() + 4);
-
- retVec.push_back("--free-dep");
- if (all) retVec.push_back("all");
- else {
- if (trigger) retVec.push_back("trigger");
- if (date) retVec.push_back("date");
- if (time) retVec.push_back("time");
- }
- std::copy(paths.begin(),paths.end(),std::back_inserter(retVec));
- return retVec;
-}
-std::vector<std::string> CtsApi::freeDep(const std::string& path,bool trigger, bool all, bool date, bool time) {
-
- return CtsApi::freeDep(std::vector<std::string>(1,path),trigger,all,date,time);
-}
-const char* CtsApi::freeDepArg() { return "free-dep"; }
-
-
-std::vector<std::string> CtsApi::file(const std::string& absNodePath, const std::string& fileType, const std::string& max_lines)
-{
- std::vector<std::string> retVec; retVec.reserve(3);
- std::string ret = "--file="; ret += absNodePath;
- retVec.push_back(ret);
- retVec.push_back(fileType);
- retVec.push_back(max_lines);
- return retVec;
-}
-const char* CtsApi::fileArg() { return "file"; }
-
-
-std::vector<std::string> CtsApi::plug(const std::string& sourcePath, const std::string& destPath)
-{
- std::vector<std::string> retVec; retVec.reserve(2);
-
- std::string ret = "--plug="; ret += sourcePath;
- retVec.push_back(ret);
- retVec.push_back(destPath);
-
- return retVec;
-}
-const char* CtsApi::plugArg() { return "plug"; }
-
-std::vector<std::string> CtsApi::alter(
- const std::vector<std::string>& paths,
- const std::string& alterType,
- const std::string& attrType,
- const std::string& name,
- const std::string& value)
-{
- std::vector<std::string> retVec; retVec.reserve(5 + paths.size());
-
- retVec.push_back("--alter");
- retVec.push_back(alterType);
- retVec.push_back(attrType);
- if ( !name.empty() ) retVec.push_back(name);
- if ( !value.empty() ) retVec.push_back(value);
- std::copy(paths.begin(),paths.end(),std::back_inserter(retVec));
- return retVec;
-}
-std::vector<std::string> CtsApi::alter(
- const std::string& path,
- const std::string& alterType,
- const std::string& attrType,
- const std::string& name,
- const std::string& value)
-{
- return CtsApi::alter(std::vector<std::string>(1,path),alterType,attrType,name,value);
-}
-const char* CtsApi::alterArg() { return "alter"; }
-
-
-std::string CtsApi::reloadwsfile() { return "--reloadwsfile"; }
-const char* CtsApi::reloadwsfileArg() { return "reloadwsfile"; }
-
-std::string CtsApi::group(const std::string& cmds) {
- std::string ret = "--group=";
- ret += cmds;
- return ret;
-}
-const char* CtsApi::groupArg() { return "group"; }
-
-std::vector<std::string> CtsApi::getLog(int lastLine) {
- std::vector<std::string> retVec; retVec.reserve(2);
- retVec.push_back("--log=get");
- if (lastLine != 0) {
- std::stringstream ss; ss << lastLine;
- retVec.push_back(ss.str());
- }
- return retVec;
-}
-std::vector<std::string> CtsApi::new_log(const std::string& new_path) {
- std::vector<std::string> retVec; retVec.reserve(2);
- retVec.push_back("--log=new");
- if (!new_path.empty()) retVec.push_back(new_path);
- return retVec;
-}
-std::string CtsApi::clearLog() { return "--log=clear"; }
-std::string CtsApi::flushLog() { return "--log=flush"; }
-std::string CtsApi::get_log_path() { return "--log=path"; }
-
-
-std::string CtsApi::forceDependencyEval() { return "--force-dep-eval";}
-const char* CtsApi::forceDependencyEvalArg() { return "force-dep-eval";}
-
-
-std::vector<std::string> CtsApi::edit_script(
- const std::string& path_to_task,
- const std::string& edit_type,
- const std::string& path_to_script,
- bool create_alias,
- bool run
- )
-{
- std::vector<std::string> retVec;
- std::string ret = "--edit_script=";
- ret += path_to_task;
- retVec.push_back(ret);
- retVec.push_back(edit_type);
- if (!path_to_script.empty()) retVec.push_back(path_to_script);
- if (create_alias) retVec.push_back("create_alias");
- if (!run) retVec.push_back("no_run");
- return retVec;
-}
-const char* CtsApi::edit_script_arg() { return "edit_script";}
-
diff --git a/ecflow_4_0_7/Base/src/cts/CtsApi.hpp b/ecflow_4_0_7/Base/src/cts/CtsApi.hpp
deleted file mode 100644
index d6c5c00..0000000
--- a/ecflow_4_0_7/Base/src/cts/CtsApi.hpp
+++ /dev/null
@@ -1,216 +0,0 @@
-#ifndef CTS_API_HPP_
-#define CTS_API_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #74 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : (C)lient (t)o (s)erver API
-//============================================================================
-#include <boost/noncopyable.hpp>
-#include <boost/shared_ptr.hpp>
-#include <string>
-#include <vector>
-#include "NodeFwd.hpp"
-#include "CheckPt.hpp"
-
-// The two variant api must correspond i.e '--get' and 'get' since this is used by boost program options
-// *************************************************************************************
-// Note:: if the api requires multiple parameters it must return a std::vector<std::string>
-// ***************************************************************************************
-class CtsApi : private boost::noncopyable {
-public:
- static std::string to_string(const std::vector<std::string>& );
-
- static std::string server_version();
-
- // For python
- static defs_ptr load( defs_ptr defs) { return defs;}
- static std::vector<std::string> loadDefs(const std::string& filePath,bool force,bool check_only);
- static std::string get(const std::string& absNodePath = "");
- static std::string get_state(const std::string& absNodePath = "");
- static std::string migrate(const std::string& absNodePath = "");
- static std::vector<std::string> sync(unsigned int client_handle, unsigned int state_change_no, unsigned int modify_change_no );
- static std::string sync_full(unsigned int client_handle);
- static std::vector<std::string> news(unsigned int client_handle, unsigned int state_change_no, unsigned int modify_change_no );
-
- static std::vector<std::string> ch_register( bool auto_add_new_suites, const std::vector<std::string>& suites);
- static std::string ch_suites();
- static std::string ch_drop(int client_handle);
- static std::string ch_drop_user(const std::string& user);
- static std::vector<std::string> ch_add(int client_handle, const std::vector<std::string>& suites);
- static std::vector<std::string> ch_remove(int client_handle, const std::vector<std::string>& suites);
- static std::vector<std::string> ch_auto_add(int client_handle, bool auto_add_new_suites);
- static std::string suites(); // returns list if all suites, and client handles.
-
- static std::string restartServer();
- static std::string haltServer(bool auto_confirm = true);
- static std::string shutdownServer(bool auto_confirm = true);
- static std::string terminateServer(bool auto_confirm = true);
- static std::string pingServer();
- static std::string server_load(const std::string& path_to_log_file);
- static std::string debug_server_on();
- static std::string debug_server_off();
-
- // odd one out, take multi-args but expects string
- static std::string begin(const std::string& suiteName = "", bool force = false); // no suite begins all suites
-
- static std::string job_gen(const std::string& absNodePath = "");
- static std::string checkJobGenOnly(const std::string& absNodePath = "");
-
- static std::vector<std::string> check(const std::string& absNodePath = "");
- static std::vector<std::string> check(const std::vector<std::string>& paths);
- static std::vector<std::string> delete_node(const std::vector<std::string>& paths, bool force = false, bool auto_confirm = true); // no paths specified ,delete all suites, for test
- static std::vector<std::string> delete_node(const std::string& absNodePath = "", bool force = false, bool auto_confirm = true); // no node specified ,delete all suites, for test
- static std::vector<std::string> suspend(const std::string& absNodePath);
- static std::vector<std::string> suspend(const std::vector<std::string>& paths);
- static std::vector<std::string> resume(const std::string& absNodePath);
- static std::vector<std::string> resume(const std::vector<std::string>& paths);
- static std::vector<std::string> kill(const std::string& absNodePath);
- static std::vector<std::string> kill(const std::vector<std::string>& paths);
- static std::vector<std::string> status(const std::string& absNodePath);
- static std::vector<std::string> status(const std::vector<std::string>& paths);
- static std::vector<std::string> edit_history(const std::vector<std::string>& paths);
- static std::vector<std::string> edit_history(const std::string& absNodePath);
-
- static std::string why(const std::string& absNodePath);
- static std::string zombieGet();
- static std::vector<std::string> zombieFob(const std::string& task_path,const std::string& process_id, const std::string& password);
- static std::vector<std::string> zombieFail(const std::string& task_path,const std::string& process_id, const std::string& password);
- static std::vector<std::string> zombieAdopt(const std::string& task_path,const std::string& process_id, const std::string& password);
- static std::vector<std::string> zombieRemove(const std::string& task_path,const std::string& process_id, const std::string& password);
- static std::vector<std::string> zombieBlock(const std::string& task_path,const std::string& process_id, const std::string& password);
- static std::vector<std::string> zombieKill(const std::string& task_path,const std::string& process_id, const std::string& password);
- static std::string zombieFobCli(const std::string& task_path);
- static std::string zombieFailCli(const std::string& task_path);
- static std::string zombieAdoptCli(const std::string& task_path);
- static std::string zombieRemoveCli(const std::string& task_path);
- static std::string zombieBlockCli(const std::string& task_path);
- static std::string zombieKillCli(const std::string& task_path);
-
- static std::vector<std::string> replace( const std::string& absNodePath,
- const std::string& path_to_client_defs,
- bool create_parents_as_required = true,
- bool force = false);
- static std::vector<std::string> requeue(const std::vector<std::string>& paths, const std::string& option/* [ "" | "force" | "abort" ] */);
- static std::vector<std::string> requeue(const std::string& absNodePath, const std::string& option/* [ "" | "force" | "abort" ] */);
- static std::vector<std::string> run(const std::vector<std::string>& paths,bool force = false);
- static std::vector<std::string> run(const std::string& absNodePath,bool force = false);
- static std::vector<std::string> order(const std::string& absNodePath,const std::string& orderType);
-
- static std::string checkPtDefs(ecf::CheckPt::Mode m = ecf::CheckPt::UNDEFINED, int check_pt_interval = 0, int check_pt_save_time_alarm = 0);
- static std::string restoreDefsFromCheckPt();
-
- static std::vector<std::string> force(const std::vector<std::string>& paths,const std::string& state_or_event,bool recursive = false,bool set_repeats_to_last_value = false);
- static std::vector<std::string> force(const std::string& path,const std::string& state_or_event,bool recursive = false,bool set_repeats_to_last_value = false);
-
- static std::vector<std::string> freeDep(const std::vector<std::string>& paths,bool trigger = true, bool all = false, bool date = false, bool time = false);
- static std::vector<std::string> freeDep(const std::string& absNodePath,bool trigger = true, bool all = false, bool date = false, bool time = false);
-
- static std::vector<std::string> file(const std::string& absNodePath, const std::string& fileType, const std::string& max_lines);
- static std::vector<std::string> plug(const std::string& sourcePath, const std::string& destPath);
-
- static std::vector<std::string> alter(const std::string& path,
- const std::string& alterType, /* one of [ 'add' | 'change' | 'delete' | 'set_flag' | 'clear_flag' ] */
- const std::string& attrType,
- const std::string& name = "",
- const std::string& value = "");
- static std::vector<std::string> alter(const std::vector<std::string>& paths,
- const std::string& alterType, /* one of [ 'add' | 'change' | 'delete' | 'set_flag' | 'clear_flag' ] */
- const std::string& attrType,
- const std::string& name = "",
- const std::string& value = "");
-
- static std::string reloadwsfile();
-
- // "expect string of the form "shutdown; get" must be ';' separated
- static std::string group(const std::string& cmds);
-
- static std::string logMsg(const std::string& theMsgToLog);
- static std::vector<std::string> getLog(int lastLines = 0);
- static std::vector<std::string> new_log(const std::string& new_path);
- static std::string get_log_path();
- static std::string clearLog();
- static std::string flushLog();
- static std::string forceDependencyEval();
-
- static std::string stats();
- static std::string stats_reset();
- static std::vector<std::string> edit_script(const std::string& path_to_task,
- const std::string& edit_type,
- const std::string& path_to_script = "",
- bool create_alias = false,
- bool run = true);
-
- // Only to be used in Cmd
- static const char* server_version_arg();
- static const char* statsArg();
- static const char* stats_reset_arg();
- static const char* suitesArg();
- static const char* ch_register_arg();
- static const char* ch_drop_arg();
- static const char* ch_suites_arg();
- static const char* ch_drop_user_arg();
- static const char* ch_add_arg();
- static const char* ch_remove_arg();
- static const char* ch_auto_add_arg();
-
- static const char* terminateServerArg();
- static const char* restartServerArg();
- static const char* haltServerArg();
- static const char* shutdownServerArg();
- static const char* pingServerArg();
- static const char* server_load_arg();
- static const char* debug_server_on_arg();
- static const char* debug_server_off_arg();
-
- static const char* getArg();
- static const char* get_state_arg();
- static const char* migrate_arg();
- static const char* syncArg();
- static const char* sync_full_arg();
- static const char* newsArg();
- static const char* loadDefsArg();
- static const char* beginArg();
- static const char* job_genArg();
- static const char* check_arg();
- static const char* checkJobGenOnlyArg();
- static const char* delete_node_arg();
- static const char* suspend_arg();
- static const char* resume_arg();
- static const char* kill_arg();
- static const char* statusArg();
- static const char* edit_history_arg();
- static const char* whyArg();
- static const char* zombieGetArg();
- static const char* zombieFobArg();
- static const char* zombieFailArg();
- static const char* zombieAdoptArg();
- static const char* zombieRemoveArg();
- static const char* zombieBlockArg();
- static const char* zombieKillArg();
- static const char* replace_arg();
- static const char* requeueArg();
- static const char* runArg();
- static const char* orderArg();
- static const char* checkPtDefsArg();
- static const char* restoreDefsFromCheckPtArg();
- static const char* logMsgArg();
- static const char* forceArg();
- static const char* freeDepArg();
- static const char* fileArg();
- static const char* plugArg();
- static const char* reloadwsfileArg();
- static const char* groupArg();
- static const char* forceDependencyEvalArg();
- static const char* alterArg();
- static const char* edit_script_arg();
-};
-#endif
diff --git a/ecflow_4_0_7/Base/src/cts/CtsCmd.cpp b/ecflow_4_0_7/Base/src/cts/CtsCmd.cpp
deleted file mode 100644
index 3be6910..0000000
--- a/ecflow_4_0_7/Base/src/cts/CtsCmd.cpp
+++ /dev/null
@@ -1,390 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #81 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/lexical_cast.hpp>
-
-#include "ClientToServerCmd.hpp"
-#include "AbstractServer.hpp"
-#include "AbstractClientEnv.hpp"
-#include "CtsApi.hpp"
-#include "Jobs.hpp"
-#include "JobsParam.hpp"
-#include "Defs.hpp"
-#include "Log.hpp"
-#include "Ecf.hpp"
-#include "Gnuplot.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-namespace po = boost::program_options;
-
-// *IMPORTANT*: STATS_RESET was introduced in release 4.0.5
-
-std::ostream& CtsCmd::print(std::ostream& os) const
-{
- switch (api_) {
- case CtsCmd::GET_ZOMBIES: return user_cmd(os,CtsApi::zombieGet()); break;
- case CtsCmd::RESTORE_DEFS_FROM_CHECKPT: return user_cmd(os,CtsApi::restoreDefsFromCheckPt()); break;
- case CtsCmd::RESTART_SERVER: return user_cmd(os,CtsApi::restartServer()); break;
- case CtsCmd::SHUTDOWN_SERVER: return user_cmd(os,CtsApi::shutdownServer()); break;
- case CtsCmd::HALT_SERVER: return user_cmd(os,CtsApi::haltServer()); break;
- case CtsCmd::TERMINATE_SERVER: return user_cmd(os,CtsApi::terminateServer()); break;
- case CtsCmd::RELOAD_WHITE_LIST_FILE: return user_cmd(os,CtsApi::reloadwsfile()); break;
- case CtsCmd::FORCE_DEP_EVAL: return user_cmd(os,CtsApi::forceDependencyEval()); break;
- case CtsCmd::PING: return user_cmd(os,CtsApi::pingServer()); break;
- case CtsCmd::STATS: return user_cmd(os,CtsApi::stats()); break;
- case CtsCmd::STATS_RESET: return user_cmd(os,CtsApi::stats_reset()); break;
- case CtsCmd::SUITES: return user_cmd(os,CtsApi::suites()); break;
- case CtsCmd::DEBUG_SERVER_ON: return user_cmd(os,CtsApi::debug_server_on()); break;
- case CtsCmd::DEBUG_SERVER_OFF: return user_cmd(os,CtsApi::debug_server_off()); break;
- case CtsCmd::SERVER_LOAD: return user_cmd(os,CtsApi::server_load("")); break;
- case CtsCmd::NO_CMD: assert(false); break;
- default: assert(false); break;
- }
- return os;
-}
-
-bool CtsCmd::equals(ClientToServerCmd* rhs) const
-{
- CtsCmd* the_rhs = dynamic_cast< CtsCmd* > ( rhs );
- if ( !the_rhs ) return false;
- if (api_ != the_rhs->api()) return false;
- return UserCmd::equals(rhs);
-}
-
-bool CtsCmd::isWrite() const
-{
- switch (api_) {
- case CtsCmd::GET_ZOMBIES: return false; break; // read only
- case CtsCmd::RESTORE_DEFS_FROM_CHECKPT: return true; break; // requires write privilege
- case CtsCmd::RESTART_SERVER: return true; break; // requires write privilege
- case CtsCmd::SHUTDOWN_SERVER: return true; break; // requires write privilege
- case CtsCmd::HALT_SERVER: return true; break; // requires write privilege
- case CtsCmd::TERMINATE_SERVER: return true; break; // requires write privilege
- case CtsCmd::RELOAD_WHITE_LIST_FILE:return true; break; // requires write privilege
- case CtsCmd::FORCE_DEP_EVAL: return true; break; // requires write privilege
- case CtsCmd::PING: return false; break; // read only
- case CtsCmd::STATS: return false; break; // read only
- case CtsCmd::STATS_RESET: return true; break; // requires write privilege
- case CtsCmd::SUITES: return false; break; // read only
- case CtsCmd::DEBUG_SERVER_ON: return false; break; // read only
- case CtsCmd::DEBUG_SERVER_OFF: return false; break; // read only
- case CtsCmd::SERVER_LOAD: return false; break; // read only
- case CtsCmd::NO_CMD: assert(false); break;
- default: assert(false); break;
- }
- assert(false);
- return false;
-}
-
-int CtsCmd::timeout() const
-{
- if (api_ == CtsCmd::PING) return 10;
- return ClientToServerCmd::timeout();
-}
-
-const char* CtsCmd::theArg() const
-{
- switch (api_) {
- case CtsCmd::GET_ZOMBIES: return CtsApi::zombieGetArg(); break;
- case CtsCmd::RESTORE_DEFS_FROM_CHECKPT: return CtsApi::restoreDefsFromCheckPtArg(); break;
- case CtsCmd::RESTART_SERVER: return CtsApi::restartServerArg(); break;
- case CtsCmd::SHUTDOWN_SERVER: return CtsApi::shutdownServerArg(); break;
- case CtsCmd::HALT_SERVER: return CtsApi::haltServerArg(); break;
- case CtsCmd::TERMINATE_SERVER: return CtsApi::terminateServerArg(); break;
- case CtsCmd::RELOAD_WHITE_LIST_FILE:return CtsApi::reloadwsfileArg(); break;
- case CtsCmd::FORCE_DEP_EVAL: return CtsApi::forceDependencyEvalArg(); break;
- case CtsCmd::PING: return CtsApi::pingServerArg(); break;
- case CtsCmd::STATS: return CtsApi::statsArg(); break;
- case CtsCmd::STATS_RESET: return CtsApi::stats_reset_arg(); break;
- case CtsCmd::SUITES: return CtsApi::suitesArg(); break;
- case CtsCmd::DEBUG_SERVER_ON: return CtsApi::debug_server_on_arg(); break;
- case CtsCmd::DEBUG_SERVER_OFF: return CtsApi::debug_server_off_arg(); break;
- case CtsCmd::SERVER_LOAD: return CtsApi::server_load_arg(); break;
- case CtsCmd::NO_CMD: assert(false); break;
- default: assert(false); break;
- }
- assert(false);
- return NULL;
-}
-
-STC_Cmd_ptr CtsCmd::doHandleRequest(AbstractServer* as) const
-{
- switch (api_) {
- case CtsCmd::GET_ZOMBIES: {
- as->update_stats().zombie_get_++;
- return PreAllocatedReply::zombie_get_cmd( as );
- }
-
- case CtsCmd::RESTORE_DEFS_FROM_CHECKPT: {
- as->update_stats().restore_defs_from_checkpt_++;
- as->restore_defs_from_checkpt(); // this can throw, i.e. if server not halted, or defs has suites, etc
- break;
- }
-
- case CtsCmd::RESTART_SERVER: {
- as->update_stats().restart_server_++;
- as->restart();
- return doJobSubmission( as );
- }
- case CtsCmd::SHUTDOWN_SERVER: as->update_stats().shutdown_server_++; as->shutdown(); break;
- case CtsCmd::HALT_SERVER: as->update_stats().halt_server_++; as->halted(); break;
- case CtsCmd::TERMINATE_SERVER: as->checkPtDefs(); break;
- case CtsCmd::RELOAD_WHITE_LIST_FILE: {
- as->update_stats().reload_white_list_file_++;
- std::string errorMsg;
- if (!as->reloadWhiteListFile(errorMsg)) {
- throw std::runtime_error( errorMsg ) ;
- }
- break;
- }
- case CtsCmd::FORCE_DEP_EVAL: {
- // The Default JobsParam does *not* allow Job creation, & hence => does not submit jobs
- // The default does *not* allow job spawning
- Jobs jobs(as->defs());
- JobsParam jobsParam; // create jobs = false, spawn_jobs = false
- if (!jobs.generate(jobsParam)) throw std::runtime_error( jobsParam.getErrorMsg() ) ;
- break;
- }
- case CtsCmd::PING: as->update_stats().ping_++; break;
- case CtsCmd::STATS: as->update_stats().stats_++; return PreAllocatedReply::stats_cmd( as ); break;
- case CtsCmd::STATS_RESET: as->update_stats().reset(); break; // we could have done as->update_stats().stats_++, to honor reset, we dont
- case CtsCmd::SUITES: as->update_stats().suites_++; return PreAllocatedReply::suites_cmd( as ); break;
- case CtsCmd::DEBUG_SERVER_ON: as->update_stats().debug_server_on_++; as->debug_server_on(); break;
- case CtsCmd::DEBUG_SERVER_OFF: as->update_stats().debug_server_off_++; as->debug_server_off(); break;
- case CtsCmd::SERVER_LOAD: { as->update_stats().server_load_cmd_++;
- if (Log::instance()) {
- return PreAllocatedReply::server_load_cmd( Log::instance()->path() );
- }
- break;
- }
- case CtsCmd::NO_CMD: assert(false); break;
- default: assert(false); break;
- }
-
- return PreAllocatedReply::ok_cmd();
-}
-
-static const char* server_load_desc() {
- /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
- return
- "Shows the server load graphically, by parsing the log file.\n"
- "If no log file is provided, then the log file path is obtained from\n"
- "the server. *If* this file is accessible from the client, then a\n"
- "graphical view of the server load is shown.\n"
- "This command assumes that gnuplot is available on $PATH. This command\n"
- "produces two files in the CWD 'gnuplot.dat' and 'gnuplot.script'.\n"
- "This generated script can be manually changed, to see different rendering\n"
- "effects. i.e. just run 'gnuplot gnuplot.script'\n\n"
- " arg1 = <optional> path to log file\n"
- "If the path to log file is known, it is *preferable* to use this,\n"
- "rather than requesting the log path from the server.\n"
- "Usage:\n"
- " --server_load=/path/to_log_file # parses log and shows a gnuplot window\n"
- " --server_load # log file path is requested from server\n"
- " # which is then used to produce gnuplot window\n"
- " # *AVOID* if log file path is accessible"
- ;
-}
-
-void CtsCmd::addOption(boost::program_options::options_description& desc) const
-{
- switch (api_) {
- case CtsCmd::GET_ZOMBIES:{
- desc.add_options()(CtsApi::zombieGetArg(),
- "Returns the list of zombies from the server.\n"
- "Results reported to standard output."
- );
- break;
- }
- case CtsCmd::RESTORE_DEFS_FROM_CHECKPT:{
- desc.add_options()(CtsApi::restoreDefsFromCheckPtArg(),
- "Ask the server to load the definition from an check pt file.\n"
- "The server must be halted and the definition in the server must be deleted\n"
- "first, otherwise an error is returned"
- );
- break;
- }
- case CtsCmd::RESTART_SERVER:{
- desc.add_options()( CtsApi::restartServerArg(),
- "Start job scheduling, communication with jobs, and respond to all requests.\n"
- "The following table shows server behaviour in the different states.\n"
- "|----------------------------------------------------------------------------------|\n"
- "| Server State | User Request | Task Request |Job Scheduling | Auto-Check-pointing |\n"
- "|--------------|--------------|--------------|---------------|---------------------|\n"
- "| RUNNING | yes | yes | yes | yes |\n"
- "| SHUTDOWN | yes | yes | no | yes |\n"
- "| HALTED | yes | no | no | no |\n"
- "|--------------|--------------|--------------|---------------|---------------------|"
- );
- break;
- }
- case CtsCmd::SHUTDOWN_SERVER: {
- desc.add_options()( CtsApi::shutdownServerArg(),po::value< string >()->implicit_value( string("") ),
- "Stop server from scheduling new jobs.\n"
- " arg1 = yes(optional) # use to bypass confirmation prompt\n"
- "The following table shows server behaviour in the different states.\n"
- "|----------------------------------------------------------------------------------|\n"
- "| Server State | User Request | Task Request |Job Scheduling | Auto-Check-pointing |\n"
- "|--------------|--------------|--------------|---------------|---------------------|\n"
- "| RUNNING | yes | yes | yes | yes |\n"
- "| SHUTDOWN | yes | yes | no | yes |\n"
- "| HALTED | yes | no | no | no |\n"
- "|--------------|--------------|--------------|---------------|---------------------|"
- );
- break;
- }
- case CtsCmd::HALT_SERVER: {
- desc.add_options()( CtsApi::haltServerArg(),po::value< string >()->implicit_value( string("") ),
- "Stop server communication with jobs, and new job scheduling.\n"
- "Also stops automatic check pointing\n"
- " arg1 = yes(optional) # use to bypass confirmation prompt\n"
- "The following table shows server behaviour in the different states.\n"
- "|----------------------------------------------------------------------------------|\n"
- "| Server State | User Request | Task Request |Job Scheduling | Auto-Check-pointing |\n"
- "|--------------|--------------|--------------|---------------|---------------------|\n"
- "| RUNNING | yes | yes | yes | yes |\n"
- "| SHUTDOWN | yes | yes | no | yes |\n"
- "| HALTED | yes | no | no | no |\n"
- "|--------------|--------------|--------------|---------------|---------------------|"
- );
- break;
- }
- case CtsCmd::TERMINATE_SERVER:{
- desc.add_options()( CtsApi::terminateServerArg(),po::value< string >()->implicit_value( string("") ),
- "Terminate the server.\n"
- " arg1 = yes(optional) # use to bypass confirmation prompt"
- );
- break;
- }
- case CtsCmd::RELOAD_WHITE_LIST_FILE:{
- desc.add_options()( CtsApi::reloadwsfileArg(),
- "Reload the white list file.\n"
- "The white list file is used to authenticate 'user' commands.\n"
- "Raises an error if file does not exist, or fails to parse\n"
- "Expected format for this file is:\n\n"
- "# comment\n"
- "4.4.14 # version number\n\n"
- "# Users with read/write access\n"
- "user1 # comment\n"
- "user2 # comment\n\n"
- "# Users with read access, must have - before user name\n"
- "-user3 # comment\n"
- "-user4"
- );
- break;
- }
- case CtsCmd::FORCE_DEP_EVAL:{
- desc.add_options()( CtsApi::forceDependencyEvalArg(),
- "Force dependency evaluation. Used for DEBUG only."
- );
- break;
- }
- case CtsCmd::PING:{
- desc.add_options()( CtsApi::pingServerArg(),
- "Check if server is running on given host/port. Result reported to standard output.\n"
- "Usage:\n"
- " --ping --host=mach --port=3144 # Check if server alive on host mach & port 3144\n"
- " --ping --host=fred # Check if server alive on host fred and port ECF_PORT,\n"
- " # otherwise default port of 3141\n"
- " --ping # Check if server alive by using environment variables\n"
- " # ECF_NODE and ECF_PORT\n"
- "If ECF_NODE not defined uses 'localhost', if ECF_PORT not defined assumes 3141"
- );
- break;
- }
- case CtsCmd::STATS:{
- desc.add_options()( CtsApi::statsArg(),
- "Returns the server statistics."
- );
- break;
- }
- case CtsCmd::STATS_RESET:{
- desc.add_options()( CtsApi::stats_reset_arg(),
- "Resets the server statistics."
- );
- break;
- }
- case CtsCmd::SUITES:{
- desc.add_options()( CtsApi::suitesArg(),
- "Returns the list of suites, in the order defined in the server."
- );
- break;
- }
- case CtsCmd::DEBUG_SERVER_ON: {
- desc.add_options()( CtsApi::debug_server_on_arg(),
- "Enables debug output from the server"
- );
- break;
- }
- case CtsCmd::DEBUG_SERVER_OFF: {
- desc.add_options()( CtsApi::debug_server_off_arg(),
- "Disables debug output from the server"
- );
- break;
- }
- case CtsCmd::SERVER_LOAD: {
- desc.add_options()( CtsApi::server_load_arg(),po::value< std::string >()->implicit_value( string("") ), server_load_desc() );
- break;
- }
- case CtsCmd::NO_CMD: assert(false); break;
- default: assert(false); break;
- }
-}
-
-bool CtsCmd::handleRequestIsTestable() const {
- if (api_ == CtsCmd::TERMINATE_SERVER) return false;
- if (api_ == CtsCmd::RESTORE_DEFS_FROM_CHECKPT) return false;
- return true;
-}
-
-void CtsCmd::create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* ac ) const
-{
- if (ac->debug()) cout << "CtsCmd::create api = '" << api_ << "'.\n";
-
- assert( api_ != CtsCmd::NO_CMD);
-
- if (api_ == CtsCmd::HALT_SERVER || api_ == CtsCmd::SHUTDOWN_SERVER || api_ == CtsCmd::TERMINATE_SERVER) {
-
- std::string do_prompt = vm[ theArg() ].as< std::string > ();
- if (do_prompt.empty()) {
- if (api_ == CtsCmd::HALT_SERVER) prompt_for_confirmation("Are you sure you want to halt the server ? ");
- else if (api_ == CtsCmd::SHUTDOWN_SERVER) prompt_for_confirmation("Are you sure you want to shut down the server ? ");
- else prompt_for_confirmation("Are you sure you want to terminate the server ? ");
- }
- else if ( do_prompt != "yes" )
- throw std::runtime_error("Halt, shutdown and terminate expected 'yes' as the only argument to bypass the confirmation prompt");
- }
- else if ( api_ == CtsCmd::SERVER_LOAD) {
-
- std::string log_file = vm[ theArg() ].as< std::string > ();
- if (ac->debug()) std::cout << " CtsCmd::create CtsCmd::SERVER_LOAD " << log_file << "\n";
-
- if (!log_file.empty()) {
-
- // testing client interface
- if (ac->under_test()) return;
-
- // No need to call server. Parse the log file to create gnu_plot file.
- Gnuplot::show_server_load(log_file);
- return; // Don't create command, since with log file, it is client specific only
- }
- }
- cmd = Cmd_ptr(new CtsCmd( api_ ));
-}
-
-std::ostream& operator<<(std::ostream& os, const CtsCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/cts/CtsCmdRegistry.cpp b/ecflow_4_0_7/Base/src/cts/CtsCmdRegistry.cpp
deleted file mode 100644
index aa5f779..0000000
--- a/ecflow_4_0_7/Base/src/cts/CtsCmdRegistry.cpp
+++ /dev/null
@@ -1,145 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #52 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/make_shared.hpp>
-#include "CtsCmdRegistry.hpp"
-#include "ClientToServerCmd.hpp"
-#include "AbstractClientEnv.hpp"
-namespace po = boost::program_options;
-
-
-CtsCmdRegistry::CtsCmdRegistry(bool addGroupCmd)
-{
- // If a new client to server command is added. Make sure to add it here.
- // Could have used static initialisation' but this is less problematic.
-
- /// The order dictates how the --help is shown *BUT* Since we traverse this list.
- /// Place the command which require the fastest response first.
- vec_.reserve(70);
-
- vec_.push_back( boost::make_shared<CSyncCmd>(CSyncCmd::NEWS,0,0,0));
- vec_.push_back( boost::make_shared<CSyncCmd>(CSyncCmd::SYNC,0,0,0));
- vec_.push_back( boost::make_shared<CSyncCmd>(0)); // SYNC_FULL
- vec_.push_back( boost::make_shared<CtsNodeCmd>(CtsNodeCmd::GET));
- vec_.push_back( boost::make_shared<CtsNodeCmd>(CtsNodeCmd::GET_STATE));
- vec_.push_back( boost::make_shared<CtsNodeCmd>(CtsNodeCmd::MIGRATE));
- vec_.push_back( boost::make_shared<CheckPtCmd>());
- vec_.push_back( boost::make_shared<CtsCmd>(CtsCmd::PING));
- vec_.push_back( boost::make_shared<CtsCmd>(CtsCmd::RESTORE_DEFS_FROM_CHECKPT));
- vec_.push_back( boost::make_shared<CtsCmd>(CtsCmd::RESTART_SERVER));
- vec_.push_back( boost::make_shared<CtsCmd>(CtsCmd::HALT_SERVER));
- vec_.push_back( boost::make_shared<CtsCmd>(CtsCmd::SHUTDOWN_SERVER));
- vec_.push_back( boost::make_shared<CtsCmd>(CtsCmd::TERMINATE_SERVER));
- vec_.push_back( boost::make_shared<CtsCmd>(CtsCmd::RELOAD_WHITE_LIST_FILE));
- vec_.push_back( boost::make_shared<CtsCmd>(CtsCmd::FORCE_DEP_EVAL));
- vec_.push_back( boost::make_shared<CtsCmd>(CtsCmd::STATS));
- vec_.push_back( boost::make_shared<CtsCmd>(CtsCmd::STATS_RESET));
- vec_.push_back( boost::make_shared<CtsCmd>(CtsCmd::DEBUG_SERVER_ON));
- vec_.push_back( boost::make_shared<CtsCmd>(CtsCmd::DEBUG_SERVER_OFF));
- vec_.push_back( boost::make_shared<CtsCmd>(CtsCmd::SERVER_LOAD));
- vec_.push_back( boost::make_shared<CtsNodeCmd>(CtsNodeCmd::JOB_GEN));
- vec_.push_back( boost::make_shared<CtsNodeCmd>(CtsNodeCmd::CHECK_JOB_GEN_ONLY));
- vec_.push_back( boost::make_shared<PathsCmd>(PathsCmd::DELETE));
- vec_.push_back( boost::make_shared<PathsCmd>(PathsCmd::SUSPEND));
- vec_.push_back( boost::make_shared<PathsCmd>(PathsCmd::RESUME));
- vec_.push_back( boost::make_shared<PathsCmd>(PathsCmd::KILL));
- vec_.push_back( boost::make_shared<PathsCmd>(PathsCmd::STATUS));
- vec_.push_back( boost::make_shared<PathsCmd>(PathsCmd::CHECK));
- vec_.push_back( boost::make_shared<PathsCmd>(PathsCmd::EDIT_HISTORY));
- vec_.push_back( boost::make_shared<ZombieCmd>(ecf::User::FOB));
- vec_.push_back( boost::make_shared<ZombieCmd>(ecf::User::FAIL));
- vec_.push_back( boost::make_shared<ZombieCmd>(ecf::User::ADOPT));
- vec_.push_back( boost::make_shared<ZombieCmd>(ecf::User::BLOCK));
- vec_.push_back( boost::make_shared<ZombieCmd>(ecf::User::REMOVE));
- vec_.push_back( boost::make_shared<ZombieCmd>(ecf::User::KILL));
- vec_.push_back( boost::make_shared<CtsCmd>(CtsCmd::GET_ZOMBIES));
- vec_.push_back( boost::make_shared<CtsCmd>(CtsCmd::SUITES));
- vec_.push_back( boost::make_shared<ClientHandleCmd>(ClientHandleCmd::REGISTER));
- vec_.push_back( boost::make_shared<ClientHandleCmd>(ClientHandleCmd::DROP));
- vec_.push_back( boost::make_shared<ClientHandleCmd>(ClientHandleCmd::DROP_USER));
- vec_.push_back( boost::make_shared<ClientHandleCmd>(ClientHandleCmd::ADD));
- vec_.push_back( boost::make_shared<ClientHandleCmd>(ClientHandleCmd::REMOVE));
- vec_.push_back( boost::make_shared<ClientHandleCmd>(ClientHandleCmd::AUTO_ADD));
- vec_.push_back( boost::make_shared<ClientHandleCmd>(ClientHandleCmd::SUITES));
- vec_.push_back( boost::make_shared<LogCmd>());
- vec_.push_back( boost::make_shared<ServerVersionCmd>());
- vec_.push_back( boost::make_shared<LogMessageCmd>());
- vec_.push_back( boost::make_shared<BeginCmd>());
- vec_.push_back( boost::make_shared<InitCmd>());
- vec_.push_back( boost::make_shared<CompleteCmd>());
- vec_.push_back( boost::make_shared<AbortCmd>());
- vec_.push_back( boost::make_shared<CtsWaitCmd>());
- vec_.push_back( boost::make_shared<EventCmd>());
- vec_.push_back( boost::make_shared<MeterCmd>());
- vec_.push_back( boost::make_shared<LabelCmd>());
- vec_.push_back( boost::make_shared<RequeueNodeCmd>());
- vec_.push_back( boost::make_shared<OrderNodeCmd>());
- vec_.push_back( boost::make_shared<RunNodeCmd>());
- vec_.push_back( boost::make_shared<ForceCmd>());
- vec_.push_back( boost::make_shared<FreeDepCmd>());
- vec_.push_back( boost::make_shared<LoadDefsCmd>());
- vec_.push_back( boost::make_shared<ReplaceNodeCmd>());
- vec_.push_back( boost::make_shared<CFileCmd>());
- vec_.push_back( boost::make_shared<EditScriptCmd>());
- vec_.push_back( boost::make_shared<AlterCmd>());
- vec_.push_back( boost::make_shared<PlugCmd>());
- // Note: we deliberately do not add MoveCmd, as it should not appear in the public api
- // It is created on the fly by the PlugCmd
-
- /// Command that can *ONLY* be used in a group command
- vec_.push_back( boost::make_shared<CtsNodeCmd>(CtsNodeCmd::WHY));
- vec_.push_back( boost::make_shared<ShowCmd>());
- if (addGroupCmd) vec_.push_back( boost::make_shared<GroupCTSCmd>());
-}
-
-bool CtsCmdRegistry::parse(Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const
-{
- size_t vec_size = vec_.size();
- for(size_t i = 0; i < vec_size; i++) {
-
- if ( vm.count( vec_[i]->theArg() ) ) {
-
- if (clientEnv->debug()) std::cout << "CtsCmdRegistry::parse matched with registered command " << vec_[i]->theArg() << "\n";
-
- vec_[i]->create(cmd,vm,clientEnv);
- return true;
- }
- }
- return false;
-}
-
-void CtsCmdRegistry::addAllOptions(boost::program_options::options_description& desc) const
-{
- addCmdOptions(desc);
- addHelpOption(desc);
-}
-
-void CtsCmdRegistry::addCmdOptions(boost::program_options::options_description& desc) const
-{
- size_t vec_size = vec_.size();
- for(size_t i = 0; i < vec_size; i++) {
- vec_[i]->addOption(desc);
- }
-}
-
-void CtsCmdRegistry::addHelpOption(boost::program_options::options_description& desc) const
-{
- /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
- desc.add_options() ("help,h",po::value< std::string >()->implicit_value( std::string("") ), "Produce help message");
- desc.add_options() ("version,v", "Show ecflow client version number, and version of the boost library used" );
- desc.add_options() ("debug,d",
- "Dump out client environment settings for debug\n"
- "Set environment variable ECF_DEBUG_CLIENT for additional debug" );
-}
diff --git a/ecflow_4_0_7/Base/src/cts/CtsCmdRegistry.hpp b/ecflow_4_0_7/Base/src/cts/CtsCmdRegistry.hpp
deleted file mode 100644
index b703b36..0000000
--- a/ecflow_4_0_7/Base/src/cts/CtsCmdRegistry.hpp
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef CTS_CMD_REGISTRY_HPP_
-#define CTS_CMD_REGISTRY_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Registration of all the client to server commands
-// This allows us to parse the arg associated with
-// commands in this category. The idea being to keep
-// new commands functionality in one place.
-// Any new client to server commands that are created
-// must be added to this class.
-//============================================================================
-
-#include <boost/noncopyable.hpp>
-#include <boost/program_options.hpp>
-#include <vector>
-#include "Cmd.hpp"
-
-class AbstractClientEnv;
-
-class CtsCmdRegistry : private boost::noncopyable {
-public:
- CtsCmdRegistry(bool addGroupCmd = true );
-
- /// These option describe the arguments for each of the commands
- /// They also can be presented to the user via --help option.
- void addAllOptions(boost::program_options::options_description& desc) const;
- void addCmdOptions(boost::program_options::options_description& desc) const;
-
- /// Parse arguments given in 'vm' and use that to create a command
- /// that will be sent to the server. Will throw std::runtime_error for errors
- /// Returns true if command line argument specified via 'vm', matches one of the
- /// registered command.
- /// *** This allows us to distinguish between where we match with a registered
- /// *** command, but do *NOT* set Cmd_ptr, ie since its a client specific command
- /// *** i.e there is no need to send it to the server
- bool parse( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const;
-
-private:
- std::vector<Cmd_ptr > vec_;
-
- void addHelpOption(boost::program_options::options_description& desc) const;
-};
-
-#endif
diff --git a/ecflow_4_0_7/Base/src/cts/CtsNodeCmd.cpp b/ecflow_4_0_7/Base/src/cts/CtsNodeCmd.cpp
deleted file mode 100644
index f56b0cb..0000000
--- a/ecflow_4_0_7/Base/src/cts/CtsNodeCmd.cpp
+++ /dev/null
@@ -1,338 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #70 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/make_shared.hpp>
-
-#include "ClientToServerCmd.hpp"
-#include "AbstractServer.hpp"
-#include "AbstractClientEnv.hpp"
-#include "CtsApi.hpp"
-#include "Defs.hpp"
-#include "Task.hpp"
-#include "JobCreationCtrl.hpp"
-#include "Ecf.hpp"
-#include "Jobs.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-namespace po = boost::program_options;
-
-bool CtsNodeCmd::why_cmd( std::string& nodePath) const
-{
- if (api_ == CtsNodeCmd::WHY) {
- nodePath = absNodePath_;
- return true;
- }
- return false;
-}
-
-std::ostream& CtsNodeCmd::print(std::ostream& os) const
-{
- switch (api_) {
- case CtsNodeCmd::GET: {
- std::stringstream ss;
- ss << CtsApi::get(absNodePath_);
-#ifdef DEBUG
- if (Ecf::server()) ss << " [server(" << Ecf::state_change_no() << " " << Ecf::modify_change_no() << ")]";
-#endif
- return user_cmd(os,ss.str());
- }
- case CtsNodeCmd::GET_STATE: return user_cmd(os,CtsApi::get_state(absNodePath_)); break;
- case CtsNodeCmd::MIGRATE: return user_cmd(os,CtsApi::migrate(absNodePath_)); break;
- case CtsNodeCmd::JOB_GEN: return user_cmd(os,CtsApi::job_gen(absNodePath_)); break;
- case CtsNodeCmd::CHECK_JOB_GEN_ONLY: return user_cmd(os,CtsApi::checkJobGenOnly(absNodePath_)); break;
- case CtsNodeCmd::WHY: return user_cmd(os,CtsApi::why(absNodePath_)); break;
- case CtsNodeCmd::NO_CMD: break;
- default: throw std::runtime_error("CtsNodeCmd::print: Unrecognised command");break;
- }
- return os;
-}
-
-bool CtsNodeCmd::equals(ClientToServerCmd* rhs) const
-{
- CtsNodeCmd* the_rhs = dynamic_cast< CtsNodeCmd* > ( rhs );
- if ( !the_rhs ) return false;
- if (api_ != the_rhs->api()) return false;
- if (absNodePath_ != the_rhs->absNodePath()) return false;
- return UserCmd::equals(rhs);
-}
-
-bool CtsNodeCmd::isWrite() const
-{
- switch (api_) {
- case CtsNodeCmd::GET: return false; break; // read only
- case CtsNodeCmd::GET_STATE: return false; break; // read only
- case CtsNodeCmd::MIGRATE: return false; break; // read only
- case CtsNodeCmd::JOB_GEN: return true; break; // requires write privilege
- case CtsNodeCmd::CHECK_JOB_GEN_ONLY:return false; break; // read only
- case CtsNodeCmd::WHY: return false; break; // read only
- case CtsNodeCmd::NO_CMD: break;
- default: throw std::runtime_error("CtsNodeCmd::isWrite: Unrecognised command");break;
- }
- assert(false);
- return false;
-}
-
-const char* CtsNodeCmd::theArg() const
-{
- switch (api_) {
- case CtsNodeCmd::GET: return CtsApi::getArg(); break;
- case CtsNodeCmd::GET_STATE: return CtsApi::get_state_arg(); break;
- case CtsNodeCmd::MIGRATE: return CtsApi::migrate_arg(); break;
- case CtsNodeCmd::JOB_GEN: return CtsApi::job_genArg(); break;
- case CtsNodeCmd::CHECK_JOB_GEN_ONLY: return CtsApi::checkJobGenOnlyArg(); break;
- case CtsNodeCmd::WHY: return CtsApi::whyArg(); break;
- case CtsNodeCmd::NO_CMD: break;
- default: throw std::runtime_error("CtsNodeCmd::theArg: Unrecognised command");break;
- }
- assert(false);
- return NULL;
-}
-
-PrintStyle::Type_t CtsNodeCmd::show_style() const
-{
- if (api_ == CtsNodeCmd::GET) return PrintStyle::DEFS;
- else if (api_ == CtsNodeCmd::GET_STATE) return PrintStyle::STATE;
- else if (api_ == CtsNodeCmd::MIGRATE) return PrintStyle::MIGRATE;
- return ClientToServerCmd::show_style();
-}
-
-
-int CtsNodeCmd::timeout() const
-{
- if (api_ == CtsNodeCmd::GET) {
- return time_out_for_load_sync_and_get();
- }
- return ClientToServerCmd::timeout();
-}
-
-STC_Cmd_ptr CtsNodeCmd::doHandleRequest(AbstractServer* as) const
-{
- switch (api_) {
-
- case CtsNodeCmd::GET:
- case CtsNodeCmd::MIGRATE:
- case CtsNodeCmd::GET_STATE: {
- // The client will configure the output display
- as->update_stats().get_defs_++;
- if ( absNodePath_.empty() ) {
- // with migrate we need to get edit history.
- return PreAllocatedReply::defs_cmd(as,(api_ == MIGRATE));
- }
- // however request for a particular node, thats not there, treated as an error
- node_ptr theNodeToReturn = find_node(as,absNodePath_);
- return PreAllocatedReply::node_cmd(as,theNodeToReturn);
- }
-
- case CtsNodeCmd::CHECK_JOB_GEN_ONLY: {
- as->update_stats().node_check_job_gen_only_++;
- job_creation_ctrl_ptr jobCtrl = boost::make_shared<JobCreationCtrl>();
- jobCtrl->set_node_path(absNodePath_);
- as->defs()->check_job_creation(jobCtrl);
- if (! jobCtrl->get_error_msg().empty() ) {
- throw std::runtime_error( jobCtrl->get_error_msg() ) ;
- }
- break;
- }
-
- case CtsNodeCmd::JOB_GEN: {
- as->update_stats().node_job_gen_++;
-
- if (as->state() == SState::RUNNING) {
-
- if ( absNodePath_.empty() ) {
- // If no path specified do a full job generation over all suites
- return doJobSubmission( as );
- }
-
- // Generate jobs for the given node, downwards
- node_ptr theNode = find_node_for_edit(as,absNodePath_);
- Jobs jobs(theNode.get());
- jobs.generate();
- }
- break;
- }
-
- case CtsNodeCmd::WHY: {
- /// Why is actually invoked on client side.
- /// Added as a command because:
- /// o documentation
- /// o allows use with group command, without any other changes
- break;
- }
-
- case CtsNodeCmd::NO_CMD:
- default: throw std::runtime_error("CtsNodeCmd::doHandleRequest: Unrecognised command");break;
- }
-
- return PreAllocatedReply::ok_cmd();
-}
-
-static const char* job_gen_only_desc() {
- return
- "Test hierarchical Job generation only, for chosen Node.\n"
- "The jobs are generated independent of the dependencies\n"
- "This will generate the jobs *only*, i.e. no job submission. Used for checking job generation only\n"
- " arg = node path | arg = NULL\n"
- " If no node path specified generates for all Tasks in the definition. For Test only"
- ;
-}
-
-static const char* job_gen_desc() { // dependency_dependent_job_submission
- return
- "Job submission for chosen Node *based* on dependencies.\n"
- "The server traverses the node tree every 60 seconds, and if the dependencies are free\n"
- "does job generation and submission. Sometimes the user may free time/date dependencies\n"
- "to avoid waiting for the server poll, this commands allows early job generation\n"
- " arg = node path | arg = NULL\n"
- " If no node path specified generates for full definition."
- ;
-}
-
-static const char* why_desc() {
- return
- "Show the reason why a node is not running.\n"
- "Can only be used with the group command. The group command must include a \n"
- "'get' command(i.e returns the server defs)\n"
- "The why command take a optional string argument representing a node path\n"
- "Will return reason why the node is holding and for all its children.\n"
- "If no arguments supplied will report on all nodes\n"
- " arg = node path | arg = NULL\n"
- "Usage:\n"
- " --group=\"get; why\" # returns why for all holding nodes\n"
- " --group=\"get; why /suite/family\" # returns why for a specific node"
- ;
-}
-
-static const char* get_desc() {
- return
- "Get the suite definition or node tree in form that is re-parse able\n"
- "Get all suite node tree's from the server and write to standard out.\n"
- "The output is parse-able, and can be used to re-load the definition\n"
- " arg = NULL | arg = node path\n"
- "Usage:\n"
- " --get # gets the definition from the server,and writes to standard out\n"
- " --get /s1 # gets the suite from the server,and writes to standard out"
- ;
-}
-
-static const char* get_state_desc() {
- return
- "Get state data. For the whole suite definition or individual nodes.\n"
- "This will include event, meter, node state, trigger and time state.\n"
- "The output is written to standard out.\n"
- " arg = NULL | arg = node path\n"
- "Usage:\n"
- " --get_state # gets the definition from the server,and writes to standard out\n"
- " --get_state /s1 # gets the suite from the server,and writes to standard out"
- ;
-}
-
-const char* migrate_desc() {
- return "Used to print state of the definition returned from the server to standard output.\n"
- "The node state is shown in the comments.\n"
- "This format allows the definition to be migrated to future version of ecflow.\n"
- "The output includes edit history but excludes externs.\n"
- "When the definition is reloaded *NO* checking is done.\n"
- "\n"
- "The following shows a summary of the features associated with each choice:\n"
- " --get --get_state --migrate\n"
- "Auto generate externs Yes Yes No\n"
- "Checking on reload Yes Yes No\n"
- "Edit History No No Yes\n"
- "Show trigger AST No Yes No\n"
- "\n\n"
- "Migration is required when the release number changes:\n"
- " <release-number>.<major>.<minor>\n"
- " 6.1.7 -> 7.0.0\n"
- "as the checkpoint files are not compatible.\n\n"
- "To actually migrate to a newer version of ecflow, follow these steps:\n\n"
- " Steps for Old server:\n"
- " o shutdown\n"
- " # ecflow_client --shutdown\n"
- " o suspend all suites\n"
- " # CL=\"ecflow_client --port 32222 --host vsms1\"\n"
- " # for s in $($CL --suites); do $CL --suspend /$s; done\n"
- " o wait for active/submitted tasks to complete\n"
- " o halt the server\n"
- " # ecflow_client --halt\n"
- " o Use --migrate to dump state and structure to a file\n"
- " # ecflow_client --migrate > all_suites.def\n"
- " o terminate server *or* leave server running but start new server on different machine\n"
- " to avoid port number clash.\n"
- " o remove checkpt and backup checkpt files, to prevent new server from loading them\n"
- " *Only* applicable if starting new server on same machine\n\n"
- " Steps for New server:\n"
- " o start server\n"
- " o load the migration file\n"
- " # ecflow_client --load all_suites.def\n"
- " o set server running:\n"
- " # ecflow_client --restart\n"
- " o resume suspended suites\n"
- " # CL=\"ecflow_client --port 32222 --host vsms1\"\n"
- " # for s in $($CL --suites); do $CL --resume /$s; done\n\n"
- "Usage:\n"
- " --migrate # show all suites\n"
- " --migrate=/s1 # show state for suite s1\n"
- ;
-}
-
-
-void CtsNodeCmd::addOption(boost::program_options::options_description& desc) const
-{
- switch (api_) {
- case CtsNodeCmd::GET:{
- desc.add_options()(CtsApi::getArg(),po::value< string >()->implicit_value(string()),get_desc());
- break;
- }
- case CtsNodeCmd::GET_STATE:{
- desc.add_options()(CtsApi::get_state_arg(),po::value< string >()->implicit_value(string()),get_state_desc());
- break;
- }
- case CtsNodeCmd::MIGRATE:{
- desc.add_options()(CtsApi::migrate_arg(),po::value< string >()->implicit_value(string()),migrate_desc());
- break;
- }
- case CtsNodeCmd::JOB_GEN:{
- desc.add_options()( CtsApi::job_genArg(), po::value< string >()->implicit_value(string()), job_gen_desc() );
- break;
- }
- case CtsNodeCmd::CHECK_JOB_GEN_ONLY:{
- desc.add_options()( CtsApi::checkJobGenOnlyArg(), po::value< string >()->implicit_value(string()), job_gen_only_desc() );
- break;
- }
- case CtsNodeCmd::WHY: {
- desc.add_options()( CtsApi::whyArg(), po::value< string >()->implicit_value(string()),why_desc());
- break;
- }
- case CtsNodeCmd::NO_CMD: assert(false); break;
- default: assert(false); break;
- }
-}
-
-void CtsNodeCmd::create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* ac ) const
-{
- assert( api_ != CtsNodeCmd::NO_CMD);
-
- if (ac->debug()) cout << "CtsNodeCmd::create = '" << theArg() << "'.\n";
-
- std::string absNodePath = vm[ theArg() ].as< std::string > ();
-
- cmd = Cmd_ptr(new CtsNodeCmd( api_ , absNodePath));
-}
-
-std::ostream& operator<<(std::ostream& os, const CtsNodeCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/cts/EditHistoryMgr.cpp b/ecflow_4_0_7/Base/src/cts/EditHistoryMgr.cpp
deleted file mode 100644
index 351c5a9..0000000
--- a/ecflow_4_0_7/Base/src/cts/EditHistoryMgr.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #72 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include "EditHistoryMgr.hpp"
-#include "ClientToServerCmd.hpp"
-#include "AbstractServer.hpp"
-#include "Defs.hpp"
-#include "Log.hpp"
-#include "Node.hpp"
-#include "SuiteChanged.hpp"
-#include "Ecf.hpp"
-#include "Str.hpp"
-
-using namespace std;
-using namespace boost;
-using namespace ecf;
-
-EditHistoryMgr::EditHistoryMgr(const ClientToServerCmd* c,AbstractServer* a)
-: cts_cmd_(c),
- as_(a),
- state_change_no_(Ecf::state_change_no()),
- modify_change_no_(Ecf::modify_change_no())
-{
- assert(cts_cmd_->edit_history_nodes_.empty());
-}
-
-EditHistoryMgr::~EditHistoryMgr()
-{
- // check if state changed
- if (state_change_no_ != Ecf::state_change_no() || modify_change_no_ != Ecf::modify_change_no()) {
-
- // Ignore child commands for edit history, where only interested in user commands
- if (!cts_cmd_->task_cmd() && as_->defs()) {
-
- // *ONLY* record edit history to commands that change the data model
- // Otherwise we will end up making a data model change for read only commands
- // If there has been a change in defs state then the command must return true from isWrite
- if (cts_cmd_->isWrite()) {
- if (cts_cmd_->edit_history_nodes_.empty()) {
-
- as_->defs()->flag().set(Flag::MESSAGE);
- add_edit_history(Str::ROOT_PATH());
- }
- else {
- size_t the_size = cts_cmd_->edit_history_nodes_.size();
- for(size_t i = 0; i < the_size; i++) {
- node_ptr edited_node = cts_cmd_->edit_history_nodes_[i].lock();
- if (edited_node.get()) {
- // Setting the flag will make a state change. But its OK command allows it.
- SuiteChanged0 suiteChanged(edited_node);
- edited_node->flag().set(Flag::MESSAGE); // trap state change in suite for sync
- add_edit_history(edited_node->absNodePath());
- }
- }
- }
- }
- else {
- // Read only command, that is making data model changes, oops ?
- std::stringstream ss;
- cts_cmd_->print(ss);
- cout << "cmd " << ss.str() << " should return true from isWrite() ******************\n";
- cout << "Read only command is making data changes to defs.?????\n";
- }
- }
- }
-
- // Clear edit history nodes;
- cts_cmd_->edit_history_nodes_.clear();
-}
-
-void EditHistoryMgr::add_edit_history(const std::string& path) const
-{
- // record all the user edits to the node. Reuse the time stamp cache created in handleRequest()
- std::stringstream ss;
- ss << "MSG:";
- if (Log::instance()) ss << Log::instance()->get_cached_time_stamp();
- cts_cmd_->print(ss);
- as_->defs()->add_edit_history(path,ss.str());
-}
diff --git a/ecflow_4_0_7/Base/src/cts/EditHistoryMgr.hpp b/ecflow_4_0_7/Base/src/cts/EditHistoryMgr.hpp
deleted file mode 100644
index 8391a55..0000000
--- a/ecflow_4_0_7/Base/src/cts/EditHistoryMgr.hpp
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef EDIT_HISTORY_MGR_HPP_
-#define EDIT_HISTORY_MGR_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #72 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// This class manages the edit history, for the commands.
-// It determines if there was a state change, if there was, it adds edit
-// history to the stored nodes.
-// Additionally we check that if there was an edit then the command must
-// return ClientToServerCmd::isWrite() true.
-//============================================================================
-#include <boost/noncopyable.hpp>
-#include <string>
-
-class ClientToServerCmd;
-class AbstractServer;
-
-class EditHistoryMgr : private boost::noncopyable {
-public:
- EditHistoryMgr(const ClientToServerCmd*,AbstractServer*);
- ~EditHistoryMgr();
-
-private:
- void add_edit_history(const std::string& path) const;
-
-private:
- const ClientToServerCmd* cts_cmd_;
- AbstractServer* as_;
- mutable unsigned int state_change_no_; // detect state change in defs
- mutable unsigned int modify_change_no_; // detect state change in defs
-};
-#endif
diff --git a/ecflow_4_0_7/Base/src/cts/EditScriptCmd.cpp b/ecflow_4_0_7/Base/src/cts/EditScriptCmd.cpp
deleted file mode 100644
index a9dee37..0000000
--- a/ecflow_4_0_7/Base/src/cts/EditScriptCmd.cpp
+++ /dev/null
@@ -1,400 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #37 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "boost/filesystem/operations.hpp"
-
-#include "ClientToServerCmd.hpp"
-#include "AbstractServer.hpp"
-#include "AbstractClientEnv.hpp"
-#include "File.hpp"
-#include "CtsApi.hpp"
-#include "Defs.hpp"
-#include "Task.hpp"
-#include "Alias.hpp"
-#include "Suite.hpp"
-#include "EcfFile.hpp"
-#include "JobsParam.hpp"
-#include "SuiteChanged.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-namespace po = boost::program_options;
-namespace fs = boost::filesystem;
-
-bool EditScriptCmd::equals(ClientToServerCmd* rhs) const
-{
- EditScriptCmd* the_rhs = dynamic_cast<EditScriptCmd*>(rhs);
- if (!the_rhs) return false;
- if ( path_to_node_ != the_rhs->path_to_node()) { return false; }
- if ( edit_type_ != the_rhs->edit_type()) { return false; }
- if ( alias_ != the_rhs->alias()) { return false; }
- if ( run_ != the_rhs->run()) { return false; }
- return UserCmd::equals(rhs);
-}
-
-static std::string to_string(EditScriptCmd::EditType et) {
- switch (et) {
- case EditScriptCmd::EDIT: return "edit"; break;
- case EditScriptCmd::PREPROCESS: return "pre_process"; break;
- case EditScriptCmd::SUBMIT: return "submit"; break;
- case EditScriptCmd::PREPROCESS_USER_FILE:return "pre_process_file"; break;
- case EditScriptCmd::SUBMIT_USER_FILE: return "submit_file"; break;
- default : assert(false); break;
- }
- return "edit";
-}
-static std::vector<std::string> valid_edit_types() {
- std::vector<std::string> edit_types; edit_types.reserve(5);
- edit_types.push_back("edit");
- edit_types.push_back("pre_process");
- edit_types.push_back("submit");
- edit_types.push_back("pre_process_file");
- edit_types.push_back("submit_file");
- return edit_types;
-}
-
-
-std::ostream& EditScriptCmd::print(std::ostream& os) const
-{
- return user_cmd(os,CtsApi::to_string(CtsApi::edit_script(path_to_node_,to_string(edit_type()),"",alias_,run_)));
-}
-
-bool EditScriptCmd::isWrite() const
-{
- switch (edit_type_) {
- case EditScriptCmd::EDIT: return false; break;
- case EditScriptCmd::PREPROCESS: return false; break;
- case EditScriptCmd::PREPROCESS_USER_FILE:return false; break;
- case EditScriptCmd::SUBMIT: return true; break;
- case EditScriptCmd::SUBMIT_USER_FILE: return true; break;
- default : assert(false); break;
- }
- return false;
-}
-
-
-STC_Cmd_ptr EditScriptCmd::doHandleRequest(AbstractServer* as) const
-{
- as->update_stats().edit_script_++;
-
- node_ptr node = find_node_for_edit(as,path_to_node_); // will throw if defs not defined, or node not found
- Submittable* submittable = node->isSubmittable();
- if (!submittable) throw std::runtime_error( "EditScriptCmd failed. Can not locate task or alias at path " + path_to_node_ ) ;
-
- /// record any changes made to suite. Needed for incremental updates
- SuiteChanged0 changed(node);
-
- switch (edit_type_) {
- case EditScriptCmd::EDIT: {
-
- /// Find all the used variable in the script, i.e 'ecf file'
- EcfFile ecf_file = submittable->locatedEcfFile(); // will throw std::runtime_error for errors
-
- /// This will throw std::runtime_error for parse errors
- /// Returns the script with the used variables added at the front of the file
- // **********************************************************************
- // Custom handling of dynamic variables, i.e ECF_TRYNO, ECF_PASS and
- // any variable that embeds a try number, i.e. ECF_JOB, ECF_JOBOUT
- // This is required since the try number is *always* incremented *before* job submission,
- // hence the value extracted from the job file will not be accurate, hence we exclude it.
- // This way at job submission we use the latest/correct value, which is in-sync with JOB OUTPUT
- // Note: Otherwise the job output will not be in sync
- //
- // Custom handling of ECF_PORT,ECF_NODE,ECF_NAME do not show these variables, these veriables
- // including ECF_PASS appear in the script. If the user accidentally edits them,
- // Child communication with the server will be broken. Hence not shown
- //
- // This special handling is done in: EcfFile::get_used_variables
- // **********************************************************************
- std::string ret_file_contents;
- ecf_file.edit_used_variables(ret_file_contents);
- return PreAllocatedReply::string_cmd(ret_file_contents);
- }
-
-
- case EditScriptCmd::PREPROCESS: {
-
- /// PRE_PROCESS the ecf file accessible by the server
- EcfFile ecf_file = submittable->locatedEcfFile(); // will throw std::runtime_error for errors
-
- /// This function can throw std::runtime error if pre_processing fails
- /// This *WILL* also include the used variables
- std::string ret_file_contents ;
- ecf_file.pre_process(ret_file_contents);
- return PreAllocatedReply::string_cmd(ret_file_contents);
- }
-
-
- case EditScriptCmd::PREPROCESS_USER_FILE: {
-
- /// The file contents('user_file_contents_') here could have been edited by the user on the client side.
- EcfFile ecf_file = submittable->locatedEcfFile(); // will throw std::runtime_error for errors
-
- /// This function can throw std::runtime error if pre_processing fails
- std::string ret_file_contents ;
- ecf_file.pre_process(user_file_contents_,ret_file_contents);
- vector<string>().swap(user_file_contents_); // clear user_file_contents_ and minimise its capacity
- return PreAllocatedReply::string_cmd(ret_file_contents);
- }
-
-
- case EditScriptCmd::SUBMIT: {
-
- if (submittable->state() == NState::ACTIVE || submittable->state() == NState::SUBMITTED ) {
- std::stringstream ss;
- ss << "Node " << path_to_node_ << " is already " << NState::toString(submittable->state()) << " : ";
- throw std::runtime_error("EditScriptCmd:: failed for submit: " + ss.str() );
- }
-
- /// Using the User edited variables, generate the job using the ECF/USR file accessible from the server
- /// Convert from vector to map
- NameValueMap user_variables_map;
- for(size_t i = 0; i < user_variables_.size(); i++) {
- user_variables_map.insert( std::make_pair(user_variables_[i].first, user_variables_[i].second ));
- }
-
- /// Do job submission, but creating .usr file first
- /// This will *NOT* timeout, unlike server Job generation
- JobsParam jobsParam(as->poll_interval(),true /* create jobs */); // spawn_jobs = true
- jobsParam.set_user_edit_variables( user_variables_map );
-
- // Custom handling of dynamic variables, i.e ECF_TRYNO, ECF_PASS and
- // any variable that embeds a try number, i.e. ECF_JOB, ECF_JOBOUT
- // This is required since the try number is *always* incremented *before* job submission,
- // hence the value extracted from the job file will *not* be accurate, hence we exclude it form user variables
- if (!submittable->submitJob(jobsParam)) {
- throw std::runtime_error("EditScriptCmd:: failed for submit: " + jobsParam.getErrorMsg());
- }
- submittable->flag().set(ecf::Flag::USER_EDIT);
- break; }
-
-
- case EditScriptCmd::SUBMIT_USER_FILE: {
- /// The file contents('user_file_contents_') here could have been edited by the user on the client side. ECF_HOME
- /// If the selected node is an Alias, Just submit it. Since aliases can *NOT* have other aliases as children
- if (!alias_ || submittable->isAlias()) {
- if (submittable->state() == NState::ACTIVE || submittable->state() == NState::SUBMITTED ) {
- std::stringstream ss;
- ss << "Node " << path_to_node_ << " is already " << NState::toString(submittable->state()) << " : ";
- throw std::runtime_error("EditScriptCmd:: failed for submit: " + ss.str() );
- }
-
- /// Convert from vector to map
- NameValueMap user_variables_map;
- for(size_t i = 0; i < user_variables_.size(); i++) {
- user_variables_map.insert( std::make_pair(user_variables_[i].first, user_variables_[i].second ));
- }
-
- /// Do job submission, *USING* the user supplied file , will create .usr file
- /// This will *NOT* timeout, unlike server Job generation
- JobsParam jobsParam(as->poll_interval(),true /* create jobs */); // spawn_jobs = true
- jobsParam.set_user_edit_variables( user_variables_map );
- jobsParam.set_user_edit_file( user_file_contents_);
-
- if (!submittable->submitJob(jobsParam)) {
- vector<string>().swap(user_file_contents_); // clear user_file_contents_ and minimise its capacity
- throw std::runtime_error("EditScriptCmd::SUBMIT_USER_FILE: failed : " + jobsParam.getErrorMsg());
- }
- submittable->flag().set(ecf::Flag::USER_EDIT);
- }
- else {
- // CREATE a Child Alias. The create alias and parent it to the Task., and choose to run or not.
- Task* task = submittable->isTask();
- if (!task) {
- vector<string>().swap(user_file_contents_); // clear user_file_contents_ and minimise its capacity
- throw std::runtime_error("EditScriptCmd::SUBMIT_USER_FILE: Aliases can only be created for a task. Selected path is a Alias. Please select a Task path");
- }
- alias_ptr alias = task->add_alias(user_file_contents_,user_variables_);
-
- if (run_) {
- /// This will *NOT* timeout, unlike server Job generation
- JobsParam jobsParam(as->poll_interval(),true /* create jobs */); // spawn jobs = true
- if (!alias->submitJob(jobsParam)) {
- vector<string>().swap(user_file_contents_); // clear user_file_contents_ and minimise its capacity
- throw std::runtime_error("EditScriptCmd::SUBMIT_USER_FILE: failed for Alias : " + jobsParam.getErrorMsg());
- }
- alias->flag().set(ecf::Flag::USER_EDIT);
- }
- }
- break; }
-
- default : assert(false); break;
- }
-
-
- // Clear up memory allocated *ASAP*
- // When dealing with several thousands strings, this makes a *HUGE* difference
- vector<string>().swap(user_file_contents_); // clear user_file_contents_ and minimise its capacity
-
- return PreAllocatedReply::ok_cmd();
-}
-
-const char* EditScriptCmd::arg() { return CtsApi::edit_script_arg();}
-const char* EditScriptCmd::desc() {
- /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
- return "Allows user to edit, pre-process and submit the script.\n"
- " arg1 = path to task # The path to the task/alias\n"
- " arg2 = [ edit | pre_process | submit | pre_process_file | submit_file ]\n"
- " edit : will return the script file to standard out. The script will\n"
- " include used variables enclosed between %comment/%end at the\n"
- " start of the file\n"
- " pre_process: Will return the script file to standard out.The script will\n"
- " include used variables enclosed between %comment/%end at the\n"
- " start of the file and with all %include expanded\n"
- " submit: Will extract the used variables from the supplied file, i.e \n"
- " between the %comment/%end and use these them to generate the\n"
- " job using the ecf file accessible from the server\n"
- " pre_process_file: Will pre process the user supplied file\n"
- " submit_file: Like submit, but the supplied file, is submitted by the server\n"
- " The last 2 options allow complete freedom to debug the script file\n"
- " arg3 = [ path_to_script_file ]\n"
- " needed for option [ pre_process_file | submit_file ]\n"
- " arg4 = create_alias (optional) default value is false, for use with 'submit_file' option\n"
- " arg5 = no_run (optional) default value is false, i.e immediately run the alias\n"
- " is no_run is specified the alias in only created\n"
- "Usage:\n"
- "--edit_script /path/to/task edit > script_file\n"
- " server returns script with the used variables to standard out\n"
- " The user can choose to edit this file\n"
- "--edit_script /path/to/task pre_process > pre_processed_script_file\n"
- " server will pre process the ecf file accessible from the server\n"
- " (i.e expand all %includes) and return the file to standard out\n"
- "--edit_script /path/to/task submit script_file\n"
- " Will extract the used variables in the 'script_file' and will uses these\n"
- " variables during variable substitution of the ecf file accessible by the\n"
- " server. This is then submitted as a job\n"
- "--edit_script /path/to/task pre_process_file file_to_pre_process\n"
- " The server will pre-process the user supplied file and return the contents\n"
- " to standard out\n"
- "--edit_script /path/to/task submit_file file_to_submit\n"
- " Will extract the used variables in the 'file_to_submit' and will uses these\n"
- " variables during variable substitution, the file is then submitted for job\n"
- " generation by the server\n"
- "--edit_script /path/to/task submit_file file_to_submit create_alias\n"
- " Like the the previous example but will create and run as an alias"
- ;
-}
-
-void EditScriptCmd::addOption(boost::program_options::options_description& desc) const {
- desc.add_options()( EditScriptCmd::arg(),po::value< vector<string> >()->multitoken(), EditScriptCmd::desc() );
-}
-
-void EditScriptCmd::create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* ac) const
-{
- vector<string> args = vm[ arg() ].as< vector<string> >();
-
- if (ac->debug()) dumpVecArgs(EditScriptCmd::arg(),args);
-
- std::stringstream ss;
- if (args.size() < 2) {
- ss << "EditScriptCmd:At least 2 arguments required:\n" << EditScriptCmd::desc();
- throw std::runtime_error(ss.str());
- }
-
- string path_to_task = args[0];
- string edit_type_str = args[1];
- EditScriptCmd::EditType edit_type = EditScriptCmd::EDIT;
-
- /// Check edit_type is valid
- bool ok = false;
- std::vector<std::string> edit_types = valid_edit_types();
- for(size_t i = 0; i < edit_types.size(); i++) {
- if (edit_type_str == edit_types[i]) {
- if (edit_type_str == "edit") edit_type = EditScriptCmd::EDIT;
- else if (edit_type_str == "pre_process") edit_type = EditScriptCmd::PREPROCESS;
- else if (edit_type_str == "submit") edit_type = EditScriptCmd::SUBMIT;
- else if (edit_type_str == "pre_process_file") edit_type = EditScriptCmd::PREPROCESS_USER_FILE;
- else if (edit_type_str == "submit_file") edit_type = EditScriptCmd::SUBMIT_USER_FILE;
- else { assert(false); }
- ok = true; break;
- }
- }
-
- if (!ok) {
- ss << "The second argument(" << args[1] << ") to edit_script must be one of [ ";
- for(size_t i = 0; i < edit_types.size(); ++i) { if (i != 0) ss << " | "; ss << edit_types[i];}
- ss << "]\n" << EditScriptCmd::desc();
- throw std::runtime_error( ss.str() );
- }
-
- if (args.size() == 2) {
- if (edit_type == EditScriptCmd::EDIT || edit_type == EditScriptCmd::PREPROCESS) {
- cmd = Cmd_ptr( new EditScriptCmd( path_to_task, edit_type) );
- return;
- }
- else {
- ss << "When two arguments specified, the second argument must be one of [ edit | pre_process ]\n" << EditScriptCmd::desc();
- throw ss.str();
- }
- }
-
- bool create_alias = false; // for use with "submit_file" option only
- bool run_alias = true; // for use with "submit_file" option only
- for(size_t i = 0; i < args.size(); i++) {
- if (i > 2 && args[i] == "create_alias") create_alias = true;
- if (i > 2 && args[i] == "no_run") run_alias = false;
- }
- if ( ( create_alias || !run_alias) && edit_type != EditScriptCmd::SUBMIT_USER_FILE ) {
- ss << "The create_alias option is only valid when the second argument is 'submit_file' \n" << EditScriptCmd::desc();
- throw ss.str();
- }
-
-
- if (args.size() >= 3 && args.size() <= 5) {
- string path_to_script = args[2];
- std::vector<std::string> script_lines;
-
- if (!fs::exists(path_to_script)) {
- ss << "The script file specified '" << path_to_script << "' does not exist\n";
- throw std::runtime_error(ss.str());
- }
- if (!File::splitFileIntoLines(path_to_script, script_lines)) {
- ss << "Could not open script file " << path_to_script;
- throw std::runtime_error(ss.str());
- }
-
- if (edit_type == EditScriptCmd::SUBMIT || EditScriptCmd::SUBMIT_USER_FILE) {
- // extract the Used variables from the script file
- NameValueMap used_variables_as_map;
- EcfFile::extract_used_variables(used_variables_as_map,script_lines);
-
- // Convert MAP to Vec
- NameValueVec used_variables_as_vec;
- std::pair<std::string, std::string> pair;
- BOOST_FOREACH(pair, used_variables_as_map) { used_variables_as_vec.push_back( std::make_pair(pair.first,pair.second) ); }
-
- if (edit_type == EditScriptCmd::SUBMIT) {
- cmd = Cmd_ptr( new EditScriptCmd( path_to_task, used_variables_as_vec ) ); //SUMBIT
- return;
- }
-
- cmd = Cmd_ptr( new EditScriptCmd( path_to_task, used_variables_as_vec, script_lines, create_alias, run_alias ) ); // SUBMIT_USER_FILE
- return;
- }
- else if (edit_type == EditScriptCmd::PREPROCESS_USER_FILE ) {
-
- cmd = Cmd_ptr( new EditScriptCmd( path_to_task, script_lines ) );
- return;
- }
- }
-
- ss << "Wrong number of arguments specified\n" << EditScriptCmd::desc();
- throw std::runtime_error(ss.str());
-}
-
-std::ostream& operator<<(std::ostream& os, const EditScriptCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/cts/ForceCmd.cpp b/ecflow_4_0_7/Base/src/cts/ForceCmd.cpp
deleted file mode 100644
index 49d5800..0000000
--- a/ecflow_4_0_7/Base/src/cts/ForceCmd.cpp
+++ /dev/null
@@ -1,259 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #36 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include "ClientToServerCmd.hpp"
-#include "AbstractServer.hpp"
-#include "AbstractClientEnv.hpp"
-#include "CtsApi.hpp"
-#include "Defs.hpp"
-#include "Node.hpp"
-#include "Str.hpp"
-#include "SuiteChanged.hpp"
-#include "Extract.hpp"
-#include "Log.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-namespace po = boost::program_options;
-
-// ===================================================================================
-
-bool ForceCmd::equals(ClientToServerCmd* rhs) const
-{
- ForceCmd* the_rhs = dynamic_cast<ForceCmd*>(rhs);
- if (!the_rhs) return false;
- if ( paths_ != the_rhs->paths()) { return false;}
- if ( stateOrEvent_ != the_rhs->stateOrEvent()) { return false; }
- if ( recursive_ != the_rhs->recursive()) { return false; }
- if ( setRepeatToLastValue_ != the_rhs->setRepeatToLastValue()) { return false; }
- return UserCmd::equals(rhs);
-}
-
-std::ostream& ForceCmd::print(std::ostream& os) const
-{
- return user_cmd(os,CtsApi::to_string(CtsApi::force(paths_,stateOrEvent_,recursive_,setRepeatToLastValue_)));
-}
-
-STC_Cmd_ptr ForceCmd::doHandleRequest(AbstractServer* as) const
-{
- as->update_stats().force_++;
-
- assert(isWrite()); // isWrite used in handleRequest() to control check pointing
-
- bool is_event_state = Event::isValidState(stateOrEvent_);
- bool is_node_state = NState::isValid(stateOrEvent_);
- if (!is_node_state && !is_event_state) {
- std::stringstream ss;
- ss << "ForceCmd: failed. Invalid node state or event " << stateOrEvent_ << " expected one of "
- << "[ unknown | complete | queued | submitted | active | aborted | clear | set]";
- throw std::runtime_error( ss.str() ) ;
- }
-
- std::stringstream error_ss;
- size_t vec_size = paths_.size();
- for(size_t i = 0; i < vec_size; i++) {
-
- string the_path = paths_[i];
- string the_event;
- if ( is_event_state ) {
- Extract::pathAndName(paths_[i],the_path, the_event);
- if ( the_path.empty() || the_event.empty() ) {
- std::stringstream ss;
- ss << "ForceCmd: When 'set' or 'clear' is specified the path needs to include name of the event i.e --force=/path/to_task:event_name set";
- std::string error_msg = ss.str();
- ecf::log(Log::ERR, error_msg);
- error_ss << error_msg << "\n";
- continue;
- }
- }
-
- node_ptr node = find_node_for_edit_no_throw(as,the_path);
- if (!node.get()) {
- std::stringstream ss;
- ss << "ForceCmd: Could not find node at path " << the_path;
- std::string error_msg = ss.str();
- ecf::log(Log::ERR, error_msg);
- error_ss << error_msg << "\n";
- continue;
- }
- SuiteChanged0 changed(node); // Cater for suites in handles
-
- if (is_node_state) {
- /// We want this to have side effects. i.e bubble up state and re-queue if complete and has repeat's
- /// **** However if state is SET to complete, we want to MISS the next time slot.
- /// **** we need to mark the time dependency as *expired*, otherwise, it will be automatically reset to QUEUED state
- NState::State new_state = NState::toState(stateOrEvent_);
- if (new_state == NState::COMPLETE) {
- node->miss_next_time_slot();
- }
-
- if (recursive_) node->set_state_hierarchically( new_state, true /* force */ );
- else node->set_state( new_state, true /* force */ );
- }
- else {
- // The recursive option is *NOT* applicable to events, hence ignore. According to Axel !!!!
- if ( stateOrEvent_ == Event::SET() ) {
- if (!node->set_event(the_event)) {
- std::stringstream ss;
- ss << "ForceCmd: force set: failed for node(" << node->absNodePath() << ") can not find event(" << the_event << ")";
- std::string error_msg = ss.str();
- ecf::log(Log::ERR, error_msg);
- error_ss << error_msg << "\n";
- continue;
- }
- }
- else if ( stateOrEvent_ == Event::CLEAR() ) {
- if (!node->clear_event(the_event)) {
- std::stringstream ss;
- ss << "ForceCmd: force clear: failed for node(" << node->absNodePath() << ") can not find event(" << the_event << ")";
- std::string error_msg = ss.str();
- ecf::log(Log::ERR, error_msg);
- error_ss << error_msg << "\n";
- continue;
- }
- }
- else throw std::runtime_error("ForceCmd: Invalid parameter") ;
- }
-
- if ( recursive_ && setRepeatToLastValue_) {
- node->setRepeatToLastValueHierarchically();
- }
- }
-
- // Clear up memory allocated to path. *ASAP*
- // When paths is very large, freeing memory has big impact on performance
- // i.e comment this out and run Client/test/TestSinglePerf.cpp -> ecflow test_performance to see the effect
- // Commands run after this are considerably slower.Looks like it still retained in memory dues to shared ptr, slightly longer
- // When dealing with several thousands paths, this makes a *HUGE* difference
- vector<string>().swap(paths_); // clear paths_ and minimise its capacity *ASAP*
-
- std::string error_msg = error_ss.str();
- if (!error_msg.empty()) {
- throw std::runtime_error( error_msg ) ;
- }
-
- /// Change of state, do immediate job generation
- return doJobSubmission( as );
-}
-
-const char* ForceCmd::arg() { return CtsApi::forceArg();}
-const char* ForceCmd::desc() {
- /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
- return
- "Force a node to a given state, or set its event.\n"
- "When a task is set to complete, it may be automatically re-queued if it has\n"
- "multiple future time dependencies. However each time we force a complete it will\n"
- "expire any time based attribute on that node. When the last time based attribute\n"
- "expires, the node will stay in a complete state.\n"
- "This behaviour allow Repeat values to be incremented interactively.\n"
- "A repeat attribute is incremented when all the child nodes are complete\n"
- "in this case the child nodes are automatically re-queued.\n"
- " arg1 = [ unknown | complete | queued | submitted | active | aborted | clear | set ]\n"
- " arg2 = (optional) recursive\n"
- " Applies state to node and recursively to all its children\n"
- " arg3 = (optional) full\n"
- " Set repeat variables to last value, only works in conjunction\n"
- " with recursive option\n"
- " arg4 = path_to_node or path_to_node:<event>: paths must begin with '/'\n"
- "Usage:\n"
- " --force=complete /suite/t1 /suite/t2 # Set task t1 & t2 to complete\n"
- " --force=clear /suite/task:ev # Clear the event 'ev' on task /suite/task\n"
- " --force=complete recursive /suite/f1 # Recursively set complete all children of /suite/f1\n"
- "Effect:\n"
- " Consider the effect of forcing complete when the current time is at 09:00\n"
- " suite s1\n"
- " task t1; time 12:00 # will complete straight away\n"
- " task t2; time 10:00 13:00 01:00 # will complete on fourth attempt\n\n"
- " --force=complete /s1/t1 /s1/t2\n"
- " When we have a time range(i.e as shown with task t2), it is re-queued and the\n"
- " next time slot is incremented for each complete, until it expires, and the task completes.\n"
- " Use the Why command, to show next run time (i.e. next time slot)"
- ;
-}
-
-void ForceCmd::addOption(boost::program_options::options_description& desc) const {
- desc.add_options()( ForceCmd::arg(),po::value< vector<string> >()->multitoken(), ForceCmd::desc() );
-}
-void ForceCmd::create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* ac) const
-{
- vector<string> args = vm[ arg() ].as< vector<string> >();
-
- if (ac->debug()) dumpVecArgs(ForceCmd::arg(),args);
-
- if (args.size() < 2 ) {
- std::stringstream ss;
- ss << "ForceCmd: At least two arguments expected for Force. Found " << args.size() << "\n"
- << ForceCmd::desc() << "\n";
- throw std::runtime_error( ss.str() );
- }
-
- std::vector<std::string> options,paths;
- split_args_to_options_and_paths(args,options,paths); // relative order is still preserved
- if (paths.empty()) {
- std::stringstream ss;
- ss << "ForceCmd: No paths specified. Paths must begin with a leading '/' character\n" << ForceCmd::desc() << "\n";
- throw std::runtime_error( ss.str() );
- }
- if (options.empty()) {
- std::stringstream ss;
- ss << "ForceCmd: Invalid argument list. Expected of:\n"
- << "[ unknown | complete | queued | submitted | active | aborted | clear | set]\n" << ForceCmd::desc() << "\n";
- throw std::runtime_error( ss.str() );
- }
-
- bool is_valid_state = false;
- bool is_valid_event_state = false;
- bool setRepeatToLastValue = false;
- bool recursive = false;
- std::string stateOrEvent;
- size_t vec_size = options.size();
- for(size_t i = 0; i < vec_size; i++) {
- if (Str::caseInsCompare(options[i],"recursive")) recursive = true;
- else if (Str::caseInsCompare( options[i],"full")) setRepeatToLastValue = true;
- else if (NState::isValid(options[i])) { is_valid_state = true; stateOrEvent = options[i];}
- else if (Event::isValidState(options[i])) { is_valid_event_state = true; stateOrEvent = options[i];}
- else {
- std::stringstream ss; ss << "ForceCmd: Invalid argument \n" << ForceCmd::desc() << "\n";
- throw std::runtime_error( ss.str() );
- }
- }
-
- if (!is_valid_state && !is_valid_event_state) {
- std::stringstream ss;
- ss << "ForceCmd: Invalid node state or event expected one of:\n"
- << "[ unknown | complete | queued | submitted | active | aborted | clear | set]\n";
- throw std::runtime_error( ss.str() );
- }
-
- if ( is_valid_event_state ) {
- // When set or clear used the path needs to include the name of the event:
- size_t vec_size = paths.size();
- for(size_t i = 0; i < vec_size; i++) {
- string the_event,the_path;
- Extract::pathAndName(paths[i],the_path, the_event);
- if ( the_path.empty() || the_event.empty() ) {
- std::stringstream ss;
- ss << "ForceCmd: When 'set' or 'clear' is specified the path needs to include name of the event i.e\n";
- ss << " --force=/path/to_task:event_name set\n";
- throw std::runtime_error( ss.str() );
- }
- }
- }
- cmd = Cmd_ptr( new ForceCmd(paths, stateOrEvent, recursive, setRepeatToLastValue ) );
-}
-
-std::ostream& operator<<(std::ostream& os, const ForceCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/cts/FreeDepCmd.cpp b/ecflow_4_0_7/Base/src/cts/FreeDepCmd.cpp
deleted file mode 100644
index 4276286..0000000
--- a/ecflow_4_0_7/Base/src/cts/FreeDepCmd.cpp
+++ /dev/null
@@ -1,154 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #28 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include "ClientToServerCmd.hpp"
-#include "AbstractServer.hpp"
-#include "AbstractClientEnv.hpp"
-#include "CtsApi.hpp"
-#include "Defs.hpp"
-#include "Node.hpp"
-#include "SuiteChanged.hpp"
-#include "Log.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-namespace po = boost::program_options;
-
-//=======================================================================================
-
-bool FreeDepCmd::equals(ClientToServerCmd* rhs) const
-{
- FreeDepCmd* the_rhs = dynamic_cast<FreeDepCmd*>(rhs);
- if (!the_rhs) return false;
- if ( paths_ != the_rhs->paths()) { return false;}
- if ( all_ != the_rhs->all()) { return false; }
- if ( trigger_ != the_rhs->trigger()) { return false; }
- if ( date_ != the_rhs->date()) { return false; }
- if ( time_ != the_rhs->time()) { return false; }
- return UserCmd::equals(rhs);
-}
-
-std::ostream& FreeDepCmd::print(std::ostream& os) const
-{
- return user_cmd(os,CtsApi::to_string(CtsApi::freeDep(paths_,trigger_,all_,date_,time_)));
-}
-
-STC_Cmd_ptr FreeDepCmd::doHandleRequest(AbstractServer* as) const
-{
- as->update_stats().free_dep_++;
-
- std::stringstream ss;
- size_t vec_size = paths_.size();
- for(size_t i = 0; i < vec_size; i++) {
-
- node_ptr node = find_node_for_edit_no_throw(as,paths_[i]);
- if (!node.get()) {
- ss << "FreeDepCmd: Could not find node at path " << paths_[i] << "\n";
- LOG(Log::ERR,"FreeDepCmd: Could not find node at path " << paths_[i]);
- continue;
- }
-
- SuiteChanged0 changed(node);
- if (all_) {
- node->freeTrigger();
- node->freeHoldingDateDependencies();
- node->freeHoldingTimeDependencies();
- }
- else {
- if (trigger_) node->freeTrigger();
- if (date_) node->freeHoldingDateDependencies();
- if (time_) node->freeHoldingTimeDependencies();
- }
- }
-
- // Clear up memory allocated to path *ASAP*
- // When dealing with several thousands paths, this makes a *HUGE* difference
- vector<string>().swap(paths_); // clear paths_ and minimise its capacity
-
- std::string error_msg = ss.str();
- if (!error_msg.empty()) {
- throw std::runtime_error( error_msg ) ;
- }
-
- return doJobSubmission( as );
-}
-
-const char* FreeDepCmd::arg() { return CtsApi::freeDepArg();}
-const char* FreeDepCmd::desc() {
- return
- "Free dependencies for a node. Defaults to triggers\n"
- "After freeing the time related dependencies (i.e time,today,cron)\n"
- "the next time slot will be missed.\n"
- " arg1 = (optional) trigger\n"
- " arg2 = (optional) all\n"
- " Free trigger, date and all time dependencies\n"
- " arg3 = (optional) date\n"
- " Free date dependencies\n"
- " arg4 = (optional) time\n"
- " Free all time dependencies i.e time, day, today, cron\n"
- " arg5 = List of paths. At least one required. Must start with a leading '/'\n"
- "Usage:\n"
- " --free-dep=/s1/t1 /s2/t2 # free trigger dependencies for task's t1,t2\n"
- " --free-dep=all /s1/f1/t1 # free all dependencies of /s1/f1/t1\n"
- " --free-dep=date /s1/f1 # free holding date dependencies of /s1/f1"
- ;
-}
-
-void FreeDepCmd::addOption(boost::program_options::options_description& desc) const {
- desc.add_options()( FreeDepCmd::arg(),po::value< vector<string> >()->multitoken(), FreeDepCmd::desc() );
-}
-void FreeDepCmd::create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* ac) const
-{
- vector<string> args = vm[ arg() ].as< vector<string> >();
-
- if (ac->debug()) dumpVecArgs(FreeDepCmd::arg(),args);
-
- if (args.size() < 1 ) {
- std::stringstream ss;
- ss << "FreeDepCmd: At least one arguments expected for Free dependencies. Found " << args.size() << "\n" << FreeDepCmd::desc() << "\n";
- throw std::runtime_error( ss.str() );
- }
-
- std::vector<std::string> options,paths;
- split_args_to_options_and_paths(args,options,paths); // relative order is still preserved
- if (paths.empty()) {
- std::stringstream ss;
- ss << "FreeDepCmd: No paths specified. Paths must begin with a leading '/' character\n" << FreeDepCmd::desc() << "\n";
- throw std::runtime_error( ss.str() );
- }
-
- bool trigger = options.empty(); // If no options default to freeing trigger dependencies
- bool all = false;
- bool date = false;
- bool time = false;
- size_t vec_size = options.size();
- for(size_t i = 0; i < vec_size; i++) {
- if (options[i] == "trigger") trigger = true;
- else if ( options[i] == "all") all = true;
- else if ( options[i] == "date") date = true;
- else if ( options[i] == "time") time = true;
- else {
- std::stringstream ss;
- ss << "FreeDepCmd: Invalid argument(" << options[i] << ")\n" << FreeDepCmd::desc() << "\n";
- throw std::runtime_error( ss.str() );
- }
- }
- assert(trigger || all || date || time); // at least one must be true
- cmd = Cmd_ptr( new FreeDepCmd(paths, trigger, all, date , time) );
-}
-
-std::ostream& operator<<(std::ostream& os, const FreeDepCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/cts/GroupCTSCmd.cpp b/ecflow_4_0_7/Base/src/cts/GroupCTSCmd.cpp
deleted file mode 100644
index ccff662..0000000
--- a/ecflow_4_0_7/Base/src/cts/GroupCTSCmd.cpp
+++ /dev/null
@@ -1,293 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #29 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <iostream>
-#include <boost/foreach.hpp>
-#include <boost/algorithm/string/trim.hpp>
-#include <boost/make_shared.hpp>
-
-#include "ClientToServerCmd.hpp"
-#include "GroupSTCCmd.hpp"
-#include "AbstractServer.hpp"
-#include "AbstractClientEnv.hpp"
-#include "Str.hpp"
-#include "CtsApi.hpp"
-#include "CtsCmdRegistry.hpp"
-#include "ArgvCreator.hpp"
-#include "Log.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-namespace po = boost::program_options;
-
-//#define DEBUG_GROUP_CMD 1
-
-//======================================================================================
-
-GroupCTSCmd::GroupCTSCmd(const std::string& cmdSeries,AbstractClientEnv* clientEnv)
-{
- std::vector<std::string> individualCmdVec;
- Str::split(cmdSeries,individualCmdVec,";");
- if ( individualCmdVec.empty()) throw std::runtime_error("GroupCTSCmd::GroupCTSCmd: Please provide a list of ';' separated commands\n" );
- if (clientEnv->debug()){
- for(size_t i=0; i < individualCmdVec.size(); i++) { cout << " CHILD COMMAND = " << individualCmdVec[i] << "\n";}
- }
-
-
- // Create a list of allowable commands for a group. i.e excludes help, group
- po::options_description desc( "Allowed group options" );
- CtsCmdRegistry cmdRegistry( false /* don't add group option */);
- cmdRegistry.addCmdOptions(desc);
-
-
- for(size_t i=0; i < individualCmdVec.size(); i++){
- // massage the commands so that, we add -- at the start of each command. This is required
- // by the boost program options.
- std::string aCmd = individualCmdVec[i];
- boost::algorithm::trim(aCmd);
-
- std::string subCmd;
- if (aCmd.find("--") == std::string::npos) subCmd = "--";
- subCmd += aCmd;
-
- // Each sub command can have, many args
- std::vector<std::string> subCmdArgs;
- Str::split(subCmd,subCmdArgs);
-
- /// Hack because we *can't* create program option with vector of strings, which can be empty
- /// Hence if command is just show, add a dummy arg.
- //if (aCmd == "show") subCmdArgs.push_back("<dummy_arg>");
-
- std::vector<std::string> theArgs; theArgs.push_back("ClientInvoker");
- std::copy( subCmdArgs.begin(), subCmdArgs.end(), std::back_inserter(theArgs));
-
- // Create a Argv array from a vector of strings
- ArgvCreator argvCreator(theArgs);
-
- if (clientEnv->debug()) {
- cout << " PROCESSING COMMAND = '" << subCmd << "' argc(" << argvCreator.argc() << ")";
- cout << argvCreator.toString() << "\n";
- }
-
- // Treat each sub command separately
- boost::program_options::variables_map group_vm;
- po::store( po::parse_command_line( argvCreator.argc(), argvCreator.argv(), desc ), group_vm );
- po::notify( group_vm );
-
- Cmd_ptr childCmd;
- cmdRegistry.parse( childCmd,group_vm,clientEnv);
- addChild( childCmd );
- }
-}
-
-
-bool GroupCTSCmd::isWrite() const
-{
- BOOST_FOREACH(Cmd_ptr subCmd, cmdVec_) { if (subCmd->isWrite()) return true; }
- return false;
-}
-
-bool GroupCTSCmd::get_cmd() const
-{
- BOOST_FOREACH(Cmd_ptr subCmd, cmdVec_) { if (subCmd->get_cmd()) return true; }
- return false;
-}
-
-PrintStyle::Type_t GroupCTSCmd::show_style() const
-{
- // Only return non default style( PrintStyle::NOTHING ) if sub command
- // contains a show cmd
- BOOST_FOREACH(Cmd_ptr subCmd, cmdVec_) {
- if ( subCmd->show_cmd() ) return subCmd->show_style();
- }
- return PrintStyle::NOTHING;
-}
-
-bool GroupCTSCmd::task_cmd() const
-{
- BOOST_FOREACH(Cmd_ptr subCmd, cmdVec_) { if (subCmd->task_cmd()) return true; }
- return false;
-}
-
-bool GroupCTSCmd::terminate_cmd() const
-{
- BOOST_FOREACH(Cmd_ptr subCmd, cmdVec_) { if (subCmd->terminate_cmd()) return true; }
- return false;
-}
-
-bool GroupCTSCmd::why_cmd( std::string& nodePath) const
-{
- BOOST_FOREACH(Cmd_ptr subCmd, cmdVec_) { if (subCmd->why_cmd(nodePath)) return true; }
- return false;
-}
-
-std::ostream& GroupCTSCmd::print(std::ostream& os) const
-{
- std::stringstream ss;
- size_t the_size = cmdVec_.size();
- for(size_t i = 0; i < the_size; i++) {
- cmdVec_[i]->print(ss);
- ss <<"; ";
- }
- return user_cmd(os,CtsApi::group(ss.str()));
-}
-
-bool GroupCTSCmd::equals(ClientToServerCmd* rhs) const
-{
- GroupCTSCmd* the_rhs = dynamic_cast< GroupCTSCmd* > ( rhs );
- if ( !the_rhs ) return false;
-
- const std::vector<Cmd_ptr>& rhsCmdVec = the_rhs->cmdVec();
- if (cmdVec_.size() != rhsCmdVec.size()) return false;
-
- for(size_t i = 0; i < cmdVec_.size(); i++) {
- if ( !cmdVec_[i]->equals( rhsCmdVec[i].get() ) ) {
- return false;
- }
- }
-
- return UserCmd::equals(rhs);
-}
-
-void GroupCTSCmd::addChild(Cmd_ptr childCmd)
-{
- assert(childCmd.get()); // Dont add NULL children
- cmdVec_.push_back(childCmd);
-}
-
-void GroupCTSCmd::setup_user_authentification()
-{
- UserCmd::setup_user_authentification();
- for(size_t i = 0; i < cmdVec_.size(); i++) {
- cmdVec_[i]->setup_user_authentification();
- }
-}
-
-bool GroupCTSCmd::authenticate(AbstractServer* as, STC_Cmd_ptr& errorMsg) const
-{
- // Can only run Group cmd if all child commands authenticate
- size_t cmd_vec_size = cmdVec_.size();
- for(size_t i = 0; i < cmd_vec_size; i++) {
- if (!cmdVec_[i]->authenticate(as,errorMsg)) {
-
- // Log authentication failure:
- std::stringstream ss;
- ss << "GroupCTSCmd::authenticate failed: for ";
- cmdVec_[i]->print(ss);
- ss << errorMsg;
- log(Log::ERR,ss.str()); // will automatically add end of line
-
-#ifdef DEBUG_GROUP_CMD
- std::cout << "GroupCTSCmd::authenticate failed for "; cmdVec_[i]->print(std::cout); std::cout << errorMsg << "\n";
-#endif
- return false;
- }
- }
- return true;
-}
-
-STC_Cmd_ptr GroupCTSCmd::doHandleRequest(AbstractServer* as) const
-{
-#ifdef DEBUG_GROUP_CMD
- std::cout << "GroupCTSCmd::doHandleRequest cmdVec_.size() = " << cmdVec_.size() << "\n";
-#endif
-
- as->update_stats().group_cmd_++;
-
- boost::shared_ptr<GroupSTCCmd> theReturnedGroupCmd = boost::make_shared<GroupSTCCmd>();
-
- // For the command to succeed all children MUST succeed
- size_t cmd_vec_size = cmdVec_.size();
- for(size_t i = 0; i < cmd_vec_size; i++) {
-#ifdef DEBUG_GROUP_CMD
- std::cout << " GroupCTSCmd::doHandleRequest calling "; cmdVec_[i]->print(std::cout); // std::cout << "\n";
-#endif
-
- STC_Cmd_ptr theReturnCmd = cmdVec_[i]->doHandleRequest(as);
-
-#ifdef DEBUG_GROUP_CMD
- std::cout << " return Cmd = "; theReturnCmd->print(std::cout); std::cout << "\n";
-#endif
-
- if ( !theReturnCmd->ok() ) {
- return theReturnCmd; // The Error Command
- }
-
- if ( !theReturnCmd->get_string().empty() ) {
-#ifdef DEBUG_GROUP_CMD
- std::cout << " GroupCTSCmd::doHandleRequest returning Cmd = "; theReturnCmd->print(std::cout); std::cout << " to client\n";
-#endif
- theReturnedGroupCmd->addChild( theReturnCmd );
- continue;
- }
-
- if ( theReturnCmd->hasDefs() ) {
-#ifdef DEBUG_GROUP_CMD
- std::cout << " GroupCTSCmd::doHandleRequest returning Cmd = "; theReturnCmd->print(std::cout); std::cout << " to client\n";
-#endif
- theReturnedGroupCmd->addChild( theReturnCmd );
- continue;
- }
-
- if ( theReturnCmd->hasNode() ) {
-#ifdef DEBUG_GROUP_CMD
- std::cout << " GroupCTSCmd::doHandleRequest returning Cmd = "; theReturnCmd->print(std::cout); std::cout << " to client\n";
-#endif
- theReturnedGroupCmd->addChild( theReturnCmd );
- }
- }
-
- if ( theReturnedGroupCmd->cmdVec().empty() ) {
- // Nothing to return, i.e. no Defs, Node or Log file
- return PreAllocatedReply::ok_cmd();
- }
-
- return theReturnedGroupCmd ;
-}
-
-const char* GroupCTSCmd::arg() { return CtsApi::groupArg() ;}
-const char* GroupCTSCmd::desc() {
- return
- "Allows a series of ';' separated commands to be grouped and executed as one.\n"
- "Some commands like halt, shutdown and terminate will prompt the user. To bypass the prompt\n"
- "provide 'yes' as an additional parameter. See example below.\n"
- " arg = string\n"
- "Usage:\n"
- " --group=\"halt yes; reloadwsfile; restart;\"\n"
- " # halt server,bypass the confirmation prompt,\n"
- " # reload white list file, restart server\n"
- " --group=\"get; show\" # get server defs, and write to standard output\n"
- " --group=\"get /s1; show state\" # get suite 's1', and write state to standard output"
- ;
-}
-
-void GroupCTSCmd::addOption(boost::program_options::options_description& desc) const {
- desc.add_options()( GroupCTSCmd::arg(), po::value< string >(), GroupCTSCmd::desc() );
-}
-
-void GroupCTSCmd::create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const
-{
- if (clientEnv->debug()) cout << arg() << ": Group Cmd '" << vm[ arg() ].as< std::string > () << "'\n";
-
- // Parse and split commands and then parse individually. Assumes commands are separated by ';'
- std::string cmdSeries = vm[GroupCTSCmd::arg()].as< std::string > ();
-
- cmd = Cmd_ptr( new GroupCTSCmd(cmdSeries,clientEnv) );
-}
-
-std::ostream& operator<<(std::ostream& os, const GroupCTSCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/cts/LoadDefsCmd.cpp b/ecflow_4_0_7/Base/src/cts/LoadDefsCmd.cpp
deleted file mode 100644
index 10d9f95..0000000
--- a/ecflow_4_0_7/Base/src/cts/LoadDefsCmd.cpp
+++ /dev/null
@@ -1,154 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #43 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <boost/make_shared.hpp>
-#include "ClientToServerCmd.hpp"
-#include "AbstractServer.hpp"
-#include "AbstractClientEnv.hpp"
-#include "Str.hpp"
-#include "CtsApi.hpp"
-#include "Defs.hpp"
-#include "Log.hpp"
-#include "DefsStructureParser.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-namespace po = boost::program_options;
-
-LoadDefsCmd::LoadDefsCmd(const std::string& defs_filename, bool force)
-: force_(force), defs_(Defs::create()), defs_filename_(defs_filename)
-{
- if (defs_filename_.empty()) {
- std::stringstream ss;
- ss << "LoadDefsCmd::LoadDefsCmd: The pathname to the definition file must be provided\n" << LoadDefsCmd::desc();
- throw std::runtime_error(ss.str());
- }
-
- // At the end of the parse check the trigger/complete expressions and resolve in-limits
- DefsStructureParser checkPtParser( defs_.get(), defs_filename_ );
- std::string errMsg, warningMsg;
- if ( checkPtParser.doParse( errMsg , warningMsg) ) {
- // Dump out the in memory Node tree
- // std::cout << defs_.get();
-
- // Out put any warning to standard output
- cout << warningMsg;
- }
- else {
- std::stringstream ss; ss << "\nLoadDefsCmd::LoadDefsCmd. Failed to parse file " << defs_filename_ << "\n";
- ss << errMsg;
- throw std::runtime_error( ss.str() );
- }
-}
-
-bool LoadDefsCmd::equals(ClientToServerCmd* rhs) const
-{
- LoadDefsCmd* the_rhs = dynamic_cast<LoadDefsCmd*>(rhs);
- if (!the_rhs) return false;
-
- if (!UserCmd::equals(rhs)) return false;
-
- if (defs_ == NULL && the_rhs->theDefs() == NULL) return true;
- if (defs_ == NULL && the_rhs->theDefs() != NULL) return false;
- if (defs_ != NULL && the_rhs->theDefs() == NULL) return false;
-
- return (*defs_ == *(the_rhs->theDefs()));
-}
-
-STC_Cmd_ptr LoadDefsCmd::doHandleRequest(AbstractServer* as) const
-{
- as->update_stats().load_defs_++;
-
- assert(isWrite()); // isWrite used in handleRequest() to control check pointing
- if (defs_) {
-
- // After the updateDefs, defs_ will be left with NO suites.
- // Can't really used defs_ after this point
- // *NOTE* Externs are not persisted. Hence calling check() will report
- // all errors, references are not resolved.
- as->updateDefs(defs_,force_);
- }
-
- return PreAllocatedReply::ok_cmd();
-}
-
-std::ostream& LoadDefsCmd::print(std::ostream& os) const
-{
- /// If defs_filename_ is empty, the Defs was a in memory defs.
- if (defs_filename_.empty()) {
- return user_cmd(os,CtsApi::to_string(CtsApi::loadDefs("<in-memory-defs>",force_,false/*check_only*/)));
- }
- return user_cmd(os,CtsApi::to_string(CtsApi::loadDefs(defs_filename_,force_,false/*check_only*/)));
-}
-
-const char* LoadDefsCmd::arg() { return CtsApi::loadDefsArg();}
-const char* LoadDefsCmd::desc() {
- return "Check and load definition file into server.\n"
- "The loaded definition will be checked for valid trigger and complete expressions,\n"
- "additionally in-limit references to limits will be validated.\n"
- "If the server already has the 'suites' of the same name, then a error message is issued.\n"
- "The suite's can be overwritten if the force option is used.\n"
- "To just check the definition and not send to server, use 'check_only'\n"
- " arg1 = path to the definition file\n"
- " arg2 = (optional) [ force | check_only ] # default = false for both\n"
- "Usage:\n"
- "--load=/my/home/exotic.def # will error if suites of same name exists\n"
- "--load=/my/home/exotic.def force # overwrite suite's of same name\n"
- "--load=/my/home/exotic.def check_only # Just check, don't send to server"
- ;
-}
-
-void LoadDefsCmd::addOption(boost::program_options::options_description& desc) const{
- desc.add_options()( LoadDefsCmd::arg(), po::value< vector<string> >()->multitoken(), LoadDefsCmd:: desc() );
-}
-
-void LoadDefsCmd::create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const
-{
- vector<string> args = vm[ arg() ].as< vector<string> >();
- if (clientEnv->debug()) dumpVecArgs(LoadDefsCmd::arg(),args);
-
- bool check_only = false;
- bool force = false;
- std::string defs_filename;
- for(size_t i = 0; i < args.size(); i++) {
- if (args[i] == "force") force = true;
- else if (args[i] == "check_only") check_only = true;
- else defs_filename = args[i];
- }
- if (clientEnv->debug()) cout << "LoadDefsCmd::create: Defs file '" << defs_filename << "'.\n";
-
- cmd = LoadDefsCmd::create(defs_filename,force, check_only,clientEnv );
-}
-
-Cmd_ptr LoadDefsCmd::create(const std::string& defs_filename, bool force, bool check_only, AbstractClientEnv* clientEnv)
-{
- // The constructor can throw if parsing of defs_filename fail's
- boost::shared_ptr<LoadDefsCmd> load_cmd = boost::make_shared<LoadDefsCmd>(defs_filename,force);
-
- // Don't send to server if checking, i.e cmd not set
- if (check_only) return Cmd_ptr();
-
- // For test allow the server environment to be changed, i.e. allow us to inject ECF_CLIENT
- // The server will also update the env on the defs, server will override client env, where they clash
- load_cmd->theDefs()->set_server().add_or_update_user_variables( clientEnv->env() );
-
- return load_cmd;
-}
-
-
-std::ostream& operator<<(std::ostream& os, const LoadDefsCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/cts/LogCmd.cpp b/ecflow_4_0_7/Base/src/cts/LogCmd.cpp
deleted file mode 100644
index 39f8171..0000000
--- a/ecflow_4_0_7/Base/src/cts/LogCmd.cpp
+++ /dev/null
@@ -1,234 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #30 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include "boost/filesystem/path.hpp"
-#include "boost/filesystem/operations.hpp"
-
-#include "ClientToServerCmd.hpp"
-#include "AbstractServer.hpp"
-#include "AbstractClientEnv.hpp"
-#include "Log.hpp"
-#include "CtsApi.hpp"
-#include "Str.hpp"
-#include "Defs.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-namespace po = boost::program_options;
-namespace fs = boost::filesystem;
-
-
-LogCmd::LogCmd(LogApi a, int get_last_n_lines)
-: api_(a), get_last_n_lines_(get_last_n_lines)
-{
- if (get_last_n_lines_ == 0) get_last_n_lines_ = Log::get_last_n_lines_default();
-}
-
-
-LogCmd::LogCmd()
-: api_(LogCmd::GET),get_last_n_lines_(Log::get_last_n_lines_default()) {}
-
-
-LogCmd::LogCmd(const std::string& path)
-: api_(NEW),get_last_n_lines_(Log::get_last_n_lines_default()),new_path_(path)
-{
- // ECFLOW-154, If path to new log file is specified, it should only be checked by the server,
- // as that could be on a different machine.
- // ECFLOW-174, Never get the full log, as this can make server consume to much memory
- // default taken from get_last_n_lines_default
-}
-
-std::ostream& LogCmd::print(std::ostream& os) const
-{
- switch (api_) {
- case LogCmd::GET: return user_cmd(os,CtsApi::to_string(CtsApi::getLog(get_last_n_lines_))); break;
- case LogCmd::CLEAR: return user_cmd(os,CtsApi::clearLog()); break;
- case LogCmd::FLUSH: return user_cmd(os,CtsApi::flushLog()); break;
- case LogCmd::NEW: return user_cmd(os,CtsApi::to_string(CtsApi::new_log(new_path_))); break;
- case LogCmd::PATH: return user_cmd(os,CtsApi::get_log_path()); break;
- default : throw std::runtime_error( "LogCmd::print: Unrecognised log api command,") ;
- }
- return os;
-}
-
-bool LogCmd::equals(ClientToServerCmd* rhs) const
-{
- LogCmd* the_rhs = dynamic_cast< LogCmd* > ( rhs );
- if ( !the_rhs ) return false;
- if (api_ != the_rhs->api()) return false;
- if (get_last_n_lines_ != the_rhs->get_last_n_lines()) return false;
- if (new_path_ != the_rhs->new_path()) return false;
- return UserCmd::equals(rhs);
-}
-
-STC_Cmd_ptr LogCmd::doHandleRequest(AbstractServer* as) const
-{
- as->update_stats().log_cmd_++;
-
- if (Log::instance()) {
- switch (api_) {
- case LogCmd::GET: return PreAllocatedReply::string_cmd( Log::instance()->contents(get_last_n_lines_) ); break;
- case LogCmd::CLEAR: Log::instance()->clear(); break;
- case LogCmd::FLUSH: Log::instance()->flush(); break;
- case LogCmd::NEW: {
- if (!new_path_.empty()) {
- Log::instance()->new_path(new_path_); // will throw for errors
-
- // Update the corresponding server variable
- NameValueVec vec;
- vec.push_back(std::make_pair(Str::ECF_LOG(),Log::instance()->path()));
- as->defs()->set_server().add_or_update_server_variables(vec);
- }
- else {
- // User could have overridden ECF_LOG variable
- const std::string& log_file_name = as->defs()->server().find_variable(Str::ECF_LOG());
- Log::instance()->new_path(log_file_name); // will throw for errors
- }
-
- as->stats().ECF_LOG_ = Log::instance()->path(); // do NOT update number of requests
- break;
- }
- case LogCmd::PATH: return PreAllocatedReply::string_cmd( Log::instance()->path() ); break;
- default : throw std::runtime_error( "Unrecognised log api command,") ;
- }
- }
- return PreAllocatedReply::ok_cmd();
-}
-
-const char* LogCmd::arg() { return "log";}
-const char* LogCmd::desc() {
- return "Get,clear,flush or create a new log file.\n"
- "The user must ensure that a valid path is specified.\n"
- "Specifying '--log=get' with a large number of lines from the server,\n"
- "can consume a lot of **memory**. The log file can be a very large file,\n"
- "hence we use a default of 100 lines, optionally the number of lines can be specified.\n"
- " arg1 = [ get | clear | flush | new | path ]\n"
- " get - Outputs the log file to standard out.\n"
- " defaults to return the last 100 lines\n"
- " The second argument can specify how many lines to return\n"
- " clear - Clear the log file of its contents.\n"
- " flush - Flush and close the log file. (only temporary) next time\n"
- " server writes to log, it will be opened again. Hence it best\n"
- " to halt the server first\n"
- " new - Flush and close the existing log file, and start using the\n"
- " the path defined for ECF_LOG. By changing this variable\n"
- " a new log file path can be used\n"
- " Alternatively an explicit path can also be provided\n"
- " in which case ECF_LOG is also updated\n"
- " path - Returns the path name to the existing log file\n"
- " arg2 = [ new_path | optional last n lines ]\n"
- " if get specified can specify lines to get. Value must be convertible to an integer\n"
- " Otherwise if arg1 is 'new' then the second argument must be a path\n"
- "Usage:\n"
- " --log=get # Write the last 100 lines of the log file to standard out\n"
- " --log=get 200 # Write the last 200 lines of the log file to standard out\n"
- " --log=clear # Clear the log file. The log is now empty\n"
- " --log=flush # Flush and close log file, next request will re-open log file\n"
- " --log=new /path/to/new/log/file # Close and flush log file, and create a new log file, updates ECF_LOG\n"
- " --log=new # Close and flush log file, and create a new log file using ECF_LOG variable"
- ;
-}
-
-void LogCmd::addOption(boost::program_options::options_description& desc) const {
- desc.add_options()( LogCmd::arg(), po::value< vector<string> >()->multitoken(), LogCmd::desc() );
-}
-
-void LogCmd::create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* ac) const
-{
- vector<string> args = vm[ arg() ].as< vector<string> >();
-
- if (ac->debug()) dumpVecArgs(LogCmd::arg(),args);
-
- if (!args.empty() && args[0] == "get") {
-
- if ( args.size() != 1 && args.size() != 2) {
- std::stringstream ss;
- ss << "LogCmd: Please use '--log==get 100' to get the log file contents from the server\n";
- ss << "optionally an integer can be provide to specify the last number of lines\n";
- throw std::runtime_error( ss.str() );
- }
-
- if (args.size() == 1 ) {
- // This will retrieve Log::get_last_n_lines_default() lines from the log file.
- cmd = Cmd_ptr( new LogCmd( LogCmd::GET , Log::get_last_n_lines_default() ) );
- return;
- }
-
- int value = Log::get_last_n_lines_default();
- if (args.size() == 2) {
- try { value = boost::lexical_cast<int>(args[1]); }
- catch (boost::bad_lexical_cast& e) {
- throw std::runtime_error( "LogCmd: Second argument must be a integer, i.e. --log get 100\n" );
- }
- }
-
- cmd = Cmd_ptr( new LogCmd( LogCmd::GET, value ) );
- return ;
- }
-
- if (!args.empty() && args[0] == "clear") {
-
- if (args.size() != 1 ) {
- std::stringstream ss;
- ss << "LogCmd: Too many arguments. Please use " << CtsApi::clearLog() << " to clear the log file\n";
- throw std::runtime_error( ss.str() );
- }
- cmd = Cmd_ptr( new LogCmd( LogCmd::CLEAR ) );
- return;
- }
- if (!args.empty() && args[0] == "flush") {
-
- if (args.size() != 1 ) {
- std::stringstream ss;
- ss << "LogCmd: Too many arguments. Please use " << CtsApi::flushLog() << " to flush the log file\n";
- throw std::runtime_error( ss.str() );
- }
- cmd = Cmd_ptr( new LogCmd( LogCmd::FLUSH ) );
- return;
- }
- if (!args.empty() && args[0] == "path") {
-
- if (args.size() != 1 ) {
- std::stringstream ss;
- ss << "LogCmd: Too many arguments. Please use " << CtsApi::get_log_path() << " to get the log file path\n";
- throw std::runtime_error( ss.str() );
- }
- cmd = Cmd_ptr( new LogCmd( LogCmd::PATH ) );
- return;
- }
-
- if (!args.empty() && args[0] == "new") {
-
- if (args.size() > 2 ) {
- std::stringstream ss;
- ss << "LogCmd: Too many arguments. Expected --log=new OR --log=new /path/to/newlog/file\n";
- throw std::runtime_error( ss.str() );
- }
- std::string path;
- if ( args.size() == 2 ) {
- path = args[1];
- }
- cmd = Cmd_ptr( new LogCmd( path ) );
- return;
- }
-
- std::stringstream ss;
- ss << "LogCmd: The arguments have not been specified correctly\n" << LogCmd::desc();
- throw std::runtime_error( ss.str() );
-}
-
-std::ostream& operator<<(std::ostream& os, const LogCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/cts/LogMessageCmd.cpp b/ecflow_4_0_7/Base/src/cts/LogMessageCmd.cpp
deleted file mode 100644
index 0486f2d..0000000
--- a/ecflow_4_0_7/Base/src/cts/LogMessageCmd.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #14 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <iostream>
-
-#include "ClientToServerCmd.hpp"
-#include "AbstractServer.hpp"
-#include "AbstractClientEnv.hpp"
-#include "Log.hpp"
-#include "Stats.hpp"
-#include "CtsApi.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-namespace po = boost::program_options;
-
-std::ostream& LogMessageCmd::print(std::ostream& os) const
-{
- return user_cmd(os,CtsApi::logMsg(msg_));
-}
-
-bool LogMessageCmd::equals(ClientToServerCmd* rhs) const
-{
- LogMessageCmd* the_rhs = dynamic_cast< LogMessageCmd* > ( rhs );
- if ( !the_rhs ) return false;
- if (msg_ != the_rhs->msg()) return false;
- return UserCmd::equals(rhs);
-}
-
-STC_Cmd_ptr LogMessageCmd::doHandleRequest(AbstractServer* as) const
-{
- // ***** No need to log message here, already done via print, in base ****
- as->update_stats().log_msg_cmd_++;
- return PreAllocatedReply::ok_cmd();
-}
-
-const char* LogMessageCmd::arg() { return CtsApi::logMsgArg();}
-const char* LogMessageCmd::desc() {
- return
- "Writes the input string to the log file.\n"
- " arg1 = string\n"
- "Usage:\n"
- " --msg=\"place me in the log file\""
- ;
-}
-
-void LogMessageCmd::addOption(boost::program_options::options_description& desc) const {
- desc.add_options()( LogMessageCmd::arg(), po::value< string >(), LogMessageCmd::desc() );
-}
-
-void LogMessageCmd::create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* ace) const
-{
- string msg = vm[ arg() ].as< string >();
- if (ace->debug()) { cout << " LogMessageCmd::create arg = " << msg << "\n";}
- cmd = Cmd_ptr( new LogMessageCmd( msg ) );
-}
-
-std::ostream& operator<<(std::ostream& os, const LogMessageCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/cts/OrderNodeCmd.cpp b/ecflow_4_0_7/Base/src/cts/OrderNodeCmd.cpp
deleted file mode 100644
index b6f28b3..0000000
--- a/ecflow_4_0_7/Base/src/cts/OrderNodeCmd.cpp
+++ /dev/null
@@ -1,110 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #21 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include "ClientToServerCmd.hpp"
-#include "AbstractServer.hpp"
-#include "AbstractClientEnv.hpp"
-#include "CtsApi.hpp"
-#include "Defs.hpp"
-#include "Task.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-namespace po = boost::program_options;
-
-bool OrderNodeCmd::equals(ClientToServerCmd* rhs) const
-{
- OrderNodeCmd* the_rhs = dynamic_cast< OrderNodeCmd* > ( rhs );
- if ( !the_rhs ) return false;
- if (absNodepath_ != the_rhs->absNodepath()) return false;
- if (option_ != the_rhs->option()) return false;
- return UserCmd::equals(rhs);
-}
-
-std::ostream& OrderNodeCmd::print(std::ostream& os) const
-{
- return user_cmd(os,CtsApi::to_string(CtsApi::order(absNodepath_,NOrder::toString(option_))));
-}
-
-STC_Cmd_ptr OrderNodeCmd::doHandleRequest(AbstractServer* as) const
-{
- assert(isWrite()); // isWrite used in handleRequest() to control check pointing
-
- as->update_stats().order_node_++;
-
- node_ptr theNode = find_node_for_edit(as,absNodepath_);
-
- Node* theParent = theNode->parent();
- if ( theParent ) theParent->order(theNode.get(), option_);
- else as->defs()->order(theNode.get(), option_);
-
- return doJobSubmission( as );
-}
-
-const char* OrderNodeCmd::arg() { return CtsApi::orderArg();}
-const char* OrderNodeCmd::desc() {
- return
- "Re-orders the nodes held by the server\n"
- " arg1 = node path\n"
- " arg2 = [ top | bottom | alpha | order | up | down ]\n"
- "It should be noted that in the absence of triggers and time/date dependencies,\n"
- "the tasks are submitted in order.\n"
- "This changes the order and hence affects the submission order::\n\n"
- " o top raises the node within its parent, so that it is first\n"
- " o bottom lowers the node within its parent, so that it is last\n"
- " o alpha Arranges for all the peers of selected note to be sorted alphabetically (case-insensitive)\n"
- " o order Arranges for all the peers of selected note to be sorted in reverse alphabet(case-insensitive)\n"
- " o up Moves the selected node up one place amongst its peers\n"
- " o down Moves the selected node down one place amongst its peers\n\n"
- "This command can fail because:\n"
- "- The node path does not exist in the server\n"
- "- The order_type is not does not match one of arg2\n"
- "Usage:\n"
- " --order=/suite/f1 top # move node f1 to the top"
- ;
-}
-
-void OrderNodeCmd::addOption(boost::program_options::options_description& desc) const{
- desc.add_options()( OrderNodeCmd::arg(), po::value< vector<string> >()->multitoken(), OrderNodeCmd::desc() );
-}
-void OrderNodeCmd::create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* ac) const
-{
- vector<string> args = vm[ OrderNodeCmd::arg() ].as< vector<string> >();
-
- if (ac->debug()) dumpVecArgs(OrderNodeCmd::arg(),args);
-
- if (args.size() != 2 ) {
- std::stringstream ss;
- ss << "OrderNodeCmd: Two arguments expected. Please specify one of:\n";
- ss << OrderNodeCmd::arg() << " pathToNode top\n";
- ss << OrderNodeCmd::arg() << " pathToNode bottom\n";
- ss << OrderNodeCmd::arg() << " pathToNode alpha\n";
- ss << OrderNodeCmd::arg() << " pathToNode order\n";
- ss << OrderNodeCmd::arg() << " pathToNode up\n";
- ss << OrderNodeCmd::arg() << " pathToNode down\n";
- throw std::runtime_error( ss.str() );
- }
-
- if (!NOrder::isValid(args[1])) {
- throw std::runtime_error( "OrderNodeCmd: Invalid second option: please specify one of [ top, bottom, alpha, order, up, down ]\n");
- }
-
- cmd = Cmd_ptr(new OrderNodeCmd( args[0],NOrder::toOrder(args[1])));
-}
-
-std::ostream& operator<<(std::ostream& os, const OrderNodeCmd& c) { return c.print(os); }
-
diff --git a/ecflow_4_0_7/Base/src/cts/PathsCmd.cpp b/ecflow_4_0_7/Base/src/cts/PathsCmd.cpp
deleted file mode 100644
index 2ad9fdb..0000000
--- a/ecflow_4_0_7/Base/src/cts/PathsCmd.cpp
+++ /dev/null
@@ -1,505 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #16 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <algorithm>
-#include <boost/make_shared.hpp>
-
-#include "ClientToServerCmd.hpp"
-#include "AbstractServer.hpp"
-#include "AbstractClientEnv.hpp"
-#include "CtsApi.hpp"
-#include "Defs.hpp"
-#include "Task.hpp"
-#include "Suite.hpp"
-#include "SuiteChanged.hpp"
-#include "Ecf.hpp"
-#include "Log.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-namespace po = boost::program_options;
-
-// forward declare static functions
-static void check_for_active_or_submitted_tasks(AbstractServer* as,node_ptr theNodeToDelete);
-
-
-PathsCmd::PathsCmd(Api api,const std::string& absNodePath, bool force)
-: api_(api),force_(force)
-{
- if (!absNodePath.empty()) paths_.push_back(absNodePath);
-}
-
-std::ostream& PathsCmd::print(std::ostream& os) const
-{
- switch (api_) {
- case PathsCmd::DELETE: return user_cmd(os,CtsApi::to_string(CtsApi::delete_node(paths_,force_))); break;
- case PathsCmd::SUSPEND: return user_cmd(os,CtsApi::to_string(CtsApi::suspend(paths_))); break;
- case PathsCmd::RESUME: return user_cmd(os,CtsApi::to_string(CtsApi::resume(paths_))); break;
- case PathsCmd::KILL: return user_cmd(os,CtsApi::to_string(CtsApi::kill(paths_))); break;
- case PathsCmd::STATUS: return user_cmd(os,CtsApi::to_string(CtsApi::status(paths_))); break;
- case PathsCmd::CHECK: return user_cmd(os,CtsApi::to_string(CtsApi::check(paths_))); break;
- case PathsCmd::EDIT_HISTORY: return user_cmd(os,CtsApi::to_string(CtsApi::edit_history(paths_))); break;
- case PathsCmd::NO_CMD: break;
- default: assert(false);break;
- }
- return os;
-}
-
-bool PathsCmd::equals(ClientToServerCmd* rhs) const
-{
- PathsCmd* the_rhs = dynamic_cast< PathsCmd* > ( rhs );
- if ( !the_rhs ) return false;
- if (api_ != the_rhs->api()) return false;
- if (paths_ != the_rhs->paths()) return false;
- if (force_ != the_rhs->force()) return false;
- return UserCmd::equals(rhs);
-}
-
-bool PathsCmd::isWrite() const
-{
- switch (api_) {
- case PathsCmd::DELETE: return true; break; // requires write privilege
- case PathsCmd::SUSPEND: return true; break; // requires write privilege
- case PathsCmd::RESUME: return true; break; // requires write privilege
- case PathsCmd::KILL: return true; break; // requires write privilege
- case PathsCmd::STATUS: return false; break; // read only
- case PathsCmd::CHECK: return false; break; // read only
- case PathsCmd::EDIT_HISTORY: return false; break; // read only
- case PathsCmd::NO_CMD: break;
- default: break;
- }
- assert(false);
- return false;
-}
-
-const char* PathsCmd::theArg() const
-{
- switch (api_) {
- case PathsCmd::DELETE: return CtsApi::delete_node_arg(); break;
- case PathsCmd::SUSPEND: return CtsApi::suspend_arg(); break;
- case PathsCmd::RESUME: return CtsApi::resume_arg(); break;
- case PathsCmd::KILL: return CtsApi::kill_arg(); break;
- case PathsCmd::STATUS: return CtsApi::statusArg(); break;
- case PathsCmd::CHECK: return CtsApi::check_arg(); break;
- case PathsCmd::EDIT_HISTORY: return CtsApi::edit_history_arg(); break;
- case PathsCmd::NO_CMD: break;
- default: break;
- }
- assert(false);
- return NULL;
-}
-
-bool PathsCmd::delete_all_cmd() const
-{
- if (api_ == PathsCmd::DELETE && paths_.empty()) {
- return true;
- }
- return false ;
-}
-
-STC_Cmd_ptr PathsCmd::doHandleRequest(AbstractServer* as) const
-{
- std::stringstream ss;
- switch (api_) {
-
- case PathsCmd::CHECK: {
- as->update_stats().check_++;
-
- if ( paths_.empty() ) {
- // check all the defs,
- std::string error_msg,warning_msg;
- if (!as->defs()->check(error_msg,warning_msg)) {
- error_msg += "\n";
- error_msg += warning_msg;
- return PreAllocatedReply::string_cmd(error_msg);
- }
- return PreAllocatedReply::string_cmd(warning_msg); // can be empty
- }
- else {
- std::string acc_warning_msg;
- size_t vec_size = paths_.size();
- for(size_t i = 0; i < vec_size; i++) {
-
- node_ptr theNodeToCheck = as->defs()->findAbsNode(paths_[i]);
- if (!theNodeToCheck.get()) {
- ss << "PathsCmd:Check: Could not find node at path '" << paths_[i] << "'\n";
- LOG(Log::ERR,"Check: Could not find node at path " << paths_[i]);
- continue;
- }
-
- std::string error_msg,warning_msg;
- if (!theNodeToCheck->check(error_msg,warning_msg)) {
- error_msg += "\n";
- error_msg += warning_msg;
- return PreAllocatedReply::string_cmd(error_msg);
- }
- acc_warning_msg += warning_msg;
- }
- std::string paths_not_fnd_error_msg = ss.str();
- if (!paths_not_fnd_error_msg.empty()) throw std::runtime_error( paths_not_fnd_error_msg );
- return PreAllocatedReply::string_cmd(acc_warning_msg);
- }
- break;
- }
-
- case PathsCmd::DELETE: {
- as->update_stats().node_delete_++;
-
- if ( paths_.empty() ) {
- if (!force_) check_for_active_or_submitted_tasks(as,node_ptr());
- else as->zombie_ctrl().add_user_zombies(as->defs());
- as->clear_defs();
- }
- else {
-
- size_t vec_size = paths_.size();
- for(size_t i = 0; i < vec_size; i++) {
-
- node_ptr theNodeToDelete = as->defs()->findAbsNode(paths_[i]);
- if (!theNodeToDelete.get()) {
- ss << "PathsCmd:Delete: Could not find node at path '" << paths_[i] << "'\n";
- LOG(Log::ERR,"Delete: Could not find node at path " << paths_[i]);
- continue;
- }
-
- if (!force_) check_for_active_or_submitted_tasks(as,theNodeToDelete);
- else as->zombie_ctrl().add_user_zombies(theNodeToDelete);
-
- if (!as->defs()->deleteChild( theNodeToDelete.get() )) {
- std::string errorMsg = "Delete: Can not delete node " + theNodeToDelete->debugNodePath();
- throw std::runtime_error( errorMsg ) ;
- }
- }
- }
- break;
- }
-
- case PathsCmd::SUSPEND: {
- as->update_stats().node_suspend_++;
- size_t vec_size = paths_.size();
- for(size_t i = 0; i < vec_size; i++) {
- node_ptr theNode = find_node_for_edit_no_throw(as,paths_[i]);
- if (!theNode.get()) {
- ss << "PathsCmd:Suspend: Could not find node at path '" << paths_[i] << "'\n";
- LOG(Log::ERR,"Suspend: Could not find node at path " << paths_[i]);
- continue;
- }
- SuiteChanged0 changed(theNode);
- theNode->suspend();
- }
- break;
- }
-
- case PathsCmd::RESUME: {
-
- // At the end of resume, we need to traverse node tree, and do job submission
- as->update_stats().node_resume_++;
- size_t vec_size = paths_.size();
- for(size_t i = 0; i < vec_size; i++) {
- node_ptr theNode = find_node_for_edit_no_throw(as,paths_[i]);
- if (!theNode.get()) {
- ss << "PathsCmd:Resume: Could not find node at path '" << paths_[i] << "'\n";
- LOG(Log::ERR,"Resume: Could not find path " << paths_[i]);
- continue;
- }
- SuiteChanged0 changed(theNode);
- theNode->resume();
- as->increment_job_generation_count(); // in case we throw below
- }
- break;
- }
-
- case PathsCmd::KILL: {
- as->update_stats().node_kill_++;
- size_t vec_size = paths_.size();
- for(size_t i = 0; i < vec_size; i++) {
- node_ptr theNode = find_node_for_edit_no_throw(as,paths_[i]);
- if (!theNode.get()) {
- ss << "PathsCmd:Kill: Could not find node at path '" << paths_[i] << "'\n";
- LOG(Log::ERR,"Kill: Could not find node at path " << paths_[i]);
- continue;
- }
- SuiteChanged0 changed(theNode);
- theNode->kill(); // this can throw std::runtime_error
- }
- break;
- }
-
- case PathsCmd::STATUS: {
- as->update_stats().node_status_++;
- size_t vec_size = paths_.size();
- for(size_t i = 0; i < vec_size; i++) {
- node_ptr theNode = find_node_for_edit_no_throw(as,paths_[i]);
- if (!theNode.get()) {
- ss << "PathsCmd:Status: Could not find node at path '" << paths_[i] << "'\n";
- LOG(Log::ERR,"Status: Could not find node at path " << paths_[i]);
- continue;
- }
- if (!theNode->suite()->begun()) {
- std::stringstream ss;
- ss << "Status failed. For " << paths_[i] << " The suite " << theNode->suite()->name() << " must be 'begun' first\n";
- throw std::runtime_error( ss.str() ) ;
- }
- SuiteChanged0 changed(theNode);
- theNode->status(); // this can throw std::runtime_error
- }
- break;
- }
-
- case PathsCmd::EDIT_HISTORY: {
- as->update_stats().node_edit_history_++;
- if (paths_.empty()) throw std::runtime_error( "No paths specified for edit history") ;
- // Only first path used
- const std::deque<std::string>& edit_history = as->defs()->get_edit_history(paths_[0]);
- std::vector<std::string> vec; vec.reserve(edit_history.size());
- std::copy(edit_history.begin(),edit_history.end(),std::back_inserter(vec));
- return PreAllocatedReply::string_vec_cmd(vec);
- }
-
- case PathsCmd::NO_CMD: assert(false); break;
-
- default: assert(false); break;
- }
-
- // Clear up memory allocated to path.
- // When dealing with several thousands paths, this makes a *HUGE* difference
- vector<string>().swap(paths_); // clear paths_ and minimise its capacity
-
- std::string error_msg = ss.str();
- if (!error_msg.empty()) {
- throw std::runtime_error( error_msg ) ;
- }
-
- if ( PathsCmd::RESUME == api_) {
- // After resume we need to do job submission.
- return doJobSubmission(as);
- }
-
- return PreAllocatedReply::ok_cmd();
-}
-
-static void check_for_active_or_submitted_tasks(AbstractServer* as,node_ptr theNodeToDelete)
-{
- vector<Task*> taskVec;
- if ( theNodeToDelete.get() ) {
- theNodeToDelete->getAllTasks(taskVec);
- }
- else {
- as->defs()->getAllTasks(taskVec);
- }
-
- vector<Task*> activeVec,submittedVec;
- BOOST_FOREACH(Task* t, taskVec) {
- if (t->state() == NState::ACTIVE) activeVec.push_back(t);
- if (t->state() == NState::SUBMITTED) submittedVec.push_back(t);
- }
- if (!activeVec.empty() || !submittedVec.empty()) {
- std::stringstream ss;
- if (theNodeToDelete.get()) ss << "Can not delete node " << theNodeToDelete->debugNodePath() << "\n";
- else ss << "Can not delete all nodes.\n";
- if (!activeVec.empty() ) {
- ss << " There are " << activeVec.size() << " active tasks. First : " << activeVec.front()->absNodePath() << "\n";
- }
- if (!submittedVec.empty() ) {
- ss << " There are " << submittedVec.size() << " submitted tasks. First : " << submittedVec.front()->absNodePath() << "\n";
- }
- ss << "Please use the 'force' option to bypass this check, at the expense of creating zombies\n";
- throw std::runtime_error( ss.str() ) ;
- }
-}
-
-static const char* delete_node_desc() {
- return
- "Deletes the specified node(s) or _ALL_ existing definitions( i.e delete all suites) in the server.\n"
- " arg1 = [ force | yes ](optional) # Use this parameter to bypass checks, i.e. for active or submitted tasks\n"
- " arg2 = yes(optional) # Use 'yes' to bypass the confirmation prompt\n"
- " arg3 = node paths | _all_ # _all_ means delete all suites\n"
- " # node paths must start with a leading '/'\n"
- "Usage:\n"
- " --delete=_all_ # Delete all suites in server. Use with care.\n"
- " --delete=/suite/f1/t1 # Delete node at /suite/f1/t1. This will prompt\n"
- " --delete=force /suite/f1/t1 # Delete node at /suite/f1/t1 even if active or submitted\n"
- " --delete=force yes /s1 /s2 # Delete suites s1,s2 even if active or submitted, bypassing prompt"
- ;
-}
-
-static const char* get_check_desc() {
- return
- "Checks the expression and limits in the server. Will also check trigger references.\n"
- "Trigger expressions that reference paths that don't exist, will be reported as errors.\n"
- "(Note: On the client side unresolved paths in trigger expressions must\n"
- "have an associated 'extern' specified)\n"
- " arg = [ _all_ | list of node paths ]\n"
- "Usage:\n"
- " --check=_all_ # Checks the whole suite\n"
- " --check /s1 /s2/f1/t1 # Check suite /s1 and task t1"
- ;
-}
-
-static const char* get_kill_desc() {
- return
- "Kills the job associated with the node.\n"
- "If a family or suite is selected, will kill hierarchically.\n"
- "Kill uses the ECF_KILL_CMD variable. After variable substitution it is invoked as a command.\n"
- "The command should be written in such a way that the output is written to %ECF_JOB%.kill\n"
- "as this allow the --file command to report the output: .e.e.\n"
- " /home/ma/emos/bin/ecfkill %USER% %HOST% %ECF_RID% %ECF_JOB% > %ECF_JOB%.kill 2>&1::\n"
- "Usage::\n"
- " --kill /s1/f1/t1 /s1/f2/t2 # kill the jobs for tasks t1 and t2\n"
- " --file /s1/f1/t1 kill # write to standard out the '.kill' file for task /s1/f1/t1"
- ;
-}
-const char* get_status_desc(){
- return
- "Shows the status of a job associated with a task.\n"
- "If a family or suite is selected, will invoke status command hierarchically.\n"
- "Status uses the ECF_STATUS_CMD variable. After variable substitution it is invoked as a command.\n"
- "The command should be written in such a way that the output is written to %ECF_JOB%.stat\n"
- "This will allow the output of status command to be shown by the --file command\n"
- "i.e /home/ma/emos/bin/ecfstatus %USER% %HOST% %ECF_RID% %ECF_JOB% > %ECF_JOB%.stat 2>&1::\n"
- "Usage::\n"
- " --status /s1/f1/t1 /s1/f2/t2\n"
- " --file /s1/f1/t1 stat # write to standard out the '.stat' file"
- ;
-}
-const char* get_edit_history_desc(){
- return
- "Returns the edit history associated with a Node.\n"
- "Usage::\n"
- " --edit_history /s1/f1/t1\n"
- ;
-}
-const char* suspend_desc(){
- return
- "Suspend the given node. This prevents job generation for the given node, or any child node.\n"
- "Usage::\n"
- " --suspend /s1/f1/t1 # suspend task s1/f1/t1\n"
- " --suspend /s1 /s2 # suspend suites /s1 and /s2\n"
- ;
-}
-const char* resume_desc(){
- return
- "Resume the given node. This allows job generation for the given node, or any child node.\n"
- "Usage::\n"
- " --resume /s1/f1/t1 # resume task s1/f1/t1\n"
- " --resume /s1 /s2 # resume suites /s1 and /s2\n"
- ;
-}
-
-void PathsCmd::addOption(boost::program_options::options_description& desc) const
-{
- switch (api_) {
- case PathsCmd::CHECK:{
- desc.add_options()(CtsApi::check_arg(),po::value< vector<string> >()->multitoken(),get_check_desc());
- break;
- }
- case PathsCmd::DELETE:{
- desc.add_options()( CtsApi::delete_node_arg(), po::value< vector<string> >()->multitoken(), delete_node_desc() );
- break;
- }
- case PathsCmd::SUSPEND:{
- desc.add_options()( CtsApi::suspend_arg(), po::value< vector<string> >()->multitoken(),suspend_desc());
- break;
- }
- case PathsCmd::RESUME: {
- desc.add_options()( CtsApi::resume_arg(), po::value< vector<string> >()->multitoken(),resume_desc());
- break;
- }
- case PathsCmd::KILL: {
- desc.add_options()( CtsApi::kill_arg(), po::value< vector<string> >()->multitoken(),get_kill_desc());
- break;
- }
- case PathsCmd::STATUS: {
- desc.add_options()( CtsApi::statusArg(), po::value< vector<string> >()->multitoken(), get_status_desc());
- break;
- }
- case PathsCmd::EDIT_HISTORY: {
- desc.add_options()( CtsApi::edit_history_arg(), po::value< vector<string> >()->multitoken(), get_edit_history_desc());
- break;
- }
- case PathsCmd::NO_CMD: assert(false); break;
- default: assert(false); break;
- }
-}
-
-void PathsCmd::create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* ac ) const
-{
- assert( api_ != PathsCmd::NO_CMD);
-
- vector<string> args = vm[ theArg() ].as< vector<string> >();
- if (ac->debug()) dumpVecArgs( theArg(), args);
-
- std::vector<std::string> options,paths;
- split_args_to_options_and_paths(args,options,paths); // relative order is still preserved
-
- bool force = false;
- if (api_ == PathsCmd::DELETE) {
- bool all = false;
- bool do_prompt = true;
- size_t vec_size = options.size();
- for(size_t i = 0; i < vec_size; i++) {
- if (args[i] == "_all_") all = true;
- if (args[i] == "force") force = true;
- if (args[i] == "yes") do_prompt = false;
- }
-
- if (!all && paths.empty()) {
- std::stringstream ss;
- ss << "Delete: No paths specified. Paths must begin with a leading '/' character\n";
- throw std::runtime_error( ss.str() );
- }
-
- if (do_prompt) {
- std::string confirm;
- if (paths.empty()) confirm = "Are you sure you want to delete all the suites ? ";
- else {
- confirm = "Are you sure want to delete nodes at paths:\n";
- size_t vec_size = paths.size();
- for(size_t i = 0; i < vec_size; i++) {
- confirm += " " + paths[i];
- if ( i == vec_size -1) confirm += " ? ";
- else confirm += "\n";
- }
- }
- prompt_for_confirmation(confirm);
- }
- }
- else if (api_ == PathsCmd::CHECK) {
-
- bool all = false;
- size_t vec_size = options.size();
- for(size_t i = 0; i < vec_size; i++) {
- if (args[i] == "_all_") all = true;
- }
- if (!all && paths.empty()) {
- std::stringstream ss;
- ss << "Check: Please specify '_all_' or a list of paths. Paths must begin with a leading '/' character\n";
- throw std::runtime_error( ss.str() );
- }
- }
- else {
- if (paths.empty()) {
- std::stringstream ss;
- ss << theArg() << ": No paths specified. Paths must begin with a leading '/' character\n";
- throw std::runtime_error( ss.str() );
- }
- }
-
- cmd = Cmd_ptr(new PathsCmd( api_ , paths, force));
-}
-
-std::ostream& operator<<(std::ostream& os, const PathsCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/cts/PlugCmd.cpp b/ecflow_4_0_7/Base/src/cts/PlugCmd.cpp
deleted file mode 100644
index c108725..0000000
--- a/ecflow_4_0_7/Base/src/cts/PlugCmd.cpp
+++ /dev/null
@@ -1,392 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #32 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/make_shared.hpp>
-
-#include "ClientToServerCmd.hpp"
-#include "AbstractServer.hpp"
-#include "AbstractClientEnv.hpp"
-#include "Str.hpp"
-#include "CtsApi.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Task.hpp"
-#include "Family.hpp"
-#include "NodePath.hpp"
-#include "Client.hpp"
-#include "SuiteChanged.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-namespace po = boost::program_options;
-
-//=======================================================================================
-
-bool PlugCmd::equals(ClientToServerCmd* rhs) const
-{
- PlugCmd* the_rhs = dynamic_cast<PlugCmd*>(rhs);
- if (!the_rhs) return false;
- if ( source_ != the_rhs->source()) { return false; }
- if ( dest_ != the_rhs->dest()) { return false; }
- return UserCmd::equals(rhs);
-}
-
-std::ostream& PlugCmd::print(std::ostream& os) const
-{
- return user_cmd(os,CtsApi::to_string(CtsApi::plug(source_,dest_)));
-}
-
-/// Class to manage locking: Only unlock if acquired the lock,
-class Lock {
-public:
- Lock(const std::string& user, AbstractServer* as) : as_(as) { ok_ = as->lock(user); }
- ~Lock() { if (ok_) as_->unlock(); }
- bool ok() const { return ok_;}
-private:
- bool ok_;
- AbstractServer* as_;
-};
-
-STC_Cmd_ptr PlugCmd::doHandleRequest(AbstractServer* as) const
-{
- as->update_stats().plug_++;
-
- Lock lock(user(),as);
- if (!lock.ok()) {
- std::string errorMsg = "Plug command failed. User "; errorMsg += as->lockedUser();
- errorMsg += " already has an exclusive lock";
- throw std::runtime_error( errorMsg ) ;
- }
-
- node_ptr sourceNode = as->defs()->findAbsNode(source_);
- if (!sourceNode.get()) throw std::runtime_error( "Plug command failed. Could not find source path " + source_ ) ;
-
- // Moving a node which is active, or submitted, will lead to zombie's. hence prevent
- if (sourceNode->state() == NState::ACTIVE || sourceNode->state() == NState::SUBMITTED) {
- std::string errorMsg = "Plug command failed. The source node "; errorMsg += source_;
- errorMsg += " is ";
- errorMsg += NState::toString(sourceNode->state());
- throw std::runtime_error( errorMsg ) ;
- }
-
- if (sourceNode->isAlias()) {
- std::string errorMsg = "Plug command failed. The source node "; errorMsg += source_;
- errorMsg += " is a Alias. Alias can not be moved";
- throw std::runtime_error( errorMsg ) ;
- }
-
-
- // Check to see if dest node is on the same server
- std::string host,port,destPath;
- node_ptr destNode = as->defs()->findAbsNode(dest_);
- if (!destNode.get()) {
-
- // Dest could still be on the same server. Extract host and port
- // expect: host:port/suite/family/node
- if (!NodePath::extractHostPort(dest_,host,port)) {
- std::string errorMsg = "Plug command failed. The destination path "; errorMsg += dest_;
- errorMsg += " does not exist on server, and could not extract host/port from the destination path";
- throw std::runtime_error( errorMsg ) ;
- }
-
- // Remove the host:port from the path
- destPath = NodePath::removeHostPortFromPath(dest_);
-
- std::pair<std::string,std::string> hostPortPair = as->hostPort();
- if ( hostPortPair.first == host && hostPortPair.second == port) {
-
- // Matches local server, try to find dest node again.
- destNode = as->defs()->findAbsNode(destPath);
- if (!destNode) {
- std::string errorMsg = "Plug command failed. The destination path "; errorMsg += dest_;
- errorMsg += " does not exist on server "; errorMsg += hostPortPair.first;
- throw std::runtime_error( errorMsg ) ;
- }
- }
- // dest_ is on another server.
- }
-
- if (!destNode.get()) {
-
- // Since host/port does not match local server, move source node to remote server
- try {
- if (destPath.empty()) {
- // Note destPath can be empty, when moving a suite
- if (!sourceNode->isSuite()) {
- throw std::runtime_error( "Destination path can only be empty when moving a whole suite to a new server" ) ;
- }
- }
-
- {
- // Server is acting like a client, Send MoveCmd to another server
- // The source should end up being copied, when sent to remote server
- boost::asio::io_service io_service;
- Client theClient( io_service, Cmd_ptr( new MoveCmd(as->hostPort(),sourceNode.get(), destPath) ), host, port );
- io_service.run();
-
- ServerReply server_reply;
- theClient.handle_server_response( server_reply, false /* debug */ );
- if (server_reply.client_request_failed()) {
- throw std::runtime_error( server_reply.error_msg() ) ;
- }
- }
-
- // The move command was ok, remove the source node, and delete its memory
- sourceNode->remove();
-
- // Updated defs state
- as->defs()->set_most_significant_state();
-
- return PreAllocatedReply::ok_cmd();
- }
- catch (std::exception& e) {
- std::stringstream ss; ss << "MoveCmd Failed for " << host << ":" << port << " " << e.what() << "\n";
- throw std::runtime_error( ss.str() ) ;
- }
- }
-
- // source and destination on same defs file
-
- // If the destination is task, replace with its parent
-
- Node* theDestNode = destNode.get();
- if (theDestNode->isTask()) theDestNode = theDestNode->parent();
-
- // Before we do remove the source node, check its ok to add it as a child
- std::string errorMsg;
- if (!theDestNode->isAddChildOk(sourceNode.get(),errorMsg) ) {
- throw std::runtime_error( "Plug command failed. " + errorMsg ) ;
- }
-
- if (!theDestNode->addChild( sourceNode->remove() ) ) {
- // This should never fail !!!! else we have lost/ and leaked source node !!!!
- throw std::runtime_error("Fatal error plug command failed.") ;
- }
-
- add_node_for_edit_history(destNode);
-
- // Updated defs state
- as->defs()->set_most_significant_state();
-
- return PreAllocatedReply::ok_cmd();
-}
-
-const char* PlugCmd::arg() { return CtsApi::plugArg();}
-const char* PlugCmd::desc() {
- return
- "Plug command is used to move nodes.\n"
- "The destination node can be on another server In which case the destination\n"
- "path should be of the form '<host>:<port>/suite/family/task\n"
- " arg1 = path to source node\n"
- " arg2 = path to the destination node\n"
- "This command can fail because:\n"
- "- Source node is in a 'active' or 'submitted' state\n"
- "- Another user already has an lock\n"
- "- source/destination paths do not exist on the corresponding servers\n"
- "- If the destination node path is empty, i.e. only host:port is specified,\n"
- " then the source node must correspond to a suite.\n"
- "- If the source node is added as a child, then its name must be unique\n"
- " amongst its peers\n"
- "Usage:\n"
- " --plug=/suite macX:3141 # move the suite to ecFlow server on host(macX) and port(3141)"
- ;
-}
-
-void PlugCmd::addOption(boost::program_options::options_description& desc) const {
- desc.add_options()( PlugCmd::arg(),po::value< vector<string> >()->multitoken(), PlugCmd::desc() );
-}
-
-void PlugCmd::create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* ace) const
-{
- vector<string> args = vm[ arg() ].as< vector<string> >();
-
- if (ace->debug()) dumpVecArgs(PlugCmd::arg(),args);
-
- if (args.size() != 2 ) {
- std::stringstream ss;
- ss << "PlugCmd: Two arguments are expected, found " << args.size() << "\n" << PlugCmd::desc() << "\n";
- throw std::runtime_error( ss.str() );
- }
-
- std::string sourceNode = args[0];
- std::string destNode = args[1];
-
- cmd = Cmd_ptr( new PlugCmd(sourceNode, destNode) );
-}
-
-// ===================================================================================
-
-MoveCmd::MoveCmd(const std::pair<std::string,std::string>& host_port, Node* src, const std::string& dest)
- : sourceSuite_(src->isSuite()),
- sourceFamily_(src->isFamily()),
- sourceTask_(src->isTask()),
- src_host_(host_port.first),
- src_port_(host_port.second),
- src_path_(src->absNodePath()),
- dest_(dest) {}
-
-MoveCmd::MoveCmd()
-: sourceSuite_(NULL),
- sourceFamily_(NULL),
- sourceTask_(NULL) {}
-
-MoveCmd::~MoveCmd(){}
-
-bool MoveCmd::equals(ClientToServerCmd* rhs) const
-{
- MoveCmd* the_rhs = dynamic_cast<MoveCmd*>(rhs);
- if (!the_rhs) return false;
- if (dest_ != the_rhs->dest()) { return false; }
-
- Node* theSource = source();
- if (theSource == NULL && the_rhs->source()) { return false; }
- if (theSource && the_rhs->source() == NULL) { return false; }
- if (theSource == NULL && the_rhs->source() == NULL) { return true; }
- if (theSource->absNodePath() != the_rhs->source()->absNodePath()) { return false; }
- return UserCmd::equals(rhs);
-}
-
-std::ostream& MoveCmd::print(std::ostream& os) const
-{
- std::stringstream ss;
- ss << "Plug(Move) source(" << src_host_ << ":" << src_port_ << ":" << src_path_ << ") destination(" << dest_ << ")";
- return user_cmd(os,ss.str());
-}
-
-Node* MoveCmd::source() const
-{
- if ( sourceSuite_ ) return sourceSuite_ ;
- if ( sourceFamily_ ) return sourceFamily_;
- if ( sourceTask_ ) return sourceTask_;
- return NULL;
-}
-
-bool MoveCmd::check_source() const
-{
- if ( sourceSuite_ || sourceFamily_ || sourceTask_ ) return true ;
- return false;
-}
-
-STC_Cmd_ptr MoveCmd::doHandleRequest(AbstractServer* as) const
-{
- Lock lock(user(),as);
- if (!lock.ok()) {
- std::string errorMsg = "Plug(Move) command failed. User "; errorMsg += as->lockedUser();
- errorMsg += " already has an exclusive lock";
- throw std::runtime_error( errorMsg);
- }
-
- if (!check_source()) {
- throw std::runtime_error("Plug(Move) command failed. No source specified");
- }
-
- // destNode can be NULL when we are moving a suite
- node_ptr destNode;
- if (!dest_.empty()) {
-
- if (!as->defs()) throw std::runtime_error( "No definition in server");
-
- destNode = as->defs()->findAbsNode(dest_);
- if (!destNode.get()) {
- std::string errorMsg = "Plug(Move) command failed. The destination path "; errorMsg += dest_;
- errorMsg += " does not exist on server";
- throw std::runtime_error( errorMsg);
- }
- }
- else {
- if (!source()->isSuite()) {
- throw std::runtime_error("::Destination path can only be empty when moving a whole suite to a new server");
- }
- }
-
- if (destNode.get()) {
-
- // The destNode containing suite may be in a handle
- SuiteChanged0 suiteChanged(destNode);
-
- // If the destination is task, replace with its parent
- Node* thedestNode = destNode.get();
- if (thedestNode->isTask()) thedestNode = thedestNode->parent();
-
- // check its ok to add
- std::string errorMsg;
- if (!thedestNode->isAddChildOk(source(),errorMsg) ) {
- std::string msg = "Plug(Move) command failed. "; msg += errorMsg;
- throw std::runtime_error( msg) ;
- }
-
- // pass ownership
- if (!thedestNode->addChild( node_ptr( source() ) )) {
- // This should never fail !!!! else we have lost/ and leaked source node !!!!
- throw std::runtime_error("Fatal error plug(move) command failed.") ;
- }
-
- add_node_for_edit_history(destNode);
- }
- else {
-
- if (!sourceSuite_) throw std::runtime_error("Source node was expected to be a suite");
-
- suite_ptr the_source_suite(sourceSuite_); // pass ownership to suite_ptr
-
- // The sourceSuite may be in a handle or pre-registered suite
- SuiteChanged suiteChanged(the_source_suite);
-
- if (!as->defs()) {
- defs_ptr newDefs = Defs::create();
- newDefs->addSuite( the_source_suite );
- as->updateDefs( newDefs, true /*force*/ ); // force is mute, since we adding a new defs in the server
- }
- else {
-
- if (as->defs()->findSuite(the_source_suite->name())) {
- std::stringstream ss; ss << "Suite of name " << the_source_suite->name() << " already exists\n";
- throw std::runtime_error( ss.str() );
- }
-
- as->defs()->addSuite( the_source_suite ) ;
- }
-
- /// A bit of hack, since need a way of getting a node_ptr from a Node*
- add_node_for_edit_history(as,the_source_suite->absNodePath());
- }
-
- // Updated defs state
- if (as->defs()) as->defs()->set_most_significant_state();
-
- // Ownership for sourceSuite_ has been passed on.
- sourceSuite_ = NULL;
- sourceFamily_ = NULL;
- sourceTask_ = NULL;
-
- return PreAllocatedReply::ok_cmd();
-}
-
-const char* MoveCmd::arg() { return "move";}
-const char* MoveCmd::desc() { return "The move command is an internal cmd, Called by the plug cmd. Does not appear on public api.";}
-
-void MoveCmd::addOption(boost::program_options::options_description& desc) const {
- desc.add_options()( MoveCmd::arg(),po::value< vector<string> >()->multitoken(), MoveCmd::desc() );
-}
-
-void MoveCmd::create(Cmd_ptr&, boost::program_options::variables_map&, AbstractClientEnv* ) const
-{
- assert(false);
-}
-
-std::ostream& operator<<(std::ostream& os, const PlugCmd& c) { return c.print(os); }
-std::ostream& operator<<(std::ostream& os, const MoveCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/cts/ReplaceNodeCmd.cpp b/ecflow_4_0_7/Base/src/cts/ReplaceNodeCmd.cpp
deleted file mode 100644
index cc93e76..0000000
--- a/ecflow_4_0_7/Base/src/cts/ReplaceNodeCmd.cpp
+++ /dev/null
@@ -1,203 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #37 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <boost/make_shared.hpp>
-
-#include "ClientToServerCmd.hpp"
-#include "AbstractServer.hpp"
-#include "AbstractClientEnv.hpp"
-#include "CtsApi.hpp"
-#include "Defs.hpp"
-#include "DefsStructureParser.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-namespace po = boost::program_options;
-
-ReplaceNodeCmd::ReplaceNodeCmd(const std::string& node_path, bool createNodesAsNeeded, defs_ptr defs, bool force )
-: createNodesAsNeeded_(createNodesAsNeeded), force_(force), pathToNode_(node_path), clientDefs_(defs)
-{
- if (!clientDefs_.get()) {
- throw std::runtime_error( "ReplaceNodeCmd::ReplaceNodeCmd: client definition is empty" );
- }
-
- // Client defs has been created in memory.
- // warn about naff expression and unresolved in-limit references to Limit's
- std::string errMsg, warningMsg;
- if (!clientDefs_->check(errMsg, warningMsg)) {
- throw std::runtime_error(errMsg);
- }
-
- // Make sure pathToNode exists in the client defs
- node_ptr nodeToReplace = clientDefs_->findAbsNode( node_path );
- if (! nodeToReplace.get() ) {
- std::stringstream ss;
- ss << "ReplaceNodeCmd::ReplaceNodeCmd: Can not replace child since path " << node_path;
- ss << " does not exist in the client definition ";
- throw std::runtime_error( ss.str() );
- }
-
- // Out put any warning's to standard output
- cout << warningMsg;
-}
-
-ReplaceNodeCmd::ReplaceNodeCmd(const std::string& node_path, bool createNodesAsNeeded, const std::string& path_to_defs, bool force )
-: createNodesAsNeeded_(createNodesAsNeeded),
- force_(force),
- pathToNode_(node_path),
- path_to_defs_(path_to_defs),
- clientDefs_(Defs::create())
-{
- // Parse the file and load the defs file into memory.
- DefsStructureParser checkPtParser( clientDefs_.get(), path_to_defs );
- std::string errMsg, warningMsg;
- if ( ! checkPtParser.doParse( errMsg , warningMsg) ) {
- std::stringstream ss;
- ss << "ReplaceNodeCmd::ReplaceNodeCmd: Could not parse file " << path_to_defs << " : " << errMsg;
- throw std::runtime_error( ss.str() );
- }
-
- // Make sure pathToNode exists in the client defs
- node_ptr nodeToReplace = clientDefs_->findAbsNode( node_path );
- if (! nodeToReplace.get() ) {
- std::stringstream ss;
- ss << "ReplaceNodeCmd::ReplaceNodeCmd: Can not replace child since path " << node_path;
- ss << ", does not exist in the client definition " << path_to_defs;
- throw std::runtime_error( ss.str() );
- }
-
- // Out put any warning's to standard output
- cout << warningMsg;
-}
-
-bool ReplaceNodeCmd::equals(ClientToServerCmd* rhs) const
-{
- ReplaceNodeCmd* the_rhs = dynamic_cast<ReplaceNodeCmd*>(rhs);
- if (!the_rhs) return false;
-
- if (!UserCmd::equals(rhs)) return false;
-
- if (createNodesAsNeeded_ != the_rhs->createNodesAsNeeded()) { return false; }
- if (force_ != the_rhs->force()) return false;
- if (pathToNode_ != the_rhs->pathToNode()) return false;
- if (path_to_defs_ != the_rhs->path_to_defs()) return false;
-
- if (clientDefs_ == NULL && the_rhs->theDefs() == NULL) return true;
- if (clientDefs_ == NULL && the_rhs->theDefs() != NULL) return false;
- if (clientDefs_ != NULL && the_rhs->theDefs() == NULL) return false;
-
- return (*clientDefs_ == *(the_rhs->theDefs()));
-}
-
-STC_Cmd_ptr ReplaceNodeCmd::doHandleRequest(AbstractServer* as) const
-{
- as->update_stats().replace_++;
-
- assert(isWrite()); // isWrite used in handleRequest() to control check pointing
- if (clientDefs_) {
-
- if (as->defs().get() == clientDefs_.get()) {
- /// Typically will only happen with test environment
- throw std::runtime_error("ReplaceNodeCmd::doHandleRequest: The definition in the server is the same as the client provided definition??");
- }
-
- if (force_) {
- as->zombie_ctrl().add_user_zombies( as->defs()->findAbsNode( pathToNode_ ) );
- }
-
- std::string errorMsg;
- if (!as->defs()->replaceChild(pathToNode_, clientDefs_, createNodesAsNeeded_, force_, errorMsg)) {
- throw std::runtime_error(errorMsg);
- }
-
- add_node_for_edit_history(as,pathToNode_);
- }
- return doJobSubmission( as );
-}
-
-std::ostream& ReplaceNodeCmd::print(std::ostream& os) const
-{
- std::string path_to_client_defs = path_to_defs_;
- if (path_to_client_defs.empty()) path_to_client_defs = "<empty>"; // defs must have bee loaded in memory via python api
- return user_cmd(os,CtsApi::to_string(CtsApi::replace(pathToNode_,path_to_client_defs,createNodesAsNeeded_,force_)));
-}
-
-const char* ReplaceNodeCmd::arg() { return CtsApi::replace_arg();}
-const char* ReplaceNodeCmd::desc() {
- /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
- return
- "Replaces a node in the server, with the given path\n"
- "Can also be used to add nodes in the server\n"
- " arg1 = path to node\n"
- " must exist in the client defs(arg2). This is also the node we want to\n"
- " replace in the server\n"
- " arg2 = path to client definition file\n"
- " provides the definition of the new node\n"
- " arg3 = (optional) [ parent | false ] (default = parent)\n"
- " create parent families or suite as needed, when arg1 does not\n"
- " exist in the server\n"
- " arg4 = (optional) force (default = false) \n"
- " Force the replacement even if it causes zombies to be created\n"
- "Replace can fail if:\n"
- "- The node path(arg1) does not exist in the provided client definition(arg2)\n"
- "- The client definition(arg2) must be free of errors\n"
- "- If the third argument is not provided, then node path(arg1) must exist in the server\n"
- "- Nodes to be replaced are in active/submitted state, in which case arg4(force) can be used\n\n"
- "After replace is done, we check trigger expressions. These are reported to standard output.\n"
- "It is up to the user to correct invalid trigger expressions, otherwise the tasks will *not* run.\n"
- "Please note, you can use --check to check trigger expression and limits in the server.\n"
- "For more information use --help check.\n\n"
- "Usage:\n"
- " --replace=/suite/f1/t1 /tmp/client.def parent # Add/replace node tree /suite/f1/t1\n"
- " --replace=/suite/f1/t1 /tmp/client.def false force # replace t1 even if its active or submitted";
-}
-
-void ReplaceNodeCmd::addOption(boost::program_options::options_description& desc) const {
- desc.add_options()( ReplaceNodeCmd::arg(),po::value< vector<string> >()->multitoken(), ReplaceNodeCmd::desc() );
-}
-void ReplaceNodeCmd::create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const
-{
- vector<string> args = vm[ arg() ].as< vector<string> >();
-
- if (clientEnv->debug()) dumpVecArgs(ReplaceNodeCmd::arg(),args);
-
- if (args.size() < 2 ) {
- std::stringstream ss;
- ss << "ReplaceNodeCmd: At least two arguments expected, found " << args.size()
- << " Please specify <path-to-Node> <defs files> parent(optional) force(optional), i.e\n"
- << "--" << arg() << "=/suite/fa/t AdefsFile.def parent force\n";
- throw std::runtime_error( ss.str() );
- }
-
- std::string pathToNode = args[0];
- std::string pathToDefsFile = args[1];
- bool createNodesAsNeeded = true; // parent arg
- bool force = false;
- if ( args.size() == 3 && args[2] == "false") createNodesAsNeeded = false;
- if ( args.size() == 4 && args[3] == "force") force = true;
-
- /// If path to file does not parse, we will throw an exception
- ReplaceNodeCmd* replace_cmd = new ReplaceNodeCmd(pathToNode,createNodesAsNeeded, pathToDefsFile , force);
-
- // For test allow the defs environment to changed, i.e. allow us to inject ECF_CLIENT
- replace_cmd->theDefs()->set_server().add_or_update_user_variables( clientEnv->env() );
-
- cmd = Cmd_ptr( replace_cmd );
-}
-
-std::ostream& operator<<(std::ostream& os, const ReplaceNodeCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/cts/RequeueNodeCmd.cpp b/ecflow_4_0_7/Base/src/cts/RequeueNodeCmd.cpp
deleted file mode 100644
index 4e115e5..0000000
--- a/ecflow_4_0_7/Base/src/cts/RequeueNodeCmd.cpp
+++ /dev/null
@@ -1,219 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #32 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include "ClientToServerCmd.hpp"
-#include "AbstractServer.hpp"
-#include "AbstractClientEnv.hpp"
-#include "CtsApi.hpp"
-#include "Defs.hpp"
-#include "Task.hpp"
-#include "SuiteChanged.hpp"
-#include "Log.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-namespace po = boost::program_options;
-
-
-bool RequeueNodeCmd::equals(ClientToServerCmd* rhs) const
-{
- RequeueNodeCmd* the_rhs = dynamic_cast< RequeueNodeCmd* > ( rhs );
- if ( !the_rhs ) return false;
- if (paths_ != the_rhs->paths()) return false;
- if (option_ != the_rhs->option()) return false;
- return UserCmd::equals(rhs);
-}
-
-static std::string to_string(RequeueNodeCmd::Option option) {
- switch (option) {
- case RequeueNodeCmd::NO_OPTION: return string();
- case RequeueNodeCmd::FORCE: return "force";
- case RequeueNodeCmd::ABORT: return "abort";
- default: assert(false); break;
- }
- return string();
-}
-
-std::ostream& RequeueNodeCmd::print(std::ostream& os) const
-{
- return user_cmd(os,CtsApi::to_string(CtsApi::requeue(paths_,to_string(option_))));
-}
-
-STC_Cmd_ptr RequeueNodeCmd::doHandleRequest(AbstractServer* as) const
-{
- as->update_stats().requeue_node_++;
- assert(isWrite()); // isWrite used in handleRequest() to control check pointing
-
- // This is *only* incremented for child nodes. Hence we only clear suspended for child nodes.
- int clear_suspended_in_child_nodes = 0;
-
- std::stringstream ss;
- size_t vec_size = paths_.size();
- for(size_t i = 0; i < vec_size; i++) {
-
- node_ptr theNodeToRequeue = find_node_for_edit_no_throw(as,paths_[i]);
- if (!theNodeToRequeue.get()) {
- ss << "RequeueNodeCmd: Could not find node at path " << paths_[i] << "\n";
- LOG(Log::ERR,"RequeueNodeCmd: Could not find node at path " << paths_[i]);
- continue;
- }
-
- if (!theNodeToRequeue->suite()->begun()) {
- std::stringstream ss;
- ss << "RequeueNodeCmd::doHandleRequest: For node " << paths_[i] << ". The suite " << theNodeToRequeue->suite()->name() << " must be 'begun' first\n";
- throw std::runtime_error( ss.str() ) ;
- }
-
- SuiteChanged0 changed(theNodeToRequeue);
-
- if (option_ == RequeueNodeCmd::ABORT) {
- // ONLY Re-queue the aborted tasks
- std::vector<Task*> taskVec;
- theNodeToRequeue->getAllTasks(taskVec);
- for(size_t i=0; i < taskVec.size(); i++) {
- if (taskVec[i]->state() == NState::ABORTED) {
- taskVec[i]->requeue( true /* reset repeats */,
- clear_suspended_in_child_nodes,
- true /* reset_next_time_slot */);
- taskVec[i]->set_most_significant_state_up_node_tree(); // can be waste full
- }
- }
- }
- else if ( option_ == RequeueNodeCmd::NO_OPTION) {
- // ONLY Re-queue if there no tasks in submitted or active states
- std::vector<Task*> taskVec;
- theNodeToRequeue->getAllTasks(taskVec);
- for(size_t i=0; i < taskVec.size(); i++) {
- if (taskVec[i]->state() == NState::SUBMITTED || taskVec[i]->state() == NState::ACTIVE) {
- return PreAllocatedReply::ok_cmd();
- }
- }
-
- // The NO_REQUE_IF_SINGLE_TIME_DEP is typically cleared at the *end* requeue, however there are cases
- // where we need to reset it *BEFORE* re-queue. Since it is tied to missing the next time slot
- // i.e take this case:
- // time 10:00 15:00 00:30
- // If we force complete, we set NO_REQUE_IF_SINGLE_TIME_DEP, which is used to advance next valid time slot
- // (i.e no reset), however when we reach the *end* time i.e 15:00
- // calling force complete now leaves node in a complete state and with NO_REQUE_IF_SINGLE_TIME_DEP set.
- // Therefore *any* *MANUAL* re-queue afterward will NOT reset the next valid time slot.
- // To overcome this manual re-queue will always clear NO_REQUE_IF_SINGLE_TIME_DEP and hence reset next valid time slot
- theNodeToRequeue->requeue( true /* reset repeats */,
- clear_suspended_in_child_nodes,
- true /* reset_next_time_slot */ );
- theNodeToRequeue->set_most_significant_state_up_node_tree();
- }
- else if ( option_ == RequeueNodeCmd::FORCE) {
-
- as->zombie_ctrl().add_user_zombies(theNodeToRequeue);
-
- // Please note: that if any tasks under theNodeToRequeue are in
- // active or submitted states, then we will have created zombie jobs
- // The GUI: that calls this command should call a separate request
- // the returns the active/submitted tasks first. This can then be
- // presented to the user, who can elect to kill them if required.
- theNodeToRequeue->requeue( true /* reset repeats */,
- clear_suspended_in_child_nodes,
- true /* reset_next_time_slot */ );
- theNodeToRequeue->set_most_significant_state_up_node_tree();
- }
- }
-
- // Clear up memory allocated to path *ASAP*
- // When dealing with several thousands paths, this makes a *HUGE* difference
- vector<string>().swap(paths_); // clear paths_ and minimise its capacity
-
- std::string error_msg = ss.str();
- if (!error_msg.empty()) {
- throw std::runtime_error( error_msg ) ;
- }
-
- // Do an immediate job submission, so that any re-queued tasks are submitted
- return doJobSubmission(as);
-}
-
-const char* RequeueNodeCmd::arg() { return CtsApi::requeueArg();}
-const char* RequeueNodeCmd::desc() {
- return
- "Re queues the specified node(s)\n"
- " If any child of the specified node(s) is in a suspended state, this state is cleared\n"
- " arg1 = (optional) [ abort | force ]\n"
- " abort = re-queue only aborted tasks below node\n"
- " force = Force the re-queueing even if there are nodes that are active or submitted\n"
- " <null> = Checks if any tasks are in submitted or active states below the node\n"
- " if so does nothing. Otherwise re-queues the node.\n"
- " arg2 = list of node paths. The node paths must begin with a leading '/' character\n\n"
- "Usage:\n"
- " --requeue=abort /suite/f1 # re-queue all aborted children of /suite/f1\n"
- " --requeue=force /suite/f1 # forcibly re-queue /suite/f1 and all its children.May cause zombies.\n"
- " --requeue=/s1/f1/t1 /s1/t2 # Re-queue node '/suite/f1/t1' and '/s1/t2'"
- ;
-}
-
-void RequeueNodeCmd::addOption(boost::program_options::options_description& desc) const{
- desc.add_options()( RequeueNodeCmd::arg(), po::value< vector<string> >()->multitoken(), RequeueNodeCmd::desc() );
-}
-void RequeueNodeCmd::create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* ac) const
-{
- vector<string> args = vm[ RequeueNodeCmd::arg() ].as< vector<string> >();
-
- if (ac->debug()) dumpVecArgs(RequeueNodeCmd::arg(),args);
-
- if (args.size() < 1 ) {
- std::stringstream ss;
- ss << "RequeueNodeCmd: At least 1 argument(path to node) expected. Please specify one of:\n";
- ss << RequeueNodeCmd::arg() << " pathToNode\n";
- ss << RequeueNodeCmd::arg() << " abort pathToNode\n";
- ss << RequeueNodeCmd::arg() << " force pathToNode\n";
- throw std::runtime_error( ss.str() );
- }
-
- std::vector<std::string> options,paths;
- split_args_to_options_and_paths(args,options,paths); // relative order is still preserved
- if (paths.empty()) {
- std::stringstream ss;
- ss << "RequeueNodeCmd: No paths specified. At least one path expected. Paths must begin with a leading '/' character\n" << RequeueNodeCmd::desc() << "\n";
- throw std::runtime_error( ss.str() );
- }
-
- RequeueNodeCmd::Option option = RequeueNodeCmd::NO_OPTION;
- size_t vec_size = options.size();
- for(size_t i = 0; i < vec_size; i++) {
- if (options[i] == "abort") {
- option = RequeueNodeCmd::ABORT;
- if (ac->debug()) cout << "ABORT selected\n";
- }
- else if (options[i] == "force") {
- option = RequeueNodeCmd::FORCE;
- if (ac->debug()) cout << "FORCE selected\n";
- }
- else {
- std::stringstream ss;
- ss << "RequeueNodeCmd: RequeueNodeCmd: Expected : [force | abort ] paths.\n" << RequeueNodeCmd::desc() << "\n";
- throw std::runtime_error( ss.str() );
- }
- }
- if (options.size() > 1) {
- std::stringstream ss;
- ss << "RequeueNodeCmd: Expected only a single option i.e [ force | abort ]\n" << RequeueNodeCmd::desc() << "\n";
- throw std::runtime_error( ss.str() );
- }
-
- cmd = Cmd_ptr(new RequeueNodeCmd(paths,option));
-}
-
-std::ostream& operator<<(std::ostream& os, const RequeueNodeCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/cts/RunNodeCmd.cpp b/ecflow_4_0_7/Base/src/cts/RunNodeCmd.cpp
deleted file mode 100644
index 7d52a2b..0000000
--- a/ecflow_4_0_7/Base/src/cts/RunNodeCmd.cpp
+++ /dev/null
@@ -1,170 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #34 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include "ClientToServerCmd.hpp"
-#include "AbstractServer.hpp"
-#include "AbstractClientEnv.hpp"
-#include "Str.hpp"
-#include "CtsApi.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "JobsParam.hpp"
-#include "SuiteChanged.hpp"
-#include "Log.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-namespace po = boost::program_options;
-
-bool RunNodeCmd::equals(ClientToServerCmd* rhs) const
-{
- RunNodeCmd* the_rhs = dynamic_cast< RunNodeCmd* > ( rhs );
- if ( !the_rhs ) return false;
- if (paths_ != the_rhs->paths()) return false;
- if (force_ != the_rhs->force()) return false;
- return UserCmd::equals(rhs);
-}
-
-std::ostream& RunNodeCmd::print(std::ostream& os) const
-{
- return user_cmd(os,CtsApi::to_string(CtsApi::run(paths_,force_)));
-}
-
-STC_Cmd_ptr RunNodeCmd::doHandleRequest(AbstractServer* as) const
-{
- as->update_stats().run_node_++;
-
- assert(isWrite()); // isWrite used in handleRequest() to control check pointing
-
- std::stringstream ss;
- size_t vec_size = paths_.size();
- for(size_t i = 0; i < vec_size; i++) {
- node_ptr node = find_node_for_edit_no_throw(as,paths_[i]);
- if (!node.get()) {
- ss << "RunNodeCmd: Could not find node at path " << paths_[i] << "\n";
- LOG(Log::ERR,"RunNodeCmd: Could not find node at path " << paths_[i]);
- continue;
- }
-
- if (!node->suite()->begun()) {
- std::stringstream ss;
- ss << "RunNodeCmd failed: For " << paths_[i] << ". The suite " << node->suite()->name() << " must be 'begun' first\n";
- throw std::runtime_error( ss.str() ) ;
- }
-
- SuiteChanged0 changed(node);
-
- // Please note: that if any tasks under theNode are in
- // active or submitted states, then we will have created zombies jobs
- // The GUI: that calls this command should call a separate request
- // the returns the active/submitted tasks first. This can then be
- // presented to the user, who can elect to kill them if required.
- bool createJobs = true;
- if (test_) createJobs = false;
-
- /// This will *NOT* timeout, unlike server Job generation
- JobsParam jobsParam(as->poll_interval(), createJobs ); // default here is to spawn jobs , spawn jobs = true
- // At the task level, if create jobs is false, we will not spawn jobs
-#ifdef DEBUG_JOB_SUBMISSION
- jobsParam.logDebugMessage(" from RunNodeCmd::doHandleRequest");
-#endif
-
- if (force_) as->zombie_ctrl().add_user_zombies(node);
-
- // Avoid re-running the task again on the same time slot
- node->miss_next_time_slot();
-
- if (!node->run(jobsParam, force_)) {
- LOG(Log::ERR,"RunNodeCmd: Failed for " << paths_[i] << " : " << jobsParam.getErrorMsg());
- }
- }
-
- // Clear up memory allocated to path *ASAP*
- // When dealing with several thousands paths, this makes a *HUGE* difference
- vector<string>().swap(paths_); // clear paths_ and minimise its capacity
-
- std::string error_msg = ss.str();
- if (!error_msg.empty()) {
- throw std::runtime_error( error_msg ) ;
- }
-
- return PreAllocatedReply::ok_cmd();
-}
-
-const char* RunNodeCmd::arg() { return CtsApi::runArg();}
-const char* RunNodeCmd::desc() {
- return "Ignore triggers, limits, time or date dependencies, just run the Task.\n"
- "When a job completes, it may be automatically re-queued if it has a cron\n"
- "or multiple time dependencies. If we have multiple time based attributes,\n"
- "then each run, will expire the time.\n"
- "When we run before the time, we want to avoid re-running the task then\n"
- "a flag is set, so that it is not automatically re-queued.\n"
- "A repeat attribute is incremented when all the child nodes are complete\n"
- "in this case the child nodes are automatically re-queued.\n"
- "Hence this command can be aid, in allowing a Repeat attribute to be incremented\n"
- " arg1 = (optional)force\n"
- " Forcibly run, even if there are nodes that are active or submitted\n"
- " This can result in zombie creation\n"
- " arg2 = node path(s). The paths must begin with a leading '/' character.\n"
- " If the path is /suite/family will recursively run all tasks\n"
- " When providing multiple paths avoid running the same task twice\n"
- "Example:\n"
- " --run /suite/t1 # run task t1\n"
- "Effect:\n"
- " task t1; time 12:00 # will complete if run manually\n"
- " task t2; time 10:00 13:00 01:00 # will run 4 times before completing\n"
- " When we have a time range(i.e as shown with task t2), then next time slot\n"
- " is incremented for each run, until it expires, and the task completes.\n"
- " Use the Why command, to show next run time (i.e. next time slot)"
- ;
-}
-
-void RunNodeCmd::addOption(boost::program_options::options_description& desc) const{
- desc.add_options()( RunNodeCmd::arg(), po::value< vector<string> >()->multitoken(), RunNodeCmd::desc() );
-}
-void RunNodeCmd::create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* ace) const
-{
- vector<string> args = vm[ RunNodeCmd::arg() ].as< vector<string> >();
-
- if (ace->debug()) dumpVecArgs(RunNodeCmd::arg(),args);
-
- std::vector<std::string> options,paths;
- split_args_to_options_and_paths(args,options,paths); // relative order is still preserved
- if (paths.empty()) {
- std::stringstream ss;
- ss << "RunNodeCmd: No paths specified. Paths must begin with a leading '/' character\n" << RunNodeCmd::desc() << "\n";
- throw std::runtime_error( ss.str() );
- }
-
- bool force = false;
- if (!options.empty()) {
- if (options.size() != 1) {
- std::stringstream ss;
- ss << "RunNodeCmd: Invalid arguments. Expected a single optional 'force'\n" << RunNodeCmd::desc() << "\n";
- throw std::runtime_error( ss.str() );
- }
- if (options[0].find("force") != std::string::npos) force = true;
- else {
- std::stringstream ss;
- ss << "RunNodeCmd: Expected force <path(s)>\n" << RunNodeCmd::desc() << "\n";
- throw std::runtime_error( ss.str() );
- }
- }
- cmd = Cmd_ptr(new RunNodeCmd(paths,force));
-}
-
-std::ostream& operator<<(std::ostream& os, const RunNodeCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/cts/ServerVersionCmd.cpp b/ecflow_4_0_7/Base/src/cts/ServerVersionCmd.cpp
deleted file mode 100644
index 3cd9c03..0000000
--- a/ecflow_4_0_7/Base/src/cts/ServerVersionCmd.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #8 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : returns the server version.
-// This command should not be changed
-// It will allow new clients to ask OLD server their version numbers
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "ClientToServerCmd.hpp"
-#include "AbstractServer.hpp"
-#include "AbstractClientEnv.hpp"
-#include "CtsApi.hpp"
-#include "Version.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-namespace po = boost::program_options;
-
-std::ostream& ServerVersionCmd::print(std::ostream& os) const
-{
- return user_cmd(os,CtsApi::server_version());
-}
-
-bool ServerVersionCmd::equals(ClientToServerCmd* rhs) const
-{
- ServerVersionCmd* the_rhs = dynamic_cast< ServerVersionCmd* > ( rhs );
- if ( !the_rhs ) return false;
- return UserCmd::equals(rhs);
-}
-
-const char* ServerVersionCmd::theArg() const
-{
- return CtsApi::server_version_arg();
-}
-
-STC_Cmd_ptr ServerVersionCmd::doHandleRequest(AbstractServer* as) const
-{
- as->update_stats().server_version_++;
- return PreAllocatedReply::string_cmd(Version::raw());
-}
-
-static const char* arg_desc()
-{
- /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
- return
- "Returns the version number of the server\n"
- "Usage:\n"
- " --server_version\n"
- " Writes the version to standard output\n"
- ;
-}
-
-void ServerVersionCmd::addOption(boost::program_options::options_description& desc) const
-{
- desc.add_options()(CtsApi::server_version_arg(),arg_desc());
-}
-
-void ServerVersionCmd::create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* ace ) const
-{
- if (ace->debug()) cout << "ServerVersionCmd::create\n";
-
- // testing client interface
- if (ace->under_test()) return;
-
- cmd = Cmd_ptr(new ServerVersionCmd());
-}
-
-std::ostream& operator<<(std::ostream& os, const ServerVersionCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/cts/ShowCmd.cpp b/ecflow_4_0_7/Base/src/cts/ShowCmd.cpp
deleted file mode 100644
index 648087a..0000000
--- a/ecflow_4_0_7/Base/src/cts/ShowCmd.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #20 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <iostream>
-#include "ClientToServerCmd.hpp"
-#include "AbstractServer.hpp"
-#include "Str.hpp"
-#include "CtsApi.hpp"
-#include "AbstractClientEnv.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-namespace po = boost::program_options;
-
-//////////////////////////////////////////////////////////////////////////////////////////////////
-
-bool ShowCmd::equals(ClientToServerCmd* rhs) const
-{
- return (dynamic_cast<ShowCmd*>(rhs)) ? UserCmd::equals(rhs) : false;
-}
-
-std::ostream& ShowCmd::print(std::ostream& os) const
-{
- return user_cmd(os,"show");
-}
-
-STC_Cmd_ptr ShowCmd::doHandleRequest(AbstractServer* as) const
-{
- /// Should never get called since, show command is only called on client side.
- return PreAllocatedReply::ok_cmd();
-}
-
-const char* ShowCmd::arg() { return "show";}
-const char* ShowCmd::desc() {
- return "Used to print state of the definition returned from the server to standard output.\n"
- "This command can *only* be used in a group command, and will only work if it is\n"
- "preceded with a get command. See examples below.\n"
- " arg1 = [ defs | state | migrate ] \n"
- "The output of show has several options: i.e\n"
- " o no arguments: With no arguments, print the definition structure to standard output\n"
- " Extern's are automatically added, allowing the output to be reloaded into the server\n"
- " i.e --group=\"get ; show\"\n"
- " o state:\n"
- " This will output definition structure along with all the state information.\n"
- " This will include the trigger expressions, abstract syntax tree as comments.\n"
- " Excludes the edit history\n"
- " o migrate:\n"
- " This will output definition structure along with all the state information.\n"
- " The node state is shown in the comments.\n"
- " This format allows the definition to be migrated to future version of ecflow.\n"
- " The output includes edit history but excludes externs.\n"
- " When the definition is reloaded *NO* checking is done.\n"
- "\n"
- "The following shows a summary of the features associated with each choice\n"
- " DEFS STATE MIGRATE\n"
- "Auto generate externs Yes Yes No\n"
- "Checking on reload Yes Yes No\n"
- "Edit History No No Yes\n"
- "trigger AST No Yes No\n"
- "\n"
- "Usage:\n"
- " --group=\"get ; show\"\n"
- " --group=\"get ; show defs\" # same as the previous example\n"
- " --group=\"get ; show state\" # Show all state for the node tree\n"
- " --group=\"get ; show migrate\" # Shows state and allows migration\n"
- " --group=\"get /s1; show\" # show state for the node only\n"
- " --group=\"get /s1; show state\""
- ;
-}
-
-void ShowCmd::addOption(boost::program_options::options_description& desc) const {
- desc.add_options()( ShowCmd::arg(), po::value< string >()->implicit_value(string()), ShowCmd::desc() );
-}
-void ShowCmd::create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* ac ) const
-{
- std::string show_state = vm[ ShowCmd::arg() ].as< std::string > ();
-
- if (ac->debug()) cout << "ShowCmd::create api = '" << show_state << "'.\n";
-
- PrintStyle::Type_t style = PrintStyle::DEFS;
- if (!show_state.empty()) {
- if (show_state == "state") style = PrintStyle::STATE;
- else if (show_state == "migrate" ) style = PrintStyle::MIGRATE;
- else if (show_state == "defs" ) style = PrintStyle::DEFS;
- else throw std::runtime_error("ShowCmd::create invalid show option expected one of [ defs | state | migrate ] but found " + show_state);
- }
- cmd = Cmd_ptr( new ShowCmd( style ) );
-}
-
-std::ostream& operator<<(std::ostream& os, const ShowCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/cts/TaskApi.cpp b/ecflow_4_0_7/Base/src/cts/TaskApi.cpp
deleted file mode 100644
index f3c23db..0000000
--- a/ecflow_4_0_7/Base/src/cts/TaskApi.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <boost/algorithm/string/trim.hpp>
-#include "TaskApi.hpp"
-
-std::string TaskApi::init(const std::string& process_id)
-{
- std::string ret = "--init=";
- ret += process_id;
- return ret;
-}
-const char* TaskApi::initArg() { return "init"; }
-
-
-std::string TaskApi::abort(const std::string& reason)
-{
- if (reason.empty()) return "--abort";
- std::string ret = "--abort=";
- ret += reason;
- return ret;
-}
-const char* TaskApi::abortArg() { return "abort"; }
-
-
-std::string TaskApi::event(const std::string& eventName) {
- std::string ret = "--event=";
- ret += eventName;
- return ret;
-}
-const char* TaskApi::eventArg() { return "event"; }
-
-
-std::vector<std::string> TaskApi::meter(const std::string& meterName,const std::string& new_meter_value)
-{
- std::vector<std::string> retVec; retVec.reserve(2);
- std::string ret = "--meter=";ret += meterName;
- retVec.push_back(ret);
- retVec.push_back(new_meter_value);
- return retVec;
-}
-const char* TaskApi::meterArg() { return "meter"; }
-
-
-std::vector<std::string> TaskApi::label(const std::string& label_name, const std::vector<std::string>& labels )
-{
- std::vector<std::string> retVec; retVec.reserve(labels.size() +1);
- std::string ret = "--label=";
- ret += label_name;
- retVec.push_back(ret);
- for(size_t i = 0; i < labels.size(); i++) { retVec.push_back(labels[i]);}
- return retVec;
-}
-const char* TaskApi::labelArg() { return "label"; }
-
-
-std::string TaskApi::complete() { return "--complete"; }
-const char* TaskApi::completeArg() { return "complete"; }
-
-
-std::string TaskApi::wait(const std::string& expression)
-{
- std::string ret = "--wait=";
- ret += expression;
- return ret;
-}
-const char* TaskApi::waitArg() { return "wait"; }
-
-
diff --git a/ecflow_4_0_7/Base/src/cts/TaskApi.hpp b/ecflow_4_0_7/Base/src/cts/TaskApi.hpp
deleted file mode 100644
index 0289e78..0000000
--- a/ecflow_4_0_7/Base/src/cts/TaskApi.hpp
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef TASK_API_HPP_
-#define TASK_API_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Task api. i.e the child commands, typically called from the jobs files
-// The two variant api must correspond i.e '--get' and 'get'
-// since this is used by boost program options
-//============================================================================
-#include <boost/noncopyable.hpp>
-#include <string>
-#include <vector>
-
-class TaskApi : private boost::noncopyable {
-public:
- /// Used to construct arguments, for argc,argv
- static std::string init(const std::string& process_id);
- static std::string abort(const std::string& reason = "");
- static std::string event(const std::string& eventName);
- static std::vector<std::string> meter(const std::string& meterName,const std::string& metervalue);
- static std::vector<std::string> label(const std::string& label_name, const std::vector<std::string>& labels );
- static std::string complete();
- static std::string wait(const std::string& expression);
-
- // Only to be used in Cmd
- static const char* initArg();
- static const char* abortArg();
- static const char* eventArg();
- static const char* meterArg();
- static const char* labelArg();
- static const char* completeArg();
- static const char* waitArg();
-};
-#endif
diff --git a/ecflow_4_0_7/Base/src/cts/TaskCmds.cpp b/ecflow_4_0_7/Base/src/cts/TaskCmds.cpp
deleted file mode 100644
index c3f6a80..0000000
--- a/ecflow_4_0_7/Base/src/cts/TaskCmds.cpp
+++ /dev/null
@@ -1,923 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #91 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include "ClientToServerCmd.hpp"
-#include "AbstractServer.hpp"
-#include "AbstractClientEnv.hpp"
-#include "TaskApi.hpp"
-#include "ExprAst.hpp"
-#include "ExprAstVisitor.hpp"
-
-#include "Defs.hpp"
-#include "Task.hpp"
-#include "SuiteChanged.hpp"
-#include "Log.hpp"
-#include "Str.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-namespace po = boost::program_options;
-
-//#define DEBUG_ZOMBIE 1
-
-////////////////////////////////////////////////////////////////////////////////////////////////
-bool TaskCmd::equals(ClientToServerCmd* rhs) const
-{
- TaskCmd* the_rhs = dynamic_cast<TaskCmd*>(rhs);
- if (!the_rhs) return false;
- if (path_to_submittable_ != the_rhs->path_to_node()) return false;
- if (jobs_password_ != the_rhs->jobs_password()) return false;
- if (process_or_remote_id_ != the_rhs->process_or_remote_id()) return false;
- if (try_no_ != the_rhs->try_no()) return false;
-
- // avoid calling base equals, as task cmd's don't use User(user_) variables.
- return true;
-}
-
-// **********************************************************************************
-// IMPORTANT: In the current SMS/ECF only the init child command, passes the
-// process_or_remote_id_, for *ALL* other child commands this is empty.
-// The Automated tests get round this via setting ECF_RID in the header/tail job includes
-// However since this may not be in .sms/.ecf files, we can not rely on it
-// Hence we need to be able to handle *EMPTY* process_or_remote_id_ for child commands
-// ************************************************************************************
-bool TaskCmd::authenticate(AbstractServer* as, STC_Cmd_ptr& theReply) const
-{
-#ifdef DEBUG_ZOMBIE
- std::cout << " TaskCmd::authenticate " << Child::to_string(child_type());
- std::cout << " " << path_to_submittable_ << " " << process_or_remote_id_ << " " << jobs_password_ << " " << try_no_;
- const Zombie& zombie = as->zombie_ctrl().find(path_to_submittable_,process_or_remote_id_,jobs_password_);
- if (!zombie.empty()) std::cout << " " << zombie;
- else {
- const Zombie& zombie = as->zombie_ctrl().find_by_path_only(path_to_submittable_);
- if (!zombie.empty()) std::cout << " find_by_path_only: " << zombie;
- }
-#endif
- /// ***************************************************************************
- /// Task based cmd have their own authentication mechanism, hence we
- /// Don't need to call the base class authenticate
- /// **************************************************************************
-
- if (!as->allowTaskCommunication()) {
- // This is not an Error, hence we don't throw exception
- theReply = PreAllocatedReply::block_client_server_halted_cmd();
- return false;
- }
-
- submittable_ = get_submittable(as);
- if (!submittable_) {
-#ifdef DEBUG_ZOMBIE
- std::cout << ": PATH Zombie\n";
-#endif
- // Create path zombie, if not already created:
- std::string action_taken;
- (void)as->zombie_ctrl().handle_path_zombie(as,this,action_taken,theReply);
-
- // distinguish output by using *path*
- std::stringstream ss; ss << " zombie(*path*) : " << process_or_remote_id_ << " : " << jobs_password_ << " : action taken(" << action_taken << ")";
- log(Log::ERR,ss.str());
- return false;
- }
-
- // If the CMD *WAS* created with Submittable::DUMMY_JOBS_PASSWORD then we were testing
- // This will be copied from client to server, hence we want to avoid same check in the
- // server. when handleRequest is called()
- // DO NOT place #ifdef DEBUG otherwise test will start failing for the release build
- if ( jobs_password_ == Submittable::DUMMY_JOBS_PASSWORD()) {
- return true;
- }
-
- SuiteChanged1 changed(submittable_->suite());
-
- /// Check if User wants to explicitly bypass password checking
- /// This can be done via AlterCmd by adding a variable on the task, ECF_PASS with value Submittable::FREE_JOBS_PASSWORD
- /// Note: this *does not* look for the variable up the node tree, only on the task.
- std::string ecf_pass_value;
- if (submittable_->findVariableValue(Str::ECF_PASS(), ecf_pass_value)) {
-
- if ( ecf_pass_value == Submittable::FREE_JOBS_PASSWORD()) {
- submittable_->flag().clear(ecf::Flag::ZOMBIE);
- return true;
- }
- }
-
- /// Handle corner case ,where we have two jobs with different process id, but same password
- /// Can happen if jobs is started externally,
- /// or via test(i.e submit 1,submit 2(force)) before job1 active its password is overridden
- bool submittable_allready_aborted = false;
- bool submittable_allready_active = false;
- bool submittable_allready_complete = false;
- bool password_missmatch = false;
- bool pid_missmatch = false;
-
- if ( submittable_->jobsPassword() != jobs_password_) {
-#ifdef DEBUG_ZOMBIE
- std::cout << ": submittable pass(" << submittable_->jobsPassword() << ") != jobs_password_(" << jobs_password_ << ")";
-#endif
- password_missmatch = true;
- }
-
- /// *** See Note above: Not all child commands pass a process_id. ***
- /// *** Hence this test for zombies is ONLY valid if process sets the process_or_remote_id_ ****
- /// *** User should really set ECF_RID in the scripts
- if (!submittable_->process_or_remote_id().empty() && !process_or_remote_id_.empty() && submittable_->process_or_remote_id() != process_or_remote_id_) {
-#ifdef DEBUG_ZOMBIE
- std::cout << ":task pid(" << submittable_->process_or_remote_id() << ") != process pid(" << process_or_remote_id_ << ")";
-#endif
- pid_missmatch = true;
- }
-
- if ((child_type() == Child::INIT) && (submittable_->state() == NState::ACTIVE)) {
-#ifdef DEBUG_ZOMBIE
- std::cout << ":(child_type() == Child::INIT) && submittable_->state() == NState::ACTIVE)";
-#endif
-
- // If ECF_NONSTRICT_ZOMBIES be more forgiving
- if (!password_missmatch && !pid_missmatch ) {
- if (submittable_->user_variable_exists("ECF_NONSTRICT_ZOMBIES")) {
- std::stringstream ss; ss << " zombie(ECF_NONSTRICT_ZOMBIES) : " << path_to_submittable_ << " : already active : action taken( fob )";
- log(Log::WAR, ss.str() );
- theReply = PreAllocatedReply::ok_cmd();
- return false;
- }
- }
-
- submittable_allready_active = true;
- }
-
- if ( submittable_->state() == NState::COMPLETE) {
-#ifdef DEBUG_ZOMBIE
- std::cout << ": submittable_->state() == NState::COMPLETE)";
-#endif
-
- // If ECF_NONSTRICT_ZOMBIES be more forgiving
- if (child_type() == Child::COMPLETE) {
- if (submittable_->user_variable_exists("ECF_NONSTRICT_ZOMBIES")) {
- std::stringstream ss; ss << " zombie(ECF_NONSTRICT_ZOMBIES) : " << path_to_submittable_ ;
- if (password_missmatch) ss << " : password miss-match[ task:"<< submittable_->jobsPassword()<<" child:" << jobs_password_ << " ]";
- if (pid_missmatch) ss << " : pid miss-match[ task:"<< submittable_->process_or_remote_id()<<" child:" << process_or_remote_id_ << " ]";
- ss << " : already complete : action taken( fob )";
- log(Log::WAR, ss.str() );
- theReply = PreAllocatedReply::ok_cmd();
- return false;
- }
- }
-
- // If Task state is complete, and we receive **any** child command then it is a zombie
- submittable_allready_complete = true;
- }
-
- if ( submittable_->state() == NState::ABORTED) {
-#ifdef DEBUG_ZOMBIE
- std::cout << ": submittable_->state() == NState::ABORTED)";
-#endif
-
- // If ECF_NONSTRICT_ZOMBIES be more forgiving
- if (child_type() == Child::ABORT) {
- if (submittable_->user_variable_exists("ECF_NONSTRICT_ZOMBIES")) {
- std::stringstream ss; ss << " zombie(ECF_NONSTRICT_ZOMBIES) : " << path_to_submittable_ ;
- if (password_missmatch) ss << " : password miss-match[ task:"<< submittable_->jobsPassword() << " child:" << jobs_password_ << " ]";
- if (pid_missmatch) ss << " : pid miss-match[ task:"<< submittable_->process_or_remote_id() << " child:" << process_or_remote_id_ << " ]";
- ss << " : already aborted : action taken( fob )";
- log(Log::WAR, ss.str() );
- theReply = PreAllocatedReply::ok_cmd();
- return false;
- }
- }
-
- // If Task state is aborted, and we receive **any** child command then it is a zombie
- submittable_allready_aborted = true;
- }
-
-#ifdef DEBUG_ZOMBIE
- std::cout << "\n";
-#endif
-
- if (password_missmatch || pid_missmatch || submittable_allready_active || submittable_allready_complete || submittable_allready_aborted){
- /// If the task has adopted we return true, and carry on as normal
- std::string action_taken;
- if (!as->zombie_ctrl().handle_zombie(submittable_,this,action_taken,theReply)) {
-
- // LOG failure: Include type of zombie.
- // ** NOTE **: the zombie may have been removed by user actions. i.e if fob and child cmd is abort | complete, etc
- std::stringstream ss; ss << " zombie";
- const Zombie& theZombie = as->zombie_ctrl().find(path_to_submittable_, process_or_remote_id_, jobs_password_ );
- if (!theZombie.empty() ) ss << "(" << theZombie.type_str() << ")";
-
- ss << " : " << path_to_submittable_ << " : " << process_or_remote_id_ << " : " << jobs_password_;
- if (submittable_allready_active) ss << " : already active";
- if (submittable_allready_complete) ss << " : already complete";
- if (submittable_allready_aborted) ss << " : already aborted";
- if (password_missmatch) ss << " : password miss-match[ task:"<< submittable_->jobsPassword()<<" child:" << jobs_password_ << " ]";
- if (pid_missmatch) ss << " : pid miss-match[ task:"<< submittable_->process_or_remote_id()<<" child:" << process_or_remote_id_ << " ]";
- ss << " : action taken(" << action_taken << ")";
- log(Log::ERR,ss.str());
- return false;
- }
- }
- return true;
-}
-
-Submittable* TaskCmd::get_submittable(AbstractServer* as) const
-{
- node_ptr node = as->defs()->findAbsNode(path_to_submittable_);
- if (!node.get()) {
- return NULL;
- }
-
- return node->isSubmittable();
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////////
-
-std::ostream& InitCmd::print(std::ostream& os) const
-{
- return os << Str::CHILD_CMD() << "init " << path_to_node();
-}
-
-bool InitCmd::equals(ClientToServerCmd* rhs) const
-{
- InitCmd* the_rhs = dynamic_cast<InitCmd*>(rhs);
- if (!the_rhs) return false;
- return TaskCmd::equals(rhs);
-}
-
-STC_Cmd_ptr InitCmd::doHandleRequest(AbstractServer* as) const
-{
- as->update_stats().task_init_++;
-
- { // update suite change numbers before job submission. submittable_ setup during authentication
- SuiteChanged1 changed(submittable_->suite());
- submittable_->init(process_or_remote_id()); // will set task->set_state(NState::ACTIVE);
- }
-
- // Do job submission in case any triggers dependent on NState::ACTIVE
- as->increment_job_generation_count();
- return PreAllocatedReply::ok_cmd();
-}
-
-const char* InitCmd::arg() { return TaskApi::initArg();}
-const char* InitCmd::desc() {
- return
- "Mark task as started(active). For use in the '.ecf' script file *only*\n"
- "Hence the context is supplied via environment variables.\n"
- " arg = process_or_remote_id. The process id of the job or remote_id\n"
- " Using remote id allows the jobs to be killed\n\n"
- "If this child command is a zombie, then the default action will be to *block*.\n"
- "The default can be overridden by using zombie attributes.\n"
- "Otherwise the blocking period is defined by ECF_TIMEOUT.\n\n"
- "Usage:\n"
- " ecflow_client --init=$$"
- ;
-}
-
-void InitCmd::addOption(boost::program_options::options_description& desc) const{
- desc.add_options()( InitCmd::arg(), po::value< string >(), InitCmd::desc() );
-}
-
-void InitCmd::create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const
-{
- std::string process_or_remote_id = vm[ arg() ].as< std::string > ();
-
- if (clientEnv->debug())
- cout << "InitCmd::create " << InitCmd::arg()
- << " clientEnv->task_path(" << clientEnv->task_path()
- << ") clientEnv->jobs_password(" << clientEnv->jobs_password()
- << ") clientEnv->process_or_remote_id(" << clientEnv->process_or_remote_id()
- << ") clientEnv->task_try_no(" << clientEnv->task_try_no()
- << ") process_or_remote_id(" << process_or_remote_id
- << ") clientEnv->under_test(" << clientEnv->under_test()
- << ")\n";
-
- std::string errorMsg;
- if ( !clientEnv->checkTaskPathAndPassword(errorMsg) ) {
- throw std::runtime_error( "InitCmd: " + errorMsg );
- }
-
- /// if ECF_RID is specified then it *MUST* be the same as input argument
- /// On cca we ECF_RID can be specified under test, and therefore fail this check, hence we use clientEnv->under_test()
- if (!clientEnv->under_test() && !clientEnv->process_or_remote_id().empty() && clientEnv->process_or_remote_id() != process_or_remote_id) {
- std::stringstream ss;
- ss << "remote id(" << process_or_remote_id << ") passed as an argument, not the same the client environment ECF_RID(" << clientEnv->process_or_remote_id() << ")";
- throw std::runtime_error(ss.str());
- }
-
- cmd = Cmd_ptr( new InitCmd( clientEnv->task_path(),
- clientEnv->jobs_password(),
- process_or_remote_id,
- clientEnv->task_try_no()
- )
- );
-}
-//////////////////////////////////////////////////////////////////////////////////////////////////
-
-std::ostream& CompleteCmd::print(std::ostream& os) const
-{
- return os << Str::CHILD_CMD() << "complete " << path_to_node();
-}
-
-bool CompleteCmd::equals(ClientToServerCmd* rhs) const
-{
- CompleteCmd* the_rhs = dynamic_cast<CompleteCmd*>(rhs);
- if (!the_rhs) return false;
- return TaskCmd::equals(rhs);
-}
-
-STC_Cmd_ptr CompleteCmd::doHandleRequest(AbstractServer* as) const
-{
- as->update_stats().task_complete_++;
-
- {
- /// If there is an associated zombie, remove from the list. Must match,
- /// Do this before task->complete(), since that clears password & process id
- /// remove(..) uses password/ process id to match the right zombie
- as->zombie_ctrl().remove( submittable_ );
-
- // update suite change numbers before job submission, submittable_ setup during authentication
- SuiteChanged1 changed(submittable_->suite());
- submittable_->complete(); // will set task->set_state(NState::COMPLETE);
- }
-
- // Do job submission in case any triggers dependent on NState::COMPLETE
- as->increment_job_generation_count();
- return PreAllocatedReply::ok_cmd();
-}
-
-const char* CompleteCmd::arg() { return TaskApi::completeArg();}
-const char* CompleteCmd::desc()
-{
- return
- "Mark task as complete. For use in the '.ecf' script file *only*\n"
- "Hence the context is supplied via environment variables\n\n"
- "If this child command is a zombie, then the default action will be to *block*.\n"
- "The default can be overridden by using zombie attributes.\n"
- "Otherwise the blocking period is defined by ECF_TIMEOUT.\n\n"
- "Usage:\n"
- " ecflow_client --complete"
- ;
-}
-
-void CompleteCmd::addOption(boost::program_options::options_description& desc) const {
- desc.add_options()( CompleteCmd::arg(), CompleteCmd::desc() );
-}
-void CompleteCmd::create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const
-{
- if (clientEnv->debug())
- cout << "CompleteCmd::create " << CompleteCmd::arg()
- << " task_path(" << clientEnv->task_path()
- << ") password(" << clientEnv->jobs_password()
- << ") remote_id(" << clientEnv->process_or_remote_id()
- << ") try_no(" << clientEnv->task_try_no()
- << ")\n";
-
-
- std::string errorMsg;
- if ( !clientEnv->checkTaskPathAndPassword(errorMsg) ) {
- throw std::runtime_error( "CompleteCmd: " + errorMsg );
- }
-
- cmd = Cmd_ptr( new CompleteCmd( clientEnv->task_path(),
- clientEnv->jobs_password(),
- clientEnv->process_or_remote_id(),
- clientEnv->task_try_no()) );
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////////
-
-CtsWaitCmd::CtsWaitCmd(const std::string& pathToTask,
- const std::string& jobsPassword,
- const std::string& process_or_remote_id,
- int try_no,
- const std::string& expression)
- : TaskCmd(pathToTask,jobsPassword,process_or_remote_id,try_no), expression_(expression)
-{
- // Parse expression to make sure its valid
- PartExpression exp(expression);
- string parseErrorMsg;
- std::auto_ptr<AstTop> ast = exp.parseExpressions( parseErrorMsg );
- if (!ast.get()) {
-
- assert( !parseErrorMsg.empty() );
- std::stringstream ss; ss << "CtsWaitCmd: Failed to parse expression '" << expression << "'. " << parseErrorMsg;
- throw std::runtime_error( ss.str() );
- }
-}
-
-std::ostream& CtsWaitCmd::print(std::ostream& os) const
-{
- return os << Str::CHILD_CMD() << "wait " << expression_ << " " << path_to_node();
-}
-
-bool CtsWaitCmd::equals(ClientToServerCmd* rhs) const
-{
- CtsWaitCmd* the_rhs = dynamic_cast< CtsWaitCmd* > ( rhs );
- if ( !the_rhs ) return false;
- if (expression_ != the_rhs->expression()) return false;
- return TaskCmd::equals(rhs);
-}
-
-STC_Cmd_ptr CtsWaitCmd::doHandleRequest(AbstractServer* as) const
-{
- as->update_stats().task_wait_++;
-
- SuiteChanged1 changed(submittable_->suite());
-
- // Parse the expression
- PartExpression exp(expression_);
- string parseErrorMsg;
- std::auto_ptr<AstTop> ast = exp.parseExpressions( parseErrorMsg );
- if (!ast.get()) {
- // should NOT really, since client did check
- std::stringstream ss; ss << "CtsWaitCmd: Failed to parse expression '" << expression_ << "'. " << parseErrorMsg;
- throw std::runtime_error( ss.str() ) ;
- }
-
- // The complete expression have been parsed and we have created the abstract syntax tree
- // We now need CHECK the AST for path nodes, event and meter. repeats,etc.
- // *** This will also set the Node pointers ***
- AstResolveVisitor astVisitor(submittable_);
- ast->accept(astVisitor);
-
- // If the expression references paths that don't exist throw an error
- // This be captured in the ecf script, which should then abort the task
- // Otherwise we will end up blocking indefinitely
- if ( !astVisitor.errorMsg().empty() ) {
- std::stringstream ss;
- ss << "CtsWaitCmd: AST node tree references failed for " << expression_;
- ss << " at " << submittable_->debugNodePath() << " : " << astVisitor.errorMsg();
- throw std::runtime_error( ss.str() ) ;
- }
-
- // Evaluate the expression
- if ( ast->evaluate() ) {
-
- submittable_->flag().clear(ecf::Flag::WAIT);
-
- // expression evaluates, return OK
- return PreAllocatedReply::ok_cmd();
- }
-
- submittable_->flag().set(ecf::Flag::WAIT);
-
- // Block/wait while expression is false
- return PreAllocatedReply::block_client_on_home_server_cmd();
-}
-
-const char* CtsWaitCmd::arg() { return TaskApi::waitArg();}
-const char* CtsWaitCmd::desc() {
- return
- "Evaluates an expression, and block while the expression is false.\n"
- "For use in the '.ecf' file *only*, hence the context is supplied via environment variables\n"
- " arg1 = string(expression)\n"
- "Usage:\n"
- " ecflow_client --wait=\"/suite/taskx == complete\""
- ;
-}
-
-void CtsWaitCmd::addOption(boost::program_options::options_description& desc) const {
- desc.add_options()( CtsWaitCmd::arg(), po::value< string >(), CtsWaitCmd::desc() );
-}
-void CtsWaitCmd::create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const
-{
- std::string expression = vm[ arg() ].as< std::string > ();
-
- if (clientEnv->debug())
- cout << "CtsWaitCmd::create " << CtsWaitCmd::arg()
- << " task_path(" << clientEnv->task_path()
- << ") password(" << clientEnv->jobs_password()
- << ") remote_id(" << clientEnv->process_or_remote_id()
- << ") try_no(" << clientEnv->task_try_no()
- << ") expression(" << expression << ")\n";
-
- std::string errorMsg;
- if ( !clientEnv->checkTaskPathAndPassword(errorMsg) ) {
- throw std::runtime_error( "CtsWaitCmd: " + errorMsg );
- }
-
- cmd = Cmd_ptr( new CtsWaitCmd( clientEnv->task_path(),
- clientEnv->jobs_password(),
- clientEnv->process_or_remote_id(),
- clientEnv->task_try_no(),
- expression) );
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////////
-
-AbortCmd::AbortCmd(const std::string& pathToTask,
- const std::string& jobsPassword,
- const std::string& process_or_remote_id,
- int try_no,
- const std::string& reason)
-:TaskCmd(pathToTask,jobsPassword,process_or_remote_id,try_no), reason_(reason)
-{
- if (!reason_.empty()) {
- // Do not use "\n" | ';' in abortedReason_, as this can mess up, --migrate output
- // Which would then affect --load.
- Str::replace(reason_,"\n","");
- Str::replace(reason_,";"," ");
- }
-}
-
-std::ostream& AbortCmd::print(std::ostream& os) const
-{
- return os << Str::CHILD_CMD() << "abort " << path_to_node() << " " << reason_;
-}
-
-bool AbortCmd::equals(ClientToServerCmd* rhs) const
-{
- AbortCmd* the_rhs = dynamic_cast<AbortCmd*>(rhs);
- if (!the_rhs) return false;
- if (reason_ != the_rhs->reason()) return false;
- return TaskCmd::equals(rhs);
-}
-
-STC_Cmd_ptr AbortCmd::doHandleRequest(AbstractServer* as) const
-{
- as->update_stats().task_abort_++;
-
- assert(isWrite()); // isWrite used in handleRequest() to control check pointing
-
- {
- /// If there is an associated zombie, remove from the list
- as->zombie_ctrl().remove( submittable_ );
-
- // update suite change numbers before job submission, submittable_ setup during authentication
- SuiteChanged1 changed(submittable_->suite());
-
- string theReason = reason_;
- if ( theReason.empty() ) theReason = "Trap raised in job file";
-
- submittable_->aborted(theReason); // will set task->set_state(NState::ABORTED);
- }
-
- // Do job submission in case any triggers dependent on NState::ABORTED
- // If task try number is less than ECF_TRIES we attempt to re-submit the job.(ie if still in limit)
- as->increment_job_generation_count();
- return PreAllocatedReply::ok_cmd();
-}
-
-const char* AbortCmd::arg() { return TaskApi::abortArg();}
-const char* AbortCmd::desc() {
- return
- "Mark task as aborted. For use in the '.ecf' script file *only*\n"
- "Hence the context is supplied via environment variables\n"
- " arg1 = (optional) string(reason)\n"
- " Optionally provide a reason why the abort was raised\n\n"
- "If this child command is a zombie, then the default action will be to *block*.\n"
- "The default can be overridden by using zombie attributes.\n"
- "Otherwise the blocking period is defined by ECF_TIMEOUT.\n\n"
- "Usage:\n"
- " ecflow_client --abort=reasonX"
- ;
-}
-
-void AbortCmd::addOption(boost::program_options::options_description& desc) const{
- desc.add_options()( AbortCmd::arg(), po::value< string >()->implicit_value(string()), AbortCmd::desc() );
-}
-void AbortCmd::create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const
-{
- std::string reason = vm[ arg() ].as< std::string > ();
-
- if (clientEnv->debug())
- cout << "AbortCmd::create " << AbortCmd::arg()
- << " task_path(" << clientEnv->task_path()
- << ") password(" << clientEnv->jobs_password()
- << ") remote_id(" << clientEnv->process_or_remote_id()
- << ") try_no(" << clientEnv->task_try_no()
- << ") reason(" << reason << ")\n";
-
-
- std::string errorMsg;
- if ( !clientEnv->checkTaskPathAndPassword(errorMsg) ) {
- throw std::runtime_error( "AbortCmd: " + errorMsg );
- }
-
- cmd = Cmd_ptr(new AbortCmd( clientEnv->task_path(),
- clientEnv->jobs_password(),
- clientEnv->process_or_remote_id(),
- clientEnv->task_try_no(),
- reason));
-}
-//////////////////////////////////////////////////////////////////////////////////////////////////
-
-bool EventCmd::equals(ClientToServerCmd* rhs) const
-{
- EventCmd* the_rhs = dynamic_cast<EventCmd*>(rhs);
- if (!the_rhs) return false;
- if (name_ != the_rhs->name()) return false;
- return TaskCmd::equals(rhs);
-}
-
-std::ostream& EventCmd::print(std::ostream& os) const
-{
- return os << Str::CHILD_CMD() << "event " << name_ << " " << path_to_node();
-}
-
-STC_Cmd_ptr EventCmd::doHandleRequest(AbstractServer* as) const
-{
- as->update_stats().task_event_++;
-
- { // update suite change numbers before job submission, task_ setup during authentication
- SuiteChanged1 changed(submittable_->suite());
-
- // The name could either be "string" or an integer either way it should be unique
- if (!submittable_->set_event(name_,true)) {
- std::string ss; ss = "Event request failed as event '"; ss += name_; ss += "' does not exist on task "; ss += path_to_node();
- ecf::log(Log::ERR,ss);
- return PreAllocatedReply::ok_cmd();
- }
- }
-
- // Do job submission in case any triggers dependent on events
- as->increment_job_generation_count();
- return PreAllocatedReply::ok_cmd();
-}
-
-const char* EventCmd::arg() { return TaskApi::eventArg();}
-const char* EventCmd::desc() {
- return
- "Change event. For use in the '.ecf' script file *only*\n"
- "Hence the context is supplied via environment variables\n"
- " arg1(string | int) = event-name\n\n"
- "If this child command is a zombie, then the default action will be to *fob*,\n"
- "i.e allow the ecflow client command to complete without an error\n"
- "The default can be overridden by using zombie attributes.\n\n"
- "Usage:\n"
- " ecflow_client --event=ev"
- ;
-}
-
-void EventCmd::addOption(boost::program_options::options_description& desc) const {
- desc.add_options()( EventCmd::arg(), po::value< string >(), EventCmd::desc() );
-}
-void EventCmd::create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const
-{
- std::string event = vm[ arg() ].as< std::string > ();
-
- if (clientEnv->debug())
- cout << "EventCmd::create " << EventCmd::arg()
- << " task_path(" << clientEnv->task_path()
- << ") password(" << clientEnv->jobs_password()
- << ") remote_id(" << clientEnv->process_or_remote_id()
- << ") try_no(" << clientEnv->task_try_no()
- << ") event(" << event << ")\n";
-
-
- std::string errorMsg;
- if ( !clientEnv->checkTaskPathAndPassword(errorMsg) ) {
- throw std::runtime_error( "EventCmd: " + errorMsg );
- }
-
- cmd = Cmd_ptr(new EventCmd( clientEnv->task_path(),
- clientEnv->jobs_password(),
- clientEnv->process_or_remote_id(),
- clientEnv->task_try_no(),
- event ));
-}
-//////////////////////////////////////////////////////////////////////////////////////////////////
-
-bool MeterCmd::equals(ClientToServerCmd* rhs) const
-{
- MeterCmd* the_rhs = dynamic_cast<MeterCmd*>(rhs);
- if (!the_rhs) return false;
- if (name_ != the_rhs->name()) return false;
- if (value_ != the_rhs->value()) return false;
- return TaskCmd::equals(rhs);
-}
-
-std::ostream& MeterCmd::print(std::ostream& os) const
-{
- return os << Str::CHILD_CMD() << "meter " << name_ << " " << value_ << " " << path_to_node();
-}
-
-STC_Cmd_ptr MeterCmd::doHandleRequest(AbstractServer* as) const
-{
- as->update_stats().task_meter_++;
-
- { // Added scope for SuiteChanged1 changed: i.e update suite change numbers before job submission
- // submittable_ setup during authentication
- SuiteChanged1 changed(submittable_->suite());
-
- /// Allow meter to set any valid value that is in range because:
- /// - When we have a network failure, and restoration. The meter tasks, will come in random, order.
- /// - When task is executed without a requee the meter value will less than maximum
- ///
- /// This has *IMPLICATION*, if the meter is used in a trigger, using a equality
- /// operator, then the trigger will always hold. hence suite designers need to
- /// aware of this.
- try {
-
- Meter& the_meter = submittable_->find_meter(name_);
- if (the_meter.empty()) {
- LOG(Log::ERR,"MeterCmd::doHandleRequest: failed as meter '" << name_ << "' does not exist on task " << path_to_node());
- return PreAllocatedReply::ok_cmd();
- }
-
- /// Invalid meter values(out or range) will raise exceptions.
- /// Just ignore the request rather than failing client cmd
- the_meter.set_value(value_);
- }
- catch (std::exception& e) {
- LOG(Log::ERR,"MeterCmd::doHandleRequest: failed for task " << path_to_node() << ". " << e.what());
- return PreAllocatedReply::ok_cmd();
- }
- }
-
- // Do job submission in case any triggers dependent on meters
- as->increment_job_generation_count();
- return PreAllocatedReply::ok_cmd();
-}
-
-const char* MeterCmd::arg() { return TaskApi::meterArg();}
-const char* MeterCmd::desc() {
- return
- "Change meter. For use in the '.ecf' script file *only*\n"
- "Hence the context is supplied via environment variables\n"
- " arg1(string) = meter-name\n"
- " arg2(int) = the new meter value\n\n"
- "If this child command is a zombie, then the default action will be to *fob*,\n"
- "i.e allow the ecflow client command to complete without an error\n"
- "The default can be overridden by using zombie attributes.\n\n"
- "Usage:\n"
- " ecflow_client --meter=my_meter 20"
- ;
-}
-
-void MeterCmd::addOption(boost::program_options::options_description& desc) const {
- desc.add_options()( MeterCmd::arg(), po::value< vector<string> >()->multitoken(), MeterCmd::desc() );
-}
-void MeterCmd::create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const
-{
- vector<string> args = vm[ arg() ].as< vector<string> >();
-
- if (clientEnv->debug()) {
- dumpVecArgs(MeterCmd::arg(),args);
- cout << "MeterCmd::create " << MeterCmd::arg()
- << " task_path(" << clientEnv->task_path()
- << ") password(" << clientEnv->jobs_password()
- << ") remote_id(" << clientEnv->process_or_remote_id()
- << ") try_no(" << clientEnv->task_try_no()
- << ")\n";
- }
-
- if (args.size() != 2 ) {
- std::stringstream ss;
- ss << "MeterCmd: Two arguments expected, found " << args.size()
- << " Please specify <meter-name> <meter-value>, ie --meter=name 100\n";
- throw std::runtime_error( ss.str() );
- }
-
- int value = 0;
- try {
- std::string strVal = args[1];
- value = boost::lexical_cast<int>(strVal);
- }
- catch (boost::bad_lexical_cast& e) {
- throw std::runtime_error( "MeterCmd: Second argument must be a integer, i.e. --meter name 100\n" );
- }
-
- std::string errorMsg;
- if ( !clientEnv->checkTaskPathAndPassword(errorMsg) ) {
- throw std::runtime_error( "MeterCmd: " + errorMsg );
- }
-
- cmd = Cmd_ptr(new MeterCmd( clientEnv->task_path(),
- clientEnv->jobs_password(),
- clientEnv->process_or_remote_id(),
- clientEnv->task_try_no(),
- args[0],
- value ));
-}
-//////////////////////////////////////////////////////////////////////////////////////////////////
-
-bool LabelCmd::equals(ClientToServerCmd* rhs) const
-{
- LabelCmd* the_rhs = dynamic_cast<LabelCmd*>(rhs);
- if (!the_rhs) return false;
- if (name_ != the_rhs->name()) return false;
- if (label_ != the_rhs->label()) return false;
- return TaskCmd::equals(rhs);
-}
-
-std::ostream& LabelCmd::print(std::ostream& os) const
-{
- return os << Str::CHILD_CMD() << "label " << name_ << " '" << label_ << "' " << path_to_node();
-}
-
-STC_Cmd_ptr LabelCmd::doHandleRequest(AbstractServer* as) const
-{
- as->update_stats().task_label_++;
-
- assert(isWrite()); // isWrite used in handleRequest() to control check pointing
-
- // submittable_ setup during authentication
- if (submittable_->findLabel(name_)) {
-
- SuiteChanged1 changed(submittable_->suite());
- submittable_->changeLabel(name_,label_);
- }
- // else {
- // // ECFLOW-175, avoid filling up log file. Can get thousands of these messages, especially form MARS
- // std::string ss;
- // ss = "Label request failed as label '"; ss += name_; ss += "' does not exist on task "; ss += path_to_node();
- // ecf::log(Log::ERR,ss);
- //}
-
- // Note: reclaiming memory for label_ earlier make *no* difference to performance of server
-
- return PreAllocatedReply::ok_cmd();
-}
-
-const char* LabelCmd::arg() { return TaskApi::labelArg();}
-const char* LabelCmd::desc() {
- return
- "Change Label. For use in the '.ecf' script file *only*\n"
- "Hence the context is supplied via environment variables\n"
- " arg1 = label-name\n"
- " arg2 = The new label value\n"
- " The labels values can be single or multi-line(space separated quoted strings)\n\n"
- "If this child command is a zombie, then the default action will be to *fob*,\n"
- "i.e allow the ecflow client command to complete without an error\n"
- "The default can be overridden by using zombie attributes.\n\n"
- "Usage:\n"
- " ecflow_client --label=progressed merlin"
- ;
-}
-
-void LabelCmd::addOption(boost::program_options::options_description& desc) const {
- desc.add_options()( LabelCmd::arg(), po::value< vector<string> >()->multitoken(), LabelCmd::desc() );
-}
-void LabelCmd::create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* clientEnv ) const
-{
- vector<string> args = vm[ arg() ].as< vector<string> >();
-
- if (clientEnv->debug()) {
- dumpVecArgs(LabelCmd::arg(),args);
- cout << "LabelCmd::create " << LabelCmd::arg()
- << " task_path(" << clientEnv->task_path()
- << ") password(" << clientEnv->jobs_password()
- << ") remote_id(" << clientEnv->process_or_remote_id()
- << ") try_no(" << clientEnv->task_try_no()
- << ")\n";
- }
-
- if (args.size() < 2 ) {
- std::stringstream ss;
- ss << "LabelCmd: At least 2 arguments expected. Please specify <label-name> <string1> <string2>\n";
- throw std::runtime_error( ss.str() );
- }
-
- std::string labelName = args[0];
- args.erase(args.begin()); // remove name from vector of strings
- std::string labelValue;
- for(size_t i =0; i < args.size(); i++) {
- if (i != 0) labelValue += " ";
- labelValue += args[i];
- }
-
- std::string errorMsg;
- if ( !clientEnv->checkTaskPathAndPassword(errorMsg) ) {
- throw std::runtime_error( "LabelCmd: " + errorMsg );
- }
-
- cmd = Cmd_ptr(new LabelCmd( clientEnv->task_path(),
- clientEnv->jobs_password(),
- clientEnv->process_or_remote_id(),
- clientEnv->task_try_no(),
- labelName,
- labelValue));
-}
-
-std::ostream& operator<<(std::ostream& os, const InitCmd& c) { return c.print(os); }
-std::ostream& operator<<(std::ostream& os, const EventCmd& c) { return c.print(os); }
-std::ostream& operator<<(std::ostream& os, const MeterCmd& c) { return c.print(os); }
-std::ostream& operator<<(std::ostream& os, const LabelCmd& c) { return c.print(os); }
-std::ostream& operator<<(std::ostream& os, const AbortCmd& c) { return c.print(os); }
-std::ostream& operator<<(std::ostream& os, const CompleteCmd& c) { return c.print(os); }
-std::ostream& operator<<(std::ostream& os, const CtsWaitCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/cts/UserCmd.cpp b/ecflow_4_0_7/Base/src/cts/UserCmd.cpp
deleted file mode 100644
index 4014788..0000000
--- a/ecflow_4_0_7/Base/src/cts/UserCmd.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #65 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <iostream>
-#include <sstream>
-#include <fstream>
-
-#include <pwd.h> /* getpwuid */
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdio.h> /* tolower */
-
-#include "ClientToServerCmd.hpp"
-
-#include "AbstractServer.hpp"
-#include "Log.hpp"
-#include "Str.hpp"
-
-using namespace std;
-using namespace boost;
-using namespace ecf;
-
-bool UserCmd::equals(ClientToServerCmd* rhs) const
-{
- UserCmd* the_rhs = dynamic_cast< UserCmd* > ( rhs );
- if ( !the_rhs ) return false;
- return user_ == the_rhs->user();
-}
-
-bool UserCmd::authenticate(AbstractServer* as, STC_Cmd_ptr& ) const
-{
- LOG_ASSERT(!user().empty(),"");
-
- // get the current user. This should have been set by the client
- if (as->authenticateUser(user())) {
- if (as->authenticateWriteAccess(user(),isWrite())) {
- return true;
- }
-
- std::string msg = "[ authentication failed ] User ";
- msg += user();
- msg += " has no write access. Please see your administrator.";
- throw std::runtime_error( msg );
- }
-
- std::string msg = "[ authentication failed ] User ";
- msg += user();
- msg += " is not allowed any access.";
- throw std::runtime_error( msg );
-
- return false;
-}
-
-void UserCmd::setup_user_authentification()
-{
- // Minimise system calls by using static.
- static std::string the_user_name;
- if (the_user_name.empty()) {
- // Get the uid of the running process and use it to get a record from /etc/passwd */
- struct passwd * thePassWord = getpwuid ( getuid() );
- the_user_name = thePassWord->pw_name; // equivalent to the login name
- }
-
- user_ = the_user_name;
-}
-
-void UserCmd::prompt_for_confirmation(const std::string& prompt)
-{
- cout << prompt;
- char reply[256];
- cin.getline (reply,256);
- if (reply[0] != 'y' && reply[0] != 'Y') {
- exit(1);
- }
-}
-
-std::ostream& UserCmd::user_cmd(std::ostream& os, const std::string& the_cmd) const
-{
- return os << the_cmd << " :" << user();
-}
-
-//#define DEBUG_ME 1
-
-void UserCmd::split_args_to_options_and_paths(
- const std::vector<std::string>& args,
- std::vector<std::string>& options,
- std::vector<std::string>& paths)
-{
- // ** ECFLOW-137 **, if the trigger expression have a leading '/' then it gets parsed into the paths
- // vector and not options
- // This is because boost program options does *NOT* seem to preserve the leading quotes around the
- // trigger/complete expression, i.e "/suite/t2 == complete" is read as /suite/t2 == complete
- // However in paths we do expect to see any spaces
-
- size_t vec_size = args.size();
- for(size_t i = 0; i < vec_size; i++) {
- if (args[i].empty()) continue;
- if (args[i][0] == '/' && args[i].find(" ") == std::string::npos) {
- paths.push_back(args[i]);
- }
- else {
- options.push_back(args[i]);
- }
- }
-
-#ifdef DEBUG_ME
- std::cout << "split_args_to_options_and_paths\n";
- for(size_t i = 0; i < args.size(); ++i) { std::cout << "args[" << i << "]=" <<args[i] << "\n"; }
- for(size_t i = 0; i < options.size(); ++i) { std::cout << "options[" << i << "]=" << options[i] << "\n"; }
- for(size_t i = 0; i < paths.size(); ++i) { std::cout << "paths[" << i << "]=" << paths[i] << "\n"; }
-#endif
-}
-
-int UserCmd::time_out_for_load_sync_and_get() { return 600; }
-
diff --git a/ecflow_4_0_7/Base/src/cts/ZombieCmd.cpp b/ecflow_4_0_7/Base/src/cts/ZombieCmd.cpp
deleted file mode 100644
index 7f7b167..0000000
--- a/ecflow_4_0_7/Base/src/cts/ZombieCmd.cpp
+++ /dev/null
@@ -1,226 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #24 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include "ClientToServerCmd.hpp"
-#include "AbstractServer.hpp"
-#include "CtsApi.hpp"
-#include "AbstractClientEnv.hpp"
-#include "Defs.hpp"
-#include "Task.hpp"
-#include "Str.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-namespace po = boost::program_options;
-
-std::ostream& ZombieCmd::print(std::ostream& os) const
-{
- switch (user_action_) {
- case User::FOB: return user_cmd(os,CtsApi::to_string(CtsApi::zombieFob(path_,process_id_,password_))); break;
- case User::FAIL: return user_cmd(os,CtsApi::to_string(CtsApi::zombieFail(path_,process_id_,password_))); break;
- case User::ADOPT: return user_cmd(os,CtsApi::to_string(CtsApi::zombieAdopt(path_,process_id_,password_))); break;
- case User::REMOVE: return user_cmd(os,CtsApi::to_string(CtsApi::zombieRemove(path_,process_id_,password_))); break;
- case User::BLOCK: return user_cmd(os,CtsApi::to_string(CtsApi::zombieBlock(path_,process_id_,password_))); break;
- case User::KILL: return user_cmd(os,CtsApi::to_string(CtsApi::zombieKill(path_,process_id_,password_))); break;
- default: break;
- }
- return os;
-}
-
-bool ZombieCmd::equals(ClientToServerCmd* rhs) const
-{
- ZombieCmd* the_rhs = dynamic_cast< ZombieCmd* > ( rhs );
- if ( !the_rhs ) return false;
- if (path_ != the_rhs->path_to_task()) return false;
- if (process_id_ != the_rhs->process_or_remote_id()) return false;
- if (password_ != the_rhs->password()) return false;
- return UserCmd::equals(rhs);
-}
-
-STC_Cmd_ptr ZombieCmd::doHandleRequest(AbstractServer* as) const
-{
- // To uniquely identify a zombie we need path to task and remote_id, This information
- // is available from the zombie class via get command. However we do not want to
- // expose the password.
- // Hence the Command level interface will make do with just the path to the task.
- // The first zombie whose corresponding task where password does *NOT* match is acted upon
- Task* task = NULL;
- if ( process_id_.empty() && password_.empty()) {
- node_ptr node = as->defs()->findAbsNode(path_);
- if (node.get()) task = node->isTask();
- }
-
- switch (user_action_) {
-
- case User::FOB: {
- as->update_stats().zombie_fob_++;
- if ( process_id_.empty() && password_.empty()) as->zombie_ctrl().fobCli(path_,task);
- else as->zombie_ctrl().fob(path_,process_id_,password_);
- break;
- }
-
- case User::FAIL: {
- as->update_stats().zombie_fail_++;
- if ( process_id_.empty() && password_.empty()) as->zombie_ctrl().failCli(path_,task);
- else as->zombie_ctrl().fail(path_,process_id_,password_);
- break;
- }
-
- case User::ADOPT: {
- as->update_stats().zombie_adopt_++;
- if ( process_id_.empty() && password_.empty()) as->zombie_ctrl().adoptCli(path_,task);
- else as->zombie_ctrl().adopt(path_,process_id_,password_);
- break;
- }
-
- case User::REMOVE: {
- as->update_stats().zombie_remove_++;
- if ( process_id_.empty() && password_.empty()) as->zombie_ctrl().removeCli(path_,task);
- else as->zombie_ctrl().remove(path_,process_id_,password_);
- break;
- }
-
- case User::BLOCK: {
- as->update_stats().zombie_block_++;
- if ( process_id_.empty() && password_.empty()) as->zombie_ctrl().blockCli(path_,task);
- else as->zombie_ctrl().block(path_,process_id_,password_);
- break;
- }
-
- case User::KILL: {
- as->update_stats().zombie_kill_++;
- if ( process_id_.empty() && password_.empty()) as->zombie_ctrl().killCli(path_,task);
- else as->zombie_ctrl().kill(path_,process_id_,password_);
- break;
- }
- }
-
- return PreAllocatedReply::ok_cmd();
-}
-
-const char* ZombieCmd::theArg() const {
-
- switch (user_action_) {
- case User::FOB: return CtsApi::zombieFobArg(); break;
- case User::FAIL: return CtsApi::zombieFailArg(); break;
- case User::ADOPT: return CtsApi::zombieAdoptArg(); break;
- case User::REMOVE: return CtsApi::zombieRemoveArg(); break;
- case User::BLOCK: return CtsApi::zombieBlockArg(); break;
- case User::KILL: return CtsApi::zombieKillArg(); break;
- default: break;
- }
- assert(false);
- return NULL;
-}
-
-void ZombieCmd::addOption(boost::program_options::options_description& desc) const
-{
- switch (user_action_) {
-
- case User::FOB: {
- desc.add_options()( CtsApi::zombieFobArg(), po::value< vector<string> >()->multitoken(),
- "Locates the task in the zombie list, and sets to fob.\n"
- "Next time the child commands (init,event,meter,label,abort,complete) communicate\n"
- "with the server, they will complete successfully (but without updating the node tree)\n"
- "allowing the job to finish.\n"
- "The server zombie is automatically deleted after 1 hour\n"
- " arg = path to task"
- );
- break;
- }
- case User::FAIL: {
- desc.add_options()( CtsApi::zombieFailArg(), po::value< vector<string> >()->multitoken(),
- "Locates the task in the zombie list, and sets to fail.\n"
- "Next time the child commands (init,event,meter,label,abort,complete) communicate\n"
- "with the server, they will be set to fail. Depending on the job setup this may\n"
- "force a abort, the abort will also fail.\n"
- "Hence job structure should use 'set -e' in the error trapping functions to prevent\n"
- "infinite recursion. The server zombie is automatically deleted after 1 hour\n"
- " arg = path to task"
- );
- break;
- }
- case User::ADOPT: {
- desc.add_options()( CtsApi::zombieAdoptArg(), po::value< vector<string> >()->multitoken(),
- "Locates the task in the zombie list, and sets to adopt.\n"
- "Next time the child commands (init,event,meter,label,abort,complete) communicate\n"
- "with the server, the password on the zombie is adopted by the task.\n"
- "The zombie is then deleted.\n"
- " arg = path to task"
- );
- break;
- }
- case User::REMOVE: {
- desc.add_options()( CtsApi::zombieRemoveArg(), po::value< vector<string> >()->multitoken(),
- "Locates the task in the zombie list, and removes it.\n"
- "Since a job typically has many child commands(i.e init, complete, event, meter, label)\n"
- "the zombie may reappear\n"
- " arg = path to task"
- );
- break;
- }
- case User::BLOCK: {
- desc.add_options()( CtsApi::zombieBlockArg(), po::value< vector<string> >()->multitoken(),
- "Locates the task in the zombie list, and blocks it.\n"
- "This is default behaviour of the child commands(init,event,meter,label,abort,complete)\n"
- "when the server can not match the passwords. Each child commands will continue\n"
- "attempting to connect to the server for 24 hours, and will then return an error.\n"
- "The connection timeout can be configured with environment ECF_TIMEOUT\n"
- " arg = path to task"
- );
- break;
- }
- case User::KILL: {
- desc.add_options()( CtsApi::zombieKillArg(), po::value< vector<string> >()->multitoken(),
- "Locates the task in the zombie list, and kills the associated job.\n"
- "The kill is done using ECF_KILL_CMD, but using the process_id from the zombie\n"
- "The job is allowed to continue until the kill is received\n"
- "Can only kill zombies that have an associated Task, hence path zombies\n"
- "must be killed manually.\n"
- " arg = path to task"
- );
- break;
- }
- default: assert(false); break;
- }
-}
-
-void ZombieCmd::create( Cmd_ptr& cmd,
- boost::program_options::variables_map& vm,
- AbstractClientEnv* ace ) const
-{
- vector<string> args = vm[ theArg() ].as< vector<string> >();
- if (ace->debug()) dumpVecArgs( theArg(), args);
-
- // For Command Line Interface only the task_path is provided. Just have to make do.
- // arg1 = task_path
- // arg2 = process_or_remote_id ( empty for CLI)
- // arg3 = password ( empty for CLI)
- std::string path;
- std::string process_or_remote_id;
- std::string password;
- for(size_t i = 0; i < args.size(); i++) {
- if (i == 0 ) path = args[i];
- if (i == 1 ) process_or_remote_id = args[i];
- if (i == 2 ) password = args[i];
- }
- if (path.empty()) {
- throw std::runtime_error("ZombieCmd::create: expects at least one argument. path to task");
- }
-
- cmd = Cmd_ptr(new ZombieCmd(user_action_, path, process_or_remote_id, password ));
-}
-
-std::ostream& operator<<(std::ostream& os, const ZombieCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/stc/DefsCmd.cpp b/ecflow_4_0_7/Base/src/stc/DefsCmd.cpp
deleted file mode 100644
index 15361b5..0000000
--- a/ecflow_4_0_7/Base/src/stc/DefsCmd.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name : Cmd
-// Author : Avi
-// Revision : $Revision: #27 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <iostream>
-
-#include "DefsCmd.hpp"
-#include "ClientToServerCmd.hpp"
-#include "Defs.hpp"
-#include "Ecf.hpp"
-#include "AbstractServer.hpp"
-#include "PrintStyle.hpp"
-
-using namespace std;
-using namespace boost;
-
-//=====================================================================================
-// The defs command returns the full definition back to the client
-
-DefsCmd::DefsCmd(AbstractServer* as,bool save_edit_history)
-{
- init(as,save_edit_history);
-}
-
-void DefsCmd::init(AbstractServer* as,bool save_edit_history)
-{
- defs_ = as->defs();
- /// Return the current value of the state change no. So the that
- /// the next call to get the SSYncCmd , we need only return what's changed
- defs_->set_state_change_no( Ecf::state_change_no() );
- defs_->set_modify_change_no( Ecf::modify_change_no() );
- defs_->save_edit_history(save_edit_history);
-}
-
-bool DefsCmd::equals(ServerToClientCmd* rhs) const
-{
- DefsCmd* the_rhs = dynamic_cast<DefsCmd*>(rhs);
- if (!the_rhs) return false;
- if (!ServerToClientCmd::equals(rhs)) return false;
-
- if (defs_ == NULL && the_rhs->defs() == NULL) return true;
- if (defs_ == NULL && the_rhs->defs() != NULL) return false;
- if (defs_ != NULL && the_rhs->defs() == NULL) return false;
- return (*defs_ == *(the_rhs->defs()));
-}
-
-std::ostream& DefsCmd::print(std::ostream& os) const
-{
- os << "cmd:DefsCmd [ defs ]";
- return os;
-}
-
-// Called in client
-bool DefsCmd::handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const
-{
- if (debug) std::cout << "DefsCmd::handle_server_response show_state = " << PrintStyle::to_string(cts_cmd->show_style()) << "\n";
-
- // If we asked for the defs node tree from the server, then this is what we should have got back.
- // ** Keep existing defs in memory, until a new one is requested. This allows clients
- // ** to continue using this defs, in between other api calls, until a new defs is requested.
-
- if ( !defs_.get() ) {
- std::stringstream ss;
- ss << "DefsCmd::handle_server_response: Error Node tree could not be retrieved from server. Request "; cts_cmd->print(ss); ss << " failed.\n";
- throw std::runtime_error(ss.str());
- }
-
- if (server_reply.cli() && !cts_cmd->group_cmd()) {
- /// This Could be part of a group command, hence ONLY show defs if NOT group command
- PrintStyle style(cts_cmd->show_style());
-
- if (cts_cmd->show_style() != PrintStyle::MIGRATE) {
- /// Auto generate externs, before writing to standard out. This can be expensive since
- /// All the trigger references need to to be resolved. & AST need to be created first
- /// The old spirit based parsing, horrendously, slow. Can't use Spirit QI, till IBM pull support it
- defs_->auto_add_externs();
- }
- std::cout << *defs_;
- }
- else {
- server_reply.set_sync( true ); // always in sync when getting the full defs
- server_reply.set_full_sync( true ); // Done a full sync, as opposed to incremental
- server_reply.set_client_defs( defs_ );
- }
- return true;
-}
-
-
-std::ostream& operator<<(std::ostream& os, const DefsCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/stc/DefsCmd.hpp b/ecflow_4_0_7/Base/src/stc/DefsCmd.hpp
deleted file mode 100644
index 06c5499..0000000
--- a/ecflow_4_0_7/Base/src/stc/DefsCmd.hpp
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef DEFS_CMD_HPP_
-#define DEFS_CMD_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #14 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "ServerToClientCmd.hpp"
-class AbstractServer;
-
-//================================================================================
-// Paired with CtsNodeCmd(GET)
-// Client---CtsNodeCmd(GET)---->Server-----(DefsCmd | SNodeCmd)--->client:
-//================================================================================
-class DefsCmd : public ServerToClientCmd {
-public:
- DefsCmd(AbstractServer* as, bool save_edit_history = false);
- DefsCmd() {}
-
- void init(AbstractServer* as, bool save_edit_history);
-
- defs_ptr defs() const { return defs_; }
-
- virtual bool hasDefs() const { return defs_.get() != NULL; }
- virtual bool handle_server_response( ServerReply&, Cmd_ptr cts_cmd, bool debug ) const;
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ServerToClientCmd*) const;
-
-private:
- defs_ptr defs_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< ServerToClientCmd >( *this );
- ar & defs_;
- }
-};
-
-std::ostream& operator<<(std::ostream& os, const DefsCmd&);
-
-#endif
diff --git a/ecflow_4_0_7/Base/src/stc/ErrorCmd.cpp b/ecflow_4_0_7/Base/src/stc/ErrorCmd.cpp
deleted file mode 100644
index 1327974..0000000
--- a/ecflow_4_0_7/Base/src/stc/ErrorCmd.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #13 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <iostream>
-#include "ErrorCmd.hpp"
-#include "ClientToServerCmd.hpp"
-#include "Log.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-
-ErrorCmd::ErrorCmd(const std::string& errorMsg)
-{
- init(errorMsg);
-}
-
-void ErrorCmd::init( const std::string& errorMsg)
-{
-//#ifdef DEBUG
-// std::cout << ErrorCmd::init " << errorMsg << "\n";
-// LogToCout toCoutAsWell;
-//#endif
-
- LOG_ASSERT(!errorMsg.empty(),"");
- error_msg_ = errorMsg;
-
- // Log the error, Remove any "/n" as the log file will add this automatically
- size_t pos = error_msg_.rfind("\n");
- if (pos != string::npos) error_msg_.erase(error_msg_.begin() + pos);
- ecf::log(Log::ERR,error_msg_); // will automatically add end of line
-}
-
-std::ostream& ErrorCmd::print(std::ostream& os) const { return os << "cmd:Error [ " << error_msg_ << " ]";}
-
-bool ErrorCmd::equals(ServerToClientCmd* rhs) const
-{
- return (dynamic_cast<ErrorCmd*>(rhs)) ? ServerToClientCmd::equals(rhs) : false;
-}
-
-bool ErrorCmd::handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const
-{
- if (debug) std::cout << "ErrorCmd::handle_server_response " << error_msg_ << "\n";
-
- std::stringstream ss;
- ss << "Error: request( "; cts_cmd->print(ss); ss << " ) failed! Server replied with: '" << error_msg_ << "'\n";
- server_reply.set_error_msg(ss.str());
- return false;
-}
-
-std::ostream& operator<<(std::ostream& os, const ErrorCmd& c) { return c.print(os); }
-
diff --git a/ecflow_4_0_7/Base/src/stc/ErrorCmd.hpp b/ecflow_4_0_7/Base/src/stc/ErrorCmd.hpp
deleted file mode 100644
index 4b3ee5f..0000000
--- a/ecflow_4_0_7/Base/src/stc/ErrorCmd.hpp
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef ERROR_CMD_HPP_
-#define ERROR_CMD_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include "ServerToClientCmd.hpp"
-
-class ErrorCmd : public ServerToClientCmd {
-public:
- ErrorCmd(const std::string& errorMsg);
- ErrorCmd() : ServerToClientCmd() {}
-
- void init( const std::string& errorMsg);
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ServerToClientCmd*) const;
- virtual bool handle_server_response( ServerReply&, Cmd_ptr cts_cmd, bool debug ) const;
-
- virtual std::string error() const { return error_msg_;} /// Used by test
- virtual bool ok() const { return false; } /// Used by group command
-
-private:
- std::string error_msg_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< ServerToClientCmd >( *this );
- ar & error_msg_;
- }
-};
-
-std::ostream& operator<<(std::ostream& os, const ErrorCmd&);
-
-#endif
diff --git a/ecflow_4_0_7/Base/src/stc/GroupSTCCmd.cpp b/ecflow_4_0_7/Base/src/stc/GroupSTCCmd.cpp
deleted file mode 100644
index 983723d..0000000
--- a/ecflow_4_0_7/Base/src/stc/GroupSTCCmd.cpp
+++ /dev/null
@@ -1,124 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #18 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <boost/foreach.hpp>
-#include "GroupSTCCmd.hpp"
-#include "ClientToServerCmd.hpp"
-#include "Str.hpp"
-#include "Defs.hpp"
-#include "Log.hpp"
-#include "PrintStyle.hpp"
-#include "WhyCmd.hpp"
-#include "Task.hpp"
-#include "Family.hpp"
-#include "Suite.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-
-std::ostream& GroupSTCCmd::print(std::ostream& os) const
-{
- return os << "cmd:GroupSTCCmd";
-}
-
-bool GroupSTCCmd::equals(ServerToClientCmd* rhs) const
-{
- GroupSTCCmd* the_rhs = dynamic_cast< GroupSTCCmd* > ( rhs );
- if ( !the_rhs ) return false;
-
- const std::vector<STC_Cmd_ptr>& rhsCmdVec = the_rhs->cmdVec();
- if (cmdVec_.size() != rhsCmdVec.size()) return false;
-
- for(size_t i = 0; i < cmdVec_.size(); i++) {
- if ( !cmdVec_[i]->equals( rhsCmdVec[i].get() ) ) {
- return false;
- }
- }
-
- return ServerToClientCmd::equals(rhs);
-}
-
-bool GroupSTCCmd::handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const
-{
- if (debug) std::cout << "GroupSTCCmd::handle_server_response\n";
-
- BOOST_FOREACH(STC_Cmd_ptr subCmd, cmdVec_) {
- (void)subCmd->handle_server_response(server_reply, cts_cmd, debug);
- }
-
- /// This assumes the DefsCmd::handle_server_response() | SNodeCmd::handle_server_response has been called
- /// this will populate ServerReply with the defs/node returned from the server
- defs_ptr defs = server_reply.client_defs();
- node_ptr node = server_reply.client_node();
-
- if ( cts_cmd->get_cmd() && (defs.get() || node.get())) {
- if (debug) std::cout << " GroupSTCCmd::handle_server_response *get* was called\n";
-
- /// client --group="get; show" # where get will call DefsCmd will return defs, from the server
- /// client --group="get; show state" # where get will call DefsCmd will return defs, from the server
- /// client --group="get /s1; show state" # where get will call DefsCmd will return defs, from the server
-
- // Print out the data that was received from server. as a part of get request.
- // The server can not do a show, it MUST be done at the Client side
- // The show request is only valid if the out bound request to the server
- PrintStyle::Type_t style = cts_cmd->show_style();
- if ( style != PrintStyle::NOTHING ) {
- if (debug) std::cout << " GroupSTCCmd::handle_server_response *show* was called " << PrintStyle::to_string(style) << "\n";
- PrintStyle::setStyle(style);
- if (defs.get()) {
-
- /// Auto generate externs, before writing to standard out. This can be expensive since
- /// All the trigger references need to to be resolved. & AST need to be created first
- /// The old spirit based parsing is horrendously, slow. Can't use Spirit QI, till IBM support it
- if (cts_cmd->show_style() != PrintStyle::MIGRATE) {
- defs->auto_add_externs();
- }
-
- std::cout << *defs.get();
- }
- else {
- if (node.get()) {
- Suite* suite = node->isSuite();
- if (suite) std::cout << *suite << "\n";
- Family* fam = node->isFamily();
- if (fam) std::cout << *fam << "\n";
- Task* task = node->isTask();
- if (task) std::cout << *task << "\n";
- }
- }
- }
- }
-
- std::string nodePath;
- if (cts_cmd->why_cmd(nodePath) && defs.get()) {
- if (debug) std::cout << " GroupSTCCmd::handle_server_response *why* was called\n";
-
- /// client --group="get; why" # where get will call DefsCmd will return defs, from the server
- /// client --group="get; why <path>" # where get will call DefsCmd will return defs, from the server
- WhyCmd cmd(defs, nodePath);
- std::cout << cmd.why() << "\n";
- }
-
- return true;
-}
-
-void GroupSTCCmd::addChild(STC_Cmd_ptr childCmd)
-{
- LOG_ASSERT(childCmd.get(),""); // Dont add NULL children
- cmdVec_.push_back(childCmd);
-}
-
-std::ostream& operator<<(std::ostream& os, const GroupSTCCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/stc/GroupSTCCmd.hpp b/ecflow_4_0_7/Base/src/stc/GroupSTCCmd.hpp
deleted file mode 100644
index cdad074..0000000
--- a/ecflow_4_0_7/Base/src/stc/GroupSTCCmd.hpp
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef GROUP_STC_CMD_HPP_
-#define GROUP_STC_CMD_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #8 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "ServerToClientCmd.hpp"
-
-class GroupSTCCmd : public ServerToClientCmd {
-public:
- GroupSTCCmd() : ServerToClientCmd() {}
-
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ServerToClientCmd*) const;
- virtual bool handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const;
-
- void addChild(STC_Cmd_ptr childCmd);
- const std::vector<STC_Cmd_ptr>& cmdVec() const { return cmdVec_;}
-
-private:
- std::vector<STC_Cmd_ptr> cmdVec_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< ServerToClientCmd >( *this );
- ar & cmdVec_;
- }
-};
-
-std::ostream& operator<<(std::ostream& os, const GroupSTCCmd&);
-
-#endif
diff --git a/ecflow_4_0_7/Base/src/stc/PreAllocatedReply.cpp b/ecflow_4_0_7/Base/src/stc/PreAllocatedReply.cpp
deleted file mode 100644
index 0607ccf..0000000
--- a/ecflow_4_0_7/Base/src/stc/PreAllocatedReply.cpp
+++ /dev/null
@@ -1,201 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #24 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "PreAllocatedReply.hpp"
-
-#include "StcCmd.hpp"
-#include "DefsCmd.hpp"
-#include "SNodeCmd.hpp"
-#include "SStringCmd.hpp"
-#include "SStringVecCmd.hpp"
-#include "SServerLoadCmd.hpp"
-#include "GroupSTCCmd.hpp"
-#include "ErrorCmd.hpp"
-#include "SNewsCmd.hpp"
-#include "SSyncCmd.hpp"
-#include "SStatsCmd.hpp"
-#include "SSuitesCmd.hpp"
-#include "SClientHandleCmd.hpp"
-#include "SClientHandleSuitesCmd.hpp"
-#include "ZombieGetCmd.hpp"
-
-STC_Cmd_ptr PreAllocatedReply::stc_cmd_ = STC_Cmd_ptr( new StcCmd() );
-STC_Cmd_ptr PreAllocatedReply::defs_cmd_ = STC_Cmd_ptr( new DefsCmd() );
-STC_Cmd_ptr PreAllocatedReply::node_cmd_ = STC_Cmd_ptr( new SNodeCmd() );
-STC_Cmd_ptr PreAllocatedReply::stats_cmd_ = STC_Cmd_ptr( new SStatsCmd() );
-STC_Cmd_ptr PreAllocatedReply::suites_cmd_ = STC_Cmd_ptr( new SSuitesCmd() );
-STC_Cmd_ptr PreAllocatedReply::zombie_get_cmd_ = STC_Cmd_ptr( new ZombieGetCmd() );
-STC_Cmd_ptr PreAllocatedReply::error_cmd_ = STC_Cmd_ptr( new ErrorCmd() );
-STC_Cmd_ptr PreAllocatedReply::client_handle_cmd_ = STC_Cmd_ptr( new SClientHandleCmd() );
-STC_Cmd_ptr PreAllocatedReply::client_handle_suites_cmd_ = STC_Cmd_ptr( new SClientHandleSuitesCmd() );
-STC_Cmd_ptr PreAllocatedReply::string_cmd_ = STC_Cmd_ptr( new SStringCmd() );
-STC_Cmd_ptr PreAllocatedReply::string_vec_cmd_ = STC_Cmd_ptr( new SStringVecCmd() );
-STC_Cmd_ptr PreAllocatedReply::server_load_cmd_ = STC_Cmd_ptr( new SServerLoadCmd() );
-STC_Cmd_ptr PreAllocatedReply::news_cmd_ = STC_Cmd_ptr( new SNewsCmd() );
-STC_Cmd_ptr PreAllocatedReply::sync_cmd_ = STC_Cmd_ptr( new SSyncCmd() );
-
-STC_Cmd_ptr PreAllocatedReply::ok_cmd()
-{
- StcCmd* cmd = dynamic_cast<StcCmd*>(stc_cmd_.get());
- cmd->init(StcCmd::OK);
- return stc_cmd_;
-}
-STC_Cmd_ptr PreAllocatedReply::block_client_server_halted_cmd()
-{
- StcCmd* cmd = dynamic_cast<StcCmd*>(stc_cmd_.get());
- cmd->init(StcCmd::BLOCK_CLIENT_SERVER_HALTED);
- return stc_cmd_;
-}
-STC_Cmd_ptr PreAllocatedReply::block_client_on_home_server_cmd()
-{
- StcCmd* cmd = dynamic_cast<StcCmd*>(stc_cmd_.get());
- cmd->init(StcCmd::BLOCK_CLIENT_ON_HOME_SERVER);
- return stc_cmd_;
-}
-STC_Cmd_ptr PreAllocatedReply::block_client_zombie_cmd()
-{
- StcCmd* cmd = dynamic_cast<StcCmd*>(stc_cmd_.get());
- cmd->init(StcCmd::BLOCK_CLIENT_ZOMBIE);
- return stc_cmd_;
-}
-
-STC_Cmd_ptr PreAllocatedReply::defs_cmd(AbstractServer* as,bool save_edit_history)
-{
- DefsCmd* cmd = dynamic_cast<DefsCmd*>(defs_cmd_.get());
- cmd->init(as,save_edit_history);
- return defs_cmd_;
-}
-
-STC_Cmd_ptr PreAllocatedReply::node_cmd(AbstractServer* as,node_ptr node)
-{
- SNodeCmd* cmd = dynamic_cast<SNodeCmd*>(node_cmd_.get());
- cmd->init(as,node);
- return node_cmd_;
-}
-
-STC_Cmd_ptr PreAllocatedReply::stats_cmd(AbstractServer* as)
-{
- SStatsCmd* cmd = dynamic_cast<SStatsCmd*>(stats_cmd_.get());
- cmd->init(as);
- return stats_cmd_;
-}
-
-STC_Cmd_ptr PreAllocatedReply::suites_cmd(AbstractServer* as)
-{
- SSuitesCmd* cmd = dynamic_cast<SSuitesCmd*>(suites_cmd_.get());
- cmd->init(as);
- return suites_cmd_;
-}
-
-STC_Cmd_ptr PreAllocatedReply::zombie_get_cmd(AbstractServer* as)
-{
- ZombieGetCmd* cmd = dynamic_cast<ZombieGetCmd*>(zombie_get_cmd_.get());
- cmd->init(as);
- return zombie_get_cmd_;
-}
-
-STC_Cmd_ptr PreAllocatedReply::error_cmd(const std::string& error_msg)
-{
- ErrorCmd* cmd = dynamic_cast<ErrorCmd*>(error_cmd_.get());
- cmd->init(error_msg);
- return error_cmd_;
-}
-
-STC_Cmd_ptr PreAllocatedReply::client_handle_cmd(int handle)
-{
- SClientHandleCmd* cmd = dynamic_cast<SClientHandleCmd*>(client_handle_cmd_.get());
- cmd->init(handle);
- return client_handle_cmd_;
-}
-
-STC_Cmd_ptr PreAllocatedReply::client_handle_suites_cmd(AbstractServer* as)
-{
- SClientHandleSuitesCmd* cmd = dynamic_cast<SClientHandleSuitesCmd*>(client_handle_suites_cmd_.get());
- cmd->init(as);
- return client_handle_suites_cmd_;
-}
-
-STC_Cmd_ptr PreAllocatedReply::string_cmd(const std::string& any_string)
-{
- SStringCmd* cmd = dynamic_cast<SStringCmd*>(string_cmd_.get());
- cmd->init(any_string);
- return string_cmd_;
-}
-
-STC_Cmd_ptr PreAllocatedReply::string_vec_cmd(const std::vector<std::string>& vec)
-{
- SStringVecCmd* cmd = dynamic_cast<SStringVecCmd*>(string_vec_cmd_.get());
- cmd->init(vec);
- return string_vec_cmd_;
-}
-
-STC_Cmd_ptr PreAllocatedReply::server_load_cmd(const std::string& log_file_path)
-{
- SServerLoadCmd* cmd = dynamic_cast<SServerLoadCmd*>(server_load_cmd_.get());
- cmd->init(log_file_path);
- return server_load_cmd_;
-}
-
-STC_Cmd_ptr PreAllocatedReply::news_cmd(unsigned int client_handle,
- unsigned int client_state_change_no,
- unsigned int client_modify_change_no,
- AbstractServer* as)
-{
- SNewsCmd* cmd = dynamic_cast<SNewsCmd*>(news_cmd_.get());
- cmd->init(client_handle,client_state_change_no,client_modify_change_no,as);
- return news_cmd_;
-}
-
-STC_Cmd_ptr PreAllocatedReply::sync_cmd(unsigned int client_handle,
- unsigned int client_state_change_no,
- unsigned int client_modify_change_no,
- AbstractServer* as)
-{
- SSyncCmd* cmd = dynamic_cast<SSyncCmd*>(sync_cmd_.get());
- cmd->init(client_handle,client_state_change_no,client_modify_change_no,false,as);
- return sync_cmd_;
-}
-
-STC_Cmd_ptr PreAllocatedReply::sync_full_cmd(unsigned int client_handle,AbstractServer* as)
-{
- SSyncCmd* cmd = dynamic_cast<SSyncCmd*>(sync_cmd_.get()); // can reuse the same command
- cmd->init(client_handle,0,0,true,as);
- return sync_cmd_;
-}
-
-// ==============================================================================
-// Serialisation export
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "boost_archive.hpp"
-
-#include <boost/serialization/export.hpp> // explicit code for exports (place last) , needed for BOOST_CLASS_EXPORT
-BOOST_CLASS_EXPORT(DefsCmd)
-BOOST_CLASS_EXPORT(SNodeCmd)
-BOOST_CLASS_EXPORT(SStringCmd)
-BOOST_CLASS_EXPORT(SStringVecCmd)
-BOOST_CLASS_EXPORT(SServerLoadCmd)
-BOOST_CLASS_EXPORT(GroupSTCCmd)
-BOOST_CLASS_EXPORT(ErrorCmd)
-BOOST_CLASS_EXPORT(StcCmd)
-BOOST_CLASS_EXPORT(SSyncCmd)
-BOOST_CLASS_EXPORT(SNewsCmd)
-BOOST_CLASS_EXPORT(SStatsCmd)
-BOOST_CLASS_EXPORT(SSuitesCmd)
-BOOST_CLASS_EXPORT(SClientHandleCmd)
-BOOST_CLASS_EXPORT(SClientHandleSuitesCmd)
-BOOST_CLASS_EXPORT(ZombieGetCmd)
diff --git a/ecflow_4_0_7/Base/src/stc/PreAllocatedReply.hpp b/ecflow_4_0_7/Base/src/stc/PreAllocatedReply.hpp
deleted file mode 100644
index 13da996..0000000
--- a/ecflow_4_0_7/Base/src/stc/PreAllocatedReply.hpp
+++ /dev/null
@@ -1,71 +0,0 @@
-#ifndef PRE_ALLOCATED_REPLY_HPP_
-#define PRE_ALLOCATED_REPLY_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #22 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <string>
-#include <boost/noncopyable.hpp>
-#include "Cmd.hpp"
-#include "NodeFwd.hpp"
-class AbstractServer;
-
-// class PreAllocatedReply:
-// This class pre allocates the replies back to the client
-// This will help to reduce memory fragmentation.
-// Since the commands are re-used those commands with state,
-// should be cleared first
-class PreAllocatedReply : private boost::noncopyable {
-public:
- static STC_Cmd_ptr ok_cmd();
- static STC_Cmd_ptr block_client_server_halted_cmd();
- static STC_Cmd_ptr block_client_on_home_server_cmd();
- static STC_Cmd_ptr block_client_zombie_cmd();
-
- static STC_Cmd_ptr defs_cmd(AbstractServer*, bool save_edit_history);
- static STC_Cmd_ptr node_cmd(AbstractServer*,node_ptr);
- static STC_Cmd_ptr stats_cmd(AbstractServer*);
- static STC_Cmd_ptr suites_cmd(AbstractServer*);
- static STC_Cmd_ptr zombie_get_cmd(AbstractServer*);
- static STC_Cmd_ptr error_cmd(const std::string& error_msg);
- static STC_Cmd_ptr client_handle_cmd(int handle);
- static STC_Cmd_ptr client_handle_suites_cmd(AbstractServer*);
- static STC_Cmd_ptr string_cmd(const std::string& any_string);
- static STC_Cmd_ptr string_vec_cmd(const std::vector<std::string>&);
- static STC_Cmd_ptr server_load_cmd(const std::string& any_string);
- static STC_Cmd_ptr news_cmd(unsigned int client_handle,
- unsigned int client_state_change_no,
- unsigned int client_modify_change_no, AbstractServer* as);
- static STC_Cmd_ptr sync_cmd(unsigned int client_handle,
- unsigned int client_state_change_no,
- unsigned int client_modify_change_no, AbstractServer* as);
- static STC_Cmd_ptr sync_full_cmd(unsigned int client_handle,AbstractServer* as);
-private:
-
- static STC_Cmd_ptr stc_cmd_;
- static STC_Cmd_ptr defs_cmd_;
- static STC_Cmd_ptr node_cmd_;
- static STC_Cmd_ptr stats_cmd_;
- static STC_Cmd_ptr suites_cmd_;
- static STC_Cmd_ptr zombie_get_cmd_;
- static STC_Cmd_ptr error_cmd_;
- static STC_Cmd_ptr client_handle_cmd_;
- static STC_Cmd_ptr client_handle_suites_cmd_;
- static STC_Cmd_ptr string_cmd_;
- static STC_Cmd_ptr string_vec_cmd_;
- static STC_Cmd_ptr server_load_cmd_;
- static STC_Cmd_ptr news_cmd_;
- static STC_Cmd_ptr sync_cmd_;
-};
-
-#endif
diff --git a/ecflow_4_0_7/Base/src/stc/SClientHandleCmd.cpp b/ecflow_4_0_7/Base/src/stc/SClientHandleCmd.cpp
deleted file mode 100644
index 875d70d..0000000
--- a/ecflow_4_0_7/Base/src/stc/SClientHandleCmd.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <iostream>
-#include "SClientHandleCmd.hpp"
-
-using namespace ecf;
-using namespace std;
-
-bool SClientHandleCmd::equals(ServerToClientCmd* rhs) const
-{
- return (dynamic_cast<SClientHandleCmd*>(rhs)) ? ServerToClientCmd::equals(rhs) : false;
-}
-
-bool SClientHandleCmd::handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const
-{
- if (debug) cout << "SClientHandleCmd::handle_server_response handle_ = " << handle_ << "\n";
- server_reply.set_client_handle( handle_ );
- return true;
-}
-
-std::ostream& operator<<(std::ostream& os, const SClientHandleCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/stc/SClientHandleCmd.hpp b/ecflow_4_0_7/Base/src/stc/SClientHandleCmd.hpp
deleted file mode 100644
index f21d48c..0000000
--- a/ecflow_4_0_7/Base/src/stc/SClientHandleCmd.hpp
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef SCLIENT_HANDLE_CMD_HPP_
-#define SCLIENT_HANDLE_CMD_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include "ServerToClientCmd.hpp"
-
-class SClientHandleCmd : public ServerToClientCmd {
-public:
- SClientHandleCmd(int handle) : handle_(handle) {}
- SClientHandleCmd() : ServerToClientCmd() , handle_(0) {}
-
- void init(int handle) { handle_ = handle; }
- virtual std::ostream& print(std::ostream& os) const { return os << "cmd:SClientHandleCmd [ " << handle_ << " ]";}
- virtual bool equals(ServerToClientCmd*) const;
- virtual bool handle_server_response( ServerReply&, Cmd_ptr cts_cmd, bool debug ) const;
-
-private:
- int handle_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< ServerToClientCmd >( *this );
- ar & handle_;
- }
-};
-
-std::ostream& operator<<(std::ostream& os, const SClientHandleCmd&);
-
-#endif
diff --git a/ecflow_4_0_7/Base/src/stc/SClientHandleSuitesCmd.cpp b/ecflow_4_0_7/Base/src/stc/SClientHandleSuitesCmd.cpp
deleted file mode 100644
index 25faab2..0000000
--- a/ecflow_4_0_7/Base/src/stc/SClientHandleSuitesCmd.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #12 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include "SClientHandleSuitesCmd.hpp"
-#include "AbstractServer.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "ClientSuiteMgr.hpp"
-#include "ClientToServerCmd.hpp"
-
-using namespace std;
-
-//////////////////////////////////////////////////////////////////////////////////////////////////
-
-SClientHandleSuitesCmd::SClientHandleSuitesCmd(AbstractServer* as )
-{
- init(as);
-}
-
-void SClientHandleSuitesCmd::init(AbstractServer* as)
-{
- // This command can be re-used hence clear existing data members
- users_.clear();
- client_handles_.clear();
-
- ClientSuiteMgr& client_suite_mgr = as->defs()->client_suite_mgr();
- const std::vector<ecf::ClientSuites>& clientSuites = client_suite_mgr.clientSuites();
-
- size_t client_suites_size = clientSuites.size();
- client_handles_.reserve(client_suites_size);
- for(size_t c = 0; c < client_suites_size; c++) {
-
- // The handle suites are already ordered same as Defs suites
- std::vector<std::string> suite_names;
- clientSuites[c].suites( suite_names );
-
- client_handles_.push_back( std::make_pair(clientSuites[c].handle(), suite_names) );
-
- // Create user, and his list of handles
- bool fnd_user = false;
- for(size_t u = 0; u < users_.size(); u++) {
- if (users_[u].first == clientSuites[c].user()) {
- users_[u].second.push_back(clientSuites[c].handle());
- fnd_user = true;
- break;
- }
- }
- if (!fnd_user) {
- std::vector<unsigned int> handles; handles.push_back(clientSuites[c].handle());
- users_.push_back( std::make_pair(clientSuites[c].user(),handles) );
- }
- }
-}
-
-bool SClientHandleSuitesCmd::equals(ServerToClientCmd* rhs) const
-{
- SClientHandleSuitesCmd* the_rhs = dynamic_cast<SClientHandleSuitesCmd*>(rhs);
- if (!the_rhs) return false;
- return ServerToClientCmd::equals(rhs);
-}
-
-std::ostream& SClientHandleSuitesCmd::print(std::ostream& os) const
-{
- os << "cmd:SClientHandleSuitesCmd ";
- return os;
-}
-
-bool SClientHandleSuitesCmd::handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const
-{
- if (debug) std::cout << "SClientHandleSuitesCmd::handle_server_response\n";
-
- if (server_reply.cli() && !cts_cmd->group_cmd()) {
- /// This Could be part of a group command, hence ONLY if NOT group command
-
- // print out:
- // user handle suites
- // user1 1 s1 s2 s3
- // 2 s1 s2
- // user2 1 s1 s2 s3
- // 2 s1 s2
- for(size_t u = 0; u < users_.size(); u++) {
- if (u == 0) {
- cout << "\n";
- cout << left << setw(10) << "User" << setw(6) << "handle" << " suites\n";
- }
- cout << left << setw(10) << users_[u].first;
- for(size_t h = 0; h < users_[u].second.size(); h++) {
- unsigned int handle = users_[u].second[h];
- for( size_t c = 0; c < client_handles_.size(); c++) {
- if (handle == client_handles_[c].first) {
- if (h != 0) cout << " "; // 10 spaces to align handles
- cout << right << setw(6) << handle << " ";
- const std::vector<std::string>& suites = client_handles_[c].second;
- for(size_t i = 0; i < suites.size(); i++) { cout << suites[i] << " "; }
- cout << "\n";
- }
- }
- }
- }
- }
- else {
- server_reply.set_client_handle_suites(client_handles_);
- }
- return true;
-}
-
-std::ostream& operator<<(std::ostream& os, const SClientHandleSuitesCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/stc/SClientHandleSuitesCmd.hpp b/ecflow_4_0_7/Base/src/stc/SClientHandleSuitesCmd.hpp
deleted file mode 100644
index 57d5f95..0000000
--- a/ecflow_4_0_7/Base/src/stc/SClientHandleSuitesCmd.hpp
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef SCLIENT_HANDLE_SUITES_CMD_HPP_
-#define SCLIENT_HANDLE_SUITES_CMD_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "ServerToClientCmd.hpp"
-class AbstractServer;
-
-//================================================================================
-class SClientHandleSuitesCmd : public ServerToClientCmd {
-public:
- SClientHandleSuitesCmd(AbstractServer* as );
- SClientHandleSuitesCmd() : ServerToClientCmd() {}
-
- void init(AbstractServer* as);
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ServerToClientCmd*) const;
- virtual bool handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const;
-
-private:
- std::vector<std::pair<std::string, std::vector<unsigned int> > > users_; // users , list of handles
- std::vector<std::pair<unsigned int, std::vector<std::string> > > client_handles_; // handle, list of suites
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< ServerToClientCmd >( *this );
- ar & users_;
- ar & client_handles_;
- }
-};
-
-std::ostream& operator<<(std::ostream& os, const SClientHandleSuitesCmd&);
-
-#endif
diff --git a/ecflow_4_0_7/Base/src/stc/SNewsCmd.cpp b/ecflow_4_0_7/Base/src/stc/SNewsCmd.cpp
deleted file mode 100644
index 076e9f6..0000000
--- a/ecflow_4_0_7/Base/src/stc/SNewsCmd.cpp
+++ /dev/null
@@ -1,262 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #31 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <iostream>
-#include "SNewsCmd.hpp"
-#include "Defs.hpp"
-#include "Ecf.hpp"
-#include "AbstractServer.hpp"
-#include "Log.hpp"
-
-using namespace std;
-using namespace ecf;
-
-/// Custom handling of command logging so that we can add additional debug.
-/// Rely's on CSyncCmd not adding newline when logging the command
-#define DEBUG_NEWS 1
-
-
-SNewsCmd::SNewsCmd( unsigned int client_handle,
- unsigned int client_state_change_no,
- unsigned int client_modify_change_no,
- AbstractServer* as)
-: news_(ServerReply::NO_NEWS)
-{
- init(client_handle,client_state_change_no,client_modify_change_no,as);
-}
-
-/// Called in the server
-void SNewsCmd::init(
- unsigned int client_handle, // a reference to a set of suites used by client
- unsigned int client_state_change_no,
- unsigned int client_modify_change_no, AbstractServer* as)
-{
- news_ = ServerReply::NO_NEWS;
-
- // After ECFLOW-182 server will always have a defs, hence we should never return ServerReply::NO_DEFS
- // However keep as an enum, to allow new client(ecflowview) deal with reply from old server
- // defs_ptr server_defs = as->defs();
- // if ( ! server_defs.get() ) {
- //
- // news_ = ServerReply::NO_DEFS;
- //#if DEBUG_NEWS
- // log_append(" [:NO_DEFS]");
- //#else
- // log_append("");
- //#endif
- // return;
- // }
-
-
- // =====================================================================================
- // The code to determine changes here must also relate to SSyncCmd
- // ======================================================================================
-
- if (client_handle == 0) {
-
- // Here Ecf::modify_change_no() and Ecf::state_change_no() represent the max change numbers over *all* the suites
-
- /// *** The client_modify_change_no and client_state_change_no should always be trailing the server
- /// *** i.e the value should be less or equal to server. However if::
- /// *** o/ Server **dies** we can get the case, where client numbers are greater than server numbers.
- /// *** o/ Server changes number overflows, since it unsigned, and re-start's with 0
- /// *** When no handle are involved, we can get by with a full sync
- /// *** Note: whenever the server starts, the state and modify numbers start from zero
- if ( (client_modify_change_no > Ecf::modify_change_no()) || (client_state_change_no > Ecf::state_change_no())) {
-
- news_ = ServerReply::DO_FULL_SYNC;
-
-#if DEBUG_NEWS
- std::stringstream ss;
- ss << " [server(" << Ecf::state_change_no() << "," << Ecf::modify_change_no() << ") : client no > server no ! :DO_FULL_SYNC]";
- log_append(ss.str());
-#else
- log_append("");
-#endif
- return;
- }
-
- if ( client_modify_change_no < Ecf::modify_change_no()) {
-
- news_ = ServerReply::NEWS;
-
-#if DEBUG_NEWS
- std::stringstream ss;
- ss << " [server(" << Ecf::state_change_no() << "," << Ecf::modify_change_no() << ") : *Large* scale changes :NEWS]";
- log_append(ss.str());
-#else
- log_append("");
-#endif
- return;
- }
-
- if ( client_state_change_no < Ecf::state_change_no() ) {
-
- news_ = ServerReply::NEWS;
-
-#if DEBUG_NEWS
- std::stringstream ss;
- ss << " [server(" << Ecf::state_change_no() << "," << Ecf::modify_change_no() << ") : *Small* scale changes :NEWS]";
- log_append( ss.str());
-#else
- log_append("");
-#endif
- return;
- }
-
-
-#if DEBUG_NEWS
- log_append(" [:NO_NEWS]");
-#else
- log_append("");
-#endif
- return;
- }
-
- // =============================================================================================
- // Handle used: Determine the max modify and state change no, for suites in our handle
- // =============================================================================================
-
- /// *** If we can't find the handle, then it may be that the server died ?
- /// *** It is up to the client to do a full sync *including* re-registering suites
- ClientSuiteMgr& client_suite_mgr = as->defs()->client_suite_mgr();
- if ( ! client_suite_mgr.valid_handle(client_handle)) {
-
- news_ = ServerReply::DO_FULL_SYNC;
-
-#if DEBUG_NEWS
- std::stringstream ss;
- ss << " [server(" << Ecf::state_change_no() << "," << Ecf::modify_change_no() << ") : Can not find handle(" << client_handle << ") :DO_FULL_SYNC]";
- log_append(ss.str());
-#else
- log_append("");
-#endif
-
- return;
- }
-
- /// *** The client_modify_change_no and client_state_change_no should always be trailing the server
- /// *** i.e the value should be less or equal to server. However if
- /// *** o/ Server **dies** we can get the case, where client numbers are greater than server numbers.
- /// *** o/ Server changes number overflows, since it unsigned, and re-start's with 0
- /// *** we can get the case, where client numbers are greater than server numbers and also the
- /// *** handle will not exist in the server,
- /// *** It is up to the client to do a full sync *including* re-registering suites
- /// *** Note: whenever the server starts, the state and modify numbers start from zero
- unsigned int max_client_handle_modify_change_no = 0;
- unsigned int max_client_handle_state_change_no = 0;
- client_suite_mgr.max_change_no( client_handle,max_client_handle_state_change_no,max_client_handle_modify_change_no);
-
- if ((client_modify_change_no > max_client_handle_modify_change_no) || (client_state_change_no > max_client_handle_state_change_no)) {
-
- news_ = ServerReply::DO_FULL_SYNC;
-
-#if DEBUG_NEWS
- std::stringstream ss;
- ss << " [server handle(" << max_client_handle_state_change_no << ","
- << max_client_handle_modify_change_no << ") server(" << Ecf::state_change_no() << "," << Ecf::modify_change_no()
- << ") : client no > server no ! :DO_FULL_SYNC]";
- log_append(ss.str());
-#else
- log_append("");
-#endif
-
- return;
- }
-
- /// Changes where user adds a new handle/auto adds/removes require a full update, but only for changed handle
- if (client_suite_mgr.handle_changed( client_handle )) {
-
- news_ = ServerReply::NEWS;
-
-#if DEBUG_NEWS
- std::stringstream ss;
- ss << " [server handle(" << max_client_handle_state_change_no << ","
- << max_client_handle_modify_change_no << ") server(" << Ecf::state_change_no() << "," << Ecf::modify_change_no()
- << ") : *Large* scale changes (new handle or suites added or removed) :NEWS]";
- log_append(ss.str());
-#else
- log_append("");
-#endif
-
- return;
- }
-
- // The client handle represents a subset of the suites.
- if ( client_modify_change_no < max_client_handle_modify_change_no) {
-
- news_ = ServerReply::NEWS;
-
-#if DEBUG_NEWS
- std::stringstream ss;
- ss << " [server handle(" << max_client_handle_state_change_no << ","
- << max_client_handle_modify_change_no << ") server(" << Ecf::state_change_no() << "," << Ecf::modify_change_no()
- << ") : *Large* scale changes :NEWS]";
- log_append( ss.str());
-#else
- log_append("");
-#endif
-
- return;
- }
-
- // This should also reflect changes made just to the defs(state/suspended) and also the server state
- if ( client_state_change_no < max_client_handle_state_change_no ) {
-
- news_ = ServerReply::NEWS;
-
-#if DEBUG_NEWS
- std::stringstream ss;
- ss << " [server handle(" << max_client_handle_state_change_no << ","
- << max_client_handle_modify_change_no << ") server(" << Ecf::state_change_no() << "," << Ecf::modify_change_no()
- << ") : *Small* scale changes :NEWS]";
- log_append(ss.str());
-#else
- log_append("");
-#endif
-
- return;
- }
-
-#if DEBUG_NEWS
- log_append(" [:NO_NEWS]");
-#else
- log_append("");
-#endif
-}
-
-
-/// Called in the client
-bool SNewsCmd::handle_server_response( ServerReply& server_reply, Cmd_ptr /*cts_cmd*/, bool debug ) const
-{
- if (debug) std::cout << "SNewsCmd::handle_server_response news_ = " << news_ << "\n";
- server_reply.set_news( news_);
- return true;
-}
-
-bool SNewsCmd::equals(ServerToClientCmd* rhs) const
-{
- SNewsCmd* the_rhs = dynamic_cast<SNewsCmd*>(rhs);
- if (!the_rhs) return false;
- if (news_ != the_rhs->news()) return false;
- return ServerToClientCmd::equals(rhs);
-}
-
-std::ostream& SNewsCmd::print(std::ostream& os) const
-{
- os << "cmd:SNewsCmd [ " << news_ << " ] ";
- return os;
-}
-
-std::ostream& operator<<(std::ostream& os, const SNewsCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/stc/SNewsCmd.hpp b/ecflow_4_0_7/Base/src/stc/SNewsCmd.hpp
deleted file mode 100644
index e33dd99..0000000
--- a/ecflow_4_0_7/Base/src/stc/SNewsCmd.hpp
+++ /dev/null
@@ -1,63 +0,0 @@
-#ifndef SNEWS_CMD_HPP_
-#define SNEWS_CMD_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #9 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : class SNewsCmd: Used to determine any change in the server
-//
-// The *client_state_change_no* was passed from the client to the server
-// The *client_modify_change_no* was passed from the client to the server
-//
-// The code here needs to coordinate with SSyncCmd
-//
-// Paired with CtsCmd(NEWS)
-// Client---CtsCmd(NEWS)---->Server-----(SNewsCmd)--->client:
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "ServerToClientCmd.hpp"
-
-class SNewsCmd : public ServerToClientCmd {
-public:
- // The constructor is *called* in the server.
- SNewsCmd(unsigned int client_handle, // a reference to a set of suites used by client
- unsigned int client_state_change_no,
- unsigned int client_modify_change_no,
- AbstractServer* as);
- SNewsCmd() : ServerToClientCmd(), news_(ServerReply::NO_NEWS) {}
-
- void init(unsigned int client_handle, // a reference to a set of suites used by client
- unsigned int client_state_change_no,
- unsigned int client_modify_change_no,
- AbstractServer* as);
-
- ServerReply::News_t news() const { return news_;} // used by equals only
- bool get_news() const { return ( news_ != ServerReply::NO_NEWS); }
-
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ServerToClientCmd*) const;
- virtual bool handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const;
-
-private:
- // After ECFLOW-182, ServerReply::NO_DEFS no longer used, however kept, to ensure client/server compatibility
- // ie. for new client(viewer) must process this from old server, which could return NO_DEFS
- ServerReply::News_t news_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< ServerToClientCmd >( *this );
- ar & news_;
- }
-};
-
-std::ostream& operator<<(std::ostream& os, const SNewsCmd&);
-#endif
diff --git a/ecflow_4_0_7/Base/src/stc/SNodeCmd.cpp b/ecflow_4_0_7/Base/src/stc/SNodeCmd.cpp
deleted file mode 100644
index 98ace43..0000000
--- a/ecflow_4_0_7/Base/src/stc/SNodeCmd.cpp
+++ /dev/null
@@ -1,144 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name : Cmd
-// Author : Avi
-// Revision : $Revision: #11 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <iostream>
-
-#include "SNodeCmd.hpp"
-#include "ClientToServerCmd.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "Alias.hpp"
-#include "AbstractServer.hpp"
-#include "PrintStyle.hpp"
-
-using namespace std;
-using namespace boost;
-
-//=====================================================================================
-// This command returns the requested node back to the client
-// Note: In the case where defs has not been loaded, it can be NULL
-
-SNodeCmd::SNodeCmd(AbstractServer* as,node_ptr node)
-{
- init(as,node);
-}
-
-void SNodeCmd::init(AbstractServer* as, node_ptr node)
-{
- suite_.reset();
- family_.reset();
- task_.reset();
- alias_.reset();
-
- if (node.get()) {
- if (node->isSuite()) {
- suite_ = boost::dynamic_pointer_cast<Suite>(node);
- }
- else if (node->isFamily()) {
- family_ = boost::dynamic_pointer_cast<Family>(node);
- }
- else if (node->isTask()) {
- task_ = boost::dynamic_pointer_cast<Task>(node);
- }
- else if (node->isAlias()) {
- alias_ = boost::dynamic_pointer_cast<Alias>(node);
- }
- }
-}
-
-node_ptr SNodeCmd::get_node_ptr() const
-{
- if (suite_.get()) {
- return boost::dynamic_pointer_cast<Node>(suite_);
- }
- else if (family_.get()) {
- return boost::dynamic_pointer_cast<Node>(family_);
- }
- else if (task_.get()) {
- return boost::dynamic_pointer_cast<Node>(task_);
- }
- else if (alias_.get()) {
- return boost::dynamic_pointer_cast<Node>(alias_);
- }
- return node_ptr();
-}
-
-bool SNodeCmd::equals(ServerToClientCmd* rhs) const
-{
- SNodeCmd* the_rhs = dynamic_cast<SNodeCmd*>(rhs);
- if (!the_rhs) return false;
- if (!ServerToClientCmd::equals(rhs)) return false;
- return true;
-}
-
-std::ostream& SNodeCmd::print(std::ostream& os) const
-{
- os << "cmd:SNodeCmd [ ";
- node_ptr node = get_node_ptr();
- if (node.get()) os << node->absNodePath();
- else os << "node == NULL";
- os << " ]";
- return os;
-}
-
-// Called in client
-bool SNodeCmd::handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const
-{
- if (debug) std::cout << "SNodeCmd::handle_server_response\n";
-
- node_ptr node = get_node_ptr();
- if ( !node.get() ) {
- std::stringstream ss;
- ss << "SNodeCmd::handle_server_response: Error Node could not be retrieved from server. Request "; cts_cmd->print(ss); ss << " failed.\n";
- throw std::runtime_error(ss.str());
- }
-
-
- if (server_reply.cli() && !cts_cmd->group_cmd()) {
- /// This Could be part of a group command, hence ONLY show Node if NOT group command
- PrintStyle style(cts_cmd->show_style());
-
- Suite* suite = node->isSuite();
- if (suite) {
- if (cts_cmd->show_style() != PrintStyle::MIGRATE) {
- /// Auto generate externs, before writing to standard out. This can be expensive since
- /// All the trigger references need to to be resolved. & AST need to be created first
- /// The old spirit based parsing, horrendously, slow. Can't use Spirit QI, till IBM pull support it
- ///
- /// We need a fabricate a defs to show the externs, used by the suite
- Defs defs;
- defs.addSuite(boost::dynamic_pointer_cast<Suite>( node ));
- defs.auto_add_externs();
- std::cout << defs;
- return true;
- }
- std::cout << *suite << "\n";
- return true;
- }
- Family* fam = node->isFamily();
- if (fam) std::cout << *fam << "\n";
- Task* task = node->isTask();
- if (task) std::cout << *task << "\n";
- Alias* alias = node->isAlias();
- if (alias) std::cout << *alias << "\n";
- }
- else {
- server_reply.set_client_node( node );
- }
- return true;
-}
-
-std::ostream& operator<<(std::ostream& os, const SNodeCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/stc/SNodeCmd.hpp b/ecflow_4_0_7/Base/src/stc/SNodeCmd.hpp
deleted file mode 100644
index ac57463..0000000
--- a/ecflow_4_0_7/Base/src/stc/SNodeCmd.hpp
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef SNODE_CMD_HPP_
-#define SNODE_CMD_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "ServerToClientCmd.hpp"
-class AbstractServer;
-
-//================================================================================
-// Paired with CtsNodeCmd(Get)
-// Client---CtsNodeCmd(GET)---->Server-----(SNodeCmd | SNodeCmd)--->client:
-//================================================================================
-class SNodeCmd : public ServerToClientCmd {
-public:
- SNodeCmd(AbstractServer* as,node_ptr node);
- SNodeCmd() {}
-
- void init(AbstractServer* as, node_ptr node);
-
- virtual bool handle_server_response( ServerReply&, Cmd_ptr cts_cmd, bool debug ) const;
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ServerToClientCmd*) const;
- virtual bool hasNode() const { return true; } /// used by group command
-
-private:
- node_ptr get_node_ptr() const;
-
- suite_ptr suite_;
- family_ptr family_;
- task_ptr task_;
- alias_ptr alias_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< ServerToClientCmd >( *this );
- ar & suite_;
- ar & family_;
- ar & task_;
- ar & alias_;
- }
-};
-
-std::ostream& operator<<(std::ostream& os, const SNodeCmd&);
-
-#endif
diff --git a/ecflow_4_0_7/Base/src/stc/SServerLoadCmd.cpp b/ecflow_4_0_7/Base/src/stc/SServerLoadCmd.cpp
deleted file mode 100644
index 29c5cbe..0000000
--- a/ecflow_4_0_7/Base/src/stc/SServerLoadCmd.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <iostream>
-#include "SServerLoadCmd.hpp"
-#include "Gnuplot.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-
-bool SServerLoadCmd::equals(ServerToClientCmd* rhs) const
-{
- SServerLoadCmd* the_rhs = dynamic_cast<SServerLoadCmd*>(rhs);
- if (!the_rhs) return false;
- if (log_file_path_ != the_rhs->log_file_path()) return false;
- return ServerToClientCmd::equals(rhs);
-}
-
-std::ostream& SServerLoadCmd::print(std::ostream& os) const
-{
- os << "cmd:SServerLoadCmd [ " << log_file_path_ << " ]";
- return os;
-}
-
-bool SServerLoadCmd::handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const
-{
- if (debug) cout << "SServerLoadCmd::handle_server_response log_file_path = " << log_file_path() << "\n";
- Gnuplot::show_server_load(log_file_path());
- return true;
-}
-
-std::ostream& operator<<(std::ostream& os, const SServerLoadCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/stc/SServerLoadCmd.hpp b/ecflow_4_0_7/Base/src/stc/SServerLoadCmd.hpp
deleted file mode 100644
index a1d08a7..0000000
--- a/ecflow_4_0_7/Base/src/stc/SServerLoadCmd.hpp
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef SSERVER_LOAD_CMD_HPP_
-#define SSERVER_LOAD_CMD_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "ServerToClientCmd.hpp"
-
-///================================================================================
-/// Paired with CtsCmd::SERVER_LOAD
-/// Client---(CtsCmd::SERVER_LOAD)---->Server-----(SServerLoadCmd)--->client:
-///================================================================================
-class SServerLoadCmd : public ServerToClientCmd {
-public:
- SServerLoadCmd(const std::string& log_file_path) : log_file_path_(log_file_path) {}
- SServerLoadCmd() : ServerToClientCmd() {}
-
- void init(const std::string& s) { log_file_path_ = s;}
- const std::string& log_file_path() const { return log_file_path_; }
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ServerToClientCmd*) const;
- virtual bool handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const;
-
-private:
- std::string log_file_path_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< ServerToClientCmd >( *this );
- ar & log_file_path_;
- }
-};
-
-std::ostream& operator<<(std::ostream& os, const SServerLoadCmd&);
-
-#endif
diff --git a/ecflow_4_0_7/Base/src/stc/SStatsCmd.cpp b/ecflow_4_0_7/Base/src/stc/SStatsCmd.cpp
deleted file mode 100644
index d31f09e..0000000
--- a/ecflow_4_0_7/Base/src/stc/SStatsCmd.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #11 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "SStatsCmd.hpp"
-#include "AbstractServer.hpp"
-#include "Defs.hpp"
-
-using namespace std;
-
-//////////////////////////////////////////////////////////////////////////////////////////////////
-
-SStatsCmd::SStatsCmd(AbstractServer* as )
-{
- init(as);
-}
-
-void SStatsCmd::init(AbstractServer* as)
-{
- as->stats().update_for_serialisation();
- stats_ = as->stats();
- stats_.no_of_suites_ = as->defs()->suiteVec().size();
-}
-
-bool SStatsCmd::equals(ServerToClientCmd* rhs) const
-{
- SStatsCmd* the_rhs = dynamic_cast<SStatsCmd*>(rhs);
- if (!the_rhs) return false;
- return ServerToClientCmd::equals(rhs);
-}
-
-std::ostream& SStatsCmd::print(std::ostream& os) const
-{
- os << "cmd:SStatsCmd ";
- return os;
-}
-
-bool SStatsCmd::handle_server_response( ServerReply& server_reply, Cmd_ptr /*cts_cmd*/, bool debug ) const
-{
- if (debug) std::cout << "SStatsCmd::handle_server_response\n";
- if (server_reply.cli()) stats_.show();
- else server_reply.set_stats( stats_ );
- return true;
-}
-
-std::ostream& operator<<(std::ostream& os, const SStatsCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/stc/SStatsCmd.hpp b/ecflow_4_0_7/Base/src/stc/SStatsCmd.hpp
deleted file mode 100644
index fa2017a..0000000
--- a/ecflow_4_0_7/Base/src/stc/SStatsCmd.hpp
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef SSTATS_CMD_HPP_
-#define SSTATS_CMD_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #8 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "ServerToClientCmd.hpp"
-#include "Stats.hpp"
-class AbstractServer;
-
-//================================================================================
-// Paired with CtsCmd(STATS)
-// Client---(CtsCmd(STATS))---->Server-----(SStatsCmd)--->client:
-//================================================================================
-class SStatsCmd : public ServerToClientCmd {
-public:
- SStatsCmd(AbstractServer* as );
- SStatsCmd() : ServerToClientCmd() {}
-
- void init(AbstractServer* as);
-
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ServerToClientCmd*) const;
- virtual bool handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const;
-
-private:
- Stats stats_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< ServerToClientCmd >( *this );
- ar & stats_;
- }
-};
-
-std::ostream& operator<<(std::ostream& os, const SStatsCmd&);
-
-#endif
diff --git a/ecflow_4_0_7/Base/src/stc/SStringCmd.cpp b/ecflow_4_0_7/Base/src/stc/SStringCmd.cpp
deleted file mode 100644
index 6b9525b..0000000
--- a/ecflow_4_0_7/Base/src/stc/SStringCmd.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <iostream>
-#include "SStringCmd.hpp"
-
-using namespace std;
-using namespace boost;
-
-//////////////////////////////////////////////////////////////////////////////////////////////////
-
-bool SStringCmd::equals(ServerToClientCmd* rhs) const
-{
- SStringCmd* the_rhs = dynamic_cast<SStringCmd*>(rhs);
- if (!the_rhs) return false;
- if (str_ != the_rhs->get_string()) return false;
- return ServerToClientCmd::equals(rhs);
-}
-
-std::ostream& SStringCmd::print(std::ostream& os) const
-{
- os << "cmd:SStringCmd ";
- return os;
-}
-
-bool SStringCmd::handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const
-{
- if (debug) cout << "SStringCmd::handle_server_response str.size()= " << str_.size() << "\n";
- if (server_reply.cli()) std::cout << str_ << "\n";
- else server_reply.set_string( str_ );
- return true;
-}
-
-std::ostream& operator<<(std::ostream& os, const SStringCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/stc/SStringCmd.hpp b/ecflow_4_0_7/Base/src/stc/SStringCmd.hpp
deleted file mode 100644
index 56bc215..0000000
--- a/ecflow_4_0_7/Base/src/stc/SStringCmd.hpp
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef SSTRING_CMD_HPP_
-#define SSTRING_CMD_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "ServerToClientCmd.hpp"
-
-///================================================================================
-/// Paired with CFileCmd
-/// Client---(CFileCmd)---->Server-----(SStringCmd)--->client:
-/// Only valid when the clients request a CFileCmd *OR* Log file
-/// Other times this will be empty.
-/// CFileCmd:: The file Contents(script,job,jobout,manual)
-/// Can be potentially very large
-/// LogCmd: The log file Can be potentially very large
-/// Only really valid if the out bound request was a LogCmd(LogCmd::GET)
-///================================================================================
-class SStringCmd : public ServerToClientCmd {
-public:
- SStringCmd(const std::string& s) : str_(s) {}
- SStringCmd() : ServerToClientCmd() {}
-
- void init(const std::string& s) { str_ = s;}
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ServerToClientCmd*) const;
- virtual const std::string& get_string() const { return str_;} // used by group command
- virtual bool handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const;
-
-private:
- std::string str_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< ServerToClientCmd >( *this );
- ar & str_;
- }
-};
-
-std::ostream& operator<<(std::ostream& os, const SStringCmd&);
-
-#endif
diff --git a/ecflow_4_0_7/Base/src/stc/SStringVecCmd.cpp b/ecflow_4_0_7/Base/src/stc/SStringVecCmd.cpp
deleted file mode 100644
index 6e3efd9..0000000
--- a/ecflow_4_0_7/Base/src/stc/SStringVecCmd.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <iostream>
-#include "SStringVecCmd.hpp"
-
-using namespace std;
-using namespace boost;
-
-//////////////////////////////////////////////////////////////////////////////////////////////////
-
-bool SStringVecCmd::equals(ServerToClientCmd* rhs) const
-{
- SStringVecCmd* the_rhs = dynamic_cast<SStringVecCmd*>(rhs);
- if (!the_rhs) return false;
- if (vec_ != the_rhs->get_string_vec()) return false;
- return ServerToClientCmd::equals(rhs);
-}
-
-std::ostream& SStringVecCmd::print(std::ostream& os) const
-{
- os << "cmd:SStringVecCmd ";
- return os;
-}
-
-bool SStringVecCmd::handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const
-{
- if (debug) cout << "SStringVecCmd::handle_server_response str.size()= " << vec_.size() << "\n";
- if (server_reply.cli()) {
- for(size_t i = 0; i < vec_.size(); i++) {
- std::cout << vec_[i] << "\n";
- }
- }
- else server_reply.set_string_vec( vec_ );
- return true;
-}
-
-std::ostream& operator<<(std::ostream& os, const SStringVecCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/stc/SStringVecCmd.hpp b/ecflow_4_0_7/Base/src/stc/SStringVecCmd.hpp
deleted file mode 100644
index b9b092e..0000000
--- a/ecflow_4_0_7/Base/src/stc/SStringVecCmd.hpp
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef SSTRING_VEC_CMD_HPP_
-#define SSTRING_VEC_CMD_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "ServerToClientCmd.hpp"
-
-///================================================================================
-class SStringVecCmd : public ServerToClientCmd {
-public:
- SStringVecCmd(const std::vector<std::string>& s) : vec_(s) {}
- SStringVecCmd() : ServerToClientCmd() {}
-
- void init(const std::vector<std::string>& s) { vec_ = s;}
- const std::vector<std::string>& get_string_vec() const { return vec_;}
-
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ServerToClientCmd*) const;
- virtual bool handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const;
-
-private:
- std::vector<std::string> vec_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< ServerToClientCmd >( *this );
- ar & vec_;
- }
-};
-
-std::ostream& operator<<(std::ostream& os, const SStringVecCmd&);
-
-#endif
diff --git a/ecflow_4_0_7/Base/src/stc/SSuitesCmd.cpp b/ecflow_4_0_7/Base/src/stc/SSuitesCmd.cpp
deleted file mode 100644
index ec312e6..0000000
--- a/ecflow_4_0_7/Base/src/stc/SSuitesCmd.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #13 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "SSuitesCmd.hpp"
-#include "AbstractServer.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "ClientSuiteMgr.hpp"
-#include "ClientToServerCmd.hpp"
-
-using namespace std;
-
-//////////////////////////////////////////////////////////////////////////////////////////////////
-
-SSuitesCmd::SSuitesCmd(AbstractServer* as )
-{
- init(as);
-}
-
-void SSuitesCmd::init(AbstractServer* as)
-{
- // This command can be re-used hence clear existing data members
- suites_.clear();
-
- const std::vector<suite_ptr>& suiteVec = as->defs()->suiteVec();
- size_t suite_vec_size = suiteVec.size();
- suites_.reserve(suite_vec_size);
- for(size_t i = 0; i < suite_vec_size; i++) {
- suites_.push_back( suiteVec[i]->name() );
- }
-}
-
-bool SSuitesCmd::equals(ServerToClientCmd* rhs) const
-{
- SSuitesCmd* the_rhs = dynamic_cast<SSuitesCmd*>(rhs);
- if (!the_rhs) return false;
- return ServerToClientCmd::equals(rhs);
-}
-
-std::ostream& SSuitesCmd::print(std::ostream& os) const
-{
- os << "cmd:SSuitesCmd ";
- return os;
-}
-
-bool SSuitesCmd::handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const
-{
- if (debug) std::cout << "SSuitesCmd::handle_server_response\n";
-
- if (server_reply.cli() && !cts_cmd->group_cmd()) {
- /// This Could be part of a group command, hence ONLY if NOT group command
-
- if (suites_.empty()) {
- cout << "No suites\n";
- }
-
- int newline_at = 4;
- size_t the_size = suites_.size();
- for(size_t i = 0; i < the_size; i++) {
- cout << left << setw(20) << suites_[i];
- if (i != 0 && (i % newline_at) == 0) {
- cout << "\n";
- newline_at += 5;
- }
- }
- cout << "\n";
- }
- else {
- server_reply.set_string_vec(suites_);
- }
- return true;
-}
-
-std::ostream& operator<<(std::ostream& os, const SSuitesCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/stc/SSuitesCmd.hpp b/ecflow_4_0_7/Base/src/stc/SSuitesCmd.hpp
deleted file mode 100644
index e73095e..0000000
--- a/ecflow_4_0_7/Base/src/stc/SSuitesCmd.hpp
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef SSUITES_CMD_HPP_
-#define SSUITES_CMD_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #8 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "ServerToClientCmd.hpp"
-class AbstractServer;
-
-//================================================================================
-// Paired with CtsCmd(SUITES)
-// Client---(CtsCmd(SUITES))---->Server-----(SSuitesCmd)--->client:
-//================================================================================
-class SSuitesCmd : public ServerToClientCmd {
-public:
- SSuitesCmd(AbstractServer* as );
- SSuitesCmd() : ServerToClientCmd() {}
-
- void init(AbstractServer* as);
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ServerToClientCmd*) const;
- virtual bool handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const;
-
-private:
- std::vector<std::string> suites_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< ServerToClientCmd >( *this );
- ar & suites_;
- }
-};
-
-std::ostream& operator<<(std::ostream& os, const SSuitesCmd&);
-
-#endif
diff --git a/ecflow_4_0_7/Base/src/stc/SSyncCmd.cpp b/ecflow_4_0_7/Base/src/stc/SSyncCmd.cpp
deleted file mode 100644
index 40fa43c..0000000
--- a/ecflow_4_0_7/Base/src/stc/SSyncCmd.cpp
+++ /dev/null
@@ -1,466 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #55 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <iostream>
-
-#include "SSyncCmd.hpp"
-#include "Defs.hpp"
-#include "Ecf.hpp"
-#include "Log.hpp"
-#include "AbstractServer.hpp"
-#include "boost_archive.hpp" // collates boost archive includes
-
-using namespace std;
-using namespace boost;
-
-// =====================================================================================================
-//#define DEBUG_SERVER_SYNC 1
-//#define DEBUG_CLIENT_SYNC 1
-
-// ===========================================================================================
-// CACHE: the deserialization costs, so that if multiple clients request the full defs
-// we can improve the performance, by only performing that once for each state change.
-std::string FullServerDefsCache::full_server_defs_as_string_ = "";
-unsigned int FullServerDefsCache::state_change_no_ = 0;
-unsigned int FullServerDefsCache::modify_change_no_= 0;
-
-void FullServerDefsCache::update_cache_if_state_changed(defs_ptr defs)
-{
- // See if there was a state change *OR* if cache is empty
- if (state_change_no_ != Ecf::state_change_no() ||
- modify_change_no_ != Ecf::modify_change_no() ||
- full_server_defs_as_string_.empty()
- )
- {
- try {
-#ifdef DEBUG_SERVER_SYNC
- cout << ": *updating* cache";
-#endif
- // Update cache
- std::ostringstream archive_stream;
-
-#if defined(BINARY_ARCHIVE)
- boost::archive::binary_oarchive archive( archive_stream );
- archive << defs;
- full_server_defs_as_string_ = archive_stream.str();
- // std::cout << "async_write BINARY " << outbound_data_ << "\n";
-
-#elif defined(PORTABLE_BINARY_ARCHIVE)
- portable_binary_oarchive archive( archive_stream );
- archive << defs;
- full_server_defs_as_string_ = archive_stream.str();
- // std::cout << "async_write PORTABLE_BINARY " << outbound_data_ << "\n";
-
-#elif defined(EOS_PORTABLE_BINARY_ARCHIVE)
- eos::portable_oarchive archive( archive_stream );
- archive << defs;
- full_server_defs_as_string_ = archive_stream.str();
- // std::cout << "async_write EOS_PORTABLE_BINARY " << outbound_data_ << "\n";
-#else
- boost::archive::text_oarchive archive( archive_stream );
- archive << defs;
- full_server_defs_as_string_ = archive_stream.str();
- // std::cout << "async_write TEXT " << outbound_data_ << "\n";
-#endif
- }
- catch (const boost::archive::archive_exception& ae ) {
- // Unable to decode data. Something went wrong, inform the caller.
- ecf::LogToCout logToCout;
- LOG(ecf::Log::ERR,"FullServerDefsCache::update_cache_if_state_changed boost::archive::archive_exception " << ae.what());
- throw;
- }
-
- state_change_no_ = Ecf::state_change_no();
- modify_change_no_ = Ecf::modify_change_no();
- }
-#ifdef DEBUG_SERVER_SYNC
- else {
- cout << ": *cache* up to date";
- }
-#endif
-}
-
-defs_ptr FullServerDefsCache::restore_defs_from_string(const std::string& archive_data)
-{
-#ifdef DEBUG_CLIENT_SYNC
- cout << ": FullServerDefsCache::restore_defs_from_string: archive_data.size(" << archive_data.size() << ")";
-#endif
- defs_ptr defs;
- try {
- std::istringstream archive_stream(archive_data);
-
-#if defined(BINARY_ARCHIVE)
- // std::cout << "handle_read_data Archive BINARY\n";
- boost::archive::binary_iarchive archive( archive_stream );
- archive >> defs;
-
-#elif defined(PORTABLE_BINARY_ARCHIVE)
- // std::cout << "handle_read_data Archive PORTABLE_BINARY\n";
- portable_binary_iarchive archive( archive_stream );
- archive >> defs;
-
-#elif defined(EOS_PORTABLE_BINARY_ARCHIVE)
- // std::cout << "handle_read_data Archive EOS_PORTABLE_BINARY\n";
- eos::portable_iarchive archive( archive_stream );
- archive >> defs;
-
-#else
- // std::cout << "handle_read_data Archive TEXT\n";
- boost::archive::text_iarchive archive( archive_stream );
- archive >> defs;
-#endif
- } catch (const boost::archive::archive_exception& ae ) {
- // Unable to decode data.
- ecf::LogToCout logToCout;
- LOG(ecf::Log::ERR,"FullServerDefsCache::restore_defs_from_string: boost::archive::archive_exception " << ae.what());
- throw;
- } catch (std::exception& e) {
- // Unable to decode data.
- ecf::LogToCout logToCout;
- LOG(ecf::Log::ERR,"FullServerDefsCache::restore_defs_from_string " << e.what());
- throw;
- }
-
-#ifdef DEBUG_CLIENT_SYNC
- if (defs.get()) cout << ": valid defs";
- else cout << ": *empty* defs?";
-#endif
- return defs;
-}
-
-defs_ptr FullServerDefsCache::restore_defs_from_string()
-{
- // Used in Test when no client/server
- return restore_defs_from_string(full_server_defs_as_string_);
-}
-
-
-SSyncCmd::SSyncCmd(
- unsigned int client_handle,
- unsigned int client_state_change_no,
- unsigned int client_modify_change_no,
- AbstractServer* as
-)
-: full_defs_(false),no_defs_(false),
- incremental_changes_(client_state_change_no)
-{
- init(client_handle, client_state_change_no, client_modify_change_no, false, as);
-}
-
-void SSyncCmd::reset_data_members(unsigned int client_state_change_no)
-{
- full_defs_ = false;
- no_defs_ = false;
- incremental_changes_.init(client_state_change_no); // persisted, used for returning INCREMENTAL changes
- server_defs_ = defs_ptr(); // persisted, used for returning FULL definition
- full_server_defs_as_string_.clear(); // semi-persisted, i.e on load & not on saving
-}
-
-void SSyncCmd::init(
- unsigned int client_handle, // a reference to a set of suites used by client
- unsigned int client_state_change_no,
- unsigned int client_modify_change_no,
- bool do_full_sync,
- AbstractServer* as
-)
-{
- // ********************************************************
- // This is called in the server
- // ********************************************************
-#ifdef DEBUG_SERVER_SYNC
- cout << "SSyncCmd::init: client(" << client_state_change_no << "," << client_modify_change_no << ") server(" << Ecf::state_change_no() << "," << Ecf::modify_change_no() << ")";
-#endif
-
- // Reset all data members since this command can be re-used
- reset_data_members(client_state_change_no);
-
- // After ECFLOW-182 server will always have a defs, hence we should never return ServerReply::NO_DEFS
- // We have kept no_defs_ to allow compatibility. To allow new client(ecflowview) deal with reply from old server
- // Hence from release >= 4.0.7 no_defs_ will always be false
- // if ( ! as->defs().get() ) {
- //#ifdef DEBUG_SERVER_SYNC
- // cout << ": *NO* defs\n";
- //#endif
- // no_defs_ = true;
- // return;
- // }
-
- // explicit request
- if (do_full_sync) {
-#ifdef DEBUG_SERVER_SYNC
- cout << ": *Flag do_full_sync set* ";
-#endif
- full_sync(client_handle,as);
- return;
- }
-
- if (client_handle == 0) {
-#ifdef DEBUG_SERVER_SYNC
- cout << ": No *handle* ";
-#endif
-
- /// *** The client_modify_change_no and client_state_change_no should always be trailing the server
- /// *** i.e the value should be less or equal to server. However if the server **dies** we can
- /// *** get the case, where client numbers are greater than server numbers.
- /// *** When no handle are involved, we get by with a full sync
- /// *** Note: whenever the server starts, the state and modify numbers start from zero
- if ( client_modify_change_no > Ecf::modify_change_no() || client_state_change_no > Ecf::state_change_no()) {
-#ifdef DEBUG_SERVER_SYNC
- cout << ": client modify no > server modify no: Server died/restored? ";
-#endif
- full_sync(client_handle,as);
- return;
- }
-
- if ( client_modify_change_no < Ecf::modify_change_no()) {
-#ifdef DEBUG_SERVER_SYNC
- cout << ": *Large* scale changes: modify numbers not in sync ";
-#endif
- full_sync(client_handle,as);
- return;
- }
-
- // small scale changes. Collate changes over *defs* and all suites.
- // Suite stores the maximum state change, over *all* its children, this is used by client handle mechanism
- // and here to avoid traversing down the hierarchy.
- // ******** We must trap all child changes under the suite. See class SuiteChanged
- // ******** otherwise some attribute sync's will be missed
- as->defs()->collateChanges(client_handle,incremental_changes_);
- incremental_changes_.set_server_state_change_no(Ecf::state_change_no());
- incremental_changes_.set_server_modify_change_no(Ecf::modify_change_no());
-#ifdef DEBUG_SERVER_SYNC
- if (incremental_changes_.size()) cout << ":*small* scale changes: no of changes(" << incremental_changes_.size() << ")\n";
- else cout << ": *No changes*\n";
-#endif
- return;
- }
-
-
- //==========================================================================================
- // Handle used
- //==========================================================================================
- ClientSuiteMgr& client_suite_mgr = as->defs()->client_suite_mgr();
-#ifdef DEBUG_SERVER_SYNC
- cout << ": *handle* used " << client_handle << " : ";
- std::vector<string> suites; client_suite_mgr.suites(client_handle,suites);
- BOOST_FOREACH(const std::string& name, suites) { std::cout << name << " "; }
-#endif
-
- /// *** The client_modify_change_no and client_state_change_no should always be trailing the server
- /// *** i.e the value should be less or equal to server. However if the server **dies** we can
- /// *** get the case, where client numbers are greater than server numbers. In this case we do a full sync
- /// *** It is up to the client to catch the exception. and do a full sync *including* re-registering suites
- /// *** Note: whenever the server starts, the state and modify numbers start from zero
- unsigned int max_client_handle_modify_change_no = 0;
- unsigned int max_client_handle_state_change_no = 0;
- client_suite_mgr.max_change_no( client_handle, max_client_handle_state_change_no,max_client_handle_modify_change_no);
-#ifdef DEBUG_SERVER_SYNC
- cout << ": server_handle(" << max_client_handle_state_change_no << "," << max_client_handle_modify_change_no << ")";
-#endif
-
-
- if (client_modify_change_no > max_client_handle_modify_change_no || client_state_change_no > max_client_handle_state_change_no) {
-#ifdef DEBUG_SERVER_SYNC
- cout << ": client no > server no: Server died/restored?";
-#endif
- full_sync(client_handle,as);
- return;
- }
-
- if ( client_modify_change_no < max_client_handle_modify_change_no) {
-#ifdef DEBUG_SERVER_SYNC
- cout << ": *Large* scale changes : modify numbers not in sync";
-#endif
- full_sync(client_handle,as);
- return;
- }
-
- if (client_suite_mgr.handle_changed( client_handle )) {
- // *Large* scale handle changes, i.e. created handle/ added or removed suites
-#ifdef DEBUG_SERVER_SYNC
- cout << ": *Large* scale changes: added/removed suites to handle";
-#endif
- full_sync(client_handle,as);
- return;
- }
-
- // small scale changes
- as->defs()->collateChanges(client_handle,incremental_changes_);
- incremental_changes_.set_server_state_change_no(max_client_handle_state_change_no);
- incremental_changes_.set_server_modify_change_no(max_client_handle_modify_change_no);
-#ifdef DEBUG_SERVER_SYNC
- if (incremental_changes_.size()) cout << ": *small* scale changes: no of changes(" << incremental_changes_.size() << ")\n";
- else cout << ": *No changes*\n";
-#endif
-}
-
-
-void SSyncCmd::full_sync(unsigned int client_handle, AbstractServer* as)
-{
- if ( 0 == client_handle ) {
- // Have already checked for no defs.
- as->defs()->set_state_change_no( Ecf::state_change_no() );
- as->defs()->set_modify_change_no( Ecf::modify_change_no() );
-
- FullServerDefsCache::update_cache_if_state_changed(as->defs());
- full_defs_ = true;
-#ifdef DEBUG_SERVER_SYNC
- cout << ": *no handle* returning FULL defs(*cached* string, size(" << FullServerDefsCache::full_server_defs_as_string_.size() << "))" << endl;
-#endif
- return;
- }
-
-
-#ifdef DEBUG_SERVER_SYNC
- cout << ": returning handle based FULL defs";
-#endif
- // Only return the defs state and suites that the client has registered in the client handle
- // *HOWEVER* if the client has registered *ALL* the suites, just return the server defs
- // *with* the updated change numbers
- //
- // *OTHERWISE* this compute the **maximum** state and modify change numbers over
- // the suites managed by the client handle and then set it on the newly created defs file.
- // **** It also takes special precaution *NOT* to change Ecf::state_change_no() and Ecf::modify_change_no()
- // **** so that we avoid changing max modify no for suites not in our handle
- // **** Will clear the handle_changed flag
- //
- // **** Although we create a new defs, we use the same suites. This presents
- // **** a problem with the suites defs() pointer. To avoid corrupting the server defs
- // **** we set the suite defs ptr to the the real server defs.
- // **** --> The defs serialisation will setup the suite defs pointers. <---
- // **** An alternative would be to clone the entire suites, since this can have
- // **** hundreds of tasks. It would be very expensive.
- // **** This means that server_defs_ will fail invarint_checking before serialisation
- defs_ptr the_server_defs = as->defs()->client_suite_mgr().create_defs( client_handle, as->defs() );
- if ( the_server_defs.get() == as->defs().get()) {
- FullServerDefsCache::update_cache_if_state_changed(as->defs());
- full_defs_ = true;
-#ifdef DEBUG_SERVER_SYNC
- cout << ": The handle has *ALL* the suites: return the FULL defs(*cached* string, size(" << FullServerDefsCache::full_server_defs_as_string_.size() << "))";
-#endif
- }
- else {
- server_defs_ = the_server_defs;
- }
-
-#ifdef DEBUG_SERVER_SYNC
- if (server_defs_) cout << ": no of suites(" << server_defs_->suiteVec().size() << ")" << endl;
- else cout << ": NULL defs!" << endl;
-#endif
-}
-
-bool SSyncCmd::equals(ServerToClientCmd* rhs) const
-{
- SSyncCmd* the_rhs = dynamic_cast<SSyncCmd*>(rhs);
- if (!the_rhs) return false;
- return ServerToClientCmd::equals(rhs);
-}
-
-std::ostream& SSyncCmd::print(std::ostream& os) const
-{
- os << "cmd:SSyncCmd";
- return os;
-}
-
-bool SSyncCmd::handle_server_response( ServerReply& server_reply, Cmd_ptr /*cts_cmd*/, bool debug ) const
-{
- // Update server_reply.client_defs_, with the changes returned from the server
- do_sync( server_reply, debug );
-
- return true;
-}
-
-bool SSyncCmd::do_sync( ServerReply& server_reply, bool debug) const
-{
- // ****************************************************
- // On the client side
- // ****************************************************
- if (no_defs_) {
-#ifdef DEBUG_CLIENT_SYNC
- std::cout << "SSyncCmd::do_sync: No defs in the server. Reset client caches\n";
-#endif
- if (debug) std::cout << "SSyncCmd::do_sync:: No defs in the server. Reset client caches\n";
- server_reply.client_handle_ = 0;
- server_reply.client_defs_ = defs_ptr();
- server_reply.client_node_ = node_ptr();
- server_reply.set_sync( true );
- server_reply.set_full_sync( true );
- return true;
- }
-
- if (server_defs_.get()) {
- // *FULL* sync
- // to keep pace with the state changes. Passed back later on, get further changes
- // If non zero handle will contain suites specified in the client handle, including their max change numbers
- server_reply.client_defs_ = server_defs_;
- server_reply.set_sync( true );
- server_reply.set_full_sync( true );
- if (debug) cout << "SSyncCmd::do_sync::*FULL sync*, client side state/modify numbers(" << server_defs_->state_change_no() << "," << server_defs_->modify_change_no() << ")\n";
-#ifdef DEBUG_CLIENT_SYNC
- cout << "SSyncCmd::do_sync: defs *FULL sync*, client side state/modify numbers(" << server_defs_->state_change_no() << "," << server_defs_->modify_change_no() << ")\n";
-#endif
- return true;
- }
-
- if (full_defs_) {
- if (full_server_defs_as_string_.empty()) {
- // TEST path.(i.e no client server): re-use static string
-#ifdef DEBUG_CLIENT_SYNC
- cout << "SSyncCmd::do_sync: TEST PATH: *FULL CACHE sync* : using static cache";
-#endif
- server_reply.client_defs_ = FullServerDefsCache::restore_defs_from_string();
- }
- else {
-#ifdef DEBUG_CLIENT_SYNC
- cout << "SSyncCmd::do_sync: *FULL CACHE sync* : using cache returned from server: cache_size(" << full_server_defs_as_string_.size() << ")";
-#endif
- server_reply.client_defs_ = FullServerDefsCache::restore_defs_from_string(full_server_defs_as_string_);
- }
- server_reply.set_sync( true );
- server_reply.set_full_sync( true );
- if (debug) cout << "SSyncCmd::do_sync::*FULL CACHE sync*, client side state/modify numbers(" << server_reply.client_defs_->state_change_no() << "," << server_reply.client_defs_->modify_change_no() << ")\n";
-#ifdef DEBUG_CLIENT_SYNC
- cout << ": client side state/modify numbers(" << server_reply.client_defs_->state_change_no() << "," << server_reply.client_defs_->modify_change_no() << ")\n";
-#endif
- return true;
- }
-
- // Can only sync, *if* we have definition on the client side
- if (server_reply.client_defs_.get() ) {
- // *INCREMENTAL* sync
- // Apply mementos to the client side defs, to bring in sync with server defs
- // If *no* server loaded, then no changes applied
- // Returns true if are any memento's, i.e. server changed.
- server_reply.set_full_sync( false );
- bool changes_made_to_client = incremental_changes_.incremental_sync(server_reply.client_defs_,server_reply.changed_nodes());
- server_reply.set_sync( changes_made_to_client );
-
- if (debug) cout << "SSyncCmd::do_sync::*INCREMENTAL sync*, client side state/modify numbers("
- << incremental_changes_.get_server_state_change_no() << ","
- << incremental_changes_.get_server_modify_change_no() << ") changes_made_to_client("
- << changes_made_to_client << ")\n";
-
-#ifdef DEBUG_CLIENT_SYNC
- cout << "SSyncCmd::do_sync::*INCREMENTAL sync*, client side state/modify numbers("
- << incremental_changes_.get_server_state_change_no() << ","
- << incremental_changes_.get_server_modify_change_no() << ") changes_made_to_client("
- << changes_made_to_client << "), changed_node_paths("
- << server_reply.changed_nodes().size() << ")\n";
-#endif
- return changes_made_to_client;
- }
- return false;
-}
-
-std::ostream& operator<<(std::ostream& os, const SSyncCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/stc/SSyncCmd.hpp b/ecflow_4_0_7/Base/src/stc/SSyncCmd.hpp
deleted file mode 100644
index c474bfe..0000000
--- a/ecflow_4_0_7/Base/src/stc/SSyncCmd.hpp
+++ /dev/null
@@ -1,160 +0,0 @@
-#ifndef SSYNC_CMD_HPP_
-#define SSYNC_CMD_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #25 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/noncopyable.hpp>
-
-#include "ServerToClientCmd.hpp"
-#include "DefsDelta.hpp"
-
-//================================================================================
-// Cache the de-serialisation cost, in the *SERVER* when returning the FULL definition
-// When there are no state changes, we can just return the cache string for other clients
-// Thereby saving time in the server and client for de-serialisation.
-// Here we are trading memory for speed:
-//
-// Current for each client request we have:
-// client1: --------------> get---------------> Server
-// serialise---------<----de-serialize
-//
-// client2: --------------> get---------------> Server
-// serialise---------<----de-serialize
-//
-// client3: --------------> get---------------> Server
-// serialise---------<----de-serialize
-//
-// By caching the de-serialisation process, we can speed up the downloads.
-// However whenever there is a state change we need to update the cache
-//
-// client1: --------------> get---------------> Server
-// serialise------<----de-serialisation
-//
-// client2: --------------> get---------------> Server
-// serialise---------<----return cache
-//
-// client3: --------------> get---------------> Server
-// serialise---------<----return cache
-//================================================================================
-class FullServerDefsCache : private boost::noncopyable {
-public:
- // Server side
- static void update_cache_if_state_changed(defs_ptr defs);
-
- // Client side
- static defs_ptr restore_defs_from_string(const std::string&);
- static defs_ptr restore_defs_from_string(); // used in test
-
-private:
- friend class SSyncCmd;
-
- FullServerDefsCache();
- ~FullServerDefsCache();
- static std::string full_server_defs_as_string_;
- static unsigned int state_change_no_; // detect state change in defs across clients
- static unsigned int modify_change_no_; // detect state change in defs across clients
-};
-
-//================================================================================
-// class SSyncCmd: Used to transfer changes made in the server to the client
-// The client can then apply the changes to the client side defs.
-//
-// *** This class should be used in conjunction with the news command.
-// *** i.e The news command is used to test for server changes. This command
-// *** will then get those changes and merge them with client side defs, bringing
-// *** client and server defs in sync.
-//
-// The *client_state_change_no* was passed from the client to the server
-// The *client_modify_change_no* was passed from the client to the server
-//
-// This class make use of FullServerDefsCache as a performance optimisation.
-//================================================================================
-class SSyncCmd : public ServerToClientCmd {
-public:
- // The constructor is *called* in the server.
- // This will collate the incremental changes made so far relative to the client_state_change_no.
- // For large scale change we use client_modify_change_no this will require a full update
- // *THIS* constructor is used for *TEST* only
- SSyncCmd(unsigned int client_handle, // a reference to a set of suites used by client
- unsigned int client_state_change_no,
- unsigned int client_modify_change_no,
- AbstractServer* as);
-
- SSyncCmd() : ServerToClientCmd(), full_defs_(false), no_defs_(false), incremental_changes_(0) {}
-
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ServerToClientCmd*) const;
-
- // Client side functions:
- virtual bool handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const;
-
- /// do_sync() is invoked on the *client side*, Can throw std::runtime_error
- /// Either does a *FULL* or *INCREMENTAL sync depending on the
- /// changes in the server. Returns true if client defs changed.
- bool do_sync( ServerReply& server_reply, bool debug = false) const;
-
-private:
-
- friend class PreAllocatedReply;
- void init(unsigned int client_handle, // a reference to a set of suites used by client
- unsigned int client_state_change_no,
- unsigned int client_modify_change_no,
- bool full_sync,
- AbstractServer* as);
-
- /// For use when doing a full sync
- void init(unsigned int client_handle,AbstractServer* as);
-
- void reset_data_members(unsigned int client_state_change_no);
- void full_sync(unsigned int client_handle,AbstractServer* as);
-
-private:
-
- bool full_defs_;
- bool no_defs_;
- DefsDelta incremental_changes_;
- defs_ptr server_defs_; // for returning a subset of the suites
- std::string full_server_defs_as_string_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< ServerToClientCmd >( *this );
- ar & no_defs_; // inform user defs does not exist.
- ar & full_defs_; // returning full defs as a string
- ar & incremental_changes_; // state changes, small scale changes
-
- /// When the server_defs_ was created the def's pointer on the suites was reset back to real server defs
- /// This is not correct for server_defs_, since we use the *same* suites
- /// **** This is OK since by default the Defs serialisation will fix up the suite's def's pointers ***
- /// The alternative is to clone all the suites, which is very expensive
- ar & server_defs_; // large scale changes, if non zero handle, a small subset of the suites
-
- // when full_defs_ is set server_defs_ will be empty.
- if (Archive::is_saving::value) {
- // Avoid copying the string. As this could be very large > 60MB
- if (full_defs_) {
- ar & FullServerDefsCache::full_server_defs_as_string_;
- }
- else ar & full_server_defs_as_string_;
- }
- else {
- ar & full_server_defs_as_string_;
- }
- }
-};
-
-std::ostream& operator<<(std::ostream& os, const SSyncCmd&);
-
-#endif
diff --git a/ecflow_4_0_7/Base/src/stc/ServerToClientCmd.cpp b/ecflow_4_0_7/Base/src/stc/ServerToClientCmd.cpp
deleted file mode 100644
index cb0a07e..0000000
--- a/ecflow_4_0_7/Base/src/stc/ServerToClientCmd.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #16 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "ServerToClientCmd.hpp"
-#include "Str.hpp"
-
-using namespace ecf;
-
-ServerToClientCmd::~ServerToClientCmd() {}
-
-const std::string& ServerToClientCmd::get_string() const
-{
- return Str::EMPTY();
-}
diff --git a/ecflow_4_0_7/Base/src/stc/ServerToClientCmd.hpp b/ecflow_4_0_7/Base/src/stc/ServerToClientCmd.hpp
deleted file mode 100644
index 3f520a8..0000000
--- a/ecflow_4_0_7/Base/src/stc/ServerToClientCmd.hpp
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef SERVER_TO_CLIENT_CMD_HPP_
-#define SERVER_TO_CLIENT_CMD_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #19 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <string>
-#include <vector>
-
-#include <boost/serialization/base_object.hpp> // base class serialization
-#include <boost/serialization/serialization.hpp>
-#include <boost/serialization/assume_abstract.hpp>
-#include <boost/serialization/shared_ptr.hpp>
-
-#include "Cmd.hpp"
-#include "NodeFwd.hpp"
-#include "ServerReply.hpp"
-class AbstractServer;
-
-//================================================================================
-// Start of Server->client
-//================================================================================
-class ServerToClientCmd {
-public:
- virtual ~ServerToClientCmd();
-
- virtual std::ostream& print(std::ostream& os) const = 0;
- virtual bool equals(ServerToClientCmd*) const { return true;}
-
- virtual const std::string& get_string() const; /// Used by group command, can return any string, including file contents
- virtual bool ok() const { return true;} /// Used by group command
- virtual bool hasDefs() const { return false; } /// used by group command
- virtual bool hasNode() const { return false; } /// used by group command
- virtual std::string error() const { return std::string();} /// Used by test
- virtual bool isOkCmd() const { return false; } /// Used by server, to not respond back, client assumes OK
-
- // Called in client, if any data to be returned , the set on class ServerReply
- // Cmd_ptr cts_cmd can used for additional context.
- // return true, if client should exit, returns false, if further work required, ie blocking, errors, etc
- virtual bool handle_server_response( ServerReply&, Cmd_ptr cts_cmd, bool debug ) const = 0;
-
-protected:
- ServerToClientCmd(){}
-private:
- friend class boost::serialization::access;
- template<class Archive>
- void serialize(Archive &ar, const unsigned int /*version*/) {}
-};
-BOOST_SERIALIZATION_ASSUME_ABSTRACT(ServerToClientCmd)
-
-#endif
diff --git a/ecflow_4_0_7/Base/src/stc/StcCmd.cpp b/ecflow_4_0_7/Base/src/stc/StcCmd.cpp
deleted file mode 100644
index 95f7629..0000000
--- a/ecflow_4_0_7/Base/src/stc/StcCmd.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name : Cmd
-// Author : Avi
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <iostream>
-#include "StcCmd.hpp"
-
-std::ostream& StcCmd::print(std::ostream& os) const
-{
- switch (api_) {
- case StcCmd::OK: return os << "cmd:Ok"; break;
- case StcCmd::BLOCK_CLIENT_SERVER_HALTED: return os << "cmd:Server_halted"; break;
- case StcCmd::BLOCK_CLIENT_ON_HOME_SERVER: return os << "cmd:Wait"; break;
- case StcCmd::BLOCK_CLIENT_ZOMBIE: return os << "cmd:Zombie"; break;
- default: assert(false); break;
- }
- assert(false); // unknown command
- return os << "cmd:Unknown??";
-}
-
-// Client context
-bool StcCmd::handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const
-{
- bool ret = false;
- switch (api_) {
- case StcCmd::OK: {
- if (debug) std::cout << "StcCmd::handle_server_response OK\n";
- ret = true;
- break;
- }
- case StcCmd::BLOCK_CLIENT_SERVER_HALTED: {
- if (debug) std::cout << "StcCmd::handle_server_response BLOCK_CLIENT_SERVER_HALTED\n";
- server_reply.set_block_client_server_halted(); // requires further work, by ClientInvoker
- break;
- }
- case StcCmd::BLOCK_CLIENT_ON_HOME_SERVER: {
- if (debug) std::cout << "StcCmd::handle_server_response BLOCK_CLIENT_ON_HOME_SERVER\n";
- server_reply.set_block_client_on_home_server(); // requires further work, by ClientInvoker
- break;
- }
- case StcCmd::BLOCK_CLIENT_ZOMBIE: {
- if (debug) std::cout << "StcCmd::handle_server_response BLOCK_CLIENT_ZOMBIE\n";
- server_reply.set_block_client_zombie_detected(); // requires further work, by ClientInvoker
- break;
- }
- default: assert(false); break;
- }
- return ret;
-}
-
-bool StcCmd::equals(ServerToClientCmd* rhs) const
-{
- StcCmd* the_rhs = dynamic_cast<StcCmd*>(rhs);
- if (!the_rhs) return false;
- if (api_ != the_rhs->api()) return false;
- return ServerToClientCmd::equals(rhs);
-}
-
-std::ostream& operator<<(std::ostream& os, const StcCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/stc/StcCmd.hpp b/ecflow_4_0_7/Base/src/stc/StcCmd.hpp
deleted file mode 100644
index 1fff2af..0000000
--- a/ecflow_4_0_7/Base/src/stc/StcCmd.hpp
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef STC_CMD_HPP_
-#define STC_CMD_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #8 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "ServerToClientCmd.hpp"
-
-// Command that are simple replies to the client.
-// Originally we had separate commands. However this lead
-// TOC overflow on the AIX. Hence in order to minimise global
-// symbols due to use of boost serialisation, will use a single command
-class StcCmd : public ServerToClientCmd {
-public:
- enum Api { OK,
- BLOCK_CLIENT_SERVER_HALTED,
- BLOCK_CLIENT_ON_HOME_SERVER,
- BLOCK_CLIENT_ZOMBIE
- };
- StcCmd(Api a) : api_(a) {}
- StcCmd() : api_(OK) {}
-
- void init(Api a) { api_ = a;}
- Api api() const { return api_;}
-
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ServerToClientCmd*) const;
- virtual bool handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const;
-
- /// Other legitimate ServerToClientCmd commands also return ok() as true
- /// Hence must still have isOkCmd()
- virtual bool ok() const { return api_ == OK; } // used by group command
- virtual bool isOkCmd() const { return api_ == OK; } // Used if no reply back from server
-
-private:
- Api api_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< ServerToClientCmd >( *this );
- ar & api_;
- }
-};
-std::ostream& operator<<(std::ostream& os, const StcCmd&);
-#endif
diff --git a/ecflow_4_0_7/Base/src/stc/ZombieGetCmd.cpp b/ecflow_4_0_7/Base/src/stc/ZombieGetCmd.cpp
deleted file mode 100644
index e1dfef3..0000000
--- a/ecflow_4_0_7/Base/src/stc/ZombieGetCmd.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #11 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <iostream>
-#include "ZombieGetCmd.hpp"
-#include "AbstractServer.hpp"
-
-using namespace std;
-using namespace boost;
-
-ZombieGetCmd::ZombieGetCmd(AbstractServer* as)
-{
- init(as);
-}
-
-// called in the server
-void ZombieGetCmd::init(AbstractServer* as)
-{
- zombies_.clear();
- as->zombie_ctrl().get(zombies_);
-}
-
-bool ZombieGetCmd::equals(ServerToClientCmd* rhs) const
-{
- ZombieGetCmd* the_rhs = dynamic_cast<ZombieGetCmd*>(rhs);
- if (!the_rhs) return false;
- return ServerToClientCmd::equals(rhs);
-}
-
-std::ostream& ZombieGetCmd::print(std::ostream& os) const
-{
- os << "cmd:ZombieGetCmd [ " << zombies_.size() << " ]";
- return os;
-}
-
-// Called in client
-bool ZombieGetCmd::handle_server_response( ServerReply& server_reply, Cmd_ptr cts_cmd, bool debug ) const
-{
- if (debug) {
- std::cout << "ZombieGetCmd::handle_server_response zombies.size() = " << zombies_.size() << "\n";
- }
-
- if (server_reply.cli()) {
- std::cout << Zombie::pretty_print(zombies_);
- }
- else {
- if (debug) {
- std::cout << Zombie::pretty_print(zombies_);
- }
- server_reply.set_zombies( zombies_);
- }
- return true;
-}
-
-std::ostream& operator<<(std::ostream& os, const ZombieGetCmd& c) { return c.print(os); }
diff --git a/ecflow_4_0_7/Base/src/stc/ZombieGetCmd.hpp b/ecflow_4_0_7/Base/src/stc/ZombieGetCmd.hpp
deleted file mode 100644
index 680fb08..0000000
--- a/ecflow_4_0_7/Base/src/stc/ZombieGetCmd.hpp
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef ZOMBIE_GET_CMD_HPP_
-#define ZOMBIE_GET_CMD_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "ServerToClientCmd.hpp"
-#include "Zombie.hpp"
-class AbstractServer;
-
-//================================================================================
-// Paired with CtsCmd(GET_ZOMBIES)
-// Client---CtsCmd(GET_ZOMBIES)---->Server-----(ZombieGetCmd)--->client:
-//================================================================================
-class ZombieGetCmd : public ServerToClientCmd {
-public:
- ZombieGetCmd(AbstractServer*);
- ZombieGetCmd() : ServerToClientCmd() {}
-
- void init(AbstractServer*);
- virtual bool handle_server_response( ServerReply&, Cmd_ptr cts_cmd, bool debug ) const;
- virtual std::ostream& print(std::ostream& os) const;
- virtual bool equals(ServerToClientCmd*) const;
-
-private:
- std::vector<Zombie> zombies_;
-
- friend class boost::serialization::access;
- template<class Archive>
- void serialize( Archive & ar, const unsigned int /*version*/ ) {
- ar & boost::serialization::base_object< ServerToClientCmd >( *this );
- ar & zombies_;
- }
-};
-
-std::ostream& operator<<(std::ostream& os, const ZombieGetCmd&);
-
-#endif
diff --git a/ecflow_4_0_7/Base/test/MockServer.hpp b/ecflow_4_0_7/Base/test/MockServer.hpp
deleted file mode 100644
index 3c34436..0000000
--- a/ecflow_4_0_7/Base/test/MockServer.hpp
+++ /dev/null
@@ -1,98 +0,0 @@
-#ifndef MOCK_SERVER_HPP_
-#define MOCK_SERVER_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #26 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <assert.h>
-#include "Defs.hpp"
-#include "SuiteChanged.hpp"
-#include "AbstractServer.hpp"
-#include "JobsParam.hpp"
-#include "Jobs.hpp"
-#include "Log.hpp"
-#include "Ecf.hpp" // In server we increment modify and state change numbers,
-
-/// Act as stand in for a server since Request require at least a AbstractServer
-class MockServer : public AbstractServer {
-public:
- // For the MockServer don't delete the Defs. since we past in a fixture defs
- struct null_deleter {
- void operator()(void const *) const{}
- };
-
- // Only in server side do we increment state/modify numbers, controlled by: Ecf::set_server(true)
- MockServer(Defs* defs) : defs_(defs_ptr(defs,MockServer::null_deleter())) { Ecf::set_server(true); }
- MockServer(defs_ptr defs) : defs_(defs) { Ecf::set_server(true); }
- ~MockServer() { Ecf::set_server(false); }
-
- virtual SState::State state() const { return SState::RUNNING;}
- virtual std::pair<std::string,std::string> hostPort() const { assert(defs_.get()); return defs_->server().hostPort(); }
- virtual defs_ptr defs() const { return defs_;}
- virtual void updateDefs(defs_ptr d, bool force) { assert(defs_.get()); defs_->absorb(d.get(),force); }
- virtual void clear_defs() { if (defs_.get()) defs_->clear(); } // dont delete since we pass in Fixture defs. Otherwise it will crash
- virtual void checkPtDefs(ecf::CheckPt::Mode m = ecf::CheckPt::UNDEFINED,
- int check_pt_interval = 0,
- int check_pt_save_time_alarm = 0) {}
- virtual void restore_defs_from_checkpt() {}
- virtual void nodeTreeStateChanged() {}
- virtual bool allowTaskCommunication() const { return true;}
- virtual void shutdown() {}
- virtual void halted() {}
- virtual void restart() {}
- virtual bool reloadWhiteListFile(std::string&) { return true;}
- virtual bool authenticateUser(const std::string& ) { return true;}
- virtual bool authenticateWriteAccess(const std::string& , bool ) { return true;}
- virtual bool lock(const std::string& user) {
- if (userWhoHasLock_.empty()) {
- userWhoHasLock_ = user;
- shutdown();
- return true;
- }
- return false;
- }
- virtual void unlock() { userWhoHasLock_.clear(); restart(); }
- virtual const std::string& lockedUser() const { return userWhoHasLock_;}
- virtual void traverse_node_tree_and_job_generate(const boost::posix_time::ptime& time_now,bool user_cmd_context) const {
- if (state() == SState::RUNNING && defs_.get()) {
- JobsParam jobsParam(poll_interval(), false /* as->allow_job_creation_during_tree_walk() */ );
- Jobs jobs(defs_);
- if (!jobs.generate(jobsParam)) ecf::log(ecf::Log::ERR,jobsParam.getErrorMsg()); // will automatically add end of line
- }
- }
- virtual int poll_interval() const { return 60; }
- virtual void debug_server_on(){}
- virtual void debug_server_off(){}
- virtual bool debug() const { return true; }
-
-private:
- defs_ptr defs_;
- std::string userWhoHasLock_;
-};
-
-/// This class is used to create a Mock Server, so that we can make direct
-/// data model changes without using commands.
-/// In particular it will:
-/// o Ecf::set_server(true): This controls incrementing of state/modify change numbers
-/// which should *only* be done on the server side
-/// o Update Suite state/modify change number
-class MockSuiteChangedServer : private boost::noncopyable {
-public:
- MockSuiteChangedServer(suite_ptr suite) : suiteChanged_(suite) { Ecf::set_server(true);}
- ~MockSuiteChangedServer() { Ecf::set_server(false); }
-private:
- ecf::SuiteChanged suiteChanged_;
-};
-#endif
-
diff --git a/ecflow_4_0_7/Base/test/TestAlterCmd.cpp b/ecflow_4_0_7/Base/test/TestAlterCmd.cpp
deleted file mode 100644
index 240bcee..0000000
--- a/ecflow_4_0_7/Base/test/TestAlterCmd.cpp
+++ /dev/null
@@ -1,780 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #48 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <boost/test/unit_test.hpp>
-
-#include "ClientToServerCmd.hpp"
-#include "ServerToClientCmd.hpp"
-#include "MyDefsFixture.hpp"
-#include "TestHelper.hpp"
-#include "Str.hpp"
-#include "System.hpp"
-
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( BaseTestSuite )
-
-class TestStateChanged {
-public:
- TestStateChanged(suite_ptr s)
- : suite_(s),
- initial_suite_state_change_no_(s->state_change_no()),
- initial_suite_modify_change_no_(s->modify_change_no()) { Ecf::set_server(true);}
-
- ~TestStateChanged() {
- Ecf::set_server(false);
- BOOST_CHECK_MESSAGE(suite_->state_change_no() != initial_suite_state_change_no_ ||
- suite_->modify_change_no() != initial_suite_modify_change_no_,
- "Suite " << suite_->name() << " has no change in attributes. Forget to increment change no?"
- << " suite_->state_change_no(" << suite_->state_change_no()<< ")-"
- << "-initial_suite_state_change_no_(" << initial_suite_state_change_no_ << ") "
- << " suite_->modify_change_no(" << suite_->modify_change_no() << ")-"
- << "-initial_suite_modify_change_no_(" << initial_suite_modify_change_no_ << ")"
- );
- }
-private:
- suite_ptr suite_;
- unsigned int initial_suite_state_change_no_;
- unsigned int initial_suite_modify_change_no_;
-};
-
-
-class TestDefsStateChanged {
-public:
- TestDefsStateChanged(Defs* s)
- : defs_(s),
- initial_state_change_no_(s->defs_only_max_state_change_no()) {}
-
- ~TestDefsStateChanged() {
- Ecf::set_server(false);
- BOOST_CHECK_MESSAGE(defs_->defs_only_max_state_change_no() != initial_state_change_no_,
- "Defs has no change in attributes. Forget to increment change no?"
- );
- }
-private:
- Defs* defs_;
- unsigned int initial_state_change_no_;
-};
-
-
-BOOST_AUTO_TEST_CASE( test_alter_cmd_for_clock_type_hybrid )
-{
- cout << "Base:: ...test_alter_cmd_for_clock_type_hybrid\n";
-
- // In this test the suite has NO Clock attribute. It should get added automatically
- // when a new clock is added, we should sync with the computer clock
- Defs defs;
- suite_ptr s = Suite::create("suite");
- defs.addSuite( s );
-
- BOOST_CHECK_MESSAGE( !s->clockAttr(), "Expected no clock");
- std::string error_msg;
- BOOST_CHECK_MESSAGE(defs.checkInvariants(error_msg),"checkInvariants failed " << error_msg);
-
- { // Change clock type =====================================================================================================
- defs.beginAll();
- TestStateChanged changed(s);
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::CLOCK_TYPE,"hybrid","")));
- clock_ptr v = s->clockAttr();
- BOOST_CHECK_MESSAGE( v && v->hybrid() , "expected clock to be added and be hybrid");
-
- // Altering the suite clock attributes, should force suite calendar to align to todays date and time
- boost::posix_time::ptime date_now = Calendar::second_clock_time();
- int day_of_month = date_now.date().day();
- int month = date_now.date().month();
- int year = date_now.date().year();
- BOOST_CHECK_MESSAGE( s->calendar().day_of_month() == day_of_month, "Calendar should be updated after re-queue/begin. Expected " << day_of_month << " but found " << s->calendar().day_of_month());
- BOOST_CHECK_MESSAGE( s->calendar().month() == month, "Calendar should be updated after re-queue/begin. Expected " << month << " but found " << s->calendar().month());
- BOOST_CHECK_MESSAGE( s->calendar().year() == year, "Calendar should be updated after re-queued/begin");
- BOOST_CHECK_MESSAGE(defs.checkInvariants(error_msg),"checkInvariants failed " << error_msg);
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_alter_cmd_for_clock_type_real )
-{
- cout << "Base:: ...test_alter_cmd_for_clock_type_real\n";
-
- // In this test the suite has NO Clock attribute. It should get added automatically
- // when a new clock is added, we should sync with the computer clock
- Defs defs;
- suite_ptr s = defs.add_suite("suite");
-
- BOOST_CHECK_MESSAGE( !s->clockAttr(), "Expected no clock");
- std::string error_msg; BOOST_CHECK_MESSAGE(defs.checkInvariants(error_msg),"checkInvariants failed " << error_msg);
-
- { // Change clock type =====================================================================================================
- defs.beginAll();
- TestStateChanged changed(s);
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::CLOCK_TYPE,"real","")));
- clock_ptr v = s->clockAttr();
- BOOST_CHECK_MESSAGE( v && !v->hybrid() , "expected clock to be added and be real");
-
- // Altering the suite clock attributes, should force suite calendar to align to todays date and time
- boost::posix_time::ptime date_now = Calendar::second_clock_time();
- int day_of_month = date_now.date().day();
- int month = date_now.date().month();
- int year = date_now.date().year();
- BOOST_CHECK_MESSAGE( s->calendar().day_of_month() == day_of_month, "Calendar should be updated after re-queue/begin. Expected " << day_of_month << " but found " << s->calendar().day_of_month());
- BOOST_CHECK_MESSAGE( s->calendar().month() == month, "Calendar should be updated after re-queue/begin. Expected " << month << " but found " << s->calendar().month());
- BOOST_CHECK_MESSAGE( s->calendar().year() == year, "Calendar should be updated after re-queued/begin");
- BOOST_CHECK_MESSAGE(defs.checkInvariants(error_msg),"checkInvariants failed " << error_msg);
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_alter_cmd_for_clock_sync )
-{
- cout << "Base:: ...test_alter_cmd_for_clock_sync\n";
-
- // Add a suite with a hybrid clock set to the past, on switch to real time, should have todays date
- // Since the clock exists on the suite, with another date, we must explicitly sync with computer
- // alternatively user can change clock date and clock gain to align with computer
- Defs defs;
- suite_ptr s = defs.add_suite("suite");
- ClockAttr clockAttr(true); // add hybrid clock
- clockAttr.date(1,1,2009);
- s->addClock( clockAttr );
-
- BOOST_REQUIRE_MESSAGE( s->clockAttr(), "Expected clock");
- BOOST_REQUIRE_MESSAGE( s->clockAttr()->hybrid(), "Expected hybrid clock");
- std::string error_msg; BOOST_CHECK_MESSAGE(defs.checkInvariants(error_msg),"checkInvariants failed " << error_msg);
-
- { // Change clock type =====================================================================================================
- defs.beginAll();
- TestStateChanged changed(s);
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::CLOCK_TYPE,"real","")));
- clock_ptr v = s->clockAttr();
- BOOST_CHECK_MESSAGE( v && !v->hybrid() , "expected clock to be added and be real");
-
- // When we reque, the date should be unchanged
- TestHelper::invokeRequest(&defs,Cmd_ptr( new RequeueNodeCmd("/" + s->name())));
- BOOST_CHECK_MESSAGE( s->calendar().day_of_month() == 1, "Calendar should be updated after re-queue/begin. Expected day of month " << 1 << " but found " << s->calendar().day_of_month());
- BOOST_CHECK_MESSAGE( s->calendar().month() == 1, "Calendar should be updated after re-queue/begin. Expected month " << 1 << " but found " << s->calendar().month());
- BOOST_CHECK_MESSAGE( s->calendar().year() == 2009, "Calendar should be updated after re-queued/begin, Expected year " << 2009 << " but found " << s->calendar().year());
- BOOST_CHECK_MESSAGE(defs.checkInvariants(error_msg),"checkInvariants failed " << error_msg);
-
- // After a clk sync, data should match computer
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::CLOCK_SYNC,"","")));
-
- boost::posix_time::ptime date_now = Calendar::second_clock_time();
- int day_of_month = date_now.date().day();
- int month = date_now.date().month();
- int year = date_now.date().year();
- BOOST_CHECK_MESSAGE( s->calendar().day_of_month() == day_of_month, "Calendar should be updated after re-queue/begin. Expected " << day_of_month << " but found " << s->calendar().day_of_month());
- BOOST_CHECK_MESSAGE( s->calendar().month() == month, "Calendar should be updated after re-queue/begin. Expected " << month << " but found " << s->calendar().month());
- BOOST_CHECK_MESSAGE( s->calendar().year() == year, "Calendar should be updated after re-queued/begin");
- BOOST_CHECK_MESSAGE(defs.checkInvariants(error_msg),"checkInvariants failed " << error_msg);
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_alter_cmd_for_clock_date )
-{
- cout << "Base:: ...test_alter_cmd_for_clock_date\n";
-
- // In this test the suite has NO Clock attribute. It should get added automatically
- Defs defs;
- suite_ptr s = defs.add_suite("suite");
- BOOST_CHECK_MESSAGE( !s->clockAttr(), "Expected no clock");
- std::string error_msg; BOOST_CHECK_MESSAGE(defs.checkInvariants(error_msg),"checkInvariants failed " << error_msg);
-
- // Change clock date =====================================================================================================
- TestStateChanged changed(s);
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::CLOCK_DATE,"12.12.2012","")));
- clock_ptr v = s->clockAttr();
- BOOST_CHECK_MESSAGE( v.get(), "expected clock to be added");
-
- // Check that calendar is updated by the Alter
- {
- BOOST_CHECK_MESSAGE( s->calendar().day_of_month() == 12, "Calendar should be updated");
- BOOST_CHECK_MESSAGE( s->calendar().month() == 12, "Calendar should be updated");
- BOOST_CHECK_MESSAGE( s->calendar().year() == 2012, "Calendar should be updated");
-
- defs.beginAll();
- TestHelper::invokeRequest(&defs,Cmd_ptr( new RequeueNodeCmd(s->absNodePath())));
- BOOST_CHECK_MESSAGE( s->calendar().day_of_month() == 12, "Calendar should be updated after re-queued");
- BOOST_CHECK_MESSAGE( s->calendar().month() == 12, "Calendar should be updated after re-queued");
- BOOST_CHECK_MESSAGE( s->calendar().year() == 2012, "Calendar should be updated after re-queued");
-
- // Now re sync with the computers clock, the suite calendar should align to todays date and time
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::CLOCK_SYNC,"","")));
-
- boost::posix_time::ptime date_now = Calendar::second_clock_time();
- int day_of_month = date_now.date().day();
- int month = date_now.date().month();
- int year = date_now.date().year();
- BOOST_CHECK_MESSAGE( s->calendar().day_of_month() == day_of_month, "Calendar should be updated after re-queue/begin. Expected " << day_of_month << " but found " << s->calendar().day_of_month());
- BOOST_CHECK_MESSAGE( s->calendar().month() == month, "Calendar should be updated after re-queue/begin. Expected " << month << " but found " << s->calendar().month());
- BOOST_CHECK_MESSAGE( s->calendar().year() == year, "Calendar should be updated after re-queued/begin");
- BOOST_CHECK_MESSAGE(defs.checkInvariants(error_msg),"checkInvariants failed " << error_msg);
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_alter_cmd_for_clock_gain )
-{
- cout << "Base:: ...test_alter_cmd_for_clock_gain\n";
-
- // In this test the suite has NO Clock attribute. It should get added automatically
- Defs defs;
- std::string suitename = "suite";
- suite_ptr s = defs.add_suite(suitename);
- BOOST_CHECK_MESSAGE( !s->clockAttr(), "Expected no clock");
- std::string error_msg; BOOST_CHECK_MESSAGE(defs.checkInvariants(error_msg),"checkInvariants failed " << error_msg);
-
- { // Change clock gain =====================================================================================================
- TestStateChanged changed(s);
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(suitename,AlterCmd::CLOCK_GAIN,"86400",""))); // add 24 hours in seconds
- clock_ptr v = s->clockAttr();
- BOOST_CHECK_MESSAGE( v.get(), "expected clock to be added");
- BOOST_CHECK_MESSAGE( v && v->gain() == 86400 , "expected clock gain to be 86400 but found " << v->gain());
-
- // Check that calendar is updated by the alter
- {
- // add one day, to current date, to simulate a gain of 24 hours
- boost::posix_time::ptime date_now = Calendar::second_clock_time();
- boost::gregorian::date newDate = date_now.date();
- boost::gregorian::date_duration one_day(1);
- newDate += one_day;
- int day_of_month = newDate.day();
- int month = newDate.month();
- int year = newDate.year();
- BOOST_CHECK_MESSAGE( s->calendar().day_of_month() == day_of_month, "Calendar should be updated after alter. Expected " << day_of_month << " but found " << s->calendar().day_of_month());
- BOOST_CHECK_MESSAGE( s->calendar().month() == month, "Calendar should be updated after alter. Expected " << month << " but found " << s->calendar().month());
- BOOST_CHECK_MESSAGE( s->calendar().year() == year, "Calendar should be updated after alter");
-
- // This should init calendar with todays date + 86400 seconds. i.e +1 day.
- defs.beginAll();
- TestHelper::invokeRequest(&defs,Cmd_ptr( new RequeueNodeCmd("/" + suitename)));
- BOOST_CHECK_MESSAGE( s->calendar().day_of_month() == day_of_month, "Calendar should be updated after re-queue/begin. Expected " << day_of_month << " but found " << s->calendar().day_of_month());
- BOOST_CHECK_MESSAGE( s->calendar().month() == month, "Calendar should be updated after re-queue/begin. Expected " << month << " but found " << s->calendar().month());
- BOOST_CHECK_MESSAGE( s->calendar().year() == year, "Calendar should be updated after re-queued/begin");
-
- // Now re sync with the computers clock,When we reque, the suite calendar should align to todays date and time
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::CLOCK_SYNC,"","")));
- day_of_month = date_now.date().day();
- month = date_now.date().month();
- year = date_now.date().year();
- BOOST_CHECK_MESSAGE( s->calendar().day_of_month() == day_of_month, "Calendar should be updated after re-queue/begin. Expected " << day_of_month << " but found " << s->calendar().day_of_month());
- BOOST_CHECK_MESSAGE( s->calendar().month() == month, "Calendar should be updated after re-queue/begin. Expected " << month << " but found " << s->calendar().month());
- BOOST_CHECK_MESSAGE( s->calendar().year() == year, "Calendar should be updated after re-queued/begin");
- BOOST_CHECK_MESSAGE(defs.checkInvariants(error_msg),"checkInvariants failed " << error_msg);
- }
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_alter_cmd )
-{
- cout << "Base:: ...test_alter_cmd\n";
-
- Defs defs;
- suite_ptr s = defs.add_suite("suite");
- task_ptr task = s->add_task("t1");
- {
- ClockAttr clockAttr(false); // real clock
- clockAttr.date(1,1,2009);
- clockAttr.set_gain_in_seconds(3600);
- clockAttr.startStopWithServer(true);
- s->addClock( clockAttr );
- s->addDefStatus(DState::SUSPENDED); // avoid AlterCmd from job submission
- }
-
- std::string error_msg; BOOST_CHECK_MESSAGE(defs.checkInvariants(error_msg),"checkInvariants failed " << error_msg);
-
- { // Change server state. This will cause Flag::MESSAGE to be set on the defs
- TestDefsStateChanged chenged(&defs);
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd("/",AlterCmd::ADD_VARIABLE,"_fred_","value")));
- BOOST_CHECK_MESSAGE( defs.server().find_variable("_fred_") == "value" , "expected to find value");
-
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd("/",AlterCmd::VARIABLE,"_fred_","_value_")));
- BOOST_CHECK_MESSAGE( defs.server().find_variable("_fred_") == "_value_" , "expected to find _value_");
-
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd("/",AlterCmd::DEL_VARIABLE,"_fred_")));
- BOOST_CHECK_MESSAGE( defs.server().find_variable("_fred_") == "" , "expected to find empty string");
-
- BOOST_CHECK_MESSAGE( defs.get_edit_history("/").size() == 3,
- "expected edit_history of 3 to be added but found " << defs.get_edit_history("/").size());
-
- {
- // test set and clear flags of the definition
- // Note: we can not really test Flag::Message clear, since that act of clearing, sets the message
- std::vector<Flag::Type> flag_list = Flag::list();
- for(size_t i =0; i < flag_list.size(); ++i) {
- // When any user command(including setting flags) invoked, we set Flag::MESSAGE on the defs.
- // Hence setting flag Flag::MESSAGE has no effect. Likewise clearing has no affect since it get set
- if ( flag_list[i] == Flag::MESSAGE) continue;
-
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd("/",flag_list[i],true)));
- BOOST_CHECK_MESSAGE( defs.flag().is_set(flag_list[i]), "Expected flag " << flag_list[i] << " to be set ");
-
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd("/",flag_list[i],false)));
- BOOST_CHECK_MESSAGE( ! defs.flag().is_set(flag_list[i]), "Expected flag " << flag_list[i] << " to be clear ");
- }
- }
- }
-
- { // Change clock type =====================================================================================================
- defs.beginAll();
- BOOST_CHECK_MESSAGE( s->calendar().hybrid() == false, "expected calendar to be real after begin");
- BOOST_CHECK_MESSAGE( s->calendar().hybrid() == s->clockAttr()->hybrid(), "Calendar and Clock attribute must be in sync after begin");
-
- TestStateChanged changed(s);
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::CLOCK_TYPE,"hybrid","")));
- clock_ptr v = s->clockAttr();
- BOOST_CHECK_MESSAGE( v && v->hybrid() , "expected clock to be hybrid");
- BOOST_CHECK_MESSAGE( defs.get_edit_history(s->absNodePath()).size() == 1,
- "expected edit_history of 1 to be added but found " << defs.get_edit_history(s->absNodePath()).size());
-
- // Check that calendar is in sync with clock attribute after the alter
- {
- BOOST_CHECK_MESSAGE( s->calendar().hybrid() == s->clockAttr()->hybrid(), "Calendar and Clock attribute must be in sync after alter");
- BOOST_CHECK_MESSAGE( s->calendar().hybrid() == true, "expected calendar to be re-initialised to be hybrid after alter");
- }
-
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::CLOCK_TYPE,"real","")));
- BOOST_CHECK_MESSAGE( v && !v->hybrid() , "expected clock to be real");
- BOOST_CHECK_MESSAGE( defs.get_edit_history(s->absNodePath()).size() == 2,
- "expected edit_history of 2 to be added but found " << defs.get_edit_history(s->absNodePath()).size());
-
- // Check that calendar is in sync with clock attribute after the alter
- {
- BOOST_CHECK_MESSAGE( s->calendar().hybrid() == s->clockAttr()->hybrid(), "Calendar and Clock attribute must be in sync after alter");
- BOOST_CHECK_MESSAGE( s->calendar().hybrid() == false, "expected calendar to be re-initialised to be real after alter");
- }
- }
-
- { // Change clock date =====================================================================================================
- TestStateChanged changed(s);
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::CLOCK_DATE,"12.12.2012","")));
- clock_ptr v = s->clockAttr();
- BOOST_CHECK_MESSAGE( (v->day() == 12 && v->month() == 12 && v->year() == 2012) , "expected clock date to be 12.12.2012 but found " << v->toString());
- BOOST_CHECK_MESSAGE( defs.get_edit_history(s->absNodePath()).size() == 3,
- "expected edit_history of 3 to be added but found " << defs.get_edit_history(s->absNodePath()).size());
-
- // Check that calendar is updated after alter
- {
- BOOST_CHECK_MESSAGE( s->calendar().day_of_month() == 12, "Calendar should be updated after re-queued");
- BOOST_CHECK_MESSAGE( s->calendar().month() == 12, "Calendar should be updated after re-queued");
- BOOST_CHECK_MESSAGE( s->calendar().year() == 2012, "Calendar should be updated after re-queued");
- }
- }
-
- { // Change clock gain =====================================================================================================
- TestStateChanged changed(s);
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::CLOCK_GAIN,"86400",""))); // add 24 hours in seconds
- clock_ptr v = s->clockAttr();
- BOOST_CHECK_MESSAGE( v && v->gain() == 86400 , "expected clock gain to be 3333 but found " << v->gain());
- BOOST_CHECK_MESSAGE( defs.get_edit_history(s->absNodePath()).size() == 4,
- "expected edit_history of 4 to be added but found " << defs.get_edit_history(s->absNodePath()).size());
-
- // Check that calendar is updated after the alter
- {
- BOOST_CHECK_MESSAGE( s->calendar().day_of_month() == 13, "Calendar should be updated after re-queued");
- BOOST_CHECK_MESSAGE( s->calendar().month() == 12, "Calendar should be updated after re-queued");
- BOOST_CHECK_MESSAGE( s->calendar().year() == 2012, "Calendar should be updated after re-queued");
- }
- }
-
- // test add, the deleting of a specific attribute
- {
- TestStateChanged changed(s);
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_DATE,"12.12.2010")));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_DAY,"sunday")));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_TIME,"23:00")));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_TODAY,"23:00")));
- BOOST_CHECK_MESSAGE( task->dates().size() == 1, "expected 1 date to be added but found " << s->dates().size());
- BOOST_CHECK_MESSAGE( task->days().size() == 1, "expected 1 day to be added but found " << s->days().size());
- BOOST_CHECK_MESSAGE( task->timeVec().size() == 1, "expected 1 time to be added but found " << s->timeVec().size());
- BOOST_CHECK_MESSAGE( task->todayVec().size() == 1, "expected 1 today attr, to be added but found " << s->todayVec().size());
- BOOST_CHECK_MESSAGE( defs.get_edit_history(task->absNodePath()).size() == 4, "expected edit_history of 4 to be added but found " << defs.get_edit_history(task->absNodePath()).size());
- }
- {
- TestStateChanged changed(s);
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::DEL_DATE,"12.12.2010")));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::DEL_DAY,"sunday")));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::DEL_TIME,"23:00")));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::DEL_TODAY,"23:00")));
- BOOST_CHECK_MESSAGE( task->dates().size() == 0, "expected 0 dates, but found " << s->dates().size());
- BOOST_CHECK_MESSAGE( task->days().size() == 0, "expected 0 day but found " << s->days().size());
- BOOST_CHECK_MESSAGE( task->timeVec().size() == 0, "expected 0 time but found " << s->timeVec().size());
- BOOST_CHECK_MESSAGE( task->todayVec().size() == 0, "expected 0 today but found " << s->todayVec().size());
- BOOST_CHECK_MESSAGE( defs.get_edit_history(task->absNodePath()).size() == 8, "expected edit_history of 8 to be added but found " << defs.get_edit_history(task->absNodePath()).size());
- }
-
- { // test delete all
- TestStateChanged changed(s);
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_DATE,"12.12.2010")));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_DATE,"12.*.2010")));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_DATE,"8.*.2010")));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_DAY,"sunday")));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_DAY,"monday")));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_DAY,"tuesday")));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_TIME,"09:00")));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_TIME,"22:00")));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_TIME,"23:00")));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_TODAY,"02:00")));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_TODAY,"03:00")));
- BOOST_CHECK_MESSAGE( defs.get_edit_history(task->absNodePath()).size() == 19, "expected edit_history of 19 to be added but found " << defs.get_edit_history(task->absNodePath()).size());
-
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::DEL_DATE)));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::DEL_DAY)));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::DEL_TIME)));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::DEL_TODAY)));
- BOOST_CHECK_MESSAGE( task->dates().size() == 0, "expected 0 dates, but found " << s->dates().size());
- BOOST_CHECK_MESSAGE( task->days().size() == 0, "expected 0 day but found " << s->days().size());
- BOOST_CHECK_MESSAGE( task->timeVec().size() == 0, "expected 0 time but found " << s->timeVec().size());
- BOOST_CHECK_MESSAGE( task->todayVec().size() == 0, "expected 0 today but found " << s->todayVec().size());
-
- /// Edit history should be truncated to max of 20
- BOOST_CHECK_MESSAGE( defs.get_edit_history(task->absNodePath()).size() == 20, "expected edit_history to be truncated to 20, but found " << defs.get_edit_history(task->absNodePath()).size());
- }
-
- { // test add variables
- TestStateChanged changed(s);
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::ADD_VARIABLE,"FRED1","_val_")));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::ADD_VARIABLE,"FRED2","_val_")));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::ADD_VARIABLE,"FRED3","_val_")));
- BOOST_CHECK_MESSAGE( s->variables().size() == 3, "expected 3 variable but found " << s->variables().size());
-
- // test delete variables
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_VARIABLE,"FRED1")));
- BOOST_CHECK_MESSAGE( s->variables().size() == 2, "expected 2 variable but found " << s->variables().size());
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_VARIABLE)));
- BOOST_CHECK_MESSAGE( s->variables().size() == 0, "expected 0 variable but found " << s->variables().size());
-
- // test change variable
- s->add_variable("FRED1","BILL");
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::VARIABLE,"FRED1","BILL1")));
- const Variable& v = s->findVariable("FRED1");
- BOOST_CHECK_MESSAGE( !v.empty() && v.theValue() == "BILL1", "expected to find variable FRED1, with value BILL1");
- }
-
- { // test add event
- TestStateChanged changed(s);
- s->addEvent( Event(1,"event1") );
- s->addEvent( Event(2,"event2") );
- s->addEvent( Event(3,"event3") );
- BOOST_CHECK_MESSAGE( s->events().size() == 3, "expected 3 but found " << s->events().size());
-
- // test delete event
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_EVENT,"event1")));
- BOOST_CHECK_MESSAGE( s->events().size() == 2, "expected 2 but found " << s->events().size());
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_EVENT)));
- BOOST_CHECK_MESSAGE( s->events().size() == 0, "expected 0 but found " << s->events().size());
-
- // test change event
- s->addEvent( Event(1,"event1") );
- s->addEvent( Event(2,"event2") );
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::EVENT,"event1",Event::SET())));
- {const Event& v = s->findEventByNameOrNumber("event1");
- BOOST_CHECK_MESSAGE( v.value() == 1, "expected to find event with value set");}
-
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::EVENT,"event1",Event::CLEAR())));
- {const Event& v = s->findEventByNameOrNumber("event1");
- BOOST_CHECK_MESSAGE( !v.empty() && v.value() == 0, "expected to find event with value cleared");}
-
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::EVENT,"event1","")));
- {const Event& v = s->findEventByNameOrNumber("event1");
- BOOST_CHECK_MESSAGE( v.value() == 1, "expected to find event with value set");}
- }
-
- { // test add meter
- TestStateChanged changed(s);
- s->addMeter( Meter("meter",0,100,100) );
- s->addMeter( Meter("meter1",0,100,100) );
- s->addMeter( Meter("meter2",0,100,100) );
- BOOST_CHECK_MESSAGE( s->meters().size() == 3, "expected 3 but found " << s->meters().size());
-
- // test delete meter
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_METER,"meter")));
- BOOST_CHECK_MESSAGE( s->meters().size() == 2, "expected 2 but found " << s->meters().size());
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_METER)));
- BOOST_CHECK_MESSAGE( s->meters().size() == 0, "expected 0 but found " << s->meters().size());
-
- // test change meter value
- s->addMeter( Meter("meter",0,100,100) );
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::METER,"meter","10")));
- const Meter& v = s->findMeter("meter");
- BOOST_CHECK_MESSAGE( v.value() == 10, "expected to find meter with value 10");
- }
-
- { // test add label
- TestStateChanged changed(s);
- s->addLabel( Label("label","labelValue") );
- s->addLabel( Label("label1","\"labelValue\"") );
- s->addLabel( Label("label2","\"labelValue\"") );
- BOOST_CHECK_MESSAGE( s->labels().size() == 3, "expected 3 but found " << s->labels().size());
-
- // test delete label
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_LABEL,"label")));
- BOOST_CHECK_MESSAGE( s->labels().size() == 2, "expected 2 but found " << s->labels().size());
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_LABEL)));
- BOOST_CHECK_MESSAGE( s->labels().size() == 0, "expected 0 but found " << s->labels().size());
-
- // test change label value
- s->addLabel( Label("label","labelValue") );
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::LABEL,"label","--fred--")));
- std::string label_value;
- BOOST_CHECK_MESSAGE(s->getLabelValue("label",label_value ),"Expected to find label");
- BOOST_CHECK_MESSAGE( label_value == "--fred--", "expected to find label with value --fred--");
- }
-
- { // test add Trigger
- TestStateChanged changed(s);
- s->add_trigger( "t1 == complete");
- BOOST_CHECK_MESSAGE( s->get_trigger(), "expected trigger to be added");
-
- // test delete trigger
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_TRIGGER)));
- BOOST_CHECK_MESSAGE( !s->get_trigger(), "expected trigger to be deleted");
-
- // test change trigger expression
- s->add_trigger( "t1 == complete" );
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::TRIGGER,"x == complete","")));
- BOOST_CHECK_MESSAGE( s->triggerExpression() == "trigger x == complete", "expected trigger to be changed found " << s->triggerExpression());
- }
-
- { // test add complete expression
- TestStateChanged changed(s);
- s->add_complete( "t1 == complete" );
- BOOST_CHECK_MESSAGE( s->get_complete(), "expected complete to be added");
-
- // test delete complete
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_COMPLETE)));
- BOOST_CHECK_MESSAGE( !s->get_complete(), "expected complete to be deleted");
-
- // test change complete expression
- s->add_complete( "t1 == complete" );
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::COMPLETE,"x == complete","")));
- BOOST_CHECK_MESSAGE( s->completeExpression() == "complete x == complete", "expected complete expression to be changed found " << s->completeExpression() );
- }
-
- { // test add limit
- TestStateChanged changed(s);
- s->addLimit( Limit("limit",10) );
- s->addLimit( Limit("limit1",10) );
- s->addLimit( Limit("limit2",10) );
- BOOST_CHECK_MESSAGE( s->limits().size() == 3, "expected 3 but found " << s->limits().size());
-
- // test delete limit
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_LIMIT,"limit2")));
- BOOST_CHECK_MESSAGE( s->limits().size() == 2, "expected 2 but found " << s->limits().size());
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_LIMIT)));
- BOOST_CHECK_MESSAGE( s->limits().size() == 0, "expected 0 but found " << s->limits().size());
-
- // test change limit max value
- s->addLimit( Limit("limit",10) );
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::LIMIT_MAX,"limit","90")));
- limit_ptr v = s->find_limit("limit");
- BOOST_CHECK_MESSAGE( v.get() && v->theLimit() == 90, "expected to find limit with max value of 90");
-
- // test change limit value
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::LIMIT_VAL,"limit","33")));
- BOOST_CHECK_MESSAGE( v.get() && v->value() == 33, "expected to find limit with value of 33");
-
- // Test delete limit path
- std::set<std::string> paths; paths.insert("made_up_path");
- Limit limit_path("limit_name",10);
- limit_path.set_paths(paths);
-
- s->addLimit( limit_path );
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_LIMIT_PATH,"limit_name","made_up_path")));
- limit_ptr lm = s->find_limit("limit_name");
- BOOST_CHECK_MESSAGE( lm.get() && lm->paths().empty(), "Expected no paths but found " << lm->paths().size());
- }
-
- { // test add repeat
- TestStateChanged changed(s);
- s->addRepeat( RepeatDate("YMD",20090916,20090930,1));
- BOOST_CHECK_MESSAGE( !s->repeat().empty(), "expected repeat to be added");
-
- // test delete repeat
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_REPEAT)));
- BOOST_CHECK_MESSAGE( s->repeat().empty(), "expected repeat to be deleted");
-
- // test change repeat value
- s->addRepeat( RepeatDate("YMD",20090916,20090930,1));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::REPEAT,"20090917","")));
- BOOST_CHECK_MESSAGE( s->repeat().valueAsString() == "20090917", "expected 20090917 but found " << s->repeat().valueAsString());
- }
- {
- TestStateChanged changed(s);
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_REPEAT))); // delete previous repeat
-
- std::vector<std::string> stringList; stringList.reserve(3);
- stringList.push_back("a");
- stringList.push_back("b");
- stringList.push_back("c");
-
- s->addRepeat( RepeatEnumerated("AEnum",stringList));
- BOOST_CHECK_MESSAGE( !s->repeat().empty(), "expected repeat to be added");
-
- // test delete repeat
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_REPEAT)));
- BOOST_CHECK_MESSAGE( s->repeat().empty(), "expected repeat to be deleted");
-
- // test change repeat value
- s->addRepeat( RepeatEnumerated("AEnum",stringList));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::REPEAT,"1","")));
- BOOST_CHECK_MESSAGE( s->repeat().valueAsString() == "b", "expected 'b' but found " << s->repeat().valueAsString());
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::REPEAT,"c","")));
- BOOST_CHECK_MESSAGE( s->repeat().valueAsString() == "c", "expected 'c' but found " << s->repeat().valueAsString());
- }
- {
- TestStateChanged changed(s);
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_REPEAT))); // delete previous repeat
-
- std::vector<std::string> stringList; stringList.reserve(3);
- stringList.push_back("a");
- stringList.push_back("b");
- stringList.push_back("c");
-
- s->addRepeat( RepeatString("RepeatString",stringList));
- BOOST_CHECK_MESSAGE( !s->repeat().empty(), "expected repeat to be added");
-
- // test delete repeat
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_REPEAT)));
- BOOST_CHECK_MESSAGE( s->repeat().empty(), "expected repeat to be deleted");
-
- // test change repeat value
- s->addRepeat( RepeatString("RepeatString",stringList));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::REPEAT,"1","")));
- BOOST_CHECK_MESSAGE( s->repeat().valueAsString() == "b", "expected 'b' but found " << s->repeat().valueAsString());
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::REPEAT,"c","")));
- BOOST_CHECK_MESSAGE( s->repeat().valueAsString() == "c", "expected 'c' but found " << s->repeat().valueAsString());
- }
-
- {
- TestStateChanged changed(s);
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_REPEAT))); // delete previous repeat
-
- std::vector<std::string> stringList; stringList.reserve(3);
- stringList.push_back("a");
- stringList.push_back("b");
- stringList.push_back("c");
-
- s->addRepeat( RepeatInteger("rep",0,100,1));
- BOOST_CHECK_MESSAGE( !s->repeat().empty(), "expected repeat to be added");
-
- // test delete repeat
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_REPEAT)));
- BOOST_CHECK_MESSAGE( s->repeat().empty(), "expected repeat to be deleted");
-
- // test change repeat value
- s->addRepeat( RepeatInteger("rep",0,100,1));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::REPEAT,"22","")));
- BOOST_CHECK_MESSAGE( s->repeat().valueAsString() == "22", "expected '22' but found " << s->repeat().valueAsString());
- }
-
- { // add cron
- TestStateChanged changed(s);
- ecf::CronAttr cronAttr;
- ecf::TimeSlot start( 0, 0 );
- ecf::TimeSlot finish( 10, 0 );
- ecf::TimeSlot incr( 0, 5 );
- std::vector<int> weekdays; for(int i=0;i<7;++i) weekdays.push_back(i);
- std::vector<int> daysOfMonth;for(int i=1;i<32;++i) daysOfMonth.push_back(i);
- std::vector<int> months; for(int i=1;i<13;++i) months.push_back(i);
- cronAttr.addTimeSeries(start,finish,incr);
- cronAttr.addWeekDays( weekdays );
- cronAttr.addDaysOfMonth(daysOfMonth);
- cronAttr.addMonths( months );
- task->addCron( cronAttr );
-
- BOOST_CHECK_MESSAGE( task->crons().size() == 1, "expected cron to be added");
-
- // test delete cron
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::DEL_CRON)));
- BOOST_CHECK_MESSAGE( task->crons().size() == 0, "expected cron to be delete");
- }
-
- { // test suite changed
- TestStateChanged changed(s);
-
- // test add zombie
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::ADD_ZOMBIE,"user:fob:init:300")));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::ADD_ZOMBIE,"path:fob:init:300")));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::ADD_ZOMBIE,"ecf:fob:init:300")));
- BOOST_CHECK_MESSAGE( s->zombies().size() == 3, "expected 3 but found " << s->zombies().size());
-
- // test delete zombie
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_ZOMBIE,"ecf")));
- BOOST_CHECK_MESSAGE( s->zombies().size() == 2, "expected 2 but found " << s->zombies().size());
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_ZOMBIE,"path")));
- BOOST_CHECK_MESSAGE( s->zombies().size() == 1, "expected 1 but found " << s->zombies().size());
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEL_ZOMBIE,"user")));
- BOOST_CHECK_MESSAGE( s->zombies().size() == 0, "expected 0 but found " << s->zombies().size());
- }
-
- { // free password
- TestStateChanged changed(s);
- std::string returnedValue;
- BOOST_CHECK_MESSAGE( !task->findVariableValue(Str::ECF_PASS(),returnedValue), "Expected no variable of name ECF_PASS");
-
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(task->absNodePath(),AlterCmd::ADD_VARIABLE,Str::ECF_PASS(),Submittable::FREE_JOBS_PASSWORD())));
-
- BOOST_CHECK_MESSAGE( task->findVariableValue(Str::ECF_PASS(),returnedValue), "Expected to find variable ECF_PASS on the task");
- BOOST_CHECK_MESSAGE( returnedValue == Submittable::FREE_JOBS_PASSWORD(), "Expected variable value of name " << Submittable::FREE_JOBS_PASSWORD() << " but found " << returnedValue);
- }
-
- {
- // test set and clear flags
- // Note: we can not really test Flag::Message clear, since that act of clearing, sets the message
- std::vector<Flag::Type> flag_list = Flag::list();
- for(size_t i =0; i < flag_list.size(); ++i) {
- // When any user command(including setting flags) invoked, we set Flag::MESSAGE on the defs.
- // Hence setting flag Flag::MESSAGE has no effect. Likewise clearing has no affect since it get set
- if ( flag_list[i] == Flag::MESSAGE) continue;
-
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),flag_list[i],true)));
- BOOST_CHECK_MESSAGE( s->flag().is_set(flag_list[i]), "Expected flag " << flag_list[i] << " to be set ");
-
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),flag_list[i],false)));
- BOOST_CHECK_MESSAGE( ! s->flag().is_set(flag_list[i]), "Expected flag " << flag_list[i] << " to be clear ");
- }
- }
-
- BOOST_CHECK_MESSAGE( defs.get_edit_history(s->absNodePath()).size() == 20, "expected edit_history to be truncated to 20, but found " << defs.get_edit_history(s->absNodePath()).size());
-
- { // Change suite def status =====================================================================================================
- TestStateChanged changed(s);
- std::vector<std::string> dstates = DState::allStates();
- for(size_t i = 0; i < dstates.size(); i++) {
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEFSTATUS,dstates[i])));
- }
- // reset back to suspended
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::DEFSTATUS,"suspended")));
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_alter_cmd_errors )
-{
- cout << "Base:: ...test_alter_cmd_errors\n";
-
- Defs defs;
- suite_ptr s = defs.add_suite("suite");
- s->add_task("t1");
-
- { // test add variables
- TestStateChanged changed(s);
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::ADD_VARIABLE,"FRED1","_val_")));
- BOOST_CHECK_MESSAGE( s->variables().size() == 1, "expected 1 variable but found " << s->variables().size());
-
- // test delete variables, with a non existent path
- TestHelper::invokeFailureRequest(&defs,Cmd_ptr( new AlterCmd("/idont/exist",AlterCmd::DEL_VARIABLE,"FRED1")));
- }
-
- /// Destroy singleton's to avoid valgrind from complaining
- System::destroy();
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Base/test/TestClientHandleCmd.cpp b/ecflow_4_0_7/Base/test/TestClientHandleCmd.cpp
deleted file mode 100644
index b827a41..0000000
--- a/ecflow_4_0_7/Base/test/TestClientHandleCmd.cpp
+++ /dev/null
@@ -1,260 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #12 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <boost/test/unit_test.hpp>
-
-#include "ClientToServerCmd.hpp"
-#include "ServerToClientCmd.hpp"
-#include "TestHelper.hpp"
-#include "Suite.hpp"
-
-using namespace std;
-using namespace ecf;
-
-// The client handle commands do not change state & modify change number, hence need to bypass these checks
-static bool bypass_state_modify_change_check = false;
-
-BOOST_AUTO_TEST_SUITE( BaseTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_client_handle_cmd_empty_server )
-{
- cout << "Base:: ...test_client_handle_cmd_empty_server\n";
-
- std::vector<std::string> suite_names; suite_names.reserve(5);
- for(int i=0; i < 5; i++) suite_names.push_back( "s" + boost::lexical_cast<std::string>(i) );
-
- defs_ptr new_defs = Defs::create();
-
- // Register new handle on an EMPTY server. register the suite
- for(size_t j = 0; j < suite_names.size(); j++) {
- std::vector<std::string> names; names.push_back(suite_names[j]);
- TestHelper::invokeRequest(new_defs.get(),Cmd_ptr( new ClientHandleCmd(names,false)),bypass_state_modify_change_check);
- }
-
- // We should have 5 handle, 1,2,3,4,5
-
- //std::cout << " expect failure when dropping(DROP_USER) on handle that does not exist, handle 6" << endl;
- TestHelper::invokeFailureRequest(new_defs.get(),Cmd_ptr( new ClientHandleCmd(6)));
-
- //std::cout << " expect failure for auto add,on handle that does not exist, handle 6" << endl;
- TestHelper::invokeFailureRequest(new_defs.get(),Cmd_ptr( new ClientHandleCmd(6,true /* auto add */)));
-
- //std::cout << " expect failure for ADD,on handle that does not exist, handle 6" << endl;
- TestHelper::invokeFailureRequest(new_defs.get(),Cmd_ptr( new ClientHandleCmd(6,suite_names,ClientHandleCmd::ADD)));
-
- //std::cout << " expect failure for REMOVE, on handle that does not exist, handle 6" << endl;
- TestHelper::invokeFailureRequest(new_defs.get(),Cmd_ptr( new ClientHandleCmd(6,suite_names,ClientHandleCmd::REMOVE)));
-
- for(int handle=1; handle < 6; handle++) {
-
- //std::cout << " expect success for dropping handle " << handle << endl;
- TestHelper::invokeRequest(new_defs.get(),Cmd_ptr( new ClientHandleCmd(handle)),bypass_state_modify_change_check);
-
- //std::cout << " expect failure for auto add,on handle that does not exist, handle " << handle << endl;
- TestHelper::invokeFailureRequest(new_defs.get(),Cmd_ptr( new ClientHandleCmd(6,true /* auto add */)));
-
- //std::cout << " expect failure for ADD,on handle that does not exist, handle " << handle <<endl;
- TestHelper::invokeFailureRequest(new_defs.get(),Cmd_ptr( new ClientHandleCmd(6,suite_names,ClientHandleCmd::ADD)));
-
- //std::cout << " expect failure for REMOVE, on handle that does not exist, handle " << handle << "\n" << endl;
- TestHelper::invokeFailureRequest(new_defs.get(),Cmd_ptr( new ClientHandleCmd(6,suite_names,ClientHandleCmd::REMOVE)));
- }
-}
-
-
-BOOST_AUTO_TEST_CASE( test_client_handle_cmd_register_and_drop )
-{
- cout << "Base:: ...test_client_handle_cmd_register_and_drop\n";
-
- std::vector<std::string> suite_names; suite_names.reserve(6);
- for(int i=0; i < 5; i++) suite_names.push_back( "s" + boost::lexical_cast<std::string>(i) );
-
- Defs defs;
- for(size_t j = 0; j < suite_names.size(); j++) defs.addSuite( Suite::create(suite_names[j]) );
-
- // Register new handle
- for(size_t j = 0; j < suite_names.size(); j++) {
- std::vector<std::string> names; names.push_back(suite_names[j]);
- TestHelper::invokeRequest(&defs,Cmd_ptr( new ClientHandleCmd(names,false)),bypass_state_modify_change_check);
- BOOST_CHECK_MESSAGE(defs.client_suite_mgr().clientSuites().size() == j+1,"Expected " << j+1 << " Client suites but found " << defs.client_suite_mgr().clientSuites().size());
- }
-
- // Drop the handles. take a copy, since we about to delete clientSuites
- std::vector<ecf::ClientSuites> clientSuites = defs.client_suite_mgr().clientSuites();
- for(size_t k =0; k< clientSuites.size(); k++) {
- TestHelper::invokeRequest(&defs,Cmd_ptr( new ClientHandleCmd( clientSuites[k].handle() )),bypass_state_modify_change_check);
- }
- BOOST_CHECK_MESSAGE(defs.client_suite_mgr().clientSuites().empty(),"Expected no client handles, but found " << defs.client_suite_mgr().clientSuites().size());
-}
-
-
-BOOST_AUTO_TEST_CASE( test_client_handle_cmd_auto_add )
-{
- cout << "Base:: ...test_client_handle_cmd_auto_add\n";
-
- std::vector<std::string> suite_names; suite_names.reserve(6);
- for(int i=0; i < 5; i++) suite_names.push_back( "s" + boost::lexical_cast<std::string>(i) );
-
- Defs defs;
- for(size_t j = 0; j < suite_names.size(); j++) defs.addSuite( Suite::create(suite_names[j]) );
-
- // Register new handle, with no suites, but with auto add new suites
- std::vector<std::string> names;
- TestHelper::invokeRequest(&defs,Cmd_ptr( new ClientHandleCmd(names,false/* auto_add */)),bypass_state_modify_change_check);
- BOOST_CHECK_MESSAGE(defs.client_suite_mgr().clientSuites().size() == 1,"Expected 1 Client suites but found " << defs.client_suite_mgr().clientSuites().size());
- BOOST_CHECK_MESSAGE(defs.client_suite_mgr().clientSuites().front().auto_add_new_suites() == false,"Expected auto add to be disabled");
-
- // Now enable auto add
- TestHelper::invokeRequest(&defs,Cmd_ptr( new ClientHandleCmd(defs.client_suite_mgr().clientSuites().front().handle(),true /* auto add */)),bypass_state_modify_change_check);
- BOOST_CHECK_MESSAGE(defs.client_suite_mgr().clientSuites().front().auto_add_new_suites(),"Expected auto add to be enabled");
-
- // now add new suite, they should get added to the new client handles
- names.clear();
- for(int i=5; i < 10; i++) names.push_back( "s" + boost::lexical_cast<std::string>(i) );
- for(size_t j = 0; j < names.size(); j++) defs.addSuite( Suite::create(names[j]) );
-
- std::vector<ecf::ClientSuites> clientSuites = defs.client_suite_mgr().clientSuites();
- std::vector<std::string> handle_suites;
- clientSuites[0].suites(handle_suites);
- BOOST_CHECK_MESSAGE(handle_suites == names ,"Expected suites to be automatically added to our handle");
-
- // Delete the suite s5,s6,s7,s8,s9
- for(int i=5; i < 10; i++) {
- suite_ptr suite = defs.findSuite("s" + boost::lexical_cast<std::string>(i));
- BOOST_CHECK_MESSAGE(suite.get(),"Failed to find suite s" << i);
- suite->remove();
- }
-
- { // Even when suites have been removed, we still keep registered suite
- // These have to be explicitly deleted by the user
- std::vector<ecf::ClientSuites> clientSuites = defs.client_suite_mgr().clientSuites();
- std::vector<std::string> handle_suites;
- clientSuites[0].suites(handle_suites);
- BOOST_CHECK_MESSAGE(handle_suites.size() == 5,"Expected handle to have 5 suites but found" << handle_suites.size());
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_client_handle_cmd_add_remove )
-{
- cout << "Base:: ...test_client_handle_cmd_add_remove\n";
-
- std::vector<std::string> suite_names; suite_names.reserve(6);
- for(int i=0; i < 5; i++) suite_names.push_back( "s" + boost::lexical_cast<std::string>(i) );
-
- defs_ptr defs = Defs::create();
- for(size_t j = 0; j < suite_names.size(); j++) defs->addSuite( Suite::create(suite_names[j]) );
- std::vector<std::string> empty_vec;
-
- // Register new handle, with no suites,
- {
- TestHelper::invokeRequest(defs.get(),Cmd_ptr( new ClientHandleCmd(empty_vec,false)),bypass_state_modify_change_check);
- BOOST_CHECK_MESSAGE(defs->client_suite_mgr().clientSuites().size() == 1,"Expected 1 Client suites but found " << defs->client_suite_mgr().clientSuites().size());
- BOOST_CHECK_MESSAGE(!defs->client_suite_mgr().handle_changed(1),"Expected No handle change, when no real suites added");
-
- defs_ptr created_defs = defs->client_suite_mgr().create_defs(1,defs); // clear the handle change
- BOOST_CHECK_MESSAGE(created_defs,"Expected defs to be created");
- BOOST_CHECK_MESSAGE(created_defs->suiteVec().empty(),"Expected no suites");
- BOOST_CHECK_MESSAGE(!defs->client_suite_mgr().handle_changed(1),"Expected handle changed to be cleared after create_defs()");
- }
-
- // Now add suites to the existing handle, then check they match.
- std::vector<std::string> handle_suites;
- {
- TestHelper::invokeRequest(defs.get(),Cmd_ptr( new ClientHandleCmd(defs->client_suite_mgr().clientSuites().front().handle(),suite_names,ClientHandleCmd::ADD)),bypass_state_modify_change_check);
- defs->client_suite_mgr().clientSuites().front().suites(handle_suites);
- BOOST_CHECK_MESSAGE(handle_suites == suite_names ,"Expected suites to be added to our handle");
- BOOST_CHECK_MESSAGE(defs->client_suite_mgr().handle_changed(1),"Expected handle changed when adding new suites to our handle");
-
- defs_ptr created_defs = defs->client_suite_mgr().create_defs(1,defs); // clear the handle change
- BOOST_CHECK_MESSAGE(created_defs,"Expected defs to be created");
- BOOST_CHECK_MESSAGE(created_defs.get() == defs.get(),"When *ALL* suites registered, the returned defs should be the same");
- BOOST_CHECK_MESSAGE(created_defs->suiteVec().size() == suite_names.size(),"Not all suites created");
- }
-
- // Now remove the suites from the handle
- {
- TestHelper::invokeRequest(defs.get(),Cmd_ptr( new ClientHandleCmd(defs->client_suite_mgr().clientSuites().front().handle(),suite_names,ClientHandleCmd::REMOVE)),bypass_state_modify_change_check);
- handle_suites.clear();
- defs->client_suite_mgr().clientSuites().front().suites(handle_suites);
- BOOST_CHECK_MESSAGE(handle_suites == empty_vec ,"Expected no suites in our handle but found " << handle_suites.size());
- BOOST_CHECK_MESSAGE(defs->client_suite_mgr().handle_changed(1),"Expected handle changed when adding new removing suites");
-
- defs_ptr created_defs = defs->client_suite_mgr().create_defs(1,defs); // clear the handle change
- BOOST_CHECK_MESSAGE(created_defs,"Expected defs to be created");
- BOOST_CHECK_MESSAGE(created_defs->suiteVec().empty(),"Expected no suites");
- BOOST_CHECK_MESSAGE(!defs->client_suite_mgr().handle_changed(1),"Expected handle changed to be cleared after create_defs()");
- }
-}
-
-static bool check_ordering(Defs& defs)
-{
- // make sure order of suites in handles is the same as server order
- const std::vector<suite_ptr>& suite_vec = defs.suiteVec();
- std::vector<std::string> suite_names;
- for(size_t i = 0; i < suite_vec.size(); i++) suite_names.push_back(suite_vec[i]->name());
-
- // Drop the handles. take a copy, since we about to delete clientSuites
- std::vector<ecf::ClientSuites> clientSuites = defs.client_suite_mgr().clientSuites();
- for(size_t k =0; k< clientSuites.size(); k++) {
- std::vector<std::string> names; names.reserve(6);
- clientSuites[k].suites(names);
- if (names != suite_names) return false;
- }
- return true;
-}
-
-BOOST_AUTO_TEST_CASE( test_client_handle_suite_ordering )
-{
- cout << "Base:: ...test_client_handle_suite_ordering\n";
- // ensure order of suites in a handle is the same as server suites
-
- std::vector<std::string> suite_names; suite_names.reserve(6);
- for(int i=0; i < 5; i++) suite_names.push_back( "s" + boost::lexical_cast<std::string>(i) );
-
- Defs defs;
- for(size_t j = 0; j < suite_names.size(); j++) defs.addSuite( Suite::create(suite_names[j]) );
-
- // Register 3 new handle
- TestHelper::invokeRequest(&defs,Cmd_ptr( new ClientHandleCmd(suite_names,true)),bypass_state_modify_change_check);
- TestHelper::invokeRequest(&defs,Cmd_ptr( new ClientHandleCmd(suite_names,true)),bypass_state_modify_change_check);
- TestHelper::invokeRequest(&defs,Cmd_ptr( new ClientHandleCmd(suite_names,true)),bypass_state_modify_change_check);
- BOOST_CHECK_MESSAGE(defs.client_suite_mgr().clientSuites().size() == 3,"Expected 3 Client suites but found " << defs.client_suite_mgr().clientSuites().size());
-
- // After registration make sure ordering is the same
- BOOST_CHECK_MESSAGE(check_ordering(defs),"Ordering not preserved after registration of handles");
-
-
- // Check ordering after OrderNodeCmd
- TestHelper::invokeRequest(&defs,Cmd_ptr( new OrderNodeCmd("/s0",NOrder::DOWN)));
- BOOST_CHECK_MESSAGE(check_ordering(defs),"Ordering not preserved after NOrder::DOWN");
-
- TestHelper::invokeRequest(&defs,Cmd_ptr( new OrderNodeCmd("/s0",NOrder::UP)));
- BOOST_CHECK_MESSAGE(check_ordering(defs),"Ordering not preserved after NOrder::UP");
-
- TestHelper::invokeRequest(&defs,Cmd_ptr( new OrderNodeCmd("/s0",NOrder::BOTTOM)));
- BOOST_CHECK_MESSAGE(check_ordering(defs),"Ordering not preserved after NOrder::BOTTOM");
-
- TestHelper::invokeRequest(&defs,Cmd_ptr( new OrderNodeCmd("/s0",NOrder::TOP)));
- BOOST_CHECK_MESSAGE(check_ordering(defs),"Ordering not preserved after NOrder::TOP");
-
- TestHelper::invokeRequest(&defs,Cmd_ptr( new OrderNodeCmd("/s0",NOrder::ALPHA)));
- BOOST_CHECK_MESSAGE(check_ordering(defs),"Ordering not preserved after NOrder::ALPHA");
-
-
- // check ordering after adding new suites, notice we auto add new suites to all our handles
- defs.add_suite("sxx");
- BOOST_CHECK_MESSAGE(check_ordering(defs),"Ordering not preserved after adding a new suite");
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Base/test/TestCmd.cpp b/ecflow_4_0_7/Base/test/TestCmd.cpp
deleted file mode 100644
index 6bb841d..0000000
--- a/ecflow_4_0_7/Base/test/TestCmd.cpp
+++ /dev/null
@@ -1,109 +0,0 @@
- //============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #23 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <boost/test/unit_test.hpp>
-#include <boost/foreach.hpp>
-#include <string>
-#include <iostream>
-#include <fstream>
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "TestHelper.hpp"
-#include "System.hpp"
-#include "Str.hpp"
-
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( BaseTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_simple_cmd )
-{
- cout << "Base:: ...test_simple_cmd\n";
- // Create the defs file. Note that the default ECF_TRIES = 3
- // suite suite
- // family f
- // task t1
- // task t2
- // endfamily
- // endsuite
- Defs defs;
- string suite_f_t1 = "suite/f/t1";
- std::string suitename = "suite";
- family_ptr f = Family::create("f");
- task_ptr t1 = Task::create("t1");
- task_ptr t2 = Task::create("t2");
- suite_ptr s = Suite::create(suitename);
- {
- f->addTask( t1 );
- f->addTask( t2 );
- s->addFamily(f);
- defs.addSuite( s );
- }
-
- // ***********************************************************************
- // Create a request to begin suite
- // make sure chosen suite can begin to resolve dependencies.
- // beginning the suite will:
- // 1/ set all children to the QUEUED state
- // 2/ Begin job submission, and hence changes state to ACTIVE for submitted jobs
- {
- TestHelper::invokeRequest(&defs,Cmd_ptr( new BeginCmd(suitename,false)));
- BOOST_CHECK_MESSAGE( s->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(s->state()));
- BOOST_CHECK_MESSAGE( f->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f->state()));
- BOOST_CHECK_MESSAGE( t1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(t1->state()));
- BOOST_CHECK_MESSAGE( t2->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(t2->state()));
- }
-
-
- // ***********************************************************************
- // Create a request to abort Node: suite1/f/t1, Since the default ECF_TRIES is > 0, the aborted tasks
- // should be re-submitted, until the task try number > ECF_TRIES
- {
- std::string varValue;
- if (t1->findParentUserVariableValue( Str::ECF_TRIES(), varValue )) {
- int ecf_tries = boost::lexical_cast< int > (varValue);
- while (1) {
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AbortCmd(suite_f_t1,Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1)));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new CtsCmd( CtsCmd::FORCE_DEP_EVAL)));
- BOOST_CHECK_MESSAGE( t1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(t1->state()));
- BOOST_CHECK_MESSAGE( f->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f->state()));
- BOOST_CHECK_MESSAGE( s->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(s->state()));
- //std::cout << "tryNo = " << t1->try_no() << " ECF_TRIES = " << ecf_tries << "\n";
- if ( t1->try_no() == ecf_tries) break;
- }
-
- /// Since we have exceeded the try number, abort should mean abort
- TestHelper::invokeRequest(&defs,Cmd_ptr( new AbortCmd(suite_f_t1,Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1)));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new CtsCmd( CtsCmd::FORCE_DEP_EVAL)),false);
- BOOST_CHECK_MESSAGE( t1->state() == NState::ABORTED, "expected state NState::ABORTED, but found to be " << NState::toString(t1->state()));
- BOOST_CHECK_MESSAGE( f->state() == NState::ABORTED, "expected state NState::ABORTED, but found to be " << NState::toString(f->state()));
- BOOST_CHECK_MESSAGE( s->state() == NState::ABORTED, "expected state NState::ABORTED, but found to be " << NState::toString(s->state()));
- }
- }
-
- {
- std::string errorMsg;
- BOOST_CHECK_MESSAGE( defs.checkInvariants(errorMsg), errorMsg);
- }
-
- /// Destroy System singleton to avoid valgrind from complaining
- System::destroy();
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/Base/test/TestDeleteNodeCmd.cpp b/ecflow_4_0_7/Base/test/TestDeleteNodeCmd.cpp
deleted file mode 100644
index 863d21c..0000000
--- a/ecflow_4_0_7/Base/test/TestDeleteNodeCmd.cpp
+++ /dev/null
@@ -1,163 +0,0 @@
-//============================================================================
-// Name : Request
-// Author : Avi
-// Revision : $Revision: #16 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-
-#include "ClientToServerCmd.hpp"
-#include "ServerToClientCmd.hpp"
-#include "MyDefsFixture.hpp"
-#include "TestHelper.hpp"
-#include "DefsStructureParser.hpp"
-#include "DurationTimer.hpp"
-
-using namespace std;
-using namespace ecf;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( BaseTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_delete_node_cmd )
-{
- cout << "Base:: ...test_delete_node_cmd\n";
-
- MyDefsFixture fixtureDef;
- MockServer mockServer(&fixtureDef.defsfile_);
-
- // IMPORTANT: ******************************************************************************
- // If the PathsCmd is given a EMPTY list of paths, it will delete *EVERYTHING*
- // *****************************************************************************************
-
- // Delete all Aliases
- {
- std::vector<alias_ptr> vec;
- fixtureDef.defsfile_.get_all_aliases(vec);
- BOOST_CHECK_MESSAGE( vec.size() > 0,"Expected > 0 aliases but found " << vec.size());
-
- std::vector<std::string> paths; paths.reserve(vec.size());
- BOOST_FOREACH(alias_ptr t, vec) { paths.push_back(t->absNodePath()); }
-
- BOOST_CHECK_MESSAGE( !paths.empty(),"Expected paths to be specified, *OTHERWISE* we delete all nodes");
- PathsCmd cmd(PathsCmd::DELETE,paths);
- cmd.setup_user_authentification();
- STC_Cmd_ptr returnCmd = cmd.handleRequest( &mockServer );
- BOOST_CHECK_MESSAGE(returnCmd->ok(),"Failed to delete aliases");
-
- std::vector<alias_ptr> afterDeleteVec;
- fixtureDef.defsfile_.get_all_aliases(afterDeleteVec);
- BOOST_REQUIRE_MESSAGE( afterDeleteVec.empty(),"Expected all aliases to be deleted but found " << afterDeleteVec.size());
- }
-
- // Delete all tasks
- {
- std::vector<Task*> vec;
- fixtureDef.defsfile_.getAllTasks(vec);
- BOOST_CHECK_MESSAGE( vec.size() > 0,"Expected > 0 tasks but found " << vec.size());
-
- std::vector<std::string> paths; paths.reserve(vec.size());
- BOOST_FOREACH(Task* t, vec) { paths.push_back(t->absNodePath()); }
-
- BOOST_CHECK_MESSAGE( !paths.empty(),"Expected paths to be specified, *OTHERWISE* we delete all nodes");
- PathsCmd cmd(PathsCmd::DELETE,paths);
- cmd.setup_user_authentification();
- STC_Cmd_ptr returnCmd = cmd.handleRequest( &mockServer );
- BOOST_CHECK_MESSAGE(returnCmd->ok(),"Failed to delete tasks");
-
- std::vector<Task*> afterDeleteVec;
- fixtureDef.defsfile_.getAllTasks(afterDeleteVec);
- BOOST_REQUIRE_MESSAGE( afterDeleteVec.empty(),"Expected all tasks to be deleted but found " << afterDeleteVec.size());
- }
-
- // Delete all Families
- {
- // DONT use getAllFamilies as this will return hierarchical families
- // we don't want to delete families twice
- // std::vector<Family*> vec;
- // fixtureDef.defsfile_.getAllFamilies(vec);
- }
-
- // Delete all Suites
- {
- std::vector<suite_ptr> vec = fixtureDef.defsfile_.suiteVec();
- BOOST_CHECK_MESSAGE( vec.size() > 0,"Expected > 0 Suites but found " << vec.size());
- BOOST_FOREACH(suite_ptr s, vec) {
- {
- // Delete all Families
- // *********************************************************************************************
- // **EXPLICITLY** check for empty paths otherwise we can end up deleting ALL suites accidentally
- // if PathsCmd is given an empty list, we will delete all nodes including the suites
- // *********************************************************************************************
- std::vector<family_ptr> familyVec = s->familyVec();
- // DONT USE:
- // BOOST_FOREACH(family_ptr f, s->familyVec()) {
- // As with this will invalidate the iterators.
- std::vector<std::string> paths; paths.reserve(vec.size());
- BOOST_FOREACH(family_ptr f, familyVec) { paths.push_back(f->absNodePath()); }
-
- if (!paths.empty()) {
- PathsCmd cmd(PathsCmd::DELETE,paths);
- cmd.setup_user_authentification();
- STC_Cmd_ptr returnCmd = cmd.handleRequest( &mockServer );
- BOOST_CHECK_MESSAGE(returnCmd->ok(),"Failed to delete families");
- BOOST_REQUIRE_MESSAGE( s->familyVec().empty(),"Expected all Families to be deleted but found " << s->familyVec().size());
- }
- }
-
- // delete the suite
- std::string absNodePath = s->absNodePath();
- PathsCmd cmd(PathsCmd::DELETE,absNodePath);
- cmd.setup_user_authentification();
- STC_Cmd_ptr returnCmd = cmd.handleRequest( &mockServer );
- BOOST_CHECK_MESSAGE(returnCmd->ok(),"Failed to delete suite at path " << absNodePath);
- }
-
- BOOST_REQUIRE_MESSAGE( fixtureDef.defsfile_.suiteVec().empty(),"Expected all Suites to be deleted but found " << fixtureDef.defsfile_.suiteVec().size());
- }
-}
-
-// Will break for valgrind hence commented out
-//BOOST_AUTO_TEST_CASE( test_delete_cmd_for_defs )
-//{
-// std::string path_to_very_large_defs_file = "/var/tmp/ma0/BIG_DEFS/3199.def";
-// cout << "Base:: ...test_delete_cmd_for_defs " << path_to_very_large_defs_file;
-//
-// // Ok will only run locally, so don't fail, for other platforms
-// if (!fs::exists(path_to_very_large_defs_file)) cout << " ... missing test\n";
-// else {
-// Defs defs;
-// {
-// DurationTimer duration_timer;
-// DefsStructureParser checkPtParser( &defs, path_to_very_large_defs_file);
-// std::string errorMsg,warningMsg;
-// BOOST_REQUIRE_MESSAGE(checkPtParser.doParse(errorMsg,warningMsg),"failed to parse 3199.def");
-// cout << " ...Loading took " << duration_timer.duration();
-// BOOST_CHECK_MESSAGE( duration_timer.duration() < 20,"Loading defs "
-// << path_to_very_large_defs_file << " took " << duration_timer.duration() << " Expected to take < 20 seconds");
-// }
-//
-// DurationTimer duration_timer;
-// MockServer mockServer(&defs);
-// PathsCmd cmd(PathsCmd::DELETE,"",true);
-// cmd.setup_user_authentification();
-// STC_Cmd_ptr returnCmd = cmd.handleRequest( &mockServer );
-// BOOST_CHECK_MESSAGE(returnCmd->ok(),"Failed to delete defs");
-// cout << " ...Deleting took " << duration_timer.duration() << "\n";
-// BOOST_CHECK_MESSAGE( duration_timer.duration() < 2,"Deleting defs "
-// << path_to_very_large_defs_file << " took " << duration_timer.duration() << " Expected to take < 2 seconds");
-// }
-//}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/Base/test/TestECFLOW-189.cpp b/ecflow_4_0_7/Base/test/TestECFLOW-189.cpp
deleted file mode 100644
index 44cd048..0000000
--- a/ecflow_4_0_7/Base/test/TestECFLOW-189.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #23 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <boost/test/unit_test.hpp>
-
-#include "ClientToServerCmd.hpp"
-#include "ServerToClientCmd.hpp"
-#include "MyDefsFixture.hpp"
-#include "MockServer.hpp"
-#include "TestHelper.hpp"
-#include "System.hpp"
-#include "PrintStyle.hpp"
-#include "ChangeMgrSingleton.hpp"
-#include "Defs.hpp"
-
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( BaseTestSuite )
-
-static defs_ptr create_defs()
-{
- // suite s1
- // family f1
- // trigger f2 == complete
- // task t1
- // task t2
- // endfamily
- // family f2
- // task t1
- // task t2
- // endfamily
- // endsuite
- defs_ptr theDefs = Defs::create();
- suite_ptr suite = theDefs->add_suite( "s1" ) ;
- family_ptr f1 = suite->add_family( "f1" ) ;
- family_ptr f2 = suite->add_family( "f2" ) ;
- f1->add_trigger("f2 == complete");
- f1->add_task("t1");
- f1->add_task("t2");
- f2->add_task("t1");
- f2->add_task("t2");
-
- return theDefs;
-}
-
-BOOST_AUTO_TEST_CASE( test_ECFLOW_189 )
-{
- cout << "Base:: ...test_ECFLOW_189\n";
- defs_ptr the_defs = create_defs();
- the_defs->beginAll();
- node_ptr s1 = the_defs->findAbsNode("/s1");
- node_ptr f1 = the_defs->findAbsNode("/s1/f1");
- node_ptr t1 = the_defs->findAbsNode("/s1/f1/t1");
- node_ptr t2 = the_defs->findAbsNode("/s1/f1/t2");
-
- TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new PathsCmd(PathsCmd::SUSPEND, t1->absNodePath())));
- TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new PathsCmd(PathsCmd::SUSPEND, t2->absNodePath())));
-
- TestHelper::test_state(t1,DState::SUSPENDED);
- TestHelper::test_state(t2,DState::SUSPENDED);
-
- // Now resume /s1/f1/t1 and /s1/f1/t2
- TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new PathsCmd(PathsCmd::RESUME, t1->absNodePath())));
-
- // We expect state to be queued since the trigger on /s1/f1 should prevent jobs from running
- // If we find submitted or aborted(i.e it was free to run, but could not generate the jobs), then its an error
- TestHelper::test_state(t1,NState::QUEUED);
- TestHelper::test_state(t2,NState::QUEUED);
-
- /// Destroy System singleton to avoid valgrind from complaining
- System::destroy();
- ChangeMgrSingleton::destroy();
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Base/test/TestForceCmd.cpp b/ecflow_4_0_7/Base/test/TestForceCmd.cpp
deleted file mode 100644
index 320b62e..0000000
--- a/ecflow_4_0_7/Base/test/TestForceCmd.cpp
+++ /dev/null
@@ -1,922 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #23 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <boost/test/unit_test.hpp>
-
-#include "ClientToServerCmd.hpp"
-#include "ServerToClientCmd.hpp"
-#include "MyDefsFixture.hpp"
-#include "MockServer.hpp"
-#include "TestHelper.hpp"
-#include "System.hpp"
-#include "PrintStyle.hpp"
-#include "ChangeMgrSingleton.hpp"
-
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( BaseTestSuite )
-
-static defs_ptr create_defs()
-{
- defs_ptr theDefs = Defs::create();
- suite_ptr suite = theDefs->add_suite( "s1" ) ;
- family_ptr f1 = suite->add_family( "f1" ) ;
- task_ptr t1 = f1->add_task("t1");
- t1->addTime( TimeAttr(10,30));
- t1->add_alias_only();
- task_ptr t2 = f1->add_task("t2");
- t2->add_alias_only();
- return theDefs;
-}
-
-BOOST_AUTO_TEST_CASE( test_force_cmd )
-{
- cout << "Base:: ...test_force_cmd\n";
- defs_ptr the_defs = create_defs();
- the_defs->beginAll();
- node_ptr s1 = the_defs->findAbsNode("/s1");
- node_ptr f1 = the_defs->findAbsNode("/s1/f1");
- node_ptr t1 = the_defs->findAbsNode("/s1/f1/t1");
- node_ptr t2 = the_defs->findAbsNode("/s1/f1/t2");
-
- TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",true /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(t1,NState::COMPLETE);
- BOOST_CHECK_MESSAGE(t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be set");
- BOOST_CHECK_MESSAGE(!f1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be NOT set");
- BOOST_CHECK_MESSAGE(!s1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be NOT set");
-
- TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new ForceCmd(t2->absNodePath(),"complete",true /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(t2,NState::COMPLETE);
- BOOST_CHECK_MESSAGE(!t2->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be NOT set since there are NO time depedencies");
- BOOST_CHECK_MESSAGE(!f1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be NOT set");
- BOOST_CHECK_MESSAGE(!s1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be NOT set");
-
-
- TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new ForceCmd(s1->absNodePath(),"complete",true /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(s1,NState::COMPLETE);
- TestHelper::test_state(f1,NState::COMPLETE);
- TestHelper::test_state(t1,NState::COMPLETE);
-
- int clear_suspended_in_child_nodes = 0;
- s1->requeue(true,clear_suspended_in_child_nodes,false);
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear after requeue");
- BOOST_CHECK_MESSAGE(!t2->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear after requeue");
- BOOST_CHECK_MESSAGE(!f1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear after requeue");
- BOOST_CHECK_MESSAGE(!s1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear after requeue");
-
- node_ptr alias = the_defs->findAbsNode("/s1/f1/t1/alias0");
- TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new ForceCmd(alias->absNodePath(),"complete",true /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(alias,NState::COMPLETE);
-}
-
-
-static void doForce(MockServer& mockServer,
- Node* node,
- const std::string& stateOrEvent,
- const std::vector<Node*>& nodes)
-{
- ForceCmd cmd(node->absNodePath(), stateOrEvent, true /*recursive */, true /* set Repeat to last value */);
- cmd.setup_user_authentification();
- STC_Cmd_ptr returnCmd = cmd.handleRequest( &mockServer );
- BOOST_REQUIRE_MESSAGE(returnCmd->ok(),"Failed to force for node " << node->debugNodePath());
-
- for(size_t i = 0; i < nodes.size(); i++) {
- if (NState::isValid(stateOrEvent)) {
- NState::State state = NState::toState(stateOrEvent);
-
- // Force Cmd recursive does **NOT** apply to aliases.
- if (nodes[i]->isAlias()) {
- // The alias should still be in default QUEUED state
- BOOST_CHECK_MESSAGE( nodes[i]->state() == NState::QUEUED, "Expected state NState::QUEUED for alias but found " << NState::toString(nodes[i]->state()) << " for alias " << nodes[i]->debugNodePath());
- }
- else {
- BOOST_CHECK_MESSAGE( nodes[i]->state() == state, "Expected state " << NState::toString(state) << " but found " << NState::toString(nodes[i]->state()) << " for node " << nodes[i]->debugNodePath());
- }
- }
- else BOOST_CHECK_MESSAGE(false, "oops");
-
- if (!(nodes[i]->repeat().empty())) {
- BOOST_CHECK_MESSAGE( !nodes[i]->repeat().valid(), "Expected repeat to be set to last value. ie in valid");
- }
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_force_cmd_recursive )
-{
- cout << "Base:: ...test_force_cmd_recursive\n";
-
- defs_ptr the_defs = create_defs();
- node_ptr suite = the_defs->findAbsNode("/s1");
- std::vector<Node*> nodes;
- suite->getAllNodes(nodes);
-
- MockServer mockServer(the_defs);
- std::vector< std::string > all_states = NState::allStates();
- BOOST_FOREACH(const std::string& state, all_states) {
- doForce(mockServer,suite.get(),state,nodes);
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_force_cmd_bubbles_up_state_changes )
-{
- cout << "Base:: ...test_force_cmd_bubbles_up_state_changes\n";
-
- defs_ptr the_defs = create_defs();
- std::vector<Node*> nodes;
- std::vector<Task*> tasks;
- the_defs->getAllNodes(nodes);
- the_defs->getAllTasks(tasks);
- node_ptr suite = the_defs->findAbsNode("/s1");
-
- MockServer mockServer(the_defs);
-
- std::vector< std::string > all_states = NState::allStates();
- BOOST_FOREACH(const std::string& state, all_states) {
-
- // cout << "Setting all tasks to state " << state << "\n";
- BOOST_FOREACH(Task* task, tasks) {
- ForceCmd cmd(task->absNodePath(), state, false /*recursive */, false /* set Repeat to last value */);
- cmd.setup_user_authentification();
- STC_Cmd_ptr returnCmd = cmd.handleRequest( &mockServer );
- BOOST_REQUIRE_MESSAGE(returnCmd->ok(),"Failed to force for node " << task->debugNodePath());
- }
-
- // Check that state change set on task has bubbled up to the suite.
- // Since the state has been set on *all* tasks
- // cout << "Suite state = " << NState::toString(suite->state()) << "\n";
- NState::State expected_state = NState::toState(state);
- BOOST_CHECK_MESSAGE( suite->state() == expected_state, "Expected state " << NState::toString(expected_state) << " but found " << NState::toString(suite->state()) << " for suite " << suite->debugNodePath());
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_force_cmd_alias_does_not_bubble_up_state_changes )
-{
- cout << "Base:: ...test_force_cmd_alias_does_not_bubble_up_state_changes\n";
-
- defs_ptr the_defs = create_defs();
- std::vector<Node*> nodes;
- std::vector<alias_ptr> aliases;
- the_defs->getAllNodes(nodes);
- the_defs->get_all_aliases(aliases);
- node_ptr suite = the_defs->findAbsNode("/s1");
-
- // initialize by setting all nodes to state QUEUED
- BOOST_FOREACH(Node* n, nodes) { n->set_state(NState::QUEUED); }
-
- MockServer mockServer(the_defs);
- std::vector< std::string > all_states = NState::allStates();
- BOOST_FOREACH(const std::string& state, all_states) {
-
- BOOST_FOREACH(alias_ptr alias, aliases) {
- ForceCmd cmd(alias->absNodePath(), state, false /*recursive */, false /* set Repeat to last value */);
- cmd.setup_user_authentification();
- STC_Cmd_ptr returnCmd = cmd.handleRequest( &mockServer );
- BOOST_REQUIRE_MESSAGE(returnCmd->ok(),"Failed to force for alias " << alias->debugNodePath());
- }
-
- // Check that state change set on alias has *NOT* bubbled up to the suite.
- BOOST_CHECK_MESSAGE( suite->state() == NState::QUEUED, "Expected suite to have state QUEUED but found " << NState::toString(suite->state()));
- }
-}
-
-
-BOOST_AUTO_TEST_CASE( test_force_events )
-{
- cout << "Base:: ...test_force_events\n";
-
- MyDefsFixture fixtureDef;
- MockServer mockServer(&fixtureDef.defsfile_);
-
- node_ptr suite = fixtureDef.fixtureDefsFile().findAbsNode("/suiteName");
- BOOST_REQUIRE_MESSAGE( suite.get(), "Could not find suite");
- std::vector<Node*> nodes;
- suite->getAllNodes(nodes);
-
- /// Set and clear events
- BOOST_FOREACH(Node* node, nodes) {
- BOOST_FOREACH(const Event& e, node->events()) {
- std::string path = node->absNodePath() + ":" + e.name_or_number();
- ForceCmd cmd(path, Event::SET(), false /*recursive */, false /* set Repeat to last value */);
- cmd.setup_user_authentification();
- STC_Cmd_ptr returnCmd = cmd.handleRequest( &mockServer );
- BOOST_REQUIRE_MESSAGE(returnCmd->ok(),"Failed to force event for node " << node->debugNodePath());
- }
- BOOST_FOREACH(const Event& e, node->events()) {
- BOOST_CHECK_MESSAGE(e.value(), "Event not set as expected for node " << node->debugNodePath());
- }
- }
- BOOST_FOREACH(Node* node, nodes) {
- BOOST_FOREACH(const Event& e, node->events()) {
- std::string path = node->absNodePath() + ":" + e.name_or_number();
- ForceCmd cmd(path, Event::CLEAR(), false /*recursive */, false /* set Repeat to last value */);
- cmd.setup_user_authentification();
- STC_Cmd_ptr returnCmd = cmd.handleRequest( &mockServer );
- BOOST_REQUIRE_MESSAGE(returnCmd->ok(),"Failed to force event for node " << node->debugNodePath());
- }
- BOOST_FOREACH(const Event& e, node->events()) {
- BOOST_CHECK_MESSAGE(!e.value(), "Event not cleared as expected for node " << node->debugNodePath());
- }
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_force_events_errors )
-{
- cout << "Base:: ...test_force_events_errors\n";
-
- MyDefsFixture fixtureDef;
- MockServer mockServer(&fixtureDef.defsfile_);
-
- node_ptr suite = fixtureDef.fixtureDefsFile().findAbsNode("/suiteName");
- BOOST_REQUIRE_MESSAGE( suite.get(), "Could not find suite");
- std::vector<Node*> nodes;
- suite->getAllNodes(nodes);
-
- /// Make a path that does not exist
- BOOST_FOREACH(Node* node, nodes) {
- BOOST_FOREACH(const Event& e, node->events()) {
- std::string path = node->absNodePath() + "/path/doesnot/exist" + ":" + e.name_or_number();
- ForceCmd cmd(path, Event::SET(), false /*recursive */, false /* set Repeat to last value */);
- cmd.setup_user_authentification();
- BOOST_REQUIRE_THROW(cmd.handleRequest( &mockServer ) , std::runtime_error);
- }
- }
- BOOST_FOREACH(Node* node, nodes) {
- BOOST_FOREACH(const Event& e, node->events()) {
- std::string path = node->absNodePath() + "/path/doesnot/exist" + ":" + e.name_or_number();
- ForceCmd cmd(path, Event::CLEAR(), false /*recursive */, false /* set Repeat to last value */);
- cmd.setup_user_authentification();
- BOOST_REQUIRE_THROW(cmd.handleRequest( &mockServer ) , std::runtime_error);
- }
- }
-
- /// Make path that does not contain a event
- BOOST_FOREACH(Node* node, nodes) {
- if (node->events().empty()) {
- std::string path = node->absNodePath() ;
- ForceCmd cmd(path, Event::SET(), false /*recursive */, false /* set Repeat to last value */);
- cmd.setup_user_authentification();
- BOOST_REQUIRE_THROW(cmd.handleRequest( &mockServer ) , std::runtime_error);
- }
- }
- BOOST_FOREACH(Node* node, nodes) {
- if (node->events().empty()) {
- std::string path = node->absNodePath();
- ForceCmd cmd(path, Event::CLEAR(), false /*recursive */, false /* set Repeat to last value */);
- cmd.setup_user_authentification();
- BOOST_REQUIRE_THROW(cmd.handleRequest( &mockServer ) , std::runtime_error);
- }
- }
-
- /// Make a event that does not exist
- BOOST_FOREACH(Node* node, nodes) {
- BOOST_FOREACH(const Event& e, node->events()) {
- std::string path = node->absNodePath() + ":" + e.name_or_number() + "made_up";
- ForceCmd cmd(path, Event::SET(), false /*recursive */, false /* set Repeat to last value */);
- cmd.setup_user_authentification();
- BOOST_REQUIRE_THROW(cmd.handleRequest( &mockServer ) , std::runtime_error);
- }
- }
- BOOST_FOREACH(Node* node, nodes) {
- BOOST_FOREACH(const Event& e, node->events()) {
- std::string path = node->absNodePath() + ":" + e.name_or_number() + "made_up";
- ForceCmd cmd(path, Event::CLEAR(), false /*recursive */, false /* set Repeat to last value */);
- cmd.setup_user_authentification();
- BOOST_REQUIRE_THROW(cmd.handleRequest( &mockServer ) , std::runtime_error);
- }
- }
-}
-
-
-BOOST_AUTO_TEST_CASE( test_force_interactive )
-{
- // This test is custom. When the user interactively forces a node to the
- // complete state, and that node has pending time activities. The default
- // behaviour, is the node is re-queued again, and hence the propagation up the
- // node tree does not happen. This is test checks that the node does *not* exhibit
- // this functionality. What we want is that task is set to complete, without
- // forcing a re-queue, this is then propagated up the node tree. Which forces the
- // family to complete, and hence update the repeat variable.
- cout << "Base:: ...test_force_interactive\n";
-
- // suite s1
- // family daily
- // repeat date YMD 20101215 20101217 1
- // task t1
- // time 11:30
- // endfamily
- // endsuite
- // make sure time is set *before* 11:30, so that time dependency holds the task
- defs_ptr the_defs = Defs::create();
- suite_ptr suite = Suite::create( "s1" ) ;
- ClockAttr clockAttr(15,12,2010,false);
- clockAttr.set_gain(1/*hour*/,0/*minutes*/);
- suite->addClock( clockAttr );
- family_ptr f1 = Family::create( "daily" ) ;
- f1->addRepeat( RepeatDate("date", 20101215, 20101217) );
- task_ptr t1 = Task::create("t1" );
- t1->addTime( ecf::TimeAttr(ecf::TimeSlot(11,30)) );
- f1->addTask( t1 );
- suite->addFamily( f1 );
- the_defs->addSuite( suite );
-
- // before test flags should be clear
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear,before test");
- BOOST_CHECK_MESSAGE(!f1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, before test");
- BOOST_CHECK_MESSAGE(!suite->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, before test");
-
- /// begin the suite
- TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new BeginCmd("s1",false)));
- TestHelper::test_state(t1,NState::QUEUED);
- BOOST_REQUIRE_MESSAGE(f1->repeat().value() == 20101215,"Repeat value expected is 20101215 but found " << f1->repeat().value());
-
-
- // Force the task t1 to complete state.
- // Since task t1 is complete, the family 'daily' should complete.
- // This will cause the repeat to take the next value anf forcing a requeue
- TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(t1,NState::QUEUED);
- BOOST_REQUIRE_MESSAGE(f1->repeat().value() == 20101216,"Repeat value expected is 20101216 but found " << f1->repeat().value());
-
- // Reque should mean flag was cleared + on suite should never get set, since flag is stopped at repeat
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, since task was REQUED");
- BOOST_CHECK_MESSAGE(!f1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, since family was REQUED");
- BOOST_CHECK_MESSAGE(!suite->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, since repeat should stop flag propagation up node tree");
-
- // Force the task t1 to complete again
- TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(t1,NState::QUEUED);
- BOOST_REQUIRE_MESSAGE(f1->repeat().value() == 20101217,"Repeat value expected is 20101217 but found " << f1->repeat().value());
-
- // Do for the last time,
- TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(t1,NState::COMPLETE);
- TestHelper::test_state(f1,NState::COMPLETE);
- TestHelper::test_state(suite,NState::COMPLETE);
-
- // Since we completed, without a requeue, we should expect flag to stay set.
- BOOST_CHECK_MESSAGE(t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be set, since there was no reque");
-
- // Flag propagation should stop at the repeat
- BOOST_CHECK_MESSAGE(!suite->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP *NOT* to be set");
-}
-
-BOOST_AUTO_TEST_CASE( test_force_interactive_next_time_slot )
-{
- // This test is custom. When the user interactively forces a node to the complete state,
- // But where the user has a single time slot. We should stay complete and NOT requee
- //
- cout << "Base:: ...test_force_interactive_next_time_slot\n";
-
- // suite s1
- // task t1
- // time 10:00
- // endsuite
- // make sure time is set *before* 10:00, so that time dependency holds the task
- Defs the_defs;
- suite_ptr suite = the_defs.add_suite("s1");
- task_ptr t1 = suite->add_task("t1");
- t1->addTime( TimeAttr(10,0) );
- ClockAttr clockAttr(15,12,2010,false);
- clockAttr.set_gain(9/*hour*/,30/*minutes*/); // start at 09:30
- suite->addClock( clockAttr );
-
- // before test flags should be clear
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear,before test");
-
- /// begin the suite
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new BeginCmd("s1",false)));
- TestHelper::test_state(t1,NState::QUEUED);
-// PrintStyle::setStyle(PrintStyle::STATE);
-// cout << the_defs << "\n";
-
- // since we started at 09:30 the next time slot should be 10:00
- const TimeSlot& next_time_slot = t1->timeVec().back().time_series().get_next_time_slot();
- BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(10,0),"Expected next time slot of 10:00 but found " << next_time_slot.toString());
-
- // Force the task t1 to complete state. Since we had ONLY a SINGLE time dependency we should stay complete
- // It should also advance the next time slot
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(t1,NState::COMPLETE);
- BOOST_CHECK_MESSAGE( !t1->timeVec().back().time_series().is_valid(),"Expected 10:00 time slot to have expired");
- BOOST_CHECK_MESSAGE( t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be set");
-
- // call again should, should be do difference
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(t1,NState::COMPLETE);
- BOOST_CHECK_MESSAGE( !t1->timeVec().back().time_series().is_valid(),"Expected 10:00 time slot to have expired");
- BOOST_CHECK_MESSAGE( t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be set");
-
- /// we will now Re-queue, Since the time is still 09:30, we expect next_time slot to be 10:00
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new RequeueNodeCmd(t1->absNodePath())));
- TestHelper::test_state(t1,NState::QUEUED);
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear");
- BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(10,0),"After Re-queue, Expected next time slot of 10:00 but found " << next_time_slot.toString());
-}
-
-
-BOOST_AUTO_TEST_CASE( test_force_interactive_next_time_slot_1 )
-{
- // Start TIME at 9:30
- // This test is custom. When the user interactively forces a node to the complete state,
- // But where the user set of time slots. In this case the node should complete and then
- // requee and miss the next time. If this is repeated, eventually we should reach the
- // end of the time slot. In which case the node should *not* re-queue and stay complete
- //
- // When the node is then re-queued check that the time has been correctly reset.
- cout << "Base:: ...test_force_interactive_next_time_slot_1\n";
-
- // suite s1
- // task t1
- // time 10:00
- // time 11:00
- // time 12:00
- // time 13:00
- // endsuite
- Defs the_defs;
- suite_ptr suite = the_defs.add_suite("s1");
- task_ptr t1 = suite->add_task("t1");
- t1->addTime( TimeAttr(10,0) );
- t1->addTime( TimeAttr(11,0) );
- t1->addTime( TimeAttr(12,0) );
- t1->addTime( TimeAttr(13,0) );
- ClockAttr clockAttr(15,12,2010,false);
- clockAttr.set_gain(9/*hour*/,30/*minutes*/); // *start* at 9:30
- suite->addClock( clockAttr );
-
- // before test flags should be clear
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear,before test");
-
- /// begin the suite
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new BeginCmd("s1",false)));
- TestHelper::test_state(t1,NState::QUEUED);
-// PrintStyle::setStyle(PrintStyle::STATE);
-// cout << the_defs << "\n";
-
- // get all the time attributes
- const TimeSeries& ts_10 = t1->timeVec()[0].time_series();
- const TimeSeries& ts_11 = t1->timeVec()[1].time_series();
- const TimeSeries& ts_12 = t1->timeVec()[2].time_series();
- const TimeSeries& ts_13 = t1->timeVec()[3].time_series();
- BOOST_CHECK_MESSAGE( ts_10.is_valid(), "Expected time 10 to be valid since we started at 9:30 ");
- BOOST_CHECK_MESSAGE( ts_11.is_valid(), "Expected time 11 to be valid since we started at 9:30");
- BOOST_CHECK_MESSAGE( ts_12.is_valid(), "Expected time 12 to be valid since we started at 9:30");
- BOOST_CHECK_MESSAGE( ts_13.is_valid(), "Expected time 13 to be valid since we started at 9:30");
-
- const TimeSlot& time_10 = t1->timeVec()[0].time_series().get_next_time_slot();
- const TimeSlot& time_11 = t1->timeVec()[1].time_series().get_next_time_slot();
- const TimeSlot& time_12 = t1->timeVec()[2].time_series().get_next_time_slot();
- const TimeSlot& time_13 = t1->timeVec()[3].time_series().get_next_time_slot();
- BOOST_CHECK_MESSAGE( time_10 == TimeSlot(10,0),"Expected next time slot of 10:00 but found " << time_10.toString());
- BOOST_CHECK_MESSAGE( time_11 == TimeSlot(11,0),"Expected next time slot of 11:00 but found " << time_11.toString());
- BOOST_CHECK_MESSAGE( time_12 == TimeSlot(12,0),"Expected next time slot of 12:00 but found " << time_12.toString());
- BOOST_CHECK_MESSAGE( time_13 == TimeSlot(13,0),"Expected next time slot of 13:00 but found " << time_13.toString());
-
-
- // Force the task t1 to complete state. Since we have a future time dependency, we should get re-queued again
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(t1,NState::QUEUED);
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear");
- BOOST_CHECK_MESSAGE( !ts_10.is_valid(), "Expected time 10 to be expired ");
- BOOST_CHECK_MESSAGE( ts_11.is_valid(), "Expected time 11 to be valid.");
- BOOST_CHECK_MESSAGE( ts_12.is_valid(), "Expected time 12 to be valid");
- BOOST_CHECK_MESSAGE( ts_13.is_valid(), "Expected time 13 to be valid");
-
- // Repeat
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(t1,NState::QUEUED);
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear");
- BOOST_CHECK_MESSAGE( !ts_10.is_valid(), "Expected time 10 to be expired due to force cmd");
- BOOST_CHECK_MESSAGE( !ts_11.is_valid(), "Expected time 11 to be expired due to force cmd");
- BOOST_CHECK_MESSAGE( ts_12.is_valid(), "Expected time 12 to be valid");
- BOOST_CHECK_MESSAGE( ts_13.is_valid(), "Expected time 13 to be valid");
-
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(t1,NState::QUEUED);
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear");
- BOOST_CHECK_MESSAGE( !ts_10.is_valid(), "Expected time 10 to be expired due to force cmd");
- BOOST_CHECK_MESSAGE( !ts_11.is_valid(), "Expected time 11 to be expired due to force cmd");
- BOOST_CHECK_MESSAGE( !ts_12.is_valid(), "Expected time 12 to be expired due to force cmd");
- BOOST_CHECK_MESSAGE( ts_13.is_valid(), "Expected time 13 to be valid");
-
-
- // Repeat *last* time, since all times have expired, we expect task to stay complete.
- // Addtionally since we have *not* re-queued the flag NO_REQUE_IF_SINGLE_TIME_DEP should have remained set
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(t1,NState::COMPLETE);
- BOOST_CHECK_MESSAGE( t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be set");
- BOOST_CHECK_MESSAGE( !ts_10.is_valid(), "Expected time 10 to be expired since we started clock at 10:30 ");
- BOOST_CHECK_MESSAGE( !ts_11.is_valid(), "Expected time 11 to be expired due to force cmd");
- BOOST_CHECK_MESSAGE( !ts_12.is_valid(), "Expected time 12 to be expired due to force cmd");
- BOOST_CHECK_MESSAGE( !ts_13.is_valid(), "Expected time 13 to be expired due to force cmd");
-
- /// we will now Re-queue, Since the time is still 10:30, we expect valid from 11:00 and not 10:00
- /// We should also have cleared NO_REQUE_IF_SINGLE_TIME_DEP
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new RequeueNodeCmd(t1->absNodePath())));
- TestHelper::test_state(t1,NState::QUEUED);
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear");
- BOOST_CHECK_MESSAGE( ts_10.is_valid(), "Expected time 10 to be in valid since we started clock at 9:30 ");
- BOOST_CHECK_MESSAGE( ts_11.is_valid(), "Expected time 11 to be valid");
- BOOST_CHECK_MESSAGE( ts_12.is_valid(), "Expected time 12 to be valid");
- BOOST_CHECK_MESSAGE( ts_13.is_valid(), "Expected time 13 to be valid");
-}
-
-BOOST_AUTO_TEST_CASE( test_force_interactive_next_time_slot_2 )
-{
- // Start TIME at 9:30
- // This test is custom. When the user interactively forces a node to the complete state,
- // But where the user has a time range. In this case the node should complete and then
- // requee and miss the next time slot. If this is repeated, eventually we should reach the
- // end of the time slot. In which case the node should *not* reque and stay complete
- //
- // When the node is then requeed check that the next time slot has been correctly reset.
- cout << "Base:: ...test_force_interactive_next_time_slot_2\n";
-
- // suite s1
- // task t1
- // time 10:00 14:00 01:00
- // endsuite
- Defs the_defs;
- suite_ptr suite = the_defs.add_suite("s1");
- task_ptr t1 = suite->add_task("t1");
- t1->addTime( TimeAttr(TimeSlot(10,0),TimeSlot(14,0),TimeSlot(1,0)) );
- ClockAttr clockAttr(15,12,2010,false);
- clockAttr.set_gain(9/*hour*/,30/*minutes*/); // start at 99:30
- suite->addClock( clockAttr );
-
- // before test flags should be clear
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear,before test");
-
- /// begin the suite
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new BeginCmd("s1",false)));
- TestHelper::test_state(t1,NState::QUEUED);
-// PrintStyle::setStyle(PrintStyle::STATE);
-// cout << the_defs << "\n";
-
- // since we started at 09:30 the next time slot should be 10:00
- const TimeSlot& next_time_slot = t1->timeVec().back().time_series().get_next_time_slot();
- BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(10,0),"Expected next time slot of 10:00 but found " << next_time_slot.toString());
-
- // Force the task t1 to complete state. Since we have a future time dependency, we should get re-queued again
- // It should also advance the next time slot
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(t1,NState::QUEUED);
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, after a requeue");
- BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(11,0),"Expected next time slot of 11:00 but found " << next_time_slot.toString());
-
- // Repeat, to make sure next_time_slot is advanced
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(t1,NState::QUEUED);
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, after a requeue");
- BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(12,0),"Expected next time slot of 12:00 but found " << next_time_slot.toString());
-
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(t1,NState::QUEUED);
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, after a requeue");
- BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(13,0),"Expected next time slot of 13:00 but found " << next_time_slot.toString());
-
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(t1,NState::QUEUED);
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, after a requeue");
- BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(14,0),"Expected next time slot of 14:00 but found " << next_time_slot.toString());
-
- // Repeat, ** THIS time we have *exceeded* the time range, it should no longer requeue, and should stay complete
- // Additionally since there is no reque we expect NO_REQUE_IF_SINGLE_TIME_DEP to remain set
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(t1,NState::COMPLETE);
- BOOST_CHECK_MESSAGE(t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be set");
- BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(15,0),"Expected next time slot of 15:00 but found " << next_time_slot.toString());
-
- /// we will now Re-queue, Since the time is still 10:30, we expect next_time slot to be 11:00 and not 10:00
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new RequeueNodeCmd(t1->absNodePath())));
- TestHelper::test_state(t1,NState::QUEUED);
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear");
- BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(10,0),"After Re-queue, Expected next time slot of 10:00 but found " << next_time_slot.toString());
-}
-
-
-BOOST_AUTO_TEST_CASE( test_force_interactive_next_time_slot_3 )
-{
- // Start TIME at 10:30
- // This test is custom. When the user interactively forces a node to the complete state,
- // But where the user set of time slots. In this case the node should complete and then
- // requee and miss the next time. If this is repeated, eventually we should reach the
- // end of the time slot. In which case the node should *not* re-queue and stay complete
- //
- // When the node is then re-queued check that the time has been correctly reset.
- cout << "Base:: ...test_force_interactive_next_time_slot_3\n";
-
- // suite s1
- // task t1
- // time 10:00
- // time 11:00
- // time 12:00
- // time 13:00
- // endsuite
- Defs the_defs;
- suite_ptr suite = the_defs.add_suite("s1");
- task_ptr t1 = suite->add_task("t1");
- t1->addTime( TimeAttr(10,0) );
- t1->addTime( TimeAttr(11,0) );
- t1->addTime( TimeAttr(12,0) );
- t1->addTime( TimeAttr(13,0) );
- ClockAttr clockAttr(15,12,2010,false);
- clockAttr.set_gain(10/*hour*/,30/*minutes*/); // *start* at 10:30
- suite->addClock( clockAttr );
-
- // before test flags should be clear
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear,before test");
-
- /// begin the suite
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new BeginCmd("s1",false)));
- TestHelper::test_state(t1,NState::QUEUED);
-// PrintStyle::setStyle(PrintStyle::STATE);
-// cout << the_defs << "\n";
-
- // get all the time attributes
- const TimeSeries& ts_10 = t1->timeVec()[0].time_series();
- const TimeSeries& ts_11 = t1->timeVec()[1].time_series();
- const TimeSeries& ts_12 = t1->timeVec()[2].time_series();
- const TimeSeries& ts_13 = t1->timeVec()[3].time_series();
- BOOST_CHECK_MESSAGE( !ts_10.is_valid(), "Expected time 10 to be in-valid since we started clock at 10:30 ");
- BOOST_CHECK_MESSAGE( ts_11.is_valid(), "Expected time 11 to be valid since we started at 10:30");
- BOOST_CHECK_MESSAGE( ts_12.is_valid(), "Expected time 12 to be valid since we started at 10:30");
- BOOST_CHECK_MESSAGE( ts_13.is_valid(), "Expected time 13 to be valid since we started at 10:30");
-
- const TimeSlot& time_10 = t1->timeVec()[0].time_series().get_next_time_slot();
- const TimeSlot& time_11 = t1->timeVec()[1].time_series().get_next_time_slot();
- const TimeSlot& time_12 = t1->timeVec()[2].time_series().get_next_time_slot();
- const TimeSlot& time_13 = t1->timeVec()[3].time_series().get_next_time_slot();
- BOOST_CHECK_MESSAGE( time_10 == TimeSlot(10,0),"Expected next time slot of 10:00 but found " << time_10.toString());
- BOOST_CHECK_MESSAGE( time_11 == TimeSlot(11,0),"Expected next time slot of 11:00 but found " << time_11.toString());
- BOOST_CHECK_MESSAGE( time_12 == TimeSlot(12,0),"Expected next time slot of 12:00 but found " << time_12.toString());
- BOOST_CHECK_MESSAGE( time_13 == TimeSlot(13,0),"Expected next time slot of 13:00 but found " << time_13.toString());
-
-
- // Force the task t1 to complete state. Since we have a future time dependency, we should get re-queued again
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(t1,NState::QUEUED);
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear");
- BOOST_CHECK_MESSAGE( !ts_10.is_valid(), "Expected time 10 to be expired since we started clock at 10:30 ");
- BOOST_CHECK_MESSAGE( !ts_11.is_valid(), "Expected time 11 to be expired, since we just completed.");
- BOOST_CHECK_MESSAGE( ts_12.is_valid(), "Expected time 12 to be valid");
- BOOST_CHECK_MESSAGE( ts_13.is_valid(), "Expected time 13 to be valid");
-
- // Repeat
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(t1,NState::QUEUED);
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear");
- BOOST_CHECK_MESSAGE( !ts_10.is_valid(), "Expected time 10 to be expired since we started clock at 10:30 ");
- BOOST_CHECK_MESSAGE( !ts_11.is_valid(), "Expected time 11 to be expired due to force cmd");
- BOOST_CHECK_MESSAGE( !ts_12.is_valid(), "Expected time 12 to be expired due to force cmd");
- BOOST_CHECK_MESSAGE( ts_13.is_valid(), "Expected time 13 to be valid");
-
- // Repeat *last* time, since all times have expired, we expect task to complete.
- // Addtionally since we have *not* re-queued the flag NO_REQUE_IF_SINGLE_TIME_DEP should have remained set
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(t1,NState::COMPLETE);
- BOOST_CHECK_MESSAGE( t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be set");
- BOOST_CHECK_MESSAGE( !ts_10.is_valid(), "Expected time 10 to be expired since we started clock at 10:30 ");
- BOOST_CHECK_MESSAGE( !ts_11.is_valid(), "Expected time 11 to be expired due to force cmd");
- BOOST_CHECK_MESSAGE( !ts_12.is_valid(), "Expected time 12 to be expired due to force cmd");
- BOOST_CHECK_MESSAGE( !ts_13.is_valid(), "Expected time 13 to be expired due to force cmd");
-
- /// we will now Re-queue, Since the time is still 10:30, we expect valid from 11:00 and not 10:00
- /// We should also have cleared NO_REQUE_IF_SINGLE_TIME_DEP
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new RequeueNodeCmd(t1->absNodePath())));
- TestHelper::test_state(t1,NState::QUEUED);
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear");
- BOOST_CHECK_MESSAGE( !ts_10.is_valid(), "Expected time 10 to be in valid since we started clock at 10:30 ");
- BOOST_CHECK_MESSAGE( ts_11.is_valid(), "Expected time 11 to be valid");
- BOOST_CHECK_MESSAGE( ts_12.is_valid(), "Expected time 12 to be valid");
- BOOST_CHECK_MESSAGE( ts_13.is_valid(), "Expected time 13 to be valid");
-}
-
-
-BOOST_AUTO_TEST_CASE( test_force_interactive_next_time_slot_4 )
-{
- // This test is custom. When the user interactively forces a node to the complete state,
- // But where the user has a time range. In this case the node should complete and then
- // requee and miss the next time slot. If this is repeated, eventually we should reach the
- // end of the time slot. In which case the node should *not* reque and stay complete
- //
- // When the node is then requeed check that the next time slot has been correctly reset.
- cout << "Base:: ...test_force_interactive_next_time_slot_4\n";
-
- // suite s1
- // task t1
- // time 10:00 14:00 01:00
- // endsuite
- Defs the_defs;
- suite_ptr suite = the_defs.add_suite("s1");
- task_ptr t1 = suite->add_task("t1");
- t1->addTime( TimeAttr(TimeSlot(10,0),TimeSlot(14,0),TimeSlot(1,0)) );
- ClockAttr clockAttr(15,12,2010,false);
- clockAttr.set_gain(10/*hour*/,30/*minutes*/); // start at 10:30
- suite->addClock( clockAttr );
-
- // before test flags should be clear
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear,before test");
-
- /// begin the suite
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new BeginCmd("s1",false)));
- TestHelper::test_state(t1,NState::QUEUED);
-// PrintStyle::setStyle(PrintStyle::STATE);
-// cout << the_defs << "\n";
-
- // since we started at 10:30 the next time slot should be 11:00
- const TimeSlot& next_time_slot = t1->timeVec().back().time_series().get_next_time_slot();
- BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(11,0),"Expected next time slot of 11:00 but found " << next_time_slot.toString());
-
- // Force the task t1 to complete state. Since we have a future time dependency, we should get re-queued again
- // It should also advance the next time slot
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(t1,NState::QUEUED);
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, after a requeue");
- BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(12,0),"Expected next time slot of 12:00 but found " << next_time_slot.toString());
-
- // Repeat, to make sure next_time_slot is advanced
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(t1,NState::QUEUED);
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, after a requeue");
- BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(13,0),"Expected next time slot of 13:00 but found " << next_time_slot.toString());
-
- // Repeat, to make sure next_time_slot is advanced
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(t1,NState::QUEUED);
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, after a requeue");
- BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(14,0),"Expected next time slot of 14:00 but found " << next_time_slot.toString());
-
- // Repeat, ** THIS time we have *exceeded* the time range, it should no longer requeue, and should stay complete
- // Additionally since there is no reque we expect NO_REQUE_IF_SINGLE_TIME_DEP to remain set
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(t1,NState::COMPLETE);
- BOOST_CHECK_MESSAGE(t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be set");
- BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(15,0),"Expected next time slot of 15:00 but found " << next_time_slot.toString());
-
- /// we will now Re-queue, Since the time is still 10:30, we expect next_time slot to be 11:00 and not 10:00
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new RequeueNodeCmd(t1->absNodePath())));
- TestHelper::test_state(t1,NState::QUEUED);
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear");
- BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(11,0),"After Re-queue, Expected next time slot of 11:00 but found " << next_time_slot.toString());
-}
-
-
-BOOST_AUTO_TEST_CASE( test_force_interactive_next_time_slot_for_cron )
-{
- // This test is custom. When the user interactively forces a node to the complete state,
- // But where the user has a time range. In this case the node should complete and then
- // requee and miss the next time slot. If this is repeated, eventually we should reach the
- // end of the time slot.
- //
- // When the node is then requeed check that the next time slot has been correctly reset.
- cout << "Base:: ...test_force_interactive_next_time_slot_for_cron\n";
-
- // suite s1
- // task t1
- // cron 10:00 13:00 01:00
- // endsuite
- Defs the_defs;
- suite_ptr suite = the_defs.add_suite("s1");
- ClockAttr clockAttr(15,12,2010,false);
- clockAttr.set_gain(9/*hour*/,30/*minutes*/); // start at 09:30
- suite->addClock( clockAttr );
-
- task_ptr t1 = suite->add_task("t1");
- ecf::CronAttr cronAttr;
- cronAttr.addTimeSeries(TimeSlot(10,0),TimeSlot(13,0),TimeSlot(1,0));
- t1->addCron(cronAttr);
-
- // before test flags should be clear
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear,before test");
-
- /// begin the suite
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new BeginCmd("s1",false)));
- TestHelper::test_state(t1,NState::QUEUED);
-// PrintStyle::setStyle(PrintStyle::STATE);
-// cout << the_defs << "\n";
-
- // since we started at 09:30 the next time slot should be 10:00
- const TimeSlot& next_time_slot = t1->crons().back().time_series().get_next_time_slot();
- BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(10,0),"Expected next time slot of 10:00 but found " << next_time_slot.toString());
-
- // Force the task t1 to complete state. Since we have a future time dependency, we should get re-queued again
- // It should also advance the next time slot
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(t1,NState::QUEUED);
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, after a requeue");
- BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(11,0),"Expected next time slot of 11:00 but found " << next_time_slot.toString());
-
- // Repeat, to make sure next_time_slot is advanced
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(t1,NState::QUEUED);
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, after a requeue");
- BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(12,0),"Expected next time slot of 12:00 but found " << next_time_slot.toString());
-
- // Repeat, to make sure next_time_slot is advanced
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(t1,NState::QUEUED);
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, after a requeue");
- BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(13,0),"Expected next time slot of 13:00 but found " << next_time_slot.toString());
-
- // Repeat, ** THIS time we have *exceeded* the time range, However the cron *ALWAYS* re-queues
- // Additionally since there is no reque we expect NO_REQUE_IF_SINGLE_TIME_DEP to remain set
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(t1,NState::QUEUED);
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear, after a requeue");
- BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(14,0),"Expected next time slot of 14:00 but found " << next_time_slot.toString());
-
- /// we will now Re-queue, Since the time is still 09:30, we expect next_time slot to be 10:00 and not 14:00
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new RequeueNodeCmd(t1->absNodePath())));
- TestHelper::test_state(t1,NState::QUEUED);
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear");
- BOOST_CHECK_MESSAGE( next_time_slot == TimeSlot(10,0),"After Re-queue, Expected next time slot of 10:00 but found " << next_time_slot.toString());
-}
-
-
-BOOST_AUTO_TEST_CASE( test_force_interactive_next_time_slot_for_cron_on_family )
-{
- // This test is custom. When the user interactively forces a node to the complete state,
- // But where the user has a time range. In this case the node should complete and then
- // requee and miss the next time slot. If this is repeated, eventually we should reach the
- // end of the time slot.
- //
- // When the node is then requeed check that the next time slot has been correctly reset.
- cout << "Base:: ...test_force_interactive_next_time_slot_for_cron_on_family\n";
-
- // suite s1
- // family
- // cron 10:00 13:00 01:00
- // task t1
- // time 11:00
- // task t2
- // time 12:00
- // endsuite
- Defs the_defs;
- suite_ptr suite = the_defs.add_suite("s1");
- ClockAttr clockAttr(15,12,2010,false);
- clockAttr.set_gain(9/*hour*/,30/*minutes*/); // start at 09:30
- suite->addClock( clockAttr );
-
- family_ptr f1 = suite->add_family("f1");
- ecf::CronAttr cronAttr;
- cronAttr.addTimeSeries(TimeSlot(10,0),TimeSlot(13,0),TimeSlot(1,0));
- f1->addCron(cronAttr);
-
- task_ptr t1 = f1->add_task("t1");
- t1->addTime( TimeAttr(11,0) );
-
- task_ptr t2 = f1->add_task("t2");
- t2->addTime( TimeAttr(12,0) );
-
- // before test flags should be clear
- BOOST_CHECK_MESSAGE(!f1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear,before test");
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear,before test");
- BOOST_CHECK_MESSAGE(!t2->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear,before test");
-
- /// begin the suite
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new BeginCmd("s1",false)));
- TestHelper::test_state(t1,NState::QUEUED);
- TestHelper::test_state(t2,NState::QUEUED);
-// PrintStyle::setStyle(PrintStyle::STATE);
-// cout << the_defs << "\n";
-
- // since we started at 09:30 the next time slot should be 11:00
- const TimeSlot& t1_next_time_slot = t1->timeVec().back().time_series().get_next_time_slot();
- const TimeSlot& t2_next_time_slot = t2->timeVec().back().time_series().get_next_time_slot();
- BOOST_CHECK_MESSAGE( t1_next_time_slot == TimeSlot(11,0),"Expected next time slot of 11:00 but found " << t1_next_time_slot.toString());
- BOOST_CHECK_MESSAGE( t2_next_time_slot == TimeSlot(12,0),"Expected next time slot of 12:00 but found " << t2_next_time_slot.toString());
-
- // Force the task t1 & t2 to complete state. Since we only have a single time dependency it should expire
- // It should also advance the next time slot
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(t1,NState::COMPLETE);
- TestHelper::test_state(t2,NState::QUEUED);
- BOOST_CHECK_MESSAGE( ! t1->timeVec().back().time_series().is_valid(),"Expected 11:00 time slot to be expired ");
-
- // Forcing t2 to complete as well should, end up requeueing t1,t2 due to parent cron
- TestHelper::invokeRequest(&the_defs,Cmd_ptr( new ForceCmd(t2->absNodePath(),"complete",false /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(t1,NState::QUEUED);
- TestHelper::test_state(t2,NState::QUEUED);
- BOOST_CHECK_MESSAGE( t1->timeVec().back().time_series().is_valid(),"Expected 11:00 time slot to be valid ");
- BOOST_CHECK_MESSAGE( t2->timeVec().back().time_series().is_valid(),"Expected 12:00 time slot to be valid ");
- BOOST_CHECK_MESSAGE(!t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear");
- BOOST_CHECK_MESSAGE(!t2->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear");
-
- /// Destroy System singleton to avoid valgrind from complaining
- System::destroy();
- ChangeMgrSingleton::destroy();
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Base/test/TestFreeDepCmd.cpp b/ecflow_4_0_7/Base/test/TestFreeDepCmd.cpp
deleted file mode 100644
index cccb9cb..0000000
--- a/ecflow_4_0_7/Base/test/TestFreeDepCmd.cpp
+++ /dev/null
@@ -1,304 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #22 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <iostream>
-#include <fstream>
-#include <stdlib.h>
-
-#include <boost/test/unit_test.hpp>
-
-#include "ClientToServerCmd.hpp"
-#include "ServerToClientCmd.hpp"
-#include "Suite.hpp"
-#include "Task.hpp"
-#include "Family.hpp"
-#include "Defs.hpp"
-#include "ExprAst.hpp"
-#include "MockServer.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-
-BOOST_AUTO_TEST_SUITE( BaseTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_free_dep_cmd )
-{
- cout << "Base:: ...test_free_dep_cmd\n";
-
- // Create a test and add the date and time dependencies
- ptime theLocalTime(date(2011,Nov,4), time_duration(9,30,0));
- ptime time_plus_hour = theLocalTime + hours(1);
- ptime time_plus_2_hour = theLocalTime + hours(2);
- date todaysDate = theLocalTime.date();
- date tomorrows_date = todaysDate + date_duration(1);
- date tomorrows_date_1 = todaysDate + date_duration(2);
-
- // Get tomorrow as a day so that isFree fails.
- tm day_1 = to_tm(tomorrows_date);
- tm day_2 = to_tm(tomorrows_date_1);
-
- suite_ptr suite;
- task_ptr task;
- Defs theDefs; {
- suite = theDefs.add_suite( "test_time" );
- ClockAttr clockAttr(theLocalTime,false/*false means use real clock*/);
- suite->addClock( clockAttr );
-
- family_ptr fam = suite->add_family( "family" );
- task = fam->add_task( "t" );
- task->addTime( ecf::TimeAttr( TimeSlot(time_plus_hour.time_of_day()) ) );
- task->addTime( ecf::TimeAttr( TimeSlot(time_plus_2_hour.time_of_day()) ) );
- task->addTime( ecf::TimeAttr( ecf::TimeSlot(1,1), ecf::TimeSlot(1,3), ecf::TimeSlot(0,1),
- true /*relative to suite start*/
- ));
- task->addToday( ecf::TodayAttr( TimeSlot(time_plus_hour.time_of_day()) ) );
- task->addToday( ecf::TodayAttr( TimeSlot(time_plus_2_hour.time_of_day()) ) );
- task->addDate( DateAttr(tomorrows_date.day(),tomorrows_date.month(),tomorrows_date.year()) );
- task->addDate( DateAttr(tomorrows_date_1.day(),tomorrows_date_1.month(),tomorrows_date_1.year()) );
- task->addDay( DayAttr(static_cast<DayAttr::Day_t>(day_1.tm_wday) ));
- task->addDay( DayAttr(static_cast<DayAttr::Day_t>(day_2.tm_wday) ));
- task->add_trigger( "t2 == complete" );
-
- CronAttr cronAttr;
- cronAttr.addTimeSeries( ecf::TimeSlot(time_plus_hour.time_of_day()),
- ecf::TimeSlot(time_plus_2_hour.time_of_day()),
- ecf::TimeSlot(0,1) );
- task->addCron( cronAttr );
-
- fam->add_task( "t2" );
- // cout << theDefs << "\n";
- }
- std::vector<task_ptr> vec;
- theDefs.get_all_tasks(vec);
- BOOST_REQUIRE_MESSAGE(vec.size() == 2,"Error in number of tasks");
-
- // This will initialise the calendar from the Clock attribute
- theDefs.beginAll();
-
- // First all trigger should fail to evaluate AND all dependencies should NOT be free
- BOOST_REQUIRE_MESSAGE(task->triggerAst(),"Expected trigger abstract syntax tree for task " << task->absNodePath());
- BOOST_REQUIRE_MESSAGE(!task->triggerAst()->evaluate(),"Trigger should not evaluate");
-
- const Calendar& cal = suite->calendar();
- BOOST_FOREACH(const ecf::TimeAttr& attr, task->timeVec()) {
- BOOST_CHECK_MESSAGE(!attr.isFree(cal)," Time should not be free");
- }
- BOOST_FOREACH(const ecf::TodayAttr& attr, task->todayVec()) {
- BOOST_CHECK_MESSAGE(!attr.isFree(cal)," Today should not be free");
- }
- BOOST_FOREACH(const ecf::CronAttr& attr, task->crons()) {
- BOOST_CHECK_MESSAGE(!attr.isFree(cal)," Cron should not be free");
- }
- BOOST_FOREACH(const DateAttr& attr, task->dates()) {
- BOOST_CHECK_MESSAGE(!attr.isFree(cal)," Date should not be free");
- }
- BOOST_FOREACH(const DayAttr& attr, task->days()) {
- BOOST_CHECK_MESSAGE(!attr.isFree(cal),"Day should not be free");
- }
-
-
- // Invoke the FreeDepCmd
- MockServer mockServer(&theDefs);
-
- FreeDepCmd cmd(task->absNodePath(),true/*trigger*/,true/* all */);
- cmd.setup_user_authentification();
- STC_Cmd_ptr returnCmd = cmd.handleRequest( &mockServer );
- BOOST_REQUIRE_MESSAGE(returnCmd->ok(),"Failed to for FreeDepCmd");
-
-
- // Dependencies should now all be free now.
- BOOST_REQUIRE_MESSAGE(task->get_trigger()->isFree(),"Trigger should evaluate");
- bool at_least_one_free = false;
- BOOST_FOREACH(const ecf::TimeAttr& attr, task->timeVec()) {
- if (attr.isFree(cal)) { at_least_one_free = true; break;}
- }
- BOOST_CHECK_MESSAGE(at_least_one_free,"At least one Time should be free");
-
- at_least_one_free = false;
- BOOST_FOREACH(const ecf::TodayAttr& attr, task->todayVec()) {
- if (attr.isFree(cal)) { at_least_one_free = true; break;}
- }
- BOOST_CHECK_MESSAGE(at_least_one_free,"At least one Today should be free");
-
- at_least_one_free = false;
- BOOST_FOREACH(const ecf::CronAttr& attr, task->crons()) {
- if (attr.isFree(cal)) { at_least_one_free = true; break;}
- }
- BOOST_CHECK_MESSAGE(at_least_one_free,"At least one Cron should be free");
-
- at_least_one_free = false;
- BOOST_FOREACH(const DateAttr& attr, task->dates()) {
- if (attr.isFree(cal)) { at_least_one_free = true; break;}
- }
- BOOST_CHECK_MESSAGE(at_least_one_free,"At least one Date should be free");
-
- at_least_one_free = false;
- BOOST_FOREACH(const DayAttr& attr, task->days()) {
- if (attr.isFree(cal)) { at_least_one_free = true; break;}
- }
- BOOST_CHECK_MESSAGE(at_least_one_free,"At least one Day should be free");
-}
-
-BOOST_AUTO_TEST_CASE( test_free_dep_cmd_single_time_slot )
-{
- cout << "Base:: ...test_free_dep_cmd_single_time_slot\n";
-
- // We add a time dependency *AFTER* the suite/calendar time
- // This checks that we DO NOT re-queue a task with a future time dependency
- // when a time dependency has been freed
- ptime theLocalTime(date(2011,Nov,4), time_duration(9,30,0));
- ptime time_plus_2minute = theLocalTime + minutes(2);
-
- suite_ptr suite;
- task_ptr task;
- Defs theDefs; {
- suite = theDefs.add_suite( "test_time" );
- ClockAttr clockAttr(theLocalTime,false/*false means use real clock*/);
- suite->addClock( clockAttr );
- task = suite->add_task( "t" );
- task->addTime( ecf::TimeAttr( TimeSlot(time_plus_2minute.time_of_day()) ) );
- }
-
- // This will initialise the calendar from the Clock attribute
- theDefs.beginAll();
-
- // expect task to be holding at 9:30
- const Calendar& cal = suite->calendar();
- BOOST_FOREACH(const ecf::TimeAttr& attr, task->timeVec()) {
- BOOST_CHECK_MESSAGE(!attr.isFree(cal)," Time should not be free");
- }
-
- // Invoke the FreeDepCmd
- MockServer mockServer(&theDefs);
- FreeDepCmd cmd(task->absNodePath(),true/*trigger*/,true/* all */);
- cmd.setup_user_authentification();
- STC_Cmd_ptr returnCmd = cmd.handleRequest( &mockServer );
- BOOST_REQUIRE_MESSAGE(returnCmd->ok(),"Failed to for FreeDepCmd");
-
- // expect task to be free
- bool at_least_one_free = false;
- BOOST_FOREACH(const ecf::TimeAttr& attr, task->timeVec()) {
- if (attr.isFree(cal)) { at_least_one_free = true; break;}
- }
- BOOST_CHECK_MESSAGE(at_least_one_free,"At least one Time should be free");
-
- // The crux of the test. Should not requeue.
- BOOST_CHECK_MESSAGE(task->state() == NState::ACTIVE,"Free dependency should have done an immediate job submission. Expected active state");
- task->complete();
- BOOST_CHECK_MESSAGE(task->state() == NState::COMPLETE,"Expected Complete but found " << NState::toString(task->state()) << ", free dependency should avoid re-queue for a future single time dependency.");
-}
-
-BOOST_AUTO_TEST_CASE( test_free_dep_cmd_with_time_series )
-{
- cout << "Base:: ...test_free_dep_cmd_with_time_series\n";
-
- // We start the suite *IN BETWEEN* a time series, and the force free dependency
- // This checks that we DO NOT re-queue a task with a future time dependency
- // when a time dependency has been freed
- ptime theLocalTime(date(2011,Nov,4), time_duration(9,29,0));
- suite_ptr suite;
- task_ptr task;
- Defs theDefs; {
- suite = theDefs.add_suite( "test_time" );
- ClockAttr clockAttr(theLocalTime,false/*false means use real clock*/);
- suite->addClock( clockAttr );
- task = suite->add_task( "t" );
- task->addTime( ecf::TimeAttr( ecf::TimeSlot(9,28), ecf::TimeSlot(9,30), ecf::TimeSlot(0,2),
- false /*relative to suite start*/
- ));
- }
-
- // This will initialise the calendar from the Clock attribute
- theDefs.beginAll();
-
- // expect task to be holding, at 9:29
- const Calendar& cal = suite->calendar();
- BOOST_FOREACH(const ecf::TimeAttr& attr, task->timeVec()) {
- BOOST_CHECK_MESSAGE(!attr.isFree(cal)," Time should not be free");
- }
-
- // Invoke the FreeDepCmd
- MockServer mockServer(&theDefs);
- FreeDepCmd cmd(task->absNodePath(),true/*trigger*/,true/* all */);
- cmd.setup_user_authentification();
- STC_Cmd_ptr returnCmd = cmd.handleRequest( &mockServer );
- BOOST_REQUIRE_MESSAGE(returnCmd->ok(),"Failed to for FreeDepCmd");
-
- // expect task to be free
- bool at_least_one_free = false;
- BOOST_FOREACH(const ecf::TimeAttr& attr, task->timeVec()) {
- if (attr.isFree(cal)) { at_least_one_free = true; break;}
- }
- BOOST_CHECK_MESSAGE(at_least_one_free,"At least one Time should be free");
-
- // The crux of the test. Should not requeue, as we should have advanced the time slot beyond the END point
- // i.e FreeDepCmd will advance the time slot, beyond end time
- BOOST_CHECK_MESSAGE(task->state() == NState::ACTIVE,"Free dependency should have done an immediate job submission. Expected active state");
- task->complete();
- BOOST_CHECK_MESSAGE(task->state() == NState::COMPLETE,"Expected Complete but found " << NState::toString(task->state()) << ", free dependency should avoid re-queue for a future single time dependency.");
-}
-
-BOOST_AUTO_TEST_CASE( test_free_dep_cmd_with_time_series_2 )
-{
- cout << "Base:: ...test_free_dep_cmd_with_time_series_2\n";
-
- // We start the suite *IN BETWEEN* a time series, and the force free dependency
- // This time we have a larger range, and *SHOULD* re-queue, even if we miss a time slot
- ptime theLocalTime(date(2011,Nov,4), time_duration(9,29,0));
- suite_ptr suite;
- task_ptr task;
- Defs theDefs; {
- suite = theDefs.add_suite( "test_time" );
- ClockAttr clockAttr(theLocalTime,false/*false means use real clock*/);
- suite->addClock( clockAttr );
- task = suite->add_task( "t" );
- task->addTime( ecf::TimeAttr( ecf::TimeSlot(9,28), ecf::TimeSlot(9,34), ecf::TimeSlot(0,2),
- false /*relative to suite start*/
- ));
- }
-
- // This will initialise the calendar from the Clock attribute
- // Will initialise nextTimeSlot=09:30
- theDefs.beginAll();
-
- // expect task to be holding, at 9:29
- const Calendar& cal = suite->calendar();
- BOOST_FOREACH(const ecf::TimeAttr& attr, task->timeVec()) {
- BOOST_CHECK_MESSAGE(!attr.isFree(cal)," Time should not be free");
- }
-
- // Invoke the FreeDepCmd. This will update next nextTimeSlot to 09:32
- MockServer mockServer(&theDefs);
- FreeDepCmd cmd(task->absNodePath(),true/*trigger*/,true/* all */);
- cmd.setup_user_authentification();
- STC_Cmd_ptr returnCmd = cmd.handleRequest( &mockServer );
- BOOST_REQUIRE_MESSAGE(returnCmd->ok(),"Failed to for FreeDepCmd");
-
- // expect task to be free
- bool at_least_one_free = false;
- BOOST_FOREACH(const ecf::TimeAttr& attr, task->timeVec()) {
- if (attr.isFree(cal)) { at_least_one_free = true; break;}
- }
- BOOST_CHECK_MESSAGE(at_least_one_free,"At least one Time should be free");
-
- // The crux of the test. Even if we advance the time slot we should *STILL* be in range
- BOOST_CHECK_MESSAGE(task->state() == NState::ACTIVE,"Free dependency should have done an immediate job submission. Expected active state");
- task->complete();
- BOOST_CHECK_MESSAGE(task->state() == NState::QUEUED,"Expected QUEUED but found " << NState::toString(task->state()) << ", free dependency should avoid re-queue for a future single time dependency.");
-}
-
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Base/test/TestHelper.hpp b/ecflow_4_0_7/Base/test/TestHelper.hpp
deleted file mode 100644
index 371d4f0..0000000
--- a/ecflow_4_0_7/Base/test/TestHelper.hpp
+++ /dev/null
@@ -1,90 +0,0 @@
-#ifndef TESTHELPER_HPP_
-#define TESTHELPER_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #33 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <boost/test/test_tools.hpp>
-
-#include "ClientToServerCmd.hpp"
-#include "ServerToClientCmd.hpp"
-#include "ClientToServerRequest.hpp"
-#include "MockServer.hpp"
-#include "Node.hpp"
-
-// defines statics utility functions used by more than one test
-class TestHelper {
-public:
- static void invokeRequest( Defs* defs, Cmd_ptr theCmd, bool check_change_numbers = true ) {
-
- // Check that state change happens
- unsigned int state_change_no = Ecf::state_change_no();
- unsigned int modify_change_no = Ecf::modify_change_no();
-
- // Setup command for invocation
- ClientToServerRequest cmd_request;
- cmd_request.set_cmd( theCmd );
- // std::cout << cmd_request << "\n";
-
- MockServer server(defs);
- STC_Cmd_ptr result = cmd_request.handleRequest(&server);
- BOOST_CHECK_MESSAGE( result, "ClientToServerRequest " << cmd_request << " returned NULL\n");
- BOOST_CHECK_MESSAGE( result->error().empty(), cmd_request << " " << result->error());
- if (check_change_numbers) {
- BOOST_CHECK_MESSAGE( state_change_no != Ecf::state_change_no() || modify_change_no != Ecf::modify_change_no(),
- "State & modify change numbers unaltered by command " << cmd_request);
-
- // Some tests(TestSSyncCmd_CH1.cpp), create defs where invariants like change numbers are deliberately different
- std::string error_msg;
- BOOST_CHECK_MESSAGE(defs->checkInvariants(error_msg),"invokeRequest checkInvariants failed " << error_msg << " for cmd " << cmd_request );
- }
- }
-
- static void invokeFailureRequest( Defs* defs, Cmd_ptr theCmd ) {
-
- ClientToServerRequest cmd_request;
- cmd_request.set_cmd( theCmd );
-
- MockServer server(defs);
-
- // We expect this to fail
- BOOST_CHECK_THROW(cmd_request.handleRequest(&server), std::runtime_error );
- }
-
- static void invokeFailureRequest(MockServer& server, Cmd_ptr theCmd ) {
-
- ClientToServerRequest cmd_request;
- cmd_request.set_cmd( theCmd );
-
- BOOST_CHECK_THROW(cmd_request.handleRequest(&server), std::runtime_error );
-
-// STC_Cmd_ptr result = cmd_request.handleRequest(&server);
-// BOOST_CHECK_MESSAGE( !result->ok(), "ClientToServerRequest " << cmd_request << " was expected to fail \n");
- }
-
- static void test_state(node_ptr n,NState::State expected)
- {
- BOOST_REQUIRE_MESSAGE(n->state() == expected,"Expected state " << NState::toString(expected) << " but found " << NState::toString(n->state()) << " for " << n->debugNodePath());
- }
-
- static void test_state(node_ptr n,DState::State expected)
- {
- BOOST_REQUIRE_MESSAGE(n->dstate() == expected,"Expected state " << DState::toString(expected) << " but found " << DState::toString(n->dstate()) << " for " << n->debugNodePath());
- }
-
-private:
- TestHelper() {}
-};
-#endif /* TESTHELPER_HPP_ */
-
diff --git a/ecflow_4_0_7/Base/test/TestLimit.cpp b/ecflow_4_0_7/Base/test/TestLimit.cpp
deleted file mode 100644
index ddfb500..0000000
--- a/ecflow_4_0_7/Base/test/TestLimit.cpp
+++ /dev/null
@@ -1,669 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #32 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <string>
-#include <iostream>
-#include <fstream>
-
-#include <boost/test/unit_test.hpp>
-#include <boost/foreach.hpp>
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "TestHelper.hpp"
-#include "JobsParam.hpp"
-#include "Jobs.hpp"
-#include "System.hpp"
-
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( BaseTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_add_limit )
-{
- cout << "Base:: ...test_add_limit\n";
- suite_ptr suite = Suite::create("suite");
- suite->addLimit(Limit("fast",1)) ; // " Adding limit first time should be ok");
- BOOST_REQUIRE_THROW(suite->addLimit(Limit("fast",1)), std::runtime_error); //" Adding same limit second time should fail");
-
- suite->addInLimit(InLimit("fast","/suite")); //" Adding in-limit first time should be ok");
- BOOST_REQUIRE_THROW(suite->addInLimit(InLimit("fast","/suite")), std::runtime_error); // " Adding in-limit second time should fail");
-}
-
-BOOST_AUTO_TEST_CASE( test_limit_increment )
-{
- cout << "Base:: ...test_limit_increment\n";
-
- // Test than when a job is submitted multiple times, it should only consume 1 token
- //
- // Create the defs file
- // suite suite
- // limit fast 10
- // family f
- // inlimit /suite:fast
- // task t1
- // endfamily
- // endsuite
- Defs defs;
- std::string limitName = "fast";
- std::string pathToLimit = "/suite";
- std::string suitename = "suite";
- suite_ptr s = defs.add_suite(suitename);
- family_ptr f = s->add_family("f");
- task_ptr t1 = f->add_task("t1");
- {
- f->addInLimit(InLimit(limitName,pathToLimit));
- s->addLimit(Limit(limitName,10));
- }
- // cerr << defs << "\n";
-
-
- {
- // Resolve dependencies:: BEFORE calling beginCmd, should be a NO OP
- JobsParam jobsParam; // create jobs = false, spawn jobs = false
- Jobs jobs(&defs);
- BOOST_CHECK_MESSAGE( jobs.generate(jobsParam),jobsParam.getErrorMsg());
- BOOST_CHECK_MESSAGE( jobsParam.submitted().size() == 0, "Expected 0 tasks to submit but found " << jobsParam.submitted().size());
- }
-
- {
- // Create a request to begin suite
- // make sure chosen suite can begin to resolve dependencies.
- // beginning the suite will:
- // 1/ set all children to the QUEUED state
- // 2/ Begin job submission, and hence changes state to ACTIVE for submitted jobs
- //
- // Resolve dependencies. Only one task should be submitted due to Limit
- TestHelper::invokeRequest(&defs,Cmd_ptr( new BeginCmd(suitename)));
- BOOST_CHECK_MESSAGE( s->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(s->state()));
- BOOST_CHECK_MESSAGE( f->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f->state()));
- BOOST_CHECK_MESSAGE( t1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(t1->state()));
- }
-
- {
- // Resolve dependencies. No task should submit since we have reached the limit
- JobsParam jobsParam; // create jobs = false, spawn jobs = false
- Jobs jobs(&defs);
- BOOST_CHECK_MESSAGE( jobs.generate(jobsParam),jobsParam.getErrorMsg());
- BOOST_CHECK_MESSAGE( jobsParam.submitted().size() == 0, "Expected 0 task to submit but found " << jobsParam.submitted().size());
- }
-
- {
- // Try resubmitting the an active task, it should still only consume 1 token in the limit
- BOOST_CHECK_MESSAGE( t1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(t1->state()));
-
- // Hack the state, to allow job to re- resubmitted
- t1->setStateOnly(NState::QUEUED);
-
- JobsParam jobsParam; // create jobs = false, spawn jobs = false
- Jobs jobs(&defs);
- BOOST_CHECK_MESSAGE( jobs.generate(jobsParam),jobsParam.getErrorMsg());
- BOOST_CHECK_MESSAGE( jobsParam.submitted().size() == 1, "Expected 1 task to submit but found " << jobsParam.submitted().size());
-
- // Limit should still have only consumed one token
- limit_ptr limit = s->find_limit(limitName);
- BOOST_CHECK_MESSAGE( limit.get(), "Limit not found");
- BOOST_CHECK_MESSAGE( limit->value() == 1, "Expected limit of value 1, but found " << limit->value());
- BOOST_CHECK_MESSAGE( limit->paths().size() == 1, "Expected Only 1 task path in limit but found " << limit->paths().size());
- }
-}
-
-
-//===============================================================================
-// This TEST is used to test limit and inLimit.
-// Both examples taken from the documentation
-BOOST_AUTO_TEST_CASE( test_limit )
-{
- cout << "Base:: ...test_limit\n";
-
- ///////////////////////////////////////////////////////////////////////////
- // Create the defs file
- // suite suite
- // limit fast 1
- // family f
- // inlimit /suite:fast
- // task t1
- // task t2
- // endfamily
- // endsuite
- Defs defs;
- std::string limitName = "fast";
- std::string pathToLimit = "/suite";
- std::string suitename = "suite";
- family_ptr f = Family::create("f");
- task_ptr t1 = Task::create("t1");
- task_ptr t2 = Task::create("t2");
- suite_ptr s = Suite::create(suitename);
- {
- f->addTask( t1 );
- f->addTask( t2);
- f->addInLimit(InLimit(limitName,pathToLimit));
-
- s->addFamily(f);
- s->addLimit(Limit(limitName,1));
-
- defs.addSuite( s );
- }
- // cerr << defs << "\n";
-
-
- //*******************************************************************************
- // Resolve dependencies:: BEFORE calling beginCmd, should be a NO OP
- {
- JobsParam jobsParam; // create jobs = false, spawn jobs = false
- Jobs jobs(&defs);
- BOOST_CHECK_MESSAGE( jobs.generate(jobsParam),jobsParam.getErrorMsg());
- BOOST_CHECK_MESSAGE( jobsParam.submitted().size() == 0, "Expected 0 tasks to submit but found " << jobsParam.submitted().size());
- }
-
- // ***********************************************************************
- // Create a request to begin suite
- // make sure chosen suite can begin to resolve dependencies.
- // beginning the suite will:
- // 1/ set all children to the QUEUED state
- // 2/ Begin job submission, and hence changes state to ACTIVE for submitted jobs
- //
- // Resolve dependencies. Only one task should be submitted due to Limit
- //
- {
- TestHelper::invokeRequest(&defs,Cmd_ptr( new BeginCmd(suitename)));
- BOOST_CHECK_MESSAGE( s->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(s->state()));
- BOOST_CHECK_MESSAGE( f->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f->state()));
- BOOST_CHECK_MESSAGE( t1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(t1->state()));
- BOOST_CHECK_MESSAGE( t2->state() == NState::QUEUED, "expected state NState::QUEUED, but found to be " << NState::toString(t2->state()));
- }
-
- //*******************************************************************************
- // Resolve dependencies. No task should submit since we have reached the limit
- {
- JobsParam jobsParam; // create jobs = false, spawn jobs = false
- Jobs jobs(&defs);
- BOOST_CHECK_MESSAGE( jobs.generate(jobsParam),jobsParam.getErrorMsg());
- BOOST_CHECK_MESSAGE( jobsParam.submitted().size() == 0, "Expected 0 task to submit but found " << jobsParam.submitted().size());
- }
-
- {
- std::string errorMsg;
- BOOST_CHECK_MESSAGE( defs.checkInvariants(errorMsg), errorMsg);
- }
-}
-
-
-BOOST_AUTO_TEST_CASE( test_limit1 )
-{
- cout << "Base:: ...test_limit1\n";
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- // Create the defs file
- // suite suite
- // limit disk 50
- // family f
- // inlimit /suite:disk 20
- // task t1
- // task t2
- // task t3
- // endfamily
- // endsuite
- //
- // Test that only 2 Tasks can run
- Defs defs;
- std::string limitName = "disk";
- std::string pathToLimit = "/suite";
- std::string suitename = "suite";
- family_ptr f = Family::create("f");
- task_ptr t1 = Task::create("t1");
- task_ptr t2 = Task::create("t2");
- task_ptr t3 = Task::create("t3");
- suite_ptr s = Suite::create(suitename);
- {
- f->addTask( t1 );
- f->addTask( t2 );
- f->addTask( t3 );
- f->addInLimit(InLimit(limitName,pathToLimit,20));
-
- s->addFamily(f);
- s->addLimit(Limit(limitName,50));
-
- defs.addSuite( s );
- }
- // cerr << defs << "\n";
-
- //*******************************************************************************
- // Resolve dependencies:: BEFORE calling beginCmd, should be a NO OP
- {
- JobsParam jobsParam; // create jobs = false, spawn jobs = false
- Jobs jobs(&defs);
- BOOST_CHECK_MESSAGE( jobs.generate(jobsParam),jobsParam.getErrorMsg());
- BOOST_CHECK_MESSAGE( jobsParam.submitted().size() == 0, "Expected 0 tasks to submit but found " << jobsParam.submitted().size());
- }
-
- // ***********************************************************************
- // Create a request to begin suite
- // make sure chosen suite can begin to resolve dependencies.
- // beginning the suite will:
- // 1/ set all children to the QUEUED state
- // 2/ Begin job submission, and hence changes state to ACTIVE for submitted jobs
- //
- // Resolve dependencies. Only TWO task should be active due to Limit
- {
- TestHelper::invokeRequest(&defs,Cmd_ptr( new BeginCmd(suitename)));
- BOOST_CHECK_MESSAGE( s->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(s->state()));
- BOOST_CHECK_MESSAGE( f->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f->state()));
- BOOST_CHECK_MESSAGE( t1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(t1->state()));
- BOOST_CHECK_MESSAGE( t2->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(t2->state()));
- BOOST_CHECK_MESSAGE( t3->state() == NState::QUEUED, "expected state NState::QUEUED, but found to be " << NState::toString(t3->state()));
- }
-
- //*******************************************************************************
- // Resolve dependencies. No task should submit since we have reached the limit
- {
- JobsParam jobsParam; // create jobs = false, spawn jobs = false
- Jobs jobs(&defs);
- BOOST_CHECK_MESSAGE( jobs.generate(jobsParam),jobsParam.getErrorMsg());
- BOOST_CHECK_MESSAGE( jobsParam.submitted().size() == 0, "Expected 0 task to submit but found " << jobsParam.submitted().size());
- if (jobsParam.submitted().size() != 0 ) {
- BOOST_FOREACH(Submittable* t, jobsParam.submitted()) { cerr << "Submittable " << t->absNodePath() << "\n";}
- }
- }
-
- {
- std::string errorMsg;
- BOOST_CHECK_MESSAGE( defs.checkInvariants(errorMsg), errorMsg);
- }
-}
-
-
-BOOST_AUTO_TEST_CASE( test_limit_references_after_delete )
-{
- /// In-limit have a reference to a limit. This limit can be on another node. If that node is deleted
- /// The limits are also deleted, hence we need to ensure in-limit reference to limits that are being
- /// deleted are cleared. Currently we use shared_ptr to achieve this
- cout << "Base:: ...test_limit_references_after_delete\n";
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- // Create the defs file
- // suite suiteLimits # the limit we want delete
- // limit limit1 1
- // limit limit2 1
- // limit limit3 1
- // endsuite
- //
- // suite suite
- // family f
- // inlimit /suiteLimits:limit1 # check limits references cleared after suiteLimits is deleted
- // task t1
- // endfamily
- // family f1
- // inlimit /suiteLimits:limit2
- // task t1
- // endfamily
- // family f2
- // inlimit /suiteLimits:limit3
- // task t1
- // endfamily
- // endsuite
- //
- // In this test case we will delete the suiteLimits, and then test to ensure the the in-limits
- // in suite have been reset.
- Defs defs;
- {
- suite_ptr suite = Suite::create("suiteLimits" );
- suite->addLimit(Limit("limit1",1));
- suite->addLimit(Limit("limit2",1));
- suite->addLimit(Limit("limit3",1));
- defs.addSuite( suite );
- }
-
- InLimit in_limit1("limit1","/suiteLimits");
- InLimit in_limit2("limit2","/suiteLimits");
- InLimit in_limit3("limit3","/suiteLimits");
- {
- suite_ptr suite = Suite::create("suite");
-
- family_ptr fam = Family::create("f");
- fam->addTask( Task::create("t1") );
- fam->addInLimit(in_limit1);
- suite->addFamily(fam);
-
- family_ptr fam2 = Family::create("f1");
- fam2->addTask( Task::create("t1") );
- fam2->addInLimit(in_limit2);
- suite->addFamily(fam2);
-
- family_ptr fam3 = Family::create("f2");
- fam3->addTask( Task::create("t1") );
- fam3->addInLimit(in_limit3);
- suite->addFamily(fam3);
-
- defs.addSuite( suite );
- }
-
-
- // First check that in-limit reference have been setup
- node_ptr f = defs.findAbsNode("/suite/f");
- node_ptr f1 = defs.findAbsNode("/suite/f1");
- node_ptr f2 = defs.findAbsNode("/suite/f2");
- BOOST_REQUIRE_MESSAGE( f.get() && f1.get() && f2.get(), "Failed to find family than contain the inlimits");
-
-
- BOOST_REQUIRE_MESSAGE( f->findInLimitByNameAndPath(in_limit1) &&
- f1->findInLimitByNameAndPath(in_limit2) &&
- f2->findInLimitByNameAndPath(in_limit3) , "Failed to find in-limits on the families" << defs);
-
- // Now check they all reference the limits
- BOOST_REQUIRE_MESSAGE( f->findLimitViaInLimit(in_limit1), "Inlimit does not reference its limit. Post process failed ?");
- BOOST_REQUIRE_MESSAGE( f1->findLimitViaInLimit(in_limit2), "Inlimit does not reference its limit. Post process failed ?");
- BOOST_REQUIRE_MESSAGE( f2->findLimitViaInLimit(in_limit3), "Inlimit does not reference its limit. Post process failed ?");
-
- // Ok Now delete suiteLimits, as this is where the limits reside
- // *** It is extremely important that shared_ptr for '/suiteLimit' is in its own
- // *** scope, otherwise it will keep the 'suite' live, and NOT delete the limits
- {
- node_ptr suiteLimits = defs.findAbsNode("/suiteLimits");
- BOOST_REQUIRE_MESSAGE( suiteLimits.get(), "Could not find the suite we want to delete?");
- BOOST_REQUIRE_MESSAGE( defs.deleteChild(suiteLimits.get()), "Deletion failed?");
- BOOST_REQUIRE_MESSAGE( !defs.findAbsNode("/suiteLimits").get(), "Deletion failed?");
- }
-
- BOOST_REQUIRE_MESSAGE( !f->findLimitViaInLimit(in_limit1), "In-limit still references limit that has been deleted?");
- BOOST_REQUIRE_MESSAGE( !f1->findLimitViaInLimit(in_limit2), "In-limit still references limit that has been deleted?");
- BOOST_REQUIRE_MESSAGE( !f2->findLimitViaInLimit(in_limit3), "In-limit still references limit that has been deleted?");
-}
-
-BOOST_AUTO_TEST_CASE( test_limits_after_force_cmd )
-{
- cout << "Base:: ...test_limits_after_force_cmd\n";
-
- // Create the following defs
- // suite s1
- // limit A 10
- // family f1
- // inlimit A
- // task t1
- // task t2
- // family f2
- // inlimit A
- // task t1
- // task t2
-
- // When all the tasks are running/submitted state, limit A should have consumed 4 tokens
- // However if we how force family f2 to be complete, then the limit should be reset back to 2 tokens.
- // Repeating for family f1, should result with a Limit with no tokens
- Defs defs;
- suite_ptr s1 = defs.add_suite("s1");
- s1->addLimit(Limit("A",10));
- family_ptr f1 = s1->add_family("f1");
- f1->addInLimit( InLimit("A","/s1"));
- task_ptr f1_t1 = f1->add_task("t1");
- task_ptr f1_t2 = f1->add_task("t2");
- family_ptr f2 = s1->add_family("f2");
- f2->addInLimit( InLimit("A","/s1"));
- task_ptr f2_t1 = f2->add_task("t1");
- task_ptr f2_t2 = f2->add_task("t2");
- //cout << defs;
-
- // Create a request to begin suite
- // make sure chosen suite can begin to resolve dependencies.
- // beginning the suite will:
- // 1/ set all children to the QUEUED state
- // 2/ Begin job submission, and hence changes state to ACTIVE for submitted jobs
- //
- // Resolve dependencies. All tasks are within the limit and hence should start
- {
- TestHelper::invokeRequest(&defs,Cmd_ptr( new BeginCmd("/s1")));
- BOOST_CHECK_MESSAGE( s1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(s1->state()));
- BOOST_CHECK_MESSAGE( f1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1->state()));
- BOOST_CHECK_MESSAGE( f1_t1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1_t1->state()));
- BOOST_CHECK_MESSAGE( f1_t2->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1_t2->state()));
- BOOST_CHECK_MESSAGE( f2->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f2->state()));
- BOOST_CHECK_MESSAGE( f2_t1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f2_t1->state()));
- BOOST_CHECK_MESSAGE( f2_t2->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f2_t2->state()));
-
- limit_ptr the_limit = s1->find_limit("A");
- BOOST_CHECK_MESSAGE( the_limit, "Could not find limit");
- BOOST_CHECK_MESSAGE( the_limit->value() == 4,"Expected limit value to be 4 but found " << the_limit->value());
- }
-
- {
- TestHelper::invokeRequest(&defs,Cmd_ptr( new ForceCmd(f2->absNodePath(),"complete",true /*recursive */, false /* set Repeat to last value */)));
-
- BOOST_CHECK_MESSAGE( s1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(s1->state()));
- BOOST_CHECK_MESSAGE( f1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1->state()));
- BOOST_CHECK_MESSAGE( f1_t1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1_t1->state()));
- BOOST_CHECK_MESSAGE( f1_t2->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1_t2->state()));
- BOOST_CHECK_MESSAGE( f2->state() == NState::COMPLETE, "expected state NState::COMPLETE, but found to be " << NState::toString(f2->state()));
- BOOST_CHECK_MESSAGE( f2_t1->state() == NState::COMPLETE, "expected state NState::COMPLETE, but found to be " << NState::toString(f2_t1->state()));
- BOOST_CHECK_MESSAGE( f2_t2->state() == NState::COMPLETE, "expected state NState::COMPLETE, but found to be " << NState::toString(f2_t2->state()));
-
- limit_ptr the_limit = s1->find_limit("A");
- BOOST_CHECK_MESSAGE( the_limit, "Could not find limit");
- BOOST_CHECK_MESSAGE( the_limit->value() == 2,"Expected limit value to be 2 but found " << the_limit->value());
- }
-
- {
- TestHelper::invokeRequest(&defs,Cmd_ptr( new ForceCmd(f1->absNodePath(),"complete",true /*recursive */, false /* set Repeat to last value */)));
-
- BOOST_CHECK_MESSAGE( s1->state() == NState::COMPLETE, "expected state NState::ACTIVE, but found to be " << NState::toString(s1->state()));
- BOOST_CHECK_MESSAGE( f1->state() == NState::COMPLETE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1->state()));
- BOOST_CHECK_MESSAGE( f1_t1->state() == NState::COMPLETE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1_t1->state()));
- BOOST_CHECK_MESSAGE( f1_t2->state() == NState::COMPLETE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1_t2->state()));
- BOOST_CHECK_MESSAGE( f2->state() == NState::COMPLETE, "expected state NState::COMPLETE, but found to be " << NState::toString(f2->state()));
- BOOST_CHECK_MESSAGE( f2_t1->state() == NState::COMPLETE, "expected state NState::COMPLETE, but found to be " << NState::toString(f2_t1->state()));
- BOOST_CHECK_MESSAGE( f2_t2->state() == NState::COMPLETE, "expected state NState::COMPLETE, but found to be " << NState::toString(f2_t2->state()));
-
- limit_ptr the_limit = s1->find_limit("A");
- BOOST_CHECK_MESSAGE( the_limit, "Could not find limit");
- BOOST_CHECK_MESSAGE( the_limit->value() == 0,"Expected limit value to be 0 but found " << the_limit->value());
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_limits_after_requeue_family_ECFLOW_196 )
-{
- cout << "Base:: ...test_limits_after_requeue_family_ECFLOW_196\n";
-
- // This test is used to ensure that, requeue causes node to release tokens held by the Limits
-
- // Create the following defs
- // suite s1
- // limit A 10
- // family f1
- // inlimit A
- // task t1
- // task t2
- // family f2
- // inlimit A
- // task t1
- // task t2
-
- // When all the tasks are running/submitted state, limit A should have consumed 4 tokens
- // However if we how force family f2 to be requeud, then the limit should be reset back to 2 tokens.
- Defs defs;
- suite_ptr s1 = defs.add_suite("s1");
- s1->addLimit(Limit("A",10));
- family_ptr f1 = s1->add_family("f1");
- f1->addInLimit( InLimit("A","/s1"));
- task_ptr f1_t1 = f1->add_task("t1");
- task_ptr f1_t2 = f1->add_task("t2");
- family_ptr f2 = s1->add_family("f2");
- f2->addInLimit( InLimit("A","/s1"));
- task_ptr f2_t1 = f2->add_task("t1");
- task_ptr f2_t2 = f2->add_task("t2");
- //cout << defs;
-
-
- // Create a request to begin suite
- // make sure chosen suite can begin to resolve dependencies.
- // beginning the suite will:
- // 1/ set all children to the QUEUED state
- // 2/ Begin job submission, and hence changes state to ACTIVE for submitted jobs
- //
- // Resolve dependencies. All tasks are within the limit and hence should start
- int expected_limit_value = 4;
- limit_ptr the_limit = s1->find_limit("A");
- BOOST_CHECK_MESSAGE( the_limit, "Could not find limit");
- {
- TestHelper::invokeRequest(&defs,Cmd_ptr( new BeginCmd("/s1")));
- BOOST_CHECK_MESSAGE( s1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(s1->state()));
- BOOST_CHECK_MESSAGE( f1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1->state()));
- BOOST_CHECK_MESSAGE( f1_t1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1_t1->state()));
- BOOST_CHECK_MESSAGE( f1_t2->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1_t2->state()));
- BOOST_CHECK_MESSAGE( f2->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f2->state()));
- BOOST_CHECK_MESSAGE( f2_t1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f2_t1->state()));
- BOOST_CHECK_MESSAGE( f2_t2->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f2_t2->state()));
-
- BOOST_CHECK_MESSAGE( the_limit->value() == expected_limit_value,"Expected limit value to be 4 but found " << the_limit->value());
- }
-
- {
- expected_limit_value = 2;
- // We now want to re-queue node f2, and check to see that limit tokens are released after the re-queue
- // However, the Mock server, will call resolve dependencies after re-queue command , and place nodes *back* into active
- // state, to *STOP* this, we will add a trigger, so that the dependencies will not resolve, and hence nodes stay queued
- f2->add_trigger("1 == 0");
- TestHelper::invokeRequest(&defs,Cmd_ptr( new RequeueNodeCmd(f2->absNodePath(),RequeueNodeCmd::FORCE)));
-
- BOOST_CHECK_MESSAGE( s1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(s1->state()));
- BOOST_CHECK_MESSAGE( f1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1->state()));
- BOOST_CHECK_MESSAGE( f1_t1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1_t1->state()));
- BOOST_CHECK_MESSAGE( f1_t2->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1_t2->state()));
- BOOST_CHECK_MESSAGE( f2->state() == NState::QUEUED, "expected state NState::QUEUED, but found to be " << NState::toString(f2->state()));
- BOOST_CHECK_MESSAGE( f2_t1->state() == NState::QUEUED, "expected state NState::QUEUED, but found to be " << NState::toString(f2_t1->state()));
- BOOST_CHECK_MESSAGE( f2_t2->state() == NState::QUEUED, "expected state NState::QUEUED, but found to be " << NState::toString(f2_t2->state()));
-
- BOOST_CHECK_MESSAGE( the_limit->value() == expected_limit_value,"Expected limit value to be 2 but found " << the_limit->value());
- }
-
- {
- expected_limit_value = 0;
- // We now want to re-queue node f1, and check to see that limit tokens are released after the re-queue
- // However, the Mock server, will call resolve dependencies after re-queue command , and place nodes *back* into active
- // state, to *STOP* this, we will add a trigger, so that the dependencies will not resolve, and hence nodes stay queued
- f1->add_trigger("1 == 0");
- TestHelper::invokeRequest(&defs,Cmd_ptr( new RequeueNodeCmd(f1->absNodePath(),RequeueNodeCmd::FORCE)));
-
- BOOST_CHECK_MESSAGE( s1->state() == NState::QUEUED, "expected state NState::ACTIVE, but found to be " << NState::toString(s1->state()));
- BOOST_CHECK_MESSAGE( f1->state() == NState::QUEUED, "expected state NState::ACTIVE, but found to be " << NState::toString(f1->state()));
- BOOST_CHECK_MESSAGE( f1_t1->state() == NState::QUEUED, "expected state NState::ACTIVE, but found to be " << NState::toString(f1_t1->state()));
- BOOST_CHECK_MESSAGE( f1_t2->state() == NState::QUEUED, "expected state NState::ACTIVE, but found to be " << NState::toString(f1_t2->state()));
- BOOST_CHECK_MESSAGE( f2->state() == NState::QUEUED, "expected state NState::QUEUED, but found to be " << NState::toString(f2->state()));
- BOOST_CHECK_MESSAGE( f2_t1->state() == NState::QUEUED, "expected state NState::QUEUED, but found to be " << NState::toString(f2_t1->state()));
- BOOST_CHECK_MESSAGE( f2_t2->state() == NState::QUEUED, "expected state NState::QUEUED, but found to be " << NState::toString(f2_t2->state()));
-
- BOOST_CHECK_MESSAGE( the_limit->value() == expected_limit_value,"Expected limit value to be 0 but found " << the_limit->value());
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_limits_after_requeue_task_ECFLOW_196 )
-{
- cout << "Base:: ...test_limits_after_requeue_task_ECFLOW_196\n";
-
- // This test is used to ensure that, requeue causes node to release tokens held by the Limits
-
- // Create the following def, i.e using internal and external limits
- // suite s0
- // limit X 5
- // suite s1
- // limit A 10
- // limit B 5
- // family f1
- // inlimit A
- // inlimit B
- // inlimit X /s0/
- // task t1
- // task t2
- // family f2
- // inlimit A
- // inlimit B
- // inlimit X /s0/
- // task t1
- // task t2
-
- // When all the tasks are running/submitted state, limit A should have consumed 4 tokens
- // However if we how force task to reque, then the token should be released
- Defs defs;
- suite_ptr s0 = defs.add_suite("s0");
- s0->addLimit(Limit("X",10));
-
- suite_ptr s1 = defs.add_suite("s1");
- s1->addLimit(Limit("A",10));
- s1->addLimit(Limit("B",5));
- family_ptr f1 = s1->add_family("f1");
- f1->addInLimit( InLimit("A","/s1"));
- f1->addInLimit( InLimit("B","/s1"));
- f1->addInLimit( InLimit("X","/s0"));
- task_ptr f1_t1 = f1->add_task("t1");
- task_ptr f1_t2 = f1->add_task("t2");
- family_ptr f2 = s1->add_family("f2");
- f2->addInLimit( InLimit("A","/s1"));
- f2->addInLimit( InLimit("B","/s1"));
- f2->addInLimit( InLimit("X","/s0"));
- task_ptr f2_t1 = f2->add_task("t1");
- task_ptr f2_t2 = f2->add_task("t2");
-
- std::vector<task_ptr> tasks;
- tasks.push_back(f1_t1); tasks.push_back(f1_t2);
- tasks.push_back(f2_t1); tasks.push_back(f2_t2);
- //cout << defs;
-
- limit_ptr the_A_limit = s1->find_limit("A");
- limit_ptr the_B_limit = s1->find_limit("B");
- limit_ptr the_X_limit = s0->find_limit("X");
- BOOST_CHECK_MESSAGE( the_A_limit && the_B_limit && the_X_limit, "Could not find limits");
-
- // Create a request to begin suite
- // make sure chosen suite can begin to resolve dependencies.
- // beginning the suite will:
- // 1/ set all children to the QUEUED state
- // 2/ Begin job submission, and hence changes state to ACTIVE for submitted jobs
- //
- // Resolve dependencies. All tasks are within the limit and hence should start
- int expected_limit_value = 4;
- {
- TestHelper::invokeRequest(&defs,Cmd_ptr( new BeginCmd("/s1")));
- BOOST_CHECK_MESSAGE( s1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(s1->state()));
- BOOST_CHECK_MESSAGE( f1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1->state()));
- BOOST_CHECK_MESSAGE( f1_t1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1_t1->state()));
- BOOST_CHECK_MESSAGE( f1_t2->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f1_t2->state()));
- BOOST_CHECK_MESSAGE( f2->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f2->state()));
- BOOST_CHECK_MESSAGE( f2_t1->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f2_t1->state()));
- BOOST_CHECK_MESSAGE( f2_t2->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(f2_t2->state()));
-
- BOOST_CHECK_MESSAGE( the_A_limit->value() == expected_limit_value,"Expected limit value to be " << expected_limit_value << " but found " << the_A_limit->value());
- BOOST_CHECK_MESSAGE( the_B_limit->value() == expected_limit_value,"Expected limit value to be " << expected_limit_value << " but found " << the_B_limit->value());
- BOOST_CHECK_MESSAGE( the_X_limit->value() == expected_limit_value,"Expected limit value to be " << expected_limit_value << " but found " << the_X_limit->value());
- }
-
- {
- // We now want to re-queue node tasks, and check to see that limit tokens are released after the re-queue
- // However, the Mock server, will call resolve dependencies after re-queue command , and place nodes *back* into active
- // state, to *STOP* this, we will add a trigger, so that the dependencies will not resolve, and hence nodes stay queued
- f1->add_trigger("1 == 0");
- f2->add_trigger("1 == 0");
-
- for(size_t i =0; i < tasks.size(); i++) {
- TestHelper::invokeRequest(&defs,Cmd_ptr( new RequeueNodeCmd(tasks[i]->absNodePath(),RequeueNodeCmd::FORCE)));
- expected_limit_value--;
- BOOST_CHECK_MESSAGE( the_A_limit->value() == expected_limit_value,"Expected limit value " << expected_limit_value << " but found " << the_A_limit->value());
- BOOST_CHECK_MESSAGE( the_B_limit->value() == expected_limit_value,"Expected limit value " << expected_limit_value << " but found " << the_B_limit->value());
- BOOST_CHECK_MESSAGE( the_X_limit->value() == expected_limit_value,"Expected limit value " << expected_limit_value << " but found " << the_X_limit->value());
- }
- }
-
- /// Destroy System singleton to avoid valgrind from complaining
- System::destroy();
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Base/test/TestMeterCmd.cpp b/ecflow_4_0_7/Base/test/TestMeterCmd.cpp
deleted file mode 100644
index f7860e1..0000000
--- a/ecflow_4_0_7/Base/test/TestMeterCmd.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
- //============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #9 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <boost/test/unit_test.hpp>
-#include <boost/foreach.hpp>
-#include <string>
-#include <iostream>
-#include <fstream>
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "TestHelper.hpp"
-#include "System.hpp"
-
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( BaseTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_meter_cmd )
-{
- cout << "Base:: ...test_meter_cmd\n";
- // Create the defs file.
- // suite suite
- // family f
- // task t1
- // meter m 0 100 100
- // endfamily
- // endsuite
- Defs defs;
- string suite_f_t1 = "suite/f/t1";
- task_ptr t1 = Task::create("t1");
- std::string meter_name = "m";
- {
- t1->addMeter( Meter(meter_name,0,100,100));
- suite_ptr s = Suite::create("suite");
- family_ptr f = Family::create("f");
- f->addTask( t1 );
- s->addFamily(f);
- defs.addSuite( s );
- }
-
- // Meter which doesn't exist should be silently ignore
- int meter_value = 10;
- TestHelper::invokeRequest(&defs,
- Cmd_ptr( new MeterCmd(suite_f_t1,
- Submittable::DUMMY_JOBS_PASSWORD(),
- Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),
- 1,"FRED",meter_value)),
- false /* expect change number not to change */
- );
-
- /// Test setting meter value
- TestHelper::invokeRequest(&defs,Cmd_ptr( new MeterCmd(suite_f_t1,Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1,meter_name,meter_value)));
- const Meter& the_meter = t1->findMeter(meter_name);
- BOOST_CHECK_MESSAGE( !the_meter.empty(), "Meter not found");
- BOOST_CHECK_MESSAGE( the_meter.value() == meter_value, "Expected meter value " << meter_value << " but found " << the_meter.value());
-
-
- /// Set a meter value less than the current value.
- meter_value = 9;
- TestHelper::invokeRequest(&defs,Cmd_ptr( new MeterCmd(suite_f_t1,Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1,meter_name,meter_value)));
- BOOST_CHECK_MESSAGE( the_meter.value() == meter_value, "Expected meter value " << meter_value << " but found " << the_meter.value());
-
- /// Set a meter value greater than max meter, this should be ignored
- /// Avoid failing task, if meter, value is out of range. Just log a warning message
- meter_value = 2000;
- TestHelper::invokeRequest(&defs,Cmd_ptr( new MeterCmd(suite_f_t1,Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1,meter_name,meter_value))
- ,false /* expect change number not to change */);
- BOOST_CHECK_MESSAGE( the_meter.value() == 9, "Expected meter value 9 but found " << the_meter.value());
-
-
- /// Set to valid value
- meter_value = 20;
- TestHelper::invokeRequest(&defs,Cmd_ptr( new MeterCmd(suite_f_t1,Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1,meter_name,meter_value)));
- BOOST_CHECK_MESSAGE( the_meter.value() == meter_value, "Expected meter value " << meter_value << " but found " << the_meter.value());
-
- /// Destroy System singleton to avoid valgrind from complaining
- System::destroy();
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/Base/test/TestRequest.cpp b/ecflow_4_0_7/Base/test/TestRequest.cpp
deleted file mode 100644
index 16b6b50..0000000
--- a/ecflow_4_0_7/Base/test/TestRequest.cpp
+++ /dev/null
@@ -1,316 +0,0 @@
-//============================================================================
-// Name : Request
-// Author : Avi
-// Revision : $Revision: #128 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include "boost/make_shared.hpp"
-
-#include "MyDefsFixture.hpp"
-#include "ServerToClientResponse.hpp"
-#include "TestHelper.hpp"
-#include "SerializationTest.hpp"
-#include "DefsCmd.hpp"
-#include "SNodeCmd.hpp"
-#include "ErrorCmd.hpp"
-#include "StcCmd.hpp"
-#include "SStringCmd.hpp"
-#include "SServerLoadCmd.hpp"
-#include "GroupSTCCmd.hpp"
-#include "SSyncCmd.hpp"
-#include "SNewsCmd.hpp"
-#include "System.hpp"
-
-using namespace std;
-using namespace ecf;
-namespace fs = boost::filesystem;
-
-
-BOOST_FIXTURE_TEST_SUITE( BaseTestSuite, MyDefsFixture )
-
-// Can't delete the fixture defs, hence use a NULL deleter to avoid freeing memory twice.
-// Required since DefsCmd and LoadDefsCmd requires a shared_ptr.
-struct null_deleter { void operator()(void const *) const{} };
-
-
-static void populateCmdVec(std::vector<Cmd_ptr>& cmd_vec, std::vector<STC_Cmd_ptr>& stc_cmd_vec, MockServer* mock_server)
-{
- std::vector<std::string> suite_names; suite_names.push_back("suiteName");
- MyDefsFixture fixture;
- defs_ptr client_defs = fixture.create_defs();
-
- // Client --> Server commands
- // make sure begin cmd is first. As this will init calendar. + other commands rely on it
- // i.e RequeueNodeCmd assumes calendar has been initialized
- cmd_vec.push_back( Cmd_ptr( new ShowCmd()));
- cmd_vec.push_back( Cmd_ptr( new ServerVersionCmd()));
- cmd_vec.push_back( Cmd_ptr( new BeginCmd("suiteName"))); // must be first
- cmd_vec.push_back( Cmd_ptr( new BeginCmd("EmptySuite"))); // must be first
- cmd_vec.push_back( Cmd_ptr( new ReplaceNodeCmd("suiteName",false,client_defs, true)));
- cmd_vec.push_back( Cmd_ptr( new LoadDefsCmd(mock_server->defs(),true/*force*/)));
- cmd_vec.push_back( Cmd_ptr( new LogMessageCmd("LogMessageCmd")) );
- cmd_vec.push_back( Cmd_ptr( new LogCmd(LogCmd::CLEAR))); // server replies back OK/Error Cmd
- cmd_vec.push_back( Cmd_ptr( new LogCmd(LogCmd::GET))); // server replies back OK/Error | SStringCmd
- cmd_vec.push_back( Cmd_ptr( new LogCmd(LogCmd::PATH))); // server replies back Error |SStringCmd
- cmd_vec.push_back( Cmd_ptr( new CtsCmd(CtsCmd::RESTORE_DEFS_FROM_CHECKPT)));
- cmd_vec.push_back( Cmd_ptr( new CheckPtCmd()));
- cmd_vec.push_back( Cmd_ptr( new CtsCmd(CtsCmd::PING)));
- cmd_vec.push_back( Cmd_ptr( new CtsCmd(CtsCmd::DEBUG_SERVER_ON)));
- cmd_vec.push_back( Cmd_ptr( new CtsCmd(CtsCmd::DEBUG_SERVER_OFF)));
- cmd_vec.push_back( Cmd_ptr( new CtsCmd(CtsCmd::RESTART_SERVER)));
- cmd_vec.push_back( Cmd_ptr( new CtsCmd(CtsCmd::SHUTDOWN_SERVER)));
- cmd_vec.push_back( Cmd_ptr( new CtsCmd(CtsCmd::HALT_SERVER)));
- cmd_vec.push_back( Cmd_ptr( new CtsCmd(CtsCmd::TERMINATE_SERVER)));
- cmd_vec.push_back( Cmd_ptr( new CtsCmd(CtsCmd::RELOAD_WHITE_LIST_FILE)));
- cmd_vec.push_back( Cmd_ptr( new CtsCmd(CtsCmd::FORCE_DEP_EVAL)));
- cmd_vec.push_back( Cmd_ptr( new CtsCmd(CtsCmd::STATS)));
- cmd_vec.push_back( Cmd_ptr( new CtsCmd(CtsCmd::STATS_RESET)));
- cmd_vec.push_back( Cmd_ptr( new CtsCmd(CtsCmd::SUITES)));
- cmd_vec.push_back( Cmd_ptr( new CSyncCmd(CSyncCmd::NEWS,0,0,0)));
- cmd_vec.push_back( Cmd_ptr( new CSyncCmd(CSyncCmd::SYNC,0,0,0)));
- cmd_vec.push_back( Cmd_ptr( new CSyncCmd(0))); // SYNC_FULL
- cmd_vec.push_back( Cmd_ptr( new RequeueNodeCmd("/suiteName",RequeueNodeCmd::NO_OPTION)));
- cmd_vec.push_back( Cmd_ptr( new OrderNodeCmd("/suiteName",NOrder::ALPHA)));
- cmd_vec.push_back( Cmd_ptr( new RunNodeCmd("/suiteName", true/* force for test */, true /* for test */)));
- cmd_vec.push_back( Cmd_ptr( new PathsCmd(PathsCmd::SUSPEND,"EmptySuite")));
- cmd_vec.push_back( Cmd_ptr( new PathsCmd(PathsCmd::RESUME,"EmptySuite")));
- cmd_vec.push_back( Cmd_ptr( new PathsCmd(PathsCmd::KILL,"EmptySuite")));
- cmd_vec.push_back( Cmd_ptr( new PathsCmd(PathsCmd::STATUS,"EmptySuite")));
- cmd_vec.push_back( Cmd_ptr( new PathsCmd(PathsCmd::CHECK,"/suiteName")));
- cmd_vec.push_back( Cmd_ptr( new PathsCmd(PathsCmd::CHECK,""))); // check the full defs
- cmd_vec.push_back( Cmd_ptr( new PathsCmd(PathsCmd::EDIT_HISTORY,"/suiteName"))); // check the full defs
- cmd_vec.push_back( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::WHY,"/suiteName")));
- cmd_vec.push_back( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::GET,"/suiteName")));
- cmd_vec.push_back( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::GET_STATE,"/suiteName")));
- cmd_vec.push_back( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::MIGRATE,"/suiteName")));
- cmd_vec.push_back( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::CHECK_JOB_GEN_ONLY,"EmptySuite"))); // will *reset* begin
- cmd_vec.push_back( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::GET,""))); // return the full defs
- cmd_vec.push_back( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::GET_STATE,"")));
- cmd_vec.push_back( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::MIGRATE,"")));
- cmd_vec.push_back( Cmd_ptr( new ZombieCmd(ecf::User::FOB,"suiteName/familyName/taskName",Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),Submittable::DUMMY_JOBS_PASSWORD())));
- cmd_vec.push_back( Cmd_ptr( new ZombieCmd(ecf::User::FAIL,"suiteName/familyName/taskName",Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),Submittable::DUMMY_JOBS_PASSWORD())));
- cmd_vec.push_back( Cmd_ptr( new ZombieCmd(ecf::User::ADOPT,"suiteName/familyName/taskName",Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),Submittable::DUMMY_JOBS_PASSWORD())));
- cmd_vec.push_back( Cmd_ptr( new ZombieCmd(ecf::User::REMOVE,"suiteName/familyName/taskName",Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),Submittable::DUMMY_JOBS_PASSWORD())));
- cmd_vec.push_back( Cmd_ptr( new ZombieCmd(ecf::User::KILL,"suiteName/familyName/taskName",Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),Submittable::DUMMY_JOBS_PASSWORD())));
- cmd_vec.push_back( Cmd_ptr( new ClientHandleCmd(suite_names,true))); // register
- cmd_vec.push_back( Cmd_ptr( new ClientHandleCmd(1,suite_names,ClientHandleCmd::ADD))); // add
- cmd_vec.push_back( Cmd_ptr( new ClientHandleCmd(1,suite_names,ClientHandleCmd::REMOVE))); // remove
- cmd_vec.push_back( Cmd_ptr( new ClientHandleCmd(1, true))); // auto_add new suites
- cmd_vec.push_back( Cmd_ptr( new ClientHandleCmd(1))); // de-register/drop
- cmd_vec.push_back( Cmd_ptr( new InitCmd("suiteName/familyName/taskName",Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1)));
- cmd_vec.push_back( Cmd_ptr( new EventCmd("suiteName/familyName/taskName",Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1,"eventName")));
- cmd_vec.push_back( Cmd_ptr( new MeterCmd("suiteName/familyName/heir_familyName/taskName",Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1,"myMeter",100)));
- cmd_vec.push_back( Cmd_ptr( new CompleteCmd("suiteName/familyName/taskName",Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1)));
- cmd_vec.push_back( Cmd_ptr( new AbortCmd("suiteName/familyName/taskName",Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1)));
- cmd_vec.push_back( Cmd_ptr( new CtsWaitCmd("suiteName/familyName/taskName",Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1,"1 eq 1")));
- cmd_vec.push_back( Cmd_ptr( new LabelCmd("suiteName/familyName/taskName",Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1,"labelName","label value")));
- cmd_vec.push_back( Cmd_ptr( new ForceCmd("/suiteName","complete",true,true)));
- cmd_vec.push_back( Cmd_ptr( new FreeDepCmd("/suiteName")));
- cmd_vec.push_back( Cmd_ptr( new CFileCmd("/suiteName",CFileCmd::ECF, 10)));
- cmd_vec.push_back( Cmd_ptr( new CFileCmd("/suiteName",CFileCmd::JOB,100)));
- cmd_vec.push_back( Cmd_ptr( new CFileCmd("/suiteName",CFileCmd::JOBOUT,100)));
- cmd_vec.push_back( Cmd_ptr( new CFileCmd("/suiteName",CFileCmd::MANUAL,100)));
- cmd_vec.push_back( Cmd_ptr( new EditScriptCmd()));
- cmd_vec.push_back( Cmd_ptr( new AlterCmd("/suiteName/t1",AlterCmd::ADD_DATE,"12.*.*")));
- cmd_vec.push_back( Cmd_ptr( new AlterCmd("/suiteName/t1",AlterCmd::ADD_DAY,"sunday")));
- cmd_vec.push_back( Cmd_ptr( new AlterCmd("/suiteName/t1",AlterCmd::ADD_TIME,"+12:00")));
- cmd_vec.push_back( Cmd_ptr( new AlterCmd("/suiteName/t1",AlterCmd::ADD_TIME,"+10:00 20:00 00:30")));
- cmd_vec.push_back( Cmd_ptr( new AlterCmd("/suiteName/t1",AlterCmd::ADD_TODAY,"10:00 20:00 00:30")));
- cmd_vec.push_back( Cmd_ptr( new PlugCmd()));
-
- boost::shared_ptr<GroupCTSCmd> theGroupCmd = boost::make_shared<GroupCTSCmd>();
- theGroupCmd->addChild( Cmd_ptr( new BeginCmd("suiteName")) );
- theGroupCmd->addChild( Cmd_ptr( new BeginCmd("EmptySuite")) );
- theGroupCmd->addChild( Cmd_ptr( new ServerVersionCmd()) );
- theGroupCmd->addChild( Cmd_ptr( new CtsCmd(CtsCmd::PING)) );
- theGroupCmd->addChild( Cmd_ptr( new CtsCmd(CtsCmd::RESTART_SERVER)) );
- theGroupCmd->addChild( Cmd_ptr( new CtsCmd(CtsCmd::SHUTDOWN_SERVER)) );
- theGroupCmd->addChild( Cmd_ptr( new CtsCmd(CtsCmd::HALT_SERVER)) );
- theGroupCmd->addChild( Cmd_ptr( new CtsCmd(CtsCmd::TERMINATE_SERVER)) );
- theGroupCmd->addChild( Cmd_ptr( new CtsCmd(CtsCmd::RELOAD_WHITE_LIST_FILE)) );
- theGroupCmd->addChild( Cmd_ptr( new CtsCmd(CtsCmd::SERVER_LOAD)) );
- theGroupCmd->addChild( Cmd_ptr( new PathsCmd(PathsCmd::SUSPEND,"EmptySuite")) );
- theGroupCmd->addChild( Cmd_ptr( new PathsCmd(PathsCmd::RESUME,"EmptySuite")) );
- theGroupCmd->addChild( Cmd_ptr( new PathsCmd(PathsCmd::KILL,"EmptySuite")) );
- theGroupCmd->addChild( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::GET,"EmptySuite")) );
- theGroupCmd->addChild( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::GET_STATE,"EmptySuite")) );
- theGroupCmd->addChild( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::MIGRATE,"EmptySuite")) );
- theGroupCmd->addChild( Cmd_ptr( new ShowCmd()));
- theGroupCmd->addChild( Cmd_ptr( new ZombieCmd(ecf::User::FOB,"suiteName/familyName/taskName",Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),Submittable::DUMMY_JOBS_PASSWORD())));
- theGroupCmd->addChild( Cmd_ptr( new ZombieCmd(ecf::User::FAIL,"suiteName/familyName/taskName",Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),Submittable::DUMMY_JOBS_PASSWORD())));
- theGroupCmd->addChild( Cmd_ptr( new ZombieCmd(ecf::User::ADOPT,"suiteName/familyName/taskName",Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),Submittable::DUMMY_JOBS_PASSWORD())));
- theGroupCmd->addChild( Cmd_ptr( new ZombieCmd(ecf::User::REMOVE,"suiteName/familyName/taskName",Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),Submittable::DUMMY_JOBS_PASSWORD())));
- theGroupCmd->addChild( Cmd_ptr( new RequeueNodeCmd("/suiteName",RequeueNodeCmd::NO_OPTION)) );
- theGroupCmd->addChild( Cmd_ptr( new OrderNodeCmd("/suiteName",NOrder::ALPHA)) );
- theGroupCmd->addChild( Cmd_ptr( new RunNodeCmd("/suiteName",true/*force for test*/, true /* for test */)) );
- theGroupCmd->addChild( Cmd_ptr( new InitCmd("suiteName/familyName/taskName",Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1)) );
- theGroupCmd->addChild( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::CHECK_JOB_GEN_ONLY,"EmptySuite")) ); // will *reset* begin
- theGroupCmd->addChild( Cmd_ptr( new EventCmd("suiteName/familyName/taskName",Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1,"eventName")) );
- theGroupCmd->addChild( Cmd_ptr( new MeterCmd("suiteName/familyName/heir_familyName/taskName",Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1,"myMeter",100)) );
- theGroupCmd->addChild( Cmd_ptr( new CompleteCmd("suiteName/familyName/taskName",Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1)) );
- theGroupCmd->addChild( Cmd_ptr( new AbortCmd("suiteName/familyName/taskName",Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1)) );
- theGroupCmd->addChild( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::GET)) );
- theGroupCmd->addChild( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::GET_STATE)) );
- theGroupCmd->addChild( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::MIGRATE)) );
- theGroupCmd->addChild( Cmd_ptr( new CtsCmd(CtsCmd::FORCE_DEP_EVAL)) ); // will force deletion of any Node which has autocomplete
- theGroupCmd->addChild( Cmd_ptr( new LoadDefsCmd(mock_server->defs(), true/*force*/)) );
- theGroupCmd->addChild( Cmd_ptr( new LogCmd(LogCmd::GET)) );
- theGroupCmd->addChild( Cmd_ptr( new LogCmd(LogCmd::CLEAR)) );
- theGroupCmd->addChild( Cmd_ptr( new LogMessageCmd("LogMessageCmd")) );
- theGroupCmd->addChild( Cmd_ptr( new ForceCmd("/suiteName","complete",true,true)) );
- theGroupCmd->addChild( Cmd_ptr( new FreeDepCmd("/suiteName",false,true)) );
-
- BOOST_CHECK_MESSAGE(theGroupCmd->isWrite(),"Expected isWrite() to return true");
- BOOST_CHECK_MESSAGE(theGroupCmd->get_cmd(),"Expected get_cmd() to return true");
- BOOST_CHECK_MESSAGE(theGroupCmd->task_cmd(),"Expected task_cmd() to return true");
- BOOST_CHECK_MESSAGE(theGroupCmd->terminate_cmd(),"Expected terminate_cmd() to return true");
- BOOST_CHECK_MESSAGE(theGroupCmd->group_cmd(),"Expected group_cmd() to return true");
- cmd_vec.push_back( theGroupCmd );
-
-
- // Server --> Client commands
- stc_cmd_vec.push_back( STC_Cmd_ptr( new ErrorCmd("The error")));
- stc_cmd_vec.push_back( STC_Cmd_ptr( new StcCmd(StcCmd::OK)));
- stc_cmd_vec.push_back( STC_Cmd_ptr( new StcCmd(StcCmd::BLOCK_CLIENT_SERVER_HALTED)));
- stc_cmd_vec.push_back( STC_Cmd_ptr( new StcCmd(StcCmd::BLOCK_CLIENT_ON_HOME_SERVER)));
- stc_cmd_vec.push_back( STC_Cmd_ptr( new SStringCmd("Dummy contents")));
- stc_cmd_vec.push_back( STC_Cmd_ptr( new SServerLoadCmd("/path/to/log_file")));
- stc_cmd_vec.push_back( STC_Cmd_ptr( new SSyncCmd(0,0,0,mock_server )));
- stc_cmd_vec.push_back( STC_Cmd_ptr( new SNewsCmd(0,0,0,mock_server)));
- stc_cmd_vec.push_back( STC_Cmd_ptr( new DefsCmd(mock_server)));
- stc_cmd_vec.push_back( STC_Cmd_ptr( new SNodeCmd(mock_server,node_ptr()) ));
-
- boost::shared_ptr<GroupSTCCmd> theSTCGroupCmd = boost::make_shared<GroupSTCCmd>() ;
- theSTCGroupCmd->addChild( STC_Cmd_ptr( new ErrorCmd()) );
- theSTCGroupCmd->addChild( STC_Cmd_ptr( new StcCmd(StcCmd::OK)) );
- theSTCGroupCmd->addChild( STC_Cmd_ptr( new StcCmd(StcCmd::BLOCK_CLIENT_SERVER_HALTED)) );
- theSTCGroupCmd->addChild( STC_Cmd_ptr( new StcCmd(StcCmd::BLOCK_CLIENT_ON_HOME_SERVER)) );
- theSTCGroupCmd->addChild( STC_Cmd_ptr( new SStringCmd()) );
- theSTCGroupCmd->addChild( STC_Cmd_ptr( new SServerLoadCmd()) );
- theSTCGroupCmd->addChild( STC_Cmd_ptr( new DefsCmd(mock_server)));
- theSTCGroupCmd->addChild( STC_Cmd_ptr( new SNodeCmd(mock_server,node_ptr())));
- stc_cmd_vec.push_back( theSTCGroupCmd );
-}
-
-static void test_persistence(const Defs& theFixtureDefs )
-{
- Defs* fixtureDefs = const_cast<Defs*>(&theFixtureDefs);
- MockServer mockServer(fixtureDefs); // creates shared ptr with a NULL deleter
-
- std::vector<Cmd_ptr> cmd_vec;
- std::vector<STC_Cmd_ptr> stc_cmd_vec;
- populateCmdVec(cmd_vec, stc_cmd_vec, &mockServer);
-
- int getRequest = 0;
- int terminateRequest = 0;
- int groupRequest = 0;
- BOOST_FOREACH(const Cmd_ptr& theCmd, cmd_vec) {
-
- // std::cout << "TheCmd "; theCmd->print(std::cout); std::cout << "\n";
- if (theCmd->connect_to_different_servers()) {
- BOOST_CHECK_MESSAGE(theCmd->task_cmd(),"Currently only tasks commands, are allowed to connect to different servers");
- }
-
- const ClientToServerRequest cmd_request(theCmd); // MUST be const to avoid AIX compiler warning
- {
- if (theCmd.get()->handleRequestIsTestable()) {
- // test handleRequest while were at it.
- // Avoid TERMINATE_SERVER cmd as this will prematurely cause an exit, wont appear as an error
- // cerr << "cmd_request = " << cmd_request << "\n";
- try {
- STC_Cmd_ptr ok_or_error_cmd = cmd_request.handleRequest(&mockServer);
- if (ok_or_error_cmd) {
- // Commands like ErrorCmd, OkCmd don't return a cmd_ptr from handleRequest
- // those that do, check OkCmd returned, else if ErrorCmd show the error
- BOOST_CHECK_MESSAGE(ok_or_error_cmd->ok(),"Request '" << cmd_request << "' returned " << ok_or_error_cmd->error());
- }
- }
- catch (std::exception& e ) {
- BOOST_CHECK_MESSAGE(false,"Unexpected exception : " << e.what() << " : " << cmd_request ) ;
- }
- }
- }
-
- BOOST_REQUIRE_NO_THROW(ecf::save("request.txt",cmd_request));
-
- ClientToServerRequest restoredRequest;
- BOOST_REQUIRE_NO_THROW(ecf::restore("request.txt", restoredRequest));
- BOOST_REQUIRE_MESSAGE(restoredRequest == cmd_request, "restoredRequest " << restoredRequest << " cmd_request " << cmd_request);
-
- if (restoredRequest.getRequest()) getRequest++;
- if (restoredRequest.terminateRequest()) terminateRequest++;
- if (restoredRequest.groupRequest()) groupRequest++;
- fs::remove("request.txt");
- }
-
- BOOST_CHECK_MESSAGE(getRequest ==3," expected 3 get Request but found " << getRequest );
- BOOST_CHECK_MESSAGE(terminateRequest ==2," expected 2 terminate Request but found " << terminateRequest );
- BOOST_CHECK_MESSAGE(groupRequest ==1," expected 1 group Request but found " << groupRequest );
-
-
- BOOST_FOREACH(const STC_Cmd_ptr& theCmd, stc_cmd_vec) {
-// std::cout << "TheCmd "; theCmd->print(std::cout); std::cout << "\n";
-
- const ServerToClientResponse cmd_request(theCmd); // MUST be const to avoid AIX compiler warning
- BOOST_REQUIRE_NO_THROW(ecf::save("request.txt",cmd_request));
-
- ServerToClientResponse restoredRequest;
- BOOST_REQUIRE_NO_THROW(ecf::restore("request.txt", restoredRequest));
- BOOST_REQUIRE_MESSAGE(restoredRequest == cmd_request, "restoredRequest " << restoredRequest << " cmd_request " << cmd_request);
- fs::remove("request.txt");
- }
-}
-
-#if defined(BINARY_ARCHIVE)
-BOOST_AUTO_TEST_CASE( test_all_request_persistence_binary )
-{
- cout << "Base:: ...test_all_request_persistence_binary\n";
- test_persistence( fixtureDefsFile());
-}
-#elif defined(PORTABLE_BINARY_ARCHIVE)
-BOOST_AUTO_TEST_CASE( test_all_request_persistence_portable_binary )
-{
- cout << "Base:: ...test_all_request_persistence_portable_binary\n";
- test_persistence( fixtureDefsFile() );
-}
-#elif defined(EOS_PORTABLE_BINARY_ARCHIVE)
-BOOST_AUTO_TEST_CASE( test_all_request_persistence_eos_portable_binary )
-{
- cout << "Base:: ...test_all_request_persistence_eos_portable_binary\n";
- test_persistence( fixtureDefsFile() );
-}
-#else
-BOOST_AUTO_TEST_CASE( test_all_request_persistence_text )
-{
- cout << "Base:: ...test_all_request_persistence_text\n";
- test_persistence( fixtureDefsFile());
-}
-#endif
-
-BOOST_AUTO_TEST_CASE( test_request_authenticate )
-{
- cout << "Base:: ...test_request_authenticate\n";
-
- // the path "suiteName0/familyName0/taskName0" must exist in the defsfile_ fixture
- Cmd_ptr cmd_ptr(new InitCmd("suiteName/familyName/taskName",Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1));
-
- // The invokeRequest will return check if the path and password exist in the Node tree
- TestHelper::invokeRequest(&defsfile_, cmd_ptr);
-
- /// Destroy System singleton to avoid valgrind from complaining
- System::destroy();
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/Base/test/TestRequeueNodeCmd.cpp b/ecflow_4_0_7/Base/test/TestRequeueNodeCmd.cpp
deleted file mode 100644
index 4bb5e92..0000000
--- a/ecflow_4_0_7/Base/test/TestRequeueNodeCmd.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #22 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <boost/test/unit_test.hpp>
-
-#include "ClientToServerCmd.hpp"
-#include "TestHelper.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( BaseTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_requeue_with_suspend )
-{
- cout << "Base:: ...test_requeue_with_suspend\n";
-
- defs_ptr the_defs = Defs::create();
- suite_ptr s1 = the_defs->add_suite( "s1" ) ;
- family_ptr f1 = s1->add_family( "f1" ) ;
- task_ptr t1 = f1->add_task("t1");
- task_ptr t2 = f1->add_task("t2");
- task_ptr t3 = f1->add_task("t3");
- t3->addDefStatus(DState::SUSPENDED);
-
- the_defs->beginAll();
-
- // After begin/requeue we must honour defs status
- BOOST_CHECK_MESSAGE(t3->isSuspended(),"Expected node to be suspended");
-
- // Suspend all nodes
- TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new PathsCmd(PathsCmd::SUSPEND,s1->absNodePath())));
- TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new PathsCmd(PathsCmd::SUSPEND,f1->absNodePath())));
- TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new PathsCmd(PathsCmd::SUSPEND,t1->absNodePath())));
- TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new PathsCmd(PathsCmd::SUSPEND,t2->absNodePath())));
- BOOST_CHECK_MESSAGE(s1->isSuspended(),"Expected node to be suspended");
- BOOST_CHECK_MESSAGE(f1->isSuspended(),"Expected node to be suspended");
- BOOST_CHECK_MESSAGE(t1->isSuspended(),"Expected node to be suspended");
- BOOST_CHECK_MESSAGE(t2->isSuspended(),"Expected node to be suspended");
-
- // Re-queue of the nodes, that are suspended, they should *stay* suspended
- TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new RequeueNodeCmd(t1->absNodePath())));
- BOOST_CHECK_MESSAGE(t1->isSuspended(),"Expected node to stay suspended");
-
- // Now re-queue the top level suite, this is suspended.
- // This should stay suspended *BUT* child nodes which are suspend should be cleared
- TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new RequeueNodeCmd(s1->absNodePath())));
- BOOST_CHECK_MESSAGE(s1->isSuspended(),"Suite should stay suspend");
- BOOST_CHECK_MESSAGE(!f1->isSuspended(),"Expected child nodes to be un-suspended");
- BOOST_CHECK_MESSAGE(!t1->isSuspended(),"Expected child nodes to be un-suspended");
- BOOST_CHECK_MESSAGE(!t2->isSuspended(),"Expected child nodes to be un-suspended");
- BOOST_CHECK_MESSAGE(t3->isSuspended(), "Requeue must honour def status");
-}
-
-BOOST_AUTO_TEST_CASE( test_requeue_family_clears_children_SUP_909 )
-{
- cout << "Base:: ...test_requeue_family_clears_children_SUP_909\n";
-
- // suite s1
- // family f1
- // task t1
- // time 23:30
- // endFamily
- // endsuite
- // make sure time is set *before* 23:30, so that time dependency holds the task
-
- defs_ptr the_defs = Defs::create();
- suite_ptr suite = the_defs->add_suite( "s1" ) ;
- ClockAttr clockAttr(15,12,2010,false);
- clockAttr.set_gain(9/*hour*/,30/*minutes*/); // start at 09:30
- suite->addClock( clockAttr );
-
- family_ptr f1 = suite->add_family( "f1" ) ;
- task_ptr t1 = f1->add_task("t1");
- t1->addTime( TimeAttr(23,30));
-
- const TimeSeries& theTime = t1->timeVec().back().time_series();
-
- the_defs->beginAll();
-
- BOOST_CHECK_MESSAGE(theTime.is_valid(), "Expected time to be holding");
- TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",true /*recursive */, false /* set Repeat to last value */)));
- TestHelper::test_state(t1,NState::COMPLETE);
- BOOST_CHECK_MESSAGE( !theTime.is_valid(), "Expected time to have expired");
- BOOST_CHECK_MESSAGE( t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be set");
-
- // Now reque the family, this should clear the time, so that it now holding again
- TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new RequeueNodeCmd(f1->absNodePath())));
- TestHelper::test_state(f1,NState::QUEUED);
- TestHelper::test_state(t1,NState::QUEUED);
- BOOST_CHECK_MESSAGE( theTime.is_valid(), "Expected time to be reset");
- BOOST_CHECK_MESSAGE( !t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear");
-}
-
-BOOST_AUTO_TEST_CASE( test_repeat_based_requeue_clears_children )
-{
- cout << "Base:: ...test_repeat_based_requeue_clears_children\n";
-
- // suite s1
- // repeat day 1
- // family f1
- // task t1
- // time 23:30
- // endfamily
- // endsuite
- // make sure time is set *before* 23:30, so that time dependency holds the task
-
- defs_ptr the_defs = Defs::create();
- suite_ptr suite = the_defs->add_suite( "s1" ) ;
- ClockAttr clockAttr(15,12,2010,false);
- clockAttr.set_gain(9/*hour*/,30/*minutes*/); // start at 09:30
- suite->addClock( clockAttr );
-
- suite->addRepeat( RepeatDay(1) );
-
- family_ptr f1 = suite->add_family( "f1" ) ;
- task_ptr t1 = f1->add_task("t1");
- t1->addTime( TimeAttr(23,30));
-
- const TimeSeries& theTime = t1->timeVec().back().time_series();
-
- the_defs->beginAll();
-
- BOOST_CHECK_MESSAGE(theTime.is_valid(), "Expected time to be holding");
-
- // Forcing task t1 to complete, should cause the top, level repeat to REQEUE
- TestHelper::invokeRequest(the_defs.get(),Cmd_ptr( new ForceCmd(t1->absNodePath(),"complete",true /*recursive */, false /* set Repeat to last value */)));
-
- TestHelper::test_state(t1,NState::QUEUED);
- BOOST_CHECK_MESSAGE( theTime.is_valid(), "Expected time to be holding");
- BOOST_CHECK_MESSAGE( !t1->get_flag().is_set(ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP),"Expected ecf::Flag::NO_REQUE_IF_SINGLE_TIME_DEP to be clear");
-}
-
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Base/test/TestResolveDependencies.cpp b/ecflow_4_0_7/Base/test/TestResolveDependencies.cpp
deleted file mode 100644
index 737900d..0000000
--- a/ecflow_4_0_7/Base/test/TestResolveDependencies.cpp
+++ /dev/null
@@ -1,277 +0,0 @@
-#define BOOST_TEST_MODULE TestBase
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #37 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <iostream>
-#include <fstream>
-
-#include <boost/test/unit_test.hpp>
-#include <boost/foreach.hpp>
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "ExprAst.hpp"
-#include "TestHelper.hpp"
-#include "JobsParam.hpp"
-#include "Jobs.hpp"
-#include "System.hpp"
-
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( BaseTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_resolve_dependencies )
-{
- cout << "Base:: ...test_resolve_dependencies\n";
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- // Create the defs file
- // suite suite
- // family f
- // task t
- // meter step 0 240 120
- // task tt
- // complete t:step ge 120
- // trigger t == complete
- // endfamily
- // endsuite
- Defs defs;
- std::string metername = "step";
- std::string suitename = "suite";
- std::string familyname = "f";
- {
- suite_ptr suite = defs.add_suite( suitename );
- family_ptr fam = suite->add_family( familyname );
-
- task_ptr task = fam->add_task( "t" );
- task->addMeter( Meter(metername,0,240,120) );
-
- task_ptr task_tt = fam->add_task( "tt" );
- task_tt->add_complete( "t:step ge 120");
- task_tt->add_trigger( "t == complete" );
-
- std::string errorMsg;
- BOOST_CHECK_MESSAGE( defs.checkInvariants(errorMsg), errorMsg);
- }
-
-
- // Ensure initial state is unknown
- string suite_f_t = "/suite/f/t";
- string suite_f_tt = "/suite/f/tt";
- node_ptr node_t = defs.findAbsNode(suite_f_t);
- node_ptr node_tt = defs.findAbsNode(suite_f_tt);
- suite_ptr suite = defs.findSuite(suitename);
- family_ptr fam = suite->findFamily(familyname);
- BOOST_CHECK_MESSAGE( suite->state() == NState::UNKNOWN, "expected state NState::UNKNOWN, but found to be " << NState::toString(suite->state()));
- BOOST_CHECK_MESSAGE( node_t->state() == NState::UNKNOWN, "expected state NState::UNKNOWN, but found to be " << NState::toString(node_t->state()));
- BOOST_CHECK_MESSAGE( node_tt->state() == NState::UNKNOWN, "expected state NState::UNKNOWN, but found to be " << NState::toString(node_tt->state()));
- BOOST_CHECK_MESSAGE( fam->state() == NState::UNKNOWN, "expected state NState::UNKNOWN, but found to be " << NState::toString(fam->state()));
-
-
- // ***********************************************************************
- // Create a request to begin suite
- // make sure chosen suite can begin to resolve dependencies.
- // beginning the suite will :
- // 1/ set all children to the QUEUED state
- // 2/ Begin job submission, and hence changes state to ACTIVE for submitted jobs
- {
- TestHelper::invokeRequest(&defs,Cmd_ptr( new BeginCmd(suitename)));
- BOOST_CHECK_MESSAGE( suite->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(suite->state()));
- BOOST_CHECK_MESSAGE( fam->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(fam->state()));
- BOOST_CHECK_MESSAGE( node_t->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(node_t->state()));
- BOOST_CHECK_MESSAGE( node_tt->state() == NState::QUEUED, "expected state NState::QUEUED, but found to be " << NState::toString(node_tt->state()));
- }
-
- //*******************************************************************************
- // Resolve dependencies.
- // task t
- // meter step 0 240 120 EXPECTED to be sumbitted
- //
- // task tt
- // complete t:step ge 120 Expected to HOLD, since we ain't done nothing yet
- // trigger t == complete
- {
- JobsParam jobsParam; // create jobs = false, spawn jobs = false
- Jobs jobs(&defs);
- BOOST_CHECK_MESSAGE( jobs.generate(jobsParam),jobsParam.getErrorMsg());
- BOOST_CHECK_MESSAGE( jobsParam.submitted().size() == 0, "Expected 0 task to submit but found " << jobsParam.submitted().size());
- BOOST_CHECK_MESSAGE( node_t->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(node_t->state()));
- BOOST_CHECK_MESSAGE( node_tt->state() == NState::QUEUED,"expected state NState::QUEUED, but found to be " << NState::toString(node_tt->state()));
- }
-
- //**********************************************************************
- // Create a request to set the Meter node t. This should force node tt
- // to complete immediately
- {
- int meterValue = 120;
- TestHelper::invokeRequest(&defs, Cmd_ptr( new MeterCmd(suite_f_t,Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1,metername,meterValue)));
- TestHelper::invokeRequest(&defs, Cmd_ptr( new CtsCmd( CtsCmd::FORCE_DEP_EVAL)));
- const Meter& theMeter = node_t->findMeter(metername);
- BOOST_CHECK_MESSAGE( !theMeter.empty(), "Could not find the meter ");
- BOOST_CHECK_MESSAGE( theMeter.value() == meterValue , "Meter value not set");
-
- BOOST_CHECK_MESSAGE( node_t->state() == NState::ACTIVE, "expected state NState::ACTIVE, but found to be " << NState::toString(node_t->state()));
- BOOST_CHECK_MESSAGE( node_tt->state() == NState::COMPLETE,"expected state NState::COMPLETE, but found to be " << NState::toString(node_tt->state()));
-
- }
-
- {
- std::string errorMsg;
- BOOST_CHECK_MESSAGE( defs.checkInvariants(errorMsg), errorMsg);
- }
-
- /// Destroy System singleton to avoid valgrind from complaining
- System::destroy();
-}
-
-BOOST_AUTO_TEST_CASE( test_trigger_after_delete )
-{
- cout << "Base:: ...test_trigger_after_delete\n";
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- // Create the defs file
- // suite suite1 # the limit we want delete
- // family f
- // task t0
- // defstatus complete
- // task t1
- // event event
- // task t2
- // meter meter 0 100 100
- // task t3
- // edit user_var 1
- // task t4
- // repeat integer repeat_var 0 10 2
- // endfamily
- // endsuite
- // suite suite2
- // family f
- // task t0
- // trigger /suite1/f/t0 == complete
- // task t1
- // trigger /suite1/f/t1:event == set
- // task t2
- // trigger /suite1/f/t2:meter == 10
- // task t3
- // trigger /suite1/f/t2:user_var == 1
- // task t4
- // trigger /suite1/f/t2:repeat_var == 2
- // endfamily
- // endsuite
- //
- // In this test case all triggers in suite2 will evalate true, we then delete suite1 and
- // all the triggers should evaluate false; This is used to test the shared ptr in
- // the expression, which hold the reference nodes. When the reference nodes are deleted
- // then the expression should not evaluate
- Defs defs;
- {
- suite_ptr suite = Suite::create("suite1" );
- family_ptr f = Family::create("f" );
- task_ptr t0 = Task::create("t0" );
- task_ptr t1 = Task::create("t1" );
- task_ptr t2 = Task::create("t2" );
- task_ptr t3 = Task::create("t3" );
- task_ptr t4 = Task::create("t4" );
- t0->addDefStatus(DState::COMPLETE);
- t1->addEvent(Event(0,"event"));
- t2->addMeter(Meter("meter",0,100,100));
- t3->addVariable(Variable("user_var","1"));
- t4->addRepeat(RepeatInteger("repeat_var",0,10,2));
-
- f->addTask(t0);
- f->addTask(t1);
- f->addTask(t2);
- f->addTask(t3);
- f->addTask(t4);
- suite->addFamily(f);
- defs.addSuite( suite );
- }
- {
- suite_ptr suite = Suite::create("suite2" );
- family_ptr f = Family::create("f" );
- task_ptr t0 = Task::create("t0" );
- task_ptr t1 = Task::create("t1" );
- task_ptr t2 = Task::create("t2" );
- task_ptr t3 = Task::create("t3" );
- task_ptr t4 = Task::create("t4" );
- t0->add_trigger("/suite1/f/t0 == complete");
- t1->add_trigger("/suite1/f/t1:event == set");
- t2->add_trigger("/suite1/f/t2:meter == 10");
- t3->add_trigger("/suite1/f/t3:user_var == 1");
- t4->add_trigger("/suite1/f/t4:repeat_var == 2");
-
- f->addTask(t0);
- f->addTask(t1);
- f->addTask(t2);
- f->addTask(t3);
- f->addTask(t4);
- suite->addFamily(f);
- defs.addSuite( suite );
- }
-
- // begin. This will reset all attributes
- defs.beginAll();
-
- // setup attrbutes in suite1 so that evalaution will succeed in suite 2
- // *** this must be in its own scope otherwise the shared_ptr will keep the node alive
- {
- node_ptr t1 = defs.findAbsNode("/suite1/f/t1"); t1->changeEvent("event","set");
- node_ptr t2 = defs.findAbsNode("/suite1/f/t2"); t2->changeMeter("meter",10);
- node_ptr t4 = defs.findAbsNode("/suite1/f/t4"); t4->changeRepeat("2");
- // cout << defs;
- }
-
- // evalate the triggers in suite2
- {
- node_ptr suite2 = defs.findAbsNode("/suite2");
- std::vector<task_ptr> suite2_tasks;
- suite2->get_all_tasks(suite2_tasks);
- BOOST_REQUIRE_MESSAGE(suite2_tasks.size() == 5, "Expected 5 tasks on suite2 but found " << suite2_tasks.size());
-
- for(size_t i = 0; i < suite2_tasks.size(); i++) {
- BOOST_REQUIRE_MESSAGE( suite2_tasks[i]->triggerAst()->evaluate(), "Expected task " << suite2_tasks[i]->absNodePath() << " to evaluate");
- }
- }
-
-
- // Ok Now delete suite1,
- // *** It is extremely important that shared_ptr for '/suite1' is in its own
- // *** scope, otherwise it will keep the 'suite' live, and NOT delete the limits
- {
- node_ptr suite1 = defs.findAbsNode("/suite1");
- BOOST_REQUIRE_MESSAGE( suite1.get(), "Could not find the suite we want to delete?");
- BOOST_REQUIRE_MESSAGE( defs.deleteChild(suite1.get()), "Deletion failed?");
- BOOST_REQUIRE_MESSAGE( !defs.findAbsNode("/suite1").get(), "Deletion failed?");
- }
-
- // revaluate the triggers in suite2. This should fail, since we have delete suite1
- {
- node_ptr suite2 = defs.findAbsNode("/suite2");
- std::vector<task_ptr> suite2_tasks;
- suite2->get_all_tasks(suite2_tasks);
- BOOST_REQUIRE_MESSAGE(suite2_tasks.size() == 5, "Expected 5 tasks on suite2 but found " << suite2_tasks.size());
-
- for(size_t i = 0; i < suite2_tasks.size(); i++) {
- BOOST_REQUIRE_MESSAGE( !suite2_tasks[i]->triggerAst()->evaluate(), "Expected task " << suite2_tasks[i]->absNodePath() << " to fail evaluation");
- }
- }
-
- /// Destroy System singleton to avoid valgrind from complaining
- System::destroy();
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/Base/test/TestSSyncCmd.cpp b/ecflow_4_0_7/Base/test/TestSSyncCmd.cpp
deleted file mode 100644
index 2bb6988..0000000
--- a/ecflow_4_0_7/Base/test/TestSSyncCmd.cpp
+++ /dev/null
@@ -1,383 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #40 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <boost/test/unit_test.hpp>
-#include <boost/function.hpp>
-
-#include "ClientToServerCmd.hpp"
-#include "ServerToClientCmd.hpp"
-#include "MyDefsFixture.hpp"
-#include "MockServer.hpp"
-#include "TestHelper.hpp"
-#include "SSyncCmd.hpp"
-#include "SNewsCmd.hpp"
-#include "Ecf.hpp"
-#include "NodeFwd.hpp"
-#include "SuiteChanged.hpp"
-#include "ChangeMgrSingleton.hpp"
-#include "CalendarUpdateParams.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-
-
-BOOST_AUTO_TEST_SUITE( BaseTestSuite )
-
-/// define a function which returns nothing, and takes a defs_ptr parameter
-typedef boost::function<void (defs_ptr)> defs_change_cmd;
-
-/// Re-use the same test scaffold to modify and then resync, by passing
-/// in a function that will modify the defs
-static void test_sync_scaffold(
- defs_change_cmd the_defs_change_command,
- const std::string& test_name,
- bool full_sync = false,
- bool start_with_begin = false)
-{
- MyDefsFixture clientFixture;
- MyDefsFixture serverFixture;
- defs_ptr server_defs = serverFixture.create_defs();
- if ( start_with_begin ) server_defs->beginAll();
- server_defs->set_server().set_state( SState::HALTED); // if defs default state is RUNNING, whereas for server it is HALTED
-
- ServerReply server_reply;
- defs_ptr client_defs = clientFixture.create_defs();
- if ( start_with_begin ) client_defs->beginAll();
- client_defs->set_server().set_state( SState::HALTED); // if defs default state is RUNNING, whereas for server it is HALTED
- server_reply.set_client_defs( client_defs );
-
-
- Ecf::set_debug_equality(true); // only has affect in DEBUG build
- BOOST_CHECK_MESSAGE( *server_defs == *server_reply.client_defs(),"Test:" << test_name << ": Starting point client and server defs should be the same");
- Ecf::set_debug_equality(false);
-
- // Get change number before any changes
- unsigned int client_state_change_no = Ecf::state_change_no();
- unsigned int client_modify_change_no = Ecf::modify_change_no();
-
- // make some change to the server
- {
- Ecf::set_server(true);
-
- the_defs_change_command(server_defs);
-
- std::string error_msg;
- BOOST_REQUIRE_MESSAGE( server_defs->checkInvariants(error_msg),"Test:" << test_name << ": Invariants failed: " << error_msg);
- BOOST_REQUIRE_MESSAGE( !(*server_reply.client_defs() == *server_defs),"Test:" << test_name << ": Expected client and server defs to differ\n" << *server_reply.client_defs() << "\n" << "server defs = " << *server_defs);
- Ecf::set_server(false);
- }
-
- MockServer mock_server(server_defs);
- unsigned int client_handle = 0;
- SNewsCmd news_cmd(client_handle, client_state_change_no, client_modify_change_no, &mock_server );
- SSyncCmd cmd(client_handle, client_state_change_no, client_modify_change_no, &mock_server );
-
- std::string error_msg;
- BOOST_REQUIRE_MESSAGE( server_defs->checkInvariants(error_msg),"Test:" << test_name << ": Invariants failed: " << error_msg);
- BOOST_CHECK_MESSAGE( news_cmd.get_news(), "Test:" << test_name << ": Expected server to change");
- BOOST_CHECK_MESSAGE( cmd.do_sync( server_reply ),"Test:" << test_name << ": Expected server to change");
- BOOST_CHECK_MESSAGE( server_reply.in_sync(), "Test:" << test_name << ": Expected server to change");
- BOOST_CHECK_MESSAGE( server_reply.full_sync() == full_sync,"Test:" << test_name << ": Expected sync not as expected");
-
- error_msg.clear();
- BOOST_REQUIRE_MESSAGE( server_reply.client_defs()->checkInvariants(error_msg),"Test:" << test_name << ": Invariants failed: " << error_msg);
-
- Ecf::set_debug_equality(true);
- BOOST_CHECK_MESSAGE( *server_defs == *server_reply.client_defs(),"Test:" << test_name << ": Server and client should be same after sync" );
- Ecf::set_debug_equality(false);
-}
-
-// The modifiers
-void delete_some_attributes(defs_ptr defs)
-{
- std::vector<Task*> tasks;
- defs->getAllTasks(tasks);
- BOOST_FOREACH(Task* task, tasks) {
-
- SuiteChanged1 changed(task->suite());
-
- /// Take a copy, of the objects we want to delete. since there are returned by reference
- std::vector<Event> events = task->events();
- std::vector<Meter> meters = task->meters();
- std::vector<Label> labels = task->labels();
-
- BOOST_FOREACH(const Event& e, events) { task->deleteEvent( e.name_or_number() );}
- BOOST_FOREACH(const Meter& m, meters) { task->deleteMeter( m.name() ); }
- BOOST_FOREACH(const Label& l, labels) { task->deleteLabel( l.name() ); }
-
- BOOST_REQUIRE_MESSAGE( task->events().empty(),"Expected all events to be deleted");
- BOOST_REQUIRE_MESSAGE( task->meters().empty(),"Expected all meters to be deleted");
- BOOST_REQUIRE_MESSAGE( task->labels().empty(),"Expected all labels to be deleted");
- }
-}
-
-void add_some_attributes(defs_ptr defs) {
- std::vector<task_ptr> tasks;
- defs->get_all_tasks(tasks);
- BOOST_FOREACH(task_ptr task, tasks) { SuiteChanged1 changed(task->suite()); task->addDay( DayAttr(DayAttr::TUESDAY) );}
-}
-
-void begin(defs_ptr defs) { defs->beginAll();} // reset all attributes
-
-void add_alias(defs_ptr defs) {
-
- std::vector<task_ptr> tasks;
- defs->get_all_tasks(tasks);
- BOOST_REQUIRE_MESSAGE( !tasks.empty(), "Expected at least one task");
-
- SuiteChanged1 changed(tasks[0]->suite());
- tasks[0]->add_alias_only();
-}
-
-void remove_all_aliases(defs_ptr defs) {
-
- std::vector<alias_ptr> aliases;
- defs->get_all_aliases(aliases);
- BOOST_REQUIRE_MESSAGE( !aliases.empty(), "Expected at least one alias");
-
- BOOST_FOREACH(alias_ptr alias, aliases) {
- TestHelper::invokeRequest(defs.get(),Cmd_ptr( new PathsCmd(PathsCmd::DELETE,alias->absNodePath())));
- }
-
- aliases.clear();
- defs->get_all_aliases(aliases);
- BOOST_REQUIRE_MESSAGE( aliases.empty(), "Expected at no alias");
-}
-
-void remove_all_tasks(defs_ptr defs) {
-
- // Remove tasks should force a incremental sync
- std::vector<task_ptr> tasks;
- defs->get_all_tasks(tasks);
- BOOST_FOREACH(task_ptr task, tasks) { SuiteChanged1 changed(task->suite()); task->remove() ;}
-
- tasks.clear();
- defs->get_all_tasks(tasks);
- BOOST_REQUIRE_MESSAGE( tasks.empty(), "Failed to delete tasks");
-}
-
-void remove_a_family(defs_ptr defs) {
-
- // Remove tasks should force a incremental sync
- std::vector<Family*> vec;
- defs->getAllFamilies(vec);
- size_t family_size = vec.size();
- BOOST_REQUIRE_MESSAGE( !vec.empty(), "Expected at least one family");
- if (!vec.empty()) {
- SuiteChanged1 changed(vec[0]->suite());
- vec[0]->remove();
- }
-
- vec.clear();
- defs->getAllFamilies(vec);
- BOOST_REQUIRE_MESSAGE( vec.size() < family_size, "Failed to delete family");
-}
-
-
-void change_clock_gain(defs_ptr defs) {
- BOOST_FOREACH(suite_ptr suite, defs->suiteVec()) {
- if (suite->clockAttr().get()) {
- SuiteChanged changed(suite);
- suite->changeClockGain("100001");
- }
- }
-}
-void change_clock_type_to_real(defs_ptr defs) {
-
- BOOST_FOREACH(suite_ptr suite, defs->suiteVec()) {
- if (suite->clockAttr().get()) {
- SuiteChanged changed(suite);
- suite->changeClockType("real");
- }
- }
-}
-void change_clock_type_to_hybrid(defs_ptr defs) {
-
- BOOST_FOREACH(suite_ptr suite, defs->suiteVec()) {
- if (suite->clockAttr().get()) {
- SuiteChanged changed(suite);
- suite->changeClockType("hybrid");
- }
- }
-}
-void change_clock_date(defs_ptr defs) {
-
- BOOST_FOREACH(suite_ptr suite, defs->suiteVec()) {
- if (suite->clockAttr().get()) {
- SuiteChanged changed(suite);
- suite->changeClockDate("1.1.2001");
- }
- }
-}
-void change_clock_sync(defs_ptr defs) {
-
- BOOST_FOREACH(suite_ptr suite, defs->suiteVec()) {
- if (suite->clockAttr().get()) {
- SuiteChanged changed(suite);
- suite->changeClockSync();
- }
- }
-}
-
-
-/// This has been split into two functions, as changing both together could mask an error
-/// i.e found bug where we forgot to update state_change number when changing the limit
-/// max value, however because we had, changed value as well it got masked.
-void change_limit_max(defs_ptr defs) {
-
- BOOST_FOREACH(suite_ptr s, defs->suiteVec()) {
- std::vector<limit_ptr> theLimits = s->limits();
- BOOST_FOREACH(limit_ptr l, theLimits) {
- //std::cout << "found " << l->toString() << "\n";
- TestHelper::invokeRequest(defs.get(),Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::LIMIT_MAX,l->name(),"90")));
- limit_ptr v = s->find_limit(l->name());
- BOOST_CHECK_MESSAGE( v.get() && v->theLimit() == 90, "expected to find limit with max value of 90");
- }
- }
-}
-void change_limit_value(defs_ptr defs) {
-
- BOOST_FOREACH(suite_ptr s, defs->suiteVec()) {
- std::vector<limit_ptr> theLimits = s->limits();
- BOOST_FOREACH(limit_ptr l, theLimits) {
- TestHelper::invokeRequest(defs.get(),Cmd_ptr( new AlterCmd(s->absNodePath(),AlterCmd::LIMIT_VAL,l->name(),"33")));
- limit_ptr v = s->find_limit(l->name());
- BOOST_CHECK_MESSAGE( v.get() && v->value() == 33, "expected to find limit with value of 33");
- }
- }
-}
-
-
-void update_repeat(defs_ptr defs) {
-
- std::vector<Node*> nodes;
- defs->getAllNodes(nodes);
-
- BOOST_FOREACH(Node* n, nodes) {
- if (!n->repeat().empty()) {
- SuiteChanged1 changed(n->suite());
- n->increment_repeat();
- }
- }
-}
-
-void update_calendar(defs_ptr defs) {
-
- // The calendar is *only* updated if the suite have been begun. Hence make sure this test scaffold
- // starts the test, with all the suites in a begun state
- CalendarUpdateParams p( Calendar::second_clock_time(), minutes(1), true /* server running */, false/* for Test*/ );
- defs->updateCalendar(p);
-
- // Currently updating the calendar, does not cause change, Hence force a change
- BOOST_FOREACH(suite_ptr suite, defs->suiteVec()) {
- SuiteChanged changed(suite);
- suite->add_variable("name","value");
- }
-
- // Note: In the real server, persisting that calendar, the clock type is not persisted.
- // i.e when we have hybrid calendar, when restored on the client side it will be 'real' clock since
- // that is the default now. This is not correct and will fail invariant checking.
- // however the memento should reset clock type on the calenadar form the clok attribute.
-}
-
-
-void delete_suite(defs_ptr defs) {
- std::vector<suite_ptr> vec = defs->suiteVec();
- BOOST_REQUIRE_MESSAGE(!vec.empty(),"Expected suites");
- vec[0]->remove();
-}
-
-void set_server_state_shutdown(defs_ptr defs) {
- defs->set_server().set_state( SState::SHUTDOWN );
-}
-void set_server_state_running(defs_ptr defs) {
- defs->set_server().set_state( SState::RUNNING );
-}
-
-void add_server_variable(defs_ptr defs) {
- TestHelper::invokeRequest(defs.get(),Cmd_ptr( new AlterCmd("/",AlterCmd::ADD_VARIABLE,"_fred_","value")));
-}
-void change_server_variable(defs_ptr defs) {
- // Because the scaffold create client/server defs each time.
- // To test change/delete variables we modify the default set
- TestHelper::invokeRequest(defs.get(),Cmd_ptr( new AlterCmd("/",AlterCmd::VARIABLE,"ECF_TRIES","4")));
-}
-void delete_server_variable(defs_ptr defs) {
- // Because the scaffold create client/server defs each time.
- // To test change/delete variables we modify the default set
- // ***NOTE*** we can not delete server variables like ECF_TRIES, can only change them
- // However we can delete user variables added to the server
- TestHelper::invokeRequest(defs.get(),Cmd_ptr( new AlterCmd("/",AlterCmd::DEL_VARIABLE,"MyDefsFixture_user_variable")));
-}
-
-void reorder_suites(defs_ptr defs) {
- std::vector<suite_ptr> suiteVec = defs->suiteVec();
- BOOST_REQUIRE_MESSAGE(!suiteVec.empty(),"Expected suites");
- std::string path = "/" + suiteVec[0]->name();
- TestHelper::invokeRequest(defs.get(),Cmd_ptr( new OrderNodeCmd(path,NOrder::ALPHA)));
-}
-
-void set_defs_flag(defs_ptr defs) {
- defs->flag().set(ecf::Flag::MESSAGE);
-}
-
-void set_defs_state(defs_ptr defs) {
- defs->set_state(NState::ABORTED);
-}
-
-BOOST_AUTO_TEST_CASE( test_ssync_cmd )
-{
- // To DEBUG: enable the defines in Memento.hpp
- cout << "Base:: ...test_ssync_cmd\n";
- test_sync_scaffold(update_repeat,"update_repeat");
- test_sync_scaffold(delete_some_attributes,"delete_some_attributes");
- test_sync_scaffold(add_some_attributes,"add_some_attributes");
- test_sync_scaffold(begin,"begin",true /* expect full_sync */);
- test_sync_scaffold(add_alias,"add_alias");
- test_sync_scaffold(remove_all_aliases,"remove_all_aliases");
- test_sync_scaffold(remove_all_tasks,"remove_all_tasks");
- test_sync_scaffold(remove_a_family,"remove_a_family");
- test_sync_scaffold(change_clock_gain,"change_clock_gain", true /* expect full_sync */);
- test_sync_scaffold(change_clock_type_to_real,"change_clock_type_to_real", true /* expect full_sync */);
- test_sync_scaffold(change_clock_type_to_hybrid,"change_clock_type_to_hybrid", true /* expect full_sync */);
- test_sync_scaffold(change_clock_date,"change_clock_date", true /* expect full_sync */);
- test_sync_scaffold(change_clock_sync,"change_clock_sync", true /* expect full_sync */);
- test_sync_scaffold(update_calendar,"update_calendar", false/* expect full_sync */, true /* start test with begin */ );
- test_sync_scaffold(change_limit_max,"change_limit_max");
- test_sync_scaffold(change_limit_value,"change_limit_value");
- test_sync_scaffold(delete_suite,"delete_suite", true /* expect full_sync */);
-
- // Test Changes in Defs
- // The default server state is HALTED, hence setting to halted will not show a change
- test_sync_scaffold(set_server_state_shutdown,"set_server_state_shutdown");
- test_sync_scaffold(set_server_state_running,"set_server_state_running");
-
- test_sync_scaffold(add_server_variable,"add_server_variable");
- test_sync_scaffold(change_server_variable,"change_server_variable");
- test_sync_scaffold(delete_server_variable,"delete_server_variable");
-
- test_sync_scaffold(reorder_suites,"reorder_suites");
-
- test_sync_scaffold(set_defs_flag,"set_defs_flag");
- test_sync_scaffold(set_defs_state,"set_defs_state");
-
- /// Keep valgrind happy
- ChangeMgrSingleton::destroy();
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-
diff --git a/ecflow_4_0_7/Base/test/TestSSyncCmdOrder.cpp b/ecflow_4_0_7/Base/test/TestSSyncCmdOrder.cpp
deleted file mode 100644
index 06d91d4..0000000
--- a/ecflow_4_0_7/Base/test/TestSSyncCmdOrder.cpp
+++ /dev/null
@@ -1,233 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <boost/test/unit_test.hpp>
-#include <boost/function.hpp>
-
-#include "ClientToServerCmd.hpp"
-#include "ServerToClientCmd.hpp"
-#include "MyDefsFixture.hpp"
-#include "MockServer.hpp"
-#include "TestHelper.hpp"
-#include "SSyncCmd.hpp"
-#include "Ecf.hpp"
-#include "NodeFwd.hpp"
-#include "SuiteChanged.hpp"
-#include "ChangeMgrSingleton.hpp"
-#include "System.hpp"
-
-using namespace std;
-using namespace ecf;
-
-// The client handle commands do not change state & modify change number, hence need to bypass these checks
-static bool bypass_state_modify_change_check = false;
-
-BOOST_AUTO_TEST_SUITE( BaseTestSuite )
-
-/// define a function which returns nothing, and takes a defs_ptr parameter
-typedef boost::function<void (defs_ptr)> defs_change_cmd;
-
-template <typename T>
-static std::vector<std::string> toStrVec(const std::vector<T>& vec)
-{
- std::vector<std::string> retVec; retVec.reserve(vec.size());
- BOOST_FOREACH(T s, vec) { retVec.push_back(s->name()); }
- return retVec;
-}
-
-static std::string toString(const std::vector<std::string>& c)
-{
- std::stringstream ss;
- std::copy (c.begin(), c.end(), std::ostream_iterator <std::string> (ss, ", "));
- return ss.str();
-}
-
-static std::vector<std::string> vector_abcd() {
- std::vector<std::string> names; names.reserve(4);
- names.push_back("a"); names.push_back("b"); names.push_back("c"); names.push_back("d");
- return names;
-}
-static std::vector<std::string> vector_dcba() {
- std::vector<std::string> names; names.reserve(4);
- names.push_back("d"); names.push_back("c"); names.push_back("b"); names.push_back("a");
- return names;
-}
-
-static defs_ptr create_defs()
-{
- std::vector<std::string> names = vector_dcba();
- defs_ptr defs = Defs::create();
- for(size_t j = 0; j <names.size(); j++) {
- suite_ptr s = defs->add_suite( names[j] );
- if ( 0 == j) { // only add family to first suite
- for(size_t k = 0; k <names.size(); k++) {
- family_ptr f = s->add_family(names[k]);
- for(size_t l = 0; l <names.size(); l++) {
- task_ptr t = f->add_task(names[l]);
-// t->add_alias_only(); // alias0
-// t->add_alias_only(); // alias1
-// t->add_alias_only(); // alias2
- }
- }
- }
- }
- return defs;
-}
-
-
-/// Re-use the same test scaffold to modify and then resync, by passing in a function that will modify the defs
-static void test_sync_scaffold( defs_change_cmd the_defs_change_command,
- unsigned int test_equality, /*0 means test equality, any other number test size*/
- bool full_sync, unsigned int client_handle)
-{
- defs_ptr server_defs = create_defs();
- ServerReply server_reply;
- server_reply.set_client_defs( create_defs() );
-
-
- Ecf::set_debug_equality(true); // only has affect in DEBUG build
- BOOST_CHECK_MESSAGE( *server_defs == *server_reply.client_defs(), "Starting point client and server defs should be the same");
- Ecf::set_debug_equality(false);
-
- // Get change number before any changes
- Ecf::set_state_change_no(0);
- Ecf::set_modify_change_no(0);
- unsigned int client_state_change_no = Ecf::state_change_no();
- unsigned int client_modify_change_no = Ecf::modify_change_no();
-
- // make some change to the server
- {
- Ecf::set_server(true);
-
- the_defs_change_command(server_defs);
- std::string errorMsg;
- BOOST_REQUIRE_MESSAGE( server_defs->checkInvariants(errorMsg),"Invariants failed " << errorMsg);
- BOOST_REQUIRE_MESSAGE( !(*server_reply.client_defs() == *server_defs), "Expected client and server defs to differ " << *server_reply.client_defs() << "\n" << "server defs = " << *server_defs);
- Ecf::set_server(false);
- }
-
-// cout << "test_sync_scaffold AFTER Command before SYNC: Server:\n" << *server_defs << "\n";
-// cout << "test_sync_scaffold AFTER Command before SYNC: Client:\n" << *server_reply.client_defs() << "\n";
-
- MockServer mock_server(server_defs);
- SSyncCmd cmd(client_handle, client_state_change_no, client_modify_change_no, &mock_server );
- string error_msg;BOOST_REQUIRE_MESSAGE(mock_server.defs()->checkInvariants(error_msg), error_msg);
- BOOST_CHECK_MESSAGE( cmd.do_sync( server_reply ), "Expected server to change");
- BOOST_CHECK_MESSAGE( server_reply.in_sync(), "Expected to be in sync");
- BOOST_CHECK_MESSAGE( server_reply.full_sync() == full_sync, "Expected full sync");
-
- if (0 == test_equality) {
- Ecf::set_debug_equality(true);
- BOOST_CHECK_MESSAGE( *server_defs == *server_reply.client_defs(), "Server and client should be same after sync" );
- Ecf::set_debug_equality(false);
- }
- else {
- BOOST_CHECK_MESSAGE( server_reply.client_defs()->suiteVec().size() == test_equality, "Expected suite of size " << test_equality << " but found " << server_reply.client_defs()->suiteVec().size());
- }
-}
-
-static void reorder_suites(defs_ptr theDefs) {
-
- TestHelper::invokeRequest(theDefs.get(),Cmd_ptr( new OrderNodeCmd("/a",NOrder::ALPHA)));
- BOOST_REQUIRE_MESSAGE( toStrVec(theDefs->suiteVec()) == vector_abcd(),"NOrder::ALPHA expected " << toString(vector_abcd())<< " but found: " << toString(toStrVec(theDefs->suiteVec())));
-}
-
-static void reorder_family(defs_ptr theDefs) {
-// std::cout << "reorder_family\n" << *theDefs << "\n";
-
- TestHelper::invokeRequest(theDefs.get(),Cmd_ptr( new OrderNodeCmd("/d/d",NOrder::ALPHA)));
-
- std::vector<Family*> families;
- theDefs->findSuite("d")->getAllFamilies(families);
- BOOST_REQUIRE_MESSAGE( toStrVec(families) == vector_abcd(),"NOrder::ALPHA expected " << toString(vector_abcd())<< " but found: " << toString(toStrVec(families)));
-}
-
-static void reorder_task(defs_ptr theDefs) {
- //std::cout << "reorder_task\n" << *theDefs << "\n";
-
- TestHelper::invokeRequest(theDefs.get(),Cmd_ptr( new OrderNodeCmd("/d/d/d",NOrder::ALPHA)));
-
- std::vector<Task*> tasks;
- theDefs->findAbsNode("/d/d")->getAllTasks(tasks);
- BOOST_REQUIRE_MESSAGE( toStrVec(tasks) == vector_abcd(),"NOrder::ALPHA expected " << toString(vector_abcd())<< " but found: " << toString(toStrVec(tasks)));
-}
-
-//static void reorder_alias(defs_ptr theDefs) {
-// //std::cout << "reorder_task\n" << *theDefs << "\n";
-//
-// TestHelper::invokeRequest(theDefs.get(),Cmd_ptr( new OrderNodeCmd("/d/d/d/alias0",NOrder::ALPHA)));
-//
-// std::vector<alias_ptr> aliases;
-// theDefs->findAbsNode("/d/d/d")->get_all_aliases(aliases);
-// BOOST_REQUIRE_MESSAGE( toStrVec(aliases) == vector_abcd(),"NOrder::ALPHA expected " << toString(vector_abcd())<< " but found: " << toString(toStrVec(tasks)));
-//}
-
-
-static void reorder_suites_using_handles(defs_ptr theDefs) {
-
- // *** NOTE ****: Whenever we register a handle, we get a *FULL* sync
-
- // create client handle which references all the suites
- // It should be noted that invokeRequest, uses a MockServer, which set/unsets
- // Hence after this call Ecf::server_ is false. Hence we need to ensure that following
- // commands/ DM function set Ecf::server_ to true.
- std::vector<std::string> suite_names = vector_abcd();
- TestHelper::invokeRequest(theDefs.get(),Cmd_ptr( new ClientHandleCmd(suite_names,false)),bypass_state_modify_change_check);
- BOOST_CHECK_MESSAGE(theDefs->client_suite_mgr().clientSuites().size() == 1,"Expected 1 Client suites but found " << theDefs->client_suite_mgr().clientSuites().size());
-
- TestHelper::invokeRequest(theDefs.get(),Cmd_ptr( new OrderNodeCmd("/a",NOrder::ALPHA)));
- BOOST_REQUIRE_MESSAGE( toStrVec(theDefs->suiteVec()) == vector_abcd(),"NOrder::ALPHA expected " << toString(vector_abcd())<< " but found: " << toString(toStrVec(theDefs->suiteVec())));
-}
-
-static void reorder_family_using_handles(defs_ptr theDefs) {
-
- // *** NOTE ****: Whenever we register a handle, we get a *FULL* sync
-
- // create client handle which references all the suites
- // It should be noted that invokeRequest, uses a MockServer, which set/unsets
- // Hence after this call Ecf::server_ is false. Hence we need to ensure that following
- // commands/ DM function set Ecf::server_ to true.
- std::vector<std::string> suite_names ; suite_names.push_back("d"); // clinet handle for suite 'd' ONLY
- TestHelper::invokeRequest(theDefs.get(),Cmd_ptr( new ClientHandleCmd(suite_names,false)),bypass_state_modify_change_check);
- BOOST_CHECK_MESSAGE(theDefs->client_suite_mgr().clientSuites().size() == 1,"Expected 1 Client suites but found " << theDefs->client_suite_mgr().clientSuites().size());
-
- /// Don't call, data model function directly, since Ecf::server_ is false. *here*
- /// The suite should stay the same, only suite d's family should change
- TestHelper::invokeRequest(theDefs.get(),Cmd_ptr( new OrderNodeCmd("/d/d",NOrder::ALPHA)));
- BOOST_REQUIRE_MESSAGE( toStrVec(theDefs->suiteVec()) == vector_dcba(),"expected " << toString(vector_dcba())<< " but found: " << toString(toStrVec(theDefs->suiteVec())));
-
- suite_ptr suite_a = theDefs->findSuite("d");
- std::vector<Family*> families; suite_a->getAllFamilies(families);
- BOOST_REQUIRE_MESSAGE( toStrVec(families) == vector_abcd(),"NOrder::ALPHA expected " << toString(vector_abcd())<< " but found: " << toString(toStrVec(families)));
-}
-
-
-BOOST_AUTO_TEST_CASE( test_ssync_cmd_test_order )
-{
- cout << "Base:: ...test_ssync_cmd_test_order\n";
- test_sync_scaffold(reorder_suites, 0 /* test equality */, false /* expect full_sync */, 0);
- test_sync_scaffold(reorder_family, 0 /* test equality */, false /* expect full_sync */, 0);
- test_sync_scaffold(reorder_task, 0 /* test equality */, false /* expect full_sync */, 0);
-// test_sync_scaffold(reorder_alias, 0 /* test equality */, false /* expect full_sync */, 0);
-
- test_sync_scaffold(reorder_suites_using_handles, 0 /* test equality */, true /* expect full_sync */, 1 /* client handle */);
- test_sync_scaffold(reorder_family_using_handles, 1 /* test size */, true /* expect full_sync */, 1 /* client handle */);
-
- /// Keep valgrind happy
- ChangeMgrSingleton::destroy();
- System::destroy();
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/Base/test/TestSSyncCmd_CH1.cpp b/ecflow_4_0_7/Base/test/TestSSyncCmd_CH1.cpp
deleted file mode 100644
index 058cdf9..0000000
--- a/ecflow_4_0_7/Base/test/TestSSyncCmd_CH1.cpp
+++ /dev/null
@@ -1,678 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #18 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <boost/test/unit_test.hpp>
-#include <boost/function.hpp>
-
-#include "ClientToServerCmd.hpp"
-#include "ServerToClientCmd.hpp"
-#include "MyDefsFixture.hpp"
-#include "MockServer.hpp"
-#include "TestHelper.hpp"
-#include "SSyncCmd.hpp"
-#include "SNewsCmd.hpp"
-#include "Ecf.hpp"
-#include "NodeFwd.hpp"
-#include "SuiteChanged.hpp"
-#include "ChangeMgrSingleton.hpp"
-
-using namespace std;
-using namespace ecf;
-
-/// This test, is used to check sync with the client handles.
-/// The client handles will register interest in a set of suites
-/// When calling sync, check will only receive notification on our
-/// our suites
-// In particular when a set of suites are registered to a handle
-// and we add/delete/check point/order the server passes back to the client
-// the a *new* defs with all the suites corresponding to the handle
-// There is a complication however, the suite are not copied/cloned
-// This causes a problem, since if we create a new defs, and add
-// the suites, the suite defs pointer is *NOW* corrupted, as it will point
-// to the new defs. This is not an issue in real apps, since searisation
-// fixes up these ptrs.
-
-// The client handle commands do not change state & modify change number, hence need to bypass these checks
-static bool bypass_state_modify_change_check = false;
-
-BOOST_AUTO_TEST_SUITE( BaseTestSuite )
-
-static defs_ptr create_client_defs(defs_ptr defs)
-{
- for(size_t j = 0; j < 5; j++) {
- suite_ptr suite = defs->add_suite( "s" + boost::lexical_cast<std::string>(j) );
- family_ptr f = suite->add_family("f");
- f->add_task("t");
- if (j == 0) {
- suite->addLimit( Limit("suiteLimit",10) );
- suite->addRepeat( RepeatDate("YMD",20090916,20090916,1) );
- }
- }
- return defs;
-}
-
-static defs_ptr create_server_defs()
-{
- defs_ptr defs = Defs::create();
-
- // Create server defs, with a port other than default.
- // This allows additional testing. i.e server variables
- std::vector<Variable> server_variables;
- ServerState::setup_default_server_variables(server_variables,"4000");
- defs->set_server().set_server_variables(server_variables);
-
- // ensure client/server start out the same
- return create_client_defs(defs);
-}
-
-/// define a function which returns nothing, and takes a defs_ptr parameter
-typedef boost::function<bool (defs_ptr)> defs_change_cmd;
-
-/// Re-use the same test scaffold to modify and then resync, by passing
-/// in a function that will modify the defs
-void test_sync_scaffold( defs_change_cmd the_defs_change_command, const std::string& test_name, bool full_sync = false)
-{
- // Create the defs
- defs_ptr server_defs = create_server_defs();
- ServerReply server_reply;
- server_reply.set_client_defs( create_client_defs(Defs::create()) );
-
- Ecf::set_debug_equality(true); // only has affect in DEBUG build
- BOOST_CHECK_MESSAGE( *server_defs == *server_reply.client_defs(),
- test_name << ": Starting point client and server defs should be the same : "
- << "SERVER\n" << server_defs
- << "CLIENT\n" << server_reply.client_defs());
- Ecf::set_debug_equality(false);
-
- // set handle and change numbers, before any changes
- Ecf::set_state_change_no(0);
- Ecf::set_modify_change_no(0);
- unsigned int client_state_change_no = Ecf::state_change_no();
- unsigned int client_modify_change_no = Ecf::modify_change_no();
- unsigned int client_handle = 0;
-
- bool expected_change;
-
- // make some change to the server
- {
- /// create client handle which references suites s0 and s4, in the server defs
- /// Registering suites should change handle_changed boolean
- std::vector<std::string> suite_names; suite_names.push_back("s0"); suite_names.push_back("s4");
- TestHelper::invokeRequest(server_defs.get(),Cmd_ptr( new ClientHandleCmd(suite_names,false)),bypass_state_modify_change_check);
-
- BOOST_CHECK_MESSAGE(server_defs->client_suite_mgr().clientSuites().size() == 1,test_name << ": Expected 1 Client suites but found " <<server_defs->client_suite_mgr().clientSuites().size());
- client_handle = server_defs->client_suite_mgr().clientSuites().front().handle();
- BOOST_CHECK_MESSAGE( client_handle == 1,"" );
-
- /// Check that handle_changed set, required for syncing, i.e needed for full sync , without change state/modify numbers
- BOOST_CHECK_MESSAGE(server_defs->client_suite_mgr().handle_changed(client_handle) == true,"Expected handle_changed to be set when suites are registered ");
-
- /// called create Defs should clear the flag. make sure server state, is synced
- defs_ptr the_client_defs = server_defs->client_suite_mgr().create_defs(client_handle,server_defs);
- BOOST_CHECK_MESSAGE(the_client_defs->suiteVec().size() == 2 ,test_name << ": Expected 2 suites");
- BOOST_CHECK_MESSAGE(server_defs->client_suite_mgr().handle_changed(client_handle) == false,test_name << ": Expected handle_changed to be cleared after create_defs()");
- Ecf::set_debug_equality(true);
- BOOST_CHECK_MESSAGE( server_defs->server().compare(the_client_defs->server() ), test_name << ": Server state does not match");
- Ecf::set_debug_equality(false);
-
- Ecf::set_server(true);
- expected_change = the_defs_change_command(server_defs);
- std::string error_msg;
- BOOST_REQUIRE_MESSAGE( server_defs->checkInvariants(error_msg) , test_name << ": Invariants failed: " << error_msg);
- Ecf::set_server(false);
-
- /// Call create defs again, after change in server defs, check server state is synced
- the_client_defs = server_defs->client_suite_mgr().create_defs(client_handle,server_defs);
- Ecf::set_debug_equality(true);
- BOOST_CHECK_MESSAGE( server_defs->server().compare(the_client_defs->server() ), test_name << ": Server state does not match");
- Ecf::set_debug_equality(false);
- }
-
- MockServer mock_server(server_defs);
- SNewsCmd news_cmd(client_handle, client_state_change_no, client_modify_change_no, &mock_server );
- SSyncCmd cmd(client_handle, client_state_change_no, client_modify_change_no, &mock_server );
-
- if ( expected_change ) {
- BOOST_CHECK_MESSAGE( news_cmd.get_news(), test_name << " : get_news : Expected server to change");
- BOOST_CHECK_MESSAGE( cmd.do_sync( server_reply ), test_name << " : do_sync : Expected server to change");
- BOOST_CHECK_MESSAGE( server_reply.in_sync(), test_name << " : in_sync : Expected client server to be in sync");
- BOOST_CHECK_MESSAGE( server_reply.full_sync() == full_sync,test_name << ": Expected sync not as expected. client: " << server_reply.full_sync() << " full_sync: " << full_sync);
- BOOST_CHECK_MESSAGE( server_defs->state() == server_reply.client_defs()->state(),test_name << ": Expected server State(" << NState::toString(server_defs->state()) << ") to be same as client state(" << NState::toString(server_reply.client_defs()->state()) << ")");
- if (full_sync) {
- Ecf::set_debug_equality(true);
- BOOST_CHECK_MESSAGE( server_defs->server().compare(server_reply.client_defs()->server()),test_name << ": Server state does not match");
- Ecf::set_debug_equality(false);
- }
- else {
- }
-
- // * Note we expect client defs to fail invariant checking when doing a full sync with handles
- // * Under real server this should be ok since, we fix up the defs ptr, during serialisation
-
- // * note. We can't really compare server and client defs, since when we sync with
- // * with handles, we only return a sub set of the suites, in our handle
-
- // DO a sync again. hence we should expect no changes
- server_reply.clear_for_invoke(false);
- Ecf::set_server(true);
- /* server side */ SNewsCmd news_cmd1(client_handle, server_reply.client_defs()->state_change_no(), server_reply.client_defs()->modify_change_no(), &mock_server );
- /* server side */ SSyncCmd cmd1(client_handle, server_reply.client_defs()->state_change_no(), server_reply.client_defs()->modify_change_no(), &mock_server );
- Ecf::set_server(false);
- /* client side */ BOOST_CHECK_MESSAGE( !news_cmd1.get_news(), test_name << ": Expected no changes to client, we should be in sync");
- /* client side */ BOOST_CHECK_MESSAGE( !cmd1.do_sync( server_reply ), test_name << ": Expected no changes to client, we should be in sync");
- }
- else {
-
- BOOST_CHECK_MESSAGE( !news_cmd.get_news(), test_name << ": Expected no change");
- BOOST_CHECK_MESSAGE( !cmd.do_sync( server_reply ), test_name << ": Expected no change");
- BOOST_CHECK_MESSAGE( !server_reply.in_sync(), test_name << ": Expected no change");
- BOOST_CHECK_MESSAGE( !(*server_defs == *server_reply.client_defs()), test_name << ": Server and client defs expected to differ" );
- }
-}
-
-
-static bool set_server_state_shutdown(defs_ptr defs) {
- defs->set_server().set_state( SState::SHUTDOWN );
- return true; // expect changes
-}
-static bool set_server_state_running(defs_ptr defs) {
- defs->set_server().set_state( SState::RUNNING );
- return true; // expect changes
-}
-
-static bool change_suites_s3_outside_of_handle(defs_ptr defs)
-{
- /// Make a state change to suites s3, in the server. This is *not* in the client handle
- /// Note: we do *NOT* make a state change as this will be propagated to the defs, and hence will be synced
- /// We *NEED* MockSuiteChangedServer, so that change is propagated to the suite.
- MockSuiteChangedServer mockServer(defs->findSuite("s3")); // Increment suite state/modify change number
- defs->findSuite("s3")->suspend(); // small scale state change
- return false; // expect no changes
-}
-
-static bool change_suites_s3_outside_of_handle_add_variable(defs_ptr defs)
-{
- /// make a state change to suites s3, in the server. This is *not* in the client handle
- /// We *NEED* MockSuiteChangedServer, so that change is propagated to the suite.
- MockSuiteChangedServer mockServer(defs->findSuite("s3")); // Increment suite state/modify change number
- defs->findSuite("s3")->add_variable("Var","value"); // small scale state change
- return false; // expect no changes in sync
-}
-
-static bool add_task_to_suite_s3(defs_ptr defs)
-{
- /// make a modify change to suites s3, in the server. This is *not* in the client handle
- MockSuiteChangedServer mockServer(defs->findSuite("s3")); // Increment suite state/modify change number
- defs->findSuite("s3")->addTask( Task::create("s3_task")); // small scale change
- return false; // expect no changes, since suite s3 not in handle
-}
-
-static bool delete_task_on_suite_s3(defs_ptr defs)
-{
- /// make a modify change to suites s3, in the server. This is *not* in the client handle
- MockSuiteChangedServer mockServer(defs->findSuite("s3")); // Increment suite state/modify change number
- defs->findAbsNode("/s3/f/t")->remove(); // small scale change
- return false; // expect no changes, since suite s3 not in handle
-}
-static bool delete_family_on_suite_s3(defs_ptr defs)
-{
- /// make a modify change to suites s3, in the server. This is *not* in the client handle
- MockSuiteChangedServer mockServer(defs->findSuite("s3")); // Increment suite state/modify change number
- defs->findAbsNode("/s3/f")->remove(); // small scale change
- return false; // expect no changes, since suite s3 not in handle
-}
-
-static bool change_state_of_s4(defs_ptr defs)
-{
- /// Ok now make state change to s4, which **is** in the handle
- /// We need MockSuiteChangedServer, so that change is propagated to the suite.
- MockSuiteChangedServer mockServer(defs->findSuite("s4")); // Increment suite state/modify change number
- defs->findSuite("s4")->set_state(NState::SUBMITTED); // small scale change
- return true; // expect changes
-}
-
-static bool add_variable_to_suite_s4(defs_ptr defs)
-{
- /// Ok now make state change to s4, which **is** in the handle
- /// We need MockSuiteChangedServer, so that change is propagated to the suite.
- MockSuiteChangedServer mockServer(defs->findSuite("s4")); // Increment suite state/modify change number
- defs->findSuite("s4")->add_variable("Var","value"); // small scale state change
- return true; // expect changes
-}
-
-static bool add_server_user_variables(defs_ptr defs)
-{
- // Change server. This is outside of any suites
- std::vector<Variable> user_variables;
- user_variables.push_back(Variable("a","b"));
- user_variables.push_back(Variable("c","d"));
- defs->set_server().set_user_variables(user_variables);
- return true; // expect change
-}
-
-static bool add_task_to_suite_s4(defs_ptr defs)
-{
- /// Ok now make modify change to s4, which **is** in the handle
- MockSuiteChangedServer mockServer(defs->findSuite("s4")); // Increment suite state/modify change number
- defs->findSuite("s4")->addTask( Task::create("s4_task")); // small scale change
- return true; // expect changes
-}
-
-static bool delete_task_on_suite_s4(defs_ptr defs)
-{
- /// Ok now make modify change to s4, which **is** in the handle
- MockSuiteChangedServer mockServer(defs->findSuite("s4")); // Increment suite state/modify change number
- defs->findAbsNode("/s4/f/t")->remove(); // small scale change
- return true; // expect changes, since suite s4 is in handle
-}
-
-static bool delete_family_on_suite_s4(defs_ptr defs)
-{
- /// Ok now make modify change to s4, which **is** in the handle
- MockSuiteChangedServer mockServer(defs->findSuite("s4")); // Increment suite state/modify change number
- defs->findAbsNode("/s4/f")->remove(); // small scale change
- return true; // expect changes, since suite s4 is in handle
-}
-
-static bool change_order_of_s4_top(defs_ptr defs) {
- /// Ok make modify change to s4, which **is** in the handle
- suite_ptr s4 = defs->findSuite("s4");
- MockSuiteChangedServer mockServer(s4); // Increment suite state/modify change number
- defs->order(s4.get(),NOrder::TOP) ; // small scale scale change
- return true;
-}
-
-static bool change_order_of_s4_bottom(defs_ptr defs) {
- /// Ok make modify change to s4, which **is** in the handle
- suite_ptr s4 = defs->findSuite("s4");
- MockSuiteChangedServer mockServer(s4); // Increment suite state/modify change number
- defs->order(s4.get(),NOrder::BOTTOM) ; // small scale change
- return true;
-}
-
-static bool delete_suite_s4(defs_ptr defs)
-{
- /// Ok now make delete s4 which, which **is** in the handle
- MockSuiteChangedServer mockServer(defs->findSuite("s4")); // Increment suite state/modify change number
- defs->findSuite("s4")->remove(); // large scale change
- return true; // expect changes
-}
-
-static bool set_defs_state(defs_ptr defs)
-{
- defs->set_state( NState::ABORTED ); // changes the defs state
- return true; // expect changes
-}
-
-static bool set_defs_state_2(defs_ptr defs)
-{
- defs->set_state( NState::ABORTED ); // changes the defs state
- return delete_suite_s4( defs ); // large scale change
-}
-
-static bool add_server_variable(defs_ptr defs) {
- // Change defs server state. small scale change
- TestHelper::invokeRequest(defs.get(),Cmd_ptr( new AlterCmd("/",AlterCmd::ADD_VARIABLE,"_fred_","value")));
- return true;
-}
-
-static bool change_server_variable(defs_ptr defs) {
- // Because the scaffold create client/server defs each time.
- // To test change/delete variables we modify the default set
- TestHelper::invokeRequest(defs.get(),Cmd_ptr( new AlterCmd("/",AlterCmd::VARIABLE,"ECF_TRIES","4")));
- return true;
-}
-
-// ===============================================================================
-// The modifiers, do this for suite s0 which is in a handle
-// ===============================================================================
-static bool s0_delete_some_attributes(defs_ptr defs) {
-
- /// Ok now make state change to s4, which **is** in the handle
- /// We need MockSuiteChangedServer, so that change is propagated to the suite.
- suite_ptr suite = defs->findSuite("s0");
- BOOST_REQUIRE_MESSAGE( suite,"Could not find suite");
- MockSuiteChangedServer mockServer(suite); // Increment suite state/modify change number
-
- std::vector<Task*> tasks;
- suite->getAllTasks(tasks);
- BOOST_REQUIRE_MESSAGE( !tasks.empty(), "Expected at least one task");
-
- BOOST_FOREACH(Task* task, tasks) {
- SuiteChanged1 changed(task->suite());
- task->addMeter(Meter("meter",0,100));
- }
- return true;
-}
-
-static bool s0_add_some_attributes(defs_ptr defs) {
- suite_ptr suite = defs->findSuite("s0");
- BOOST_REQUIRE_MESSAGE( suite,"Could not find suite");
- MockSuiteChangedServer mockServer(suite); // Increment suite state/modify change number
-
- std::vector<task_ptr> tasks;
- suite->get_all_tasks(tasks);
- BOOST_REQUIRE_MESSAGE( !tasks.empty(), "Expected at least one task");
-
- BOOST_FOREACH(task_ptr task, tasks) { SuiteChanged1 changed(suite.get()); task->addDay( DayAttr(DayAttr::TUESDAY) );}
- return true;
-}
-
-static bool s0_begin(defs_ptr defs) {
- suite_ptr suite = defs->findSuite("s0");
- BOOST_REQUIRE_MESSAGE( suite,"Could not find suite");
- MockSuiteChangedServer mockServer(suite); // Increment suite state/modify change number
-
- suite->begin();
- return true;
-}
-
-static bool s0_add_alias(defs_ptr defs) {
- suite_ptr suite = defs->findSuite("s0");
- BOOST_REQUIRE_MESSAGE( suite,"Could not find suite");
- MockSuiteChangedServer mockServer(suite); // Increment suite state/modify change number
-
- std::vector<task_ptr> tasks;
- suite->get_all_tasks(tasks);
- BOOST_REQUIRE_MESSAGE( !tasks.empty(), "Expected at least one task");
-
- SuiteChanged1 changed(tasks[0]->suite());
- tasks[0]->add_alias_only();
- return true;
-}
-
-static bool s0_remove_all_tasks(defs_ptr defs) {
- suite_ptr suite = defs->findSuite("s0");
- BOOST_REQUIRE_MESSAGE( suite,"Could not find suite");
- MockSuiteChangedServer mockServer(suite); // Increment suite state/modify change number
-
-
- // Remove tasks should force a incremental sync
- std::vector<task_ptr> tasks;
- suite->get_all_tasks(tasks);
- BOOST_REQUIRE_MESSAGE( !tasks.empty(), "Expected at least one task");
- BOOST_FOREACH(task_ptr task, tasks) { SuiteChanged1 changed(task->suite()); task->remove() ;}
-
- tasks.clear();
- suite->get_all_tasks(tasks);
- BOOST_REQUIRE_MESSAGE( tasks.empty(), "Failed to delete tasks");
- return true;
-}
-
-static bool s0_remove_a_family(defs_ptr defs) {
- suite_ptr suite = defs->findSuite("s0");
- BOOST_REQUIRE_MESSAGE( suite,"Could not find suite");
- MockSuiteChangedServer mockServer(suite); // Increment suite state/modify change number
-
- std::vector<Family*> vec;
- suite->getAllFamilies(vec);
- size_t family_size = vec.size();
- BOOST_REQUIRE_MESSAGE( !vec.empty(), "Expected at least one family");
- if (!vec.empty()) {
- SuiteChanged1 changed(vec[0]->suite());
- vec[0]->remove();
- }
-
- vec.clear();
- suite->getAllFamilies(vec);
- BOOST_REQUIRE_MESSAGE( vec.size() < family_size, "Failed to delete family");
- return true;
-}
-
-
-static bool s0_change_clock_gain(defs_ptr defs) {
- suite_ptr suite = defs->findSuite("s0");
- BOOST_REQUIRE_MESSAGE( suite,"Could not find suite");
- MockSuiteChangedServer mockServer(suite); // Increment suite state/modify change number
-
- suite->changeClockGain("100001");
- return true;
-}
-
-static bool s0_change_clock_type_to_real(defs_ptr defs) {
- suite_ptr suite = defs->findSuite("s0");
- BOOST_REQUIRE_MESSAGE( suite,"Could not find suite");
- MockSuiteChangedServer mockServer(suite); // Increment suite state/modify change number
-
- suite->changeClockType("hybrid");
- return true;
-}
-
-static bool s0_change_clock_date(defs_ptr defs) {
- suite_ptr suite = defs->findSuite("s0");
- BOOST_REQUIRE_MESSAGE( suite,"Could not find suite");
-
- suite->changeClockDate("1.1.2001");
- return true;
-}
-
-static bool s0_change_clock_sync(defs_ptr defs) {
- suite_ptr suite = defs->findSuite("s0");
- BOOST_REQUIRE_MESSAGE( suite,"Could not find suite");
- MockSuiteChangedServer mockServer(suite); // Increment suite state/modify change number
-
- suite->changeClockSync();
- return true;
-}
-
-/// This has been split into two functions, as changing both together could mask an error
-/// i.e found bug where we forgot to update state_change number when changing the limit
-/// max value, however because we had, changed value as well it got masked.
-static bool s0_change_limit_max(defs_ptr defs) {
- suite_ptr suite = defs->findSuite("s0");
- BOOST_REQUIRE_MESSAGE( suite,"Could not find suite");
- // Note: we ONLY* need MockSuiteChangedServer, when we make changes via functions and not commands
-
- std::vector<limit_ptr> theLimits = suite->limits();
- BOOST_REQUIRE_MESSAGE( !theLimits.empty(),"The limit are empty on suite s0 " << defs);
- BOOST_FOREACH(limit_ptr l, theLimits) {
- //std::cout << "found " << l->toString() << "\n";
- TestHelper::invokeRequest(defs.get(),Cmd_ptr( new AlterCmd(suite->absNodePath(),AlterCmd::LIMIT_MAX,l->name(),"90")));
- limit_ptr v = suite->find_limit(l->name());
- BOOST_CHECK_MESSAGE( v.get() && v->theLimit() == 90, "expected to find limit with max value of 90");
- }
- return true;
-}
-
-static bool s0_change_limit_value(defs_ptr defs) {
- suite_ptr suite = defs->findSuite("s0");
- BOOST_REQUIRE_MESSAGE( suite,"Could not find suite");
- // Note: we ONLY* need MockSuiteChangedServer, when we make changes via functions and not commands
-
- std::vector<limit_ptr> theLimits = suite->limits();
- BOOST_FOREACH(limit_ptr l, theLimits) {
- TestHelper::invokeRequest(defs.get(),Cmd_ptr( new AlterCmd(suite->absNodePath(),AlterCmd::LIMIT_VAL,l->name(),"33")));
- limit_ptr v = suite->find_limit(l->name());
- BOOST_CHECK_MESSAGE( v.get() && v->value() == 33, "expected to find limit with value of 33");
- }
- return true;
-}
-
-static bool s0_update_repeat(defs_ptr defs) {
-
- suite_ptr suite = defs->findSuite("s0");
- BOOST_REQUIRE_MESSAGE( suite,"Could not find suite");
- MockSuiteChangedServer mockServer(suite); // Increment suite state/modify change number
-
-
- SuiteChanged1 changed(suite.get());
- suite->increment_repeat();
- return true;
-}
-
-// ===============================================
-
-BOOST_AUTO_TEST_CASE( test_ssync_using_handle )
-{
- cout << "Base:: ...test_ssync_using_handle\n";
-
- // =======================================================================================
- // Note: where we update Suite::modify_change_no() we should *EXPECT* a full sync
- // =======================================================================================
-
- // test_sync_scaffold will created 5 suites s0,s1,s2,s3,s4,s5 and add suites s0 & s4 to a handle
- // The following test will perform changes in/out of handles
-
- { // Change defs state in the presence of handles. These should sync regardless of handles
- // The default server state is HALTED, hence setting to halted will not show a change
- test_sync_scaffold(set_server_state_shutdown,"set_server_state_shutdown");
- test_sync_scaffold(set_server_state_running,"set_server_state_running");
-
- test_sync_scaffold(add_server_variable,"add_server_variable");
- test_sync_scaffold(change_server_variable,"change_server_variable");
-
- test_sync_scaffold(set_defs_state,"set_defs_state");
- test_sync_scaffold(set_defs_state_2,"set_defs_state_2",true /* expect a full sync */);
- }
-
- test_sync_scaffold(change_suites_s3_outside_of_handle,"change_suites_s3_outside_of_handle");
- test_sync_scaffold(change_suites_s3_outside_of_handle_add_variable,"change_suites_s3_outside_of_handle_add_variable");
- test_sync_scaffold(add_task_to_suite_s3,"add_task_to_suite_s3");
- test_sync_scaffold(delete_task_on_suite_s3,"delete_task_on_suite_s3");
- test_sync_scaffold(delete_family_on_suite_s3,"delete_family_on_suite_s3");
-
- test_sync_scaffold(change_order_of_s4_top,"change_order_of_s4_top"); // change order is an incremental sync
- test_sync_scaffold(change_order_of_s4_bottom,"change_order_of_s4_bottom"); // change order is an incremental sync
-
- test_sync_scaffold(change_state_of_s4,"change_state_of_s4");
- test_sync_scaffold(add_variable_to_suite_s4,"add_variable_to_suite_s4");
- test_sync_scaffold(add_server_user_variables,"add_server_user_variables");
- test_sync_scaffold(add_task_to_suite_s4,"add_task_to_suite_s4");
- test_sync_scaffold(delete_task_on_suite_s4,"delete_task_on_suite_s4");
- test_sync_scaffold(delete_family_on_suite_s4,"delete_family_on_suite_s4");
- test_sync_scaffold(delete_suite_s4,"delete_suite_s4", true /* expect a full sync */);
-
-
- test_sync_scaffold(s0_delete_some_attributes,"s0_delete_some_attributes");
- test_sync_scaffold(s0_add_some_attributes,"s0_add_some_attributes");
- test_sync_scaffold(s0_add_alias,"s0_add_alias");
- test_sync_scaffold(s0_update_repeat,"s0_update_repeat");
- test_sync_scaffold(s0_change_limit_max,"s0_change_limit_max");
- test_sync_scaffold(s0_change_limit_value,"s0_change_limit_value");
- test_sync_scaffold(s0_begin,"s0_begin", true/* expect a full sync */);
-
- test_sync_scaffold(s0_remove_all_tasks,"s0_remove_all_tasks" );
- test_sync_scaffold(s0_remove_a_family,"s0_remove_a_family");
-
- test_sync_scaffold(s0_change_clock_gain,"s0_change_clock_gain", true/* expect a full sync */);
- test_sync_scaffold(s0_change_clock_type_to_real,"s0_change_clock_type_to_real", true/* expect a full sync */);
- test_sync_scaffold(s0_change_clock_date,"s0_change_clock_date", true/* expect a full sync */);
- test_sync_scaffold(s0_change_clock_sync,"s0_change_clock_sync", true/* expect a full sync */);
-
- /// Keep valgrind happy
- ChangeMgrSingleton::destroy();
-}
-
-
-
-static defs_ptr create_the_server_defs()
-{
- defs_ptr defs = create_server_defs();
- std::vector<suite_ptr> suite_vec = defs->suiteVec();
- for(size_t j = 0; j < suite_vec.size(); j++) {
- suite_vec[j]->set_state_change_no(j);
- suite_vec[j]->set_modify_change_no(j);
- }
- return defs;
-}
-
-BOOST_AUTO_TEST_CASE( test_ssync_full_sync_using_handle )
-{
- /// This test checks that when user has registered with all the suites.
- /// Syncing should use the global change numbers
- /// **ADDITIONALLY* the newsCmd must reflect this.
- /// This is handled in ClientSuites::create_defs, in that we *MUST* update the
- /// local change numbers to be the same as the global change numbers
- /// This is important since the NewsCmd must be in *SYNC* with SYNCCmd
-
- cout << "Base:: ...test_ssync_full_sync_using_handle\n";
- // Create the server defs with some changes, in state & modify numbers
- defs_ptr server_defs = create_the_server_defs();
-
- // Create Client defs, without any changes
- ServerReply server_reply;
- server_reply.set_client_defs( create_client_defs(Defs::create()) );
-
- // Server & client should be the same, since we ignore change numbers in the comparison
- Ecf::set_debug_equality(true); // only has affect in DEBUG build
- BOOST_CHECK_MESSAGE( *server_defs == *server_reply.client_defs(), "Starting point client and server defs should be the same"
- << "SERVER\n" << server_defs
- << "CLIENT\n" << server_reply.client_defs());
- Ecf::set_debug_equality(false);
-
- /// register interest in **ALL** the suites
- std::vector<std::string> suite_names;
- suite_names.push_back("s0");
- suite_names.push_back("s1");
- suite_names.push_back("s2");
- suite_names.push_back("s3");
- suite_names.push_back("s4");
- TestHelper::invokeRequest(server_defs.get(),Cmd_ptr( new ClientHandleCmd(suite_names,false)),bypass_state_modify_change_check);
-
- /// make sure handle created.
- BOOST_CHECK_MESSAGE(server_defs->client_suite_mgr().clientSuites().size() == 1,"Expected 1 Client suites but found " <<server_defs->client_suite_mgr().clientSuites().size());
- unsigned int client_handle = server_defs->client_suite_mgr().clientSuites().front().handle();
- BOOST_CHECK_MESSAGE( client_handle == 1,"" );
-
- // make sure server suites have different state/modify numbers from the client
- {
- unsigned int server_state_change_no = 0;
- unsigned int server_modify_change_no = 0;
- server_defs->client_suite_mgr().max_change_no(client_handle,server_state_change_no, server_modify_change_no);
- BOOST_CHECK_MESSAGE(server_state_change_no == 4,"" );
- BOOST_CHECK_MESSAGE(server_modify_change_no == 4,"" );
-
- // *MAKE* sure global change numbers are different to handle suite change numbers
- // This is the key part of this test.
- // Since syncing should transfer these change numbers to the client
- Ecf::set_state_change_no(server_state_change_no+10);
- Ecf::set_modify_change_no(server_modify_change_no+20);
- }
-
- // Now sync from server
- Ecf::set_server(true);
- MockServer mock_server(server_defs);
- /* server side */ SNewsCmd news_cmd(client_handle, server_reply.client_defs()->state_change_no(), server_reply.client_defs()->modify_change_no(), &mock_server );
- /* server side */ SSyncCmd cmd(client_handle, server_reply.client_defs()->state_change_no(), server_reply.client_defs()->modify_change_no(), &mock_server );
- Ecf::set_server(false);
-
- // make sure SSyncCmd updated the server change numbers, to use global change numbers
- unsigned int server_state_change_no = 0;
- unsigned int server_modify_change_no = 0;
- {
- server_defs->client_suite_mgr().max_change_no(client_handle,server_state_change_no, server_modify_change_no);
- BOOST_CHECK_MESSAGE(server_state_change_no == 14,"" );
- BOOST_CHECK_MESSAGE(server_modify_change_no == 24,"" );
- }
-
- // SYNC the client, via do_sync( this should transfer change numbers to the client )
- BOOST_CHECK_MESSAGE( news_cmd.get_news(), "Expected server to change");
- BOOST_CHECK_MESSAGE( cmd.do_sync( server_reply ), "Expected server to change");
- BOOST_CHECK_MESSAGE( server_reply.in_sync(), "Expected server to change");
- BOOST_CHECK_MESSAGE( server_defs->state() == server_reply.client_defs()->state(),"Expected server State(" << NState::toString(server_defs->state()) << ") to be same as client state(" << NState::toString(server_reply.client_defs()->state()) << ")");
-
- // After do_sync client and server change number should be in sync
- BOOST_CHECK_MESSAGE(server_reply.client_defs()->state_change_no() == server_state_change_no,"Expected " << server_reply.client_defs()->state_change_no() << " state change number but found " << server_state_change_no);
- BOOST_CHECK_MESSAGE(server_reply.client_defs()->modify_change_no() == server_modify_change_no,"Expected " << server_reply.client_defs()->modify_change_no() << " modify change number but found " << server_modify_change_no);
-
- // Do final sync, there should not be ANY changes
- Ecf::set_server(true);
- /* server side */ SNewsCmd news_cmd1(client_handle, server_reply.client_defs()->state_change_no(), server_reply.client_defs()->modify_change_no(), &mock_server );
- /* server side */ SSyncCmd cmd1(client_handle, server_reply.client_defs()->state_change_no(), server_reply.client_defs()->modify_change_no(), &mock_server );
- Ecf::set_server(false);
- /* client side */ BOOST_CHECK_MESSAGE( !news_cmd1.get_news(), "Expected no changes to client, we should be in sync");
- /* client side */ BOOST_CHECK_MESSAGE( !cmd1.do_sync( server_reply ), "Expected no changes to client, we should be in sync");
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/CMakeLists.txt b/ecflow_4_0_7/CMakeLists.txt
deleted file mode 100644
index b75fb3e..0000000
--- a/ecflow_4_0_7/CMakeLists.txt
+++ /dev/null
@@ -1,191 +0,0 @@
-############################################################################################
-# cmake options:
-#
-# -DCMAKE_BUILD_TYPE=Debug|RelWithDebInfo|Release|Production
-# -DCMAKE_INSTALL_PREFIX=/path/to/install
-#
-# -DCMAKE_MODULE_PATH=/path/to/ecbuild/cmake
-#
-# -DCMAKE_C_COMPILER=gcc
-# -DCMAKE_C_COMPILER=g++
-#
-# -DCMAKE_PREFIX_PATH=/path/to/jasper:/path/to/any/package/out/of/place
-# -DBUILD_SHARED_LIBS=OFF
-# =========================================================================================
-# Usage instructions:
-#
-# cd $WK
-# release=$(cat VERSION.cmake | grep 'set( ECFLOW_RELEASE' | awk '{print $3}'| sed 's/["]//g')
-# major=$(cat VERSION.cmake | grep 'set( ECFLOW_MAJOR' | awk '{print $3}'| sed 's/["]//g')
-# minor=$(cat VERSION.cmake | grep 'set( ECFLOW_MINOR' | awk '{print $3}'| sed 's/["]//g')
-#
-# mkdir ecbuild
-# cd ecbuild
-# mkdir debug
-# mkdir release
-# cd debug
-#
-#/usr/local/apps/cmake/current/bin/cmake ../../ \
-# -DCMAKE_BUILD_TYPE=Debug \
-# -DCMAKE_MODULE_PATH=/usr/local/apps/ecbuild/current/share/ecbuild/cmake \
-# -DPYTHON_LIBRARY=/usr/local/apps/python/current/lib/libpython2.7.a \
-# -DPYTHON_INCLUDE_DIR=/usr/local/apps/python/current/include/python2.7 \
-# -DPYTHON_EXECUTABLE=/usr/local/apps/python/current/bin/python2.7 \
-# -DCMAKE_INSTALL_PREFIX=/usr/local/apps/ecflow/$release.$major.$minor
-#
-# -DCMAKE_INSTALL_PREFIX=/var/tmp/ma0/cmake/ecflow/4.0.1
-#
-#############################################################
-
-cmake_minimum_required( VERSION 2.8.4 FATAL_ERROR )
-
-project( ecflow CXX )
-
-set( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../ecbuild/cmake")
-# message( STATUS "CMAKE_MODULE_PATH : ${CMAKE_MODULE_PATH}")
-
-include( ecbuild_system )
-
-ecbuild_requires_macro_version( 1.3 )
-
-###############################################################################
-# local project
-
-ecbuild_declare_project()
-
-# =========================================================================================
-# VERSION
-# Get the ecflow version specified in 'VERSION.cmake'. This is only accessible after ecbuild_declare_project()
-# The ecflow version config is done in ACore directory
-# =========================================================================================
-
-message( STATUS "CMAKE_INSTALL_PREFIX : ${CMAKE_INSTALL_PREFIX}" )
-message( STATUS "ECFLOW_RELEASE : ${ECFLOW_RELEASE}" )
-message( STATUS "ECFLOW_MAJOR : ${ECFLOW_MAJOR}" )
-message( STATUS "ECFLOW_MINOR : ${ECFLOW_MINOR}" )
-message( STATUS "ECFLOW_VERSION : ${ECFLOW_VERSION_STR}" )
-
-# =========================================================================================
-# Python
-# =========================================================================================
-# some variables of this project
-
-option( ENABLE_PYTHON "enable python interface" ON )
-
-if(ENABLE_PYTHON)
- ecbuild_find_python( VERSION 2.7 REQUIRED )
- debug_var(PYTHON_LIBRARIES)
- debug_var(PYTHON_INCLUDE_DIR)
-else()
- ecbuild_find_python( VERSION 2.7 )
-endif()
-
-# =========================================================================================
-# Boost
-# Jira ISSUE: ECBUILD-40 ecbuild 1.3.2 ignores -DBOOST_ROOT
-# setting -DBOOST_ROOT=/var/tmp/ma0/boost/boost_1_53_0
-# Does not appear to be honored. ?
-# It always seem to use boost in /usr/local/apps
-# =========================================================================================
-
-ecbuild_add_extra_search_paths( boost ) # also respects BOOST_ROOT
-
-# Ecflow test require statics libs, otherwise get double free, error.
-# To use static boost python ensure that Boost_USE_STATIC_LIBS is set on.
-# See: http://www.cmake.org/cmake/help/v3.0/module/FindBoost.html
-set(Boost_USE_STATIC_LIBS ON)
-set(Boost_USE_MULTITHREADED ON)
-set(Boost_NO_SYSTEM_PATHS ON)
-set(Boost_DETAILED_FAILURE_MSG ON)
-set(Boost_DEBUG ON)
-
-find_package( Boost 1.53.0 REQUIRED COMPONENTS python serialization system thread unit_test_framework test_exec_monitor filesystem program_options date_time )
-#
-# Available boost lib should be referenced as:
-#
-# ${Boost_SYSTEM_LIBRARY}
-# ${Boost_SERIALIZATION_LIBRARY}
-# ${Boost_THREAD_LIBRARY}
-# ${Boost_FILESYSTEM_LIBRARY}
-# ${Boost_PROGRAM_OPTIONS_LIBRARY}
-# ${Boost_DATE_TIME_LIBRARY}
-#
-# ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}
-# ${Boost_TEST_EXEC_MONITOR_LIBRARY}
-
-message( STATUS "Boost_LIBRARIES : ${Boost_LIBRARIES}" )
-
-
-# =========================================================================================
-# debug
-# =========================================================================================
-if( CMAKE_BUILD_TYPE MATCHES "[Dd][Ee][Bb][Uu][Gg]" )
-
- message( STATUS "INFO: DEBUG BUILD" )
-
- # for debug type builds, turn on verbose makefiles
- # set(CMAKE_VERBOSE_MAKEFILE ON)
-
- # Tell other CMake files that we're doing a debug build
- # set( DEBUG_BUILD 1 ) -- not used anymore
-
- # Tell C/C++ that we're doing a debug build
- add_definitions( -DDEBUG )
-
-endif()
-
-
-# =========================================================================================
-# build source code
-# =========================================================================================
-
-add_subdirectory( ACore )
-add_subdirectory( ANattr )
-add_subdirectory( ANode )
-add_subdirectory( AParser )
-add_subdirectory( Base )
-add_subdirectory( Client )
-add_subdirectory( CSim )
-add_subdirectory( Server )
-add_subdirectory( Test )
-add_subdirectory( Pyext )
-add_subdirectory( view )
-
-# Directories not need in the distribution tar ball!
-ecbuild_add_resources( TARGET build_nightly DONT_PACK_DIRS build/nightly)
-ecbuild_add_resources( TARGET SCRATCH DONT_PACK_DIRS SCRATCH)
-ecbuild_add_resources( TARGET Doc DONT_PACK_DIRS Doc/func_spec Doc/misc Doc/New_viewer Doc/newsletter Doc/online Doc/presentations Doc/tac)
-
-# =========================================================================================
-# install
-# =========================================================================================
-# install scripts
-install( FILES
- ${CMAKE_SOURCE_DIR}/tools/ecflow_logsvr.pl
- ${CMAKE_SOURCE_DIR}/tools/ecflow_logsvr.sh
- ${CMAKE_SOURCE_DIR}/tools/ecflow_start.sh
- ${CMAKE_SOURCE_DIR}/tools/ecflow_stop.sh
- ${CMAKE_SOURCE_DIR}/tools/noconnect.sh
- ${CMAKE_SOURCE_DIR}/Pyext/migrate/ecflow_migrate.py
- DESTINATION bin
- PERMISSIONS OWNER_READ GROUP_READ WORLD_READ OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE
- )
-
-# install documentation
-install( FILES
- ${CMAKE_SOURCE_DIR}/Doc/user-manual/client_options.docx
- ${CMAKE_SOURCE_DIR}/Doc/user-manual/user_manual.docx
- ${CMAKE_SOURCE_DIR}/Doc/user-manual/user_manual.pdf
- DESTINATION doc/ecflow
- PERMISSIONS OWNER_READ GROUP_READ WORLD_READ OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE
- )
-
-# =========================================================================================
-# final
-# =========================================================================================
-
-# prepares a tar.gz of your sources and/or binaries
-ecbuild_install_project( NAME ecFlow )
-
-# print the summary of the configuration
-ecbuild_print_summary()
diff --git a/ecflow_4_0_7/CSim/CMakeLists.txt b/ecflow_4_0_7/CSim/CMakeLists.txt
deleted file mode 100644
index d5ad142..0000000
--- a/ecflow_4_0_7/CSim/CMakeLists.txt
+++ /dev/null
@@ -1,50 +0,0 @@
-list( APPEND srcs
- src/Analyser.cpp
- src/AstAnalyserVisitor.cpp
- src/DefsAnalyserVisitor.cpp
- src/FlatAnalyserVisitor.cpp
- src/Simulator.cpp
- src/SimulatorVisitor.cpp
-)
-ecbuild_add_library( TARGET libsimu
- NOINSTALL
- TYPE STATIC
- SOURCES ${srcs}
- LIBS libparser node nodeattr core
- INCLUDES src
- ../ACore/src
- ../ANattr/src
- ../ANode/src
- ../AParser/src
- ../Base/src
- )
-
-
-list( APPEND test_srcs
- test/TestMeter.cpp
- test/TestTime.cpp
- test/TestUtil.cpp
- test/TestSimulator.cpp
- test/TestAutoCancel.cpp
- test/TestRepeat.cpp
- test/TestToday.cpp
- test/TestAnalysis.cpp
-)
-ecbuild_add_test( TARGET c_csim
- BOOST
- SOURCES ${test_srcs}
- LIBS libsimu
- pthread
- INCLUDES ../ANode/test
- TEST_DEPENDS u_base
- )
-
-ecbuild_add_test( TARGET c_csim_single
- BOOST
- SOURCES test/TestSingleSimulator.cpp test/TestUtil.cpp
- LIBS libsimu
- pthread
- INCLUDES ../ANode/test
- TEST_DEPENDS u_base
- )
-
\ No newline at end of file
diff --git a/ecflow_4_0_7/CSim/jamfile.jam b/ecflow_4_0_7/CSim/jamfile.jam
deleted file mode 100644
index 4418317..0000000
--- a/ecflow_4_0_7/CSim/jamfile.jam
+++ /dev/null
@@ -1,95 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-#
-# Simulator. Standalone exe that can:
-# 1/ Check structure of the definition file
-# 2/ Simulate the definition
-# allow checking for dead locks, etc
-project theSimulator ;
-
-#
-# IMPORTANT: Simulator *MUST* not link with server or any of its source code
-#
-use-project theCore : ../ACore ;
-use-project theNodeAttr : ../ANattr ;
-use-project theNode : ../ANode ;
-use-project theParser : ../AParser ;
-use-project theBase : ../Base ;
-
-lib pthread ;
-
-#
-# Split into library, so that testing can use library, and hence same compiler option
-#
-# The <include> means we will automatically add this directory to the include path
-# of any other target that uses this lib
-#
-lib libsimu : [ glob src/*.cpp ]
- : <include>../ACore/src
- <include>../ANattr/src
- <include>../ANode/src
- <include>../AParser/src
- <include>../Base/src
- <variant>debug:<define>DEBUG
- <link>static
- <use>/theCore//core
- <use>/theNodeAttr//nodeattr
- <use>/theNode//node
- <use>/theBase//base
- <use>/theParser//libparser
- <use>/site-config//boost_system
- <use>/site-config//boost_serialization
- <use>/site-config//boost_filesystem
- <use>/site-config//boost_program_options
- <use>/site-config//boost_datetime
- :
- : <include>../CSim/src
- ;
-
-
-#
-# Test for simulator
-# IMPORTANT: server *MUST* not link with client or include any of the client code
-#
-exe c_csim : [ glob test/*.cpp : test/TestSingleSimulator.cpp ]
- pthread
- /theCore//core
- /theNodeAttr//nodeattr
- /theNode//node
- /theParser//libparser
- /theBase//base
- libsimu
- /site-config//boost_system
- /site-config//boost_serialization
- /site-config//boost_filesystem
- /site-config//boost_datetime
- /site-config//boost_program_options
- /site-config//boost_test
- : <variant>debug:<define>DEBUG
- ;
-
-#
-# Test for single simulator. Use for developing the tests
-# IMPORTANT: server *MUST* not link with client or include any of the client code
-#
-exe c_csim_single : [ glob test/TestSingleSimulator.cpp test/TestUtil.cpp ]
- pthread
- /theCore//core
- /theNodeAttr//nodeattr
- /theNode//node
- /theParser//libparser
- /theBase//base
- libsimu
- /site-config//boost_system
- /site-config//boost_serialization
- /site-config//boost_filesystem
- /site-config//boost_datetime
- /site-config//boost_program_options
- /site-config//boost_test
- : <variant>debug:<define>DEBUG
- ;
diff --git a/ecflow_4_0_7/CSim/src/Analyser.cpp b/ecflow_4_0_7/CSim/src/Analyser.cpp
deleted file mode 100644
index 6f8febf..0000000
--- a/ecflow_4_0_7/CSim/src/Analyser.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "Analyser.hpp"
-#include "DefsAnalyserVisitor.hpp"
-#include "FlatAnalyserVisitor.hpp"
-#include "Defs.hpp"
-#include "File.hpp"
-#include <iostream>
-#include <fstream>
-
-using namespace std;
-
-namespace ecf {
-
-Analyser::Analyser() {}
-
-void Analyser::run(Defs& theDefs)
-{
- // Run flat analysis
- {
- FlatAnalyserVisitor visitor;
- theDefs.acceptVisitTraversor(visitor);
-
- std::string fileName = "defs.flat";
-
- std::ofstream file(fileName.c_str());
- file << visitor.report();
- }
-
- // run depth first analysis
- {
- DefsAnalyserVisitor visitor;
- theDefs.acceptVisitTraversor(visitor);
-
- std::string fileName = "defs.depth";
-
- std::ofstream file(fileName.c_str(),ios::out);
- file << visitor.report();
- file.close();
- }
-}
-
-}
-
diff --git a/ecflow_4_0_7/CSim/src/Analyser.hpp b/ecflow_4_0_7/CSim/src/Analyser.hpp
deleted file mode 100644
index c223180..0000000
--- a/ecflow_4_0_7/CSim/src/Analyser.hpp
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef ANALYSER_HPP_
-#define ANALYSER_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-class Defs;
-
-namespace ecf {
-
-class Analyser {
-public:
- Analyser();
-
- static void run(Defs& theDefs);
-};
-
-}
-#endif
diff --git a/ecflow_4_0_7/CSim/src/AstAnalyserVisitor.cpp b/ecflow_4_0_7/CSim/src/AstAnalyserVisitor.cpp
deleted file mode 100644
index c56f592..0000000
--- a/ecflow_4_0_7/CSim/src/AstAnalyserVisitor.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
- //============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "AstAnalyserVisitor.hpp"
-#include "ExprAst.hpp"
-#include "Defs.hpp"
-
-using namespace std;
-
-namespace ecf {
-
-AstAnalyserVisitor::AstAnalyserVisitor() {}
-AstAnalyserVisitor::~AstAnalyserVisitor() {}
-
-void AstAnalyserVisitor::visitTop(AstTop*) {}
-void AstAnalyserVisitor::visitRoot(AstRoot*) {}
-void AstAnalyserVisitor::visitAnd(AstAnd*) {}
-void AstAnalyserVisitor::visitNot(AstNot*) {}
-void AstAnalyserVisitor::visitPlus(AstPlus*) {}
-void AstAnalyserVisitor::visitMinus(AstMinus*) {}
-void AstAnalyserVisitor::visitDivide(AstDivide*) {}
-void AstAnalyserVisitor::visitMultiply(AstMultiply*) {}
-void AstAnalyserVisitor::visitModulo(AstModulo*) {}
-void AstAnalyserVisitor::visitOr(AstOr*) {}
-void AstAnalyserVisitor::visitEqual(AstEqual*) {}
-void AstAnalyserVisitor::visitNotEqual(AstNotEqual*) {}
-void AstAnalyserVisitor::visitLessEqual(AstLessEqual*) {}
-void AstAnalyserVisitor::visitGreaterEqual(AstGreaterEqual*) {}
-void AstAnalyserVisitor::visitGreaterThan(AstGreaterThan*) {}
-void AstAnalyserVisitor::visitLessThan(AstLessThan*) {}
-void AstAnalyserVisitor::visitLeaf(AstLeaf*) {}
-void AstAnalyserVisitor::visitInteger(AstInteger*) {}
-void AstAnalyserVisitor::visitString(AstString*) {}
-void AstAnalyserVisitor::visitNodeState(AstNodeState*) {}
-void AstAnalyserVisitor::visitEventState(AstEventState*) {}
-
-void AstAnalyserVisitor::visitNode(AstNode* astNode)
-{
- Node* refNode = astNode->referencedNode();
- if ( refNode ) dependentNodes_.insert( refNode);
- else dependentNodePaths_.insert(astNode->nodePath());
-}
-
-void AstAnalyserVisitor::visitVariable(AstVariable* astVar){}
-
-}
diff --git a/ecflow_4_0_7/CSim/src/AstAnalyserVisitor.hpp b/ecflow_4_0_7/CSim/src/AstAnalyserVisitor.hpp
deleted file mode 100644
index 216f52f..0000000
--- a/ecflow_4_0_7/CSim/src/AstAnalyserVisitor.hpp
+++ /dev/null
@@ -1,64 +0,0 @@
-#ifndef ASTANALYSERVISITOR_HPP_
-#define ASTANALYSERVISITOR_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "ExprAstVisitor.hpp"
-#include <iostream>
-#include <sstream>
-#include <set>
-class Node;
-
-namespace ecf {
-
-class AstAnalyserVisitor : public ExprAstVisitor {
-public:
- AstAnalyserVisitor();
- virtual ~AstAnalyserVisitor();
-
- const std::set<Node*>& dependentNodes() const { return dependentNodes_;}
- const std::set<std::string>& dependentNodePaths() const { return dependentNodePaths_;}
-
- virtual void visitTop(AstTop*);
- virtual void visitRoot(AstRoot*);
- virtual void visitAnd(AstAnd*);
- virtual void visitNot(AstNot*);
- virtual void visitPlus(AstPlus*);
- virtual void visitMinus(AstMinus*);
- virtual void visitDivide(AstDivide*);
- virtual void visitMultiply(AstMultiply*);
- virtual void visitModulo(AstModulo*);
- virtual void visitOr(AstOr*);
- virtual void visitEqual(AstEqual*);
- virtual void visitNotEqual(AstNotEqual*);
- virtual void visitLessEqual(AstLessEqual*);
- virtual void visitGreaterEqual(AstGreaterEqual*);
- virtual void visitGreaterThan(AstGreaterThan*);
- virtual void visitLessThan(AstLessThan*);
- virtual void visitLeaf(AstLeaf*);
- virtual void visitInteger(AstInteger*);
- virtual void visitString(AstString*);
- virtual void visitNodeState(AstNodeState*);
- virtual void visitEventState(AstEventState*);
- virtual void visitNode(AstNode*);
- virtual void visitVariable(AstVariable*);
-
-private:
- std::set<Node*> dependentNodes_;
- std::set<std::string> dependentNodePaths_;
-};
-}
-#endif
diff --git a/ecflow_4_0_7/CSim/src/DefsAnalyserVisitor.cpp b/ecflow_4_0_7/CSim/src/DefsAnalyserVisitor.cpp
deleted file mode 100644
index dcd5d3b..0000000
--- a/ecflow_4_0_7/CSim/src/DefsAnalyserVisitor.cpp
+++ /dev/null
@@ -1,167 +0,0 @@
- //============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "DefsAnalyserVisitor.hpp"
-#include "AstAnalyserVisitor.hpp"
-#include "ExprAst.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "Indentor.hpp"
-#include "Str.hpp"
-
-using namespace std;
-
-namespace ecf {
-
-///////////////////////////////////////////////////////////////////////////////
-DefsAnalyserVisitor::DefsAnalyserVisitor() {}
-
-void DefsAnalyserVisitor::visitDefs( Defs* d) {
- BOOST_FOREACH(suite_ptr s, d->suiteVec()) { s->acceptVisitTraversor(*this); }
-}
-
-void DefsAnalyserVisitor::visitSuite( Suite* s) { visitNodeContainer(s);}
-void DefsAnalyserVisitor::visitFamily( Family* f) { visitNodeContainer(f);}
-
-void DefsAnalyserVisitor::visitNodeContainer(NodeContainer* nc)
-{
- std::set<Node*> dependentNodes;
- analyse(nc,dependentNodes);
-
- BOOST_FOREACH(node_ptr t, nc->nodeVec()) { t->acceptVisitTraversor(*this);}
-}
-
-void DefsAnalyserVisitor::visitTask( Task* t)
-{
- std::set<Node*> dependentNodes;
- analyse(t,dependentNodes);
-}
-
-void DefsAnalyserVisitor::analyse(Node* node,std::set<Node*>& dependentNodes, bool dependent)
-{
- // ***************************************************************
- // Do a depth first search to find the root cause of the blockage
- // ***************************************************************
-//#ifdef DEBUG
-// if (dependent) {
-// ss_ << "DefsAnalyserVisitor::analyse " << node->debugType() << Str::COLON() << node->absNodePath();
-// ss_ << " state(" << NState::toString(node->state()) << ")\n";
-// }
-//#endif
- if (analysedNodes_.find(node) != analysedNodes_.end()) return;
- analysedNodes_.insert( node );
- if (node->state() == NState::COMPLETE ) return;
-
- if (node->state() == NState::QUEUED) {
- std::vector<std::string> theReasonWhy;
- node->why(theReasonWhy);
- for(size_t i = 0; i < theReasonWhy.size(); ++i) {
- Indentor::indent(ss_) << "Reason: " << theReasonWhy[i] << "\n";
- }
- }
-
-
- /// Note a complete expression that does not evaluate, does *NOT* hold the node
- /// It merly sets node to complete.
- if ( node->completeAst() && !node->evaluateComplete()) {
- // Follow nodes referenced in the complete expressions
- analyseExpressions(node,dependentNodes,false,dependent);
-
- // follow child nodes
- NodeContainer* nc = dynamic_cast<NodeContainer*>(node);
- if (nc) {
- BOOST_FOREACH(node_ptr t, nc->nodeVec()) { t->acceptVisitTraversor(*this);}
- }
- }
-
-
- if ( node->triggerAst() && !node->evaluateTrigger() ) {
- // Follow nodes referenced in the trigger expressions
- analyseExpressions(node,dependentNodes,true,dependent);
-
- // follow child nodes
- NodeContainer* nc = dynamic_cast<NodeContainer*>(node);
- if (nc) {
- BOOST_FOREACH(node_ptr t, nc->nodeVec()) { t->acceptVisitTraversor(*this);}
- }
- }
-}
-
-void DefsAnalyserVisitor::analyseExpressions(Node* node,std::set<Node*>& dependentNodes, bool trigger, bool dependent)
-{
- Indentor in; Indentor::indent(ss_);
- if ( dependent ) ss_ << "DEPENDENT ";
- if (trigger) {
- ss_ << node->debugNodePath() << " holding on trigger expression '" << node->triggerExpression() << "'\n";
- }
- else {
- ss_ << node->debugNodePath() << " holding on complete expression '" << node->completeExpression() << "'\n";
- }
-
-
- AstAnalyserVisitor astVisitor;
- if ( trigger ) {
- node->triggerAst()->accept(astVisitor);
- ss_ << *node->triggerAst();
- }
- else {
- node->completeAst()->accept(astVisitor);
- ss_ << *node->completeAst();
- }
-
- // Warn about NULL node references in the trigger expressions
- BOOST_FOREACH(const string& nodePath, astVisitor.dependentNodePaths()) {
- Indentor in; Indentor::indent(ss_) << "'" << nodePath << "' is not defined in the expression\n";
- }
-
- // **** NOTE: Currently for COMPLETE expression will only follow trigger expressions
- BOOST_FOREACH(Node* triggerNode, astVisitor.dependentNodes()) {
-
-
- Indentor in; Indentor::indent(ss_) << "EXPRESSION NODE " << triggerNode->debugNodePath();
- ss_ << " state(" << NState::toString(triggerNode->state()) << ")";
- if (triggerNode->triggerAst()) ss_ << " trigger(evaluation = " << triggerNode->evaluateTrigger() << "))";
- if (analysedNodes_.find(triggerNode) != analysedNodes_.end()) ss_ << " analysed ";
- if (dependentNodes.find(triggerNode) != dependentNodes.end()) ss_ << " ** ";
- ss_ << "\n";
-
- if ( dependentNodes.find(triggerNode) != dependentNodes.end()) {
- // possible deadlock make sure
- if (triggerNode->triggerAst()) {
- AstAnalyserVisitor visitor;
- triggerNode->triggerAst()->accept(visitor);
-
-// cerr << "Node = " << node->absNodePath() << "\n";
-// cerr << "triggerNode = " << triggerNode->absNodePath() << "\n";
-// BOOST_FOREACH(Node* n,visitor.dependentNodes() ) {
-// cerr << "triggerNode Node dependents = " << n->absNodePath() << "\n";
-// }
-
- if (visitor.dependentNodes().find(node) != visitor.dependentNodes().end()) {
- Indentor in; Indentor::indent(ss_) << "Deadlock detected between:\n";
- Indentor in2; Indentor::indent(ss_) << node->debugNodePath() << "\n";
- Indentor::indent(ss_) << triggerNode->debugNodePath() << "\n";
- }
- }
- continue;
- }
- dependentNodes.insert( triggerNode );
- analyse(triggerNode,dependentNodes,true);
- }
-}
-
-}
diff --git a/ecflow_4_0_7/CSim/src/DefsAnalyserVisitor.hpp b/ecflow_4_0_7/CSim/src/DefsAnalyserVisitor.hpp
deleted file mode 100644
index bf9b33e..0000000
--- a/ecflow_4_0_7/CSim/src/DefsAnalyserVisitor.hpp
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef DEFSANALYSERVISITOR_HPP_
-#define DEFSANALYSERVISITOR_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "NodeTreeVisitor.hpp"
-#include <sstream>
-#include <set>
-#include <vector>
-class Node;
-
-namespace ecf {
-
-class DefsAnalyserVisitor : public NodeTreeVisitor {
-public:
- DefsAnalyserVisitor();
- std::string report() const { return ss_.str();}
-
- virtual bool traverseObjectStructureViaVisitors() const { return true;}
- virtual void visitDefs(Defs*);
- virtual void visitSuite(Suite*);
- virtual void visitFamily(Family*);
- virtual void visitNodeContainer(NodeContainer*);
- virtual void visitTask(Task*);
-
-private:
- void analyse(Node* n,std::set<Node*>& dependentNodes, bool dependent = false);
- void analyseExpressions(Node* node,std::set<Node*>& dependentNodes, bool trigger, bool dependent);
-
- std::stringstream ss_;
- std::set<Node*> analysedNodes_; // The node we analysed
-};
-}
-#endif
diff --git a/ecflow_4_0_7/CSim/src/FlatAnalyserVisitor.cpp b/ecflow_4_0_7/CSim/src/FlatAnalyserVisitor.cpp
deleted file mode 100644
index f89391e..0000000
--- a/ecflow_4_0_7/CSim/src/FlatAnalyserVisitor.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
- //============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "FlatAnalyserVisitor.hpp"
-#include "AstAnalyserVisitor.hpp"
-#include "ExprAst.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "Indentor.hpp"
-#include "Str.hpp"
-
-using namespace std;
-
-namespace ecf {
-
-///////////////////////////////////////////////////////////////////////////////
-FlatAnalyserVisitor::FlatAnalyserVisitor() {}
-
-void FlatAnalyserVisitor::visitDefs( Defs* d) {
- BOOST_FOREACH(suite_ptr s, d->suiteVec()) { s->acceptVisitTraversor(*this); }
-}
-
-void FlatAnalyserVisitor::visitSuite( Suite* s) { visitNodeContainer(s);}
-void FlatAnalyserVisitor::visitFamily( Family* f) { visitNodeContainer(f);}
-
-void FlatAnalyserVisitor::visitNodeContainer(NodeContainer* nc)
-{
- if (nc->state() == NState::COMPLETE ) return;
-
- Indentor in;
- bool traverseChildren = analyse(nc);
-
- // Dont bother traversing children if parent is holding on trigger/complete expression
- if (traverseChildren) {
- BOOST_FOREACH(node_ptr t, nc->nodeVec()) { t->acceptVisitTraversor(*this);}
- }
-}
-
-void FlatAnalyserVisitor::visitTask( Task* t)
-{
- Indentor in;
- analyse(t);
-}
-
-bool FlatAnalyserVisitor::analyse(Node* node)
-{
- bool traverseChildren = true;
-
- Indentor::indent(ss_) << node->debugType() << Str::COLON() << node->name() << " state(" << NState::toString(node->state()) << ")";
- if (node->state() != NState::COMPLETE ) {
-
- if (node->repeat().isInfinite()) {
- ss_ << " may **NEVER** complete due to " << node->repeat().toString();
- }
- ss_ << "\n";
-
- if (node->state() == NState::QUEUED) {
- std::vector<std::string> theReasonWhy;
- node->why(theReasonWhy);
- for(size_t i = 0; i < theReasonWhy.size(); ++i) {
- Indentor::indent(ss_) << "Reason: " << theReasonWhy[i] << "\n";
- }
- }
-
- /// Note a complete expression that does not evaluate, does *NOT* hold the node
- /// It merly sets node to complete.
- if ( node->completeAst() && !node->evaluateComplete()) {
- Indentor::indent(ss_) << "holding on complete expression '" << node->completeExpression() << "'\n";
-
- AstAnalyserVisitor astVisitor;
- node->completeAst()->accept(astVisitor);
- BOOST_FOREACH(const string& nodePath, astVisitor.dependentNodePaths()) {
- Indentor in; Indentor::indent(ss_) << "'" << nodePath << "' is not defined in the expression\n";
- }
- ss_ << *node->completeAst();
-
- traverseChildren = false;
- }
-
- if ( node->triggerAst() && !node->evaluateTrigger() ) {
- Indentor::indent(ss_) << "holding on trigger expression '" << node->triggerExpression() << "'\n";
-
- AstAnalyserVisitor astVisitor;
- node->triggerAst()->accept(astVisitor);
- BOOST_FOREACH(const string& nodePath, astVisitor.dependentNodePaths()) {
- Indentor in; Indentor::indent(ss_) << "'" << nodePath << "' is not defined in the expression\n";
- }
- ss_ << *node->triggerAst();
-
- traverseChildren = false;
- }
- }
- ss_ << "\n";
- return traverseChildren;
-}
-
-}
diff --git a/ecflow_4_0_7/CSim/src/FlatAnalyserVisitor.hpp b/ecflow_4_0_7/CSim/src/FlatAnalyserVisitor.hpp
deleted file mode 100644
index 3f4daf1..0000000
--- a/ecflow_4_0_7/CSim/src/FlatAnalyserVisitor.hpp
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef FLATANALYSERVISITOR_HPP_
-#define FLATANALYSERVISITOR_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "NodeTreeVisitor.hpp"
-#include <sstream>
-class Node;
-
-namespace ecf {
-
-class FlatAnalyserVisitor : public NodeTreeVisitor {
-public:
- FlatAnalyserVisitor();
- std::string report() const { return ss_.str();}
-
- virtual bool traverseObjectStructureViaVisitors() const { return true;}
- virtual void visitDefs(Defs*);
- virtual void visitSuite(Suite*);
- virtual void visitFamily(Family*);
- virtual void visitNodeContainer(NodeContainer*);
- virtual void visitTask(Task*);
-
-private:
- bool analyse(Node* n);
- std::stringstream ss_;
-};
-
-}
-#endif
diff --git a/ecflow_4_0_7/CSim/src/Simulator.cpp b/ecflow_4_0_7/CSim/src/Simulator.cpp
deleted file mode 100644
index 30ca4bf..0000000
--- a/ecflow_4_0_7/CSim/src/Simulator.cpp
+++ /dev/null
@@ -1,360 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <iostream>
-#include <fstream>
-#include <stdlib.h>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/lexical_cast.hpp>
-#include <boost/date_time/posix_time/time_formatters.hpp> // requires boost date and time lib
-
-#include "Simulator.hpp"
-#include "Analyser.hpp"
-#include "SimulatorVisitor.hpp"
-#include "DefsStructureParser.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "Log.hpp"
-#include "JobsParam.hpp"
-#include "Jobs.hpp"
-#include "CalendarUpdateParams.hpp"
-#include "CmdContext.hpp"
-
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-using namespace std;
-using namespace ecf;
-namespace fs = boost::filesystem;
-
-//#define DEBUG_LONG_RUNNING_SUITES 1
-
-namespace ecf {
-
-/// Class that allows multiple log files.
-class LogDestroyer {
-public:
- LogDestroyer() {}
- ~LogDestroyer() { Log::destroy(); }
-};
-
-Simulator::Simulator(const boost::posix_time::time_duration& period)
-: max_simulation_period_(period),
- truncateLongRepeatsTo_(0),
- level_(0),
- foundCrons_(false)
-{
-#ifdef DEBUG_LONG_RUNNING_SUITES
- std::cout << "Simulator::Simulator max_simulation_period_ " << to_simple_string(max_simulation_period_) << endl;
-#endif
-}
-
-bool Simulator::run(Defs& theDefs, const std::string& defs_filename, std::string& errorMsg, bool do_checks) const
-{
- CmdContext cmd_context;
-
-#ifdef DEBUG_LONG_RUNNING_SUITES
- std::cout << "Simulator::run " << defs_filename << endl;
-#endif
- // ****:NOTE:******
- // ** This simulator relies on the defs checking to set event and meter usedInTrigger()
- // ** to speed up simulator. However this is done in AstResolveVisitor.
- // ** Which is called during checking:
- // ** By default checking in done when reading a defs file from disk:
- // ** However many test create Defs on the fly. These may not do_checks.
- // ** Hence we do it here, since it is simulator specific.
- if (do_checks) {
- std::string warningMsg;
- if (!theDefs.check(errorMsg,warningMsg)) {
- return false;
- }
- }
-
-
- // Allow new log to be created each time, by destroying the old log.
- LogDestroyer destroyLog;
-
- // Initialise the Log file, and destroy when done. This
- // allows new log file to be created named after the definition file
- std::string logFileName = defs_filename + ".log";
- fs::remove(logFileName);
- Log::create(logFileName);
- //cout << "defs_filename " << defs_filename << "\n";
- //cout << "***** after Log::create(logFileName)\n";
-
- // Do the following:
- // o call begin() for each suite
- // o determine calendar increment. If no time dependencies use an hour increment
- // o determine max simulation period. ie looks at size of repeats
- // o If multiple suites and some suites have no tasks, mark them as complete, these may have server limits
- // o If no tasks at all, no point in simulating
- // **** Need a better mechanism of handling long repeats, the old way of changing repeat
- // **** attributes is not acceptable.(i.e user could save in python after simulation
- // **** and there defs would be corrupted
- SimulatorVisitor simiVisitor(truncateLongRepeatsTo_ /* NOT USED */);
- theDefs.acceptVisitTraversor(simiVisitor);
- foundCrons_ = simiVisitor.foundCrons();
-
- if (!simiVisitor.foundTasks()) {
- errorMsg += "The defs file ";
- errorMsg += defs_filename;
- errorMsg += " has no tasks, can not simulate\n";
- return false;
- }
-
- // Let visitor determine calendar increment. i.e if no time dependencies we will use 1 hour increment
- // Default max_simulation_period_ is 1 year, however some operation suites run for many years
- // Analyse the repeats to determine max simulation period
- time_duration calendarIncrement = simiVisitor.calendarIncrement();
- boost::posix_time::time_duration max_simulation_period = simiVisitor.maxSimulationPeriod();
- if ( max_simulation_period > max_simulation_period_) max_simulation_period_ = max_simulation_period;
-
-#ifdef DEBUG_LONG_RUNNING_SUITES
- cout << defs_filename << " time dependency = " << simiVisitor.hasTimeDependencies()
- << " max_simulation_period_=" << to_simple_string(max_simulation_period_)
- << " calendarIncrement=" << to_simple_string(calendarIncrement)
- << endl;
-#endif
-
- CalendarUpdateParams calUpdateParams( calendarIncrement );
-
- // Start simulation ...
- boost::posix_time::time_duration duration(0,0,0,0);
- while (1) {
-
-// cout << "duration = " << to_simple_string(duration) << endl;
-
- // Resolve dependencies and submit jobs
- if (!doJobSubmission(theDefs,errorMsg)) return false;
-
- // Determine termination criteria. If all suite complete, exit,
- // Let simulation termination take autocancel into account. i.e we extend simulation even though
- // suite may have completed, to allow autocancel to take effect.
- // Hence if a suite has complete, but has autocancel we continue simulation
- // Note: should also handle case of autocancel which remove all suites
- size_t completeSuiteCnt = 0;
- int hasAutoCancel = 0;
- BOOST_FOREACH(suite_ptr s, theDefs.suiteVec()) {
- if (s->state() == NState::COMPLETE) completeSuiteCnt++;
- if (s->hasAutoCancel()) hasAutoCancel++;
- }
- if ( (theDefs.suiteVec().size() == completeSuiteCnt) && (hasAutoCancel == 0)) {
- LOG(Log::MSG, "Simulation complete in " << to_simple_string(duration) );
-
- if ( !theDefs.checkInvariants(errorMsg) ) break;
-
- // Run verification on the completed suite
- return theDefs.verification(errorMsg);
- }
-
- // crons run for ever. To terminate, we rely on test to have Verify attributes
- // The verify attributes should *only* be on the task. (i.e task auto-reques
- // hance parent is never complete, and hence no point in having verify attributes
- if (foundCrons_) {
- std::string msg;
- if (theDefs.verification(msg)) {
- return true;
- }
- }
-
- // if simulation runs to long bomb out., then Analyse the defs,
- // to determine why the simulation would not complete
- if (abortSimulation(simiVisitor, duration, errorMsg) ) {
-
- if ( !theDefs.checkInvariants(errorMsg) ) break;
-
- if ( (theDefs.suiteVec().size() == completeSuiteCnt) && (hasAutoCancel != 0)) {
- errorMsg += "All suites have completed, but autocancel has not taken effect?\n";
- }
-
- if (foundCrons_) {
- std::string msg;
- if (!theDefs.verification(msg)) {
- errorMsg += msg;
- errorMsg += "\n";
- }
- }
-
- Analyser analyser;
- analyser.run(theDefs);
- errorMsg += "Please see files .flat and .depth for analysis\n";
-
- PrintStyle::setStyle(PrintStyle::MIGRATE);
- std::stringstream ss;
- ss << theDefs;
- errorMsg += ss.str();
- return false;
- }
-
- // Increment calendar.
- theDefs.updateCalendar( calUpdateParams );
- duration += calendarIncrement;
- }
-
- return false;
-}
-
-
-bool Simulator::run(const std::string& theDefsFile,std::string& errorMsg) const
-{
-#ifdef DEBUG_LONG_RUNNING_SUITES
- cout << "Simulator::run parsing file " << theDefsFile << endl;
-#endif
-
- Defs theDefs;
- DefsStructureParser checkPtParser( &theDefs , theDefsFile );
- std::string warningMsg;
- if (!checkPtParser.doParse(errorMsg,warningMsg)) return false;
-
- return run(theDefs,theDefsFile,errorMsg, false /* don't do check, allready done */);
-}
-
-//---------------------------------------------------------------------------------------
-
-bool Simulator::abortSimulation( const SimulatorVisitor& simiVisitor,
- const boost::posix_time::time_duration& duration,
- std::string& errorMsg) const
-{
-#ifdef DEBUG_LONG_RUNNING_SUITES
- cout << " duration = " << to_simple_string(duration)
- << " max_simulation_period_=" << to_simple_string(max_simulation_period_)
- << "\n";
-#endif
- if (duration > max_simulation_period_) {
-
- errorMsg = "\nTimed out after ";
- errorMsg += to_simple_string(max_simulation_period_);
- errorMsg += " hours of simulation.\n";
-
- if (!simiVisitor.hasTimeDependencies()) errorMsg += "The definition has no time dependencies.\n";
- return true;
- }
-
- return false;
-}
-
-
-bool Simulator::doJobSubmission(Defs& theDefs, std::string& errorMsg) const
-{
- // For the simulation we ensure job submission takes less than 2 seconds
- int submitJobsInterval = 10;
-
- // Resolve dependencies and submit jobs
- JobsParam jobsParam(submitJobsInterval, false /*create jobs*/); // spawn jobs *will* be set to false
- Jobs jobs(&theDefs);
- if (!jobs.generate(jobsParam)) {
- ecf::log(Log::ERR, jobsParam.getErrorMsg());
- assert(false);
- return false;
- }
-
-//#ifdef DEBUG_LONG_RUNNING_SUITES
-// cout << "Simulator::doJobSubmission jobsParam.submitted().size() " << jobsParam.submitted().size() << " level = " << level_ << endl;
-//#endif
- level_++;
-
- // For those jobs that were submitted, Simulate client by going
- // through the task events and meters and updating them and then
- // re-checking for job submission. Finally mark task as complete
- // This is important as there may be other task dependent on this.
- BOOST_FOREACH(Submittable* t, jobsParam.submitted()) {
-
-#ifdef DEBUG_LONG_RUNNING_SUITES
- // If task repeating themselves, determine what is causing this:
- std::map<Task*,int>::iterator i = taskIntMap_.find(t);
- if (i == taskIntMap_.end()) taskIntMap_.insert( std::make_pair(t,1));
- else {
- (*i).second++;
- // Find top most node that has a repeat, check if its incrementing:
- Node* nodeWithRepeat = NULL;
- Node* theParent = t->parent();
- while (theParent) {
- if (!theParent->repeat().empty()) nodeWithRepeat = theParent;
- theParent = theParent->parent();
- }
- //cout << t->suite()->calendar().toString();
- if ( nodeWithRepeat) {
- cout << " level " << level_ << " submitted task " << t->debugNodePath() << " count = " << (*i).second
- << " HAS parent Repeating node " << nodeWithRepeat->debugNodePath()
- << " " << nodeWithRepeat->repeat().dump() << endl;
- }
- else { // cound be a cron
- cout << " level " << level_ << " submitted task " << t->debugNodePath() << " count = " << (*i).second << endl;
- }
- }
-#endif
-
- // If the task has any event used in the trigger expressions, then update event.
- BOOST_FOREACH(Event& event, t->ref_events()) {
-
- if (event.usedInTrigger()) { // event used in triger/complete expression
- event.set_value(true);
- if (!doJobSubmission(theDefs,errorMsg)) {
- level_--;
- return false;
- }
- }
- else {
- // warn about events not used in any trigger or complete expressions
-// cout << "submitted task " << t->debugNodePath() << " UN-USED event " << event.toString() << "\n";
- }
- }
-
- // if the task has any meters used in trigger expressions, then increment meters
- BOOST_FOREACH(Meter& meter, t->ref_meters()) {
-
- if (meter.usedInTrigger()) { // meter used in trigger/complete expression
- while (meter.value() < meter.max()) {
- meter.set_value(meter.value()+1);
- if (!doJobSubmission(theDefs,errorMsg)) {
- level_--;
- return false;
- }
- }
- }
- else {
- // Meters that are not used in trigger are usually used to indicate progress.
- meter.set_value(meter.max());
- }
- }
-
- // any state change should be followed with a job submission
- t->complete(); // Finally mark task as complete
-
- // crons run for ever. To terminate, we rely on test to have Verify attributes
- if (foundCrons_) {
- std::string msg;
- t->verification(msg);
- if (msg.empty()) {
- return true;
- }
- }
-
-#ifdef DEBUG_LONG_RUNNING_SUITES
- cout << t->debugNodePath() << " completes at " << t->suite()->calendar().toString() << " level " << level_ << endl;
-#endif
- if (!doJobSubmission(theDefs,errorMsg)) {
- level_--;
- return false;
- }
- }
-
- level_--;
- return true;
-}
-
-}
diff --git a/ecflow_4_0_7/CSim/src/Simulator.hpp b/ecflow_4_0_7/CSim/src/Simulator.hpp
deleted file mode 100644
index d1540be..0000000
--- a/ecflow_4_0_7/CSim/src/Simulator.hpp
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef SIMULATOR_HPP_
-#define SIMULATOR_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <boost/noncopyable.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-#include <string>
-#include <map>
-class Defs;
-class Task;
-namespace ecf { class SimulatorVisitor;}
-
-namespace ecf {
-
-/// This class is used to simulate a definition file. This is use full
-/// because:
-// a/ Save time over involving server and asking client to play definition file
-// b/ Tells you of any parser errors in the definition file
-// c/ Tells you about any deadlocks, ie if suite does not complete
-// d/ Will simulate for both real and hybrid clocks
-// e/ Simulation will by default run for a year.
-class Simulator : private boost::noncopyable {
-public:
- // default to run simulation for 1 year, or until suites complete if there are time dependencies 8784 = 366 X 24
- // Otherwise will simulate for 24 hours
- Simulator(const boost::posix_time::time_duration& period = boost::posix_time::time_duration(8784,0,0,0));
-
- /// Some definition file will run forever. **NOT USED ***, kept for reference. Need a better mechanism
- void truncateLongRepeats(int truncateTo) { truncateLongRepeatsTo_ = truncateTo ;}
-
- /// return true if all ok else returns false;
- bool run(Defs&, const std::string& defs_filename, std::string& errorMsg, bool do_checks = true) const;
- bool run(const std::string& theDefsFile, std::string& errorMsg) const;
-
-private:
-
- bool abortSimulation(const ecf::SimulatorVisitor&, const boost::posix_time::time_duration& duration,std::string& message) const;
- bool doJobSubmission(Defs&, std::string& errorMsg) const;
-
- mutable boost::posix_time::time_duration max_simulation_period_;
- mutable std::map<Task*,int> taskIntMap_;
- int truncateLongRepeatsTo_;
- mutable int level_;
- mutable bool foundCrons_;
-};
-}
-#endif /* SIMULATOR_HPP_ */
diff --git a/ecflow_4_0_7/CSim/src/SimulatorVisitor.cpp b/ecflow_4_0_7/CSim/src/SimulatorVisitor.cpp
deleted file mode 100644
index 65479d1..0000000
--- a/ecflow_4_0_7/CSim/src/SimulatorVisitor.cpp
+++ /dev/null
@@ -1,148 +0,0 @@
- //============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <iostream>
-#include "SimulatorVisitor.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "Indentor.hpp"
-
-using namespace std;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-
-//#define DEBUG_VISITOR 1
-
-namespace ecf {
-
-///////////////////////////////////////////////////////////////////////////////
-SimulatorVisitor::SimulatorVisitor(int /* truncateRepeats */)
-: /* truncateRepeats_(truncateRepeats), */
- foundTasks_(false),
- foundCrons_(false),
- hasTimeDependencies_(false),
- max_length_(0),
- ci_(hours(1))
- {}
-
-void SimulatorVisitor::visitDefs( Defs* d) {
- BOOST_FOREACH(suite_ptr s, d->suiteVec()) { s->acceptVisitTraversor(*this); }
-}
-
-void SimulatorVisitor::visitSuite( Suite* s) {
-
-#ifdef DEBUG_VISITOR
- cout << "SimulatorVisitor::visitSuite " << s->debugNodePath() << "\n";
-#endif
-
- /// begin , will cause creation of generated variables. The generated variables
- /// are use in client scripts and used to locate the sms files.
- s->begin();
-
- // IF the suite has no task (i.e could consist of just limits, set suite to complete
- // Since we rely on it for termination of tests
- // make setting NState::COMPLETE is after begin(), which will set Node into the queued state
- std::vector<Task*> theTasks;
- s->getAllTasks(theTasks);
- if (theTasks.empty()) {
- s->set_state(NState::COMPLETE);
- return;
- }
- foundTasks_ = true;
-
- // Found time dependencies use calendar increment of one minute
- if (s->hasTimeDependencies()) {
- hasTimeDependencies_ = true;
- ci_ = minutes(1);
- }
-
- // If suite has repeat day attribute( a infinite repeat), it will run forever, hence disable this for simulation purposes
- /// reset will clear the invalid flag., when doing a real job submission.
- /// *** this must be placed after begin() since begin() will reset all attributes() *****
- if (s->ref_repeat().makeInfiniteInValid()) {
- cout << "Disabling '" << s->repeat().dump() << "' attribute of " << s->debugNodePath() << ". This will allow simulation to complete earlier.\n";
- }
-
- if (!s->crons().empty()) {
- foundCrons_ = true;
- //cout << "Found crons on Suite\n";
- }
-
- visitNodeContainer(s);
-}
-
-void SimulatorVisitor::visitFamily( Family* f) { visitNodeContainer(f);}
-
-void SimulatorVisitor::visitNodeContainer(NodeContainer* nc)
-{
- if (!nc->crons().empty()) {
- foundCrons_ = true;
- cout << "Found crons on NodeContainer\n";
- }
-
-// analyse(nc);
- BOOST_FOREACH(node_ptr t, nc->nodeVec()) { t->acceptVisitTraversor(*this);}
-}
-
-void SimulatorVisitor::visitTask( Task* t )
-{
- if (!t->crons().empty()) {
- foundCrons_ = true;
- // cout << "Found crons on task\n";
- }
-// analyse(t);
-}
-
-boost::posix_time::time_duration SimulatorVisitor::maxSimulationPeriod() const
-{
- if ( hasTimeDependencies_) return hours(max_length_);
- return hours(24);
-}
-
-/// Commented out, since we need to find a better mechanism of truncating long repeats
-/// without change repeat structure/attributes. (i.e need a simulation mode, with a max length
-/// that is ignored in the server.
-//void SimulatorVisitor::analyse(Node* node)
-//{
-// if (!node->repeat().empty()) {
-// int lengthInDays = node->repeat().length();
-//
-//#ifdef DEBUG_VISITOR
-// cout << "SimulatorVisitor::analyse " << node->debugNodePath() << " " << node->repeat().dump() << " length = " << lengthInDays << "\n";
-//#endif
-//
-// // **************************************************************************
-// // ****** CAUTION: Truncate make a change to defs structure. Use with care
-// // **************************************************************************
-// if (truncateRepeats_ != 0 && lengthInDays > truncateRepeats_) {
-// node->repeat_.truncate(truncateRepeats_);
-// lengthInDays = node->repeat().length();
-// }
-//
-// lengthInDays *= 24; // convert to hours Day of month value
-//
-// if ( lengthInDays > max_length_) {
-// max_length_ = lengthInDays;
-//
-//#ifdef DEBUG_VISITOR
-// cout << "max_length_ = " << max_length_ << " hours \n";
-//#endif
-// }
-// }
-//}
-
-}
diff --git a/ecflow_4_0_7/CSim/src/SimulatorVisitor.hpp b/ecflow_4_0_7/CSim/src/SimulatorVisitor.hpp
deleted file mode 100644
index ee6ea4d..0000000
--- a/ecflow_4_0_7/CSim/src/SimulatorVisitor.hpp
+++ /dev/null
@@ -1,73 +0,0 @@
-#ifndef SIMULATORVISITOR_HPP_
-#define SIMULATORVISITOR_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "NodeTreeVisitor.hpp"
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-#include <iostream>
-#include <sstream>
-#include <set>
-#include <vector>
-class Node;
-
-namespace ecf {
-
-class SimulatorVisitor : public NodeTreeVisitor {
-public:
- SimulatorVisitor(int truncateRepeats);
-
- /// If the definition file has suites with no tasks, ie they could have server limits
- /// then for simulation purposes(i.e when all suites complete we terminate simulation)
- /// mark these as complete. Must be done *AFTER* beginAll() which sets all nodes to queued state
- bool foundTasks() const { return foundTasks_;}
-
- /// Crons run for ever. Detect them so that we can abort early
- bool foundCrons() const { return foundCrons_;}
-
- /// returns true if defs has time,date,today, date time based attributes
- bool hasTimeDependencies() const { return hasTimeDependencies_;}
-
- /// Determine the max simulation period in hours. We will default to a years 8784 = 366 X 24
- /// However by going through and looking at the repeats, we can get a better idea
- boost::posix_time::time_duration maxSimulationPeriod() const;
-
- // default calendar increment is one minute, however if we have no time dependencies,
- // then simulation can be speeded up, ie by using hour increment
- const boost::posix_time::time_duration& calendarIncrement() const { return ci_;}
-
- virtual bool traverseObjectStructureViaVisitors() const { return true;}
- virtual void visitDefs(Defs*);
- virtual void visitSuite(Suite*);
- virtual void visitFamily(Family*);
- virtual void visitNodeContainer(NodeContainer*);
- virtual void visitTask(Task*);
-
-private:
- /// Commented out since, we need to find a way of truncating lon repeats
- /// without changing repeat structure.
-// void analyse(Node* node);
-// int truncateRepeats_; // allow for simulation to complete earlier. ***NOT USED, kept for reference *****
-
- bool foundTasks_;
- bool foundCrons_;
- bool hasTimeDependencies_;
- int max_length_;
- boost::posix_time::time_duration ci_;
-};
-
-}
-#endif
diff --git a/ecflow_4_0_7/CSim/test/TestAnalysis.cpp b/ecflow_4_0_7/CSim/test/TestAnalysis.cpp
deleted file mode 100644
index 02102b7..0000000
--- a/ecflow_4_0_7/CSim/test/TestAnalysis.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <iostream>
-#include <fstream>
-#include <stdlib.h>
-
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-
-#include "Simulator.hpp"
-
-#include "File.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "TestUtil.hpp"
-#include "System.hpp"
-
-using namespace std;
-using namespace ecf;
-
-
-BOOST_AUTO_TEST_SUITE( SimulatorTestSuite )
-
-/// Use this class to test single simulation of definition file that we want to add
-/// to Test Simulator. This is a separate exe
-
-BOOST_AUTO_TEST_CASE( test_analysys )
-{
- cout << "Simulator:: ...test_analysys\n";
- //suite suite
- // family family
- // task t1
- // trigger t2 == complete
- // task t2
- // trigger t1 == complete
- // endfamily
- //endsuite
-
- // This simulation is expected to fail, since we have a deadlock/ race condition
- // It will prodice a defs.depth and defs.flat files. Make sure to remove them
- Defs theDefs;
- {
- suite_ptr suite = theDefs.add_suite("test_analysys");
- family_ptr fam = suite->add_family("family");
-
- task_ptr task1 = fam->add_task("t1");
- task1->add_trigger( "t2 == complete" );
-
- task_ptr task2 = fam->add_task("t2");
- task2->add_trigger( "t1 == complete" );
-
- // cout << theDefs << "\n";
- }
-
- Simulator simulator;
- std::string errorMsg;
- BOOST_CHECK_MESSAGE(!simulator.run(theDefs, TestUtil::testDataLocation("test_analysys.def") , errorMsg),errorMsg);
-
- // cout << theDefs << "\n";
- boost::filesystem::remove("defs.depth");
- boost::filesystem::remove("defs.flat");
-
- /// Destroy singleton's to avoid valgrind from complaining
- System::destroy();
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/CSim/test/TestAutoCancel.cpp b/ecflow_4_0_7/CSim/test/TestAutoCancel.cpp
deleted file mode 100644
index f971cc4..0000000
--- a/ecflow_4_0_7/CSim/test/TestAutoCancel.cpp
+++ /dev/null
@@ -1,271 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include "Simulator.hpp"
-#include "File.hpp"
-#include "Log.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "TestUtil.hpp"
-
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include "boost/progress.hpp"
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include <iostream>
-#include <fstream>
-#include <stdlib.h>
-
-using namespace std;
-using namespace ecf;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-
-namespace fs = boost::filesystem;
-
-/// Simulate definition files that are created on then fly. This us to validate
-/// Defs file, to check for correctness
-
-BOOST_AUTO_TEST_SUITE( SimulatorTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_autocancel_ast_node_reset )
-{
- cout << "Simulator:: ...test_autocancel_ast_node_reset\n";
-
- // ****: Since we have no time dependencies the simulator calendar increment
- // ****: is in hours. Hence autocancel at hour resolution
- Defs theDefs;
- {
- ClockAttr clockAttr(true);
- clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
- suite_ptr suite = theDefs.add_suite("s1");
- suite->addClock( clockAttr );
-
- family_ptr fam = suite->add_family("family");
- task_ptr task = fam->add_task("t");
- task->add_trigger( "/s2/family/t == complete" );
-
- task_ptr task2 = fam->add_task("t2");
- task2->add_trigger( "/s3/family/t == complete" );
- task2->add_complete( "/s2/family == complete" );
-
- task_ptr task3 = fam->add_task("t3");
- task3->add_trigger( "/s3 == complete" );
- task3->add_complete( "/s2 == complete");
- // cout << theDefs << "\n";
- }
- {
- ClockAttr clockAttr(true);
- clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
-
- suite_ptr suite = theDefs.add_suite("s2");
- suite->addClock( clockAttr );
- suite->addAutoCancel( ecf::AutoCancelAttr( ecf::TimeSlot(1,0), false));
-
- family_ptr fam = suite->add_family("family");
- fam->add_task("t");
- }
- {
- ClockAttr clockAttr(true);
- clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
- suite_ptr suite = theDefs.add_suite("s3");
- suite->addClock( clockAttr );
- suite->addAutoCancel( ecf::AutoCancelAttr( ecf::TimeSlot(1,0), false));
-
- family_ptr fam = suite->add_family("family");
- fam->add_task("t");
- }
-
- // Check number of AST nodes. The AST should be created on the fly
- std::set<Node*> theSet;
- theDefs.getAllAstNodes(theSet);
- BOOST_CHECK_MESSAGE(theSet.size() == 5,"Expected to have 5 AST nodes in trigger/complete expressions but found " << theSet.size());
-
- // Run the simulator
- Simulator simulator;
- std::string errorMsg;
- BOOST_CHECK_MESSAGE(simulator.run(theDefs,TestUtil::testDataLocation("test_autocancel_ast_node_reset.def"), errorMsg),errorMsg);
-
- // Auto cancel should delete suite s2 and s3, leaving one suite i.e s1
- BOOST_CHECK_MESSAGE(theDefs.suiteVec().size() == 1,"Expected to have 1 suites but found " << theDefs.suiteVec().size());
-
- // The references to nodes in suites s2, s3 should have been cleared in suite s1
- {
- std::set<Node*> theSet;
- theDefs.getAllAstNodes(theSet);
- BOOST_CHECK_MESSAGE(theSet.empty(),"Expected to have 0 AST nodes in trigger/complete expressions but found " << theSet.size());
- }
-}
-
-
-BOOST_AUTO_TEST_CASE( test_autocancel_suite )
-{
- cout << "Simulator:: ...test_autocancel_suite\n";
-
- // ****: Since we have no time dependencies the simulator calendar increment
- // ****: is in hours. Hence autocancel at hour resolution
- Defs theDefs;
- {
- ClockAttr clockAttr(true);
- clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
- suite_ptr suite = theDefs.add_suite("test_autocancel_10_hours_relative");
- suite->addClock( clockAttr );
- suite->addAutoCancel( ecf::AutoCancelAttr( ecf::TimeSlot(10,0), true));
- family_ptr fam = suite->add_family("family");
- fam->add_task("t");
- }
- {
- ClockAttr clockAttr(true);
- clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
- suite_ptr suite = theDefs.add_suite("test_autocancel_1_hours_real");
- suite->addClock( clockAttr );
- suite->addAutoCancel( ecf::AutoCancelAttr( ecf::TimeSlot(1,0), false));
- family_ptr fam = suite->add_family("family");
- fam->add_task("t");
- }
- {
- ClockAttr clockAttr(true);
- clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
- suite_ptr suite = theDefs.add_suite("test_autocancel_1_day_relative");
- suite->addClock( clockAttr );
- suite->addAutoCancel( ecf::AutoCancelAttr(1) );
- family_ptr fam = suite->add_family("family");
- fam->add_task("t");
- // cout << theDefs << "\n";
- }
-
- Simulator simulator;
- std::string errorMsg;
- BOOST_CHECK_MESSAGE(simulator.run(theDefs, TestUtil::testDataLocation("test_autocancel_suite.def"), errorMsg),errorMsg);
-
- // make sure autocancel deletes the suite.
- BOOST_CHECK_MESSAGE(theDefs.suiteVec().size() == 0,"Expected to have 0 suites but found " << theDefs.suiteVec().size());
-}
-
-BOOST_AUTO_TEST_CASE( test_autocancel_family_and_task )
-{
- cout << "Simulator:: ...test_autocancel_family_and_task\n";
-
- // ****: Since we have no time dependencies the simulator calendar increment
- // ****: is in hours. Hence autocancel at hour resolution
- Defs theDefs;
- {
- ClockAttr clockAttr(true);
- clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
- suite_ptr suite = theDefs.add_suite("test_autocancel_9_10_hours_relative");
- suite->addClock( clockAttr );
-
- family_ptr fam = suite->add_family("family");
- fam->addAutoCancel( ecf::AutoCancelAttr( ecf::TimeSlot(10,0), true));
-
- task_ptr task = fam->add_task("t");
- task->addAutoCancel( ecf::AutoCancelAttr( ecf::TimeSlot(9,0), true));
-
- // cout << theDefs << "\n";
- }
- {
- ClockAttr clockAttr(true);
- clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
- suite_ptr suite = theDefs.add_suite("test_autocancel_1_2_hours_real");
- suite->addClock( clockAttr );
-
- family_ptr fam = suite->add_family("family");
- fam->addAutoCancel( ecf::AutoCancelAttr( ecf::TimeSlot(2,0), false));
-
- task_ptr task = fam->add_task("t");
- task->addAutoCancel( ecf::AutoCancelAttr( ecf::TimeSlot(1,0), false));
- }
- {
- ClockAttr clockAttr(true);
- clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
- suite_ptr suite = theDefs.add_suite("test_autocancel_1_2_day_relative");
- suite->addClock( clockAttr );
-
- family_ptr fam = suite->add_family("family");
- fam->addAutoCancel( ecf::AutoCancelAttr(2) );
-
- task_ptr task = fam->add_task("t");
- task->addAutoCancel( ecf::AutoCancelAttr(1) );
- // cout << theDefs << "\n";
- }
-
- Simulator simulator;
- std::string errorMsg;
- BOOST_CHECK_MESSAGE(simulator.run(theDefs,TestUtil::testDataLocation("test_autocancel_family_and_task.def"), errorMsg),errorMsg);
-
- // make sure autocancel deletes the families.
- std::vector<Family*> famVec;
- theDefs.getAllFamilies(famVec);
- BOOST_CHECK_MESSAGE(famVec.size() == 0,"Expected to have 0 families but found " << famVec.size());
-}
-
-BOOST_AUTO_TEST_CASE( test_autocancel_task )
-{
- cout << "Simulator:: ...test_autocancel_task\n";
-
- // ****: Since we have no time dependencies the simulator calendar increment
- // ****: is in hours. Hence autocancel at hour resolution
- Defs theDefs;
- {
- ClockAttr clockAttr(true);
- clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
- suite_ptr suite = theDefs.add_suite("test_autocancel_10_hours_relative");
- suite->addClock( clockAttr );
-
- family_ptr fam = suite->add_family("family");
- task_ptr task = fam->add_task("t");
- task->addAutoCancel( ecf::AutoCancelAttr( ecf::TimeSlot(10,0), true));
- }
- {
- ClockAttr clockAttr(true);
- clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
- suite_ptr suite = theDefs.add_suite("test_autocancel_1_hours_real");
- suite->addClock( clockAttr );
- family_ptr fam = suite->add_family("family");
- task_ptr task = fam->add_task("t");
- task->addAutoCancel( ecf::AutoCancelAttr( ecf::TimeSlot(1,0), false));
- }
- {
- ClockAttr clockAttr(true);
- clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
- suite_ptr suite = theDefs.add_suite("test_autocancel_1_day_relative");
- suite->addClock( clockAttr );
-
- family_ptr fam = suite->add_family("family");
- task_ptr task = fam->add_task("t");
- task->addAutoCancel( ecf::AutoCancelAttr(1) );
- // cout << theDefs << "\n";
- }
-
- Simulator simulator;
- std::string errorMsg;
- BOOST_CHECK_MESSAGE(simulator.run(theDefs,TestUtil::testDataLocation("test_autocancel_task.def"), errorMsg),errorMsg);
-
- // make sure autocancel deletes the tasks and leaves families intact.
- std::vector<task_ptr> task_vec;
- theDefs.get_all_tasks(task_vec);
-
- std::vector<Family*> famVec;
- theDefs.getAllFamilies(famVec);
-
- BOOST_CHECK_MESSAGE(famVec.size() == 3,"Expected to have 3 families but found " << famVec.size());
- BOOST_CHECK_MESSAGE(task_vec.size() == 0,"Expected to have 0 tasks but found " << task_vec.size());
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/CSim/test/TestMeter.cpp b/ecflow_4_0_7/CSim/test/TestMeter.cpp
deleted file mode 100644
index 05fe771..0000000
--- a/ecflow_4_0_7/CSim/test/TestMeter.cpp
+++ /dev/null
@@ -1,108 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include "Simulator.hpp"
-#include "File.hpp"
-#include "Log.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "TestUtil.hpp"
-#include "System.hpp"
-
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include "boost/progress.hpp"
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include <iostream>
-#include <fstream>
-#include <stdlib.h>
-
-using namespace std;
-using namespace ecf;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-
-namespace fs = boost::filesystem;
-
-/// Simulate definition files that are created on then fly. This us to validate
-/// Defs file, to check for correctness
-
-BOOST_AUTO_TEST_SUITE( SimulatorTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_meter )
-{
- cout << "Simulator:: ...test_meter\n";
-
- //suite suite
- // clock real <todays date>
- // family family
- // task fc
- // meter hour 0 240
- // task half
- // trigger fc:hour >= 120
- // endfamily
- //endsuite
-
- // Initialise clock with todays date then create a time attribute + minutes
- // such that the task should only run once, in the next minute
- boost::posix_time::ptime theLocalTime = Calendar::second_clock_time();
-
- Defs theDefs;
- {
- ClockAttr clockAttr(theLocalTime );
- suite_ptr suite = theDefs.add_suite("test_meter");
- suite->addClock( clockAttr );
- suite->addVerify( VerifyAttr(NState::COMPLETE,1) );
-
- family_ptr fam = suite->add_family("family");
- fam->addVerify( VerifyAttr(NState::COMPLETE,1) );
-
- task_ptr fc = fam->add_task("fc");
- fc->addMeter( Meter("hour",0,240,240) );
- fc->addVerify( VerifyAttr(NState::COMPLETE,1) );
-
- task_ptr half = fam->add_task("half");
- half->add_trigger( "fc:hour >= 120" );
- half->addVerify( VerifyAttr(NState::COMPLETE,1) );
-// cout << theDefs << "\n";
- }
-
- Simulator simulator;
- std::string errorMsg;
- BOOST_CHECK_MESSAGE(simulator.run(theDefs,TestUtil::testDataLocation("test_meter.def"), errorMsg),errorMsg);
-
- // The simulator will set all the meter values, so final value must be the max value.
- bool found_task = false;
- std::vector<Task*> theServerTasks;
- theDefs.getAllTasks(theServerTasks);
- BOOST_FOREACH(Task* t, theServerTasks) {
- if (t->name() == "fc") {
- found_task = true;
- const std::vector<Meter>& meters = t->meters();
- BOOST_REQUIRE_MESSAGE(meters.size() == 1,"Expected one meter but found " << meters.size());
- BOOST_CHECK_MESSAGE(meters[0].value() == meters[0].max(),"Expected meter to have value of " << meters[0].max() << " but found " << meters[0].value() );
- }
- }
- BOOST_REQUIRE_MESSAGE(found_task ,"Failed to find task fc ");
-
- /// Destroy System singleton to avoid valgrind from complaining
- System::destroy();
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/CSim/test/TestRepeat.cpp b/ecflow_4_0_7/CSim/test/TestRepeat.cpp
deleted file mode 100644
index a6163d0..0000000
--- a/ecflow_4_0_7/CSim/test/TestRepeat.cpp
+++ /dev/null
@@ -1,412 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include "Simulator.hpp"
-#include "File.hpp"
-#include "Log.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "TestUtil.hpp"
-
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include "boost/progress.hpp"
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include <iostream>
-#include <fstream>
-#include <stdlib.h>
-
-using namespace std;
-using namespace ecf;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-
-namespace fs = boost::filesystem;
-
-/// Simulate definition files that are created on then fly. This us to validate
-/// Defs file, to check for correctness
-
-BOOST_AUTO_TEST_SUITE( SimulatorTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_repeat_integer )
-{
- cout << "Simulator:: ...test_repeat_integer\n";
-
- //suite suite
- // repeat integer VAR 0 1 1 # run at 0, 1 2 times
- // edit SLEEPTIME 1
- // edit ECF_INCLUDE $ECF_HOME/includes
- // family family
- // repeat integer VAR 0 1 1 # run at 0, 1 2 times
- // task t<n>
- // ....
- // endfamily
- //endsuite
-
- // Each task/job should be run *4* times, according to the repeats
- // Mimics nested loops
- Defs theDefs;
- {
- suite_ptr suite = theDefs.add_suite("suite");
- suite->addRepeat( RepeatInteger("VAR",0,1,1)); // repeat contents 2 times
- suite->addVerify( VerifyAttr(NState::COMPLETE,2) );
- family_ptr fam = suite->add_family( "family" );
- fam->addRepeat( RepeatInteger("VAR",0,1,1)); // repeat contents 2 times
- fam->addVerify( VerifyAttr(NState::COMPLETE,4) ); // verify family repeats 2 times
- int taskSize = 2;
- for(int i=0; i < taskSize; i++) {
- task_ptr t = fam->add_task( "t" + boost::lexical_cast<std::string>(i) );
- t->addVerify( VerifyAttr(NState::COMPLETE,4) ); // Each task should run 4 times
- }
- // cout << theDefs << "\n";
- }
-
- Simulator simulator;
- std::string errorMsg;
- BOOST_CHECK_MESSAGE(simulator.run(theDefs,TestUtil::testDataLocation("test_repeat_integer.def"),errorMsg),errorMsg);
-// cout << theDefs << "\n";
-}
-
-BOOST_AUTO_TEST_CASE( test_repeat_integer_relative )
-{
- cout << "Simulator:: ...test_repeat_integer_relative\n";
-
- //suite suite
- // repeat integer VAR 0 1 1 # run at 0, 1 2 times
- // edit SLEEPTIME 1
- // edit ECF_INCLUDE $ECF_HOME/includes
- // family family
- // repeat integer VAR 0 1 1 # run at 0, 1 2 times
- // task t1
- // time +0;02
- // endfamily
- //endsuite
-
- // Each task/job should be run *4* times relative to Node times, according to the repeats
- // Mimics nested loops
- Defs theDefs;
- {
- ClockAttr clockAttr(true/*false means use hybrid clock*/);
- clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
- suite_ptr suite = theDefs.add_suite("test_repeat_integer_relative");
- suite->addClock( clockAttr );
- suite->addRepeat( RepeatInteger("VAR",0,1,1)); // repeat contents 2 times
- suite->addVerify( VerifyAttr(NState::COMPLETE,2) );
-
- family_ptr fam = suite->add_family( "family" );
- fam->addRepeat( RepeatInteger("VAR",0,1,1)); // repeat contents 2 times
- fam->addVerify( VerifyAttr(NState::COMPLETE,4) );
-
- task_ptr t = fam->add_task("t1");
- t->addTime( ecf::TimeAttr( TimeSlot(0,2), true /*relative*/ ) );
- t->addVerify( VerifyAttr(NState::COMPLETE,4) ); // Each task should run 4 times
-
-// cout << theDefs << "\n";
- }
-
- Simulator simulator;
- std::string errorMsg;
- BOOST_CHECK_MESSAGE(simulator.run(theDefs,TestUtil::testDataLocation("test_repeat_integer_relative.def"),errorMsg),errorMsg);
-// cout << theDefs << "\n";
-}
-
-
-BOOST_AUTO_TEST_CASE( test_repeat_date )
-{
- cout << "Simulator:: ...test_repeat_date\n";
- //suite suite
- // clock real <fixed date + time>
- // family family
- // repeat date YMD 20091001 20091015 1 # yyyymmdd
- // task t
- // time 10:00
- // endfamily
- //endsuite
-
- // Each task should be run 15 times, ie every day at 10.00 am from 1st Oct->15 October 15 times
- Defs theDefs;
- {
- ClockAttr clockAttr;
- clockAttr.date(1,10,2009);
- suite_ptr suite = theDefs.add_suite("test_repeat_date");
- suite->addVerify( VerifyAttr(NState::COMPLETE,1) );
- suite->addClock( clockAttr );
-
- family_ptr fam = suite->add_family( "family" );
- fam->addRepeat( RepeatDate("YMD",20091001,20091015,1)); // repeat contents 15 times
- fam->addVerify( VerifyAttr(NState::COMPLETE,15) );
-
- task_ptr task = fam->add_task("t");
- task->addTime( ecf::TimeAttr( TimeSlot(10,0) ) );
- task->addVerify( VerifyAttr(NState::COMPLETE,15) ); // task should complete 15 times
-
-// cout << theDefs << "\n";
- }
-
- Simulator simulator;
- std::string errorMsg;
- BOOST_CHECK_MESSAGE(simulator.run(theDefs, TestUtil::testDataLocation("test_repeat_date.def"), errorMsg),errorMsg);
-}
-
-
-BOOST_AUTO_TEST_CASE( test_repeat_date_for_loop )
-{
- cout << "Simulator:: ...test_repeat_date_for_loop\n";
-
- //suite suite
- // clock real <todays date>
- // repeat date YMD 20091001 20091005 1 # yyyymmdd
- // family family
- // repeat date YMD 20091001 20091005 1 # yyyymmdd
- // task t
- // time 10:00
- // endfamily
- //endsuite
-
- // Each task should be run 5 * 5= 25 times, ie every day from from 1st Oct -> 5 Oct 5*5 times
- Defs theDefs;
- {
- suite_ptr suite = theDefs.add_suite("test_repeat_date_for_loop");
- suite->addRepeat( RepeatDate("YMD",20091001,20091005,1)); // repeat contents 5 times
- suite->addVerify( VerifyAttr(NState::COMPLETE,5) );
-
- // start at specific time other wise time dependent checks will not verify
- ClockAttr clockAttr;
- clockAttr.date(1,10,2009);
- suite->addClock( clockAttr );
-
- family_ptr fam = suite->add_family( "family" );
- fam->addRepeat( RepeatDate("YMD",20091001,20091005,1)); // repeat contents 5 times
- fam->addVerify( VerifyAttr(NState::COMPLETE,25) );
-
- task_ptr task = fam->add_task("t");
- task->addTime( ecf::TimeAttr( TimeSlot(10,0) ) );
- task->addVerify( VerifyAttr(NState::COMPLETE,25) ); // task should complete 25 times
-
-// cout << theDefs << "\n";
- }
-
- Simulator simulator;
- std::string errorMsg;
- BOOST_CHECK_MESSAGE(simulator.run(theDefs, TestUtil::testDataLocation("test_repeat_date_for_loop.def"), errorMsg),errorMsg);
-}
-
-
-BOOST_AUTO_TEST_CASE( test_repeat_date_for_loop2 )
-{
- cout << "Simulator:: ...test_repeat_date_for_loop2\n";
-
- //suite suite
- // clock real <todays date>
- // repeat date YMD 20091001 20091005 1 # yyyymmdd
- // family family
- // repeat date YMD 20091001 20091005 1 # yyyymmdd
- // task t
- // time 10:00
- // time 11:00
- // endfamily
- //endsuite
-
- // Each task should be run 5 * 5 * 2 = 50 times, ie every day from from 1st Oct -> 5 Oct 5*5 times * 2 time slots
- Defs theDefs;
- {
- // start at specific time other wise time dependent checks will not verify
- suite_ptr suite = theDefs.add_suite("test_repeat_date_for_loop2");
- suite->addRepeat( RepeatDate("YMD",20091001,20091005,1)); // repeat contents 5 times
- suite->addVerify( VerifyAttr(NState::COMPLETE,5) );
-
- ClockAttr clockAttr;
- clockAttr.date(1,10,2009);
- suite->addClock( clockAttr );
-
- family_ptr fam = suite->add_family( "family" );
- fam->addRepeat( RepeatDate("YMD",20091001,20091005,1)); // repeat contents 5 times
- fam->addVerify( VerifyAttr(NState::COMPLETE,25) );
-
- task_ptr task = fam->add_task("t");
- task->addTime( ecf::TimeAttr( TimeSlot(10,0) ) );
- task->addTime( ecf::TimeAttr( TimeSlot(11,0) ) );
- task->addVerify( VerifyAttr(NState::COMPLETE,50) ); // task should complete 50 times
-
- // cout << theDefs << "\n";
- }
-
- Simulator simulator;
- std::string errorMsg;
- BOOST_CHECK_MESSAGE(simulator.run(theDefs, TestUtil::testDataLocation("test_repeat_date_for_loop2.def"), errorMsg),errorMsg);
-}
-
-
-BOOST_AUTO_TEST_CASE( test_repeat_with_cron )
-{
- cout << "Simulator:: ...test_repeat_with_cron\n";
-// suite s
-// clock real <today date>
-// family f
-// repeat date YMD 20091001 20091004 1 # yyyymmdd
-// family plot
-// complete plot/finish == complete
-//
-// task finish
-// trigger 1 == 0 # stops task from running
-// complete checkdata::done or checkdata == complete
-//
-// task checkdata
-// event done
-// cron <today date> + 2 minutes # cron that run forever
-// endfamily
-// endfamily
-// endsuite
-
- Defs theDefs;
- {
- boost::posix_time::ptime theLocalTime = Calendar::second_clock_time();
- boost::posix_time::ptime time_plus_2_minute = theLocalTime + minutes(2);
- ClockAttr clockAttr(theLocalTime, false/* real clock*/);
-
- suite_ptr suite = theDefs.add_suite("test_repeat_with_cron");
- suite->addClock( clockAttr );
-
- family_ptr f = suite->add_family( "f" );
- f->addRepeat( RepeatDate("YMD",20091001,20091004,1)); // repeat contents 4 times
- f->addVerify( VerifyAttr(NState::COMPLETE,4) );
-
- family_ptr family_plot = f->add_family( "plot" );
- family_plot->add_complete( "plot/finish == complete");
- family_plot->addVerify( VerifyAttr(NState::COMPLETE,4) );
-
-
- task_ptr task_finish = family_plot->add_task("finish");
- task_finish->add_trigger( "1 == 0");
- task_finish->add_complete( "checkdata:done or checkdata == complete" );
- task_finish->addVerify( VerifyAttr(NState::COMPLETE,8) );
-
- task_ptr task_checkdata = family_plot->add_task("checkdata");
- task_checkdata->addEvent( Event(1,"done"));
-
- CronAttr cronAttr;
- cronAttr.addTimeSeries( ecf::TimeSlot(time_plus_2_minute.time_of_day()) );
- task_checkdata->addCron( cronAttr );
- task_checkdata->addVerify( VerifyAttr(NState::COMPLETE,8) );
-
-// cout << theDefs << "\n";
- }
-
- Simulator simulator;
- std::string errorMsg;
- BOOST_REQUIRE_MESSAGE(simulator.run(theDefs, TestUtil::testDataLocation("test_repeat_with_cron.def"), errorMsg),errorMsg);
-}
-
-BOOST_AUTO_TEST_CASE( test_repeat_enumerated )
-{
- cout << "Simulator:: ...test_repeat_enumerated\n";
- //suite suite
- // family family
- // repeat enumerated ENUM "hello" "there" "bill" # run 3 times
- // task t1
- // endfamily
- //endsuite
-
- // Each task/job should be run 3 according to the repeats
- Defs theDefs;
- {
- suite_ptr suite = theDefs.add_suite("test_repeat_enumerated");
-
- std::vector<std::string> theEnums;
- theEnums.push_back("hello"); // index 0
- theEnums.push_back("there"); // index 1
- theEnums.push_back("bill"); // index 2
-
- family_ptr fam = suite->add_family( "family" );
- fam->addRepeat( RepeatEnumerated("ENUM",theEnums)); // repeat contents 3 times
- fam->addVerify( VerifyAttr(NState::COMPLETE,3) );
-
- task_ptr task = fam->add_task("t1");
- task->addVerify( VerifyAttr(NState::COMPLETE,3) );
-
- // cout << theDefs << "\n";
- }
-
- Simulator simulator;
- std::string errorMsg;
- BOOST_CHECK_MESSAGE(simulator.run(theDefs,TestUtil::testDataLocation("test_repeat_enumerated.def"), errorMsg),errorMsg);
- // cout << theDefs << "\n";
-
-
- std::vector<Task*> theServerTasks;
- theDefs.getAllTasks(theServerTasks);
- BOOST_FOREACH(Task* t, theServerTasks) {
- // verify repeat has the last value
- Family* family = dynamic_cast<Family*>(t->parent());
- const Repeat& repeat = family->findRepeat("ENUM");
- BOOST_REQUIRE_MESSAGE(!repeat.empty(),"Expected to find repeat on family " << family->absNodePath() );
- BOOST_REQUIRE_MESSAGE(!repeat.valid(),"Expected invalid repeat");
- BOOST_REQUIRE_MESSAGE(repeat.value() == 3,"Expected to find repeat with value 3 but found " << repeat.value() );
- BOOST_REQUIRE_MESSAGE(repeat.last_valid_value() == 2,"Expected to find repeat with last valid value 2 but found " << repeat.last_valid_value() );
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_repeat_string )
-{
- cout << "Simulator:: ...test_repeat_string\n";
- //suite suite
- // family family
- // repeat string STRING "hello" "there" # run 2 times
- // task t1
- // endfamily
- //endsuite
-
- // Each task/job should be run 3 according to the repeats
- Defs theDefs;
- {
- suite_ptr suite = theDefs.add_suite("test_repeat_string");
-
- std::vector<std::string> theStrings;
- theStrings.push_back("hello"); // index 0
- theStrings.push_back("there"); // index 1
-
- family_ptr fam = suite->add_family( "family" );
- fam->addRepeat( RepeatString("STRING",theStrings)); // repeat contents 2 times
- fam->addVerify( VerifyAttr(NState::COMPLETE,2) );
-
- task_ptr task = fam->add_task("t1");
- task->addVerify( VerifyAttr(NState::COMPLETE,2) );
-
- // cout << theDefs << "\n";
- }
-
- Simulator simulator;
- std::string errorMsg;
- BOOST_CHECK_MESSAGE(simulator.run(theDefs, TestUtil::testDataLocation("test_repeat_string.def"), errorMsg),errorMsg);
- // cout << theDefs << "\n";
-
- std::vector<Task*> theServerTasks;
- theDefs.getAllTasks(theServerTasks);
- BOOST_FOREACH(Task* t, theServerTasks) {
- // verify repeat has the last value
- Family* family = dynamic_cast<Family*>(t->parent());
- const Repeat& repeat = family->findRepeat("STRING");
- BOOST_REQUIRE_MESSAGE(!repeat.empty(),"Expected to find repeat on family " << family->absNodePath() );
- BOOST_REQUIRE_MESSAGE(!repeat.valid(),"Expected invalid repeat");
- BOOST_REQUIRE_MESSAGE(repeat.value() == 2,"Expected to find repeat with value 2 but found " << repeat.value() );
- BOOST_REQUIRE_MESSAGE(repeat.last_valid_value() == 1,"Expected to find repeat with last valid value 1 but found " << repeat.last_valid_value() );
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/CSim/test/TestSimulator.cpp b/ecflow_4_0_7/CSim/test/TestSimulator.cpp
deleted file mode 100644
index 1e04edb..0000000
--- a/ecflow_4_0_7/CSim/test/TestSimulator.cpp
+++ /dev/null
@@ -1,135 +0,0 @@
-#define BOOST_TEST_MODULE TestSimulator
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #11 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <string>
-#include <iostream>
-#include <fstream>
-
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include "boost/progress.hpp"
-
-#include "System.hpp"
-#include "Simulator.hpp"
-#include "File.hpp"
-#include "LogVerification.hpp"
-
-namespace fs = boost::filesystem;
-
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( SimulatorTestSuite )
-
-void simulate(const std::string& directory, bool pass)
-{
- fs::path full_path( fs::initial_path<fs::path>() );
- full_path = fs::system_complete( fs::path( directory ) );
-
- BOOST_CHECK(fs::exists( full_path ));
- BOOST_CHECK(fs::is_directory( full_path ));
-
- //std::cout << "\nIn directory: " << full_path.directory_string() << "\n\n";
- fs::directory_iterator end_iter;
- for ( fs::directory_iterator dir_itr( full_path ); dir_itr != end_iter; ++dir_itr ) {
-
- try {
- fs::path relPath(directory + "/" + dir_itr->path().filename().string());
-
- // recurse down directories
- if ( is_directory(dir_itr->status()) ) {
- simulate(relPath.string(),pass);
- continue;
- }
-
- // Only simulate file with .def file extension, i.e. ignore log files.
-// cout << "path = " << relPath << "\n";
- if (File::getExt(relPath.filename().string()) != "def" && File::getExt(relPath.filename().string()) != "got") continue;
-
-// std::cout << "...............Simulating file " << relPath.string() << "\n";
- Simulator simulator;
- std::string errorMsg;
- bool simPass = simulator.run(relPath.string(), errorMsg);
- if (pass) {
- // Test expected to pass
- BOOST_CHECK_MESSAGE(simPass,"Simulator expected to pass for " << relPath << "\n" << errorMsg);
-
- // Compare/ create log files
- if (simPass) {
- std::string logFileName = relPath.string() + ".log";
- std::string goldenFileName = relPath.string() + ".glog";
- BOOST_CHECK_MESSAGE(fs::exists(logFileName),"Log file " << logFileName << " should have been created");
- if (fs::exists(goldenFileName) ) {
-
- ofstream my_file(goldenFileName.c_str());
- if (!my_file.good()) {
- // read able file
-// cout << "file " << goldenFileName << " is readable \n";
- std::string errorMessage;
- BOOST_CHECK_MESSAGE(LogVerification::compareNodeStates(logFileName,goldenFileName,errorMessage),
- "Log file comparison failed for " << relPath.string() << "\n" << errorMessage);
- }
- else {
- // writable file, overwrite
-// cout << "Golden file " << goldenFileName << " is writeable, overwriting\n";
- fs::remove(goldenFileName);
- fs::copy_file(logFileName,goldenFileName);
- }
- }
- else {
- // Create golden log file so that it can be compared next time
- // fs::copy_file(logFileName,goldenFileName);
- }
- }
- }
- else {
- // test expected to fail
- BOOST_CHECK_MESSAGE(!simPass,"Simulator expected to fail for " << relPath << "\n" << errorMsg);
- }
- }
- catch ( const std::exception & ex )
- {
- std::cout << dir_itr->path().filename() << " " << ex.what() << std::endl;
- }
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_simulate_good_defs )
-{
- cout << "Simulator:: ...test_simulate_good_defs\n";
-
- std::string path = File::test_data("CSim/test/data/good_defs","CSim");
-
- // All the defs in this directory are expected to pass
- simulate(path, true);
-}
-
-BOOST_AUTO_TEST_CASE( test_simulate_bad_defs )
-{
- cout << "Simulator:: ...test_simulate_bad_defs\n";
-
- std::string path = File::test_data("CSim/test/data/bad_defs","CSim");
-
- // All the defs in this directory are expected to fail
- simulate(path, false);
-
- /// Destroy System singleton to avoid valgrind from complaining
- System::destroy();
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/CSim/test/TestSingleSimulator.cpp b/ecflow_4_0_7/CSim/test/TestSingleSimulator.cpp
deleted file mode 100644
index e225217..0000000
--- a/ecflow_4_0_7/CSim/test/TestSingleSimulator.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
-#define BOOST_TEST_MODULE TestSingleSimulator
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/// Use this class to test single simulation of definition file that we want to add
-/// to Test Simulator. This is a separate exe
-//============================================================================
-#include "Simulator.hpp"
-
-#include "File.hpp"
-#include "Log.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "TestUtil.hpp"
-
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include "boost/progress.hpp"
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include <iostream>
-#include <fstream>
-#include <stdlib.h>
-
-using namespace std;
-using namespace ecf;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( SimulatorTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_repeat_date_for_loop2 )
-{
- cout << "Simulator:: ...test_repeat_date_for_loop2\n";
-
- //suite suite
- // clock real <todays date>
- // repeat date YMD 20091001 20091005 1 # yyyymmdd
- // family family
- // repeat date YMD 20091001 20091005 1 # yyyymmdd
- // task t
- // time 10:00
- // time 11:00
- // endfamily
- //endsuite
-
- // Each task should be run 5 * 5 * 2 = 50 times, ie every day from from 1st Oct -> 5 Oct 5*5 times * 2 time slots
- Defs theDefs;
- {
- // start at specific time other wise time dependent checks will not verify
- suite_ptr suite = theDefs.add_suite("test_repeat_date_for_loop2");
- suite->addRepeat( RepeatDate("YMD",20091001,20091005,1)); // repeat contents 5 times
- suite->addVerify( VerifyAttr(NState::COMPLETE,5) );
-
- ClockAttr clockAttr;
- clockAttr.date(1,10,2009);
- suite->addClock( clockAttr );
-
- family_ptr fam = suite->add_family( "family" );
- fam->addRepeat( RepeatDate("YMD",20091001,20091005,1)); // repeat contents 5 times
- fam->addVerify( VerifyAttr(NState::COMPLETE,25) );
-
- task_ptr task = fam->add_task("t");
- task->addTime( ecf::TimeAttr( TimeSlot(10,0) ) );
- task->addTime( ecf::TimeAttr( TimeSlot(11,0) ) );
- task->addVerify( VerifyAttr(NState::COMPLETE,50) ); // task should complete 50 times
-
- // cout << theDefs << "\n";
- }
-
- Simulator simulator;
- std::string errorMsg;
- BOOST_CHECK_MESSAGE(simulator.run(theDefs, TestUtil::testDataLocation("test_repeat_date_for_loop2.def"), errorMsg),errorMsg);
-}
-
-
-//BOOST_AUTO_TEST_CASE( test_single_from_file )
-//{
-// cout << "Simulator:: ...test_single_from_file\n";
-//
-////std::string path = File::test_data("CSim/test/data/good_defs/operations/loop.def","CSim");
-// std::string path = File::test_data("CSim/test/data/good_defs/ECFLOW-130/radarlvl2.def","CSim");
-//
-// Simulator simulator;
-// std::string errorMsg;
-// bool passed = simulator.run(path, errorMsg);
-//
-// BOOST_REQUIRE_MESSAGE(passed, path << " failed simulation \n" << errorMsg);
-//}
-
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/CSim/test/TestTime.cpp b/ecflow_4_0_7/CSim/test/TestTime.cpp
deleted file mode 100644
index 62bcef6..0000000
--- a/ecflow_4_0_7/CSim/test/TestTime.cpp
+++ /dev/null
@@ -1,380 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include "Simulator.hpp"
-#include "File.hpp"
-#include "Log.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "TestUtil.hpp"
-
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include "boost/progress.hpp"
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include <iostream>
-#include <fstream>
-#include <stdlib.h>
-
-using namespace std;
-using namespace ecf;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-
-namespace fs = boost::filesystem;
-
-/// Simulate definition files that are created on then fly. This allows us to create
-/// tests with todays date/time this speeds up the testr, we can also validate
-/// Defs file, to check for correctness
-
-BOOST_AUTO_TEST_SUITE( SimulatorTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_time )
-{
- cout << "Simulator:: ...test_time\n";
-
- //# Note: we have to use relative paths, since these tests are relocatable
- //suite suite
- // clock real <todays date>
- // family family
- // task t1
- // time <start>
- // endfamily
- //endsuite
-
- // Initialise clock with todays date then create a time attribute + minutes
- // such that the task should only run once, in the next minute
- boost::posix_time::ptime theLocalTime = Calendar::second_clock_time();
- boost::posix_time::ptime time_plus_minute = theLocalTime + minutes(1);
-
- Defs theDefs;
- {
- suite_ptr suite = theDefs.add_suite("test_time");
- ClockAttr clockAttr(theLocalTime,false/*false means use real clock*/);
- suite->addClock( clockAttr );
-
- family_ptr fam = suite->add_family( "family" );
- task_ptr task = fam->add_task("t");
- task->addTime( ecf::TimeAttr( TimeSlot(time_plus_minute.time_of_day()) ) );
- task->addVerify( VerifyAttr(NState::COMPLETE,1) ); // expect task to complete 1 time
-
- // cout << theDefs << "\n";
- }
-
- Simulator simulator;
- std::string errorMsg;
- BOOST_CHECK_MESSAGE(simulator.run(theDefs, TestUtil::testDataLocation("test_time.def"), errorMsg),errorMsg);
-}
-
-BOOST_AUTO_TEST_CASE( test_time_series )
-{
- cout << "Simulator:: ...test_time_series\n";
-
- //suite suite
- // clock real <sunday>
- // family family
- // task t1
- // time 00:30 23:59 04:00 # should run 6 times 00:30 4:30 8:30 12:30 16:30 20:30
- // endfamily
- //endsuite
-
- // Initialise real clock on a Moday, such that task should _only_ run
- // on Monday since we are using a hybrid clock
- Defs theDefs;
- {
- ClockAttr clockAttr(true/*false means use hybrid clock*/);
- clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
- suite_ptr suite = theDefs.add_suite("test_time_series");
- suite->addClock( clockAttr );
-
- family_ptr fam = suite->add_family( "family" );
- task_ptr task = fam->add_task("t");
- TimeSeries timeSeries(TimeSlot(00,30), TimeSlot(23,59), TimeSlot(4,0), false/* relative */);
-
- task->addTime( TimeAttr( timeSeries ));
- task->addVerify( VerifyAttr(NState::COMPLETE,6) ); // expect task to complete 6 times
-
- // cout << theDefs << "\n";
- }
-
- Simulator simulator;
- std::string errorMsg;
- BOOST_CHECK_MESSAGE(simulator.run(theDefs, TestUtil::testDataLocation("test_time_series.def"), errorMsg),errorMsg);
-}
-
-BOOST_AUTO_TEST_CASE( test_time_and_date )
-{
- cout << "Simulator:: ...test_time_and_date\n";
-
- //# Note: we have to use relative paths, since these tests are relocatable
- //suite suite
- // clock real <todays date>
- // family family
- // task t1
- // date <today date>
- // time <start>
- // endfamily
- //endsuite
-
-
- Defs theDefs;
- {
- // Initialise clock with todays date then create a time attribute + minutes
- // such that the task should only run once, in the next minute
- boost::posix_time::ptime theLocalTime = Calendar::second_clock_time();
- boost::gregorian::date todaysDate = theLocalTime.date();
- boost::posix_time::ptime time_plus_minute = theLocalTime + minutes(1);
-
- ClockAttr clockAttr(theLocalTime,false/*false means use real clock*/);
- suite_ptr suite = theDefs.add_suite("test_time_and_date");
- suite->addClock( clockAttr );
-
- family_ptr fam = suite->add_family( "family" );
- task_ptr task = fam->add_task("t");
- task->addDate( DateAttr(todaysDate.day(),todaysDate.month(),todaysDate.year()) );
- task->addTime( ecf::TimeAttr( TimeSlot(time_plus_minute.time_of_day()) ) );
- task->addVerify( VerifyAttr(NState::COMPLETE,1) ); // expect task to complete 1 time
-
- // cout << theDefs << "\n";
- }
-
- Simulator simulator;
- std::string errorMsg;
- BOOST_CHECK_MESSAGE(simulator.run(theDefs, TestUtil::testDataLocation("test_time_and_date.def"), errorMsg),errorMsg);
-}
-
-BOOST_AUTO_TEST_CASE( test_time_and_tomorrows_date )
-{
- cout << "Simulator:: ...test_time_and_tomorrows_date\n";
-
- //# Note: we have to use relative paths, since these tests are relocatable
- //suite suite
- // clock real <tomorrows date>
- // family family
- // task t1
- // date <tomorrows date>
- // time <start>
- // endfamily
- //endsuite
-
-
- Defs theDefs;
- {
- // Initialise clock with todays date then create a time attribute + minutes
- // such that the task should only run once, in the next minute
- boost::posix_time::ptime theLocalTime = Calendar::second_clock_time();
- boost::gregorian::date tomorrows_date = theLocalTime.date();
- tomorrows_date += days(1);
- boost::posix_time::ptime time_plus_minute = theLocalTime + minutes(1);
-
- ClockAttr clockAttr(theLocalTime,false/*false means use real clock*/);
- suite_ptr suite = theDefs.add_suite("test_time_and_tomorrows_date");
- suite->addClock( clockAttr );
-
- family_ptr fam = suite->add_family( "family" );
- task_ptr task = fam->add_task("t");
- task->addDate( DateAttr(tomorrows_date.day(),tomorrows_date.month(),tomorrows_date.year()) );
- task->addTime( ecf::TimeAttr( TimeSlot(time_plus_minute.time_of_day()) ) );
- task->addVerify( VerifyAttr(NState::COMPLETE,1) ); // expect task to complete 1 time
-
- // cout << theDefs << "\n";
- }
-
- Simulator simulator;
- std::string errorMsg;
- BOOST_CHECK_MESSAGE(simulator.run(theDefs, TestUtil::testDataLocation("test_time_and_tomorrows_date.def"), errorMsg),errorMsg);
-}
-
-
-BOOST_AUTO_TEST_CASE( test_multiple_times_and_dates )
-{
- cout << "Simulator:: ...test_multiple_times_and_dates\n";
-
- //# Note: we have to use relative paths, since these tests are relocatable
- //suite suite
- // clock real <todays date>
- // family family
- // repeat integer 0 1 1 # repeat twice
- // task t1
- // date <today date>
- // date <tomrrows date>
- // time <start>
- // time <start>
- // endfamily
- //endsuite
- Defs theDefs;
- {
- // Initialise clock with todays date then create a time attribute + minutes
- // Note: we don't use:
- // boost::posix_time::ptime theLocalTime = Calendar::second_clock_time();
- // because if run at late we can end up with illegal for the hour, ie. > 24
-
- boost::gregorian::date todaysDate(2009,2,10);
- ptime theLocalTime(todaysDate, hours(3));
- boost::gregorian::date tomarrows_date = todaysDate + date_duration(1);
- boost::posix_time::time_duration td_plus_minute = theLocalTime.time_of_day() + minutes(1);
- boost::posix_time::time_duration td_plus_hour = theLocalTime.time_of_day() + hours(1);
-
- ClockAttr clockAttr(theLocalTime,false/*false means use real clock*/);
- suite_ptr suite = theDefs.add_suite("test_multiple_times_and_dates");
- suite->addClock( clockAttr );
-
-
- family_ptr fam = suite->add_family( "family" );
- //fam->addRepeat( RepeatInteger("rep",0,1,1) );
- task_ptr task = fam->add_task("t");
- task->addDate( DateAttr(todaysDate.day(),todaysDate.month(),todaysDate.year()) );
- task->addDate( DateAttr(tomarrows_date.day(),tomarrows_date.month(),tomarrows_date.year()) );
- task->addTime( TimeAttr( TimeSlot(td_plus_minute) ));
- task->addTime( TimeAttr( TimeSlot(td_plus_hour) ));
- task->addVerify( VerifyAttr(NState::COMPLETE,4) ); // expect task to complete 4 time
-
- // cout << theDefs << "\n";
- }
-
- Simulator simulator;
- std::string errorMsg;
- BOOST_CHECK_MESSAGE(simulator.run(theDefs,TestUtil::testDataLocation("test_multiple_times_and_dates.def"), errorMsg),errorMsg);
-}
-
-BOOST_AUTO_TEST_CASE( test_multiple_times_and_dates_hybrid )
-{
- cout << "Simulator:: ...test_multiple_times_and_dates_hybrid\n";
-
- //# Note: we have to use relative paths, since these tests are relocatable
- //suite suite
- // clock hybrid <todays date>
- // family family
- // task t1
- // date <today date>
- // date <tomrrows date>
- // time <start>
- // time <start>
- // endfamily
- //endsuite
- Defs theDefs;
- {
- // Initialise clock with todays date then create a time attribute + minutes
- // such that the task should only run once, in the next minute
- boost::posix_time::ptime theLocalTime = boost::posix_time::ptime(date(2012,2,22),time_duration(10,20,0));
- boost::gregorian::date todaysDate = theLocalTime.date();
- boost::gregorian::date tomorrows_date = todaysDate + date_duration(1);
- boost::posix_time::time_duration td_plus_minute = theLocalTime.time_of_day() + minutes(1);
- boost::posix_time::time_duration td_plus_10_minute = theLocalTime.time_of_day() + minutes(10);
-
- suite_ptr suite = theDefs.add_suite("test_multiple_times_and_dates_hybrid");
- suite->addClock( ClockAttr(theLocalTime,true) ); // true means use hybrid clock
-
- family_ptr fam = suite->add_family("family");
- task_ptr task = fam->add_task("t");
- task->addDate( DateAttr(todaysDate.day(),todaysDate.month(),todaysDate.year()) );
- task->addDate( DateAttr(tomorrows_date.day(),tomorrows_date.month(),tomorrows_date.year()) );
- task->addTime( TimeAttr( TimeSlot(td_plus_minute) ));
- task->addTime( TimeAttr( TimeSlot(td_plus_10_minute) ));
- task->addVerify( VerifyAttr(NState::COMPLETE,2) ); // expect task to complete 2 time
- //cout << theDefs << "\n";
- }
-
- Simulator simulator;
- std::string errorMsg;
- BOOST_CHECK_MESSAGE(simulator.run(theDefs, TestUtil::testDataLocation("test_multiple_times_and_dates_hybrid.def"), errorMsg),errorMsg);
-}
-
-BOOST_AUTO_TEST_CASE( test_multiple_times_and_days )
-{
- cout << "Simulator:: ...test_multiple_times_and_days\n";
-
- //suite suite
- // clock real <sunday>
- // family family
- // rep integer 0 1 1 # repeat twice
- // task t1
- // day monday
- // day tuesday
- // time <start>
- // time <start>
- // endfamily
- //endsuite
-
- // Initialise real clock on a sunday, such that task should run on Monday & tuesday twice
- Defs theDefs;
- {
- ClockAttr clockAttr(false/*false means use real clock*/);
- clockAttr.date(11,10,2009); // 11 October 2009 was a sunday
- suite_ptr suite = theDefs.add_suite("test_multiple_times_and_days");
- suite->addClock( clockAttr );
-
- family_ptr fam = suite->add_family("family");
- //fam->addRepeat( RepeatInteger("rep",0,1,1) );
- task_ptr task = fam->add_task("t");
- task->addDay( DayAttr(DayAttr::MONDAY) );
- task->addDay( DayAttr(DayAttr::TUESDAY) );
- task->addTime( TimeAttr( TimeSlot(10,0) ));
- task->addTime( TimeAttr( TimeSlot(20,0) ));
- task->addVerify( VerifyAttr(NState::COMPLETE,4) ); // expect task to complete 4 time
-
- // cout << theDefs << "\n";
- }
-
- Simulator simulator;
- std::string errorMsg;
- BOOST_CHECK_MESSAGE(simulator.run(theDefs, TestUtil::testDataLocation("test_multiple_times_and_days.def"), errorMsg),errorMsg);
-}
-
-BOOST_AUTO_TEST_CASE( test_multiple_times_and_days_hybrid )
-{
- cout << "Simulator:: ...test_multiple_times_and_days_hybrid\n";
-
- //suite suite
- // clock real <sunday>
- // family family
- // task t1
- // day monday
- // day tuesday
- // time <start>
- // time <start>
- // endfamily
- //endsuite
-
- // Initialise real clock on a Monday, such that task should _only_ run
- // on Monday since we are using a hybrid clock
- Defs theDefs;
- {
- ClockAttr clockAttr(true/*false means use hybrid clock*/);
- clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
- suite_ptr suite = theDefs.add_suite("test_multiple_times_and_days_hybrid");
- suite->addClock( clockAttr );
-
- family_ptr fam = suite->add_family("family");
- task_ptr task = fam->add_task("t");
- task->addDay( DayAttr(DayAttr::MONDAY) );
- task->addDay( DayAttr(DayAttr::TUESDAY) );
- task->addTime( TimeAttr( TimeSlot(10,0) ));
- task->addTime( TimeAttr( TimeSlot(11,0) ));
- task->addTime( TimeAttr( TimeSlot(20,0) ));
- task->addVerify( VerifyAttr(NState::COMPLETE,3) ); // expect task to complete 3 times
-
- // cout << theDefs << "\n";
- }
-
- Simulator simulator;
- std::string errorMsg;
- BOOST_CHECK_MESSAGE(simulator.run(theDefs, TestUtil::testDataLocation("test_multiple_times_and_days_hybrid.def"), errorMsg),errorMsg);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/CSim/test/TestToday.cpp b/ecflow_4_0_7/CSim/test/TestToday.cpp
deleted file mode 100644
index 186f62a..0000000
--- a/ecflow_4_0_7/CSim/test/TestToday.cpp
+++ /dev/null
@@ -1,158 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include "Simulator.hpp"
-#include "File.hpp"
-#include "Log.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "TestUtil.hpp"
-
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include "boost/progress.hpp"
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include <iostream>
-#include <fstream>
-#include <stdlib.h>
-
-using namespace std;
-using namespace ecf;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-
-namespace fs = boost::filesystem;
-
-/// Simulate definition files that are created on then fly. This allows us to create
-/// tests with todays date/time this speeds up the testr, we can also validate
-/// Defs file, to check for correctness
-
-BOOST_AUTO_TEST_SUITE( SimulatorTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_today )
-{
- cout << "Simulator:: ...test_today\n";
-
- //suite suite
- // clock real <fixed date>
- // family family
- // task t1
- // today <start> # +1 minute
- // today <start> # +2 minute
- // endfamily
- //endsuite
- Defs theDefs;
- {
- // Initialise clock then create a today attribute + minutes
- // such that the task should only run once, in the next minute
- ptime theLocalTime = boost::posix_time::ptime(date(2010,6,21),time_duration(1,2,0));
- boost::posix_time::ptime time_plus_minute = theLocalTime + minutes(1);
- boost::posix_time::ptime time_plus_10_minute = theLocalTime + minutes(10);
-
- suite_ptr suite = theDefs.add_suite( "test_today" );
- ClockAttr clockAttr(theLocalTime,false/*false means use real clock*/);
- suite->addClock( clockAttr );
-
- family_ptr fam = suite->add_family( "family" );
- task_ptr task = fam->add_task( "t" );
- task->addToday( ecf::TodayAttr( TimeSlot(time_plus_minute.time_of_day()) ) );
- task->addToday( ecf::TodayAttr( TimeSlot(time_plus_10_minute.time_of_day()) ) );
- task->addVerify( VerifyAttr(NState::COMPLETE,2) ); // expect task to complete 2 time
- // cout << theDefs << "\n";
- }
-
- Simulator simulator;
- std::string errorMsg;
- bool result = simulator.run(theDefs, TestUtil::testDataLocation("test_today.def"), errorMsg);
-
- BOOST_CHECK_MESSAGE(result,errorMsg);
-}
-
-BOOST_AUTO_TEST_CASE( test_today_time_series )
-{
- cout << "Simulator:: ...test_today_time_series\n";
-
- //suite suite
- // clock real <monday>
- // family family
- // task t1
- // today 00:30 18:59 04:00 # should run 5 times 00:30 4:30 8:30 12:30 16:30
- // endfamily
- //endsuite
-
- Defs theDefs;
- {
- suite_ptr suite = theDefs.add_suite( "test_today_time_series" );
- ClockAttr clockAttr(true/*false means use hybrid clock*/);
- clockAttr.date(12,10,2009); // 12 October 2009 was a Monday
- suite->addClock( clockAttr );
-
- family_ptr fam = suite->add_family( "family" );
- task_ptr task = fam->add_task( "t" );
- TimeSeries timeSeries(TimeSlot(00,30), TimeSlot(18,59), TimeSlot(4,0), false/* relative */);
-
- task->addToday( TodayAttr( timeSeries ));
- task->addVerify( VerifyAttr(NState::COMPLETE,5) );
- // cout << theDefs << "\n";
- }
-
- Simulator simulator;
- std::string errorMsg;
- BOOST_CHECK_MESSAGE(simulator.run(theDefs, TestUtil::testDataLocation("test_today_time_series.def") , errorMsg),errorMsg);
-}
-
-BOOST_AUTO_TEST_CASE( test_today_time_and_date )
-{
- cout << "Simulator:: ...test_today_time_and_date\n";
-
- //suite suite
- // clock real <todays date>
- // family family
- // task t1
- // date <today date>
- // time <start>
- // today <start>
- // endfamily
- //endsuite
- Defs theDefs;
- {
- // Task will only run if all time dependencies are satisfied
- boost::posix_time::ptime theLocalTime = Calendar::second_clock_time();
- boost::gregorian::date todaysDate = theLocalTime.date();
- boost::posix_time::ptime time_plus_minute = theLocalTime + minutes(1);
-
- suite_ptr suite = theDefs.add_suite( "test_today_time_and_date" );
- ClockAttr clockAttr(theLocalTime,false/*false means use real clock*/);
- suite->addClock( clockAttr );
-
- family_ptr fam = suite->add_family( "family" );
- task_ptr task = fam->add_task( "t" );
- task->addDate( DateAttr(todaysDate.day(),todaysDate.month(),todaysDate.year()) );
- task->addTime( ecf::TimeAttr( TimeSlot(time_plus_minute.time_of_day()) ) );
- task->addToday( ecf::TodayAttr( TimeSlot(time_plus_minute.time_of_day()) ) );
-
- task->addVerify( VerifyAttr(NState::COMPLETE,1) );
- // cout << theDefs << "\n";
- }
-
- Simulator simulator;
- std::string errorMsg;
- BOOST_CHECK_MESSAGE(simulator.run(theDefs,TestUtil::testDataLocation("test_today_time_and_date.def"),errorMsg),errorMsg);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/CSim/test/TestUtil.cpp b/ecflow_4_0_7/CSim/test/TestUtil.cpp
deleted file mode 100644
index 66f746a..0000000
--- a/ecflow_4_0_7/CSim/test/TestUtil.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include "TestUtil.hpp"
-#include "File.hpp"
-
-using namespace std;
-using namespace ecf;
-
-std::string TestUtil::testDataLocation( const std::string& defsFile)
-{
- std::string testData = File::test_data("CSim/test/data","CSim");
-
- testData += "/";
- testData += defsFile;
- return testData;
-}
diff --git a/ecflow_4_0_7/CSim/test/TestUtil.hpp b/ecflow_4_0_7/CSim/test/TestUtil.hpp
deleted file mode 100644
index 92d222e..0000000
--- a/ecflow_4_0_7/CSim/test/TestUtil.hpp
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef TESTUTIL_HPP_
-#define TESTUTIL_HPP_
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <boost/noncopyable.hpp>
-#include <string>
-#include <map>
-#include "Defs.hpp"
-
-// This class provides a test harness for running defs file in a client server environment
-// To avoid Address in use errors, we can have client/server use a different port number
-// This is more important when doing instrumentation in HP-UX, as that can take a long time.
-//
-class TestUtil : private boost::noncopyable {
-public:
-
-
- /// Returns the location of the defs file, such thats it in the test data area
- static std::string testDataLocation( const std::string& defsFile);
-
-};
-#endif /* TESTUTIL_HPP_ */
diff --git a/ecflow_4_0_7/Client/CMakeLists.txt b/ecflow_4_0_7/Client/CMakeLists.txt
deleted file mode 100644
index 288cc3e..0000000
--- a/ecflow_4_0_7/Client/CMakeLists.txt
+++ /dev/null
@@ -1,125 +0,0 @@
- # =======================================================
- # LIB
- # to list all sources to build use:
- # cd $WK/Base
- # find src -name \*.cpp --print
- # =======================================================
-
- # Excludes src/ClientMain.cpp
-list( APPEND srcs
- src/Rtt.cpp
- src/ClientEnvironment.cpp
- src/ClientInvoker.cpp
- src/Rtt.cpp
- src/ClientOptions.cpp
- src/UrlCmd.cpp
-)
-ecbuild_add_library( TARGET libclient
- NOINSTALL
- TYPE STATIC
- SOURCES ${srcs}
- LIBS base libparser node nodeattr core
- pthread
- INCLUDES src
- ../ACore/src
- ../ANattr/src
- ../ANode/src
- ../AParser/src
- ../Base/src
- ../Base/src/cts
- ../Base/src/stc
- )
-
-# ========================================================================
-# EXE ecflow_client
-ecbuild_add_executable( TARGET ecflow_client
- SOURCES src/ClientMain.cpp
- LIBS libclient
- INCLUDES ${Boost_INCLUDE_DIRS}
- )
-
-# Override default behaviour that add RPATHS during install
-# The only thing that seem to work is set INSTALL_RPATH to ""
-# Using SKIP_BUILD_RPATH,BUILD_WITH_INSTALL_RPATH,INSTALL_RPATH_USE_LINK_PATH
-# had no effect
-#
-SET_TARGET_PROPERTIES(ecflow_client PROPERTIES
- INSTALL_RPATH ""
- )
-
-# use, i.e. don't skip the full RPATH for the build tree
-#SET(CMAKE_SKIP_BUILD_RPATH FALSE)
-
-# when building, don't use the install RPATH already
-# (but later on when installing)
-#SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
-
-# the RPATH to be used when installing
-#SET(CMAKE_INSTALL_RPATH "")
-
-# don't add the automatically determined parts of the RPATH
-# which point to directories outside the build tree to the install RPATH
-#SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)
-
-
-# ================================================================================
-# TEST
-# Use following to populate list:
-# cd $WK/Client
-# find test -name \*.cpp | sort
-list( APPEND test_srcs
- test/SCPort.cpp
- test/TestCheckPtDefsCmd.cpp
- test/TestClientEnvironment.cpp
- test/TestClientInterface.cpp
- test/TestClientInvoker.cpp
- test/TestClientTimeout.cpp
- test/TestGroupCmd.cpp
- test/TestJobGenOnly.cpp
- test/TestLifeCycle.cpp
- test/TestLoadDefsCmd.cpp
- test/TestPlugCmd.cpp
- test/TestRtt.cpp
- test/TestServer.cpp
- test/TestServerAndLifeCycle.cpp
- test/TestSignalSIGTERM.cpp
- test/TestUrlCmd.cpp
- test/TestWhiteListFile.cpp
-)
-ecbuild_add_test( TARGET s_client
- BOOST
- SOURCES ${test_srcs}
- LIBS libclient
- INCLUDES ../ANode/test
- ../Base/test
- TEST_DEPENDS u_base
- )
-
-#
-# Simple stand alone test
-#
-ecbuild_add_test( TARGET perf_test_large_defs
- BOOST
- SOURCES test/TestSinglePerf.cpp test/SCPort.cpp
- LIBS libclient
- INCLUDES ../ANode/test
- ../Base/test
- TEST_DEPENDS u_base
- )
-
-#
-# test migration
-#
-ecbuild_add_test( TARGET test_migration
- BOOST
- SOURCES test/TestMigration.cpp test/SCPort.cpp
- LIBS libclient
- INCLUDES ../ANode/test
- ../Base/test
- TEST_DEPENDS u_base
- )
-
-# ===================================================================
-# install
-# ===================================================================
-install (TARGETS ecflow_client DESTINATION bin)
diff --git a/ecflow_4_0_7/Client/Jamfile.jam b/ecflow_4_0_7/Client/Jamfile.jam
deleted file mode 100644
index a20261d..0000000
--- a/ecflow_4_0_7/Client/Jamfile.jam
+++ /dev/null
@@ -1,137 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-#
-# Client
-#
-project theClient ;
-
-use-project theCore : ../ACore ;
-use-project theNodeAttr : ../ANattr ;
-use-project theNode : ../ANode ;
-use-project theParser : ../AParser ;
-use-project theBase : ../Base ;
-
-#
-# This should be in the site-config.jam file as a project wide requirement
-# however if this is done, it will not link since, lpthread appears twice
-# on the link line
-#
-lib pthread ;
-
-#
-# define DEBUG_CLIENT for additional debug
-#
-# Having a library avoid compile objects shared between client and test having
-# differing compilation properties
-#
-# Exclude ClientMain.cpp from the library.
-#
-# The <include> means we will automatically add this directory to the include path
-# of any other target that uses this lib
-#
-lib libclient : [ glob src/*.cpp : src/*Main.cpp ]
- : <include>../ACore/src
- <include>../ANattr/src
- <include>../ANode/src
- <include>../Base/src
- <include>../AParser/src
- <include>../Client/src
- <variant>debug:<define>DEBUG
- <link>static
- <use>/theCore//core
- <use>/theNode//node
- <use>/theParser//libparser
- <use>/theBase//base
- <use>/site-config//boost_system
- <use>/site-config//boost_serialization
- <use>/site-config//boost_filesystem
- <use>/site-config//boost_program_options
- <use>/site-config//boost_datetime
- :
- : <include>../Client/src
- ;
-
-#
-# client. This Just pulls in src/ClientMain.cpp
-#
-exe ecflow_client : [ glob src/*Main.cpp ]
- /theCore//core
- /theNodeAttr//nodeattr
- /theNode//node
- /theParser//libparser
- /theBase//base
- libclient
- /site-config//boost_system
- /site-config//boost_serialization
- /site-config//boost_filesystem
- /site-config//boost_program_options
- /site-config//boost_datetime
- pthread
- : <variant>debug:<define>DEBUG
- ;
-
-#
-# Tests for client. All test source code, by pulling in libclient we avoid
-# linking with ClientMain.cpp
-#
-exe s_client : [ glob test/*.cpp : test/TestSinglePerf.cpp test/TestMigration.cpp ]
- pthread
- /theCore//core
- /theNodeAttr//nodeattr
- /theNode//node
- /theParser//libparser
- /theBase//base
- libclient
- /site-config//boost_system
- /site-config//boost_serialization
- /site-config//boost_filesystem
- /site-config//boost_program_options
- /site-config//boost_datetime
- /site-config//boost_test
- : <include>../ANode/test
- <include>../Base/test
- <variant>debug:<define>DEBUG
- ;
-
-exe perf_test_large_defs : [ glob test/TestSinglePerf.cpp ] [ glob test/SCPort.cpp ]
- /theCore//core
- /theNodeAttr//nodeattr
- /theNode//node
- /theParser//libparser
- /theBase//base
- libclient
- pthread
- /site-config//boost_system
- /site-config//boost_serialization
- /site-config//boost_filesystem
- /site-config//boost_program_options
- /site-config//boost_datetime
- /site-config//boost_test
- : <include>../ANode/test
- <include>../Base/test
- <variant>debug:<define>DEBUG
- ;
-
-exe test_migration : [ glob test/TestMigration.cpp ] [ glob test/SCPort.cpp ]
- /theCore//core
- /theNodeAttr//nodeattr
- /theNode//node
- /theParser//libparser
- /theBase//base
- libclient
- pthread
- /site-config//boost_system
- /site-config//boost_serialization
- /site-config//boost_filesystem
- /site-config//boost_program_options
- /site-config//boost_datetime
- /site-config//boost_test
- : <include>../ANode/test
- <include>../Base/test
- <variant>debug:<define>DEBUG
- ;
\ No newline at end of file
diff --git a/ecflow_4_0_7/Client/doc/config_file.doc b/ecflow_4_0_7/Client/doc/config_file.doc
deleted file mode 100644
index fbbfd35..0000000
--- a/ecflow_4_0_7/Client/doc/config_file.doc
+++ /dev/null
@@ -1,63 +0,0 @@
-// This file gives an example of how to load
-// a config file using boost program options.
-// This was originally use in test, without having to
-// specify enviroment variables.
-
-
-#include <boost/program_options.hpp>
-namespace po = boost::program_options;
-
-void ClientEnvironment::read_config_file()
-{
-#ifdef DEBUG_ENVIRONMENT
- std::cout << "ClientEnvironment::read_config_file() no_ecf_ = " << no_ecf_ << "\n";
-#endif
-
- try {
- std::string host,port,constructor_supplied_host_file;
- // use config to discover, the hosts file, otherwise use the host file provided in the constructor
- if (!host_file_.empty()) {
- constructor_supplied_host_file = host_file_;
- }
-
- // read the environment from the config file
- po::options_description config_file_options("Configuration");
- config_file_options.add_options()
- ("ECF_NODE", po::value<std::string>(&host)->default_value(Str::LOCALHOST()), "The host name")
- ("ECF_NAME", po::value<std::string>(&task_path_) , "Full name of task")
- ("ECF_PASS", po::value<std::string>(&jobs_password_)->default_value(""), "The jobs password")
- ("ECF_TRYNO", po::value<int>(&task_try_num_), "The task try number")
- ("ECF_HOSTFILE", po::value<std::string>(&host_file_), "File that lists alternate hosts")
- ("ECF_TIMEOUT", po::value<long>(&timeout_)->default_value(MIN_TIMEOUT), "Max time in seconds for client to deliver message")
- ("ECF_DENIED", po::value<bool>(&denied_)->default_value(false) , "If set ECF denies access, client will exit with failure")
- ("ECF_PORT", po::value<std::string>(&port)->default_value(Str::DEFAULT_PORT_NUMBER()), "The TCP/IP port to call")
- ("NO_ECF", po::value<bool>(&no_ecf_)->default_value("false"), " if defined then abort cmd")
- ;
-
- std::string path = File::test_data("environment.cfg","Client");
-
-
- ifstream ifs(path.c_str());
- if (ifs) {
- po::variables_map vm;
- po::store(parse_config_file(ifs, config_file_options), vm);
- po::notify( vm);
- }
-
- /// Overwrite the host file read from the config file, since we need to use
- /// host file supplied via the constructor
- if (!constructor_supplied_host_file.empty()) {
- host_file_ = constructor_supplied_host_file;
- }
-
- // Add the ECF_NODE host into list of hosts
- if (!host.empty()) {
- if (port.empty()) host_vec_.push_back(std::make_pair(host,Str::DEFAULT_PORT_NUMBER()));
- else host_vec_.push_back(std::make_pair(host,port));
- }
- }
- catch(std::exception& e)
- {
- cerr << "ClientEnvironment::read_config_file() " << e.what() << "\n";
- }
-}
\ No newline at end of file
diff --git a/ecflow_4_0_7/Client/doc/environment.cfg b/ecflow_4_0_7/Client/doc/environment.cfg
deleted file mode 100644
index 6f49158..0000000
--- a/ecflow_4_0_7/Client/doc/environment.cfg
+++ /dev/null
@@ -1,68 +0,0 @@
-#
-# This file acts as a stand in for the client enviroment
-# In a real client we will obtain the environment via Enviroment variables
-# how for testing puposes we will define here.
-#
-
-#
-# The name of machine on which the ECF server is running. It was *this* server that
-# sent the job.
-#
-ECF_NODE = localhost
-
-
-#
-# The path name to the node in the server.
-# **********************************************************************************
-# For Test purposes if this does not correspond to the loaded Defs tree it will fail.
-# ***********************************************************************************
-#
-ECF_NAME = /aSuit/aFam/aTask
-
-#
-# When a server submits a task, it generates a unique password. This is
-# used by the client to authenticate any messaged sent back to the server
-# For the moment we will just choose a name like process.
-# **********************************************************************
-# For *test* purposes this should be same as Submittable::DUMMY_JOBS_PASSWORD
-# If this variable is NOT set we ignore the request.
-# Shorted from DummyJobsPassword to _DJP_ to save on bytes
-# ***********************************************************************
-#
-ECF_PASS = _DJP_
-
-#
-# The number of times we should submitted a job, if it is aborted.
-#
-ECF_TRYNO = 3
-
-#
-# This file lists all the alternate host names, that should be tried if client can not
-# communicate with ECF_NODE host. If the files does exist or can not be opened we continue
-# connection to ECF_NODE. The port number must be the same as the job supplied port number
-#
-ECF_HOSTFILE = ecf_hostsfile
-
-#
-# This variable controls for how long child commands continue trying to connect to Server before failing.
-# Maximum time in seconds for client to deliver message to server/servers. This is
-# typically 24 hours in a real environment. It is this long to allow operators to
-# recover from any crashes.
-#
-ECF_TIMEOUT = 20
-
-#
-# If set to 1 and ECF denies access, the client will exit with failure
-#
-ECF_DENIED = 0
-
-#
-# The TCP/IP port on the server to call
-#
-ECF_PORT = 3141
-
-#
-# If this value is set we abort immediately with a valid return
-#
-NO_ECF = 0
-
diff --git a/ecflow_4_0_7/Client/src/ClientEnvironment.cpp b/ecflow_4_0_7/Client/src/ClientEnvironment.cpp
deleted file mode 100644
index 8884522..0000000
--- a/ecflow_4_0_7/Client/src/ClientEnvironment.cpp
+++ /dev/null
@@ -1,391 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name : ClientEnvironment
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <iostream>
-#include <fstream>
-#include <iterator>
-#include <stdlib.h> // for getenv()
-
-#include "boost/foreach.hpp"
-
-#include "ClientEnvironment.hpp"
-#include "ClientToServerCmd.hpp"
-#include "File.hpp"
-#include "Str.hpp"
-#include "Ecf.hpp"
-#include "boost_archive.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-
-// Provide upper and lower bounds for timeouts
-/// The timeout is used control for how long we continue to iterate over the hosts
-/// attempting to connect to the servers.
-#ifdef DEBUG
-#define MAX_TIMEOUT 120 // Max time in seconds for client to deliver message
-#define MIN_TIMEOUT 5 // Some reasonable value
-#else
-#define MAX_TIMEOUT 24*3600 // We don't try forever, only 24 hours
-#define MIN_TIMEOUT 10*60 // Some reasonable value
-#endif
-
-//#define DEBUG_ENVIRONMENT 1
-
-template<class T>
-ostream& operator<<(ostream& os, const vector<T>& v)
-{
- copy(v.begin(), v.end(), ostream_iterator<T>(cout, "\n"));
- return os;
-}
-
-
-ClientEnvironment::ClientEnvironment()
-: AbstractClientEnv(),
- task_try_num_(1),timeout_(MAX_TIMEOUT),connect_timeout_(0),
- denied_(false),no_ecf_(false), debug_(false),under_test_(false),
- host_file_read_(false),
- host_vec_index_(0),
- allow_new_client_old_server_(0)
-{
- init();
-}
-
-// test constructor
-ClientEnvironment::ClientEnvironment(const std::string& hostFile, const std::string& host, const std::string& port)
-: AbstractClientEnv(),
- task_try_num_(1),timeout_(MAX_TIMEOUT),connect_timeout_(0),
- denied_(false),no_ecf_(false), debug_(false),under_test_(false),
- host_file_read_(false),
- host_vec_index_(0),
- allow_new_client_old_server_(0)
-{
- init();
-
- /// The host file passed in takes *precedence* over ECF_HOSTFILE environment variable read in init()
- host_file_ = hostFile;
-
- /// Override config, and environment.
- if (!host.empty()) {
- host_vec_.clear();
- host_vec_.push_back(std::make_pair(host,port));
- }
-}
-
-void ClientEnvironment::init()
-{
- read_environment_variables();
-#ifdef DEBUG_ENVIRONMENT
- std::cout << toString() << std::endl;
-#endif
-
- // If no host specified default to local host and default port number
- if (host_vec_.empty())
- host_vec_.push_back(std::make_pair(Str::LOCALHOST(),Str::DEFAULT_PORT_NUMBER()));
-
- // Program option are read in last, and will override any previous setting
- // However program option are delayed until later. See notes in header
- if (debug_) std::cout << toString() << "\n";
-}
-
-bool ClientEnvironment::get_next_host(std::string& errorMsg)
-{
- if (debug_) cout << "ClientEnvironment::get_next_host() host_file_read_ = " << host_file_read_ << " host_file_ = " << host_file_ << "\n";
- if (!host_file_read_ && !host_file_.empty()) {
-
- if (!parseHostsFile(errorMsg)) {
- return false;
- }
- host_file_read_ = true;
- // SKIP OVER THE FIRST HOST, hence both paths need to increment host_vec_index_
- }
-
- host_vec_index_++;
- if (host_vec_index_ >= static_cast<int>(host_vec_.size())) {
- host_vec_index_ = 0;
- }
-
- return true;
-}
-
-// AbstractClientEnv functions: ============================================================================
-const std::string& ClientEnvironment::host() const
-{
-#ifdef DEBUG_ENVIRONMENT
-// cout << "ClientEnvironment::host() host_vec_index_ = " << host_vec_index_
-// << " host_vec_[host_vec_index_] = " << host_vec_[host_vec_index_] << "\n";
-#endif
- assert( host_vec_index_ >=0 && host_vec_index_ < static_cast<int>(host_vec_.size()));
- return host_vec_[host_vec_index_].first;
-}
-
-const std::string& ClientEnvironment::port() const
-{
- assert( host_vec_index_ >=0 && host_vec_index_ < static_cast<int>(host_vec_.size()));
- return host_vec_[host_vec_index_].second;
-}
-
-void ClientEnvironment::set_host_port(const std::string& the_host, const std::string& the_port)
-{
- if (the_host.empty()) throw std::runtime_error("ClientEnvironment::set_host_port: Empty host specified ?");
- if (the_port.empty()) throw std::runtime_error("ClientEnvironment::set_host_port: Empty port specified ?");
- try { boost::lexical_cast<int>(the_port); }
- catch ( boost::bad_lexical_cast& e) {
- throw std::runtime_error("ClientEnvironment::set_host_port: Invalid port number " + the_port);
- }
-
- // Override default
- host_vec_.clear();
-
- // make sure there only one host:port in host_vec_
- host_vec_.push_back(std::make_pair(the_host,the_port));
-
- // Make sure we don't look in hosts file.
- // When there is only one host:port in host_vec_, calling get_next_host() will always return host_vec_[0]
- host_file_read_ = true;
-
- // Update 'int allow_new_client_old_server_' *IF* ECF_ALLOW_NEW_CLIENT_OLD_SERVER set, and matches input host/port
- update_allow_new_client_old_server(the_host,the_port);
-}
-
-bool ClientEnvironment::checkTaskPathAndPassword(std::string& errorMsg) const
-{
- if ( task_path_.empty() ) {
- errorMsg = "No task path specified for ECF_NAME \n";
- return false;
- }
- if ( jobs_password_.empty() ) {
- errorMsg = "No jobs password specified for ECF_PASS \n";
- return false;
- }
- return true;
-}
-
-std::string ClientEnvironment::toString() const
-{
- std::stringstream ss;
- if (host_vec_.empty()) ss << "\n ECF_NODE =\n ";
- else {
- ss << "\n ECF_NODE : host_vec_index_ = " << host_vec_index_ << " host_vec_.size() = " << host_vec_.size() << "\n";
- std::pair<std::string,std::string> i;
- BOOST_FOREACH(i, host_vec_) { ss << " " << i.first << Str::COLON() << i.second << "\n";}
- }
- ss << " ECF_NAME = " << task_path_ << "\n";
- ss << " ECF_PASS = " << jobs_password_ << "\n";
- ss << " ECF_RID = " << remote_id_ << "\n";
- ss << " ECF_TRYNO = " << task_try_num_ << "\n";
- ss << " ECF_HOSTFILE = " << host_file_ << "\n";
- ss << " ECF_TIMEOUT = " << timeout_ << "\n";
- ss << " ECF_CONNECT_TIMEOUT = " << connect_timeout_ << "\n";
- ss << " ECF_DENIED = " << denied_ << "\n";
- assert( host_vec_index_ >=0 && host_vec_index_ < static_cast<int>(host_vec_.size()));
- if (host_vec_.empty()) ss << " ECF_PORT = \n";
- else ss << " ECF_PORT = " << host_vec_[host_vec_index_].second << "\n";
- ss << " NO_ECF = " << no_ecf_ << "\n";
- for(size_t i = 0; i < env_.size(); i++) {
- ss << " " << env_[i].first << " = " << env_[i].second << "\n";
- }
- ss << " ECF_ALLOW_NEW_CLIENT_OLD_SERVER = " << env_ecf_new_client_old_server_ << "\n";
- ss << " allow_new_client_old_server_ = " << allow_new_client_old_server_ << "\n";
-
- ss << " ECF_DEBUG_CLIENT = " << debug_ << "\n";
- return ss.str();
-}
-
-std::string ClientEnvironment::hostSpecified()
-{
- char* theEnv = getenv(Str::ECF_NODE().c_str());
- if (theEnv) {
- return std::string(theEnv);
- }
- return std::string();
-}
-
-std::string ClientEnvironment::portSpecified()
-{
- char* theEnv = getenv(Str::ECF_PORT().c_str());
- if (theEnv) {
- return std::string(theEnv);
- }
- return Str::DEFAULT_PORT_NUMBER();
-}
-
-
-void ClientEnvironment::read_environment_variables()
-{
-#ifdef DEBUG_ENVIRONMENT
- std::cout << "ClientEnvironment::read_environment_variables()\n";
-#endif
-
- if (getenv(Str::ECF_NAME().c_str())) task_path_ = getenv(Str::ECF_NAME().c_str());
- if (getenv(Str::ECF_PASS().c_str())) jobs_password_ = getenv(Str::ECF_PASS().c_str());
- if (getenv(Str::ECF_TRYNO().c_str())) task_try_num_ = atoi(getenv(Str::ECF_TRYNO().c_str()));
- if (getenv("ECF_HOSTFILE")) host_file_ = getenv("ECF_HOSTFILE");
- if (getenv(Str::ECF_RID().c_str())) remote_id_ = getenv(Str::ECF_RID().c_str());
-
- if (getenv("ECF_TIMEOUT")) timeout_ = atoi(getenv("ECF_TIMEOUT")); // host file timeout
- if( timeout_ > MAX_TIMEOUT ) timeout_ = MAX_TIMEOUT;
- if( timeout_ < MIN_TIMEOUT ) timeout_ = MIN_TIMEOUT;
-
- if (getenv("ECF_CONNECT_TIMEOUT")) connect_timeout_ = atoi(getenv("ECF_CONNECT_TIMEOUT")); // for test only
-
- if (getenv("ECF_DENIED")) denied_ = true;
- if (getenv("NO_ECF")) no_ecf_ = true;
- if (getenv("ECF_DEBUG_CLIENT")) debug_ = true;
-
- char *debug_level = getenv("ECF_DEBUG_LEVEL");
- if (debug_level) {
- try { Ecf::set_debug_level(boost::lexical_cast<unsigned int>(debug_level)); }
- catch (...) { throw std::runtime_error("The environment variable ECF_DEBUG_LEVEL must be an unsigned integer."); }
- }
-
- /// Override the config settings *IF* any
- std::string port = Str::DEFAULT_PORT_NUMBER();
- std::string host = Str::LOCALHOST();
- if (!host_vec_.empty()) {
- host = host_vec_[0].first; // first entry is the config host
- port = host_vec_[0].second; // first entry is the config port
- }
-
- if (getenv(Str::ECF_PORT().c_str())) {
- port = getenv(Str::ECF_PORT().c_str());
- host_vec_.clear(); // remove config settings, net effect is overriding
- host_vec_.push_back(std::make_pair(host,port));
- }
-
- // Add the ECF_NODE host into list of hosts. Make sure its first in host_vec_
- // as we want environment setting to take priority.
- string env_host = hostSpecified();
- if (!env_host.empty()) {
- host = env_host;
- host_vec_.clear(); // remove previous setting if any
- host_vec_.push_back(std::make_pair(host,port));
- }
-
- if (getenv("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")) {
- env_ecf_new_client_old_server_ = getenv("ECF_ALLOW_NEW_CLIENT_OLD_SERVER");
- update_allow_new_client_old_server(host,port);
- }
-}
-
-
-static std::string ecf_allow_new_client_old_server_error_msg(const std::string& env)
-{
- int current_archive_version = ecf::boost_archive::version();
- int previous_archive_version = current_archive_version -1;
- std::stringstream ss;
- ss << "\nFound environment variable ECF_ALLOW_NEW_CLIENT_OLD_SERVER=" << env << "\n";
- ss << "ECF_ALLOW_NEW_CLIENT_OLD_SERVER must have one of the formats:\n";
- ss << " ECF_ALLOW_NEW_CLIENT_OLD_SERVER=<int>\n";
- ss << " ECF_ALLOW_NEW_CLIENT_OLD_SERVER=<host>:<port>:<int>,<host>:<port>:<int>,<host>:<port>:<int>\n";
- ss << "Where <int> represents the archive version of the server. i.e the old server\n";
- ss << "i.e. export ECF_ALLOW_NEW_CLIENT_OLD_SERVER=" << previous_archive_version << "\n";
- ss << "or export ECF_ALLOW_NEW_CLIENT_OLD_SERVER=host1:3142:" << previous_archive_version << ",localhost:3142:" << previous_archive_version << "\n";
- ss << "Please ensure host/port of the server you want connect too, is on the list";
- return ss.str();
-}
-
-void ClientEnvironment::update_allow_new_client_old_server(const std::string& host, const std::string& port)
-{
- // If we update host/port via command line, we need to update this again.
- // cout << "ClientEnvironment::update_allow_new_client_old_server: host:" << host << " port:" << port << " env=" << env_ecf_new_client_old_server_ << "\n";
-
- // In the viewer context, we can have multiple clients, some where client <-> server is compatible , others which are not:
- // To allow for this, we expect following syntax:
- // option 1/ export ECF_ALLOW_NEW_CLIENT_OLD_SERVER=<int>
- // option 2/ export ECF_ALLOW_NEW_CLIENT_OLD_SERVER=<host>:<port>:<int>,<host>:<port>:<int>,<host>:<port>:<int>
- // Where <int> represents the archive version of the server. i.e the old server.
- // Only if the host/port matches in in our list do we update allow_new_client_old_server_
- //
- if (!env_ecf_new_client_old_server_.empty()) {
- try {
- // option 1:
- allow_new_client_old_server_ = boost::lexical_cast<int>(env_ecf_new_client_old_server_);
- }
- catch (...) {
- // cout << "option 2: Match the archive referring to *this* host/port specified.\n";
- std::vector<std::string> list;
- Str::split(env_ecf_new_client_old_server_,list,",");
- if (list.empty()) throw std::runtime_error(ecf_allow_new_client_old_server_error_msg(env_ecf_new_client_old_server_));
- // Find our host/port in the list:
- for(size_t i = 0; i < list.size(); ++i) {
- std::vector<std::string> host_port_archive;
- Str::split( list[i], host_port_archive, ":");
- if (host_port_archive.size() == 3) {
- // cout << host_port_archive[0] << ":" << host_port_archive[1] << ":" << host_port_archive[2] << "\n";
- if (host_port_archive[0] == host && host_port_archive[1] == port) {
- try { allow_new_client_old_server_ = boost::lexical_cast<int>(host_port_archive[2]); break;}
- catch (...) { throw std::runtime_error(ecf_allow_new_client_old_server_error_msg(env_ecf_new_client_old_server_));}
- }
- }
- else { throw std::runtime_error(ecf_allow_new_client_old_server_error_msg(env_ecf_new_client_old_server_));}
- }
- }
- }
-}
-
-
-bool ClientEnvironment::parseHostsFile(std::string& errorMsg)
-{
- std::vector<std::string> lines;
- if (!File::splitFileIntoLines(host_file_,lines,true /*IGNORE EMPTY LINES*/)) {
- std::stringstream ss; ss << "ClientEnvironment:: Could not open the hosts file " << host_file_;
- errorMsg += ss.str();
- return false;
- }
-
- // The Home server and port should be at index 0.
- std::string job_supplied_port = Str::DEFAULT_PORT_NUMBER();
- if ( !host_vec_.empty() ) job_supplied_port = host_vec_[0].second;
-
- // Each line should have the format: We only read in the first token.
- // host # comment
- // host:port # another comment
- // If no port is specified we default to port read in from the environment
- // if that was not specified we default to Str::DEFAULT_PORT_NUMBER()
- std::vector<std::string>::iterator theEnd = lines.end();
- for(std::vector<std::string>::iterator i = lines.begin(); i!= theEnd; ++i) {
-
- std::vector< std::string > tokens;
- Str::split((*i),tokens);
- if (tokens.empty()) continue;
- if (tokens[0][0] == '#') {
-// std::cout << "Ignoring line:'" << *i << "'\n";
- continue;
- }
-
- std::string theBackupHost;
- std::string thePort;
-
- size_t colonPos = tokens[0].find_first_of(':');
- if (colonPos == string::npos) {
- // When the port is *NOT* specified, we must use the job supplied port.
- // i.e. the one read in from the environment
- theBackupHost = tokens[0];
- thePort = job_supplied_port;
-// std::cout << "Host = " << theBackupHost << " Port is " << thePort << "\n";
- }
- else {
- theBackupHost = tokens[0].substr(0,colonPos);
- thePort = tokens[0].substr(colonPos+1);
-// std::cout << "Host = " << theBackupHost << " Port is specified " << thePort << "\n";
- }
-
- // std::cout << "Host = " << theBackupHost << " " << thePort << "\n";
- host_vec_.push_back(std::make_pair(theBackupHost,thePort));
- }
-
- return true;
-}
diff --git a/ecflow_4_0_7/Client/src/ClientEnvironment.hpp b/ecflow_4_0_7/Client/src/ClientEnvironment.hpp
deleted file mode 100644
index b2bb070..0000000
--- a/ecflow_4_0_7/Client/src/ClientEnvironment.hpp
+++ /dev/null
@@ -1,150 +0,0 @@
-#ifndef CLIENT_ENVIRONMENT_HPP_
-#define CLIENT_ENVIRONMENT_HPP_
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name : ClientEnvironment
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "AbstractClientEnv.hpp"
-
-class ClientEnvironment : public AbstractClientEnv {
-public:
- /// The constructor will load the environment
- ClientEnvironment();
-
- /// This constructor is only used in Test environment, as it allow the host file to be set
- ClientEnvironment(const std::string& hostFile, const std::string& host = "", const std::string& port = "");
-
- /// Forward compatibility allow new client to talk to old server
- /// Only applies when return value is non zero, in which case, it will return
- /// the boost archive version of the old server
- /// For the command line this is read from ECF_ALLOW_NEW_CLIENT_OLD_SERVER
- int allow_new_client_old_server() const { return allow_new_client_old_server_;}
- void allow_new_client_old_server(int boost_archive_version) { allow_new_client_old_server_ = boost_archive_version;}
-
- /// This controls for how long child commands continue trying to connect to Server before failing.
- /// Maximum time in seconds for client to deliver message to server/servers. This is
- /// typically 24 hours in a real environment. It is this long to allow operators to
- /// recover from any crashes.
- /// for the CHILD/task commands *ONLY*
- /// Can be overriden by changing environment variable ECF_TIMEOUT
- long max_child_cmd_timeout() const { return timeout_; }
-
- /// Allow pur python jobs to override the ECF_TIMEOUT
- void set_child_cmd_timeout(unsigned int t) { timeout_ = t; }
-
- /// The timeout feature allow the client to fail gracefully in the case
- /// where the server has died/crashed. The timeout will ensure the socket is closed.
- /// allowing the server to be restarted without getting the address is use error.
- /// Set the timeout for each client->server communication:
- // connect : timeout_ second
- // send request : timeout_ second
- // receive reply : timeout_ second
- // default is 0 second, which means take the timeout from the command/request
- // The default can be overridden with ECF_CONNECT_TIMEOUT.
- // This is useful when running valgrind --tool=callgrind which leads to
- // massive slow down and disconnection from the client, when the server is still
- // running.
- // used for **test only**
- int connect_timeout() const { return connect_timeout_;}
-
- /// When called will demand load the ecf host file, and read the hosts.
- /// Will then iterate over the host, when the end is reached will start over
- /// If host can not be opened or errors occur returns false;
- bool get_next_host(std::string& errorMsg);
-
- /// If server denies client communication and this flag is set, exit with an error
- /// Avoids 24hr hour connection attempt to server. Aids zombie control.
- bool denied() const { return denied_;}
-
- /// if NO_ECF is set then abort client immediately. Client should return success
- /// useful when we want to test jobs stand-alone
- bool no_ecf() const { return no_ecf_;}
-
- /// for debug
- std::string toString() const;
-
- /// Return contents of ECF_NODE environment variable, Otherwise an EMPTY string
- static std::string hostSpecified();
-
- /// Returns of ECF_PORT,environment variable, otherwise returns Str::DEFAULT_PORT_NUMBER
- static std::string portSpecified();
-
- // Set the rid. Only needed to override in regression test, to avoid interference
- // May be need a better name, is really the process id of running job.
- // Needs to be the same value as supplied to child command init
- void set_remote_id(const std::string& rid) { remote_id_ = rid; }
-
-// AbstractClientEnv functions:
- virtual bool checkTaskPathAndPassword(std::string& errorMsg) const;
- virtual const std::string& task_path() const { return task_path_; }
- virtual int task_try_no() const { return task_try_num_; }
- virtual const std::string& jobs_password() const { return jobs_password_ ;}
- virtual const std::string& process_or_remote_id() const { return remote_id_; }
- virtual void set_host_port(const std::string& host, const std::string& port);
- virtual const std::string& host() const;
- virtual const std::string& port() const;
- virtual const std::vector<std::pair<std::string,std::string> >& env() const { return env_;}
- virtual bool debug() const { return debug_;} //enabled if ECF_DEBUG_CLIENT set
- virtual void set_test() { under_test_ = true; }
- virtual bool under_test() const { return under_test_; }
-
-private:
-
- std::string task_path_; // ECF_NAME = /aSuit/aFam/aTask
- std::string jobs_password_; // ECF_PASS jobs password
- std::string remote_id_; // ECF_RID process id of running job
- int task_try_num_; // ECF_TRYNO. The task try number. The number of times we should submitted a job, if it is aborted
- std::string host_file_; // ECF_HOSTFILE. File that lists the backup hosts, port numbers must match
- long timeout_; // ECF_TIMEOUT. Host file iteration time out
- int connect_timeout_; // default 0, ECF_CONNECT_TIMEOUT, connection timeout
- bool denied_; // ECF_DENIED. If set ECF denies access, client will exit with failure")
- bool no_ecf_; // NO_ECF. if defined then abort cmd immediately. useful when test jobs stand-alone
-
- bool debug_; // For live debug, enabled by env variable ECF_CLIENT_DEBUG
- bool under_test_; // Used in testing client interface
- std::vector<std::pair<std::string,std::string> > env_; // For test allow env variable to be set on defs
-
- bool host_file_read_; // to ensure we read host file only once
- std::vector<std::pair<std::string, std::string> > host_vec_; // The list of host:port pairs
- int host_vec_index_; // index into host_vec;
- int allow_new_client_old_server_; // the boost archive version of old server, allow new client--> old server communication
- std::string env_ecf_new_client_old_server_;
-
- /// The option read from the command line.
- friend class ClientOptions;
-
- // Allow testing to override the task path set in the environment. In this constructor
- friend class ClientInvoker;
-
-private:
-
- void init();
-
- void read_environment_variables(); /// Get the standard environment variables
-
- void update_allow_new_client_old_server(const std::string& host, const std::string& port);
-
- void taskPath(const std::string& s) { task_path_ = s;}
- void set_jobs_password(const std::string& s) { jobs_password_ = s;}
- void set_connect_timeout(int t) { connect_timeout_ = t;}
-
- // Allow testing to add or update the environment in the Defs file
- // Each pair is ( variable name, variable value )
- void setEnv( const std::vector<std::pair<std::string,std::string> >& e) { env_= e;}
-
- bool parseHostsFile(std::string& errorMsg);
-};
-
-#endif
diff --git a/ecflow_4_0_7/Client/src/ClientInvoker.cpp b/ecflow_4_0_7/Client/src/ClientInvoker.cpp
deleted file mode 100644
index 76a0742..0000000
--- a/ecflow_4_0_7/Client/src/ClientInvoker.cpp
+++ /dev/null
@@ -1,1321 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <iostream>
-#include <iterator>
-#include <boost/date_time/posix_time/time_formatters.hpp> // requires boost date and time lib
-
-#include "ClientInvoker.hpp"
-#include "Client.hpp"
-#include "ClientEnvironment.hpp"
-#include "ClientOptions.hpp"
-#include "Defs.hpp"
-#include "ArgvCreator.hpp"
-#include "Str.hpp"
-#include "ClientToServerCmd.hpp"
-#include "Rtt.hpp"
-#include "Ecf.hpp"
-#include "DurationTimer.hpp"
-#include "ChangeMgrSingleton.hpp"
-#include "TimeStamp.hpp"
-#include "Log.hpp"
-
-#ifdef DEBUG
-
-#if defined(HPUX) || defined(_AIX)
-#define RETRY_CONNECTION_PERIOD 2
-#define NEXT_HOST_POLL_PERIOD 2
-#else
-#define RETRY_CONNECTION_PERIOD 1
-#define NEXT_HOST_POLL_PERIOD 1
-#endif
-
-#else
-#define RETRY_CONNECTION_PERIOD 10
-#define NEXT_HOST_POLL_PERIOD 30
-#endif
-
-using namespace std;
-using namespace ecf;
-using namespace boost::posix_time;
-
-// ==================================================================================
-// class ClientInvoker
-ClientInvoker::ClientInvoker()
-: on_error_throw_exception_(true), cli_(false), test_(false),testInterface_(false),
- connection_attempts_(2),retry_connection_period_(RETRY_CONNECTION_PERIOD),child_task_try_no_(0)
-{
- if (clientEnv_.debug()) cout << "\nClientInvoker::ClientInvoker():============================start============================================\n";
-}
-
-ClientInvoker::ClientInvoker(const std::string& host_port)
-: on_error_throw_exception_(true), cli_(false), test_(false),testInterface_(false),
- connection_attempts_(2),retry_connection_period_(RETRY_CONNECTION_PERIOD),child_task_try_no_(0)
-{
- if (clientEnv_.debug()) cout << "\nClientInvoker::ClientInvoker():============================start============================================\n";
- // assume format <host>:<port>
- size_t colonPos = host_port.find_first_of(':');
- if (colonPos == string::npos) throw std::runtime_error("ClientInvoker::ClientInvoker: expected <host>:<port> : no ':' found in " + host_port);
- std::string host = host_port.substr(0,colonPos);
- std::string port = host_port.substr(colonPos+1);
- set_host_port(host,port);
-}
-
-ClientInvoker::ClientInvoker(const std::string& host, const std::string& port)
-: on_error_throw_exception_(true), cli_(false), test_(false),testInterface_(false),
- connection_attempts_(2),retry_connection_period_(RETRY_CONNECTION_PERIOD)
-{
- if (clientEnv_.debug()) cout << "\nClientInvoker::ClientInvoker():============================start============================================\n";
- set_host_port(host,port);
-}
-
-ClientInvoker::ClientInvoker(const std::string& host, int port)
-: on_error_throw_exception_(true), cli_(false), test_(false),testInterface_(false),
- connection_attempts_(2),retry_connection_period_(RETRY_CONNECTION_PERIOD)
-{
- if (clientEnv_.debug()) cout << "\nClientInvoker::ClientInvoker():============================start============================================\n";
- set_host_port(host, boost::lexical_cast<std::string>(port));
-}
-
-void ClientInvoker::set_host_port(const std::string& host, const std::string& port)
-{
- // Allow host and port to be overridden.
- // o Override environment setting
- // o For child commands will override opening of ecf_hosts file
- clientEnv_.set_host_port(host,port);
-}
-
-const std::string& ClientInvoker::host() const
-{
- return clientEnv_.host();
-}
-const std::string& ClientInvoker::port() const
-{
- return clientEnv_.port();
-}
-
-void ClientInvoker::allow_new_client_old_server(int archive_version_of_old_server)
-{
- clientEnv_.allow_new_client_old_server(archive_version_of_old_server);
-}
-
-int ClientInvoker::allow_new_client_old_server() const
-{
- return clientEnv_.allow_new_client_old_server();
-}
-
-void ClientInvoker::taskPath(const std::string& s) {
- assert(!s.empty());
- test_ = true;
- clientEnv_.taskPath(s);
-}
-void ClientInvoker::set_jobs_password(const std::string& djp)
-{
- test_ = true;
- clientEnv_.set_jobs_password(djp);
-}
-
-void ClientInvoker::setEnv( const std::vector<std::pair<std::string,std::string> >& e) {
- assert(!e.empty());
- test_ = true;
- clientEnv_.setEnv(e); // For test allow env variable to be set on defs
-}
-
-void ClientInvoker::testInterface() {
- testInterface_ = true;
- clientEnv_.set_test();
-}
-
-const std::string& ClientInvoker::process_or_remote_id() const
-{
- return clientEnv_.process_or_remote_id();
-}
-
-void ClientInvoker::enable_logging(const std::string& log_file_name)
-{
- Rtt::create(log_file_name);
-}
-
-void ClientInvoker::disable_logging()
-{
- Rtt::destroy();
-}
-
-void ClientInvoker::set_connect_timeout(int t)
-{
- clientEnv_.set_connect_timeout(t);
-}
-
-void ClientInvoker::set_connection_attempts( unsigned int attempts)
-{
- connection_attempts_ = attempts;
- if ( connection_attempts_ < 1 ) connection_attempts_ = 1;
-}
-
-int ClientInvoker::invoke(int argc, char* argv[]) const
-{
- // Allow request to logged & allow logging of round trip time, Hence must be placed *before* RoundTripRecorder
- RequestLogger request_logger(this);
-
- // initialise start_time_ and rtt_,
- RoundTripRecorder round_trip_recorder(this);
-
- /// If NO_ECF set then abort immediately. returning success. Useful in testing jobs stand-alone.
- if (clientEnv_.no_ecf()) return 0; // success
-
- // Clear error message. For test. Don't keep previous error.
- // i.e If next test passes when it shouldn't the wrong message is output
- server_reply_.get_error_msg().clear();
-
- Cmd_ptr cts_cmd;
- try {
- // read in program option, and construct the client to server commands from them.
- // This will extract host/port from the environment/ args
- // This will throw std::runtime_error for invalid arguments or options
- cts_cmd = args_.parse(argc,argv,&clientEnv_);
-
- // For --help and --debug, --load defs check_only no command is created
- // When testInterface avoid writing to standard out.
- if (!cts_cmd.get()) {
- if (!testInterface_ && clientEnv_.debug()) {
- cout << "args: "; for ( int x=0; x< argc; x++) cout << argv[x] << " "; cout << "\n";
- }
- return 0;
- }
- }
- catch ( std::exception& e ) {
- stringstream ss;
- if (argc == 1) {
- ss << Ecf::CLIENT_NAME() << ": No options specified\n";
- ss << "Usage: " << Ecf::CLIENT_NAME() << " [OPTION]...\n";
- ss << "Try '" << Ecf::CLIENT_NAME() << " --help' for list of options\n";
- }
- else {
- ss << Ecf::CLIENT_NAME() << ": Caught exception whilst parsing arguments:\n" << e.what() << "\n";
- ss << "args: "; for ( int x=0; x< argc; x++) ss << argv[x] << " "; ss << "\n";
- }
- server_reply_.set_error_msg(ss.str());
- if (on_error_throw_exception_) throw std::runtime_error(server_reply_.error_msg());
- return 1;
- }
- catch ( ... ) {
- server_reply_.set_error_msg("ecflow:ClientInvoker: caught exception: Parsing arguments: unknown type!\n");
- if (on_error_throw_exception_) throw std::runtime_error(server_reply_.error_msg());
- return 1;
- }
-
- // Under debug we display round trip time for each request
- request_logger.set_cts_cmd(cts_cmd);
-
- int res = do_invoke_cmd( cts_cmd );
- if (res == 1 && on_error_throw_exception_) throw std::runtime_error(server_reply_.error_msg());
- return res;
-}
-
-int ClientInvoker::invoke( const std::string& arg ) const
-{
- int argc = 2;
- char* argv[] = { const_cast<char*>("ClientInvoker"), const_cast<char*>(arg.c_str()) };
- return invoke(argc,argv);
-}
-
-int ClientInvoker::invoke( const std::vector<std::string>& args ) const
-{
- std::vector<std::string> theArgs;
- theArgs.push_back("ClientInvoker");
- std::copy( args.begin(), args.end(), std::back_inserter(theArgs) );
- ArgvCreator argvCreator( theArgs );
- return invoke(argvCreator.argc(),argvCreator.argv());
-}
-
-int ClientInvoker::invoke(Cmd_ptr cts_cmd) const
-{
- // assumes clients of Cmd_ptr constructor has caught exceptions
-
- // Allow request to be logged & allow logging of round trip time, Hence must be placed *before* RoundTripRecorder
- RequestLogger request_logger(this);
-
- // initialise start_time_ and rtt_,
- RoundTripRecorder round_trip_recorder(this);
-
- // allow display of round trip time for each request
- request_logger.set_cts_cmd(cts_cmd);
-
- int res = do_invoke_cmd( cts_cmd );
- if (res == 1 && on_error_throw_exception_) throw std::runtime_error(server_reply_.error_msg());
- return res;
-}
-
-
-int ClientInvoker::do_invoke_cmd(Cmd_ptr cts_cmd) const
-{
- if (clientEnv_.debug()) cout << "\necflow:ClientInvoker::do_invoke_cmd on_error_throw_exception_(" << on_error_throw_exception_ << ")================================" << std::endl;
- if (clientEnv_.no_ecf()) return 0; // success If NO_ECF set then abort immediately. returning success. Useful in testing jobs stand-alone.
- if (testInterface_) return 0; // The testInterface_ flag allows testing of client interface, parsing of args, without needing to contact server
- assert(!clientEnv_.host().empty()); // make sure host is NOT empty.
-
- if (ChangeMgrSingleton::exists() && ChangeMgrSingleton::instance()->in_notification()) {
- // place break point here, Change mgr observers, calling *ANOTHER* client->server command, in a middle of update to observers
- std::cout << "***********************************************************\n";
- std::cout << "ecflow:ClientInvoker::do_invoke_cmd() "; cts_cmd->print(cout); std::cout << " called in the middle of ChangeMgrSingleton::notification. !!!!!!!!\n";
- std::cout << "***********************************************************\n";
- }
-
- /// retry_connection_period_ specifies the time to wait, before retrying to connect to server.
- /// Added to get round glitches in the network.
- /// However for ping() always default to 1 second. This avoids 10 second wait in release mode.
- /// We do this both for the CLI(command level interface) and python api
- unsigned int retry_connection_period = retry_connection_period_;
- if (cts_cmd->ping_cmd()) retry_connection_period = 1;
-
- try {
- /// report this message at least once. So client has a clue what's going on
- bool report_block_client_on_home_server = false;
- bool report_block_client_server_halted = false;
- bool report_block_client_zombie_detected = false;
-
- // We do not want to loop over the sms host list indefinitely hence we use a timer.
- // The time out period is supplied via ClientEnvironment
- bool never_polled = true; // don't wait for the first host only subsequent ones
-
- while ( true ) {
-
- // for each host try connecting several times. To compensate for network glitches.
- int no_of_tries = connection_attempts_;
- while ( no_of_tries > 0 ) {
- try {
- if (clientEnv_.debug()) { cout << "ClientInvoker: >>> About to invoke "; cts_cmd->print(cout); cout << " on " << client_env_host_port() << " : retry_connection_period(" << retry_connection_period << ") no_of_tries(" << no_of_tries << ") cmd_connect_timeout(" << cts_cmd->timeout() << ") ECF_CONNECT_TIMEOUT(" << clientEnv_.connect_timeout() << ")<<<" << endl;}
-
- /// *** Each call to io_service.run(); is a *REQUEST* to the server ***
- /// *** Hence we *MUST* clear the server_reply before each call *******
- /// *** Found during zombie test. i.e when blocking, we were responding to previous, reply, since server_reply was not being reset
- /// *Note* server_reply_.client_handle_ is kept until the next call to register a new client_handle
- /// The client invoker can be used multiple times, hence keep value of defs, and client handle in server reply
- /// However this is only done, if we are not using the Command Level Interface(cli)
- server_reply_.clear_for_invoke(cli_);
-
- boost::asio::io_service io_service;
- Client theClient( io_service, cts_cmd , clientEnv_.host(), clientEnv_.port(), clientEnv_.connect_timeout() );
- if (clientEnv_.allow_new_client_old_server() != 0) theClient.allow_new_client_old_server(clientEnv_.allow_new_client_old_server());
- io_service.run();
- if (clientEnv_.debug()) cout << "ClientInvoker: >>> After: io_service.run() <<<" << endl;;
-
- /// Let see how the server responded if at all.
- try {
- /// will return false if further action required
- if (theClient.handle_server_response( server_reply_, clientEnv_.debug() )) {
- // The normal response. RoundTriprecorder will record in rtt_
-
- // If the command was a delete_all command, reset client_handle
- if (cts_cmd->delete_all_cmd()) {
- ClientInvoker* non_const_this = const_cast<ClientInvoker*>(this);
- non_const_this->reset();
- }
- return 0; // the normal exit path
- }
- }
- catch (std::exception& e) {
- server_reply_.set_error_msg( e.what() );
- return 1;
- }
-
- if ( server_reply_.block_client_on_home_server()) {
- // Valid reply from server. Typically waiting on a expression
- // Ok _Block_ on _current_ server, and continue waiting, until server reply is ok
- if (!report_block_client_on_home_server || clientEnv_.debug()) { cout << TimeStamp::now() << "ecflow:ClientInvoker: "; cts_cmd->print(cout); cout << " : " << client_env_host_port() << " : WAITING on home server, continue waiting\n";report_block_client_on_home_server = true;}
- no_of_tries++;
- }
- else if (server_reply_.block_client_server_halted()) {
- // Valid reply from server.
- // fall through try again, then try other hosts
- if (!report_block_client_server_halted || clientEnv_.debug()){ cout << TimeStamp::now() << "ecflow:ClientInvoker: "; cts_cmd->print(cout); cout << " : " << client_env_host_port() << " : blocking : server is HALTED, continue waiting\n";report_block_client_server_halted = true;}
- }
- else if (server_reply_.block_client_zombie_detected()) {
- // Valid reply from server.
- // fall through try again, then try other hosts
- if (!report_block_client_zombie_detected || clientEnv_.debug()){ cout << TimeStamp::now() << "ecflow:ClientInvoker: "; cts_cmd->print(cout); cout << " : " << client_env_host_port() << " : blocking : zombie detected, continue waiting\n";report_block_client_zombie_detected = true;}
- }
- else if (server_reply_.client_request_failed()) {
- // Valid reply from server
- // This error is ONLY valid if we got a real reply from the server
- // as opposed to some kind of connection errors. For connections errors
- // we fall through and try again.
- if (clientEnv_.debug()) {cout << "ecflow:ClientInvoker:"; cts_cmd->print(cout); cout << " failed : " << client_env_host_port() << " : " << server_reply_.error_msg() << "\n";}
- return 1;
- }
- else {
- std::cout << TimeStamp::now() << "ecflow:ClientInvoker: missed response? for request "; cts_cmd->print(cout); std::cout << " oops" << endl;
- }
- }
- catch (std::exception& e) {
- // *Some kind of connection error*: fall through and try again. Avoid this message when pinging, i.e to see if server is alive.
- if (clientEnv_.debug()) { cerr << "ecflow:ClientInvoker: Connection error: (" << e.what() << ")" << endl; }
- if (!cts_cmd->ping_cmd()) {
- cerr << TimeStamp::now() << "ecflow:ClientInvoker: Connection error: (" << e.what() << ")" << endl;
- }
- }
-
- // Wait a bit before trying to connect again, but only if no_of_tries > 0
- no_of_tries--;
- if (no_of_tries > 0) sleep( retry_connection_period );
- }
-
- // Don't bother with other hosts when:
- // 1/ Testing
- // 2/ ping-ing
- // 3/ ECF_DENIED has been set
- // 4/ Dealing with non tasks based request
- if (!cts_cmd->connect_to_different_servers() || test_ || cts_cmd->ping_cmd() || clientEnv_.denied() ) {
- std::stringstream ss;
- ss << TimeStamp::now() << "Request( "; cts_cmd->print(ss) << " )";
- if (clientEnv_.denied()) ss << " ECF_DENIED ";
- ss << ", Failed to connect to " << client_env_host_port()
- << ". After " << connection_attempts_ << " attempts. Is the server running ?\n";
- // Only print client environment if not pinging
- if (!cts_cmd->ping_cmd()) ss << "Client environment:\n" << clientEnv_.toString() << endl;
- server_reply_.set_error_msg(ss.str());
- return 1;
- }
-
- boost::posix_time::time_duration duration = microsec_clock::universal_time() - start_time_;
- if (clientEnv_.debug()) { cout << "ClientInvoker: Time duration = " << duration.total_seconds() << " clientEnv_.max_child_cmd_timeout() = " << clientEnv_.max_child_cmd_timeout() << endl;}
-
- if ( duration.total_seconds() >= clientEnv_.max_child_cmd_timeout() ) {
- std::stringstream ss; ss << TimeStamp::now() << "ecflow:ClientInvoker: Timed out after " << clientEnv_.max_child_cmd_timeout() << " seconds : for " << client_env_host_port() << "\n";
- std::string msg = ss.str();
- cout << msg;
- server_reply_.set_error_msg(msg);
- return 1;
- }
-
- // The host is not playing ball, try the next host, will *restart* with home server, if end reached
- // *get_next_host* *only* returns false if host exists, and parsing it fails
- std::string current_host_port = client_env_host_port();
-
- std::string local_error_msg;
- if (!clientEnv_.get_next_host(local_error_msg)) {
- /// Instead of exiting, Just spit out a warning
- cout << TimeStamp::now() << "ecflow:ClientInvoker: "; cts_cmd->print(cout); cout << " get next host failed because: " << local_error_msg << endl;
- }
-
- cout << TimeStamp::now() << "ecflow:ClientInvoker: "; cts_cmd->print(cout); cout << " current host(" << current_host_port << ") trying next host(" << client_env_host_port() << ")" << endl;
-
- if( never_polled ) never_polled = false; // To avoid the first wait
- else sleep(NEXT_HOST_POLL_PERIOD);
- }
- }
- catch ( std::exception& e ) {
- stringstream ss; ss << TimeStamp::now() << "ecflow:ClientInvoker: caught exception: " << e.what() << "\n";
- server_reply_.set_error_msg(ss.str());
- }
- catch ( ... ) {
- stringstream ss; ss << TimeStamp::now() << "ecflow:ClientInvoker: Caught Exception of unknown type!\n";
- server_reply_.set_error_msg(ss.str());
- }
- return 1;
-}
-
-
-void ClientInvoker::reset()
-{
- server_reply_.set_client_defs( defs_ptr() );
- server_reply_.set_client_node( node_ptr() );
- server_reply_.set_client_handle( 0 );
-}
-
-//=====================================================================================
-// By using the command directly, it is a lot faster than using argc/argv
-// preserve old method to test api/command level interface.
-
-int ClientInvoker::getDefs() const
-{
- if (testInterface_) return invoke(CtsApi::get());
- return invoke( Cmd_ptr( new CtsNodeCmd( CtsNodeCmd::GET) ) );
-}
-
-int ClientInvoker::loadDefs(
- const std::string& filePath,
- bool force, /* true means overwrite suite of same name */
- bool check_only /* true means don't send to server, just check only */
-) const
-{
- if (testInterface_) return invoke(CtsApi::loadDefs(filePath,force,check_only));
- Cmd_ptr cmd = LoadDefsCmd::create(filePath,force,check_only,&clientEnv_);
- if (cmd) return invoke(cmd); // If check_only cmd will be empty
- return 0;
-}
-
-int ClientInvoker::sync(defs_ptr& client_defs) const
-{
- if (client_defs.get()) {
- server_reply_.set_client_defs( client_defs );
- if (testInterface_) return invoke(CtsApi::sync(server_reply_.client_handle(), client_defs->state_change_no(), client_defs->modify_change_no()));
- return invoke( Cmd_ptr( new CSyncCmd(CSyncCmd::SYNC,server_reply_.client_handle(), client_defs->state_change_no(), client_defs->modify_change_no() ) ) );
- }
-
- if (testInterface_) return invoke(CtsApi::get());
- int res = invoke( Cmd_ptr( new CtsNodeCmd(CtsNodeCmd::GET)));
- if (res == 0) {
- client_defs = server_reply_.client_defs(); // update change number
- }
- return res;
-}
-
-int ClientInvoker::sync_local() const
-{
- // Prevent infinite loops in change observers.
- // This can be removed when we do the new ecflowview. TODO
- if (ChangeMgrSingleton::exists() && ChangeMgrSingleton::instance()->in_notification()) {
- std::cout << "ecflow:ClientInvoker::sync_local() called in the middle of ChangeMgrSingleton::notification. Ignoring..... \n";
- return 0;
- }
-
- defs_ptr defs = server_reply_.client_defs();
- if (defs.get()) {
- if (testInterface_) return invoke(CtsApi::sync(server_reply_.client_handle(),defs->state_change_no(), defs->modify_change_no()));
- return invoke( Cmd_ptr( new CSyncCmd(CSyncCmd::SYNC,server_reply_.client_handle(), defs->state_change_no(), defs->modify_change_no() ) ) );
- }
- // If we have a handle return the defs, with the registered suites, else returns the full defs
- if (testInterface_) return invoke(CtsApi::sync_full(server_reply_.client_handle()));
- return invoke( Cmd_ptr( new CSyncCmd(server_reply_.client_handle()) ) );
-}
-
-int ClientInvoker::news(defs_ptr& client_defs) const
-{
- if (client_defs.get()) {
- if (testInterface_) return invoke(CtsApi::news(server_reply_.client_handle(),client_defs->state_change_no(), client_defs->modify_change_no()));
- return invoke( Cmd_ptr( new CSyncCmd(CSyncCmd::NEWS,server_reply_.client_handle(), client_defs->state_change_no(), client_defs->modify_change_no() ) ) );
- }
- server_reply_.set_error_msg("The client definition is empty.");
- if (on_error_throw_exception_) throw std::runtime_error(server_reply_.error_msg());
- return 1;
-}
-
-int ClientInvoker::news_local() const
-{
- defs_ptr defs = server_reply_.client_defs();
- if (defs.get()) {
- if (testInterface_) return invoke(CtsApi::news(server_reply_.client_handle(), defs->state_change_no(), defs->modify_change_no()));
- return invoke( Cmd_ptr( new CSyncCmd(CSyncCmd::NEWS,server_reply_.client_handle(), defs->state_change_no(), defs->modify_change_no() ) ) );
- }
-
- // There is no local defs, i.e first time call, The default client handle should be 0.
- // go with defaults for state and modify change numbers
- // User is expected to call sync_local(), which will update local defs.
- if (testInterface_) return invoke(CtsApi::news(server_reply_.client_handle(), 0, 0));
- return invoke( Cmd_ptr( new CSyncCmd(CSyncCmd::NEWS,server_reply_.client_handle(), 0, 0 ) ) );
-}
-//=====================================================================================
-int ClientInvoker::restartServer() const
-{
- if (testInterface_) return invoke(CtsApi::restartServer());
- return invoke(Cmd_ptr(new CtsCmd(CtsCmd::RESTART_SERVER)));
-}
-int ClientInvoker::haltServer() const
-{
- if (testInterface_) return invoke(CtsApi::haltServer(true/*auto_confirm*/));
- return invoke(Cmd_ptr(new CtsCmd(CtsCmd::HALT_SERVER)));
-}
-int ClientInvoker::pingServer() const
-{
- if (testInterface_) return invoke( CtsApi::pingServer());
- return invoke(Cmd_ptr(new CtsCmd(CtsCmd::PING)));
-}
-int ClientInvoker::shutdownServer() const
-{
- if (testInterface_) return invoke(CtsApi::shutdownServer(true/*auto_confirm*/));
- return invoke(Cmd_ptr(new CtsCmd(CtsCmd::SHUTDOWN_SERVER)));
-}
-int ClientInvoker::terminateServer() const
-{
- if (testInterface_) return invoke(CtsApi::terminateServer(true/*auto_confirm*/));
- return invoke(Cmd_ptr(new CtsCmd(CtsCmd::TERMINATE_SERVER)));
-}
-int ClientInvoker::stats() const
-{
- if (testInterface_) return invoke(CtsApi::stats());
- return invoke(Cmd_ptr(new CtsCmd(CtsCmd::STATS)));
-}
-int ClientInvoker::stats_reset() const
-{
- if (testInterface_) return invoke(CtsApi::stats_reset());
- return invoke(Cmd_ptr(new CtsCmd(CtsCmd::STATS_RESET)));
-}
-int ClientInvoker::suites() const
-{
- if (testInterface_) return invoke(CtsApi::suites());
- return invoke(Cmd_ptr(new CtsCmd(CtsCmd::SUITES)));
-}
-int ClientInvoker::server_version() const
-{
- if (testInterface_) return invoke(CtsApi::server_version());
- return invoke(Cmd_ptr(new ServerVersionCmd()) );
-}
-int ClientInvoker::debug_server_on() const
-{
- if (testInterface_) return invoke(CtsApi::debug_server_on());
- return invoke(Cmd_ptr(new CtsCmd(CtsCmd::DEBUG_SERVER_ON)));
-}
-int ClientInvoker::debug_server_off() const
-{
- if (testInterface_) return invoke(CtsApi::debug_server_off());
- return invoke(Cmd_ptr(new CtsCmd(CtsCmd::DEBUG_SERVER_OFF)));
-}
-
-//=====================================================================================
-
-int ClientInvoker::ch_register( bool auto_add_new_suites,const std::vector<std::string>& suites ) const
-{
- if (testInterface_) return invoke(CtsApi::ch_register(auto_add_new_suites, suites));
- return invoke(Cmd_ptr(new ClientHandleCmd(suites, auto_add_new_suites)) );
-}
-int ClientInvoker::ch_suites() const
-{
- if (testInterface_) return invoke(CtsApi::ch_suites());
- return invoke(Cmd_ptr(new ClientHandleCmd(ClientHandleCmd::SUITES)) );
-}
-int ClientInvoker::ch_drop( int client_handle ) const
-{
- if (testInterface_) return invoke(CtsApi::ch_drop(client_handle));
- return invoke(Cmd_ptr(new ClientHandleCmd(client_handle)) );
-}
-int ClientInvoker::ch_drop_user( const std::string& user) const
-{
- if (testInterface_) return invoke(CtsApi::ch_drop_user(user));
- return invoke(Cmd_ptr(new ClientHandleCmd(user)) );
-}
-int ClientInvoker::ch_add( int client_handle, const std::vector<std::string>& suites ) const
-{
- if (testInterface_) return invoke(CtsApi::ch_add(client_handle, suites));
- return invoke(Cmd_ptr(new ClientHandleCmd(client_handle, suites, ClientHandleCmd::ADD)) );
-}
-int ClientInvoker::ch_remove( int client_handle, const std::vector<std::string>& suites ) const
-{
- if (testInterface_) return invoke(CtsApi::ch_remove(client_handle, suites));
- return invoke(Cmd_ptr(new ClientHandleCmd(client_handle, suites, ClientHandleCmd::REMOVE)) );
-}
-int ClientInvoker::ch_auto_add( int client_handle, bool auto_add_new_suites ) const
-{
- if (testInterface_) return invoke(CtsApi::ch_auto_add(client_handle, auto_add_new_suites));
- return invoke(Cmd_ptr(new ClientHandleCmd(client_handle,auto_add_new_suites)) );
-}
-int ClientInvoker::ch1_drop() const
-{
- if (0 == server_reply_.client_handle()) return 0;
- if (testInterface_) return invoke(CtsApi::ch_drop(server_reply_.client_handle()));
- return invoke(Cmd_ptr(new ClientHandleCmd(server_reply_.client_handle())) );
-}
-int ClientInvoker::ch1_add( const std::vector<std::string>& suites ) const
-{
- if (testInterface_) return invoke(CtsApi::ch_add(server_reply_.client_handle(), suites));
- return invoke(Cmd_ptr(new ClientHandleCmd(server_reply_.client_handle(), suites, ClientHandleCmd::ADD)) );
-}
-int ClientInvoker::ch1_remove( const std::vector<std::string>& suites ) const
-{
- if (testInterface_) return invoke(CtsApi::ch_remove(server_reply_.client_handle(), suites));
- return invoke(Cmd_ptr(new ClientHandleCmd(server_reply_.client_handle(), suites, ClientHandleCmd::REMOVE)) );
-}
-int ClientInvoker::ch1_auto_add( bool auto_add_new_suites ) const
-{
- if (testInterface_) return invoke(CtsApi::ch_auto_add(server_reply_.client_handle(), auto_add_new_suites));
- return invoke(Cmd_ptr(new ClientHandleCmd(server_reply_.client_handle(),auto_add_new_suites)) );
-}
-
-// ======================================================================================================
-
-int ClientInvoker::begin( const std::string& suiteName, bool force ) const
-{
- if (testInterface_) return invoke(CtsApi::begin(suiteName, force));
- return invoke(Cmd_ptr(new BeginCmd(suiteName, force )) );
-}
-int ClientInvoker::begin_all_suites( bool force ) const
-{
- if (testInterface_) return invoke(CtsApi::begin("", force));
- return invoke(Cmd_ptr(new BeginCmd("", force )) );
-}
-// ======================================================================================================
-
-int ClientInvoker::zombieGet() const
-{
- if (testInterface_) return invoke(CtsApi::zombieGet());
- return invoke(Cmd_ptr(new CtsCmd(CtsCmd::GET_ZOMBIES)));
-}
-int ClientInvoker::zombieFob( const Zombie& z ) const
-{
- if (testInterface_) return invoke(CtsApi::zombieFob(z.path_to_task(), z.process_or_remote_id(), z.jobs_password()));
- return invoke(Cmd_ptr(new ZombieCmd(User::FOB, z.path_to_task(), z.process_or_remote_id(), z.jobs_password() )));
-}
-int ClientInvoker::zombieFail( const Zombie& z ) const
-{
- if (testInterface_) return invoke(CtsApi::zombieFail(z.path_to_task(), z.process_or_remote_id(), z.jobs_password()));
- return invoke(Cmd_ptr(new ZombieCmd(User::FAIL, z.path_to_task(), z.process_or_remote_id(), z.jobs_password() )));
-}
-int ClientInvoker::zombieAdopt( const Zombie& z ) const
-{
- if (testInterface_) return invoke(CtsApi::zombieAdopt(z.path_to_task(), z.process_or_remote_id(), z.jobs_password()));
- return invoke(Cmd_ptr(new ZombieCmd(User::ADOPT, z.path_to_task(), z.process_or_remote_id(), z.jobs_password() )));
-}
-int ClientInvoker::zombieBlock( const Zombie& z ) const
-{
- if (testInterface_) return invoke(CtsApi::zombieBlock(z.path_to_task(), z.process_or_remote_id(), z.jobs_password()));
- return invoke(Cmd_ptr(new ZombieCmd(User::BLOCK, z.path_to_task(), z.process_or_remote_id(), z.jobs_password() )));
-}
-int ClientInvoker::zombieRemove( const Zombie& z ) const
-{
- if (testInterface_) return invoke(CtsApi::zombieRemove(z.path_to_task(), z.process_or_remote_id(), z.jobs_password()));
- return invoke(Cmd_ptr(new ZombieCmd(User::REMOVE, z.path_to_task(), z.process_or_remote_id(), z.jobs_password() )));
-}
-int ClientInvoker::zombieKill( const Zombie& z ) const
-{
- if (testInterface_) return invoke(CtsApi::zombieKill(z.path_to_task(), z.process_or_remote_id(), z.jobs_password()));
- return invoke(Cmd_ptr(new ZombieCmd(User::KILL, z.path_to_task(), z.process_or_remote_id(), z.jobs_password() )));
-}
-int ClientInvoker::zombieFobCli( const std::string& absNodePath ) const
-{
- if (testInterface_) return invoke(CtsApi::zombieFobCli(absNodePath));
- return invoke(Cmd_ptr(new ZombieCmd(User::FOB, absNodePath,"","")));
-}
-int ClientInvoker::zombieFailCli( const std::string& absNodePath ) const
-{
- if (testInterface_) return invoke(CtsApi::zombieFailCli(absNodePath));
- return invoke(Cmd_ptr(new ZombieCmd(User::FAIL, absNodePath,"","" )));
-}
-int ClientInvoker::zombieAdoptCli( const std::string& absNodePath ) const
-{
- if (testInterface_) return invoke(CtsApi::zombieAdoptCli(absNodePath));
- return invoke(Cmd_ptr(new ZombieCmd(User::ADOPT, absNodePath,"","" )));
-}
-int ClientInvoker::zombieBlockCli( const std::string& absNodePath ) const
-{
- if (testInterface_) return invoke(CtsApi::zombieBlockCli(absNodePath));
- return invoke(Cmd_ptr(new ZombieCmd(User::BLOCK, absNodePath,"","" )));
-}
-int ClientInvoker::zombieRemoveCli( const std::string& absNodePath ) const
-{
- if (testInterface_) return invoke(CtsApi::zombieRemoveCli(absNodePath));
- return invoke(Cmd_ptr(new ZombieCmd(User::REMOVE, absNodePath,"","" )));
-}
-int ClientInvoker::zombieKillCli( const std::string& absNodePath ) const
-{
- if (testInterface_) return invoke(CtsApi::zombieKillCli(absNodePath));
- return invoke(Cmd_ptr(new ZombieCmd(User::KILL, absNodePath,"","" )));
-}
-
-// ======================================================================================================
-
-int ClientInvoker::job_gen( const std::string& absNodePath ) const
-{
- if (testInterface_) return invoke(CtsApi::job_gen(absNodePath));
- return invoke(Cmd_ptr(new CtsNodeCmd( CtsNodeCmd::JOB_GEN, absNodePath)));
-}
-
-int ClientInvoker::edit_history( const std::string& path ) const
-{
- if (testInterface_) return invoke(CtsApi::edit_history(path));
- return invoke(Cmd_ptr(new PathsCmd( PathsCmd::EDIT_HISTORY, path)));
-}
-int ClientInvoker::kill( const std::vector<std::string>& paths ) const
-{
- if (testInterface_) return invoke(CtsApi::kill(paths));
- return invoke(Cmd_ptr(new PathsCmd( PathsCmd::KILL, paths)));
-}
-int ClientInvoker::kill( const std::string& absNodePath ) const
-{
- if (testInterface_) return invoke(CtsApi::kill(absNodePath));
- return invoke(Cmd_ptr(new PathsCmd( PathsCmd::KILL, absNodePath)));
-}
-int ClientInvoker::status( const std::vector<std::string>& paths ) const
-{
- if (testInterface_) return invoke(CtsApi::status(paths));
- return invoke(Cmd_ptr(new PathsCmd( PathsCmd::STATUS, paths)));
-}
-int ClientInvoker::status( const std::string& absNodePath ) const
-{
- if (testInterface_) return invoke(CtsApi::status(absNodePath));
- return invoke(Cmd_ptr(new PathsCmd( PathsCmd::STATUS, absNodePath)));
-}
-int ClientInvoker::suspend( const std::vector<std::string>& paths ) const
-{
- if (testInterface_) return invoke(CtsApi::suspend(paths));
- return invoke(Cmd_ptr(new PathsCmd( PathsCmd::SUSPEND, paths)));
-}
-int ClientInvoker::suspend( const std::string& absNodePath ) const
-{
- if (testInterface_) return invoke(CtsApi::suspend(absNodePath));
- return invoke(Cmd_ptr(new PathsCmd( PathsCmd::SUSPEND, absNodePath)));
-}
-int ClientInvoker::resume( const std::vector<std::string>& paths ) const
-{
- if (testInterface_) return invoke(CtsApi::resume(paths));
- return invoke(Cmd_ptr(new PathsCmd( PathsCmd::RESUME, paths)));
-}
-int ClientInvoker::resume( const std::string& absNodePath ) const
-{
- if (testInterface_) return invoke(CtsApi::resume(absNodePath));
- return invoke(Cmd_ptr(new PathsCmd( PathsCmd::RESUME, absNodePath)));
-}
-int ClientInvoker::check( const std::vector<std::string>& paths ) const
-{
- if (testInterface_) return invoke(CtsApi::check(paths));
- return invoke(Cmd_ptr(new PathsCmd( PathsCmd::CHECK, paths)));
-}
-int ClientInvoker::check( const std::string& absNodePath ) const
-{
- if (testInterface_) return invoke(CtsApi::check(absNodePath));
- return invoke(Cmd_ptr(new PathsCmd( PathsCmd::CHECK, absNodePath)));
-}
-int ClientInvoker::delete_nodes( const std::vector<std::string>& paths, bool force ) const
-{
- if (testInterface_) return invoke(CtsApi::delete_node(paths, force, true/*auto_confirm*/));
- return invoke(Cmd_ptr(new PathsCmd( PathsCmd::DELETE, paths,force)));
-}
-int ClientInvoker::delete_node( const std::string& absNodePath, bool force ) const
-{
- if (testInterface_) return invoke(CtsApi::delete_node(absNodePath, force, true/*auto_confirm*/));
- return invoke(Cmd_ptr(new PathsCmd( PathsCmd::DELETE, absNodePath,force)));
-}
-int ClientInvoker::delete_all( bool force) const
-{
- if (testInterface_) return invoke(CtsApi::delete_node(std::vector<std::string>(),force));
- return invoke(Cmd_ptr(new PathsCmd( PathsCmd::DELETE, std::vector<std::string>(),force)));
-}
-
-// ======================================================================================================
-
-int ClientInvoker::replace( const std::string& absNodePath, const std::string& path_to_client_defs,
- bool create_parents_as_required, bool force) const
-{
- if (testInterface_) return invoke(CtsApi::replace(absNodePath, path_to_client_defs, create_parents_as_required, force));
-
- /// *Note* server_reply_.client_handle_ is kept until the next call to register_client_handle
- /// The client invoker can be used multiple times, hence keep value of defs, and client handle in server reply
- server_reply_.clear_for_invoke(cli_);
-
- /// Handle command constructors that can throw
- Cmd_ptr cts_cmd;
- try {
-
- ReplaceNodeCmd* replace_cmd = new ReplaceNodeCmd( absNodePath, create_parents_as_required, path_to_client_defs, force);
-
- // For test allow the defs environment to changed, i.e. allow us to inject ECF_CLIENT ???
- replace_cmd->theDefs()->set_server().add_or_update_user_variables( clientEnv_.env() );
-
- cts_cmd = Cmd_ptr( replace_cmd );
- }
- catch (std::exception& e ){
- std::stringstream ss; ss << "ecflow:ClientInvoker::replace(" << absNodePath << "," << path_to_client_defs << ", ...) failed: " << e.what();
- server_reply_.set_error_msg( ss.str() );
- if (on_error_throw_exception_) throw std::runtime_error( server_reply_.error_msg() );
- return 1;
- }
-
- return invoke( cts_cmd );
-}
-
-int ClientInvoker::replace_1(const std::string& absNodePath, defs_ptr client_defs, bool create_parents_as_required, bool force) const
-{
- /// *Note* server_reply_.client_handle_ is kept until the next call to register_client_handle
- /// The client invoker can be used multiple times, hence keep value of defs, and client handle in server reply
- server_reply_.clear_for_invoke(cli_);
-
- /// Handle command constructors that can throw
- Cmd_ptr cts_cmd;
- try {
- cts_cmd = Cmd_ptr( new ReplaceNodeCmd( absNodePath, create_parents_as_required, client_defs, force) );
- }
- catch (std::exception& e ){
- std::stringstream ss; ss << "ecflow:ClientInvoker::replace_1(" << absNodePath << " ...) failed: " << e.what();
- server_reply_.set_error_msg( ss.str() );
- if (on_error_throw_exception_) throw std::runtime_error( server_reply_.error_msg() );
- return 1;
- }
-
- return invoke( cts_cmd );
-}
-
-int ClientInvoker::requeue( const std::vector<std::string>& paths, const std::string& option ) const
-{
- if (testInterface_) return invoke(CtsApi::requeue(paths, option));
-
- RequeueNodeCmd::Option the_option = RequeueNodeCmd::NO_OPTION;
- if (!option.empty()) {
- if (option == "abort") the_option = RequeueNodeCmd::ABORT;
- else if (option == "force") the_option = RequeueNodeCmd::FORCE;
- else {
- server_reply_.set_error_msg("ecflow:ClientInvoker::requeue: Expected option = [ force | abort ]");
- if (on_error_throw_exception_) {
- throw std::runtime_error(server_reply_.error_msg());
- }
- return 1;
- }
- }
- return invoke(Cmd_ptr(new RequeueNodeCmd(paths, the_option)));
-}
-int ClientInvoker::requeue( const std::string& absNodePath, const std::string& option) const
-{
- if (testInterface_) return invoke(CtsApi::requeue(absNodePath, option));
-
- RequeueNodeCmd::Option the_option = RequeueNodeCmd::NO_OPTION;
- if (!option.empty()) {
- if (option == "abort") the_option = RequeueNodeCmd::ABORT;
- else if (option == "force") the_option = RequeueNodeCmd::FORCE;
- else {
- server_reply_.set_error_msg("ecflow:ClientInvoker::requeue: Expected option = [ force | abort ]");
- if (on_error_throw_exception_) throw std::runtime_error(server_reply_.error_msg());
- return 1;
- }
- }
- return invoke(Cmd_ptr(new RequeueNodeCmd(absNodePath, the_option)));
-}
-
-int ClientInvoker::run( const std::vector<std::string>& paths, bool force ) const
-{
- if (testInterface_) return invoke(CtsApi::run(paths, force));
- return invoke(Cmd_ptr(new RunNodeCmd(paths, force)));
-}
-int ClientInvoker::run( const std::string& absNodePath, bool force ) const
-{
- if (testInterface_) return invoke(CtsApi::run(absNodePath, force));
- return invoke(Cmd_ptr(new RunNodeCmd(absNodePath, force)));
-}
-int ClientInvoker::order( const std::string& absNodePath, const std::string& order ) const
-{
- if (testInterface_) return invoke(CtsApi::order(absNodePath, order));
-
- if (!NOrder::isValid(order)) {
- server_reply_.set_error_msg("ecflow:ClientInvoker::order: please specify one of [ top, bottom, alpha, order, up, down ]\n");
- if (on_error_throw_exception_) throw std::runtime_error(server_reply_.error_msg());
- return 1;
- }
- return invoke(Cmd_ptr(new OrderNodeCmd(absNodePath, NOrder::toOrder(order))));
-}
-int ClientInvoker::order(const std::string& absNodePath,NOrder::Order order) const
-{
- return invoke(Cmd_ptr(new OrderNodeCmd(absNodePath, order)));
-}
-
-// ======================================================================================================
-
-int ClientInvoker::checkPtDefs(ecf::CheckPt::Mode m,int check_pt_interval,int check_pt_save_time_alarm) const
-{
- if (testInterface_) return invoke(CtsApi::checkPtDefs(m, check_pt_interval, check_pt_save_time_alarm));
- return invoke(Cmd_ptr(new CheckPtCmd(m,check_pt_interval,check_pt_save_time_alarm)));
-}
-int ClientInvoker::restoreDefsFromCheckPt() const
-{
- if (testInterface_) return invoke(CtsApi::restoreDefsFromCheckPt());
- return invoke(Cmd_ptr(new CtsCmd( CtsCmd::RESTORE_DEFS_FROM_CHECKPT )));
-}
-
-int ClientInvoker::force( const std::string& absNodePath, const std::string& state_or_event,bool recursive, bool set_repeats_to_last_value ) const
-{
- if (testInterface_) return invoke(CtsApi::force(absNodePath, state_or_event, recursive, set_repeats_to_last_value));
- return invoke(Cmd_ptr(new ForceCmd(absNodePath, state_or_event, recursive, set_repeats_to_last_value )));
-}
-int ClientInvoker::force( const std::vector<std::string>& paths, const std::string& state_or_event,bool recursive, bool set_repeats_to_last_value) const
-{
- if (testInterface_) return invoke(CtsApi::force(paths, state_or_event, recursive, set_repeats_to_last_value));
- return invoke(Cmd_ptr(new ForceCmd(paths, state_or_event, recursive, set_repeats_to_last_value )));
-}
-
-int ClientInvoker::freeDep( const std::vector<std::string>& paths, bool trigger,bool all, bool date, bool the_time ) const
-{
- if (testInterface_) return invoke(CtsApi::freeDep(paths, trigger, all, date, the_time));
- return invoke(Cmd_ptr(new FreeDepCmd(paths, trigger, all, date , the_time)));
-}
-int ClientInvoker::freeDep( const std::string& absNodePath, bool trigger, bool all,bool date, bool the_time ) const
-{
- if (testInterface_) return invoke(CtsApi::freeDep(absNodePath, trigger, all, date, the_time));
- return invoke(Cmd_ptr(new FreeDepCmd(absNodePath, trigger, all, date , the_time)));
-}
-
-int ClientInvoker::file( const std::string& absNodePath, const std::string& fileType, const std::string& max_lines ) const
-{
- if (testInterface_) return invoke(CtsApi::file(absNodePath, fileType, max_lines));
-
- /// Handle command constructors that can throw
- Cmd_ptr cts_cmd;
- try {
- cts_cmd = Cmd_ptr( new CFileCmd(absNodePath, fileType, max_lines));
- }
- catch (std::exception& e ){
- std::stringstream ss; ss << "ecflow:ClientInvoker::file(" << absNodePath << "," << fileType << "," << max_lines << ") failed:\n" << e.what();
- server_reply_.set_error_msg( ss.str() );
- if (on_error_throw_exception_) {
- throw std::runtime_error( server_reply_.error_msg() );
- }
- return 1;
- }
-
- return invoke( cts_cmd );
-}
-
-int ClientInvoker::plug( const std::string& sourcePath, const std::string& destPath ) const
-{
- if (testInterface_) return invoke(CtsApi::plug(sourcePath, destPath));
- return invoke(Cmd_ptr(new PlugCmd(sourcePath, destPath)));
-}
-
-// ======================================================================================================
-
-int ClientInvoker::reloadwsfile() const
-{
- if (testInterface_) return invoke(CtsApi::reloadwsfile());
- return invoke(Cmd_ptr(new CtsCmd( CtsCmd::RELOAD_WHITE_LIST_FILE )));
-}
-int ClientInvoker::group( const std::string& groupRequest ) const
-{
- if (testInterface_) return invoke(CtsApi::group(groupRequest));
- return invoke(Cmd_ptr(new GroupCTSCmd(groupRequest,&clientEnv_)));
-}
-
-int ClientInvoker::logMsg( const std::string& msg ) const
-{
- if (testInterface_) return invoke(CtsApi::logMsg(msg));
- return invoke(Cmd_ptr(new LogMessageCmd( msg )));
-}
-int ClientInvoker::new_log( const std::string& new_path) const
-{
- if (testInterface_) return invoke(CtsApi::new_log(new_path));
-
- /// Handle command constructors that can throw
- Cmd_ptr cts_cmd;
- try {
- cts_cmd = Cmd_ptr(new LogCmd( new_path ));
- }
- catch (std::exception& e ){
- server_reply_.set_error_msg( e.what() );
- if (on_error_throw_exception_) throw std::runtime_error( server_reply_.error_msg() );
- return 1;
- }
- return invoke(cts_cmd);
-}
-int ClientInvoker::getLog( int lastLines) const
-{
- if (lastLines == 0) lastLines = Log::get_last_n_lines_default();
- if (testInterface_) return invoke(CtsApi::getLog(lastLines));
- return invoke(Cmd_ptr(new LogCmd( LogCmd::GET, lastLines )));
-}
-int ClientInvoker::clearLog() const
-{
- if (testInterface_) return invoke(CtsApi::clearLog());
- return invoke(Cmd_ptr(new LogCmd( LogCmd::CLEAR )));
-}
-int ClientInvoker::flushLog() const
-{
- if (testInterface_) return invoke(CtsApi::flushLog());
- return invoke(Cmd_ptr(new LogCmd( LogCmd::FLUSH )));
-}
-int ClientInvoker::get_log_path() const
-{
- if (testInterface_) return invoke(CtsApi::get_log_path());
- return invoke(Cmd_ptr(new LogCmd( LogCmd::PATH )));
-}
-
-int ClientInvoker::forceDependencyEval() const
-{
- return invoke(CtsApi::forceDependencyEval());
-}
-
-// ======================================================================================================
-
-int ClientInvoker::edit_script_edit(const std::string& path_to_task)
-{
- return invoke(Cmd_ptr( new EditScriptCmd( path_to_task, EditScriptCmd::EDIT) ) );
-}
-
-int ClientInvoker::edit_script_preprocess(const std::string& path_to_task)
-{
- return invoke(Cmd_ptr( new EditScriptCmd( path_to_task, EditScriptCmd::PREPROCESS) ) );
-}
-
-int ClientInvoker::edit_script_preprocess(const std::string& path_to_task,const std::vector<std::string>& file_contents)
-{
- return invoke(Cmd_ptr( new EditScriptCmd( path_to_task,file_contents) ) );
-}
-
-int ClientInvoker::edit_script_submit(const std::string& path_to_task,const NameValueVec& used_variables)
-{
- return invoke(Cmd_ptr( new EditScriptCmd( path_to_task,used_variables) ) );
-}
-
-int ClientInvoker::edit_script_submit(
- const std::string& path_to_task,
- const NameValueVec& used_variables,
- const std::vector<std::string>& file_contents,
- bool create_alias,
- bool run_alias)
-{
- return invoke(Cmd_ptr( new EditScriptCmd( path_to_task,used_variables,file_contents,create_alias,run_alias) ) );
-}
-
-std::string ClientInvoker::client_env_host_port() const
-{
- std::string host_port = clientEnv_.host();
- host_port += Str::COLON();
- host_port += clientEnv_.port();
- return host_port;
-}
-
-std::string ClientInvoker::find_free_port(int seed_port_number, bool debug)
-{
- // Ping failed, We need to distinguish between:
- // a/ Server does not exist : <FREE> port
- // b/ Address in use : <BUSY> port on existing server
- // Using server_version() but then get error messages
- // ******** Until this is done we can't implement port hopping **********
-
- if (debug) cout << "ClientInvoker::find_free_port: starting with port " << seed_port_number << "\n";
- int the_port = seed_port_number;
- std::string free_port;
- ClientInvoker client;
- client.set_retry_connection_period(1); // avoid long wait
- client.set_connection_attempts(1); // avoid long wait
- while (1) {
- free_port = boost::lexical_cast<std::string>(the_port);
- try {
- if (debug) cout << " Trying to connect to server on '" << Str::LOCALHOST() << ":" << free_port << "'\n";
- client.set_host_port(Str::LOCALHOST(),free_port);
- client.pingServer();
- if (debug) cout << " Connected to server on port " << free_port << " trying next port\n";
- the_port++;
- }
- catch ( std::runtime_error& e) {
- std::string error_msg = e.what();
- if (debug) cout << " " << e.what();
- if (error_msg.find("authentication failed") != std::string::npos) {
- if (debug) cout << " Could not connect, due to authentication failure, hence port " << the_port << " is used,trying next port\n";
- the_port++;
- continue;
- }
- else {
- if (debug) cout << " Found free port " << free_port << "\n";
- break;
- }
- }
- }
- return free_port;
-}
-
-bool ClientInvoker::wait_for_server_reply(int time_out) const
-{
- DurationTimer timer;
- while(1) {
- sleep(2);
-
- if (on_error_throw_exception_) {
- try {
- pingServer(); // will throw exception
- return true; // no exception, server lives
- }
- catch( ... ) {}
- }
- else {
- if (pingServer() == 0) {
- return true; // ping OK,
- }
- }
- if (timer.duration() > time_out) {
- return false;
- }
- }
- return false;
-}
-
-bool ClientInvoker::wait_for_server_death(int time_out) const
-{
- DurationTimer timer;
- while(1) {
-
- if (on_error_throw_exception_) {
- try {
- pingServer(); // will throw exception
- }
- catch( ... ) {
- // server died
- return true;
- }
- }
- else {
- if (pingServer() == 1) {
- return true; // ping failed, server has died,
- }
- }
- if (timer.duration() > time_out) {
- return false; // server still lives
- }
-
- // Ping ok, server lives, continue pinging, until timeout
- sleep(2);
- }
- return false;
-}
-
-
-int ClientInvoker::load_in_memory_defs( const defs_ptr& clientDefs, bool force) const
-{
- /// *Note* server_reply_.client_handle_ is kept until the next call to register_client_handle
- /// The client invoker can be used multiple times, hence keep value of defs, and client handle in server reply
- server_reply_.clear_for_invoke(cli_);
-
- if ( !clientDefs.get() ) {
- server_reply_.set_error_msg("The client definition is empty.");
- if (on_error_throw_exception_) throw std::runtime_error(server_reply_.error_msg());
- return 1;
- }
-
- // Client defs has been created in memory.
- // warn about naff expression and unresolved in-limit references to Limit's
- // Don't allow defs to be loaded into server, with trigger parser errors.
- std::string warningMsg;
- if (!clientDefs->check(server_reply_.get_error_msg(), warningMsg)) {
- if (on_error_throw_exception_) throw std::runtime_error(server_reply_.error_msg());
- return 1;
- }
-
- return invoke( Cmd_ptr( new LoadDefsCmd( clientDefs, force /*force overwrite suite of same name*/) ) );
-}
-
-
-// ==========================================================================
-// Python child support
-// ==========================================================================
-void ClientInvoker::set_child_path(const std::string& path)
-{
- child_task_path_ = path;
-}
-void ClientInvoker::set_child_password(const std::string& pass)
-{
- child_task_password_ = pass;
-}
-void ClientInvoker::set_child_pid(const std::string& pid)
-{
- child_task_pid_ = pid;
-}
-void ClientInvoker::set_child_try_no(unsigned int try_no)
-{
- child_task_try_no_ = try_no;
-}
-void ClientInvoker::set_child_timeout(unsigned int seconds )
-{
- clientEnv_.set_child_cmd_timeout(seconds);
-}
-
-
-void ClientInvoker::check_child_parameters() const
-{
- if (clientEnv_.debug()) {
- std::cout << " child_task_path_ = '" << child_task_path_ << "'\n";
- std::cout << " child_task_password_ = '" << child_task_password_ << "'\n";
- std::cout << " child_task_pid_ = '" << child_task_pid_ << "'\n";
- std::cout << " child_task_try_no_ = " << child_task_try_no_ << "\n";
- }
- if (child_task_path_.empty()) throw std::runtime_error("Child Path not set");
- if (child_task_password_.empty()) throw std::runtime_error("Child password not set");
- if (child_task_pid_.empty()) throw std::runtime_error("Child pid not set");
- if (child_task_try_no_ == 0) throw std::runtime_error("Child try_no not set");
-}
-
-void ClientInvoker::child_init()
-{
- check_child_parameters();
- on_error_throw_exception_ = true; // for python always throw exception
- invoke( Cmd_ptr( new InitCmd(child_task_path_, child_task_password_, child_task_pid_, child_task_try_no_ ) ) );
-}
-
-void ClientInvoker::child_abort(const std::string& reason )
-{
- check_child_parameters();
- on_error_throw_exception_ = true; // for python always throw exception
- invoke( Cmd_ptr( new AbortCmd(child_task_path_, child_task_password_, child_task_pid_, child_task_try_no_,reason ) ) );
-}
-
-void ClientInvoker::child_event(const std::string& event_name_or_number)
-{
- check_child_parameters();
- on_error_throw_exception_ = true; // for python always throw exception
- invoke( Cmd_ptr( new EventCmd(child_task_path_, child_task_password_, child_task_pid_, child_task_try_no_,event_name_or_number ) ) );
-}
-
-void ClientInvoker::child_meter(const std::string& meter_name, int meter_value)
-{
- if (meter_name.empty()) throw std::runtime_error("Meter name not set");
- check_child_parameters();
- on_error_throw_exception_ = true; // for python always throw exception
- invoke( Cmd_ptr( new MeterCmd(child_task_path_, child_task_password_, child_task_pid_, child_task_try_no_,meter_name,meter_value ) ) );
-}
-
-void ClientInvoker::child_label(const std::string& label_name, const std::string& label_value)
-{
- if (label_name.empty()) throw std::runtime_error("Label name not set");
- check_child_parameters();
- on_error_throw_exception_ = true; // for python always throw exception
- invoke( Cmd_ptr( new LabelCmd(child_task_path_, child_task_password_, child_task_pid_, child_task_try_no_,label_name,label_value ) ) );
-}
-
-void ClientInvoker::child_wait(const std::string& expression)
-{
- check_child_parameters();
- on_error_throw_exception_ = true; // for python always throw exception
- invoke( Cmd_ptr( new CtsWaitCmd(child_task_path_, child_task_password_, child_task_pid_, child_task_try_no_, expression ) ) );
-}
-
-void ClientInvoker::child_complete()
-{
- check_child_parameters();
- on_error_throw_exception_ = true; // for python always throw exception
- invoke( Cmd_ptr( new CompleteCmd(child_task_path_, child_task_password_, child_task_pid_, child_task_try_no_ ) ) );
-}
-
-// ==========================================================================
-// class RequestLogger:
-// ==========================================================================
-RequestLogger::RequestLogger(const ClientInvoker* ci) : ci_(ci){}
-RequestLogger::~RequestLogger() {
-
- // *assumes* destructor of RoundTripRecorder was invoked first, to allow recording of the time rtt_
- if (cmd_.get()) {
- if (ci_->clientEnv_.debug() && ci_->server_reply_.error_msg().empty()) {
- cout << "ClientInvoker "; cmd_->print(cout); cout << " SUCCEDED " << to_simple_string(ci_->rtt_) << "\n";
- }
-
- if (Rtt::instance()) {
- std::stringstream ss;
- ss << ci_->client_env_host_port() << " ";
- cmd_->print(ss);
- ss << " " << Rtt::tag() << to_simple_string(ci_->rtt_); // Note: endl added rtt(..)
- ss << " : " << ci_->server_reply_.error_msg();
- rtt(ss.str());
- }
-
- if (ci_->cli_ && cmd_->ping_cmd() && ci_->server_reply_.error_msg().empty()) {
- cout << "ping server(" << ci_->client_env_host_port() << ") succeeded in " << to_simple_string(ci_->rtt_) << " ~" << ci_->rtt_.total_milliseconds() << " milliseconds\n";
- }
- }
-}
-
-// ==========================================================================
-// class RoundTripRecorder:
-// ==========================================================================
-RoundTripRecorder::RoundTripRecorder(const ClientInvoker* ci)
-: ci_(ci)
-{
- // get the current time from the clock -- one second resolution
- ci_->start_time_ = microsec_clock::universal_time();
- ci_->rtt_ = boost::posix_time::time_duration();
-}
-
-RoundTripRecorder::~RoundTripRecorder() {
- ci_->rtt_ = microsec_clock::universal_time() - ci_->start_time_;
-}
diff --git a/ecflow_4_0_7/Client/src/ClientInvoker.hpp b/ecflow_4_0_7/Client/src/ClientInvoker.hpp
deleted file mode 100644
index 802f802..0000000
--- a/ecflow_4_0_7/Client/src/ClientInvoker.hpp
+++ /dev/null
@@ -1,365 +0,0 @@
-#ifndef CLIENT_INVOKER_HPP_
-#define CLIENT_INVOKER_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/noncopyable.hpp>
-#include <boost/shared_ptr.hpp>
-#include "boost/date_time/posix_time/posix_time_types.hpp"
-
-#include "ClientEnvironment.hpp"
-#include "ClientOptions.hpp"
-#include "Cmd.hpp"
-#include "CtsApi.hpp"
-#include "TaskApi.hpp"
-#include "NodeFwd.hpp"
-#include "ServerReply.hpp"
-#include "Zombie.hpp"
-#include "NOrder.hpp"
-
-/// Invokes the client depending on the arguments
-/// This has been separated from main, to allow us to invoke the client
-/// from a test suite.
-/// Important: We can make *many* calls with the same ClientInvoker.
-/// This is more efficient than creating a ClientInvoker for each request
-class ClientInvoker : private boost::noncopyable {
-public:
- /// Will create the *ClientEnvironment* once on construction
- /// By default will throw exception std::runtime_error for errors
- ClientInvoker();
- ClientInvoker(const std::string& host_port);
- ClientInvoker(const std::string& host, const std::string& port);
- ClientInvoker(const std::string& host, int port);
-
- /// if throw_exception_on_error = false, then
- /// invoke() will return 0 for success and 1 for error.
- /// The error message can be retrieved from errorMsg()
- /// if throw_exception_on_error = true,
- /// then invoke() for errors will throw std::runtime_error
- /// will still return 0 for success.
- void set_throw_on_error(bool f) { on_error_throw_exception_ = f;}
-
- /// Return the time it takes to contact server and get a reply.
- const boost::posix_time::time_duration& round_trip_time() const { return rtt_;}
-
- /// Configure to using command line interface
- /// This affect commands like ping, log & file, so that, output is written to standard out
- void set_cli(bool f) { cli_ = f; }
-
- /// This will override the environment setting.
- /// In particular setting host explicitly will avoid cycling through server list,
- /// if connection fails. hence will bomb out earlier
- /// If applied to child command's will continue attempting this host/port until timeout
- void set_host_port(const std::string& h, const std::string& p);
- const std::string& host() const;
- const std::string& port() const;
-
- /// Whenever there is a connections failure we wait a number of seconds
- /// before trying again. ( i.e. to get round glitches in the network.)
- /// For the ping command this is set as 1 second
- /// This wait between connection attempts can be configured here.
- /// i.e for the GUI & python interface this can be reduced to increase responsiveness.
- /// Default: In debug this period in set to 1 second and in release mode 10 seconds
- void set_retry_connection_period(unsigned int period) { retry_connection_period_ = period; }
-
- /// Set the number of times to connect to server, in case of failure
- /// The period between connection attempts is handled by set_retry_connection_period
- /// i.e for the GUI & python interface this can be reduced to increase responsiveness.
- /// Default value is set as 2. Setting a value less than 1 is ignored, will default to 1 in this case
- void set_connection_attempts( unsigned int attempts);
-
- /// returns 1 on error and 0 on success. The errorMsg can be accessed via errorMsg()
- /// Will attempt to connect to the server a number of times. If this fails it will
- /// try the next server, and so on until a timeout period is reached.
- int invoke( int argc, char* argv[]) const;
-
- // support for forward compatibility, by changing boost archive version
- // Chosen to change client side only
- void allow_new_client_old_server(int archive_version_of_old_server);
- int allow_new_client_old_server() const;
-
- /// If testing, overwrite the task path set in the environment, required for
- /// testing the task based commands.
- /// By allowing environment to be changed, we allow smsinit,smscomplete, etc to be replaced
- /// with ECF_CLIENT path executable
- /// The following functions are only used for testing purposes.
- /// Override task paths,env' & job creation at begin time
- void taskPath(const std::string& s);
- void set_jobs_password(const std::string&);
- void setEnv( const std::vector<std::pair<std::string,std::string> >& e);
- void testInterface(); // allow cmd construction to be aware thats it under test
- const std::string& process_or_remote_id() const;
-
- /// record each request its arguments and the round trip time to and from server
- /// If the file can not opened for create/append then an runtime error exception is thrown
- void enable_logging(const std::string& log_file_name);
- void disable_logging();
-
- /// The timeout feature allow the client to fail gracefully in the case
- /// where the server has died/crashed. The timeout will ensure the socket is closed.
- /// allowing the server to be restarted without getting the address is use error.
- /// Set the timeout for each client->server communication:
- // connect : timeout_ second
- // send request : timeout_ second
- // receive reply : timeout_ second
- // default is 0 second, which means take the timeout from the command/request
- // used for test only
- void set_connect_timeout(int t);
-
- /// ServerReply Holds the reply from the server
- void reset(); // will clear local client definition and handle
- const ServerReply& server_reply() const { return server_reply_;}
- defs_ptr defs() const { return server_reply_.client_defs(); }
- const std::string& get_string() const { return server_reply_.get_string(); }
- bool in_sync() const { return server_reply_.in_sync();}
- bool get_news() const { return (server_reply_.get_news() != ServerReply::NO_NEWS); }
- int client_handle() const { return server_reply_.client_handle(); }
-
- /// If invoke returns 1, the error message can be retrieved with this function
- const std::string& errorMsg() const { return server_reply_.error_msg();}
-
- // ***************************************************************************
- // Task/child based api. Only added here for test.
- // Relies on environment for the other args
- int initTask(const std::string& process_id)const
- { return invoke(TaskApi::init(process_id)); }
- int abortTask(const std::string& reason_why = "") const
- { return invoke(TaskApi::abort(reason_why)); }
- int eventTask(const std::string& eventName) const
- { return invoke(TaskApi::event(eventName)); }
- int meterTask(const std::string& meterName, const std::string& new_meter_value) const
- { return invoke(TaskApi::meter(meterName,new_meter_value)); }
- int labelTask(const std::string& labelName, const std::vector<std::string>& labels) const
- { return invoke(TaskApi::label(labelName,labels)); }
- int waitTask(const std::string& on_expression) const
- { return invoke(TaskApi::wait(on_expression)); }
- int completeTask() const
- { return invoke(TaskApi::complete()); }
-
- // Support for python child commands, and python jobs
- void set_child_path(const std::string& path);
- void set_child_password(const std::string& pass);
- void set_child_pid(const std::string& pid);
- void set_child_try_no(unsigned int try_no);
- void set_child_timeout(unsigned int seconds ); // ECF_TIMEOUT default is 24 hours allow python jobs to override
- void child_init();
- void child_abort(const std::string& reason = "");
- void child_event(const std::string& event_name_or_number);
- void child_meter(const std::string& meter_name, int meter_value);
- void child_label(const std::string& label_name, const std::string& label_value);
- void child_wait(const std::string& on_expression);
- void child_complete();
-
- // ********************************************************************************
- // The client api. Mirrors CtsApi on the whole
- int getDefs() const;
- int loadDefs(const std::string& filePath,
- bool force = false, /* true means overwrite suite of same name */
- bool check_only = false /* true means don't send to server, just check only */
- ) const;
- int load( const defs_ptr& defs, bool force = false /*true means overwrite suite of same name*/) const
- { return load_in_memory_defs(defs,force); }
- int sync(defs_ptr& client_defs) const;
- int sync_local() const;
- int news(defs_ptr& client_defs) const;
- int news_local() const;
-
- // find free port on local host. Not 100% accurate, use in test
- static std::string find_free_port(int seed_port_number, bool debug = false);
-
- bool wait_for_server_reply(int time_out = 60) const; // wait for server reply, returning false means timed out.
- bool wait_for_server_death(int time_out = 60) const; // wait for server reply, returning true means server died,false means timed out.
- int restartServer() const;
- int haltServer() const;
- int shutdownServer() const ;
- int terminateServer() const;
- int pingServer() const;
- int server_load(const std::string& path_to_log_file = "") const { return invoke(CtsApi::server_load(path_to_log_file)); }
- int debug_server_on() const;
- int debug_server_off() const;
- int stats() const;
- int stats_reset() const;
- int server_version() const;
-
- int suites() const;
- int ch_register( bool auto_add_new_suites, const std::vector<std::string>& suites) const;
- int ch_suites() const;
- int ch_drop(int client_handle) const;
- int ch_drop_user(const std::string& user = "") const;
- int ch_add(int client_handle, const std::vector<std::string>& suites) const;
- int ch_remove(int client_handle, const std::vector<std::string>& suites) const;
- int ch_auto_add(int client_handle, bool auto_add_new_suites) const;
- int ch1_drop() const;
- int ch1_add(const std::vector<std::string>& suites) const;
- int ch1_remove(const std::vector<std::string>& suites) const;
- int ch1_auto_add(bool auto_add_new_suites) const;
-
- int begin(const std::string& suiteName,bool force = false) const;
- int begin_all_suites(bool force = false) const;
-
- int zombieGet() const;
- int zombieFob(const Zombie& z) const;
- int zombieFail(const Zombie& z) const;
- int zombieAdopt(const Zombie& z) const;
- int zombieBlock(const Zombie& z) const;
- int zombieRemove(const Zombie& z) const;
- int zombieKill(const Zombie& z) const;
- int zombieFobCli(const std::string& absNodePath) const;
- int zombieFailCli(const std::string& absNodePath) const;
- int zombieAdoptCli(const std::string& absNodePath) const;
- int zombieBlockCli(const std::string& absNodePath) const;
- int zombieRemoveCli(const std::string& absNodePath) const;
- int zombieKillCli(const std::string& absNodePath) const;
-
- int job_gen(const std::string& absNodePath) const;
-
- int edit_history(const std::string& path) const;
- int kill(const std::vector<std::string>& paths) const;
- int kill(const std::string& absNodePath) const;
- int status(const std::vector<std::string>& paths) const;
- int status(const std::string& absNodePath) const;
- int suspend(const std::vector<std::string>& paths) const;
- int suspend(const std::string& absNodePath) const;
- int resume(const std::vector<std::string>& paths) const;
- int resume(const std::string& absNodePath) const;
- int check(const std::vector<std::string>& paths) const;
- int check(const std::string& absNodePath) const;
- int delete_nodes(const std::vector<std::string>& paths,bool force = false) const;
- int delete_node(const std::string& absNodePath,bool force = false) const;
- int delete_all(bool force = false) const;
-
- int replace( const std::string& absNodePath, const std::string& path_to_client_defs,
- bool create_parents_as_required = true, bool force = false) const;
- int replace_1( const std::string& absNodePath, defs_ptr client_defs, bool create_parents_as_required = true, bool force = false) const;
-
- int requeue(const std::vector<std::string>& paths,const std::string& option = "") const;
- int requeue(const std::string& absNodePath,const std::string& option = "") const;
- int run(const std::vector<std::string>& paths,bool force = false) const;
- int run(const std::string& absNodePath,bool force = false) const;
- int order(const std::string& absNodePath,const std::string& order) const; // slow
- int order(const std::string& absNodePath,NOrder::Order) const; // fast
-
- int checkPtDefs(ecf::CheckPt::Mode m = ecf::CheckPt::UNDEFINED, int check_pt_interval = 0, int check_pt_save_time_alarm = 0) const;
- int restoreDefsFromCheckPt() const;
-
- int force(const std::string& absNodePath,const std::string& state_or_event,bool recursive = false,bool set_repeats_to_last_value = false) const;
- int force(const std::vector<std::string>& paths,const std::string& state_or_event,bool recursive = false,bool set_repeats_to_last_value = false) const;
-
- int freeDep(const std::vector<std::string>& paths,bool trigger = true, bool all = false, bool date = false, bool time = false) const;
- int freeDep(const std::string& absNodePath,bool trigger = true, bool all = false, bool date = false, bool time = false) const;
-
- int file(const std::string& absNodePath, const std::string& fileType, const std::string& max_lines = "10000") const;
-
- int plug(const std::string& sourcePath, const std::string& destPath) const;
-
- int alter(const std::vector<std::string>& paths,
- const std::string& alterType, /* one of [ add | change | delete | set_flag | clear_flag ] */
- const std::string& attrType,
- const std::string& name = "",
- const std::string& value = "") const { return invoke(CtsApi::alter(paths,alterType,attrType,name,value)); }
- int alter(const std::string& path,
- const std::string& alterType, /* one of [ add | change | delete | set_flag | clear_flag ] */
- const std::string& attrType,
- const std::string& name = "",
- const std::string& value = "") const { return invoke(CtsApi::alter(path,alterType,attrType,name,value)); }
-
- int reloadwsfile() const;
- int group(const std::string& groupRequest) const;
-
- int logMsg(const std::string& msg) const;
- int new_log(const std::string& new_path = "") const;
- int getLog(int lastLines = 0) const;
- int clearLog() const;
- int flushLog() const;
- int get_log_path() const;
-
- int forceDependencyEval() const;
-
- /// The first is for use by CLI(Commend level interface), the other are for ecFlowview/Python
- int edit_script( const std::string& path_to_task,
- const std::string& edit_type,
- const std::string& path_to_script = "",
- bool create_alias = false,
- bool run = true)
- {return invoke(CtsApi::edit_script(path_to_task,edit_type,path_to_script,create_alias,run));}
- int edit_script_edit(const std::string& path_to_task); // ecFlowview EDIT
- int edit_script_preprocess(const std::string& path_to_task); // ecFlowview PRE_PROCESS
- int edit_script_submit(const std::string& path_to_task,const NameValueVec& used_variables ); // ecFlowview SUBMIT
- int edit_script_preprocess(const std::string& path_to_task,const std::vector<std::string>& file_contents); // ecFlowview PRE_PROCESS USER File
- int edit_script_submit(const std::string& path_to_task,
- const NameValueVec& used_variables,
- const std::vector<std::string>& file_contents,
- bool alias = false,
- bool run = true); // ecFlowview SUBMIT_FILE
-
-private:
- /// returns 1 on error and 0 on success. The errorMsg can be accessed via errorMsg()
- int invoke( const std::string& arg ) const;
- int invoke( const std::vector<std::string>& args ) const;
- int invoke(Cmd_ptr) const; // assumes clients of Cmd_ptr constructor has caught exceptions
-
- int do_invoke_cmd(Cmd_ptr) const;
- int load_in_memory_defs( const defs_ptr& clientDefs, bool force) const; /// For clients that want to load a in memory definition into the server.
- std::string client_env_host_port() const;
- void check_child_parameters() const;
-
-private:
- friend class RoundTripRecorder;
- friend class RequestLogger;
-private:
- bool on_error_throw_exception_;
- bool cli_; // Command Line Interface. Controls whether output written to standard out
- bool test_; // used in testing only
- bool testInterface_; // used in testing only
- unsigned int connection_attempts_; // No of attempts to establish connection with the server
- unsigned int retry_connection_period_; // No of seconds to wait before trying to connect in case of failure.
-
- std::string child_task_path_; // support for python child commands
- std::string child_task_password_; // support for python child commands
- std::string child_task_pid_; // support for python child commands
- int child_task_try_no_; // support for python child commands
-
- mutable boost::posix_time::time_duration rtt_;// record latency for each cmd.
- mutable boost::posix_time::ptime start_time_; // Used for time out and measuring latency
- mutable ClientEnvironment clientEnv_; // Will read the environment *once* on construction. Must be before Client options
- mutable ClientOptions args_; // Used for argument parsing & creating client request
- mutable ServerReply server_reply_; // stores the local defs, client_handle, & all server replies
-
- /// For use by python interface,
- std::vector<std::string>::const_iterator changed_node_paths_begin() const { return server_reply_.changed_nodes().begin();}
- std::vector<std::string>::const_iterator changed_node_paths_end() const { return server_reply_.changed_nodes().end();}
- friend void export_Client();
-};
-
-// Allow logging and debug output of request round trip times
-class RequestLogger : private boost::noncopyable {
-public:
- RequestLogger(const ClientInvoker* ci);
- ~RequestLogger();
- void set_cts_cmd(Cmd_ptr cmd) { cmd_ = cmd;}
-private:
- const ClientInvoker* ci_;
- Cmd_ptr cmd_;
-};
-
-class RoundTripRecorder : private boost::noncopyable {
-public:
- RoundTripRecorder(const ClientInvoker* ci);
- ~RoundTripRecorder();
-private:
- const ClientInvoker* ci_;
-};
-
-#endif
diff --git a/ecflow_4_0_7/Client/src/ClientMain.cpp b/ecflow_4_0_7/Client/src/ClientMain.cpp
deleted file mode 100644
index b1c2f85..0000000
--- a/ecflow_4_0_7/Client/src/ClientMain.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-//============================================================================
-// Name : ClientMain
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include "ClientInvoker.hpp"
-#include <iostream>
-
-int main( int argc, char* argv[] ) {
-
- /// By default, error condition will throw exception.
- try {
- ClientInvoker client;
- client.set_cli(true); // output log and file commands to standard out
- (void) client.invoke(argc,argv);
- }
- catch (std::exception& e ) {
- std::cerr << e.what() << std::endl;
- return 1;
- }
- return 0;
-}
diff --git a/ecflow_4_0_7/Client/src/ClientOptions.cpp b/ecflow_4_0_7/Client/src/ClientOptions.cpp
deleted file mode 100644
index 008e604..0000000
--- a/ecflow_4_0_7/Client/src/ClientOptions.cpp
+++ /dev/null
@@ -1,328 +0,0 @@
-//============================================================================
-// Name : ClientOptions
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Delegates argument parsing to the registered commands
-//============================================================================
-#include <boost/lexical_cast.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/bind.hpp>
-#include <iostream>
-#include <iomanip>
-
-#include "ClientOptions.hpp"
-#include "ClientEnvironment.hpp"
-#include "Version.hpp"
-#include "Str.hpp"
-#include "Ecf.hpp"
-#include "Child.hpp"
-#include "TaskApi.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost;
-namespace po = boost::program_options;
-
-static const char* client_env_description();
-static const char* client_task_env_description();
-
-
-ClientOptions::ClientOptions()
-{
- // This could have been moved to parse(). However since the same ClienttInvoker can be
- // be used for multiple commands. We have separated out the parts the need only be done once.
- // hence improving the performance:
- std::string title_help = "Client options, ";
- title_help += Version::description();
- title_help += " ";
- desc_ = new po::options_description( title_help , po::options_description::m_default_line_length + 80 );
-
- // This will iterate over all the registered client to server commands and
- // Each command will add to the option description, its required arguments
- cmdRegistry_.addAllOptions(*desc_);
-
- // Allow the host,port and rid to be overridden by the command line
- // This allows the jobs, which make other calls to ecflow_client from interfering with each other
- desc_->add_options()("rid",po::value< string >()->implicit_value( string("") ),
- "rid: If specified will override the environment variable ECF_RID, Can only be used for child commands");
- desc_->add_options()("port",po::value< string >()->implicit_value( string("") ),
- "port: If specified will override the environment variable ECF_PORT and default port number of 3141");
- desc_->add_options()("host",po::value< string >()->implicit_value( string("") ),
- "host: If specified will override the environment variable ECF_NODE and default host, localhost");
-}
-
-ClientOptions::~ClientOptions()
-{
- delete desc_;
-}
-
-Cmd_ptr ClientOptions::parse(int argc, char* argv[],ClientEnvironment* env) const
-{
- if (env->debug()) {
- cout << "ClientOptions::parse argc=" << argc;
- for(int i = 0; i < argc; i++) { cout << " arg" << i << "=" << argv[i];}
- cout << "\n";
- std::cout << "help column width = " << po::options_description::m_default_line_length + 80 << "\n";
- }
-
- // parse arguments into 'vm'.
- // Note: negative numbers get treated as options: i.e trying to change meter value to a negative number
- // --alter=/s1 change meter name -1
- // To avoid negative numbers from being treated as option use, we need to change command line style:
- // po::command_line_style::unix_style ^ po::command_line_style::allow_short
- boost::program_options::variables_map vm;
- po::store( po::parse_command_line( argc, argv, *desc_ ,po::command_line_style::unix_style ^ po::command_line_style::allow_short), vm );
- po::notify( vm );
-
-
- // Check to see if host or port, specified. This will override the environment variables
- std::string host,port;
- if ( vm.count( "port" ) ) {
- port = vm[ "port" ].as< std::string > ();
- if (env->debug()) std::cout << " port " << port << " overridden at the command line\n";
- try { boost::lexical_cast< int >( port );}
- catch ( boost::bad_lexical_cast& e ) {
- std::stringstream ss; ss << "ClientOptions::parse: The specified port(" << port << ") must be convertible to an integer";
- throw std::runtime_error( ss.str() );
- }
- }
- if ( vm.count( "host" ) ) {
- host = vm[ "host" ].as< std::string > ();
- if (env->debug()) std::cout << " host " << host << " overridden at the command line\n";
- }
- if (!host.empty() || !port.empty()) {
- if (host.empty()) host = env->hostSpecified(); // get the environment variable ECF_NODE
- if (port.empty()) port = env->portSpecified(); // get the environment variable ECF_PORT
- if (host.empty()) host = Str::LOCALHOST(); // if ECF_NODE not specified default to localhost
- if (port.empty()) port = Str::DEFAULT_PORT_NUMBER(); // if ECF_PORT not specified use default
- env->set_host_port(host,port);
- }
- if ( vm.count( "rid" ) ) {
- std::string rid = vm[ "rid" ].as< std::string > ();
- if (env->debug()) std::cout << " rid " << rid << " overridden at the command line\n";
- env->set_remote_id(rid);
- }
-
- // Defer the parsing of the command , to the command. This allows
- // all cmd functionality to be centralised with the command
- // This can throw std::runtime_error if arg's don't parse
- Cmd_ptr client_request;
- if ( ! cmdRegistry_.parse( client_request, vm, env) ) {
-
- // The arguments did *NOT* match with any of the registered command.
- // Hence if arguments don't match help, debug or version its an error
- // Note: we did *NOT* check for a NULL client_request since *NOT* all
- // request need to create it. Some commands are client specific.
- // For example:
- // --server_load // this is sent to server
- // --server_load=<path> // no command returned, command executed by client
- if ( vm.count( "help" ) ) {
- string help_cmd = vm[ "help" ].as< std::string > ();
- show_help(help_cmd);
- return client_request;
- }
-
- if ( vm.count( "debug" ) ) {
- cout << env->toString() << "\n";
- return client_request;
- }
-
- if ( vm.count( "version" ) ) {
- cout << Version::description() << "\n";
- exit(0);
- }
-
- std::stringstream ss;
- ss << "ClientOptions::parse: Arguments did not match any commands.\n";
- ss << " argc=" << argc << "\n"; for(int i = 0; i < argc; i++) { ss << " arg" << i << "=" << argv[i];}
- ss << "\nUse --help to see all the available commands\n";
- throw std::runtime_error(ss.str());
- }
-
- return client_request;
-}
-
-void ClientOptions::show_help(const std::string & help_cmd) const
-{
- // WARNING: This assumes that there are no user/child commands with name 'summary','all','child','user'
- if (help_cmd.empty()) {
-
- cout << "\nClient/server based work flow package:\n\n";
- cout << Version::description() << "\n\n";
- cout << Ecf::CLIENT_NAME() << " provides the command line interface, for interacting with the server:\n";
-
- cout << "Try:\n\n";
- cout << " " << Ecf::CLIENT_NAME() << " --help all # List all commands, verbosely\n";
- cout << " " << Ecf::CLIENT_NAME() << " --help summary # One line summary of all commands\n";
- cout << " " << Ecf::CLIENT_NAME() << " --help child # One line summary of child commands\n";
- cout << " " << Ecf::CLIENT_NAME() << " --help user # One line summary of user command\n";
- cout << " " << Ecf::CLIENT_NAME() << " --help <cmd> # Detailed help on each command\n\n";
-
- show_all_commands("Commands:");
- }
- else {
- if (help_cmd == "all") cout << *desc_ << "\n";
- else if (help_cmd == "summary") show_cmd_summary("\nEcflow client commands:\n");
- else if (help_cmd == "child") show_cmd_summary("\nEcflow child client commands:\n","child");
- else if (help_cmd == "user") show_cmd_summary("\nEcflow user client commands:\n","user");
- else {
- // Help on individual command
- const po::option_description* od = desc_->find_nothrow(help_cmd,
- true, /*approx, will find nearest match*/
- false, /*long_ignore_case = false*/
- false /*short_ignore_case = false*/
- );
-// cout << "long_name = " << od.long_name() << "\n";
-// cout << "format_name = " << od.format_name() << "\n";
-// cout << "format_parameter = " << od.format_parameter() << "\n";
- if (od) {
- cout << "\n";
- cout << od->long_name() << "\n";
- for(size_t i =0; i< od->long_name().size(); i++) cout << "-";
- cout << "\n\n";
- cout << od->description() << "\n\n";
- cout << client_env_description();
- if ( od->long_name() == TaskApi::initArg() ||
- od->long_name() == TaskApi::completeArg() ||
- od->long_name() == TaskApi::abortArg() ||
- od->long_name() == TaskApi::waitArg() ||
- od->long_name() == TaskApi::eventArg() ||
- od->long_name() == TaskApi::labelArg() ||
- od->long_name() == TaskApi::meterArg()) {
- cout << "\n";
- cout << client_task_env_description();
- }
- }
- else {
- show_all_commands("No matching command found, please choose from:");
- }
- }
- }
-}
-
-void ClientOptions::show_all_commands(const char* title) const
-{
- cout << title << "\n";
- // take a copy, since we need to sort
- std::vector< boost::shared_ptr<po::option_description> > options = desc_->options();
-
- // sort using long_name
- std::sort(options.begin(),options.end(),
- boost::bind(std::less<std::string>(),
- boost::bind(&po::option_description::long_name,_1),
- boost::bind(&po::option_description::long_name,_2)));
-
- size_t vec_size = options.size();
- size_t max_width = 0;
- for(size_t i = 0; i < vec_size; i++) { max_width = std::max(max_width,options[i]->long_name().size()); }
- max_width += 1;
- for(size_t i = 0; i < vec_size; i++) {
- if (i == 0 || i % 5 == 0) cout << "\n ";
- cout << left << std::setw(max_width) << options[i]->long_name();
- }
- cout << "\n";
-}
-
-void ClientOptions::show_cmd_summary(const char *title,const std::string& user_or_child) const
-{
- assert(user_or_child.empty() || user_or_child == "child" || user_or_child == "user");
- cout << title << "\n";
-
- // take a copy, since we need to sort
- std::vector< boost::shared_ptr<po::option_description> > options = desc_->options();
-
- // sort using long_name
- std::sort(options.begin(),options.end(),
- boost::bind(std::less<std::string>(),
- boost::bind(&po::option_description::long_name,_1),
- boost::bind(&po::option_description::long_name,_2)));
-
- size_t vec_size = options.size();
- size_t max_width = 0;
- for(size_t i = 0; i < vec_size; i++) { max_width = std::max(max_width,options[i]->long_name().size()); }
- max_width += 1;
- for(size_t i = 0; i < vec_size; i++) {
-
- if (user_or_child == "child" && Child::valid_child_cmd(options[i]->long_name())) {
- std::vector< std::string > lines;
- Str::split(options[i]->description(),lines,"\n");
- if (!lines.empty()) {
- cout << " " << left << std::setw(max_width) << options[i]->long_name() << " ";
- cout << "child ";
- cout << lines[0] << "\n";
- }
- }
- else if (user_or_child == "user" && !Child::valid_child_cmd(options[i]->long_name())) {
- std::vector< std::string > lines;
- Str::split(options[i]->description(),lines,"\n");
- if (!lines.empty()) {
- cout << " " << left << std::setw(max_width) << options[i]->long_name() << " ";
- cout << "user ";
- cout << lines[0] << "\n";
- }
- }
- else if (user_or_child .empty()) {
- std::vector< std::string > lines;
- Str::split(options[i]->description(),lines,"\n");
- if (!lines.empty()) {
- cout << " " << left << std::setw(max_width) << options[i]->long_name() << " ";
- if (Child::valid_child_cmd(options[i]->long_name())) cout << "child ";
- else cout << "user ";
- cout << lines[0] << "\n";
- }
- }
- }
- cout << "\n";
-}
-
-const char* client_env_description() {
- return
- "The client reads in the following environment variables. These are read by user and child command\n\n"
- "|----------|----------|------------|-------------------------------------------------------------------|\n"
- "| Name | Type | Required | Description |\n"
- "|----------|----------|------------|-------------------------------------------------------------------|\n"
- "| ECF_NODE | <string> | Mandatory* | The host name of the main server. defaults to 'localhost' |\n"
- "| ECF_PORT | <int> | Mandatory* | The TCP/IP port to call on the server. Must be unique to a server |\n"
- "|----------|----------|------------|-------------------------------------------------------------------|\n\n"
- "* The host and port must be specified in order for the client to communicate with the server, this can \n"
- " be done by setting ECF_NODE, ECF_PORT or by specifying --host <host> --port <int> on the command line\n"
- ;
-}
-
-const char* client_task_env_description()
-{
- return
- "The following environment variables are specific to child commands.\n"
- "The scripts should export the mandatory variables. Typically defined in the head/tail includes files\n\n"
- "|--------------|----------|-----------|---------------------------------------------------------------|\n"
- "| Name | Type | Required | Description |\n"
- "|--------------|----------|-----------|---------------------------------------------------------------|\n"
- "| ECF_NAME | <string> | Mandatory | Full path name to the task |\n"
- "| ECF_PASS | <string> | Mandatory | The jobs password, allocated by server, then used by server to|\n"
- "| | | | authenticate client request |\n"
- "| ECF_TRYNO | <int> | Mandatory | The number of times the job has run. This is allocated by the |\n"
- "| | | | server, and used in job/output file name generation. |\n"
- "| ECF_RID | <string> | Mandatory | The process identifier. Helps zombies identification and |\n"
- "| | | | automated killing of running jobs |\n"
- "| ECF_TIMEOUT | <int> | optional | Max time in *seconds* for client to deliver message to main |\n"
- "| | | | server. The default is 24 hours |\n"
- "| ECF_HOSTFILE | <string> | optional | File that lists alternate hosts to try, if connection to main |\n"
- "| | | | host fails |\n"
- "| ECF_DENIED | <any> | optional | Provides a way for child to exit with an error, if server |\n"
- "| | | | denies connection. Avoids 24hr wait. Note: when you have |\n"
- "| | | | hundreds of tasks, using this approach requires a lot of |\n"
- "| | | | manual intervention to determine job status |\n"
- "| NO_ECF | <any> | optional | If set exit's ecflow_client immediately with success. This |\n"
- "| | | | allows the scripts to be tested independent of the server |\n"
- "|--------------|----------|-----------|---------------------------------------------------------------|\n"
- ;
-}
-
diff --git a/ecflow_4_0_7/Client/src/ClientOptions.hpp b/ecflow_4_0_7/Client/src/ClientOptions.hpp
deleted file mode 100644
index 2deb931..0000000
--- a/ecflow_4_0_7/Client/src/ClientOptions.hpp
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef CLIENTOPTIONS_HPP_
-#define CLIENTOPTIONS_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name : ClientOptions
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Will parse the client argument line, and construct a command
-// that will be sent to the server.
-//
-// The environment must be read in before the program options. The program options
-// will construct the commands, some of which require the environment
-// We could have just done this as last part of constructor. However we need a
-// separation between reading the environment and reading the option for:
-// a/ testing purposes. i.e as this allows us to inject/override the task path
-// read in from the environment.
-// b/ override host and port number.
-// will throw std::runtime_error for invalid arguments
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/noncopyable.hpp>
-#include "CtsCmdRegistry.hpp"
-class ClientEnvironment;
-
-class ClientOptions : private boost::noncopyable {
-public:
- /// Will create command register, & ask each cmd to describe their arguments
- ClientOptions();
- ~ClientOptions();
-
- /// parse the arguments and create the client request that is to be sent
- /// to the server. Will throw std::runtime_error if invalid arguments specified
- Cmd_ptr parse(int argc, char* argv[], ClientEnvironment*) const;
-
-private:
-
- void show_help(const std::string& help_cmd) const;
- void show_all_commands(const char* title) const;
- void show_cmd_summary(const char* title, const std::string& user_or_child = "") const;
-
- CtsCmdRegistry cmdRegistry_;
- boost::program_options::options_description* desc_;
-};
-#endif
diff --git a/ecflow_4_0_7/Client/src/Rtt.cpp b/ecflow_4_0_7/Client/src/Rtt.cpp
deleted file mode 100644
index a7be89f..0000000
--- a/ecflow_4_0_7/Client/src/Rtt.cpp
+++ /dev/null
@@ -1,180 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Simple singleton implementation of log
-//============================================================================
-#include <assert.h>
-#include <vector>
-#include <iostream>
-#include <boost/lexical_cast.hpp>
-#include <boost/foreach.hpp>
-#include "boost/date_time/posix_time/posix_time.hpp" //include all types plus i/o
-
-#include "Rtt.hpp"
-#include "File.hpp"
-#include "Str.hpp"
-#include "Indentor.hpp"
-
-using namespace std;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-
-namespace ecf {
-
-Rtt* Rtt::instance_ = NULL;
-
-void Rtt::create(const std::string& filename)
-{
- if ( instance_ == NULL) {
- instance_ = new Rtt(filename);
- }
-}
-
-void Rtt::destroy()
-{
- delete instance_;
- instance_ = NULL;
-}
-
-
-Rtt::Rtt(const std::string& filename)
-: file_(filename.c_str(), ios::out | ios::app)
-{
- if (!file_.is_open()) {
- std::cerr << "Rtt::Rtt Could not open file '" << filename << "'\n";
- std::runtime_error("Rtt::Rtt: Could not open file " + filename);
- }
-}
-
-Rtt::~Rtt(){}
-
-void Rtt::log(const std::string& message)
-{
- file_ << message << endl;
-}
-
-void rtt(const std::string& message)
-{
- if (Rtt::instance()) {
- Rtt::instance()->log(message);
- }
-}
-
-std::string Rtt::analyis(const std::string& filename)
-{
- std::vector<std::string> lines;
- if (!File::splitFileIntoLines(filename,lines)) {
- std::cout << "Rtt::analyis: could not open file " << filename << "\n";
- return string();
- }
-
- // Typical format
- // localhost:3141 --ping :ma0 rtt:00:00:00.001082
- // localhost:3141 --log=new Test/data/ECF_HOME/test_wait_cmd/test_wait_cmd.def_log :ma0 rtt:00:00:00.000930
- // localhost:3141 --zombie_get :ma0 rtt:00:00:00.003982
-
- /// Extract the command name and time, and add to map, to compute averages, min,max & standard deviation
- map<string,vector<time_duration> > cmd_time_map;
- size_t max_cmd_size = 0;
- for(size_t i = 0; i < lines.size(); i++) {
-
- if (lines[i].empty()) continue;
-// cout << i << ":" << lines[i] << " ";
- string::size_type dash = lines[i].find("--");
- string::size_type rtt_pos = lines[i].find(Rtt::tag());
- if (dash == std::string::npos) continue;
- if (rtt_pos == std::string::npos) continue;
-
-
- int cmd_length = 0;
- string::size_type equals = lines[i].find("=",dash);
- string::size_type space = lines[i].find(" ",dash);
- if (equals != std::string::npos) cmd_length = equals;
- else if (space != std::string::npos) cmd_length = space;
- string cmd = lines[i].substr(0,cmd_length);
- max_cmd_size = std::max(max_cmd_size,cmd.size());
-
- string time = lines[i].substr(rtt_pos+4);
- time_duration td(duration_from_string(time));
-// cout << " cmd:(" << cmd << ") time(" << to_simple_string(td) << ")\n";
-
- map<string,vector<time_duration> >::iterator cmd_iterator = cmd_time_map.find(cmd);
- if ( cmd_iterator == cmd_time_map.end()) {
- vector<time_duration> vec;
- vec.push_back(td);
- std::pair<string, vector<time_duration> > p = std::make_pair(cmd,vec);
- cmd_time_map.insert( p );
- }
- else {
- (*cmd_iterator).second.push_back(td);
- }
- }
-
- time_duration total(0,0,0,0);
- int total_requests = 0;
-
- // Create title
- std::stringstream ss;
- ss << left << setw(max_cmd_size+1) << "Command" << right << setw(5) << "count" << setw(9) << "min" << setw(9) << "average" << setw(9) << "max" << setw(9) << right << "std\n";
- std::pair<string, vector<time_duration> > p;
- BOOST_FOREACH(p, cmd_time_map) {
-
- time_duration average_td(0,0,0,0);
- time_duration min(24,59,59,0);
- time_duration max(0,0,0,0);
- for(size_t i = 0; i < p.second.size(); i++) {
- average_td += p.second[i];
- total_requests++;
- total += p.second[i];
- min = std::min(min,p.second[i]);
- max = std::max(max,p.second[i]);
- }
-
- ss << left << setw(max_cmd_size+1) << p.first << setw(5) << right << p.second.size();
- if (p.second.empty()) {
- ss << setw(9) << right << p.second[0].total_microseconds() << " ? ";
- }
- else if ( p.second.size() == 1) {
- ss << setw(9) << right << p.second[0].total_microseconds();
- }
- else {
- int average = average_td.total_microseconds()/p.second.size();
-
-// bool debug = false;
-// if (p.first == "begin") debug = true;
-
- // compute standard deviation
- unsigned int total_diff_from_avg = 0;
- for(size_t i = 0; i < p.second.size(); i++) {
- int diff = p.second[i].total_microseconds() - average;
- int diff_squared = diff * diff;
- total_diff_from_avg += diff_squared;
-// if (debug) cout << "diff: " << diff << " diff_squared: " << diff_squared << " total_diff_from_avg: " << total_diff_from_avg << "\n";
- }
-
- double avg = total_diff_from_avg/p.second.size();
- int stdd = (int)sqrt(avg);
-// if (debug) cout << "avg: " << avg << " stdd: " << stdd << "\n";
-
- ss << setw(9) << right << min.total_microseconds() ;
- ss << setw(9) << right << average;
- ss << setw(9) << right << max.total_microseconds();
- ss << setw(9) << right << stdd;
- }
- ss << "\n";
- }
- ss << "\ntotal round trip time " << to_simple_string(total) << " for " << total_requests << " requests\n";
- return ss.str();
-}
-
-}
-
diff --git a/ecflow_4_0_7/Client/src/Rtt.hpp b/ecflow_4_0_7/Client/src/Rtt.hpp
deleted file mode 100644
index 1f933ab..0000000
--- a/ecflow_4_0_7/Client/src/Rtt.hpp
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef RTT_HPP_
-#define RTT_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name : Rtt
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Simple client based singleton for recording round trip times
-// of all client based command
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <string>
-#include <fstream>
-#include <sstream>
-#include <boost/noncopyable.hpp>
-#include <boost/lambda/lambda.hpp>
-
-namespace ecf {
-
-class Rtt : private boost::noncopyable {
-public:
- static void create(const std::string& filename);
- static void destroy();
- static Rtt* instance() { return instance_;}
-
- void log(const std::string& message);
-
- /// Open the file, and create average times for all client invoker round trip times
- static std::string analyis(const std::string& filename);
-
- /// Used in output and parsing, when computing averages
- static const char* tag() { return "rtt:";}
-
-private:
- ~Rtt();
- Rtt(const std::string& filename);
- static Rtt* instance_;
- mutable std::ofstream file_;
-};
-
-void rtt(const std::string& message);
-
-// allow user to do the following:
-// RTT("this is " << path << " ok ");
-//
-// helper, see STRINGIZE() macro
-template <typename Functor>
-std::string stringize_rtt(Functor const & f) {
- std::ostringstream out;
- f(out);
- return out.str();
-}
-#define STRINGIZE_RTT(EXPRESSION) (ecf::stringize_rtt(boost::lambda::_1 << EXPRESSION))
-#define RTT(EXPRESSION) ecf::rtt(STRINGIZE_RTT(EXPRESSION))
-}
-#endif
diff --git a/ecflow_4_0_7/Client/src/UrlCmd.cpp b/ecflow_4_0_7/Client/src/UrlCmd.cpp
deleted file mode 100644
index 1d350c4..0000000
--- a/ecflow_4_0_7/Client/src/UrlCmd.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Client side command only.
-// Placed in this category, since the server does not need to link
-// with it.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/foreach.hpp>
-#include "UrlCmd.hpp"
-#include "Defs.hpp"
-#include "Node.hpp"
-
-UrlCmd::UrlCmd(defs_ptr defs, const std::string& absNodePath)
-: defs_(defs),node_(NULL)
-{
- if (!defs_.get()) {
- throw std::runtime_error("UrlCmd: The definition parameter is empty");
- }
-
- if (absNodePath.empty()) {
- throw std::runtime_error("UrlCmd: The node path parameter is empty");
- }
-
- node_ = defs_->findAbsNode(absNodePath).get();
- if ( !node_ ) {
- std::string errorMsg = "UrlCmd: The node path parameter '";
- errorMsg += absNodePath;
- errorMsg += "' can not be found.";
- throw std::runtime_error(errorMsg);
- }
-}
-
-std::string UrlCmd::getUrl() const
-{
- std::string url;
- node_->findParentUserVariableValue("ECF_URL_CMD", url);
- if (url.empty()) {
- std::string errorMsg = "UrlCmd: Could not find variable ECF_URL_CMD from node ";
- errorMsg += node_->absNodePath();
- throw std::runtime_error(errorMsg);
- }
-
- if (!node_->variableSubsitution(url)) {
- std::string errorMsg = "UrlCmd:: Variable substitution failed for ";
- errorMsg += url;
- throw std::runtime_error(errorMsg);
- }
- return url;
-}
-
-void UrlCmd::execute() const
-{
- // invoke as a system command, we don't use System::instance()
- // since this is on the client side. hence no need manage the spawned process
- system(getUrl().c_str());
-}
-
diff --git a/ecflow_4_0_7/Client/src/UrlCmd.hpp b/ecflow_4_0_7/Client/src/UrlCmd.hpp
deleted file mode 100644
index 14999b0..0000000
--- a/ecflow_4_0_7/Client/src/UrlCmd.hpp
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef URL_CMD_HPP_
-#define URL_CMD_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Version : Beta version for test use only
-// Revision : $Revision$
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Client side command only.
-// Placed in this category, since the server does not need to link
-// with it.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <string>
-#include <boost/noncopyable.hpp>
-#include "NodeFwd.hpp"
-
-class UrlCmd : private boost::noncopyable {
-public:
- /// Will throw std::runtime_error if defs or node path is not correct
- UrlCmd(defs_ptr defs, const std::string& absNodePath );
-
- /// Will throw std::runtime_error if url can not be formed
- std::string getUrl() const;
-
- /// Execute the url command
- void execute() const;
-
-private:
- defs_ptr defs_;
- Node* node_;
-};
-
-#endif
diff --git a/ecflow_4_0_7/Client/test/EcfPortLock.hpp b/ecflow_4_0_7/Client/test/EcfPortLock.hpp
deleted file mode 100644
index 5cdcce3..0000000
--- a/ecflow_4_0_7/Client/test/EcfPortLock.hpp
+++ /dev/null
@@ -1,79 +0,0 @@
-#ifndef ECF_PORT_LOCK_HPP_
-#define ECF_PORT_LOCK_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : This class is used in TEST only
-// It allows functionality to create a lock file file, so that different process
-// can avoid creating server with same port number
-//
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <boost/noncopyable.hpp>
-#include "boost/filesystem.hpp"
-#include "boost/filesystem/operations.hpp"
-#include <boost/lexical_cast.hpp>
-#include <sstream>
-#include <iostream>
-#include "File.hpp"
-
-namespace ecf {
-
-class EcfPortLock : private boost::noncopyable {
-public:
-
- static bool is_free(int port)
- {
- std::string the_port = boost::lexical_cast<std::string>(port);
- if (boost::filesystem::exists(port_file(the_port))) {
- // std::cout << "EcfPortLock::is_free returning FALSE\n ";
- return false;
- }
- // std::cout << "EcfPortLock::is_free returning TRUE\n ";
- return true;
- }
-
- static void create(const std::string& the_port)
- {
- std::string the_file = port_file( the_port );
- // std::cout << "EcfPortLock::create " << the_file << "\n";
- std::string errorMsg;
- if (!ecf::File::create(the_file,"",errorMsg)) {
- std::stringstream sb;
- sb << "EcfPortLock::create_free_port_file : could not create file " << the_file;
- throw std::runtime_error(sb.str());
- }
- }
-
- static void remove(const std::string& the_port)
- {
- std::string the_file = port_file(the_port);
- // std::cout << "EcfPortLock::remove " << the_file << "\n";
- boost::filesystem::remove(the_file);
- }
-
-private:
- EcfPortLock();
-
- static std::string port_file(const std::string& the_port)
- {
- // We need the *SAME* location so that different process find the same file. Get to the workspace directory
- std::string path = File::root_build_dir();
- //std::cout << "\nworkspace_dir = " << path << " ------------------------------------------------------\n";
- path += "/ECF_PORT_used_";
- path += the_port;
- path += ".lock";
- return path;
- }
-};
-}
-#endif
diff --git a/ecflow_4_0_7/Client/test/InvokeServer.hpp b/ecflow_4_0_7/Client/test/InvokeServer.hpp
deleted file mode 100644
index 659fa1f..0000000
--- a/ecflow_4_0_7/Client/test/InvokeServer.hpp
+++ /dev/null
@@ -1,158 +0,0 @@
-#ifndef INVOKESERVER_HPP_
-#define INVOKESERVER_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #32 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <iostream>
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include <boost/noncopyable.hpp>
-
-#include "TestHelper.hpp"
-#include "ClientInvoker.hpp"
-#include "Str.hpp"
-#include "File.hpp"
-#include "EcfPortLock.hpp"
-#include "Host.hpp"
-
-class InvokeServer : private boost::noncopyable {
-public:
- InvokeServer(const std::string& msg,
- const std::string& port = ecf::Str::DEFAULT_PORT_NUMBER(),
- bool disable_job_generation = false,
- bool remove_checkpt_file_before_server_start = true,
- bool remove_checkpt_file_after_server_exit = true
- ) : port_(port),
- host_(ClientEnvironment::hostSpecified()),
- remove_checkpt_file_after_server_exit_(remove_checkpt_file_after_server_exit)
- {
- if (host_.empty()) {
- if(!msg.empty()) std::cout << msg << " port(" << port_ << ")" << std::endl;
-
- doStart(port_,disable_job_generation,remove_checkpt_file_before_server_start);
- }
- else {
- // Start of test, clear any existing defs on remote server
- // Assuming this has been started on DEFAULT_PORT_NUMBER, can't use existing port_
- port_ = ecf::Str::DEFAULT_PORT_NUMBER();
- std::string test_name = msg;
- test_name += " on ";
- test_name += host_;
- test_name += ecf::Str::COLON();
- test_name += port_;
-
- std::cout << test_name << std::endl;
-
- ClientInvoker theClient(host_,port_);
- theClient.logMsg( test_name );
- BOOST_REQUIRE_MESSAGE( theClient.delete_all() == 0,CtsApi::to_string(CtsApi::delete_node()) << " failed should return 0. Should Delete ALL existing defs in the server\n" << theClient.errorMsg());
- }
- }
-
- InvokeServer(const std::string& port,
- bool stop_ambiguaty,
- bool disable_job_generation = false,
- bool remove_checkpt_file_before_server_start = true,
- bool remove_checkpt_file_after_server_exit = true
- ) : port_(port),
- remove_checkpt_file_after_server_exit_(remove_checkpt_file_after_server_exit)
- {
- // host_ is empty.
- doStart(port_,disable_job_generation,remove_checkpt_file_before_server_start);
- }
-
- ~InvokeServer() {
- // This will also remove the generated files.
- // Will only terminate local server, host_ is *EMPTY* for local server, using two constructors above
- if (host_.empty()) {
- doEnd(ecf::Str::LOCALHOST(), port_, remove_checkpt_file_after_server_exit_);
- }
- }
-
- const std::string& port() const { return port_; }
- const std::string& host() const { if (host_.empty()) return ecf::Str::LOCALHOST(); return host_; }
-
- std::string ecf_log_file() const { return host_name_.ecf_log_file(port_);}
- std::string ecf_checkpt_file() const { return host_name_.ecf_checkpt_file(port_); }
- std::string ecf_backup_checkpt_file() const { return host_name_.ecf_backup_checkpt_file(port_); }
-
-
- static void doStart(const std::string& port,bool disable_job_generation = false, bool remove_checkpt_file_before_server_start = true)
- {
- /// Remove check pt and backup check pt file, else server will load it & remove log file
- ecf::Host h;
- if (remove_checkpt_file_before_server_start) {
- boost::filesystem::remove(h.ecf_checkpt_file(port));
- boost::filesystem::remove(h.ecf_backup_checkpt_file(port));
- }
- boost::filesystem::remove(h.ecf_log_file(port));
-
- // start the server in the background
- std::string theServerInvokePath = ecf::File::find_ecf_server_path();
- BOOST_REQUIRE_MESSAGE(!theServerInvokePath.empty(),"InvokeServer::doStart: The server program could not be found");
- BOOST_REQUIRE_MESSAGE(boost::filesystem::exists(theServerInvokePath),"InvokeServer::doStart: server exe does not exist at:" << theServerInvokePath);
-
- // Create a port file. To avoid creating multiple servers on the same port number
- ecf::EcfPortLock::create( port );
-
- // Make sure server starts in the background to avoid hanging test
- theServerInvokePath += " --port=" + port;
- if (disable_job_generation) {
- theServerInvokePath += " --dis_job_gen";
- }
- theServerInvokePath += " &";
-
- //std::cout << "InvokeServer::doStart port = " << port << " server path = " << theServerInvokePath << "\n";
- (void)system( theServerInvokePath.c_str() );
-
- // Allow time for server process to kick in.
- ClientInvoker theClient(ecf::Str::LOCALHOST(),port);
- BOOST_REQUIRE_MESSAGE(theClient.wait_for_server_reply(),"InvokeServer::doStart: Server failed to start after 60 second on " << ecf::Str::LOCALHOST() << ":" << port);
- }
-
-
- static void doEnd( const std::string& host, const std::string& port, bool remove_checkpt_file_after_server_exit )
- {
- // std::cout << "*****InvokeServer::doEnd Closing server on " << host << ecf::Str::COLON() << port << "\n";
- {
- ClientInvoker theClient(host,port);
- BOOST_REQUIRE_NO_THROW( theClient.terminateServer() );
- BOOST_REQUIRE_MESSAGE( theClient.wait_for_server_death(),"Failed to terminate server after 60 seconds\n");
- }
-
- // remove port file. This prevented multiple different process from opening servers with same port number
- ecf::EcfPortLock::remove( port );
-
- // Remove generated file comment for debug
- ecf::Host h;
- boost::filesystem::remove(h.ecf_log_file(port));
- BOOST_CHECK_MESSAGE(!boost::filesystem::exists(h.ecf_log_file(port)), "log file " << h.ecf_log_file(port) << " not deleted\n");
-
- if (remove_checkpt_file_after_server_exit) {
- boost::filesystem::remove(h.ecf_checkpt_file(port));
- boost::filesystem::remove(h.ecf_backup_checkpt_file(port));
- BOOST_CHECK_MESSAGE(!boost::filesystem::exists(h.ecf_checkpt_file(port)), "file " << h.ecf_checkpt_file(port) << " not deleted\n");
- BOOST_CHECK_MESSAGE(!boost::filesystem::exists(h.ecf_backup_checkpt_file(port)), "file " << h.ecf_backup_checkpt_file(port) << " not deleted\n");
- }
- }
-
-private:
- InvokeServer(const InvokeServer&);
- std::string port_;
- std::string host_;
- ecf::Host host_name_;
- bool remove_checkpt_file_after_server_exit_;
-};
-
-#endif
diff --git a/ecflow_4_0_7/Client/test/SCPort.cpp b/ecflow_4_0_7/Client/test/SCPort.cpp
deleted file mode 100644
index e367a33..0000000
--- a/ecflow_4_0_7/Client/test/SCPort.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #8 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <iostream>
-#include "SCPort.hpp"
-#include "EcfPortLock.hpp"
-#include "ClientInvoker.hpp"
-
-namespace ecf {
-
-// init the globals. Note we dont use 3141, so that in the case where we already
-// have a remote/local server started external to the test, it does not clash
-// Also debug and release version use different port numbers to avoid clashes, if both tests run at same time
-
-#ifdef DEBUG
-int SCPort::thePort_ = 3161;
-#else
-int SCPort::thePort_ = 3142;
-#endif
-
-std::string SCPort::next()
-{
- // Use a combination of local lock file, and pinging the server
- while (!EcfPortLock::is_free(thePort_)) thePort_++;
- // std::cout << "SCPort::next() = " << thePort << "\n";
- return ClientInvoker::find_free_port(thePort_);
-}
-
-}
diff --git a/ecflow_4_0_7/Client/test/SCPort.hpp b/ecflow_4_0_7/Client/test/SCPort.hpp
deleted file mode 100644
index bf036f9..0000000
--- a/ecflow_4_0_7/Client/test/SCPort.hpp
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef PORT_HPP_
-#define PORT_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <string>
-
-namespace ecf {
-
-// If two different process/servers both try to use the same port number, you
-// get an "Address in use" error, even if one the process is dead. This is
-// because the kernel does not immediately release the resource and there is
-// time out period. To get round this we will start the new server/client
-// and use a different port number.
-
-class SCPort {
-public:
-
- /// make sure we have a unique port, each time next() is called;
- static std::string next();
-
-private:
- SCPort();
- ~SCPort();
-
- static int thePort_;
-};
-}
-
-#endif
diff --git a/ecflow_4_0_7/Client/test/TestCheckPtDefsCmd.cpp b/ecflow_4_0_7/Client/test/TestCheckPtDefsCmd.cpp
deleted file mode 100644
index 2d8c9ae..0000000
--- a/ecflow_4_0_7/Client/test/TestCheckPtDefsCmd.cpp
+++ /dev/null
@@ -1,237 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #29 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <string>
-#include <fstream>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/test/unit_test.hpp>
-
-#include "ClientInvoker.hpp"
-#include "ClientEnvironment.hpp"
-#include "InvokeServer.hpp"
-#include "SCPort.hpp"
-#include "Str.hpp"
-#include "File.hpp"
-
-namespace fs = boost::filesystem;
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( ClientTestSuite )
-
-// ************************************************************************************
-// Note: If you make edits to node tree, they will have no effect until the server is rebuilt
-// ************************************************************************************
-BOOST_AUTO_TEST_CASE( test_check_pt_defs_cmd )
-{
- // This will remove check pt and backup file before server start, to avoid the server from loading previous test data
- InvokeServer invokeServer("Client:: ...test_check_pt_defs_cmd",SCPort::next());
-
- ClientInvoker theClient(invokeServer.host(),invokeServer.port());
- BOOST_REQUIRE_MESSAGE( theClient.restartServer() == 0,CtsApi::restartServer() << " should return 0 server not started, or connection refused\n" << theClient.errorMsg());
-
- std::string path = File::test_data("Client/test/data/lifecycle.txt","Client");
-
- BOOST_REQUIRE_MESSAGE(theClient.loadDefs(path) == 0,"load defs failed \n" << theClient.errorMsg());
-
- // First time. Should create a ecf_checkpt_file, but _no_ backup file
- BOOST_REQUIRE_MESSAGE(theClient.checkPtDefs() == 0,CtsApi::checkPtDefs() << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(fs::exists(invokeServer.ecf_checkpt_file()),CtsApi::checkPtDefs() << " failed file(" << invokeServer.ecf_checkpt_file() << ") not saved");
- BOOST_REQUIRE_MESSAGE(fs::file_size(invokeServer.ecf_checkpt_file()) !=0,"Expected check point file(" << invokeServer.ecf_checkpt_file() << "), to have file size > 0");
- if (ClientEnvironment::hostSpecified().empty()) {
- // This check only valid if server was invoked locally. Ignore for remote servers
- BOOST_REQUIRE_MESSAGE(!fs::exists(invokeServer.ecf_backup_checkpt_file()), "Backup check point file(" << invokeServer.ecf_backup_checkpt_file() << ")should not exist,for very first time.");
- }
-
- // Save checkpoint file again. This should create a backup file, we should have ecf_checkpt_file and ecf_backup_checkpt_file
- BOOST_REQUIRE_MESSAGE(theClient.checkPtDefs() == 0,CtsApi::checkPtDefs() << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(fs::exists(invokeServer.ecf_checkpt_file()),CtsApi::checkPtDefs() << " failed No check pt file(" << invokeServer.ecf_checkpt_file() << ") saved");
- BOOST_REQUIRE_MESSAGE(fs::file_size(invokeServer.ecf_checkpt_file()) !=0,"Expected check point file(" << invokeServer.ecf_checkpt_file() << ") to have file size > 0 ");
- BOOST_REQUIRE_MESSAGE(fs::exists(invokeServer.ecf_backup_checkpt_file()), "Backup check point file(" << invokeServer.ecf_backup_checkpt_file() << ") not created");
- BOOST_REQUIRE_MESSAGE(fs::file_size(invokeServer.ecf_backup_checkpt_file()) !=0,"Expected backup check point file(" << invokeServer.ecf_backup_checkpt_file() << "), to have file size > 0");
-
- // Check the defaults for mode , interval and alarm time before making any changes
- BOOST_REQUIRE_MESSAGE(theClient.stats() == 0,CtsApi::stats() << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_mode_ == ecf::CheckPt::ON_TIME, " Expected default check pt mode to be ON_TIME");
- BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_interval_ == CheckPt::default_interval(), " Expected default check pt interval of " << CheckPt::default_interval() << " but found " << theClient.server_reply().stats().checkpt_interval_);
- BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_save_time_alarm_ == CheckPt::default_save_time_alarm(), " Expected default check pt alarm time of " << CheckPt::default_save_time_alarm() << " but found " << theClient.server_reply().stats().checkpt_save_time_alarm_);
-
-
- // Test change of check_pt interval and mode and alarm
- BOOST_REQUIRE_MESSAGE(theClient.checkPtDefs(ecf::CheckPt::NEVER) == 0,CtsApi::checkPtDefs(ecf::CheckPt::NEVER) << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.stats() == 0,CtsApi::stats() << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_mode_ == ecf::CheckPt::NEVER, " Expected check pt mode of NEVER");
-
- BOOST_REQUIRE_MESSAGE(theClient.checkPtDefs(ecf::CheckPt::ON_TIME) == 0,CtsApi::checkPtDefs(ecf::CheckPt::ON_TIME) << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.stats() == 0,CtsApi::stats() << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_mode_ == ecf::CheckPt::ON_TIME, " Expected check pt mode of ON_TIME");
-
- BOOST_REQUIRE_MESSAGE(theClient.checkPtDefs(ecf::CheckPt::ALWAYS) == 0,CtsApi::checkPtDefs(ecf::CheckPt::ALWAYS) << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.stats() == 0,CtsApi::stats() << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_mode_ == ecf::CheckPt::ALWAYS, " Expected check pt mode of ALWAYS");
-
- BOOST_REQUIRE_MESSAGE(theClient.checkPtDefs(ecf::CheckPt::ON_TIME,30) == 0,CtsApi::checkPtDefs(ecf::CheckPt::ON_TIME,30) << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.stats() == 0,CtsApi::stats() << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_mode_ == ecf::CheckPt::ON_TIME, " Expected check pt mode of ON_TIME");
- BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_interval_ == 30, " Expected check pt interval of 30 but found " << theClient.server_reply().stats().checkpt_interval_);
-
- BOOST_REQUIRE_MESSAGE(theClient.checkPtDefs(ecf::CheckPt::UNDEFINED,56) == 0,CtsApi::checkPtDefs(ecf::CheckPt::UNDEFINED,56) << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.stats() == 0,CtsApi::stats() << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_mode_ == ecf::CheckPt::ON_TIME, " Expected check pt mode of ON_TIME");
- BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_interval_ == 56, " Expected check pt interval of 56 but found " << theClient.server_reply().stats().checkpt_interval_);
-
- // Mode and interval should remain unchanged only the alarm time should be changed
- BOOST_REQUIRE_MESSAGE(theClient.checkPtDefs(ecf::CheckPt::UNDEFINED,0,10) == 0,CtsApi::checkPtDefs(ecf::CheckPt::UNDEFINED,0,10) << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.stats() == 0,CtsApi::stats() << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_mode_ == ecf::CheckPt::ON_TIME, " Expected check pt mode of ON_TIME");
- BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_interval_ == 56, " Expected check pt interval of 56 but found " << theClient.server_reply().stats().checkpt_interval_);
- BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_save_time_alarm_ == 10, " Expected check pt alarm time of 10 but found " << theClient.server_reply().stats().checkpt_save_time_alarm_);
-
- // restore default check pointing for test that follow.
- BOOST_REQUIRE_MESSAGE(theClient.checkPtDefs(ecf::CheckPt::ON_TIME,CheckPt::default_interval()) == 0,CtsApi::checkPtDefs(ecf::CheckPt::ON_TIME) << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.checkPtDefs(ecf::CheckPt::UNDEFINED,0,CheckPt::default_save_time_alarm()) == 0,CtsApi::checkPtDefs(ecf::CheckPt::ON_TIME) << " failed should return 0\n" << theClient.errorMsg());
-
- // check defaults were set
- BOOST_REQUIRE_MESSAGE(theClient.stats() == 0,CtsApi::stats() << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_mode_ == ecf::CheckPt::ON_TIME, " Expected default check pt mode to be ON_TIME");
- BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_interval_ == CheckPt::default_interval(), " Expected default check pt interval of " << CheckPt::default_interval() << " but found " << theClient.server_reply().stats().checkpt_interval_);
- BOOST_REQUIRE_MESSAGE(theClient.server_reply().stats().checkpt_save_time_alarm_ == CheckPt::default_save_time_alarm(), " Expected default check pt alarm time of " << CheckPt::default_save_time_alarm() << " but found " << theClient.server_reply().stats().checkpt_save_time_alarm_);
-}
-
-
-BOOST_AUTO_TEST_CASE( test_restore_from_check_pt )
-{
- InvokeServer invokeServer("Client:: ...test_restore_from_check_pt",SCPort::next());
-
- defs_ptr the_defs = Defs::create();
- the_defs->add_suite("s0");
- the_defs->add_suite("s1");
- the_defs->add_suite("s2");
- the_defs->add_suite("s3");
- the_defs->add_suite("s4");
-
- ClientInvoker theClient(invokeServer.host(),invokeServer.port());
- BOOST_REQUIRE_MESSAGE(theClient.load(the_defs) == 0,"load defs failed \n" << theClient.errorMsg());
-
- size_t expected_no_of_suites = 5;
- for(int i = 0; i < 5; i++) {
- BOOST_REQUIRE_MESSAGE(theClient.checkPtDefs() == 0,CtsApi::checkPtDefs() << " failed should return 0\n" << theClient.errorMsg());
-
- BOOST_REQUIRE_MESSAGE( theClient.delete_all() == 0,"Expected delete all nodes to succeed\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.haltServer() == 0,"Expected halt server to succeed\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.restoreDefsFromCheckPt() == 0,"Expected restoreDefsFromCheckPt succeed\n");
- BOOST_REQUIRE_MESSAGE( theClient.getDefs() == 0, "Expected getDefs() to succeed, i.e expected empty defs\n");
- BOOST_REQUIRE_MESSAGE( theClient.defs()->suiteVec().size() == expected_no_of_suites, "Expected " << expected_no_of_suites << " suites, after restoreDefsFromCheckPt but found " << theClient.defs()->suiteVec().size() << "\n");
-
- std::string suite = "/s" + boost::lexical_cast<std::string>(i);
- BOOST_REQUIRE_MESSAGE( theClient.delete_node(suite) == 0,"Expected delete single suite to succeed\n" << theClient.errorMsg());
- expected_no_of_suites--;
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_restore_from_check_pt_using_new_server )
-{
- // This test relies on a NEW server invocation. Hence if ECF_NODE/remote server is used
- // the test will will invalid. hence ignore.
- if (!ClientEnvironment::hostSpecified().empty()) {
- cout << "Client:: ...test_restore_from_check_pt_using_new_server: ignoring test when ECF_NODE specified\n";
- return;
- }
-
- std::string port = SCPort::next();
- {
- // Start a new server. However make sure that on server exist we not delete check pt files
- InvokeServer invokeServer("Client:: ...test_restore_from_check_pt_using_new_server",
- port,
- false, /* bool disable_job_generation = false */
- true, /* bool remove_checkpt_file_before_server_start = true */
- false /* bool remove_checkpt_file_after_server_exit = true */
- );
-
- defs_ptr the_defs = Defs::create();
- the_defs->add_suite("s0");
- the_defs->add_suite("s1");
- the_defs->add_suite("s2");
- the_defs->add_suite("s3");
- the_defs->add_suite("s4");
-
- ClientInvoker theClient(invokeServer.host(),invokeServer.port());
- BOOST_REQUIRE_MESSAGE( theClient.load(the_defs) == 0,"load defs failed \n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.checkPtDefs() == 0,CtsApi::checkPtDefs() << " failed should\n" << theClient.errorMsg());
- }
-
- // start a new server, using same port. Make sure on start, we do not delete any checkpt files on start up
- // server should load check pt file on start up
- InvokeServer invokeServer("", /* for debug use -new server- as msg */
- port,
- false, /* bool disable_job_generation = false */
- false, /* bool remove_checkpt_file_before_server_start = true */
- true /* bool remove_checkpt_file_after_server_exit = true */
- );
-
- ClientInvoker theClient(invokeServer.host(),invokeServer.port());
- BOOST_REQUIRE_MESSAGE( theClient.sync_local() == 0, "Expected sync_local() to succeed \n");
- BOOST_REQUIRE_MESSAGE( theClient.defs(), "Expected sync_local() to succeed defs is empty\n");
- BOOST_REQUIRE_MESSAGE( theClient.defs()->suiteVec().size() == 5, "Expected 5 suites, after restoreDefsFromCheckPt but found " << theClient.defs()->suiteVec().size() << "\n");
-}
-
-BOOST_AUTO_TEST_CASE( test_check_pt_edit_history )
-{
- // This test relies on a NEW server invocation. Hence if ECF_NODE/remote server is used
- // the test will will invalid. hence ignore.
- if (!ClientEnvironment::hostSpecified().empty()) {
- cout << "Client:: ...test_check_pt_edit_history: ignoring test when ECF_NODE specified\n";
- return;
- }
-
- // This will remove check pt and backup file before server start, to avoid the server from loading previous test data
- InvokeServer invokeServer("Client:: ...test_check_pt_edit_history",SCPort::next());
-
- ClientInvoker theClient(invokeServer.host(),invokeServer.port());
- BOOST_REQUIRE_MESSAGE(theClient.edit_history(Str::ROOT_PATH()) == 0,CtsApi::to_string(CtsApi::edit_history(Str::ROOT_PATH())) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.server_reply().get_string_vec().size() == 0,"Expected edit history of size 0 after server start, but found " << theClient.server_reply().get_string_vec().size());
-
-
- // make 5 edits
- BOOST_REQUIRE_MESSAGE( theClient.restartServer() == 0,CtsApi::restartServer() << " should return 0 server not started, or connection refused\n" << theClient.errorMsg());
- std::string path = File::test_data("Client/test/data/lifecycle.txt","Client");
- BOOST_REQUIRE_MESSAGE(theClient.loadDefs(path) == 0,"load defs failed \n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.shutdownServer() == 0,CtsApi::shutdownServer() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.haltServer() == 0,CtsApi::haltServer() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.restartServer() == 0,CtsApi::restartServer() << " should return 0\n" << theClient.errorMsg());
-
- // make sure edit history updated
- BOOST_REQUIRE_MESSAGE(theClient.edit_history(Str::ROOT_PATH()) == 0,CtsApi::to_string(CtsApi::edit_history(Str::ROOT_PATH())) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.server_reply().get_string_vec().size() == 5,"Expected edit history of size 5, but found " << theClient.server_reply().get_string_vec().size());
-
- // make sure edit history was *NOT* serialized, It is only serialized when check pointing
- BOOST_REQUIRE_MESSAGE(theClient.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.defs()->get_edit_history(Str::ROOT_PATH()).size() == 0,"Expected edit history of size 0, but found " << theClient.defs()->get_edit_history(Str::ROOT_PATH()).size());
-
- // This should write the edit history
- BOOST_REQUIRE_MESSAGE(theClient.checkPtDefs(ecf::CheckPt::ALWAYS) == 0,CtsApi::checkPtDefs(ecf::CheckPt::ALWAYS) << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(fs::exists(invokeServer.ecf_checkpt_file()),CtsApi::checkPtDefs() << " failed No check pt file(" << invokeServer.ecf_checkpt_file() << ") saved");
- BOOST_REQUIRE_MESSAGE(fs::file_size(invokeServer.ecf_checkpt_file()) !=0,"Expected check point file(" << invokeServer.ecf_checkpt_file() << ") to have file size > 0 ");
-
-
- // Create a defs file from the check pt file & check edit history
- Defs defs;
- defs.restore_from_checkpt(invokeServer.ecf_checkpt_file()); // make a data model change
- BOOST_REQUIRE_MESSAGE(defs.get_edit_history(Str::ROOT_PATH()).size() == 5,"Expected edit history of size 5, but found " << defs.get_edit_history(Str::ROOT_PATH()).size());
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/Client/test/TestClientEnvironment.cpp b/ecflow_4_0_7/Client/test/TestClientEnvironment.cpp
deleted file mode 100644
index 7c2e39a..0000000
--- a/ecflow_4_0_7/Client/test/TestClientEnvironment.cpp
+++ /dev/null
@@ -1,256 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #9 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <iostream>
-#include <vector>
-#include <string>
-
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-
-#include "ClientEnvironment.hpp"
-#include "Str.hpp"
-#include "File.hpp"
-
-namespace fs = boost::filesystem;
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( ClientTestSuite )
-
-// **************************************************************************************
-// test the client environment:
-// In particular test host file parsing
-// **************************************************************************************
-BOOST_AUTO_TEST_CASE( test_client_environment_host_file_parsing )
-{
- std::cout << "Client:: ...test_client_environment_host_file_parsing" << endl;
-
- std::string good_host_file = File::test_data("Client/test/data/good_hostfile","Client");
-
- // local host should be implicitly added to internal host list
- std::vector<std::string> expectedHost;
- expectedHost.push_back(Str::LOCALHOST());
- expectedHost.push_back("host1");
- expectedHost.push_back("host2");
- expectedHost.push_back("host3");
- expectedHost.push_back("host4");
- expectedHost.push_back("host5");
- expectedHost.push_back("host6");
-
-
- ClientEnvironment client_env( good_host_file );
-// cout << "client_env " << client_env.toString() << "\n";
- std::string home_host = client_env.host();
- std::string host;
-// cout << "client_env home host " << client_env.host() << " job supplied port " << client_env.port() << "\n";
- size_t count = 0;
- BOOST_CHECK_MESSAGE( home_host == expectedHost[count], "Expected home host " << expectedHost[count] << " but found " << home_host);
-
- bool home_host_fnd = false;
- while (home_host != host) {
- // Cycle through the host until we reach the home host
- std::string errorMsg;
- BOOST_CHECK_MESSAGE( client_env.get_next_host(errorMsg), errorMsg);
-// cout << "client_env host " << client_env.host() << " port " << client_env.port() << "\n";
- host = client_env.host();
- count++;
- if (host == home_host) {
- home_host_fnd = true ;
- count = 0;
- }
- BOOST_REQUIRE_MESSAGE( count < expectedHost.size(), "Test file out of date");
- BOOST_CHECK_MESSAGE( host == expectedHost[count], "Expected host " << expectedHost[count] << " but found " << host);
- }
- BOOST_CHECK_MESSAGE( home_host_fnd, "Cycling through host file, should lead to home host");
-}
-
-BOOST_AUTO_TEST_CASE( test_client_environment_host_file_defaults )
-{
- std::cout << "Client:: ...test_client_environment_host_file_defaults" << endl;
-
- // When the HOST file does *NOT* indicate the port, it should be taken
- // from the config/environment.
- // In file good_hostfile, host3 and host5 do not specify a port, hence
- // this port is assumed to be the job supplied port, that was read from
- // config or environment. To test this correctly we need to specify a port
- // other than the default
-
- std::string good_host_file = File::test_data("Client/test/data/good_hostfile","Client");
-
-
- // local host should be implicitly added to internal host list
- std::vector<std::pair<std::string,std::string> > expectedHost;
- expectedHost.push_back( make_pair(Str::LOCALHOST(), string("5111")) ); // here 5111 is job supplied port
- expectedHost.push_back( make_pair(string("host1"), string("3142")) );
- expectedHost.push_back( make_pair(string("host2"), string("3141")) );
- expectedHost.push_back( make_pair(string("host3"), string("5111")) ); // not specified in host file, hence expect 5111
- expectedHost.push_back( make_pair(string("host4"), string("4001")) );
- expectedHost.push_back( make_pair(string("host5"), string("5111")) ); // not specified in host file, hence expect 5111
- expectedHost.push_back( make_pair(string("host6"), string("4081")) );
-
- // Create the ClientEnvironment overriding the config & environment. To specify host and port
- ClientEnvironment client_env( good_host_file , Str::LOCALHOST(),"5111");
-// cout << "client_env " << client_env.toString() << "\n";
- std::string home_host = client_env.host();
- std::string home_port = client_env.port();
- BOOST_CHECK_MESSAGE( Str::LOCALHOST() == home_host && "5111" == home_port,"host host & port not as expected");
-
- std::string host;
-// cout << "client_env home host " << client_env.host() << " job supplied port " << client_env.port() << "\n";
- size_t count = 0;
- bool home_host_fnd = false;
- while (home_host != host) {
- // Cycle through the host until we reach the home host
- std::string errorMsg;
- BOOST_CHECK_MESSAGE( client_env.get_next_host(errorMsg), errorMsg);
-// cout << "client_env host " << client_env.host() << " port " << client_env.port() << "\n";
- host = client_env.host();
- std::string port = client_env.port();
- count++;
- if (host == home_host) {
- BOOST_CHECK_MESSAGE( count-1 == 6, "Expected 6 hosts in host file"); // ignore last increment of count, hence -1
- home_host_fnd = true ;
- count = 0;
- }
- BOOST_REQUIRE_MESSAGE( count < expectedHost.size(), "Test file out of date");
- BOOST_CHECK_MESSAGE( host == expectedHost[count].first, "Expected host " << expectedHost[count].first << " but found " << host);
- BOOST_CHECK_MESSAGE( port == expectedHost[count].second, "Expected port " << expectedHost[count].second << " but found " << port);
- }
- BOOST_CHECK_MESSAGE( home_host_fnd, "Cycling through host file, should lead to home host");
-}
-
-
-BOOST_AUTO_TEST_CASE( test_client_environment_empty_host_file )
-{
- std::cout << "Client:: ...test_client_environment_empty_host_file" << endl;
-
- std::string empty_host_file = File::test_data("Client/test/data/empty_hostfile","Client");
-
- std::string errormsg;
- BOOST_CHECK_MESSAGE(File::create(empty_host_file,"",errormsg), "Failed to create empty host file " << errormsg);
-
- ClientEnvironment client_env( empty_host_file );
- std::string errorMsg;
- BOOST_CHECK_MESSAGE( client_env.get_next_host(errorMsg),errorMsg);
- BOOST_CHECK_MESSAGE( client_env.get_next_host(errorMsg),errorMsg);
-
- fs::remove(empty_host_file);
-}
-
-
-BOOST_AUTO_TEST_CASE( test_client_environment_errors )
-{
- if (getenv("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")) {
- cout << "Client:: ...test_client_environment_errors-ECF_ALLOW_NEW_CLIENT_OLD_SERVER: ignoring test when ECF_ALLOW_NEW_CLIENT_OLD_SERVER specified\n";
- return;
- }
- if (getenv("ECF_PORT")) {
- cout << "Client:: ...test_client_environment_errors-ECF_ALLOW_NEW_CLIENT_OLD_SERVER: ignoring test when ECF_PORT specified\n";
- return;
- }
-
- std::cout << "Client:: ...test_client_environment_errors-ECF_ALLOW_NEW_CLIENT_OLD_SERVER" << endl;
- {
- char* put = const_cast<char*>("ECF_ALLOW_NEW_CLIENT_OLD_SERVER=xx");
- BOOST_CHECK_MESSAGE(putenv(put) == 0,"putenv failed for " << put);
- BOOST_CHECK_THROW(ClientEnvironment client_env, std::runtime_error );
- putenv(const_cast<char*>("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")); // remove from env, otherwise valgrind complains
- }
-
- {
- // ONLY run this test if enviroment variable ECF_PORT not defined
- std::string env = "ECF_ALLOW_NEW_CLIENT_OLD_SERVER=";
- env += Str::LOCALHOST(); env += ":"; env += Str::DEFAULT_PORT_NUMBER(); env += ":xx";
- BOOST_CHECK_MESSAGE(putenv(const_cast<char*>(env.c_str())) == 0,"putenv failed for " << env);
- BOOST_CHECK_THROW(ClientEnvironment client_env, std::runtime_error );
- putenv(const_cast<char*>("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")); // remove from env, otherwise valgrind complains
- }
- {
- std::string env = "ECF_ALLOW_NEW_CLIENT_OLD_SERVER=";
- env += Str::LOCALHOST(); env += ":"; env += Str::DEFAULT_PORT_NUMBER(); env += "xx";
- BOOST_CHECK_MESSAGE(putenv(const_cast<char*>(env.c_str())) == 0,"putenv failed for " << env);
- BOOST_CHECK_THROW(ClientEnvironment client_env, std::runtime_error );
- putenv(const_cast<char*>("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")); // remove from env, otherwise valgrind complains
- }
- {
- std::string env = "ECF_ALLOW_NEW_CLIENT_OLD_SERVER=";
- env += Str::LOCALHOST(); env += Str::DEFAULT_PORT_NUMBER(); env += "12";
- BOOST_CHECK_MESSAGE(putenv(const_cast<char*>(env.c_str())) == 0,"putenv failed for " << env);
- BOOST_CHECK_THROW(ClientEnvironment client_env, std::runtime_error );
- putenv(const_cast<char*>("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")); // remove from env, otherwise valgrind complains
- }
- {
- std::stringstream ss;
- ss << "ECF_ALLOW_NEW_CLIENT_OLD_SERVER=fred:2222:0,bill:333:2222," << Str::LOCALHOST() << ":" << Str::DEFAULT_PORT_NUMBER() << ":xx";
- std::string env = ss.str();
- BOOST_CHECK_MESSAGE(putenv(const_cast<char*>(env.c_str())) == 0,"putenv failed for " << env);
- BOOST_CHECK_THROW(ClientEnvironment client_env, std::runtime_error );
- putenv(const_cast<char*>("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")); // remove from env, otherwise valgrind complains
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_client_environment )
-{
- if (getenv("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")) {
- cout << "Client:: ...test_client_environment-ECF_ALLOW_NEW_CLIENT_OLD_SERVER: ignoring test when ECF_ALLOW_NEW_CLIENT_OLD_SERVER specified\n";
- return;
- }
- if (getenv("ECF_PORT")) {
- cout << "Client:: ...test_client_environment-ECF_ALLOW_NEW_CLIENT_OLD_SERVER: ignoring test when ECF_PORT specified\n";
- return;
- }
-
- std::cout << "Client:: ...test_client_environment-ECF_ALLOW_NEW_CLIENT_OLD_SERVER" << endl;
- {
- std::string env = "ECF_ALLOW_NEW_CLIENT_OLD_SERVER=";
- env += Str::LOCALHOST(); env += ":"; env += Str::DEFAULT_PORT_NUMBER(); env += ":11";
- BOOST_CHECK_MESSAGE(putenv(const_cast<char*>(env.c_str())) == 0,"putenv failed for " << env);
- ClientEnvironment client_env;
- BOOST_CHECK_MESSAGE(client_env.allow_new_client_old_server()==11,"Expected 11 but found " << client_env.allow_new_client_old_server() << " for env " << env);
- putenv(const_cast<char*>("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")); // remove from env, otherwise valgrind complains
- }
- {
- std::stringstream ss;
- ss << "ECF_ALLOW_NEW_CLIENT_OLD_SERVER=fred:2222:0,bill:333:2222," << Str::LOCALHOST() << ":" << Str::DEFAULT_PORT_NUMBER() << ":" << 33;
- std::string env = ss.str();
- BOOST_CHECK_MESSAGE(putenv(const_cast<char*>(env.c_str())) == 0,"putenv failed for " << env);
- ClientEnvironment client_env;
- BOOST_CHECK_MESSAGE(client_env.allow_new_client_old_server()==33,"Expected 33 but found " << client_env.allow_new_client_old_server() << " for env " << env);
- putenv(const_cast<char*>("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")); // remove from env, otherwise valgrind complains
- }
- {
- // Create a valid ECF_ALLOW_NEW_CLIENT_OLD_SERVER list where there is no match with our host/port.
- // hence allow_new_client_old_server should remain zero
- std::stringstream ss;
- ss << "ECF_ALLOW_NEW_CLIENT_OLD_SERVER=fred:2222:0,bill:333:2222,bill:333:2222,bill:333:2222,bill:333:2222,bill:333:2222";
- std::string env = ss.str();
- BOOST_CHECK_MESSAGE(putenv(const_cast<char*>(env.c_str())) == 0,"putenv failed for " << env);
- ClientEnvironment client_env;
- BOOST_CHECK_MESSAGE(client_env.allow_new_client_old_server()==0,"Should remain unchanged but found " << client_env.allow_new_client_old_server());
- putenv(const_cast<char*>("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")); // remove from env, otherwise valgrind complains
- }
- {
- char* put = const_cast<char*>("ECF_ALLOW_NEW_CLIENT_OLD_SERVER=10");
- BOOST_CHECK_MESSAGE(putenv(put) == 0,"putenv failed for " << put);
- ClientEnvironment client_env;
- BOOST_CHECK_MESSAGE(client_env.allow_new_client_old_server()==10,"expcted 10 but found " << client_env.allow_new_client_old_server());
- putenv(const_cast<char*>("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")); // remove from env, otherwise valgrind complains
- }
-}
-
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/Client/test/TestClientInterface.cpp b/ecflow_4_0_7/Client/test/TestClientInterface.cpp
deleted file mode 100644
index 141aa21..0000000
--- a/ecflow_4_0_7/Client/test/TestClientInterface.cpp
+++ /dev/null
@@ -1,515 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #75 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <fstream>
-#include <iostream>
-
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/foreach.hpp>
-
-#include "ClientInvoker.hpp"
-#include "ClientToServerCmd.hpp"
-#include "ClientEnvironment.hpp"
-#include "NState.hpp"
-#include "Defs.hpp"
-#include "Task.hpp"
-#include "Suite.hpp"
-#include "Child.hpp"
-#include "File.hpp"
-#include "Flag.hpp"
-
-namespace fs = boost::filesystem;
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( ClientTestSuite )
-
-// **************************************************************************************
-// test the interface, this will create the cmd without actually submitting to the server
-// This will test argument parsing.
-// **************************************************************************************
-BOOST_AUTO_TEST_CASE( test_client_interface )
-{
- std::cout << "Client:: ...test_client_interface" << endl;
-
- ClientInvoker theClient ;
- theClient.testInterface(); // stops submission to server
- std::vector<std::string> paths; paths.push_back("/s1"); paths.push_back("/s2");
-
- BOOST_REQUIRE_MESSAGE( theClient.delete_all() == 0,CtsApi::to_string(CtsApi::delete_node()) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.shutdownServer() == 0,CtsApi::shutdownServer() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.haltServer() == 0,CtsApi::haltServer() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.restartServer() == 0,CtsApi::restartServer() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.terminateServer() == 0,CtsApi::terminateServer() << " should return 0\n" << theClient.errorMsg());
-
- BOOST_REQUIRE_MESSAGE( theClient.server_version() == 0,CtsApi::server_version() << " should return 0\n" << theClient.errorMsg());
-
- {
- defs_ptr dummy_defs = Defs::create();
- BOOST_REQUIRE_MESSAGE( theClient.sync(dummy_defs) == 0, std::string(CtsApi::syncArg()) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.news(dummy_defs) == 0, std::string(CtsApi::newsArg()) << " should return 0\n" << theClient.errorMsg());
- }
-
- BOOST_REQUIRE_MESSAGE( theClient.server_load("/path/to_log/file") == 0,CtsApi::server_load("/path/to_log/file") << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.server_load() == 0,CtsApi::server_load("") << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.pingServer() == 0,CtsApi::pingServer() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.debug_server_on() == 0,CtsApi::debug_server_on() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.debug_server_off() == 0,CtsApi::debug_server_off() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.stats() == 0,CtsApi::stats() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.stats_reset() == 0,CtsApi::stats_reset() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.suites() == 0,CtsApi::suites() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.getDefs() == 0,CtsApi::get() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.begin("/suite") == 0,CtsApi::begin("/suite") << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.begin("/suite",true) == 0,CtsApi::begin("/suite",true) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.begin("/suite",false) == 0,CtsApi::begin("/suite",false) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.begin_all_suites() == 0,CtsApi::begin() << " should return 0\n" << theClient.errorMsg());
-
-
- Zombie z(Child::USER,ecf::Child::INIT,ZombieAttr::get_default_attr(Child::USER),"path_to_task","DUMMY_JOBS_PASSWORD", "DUMMY_PROCESS_OR_REMOTE_ID",1);
- BOOST_REQUIRE_MESSAGE( theClient.zombieGet() == 0,CtsApi::zombieGet() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.zombieFob(z) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.zombieFail(z) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.zombieAdopt(z) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.zombieBlock(z) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.zombieRemove(z) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.zombieKill(z) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.zombieFobCli("path_to_task") == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.zombieFailCli("path_to_task") == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.zombieAdoptCli("path_to_task") == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.zombieBlockCli("path_to_task") == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.zombieRemoveCli("path_to_task") == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.zombieKillCli("path_to_task") == 0, " should return 0\n" << theClient.errorMsg());
-
- BOOST_REQUIRE_MESSAGE( theClient.job_gen("") == 0,CtsApi::job_gen("") << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.job_gen("/s") == 0,CtsApi::job_gen("/s") << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.check("") == 0,CtsApi::to_string(CtsApi::check("")) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.check("/s") == 0,CtsApi::to_string(CtsApi::check("/s")) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.check(paths) == 0,CtsApi::to_string(CtsApi::check(paths)) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.kill("/s") == 0,CtsApi::to_string(CtsApi::kill("/s")) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.kill(paths) == 0,CtsApi::to_string(CtsApi::kill(paths)) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.status("/s") == 0,CtsApi::to_string(CtsApi::status("/s")) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.status(paths) == 0,CtsApi::to_string(CtsApi::status(paths)) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.suspend("/s") == 0,CtsApi::to_string(CtsApi::suspend("/s"))<< " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.suspend(paths) == 0,CtsApi::to_string(CtsApi::suspend(paths))<< " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.resume("/s") == 0,CtsApi::to_string(CtsApi::resume("/s")) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.resume(paths) == 0,CtsApi::to_string(CtsApi::resume(paths)) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.edit_history("/s") == 0,CtsApi::to_string(CtsApi::edit_history("/s")) << " should return 0\n" << theClient.errorMsg());
-
- // empty string should be same as delete all
- BOOST_REQUIRE_MESSAGE( theClient.delete_node("") == 0,CtsApi::to_string(CtsApi::delete_node()) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.delete_node("/s") == 0,CtsApi::to_string(CtsApi::delete_node("/s")) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.delete_node("/s",true) == 0,CtsApi::to_string(CtsApi::delete_node("/s",true)) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.delete_node("/s",false) == 0,CtsApi::to_string(CtsApi::delete_node("/s",false)) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.delete_nodes(paths,false) == 0,CtsApi::to_string(CtsApi::delete_node(paths,false)) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.delete_nodes(paths,true) == 0,CtsApi::to_string(CtsApi::delete_node(paths,false)) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.delete_all() == 0,CtsApi::to_string(CtsApi::delete_node()) << " should return 0\n" << theClient.errorMsg());
-
- BOOST_REQUIRE_MESSAGE( theClient.requeue("/s","") == 0, CtsApi::to_string(CtsApi::requeue("/s","")) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.requeue("/s","force") == 0, CtsApi::to_string(CtsApi::requeue("/s","force")) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.requeue("/s","abort") == 0, CtsApi::to_string(CtsApi::requeue("/s","abort")) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.requeue(paths,"") == 0, CtsApi::to_string(CtsApi::requeue(paths,"")) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.requeue(paths,"force") == 0,CtsApi::to_string(CtsApi::requeue(paths,"force")) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.requeue(paths,"abort") == 0,CtsApi::to_string(CtsApi::requeue(paths,"abort")) << " should return 0\n" << theClient.errorMsg());
-
-
- BOOST_REQUIRE_MESSAGE( theClient.run("/s") == 0,CtsApi::to_string(CtsApi::run("/s")) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.run("/s",true) == 0,CtsApi::to_string(CtsApi::run("/s",true)) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.run(paths) == 0,CtsApi::to_string(CtsApi::run(paths)) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.run(paths,true) == 0,CtsApi::to_string(CtsApi::run(paths,true)) << " should return 0\n" << theClient.errorMsg());
-
-
- std::string path = File::test_data("Client/test/data/lifecycle.txt","Client");
- BOOST_REQUIRE_MESSAGE( theClient.loadDefs(path) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.loadDefs(path,true/*force*/) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.loadDefs(path,true/*force*/,true/*check_only*/) == 0, "should return 0\n" << theClient.errorMsg());
-
- BOOST_REQUIRE_MESSAGE( theClient.replace("/suite1",path) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.replace("/suite1",path,true) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.replace("/suite1",path,true, true) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.replace("/suite1",path,false, true) == 0, " should return 0\n" << theClient.errorMsg());
-
- BOOST_REQUIRE_MESSAGE( theClient.order("/s","top") == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.order("/s","bottom") == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.order("/s","alpha") == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.order("/s","order") == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.order("/s","up") == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.order("/s","down") == 0, " should return 0\n" << theClient.errorMsg());
-
- BOOST_REQUIRE_MESSAGE( theClient.checkPtDefs() == 0,CtsApi::checkPtDefs() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.checkPtDefs(ecf::CheckPt::NEVER) == 0," should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.checkPtDefs(ecf::CheckPt::ON_TIME) == 0," should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.checkPtDefs(ecf::CheckPt::ON_TIME,180) == 0," should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.checkPtDefs(ecf::CheckPt::ALWAYS) == 0," should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.checkPtDefs(ecf::CheckPt::UNDEFINED) == 0," should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.checkPtDefs(ecf::CheckPt::UNDEFINED,0,35) == 0," should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.restoreDefsFromCheckPt() == 0,CtsApi::restoreDefsFromCheckPt() << " should return 0\n" << theClient.errorMsg());
-
- std::vector<std::string> event_paths; event_paths.push_back("/s1:e"); event_paths.push_back("/s2/f1/t1:e");
- BOOST_REQUIRE_MESSAGE( theClient.force(event_paths[0],"set") == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.force(event_paths[1],"clear") == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.force(event_paths,"set") == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.force(event_paths,"clear") == 0," should return 0\n" << theClient.errorMsg());
- std::vector<std::string> validStates = NState::allStates(); // HPUX barfs if use NState::allStates() directly
- BOOST_FOREACH(const string& state, validStates) {
- BOOST_REQUIRE_MESSAGE( theClient.force("/s",state,true,true) == 0, "force " << state << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.force(paths,state,true,true) == 0, "force " << state << " should return 0\n" << theClient.errorMsg());
- }
-
- BOOST_REQUIRE_MESSAGE( theClient.freeDep("/s") == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.freeDep("/s",true,true,true,true) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.freeDep("/s",true) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.freeDep("/s",false,true) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.freeDep("/s",false,false,true) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.freeDep("/s",false,false,false,true) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.freeDep(paths) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.freeDep(paths,true,true,true,true) == 0, " should return 0\n" << theClient.errorMsg());
-
- std::vector<CFileCmd::File_t> fileTypesVec = CFileCmd::fileTypesVec();
- for(size_t i = 0; i < fileTypesVec.size(); i++) {
- BOOST_REQUIRE_MESSAGE( theClient.file("/s",CFileCmd::toString(fileTypesVec[i]),string("100")) == 0, " should return 0\n" << theClient.errorMsg());
- }
-
- BOOST_REQUIRE_MESSAGE( theClient.plug("/source","/dest") == 0, " should return 0\n" << theClient.errorMsg());
-
- {
- BOOST_REQUIRE_MESSAGE( theClient.getLog(10) == 0," should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.clearLog() == 0, CtsApi::clearLog() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.flushLog() == 0, CtsApi::flushLog() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.get_log_path() == 0, CtsApi::get_log_path() << " should return 0\n" << theClient.errorMsg());
-
- std::string new_log_path = File::test_data("Client/test/data/new_log.log","Client");
- BOOST_REQUIRE_MESSAGE( theClient.new_log(new_log_path) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.new_log("") == 0, " should return 0\n" << theClient.errorMsg());
- }
-
- BOOST_REQUIRE_MESSAGE( theClient.reloadwsfile() == 0,CtsApi::reloadwsfile() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.forceDependencyEval() == 0, CtsApi::forceDependencyEval() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.group("shutdown yes;halt yes;restart") == 0,"--group should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.group("get ; show") == 0,"--group should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.group("get ; show state") == 0,"--group should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.group("get ; show defs") == 0,"--group should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.group("get ; show migrate") == 0,"--group should return 0\n" << theClient.errorMsg());
-
-
- {
- std::string path_to_script = "dummy_ecf_file" + File::ECF_EXTN();
- std::string contents = "%comment\n"
- "VAR = fred\n"
- "%end\n"
- "# rest of the ecf file\n";
- std::string error_msg;
- BOOST_CHECK_MESSAGE(File::create(path_to_script,contents,error_msg),error_msg);
-
- std::vector<std::string> file_contents;
- NameValueVec used_variables;
- BOOST_REQUIRE_MESSAGE( theClient.edit_script_edit("/s") == 0,"--edit_script_edit should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.edit_script_preprocess("/s") == 0,"--edit_script_preprocess should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.edit_script_preprocess("/s",file_contents) == 0,"--edit_script_preprocess should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.edit_script_submit("/s",used_variables) == 0,"--edit_script_submit should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.edit_script_submit("/s",used_variables,file_contents) == 0,"--edit_script_submit should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.edit_script_submit("/s",used_variables,file_contents,true/*alias*/) == 0,"--edit_script_submit should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.edit_script_submit("/s",used_variables,file_contents,true/*alias*/,true/*run*/) == 0,"--edit_script_submit should return 0\n" << theClient.errorMsg());
-
- BOOST_REQUIRE_MESSAGE( theClient.edit_script("/s","edit") == 0,"--edit_script should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.edit_script("/s","pre_process") == 0,"--edit_script should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.edit_script("/s","submit",path_to_script) == 0,"--edit_script should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.edit_script("/s","submit_file",path_to_script) == 0,"--edit_script should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.edit_script("/s","submit_file",path_to_script,true) == 0,"--edit_script should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.edit_script("/s","submit_file",path_to_script,false) == 0,"--edit_script should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.edit_script("/s","submit_file",path_to_script,false,true) == 0,"--edit_script should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.edit_script("/s","submit_file",path_to_script,false,false) == 0,"--edit_script should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.edit_script("/s","pre_process_file",path_to_script) == 0,"--edit_script should return 0\n" << theClient.errorMsg());
- fs::remove(path_to_script);
- }
-
- {
- std::vector<std::string> suites; suites.push_back("a"); suites.push_back("b");
- BOOST_REQUIRE_MESSAGE( theClient.ch_register(true,suites) == 0,"--ch_register \n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.ch_register(false,suites) == 0,"--ch_register \n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.ch_suites() == 0,"--ch_suites should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.ch_drop(1) == 0,"--ch_drop should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.ch_drop_user("user") == 0,"--ch_drop_user should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.ch_add(1,suites) == 0,"--ch_add \n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.ch_remove(1,suites) == 0,"--ch_remove \n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.ch_auto_add(1,true) == 0,"--ch_auto_add \n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.ch_auto_add(1,false) == 0,"--ch_auto_add \n" << theClient.errorMsg());
- // need test interface that allows client handle to set on ClinetInvoker
-// BOOST_REQUIRE_MESSAGE( theClient.ch1_drop() == 0,"--ch1_drop \n" << theClient.errorMsg());
-// BOOST_REQUIRE_MESSAGE( theClient.ch1_add(suites) == 0,"--ch1_add \n" << theClient.errorMsg());
-// BOOST_REQUIRE_MESSAGE( theClient.ch1_remove(suites) == 0,"--ch1_remove \n" << theClient.errorMsg());
-// BOOST_REQUIRE_MESSAGE( theClient.ch1_auto_add(true) == 0,"--ch1_auto_add \n" << theClient.errorMsg());
-// BOOST_REQUIRE_MESSAGE( theClient.ch1_auto_add(false) == 0,"--ch1_auto_add \n" << theClient.errorMsg());
- }
-
- {
- defs_ptr theDefs = Defs::create();
- theDefs->addSuite( Suite::create("s1") );
- BOOST_REQUIRE_MESSAGE( theClient.load( theDefs ) == 0,"-- load should return 0\n" << theClient.errorMsg());
- }
-
- /// test alter
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","zombie","ecf:fob::10") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","zombie","ecf:fob::") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","zombie","user:fob::10") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","zombie","path:fob::10") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","zombie","path:fob::") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","zombie","ecf:fob:init,event,meter,label,wait,complete,abort:10") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","zombie","ecf:fob:init,event,meter,label,wait,complete:10") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","zombie","ecf:fail:init,event,meter,label,wait,complete:10000") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","zombie","ecf:adopt:init,event,meter,label,wait,complete:23") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","zombie","ecf:remove:init,event,meter,label,wait,complete:0") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","zombie","ecf:block:init,event,meter,label,wait,complete:") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","zombie","ecf:kill:init,event,meter,label,wait,complete:103333333") == 0,"--alter should return 0\n" << theClient.errorMsg());
-
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","time","+12:00") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","time","+10:00 20:00 00:30") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","today","12:00") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","today","10:00 20:00 00:30") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","date","12.12.2009") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","date","*.12.2009") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","date","*.*.2009") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","date","*.*.*") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","variable","name","value") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","variable","name","/value/with/path") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/", "add","variable","name","value") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/", "add","variable","name","/value/with/path") == 0,"--alter should return 0\n" << theClient.errorMsg());
-
- std::vector<std::string> validDays = DayAttr::allDays(); // HPUX barfs if use DayAttr::allDays() directly in BOOST_FOREACH
- BOOST_FOREACH(const string& day, validDays) {
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","day",day) == 0,"--alter should return 0\n" << theClient.errorMsg());
- }
- BOOST_REQUIRE_MESSAGE( theClient.alter("/", "delete","variable","varName") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","variable","varName") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","variable") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","time") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","time","+12:00") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","time","+10:00 20:00 00:30") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","today") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","today","12:00") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","today","10:00 20:00 00:30") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","date") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","date","12.12.2009") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","date","*.12.2009") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","date","*.*.2009") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","date","*.*.*") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","day","sunday") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","day") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","23:00") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","10:00 20:00 01:00") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","-w 0,1 10:00") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","-d 10,11,12 12:00") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","-w 0 -m 5,6,7,8 10:00 20:00 01:00") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","event","name") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","event","1") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","event") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","meter","name") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","meter") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","trigger") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","complete") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","repeat") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","limit","name") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","limit_path","limit_name","path") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","limit_path","limit_name","/path/with/slash") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","inlimit","name") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","zombie","user") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","zombie","ecf") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","zombie","path") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","variable","name","newValue") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","variable","name","/new/value/with/path") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_type","hybrid") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_type","real") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_date","12.6.2013") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_gain","20") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_sync") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","event","22","set") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","event","33","clear") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","event","4") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","event","name","set") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","event","name","clear") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","event","name") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","meter","name","20") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","meter","name","-1") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","label","name","newValue") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","trigger","(t:step + 20) ge (t:step1 - 20)") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","trigger","/suite/fred == complete") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","trigger","/suite/fred:event") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","complete","not ( a == complete )") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","complete","/trigger/with/leading/slash == aborted") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","complete","/trigger/with/leading/slash:event") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","repeat","1") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","repeat","blue") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","limit_max","limit_name","12") == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","limit_value","limit_name","12") == 0,"--alter should return 0\n" << theClient.errorMsg());
-
- std::vector<std::string> dstates = DState::allStates();
- for(size_t i = 0; i < dstates.size(); i++) {
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","defstatus",dstates[i]) == 0,"--alter should return 0\n" << theClient.errorMsg());
- }
-
- std::vector<std::string> flag_types;
- Flag::valid_flag_type(flag_types);
- for(size_t i = 0; i < flag_types.size(); i++) {
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","set_flag",flag_types[i]) == 0,"--alter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","clear_flag",flag_types[i]) == 0,"--alter should return 0\n" << theClient.errorMsg());
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_client_interface_for_fail )
-{
- std::cout << "Client:: ...test_client_interface_for_fail" << endl;
-
- ClientInvoker theClient ;
- theClient.testInterface(); // stops submission to server
- theClient.set_throw_on_error(false);
-
- std::vector<std::string> paths; paths.push_back("/s1"); paths.push_back("/s2");
-
- /// test alter
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","time","") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","time","012:00") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","time","1200") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","time","fred") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","time","+10:0020:00 00:30") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","time","+10:00 2000 00:30") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","time","+1000 20:00 00:30") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","time","+10:00 20:00 0030") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","time","any old rubbish") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","today","+10:0020:00 00:30") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","today","+10:00 2000 00:30") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","today","+1000 20:00 00:30") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","today","+10:00 20:00 0030") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","today","any old rubbish") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","today","") == 1,"--alter expected to fail\n" << theClient.errorMsg());
-
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","date","") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","date","0.12.2009") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","date","12.0.2009") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","date","12.12.g") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","date","*..2009") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","date","12..2009") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","date","12.12.") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","date","fred") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","date","any old rubbish") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","day","frenday") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","day","") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","day","opps ") == 1,"--alter expected to fail\n" << theClient.errorMsg());
-
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","add","variable","na me","value") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/", "add","variable","na me","value") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/", "add","variable","","value") == 1,"--alter expected to fail\n" << theClient.errorMsg());
-
-
- BOOST_REQUIRE_MESSAGE( theClient.alter("/", "delete","vari able","varName") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","v ariable","varName") == 1,"--alter expected to fail\n" << theClient.errorMsg());
-
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","time","012:00") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","time","1200") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","time","fred") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","time","+10:0020:00 00:30") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","time","+10:00 2000 00:30") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","time","+1000 20:00 00:30") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","time","+10:00 20:00 0030") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","time","any old rubbish") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","today","+10:0020:00 00:30") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","today","+10:00 2000 00:30") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","today","+1000 20:00 00:30") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","today","+10:00 20:00 0030") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","today","any old rubbish") == 1,"--alter expected to fail\n" << theClient.errorMsg());
-
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","date","0.12.2009") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","date","12.0.2009") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","date","12.12.g") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","date","*..2009") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","date","12..2009") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","date","12.12.") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","date","fred") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","date","any old rubbish") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","day","su nday") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","day","fryday") == 1,"--alter expected to fail\n" << theClient.errorMsg());
-
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","any old rubbish") == 1,"Expected fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","2300") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","1000 20:00 01:00") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","-w 0,1 1000'") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","-w 1000") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","-d 10,11,12 1200") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","-d 10,11,12") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","-d 1200") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","-w 0 -m 5,6,7,8 10:00 20:00 01:000") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","-w 0 -m 5,6,7,8 10:00 20:00 0100") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","-w -m 20:00 01:00") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","-w 0 -m 5,6,7,8 1000 20:00 01:00") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","-w 20 -m 5,6,7,8 10:00 20:00 01:00") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","cron","-w 0 -m 5,6,7,8,24 10:00 20:00 01:00") == 1,"--alter expected to fail\n" << theClient.errorMsg());
-
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","event","name df") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","event","22 56 ") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","meter","na me") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","limit"," name") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","delete","inlimit","na me") == 1,"--alter expected to fail\n" << theClient.errorMsg());
-
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","vari able","name","newValue") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","","name","/new/value/with/path") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_type","") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_type","hyb rid") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_type","hybrid ") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_type","ybrid") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_type","re al") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_type","rreal") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_date","*.6.2013") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_date","12.0.2013") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_date","any old rubbish") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_date","") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_gain","string") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_gain","") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","clock_gain","fred") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","event","name","fr ed") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","event","na me") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","meter","name","") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","meter","na me","20") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","meter","name","-") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","label","na me","newValue") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","trigger","t:step + 20) ge (t:step1 - 20)") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","complete","not a == complete )") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","limit_max","limit_ name","12") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","limit_value","limit_ name","12") == 1,"--alter expected to fail\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.alter("/s1","change","defstatus","complete-34") == 1,"--alter expected to fail\n" << theClient.errorMsg());
-}
-
-
-BOOST_AUTO_TEST_CASE( test_client_task_interface )
-{
- std::cout << "Client:: ...test_client_task_interface" << endl;
-
- ClientInvoker theClient ;
- theClient.testInterface(); // stops submission to server
- theClient.taskPath("/a/made/up/path");
- theClient.set_jobs_password( Submittable::DUMMY_JOBS_PASSWORD() );
-
- BOOST_REQUIRE_MESSAGE( theClient.initTask(Submittable::DUMMY_PROCESS_OR_REMOTE_ID()) == 0,"--init should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.abortTask("reason for abort") == 0,"--abort should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.eventTask("event_name") == 0,"--event should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.meterTask("meter_name","20") == 0,"--meter should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.waitTask("a == complete") == 0,"--wait should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.completeTask() == 0,"--complete should return 0\n" << theClient.errorMsg());
- std::vector<std::string> labels; labels.push_back("test_client_task_interface");
- BOOST_REQUIRE_MESSAGE( theClient.labelTask("label_name",labels) == 0,"--label should return 0\n" << theClient.errorMsg());
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/Client/test/TestClientInvoker.cpp b/ecflow_4_0_7/Client/test/TestClientInvoker.cpp
deleted file mode 100644
index b8cfca0..0000000
--- a/ecflow_4_0_7/Client/test/TestClientInvoker.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #9 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <iostream>
-#include <vector>
-#include <string>
-
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-
-#include "ClientInvoker.hpp"
-#include "Str.hpp"
-#include "File.hpp"
-
-namespace fs = boost::filesystem;
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( ClientTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_client_invoker )
-{
- if (getenv("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")) {
- cout << "Client:: ...test_client_invoker: ignoring test when ECF_ALLOW_NEW_CLIENT_OLD_SERVER specified\n";
- return;
- }
-
- std::cout << "Client:: ...test_client_invoker" << endl;
- {
- char* put = const_cast<char*>("ECF_ALLOW_NEW_CLIENT_OLD_SERVER=10");
- BOOST_CHECK_MESSAGE(putenv(put) == 0,"putenv failed for " << put);
- ClientInvoker invoker;
- BOOST_CHECK_MESSAGE(invoker.allow_new_client_old_server()==10,"Expected 10 but found " << invoker.allow_new_client_old_server() << " for env " << put);
- putenv(const_cast<char*>("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")); // remove from env, otherwise valgrind complains
- }
- {
- std::stringstream ss;
- ss << "ECF_ALLOW_NEW_CLIENT_OLD_SERVER=fred:2222:12,bill:3333:2222,bill4:6666:1313";
- std::string env = ss.str();
- BOOST_CHECK_MESSAGE(putenv(const_cast<char*>(env.c_str())) == 0,"putenv failed for " << env);
- ClientInvoker invoker("bill","3333");
- BOOST_CHECK_MESSAGE(invoker.allow_new_client_old_server()==2222,"Expected 2222 but found " << invoker.allow_new_client_old_server() << " for env " << env);
-
- invoker.set_host_port("bill4","6666");
- BOOST_CHECK_MESSAGE(invoker.allow_new_client_old_server()==1313,"Expected 1313 but found " << invoker.allow_new_client_old_server() << " for env " << env);
- putenv(const_cast<char*>("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")); // remove from env, otherwise valgrind complains, + *COULD* affect other tests
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/Client/test/TestClientTimeout.cpp b/ecflow_4_0_7/Client/test/TestClientTimeout.cpp
deleted file mode 100644
index 669fd84..0000000
--- a/ecflow_4_0_7/Client/test/TestClientTimeout.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-////============================================================================
-//// Name :
-//// Author : Avi
-//// Revision : $Revision: #5 $
-////
-//// Copyright 2009-2012 ECMWF.
-//// This software is licensed under the terms of the Apache Licence version 2.0
-//// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-//// In applying this licence, ECMWF does not waive the privileges and immunities
-//// granted to it by virtue of its status as an intergovernmental organisation
-//// nor does it submit to any jurisdiction.
-////
-//// Description :
-////============================================================================
-//#include <string>
-//#include <fstream>
-//
-//#include "boost/filesystem/operations.hpp"
-//#include "boost/filesystem/path.hpp"
-//#include <boost/test/unit_test.hpp>
-//
-//#include "ClientInvoker.hpp"
-//#include "ClientEnvironment.hpp"
-//#include "InvokeServer.hpp"
-//#include "SCPort.hpp"
-//#include "Str.hpp"
-//
-//namespace fs = boost::filesystem;
-//using namespace std;
-//using namespace ecf;
-//
-//BOOST_AUTO_TEST_SUITE( ClientTestSuite )
-//
-//// ************************************************************************************
-//// Note: If you make edits to node tree, they will have no effect until the server is rebuilt
-//// ************************************************************************************
-//
-///// This test will check the timeoout feature of the Client
-///// The timeout feature allow the client to fail gracefully in the case
-///// where the server has died/crashed. The timeout will ensure the scoket is closed.
-///// allowing the server to be restarted withou getting the address is use error.
-//BOOST_AUTO_TEST_CASE( test_client_timeout )
-//{
-// // This will remove check pt and backup file before server start, to avoid the server from loading previous test data
-// InvokeServer invokeServer("Client:: ...test_client_timeout",SCPort::next());
-//
-// // The timeout is configured to vary according the the client request
-// // however we can override for testing.
-// // Here we set a timeout for 1 second, then attempt to load a very large definition into the server.
-// // Note: the timeout of 1 second means we have 1 second for each communication, hence:
-// // connect : 1 second
-// // send request : 1 second
-// // receive reply : 1 second
-// ClientInvoker theClient(invokeServer.host(),invokeServer.port());
-// theClient.set_timeout(1);
-//
-// std::string path = File::test_data("AParser/test/data/single_defs/mega.def","AParser");
-// BOOST_REQUIRE_THROW(theClient.loadDefs(path),std::runtime_error); // Expected load defs to fail with a timeout of 1 second\n
-//
-// /// Now see what timeout value we succeed with
-// bool loaded_defs = false;
-// for(int i = 2; i < 10; ++i) {
-// theClient.set_timeout(i);
-// try {
-// cout << "Trying with timeout of " << i << " seconds\n";
-// theClient.loadDefs(path);
-// cout << " loaded mega defs with a timeout of " << i << " seconds\n";
-// loaded_defs = true;
-// break;
-// }
-// catch (...) {}
-// }
-// BOOST_REQUIRE_MESSAGE(loaded_defs,"Expected load of defs to succeed\n");
-//}
-//
-//BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/Client/test/TestGroupCmd.cpp b/ecflow_4_0_7/Client/test/TestGroupCmd.cpp
deleted file mode 100644
index 0ef2e2a..0000000
--- a/ecflow_4_0_7/Client/test/TestGroupCmd.cpp
+++ /dev/null
@@ -1,219 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #37 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <fstream>
-
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-
-#include "ClientInvoker.hpp"
-#include "ClientEnvironment.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "File.hpp"
-#include "PrintStyle.hpp"
-#include "InvokeServer.hpp"
-#include "SCPort.hpp"
-
-namespace fs = boost::filesystem;
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( ClientTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_group_cmd )
-{
- // The previous test's has created/destroyed a server process
- // If two different process both try to use the same port number, you
- // get an "Address in use" error, even if one the process is dead. This is
- // because the kernel does not immediately release the resource and there is
- // time out period. To get round this we will start the new server/client
- // and use a different port number. the default is 3141
-
- // This will remove check pt and backup file before server start, to avoid the server from loading previous test data
- InvokeServer invokeServer("Client:: ...test_group_cmd",SCPort::next());
-
- ClientInvoker theClient(invokeServer.host(),invokeServer.port());
- BOOST_REQUIRE_MESSAGE( theClient.group("shutdown yes;halt yes;restart") == 0,"--group should return 0\n" << theClient.errorMsg());
-}
-
-BOOST_AUTO_TEST_CASE( test_client_group_lifecyle )
-{
- /// *** This test is the same as in file TestServerAndLifeCyle.cpp only this time
- /// *** we use the group command where ever possible
- // This will remove check pt and backup file before server start, to avoid the server from loading previous test data
-
- // ** NOTE: We disable job generation in the server **/
- InvokeServer invokeServer("Client:: ...test_client_group_lifecyle",SCPort::next(),true /*disable job generation in server*/);
-
- ClientInvoker theClient(invokeServer.host(),invokeServer.port());
-
- {
- // restart server, load lifecycle, and get the defs tree from the server
- std::string groupRequest ="--restart; load=";
- groupRequest += File::test_data("Client/test/data/lifecycle.txt","Client");
- groupRequest += "; get";
-
- BOOST_REQUIRE_MESSAGE( theClient.group(groupRequest) == 0,"Group request " << CtsApi::group(groupRequest) << " failed should return 0\n" << theClient.errorMsg());
- defs_ptr serverDefs = theClient.defs();
- BOOST_REQUIRE_MESSAGE( serverDefs.get(),"Server returned a NULL defs");
- BOOST_REQUIRE_MESSAGE( serverDefs->suiteVec().size() >= 1," no suite ?");
- }
-
- // Now go through and simulate client request to change Node tree state.
- // This is **highly** dependent on lifecycle.txt
- // suite suite1
- // family family1
- // task a
- // event 1 myEvent
- // meter myMeter 0 100
- // task b
- // trigger a == complete
- // endfamily
- // family family2
- // task aa
- // trigger ../family1/a:myMeter >= 20 and ../family1/a:myEvent
- // task bb
- // trigger ../family1/a:myMeter >= 50 || ../family1/a:myEvent
- // endfamily
- // endsuite
- string suite1_family1_a = "suite1/family1/a";
- string suite1_family1_b = "suite1/family1/b";
- string suite1_family2_aa = "suite1/family2/aa";
- string suite1_family2_bb = "suite1/family2/bb";
-
-
- // ***********************************************************************
- // Create a request to initialise Node: suite1/family1/a
- // Create a request to set the event on Node suite1/family1/a
- // This should place suite1_family2_bb immediately into submitted state
- // Since we at least one node in ACTIVE, suite should be in ACTIVE state
- {
- theClient.taskPath(suite1_family1_a);
- theClient.set_jobs_password(Submittable::DUMMY_JOBS_PASSWORD());
-
- // make sure to use same ECF_RID if its specified
- std::string remote_id= "process_or_remote_id";
- if (!theClient.process_or_remote_id().empty()) remote_id = theClient.process_or_remote_id();
- std::string groupRequest ="begin=suite1; init=";
- groupRequest += remote_id;
- groupRequest += "; event=myEvent; force-dep-eval; get";
-
- BOOST_REQUIRE_MESSAGE(theClient.group(groupRequest) == 0,"Group request " << groupRequest << " failed should return 0\n" << theClient.errorMsg());
-
- defs_ptr serverDefs = theClient.defs();
- // PrintStyle style(PrintStyle::STATE);
- // cerr << *serverDefs.get() << "\n";
- BOOST_REQUIRE_MESSAGE( serverDefs.get(),"get command failed to get node tree from server");
-
- node_ptr node = serverDefs->findAbsNode(suite1_family1_a);
- BOOST_REQUIRE_MESSAGE( node->state() == NState::ACTIVE, "Node expected NState::ACTIVE, but found to be " << NState::toString(node->state()));
- node_ptr nodeb = serverDefs->findAbsNode(suite1_family2_bb);
- BOOST_REQUIRE_MESSAGE( nodeb->state() == NState::ACTIVE, "Node expected NState::ACTIVE, but found to be " << NState::toString(nodeb->state()));
- }
-
-
- //**********************************************************************
- // Create a request to set the Meter on Node suite1/family1/a
- // This should force suite1_family2_aa immediately into submitted state
- // This should force suite1_family2_bb immediately into submitted state
- {
- theClient.taskPath(suite1_family1_a);
- std::string groupRequest ="meter=myMeter 100; force-dep-eval; get";
- BOOST_REQUIRE_MESSAGE( theClient.group(groupRequest) == 0,"Group request " << CtsApi::group(groupRequest) << " failed should return 0\n" << theClient.errorMsg());
-
- defs_ptr serverDefs = theClient.defs();
- BOOST_REQUIRE_MESSAGE( serverDefs.get(),"get command failed to get node tree from server");
-
- node_ptr nodeaa = serverDefs->findAbsNode(suite1_family2_aa);
- BOOST_REQUIRE_MESSAGE( nodeaa->state() == NState::ACTIVE, "Node expected NState::ACTIVE, but found to be " << NState::toString(nodeaa->state()));
-
- node_ptr nodebb = serverDefs->findAbsNode(suite1_family2_bb);
- BOOST_REQUIRE_MESSAGE( nodebb->state() == NState::ACTIVE, "Node expected NState::ACTIVE, but found to be " << NState::toString(nodebb->state()));
- }
-
- //**********************************************************************
- // Create a request to complete task suite1/family1/a
- // This should force suite1_family1_b to complete
- // Resolve dependencies
- // We could either wait 60 second or
- // added a custom command that will force dependency evaluation
- {
- theClient.taskPath(suite1_family1_a);
- std::string groupRequest ="complete;force-dep-eval;get";
- BOOST_REQUIRE_MESSAGE( theClient.group(groupRequest) == 0,"Group request " << CtsApi::group(groupRequest) << " failed should return 0\n" << theClient.errorMsg());
-
- defs_ptr serverDefs = theClient.defs();
- BOOST_REQUIRE_MESSAGE( serverDefs.get(),"get command failed to get node tree from server");
-
- node_ptr node = serverDefs->findAbsNode(suite1_family1_b);
- BOOST_REQUIRE_MESSAGE( node->state() == NState::ACTIVE, "Expected NState::ACTIVE, but found " << NState::toString(node->state()));
- }
-
- //********************************************************************************
- // Complete the remaining tasks. Should really call init first, but what the eck.
- //
- // Get the node tree back from the server, and check its node state
- // All node state should be complete. + check meter/event value was set properly
-
- {
- theClient.taskPath(suite1_family1_b);
- BOOST_REQUIRE_MESSAGE(theClient.completeTask() == 0,TaskApi::complete() << " failed should return 0\n" << theClient.errorMsg());
-
- theClient.taskPath(suite1_family2_aa);
- BOOST_REQUIRE_MESSAGE(theClient.completeTask() == 0,TaskApi::complete() << " failed should return 0\n" << theClient.errorMsg());
-
- theClient.taskPath(suite1_family2_bb);
- std::string groupRequest ="complete;force-dep-eval;get";
- BOOST_REQUIRE_MESSAGE( theClient.group(groupRequest) == 0,"Group request " << CtsApi::group(groupRequest) << " failed should return 0\n" << theClient.errorMsg());
-
-
- defs_ptr serverDefs = theClient.defs();
- BOOST_REQUIRE_MESSAGE( serverDefs.get(),"get command failed to get node tree from server");
-
- std::string metername = "myMeter";
- int meterValue = 100;
- node_ptr node = serverDefs->findAbsNode(suite1_family1_a);
- const Meter& theMeter = node->findMeter(metername);
- BOOST_REQUIRE_MESSAGE( !theMeter.empty(), "Could not find the meter");
- BOOST_REQUIRE_MESSAGE( theMeter.value() == meterValue , "Expected meter value " << meterValue << " but found " << theMeter.value());
- {
- std::string errorMsg; BOOST_REQUIRE_MESSAGE( serverDefs->checkInvariants(errorMsg), errorMsg);
- }
-
- std::string eventname = "myEvent";
- const Event& theEvent = node->findEventByNameOrNumber(eventname);
- BOOST_REQUIRE_MESSAGE( !theEvent.empty(), "Could not find the event myEvent");
- BOOST_REQUIRE_MESSAGE( theEvent.value(), "The event was not set");
-
- const std::vector<suite_ptr>& suiteVec = serverDefs->suiteVec();
- suite_ptr suite = suiteVec.back();
- BOOST_REQUIRE_MESSAGE( suite->state() == NState::COMPLETE,
- "Suite expected NState::COMPLETE, but found to be " << NState::toString(suite->state()));
- }
-
- {
- // Check that a log file was created, by asking the server for it.
- BOOST_REQUIRE_MESSAGE( theClient.getLog() == 0, "get log failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(!theClient.get_string().empty(),"The log file returned from the server is empty!!");
-
- // Clear the log
- BOOST_REQUIRE_MESSAGE( theClient.clearLog() == 0,CtsApi::clearLog() << " failed should return 0\n" << theClient.errorMsg());
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/Client/test/TestJobGenOnly.cpp b/ecflow_4_0_7/Client/test/TestJobGenOnly.cpp
deleted file mode 100644
index 8a8d6ba..0000000
--- a/ecflow_4_0_7/Client/test/TestJobGenOnly.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #40 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <iostream>
-#include <fstream>
-
-#include "boost/make_shared.hpp"
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/test/unit_test.hpp>
-#include <boost/foreach.hpp>
-#include <boost/timer.hpp>
-
-#include "Defs.hpp"
-#include "DefsStructureParser.hpp"
-#include "NodeAttr.hpp"
-#include "Suite.hpp"
-#include "Task.hpp"
-#include "Str.hpp"
-#include "File.hpp"
-#include "EcfFile.hpp"
-#include "ExprAst.hpp"
-#include "TestHelper.hpp"
-#include "JobCreationCtrl.hpp"
-
-using namespace std;
-using namespace ecf;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( ClientTestSuite )
-
-// Tests the Job generation against the OLD sms
-BOOST_AUTO_TEST_CASE( test_jobgenonly )
-{
- cout << "Client:: ...test_jobgenonly" << endl;
-
- // Define paths to ECF_HOME and location of the defs file
-
- std::string defsFile = File::test_data("Client/test/data/jobgenonly.def","Client");
- std::string ecf_home = File::test_data("Client/test/data/ECF_HOME","Client");
-
- /// Remove existing job file if any.
- /// Job file location may NOT be same as ecf file.
- /// The default Job location is defined by generated variable ECF_JOB
- /// ECF_JOB = ECF_HOME/<abs node path>.job<try_no>.
- std::vector<std::string> generatedFiles; generatedFiles.reserve(5);
- std::string t1_job = ecf_home + "/suite/family/t1.job0"; generatedFiles.push_back(t1_job);
- std::string t2_job = ecf_home + "/suite/family/t2.job0"; generatedFiles.push_back(t2_job);
- std::string t3_job = ecf_home + "/suite/family/t3.job0"; generatedFiles.push_back(t3_job);
-
- // See EcfFile.cpp: To enable generation of man files, for test. i.e DEBUG_MAN_FILE
-#ifdef DEBUG_MAN_FILE
- std::string t1_man = ecf_home + "/suite/family/t1.man"; generatedFiles.push_back(t1_man);
- std::string t3_man = ecf_home + "/suite/family/t3.man"; generatedFiles.push_back(t3_man);
-#endif
- BOOST_FOREACH(const std::string& s, generatedFiles ) { fs::remove(s); }
- BOOST_FOREACH(const std::string& s, generatedFiles ) { BOOST_REQUIRE_MESSAGE(!fs::exists(s),"Could not delete file " << s); }
-
-
- // Load the defs file 'jobgenonly.def'
- Defs theDefs;
- DefsStructureParser checkPtParser( &theDefs, defsFile );
- std::string errorMsg,warningMsg;
- BOOST_REQUIRE_MESSAGE(checkPtParser.doParse(errorMsg,warningMsg),errorMsg);
-
- // Override ECF_HOME. ECF_HOME is needed to locate to the .ecf files
- theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(),ecf_home);
-
- // provide definition of ECF_CLIENT. This should replace smsinit, smscomplete, smsevent,etc
- // with path to the ecf client
- std::string clientPath = File::find_ecf_client_path();
- BOOST_REQUIRE_MESSAGE( !clientPath.empty(), "Could not find path to client executable");
- theDefs.set_server().add_or_update_user_variables("ECF_CLIENT",clientPath);
-
- // JobCreationCtrl is used control what node we generate the jobs for:
- // Since we have not set the node on it, we force job generation for all tasks
- job_creation_ctrl_ptr jobCtrl = boost::make_shared<JobCreationCtrl>();
- theDefs.check_job_creation(jobCtrl);
- BOOST_REQUIRE_MESSAGE(jobCtrl->get_error_msg().empty(), jobCtrl->get_error_msg());
- BOOST_REQUIRE_MESSAGE(jobCtrl->fail_submittables().empty(),"Expected no failing tasks");
-
- // Check if jobs file were generated.
- BOOST_FOREACH(const std::string& s, generatedFiles ) { BOOST_REQUIRE_MESSAGE(fs::exists(s),"File " << s << " should have been created"); }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Client/test/TestLifeCycle.cpp b/ecflow_4_0_7/Client/test/TestLifeCycle.cpp
deleted file mode 100644
index 6d9cecd..0000000
--- a/ecflow_4_0_7/Client/test/TestLifeCycle.cpp
+++ /dev/null
@@ -1,216 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #50 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <iostream>
-#include <fstream>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include "boost/progress.hpp"
-#include <boost/test/unit_test.hpp>
-
-#include "DefsStructureParser.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "TestHelper.hpp"
-#include "JobsParam.hpp"
-#include "Jobs.hpp"
-#include "File.hpp"
-
-namespace fs = boost::filesystem;
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( ClientTestSuite)
-
-BOOST_AUTO_TEST_CASE( test_node_tree_lifecycle )
-{
- cout << "Client:: ...test_node_tree_lifecycle" << endl;
-
- std::string path = File::test_data("Client/test/data/lifecycle.txt","Client");
-
- Defs defs;
- DefsStructureParser checkPtParser( &defs, path );
- std::string errorMsg,warningMsg;
- bool parse = checkPtParser.doParse(errorMsg,warningMsg);
- if (!parse) std::cerr << errorMsg;
- BOOST_CHECK(parse);
-
- // Now go through and simulate client request to change Node tree state.
- // This is **highly** dependent on lifecycle.txt
-// suite suite1
-// family family1
-// task a
-// event 1 myEvent
-// meter myMeter 0 100
-// task b
-// trigger a == complete
-// endfamily
-// family family2
-// task aa
-// trigger ../family1/a:myMeter >= 20 and ../family1/a:myEvent
-// task bb
-// trigger ../family1/a:myMeter >= 50 || ../family1/a:myEvent
-// endfamily
-// endsuite
-
- // get the suite, before we do anything initial state should be UNKNOWN
- const std::vector<suite_ptr>& suiteVec = defs.suiteVec();
- suite_ptr suite = suiteVec.back();
- BOOST_CHECK_MESSAGE( suite->state() == NState::UNKNOWN," Initial suite state should be NState::UNKNOWN");
-
- string suite1_family1_a = "suite1/family1/a";
- string suite1_family1_b = "suite1/family1/b";
- string suite1_family2_aa = "suite1/family2/aa";
- string suite1_family2_bb = "suite1/family2/bb";
-
-
- // Pick the suite that is allowed to resolve dependencies
- // The suite must be loaded and be in state UNKNOWN or COMPLETE
- TestHelper::invokeRequest(&defs,Cmd_ptr( new BeginCmd("suite1")));
-
-
- // ***********************************************************************
- // Create a request to initialise Node: suite1/family1/a
- {
- TestHelper::invokeRequest(&defs,Cmd_ptr( new InitCmd(suite1_family1_a,Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1)));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new CtsCmd( CtsCmd::FORCE_DEP_EVAL)),false);
-
- node_ptr node = defs.findAbsNode(suite1_family1_a);
- BOOST_CHECK_MESSAGE( node, "Could not find node");
- BOOST_CHECK_MESSAGE( node->state() == NState::ACTIVE, "Init request should place node in NState::ACTIVE");
- BOOST_CHECK_MESSAGE( suite->state() == NState::ACTIVE, "Suite should be in NState::ACTIVE after init cmd");
- std::string errorMsg; BOOST_CHECK_MESSAGE( defs.checkInvariants(errorMsg),errorMsg);
- }
-
- //**********************************************************************
- // Create a request to set the event on Node suite1/family1/a
- // This should force suite1_family2_bb immediately into submitted/active state
- {
- std::string eventname = "myEvent";
- TestHelper::invokeRequest(&defs,Cmd_ptr( new EventCmd(suite1_family1_a,Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1,eventname)));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new CtsCmd( CtsCmd::FORCE_DEP_EVAL)));
- node_ptr node = defs.findAbsNode(suite1_family1_a);
-
- const Event& theEvent = node->findEventByNameOrNumber(eventname);
- BOOST_CHECK_MESSAGE( !theEvent.empty(), "Could not find the event myEvent");
- BOOST_CHECK_MESSAGE( theEvent.value(), "The event was not set");
- std::string errorMsg; BOOST_CHECK_MESSAGE( defs.checkInvariants(errorMsg),errorMsg);
-
- // cerr << "Defs " << defs << "\n";
- BOOST_CHECK_MESSAGE( node->state() == NState::ACTIVE, "State should be NState::ACTIVE but found to be " << NState::toString(node->state()));
- BOOST_CHECK_MESSAGE( suite->state() == NState::ACTIVE, "Suite should be in NState::ACTIVE but found to be " << NState::toString(suite->state()));
-
- node_ptr nodebb = defs.findAbsNode(suite1_family2_bb);
- BOOST_CHECK_MESSAGE( nodebb->state() == NState::ACTIVE, "State should be NState::ACTIVE but found to be " << NState::toString(nodebb->state()));
- }
-
- //*******************************************************************************
- // Resolve dependencies. After previous event suite1_family2_bb should have
- // been put into ACTIVE state.
- // ** Tests trigger/AST OR functionality **
- // Since we at least one node in active, suite should
- // be in avtive state
- {
- JobsParam jobsParam; // create jobs = false, spawn jobs = false
- Jobs jobs(&defs);
- BOOST_CHECK_MESSAGE(jobs.generate(jobsParam),jobsParam.getErrorMsg());
- BOOST_FOREACH(Submittable* t, jobsParam.submitted() ) {
- BOOST_CHECK_MESSAGE( t->state() == NState::SUBMITTED, "jobSubmission should change Node state");
- }
-
- {
- node_ptr node = defs.findAbsNode(suite1_family1_a);
- BOOST_CHECK_MESSAGE( node->state() == NState::ACTIVE, "resolve dependencies should change Node state here");
- }
- node_ptr node = defs.findAbsNode(suite1_family2_bb);
- BOOST_CHECK_MESSAGE( node, "Could Not find Node " << suite1_family2_bb );
- BOOST_CHECK_MESSAGE( node->state() == NState::ACTIVE, "resolve dependencies should change Node state");
- BOOST_CHECK_MESSAGE( suite->state() == NState::ACTIVE, "Suite expected NState::ACTIVE, but found to be " << NState::toString(suite->state()));
- std::string errorMsg; BOOST_CHECK_MESSAGE( defs.checkInvariants(errorMsg),errorMsg);
- }
-
- //**********************************************************************
- // Create a request to set the Meter on Node suite1/family1/a
- // This should immediately change suite1_family2_aa into submitted state
- {
- std::string metername = "myMeter";
- int meterValue = 100;
- TestHelper::invokeRequest(&defs, Cmd_ptr( new MeterCmd(suite1_family1_a,Submittable::DUMMY_JOBS_PASSWORD(),Submittable::DUMMY_PROCESS_OR_REMOTE_ID(),1,metername,meterValue)));
- TestHelper::invokeRequest(&defs, Cmd_ptr( new CtsCmd( CtsCmd::FORCE_DEP_EVAL)));
-
- node_ptr node = defs.findAbsNode(suite1_family1_a);
- BOOST_CHECK_MESSAGE( node->state() == NState::ACTIVE,
- "Expected Node '" << node->absNodePath() << "' to be NState::ACTIVE, but found " << NState::toString(node->state()) << "\n");
- BOOST_CHECK_MESSAGE( suite->state() == NState::ACTIVE,
- "Suite expected NState::ACTIVE, but found to be " << NState::toString(suite->state()));
-
- const Meter& theMeter = node->findMeter(metername);
- BOOST_CHECK_MESSAGE( !theMeter.empty(), "Could not find the meter");
- BOOST_CHECK_MESSAGE( theMeter.value() == meterValue , "Meter value not set");
- std::string errorMsg; BOOST_REQUIRE_MESSAGE( defs.checkInvariants(errorMsg), errorMsg);
-
- node_ptr nodeaa = defs.findAbsNode(suite1_family2_aa);
- BOOST_CHECK_MESSAGE( nodeaa, "Could Not find Node " << suite1_family2_aa );
- BOOST_CHECK_MESSAGE( nodeaa->state() == NState::ACTIVE, "resolve dependencies should change Node state");
- }
-
- //**********************************************************************
- // Create a request to complete task suite1/family1/a
- // A is complete, which means evaluation dependencies should force:
- // suite1/family1/b :->to be submitted.
- // since the complete command does an immediate job submission afterwards
- {
- TestHelper::invokeRequest(&defs,Cmd_ptr( new CompleteCmd(suite1_family1_a,Submittable::DUMMY_JOBS_PASSWORD())));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new CtsCmd( CtsCmd::FORCE_DEP_EVAL)));
-
- node_ptr node = defs.findAbsNode(suite1_family1_a);
- BOOST_CHECK_MESSAGE( node, "Could not find node");
- BOOST_CHECK_MESSAGE( node->state() == NState::COMPLETE, "Complete request should place node in NState::COMPLETE");
- BOOST_CHECK_MESSAGE( suite->state() == NState::ACTIVE, "Expected NState::ACTIVE, but found to be " << NState::toString(suite->state()));
-
-
- node_ptr nodeb = defs.findAbsNode(suite1_family1_b);
- BOOST_CHECK_MESSAGE( nodeb, "Could not find node");
- BOOST_CHECK_MESSAGE( nodeb->state() == NState::ACTIVE, "Expected NState::ACTIVE, but found to be " << NState::toString(nodeb->state()));
-
- std::string errorMsg; BOOST_CHECK_MESSAGE( defs.checkInvariants(errorMsg),errorMsg);
- }
-
- //*******************************************************************************
- // Job submission, should not send any jobs for submission.
- // This will evaluate dependencies( ie day,date, trigger ast)
- {
- JobsParam jobsParam; // create jobs = false, spawn jobs = false
- Jobs jobs(&defs);
- BOOST_CHECK_MESSAGE( jobs.generate(jobsParam),jobsParam.getErrorMsg());
- BOOST_CHECK_MESSAGE( jobsParam.submitted().size() == 0, "Expected 0 task to submit but found " << jobsParam.submitted().size());
- }
-
- //********************************************************************************
- // Complete the remaining tasks
- {
- TestHelper::invokeRequest(&defs , Cmd_ptr( new CompleteCmd("suite1/family1/b",Submittable::DUMMY_JOBS_PASSWORD())));
- TestHelper::invokeRequest(&defs , Cmd_ptr( new CompleteCmd(suite1_family2_aa,Submittable::DUMMY_JOBS_PASSWORD())));
- TestHelper::invokeRequest(&defs , Cmd_ptr( new CompleteCmd(suite1_family2_bb,Submittable::DUMMY_JOBS_PASSWORD())));
-
- BOOST_CHECK_MESSAGE( suite->state() == NState::COMPLETE, "Suite should be in NState::COMPLETE state");
- std::string errorMsg; BOOST_CHECK_MESSAGE( defs.checkInvariants(errorMsg),errorMsg);
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/Client/test/TestLoadDefsCmd.cpp b/ecflow_4_0_7/Client/test/TestLoadDefsCmd.cpp
deleted file mode 100644
index 8bdf824..0000000
--- a/ecflow_4_0_7/Client/test/TestLoadDefsCmd.cpp
+++ /dev/null
@@ -1,160 +0,0 @@
-//============================================================================
-// Name : Request
-// Author : Avi
-// Revision : $Revision: #42 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <string>
-#include <iostream>
-#include <fstream>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/test/unit_test.hpp>
-
-#include "DefsStructureParser.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "ClientToServerCmd.hpp"
-#include "ServerToClientCmd.hpp"
-#include "MockServer.hpp"
-#include "InvokeServer.hpp"
-#include "SCPort.hpp"
-#include "System.hpp"
-#include "ChangeMgrSingleton.hpp"
-
-using namespace std;
-using namespace ecf;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( ClientTestSuite )
-
-//=============================================================================
-// This test the LoadDefsCmd. This command will merge/absorb a defs file
-// Since we are merging 2 files. It will give us an opportunity to resolve
-// the extern node paths in the trigger expressions.
-//
-// ********************************************************************
-// In the real server, we dont store, externs
-// *******************************************************************
-BOOST_AUTO_TEST_CASE( test_load_defs_cmd_handleRequest )
-{
- cout << "Client:: ...test_load_defs_cmd_handleRequest"<< endl;
-
- std::string firstDef = File::test_data("Client/test/data/first.def","Client");
-
- // Load the FIRST file with a set of unresolved extrens
- defs_ptr firstDefs = Defs::create();
- {
- DefsStructureParser checkPtParser( firstDefs.get(), firstDef );
- std::string errorMsg,warningMsg;
- bool parse = checkPtParser.doParse(errorMsg,warningMsg);
- BOOST_CHECK_MESSAGE(parse,"Parse failed. " << errorMsg);
- }
- size_t noOfSuites = firstDefs->suiteVec().size();
- size_t noOfExterns = firstDefs->externs().size();
-
-
- // load the SECOND file, which should resolve the externs
- std::string secondDef = File::test_data("Client/test/data/second.def","Client");
- Defs secondDefs;
- {
- DefsStructureParser checkPtParser( &secondDefs , secondDef);
- std::string errorMsg,warningMsg;
- bool parse = checkPtParser.doParse(errorMsg,warningMsg);
- BOOST_CHECK_MESSAGE(parse,"Parse failed. " << errorMsg);
- }
- noOfSuites += secondDefs.suiteVec().size();
- noOfExterns += secondDefs.externs().size();
-
-
- // Create a LoadDefsCmd. This capable of merging defs files and resolving externs
- LoadDefsCmd cmd(firstDefs);
- cmd.setup_user_authentification();
-
- // Calling handelRequest will absorb the first defs into second including externs & server user variables
- // AND resolve any references to node paths in the trigger expressions
- // Test that the merge was OK as well
- MockServer mockServer(&secondDefs);
- STC_Cmd_ptr requestStatus = cmd.handleRequest(&mockServer);
- BOOST_CHECK_MESSAGE( requestStatus, "Handle Request " << cmd << " returned NULL\n");
- BOOST_CHECK_MESSAGE( requestStatus->error().empty(), requestStatus->error());
- BOOST_CHECK_MESSAGE( secondDefs.suiteVec().size() == noOfSuites,"Merge failed to add suites");
- BOOST_CHECK_MESSAGE( secondDefs.externs().size() == noOfExterns,"Merge failed to add externs");
- BOOST_CHECK_MESSAGE( firstDefs->suiteVec().size() == 0, "Merge failed to remove suites");
-
-
- // Modify the Defs file to add a task/trigger that references the undefined
- // extern path defined in file 'first.def' This should fail.
- task_ptr task = Task::create( "AMadeUpName");
- task->add_trigger( "/a/b/c/d/e/f/g/h/j == complete");
- secondDefs.suiteVec().back()->familyVec().back()->addTask(task);
-
- // we just added an expression, re-parse to create AST
- // This should also attempt to resolve the extern node path /a/b/c/d/e/f/g/h/j
- // The suite 'a' should exist. But the full path is non existent
- // hence we expect the PARSE to fail.
- std::string errormsg,warningMsg;
- BOOST_CHECK_MESSAGE(!secondDefs.check(errormsg,warningMsg),errormsg);
-}
-
-BOOST_AUTO_TEST_CASE( test_load_defs_check_only )
-{
- /// Test that when check only is called the definition is NOT loaded
- InvokeServer invokeServer("Client:: ...test_load_defs_check_only",SCPort::next());
-
- std::string path = File::test_data("Client/test/data/lifecycle.txt","Client");
-
- // Do not load the defs do a check only
- ClientInvoker theClient(invokeServer.host(),invokeServer.port());
- BOOST_REQUIRE_MESSAGE( theClient.loadDefs(path,false,true/* check only*/) == 0,"Expected load to succeed\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.sync_local() == 0,"Expected sync to succeed\n" << theClient.errorMsg());
-
- // Note: when running with ECF_NODE=localhost the defs may exist, but the number of suites should be empty
- BOOST_REQUIRE_MESSAGE( !theClient.defs() || theClient.defs()->suiteVec().empty(),"Expected no defs, since nothing should have been loaded\n" << theClient.errorMsg());
-
- // provide path to definition that should fail to parse
- std::string path_bad_def = File::test_data("Client/test/data/bad.def","Client");
- BOOST_REQUIRE_THROW( theClient.loadDefs(path_bad_def,false,true/* check only*/),std::runtime_error);
-}
-
-BOOST_AUTO_TEST_CASE( test_load_defs )
-{
- /// Test that loading a defs a second time, with the same suite, throws a errors
- /// unless the -force option is used.
- InvokeServer invokeServer("Client:: ...test_load_defs",SCPort::next());
-
- // create a defs with a single suite 's1'
- defs_ptr theDefs = Defs::create();
- {
- suite_ptr suite = Suite::create("s1");
- theDefs->addSuite( suite );
- }
-
- // Load the defs into the server
- ClientInvoker theClient(invokeServer.host(),invokeServer.port());
- theClient.set_throw_on_error(false);
- BOOST_REQUIRE_MESSAGE( theClient.load(theDefs) == 0,"Expected load to succeed\n" << theClient.errorMsg());
-
- // load the defs again. This should fail. as it stops accidental overwrites
- BOOST_REQUIRE_MESSAGE( theClient.load(theDefs) == 1,"Expected load to fail\n" << theClient.errorMsg());
-
- // Try again but with force
- BOOST_REQUIRE_MESSAGE( theClient.load(theDefs,true /*force*/) == 0,"Expected load to succeed\n" << theClient.errorMsg());
-
- /// Destroy singleton's to avoid valgrind from complaining
- System::destroy();
- ChangeMgrSingleton::destroy();
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Client/test/TestMigration.cpp b/ecflow_4_0_7/Client/test/TestMigration.cpp
deleted file mode 100644
index 23fa14f..0000000
--- a/ecflow_4_0_7/Client/test/TestMigration.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
-#define BOOST_TEST_MODULE TestMigration
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #11 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <fstream>
-
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/timer.hpp>
-
-#include "ClientInvoker.hpp"
-#include "ClientEnvironment.hpp"
-#include "File.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Task.hpp"
-#include "TestHelper.hpp"
-#include "InvokeServer.hpp"
-#include "SCPort.hpp"
-#include "Str.hpp"
-#include "Host.hpp"
-#include "Rtt.hpp"
-#include "DurationTimer.hpp"
-
-namespace fs = boost::filesystem;
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( ClientTestSuite )
-
-// ************************************************************************************
-// Note: If you make edits to node tree, they will have no effect until the server is rebuilt
-// ************************************************************************************
-
-void do_test_migration(
- ClientInvoker& theClient,
- const std::string& host,
- const std::string& port,
- const std::string& directory,
- int & error_cnt
-)
-{
- fs::path full_path( fs::initial_path<fs::path>() );
- full_path = fs::system_complete( fs::path( directory ) );
-
- BOOST_CHECK(fs::exists( full_path ));
- BOOST_CHECK(fs::is_directory( full_path ));
-
- //std::cout << "\nIn directory: " << full_path.directory_string() << "\n\n";
- fs::directory_iterator end_iter;
- for ( fs::directory_iterator dir_itr( full_path ); dir_itr != end_iter; ++dir_itr ) {
- try {
- fs::path relPath(directory + "/" + dir_itr->path().filename().string());
-
- // recurse down directories
- if ( is_directory(dir_itr->status()) ) {
- do_test_migration(theClient,host,port,relPath.string(),error_cnt);
- continue;
- }
-
- cout << relPath.string() << " : file size " << fs::file_size(relPath) << "\n\n";
- if ( fs::file_size(relPath) > 0) {
- try {
- theClient.loadDefs(relPath.string());
- theClient.delete_all(true);
- }
- catch ( std::exception& e) {
- error_cnt++;
- BOOST_CHECK_MESSAGE(false,theClient.errorMsg() << " : " << e.what());
- }
- }
- }
- catch ( const std::exception & ex ) {
- std::cout << dir_itr->path().filename() << " " << ex.what() << std::endl;
- }
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_migration )
-{
- if (fs::exists("/var/tmp/ma0/ECFLOW_TEST/migration")) {
- /// This will remove checkpt and backup , to avoid server from loading it. (i.e from previous test)
- InvokeServer invokeServer("Client:: ...test_migration:",SCPort::next());
-
- ClientInvoker theClient(invokeServer.host(), invokeServer.port());
- int error_cnt = 0;
- do_test_migration(theClient,invokeServer.host(), invokeServer.port(),"/var/tmp/ma0/ECFLOW_TEST/migration",error_cnt);
- BOOST_REQUIRE_MESSAGE( error_cnt == 0, "Migration test failed " << error_cnt << " times " );
- }
- else {
- std::cout << "Ignoring test, since directory '/var/tmp/ma0/ECFLOW_TEST/migration' not found\n";
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Client/test/TestPlugCmd.cpp b/ecflow_4_0_7/Client/test/TestPlugCmd.cpp
deleted file mode 100644
index 2bff0ae..0000000
--- a/ecflow_4_0_7/Client/test/TestPlugCmd.cpp
+++ /dev/null
@@ -1,321 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #34 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <boost/test/unit_test.hpp>
-#include <iostream>
-#include <fstream>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include "boost/progress.hpp"
-
-#include "DefsStructureParser.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "TestHelper.hpp"
-#include "MockServer.hpp"
-
-#include "ClientInvoker.hpp"
-#include "InvokeServer.hpp"
-#include "SCPort.hpp"
-#include "File.hpp"
-
-namespace fs = boost::filesystem;
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( ClientTestSuite)
-
-BOOST_AUTO_TEST_CASE( test_plug_cmd )
-{
- cout << "Client:: ...test_plug_cmd" << endl;
-
- std::string path = File::test_data("Client/test/data/lifecycle.txt","Client");
-
- Defs defs;
- DefsStructureParser checkPtParser( &defs , path );
- std::string errorMsg,warningMsg;
- bool parse = checkPtParser.doParse(errorMsg,warningMsg);
- if (!parse) std::cerr << errorMsg;
- BOOST_CHECK(parse);
-
-// suite suite1
-// family family1
-// task a
-// event 1 myEvent
-// meter myMeter 0 100
-// task b
-// trigger a == complete
-// endfamily
-// family family2
-// task aa
-// trigger ../family1/a:myMeter >= 20 and ../family1/a:myEvent
-// task bb
-// trigger ../family1/a:myMeter >= 50 || ../family1/a:myEvent
-// endfamily
-// endsuite
-
- /// Test failure modes, MockServer defaults to localhost:3141
- // test source node that does not exist, fails
- TestHelper::invokeFailureRequest(&defs, Cmd_ptr( new PlugCmd("I/dont/exist/on/the server", "suite1/family2") ));
-
- // test dest node that does not exist, fails
- TestHelper::invokeFailureRequest(&defs, Cmd_ptr( new PlugCmd("suite1/family1/a", "i/dont/exist/on/server") ));
-
- // test source node same as dest node, fails
- TestHelper::invokeFailureRequest(&defs, Cmd_ptr( new PlugCmd("suite1/family1/a", "suite1/family1/a") ));
-
- // test dest node that matches local server host and port, but where path does not exist, fails
- TestHelper::invokeFailureRequest(&defs, Cmd_ptr( new PlugCmd("suite1/family1/a", "//localhost:3141/i/dont/exist/on/local_server") ));
-
- // Lock server as another user. Invoke a valid request that should fail, due to a lock
- MockServer server(&defs);
- BOOST_REQUIRE_MESSAGE(server.lock("A user"),"Lock expected to succeed");
- TestHelper::invokeFailureRequest(server,Cmd_ptr( new PlugCmd("suite1/family1/a", "suite1/family2")));
-
-
- { // Move the TASKS: on family1 --> family2
- // Note: if on the destination node we select a task 'suite1/family2/aa', then node is moved to its parent
- TestHelper::invokeRequest(&defs,Cmd_ptr( new PlugCmd("suite1/family1/a", "suite1/family2")));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new PlugCmd("suite1/family1/b", "//localhost:3141/suite1/family2/aa")));
-
- node_ptr node = defs.findAbsNode("suite1/family1");
- BOOST_REQUIRE_MESSAGE( node.get() && node->isFamily(), "Could not find suite1/family1");
- BOOST_REQUIRE_MESSAGE( node->isFamily()->taskVec().size() == 0, "Failed to move task to other family");
-
- node_ptr node2 = defs.findAbsNode("suite1/family2");
- BOOST_REQUIRE_MESSAGE( node2.get() && node->isFamily(), "Could not find suite1/family2");
- BOOST_REQUIRE_MESSAGE( node2->isFamily()->taskVec().size() == 4, "family2 two should have 4 tasks");
- }
-
- { // Move FAMILIES: Add a new suite and move family1 and family2 to it.
- defs.addSuite( Suite::create("suite2") );
-
- TestHelper::invokeRequest(&defs,Cmd_ptr( new PlugCmd("suite1/family1", "suite2")));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new PlugCmd("suite1/family2", "suite2")));
-
- node_ptr suite1 = defs.findAbsNode("suite1");
- BOOST_REQUIRE_MESSAGE( suite1.get() && suite1->isSuite(), "Could not find suite1");
- BOOST_REQUIRE_MESSAGE( suite1->isSuite()->familyVec().size() == 0, "Expected suite1 to have '0' families as they should have been moved to suite2");
-
- node_ptr suite2 = defs.findAbsNode("suite2");
- BOOST_REQUIRE_MESSAGE( suite2.get() && suite2->isSuite(), "Could not find suite2");
- BOOST_REQUIRE_MESSAGE( suite2->isSuite()->familyVec().size() == 2, "Expected suite2 to have '2' families");
- }
-}
-
-
-BOOST_AUTO_TEST_CASE( test_plug_cmd_with_handles )
-{
- cout << "Client:: ...test_plug_cmd_with_handles" << endl;
-
- std::string path = File::test_data("Client/test/data/lifecycle.txt","Client");
-
- Defs defs;
- DefsStructureParser checkPtParser( &defs , path );
- std::string errorMsg,warningMsg;
- bool parse = checkPtParser.doParse(errorMsg,warningMsg);
- if (!parse) std::cerr << errorMsg;
- BOOST_CHECK(parse);
-
-// suite suite1
-// family family1
-// task a
-// event 1 myEvent
-// meter myMeter 0 100
-// task b
-// trigger a == complete
-// endfamily
-// family family2
-// task aa
-// trigger ../family1/a:myMeter >= 20 and ../family1/a:myEvent
-// task bb
-// trigger ../family1/a:myMeter >= 50 || ../family1/a:myEvent
-// endfamily
-// endsuite
-
- /// create client handle which references suites suite in the server defs
- std::vector<std::string> suite_names; suite_names.push_back("suite"); suite_names.push_back("suite2");
- TestHelper::invokeRequest(&defs,Cmd_ptr( new ClientHandleCmd(suite_names,false)),false /* bypass_state_modify_change_check */);
-
-
- { // Move the TASKS: on family1 --> family2
- // Note: if on the destination node we select a task 'suite1/family2/aa', then node is moved to its parent
- Suite* suite = defs.findAbsNode("suite1")->isSuite();
- unsigned int state_change_no = suite->state_change_no();
- unsigned int modify_change_no = suite->modify_change_no();
-
- TestHelper::invokeRequest(&defs,Cmd_ptr( new PlugCmd("suite1/family1/a", "suite1/family2")));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new PlugCmd("suite1/family1/b", "//localhost:3141/suite1/family2/aa")));
-
- BOOST_CHECK_MESSAGE(state_change_no != suite->state_change_no() || modify_change_no != suite->modify_change_no(),
- "state and modify change numbers unaltered by plug command when using handles");
- }
-
- { // Move FAMILIES: Add a new suite and move family1 and family2 to it.
- suite_ptr suite2 = defs.add_suite("suite2");
- unsigned int state_change_no = suite2->state_change_no();
- unsigned int modify_change_no = suite2->modify_change_no();
- TestHelper::invokeRequest(&defs,Cmd_ptr( new PlugCmd("suite1/family1", "suite2")));
- TestHelper::invokeRequest(&defs,Cmd_ptr( new PlugCmd("suite1/family2", "suite2")));
- BOOST_CHECK_MESSAGE(state_change_no != suite2->state_change_no() || modify_change_no != suite2->modify_change_no(),
- "state and modify change numbers unaltered by plug command when using handles");
- }
-}
-
-static void test_plug_on_multiple_server(
- const std::string& host1, const std::string& port1,
- const std::string& host2, const std::string& port2
-)
-{
- std::cout << " on host1("<< host1 << ":" << port1 << ") host2(" << host2 << ":" << port2 << ")" << endl;
- ClientInvoker server1Client(host1,port1); server1Client.set_throw_on_error(false);
- ClientInvoker server2Client(host2,port2); server2Client.set_throw_on_error(false);
-
- //std::cout << " restartServer the FIRST and SECOND servers" << endl;
- BOOST_REQUIRE_MESSAGE( server1Client.restartServer() == 0,CtsApi::restartServer() << " should return 0 server not started, or connection refused\n" << server1Client.errorMsg());
- BOOST_REQUIRE_MESSAGE( server2Client.restartServer() == 0,CtsApi::restartServer() << " should return 0 server not started, or connection refused\n" << server2Client.errorMsg());
-
- //std::cout << " LOAD the defs into FIRST server(" << host1 << ":" << port1 << ") There is NO DEFS in the second server." << endl;
- std::string path = File::test_data("Client/test/data/lifecycle.txt","Client");
- BOOST_REQUIRE_MESSAGE( server1Client.loadDefs(path) == 0,"load defs failed \n" << server1Client.errorMsg());
-
-
- //cout << " Test the ERROR conditions in MoveCmd" << endl;
- std::string sourcePath = "/suite1";
- std::string secondServerHostPort = "//localhost:" + port2; // The destination path must encode the host:port path to the second server
-
- std::string destPath = secondServerHostPort + "/A/made/up/dest/path/that/does/not/exist/on/server2";
- //cout << " Plug/Move from server1(" << host1 << ":" << port1 << ") to destination server " << destPath << endl;
- int theResult = server1Client.plug(sourcePath,destPath);
- BOOST_REQUIRE_MESSAGE( theResult == 1,CtsApi::plugArg() << "Expected to fail since no defs in server 2\n");
- // std::cout << "Error message = " << server1Client.errorMsg() << "\n";
-
- //cout << " *** Load Defs into SECOND server ***, ie both servers have the same definitions" << endl;
- BOOST_REQUIRE_MESSAGE( server2Client.loadDefs(path) == 0,"load defs failed \n" << server2Client.errorMsg());
-
-
- destPath = secondServerHostPort + "/suite1";
- theResult = server1Client.plug(sourcePath,destPath);
- // cout << "server1Client.errorMsg() = " << server1Client.errorMsg() << "\n";
- BOOST_REQUIRE_MESSAGE( theResult == 1,CtsApi::plugArg() << " Expected to fail, since 'suite1' already exists in the server \n");
-
- destPath = secondServerHostPort + "/suite1/family1";
- theResult = server1Client.plug(sourcePath,destPath);
- // cout << "server1Client.errorMsg() = " << server1Client.errorMsg() << "\n";
- BOOST_REQUIRE_MESSAGE( theResult == 1,CtsApi::plugArg() << " Expected to fail, since can't move a suite into a family\n");
-
- destPath = secondServerHostPort + "/suite1";
- theResult = server1Client.plug("/suite1/family1",destPath);
- // cout << "server1Client.errorMsg() = " << server1Client.errorMsg() << "\n";
- BOOST_REQUIRE_MESSAGE( theResult == 1,CtsApi::plugArg() << " Expected to fail, Destination already has a family1 \n");
-
- destPath = secondServerHostPort + "/A/made/up/dest/path/that/does/not/exist/on/server2";
- theResult = server1Client.plug(sourcePath,destPath);
- // cout << "server1Client.errorMsg() = " << server1Client.errorMsg() << "\n";
- BOOST_REQUIRE_MESSAGE( theResult == 1,CtsApi::plugArg() << " Expected to fail, since destination path does not exist\n");
-
- destPath = secondServerHostPort;
- theResult = server1Client.plug("/suite1/family1",destPath);
- // cout << "server1Client.errorMsg() = " << server1Client.errorMsg() << "\n";
- BOOST_REQUIRE_MESSAGE( theResult == 1,CtsApi::plugArg() << " Expected to fail,since source path must be a suite, if the destination path name is empty\n");
-
-
- // ==========================================================================================
- // Test Plug command works
- // ==========================================================================================
-
- // Completely remove the 'suite1' file in the second server
- BOOST_REQUIRE_MESSAGE( server2Client.delete_node(sourcePath) == 0,CtsApi::to_string(CtsApi::delete_node(sourcePath)) << " failed \n" << server2Client.errorMsg());
- BOOST_REQUIRE_MESSAGE( server2Client.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << server2Client.errorMsg());
- BOOST_REQUIRE_MESSAGE( server2Client.defs().get(),"Server returned a NULL defs");
- BOOST_REQUIRE_MESSAGE( server2Client.defs()->suiteVec().size() == 0," Expected server2 to have zero suite");
-
- // Move the suite FROM the FIRST server TO the SECOND server and check that it worked
- destPath = secondServerHostPort;
- theResult = server1Client.plug(sourcePath,destPath);
- BOOST_REQUIRE_MESSAGE( theResult == 0,CtsApi::plugArg() << " failed \n" << server1Client.errorMsg());
-
- BOOST_REQUIRE_MESSAGE( server1Client.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << server1Client.errorMsg());
- BOOST_REQUIRE_MESSAGE( server1Client.defs().get(),"Server returned a NULL defs");
- BOOST_REQUIRE_MESSAGE( server1Client.defs()->suiteVec().size() == 0," Expected server1 to have no suites");
-
- BOOST_REQUIRE_MESSAGE( server2Client.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << server2Client.errorMsg());
- BOOST_REQUIRE_MESSAGE( server2Client.defs().get(),"Server returned a NULL defs");
- BOOST_REQUIRE_MESSAGE( server2Client.defs()->suiteVec().size() == 1," Expected server2 to have one suite");
-
-
- // ==========================================================================
- // Do it again, but with no defs file in second server. reload defs into server1
- BOOST_REQUIRE_MESSAGE(server1Client.delete_all() == 0,CtsApi::to_string(CtsApi::delete_node()) << " failed \n" << server1Client.errorMsg());
- BOOST_REQUIRE_MESSAGE(server2Client.delete_all() == 0,CtsApi::to_string(CtsApi::delete_node()) << " failed \n" << server2Client.errorMsg());
- BOOST_REQUIRE_MESSAGE(server1Client.loadDefs(path) == 0,"load defs failed \n" << server1Client.errorMsg());
-
- destPath = secondServerHostPort;
- theResult = server1Client.plug(sourcePath,destPath);
- BOOST_REQUIRE_MESSAGE( theResult == 0,CtsApi::plugArg() << " failed \n" << server1Client.errorMsg());
-
- BOOST_REQUIRE_MESSAGE(server1Client.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << server1Client.errorMsg());
- BOOST_REQUIRE_MESSAGE( server1Client.defs().get(),"Server returned a NULL defs");
- BOOST_REQUIRE_MESSAGE( server1Client.defs()->suiteVec().size() == 0," Expected server1 to have no suites");
-
- BOOST_REQUIRE_MESSAGE(server2Client.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << server2Client.errorMsg());
- BOOST_REQUIRE_MESSAGE( server2Client.defs().get(),"Server returned a NULL defs");
- BOOST_REQUIRE_MESSAGE( server2Client.defs()->suiteVec().size() == 1," Expected server2 to have one suite");
-}
-
-BOOST_AUTO_TEST_CASE( test_server_plug_cmd )
-{
- if (ClientEnvironment::hostSpecified().empty()) {
-
- cout << "Client:: ...test_server_plug_cmd";
-
- // Invoke two servers. *which* will both terminate at the end of this scope
- // This will remove check pt and backup file before server start, to avoid the server from loading previous test data
- InvokeServer invokeServer1("",SCPort::next());
- InvokeServer invokeServer2("",SCPort::next());
-
- test_plug_on_multiple_server(invokeServer1.host(), invokeServer1.port(),
- invokeServer2.host(), invokeServer2.port());
- }
- else {
-
- // Plug is broken for new->old servers, where boost serialsation version number changes.
- if (getenv("ECF_ALLOW_NEW_CLIENT_OLD_SERVER")) {
- cout << "Client:: ...test_server_plug_cmd: ignoring test when ECF_ALLOW_NEW_CLIENT_OLD_SERVER specified" << endl;
- return;
- }
-
- cout << "Client:: ...test_server_plug_cmd";
-
- // Remote server all ready running, start one more additional server
- {
- // remove any suites on the remote server. Since this test requires it.
- ClientInvoker theClient(ClientEnvironment::hostSpecified(),ClientEnvironment::portSpecified());
- BOOST_REQUIRE_MESSAGE( theClient.delete_all() == 0,CtsApi::to_string(CtsApi::delete_node()) << " failed should return 0. Should Delete ALL existing defs in the server\n" << theClient.errorMsg());
- }
-
- // Start additional local server, special constructor. need false flag, to avoid ambiguity, with the other constructor.
- std::string port2 = SCPort::next();
- InvokeServer invokeServer2(port2,false);
-
- test_plug_on_multiple_server(ClientEnvironment::hostSpecified(), Str::DEFAULT_PORT_NUMBER(),
- Str::LOCALHOST(), port2);
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/Client/test/TestRtt.cpp b/ecflow_4_0_7/Client/test/TestRtt.cpp
deleted file mode 100644
index 3c6e403..0000000
--- a/ecflow_4_0_7/Client/test/TestRtt.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <iostream>
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/timer.hpp>
-
-#include "Rtt.hpp"
-#include "File.hpp"
-
-namespace fs = boost::filesystem;
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( ClientTestSuite )
-
-BOOST_AUTO_TEST_CASE( test_client_invoker_round_trip_times )
-{
- cout << "Client:: ...test_client_invoker_round_trip_times" << endl;
-
- std::string root_path = File::test_data("Client/test/data/","Client");
-
- /// Open file rtt.dat and compute average round trip times
- std::string result = Rtt::analyis( root_path + "rtt.dat");
- //cout << result << "\n";
-
- /// generated a file with results
- std::string errorMsg;
- string generated_file = root_path + "rtt_analysis.dat";
- BOOST_CHECK_MESSAGE(File::create(generated_file, result,errorMsg),errorMsg);
-
- /// Compare with a reference file
- std::vector<std::string> ignoreVec; errorMsg.clear();
- std::string diffs = File::diff(generated_file, root_path + "ref_analysis.dat", ignoreVec, errorMsg );
- BOOST_CHECK_MESSAGE(diffs.empty(),diffs << "\n" << errorMsg);
-
- if (diffs.empty()) boost::filesystem::remove(generated_file);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Client/test/TestServer.cpp b/ecflow_4_0_7/Client/test/TestServer.cpp
deleted file mode 100644
index 0472366..0000000
--- a/ecflow_4_0_7/Client/test/TestServer.cpp
+++ /dev/null
@@ -1,318 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #45 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <fstream>
-
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/timer.hpp>
-#include <boost/date_time/posix_time/time_formatters.hpp> // requires boost date and time lib, for to_simple_string
-
-#include "ClientInvoker.hpp"
-#include "ClientEnvironment.hpp"
-#include "File.hpp"
-#include "TestHelper.hpp"
-#include "InvokeServer.hpp"
-#include "SCPort.hpp"
-#include "Str.hpp"
-#include "DurationTimer.hpp"
-#include "Host.hpp"
-#include "Version.hpp"
-
-namespace fs = boost::filesystem;
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( ClientTestSuite )
-
-// ************************************************************************************
-// Note: If you make edits to node tree, they will have no effect until the server is rebuilt
-//
-// Note: To test HPUX->Linux, invoke serve on (Linux/HPUX) and the client cmds on other system
-// On the client side set ECF_NODE to machine name. To allow further testing if ECF_NODE
-// is specified then *don't* shutdown the server
-// ************************************************************************************
-
-BOOST_AUTO_TEST_CASE( test_server_version )
-{
- /// This will remove checkpt and backup , to avoid server from loading it. (i.e from previous test)
- InvokeServer invokeServer("Client:: ...test_server_version:",SCPort::next());
-
- ClientInvoker theClient(invokeServer.host(), invokeServer.port());
- BOOST_REQUIRE_MESSAGE(theClient.server_version() == 0,"server version\n" << theClient.errorMsg());
- if (ClientEnvironment::hostSpecified().empty()) {
- // This check only valid if server was invoked locally. Ignore for remote servers
- BOOST_REQUIRE_MESSAGE(theClient.get_string() == Version::raw(),"Expected client version(" << Version::raw() << ") to match server version(" << theClient.get_string() << ")");
- }
- else {
- // remote server, version may be different
- BOOST_WARN_MESSAGE(theClient.get_string() == Version::raw(),"Client version(" << Version::raw() << ") does not match server version(" << theClient.get_string() << ")");
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_server_state_changes )
-{
- /// This will remove checkpt and backup , to avoid server from loading it. (i.e from previous test)
- InvokeServer invokeServer("Client:: ...test_server_state_changes:",SCPort::next());
-
- std::string path = File::test_data("Client/test/data/lifecycle.txt","Client");
-
- ClientInvoker theClient(invokeServer.host(), invokeServer.port());
- BOOST_REQUIRE_MESSAGE(theClient.loadDefs(path) == 0,"load defs failed \n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << theClient.errorMsg());
- if (ClientEnvironment::hostSpecified().empty()) {
- // server started locally
- BOOST_REQUIRE_MESSAGE(theClient.defs()->server().get_state() == SState::HALTED,"Expected INITIAL server state HALTED but found " << SState::to_string(theClient.defs()->server().get_state()));
- }
-
- BOOST_REQUIRE_MESSAGE(theClient.shutdownServer() == 0,CtsApi::shutdownServer() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.defs()->server().get_state() == SState::SHUTDOWN,"Expected server state SHUTDOWN but found " << SState::to_string(theClient.defs()->server().get_state()));
-
- BOOST_REQUIRE_MESSAGE(theClient.haltServer() == 0,CtsApi::haltServer() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.defs()->server().get_state() == SState::HALTED,"Expected server state HALTED but found " << SState::to_string(theClient.defs()->server().get_state()));
-
- BOOST_REQUIRE_MESSAGE(theClient.restartServer() == 0,CtsApi::restartServer() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.defs()->server().get_state() == SState::RUNNING,"Expected server state RUNNING but found " << SState::to_string(theClient.defs()->server().get_state()));
-
- /// Repeat test using sync_local() to test incremental changes of server
- BOOST_REQUIRE_MESSAGE(theClient.shutdownServer() == 0,CtsApi::shutdownServer() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.sync_local() == 0," failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.defs()->server().get_state() == SState::SHUTDOWN,"Expected server state SHUTDOWN but found " << SState::to_string(theClient.defs()->server().get_state()));
-
- BOOST_REQUIRE_MESSAGE(theClient.haltServer() == 0,CtsApi::haltServer() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.sync_local() == 0," failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.defs()->server().get_state() == SState::HALTED,"Expected server state HALTED but found " << SState::to_string(theClient.defs()->server().get_state()));
-
- BOOST_REQUIRE_MESSAGE(theClient.restartServer() == 0,CtsApi::restartServer() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.sync_local() == 0," failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.defs()->server().get_state() == SState::RUNNING,"Expected server state RUNNING but found " << SState::to_string(theClient.defs()->server().get_state()));
-
- if (ClientEnvironment::hostSpecified().empty()) {
- // This check only valid if server was invoked locally. Ignore for remote servers
-
- // make sure edit history updated
- BOOST_REQUIRE_MESSAGE(theClient.edit_history(Str::ROOT_PATH()) == 0,CtsApi::to_string(CtsApi::edit_history(Str::ROOT_PATH())) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.server_reply().get_string_vec().size() == 7,"Expected edit history of size 7, but found " << theClient.server_reply().get_string_vec().size());
-
- // make sure edit history was *NOT* serialized, It is only serialized when check pointing
- BOOST_REQUIRE_MESSAGE(theClient.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.defs()->get_edit_history(Str::ROOT_PATH()).size() == 0,"Expected edit history of size 0, but found " << theClient.defs()->get_edit_history(Str::ROOT_PATH()).size());
- }
-}
-
-
-BOOST_AUTO_TEST_CASE( test_server_stress_test )
-{
- /// This will remove checkpt and backup , to avoid server from loading it. (i.e from previous test)
- InvokeServer invokeServer("Client:: ...test_server_stress_test:",SCPort::next());
-
- std::string path = File::test_data("Client/test/data/lifecycle.txt","Client");
-
- boost::timer boost_timer; // measures CPU, replace with cpu_timer with boost > 1.51, measures cpu & elapsed
- DurationTimer duration_timer;
- ClientInvoker theClient(invokeServer.host(), invokeServer.port());
- int load = 125;
- for(int i = 0; i < load; i++) {
-
- BOOST_REQUIRE_MESSAGE(theClient.delete_all() == 0,CtsApi::to_string(CtsApi::delete_node()) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.loadDefs(path) == 0,"load defs failed \n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.shutdownServer() == 0,CtsApi::shutdownServer() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.haltServer() == 0,CtsApi::haltServer() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.restartServer() == 0,CtsApi::restartServer() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.restartServer() == 0,CtsApi::restartServer() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.checkPtDefs() == 0,CtsApi::checkPtDefs() << " failed should return 0\n" << theClient.errorMsg());
-
- BOOST_REQUIRE_MESSAGE(theClient.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.defs().get(),"Server returned a NULL defs");
- BOOST_REQUIRE_MESSAGE( theClient.defs()->suiteVec().size() >= 1," no suite ?");
- }
- cout << " Server handled " << load * 8
- << " requests in boost_timer(" << boost_timer.elapsed()
- << ") DurationTimer(" << to_simple_string(duration_timer.elapsed())
- << ")" << endl;
-}
-
-
-BOOST_AUTO_TEST_CASE( test_server_group_stress_test )
-{
- /// This is exactly the same test as above, but uses the group command
- /// This should be faster as the network traffic should be a lot less
- InvokeServer invokeServer("Client:: ...test_server_group_stress_test:",SCPort::next());
-
- std::string path = File::test_data("Client/test/data/lifecycle.txt","Client");
-
- boost::timer boost_timer; // measures CPU, replace with cpu_timer with boost > 1.51, measures cpu & elapsed
- DurationTimer duration_timer;
- ClientInvoker theClient(invokeServer.host(), invokeServer.port());
-
- std::string groupRequest = CtsApi::to_string(CtsApi::delete_node());
- groupRequest += ";";
- groupRequest += CtsApi::to_string(CtsApi::loadDefs(path,true/*force*/,false /*check_only*/));
- groupRequest += ";";
- groupRequest += CtsApi::shutdownServer();
- groupRequest += ";";
- groupRequest += CtsApi::haltServer();
- groupRequest += ";";
- groupRequest += CtsApi::restartServer();
- groupRequest += ";";
- groupRequest += CtsApi::restartServer();
- groupRequest += ";";
- groupRequest += CtsApi::checkPtDefs();
- groupRequest += ";";
- groupRequest += CtsApi::get();
-
- //cout << "groupRequest = " << groupRequest << "\n";
-
- int load = 125;
- for(int i = 0; i < load; i++) {
- BOOST_REQUIRE_MESSAGE( theClient.group(groupRequest) == 0,"Group request " << CtsApi::group(groupRequest) << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.defs().get(),"Server returned a NULL defs");
- BOOST_REQUIRE_MESSAGE( theClient.defs()->suiteVec().size() >= 1," no suite ?");
- }
- cout << " Server handled " << load * 8
- << " commands using " << load << " group requests in boost_timer(" << boost_timer.elapsed()
- << ") DurationTimer(" << to_simple_string(duration_timer.elapsed())
- << ")" << endl;
-}
-
-BOOST_AUTO_TEST_CASE( test_server_stress_test_2 )
-{
- /// More extensive stress test, using as many user based command as possible.
- ///
- /// This will remove checkpt and backup , to avoid server from loading it. (i.e from previous test)
- InvokeServer invokeServer("Client:: ...test_server_stress_test_2:",SCPort::next());
-
- std::string path = File::test_data("Client/test/data/lifecycle.txt","Client");
-
- Zombie z(Child::USER,ecf::Child::INIT,ZombieAttr::get_default_attr(Child::USER),"path_to_task","DUMMY_JOBS_PASSWORD", "DUMMY_PROCESS_OR_REMOTE_ID",1);
- std::vector<std::string> suites; suites.push_back("suite1"); suites.push_back("made_up_suite");
-
- std::vector<std::string> nodes_to_delete;
- nodes_to_delete.push_back("/suite1/family2/aa"); // these should exist in lifecycle.txt
- nodes_to_delete.push_back("/suite1/family2/bb");
-
-#if defined(HPUX)
- int load = 10; // On non linux systems use different load otherwise it takes to long
-#elif defined(_AIX)
- int load = 65; // On non linux systems use different load otherwise it takes to long
-#else
- int load = 136;
-#endif
-
- boost::timer boost_timer; // measures CPU, replace with cpu_timer with boost > 1.51, measures cpu & elapsed
- DurationTimer duration_timer;
- ClientInvoker theClient(invokeServer.host(), invokeServer.port());
- theClient.set_throw_on_error(false);
- for(int i = 0; i < load; i++) {
-
- BOOST_REQUIRE_MESSAGE( theClient.pingServer() == 0, " ping should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.delete_all() == 0,CtsApi::to_string(CtsApi::delete_node()) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.loadDefs(path) == 0,"load defs failed \n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.shutdownServer() == 0,CtsApi::shutdownServer() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.haltServer() == 0,CtsApi::haltServer() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.restartServer() == 0,CtsApi::restartServer() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.news_local() == 0, " new local failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.sync_local() == 0, "failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.stats() == 0,CtsApi::stats() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.suites() == 0,CtsApi::suites() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.server_version() == 0,CtsApi::server_version() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.debug_server_off() == 0,CtsApi::debug_server_off() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.check("/suite1") == 0,"check should return 0\n" << theClient.errorMsg()); //13
-
- BOOST_REQUIRE_MESSAGE( theClient.logMsg("start") == 0,"log msg should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.get_log_path() == 0,"get_log_path should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.getLog(1) == 0,"get_log last line should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.flushLog() == 0,"flushLog should return 0\n" << theClient.errorMsg());
-
- BOOST_REQUIRE_MESSAGE( theClient.force("/suite1","unknown",true) == 0,"check should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.force("/suite1","complete",true) == 0,"check should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.force("/suite1","submitted",true) == 0,"check should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.force("/suite1","active",true) == 0,"check should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.force("/suite1","aborted",true) == 0,"check should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.force("/suite1","queued",true) == 0,"check should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.force("/suite1/family1/a:myEvent","set") == 0,"check should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.force("/suite1/family1/a:myEvent","clear") == 0,"check should return 0\n" << theClient.errorMsg());
-
- BOOST_REQUIRE_MESSAGE( theClient.zombieGet() == 0,CtsApi::zombieGet() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.zombieFob(z) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.zombieFail(z) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.zombieAdopt(z) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.zombieBlock(z) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.zombieRemove(z) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.zombieKill(z) == 0, " should return 0\n" << theClient.errorMsg()); //19
-
- BOOST_REQUIRE_MESSAGE( theClient.suspend("/suite1") == 0,CtsApi::to_string(CtsApi::suspend("/suite1"))<< " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.resume("/suite1") == 0,CtsApi::to_string(CtsApi::resume("/suite1")) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.edit_history("/suite1") == 0,CtsApi::to_string(CtsApi::edit_history("/suite1")) << " should return 0\n" << theClient.errorMsg());
-
- BOOST_REQUIRE_MESSAGE( theClient.replace("/suite1",path) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.replace("/suite1",path,true) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.replace("/suite1",path,true, true) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.replace("/suite1",path,false, true) == 0, " should return 0\n" << theClient.errorMsg()); //26
-
- BOOST_REQUIRE_MESSAGE( theClient.checkPtDefs() == 0,CtsApi::checkPtDefs() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.checkPtDefs(ecf::CheckPt::NEVER) == 0," should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.checkPtDefs(ecf::CheckPt::ALWAYS) == 0," should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.checkPtDefs(ecf::CheckPt::ON_TIME,180) == 0," should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.checkPtDefs(ecf::CheckPt::ON_TIME) == 0," should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.checkPtDefs(ecf::CheckPt::UNDEFINED) == 0," should return 0\n" << theClient.errorMsg()); //32
- BOOST_REQUIRE_MESSAGE( theClient.checkPtDefs(ecf::CheckPt::ON_TIME,CheckPt::default_interval()) == 0," should return 0\n" << theClient.errorMsg());
-
- BOOST_REQUIRE_MESSAGE( theClient.freeDep("/suite1") == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.freeDep("/suite1",true,true,true,true) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.freeDep("/suite1",true) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.freeDep("/suite1",false,true) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.freeDep("/suite1",false,false,true) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.freeDep("/suite1",false,false,false,true) == 0, " should return 0\n" << theClient.errorMsg()); //38
-
- BOOST_REQUIRE_MESSAGE( theClient.ch_register(true,suites) == 0,"--ch_register \n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.ch_suites() == 0,"--ch_suites should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.ch_add(1,suites) == 0,"--ch_add \n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.ch_remove(1,suites) == 0,"--ch_remove \n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.ch_auto_add(1,true) == 0,"--ch_auto_add \n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.ch_auto_add(1,false) == 0,"--ch_auto_add \n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.ch_drop(1) == 0,"--ch_drop should return 0\n" << theClient.errorMsg()); //45
-
- BOOST_REQUIRE_MESSAGE( theClient.ch_register(true,suites) == 0,"--ch_register \n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.ch1_add(suites) == 0,"--ch1_add \n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.ch1_auto_add(true) == 0,"--ch1_auto_add \n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.ch1_auto_add(false) == 0,"--ch1_auto_add \n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.ch1_remove(suites) == 0,"--ch1_remove \n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.ch1_drop() == 0,"--ch1_drop \n" << theClient.errorMsg()); //51
-
- BOOST_REQUIRE_MESSAGE( theClient.order("/suite1","top") == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.order("/suite1","bottom") == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.order("/suite1","alpha") == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.order("/suite1",NOrder::ORDER) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.order("/suite1",NOrder::UP) == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.order("/suite1",NOrder::DOWN) == 0, " should return 0\n" << theClient.errorMsg()); //57
-
- BOOST_REQUIRE_MESSAGE( theClient.delete_node("/suite1/family1/a") == 0, " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.delete_nodes(nodes_to_delete) == 0, " should return 0\n" << theClient.errorMsg());
-
- BOOST_REQUIRE_MESSAGE( theClient.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << theClient.errorMsg()); //60
- BOOST_REQUIRE_MESSAGE( theClient.defs().get(),"Server returned a NULL defs");
- BOOST_REQUIRE_MESSAGE( theClient.defs()->suiteVec().size() >= 1," no suite ?");
- }
- cout << " Server handled " << load * 74
- << " requests in boost_timer(" << boost_timer.elapsed()
- << ") DurationTimer(" << to_simple_string(duration_timer.elapsed())
- << ")" << endl;
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Client/test/TestServerAndLifeCycle.cpp b/ecflow_4_0_7/Client/test/TestServerAndLifeCycle.cpp
deleted file mode 100644
index d326f13..0000000
--- a/ecflow_4_0_7/Client/test/TestServerAndLifeCycle.cpp
+++ /dev/null
@@ -1,249 +0,0 @@
-#define BOOST_TEST_MODULE TestClient
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #54 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <fstream>
-
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-
-#include "ClientInvoker.hpp"
-#include "ClientEnvironment.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "File.hpp"
-#include "PrintStyle.hpp"
-#include "WhiteListFile.hpp"
-#include "InvokeServer.hpp"
-#include "SCPort.hpp"
-#include "Str.hpp"
-#include "System.hpp" // kill singleton for valgrind
-#include "ChangeMgrSingleton.hpp" // kill singleton for valgrind
-
-namespace fs = boost::filesystem;
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( ClientTestSuite )
-
-// ************************************************************************************
-// Note: If you make edits to node tree, they will have no effect until the server is rebuilt
-//
-// Note: To test HPUX->Linux, invoke serve on (Linux/HPUX) and the client cmds on other system
-// On the client side set ECF_NODE to machine name. To allow further testing if ECF_NODE
-// is specified then *don't* shutdown the server
-// ************************************************************************************
-
-BOOST_AUTO_TEST_CASE( test_client_lifecyle )
-{
- // *******************************************************************************************
- // This test will *ONLY* work when testing with new server invocation, since it relies
- // on disabling job generation. Hence ignore test if ECF_NODE has been defined
- // *******************************************************************************************
- std::string host = ClientEnvironment::hostSpecified();
- if (!host.empty()) {
- // Server allready started, since we cant disable job generation ignore this test
- std::cout << "Client:: ...test_client_lifecycle, ignoring test when ECF_NODE specified..." << endl;
- return;
- }
-
- // This will remove check pt and backup file before server start, to avoid the server from loading previous test data
- // ** NOTE: We disable job generation in the server **/
- InvokeServer invokeServer("Client:: ...test_client_lifecycle",SCPort::next(),true /*disable job generation in server*/);
-
- ClientInvoker theClient(invokeServer.host(),invokeServer.port());
- BOOST_REQUIRE_MESSAGE( theClient.restartServer() == 0,CtsApi::restartServer() << " should return 0 server not started, or connection refused\n" << theClient.errorMsg());
-
- // load the defs into the server
- {
- std::string path = File::test_data("Client/test/data/lifecycle.txt","Client");
- BOOST_REQUIRE_MESSAGE(theClient.delete_all() == 0,CtsApi::to_string(CtsApi::delete_node()) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.loadDefs(path) == 0, "Load defs failed \n" << theClient.errorMsg());
- }
- {
- BOOST_REQUIRE_MESSAGE(theClient.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << theClient.errorMsg());
- defs_ptr serverDefs = theClient.defs();
- BOOST_REQUIRE_MESSAGE( serverDefs.get(),"Server returned a NULL defs");
- BOOST_REQUIRE_MESSAGE( serverDefs->suiteVec().size() >= 1," no suite ?");
- }
-
-
- // Now go through and simulate client request to change Node tree state.
- // This is **highly** dependent on lifecycle.txt
- // suite suite1
- // family family1
- // task a
- // event 1 myEvent
- // meter myMeter 0 100
- // task b
- // trigger a == complete
- // endfamily
- // family family2
- // task aa
- // trigger ../family1/a:myMeter >= 20 and ../family1/a:myEvent
- // task bb
- // trigger ../family1/a:myMeter >= 50 || ../family1/a:myEvent
- // endfamily
- // endsuite
-
- string suite1_family1_a = "suite1/family1/a";
- string suite1_family1_b = "suite1/family1/b";
- string suite1_family2_aa = "suite1/family2/aa";
- string suite1_family2_bb = "suite1/family2/bb";
-
- {
- // Begin will set all states to queued and then start job submission placing
- // any submiited jobs into the active state. Note server setup has disabled job generation
- BOOST_REQUIRE_MESSAGE(theClient.begin("suite1") == 0,CtsApi::begin("suite1") << " failed should return 0\n" << theClient.errorMsg());
-
- BOOST_REQUIRE_MESSAGE(theClient.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << theClient.errorMsg());
- defs_ptr serverDefs = theClient.defs();
- node_ptr node = serverDefs->findAbsNode(suite1_family1_a);
- BOOST_REQUIRE_MESSAGE( node->state() == NState::ACTIVE, "Node expected NState::ACTIVE, but found to be " << NState::toString(node->state()));
- }
-
- //**********************************************************************
- // Create a request to set the event on Node suite1/family1/a
- // This should place suite1_family2_bb immediately into submitted state
- // Since we at least one node in submitted, suite should be in SUBMITTED state
- {
- theClient.taskPath(suite1_family1_a);
- theClient.set_jobs_password(Submittable::DUMMY_JOBS_PASSWORD());
- BOOST_REQUIRE_MESSAGE(theClient.eventTask("myEvent") == 0,TaskApi::event("myEvent") << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.forceDependencyEval() == 0,CtsApi::forceDependencyEval() << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << theClient.errorMsg());
- defs_ptr serverDefs = theClient.defs();
- // PrintStyle style(PrintStyle::STATE);
- // cerr << *serverDefs.get() << "\n";
- BOOST_REQUIRE_MESSAGE( serverDefs.get(),"get command failed to get node tree from server");
-
- node_ptr node = serverDefs->findAbsNode(suite1_family1_a);
- BOOST_REQUIRE_MESSAGE( node->state() == NState::ACTIVE, "Node expected NState::ACTIVE, but found to be " << NState::toString(node->state()));
- node_ptr nodeb = serverDefs->findAbsNode(suite1_family2_bb);
- BOOST_REQUIRE_MESSAGE( nodeb->state() == NState::ACTIVE, "Node expected NState::ACTIVE, but found to be " << NState::toString(nodeb->state()));
- }
-
-
- //**********************************************************************
- // Create a request to set the Meter on Node suite1/family1/a
- // This should force suite1_family2_aa immediately into submitted state
- // This should force suite1_family2_bb immediately into submitted state
- {
- theClient.taskPath(suite1_family1_a);
- {
- char* argv[] = { const_cast<char*>("ClientInvoker"),
- const_cast<char*>("--meter=myMeter"),
- const_cast<char*>("100")
- };
- BOOST_REQUIRE_MESSAGE(theClient.invoke(3,argv) == 0," should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.forceDependencyEval() == 0,CtsApi::forceDependencyEval() << " failed should return 0\n" << theClient.errorMsg());
- }
-
- BOOST_REQUIRE_MESSAGE(theClient.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << theClient.errorMsg());
- defs_ptr serverDefs = theClient.defs();
- BOOST_REQUIRE_MESSAGE( serverDefs.get(),"get command failed to get node tree from server");
-
- node_ptr nodeaa = serverDefs->findAbsNode(suite1_family2_aa);
- BOOST_REQUIRE_MESSAGE( nodeaa->state() == NState::ACTIVE, "Node expected NState::ACTIVE, but found to be " << NState::toString(nodeaa->state()));
-
- node_ptr nodebb = serverDefs->findAbsNode(suite1_family2_bb);
- BOOST_REQUIRE_MESSAGE( nodebb->state() == NState::ACTIVE, "Node expected NState::ACTIVE, but found to be " << NState::toString(nodebb->state()));
- }
-
- //**********************************************************************
- // Create a request to complete task suite1/family1/a
- // This should force suite1_family1_b to complete
- {
- theClient.taskPath(suite1_family1_a);
- BOOST_REQUIRE_MESSAGE(theClient.completeTask() == 0,TaskApi::complete() << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.forceDependencyEval() == 0,CtsApi::forceDependencyEval() << " failed should return 0\n" << theClient.errorMsg());
-
- // Resolve dependencies
- // We could either wait 60 second or
- // added a custom command that will force dependency evaluation
- BOOST_REQUIRE_MESSAGE( theClient.forceDependencyEval() == 0,"--force-dep-eval failed should return 0\n" << theClient.errorMsg());
-
- BOOST_REQUIRE_MESSAGE(theClient.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << theClient.errorMsg());
- defs_ptr serverDefs = theClient.defs();
- BOOST_REQUIRE_MESSAGE( serverDefs.get(),"get command failed to get node tree from server");
-
- node_ptr node = serverDefs->findAbsNode(suite1_family1_b);
- BOOST_REQUIRE_MESSAGE( node->state() == NState::ACTIVE, "Expected NState::ACTIVE, but found " << NState::toString(node->state()));
- }
-
- //********************************************************************************
- // Complete the remaining tasks. Should really call init first, but what the eck.
- {
- theClient.taskPath(suite1_family1_b);
- BOOST_REQUIRE_MESSAGE(theClient.completeTask() == 0,TaskApi::complete() << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.forceDependencyEval() == 0,CtsApi::forceDependencyEval() << " failed should return 0\n" << theClient.errorMsg());
-
- theClient.taskPath(suite1_family2_aa);
- BOOST_REQUIRE_MESSAGE(theClient.completeTask() == 0,TaskApi::complete() << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.forceDependencyEval() == 0,CtsApi::forceDependencyEval() << " failed should return 0\n" << theClient.errorMsg());
-
- theClient.taskPath(suite1_family2_bb);
- BOOST_REQUIRE_MESSAGE(theClient.completeTask() == 0,TaskApi::complete() << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.forceDependencyEval() == 0,CtsApi::forceDependencyEval() << " failed should return 0\n" << theClient.errorMsg());
- }
-
- {
- // Get the node tree back from the server, and check its node state
- // All node state should be complete. + check meter/event value was set properly
- BOOST_REQUIRE_MESSAGE(theClient.getDefs() == 0,CtsApi::get() << " failed should return 0\n" << theClient.errorMsg());
-
- defs_ptr serverDefs = theClient.defs();
- BOOST_REQUIRE_MESSAGE( serverDefs.get(),"get command failed to get node tree from server");
-
- std::string metername = "myMeter";
- int meterValue = 100;
- node_ptr node = serverDefs->findAbsNode(suite1_family1_a);
- const Meter& theMeter = node->findMeter(metername);
- BOOST_REQUIRE_MESSAGE( !theMeter.empty(), "Could not find the meter");
- BOOST_REQUIRE_MESSAGE( theMeter.value() == meterValue , "Expected meter value " << meterValue << " but found " << theMeter.value());
- {
- std::string errorMsg; BOOST_REQUIRE_MESSAGE( serverDefs->checkInvariants(errorMsg), errorMsg);
- }
-
- std::string eventname = "myEvent";
- const Event& theEvent = node->findEventByNameOrNumber(eventname);
- BOOST_REQUIRE_MESSAGE( !theEvent.empty(), "Could not find the event myEvent");
- BOOST_REQUIRE_MESSAGE( theEvent.value(), "The event was not set");
-
- const std::vector<suite_ptr>& suiteVec = serverDefs->suiteVec();
- suite_ptr suite = suiteVec.back();
- BOOST_REQUIRE_MESSAGE( suite->state() == NState::COMPLETE,
- "Suite expected NState::COMPLETE, but found to be " << NState::toString(suite->state()));
- }
-
- {
- // Check that a log file was created, by asking the server for it.
- BOOST_REQUIRE_MESSAGE( theClient.getLog() == 0, "get log failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(!theClient.get_string().empty(),"The log file returned from the server is empty!!");
-
- // Clear the log
- BOOST_REQUIRE_MESSAGE(theClient.flushLog() == 0,CtsApi::flushLog() << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.clearLog() == 0,CtsApi::clearLog() << " failed should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE(theClient.delete_all() == 0,CtsApi::to_string(CtsApi::delete_node()) << " should return 0\n" << theClient.errorMsg());
- }
-
- /// Destroy singleton's to avoid valgrind from complaining
- System::destroy();
- ChangeMgrSingleton::destroy();
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/Client/test/TestSignalSIGTERM.cpp b/ecflow_4_0_7/Client/test/TestSignalSIGTERM.cpp
deleted file mode 100644
index aa67be9..0000000
--- a/ecflow_4_0_7/Client/test/TestSignalSIGTERM.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <string>
-#include <fstream>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/test/unit_test.hpp>
-
-#include "ClientInvoker.hpp"
-#include "ClientEnvironment.hpp"
-#include "InvokeServer.hpp"
-#include "SCPort.hpp"
-#include "Str.hpp"
-
-namespace fs = boost::filesystem;
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( ClientTestSuite )
-
-// ************************************************************************************
-// Note: If you make edits to node tree, they will have no effect until the server is rebuilt
-//
-// This test will send a signal SIGTERM, i.e (via kill -15 pid) and check to ensure
-// that a check point file is saved.
-// ************************************************************************************
-BOOST_AUTO_TEST_CASE( test_signal_SIGTERM )
-{
- // This will remove check pt and backup file before server start, to avoid the server from loading previous test data
- InvokeServer invokeServer("Client:: ...test_signal_SIGTERM",SCPort::next());
-
- ClientInvoker theClient(invokeServer.host(),invokeServer.port());
- BOOST_REQUIRE_MESSAGE( theClient.restartServer() == 0,CtsApi::restartServer() << " should return 0 server not started, or connection refused\n" << theClient.errorMsg());
-
- std::string path = File::test_data("Client/test/data/lifecycle.txt","Client");
- BOOST_REQUIRE_MESSAGE(theClient.loadDefs(path) == 0,"load defs failed \n" << theClient.errorMsg());
-
- // Get the definition
- BOOST_REQUIRE_MESSAGE(theClient.sync_local() == 0, "Sync local failed\n" << theClient.errorMsg());
-
- // Get the process id of the server
- const std::string& ecf_pid = theClient.defs()->server().find_variable("ECF_PID");
- BOOST_REQUIRE_MESSAGE(!ecf_pid.empty(),"ECF_PID not set in the server");
-
- // Send a SIGTERM to the server and ensure that a check point file is created
- std::string sigterm = "kill -15 " + ecf_pid ;
- system(sigterm.c_str());
- sleep(2); // allow time for system call
-
- // We expect a check point file to be save to disk, but *no* backup
- BOOST_REQUIRE_MESSAGE(fs::exists(invokeServer.ecf_checkpt_file()),CtsApi::checkPtDefs() << " failed file(" << invokeServer.ecf_checkpt_file() << ") not saved");
- BOOST_REQUIRE_MESSAGE(fs::file_size(invokeServer.ecf_checkpt_file()) !=0,"Expected check point file(" << invokeServer.ecf_checkpt_file() << "), to have file size > 0");
- if (ClientEnvironment::hostSpecified().empty()) {
- // This check only valid if server was invoked locally. Ignore for remote servers
- BOOST_REQUIRE_MESSAGE(!fs::exists(invokeServer.ecf_backup_checkpt_file()), "Backup check point file(" << invokeServer.ecf_backup_checkpt_file() << ")should not exist,for very first time.");
- }
-
- // Send a SIGTERM again. This time we expect the backup check point file to be created.
- system(sigterm.c_str());
- sleep(2); // allow time for system call
-
- BOOST_REQUIRE_MESSAGE(fs::exists(invokeServer.ecf_checkpt_file()),CtsApi::checkPtDefs() << " failed No check pt file(" << invokeServer.ecf_checkpt_file() << ") saved");
- BOOST_REQUIRE_MESSAGE(fs::file_size(invokeServer.ecf_checkpt_file()) !=0,"Expected check point file(" << invokeServer.ecf_checkpt_file() << ") to have file size > 0 ");
- BOOST_REQUIRE_MESSAGE(fs::exists(invokeServer.ecf_backup_checkpt_file()), "Expected backup check point file(" << invokeServer.ecf_backup_checkpt_file() << ") to be created");
- BOOST_REQUIRE_MESSAGE(fs::file_size(invokeServer.ecf_backup_checkpt_file()) !=0,"Expected backup check point file(" << invokeServer.ecf_backup_checkpt_file() << "), to have file size > 0");
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/Client/test/TestSinglePerf.cpp b/ecflow_4_0_7/Client/test/TestSinglePerf.cpp
deleted file mode 100644
index 6fad523..0000000
--- a/ecflow_4_0_7/Client/test/TestSinglePerf.cpp
+++ /dev/null
@@ -1,211 +0,0 @@
-#define BOOST_TEST_MODULE TestSingle
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #11 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <fstream>
-
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/timer.hpp>
-
-#include "ClientInvoker.hpp"
-#include "ClientEnvironment.hpp"
-#include "File.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Task.hpp"
-#include "TestHelper.hpp"
-#include "InvokeServer.hpp"
-#include "SCPort.hpp"
-#include "Str.hpp"
-#include "Host.hpp"
-#include "Rtt.hpp"
-#include "DurationTimer.hpp"
-
-namespace fs = boost::filesystem;
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( ClientTestSuite )
-
-// ************************************************************************************
-// Note: If you make edits to node tree, they will have no effect until the server is rebuilt
-// ************************************************************************************
-
-static void sync_and_news_local(ClientInvoker& theClient)
-{
- {
- cout << " news_local() : ";
- DurationTimer duration_timer;
- theClient.news_local();
- cout << (double)duration_timer.elapsed().total_milliseconds()/(double)1000;
- }
- {
- cout << " sync_local() : ";
- DurationTimer duration_timer;
- theClient.sync_local();
- cout << (double)duration_timer.elapsed().total_milliseconds()/(double)1000 << endl;
- }
-}
-
-void time_load_and_downloads(
- ClientInvoker& theClient,
- const std::string& host,
- const std::string& port,
- const std::string& directory
-)
-{
- fs::path full_path( fs::initial_path<fs::path>() );
- full_path = fs::system_complete( fs::path( directory ) );
-
- BOOST_CHECK(fs::exists( full_path ));
- BOOST_CHECK(fs::is_directory( full_path ));
-
- int count = 10;
-
- //std::cout << "\nIn directory: " << full_path.directory_string() << "\n\n";
- fs::directory_iterator end_iter;
- for ( fs::directory_iterator dir_itr( full_path ); dir_itr != end_iter; ++dir_itr )
- {
- try
- {
- fs::path relPath(directory + "/" + dir_itr->path().filename().string());
-
- // recurse down directories
- if ( is_directory(dir_itr->status()) ) {
- time_load_and_downloads(theClient,host,port,relPath.string());
- continue;
- }
-
- cout << "\n" << relPath.string() << " : file size " << fs::file_size(relPath) << endl;
- {
- DurationTimer duration_timer;
- BOOST_REQUIRE_MESSAGE(theClient.loadDefs(relPath.string()) == 0,"load defs failed \n" << theClient.errorMsg());
- cout << " Load: " << duration_timer.elapsed().total_milliseconds() << "ms" << endl;
- }
- {
- DurationTimer duration_timer;
- BOOST_REQUIRE_MESSAGE(theClient.begin_all_suites() == 0,"begin failed \n" << theClient.errorMsg());
- cout << " Begin: " << duration_timer.elapsed().total_milliseconds() << "ms" << endl;
- }
- {
- cout << " Download(Sync): ";
- for(int i = 0; i < count; i++) {
- DurationTimer duration_timer;
- theClient.sync_local();
- int seconds = duration_timer.elapsed().total_milliseconds();
- cout << seconds << " ";
- }
- cout << ":(milli-seconds) sync_local() with the same Client. First call updates cache." << endl;
- }
- {
- // On construction of Defs, hence should be slightly faster
- cout << " Download(Sync-FULL): ";
- double total = 0;
- for(int i = 0; i < count; i++) {
- ClientInvoker client(host,port);
- DurationTimer duration_timer;
- client.sync_local();
- int seconds = duration_timer.elapsed().total_milliseconds();
- cout << seconds << " ";
- total += seconds;
- }
- cout << ": Avg:" << (double)(total)/((double)count*1000) << "(sec) : sync_local() with *different* clients. Uses Cache" << endl;
- }
- {
- // This should more expensive on second call, due to destruction of
- // defs(on theClient) from previous calls
- cout << " Download(FULL): ";
- double total = 0;
- for(int i = 0; i < count; i++) {
- DurationTimer duration_timer;
- theClient.getDefs();
- int seconds = duration_timer.elapsed().total_milliseconds();
- cout << seconds << " ";
- total += seconds;
- }
- cout << ": Avg:" << (double)(total)/((double)count*1000) << "(sec) : get_defs() from same client" << endl;
- }
- {
- std::vector<task_ptr> all_tasks;
- theClient.defs()->get_all_tasks(all_tasks);
- std::vector<std::string> paths;paths.reserve(all_tasks.size());
- for(size_t i = 0; i < all_tasks.size(); i++) {
- paths.push_back(all_tasks[i]->absNodePath());
- if (i == 6000) break; // > 9000 really slows down, could be logging ??
- }
- {
- cout << " Suspend " << paths.size() << " tasks : ";
- DurationTimer duration_timer;
- theClient.suspend(paths);
- cout << (double)duration_timer.elapsed().total_milliseconds()/(double)1000;
- }
- sync_and_news_local(theClient);
- {
- cout << " Resume " << paths.size() << " tasks : ";
- DurationTimer duration_timer;
- theClient.resume(paths);
- cout << (double)duration_timer.elapsed().total_milliseconds()/(double)1000;
- }
- sync_and_news_local(theClient);
- {
- cout << " force " << paths.size() << " tasks : ";
- DurationTimer duration_timer;
- theClient.force(paths,"complete");
- cout << (double)duration_timer.elapsed().total_milliseconds()/(double)1000;
- }
- sync_and_news_local(theClient);
- }
- {
- // This should more expensive on second call, due to destruction of
- // defs(on theClient) from previous calls
- cout << " Check pt: ";
- double total = 0;
- for(int i = 0; i < count; i++) {
- DurationTimer duration_timer;
- theClient.checkPtDefs();
- int seconds = duration_timer.elapsed().total_milliseconds();
- cout << seconds << " ";
- total += seconds;
- }
- cout << ": Avg:" << (double)(total)/((double)count*1000) << "ms" << endl;
- }
- {
- DurationTimer duration_timer;
- BOOST_REQUIRE_MESSAGE(theClient.delete_all(true) == 0,"delete all defs failed \n" << theClient.errorMsg());
- cout << " Delete: " << duration_timer.elapsed().total_milliseconds() << "ms" << endl;
- }
- }
- catch ( const std::exception & ex ) {
- std::cout << dir_itr->path().filename() << " " << ex.what() << std::endl;
- }
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_perf_for_large_defs )
-{
- if (fs::exists("/var/tmp/ma0/BIG_DEFS")) {
- /// This will remove checkpt and backup , to avoid server from loading it. (i.e from previous test)
- InvokeServer invokeServer("Client:: ...test_perf_for_large_defs:",SCPort::next());
-
- ClientInvoker theClient(invokeServer.host(), invokeServer.port());
- time_load_and_downloads(theClient,invokeServer.host(), invokeServer.port(),"/var/tmp/ma0/BIG_DEFS");
- }
- else {
- std::cout << "Ingoring test, since directory /var/tmp/ma0/BIG_DEFS does not exist";
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Client/test/TestUrlCmd.cpp b/ecflow_4_0_7/Client/test/TestUrlCmd.cpp
deleted file mode 100644
index aa6fd47..0000000
--- a/ecflow_4_0_7/Client/test/TestUrlCmd.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-//============================================================================
-// Name : Request
-// Author : Avi
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <string>
-#include <iostream>
-#include <fstream>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/test/unit_test.hpp>
-
-#include "DefsStructureParser.hpp"
-#include "Defs.hpp"
-#include "UrlCmd.hpp"
-#include "File.hpp"
-
-using namespace std;
-using namespace ecf;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( ClientTestSuite )
-
-//=============================================================================
-// This will test the UrlCmd.
-BOOST_AUTO_TEST_CASE( test_url_cmd )
-{
- cout << "Client:: ...test_url_cmd" << endl;
-
- std::string path = File::test_data("Client/test/data/lifecycle.txt","Client");
-
- defs_ptr defs = Defs::create();
-
- DefsStructureParser checkPtParser( defs.get(), path );
- std::string errorMsg,warningMsg;
- bool parse = checkPtParser.doParse(errorMsg,warningMsg);
- BOOST_CHECK_MESSAGE(parse,errorMsg);
-
- // Check error conditions
- BOOST_REQUIRE_THROW(UrlCmd(defs,"a made up name"), std::runtime_error );
- BOOST_REQUIRE_THROW(UrlCmd(defs_ptr(),"/suite1/family1/a"), std::runtime_error );
-
- // The Url command relies on variable substitution, hence we must ensure that
- // generated variables are created.
- defs->beginAll();
-
- UrlCmd urlCmd(defs,"/suite1/family1/a");
- std::string expected = "${BROWSER:=firefox} -remote 'openURL(http://www.ecmwf.int/publications/manuals/sms)'";
- std::string actual = urlCmd.getUrl();
- BOOST_CHECK_MESSAGE( expected == actual,"Expected '" << expected << "' but found " << actual);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-
diff --git a/ecflow_4_0_7/Client/test/TestWhiteListFile.cpp b/ecflow_4_0_7/Client/test/TestWhiteListFile.cpp
deleted file mode 100644
index 2ed7e11..0000000
--- a/ecflow_4_0_7/Client/test/TestWhiteListFile.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <boost/test/unit_test.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-
-#include "ClientInvoker.hpp"
-#include "ClientEnvironment.hpp"
-#include "WhiteListFile.hpp"
-#include "InvokeServer.hpp"
-#include "SCPort.hpp"
-#include "Str.hpp"
-
-namespace fs = boost::filesystem;
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( ClientTestSuite )
-
-// ************************************************************************************
-// Note: If you make edits to node tree, they will have no effect until the server is rebuilt
-//
-// Note: To test HPUX->Linux, invoke serve on (Linux/HPUX) and the client cmds on other system
-// On the client side set ECF_NODE to machine name. To allow further testing if ECF_NODE
-// is specified then *don't* shutdown the server
-// ************************************************************************************
-
-BOOST_AUTO_TEST_CASE( test_loading_of_white_list_file )
-{
- Host the_host;
- std::string port = SCPort::next();
- std::string host = ClientEnvironment::hostSpecified();
- if (host.empty()) {
-
- // make sure NO whitelist file is present before the server is started.
- // This allows any user to send requests to the server
- // Only do this locally, as white list file on remote machine may not be accessible
- fs::remove(the_host.ecf_lists_file(port));
- }
-
- // This will remove check pt and backup file before server start, to avoid the server from loading previous test data
- InvokeServer invokeServer("Client:: ...test_loading_of_white_list_file",port);
-
- ClientInvoker theClient(invokeServer.host(),invokeServer.port());
- BOOST_REQUIRE_MESSAGE( theClient.delete_all() == 0,CtsApi::to_string(CtsApi::delete_node()) << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.shutdownServer() == 0,CtsApi::shutdownServer() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.haltServer() == 0,CtsApi::haltServer() << " should return 0\n" << theClient.errorMsg());
- BOOST_REQUIRE_MESSAGE( theClient.restartServer() == 0,CtsApi::restartServer() << " should return 0\n" << theClient.errorMsg());
-
- // OK now test white list file functionality, but only if server was invoked locally
- if ( host.empty() ) {
-
- // The white list file should not exist, hence reload white list SHOULD fail.
- // i.e because we deleted it earlier
- BOOST_REQUIRE_THROW( theClient.reloadwsfile(), std::runtime_error);
-
- // Create a valid white list file; For the FIRST time:
- // **** IMPORTANT: if we had reloaded a white list file where the user has read access
- // **************: _FIRST_ it will not be possible reload white file with write access, afterwards
- // **************: since subsequent RELOAD command itself will require write access
- std::string errorMsg;
- BOOST_REQUIRE_MESSAGE(WhiteListFile::createWithWriteAccess(the_host.ecf_lists_file(port),errorMsg),errorMsg);
-
- // Reload should pass, as its the _first_ time
- BOOST_REQUIRE_MESSAGE( theClient.reloadwsfile() == 0, CtsApi::reloadwsfile() << " should return 0\n" << theClient.errorMsg());
-
- // Invoking a client request that requires write access, should pass
- BOOST_CHECK_MESSAGE( theClient.shutdownServer() == 0,"should return 0\n" << theClient.errorMsg());
-
- // Remove the white list file. Comment out for debug
- fs::remove(the_host.ecf_lists_file(port));
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/Doc/user-manual/user_manual.docx b/ecflow_4_0_7/Doc/user-manual/user_manual.docx
deleted file mode 100644
index f30dccc..0000000
Binary files a/ecflow_4_0_7/Doc/user-manual/user_manual.docx and /dev/null differ
diff --git a/ecflow_4_0_7/Jamroot.jam b/ecflow_4_0_7/Jamroot.jam
deleted file mode 100644
index b5e658e..0000000
--- a/ecflow_4_0_7/Jamroot.jam
+++ /dev/null
@@ -1,187 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-#
-# To clean all the sub projects just use: bjam --clean
-#
-path-constant TOP : . ; # After that, the TOP variable can be used in every Jamfile.
-
-build-project ACore ;
-build-project ANattr ;
-build-project ANode ;
-build-project AParser ;
-build-project Base ;
-build-project Client ;
-build-project CSim ;
-build-project Server ;
-build-project Test ;
-
-# The gui is not built on HPUX and IBM(power6) platforms
-import os ;
-ARCH = [ os.environ ARCH ] ;
-ARCH default = UNDEF ; # if arch not defined set as UNDEF, otherwise if $(ARCH) will be true
-build_gui = linux cray other_gui_arch ;
-# echo "ARCH = $(ARCH)" ;
-if $(ARCH) in $(build_gui) {
- build-project view ;
-}
-
-# Some user do no want python: They must define ECF_NO_PYTHON
-NO_PYTHON = [ os.environ ECF_NO_PYTHON ] ;
-#echo "NO_PYTHON = $(NO_PYTHON)" ;
-if ! $(NO_PYTHON) {
- # echo "building python" ;
- build-project Pyext ;
-}
-
-# ==================== INSTALL ==========================================================
-
-local dest_dir = [ os.environ ECFLOW_DESTDIR ] ;
-dest_dir default = "" ;
-constant ECFLOW_DESTDIR : $(dest_dir) ;
-
-local ECFLOW_VERSION = [ SHELL "cd $(TOP); ./version.sh" ] ;
-local install_dir = [ os.environ ECFLOW_INSTALL_DIR ] ;
-install_dir default = "/usr/local/apps/ecflow/$(ECFLOW_VERSION)" ;
-constant ECFLOW_INSTALL_DIR : $(install_dir) ;
-
-local python_install_dir = [ os.environ ECFLOW_PYTHON_INSTALL_DIR ] ;
-python_install_dir default = $(install_dir)/lib/python2.7/site-packages/ecflow ;
-constant ECFLOW_PYTHON_INSTALL_DIR : $(python_install_dir) ;
-
-# Used for ecflowview files
-constant ECFLOW_SHARED_DIR : $(ECFLOW_DESTDIR)$(ECFLOW_INSTALL_DIR)/share/ecflow ;
-
-#echo "ECFLOW_VERSION = '$(ECFLOW_VERSION)'" ;
-#echo "ECFLOW_DESTDIR = '$(ECFLOW_DESTDIR)'" ;
-#echo "ECFLOW_INSTALL_DIR = '$(ECFLOW_INSTALL_DIR)'" ;
-#echo "ECFLOW_PYTHON_INSTALL_DIR = '$(ECFLOW_PYTHON_INSTALL_DIR)'" ;
-#echo "ECFLOW_SHARED_DIR = '$(ECFLOW_SHARED_DIR)'" ;
-
-#
-# Allow the installation directory be be defined externally, by the environment variable ECFLOW_INSTALL_DIR
-#
-# However we want this to be explicit, as we dont need it on a day to day basis.
-# Usage:
-# bjam install variant=release
-#
-# to install the debug version
-# bjam install | bjam install variant=debug
-#
-# To preview the installation witout actaully doing it:
-# bjam install variant=release -d2 -n
-#
-# Note: if you find that the install has started to create directories
-# of name install-server,install-client,,install-py
-# Then *ensure* you have set the environment variables ECFLOW_INSTALL_DIR,
-#
-# Note: Not all system have XLib, hence install ecFlowview manually by using:
-# bjam -d2 install-viewer
-#
-# Make sure for ECMWF that ECFLOW_INSTALL_DIR leaf directory encompasses version number
-# that ties up with $WK/VERSION.cmake
-#
-
-# Do no call this on the command line, prefer bjam install-all || install-viewer
-# If this is called in isolation ldd will show the referenced shared lib as missing
-install install-view
- : view//ecflowview
- : <location>$(ECFLOW_DESTDIR)/$(ECFLOW_INSTALL_DIR)/bin
- <dll-path>$(ECFLOW_INSTALL_DIR)/lib
- ;
-
-
-# Some linux RPM have requirements that 64 bit libs must be under lib64
-# See http://software.ecmwf.int/issues/browse/ECFLOW-30, 64-bit Linux platforms expect libraries to go to the $PREFIX/lib64 directory, not $PREFIX/lib
-#
-install install-view64
- : view//ecflowview
- : <location>$(ECFLOW_DESTDIR)/$(ECFLOW_INSTALL_DIR)/bin
- <dll-path>$(ECFLOW_INSTALL_DIR)/lib64
- ;
-
-install install-view-files
- : [ glob view/servers ]
- [ glob view/src/ecflowview.menu ]
- : <location>$(ECFLOW_SHARED_DIR)
- ;
-
-install install-server
- : Server//ecflow_server
- : <location>$(ECFLOW_DESTDIR)/$(ECFLOW_INSTALL_DIR)/bin
- ;
-
-install install-client
- : Client//ecflow_client
- : <location>$(ECFLOW_DESTDIR)/$(ECFLOW_INSTALL_DIR)/bin
- ;
-
-install install-tools
- : [ glob tools/*.sh ]
- [ glob tools/*.pl ]
- : <location>$(ECFLOW_DESTDIR)/$(ECFLOW_INSTALL_DIR)/bin
- ;
-
-install install-doc
- : [ glob Doc/user-manual/*.docx ]
- [ glob Doc/user-manual/*.pdf ]
- : <location>$(ECFLOW_DESTDIR)/$(ECFLOW_INSTALL_DIR)/doc/ecflow
- ;
-
-# Fix bugs associated with the output of old version of ecflow_client --migrate
-install install-migrate
- : [ glob Pyext/migrate/ecflow_migrate.py ]
- : <location>$(ECFLOW_DESTDIR)/$(ECFLOW_INSTALL_DIR)/bin
- ;
-
-# ===============================================================================================
-
-# Use this for a non-python install
-alias install-base :
- install-server
- install-client
- install-tools
- install-doc
- install-migrate
- ;
-alias install :
- install-base
- Pyext//install-py
- Pyext//install-py1
- ;
-alias install-viewer :
- install-view
- install-view-files
- ;
-alias install-viewer64 :
- install-view64
- install-view-files
- ;
-alias install-all :
- install
- install-viewer
- ;
-alias install-all64 :
- install
- install-viewer64
- ;
-
-# make install explicit, otherwise we end installing for all calls to bjam
-explicit install-server ;
-explicit install-client ;
-explicit install-tools ;
-explicit install-view ;
-explicit install-viewer ;
-explicit install-view64 ;
-explicit install-viewer64 ;
-explicit install-view-files ;
-explicit install-doc ;
-explicit install-migrate ;
-explicit install ;
-explicit install-base ;
-explicit install-all ;
-explicit install-all64 ;
diff --git a/ecflow_4_0_7/Makefile b/ecflow_4_0_7/Makefile
deleted file mode 100644
index db1d031..0000000
--- a/ecflow_4_0_7/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-# This is used as part of install build/install for cmake/ecbuild
-
-default: release
-
-release:
- (cd ../cmake_build_dir/ecflow/release; make -j4)
-
-install:
- (cd ../cmake_build_dir/ecflow/release; make install)
diff --git a/ecflow_4_0_7/Makefile.old b/ecflow_4_0_7/Makefile.old
deleted file mode 100644
index f1a3316..0000000
--- a/ecflow_4_0_7/Makefile.old
+++ /dev/null
@@ -1,24 +0,0 @@
-BJAM=$(BOOST_ROOT)/bjam c++-template-depth=512
-
-all: ecf view
-
-ecf:
- echo . ./view/tool/env.sh
- $(BJAM) -j4
-rel:
- $(BJAM) -j4 variant=release
-
-view:
- (cd view; $(BJAM) -j4)
-
-clean:
- $(BJAM) clean;
- (cd view; $(BJAM) clean)
-
-realclean:
- rm -rf */bin Pyext/ecflow/ecflow.so
-
-tar:
- cd ../..; tar -cjvf $SCRATCH/ecf.tbz workspace
-
-
diff --git a/ecflow_4_0_7/NOTICE b/ecflow_4_0_7/NOTICE
deleted file mode 100644
index 16e734d..0000000
--- a/ecflow_4_0_7/NOTICE
+++ /dev/null
@@ -1,56 +0,0 @@
-Apache [ecflow]
- Copyright [2009-2012] The Apache Software Foundation
-
- This product includes software developed at
- The Apache Software Foundation (http://www.apache.org/).
-
-
-
-Boost Software License - Version 1.0 - August 17th, 2003
-========================================================
-
-Permission is hereby granted, free of charge, to any person or organization
-obtaining a copy of the software and accompanying documentation covered by
-this license (the "Software") to use, reproduce, display, distribute,
-execute, and transmit the Software, and to prepare derivative works of the
-Software, and to permit third-parties to whom the Software is furnished to
-do so, all subject to the following:
-
-The copyright notices in the Software and this entire statement, including
-the above license grant, this restriction and the following disclaimer,
-must be included in all copies of the Software, in whole or in part, and
-all derivative works of the Software, unless such copies or derivative
-works are solely in the form of machine-executable object code generated by
-a source language processor.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
-SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
-FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
-ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.
-
-
-
-The MIT License (MIT) - EOS-Portable-library
-============================================
-Copyright (c) 2012 EOS GmbH
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"),
-to deal in the Software without restriction, including without limitation
-the rights to use, copy, modify, merge, publish, distribute, sublicense,
-and/or sell copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included
-in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
-SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
-FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
-OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/ecflow_4_0_7/Pyext/.gitignore b/ecflow_4_0_7/Pyext/.gitignore
deleted file mode 100644
index 7558d28..0000000
--- a/ecflow_4_0_7/Pyext/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-/build
-/setup.py
diff --git a/ecflow_4_0_7/Pyext/CMakeLists.txt b/ecflow_4_0_7/Pyext/CMakeLists.txt
deleted file mode 100644
index f96babd..0000000
--- a/ecflow_4_0_7/Pyext/CMakeLists.txt
+++ /dev/null
@@ -1,143 +0,0 @@
-### ecflow python bindings
-
-file( GLOB srcs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp" "src/*.hpp" )
-
-# local includes
-include_directories(
- ../ACore/src
- ../ANattr/src
- ../ANode/src
- ../AParser/src
- ../Base/src
- ../Base/src/cts
- ../Base/src/stc
- ../Client/src
- ../CSim/src
- )
-
-# INCLUDES here is for external includes
-ecbuild_add_library( TARGET ecflow
- TYPE MODULE
- SOURCES ${srcs}
- CONDITION PYTHONLIBS_FOUND
- LIBS libclient libsimu base libparser node nodeattr core
- ${PYTHON_LIBRARIES}
- INCLUDES
- ${Boost_INCLUDE_DIRS}
- ${PYTHON_INCLUDE_DIRS}
- )
-
-# This ensures that for debug config, we only link with debug boost libs, for other configs, we link with optimised boost libs
-target_link_libraries(ecflow debug ${Boost_PYTHON_LIBRARY_DEBUG} ${Boost_PYTHON_LIBRARY_RELEASE})
-
-#
-# Override default behaviour that add RPATHS during install
-# The only thing that seem to work is set INSTALL_RPATH to ""
-# Using SKIP_BUILD_RPATH,BUILD_WITH_INSTALL_RPATH,INSTALL_RPATH_USE_LINK_PATH
-# had no effect
-#
-# by default cmake add prefix 'lib', we don't want this hence disable
-set_target_properties(ecflow PROPERTIES
- PREFIX ""
- INSTALL_RPATH ""
- )
-
-### tests
-
-list( APPEND tests
- py_u_TestAddDelete
- py_u_TestAddDeleteFunc
- py_u_TestAddNodeFunc
- py_s_TestClientApi
- py_s_TestPythonChildApi
- py_u_TestDefs
- py_u_TestDefsCheck
- py_u_TestDerivable
- py_u_TestEcf
- py_u_TestError
- py_u_TestFind
- py_u_TestGetAllTasks
- py_u_TestJobGeneration
- py_u_TestParent
- py_u_TestRepeatArithmetic
- py_u_TestSimulator
- py_u_TestTraversal
- py_u_TestUserManual
- py_u_TestWith
-)
-
-foreach( test ${tests} )
-
- ecbuild_add_test( TARGET ${test}
- TYPE PYTHON
- ARGS ${CMAKE_CURRENT_SOURCE_DIR}/test/${test}.py
- ENVIRONMENT "PYTHONPATH=${CMAKE_BINARY_DIR}/lib"
- TEST_DEPENDS u_base
- )
-endforeach()
-
-set_property(TEST py_s_TestClientApi APPEND PROPERTY DEPENDS s_test)
-set_property(TEST py_s_TestPythonChildApi APPEND PROPERTY DEPENDS py_s_TestClientApi)
-
-ecbuild_add_test( TARGET py_u_TestMigrate
- TYPE PYTHON
- ARGS ${CMAKE_CURRENT_SOURCE_DIR}/migrate/py_u_TestMigrate.py
- ENVIRONMENT "PYTHONPATH=${CMAKE_BINARY_DIR}/lib" )
-
-
-# ==========================================================================
-# install
-# ==========================================================================
-if( ENABLE_PYTHON )
-
- message( STATUS "python found, CMAKE_PYTHON_INSTALL_TYPE=${CMAKE_PYTHON_INSTALL_TYPE}")
-
- # CMAKE_PYTHON_INSTALL_TYPE = [ local | setup ]
-
- if( CMAKE_PYTHON_INSTALL_TYPE MATCHES "local" OR NOT DEFINED CMAKE_PYTHON_INSTALL_TYPE )
-
- message(STATUS "python install *LOCAL* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
- set(PYTHON_SITE "lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages" )
- set(PYTHON_DEST "${PYTHON_SITE}/ecflow" )
-
- install( TARGETS ecflow DESTINATION ${PYTHON_DEST}
- RENAME ecflow.so
- )
- install( FILES ecflow/__init__.py DESTINATION ${PYTHON_DEST} )
-
- else()
-
- # -------------------------------------------------------------------------------------
- # Install using setup.py
- # See: http://bloerg.net/2012/11/10/cmake-and-distutils.html
- # -------------------------------------------------------------------------------------
- message(STATUS "python install using *setup.py* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
- message(STATUS "CMAKE_CURRENT_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}")
- message(STATUS "CMAKE_BINARY_DIR=${CMAKE_BINARY_DIR}")
- message(STATUS "CMAKE_PYTHON_INSTALL_PREFIX : ${CMAKE_PYTHON_INSTALL_PREFIX}" )
-
- set(SETUP_PY_IN "${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in")
- set(SETUP_PY "${CMAKE_CURRENT_SOURCE_DIR}/setup.py")
- set(DEPS "${CMAKE_CURRENT_SOURCE_DIR}/ecflow/__init__.py")
- set(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/timestamp")
-
- configure_file(${SETUP_PY_IN} ${SETUP_PY} )
-
- add_custom_command(OUTPUT ${OUTPUT}
- COMMAND ${PYTHON} ${SETUP_PY} build
- COMMAND ${CMAKE_COMMAND} -E touch ${OUTPUT}
- DEPENDS ${DEPS})
- add_custom_target(target ALL DEPENDS ${OUTPUT})
-
-
- install(CODE "execute_process(COMMAND ${PYTHON} ${SETUP_PY} build_ext)")
-
- if( DEFINED CMAKE_PYTHON_INSTALL_PREFIX )
- message(STATUS "custom/*test* python install prefix defined CMAKE_PYTHON_INSTALL_PREFIX=${CMAKE_PYTHON_INSTALL_PREFIX}")
- install(CODE "execute_process(COMMAND ${PYTHON} ${SETUP_PY} install -f --prefix=${CMAKE_PYTHON_INSTALL_PREFIX})")
- else()
- install(CODE "execute_process(COMMAND ${PYTHON} ${SETUP_PY} install)")
- endif()
- endif()
-
-endif()
diff --git a/ecflow_4_0_7/Pyext/doc/jamfile.jam b/ecflow_4_0_7/Pyext/doc/jamfile.jam
deleted file mode 100644
index af12a9d..0000000
--- a/ecflow_4_0_7/Pyext/doc/jamfile.jam
+++ /dev/null
@@ -1,299 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-# =============================================================================
-# This jam file, allows for creation of ecflow python extension module, where
-# we have a SHARED link to boost python, additionally boost python is
-# installed, and a rpath is set to it.
-# ===============================================================================
-
-# ===============================================================================
-# Error to watch out for:
-# error: No best alternative for /python_for_extensions
-# next alternative: required properties: <python>2.7 <target-os>linux
-# matched
-# next alternative: required properties: <python>2.7 <target-os>linux
-# matched
-#
-# Please check if you have more than one 'using python' in configuration files.
-# Please check site-config.jam, user-config.jam and project-config.jam and
-# remove duplicated 'using python'
-# ===============================================================================
-
-#
-# jamfile for installing, building exposing c++ library to python.
-# and for testing embedded python
-#
-# Use of <dll-path> should force a relink. But this *ONLY* works for executables
-# and *NOT* shared libraries. The HACKY work around is use <dll-path> when
-# building the extension. Hence this requires that ECFLOW_INSTALL_DIR
-# is correctly set during build time. Yuk.
-#
-project thePyext ;
-
-use-project theCore : ../ACore ;
-use-project theNodeAttr : ../ANattr ;
-use-project theNode : ../ANode ;
-use-project theParser : ../AParser ;
-use-project theBase : ../Base ;
-use-project theClient : ../Client ;
-use-project theSimulator : ../CSim ;
-
-# Make the definition of the python-extension rule available
-# Somehow this bjam causes boost python libs to be built under $BOOST_ROOT/bin.v2
-# How can I get it to use boost python that was built with all the other boost libs ???
-import python ;
-
-if ! [ python.configured ]
-{
- # ECHO "notice: no Python configured in user-config.jam" ;
- # ECHO "notice: will use default configuration" ;
- # We will typically place this in user-congig/site-config.jam
- #using python
- # : # version
- # : # cmd-or-prefix
- # : # includes
- # : # libraries
- # : # condition
- # ;
- using python ;
-}
-
-# Specify the path to the Boost project. If you move this project,
-# adjust this path to refer to the Boost root directory.
-import os ;
-local BOOST_ROOT = [ os.environ BOOST_ROOT ] ;
-use-project boost
- : $(BOOST_ROOT) ;
-
-
-# ===================== project settings =================================
-# Set up the project-wide requirements that everything uses the
-# boost_python library from the project whose global ID is /boost/python.
-#
-# AIX: need to add additional include for pyconfig.hpp since we have
-# one for python32 and another one for python64.
-# (Typically there is only _one_ in the python includes dir)
-# *** This should have been added to site-config.jam file **
-#
-# AIX: we get TOC overflow, because compiler/linker has 64k limit on
-# the number of global symbols. Options are use:
-# 0/ Break up shared lib
-# 1/ -bbigtoc to overcome at the cost of performance degradation
-# 2/ --qipa=level=0 if this fails try
-# 3/ --qipa=level=1 if this fails try
-# 4/ --qipa=level=2 if this fails, revert to -bbigtoc
-# Currently option 2-4 didn't work!
-# *** This should have been added to site-config.jam file **
-# prevously we had: : requirements <toolset>vacpp:<linkflags>-bbigtoc
-#
-# If we use:
-# : requirements <library>/boost/python//boost_python
-# THEN we will depend on $BOOST_ROOT/bin.v2/...
-# This will be automatically compiled if it does not exist
-# : requirements <library>/site-config//boost_python
-# THEN use the boost python in $BOOST_ROOT/stage/lib/
-# This is also expects we have defined boost_python in site-config.jam/user-config.jam
-#
-project
-# : requirements <library>/boost/python//boost_python
- : requirements <library>/site-config//boost_python
- ;
-
-# ======================== libs ============================================
-# HPUX: ADD standard libs. They don't get added by default ?
-# Also on HPUX the shared libs appears reversed, and don't appear
-# in the order specified weird ?
-# Notice the use of <library> to add additional library on the link line
-# but only for HPUX/acc toolset
-# <ALL>: It appears the pthread lib is automatically added. i.e >lib pthread ;
-#
-# Note: <toolset>vacpp:<linkflags>-bbigtoc was required for
-# ecgate(rs6000) ONLY and not c1b(ibm_power6)
-
-lib std_v2 ;
-lib stream ;
-lib Csup ;
-lib unwind ;
-lib m ;
-alias hpux_std_libs : std_v2 stream Csup unwind m ;
-
-# ========================================================================
-# Extension: Declare a Python extension called ecflow.
-# ========================================================================
-python-extension ecflow : [ glob src/*.cpp ]
- /theCore//core
- /theNodeAttr//nodeattr
- /theNode//node
- /theParser//libparser
- /theBase//base
- /theClient//libclient
- /theSimulator//libsimu
- /site-config//boost_system
- /site-config//boost_serialization
- /site-config//boost_filesystem
- /site-config//boost_program_options
- /site-config//boost_datetime
- : <variant>debug:<define>DEBUG
- <toolset>acc:<library>hpux_std_libs
- <toolset>acc:<linkflags>-L$(ECFLOW_PYTHON_INSTALL_DIR)
- <toolset>vacpp:<linkflags>-L$(ECFLOW_PYTHON_INSTALL_DIR)
- <toolset>vacpp:<linkflags>-bbigtoc
- <dll-path>$(ECFLOW_PYTHON_INSTALL_DIR)
- ;
-
-# ========================================================================
-# Documentation:
-# ========================================================================
-# Place the shared library 'ecflow' into the ecflow/ directory.
-# - *REQUIRED* for sphinx-build. Documentation generation See Doc/online/conf.py
-# We use this as first place to look for c++ extension
-# - avoids hard wired dependency on compiler path
-# - Picks up latest changes
-install ecflow/ : ecflow ;
-
-
-# ========================================================================
-# INSTALLATION:
-# ========================================================================
-# <dll-path> specify the path which will be used at runtime to search for dynamic libraries
-# it is like using rpath, i.e. to hard code a directory, when doing a runtime search for a library
-# <dll-path>$(ECFLOW_PYTHON_INSTALL_DIR), is used, to dynamically load boost-python shared library
-# Requested by User Support, to avoid having user add LD_LIBRARY_PATH to their environment
-#
-# *HOWEVER* this does not work at install time, and must be done at link time. See below
-#
-# The tests(run-test) *BELOW* specify LD_LIBRARY_PATH and hence override <dll-path>
-#
-# Linux: ldd <extension>
-# If the embedded object is not accessible, it just shows "=>not found"
-# In our case the boost python shared lib may not exist until added at install time.
-# *** Hence ldd can be very misleading ***
-# *** Also if LD_LIBRARY_PATH is set *and* path exist, this will be shown & hence hide embedded paths ***
-#
-# objdump -p <extension> // detailed dump, *SHOWS* the embedded paths, and search order
-# shared library dynamic path search:
-# LD_LIBRARY_PATH enabled first
-# embedded path enabled second
-#
-# HPUX: ldd <extension>
-# chatr <extension> // detailed dump, *SHOWS* search path and embedded path
-# shared library dynamic path search:
-# LD_LIBRARY_PATH enabled first
-# SHLIB_PATH enabled second
-# embedded path enabled third
-#
-# AIX: ldd <extension>
-# dump -H <extension>
-#
-# NOTE: <linkflags>-L$(ECFLOW_PYTHON_INSTALL_DIR)
-# <dll-path>$(ECFLOW_PYTHON_INSTALL_DIR)
-# is ONLY required during install.
-# However install does not appear to force a relink.
-# The bjam documentations suggests that <dll-path> is only required at install.
-# But that does not work, since we don't appear to relink. It *ONLY* works with exe's and not shared libs
-# As a result tried to use <dll-path> at link time, with mixed results:
-# hardcode-dll-paths install link
-# Linux: does not work, <dll-path> does not work <dll-path> works
-# HPUX: works <dll-path> does not work <dll-path> does not work
-# adding -L/path added, but get ignored by -L
-# allready there on development path
-# AIX: does not work <dll-path> does not work <dll-path> does not work
-# -L/path however does
-# Bjam documentation suggest hardcode-dll-paths has a default value of true,
-# this however can only be seen on HPUX. Tried combination of:
-# <toolset>acc:<hardcode-dll-paths>false
-# <toolset>acc:<linkflags>-L$(ECFLOW_PYTHON_INSTALL_DIR)
-# Again no effect:
-#
-# Tried using: bjam install-py dll-path=/var/tmp/ma0/ecflow/1.9.15/lib/python2.5/site-packages/ecflow -d2
-# This will ONLY work if the extension needs building, will not work for installing as emos
-# as emos will not have permission to write into workspace first.
-#
-# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
-# The hacky workaround is to use <dll-path> when building the extension. This requires
-# that ECFLOW_INSTALL_DIR is correctly set, which requires that ECFLOW_INSTALL_DIR
-# is correctly set. i.e during the build and NOT just install
-# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
-
-# - install __init__.py file.
-# - This install is referenced in JamRoot.jam
-install install-py1
- : [ glob ecflow/*.py ]
- : <location>$(ECFLOW_DESTDIR)/$(ECFLOW_PYTHON_INSTALL_DIR)
- ;
-
-# - <dll-path> for install Left in, in case its fixed in the future.
-# - This install is referenced in JamRoot.jam
-install install-py
- : ecflow
- : <install-dependencies>on
- <install-type>PYTHON_EXTENSION
- <install-type>SHARED_LIB
- <dll-path>$(ECFLOW_PYTHON_INSTALL_DIR)
- <location>$(ECFLOW_DESTDIR)$(ECFLOW_PYTHON_INSTALL_DIR)
- ;
-
-# make install explicit, otherwise we end installing for all calls to bjam
-explicit install-py1 ;
-explicit install-py ;
-
-
-# ========================================================================
-# TESTING: unit-tests and test for python fragments in online tutorial
-# ========================================================================
-import testing ;
-
-# A little "rule" (function) to clean up the syntax of declaring tests
-# of these extension modules.
-local rule run-test ( test-name : sources + )
-{
- testing.make-test run-pyd : $(sources) : : $(test-name) ;
-}
-
-#
-# Declare test targets;
-# Note cant run TestWith until all plarforms support with statement, i.e python 2.6 or greater
-#
-run-test TestClientApi : ecflow [ glob test/py_s_TestClientApi.py ] ;
-run-test TestDefs : ecflow [ glob test/py_u_TestDefs.py ] ;
-run-test TestError : ecflow [ glob test/py_u_TestError.py ] ;
-run-test TestTraversal : ecflow [ glob test/py_u_TestTraversal.py ] ;
-run-test TestDefsCheck : ecflow [ glob test/py_u_TestDefsCheck.py ] ;
-run-test TestSimulator : ecflow [ glob test/py_u_TestSimulator.py ] ;
-run-test TestAddDelete : ecflow [ glob test/py_u_TestAddDelete.py ] ;
-run-test TestAddDeleteFunc : ecflow [ glob test/py_u_TestAddDeleteFunc.py ] ;
-run-test TestAddNodeFunc : ecflow [ glob test/py_u_TestAddNodeFunc.py ] ;
-run-test TestParent : ecflow [ glob test/py_u_TestParent.py ] ;
-run-test TestUserManual : ecflow [ glob test/py_u_TestUserManual.py ] ;
-run-test TestJobGeneration : ecflow [ glob test/py_u_TestJobGeneration.py ] ;
-run-test TestGetAllTasks : ecflow [ glob test/py_u_TestGetAllTasks.py ] ;
-run-test TestDerivable : ecflow [ glob test/py_u_TestDerivable.py ] ;
-run-test TestWith : ecflow [ glob test/py_u_TestWith.py ] ;
-run-test TestFind : ecflow [ glob test/py_u_TestFind.py ] ;
-run-test TestMigrate : ecflow [ glob migrate/py_u_TestMigrate.py ] ;
-run-test TestRepeatArithmetic : ecflow [ glob test/py_u_TestRepeatArithmetic.py ] ;
-run-test TestGeneratedVariable : ecflow [ glob test/py_u_TestGeneratedVariable.py ] ;
-run-test TestEcf : ecflow [ glob test/py_u_TestEcf.py ] ;
-
-# A target that runs all the tests.
-# Note test_embed & test_embed_ecf commented out since we dont use this functionality
-alias test-all
- : TestUserManual TestJobGeneration TestClientApi TestDefs TestError TestTraversal TestDefsCheck
- TestSimulator TestAddDelete TestAddDeleteFunc TestAddNodeFunc TestParent TestGetAllTasks TestDerivable
- TestMigrate TestRepeatArithmetic TestWith TestFind TestGeneratedVariable TestEcf
- # test_embed test_embed_ecf
- ;
-
-# Only run tests when explicitly requested
-explicit test-all
- TestUserManual TestJobGeneration TestClientApi TestDefs TestError TestTraversal TestDefsCheck
- TestSimulator TestAddDelete TestAddDeleteFunc TestAddNodeFunc TestParent TestGetAllTasks TestDerivable
- TestMigrate TestRepeatArithmetic TestWith TestFind TestGeneratedVariable TestEcf
- # test_embed test_embed_ecf
- ;
-
\ No newline at end of file
diff --git a/ecflow_4_0_7/Pyext/doc/overload.txt b/ecflow_4_0_7/Pyext/doc/overload.txt
deleted file mode 100644
index 6588e39..0000000
--- a/ecflow_4_0_7/Pyext/doc/overload.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-
-When we have mutiple function of the same name but different args we can use
-the following to choose the correct overload
-
- // choose the correct overload
- void (NodeContainer::*add_family)(family_ptr) = &NodeContainer::addFamily;
- void (NodeContainer::*add_task)(task_ptr) = &NodeContainer::addTask;
- class_<NodeContainer, bases<Node>, boost::noncopyable >("NodeContainer",DefsDoc::node_container_doc(), no_init)
- .def("add_family",&NodeContainer::add_family ,DefsDoc::add_family_doc())
- .def("add_task", &NodeContainer::add_task , DefsDoc::add_task_doc())
- .def("add_family",add_family ,DefsDoc::add_family_doc())
- .def("add_task", add_task, DefsDoc::add_task_doc())
- .add_property("nodes", boost::python::range( &NodeContainer::node_begin, &NodeContainer::node_end),"Returns a list of Node's")
- ;
\ No newline at end of file
diff --git a/ecflow_4_0_7/Pyext/ecflow/__init__.py b/ecflow_4_0_7/Pyext/ecflow/__init__.py
deleted file mode 100644
index c9f8f93..0000000
--- a/ecflow_4_0_7/Pyext/ecflow/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from ecflow import *
-
-# Name :
-# Author : Avi
-# Revision : $Revision: #10 $
-#
-# Copyright 2009-2012 ECMWF.
-# This software is licensed under the terms of the Apache Licence version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation
-# nor does it submit to any jurisdiction.
\ No newline at end of file
diff --git a/ecflow_4_0_7/Pyext/jamfile.jam b/ecflow_4_0_7/Pyext/jamfile.jam
deleted file mode 100755
index 8b22c64..0000000
--- a/ecflow_4_0_7/Pyext/jamfile.jam
+++ /dev/null
@@ -1,205 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-# =============================================================================
-# This jam file, allows for creation of ecflow python extension module, where
-# we have a STATIC link to boost python
-# ===============================================================================
-
-# ===============================================================================
-# Error to watch out for:
-# error: No best alternative for /python_for_extensions
-# next alternative: required properties: <python>2.7 <target-os>linux
-# matched
-# next alternative: required properties: <python>2.7 <target-os>linux
-# matched
-#
-# Please check if you have more than one 'using python' in configuration files.
-# Please check site-config.jam, user-config.jam and project-config.jam and
-# remove duplicated 'using python'
-#
-# When installing BOOST-python libs, make sure to call module load python *FIRST*
-# Otherwise it will pick the python specified in project-config.jam, which make not be correct
-#
-# ===============================================================================
-
-#
-# jamfile for installing, building exposing c++ library to python.
-# and for testing embedded python
-#
-# Use of <dll-path> should force a relink. But this *ONLY* works for executables
-# and *NOT* shared libraries. The HACKY work around is use <dll-path> when
-# building the extension. Hence this requires that ECFLOW_INSTALL_DIR
-# is correctly set during build time. Yuk.
-#
-project thePyext ;
-
-use-project theCore : ../ACore ;
-use-project theNodeAttr : ../ANattr ;
-use-project theNode : ../ANode ;
-use-project theParser : ../AParser ;
-use-project theBase : ../Base ;
-use-project theClient : ../Client ;
-use-project theSimulator : ../CSim ;
-
-# Make the definition of the python-extension rule available
-import python ;
-
-if ! [ python.configured ]
-{
- # ECHO "notice: no Python configured in user-config.jam" ;
- # ECHO "notice: will use default configuration" ;
- # We will typically place this in user-congig/site-config.jam
- #using python
- # : # version
- # : # cmd-or-prefix
- # : # includes
- # : # libraries
- # : # condition
- # ;
- using python ;
-}
-
-# Specify the path to the Boost project. If you move this project,
-# adjust this path to refer to the Boost root directory.
-import os ;
-local BOOST_ROOT = [ os.environ BOOST_ROOT ] ;
-use-project boost
- : $(BOOST_ROOT) ;
-
-
-# ======================== libs ============================================
-# HPUX: ADD standard libs. They don't get added by default ?
-# Also on HPUX the shared libs appears reversed, and don't appear
-# in the order specified weird ?
-# Notice the use of <library> to add additional library on the link line
-# but only for HPUX/acc toolset
-# <ALL>: It appears the pthread lib is automatically added. i.e >lib pthread ;
-#
-
-lib std_v2 ;
-lib stream ;
-lib Csup ;
-lib unwind ;
-lib m ;
-alias hpux_std_libs : std_v2 stream Csup unwind m ;
-
-# ========================================================================
-# Extension: Declare a Python extension called ecflow.
-# ========================================================================
-python-extension ecflow : [ glob src/*.cpp ]
- /theCore//core
- /theNodeAttr//nodeattr
- /theNode//node
- /theParser//libparser
- /theBase//base
- /theClient//libclient
- /theSimulator//libsimu
- /site-config//boost_system
- /site-config//boost_serialization
- /site-config//boost_filesystem
- /site-config//boost_program_options
- /site-config//boost_datetime
- /site-config//boost_python_static
- : <variant>debug:<define>DEBUG
- <toolset>acc:<library>hpux_std_libs
- ;
-
-# ========================================================================
-# Documentation:
-# ========================================================================
-# Place the shared library 'ecflow' into the ecflow/ directory.
-# - *REQUIRED* for sphinx-build. Documentation generation See Doc/online/conf.py
-# We use this as first place to look for c++ extension
-# - avoids hard wired dependency on compiler path
-# - Picks up latest changes
-install ecflow/ : ecflow ;
-
-
-# ========================================================================
-# INSTALLATION:
-# ========================================================================
-# - install __init__.py file.
-# - This install is referenced in JamRoot.jam
-install install-py1
- : [ glob ecflow/*.py ]
- : <location>$(ECFLOW_DESTDIR)/$(ECFLOW_PYTHON_INSTALL_DIR)
- ;
-
-# - <dll-path> for install Left in, in case its fixed in the future.
-# - This install is referenced in JamRoot.jam
-# - <install-dependencies>on will also install boost_python shared lib and add repath to it.
-install install-py
- : ecflow
- : <install-type>PYTHON_EXTENSION
- <install-type>SHARED_LIB
- <location>$(ECFLOW_DESTDIR)$(ECFLOW_PYTHON_INSTALL_DIR)
- ;
-
-# make install explicit, otherwise we end installing for all calls to bjam
-explicit install-py1 ;
-explicit install-py ;
-
-
-# ========================================================================
-# TESTING: unit-tests and test for python fragments in online tutorial
-# ========================================================================
-import testing ;
-
-# A little "rule" (function) to clean up the syntax of declaring tests
-# of these extension modules.
-local rule run-test ( test-name : sources + )
-{
- testing.make-test run-pyd : $(sources) : : $(test-name) ;
-}
-
-#
-# Declare test targets;
-# Note cant run TestWith until all plarforms support with statement, i.e python 2.6 or greater
-#
-run-test TestClientApi : ecflow [ glob test/py_s_TestClientApi.py ] ;
-run-test TestPythonChildApi : ecflow [ glob test/py_s_TestPythonChildApi.py ] ;
-run-test TestDefs : ecflow [ glob test/py_u_TestDefs.py ] ;
-run-test TestError : ecflow [ glob test/py_u_TestError.py ] ;
-run-test TestTraversal : ecflow [ glob test/py_u_TestTraversal.py ] ;
-run-test TestDefsCheck : ecflow [ glob test/py_u_TestDefsCheck.py ] ;
-run-test TestSimulator : ecflow [ glob test/py_u_TestSimulator.py ] ;
-run-test TestAddDelete : ecflow [ glob test/py_u_TestAddDelete.py ] ;
-run-test TestAddDeleteError : ecflow [ glob test/py_u_TestAddDeleteError.py ] ;
-run-test TestAddDeleteFunc : ecflow [ glob test/py_u_TestAddDeleteFunc.py ] ;
-run-test TestAddNodeFunc : ecflow [ glob test/py_u_TestAddNodeFunc.py ] ;
-run-test TestParent : ecflow [ glob test/py_u_TestParent.py ] ;
-run-test TestUserManual : ecflow [ glob test/py_u_TestUserManual.py ] ;
-run-test TestJobGeneration : ecflow [ glob test/py_u_TestJobGeneration.py ] ;
-run-test TestGetAllTasks : ecflow [ glob test/py_u_TestGetAllTasks.py ] ;
-run-test TestDerivable : ecflow [ glob test/py_u_TestDerivable.py ] ;
-run-test TestWith : ecflow [ glob test/py_u_TestWith.py ] ;
-run-test TestFind : ecflow [ glob test/py_u_TestFind.py ] ;
-run-test TestMigrate : ecflow [ glob migrate/py_u_TestMigrate.py ] ;
-run-test TestRepeatArithmetic : ecflow [ glob test/py_u_TestRepeatArithmetic.py ] ;
-run-test TestGeneratedVariable : ecflow [ glob test/py_u_TestGeneratedVariable.py ] ;
-run-test TestEcf : ecflow [ glob test/py_u_TestEcf.py ] ;
-
-# A target that runs all the tests.
-# Note test_embed & test_embed_ecf commented out since we dont use this functionality
-alias test-all
- : TestUserManual TestJobGeneration TestDefs TestError TestTraversal TestDefsCheck
- TestSimulator TestAddDelete TestAddDeleteError TestAddDeleteFunc TestAddNodeFunc TestParent TestGetAllTasks
- TestDerivable TestMigrate TestRepeatArithmetic TestWith TestFind TestGeneratedVariable TestEcf
- TestClientApi TestPythonChildApi
- # test_embed test_embed_ecf
- ;
-
-# Only run tests when explicitly requested
-explicit test-all
- TestUserManual TestJobGeneration TestDefs TestError TestTraversal TestDefsCheck
- TestSimulator TestAddDelete TestAddDeleteError TestAddDeleteFunc TestAddNodeFunc TestParent TestGetAllTasks
- TestDerivable TestMigrate TestRepeatArithmetic TestWith TestFind TestGeneratedVariable TestEcf
- TestClientApi TestPythonChildApi
- # test_embed test_embed_ecf
- ;
-
\ No newline at end of file
diff --git a/ecflow_4_0_7/Pyext/migrate/ecflow_migrate.py b/ecflow_4_0_7/Pyext/migrate/ecflow_migrate.py
deleted file mode 100644
index 51deede..0000000
--- a/ecflow_4_0_7/Pyext/migrate/ecflow_migrate.py
+++ /dev/null
@@ -1,416 +0,0 @@
-#!/usr/bin/env python2.7
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# Name :
-# Author : Avi
-# Revision : $Revision: #10 $
-#
-# Copyright 2009-2012 ECMWF.
-# This software is licensed under the terms of the Apache Licence version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation
-# nor does it submit to any jurisdiction.
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-import os # for getenv
-import shutil # used to remove directory tree
-#import argparse # requires python 2.7
-import getopt, sys # for argument parsing
-
-class Migrator(object):
- def __init__(self, list_of_input_lines):
- self.list_of_input_lines = list_of_input_lines
- self.list_of_output_lines = []
-
- def _migration_hook(self,default_version_number):
- """Derived suite should override this function to perform the migration
- """
- return False;
-
- def output_lines(self):
- return self.list_of_output_lines
-
- def migrate(self, default_version_number):
- """Template/skeleton function, which will call the hooks
- """
- version = self.version_number_as_integer(default_version_number)
- if version >= default_version_number:
- self.list_of_output_lines = self.list_of_input_lines
- return False
-
- self.list_of_output_lines = []
- migrated = self._migration_hook(default_version_number)
- if migrated :
- self.list_of_input_lines = self.list_of_output_lines # preserve this migration
- print "Applying " + type(self).__name__
- else:
- self.list_of_output_lines = self.list_of_input_lines
- return migrated
-
- def version_number_as_integer(self,default_version):
- """Determine the version number used in ecflow_client --migrate
- This should be in the very first line
- # 3.1.8
- """
- if len(self.list_of_input_lines) > 0:
- tokens = self.list_of_input_lines[0].split()
- if len(tokens) > 1:
- # print tokens
- version = (int)(tokens[1].replace(".",""))
- # print "******************* found version " + str(version)
- return version;
- return default_version
-
-
-class MigrateForTaskAbort(Migrator):
- """Fix bug where the task abort states(i.e a string) will contain new lines and hence
- spill over the next line, and affecting the parser. This will move the abort string
- into the same line, and remove the interleaving new lines
- """
- def __init__(self, list_of_input_lines):
- Migrator.__init__(self, list_of_input_lines)
-
- def _migration_hook(self,default_version_number):
- """
- The correct format is: where abort state is on the same line
- task task # passwd:jxX0gIbR abort<: reason for abort >abort:
- ensure_start_abort_and_end_abort_on_sameline
- """
- migrated = False
- start_line_append = ""
- for line in self.list_of_input_lines:
- # process line
- end_abort_pos = line.find(">abort")
- task_pos = line.find("task")
- if task_pos != -1:
- start_abort_pos = line.find("abort<:")
- if start_abort_pos != -1 and end_abort_pos != -1:
- # start and end found on same line. This is the correct format
- start_line_append = ""
-
- if start_abort_pos != -1 and end_abort_pos == -1:
- # print "start abort found with no end abort"
- start_line_append = line
- start_line_append = start_line_append.rstrip('\n')
- start_line_append += " "
- migrated = True
- continue
-
- if len(start_line_append) > 0:
- start_line_append += line
- if end_abort_pos != -1:
- self.list_of_output_lines.append(start_line_append) # preserve'\n' for this case
- # print start_line_append
- start_line_append = "";
- else:
- start_line_append = start_line_append.rstrip('\n')
- start_line_append += " "
-
- continue;
-
- self.list_of_output_lines.append(line)
-
- return migrated
-
-
-class MigrateForLabel(Migrator):
- """Fix bug where label value has new lines, and hence spills over to next line
- This will remove place newline back onto the same line
- """
- def __init__(self, list_of_input_lines):
- Migrator.__init__(self, list_of_input_lines)
-
- def _migration_hook(self,default_version_number):
- """
- The correct format is where label in on the same line
- label name "value" # "new value"
- However if the value or new value has new line it can mess up the parsing
- label info "have you? set START_LOBSVR=1 in the task, once, to launch the logserver,
- setup ssh login
- created remote /tmp/map/cray"
- """
- #count = 0;
- no_of_label_quotes = 0
- migrated = False
- start_line_append = ""
- for line in self.list_of_input_lines:
- #count = count + 1
- #print str(count) + ": " + line
- #if count == 383119:
- # print "debug mee"
- if len(start_line_append) > 0:
- no_of_label_quotes += line.count('"')
- start_line_append += line
- if no_of_label_quotes % 2 == 0:
- # even number of quotes
- self.list_of_output_lines.append(start_line_append) # preserve last '\n'
- start_line_append = ""
- no_of_label_quotes = 0
- else:
- start_line_append = start_line_append.rstrip('\n')
- continue
- else:
-
- # process line
- tokens = line.split()
- if len(tokens) >0 and tokens[0] == "label":
- no_of_label_quotes = line.count('"')
- if no_of_label_quotes % 2 != 0 :
- start_line_append = line
- start_line_append = start_line_append.rstrip('\n')
- migrated = True
- continue
-
- self.list_of_output_lines.append(line)
-
- return migrated
-
-class MigrateForVariable(Migrator):
- """Fix bug where variable value has new lines, and hence spills over to next line
- This will remove place newline back onto the same line
- """
- def __init__(self, list_of_input_lines):
- Migrator.__init__(self, list_of_input_lines)
-
- def _migration_hook(self,default_version_number):
- """
- The correct format is where variable in on the same line
- edit EMOS_TYPE ' family prod_wparam
- endfamily
-'
- """
- #count = 0;
- no_of_label_quotes = 0
- migrated = False
- start_line_append = ""
- for line in self.list_of_input_lines:
- #count = count + 1
- #print str(count) + ": " + line
- #if count == 383119:
- # print "debug mee"
- if len(start_line_append) > 0:
- no_of_label_quotes += line.count("'")
- start_line_append += line
- if no_of_label_quotes % 2 == 0:
- # even number of quotes
- self.list_of_output_lines.append(start_line_append) # preserve last '\n'
- start_line_append = ""
- no_of_label_quotes = 0
- else:
- start_line_append = start_line_append.rstrip('\n')
- continue
- else:
-
- # process line, avoid ECF_URL_CMD as that could by error have uneven number of "'' i.e
- # edit ECF_URL_CMD '${BROWSER:=firefox} -remote 'openURL(%URL%'
- # hence we use
- # if no_of_label_quotes == 1:
- # instead of
- # if no_of_label_quotes % 2 == 0:
- tokens = line.split()
- if len(tokens) >= 3 and tokens[0] == "edit":
- no_of_label_quotes = line.count("'")
- if no_of_label_quotes == 1:
- start_line_append = line
- start_line_append = start_line_append.rstrip('\n')
- migrated = True
- continue
-
- self.list_of_output_lines.append(line)
-
- return migrated
-
-
-class MigrateForHistory(Migrator):
- """Fix bug where history spans multiple lines.
- See File: history_bug.def
- """
- def __init__(self, list_of_input_lines):
- Migrator.__init__(self, list_of_input_lines)
-
- def _migration_hook(self,default_version_number):
- """
- The history should all be on one line
- defs_state MIGRATE state>:queued flag:message state_change:1500811 modify_change:48
- edit ECF_LOG '/vol/emos_nc/output/ecflow/vali.21801.ecf.log'
- edit SMSNAME '0'
- history /s2s_devel/ecmf/back MSG:[15:53:06 21.10.2014] --replace=/s2s_devel/ecmf/back s2s_devel.def parent :emos
- history /s2s_devel/ecmf/enfh MSG:[13:45:53 12.11.2014] -alter change label last_run 20140929
- 20141002
- 20141016
- 20141023 /s2s_devel/ecmf/enfh/ :emos MSG:[14:05:53 14.11.2014] --requeue force /s2s_devel/ecmf/enfh :emos
- history /s2s_devel/ecmf/enfh/back MSG:[13:38:30 11.11.2014] --alter change event doIt set /s2s_devel/ecmf/enfh/back :emos
- suite limits # begun:1 state:complete flag:message suspended:1
- endsuite
- """
- migrated = False
- history_started = False
- for line in self.list_of_input_lines:
- # process line
- tokens = line.split()
- if len(tokens) >= 2 and tokens[0] == "suite":
- history_started = False
-
- if not history_started and len(tokens) >= 2 and tokens[0] == "history":
- history_started = True
-
- if history_started:
- # append to previous line
- if len(tokens) >= 1 and tokens[0] != "history":
- # get last line of output lines, string the new line and append
- self.list_of_output_lines[-1] = self.list_of_output_lines[-1].rstrip()
- self.list_of_output_lines[-1] = self.list_of_output_lines[-1] + line
- migrated = True
- continue;
-
- self.list_of_output_lines.append(line)
-
- return migrated
-
-
-def do_migrate(defs_file):
-
- migration_count = 0
- fileName, fileExtension = os.path.splitext(defs_file)
- output_file_name = fileName + ".mig";
-
- input_file_object = open(defs_file,'r')
- output_file_object = open(output_file_name,'w')
- try:
- list_of_input_lines = input_file_object.readlines() # preserves new lines, we want this
-
- list_of_output_lines = []
- abort_migrator = MigrateForTaskAbort(list_of_input_lines)
- if abort_migrator.migrate(401):
- migration_count += 1
- # did migration, update input lines for next migration
- list_of_input_lines = abort_migrator.output_lines()
- list_of_output_lines = abort_migrator.output_lines()
-
-
- label_migrator = MigrateForLabel(list_of_input_lines)
- if label_migrator.migrate(319):
- migration_count += 1
- # did migration, update input lines for next migration
- list_of_input_lines = label_migrator.output_lines()
- list_of_output_lines = label_migrator.output_lines()
-
-
- variable_migrator = MigrateForVariable(list_of_input_lines)
- if variable_migrator.migrate(401):
- migration_count += 1
- # did migration, update input lines for next migration
- list_of_input_lines = variable_migrator.output_lines()
- list_of_output_lines = variable_migrator.output_lines()
-
-
- variable_migrator = MigrateForHistory(list_of_input_lines)
- if variable_migrator.migrate(406):
- migration_count += 1
- # did migration, update input lines for next migration
- list_of_input_lines = variable_migrator.output_lines()
- list_of_output_lines = variable_migrator.output_lines()
-
- output_file_object.writelines(list_of_output_lines)
- finally:
- input_file_object.close()
- output_file_object.close()
-
- return migration_count
-
-def usage():
- DESC = """\nThis python file is used to *FIX* migration bugs, when migrating from one release of ecflow to another.
-
- Migration may be required when the release number changes:
- <release-number>.<major>.<minor>
- 6.1.7 -> 7.0.0
- as the checkpoint files *may* not be compatible.
-
- This can be *checked* before hand. By attempting to load the check pt into the new server.
- On the old server run:
- ecflow_client --check_pt # this will write out a checkpt file
- Now copy this file to a separate directory, and start the *new* server using the same port number
- If no errors are reported, you do not need to migrate.
- If loading the checkpt file into the new server fails for any reason then
- then please follow these steps.
-
- Steps for Old server:
- o shutdown
- # ecflow_client --shutdown
- o suspend all suites
- # CL="ecflow_client --port 32222 --host vsms1"
- # for s in $($CL --suites); do $CL --suspend /$s; done
- o wait for active/submitted tasks to complete
- o halt the server
- # ecflow_client --halt
- o Use --migrate to dump state and structure to a file
- # ecflow_client --migrate > all_suites.def
- o terminate server *or* leave server running but start new server on different machine
- to avoid port number clash.
- o remove checkpt and backup checkpt files, to prevent new server from loading them
- *Only* applicable if starting new server on same machine
- o Run this script
- python ecflow_migrate.py -d all_suites.def
- This will fix any issues associated with reloading this defs into the new server.
- It write a file called 'all_suites.mig', which we will need to load into the new server.
- See below.
-
- Steps for New server:
- o start server
- o load the migration file
- # ecflow_client --load all_suites.mig
- o set server running:
- # ecflow_client --restart
- o resume suspended suites
- # CL="ecflow_client --port 32222 --host vsms1"
- # for s in $($CL --suites); do $CL --resume /$s; done
-
-
- There could be bugs with *old* "ecflow_client --migrate > all_suites.def"
- This file, will fix any bugs associated --migrate, so that the subsequent
- load with *new* client (ecflow_client --load all_suites.mig) will work
-
- Usage:
- python ecflow_migrate.py --defs_file <filename>
- python ecflow_migrate.py --d <filename>
- python ecflow_migrate.py --defs_file all_suites.def
-
- The fixed definition is written as filename.mig, i.e. all_suites.mig
- """
- return DESC;
-
-
-if __name__ == "__main__":
-
-# PARSER = argparse.ArgumentParser(description=usage(),
-# formatter_class=argparse.RawDescriptionHelpFormatter)
-# PARSER.add_argument('defs_file', help="The definition file to *fix* for migration")
-# ARGS = PARSER.parse_args()
-# ARGS.defs_file = os.path.expandvars(ARGS.defs_file) # expand references to any environment variables
-# print ARGS
-# do_migrate( ARGS.defs_file )
-
- try:
- opts, args = getopt.getopt(sys.argv[1:], "hd", ["help", "defs_file="])
- except getopt.GetoptError as err:
- # print help information and exit:
- print(err) # will print something like "option -a not recognised"
- print usage()
- sys.exit(2)
-
- defs_file = None
- for o, a in opts:
- if o in ("-h", "--help"):
- print usage()
- sys.exit()
- elif o in ("-d", "--defs_file"):
- defs_file = a
- else:
- assert False, "un-handled option"
-
- if defs_file == None:
- print "Please enter path to the defs file i.e ecflow_migrate --d ./defs_file.def"
- sys.exit(1)
-
- defs_file = os.path.expandvars(defs_file); # expand references to any environment variables
- do_migrate( defs_file )
diff --git a/ecflow_4_0_7/Pyext/migrate/py_u_TestMigrate.py b/ecflow_4_0_7/Pyext/migrate/py_u_TestMigrate.py
deleted file mode 100644
index 69d4bf7..0000000
--- a/ecflow_4_0_7/Pyext/migrate/py_u_TestMigrate.py
+++ /dev/null
@@ -1,189 +0,0 @@
-
-import os
-import ecflow_migrate
-import unittest
-import filecmp
-
-def get_parent_dir(file_path):
- return os.path.dirname(file_path)
-
-def get_root_source_dir():
- cwd = os.getcwd()
- #print "get_root_source_dir from: " + cwd
- while (1):
- # Get to directory that has ecflow
- head, tail = os.path.split(cwd)
- #print " tail:" + tail
- if tail.find("ecflow") != -1 :
-
- # bjam, already at the source directory
- if os.path.exists(cwd + "/VERSION.cmake"):
- #print " Found VERSION.cmake in " + cwd
- return cwd
-
- # in cmake, we may be in the build directory, hence we need to determine source directory
- file = cwd + "/CTestTestfile.cmake"
- print " searching for " + file
- if os.path.exists(file):
- # determine path by looking into this file:
- for line in open(file):
- ## Source directory: /tmp/ma0/clientRoot/workspace/working-directory/ecflow/Acore
- if line.find("Source directory"):
- tokens = line.split()
- if len(tokens) == 4:
- return tokens[3]
- raise RuntimeError("ERROR could not find Source directory in CTestTestfile.cmake")
- else:
- raise RuntimeError("ERROR could not find file CTestTestfile.cmake in " + cwd)
-
- cwd = head
- return cwd
-
-
-
-# These tests the migration for ecflow < 318 to ecflow 318
-#
-# In ecflow_client --migrate, we can get abort reason to span multiple line, hence messing up load
-#
-class TestMigrate318(unittest.TestCase):
- def setUp(self):
- # perform setup actions if any
- self.workspace_dir = get_root_source_dir()
- #print "setup : " + self.workspace_dir
-
- def tearDown(self):
- # Perform clean -up actions if any
- pass
-
- def locate(self,file):
- return self.workspace_dir + "/Pyext/" + file
-
- def testMigrateVersionNumber(self):
- list_of_defs_lines =[ "# 3.1.2"]
-
- mig = ecflow_migrate.Migrator(list_of_defs_lines)
- self.assertEqual(mig.version_number_as_integer(0), 312,"expected version 3.1.2")
-
- list_of_defs_lines =[ "# "]
- mig = ecflow_migrate.Migrator(list_of_defs_lines)
- self.assertEqual(mig.version_number_as_integer(10), 10,"Expected 10, since valid version not provided")
-
- def test_no_migration(self):
- migration_count = ecflow_migrate.do_migrate(self.locate("migrate/no_migration.def"))
- self.assertEqual(migration_count,0,"Expected no migration")
- self.assertTrue(filecmp.cmp(self.locate("migrate/no_migration.def"),self.locate("migrate/no_migration.mig")))
- # remove the generated file
- try: os.remove(self.locate("migrate/no_migration.mig"))
- except: pass
-
-# ==============================================================================================
- # Test for abort bug
-
- def test_normal_abort_case(self):
- list_of_defs_lines = [ "# 3.1.2", "task task abort<: aa >abort\n" ]
- abort_migrator = ecflow_migrate.MigrateForTaskAbort(list_of_defs_lines)
- abort_migrator.migrate(318)
-
- expected_output_lines = ["# 3.1.2", "task task abort<: aa >abort\n"]
- self.assertEqual(abort_migrator.output_lines(),expected_output_lines)
-
- def test_task_abort_reason_bug_simple(self):
- list_of_defs_lines = ["# 3.1.2", "task task abort<: aa\n",">abort\n" ]
- abort_migrator = ecflow_migrate.MigrateForTaskAbort(list_of_defs_lines)
- abort_migrator.migrate(318)
-
- expected_output_lines = ["# 3.1.2","task task abort<: aa >abort\n"]
- self.assertEqual(abort_migrator.output_lines(),expected_output_lines)
-
- def test_task_abort_reason_bug(self):
- # In ecflow_client --migrate, we can get abort reason to span multiple line, hence messing up load
- list_of_defs_lines = ["# 3.1.2","task task # passwd:jxX0gIbR abort<: Script for /suite/family/task can not be found:\n",
- "line2\n", "line3\n",">abort try:2 state:aborted dur:02:19:57 flag:task_aborted,no_script\n" ]
-
- abort_migrator = ecflow_migrate.MigrateForTaskAbort(list_of_defs_lines)
- abort_migrator.migrate(318)
-
- expected_output_lines = ["# 3.1.2","task task # passwd:jxX0gIbR abort<: Script for /suite/family/task can not be found: line2 line3 >abort try:2 state:aborted dur:02:19:57 flag:task_aborted,no_script\n"]
- self.assertEqual(abort_migrator.output_lines(),expected_output_lines)
-
- def test_migrate_abort_file(self):
- migration_count = ecflow_migrate.do_migrate(self.locate("migrate/aborted_reason_bug.def"))
- self.assertEqual(migration_count,1,"Expected defs file to be migrated")
-
- # remove the generated file
- try: os.remove(self.locate("migrate/aborted_reason_bug.mig"))
- except: pass
-
-# ===============================================================================================
-
- def test_normal_label(self):
- list_of_defs_lines = ["# 3.1.2","label name \"value\"\n" ]
-
- migrator = ecflow_migrate.MigrateForLabel(list_of_defs_lines)
- migrator.migrate(319)
-
- expected_output_lines = ["# 3.1.2","label name \"value\"\n" ]
- self.assertEqual(migrator.output_lines(),expected_output_lines)
-
- def test_label_over_multiple_lines(self):
- list_of_defs_lines = ["# 3.1.2","label name \"value1\n", "value2\n", "value3\"\n" ]
-
- migrator = ecflow_migrate.MigrateForLabel(list_of_defs_lines)
- migrator.migrate(319)
-
- expected_output_lines = ["# 3.1.2","label name \"value1value2value3\"\n" ]
- self.assertEqual(migrator.output_lines(),expected_output_lines)
-
- def test_label_over_multiple_lines_with_state(self):
- list_of_defs_lines = ["# 3.1.2","label name \"value1\n", "value2\n", "value3\" # \"value4\n", "value5\"\n" ]
-
- migrator = ecflow_migrate.MigrateForLabel(list_of_defs_lines)
- migrator.migrate(319)
-
- expected_output_lines = ["# 3.1.2","label name \"value1value2value3\" # \"value4value5\"\n" ]
- self.assertEqual(migrator.output_lines(),expected_output_lines)
-
-
- def test_migrate_label_file(self):
- migration_count = ecflow_migrate.do_migrate(self.locate("migrate/label_bug.def"))
- self.assertEqual(migration_count,1,"Expected defs file to be migrated")
-
- # remove the generated file
- try: os.remove(self.locate("migrate/label_bug.mig"))
- except: pass
-
- def test_migrate_variable_file(self):
- migration_count = ecflow_migrate.do_migrate(self.locate("migrate/variable_bug.def"))
- self.assertEqual(migration_count,1,"Expected defs file to be migrated")
-
- # remove the generated file
- try: os.remove(self.locate("migrate/variable_bug.mig"))
- except: pass
-
-# ====================================================================================================
-# test both together
-
- def test_migrate_abort_and_label(self):
- migration_count = ecflow_migrate.do_migrate(self.locate("migrate/abort_and_label_bug.def"))
- self.assertEqual(migration_count,2,"Expected 2 migrations, one for abort and one for label")
-
- # remove the generated file
- try: os.remove(self.locate("migrate/abort_and_label_bug.mig"))
- except: pass
-
-#====================================================================================================
-#test history
-
- def test_migrate_history(self):
- print "test_migrate_history"
- migration_count = ecflow_migrate.do_migrate(self.locate("migrate/history_bug.def"))
- self.assertEqual(migration_count,1,"Expected 1 migrations,for history")
-
- # remove the generated file
- try: os.remove(self.locate("migrate/history_bug.mig"))
- except: pass
-
-#run the tests
-if __name__ == '__main__':
- #print "Current working directory: " + os.getcwd()
- unittest.main()
\ No newline at end of file
diff --git a/ecflow_4_0_7/Pyext/samples/ListVariables.py b/ecflow_4_0_7/Pyext/samples/ListVariables.py
deleted file mode 100755
index 0861b1f..0000000
--- a/ecflow_4_0_7/Pyext/samples/ListVariables.py
+++ /dev/null
@@ -1,65 +0,0 @@
-#!/usr/bin/env python2.7
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# Name :
-# Author : Avi
-# Revision : $Revision: #10 $
-#
-# Copyright 2009-2012 ECMWF.
-# This software is licensed under the terms of the Apache Licence version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation
-# nor does it submit to any jurisdiction.
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-import ecflow
-import argparse # for argument parsing
-
-if __name__ == "__main__":
-
- DESC = """Will list variables for any node
- Usage:
- Example1: List all the server variables
- ListVariables.py --host cca --port 4141 --path /
-
- Example2: List the variables for the given node
- ListVariables.py --host cca --port 4141 --path /path/to/node
- """
- PARSER = argparse.ArgumentParser(description=DESC,
- formatter_class=argparse.RawDescriptionHelpFormatter)
- PARSER.add_argument('--host', default="localhost",
- help="The name of the host machine, defaults to 'localhost'")
- PARSER.add_argument('--port', default="3141",
- help="The port on the host, defaults to 3141")
- PARSER.add_argument('--path', default="/",
- help="The path to the node. i.e /suite/family/task")
- ARGS = PARSER.parse_args()
- #print ARGS
-
- # ===========================================================================
- CL = ecflow.Client(ARGS.host, ARGS.port)
- try:
- CL.ping()
-
- # get the incremental changes, and merge with defs stored on the Client
- CL.sync_local()
-
- # check to see if definition exists in the server
- defs = CL.get_defs()
- if defs == None :
- print "No definition found, exiting..."
- exit(0)
-
- # print defs;
- if ARGS.path == "/":
- for var in defs.server_variables: print "edit " + var.name() + " '" + var.value() + "'"
- for var in defs.user_variables: print "edit " + var.name() + " '" + var.value() + "'"
- else:
- node = defs.find_abs_node(ARGS.path)
- if node == None:
- print "No node found at path " + ARGS.path
- else:
- for var in node.variables: print "edit " + var.name() + " '" + var.value() + "'"
-
- except RuntimeError, ex:
- print "Error: " + str(ex)
- print "Check host and port number are correct."
diff --git a/ecflow_4_0_7/Pyext/samples/TestBench.py b/ecflow_4_0_7/Pyext/samples/TestBench.py
deleted file mode 100644
index 875b23b..0000000
--- a/ecflow_4_0_7/Pyext/samples/TestBench.py
+++ /dev/null
@@ -1,200 +0,0 @@
-#!/usr/bin/env python2.7
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# Name :
-# Author : Avi
-# Revision : $Revision: #10 $
-#
-# Copyright 2009-2012 ECMWF.
-# This software is licensed under the terms of the Apache Licence version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation
-# nor does it submit to any jurisdiction.
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-# =============================================================================
-# Code for testing *any* definition
-# Since any ad hoc definition will reference local directories in the
-# ECF_ variables, we need to remove them and inject our own.
-#
-# This script is re-runnable, and hence will delete suites in the server
-# matching those in the input definition. Hence it is best to use this
-# script with a *test* server to avoid accidentally deleting existing suites
-# of the same name.
-# =============================================================================
-import ecflow
-import os # for getenv
-import shutil # used to remove directory tree
-import argparse # for argument parsing
-
-def delete_variables_affecting_job_generation(node):
- """delete customer related ECF variables, these will point to directories
- that don't exist. Its ok we will regenerate our own local ones"""
- var = node.find_variable("ECF_HOME")
- if not var.empty() :
- node.delete_variable("ECF_HOME")
- var = node.find_variable("ECF_FILES")
- if not var.empty() :
- node.delete_variable("ECF_FILES")
- var = node.find_variable("ECF_INCLUDE")
- if not var.empty() :
- node.delete_variable("ECF_INCLUDE")
- var = node.find_variable("ECF_JOB_CMD")
- if not var.empty() :
- node.delete_variable("ECF_JOB_CMD")
- var = node.find_variable("ECF_KILL_CMD")
- if not var.empty() :
- node.delete_variable("ECF_KILL_CMD")
- var = node.find_variable("ECF_STATUS_CMD")
- if not var.empty() :
- node.delete_variable("ECF_STATUS_CMD")
- var = node.find_variable("ECF_OUT")
- if not var.empty() :
- node.delete_variable("ECF_OUT")
-
-def traverse_container(node_container):
- """Recursively traverse definition node hierarchy and delete
- the variables that affect job generation.
- """
- delete_variables_affecting_job_generation(node_container)
- for node in node_container.nodes:
- delete_variables_affecting_job_generation(node)
- if not isinstance(node, ecflow.Task):
- traverse_container(node)
-
-if __name__ == "__main__":
-
- DESC = """Will allow any definition to be loaded and played on the server
- This is done by:
- o Remove existing ECF_ variables that affect job generation.
- i.e variables that refer to customer specific directories are removed
- o Allows ECF_HOME to specified, defaults to ./CUSTOMER/ECF_HOME
- o Generates the scripts(.ecf files) automatically based on the definition.
- i.e if a task has events,meters,labels then the client request for these are
- automatically injected in the generated .ecf script files
- o Will clear out existing data both on disk and on the server to allow
- multiple re-runs of this script. ** If this is an issue please use
- a test server **
- o All suites are put into a suspended state. This allows the GUI to resume them
- o The server is restarted and suites are begun
- This programs assumes that ecflow module is accessible.
- """
- PARSER = argparse.ArgumentParser(description=DESC,
- formatter_class=argparse.RawDescriptionHelpFormatter)
- PARSER.add_argument('defs_file',
- help="The definition file")
- PARSER.add_argument('--host', default="localhost",
- help="The name of the host machine, defaults to 'localhost'")
- PARSER.add_argument('--port', default="3141",
- help="The port on the host, defaults to 3141")
- PARSER.add_argument('--path', default="/",
- help="replace only the node path in the suite")
- PARSER.add_argument('--ecf_home', default=os.getcwd() + "/CUSTOMER/ECF_HOME",
- help="Directory to be used for generated scripts(ECF_HOME), defaults to ./CUSTOMER/ECF_HOME")
- PARSER.add_argument('--verbose', nargs='?', default=False, const=True, type=bool,
- help="Show verbose output")
- ARGS = PARSER.parse_args()
- ARGS.defs_file = os.path.expandvars(ARGS.defs_file) # expand references to any environment variables
- print ARGS
-
- # If running on local work space, use /Pyext/test/data/CUSTOMER/ECF_HOME as ecf_home
- if not ARGS.ecf_home:
- if os.getenv("WK") == None:
- print "No ecf_home specified. Please specify a writable directory"
- exit(1)
- ARGS.ecf_home = os.getenv("WK") + "/Pyext/test/data/CUSTOMER/ECF_HOME"
- if ARGS.verbose:
- print "Workspace is defined"
- print "using /Client/bin/gcc\-4.5/debug/ecflow_client"
-
- if ARGS.verbose:
- print "Using ECF_HOME=" + ARGS.ecf_home
-
- if ARGS.verbose:
- print "\nloading the definition from the input arguments(" + ARGS.defs_file + ")\n"
- try:
- DEFS = ecflow.Defs(ARGS.defs_file)
- except RuntimeError, ex:
- print " ecflow.Defs(" + ARGS.defs_file + ") failed:\n" + str(ex)
- exit(1)
-
- if ARGS.verbose:
- print "remove test data associated with the DEFS, so we start fresh, Allows rerun"
- for suite in DEFS.suites:
- dir_to_remove = ARGS.ecf_home + suite.get_abs_node_path()
- if ARGS.verbose:
- print " Deleting directory: " + dir_to_remove + "\n"
- shutil.rmtree(dir_to_remove, True)
-
- if ARGS.verbose:
- print "remove remote reference to ECF_HOME and ECF_INCLUDE, since we inject or own\n"
- for suite in DEFS.suites:
- traverse_container(suite)
-
- if ARGS.verbose:
- print "add variables required for script generation, for all suites\n"
- DEFS.add_variable("ECF_HOME", ARGS.ecf_home)
- if os.getenv("WK") != None:
- if os.path.exists(os.getenv("WK") + "/Client/bin/gcc\-4.5/debug/ecflow_client"):
- DEFS.add_variable("ECF_CLIENT_EXE_PATH", os.getenv("WK") + "/Client/bin/gcc\-4.5/debug/ecflow_client")
- else:
- DEFS.add_variable("ECF_CLIENT_EXE_PATH", os.getenv("WK") + "/Client/bin/gcc\-4.5/release/ecflow_client")
- DEFS.add_variable("SLEEP", "10") # not strictly required since default is 1 second
- DEFS.add_variable("ECF_INCLUDE", ARGS.ecf_home + "/includes")
-
-
- if ARGS.verbose:
- print "Place all suites into suspended state, so they can be started by the GUI\n"
- for suite in DEFS.suites:
- suite.add_defstatus(ecflow.DState.suspended)
-
- # ecflow.PrintStyle.set_style(ecflow.Style.STATE)
- if ARGS.verbose:
- print DEFS
-
- if ARGS.verbose:
- print "Generating script files(.ecf) from the definition"
- DEFS.generate_scripts()
-
- if ARGS.verbose:
- print "\nchecking script file generation, pre-processing & variable substitution\n"
- JOB_CTRL = ecflow.JobCreationCtrl()
- DEFS.check_job_creation(JOB_CTRL)
- assert len(JOB_CTRL.get_error_msg()) == 0, JOB_CTRL.get_error_msg()
-
- # ===========================================================================
- CL = ecflow.Client(ARGS.host, ARGS.port)
- try:
- if ARGS.verbose:
- print "check server " + ARGS.host + ":" + ARGS.port + " is running"
- CL.ping()
-
- if ARGS.verbose:
- print "Server is already running. re-start the server"
- CL.restart_server()
-
- if ARGS.verbose:
- print "Remove suites associated with this DEFS, allows rerun *******************************************"
- for suite in DEFS.suites:
- try:
- CL.delete(suite.get_abs_node_path(), True)
- except RuntimeError, ex:
- pass # For first run this will fail, hence ignore
-
- if ARGS.verbose:
- print "Load the definition into " + ARGS.host + ":" + ARGS.port
- if ARGS.path == "/":
- CL.load(DEFS)
- else:
- CL.replace(ARGS.path, DEFS)
-
- if ARGS.verbose:
- print "Begin all suites. They should be suspended."
- print "Loaded suites:"
- for suite in DEFS.suites:
- CL.begin_suite(suite.name())
- print " " + suite.name()
- print "into server " + ARGS.host \
- + ":" + ARGS.port + ", please view the playable suites in the GUI"
- except RuntimeError, ex:
- print "Error: " + str(ex)
diff --git a/ecflow_4_0_7/Pyext/samples/TestJobGenPerf.py b/ecflow_4_0_7/Pyext/samples/TestJobGenPerf.py
deleted file mode 100644
index dd7c6e2..0000000
--- a/ecflow_4_0_7/Pyext/samples/TestJobGenPerf.py
+++ /dev/null
@@ -1,155 +0,0 @@
-#!/usr/bin/env python2.7
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# Name :
-# Author : Avi
-# Revision : $Revision: #10 $
-#
-# Copyright 2009-2012 ECMWF.
-# This software is licensed under the terms of the Apache Licence version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation
-# nor does it submit to any jurisdiction.
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-# =============================================================================
-# Code for testing *any* definition
-# Since any ad hoc definition will reference local directories in the
-# ECF_ variables, we need to remove them and inject our own.
-#
-# This test was created aid the performance testing of job generation
-# It is tied to AParser/test/TestJobGenPerf.cpp
-# =============================================================================
-import ecflow
-import os # for getenv
-import shutil # used to remove directory tree
-import argparse # for argument parsing
-
-def delete_variables_affecting_job_generation(node):
- """delete customer related ECF variables, these will point to directories
- that don't exist. Its ok we will regenerate our own local ones"""
- var = node.find_variable("ECF_HOME")
- if not var.empty() :
- node.delete_variable("ECF_HOME")
- var = node.find_variable("ECF_FILES")
- if not var.empty() :
- node.delete_variable("ECF_FILES")
- var = node.find_variable("ECF_INCLUDE")
- if not var.empty() :
- node.delete_variable("ECF_INCLUDE")
- var = node.find_variable("ECF_JOB_CMD")
- if not var.empty() :
- node.delete_variable("ECF_JOB_CMD")
- var = node.find_variable("ECF_KILL_CMD")
- if not var.empty() :
- node.delete_variable("ECF_KILL_CMD")
- var = node.find_variable("ECF_STATUS_CMD")
- if not var.empty() :
- node.delete_variable("ECF_STATUS_CMD")
- var = node.find_variable("ECF_OUT")
- if not var.empty() :
- node.delete_variable("ECF_OUT")
-
-def traverse_container(node_container):
- """Recursively traverse definition node hierarchy and delete
- the variables that affect job generation.
- """
- delete_variables_affecting_job_generation(node_container)
- for node in node_container.nodes:
- delete_variables_affecting_job_generation(node)
- if not isinstance(node, ecflow.Task):
- traverse_container(node)
-
-if __name__ == "__main__":
-
- DESC = """Will allow any definition to be loaded and played on the server
- This is done by:
- o Remove existing ECF_ variables that affect job generation.
- i.e variables that refer to customer specific directories are removed
- o Allows ECF_HOME to specified, defaults to ./CUSTOMER/ECF_HOME
- o Generates the scripts(.ecf files) automatically based on the definition.
- i.e if a task has events,meters,labels then the client request for these are
- automatically injected in the generated .ecf script files
- o Will clear out existing data both on disk and on the server to allow
- multiple re-runs of this script. ** If this is an issue please use
- a test server **
- This programs assumes that ecflow module is accessible.
- """
- PARSER = argparse.ArgumentParser(description=DESC,
- formatter_class=argparse.RawDescriptionHelpFormatter)
- PARSER.add_argument('defs_file',
- help="The definition file")
- PARSER.add_argument('--ecf_home', default="/var/tmp/ma0/ECFLOW_TEST/TestJobGenPerf/ECF_HOME",
- help="Directory to be used for generated scripts(ECF_HOME), defaults to /var/tmp/ma0/ECFLOW_TEST/TestJobGenPerf/ECF_HOME")
- PARSER.add_argument('--verbose', nargs='?', default=False, const=True, type=bool,
- help="Show verbose output")
- ARGS = PARSER.parse_args()
- ARGS.defs_file = os.path.expandvars(ARGS.defs_file) # expand references to any environment variables
- print ARGS
-
- # If running on local work space, use /Pyext/test/data/CUSTOMER/ECF_HOME as ecf_home
- if not ARGS.ecf_home:
- if os.getenv("WK") == None:
- print "No ecf_home specified. Please specify a writable directory"
- exit(1)
- ARGS.ecf_home = "/var/tmp/ma0/ECFLOW_TEST/TestJobGenPerf/ECF_HOME"
- if ARGS.verbose:
- print "Workspace is defined"
- print "using /Client/bin/gcc\-4.5/debug/ecflow_client"
-
- print "Using ECF_HOME=" + ARGS.ecf_home
- print "removing directory " + ARGS.ecf_home
- try:
- shutil.rmtree(ARGS.ecf_home)
- except:
- pass
-
- if not os.path.exists(ARGS.ecf_home):
- print ARGS.ecf_home + " directory does not exist, creating"
- os.makedirs(ARGS.ecf_home)
-
- print "\nloading the definition from the input arguments(" + ARGS.defs_file + ")\n"
-
- try:
- DEFS = ecflow.Defs(ARGS.defs_file)
- except RuntimeError, ex:
- print " ecflow.Defs(" + ARGS.defs_file + ") failed:\n" + str(ex)
- exit(1)
-
- if ARGS.verbose:
- print "remove test data associated with the DEFS, so we start fresh, Allows rerun"
- for suite in DEFS.suites:
- dir_to_remove = ARGS.ecf_home + suite.get_abs_node_path()
- if ARGS.verbose:
- print " Deleting directory: " + dir_to_remove + "\n"
- shutil.rmtree(dir_to_remove, True)
-
- if ARGS.verbose:
- print "remove remote reference to ECF_HOME and ECF_INCLUDE, since we inject or own\n"
- for suite in DEFS.suites:
- print "add variables required for script generation, for all suites\n"
- traverse_container(suite)
-
- suite.add_variable("ECF_HOME", ARGS.ecf_home)
- suite.add_variable("ECF_INCLUDE", ARGS.ecf_home + "/includes")
- suite.add_variable("ECF_CLIENT_EXE_PATH", os.getenv("WK") + "/Client/bin/gcc\-4.5/debug/ecflow_client")
- suite.add_variable("SLEEP", "10") # not strictly required since default is 1 second
-
-
-
- # ecflow.PrintStyle.set_style(ecflow.Style.STATE)
- #if ARGS.verbose:
- #print DEFS
- DEFS.generate_scripts()
-
- if ARGS.verbose:
- print "\nchecking script file generation, pre-processing & variable substitution\n"
- JOB_CTRL = ecflow.JobCreationCtrl()
- DEFS.check_job_creation(JOB_CTRL)
- assert len(JOB_CTRL.get_error_msg()) == 0, JOB_CTRL.get_error_msg()
-
-
- newDefs = ARGS.ecf_home + "/../" + os.path.basename(ARGS.defs_file)
- print "Saving modified defs as " + newDefs
- DEFS.save_as_defs(newDefs)
-
diff --git a/ecflow_4_0_7/Pyext/samples/TestServerGetDefs.py b/ecflow_4_0_7/Pyext/samples/TestServerGetDefs.py
deleted file mode 100644
index ca54b0d..0000000
--- a/ecflow_4_0_7/Pyext/samples/TestServerGetDefs.py
+++ /dev/null
@@ -1,59 +0,0 @@
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# Name :
-# Author : Avi
-# Revision : $Revision: #10 $
-#
-# Copyright 2009-2012 ECMWF.
-# This software is licensed under the terms of the Apache Licence version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation
-# nor does it submit to any jurisdiction.
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-# This test is a simple client that, repeatedly calls gets defs
-# This is used to stress test the server to determine how many defs
-# can be called before the server gets overloaded
-
-import datetime
-import time, sys
-from ecflow import Client
-
-def main(ci,inc = 2):
- while True:
- start_time = datetime.datetime.now()
- try:
- ci.get_server_defs()
- except RuntimeError, e :
- print "Error:" + str(e)
-
- print "get_server_defs took: " + str(datetime.datetime.now() - start_time)
- time.sleep(inc)
-
-if __name__ == "__main__":
-
- numargs = len(sys.argv) - 1
- #print "numargs = " + str(numargs)
- #i = 0;
- #while i < len(sys.argv):
- #print "arg " + str(i) + ": " + sys.argv[i]
- #i = i + 1
-
- if numargs > 3:
- print "usage: " + sys.argv[0] + " host port seconds_delay"
- sys.exit(1)
-
- port = "3142"
- host = "localhost"
- inc = 1
- if numargs >= 1: host = sys.argv[1];
- if numargs >= 2: port = sys.argv[2]
- if numargs >= 3: inc = int(sys.argv[3])
-
- #print "host(" + host + ") port(" + port + ") delay between get_server_defs(" + str(inc) +")"
-
- ci = Client(host,port)
- ci.ping()
-
- main(ci,inc)
-
\ No newline at end of file
diff --git a/ecflow_4_0_7/Pyext/samples/ecf.py b/ecflow_4_0_7/Pyext/samples/ecf.py
deleted file mode 100755
index 61af672..0000000
--- a/ecflow_4_0_7/Pyext/samples/ecf.py
+++ /dev/null
@@ -1,1012 +0,0 @@
-#!/usr/bin/env python
-# This software is provided under the ECMWF standard software license agreement.
-""" a layer over raw ecflow api
-
-use 'export ECF_DEBUG_LEVEL=10' to remove warning message related to
-variables overwrite
-
-"""
-
-import pwd, os, unittest
-try:
- from ecflow import TimeSlot
- from ecflow import JobCreationCtrl as JobCreationCtrl
- from ecflow import ChildCmdType
- from ecflow import ZombieType, ZombieAttr, ZombieUserActionType
-except: print "# ecf.py cannot import few types"
-
-import ecflow
-ecflow.Ecf.set_debug_level(3)
-
-DEBUG = 0
-DECORATE = "ALL"
-# DECORATE = "ONLY_TRIGGER"
-# DECORATE = "NO_TRIGGER"
-# DECORATE = "ONLY_EVENT"
-# DECORATE = "NO_ATTRIBUTE"
-
-USE_TIME = True
-USE_LATE = False
-USE_TRIGGER = True
-USE_LIMIT = True
-
-if DECORATE == "NO_TRIGGER":
- USE_TRIGGER = False
- USE_LIMIT = True
- USE_EVENT = True
-# elif DECORATE == "ONLY_TRIGGER":
-# USE_TRIGGER = True
-# USE_LIMIT = False
-# USE_EVENT = False
-# elif DECORATE == "NO_ATTRIBUTE":
-# USE_TRIGGER = False
-# USE_LIMIT = False
-# USE_EVENT = False
-# elif DECORATE == "ONLY_EVENT":
-# USE_TRIGGER = False
-# USE_LIMIT = False
-# USE_EVENT = True
-elif DECORATE == "ALL":
- USE_TRIGGER = True
- USE_LIMIT = True
- USE_EVENT = True
-else: raise BaseException
-
-def get_username():
- return pwd.getpwuid( os.getuid() )[ 0 ]
-def get_uid():
- return pwd.getpwnam(get_username()).pw_uid
-
-def translate(name, value=None):
- """ Translate from sms to ecflow """
- import sms2ecf, sys
- def is_sms():
- if sys.argv[-1] in ( # "localhost"
- "sms", "od3", "ode","pikachu","ibis","map", "od", "od2", ):
- sms2ecf.ECF_MODE = "sms"
- return True
- return sms2ecf.ECF_MODE == "sms"
- if is_sms():
- sms2ecf.ECF_MODE = "sms"
- return sms2ecf.translate(name, value)
- return name, value
-
-class State:
- """ this class aims at affording a user the possibility to add Triggers as
- t1 = Task("t1")
- Task("ts").add(Trigger(t1 == COMPLETE))
-
- SUBMITTED, ACTIVE, SUSPENDED, ABORTED, QUEUED, COMPLETE, UNKNOWN
- are instance of this class.
- """
-
- def __init__(self, state):
- """ store the status """
- self.state = str(state)
-
- def __str__(self):
- """ translate into string """
- return "%s" % self.state
-
- def __eq__(self, arg):
- """ when == is used, we should care about task name starting with 0-9"""
- if type(arg) == str:
- add = ""
- if type(arg[0]) == int:
- add = "./"
- return add + arg + " == " + self.state
- elif isinstance(arg, ecflow.Node):
- return arg.get_abs_node_path() + " == " + self.state
- return False
-
- def __ne__(self, arg):
- """ aka != """
- if type(arg) == str:
- add = ""
- if type(arg[0]) == int:
- add = "./"
- return add + arg + " != " + self.state
- elif isinstance(arg, ecflow.Node):
- return arg.get_abs_node_path() + " != " + self.state
- return False
-
- def value(self):
- """ return state """
- return self.state
-
- def eval(self, node):
- """ return state """
- return self.state == node.get_state()
-
-
-
-SUBMITTED = State("submitted")
-ACTIVE = State("active")
-SUSPENDED = State("suspended")
-ABORTED = State("aborted")
-QUEUED = State("queued")
-COMPLETE = State("complete")
-UNKNOWN = State("unknown")
-
-class Attribute(object):
- """ generic attribute to be attached to a node"""
- def add_to(self, node):
- """ use polymorphism to attach attribute to a node"""
- pass
-
-class Variable(Attribute, ecflow.Variable):
- """ filter variables to be attached to a node, may alter its name SMS-ECF"""
- def add_to(self, node):
- """ add_variable"""
- keyt, valt = translate(self.name(), self.value())
- if "/tc1/emos_es" in valt: raise BaseException # FIXME
- node.add_variable(keyt, valt)
-
-class Label(Attribute, ecflow.Label):
- """ wrap around label"""
- def add_to(self, node):
- """ add_label"""
- node.add_label(self)
-
-class Meter(Attribute, ecflow.Meter):
- """ wrap around meter"""
- def add_to(self, node):
- """ add_meter"""
- node.add_meter(self)
-
-class Event(Attribute, ecflow.Event):
- """ wrap around event"""
- def add_to(self, node):
- """ add_event"""
- node.add_event(self)
-
-class InLimit(Attribute):
- """ a class to host a path for a limit
- silently ignore if USE_LIMIT is False,
- (in debug mode) """
-
- def __init__(self, fullpath):
- self.data = None
- if USE_LIMIT:
- try: path, name = fullpath.split(":")
- except: name = fullpath; path = ""
- if name is None: raise BaseException
- self.data = ecflow.InLimit(name, path)
- self.path_ = path
- self.name_ = name
-
- def add_to(self, node):
- """ add_inlimit"""
- if USE_LIMIT and self.data is None: raise BaseException
- if USE_LIMIT and self.data is not None:
- node.add_inlimit(self.data)
-
- def value(self):
- """ get limit fullpath-name """
- return self.path_ + ":" + self.name_
-
- def name(self):
- """ get limit name """
- return self.name_
-
-class Inlimit(InLimit):
- def __init__(self, fullpath):
- super(Inlimit, self).__init__(fullpath)
-
-class Trigger(Attribute):
- """ add trigger (string, list of task names, or directly
- expression and: and'ed (True) or or'ed (False) unk: add or
- [name]==unknown for RD
- """
- def __init__(self, expr, unk=False, anded=True):
- self.expr = None
- if expr is None:
- return
- if expr == "":
- return
- if type(expr) == str:
- # self.expr = ecflow.Expression(expr)
- self.expr = expr
- return
- if type(expr) == tuple:
- prep = list(expr)
- expr = prep
-
- if type(expr) == list:
- for index, name in enumerate(expr):
- if name == None:
- continue
- pre = ""
-
- if type(name) in (Node, Task, Family, Suite):
- fullname = name.fullname()
- name = fullname
- elif type(name) in (ecflow.Task, ecflow.Family):
- name = name.name()
- else: pass
-
- if name[0].isdigit(): pre = "./" # "0123456789":
-
- if ':' in name:
- item = pre + name
- else:
- item = pre + "%s == complete" % name
- if unk: item += " or %s%s==unknown" % (pre, name)
- else: pass
-
- if item is None: self.expr = None
- elif index == 0 or self.expr is None:
- # 20131125 # self.expr = ecflow.Expression(item)
- self.expr = item
- elif item is None: return
- else: # self.expr.add(ecflow.PartExpression(item,anded))
- self.expr += " and %s" % item
-
- elif type(expr) in (ecflow.Expression,
- ecflow.PartExpression):
- self.expr = ecflow.Expression(str(item))
- else: print type(expr); raise Exception("what? trigger?")
-
- def add_to(self, node):
- if not USE_TRIGGER:
- return
- if self.expr is None:
- return
- if node.get_trigger() is None:
- node.add_trigger(self.expr)
- else: node.add_part_trigger(ecflow.PartExpression(self.expr, True))
-
-class TriggerAnd(Trigger):
- def __init__(self, expr, unk=False, anded=True):
- self.expr = expr
- if (not ":" in expr and
- not " eq " in expr and
- not "==" in expr):
- self.expr += " eq complete"
- def add_to(self, node):
- node.add_part_trigger(ecflow.PartExpression(self.expr, True))
-
-class TriggerImpossible(Trigger):
- """ attribute to be added to node when it is not expected to run
- any task"""
-
- def __init__(self):
- """ add an 'impossible trigger', for a task not to run """
- super(TriggerImpossible, self).__init__("1==0")
-
-class TriggerAlways(Trigger):
- """ attribute to be added to node when it is not expected to run
- any task"""
-
- def __init__(self):
- """ add an 'impossible trigger', for a task not to run """
- super(TriggerAlways, self).__init__("1==1")
-
-class Complete(Trigger):
- """ class to host complete expression, added later to a node"""
- def __init__(self, expression, unk=False, anded=False):
- super(Complete, self).__init__(expression, unk, anded)
-
- def add_to(self, node):
- if USE_TRIGGER and self.expr is not None:
- node.add_complete(self.expr)
-
-class Clock(Attribute):
- """ wrapper to add clock """
- def __init__(self, arg):
- if type(arg) == str:
- hybrid = "hybrid" in arg
- hhh, mmm, sss = [0, 0, 0]
- try:
- hhh, mmm, sss = arg.split(':')
- self.data = ecflow.Clock(hhh, mmm, sss, hybrid)
- except:
- self.data = ecflow.Clock(hybrid)
- else: self.data = ecflow.Clock(arg)
-
- def add_to(self, node):
- if type(node) != Suite:
- print "WAR: clock can only be attached to suite node, "
- print "WAR: clock is ignored"
- return
- node.add_clock(self.data)
-
-class AutoCancel(Attribute):
- """ wrapper to add time """
- def __init__(self, arg):
- if type(arg) == str:
- hhh, mmm = arg.split(':')
- rel = '+' in arg
- self.data = ecflow.Autocancel(int(hhh), int(mmm), rel)
- else: self.data = ecflow.Autocancel(arg)
-
- def add_to(self, node):
- node.add_autocancel(self.data)
-
-class Time(Attribute):
- """ wrapper to add time """
- def __init__(self, arg):
- self.data = arg
-
- def add_to(self, node):
- if USE_TIME and self.data is not None:
- node.add_time(self.data)
-
-class Today(Time):
- """ wrapper to add time """
- def __init__(self, arg):
- self.data = arg
-
- def add_to(self, node):
- if USE_TIME and self.data is not None:
- node.add_today(self.data)
-
-class Cron(Time):
- """ wrapper to add time """
- def __init__(self, bes, wdays=None, days=None, months=None):
- self.data = ecflow.Cron()
-
- if not ("-w" in bes or "-m" in bes or "-d" in bes):
- self.data.set_time_series(bes);
- return
-
- import argparse
- parser = argparse.ArgumentParser()
- parser.add_argument("-w", nargs='?', default=0, help= "weekdays")
- parser.add_argument("-d", nargs='?', default=0, help= "days")
- parser.add_argument("-m", nargs='?', default=0, help= "months")
- parser.add_argument("arg", type=str, help= "begin end step")
- parsed = parser.parse_args(bes.split())
-
- if parsed.w:
- self.data.set_week_days([int(x) for x in parsed.w.split(',')])
- if parsed.d:
- self.data.set_week_days([int(x) for x in parsed.d.split(',')])
- if parsed.m:
- self.data.set_months([int(x) for x in parsed.m.split(',')])
- self.data.set_time_series(parsed.arg)
-
- def add_to(self, node):
- if USE_TIME and self.data is not None:
- node.add_cron(self.data)
- else: print "#WAR: ignoring: %s" % self.data
-
-class Date(Time):
- """ wrapper to add date """
-
- def __init__(self, arg, mask=False):
- super(Date, self).__init__(arg)
- self.mask = mask
-
- def add_to(self, node):
- if USE_TIME and self.data is not None:
- ### ??? FIX, emos avoids dates, datasvc would not
- if self.mask:
- node.add_variable("DATEMASK", self.data)
- else:
- ddd, mmm, yyy = self.data.split('.')
- if ddd == '*': ddd = 0
- if mmm == '*': mmm = 0
- if yyy == '*': yyy = 0
-
- node.add_date(int(ddd), int(mmm), int(yyy))
- # node.add_date(self.data)
-
-class Day(Date):
- """ wrapper to add day """
- def add_to(self, node):
- if USE_TIME and self.data is not None:
- # node.add_date(self.data) ### FIX
- node.add_variable("WEEKDAY", self.data)
-
-class Defcomplete(Attribute):
- """ wrapper to add defstatus complete """
- def __init__(self):
- pass
-
- def add_to(self, node):
- node.defstatus("complete")
-
-class Defstatus(Defcomplete):
- """ add defstatus attribute"""
- def __init__(self, kind):
- if type(kind) == str:
- kinds = {"suspended": ecflow.DState.suspended,
- "aborted": ecflow.DState.aborted,
- "complete": ecflow.DState.complete,
- "active": ecflow.DState.active,
- "submitted": ecflow.DState.submitted,
- "unknown": ecflow.DState.unknown,
- "queued": ecflow.DState.queued,
- }
- self.data = kinds[kind]
- else: self.data = kind
-
- def add_to(self, node):
- node.add_defstatus(self.data)
-
-class DefcompleteIf(Defcomplete):
- """ wrapper to add conditional defstatus complete
- just change name to make it explicit
- """
- def __init__(self, arg=True):
- # super(DefcompleteIf, self).__init__()
- self.data = arg
-
- def add_to(self, node):
- if self.data:
- node.defstatus("complete")
- # else: node.defstatus("queued") # in comment to prevent
- # overwrite when using multiple defcomplete
-
-class Limit(Attribute):
- """ wrapper to add limit """
-
- # name = None; size = 1
-
- def __init__(self, name=None, size=1):
- self.name = name
- self.size = size
-
- def add_to(self, node):
- if USE_LIMIT and self.name is not None:
- if type(self.name) is dict:
- for name, size in self.name.items():
- node.add_limit(name, size)
- else: node.add_limit(self.name, self.size)
-
-class Late(Attribute):
- """ wrapper around late, to be add'ed to families and tasks """
-
- def __init__(self, arg):
- self.data = None
- if not USE_LATE:
- # print "#MSG: late is disabled"
- return
- sub = False
- act = False
- com = False
- rel = False
- self.data = ecflow.Late()
- for item in arg.split(" "):
- if item == "-s":
- sub = True
- elif item == "-c":
- com = True
- elif item == "-a":
- act = True
- else:
- hour, mins = item.split(":")
- rel = "+" in hour
- if "+" in hour: hour= hour[1:]
- if sub:
- self._add_sub(hour, mins)
- elif com:
- self._add_com(hour, mins, rel)
- elif act:
- self._add_act(hour, mins)
- sub = False
- act = False
- com = False
-
- def _add_sub(self, hour, mins):
- """ submitted"""
- self.data.submitted(ecflow.TimeSlot(int(hour), int(mins)))
-
- def _add_com(self, hour, mins, rel):
- """ complete"""
- self.data.complete(ecflow.TimeSlot(int(hour), int(mins)), rel)
-
- def _add_act(self, hour, mins):
- """ active"""
- self.data.active(ecflow.TimeSlot(int(hour), int(mins)))
-
- def add_to(self, node):
- if USE_LATE and self.data is not None:
- node.add_late(self.data)
-
-class Variables(Attribute):
- """ dedicated class to enable variable addition with different
- syntax """
-
- def _set_tvar(self, key, val):
- """ facilitate to load a ecflow suite to SMS, translating
- variable names"""
- keyt, valt = translate(str(key), str(val))
- if self.data is None:
- self.data = Variable(keyt, valt)
- else:
- next = self.next
- self.next = Variables(keyt, valt, next)
-
- def __init__(self, __a=None, __b=None, __next=None, *args, **kwargs):
- self.data = None
- self.next = __next
-
- if len(args) > 0:
- if type(args) == list:
- for item in args.iteritems():
- self._set_tvar(item.name(), item.value())
- elif type(args) == tuple:
- for key, val in args.items():
- self._set_tvar(key, val)
- else: raise BaseException()
- if len(kwargs) > 0:
- for key, val in kwargs.items():
- self._set_tvar(key, val)
- if type(__a) == dict:
- for key, val in __a.items():
- self._set_tvar(key, val)
- elif type(__a) == tuple: raise BaseException()
- # for key, val in __a.items(): self._set_tvar(key, val)
- elif type(__a) == list: raise BaseException()
- elif type(__a) == Variable: self.data = __a
- elif __a is not None and __b is not None:
- self._set_tvar(__a, __b)
- elif __a is None and __b is None: pass
- else: raise BaseException(__a, __b, __next, args, kwargs)
-
- def add_to(self, node):
- if self.data is not None:
- node.add_variable(self.data)
- if self.next is not None:
- self.next.add_to(node)
-
- def add(self, what): raise baseException(what.fullname())
-
-class Limits(Attribute):
- """ dedicated class to enable limits addition with different syntax """
-
- def _set_tvar(self, key, val):
- """ append limits """
- if self.data is None:
- self.data = ecflow.Limit(key, val)
- else:
- next = self.next
- self.next = Limits(key, val, next)
-
- def __init__(self, __a=None, __b=None, __next=None, *args, **kwargs):
- self.data = None
- self.next = __next
-
- if len(args) > 0:
- if type(args) == list:
- for item in args.iteritems():
- self._set_tvar(item.name(), item.value())
- elif type(args) == tuple:
- for key, val in args.items():
- self._set_tvar(key, val)
- elif len(kwargs) > 0:
- for key, val in kwargs.items():
- self._set_tvar(key, val)
- elif type(__a) == dict:
- for key in sorted(__a.iterkeys()):
- self._set_tvar(key, __a[key])
-
- if __a is not None and __b is not None:
- self._set_tvar(__a, __b)
-
- def add_to(self, node):
- if self.data is not None:
- node.add_limit(self.data)
- if self.next is not None:
- self.next.add_to(node)
-
-class Repeat(Attribute):
- def __init__(self, name="YMD", start=20120101, end=21010101, step=1, kind="date"):
- if kind == "date":
- # print "# repeat", start, end, step, name, kind
- self.data = ecflow.RepeatDate(name, int(start), int(end),
- int(step))
- elif "int" in kind:
- self.data = ecflow.RepeatInteger(name, int(start), int(end), int(step))
- elif kind == "string":
- self.data = ecflow.RepeatString(name, start)
- elif "enum" in kind:
- self.data = ecflow.RepeatEnumerated(name, start)
- elif kind == "day":
- self.data = ecflow.RepeatDay(step)
- else: self.data = None
-
- def add_to(self, node):
- if self.data is not None:
- node.add_repeat(self.data)
-
-def If(test=True, then=None, otow=None):
- """ enable Task("t1").add(If(test= (1==1),
- then= Variables(ONE=1),
- otow= Variables(TWO=2)))
- appreciate that both branches are evaluated, using this If class
- ie there is no 'dead code' as it is with python language 'if' structure
-
- using If to distinguish od/rd mode request that both users share
- the variables (parameter.py) and ecf.py
-
- otow: on the other way?
- """
- if test:
- return then
- return otow
-
-class Root(object): # from where Suite and Node derive
- """ generic tree node """
-
- def __str__(self):
- if isinstance(self, ecflow.Node):
- return self.fullname()
- return str(self)
-
- def __eq__(self, node):
- if isinstance(self, ecflow.Node):
- return "%s == " % self.fullname() + str(node)
- return False
-
- def __ne__(self, node):
- if isinstance(self, ecflow.Node):
- return "%s != " % self.fullname() + str(node)
- return False
-
- def __and__(self, node):
- if isinstance(self, ecflow.Node):
- return "%s and " % self.fullname() + str(node)
- return False
-
- def __or__(self, node):
- if isinstance(self, ecflow.Node):
- return "%s or " % self.fullname() + str(node)
- return False
-
- def fullname(self):
- """ simple syntax """
- if isinstance(self, ecflow.Node):
- return self.get_abs_node_path()
- return str(self)
-
- def repeat(self, name="YMD", start=20120101, end=20321212, step=1,
- kind="date"):
- """ add repeat attribute"""
- if kind == "date":
- self.add_repeat(ecflow.RepeatDate(name, int(start), int(end),
- int(step)))
- elif kind == "integer":
- self.add_repeat(ecflow.RepeatInteger(name, int(start), int(end), int(step)))
- elif kind == "string":
- self.add_repeat(ecflow.RepeatString(name, start))
- elif kind == "enumerated":
- self.add_repeat(ecflow.RepeatEnumerated(name, start))
- elif kind == "day":
- self.add_repeat(ecflow.RepeatDay(step))
- else: raise BaseException
- return self
-
- def defstatus(self, kind):
- """ add defstatus attribute"""
- status = kind
- if type(kind) == str:
- kinds = {"suspended": ecflow.DState.suspended,
- "aborted": ecflow.DState.aborted,
- "complete": ecflow.DState.complete,
- "active": ecflow.DState.active,
- "submitted": ecflow.DState.submitted,
- "unknown": ecflow.DState.unknown,
- "queued": ecflow.DState.queued,
- }
- status = kinds[kind]
- self.add_defstatus(status)
- return self
-
- def add(self, item=None, *args):
- """ add a task, a family or an attribute """
- if DEBUG: print self.fullname(), item, args
-
- if item is not None:
- if type(item) == tuple:
- for val in item:
- self.add(val)
- elif type(item) == list:
- for val in item:
- self.add(val)
- else:
- try: item.add_to(self)
- except Exception, exc:
- raise BaseException("not yet", self, type(item), exc)
-
- if len(args) > 0:
- if type(args) == tuple:
- for val in args:
- self.add(val)
- elif type(args) == list:
- for val in args:
- self.add(val)
- else: raise BaseException()
-
- if not isinstance(self, ecflow.Node): raise BaseException(
- "you don't want that")
-
- return self
-
- def limit(self, name, size):
- """ add limit attribute"""
- if name is None: raise BaseException
- self.add_limit(name, size)
- return self
-
- def inlimit(self, full_path):
- """ add inlimit attribute"""
- if not USE_LIMIT:
- return self
-
- path, name = full_path.split(":")
- if name is None: raise BaseException()
- if path is None: raise BaseException()
-
- self.add_inlimit(name, path)
- return self
-
-class Node(Root): # from where Task and Family derive
- """ Node class is shared by family and task """
-
- def add_limits(self, __a = None, __b = None, **kwargs):
- """ add limit dependency"""
- if isinstance(__a, basestring):
- self.add_limit(__a, __b)
- elif isinstance(__a, dict):
- assert __b is None
- for key, val in __a.items():
- self.add_limit(key, val)
- for key, val in kwargs.items():
- self.add_limit(key, val)
- return self
-
- def meter(self, name, start, end, threshold=None):
- """ add meter attribute"""
- if threshold == None:
- threshold = end
- self.add_meter(name, start, end, threshold)
- return self
-
- def label(self, name, default=""):
- """ add label attribute"""
- self.add_label(name, default)
- return self
-
- def event(self, name=1):
- """ add event attribute"""
- if USE_EVENT:
- self.add_event(name)
- return self
-
- def cron(self, time, dom=False, wdays=False, month=False):
- """ wrapper for add_cron """
- cron = ecflow.Cron()
- cron.set_time_series(time)
- if wdays is not False:
- cron.set_week_days(wdays)
- if month is not False:
- cron.set_months(month)
- if dom is not False:
- cron.set_day_of_month(dom)
-
- self.add_cron(cron)
- return self
-
- def today(self, hhmm):
- """ wrapper around time """
- self.time(hhmm)
- return self # ???
-
- def time(self, hhmm):
- """ wrapper around time, None argument is silently ignored """
- if hhmm is not None:
- self.add_time(hhmm)
- return self
-
- def trigger(self, arg):
- """ add trigger attribute"""
- if USE_TRIGGER and arg is not None:
- self.add_trigger(arg)
- return self
-
- def trigger_and(self, arg):
- """ append to existing trigger"""
- if USE_TRIGGER and arg is not None:
- self.add_part_trigger(ecflow.PartExpression(arg, True))
- return self
-
- def trigger_or(self, arg):
- """ append to existing trigger"""
- if USE_TRIGGER and arg is not None:
- self.add_part_trigger(ecflow.PartExpression(arg, False))
- return self
-
- def complete(self, arg):
- """ add complete attribute"""
- if USE_TRIGGER and arg is not None:
- self.add_complete(arg)
- return self
-
- def complete_and(self, arg):
- """ append to existing complete"""
- if USE_TRIGGER and arg is not None:
- self.add_part_complete(ecflow.PartExpression(arg, True))
- return self
-
- def complete_or(self, arg):
- """ append to existing complete"""
- if USE_TRIGGER and arg is not None:
- self.add_part_complete(ecflow.PartExpression(arg, False))
- return self
-
- def up(self):
- """ get parent, one level up"""
- return self.get_parent()
-
-class Defs(ecflow.Defs):
- """ wrapper for the definition """
- def add(self, suite):
- """ add suite """
- self.add_suite(suite)
- return suite
-
- def suite(self, name):
- """ add suite providing its name """
- suite = Suite(name)
- self.add(suite)
- return suite
-
-class Client(ecflow.Client):
- """ wrapper around client """
- def __init__(self, host="localhost", port="31415"):
- if "@" in host:
- host, port = host.split("@")
- # super(Client, self).__init__(host, int(port))
- super(Client, self).__init__()
- self.set_host_port(host, int(port))
- else:
- super(Client, self).__init__()
- self.set_host_port(host, int(port))
- # super(Client, self).__init__(host, "%s" % port)
- self.host = host
- self.port = port
-
- def __str__(self):
- return "ecflow client %s@%s v%s" % (self.host, self.port,
- self.version())
-
-class Suite(ecflow.Suite, Root):
- """ wrapper for a suite """
-
- def family(self, name):
- """ add family """
- fam = Family(name)
- self.add_family(fam)
- return fam
-
- def task(self, name):
- """ add family """
- tsk = Task(name)
- self.add_task(tsk)
- return tsk
-
- # def __enter__(self): return self
- # def __exit__(self, *args): pass
-
-class Family(ecflow.Family, Node, Attribute):
- """ wrapper around family """
-
- def family(self, name):
- """ add a family """
- fam = Family(name)
- self.add_family(fam)
- return fam
-
- def task(self, name):
- """ add a task """
- tsk = Task(name)
- self.add_task(tsk)
- return tsk
-
- def add_to(self, node):
- node.add_family(self)
-
- # def __enter__(self): return self
- # def __exit__(self, *args): pass
-
-class Task(ecflow.Task, Node, Attribute):
- """ wrapper around task """
-
- def __setattr__(self, key, val):
- # assert key.isupper()
- if key.isupper():
- key, val = translate(key, val)
- self.add_variable(key, val)
-
- def add_to(self, node):
- node.add_task(self)
-
- def add_family(self, node): raise BaseException()
-
-def display(defs, fname=None):
- """ print defs"""
- if fname is None:
- pass # print defs
- else:
- fop = open(fname, "w")
- print >> fop, defs
-
-
-class TestEcf(unittest.TestCase):
- """ a test case """
- def test_xxx(self):
- """ a test """
-
- suite = Suite ("a_suite")
- suite.defstatus("suspended")
-
- fam = Family("a_family")
- tsk = Task("a_task")
-
- ft2 = Task("a_fam")
- ft2.add_to(fam)
-
- tsk.VAR = "VALUE" # edit VAR "VALUE"
- tsk.add(Late("-s 00:05 -c 01:00"))
-
- fam.add(tsk,
-
- (Task("1"), Task("2")),
- [Task("11"), Task("12")],
- Task("111"), Task("211"),
-
- Task("t2").add(Trigger(tsk == COMPLETE),
- Time("01:00")) )
-
- fam.add(Task("t3").add(
- If(test= (1==1),
- then=Variables(ADD_ONE=1),
- otow=Variables(ADD_TWO=1)),
-
- If(test= (1==0),
- then=Variables(ADD_ONE=0),
- otow=Variables(ADD_TWO=0)),
- Trigger(tsk != ABORTED),
- Complete(tsk == COMPLETE))) # longer
-
- fam.add(
- Task("2t"),
- Task("t4").add(
- Trigger(tsk.name() != COMPLETE)),
- Late("-s 00:05 -c 01:00"),
- Variables(VAR="VALUE"),
- Task("t5").add(Trigger(["t4", "t3", "t2"])),
- Task("t6").add(Trigger("2t" == COMPLETE)),
- Task("t7").add(Trigger("2t eq complete")),
- )
-
- tsk.add(Limit("a_limit", 10),
- InLimit("a_task:a_limit"),
- Meter("step", -1, 100),
- Label("info", "none"),
- Event(1),
- Event("a"),
- Defcomplete())
-
- tsk.add(Variables({"A": "a", "B": "b"}))
- tsk.add(Variables(D="d", E="e"))
- tsk.add(Variables("C", "c"))
- suite.add(fam)
-
- fam.family("another").add(DefcompleteIf(True))
-
- defs = Defs()
- defs.add(suite)
- another = defs.suite("another")
- another.defstatus("suspended")
- another.task("tn")
- afam = another.family("another_fam")
- afam.task("t2n")
-
- display(defs, fname="test_ecf.tmp")
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/ecflow_4_0_7/Pyext/samples/printdefs.py b/ecflow_4_0_7/Pyext/samples/printdefs.py
deleted file mode 100644
index 886194d..0000000
--- a/ecflow_4_0_7/Pyext/samples/printdefs.py
+++ /dev/null
@@ -1,178 +0,0 @@
-#!/usr/bin/env python2.7
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# Name :
-# Author : Avi
-# Revision : $Revision: #10 $
-#
-# Copyright 2009-2012 ECMWF.
-# This software is licensed under the terms of the Apache Licence version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation
-# nor does it submit to any jurisdiction.
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-import ecflow
-import argparse # for argument parsing
-
-class Indentor:
- """This class manages indentation,
- It is used to correctly indent the definition node tree hierarchy
- """
- _index = 0
- def __init__(self):
- Indentor._index += 1
- def __del__(self):
- Indentor._index -= 1
- @classmethod
- def indent(cls):
- for i in range(Indentor._index):
- print ' ',
-
-class DefsTraverser:
- """Traverse the ecflow.Defs definition and writes to standard out.
-
- Ecflow has the following hierarchy::
- Task --> Submittable -->Node
- Family --> NodeContainer -->Node
- Suite --> NodeContainer -->Node
-
- This demonstrates that all nodes in the node tree and all attributes are accessible.
- Additionally the state data is also accessible. This class will write state data as
- comments. If the definition was returned from the server, it allows access to latest
- snapshot of the state data held in the server.
- """
- def __init__(self,defs):
- assert (isinstance(defs,ecflow.Defs)),"Expected ecflow.Defs as first argument"
- self.__defs = defs
-
- def do_print(self):
- for extern in self.__defs.externs:
- self.__println("extern " + extern)
- for suite in self.__defs.suites:
- self.__print("suite ")
- self.__print_node(suite)
- clock = suite.get_clock()
- if clock:
- indent = Indentor()
- self.__println(str(clock))
- del indent
- self.__print_nc(suite)
- self.__println("endsuite")
-
- def __print_nc(self,node_container):
- indent = Indentor()
- for node in node_container.nodes:
- if isinstance(node, ecflow.Task):
- self.__print("task ")
- self.__print_node(node)
- self.__print_alias(node)
- else:
- self.__print("family ")
- self.__print_node(node)
- self.__print_nc(node)
- self.__println("endfamily")
- del indent
-
- def __print_alias(self,task):
- indent = Indentor()
- for alias in task.nodes:
- self.__print("alias ")
- self.__print_node(alias)
- self.__println("endalias")
- del indent
-
- def __print_node(self,node):
- print node.name() + " # state:" + str(node.get_state())
-
- indent = Indentor()
- defStatus = node.get_defstatus()
- if defStatus != ecflow.DState.queued:
- self.__println("defstatus " + str(defStatus))
-
- autocancel = node.get_autocancel()
- if autocancel: self.__println(str(autocancel))
-
- repeat = node.get_repeat()
- if not repeat.empty(): self.__println(str(repeat) + " # value: " + str(repeat.value()))
-
- late = node.get_late()
- if late: self.__println(str(late) + " # is_late: " + str(late.is_late()))
-
- complete_expr = node.get_complete()
- if complete_expr:
- for part_expr in complete_expr.parts:
- trig = "complete "
- if part_expr.and_expr(): trig = trig + "-a "
- if part_expr.or_expr(): trig = trig + "-o "
- self.__print(trig)
- print part_expr.get_expression()
- trigger_expr = node.get_trigger()
- if trigger_expr:
- for part_expr in trigger_expr.parts:
- trig = "trigger "
- if part_expr.and_expr(): trig = trig + "-a "
- if part_expr.or_expr(): trig = trig + "-o "
- self.__print(trig)
- print part_expr.get_expression()
-
- for var in node.variables: self.__println("edit " + var.name() + " '" + var.value() + "'")
- for meter in node.meters: self.__println(str(meter) + " # value: " + str(meter.value()))
- for event in node.events: self.__println(str(event) + " # value: " + str(event.value()))
- for label in node.labels: self.__println(str(label) + " # value: " + label.new_value())
- for limit in node.limits: self.__println(str(limit) + " # value: " + str(limit.value()))
- for inlimit in node.inlimits: self.__println(str(inlimit))
- for the_time in node.times: self.__println(str(the_time))
- for today in node.todays: self.__println(str(today))
- for date in node.dates: self.__println(str(date))
- for day in node.days: self.__println(str(day))
- for cron in node.crons: self.__println(str(cron))
- for verify in node.verifies: self.__println(str(verify))
- for zombie in node.zombies: self.__println(str(zombie))
-
- del indent
-
- def __print(self,the_string):
- Indentor.indent()
- print the_string,
-
- def __println(self,the_string):
- Indentor.indent()
- print the_string
-
-if __name__ == "__main__":
-
- DESC = """Will list all the nodes and attributes in the definition
- Usage:
- Example1: List all the states
- printdefs.py --host cca --port 4141
- """
- PARSER = argparse.ArgumentParser(description=DESC,
- formatter_class=argparse.RawDescriptionHelpFormatter)
- PARSER.add_argument('--host', default="localhost",
- help="The name of the host machine, defaults to 'localhost'")
- PARSER.add_argument('--port', default="3141",
- help="The port on the host, defaults to 3141")
- ARGS = PARSER.parse_args()
- #print ARGS
-
- # ===========================================================================
- CL = ecflow.Client(ARGS.host, ARGS.port)
- try:
- CL.ping()
-
- # get the incremental changes, and merge with defs stored on the Client
- CL.sync_local()
-
- # check to see if definition exists in the server
- defs = CL.get_defs()
- if defs == None :
- print "No definition found, exiting..."
- exit(0)
-
- # print defs;
- defs_traverser = DefsTraverser(defs)
- defs_traverser.do_print()
-
- except RuntimeError, ex:
- print "Error: " + str(ex)
- print "Check host and port number are correct."
diff --git a/ecflow_4_0_7/Pyext/script.py b/ecflow_4_0_7/Pyext/script.py
deleted file mode 100644
index 0d73b95..0000000
--- a/ecflow_4_0_7/Pyext/script.py
+++ /dev/null
@@ -1,11 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-#
-#
-print 'Hello World !'
-number = 42
diff --git a/ecflow_4_0_7/Pyext/setup.py.in b/ecflow_4_0_7/Pyext/setup.py.in
deleted file mode 100755
index b587c90..0000000
--- a/ecflow_4_0_7/Pyext/setup.py.in
+++ /dev/null
@@ -1,135 +0,0 @@
-#!/usr/bin/env python
-from distutils.core import setup, Extension
-import os
-import sys
-import glob
-
-# ========================================================================
-# Usage:
-# cd $WK; cd ecbuild/release/; sh -x ../../cmake.sh release; make ; make install
-# calling 'sh -x ../../cmake.sh release' will generate steup.py from setup.py.in
-# Issues:
-# Can not test cmake install, since it will always install to
-# /usr/local/apps/python/current/lib/python2.7/site-packages/ecflow
-#
-# To test install manually, we can:
-# cd $WK/Pyext
-# rm -rf build/ # for a clean build
-# python setup.py build_ext
-# python setup.py install --home=~
-#
-# See: http://docs.python.org/2/distutils/apiref.html?highlight=extension#distutils.core.Extension
-#
-# ========================================================================
-# AIX: On AIX we need custom compile and link flags:
-# The final link line is wrong: xlC_r xlc_r ,
-# /usr/local/lpp/vacpp11109/usr/vacpp/bin/.orig/xlC_r: 1501-228 (W) input file xlc_r not found
-#
-# Removing the duplicated xlc_r, We then get a little further,
-# ld: 0711-317 ERROR: Undefined symbol: .main
-# Using -bnoquiet
-# .main [12] ER PR crt0_64.s(/lib/crt0_64.o)
-# 00000070 .text R_RBR [34] .__start
-# This is because it is missing -G (generate dynamic library)
-# When we manually add -G, we sucessfully link(ecflow.so)
-#
-# Both of these can be fixed, by overriding the Link line with:
-# export LDSHARED="xlC_r -G -Wl,-bI:/usr/local/apps/python/2.7.2-01/lib/python2.7/config/python.exp"
-#
-# To find out what python is going to use:
-# python -c "from distutils import sysconfig; print sysconfig.get_config_vars('LDSHARED')[0]"
-# On AIX, it does not use this value ?
-#
-# See python issue 18235 _sysconfigdata.py wrong on AIX installations
-# ==========================================================================
-
-# ==========================================================================
-# Permissions: The permission of congfigured file are wrong: 2 choices
-# o Make sure origin file, has the right permissions
-# o Copy file to different directory, and change the permissions
-# since file(COPY) does rename files
-# configure_file(setup.py.in ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/setup.py)
-# now copy the temporary into the final destination, setting the permissions
-# file(COPY ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/setup.py
-# DESTINATION ${CMAKE_BINARY_DIR}
-# FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ
-# GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
-# ============================================================================
-
-#=============================================================================
-# define the directories to search for include files
-# to get this to work, you will need to include the path
-# to your boost installation and ecflow includes
-boost_root=os.getenv("BOOST_ROOT")
-include_dirs = [ "@CMAKE_CURRENT_SOURCE_DIR@/../ACore/src",
- "@CMAKE_CURRENT_SOURCE_DIR@/../ANattr/src",
- "@CMAKE_CURRENT_SOURCE_DIR@/../ANode/src",
- "@CMAKE_CURRENT_SOURCE_DIR@/../AParser/src",
- "@CMAKE_CURRENT_SOURCE_DIR@/../Base/src",
- "@CMAKE_CURRENT_SOURCE_DIR@/../Base/src/cts",
- "@CMAKE_CURRENT_SOURCE_DIR@/../Base/src/stc",
- "@CMAKE_CURRENT_SOURCE_DIR@/../CSim/src",
- "@CMAKE_CURRENT_SOURCE_DIR@/../Client/src",
- "@CMAKE_CURRENT_SOURCE_DIR@/src",
- boost_root,
- ]
-
-# define the library directories to include any extra libraries that may be needed.
-# Give preference to release libs
-boost_lib_dir = boost_root + "/stage/lib/"
-library_dirs = ['@CMAKE_BINARY_DIR@/ACore',
- '@CMAKE_BINARY_DIR@/ANattr/',
- '@CMAKE_BINARY_DIR@/ANode/',
- '@CMAKE_BINARY_DIR@/AParser/',
- '@CMAKE_BINARY_DIR@/Base/',
- '@CMAKE_BINARY_DIR@/CSim/',
- '@CMAKE_BINARY_DIR@/Client/',
- boost_lib_dir
- ]
-
-# define the libraries to link with this includes the boost lib
-libraries = [ 'core' , 'nodeattr', 'node', 'libparser', 'base', 'libsimu', 'libclient',
- 'boost_system-mt',
- 'boost_serialization-mt',
- 'boost_filesystem-mt',
- 'boost_program_options-mt',
- 'boost_date_time-mt',
- 'boost_python-mt' ]
-
-# extra compile flags needed for AIX only
-# Note setup.py will add -q64 -qcpluscmt -DNDEBUG automatically
-# Note: two extra_compile_args, debug and release, use the debug for testing and faster compiles
-extra_compile_args = []
-extra_link_args = []
-if sys.platform.startswith("aix"):
- extra_compile_args = [ '-qsuppress=1540-0198', '-O3', '-qstrict', '-qfuncsect', '-qeh', '-qrtti' ]
- #extra_compile_args = [ '-qsuppress=1540-0198', '-qNOOPTimize', '-qnoinline', '-qfullpath', '-qfuncsect', '-qeh', '-qrtti' ]
- extra_link_args= [ '-lpthread', '-ldl', '-bbigtoc' ] # '-G', '-noipath',
-
-
-# create the extension and add it to the python distribution
-# o glob.glob(os.path.join('src', '*.cpp'))
-# This expand the list of cpp files that need to be compiled
-#
-# The configuation below installs to:
-# o /usr/local/apps/python/current/lib/python2.7/site-packages/ecflow
-# when, "python setup.py install" is used:
-# lib/python2.7/site-packages/ecflow/ecflow.so
-# __init__.py
-setup( name='ecflow',
- version='@ECFLOW_VERSION@',
- author = 'ECMWF',
- description = """ecflow Python interface""",
- packages = [ 'ecflow' ],
- package_dir={'ecflow': '@CMAKE_CURRENT_SOURCE_DIR@/ecflow'},
- ext_modules=[ Extension(
- 'ecflow.ecflow',
- glob.glob(os.path.join('@CMAKE_CURRENT_SOURCE_DIR@/src', '*.cpp')),
- include_dirs=include_dirs,
- library_dirs=library_dirs,
- libraries=libraries,
- extra_compile_args=extra_compile_args,
- extra_link_args=extra_link_args
- )
- ],
- )
diff --git a/ecflow_4_0_7/Pyext/src/BoostPythonUtil.cpp b/ecflow_4_0_7/Pyext/src/BoostPythonUtil.cpp
deleted file mode 100644
index 7634251..0000000
--- a/ecflow_4_0_7/Pyext/src/BoostPythonUtil.cpp
+++ /dev/null
@@ -1,56 +0,0 @@
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "BoostPythonUtil.hpp"
-
-void BoostPythonUtil::list_to_int_vec(const boost::python::list& list, std::vector<int>& int_vec)
-{
- int the_list_size = len(list);
- int_vec.reserve(the_list_size);
- for (int i = 0; i < the_list_size; ++i) {
- int_vec.push_back(boost::python::extract<int>(list[i]));
- }
-}
-
-void BoostPythonUtil::list_to_str_vec(const boost::python::list& list, std::vector<std::string>& vec)
-{
- int the_list_size = len(list);
- vec.reserve(the_list_size);
- for (int i = 0; i < the_list_size; ++i) {
- vec.push_back(boost::python::extract<std::string>(list[i]));
- }
-}
-
-void BoostPythonUtil::dict_to_str_vec(const boost::python::dict& dict, std::vector<std::pair<std::string,std::string> >& str_pair_vec)
-{
- boost::python::list keys = dict.keys();
- const int no_of_keys = len(keys);
- str_pair_vec.reserve(no_of_keys);
-
- for(int i = 0; i < no_of_keys; ++i) {
-
- boost::python::object curArg = dict[keys[i]];
- if(curArg) {
- std::string first = boost::python::extract<std::string>(keys[i]);
- std::string second = boost::python::extract<std::string>(dict[keys[i]]);
- str_pair_vec.push_back( std::make_pair(first,second));
-// std::cout << "BoostPythonUtil::dict_to_str_vec " << first << " " << second << "\n";
- }
- }
-
-}
-
diff --git a/ecflow_4_0_7/Pyext/src/BoostPythonUtil.hpp b/ecflow_4_0_7/Pyext/src/BoostPythonUtil.hpp
deleted file mode 100644
index 8dc1c9a..0000000
--- a/ecflow_4_0_7/Pyext/src/BoostPythonUtil.hpp
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef BOOST_PYTHON_UTIL_HPP_
-#define BOOST_PYTHON_UTIL_HPP_
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <boost/noncopyable.hpp>
-#include <boost/python.hpp>
-#include <vector>
-#include <string>
-
-// See: http://wiki.python.org/moin/boost.python/HowTo#boost.function_objects
-
-class BoostPythonUtil : private boost::noncopyable {
-public:
-
- /// Convert python list to a vector of integers. raises a type error if integer extraction fails
- static void list_to_int_vec(const boost::python::list& list, std::vector<int>& int_vec);
- static void list_to_str_vec(const boost::python::list& list, std::vector<std::string>& int_vec);
- static void dict_to_str_vec(const boost::python::dict& dict, std::vector<std::pair<std::string,std::string> >& str_pair);
-
-};
-
-#endif
diff --git a/ecflow_4_0_7/Pyext/src/ClientDoc.cpp b/ecflow_4_0_7/Pyext/src/ClientDoc.cpp
deleted file mode 100644
index 0e65f44..0000000
--- a/ecflow_4_0_7/Pyext/src/ClientDoc.cpp
+++ /dev/null
@@ -1,1419 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #89 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "ClientDoc.hpp"
-
-const char* ClientDoc::class_client(){
- return
- "Class client provides an interface to communicate with the :term:`ecflow_server`.::\n\n"
- " Client(\n"
- " string host, # The server name. Can not be empty.\n"
- " string port # The port on the server, must be unique to the server\n"
- " )\n\n"
- " Client(\n"
- " string host, # The server name. Can not be empty.\n"
- " int port # The port on the server, must be unique to the server\n"
- " )\n\n"
- " Client(\n"
- " string host_port, # Expect's <host>:<port>\n"
- " )\n\n"
- "The client reads in the following environment variables.\n"
- "For child commands,(i.e these are commands called in the .ecf/jobs files), these variables are used.\n"
- "For the python interface these environment variable are not really applicable but documented for completeness:\n\n"
- "* ECF_NAME <string> : Full path name to the task\n"
- "* ECF_PASS <string> : The jobs password, allocated by server, then used by server to authenticate client request\n"
- "* ECF_TRYNO <int> : The number of times to start a job if it aborts\n"
- "* ECF_TIMEOUT <int> : Max time in seconds for client to deliver message to main server\n"
- "* ECF_HOSTFILE<string> : File that lists alternate hosts to try, if connection to main host fails\n"
- "* ECF_DENIED <any> : Provides a way for child to exit with an error, if server denies connection.\n"
- " Avoids 24hr wait. Note: when you have hundreds of tasks, using this approach\n"
- " requires a lot of manual intervention to determine job status\n"
- "* NO_ECF <any> : If set exit's immediately with success. Used to test jobs without communicating with server\n\n"
- "The following environment variables are used by the python interface and child commands\n\n"
- "* ECF_NODE <string> : The host name of the main server. defaults to 'localhost'\n"
- "* ECF_PORT <int> : The TCP/IP port to call on the server. Must be unique to a server\n\n"
- "The ECF_NODE and ECF_PORT can be overridden by using the Constructor or set_host_port() member function.\n"
- "For optimal usage it is best to reuse the same Client rather than recreating for each client server interaction\n"
- "By default the Client interface will throw exceptions for error's.\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client(\"localhost:3150\") # for errors will throw RuntimeError\n"
- " ci.terminate_server()\n"
- " except RuntimeError, e:\n"
- " print str(e)\n\n"
- ;
-}
-
-const char* ClientDoc::set_host_port(){
- return
- "Override the default(localhost and port 3141) and environment setting(ECF_NODE and ECF_PORT)\n"
- "and set it explicitly::\n\n"
- " set_host_port(\n"
- " string host, # The server name. Can not be empty.\n"
- " string port # The port on the server, must be unique to the server\n"
- " )\n\n"
- " set_host_port(\n"
- " string host, # The server name. Can not be empty.\n"
- " int port # The port on the server, must be unique to the server\n"
- " )\n\n"
- " set_host_port(\n"
- " string host_port, # Expect's <host>:<port>\n"
- " )\n\n"
- "Exceptions:\n\n"
- "- Raise a RuntimeError if the host or port is empty\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client();\n"
- " ci.set_host_port(\"localhost\",\"3150\")\n"
- " ci.set_host_port(\"avi\",3150)\n"
- " ci.set_host_port(\"avi:3150\")\n"
- " except RuntimeError, e:\n"
- " print str(e)\n\n"
- ;
-}
-
-const char* ClientDoc::set_retry_connection_period() {
- return
- "Set the sleep period between connection attempts\n\n"
- "Whenever there is a connection failure we wait a number of seconds before trying again.\n"
- "i.e. to get round glitches in the network.\n"
- "For the ping command this is hard wired as 1 second.\n"
- "This wait between connection attempts can be configured here.\n"
- "i.e This could be reduced to increase responsiveness.\n"
- "Default: In debug this period is 1 second and in release mode 10 seconds::\n\n"
- " set_retry_connection_period(\n"
- " int period # must be an integer >= 0\n"
- " )\n\n"
- "Exceptions:\n\n"
- "- None\n"
- "\nUsage::\n\n"
- " ci = Client()\n"
- " ci.set_connection_attempts(3) # make 3 attempts for server connection\n"
- " ci.set_retry_connection_period(1) # wait 1 second between each attempt\n"
- ;
-}
-
-const char* ClientDoc::set_connection_attempts() {
- return
- "Set the number of times to connect to :term:`ecflow_server`, in case of connection failures\n\n"
- "The period between connection attempts is handled by Client.set_retry_connection_period().\n"
- "If the network is unreliable the connection attempts can be be increased, likewise\n"
- "when the network is stable this number could be reduced to one.\n"
- "This can increase responsiveness and reduce latency.\n"
- "Default value is set as 2.\n"
- "Setting a value less than one is ignored, will default to 1 in this case::\n\n"
- " set_connection_attempts(\n"
- " int attempts # must be an integer >= 1\n"
- " )\n"
- "\nExceptions:\n\n"
- "- None\n"
- "\nUsage::\n\n"
- " ci = Client()\n"
- " ci.set_connection_attempts(3) # make 3 attempts for server connection\n"
- " ci.set_retry_connection_period(1) # wait 1 second between each attempt\n"
- ;
-}
-
-const char* ClientDoc::get_defs(){
- return
- "Returns the :term:`suite definition` stored on the Client.\n\n"
- "Use :py:class:`ecflow.Client.sync_local()` to retrieve the definition from the server first.\n"
- "The definition is *retained* in memory until the next call to sync_local().\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.sync_local() # get the definition from the server and store on 'ci'\n"
- " print ci.get_defs() # print out definition stored in the client\n"
- " print ci.get_defs() # print again, this shows that defs is retained on ci\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::get_log()
-{
- return
- "Request the :term:`ecflow_server` to return the log file contents as a string\n\n"
- "Use with caution as the returned string could be several megabytes.\n"
- "Only enabled in the debug build of ECF.\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " print ci.get_log() # get the log file from the server\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::new_log()
-{
- return
- "Request the :term:`ecflow_server` to use the path provided, as the new log file\n\n"
- "The old log file is released.\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.new_log('/path/log.log') # use '/path/log,log' as the new log file\n"
- " # To keep track of log file Can change ECF_LOG\n"
- " ci.alter('\','change','variable','ECF_LOG','/new/path.log')\n"
- " ci.new_log()\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::clear_log()
-{
- return
- "Request the :term:`ecflow_server` to clear log file.\n"
- "Log file will be empty after this call.\n\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.clear_log() # log file is now empty\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::flush_log()
-{
- return
- "Request the :term:`ecflow_server` to flush and then close log file\n\n"
- "It is best that the server is :term:`shutdown` first, as log file will be reopened\n"
- "whenever a command wishes to log any changes.\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.flush_log() # Log can now opened by external program\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::log_msg()
-{
- return
- "Request the :term:`ecflow_server` writes a string message to the log file.\n\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.log_msg(\"A message\") # Write message to log file\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::restart_server() {
- return
- "Restart the :term:`ecflow_server`\n\n"
- "Start job scheduling, communication with jobs, and respond to all requests.\n"
- "See :term:`server states`\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.retstart_server()\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-const char* ClientDoc::halt_server() {
- return
- "Halt the :term:`ecflow_server`\n\n"
- "Stop server communication with jobs, and new job scheduling, and stops check pointing.\n"
- "See :term:`server states`\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.halt_server()\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-const char* ClientDoc::shutdown_server() {
- return
- "Shut down the :term:`ecflow_server`\n\n"
- "Stop server from scheduling new jobs.\n"
- "See :term:`server states`\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.shutdown_server()\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::terminate_server() {
- return "Terminate the :term:`ecflow_server`::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.terminate_server()\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::wait_for_server_reply() {
- return "Wait for a response from the :term:`ecflow_server`::\n\n"
- " void wait_for_server_reply(\n"
- " int time_out : (default = 60) \n"
- " )\n\n"
- "This is used to check if server has started. Typically for tests.\n"
- "Returns true if server(ping) replies before time out, otherwise false\n"
- "\nUsage::\n\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " if ci.wait_for_server_reply(30):\n"
- " print 'Server is alive'\n"
- " else:\n"
- " print 'Timed out after 30 second wait for server response.?'\n"
- ;
-}
-
-const char* ClientDoc::load_defs(){
- return
- "Load a :term:`suite definition` given by the file_path argument into the :term:`ecflow_server`::\n\n"
- " void load(\n"
- " string file_path : path name to the definition file\n"
- " [(bool)force=False] : If true overwrite suite of same name\n"
- " )\n\n"
- "By default throws a RuntimeError exception for errors.\n"
- "If force is not used and :term:`suite` of the same name already exists in the server,\n"
- "then a error is thrown\n"
- "\nUsage::\n\n"
- " defs_file = \"Hello.def\" \n"
- " defs = Defs()\n"
- " suite = def.add_suite(\"s1\")\n"
- " family = suite.add_family(\"f1\")\n"
- " for i in [ \"_1\", \"_2\", \"_3\" ]:\n"
- " family.add_task( \"t\" + i )\n"
- " defs.save_as_defs(defs_file) # write out in memory defs into the file 'Hello.def'\n"
- " ...\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.load(defs_file) # open and parse defs file, and load into server.\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::load(){
- return
- "Load a in memory :term:`suite definition` into the :term:`ecflow_server`::\n\n"
- " void load(\n"
- " Defs defs : A in memory definition\n"
- " [(bool)force=False] : for true overwrite suite of same name\n"
- " )\n\n"
- "If force is not used and :term:`suite` already exists in the server, then a error is thrown.\n"
- "\nUsage::\n\n"
- " defs = Defs(\"hello.def\")\n"
- " suite = defs.add_suite(\"s1\")\n"
- " family = suite.add_family(\"f1\")\n"
- " for i in [ \"_1\", \"_2\", \"_3\" ]: \n"
- " family.add_task( Task( \"t\" + i) )\n"
- " ...\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.load(defs) # Load in memory defs, into the server\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::get_server_defs() {
- return
- "Get all suite Node tree's from the :term:`ecflow_server`.\n\n"
- "The definition is *retained* in memory until the next call to get_server_defs().\n"
- "This is important since get_server_defs() could return several megabytes of data.\n"
- "Hence we only want to call it once, and then access it locally with get_defs().\n"
- "If you need to access the server definition in a loop use :py:class:`ecflow.Client.sync_local` instead\n"
- "since this is capable of returning incremental changes, and thus considerably\n"
- "reducing the network load.\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.get_server_defs() # get the definition from the server and store on 'ci'\n"
- " print ci.get_defs() # print out definition stored in the client\n"
- " print ci.get_defs() # print again, this shows that defs is retained on ci\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::sync() {
- return
- "Requests that :term:`ecflow_server` returns the full definition or incremental change made and applies them to the client Defs\n\n"
- "When there is a very large definition, calling :py:class:`ecflow.Client.get_server_defs` each time can be *very* expensive\n"
- "both in terms of memory, speed, and network bandwidth. The alternative is to call \n"
- "this function, which will get the incremental changes, and apply them local client :term:`suite definition`\n"
- "effectively synchronising the client and server Defs.\n"
- "If the period of time between two sync() calls is too long, then the full server definition\n"
- "is returned and assigned to the client Defs.\n"
- "We can determine if the changes were applied by calling in_sync() after the call to sync_local()::\n\n"
- " void sync_local(); # The very first call, will get the full Defs.\n"
- "\n"
- "Exceptions:\n\n"
- "- raise a RuntimeError if the delta change can not be applied.\n"
- "- this could happen if the client Defs bears no resemblance to server Defs\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.sync_local() # Very first call gets the full Defs\n"
- " client_defs = ci.get_defs() # End user access to the returned Defs\n"
- " ... after a period of time\n"
- " ci.sync_local() # Subsequent calls to sync_local() users the local Defs to sync incrementally\n"
- " if ci.in_sync(): # returns true server changed and changes applied to client\n"
- " print 'Client is now in sync with server'\n"
- " client_defs = ci.get_defs() # End user access to the returned Defs\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- "\n"
- "Calling sync_local() is considerably faster than calling get_server_defs() for large Definitions"
- ;
-}
-
-const char* ClientDoc::in_sync() {
- return
- "Returns true if the definition on the client is in sync with the :term:`ecflow_server`\n\n"
- "Calling in_sync() is **only** valid after a call to sync_local().\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.sync_local() # very first call gets the full Defs\n"
- " client_defs = ci.get_defs() # End user access to the returned Defs\n"
- " ... after a period of time\n"
- " ci.sync_local() # Subsequent calls to sync_local() users the local Defs to sync incrementally\n"
- " if ci.in_sync(): # returns true changed and changes applied to client\n"
- " print 'Client is now in sync with server'\n"
- " client_defs = ci.get_defs() # End user access to the returned Defs\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::news() {
- return
- "Query the :term:`ecflow_server` to detect any changes.\n\n"
- "This returns a simple bool, if there has been changes, the user should call :py:class:`ecflow.Client.sync_local`.\n"
- "This will bring the client in sync with changes in the server. If sync_local() is not called\n"
- "then calling news_local() will always return true.\n"
- "news_local() uses the definition stored on the client::\n\n"
- " bool news_local()\n"
- "\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " if ci.news_local(): # has the server changed\n"
- " print 'Server Changed' # server changed bring client in sync with server\n"
- " ci.sync_local() # get the full definition from the server if first time\n"
- " # otherwise apply incremental changes to Client definition,\n"
- " # bringing it in sync with the server definition\n"
- " print ci.get_defs() # print the synchronised definition. Should be same as server\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::changed_node_paths() {
- return
- "After a call to sync_local() we can access the list of nodes that changed\n\n"
- "The returned list consists of node paths. *IF* the list is empty assume that\n"
- "whole definition changed. This should be expected after the first call to sync_local()\n"
- "since that always retrieves the full definition from the server::\n\n"
- " void changed_node_paths()\n"
- "\n"
- "\nUsage::\n\n"
- "try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " if ci.news_local(): # has the server changed\n"
- " print 'Server Changed' # server changed bring client in sync with server\n"
- " ci.sync_local() # get the full definition from the server if first time\n"
- " # otherwise apply incremental changes to Client definition,\n"
- " # bringing it in sync with the server definition\n"
- " defs = ci.get_defs() # get the updated/synchronised definition\n"
- " for path in ci.changed_node_paths():\n"
- " print path;\n"
- " if path == '/': # path '/' represent change to server node/defs\n"
- " print 'defs changed' # defs state change or user variables changed\n"
- " else:\n"
- " node = defs.find_abs_node_path()\n"
- "\n"
- " # if changed_node_paths is empty, then assume entire definition changed\n"
- " print defs # print the synchronised definition. Should be same as server\n"
- "except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-
-const char* ClientDoc::checkpt(){
- return
- "Request the :term:`ecflow_server` :term:`check point` s the definition held in the server immediately\n\n"
- "This effectively saves the definition held in the server to disk,\n"
- "in a platform independent manner. This is the default when no arguments are specified.\n"
- "The saved file will include node state, passwords, etc.\n"
- "The default file name is <host>.<port>.ecf.check and is saved in ECF_HOME directory.\n"
- "The :term:`check point` file name can be overridden via ECF_CHECK server environment variable.\n"
- "The back up :term:`check point` file name can be overridden via ECF_CHECKOLD server environment variable::\n\n"
- " void checkpt(\n"
- " [(CheckPt::Mode)mode=CheckPt.UNDEFINED]\n"
- " : Must be one of [ NEVER, ON_TIME, ALWAYS, UNDEFINED ]\n"
- " NEVER : Never check point the definition in the server\n"
- " ON_TIME: Turn on automatic check pointing at interval stored on server\n"
- " or with interval specified as the second argument\n"
- " ALWAYS: Check point at any change in node tree, *NOT* recommended for large definitions\n"
- " UNDEFINED:The default, which allows for immediate check pointing, or alarm setting\n"
- " [(int)interval=120] : This specifies the interval in seconds when server should automatically check pt.\n"
- " This will only take effect if mode is on_time/CHECK_ON_TIME\n"
- " Should ideally be a value greater than 60 seconds, default is 120 seconds\n"
- " [(int)alarm=30] : Specifies check pt save alarm time. If saving the check pt takes longer than\n"
- " the alarm time, then the late flag is set on the server.\n"
- " This flag will need to be cleared manually.\n"
- " )\n\n"
- "Note: When the time taken to save the check pt is excessive, it can interfere with job scheduling.\n\n"
- "It may be an indication of the following:\n\n"
- "* slow disk\n"
- "* file system full\n"
- "* The definition is very large and needs to split\n\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.checkpt() # Save the definition held in the server to disk\n"
- " ci.checkpt(CheckPt.NEVER) # Switch off check pointing\n"
- " ci.checkpt(CheckPt.ON_TIME) # Start automatic check pointing at the interval stored in the server\n"
- " ci.checkpt(CheckPt.ON_TIME,180) # Start automatic check pointing every 180 seconds\n"
- " ci.checkpt(CheckPt.ALWAYS) # Check point at any state change in node tree. *not* recommended for large defs\n"
- " ci.checkpt(CheckPt.UNDEFINED,0,35) # Change check point save time alarm to 35 seconds\n"
- " # With these arguments mode and interval remain unchanged\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-
-const char* ClientDoc::restore_from_checkpt() {
- return
- "Request the :term:`ecflow_server` loads the :term:`check point` file from disk\n\n"
- "The server will first try to open file at ECF_HOME/ECF_CHECK if that fails it will\n"
- "then try path ECF_HOME/ECF_CHECKOLD.\n"
- "An error is returned if the server has not been :term:`halted` or contains a :term:`suite definition`\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.halt_server() # server must be halted, otherwise restore_from_checkpt will throw\n"
- " ci.restore_from_checkpt() # restore the definition from the check point file\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-
-const char* ClientDoc::reload_wl_file(){
- return
- "Request that the :term:`ecflow_server` reload the white list file.\n\n"
- "The white list file if present, can be used to control who has read/write\n"
- "access to the :term:`ecflow_server`::\n\n"
- " void reload_wl_file()\n\n"
- "Usage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.reload_wl_file()\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::run(){
- return
- "Immediately run the jobs associated with the input :term:`node`.\n\n"
- "Ignore :term:`trigger` s, :term:`limit` s, :term:`suspended`, :term:`time` or :term:`date` dependencies,\n"
- "just run the :term:`task`.\n"
- "When a job completes, it may be automatically re-queued if it has\n"
- "multiple time :term:`dependencies`. In the specific case where a :term:`task` has a SINGLE\n"
- "time dependency and we want to avoid re running the :term:`task` then\n"
- "a flag is set so that it is not automatically re-queued when set to :term:`complete`.\n"
- "The flag is applied up the :term:`node` hierarchy until we reach a node with a :term:`repeat`\n"
- "or :term:`cron` attribute. This behaviour allow :term:`repeat` values to be incremented interactively.\n"
- "A :term:`repeat` attribute is incremented when all the child nodes are :term:`complete`\n"
- "in this case the child nodes are automatically re-queued\n::\n\n"
- " void run(\n"
- " string absolute_node_path : Path name to node. If the path is suite/family will recursively\n"
- " run all child tasks\n"
- " [(bool)force=False] : If true, run even if there are nodes that are active or submitted.\n"
- " )\n"
- " void run(\n"
- " list paths : List of paths. If the path is suite/family will recursively run all child tasks\n"
- " [(bool)force=False] : If true, run even if there are nodes that are active or submitted.\n"
- " )\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.run('/s1') # run all tasks under suite /s1\n"
- "\n"
- " path_list = ['/s1/f1/t1','/s2/f1/t2']\n"
- " ci.run(path_list) # run all tasks specified in the paths\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- "\nEffect::\n\n"
- " Lets see the effect of run command on the following defs::\n\n"
- " suite s1\n"
- " task t1; time 10:00 # will complete straight away\n"
- " task t2; time 10:00 13:00 01:00 # will re-queue 3 times and complete on fourth run\n\n"
- "In the last case (task t2) after each run the next time slot is incremented.\n"
- "This can be seen by calling the Why command."
- ;
-}
-
-const char* ClientDoc::requeue(){
-
- return
- "Re queues the specified :term:`node` (s)::\n\n"
- " void requeue(\n"
- " list paths : A list of paths. Node paths must begin with a leading '/' character\n"
- " [(str)option=''] : option = ('' | 'abort' | 'force')\n"
- " '' : empty string, the default, re-queue the node\n"
- " abort: means re-queue only aborted tasks below node\n"
- " force: means re-queueing even if there are nodes that are active or submitted\n"
- " )\n"
- " void requeue(\n"
- " string absolute_node_path : Path name to node\n"
- " [(string)option=''] : option = ('' | 'abort' | 'force')\n"
- " )\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.requeue('/s1','abort') # re-queue aborted tasks below suite /s1\n"
- "\n"
- " path_list = ['/s1/f1/t1','/s2/f1/t2']\n"
- " ci.requeue(path_list)\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::free_trigger_dep(){
- return
- "Free :term:`trigger` :term:`dependencies` for a :term:`node`::\n\n"
- " void free_trigger_dep(\n"
- " string absolute_node_path : Path name to node\n"
- " )\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.free_trigger_dep('/s1')\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::free_date_dep(){
- return
- "Free :term:`date` :term:`dependencies` for a :term:`node`::\n\n"
- " void free_date_dep(\n"
- " string absolute_node_path : Path name to node\n"
- " )\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.free_date_dep('/s1')\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::free_time_dep(){
- return
- "Free all time :term:`dependencies`. i.e :term:`time`, :term:`day`, :term:`today`, :term:`cron`::\n\n"
- " void free_time_dep(\n"
- " string absolute_node_path : Path name to node\n"
- " )\n\n"
- "After freeing the time related dependencies (i.e time,today,cron)\n"
- "the next time slot will be missed.\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.free_time_dep('/s1')\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::free_all_dep(){
- return
- "Free all :term:`trigger`, :term:`date` and all time(:term:`day`, :term:`today`, :term:`cron`,etc) :term:`dependencies`::\n\n"
- " void free_all_dep(\n"
- " string absolute_node_path : Path name to node\n"
- " )\n\n"
- "After freeing the time related dependencies (i.e time,today,cron)\n"
- "the next time slot will be missed.\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.free_all_dep('/s1')\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::ping(){
- return
- "Checks if the :term:`ecflow_server` is running::\n\n"
- " void ping()\n\n"
- "The default behaviour is to check on host 'localhost' and port 3141\n"
- "It should be noted that any Client function will fail if the server is\n"
- "is not running. Hence ping() is not strictly required. However its main\n"
- "distinction from other Client function is that it is quite fast.\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client(\"localhost\",\"3150\")\n"
- " ci.ping()\n"
- " print \"------- Server already running------\"\n"
- " do_something_with_server(ci)\n"
- " except RuntimeError, e:\n"
- " print \"------- Server *NOT* running------\" + str(e)\n"
- ;
-}
-
-const char* ClientDoc::stats(){
- return
- "Prints the :term:`ecflow_server` statistics to standard out::\n\n"
- " void stats()\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.stats()\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::stats_reset(){
- return
- "Resets the statistical data in the server::\n\n"
- " void stats_reset()\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.stats_reset()\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::suites(){
- return
- "Returns a list strings representing the :term:`suite` names.\n\n"
- " list(string) suites()\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " suites = ci.suites()\n"
- " print suites\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::ch_register() {
- return
- "Register interest in a set of :term:`suite` s.\n\n"
- "If a definition has lots of suites, but the client is only interested in a small subset.\n"
- "Then using this command can reduce network bandwidth and synchronisation will be quicker.\n"
- "This command will create a client handle. This handle is held locally on the :py:class:`ecflow.Client`, and\n"
- "can be used implicitly by ch_drop(),ch_add(),ch_remove() and ch_auto_add().\n"
- "Registering a client handle affects the news() and sync() commands::\n\n"
- " void ch_register(\n"
- " bool auto_add_new_suites : true means add new suites to my list, when they are created\n"
- " list suite_names : should be a list of suite names, names not in the definition are ignored\n"
- " )\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client()\n"
- " suite_names = [ 's1', 's2', 's3' ]\n"
- " ci.ch_register(True,suite_names) # register interest in suites s1,s2,s3 and any new suites\n"
- " ci.ch_register(False,suite_names) # register interest in suites s1,s2,s3 only\n"
- " except RuntimeError, e:\n"
- " print str(e)\n\n"
- "The client 'ci' will hold locally the client handle. Since we have made multiple calls to register\n"
- "a handle, the variable 'ci' will hold the handle for the last call only.\n"
- "The handle associated with the suite can be manually retrieved::\n\n"
- " try:\n"
- " ci = Client()\n"
- " suite_names = [ 's1', 's2', 's3' ]\n"
- " ci.ch_register(True,suite_names) # register interest in suites s1,s2,s3 and any new suites\n"
- " client_handle = ci.ch_handle()\n # get the handle associated with last call to ch_register\n"
- " ci.ch_drop( client_handle ) # de-register the handle\n"
- " except RuntimeError, e:\n"
- " print str(e)\n\n"
- ;
-}
-
-const char* ClientDoc::ch_suites() {
- return
- "Writes to standard out the list of registered handles and the suites they reference.\n\n";
-}
-
-const char* ClientDoc::ch_drop(){
- return
- "Drop/de-register the client handle.\n\n"
- "Client must ensure un-used handle are dropped otherwise they will stay, in the :term:`ecflow_server`::\n\n"
- " void ch_drop(\n"
- " int client_handle : The handle must be an integer that is > 0\n"
- " )\n"
- " void ch_drop() : Uses the local handle stored on the client, from last call to ch_register()\n\n"
- "Exception:\n\n"
- "- RunTimeError thrown if handle has not been previously registered\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " suites = [ 's1', 's2' ]\n"
- " ci.ch_register(False, suites)\n"
- " while( 1 ):\n"
- " # get incremental changes to suites s1 & s2, uses data stored on ci/defs\n"
- " ci.sync_local() # will only retrieve data for suites s1 & s2\n"
- " update(ci.get_defs())\n"
- " finally:\n"
- " ci.ch_drop()\n"
- ;
-}
-
-const char* ClientDoc::ch_drop_user(){
- return
- "Drop/de-register all handles associated with user.\n\n"
- "Client must ensure un-used handle are dropped otherwise they will stay, in the :term:`ecflow_server`::\n\n"
- " void ch_drop_user(\n"
- " string user # If empty string will drop current user\n"
- " )\n\n"
- "Exception:\n\n"
- "- RunTimeError thrown if handle has not been previously registered\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " suites = [ 's1', 's2' ]\n"
- " ci.ch_register(False, suites)\n"
- " while( 1 ):\n"
- " # get incremental changes to suites s1 & s2, uses data stored on ci/defs\n"
- " ci.sync_local() # will only retrieve data for suites s1 & s2\n"
- " update(ci.get_defs())\n"
- " finally:\n"
- " ci.ch_drop_user(\"\") # drop all handles associated with current user\n\n"
- ;
-}
-
-const char* ClientDoc::ch_add() {
- return
- "Add a set of suites, to an existing handle::\n\n"
- " integer ch_add(\n"
- " integer handle : the handle obtained after ch_register\n"
- " list suite_names : list of strings representing suite names\n"
- " )\n"
- " integer ch_add(\n"
- " list suite_names : list of strings representing suite names\n"
- " )\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " suite_names = []\n"
- " ci.ch_register(True,suite_names) # register interest in any new suites\n"
- " suite_names = [ 's1', 's2' ]\n"
- " ci.ch_add(suite_names) # add suites s1,s2 to the last added handle\n"
- " except RuntimeError, e:\n"
- " print str(e)\n\n"
- ;
-}
-
-const char* ClientDoc::ch_remove() {
- return
- "Remove a set of suites, from an existing handle::\n\n"
- " integer ch_remove(\n"
- " integer handle : the handle obtained after ch_register\n"
- " list suite_names : list of strings representing suite names\n"
- " )\n"
- " integer ch_remove(\n"
- " list suite_names : list of strings representing suite names\n"
- " )\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " suite_names = [ 's1', 's2' , 's3']\n"
- " ci.ch_register(True,suite_names) # register interest in suites s1,s2,s3 and any new suites\n"
- " suite_names = [ 's1' ]\n"
- " ci.ch_remove( suite_names ) # remove suites s1 from the last added handle\n"
- " except RuntimeError, e:\n"
- " print str(e)\n\n"
- ;
-}
-
-const char* ClientDoc::ch_auto_add() {
- return
- "Change an existing handle so that new suites can be added automatically::\n\n"
- " void ch_auto_add(\n"
- " integer handle, : the handle obtained after ch_register\n"
- " bool auto_add_new_suite : automatically add new suites, this handle when they are created\n"
- " )\n"
- " void ch_auto_add(\n"
- " bool auto_add_new_suite : automatically add new suites using handle on the client\n"
- " )\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " suite_names = [ 's1', 's2' , 's3']\n"
- " ci.ch_register(True,suite_names) # register interest in suites s1,s2,s3 and any new suites\n"
- " ci.ch_auto_add( False ) # disable adding newly created suites to my handle\n"
- " except RuntimeError, e:\n"
- " print str(e)\n\n"
- ;
-}
-
-const char* ClientDoc::get_file(){
- return
- "File command can be used to request the various file types associated with a :term:`node`\n\n"
- "This command defaults to returning a max of 10000 lines. This can be changed::\n\n"
- " string get_file(\n"
- " string absolute_node_path : Path name to node\n"
- " [(string)file_type='script'] : file_type = [ script<default> | job | jobout | manual | kill | stat ]\n"
- " [(string)max_lines=\"10000\"] : The number of lines in the file to return\n"
- " )\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " for file in [ 'script', 'job', 'jobout', 'manual', 'kill', 'stat' ]:\n"
- " print ci.get_file('/suite/f1/t1',file) # make a request to the server\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::plug(){
- return
- "Plug command is used to move :term:`node` s\n\n"
- "The destination node can be on another :term:`ecflow_server`.\n"
- "In which case the destination path should be of the form '//<host>:<port>/suite/family/task::\n\n"
- " void plug(\n"
- " string source_absolute_node_path : Path name to source node\n"
- " string destination_absolute_node_path : Path name to destination node. Note if only\n"
- " '//host:port' is specified the whole suite can be moved\n"
- " )\n\n"
- "By default throws a RuntimeError exception for errors.\n\n"
- "Exceptions can be raised because:\n\n"
- "- Source :term:`node` is in a :term:`active` or :term:`submitted` state.\n"
- "- Another user already has an lock.\n"
- "- source/destination paths do not exist on the corresponding servers\n"
- "- If the destination node path is empty, i.e. only host:port is specified,\n"
- " then the source :term:`node` must correspond to a :term:`suite`.\n"
- "- If the source node is added as a child, then its name must be unique\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.plug('/suite','host3:3141')\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::alter(){
- return
- "Alter command is used to change the attributes of a node::\n\n"
- " void alter(\n"
- " (list | string ) paths(s) : A single or list of paths. Path name to the node whose attributes are to be changed\n"
- " string alter_type : This must be one of [ 'add' | 'change' | 'delete' | 'set_flag' | 'clear_flag' ]\n"
- " string attr_type : This varies according to the 'alter_type'. valid strings are:\n"
- " add : [ variable,time, today, date, day, zombie]\n"
- " delete : [ variable,time,today,date,day,cron,event,meter,label,trigger complete, repeat,limit,inlimit,limit_path,zombie]\n"
- " change : [ variable,clock-type,clock-gain,event,meter,label,trigger,complete,repeat,limit-max,limit-value]\n"
- " set_flag and clear_flag:\n"
- " [ force_aborted | user_edit | task_aborted | edit_failed | ecfcmd_failed | no_script | killed | \n"
- " migrated | late | message | complete | queue_limit | task_waiting | locked | zombie ]\n"
- " string name : used to locate the attribute, when multiple attributes of the same type,\n"
- " optional for some.i.e. when changing, attributes like variable,meter,event,label,limits\n"
- " string value : Only used when 'changing' a attribute. provides a new value\n"
- " )\n\n"
- "Exceptions can be raised because:\n\n"
- "- absolute_node_path does not exist.\n"
- "- parsing fails\n"
- "\n"
- "The following describes the parameters in more detail::\n\n"
- " add variable variable_name variable_value\n"
- " add time format # when format is +hh:mm | hh:mm | hh:mm(start) hh:mm(finish) hh:mm(increment)\n"
- " add today format # when format is +hh:mm | hh:mm | hh:mm(start) hh:mm(finish) hh:mm(increment)\n"
- " add date format # when format dd.mm.yyyy, can use '*' to indicate any day,month, or year\n"
- " add day format # when format is one of [ sunday,monday,tuesday,wednesday,friday,saturday ]\n"
- " add zombie format # when format is one of <zombie-type>:<child>:<server-action>|<client-action>:<zombie-lifetime>\n"
- " # <zombie-type> := [ user | ecf | path ]\n"
- " # <child> := [ init, event, meter, label, wait, abort, complete ]\n"
- " # <server-action> := [ adopt | delete ]\n"
- " # <client-action> := [ fob | fail | block(default) ]\n"
- " # <zombie-lifetime>:= lifetime of zombie in the server\n"
- " # example\n"
- " # add zombie :label:fob:0 # fob all child label request, & remove zombie as soon as possible\n"
- "\n"
- " delete variable name # if name is empty will delete -all- variables on the node\n"
- " delete time name # To delete a specific time, enter the time in same format as show above,\n"
- " # or as specified in the defs file\n"
- " # an empty name will delete all time attributes on the node\n"
- " delete today name # To delete a specific today attribute, enter in same format as show above,\n"
- " # or as specified in the defs file.\n"
- " # an empty name will delete all today attributes on the node\n"
- " delete date name # To delete a specific date attribute, enter in same format as show above,\n"
- " # or as specified in the defs file\n"
- " # an empty name will delete all date attributes on the node\n"
- " delete day name # To delete a specific day attribute, enter in same format as show above,\n"
- " # or as specified in the defs file\n"
- " # an empty name will delete all day attributes on the node\n"
- " delete cron name # To delete a specific cron attribute, enter in same as specified in the defs file\n"
- " # an empty name will delete all cron attributes on the node\n"
- " delete event name # To delete a specific event, enter name or number\n"
- " # an empty name will delete all events on the node\n"
- " delete meter name # To delete a specific meter , enter the meter name\n"
- " # an empty name will delete all meter on the node \n"
- " delete label name # To delete a specific label , enter the label name\n"
- " # an empty name will delete all labels on the node\n"
- " delete limit name # To delete a specific limit , enter the limit name\n"
- " # an empty name will delete all limits on the node\n"
- " delete inlimit name # To delete a specific inlimit , enter the inlimit name\n"
- " # an empty name will delete all inlimits on the node\n"
- " delete limit_path limit_name limit_path # To delete a specific limit path\n"
- " delete trigger # A node can only have one trigger expression, hence the name is not required\n"
- " delete complete # A node can only have one complete expression, hence the name is not required\n"
- " delete repeat # A node can only have one repeat, hence the name is not required\n"
- "\n"
- " change variable name value # Find the specified variable, and set the new value.\n"
- " change clock_type name # The name must be one of 'hybrid' or 'real'.\n"
- " change clock_gain name # The gain must be convertible to an integer.\n"
- " change clock_sync name # Sync suite calendar with the computer.\n"
- " change event name(optional ) # if no name specified the event is set, otherwise name must be 'set' or 'clear'\n"
- " change meter name value # The meter value must be convertible to an integer, and between meter min-max range.\n"
- " change label name value # sets the label\n"
- " change trigger name # The name must be expression. returns an error if the expression does not parse\n"
- " change complete name # The name must be expression. returns an error if the expression does not parse\n"
- " change limit_max name value # Sets the max value of the limit. The value must be convertible to an integer\n"
- " change limit_value name value # Sets the consumed tokens to value.The value must be convertible to an integer\n"
- " change repeat value # If the repeat is a date, then the value must be a valid YMD ( ie. yyyymmdd)\n"
- " # and be convertible to an integer, additionally the value must be in range\n"
- " # of the repeat start and end dates. Like wise for repeat integer. For repeat\n"
- " # string and enum, the name must either be an integer, that is a valid index or\n"
- " # if it is a string, it must correspond to one of enum's or strings list\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.alter('/suite','change','trigger','b2 == complete')\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::force_state(){
-
- return
- "Force a node(s) to a given state\n\n"
- "When a :term:`task` is set to :term:`complete`, it may be automatically re-queued if it has\n"
- "multiple time :term:`dependencies`. In the specific case where a task has a single\n"
- "time dependency and we want to interactively set it to :term:`complete`\n"
- "a flag is set so that it is not automatically re-queued when set to complete.\n"
- "The flag is applied up the node hierarchy until reach a node with a :term:`repeat`\n"
- "or :term:`cron` attribute. This behaviour allow :term:`repeat` values to be incremented interactively.\n"
- "A :term:`repeat` attribute is incremented when all the child nodes are :term:`complete`\n"
- "in this case the child nodes are automatically re-queued\n::\n\n"
- " void force_state(\n"
- " string absolute_node_path: Path name to node. The path must begin with a leading '/'\n"
- " State::State state : [ unknown | complete | queued | submitted | active | aborted ]\n"
- " )\n"
- " void force_state(\n"
- " list paths : A list of absolute node paths. The paths must begin with a leading '/'\n"
- " State::State state : [ unknown | complete | queued | submitted | active | aborted ]\n"
- " )\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " # force a single node to complete\n"
- " ci.force_state('/s1/f1',State.complete)\n"
- "\n"
- " # force a list of nodes to complete\n"
- " paths = [ '/s1/t1', '/s1/t2', '/s1/f1/t1' ]\n"
- " ci.force_state(paths,State.complete)\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- "\nEffect::\n\n"
- " Lets see the effect of forcing complete on the following defs::\n\n"
- " suite s1\n"
- " task t1; time 10:00 # will complete straight away\n"
- " task t2; time 10:00 13:00 01:00 # will re-queue 3 times and complete on fourth \n\n"
- "In the last case (task t2) after each force complete, the next time slot is incremented.\n"
- "This can be seen by calling the Why command."
-
- ;
-}
-
-const char* ClientDoc::force_state_recursive(){
-
- return
- "Force node(s) to a given state recursively::\n\n"
- " void force_state_recursive(\n"
- " string absolute_node_path: Path name to node.The paths must begin with a leading '/'\n"
- " State::State state : [ unknown | complete | queued | submitted | active | aborted ]\n"
- " )\n"
- " void force_state_recursive(\n"
- " list paths : A list of absolute node paths.The paths must begin with a leading '/'\n"
- " State::State state : [ unknown | complete | queued | submitted | active | aborted ]\n"
- " )\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.force_state_recursive('/s1/f1',State.complete)\n"
- "\n"
- " # recursively force a list of nodes to complete\n"
- " paths = [ '/s1', '/s2', '/s1/f1/t1' ]\n"
- " ci.force_state_recursive(paths,State.complete)\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::force_event(){
-
- return
- "Set or clear a :term:`event`::\n\n"
- " void force_event(\n"
- " string absolute_node_path:event: Path name to node: < event name | number>\n"
- " The paths must begin with a leading '/'\n"
- " string signal : [ set | clear ]\n"
- " )\n"
- " void force_event(\n"
- " list paths : A list of absolute node paths. Each path must include a event name\n"
- " The paths must begin with a leading '/'\n"
- " string signal : [ set | clear ]\n"
- " )\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.force_event('/s1/f1:event_name','set')\n"
- "\n"
- " # Set or clear a event for a list of events\n"
- " paths = [ '/s1/t1:ev1', '/s2/t2:ev2' ]\n"
- " ci.force_event(paths,State.complete)\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::replace(){
- return
- "Replaces a :term:`node` in a :term:`suite definition` with the given path. The definition is in the :term:`ecflow_server`::\n\n"
- " void replace(\n"
- " string absolute_node_path: Path name to node in the client defs.\n"
- " This is also the node we want to replace in the server.\n"
- " string client_defs_file : File path to defs files, that provides the definition of the new node\n"
- " [(bool)parent=False] : create parent families or suite as needed,\n"
- " when absolute_node_path does not exist in the server\n"
- " [(bool)force=False] : check for zombies, if force = true, bypass checks\n"
- " )\n"
- "\n"
- " void replace(\n"
- " string absolute_node_path: Path name to node in the client defs.\n"
- " This is also the node we want to replace in the server.\n"
- " Defs client_defs : In memory client definition that provides the definition of the new node\n"
- " [(bool)parent=False] : create parent families or suite as needed,\n"
- " when absolute_node_path does not exist in the server\n"
- " [(bool)force=False] : check for zombies, force = true, bypass checks\n"
- " )\n"
- "\n"
- "Exceptions can be raised because:\n\n"
- "- The absolute_node_path does not exist in the provided definition\n"
- "- The provided client definition must be free of errors\n"
- "- If the third argument is not provided, then the absolute_node_path must exist in the server defs\n"
- "- replace will fail, if child task nodes are in :term:`active` / :term:`submitted` state\n\n"
- "After replace is done, we check trigger expressions. These are reported to standard output.\n"
- "It is up to the user to correct invalid trigger expressions, otherwise the tasks will *not* run.\n"
- "Please note, you can use check() to check trigger expression and limits in the server.\n\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.replace('/s1/f1','/tmp/defs.def')\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- "\n"
- " try:\n"
- " ci.replace('/s1',client_defs) # replace suite 's1' in the server, with 's1' in the client_defs\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::kill(){
- return
- "Kills the job associated with the :term:`node`.::\n\n"
- " void kill(\n"
- " list paths: List of paths. Paths must begin with a leading '/' character\n"
- " )\n"
- " void kill(\n"
- " string absolute_node_path: Path name to node to kill.\n"
- " )\n"
- "\n"
- "If a :term:`family` or :term:`suite` is selected, will kill hierarchically.\n"
- "Kill uses the ECF_KILL_CMD variable. After :term:`variable substitution` it is invoked as a command.\n"
- "The ECF_KILL_CMD variable should be written in such a way that the output is written to %ECF_JOB%.kill, i.e::\n\n"
- " kill -15 %ECF_RID% > %ECF_JOB%.kill 2>&1\n"
- " /home/ma/emos/bin/ecfkill %USER% %HOST% %ECF_RID% %ECF_JOB% > %ECF_JOB%.kill 2>&1\n\n"
- "\n"
- "Exceptions can be raised because:\n\n"
- "- The absolute_node_path does not exist in the server\n"
- "- ECF_KILL_CMD variable is not defined\n"
- "- :term:`variable substitution` fails\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.kill('/s1/f1')\n"
- " time.sleep(2)\n"
- " print ci.file('/s1/t1','kill') # request kill output\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::status(){
- return
- "Shows the status of a job associated with a :term:`task` ::\n\n"
- " void status(\n"
- " list paths: List of paths. Paths must begin with a leading '/' character\n"
- " )\n"
- " void status(\n"
- " string absolute_node_path\n"
- " )\n\n"
- "If a :term:`family` or :term:`suite` is selected, will invoke status command hierarchically.\n"
- "Status uses the ECF_STATUS_CMD variable. After :term:`variable substitution` it is invoked as a command.\n"
- "The command should be written in such a way that the output is written to %ECF_JOB%.stat, i.e::\n\n"
- " /home/ma/emos/bin/ecfstatus %USER% %HOST% %ECF_RID% %ECF_JOB% > %ECF_JOB%.stat 2>&1\n\n"
- "Exceptions can be raised because:\n\n"
- "- The absolute_node_path does not exist in the server\n"
- "- ECF_STATUS_CMD variable is not defined\n"
- "- :term:`variable substitution` fails\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.status('/s1/t1')\n"
- " time.sleep(2)\n"
- " print ci.file('/s1/t1','stats') # request status output\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::order(){
- return
- "Re-orders the :term:`node` s in the :term:`suite definition` held by the :term:`ecflow_server`\n\n"
- "It should be noted that in the absence of :term:`dependencies`,\n"
- "the order in which :term:`task` s are :term:`submitted`, depends on the order in the definition.\n"
- "This changes the order and hence affects the submission order::\n\n"
- " void order(\n"
- " string absolute_node_path: Path name to node.\n"
- " string order_type : Must be one of [ top | bottom | alpha | order | up | down ]\n"
- " )\n"
- " o top raises the node within its parent, so that it is first\n"
- " o bottom lowers the node within its parent, so that it is last\n"
- " o alpha Arranges for all the peers of selected note to be sorted alphabetically\n"
- " o order Arranges for all the peers of selected note to be sorted in reverse alphabet\n"
- " o up Moves the selected node up one place amongst its peers\n"
- " o down Moves the selected node down one place amongst its peers\n\n"
- "Exceptions can be raised because:\n\n"
- "- The absolute_node_path does not exist in the server\n"
- "- The order_type is not the right type\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.order('/s1/f1','top')\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::group(){
- return
- "Allows a series of commands to be executed in the :term:`ecflow_server`::\n\n"
- " void group(\n"
- " string cmds : a list of ';' separated commands \n"
- " )\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.group('get; show')\n"
- " ci.group('get; show state') # show node states and trigger abstract syntax trees\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::begin_suite(){
- return
- "Begin playing the chosen :term:`suite` s in the :term:`ecflow_server`\n"
- "Note: using the force option may cause :term:`zombie` s::\n\n"
- " void begin_suite\n"
- " string suite_name : begin playing the given suite\n"
- " [(bool)force=False] : bypass the checks\n"
- " )\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.begin_suite('/suite1') # begin playing suite '/suite1'\n"
- " ci.begin_suite('/suite1',True) # begin playing suite '/suite1' bypass any checks"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::begin_all(){
- return
- "Begin playing all the :term:`suite` s in the :term:`ecflow_server`\n"
- "Note: using the force option may cause :term:`zombie` s::\n\n"
- " void begin_all_suites(\n"
- " [(bool)force=False] : bypass the checks\n"
- " )\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.begin_all_suites() # begin playing all the suites\n"
- " ci.begin_all_suites(True) # begin playing all the suites, by passing checks\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::suspend(){
- return
- "Suspend :term:`job creation` / generation for the given :term:`node`::\n\n"
- " void suspend(\n"
- " list paths: List of paths. Paths must begin with a leading '/' character\n"
- " )\n"
- " void suspend(\n"
- " string absolute_node_path: Path name to node to suspend.\n"
- " )\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.suspend('/s1/f1/task1')\n"
- " paths = ['/s1/f1/t1','/s2/f1/t2']\n"
- " ci.suspend(paths)\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::resume(){
- return
- "Resume :term:`job creation` / generation for the given :term:`node`::\n\n"
- " void resume(\n"
- " list paths: List of paths. Paths must begin with a leading '/' character\n"
- " )\n"
- " void resume(\n"
- " string absolute_node_path: Path name to node to resume.\n"
- " )\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.resume('/s1/f1/task1')\n"
- " paths = ['/s1/f1/t1','/s2/f1/t2']\n"
- " ci.resume(paths)\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::job_gen(){
- return
- "Job submission for chosen Node *based* on :term:`dependencies`\n"
- "The :term:`ecflow_server` traverses the :term:`node` tree every 60 seconds, and if the dependencies are free\n"
- "does :term:`job creation` and submission. Sometimes the user may free time/date dependencies\n"
- "to avoid waiting for the server poll, this commands allows early job generation::\n\n"
- " void job_generation(\n"
- " string absolute_node_path: Path name for job generation to start from\n"
- " )\n"
- " If empty string specified generates for full definition.\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.job_generation('/s1') # generate jobs for suite '/s1 \n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::delete_node(){
- return
- "Delete the :term:`node` (s) specified.\n\n"
- "If a node is :term:`submitted` or :term:`active`, then a Exception will be raised.\n"
- "To force the deletion at the expense of :term:`zombie` creation, then set\n"
- "the force parameter to true::\n\n"
- " void delete(\n"
- " list paths : List of paths.\n"
- " [(bool)force=False] : If true delete even if in 'active' or 'submitted' states\n"
- " Which risks creating zombies.\n"
- " )\n"
- " void delete(\n"
- " string absolute_node_path: Path name of node to delete.\n"
- " [(bool)force=False] : If true delete even if in 'active' or 'submitted' states\n"
- " )\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.delete('/s1/f1/task1')\n"
- "\n"
- " paths = ['/s1/f1/t1','/s2/f1/t2']\n"
- " ci.delete(paths) # delete all tasks specified in the paths\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* ClientDoc::delete_all(){
- return
- "Delete all the :term:`node` s held in the :term:`ecflow_server`.\n\n"
- "The :term:`suite definition` in the server will be empty, after this call. **Use with care**\n"
- "If a node is :term:`submitted` or :term:`active`, then a Exception will be raised.\n"
- "To force the deletion at the expense of :term:`zombie` creation, then set\n"
- "the force parameter to true::\n\n"
- " void delete_all(\n"
- " [(bool)force=False] : If true delete even if in 'active' or 'submitted' states\n"
- " Which risks creating zombies.\n"
- " )\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.delete_all()\n"
- " ci.get_server_defs()\n"
- " except RuntimeError, e:\n"
- " print str(e); # expect failure since all nodes deleted"
- ;
-}
-
-const char* ClientDoc::check()
-{
- return
- "Check :term:`trigger` and :term:`complete expression` s and :term:`limit` s\n\n"
- "The :term:`ecflow_server` does not store :term:`extern` s. Hence all unresolved references\n"
- "are reported as errors.\n"
- "Returns a non empty string for any errors or warning::\n\n"
- " string check(\n"
- " list paths # List of paths.\n"
- " )\n"
- " string check(\n"
- " string absolute_node_path\n"
- " )\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " print ci.check('/suite1')\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
diff --git a/ecflow_4_0_7/Pyext/src/ClientDoc.hpp b/ecflow_4_0_7/Pyext/src/ClientDoc.hpp
deleted file mode 100644
index 29224ee..0000000
--- a/ecflow_4_0_7/Pyext/src/ClientDoc.hpp
+++ /dev/null
@@ -1,92 +0,0 @@
-#ifndef CLIENT_DOC_HPP_
-#define CLIENT_DOC_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #32 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/noncopyable.hpp>
-
-// ===========================================================================
-// IMPORTANT: These appear as python doc strings.
-// Additionally they are auto documented using sphinx-poco
-// Hence the doc strings use reStructuredText markup.
-// ===========================================================================
-class ClientDoc : private boost::noncopyable {
-public:
- static const char* class_client();
- static const char* set_host_port();
- static const char* set_retry_connection_period();
- static const char* set_connection_attempts();
- static const char* get_defs();
-
- static const char* get_log();
- static const char* new_log();
- static const char* clear_log();
- static const char* flush_log();
- static const char* log_msg();
- static const char* restart_server();
- static const char* halt_server();
- static const char* shutdown_server();
- static const char* terminate_server();
- static const char* wait_for_server_reply();
- static const char* load_defs();
- static const char* load();
- static const char* get_server_defs();
- static const char* sync();
- static const char* in_sync();
- static const char* news();
- static const char* changed_node_paths();
- static const char* checkpt();
- static const char* restore_from_checkpt();
- static const char* reload_wl_file();
- static const char* run();
- static const char* requeue();
- static const char* free_date_dep();
- static const char* free_trigger_dep();
- static const char* free_time_dep();
- static const char* free_all_dep();
- static const char* ping();
- static const char* stats();
- static const char* stats_reset();
- static const char* suites();
- static const char* ch_register();
- static const char* ch_suites();
- static const char* ch_drop();
- static const char* ch_drop_user();
- static const char* ch_add();
- static const char* ch_remove();
- static const char* ch_auto_add();
- static const char* get_file();
- static const char* plug();
- static const char* alter();
- static const char* force_state();
- static const char* force_state_recursive();
- static const char* force_event();
- static const char* replace();
- static const char* kill();
- static const char* check();
- static const char* status();
- static const char* order();
- static const char* group();
- static const char* begin_suite();
- static const char* begin_all();
- static const char* suspend();
- static const char* resume();
- static const char* job_gen();
- static const char* delete_node();
- static const char* delete_all();
-
-private:
- ClientDoc(){}
-};
-#endif
diff --git a/ecflow_4_0_7/Pyext/src/DefsDoc.cpp b/ecflow_4_0_7/Pyext/src/DefsDoc.cpp
deleted file mode 100644
index 7d6d718..0000000
--- a/ecflow_4_0_7/Pyext/src/DefsDoc.cpp
+++ /dev/null
@@ -1,800 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #73 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : This class is used as a helper class
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "DefsDoc.hpp"
-
-const char* DefsDoc::abs_node_path_doc()
-{
- return "returns a string which holds the path to the node\n\n";
-}
-
-const char* DefsDoc::part_expression_doc()
-{
- return
- "PartExpression holds part of a :term:`trigger` or :term:`complete expression`.\n\n"
- "Expressions can contain references to :term:`event`, :term:`meter` s, user variables,\n"
- ":term:`repeat` variables and generated variables. The part expression allows us\n"
- "to split a large trigger or complete expression into smaller ones\n"
- "\nConstructor::\n\n"
- " PartExpression(exp )\n"
- " string exp: This represents the *first* expression\n\n"
- " PartExpression(exp, bool and_expr)\n"
- " string exp: This represents the expression\n"
- " bool and_exp: If true the expression is to be anded, with a previously added expression\n"
- " If false the expression is to be 'ored', with a previously added expression\n"
- "\nUsage:\n"
- "To add simple expression this class can be by-passed, i.e. can use::\n\n"
- " task = Task('t1')\n"
- " task.add_trigger( 't2 == active' )\n"
- " task.add_complete( 't2 == complete' )\n\n"
- "To add large triggers and complete expression::\n\n"
- " exp1 = PartExpression('t1 == complete')\n # a simple expression can be added as a string\n"
- " ....\n"
- " task2.add_part_trigger( PartExpression(\"t1 == complete or t4 == complete\") ) \n"
- " task2.add_part_trigger( PartExpression(\"t5 == active\",True) ) # anded with first expression\n"
- " task2.add_part_trigger( PartExpression(\"t7 == active\",False) ) # or'ed with last expression added\n\n"
- "The trigger for task2 is equivalent to\n"
- "'t1 == complete or t4 == complete and t5 == active or t7 == active'"
- ;
-}
-
-const char* DefsDoc::expression_doc()
-{
- return
- "Expression holds :term:`trigger` or :term:`complete expression`.\n\n"
- "Expressions can contain references to events, meters, user variables,repeat variables and generated variables.\n"
- "Expressions hold a list of part expressions. This allows us to split a large trigger or complete\n"
- "expression into smaller ones.\n"
- "\nConstructor::\n\n"
- " Expression( expression )\n"
- " string expression : This typically represents the complete expression\n"
- " however part expression can still be added\n"
- " Expression( part )\n"
- " PartExpression part: The first part expression should have no 'and/or' set\n"
- "\nUsage:\n"
- "To add simple expression this class can be by passed, i.e. can use::\n\n"
- " task = Task('t1')\n"
- " task.add_trigger( 't2 == active' )\n"
- " task.add_complete( 't2 == complete' )\n"
- "\n"
- " task = Task('t2')\n"
- " task.add_trigger( 't1 == active' )\n"
- " task.add_part_trigger( 't3 == active', True)\n\n"
- "To store and add large expressions use a Expression with PartExpression::\n\n"
- " big_expr = Expression( PartExpression(\"t1 == complete or t4 == complete\") )\n"
- " big_expr.add( PartExpression(\"t5 == active\",True) )\n"
- " big_expr.add( PartExpression(\"t7 == active\",False) )\n"
- " task.add_trigger( big_expr)\n\n"
- "In the example above the trigger for task is equivalent to\n"
- "'t1 == complete or t4 == complete and t5 == active or t7 == active'\n\n"
- "::\n\n"
- " big_expr2 = Expression('t0 == complete'))\n"
- " big_expr2.add( PartExpression(\"t1 == complete or t4 == complete\",True) )\n"
- " big_expr2.add( PartExpression(\"t5 == active\",False) )\n"
- " task2.add_trigger( big_expr2)\n\n"
- "Here the trigger for task2 is equivalent to\n"
- "'t0 == complete and t1 == complete or t4 == complete or t5 == active'"
- ;
-}
-
-const char* DefsDoc::add_trigger_doc()
-{
- return
- "Add a :term:`trigger` or :term:`complete expression`.\n\n"
- "This defines a dependency for a :term:`node`.\n"
- "There can only be one :term:`trigger` or :term:`complete expression` dependency per node.\n"
- "A :term:`node` with a trigger can only be activated when the trigger has expired.\n"
- "A trigger holds a node as long as the expression returns false.\n"
- "\nException:\n\n"
- "- Will throw RuntimeError if multiple trigger or complete expression are added\n"
- "- Will throw RuntimeError if first expression is added as 'AND' or 'OR' expression\n"
- " Like wise second and subsequent expression must have 'AND' or 'OR' booleans set\n"
- "\nUsage:\n\n"
- "Note we can not make multiple add_trigger(..) calls on the same :term:`task`!\n"
- "to add a simple trigger::\n\n"
- " task1.add_trigger( \"t2 == active\" )\n"
- " task2.add_trigger( \"t1 == complete or t4 == complete\" )\n"
- " task3.add_trigger( \"t5 == active\" )\n"
- "\n"
- "Long expression can be broken up using add_part_trigger::\n\n"
- " task2.add_part_trigger( \"t1 == complete or t4 == complete\")\n"
- " task2.add_part_trigger( \"t5 == active\",True) # True means AND\n"
- " task2.add_part_trigger( \"t7 == active\",False) # False means OR\n\n"
- "The trigger for task2 is equivalent to:\n"
- "'t1 == complete or t4 == complete and t5 == active or t7 == active'"
- ;
-}
-
-const char* DefsDoc::add_variable_doc()
-{
- return
- "Adds a name value :term:`variable`.\n\n"
- "This defines a variable for use in :term:`variable substitution` in a :term:`ecf script` file.\n"
- "There can be any number of variables. The variables are names inside a pair of\n"
- "'%' characters in an :term:`ecf script`. The name are case sensitive.\n"
- "Special character in the value, must be placed inside single quotes if misinterpretation\n"
- "is to be avoided.\n"
- "The value of the variable replaces the variable name in the :term:`ecf script` at :term:`job creation` time.\n"
- "The variable names for any given node must be unique. If duplicates are added then the\n"
- "the last value added is kept.\n"
- "\nException:\n\n"
- "- Writes warning to standard output, if a duplicate variable name is added\n"
- "\nUsage::\n\n"
- " task.add_variable( Variable(\"ECF_HOME\",\"/tmp/\"))\n"
- " task.add_variable( \"TMPDIR\",\"/tmp/\")\n"
- " task.add_variable( \"COUNT\",2)\n"
- " a_dict = { \"name\":\"value\", \"name2\":\"value2\", \"name3\":\"value3\" }\n"
- " task.add_variable(a_dict)\n"
- ;
-}
-
-const char* DefsDoc::add_label_doc()
-{
- return
- "Adds a :term:`label` to a :term:`node`.\n\n"
- "Labels can be updated from the jobs files, via :term:`child command`\n"
- "\nException:\n\n"
- "- Throws RuntimeError if a duplicate label name is added\n"
- "\nUsage::\n\n"
- " task.add_label( Label(\"TEA\",\"/me/\"))\n"
- " task.add_label( \"Joe\",\"/me/\")\n\n"
- "The corresponding child command in the .ecf script file might be::\n"
- " ecflow_client --label TEA time\n"
- " ecflow_client --label Joe ninety\n"
- ;
-}
-
-const char* DefsDoc::add_limit_doc()
-{
- return
- "Adds a :term:`limit` to a :term:`node` for simple load management.\n\n"
- "Multiple limits can be added, however the limit name must be unique.\n"
- "For a node to be in a limit, a :term:`inlimit` must be used.\n"
- "\nException:\n\n"
- "- Throws RuntimeError if a duplicate limit name is added\n"
- "\nUsage::\n\n"
- " family.add_limit( Limit(\"load\",12) )\n"
- " family.add_limit( \"load\",12 )\n"
- ;
-}
-
-const char* DefsDoc::add_inlimit_doc()
-{
- return
- "Adds a :term:`inlimit` to a :term:`node`.\n\n"
- "InLimit reference a :term:`limit`/:py:class:`ecflow.Limit`. Duplicate InLimits are not allowed\n"
- "\nException:\n\n"
- "- Throws RuntimeError if a duplicate is added\n"
- "\nUsage::\n\n"
- " task2.add_inlimit( InLimit(\"limitName\",\"/s1/f1\",2) )\n"
- " task2.add_inlimit( \"limitName\",\"/s1/f1\",2 )\n"
- ;
-}
-
-const char* DefsDoc::suite_doc()
-{
- return
- "A :term:`suite` is a collection of Families,Tasks,Variables, :term:`repeat` and :term:`clock` definitions\n\n"
- "Suite is the only node that can be started using the begin API.\n"
- "There are two ways of adding a suite, see example below and :py:class:`ecflow.Defs.add_suite`\n"
- "\nConstructor::\n\n"
- " Suite(name)\n"
- " string name : The Suite name. name must consist of alpha numeric characters or\n"
- " underscore or dot. The first character can not be a dot, as this\n"
- " will interfere with trigger expressions. Case is significant\n"
- "\nException:\n\n"
- "- Throws a RuntimeError if the name is not valid\n"
- "- Throws a RuntimeError if duplicate suite names added\n"
- "\nUsage::\n\n"
- " defs = Defs(\"new.def\") # create a defs\n"
- " suite = Suite(\"suite_1\") # create a suite\n"
- " defs.add_suite(suite) # add suite to definition\n"
- " suite2 = defs.add_suite(\"s2\") # create a suite and add it to the defs\n"
- ;
-}
-
-const char* DefsDoc::family_doc()
-{
- return
- "Create a :term:`family` :term:`node`.A Family node lives inside a :term:`suite` or another :term:`family`\n\n"
- "A family is used to collect :term:`task` s together or to group other families.\n"
- "Typically you place tasks that are related to each other inside the same family\n"
- "analogous to the way you create directories to contain related files.\n"
- "There are two ways of adding a family, see example below.\n"
- "\nConstructor::\n\n"
- " Family(name)\n"
- " string name : The Family name. name must consist of alpha numeric characters or\n"
- " underscore or dot. The first character can not be dot, as this\n"
- " will interfere with trigger expressions. Case is significant\n"
- "\nException:\n\n"
- "- Throws a RuntimeError if the name is not valid\n"
- "- Throws a RuntimeError if a duplicate family is added\n"
- "\nUsage::\n\n"
- " suite = Suite(\"suite_1\") # create a suite\n"
- " family = Family(\"family_1\") # create a family\n"
- " suite.add_family(family) # add created family to a suite\n"
- " f2 = suite.add_family(\"f2\") # create a family r2 and add to suite\n"
- ;
-}
-
-const char* DefsDoc::task_doc()
-{
- return
- "Creates a :term:`task` :term:`node`.Task is a child of a :term:`suite` or :term:`family` node.\n\n"
- "Multiple Tasks can be added, however the task names must be unique for a given parent.\n"
- "Note case is significant. Only Tasks can be submitted. A job inside a Task :term:`ecf script` (i.e .ecf file)\n"
- "should generally be re-entrant since a Task may be automatically submitted more than once if it aborts.\n"
- "There are two ways of adding a task, see example below\n"
- "\nConstructor::\n\n"
- " Task(name)\n"
- " string name : The Task name.Name must consist of alpha numeric characters or\n"
- " underscore or dot. First character can not be a dot.\n"
- " Case is significant\n"
- "\nException:\n\n"
- "- Throws a RuntimeError if the name is not valid\n"
- "- Throws a RuntimeError if a duplicate Task is added\n"
- "\nUsage::\n\n"
- " task = Task(\"t1\") # create a task\n"
- " family.add_task(task) # add to the family\n"
- " t2 = family.add_task(\"t2\") # create a task t2 and add to the family\n\n"
- ;
-}
-
-const char* DefsDoc::alias_doc()
-{
- return
- "A Aliases is create by the GUI or via edit_script command\n\n"
- "Aliases provide a mechanism to edit/test task scripts without effecting the suite\n"
- "The Aliases parent is always a Task.Multiple Alias can be added\n"
- ;
-}
-
-const char* DefsDoc::add_suite_doc()
-{
- return
- "Add a :term:`suite` :term:`node`. See :py:class:`ecflow.Suite`\n\n"
- "Only one suite should be added for ease of maintenance. If a new suite is added\n"
- "which matches the name of an existing suite, then an exception is thrown.\n"
- "\nException:\n\n"
- "- Throws RuntimeError is the suite name is not valid\n"
- "- Throws RuntimeError if duplicate suite is added\n"
- "\nUsage::\n\n"
- " Defs defs(\"file.def\" # create a defs)\n"
- " suite = Suite(\"suite\") # create a Suite \n"
- " defs.add_suite(suite) # add suite to defs\n"
- " s2 = defs.add_suite(\"s2\") # create a suite and add to defs\n"
- ;
-}
-
-const char* DefsDoc::add_extern_doc()
-{
- return
- ":term:`extern` refer to nodes that have not yet been defined typically due to cross suite :term:`dependencies`\n\n"
- ":term:`trigger` and :term:`complete expression` s may refer to paths, and variables in other suites, that have not been\n"
- "loaded yet. The references to node paths and variable must exist, or exist as externs\n"
- "Externs can be added manually or automatically.\n\n"
- "Manual Method::\n\n"
- " void add_extern(string nodePath )\n"
- "\nUsage::\n\n"
- " defs = Defs(\"file.def\")\n"
- " ....\n"
- " defs.add_extern('/temp/bill:event_name')\n"
- " defs.add_extern('/temp/bill:meter_name')\n"
- " defs.add_extern('/temp/bill:repeat_name')\n"
- " defs.add_extern('/temp/bill:edit_name')\n"
- " defs.add_extern('/temp/bill')\n"
- "\n"
- "Automatic Method:\n"
- " This will scan all trigger and complete expressions, looking for paths and variables\n"
- " that have not been defined. The added benefit of this approach is that duplicates will not\n"
- " be added. It is the user's responsibility to check that extern's are eventually defined\n"
- " otherwise trigger expression will not evaluate correctly\n\n"
- "::\n\n"
- " void auto_add_externs(bool remove_existing_externs_first )\n"
- "\nUsage::\n\n"
- " defs = Defs(\"file.def\")\n"
- " ...\n"
- " defs.auto_add_externs(True) # remove existing extern first.\n"
- ;
-}
-
-
-const char* DefsDoc::node_doc()
-{
- return
- "A Node class is the abstract base class for Suite, Family and Task\n\n"
- "Every Node instance has a name, and a path relative to a suite"
- ;
-}
-
-const char* DefsDoc::node_container_doc()
-{
- return
- "NodeContainer is the abstract base class for a Suite and Family\n\n"
- "A NodeContainer can have Families and Tasks as children"
- ;
-}
-
-const char* DefsDoc::submittable_doc()
-{
- return
- "Submittable is the abstract base class for a Task and Alias\n\n"
- "It provides a process id, password and try number"
- ;
-}
-
-const char* DefsDoc::add_family_doc()
-{
- return
- "Add a :term:`family`. See :py:class:`ecflow.Family`.\n\n"
- "Multiple families can be added. However family names must be unique.\n"
- "for a given parent. Families can be hierarchical.\n"
- "\nException:\n\n"
- "- Throws RuntimeError if a duplicate is added\n"
- "\nUsage::\n\n"
- " suite = Suite(\"suite\") # create a suite\n"
- " f1 = Family(\"f1\") # create a family\n"
- " suite.add_family(f1) # add family to suite\n"
- " f2 = suite.add_family(\"f2\") # create a family and add to suite\n"
- ;
-}
-
-const char* DefsDoc::add_task_doc()
-{
- return
- "Add a :term:`task`. See :py:class:`ecflow.Task`\n\n"
- "Multiple Tasks can be added. However Task names must be unique,\n"
- "for a given parent. Task can be added to Familiy's or Suites.\n"
- "\nException:\n\n"
- "- Throws RuntimeError if a duplicate is added\n"
- "\nUsage::\n\n"
- " f1 = Family(\"f1\") # create a family\n"
- " t1 = Task(\"t1\") # create a task\n"
- " f1.add_task(t1) # add task to family\n"
- " t2 = f1.add_task(\"t2\") # create task 't2' and add to family"
- ;
-}
-
-
-const char* DefsDoc::add_definition_doc()
-{
- return
- "The Defs class holds the :term:`suite definition` structure.\n\n"
- "It contains all the suites and hence acts like the root for suite node tree hierarchy.\n"
- "The definition can be kept as python code, alternatively it can be saved as a flat\n"
- "ASCII definition file.\n"
- "If a definition is read in from disk, it will by default, check the :term:`trigger` expressions.\n"
- "If however the definition is created in python, then checking should be done explicitly.\n"
- "The Defs class take one argument which represents the file name\n\n"
- "Example::\n\n"
- " defs = Defs() # create an empty defs\n"
- " suite = defs.add_suite(\"s1\")\n"
- " family = suite.add_family(\"f1\")\n"
- " for i in [ \"_1\", \"_2\", \"_3\" ]: family.add_task( \"t\" + i )\n"
- " defs.save_as_defs('filename.def') # save defs into file\n"
- "\n"
- "Create a Defs from an existing file on disk.\n"
- "\n"
- " defs = Defs('filename.def') # Will open and parse the file and create the Definition\n"
- " print defs\n"
- ;
-}
-
-const char* DefsDoc::add_event_doc()
-{
- return
- "Add a :term:`event`. See :py:class:`ecflow.Event`\n"
- "Events can be referenced in :term:`trigger` and :term:`complete expression` s\n\n"
- "\nException:\n\n"
- "- Throws RuntimeError if a duplicate is added\n"
- "\nUsage::\n\n"
- " t1 = Task(\"t1\")\n"
- " t1.add_event( Event(10) )\n"
- " t1.add_event( Event(11,\"Eventname\") )\n"
- " t1.add_event( 12 )\n"
- " t1.add_event( 13, \"name\")\n"
- " t1.add_event(\"flag\")\n\n"
- "To reference in a trigger::\n\n"
- " t2 = Task(\"t2\")\n"
- " t2.add_trigger('t1:flag == set')\n"
- ;
-}
-
-const char* DefsDoc::add_meter_doc()
-{
- return
- "Add a :term:`meter`. See :py:class:`ecflow.Meter`\n"
- "Meters can be referenced in :term:`trigger` and :term:`complete expression` s\n\n"
- "\nException:\n\n"
- "- Throws RuntimeError if a duplicate is added\n"
- "\nUsage::\n\n"
- " t1 = Task(\"t1\")\n"
- " t1.add_meter( Meter(\"metername\",0,100,50) )\n"
- " t1.add_meter( \"meter\",0,200)\n\n"
- "To reference in a trigger::\n\n"
- " t2 = Task(\"t2\")\n"
- " t2.add_trigger('t1:meter >= 10')\n"
- ;
-}
-
-const char* DefsDoc::add_date_doc()
-{
- return
- "Add a :term:`date` time dependency\n\n"
- "A value of zero for day,month,year means every day, every month, every year\n"
- "\nException:\n\n"
- "- Throws RuntimeError if an invalid date is added\n"
- "\nUsage::\n\n"
- " t1 = Task(\"t1\")\n"
- " t1.add_date( Date(1,1,2010) ) # day,month,year\n"
- " t1.add_date( 2,1,2010) # day,month,year\n"
- " t1.add_date( 1,0,0) # day,month,year, the first of each month for every year\n"
- ;
-}
-
-const char* DefsDoc::add_day_doc()
-{
- return
- "Add a :term:`day` time dependency\n\n"
- "\nUsage::\n\n"
- " t1 = Task(\"t1\")\n"
- " t1.add_day( Day(Days.sunday) ) \n"
- " t1.add_day( Days.monday)\n"
- " t1.add_day( \"tuesday\")\n"
- ;
-}
-
-const char* DefsDoc::add_today_doc()
-{
- return
- "Add a :term:`today` time dependency\n\n"
- "\nUsage::\n\n"
- " t1 = Task(\"t1\")\n"
- " t1.add_today( \"00:30\" )\n"
- " t1.add_today( \"+00:30\" )\n"
- " t1.add_today( \"+00:30 20:00 01:00\" )\n"
- " t1.add_today( Today( 0,10 )) # hour,min,relative =false\n"
- " t1.add_today( Today( 0,12,True )) # hour,min,relative\n"
- " t1.add_today( Today(TimeSlot(20,20),False))\n"
- " t1.add_today( 0,1 )) # hour,min,relative=false\n"
- " t1.add_today( 0,3,False )) # hour,min,relative=false\n"
- " start = TimeSlot(0,0)\n"
- " finish = TimeSlot(23,0)\n"
- " incr = TimeSlot(0,30)\n"
- " ts = TimeSeries( start, finish, incr, True)\n"
- " task2.add_today( Today(ts) )\n"
- ;
-}
-
-const char* DefsDoc::add_time_doc()
-{
- return
- "Add a :term:`time` dependency\n\n"
- "\nUsage::\n\n"
- " t1 = Task(\"t1\")\n"
- " t1.add_time( \"00:30\" )\n"
- " t1.add_time( \"+00:30\" )\n"
- " t1.add_time( \"+00:30 20:00 01:00\" )\n"
- " t1.add_time( Time( 0,10 )) # hour,min,relative =false\n"
- " t1.add_time( Time( 0,12,True )) # hour,min,relative\n"
- " t1.add_time( Time(TimeSlot(20,20),False))\n"
- " t1.add_time( 0,1 )) # hour,min,relative=false\n"
- " t1.add_time( 0,3,False )) # hour,min,relative=false\n"
- " start = TimeSlot(0,0)\n"
- " finish = TimeSlot(23,0)\n"
- " incr = TimeSlot(0,30)\n"
- " ts = TimeSeries( start, finish, incr, True)\n"
- " task2.add_time( Time(ts) )\n"
- ;
-}
-
-const char* DefsDoc::add_cron_doc()
-{
- return
- "Add a :term:`cron` time dependency\n\n"
- "\nUsage::\n\n"
- " start = TimeSlot(0,0)\n"
- " finish = TimeSlot(23,0)\n"
- " incr = TimeSlot(0,30)\n"
- " time_series = TimeSeries( start, finish, incr, True)\n"
- " cron = Cron()\n"
- " cron.set_week_days( [0,1,2,3,4,5,6] )\n"
- " cron.set_days_of_month( [1,2,3,4,5,6] )\n"
- " cron.set_months( [1,2,3,4,5,6] )\n"
- " cron.set_time_series( time_series )\n"
- " t1 = Task(\"t1\")\n"
- " t1.add_cron( cron )\n"
- ;
-}
-
-const char* DefsDoc::add_late_doc()
-{
- return
- "Add a :term:`late` attribute\n\n"
- "\nException:\n\n"
- "- Throws a RuntimeError if more than one late is added\n"
- "\nUsage::\n\n"
- " late = Late()\n"
- " late.submitted( 20,10 ) # hour,minute\n"
- " late.active( 20,10 ) # hour,minute\n"
- " late.complete( 20,10,True) # hour,minute,relative\n"
- " t1 = Task(\"t1\")\n"
- " t1.add_late( late )\n"
- ;
-}
-
-const char* DefsDoc::add_autocancel_doc()
-{
- return
- "Add a :term:`autocancel` attribute.\n\n"
- "This will delete the node on completion. The deletion may be delayed by\n"
- "an amount of time in hours and minutes or expressed as days\n"
- "Node deletion is not immediate. The nodes are checked once a minute\n"
- "and expired auto cancel nodes are deleted\n"
- "A node may only have one auto cancel attribute\n"
- "\nException:\n\n"
- "- Throws a RuntimeError if more than one auto cancel is added\n"
- "\nUsage::\n\n"
- " t1 = Task('t1')\n"
- " t1.add_autocancel( Autocancel(20,10,False) ) # hour,min, relative\n"
- " t2 = Task('t2')\n"
- " t2.add_autocancel( 3 ) # 3 days \n"
- " t3 = Task('t3')\n"
- " t3.add_autocancel( 20,10,True ) # hour,minutes,relative \n"
- " t4 = Task('t4')\n"
- " t4.add_autocancel( TimeSlot(20,10),True ) # hour,minutes,relative \n"
- ;
-}
-
-const char* DefsDoc::add_verify_doc()
-{
- return
- "Add a Verify attribute.\n\n"
- "For DEBUG/test used to assert that a particular state was reached."
- ;
-}
-
-const char* DefsDoc::add_repeat_date_doc()
-{
- return
- "Add a RepeatDate attribute.\n\n"
- "A node can only have one repeat\n"
- "\nException:\n\n"
- "- Throws a RuntimeError if more than one repeat is added\n"
- "\nUsage::\n\n"
- " t1 = Task('t1')\n"
- " t1.add_repeat( RepeatDate(\"testDate\",20100111,20100115) )\n"
- ;
-}
-
-const char* DefsDoc::add_repeat_integer_doc()
-{
- return
- "Add a RepeatInteger attribute.\n\n"
- "A node can only have one :term:`repeat`\n"
- "\nException:\n\n"
- "- Throws a RuntimeError if more than one repeat is added\n"
- "\nUsage::\n\n"
- " t1 = Task('t1')\n"
- " t1.add_repeat( RepeatInteger(\"testInteger\",0,100,2) )\n"
- ;
-}
-
-const char* DefsDoc::add_repeat_string_doc()
-{
- return
- "Add a RepeatString attribute.\n\n"
- "A node can only have one :term:`repeat`\n"
- "\nException:\n\n"
- "- Throws a RuntimeError if more than one repeat is added\n"
- "\nUsage::\n\n"
- " t1 = Task('t1')\n"
- " t1.add_repeat( RepeatString(\"test_string\",['a', 'b', 'c' ] ) )\n"
- ;
-}
-
-const char* DefsDoc::add_repeat_enumerated_doc()
-{
- return
- "Add a RepeatEnumerated attribute.\n\n"
- "A node can only have one :term:`repeat`\n"
- "\nException:\n\n"
- "- Throws a RuntimeError if more than one repeat is added\n"
- "\nUsage::\n\n"
- " t1 = Task('t1')\n"
- " t1.add_repeat( RepeatEnumerated(\"test_string\", ['red', 'green', 'blue' ] ) )\n"
- ;
-}
-
-const char* DefsDoc::add_repeat_day_doc()
-{
- return
- "Add a RepeatDay attribute.\n\n"
- "A node can only have one :term:`repeat`\n"
- "\nException:\n\n"
- "- Throws a RuntimeError if more than one repeat is added\n"
- ;
-}
-
-const char* DefsDoc::add_defstatus_doc()
-{
- return
- "Set the default status( :term:`defstatus` ) of node at begin or re queue\n\n"
- "A :term:`defstatus` is useful in preventing suites from running automatically\n"
- "once begun, or in setting Task's complete so they can be run selectively\n"
- "\nUsage::\n\n"
- " t1 = Task('t1')\n"
- " t1.add_defstatus( DState.suspended )\n"
- ;
-}
-
-const char* DefsDoc::jobgenctrl_doc()
-{
- return
- "The class JobCreationCtrl is used in :term:`job creation` checking\n\n"
- "Constructor::\n\n"
- " JobCreationCtrl()\n\n"
- "\nUsage::\n\n"
- " defs = Defs('my.def') # specify the definition we want to check, load into memory\n"
- " job_ctrl = JobCreationCtrl()\n"
- " job_ctrl.set_node_path('/suite/to_check') # will hierarchically check job creation under this node\n"
- " defs.check_job_creation(job_ctrl) # job files generated to ECF_JOB\n"
- " print job_ctrl.get_error_msg() # report any errors in job generation\n"
- "\n"
- " job_ctrl = JobCreationCtrl() # no set_node_path() hence check job creation for all tasks\n"
- " job_ctrl.set_dir_for_job_creation(tmp) # generate jobs file under this directory\n"
- " defs.check_job_creation(job_ctrl)\n"
- " print job_ctrl.get_error_msg()\n"
- "\n"
- " job_ctrl = JobCreationCtrl() # no set_node_path() hence check job creation for all tasks\n"
- " job_ctrl.generate_temp_dir() # automatically generate directory for job file\n"
- " defs.check_job_creation(job_ctrl)\n"
- " print job_ctrl.get_error_msg()\n"
- ;
-}
-
-const char* DefsDoc::check_job_creation_doc()
-{
- return
- "Check :term:`job creation` .\n\n"
- "Will check the following:\n\n"
- "- :term:`ecf script` files and includes files can be located\n"
- "- recursive includes\n"
- "- manual and comments :term:`pre-processing`\n"
- "- :term:`variable substitution`\n\n"
- "Some :term:`task` s are dummy tasks have no associated :term:`ecf script` file.\n"
- "To disable error message for these tasks please add a variable called ECF_DUMMY_TASK to them.\n"
- "Checking is done in conjunction with the class :py:class:`ecflow.JobCreationCtrl`.\n"
- "If no node path is set on class JobCreationCtrl then all tasks are checked.\n"
- "In the case where we want to check all tasks, use the convenience function that take no arguments.\n"
- "\nUsage::\n\n"
- " defs = Defs('my.def') # specify the defs we want to check, load into memory\n"
- " ...\n"
- " print defs.check_job_creation() # Check job generation for all tasks\n"
- " ...\n"
- " job_ctrl = JobCreationCtrl()\n"
- " defs.check_job_creation(job_ctrl) # Check job generation for all tasks, same as above\n"
- " print job_ctrl.get_error_msg()\n"
- " ...\n"
- " job_ctrl = JobCreationCtrl()\n"
- " job_ctrl.set_node_path('/suite/to_check') # will hierarchically check job creation under this node\n"
- " defs.check_job_creation(job_ctrl) # job files generated to ECF_JOB\n"
- " print job_ctrl.get_error_msg()\n"
- " ...\n"
- " job_ctrl = JobCreationCtrl() # no set_node_path() hence check job creation for all tasks\n"
- " job_ctrl.set_dir_for_job_creation(tmp) # generate jobs file under this directory\n"
- " defs.check_job_creation(job_ctrl)\n"
- " print job_ctrl.get_error_msg()\n"
- " ...\n"
- " job_ctrl = JobCreationCtrl() # no set_node_path() hence check job creation for all tasks\n"
- " job_ctrl.generate_temp_dir() # automatically generate directory for job file\n"
- " defs.check_job_creation(job_ctrl)\n"
- " print job_ctrl.get_error_msg()\n"
- ;
-}
-
-const char* DefsDoc::generate_scripts_doc()
-{
- return
- "Automatically generate template :term:`ecf script` s for this definition\n"
- "Will automatically add :term:`child command` s for :term:`event`, :term:`meter` and :term:`label` s.\n"
- "This allows the definition to be refined with out worrying about the scripts.\n"
- "However it should be noted that, this will create a lot of *duplicated* script contents\n"
- "i.e in the absence of :term:`event` s, :term:`meter` s and :term:`label` s, most of generated :term:`ecf script` files will\n"
- "be the same. Hence should only be used an aid to debugging the definition.\n"
- "It uses the contents of the definition to parameterise what gets\n"
- "generated, and the location of the files. Will throw Exceptions for errors.\n"
- "\nRequires:\n\n"
- "- ECF_HOME: specified and accessible for all Tasks, otherwise RuntimeError is raised\n"
- "- ECF_INCLUDE: specifies location for head.h and tail.h includes, will use angle brackets,\n"
- " i.e %include <head.h>, if the head.h and tail.h already exist they are used otherwise\n"
- " they are generated\n"
- "\nOptional:\n\n"
- "- ECF_FILES: If specified, then scripts are generated under this directory otherwise ECF_HOME is used.\n"
- " The missing directories are automatically created.\n"
- "- ECF_CLIENT_EXE_PATH: if specified child command will use this, otherwise will use ecflow_client\n"
- " and assume this accessible on the path.\n"
- "- ECF_DUMMY_TASK: Will not generated scripts for this task.\n"
- "- SLEEP: Uses this variable to delay time between calls to child commands, if not specified uses delay of one second\n\n"
- "\nUsage::\n\n"
- " defs = ecflow.Defs()\n"
- " suite = defs.add_suite('s1')\n"
- " suite.add_variable(\"ECF_HOME\",\"/user/var/home\")\n"
- " suite.add_variable(\"ECF_INCLUDE\",\"/user/var/home/includes\")\n"
- " for i in range(1,7) :\n"
- " fam = suite.add_family(\"f\" + str(i))\n"
- " for t in ( \"a\", \"b\", \"c\", \"d\", \"e\" ) :\n"
- " fam.add_task(t);\n"
- " defs.generate_scripts() # generate '.ecf' and head.h/tail.h if required\n"
- ;
-}
-
-const char* DefsDoc::check()
-{
- return
- "Check :term:`trigger` and :term:`complete expression` s and :term:`limit` s\n\n"
- "* Client Side: The client side can specify externs. Hence all node path references\n"
- " in :term:`trigger` expressions, and :term:`inlimit` references to :term:`limit` s, that are\n"
- " unresolved and which do *not* appear in :term:`extern` s are reported as errors\n"
- "* Server Side: The server does not store externs. Hence all unresolved references\n"
- " are reported as errors\n\n"
- "Returns a non empty string for any errors or warning\n"
- "\nUsage::\n\n"
- " # Client side\n"
- " defs = Defs('my.def') # Load my.def from disk\n"
- " ....\n"
- " print defs.check() # do the check\n"
- "\n"
- " # Server Side\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " print ci.check('/suite')\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
-
-const char* DefsDoc::simulate()
-{
- return
- "Simulates a :term:`suite definition` for 1 year:\n\n"
- "Will disable infinite repeats at the suite level. i.e repeat day\n"
- "This allows simulation to progress faster.\n"
- "By default will run simulation for a year. If the simulation does not complete\n"
- "creates .flat and .depth files. This provides clues as to the state of the definition\n"
- "at the end of the simulation\n"
- "\nUsage::\n\n"
- " defs = Defs('my.def') # specify the defs we want to simulate\n"
- " ....\n"
- " theResults = defs.simulate()\n"
- " print theResults\n"
- ;
-}
-
-
-const char* DefsDoc::get_server_state()
-{
- return
- "Returns the :term:`ecflow_server` state: See :term:`server states`\n\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client() # use default host(ECF_NODE) & port(ECF_PORT)\n"
- " ci.shutdown_server()\n"
- " ci.sync_local()\n"
- " assert ci.get_defs().get_server_state() == SState.SHUTDOWN, \"Expected server to be shutdown\"\n"
- " except RuntimeError, e:\n"
- " print str(e)\n"
- ;
-}
diff --git a/ecflow_4_0_7/Pyext/src/DefsDoc.hpp b/ecflow_4_0_7/Pyext/src/DefsDoc.hpp
deleted file mode 100644
index d223487..0000000
--- a/ecflow_4_0_7/Pyext/src/DefsDoc.hpp
+++ /dev/null
@@ -1,71 +0,0 @@
-#ifndef DEFS_DOC_HPP_
-#define DEFS_DOC_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #18 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/noncopyable.hpp>
-
-// ===========================================================================
-// IMPORTANT: These appear as python doc strings.
-// Additionally they are auto documented using sphinx-poco
-// Hence the doc strings use reStructuredText markup.
-// ===========================================================================
-class DefsDoc : private boost::noncopyable {
-public:
- static const char* abs_node_path_doc();
- static const char* part_expression_doc();
- static const char* expression_doc();
- static const char* add_trigger_doc();
- static const char* add_variable_doc();
- static const char* add_label_doc();
- static const char* add_limit_doc();
- static const char* add_inlimit_doc();
- static const char* node_doc();
- static const char* node_container_doc();
- static const char* submittable_doc();
- static const char* task_doc();
- static const char* alias_doc();
- static const char* family_doc();
- static const char* add_suite_doc();
- static const char* add_extern_doc();
- static const char* add_family_doc();
- static const char* add_task_doc();
- static const char* suite_doc();
- static const char* add_definition_doc();
- static const char* add_event_doc();
- static const char* add_meter_doc();
- static const char* add_date_doc();
- static const char* add_day_doc();
- static const char* add_today_doc();
- static const char* add_time_doc();
- static const char* add_cron_doc();
- static const char* add_late_doc();
- static const char* add_autocancel_doc();
- static const char* add_verify_doc();
- static const char* add_repeat_date_doc();
- static const char* add_repeat_integer_doc();
- static const char* add_repeat_string_doc();
- static const char* add_repeat_enumerated_doc();
- static const char* add_repeat_day_doc();
- static const char* add_defstatus_doc();
- static const char* jobgenctrl_doc();
- static const char* check_job_creation_doc();
- static const char* generate_scripts_doc();
- static const char* check();
- static const char* simulate();
- static const char* get_server_state();
-private:
- DefsDoc(){}
-};
-#endif
diff --git a/ecflow_4_0_7/Pyext/src/EcfExt.cpp b/ecflow_4_0_7/Pyext/src/EcfExt.cpp
deleted file mode 100644
index c5f7a4d..0000000
--- a/ecflow_4_0_7/Pyext/src/EcfExt.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #17 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/python.hpp>
-#include <boost/python/docstring_options.hpp>
-using namespace boost::python;
-
-void export_Core();
-void export_NodeAttr();
-void export_Node();
-void export_Task();
-void export_SuiteAndFamily();
-void export_Defs();
-void export_Client();
-
-// See: http://wiki.python.org/moin/boost.python/HowTo#boost.function_objects
-BOOST_PYTHON_MODULE(ecflow)
-{
- boost::python::docstring_options doc_options(
- true, // show the docstrings from here
- true, // show Python signatures.
- false // Don't mention the C++ method signatures in the generated docstrings
- );
- scope().attr("__doc__") =
- "The ecflow module provides the python bindings/api for creating definition structure and communicating with the server.";
-
- export_Core();
- export_NodeAttr();
- export_Node();
- export_Task();
- export_SuiteAndFamily();
- export_Defs();
- export_Client();
-}
diff --git a/ecflow_4_0_7/Pyext/src/ExportClient.cpp b/ecflow_4_0_7/Pyext/src/ExportClient.cpp
deleted file mode 100644
index d746b64..0000000
--- a/ecflow_4_0_7/Pyext/src/ExportClient.cpp
+++ /dev/null
@@ -1,329 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #85 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/python.hpp>
-#include <boost/noncopyable.hpp>
-
-#include "ClientInvoker.hpp"
-#include "Defs.hpp"
-#include "ClientDoc.hpp"
-#include "WhyCmd.hpp"
-#include "UrlCmd.hpp"
-#include "NState.hpp"
-#include "Version.hpp"
-#include "BoostPythonUtil.hpp"
-
-using namespace boost::python;
-using namespace std;
-namespace bp = boost::python;
-
-// See: http://wiki.python.org/moin/boost.python/HowTo#boost.function_objects
-
-void set_host_port(ClientInvoker* self, const std::string& host,int port) {self->set_host_port(host,boost::lexical_cast<std::string>(port));}
-void set_host_port_1(ClientInvoker* self, const std::string& host_port){
- // assume format <host>:<port>
- size_t colonPos = host_port.find_first_of(':');
- if (colonPos == string::npos) throw std::runtime_error("set_host_port: expected <host>:<port> : no ':' found in " + host_port);
- std::string host = host_port.substr(0,colonPos);
- std::string port = host_port.substr(colonPos+1);
- self->set_host_port(host,port);
-}
-
-
-std::string version(ClientInvoker* self) { return ecf::Version::raw();}
-std::string server_version(ClientInvoker* self) { self->server_version(); return self->get_string();}
-
-const std::string& get_log(ClientInvoker* self) { self->getLog(); return self->get_string();}
-
-const std::string& get_file(ClientInvoker* self,
- const std::string& absNodePath,
- const std::string& file_type = "script",
- const std::string& max_lines = "10000")
-{ self->file(absNodePath,file_type,max_lines); return self->get_string(); }
-
-const std::string& get_file_1(ClientInvoker* self,
- const std::string& absNodePath,
- const std::string& file_type = "script" )
-{ self->file(absNodePath,file_type,"10000"); return self->get_string(); }
-
-
-/// Set the CLI to enable output to standard out
-class CliSetter {
-public:
- CliSetter(ClientInvoker* self) : _self(self) { self->set_cli(true); }
- ~CliSetter() { _self->set_cli(false);}
-private:
- ClientInvoker* _self;
-};
-void stats(ClientInvoker* self) { CliSetter setter(self); self->stats(); }
-void stats_reset(ClientInvoker* self) { self->stats_reset(); }
-boost::python::list suites(ClientInvoker* self) {
- self->suites();
- const std::vector<std::string> the_suites = self->server_reply().get_string_vec();
- boost::python::list list;
- size_t the_size = the_suites.size();
- for(size_t i = 0; i < the_size; i++) list.append( the_suites[i] );
- return list;
-}
-
-bool news_local(ClientInvoker* self) { self->news_local(); return self->get_news(); }
-
-void free_trigger_dep(ClientInvoker* self, const std::string& path) { self->freeDep(path,true /*trigger*/,false/*all*/,false/*date*/,false/*time*/); }
-void free_date_dep(ClientInvoker* self, const std::string& path) { self->freeDep(path,false/*trigger*/,false/*all*/,true /*date*/,false/*time*/); }
-void free_time_dep(ClientInvoker* self, const std::string& path) { self->freeDep(path,false/*trigger*/,false/*all*/,false/*date*/,true /*time*/); }
-void free_all_dep(ClientInvoker* self, const std::string& path) { self->freeDep(path,false/*trigger*/,true /*all*/,false/*date*/,false/*time*/); }
-void free_trigger_dep1(ClientInvoker* self,const boost::python::list& list) { std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths);self->freeDep(paths,true /*trigger*/,false/*all*/,false/*date*/,false/*time*/); }
-void free_date_dep1(ClientInvoker* self, const boost::python::list& list) { std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths);self->freeDep(paths,false/*trigger*/,false/*all*/,true /*date*/,false/*time*/); }
-void free_time_dep1(ClientInvoker* self, const boost::python::list& list) { std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths);self->freeDep(paths,false/*trigger*/,false/*all*/,false/*date*/,true /*time*/); }
-void free_all_dep1(ClientInvoker* self, const boost::python::list& list) { std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths);self->freeDep(paths,false/*trigger*/,true /*all*/,false/*date*/,false/*time*/); }
-
-void force_state(ClientInvoker* self, const std::string& path, NState::State state) { self->force(path,NState::toString(state),false);}
-void force_states(ClientInvoker* self, const boost::python::list& list, NState::State state){ std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths);self->force(paths,NState::toString(state),false);}
-void force_state_recursive(ClientInvoker* self, const std::string& path, NState::State state) { self->force(path,NState::toString(state),true);}
-void force_states_recursive(ClientInvoker* self,const boost::python::list& list,NState::State state){ std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths);self->force(paths,NState::toString(state),true);}
-void force_event(ClientInvoker* self, const std::string& path, const std::string& set_or_clear) { self->force(path,set_or_clear);}
-void force_events(ClientInvoker* self,const boost::python::list& list,const std::string& set_or_clear) { std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths);self->force(paths,set_or_clear);}
-
-void run(ClientInvoker* self, const std::string& path, bool force) { self->run(path,force);}
-void runs(ClientInvoker* self,const boost::python::list& list, bool force) { std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths); self->run(paths,force);}
-void requeue(ClientInvoker* self,std::string path, const std::string& option) { self->requeue(path,option);}
-void requeues(ClientInvoker* self,const boost::python::list& list, const std::string& option) { std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths);self->requeue(paths,option);}
-void suspend(ClientInvoker* self, const std::string& path) { self->suspend(path);}
-void suspends(ClientInvoker* self,const boost::python::list& list) { std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths);self->suspend(paths);}
-void resume(ClientInvoker* self, const std::string& path) { self->resume(path);}
-void resumes(ClientInvoker* self,const boost::python::list& list) { std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths);self->resume(paths);}
-void status(ClientInvoker* self, const std::string& path) { self->status(path);}
-void statuss(ClientInvoker* self,const boost::python::list& list) { std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths);self->status(paths);}
-void do_kill(ClientInvoker* self, const std::string& path) { self->kill(path);}
-void do_kills(ClientInvoker* self,const boost::python::list& list) { std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths);self->kill(paths);}
-const std::string& check(ClientInvoker* self, const std::string& node_path) { self->check(node_path); return self->get_string(); }
-const std::string& checks(ClientInvoker* self, const boost::python::list& list) { std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths);self->check(paths); return self->get_string(); }
-
-void delete_node(ClientInvoker* self,const boost::python::list& list, bool force) { std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths);self->delete_nodes(paths,force);}
-
-void ch_suites(ClientInvoker* self){ CliSetter cli(self);self->ch_suites();}
-void ch_register(ClientInvoker* self,bool auto_add_new_suites,const boost::python::list& list)
-{std::vector<std::string> suites;BoostPythonUtil::list_to_str_vec(list,suites); self->ch_register(auto_add_new_suites,suites);}
-
-void ch_add(ClientInvoker* self,int client_handle,const boost::python::list& list)
-{std::vector<std::string> suites;BoostPythonUtil::list_to_str_vec(list,suites); self->ch_add(client_handle,suites);}
-void ch1_add(ClientInvoker* self,const boost::python::list& list)
-{std::vector<std::string> suites;BoostPythonUtil::list_to_str_vec(list,suites); self->ch1_add(suites);}
-
-void ch_remove(ClientInvoker* self,int client_handle,const boost::python::list& list)
-{std::vector<std::string> suites;BoostPythonUtil::list_to_str_vec(list,suites); self->ch_remove(client_handle,suites);}
-void ch1_remove(ClientInvoker* self,const boost::python::list& list)
-{std::vector<std::string> suites;BoostPythonUtil::list_to_str_vec(list,suites); self->ch1_remove(suites);}
-
-/// Need to provide override since the boolean argument is optional.
-/// This saves on client python code, on having to specify the optional arg
-void replace_1(ClientInvoker* self,const std::string& absNodePath, defs_ptr client_defs) { self->replace_1(absNodePath,client_defs);}
-void replace_2(ClientInvoker* self,const std::string& absNodePath, const std::string& path_to_client_defs) { self->replace(absNodePath,path_to_client_defs);}
-
-void order(ClientInvoker* self,const std::string& absNodePath,const std::string& the_order){ self->order(absNodePath,the_order);}
-
-void alters(ClientInvoker* self,
- const boost::python::list& list,
- const std::string& alterType, /* one of [ add | change | delete | set_flag | clear_flag ] */
- const std::string& attrType,
- const std::string& name = "",
- const std::string& value = "") { std::vector<std::string> paths;BoostPythonUtil::list_to_str_vec(list,paths);self->check(paths);self->alter(paths,alterType,attrType,name,value); }
-void alter(ClientInvoker* self,
- const std::string& path,
- const std::string& alterType, /* one of [ add | change | delete | set_flag | clear_flag ] */
- const std::string& attrType,
- const std::string& name = "",
- const std::string& value = "") { self->alter(path,alterType,attrType,name,value); }
-
-void set_child_pid(ClientInvoker* self,int pid) { self->set_child_pid( boost::lexical_cast<std::string>(pid)); }
-
-
-void export_Client()
-{
- class_<ClientInvoker, boost::noncopyable >("Client",ClientDoc::class_client())
- .def( init<std::string>() /* host:port */)
- .def( init<std::string,std::string>() /* host, port */)
- .def( init<std::string,int>() /* host, port(int) */)
- .def("version", &version, "Returns the current client version")
- .def("server_version", &server_version, "Returns the server version, can throw for old servers, that did not implement this request.")
- .def("set_host_port", &ClientInvoker::set_host_port, ClientDoc::set_host_port())
- .def("set_host_port", &set_host_port )
- .def("set_host_port", &set_host_port_1 )
- .def("get_host", &ClientInvoker::host, return_value_policy<copy_const_reference>(), "Return the host, assume set_host_port() has been set, otherwise return localhost" )
- .def("get_port", &ClientInvoker::port, return_value_policy<copy_const_reference>(), "Return the port, assume set_host_port() has been set. otherwise returns 3141" )
- .def("set_retry_connection_period",&ClientInvoker::set_retry_connection_period, ClientDoc::set_retry_connection_period())
- .def("set_connection_attempts",&ClientInvoker::set_connection_attempts, ClientDoc::set_connection_attempts())
- .def("get_defs", &ClientInvoker::defs, ClientDoc::get_defs())
- .def("in_sync", &ClientInvoker::in_sync, ClientDoc::in_sync())
-#ifdef DEBUG
- .def("get_log" , &get_log, return_value_policy<copy_const_reference>(),ClientDoc::get_log())
-#endif
- .def("new_log", &ClientInvoker::new_log, (bp::arg("path")=""),ClientDoc::new_log())
- .def("clear_log", &ClientInvoker::clearLog, ClientDoc::clear_log())
- .def("flush_log", &ClientInvoker::flushLog, ClientDoc::flush_log())
- .def("log_msg", &ClientInvoker::logMsg, ClientDoc::log_msg())
- .def("restart_server", &ClientInvoker::restartServer, ClientDoc::restart_server())
- .def("halt_server", &ClientInvoker::haltServer, ClientDoc::halt_server())
- .def("shutdown_server", &ClientInvoker::shutdownServer, ClientDoc::shutdown_server())
- .def("terminate_server", &ClientInvoker::terminateServer, ClientDoc::terminate_server())
- .def("wait_for_server_reply",&ClientInvoker::wait_for_server_reply,(bp::arg("time_out")=60), ClientDoc::wait_for_server_reply())
- .def("load" , &ClientInvoker::loadDefs,(bp::arg("path_to_defs"), bp::arg("force")=false,bp::arg("check_only")=false),ClientDoc::load_defs())
- .def("load" , &ClientInvoker::load,(bp::arg("defs"), bp::arg("force")=false),ClientDoc::load())
- .def("get_server_defs", &ClientInvoker::getDefs, ClientDoc::get_server_defs())
- .def("sync_local", &ClientInvoker::sync_local, ClientDoc::sync())
- .def("news_local", &news_local, ClientDoc::news())
- .add_property("changed_node_paths",boost::python::range( &ClientInvoker::changed_node_paths_begin, &ClientInvoker::changed_node_paths_end),ClientDoc::changed_node_paths())
- .def("suites" , &suites, ClientDoc::suites())
- .def("ch_register", &ch_register, ClientDoc::ch_register())
- .def("ch_suites", &ch_suites, ClientDoc::ch_suites())
- .def("ch_handle", &ClientInvoker::client_handle, ClientDoc::ch_register())
- .def("ch_drop", &ClientInvoker::ch_drop, ClientDoc::ch_drop())
- .def("ch_drop", &ClientInvoker::ch1_drop)
- .def("ch_drop_user", &ClientInvoker::ch_drop_user, ClientDoc::ch_drop_user())
- .def("ch_add", &ch_add, ClientDoc::ch_add())
- .def("ch_add", &ch1_add )
- .def("ch_remove", &ch_remove, ClientDoc::ch_remove())
- .def("ch_remove", &ch1_remove)
- .def("ch_auto_add", &ClientInvoker::ch_auto_add, ClientDoc::ch_auto_add())
- .def("ch_auto_add", &ClientInvoker::ch1_auto_add)
- .def("checkpt", &ClientInvoker::checkPtDefs, (bp::arg("mode")=ecf::CheckPt::UNDEFINED, bp::arg("check_pt_interval")=0,bp::arg("check_pt_save_alarm_time")=0), ClientDoc::checkpt())
- .def("restore_from_checkpt",&ClientInvoker::restoreDefsFromCheckPt,ClientDoc::restore_from_checkpt())
- .def("reload_wl_file" , &ClientInvoker::reloadwsfile, ClientDoc::reload_wl_file())
- .def("requeue" , &requeue, (bp::arg("abs_node_path"), bp::arg("option")=""), ClientDoc::requeue())
- .def("requeue" , &requeues, (bp::arg("paths"), bp::arg("option")="") )
- .def("free_trigger_dep", &free_trigger_dep, ClientDoc::free_trigger_dep())
- .def("free_trigger_dep", &free_trigger_dep1 )
- .def("free_date_dep", &free_date_dep, ClientDoc::free_date_dep())
- .def("free_date_dep", &free_date_dep1 )
- .def("free_time_dep", &free_time_dep, ClientDoc::free_time_dep())
- .def("free_time_dep", &free_time_dep1)
- .def("free_all_dep", &free_all_dep, ClientDoc::free_all_dep())
- .def("free_all_dep", &free_all_dep1)
- .def("ping" , &ClientInvoker::pingServer, ClientDoc::ping())
- .def("stats" , &stats, ClientDoc::stats())
- .def("stats_reset" , &stats_reset, ClientDoc::stats_reset())
- .def("get_file" , &get_file, return_value_policy<copy_const_reference>(), ClientDoc::get_file())
- .def("get_file" , &get_file_1, return_value_policy<copy_const_reference>())
- .def("plug" , &ClientInvoker::plug, ClientDoc::plug())
- .def("alter" , &alters,(bp::arg("paths"),bp::arg("alter_type"),bp::arg("attribute_type"),bp::arg("name")="",bp::arg("value")=""), ClientDoc::alter())
- .def("alter" , &alter,(bp::arg("abs_node_path"),bp::arg("alter_type"),bp::arg("attribute_type"),bp::arg("name")="",bp::arg("value")=""))
- .def("force_event" , &force_event, ClientDoc::force_event())
- .def("force_event" , &force_events)
- .def("force_state" , &force_state, ClientDoc::force_state())
- .def("force_state" , &force_states)
- .def("force_state_recursive",&force_state_recursive, ClientDoc::force_state_recursive())
- .def("force_state_recursive",&force_states_recursive)
- .def("replace" , &ClientInvoker::replace, ClientDoc::replace())
- .def("replace" , &ClientInvoker::replace_1)
- .def("replace" , &replace_1 )
- .def("replace" , &replace_2 )
- .def("order" , &order, ClientDoc::order())
- .def("group" , &ClientInvoker::group, ClientDoc::group())
- .def("begin_suite" , &ClientInvoker::begin, (bp::arg("suite_name"),bp::arg("force")=false), ClientDoc::begin_suite())
- .def("begin_all_suites", &ClientInvoker::begin_all_suites,(bp::arg("force")=false), ClientDoc::begin_all())
- .def("job_generation", &ClientInvoker::job_gen, ClientDoc::job_gen())
- .def("run" , &run, ClientDoc::run())
- .def("run" , &runs)
- .def("check" , &check, return_value_policy<copy_const_reference>(), ClientDoc::check())
- .def("check" , &checks, return_value_policy<copy_const_reference>())
- .def("kill" , &do_kill, ClientDoc::kill())
- .def("kill" , &do_kills)
- .def("status" , &status, ClientDoc::status())
- .def("status" , &statuss)
- .def("suspend" , &suspend, ClientDoc::suspend())
- .def("suspend" , &suspends)
- .def("resume" , &resume, ClientDoc::resume())
- .def("resume" , &resumes)
- .def("delete" , &ClientInvoker::delete_node, (bp::arg("abs_node_path"),bp::arg("force")=false), ClientDoc::delete_node())
- .def("delete" , &delete_node, (bp::arg("paths"),bp::arg("force")=false))
- .def("delete_all", &ClientInvoker::delete_all, (bp::arg("force")=false), ClientDoc::delete_all())
- .def("debug_server_on", &ClientInvoker::debug_server_on, "Enable server debug, Will dump to standard out on server host.")
- .def("debug_server_off", &ClientInvoker::debug_server_off, "Disable server debug")
-
- .def("set_child_path", &ClientInvoker::set_child_path , "Set the path to the task, obtained from server using %ECF_NAME%")
- .def("set_child_password", &ClientInvoker::set_child_password,"Set the password, needed for authentication, provided by the server using %ECF_PASS%")
- .def("set_child_pid", &ClientInvoker::set_child_pid, "Set the process id of this job" )
- .def("set_child_pid", &set_child_pid, "Set the process id of this job" )
- .def("set_child_try_no", &ClientInvoker::set_child_try_no, "Set the try no, i.e the number of times this job has run, obtained from the server, using %ECF_TRYNO%")
- .def("set_child_timeout", &ClientInvoker::set_child_timeout, "Set timeout if child can not connect to server, default is 24 hours. The input is required to be in seconds")
- .def("child_init", &ClientInvoker::child_init, "Child command,notify server job has started")
- .def("child_abort", &ClientInvoker::child_abort, (bp::arg("reason")=""), "Child command,notify server job has aborted, can provide an optional reason")
- .def("child_event", &ClientInvoker::child_event, "Child command,notify server event occurred, requires the event name")
- .def("child_meter", &ClientInvoker::child_meter, "Child command,notify server meter changed, requires meter name and value")
- .def("child_label", &ClientInvoker::child_label, "Child command,notify server label changed, requires label name, and new value")
- .def("child_wait", &ClientInvoker::child_wait, "Child command,wait for expression to come true")
- .def("child_complete", &ClientInvoker::child_complete,"Child command,notify server job has complete")
- ;
-
- class_<WhyCmd, boost::noncopyable >( "WhyCmd",
- "The why command reports, the reason why a node is not running.\n\n"
- "It needs the definition structure and the path to node\n"
- "\nConstructor::\n\n"
- " WhyCmd(defs, node_path)\n"
- " defs_ptr defs : pointer to a definition structure\n"
- " string node_path : The node path\n\n"
- "\nExceptions:\n\n"
- "- raises RuntimeError if the definition is empty\n"
- "- raises RuntimeError if the node path is empty\n"
- "- raises RuntimeError if the node path can not be found in the definition\n"
- "\nUsage::\n\n"
- " try:\n"
- " ci = Client()\n"
- " ci.sync_local()\n"
- " ask = WhyCmd(ci.get_defs(),'/suite/family')\n"
- " print ask.why()\n"
- " except RuntimeError, e:\n"
- " print str(e)\n\n"
- ,
- init<defs_ptr,std::string >()
- )
- .def("why", &WhyCmd::why, "returns a '/n' separated string, with reasons why node is not running")
- ;
-
- class_<UrlCmd, boost::noncopyable >( "UrlCmd",
- "Executes a command ECF_URL_CMD to display a url.\n\n"
- "It needs the definition structure and the path to node.\n"
- "\nConstructor::\n\n"
- " UrlCmd(defs, node_path)\n"
- " defs_ptr defs : pointer to a definition structure\n"
- " string node_path : The node path.\n\n"
- "\nExceptions\n\n"
- "- raises RuntimeError if the definition is empty\n"
- "- raises RuntimeError if the node path is empty\n"
- "- raises RuntimeError if the node path can not be found in the definition\n"
- "- raises RuntimeError if ECF_URL_CMD not defined or if variable substitution fails\n"
- "\nUsage:\n"
- "Lets assume that the server has the following definition::\n\n"
- " suite s\n"
- " edit ECF_URL_CMD \"${BROWSER:=firefox} -remote 'openURL(%ECF_URL_BASE%/%ECF_URL%)'\"\n"
- " edit ECF_URL_BASE \"http://www.ecmwf.int\"\n"
- " family f\n"
- " task t1\n"
- " edit ECF_URL \"publications/manuals/ecflow\"\n"
- " task t2\n"
- " edit ECF_URL index.html\n\n"
- "::\n\n"
- " try:\n"
- " ci = Client()\n"
- " ci.sync_local()\n"
- " url = UrlCmd(ci.get_defs(),'/suite/family/task')\n"
- " print url.execute()\n"
- " except RuntimeError, e:\n"
- " print str(e)\n\n"
- ,
- init<defs_ptr,std::string >()
- )
- .def("execute", &UrlCmd::execute, "Displays url in the chosen browser")
- ;
-}
diff --git a/ecflow_4_0_7/Pyext/src/ExportCore.cpp b/ecflow_4_0_7/Pyext/src/ExportCore.cpp
deleted file mode 100644
index 70615e0..0000000
--- a/ecflow_4_0_7/Pyext/src/ExportCore.cpp
+++ /dev/null
@@ -1,247 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #33 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/python.hpp>
-#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
-#include <boost/noncopyable.hpp>
-#include "PrintStyle.hpp"
-#include "DState.hpp"
-#include "SState.hpp"
-#include "File.hpp"
-#include "TimeSlot.hpp"
-#include "TimeSeries.hpp"
-#include "CheckPt.hpp"
-#include "Ecf.hpp"
-
-// See: http://wiki.python.org/moin/boost.python/HowTo#boost.function_objects
-// TODO:
- template<class K, class T>
- struct pair_to_tuple {
- typedef pair_to_tuple<K,T> converter;
- typedef std::pair<K,T> ctype;
-
- static PyObject* convert(ctype const& v) {
- using namespace boost::python;
- return incref(make_tuple(v.first,v.second).ptr());
- }
- static void register_to_python() {
- boost::python::to_python_converter<ctype,converter>();
- }
- };
-
-using namespace boost::python;
-using namespace std;
-using namespace ecf;
-
-bool debug_build()
-{
-#ifdef NDEBUG
- return false;
-#else
- return true;
-#endif
-}
-
-void export_Core()
-{
- // For use in test only
- def("debug_build",debug_build);
-
- class_<File, boost::noncopyable >("File", "Utility class, Used in test only.")
- .def("find_server", &File::find_ecf_server_path, "Provides pathname to the server") .staticmethod("find_server")
- .def("find_client", &File::find_ecf_client_path, "Provides pathname to the client") .staticmethod("find_client")
- ;
-
- enum_<PrintStyle::Type_t>("Style",
- "Style is used to control printing output for the definition\n\n"
- "- DEFS: This style outputs the definition file in a format that is parse-able.\n"
- " and can be re-loaded back into the server.\n"
- " Externs are automatically added.\n"
- " This excludes the edit history.\n"
- "- STATE: The output includes additional state information for debug\n"
- " This excludes the edit history\n"
- "- MIGRATE: Output includes structure and state, allow migration to future ecflow versions\n"
- " This includes edit history. If file is reloaded no checking is done\n\n"
- "The following shows a summary of the features associated with each choice\n"
- "\n"
- " ===================== ==== ===== =======\n"
- " Functionality DEFS STATE MIGRATE\n"
- " ===================== ==== ===== =======\n"
- " Auto generate externs Yes Yes No\n"
- " Checking on reload Yes Yes No\n"
- " Edit History No No Yes\n"
- " Show trigger AST No Yes No\n"
- " ===================== ==== ===== =======\n"
- )
- .value("NOTHING", PrintStyle::NOTHING)
- .value("DEFS", PrintStyle::DEFS)
- .value("STATE", PrintStyle::STATE)
- .value("MIGRATE", PrintStyle::MIGRATE)
- ;
-
- enum_<CheckPt::Mode>("CheckPt",
- "CheckPt is enum that is used to control check pointing in the :term:`ecflow_server`\n\n"
- "- NEVER : Switches of check pointing\n"
- "- ON_TIME: :term:`check point` file is saved periodically, specified by checkPtInterval. This is the default.\n"
- "- ALWAYS : :term:`check point` file is saved after any state change, *not* recommended for large definitions\n"
- "- UNDEFINED : None of the the above, used to provide default argument\n"
- )
- .value("NEVER", CheckPt::NEVER)
- .value("ON_TIME",CheckPt::ON_TIME)
- .value("ALWAYS", CheckPt::ALWAYS)
- .value("UNDEFINED", CheckPt::UNDEFINED)
- ;
-
-
- class_<PrintStyle, boost::noncopyable >("PrintStyle",
- "Singleton used to control the print Style.\n\n"
- "\nUsage::\n\n"
- " style = PrintStyle.get_style()\n"
- ,
- no_init)
- .def("get_style", &PrintStyle::getStyle,"Returns the style, static method")
- .staticmethod("get_style")
- .def("set_style", &PrintStyle::setStyle,"Set the style, static method")
- .staticmethod("set_style")
- ;
-
- class_<Ecf, boost::noncopyable >("Ecf",
- "Singleton used to control ecf debugging\n\n",
- no_init)
- .def("debug_equality", &Ecf::debug_equality,"Returns true if debugging of equality is enabled")
- .staticmethod("debug_equality")
- .def("set_debug_equality", &Ecf::set_debug_equality,"Set debugging for equality")
- .staticmethod("set_debug_equality")
- .def("debug_level", &Ecf::debug_level,"Returns integer showing debug level. debug_level > 0 will disable some warning messages")
- .staticmethod("debug_level")
- .def("set_debug_level", &Ecf::set_debug_level,"Set debug level. debug_level > 0 will disable some warning messages")
- .staticmethod("set_debug_level")
- ;
-
- enum_<NState::State>("State",
- "Each :term:`node` can have a status, which reflects the life cycle of a node.\n\n"
- "It varies as follows:\n\n"
- "- When the definition file is loaded into the :term:`ecflow_server` the :term:`task` status is :term:`unknown`\n"
- "- After begin command the :term:`task` s are either :term:`queued`, :term:`complete`, :term:`aborted` or :term:`suspended` ,\n"
- " a suspended task means that the task is really :term:`queued` but it must be resumed by\n"
- " the user first before it can be :term:`submitted`. See :py:class:`ecflow.DState`\n"
- "- Once the :term:`dependencies` are resolved a task is submitted and placed into the :term:`submitted` state,\n"
- " however if the submission fails, the task is placed in a :term:`aborted` state.\n"
- "- On a successful submission the task is placed into the :term:`active` state\n"
- "- Before a job ends, it may send other message to the server such as:\n"
- " Set an :term:`event`, Change a :term:`meter`, Change a :term:`label`, send a message to log file\n\n"
- "Jobs end by becoming either :term:`complete` or :term:`aborted`"
- )
- .value("unknown", NState::UNKNOWN)
- .value("complete", NState::COMPLETE)
- .value("queued", NState::QUEUED)
- .value("aborted", NState::ABORTED)
- .value("submitted",NState::SUBMITTED)
- .value("active", NState::ACTIVE)
- ;
-
- enum_<DState::State>("DState",
- "A DState is like a ecflow.State, except for the addition of SUSPENDED\n\n"
- "Suspended stops job generation, and hence is an attribute of a Node.\n"
- "DState can be used for setting the default state of node when it is\n"
- "begun or re queued. DState is used for defining :term:`defstatus`. See :py:class:`ecflow.Node.add_defstatus`\n"
- "The default state of a :term:`node` is :term:`queued`.\n"
- "\nUsage::\n\n"
- " task = ecflow.Task('t1')\n"
- " task.add_defstatus(ecflow.DState.complete)"
- )
- .value("unknown", DState::UNKNOWN)
- .value("complete", DState::COMPLETE)
- .value("queued", DState::QUEUED)
- .value("aborted", DState::ABORTED)
- .value("submitted",DState::SUBMITTED)
- .value("suspended",DState::SUSPENDED)
- .value("active", DState::ACTIVE)
- ;
-
- enum_<SState::State>("SState",
- "A SState holds the :term:`ecflow_server` state\n\n"
- "See :term:`server states`"
- )
- .value("HALTED", SState::HALTED)
- .value("SHUTDOWN", SState::SHUTDOWN)
- .value("RUNNING", SState::RUNNING)
- ;
-
-
- class_<TimeSlot>("TimeSlot",
- "Represents a time slot.\n\n"
- "It is typically used as an argument to a TimeSeries or\n"
- "other time dependent attributes of a node.\n"
- "\n"
- "\nConstructor::\n\n"
- " TimeSlot(hour,min)\n"
- " int hour: represent an hour:\n"
- " int minute: represents a minute:\n"
- "\nUsage::\n\n"
- " ts = TimeSlot(10,11)\n"
- ,
- init<int,int>()
- )
- .def("__str__", &TimeSlot::toString) // __str__
- .def(self == self ) // __eq__
- .def("hour", &TimeSlot::hour) // return int
- .def("minute", &TimeSlot::minute) // return int
- .def("empty", &TimeSlot::isNULL) // return bool
- ;
-
- // single slot, | start, finish, incr, bool relative to suite start
- class_<TimeSeries>("TimeSeries",
- "A TimeSeries can hold a single time slot or a series.\n\n"
- "Time series can be created relative to the :term:`suite` start or start of a repeating node.\n"
- "A Time series can be used as argument to the :py:class:`ecflow.Time`, py:class:`ecflow.Today` and py:class:`ecflow.Cron` attributes of a node.\n"
- "If a time the job takes to complete is longer than the interval, a 'slot' is missed\n"
- "e.g time 10:00 20:00 01:00, if the 10.00 run takes more than an hour the 11.00 is missed\n\n"
- "\nConstructor::\n\n"
- " TimeSeries(single,relative_to_suite_start)\n"
- " TimeSlot single : A single point in a 24 clock \n"
- " optional bool relative_to_suite_start : depend on suite begin time or\n"
- " start of repeating node. Default is false\n"
- "\n"
- " TimeSeries(hour,minute,relative_to_suite_start)\n"
- " int hour : hour in 24 clock \n"
- " int minute : minute < 59 \n"
- " bool relative_to_suite_start<optional> : depend on suite begin time or\n"
- " start of repeating node. Default is false\n"
- "\n"
- " TimeSeries(start,finish,increment,relative_to_suite_start)\n"
- " start TimeSlot : The start time \n"
- " finish TimeSlot : The finish time, when used in a series. This must greater than the start.\n"
- " increment TimeSlot : The increment. This must be less that difference between start and finish\n"
- " bool relative_to_suite_start<optional> : The time is relative suite start, or start of repeating node.\n"
- " The default is false\n"
- "\nExceptions:\n\n"
- "- Raises IndexError when an invalid time series is specified\n"
- "\nUsage::\n\n"
- " time_series = TimeSeries(TimeSlot(10,11),False)\n" ,
- init<TimeSlot, optional<bool> >())
- .def( init<int,int,optional<bool> >())
- .def( init<TimeSlot,TimeSlot,TimeSlot,optional<bool> >())
- .def("__str__", &TimeSeries::toString) // __str__
- .def(self == self ) // __eq__
- .def("has_increment", &TimeSeries::hasIncrement,"distinguish between a single time slot and a series. returns true for a series") // false if single time slot
- .def("start", &TimeSeries::start , return_value_policy<copy_const_reference>(),"returns the start time") // returns a time slot
- .def("finish", &TimeSeries::finish, return_value_policy<copy_const_reference>(),"returns the finish time if time series specified, else returns a NULL time slot") // returns a time slot
- .def("incr", &TimeSeries::incr, return_value_policy<copy_const_reference>()," returns the increment time if time series specified, else returns a NULL time slot") // returns a time slot
- .def("relative", &TimeSeries::relative,"returns a boolean where true means that the time series is relative")
- ;
-
- using namespace boost::python;
- pair_to_tuple<std::string,std::string>::register_to_python();
-}
diff --git a/ecflow_4_0_7/Pyext/src/ExportDefs.cpp b/ecflow_4_0_7/Pyext/src/ExportDefs.cpp
deleted file mode 100644
index 7033f76..0000000
--- a/ecflow_4_0_7/Pyext/src/ExportDefs.cpp
+++ /dev/null
@@ -1,189 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #93 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/python.hpp>
-#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
-
-#include <boost/shared_ptr.hpp>
-#include <boost/make_shared.hpp>
-#include <boost/enable_shared_from_this.hpp>
-#include <boost/noncopyable.hpp>
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "PrintStyle.hpp"
-#include "File.hpp"
-#include "DefsStructureParser.hpp"
-#include "JobCreationCtrl.hpp"
-#include "Simulator.hpp"
-#include "BoostPythonUtil.hpp"
-
-#include "DefsDoc.hpp"
-
-using namespace ecf;
-using namespace boost::python;
-using namespace std;
-namespace bp = boost::python;
-
-// See: http://wiki.python.org/moin/boost.python/HowTo#boost.function_objects
-
-void save_as_defs(const Defs& theDefs, const std::string& filename, PrintStyle::Type_t the_style_enum)
-{
- PrintStyle style(the_style_enum);
- std::stringstream ss; ss << theDefs;
-
- std::string file_creation_error_msg;
- if (!File::create(filename,ss.str(),file_creation_error_msg)) {
- std::string error = "save_as_defs failed: ";
- error += file_creation_error_msg;
- throw std::runtime_error(error);
- }
-}
-
-void save_as_defs_1(const Defs& theDefs, const std::string& filename)
-{
- save_as_defs(theDefs,filename,PrintStyle::DEFS);
-}
-
-static defs_ptr create_defs(const std::string& file_name)
-{
- defs_ptr defs = Defs::create();
-
- DefsStructureParser checkPtParser( defs.get(), file_name );
- std::string errorMsg,warningMsg;
- if (!checkPtParser.doParse(errorMsg,warningMsg)) {
- throw std::runtime_error(errorMsg);
- }
- if (!warningMsg.empty()) std::cerr << warningMsg;
- return defs;
-}
-
-std::string check_defs(defs_ptr defs)
-{
- std::string error_msg;
- std::string warning_msg;
- if (defs.get() && !defs->check(error_msg,warning_msg)) {
- error_msg += "\n";
- error_msg += warning_msg;
- return error_msg;
- }
- return warning_msg;
-}
-
-void save_as_checkpt(defs_ptr defs, const std::string& file_name)
-{
- defs->save_as_checkpt(file_name); // use default ARCHIVE
-}
-
-void restore_from_checkpt(defs_ptr defs, const std::string& file_name)
-{
- defs->restore_from_checkpt(file_name); // use default ARCHIVE
-}
-
-std::string simulate(defs_ptr defs)
-{
- if (defs.get()) {
- // name output file after name of the first suite
- std::string defs_filename = "pyext.def";
- if (!defs->suiteVec().empty()) {
- defs_filename = (*defs->suiteVec().begin())->name() + ".def";
- }
-
- Simulator simulator;
- std::string errorMsg;
- if (!simulator.run(*defs, defs_filename, errorMsg)) {
- return errorMsg;
- }
- }
- return string();
-}
-
-SState::State get_server_state(defs_ptr self) { return self->server().get_state(); }
-
-/// Since we don't pass in a child pos, the nodes are added to the end
-void add_suite(defs_ptr self,suite_ptr s){ self->addSuite(s); }
-
-std::vector<task_ptr> get_all_tasks(defs_ptr self){ std::vector<task_ptr> tasks; self->get_all_tasks(tasks); return tasks; }
-std::vector<node_ptr> get_all_nodes(defs_ptr self){ std::vector<node_ptr> nodes; self->get_all_nodes(nodes); return nodes; }
-
-// Context management, Only used to provide indentation
-defs_ptr defs_enter(defs_ptr self) { return self;}
-bool defs_exit(defs_ptr self,const boost::python::object& type,const boost::python::object& value,const boost::python::object& traceback){return false;}
-
-std::string check_job_creation(defs_ptr defs)
-{
- job_creation_ctrl_ptr jobCtrl = boost::make_shared<JobCreationCtrl>();
- defs->check_job_creation(jobCtrl);
- return jobCtrl->get_error_msg();
-}
-
-// Add server user variables
-defs_ptr add_variable(defs_ptr self,const std::string& name, const std::string& value) {
- self->set_server().add_or_update_user_variables(name,value); return self;}
-defs_ptr add_variable_int(defs_ptr self,const std::string& name, int value) {
- self->set_server().add_or_update_user_variables(name, boost::lexical_cast<std::string>(value)); return self;}
-defs_ptr add_variable_var(defs_ptr self,const Variable& var) {
- self->set_server().add_or_update_user_variables(var.name(),var.theValue()); return self;}
-defs_ptr add_variable_dict(defs_ptr self,const boost::python::dict& dict) {
- std::vector<std::pair<std::string,std::string> > vec;
- BoostPythonUtil::dict_to_str_vec(dict,vec);
- std::vector<std::pair<std::string,std::string> >::iterator i;
- std::vector<std::pair<std::string,std::string> >::iterator vec_end = vec.end();
- for(i = vec.begin(); i != vec_end; ++i) {
- self->set_server().add_or_update_user_variables((*i).first,(*i).second);
- }
- return self;
-}
-void delete_variable(defs_ptr self,const std::string& name) { self->set_server().delete_user_variable(name);}
-
-
-void export_Defs()
-{
- class_<Defs, boost::noncopyable, defs_ptr >( "Defs", DefsDoc::add_definition_doc() ,init<>("Create a empty Defs"))
- .def("__init__",make_constructor(&create_defs), DefsDoc::add_definition_doc())
- .def(self == self ) // __eq__
- .def("__str__", &Defs::toString) // __str__
- .def("__enter__", &defs_enter) // allow with statement, hence indentation support
- .def("__exit__", &defs_exit) // allow with statement, hence indentation support
- .def("add_suite", &add_suite, DefsDoc::add_suite_doc())
- .def("add_suite", &Defs::add_suite )
- .def("add_extern", &Defs::add_extern, DefsDoc::add_extern_doc())
- .def("auto_add_externs", &Defs::auto_add_externs, DefsDoc::add_extern_doc())
- .def("add_variable", &add_variable, DefsDoc::add_variable_doc())
- .def("add_variable", &add_variable_int)
- .def("add_variable", &add_variable_var)
- .def("add_variable", &add_variable_dict)
- .def("delete_variable", &delete_variable,"An empty string will delete all user variables")
- .def("find_suite", &Defs::findSuite,"Given a name, find the corresponding :term:`suite`")
- .def("find_abs_node", &Defs::findAbsNode,"Given a path, find the the :term:`node`")
- .def("get_all_nodes", &get_all_nodes,"Returns all the :term:`node` s in the definition")
- .def("get_all_tasks", &get_all_tasks,"Returns all the :term:`task` nodes")
- .def("has_time_dependencies", &Defs::hasTimeDependencies,"returns True if the :term:`suite definition` has any time :term:`dependencies`")
- .def("save_as_checkpt", &save_as_checkpt, "Save the in memory :term:`suite definition` as a :term:`check point` file. This includes all node state.")
- .def("restore_from_checkpt", &restore_from_checkpt, "Restore the :term:`suite definition` from a :term:`check point` file stored on disk")
- .def("save_as_defs", &save_as_defs, "Save the in memory :term:`suite definition` into a file. The file name must be passed as an argument\n\n")
- .def("save_as_defs", &save_as_defs_1, "Save the in memory :term:`suite definition` into a file. The file name must be passed as an argument\n\n")
- .def("check", &check_defs, DefsDoc::check())
- .def("simulate", &simulate, DefsDoc::simulate())
- .def("check_job_creation", &check_job_creation, DefsDoc::check_job_creation_doc() )
- .def("check_job_creation", &Defs::check_job_creation)
- .def("generate_scripts", &Defs::generate_scripts, DefsDoc::generate_scripts_doc() )
- .def("get_state", &Defs::state )
- .def("get_server_state", &get_server_state, DefsDoc::get_server_state() )
- .add_property("suites", boost::python::range( &Defs::suite_begin, &Defs::suite_end),"Returns a list of :term:`suite` s")
- .add_property("externs", boost::python::range( &Defs::extern_begin, &Defs::extern_end),"Returns a list of :term:`extern` s" )
- .add_property("user_variables", boost::python::range( &Defs::user_variables_begin, &Defs::user_variables_end),"Returns a list of user defined :term:`variable` s" )
- .add_property("server_variables", boost::python::range( &Defs::server_variables_begin, &Defs::server_variables_end),"Returns a list of server :term:`variable` s" )
- ;
-}
diff --git a/ecflow_4_0_7/Pyext/src/ExportNode.cpp b/ecflow_4_0_7/Pyext/src/ExportNode.cpp
deleted file mode 100644
index 673ddd3..0000000
--- a/ecflow_4_0_7/Pyext/src/ExportNode.cpp
+++ /dev/null
@@ -1,279 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #85 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/python.hpp>
-#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
-
-#include <boost/shared_ptr.hpp>
-#include <boost/make_shared.hpp>
-#include <boost/enable_shared_from_this.hpp>
-#include <boost/noncopyable.hpp>
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Task.hpp"
-#include "Expression.hpp"
-#include "JobCreationCtrl.hpp"
-#include "BoostPythonUtil.hpp"
-
-#include "DefsDoc.hpp"
-#include "NodeAttrDoc.hpp"
-
-using namespace ecf;
-using namespace boost::python;
-using namespace std;
-namespace bp = boost::python;
-
-// See: http://wiki.python.org/moin/boost.python/HowTo#boost.function_objects
-
-Defs* get_defs(node_ptr self) { return self->defs(); }
-
-node_ptr add_variable(node_ptr self,const std::string& name, const std::string& value) { self->add_variable(name,value); return self;}
-node_ptr add_variable_int(node_ptr self,const std::string& name, int value) { self->add_variable_int(name,value); return self;}
-node_ptr add_variable_var(node_ptr self,const Variable& var) { self->addVariable(var); return self;}
-node_ptr add_variable_dict(node_ptr self,const boost::python::dict& dict) {
- std::vector<std::pair<std::string,std::string> > vec;
- BoostPythonUtil::dict_to_str_vec(dict,vec);
- std::vector<std::pair<std::string,std::string> >::iterator i;
- std::vector<std::pair<std::string,std::string> >::iterator vec_end = vec.end();
- for(i = vec.begin(); i != vec_end; ++i) {
- self->add_variable((*i).first,(*i).second);
- }
- return self;
-}
-
-node_ptr add_event(node_ptr self,const Event& e) { self->addEvent(e); return self; }
-node_ptr add_event_1(node_ptr self,int number) { self->addEvent(Event(number)); return self; }
-node_ptr add_event_2(node_ptr self,int number,const std::string& name) { self->addEvent(Event(number,name)); return self; }
-node_ptr add_event_3(node_ptr self,const std::string& name) { self->addEvent(Event(name)); return self; }
-
-node_ptr add_meter(node_ptr self,const Meter& m) { self->addMeter(m); return self;}
-node_ptr add_meter_1(node_ptr self,const std::string& meter_name, int min,int max, int color_change) { self->addMeter(Meter(meter_name,min,max,color_change)); return self;}
-node_ptr add_meter_2(node_ptr self,const std::string& meter_name, int min,int max) { self->addMeter(Meter(meter_name,min,max));return self; }
-
-node_ptr add_label(node_ptr self,const std::string& name, const std::string& value) { self->addLabel(Label(name,value)); return self; }
-node_ptr add_label_1(node_ptr self,const Label& label) { self->addLabel(label); return self; }
-node_ptr add_limit(node_ptr self,const std::string& name, int limit) { self->addLimit(Limit(name,limit)); return self;}
-node_ptr add_limit_1(node_ptr self,const Limit& limit) { self->addLimit(limit); return self;}
-node_ptr add_in_limit(node_ptr self,const std::string& name,const std::string& pathToNode,int tokens) { self->addInLimit(InLimit(name,pathToNode,tokens)); return self;}
-node_ptr add_in_limit_1(node_ptr self,const InLimit& inlimit) { self->addInLimit(inlimit); return self;}
-node_ptr add_time(node_ptr self,int hour, int minute) { self->addTime(ecf::TimeAttr(hour,minute));return self; }
-node_ptr add_time_1(node_ptr self,int hour, int minute, bool relative) { self->addTime(ecf::TimeAttr(hour,minute,relative)); return self;}
-node_ptr add_time_2(node_ptr self,const std::string& ts) { self->addTime(ecf::TimeAttr(TimeSeries::create(ts)));return self;}
-node_ptr add_time_3(node_ptr self,const ecf::TimeAttr& ts) { self->addTime(ts);return self;}
-node_ptr add_today(node_ptr self,int hour, int minute) { self->addToday(ecf::TodayAttr(hour,minute)); return self;}
-node_ptr add_today_1(node_ptr self,int hour, int minute, bool relative) { self->addToday(ecf::TodayAttr(hour,minute,relative)); return self;}
-node_ptr add_today_2(node_ptr self,const std::string& ts) { self->addToday(ecf::TodayAttr(TimeSeries::create(ts)));return self;}
-node_ptr add_today_3(node_ptr self,const ecf::TodayAttr& ts) { self->addToday(ts);return self;}
-node_ptr add_date(node_ptr self,int day, int month, int year) { self->addDate(DateAttr(day,month,year)); return self;}
-node_ptr add_date_1(node_ptr self,const DateAttr& d) { self->addDate(d); return self;}
-node_ptr add_day(node_ptr self,DayAttr::Day_t day ) { self->addDay(DayAttr(day)); return self;}
-node_ptr add_day_1(node_ptr self,const std::string& day ) { self->addDay(DayAttr(DayAttr::getDay(day))); return self;}
-node_ptr add_day_2(node_ptr self,const DayAttr& day ) { self->addDay(day); return self;}
-node_ptr add_autocancel(node_ptr self,int days ) { self->addAutoCancel(ecf::AutoCancelAttr(days)); return self;}
-node_ptr add_autocancel_1(node_ptr self,int hour, int min,bool relative) { self->addAutoCancel(ecf::AutoCancelAttr(hour,min,relative)); return self;}
-node_ptr add_autocancel_2(node_ptr self,const TimeSlot& ts,bool relative){ self->addAutoCancel(ecf::AutoCancelAttr(ts,relative)); return self;}
-node_ptr add_autocancel_3(node_ptr self, const ecf::AutoCancelAttr& attr){ self->addAutoCancel(attr); return self;}
-node_ptr add_zombie(node_ptr self, const ZombieAttr& attr){ self->addZombie(attr); return self;}
-
-node_ptr add_cron(node_ptr self,const ecf::CronAttr& attr) { self->addCron(attr); return self; }
-node_ptr add_late(node_ptr self,const ecf::LateAttr& attr) { self->addLate(attr); return self; }
-std::string get_state_change_time(node_ptr self,const std::string& format)
-{
- if (format == "iso_extended") return to_iso_extended_string(self->state_change_time());
- else if (format == "iso") return to_iso_string(self->state_change_time());
- return to_simple_string(self->state_change_time());
-}
-
-node_ptr add_defstatus(node_ptr self,DState::State s) { self->addDefStatus(s); return self; }
-
-node_ptr add_repeat_date(node_ptr self,const RepeatDate& d) { self->addRepeat(d); return self; }
-node_ptr add_repeat_integer(node_ptr self,const RepeatInteger& d) { self->addRepeat(d); return self; }
-node_ptr add_repeat_string(node_ptr self,const RepeatString& d) { self->addRepeat(d); return self; }
-node_ptr add_repeat_enum(node_ptr self,const RepeatEnumerated& d) { self->addRepeat(d); return self; }
-node_ptr add_repeat_day(node_ptr self,const RepeatDay& d) { self->addRepeat(d); return self; }
-
-node_ptr add_trigger(node_ptr self,const std::string& expr) { self->add_trigger(expr); return self; }
-node_ptr add_trigger_expr(node_ptr self,const Expression& expr) { self->add_trigger_expr(expr); return self; }
-node_ptr add_complete(node_ptr self,const std::string& expr) { self->add_complete(expr); return self; }
-node_ptr add_complete_expr(node_ptr self,const Expression& expr) { self->add_complete_expr(expr); return self; }
-node_ptr add_part_trigger(node_ptr self,const PartExpression& expr) { self->add_part_trigger(PartExpression(expr)); return self; }
-node_ptr add_part_trigger_1(node_ptr self,const std::string& expression) { self->add_part_trigger(PartExpression(expression)); return self;}
-node_ptr add_part_trigger_2(node_ptr self,const std::string& expression, bool and_expr) { self->add_part_trigger(PartExpression(expression,and_expr)); return self;}
-node_ptr add_part_complete(node_ptr self,const PartExpression& expr) { self->add_part_complete(PartExpression(expr)); return self; }
-node_ptr add_part_complete_1(node_ptr self,const std::string& expression) { self->add_part_complete(PartExpression(expression)); return self;}
-node_ptr add_part_complete_2(node_ptr self,const std::string& expression, bool and_expr){ self->add_part_complete(PartExpression(expression,and_expr)); return self;}
-bool evaluate_trigger(node_ptr self) { Ast* t = self->triggerAst(); if (t) return t->evaluate();return false;}
-bool evaluate_complete(node_ptr self) { Ast* t = self->completeAst(); if (t) return t->evaluate();return false;}
-
-static job_creation_ctrl_ptr makeJobCreationCtrl() { return boost::make_shared<JobCreationCtrl>();}
-
-void export_Node()
-{
- class_<JobCreationCtrl, boost::noncopyable, job_creation_ctrl_ptr >("JobCreationCtrl", DefsDoc::jobgenctrl_doc())
- .def("__init__",make_constructor(makeJobCreationCtrl), DefsDoc::jobgenctrl_doc())
- .def("set_node_path", &JobCreationCtrl::set_node_path, "The node we want to check job creation for. If no node specified check all tasks")
- .def("set_dir_for_job_creation", &JobCreationCtrl::set_dir_for_job_creation, "Specify directory, for job creation")
- .def("get_dir_for_job_creation", &JobCreationCtrl::dir_for_job_creation, return_value_policy<copy_const_reference>(), "Returns the directory set for job creation")
- .def("generate_temp_dir", &JobCreationCtrl::generate_temp_dir, "Automatically generated temporary directory for job creation. Directory written to stdout for information")
- .def("get_error_msg", &JobCreationCtrl::get_error_msg, return_value_policy<copy_const_reference>(),"Returns an error message generated during checking of job creation")
- ;
-
- // mimic PartExpression(const std::string& expression )
- // mimic PartExpression(const std::string& expression, bool andExpr /* true means AND , false means OR */ )
- // Use to adding large trigger and complete expressions
- class_<PartExpression>("PartExpression",DefsDoc::part_expression_doc(), init<std::string>())
- .def(init<std::string,bool>())
- .def(self == self ) // __eq__
- .def("get_expression", &PartExpression::expression, return_value_policy<copy_const_reference>(), "returns the part expression as a string")
- .def("and_expr", &PartExpression::andExpr)
- .def("or_expr", &PartExpression::orExpr)
- ;
-
- class_<Expression, boost::shared_ptr<Expression> >("Expression",DefsDoc::expression_doc(), init<std::string>() )
- .def(init<PartExpression>())
- .def(self == self ) // __eq__
- .def("__str__", &Expression::expression) // __str__
- .def("get_expression", &Expression::expression, "returns the complete expression as a string")
- .def("add", &Expression::add,"Add a part expression, the second and subsequent part expressions must have 'and/or' set")
- .add_property("parts", boost::python::range( &Expression::part_begin, &Expression::part_end),"Returns a list of PartExpression's" )
- ;
-
- // Turn off proxies by passing true as the NoProxy template parameter.
- // shared_ptrs don't need proxies because calls on one a copy of the
- // shared_ptr will affect all of them (duh!).
- class_<std::vector<node_ptr> >("NodeVec", "Hold a list of Nodes (i.e :term:`suite`, :term:`family` or :term:`task` s)")
- .def(vector_indexing_suite<std::vector<node_ptr> , true >()) ;
-
- // Note: we have have not added __setattr__, as it seems to interfere with
- // classes derived from Node. i.e calling self.fred = bill in the derived class
- // expects self to be of type Node.
- class_<Node, boost::noncopyable, node_ptr >("Node", DefsDoc::node_doc(), no_init)
- .def("name",&Node::name, return_value_policy<copy_const_reference>() )
- .def("add_trigger", &add_trigger, DefsDoc::add_trigger_doc())
- .def("add_trigger", &add_trigger_expr)
- .def("add_complete", &add_complete, DefsDoc::add_trigger_doc())
- .def("add_complete", &add_complete_expr)
- .def("add_part_trigger" ,&add_part_trigger, DefsDoc::add_trigger_doc())
- .def("add_part_trigger" ,&add_part_trigger_1 )
- .def("add_part_trigger" ,&add_part_trigger_2 )
- .def("add_part_complete",&add_part_complete, DefsDoc::add_trigger_doc())
- .def("add_part_complete",&add_part_complete_1 )
- .def("add_part_complete",&add_part_complete_2 )
- .def("evaluate_trigger", &evaluate_trigger ,"evaluate trigger expression")
- .def("evaluate_complete",&evaluate_complete ,"evaluate complete expression")
- .def("add_variable", &add_variable, DefsDoc::add_variable_doc())
- .def("add_variable", &add_variable_int)
- .def("add_variable", &add_variable_var)
- .def("add_variable", &add_variable_dict)
- .def("add_label", &add_label, DefsDoc::add_label_doc())
- .def("add_label", &add_label_1)
- .def("add_limit", &add_limit, DefsDoc::add_limit_doc())
- .def("add_limit", &add_limit_1)
- .def("add_inlimit", &add_in_limit,(bp::arg("limit_name"),bp::arg("path_to_node_containing_limit")="",bp::arg("tokens")=1),DefsDoc::add_inlimit_doc())
- .def("add_inlimit", &add_in_limit_1)
- .def("add_event", &add_event, DefsDoc::add_event_doc())
- .def("add_event", &add_event_1)
- .def("add_event", &add_event_2)
- .def("add_event", &add_event_3)
- .def("add_meter", &add_meter, DefsDoc::add_meter_doc())
- .def("add_meter", add_meter_1)
- .def("add_meter", add_meter_2)
- .def("add_date", &add_date, DefsDoc::add_date_doc() )
- .def("add_date", &add_date_1)
- .def("add_day", &add_day, DefsDoc::add_day_doc())
- .def("add_day", &add_day_1)
- .def("add_day", &add_day_2)
- .def("add_today", &add_today, DefsDoc::add_today_doc())
- .def("add_today", &add_today_1)
- .def("add_today", &add_today_2)
- .def("add_today", &add_today_3)
- .def("add_time", &add_time, DefsDoc::add_time_doc())
- .def("add_time", &add_time_1 )
- .def("add_time", &add_time_2 )
- .def("add_time", &add_time_3 )
- .def("add_cron", &add_cron, DefsDoc::add_cron_doc())
- .def("add_late", &add_late, DefsDoc::add_late_doc())
- .def("add_autocancel", &add_autocancel, DefsDoc::add_autocancel_doc())
- .def("add_autocancel", &add_autocancel_1)
- .def("add_autocancel", &add_autocancel_2)
- .def("add_autocancel", &add_autocancel_3)
- .def("add_verify", &Node::addVerify, DefsDoc::add_verify_doc())
- .def("add_repeat", &add_repeat_date, DefsDoc::add_repeat_date_doc())
- .def("add_repeat", &add_repeat_integer, DefsDoc::add_repeat_integer_doc())
- .def("add_repeat", &add_repeat_string, DefsDoc::add_repeat_string_doc())
- .def("add_repeat", &add_repeat_enum, DefsDoc::add_repeat_enumerated_doc() )
- .def("add_repeat", &add_repeat_day, DefsDoc::add_repeat_day_doc() )
- .def("add_defstatus", &add_defstatus, DefsDoc::add_defstatus_doc())
- .def("add_zombie", &add_zombie, NodeAttrDoc::zombie_doc())
- .def("delete_variable", &Node::deleteVariable )
- .def("delete_event", &Node::deleteEvent )
- .def("delete_meter", &Node::deleteMeter )
- .def("delete_label", &Node::deleteLabel )
- .def("delete_trigger", &Node::deleteTrigger )
- .def("delete_complete", &Node::deleteComplete )
- .def("delete_repeat", &Node::deleteRepeat )
- .def("delete_limit", &Node::deleteLimit )
- .def("delete_inlimit", &Node::deleteInlimit )
- .def("delete_time", &Node::deleteTime )
- .def("delete_time", &Node::delete_time )
- .def("delete_today", &Node::deleteToday )
- .def("delete_today", &Node::delete_today )
- .def("delete_date", &Node::deleteDate )
- .def("delete_date", &Node::delete_date )
- .def("delete_day", &Node::deleteDay )
- .def("delete_day", &Node::delete_day )
- .def("delete_cron", &Node::deleteCron )
- .def("delete_cron", &Node::delete_cron )
- .def("delete_zombie", &Node::deleteZombie )
- .def("delete_zombie", &Node::delete_zombie )
- .def("change_trigger", &Node::changeTrigger )
- .def("change_complete", &Node::changeComplete )
- .def("get_abs_node_path", &Node::absNodePath, DefsDoc::abs_node_path_doc())
- .def("has_time_dependencies", &Node::hasTimeDependencies)
- .def("update_generated_variables", &Node::update_generated_variables)
- .def("get_generated_variables", &Node::gen_variables, "returns a list of generated variables. Use ecflow.VariableList as return argument")
- .def("is_suspended", &Node::isSuspended, "Returns true if the :term:`node` is in a :term:`suspended` state")
- .def("find_variable", &Node::findVariable, return_value_policy<copy_const_reference>(), "Find :term:`variable` on the node only. Returns a object")
- .def("find_meter", &Node::findMeter, return_value_policy<copy_const_reference>(), "Find the :term:`meter` on the node only. Returns a object")
- .def("find_event", &Node::findEventByNameOrNumber,return_value_policy<copy_const_reference>(), "Find the :term:`event` on the node only. Returns a object")
- .def("find_label", &Node::find_label, return_value_policy<copy_const_reference>(), "Find the :term:`label` on the node only. Returns a object")
- .def("find_limit", &Node::find_limit , "Find the :term:`limit` on the node only. returns a limit ptr" )
- .def("find_node_up_the_tree",&Node::find_node_up_the_tree , "Search immediate node, then up the node hierarchy" )
- .def("get_state", &Node::state , "Returns the state of the node. This excludes the suspended state")
- .def("get_state_change_time",&get_state_change_time, (bp::arg("format")="iso_extended"), "Returns the time of the last state change as a string. Default format is iso_extended, (iso_extended, iso, simple)")
- .def("get_dstate", &Node::dstate, "Returns the state of node. This will include suspended state")
- .def("get_defstatus", &Node::defStatus )
- .def("get_repeat", &Node::repeat, return_value_policy<copy_const_reference>() )
- .def("get_late", &Node::get_late,return_internal_reference<>() )
- .def("get_autocancel", &Node::get_autocancel, return_internal_reference<>())
- .def("get_trigger", &Node::get_trigger, return_internal_reference<>() )
- .def("get_complete", &Node::get_complete, return_internal_reference<>() )
- .def("get_defs", get_defs, return_internal_reference<>() )
- .def("get_parent", &Node::parent, return_internal_reference<>() )
- .add_property("meters", boost::python::range( &Node::meter_begin, &Node::meter_end) , "Returns a list of :term:`meter` s")
- .add_property("events", boost::python::range( &Node::event_begin, &Node::event_end) , "Returns a list of :term:`event` s")
- .add_property("variables", boost::python::range( &Node::variable_begin, &Node::variable_end),"Returns a list of user defined :term:`variable` s" )
- .add_property("labels", boost::python::range( &Node::label_begin, &Node::label_end) , "Returns a list of :term:`label` s")
- .add_property("limits", boost::python::range( &Node::limit_begin, &Node::limit_end), "Returns a list of :term:`limit` s" )
- .add_property("inlimits", boost::python::range( &Node::inlimit_begin, &Node::inlimit_end), "Returns a list of :term:`inlimit` s" )
- .add_property("verifies", boost::python::range( &Node::verify_begin, &Node::verify_end), "Returns a list of Verify's" )
- .add_property("times", boost::python::range( &Node::time_begin, &Node::time_end), "Returns a list of :term:`time` s" )
- .add_property("todays", boost::python::range( &Node::today_begin, &Node::today_end), "Returns a list of :term:`today` s" )
- .add_property("dates", boost::python::range( &Node::date_begin, &Node::date_end), "Returns a list of :term:`date` s" )
- .add_property("days", boost::python::range( &Node::day_begin, &Node::day_end), "Returns a list of :term:`day` s")
- .add_property("crons", boost::python::range( &Node::cron_begin, &Node::cron_end), "Returns a list of :term:`cron` s" )
- .add_property("zombies", boost::python::range( &Node::zombie_begin, &Node::zombie_end), "Returns a list of :term:`zombie` s" )
- ;
-}
diff --git a/ecflow_4_0_7/Pyext/src/ExportNodeAttr.cpp b/ecflow_4_0_7/Pyext/src/ExportNodeAttr.cpp
deleted file mode 100644
index 4cb52fb..0000000
--- a/ecflow_4_0_7/Pyext/src/ExportNodeAttr.cpp
+++ /dev/null
@@ -1,386 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #53 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/python.hpp>
-#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
-#include <boost/make_shared.hpp>
-
-#include "NodeAttr.hpp"
-#include "Limit.hpp"
-#include "InLimit.hpp"
-#include "Variable.hpp"
-#include "ClockAttr.hpp"
-#include "CronAttr.hpp"
-#include "DateAttr.hpp"
-#include "DayAttr.hpp"
-#include "LateAttr.hpp"
-#include "RepeatAttr.hpp"
-#include "TimeAttr.hpp"
-#include "TodayAttr.hpp"
-#include "VerifyAttr.hpp"
-#include "AutoCancelAttr.hpp"
-#include "ZombieAttr.hpp"
-#include "NodeAttrDoc.hpp"
-#include "BoostPythonUtil.hpp"
-
-using namespace ecf;
-using namespace boost::python;
-using namespace std;
-namespace bp = boost::python;
-
-// See: http://wiki.python.org/moin/boost.python/HowTo#boost.function_objects
-
-void add_time_series_3(CronAttr* self,const std::string& ts) { self->addTimeSeries(TimeSeries::create(ts));}
-
-void set_week_days(CronAttr* cron,const boost::python::list& list)
-{
- std::vector<int> int_vec;
- BoostPythonUtil::list_to_int_vec(list,int_vec);
- cron->addWeekDays(int_vec);
-}
-
-void set_days_of_month(CronAttr* cron,const boost::python::list& list)
-{
- std::vector<int> int_vec;
- BoostPythonUtil::list_to_int_vec(list,int_vec);
- cron->addDaysOfMonth(int_vec);
-}
-
-void set_months(CronAttr* cron,const boost::python::list& list)
-{
- std::vector<int> int_vec;
- BoostPythonUtil::list_to_int_vec(list,int_vec);
- cron->addMonths(int_vec);
-}
-
-// Create as shared because: we want to pass a Python list as part of the constructor,
-// *AND* the only way make_constructor works is with a pointer.
-// The Node::add function seem to cope with this, some boost python magic,must do a conversion
-// from shared_ptr to pass by reference
-static boost::shared_ptr<RepeatEnumerated> create_RepeatEnumerated(const std::string& name, const boost::python::list& list)
-{
- std::vector<std::string> vec;
- BoostPythonUtil::list_to_str_vec(list,vec);
- return boost::make_shared<RepeatEnumerated>( name,vec );
-}
-static boost::shared_ptr<RepeatString> create_RepeatString(const std::string& name, const boost::python::list& list)
-{
- std::vector<std::string> vec;
- BoostPythonUtil::list_to_str_vec(list,vec);
- return boost::make_shared<RepeatString>( name,vec );
-}
-
-static boost::shared_ptr<ZombieAttr> create_ZombieAttr(Child::ZombieType zt,const boost::python::list& list,User::Action uc,int life_time_in_server)
-{
- std::vector<Child::CmdType> vec;
- int the_list_size = len(list);
- vec.reserve(the_list_size);
- for (int i = 0; i < the_list_size; ++i) {
- vec.push_back(boost::python::extract<Child::CmdType>(list[i]));
- }
-
- return boost::make_shared<ZombieAttr>(zt,vec,uc,life_time_in_server );
-}
-
-void export_NodeAttr()
-{
- enum_<Child::ZombieType>("ZombieType", NodeAttrDoc::zombie_type_doc())
- .value("ecf", Child::ECF)
- .value("user", Child::USER)
- .value("path", Child::PATH)
- ;
-
- enum_<User::Action>("ZombieUserActionType",NodeAttrDoc::zombie_user_action_type_doc())
- .value("fob", User::FOB)
- .value("fail", User::FAIL)
- .value("remove", User::REMOVE)
- .value("adopt", User::ADOPT)
- .value("block", User::BLOCK)
- .value("kill", User::KILL)
- ;
-
- enum_<Child::CmdType>("ChildCmdType",NodeAttrDoc::child_cmd_type_doc())
- .value("init", Child::INIT)
- .value("event", Child::EVENT)
- .value("meter", Child::METER)
- .value("label", Child::LABEL)
- .value("wait", Child::WAIT)
- .value("abort", Child::ABORT)
- .value("complete",Child::COMPLETE)
- ;
-
- // ZombieAttr(ecf::Child::ZombieType t, const std::vector<ecf::Child::CmdType>& c, ecf::User::Action a, int zombie_lifetime);
- class_<ZombieAttr>("ZombieAttr",NodeAttrDoc::zombie_doc())
- .def("__init__",make_constructor(&create_ZombieAttr) )
- .def("__str__", &ZombieAttr::toString) // __str__
- .def(self == self ) // __eq__
- .def("empty", &ZombieAttr::empty, "Return true if the attribute is empty")
- .def("zombie_type", &ZombieAttr::zombie_type, "Returns the :term:`zombie type`")
- .def("user_action", &ZombieAttr::action, "The automated action to invoke, when zombies arise")
- .def("zombie_lifetime",&ZombieAttr::zombie_lifetime,"Returns the lifetime in seconds of :term:`zombie` in the server")
- .add_property( "child_cmds",boost::python::range(&ZombieAttr::child_begin,&ZombieAttr::child_end),"The list of child commands. If empty action applies to all child cmds")
- ;
-
- class_<Variable>("Variable",NodeAttrDoc::variable_doc(),init<std::string, std::string>())
- .def("__str__", &Variable::toString) // __str__
- .def(self == self ) // __eq__
- .def("name", &Variable::name, return_value_policy<copy_const_reference>(), "Return the variable name as string")
- .def("value", &Variable::theValue, return_value_policy<copy_const_reference>(), "Return the variable value as a string")
- .def("empty", &Variable::empty, "Return true if the variable is empty. Used when returning a Null variable, from a find")
- ;
-
- // We need to return pass a list of Variable as arguments, to retrieve the generated variables
- class_<std::vector<Variable> >("VariableList", "Hold a list of Variables")
- .def(vector_indexing_suite<std::vector<Variable> >()) ;
-
-
- class_<Label>("Label",NodeAttrDoc::label_doc(),init<std::string, std::string>())
- .def(self == self ) // __eq__
- .def("__str__", &Label::toString) // __str__
- .def("name", &Label::name, return_value_policy<copy_const_reference>(), "Return the :term:`label` name as string")
- .def("value", &Label::value, return_value_policy<copy_const_reference>(), "Return the original :term:`label` value as string")
- .def("new_value", &Label::new_value, return_value_policy<copy_const_reference>(), "Return the new label value as string")
- .def("empty", &Label::empty, "Return true if the Label is empty. Used when returning a NULL Label, from a find")
- ;
-
- class_<Limit, boost::shared_ptr<Limit> >("Limit",NodeAttrDoc::limit_doc(),init<std::string, int>())
- .def(self == self ) // __eq__
- .def("__str__", &Limit::toString) // __str__
- .def("name", &Limit::name, return_value_policy<copy_const_reference>(), "Return the :term:`limit` name as string")
- .def("value", &Limit::value, "The :term:`limit` token value as an integer")
- .def("limit", &Limit::theLimit, "The max value of the :term:`limit` as an integer")
- .add_property("node_paths", boost::python::range(&Limit::paths_begin,&Limit::paths_begin),"List of nodes(paths) that have consumed a limit")
- ;
-
- class_<InLimit>("InLimit",NodeAttrDoc::inlimit_doc(),init<std::string, std::string, optional<int> >())
- .def( init<std::string,std::string> () )
- .def( init<std::string> () )
- .def(self == self ) // __eq__
- .def("__str__", &InLimit::toString) // __str__
- .def("name", &InLimit::name, return_value_policy<copy_const_reference>(), "Return the :term:`inlimit` name as string")
- .def("path_to_node",&InLimit::pathToNode, return_value_policy<copy_const_reference>(), "Path to the node that holds the limit, can be empty")
- .def("tokens", &InLimit::tokens, "The number of token to consume from the Limit")
- ;
-
- class_<Event>("Event",NodeAttrDoc::event_doc(), init<int, optional<std::string> >())
- .def( init<std::string> () )
- .def(self == self ) // __eq__
- .def("__str__", &Event::toString) // __str__
- .def("name", &Event::name, return_value_policy<copy_const_reference>(), "Return the Events name as string. If number supplied name may be empty.")
- .def("number", &Event::number, "Return events number as a integer. if not specified return max integer value")
- .def("value", &Event::value, "Return events current value")
- .def("empty", &Event::empty, "Return true if the Event is empty. Used when returning a NULL Event, from a find")
- ;
-
- class_<Meter>("Meter",NodeAttrDoc::meter_doc(),init<std::string,int,int,optional<int> >())
- .def(self == self ) // __eq__
- .def("__str__", &Meter::toString) // __str__
- .def("name", &Meter::name, return_value_policy<copy_const_reference>(), "Return the Meters name as string")
- .def("min", &Meter::min, "Return the Meters minimum value")
- .def("max", &Meter::max, "Return the Meters maximum value")
- .def("value", &Meter::value, "Return meters current value")
- .def("color_change",&Meter::colorChange, "returns the color change")
- .def("empty", &Meter::empty, "Return true if the Meter is empty. Used when returning a NULL Meter, from a find")
- ;
-
- class_<DateAttr>("Date",NodeAttrDoc::date_doc() ,init<int,int,int>()) // day,month,year
- .def(self == self ) // __eq__
- .def("__str__", &DateAttr::toString) // __str__
- .def("day", &DateAttr::day, "Return the day. The range is 0-31, 0 means its wild-carded")
- .def("month", &DateAttr::month, "Return the month. The range is 0-12, 0 means its wild-carded")
- .def("year", &DateAttr::year, "Return the year, 0 means its wild-carded")
- ;
-
- enum_<DayAttr::Day_t>("Days",NodeAttrDoc::days_enum_doc())
- .value("sunday", DayAttr::SUNDAY)
- .value("monday", DayAttr::MONDAY)
- .value("tuesday", DayAttr::TUESDAY)
- .value("wednesday",DayAttr::WEDNESDAY)
- .value("thursday", DayAttr::THURSDAY)
- .value("friday", DayAttr::FRIDAY)
- .value("saturday", DayAttr::SATURDAY);
-
- class_<DayAttr>("Day",NodeAttrDoc::day_doc(),init<DayAttr::Day_t>() )
- .def(self == self ) // __eq__
- .def("__str__", &DayAttr::toString) // __str__
- .def("day", &DayAttr::day, "Return the day as enumerator")
- ;
-
- class_<TimeAttr>("Time",NodeAttrDoc::time_doc() ,init<TimeSlot, optional<bool> >())
- .def( init<int,int,optional<bool> >()) // hour, minute, relative
- .def( init<TimeSeries>())
- .def( init<TimeSlot,TimeSlot,TimeSlot,bool>())
- .def(self == self ) // __eq__
- .def("__str__", &TimeAttr::toString) // __str__
- .def("time_series",&TimeAttr::time_series,return_value_policy<copy_const_reference>(), "Return the Time attributes time series")
- ;
-
- class_<TodayAttr>("Today",NodeAttrDoc::today_doc() ,init<TimeSlot, optional<bool> >())
- .def( init<int,int,optional<bool> >()) // hour, minute, relative
- .def( init<TimeSeries>())
- .def( init<TimeSlot,TimeSlot,TimeSlot,bool>())
- .def(self == self ) // __eq__
- .def("__str__", &TodayAttr::toString) // __str__
- .def("time_series",&TodayAttr::time_series,return_value_policy<copy_const_reference>(), "Return the Todays time series")
- ;
-
-
- class_<LateAttr, boost::shared_ptr<LateAttr> >("Late",NodeAttrDoc::late_doc())
- .def( "submitted", &LateAttr::addSubmitted,
- "submitted(TimeSlot):The time node can stay :term:`submitted`. Submitted is always relative. If the node stays\n"
- "submitted longer than the time specified, the :term:`late` flag is set\n"
- )
- .def( "submitted", &LateAttr::add_submitted,
- "submitted(hour,minute) The time node can stay submitted. Submitted is always relative. If the node stays\n"
- "submitted longer than the time specified, the late flag is set\n"
- )
- .def( "active", &LateAttr::add_active,
- "active(hour,minute): The time the node must become :term:`active`. If the node is still :term:`queued` or :term:`submitted`\n"
- "by the time specified, the late flag is set"
- )
- .def( "active", &LateAttr::addActive,
- "active(TimeSlot):The time the node must become :term:`active`. If the node is still :term:`queued` or :term:`submitted`\n"
- "by the time specified, the late flag is set"
- )
- .def( "complete", &LateAttr::add_complete,
- "complete(hour,minute):The time the node must become :term:`complete`. If relative, time is taken from the time\n"
- "the node became :term:`active`, otherwise node must be :term:`complete` by the time given"
- )
- .def( "complete", &LateAttr::addComplete,
- "complete(TimeSlot): The time the node must become :term:`complete`. If relative, time is taken from the time\n"
- "the node became :term:`active`, otherwise node must be :term:`complete` by the time given"
- )
- .def(self == self ) // __eq__
- .def("__str__", &LateAttr::toString) // __str__
- .def("submitted", &LateAttr::submitted,return_value_policy<copy_const_reference>(), "Return the submitted time as a TimeSlot")
- .def("active", &LateAttr::active, return_value_policy<copy_const_reference>(), "Return the active time as a TimeSlot")
- .def("complete", &LateAttr::complete, return_value_policy<copy_const_reference>(), "Return the complete time as a TimeSlot")
- .def("complete_is_relative", &LateAttr::complete_is_relative, "Returns a boolean where true means that complete is relative")
- .def("is_late", &LateAttr::isLate, "Return True if late")
- ;
-
-
- class_<AutoCancelAttr, boost::shared_ptr<AutoCancelAttr> >(
- "Autocancel",NodeAttrDoc::autocancel_doc() ,
- init<int,int,bool >() // hour, minute, relative
- )
- .def( init<int>()) // days
- .def( init<TimeSlot, bool>())
- .def(self == self ) // __eq__
- .def("__str__", &AutoCancelAttr::toString) // __str__
- .def("time", &AutoCancelAttr::time, return_value_policy<copy_const_reference>(), "returns cancel time as a TimeSlot")
- .def("relative",&AutoCancelAttr::relative, "Returns a boolean where true means the time is relative")
- .def("days", &AutoCancelAttr::days, "Returns a boolean true if time was specified in days")
- ;
-
-
- class_<RepeatDate >("RepeatDate",NodeAttrDoc::repeat_date_doc() ,init< std::string, int, int, optional<int> >()) // name, start, end , delta
- .def(self == self ) // __eq__
- .def("__str__", &RepeatDate::toString) // __str__
- .def("name", &RepeatDate::name, return_value_policy<copy_const_reference>(),"Return the name of the repeat.")
- .def("start", &RepeatDate::start ,"Return the start date as an integer in yyyymmdd format")
- .def("end", &RepeatDate::end, "Return the end date as an integer in yyyymmdd format")
- .def("step", &RepeatDate::step, "Return the step increment. This is used to update the repeat, until end date is reached")
- ;
-
- class_<RepeatInteger>("RepeatInteger",NodeAttrDoc::repeat_integer_doc(),init< std::string, int, int, optional<int> >()) // name, start, end , delta = 1
- .def(self == self ) // __eq__
- .def("__str__", &RepeatInteger::toString) // __str__
- .def("name", &RepeatInteger::name, return_value_policy<copy_const_reference>(),"Return the name of the repeat.")
- .def("start", &RepeatInteger::start)
- .def("end", &RepeatInteger::end)
- .def("step", &RepeatInteger::step)
- ;
-
- // Create as shared because: we want to pass a Python list as part of the constructor,
- // and the only way make_constructor works is with a pointer.
- class_<RepeatEnumerated, boost::shared_ptr<RepeatEnumerated> >("RepeatEnumerated",NodeAttrDoc::repeat_enumerated_doc())
- .def("__init__",make_constructor(&create_RepeatEnumerated) )
- .def(self == self ) // __eq__
- .def("__str__", &RepeatEnumerated::toString) // __str__
- .def("name", &RepeatEnumerated::name, return_value_policy<copy_const_reference>(),"Return the name of the :term:`repeat`.")
- .def("start", &RepeatEnumerated::start)
- .def("end", &RepeatEnumerated::end)
- .def("step", &RepeatEnumerated::step)
- ;
-
- class_<RepeatString,boost::shared_ptr<RepeatString> >("RepeatString", NodeAttrDoc::repeat_string_doc())
- .def("__init__",make_constructor(&create_RepeatString) )
- .def(self == self ) // __eq__
- .def("__str__", &RepeatString::toString) // __str__
- .def("name", &RepeatString::name, return_value_policy<copy_const_reference>(),"Return the name of the :term:`repeat`.")
- .def("start", &RepeatString::start)
- .def("end", &RepeatString::end)
- .def("step", &RepeatString::step)
- ;
-
- class_<RepeatDay>("RepeatDay",NodeAttrDoc::repeat_day_doc(),init< optional<int> >())
- .def(self == self ) // __eq__
- .def("__str__", &RepeatDay::toString) // __str__
- ;
-
- class_<Repeat>("Repeat",NodeAttrDoc::repeat_doc() ,init< int >())
- .def(self == self ) // __eq__
- .def("__str__", &Repeat::toString) // __str__
- .def("empty", &Repeat::empty ,"Return true if the repeat is empty.")
- .def("name", &Repeat::name, return_value_policy<copy_const_reference>(), "The :term:`repeat` name, can be referenced in :term:`trigger` expressions")
- .def("start", &Repeat::start,"The start value of the repeat, as an integer")
- .def("end", &Repeat::end, "The last value of the repeat, as an integer")
- .def("step", &Repeat::step, "The increment for the repeat, as an integer")
- .def("value", &Repeat::last_valid_value,"The current value of the repeat as an integer")
- ;
-
-
- void (CronAttr::*add_time_series)(const TimeSeries&) = &CronAttr::addTimeSeries;
- void (CronAttr::*add_time_series_2)( const TimeSlot& s, const TimeSlot& f, const TimeSlot& i) = &CronAttr::addTimeSeries;
- class_<CronAttr>("Cron",NodeAttrDoc::cron_doc() )
- .def(self == self ) // __eq__
- .def("__str__", &CronAttr::toString) // __str__
- .def( "set_week_days", &set_week_days , "Specifies days of week. Expects a list of integers, with integer range 0==Sun to 6==Sat")
- .def( "set_days_of_month", &set_days_of_month,"Specifies days of the month. Expects a list of integers with integer range 1-31" )
- .def( "set_months", &set_months , "Specifies months. Expects a list of integers, with integer range 1-12")
- .def( "set_time_series", &CronAttr::add_time_series,(bp::arg("hour"),bp::arg("minute"),bp::arg("relative")=false),"time_series(hour(int),minute(int),relative to suite start(bool=false)), Add a time slot")
- .def( "set_time_series", add_time_series, "Add a time series. This will never complete")
- .def( "set_time_series", add_time_series_2, "Add a time series. This will never complete")
- .def( "set_time_series", &add_time_series_3,"Add a time series. This will never complete")
- .def( "time", &CronAttr::time, return_value_policy<copy_const_reference>(), "return cron time as a TimeSeries")
- .add_property( "week_days", boost::python::range(&CronAttr::week_days_begin, &CronAttr::week_days_end), "returns a integer list of week days")
- .add_property( "days_of_month",boost::python::range(&CronAttr::days_of_month_begin,&CronAttr::days_of_month_end), "returns a integer list of days of the month")
- .add_property( "months", boost::python::range(&CronAttr::months_begin, &CronAttr::months_end), "returns a integer list of months of the year")
- ;
-
-
- class_<VerifyAttr>("Verify", init<NState::State,int>()) // state, expected
- .def(self == self ) // __eq__
- .def("__str__", &VerifyAttr::toString) // __str__
- ;
-
-
- void (ClockAttr::*start_stop_with_server)(bool) = &ClockAttr::startStopWithServer;
- class_<ClockAttr, boost::shared_ptr<ClockAttr> >("Clock",NodeAttrDoc::clock_doc() ,init<int,int,int,optional<bool> > ()) // day, month, year, hybrid
- .def( init<int,int,int,bool>())
- .def( init<bool>())
- .def(self == self ) // __eq__
- .def("__str__", &ClockAttr::toString) // __str__
- .def( "set_gain_in_seconds",&ClockAttr::set_gain_in_seconds, "Set the gain in seconds")
- .def( "set_gain", &ClockAttr::set_gain, "Set the gain in hours and minutes")
- .def( "set_virtual", start_stop_with_server, "Sets/unsets the clock as being virtual")
- .def( "day", &ClockAttr::day, "Returns the day as an integer, range 1-31")
- .def( "month", &ClockAttr::month, "Returns the month as an integer, range 1-12")
- .def( "year", &ClockAttr::year, "Returns the year as an integer, > 1400")
- .def( "gain", &ClockAttr::gain, "Returns the gain as an long. This represents seconds")
- .def( "positive_gain",&ClockAttr::positive_gain,"Returns a boolean, where true means that the gain is positive")
- .def( "virtual" ,&ClockAttr::is_virtual, "Returns a boolean, where true means that clock is virtual")
- ;
-}
diff --git a/ecflow_4_0_7/Pyext/src/ExportSuiteAndFamily.cpp b/ecflow_4_0_7/Pyext/src/ExportSuiteAndFamily.cpp
deleted file mode 100644
index c6fbde4..0000000
--- a/ecflow_4_0_7/Pyext/src/ExportSuiteAndFamily.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #85 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/python.hpp>
-#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
-
-#include <boost/shared_ptr.hpp>
-#include <boost/make_shared.hpp>
-#include <boost/enable_shared_from_this.hpp>
-#include <boost/noncopyable.hpp>
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "BoostPythonUtil.hpp"
-
-#include "DefsDoc.hpp"
-
-using namespace ecf;
-using namespace boost::python;
-using namespace std;
-namespace bp = boost::python;
-
-// See: http://wiki.python.org/moin/boost.python/HowTo#boost.function_objects
-
-/// Since we don't pass in a child pos, the nodes are added to the end
-void add_family(NodeContainer* self,family_ptr f){ self->addFamily(f); }
-void add_task(NodeContainer* self,task_ptr t){ self->addTask(t); }
-
-suite_ptr add_clock(suite_ptr self, const ClockAttr& clk) { self->addClock(clk); return self;}
-
-// Context management, Only used to provide indentation
-suite_ptr suite_enter(suite_ptr self) { return self;}
-bool suite_exit(suite_ptr self,const boost::python::object& type,const boost::python::object& value,const boost::python::object& traceback){return false;}
-family_ptr family_enter(family_ptr self) { return self;}
-bool family_exit(family_ptr self,const boost::python::object& type,const boost::python::object& value,const boost::python::object& traceback){return false;}
-
-
-void export_SuiteAndFamily()
-{
- // Turn off proxies by passing true as the NoProxy template parameter.
- // shared_ptrs don't need proxies because calls on one a copy of the
- // shared_ptr will affect all of them (duh!).
- class_<std::vector<family_ptr> >("FamilyVec","Hold a list of :term:`family` nodes")
- .def(vector_indexing_suite<std::vector<family_ptr>, true >()) ;
-
- class_<std::vector<suite_ptr> >("SuiteVec","Hold a list of :term:`suite` nodes's")
- .def(vector_indexing_suite<std::vector<suite_ptr>, true >());
-
- // choose the correct overload
- class_<NodeContainer, bases<Node>, boost::noncopyable >("NodeContainer",DefsDoc::node_container_doc(), no_init)
- .def("add_family",&NodeContainer::add_family ,DefsDoc::add_family_doc())
- .def("add_family",add_family )
- .def("add_task", &NodeContainer::add_task , DefsDoc::add_task_doc())
- .def("add_task", add_task )
- .add_property("nodes",boost::python::range( &NodeContainer::node_begin,&NodeContainer::node_end),"Returns a list of Node's")
- ;
-
-
- class_<Family, bases<NodeContainer>, family_ptr, boost::noncopyable>("Family",DefsDoc::family_doc())
- .def("__init__",make_constructor(&Family::create), DefsDoc::family_doc())
- .def(self == self ) // __eq__
- .def("__str__", &Family::to_string) // __str__
- .def("__enter__", &family_enter) // allow with statement, hence indentation support
- .def("__exit__", &family_exit) // allow with statement, hence indentation support
- ;
-
-
- class_<Suite, bases<NodeContainer>, suite_ptr, boost::noncopyable>("Suite",DefsDoc::suite_doc())
- .def("__init__",make_constructor(&Suite::create), DefsDoc::suite_doc())
- .def(self == self ) // __eq__
- .def("__str__", &Suite::to_string) // __str__
- .def("__enter__", &suite_enter) // allow with statement, hence indentation support
- .def("__exit__", &suite_exit) // allow with statement, hence indentation support
- .def("add_clock", &add_clock)
- .def("get_clock", &Suite::clockAttr,"Returns the :term:`suite` :term:`clock`")
- .def("begun", &Suite::begun, "Returns true if the :term:`suite` has begun, false otherwise")
- ;
-}
diff --git a/ecflow_4_0_7/Pyext/src/ExportTask.cpp b/ecflow_4_0_7/Pyext/src/ExportTask.cpp
deleted file mode 100644
index f1406d3..0000000
--- a/ecflow_4_0_7/Pyext/src/ExportTask.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #85 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/python.hpp>
-#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
-
-#include <boost/shared_ptr.hpp>
-#include <boost/make_shared.hpp>
-#include <boost/enable_shared_from_this.hpp>
-#include <boost/noncopyable.hpp>
-
-#include "Task.hpp"
-#include "DefsDoc.hpp"
-
-using namespace ecf;
-using namespace boost::python;
-using namespace std;
-namespace bp = boost::python;
-
-task_ptr task_enter(task_ptr self) { return self;}
-bool task_exit(task_ptr self,const boost::python::object& type,const boost::python::object& value,const boost::python::object& traceback){return false;}
-
-// See: http://wiki.python.org/moin/boost.python/HowTo#boost.function_objects
-
-void export_Task()
-{
- // Turn off proxies by passing true as the NoProxy template parameter.
- // shared_ptrs don't need proxies because calls on one a copy of the
- // shared_ptr will affect all of them (duh!).
- class_<std::vector<task_ptr> >("TaskVec","Hold a list of :term:`task` nodes")
- .def(vector_indexing_suite<std::vector<task_ptr>, true >()) ;
-
- class_<Submittable, bases<Node>, boost::noncopyable >("Submittable",DefsDoc::submittable_doc(), no_init)
- .def("get_jobs_password" , &Submittable::jobsPassword, return_value_policy<copy_const_reference>(), "The password. This generated by server")
- .def("get_process_or_remote_id",&Submittable::process_or_remote_id, return_value_policy<copy_const_reference>(),"The process or remote id of the running job")
- .def("get_try_no" , &Submittable::tryNo, "The current try number as a string.")
- .def("get_int_try_no" , &Submittable::try_no, "The current try number as integer.")
- .def("get_aborted_reason" , &Submittable::abortedReason,return_value_policy<copy_const_reference>(), "If node was aborted and a reason was provided, return the string")
- ;
-
- class_<Task, bases<Submittable>, task_ptr, boost::noncopyable>("Task",DefsDoc::task_doc() )
- .def("__init__",make_constructor(&Task::create), DefsDoc::task_doc())
- .def(self == self ) // __eq__
- .def("__enter__", &task_enter) // allow with statement, hence indentation support
- .def("__exit__", &task_exit) // allow with statement, hence indentation support
- .def("__str__", &Task::to_string) // __str__
- .add_property("aliases",boost::python::range( &Task::alias_begin, &Task::alias_end), "Returns a list of aliases")
- .add_property("nodes", boost::python::range( &Task::alias_begin, &Task::alias_end), "Returns a list of aliases")
- ;
-
- class_<Alias, bases<Submittable>, alias_ptr, boost::noncopyable>("Alias",DefsDoc::alias_doc(),no_init)
- .def(self == self ) // __eq__
- .def("__str__", &Alias::to_string) // __str__
- ;
-}
diff --git a/ecflow_4_0_7/Pyext/src/NodeAttrDoc.cpp b/ecflow_4_0_7/Pyext/src/NodeAttrDoc.cpp
deleted file mode 100644
index df7d6d5..0000000
--- a/ecflow_4_0_7/Pyext/src/NodeAttrDoc.cpp
+++ /dev/null
@@ -1,567 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #36 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : This class is used as a helper class
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include "NodeAttrDoc.hpp"
-
-const char* NodeAttrDoc::variable_doc()
-{
- return
- "Defines a :term:`variable` on a :term:`node` for use in :term:`ecf script`.\n\n"
- "A Node can have a number of variables.\n"
- "These variables can be added at any node level: :term:`suite`, :term:`family` or :term:`task`.\n"
- "The variables are names inside a pair of '%' characters in an :term:`ecf script`.\n"
- "The content of a variable replaces the variable name in the :term:`ecf script` at\n"
- "job submission time. When a variable is needed at submission time, it is first\n"
- "sought in the task itself. If it is not found, it is sought from the tasks parent\n"
- "and so on, up through the node levels until found. See :term:`variable inheritance`\n"
- "A undefined variable in a :term:`ecf script`, causes the :term:`task` to be :term:`aborted`,\n"
- "without the job being submitted.\n"
- "\nConstructor::\n\n"
- " Variable(name,value)\n"
- " string name: the name of the variable\n"
- " string value: The value of the variable\n"
- "\nUsage::\n\n"
- " ..."
- " var = Variable(\"ECF_JOB_CMD\",\"/bin/sh %ECF_JOB% &\")\n"
- " task.add_variable(var)\n"
- " task.add_variable('JOE','90')\n"
- ;
-}
-
-const char* NodeAttrDoc::zombie_doc()
-{
- return
- "The :term:`zombie` attribute defines how a :term:`zombie` should be handled in an automated fashion\n\n"
- "Very careful consideration should be taken before this attribute is added\n"
- "as it may hide a genuine problem.\n"
- "It can be added to any :term:`node`. But is best defined at the :term:`suite` or :term:`family` level.\n"
- "If there is no zombie attribute the default behaviour is to block the init,complete,abort :term:`child command`.\n"
- "and *fob* the event,label,and meter :term:`child command`\n"
- "This attribute allows the server to make a automated response\n"
- "Please see: :py:class:`ecflow.ZombieType`, :py:class:`ecflow.ChildCmdType`, :py:class:`ecflow.ZombieUserActionType`\n"
- "\nConstructor::\n\n"
- " ZombieAttr(ZombieType,ChildCmdTypes, ZombieUserActionType, lifetime)\n"
- " ZombieType : Must be one of ZombieType.ecf, ZombieType.path, ZombieType.user\n"
- " ChildCmdType : A list(ChildCmdType) of Child commands. Can be left empty in\n"
- " which case the action affect all child commands\n"
- " ZombieUserActionType : One of [ fob, fail, block, remove, adopt ]\n"
- " int lifetime : Defines the life time in seconds of the zombie in the server.\n"
- " On expiration, zombie is removed automatically\n"
- "\nUsage::\n\n"
- " # Add a zombie attribute so that child label commands(i.e ecflow_client --label)\n"
- " # never block the job\n"
- " s1 = ecflow.Suite('s1')\n"
- " child_list = [ ChildCmdType.label ]\n"
- " zombie_attr = ZombieAttr(ZombieType.ecf, child_list, ZombieUserActionType.fob, 300)\n"
- " s1.add_zombie(zombie_attr)\n"
- ;
-}
-
-const char* NodeAttrDoc::zombie_type_doc()
-{
- return
- ":term:`zombie` s are running jobs that fail authentication when communicating with the :term:`ecflow_server`.\n\n"
- "See class :term:`zombie type` and :py:class:`ecflow.ZombieAttr` for further information.\n"
- ;
-}
-
-const char* NodeAttrDoc::zombie_user_action_type_doc()
-{
- return
- "ZombieUserActionType is used define an automated response. See class :py:class:`ZombieAttr`\n\n"
- "This can be either on the client side or on the server side\n"
- "\nclient side:\n\n"
- "- fob: The :term:`child command` always succeeds, i.e allowed to complete without blocking\n"
- "- fail: The :term:`child command` is asked to fail.\n"
- "- block: The :term:`child command` is asked to block. This is the default action for all child commands\n"
- "\nserver side:\n\n"
- "- adopt: Allows the password supplied with the :term:`child command` s, to be adopted by the server\n"
- "- kill: Kills the zombie process associated with the :term:`child command` using ECF_KILL_CMD.\n"
- " path zombies will need to be killed manually. If kill is specified for path zombies\n"
- " they will be fobed, i.e allowed to complete without blocking the job.\n"
- "- remove: :term:`ecflow_server` removes the :term:`zombie` from the zombie list.\n"
- " The child continues blocking. The :term:`zombie` may well re-appear\n\n"
- "Note: Only adopt will allow the :term:`child command` to continue and change the :term:`node` tree\n"
- ;
-}
-
-const char* NodeAttrDoc::child_cmd_type_doc()
-{
- return
- "ChildCmdType represents the different :term:`child command` s.\n"
- "This type is used as a parameter to the class :py:class:`ecflow.ZombieAttr`\n\n"
- "Child commands are called within a :term:`job file`::\n\n"
- " ChildCmdType::init corresponds to : ecflow_client --init=<process_id>\n"
- " ChildCmdType::event corresponds to : ecflow_client --event=<event_name | number>\n"
- " ChildCmdType::meter corresponds to : ecflow_client --meter=<meter_name>, <meter_value>\n"
- " ChildCmdType::label corresponds to : ecflow_client --label=<label_name>. <label_value>\n"
- " ChildCmdType::wait corresponds to : ecflow_client --wait=<expression>\n"
- " ChildCmdType::abort corresponds to : ecflow_client --abort=<reason>\n"
- " ChildCmdType::complete corresponds to : ecflow_client --complete\n"
- ;
-}
-
-const char* NodeAttrDoc::label_doc()
-{
- return
- "A :term:`label` has a name and value and provides a way of displaying information in a GUI.\n\n"
- "The value can be anything(ASCII) as it can not be used in triggers\n"
- "The value of the label is set to be the default value given in the definition\n"
- "when the :term:`suite` is begun. This is useful in repeated suites: A task sets the label\n"
- "to be something, e.g, the number of observations, and once the :term:`suite` is :term:`complete`\n"
- "and the next day starts) the number of observations is cleared.\n"
- "Labels can be set at any level: Suite,Family,Task\n"
- "There are two ways of updating the label\n"
- "- A :term:`child command` can be used to automatically update the label on a :term:`task`\n"
- "- By using the alter command, the labels on :term:`suite` :term:`family` and :term:`task` can be changed manually\n"
- "\nConstructor::\n\n"
- " Label(name,value)\n"
- " string name: The name of the label\n"
- " string value: The value of the label\n"
- "\nUsage::\n\n"
- " t1 = Task('t1')\n"
- " t1.add_label('l1','value')\n"
- " t1.add_label(Label('l2','value2'))\n"
- " for label in t1.labels:\n"
- " print label\n"
- ;
-}
-
-const char* NodeAttrDoc::limit_doc()
-{
- return
- ":term:`limit` provides a simple load management\n\n"
- "i.e. by limiting the number of :term:`task` s submitted by a server.\n"
- "Limits are typically defined at the :term:`suite` level, or defined in a\n"
- "separate suite, so that they can be used by multiple suites.\n"
- "Once a limit is defined in a :term:`suite definition`, you must also assign families/tasks to use\n"
- "this limit. See :term:`inlimit` and :py:class:`ecflow.InLimit`\n"
- "\nConstructor::\n\n"
- " Limit(name,value)\n"
- " string name: the name of the limit\n"
- " int value: The value of the limit\n"
- "\nUsage::\n\n"
- " limit = Limit(\"fast\", 10)\n"
- " ...\n"
- " suite.add_limit(limit)\n"
- ;
-}
-
-const char* NodeAttrDoc::inlimit_doc()
-{
- return
- ":term:`inlimit` is used in conjunction with :term:`limit` to provide simple load management::\n\n"
- " suite x\n"
- " limit fast 1\n"
- " family f\n"
- " inlimit /x:fast\n"
- " task t1\n"
- " task t2\n\n"
- "Here 'fast' is the name of limit and the number defines the maximum number of tasks\n"
- "that can run simultaneously using this limit. Thats why you do not need a :term:`trigger`\n"
- "between tasks 't1' and 't2'. There is no need to change the tasks. The jobs are\n"
- "created in the order they are defined\n"
- "\nConstructor::\n\n"
- " InLimit(name, optional<path = ''>, optional<token = 1>)\n"
- " string name : The name of the referenced Limit\n"
- " string path<optional> : The path to the Limit, if this is left out, then Limit of 'name' must be specified\n"
- " some where up the parent hierarchy\n"
- " int value<optional> : The usage of the Limit. Each job submission will consume 'value' tokens\n"
- " from the Limit. defaults to 1 if no value specified.\n"
- "\nUsage::\n\n"
- " inlimit = InLimit(\"fast\",\"/x/f\", 2)\n"
- " ...\n"
- " family.add_inlimit(inlimit)\n"
- ;
-}
-
-const char* NodeAttrDoc::event_doc()
-{
- return
- ":term:`event` s are used as signal mechanism.\n\n"
- "Typically they would be used to signal partial completion of a :term:`task`\n"
- "and to be able to :term:`trigger` another job, which is waiting for this partial completion.\n"
- "Only tasks can have events that are automatically set via a :term:`child command` s, see below.\n"
- "Events are cleared automatically when a :term:`node` is re-queued or begun.\n"
- "Suites and Families can have tasks, but these events must be set via the Alter command\n"
- "Multiple events can be added to a task.\n"
- "An Event has a number and a optional name. Events are typically used\n"
- "in :term:`trigger` and :term:`complete expression` , to control job creation.\n"
- "Event are fired within a :term:`job file`, i.e.::\n\n"
- " ecflow_client --init $$\n"
- " ecflow_client --event foo\n"
- " ecflow_client --complete\n\n"
- "Hence the defining of an event for a :term:`task`, should be followed with the addition of ecflow_client --event\n"
- ":term:`child command` in the corresponding :term:`ecf script` file.\n"
- "\nConstructor::\n\n"
- " Event(number, optional<name = ''>)\n"
- " int number : The number must be >= 0\n"
- " string name<optional> : If name is given, can only refer to Event by its name\n"
- "\nUsage::\n\n"
- " event = Event(2,\"event_name\")\n"
- " task.add_event(event)\n"
- " task1.add_event(\"2\") # create a event '1' and add to the task\n"
- " task2.add_event(\"name\") # create a event 'name' and add to task\n"
- ;
-}
-
-const char* NodeAttrDoc::meter_doc()
-{
- return
- ":term:`meter` s can be used to indicate proportional completion of :term:`task`\n\n"
- "They are able to :term:`trigger` another job, which is waiting on this proportion.\n"
- "Can also be used to indicate progress of a job. Meters can be used in\n"
- ":term:`trigger` and :term:`complete expression`.\n"
- "\nConstructor::\n\n"
- " Meter(name,min,max,<optional>color_change)\n"
- " string name : The meter name\n"
- " int min : The minimum and initial meter value\n"
- " int max : The maximum meter value. Must be greater than min value.\n"
- " int color_change<optional> : default = max, Must be between min-max, used in the GUI\n"
- "\nExceptions:\n\n"
- "- raises IndexError when an invalid Meter is specified\n"
- "\nUsage:\n\n"
- "Using a meter requires:\n\n"
- "- Defining a meter on a :term:`task`::\n\n"
- " meter = Meter(\"progress\",0,100,100)\n"
- " task.add_meter(meter)\n\n"
- "- Updating the corresponding :term:`ecf script` file with the meter :term:`child command`::\n\n"
- " ecflow_client --init=$$\n"
- " for i in 10 20 30 40 50 60 80 100; do\n"
- " ecflow_client --meter=progress $i\n"
- " sleep 2 # or do some work\n"
- " done\n"
- " ecflow_client --complete\n\n"
- "- Optionally addition in a :term:`trigger` or :term:`complete expression` for job control::\n\n"
- " trigger task:progress ge 60\n\n"
- " trigger and complete expression should *avoid* using equality i.e::\n\n"
- " trigger task:progress == 60\n\n"
- " Due to network issues the meter event's may **not** arrive in sequential order\n"
- " hence the :term:`ecflow_server` will ignore meter value's, which are less than the current value\n"
- " as a result triggers's which use meter equality may never evaluate\n"
- ;
-}
-
-const char* NodeAttrDoc::date_doc()
-{
- return
- "Used to define a :term:`date` dependency.\n\n"
- "There can be multiple Date dependencies for a :term:`node`.\n"
- "Any of the 3 attributes, i.e. day, month, year can be wild carded using a zero\n"
- "If a hybrid :term:`clock` is defined on a suite, any node held by a date dependency\n"
- "will be set to :term:`complete` at the beginning of the :term:`suite`, without the\n"
- "task ever being dispatched otherwise, the suite would never complete.\n"
- "\nConstructor::\n\n"
- " Date(day,month,year)\n"
- " int day : represents the day, zero means wild card. day >= 0 & day < 31\n"
- " int month : represents the month, zero means wild card. month >= 0 & month < 12\n"
- " int year : represents the year, zero means wild card. year >= 0\n"
- "\nExceptions:\n\n"
- "- raises IndexError when an invalid date is specified\n"
- "\nUsage::\n\n"
- " date = Date(11,12,2010) # represent 11th of December 2010\n"
- " date = Date(1,0,0); # means the first day of every month of every year\n"
- ;
-}
-
-const char* NodeAttrDoc::day_doc()
-{
- return
- "Defines a :term:`day` dependency.\n\n"
- "There can be multiple day dependencies. If a hybrid :term:`clock` is defined\n"
- "on a suite, any node held by a day dependency will be set to :term:`complete` at the\n"
- "beginning of the :term:`suite`, without the task ever being dispatched otherwise\n"
- "the suite would never complete.\n"
- "\nConstructor::\n\n"
- " Day(Days)\n"
- " Days day: Is an enumerator with represent the days of the week\n"
- "\nUsage::\n\n"
- " day1 = Day(Days.sunday)\n"
- " day2 = Day(Days.monday)\n"
- ;
-}
-
-const char* NodeAttrDoc::days_enum_doc()
-{
- return
- "This enum is used as argument to a :py:class:`ecflow.Day` class.\n\n"
- "It represents the days of the week\n"
- "\nUsage::\n\n"
- " day1 = Day(Days.sunday)\n"
- " day2 = Day(Days.monday)\n"
- " day3 = Day(Days.tuesday)\n"
- ;
-}
-
-const char* NodeAttrDoc::time_doc()
-{
- return
- "Is used to define a :term:`time` dependency\n\n"
- "This can then control job submission.\n"
- "There can be multiple time dependencies for a node, however overlapping times may\n"
- "cause unexpected results. The time dependency can be made relative to the beginning\n"
- "of the suite or in repeated families relative to the beginning of the repeated family.\n"
- "\nConstructor::\n\n"
- " Time(hour,minute,relative<optional> = false)\n"
- " int hour: hour in 24 clock\n"
- " int minute: minute <= 59\n"
- " bool relative<optional>: default = False, Relative to suite start or repeated node.\n\n"
- " Time(single,relative<optional> = false)\n"
- " TimeSlot single: A single time\n"
- " bool relative: Relative to suite start or repeated node. Default is false\n\n"
- " Time(start,finish,increment,relative<optional> = false)\n"
- " TimeSlot start: The start time\n"
- " TimeSlot finish: The finish/end time\n"
- " TimeSlot increment: The increment\n"
- " bool relative<optional>: default = False, relative to suite start or repeated node\n\n"
- " Time(time_series)\n"
- " TimeSeries time_series:Similar to constructor above\n"
- "\nExceptions:\n\n"
- "- raises IndexError when an invalid Time is specified\n"
- "\nUsage::\n\n"
- " time = Time( 10,10 ) # time 10:10 \n"
- " time = Time( TimeSlot(10,10), true) # time +10:10 \n"
- " time = Time( TimeSlot(10,10), TimeSlot(20,10),TimeSlot(0,10), false ) # time 10:10 20:10 00:10 \n"
- ;
-}
-
-const char* NodeAttrDoc::today_doc()
-{
- return
- ":term:`today` is a time dependency that does not wrap to tomorrow.\n\n"
- "If the :term:`suite` s begin time is past the time given for the Today,\n"
- "then the node is free to run.\n"
- "\nConstructor::\n\n"
- " Today(hour,minute,relative<optional> = false)\n"
- " int hour : hour in 24 clock\n"
- " int minute : minute <= 59\n"
- " bool relative<optional>: Default = false,Relative to suite start or repeated node.\n\n"
- " Today(single,relative<optional> = false)\n"
- " TimeSlot single : A single time\n"
- " bool relative : Relative to suite start or repeated node. Default is false\n\n"
- " Today(start,finish,increment,relative<optional> = false)\n"
- " TimeSlot start : The start time\n"
- " TimeSlot finish : The finish/end time. This must be greater than the start time.\n"
- " TimeSlot increment : The increment\n"
- " bool relative<optional>: Default = false, Relative to suite start or repeated node.\n\n"
- " Today(time_series)\n"
- " TimeSeries time_series: Similar to constructor above\n"
- "\nExceptions:\n\n"
- "- raises IndexError when an invalid Today is specified\n"
- "\nUsage::\n\n"
- " today = Today( 10,10 ) # today 10:10 \n"
- " today = Today( TimeSlot(10,10) ) # today 10:10 \n"
- " today = Today( TimeSlot(10,10), true) # today +10:10 \n"
- " today = Today( TimeSlot(10,10), TimeSlot(20,10),TimeSlot(0,10), false ) # time 10:10 20:10 00:10 \n"
- ;
-}
-
-const char* NodeAttrDoc::late_doc()
-{
- return
- "Sets the :term:`late` flag.\n\n"
- "When a Node is classified as being late, the only action :term:`ecflow_server` can take\n"
- "is to set a flag. The GUI will display this alongside the :term:`node` name as a icon.\n"
- "Only one Late attribute can be specified on a Node.\n"
- "\nConstructor::\n\n"
- " Late()\n"
- "\nUsage::\n\n"
- " late = Late()\n"
- " late.submitted( 0,15 )\n"
- " late.active( 20,0 )\n"
- " late.complete( 2,0, true )\n\n"
- "This is interpreted as: The node can stay :term:`submitted` for a maximum of 15 minutes\n"
- "and it must become :term:`active` by 20:00 and the run time must not exceed 2 hours"
- ;
-}
-
-const char* NodeAttrDoc::autocancel_doc()
-{
- return
- "Provides a way to automatically delete/remove a node which has completed\n\n"
- "See :term:`autocancel`\n"
- "\nConstructor::\n\n"
- " Autocancel(TimeSlot,relative)\n"
- " TimeSlot single: A time\n"
- " bool relative: Relative to completion. False means delete the node at the real time specified.\n\n"
- " Autocancel(hour,minute,relative)\n"
- " int hour: hour in 24 hrs\n"
- " int minute: minute <= 59\n"
- " bool relative: Relative to completion. False means delete the node at the real time specified.\n\n"
- " Autocancel(days)\n"
- " int days: Delete the node 'days' after completion\n"
- "\nUsage::\n\n"
- " attr = Autocancel( 1,30, true ) # delete node 1 hour and 30 minutes after completion\n"
- " attr = Autocancel( TimeSlot(0,10), true ) # delete node 10 minutes after completion\n"
- " attr = Autocancel( TimeSlot(10,10), false ) # delete node at 10:10 after completion\n"
- " attr = Autocancel( 3 ) # delete node 3 days after completion\n"
- ;
-}
-
-const char* NodeAttrDoc::repeat_doc()
-{
- return
- "Represents one of RepeatString,RepeatEnumerated,RepeatInteger,RepeatDate,RepeatDay\n\n"
- ;
-}
-
-const char* NodeAttrDoc::repeat_date_doc()
-{
- return
- "Allows a :term:`node` to be repeated using a yyyymmdd format\n\n"
- "A node can only have one :term:`repeat`.\n"
- "The repeat can be referenced in :term:`trigger` expressions.\n"
- "\nConstructor::\n\n"
- " RepeatDate(variable,start,end,delta)\n"
- " string variable: The name of the repeat. The current date can referenced in\n"
- " in trigger expressions using the variable name\n"
- " int start: Start date, must have format: yyyymmdd\n"
- " int end: End date, must have format: yyyymmdd\n"
- " int delta<optional>: default = 1, Always in days. The increment used to update the date\n"
- "\nException:\n\n"
- "- Throws a RuntimeError if start/end are not valid dates\n"
- "\nUsage::\n\n"
- " rep = RepeatDate(\"YMD\", 20050130, 20050203 )\n"
- " rep = RepeatDate(\"YMD\", 20050130, 20050203, 2 )\n"
- ;
-}
-
-const char* NodeAttrDoc::repeat_integer_doc()
-{
- return
- "Allows a :term:`node` to be repeated using a integer range.\n\n"
- "A node can only have one :term:`repeat`.\n"
- "The repeat can be referenced in :term:`trigger` expressions.\n"
- "\nConstructor::\n\n"
- " RepeatInteger(variable,start,end,step)\n"
- " string variable: The name of the repeat. The current integer value can be\n"
- " referenced in trigger expressions using the variable name\n"
- " int start: Start integer value\n"
- " int end: End end integer value\n"
- " int step<optional>: Default = 1, The step amount\n"
- "\nUsage::\n\n"
- " rep = RepeatInteger(\"HOUR\", 6, 24, 6 )\n"
- ;
-}
-
-const char* NodeAttrDoc::repeat_enumerated_doc()
-{
- return
- "Allows a node to be repeated using a enumerated list.\n\n"
- "A :term:`node` can only have one :term:`repeat`.\n"
- "The repeat can be referenced in :term:`trigger` expressions.\n"
- "\nConstructor::\n\n"
- " RepeatEnumerated(variable,list)\n"
- " string variable: The name of the repeat. The current enumeration index can be\n"
- " referenced in trigger expressions using the variable name\n"
- " vector list: The list of enumerations\n"
- "\nUsage::\n\n"
- " rep = RepeatEnumerated(\"COLOR\", [ 'red', 'green', 'blue' ] )\n"
- ;
-}
-
-const char* NodeAttrDoc::repeat_string_doc()
-{
- return
- "Allows a :term:`node` to be repeated using a string list.\n\n"
- "A :term:`node` can only have one :term:`repeat`.\n"
- "The repeat can be referenced in :term:`trigger` expressions.\n"
- "\nConstructor::\n\n"
- " RepeatString(variable,list)\n"
- " string variable: The name of the repeat. The current index of the string list can be\n"
- " referenced in trigger expressions using the variable name\n"
- " vector list: The list of enumerations\n"
- "\nUsage::\n\n"
- " rep = RepeatString(\"COLOR\", [ 'red', 'green', 'blue' ] )\n"
- ;
-}
-
-const char* NodeAttrDoc::repeat_day_doc()
-{
- return
- "A repeat that is infinite.\n\n"
- "A node can only have one :term:`repeat`.\n"
- "\nConstructor::\n\n"
- " RepeatDay(step)\n"
- " int step: The step.\n"
- "\nUsage::\n\n"
- " rep = RepeatDay( 1 )\n"
- ;
-}
-
-const char* NodeAttrDoc::cron_doc()
-{
- return
- ":term:`cron` defines a time dependency for a node.\n\n"
- "Crons are repeated indefinitely.\n\n"
- "Avoid having a cron and :term:`repeat` at the same level,\n"
- "as both provide looping functionality\n"
- "\nConstructor::\n\n"
- " Cron()\n"
- "\nExceptions:\n\n"
- "- raises IndexError when an invalid cron is specified\n"
- "\nUsage::\n\n"
- " cron = ecflow.Cron()\n"
- " cron.set_week_days([0, 1, 2, 3, 4, 5, 6])\n"
- " cron.set_days_of_month([1, 2, 3, 4, 5, 6 ])\n"
- " cron.set_months([1, 2, 3, 4, 5, 6])\n"
- " start = ecflow.TimeSlot(0 , 0)\n"
- " finish = ecflow.TimeSlot(23, 0)\n"
- " incr = ecflow.TimeSlot(0, 30)\n"
- " ts = ecflow.TimeSeries(start, finish, incr, True) # True means relative to suite start\n"
- " cron.set_time_series(ts)\n"
- "\n"
- " cron1 = ecflow.Cron()\n"
- " cron1.set_time_series(1, 30, True) # same as cron +01:30\n"
- "\n"
- " cron2 = ecflow.Cron()\n"
- " cron2.set_week_days([0, 1, 2, 3, 4, 5, 6])\n"
- " cron2.set_time_series(\"00:30 01:30 00:01\")\n"
- "\n"
- " cron3 = ecflow.Cron()\n"
- " cron3.set_week_days([0, 1, 2, 3, 4, 5, 6])\n"
- " cron3.set_time_series(\"+00:30\")\n"
- ;
-}
-
-const char* NodeAttrDoc::clock_doc()
-{
- return
- "Specifies the :term:`clock` type used by the :term:`suite`.\n\n"
- "Only suites can have a :term:`clock`.\n"
- "A gain can be specified to offset from the given date.\n"
- "\nConstructor::\n\n"
- " Clock(day,month,year,hybrid)\n"
- " int day : Specifies the day of the month 1-31\n"
- " int month : Specifies the month 1-12\n"
- " int year : Specifies the year > 1400\n"
- " bool hybrid<optional>: Default = False, true means hybrid, false means real\n"
- " by default the clock is not real\n\n"
- " Time will be set to midnight, use set_gain() to alter\n"
- "\n"
- " Clock(hybrid)\n"
- " bool hybrid: true means hybrid, false means real\n"
- " by default the clock is real\n"
- " Time will be set real time of the computer\n"
- "\n"
- "\nExceptions:\n\n"
- "- raises IndexError when an invalid Clock is specified\n"
- "\nUsage::\n\n"
- " suite = Suite('s1')\n"
- " clock = Clock(1,1,2012,False)\n"
- " clock.set_gain(1,10,True)\n"
- " suite.add_clock(clock)\n"
- ;
-}
diff --git a/ecflow_4_0_7/Pyext/src/NodeAttrDoc.hpp b/ecflow_4_0_7/Pyext/src/NodeAttrDoc.hpp
deleted file mode 100644
index b9f044b..0000000
--- a/ecflow_4_0_7/Pyext/src/NodeAttrDoc.hpp
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef NODE_ATTR_DOC_HPP_
-#define NODE_ATTR_DOC_HPP_
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #8 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-#include <boost/noncopyable.hpp>
-
-// ===========================================================================
-// IMPORTANT: These appear as python doc strings.
-// Additionally they are auto documented using sphinx-poco
-// Hence the doc strings use reStructuredText markup
-// ===========================================================================
-class NodeAttrDoc : private boost::noncopyable {
-public:
- static const char* variable_doc();
- static const char* zombie_doc();
- static const char* zombie_type_doc();
- static const char* zombie_user_action_type_doc();
- static const char* child_cmd_type_doc();
- static const char* label_doc();
- static const char* limit_doc();
- static const char* inlimit_doc();
- static const char* event_doc();
- static const char* meter_doc();
- static const char* date_doc();
- static const char* day_doc();
- static const char* days_enum_doc();
- static const char* time_doc();
- static const char* today_doc();
- static const char* late_doc();
- static const char* autocancel_doc();
- static const char* repeat_doc();
- static const char* repeat_date_doc();
- static const char* repeat_integer_doc();
- static const char* repeat_enumerated_doc();
- static const char* repeat_string_doc();
- static const char* repeat_day_doc();
- static const char* cron_doc();
- static const char* clock_doc();
-private:
- NodeAttrDoc(){}
-};
-#endif
diff --git a/ecflow_4_0_7/Pyext/test/CleanupOnlineTutorial.py b/ecflow_4_0_7/Pyext/test/CleanupOnlineTutorial.py
deleted file mode 100644
index 4c3e861..0000000
--- a/ecflow_4_0_7/Pyext/test/CleanupOnlineTutorial.py
+++ /dev/null
@@ -1,28 +0,0 @@
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# Name :
-# Author : Avi
-# Revision : $Revision: #10 $
-#
-# Copyright 2009-2012 ECMWF.
-# This software is licensed under the terms of the Apache Licence version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation
-# nor does it submit to any jurisdiction.
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-import os
-
-# clean up any file after running the online tutorial examples
-# Place in separate exception, otherwise not all files will be removed
-try: os.remove("test.def")
-except: pass
-
-try: os.remove("TestSuite.def")
-except: pass
-
-try: os.remove("SuiteBuilder.def")
-except: pass
-
-try: os.remove("server.defs")
-except: pass
diff --git a/ecflow_4_0_7/Pyext/test/TestEmbeddedEcf.cpp b/ecflow_4_0_7/Pyext/test/TestEmbeddedEcf.cpp
deleted file mode 100644
index d33f2b3..0000000
--- a/ecflow_4_0_7/Pyext/test/TestEmbeddedEcf.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-//// Commented out since we *dont* use embedded python
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-//#include <boost/python.hpp>
-//#include <boost/detail/lightweight_test.hpp>
-//#include "boost/filesystem/operations.hpp"
-//#include "boost/filesystem/path.hpp"
-//#include <iostream>
-//
-//namespace fs = boost::filesystem;
-//namespace python = boost::python;
-//
-//// init_defs is defined in BOOST_PYTHON_MODULE(_defs) in file EcfDefsExt.cpp
-//// However we need definition here. Hence expanded the pertinent contents of
-//// BOOST_PYTHON_MODULE
-//extern "C" __attribute__ ((visibility("default"))) void initecflow();
-//
-//void exec_test()
-//{
-// std::cout << "registering extension module ecflow..." << std::endl;
-//
-// // Register the module with the interpreter
-// if (PyImport_AppendInittab((char*)"_defs", initecflow) == -1)
-// throw std::runtime_error("Failed to add _defs to the interpreter's built in modules");
-//
-// std::cout << "defining Defs..." << std::endl;
-//
-// // Retrieve the main module
-// python::object main = python::import("__main__");
-//
-// // Retrieve the main module's namespace
-// python::object global(main.attr("__dict__"));
-//
-// // Define Defs in Python.
-// python::object result = python::exec(
-// "from ecflow import *\n"
-// "file = 'embedded.def'\n"
-// "defs = Defs(file)\n"
-// "suite = Suite('s1')\n"
-// "family = Family('f1')\n"
-// "for i in [ '_1', '_2', '_3' ]: family.add_task( Task( 't' + i) ) \n"
-// "defs.add_suite(suite); \n"
-// "suite.add_family(family)\n"
-// "defs.save_as_defs("embedded.def")\n",
-// global, global);
-//
-// // Check it worked by looking for the presence of embedded.def file
-// BOOST_TEST(fs::exists("embedded.def") );
-// fs::remove("embedded.def");
-//
-// std::cout << "success!" << std::endl;
-//}
-//
-//int main(int argc, char **argv)
-//{
-// // Initialize the interpreter
-// Py_Initialize();
-//
-// if ( python::handle_exception(exec_test) )
-// {
-// if (PyErr_Occurred())
-// {
-// PyErr_Print();
-// }
-// else
-// {
-// BOOST_ERROR("A C++ exception was thrown for which "
-// "there was no exception translator registered.");
-// }
-// }
-//
-// // Boost.Python doesn't support Py_Finalize yet, so don't call it!
-// return boost::report_errors();
-//}
diff --git a/ecflow_4_0_7/Pyext/test/data/includes/head.h b/ecflow_4_0_7/Pyext/test/data/includes/head.h
deleted file mode 100755
index c39d08a..0000000
--- a/ecflow_4_0_7/Pyext/test/data/includes/head.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/bin/ksh
-
-set -e # stop the shell on first error
-set -u # fail when using an undefined variable
-set -x # echo script lines as they are executed
-
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-# Defines the variables that are needed for any
-# communication with ECF_
-
-export ECF_PORT=%ECF_PORT% # ECF portnumber
-export ECF_NODE=%ECF_NODE% # The name host that issued this task
-export ECF_NAME=%ECF_NAME% # The name of this current task
-export ECF_PASS=%ECF_PASS% # A unique password
-export ECF_TRYNO=%ECF_TRYNO% # Current try number of the task
-
-# Tell ECF_ we have stated
-# The ECF_ variable ECF_RID will be set to parameter of init
-# Here we give the current PID.
-
-%ECF_CLIENT_EXE_PATH:ecflow_client% --init=$$
-
-# Defined a error hanlder
-
-ERROR() {
- set +e # Clear -e flag, so we don't fail
- wait # wait for background process to stop
- %ECF_CLIENT_EXE_PATH:ecflow_client% --abort # Notify ECF_ that something went wrong
- trap 0 # Remove the trap
- exit 0 # End the script
-}
-
-# Trap any calls to exit and errors caught by the -e flag
-
-trap ERROR 0
-
-# Trap any signal that may cause the script to fail
-
-trap '{ echo "Killed by a signal"; ERROR ; }' 1 2 3 4 5 6 7 8 10 12 13 15
diff --git a/ecflow_4_0_7/Pyext/test/ecflow_test_util.py b/ecflow_4_0_7/Pyext/test/ecflow_test_util.py
deleted file mode 100644
index 1819c8b..0000000
--- a/ecflow_4_0_7/Pyext/test/ecflow_test_util.py
+++ /dev/null
@@ -1,220 +0,0 @@
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# Name :
-# Author : Avi
-# Revision : $Revision: #10 $
-#
-# Copyright 2009-2014 ECMWF.
-# This software is licensed under the terms of the Apache Licence version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation
-# nor does it submit to any jurisdiction.
-#
-# Utility code used in the tests.
-#
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-from socket import gethostname
-import os
-import fcntl
-import shutil # used to remove directory tree
-
-from ecflow import Client, debug_build, File
-
-# Enable to stop data being deleted, and stop server from being terminated
-def debugging() : return False
-
-def ecf_home(port):
- # debug_build() is defined for ecflow. Used in test to distinguish debug/release ecflow
- # Vary ECF_HOME based on debug/release/port allowing multiple invocations of these tests
- if debug_build():
- return os.getcwd() + "/test/data/ecf_home_debug_" + str(port)
- return os.getcwd() + "/test/data/ecf_home_release_" + str(port)
-
-def get_parent_dir(file_path):
- return os.path.dirname(file_path)
-
-def get_root_source_dir():
- cwd = os.getcwd()
- #print "get_root_source_dir from: " + cwd
- while (1):
- # Get to directory that has ecflow
- head, tail = os.path.split(cwd)
- #print " tail:" + tail
- if tail.find("ecflow") != -1 :
-
- # bjam, already at the source directory
- if os.path.exists(cwd + "/VERSION.cmake"):
- #print " Found VERSION.cmake in " + cwd
- return cwd
-
- # in cmake, we may be in the build directory, hence we need to determine source directory
- file = cwd + "/CTestTestfile.cmake"
- print " searching for " + file
- if os.path.exists(file):
- # determine path by looking into this file:
- for line in open(file):
- ## Source directory: /tmp/ma0/clientRoot/workspace/working-directory/ecflow/Acore
- if line.find("Source directory"):
- tokens = line.split()
- if len(tokens) == 4:
- return tokens[3]
- raise RuntimeError("ERROR could not find Source directory in CTestTestfile.cmake")
- else:
- raise RuntimeError("ERROR could not find file CTestTestfile.cmake in " + cwd)
-
- cwd = head
- return cwd
-
-
-def log_file_path(port): return "./" + gethostname() + "." + port + ".ecf.log"
-def checkpt_file_path(port): return "./" + gethostname() + "." + port + ".ecf.check"
-def backup_checkpt_file_path(port): return "./" + gethostname() + "." + port + ".ecf.check.b"
-def white_list_file_path(port): return "./" + gethostname() + "." + port + ".ecf.lists"
-
-def clean_up_server(port):
- print " clean_up " + port
- try: os.remove(log_file_path(port))
- except: pass
- try: os.remove(checkpt_file_path(port))
- except: pass
- try: os.remove(backup_checkpt_file_path(port))
- except: pass
- try: os.remove(white_list_file_path(port))
- except: pass
-
-def clean_up_data(port):
- print " Attempting to Removing ECF_HOME " + ecf_home(port)
- try:
- shutil.rmtree(ecf_home(port),True) # True means ignore errors
- print " Remove OK"
- except:
- print " Remove Failed"
- pass
-
-# =======================================================================================
-class EcfPortLock(object):
- """allow debug and release version of python tests to run at the same
- time, buy generating a unique port each time"""
- def __init__(self):
- print " EcfPortLock:__init__"
- pass
-
- def find_free_port(self,seed_port):
- print " EcfPortLock:find_free_port starting with " + str(seed_port)
- port = seed_port
- while 1:
- if self._free_port(port) == True:
- print " *FOUND* free server port " + str(port)
- if self._do_lock(port) == True:
- break;
- else:
- print " *Server* port " + str(port) + " busy, trying next port"
- port = port + 1
-
- return str(port)
-
- def _free_port(self,port):
- try:
- ci = Client()
- ci.set_host_port("localhost",str(port))
- ci.ping()
- return False
- except RuntimeError, e:
- return True
-
- def _do_lock(self,port):
- file = self._lock_file(port)
- try:
- fp = open(file, 'w')
- try:
- fcntl.lockf(fp, fcntl.LOCK_EX | fcntl.LOCK_NB)
- self.lock_file_fp = fp
- print " *LOCKED* file " + file
- return True;
- except IOError:
- print " Could *NOT* lock file " + file + " trying next port"
- return False
- except IOError, e:
- print " Could not open file " + file + " for write trying next port"
- return False
-
- def remove(self,port):
- self.lock_file_fp.close()
- os.remove(self._lock_file(port))
-
- def _lock_file(self,port):
- lock_file = str(port) + ".lock"
- return lock_file
-
-# ===============================================================================
-
-class Server(object):
- """TestServer: allow debug and release version of python tests to run at the same
- time, by generating a unique port each time"""
- def __init__(self):
- print "Server:__init__: Starting server"
- if not debugging():
- seed_port = 3153
- if debug_build(): seed_port = 3152
- self.lock_file = EcfPortLock()
- self.the_port = self.lock_file.find_free_port(seed_port)
- else:
- self.the_port = "3152"
-
- # Only worth doing this test, if the server is running
- # ON HPUX, having only one connection attempt, sometimes fails
- #ci.set_connection_attempts(1) # improve responsiveness only make 1 attempt to connect to server
- #ci.set_retry_connection_period(0) # Only applicable when make more than one attempt. Added to check api.
- self.ci = Client("localhost", self.the_port)
-
- def __enter__(self):
- try:
- print "Server:__enter__: About to ping localhost:" + self.the_port
- self.ci.ping()
- print " ------- Server all ready running *UNEXPECTED* ------"
- except RuntimeError, e:
- print " ------- Server not running as *EXPECTED* ------ "
- print " ------- Start the server on port " + self.the_port + " ---------"
- clean_up_server(str(self.the_port))
- clean_up_data(str(self.the_port))
-
- server_exe = File.find_server();
- assert len(server_exe) != 0, "Could not locate the server executable"
-
- server_exe += " --port=" + self.the_port + " --ecfinterval=4 &"
- print " TestClient.py: Starting server ", server_exe
- os.system(server_exe)
-
- print " Allow time for server to start"
- if self.ci.wait_for_server_reply() :
- print " Server has started"
- else:
- print " Server failed to start after 60 second !!!!!!"
- assert False , "Server failed to start after 60 second !!!!!!"
-
- print " Run the tests, leaving Server:__enter__:"
-
- # return the Client, that can call to the server
- return self.ci
-
- def __exit__(self,exctype,value,tb):
- print " Server:__exit__: Kill the server, clean up log file, check pt files and lock files, ECF_HOME"
- print " exctype:==================================================="
- print exctype
- print " value:====================================================="
- print value
- print " tb:========================================================";
- print tb
- print " Terminate server ===================================================="
- self.ci.terminate_server()
- print " Terminate server OK ================================================="
- print " Remove lock file"
- self.lock_file.remove(self.the_port)
- clean_up_server(str(self.the_port))
-
- # Do not clean up data, if an assert was raised. This allow debug
- if exctype == None:
- clean_up_data(str(self.the_port))
- return False
-
-
\ No newline at end of file
diff --git a/ecflow_4_0_7/Pyext/test/py_s_TestClientApi.py b/ecflow_4_0_7/Pyext/test/py_s_TestClientApi.py
deleted file mode 100644
index b2ac1f3..0000000
--- a/ecflow_4_0_7/Pyext/test/py_s_TestClientApi.py
+++ /dev/null
@@ -1,1539 +0,0 @@
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# Name :
-# Author : Avi
-# Revision : $Revision: #10 $
-#
-# Copyright 2009-2012 ECMWF.
-# This software is licensed under the terms of the Apache Licence version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation
-# nor does it submit to any jurisdiction.
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# code for testing client code in python
-import time
-import os
-import pwd
-from datetime import datetime
-import shutil # used to remove directory tree
-
-# ecflow_test_util, see File ecflow_test_util.py
-import ecflow_test_util as Test
-from ecflow import Defs, Clock, DState, Style, State, RepeatDate, PrintStyle, File, Client, SState, \
- JobCreationCtrl, CheckPt, Cron, debug_build
-#from __builtin__ import None
-
-def ecf_includes() : return os.getcwd() + "/test/data/includes"
-
-def create_defs(name=""):
- defs = Defs()
- suite_name = name
- if len(suite_name) == 0: suite_name = "s1"
- suite = defs.add_suite(suite_name);
-
- ecfhome = Test.ecf_home(the_port);
- suite.add_variable("ECF_HOME", ecfhome);
- suite.add_variable("ECF_CLIENT_EXE_PATH", File.find_client());
- suite.add_variable("SLEEP", "1"); # not strictly required since default is 1 second
- suite.add_variable("ECF_INCLUDE", ecf_includes());
-
- family = suite.add_family("f1")
- family.add_task("t1")
- family.add_task("t2")
- return defs;
-
-def test_host_port(ci,host,port):
- try :
- ci.set_host_port(host,port)
- return True
- except RuntimeError:
- return False
-
-def test_host_port_(ci,host_port):
- try :
- ci.set_host_port(host_port)
- return True
- except RuntimeError:
- return False
-
-def test_client_host_port(host,port):
- try :
- Client(host,port)
- return True
- except RuntimeError:
- return False
-
-def test_client_host_port_(host_port):
- try :
- Client(host_port)
- return True
- except RuntimeError:
- return False
-
-def test_set_host_port():
- print "test_set_host_port"
- ci = Client();
- print " Client.get_host() = " + ci.get_host()
- print " Client.get_port() = " + ci.get_port()
- assert test_host_port(ci,"host","3141") , "Expected no errors"
- assert test_host_port(ci,"host",4444) , "Expected no errors"
- assert test_host_port_(ci,"host:4444") , "Expected no errors"
- assert test_host_port(ci,"","") == False , "Expected errors"
- assert test_host_port(ci,"host","") == False , "Expected errors"
- assert test_host_port(ci,"host","host") == False , "Expected errors"
- assert test_host_port_(ci,"host:host") == False , "Expected errors"
- assert test_host_port_(ci,"3141:host") == False , "Expected errors"
-
- assert test_client_host_port("host","3141") , "Expected no errors"
- assert test_client_host_port("host",4444) , "Expected no errors"
- assert test_client_host_port_("host:4444") , "Expected no errors"
- assert test_client_host_port("","") == False , "Expected errors"
- assert test_client_host_port("host","") == False , "Expected errors"
- assert test_client_host_port("host","host") == False , "Expected errors"
- assert test_client_host_port_("host:host") == False , "Expected errors"
- assert test_client_host_port_("3141:host") == False , "Expected errors"
-
-def test_version(ci):
- client_version = ci.version();
- server_version = ci.server_version();
- assert client_version == server_version, "Expected client version(" + client_version +") and server version(" + server_version + ") to match\n";
-
-def test_client_get_server_defs(ci):
- print "Client version is " + ci.version();
- print "test_client_get_server_defs"
- ci.delete_all() # start fresh
- ci.load(create_defs())
- ci.get_server_defs()
- assert ci.get_defs().find_suite("s1") != None, "Expected to find suite of name s1:\n" + str(ci.get_defs())
-
- ci.delete_all() # start fresh
- ci.load(create_defs())
- ci.sync_local()
- assert ci.get_defs().find_suite("s1") != None, "Expected to find suite of name s1:\n" + str(ci.get_defs())
-
-
-def test_client_new_log(ci, port):
- print "test_client_new_log"
- try : os.remove("./test_client_new_log.log") # delete file if it exists
- except: pass
-
- ci.new_log("./test_client_new_log.log")
- ci.flush_log() # close log file and force write to disk
- assert os.path.exists("./test_client_new_log.log"), "New log does not exist"
-
- # reset new log to original
- ci.new_log(Test.log_file_path(port))
- ci.ping()
- ci.flush_log() # close log file and force write to disk
- log_file = open(Test.log_file_path(port))
- try: log_text = log_file.read(); # assume log file not to big
- finally: log_file.close();
- assert log_text.find("--ping") != -1, "Expected to find --ping in log file"
- try: os.remove("./test_client_new_log.log")
- except: pass
-
-
-def test_client_clear_log(ci, port):
- print "test_client_clear_log"
- # populate log
- ci.ping();
- ci.ping();
- ci.flush_log() # close log file and force write to disk
- log_file = open(Test.log_file_path(port))
- try: log_text = log_file.read(); # assume log file not to big
- finally: log_file.close();
- assert log_text.find("--ping") != -1, "Expected to find --ping in log file"
-
- ci.clear_log()
- log_file = open(Test.log_file_path(port))
- try: log_text = log_file.read(); # assume log file not to big
- finally: log_file.close();
- assert len(log_text) == 0, "Expected log file to be empty but found " + log_text
-
-
-def test_client_log_msg(ci, port):
- print "test_client_log_msg"
- # Send a message to the log file, then make sure it was written
- ci.log_msg("Humpty dumpty sat on a wall!")
- ci.flush_log(); # flush and close log file, so we can open it
- log_file = open(Test.log_file_path(port))
- try: log_text = log_file.read(); # assume log file not to big
- finally: log_file.close();
- assert log_text.find("Humpty dumpty sat on a wall!") != -1, "Expected to find Humpty dumpty in the log file"
-
-
-def test_client_restart_server(ci):
- print "test_client_restart_server"
- ci.restart_server()
- ci.sync_local()
- assert ci.get_defs().get_server_state() == SState.RUNNING, "Expected server to be running"
-
- paths = list(ci.changed_node_paths)
- assert len(paths) == 1, "expected changed node to be the root node"
- assert paths[0] == "/", "Expected root path but found " + str(paths[0])
-
-def test_client_halt_server(ci):
- print "test_client_halt_server"
- ci.halt_server()
- ci.sync_local()
- assert ci.get_defs().get_server_state() == SState.HALTED, "Expected server to be halted"
-
- paths = list(ci.changed_node_paths)
- assert len(paths) == 1, "expected changed node to be the root node"
- assert paths[0] == "/", "Expected root path but found " + str(paths[0])
-
-def test_client_shutdown_server(ci):
- print "test_client_shutdown_server"
- ci.shutdown_server()
- ci.sync_local()
- assert ci.get_defs().get_server_state() == SState.SHUTDOWN, "Expected server to be shutdown"
-
- paths = list(ci.changed_node_paths)
- assert len(paths) == 1, "expected changed node to be the root node"
- assert paths[0] == "/", "Expected root path but found " + str(paths[0])
-
-
-def test_client_load_in_memory_defs(ci):
- print "test_client_load_in_memory_defs"
- ci.delete_all() # start fresh
- ci.load(create_defs())
- ci.sync_local()
- assert ci.get_defs().find_suite("s1") != None, "Expected to find suite of name s1:\n" + str(ci.get_defs())
-
-
-def test_client_load_from_disk(ci):
- print "test_client_load_from_disk"
- ci.delete_all() # start fresh
- defs = create_defs();
- defs_file = "test_client_load_from_disk.def"
- defs.save_as_defs(defs_file)
- assert os.path.exists(defs_file), "Expected file " + defs_file + " to exist after defs.save_as_defs()"
- ci.load(defs_file) # open and parse defs file, and load into server.\n"
-
- # check load worked
- ci.sync_local()
- assert ci.get_defs().find_suite("s1") != None, "Expected to find suite of name s1:\n" + str(ci.get_defs())
- os.remove(defs_file)
-
-
-def test_client_checkpt(ci, port):
- print "test_client_checkpt"
- # start fresh
- ci.delete_all()
- try:
- os.remove(Test.checkpt_file_path(port))
- os.remove(Test.backup_checkpt_file_path(port))
- except: pass
-
- ci.load(create_defs())
- ci.checkpt()
- assert os.path.exists(Test.checkpt_file_path(port)), "Expected check pt file to exist after ci.checkpt()"
- assert os.path.exists(Test.backup_checkpt_file_path(port)) == False, "Expected back up check pt file to *NOT* exist"
-
- ci.checkpt() # second check pt should cause backup check pt to be written
- assert os.path.exists(Test.backup_checkpt_file_path(port)), "Expected back up check pt file to exist after second ci.checkpt()"
-
- ci.checkpt(CheckPt.NEVER) # switch of check pointing
- ci.checkpt(CheckPt.ALWAYS) # always check point, at any state change
- ci.checkpt(CheckPt.ON_TIME) # Check point periodically, by interval set in server
- ci.checkpt(CheckPt.ON_TIME, 200) # Check point periodically, by interval set in server
- ci.checkpt(CheckPt.UNDEFINED, 0, 35) # Change check point save time alarm
-
- os.remove(Test.checkpt_file_path(port))
- os.remove(Test.backup_checkpt_file_path(port))
-
-
-def test_client_restore_from_checkpt(ci, port):
- print "test_client_restore_from_checkpt"
- # start fresh
- ci.delete_all()
- try:
- os.remove(Test.checkpt_file_path(port))
- os.remove(Test.backup_checkpt_file_path(port))
- except: pass
-
- ci.load(create_defs())
- ci.checkpt()
- ci.delete_all()
-
- ci.sync_local()
- assert ci.get_defs().find_suite("s1") == None, "Expected all suites to be delete:\n"
-
- ci.halt_server() # server must be halted, otherwise restore_from_checkpt will throw
- ci.restore_from_checkpt()
-
- ci.sync_local()
- assert ci.get_defs().find_suite("s1") != None, "Expected to find suite s1 after restore from checkpt:\n" + str(ci.get_defs())
-
- os.remove(Test.checkpt_file_path(port))
-
-
-def get_username(): return pwd.getpwuid(os.getuid())[ 0 ]
-
-def test_client_reload_wl_file(ci, port):
- print "test_client_reload_wl_file"
-
- expected = False
- try: ci.reload_wl_file();
- except: expected = True
- assert expected, "Expected reload to fail when no white list specified"
-
- # create a white list file
- wl_file = open(Test.white_list_file_path(port), 'w')
- wl_file.write("#\n")
- wl_file.write("4.4.14 # comment\n\n")
- wl_file.write("# These user have read and write access to the server\n")
- wl_file.write(get_username() + "\n") # add current user otherwise remaining test's, wont have access from server anymore
- wl_file.write("axel # admin\n")
- wl_file.write("john # admin\n\n")
- wl_file.write("# Read only users\n")
- wl_file.write("-fred # needs read access only\n")
- wl_file.write("-joe90 # needs read access only\n")
- wl_file.close();
-
- ci.reload_wl_file();
- os.remove(Test.white_list_file_path(port))
-
-
-def test_client_run(ci):
- print "test_client_run"
- ci.delete_all()
- defs = create_defs("test_client_run")
- suite = defs.find_suite("test_client_run")
- suite.add_defstatus(DState.suspended)
-
- defs.generate_scripts();
-
- job_ctrl = JobCreationCtrl()
- defs.check_job_creation(job_ctrl)
- assert len(job_ctrl.get_error_msg()) == 0, job_ctrl.get_error_msg()
-
- ci.restart_server()
- ci.load(defs)
- ci.begin_all_suites()
- ci.run("/test_client_run", False)
-
- count = 0
- while 1:
- count += 1
- ci.sync_local() # get the changes, synced with local defs
- suite = ci.get_defs().find_suite("test_client_run")
- assert suite != None, "Expected to find suite test_client_run:\n" + str(ci.get_defs())
- if suite.get_state() == State.complete:
- break;
- time.sleep(3)
- if count > 20:
- assert False, "test_client_run aborted after " + str(count) + " loops:\n" + str(ci.get_defs())
-
- ci.log_msg("Looped " + str(count) + " times")
-
- dir_to_remove = Test.ecf_home(the_port) + "/" + "test_client_run"
- shutil.rmtree(dir_to_remove)
-
-def test_client_run_with_multiple_paths(ci):
- print "test_client_run_with_multiple_paths"
- ci.delete_all()
- defs = create_defs("test_client_run_with_multiple_paths")
- suite = defs.find_suite("test_client_run_with_multiple_paths")
- suite.add_defstatus(DState.suspended)
-
- defs.generate_scripts();
-
- job_ctrl = JobCreationCtrl()
- defs.check_job_creation(job_ctrl)
- assert len(job_ctrl.get_error_msg()) == 0, job_ctrl.get_error_msg()
-
- ci.restart_server()
- ci.load(defs)
- ci.begin_all_suites()
- path_list = [ "/test_client_run_with_multiple_paths/f1/t1", "/test_client_run_with_multiple_paths/f1/t2"]
- ci.run( path_list, False)
-
- count = 0
- while 1:
- count += 1
- ci.sync_local() # get the changes, synced with local defs
- suite = ci.get_defs().find_suite("test_client_run_with_multiple_paths")
- assert suite != None, "Expected to find suite test_client_run_with_multiple_paths:\n" + str(ci.get_defs())
- if suite.get_state() == State.complete:
- break;
- time.sleep(3)
- if count > 20:
- assert False, "test_client_run_with_multiple_paths aborted after " + str(count) + " loops:\n" + str(ci.get_defs())
-
- ci.log_msg("Looped " + str(count) + " times")
-
- dir_to_remove = Test.ecf_home(the_port) + "/" + "test_client_run_with_multiple_paths"
- shutil.rmtree(dir_to_remove)
-
-
-def test_client_requeue(ci):
- print "test_client_requeue"
- ci.delete_all()
- defs = create_defs("test_client_requeue")
- suite = defs.find_suite("test_client_requeue")
- suite.add_defstatus(DState.suspended)
-
- defs.generate_scripts();
- job_ctrl = JobCreationCtrl()
- defs.check_job_creation(job_ctrl)
- assert len(job_ctrl.get_error_msg()) == 0, job_ctrl.get_error_msg()
-
- ci.restart_server()
- ci.load(defs)
- ci.begin_all_suites()
-
- ci.force_state_recursive("/test_client_requeue",State.unknown)
- ci.sync_local();
- suite = ci.get_defs().find_suite("test_client_requeue")
- assert suite.get_state() == State.unknown, "Expected to find suite with state unknown"
-
- ci.requeue("/test_client_requeue")
- ci.sync_local();
- suite = ci.get_defs().find_suite("test_client_requeue")
- assert suite.get_state() == State.queued, "Expected to find suite with state queued"
-
- dir_to_remove = Test.ecf_home(the_port) + "/" + "test_client_requeue"
- shutil.rmtree(dir_to_remove)
-
-def test_client_requeue_with_multiple_paths(ci):
- print "test_client_requeue_with_multiple_paths"
- ci.delete_all()
- defs = create_defs("test_client_requeue_with_multiple_paths")
- suite = defs.find_suite("test_client_requeue_with_multiple_paths")
- suite.add_defstatus(DState.suspended)
-
- defs.generate_scripts();
- job_ctrl = JobCreationCtrl()
- defs.check_job_creation(job_ctrl)
- assert len(job_ctrl.get_error_msg()) == 0, job_ctrl.get_error_msg()
-
- ci.restart_server()
- ci.load(defs)
- ci.begin_all_suites()
-
- ci.force_state_recursive("/test_client_requeue_with_multiple_paths",State.unknown)
- ci.sync_local();
- task1 = ci.get_defs().find_abs_node("/test_client_requeue_with_multiple_paths/f1/t1")
- task2 = ci.get_defs().find_abs_node("/test_client_requeue_with_multiple_paths/f1/t2")
- assert task1.get_state() == State.unknown, "Expected to find t1 with state unknown"
- assert task2.get_state() == State.unknown, "Expected to find t2 with state unknown"
-
- path_list = [ "/test_client_requeue_with_multiple_paths/f1/t1", "/test_client_requeue_with_multiple_paths/f1/t2" ]
- ci.requeue( path_list)
- ci.sync_local();
- task1 = ci.get_defs().find_abs_node("/test_client_requeue_with_multiple_paths/f1/t1")
- task2 = ci.get_defs().find_abs_node("/test_client_requeue_with_multiple_paths/f1/t2")
- assert task1.get_state() == State.queued, "Expected to find task t1 with state queued"
- assert task2.get_state() == State.queued, "Expected to find task t2 with state queued"
-
- dir_to_remove = Test.ecf_home(the_port) + "/" + "test_client_requeue_with_multiple_paths"
- shutil.rmtree(dir_to_remove)
-
-
-def test_client_free_dep(ci):
- print "test_client_free_dep"
- ci.delete_all()
-
- # add a real clock, since we are adding date dependencies
- # Note: adding a future time dependency on a task, will cause it to requeue, when complete
- # Hence even when we free these dependency they get requeued.
- # So we use todays date.
- ltime = time.localtime();
- day = ltime.tm_mday
- month = ltime.tm_mon
- year = ltime.tm_year
-
- defs = Defs()
- suite = defs.add_suite("test_client_free_dep");
- suite.add_clock(Clock(False)) # true means hybrid, False means real
- ecfhome = Test.ecf_home(the_port);
- suite.add_variable("ECF_HOME", ecfhome);
- suite.add_variable("ECF_CLIENT_EXE_PATH", File.find_client());
- suite.add_variable("SLEEPTIME", "1");
- suite.add_variable("ECF_INCLUDE", ecf_includes());
- family = suite.add_family("f1")
- family.add_task("t1").add_time("00:01")
- family.add_task("t2").add_date(day,month,year)
- family.add_task("t3").add_trigger("1 == 0")
- t4 = family.add_task("t4")
- t4.add_time("00:01")
- t4.add_date(day,month,year)
- t4.add_trigger("1 == 0")
-
- defs.generate_scripts();
-
- job_ctrl = JobCreationCtrl()
- defs.check_job_creation(job_ctrl)
- assert len(job_ctrl.get_error_msg()) == 0, job_ctrl.get_error_msg()
-
- ci.restart_server()
- ci.load(defs)
- ci.begin_all_suites()
-
- t1_path = "/test_client_free_dep/f1/t1"
- t2_path = "/test_client_free_dep/f1/t2"
- t3_path = "/test_client_free_dep/f1/t3"
- t4_path = "/test_client_free_dep/f1/t4"
- while 1:
- ci.sync_local()
- t1 = ci.get_defs().find_abs_node(t1_path)
- t2 = ci.get_defs().find_abs_node(t2_path)
- t3 = ci.get_defs().find_abs_node(t3_path)
- t4 = ci.get_defs().find_abs_node(t4_path)
-
- if t1.get_state() == State.queued: ci.free_time_dep(t1_path)
- if t2.get_state() == State.queued: ci.free_date_dep(t2_path)
- if t3.get_state() == State.queued: ci.free_trigger_dep(t3_path)
- if t4.get_state() == State.queued: ci.free_all_dep(t4_path)
-
- suite = ci.get_defs().find_suite("test_client_free_dep")
- if suite.get_state() == State.complete:
- break;
- time.sleep(3)
-
- dir_to_remove = Test.ecf_home(the_port) + "/" + "test_client_free_dep"
- shutil.rmtree(dir_to_remove)
-
-
-def test_client_stats(ci):
- print "test_client_stats"
- ci.stats() # writes to standard out
-
-def test_client_stats_reset(ci):
- print "test_client_stats_reset"
- ci.stats_reset()
- ci.stats() # should produce no ouput, where we measure requests
-
-def test_client_debug_server_on_off(ci):
- print "test_client_debug_server_on_off"
- ci.debug_server_on() # writes to standard out
- ci.debug_server_off()
-
-
-def test_client_check(ci):
- print "test_client_check"
- ci.delete_all()
-
- defs = Defs()
- defs.add_extern("/a/b/c/d")
- defs.add_extern("/a/b/c/d/e:event")
- defs.add_extern("/a/b/c/d/e:meter")
- defs.add_extern("/made/up/redundant/extren")
- defs.add_extern("/made/up/redundant/extren")
- defs.add_extern("/limits:c1a")
- defs.add_extern("/limits:c1a")
- defs.add_extern("fred")
- defs.add_extern("limits:hpcd")
- defs.add_extern("/suiteName:sg1")
- defs.add_extern("/obs/limits:hpcd")
- suite = defs.add_suite("extern")
- family_f1 = suite.add_family("f1")
- family_f1.add_task("p").add_trigger("/a/b/c/d == complete") # extern path
- family_f1.add_task("q").add_trigger("/a/b/c/d/e:event == set") # extern event path
- family_f1.add_task("r").add_trigger("/a/b/c/d/e:meter le 30") # extern meter path
-
- suite.add_inlimit("c1a","/limits")
- suite.add_inlimit("fred")
-
- family_anon = suite.add_family("anon")
- family_anon.add_inlimit("hpcd","limits")
- family_anon.add_task("t1").add_inlimit("sg1","/suiteName")
- family_anon.add_task("t2").add_inlimit("hpcd","/obs/limits")
- family_anon.add_task("t3").add_inlimit("c1a","/limits")
-
- # CLIENT side check
- client_check = defs.check()
- assert len(client_check) == 0, "Expected clean defs check due to externs but found:\n" + client_check + "\n" + str(defs)
-
- # SERVER side check
- ci.load(defs)
- server_check = ci.check("") # empty string means check the whole defs, otherwise a node path can be specified.
- # print server_check
- assert len(server_check) > 0, "Expected defs to fail, since no externs in server "
-
-def test_client_suites(ci):
- print "test_client_suites"
- ci.delete_all()
- assert len(ci.suites()) == 0 ,"expected 0 suite "
-
- defs = create_defs("test_client_suites")
- ci.load(defs)
- assert len(ci.suites()) == 1 ,"expected 1 suite "
-
- ci.delete_all()
- defs.add_suite("s2")
- ci.load(defs)
- assert len(ci.suites()) == 2 ,"expected 2 suite "
-
-def test_client_ch_suites(ci):
- print "test_client_ch_suites"
- ci.delete_all()
-
- defs = Defs()
- for i in range(1,7): defs.add_suite("s" + str(i))
- ci.load(defs)
-
- suite_names = [ 's1', 's2', 's3' ]
- ci.ch_register(True,suite_names) # register interest in suites s1,s2,s3 and any new suites
- ci.ch_register(False,[ "s1"]) # register interest in suites s1
-
- ci.ch_suites() # writes to standard out, list of suites and handles
-
-def test_client_ch_register(ci):
- print "test_client_ch_register"
- ci.delete_all()
- try: ci.ch_drop_user("") # drop all handle associated with current user
- except: pass # Drop throws if no handle registered
-
- defs = Defs()
- for i in range(1,7): defs.add_suite("s" + str(i))
- ci.load(defs)
-
- suite_names = [ 's1', 's2', 's3' ]
- ci.ch_register(True, suite_names) # register interest in suites s1,s2,s3 and any new suites
- ci.ch_register(False,suite_names) # register interest in suites s1,s2,s3 only
-
-
-def test_client_ch_drop(ci):
- print "test_client_ch_drop"
- ci.delete_all()
- try: ci.ch_drop_user("") # drop all handle associated with current user
- except: pass # Drop throws if no handle registered
-
- defs = Defs()
- for i in range(1,7): defs.add_suite("s" + str(i))
- ci.load(defs)
-
- try:
- # register interest in suites s1,s2,s3 and any new suites
- suite_names = [ 's1', 's2', 's3' ]
- ci.ch_register(True, suite_names)
- finally:
- ci.ch_drop() # drop using handle stored in ci., from last register
-
-
-def test_client_ch_drop_user(ci):
- print "test_client_ch_drop_user"
- ci.delete_all()
- try: ci.ch_drop_user("") # drop all handle associated with current user
- except: pass # Drop throws if no handle registered
-
- defs = Defs()
- for i in range(1,7): defs.add_suite("s" + str(i))
- ci.load(defs)
-
- try:
- # register interest in suites s1,s2,s3 and any new suites
- suite_names = [ 's1', 's2', 's3' ]
- ci.ch_register(True, suite_names)
- except RuntimeError, e:
- print str(e)
-
- ci.ch_drop_user("") # drop all handle associated with current user
-
-
-def test_client_ch_add(ci):
- print "test_client_ch_add"
- ci.delete_all()
- try: ci.ch_drop_user("") # drop all handle associated with current user
- except: pass # Drop throws if no handle registered
-
- defs = Defs()
- for i in range(1,7): defs.add_suite("s" + str(i))
- ci.load(defs)
-
- try:
- suite_names = []
- ci.ch_register(True,suite_names) # register interest in any new suites
- suite_names = [ 's1', 's2' ]
- ci.ch_add(suite_names) # add suites s1,s2 to the last added handle
- suite_names = [ 's3', 's4' ]
- ci.ch_add( ci.ch_handle(),suite_names) # add suites s3,s4 using last handle
- except RuntimeError, e:
- print str(e)
-
- ci.ch_drop_user("") # drop all handle associated with current user
-
-
-def test_client_ch_auto_add(ci):
- print "test_client_ch_auto_add"
- ci.delete_all()
- try: ci.ch_drop_user("") # drop all handle associated with current user
- except: pass # Drop throws if no handle registered
-
- defs = Defs()
- for i in range(1,7): defs.add_suite("s" + str(i))
- ci.load(defs)
-
- try:
- suite_names = [ 's1', 's2' , 's3']
- ci.ch_register(True,suite_names) # register interest in suites s1,s2,s3 and any new suites
- ci.ch_auto_add( False ) # disable adding newly created suites to last registered handle\n"
- ci.ch_auto_add( True ) # enable adding newly created suites to last registered handle\n"
- ci.ch_auto_add( ci.ch_handle(), False ) # disable adding newly created suites to handle\n"
- except RuntimeError, e:
- print str(e)
-
- ci.ch_drop_user("") # drop all handle associated with current user
-
-
-def test_client_ch_remove(ci):
- print "test_client_ch_remove"
- ci.delete_all()
- try: ci.ch_drop_user("") # drop all handle associated with current user
- except: pass # Drop throws if no handle registered
-
- defs = Defs()
- for i in range(1,7): defs.add_suite("s" + str(i))
- ci.load(defs)
-
- try:
- suite_names = [ 's1', 's2' , 's3']
- ci.ch_register(True,suite_names) # register interest in suites s1,s2,s3 and any new suites
- suite_names = [ 's1' ]
- ci.ch_remove( suite_names ) # remove suites s1 from the last added handle\n"
- suite_names = [ 's2' ]
- ci.ch_remove( ci.ch_handle(), suite_names ) # remove suites s2 from the last added handle\n"
- except RuntimeError, e:
- print str(e)
-
- ci.ch_drop_user("") # drop all handle associated with current user
-
-
-def test_client_get_file(ci):
- print "test_client_get_file"
- ci.delete_all()
- defs = create_defs("test_client_get_file")
-
- defs.generate_scripts();
-
- job_ctrl = JobCreationCtrl()
- defs.check_job_creation(job_ctrl)
- assert len(job_ctrl.get_error_msg()) == 0, job_ctrl.get_error_msg()
-
- ci.restart_server()
- ci.load(defs)
- ci.begin_all_suites()
-
- while 1:
- if ci.news_local():
- ci.sync_local() # get the changes, synced with local defs
- suite = ci.get_defs().find_suite("test_client_get_file")
- assert suite != None, "Expected to find suite"
- if suite.get_state() == State.complete:
- break;
-
- try:
- for file_t in [ 'script', 'job', 'jobout', 'manual' ]:
- the_returned_file = ci.get_file('/test_client_get_file/f1/t1',file_t) # make a request to the server
- assert len(the_returned_file) > 0,"Expected ci.get_file(/test_client_get_file/f1/t1," + file_t + ") to return something"
- except RuntimeError, e:
- print str(e)
-
- dir_to_remove = Test.ecf_home(the_port) + "/" + "test_client_get_file"
- shutil.rmtree(dir_to_remove,True) # True means ignore errors
-
-
-def test_client_plug(ci):
- pass
-
-def test_client_alter_add(ci):
- print "test_client_alter_add"
- ci.delete_all()
- ci.load(create_defs("test_client_alter_add"))
-
- t1 = "/test_client_alter_add/f1/t1"
- ci.alter(t1,"add","variable","var","var_name")
- ci.alter(t1,"add","time","+00:30")
- ci.alter(t1,"add","time","01:30")
- ci.alter(t1,"add","time","01:30 20:00 00:30")
- ci.alter(t1,"add","today","+00:30")
- ci.alter(t1,"add","today","01:30")
- ci.alter(t1,"add","today","01:30 20:00 00:30")
- ci.alter(t1,"add","date","01.01.2001")
- ci.alter(t1,"add","date","*.01.2001")
- ci.alter(t1,"add","date","*.*.2001")
- ci.alter(t1,"add","date","*.*.*")
- ci.alter(t1,"add","day","sunday")
- ci.alter(t1,"add","day","monday")
- ci.alter(t1,"add","day","tuesday")
- ci.alter(t1,"add","day","wednesday")
- ci.alter(t1,"add","day","thursday")
- ci.alter(t1,"add","day","friday")
- ci.alter(t1,"add","day","saturday")
-
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- assert( len(list(task_t1.variables))) == 1 ,"Expected 1 variable :\n" + str(ci.get_defs())
- assert( len(list(task_t1.times))) == 3 ,"Expected 3 time :\n" + str(ci.get_defs())
- assert( len(list(task_t1.todays))) == 3 ,"Expected 3 today's :\n" + str(ci.get_defs())
- assert( len(list(task_t1.dates))) == 4 ,"Expected 4 dates :\n" + str(ci.get_defs())
- assert( len(list(task_t1.days))) == 7 ,"Expected 7 days :\n" + str(ci.get_defs())
-
-
-def test_client_alter_delete(ci):
- print "test_client_alter_delete"
- ci.delete_all()
- defs =create_defs("test_client_alter_delete")
- t1 = "/test_client_alter_delete/f1/t1"
- task_t1 = defs.find_abs_node(t1)
- task_t1.add_variable("var","value")
- task_t1.add_variable("var1","value")
- task_t1.add_time("00:30")
- task_t1.add_time("00:31")
- task_t1.add_today("00:30")
- task_t1.add_today("00:31")
- task_t1.add_date(1,1,2001)
- task_t1.add_date(1,1,2002)
- task_t1.add_day("sunday")
- task_t1.add_day("monday")
- cron = Cron()
- cron.set_week_days( [0,1,2,3,4,5,6] )
- cron.set_time_series( "+00:30" )
- task_t1.add_cron(cron)
- task_t1.add_cron(cron)
- task_t1.add_event("event")
- task_t1.add_event("event1")
- task_t1.add_meter("meter",0,100,100)
- task_t1.add_meter("meter1",0,100,100)
- task_t1.add_label("label","name")
- task_t1.add_label("label1","name")
- task_t1.add_limit("limit",10)
- task_t1.add_limit("limit1",10)
- task_t1.add_inlimit( "limit",t1,2)
- task_t1.add_inlimit( "limit1",t1,2)
- task_t1.add_trigger( "t2 == active" )
- task_t1.add_complete( "t2 == complete" )
-
- t2 = "/test_client_alter_delete/f1/t2"
- task_t2 = defs.find_abs_node(t2)
- task_t2.add_repeat( RepeatDate("date",20100111,20100115,2) ) # can't add cron and repeat at the same level
-
- ci.load(defs)
-
- ci.alter(t1,"delete","variable","var")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- assert( len(list(task_t1.variables))) == 1 ,"Expected 1 variable :\n" + str(ci.get_defs())
- ci.alter(t1,"delete","variable") # delete all veriables
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- assert( len(list(task_t1.variables))) == 0 ,"Expected 0 variable :\n" + str(ci.get_defs())
-
- ci.alter(t1,"delete","time","00:30")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- assert( len(list(task_t1.times))) == 1 ,"Expected 1 time :\n" + str(ci.get_defs())
- ci.alter(t1,"delete","time")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- assert( len(list(task_t1.times))) == 0 ,"Expected 0 time :\n" + str(ci.get_defs())
-
- ci.alter(t1,"delete","today","00:30")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- assert( len(list(task_t1.todays))) == 1 ,"Expected 1 today :\n" + str(ci.get_defs())
- ci.alter(t1,"delete","today")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- assert( len(list(task_t1.todays))) == 0 ,"Expected 0 today :\n" + str(ci.get_defs())
-
- ci.alter(t1,"delete","date","01.01.2001")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- assert( len(list(task_t1.dates))) == 1 ,"Expected 1 date :\n" + str(ci.get_defs())
- ci.alter(t1,"delete","date")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- assert( len(list(task_t1.dates))) == 0 ,"Expected 0 date :\n" + str(ci.get_defs())
-
- ci.alter(t1,"delete","day","sunday")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- assert( len(list(task_t1.days))) == 1 ,"Expected 1 day :\n" + str(ci.get_defs())
- ci.alter(t1,"delete","day")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- assert( len(list(task_t1.days))) == 0 ,"Expected 0 day :\n" + str(ci.get_defs())
-
- ci.alter(t1,"delete","event","event")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- assert( len(list(task_t1.events))) == 1 ,"Expected 1 event :\n" + str(ci.get_defs())
- ci.alter(t1,"delete","event")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- assert( len(list(task_t1.events))) == 0 ,"Expected 0 event :\n" + str(ci.get_defs())
-
- ci.alter(t1,"delete","meter","meter")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- assert( len(list(task_t1.meters))) == 1 ,"Expected 1 meter :\n" + str(ci.get_defs())
- ci.alter(t1,"delete","meter")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- assert( len(list(task_t1.meters))) == 0 ,"Expected 0 meter :\n" + str(ci.get_defs())
-
- ci.alter(t1,"delete","label","label")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- assert( len(list(task_t1.labels))) == 1 ,"Expected 1 label :\n" + str(ci.get_defs())
- ci.alter(t1,"delete","label")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- assert( len(list(task_t1.labels))) == 0 ,"Expected 0 label :\n" + str(ci.get_defs())
-
- ci.alter(t1,"delete","limit","limit")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- assert( len(list(task_t1.limits))) == 1 ,"Expected 1 limit :\n" + str(ci.get_defs())
- ci.alter(t1,"delete","limit")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- assert( len(list(task_t1.limits))) == 0 ,"Expected 0 limit :\n" + str(ci.get_defs())
-
- ci.alter(t1,"delete","inlimit","limit")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- assert( len(list(task_t1.inlimits))) == 1 ,"Expected 1 inlimit :\n" + str(ci.get_defs())
- ci.alter(t1,"delete","inlimit")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- assert( len(list(task_t1.inlimits))) == 0 ,"Expected 0 inlimit :\n" + str(ci.get_defs())
-
- ci.alter(t1,"delete","cron")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- assert( len(list(task_t1.crons))) == 0 ,"Expected 0 crons :\n" + str(ci.get_defs())
-
-
- task_t1 = ci.get_defs().find_abs_node(t1)
- assert task_t1.get_trigger() != None, "Expected trigger:\n" + str(ci.get_defs())
- ci.alter(t1,"delete","trigger")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- assert task_t1.get_trigger() == None, "Expected trigger to be deleted:\n" + str(ci.get_defs())
-
- task_t1 = ci.get_defs().find_abs_node(t1)
- assert task_t1.get_complete() != None, "Expected complete:\n" + str(ci.get_defs())
- ci.alter(t1,"delete","complete")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- assert task_t1.get_complete() == None, "Expected complete to be deleted:\n" + str(ci.get_defs())
-
- ci.alter(t2,"delete","repeat")
- ci.sync_local()
- task_t2 = ci.get_defs().find_abs_node(t2)
- repeat = task_t2.get_repeat()
- assert repeat.empty(), "Expected repeat to be deleted:\n" + str(ci.get_defs())
-
-def test_client_alter_change(ci):
- print "test_client_alter_change"
- ci.delete_all()
- defs =create_defs("test_client_alter_change")
- t1 = "/test_client_alter_change/f1/t1"
- repeat_date_path = "/test_client_alter_change/f1/repeat_date"
- task_t1 = defs.find_abs_node(t1)
- task_t1.add_variable("var","value")
- task_t1.add_variable("var1","value")
- task_t1.add_event("event")
- task_t1.add_event("event1")
- task_t1.add_meter("meter",0,100,100)
- task_t1.add_meter("meter1",0,100,100)
- task_t1.add_label("label","name")
- task_t1.add_label("label1","name1")
- task_t1.add_limit("limit",10)
- task_t1.add_limit("limit1",10)
- task_t1.add_inlimit( "limit",t1,2)
- task_t1.add_inlimit( "limit1",t1,2)
- task_t1.add_trigger( "t2 == active" )
- task_t1.add_complete( "t2 == complete" )
-
- f1 = defs.find_abs_node("/test_client_alter_change/f1")
- repeat_date = f1.add_task("repeat_date")
- repeat_date.add_repeat( RepeatDate("date",20100111,20100115,2) ) # can't add cron and repeat at the same level
-
- ci.load(defs)
-
- ci.alter(t1,"change","variable","var","changed_var")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- variable = task_t1.find_variable("var")
- assert variable.value() == "changed_var", "Expected alter of variable to be 'change_var' but found " + variable.value()
-
- ci.alter(t1,"change","meter","meter","10")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- meter = task_t1.find_meter("meter")
- assert meter.value() == 10, "Expected alter of meter to be 10 but found " + str(meter.value())
-
- ci.alter(t1,"change","event","event","set")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- event = task_t1.find_event("event")
- assert event.value() == True, "Expected alter of event to be set but found " + str(event.value())
-
- ci.alter(t1,"change","trigger","t2 == aborted")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- trigger = task_t1.get_trigger()
- assert trigger.get_expression() == "t2 == aborted", "Expected alter of trigger to be 't2 == aborted' but found " + trigger.get_expression()
-
- ci.alter(t1,"change","trigger","/s1/f1/t2 == complete")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- trigger = task_t1.get_trigger()
- assert trigger.get_expression() == "/s1/f1/t2 == complete", "Expected alter of trigger to be '/s1/f1/t2 == complete' but found " + trigger.get_expression()
-
- ci.alter(t1,"change","complete","t2 == aborted")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- complete = task_t1.get_complete()
- assert complete.get_expression() == "t2 == aborted", "Expected alter of complete to be 't2 == aborted' but found " + complete.get_expression()
-
- ci.alter(t1,"change","complete","/s1/f1/t2 == active")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- complete = task_t1.get_complete()
- assert complete.get_expression() == "/s1/f1/t2 == active", "Expected alter of complete to be '/s1/f1/t2 == active' but found " + complete.get_expression()
-
- ci.alter(t1,"change","limit_max","limit", "2")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- limit = task_t1.find_limit("limit")
- assert limit != None, "Expected to find limit"
- assert limit.limit() == 2, "Expected alter of limit_max to be 2 but found " + str(limit.limit())
-
- ci.alter(t1,"change","limit_value","limit", "2")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- limit = task_t1.find_limit("limit")
- assert limit != None, "Expected to find limit"
- assert limit.value() == 2, "Expected alter of limit_value to be 2 but found " + str(limit.value())
-
-
- ci.alter(t1,"change","label","label","new-value")
- ci.sync_local()
- task_t1 = ci.get_defs().find_abs_node(t1)
- label = task_t1.find_label("label")
- assert label.new_value() == "new-value", "Expected alter of label to be 'new-value' but found " + label.new_value()
-
- ci.alter(repeat_date_path,"change","repeat","20100112")
- ci.sync_local()
- task = ci.get_defs().find_abs_node(repeat_date_path)
- repeat = task.get_repeat()
- assert repeat.value() == 20100112, "Expected alter of repeat to be 20100112 but found " + str(repeat.value())
-
-
- # ISSUES:
- # o Currently we can only change clock attr if we have one.
- # o Even when we have a clock attr, it only makes sense to apply clock attr changes
- # before begin(), i.e how do we apply change in gain after begin ??
-
- #" change clock-type name # The name must be one of 'hybrid' or 'real'.\n"
- # " change clock-gain name # The gain must be convertible to an integer.\n"
- # " change label name value # sets the label\n"
- # " change repeat value # If the repeat is a date, then the value must be a valid YMD ( ie. yyyymmdd)\n"
- # " # and be convertible to an integer, additionally the value must be in range\n"
- # " # of the repeat start and end dates. Like wise for repeat integer. For repeat\n"
- # " # string and enum, the name must either be an integer, that is a valid index or\n"
- # " # if it is a string, it must correspond to one of enum's or strings list\n"
-
-
-def test_client_force(ci):
- print "test_client_force"
- ci.delete_all()
- defs = create_defs("test_client_force")
-
- path_list = [ "/test_client_force/f1/t1", "/test_client_force/f1/t2" ]
- t1 = path_list[0]
- for path in path_list:
- task = defs.find_abs_node(path)
- assert task != None, "Expected to find task at path " + path
- task.add_event("event")
-
- ci.load(defs)
-
- state_list = [ State.unknown, State.active, State.complete, State.queued, State.submitted, State.aborted ]
- for state in state_list:
- ci.force_state(t1,state)
- ci.sync_local()
- task = ci.get_defs().find_abs_node(t1)
- assert task.get_state() == state, "Expected state " + state + " but found " + str(task.get_state())
- for state in state_list:
- ci.force_state( path_list,state)
- ci.sync_local()
- for path in path_list:
- task = ci.get_defs().find_abs_node(path)
- assert task.get_state() == state, "Expected state " + state + " but found " + str(task.get_state())
-
- for state in state_list:
- ci.force_state_recursive("/test_client_force",state)
- ci.sync_local()
- task = ci.get_defs().find_abs_node(t1)
- assert task.get_state() == state, "Expected state " + state + " but found " + str(task.get_state())
- suite_paths = [ "/test_client_force"]
- for state in state_list:
- ci.force_state_recursive( suite_paths,state)
- ci.sync_local()
- task = ci.get_defs().find_abs_node(t1)
- assert task.get_state() == state, "Expected state " + state + " but found " + str(task.get_state())
-
- event_states = [ "set", "clear" ]
- for ev_state in event_states:
- for path in path_list:
- ci.force_event(path + ":event" , ev_state)
- ci.sync_local()
- task = ci.get_defs().find_abs_node(path)
- event_fnd = False
- for event in task.events:
- event_fnd = True
- if ev_state == "set" : assert event.value() == True ," Expected event value to be set"
- else: assert event.value() == False ," Expected event value to be clear"
- assert event_fnd == True," Expected event to be found"
-
- event_path_list = [ "/test_client_force/f1/t1:event", "/test_client_force/f1/t2:event" ]
- event_states = [ "set", "clear" ]
- for ev_state in event_states:
- ci.force_event( event_path_list , ev_state)
- ci.sync_local()
- for path in path_list:
- task = ci.get_defs().find_abs_node(path)
- event_fnd = False
- for event in task.events:
- event_fnd = True
- if ev_state == "set" : assert event.value() == True ," Expected event value to be set"
- else: assert event.value() == False ," Expected event value to be clear"
- assert event_fnd == True," Expected event to be found"
-
-
-
-def test_client_replace(ci,on_disk):
- print "test_client_replace client_defs on disk = " + str(on_disk)
- # Create and load the following defs
- # s1
- # f1
- # t1
- # t2
- ci.delete_all()
- ci.load(create_defs("s1"))
-
- #===============================================================================
- # Example of using replace to ADD a *NEW* node hierarchy to an existing suite
- # we should end up with:
- # s1
- # f1
- # t1
- # t2
- # f2
- # t1
- # t2
- client_def = create_defs("s1")
- client_def.find_suite("s1").add_family("f2").add_task("t1")
- if on_disk:
- client_def.save_as_defs("test_client_replace.def")
- client_def = "test_client_replace.def"
-
- ci.replace("/s1/f2",client_def,True,False) # True means create parents as needed, False means don't bypass checks/zombies
- ci.get_server_defs()
- assert len(list(ci.get_defs().suites)) == 1 ,"Expected 1 suites:\n" + str(ci.get_defs())
- assert ci.get_defs().find_abs_node("/s1/f2/t1") != None, "Expected to find task /s1/f2/t1\n" + str(ci.get_defs())
-
-
- # Example of using replace to *REMOVE* node hierarchy to an existing suite, could have used delete
- assert ci.get_defs().find_abs_node("/s1/f1/t1") != None, "Expected to find task /s1/f1/t1\n" + str(ci.get_defs())
- assert ci.get_defs().find_abs_node("/s1/f2/t1") != None, "Expected to find task /s1/f2/t1\n" + str(ci.get_defs())
- client_def = Defs()
- client_def.add_suite("s1") # should only have the suite
- if on_disk:
- client_def.save_as_defs("test_client_replace.def")
- client_def = "test_client_replace.def"
-
- ci.replace("/s1",client_def)
- ci.get_server_defs()
- assert len(list(ci.get_defs().suites)) == 1 ,"Expected 1 suites:\n" + str(ci.get_defs())
- assert ci.get_defs().find_abs_node("/s1/f1/t1") == None, "Expected NOT to find task /s1/f1/t1\n" + str(ci.get_defs())
- assert ci.get_defs().find_abs_node("/s1/f2/t1") == None, "Expected NOT to find task /s1/f2/t1\n" + str(ci.get_defs())
-
-
- #===============================================================================
- # Example of using replace to add a *NEW* suite
- client_def = Defs();
- client_def.add_suite("s2")
- if on_disk:
- client_def.save_as_defs("test_client_replace.def")
- client_def = "test_client_replace.def"
-
- ci.replace("/s2",client_def,True,False) # True means create parents as needed, False means don't bypass checks/zombies
- ci.get_server_defs()
- assert len(list(ci.get_defs().suites)) == 2 ," Expected two suites:\n" + str(ci.get_defs())
-
- # replace added suite s2 with a new s2 which has a task,
- # s2 must exist on the client defs
- client_def = Defs();
- client_def.add_suite("s2").add_task("t1")
- if on_disk:
- client_def.save_as_defs("test_client_replace.def")
- client_def = "test_client_replace.def"
-
- ci.replace("/s2",client_def)
-
- ci.get_server_defs()
- assert len(list(ci.get_defs().suites)) == 2 ," Expected two suites:\n" + str(ci.get_defs())
- assert ci.get_defs().find_abs_node("/s2/t1") != None, "Expected to find task /s2/t1\n" + str(ci.get_defs())
- if on_disk:
- os.remove(client_def)
-
-def test_client_kill(ci):
- pass
-
-def test_client_status(ci):
- pass
-
-def test_client_order(ci):
- pass
-
-def test_client_group(ci):
- pass
-
-def test_client_suspend(ci):
- print "test_client_suspend"
- ci.delete_all()
- defs = create_defs("test_client_suspend")
- suite = defs.find_suite("test_client_suspend")
- suite.add_variable("ECF_DUMMY_TASK","")
-
- ci.load(defs)
- ci.begin_all_suites()
-
- ci.suspend("/test_client_suspend")
-
- ci.sync_local();
- suite = ci.get_defs().find_suite("test_client_suspend")
- assert suite.is_suspended(), "Expected to find suite suspended"
-
-
-def test_client_suspend_multiple_paths(ci):
- print "test_client_suspend_multiple_paths"
- ci.delete_all()
- defs = create_defs("test_client_suspend_multiple_paths")
- suite = defs.find_suite("test_client_suspend_multiple_paths")
- suite.add_variable("ECF_DUMMY_TASK","")
-
- ci.load(defs)
- ci.begin_all_suites()
-
- path_list = [ "/test_client_suspend_multiple_paths/f1/t1", "/test_client_suspend_multiple_paths/f1/t2" ]
- ci.suspend( path_list )
-
- ci.sync_local();
- task_t1 = ci.get_defs().find_abs_node("/test_client_suspend_multiple_paths/f1/t1")
- task_t2 = ci.get_defs().find_abs_node("/test_client_suspend_multiple_paths/f1/t2")
- assert task_t1.is_suspended(), "Expected to find task t1 to be suspended"
- assert task_t2.is_suspended(), "Expected to find task t2 to be suspended"
-
-def test_client_resume(ci):
- print "test_client_resume"
- ci.delete_all()
- defs = create_defs("test_client_resume")
- suite = defs.find_suite("test_client_resume")
- suite.add_variable("ECF_DUMMY_TASK","")
-
- ci.load(defs)
- ci.begin_all_suites()
-
- ci.suspend("/test_client_resume")
- ci.sync_local();
- suite = ci.get_defs().find_suite("test_client_resume")
- assert suite.is_suspended(), "Expected to find suite suspended"
-
- ci.resume("/test_client_resume")
- ci.sync_local();
- suite = ci.get_defs().find_suite("test_client_resume")
- assert suite.is_suspended() == False, "Expected to find suite resumed"
-
-def test_client_resume_multiple_paths(ci):
- print "test_client_resume_multiple_paths"
- ci.delete_all()
- defs = create_defs("test_client_resume_multiple_paths")
- suite = defs.find_suite("test_client_resume_multiple_paths")
- suite.add_variable("ECF_DUMMY_TASK","")
-
- ci.load(defs)
- ci.begin_all_suites()
-
- path_list = [ "/test_client_resume_multiple_paths/f1/t1", "/test_client_resume_multiple_paths/f1/t2" ]
- ci.suspend( path_list )
-
- ci.sync_local();
- task_t1 = ci.get_defs().find_abs_node("/test_client_resume_multiple_paths/f1/t1")
- task_t2 = ci.get_defs().find_abs_node("/test_client_resume_multiple_paths/f1/t2")
- assert task_t1.is_suspended(), "Expected to find task t1 to be suspended"
- assert task_t2.is_suspended(), "Expected to find task t2 to be suspended"
-
- ci.resume( path_list )
- ci.sync_local();
- task_t1 = ci.get_defs().find_abs_node("/test_client_resume_multiple_paths/f1/t1")
- task_t2 = ci.get_defs().find_abs_node("/test_client_resume_multiple_paths/f1/t2")
- assert task_t1.is_suspended() == False, "Expected to find task t1 to be resumed"
- assert task_t2.is_suspended() == False, "Expected to find task t2 to be resumed"
-
-
-def test_client_delete_node(ci):
- print "test_client_delete_node"
- ci.delete_all()
- defs = create_defs("test_client_delete_node")
-
- task_vec = defs.get_all_tasks();
- assert len(task_vec) > 0, "Expected some tasks but found none:\n" + str(defs)
-
- ci.load(defs)
- ci.sync_local();
- for task in task_vec:
- node = ci.get_defs().find_abs_node(task.get_abs_node_path())
- assert node != None , "Expected to find task " + task.get_abs_node_path() + ":\n" + str(ci.get_defs())
-
- for task in task_vec:
- ci.delete(task.get_abs_node_path())
-
- ci.sync_local();
- for task in task_vec:
- node = ci.get_defs().find_abs_node(task.get_abs_node_path())
- assert node == None , "Expected not to find task " + task.get_abs_node_path() + " as it should have been deleted:\n" + str(ci.get_defs())
-
-def test_client_delete_node_multiple_paths(ci):
- print "test_client_delete_node_multiple_paths"
- ci.delete_all()
- defs = create_defs("test_client_delete_node_multiple_paths")
-
- task_vec = defs.get_all_tasks();
- assert len(task_vec) > 0, "Expected some tasks but found none:\n" + str(defs)
-
- paths = []
- for task in task_vec:
- paths.append(task.get_abs_node_path())
-
- ci.load(defs)
-
- ci.sync_local();
- for task in task_vec:
- node = ci.get_defs().find_abs_node(task.get_abs_node_path())
- assert node != None , "Expected to find task " + task.get_abs_node_path() + ":\n" + str(ci.get_defs())
-
- ci.delete(paths)
-
- ci.sync_local();
- for task in task_vec:
- node = ci.get_defs().find_abs_node(task.get_abs_node_path())
- assert node == None , "Expected not to find task " + task.get_abs_node_path() + " as it should have been deleted:\n" + str(ci.get_defs())
-
-
-def test_client_check_defstatus(ci):
- print "test_client_check_defstatus"
- ci.delete_all()
- defs = create_defs("test_client_check_defstatus")
-
- # stop defs form running when begin is called.
- suite = defs.find_suite("test_client_check_defstatus")
- suite.add_defstatus(DState.suspended)
-
- t1 = "/test_client_check_defstatus/f1/t1"
- t2 = "/test_client_check_defstatus/f1/t2"
- task_t1 = defs.find_abs_node(t1)
- task_t1.add_defstatus(DState.suspended)
-
- defs.generate_scripts();
-
- job_ctrl = JobCreationCtrl()
- defs.check_job_creation(job_ctrl)
- assert len(job_ctrl.get_error_msg()) == 0, job_ctrl.get_error_msg()
-
- ci.restart_server()
- ci.load(defs)
- ci.begin_all_suites()
-
- ci.sync_local() # get the changes, synced with local defs
- #print ci.get_defs();
- task_t1 = ci.get_defs().find_abs_node(t1)
- task_t2 = ci.get_defs().find_abs_node(t2)
- assert task_t1 != None,"Could not find t1"
- assert task_t2 != None,"Could not find t2"
-
- assert task_t1.get_state() == State.queued, "Expected state queued but found " + str(task_t1.get_state())
- assert task_t2.get_state() == State.queued, "Expected state queued " + str(task_t2.get_state())
-
- assert task_t1.get_dstate() == DState.suspended, "Expected state suspended but found " + str(task_t1.get_state())
- assert task_t2.get_dstate() == DState.queued, "Expected state queued but found " + str(task_t2.get_state())
-
- dir_to_remove = Test.ecf_home(the_port) + "/" + "test_client_check_defstatus"
- shutil.rmtree(dir_to_remove)
-
-def test_ECFLOW_189(ci):
- # Bug, when a node is resumed it ignored holding dependencies higher up the tree.
- # i.e Previously when we resumed a node, it ignored trigger/time/node state, dependencies higher up the tree
- print "test_ECFLOW_189"
- ci.delete_all()
- defs = create_defs("test_ECFLOW_189")
- defs.generate_scripts();
-
- job_ctrl = JobCreationCtrl()
- defs.check_job_creation(job_ctrl)
- assert len(job_ctrl.get_error_msg()) == 0, job_ctrl.get_error_msg()
-
- ci.restart_server()
- ci.load(defs)
-
- ci.suspend("/test_ECFLOW_189")
- ci.suspend("/test_ECFLOW_189/f1/t1")
- ci.suspend("/test_ECFLOW_189/f1/t2")
-
- ci.begin_all_suites()
-
- ci.sync_local() # get the changes, synced with local defs
- #print ci.get_defs();
- task_t1 = ci.get_defs().find_abs_node("/test_ECFLOW_189/f1/t1")
- task_t2 = ci.get_defs().find_abs_node("/test_ECFLOW_189/f1/t2")
- assert task_t1 != None,"Could not find /test_ECFLOW_189/f1/t1"
- assert task_t2 != None,"Could not find /test_ECFLOW_189/f1/t2"
-
- assert task_t1.get_state() == State.queued, "Expected state queued but found " + str(task_t1.get_state())
- assert task_t2.get_state() == State.queued, "Expected state queued but found " + str(task_t2.get_state())
- assert task_t1.get_dstate() == DState.suspended, "Expected state suspended but found " + str(task_t1.get_dstate())
- assert task_t2.get_dstate() == DState.suspended, "Expected state suspended but found " + str(task_t2.get_dstate())
-
- # ok now resume t1/t2, they should remain queued, since the Suite is still suspended
- ci.resume("/test_ECFLOW_189/f1/t1")
- ci.resume("/test_ECFLOW_189/f1/t2")
-
- time.sleep(3)
- ci.sync_local() # get the changes, synced with local defs
- #print ci.get_defs();
- task_t1 = ci.get_defs().find_abs_node("/test_ECFLOW_189/f1/t1")
- task_t2 = ci.get_defs().find_abs_node("/test_ECFLOW_189/f1/t2")
- assert task_t1.get_state() == State.queued, "Expected state queued but found " + str(task_t1.get_state())
- assert task_t2.get_state() == State.queued, "Expected state queued but found " + str(task_t2.get_state())
- assert task_t1.get_dstate() == DState.queued, "Expected state queued but found " + str(task_t1.get_dstate())
- assert task_t2.get_dstate() == DState.queued, "Expected state queued but found " + str(task_t2.get_dstate())
-
- dir_to_remove = Test.ecf_home(the_port) + "/" + "test_ECFLOW_189"
- shutil.rmtree(dir_to_remove)
-
-
-def test_ECFLOW_199(ci):
- # Test ClientInvoker::changed_node_paths
- print "test_ECFLOW_199"
- ci.delete_all()
- defs = create_defs("test_ECFLOW_199")
- defs.generate_scripts();
-
- job_ctrl = JobCreationCtrl()
- defs.check_job_creation(job_ctrl)
- assert len(job_ctrl.get_error_msg()) == 0, job_ctrl.get_error_msg()
-
- ci.restart_server()
- ci.load(defs)
-
- ci.suspend("/test_ECFLOW_199")
- ci.suspend("/test_ECFLOW_199/f1/t1")
- ci.suspend("/test_ECFLOW_199/f1/t2")
-
- ci.begin_all_suites()
-
- ci.sync_local() # get the changes, synced with local defs
- #print ci.get_defs();
- assert len(list(ci.changed_node_paths)) == 0, "Expected first call to sync_local, to have no changed paths but found " + str(len(list(ci.changed_node_paths)))
-
- # ok now resume t1/t2, they should remain queued, since the Suite is still suspended
- ci.resume("/test_ECFLOW_199/f1/t1")
- ci.sync_local()
- for path in ci.changed_node_paths:
- print " changed node path " + path;
- assert len(list(ci.changed_node_paths)) == 1, "Expected 1 changed path but found " + str(len(list(ci.changed_node_paths)))
-
- ci.resume("/test_ECFLOW_199/f1/t2")
- ci.sync_local()
- for path in ci.changed_node_paths:
- print " changed node path " + path;
- assert len(list(ci.changed_node_paths)) == 1, "Expected 1 changed path but found " + str(len(list(ci.changed_node_paths)))
-
- dir_to_remove = Test.ecf_home(the_port) + "/" + "test_ECFLOW_199"
- shutil.rmtree(dir_to_remove)
-
-
-if __name__ == "__main__":
- print "####################################################################"
- print "Running ecflow version " + Client().version() + " debug build(" + str(debug_build()) +")"
- print "####################################################################"
-
- # server independent tests
- test_set_host_port();
-
- with Test.Server() as ci:
- global the_port
- the_port = ci.get_port();
- test_version(ci)
- PrintStyle.set_style( Style.STATE ) # show node state
- test_client_get_server_defs(ci)
- test_client_new_log(ci, the_port)
- test_client_clear_log(ci, the_port)
- test_client_log_msg(ci, the_port)
-
- test_client_restart_server(ci)
- test_client_halt_server(ci)
- test_client_shutdown_server(ci)
-
- test_client_load_in_memory_defs(ci)
- test_client_load_from_disk(ci)
- test_client_checkpt(ci, the_port)
- test_client_restore_from_checkpt(ci, the_port)
-
- test_client_reload_wl_file(ci, the_port)
-
- test_client_run(ci)
- test_client_run_with_multiple_paths(ci)
- test_client_requeue(ci)
- test_client_requeue_with_multiple_paths(ci)
- test_client_free_dep(ci)
-
- test_client_suites(ci)
- test_client_ch_suites(ci)
- test_client_ch_register(ci)
- test_client_ch_drop(ci)
- test_client_ch_drop_user(ci)
- test_client_ch_add(ci)
- test_client_ch_auto_add(ci)
- test_client_ch_remove(ci)
-
- test_client_get_file(ci)
- #test_client_plug(ci)
- test_client_alter_add(ci)
- test_client_alter_delete(ci)
- test_client_alter_change(ci)
-
- test_client_force(ci)
- test_client_replace(ci,False)
- test_client_replace(ci,True)
-
- #test_client_kill(ci)
- #test_client_status(ci)
- #test_client_order(ci)
- #test_client_group(ci)
- test_client_suspend(ci)
- test_client_suspend_multiple_paths(ci)
- test_client_resume(ci)
- test_client_resume_multiple_paths(ci)
- test_client_delete_node(ci)
- test_client_delete_node_multiple_paths(ci)
-
- test_client_check(ci)
- test_client_check_defstatus(ci)
-
- test_client_stats(ci)
- test_client_stats_reset(ci)
- test_client_debug_server_on_off(ci)
-
- test_ECFLOW_189(ci)
- test_ECFLOW_199(ci)
-
- print "All Tests pass ======================================================================"
diff --git a/ecflow_4_0_7/Pyext/test/py_s_TestPythonChildApi.py b/ecflow_4_0_7/Pyext/test/py_s_TestPythonChildApi.py
deleted file mode 100644
index c01b0fb..0000000
--- a/ecflow_4_0_7/Pyext/test/py_s_TestPythonChildApi.py
+++ /dev/null
@@ -1,140 +0,0 @@
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# Name :
-# Author : Avi
-# Revision : $Revision: #10 $
-#
-# Copyright 2009-2012 ECMWF.
-# This software is licensed under the terms of the Apache Licence version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation
-# nor does it submit to any jurisdiction.
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# code for testing client code in python
-import time
-import os
-import pwd
-from datetime import datetime
-import shutil # used to remove directory tree
-
-from ecflow import Defs, Clock, DState, Style, State, PrintStyle, File, Client, SState, debug_build
-import ecflow_test_util as Test
-
-
-def ecf_includes() : return Test.get_root_source_dir() + "/Pyext" + "/test/data/python_includes"
-
-def create_defs(name,the_port):
- defs = Defs()
- suite_name = name
- if len(suite_name) == 0: suite_name = "s1"
- suite = defs.add_suite(suite_name);
-
- ecfhome = Test.ecf_home(the_port);
- suite.add_variable("ECF_HOME", ecfhome);
- suite.add_variable("ECF_INCLUDE", ecf_includes());
-
- family = suite.add_family("f1")
- family.add_variable("ECF_JOB_CMD","python %ECF_JOB% 1> %ECF_JOBOUT% 2>&1")
-
- task = family.add_task("t1")
- task.add_event("event_fred")
- task.add_meter("meter", 0, 100)
- task.add_label("label_name", "value")
-
- family.add_task("t2") # test wait
-
- return defs;
-
-
-def test_client_run(ci):
- print "\ntest_client_run " + ci.get_host() + ":" + str(ci.get_port())
- print " ECF_HOME(" + Test.ecf_home(ci.get_port()) + ")"
- print " ECF_INCLUDES(" + ecf_includes() + ")"
- ci.delete_all()
- defs = create_defs("test_client_run",ci.get_port())
- suite = defs.find_suite("test_client_run")
- suite.add_defstatus(DState.suspended)
-
- # create the ecf file /test_client_run/f1/t1
- ecf_home = Test.ecf_home(ci.get_port())
- dir = ecf_home + "/test_client_run/f1"
-
- # on cray creating recursive directories can fail, try again. yuk
- try:
- if not os.path.exists(dir): os.makedirs(dir)
- except:
- try:
- if not os.path.exists(dir): os.makedirs(dir)
- except:
- # try breaking down
- if not os.path.exists(ecf_home): os.makedirs(ecf_home)
- new_dir = ecf_home + "/test_client_run"
- if not os.path.exists(new_dir): os.makedirs(new_dir)
- new_dir = ecf_home + "/test_client_run/f1"
- if not os.path.exists(new_dir): os.makedirs(new_dir)
- if not os.path.exists(dir): os.makedirs(dir)
-
- file = dir + "/t1.ecf"
- contents = "%include <head.py>\n\n"
- contents += "print 'doing some work'\n"
- contents += "try:\n"
- contents += " ci.child_event('event_fred')\n"
- contents += " ci.child_meter('meter',100)\n"
- contents += " ci.child_label('label_name','100')\n"
- contents += " print 'Finished event,meter and label child commands'\n"
- contents += "except:\n"
- contents += " ci.child_abort()\n\n"
- contents += "%include <tail.py>\n"
- open(file,'w').write(contents)
- print " Created file " + file
-
- # create the ecf file /test_client_run/f1/t2
- file = dir + "/t2.ecf"
- contents = "%include <head.py>\n\n"
- contents += "print 'Waiting for /test_client_run/f1/t1 == complete'\n"
- contents += "try:\n"
- contents += " ci.child_wait('/test_client_run/f1/t1 == complete')\n"
- contents += " print 'Finished waiting'\n"
- contents += "except:\n"
- contents += " ci.child_abort()\n\n"
- contents += "%include <tail.py>\n"
- open(file,'w').write(contents)
- print " Created file " + file
-
- ci.restart_server()
- ci.load(defs)
- ci.begin_all_suites()
- ci.run("/test_client_run", False)
- print " Running the test, wait for suite to complete ..."
-
- count = 0
- while 1:
- count += 1
- ci.sync_local() # get the changes, synced with local defs
- suite = ci.get_defs().find_suite("test_client_run")
- assert suite != None, " Expected to find suite test_client_run:\n" + str(ci.get_defs())
- if suite.get_state() == State.complete:
- break;
- if suite.get_state() == State.aborted:
- print defs;
- assert False," Suite aborted \n"
- time.sleep(2)
- if count > 20:
- assert False, " test_client_run aborted after " + str(count) + " loops:\n" + str(ci.get_defs())
-
- ci.log_msg("Looped " + str(count) + " times")
-
- if not Test.debugging():
- dir_to_remove = Test.ecf_home(ci.get_port()) + "/" + "test_client_run"
- print " Test OK: removing directory " + dir_to_remove
- shutil.rmtree(dir_to_remove)
-
-if __name__ == "__main__":
- print "####################################################################"
- print "Running ecflow version " + Client().version() + " debug build(" + str(debug_build()) +")"
- print "####################################################################"
-
- with Test.Server() as ci:
- PrintStyle.set_style( Style.STATE ) # show node state
- test_client_run(ci)
- print "\nAll Tests pass ======================================================================"
diff --git a/ecflow_4_0_7/Pyext/test/py_u_TestAddDelete.py b/ecflow_4_0_7/Pyext/test/py_u_TestAddDelete.py
deleted file mode 100644
index f1d1a19..0000000
--- a/ecflow_4_0_7/Pyext/test/py_u_TestAddDelete.py
+++ /dev/null
@@ -1,484 +0,0 @@
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# Name :
-# Author : Avi
-# Revision : $Revision: #10 $
-#
-# Copyright 2009-2012 ECMWF.
-# This software is licensed under the terms of the Apache Licence version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation
-# nor does it submit to any jurisdiction.
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-# code for testing addition and deletion
-#
-import ecflow
-import sys
-import os
-
-if __name__ == "__main__":
-
- print "####################################################################"
- print "Running ecflow version " + ecflow.Client().version() + " debug build(" + str(ecflow.debug_build()) +")"
- print "PYTHONPATH: " + str(os.environ['PYTHONPATH'].split(os.pathsep))
- print "sys.path: " + str(sys.path)
- print "####################################################################"
-
- #===========================================================================
- # Defs: add and delete *USER* variables
- #===========================================================================
- defs = ecflow.Defs()
- defs.add_variable("FRED", "/tmp/")
- defs.add_variable("ECF_URL_CMD", "${BROWSER:=firefox} -remote 'openURL(%ECF_URL_BASE%/%ECF_URL%)'")
- defs.add_variable("ECF_URL_BASE", "http://www.ecmwf.int")
- defs.add_variable("ECF_URL", "publications/manuals/sms")
- assert len(list(defs.user_variables)) == 4, "Expected *user* 4 variable"
- defs.delete_variable("FRED"); assert len(list(defs.user_variables)) == 3, "Expected 3 variables since we just delete FRED"
- defs.delete_variable(""); assert len(list(defs.user_variables)) == 0, "Expected 0 variables since we should have deleted all"
-
- a_dict = { "name":"value", "name2":"value2", "name3":"value3", "name4":"value4" }
- defs.add_variable(a_dict)
- assert len(list(defs.user_variables)) == 4, "Expected 4 variable"
- defs.delete_variable(""); assert len(list(defs.user_variables)) == 0, "Expected 0 variable since we should have deleted all"
-
- # add a empty dictionary
- a_dict = {}
- defs.add_variable(a_dict)
- assert len(list(defs.user_variables)) == 0, "Expected zero variables"
-
- #===========================================================================
- # Suite: add and delete variables
- #===========================================================================
- suite = ecflow.Suite("s1")
- suite.add_variable(ecflow.Variable("ECF_HOME", "/tmp/"))
- suite.add_variable("ECF_URL_CMD", "${BROWSER:=firefox} -remote 'openURL(%ECF_URL_BASE%/%ECF_URL%)'")
- suite.add_variable("ECF_URL_BASE", "http://www.ecmwf.int")
- suite.add_variable("ECF_URL", "publications/manuals/sms")
- assert len(list(suite.variables)) == 4, "Expected 4 variable"
- suite.delete_variable("ECF_HOME"); assert len(list(suite.variables)) == 3, "Expected 3 variable since we just delete ECF_HOME"
- suite.delete_variable(""); assert len(list(suite.variables)) == 0, "Expected 0 variable since we should have deleted all"
-
- a_dict = { "name":"value", "name2":"value2", "name3":"value3", "name4":"value4" }
- suite.add_variable(a_dict)
- assert len(list(suite.variables)) == 4, "Expected 4 variable"
- suite.delete_variable(""); assert len(list(suite.variables)) == 0, "Expected 0 variable since we should have deleted all"
-
- # add a empty dictionary
- a_dict = { }
- suite.add_variable(a_dict)
- assert len(list(suite.variables)) == 0, "Expected zero variables"
-
- # adding dictionary items that are not strings should result in a type error
- expected_type_error = False
- try:
- a_bad_dict = { "name":"fred", "name2":14, "name3":"12", "name4":12 }
- suite.add_variable(a_bad_dict)
- except TypeError:
- expected_type_error = True
-
- assert expected_type_error, "Expected Type error"
- assert len(list(suite.variables)) == 0, "Expected 0 variable since we should have deleted all"
-
- suite.add_variable("ECF_URL_CMD", "test duplicates")
- suite.add_variable("ECF_URL_CMD", "Expected warning") # expect a warning message to standard out
-
-
- #===========================================================================
- # add and delete limits
- #===========================================================================
- suite.add_limit(ecflow.Limit("limitName1", 10))
- suite.add_limit(ecflow.Limit("limitName2", 10))
- suite.add_limit("limitName3", 10)
- suite.add_limit("limitName4", 10)
- assert len(list(suite.limits)) == 4, "Expected 4 Limits"
- suite.delete_limit("limitName1"); assert len(list(suite.limits)) == 3, "Expected 3 limits since we just deleted one limitName1"
- suite.delete_limit(""); assert len(list(suite.limits)) == 0, "Expected 0 limits since we just deleted all of them"
-
-
- #===========================================================================
- # add and delete inlimits
- #===========================================================================
- suite.add_inlimit(ecflow.InLimit("limitName1", "/s1/f1", 2))
- suite.add_inlimit(ecflow.InLimit("limitName2", "/s1/f1", 2))
- suite.add_inlimit("limitName3", "/s1/f1", 2)
- suite.add_inlimit("limitName4", "/s1/f1", 2)
- assert len(list(suite.inlimits)) == 4, "Expected 4 inLimits"
- suite.delete_inlimit("limitName1"); assert len(list(suite.inlimits)) == 3, "Expected 3 inlimits since we just deleted one limitName1"
- suite.delete_inlimit(""); assert len(list(suite.inlimits)) == 0, "Expected 0 inlimits since we just deleted all of them"
-
- #===============================================================================
- # add and delete triggers and complete
- #===============================================================================
- task = ecflow.Task("task")
- task.add_trigger("t2 == active")
- task.add_complete("t2 == complete")
- assert task.get_complete(), "Expected complete"
- assert task.get_trigger(), "Expected trigger"
- task.delete_trigger(); assert not task.get_trigger(), "Expected no trigger"
- task.delete_complete(); assert not task.get_complete(), "Expected no complete"
-
- task.add_part_trigger(ecflow.PartExpression("t1 == complete"))
- task.add_part_trigger(ecflow.PartExpression("t2 == active", True)) # for long and/or expressions, subsequent expr must be and/or
- task.add_part_complete(ecflow.PartExpression("t3 == complete"))
- task.add_part_complete(ecflow.PartExpression("t4 == active", False)) # for long and/or expressions, subsequent expr must be and/or
- task.delete_trigger(); assert not task.get_trigger(), "Expected no trigger"
- task.delete_complete(); assert not task.get_complete(), "Expected no complete"
-
- task.add_part_trigger("t1 == complete")
- task.add_part_trigger("t2 == active", True) # for long and/or expressions, subsequent expr must be and/or
- task.add_part_complete("t3 == complete")
- task.add_part_complete("t4 == active", False) # for long and/or expressions, subsequent expr must be and/or
- task.delete_trigger(); assert not task.get_trigger(), "Expected no trigger"
- task.delete_complete(); assert not task.get_complete(), "Expected no complete"
-
- #===========================================================================
- # Add triggers using expressions
- #===========================================================================
- expr = ecflow.Expression("t1 == complete")
- task = ecflow.Task("task")
- task.add_trigger(expr)
-
- expr = ecflow.Expression("t1 == complete")
- expr.add(ecflow.PartExpression("t1 == complete", True))
- expr.add(ecflow.PartExpression("t2 == complete", True))
- task = ecflow.Task("task")
- task.add_trigger(expr)
-
-
- #===========================================================================
- # add,delete,find events
- #===========================================================================
- task.add_event(ecflow.Event(1));
- task.add_event(2)
- task.add_event(ecflow.Event(10, "Eventname"))
- task.add_event(10, "Eventname2")
- task.add_event("fred")
-
- # test find
- event = task.find_event("EVENT")
- assert(event.empty()),"Expected to not to find event"
- assert(event.name() == ""),"Expected to not to find event, number is maximum int"
- assert(event.value() == 0),"Expected to not to find event"
-
- event = task.find_event("1");
- assert(not event.empty()),"Expected to find event"
- assert(event.number() == 1), "Expected to find event 1"
- assert(event.name() == ""), "Expected name to be empty"
- assert(event.value() == 0),"Expected to not to find event"
-
- event = task.find_event("2");
- assert(not event.empty()),"Expected to find event"
- assert(event.number() == 2), "Expected to find event 1"
- assert(event.name() == ""), "Expected name to be empty"
- assert(event.value() == 0),"Expected to not to find event"
-
- event = task.find_event("10");
- assert(not event.empty()),"Expected to find event"
- assert(event.number() == 10), "Expected to find event 10"
- assert(event.name() == "Eventname"), "Expected name to be empty"
- assert(event.value() == 0),"Expected to not to find event"
-
- event = task.find_event("fred");
- assert(not event.empty()),"Expected to find event"
- assert(event.name() == "fred"), "Expected name to be empty, when name defind an not number, number is max_int"
- assert(event.value() == 0),"Expected to not to find event"
-
- for e in task.events: print str(e)," # value: ",str(e.value())
- a_dict = {}
- for e in task.events:
- if e.name() != "": a_dict[e.name()] = e.value()
- else: a_dict[e.number()] = e.value()
- print a_dict
-
- assert len(list(task.events)) == 5, "Expected 5 Events"
- task.delete_event("1"); assert len(list(task.events)) == 4, "Expected 4 Events"
- task.delete_event("Eventname"); assert len(list(task.events)) == 3, "Expected 3 Events"
- task.delete_event(""); assert len(list(task.events)) == 0, "Expected 0 Events"
-
-
- #===========================================================================
- # add and delete meter
- #===========================================================================
- task.add_meter(ecflow.Meter("metername1", 0, 100, 50))
- task.add_meter(ecflow.Meter("metername2", 0, 100))
- task.add_meter("metername3", 0, 100, 50)
- task.add_meter("metername4", 0, 100)
- assert len(list(task.meters)) == 4, "Expected 4 Meters"
- task.delete_meter("metername1"); assert len(list(task.meters)) == 3, "Expected 3 Meters"
- task.delete_meter("metername4"); assert len(list(task.meters)) == 2, "Expected 2 Meters"
- task.delete_meter(""); assert len(list(task.meters)) == 0, "Expected 0 Meters"
-
-
- #===========================================================================
- # add and delete label
- #===========================================================================
- task.add_label(ecflow.Label("label_name1", "value"))
- task.add_label(ecflow.Label("label_name2", "value"))
- task.add_label("label_name3", "value")
- task.add_label("label_name4", "value")
- assert len(list(task.labels)) == 4, "Expected 4 labels"
- task.delete_label("label_name1"); assert len(list(task.labels)) == 3, "Expected 3 Labels"
- task.delete_label("label_name4"); assert len(list(task.labels)) == 2, "Expected 2 Labels"
- task.delete_label(""); assert len(list(task.labels)) == 0, "Expected 0 Labels"
-
-
- #===========================================================================
- # add delete Repeat
- #===========================================================================
- task.add_repeat(ecflow.RepeatInteger("integer", 0, 100, 2))
- repeat = task.get_repeat(); assert not repeat.empty(), "Expected repeat"
- task.delete_repeat()
- repeat = task.get_repeat(); assert repeat.empty(), "Expected no repeat"
-
- task.add_repeat(ecflow.RepeatEnumerated("enum", ["red", "green", "blue" ]))
- print task
- task.delete_repeat()
- repeat = task.get_repeat(); assert repeat.empty(), "Expected no repeat"
-
- task.add_repeat(ecflow.RepeatDate("date", 20100111, 20100115, 2))
- task.delete_repeat()
- repeat = task.get_repeat(); assert repeat.empty(), "Expected no repeat"
-
- task.add_repeat(ecflow.RepeatString("string", ["a", "b", "c" ]))
- task.delete_repeat()
- repeat = task.get_repeat(); assert repeat.empty(), "Expected no repeat"
-
-
- #===========================================================================
- # create a time series, used for adding time and today
- #===========================================================================
- start = ecflow.TimeSlot(0, 0)
- finish = ecflow.TimeSlot(23, 0)
- incr = ecflow.TimeSlot(0, 30)
- time_series = ecflow.TimeSeries(start, finish, incr, True)
-
- # Add and delete today
- # NOTE: **********************************************************************
- # Do *NOT* delete attributes using iterator traversal
- # The iterators *are* bound to the c++ iterators hence if we delete
- # over the traversal, we can corrupt the vector, leading to undefined behavour.
- # Hence we **can not** delete more than once over a traversal
- # Soln 1: take a copy
- # *****************************************************************************
- # task.add_today( Today( 0,10 ))
- # task.add_today( Today( 0,59, True ))
- # task.add_today( Today(TimeSlot(20,10)) )
- # task.add_today( Today(TimeSlot(20,20),False))
- # for today in task.todays:
- # task.delete_today(today) # will corrupt C++ vector
-
- task.add_today("00:30")
- task.add_today("+00:30")
- task.add_today("+00:30 20:00 01:00")
- task.add_today(ecflow.Today(time_series))
- task.add_today(ecflow.Today(0, 10))
- task.add_today(0, 59, True)
- task.add_today(ecflow.Today(ecflow.TimeSlot(20, 10)))
- task.add_today(ecflow.Today(ecflow.TimeSlot(20, 20), False))
- assert len(list(task.todays)) == 8, "Expected 8 todays"
- vec_copy = []
- for today in task.todays: vec_copy.append(today)
- for today in vec_copy: task.delete_today(today)
- assert len(list(task.todays)) == 0, "Expected 0 todays"
-
- #===========================================================================
- # add and delete time
- #===========================================================================
- task.add_time("00:30")
- task.add_time("+00:30")
- task.add_time("+00:30 20:00 01:00")
- task.add_time(ecflow.Time(time_series))
- task.add_time(ecflow.Time(0, 10))
- task.add_time(0, 59, True)
- task.add_time(ecflow.Time(ecflow.TimeSlot(20, 10)))
- task.add_time(ecflow.Time(ecflow.TimeSlot(20, 20), False))
- assert len(list(task.times)) == 8, "Expected 8 times"
- vec_copy = []
- for time in task.times: vec_copy.append(time)
- for time in vec_copy: task.delete_time(time)
- assert len(list(task.todays)) == 0, "Expected 0 todays"
-
- #===========================================================================
- # add and delete date
- #===========================================================================
- for i in [ 1, 2, 4, 8, 16 ] :
- task.add_date(i, 0, 0)
- task.add_date(ecflow.Date(1, 1, 2010))
- task.add_date(1, 1, 2010) # duplicate
- task.add_date(ecflow.Date(2, 1, 2010))
- task.add_date(ecflow.Date(3, 1, 2010))
- task.add_date(ecflow.Date(4, 1, 2010))
- assert len(list(task.dates)) == 10, "Expected 10 dates but found " + str(len(list(task.dates)))
- vec_copy = []
- for attr in task.dates: vec_copy.append(attr)
- for attr in vec_copy: task.delete_date(attr)
- assert len(list(task.dates)) == 0, "Expected 0 dates"
-
- #===========================================================================
- # add and delete day
- #===========================================================================
- task.add_day(ecflow.Day(ecflow.Days.sunday))
- task.add_day(ecflow.Days.monday)
- task.add_day(ecflow.Days.tuesday) # duplicate ?
- task.add_day("sunday")
- assert len(list(task.days)) == 4, "Expected 4 days"
- vec_copy = []
- for attr in task.days: vec_copy.append(attr)
- for attr in vec_copy: task.delete_day(attr)
- assert len(list(task.days)) == 0, "Expected 0 days"
-
- #===========================================================================
- # add and delete crons
- #===========================================================================
- cron = ecflow.Cron()
- start = ecflow.TimeSlot(23 , 0)
- ts = ecflow.TimeSeries(start,True) # True means relative to suite start
- cron.set_time_series(ts)
-
- cron = ecflow.Cron()
- cron.set_week_days([0, 1, 2, 3, 4, 5, 6])
- cron.set_days_of_month([1, 2, 3, 4, 5, 6 ])
- cron.set_months([1, 2, 3, 4, 5, 6])
- start = ecflow.TimeSlot(0 , 0)
- finish = ecflow.TimeSlot(23, 0)
- incr = ecflow.TimeSlot(0, 30)
- ts = ecflow.TimeSeries(start, finish, incr, True) # True means relative to suite start
- cron.set_time_series(ts)
-
- cron0 = ecflow.Cron()
- cron0.set_week_days([0, 1, 2, 3, 4, 5 ])
- cron0.set_time_series(1, 30) # default relative = false, added in release 4.0.7
-
- cron1 = ecflow.Cron()
- cron1.set_week_days([0, 1, 2, 3, 4, 5, 6 ])
- cron1.set_time_series(1, 30, True)
-
- cron2 = ecflow.Cron()
- cron2.set_week_days([0, 1, 2, 3, 4, 5, 6])
- cron2.set_time_series("00:30 01:30 00:01")
-
- cron3 = ecflow.Cron()
- cron3.set_week_days([0, 1, 2, 3, 4, 5, 6])
- cron3.set_time_series("+00:30")
-
- task.add_cron(cron)
- task.add_cron(cron1)
- task.add_cron(cron2)
- task.add_cron(cron3)
- assert len(list(task.crons)) == 4, "Expected 4 crons"
- vec_copy = []
- for attr in task.crons: vec_copy.append(attr)
- for attr in vec_copy: task.delete_cron(attr)
- assert len(list(task.crons)) == 0, "Expected 0 crons"
-
- #===========================================================================
- # add autocancel
- #===========================================================================
- print "test add autoCancel"
- t1 = ecflow.Task("t1")
- assert t1.get_autocancel() == None, " Expected no autocancel"
- t1.add_autocancel(3) # 3 days
- assert t1.get_autocancel() != None, " Expected autocancel"
- print str(t1.get_autocancel())
-
- t3 = ecflow.Task("t3")
- t3.add_autocancel(20, 10, True) # hour,minutes,relative
- print str(t3.get_autocancel())
-
- t4 = ecflow.Task("t4")
- t4.add_autocancel(ecflow.TimeSlot(10, 10), True) # hour,minutes,relative
- print str(t4.get_autocancel())
-
- t5 = ecflow.Task("t5")
- t5.add_autocancel(ecflow.Autocancel(1, 10, True)) # hour,minutes,relative
- print str(t5.get_autocancel())
-
- #===========================================================================
- # add late
- #===========================================================================
- late = ecflow.Late()
- late.submitted(ecflow.TimeSlot(20, 10))
- late.active(ecflow.TimeSlot(20, 10))
- late.complete(ecflow.TimeSlot(20, 10), True)
- task.add_late(late)
-
- late = ecflow.Late()
- late.submitted(20, 10)
- late.active(20, 10)
- late.complete(20, 10, True)
- t1.add_late(late)
-
-
- #===========================================================================
- # add defstatus, last one set takes effect
- #===========================================================================
- task.add_defstatus(ecflow.DState.complete)
- assert task.get_defstatus() == ecflow.DState.complete
- task.add_defstatus(ecflow.DState.queued)
- assert task.get_defstatus() == ecflow.DState.queued
- task.add_defstatus(ecflow.DState.aborted)
- assert task.get_defstatus() == ecflow.DState.aborted
- task.add_defstatus(ecflow.DState.submitted)
- assert task.get_defstatus() == ecflow.DState.submitted
- task.add_defstatus(ecflow.DState.suspended)
- assert task.get_defstatus() == ecflow.DState.suspended
- task.add_defstatus(ecflow.DState.active)
- assert task.get_defstatus() == ecflow.DState.active
-
- # the state should be unknown until the suite is begun
- assert task.get_state() == ecflow.State.unknown
- assert task.get_dstate() == ecflow.DState.unknown
-
- #===========================================================================
- # add clock
- #===========================================================================
- clock = ecflow.Clock(1, 1, 2010, False) # day,month, year, hybrid
- clock.set_gain(1, 10, True) # True means positive gain
- suite = ecflow.Suite("suite")
- suite.add_clock(clock)
-
- clock = ecflow.Clock(1, 1, 2011, True) # day,month, year, hybrid
- clock.set_gain_in_seconds(12, True)
- s1 = ecflow.Suite("s1")
- s1.add_clock(clock)
-
- print "#==========================================================================="
- print "# get clock"
- print "#==========================================================================="
- s0 = ecflow.Suite("s0")
- assert s0.get_clock() == None, "Expected no clock"
-
- s0.add_clock(ecflow.Clock(1, 1, 2010, False))
- assert s0.get_clock() != None, "Expected clock"
-
- #===========================================================================
- # Add zombie. Note we can *NOT* add two zombie attributes of the same ZombieType
- #===========================================================================
- zombie_life_time_in_server = 800
- child_list = [ ecflow.ChildCmdType.init, ecflow.ChildCmdType.event, ecflow.ChildCmdType.meter, ecflow.ChildCmdType.label, ecflow.ChildCmdType.wait, ecflow.ChildCmdType.abort, ecflow.ChildCmdType.complete ]
- zombie_type_list = [ ecflow.ZombieType.ecf, ecflow.ZombieType.user, ecflow.ZombieType.path ]
- for zombie_type in zombie_type_list:
- zombie_attr = ecflow.ZombieAttr(zombie_type, child_list, ecflow.ZombieUserActionType.block, zombie_life_time_in_server)
- s1.add_zombie(zombie_attr)
-
- assert len(list(s1.zombies)) == 3, "Expected 3 zombie attributes but found " + str(len(list(s1.zombies)))
-
- # delete all the zombies
- s1.delete_zombie("")
- assert len(list(s1.zombies)) == 0, "Expected zero zombie attributes but found " + str(len(list(s1.zombies)))
-
- # repeat the the test with empty child list. Empty child list means apply to all child commands
- child_list = [ ]
- zombie_type_list = [ ecflow.ZombieType.ecf, ecflow.ZombieType.user, ecflow.ZombieType.path ]
- for zombie_type in zombie_type_list:
- zombie_attr = ecflow.ZombieAttr(zombie_type, child_list, ecflow.ZombieUserActionType.block, zombie_life_time_in_server)
- s1.add_zombie(zombie_attr)
-
- # test delete of specific zombie attribute
- assert len(list(s1.zombies)) == 1, "Expected 1 zombie attributes but found " + str(len(list(s1.zombies)))
- s1.delete_zombie(zombie_type)
- assert len(list(s1.zombies)) == 0, "Expected 0 zombie attributes but found " + str(len(list(s1.zombies)))
-
- print "All Tests pass"
-
diff --git a/ecflow_4_0_7/Pyext/test/py_u_TestAddDeleteError.py b/ecflow_4_0_7/Pyext/test/py_u_TestAddDeleteError.py
deleted file mode 100644
index c6920fd..0000000
--- a/ecflow_4_0_7/Pyext/test/py_u_TestAddDeleteError.py
+++ /dev/null
@@ -1,86 +0,0 @@
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# Name :
-# Author : Avi
-# Revision : $Revision: #10 $
-#
-# Copyright 2009-2012 ECMWF.
-# This software is licensed under the terms of the Apache Licence version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation
-# nor does it submit to any jurisdiction.
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#
-from ecflow import Defs, Suite, Variable, Limit, InLimit, Task, PartExpression, \
- Event, Meter, Label, RepeatInteger, RepeatEnumerated, RepeatDate, RepeatString, \
- TimeSlot, TimeSeries, Today, Time, Date, Day, Days, Cron, Autocancel, Late, \
- DState, Clock, ChildCmdType, ZombieType, ZombieAttr, ZombieUserActionType, Client, debug_build
-
-
-if __name__ == "__main__":
-
- print "######################################################################################"
- print "Running ecflow version " + Client().version() + " debug build(" + str(debug_build()) +")"
- print "######################################################################################"
-
- #
- # Test for: See ECFLOW-106 Times/Dates attributes attached to suite node
- #
- defs = Defs()
- suite = defs.add_suite("s1")
-
- #
- # Suite should not be allowed time based dependencies
- # Check Today
- expected_error = False
- try:
- suite.add_today("00:30")
- except RuntimeError:
- expected_error = True
- assert expected_error, "Suite should not allow any time based dependencies"
-
- expected_error = False
- try:
- suite.add_today(0,30)
- except RuntimeError:
- expected_error = True
- assert expected_error, "Suite should not allow any time based dependencies"
-
- #
- # Check Time
- expected_error = False
- try:
- suite.add_time("+00:30")
- except RuntimeError:
- expected_error = True
- assert expected_error, "Suite should not allow any time based dependencies"
-
- expected_error = False
- try:
- suite.add_time(0,30)
- except RuntimeError:
- expected_error = True
- assert expected_error, "Suite should not allow any time based dependencies"
-
- #
- # Check Date::See ECFLOW-106 Times/Dates attributes attached to suite node
- expected_error = False
- try:
- suite.add_date( 1,1,2010)
- except RuntimeError:
- expected_error = True
- assert expected_error, "Suite should not allow any time based dependencies"
-
- #
- # Check Day:: See ECFLOW-106 Times/Dates attributes attached to suite node
- expected_error = False
- try:
- suite.add_day("sunday")
- except RuntimeError:
- expected_error = True
- assert expected_error, "Suite should not allow any time based dependencies"
-
-
- print "All Tests pass"
-
\ No newline at end of file
diff --git a/ecflow_4_0_7/Pyext/test/py_u_TestAddDeleteFunc.py b/ecflow_4_0_7/Pyext/test/py_u_TestAddDeleteFunc.py
deleted file mode 100644
index 4c69289..0000000
--- a/ecflow_4_0_7/Pyext/test/py_u_TestAddDeleteFunc.py
+++ /dev/null
@@ -1,311 +0,0 @@
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# Name :
-# Author : Avi
-# Revision : $Revision: #10 $
-#
-# Copyright 2009-2012 ECMWF.
-# This software is licensed under the terms of the Apache Licence version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation
-# nor does it submit to any jurisdiction.
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#
-from ecflow import Defs, Suite, Variable, Limit, InLimit, Task, PartExpression, \
- Event, Meter, Label, RepeatInteger, RepeatEnumerated, RepeatDate, RepeatString, \
- TimeSlot, TimeSeries, Today, Time, Date, Day, Days, Cron, Autocancel, Late, \
- DState, Clock, ChildCmdType, ZombieType, ZombieAttr, ZombieUserActionType, Client, debug_build
-
-
-if __name__ == "__main__":
-
- print "####################################################################"
- print "Running ecflow version " + Client().version() + " debug build(" + str(debug_build()) +")"
- print "####################################################################"
-
- #
- # Add Nodes functional way
- #
- defs = Defs()
- defs.add_suite("s1").add_task("t1").add_variable("var","v")
- defs.add_suite("s2").add_family("f1").add_task("t1").add_variable("var","v")
- defs.add_suite("s3").add_family("f1").add_family("f2").add_task("t1").add_variable("var","v")
- assert len(list(defs.suites)) == 3,"Expected 3 suites"
-
-
- # add and delete variables
- a_dict = { "name":"value", "name2":"value2", "name3":"value3", "name4":"value4" }
- suite = Suite("s1")
- suite.add_variable(Variable("ECF_HOME","'/tmp/'")) \
- .add_variable("Fred", 1)\
- .add_variable("ECF_URL_BASE",'http://www.ecmwf.int')\
- .add_variable("ECF_URL",'"publications/manuals/sms"')\
- .add_variable(a_dict)
- print suite
- assert len(list(suite.variables)) == 8,"Expected 8 variable"
- suite.delete_variable(""); assert len(list(suite.variables)) == 0,"Expected 0 variable since we should have deleted all"
-
-
- # add and delete limits
- the_limit = Limit("limitName1", 10)
- assert len(list(the_limit.node_paths)) == 0 ,"Expected nodes which have consumed a limit to be empty"
- suite.add_limit( Limit("limitName1", 10) )\
- .add_limit( Limit("limitName2", 10) )\
- .add_limit( "limitName3", 10 )\
- .add_limit( "limitName4", 10 )
- assert len(list(suite.limits)) == 4,"Expected 4 Limits"
- suite.delete_limit(""); assert len(list(suite.limits)) == 0,"Expected 0 limits since we just deleted all of them"
-
-
- # add and delete inlimits
- suite.add_inlimit( InLimit("limitName1","/s1/f1",2) )\
- .add_inlimit( InLimit("limitName2","/s1/f1",2))\
- .add_inlimit( "limitName3","/s1/f1",2)\
- .add_inlimit( "limitName4","/s1/f1",2)
- assert len(list(suite.inlimits)) == 4,"Expected 4 inLimits"
- suite.delete_inlimit("limitName1"); assert len(list(suite.inlimits)) == 3,"Expected 3 inlimits since we just deleted one limitName1"
- suite.delete_inlimit(""); assert len(list(suite.inlimits)) == 0,"Expected 0 inlimits since we just deleted all of them"
-
-
- # add and delete triggers and complete
- task = Task("task")
- task.add_trigger( "t2 == active" ).add_complete( "t2 == complete" )
- assert task.get_complete(), "Expected complete"
- assert task.get_trigger(), "Expected trigger"
- task.delete_trigger(); assert not task.get_trigger(), "Expected no trigger"
- task.delete_complete(); assert not task.get_complete(), "Expected no complete"
-
- task.add_part_trigger( PartExpression("t1 == complete") )\
- .add_part_complete( PartExpression("t3 == complete") ) \
- .add_part_complete( PartExpression("t4 == active",False) )
- task.delete_trigger(); assert not task.get_trigger(), "Expected no trigger"
- task.delete_complete(); assert not task.get_complete(), "Expected no complete"
-
- task.add_part_trigger( "t1 == complete" ) \
- .add_part_complete( "t3 == complete" ) \
- .add_part_complete( "t4 == active",False) # for long and/or expressions, subsequent expr must be and/or
- task.delete_trigger(); assert not task.get_trigger(), "Expected no trigger"
- task.delete_complete(); assert not task.get_complete(), "Expected no complete"
-
-
- # add and delete events
- task.add_event( Event(1) ).add_event( 2 ).add_event( Event(10, "Eventname") ).add_event( 10, "Eventname2" ).add_event( "fred" )
- assert len(list(task.events)) == 5,"Expected 5 Events"
- task.delete_event(""); assert len(list(task.events)) == 0,"Expected 0 Events"
-
-
- # add and delete meter
- task.add_meter( Meter("metername1", 0, 100, 50) )\
- .add_meter( Meter("metername2", 0, 100) )\
- .add_meter( "metername3", 0, 100, 50 )\
- .add_meter( "metername4", 0, 100 )
- assert len(list(task.meters)) == 4,"Expected 4 Meters"
- task.delete_meter(""); assert len(list(task.meters)) == 0,"Expected 0 Meters"
-
-
- # add and delete label
- task.add_label( Label("label_name1", "value") )\
- .add_label( Label("label_name2", "value") )\
- .add_label( "label_name3", "value" )\
- .add_label( "label_name4", "value" )
- assert len(list(task.labels)) == 4,"Expected 4 labels"
- task.delete_label(""); assert len(list(task.labels)) == 0,"Expected 0 Labels"
-
-
- # add delete Repeat
- task.add_repeat( RepeatInteger("integer", 0, 100, 2) ).add_variable("fred","j")
- repeat = task.get_repeat(); assert not repeat.empty(), "Expected repeat"
- task.delete_repeat()
- repeat = task.get_repeat(); assert repeat.empty(), "Expected no repeat"
-
- task.add_repeat( RepeatEnumerated("enum", ["red", "green", "blue" ]) ).add_variable("Q","j")
- print task
- task.delete_repeat()
- repeat = task.get_repeat(); assert repeat.empty(), "Expected no repeat"
-
- task.add_repeat( RepeatDate("date", 20100111, 20100115,2) ).add_variable("W","j")
- task.delete_repeat()
- repeat = task.get_repeat(); assert repeat.empty(), "Expected no repeat"
-
- task.add_repeat( RepeatString("string", ["a", "b", "c" ] ) ).add_variable("E","j")
- task.delete_repeat()
- repeat = task.get_repeat(); assert repeat.empty(), "Expected no repeat"
-
-
- # create a time series, used for adding time and today
- start = TimeSlot(0, 0)
- finish = TimeSlot(23, 0)
- incr = TimeSlot(0, 30)
- time_series = TimeSeries( start, finish, incr, True)
-
- # Add and delete today
- # NOTE: **********************************************************************
- # Do *NOT* delete attributes using iterator traversal
- # The iterators *are* bound to the c++ iterators hence if we delete
- # over the traversal, we can corrupt the vector, leading to undefined behaviour.
- # Hence we **can not** delete more than once over a traversal
- # Soln 1: take a copy
- # *****************************************************************************
- # task.add_today( Today( 0,10 ))
- # task.add_today( Today( 0,59, True ))
- # task.add_today( Today(TimeSlot(20,10)) )
- # task.add_today( Today(TimeSlot(20,20),False))
- # for today in task.todays:
- # task.delete_today(today) # will corrupt C++ vector
-
- task.add_today( "00:30" ).add_today( "+00:30" ).add_today( "+00:30 20:00 01:00" )\
- .add_today( Today( time_series) )\
- .add_today( Today( 0,10 )).add_today( 0, 59, True )\
- .add_today( Today(TimeSlot(20,10)) )\
- .add_today( Today(TimeSlot(20,20),False))
- assert len(list(task.todays)) == 8,"Expected 8 todays"
- vec_copy = []
- for today in task.todays: vec_copy.append(today)
- for today in vec_copy: task.delete_today(today)
- assert len(list(task.todays)) == 0,"Expected 0 todays"
-
-
- # add and delete time
- task.add_time( "00:30" ).add_time( "+00:30" ).add_time( "+00:30 20:00 01:00" )\
- .add_time( Time(time_series ))\
- .add_time( Time( 0,10 ))\
- .add_time( 0, 59, True)\
- .add_time( Time(TimeSlot(20,10)) )\
- .add_time( Time(TimeSlot(20,20),False))
- assert len(list(task.times)) == 8,"Expected 8 times"
- vec_copy = []
- for time in task.times: vec_copy.append(time)
- for time in vec_copy: task.delete_time(time)
- assert len(list(task.todays)) == 0,"Expected 0 todays"
-
-
- # add and delete date
- for i in [ 1, 2, 4, 8, 16 ] :
- task.add_date( i, 0, 0)
- task.add_date( Date(1, 1, 2010))\
- .add_date( Date(2, 1, 2010))\
- .add_date( Date(3, 1, 2010))\
- .add_date( Date(4, 1, 2010))\
- .add_date( 1, 1, 2010)
- assert len(list(task.dates)) == 10,"Expected 10 dates but found " + str(len(list(task.dates)))
- vec_copy = []
- for attr in task.dates: vec_copy.append(attr)
- for attr in vec_copy: task.delete_date(attr)
- assert len(list(task.dates)) == 0,"Expected 0 dates"
-
- # add and delete day
- task.add_day( Day(Days.sunday))\
- .add_day( Days.monday)\
- .add_day( Days.tuesday)\
- .add_day( "sunday")
- assert len(list(task.days)) == 4,"Expected 4 days"
- vec_copy = []
- for attr in task.days: vec_copy.append(attr)
- for attr in vec_copy: task.delete_day(attr)
- assert len(list(task.days)) == 0,"Expected 0 days"
-
- # add and delete crons
- cron = Cron()
- cron.set_week_days( [0, 1, 2, 3, 4, 5, 6] )
- cron.set_days_of_month( [1, 2, 3, 4, 5, 6 ] )
- cron.set_months( [1, 2, 3, 4, 5, 6] )
- start = TimeSlot(0 ,0)
- finish = TimeSlot(23, 0)
- incr = TimeSlot(0, 30)
- ts = TimeSeries( start, finish, incr, True) # True means relative to suite start
- cron.set_time_series( ts )
-
- cron1 = Cron()
- cron1.set_week_days( [0, 1, 2, 3, 4, 5, 6 ] )
- cron1.set_time_series( 1, 30, True )
-
- cron2 = Cron()
- cron2.set_week_days( [0, 1, 2, 3, 4, 5, 6] )
- cron2.set_time_series( "00:30 01:30 00:01" )
-
- cron3 = Cron()
- cron3.set_week_days( [0, 1, 2, 3, 4, 5, 6] )
- cron3.set_time_series( "+00:30" )
-
- task.add_cron( cron ) \
- .add_cron( cron1 ) \
- .add_cron( cron2 ) \
- .add_cron( cron3 )
- assert len(list(task.crons)) == 4,"Expected 4 crons"
- vec_copy = []
- for attr in task.crons: vec_copy.append(attr)
- for attr in vec_copy: task.delete_cron(attr)
- assert len(list(task.crons)) == 0,"Expected 0 crons"
-
-
- # add autocancel
- t1 = Task("t1")
- t1.add_autocancel( 3 ).add_variable("A","j")
- t3 = Task("t3")
- t3.add_autocancel( 20, 10, True ).add_variable("B","j")
- t4 = Task("t4")
- t4.add_autocancel( TimeSlot(10, 10), True ).add_variable("C","j")
- t5 = Task("t5")
- t5.add_autocancel( Autocancel(1, 10, True) ).add_variable("D","j")
-
-
- # add late
- late = Late()
- late.submitted( TimeSlot(20, 10) )
- late.active( TimeSlot(20, 10))
- late.complete( TimeSlot(20, 10), True)
- task.add_late(late ).add_variable("FRED33","j")
-
-
- # add defstatus, last one set takes effect
- task.add_defstatus( DState.complete )\
- .add_defstatus( DState.queued )\
- .add_defstatus( DState.aborted )\
- .add_defstatus( DState.submitted )\
- .add_defstatus( DState.suspended )\
- .add_defstatus( DState.active )
-
- #
- # add clock
- #
- clock = Clock(1, 1, 2010, False) # day,month, year, hybrid
- clock.set_gain(1, 10, True) # True means positive gain
- suite = Suite("suite")
- suite.add_clock(clock).add_variable("fred1","j")
-
- clock = Clock(1, 1, 2011, True) # day,month, year, hybrid
- clock.set_gain_in_seconds(12, True)
- s1 = Suite("s1")
- s1.add_clock(clock).add_variable("fred2","j")
-
- #
- # Add zombie. Note we can *NOT* add two zombie attributes of the same ZombieType
- #
- zombie_life_time_in_server = 800
- child_list = [ ChildCmdType.init, ChildCmdType.event, ChildCmdType.meter, ChildCmdType.label, ChildCmdType.wait, ChildCmdType.abort, ChildCmdType.complete ]
- zombie_type_list = [ ZombieType.ecf, ZombieType.user, ZombieType.path ]
- for zombie_type in zombie_type_list:
- zombie_attr = ZombieAttr(zombie_type, child_list, ZombieUserActionType.block, zombie_life_time_in_server)
- s1.add_zombie(zombie_attr).add_variable("fred","j")
-
- assert len(list(s1.zombies)) == 3,"Expected 3 zombie attributes but found " + str(len(list(s1.zombies)))
-
- # delete all the zombies
- s1.delete_zombie("")
- assert len(list(s1.zombies)) == 0,"Expected zero zombie attributes but found " + str(len(list(s1.zombies)))
-
- # repeat the the test with empty child list. Empty child list means apply to all child commands
- child_list = [ ]
- zombie_type_list = [ ZombieType.ecf, ZombieType.user, ZombieType.path ]
- for zombie_type in zombie_type_list:
- zombie_attr = ZombieAttr(zombie_type, child_list, ZombieUserActionType.block, zombie_life_time_in_server)
- s1.add_zombie(zombie_attr).add_variable("fred","j")
-
- # test delete of specific zombie attribute
- assert len(list(s1.zombies)) == 1,"Expected 1 zombie attributes but found " + str(len(list(s1.zombies)))
- s1.delete_zombie(zombie_type)
- assert len(list(s1.zombies)) == 0,"Expected 0 zombie attributes but found " + str(len(list(s1.zombies)))
-
- print "All Tests pass"
-
\ No newline at end of file
diff --git a/ecflow_4_0_7/Pyext/test/py_u_TestAddNodeFunc.py b/ecflow_4_0_7/Pyext/test/py_u_TestAddNodeFunc.py
deleted file mode 100644
index 3a8a68b..0000000
--- a/ecflow_4_0_7/Pyext/test/py_u_TestAddNodeFunc.py
+++ /dev/null
@@ -1,69 +0,0 @@
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# Name :
-# Author : Avi
-# Revision : $Revision: #10 $
-#
-# Copyright 2009-2012 ECMWF.
-# This software is licensed under the terms of the Apache Licence version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation
-# nor does it submit to any jurisdiction.
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-from ecflow import Defs, Client, debug_build
-
-def create_defs_sequentially():
- local_defs = Defs()
- suite = local_defs.add_suite("s1")
- suite.add_variable("Var","value")
- suite.add_trigger("t1 == complete")
- suite.add_meter( "metername3", 0, 100, 50 )
- suite.add_event( 2 )
- suite.add_event( 3 )
- f1 = suite.add_family("f1")
- f1 = f1.add_family("f1")
- t1 = f1.add_task("t1")
- t1.add_variable("fred","jones")
-
- f2 = suite.add_family("f2")
- f1 = f2.add_family("f1")
- t1 = f1.add_task("t1")
- t1.add_variable("fred","jones")
-
- f3 = suite.add_family("f3")
- t1 = f3.add_task("t1")
- t1.add_variable("fred", "jones")
-
- suite.add_task("t1").add_variable("fred","jones")
- return local_defs
-
-def create_defs_functionally():
- f_defs = Defs()
- suite = f_defs.add_suite("s1")
- suite.add_variable("Var","value").add_family("f1").add_family("f1").add_task("t1").add_variable("fred","jones")
- suite.add_trigger("t1 == complete").add_family("f2").add_family("f1").add_task("t1").add_variable("fred","jones")
- suite.add_meter( "metername3", 0, 100, 50 ).add_family("f3").add_task("t1").add_variable("fred","jones")
- suite.add_event( 2 ).add_event( 3 ).add_task("t1").add_variable("fred","jones")
- return f_defs
-
-
-if __name__ == "__main__":
- print "####################################################################"
- print "Running ecflow version " + Client().version() + " debug build(" + str(debug_build()) +")"
- print "####################################################################"
-
- #
- # Add Nodes functional way
- #
- defs = Defs()
- defs.add_suite("s1").add_task("t1").add_variable("var","v")
- defs.add_suite("s2").add_family("f1").add_task("t1").add_variable("var","v")
- defs.add_suite("s3").add_family("f1").add_family("f2").add_task("t1").add_variable("var","v")
- assert len(list(defs.suites)) == 3,"Expected 3 suites"
-
- # These test show that although add_variable() returns a node_ptr, its really a suite
- # hence calling add_family/add_task still works.
- assert create_defs_sequentially() == create_defs_functionally(),"Functional suite not as expected "
-
- print "All Tests pass"
-
\ No newline at end of file
diff --git a/ecflow_4_0_7/Pyext/test/py_u_TestDefs.py b/ecflow_4_0_7/Pyext/test/py_u_TestDefs.py
deleted file mode 100644
index 18b5a6c..0000000
--- a/ecflow_4_0_7/Pyext/test/py_u_TestDefs.py
+++ /dev/null
@@ -1,221 +0,0 @@
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# Name :
-# Author : Avi
-# Revision : $Revision: #10 $
-#
-# Copyright 2009-2012 ECMWF.
-# This software is licensed under the terms of the Apache Licence version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation
-# nor does it submit to any jurisdiction.
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# code for testing creation of defs file in python
-import os
-import ecflow
-print ecflow.__doc__
-print ecflow.Defs.__doc__
-
-from ecflow import Suite, Family, Task, Defs, Clock, DState, PartExpression, Variable, Limit, InLimit, \
- Date, Day, Event, Meter, Label, Autocancel, Days, TimeSlot, TimeSeries, Style, State, \
- RepeatString, RepeatDate, RepeatInteger, RepeatDay, RepeatEnumerated, \
- Verify, PrintStyle, Time, Today, Late, Cron, Client, debug_build
-
-if __name__ == "__main__":
- print "####################################################################"
- print "Running ecflow version " + Client().version() + " debug build(" + str(debug_build()) +")"
- print "####################################################################"
-
- suite = Suite("s1")
- assert (isinstance(suite, ecflow.Suite)), "Expected suite"
- assert (not isinstance(suite, ecflow.Family)), "Expected suite"
- assert (not isinstance(suite, ecflow.Task)), "Expected suite"
-
- family = Family("f1")
- assert (isinstance(family, ecflow.Family)), "Expected Family"
- assert (not isinstance(family, ecflow.Suite)), "Expected Family"
- assert (not isinstance(family, ecflow.Task)), "Expected Family"
- suite.add_family(family)
-
- task = Task("f1")
- assert (isinstance(task, ecflow.Task)), "Expected Task"
- assert (not isinstance(task, ecflow.Suite)), "Expected Task"
- assert (not isinstance(task, ecflow.Family)), "Expected Task"
- family.add_task(task)
-
-
- defs = Defs()
- defs2 = Defs()
- assert defs == defs2, "Empty defs should be equal"
-
- assert defs.get_state() == ecflow.State.unknown, "Expected default state to be unknown"
- defs.add_suite(suite); # add existing suite to defs
-
- suite = defs.add_suite("s2");
- suite.add_variable(Variable("ECF_HOME","/tmp/"))
- suite.add_variable("ECF_URL_CMD", "${BROWSER:=firefox} -remote 'openURL(%ECF_URL_BASE%/%ECF_URL%)'")
- suite.add_variable("ECF_URL_BASE","http://www.ecmwf.int")
- suite.add_variable("ECF_URL","publications/manuals/sms")
- suite.add_limit( Limit("limitName", 10) )
- suite.add_limit( "limitName_2", 10 )
- assert suite.begun() == False, "Suite should not have begun"
-
- clock = Clock(1,1,2010,False);
- clock.set_gain(1,10,True);
- suite.add_clock(clock);
-
- assert defs != defs2, "Defs should no longer compare as they are different"
-
- defs.add_extern("/path/to/task");
- defs.add_extern("/fred/bill:event_name");
-
- family = suite.add_family("f1")
- family.add_defstatus( DState.active );
-
- task = family.add_task("t1")
- task.add_trigger( "t2 == active" )
- task.add_complete( "t2 == complete" )
- task.add_autocancel( Autocancel(3) );
-
- task2 = family.add_task("t2")
- task2.add_defstatus( DState.complete );
- task2.add_part_trigger( PartExpression("t1 == complete") )
- task2.add_part_trigger( PartExpression("t1 == active",True) ) # for long and/or expressions, subsequent expr must be and/or
- task2.add_part_complete( PartExpression("t1 == complete") )
- task2.add_part_complete( PartExpression("t1 == active",False) ) # for long and/or expressions, subsequent expr must be and/or
- task2.add_label( Label("labelname", "label1") )
- task2.add_label( "labelname2", "label1")
- task2.add_inlimit( InLimit("limitName","/s1/f1",2) )
- task2.add_inlimit( "limitName2" )
- task2.add_event( 10 )
- task2.add_event( Event(10,"Eventname") )
- task2.add_meter( Meter("metername",0,100,50) )
- task2.add_meter( "metername2",0,100,50 )
- task2.add_date( Date(1,1,2010) )
- task2.add_date( 1,2,2010 )
- task2.add_day( Day(Days.sunday) )
- task2.add_day( Days.monday )
- task2.add_autocancel( Autocancel(TimeSlot(20,10),True) )
-
- task2.add_today( 0,10 )
- task2.add_today( Today( 0,59, True ))
- task2.add_today( Today(TimeSlot(20,10)) )
- task2.add_today( Today(TimeSlot(20,20),False))
- start = TimeSlot(0,0)
- finish = TimeSlot(23,0)
- incr = TimeSlot(0,30)
- ts = TimeSeries( start, finish, incr, True);
- task2.add_today( Today(ts) )
-
- task2.add_time( 20,10 )
- task2.add_time( Time(20,12,True) )
- task2.add_time( Time(TimeSlot(20,12)))
- task2.add_time( Time(TimeSlot(20,20),True))
- task2.add_time( Time(ts) )
-
- late = Late()
- late.submitted( 20,10 )
- late.active(TimeSlot(20,10))
- late.complete(TimeSlot(20,10),True)
- task2.add_late( late )
-
- cron = Cron()
- cron.set_week_days( [0,1,2,3,4,5,6] )
- cron.set_days_of_month( [1,2,3,4,5,6] )
- cron.set_months( [1,2,3,4,5,6] )
- cron.set_time_series( ts )
- task2.add_cron( cron );
-
- task3 = family.add_task("t3")
- task3.add_repeat( RepeatDate("testDate",20100111,20100115,2) )
- task3.add_defstatus( DState.queued );
- task3.add_verify( Verify(State.complete, 1) )
- task3.add_autocancel( Autocancel(20,10,False) )
- task3.add_label( Label("label_name","label_value") )
-
- task3_1 = family.add_task("t3_1")
- task3_1.add_repeat( RepeatDate("testDate",20100111,20100115) )
-
-
- task4 = family.add_task("t4")
- task4.add_repeat( RepeatInteger("testInteger",0,100,2) )
- task4.add_defstatus( DState.aborted );
-
- task4_1 = family.add_task("t4_1")
- task4_1.add_repeat( RepeatInteger("testInteger",0,100) )
-
-
- task5 = family.add_task("t5")
- task5.add_repeat( RepeatEnumerated("testInteger", ["red", "green", "blue" ] ) )
- task5.add_defstatus( DState.submitted );
-
- task6 = family.add_task("t6")
- task6.add_repeat( RepeatString("test_string", ["a", "b", "c" ] ) )
- task6.add_defstatus( DState.suspended );
-
- task7 = family.add_task("t7")
- task7.add_repeat( RepeatDay(2) )
- task7.add_defstatus( DState.active );
-
- task8 = family.add_task("t8")
- task8.add_repeat( RepeatDay() )
- print "task8.get_try_no() :string:",task8.get_try_no()
- print "task8.get_int_try_no():int :",task8.get_int_try_no()
-
- the_defs = task8.get_defs()
-
-
- # Test find
- assert defs.find_suite("s1") != None, "Expected to find suite of name s1"
- assert defs.find_suite("sffff1") == None, "Should not be able to find suite of name sfffff1"
-
- # save the defs file as a check point file and restore it again
- checkpt_file = "py_u_TestDefs.check"
- defs_file = "py_u_TestDefs.def"
- if debug_build() :
- checkpt_file = "py_u_TestDefs_debug.check"
- defs_file = "py_u_TestDefs_debug.def"
- defs.save_as_checkpt(checkpt_file);
-
- restored_checkpt_defs = Defs()
- restored_checkpt_defs.restore_from_checkpt(checkpt_file)
-
- print "Save and restore as Defs ******************************************************"
- defs.save_as_defs(defs_file) # default is to save as DEFS
- restored_from_defs = Defs( defs_file ) # restore the defs
-
- defs.save_as_defs(defs_file,Style.DEFS)
- restored_from_defs = Defs( defs_file ) # restore the defs
-
- print "Save and restore using STATE ******************************************************"
- defs.save_as_defs(defs_file,Style.STATE)
- restored_from_defs = Defs( defs_file ) # restore the defs
-
- print "Save and restore using MIGRATE ******************************************************"
- defs.save_as_defs(defs_file,Style.MIGRATE)
- restored_from_defs = Defs( defs_file ) # restore the defs
- assert restored_checkpt_defs == restored_from_defs ,"File should be the same"
-
-
- print "Print in DEFS style ******************************************************"
- PrintStyle.set_style(Style.DEFS)
- the_string = str(restored_from_defs)
- assert the_string.find("defs_state") == -1, "Print in DEFS style failed"
- print the_string
-
- print "Print in STATE style *****************************************************"
- PrintStyle.set_style(Style.STATE)
- the_string = str(restored_from_defs)
- assert the_string.find("defs_state STATE") != -1, "Print in STATE style failed"
- print the_string
-
- print "Print in MIGRATE style *****************************************************"
- PrintStyle.set_style(Style.MIGRATE)
- the_string = str(restored_from_defs)
- assert the_string.find("defs_state MIGRATE") != -1, "Print in MIGRATE style failed"
- print the_string
-
- # Comment this out if you want to see what the file looked like
- os.remove(checkpt_file)
- os.remove(defs_file)
- print "All tests pass"
\ No newline at end of file
diff --git a/ecflow_4_0_7/Pyext/test/py_u_TestDefsCheck.py b/ecflow_4_0_7/Pyext/test/py_u_TestDefsCheck.py
deleted file mode 100644
index d83a8e5..0000000
--- a/ecflow_4_0_7/Pyext/test/py_u_TestDefsCheck.py
+++ /dev/null
@@ -1,72 +0,0 @@
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# Name :
-# Author : Avi
-# Revision : $Revision: #10 $
-#
-# Copyright 2009-2012 ECMWF.
-# This software is licensed under the terms of the Apache Licence version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation
-# nor does it submit to any jurisdiction.
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-# Test the error and waning checks defined in the defs work
-
-from ecflow import Defs, Limit, InLimit, Client, debug_build
-
-if __name__ == "__main__":
- print "####################################################################"
- print "Running ecflow version " + Client().version() + " debug build(" + str(debug_build()) +")"
- print "####################################################################"
-
- defs = Defs()
- suite = defs.add_suite("s1");
- suite.add_task("t1").add_trigger("t2 == active)")
- theCheckValue = defs.check();
- print "Message: '" + theCheckValue + "'"
- assert len(theCheckValue) != 0, "Expected Error: triggers fail parse, miss-matched brackets in expression."
-
- # The number of tokens specified on the in-limit must be less than or equal to those specified on the LIMIT
- defs = Defs()
- suite = defs.add_suite("s1");
- suite.add_limit( Limit("disk", 50) );
- family = suite.add_family("anon");
- family.add_inlimit( InLimit("disk","/s1",100) )
- family.add_task( "t1" );
- theCheckValue = defs.check();
- print "Message: '" + theCheckValue + "'"
- assert len(theCheckValue) != 0, "Expected Error: since inlimit value('100') is greater than the LIMIT value('50')"
-
-
- # When a path is specified on the in-limit we search for the limit on that path, otherwise the extern's
- defs = Defs()
- suite = defs.add_suite("s1");
- family = suite.add_family("anon");
- family.add_inlimit( InLimit("disk","/s1",100) )
- family.add_task( "t1" );
- theCheckValue = defs.check();
- print "Message: '" + theCheckValue + "'"
- assert len(theCheckValue) != 0, "Expected warning: since inlimit PATH(/s1:disk) reference a limit('disk') that does not exist"
-
- # Add as extern and repeat the check
- defs.add_extern("/s1:disk")
- assert len(defs.check()) == 0, "Expected no warnings, since extern specified: " + defs.check()
-
-
- # When no path is specified on the in-limit, we search for the limit up the node tree, otherwise the extern's
- defs = Defs()
- suite = defs.add_suite("s1");
- family = suite.add_family("anon");
- family.add_inlimit( InLimit("disk","",100) )
- family.add_task( "t1" );
- theCheckValue = defs.check();
- print "Message: '" + theCheckValue + "'"
- assert len(theCheckValue) != 0, "Expected warning: since inlimit SHOULD reference a limit('disk') somewhere UP parent hierarchy"
-
- # Add as extern and repeat the check
- defs.add_extern("disk")
- assert len(defs.check()) == 0, "Expected no warnings, since extern specified"
-
- print "All Tests pass"
-
\ No newline at end of file
diff --git a/ecflow_4_0_7/Pyext/test/py_u_TestDerivable.py b/ecflow_4_0_7/Pyext/test/py_u_TestDerivable.py
deleted file mode 100644
index 976e5dc..0000000
--- a/ecflow_4_0_7/Pyext/test/py_u_TestDerivable.py
+++ /dev/null
@@ -1,28 +0,0 @@
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# Name :
-# Author : Avi
-# Revision : $Revision: #10 $
-#
-# Copyright 2009-2012 ECMWF.
-# This software is licensed under the terms of the Apache Licence version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation
-# nor does it submit to any jurisdiction.
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-# code for testing derivation works
-import ecflow
-
-class MyDefs(ecflow.Defs): pass
-class MySuite(ecflow.Suite): pass
-class MyFamily(ecflow.Family): pass
-class MyTask(ecflow.Task): pass
-class MyClient(ecflow.Client): pass
-
-if __name__ == "__main__":
- print "####################################################################"
- print "Running ecflow version " + ecflow.Client().version() + " debug build(" + str(ecflow.debug_build()) +")"
- print "####################################################################"
-
- print "All tests pass"
\ No newline at end of file
diff --git a/ecflow_4_0_7/Pyext/test/py_u_TestEcf.py b/ecflow_4_0_7/Pyext/test/py_u_TestEcf.py
deleted file mode 100644
index 6dc842e..0000000
--- a/ecflow_4_0_7/Pyext/test/py_u_TestEcf.py
+++ /dev/null
@@ -1,38 +0,0 @@
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# Name :
-# Author : Avi
-# Revision : $Revision: #10 $
-#
-# Copyright 2009-2012 ECMWF.
-# This software is licensed under the terms of the Apache Licence version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation
-# nor does it submit to any jurisdiction.
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# code for testing creation of defs file in python
-import os
-import ecflow
-
-from ecflow import Ecf, Client, debug_build
-
-if __name__ == "__main__":
- print "####################################################################"
- print "Running TestEcf, ecflow version " + Client().version() + " debug build(" + str(debug_build()) +")"
- print "####################################################################"
-
- default_debug_level = Ecf.debug_level()
- assert default_debug_level == 0, "Expected default debug level to be 0"
- Ecf.set_debug_level(10)
- assert Ecf.debug_level() == 10, "Expected debug level to be 10"
- Ecf.set_debug_level(0)
- assert Ecf.debug_level() == 0, "Expected debug level to be 0"
-
-
- assert Ecf.debug_equality() == False, "Expected default for Ecf.debug_equality() == False "
- Ecf.set_debug_equality(True)
- assert Ecf.debug_equality() == True, "Expected debug_equality() == True "
- Ecf.set_debug_equality(False)
- assert Ecf.debug_equality() == False, "Expected Ecf.debug_equality() == False "
-
- print "All tests pass"
\ No newline at end of file
diff --git a/ecflow_4_0_7/Pyext/test/py_u_TestError.py b/ecflow_4_0_7/Pyext/test/py_u_TestError.py
deleted file mode 100644
index 551e0fc..0000000
--- a/ecflow_4_0_7/Pyext/test/py_u_TestError.py
+++ /dev/null
@@ -1,443 +0,0 @@
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# Name :
-# Author : Avi
-# Revision : $Revision: #10 $
-#
-# Copyright 2009-2012 ECMWF.
-# This software is licensed under the terms of the Apache Licence version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation
-# nor does it submit to any jurisdiction.
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-# code for testing errors in creation of defs file in python
-
-import os
-from ecflow import Date, Meter, Event, Clock, Variable, Label, Limit, InLimit, \
- RepeatDate, RepeatEnumerated, RepeatInteger, RepeatString, \
- Task, Family, Suite, Defs, Client, debug_build
-
-def check_date(day,month,year):
- try:
- Date(day,month,year)
- return True
- except IndexError:
- return False
-
-def check_meter(name,min_meter_value,max_meter_value,color_change):
- try:
- Meter(name,min_meter_value,max_meter_value,color_change)
- return True
- except IndexError:
- return False
- except RuntimeError:
- return False
-
-def check_event_number_and_name(number,name):
- try:
- Event(number,name)
- return True
- except:
- return False
-
-def check_event(number):
- try:
- Event(number)
- return True
- except RuntimeError:
- return False
-
-def check_clock(day_of_month,month,year):
- try:
- Clock(day_of_month,month,year)
- return True
- except IndexError:
- return False
-
-def check_variable(name,value):
- try:
- Variable(name,value)
- return True
- except RuntimeError:
- return False
-
-def check_label(name,value):
- try:
- Label(name,value)
- return True
- except RuntimeError:
- return False
-
-def check_limit(name,int_token):
- try:
- Limit(name,int_token)
- return True
- except RuntimeError:
- return False
- except TypeError:
- return False
-
-def check_inlimit(name,path_to_node,int_token):
- try:
- InLimit(name,path_to_node,int_token)
- return True
- except RuntimeError:
- return False
- except TypeError:
- return False
-
-def check_repeat_date(name, start, end, step):
- try:
- RepeatDate(name,start,end,step)
- return True
- except RuntimeError:
- return False
-
-def check_repeat_integer(name, start, end, step):
- try:
- RepeatInteger(name,start,end,step)
- return True
- except RuntimeError:
- return False
- except TypeError:
- return False
-
-def check_repeat_enumerated(name, list_of_strings):
- try:
- RepeatEnumerated(name,list_of_strings)
- return True
- except RuntimeError:
- return False
- except TypeError:
- return False
-
-def check_repeat_string(name, list_of_strings):
- try:
- RepeatString(name,list_of_strings)
- return True
- except RuntimeError:
- return False
- except TypeError:
- return False
-
-def check_node_name(name):
- try:
- Task(name)
- Family(name)
- Suite(name)
- return True;
- except RuntimeError:
- return False
-
-def check_defs(path_to_defs):
- try:
- Defs(path_to_defs)
- return True
- except RuntimeError:
- return False
-
-if __name__ == "__main__":
- print "####################################################################"
- print "Running ecflow version " + Client().version() + " debug build(" + str(debug_build()) +")"
- print "####################################################################"
-
- # Names with leading '.' should not be allowed. Will interfere with triggers
- # Empty names not allowed
- # Spaces not allowed
- invalid_names = [ ".", "", " "," ", "fred doc", "1 "]
-
- # Allow names with leading underscore
- valid_names = [ "_", "__", "_._", "1.2", "fred.doc", "_.1"]
-
- assert check_date(0,1,2010), "Expected valid date"
- assert check_date(10,0,2010), "Expected valid date"
- assert check_date(10,1,0), "Expected valid date"
- assert check_date(0,0,0), "Expected valid date"
- assert check_date(40,1,2010) == False, "Expected exception since day > 31"
- assert check_date(-10,1,2010) == False, "Expected exception since day >= 0"
- assert check_date(1,14,2010) == False, "Expected exception since month > 12"
- assert check_date(1,-1,2010) == False, "Expected exception since month >= 0"
- assert check_date(1,1,-2) == False, "Expected exception since year >= 0"
-
- # clock do not support wild carding hence we cant use 0 like in Date
- assert check_clock(12,1,2010), "Expected valid date"
- assert check_clock(10,1,2010), "Expected valid date"
- assert check_clock(10,1,1400), "Expected valid date"
- assert check_clock(31,12,2010), "Expected valid date"
- assert check_clock(40,1,2010) == False, "Expected exception since day > 31"
- assert check_clock(-10,1,2010) == False, "Expected exception since day >= 0"
- assert check_clock(1,14,2010) == False, "Expected exception since month > 12"
- assert check_clock(1,-1,2010) == False, "Expected exception since month >= 0"
- assert check_clock(1,1,-2) == False, "Expected exception since year >= 0"
-
- assert check_meter("m",0,100,100), "Expected valid Meter"
- assert check_meter("m",0,100,0), "Expected valid Meter"
- assert check_meter("m",200,100,100) == False, "Expected exception since min > max"
- assert check_meter("m",0,100,-20) == False, "Expected exception since color_change should between min-max"
- assert check_meter("m",0,100,200) == False, "Expected exception since color_change should between min-max"
- assert check_meter("",0,100,100) == False, "Expected exception since no name specified"
- assert check_meter(" ",0,100,100) == False, "Expected Exception can not have spaces for a name"
-
- assert check_event(1), "Expected valid Event"
- assert check_event(2), "Expected valid Event"
- assert check_event_number_and_name(2,"fred"), "Expected valid Event"
- assert check_event_number_and_name(2,2) == False, "Expected failure since the name is not a string"
-
- assert check_repeat_date("m",20000101,20001201,200), "Expected valid repeat"
- assert check_repeat_date("m",20001201,20000101,200) == False, "Expected exception since end YMD > start YMD"
- assert check_repeat_date("m",200001011,20001201,200)== False, "Expected Exception since start is invalid."
- assert check_repeat_date("m",20000101,200012013,200)== False, "Expected Exception since send is invalid."
- assert check_repeat_date("m",00000000,00000000,200)== False, "Expected Exception since start/end are not valid dates is invalid."
- assert check_repeat_date("",20000101,20001201,200)==False, "Expected Exception since no name specified"
- assert check_repeat_date(" ",20000101,20001201,200)==False, "Expected Exception can not have spaces for a name"
- assert check_repeat_integer("name",0, 10, 2 ), "Expected valid repeat"
- assert check_repeat_integer("",0, 10, 2 )==False, "Expected Exception since no name specified"
- assert check_repeat_integer(" ",0, 10, 2 )==False, "Expected Exception can not have spaces for a name"
- assert check_repeat_string("name",[ "a" ]), "Expected valid repeat"
- assert check_repeat_string("",["a"] )==False, "Expected Exception since no name specified"
- assert check_repeat_string(" ",["a"] )==False, "Expected Exception can not have spaces for a name"
- assert check_repeat_string("name",[ 1,2 ])==False, "Expected Exception since a list of strings was expected"
- assert check_repeat_enumerated("name",[ "a" ]), "Expected valid repeat"
- assert check_repeat_enumerated("",["a"] )==False, "Expected Exception since no name specified"
- assert check_repeat_enumerated(" ",["a"] )==False, "Expected Exception since a list of strings was expected"
- assert check_repeat_enumerated("name",[ 1,2 ])==False, "Expected Exception since a list of strings was expected"
-
-
- assert check_variable("name","value"), "Expected valid Variable"
- assert check_variable("name",""), "Expected valid Variable"
- assert check_variable("name"," "), "Expected valid Variable"
- assert check_variable("name","12"), "Expected valid Variable"
- assert check_variable("","12")==False, "Expected Exception name must be specified"
- assert check_variable(" ","12")==False, "Expected Exception can not have spaces for a name"
-
- assert check_label("name","value"), "Expected valid label"
- assert check_label("name",""), "Expected valid label"
- assert check_label("name"," "), "Expected valid label"
- assert check_label("name","12"), "Expected valid label"
- assert check_label("","12")==False, "Expected exception name must be specified"
- assert check_label(" ","12")==False, "Expected Exception can not have spaces for a name"
-
- assert check_limit("name",1), "Expected valid limit"
- assert check_limit("name",20000), "Expected valid limit"
- assert check_limit("name","ten")==False, "Expected exception, token must be a integer"
- assert check_limit("name","2")==False, "Expected exception, token must be a integer"
- assert check_limit("","2")==False, "Expected exception, no name specified"
- assert check_limit(" ","2")==False, "Expected exception, can not have spaces for a name"
-
- assert check_inlimit("limit_name","/path/to/limit",1), "Expected valid in limit"
- assert check_inlimit("limit_name","/path/to/limit",999999), "Expected valid in limit"
- assert check_inlimit("limit_name","",1), "Expected valid in limit"
- assert check_inlimit("","",1)==False, "Expected exception, no limit name specified"
- assert check_inlimit(" ","",1)==False, "Expected exception, can not have spaces for a name"
-
-
- # ========================================================================
- print "Check node names"
- for i in range(25):
- assert check_node_name(str(i)), "Integer names should be allowed"
-
- for name in valid_names:
- assert check_node_name(name), "Expected valid name " + name
-
- for name in invalid_names:
- assert check_node_name(name)==False, "Expected exception for invalid name " + name
-
-
- assert check_defs("a_made_up_path_that_doesnt_not_exit.def") == False, "Expected exception, Defs file does not exist"
-
- # =================================================================================
- print "test save_as_defs"
- defs = Defs() # create a empty definition
- s1 = defs.add_suite("s1") # create a suite "s1" and add to defs
- defs.save_as_defs("testerror.def") # create a defs on disk
- assert check_defs("testerror.def"), "Expected defs file to exist"
- os.remove("testerror.def")
-
- # =================================================================================
- print "Check duplicate suites not allowed"
- test_passed = False
- try :
- defs = Defs() # create a empty definition
- s1 = defs.add_suite("s1") # create a suite "s1" and add to defs
- s2 = defs.add_suite("s1") # Exception thrown trying to add suite name "s1" again
- except RuntimeError, e :
- test_passed = True
- pass
- assert test_passed,"duplicate suite test failed"
-
- # =================================================================================
- test_passed = False
- try:
- defs = Defs()
- defs.add_suite("1").add_today("00:30")
- except RuntimeError, e :
- test_passed = True
- pass
- assert test_passed,"Adding today at the suite level should fail"
- print "check adding today at the suite level: RuntimeError: ",e
-
- # =================================================================================
- test_passed = False
- try:
- defs = Defs()
- defs.add_suite("1").add_time("00:30")
- except RuntimeError, e :
- test_passed = True
- pass
- assert test_passed,"Adding time at the suite level should fail"
- print "check adding time at the suite level: RuntimeError: ",e
-
- # =================================================================================
- test_passed = False
- try:
- defs = Defs()
- defs.add_suite("1").add_date(1,1,2016)
- except RuntimeError, e :
- test_passed = True
- pass
- assert test_passed,"Adding date at the suite level should fail"
- print "check adding date at the suite level: RuntimeError: ",e
-
- # =================================================================================
- test_passed = False
- try:
- defs = Defs()
- defs.add_suite("1").add_day("monday")
- except RuntimeError, e :
- test_passed = True
- pass
- assert test_passed,"Adding day at the suite level should fail"
- print "check adding day at the suite level: RuntimeError: ",e
-
-
- # =================================================================================
- print "check duplicate family not allowed"
- test_passed = False
- try:
- suite = Suite("1")
- fam1 = Family("1")
- fam2 = Family("1")
- suite.add_family(fam1)
- suite.add_family(fam2)
- except RuntimeError, e :
- test_passed = True
- pass
- assert test_passed,"duplicate Family test failed"
-
- # =================================================================================
- print "duplicate task not allowed"
- test_passed = False
- try:
- suite = Suite("1")
- ta = Task("a")
- tb = Task("a")
- suite.add_task(ta)
- suite.add_task(tb)
- except RuntimeError, e :
- test_passed = True
- pass
- assert test_passed,"duplicate Task test failed"
-
- # =================================================================================
- print "check duplicate meter not allowed"
- test_passed = False
- try:
- defs = Defs()
- suite = defs.add_suite("1")
- ta = suite.add_task("a")
- ta.add_meter("meter",0,100);
- ta.add_meter("meter",0,100);
- except RuntimeError, e :
- test_passed = True
- pass
- assert test_passed,"duplicate event test failed"
-
- test_passed = False
- try:
- defs = Defs()
- suite = defs.add_suite("1")
- ta = suite.add_task("a")
- ta.add_meter(Meter("meter",0,100));
- ta.add_meter(Meter("meter",10,100));
- except RuntimeError, e :
- test_passed = True
- pass
- assert test_passed,"duplicate meter test failed"
-
- # =================================================================================
- print "check duplicate event not allowed"
- test_passed = False
- try:
- defs = Defs()
- suite = defs.add_suite("1")
- ta = suite.add_task("a")
- ta.add_event(1);
- ta.add_event("1");
- except RuntimeError, e :
- test_passed = True
- pass
- assert test_passed,"duplicate event test failed"
-
- test_passed = False
- try:
- defs = Defs()
- suite = defs.add_suite("1")
- ta = suite.add_task("a")
- ta.add_event("name");
- ta.add_event("name");
- except RuntimeError, e :
- test_passed = True
- pass
- assert test_passed,"duplicate event test failed"
-
- test_passed = False
- try:
- defs = Defs()
- suite = defs.add_suite("1")
- ta = suite.add_task("a")
- ta.add_event(1,"name");
- ta.add_event(1,"name");
- except RuntimeError, e :
- test_passed = True
- pass
- assert test_passed,"duplicate event test failed"
-
-
- # =================================================================================
- print "check cannot add same node to different containers"
- defs1 = Defs();
- suite = defs1.add_suite("s1")
- family = suite.add_family("f1")
- task = family.add_task("t1")
-
- test_passed = False
- try :
- defs2 = Defs();
- defs2.add_suite(suite)
- except RuntimeError, e :
- test_passed = True
- pass
- assert test_passed,"Can't add same suite to two different defs"
-
- test_passed = False
- try :
- defs3 = Defs();
- suite = defs3.add_suite(suite)
- suite.add_family(family)
- except RuntimeError, e :
- test_passed = True
- pass
- assert test_passed,"Can't add same family to two different suites"
-
- test_passed = False
- try :
- defs4 = Defs();
- suite = defs4.add_suite("s1")
- suite.add_task(task)
- except RuntimeError, e :
- test_passed = True
- pass
- assert test_passed,"Can't add same task to two different containers"
-
- print "All Tests pass"
\ No newline at end of file
diff --git a/ecflow_4_0_7/Pyext/test/py_u_TestFind.py b/ecflow_4_0_7/Pyext/test/py_u_TestFind.py
deleted file mode 100644
index ff12ed0..0000000
--- a/ecflow_4_0_7/Pyext/test/py_u_TestFind.py
+++ /dev/null
@@ -1,54 +0,0 @@
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# Name :
-# Author : Avi
-# Revision : $Revision: #10 $
-#
-# Copyright 2009-2012 ECMWF.
-# This software is licensed under the terms of the Apache Licence version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation
-# nor does it submit to any jurisdiction.
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-# code for testing pointers and hierarchy in python
-
-from ecflow import Suite, Family, Task, Defs, Client, debug_build
-
-def create_defs(name=""):
- defs = Defs()
- suite_name = name
- if len(suite_name) == 0: suite_name = "s1"
- suite = defs.add_suite(suite_name);
-
- f1 = suite.add_family("f1")
- f1.add_task("f1_t1")
- f1.add_task("f1_t2")
- f2 = suite.add_family("f2")
- f2.add_task("f2_t1")
- f2.add_task("f2_t2")
- return defs;
-
-
-if __name__ == "__main__":
- print "####################################################################"
- print "Running ecflow version " + Client().version() + " debug build(" + str(debug_build()) +")"
- print "####################################################################"
-
- defs = create_defs();
- tasks = defs.get_all_tasks()
- assert len(tasks) == 4, "Expected four tasks, but found " + str(len(tasks))
- for task in tasks:
- if task.name() == "f1_t1":
- node = task.find_node_up_the_tree("f1")
- assert node != None
- assert node.get_abs_node_path() == "/s1/f1"
-
- node = task.find_node_up_the_tree("s1")
- assert node != None
- assert node.get_abs_node_path() == "/s1"
-
- node = task.find_node_up_the_tree("freddd")
- assert node == None
-
- print "All Tests pass"
diff --git a/ecflow_4_0_7/Pyext/test/py_u_TestGeneratedVariable.py b/ecflow_4_0_7/Pyext/test/py_u_TestGeneratedVariable.py
deleted file mode 100644
index a5a56c8..0000000
--- a/ecflow_4_0_7/Pyext/test/py_u_TestGeneratedVariable.py
+++ /dev/null
@@ -1,76 +0,0 @@
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# Name :
-# Author : Avi
-# Revision : $Revision: #10 $
-#
-# Copyright 2009-2012 ECMWF.
-# This software is licensed under the terms of the Apache Licence version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation
-# nor does it submit to any jurisdiction.
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-# code for testing generated variables
-#
-import ecflow
-
-if __name__ == "__main__":
- print "####################################################################"
- print "Running ecflow version " + ecflow.Client().version() + " debug build(" + str(ecflow.debug_build()) +")"
- print "####################################################################"
-
- #===========================================================================
- print "Defs: test generated variables"
- #===========================================================================
- defs = ecflow.Defs()
- suite = defs.add_suite("s1")
- family = suite.add_family("f1")
- task = family.add_task("t1")
-
- print "\nsuite generated variables, Most of date related suite generated variables will only have values after the suite has begun"
- variable_list = ecflow.VariableList()
- suite.get_generated_variables(variable_list)
- for gen_var in variable_list:
- print gen_var
- assert len(list(variable_list)) == 12,"Expected 12 generated variables for suites"
- assert variable_list[0].name() == "SUITE", "expected generated variable of name SUITE but found " + variable_list[0].name()
- assert variable_list[0].value() == "s1", "expected generated variable of value 's1' but found " + variable_list[0].value()
-
-
- print "\nfamily generated variables"
- variable_list = ecflow.VariableList()
- family.get_generated_variables(variable_list)
- for gen_var in variable_list:
- print gen_var
- assert len(list(variable_list)) == 2,"Expected 2 generated variables for families"
- assert variable_list[0].name() == "FAMILY", "expected generated variable of name FAMILY but found " + variable_list[0].name()
- assert variable_list[0].value() == "f1", "expected generated variable of value 'f1' but found " + variable_list[0].value()
- assert variable_list[1].name() == "FAMILY1", "expected generated variable of name FAMILY1 but found " + variable_list[1].name()
- assert variable_list[1].value() == "f1", "expected generated variable of value 'f1' but found " + variable_list[1].value()
-
- print "\ntask generated variables"
- variable_list = ecflow.VariableList()
- task.get_generated_variables(variable_list)
- for gen_var in variable_list:
- print gen_var
- assert len(list(variable_list)) == 8,"Expected 8 generated variables for tasks"
- assert variable_list[0].name() == "TASK", "expected generated variable of name TASK but found " + variable_list[0].name()
- assert variable_list[0].value() == "t1", "expected generated variable of value 't1' but found " + variable_list[0].value()
- assert variable_list[1].name() == "ECF_JOB", "expected generated variable of name ECF_JOB but found " + variable_list[1].name()
- assert variable_list[1].value() == "./s1/f1/t1.job0", "expected generated variable of value './s1/f1/t1.job0' but found " + variable_list[1].value()
- assert variable_list[2].name() == "ECF_SCRIPT", "expected generated variable of name ECF_SCRIPT but found " + variable_list[2].name()
- assert variable_list[2].value() == "./s1/f1/t1.ecf", "expected generated variable of value './s1/f1/t1.ecf' but found " + variable_list[2].value()
- assert variable_list[3].name() == "ECF_JOBOUT", "expected generated variable of name ECF_JOBOUT but found " + variable_list[3].name()
- assert variable_list[3].value() == "./s1/f1/t1.0", "expected generated variable of value './s1/f1/t1.0' but found " + variable_list[3].value()
- assert variable_list[4].name() == "ECF_TRYNO", "expected generated variable of name ECF_TRYNO but found " + variable_list[4].name()
- assert variable_list[4].value() == "0", "expected generated variable of value '0' but found " + variable_list[4].value()
- assert variable_list[5].name() == "ECF_RID", "expected generated variable of name ECF_RID but found " + variable_list[5].name()
- assert variable_list[5].value() == "", "expected generated variable of value '' but found " + variable_list[5].value()
- assert variable_list[6].name() == "ECF_NAME", "expected generated variable of name ECF_NAME but found " + variable_list[6].name()
- assert variable_list[6].value() == "/s1/f1/t1", "expected generated variable of value '/s1/f1/t1' but found " + variable_list[6].value()
- assert variable_list[7].name() == "ECF_PASS", "expected generated variable of name ECF_NAME but found " + variable_list[7].name()
- assert variable_list[7].value() == "_DJP_", "expected generated variable of value '_DJP_' but found " + variable_list[7].value()
-
- print "\nAll Tests pass"
-
diff --git a/ecflow_4_0_7/Pyext/test/py_u_TestGetAllTasks.py b/ecflow_4_0_7/Pyext/test/py_u_TestGetAllTasks.py
deleted file mode 100644
index 47e46e7..0000000
--- a/ecflow_4_0_7/Pyext/test/py_u_TestGetAllTasks.py
+++ /dev/null
@@ -1,73 +0,0 @@
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# Name :
-# Author : Avi
-# Revision : $Revision: #10 $
-#
-# Copyright 2009-2012 ECMWF.
-# This software is licensed under the terms of the Apache Licence version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation
-# nor does it submit to any jurisdiction.
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-# Simple check for get all tasks
-from ecflow import Defs, Client, debug_build
-
-def create_defs():
- defs = Defs()
- suite = defs.add_suite("test_get_all")
- suite.add_task("t0")
- fam = suite.add_family("f1")
- fam.add_task("t1")
- fam.add_task("t2")
- fam2 = fam.add_family("f2")
- fam2.add_task("t3")
- return defs
-
-def test_get_all_tasks(defs):
-
- task_vec2 = defs.get_all_tasks()
- assert len(task_vec2) == 4, "Expected four tasks, but found " + str(len(task_vec2))
-
- assert task_vec2[0].name() == "t0", "Expected task of name t0 but found " + task_vec2[0].name()
- assert task_vec2[1].name() == "t1", "Expected task of name t1 but found " + task_vec2[1].name()
- assert task_vec2[2].name() == "t2", "Expected task of name t2 but found " + task_vec2[2].name()
- assert task_vec2[3].name() == "t3", "Expected task of name t3 but found " + task_vec2[3].name()
-
- print "test_get_all_tasks PASSED"
-
-def test_get_all_nodes(defs):
-
- # Get all the nodes make sure they are in order
- node_vec = defs.get_all_nodes()
- assert len(node_vec) == 7, "Expected seven nodes, but found " + str(len(node_vec))
- assert node_vec[0].name() == "test_get_all", "Nodes should be returned in order, expected test_get_all but found" + node_vec[0].name()
- assert node_vec[1].name() == "t0", "Nodes should be returned in order, expected 't0' but found" + node_vec[1].name()
- assert node_vec[2].name() == "f1", "Nodes should be returned in order, expected 'f1' but found" + node_vec[2].name()
- assert node_vec[3].name() == "t1", "Nodes should be returned in order, expected 't1' but found" + node_vec[3].name()
- assert node_vec[4].name() == "t2", "Nodes should be returned in order, expected 't2' but found" + node_vec[4].name()
- assert node_vec[5].name() == "f2", "Nodes should be returned in order, expected 'f2' but found" + node_vec[5].name()
- assert node_vec[6].name() == "t3", "Nodes should be returned in order, expected 't3' but found" + node_vec[6].name()
-
- # test empty defs
- empty_defs = Defs()
- node_vec = empty_defs.get_all_nodes()
- assert len(node_vec) == 0, "Expected zero nodes, for an empty defs but found " + str(len(node_vec))
-
- # test one suite defs
- one_suite_defs = Defs()
- one_suite_defs.add_suite("s1")
- node_vec = one_suite_defs.get_all_nodes()
- assert len(node_vec) == 1, "Expected one node, but found" + str(len(node_vec))
-
- print "test_get_all_nodes PASSED"
-
-if __name__ == "__main__":
- print "####################################################################"
- print "Running ecflow version " + Client().version() + " debug build(" + str(debug_build()) +")"
- print "####################################################################"
-
- test_get_all_tasks(create_defs())
- test_get_all_nodes(create_defs())
- print "All Tests pass"
\ No newline at end of file
diff --git a/ecflow_4_0_7/Pyext/test/py_u_TestJobGeneration.py b/ecflow_4_0_7/Pyext/test/py_u_TestJobGeneration.py
deleted file mode 100644
index 36cc033..0000000
--- a/ecflow_4_0_7/Pyext/test/py_u_TestJobGeneration.py
+++ /dev/null
@@ -1,135 +0,0 @@
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# Name :
-# Author : Avi
-# Revision : $Revision: #10 $
-#
-# Copyright 2009-2012 ECMWF.
-# This software is licensed under the terms of the Apache Licence version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation
-# nor does it submit to any jurisdiction.
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-# This code is used check job generation
-#
-import os
-import shutil # used to remove directory tree
-
-import ecflow_test_util as Test
-from ecflow import Defs, JobCreationCtrl, TaskVec, File, Client, debug_build
-
-def ecf_includes() : return Test.get_root_source_dir() + "/Pyext" + "/test/data/includes"
-
-def create_defs(ecf_home,task_vec):
- defs = Defs();
- suite = defs.add_suite("suite_job_gen");
- suite.add_variable("ECF_HOME",ecf_home);
- suite.add_variable("ECF_CLIENT_EXE_PATH",File.find_client());
- suite.add_variable("SLEEPTIME","1");
- suite.add_variable("ECF_INCLUDE",ecf_includes());
-
- fam = suite.add_family("family")
- t1 = fam.add_task("t1")
- t1.add_event("eventname");
- t1.add_meter("meter",0,100,100)
-
- t2 = fam.add_task("t2")
- t3 = fam.add_task("t3")
- t4 = fam.add_task("dummy_task")
- t4.add_variable("ECF_DUMMY_TASK","any"); # stop job generation errors for tasks without an .ecf
- task_vec.append(t1);
- task_vec.append(t2);
- task_vec.append(t3);
- task_vec.append(t4);
-
- return defs
-
-
-def delete_jobs(task_vec, ecf_home):
- print "delete jobs"
- for task in task_vec:
- the_job_file = ecf_home + task.get_abs_node_path() + ".job" + task.get_try_no()
- if os.path.exists(the_job_file) :
- print "removing file " + the_job_file
- try: os.remove(the_job_file)
- except: pass
- man_file = ecf_home + task.get_abs_node_path() + ".man"
- if os.path.exists(man_file) :
- print "removing man_file " + man_file
- try: os.remove(man_file)
- except: pass
-
-def check_jobs(task_vec, ecf_home):
- print "Check job file exists"
- for task in task_vec:
- variable = task.find_variable("ECF_DUMMY_TASK")
- if not variable.empty(): continue;
- the_job_file = ecf_home + task.get_abs_node_path() + ".job" + task.get_try_no()
-
- if os.path.exists(the_job_file) :
- print "Found job file " + the_job_file
- else:
- assert False, "Could not find job file " + the_job_file
-
-
-
-
-if __name__ == "__main__":
- print "####################################################################"
- print "Running ecflow version " + Client().version() + " debug build(" + str(debug_build()) +")"
- print "####################################################################"
-
- workspace = Test.get_root_source_dir();
- print workspace
-
- ecf_home = workspace + "/Pyext/test/data/ECF_HOME"
- task_vec = TaskVec()
- defs = create_defs(ecf_home,task_vec)
- print str(defs)
-
- print "Generate jobs for *ALL* tasks, to default locations ECF_HOME/ECF_NAME.job0"
- print defs.check_job_creation()
- check_jobs(task_vec,ecf_home)
- delete_jobs(task_vec,ecf_home)
-
- print "\nGenerate jobs for *ALL* tasks, to default locations ECF_HOME/ECF_NAME.job0"
- job_ctrl = JobCreationCtrl()
- defs.check_job_creation( job_ctrl )
- print job_ctrl.get_error_msg()
- check_jobs(task_vec,ecf_home)
- delete_jobs(task_vec,ecf_home)
-
- print "\nGenerate jobs for all nodes, under path, to default locations ECF_HOME/ECF_NAME.job0"
- job_ctrl = JobCreationCtrl()
- job_ctrl.set_node_path( task_vec[0].get_abs_node_path() )
- defs.check_job_creation(job_ctrl)
- print job_ctrl.get_error_msg();
- delete_jobs(task_vec,ecf_home)
-
- print "\nGenerate jobs for all tasks, to the specified directory"
- # Directory will automatically created under the provided directory
- job_ctrl = JobCreationCtrl()
- job_ctrl.set_dir_for_job_creation(workspace + "/Pyext/test/data") # generate jobs file under this directory
- defs.check_job_creation(job_ctrl)
- print job_ctrl.get_error_msg()
-
- generated_dir = job_ctrl.get_dir_for_job_creation() + "/suite_job_gen"
- print "removing directory tree " + generated_dir
- shutil.rmtree(generated_dir)
-
-
- # Create jobs for all task, to a TMP directory ($TMPDIR/ecf_check_job_creation/ECF_NAME.job0
- # When run via rsh then TMPDIR may not be defined, hence expect exception to be thrown
- try:
- job_ctrl = JobCreationCtrl()
- job_ctrl.generate_temp_dir()
- defs.check_job_creation(job_ctrl)
- print job_ctrl.get_error_msg()
- print "removing directory tree " + job_ctrl.get_dir_for_job_creation()
- shutil.rmtree(job_ctrl.get_dir_for_job_creation())
-
- delete_jobs(task_vec,ecf_home)
- print "All test pass"
- except RuntimeError, e:
- print "failed: " + str(e)
diff --git a/ecflow_4_0_7/Pyext/test/py_u_TestParent.py b/ecflow_4_0_7/Pyext/test/py_u_TestParent.py
deleted file mode 100644
index 346535b..0000000
--- a/ecflow_4_0_7/Pyext/test/py_u_TestParent.py
+++ /dev/null
@@ -1,77 +0,0 @@
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# Name :
-# Author : Avi
-# Revision : $Revision: #10 $
-#
-# Copyright 2009-2012 ECMWF.
-# This software is licensed under the terms of the Apache Licence version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation
-# nor does it submit to any jurisdiction.
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-# code for testing pointers and hierarchy in python
-
-from ecflow import Suite, Family, Task, Defs, Client, debug_build
-
-def absNodePath(node):
- """ Given a node return its absolute node path. """
- """ Example of using get_parent() """
- name_list = []
- name_list.append(node.name())
- parent = node.get_parent();
- while parent:
- name_list.append(parent.name())
- parent = parent.get_parent()
-
- name_list.reverse()
- ret = ""
- for name in name_list:
- ret = ret + "/"
- ret = ret + name
- return ret
-
-
-if __name__ == "__main__":
- print "####################################################################"
- print "Running ecflow version " + Client().version() + " debug build(" + str(debug_build()) +")"
- print "####################################################################"
-
- suite = Suite("s1");
- family = Family("f1")
- task = Task("t1")
-
- assert not suite.get_parent(), "Suite parent is always NULL"
- assert not family.get_parent(), "Expect no parent"
- assert not task.get_parent(), "Expect no parent"
-
- print "suite.get_defs() = " + str(suite.get_defs())
- print "family.get_defs() = " + str(family.get_defs())
- print "task.get_defs() = " + str(task.get_defs())
- assert not suite.get_defs(), "Expected no defs, since suite not added to defs yet"
- assert not family.get_defs(), "Expected no defs"
- assert not task.get_defs(), "Expected no defs"
-
- suite.add_family(family)
- family.add_task(task)
-
- family2 = Family("f2")
- family.add_family(family2)
-
- t1 = Task("t1")
- family2.add_task(t1)
-
- defs = Defs()
- defs.add_suite(suite);
-
- print absNodePath(t1)
- print absNodePath(family2)
- print absNodePath(family)
- print absNodePath(suite)
-
- assert t1.get_abs_node_path() == absNodePath(t1), "Expected " + t1.get_abs_node_path() + " but got " + absNodePath(t1)
- assert family2.get_abs_node_path() == absNodePath(family2),"Expected " + family2.get_abs_node_path() + " but got " + absNodePath(family2)
- assert family.get_abs_node_path() == absNodePath(family), "Expected " + family.get_abs_node_path() + " but got " + absNodePath(family)
- assert suite.get_abs_node_path() == absNodePath(suite), "Expected " + family.get_abs_node_path() + " but got " + absNodePath(suite)
- print "All Tests pass"
diff --git a/ecflow_4_0_7/Pyext/test/py_u_TestRepeatArithmetic.py b/ecflow_4_0_7/Pyext/test/py_u_TestRepeatArithmetic.py
deleted file mode 100644
index aeccbf2..0000000
--- a/ecflow_4_0_7/Pyext/test/py_u_TestRepeatArithmetic.py
+++ /dev/null
@@ -1,52 +0,0 @@
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# Name :
-# Author : Avi
-# Revision : $Revision: #10 $
-#
-# Copyright 2009-2012 ECMWF.
-# This software is licensed under the terms of the Apache Licence version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation
-# nor does it submit to any jurisdiction.
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-# This test checks trigger evaluation uses date arithmetic when
-# the expression reference a repeat DATE variable.
-# Addition and subtraction for repeat date, should follow data arithmetic
-# The repeat variable in the expression must be on the LHS(left hand side)
-# of the expression, otherwise integer arithmetic is used
-import ecflow
-
-if __name__ == "__main__":
- print "####################################################################"
- print "Running ecflow version " + ecflow.Client().version() + " debug build(" + str(ecflow.debug_build()) + ")"
- print "####################################################################"
-
- defs = ecflow.Defs()
- s1 = defs.add_suite("s1");
- t1 = s1.add_task("t1").add_repeat( ecflow.RepeatDate("YMD",20090101,20091231,1) );
- t2 = s1.add_task("t2").add_trigger("t1:YMD ge 20100601");
-
- # Check trigger expressions
- assert len(defs.check()) == 0, "Expected no errors in parsing expressions."
-
- # Initial value of repeat is 20090101 hence trigger should fail to evaluate
- assert t2.evaluate_trigger() == False, "Expected trigger to evaluate. 20090101 >= 20100601"
-
- # Check end of month - 1
- t2.change_trigger("t1:YMD - 1 eq 20081231")
- assert t2.evaluate_trigger(), "Expected trigger to evaluate. 20090101 - 1 == 20081231"
-
- # check addition
- t2.change_trigger("t1:YMD + 1 eq 20090102");
- assert t2.evaluate_trigger(), "Expected trigger to evaluate. 20090101 + 1 == 20090102"
-
- # Check the end of each month + 1
- t1.delete_repeat();
- t1.add_repeat( ecflow.RepeatDate("YMD",20090131,20101231,1))
- t2.change_trigger("t1:YMD + 1 eq 20090201");
- assert t2.evaluate_trigger(), "Expected trigger to evaluate. 20090131 + 1 == 20090201"
-
- print "All Tests pass"
-
diff --git a/ecflow_4_0_7/Pyext/test/py_u_TestSimulator.py b/ecflow_4_0_7/Pyext/test/py_u_TestSimulator.py
deleted file mode 100644
index 749d838..0000000
--- a/ecflow_4_0_7/Pyext/test/py_u_TestSimulator.py
+++ /dev/null
@@ -1,82 +0,0 @@
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# Name :
-# Author : Avi
-# Revision : $Revision: #10 $
-#
-# Copyright 2009-2012 ECMWF.
-# This software is licensed under the terms of the Apache Licence version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation
-# nor does it submit to any jurisdiction.
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-# Test the simulation works
-
-import os
-import ecflow
-
-def simulate_defs_with_time():
- #suite test_time_series
- # family family
- # task t1
- # time 00:00 23:00 04:00 # should run 6 times 00:00 04:00 08:00 12:00 16:00 20:00
- # endfamily
- #endsuite
- print "simulate_defs_with_time()"
- defs = ecflow.Defs()
- suite = defs.add_suite("test_time_series")
- clock = ecflow.Clock(1, 1, 2011, False) # day,month, year, hybrid make test start at midnight, otherwise current time used
- suite.add_clock(clock)
- family = suite.add_family("family")
- task = family.add_task("t1")
- ts = ecflow.TimeSeries(ecflow.TimeSlot(0,0), ecflow.TimeSlot(23,0), ecflow.TimeSlot(4,0), True)
- task.add_time( ecflow.Time(ts) )
- task.add_verify( ecflow.Verify(ecflow.State.complete, 6) ) # expect task to complete 6 times
-
- theResult = defs.simulate()
- assert len(theResult) == 0, "Expected simulation to return without any errors, but found:\n" + theResult
-
- print " simple check for state change time"
- print " iso_extended:",task.get_state_change_time()
- print " iso_extended:",task.get_state_change_time("is0_extended")
- print " iso :",task.get_state_change_time("iso")
- print " simple :",task.get_state_change_time("simple")
- print " rubbish :",task.get_state_change_time("rubbish")
-
- os.remove("test_time_series.def.log")
-
-def simulate_deadlock():
- # This simulation is expected to fail, since we have a deadlock/ race condition
-
- # suite dead_lock
- # family family
- # task t1
- # trigger t2 == complete
- # task t2
- # trigger t1 == complete
- # endfamily
- # endsuite
-
- defs = ecflow.Defs()
- suite = defs.add_suite("dead_lock")
- fam = suite.add_family("family")
- fam.add_task("t1").add_trigger("t2 == complete")
- fam.add_task("t2").add_trigger("t1 == complete")
-
- theResult = defs.simulate()
- assert len(theResult) != 0, "Expected simulation to return errors, but found none"
- print theResult
-
- os.remove("dead_lock.def.log")
- os.remove("defs.depth")
- os.remove("defs.flat")
-
-if __name__ == "__main__":
- print "####################################################################"
- print "Running ecflow version " + ecflow.Client().version() + " debug build(" + str(ecflow.debug_build()) +")"
- print "####################################################################"
-
- simulate_defs_with_time()
- simulate_deadlock()
- print "All Tests pass"
diff --git a/ecflow_4_0_7/Pyext/test/py_u_TestTraversal.py b/ecflow_4_0_7/Pyext/test/py_u_TestTraversal.py
deleted file mode 100644
index f5a3d3d..0000000
--- a/ecflow_4_0_7/Pyext/test/py_u_TestTraversal.py
+++ /dev/null
@@ -1,221 +0,0 @@
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# Name :
-# Author : Avi
-# Revision : $Revision: #10 $
-#
-# Copyright 2009-2012 ECMWF.
-# This software is licensed under the terms of the Apache Licence version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation
-# nor does it submit to any jurisdiction.
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-# This file is used to test the python traversal routines
-# This is done by loading from disk a defs file.
-# traversing this defs file, and creating another defs file
-# then comparing the two. If traversal was correct. the file should be the same
-
-import ecflow
-import os,fnmatch
-
-class Indentor:
- """This class manages indentation, for use with context manager
- It is used to correctly indent the definition node tree hierarchy
- """
- _index = 0
- def __init__(self):
- Indentor._index += 1
- def __del__(self):
- Indentor._index -= 1
- @classmethod
- def indent(cls,the_file):
- for i in range(Indentor._index):
- the_file.write(' ')
-
-class DefsTraverser:
- """Traverse the ecflow.Defs definition and write to file.
-
- This demonstrates that all nodes in the node tree and all attributes are accessible.
- Additionally the state data is also accessible. This class will write state data as
- comments. If the definition was returned from the server, it allows access to latest
- snapshot of the state data held in the server.
- """
- def __init__(self,defs,file_name):
- assert (isinstance(defs,ecflow.Defs)),"Expected ecflow.Defs as first argument"
- assert (isinstance(file_name,str)),"Expected a string argument. Representing a file name"
- self.__defs = defs
- self.__file = open(file_name, 'w')
-
- def write_to_file(self):
- for extern in self.__defs.externs:
- self.__writeln("extern " + extern)
- for suite in self.__defs.suites:
- self.__write("suite ")
- self.__print_node(suite)
- clock = suite.get_clock()
- if clock:
- indent = Indentor()
- self.__writeln(str(clock))
- del indent
- self.__print_nc(suite)
- self.__writeln("endsuite")
- self.__file.close()
-
- def __print_nc(self,node_container):
- indent = Indentor()
- for node in node_container.nodes:
- if isinstance(node, ecflow.Task):
- self.__write("task ")
- self.__print_node(node)
- self.__print_alias(node)
- else:
- self.__write("family ")
- self.__print_node(node)
- self.__print_nc(node)
- self.__writeln("endfamily")
- del indent
-
- def __print_alias(self,task):
- indent = Indentor()
- for alias in task.nodes:
- self.__write("alias ")
- self.__print_node(alias)
- self.__writeln("endalias")
- del indent
-
- def __print_node(self,node):
- self.__file.write(node.name() + " # state:" + str(node.get_state()) + "\n")
-
- indent = Indentor()
- defStatus = node.get_defstatus()
- if defStatus != ecflow.DState.queued:
- self.__writeln("defstatus " + str(defStatus))
-
- autocancel = node.get_autocancel()
- if autocancel: self.__writeln(str(autocancel))
-
- repeat = node.get_repeat()
- if not repeat.empty(): self.__writeln(str(repeat) + " # value: " + str(repeat.value()))
-
- late = node.get_late()
- if late: self.__writeln(str(late) + " # is_late: " + str(late.is_late()))
-
- complete_expr = node.get_complete()
- if complete_expr:
- for part_expr in complete_expr.parts:
- trig = "complete "
- if part_expr.and_expr(): trig = trig + "-a "
- if part_expr.or_expr(): trig = trig + "-o "
- self.__write(trig)
- self.__file.write( part_expr.get_expression() + "\n")
- trigger_expr = node.get_trigger()
- if trigger_expr:
- for part_expr in trigger_expr.parts:
- trig = "trigger "
- if part_expr.and_expr(): trig = trig + "-a "
- if part_expr.or_expr(): trig = trig + "-o "
- self.__write(trig)
- self.__file.write( part_expr.get_expression() + "\n")
-
- for var in node.variables: self.__writeln("edit " + var.name() + " '" + var.value() + "'")
- for meter in node.meters: self.__writeln(str(meter) + " # value: " + str(meter.value()))
- for event in node.events: self.__writeln(str(event) + " # value: " + str(event.value()))
- for label in node.labels: self.__writeln(str(label) + " # value: " + label.new_value())
- for limit in node.limits: self.__writeln(str(limit) + " # value: " + str(limit.value()))
- for inlimit in node.inlimits: self.__writeln(str(inlimit))
- for the_time in node.times: self.__writeln(str(the_time))
- for today in node.todays: self.__writeln(str(today))
- for date in node.dates: self.__writeln(str(date))
- for day in node.days: self.__writeln(str(day))
- for cron in node.crons: self.__writeln(str(cron))
- for verify in node.verifies: self.__writeln(str(verify))
- for zombie in node.zombies: self.__writeln(str(zombie))
-
- del indent
-
- def __write(self,the_string):
- Indentor.indent(self.__file)
- self.__file.write(the_string)
-
- def __writeln(self,the_string):
- Indentor.indent(self.__file)
- self.__file.write(the_string + "\n")
-
-def check_traversal(path_to_def):
- # Open a def on disk *and* load into memory
- reference_def = ecflow.Defs( path_to_def )
-
- # traverse the opened def and write it out again
- file_name = "copy.def"
- traverser = DefsTraverser(reference_def,file_name)
- traverser.write_to_file()
-
- # restore the defs we create via traversal. If traversal was good it should
- # be the same as def on disk.
- try:
- traversed_def = ecflow.Defs( file_name )
- except RuntimeError, e:
- print "Could not parse file " + file_name + "\n" + str(e)
- exit(1)
-
- # compare the two defs
- ecflow.Ecf.set_debug_equality(True)
- defs_equal = (traversed_def == reference_def)
- if not defs_equal:
- print str(path_to_def) + " FAILED "
- print "The traversed defs=========\n" + str(traversed_def) + "\nnot the same as reference def============\n" + str(reference_def)
- print "===================== " + file_name + " ===================================="
- the_traversed_def_on_disk = open(file_name)
- for line in the_traversed_def_on_disk:
- print line,
-
- assert defs_equal, "Failed: ---"
-
- # Notice: this path does not delete file_name, left for analysis of failure
- else:
- print str(path_to_def) + " PASSED "
- os.remove(file_name)
-
-
-def all_files(root, patterns='*', single_level=False, yield_folders=False):
- """Expand patterns from semi-colon separated string to list"""
- patterns = patterns.split(';')
- for path, subdirs, files in os.walk(root):
- if yield_folders:
- files.extend(subdirs)
- files.sort()
- for name in files:
- for pattern in patterns:
- if fnmatch.fnmatch(name,pattern):
- yield os.path.join(path, name)
- break
- if single_level:
- break
-
-if __name__ == "__main__":
- print "####################################################################"
- print "Running ecflow version " + ecflow.Client().version() + " debug build(" + str(ecflow.debug_build()) +")"
- print "####################################################################"
-
- cwd = os.getcwd()
- #print cwd
- #print "split = " + str(os.path.split(cwd))
- #print "basename = " + os.path.basename(cwd)
- #print "dirname = " + os.path.dirname(cwd)
- #print "splitext = " + str( os.path.splitext(cwd) )
- #print "isdir = " + str(os.path.isdir(cwd))
-
- # Traverse all the good defs in the Parser directory
- newpath = ""
- if os.path.basename(cwd) == "Pyext":
- newpath = os.path.join( os.path.dirname(cwd),"AParser/test/data/good_defs" )
-
- #print newpath
- for path_to_defs_file in all_files(newpath, '*.def;*.txt'):
- check_traversal(path_to_defs_file)
-
- # try the mega_def. Commented out since it takes to long
- #mega_def = os.path.join( os.path.dirname(cwd), "AParser/test/data/single_defs/mega.def")
- #check_traversal(mega_def)
- print "All Tests pass"
\ No newline at end of file
diff --git a/ecflow_4_0_7/Pyext/test/py_u_TestUserManual.py b/ecflow_4_0_7/Pyext/test/py_u_TestUserManual.py
deleted file mode 100644
index 7634df6..0000000
--- a/ecflow_4_0_7/Pyext/test/py_u_TestUserManual.py
+++ /dev/null
@@ -1,156 +0,0 @@
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# Name :
-# Author : Avi
-# Revision : $Revision: #10 $
-#
-# Copyright 2009-2012 ECMWF.
-# This software is licensed under the terms of the Apache Licence version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation
-# nor does it submit to any jurisdiction.
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-# This code is used in the user manual
-#
-
-from ecflow import Suite, Task, RepeatDate
-
-if __name__ == "__main__":
-
- class ExperimentalSuite(object):
- def __init__(self, start, end) :
- self.start_ = start
- self.end_ = end
- self.start_cycle_ = 12
- self.end_cycle_ = 12
-
- def generate(self) :
- x_suite = Suite("x")
- make_fam = x_suite.add_family("make")
- make_fam.add_task("build")
- make_fam.add_task("more_work")
-
- main_fam = x_suite.add_family("main")
- main_fam.add_repeat( RepeatDate("YMD",self.start_,self.end_) )
- main_fam.add_trigger( "make == complete" )
-
- previous = 0
- for FAM in ( 0, 6, 12, 18 ) :
- fam_fam = x_suite.add_family(str(FAM))
- if FAM > 0 :
- fam_fam.add_trigger( "./" + str(previous) + " == complete " )
-
- self.add_complete(fam_fam,FAM)
-
- fam_fam.add_task("run")
- fam_fam.add_task("run_more").add_trigger( "run == complete")
- previous = FAM
- return x_suite
-
- def add_complete(self, family, fam):
- if fam < self.start_cycle_ and fam > self.end_cycle_ :
- family.add_complete("../main:YMD eq " + str(self.start_) + " or ../main:YMD ge " + str(self.end_))
- elif fam < self.start_cycle_ :
- family.add_complete("../main:YMD eq " + str(self.start_))
- elif fam > self.end_cycle_ :
- family.add_complete("../main:YMD ge " + str(self.end_))
- return
-
- print str( ExperimentalSuite(20050601,20050605).generate() )
-
-# ==========================================================================
-
-# Control structure and looping
- var = "aa"
- if var in ( "a", "aa", "aaa" ) : print "it is a kind of a "
- elif var in ( "b", "bb", "bb" ) : print "it is a kind of b "
- else : print "it is something else "
-
-# ==========================================================================
-
- task = Task("task")
- the_time = 0
- if the_time == 0 :
- task.add_today(17, 30)
- task.add_variable("ANTIME", str(the_time))
- elif the_time == 6 :
- task.add_today(17, 30)
- task.add_variable("ANTIME", str(the_time))
- elif the_time == 12 :
- task.add_today(19, 15)
- task.add_variable("ANTIME", str(the_time))
- elif the_time == 18 :
- task.add_time(1, 30)
- task.add_variable("ANTIME", str(the_time))
- elif the_time == 24 :
- task.add_time(3, 0)
- task.add_variable("ANTIME", "0")
- task.add_variable("DELTA_DAY", "1")
- task.add_variable("EXPVER", "0002")
-
-# ====================================================================================
-
- # Reuseable class for adding synoptic times
- class VarAdder(object):
- def __init__(self, node):
- self.node = node
-
- def add(self, time):
- {
- 6: lambda self : self.add6(time),
- 12: lambda self : self.add12(time),
- 18: lambda self : self.add18(time),
- 24: lambda self : self.add24(time)
- }.get(time, self.errorHandler)(self)
-
- def add6(self, time):
- print "add6 " + str(time)
- self.node.add_today(17, 30)
- self.node.add_variable("ANTIME", str(time))
-
- def add12(self, time):
- print "add12 " + str(time)
- self.node.add_today(19, 15)
- self.node.add_variable("ANTIME", str(time))
-
- def add18(self, time):
- print "add18 " + str(time)
- self.node.add_time(1, 30)
- self.node.add_variable("ANTIME", str(time))
-
- def add24(self, time):
- print "add24 " + str(time)
- self.node.add_time(3, 0)
- self.node.add_variable("ANTIME", "0")
- self.node.add_variable("DELTA_DAY", "1")
- self.node.add_variable("EXPVER", "0002")
-
- def errorHandler(self, ignore): print "invalid time " + str(ignore)
-
-#for i in (0, 6 ,12, 18, 24):
-for i in (0, 6):
- task = Task("t" + str(i))
- print task.name()
- varAdder = VarAdder(task)
- varAdder.add(114)
- for var in task.variables:
- print str(var) + "\n"
- for the_time in task.times :
- print str(the_time) + "\n"
- for today in task.todays :
- print str(today) + "\n"
-
-# ==========================================================================
-
-suite = Suite("x")
-previous_time = 0
-for i in (0,6,12,18,24) :
- the_fam = suite.add_family(str(i))
- if i != 0:
- the_fam.add_trigger("./" + previous_time + " == complete ")
- the_fam.add_task("t1")
- the_fam.add_task("t2").add_trigger("t1 == complete")
- previous_time = str(i)
-
-# print str(suite)
diff --git a/ecflow_4_0_7/Pyext/test/py_u_TestWith.py b/ecflow_4_0_7/Pyext/test/py_u_TestWith.py
deleted file mode 100644
index 7b8ff9f..0000000
--- a/ecflow_4_0_7/Pyext/test/py_u_TestWith.py
+++ /dev/null
@@ -1,79 +0,0 @@
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-# Name :
-# Author : Avi
-# Revision : $Revision: #10 $
-#
-# Copyright 2009-2012 ECMWF.
-# This software is licensed under the terms of the Apache Licence version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation
-# nor does it submit to any jurisdiction.
-#////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-# code for testing with statement
-# In our case it provides the ability to indent
-
-from ecflow import Defs, Suite, Family, Client, debug_build
-import sys
-
-if __name__ == "__main__":
- print "####################################################################"
- print "Running ecflow version " + Client().version() + " debug build(" + str(debug_build()) +")"
- print "####################################################################"
-
- version = sys.version_info;
- if version[1] < 7 :
- print "This test only run with python version 2.7, but found : " + str(version)
- exit(0)
-
- print "start test"
- # Add with context manager, in our case this only provides ability to indent
- with Defs() as defs:
- with defs.add_suite("s2") as s2:
- with s2.add_family("f1") as f1:
- with f1.add_task("t1") as t1:
- assert len(list(f1.nodes)) == 1,"Expected 1 task"
- s2.add_family("f2")
- s2.add_task("t1")
- assert len(list(s2.nodes)) == 3,"Expected 2 families and one task suite"
- assert len(list(defs.suites)) == 1,"Expected 1 suite"
-# print defs
-
- with Suite("s2") as s2:
- s2.add_family("f1")
- s2.add_task("t1")
- assert len(list(s2.nodes)) == 2,"Expected 2 nodes family and task"
-
- with Family("f1") as f1:
- f1.add_family("f2")
- f1.add_task("t1")
- assert len(list(s2.nodes)) == 2,"Expected 2 nodes family and task"
-
-
- #
- # Add Nodes functional way
- #
- defs1 = Defs()
- defs1.add_suite("s1").add_task("t1").add_variable("var","v")
- defs1.add_suite("s2").add_family("f1").add_task("t1").add_variable("var","v")
- defs1.add_suite("s3").add_family("f1").add_family("f2").add_task("t1").add_variable("var","v")
-
- # add node using with, they should compare
- with Defs() as defs2:
- with defs2.add_suite("s1") as s1:
- t1 = s1.add_task("t1")
- t1.add_variable("var","v")
- with defs2.add_suite("s2") as s2:
- with s2.add_family("f1") as f1:
- with f1.add_task("t1") as t1:
- t1.add_variable("var","v")
- with defs2.add_suite("s3") as s3:
- with s3.add_family("f1") as f1:
- with f1.add_family("f2") as f2:
- with f2.add_task("t1") as t1:
- t1.add_variable("var","v")
-
- assert defs1 == defs2,"expected defs to be the same"
-
- print "All tests pass"
\ No newline at end of file
diff --git a/ecflow_4_0_7/README b/ecflow_4_0_7/README
deleted file mode 100644
index 4fb55f9..0000000
--- a/ecflow_4_0_7/README
+++ /dev/null
@@ -1,157 +0,0 @@
-===========
-**Install**
-===========
-
-* dependencies
-
- * | python 2.7, Python 3.0 not tested.
- | If you intend to use ecFlow Python api, You will need to install python.
- | If python installed in non standard installation, you may need to
- | customise $BOOST_ROOT/tools/build/v2/site-config.jam
- | The python installation should include the development packages
-
- * Xlib, X11, XMotif for :term:`ecflowview`. Do *not* use Lesstif library
- to compile ecflowview as a replacement for Motif. OpenMotif can be
- downloaded from http://www.ist.co.uk/downloads/motif_download.html
-
- * optionally cmake
-
-* ecfFlow consists of two tar files i.e. :
-
- * :file:`boost_1_53_0.tar.gz`
- * :file:`ecflow_4_0_7.tar.gz`
-
-* Create a directory for the build::
-
- > mkdir /tmp/ecflow_build
-
-* Copy the the two tar file into this directory, then change directory to :file:`/tmp/ecflow_build`
-
-* Un-zip then un-tar the two file files::
-
- # gunzip boost_1_53_0.tar.gz
- # gunzip ecflow_4_0_7.tar.gz
- # tar -xf boost_1_53_0.tar
- # tar -xf ecflow_4_0_7.tar
-
-* You should have three directories created::
-
- boost_1_53_0
- ecflow_4_0_7
- ecbuild
-
-* Create two environment variables. These are used by some of scripts::
-
- > export WK=/tmp/ecflow_build/ecflow_4_0_7
- > export BOOST_ROOT=/tmp/ecflow_build/boost_1_53_0
-
-
-* There are two ways of building ecflow, boost-build/bjam or cmake/ecbuild
-
-
-cmake/ecbuild
-=====================================================================
-
-* run $WK/configure.sh , just specify the install prefix
-
- # ./configure.sh /usr/local/apps/ecflow
- # make
- # make install
-
-
-boost/bjam
-=====================================================================
-* | For installation the following environment variables are required.
-
- ::
-
- ECFLOW_INSTALL_DIR # Directory Location for client ,server and gui program's
- ECFLOW_PYTHON_INSTALL_DIR # Directory Location for ecflow python package
-
- The python installation can be customised, by changing Pyext/jamfile.jam and site-config.jam
-
-* | Boost uses bjam for build. ecFlow also uses bjam for build and installation
- | bjam source is available in boost, hence we first need to build bjam itself
-
- ::
-
- > cd $BOOST_ROOT
- > ./bootstrap.sh
-
- Now make sure bjam is accessible from $PATH
-
-* | Ecflow uses some of compiled libraries in boost. The following script
- | will build the required lib's, in both debug and release forms
- | and will configure boost build according to your platform
-
- ::
-
- > cd $BOOST_ROOT
- > $WK/build/boost_1_53_fix.sh # fix for boost, only for some platforms
- > $WK/build/boost_build.sh # compile boost libs used by ecFlow
-
-* We now need to build ecFlow. Currently ecflowview is only built if
- environment variable of name ARCH is set to linux::
-
- > cd $WK
- > bjam variant=release install-all
-
- | On some systems like fedora/redhat you may run into compiler errors
- | which complain about the template depth being exceeded.
- | In this case compile using:
-
- ::
-
- > cd $WK
- > bjam c++-template-depth=512 variant=release install-all
-
- | If you have a multi-core machine, you can speed up the build using:
- | the -j<n> option. Where 'n' is an integer, of the number of cores.
-
- ::
-
- bjam variant=release -j4
-
-
-* | Once ecFlow is built it can be installed.
-
- ::
-
- bjam variant=release install-all
-
- This will create directories::
-
- <ECFLOW_INSTALL_DIR>/bin
- <ECFLOW_INSTALL_DIR>/lib
- <ECFLOW_INSTALL_DIR>/doc
- <ECFLOW_PYTHON_INSTALL_DIR>
-
- Depending on your umask setting you may need to call chmod 755 on the executables
-
-
-* | To use the :ref:`python_api`, you need to add/change
- | PYTHONPATH and LD_LIBRARY_PATH
-
- ::
-
- export PYTHONPATH=$PYTHONPATH:$ECFLOW_PYTHON_INSTALL_DIR
- export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ECFLOW_PYTHON_INSTALL_DIR
-
-* When compiling ecflowview in a system where motif is not installed in the
- usual location, or where both motif and lesstif are installed, it is possible
- to export the environment variables MOTIF_INCLUDE and MOTIF_LIBRARY to help
- bjam to find the right location for include files and libraries.
-
- Openmotif may be retrieve from IST server and installed locally:
- wget http://www.ist-inc.com/motif/download/motif_files/openmotif-2.1.32-2_IST.x86_64.rpm
- rpm2cpio openmotif-2.1.32-2_IST.x86_64.rpm | cpio -idmv
-
- user shall then compile setting MOTIF_INCLUDE and MOTIF_LIBRARY variable.
-
-.. ecflowview shall be started setting LD_LIBRARY_PATH=${MOTIF_LIBRARY}:$LD_LIBRARY_PATH
-
-* ECFLOWVIEW_HOME shell variable may be set to link ecflowview to the directory
- where to find 'servers' and 'ecflowview.menu' files
-
-* ECFLOWRC variable may be set to use alternative directory for user
- ecflowview option files (default is $HOME/.ecflowrc)
diff --git a/ecflow_4_0_7/Server/Jamfile.jam b/ecflow_4_0_7/Server/Jamfile.jam
deleted file mode 100644
index adcfdd3..0000000
--- a/ecflow_4_0_7/Server/Jamfile.jam
+++ /dev/null
@@ -1,93 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-#
-# Server
-#
-project theServer ;
-
-#
-# IMPORTANT: server *MUST* not link with client or include any of the client code
-#
-use-project theCore : ../ACore ;
-use-project theNodeAttr : ../ANattr ;
-use-project theNode : ../ANode ;
-use-project theBase : ../Base ;
-use-project theParser : ../AParser ;
-
-lib pthread ;
-
-#
-# Split into library, so that testing can use library, and hence same compiler option
-#
-# The <include> means we will automatically add this directory to the include path
-# of any other target that uses this lib
-
-#
-# Note: boost_thread is *ONLY* needed to test multi-threaded server, i.e when ECFLOW_MT defined
-#
-lib libserver : [ glob src/*.cpp : src/*Main.cpp ]
- : <include>../ACore/src
- <include>../ANattr/src
- <include>../ANode/src
- <include>../AParser/src
- <include>../Base/src
- <include>../Server/src
- <variant>debug:<define>DEBUG
- <link>static
- <use>/theCore//core
- <use>/theNode//node
- <use>/theBase//base
- <use>/theParser//libparser
- <use>/site-config//boost_system
- <use>/site-config//boost_thread
- <use>/site-config//boost_serialization
- <use>/site-config//boost_filesystem
- <use>/site-config//boost_program_options
- <use>/site-config//boost_datetime
- :
- : <include>../Server/src
- ;
-
-exe ecflow_server : [ glob src/*Main.cpp ]
- pthread
- /theCore//core
- /theNodeAttr//nodeattr
- /theNode//node
- /theParser//libparser
- /theBase//base
- libserver
- /site-config//boost_system
- /site-config//boost_thread
- /site-config//boost_serialization
- /site-config//boost_filesystem
- /site-config//boost_datetime
- /site-config//boost_program_options
- : <variant>debug:<define>DEBUG
- ;
-
-#
-# Test for server
-# IMPORTANT: server *MUST* not link with client or include any of the client code
-#
-exe u_server : [ glob test/*.cpp ]
- pthread
- /theCore//core
- /theNodeAttr//nodeattr
- /theNode//node
- /theParser//libparser
- /theBase//base
- libserver
- /site-config//boost_system
- /site-config//boost_thread
- /site-config//boost_serialization
- /site-config//boost_filesystem
- /site-config//boost_datetime
- /site-config//boost_program_options
- /site-config//boost_test
- : <variant>debug:<define>DEBUG
- ;
diff --git a/ecflow_4_0_7/Server/server_environment.cfg b/ecflow_4_0_7/Server/server_environment.cfg
deleted file mode 100644
index be8e578..0000000
--- a/ecflow_4_0_7/Server/server_environment.cfg
+++ /dev/null
@@ -1,153 +0,0 @@
-## Copyright 2009-2014 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-#
-# This file is used to define the standard defaults for ECF.
-# Most are *variables* used in the server
-# Some like ECF_TASK_THRESHOLD are used to debug job generation
-
-# ******************************************************************
-# Warning: Do *NOT* use quotes around the value part.
-# WRONG: ECF_MICRODEF = "%"
-# RIGHT: ECF_MICRODEF = %
-# ******************************************************************
-
-# *******************************************************************
-# * ECF_HOME is typically the home/root for all '.ecf' files
-# * Can be overridden with a environment variable of the same name
-# *******************************************************************
-ECF_HOME = .
-
-
-# ******************************************************************
-# * The name of check point file. i.e defs file with state
-# * Can be overridden with a environment variable of the same name
-# * default: is <host>.<port>.ecf.check
-# * Note: Any settings will be prepended with <host>.<port>.
-# ******************************************************************
-ECF_CHECK = ecf.check
-
-
-# ******************************************************************
-# * The name of the backup checkpoint file
-# * Can be overridden with a environment variable of the same name
-# * default: is <host>.<port>.ecf.check.b
-# * Note: Any settings will be prepended with <host>.<port>.
-# ******************************************************************
-ECF_CHECKOLD = ecf.check.b
-
-
-# ******************************************************************
-# * The intervals within the server that the checkpoint file should
-# * be saved.
-# * Can be overridden with a environment variable of the same name
-# ******************************************************************
-ECF_CHECKINTERVAL = 120
-
-
-# ******************************************************************
-# * Check point configuration:
-# *
-# * Mode must be one of:
-# * CHECK_NEVER /* No auto checkpointing */
-# * CHECK_ON_TIME /* At intervals specified by ECF_CHECKINTERVAL */
-# * CHECK_ALWAYS /* After any change */
-# * The checkpoint filenames can be configured using environment variables
-# ******************************************************************
-ECF_CHECKMODE = CHECK_ON_TIME
-
-
-# ******************************************************************
-# * The port number, this must be consistent between client and server
-# * If we get "Address in use" then both client/server number should changed.
-# * Also if two servers are started on the same machine with same port
-# * then we will also get "Address in use" error and server will bomb out.
-# * Can be overridden with a environment variable of the same name
-# ******************************************************************
-ECF_PORT = 3141
-
-
-# ******************************************************************
-# * The name of log file.
-# * default log file name is: <host>.<port>.ecf.log, i.e machine1.3141.ecf.log
-# * this is required since we can have multiple servers for a single
-# * machine, where each server will have a separate port number.
-# * Can be overridden with a environment variable of the same name
-# *
-# * Note: Any settings will be prepended with <host>.<port>.
-# ******************************************************************
-ECF_LOG = ecf.log
-
-
-# ******************************************************************
-# * The period in second for which we should traverse dependencies
-# * and submit jobs. This should rarely need changing, as it can affect
-# * correspondence with real time
-# ******************************************************************
-ECF_INTERVAL = 60
-
-
-# ******************************************************************
-# * The standard command use for job submission.
-# * Provides DEFAULT can be overridden by user variable
-# ******************************************************************
-ECF_JOB_CMD = %ECF_JOB% 1> %ECF_JOBOUT% 2>&1
-
-
-# ******************************************************************
-# * Define variable for killing any jobs.
-# * Provides DEFAULT can be overridden by user variable
-# * The output of the command should be written to %ECF_JOB%.kill
-# * ecmwf: ${ECF_KILL:=/home/ma/emos/bin/ecfkill} %USER% %HOST% %ECF_RID% %ECF_JOB% > %ECF_JOB%.kill 2>&1
-# ******************************************************************
-ECF_KILL_CMD = kill -15 %ECF_RID%
-
-
-# ******************************************************************
-# * define variable of obtaining status.
-# * Provides DEFAULT can be overridden by user variable
-# * The output of the command should be written to %ECF_JOB%.stat
-# * ecmwf: ${ECF_STAT:=/home/ma/emos/bin/ecfstatus} %USER% %HOST% %ECF_RID% %ECF_JOB% > %ECF_JOB%.stat 2>&1
-# ******************************************************************
-ECF_STATUS_CMD = ps --sid %ECF_RID% -f
-
-
-# ******************************************************************
-# * define variables used for url command.
-# * Provides DEFAULT can be overriden by user variables
-# ******************************************************************
-ECF_URL_CMD = ${BROWSER:=firefox} -remote 'openURL(%ECF_URL_BASE%/%ECF_URL%)'
-ECF_URL_BASE = https://software.ecmwf.int
-ECF_URL = wiki/display/ECFLOW/Home
-
-# ******************************************************************
-# * Defines the character used in ECF_ pre-processing. i.e identifies includes
-# * and is also used in variable substitution in '.ecf' scripts
-# ******************************************************************
-ECF_MICRODEF = %
-
-# ******************************************************************
-# * The ECF_LISTS is used to identify a file, that lists the user
-# * who can access the server via client commands. Each client command
-# * (ignoring task based commands, i.e init, complete, event, meter, label)
-# * will encode the user name of the process initiating the client request
-# * This is then compared with list of users in the ecf.lists file.
-# * If this file is empty, then no authentication is done
-# * Each server can potionally have a different list.
-# * default: <host>.<port>.ecf.lists
-# * Note: Any settings will be prepended with <host>.<port>.
-# ******************************************************************
-ECF_LISTS = ecf.lists
-
-
-# ***************************************************************************
-# * ECF_TASK_THRESHOLD:
-# * Report on an task taking longer than the threshold. !!
-# * export ECF_TASK_THRESHOLD=4000
-# ***************************************************************************
-ECF_TASK_THRESHOLD = 4000
-
\ No newline at end of file
diff --git a/ecflow_4_0_7/Server/src/CConnection.cpp b/ecflow_4_0_7/Server/src/CConnection.cpp
deleted file mode 100644
index 5777005..0000000
--- a/ecflow_4_0_7/Server/src/CConnection.cpp
+++ /dev/null
@@ -1,237 +0,0 @@
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #14 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : ONLY used if ECFLOW_MT is defined
-//
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#ifdef ECFLOW_MT
-#if defined(HPUX)
-#include <sys/select.h> // hp-ux uses pselect
-#endif
-
-#include <boost/thread/thread.hpp>
-#include <boost/bind.hpp>
-
-#include "CConnection.hpp"
-#include "Log.hpp"
-#include <vector>
-
-#include "Log.hpp"
-#include "Serialization.hpp"
-#include "Server.hpp"
-
-using namespace std;
-using namespace ecf;
-
-CConnection::CConnection(boost::asio::io_service& io_service,server* server)
- : socket_(io_service),
- server_(server)
-{
-}
-
-boost::asio::ip::tcp::socket& CConnection::socket()
-{
- return socket_;
-}
-
-void CConnection::start()
-{
- //cout << boost::this_thread::get_id() << " CConnection::start()\n";
- boost::asio::async_read(socket_, boost::asio::buffer(inbound_header_),
- server_->strand_.wrap(
- boost::bind(&CConnection::handle_read_header,
- shared_from_this(),
- boost::asio::placeholders::error)));
-}
-
-void CConnection::handle_read_header(const boost::system::error_code& e)
-{
- //cout << boost::this_thread::get_id() << " CConnection::handle_read_header\n";
- if (e) {
- LogToCout toCoutAsWell;
- LOG(Log::ERR, " CConnection::handle_read_header error occurred " << e.message());
- }
- else {
- // Determine the length of the serialized data.
- std::istringstream is(std::string(inbound_header_, header_length));
- std::size_t inbound_data_size = 0;
- if (!(is >> std::hex >> inbound_data_size)) {
-
- // Header doesn't seem to be valid. Inform the caller.
- boost::system::error_code error(boost::asio::error::invalid_argument);
- LogToCout toCoutAsWell;
- LOG(Log::ERR, " CConnection::handle_read_header error occurred " << e.message());
- return;
- }
-
- // Start an asynchronous call to receive the data.
- inbound_data_.resize(inbound_data_size);
- boost::asio::async_read(socket_,boost::asio::buffer(inbound_data_),
- server_->strand_.wrap(
- boost::bind(&CConnection::handle_read_data,
- shared_from_this(),
- boost::asio::placeholders::error)));
- }
-}
-
-void CConnection::handle_read_data(const boost::system::error_code& e)
-{
- //cout << boost::this_thread::get_id() << " CConnection::handle_read_data\n";
- if (e) {
- LogToCout toCoutAsWell;
- LOG(Log::ERR, " CConnection::handle_read_data error occurred " << e.message());
- return;
- }
-
- // Extract the data structure from the data just received.
- try {
- std::string archive_data(&inbound_data_[0], inbound_data_.size());
- ecf::restore_from_string(archive_data,inbound_request_);
- }
- catch (const boost::archive::archive_exception& ae ) {
- // Unable to decode data.
- ecf::LogToCout logToCout;
- LOG(ecf::Log::ERR,"CConnection::handle_read_data boost::archive::archive_exception " << ae.what());
- return;
- }
- catch (std::exception& ) {
- // Unable to decode data.
- ecf::LogToCout logToCout;
- LOG(ecf::Log::ERR,"CConnection::handle_read_data Unable to decode data");
- return;
- }
-
-
- // See what kind of message we got from the client
- // std::cout << boost::this_thread::get_id() << " server::handle_read : client request " << inbound_request_ << "\n";
- try {
- // Service the in bound request, handling the request will populate the outbound_response_
- // Note:: Handle request will first authenticate
- outbound_response_.set_cmd( inbound_request_.handleRequest( server_ ) );
- }
- catch (exception& ex) {
- outbound_response_.set_cmd( PreAllocatedReply::error_cmd( ex.what() ));
- }
-
- // To improve performance, when the reply, is OK, don't bother replying back to the client
- // The client will receive a EOF, and perceive this as OK.
- // Need to specifically *ignore* for terminate, otherwise server will not shutdown cleanly
- if (!inbound_request_.terminateRequest() && outbound_response_.get_cmd()->isOkCmd()) {
- // cleanly close down the connection
- socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
- socket_.close();
- return;
- }
-
- reply_back_to_client();
-}
-
-void CConnection::reply_back_to_client()
-{
-#ifdef DEBUG_CONNECTION
- std::cout << "CConnection::reply_back_to_client, Serialise the data first so we know how large it is\n";
-#endif
- // Serialise the data first so we know how large it is.
- try {
- ecf::save_as_string(outbound_data_,outbound_response_);
- } catch (const boost::archive::archive_exception& ae ) {
- // Unable to decode data. Something went wrong, inform the caller.
- ecf::LogToCout logToCout;
- LOG(ecf::Log::ERR,"Connection::async_write boost::archive::archive_exception " << ae.what());
- return;
- }
-
- // Format the header.
- std::ostringstream header_stream;
- header_stream << std::setw(header_length) << std::hex << outbound_data_.size();
- if (!header_stream || header_stream.str().size() != header_length) {
- // Something went wrong, inform the caller.
- ecf::LogToCout logToCout;
- LOG(ecf::Log::ERR,"CConnection::reply_back_to_client: could not format header");
- return;
- }
- outbound_header_ = header_stream.str();
-
-
-#ifdef DEBUG_CONNECTION
- std::cout << "Connection::async_write Write the serialized data to the socket. \n";
-#endif
- // Write the serialized data to the socket. We use "gather-write" to send
- // both the header and the data in a single write operation.
- std::vector<boost::asio::const_buffer> buffers; buffers.reserve(2);
- buffers.push_back(boost::asio::buffer(outbound_header_));
- buffers.push_back(boost::asio::buffer(outbound_data_));
- boost::asio::async_write(socket_, buffers,
- server_->strand_.wrap(
- boost::bind(&CConnection::handle_write, shared_from_this(),
- boost::asio::placeholders::error)));
-
-#ifdef DEBUG_CONNECTION
- std::cout << "Connection::async_write END \n";
-#endif
-
- // If an error occurs then no new asynchronous operations are started. This
- // means that all shared_ptr references to the CConnection object will
- // disappear and the object will be destroyed automatically after this
- // handler returns. The CConnection class's destructor closes the socket.
-}
-
-void CConnection::handle_write(const boost::system::error_code& e)
-{
- // Handle completion of a write operation.
- // Nothing to do. The socket will be closed automatically when the last
- // reference to the connection object goes away.
- //cout << boost::this_thread::get_id() << " server::handle_write: client request " << inbound_request_ << " replying with " << outbound_response_ << "\n";
-
- if (e)
- {
- ecf::LogToCout logToCout;
- LOG(ecf::Log::ERR,"Connection::handle_write: " << e.message());
-
- // No new asynchronous operations are started. This means that all shared_ptr
- // references to the CConnection object will disappear and the object will be
- // destroyed automatically after this handler returns. The CConnection class's
- // destructor closes the socket.
- return;
- }
-
-
- // Initiate graceful connection closure.
- // For portable behaviour with respect to graceful closure of a connected socket, call shutdown() before closing the socket.
- // This *CAN* throw an error if the client side socket is not connected. client may have been killed.
- // i.e "shutdown: Transport endpoint is not connected"
- boost::system::error_code ec;
- socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
- if (ec) {
- ecf::LogToCout logToCout;
- LOG(Log::ERR,"server::handle_write: socket shutdown both failed: " << ec.message());
- }
-
-
- // If asked to terminate we do it here rather than in handle_read.
- // So that we have responded to the client.
- // *HOWEVER* only do this if the request was successful.
- // we do this by checking that the out bound response was ok
- // i.e a read only user should not be allowed to terminate server.
- if (inbound_request_.terminateRequest() && outbound_response_.get_cmd()->isOkCmd()) {
- // cout << " <--server::handle_write exiting server via terminate() port " << endl;
-
- server_->terminate();
- }
-
- // No new asynchronous operations are started. This means that all shared_ptr
- // references to the CConnection object will disappear and the object will be
- // destroyed automatically after this handler returns. The CConnection class's
- // destructor closes the socket.
-}
-#endif
diff --git a/ecflow_4_0_7/Server/src/CConnection.hpp b/ecflow_4_0_7/Server/src/CConnection.hpp
deleted file mode 100644
index 8d9fb03..0000000
--- a/ecflow_4_0_7/Server/src/CConnection.hpp
+++ /dev/null
@@ -1,74 +0,0 @@
-#ifndef CCONNECTION_HPP
-#define CCONNECTION_HPP
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name :
-// Author : Avi
-// Revision : $Revision: #14 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : ONLY used if ECFLOW_MT is defined
-//
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <boost/asio.hpp>
-#include <boost/array.hpp>
-#include <boost/noncopyable.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/enable_shared_from_this.hpp>
-
-#include "ClientToServerRequest.hpp"
-#include "ServerToClientResponse.hpp"
-
-class server;
-
-/// Represents a single connection from a client.
-class CConnection : public boost::enable_shared_from_this<CConnection>, private boost::noncopyable {
-public:
- /// Construct a connection with the given io_service.
- explicit CConnection( boost::asio::io_service& io_service, server* );
-
- /// Get the socket associated with the connection.
- boost::asio::ip::tcp::socket& socket();
-
- /// Start the first asynchronous operation for the connection.
- void start();
-
-private:
- /// Handle completion of a read operation.
- void handle_read( const boost::system::error_code& e, std::size_t bytes_transferred );
-
- void handle_read_data(const boost::system::error_code& e);
- void handle_read_header(const boost::system::error_code& e);
- void reply_back_to_client();
-
- /// Handle completion of a write operation.
- void handle_write( const boost::system::error_code& e );
-
-private:
- /// Socket for the connection.
- boost::asio::ip::tcp::socket socket_;
-
- /// Strand to ensure the connection's handlers are not called concurrently.
- server* server_;
-
- /// The data, typically loaded once, and then sent to many clients
- ClientToServerRequest inbound_request_; /// The incoming request.
- ServerToClientResponse outbound_response_; /// The reply to be sent back to the client.
-
-
- std::string outbound_header_; /// Holds an out-bound header.
- std::string outbound_data_; /// Holds the out-bound data.
- enum { header_length = 8 }; /// The size of a fixed length header.
- char inbound_header_[header_length]; /// Holds an in-bound header.
- std::vector<char> inbound_data_; /// Holds the in-bound data.
-};
-
-typedef boost::shared_ptr<CConnection> CConnection_ptr;
-
-#endif
diff --git a/ecflow_4_0_7/Server/src/CheckPtSaver.cpp b/ecflow_4_0_7/Server/src/CheckPtSaver.cpp
deleted file mode 100644
index b856430..0000000
--- a/ecflow_4_0_7/Server/src/CheckPtSaver.cpp
+++ /dev/null
@@ -1,243 +0,0 @@
-//============================================================================
-// Name : CheckPtSaver.cpp
-// Author : Avi
-// Revision : $Revision: #43 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <fstream>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include "boost/bind.hpp"
-
-#include "CheckPtSaver.hpp"
-#include "Server.hpp"
-#include "ServerEnvironment.hpp"
-#include "Defs.hpp"
-#include "Log.hpp"
-#include "DurationTimer.hpp"
-#include "CtsApi.hpp"
-#include "Str.hpp"
-#include "Ecf.hpp"
-#include "File.hpp"
-
-//#define DEBUG_CHECKPT 1
-//#define DEBUG_CHECKPT_SAVE_ALLOWED 1
-
-#ifdef DEBUG_CHECKPT
-#include <boost/date_time/posix_time/time_formatters.hpp> // requires boost date and time lib, for to_simple_string
-#endif
-
-namespace fs = boost::filesystem;
-using namespace ecf;
-
-
-//-------------------------------------------------------------------------------------
-CheckPtSaver::CheckPtSaver(
- Server* s,
- boost::asio::io_service& io,
- const ServerEnvironment* serverEnv )
-: server_( s ),
- timer_( io, boost::posix_time::seconds( 0 ) ),
- firstTime_(true),
- running_(false),
- serverEnv_(serverEnv),
- state_change_no_(Ecf::state_change_no()),
- modify_change_no_(Ecf::modify_change_no())
-{
-#ifdef DEBUG_CHECKPT
- std::cout << " CheckPtSaver::CheckPtSaver period = " << serverEnv_->checkPtInterval() << "\n";
-#endif
-}
-
-CheckPtSaver::~CheckPtSaver() {
-#ifdef DEBUG_CHECKPT
- std::cout << " ~CheckPtSaver::CheckPtSaver\n";
-#endif
-}
-
-void CheckPtSaver::start()
-{
-#ifdef DEBUG_CHECKPT
- std::cout << " CheckPtSaver::start() check_mode: "
- << serverEnv_->check_mode_str() << " interval = " << serverEnv_->checkPtInterval()
- << " time = " << to_simple_string(boost::posix_time::second_clock::universal_time()) << "\n";
-#endif
-
- // Only save check pt periodically if configuration allows it
- if (serverEnv_->checkMode() != ecf::CheckPt::ON_TIME ) {
-#ifdef DEBUG_CHECKPT
- std::cout << " CheckPtSaver::start() aborted as configuration does not allow it" << std::endl;
-#endif
- return;
- }
-
- running_ = true;
-
- // * important * The time should only be started *ONCE*. Otherwise we will end up with
- // with explicit save each time server is halted/started.
- if (firstTime_) {
- firstTime_ = false;
- timer_.expires_from_now( boost::posix_time::seconds( serverEnv_->checkPtInterval() ) );
-#ifdef ECFLOW_MT
- timer_.async_wait( server_->strand_.wrap( boost::bind( &CheckPtSaver::periodicSaveCheckPt,this,boost::asio::placeholders::error ) ) );
-#else
- timer_.async_wait( server_->io_service_.wrap( boost::bind( &CheckPtSaver::periodicSaveCheckPt,this,boost::asio::placeholders::error ) ) );
-#endif
- }
-}
-
-void CheckPtSaver::stop()
-{ // The server is stopped by cancelling all outstanding asynchronous
- // operations. Once all operations have finished the io_service::run() call
- // will exit.
-#ifdef DEBUG_CHECKPT
- std::cout << " CheckPtSaver::stop() check_mode: " << serverEnv_->check_mode_str() << " interval = " << serverEnv_->checkPtInterval() << "\n";
-#endif
- running_ = false;
-}
-
-void CheckPtSaver::terminate()
-{
- timer_.cancel();
-}
-
-
-void CheckPtSaver::explicitSave(bool from_server) const
-{
- if ( server_->defs_ ) {
-
- try {
-#ifdef DEBUG_CHECKPT
- std::cout << " CheckPtSaver::explicitSave() Saving checkpt file " << serverEnv_->checkPtFilename() << "\n";
-#endif
- // Time how long we take to checkpt, Help to recognise *SLOW* disk, which can *AFFECT* server performance
- DurationTimer durationTimer;
-
- // Backup checkpoint file if it exists & is non zero
- // Avoid an empty file as a backup file, could results from a full file system
- // i.e move ecf_checkpt_file --> ecf_backup_checkpt_file
- fs::path checkPtFile(serverEnv_->checkPtFilename());
- if (fs::exists(checkPtFile) && fs::file_size(checkPtFile) != 0) {
-
- fs::path oldCheckPtFile(serverEnv_->oldCheckPtFilename());
- fs::remove(oldCheckPtFile);
- fs::rename( checkPtFile, oldCheckPtFile );
- }
-
- // write to ecf_checkpt_file, if file system is full this could result in an empty file. ?
- //
- // To optimise check pointing, we minimise system calls, i.e we can write check point as a string,
- // and save string to a file with a single write. This is faster than calling:
- // server_->defs_->save_as_checkpt( serverEnv_->checkPtFilename() );
- // This solution however does require *MORE* memory.
- std::string checkpt_as_string,error_msg;
- server_->defs_->save_checkpt_as_string(checkpt_as_string);
- if (!File::create(serverEnv_->checkPtFilename(),checkpt_as_string,error_msg)) {
- throw std::runtime_error(error_msg);
- }
-
- state_change_no_ = Ecf::state_change_no(); // For periodic update only save checkPt if it has changed
- modify_change_no_ = Ecf::modify_change_no(); // For periodic update only save checkPt if it has changed
-
-
- if (from_server) {
- // Create new time stamp otherwise we end up using the time stamp from the last command
- if (Log::instance()) Log::instance()->cache_time_stamp();
- std::string msg = Str::SVR_CMD(); msg += CtsApi::checkPtDefsArg();
- std::stringstream ss; ss << msg << " in " << durationTimer.duration() << " seconds";
- log(Log::MSG,ss.str());
- }
-
- /// If Save take longer than checkpt_save_time_alarm, then set a flag on server
- /// So that user can be aware of it.
- if (static_cast<size_t>(durationTimer.duration()) > server_->serverEnv_.checkpt_save_time_alarm() ) {
- server_->defs_->flag().set(ecf::Flag::LATE);
- std::stringstream ss;
- ss << "Check pt save time(" << durationTimer.duration() << ") is greater than alarm time("
- << server_->serverEnv_.checkpt_save_time_alarm() << "). Excessive save times can interfere with scheduling!";
- log(Log::WAR,ss.str());
- }
-#ifdef DEBUG_CHECKPT
- std::cout << " backup and save took " << durationTimer.duration() << " seconds\n";
-#endif
- }
- catch (std::exception& e) {
- LOG(Log::ERR,"Could not save checkPoint file! " << e.what() << " File system full?");
- }
- }
- else {
-#ifdef DEBUG_CHECKPT
- std::cout << " CheckPtSaver::explicitSave() Node tree not loaded, can not save check pt file\n";
-#endif
- }
-}
-
-void CheckPtSaver::periodicSaveCheckPt(const boost::system::error_code& error )
-{
-#ifdef DEBUG_CHECKPT
- std::cout << " CheckPtSaver::periodicSaveCheckPt() interval = " << serverEnv_->checkPtInterval() << " time: " << to_simple_string(boost::posix_time::second_clock::universal_time()) << "\n";
-#endif
- if (error == boost::asio::error::operation_aborted) {
-#ifdef DEBUG_CHECKPT
- std::cout << " CheckPtSaver::periodicSaveCheckPt : boost::asio::error::operation_aborted : time cancelled: Node running(" << running_ << ") interval = " << serverEnv_->checkPtInterval() << "\n";
-#endif
- return;
- }
- else if (error) {
- LogToCout toCoutAsWell;
- LOG(Log::ERR, "CheckPtSaver::periodicSaveCheckPt " << error.message());
- return;
- }
-
- if (running_) {
- // state changed
- if (state_change_no_ != Ecf::state_change_no() || modify_change_no_ != Ecf::modify_change_no()) {
- doSave();
- }
- }
-
- /// Appears that expires_from_now is more accurate then expires_at
- timer_.expires_from_now( boost::posix_time::seconds( serverEnv_->checkPtInterval() ) );
-#ifdef ECFLOW_MT
- timer_.async_wait( server_->strand_.wrap( boost::bind( &CheckPtSaver::periodicSaveCheckPt,this,boost::asio::placeholders::error ) ) );
-#else
- timer_.async_wait( server_->io_service_.wrap( boost::bind( &CheckPtSaver::periodicSaveCheckPt,this,boost::asio::placeholders::error ) ) );
-#endif
-}
-
-
-void CheckPtSaver::doSave() const
-{
-#ifdef DEBUG_CHECKPT
- std::cout << " CheckPtSaver::doSave()\n";
-#endif
- // Check to see if configuration allows save
- if (serverEnv_->checkMode() == ecf::CheckPt::NEVER ) {
-#ifdef DEBUG_CHECKPT
- std::cout << " CheckPtSaver::doSave() configuration does not allow save \n";
-#endif
- return;
- }
- explicitSave(true/* from the server, hence log */);
-}
-
-void CheckPtSaver::saveIfAllowed()
-{
- // Call on each state change. Hence will get many times
-#ifdef DEBUG_CHECKPT_SAVE_ALLOWED
- std::cout << " CheckPtSaver::saveIfAllowed()\n";
-#endif
-
- // Check to see if configuration allows immediate save.
- if (serverEnv_->checkMode() == ecf::CheckPt::ALWAYS ) {
- doSave();
- }
-}
diff --git a/ecflow_4_0_7/Server/src/CheckPtSaver.hpp b/ecflow_4_0_7/Server/src/CheckPtSaver.hpp
deleted file mode 100644
index fa2b42d..0000000
--- a/ecflow_4_0_7/Server/src/CheckPtSaver.hpp
+++ /dev/null
@@ -1,86 +0,0 @@
-#ifndef CHECKPTSAVER_HPP_
-#define CHECKPTSAVER_HPP_
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name : CheckPtSaver.cpp
-// Author : Avi
-// Revision : $Revision: #14 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//
-// This class will save the defs file periodically. The period is obtained from
-// ServerEnvironment. The save of the check point file is controlled by
-// the settings in ServerEnvironment
-//
-// The checkpoint files is the defs file, with state. However its saved in
-// boost serialisation format(i.e can be text,binary,portable binary)
-//
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <boost/noncopyable.hpp>
-#include <boost/asio.hpp>
-
-class ServerEnvironment;
-class Server;
-
-class CheckPtSaver : private boost::noncopyable {
-public:
- CheckPtSaver( Server* s, boost::asio::io_service& io, const ServerEnvironment*);
- ~CheckPtSaver();
-
- /// Start periodical save of the checkpoint file
- void start();
-
- /// Stop periodical save of the checkPoint file
- void stop();
-
- /// terminate: This will cancel the timer and any pending async operation
- /// If timer has already expired, then the handler function will be
- /// passed an operation aborted error code.
- /// Called when the server is exiting. We must be sure to cancel all
- /// async handlers or the server, will not stop.
- void terminate();
-
- /// Will always save the check pt file. Independent of any server environment
- /// The input argument is used in logging. When check pointing via user command
- /// we log the request. However we also check point automatically via the server
- /// This allows us to distinguish the two cases in the log file:
- void explicitSave(bool from_server = false) const;
-
- /// This function is called after node state changes. Check for save
- /// CheckPt::ON_TIME - will do nothing since we will save periodically
- /// CheckPt::NEVER - will return immediately
- /// CheckPt::ALWAYS - will save immediately, may cause performance issues with large Node trees
- void saveIfAllowed();
-
-private:
- /// save the node tree in the server to a checkPt file.
- /// this is controlled by the configuration. If the configuration does not
- /// allow a save, does nothing
- void doSave() const;
-
- /// Called periodically to save checkPoint file
- /// We use error parameter, since when we cancel the timer via, terminate
- /// we do NOT want to do an explicit save *PLUS* we want to return without
- /// starting another async operation. Otherwise the server will not return
- ///
- /// This will call doSave() but *ONLY* if there has been a state change
- /// This avoids writing out a checkpt file, unnecessarily & filling up log file
- void periodicSaveCheckPt(const boost::system::error_code& error);
-
- Server* server_;
- boost::asio::deadline_timer timer_;
- bool firstTime_;
- bool running_;
- const ServerEnvironment* serverEnv_;
- mutable unsigned int state_change_no_; // detect state change in defs
- mutable unsigned int modify_change_no_; // detect state change in defs
-};
-#endif
diff --git a/ecflow_4_0_7/Server/src/NodeTreeTraverser.cpp b/ecflow_4_0_7/Server/src/NodeTreeTraverser.cpp
deleted file mode 100644
index 7f13631..0000000
--- a/ecflow_4_0_7/Server/src/NodeTreeTraverser.cpp
+++ /dev/null
@@ -1,396 +0,0 @@
-//============================================================================
-// Name : NodeTreeTraverser.cpp
-// Author : Avi
-// Revision : $Revision: #101 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <iostream>
-#include "boost/bind.hpp"
-
-#include "ServerEnvironment.hpp"
-#include "NodeTreeTraverser.hpp"
-#include "Server.hpp"
-#include "Defs.hpp"
-#include "JobsParam.hpp"
-#include "Jobs.hpp"
-#include "Log.hpp"
-#include "CalendarUpdateParams.hpp"
-#include "Calendar.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost::posix_time;
-
-//#define DEBUG_TRAVERSER 1
-//#define DEBUG_POLL 1
-
-// ***********************************************************************
-// It was noticed that having a poll of 60 seconds was not very accurate
-// even when the server was not active, could be out by as much as 25 seconds
-// Hence we poll every second, and check it against the minute boundary
-// ************************************************************************
-
-NodeTreeTraverser::NodeTreeTraverser( Server* s,
- boost::asio::io_service& io,
- const ServerEnvironment& serverEnv)
-: server_( s ),
- serverEnv_(serverEnv),
- timer_( io, boost::posix_time::seconds( 0 ) ),
- interval_(0,0,serverEnv_.submitJobsInterval(),0),
- count_( 0 ),
- firstTime_( true),
- running_(false)
-{
-#ifdef DEBUG_TRAVERSER
- std::cout << "NodeTreeTraverser::NodeTreeTraverser period = " << serverEnv_.submitJobsInterval() << "\n";
-#endif
-}
-
-NodeTreeTraverser::~NodeTreeTraverser() {
-#ifdef DEBUG_TRAVERSER
- std::cout << "~NodeTreeTraverser::NodeTreeTraverser\n";
-#endif
-}
-
-void NodeTreeTraverser::start()
-{
-#ifdef DEBUG_TRAVERSER
- {LogToCout toCoutAsWell;LOG(Log::DBG, "NodeTreeTraverser::start() server_state(" << SState::to_string(server_->state()) << ") running(" << running_ << ") count(" << count_ << ") firstTime_(" << firstTime_ << ")" );}
-#endif
-
- if (!running_) {
- count_ = 0;
- running_ = true;
- if (firstTime_) {
- // If the server is stopped/started we want to avoid skewing the calendar, since each time
- // we call traverse, the calendar is updated with the server poll. hence we must make sure
- // we only start it once here
- last_time_ = Calendar::second_clock_time();
- next_poll_time_ = last_time_;
- firstTime_ = false;
-
- /// ==========================================================================
- /// Make sure we *ALIGN* the poll period exactly *** to the minute*** boundary
- /// ==========================================================================
- if ( 60 == serverEnv_.submitJobsInterval() ) {
-
- time_duration time_of_day = last_time_.time_of_day();
- int seconds_to_minute_boundary = 60 - time_of_day.seconds();
-
-#ifdef DEBUG_TRAVERSER
- std::cout << " NodeTreeTraverser::start: time_of_day(" << to_simple_string(time_of_day) << ") seconds_to_minute_boundary(" << seconds_to_minute_boundary << ")\n";
-#endif
-
- if ( seconds_to_minute_boundary != 0) {
-
-#ifdef DEBUG_TRAVERSER
- std::cout << " NodeTreeTraverser::start: Do an immediate job generation. Since we don't want to wait for minute boundary, when starting.\n";
-#endif
-
- // Make sure subsequent polls are *ALIGNED* to minute boundary
- next_poll_time_ = last_time_ + seconds(seconds_to_minute_boundary);
-
- // ************************************************************************************************
- // ** This relies on next_poll_time_ being set first, to ensure job generation does not take longer
- // ************************************************************************************************
- update_suite_calendar_and_traverse_node_tree(last_time_);
-
- timer_.expires_from_now( boost::posix_time::seconds( 1 ) );
-
-#ifdef DEBUG_TRAVERSER
- std::cout << " NodeTreeTraverser::start: next_poll_time_(" << to_simple_string(next_poll_time_) << ")\n";
-#endif
- }
- }
-#ifdef ECFLOW_MT
- timer_.async_wait( server_->strand_.wrap( boost::bind( &NodeTreeTraverser::traverse, this, boost::asio::placeholders::error ) ) );
-#else
- timer_.async_wait( server_->io_service_.wrap( boost::bind( &NodeTreeTraverser::traverse, this, boost::asio::placeholders::error ) ) );
-#endif
- }
- }
-}
-
-void NodeTreeTraverser::stop()
-{
-#ifdef DEBUG_TRAVERSER
- {LogToCout toCoutAsWell; LOG(Log::DBG, " NodeTreeTraverser::stop() count(" << count_ << ")");}
-#endif
-
- running_ = false;
-}
-
-void NodeTreeTraverser::terminate()
-{
-#ifdef DEBUG_TRAVERSER
- {LogToCout toCoutAsWell; LOG(Log::DBG, " NodeTreeTraverser::terminate() count(" << count_ << ")");}
-#endif
-
- timer_.cancel();
-}
-
-void NodeTreeTraverser::do_traverse()
-{
- // since we poll every second, if less than next poll(every 60 seconds) continue.
- ptime time_now = Calendar::second_clock_time();
- if (time_now < next_poll_time_) {
-
- // minimise the number of node tree traversal, to once every second, but only *IF* required
- // Note: if we are a few seconds to the poll time, but job generation takes a while
- // we can get warning about the interval took to long. See below:
-
- // LOG(Log::DBG,"get_job_generation_count() = " << server_->get_job_generation_count());
- if (server_->get_job_generation_count() > 0) {
- traverse_node_tree_and_job_generate( time_now , false /* not in command context */);
- }
-
- start_timer(); // timer fires *EVERY* second
- return;
- }
- // time_now >= next_poll_time_
-
-
- // We have SOFT real time, we poll every second, BUT only update the suite calendar at the job submission
- // interval. However we can not guarantee to hit exactly at the next poll time
- // *** traverse node tree and increment next_poll_time_ ***
- time_duration duration = time_now - last_time_;
- int diff_from_last_time = duration.total_seconds();
- int submitJobsIntervalInSeconds = serverEnv_.submitJobsInterval();
-#ifdef DEBUG_TRAVERSER
- int real_diff = diff_from_last_time - submitJobsIntervalInSeconds;
- std::stringstream ss;
- ss << " NodeTreeTraverser::traverse() diff_from_last_time:" << diff_from_last_time << " running:" << running_ << " count:" << count_ << " real_diff:" << real_diff << " time_now:" << to_simple_string(time_now);
- if ( diff_from_last_time == 0) ss << ": FIRST time: ";
-#endif
-
- /// Update server stat's. ie records number of requests for each poll period
- server_->update_stats(diff_from_last_time);
-
- /// The poll times will *vary* since we are trying to keep up with the hard real time.
- if ( diff_from_last_time > submitJobsIntervalInSeconds ) {
-
- /// This will happen from time to time, hence only report, for real wayward times
- int diff = diff_from_last_time - submitJobsIntervalInSeconds;
- if (diff > (submitJobsIntervalInSeconds * 0.25)) {
- LOG(Log::WAR, ": interval is (" << submitJobsIntervalInSeconds << " seconds) but took (" << diff_from_last_time << " seconds)" );
- }
- }
-
-
-
- /// Remove any stale zombies
- server_->zombie_ctrl().remove_stale_zombies(time_now);
-
-#ifdef DEBUG_TRAVERSER
- time_duration traverse_duration = Calendar::second_clock_time() - time_now;
- ss << " Traverse duration:" << traverse_duration.total_seconds();
-#endif
-
-
- // We poll *EVERY second but update the next_poll_time_ to be consistent with the job submission interval
- // Hence the next poll times *will* vary( SOFT REAL TIME ).
- // Note: On server start, we modified the next_poll_time_ to hit the minute boundary.
- //
- // FIRST time_now(skip) time_now(traverse node tree)
- // | | L | S
- // V V------------------------| V-----------------|
- // ==========0====================0====================0====================0====================0
- // ^ ^ ^ ^ ^
- // | | | | |
- // last_time_ next_poll_time_ next_poll_time_ next_poll_time_ next_poll_time_
- // next_poll_time_
- // ^ ^
- // | |
- // last_time_ last_time_
- // reset to previous next_poll_time_, to avoid yo-yoing, messages about poll being long/short
- //
- // Update next_poll_time_: WE *ONLY* get here if time_now >= next_poll_time
-
- if (time_now > next_poll_time_) {
-
- /// Continue updating next_poll_time_ by interval_ until it is greater time_now
-#ifdef DEBUG_TRAVERSER
- { ss << ": Shorten the poll time : Current time(" << to_simple_string(time_now) << ") > current poll_time(" << to_simple_string(next_poll_time_) << ")";
- time_duration diff = time_now - next_poll_time_;
- ss << " by " << diff.total_seconds() << " seconds: "; }
-#endif
-
- while (next_poll_time_ <= time_now) { next_poll_time_ += interval_;}
- }
- else {
-
- /// Hit the poll time: Should get here when traverse called for the *FIRST* time ( since time_now == next_poll_time_)
-#ifdef DEBUG_TRAVERSER
- ss << ": On poll time: ";
-#endif
-
- next_poll_time_ += interval_;
- }
-
- // At begin time for very large suites, slow disk, and in test, during job generation we can miss the next poll time(i.e a,b)
- // This means that on the next poll time because last_time was not updated, to be immediately
- // behind the next poll time by 'interval_' seconds an erroneous report is logged about missing the poll time
- //
- // FIRST Time_now
- // | |
- // V a b c X
- // ==========0====================0====================0====================0====================0
- // ^ ^ ^ ^ ^
- // | | | | |
- // last_time_ next_poll_time_ next_poll_time_ next_poll_time_ next_poll_time_
- //
- // Hence we need to ensure that last_time is always less that next_poll_time_ by interval_
- // In the diagram above missed poll time a and b, then we need to set last_time_ to 'c' and *NOT* 'a' | 'b'
- last_time_ = next_poll_time_ - interval_;
-
-
-#ifdef DEBUG_TRAVERSER
- { ss << " Next Poll at:" << to_simple_string(next_poll_time_);LogToCout toCoutAsWell; LOG(Log::DBG,ss.str()); }
-#endif
-
-
- // Start node tree traversal.
- // ************************************************************************************************
- // ** This relies on next_poll_time_ being set first, to ensure job generation does not take longer
- // ************************************************************************************************
- update_suite_calendar_and_traverse_node_tree(time_now);
-
- start_timer(); // timer fires *EVERY* second
-}
-
-void NodeTreeTraverser::start_timer()
-{
- /// Appears that expires_from_now is more accurate then expires_at i.e timer_.expires_at( timer_.expires_at() + boost::posix_time::seconds( poll_at ) );
- timer_.expires_from_now( boost::posix_time::seconds( 1 ) );
-#ifdef ECFLOW_MT
- timer_.async_wait( server_->strand_.wrap( boost::bind( &NodeTreeTraverser::traverse,this,boost::asio::placeholders::error ) ) );
-#else
- timer_.async_wait( server_->io_service_.wrap( boost::bind( &NodeTreeTraverser::traverse,this,boost::asio::placeholders::error ) ) );
-#endif
-}
-
-void NodeTreeTraverser::traverse(const boost::system::error_code& error )
-{
- if (error == boost::asio::error::operation_aborted) {
-#ifdef DEBUG_TRAVERSER
- { LogToCout toCoutAsWell; LOG(Log::DBG, "NodeTreeTraverser::traverse Timer was cancelled" ); }
-#endif
- return;
- }
- else if (error) {
- LogToCout toCoutAsWell;
- std::string msg = "NodeTreeTraverser::traverse error: "; msg += error.message();
- ecf::log(Log::ERR, msg);
- return;
- }
-
- do_traverse();
-}
-
-
-void NodeTreeTraverser::update_suite_calendar_and_traverse_node_tree(const boost::posix_time::ptime& time_now)
-{
- // *****************************************************************************
- // JOB SUBMISSION SEEMS TO WORK BEST IF THE CALENDAR INCREMENT HAPPENS FIRST
- // HOWEVER THIS MEANS WE MAY MISS THE VERY FIRST JOB SUBMISSION. ??
- // Note: events,meters and task completion kick of another job submission
- // There seems to be greater stability in terms of testing as it allows
- // process to complete, before the calendar is incremented.
- // *****************************************************************************
- if ( server_->defs_ ) {
-
- // This functions gets called every 60 seconds or so, update calendar && time
- // dependent variables in case any jobs depend on them. By default the calendar
- // update interval is the same as submitJobsInterval for non-real calendars,
- // however for testing both real/non-real calendars the calendar increment can be
- // changed to speed up calendar. This is done by setting the calendar increment
- // on the suite(i.e in the defs file) which will the _override_ this setting.
- //
- // Additionally by passing in the flag running_, it allow suites which want to
- // stop the calendar updates, when the server is stopped to do so.
- // For real time calendars we make one system call here, instead of many times in each suite
- //
- // In the case where defs/node tree is suspended updateCalendar will continue
- // to mark those time dep' are free, as free. This information is then used
- // during the resume
- ++count_;
- CalendarUpdateParams calParams(time_now, interval_/* calendar increment */, running_ );
- server_->defs_->updateCalendar( calParams );
-
- traverse_node_tree_and_job_generate(time_now, false /* not in command context */);
- }
-}
-
-void NodeTreeTraverser::traverse_node_tree_and_job_generate(
- const boost::posix_time::ptime& start_time,
- bool user_cmd_context) const
-{
- // **************************************************************************************
- // This can be called at the end of a user command(force,alter,requeue,etc),
- // hence start_time may be >= poll_time, Note: for child command we just call
- // increment_job_generation_count()
- // **************************************************************************************
-
- if ( running_ && server_->defs_) {
-#ifdef DEBUG_JOB_SUBMISSION
- jobsParam.logDebugMessage(" from NodeTreeTraverser::traverse_node_tree_and_job_generate()");
-#endif
-
- // ** In the *NON* command context, we should always have start_time < next_poll_time_
- if (user_cmd_context && start_time >= next_poll_time_) {
-
- //cout << "*****************************************************************************************************\n";
- //cout << "user Command context " << cmd_context << " start_time: " << start_time << " >= " << " next_poll_time_: " << next_poll_time_ << "\n";
- //cout << "*****************************************************************************************************\n";
-
- server_->increment_job_generation_count();
- return;
- }
-
- server_->reset_job_generation_count();
-
- // Pass submit jobs interval, so that we can check jobs submission occurs within the allocated time.
- // By default job generation is enabled, however for testing, allow job generation to be disabled.
- JobsParam jobsParam(serverEnv_.submitJobsInterval(), serverEnv_.jobGeneration());
-
- // If job generation takes longer than the time to *reach* next_poll_time_, then time out.
- // Hence we start out with 60 seconds, and time for job generation should decrease. Until reset back to 60
- // Should allow greater child communication.
- // By setting set_next_poll_time, we enable timeout of job generation.
- // ** IMPLIES => next_poll_time_ must be set first, before *THIS* function is called **
- // Note: There are other place where we may not want to timeout job generation.
- jobsParam.set_next_poll_time(next_poll_time_);
-
- Jobs jobs(server_->defs_);
- if (!jobs.generate(jobsParam)) { ecf::log(Log::ERR, jobsParam.getErrorMsg()); }
- if (jobsParam.timed_out_of_job_generation()) {
-
- // Implies we timed out, hence time_out_time >= next_poll_time_
- const ptime& time_out_time = jobsParam.time_out_time();
- // std::cout << "Job generation *timed* out: start time:" << start_time << " time_out_time:" << time_out_time << " poll_time:" << next_poll_time_ << "\n";
-
- // It could be that we started job generation a few seconds before the poll time,
- // Hence to avoid excessive warnings, Only warn if time_out_time > next_poll_time_ and forgive about 3 seconds
- if (!time_out_time.is_special() && time_out_time > next_poll_time_ ) {
- int leeway = ( serverEnv_.submitJobsInterval() == 60) ? 3 : 1;
- time_duration duration = time_out_time - next_poll_time_;
- if ( duration.total_seconds() >= leeway) {
-
- std::stringstream ss;
- ss << "Job generation *timed* out: start time:" << start_time << " time_out_time:" << time_out_time << " poll_time:" << next_poll_time_;
- ecf::log(Log::WAR,ss.str());
- }
- }
- }
- }
-}
-
diff --git a/ecflow_4_0_7/Server/src/NodeTreeTraverser.hpp b/ecflow_4_0_7/Server/src/NodeTreeTraverser.hpp
deleted file mode 100644
index 81dd277..0000000
--- a/ecflow_4_0_7/Server/src/NodeTreeTraverser.hpp
+++ /dev/null
@@ -1,86 +0,0 @@
-#ifndef NODETREETRAVERSER_HPP_
-#define NODETREETRAVERSER_HPP_
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name : NodeTreeTraverser.cpp
-// Author : Avi
-// Revision : $Revision: #26 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-// This class will traverse the node tree periodically, It is tied to a server.
-// This implementation uses a strand to ensure sequential processing of the node dependency traversal
-// in the the presence of multiple threads, without the need of explicit locking. i.e mutex's
-//
-// For testing we make the distinction between the poll period, and calendar update interval
-// Some suites require a real time calendar. Hence we must make sure that
-// poll interval is in sync with real time.
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <boost/asio.hpp>
-#include <boost/noncopyable.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-class Server;
-class ServerEnvironment;
-
-class NodeTreeTraverser : private boost::noncopyable {
-public:
- NodeTreeTraverser( Server* s, boost::asio::io_service& io, const ServerEnvironment& serverEnv);
- ~NodeTreeTraverser();
-
- /// If first time Starts traversing Node tree and resolving dependencies.
- /// This essentially starts Jobs scheduling. Calling start more than once does nothing.
- /// On subsequent calls to start resume is called. Which may cause immediate
- /// job generation. (i.e for those nodes whose node are free of time dependencies)
- /// Timer will be aligned to the minute boundary
- void start();
-
- /// Suspends job scheduling (for real time calendars/suite)
- /// Shutdown & suspend (are very similar) shutdown operate at the top/level.
- /// Both should have effect of stopping job submission and not the event loop
- ///
- /// During a system session, a node can be placed into suspend mode.
- /// In suspend mode, no jobs are submitted. (**** However node which are
- /// free to run are marked****).
- ///
- /// When the session is resumed, those node than were marked, have
- /// the task's submitted. ( This means that job dependent on a time dependency
- /// does not need to be held for the following day)
- void stop();
-
- /// terminate: This will cancel the timer and any pending async operation
- /// If timer has already expired, then the handler function will be
- /// passed an operation aborted error code.
- /// Called when the server is exiting. We must be sure to cancel all
- /// async handlers or the server, will not stop.
- void terminate();
-
- /// This can be called at the end of a *USER* command(force,alter,requeue,etc), hence time_now may be >= poll_time
- /// If this is the case, we will defer job generation
- void traverse_node_tree_and_job_generate(const boost::posix_time::ptime& time_now, bool user_cmd_context) const;
-
-private:
- void traverse(const boost::system::error_code& error );
- void do_traverse();
- void start_timer();
- void update_suite_calendar_and_traverse_node_tree(const boost::posix_time::ptime& time_now);
-
- Server* server_;
- const ServerEnvironment& serverEnv_;
- boost::asio::deadline_timer timer_;
- boost::posix_time::ptime last_time_; // ensure poll is in sync
- boost::posix_time::ptime next_poll_time_; // Keep as sync as possible with hard real times
- boost::posix_time::time_duration interval_; // Job submission interval
- int count_;
- bool firstTime_;
- bool running_;
-};
-
-#endif
diff --git a/ecflow_4_0_7/Server/src/Server.cpp b/ecflow_4_0_7/Server/src/Server.cpp
deleted file mode 100644
index d81a693..0000000
--- a/ecflow_4_0_7/Server/src/Server.cpp
+++ /dev/null
@@ -1,716 +0,0 @@
-//============================================================================
-// Name : Server.cpp
-// Author : Avi
-// Revision : $Revision: #173 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Server
-//
-// The port numbers are divided into three ranges:
-// o the Well Known Ports, (require root permission) 0 -1023
-// o the Registered Ports, 1024-49151
-// o Dynamic and/or Private Ports. 49151-65535
-//============================================================================
-
-#include <boost/date_time/posix_time/posix_time.hpp>
-#include <boost/filesystem/operations.hpp>
-#include <boost/filesystem/path.hpp>
-#include <boost/bind.hpp>
-#include <iostream>
-
-#include "Server.hpp" // Must come before boost/serialization headers.
- // defines ECFLOW_MT
-#include <boost/thread/thread.hpp> // needed for ECFLOW_MT and debug() to print thread ID
-#include "Defs.hpp"
-#include "Log.hpp"
-#include "System.hpp"
-#include "ServerEnvironment.hpp"
-#include "Ecf.hpp"
-#include "Calendar.hpp"
-#include "Version.hpp"
-#include "Str.hpp"
-
-using boost::asio::ip::tcp;
-namespace fs = boost::filesystem;
-
-using namespace std;
-using namespace ecf;
-
-
-/// Constructor opens the acceptor and starts waiting for the first incoming connection.
-Server::Server( ServerEnvironment& serverEnv ) :
- io_service_(),
- signals_(io_service_),
- acceptor_(io_service_),
-#ifdef ECFLOW_MT
- strand_(io_service_),
- thread_pool_size_(serverEnv.threads()),
- new_connection_(),
-#endif
- defs_(Defs::create()), // ECFLOW-182
- traverser_ (this, io_service_, serverEnv ),
- checkPtSaver_(this, io_service_, &serverEnv ),
- serverState_(SState::HALTED),
- serverEnv_(serverEnv)
-{
-#ifdef ECFLOW_MT
- std::cout << "Server: thread pool size = " << thread_pool_size_ << endl;
-#endif
-
- if (serverEnv_.debug()) cout << "-->Server::server starting server on port "
- << serverEnv.port()
-#ifdef ECFLOW_MT
- << " thread pool size = " << thread_pool_size_
-#endif
- << endl;
-
- // Register to handle the signals.
- // Support for emergency check pointing during system session.
- signals_.add(SIGTERM);
- signals_.async_wait(boost::bind(&Server::sigterm_signal_handler, this));
-
-
- // Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR).
- boost::asio::ip::tcp::endpoint endpoint(serverEnv.tcp_protocol(), serverEnv.port());
- acceptor_.open(endpoint.protocol());
- acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
- acceptor_.bind(endpoint);
- acceptor_.listen(); // address is use error, when it comes, bombs out here
-
-
- // Update stats, this is returned via --stats command option
- stats().host_ = serverEnv.hostPort().first;
- stats().port_ = serverEnv.hostPort().second;
- stats().job_sub_interval_ = serverEnv.submitJobsInterval();
- stats().checkpt_interval_ = serverEnv.checkPtInterval();
- stats().checkpt_save_time_alarm_ = serverEnv.checkpt_save_time_alarm();
- stats().checkpt_mode_ = serverEnv.checkMode();
- stats().up_since_ = to_simple_string(Calendar::second_clock_time());
- stats().version_ = Version::description();
- stats().status_ = static_cast<int>(serverState_);
- stats().ECF_HOME_ = serverEnv.ecf_home();
- stats().ECF_CHECK_ = serverEnv.checkPtFilename();
- stats().ECF_LOG_ = Log::instance()->path();
-
- // Update log file:
- ecf::log(Log::MSG, "Server initial state is HALTED");
-
- // The defs_ *MUST* be updated with the server state
- // When we load from the check pt file we call update_defs_server_state();
- if (!load_check_pt_file_on_startup()) {
-
- // No check pt files loaded, update defs, with server state
- update_defs_server_state(); // works on def_
- }
-
- /// Setup globals used to detect incremental changes to the definition
- Ecf::set_server(true);
-
- // Start an accept operation for a new connection.
- start_accept();
-}
-
-Server::~Server()
-{
- if (serverEnv_.debug()) cout << "<--Server::~server exiting server on port " << serverEnv_.port() << endl;
-
- defs_.reset();
-
-#ifdef DEBUG
- if ( defs_.use_count() != 0) {
- cout << "Server::~server() defs_.use_count() = " << defs_.use_count() << " something is still hold onto the defs, asserting\n";
- }
-#endif
- assert(defs_.use_count() == 0);
-}
-
-void Server::run()
-{
- // The io_service::run() call will block until all asynchronous operations
- // have finished. While the server is running, there is always at least one
- // asynchronous operation outstanding: the asynchronous accept call waiting
- // for new incoming connections.
-
-#ifdef ECFLOW_MT
- // Create a pool of threads to run all of the io_services.
- std::vector<boost::shared_ptr<boost::thread> > threads;
- for (std::size_t i = 0; i < thread_pool_size_; ++i)
- {
- boost::shared_ptr<boost::thread> thread(new boost::thread(
- boost::bind(&boost::asio::io_service::run, &io_service_)));
- threads.push_back(thread);
- }
- // Wait for all threads in the pool to exit.
- for (std::size_t i = 0; i < threads.size(); ++i)
- threads[i]->join();
-#else
- io_service_.run();
-#endif
-}
-
-void Server::start_accept()
-{
-#ifdef ECFLOW_MT
- if (serverEnv_.debug()) cout << boost::this_thread::get_id() << " Server::start_accept()" << endl;
- new_connection_.reset(new CConnection(io_service_, this));
- acceptor_.async_accept(new_connection_->socket(),
- boost::bind(&Server::handle_accept, this,
- boost::asio::placeholders::error));
-#else
- if (serverEnv_.debug()) cout << " Server::start_accept()" << endl;
- connection_ptr new_conn( new connection( io_service_ ) );
- if (serverEnv_.allow_old_client_new_server() !=0 ) {
- new_conn->allow_old_client_new_server(serverEnv_.allow_old_client_new_server());
- }
- acceptor_.async_accept( new_conn->socket(),
- boost::bind( &Server::handle_accept, this,
- boost::asio::placeholders::error,
- new_conn ) );
-#endif
-}
-
-#ifdef ECFLOW_MT
-void Server::handle_accept(const boost::system::error_code& e)
-{
- // Check whether the server was stopped by a signal before this completion
- // handler had a chance to run.
- if (!acceptor_.is_open()) {
- if (serverEnv_.debug()) cout << boost::this_thread::get_id() << " Server::handle_accept: acceptor is closed, returning\n";
- return;
- }
-
- if (!e) {
- new_connection_->start();
- }
- else {
- LogToCout toCoutAsWell;
- LOG(Log::ERR, "Server::handle_accept error occurred : " << e.message());
- }
-
- start_accept();
-}
-#else
-void Server::handle_accept( const boost::system::error_code& e, connection_ptr conn )
-{
- // Check whether the server was stopped by a signal before this completion
- // handler had a chance to run.
- if (!acceptor_.is_open()) {
- if (serverEnv_.debug()) cout << " Server::handle_accept: acceptor is closed, returning" << endl;
- return;
- }
-
- if ( !e ) {
- // Read and interpret message from the client
- if (serverEnv_.debug()) cout << " Server::handle_accept" << endl;
-
- // Successfully accepted a new connection. Determine what the
- // client sent to us. The connection::async_read() function will
- // automatically. serialise the inbound_request_ data structure for us.
- conn->async_read( inbound_request_,
- boost::bind( &Server::handle_read, this,
- boost::asio::placeholders::error,conn ) );
- }
- else {
- if (serverEnv_.debug()) cout << " Server::handle_accept " << e.message() << endl;
- if (e != boost::asio::error::operation_aborted) {
- // An error occurred. Log it
- LogToCout toCoutAsWell;
- LOG(Log::ERR, " Server::handle_accept error occurred " << e.message());
- }
- }
-
- // Start an accept operation for a new connection.
- // *NOTE* previously we had *ONLY* called this if there was no errors
- // However this would means that server would run out work.
- // When there were errors.!
- // Moved here to follow the examples used in ASIO.
- // However can this get into an infinite loop ???
- start_accept();
-}
-
-void Server::handle_read( const boost::system::error_code& e,connection_ptr conn )
-{
- /// Handle completion of a write operation.
- // **********************************************************************************
- // This function *must* finish with write, otherwise it ends up being called recursively
- // ***********************************************************************************
- if ( !e ) {
-
- // See what kind of message we got from the client
- if (serverEnv_.debug()) std::cout << " Server::handle_read : client request " << inbound_request_ << endl;
-
- try {
- // Service the in bound request, handling the request will populate the outbound_response_
- // Note:: Handle request will first authenticate
- outbound_response_.set_cmd( inbound_request_.handleRequest( this ) );
- }
- catch (exception& e) {
- outbound_response_.set_cmd( PreAllocatedReply::error_cmd( e.what() ));
- }
-
- // Release >= 4.0.6 More reliable to always respond back. Get more accurate logs
- // However allow old/new client to deal with shutdown of socket:
- // See: void Client::handle_read() See: ECFLOW-157, ECFLOW-169
- //
- // if (!serverEnv_.reply_back_if_ok()) {
- //
- // if (!inbound_request_.terminateRequest() && outbound_response_.get_cmd()->isOkCmd()) {
- //
- // // cleanly close down the connection
- // if (serverEnv_.debug()) cout << " Server::handle_read: NOT replying, since request is OK" << endl;
- //
- // if (shutdown_socket(conn,"Server::handle_read:")) conn->socket().close();
- // return;
- // }
- // }
-
- // *Reply* back to the client:
- conn->async_write( outbound_response_,
- boost::bind(&Server::handle_write,
- this,
- boost::asio::placeholders::error,
- conn ) );
- }
- else {
- // An error occurred.
- // o/ If client has been killed/disconnected/timed out
- // Server::handle_read : End of file
- //
- // o/ If a *new* client talks to an *old* server, with an unrecognised request/command
- // we will see:
- // Connection::handle_read_data boost::archive::archive_exception unregistered class
- // Server::handle_read : Invalid argument
- LogToCout toCoutAsWell;
- LOG(Log::ERR, "Server::handle_read: " << e.message());
- }
-}
-
-void Server::handle_write( const boost::system::error_code& e, connection_ptr conn )
-{
- // Handle completion of a write operation.
- // Nothing to do. The socket will be closed automatically when the last
- // reference to the connection object goes away.
- if (serverEnv_.debug())
- cout << " Server::handle_write: client request " << inbound_request_ << " replying with " << outbound_response_ << endl;
-
- if (e) {
- ecf::LogToCout logToCout;
- std::stringstream ss; ss << "Server::handle_write: " << e.message() << " : for request " << inbound_request_;
- log(Log::ERR,ss.str());
- return;
- }
-
- (void)shutdown_socket(conn,"Server::handle_write:");
-
- // If asked to terminate we do it here rather than in handle_read.
- // So that we have responded to the client.
- // *HOWEVER* only do this if the request was successful.
- // we do this by checking that the out bound response was ok
- // i.e a read only user should not be allowed to terminate server.
- if (inbound_request_.terminateRequest() && outbound_response_.get_cmd()->isOkCmd()) {
- if (serverEnv_.debug()) cout << " <--Server::handle_write exiting server via terminate() port " << serverEnv_.port() << endl;
- terminate();
- }
-}
-
-bool Server::shutdown_socket(connection_ptr conn, const std::string& msg) const
-{
- // For portable behaviour with respect to graceful closure of a connected socket,
- // call shutdown() before closing the socket.
- //
- // conn->socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both)
- // This *CAN* throw an error if the client side socket is not connected. client may have been killed *OR* timed out
- // i.e "shutdown: Transport endpoint is not connected"
- //
- // Since this can happen, instead of throwing, we use non-throwing version & just report it
- boost::system::error_code ec;
- conn->socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both,ec);
- if (ec) {
- ecf::LogToCout logToCout;
- std::stringstream ss; ss << msg << " socket shutdown both failed: " << ec.message() << " : for request " << inbound_request_;
- log(Log::ERR,ss.str());
- return false;
- }
- return true;
-}
-
-#endif
-
-
-void Server::terminate()
-{
- // The server is terminated by cancelling all outstanding asynchronous
- // operations. Once all operations have finished the io_service::run() call will exit.
- if (serverEnv_.debug()) cout << " Server::terminate(): posting call to Server::handle_terminate" << endl;
-
- // Post a call to the stop function so that Server::stop() is safe to call from any thread.
- io_service_.post(boost::bind(&Server::handle_terminate, this));
-}
-
-void Server::handle_terminate()
-{
- if (serverEnv_.debug()) cout << boost::this_thread::get_id() << " Server::handle_terminate() : cancelling checkpt and traverser timers, and signals" << endl;
-
- // Cancel signal
- signals_.clear();
- signals_.cancel();
-
- // Cancel async timers for check pointing and traversal
- traverser_.terminate();
- checkPtSaver_.terminate();
-
- acceptor_.close();
-
- // Stop the io_service object's event processing loop. Will cause run to return immediately
- io_service_.stop();
-}
-
-// ============================== other privates ===========================================
-
-bool Server::load_check_pt_file_on_startup()
-{
- // On start up we want different behaviour.
- // If check pt file exists and we can't load then we want to exit
- // This avoids the server from overwriting the check point file
- // Which may be from a different version. let the user handle it.
- LogToCout logToCout;
- bool checkpt_failed = false;
- if (restore_from_checkpt(serverEnv_.checkPtFilename(),checkpt_failed)) {
- return true;
- }
- bool backup_checkpt_failed = false;
- if (restore_from_checkpt(serverEnv_.oldCheckPtFilename(),backup_checkpt_failed)) {
- return true;
- }
-
- if (backup_checkpt_failed && !fs::exists(serverEnv_.checkPtFilename())) {
- throw std::runtime_error("Can not start server, please handle the backup checkpoint file first");
- }
-
- if (checkpt_failed && !fs::exists(serverEnv_.oldCheckPtFilename())) {
- throw std::runtime_error("Can not start server, please handle the checkpoint file first");
- }
- return false;
-}
-
-void Server::loadCheckPtFile()
-{
- // if the check point file starts with an absolute file load that first
- // otherwise check in ECF_HOME then load it. Repeat for back up check point file
- // The server environment has already asserted that we can *NOT* have an empty check point file
- bool ignore;
- if (restore_from_checkpt(serverEnv_.checkPtFilename(),ignore)) {
- return;
- }
-
- if (restore_from_checkpt(serverEnv_.oldCheckPtFilename(),ignore)) {
- return;
- }
-}
-
-bool Server::restore_from_checkpt(const std::string& filename,bool& failed)
-{
- // cout << "Server::restore_from_checkpt " << filename;
- failed = false;
- if (fs::exists(filename)) {
- // cout << " file exists\n";
- LOG(Log::MSG, "Loading check point file " << filename << " port = " << serverEnv_.port());
-
- try {
- defs_->restore_from_checkpt(filename); // this can throw
- update_defs_server_state(); // works on def_
- //cout << "Server::restore_from_checkpt SUCCEDED found " << defs_->suiteVec().size() << " suites\n";
- return true;
- }
- catch (exception& e) {
- LOG(Log::ERR, "Failed to load check point file " << filename << ", because: " << e.what());
- failed = true;
- }
- }
-// else {
-// cout << " does *not* exist\n";
-// }
- return false;
-}
-
-void Server::update_defs_server_state()
-{
- /// The Job submission interval, and host port are not persisted, on the DEFS
- /// Hence when restoring from a checkpoint file, Be sure to update server state
-
- // Do any *one* time setup on the defs
-
- // Set the server environment *ON* the defs, so that generate variables can be created.
- // gets the environment as read in by the server, and make available for defs
- // ECF_HOME .
- // ECF_CHECK ecf.check
- // ECF_CHECKOLD ecf.check.b
- std::vector<std::pair<std::string,std::string> > envVec;
- serverEnv_.variables(envVec);
- defs_->set_server().add_or_update_server_variables(envVec);
-
- defs_->set_server().hostPort( hostPort() );
- defs_->set_server().set_state( serverState_ );
-
- // let the defs store the job submission interval, & whether we want job generation.testing can disable this
- defs_->set_server().jobSubmissionInterval( serverEnv_.submitJobsInterval() );
- defs_->set_server().jobGeneration( serverEnv_.jobGeneration() );
- LOG_ASSERT( defs_->server().jobSubmissionInterval() != 0 ,"");
-
- /// System needs defs to handle process that have died, and need to flagged as aborted
- ecf::System::instance()->setDefs(defs_);
-}
-
-void Server::set_server_state(SState::State ss)
-{
- serverState_ = ss;
- stats().status_ = static_cast<int>(serverState_);
- defs_->set_server().set_state( serverState_ );
-}
-
-
-/// ======================================================================================
-/// AbstractServer function.
-/// ======================================================================================
-
-std::pair<std::string,std::string> Server::hostPort() const
-{
- return serverEnv_.hostPort();
-}
-
-void Server::updateDefs( defs_ptr defs, bool force)
-{
- if (serverEnv_.debug()) std::cout << " Server::updateDefs: Loading new suites" << endl;
-
- // After the absorb, input defs will be left with NO suites.
- defs_->absorb(defs.get(),force);
-
- defs_->set_most_significant_state();
- LOG_ASSERT( defs_->server().jobSubmissionInterval() != 0 ,"");
-}
-
-void Server::clear_defs()
-{
- if (serverEnv_.debug()) cout << " Server::clear_defs()" << endl;
-
- defs_->clear();
-}
-
-void Server::checkPtDefs(ecf::CheckPt::Mode m, int check_pt_interval, int check_pt_save_time_alarm)
-{
- if (serverEnv_.debug())
- cout << " Server::checkPtDefs() mode(" << m << ") check_pt_interval(" << check_pt_interval << ") check_pt_save_time_alarm(" << check_pt_save_time_alarm << ")" << endl;
-
- if (m == ecf::CheckPt::UNDEFINED && check_pt_interval == 0 && check_pt_save_time_alarm == 0) {
- checkPtSaver_.explicitSave(); // will always save
- }
- else {
- if ( m != ecf::CheckPt::UNDEFINED ) {
- serverEnv_.set_check_mode( m );
- stats().checkpt_mode_ = serverEnv_.checkMode();
- }
- if ( check_pt_interval > 0) {
- serverEnv_.set_checkpt_interval( check_pt_interval );
- stats().checkpt_interval_ = check_pt_interval;
- }
- if (check_pt_save_time_alarm > 0 ) {
- serverEnv_.set_checkpt_save_time_alarm( check_pt_save_time_alarm );
- stats().checkpt_save_time_alarm_ = check_pt_save_time_alarm;
- }
- }
-}
-
-void Server::restore_defs_from_checkpt()
-{
- if (serverEnv_.debug()) cout << " Server::restore_defs_from_checkpt()" << endl;
-
- if (serverState_ != SState::HALTED ) {
- throw std::runtime_error( "Can not restore from checkpt the server must be halted first");
- }
-
- if (!defs_->suiteVec().empty()) {
- // suites must be deleted manually first
- throw std::runtime_error( "Can not restore from checkpt the server suites must be deleted first");
- }
-
- loadCheckPtFile();
-}
-
-void Server::nodeTreeStateChanged()
-{
- if (serverEnv_.debug()) cout << " Server::nodeTreeStateChanged()" << endl;
-
- // will only actually save if configuration allows it
- checkPtSaver_.saveIfAllowed();
-}
-
-bool Server::allowTaskCommunication() const
-{
- return (serverState_ != SState::HALTED) ? true : false;
-}
-
-
-void Server::shutdown()
-{
- /// User Request Task Request Job Scheduling Check-pointing
- /// RUNNING yes yes yes yes
- /// SHUTDOWN yes yes no yes
- /// HALTED yes no no no
- if (serverEnv_.debug()) cout << " Server::shutdown. Stop Scheduling new jobs only" << endl;
-
- // Stop server from creating new jobs. Don't stop the checkPtSaver_ since
- // the jobs communication with server can still change state. Which we want
- // to check point.
- traverser_.stop();
-
- // Continue check pointing since, we allow tasks communication. This can change node
- // tree state. Which we *must* be able to checkpoint.
- // If we go from HALTED --> SHUTDOWN, then check pointing needs to be enabled
- checkPtSaver_.start();
-
- // Will update defs as well to stop job scheduling
- set_server_state(SState::SHUTDOWN);
-}
-
-void Server::halted()
-{
- /// User Request Task Request Job Scheduling Check-pointing
- /// RUNNING yes yes yes yes
- /// SHUTDOWN yes yes no yes
- /// HALTED yes no no no
- if (serverEnv_.debug()) cout << " Server::halted. Stop Scheduling new jobs *and* block task communication. Stop check pointing. Only accept user request" << endl;
-
- // Stop server from creating new jobs. i.e Job scheduling.
- traverser_.stop();
-
- // *** CRITICAL*** when the server is halted, we ***MUST NOT*** do any further check pointing
- // In a typical operational scenario where we have a home, and backup servers.
- // The checkpoint file is copied to the backup servers periodically (via a task)
- // hence we want to preserve the state of the last checkpoint.
- // Added after discussion with Axel.
- checkPtSaver_.stop();
-
- // Stop the task communication with server. Hence nodes can be stuck
- // in submitted/active states. Task based command will continue attempting,
- // communication with the server for up to 24hrs.
- // Will update defs as well to stop job scheduling
- set_server_state(SState::HALTED);
-}
-
-void Server::restart()
-{
- /// User Request Task Request Job Scheduling Check-pointing
- /// RUNNING yes yes yes yes
- /// SHUTDOWN yes yes no yes
- /// HALTED yes no no no
- if (serverEnv_.debug()) std::cout << " Server::restart" << endl;
-
- // The server state *MUST* be set, *before* traverser_.start(), since that can kick off job traversal.
- // Job Scheduling can only be done under RUNNING state, hence must be before traverser_.start();
- //
- // If we placed set_server_state(SState::RUNNING); after we can miss time slots
- // See:: SUP 571- Time dependency after halt/checkpoint
- set_server_state(SState::RUNNING);
-
- traverser_.start();
- checkPtSaver_.start();
-}
-
-void Server::traverse_node_tree_and_job_generate(const boost::posix_time::ptime& time_now,bool user_cmd_context ) const
-{
- traverser_.traverse_node_tree_and_job_generate(time_now, user_cmd_context);
-}
-
-bool Server::reloadWhiteListFile(std::string& errorMsg)
-{
- if (serverEnv_.debug()) cout << " Server::reloadWhiteListFile" << endl;
-
- return serverEnv_.reloadWhiteListFile(errorMsg);
-}
-
-bool Server::authenticateUser(const std::string& user)
-{
- return serverEnv_.authenticateUser(user);
-}
-
-bool Server::authenticateWriteAccess(const std::string& user, bool client_request_can_change_server_state )
-{
- return serverEnv_.authenticateWriteAccess(user, client_request_can_change_server_state);
-}
-
-bool Server::lock(const std::string& user)
-{
- if (serverEnv_.debug()) std::cout << " Server::lock " << user << endl;
-
- if (userWhoHasLock_.empty()) {
- userWhoHasLock_ = user;
- stats().locked_by_user_ = user;
- shutdown();
- return true;
- }
- else if ( userWhoHasLock_ == user && serverState_ == SState::SHUTDOWN ) {
- // Same user attempting multiple locks
- return true;
- }
- return false;
-}
-void Server::unlock()
-{
- if (serverEnv_.debug()) std::cout << " Server::unlock " << userWhoHasLock_ << endl;
-
- userWhoHasLock_.clear();
- stats().locked_by_user_.clear();
- if ( serverState_ == SState::SHUTDOWN ) restart();
-}
-const std::string& Server::lockedUser() const
-{
- return userWhoHasLock_;
-}
-
-
-int Server::poll_interval() const
-{
- return serverEnv_.submitJobsInterval();
-}
-
-void Server::debug_server_on()
-{
- serverEnv_.set_debug(true);
- std::cout << "\nEnable DEBUG, start with DUMP of server environment:\n\n";
- std::cout << serverEnv_.dump() << endl;
-}
-
-void Server::debug_server_off()
-{
- serverEnv_.set_debug(false);
-}
-
-bool Server::debug() const
-{
- return serverEnv_.debug();
-}
-
-void Server::sigterm_signal_handler()
-{
- if (io_service_.stopped()) {
- if (serverEnv_.debug()) cout << "-->Server::sigterm_signal_handler(): io_service is stopped returning " << endl;
- return;
- }
-
- if (serverEnv_.debug()) cout << "Server::sigterm_signal_handler(): Received SIGTERM : starting check pointing" << endl;
- ecf::log(Log::MSG,"Server::sigterm_signal_handler(): Received SIGTERM : starting check pointing");
-
- checkPtDefs();
-
- ecf::log(Log::MSG,"Server::sigterm_signal_handler(): finished check pointing");
- if (serverEnv_.debug()) cout << "Server::sigterm_signal_handler(): finished check pointing" << endl;
-
- // We need re-wait each time signal handler is called
- signals_.async_wait(boost::bind(&Server::sigterm_signal_handler, this));
-}
diff --git a/ecflow_4_0_7/Server/src/Server.hpp b/ecflow_4_0_7/Server/src/Server.hpp
deleted file mode 100644
index 3592b2d..0000000
--- a/ecflow_4_0_7/Server/src/Server.hpp
+++ /dev/null
@@ -1,159 +0,0 @@
-#ifndef SERVER_HPP_
-#define SERVER_HPP_
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name : Server.cpp
-// Author : Avi
-// Revision : $Revision: #62 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : ECFLOW Server. Based on ASIO
-//
-// The port numbers are divided into three ranges:
-// o the Well Known Ports, (require root permission) 0 -1023
-// o the Registered Ports, 1024-49151
-// o Dynamic and/or Private Ports. 49151-65535
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <memory>
-#include <boost/asio.hpp>
-#include <boost/shared_ptr.hpp>
-
-// ECFLOW_MT See doc/multi-threaded-server.tar/ddoc
-//#define ECFLOW_MT 1
-#ifdef ECFLOW_MT
-#include "CConnection.hpp" // Must come before boost/serialisation headers.
-#else
-#include "Connection.hpp" // Must come before boost/serialisation headers.
-#include "ClientToServerRequest.hpp"
-#include "ServerToClientResponse.hpp"
-#endif
-
-#include "NodeTreeTraverser.hpp"
-#include "CheckPtSaver.hpp"
-#include "AbstractServer.hpp"
-
-class ServerEnvironment;
-
-
-class Server : public AbstractServer {
-public:
- /// Constructor opens the acceptor and starts waiting for the first incoming
- /// connection.
- Server(ServerEnvironment&);
- virtual ~Server();
-
- /// Start the server
- /// The Server::run/io_service::run() call will block until all asynchronous operations
- /// have finished. While the server is running, there is always at least one
- /// asynchronous operation outstanding: the asynchronous accept call waiting
- /// for new incoming connections.
- void run();
-
- /// Terminate the server gracefully. Need to cancel all timers, close all sockets
- /// Server will hang if there are any pending async handlers
- void terminate();
-
-private:
-
-#ifdef ECFLOW_MT
- /// Handle completion of a accept operation.
- void handle_accept(const boost::system::error_code& e);
-#else
- /// Handle completion of a accept operation.
- void handle_accept(const boost::system::error_code& e, connection_ptr conn);
-
- /// Handle completion of a write operation.
- void handle_write(const boost::system::error_code& e, connection_ptr conn);
-
- /// Handle completion of a read operation.
- void handle_read(const boost::system::error_code& e, connection_ptr conn);
-#endif
-
- void handle_terminate();
- void start_accept();
- bool shutdown_socket(connection_ptr conn, const std::string& msg) const;
-
-private:
-
- // abort server if check pt files exist, but can't be loaded
- bool load_check_pt_file_on_startup();
- void loadCheckPtFile();
- bool restore_from_checkpt(const std::string& filename, bool& failed);
- void update_defs_server_state();
- void set_server_state(SState::State);
-
-protected: // Allow test to override
-
- /// AbstractServer functions
- virtual SState::State state() const { return serverState_; }
- virtual std::pair<std::string,std::string> hostPort() const;
- virtual defs_ptr defs() const { return defs_;}
- virtual void updateDefs(defs_ptr,bool force);
- virtual void clear_defs();
- virtual void checkPtDefs(ecf::CheckPt::Mode m = ecf::CheckPt::UNDEFINED,
- int check_pt_interval = 0,
- int check_pt_save_time_alarm = 0);
- virtual void restore_defs_from_checkpt();
- virtual void nodeTreeStateChanged();
- virtual bool allowTaskCommunication() const;
- virtual void shutdown();
- virtual void halted();
- virtual void restart();
- virtual bool reloadWhiteListFile(std::string& errorMsg);
- virtual bool authenticateUser(const std::string& user);
- virtual bool authenticateWriteAccess(const std::string& user, bool client_request_can_change_server_state);
- virtual bool lock(const std::string& user);
- virtual void unlock();
- virtual const std::string& lockedUser() const;
- virtual void traverse_node_tree_and_job_generate(const boost::posix_time::ptime& time_now, bool user_cmd_context) const;
- virtual int poll_interval() const;
- virtual void debug_server_on();
- virtual void debug_server_off();
- virtual bool debug() const;
-
- // used in signal, for emergency check point during system session
- void sigterm_signal_handler();
-
-private:
-
- /// The io_service used to perform asynchronous operations.
- boost::asio::io_service io_service_;
-
- /// The signal_set is used to register for automatic check pointing
- boost::asio::signal_set signals_;
-
- /// The acceptor object used to accept incoming socket connections.
- boost::asio::ip::tcp::acceptor acceptor_;
-
-#ifdef ECFLOW_MT
- /// Strand to ensure the connection's handlers are not called concurrently.
- boost::asio::io_service::strand strand_;
- size_t thread_pool_size_;
- CConnection_ptr new_connection_;
- friend class CConnection;
-#else
- /// The data, typically loaded once, and then sent to many clients
- ClientToServerRequest inbound_request_;
- ServerToClientResponse outbound_response_;
-#endif
-
- defs_ptr defs_; // shared because is deleted in Test, and used in System::instance()
- NodeTreeTraverser traverser_;
- friend class NodeTreeTraverser;
-
- CheckPtSaver checkPtSaver_;
- friend class CheckPtSaver;
-
- SState::State serverState_;
- ServerEnvironment& serverEnv_;
- std::string userWhoHasLock_;
-};
-
-#endif
diff --git a/ecflow_4_0_7/Server/src/ServerEnvironment.cpp b/ecflow_4_0_7/Server/src/ServerEnvironment.cpp
deleted file mode 100644
index 44937c1..0000000
--- a/ecflow_4_0_7/Server/src/ServerEnvironment.cpp
+++ /dev/null
@@ -1,635 +0,0 @@
-//============================================================================
-// Name : ServerEnvironment
-// Author : Avi
-// Revision : $Revision: #95 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//
-//============================================================================
-
-#include <sys/types.h> // for getpid
-#include <unistd.h> // for getpid
-#include <stdlib.h> // for getenv()
-
-#include <iostream>
-#include <fstream>
-#include <iterator>
-
-#include <boost/program_options.hpp>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/lexical_cast.hpp>
-#ifdef ECFLOW_MT
-#include <boost/thread/thread.hpp> // needed for ECFLOW_MT and debug() to print thread ID
-#endif
-
-#include "ServerEnvironment.hpp"
-#include "ServerOptions.hpp"
-#include "WhiteListFile.hpp"
-#include "Log.hpp"
-#include "System.hpp"
-#include "Str.hpp"
-#include "Ecf.hpp"
-#include "Version.hpp"
-#include "Calendar.hpp"
-#include "File.hpp"
-#include "boost_archive.hpp"
-#include "JobProfiler.hpp"
-
-using namespace ecf;
-using namespace std;
-using namespace boost;
-namespace po = boost::program_options;
-namespace fs = boost::filesystem;
-
-static std::string the_check_mode(ecf::CheckPt::Mode mode)
-{
- switch (mode) {
- case ecf::CheckPt::NEVER: return "CHECK_NEVER"; break;
- case ecf::CheckPt::ON_TIME: return "CHECK_ON_TIME"; break;
- case ecf::CheckPt::ALWAYS: return "CHECK_ALWAYS"; break;
- case ecf::CheckPt::UNDEFINED: return "UNDEFINED"; break;
- }
- cout << "ServerEnvironment.cpp theCheckMode: assert failed\n";
- assert(false);
- return std::string();
-}
-
-// This can be overridden by calling "server --ecfinterval 3" for test purposes
-const int defaultSubmitJobsInterval = 60;
-
-////////////////////////////////////////////////////////////////////////////////////////////
-// class ServerEnvironment:
-///////////////////////////////////////////////////////////////////////////////////////////
-
-ServerEnvironment::ServerEnvironment( int argc, char* argv[])
-: serverHost_(host_name_.name()),
- serverPort_(0),
- checkPtInterval_(0),
- checkpt_save_time_alarm_(CheckPt::default_save_time_alarm()),
- submitJobsInterval_(defaultSubmitJobsInterval),
-#ifdef ECFLOW_MT
- threads_(boost::thread::hardware_concurrency()),
-#endif
- jobGeneration_(true),
- debug_(false),
- help_option_(false),
- version_option_(false),
- allow_old_client_new_server_(0),
- checkMode_(ecf::CheckPt::ON_TIME),
- tcp_protocol_(boost::asio::ip::tcp::v4())
-{
- init(argc,argv,"server_environment.cfg");
-}
-
-// This is ONLY used in test
-ServerEnvironment::ServerEnvironment(int argc, char* argv[], const std::string& path_to_config_file)
-: serverHost_(host_name_.name()),
- serverPort_(0),
- checkPtInterval_(0),
- checkpt_save_time_alarm_(CheckPt::default_save_time_alarm()),
- submitJobsInterval_(defaultSubmitJobsInterval),
-#ifdef ECFLOW_MT
- threads_(boost::thread::hardware_concurrency()),
-#endif
- jobGeneration_(true),
- debug_(false),
- help_option_(false),
- version_option_(false),
- allow_old_client_new_server_(0),
- checkMode_(ecf::CheckPt::ON_TIME),
- tcp_protocol_(boost::asio::ip::tcp::v4())
-{
- init(argc,argv,path_to_config_file);
-}
-
-void ServerEnvironment::init(int argc, char* argv[], const std::string& path_to_config_file)
-{
- std::string log_file_name;
- try {
- read_config_file(log_file_name,path_to_config_file);
- read_environment_variables(log_file_name); // overrides any settings in the config file
- }
- catch ( std::exception& e) {
- std::string msg = "Exception in ServerEnvironment::ServerEnvironment() : ";
- std::string exception_msg = e.what();
- // On ecgate, wrong locale, causes an exception where msg is empty
- if (exception_msg.empty()) msg += "Invalid locale? Check locale using 'locale -a', then export/set LANG environment";
- else msg += e.what();
- throw ServerEnvironmentException(msg);
- }
-
- // get server process id. This may be visualised in xecf. makes it easier to kill server
- try { ecf_pid_ = boost::lexical_cast<std::string>(getpid()); }
- catch (boost::bad_lexical_cast& e) {
- throw ServerEnvironmentException("ServerEnvironment::ServerEnvironment:: Could not convert PID to a string\n");
- }
- // std::cout << "PID = " << ecf_pid_ << "\n";
-
-
- // The options(argc/argv) must be read after the environment, since they override everything else
- ServerOptions options(argc,argv,this);
- help_option_ = options.help_option();
- if (help_option_) return; // User is printing the help
- version_option_ = options.version_option();
- if (version_option_) return; // User is printing the version
-
-
- /// Config, Environment, or Options may have updated port, update port dependent file names
- /// If we have default names make unique, by prefixing host and port
- assert(!ecf_checkpt_file_.empty()); // expect name of form "ecf.check"
- assert(!ecf_backup_checkpt_file_.empty()); // expect name of form "ecf.check.b"
- assert(!log_file_name.empty()); // expect name of form "ecf.log"
- assert(!ecf_white_list_file_.empty()); // expect name of form "ecf.lists"
- std::string port = boost::lexical_cast<std::string>(serverPort_);
-
- // If path is absolute leave as is
- if (ecf_checkpt_file_ == Ecf::CHECKPT())
- ecf_checkpt_file_ = host_name_.prefix_host_and_port(port,ecf_checkpt_file_);
- if (ecf_checkpt_file_[0] != '/') {
- // Prepend with ECF_HOME
- std::string check_pt = ecf_home();
- check_pt += Str::PATH_SEPERATOR();
- check_pt += ecf_checkpt_file_;
- ecf_checkpt_file_ = check_pt;
- }
-
- // If path is absolute leave as is
- if (ecf_backup_checkpt_file_ == Ecf::BACKUP_CHECKPT())
- ecf_backup_checkpt_file_ = host_name_.prefix_host_and_port(port,ecf_backup_checkpt_file_);
- if (ecf_backup_checkpt_file_[0] != '/') {
- std::string check_pt = ecf_home();
- check_pt += Str::PATH_SEPERATOR();
- check_pt += ecf_backup_checkpt_file_;
- ecf_backup_checkpt_file_ = check_pt;
- }
-
- if (ecf_white_list_file_ == Str::WHITE_LIST_FILE())
- ecf_white_list_file_ = host_name_.prefix_host_and_port(port,ecf_white_list_file_);
-
- // Change directory to ECF_HOME and check thats its accessible
- change_dir_to_ecf_home_and_check_accesibility();
-
-
- // LOG FILE ================================================================================
- if (log_file_name == Ecf::LOG_FILE())
- log_file_name = host_name_.prefix_host_and_port(port,log_file_name);
-
- // Create the Log file. The log file is obtained from the environment. Hence **must** be done last.
- Log::create(log_file_name);
-
-
- // Init log file:
- LOG(Log::MSG, Version::description() );
- LOG(Log::MSG, "Started at " << to_simple_string(Calendar::second_clock_time()) << " universal time");
- if ( tcp_protocol_.family() == 2 /*PF_INET*/)
- LOG(Log::MSG, "Host(" << hostPort().first << ") Port(" << hostPort().second << ") using TCP/IP v4");
- else
- LOG(Log::MSG, "Host(" << hostPort().first << ") Port(" << hostPort().second << ") using TCP/IP v6");
- LOG(Log::MSG, "ECF_HOME " << ecf_home());
- LOG(Log::MSG, "Job scheduling interval: " << submitJobsInterval_);
- if (allow_old_client_new_server_ != 0) {
- LOG(Log::MSG, "ECF_ALLOW_OLD_CLIENT_NEW_SERVER enabled: " << allow_old_client_new_server_);
- }
-}
-
-ServerEnvironment::~ServerEnvironment()
-{
- /// Destroy singleton to avoid valgrind from complaining
- Log::destroy();
- System::destroy();
-}
-
-bool ServerEnvironment::valid(std::string& errorMsg) const
-{
- /// This must be called *AFTER* the constructor
-
- if (serverHost_.empty()) {
- errorMsg = "Could not determine the server host.";
- return false;
- }
- std::stringstream ss;
- if ( serverPort_ == 0 || serverPort_ <= 1023 || serverPort_ >= 49151) {
-
- ss << "Server port " << serverPort_ << " not set correctly. \n";
- ss << "The port numbers are divided into three ranges.\n";
- ss << " o the Well Known Ports, (require root permission) 0 -1023\n";
- ss << " o the Registered Ports, 1024 -49151\n";
- ss << " o Dynamic and/or Private Ports. 49151 -65535\n\n";
- ss << "Please set in the range 1024-49151 via argument or \n";
- ss << "Server/src/environment.cfg.h or set the environment variable ECF_PORT. \n";
- errorMsg = ss.str();
- return false;
- }
- if (ecfHome_.empty()) {
- ss << "No ECF_HOME specified. Please set in Server/server_environment.cfg or\n";
- ss << "set the environment variable ECF_HOME\n";
- errorMsg = ss.str();
- return false;
- }
- if (!Log::instance() || Log::instance()->path().empty()) {
- ss << "No log file name specified. Please set in Server/server_environment.cfg or\n";
- ss << "set the environment variable ECF_LOG\n";
- errorMsg = ss.str();
- return false;
- }
- if ( checkPtInterval_ == 0 ) {
- ss << "Checkpoint interval not set. Please set in Server/server_environment.cfg or\n";
- ss << "set the environment variable ECF_CHECKINTERVAL. The value must be\n";
- ss << "convertible to a integer\n";
- errorMsg = ss.str();
- return false;
- }
- if ( submitJobsInterval_ < 1 || submitJobsInterval_ > 60) {
- ss << "Submit jobs interval not set correctly. Please set in Server/server_environment.cfg\n";
- ss << "or provide as an argument. It must be in the range [1-60] \n";
- errorMsg = ss.str();
- return false;
- }
- if (ecf_checkpt_file_.empty()) {
- ss << "No checkpoint file name specified. Please set in Server/server_environment.cfg or\n";
- ss << "set the environment variable ECF_CHECK\n";
- errorMsg = ss.str();
- return false;
- }
- if (ecf_backup_checkpt_file_.empty()) {
- ss << "No old checkpoint file name specified. Please set in Server/server_environment.cfg or\n";
- ss << "set the environment variable ECF_CHECKOLD\n";
- errorMsg = ss.str();
- return false;
- }
- if (checkMode_ == ecf::CheckPt::UNDEFINED) {
- ss << "No ECF_CHECKMODE specified. Please set in Server/server_environment.cfg\n";
- errorMsg = ss.str();
- return false;
- }
- if (ecf_cmd_.empty()) {
- ss << "No ECF_JOB_CMD specified. Please set in Server/server_environment.cfg\n";
- errorMsg = ss.str();
- return false;
- }
- if (killCmd_.empty()) {
- ss << "No ECF_KILL_CMD specified. Please set in Server/server_environment.cfg\n";
- errorMsg = ss.str();
- return false;
- }
- if (statusCmd_.empty()) {
- ss << "No ECF_STATUS_CMD specified. Please set in Server/server_environment.cfg\n";
- errorMsg = ss.str();
- return false;
- }
- if (urlCmd_.empty()) {
- ss << "No ECF_URL_CMD specified. Please set in Server/server_environment.cfg\n";
- errorMsg = ss.str();
- return false;
- }
- if (urlBase_.empty()) {
- ss << "No ECF_URL_BASE specified. Please set in Server/server_environment.cfg\n";
- errorMsg = ss.str();
- return false;
- }
- if (url_.empty()) {
- ss << "No ECF_URL specified. Please set in Server/server_environment.cfg\n";
- errorMsg = ss.str();
- return false;
- }
- if (ecf_micro_.empty()) {
- ss << "No ECF_MICRODEF specified. Please set in Server/server_environment.cfg\n";
- errorMsg = ss.str();
- return false;
- }
-
- // If the white list file is empty or does not exist, its perfectly valid
- // i.e any user is free to access the server
- if (ecf_white_list_file_.empty()) return true;
- if (!fs::exists(ecf_white_list_file_)) return true;
-
- if (debug()) {
- std::cout << "White list file " << ecf_white_list_file_ << " exists, opening...\n";
- }
-
- /// read in the ecf white list file that specifies valid users and their access rights
- /// If the file can't be opened returns false and an error message and false;
- WhiteListFile theFile(ecf_white_list_file_);
- ServerEnvironment* nonConstThis = const_cast<ServerEnvironment*>(this);
- bool parse_result = theFile.parse(nonConstThis->validUsers_,errorMsg);
-
- if (debug()) {
- std::cout << dump_valid_users() << "\n";
- }
- return parse_result;
-}
-
-std::pair<std::string,std::string> ServerEnvironment::hostPort() const
-{
- return std::make_pair(serverHost_,serverPort());
-}
-
-void ServerEnvironment::variables(std::vector<std::pair<std::string,std::string> >& theRetVec) const
-{
- // Variables read in from the environment
- // Need to setup client environment.
- // The server sets these variable for use by the client. i.e when creating the jobs
- // The clients then uses them to communicate back with the server.
- theRetVec.push_back( std::make_pair(Str::ECF_PORT(), serverPort()) );
- theRetVec.push_back( std::make_pair(std::string("ECF_NODE"), serverHost_) );
-
- theRetVec.push_back( std::make_pair(Str::ECF_HOME(), ecfHome_) );
- if (Log::instance()) theRetVec.push_back( std::make_pair(std::string("ECF_LOG"), Log::instance()->path()) );
- else theRetVec.push_back( std::make_pair(std::string("ECF_LOG"), std::string() ));
- theRetVec.push_back( std::make_pair(std::string("ECF_CHECK"), ecf_checkpt_file_) );
- theRetVec.push_back( std::make_pair(std::string("ECF_CHECKOLD"), ecf_backup_checkpt_file_) );
- theRetVec.push_back( std::make_pair(std::string("ECF_INTERVAL"), boost::lexical_cast<std::string>(submitJobsInterval_)) );
-
- // These variable are read in from the environment, but are not exposed
- // since they only affect the server
- // ECF_CHECKINTERVAL
-
- theRetVec.push_back( std::make_pair(std::string("ECF_LISTS"), ecf_white_list_file_) ); // read only variable, changing it has no effect
-
- // variables that can be overridden, in the suite definition
- theRetVec.push_back( std::make_pair(std::string("ECF_JOB_CMD"), ecf_cmd_) );
- theRetVec.push_back( std::make_pair(std::string("ECF_KILL_CMD"), killCmd_) );
- theRetVec.push_back( std::make_pair(std::string("ECF_STATUS_CMD"), statusCmd_) );
- theRetVec.push_back( std::make_pair(std::string("ECF_URL_CMD"), urlCmd_) );
- theRetVec.push_back( std::make_pair(std::string("ECF_URL_BASE"), urlBase_) );
- theRetVec.push_back( std::make_pair(std::string("ECF_URL"), url_) );
- theRetVec.push_back( std::make_pair(std::string("ECF_MICRO"), ecf_micro_) );
-
- // Reference variable, these should be read only
- theRetVec.push_back( std::make_pair(std::string("ECF_PID"), ecf_pid_) ); // server PID
- theRetVec.push_back( std::make_pair(std::string("ECF_VERSION"), Version::raw()) );// server version
-}
-
-bool ServerEnvironment::reloadWhiteListFile(std::string& errorMsg)
-{
- if (debug()) cout << "ServerEnvironment::reloadWhiteListFile:(" << ecf_white_list_file_ << ") CWD(" << fs::current_path().string() << ")\n";
- if (ecf_white_list_file_.empty()) {
- errorMsg += "The ECF_LISTS file ";
- errorMsg += ecf_white_list_file_;
- errorMsg += " has not been specified.";
- return false;
- }
- if (!fs::exists(ecf_white_list_file_)) {
- errorMsg += "The ECF_LISTS file ";
- errorMsg += ecf_white_list_file_;
- errorMsg += " does not exist. Server CWD : " + fs::current_path().string();
- return false;
- }
-
- // Only override valid users if we successfully opened and parsed file
- WhiteListFile theFile(ecf_white_list_file_);
- std::map<std::string,bool> validUsers;
- if (theFile.parse(validUsers,errorMsg)) {
-
- validUsers_.clear();
- validUsers_ = validUsers;
-
- if (debug()) std::cout << dump_valid_users() << "\n";
- return true;
- }
- return false;
-}
-
-
-bool ServerEnvironment::authenticateUser(const std::string& user) const
-{
- // If validUsers_ is empty , then all user are valid
- if (validUsers_.empty()) return true;
-
- if ( validUsers_.find(user) != validUsers_.end() ) {
- return true;
- }
- return false;
-}
-
-bool ServerEnvironment::authenticateWriteAccess(const std::string& user, bool client_request_can_change_server_state) const
-{
- // If validUsers_ is empty , then all users have write access
- if (validUsers_.empty()) return true;
-
- std::map<std::string,bool>::const_iterator i = validUsers_.find(user);
- if ( i != validUsers_.end() ) {
-
- // (*i).second - true mean user is allowed read/write client requests
- // false means user is only allowed read only client request
- if (client_request_can_change_server_state && (*i).second) {
- // request can change server state and user is allowed read/write access
- // authentication is OK
- return true;
- }
- if (!client_request_can_change_server_state) {
- // request is read only, and since user in the list, they must allow read requests
- return true;
- }
- }
- return false;
-}
-
-
-// ============================================================================================
-// Privates:
-// ============================================================================================
-
-void ServerEnvironment::read_config_file(std::string& log_file_name,const std::string& path_to_config_file)
-{
- if (debug()) cout << "ServerEnvironment::read_config_file() current_path = " << fs::current_path() << "\n";
-
- try {
- std::string theCheckMode;
- int the_task_threshold = 0;
-
- // read the environment from the config file.
- // **** Port *must* be read before log file, and check pt files
- po::options_description config_file_options("Configuration");
- config_file_options.add_options()
- ("ECF_HOME", po::value<std::string>(&ecfHome_)->default_value("."), "ECF_HOME, the home for all ECF files")
- ("ECF_PORT", po::value<int>(&serverPort_)->default_value(3141), "The port number. Clients must use same port.")
- ("ECF_CHECK", po::value<std::string>(&ecf_checkpt_file_)->default_value(Ecf::CHECKPT()), "Check point file name")
- ("ECF_CHECKOLD", po::value<std::string>(&ecf_backup_checkpt_file_)->default_value(Ecf::BACKUP_CHECKPT()), "Backup checkpoint file name")
- ("ECF_LOG", po::value<std::string>(&log_file_name)->default_value(Ecf::LOG_FILE()), "Log file name")
- ("ECF_CHECKINTERVAL", po::value<int>(&checkPtInterval_)->default_value(CheckPt::default_interval()), "The interval in seconds to save check point file")
- ("ECF_INTERVAL", po::value<int>(&submitJobsInterval_)->default_value(defaultSubmitJobsInterval), "Check time dependencies and submit any jobs")
- ("ECF_CHECKMODE", po::value<std::string>(&theCheckMode), "The check mode, must be one of CHECK_NEVER, CHECK_ON_TIME, CHECK_ALWAYS")
- ("ECF_JOB_CMD", po::value<std::string>(&ecf_cmd_)->default_value(Ecf::JOB_CMD()), "Command to be executed to submit a job.")
- ("ECF_KILL_CMD", po::value<std::string>(&killCmd_)->default_value(Ecf::KILL_CMD()), "Command to be executed to kill a job.")
- ("ECF_STATUS_CMD",po::value<std::string>(&statusCmd_)->default_value(Ecf::STATUS_CMD()), "Command to be obtain the status.")
- ("ECF_URL_CMD", po::value<std::string>(&urlCmd_)->default_value(Ecf::URL_CMD()), "Command to be obtain url.")
- ("ECF_URL_BASE", po::value<std::string>(&urlBase_)->default_value(Ecf::URL_BASE()), "Defines url base.")
- ("ECF_URL", po::value<std::string>(&url_)->default_value(Ecf::URL()), "The default url.")
- ("ECF_MICRODEF", po::value<std::string>(&ecf_micro_)->default_value(Ecf::MICRO()), "Preprocessor character for variable substitution and including files")
- ("ECF_LISTS", po::value<std::string>(&ecf_white_list_file_)->default_value(Str::WHITE_LIST_FILE()), "Path name to file the list valid users and thier access rights")
- ("ECF_TASK_THRESHOLD",po::value<int>(&the_task_threshold)->default_value(JobProfiler::task_threshold_default()),"The defaults thresholfs when profiling job generation")
- ;
-
- ifstream ifs(path_to_config_file.c_str());
- if (!ifs) {
- if (debug()) cout << "Could not load server_environment.cfg " << path_to_config_file << "\n";
- }
-
- /// This is *NOT* redundant, when the file is empty/not present, then the default value
- /// defined above are set.
- po::variables_map vm;
- po::store(parse_config_file(ifs, config_file_options), vm);
- po::notify( vm);
-
- if (theCheckMode == "CHECK_ON_TIME") checkMode_ = ecf::CheckPt::ON_TIME;
- else if (theCheckMode == "CHECK_NEVER") checkMode_ = ecf::CheckPt::NEVER;
- else if (theCheckMode == "CHECK_ALWAYS") checkMode_ = ecf::CheckPt::ALWAYS;
-
- if (the_task_threshold != 0 ) {
- JobProfiler::set_task_threshold(the_task_threshold);
- }
- }
- catch(std::exception& e)
- {
- cerr << "ServerEnvironment::read_config_file() " << e.what() << "\n";
- }
-}
-
-void ServerEnvironment::read_environment_variables(std::string& log_file_name)
-{
- if (debug()) cout << "ServerEnvironment::read_environment_variables()\n";
-
- char* serverPort = getenv(Str::ECF_PORT().c_str());
- if (serverPort) {
- std::string port = serverPort;
- try { serverPort_ = boost::lexical_cast< int >( port ); }
- catch (boost::bad_lexical_cast& e) {
- std::stringstream ss;
- ss << "ServerEnvironment::read_environment_variables(): ECF_PORT is defined(" << port << ") but value is *not* convertible to an integer\n";
- throw ServerEnvironmentException(ss.str());
- }
- }
- char* checkPtInterval = getenv("ECF_CHECKINTERVAL");
- if (checkPtInterval) {
- std::string interval = checkPtInterval;
- try { checkPtInterval_ = boost::lexical_cast< int >( interval ); }
- catch (boost::bad_lexical_cast& e) {
- std::stringstream ss;
- ss << "ServerEnvironment::read_environment_variables(): ECF_CHECKINTERVAL is defined(" << interval << ") but value is *not* convertible to an integer\n";
- throw ServerEnvironmentException(ss.str());
- }
- }
-
- char* ecfHome = getenv(Str::ECF_HOME().c_str());
- if (ecfHome) ecfHome_ = ecfHome;
- if( ecfHome_ == "." ) { // expand to absolute paths
- ecfHome_ = fs::current_path().string();
- }
-
- char* logFileName = getenv("ECF_LOG");
- if (logFileName) log_file_name = logFileName;
-
- char* checkPtFileName = getenv("ECF_CHECK");
- if (checkPtFileName) ecf_checkpt_file_ = checkPtFileName;
-
- char* oldCheckPtFileName = getenv("ECF_CHECKOLD");
- if (oldCheckPtFileName) ecf_backup_checkpt_file_ = oldCheckPtFileName;
-
- char* smsWhiteListFile = getenv("ECF_LISTS");
- if (smsWhiteListFile) ecf_white_list_file_ = smsWhiteListFile;
-
- if (getenv("ECF_DEBUG_SERVER")) {
- debug_ = true; // can also be enabled via --debug option
- }
-
- if (getenv("ECF_ALLOW_OLD_CLIENT_NEW_SERVER")) {
- // we don't need exact version of boost archive version of old client, since we can determine
- // this from the message sent to the server from the *old* client
- allow_old_client_new_server_ = ecf::boost_archive::version_1_47();
- }
-
- char* threshold = getenv("ECF_TASK_THRESHOLD");
- if ( threshold ) {
- std::string task_threshold = threshold;
- try {
- JobProfiler::set_task_threshold(boost::lexical_cast<int>(task_threshold));
- }
- catch ( ... ) {
- std::stringstream ss;
- ss << "ServerEnvironment::read_environment_variables(): ECF_TASK_THRESHOLD is defined(" << threshold << ") but value is *not* convertible to an integer\n";
- throw ServerEnvironmentException(ss.str());
- }
- }
-}
-
-std::string ServerEnvironment::serverPort() const
-{
- return boost::lexical_cast< std::string >( serverPort_ );
-}
-
-void ServerEnvironment::change_dir_to_ecf_home_and_check_accesibility()
-{
- if( chdir(ecfHome_.c_str()) != 0 ) {
- std::stringstream ss;
- ss << "Can't chdir to ECF_HOME " << ecfHome_ << "\n";
- throw ServerEnvironmentException(ss.str());
- }
- if( access(ecfHome_.c_str() , X_OK|R_OK|W_OK) != 0 ) {
- // R_OK test for read permission
- // W_OK test for write permission
- // X_OK test for execute or search permission
- // F_OK test whether the directories leading to the file can be searched and the file exists.
- std::stringstream ss;
- ss << "Access restriction on ECF_HOME " << ecfHome_ << "\n";
- throw ServerEnvironmentException(ss.str());
- }
-}
-
-std::string ServerEnvironment::check_mode_str() const { return the_check_mode(checkMode_);}
-
-std::string ServerEnvironment::dump() const
-{
- std::stringstream ss;
- ss << "ECF_HOME = '" << ecfHome_ << "'\n";
- if (Log::instance()) ss << "ECF_LOG = '" << Log::instance()->path() << "'\n";
- else ss << "ECF_LOG = ''\n";
- ss << "ECF_PORT = '" << serverPort_ << "'\n";
- ss << "ECF_CHECK = '" << ecf_checkpt_file_ << "'\n";
- ss << "ECF_CHECKOLD = '" << ecf_backup_checkpt_file_ << "'\n";
- ss << "ECF_CHECKINTERVAL = '" << checkPtInterval_ << "'\n";
- ss << "ECF_INTERVAL = '" << submitJobsInterval_ << "'\n";
- ss << "ECF_CHECKMODE = '" << the_check_mode(checkMode_) << "'\n";
- ss << "ECF_JOB_CMD = '" << ecf_cmd_ << "'\n";
- ss << "ECF_KILL_CMD = '" << killCmd_ << "'\n";
- ss << "ECF_STATUS_CMD = '" << statusCmd_ << "'\n";
- ss << "ECF_URL_CMD = '" << urlCmd_ << "'\n";
- ss << "ECF_URL_BASE = '" << urlBase_ << "'\n";
- ss << "ECF_URL = '" << url_ << "'\n";
- ss << "ECF_MICRO = '" << ecf_micro_ << "'\n";
- ss << "check pt save time alarm " << checkpt_save_time_alarm_ << "\n";
- ss << "Job generation " << jobGeneration_ << "\n";
- ss << "Server host name " << serverHost_ << "\n";
-#ifdef ECFLOW_MT
- ss << "No of threads used by server " << threads_ << "\n";
-#endif
- if ( tcp_protocol_.family() == 2 /*PF_INET*/) ss << "TCP Protocol v4 \n";
- else if ( tcp_protocol_.family() == 10 /*PF_INET6*/) ss << "TCP Protocol v6 \n";
-
- ss << dump_valid_users();
- return ss.str();
-}
-
-std::string ServerEnvironment::dump_valid_users() const
-{
- std::stringstream ss;
- ss << "ECF_LISTS = '" << ecf_white_list_file_ << "'\n";
- if (validUsers_.empty()) ss << " No users specified. Everyone has read/write access\n";
-
- std::map<std::string,bool>::const_iterator i;
- for(i=validUsers_.begin(); i!= validUsers_.end(); ++i) {
- ss << " User: " << (*i).first;
- if ((*i).second) ss << " has read/write access\n";
- else ss << " has read access only\n";
- }
- return ss.str();
-}
-
diff --git a/ecflow_4_0_7/Server/src/ServerEnvironment.hpp b/ecflow_4_0_7/Server/src/ServerEnvironment.hpp
deleted file mode 100644
index c62af60..0000000
--- a/ecflow_4_0_7/Server/src/ServerEnvironment.hpp
+++ /dev/null
@@ -1,216 +0,0 @@
-#ifndef SERVER_ENVIRONMENT_HPP_
-#define SERVER_ENVIRONMENT_HPP_
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name : ServerEnvironment
-// Author : Avi
-// Revision : $Revision: #52 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//
-// The server environment is read from the configuration file. This defines
-// the defaults for the server,and is configurable by the user, at run time
-// Alternatively some variable can be set via environment. See environment.cfg
-//
-// The server must be created before the log file. Since the log is initialised
-// with the log file name from the server environment
-//
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <string>
-#include <vector>
-#include <map>
-#include <exception>
-#include <boost/noncopyable.hpp>
-#include <boost/asio.hpp>
-
-#include "Host.hpp"
-#include "CheckPt.hpp"
-
-// Added ServerEvinronmentException so that it can be in the same scope as server
-// in ServerMain. Previously we had a separate try block
-// Also distinguish between server and environment errors
-class ServerEnvironmentException : public std::runtime_error {
-public:
- ServerEnvironmentException(const std::string& msg) : std::runtime_error(msg) {}
-};
-
-
-class ServerEnvironment : private boost::noncopyable {
-public:
- ServerEnvironment(int argc, char* argv[]);
- ServerEnvironment(int argc, char* argv[], const std::string& path_to_config_file); // *only used in test*
- ~ServerEnvironment();
-
- /// return true if option are valid false and error message otherwise
- bool valid(std::string& errorMsg) const;
-
- /// return the directory path associated with smshome
- /// but can be overridden by the environment variable ECF_HOME
- std::string ecf_home() const { return ecfHome_; }
-
- /// returns the server host and port
- std::pair<std::string,std::string> hostPort() const;
-
- /// returns the server port. This has a default value defined in server_environment.cfg
- /// but can be overridden by the environment variable ECF_PORT
- int port() const { return serverPort_;}
-
- /// returns the TCP protocol. default is TCPv4. Can be changed via command line to TCPv6
- boost::asio::ip::tcp tcp_protocol() const { return tcp_protocol_;}
-
- /// Return true if job generation is enabled. By default job generation is enabled however
- /// for test/debug we can elect to disable, it.
- bool jobGeneration() const { return jobGeneration_;}
-
- /// Forward compatibility allow old clients to talk to new server
- /// Temp: This allows ecflow to be built. i.e we have old clients(3.0.x), installed on different machines
- /// they need to talk to new server. (i.e since we can't change the old clients)
- /// This is controlled with ECF_ALLOW_OLD_CLIENT_NEW_SERVER
- int allow_old_client_new_server() const { return allow_old_client_new_server_;}
-
-
- /// Whenever we save the checkpt, we time how long this takes.
- /// For very large definition the time can be significant and start to interfere with
- /// the scheduling. (i.e since write to disk is blocking).
- /// The default is 30 seconds. When the save time exceeds this, the late flag is
- /// set on the definition. This needs to be manually reset.
- size_t checkpt_save_time_alarm() const { return checkpt_save_time_alarm_;}
- void set_checkpt_save_time_alarm(size_t t) { checkpt_save_time_alarm_ = t ;}
-
- /// returns the path of the checkpoint file. This has a default name set in server_environment.cfg
- /// but can be overridden by the environment variable ECF_CHECK
- /// if the check point file starts with an absolute path return as is:
- /// otherwise returns ECF_HOME/ecf_checkpt_file_
- const std::string& checkPtFilename() const { return ecf_checkpt_file_; }
-
- /// returns the path of the old checkPointFile. This has a default name set in server_environment.cfg
- /// but can be overridden by the environment variable ECF_CHECKOLD
- /// if the check point file starts with an absolute path return as is:
- /// otherwise returns ECF_HOME/ecf_backup_checkpt_file_
- const std::string& oldCheckPtFilename() const { return ecf_backup_checkpt_file_; }
-
- /// returns the checkPt interval. This is the time in seconds, at which point the server
- /// serializes the defs node tree. This is called the check point file.
- /// This has a default value set in environment.cfg
- /// but can be overridden by the environment variable ECF_CHECKINTERVAL
- /// if set via environment variable it must be convertible to an integer
- int checkPtInterval() const { return checkPtInterval_;}
-
- /// set the check point interval. Typically set via client interface
- /// value should > 0 for valid values.
- void set_checkpt_interval(int v) { if (v > 0) checkPtInterval_ = v;}
-
- /// returns the check mode. This specifies options for saving of the checkPoint file:
- ecf::CheckPt::Mode checkMode() const { return checkMode_;}
- void set_check_mode(ecf::CheckPt::Mode m) { checkMode_ = m; }
- std::string check_mode_str() const;
-
- /// returns the number of seconds at which we should check time dependencies
- /// this includes evaluating trigger dependencies and submit the corresponding jobs.
- /// This is set at 60 seconds. But will vary for debug/test purposes only.
- /// For Testing the state change queued->submitted->active duration < submitJobsInterval
- /// If this state change happens at the job submission boundary then
- /// time series can get a skew.
- int submitJobsInterval() const { return submitJobsInterval_;}
-
- /// returns server variables, as vector of pairs.
- /// Some of these variables hold environment variables
- /// Note:: additional variable are created for use by clients, i.e like
- /// ECF_PORT(jobs, server, client)
- /// ECF_NODE(jobs). ECF_NODE is the server machine host name
- void variables(std::vector<std::pair<std::string,std::string> >&) const;
-
- /// Ask the server to reload file the hold list of users and their access rights
- /// The white list file is specified by the environment variable ECF_LISTS
- /// This allows/disallows user access on the live server
- /// Return true if file is reloaded ok, else false and error message if:
- /// a/ File does not exist
- /// b/ File is empty
- /// c/ Errors in parsing file
- /// If errors arise the exist user still stay in affect
- bool reloadWhiteListFile(std::string& errorMsg);
-
-#ifdef ECFLOW_MT
- // returns the numbers threads to be used by the server.
- size_t threads() const { return threads_; };
-#endif
-
- /// There are several kinds of authentification:
- /// a/ None
- /// b/ List mode. ASCII file based on ECF_LISTS is defined
- /// c/ Secure mode. binary file based ECF_PASSWD is defined
- /// At the moment we will only implement options a/ and b/
- //
- /// Returns true if the given user has access to the server, false otherwise
- bool authenticateUser(const std::string& user)const;
- bool authenticateWriteAccess(const std::string& user, bool client_request_can_change_server_state) const;
-
- /// return true if help option was selected
- bool help_option() const { return help_option_; }
- bool version_option() const { return version_option_; }
-
- /// debug is enabled via --debug or server invocation
- bool debug() const { return debug_;}
- void set_debug(bool f) { debug_ = f;}
-
- std::string dump() const;
-
-private:
- void init(int argc, char* argv[], const std::string& path_to_config_file);
-
- /// defaults are read from a config file
- void read_config_file(std::string& log_file_name,const std::string& path_to_config_file);
-
- /// Get the standard environment variables, overwrite any settings from config file
- void read_environment_variables(std::string& log_file_name);
-
- /// Convert server port to a string
- std::string serverPort() const;
-
- void change_dir_to_ecf_home_and_check_accesibility();
-
- /// dump out current settings
- std::string dump_valid_users() const;
-
-private:
- ecf::Host host_name_;
- std::string serverHost_; // must be after host_name_, since used in init
- int serverPort_;
- int checkPtInterval_;
- int checkpt_save_time_alarm_;
- int submitJobsInterval_;
-#ifdef ECFLOW_MT
- size_t threads_;
-#endif
- bool jobGeneration_; // used in debug/test mode only
- bool debug_;
- bool help_option_;
- bool version_option_;
- int allow_old_client_new_server_;
- ecf::CheckPt::Mode checkMode_;
- std::string ecfHome_;
- std::string ecf_checkpt_file_;
- std::string ecf_backup_checkpt_file_;
- std::string ecf_pid_;
- std::string killCmd_;
- std::string statusCmd_;
- std::string urlCmd_;
- std::string urlBase_;
- std::string url_;
- std::string ecf_cmd_;
- std::string ecf_micro_;
- std::string ecf_white_list_file_;
- std::map<std::string,bool> validUsers_; // first user name, second true is write access, false read access
- boost::asio::ip::tcp tcp_protocol_; // defaults to IPv4 TCP protocol
- friend class ServerOptions;
-};
-
-#endif
diff --git a/ecflow_4_0_7/Server/src/ServerMain.cpp b/ecflow_4_0_7/Server/src/ServerMain.cpp
deleted file mode 100644
index 75c80db..0000000
--- a/ecflow_4_0_7/Server/src/ServerMain.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-//============================================================================
-// Name : ServerMain
-// Author : Avi
-// Revision : $Revision: #37 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : Server
-//============================================================================
-
-#include <memory>
-#include "Server.hpp"
-#include "Log.hpp"
-#include "ServerEnvironment.hpp"
-
-using namespace ecf;
-using namespace std;
-
-int main( int argc, char* argv[] ) {
-
- try {
- // Get the environment settings, and parse argument line and init the log file
- ServerEnvironment server_environment(argc, argv); // This can throw ServerEnvironmentException
- if ( server_environment.help_option()) return 0;
- if ( server_environment.version_option()) return 0;
- std::string errorMsg;
- if (!server_environment.valid(errorMsg)) {
- cerr << errorMsg;
- ecf::log(Log::ERR,errorMsg);
- return 1;
- }
-
- if (server_environment.debug()) cout << "Server started: ------------------------------------------------>port:" << server_environment.port() << endl;
- Server theServer( server_environment ); // This can throw exception, bind address in use.
- for(;;) {
- try {
- theServer.run();
- if (server_environment.debug()) cout << "Normal exit from server\n";
- break;
- }
- catch ( std::exception& e ) {
- // deal with errors from the handlers
- std::string msg = "ServerMain:: "; msg += e.what();
- std::cerr << msg << endl;
- ecf::log(Log::ERR,msg);
- }
- }
-
- if (server_environment.debug()) cout << "Server EXITING: <------------------------------------------------ port:" << server_environment.port() << endl;
- return 0;
- }
- catch ( ServerEnvironmentException& e ) {
- // *** deal with server options and environment exceptions
- std::cerr << "Could not load the server environment or options :\n" << e.what() << "\n";
- std::cerr << "Invalid locale? Check locale using 'locale -a', then export/set LANG environment\n";
- }
- catch ( std::exception& e ) {
- // *** deal with errors from the server constructor ****
- std::string msg = "Exception in ServerMain:: "; msg += e.what();
- std::cerr << msg << endl;
- ecf::log(Log::ERR,msg);
-
- // dump server environment
- cerr << "\nServer environment:\n";
- ServerEnvironment server_env(argc, argv); // This can throw ServerEnvironmentException
- std::cerr << server_env.dump();
- }
- catch ( ... ) {
- std::string msg = "ServerMain:: unknown exception";
- std::cerr << msg << endl;
- ecf::log(Log::ERR,msg);
- }
- return 1;
-}
diff --git a/ecflow_4_0_7/Server/src/ServerOptions.cpp b/ecflow_4_0_7/Server/src/ServerOptions.cpp
deleted file mode 100644
index 4bc8da5..0000000
--- a/ecflow_4_0_7/Server/src/ServerOptions.cpp
+++ /dev/null
@@ -1,160 +0,0 @@
-//============================================================================
-// Name : ServerOptions
-// Author : Avi
-// Revision : $Revision: #28 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include "ServerOptions.hpp"
-#include "Version.hpp"
-#include "ServerEnvironment.hpp"
-#include <boost/lexical_cast.hpp>
-#include <iostream>
-
-using namespace std;
-using namespace ecf;
-namespace po = boost::program_options;
-
-ServerOptions::ServerOptions( int argc, char* argv[],ServerEnvironment* env )
-{
- std::stringstream ss;
- ss << "\n" << Version::description() << "\nServer options";
- po::options_description desc( ss.str() , po::options_description::m_default_line_length + 80 );
-
- desc.add_options()
-( "help,h",
- "The server reads the LANG for the locale. Please ensure that\n"
- "locale is valid otherwise the server will abort on startup.\n"
- "For a list of valid locale use 'locale -a'.\n"
- "\n"
- "The server will read the following environment variables:\n"
- "ECF_PORT:\n"
- " Defines the port that the server will listen to.\n"
- " The port number must be consistent between client and server\n"
- " If two servers are started on the same machine with same port\n"
- " then a 'Address in use' error is shown and server will exit.\n"
- " The default value for client/server is 3141\n"
- "ECF_HOME:\n"
- " This is the home/root for all '.ecf' scripts.\n"
- " When the server starts it will change directory to ECF_HOME,\n"
- " hence the directory must be accessible and writable.\n"
- " The default value is the current working directory\n"
- "ECF_LOG:\n"
- " Overrides the name of log file.\n"
- " The default log file name is: <host>.<port>.ecf.log, i.e. machine1.3141.ecf.log\n"
- " this is required since we can have multiple servers for a single machine.\n"
- " Where each server will have a separate port number.\n"
- " Note: Any settings will be prepended with <host>.<port>.\n"
- "ECF_CHECK:\n"
- " Defines the name of the check point file.\n"
- " This stores the state of the definition in memory,\n"
- " and allows recovery from crash. By default the server on start up will load\n"
- " the check point file or back up check point file if they exist.\n"
- " The default is <host>.<port>.ecf.check\n"
- " Any settings will be prepended with <host>.<port>.\n"
- "ECF_CHECKOLD:\n"
- " The name of the backup checkpoint file\n"
- " default is <host>.<port>.ecf.check.b\n"
- " Any settings will be prepended with <host>.<port>.\n"
- "ECF_CHECKINTERVAL:\n"
- " The interval in seconds within the server that the checkpoint file is saved\n"
- " Values less than 60 seconds are not recommended\n"
- " The default value is 120 seconds\n"
- "ECF_LISTS:\n"
- " This variable is used to identify a file, that lists the user\n"
- " who can access the server via client commands. Each client command\n"
- " (ignoring child commands, i.e init, complete, event, meter, label, wait)\n"
- " will encode the user name of the process initiating the client request\n"
- " This is then compared with list of users in the ecf.lists file.\n"
- " If this file is empty, then no authentication is done.\n"
- " Each server can potentially have a different list.\n"
- " The default is <host>.<port>.ecf.lists\n"
- " Note: Any settings will be prepended with <host>.<port>.\n"
- "ECF_TASK_THRESHOLD:\n"
- " The Job generation process is expected to take less than 60 seconds\n"
- " This is used to aid debugging of task tasking excessive times for job generation\n"
- " The causes can be:\n"
- " a/ Slow disk I/0, or when server is run an a virtual machine\n"
- " b/ Insufficient memory, when compared to the size of the scripts/definition\n"
- " c/ Large number of jobs submitted at the same time, and/or very large scripts\n"
- " Any task taking longer than the specified time in milliseconds will be logged.\n"
- " WAR:[..] Job generation for task /suite/family/dodgy_task took 5000ms, Exceeds ECF_TASK_THRESHOLD(4000ms)\n"
- " The default threshold is 4000 milliseconds\n"
- " Note: 1000 milliseconds = 1 second\n"
- " export ECF_TASK_THRESHOLD=1500\n"
- "\n"
- "These defaults along with several other can be specified in the file\n"
- "server_environment.cfg. The file should be placed in the current working\n"
- "directory. It can be found in ecFlow source tree under Server/ directory.\n"
- "Please read this file to see the available options.\n"
- "Note: Environment variables _override_ any settings made in the\n"
- "server_environment.cfg file."
-)
-( "port", po::value< int >(), "<int> <Allowed range 1024-49151> The socket/port the server is listening too. default = 3141\n"
- "If set will override the environment variable ECF_PORT"
-)
-( "ecfinterval", po::value< int >(), "<int> <Allowed range 1-60> Submit jobs interval. For DEBUG/Test only" )
-#ifdef ECFLOW_MT
-( "threads", po::value< int >(), "<int> No of threads used by the server. Default is no of cores on machine" )
-#endif
-( "v6", "Use IPv6 TCP protocol. Default is IPv4" )
-( "dis_job_gen", "Disable job generation. For DEBUG/Test only." )
-( "debug,d", "Enable debug output." )
-( "version,v", "Show ecflow version number,boost library version, compiler used and compilation date, then exit" )
- ;
-
- po::store( po::parse_command_line( argc, argv, desc ), vm_ );
- po::notify( vm_ );
-
- if ( vm_.count( "help" ) ) cout << desc << "\n";
-
- if ( vm_.count( "version" ) ) {
- cout << Version::description() << "\n";
- }
-
- if ( vm_.count( "debug" ) ) env->debug_ = true;
-
-
- if ( vm_.count( "port" ) ) {
- if (env->debug_) cout << "ServerOptions:: The port number set to '" << vm_["port"].as< int > () << "'\n";
- env->serverPort_ = vm_["port"].as< int > ();
- }
- if ( vm_.count( "ecfinterval" ) ) {
- if (env->debug_) cout << "ServerOptions: The ecfinterval set to '" << vm_["ecfinterval"].as< int > () << "'\n";
- env->submitJobsInterval_ = vm_["ecfinterval"].as< int > ();
- }
- if ( vm_.count( "v6" ) ) {
- if (env->debug_) cout << "ServerOptions: The tcp protocol set to v6\n";
- env->tcp_protocol_ = boost::asio::ip::tcp::v6();
- }
- if ( vm_.count( "dis_job_gen" ) ) {
- if (env->debug_) cout << "ServerOptions: The dis_job_gen is set\n";
- env->jobGeneration_ = false;
- }
-
-#ifdef ECFLOW_MT
- if ( vm_.count( "threads" ) ) {
- if (env->debug_) cout << "ServerOptions: The numbers of threads set to '" << vm_["threads"].as< int > () << "'\n";
- env->threads_ = vm_["threads"].as< int > ();
- }
-#endif
-}
-
-bool ServerOptions::help_option() const
-{
- if ( vm_.count( "help" ) ) return true;
- return false;
-}
-
-bool ServerOptions::version_option() const
-{
- if ( vm_.count( "version" ) ) return true;
- return false;
-}
diff --git a/ecflow_4_0_7/Server/src/ServerOptions.hpp b/ecflow_4_0_7/Server/src/ServerOptions.hpp
deleted file mode 100644
index eb4f4e9..0000000
--- a/ecflow_4_0_7/Server/src/ServerOptions.hpp
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef SERVER_OPTIONS_HPP_
-#define SERVER_OPTIONS_HPP_
-
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-// Name : ServerOptions
-// Author : Avi
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//
-// This class will parse the server arguments
-// It will update the ServerEnvironment
-/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
-
-#include <boost/program_options.hpp>
-#include <boost/noncopyable.hpp>
-
-class ServerEnvironment;
-
-class ServerOptions : private boost::noncopyable {
-public:
- ServerOptions(int argc, char* argv[], ServerEnvironment*);
-
- /// return true if help selected, else false
- bool help_option() const;
- bool version_option() const;
-
-private:
- boost::program_options::variables_map vm_;
-};
-#endif
diff --git a/ecflow_4_0_7/Server/test/TestServer1.cpp b/ecflow_4_0_7/Server/test/TestServer1.cpp
deleted file mode 100644
index c0516a0..0000000
--- a/ecflow_4_0_7/Server/test/TestServer1.cpp
+++ /dev/null
@@ -1,135 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #14 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <iostream>
-#include <fstream>
-#include <stdlib.h>
-
-#include <boost/test/unit_test.hpp>
-#include <boost/lexical_cast.hpp>
-#include <boost/foreach.hpp>
-#include "boost/filesystem/operations.hpp"
-
-#include "ServerEnvironment.hpp"
-#include "Log.hpp"
-#include "Host.hpp"
-#include "Str.hpp"
-#include "Ecf.hpp"
-#include "File.hpp"
-#include "Server.hpp"
-#include "Defs.hpp"
-
-using namespace std;
-using namespace ecf;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( TestServer )
-
-// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-// make public the function we wish to test:
-// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-class TestServer : public Server {
-public:
- TestServer(ServerEnvironment& s) : Server(s) {}
- virtual ~TestServer() {}
-
- // abort server if check pt files exist, but can't be loaded
- // bool load_check_pt_file_on_startup();
- // void loadCheckPtFile();
- // bool restore_from_checkpt(const std::string& filename, bool& failed);
- // void set_server_state(SState::State);
-
- /// AbstractServer functions
- virtual SState::State state() const { return Server::state(); }
- virtual std::pair<std::string,std::string> hostPort() const { return Server::hostPort(); }
- virtual defs_ptr defs() const { return Server::defs();}
- // virtual void updateDefs(defs_ptr,bool force);
- virtual void clear_defs() { Server::clear_defs();}
- // virtual void checkPtDefs(ecf::CheckPt::Mode m = ecf::CheckPt::UNDEFINED,
- // int check_pt_interval = 0,
- // int check_pt_save_time_alarm = 0);
- virtual void restore_defs_from_checkpt() { Server::restore_defs_from_checkpt();}
- virtual void nodeTreeStateChanged() { Server::nodeTreeStateChanged(); }
- virtual bool allowTaskCommunication() const { return Server::allowTaskCommunication();}
- virtual void shutdown() { Server::shutdown(); }
- virtual void halted() { Server::halted(); }
- virtual void restart() { Server::restart(); }
- virtual bool reloadWhiteListFile(std::string& errorMsg) { return Server::reloadWhiteListFile(errorMsg);}
- virtual bool authenticateUser(const std::string& user) { return Server::authenticateUser(user); }
- virtual bool authenticateWriteAccess(const std::string& user, bool client_request_can_change_server_state) { return Server::authenticateWriteAccess(user,client_request_can_change_server_state); }
- virtual bool lock(const std::string& user) { return Server::lock(user); }
- virtual void unlock() { Server::unlock();}
- virtual const std::string& lockedUser() const { return Server::lockedUser(); }
- // virtual void traverse_node_tree_and_job_generate(const boost::posix_time::ptime& time_now, bool user_cmd_context) const;
- virtual int poll_interval() const { return Server::poll_interval();}
- // virtual void debug_server_on();
- // virtual void debug_server_off();
- // virtual bool debug() const;
-};
-
-
-BOOST_AUTO_TEST_CASE( test_server )
-{
- cout << "Server:: ...test_server\n";
-
- int argc = 3;
- char* argv[] = { const_cast<char*>("ServerEnvironment"),
- const_cast<char*>("--port=3144"),
- const_cast<char*>("--ecfinterval=12")
- };
-
- ServerEnvironment server_environment(argc, argv); // This can throw ServerEnvironmentException
- std::string errorMsg;
- BOOST_CHECK_MESSAGE(server_environment.valid(errorMsg),errorMsg);
-
- {
- TestServer theServer( server_environment ); // This can throw exception, bind address in use.
-
- BOOST_REQUIRE_MESSAGE(theServer.defs(),"Expected defs to be created");
-
- const std::vector<Variable>& server_variables = theServer.defs()->server().server_variables();
- BOOST_REQUIRE_MESSAGE(!server_variables.empty(),"Expected defs to be updated with the server variables");
-
- //for(size_t i = 0; i < server_variables.size(); ++i) cout << server_variables[i].dump() << "\n";
- const std::string& ecf_port = theServer.defs()->server().find_variable("ECF_PORT");
- BOOST_REQUIRE_MESSAGE(ecf_port == "3144","Expected port 3144 but found " << ecf_port << " defs server variables, should be in sync with server");
-
-
- const std::string& interval = theServer.defs()->server().find_variable("ECF_INTERVAL");
- BOOST_REQUIRE_MESSAGE(interval == "12","Expected interval 12 but found " << interval << " defs server variables, should be in sync with server");
- BOOST_REQUIRE_MESSAGE(theServer.poll_interval() == 12,"Expected poll interval 12 but found " << theServer.poll_interval());
-
-
- BOOST_REQUIRE_MESSAGE(theServer.state() == SState::HALTED,"Expected halted at server start but found " << SState::to_string(theServer.state()));
- theServer.halted(); BOOST_REQUIRE_MESSAGE(theServer.state() == SState::HALTED,"Expected halted ");
- theServer.shutdown(); BOOST_REQUIRE_MESSAGE(theServer.state() == SState::SHUTDOWN,"Expected shutdown ");
- theServer.restart(); BOOST_REQUIRE_MESSAGE(theServer.state() == SState::RUNNING,"Expected shutdown ");
-
-
- BOOST_REQUIRE_MESSAGE(theServer.lock("fred"),"Expected to lock user fred");
- BOOST_REQUIRE_MESSAGE(theServer.state() == SState::SHUTDOWN,"Locking should shutdown server");
- BOOST_REQUIRE_MESSAGE(theServer.lockedUser() == "fred","Expected locked user 'fred' but found " << theServer.lockedUser());
- theServer.unlock();
- BOOST_REQUIRE_MESSAGE(theServer.lockedUser().empty(),"Expected no locked user but found " << theServer.lockedUser());
- BOOST_REQUIRE_MESSAGE(theServer.state() == SState::RUNNING,"Expected unlock to restart server ");
- }
-
- Host h;
- fs::remove(h.ecf_log_file(Str::DEFAULT_PORT_NUMBER()));
-
- /// Destroy Log singleton to avoid valgrind from complaining
- Log::destroy();
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Server/test/TestServerEnvironment.cpp b/ecflow_4_0_7/Server/test/TestServerEnvironment.cpp
deleted file mode 100644
index a1205d5..0000000
--- a/ecflow_4_0_7/Server/test/TestServerEnvironment.cpp
+++ /dev/null
@@ -1,364 +0,0 @@
-#define BOOST_TEST_MODULE Server
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #14 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <iostream>
-#include <fstream>
-#include <stdlib.h>
-
-#include <boost/test/unit_test.hpp>
-#include <boost/lexical_cast.hpp>
-#include <boost/foreach.hpp>
-#include "boost/filesystem/operations.hpp"
-
-#include "ServerEnvironment.hpp"
-#include "Log.hpp"
-#include "Host.hpp"
-#include "Str.hpp"
-#include "Ecf.hpp"
-#include "File.hpp"
-#include "CheckPt.hpp"
-#include "JobProfiler.hpp"
-
-using namespace std;
-using namespace ecf;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( TestServer )
-
-
-BOOST_AUTO_TEST_CASE( test_server_environment_ecfinterval )
-{
- cout << "Server:: ...test_server_environment_ecfinterval\n";
-
- // ecflow server interval is valid for range [1-60]
- for(int i=-10; i< 70; ++i)
- {
- string errorMsg;
- string argument = "--ecfinterval=" + boost::lexical_cast<std::string>(i);
-
- int argc = 2;
- char* argv[] = { const_cast<char*>("ServerEnvironment"), const_cast<char*>(argument.c_str()) };
- ServerEnvironment serverEnv(argc,argv);
- bool valid = serverEnv.valid(errorMsg);
- if (i > 0 && i < 61) {
- BOOST_REQUIRE_MESSAGE(valid,"Server environment ecfinterval valid range is [1-60] " << errorMsg);
- BOOST_CHECK_MESSAGE(serverEnv.submitJobsInterval() == i,"Expected submit jobs interval of " << i << " but found " << serverEnv.submitJobsInterval());
- }
- else BOOST_CHECK_MESSAGE(!valid,"Server environment ecfinterval valid range is [1-60] " << errorMsg);
- }
-
- Host h;
- fs::remove(h.ecf_log_file(Str::DEFAULT_PORT_NUMBER()));
-}
-
-BOOST_AUTO_TEST_CASE( test_server_environment_port )
-{
- cout << "Server:: ...test_server_environment_port\n";
-
- // The port numbers are divided into three ranges.\n";
- // o the Well Known Ports, (require root permission) 0 -1023\n";
- // o the Registered Ports, 1024 -49151\n";
- // o Dynamic and/or Private Ports. 49151 -65535\n\n";
- // Please set in the range 1024-49151 via argument or \n";
- Host h;
- int argc = 2;
- {
- std::string errorMsg;
- char* argv[] = { const_cast<char*>("ServerEnvironment"), const_cast<char*>("--port=0") };
- ServerEnvironment serverEnv(argc,argv);
- BOOST_CHECK_MESSAGE(!serverEnv.valid(errorMsg)," Server environment not valid " << errorMsg);
- fs::remove(h.ecf_log_file("0"));
- }
- {
- std::string errorMsg;
- char* argv[] = { const_cast<char*>("ServerEnvironment"), const_cast<char*>("--port=1000") };
- ServerEnvironment serverEnv(argc,argv);
- BOOST_CHECK_MESSAGE(!serverEnv.valid(errorMsg)," Server environment not valid " << errorMsg);
- fs::remove(h.ecf_log_file("1000"));
- }
- {
- std::string errorMsg;
- char* argv[] = { const_cast<char*>("ServerEnvironment"), const_cast<char*>("--port=49151") };
- ServerEnvironment serverEnv(argc,argv);
- BOOST_CHECK_MESSAGE(!serverEnv.valid(errorMsg)," Server environment not valid " << errorMsg);
- fs::remove(h.ecf_log_file("49151"));
- }
-
- {
- std::string errorMsg;
- char* argv[] = { const_cast<char*>("ServerEnvironment"), const_cast<char*>("--port=3144") };
- ServerEnvironment serverEnv(argc,argv);
- BOOST_CHECK_MESSAGE(serverEnv.valid(errorMsg)," Server environment not valid " << errorMsg);
- BOOST_CHECK_MESSAGE(serverEnv.port() == 3144,"Expected 3144 but found " << serverEnv.port());
- fs::remove(h.ecf_log_file("3144"));
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_server_environment_log_file )
-{
- // Regression test log file creation
- cout << "Server:: ...test_server_environment_log_file\n";
-
- int argc = 2;
- char* argv[] = { const_cast<char*>("ServerEnvironment"), const_cast<char*>("--port=3144") };
- ServerEnvironment serverEnv(argc,argv);
-
- BOOST_CHECK_MESSAGE(Log::instance(), "Log singleton not created");
- BOOST_CHECK_MESSAGE(fs::exists(Log::instance()->path()), "Log file not created");
-
- // Check that server variable ECF_LOG created and value is correct
- std::vector<std::pair<std::string,std::string> > server_vars;
- serverEnv.variables(server_vars);
-
- bool found_var = false;
- typedef std::pair<std::string, std::string> mpair;
- BOOST_FOREACH(const mpair& p, server_vars ) {
- if (Str::ECF_LOG() == p.first) {
- BOOST_CHECK_MESSAGE(p.second == Log::instance()->path(),"Expected " << Log::instance()->path() << " but found " << p.second);
- found_var = true;
- break;
- }
- }
- BOOST_CHECK_MESSAGE(found_var,"Failed to find server variable ECF_LOG");
-
- // tear down remove the log file created by ServerEnvironment
- Host h;
- fs::remove(h.ecf_log_file("3144"));
-
- /// Destroy Log singleton to avoid valgrind from complaining
- Log::destroy();
-}
-
-BOOST_AUTO_TEST_CASE( test_server_config_file )
-{
- // Regression test to make sure the server environment variable don't get removed
- cout << "Server:: ...test_server_config_file\n";
-
- int argc = 1;
- char* argv[] = { const_cast<char*>("ServerEnvironment") };
-
- ServerEnvironment serverEnv(argc,argv,File::test_data("Server/server_environment.cfg","Server"));
-
- // expected variables
- std::vector<std::string> expected_variables;
- expected_variables.push_back( Str::ECF_HOME() );
- expected_variables.push_back( "ECF_LOG" );
- expected_variables.push_back( "ECF_CHECK" );
- expected_variables.push_back( "ECF_CHECKOLD" );
- expected_variables.push_back( "ECF_JOB_CMD" );
- expected_variables.push_back( "ECF_KILL_CMD" );
- expected_variables.push_back( "ECF_STATUS_CMD" );
- expected_variables.push_back( "ECF_URL_CMD" );
- expected_variables.push_back( "ECF_URL_BASE" );
- expected_variables.push_back( "ECF_URL" );
- expected_variables.push_back( "ECF_MICRO" );
- expected_variables.push_back( "ECF_PID" );
- expected_variables.push_back( "ECF_VERSION" );
- expected_variables.push_back( "ECF_LISTS" );
- expected_variables.push_back( Str::ECF_PORT() );
- expected_variables.push_back( "ECF_NODE");
- expected_variables.push_back( "ECF_INTERVAL");
-
- std::vector<std::pair<std::string,std::string> > server_vars;
- serverEnv.variables(server_vars);
- BOOST_FOREACH(const std::string& expected_var, expected_variables) {
-
- bool found_var = false;
- typedef std::pair<std::string, std::string> s_pair;
- BOOST_FOREACH(const s_pair& p, server_vars ) {
- if (expected_var == p.first) { found_var = true; break; }
- }
- BOOST_CHECK_MESSAGE(found_var,"Failed to find server var " << expected_var);
- }
-
- {
- // check other way, so that this test gets updated
- typedef std::pair<std::string, std::string> mpair;
- BOOST_FOREACH(const mpair& p, server_vars ) {
- bool found_var = false;
- BOOST_FOREACH(const std::string& expected_var, expected_variables) {
- if (expected_var == p.first) { found_var = true; break; }
- }
- BOOST_CHECK_MESSAGE(found_var,"Failed to update test for server var " << p.first);
- }
- }
-
- // Check the values in the server config file, are the *SAME* as the defaults, when config is *NOT* present
- // Please note do *NOT* use quotes for the values, otherwise quotes get added.
- // WRONG: ECF_MICRODEF = "%"
- // RIGHT: ECF_MICRODEF = %
- // o IGNORE ECF_CHECK: We *ONLY check those value in the config, that should not be altered.
- // since we add root path, and append with host/port
- // o ignore ECF_CHECKMODE: not a server variable
- //
- typedef std::pair<std::string, std::string> mpair;
- BOOST_FOREACH(const mpair& p, server_vars ) {
- //std::cout << "server variables " << p.first << " " << p.second << "\n";
- if (Str::ECF_HOME() == p.first) {
- BOOST_CHECK_MESSAGE(p.second == fs::current_path().string(),"for ECF_HOME expected " << fs::current_path().string() << " but found " << p.second);
- continue;
- }
- if (string("ECF_PORT") == p.first && !getenv("ECF_PORT")) {
- BOOST_CHECK_MESSAGE(p.second == Str::DEFAULT_PORT_NUMBER(),"for ECF_PORT expected " << Str::DEFAULT_PORT_NUMBER() << " but found " << p.second);
- continue;
- }
- if (string("ECF_CHECKINTERVAL") == p.first) {
- std::string expected = boost::lexical_cast<std::string>(CheckPt::default_interval());
- BOOST_CHECK_MESSAGE(p.second == expected,"for ECF_CHECKINTERVAL expected " << CheckPt::default_interval() << " but found " << p.second);
- continue;
- }
- if (string("ECF_INTERVAL") == p.first) {
- std::string expected = "60";
- BOOST_CHECK_MESSAGE(p.second == expected,"for ECF_INTERVAL expected " << expected << " but found " << p.second);
- continue;
- }
- if (string("ECF_JOB_CMD") == p.first) {
- std::string expected = Ecf::JOB_CMD();
- BOOST_CHECK_MESSAGE(p.second == expected,"for ECF_JOB_CMD expected " << expected << " but found " << p.second);
- continue;
- }
- if (string("ECF_KILL_CMD") == p.first) {
- std::string expected = Ecf::KILL_CMD();
- BOOST_CHECK_MESSAGE(p.second == expected,"for ECF_KILL_CMD expected " << expected << " but found " << p.second);
- continue;
- }
- if (string("ECF_STATUS_CMD") == p.first) {
- std::string expected = Ecf::STATUS_CMD();
- BOOST_CHECK_MESSAGE(p.second == expected,"for ECF_STATUS_CMD expected " << expected << " but found " << p.second);
- continue;
- }
- if (string("ECF_URL_CMD") == p.first) {
- std::string expected = Ecf::URL_CMD();
- BOOST_CHECK_MESSAGE(p.second == expected,"for ECF_URL_CMD expected " << expected << " but found " << p.second);
- continue;
- }
- if (string("ECF_URL_BASE") == p.first) {
- std::string expected = Ecf::URL_BASE();
- BOOST_CHECK_MESSAGE(p.second == expected,"for ECF_URL_BASE expected " << expected << " but found " << p.second);
- continue;
- }
- if (string("ECF_URL") == p.first) {
- std::string expected = Ecf::URL();
- BOOST_CHECK_MESSAGE(p.second == expected,"for ECF_URL expected " << expected << " but found " << p.second);
- continue;
- }
- if (string("ECF_MICRODEF") == p.first) {
- std::string expected = Ecf::MICRO();
- BOOST_CHECK_MESSAGE(p.second == expected,"for ECF_MICRODEF expected " << expected << " but found " << p.second);
- continue;
- }
- }
-
- // tear down remove the log file created by ServerEnvironment
- Host host;
- fs::remove(host.ecf_log_file(Str::DEFAULT_PORT_NUMBER()));
-}
-
-
-BOOST_AUTO_TEST_CASE( test_server_environment_variables )
-{
- // Regression test to make sure the server environment variable don't get removed
- cout << "Server:: ...test_server_environment_variables\n";
-
- int argc = 2;
- char* argv[] = { const_cast<char*>("ServerEnvironment"), const_cast<char*>("--port=3144") };
- ServerEnvironment serverEnv(argc,argv);
-
- // expected variables
- std::vector<std::string> expected_variables;
- expected_variables.push_back( Str::ECF_HOME() );
- expected_variables.push_back( "ECF_LOG" );
- expected_variables.push_back( "ECF_CHECK" );
- expected_variables.push_back( "ECF_CHECKOLD" );
- expected_variables.push_back( "ECF_JOB_CMD" );
- expected_variables.push_back( "ECF_KILL_CMD" );
- expected_variables.push_back( "ECF_STATUS_CMD" );
- expected_variables.push_back( "ECF_URL_CMD" );
- expected_variables.push_back( "ECF_URL_BASE" );
- expected_variables.push_back( "ECF_URL" );
- expected_variables.push_back( "ECF_MICRO" );
- expected_variables.push_back( "ECF_PID" );
- expected_variables.push_back( "ECF_VERSION" );
- expected_variables.push_back( "ECF_LISTS" );
- expected_variables.push_back( Str::ECF_PORT() );
- expected_variables.push_back( "ECF_NODE");
- expected_variables.push_back( "ECF_INTERVAL");
-
- std::vector<std::pair<std::string,std::string> > server_vars;
- serverEnv.variables(server_vars);
- BOOST_FOREACH(const std::string& expected_var, expected_variables) {
-
- bool found_var = false;
- typedef std::pair<std::string, std::string> mpair;
- BOOST_FOREACH(const mpair& p, server_vars ) {
- if (expected_var == p.first) { found_var = true; break; }
- }
- BOOST_CHECK_MESSAGE(found_var,"Failed to find server var " << expected_var);
- }
-
- // check other way, so that this test gets updated
- typedef std::pair<std::string, std::string> mpair;
- BOOST_FOREACH(const mpair& p, server_vars ) {
- bool found_var = false;
- BOOST_FOREACH(const std::string& expected_var, expected_variables) {
- if (expected_var == p.first) { found_var = true; break; }
- }
- BOOST_CHECK_MESSAGE(found_var,"Failed to update test for server var " << p.first);
- }
-
- // tear down remove the log file created by ServerEnvironment
- Host h;
- fs::remove(h.ecf_log_file("3144"));
-
- /// Destroy Log singleton to avoid valgrind from complaining
- Log::destroy();
-}
-
-BOOST_AUTO_TEST_CASE( test_server_profile_threshold_environment_variable )
-{
- cout << "Server:: ...test_server_profile_threshold_environment_variable\n";
- int argc = 1;char* argv[] = { const_cast<char*>("ServerEnvironment") };
- {
- char* put = const_cast<char*>("ECF_TASK_THRESHOLD=9");
- BOOST_CHECK_MESSAGE(putenv(put) == 0,"putenv failed for " << put);
-
- ServerEnvironment serverEnv(argc,argv);
- BOOST_CHECK_MESSAGE(JobProfiler::task_threshold() == 9,"Expected task threshold of 9 but found " << JobProfiler::task_threshold());
- }
-
- // ==================================================================================
- // Note test for errors
- vector<string> dodgy_thresholds;
- dodgy_thresholds.push_back("ECF_TASK_THRESHOLD=x");
- dodgy_thresholds.push_back("ECF_TASK_THRESHOLD=,");
- dodgy_thresholds.push_back("ECF_TASK_THRESHOLD=:");
- dodgy_thresholds.push_back("ECF_TASK_THRESHOLD=,,");
-
- for(size_t i =0; i < dodgy_thresholds.size(); i++) {
- //cout << "check -------> " << dodgy_thresholds[i] << endl;
- BOOST_CHECK_MESSAGE(putenv(const_cast<char*>(dodgy_thresholds[i].c_str())) == 0,"putenv failed for " << dodgy_thresholds[i]);
- BOOST_CHECK_THROW(ServerEnvironment serverEnv(argc,argv), std::runtime_error );
- }
-
- putenv(const_cast<char*>("ECF_TASK_THRESHOLD")); // remove from env, otherwise valgrind complains
-
- Host h;
- fs::remove(h.ecf_log_file(Str::DEFAULT_PORT_NUMBER()));
-
- /// Destroy Log singleton to avoid valgrind from complaining
- Log::destroy();
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Test/CMakeLists.txt b/ecflow_4_0_7/Test/CMakeLists.txt
deleted file mode 100644
index 707ee8c..0000000
--- a/ecflow_4_0_7/Test/CMakeLists.txt
+++ /dev/null
@@ -1,75 +0,0 @@
-# =======================================================
-# to list all sources to build use:
-# cd $WK/Test
-# find src -name \*.cpp -print | sort
-# =======================================================
-file( GLOB srcs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp" )
-
-# This library is used for the syste, level testing, hence can include test directories
-ecbuild_add_library( TARGET libharness
- NOINSTALL
- TYPE STATIC
- SOURCES ${srcs}
- LIBS libclient base libparser node nodeattr core
- INCLUDES src
- ../ACore/src
- ../ANattr/src
- ../ANode/src
- ../ANode/test
- ../AParser/src
- ../Base/src
- ../Base/src/cts
- ../Base/src/stc
- ../Base/test
- ../Client/src
- ../Client/test
- )
-
-# =================================================================
-# test
-list( APPEND test_srcs
-./TestAbortCmd.cpp
-./TestAlias.cpp
-./TestClkSync.cpp
-./TestComplete.cpp
-./TestCron.cpp
-./TestCtsWaitCmd.cpp
-./TestEvents.cpp
-./TestFileCmd.cpp
-./TestHandle.cpp
-./TestKillCmd.cpp
-./TestLate.cpp
-./TestLimit.cpp
-./TestOrderCmd.cpp
-./TestRepeat.cpp
-./TestRequeueNode.cpp
-./TestRunner.cpp
-./TestServer.cpp
-./TestSuspend.cpp
-./TestToday.cpp
-./TestTrigger.cpp
-./TestWhyCmd.cpp
-./Test_Time.cpp
-)
-ecbuild_add_test( TARGET s_test
- BOOST
- SOURCES ${test_srcs}
- LIBS libharness
- TEST_DEPENDS s_client
- )
-
-
-ecbuild_add_test( TARGET s_test_zombies
- BOOST
- SOURCES ./TestZombies.cpp
- LIBS libharness
- TEST_DEPENDS s_test
- )
-
-# This test runs forever, hence not suitable for unit test.
-#ecbuild_add_test( TARGET singletest
-# BOOST
-# SOURCES ./TestSingle.cpp
-# LIBS libharness
-# TEST_DEPENDS s_client
-# )
diff --git a/ecflow_4_0_7/Test/DummyMain.cpp b/ecflow_4_0_7/Test/DummyMain.cpp
deleted file mode 100644
index 75f9df5..0000000
--- a/ecflow_4_0_7/Test/DummyMain.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-
-int main() { return 0; }
diff --git a/ecflow_4_0_7/Test/Jamfile.jam b/ecflow_4_0_7/Test/Jamfile.jam
deleted file mode 100644
index a2f253b..0000000
--- a/ecflow_4_0_7/Test/Jamfile.jam
+++ /dev/null
@@ -1,115 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-project theTest ;
-
-#
-# Test project
-#
-use-project theCore : ../ACore ;
-use-project theNodeAttr : ../ANattr ;
-use-project theNode : ../ANode ;
-use-project theParser : ../AParser ;
-use-project theBase : ../Base ;
-use-project theServer : ../Server ;
-use-project theClient : ../Client ;
-
-lib pthread ;
-
-#
-# Split into library, so that testing can use library, and hence same compiler option
-#
-# The <include> means we will automatically add this directory to the include path
-# of any other target that uses this lib
-#
-lib libharness : [ glob src/*.cpp ]
- : <include>../ACore/src
- <include>../ANattr/src
- <include>../ANode/src
- <include>../AParser/src
- <include>../Base/src
- <include>../Base/test
- <include>../Client/src
- <include>../Client/test
- <variant>debug:<define>DEBUG
- <link>static
- <use>/theCore//core
- <use>/theNodeAttr//nodeattr
- <use>/theNode//node
- <use>/theBase//base
- <use>/theParser//libparser
- <use>/theClient//libclient
- <use>/site-config//boost_system
- <use>/site-config//boost_serialization
- <use>/site-config//boost_filesystem
- <use>/site-config//boost_program_options
- <use>/site-config//boost_datetime
- :
- : <include>../Test/src
- ;
-
-# Ignore TestSingle.cpp, used for standalone testing
-exe s_test : [ glob Test*.cpp : TestSingle.cpp TestZombies.cpp ]
- pthread
- /theCore//core
- /theNodeAttr//nodeattr
- /theNode//node
- /theParser//libparser
- /theBase//base
- /theClient//libclient
- libharness
- /site-config//boost_system
- /site-config//boost_serialization
- /site-config//boost_filesystem
- /site-config//boost_program_options
- /site-config//boost_datetime
- /site-config//boost_test
- : <include>../Base/test
- <variant>debug:<define>DEBUG
- ;
-
-# Split because this was more error prone, Now stabilised all all platforms ?
-exe s_test_zombies : [ glob TestZombies.cpp ]
- pthread
- /theCore//core
- /theNodeAttr//nodeattr
- /theNode//node
- /theParser//libparser
- /theBase//base
- /theClient//libclient
- libharness
- /site-config//boost_system
- /site-config//boost_serialization
- /site-config//boost_filesystem
- /site-config//boost_program_options
- /site-config//boost_datetime
- /site-config//boost_test
- : <include>../Base/test
- <variant>debug:<define>DEBUG
- ;
-
-# use for standalone testing
-exe singletest : [ glob TestSingle.cpp ]
- pthread
- /theCore//core
- /theNodeAttr//nodeattr
- /theNode//node
- /theParser//libparser
- /theBase//base
- /theClient//libclient
- libharness
- /site-config//boost_system
- /site-config//boost_serialization
- /site-config//boost_filesystem
- /site-config//boost_program_options
- /site-config//boost_datetime
- /site-config//boost_test
- : <include>../Base/test
- <variant>debug:<define>DEBUG
- ;
-
-
\ No newline at end of file
diff --git a/ecflow_4_0_7/Test/TestAbortCmd.cpp b/ecflow_4_0_7/Test/TestAbortCmd.cpp
deleted file mode 100644
index 3910bdb..0000000
--- a/ecflow_4_0_7/Test/TestAbortCmd.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include "ServerTestHarness.hpp"
-#include "TestFixture.hpp"
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "DurationTimer.hpp"
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/test/unit_test.hpp>
-#include <boost/lexical_cast.hpp>
-
-#include <iostream>
-#include <fstream>
-#include <stdlib.h>
-
-using namespace std;
-using namespace ecf;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( TestSuite )
-
-// Test the abort command. This will test the abort command and the
-// retry behaviour. i.e if a task is aborted, and the variable ECF_TRIES
-// is defined. Then providing its value is less the the task's try number
-// we should do an immediate job submission.
-BOOST_AUTO_TEST_CASE( test_ )
-{
- DurationTimer timer;
- cout << "Test:: ...test_abort_cmd "<< flush;
- TestClean clean_at_start_and_end;
-
- // Create the defs file corresponding to the text below
- // ECF_HOME variable is automatically added by the test harness.
- // ECF_INCLUDE variable is automatically added by the test harness.
- // SLEEPTIME variable is automatically added by the test harness.
- // ECF_CLIENT_EXE_PATH variable is automatically added by the test harness.
- // This is substituted in ecf includes
- // Allows test to run without requiring installation
-
- //# Note: we have to use relative paths, since these tests are relocatable
- // suite test_task_abort_cmd
- // edit ECF_TRIES '4'
- // family family0
- // task abort
- // endfamily
- // endsuite
- Defs theDefs;
- {
- suite_ptr suite = theDefs.add_suite("test_abort_cmd");
- suite->addVariable( Variable("ECF_TRIES","4") );
- family_ptr fam0 = suite->add_family("family0");
- task_ptr abort = fam0->add_task("abort");
- abort->addVerify( VerifyAttr(NState::ABORTED,3) ); // task should abort 3 times & succeed on 4th attempt
- abort->addVerify( VerifyAttr(NState::COMPLETE,1) );// task should complete 1 times
- }
-
- // Create a custom ecf file for test_task_abort_cmd/family0/abort to invoke the child abort command
- std::string templateEcfFile;
- templateEcfFile += "%include <head.h>\n";
- templateEcfFile += "\n";
- templateEcfFile += "echo do some work\n";
- templateEcfFile += "if [ %ECF_TRYNO% -le 3 ] ; then\n";
- templateEcfFile += " %ECF_CLIENT_EXE_PATH% --abort=\"expected abort at task try no %ECF_TRYNO%\"\n";
- templateEcfFile += " trap 0 # Remove all traps\n";
- templateEcfFile += " exit 0 # End the shell before child command complete\n";
- templateEcfFile += "fi\n";
- templateEcfFile += "\n";
- templateEcfFile += "%include <tail.h>\n";
-
- // The test harness will create corresponding directory structure
- // Override the default ECF file, with our custom ECF_ file
- std::map<std::string,std::string> taskEcfFileMap;
- taskEcfFileMap.insert(std::make_pair(TestFixture::taskAbsNodePath(theDefs,"abort"),templateEcfFile));
-
- // Avoid standard verification since we expect to abort many times
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_abort_cmd.def"), taskEcfFileMap);
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Test/TestAlias.cpp b/ecflow_4_0_7/Test/TestAlias.cpp
deleted file mode 100644
index e0a1cbf..0000000
--- a/ecflow_4_0_7/Test/TestAlias.cpp
+++ /dev/null
@@ -1,218 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//
-// This test will TEST:
-// o Alias creation and running
-// o Alias ordering
-// o Alias deletion
-// Will indirectly test the Alias memento's
-//============================================================================
-#include <iostream>
-#include <limits> // for std::numeric_limits<int>::max()
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/lexical_cast.hpp>
-#include <boost/test/unit_test.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include "TestFixture.hpp"
-#include "ServerTestHarness.hpp"
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "DurationTimer.hpp"
-#include "PrintStyle.hpp"
-#include "ClientToServerCmd.hpp"
-#include "DefsStructureParser.hpp"
-#include "AssertTimer.hpp"
-#include "Str.hpp"
-#include "NOrder.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( TestSingleSuite )
-
-template <typename T>
-static std::vector<std::string> toStrVec(const std::vector<T>& vec)
-{
- std::vector<std::string> retVec; retVec.reserve(vec.size());
- BOOST_FOREACH(T s, vec) { retVec.push_back(s->name()); }
- return retVec;
-}
-
-std::string toString(const std::vector<std::string>& c)
-{
- std::stringstream ss;
- std::copy (c.begin(), c.end(), std::ostream_iterator <std::string> (ss, ", "));
- return ss.str();
-}
-
-void wait_for_alias_to_complete(const std::string& alias_path)
-{
- AssertTimer assertTimer(10,false); // Bomb out after 10 seconds, fall back if test fail
- while(1) {
- BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0, "Could not get the defs from server\n" << TestFixture::client().errorMsg());
- defs_ptr defs = TestFixture::client().defs();
- node_ptr alias = defs->findAbsNode(alias_path);
- BOOST_REQUIRE_MESSAGE(alias.get(), "Could not locate created alias at path " << alias_path << "\n" << TestFixture::client().errorMsg());
- if (alias->state() == NState::COMPLETE) break;
- sleep(2);
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_alias )
-{
- DurationTimer timer;
- cout << "Test:: ...test_alias "<< flush;
- TestClean clean_at_start_and_end;
-
- // Create the defs file corresponding to the text below
- // ECF_HOME variable is automatically added by the test harness.
- // ECF_INCLUDE variable is automatically added by the test harness.
- // SLEEPTIME variable is automatically added by the test harness.
- // ECF_CLIENT_EXE_PATH variable is automatically added by the test harness.
- // This is substituted in ecf includes
- // Allows test to run without requiring installation
- Defs theDefs;
- task_ptr task_a;
- {
- suite_ptr suite = theDefs.add_suite( "test_alias" ) ;
- suite->add_variable("SLEEPTIME","0");
- task_a = suite->add_task("task_a");
- task_a->addMeter( Meter("meter",0,20,20) );
- task_a->addEvent( Event(1,"event") );
- task_a->addLabel( Label("task_a_label","Label1") );
- }
-
- // The test harness will create corresponding directory structure & default ecf file
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_alias.def"));
-
- // After the task has completed create a Alias
- TestFixture::client().set_throw_on_error(false);
-
- // Get the ecf script from the current task and use it to create alias
- BOOST_REQUIRE_MESSAGE( TestFixture::client().file(task_a->absNodePath(),CFileCmd::toString(CFileCmd::ECF),"10000") == 0, "Expected to retreive script\n" << TestFixture::client().errorMsg());
- std::string script = TestFixture::client().get_string();
- BOOST_CHECK_MESSAGE( !script.empty(),"script for task " << task_a->absNodePath() << " is empty" );
-
-
- // TEST Alias CREATION and running =============================================================================
- // Split the file into line
- std::vector<std::string> script_lines;
- Str::split(script,script_lines,"\n");
-
- NameValueVec used_variables;
- int result = TestFixture::client().edit_script_submit(task_a->absNodePath(),used_variables,script_lines,true/*create alias*/,true/*run alias*/);
- BOOST_REQUIRE_MESSAGE(result == 0, "Expected alias creation and run to succeed\n" << TestFixture::client().errorMsg());
- std::string alias0_path = task_a->absNodePath() + "/alias0";
-
- // Wait for alias to complete.
- wait_for_alias_to_complete(alias0_path);
-
-//#ifdef DEBUG
-// BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0, "Could not get the defs from server\n" << TestFixture::client().errorMsg());
-// defs_ptr defs = TestFixture::client().defs();
-// PrintStyle::setStyle(PrintStyle::STATE);
-// std::cout << *defs;
-//#endif
-
-
- // TEST ORDERING:: Create another alias, but don't run it. =============================================================================
- result = TestFixture::client().edit_script_submit(task_a->absNodePath(),used_variables,script_lines,true/*create alias*/,false/*run alias*/);
- BOOST_REQUIRE_MESSAGE(result == 0, "Expected alias creation succeed\n" << TestFixture::client().errorMsg());
- {
- BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0, "Could not get the defs from server\n" << TestFixture::client().errorMsg());
- defs_ptr defs = TestFixture::client().defs();
- std::vector<alias_ptr> aliases;
- defs->get_all_aliases(aliases);
- BOOST_REQUIRE_MESSAGE(aliases.size() == 2, "Expected 2 aliases\n" << TestFixture::client().errorMsg());
- }
-
- BOOST_REQUIRE_MESSAGE(TestFixture::client().order(alias0_path, NOrder::toString(NOrder::DOWN)) == 0, "Expected order NOrder::DOWN to succeed\n" << TestFixture::client().errorMsg());
- {
- BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0, "Could not get the defs from server\n" << TestFixture::client().errorMsg());
- defs_ptr defs = TestFixture::client().defs();
- Task* task = defs->findAbsNode(task_a->absNodePath())->isTask();
- BOOST_REQUIRE_MESSAGE( task,"expected to find Task");
-
- std::vector<std::string> expected;
- expected.push_back("alias1");
- expected.push_back("alias0");
- BOOST_REQUIRE_MESSAGE( toStrVec(task->aliases()) == expected,"NOrder::DOWN expected " << toString(expected) << " but found " << toString(toStrVec(task->aliases())) );
- }
-
- BOOST_REQUIRE_MESSAGE(TestFixture::client().order(alias0_path, NOrder::toString(NOrder::UP)) == 0, "Expected order NOrder::UP to succeed\n" << TestFixture::client().errorMsg());
- {
- BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0, "Could not get the defs from server\n" << TestFixture::client().errorMsg());
- defs_ptr defs = TestFixture::client().defs();
- Task* task = defs->findAbsNode(task_a->absNodePath())->isTask();
- BOOST_REQUIRE_MESSAGE( task,"expected to find Task");
-
- std::vector<std::string> expected;
- expected.push_back("alias0");
- expected.push_back("alias1");
- BOOST_REQUIRE_MESSAGE( toStrVec(task->aliases()) == expected,"NOrder::UP expected " << toString(expected) << " but found " << toString(toStrVec(task->aliases())) );
- }
-
- BOOST_REQUIRE_MESSAGE(TestFixture::client().order(alias0_path, NOrder::toString(NOrder::ORDER)) == 0, "Expected order NOrder::ORDER to succeed\n" << TestFixture::client().errorMsg());
- {
- BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0, "Could not get the defs from server\n" << TestFixture::client().errorMsg());
- defs_ptr defs = TestFixture::client().defs();
- Task* task = defs->findAbsNode(task_a->absNodePath())->isTask();
- BOOST_REQUIRE_MESSAGE( task,"expected to find Task");
-
- std::vector<std::string> expected;
- expected.push_back("alias1");
- expected.push_back("alias0");
- BOOST_REQUIRE_MESSAGE( toStrVec(task->aliases()) == expected,"NOrder::ORDER expected " << toString(expected) << " but found " << toString(toStrVec(task->aliases())) );
- }
-
- BOOST_REQUIRE_MESSAGE(TestFixture::client().order(alias0_path, NOrder::toString(NOrder::ALPHA)) == 0, "Expected order NOrder::ALPHA to succeed\n" << TestFixture::client().errorMsg());
- {
- BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0, "Could not get the defs from server\n" << TestFixture::client().errorMsg());
- defs_ptr defs = TestFixture::client().defs();
- Task* task = defs->findAbsNode(task_a->absNodePath())->isTask();
- BOOST_REQUIRE_MESSAGE( task,"expected to find Task");
-
- std::vector<std::string> expected;
- expected.push_back("alias0");
- expected.push_back("alias1");
- BOOST_REQUIRE_MESSAGE( toStrVec(task->aliases()) == expected,"NOrder::ALPHA expected " << toString(expected) << " but found " << toString(toStrVec(task->aliases())) );
- }
-
-
- // TEST Alias DELETION =============================================================================
- std::string alias1_path = task_a->absNodePath() + "/alias1";
- BOOST_REQUIRE_MESSAGE(TestFixture::client().delete_node(alias0_path) == 0, "delete alias0 failed\n" << TestFixture::client().errorMsg());
- BOOST_REQUIRE_MESSAGE(TestFixture::client().delete_node(alias1_path) == 0, "delete alias1 failed\n" << TestFixture::client().errorMsg());
-
- // Get the defs from the server
- BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0, "Could not get the defs from server\n" << TestFixture::client().errorMsg());
- defs_ptr defs = TestFixture::client().defs();
- std::vector<alias_ptr> aliases;
- defs->get_all_aliases(aliases);
- BOOST_REQUIRE_MESSAGE(aliases.empty(), "Alias deletion falied\n" << TestFixture::client().errorMsg());
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Test/TestClkSync.cpp b/ecflow_4_0_7/Test/TestClkSync.cpp
deleted file mode 100644
index 9efd61b..0000000
--- a/ecflow_4_0_7/Test/TestClkSync.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #26 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <iostream>
-#include <fstream>
-#include <stdlib.h>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/test/unit_test.hpp>
-#include <boost/lexical_cast.hpp>
-
-#include "ServerTestHarness.hpp"
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "DurationTimer.hpp"
-
-using namespace std;
-using namespace ecf;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( TestSuite )
-
-
-BOOST_AUTO_TEST_CASE( test_clk_sync )
-{
- // This test is used to test sync'ing of the suite calendars
- // The default clock type is *real*. We will create a suite with a hybrid clock attribute
- // For the suite calendar, we do not persist the clock type(hybrid/real), since this can be
- // obtained from the clock attribute. Hence a hybrid calendar in the server, will arrive as
- // real calendar at the client side. (i.e via the memento). It is then up to the client
- // to update the calendar with clock type stored in the clock attribute.
- // See:void Suite::set_memento( const SuiteCalendarMemento* memento )
- // This test(implicitly) will check that after an incremental sync that suite calendar and
- // suite clock attribute, that both are of the same clock type.
- // This is done in ServerTestHarness via invariant checking.
-
- DurationTimer timer;
- cout << "Test:: ...test_clk_sync "<< flush;
- TestClean clean_at_start_and_end;
-
- // Create the defs file corresponding to the text below
- // ECF_HOME variable is automatically added by the test harness.
- // ECF_INCLUDE variable is automatically added by the test harness.
- // SLEEPTIME variable is automatically added by the test harness.
- // ECF_CLIENT_EXE_PATH variable is automatically added by the test harness.
- // This is substituted in ecf includes
- // Allows test to run without requiring installation
-
- //# Note: we have to use relative paths, since these tests are relocatable
- // suite test_clk_sync
- // clocl hybrid
- // task a
- // meter myMeter 0 100
- // endsuite
- Defs theDefs;
- {
- suite_ptr suite = theDefs.add_suite("test_clk_sync" );
- suite->addClock(ClockAttr(true)); // add hybrid clock
- task_ptr task_a = suite->add_task("a");
- task_a->addMeter( Meter("myMeter",0,100,100) );
- }
-
- // The test harness will create corresponding directory structure & default ecf file
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_clk_sync.def"));
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Test/TestComplete.cpp b/ecflow_4_0_7/Test/TestComplete.cpp
deleted file mode 100644
index 8b5c35b..0000000
--- a/ecflow_4_0_7/Test/TestComplete.cpp
+++ /dev/null
@@ -1,178 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #25 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include "ServerTestHarness.hpp"
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "DurationTimer.hpp"
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/test/unit_test.hpp>
-#include <boost/lexical_cast.hpp>
-
-#include <iostream>
-#include <fstream>
-#include <stdlib.h>
-
-using namespace std;
-using namespace ecf;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( TestSuite )
-
-// In the test case we will dynamically create all the test data.
-// The data is created dynamically so that we can stress test the server
-// This test does not have any time dependencies in the def file.
-//
-// This test shows the use of repeat and complete. this shows how
-// we can repeat a family without waiting for all the children to
-// complete. See page 65 of user manual
-//
-// As protection against user, a family should not complete
-// if any of its children are still in ACTIVE or SUBMIITED state.
-//
-// **************************************************************************
-// Note: When we use a complete expression. Node resolution will set complete
-// hierarchically
-// **************************************************************************
-BOOST_AUTO_TEST_CASE( test_complete )
-{
- DurationTimer timer;
- cout << "Test:: ...test_complete " << flush;
- TestClean clean_at_start_and_end;
-
- // Create the defs file corresponding to the text below
- // ECF_HOME variable is automatically added by the test harness.
- // ECF_INCLUDE variable is automatically added by the test harness.
- // SLEEPTIME variable is automatically added by the test harness.
- // ECF_CLIENT_EXE_PATH variable is automatically added by the test harness.
- // This is substituted in sms includes
- // Allows test to run without requiring installation
-
- //# Note: we have to use relative paths, since these tests are relocatable
- // suite test_complete
- // family family
- // repeat integer YMD 0 1
- // complete ./family/check:nofiles # repeat family with waiting for children to complete
- // task check
- // event 1 nofiles
- // task t1
- // trigger check==complete
- // task t2
- // trigger t2 == complete # never runs
- // endfamily
- // endsuite
- std::string eventName = "nofiles";
- Defs theDefs;
- {
- suite_ptr suite = theDefs.add_suite("test_complete");
- family_ptr fam = suite->add_family("family");
- fam->addRepeat( RepeatInteger("VAR",0,1,1)); // repeat family 2 times
- fam->add_complete( "/test_complete/family/check:nofiles" );
- fam->addVerify( VerifyAttr(NState::COMPLETE,2) ); // family should complete 2 times
-
- task_ptr task_check = fam->add_task("check");
- task_check->addEvent( Event(1,eventName) );
- task_check->addVerify( VerifyAttr(NState::COMPLETE,4) );
-
- task_ptr task_t1 = fam->add_task("t1");
- task_t1->add_trigger( "check == complete");
- task_t1->addVerify( VerifyAttr(NState::COMPLETE,2) );
-
- task_ptr task_t2 = fam->add_task("t2");
- task_t2->add_trigger( "t2 == complete" );
- task_t2->addVerify( VerifyAttr(NState::COMPLETE,2) );
- }
-
- // The test harness will create corresponding directory structure & default ecf file
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs, ServerTestHarness::testDataDefsLocation("test_complete.def") );
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-BOOST_AUTO_TEST_CASE( test_complete_does_not_hold )
-{
- DurationTimer timer;
- cout << "Test:: ...test_complete_does_not_hold " << flush;
-
- /// This test shows that a complete expression should not hold a node
- /// A complete should complete a node, and not hold it
-
- // suite test_complete
- // family family
- // complete 1 == 0 # impossible expression that never evaluates
- // task t1 # task t1 should still run
- // task t2
- // complete 1 == 0 # impossible expression that never evaluates
- // trigger t1 == complete # task t2 should still run
- // endfamily
- // endsuite
- Defs theDefs;
- {
- suite_ptr suite = theDefs.add_suite("test_complete_does_not_hold");
- family_ptr fam = suite->add_family("family");
- fam->add_complete( "1 == 0");
- task_ptr t1 = fam->add_task("t1");
- t1->addVerify( VerifyAttr(NState::COMPLETE,1) );
- task_ptr t2 = fam->add_task("t2");
- t2->add_trigger( "t1 == complete");
- t2->add_complete( "1 == 0");
- t2->addVerify( VerifyAttr(NState::COMPLETE,1) );
- }
-
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs, ServerTestHarness::testDataDefsLocation("test_complete_does_not_hold.def") );
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-BOOST_AUTO_TEST_CASE( test_complete_with_empty_family )
-{
- DurationTimer timer;
- cout << "Test:: ...test_complete_with_empty_family " << flush;
-
- // Test a family with a complete expression and that has no children
-
- // suite test_complete_with_empty_family
- // family empty
- // complete /test_complete_with_empty_family/family/t1 == complete and
- // /test_complete_with_empty_family/family/t2 == complete
- // family family
- // task t1
- // task t2
- // endfamily
- // endsuite
- Defs theDefs;
- {
- suite_ptr suite = theDefs.add_suite("test_complete_with_empty_family");
- family_ptr empty = suite->add_family("empty");
- empty->add_complete( "/test_complete_with_empty_family/family/t1 == complete and /test_complete_with_empty_family/family/t2 == complete");
- empty->addVerify( VerifyAttr(NState::COMPLETE,1) );
- family_ptr fam = suite->add_family("family");
- fam->add_task("t1")->addVerify( VerifyAttr(NState::COMPLETE,1) );
- fam->add_task("t2")->addVerify( VerifyAttr(NState::COMPLETE,1) );
- }
-
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs, ServerTestHarness::testDataDefsLocation("test_complete_with_empty_family.def") );
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Test/TestCron.cpp b/ecflow_4_0_7/Test/TestCron.cpp
deleted file mode 100644
index 0a9f2ce..0000000
--- a/ecflow_4_0_7/Test/TestCron.cpp
+++ /dev/null
@@ -1,145 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #30 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <iostream>
-#include <fstream>
-#include <stdlib.h>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/test/unit_test.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include "ServerTestHarness.hpp"
-#include "TestFixture.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "DurationTimer.hpp"
-#include "AssertTimer.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-
-BOOST_AUTO_TEST_SUITE( TestSuite )
-
-
-static void wait_for_cron( int max_time_to_wait, const std::string& path)
-{
- AssertTimer assertTimer(max_time_to_wait,false); // Bomb out after n seconds, fall back if test fail
- TestFixture::client().set_throw_on_error( false );
- while (1) {
- BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0, "sync_local failed should return 0\n" << TestFixture::client().errorMsg());
- defs_ptr defs = TestFixture::client().defs();
- if (defs) {
- node_ptr node = defs->findAbsNode(path);
- BOOST_REQUIRE_MESSAGE(node, "Could not find task at path " << path );
- if (node) {
- const std::vector<VerifyAttr>& verifys = node->verifys();
- BOOST_REQUIRE_MESSAGE(verifys.size() == 1,"Expected 1 verify");
- if (!verifys.empty()) {
- if ( verifys[0].actual() == verifys[0].expected()) {
- break;
- }
- }
- }
- }
- // make sure test does not take too long.
- if ( assertTimer.duration() >= assertTimer.timeConstraint() ) {
- BOOST_REQUIRE_MESSAGE(assertTimer.duration() < assertTimer.timeConstraint(),
- "wait_for_cron: Test wait " << assertTimer.duration() <<
- " taking longer than time constraint of " << assertTimer.timeConstraint() <<
- " aborting\n" << *defs);
- break;
- }
- sleep(1);
- }
-}
-
-
-BOOST_AUTO_TEST_CASE( test_cron_time_series )
-{
- DurationTimer timer;
- cout << "Test:: ...test_cron_time_series " << flush;
- TestClean clean_at_start_and_end;
-
- // SLOW SYSTEMS
- // for each time attribute leave GAP of 3 * job submission interval
- // on slow systems submitted->active->complete > TestFixture::job_submission_interval()
- // Also the task duration must be greater than job_submission_interval, otherwise
- // we will get multiple invocation for the same time step
-
- //# Note: we have to use relative paths, since these tests are relocatable
- //suite test_cron_time_series
- // edit SLEEPTIME 1
- // edit ECF_INCLUDE $ECF_HOME/includes
- // clock real <todays date>
- // family family
- // task t1
- // cron <start> <finish> <incr>
- // endfamily
- //endsuite
- Defs theDefs;
- std::string path;
- {
- // Initialise clock with todays date and time, then create a cron attribute
- // with a time series, so that task runs 3 times
-
- // Note: we don't use:
- // boost::posix_time::ptime theLocalTime = Calendar::second_clock_time();
- // Because this can fail with:
- // Test:: ...test_cron_time_series unknown location(0): fatal error in
- // "test_cron_time_series": std::out_of_range:
- // TimeSeries::TimeSeries: Invalid time series: Start time(23:58) is greater than end time(00:02)
- // i.e
- // if the test is started at 23:58, then adding the end time of by doing start_time + 5 will fail the check
- boost::posix_time::ptime theLocalTime = boost::posix_time::ptime(date(2010,6,21),time_duration(10,0,0));
- boost::posix_time::ptime time1 = theLocalTime + minutes(1);
- boost::posix_time::ptime time2 = theLocalTime + minutes(5);
-
- suite_ptr suite = theDefs.add_suite("test_cron_time_series");
- ClockAttr clockAttr(theLocalTime, false);
- suite->addClock( clockAttr );
-
- family_ptr fam = suite->add_family("family");
- task_ptr task = fam->add_task("t");
- task->addVerify( VerifyAttr(NState::COMPLETE,3) ); // task should complete 3 times
-
- CronAttr cronAttr;
- cronAttr.addTimeSeries( ecf::TimeSlot(time1.time_of_day()),
- ecf::TimeSlot(time2.time_of_day()),
- ecf::TimeSlot(0,2) );
- task->addCron( cronAttr);
-
- path = task->absNodePath();
- }
-
- // The test harness will create corresponding directory structure
- // and populate with standard ecf files.
- ServerTestHarness serverTestHarness;
- serverTestHarness.add_default_sleep_time(false); // avoid missing time steps due to submit->active->complete > job submission interval
- serverTestHarness.run(theDefs, ServerTestHarness::testDataDefsLocation("test_cron_time_series.def"),1 /* timeout ignored*/, false /*waitForTestCompletion*/);
-
- // crons are *infinite*, just wait for cron to complete 3 times
- wait_for_cron(40,path);
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/Test/TestCtsWaitCmd.cpp b/ecflow_4_0_7/Test/TestCtsWaitCmd.cpp
deleted file mode 100644
index af019a3..0000000
--- a/ecflow_4_0_7/Test/TestCtsWaitCmd.cpp
+++ /dev/null
@@ -1,216 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #11 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <iostream>
-#include <fstream>
-#include <stdlib.h>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/test/unit_test.hpp>
-#include <boost/lexical_cast.hpp>
-
-#include "ServerTestHarness.hpp"
-#include "TestFixture.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "DurationTimer.hpp"
-#include "AssertTimer.hpp"
-
-using namespace std;
-using namespace ecf;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( TestSuite )
-
-static void create_defs(Defs& theDefs, const std::string& suite_name)
-{
- // suite test_wait_cmd
- // family family0
- // task wait
- // family family1
- // task a
- // task b
- // endfamily
- // family family2
- // task aa
- // task bb
- // endfamily
- // endsuite
- suite_ptr suite = theDefs.add_suite(suite_name);
- family_ptr fam0 = suite->add_family("family0");
- task_ptr wait = fam0->add_task("wait");
- wait->addVerify( VerifyAttr(NState::COMPLETE,1) ); // task should complete 1 times
-
- family_ptr fam1 = suite->add_family("family1");
- fam1->add_task( "a" );
- fam1->add_task( "b" );
-
- family_ptr fam2 = suite->add_family("family2");
- fam2->add_task( "aa" );
- fam2->add_task( "bb" );
-}
-
-static bool wait_for_state(
- std::vector< std::pair<std::string,NState::State> >& path_state_vec,
- int max_time_to_wait )
-{
- AssertTimer assertTimer(max_time_to_wait,false); // Bomb out after n seconds, fall back if test fail
- while (1) {
- BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0, "sync_local failed should return 0\n" << TestFixture::client().errorMsg());
- defs_ptr defs = TestFixture::client().defs();
- bool all_states_ok = true;
- for(size_t i =0; i < path_state_vec.size(); ++i) {
- node_ptr node = defs->findAbsNode( path_state_vec[i].first );
- BOOST_REQUIRE_MESSAGE(node,"Could not find path '" << path_state_vec[i].first << "' in the defs\n" << *defs);
- if (node->state() != path_state_vec[i].second) {
- all_states_ok = false;
- break;
- }
- }
- if (all_states_ok) return true;
-
- // make sure test does not take too long.
- if ( assertTimer.duration() >= assertTimer.timeConstraint() ) {
- BOOST_REQUIRE_MESSAGE(assertTimer.duration() < assertTimer.timeConstraint(),
- "wait_for_state: Test wait " << assertTimer.duration() <<
- " taking longer than time constraint of " << assertTimer.timeConstraint() <<
- " aborting\n" << *defs);
- break;
- }
- sleep(1);
- }
- return false;
-}
-
-// Test the wait command. The Wait command is a child command.
-// The wait command is provided an expression. This expression is evaluated
-// in the server. If the evaluate returns false then the client should
-// blocks until the evaluation is true.
-// In this case the job associated with task 'wait' should block until the expression evaluates
-// to true, which should be after the completion of all other tasks
-BOOST_AUTO_TEST_CASE( test_wait_cmd )
-{
- DurationTimer timer;
- cout << "Test:: ...test_wait_cmd "<< flush;
- TestClean clean_at_start_and_end;
-
- Defs theDefs;
- create_defs(theDefs,"test_wait_cmd");
-
- // Create a custom sms file for test_wait_cmd/family0/wait to invoke the child wait command
- // with an expression that forces it to block, until all other tasks complete
- std::string templateEcfFileForWait;
- templateEcfFileForWait += "%include <head.h>\n";
- templateEcfFileForWait += "\n";
- templateEcfFileForWait += "echo do some work\n";
- templateEcfFileForWait += "%ECF_CLIENT_EXE_PATH% --wait=\"../family1/a eq complete and ../family1/b eq complete and ../family2/aa eq complete and ../family2/bb eq complete\"\n";
- templateEcfFileForWait += "\n";
- templateEcfFileForWait += "%include <tail.h>\n";
-
- // The test harness will create corresponding directory structure
- // Override the default ECF_ file, with our custom ECF_ file
- std::map<std::string,std::string> taskEcfFileMap;
- taskEcfFileMap.insert(std::make_pair(TestFixture::taskAbsNodePath(theDefs,"wait"),templateEcfFileForWait));
-
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_wait_cmd.def"), taskEcfFileMap);
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-BOOST_AUTO_TEST_CASE( test_wait_cmd_parse_fail )
-{
- DurationTimer timer;
- cout << "Test:: ...test_wait_cmd_parse_fail "<< flush;
-
- // This time we add a wait expression that
- // should fail to parse, and we should return an error
- // The error should captured by the trap in .ecf script, which will
- // then abort the task
- Defs theDefs;
- create_defs(theDefs,"test_wait_cmd_parse_fail");
-
- // Create a custom ecf file for test_wait_cmd/family0/wait to invoke the child wait command
- std::string templateEcfFileForWait;
- templateEcfFileForWait += "%include <head.h>\n";
- templateEcfFileForWait += "\n";
- templateEcfFileForWait += "echo do some work\n";
- templateEcfFileForWait += "%ECF_CLIENT_EXE_PATH% --wait=\"(((((((((../family1/a eq complete and ../family1/b eq complete and ../family2/aa eq complete and ../family2/bb eq complete\"\n";
- templateEcfFileForWait += "\n";
- templateEcfFileForWait += "%include <tail.h>\n";
-
- std::map<std::string,std::string> taskEcfFileMap;
- taskEcfFileMap.insert(std::make_pair(TestFixture::taskAbsNodePath(theDefs,"wait"),templateEcfFileForWait));
-
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_wait_cmd_parse_fail.def"), taskEcfFileMap,1 /*timeout*/, false/* don't wait for test to finish */);
-
- // wait for family1 and family2 to complete
- std::vector< std::pair<std::string,NState::State> > path_state_vec;
- path_state_vec.push_back( std::make_pair( std::string("/test_wait_cmd_parse_fail/family1"), NState::COMPLETE) );
- path_state_vec.push_back( std::make_pair( std::string("/test_wait_cmd_parse_fail/family2"), NState::COMPLETE) );
- wait_for_state(path_state_vec,10);
-
- // wait for 'wait' task to abort
- path_state_vec.clear();
- path_state_vec.push_back( std::make_pair( std::string("/test_wait_cmd_parse_fail/family0/wait"), NState::ABORTED) );
- wait_for_state(path_state_vec,10);
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-BOOST_AUTO_TEST_CASE( test_wait_cmd_non_existant_paths )
-{
- DurationTimer timer;
- cout << "Test:: ...test_wait_cmd_non_existant_paths "<< flush;
-
- // This time we add a wait expression that should fail
- // because the paths referenced in the expression don't exist
- Defs theDefs;
- create_defs(theDefs,"test_wait_cmd_non_existant_paths");
-
- // Create a custom ecf file for test_wait_cmd/family0/wait to invoke the child wait command
- // NOTE: ../family1/FRED does not exist
- std::string templateEcfFileForWait;
- templateEcfFileForWait += "%include <head.h>\n";
- templateEcfFileForWait += "\n";
- templateEcfFileForWait += "echo do some work\n";
- templateEcfFileForWait += "%ECF_CLIENT_EXE_PATH% --wait=\"../family1/FRED eq complete and ../family1/b eq complete and ../family2/aa eq complete and ../family2/bb eq complete\"\n";
- templateEcfFileForWait += "\n";
- templateEcfFileForWait += "%include <tail.h>\n";
-
- std::map<std::string,std::string> taskEcfFileMap;
- taskEcfFileMap.insert(std::make_pair(TestFixture::taskAbsNodePath(theDefs,"wait"),templateEcfFileForWait));
-
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_wait_cmd_non_existant_paths.def"), taskEcfFileMap,1 /*timeout*/, false/* don't wait for test to finish */);
-
- // wait for family1 and family2 to complete
- std::vector< std::pair<std::string,NState::State> > path_state_vec;
- path_state_vec.push_back( std::make_pair( std::string("/test_wait_cmd_non_existant_paths/family1"), NState::COMPLETE) );
- path_state_vec.push_back( std::make_pair( std::string("/test_wait_cmd_non_existant_paths/family2"), NState::COMPLETE) );
- wait_for_state(path_state_vec,10);
-
- // wait for 'wait' task to abort
- path_state_vec.clear();
- path_state_vec.push_back( std::make_pair( std::string("/test_wait_cmd_non_existant_paths/family0/wait"), NState::ABORTED) );
- wait_for_state(path_state_vec,10);
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Test/TestEvents.cpp b/ecflow_4_0_7/Test/TestEvents.cpp
deleted file mode 100644
index eb50a74..0000000
--- a/ecflow_4_0_7/Test/TestEvents.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #26 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <iostream>
-#include <fstream>
-#include <stdlib.h>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/test/unit_test.hpp>
-#include <boost/lexical_cast.hpp>
-
-#include "ServerTestHarness.hpp"
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "DurationTimer.hpp"
-
-using namespace std;
-using namespace ecf;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( TestSuite )
-
-// In the test case we will dynamically create all the test data.
-// The data is created dynamically so that we can stress test the server
-// This test does not have any time dependencies in the def file.
-
-BOOST_AUTO_TEST_CASE( test_events )
-{
- DurationTimer timer;
- cout << "Test:: ...test_events "<< flush;
- TestClean clean_at_start_and_end;
-
- // Create the defs file corresponding to the text below
- // ECF_HOME variable is automatically added by the test harness.
- // ECF_INCLUDE variable is automatically added by the test harness.
- // SLEEPTIME variable is automatically added by the test harness.
- // ECF_CLIENT_EXE_PATH variable is automatically added by the test harness.
- // This is substituted in sms includes
- // Allows test to run without requiring installation
-
- //# Note: we have to use relative paths, since these tests are relocatable
- // suite test_events
- // family family1
- // task a
- // event 1 myEvent
- // meter myMeter 0 100
- // task b
- // trigger a == complete
- // endfamily
- // family family2
- // task aa
- // trigger ../family1/a:myMeter >= 90 and ../family1/a:myEvent
- // task bb
- // trigger ../family1/a:myMeter >= 50 or ../family1/a:myEvent
- // endfamily
- // endsuite
- Defs theDefs;
- {
- suite_ptr suite = theDefs.add_suite("test_events" );
- {
- family_ptr fam = suite->add_family("family1");
- task_ptr task_a = fam->add_task("a");
- task_ptr task_b = fam->add_task("b");
- task_a->addMeter( Meter("myMeter",0,100,100) ); // ServerTestHarness will add correct ecf
- task_a->addEvent( Event(1,"myEvent") ); // ServerTestHarness will add correct ecf
- task_a->addLabel( Label("task_a_label","Label1") ); // ServerTestHarness will add correct ecf
- task_a->addVerify( VerifyAttr(NState::COMPLETE,1) );
-
- task_b->add_trigger( "a == complete" );
- task_b->addLabel( Label("task_b_label","label1 label2") ); // ServerTestHarness will add correct ecf
- task_b->addVerify( VerifyAttr(NState::COMPLETE,1) );
- }
- {
- family_ptr fam2 = suite->add_family("family2");
- task_ptr task_aa = fam2->add_task("aa");
- task_ptr task_bb = fam2->add_task("bb");
- task_aa->add_trigger( "../family1/a:myMeter >= 90 and ../family1/a:myEvent");
- task_aa->addVerify( VerifyAttr(NState::COMPLETE,1) );
- task_bb->add_trigger( "../family1/a:myMeter >= 50 or ../family1/a:myEvent" );
- task_bb->addVerify( VerifyAttr(NState::COMPLETE,1) );
- }
- //cout << theDefs;
- }
-
- // The test harness will create corresponding directory structure & default ecf file
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_events.def"));
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Test/TestFileCmd.cpp b/ecflow_4_0_7/Test/TestFileCmd.cpp
deleted file mode 100644
index c668746..0000000
--- a/ecflow_4_0_7/Test/TestFileCmd.cpp
+++ /dev/null
@@ -1,132 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #23 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : This is used to INVOKE a SINGLE test. Easier for debugging
-//============================================================================
-#include <iostream>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/lexical_cast.hpp>
-#include <boost/test/unit_test.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include "ServerTestHarness.hpp"
-#include "TestFixture.hpp"
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "DurationTimer.hpp"
-#include "ClientToServerCmd.hpp"
-#include "File.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( TestSuite )
-
-BOOST_AUTO_TEST_CASE( test_file_cmd )
-{
- DurationTimer timer;
- cout << "Test:: ...test_file_cmd " << flush;
- TestClean clean_at_start_and_end;
-
- // Create the defs file corresponding to the text below
- // ECF_HOME variable is automatically added by the test harness.
- // ECF_INCLUDE variable is automatically added by the test harness.
- // SLEEPTIME variable is automatically added by the test harness.
- // ECF_CLIENT_EXE_PATH variable is automatically added by the test harness.
- // This is substituted in sms includes
- // Allows test to run without requiring installation
-
- //# Note: we have to use relative paths, since these tests are relocate-able
- //suite test_file_cmd
- // edit SLEEPTIME 1
- // edit ECF_INCLUDE $ECF_HOME/includes
- // family family
- // task t1
- // task t2
- // endfamily
- //endsuite
-
- Defs theDefs;
- {
- suite_ptr suite = theDefs.add_suite("test_file_cmd");
- suite->addVerify( VerifyAttr(NState::COMPLETE,1) );
- family_ptr fam = suite->add_family("family");
- int taskSize = 2; // on linux 1024 tasks take ~4 seconds for job submission
- for(int i=0; i < taskSize; i++) {
- task_ptr task = fam->add_task("t" + boost::lexical_cast<std::string>(i));
- task->addVerify( VerifyAttr(NState::COMPLETE,1) );
- }
- }
-
- // The test harness will create corresponding directory structure
- // and populate with standard ecf files AND will generate man files for node containers
- ServerTestHarness serverTestHarness;
- serverTestHarness.generateManFileForNodeContainers();
- serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_file_cmd.def"));
-
- // Now invoke the file command to extract <ecffile,job file,job output, manual >
- // If the requests succeeded the client needs to create a temporary file, and populate it with
- // the contents of the string returned from the server
- TestFixture::client().set_throw_on_error(false);
-
- std::vector<Node*> nodeVec;
- theDefs.getAllNodes(nodeVec);
-
- BOOST_FOREACH(Node* node, nodeVec) {
-
- string nodePath = node->absNodePath();
- std::vector<CFileCmd::File_t> fileTypesVec = CFileCmd::fileTypesVec();
- for(size_t i = 0; i < fileTypesVec.size(); i++) {
-
- string file_type = CFileCmd::toString(fileTypesVec[i]);
- std::vector<std::string> theArgs = CtsApi::file(nodePath,file_type,"10000");
- std::string args; for(size_t x = 0; x < theArgs.size(); x++) { args += theArgs[x]; args += " "; }
-
- int theResult = TestFixture::client().file(nodePath,file_type,"10000");
-// cout << "nodePath = " << nodePath << " fileType = " << file_type << " args passed = " << args << " pass = " << theResult << "\n";
-
- /// Expect KILL and STAT file types to fail, i.e since we have not called those commands
- if (fileTypesVec[i] == CFileCmd::KILL || fileTypesVec[i] == CFileCmd::STAT) {
- BOOST_CHECK_MESSAGE( theResult == 1,args << " Expected " << CFileCmd::toString(fileTypesVec[i]) << " to fail");
- continue;
- }
-
- if (node->isSubmittable() || fileTypesVec[i] == CFileCmd::MANUAL) {
- // For suite and families only manual is valid
- BOOST_CHECK_MESSAGE( theResult == 0,args << " failed for Node should return 0.\n" << TestFixture::client().errorMsg());
- BOOST_CHECK_MESSAGE( !TestFixture::client().get_string().empty()," file contents empty for " << args );
- }
- else {
- // Should fail
- BOOST_CHECK_MESSAGE( theResult != 0, args << " Expected failure for node " << node->debugNodePath() << " with file= " << CFileCmd::toString(fileTypesVec[i]) );
- if (theResult == 0 ) {
- std::cout << "Found file contents:''\n";
- std::cout << TestFixture::client().get_string();
- std::cout << "''\n";
- }
- }
- }
- }
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/Test/TestHandle.cpp b/ecflow_4_0_7/Test/TestHandle.cpp
deleted file mode 100644
index 5c0ce93..0000000
--- a/ecflow_4_0_7/Test/TestHandle.cpp
+++ /dev/null
@@ -1,391 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #22 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : This is used to INVOKE a SINGLE test.
-// Making it easier for Easier for debugging and development
-//============================================================================
-#include <iostream>
-#include <limits> // for std::numeric_limits<int>::max()
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/lexical_cast.hpp>
-#include <boost/test/unit_test.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include "TestFixture.hpp"
-#include "ServerTestHarness.hpp"
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "DurationTimer.hpp"
-#include "PrintStyle.hpp"
-#include "ClientToServerCmd.hpp"
-#include "DefsStructureParser.hpp"
-#include "AssertTimer.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( TestSuite )
-
-//static void dump_suites_and_handles(ClientInvoker& theClient, const std::string& title)
-//{
-// std::cout << title;
-// TestFixture::client().suites();
-// {
-// const std::vector<std::string>& suites = TestFixture::client().server_reply().get_string_vec();
-// BOOST_FOREACH(const std::string& suite, suites) { std::cout << "\n---> " << suite; }
-// std::cout << "\n";
-//
-// const std::vector<std::pair<unsigned int, std::vector<std::string> > >& handles = TestFixture::client().server_reply().get_client_handle_suites();
-// std::pair<unsigned int, std::vector<std::string> > int_str_pair;
-// for(size_t i =0; i < handles.size(); i++) {
-// std::cout << "handle: " << handles[i].first << " : ";
-// BOOST_FOREACH(const std::string& suite, handles[i].second) {
-// std::cout << suite << " ";
-// }
-// std::cout << "\n";
-// }
-// }
-// std::cout << "\n";
-//}
-
-BOOST_AUTO_TEST_CASE( test_handle )
-{
- DurationTimer timer;
- cout << "Test:: ...test_handle " << flush;
- TestClean clean_at_start_and_end;
-
- Defs theDefs; {
- for(int s = 0; s < 7; s++) {
- suite_ptr suite = theDefs.add_suite("s" + boost::lexical_cast<std::string>(s));
- suite->addDefStatus(DState::SUSPENDED); // NO NEED to run jobs for this test:
- for(int t = 0; t < 2; t++) { suite->add_task("t" + boost::lexical_cast<std::string>(t)); }
- }
- }
-
- // The test harness will create corresponding directory structure & default ecf file
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,
- ServerTestHarness::testDataDefsLocation("test_handle.def"),
- 1 /*timeout*/,
- false/* don't wait for test to finish */);
-
- std::vector<std::string> suites_s0_s1_s2; suites_s0_s1_s2.push_back("s0"); suites_s0_s1_s2.push_back("s1"); suites_s0_s1_s2.push_back("s2");
- std::vector<std::string> suites_s3_s4; suites_s3_s4.push_back("s3"); suites_s3_s4.push_back("s4");
- std::vector<std::string> suites_s0_s1_s2_s3_s4; suites_s0_s1_s2_s3_s4.push_back("s0"); suites_s0_s1_s2_s3_s4.push_back("s1"); suites_s0_s1_s2_s3_s4.push_back("s2"),suites_s0_s1_s2_s3_s4.push_back("s3"),suites_s0_s1_s2_s3_s4.push_back("s4");;
- std::vector<std::pair<unsigned int, std::vector<std::string> > > ch_suites;
-
- {
- // register suites s0,s1,s2
- TestFixture::client().ch_register(false/*add new suites to handle*/,suites_s0_s1_s2);
-
- // get the handle associated with the registered suites
- unsigned int client_handle = TestFixture::client().server_reply().client_handle();
-
- // Check the sync_local() does a full sync for our handle
- TestFixture::client().sync_local();
- BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().in_sync(),"Expected to be in sync after syn_local()");
- BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().full_sync(),"Expected a full_sync() after registering");
-
- // Now check the suites were registered, correctly
- TestFixture::client().ch_suites();
- ch_suites = TestFixture::client().server_reply().get_client_handle_suites();
- BOOST_CHECK_MESSAGE(!ch_suites.empty(),"Expected to have registered suites");
- BOOST_CHECK_MESSAGE(ch_suites.size() == 1,"Expected to have registered a single set");
- BOOST_CHECK_MESSAGE(ch_suites[0].first == client_handle,"Expected first client handle to be: " << client_handle << ", but found " << ch_suites[0].first);
- BOOST_CHECK_MESSAGE(ch_suites[0].second == suites_s0_s1_s2,"Expected suites s0,s1,s2");
-
- // Now drop the handle and Check handle was dropped
- TestFixture::client().ch_drop(client_handle);
- TestFixture::client().ch_suites();
- BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().get_client_handle_suites().empty(),"Expected to have no registered suites");
- }
-
- {
- // register suites s0,s1,s2
- TestFixture::client().ch_register(false/*add new suites to handle*/,suites_s0_s1_s2);
-
- // get the handle associated with the registered suites
- unsigned int client_handle = TestFixture::client().server_reply().client_handle();
- BOOST_CHECK_MESSAGE(client_handle == 1,"Expected to have handle 1");
-
- // Check the sync_local() does a full sync for our handle. *THIS* should also clear the handle_changed flag
- TestFixture::client().sync_local();
- BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().in_sync(),"Expected to be in sync after syn_local()");
- BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().full_sync(),"Expected a full_sync() after registering");
-
-
- // add additional suites & check suites were added to our handle. Sync_local should returna full_sync()
- std::vector<std::string> added_suites; added_suites.push_back("s3"); added_suites.push_back("s4");
- TestFixture::client().ch_add(client_handle,added_suites);
-
- TestFixture::client().ch_suites();
- ch_suites = TestFixture::client().server_reply().get_client_handle_suites();
- BOOST_CHECK_MESSAGE(!ch_suites.empty(),"Expected to have registered suites");
- BOOST_CHECK_MESSAGE(ch_suites.size() == 1,"Expected to have registered a single set");
- BOOST_CHECK_MESSAGE(ch_suites[0].first == client_handle,"Expected first client handle to be: " << client_handle << ", but found " << ch_suites[0].first);
- BOOST_CHECK_MESSAGE(ch_suites[0].second == suites_s0_s1_s2_s3_s4,"Expected suites s0,s1,s2,s3,s4");
-
- TestFixture::client().sync_local();
- BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().full_sync(),"Expected a full_sync() after adding suites.");
-
-
- // remove the added suites, and check they were removed
- TestFixture::client().ch_remove(client_handle,added_suites);
-
- TestFixture::client().ch_suites();
- ch_suites = TestFixture::client().server_reply().get_client_handle_suites();
- BOOST_CHECK_MESSAGE(!ch_suites.empty(),"Expected to have registered suites");
- BOOST_CHECK_MESSAGE(ch_suites.size() == 1,"Expected to have registered a single set");
- BOOST_CHECK_MESSAGE(ch_suites[0].first == client_handle,"Expected first client handle to be: " << client_handle << ", but found " << ch_suites[0].first);
- BOOST_CHECK_MESSAGE(ch_suites[0].second == suites_s0_s1_s2,"Expected suites s0,s1,s2");
-
- TestFixture::client().sync_local();
- BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().full_sync(),"Expected a full_sync() after removing suites");
-
- // Now drop the handle and check handle was dropped
- TestFixture::client().ch_drop(client_handle);
- TestFixture::client().ch_suites();
- BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().get_client_handle_suites().empty(),"Expected to have no registered suites");
- }
-
- {
- // register suites s0,s1,s2
- TestFixture::client().ch_register(false/*add new suites to handle*/,suites_s0_s1_s2);
-
- // register suite s3,s4
- TestFixture::client().ch_register(false/*add new suites to handle*/,suites_s3_s4);
-
- // get all the registered suites
- TestFixture::client().ch_suites();
- ch_suites = TestFixture::client().server_reply().get_client_handle_suites();
- BOOST_CHECK_MESSAGE(!ch_suites.empty(),"Expected to have registered suites");
- BOOST_CHECK_MESSAGE(ch_suites.size() == 2,"Expected to have 2 registered sets");
- BOOST_CHECK_MESSAGE(ch_suites[0].first == 1,"Expected first client handle to be 1, but found " << ch_suites[0].first);
- BOOST_CHECK_MESSAGE(ch_suites[0].second == suites_s0_s1_s2,"Expected suites s0,s1,s2, in first handle");
- BOOST_CHECK_MESSAGE(ch_suites[1].first == 2,"Expected second client handle to be 2, but found " << ch_suites[1].first);
- BOOST_CHECK_MESSAGE(ch_suites[1].second == suites_s3_s4,"Expected suites s3,s4 , in second handle");
-
- // Drop all handles
- for(size_t i = 0; i < ch_suites.size(); i++) TestFixture::client().ch_drop(ch_suites[i].first);
- TestFixture::client().ch_suites();
- BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().get_client_handle_suites().empty(),"Expected to have no registered suites");
- }
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-BOOST_AUTO_TEST_CASE( test_handle_sync )
-{
- DurationTimer timer;
- cout << "Test:: ...test_handle_sync " << flush;
- TestClean clean_at_start_and_end;
-
- Defs theDefs; {
- for(int s = 0; s < 7; s++) {
- suite_ptr suite = theDefs.add_suite("s" + boost::lexical_cast<std::string>(s));
- suite->addDefStatus(DState::SUSPENDED);
- for(int t = 0; t < 2; t++) { suite->add_task("t" + boost::lexical_cast<std::string>(t)); }
- }
- }
-
- // The test harness will create corresponding directory structure & default ecf file
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,
- ServerTestHarness::testDataDefsLocation("test_handle_sync.def"),
- 1 /*timeout*/,
- false/* don't wait for test to finish */);
-
- std::vector<std::string> suites_s0_s1_s2; suites_s0_s1_s2.push_back("s0"); suites_s0_s1_s2.push_back("s1"); suites_s0_s1_s2.push_back("s2");
- std::vector<std::pair<unsigned int, std::vector<std::string> > > ch_suites;
-
- {
- // register suites s0,s1,s2
- TestFixture::client().ch_register(false/*add new suites to handle*/,suites_s0_s1_s2);
- unsigned int client_handle = TestFixture::client().server_reply().client_handle();
- TestFixture::client().news_local();
- BOOST_CHECK_MESSAGE(TestFixture::client().get_news(),"Expected news after registering");
- TestFixture::client().sync_local(); // sync for any changes to get full update before test starts
- BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().full_sync(),"Expected a full_sync() after registering");
- BOOST_CHECK_MESSAGE(TestFixture::client().defs()->suiteVec().size() == 3,"Expected 3 suites back from sync, after registering 3 suites " << *TestFixture::client().defs());
-
-
- // make a change to a suite not in our handle, that does not cause state propagation.
- // State propagation changes the defs state. The defs state is sync regardless
- TestFixture::client().suspend("/s3");
- TestFixture::client().news_local();
- BOOST_CHECK_MESSAGE(!TestFixture::client().get_news(),"Expected no change since suite s3 is not in our handle");
-
- // make a change to a suite *not* in our handle, that *does* cause state propagation.
- TestFixture::client().force("/s3/t0","aborted");
- TestFixture::client().news_local();
- BOOST_CHECK_MESSAGE(TestFixture::client().get_news(),"Expected change via state propagation to defs, even though s3 not in our handle");
-
- TestFixture::client().sync_local();
- BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().full_sync(),"Expected incremental change, not a full update");
-
-
- // make a change to a suite in our handle
- TestFixture::client().force("/s0","complete");
- TestFixture::client().news_local();
- BOOST_CHECK_MESSAGE(TestFixture::client().get_news(),"Expected news since state changed");
-
- TestFixture::client().sync_local();
- BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().full_sync(),"Expected incremental change, not a full update");
-
- TestFixture::client().ch_drop(client_handle);
- BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().get_client_handle_suites().empty(),"Expected to have no registered suites");
- }
-
- {
- // register suites s0,s1,s2
- TestFixture::client().ch_register(false/*add new suites to handle*/,suites_s0_s1_s2);
- unsigned int client_handle = TestFixture::client().server_reply().client_handle();
- TestFixture::client().news_local();
- BOOST_CHECK_MESSAGE(TestFixture::client().get_news(),"Expected news after registering");
- TestFixture::client().sync_local(); // sync for any changes to get full update before test starts
- BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().full_sync(),"Expected a full_sync() after registering");
-
-
- // make a small change to a suite *IN* our handle
- TestFixture::client().force("/s1","complete");
- TestFixture::client().sync_local();
- BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().full_sync(),"Expected incremental change, not a full update");
-
- // Change the order
- TestFixture::client().order("/s0","alpha");
- TestFixture::client().sync_local();
- BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().full_sync(),"Expected incremental update");
-
- TestFixture::client().ch_drop(client_handle);
- TestFixture::client().suites();
- BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().get_client_handle_suites().empty(),"Expected to have no registered suites");
- }
-
- {
- // register suites s0,s1,s2
- TestFixture::client().ch_register(false/*add new suites to handle*/,suites_s0_s1_s2);
- unsigned int client_handle = TestFixture::client().server_reply().client_handle();
- TestFixture::client().news_local();
- BOOST_CHECK_MESSAGE(TestFixture::client().get_news(),"Expected news after registering");
- TestFixture::client().sync_local(); // sync for any changes to get full update **before** test starts
- BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().full_sync(),"Expected a full_sync() after registering");
-
-
- // make a small change to a suite *IN* our handle
- TestFixture::client().force("/s1","unknown");
- TestFixture::client().sync_local();
- BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().full_sync(),"Expected incremental change, not a full update");
-
-
- // DELETE suite s2, i.e make a change that should force a *FULL* update
- TestFixture::client().delete_node("/s2",true/*force*/);
- TestFixture::client().news_local();
- BOOST_CHECK_MESSAGE(TestFixture::client().get_news(),"Expected news after deleting node");
- TestFixture::client().sync_local();
- BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().full_sync(),"Expected full update");
-
-
- // Check that suite s2 is STILL in our handle.
- // delete suites STAY registered until they are explicitly deleted
- TestFixture::client().ch_suites();
- ch_suites = TestFixture::client().server_reply().get_client_handle_suites();
- BOOST_CHECK_MESSAGE(ch_suites[0].second == suites_s0_s1_s2,"Expected suites s0,s1,s2, in handle");
-
- TestFixture::client().ch_drop(client_handle);
- TestFixture::client().ch_suites();
- BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().get_client_handle_suites().empty(),"Expected to have no registered suites");
- }
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-
-BOOST_AUTO_TEST_CASE( test_handle_add_remove_add )
-{
- DurationTimer timer;
- cout << "Test:: ...test_handle_add_remove_add " << flush;
- TestClean clean_at_start_and_end;
-
- defs_ptr theDefs = Defs::create(); {
- for(int s = 0; s < 3; s++) {
- suite_ptr suite = theDefs->add_suite("s" + boost::lexical_cast<std::string>(s));
- suite->addDefStatus(DState::SUSPENDED); // NO NEED to run jobs for this test:
- for(int t = 0; t < 2; t++) { suite->add_task("t" + boost::lexical_cast<std::string>(t)); }
- }
- }
-
- // The test harness will create corresponding directory structure & default ecf file
- // ADD
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(*theDefs,
- ServerTestHarness::testDataDefsLocation("test_handle_sync.def"),
- 1 /*timeout*/,
- false/* don't wait for test to finish */);
-
- TestFixture::client().set_throw_on_error( true );
- std::vector<std::string> suites_s0_s1_s2; suites_s0_s1_s2.push_back("s0"); suites_s0_s1_s2.push_back("s1"); suites_s0_s1_s2.push_back("s2");
- std::vector<std::pair<unsigned int, std::vector<std::string> > > ch_suites;
-
- {
- // register suites s0
- TestFixture::client().ch_register(false/*add new suites to handle*/,suites_s0_s1_s2);
- unsigned int client_handle = TestFixture::client().server_reply().client_handle();
- BOOST_CHECK_MESSAGE(client_handle == 1 ,"Expected handle of value 1 but found " << client_handle );
-
- // Get the registered suites
- TestFixture::client().ch_suites();
- BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().get_client_handle_suites().empty(),"Expected to have registered suites");
-
-
- // Check the sync_local() does a full sync for our handle
- TestFixture::client().sync_local();
- BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().in_sync(),"Expected to be in sync after syn_local()");
- BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().full_sync(),"Expected a full_sync() after registering");
- BOOST_CHECK_MESSAGE(TestFixture::client().defs()->suiteVec().size() == 3,"Expected 3 suites back from sync " << *TestFixture::client().defs());
-
-
- // DELETE suites. They should stay *registered*
- TestFixture::client().delete_node("/s0");
- TestFixture::client().delete_node("/s1");
- TestFixture::client().delete_node("/s2");
- TestFixture::client().sync_local();
- BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().full_sync(),"Expected a full_sync() after deleting suite");
- BOOST_CHECK_MESSAGE(TestFixture::client().defs()->suiteVec().size() == 0,"Expected 0 suites back from sync " << *TestFixture::client().defs());
-
- // Check suites are still registered. Only explicit drop can remove registered suites
- TestFixture::client().ch_suites();
- BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().get_client_handle_suites().empty(),"Expected to have registered suites");
-
-
- // RELOAD the defs, which includes s0,s1,s2:: THIS SHOULD GET RE_ADDED TO OUR EXISTING HANDLE's
- // The handle references to the suites should get *refreshed*
- TestFixture::client().load(theDefs);
- TestFixture::client().sync_local();
- BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().full_sync(),"Expected a full_sync() since client handle should be refreshed with new suite_pts");
- BOOST_CHECK_MESSAGE(TestFixture::client().defs()->suiteVec().size() == 3,"Expected 3 suites back from sync " << *TestFixture::client().defs());
-
- TestFixture::client().ch_drop(client_handle);
- BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().get_client_handle_suites().empty(),"Expected to have no registered suites");
- }
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Test/TestKillCmd.cpp b/ecflow_4_0_7/Test/TestKillCmd.cpp
deleted file mode 100644
index a59b36b..0000000
--- a/ecflow_4_0_7/Test/TestKillCmd.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #25 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : This is used to INVOKE a SINGLE test. Easier for debugging
-//============================================================================
-#include <iostream>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/lexical_cast.hpp>
-#include <boost/test/unit_test.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include "ServerTestHarness.hpp"
-#include "TestFixture.hpp"
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "DurationTimer.hpp"
-#include "PrintStyle.hpp"
-#include "ClientToServerCmd.hpp"
-#include "AssertTimer.hpp"
-#include "File.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( TestSuite )
-
-// forward declare functions
-static bool kill_cmd(bool kill_task);
-static bool waitForTaskState(NState::State state, int max_time_to_wait);
-
-// test:: test the kill command. Create a task that runs a long time
-// The associated job is then killed. This should leave task in aborted state
-BOOST_AUTO_TEST_CASE( test_kill_cmd )
-{
- DurationTimer timer;
- cout << "Test:: ...test_kill_cmd " << flush;
- TestClean clean_at_start_and_end;
- BOOST_REQUIRE_MESSAGE(kill_cmd(true)," kill of task '/test_kill_cmd/family/t0' failed");
- cout << timer.duration() << "\n";
-}
-
-BOOST_AUTO_TEST_CASE( test_hierarchical_kill_cmd )
-{
- DurationTimer timer;
- cout << "Test:: ...test_hierarchical_kill_cmd " << flush;
- TestClean clean_at_start_and_end;
- BOOST_REQUIRE_MESSAGE(kill_cmd(false),"kill of suite '/test_kill_cmd' failed");
- cout << timer.duration() << "\n";
-}
-
-
-static bool kill_cmd(bool kill_task)
-{
- /// Create dir location for log file.
- std::string defs_location = ServerTestHarness::testDataDefsLocation("test_kill_cmd.def");
- fs::path new_path = defs_location;
- if (!fs::exists(new_path.parent_path())) {
- File::createMissingDirectories(new_path.parent_path().string());
- }
-
- Defs theDefs;
- std::string kill_path;
- {
- suite_ptr suite;
- if (kill_task ) suite = theDefs.add_suite( "test_kill_task");
- else suite = theDefs.add_suite( "test_kill_suite");
- suite->addVariable( Variable("ECF_TRIES","1") ); // do not try again
- family_ptr fam = suite->add_family( "family" );
- task_ptr task = fam->add_task( "t0");
- task->addMeter( Meter("meter",0,200,100) ); // Make sure it run long enough, to receive kill, on slow systems
- task->addVerify( VerifyAttr(NState::ABORTED,1) );// task should abort 1 times
- if (kill_task) kill_path = task->absNodePath();
- else kill_path = suite->absNodePath();
- }
-
- // *******************************************************************
- // Important: The following will *not* work:
- // theDefs.set_server().add_or_update_variables("ECF_TRIES","1"); // Override ECF_TRIES so don't try to restart aborted jobs
- // theDefs.set_server().add_or_update_variables("ECF_KILL_CMD","kill -15 %ECF_RID%"); // Provide a mechanism to kill the running job
- // Since calling the begin command in the server,
- // will update the defs with the server environment, and hence overriding
- // any env variable of the same name, set here. Hence just use addVariable as above.
- // *************************************************************************
- // cout << theDefs << "\n";
-
- // cout << "test_kill_cmd Start test\n";
- // The test harness will create corresponding directory structure & default ecf file
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,defs_location,1 /*timeout*/, false/* don't wait for test to finish */);
-
-
- // cout << "test_kill_cmd Waiting for task to become active\n";
- TestFixture::client().set_throw_on_error(false);
- (void)waitForTaskState(NState::ACTIVE,10);
-
-
- // cout << "test_kill_cmd Now kill the active jobs\n";
- BOOST_REQUIRE_MESSAGE( TestFixture::client().kill(kill_path) == 0,CtsApi::to_string(CtsApi::kill(kill_path)) << " failed should return 0.\n" << TestFixture::client().errorMsg());
-
-
- // cout << "test_kill_cmd Wait for the task to be aborted\n";
- return waitForTaskState(NState::ABORTED,20 );
-}
-
-static bool waitForTaskState(NState::State state, int max_time_to_wait)
-{
- AssertTimer assertTimer(max_time_to_wait,false); // Bomb out after n seconds, fall back if test fail
- while (1) {
- BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0, "sync_local failed should return 0\n" << TestFixture::client().errorMsg());
- defs_ptr defs = TestFixture::client().defs();
- vector<Task*> tasks; defs->getAllTasks(tasks);
- BOOST_FOREACH(Task* task, tasks) {
- if (task->state() == state) {
- return true;
- }
- }
-
- // make sure test does not take too long.
- if ( assertTimer.duration() >= assertTimer.timeConstraint() ) {
- BOOST_REQUIRE_MESSAGE(assertTimer.duration() < assertTimer.timeConstraint(),
- "waitForTaskState " << NState::toString(state) << " Test wait " << assertTimer.duration() <<
- " taking longer than time constraint of " << assertTimer.timeConstraint() <<
- " aborting\n" << *defs);
- break;
- }
- sleep(2);
- }
- return false;
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/Test/TestLate.cpp b/ecflow_4_0_7/Test/TestLate.cpp
deleted file mode 100644
index 65c1cca..0000000
--- a/ecflow_4_0_7/Test/TestLate.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <iostream>
-#include <limits> // for std::numeric_limits<int>::max()
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/lexical_cast.hpp>
-#include <boost/test/unit_test.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include "TestFixture.hpp"
-#include "ServerTestHarness.hpp"
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "DurationTimer.hpp"
-#include "PrintStyle.hpp"
-#include "ClientToServerCmd.hpp"
-#include "DefsStructureParser.hpp"
-#include "AssertTimer.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( TestSuite )
-
-BOOST_AUTO_TEST_CASE( test_late )
-{
- DurationTimer timer;
- cout << "Test:: ...test_late " << flush;
- TestClean clean_at_start_and_end;
-
- /// This test will sleep longer than the job submission interval
- /// which cause the task to be late
- /// as the active time has been set for 1 minute.
- /// The check for lateness is ONLY done are server poll time.
- /// Hence the task run time must be at least twice the poll time.
- Defs theDefs;
- {
- suite_ptr suite = theDefs.add_suite("test_late");
- suite->add_variable("SLEEPTIME",boost::lexical_cast<std::string>(TestFixture::job_submission_interval()*2) ); // this will cause the late
-
- task_ptr task = suite->add_task("t1");
- ecf::LateAttr lateAttr;
- lateAttr.addComplete( ecf::TimeSlot(0,1), true);
-
- task->addLate( lateAttr );
- }
-
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_late.def"));
-
- TestFixture::client().set_throw_on_error(true);
- TestFixture::client().sync_local();
- BOOST_CHECK_MESSAGE( TestFixture::client().defs(),"Expected defs");
-
- node_ptr node = TestFixture::client().defs()->findAbsNode("/test_late/t1");
- BOOST_CHECK_MESSAGE( node,"Expected task to be found");
-
- ecf::LateAttr* late = node->get_late();
- BOOST_CHECK_MESSAGE( late->isLate(),"Expected late to be set");
- BOOST_CHECK_MESSAGE( node->flag().is_set(ecf::Flag::LATE),"Expected late flag to be set");
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Test/TestLimit.cpp b/ecflow_4_0_7/Test/TestLimit.cpp
deleted file mode 100644
index a605045..0000000
--- a/ecflow_4_0_7/Test/TestLimit.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #25 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include "ServerTestHarness.hpp"
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "DurationTimer.hpp"
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/test/unit_test.hpp>
-#include <boost/lexical_cast.hpp>
-
-#include <iostream>
-#include <fstream>
-#include <stdlib.h>
-
-using namespace std;
-using namespace ecf;
-namespace fs = boost::filesystem;
-
-
-BOOST_AUTO_TEST_SUITE( TestSuite )
-
-// In the test case we will dynamically create all the test data.
-// The data is created dynamically so that we can stress test the server
-// This test does not have any time dependencies in the def file.
-// In the test case we will dynamically create all the test data.
-// The data is created dynamically so that we can stress test the server
-// This test does not have any time dependencies in the def file.
-BOOST_AUTO_TEST_CASE( test_limit )
-{
- DurationTimer timer;
- cout << "Test:: ...test_limit "<< flush;
- TestClean clean_at_start_and_end;
-
- // Create the defs file corresponding to the text below
- // ECF_HOME variable is automatically added by the test harness.
- // ECF_INCLUDE variable is automatically added by the test harness.
- // SLEEPTIME variable is automatically added by the test harness.
- // ECF_CLIENT_EXE_PATH variable is automatically added by the test harness.
- // This is substituted in sms includes
- // Allows test to run without requiring installation
-
- //# Test the ecf file can be found via ECF_SCRIPT
- //# Note: we have to use relative paths, since these tests are relocatable
- // Create the defs file
- // suite test_limit
- // limit disk 50
- // limit fast 1
- // edit ECF_HOME data/ECF_HOME # added by test harness
- // edit SLEEPTIME 1
- // edit ECF_INCLUDE $ECF_HOME/includes
- // family family
- // inlimit /suite1:fast
- // task t1
- // task t2
- // task t3
- // endfamily
- // family family2
- // inlimit /suite1:disk 20
- // task t1
- // task t2
- // task t3
- // endfamily
- // endsuite
-
- Defs theDefs;
- {
- std::string suiteName = "test_limit";
- std::string pathToLimit = "/" + suiteName;
-
- suite_ptr suite = theDefs.add_suite( suiteName );
- suite->addLimit(Limit("fast",1));
- suite->addLimit(Limit("disk",50));
-
- family_ptr fam = suite->add_family("family");
- fam->addInLimit(InLimit("fast",pathToLimit));
- fam->addVerify( VerifyAttr(NState::COMPLETE,1) );
- int taskSize = 3;
- for(int i=0; i < taskSize; i++) {
- task_ptr task = fam->add_task( "t" + boost::lexical_cast<std::string>(i) );
- task->addVerify( VerifyAttr(NState::COMPLETE,1) );
- }
-
- family_ptr fam2 = suite->add_family("family2");
- fam2->addInLimit(InLimit("disk",pathToLimit,20));
- fam2->addVerify( VerifyAttr(NState::COMPLETE,1) );
- for(int i=0; i < taskSize; i++) {
- task_ptr task = fam2->add_task( "t" + boost::lexical_cast<std::string>(i) );
- task->addVerify( VerifyAttr(NState::COMPLETE,1) );
- }
- }
-
-
- // The test harness will create corresponding directory structure
- // and populate with standard ecf files.
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs, ServerTestHarness::testDataDefsLocation( "test_limit.def" ));
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Test/TestOrderCmd.cpp b/ecflow_4_0_7/Test/TestOrderCmd.cpp
deleted file mode 100644
index 48204ef..0000000
--- a/ecflow_4_0_7/Test/TestOrderCmd.cpp
+++ /dev/null
@@ -1,216 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : This is used to INVOKE a SINGLE test.
-// Making it easier for Easier for debugging and development
-//============================================================================
-#include <iostream>
-#include <limits> // for std::numeric_limits<int>::max()
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/lexical_cast.hpp>
-#include <boost/test/unit_test.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include "ServerTestHarness.hpp"
-#include "TestFixture.hpp"
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "DurationTimer.hpp"
-#include "PrintStyle.hpp"
-#include "ClientToServerCmd.hpp"
-#include "DefsStructureParser.hpp"
-#include "AssertTimer.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( TestSuite )
-
-std::vector<std::string> to_string_vec(const std::vector<suite_ptr>& sv) {
- std::vector<std::string> r; r.reserve(sv.size());
- for(size_t i = 0; i < sv.size(); i++) r.push_back(sv[i]->name());
- return r;
-}
-
-std::vector<std::string> to_string_vec(const std::vector<node_ptr>& sv) {
- std::vector<std::string> r; r.reserve(sv.size());
- for(size_t i = 0; i < sv.size(); i++) r.push_back(sv[i]->name());
- return r;
-}
-
-void test_ordering() {
-
- TestFixture::client().set_throw_on_error(true);
- std::vector<std::string> str_a_b_c; str_a_b_c.push_back("a"); str_a_b_c.push_back("b"); str_a_b_c.push_back("c");
- std::vector<std::string> str_c_b_a; str_c_b_a.push_back("c"); str_c_b_a.push_back("b"); str_c_b_a.push_back("a");
- std::vector<std::string> str_b_c_a; str_b_c_a.push_back("b"); str_b_c_a.push_back("c"); str_b_c_a.push_back("a");
- std::vector<std::string> str_b_a_c; str_b_a_c.push_back("b"); str_b_a_c.push_back("a"); str_b_a_c.push_back("c");
- std::vector<std::string> str_a_c_b; str_a_c_b.push_back("a"); str_a_c_b.push_back("c"); str_a_c_b.push_back("b");
- TestFixture::client().sync_local(); // First sync_local will do a full sync
- {
- // TEST SUITE ORDERING
- TestFixture::client().order("/a",NOrder::toString(NOrder::ORDER));
- TestFixture::client().sync_local();
- BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().full_sync(),"Expected incremental sync");
- BOOST_CHECK_MESSAGE(to_string_vec(TestFixture::client().defs()->suiteVec()) == str_c_b_a, "Order not as expected");
-
-
- TestFixture::client().order("/a",NOrder::toString(NOrder::ALPHA));
- TestFixture::client().sync_local();
- BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().full_sync(),"Expected incremental sync");
- BOOST_CHECK_MESSAGE(to_string_vec(TestFixture::client().defs()->suiteVec()) == str_a_b_c, "Order not as expected");
-
-
- TestFixture::client().order("/a",NOrder::toString(NOrder::BOTTOM));
- TestFixture::client().sync_local();
- BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().full_sync(),"Expected incremental sync");
- BOOST_CHECK_MESSAGE(to_string_vec(TestFixture::client().defs()->suiteVec()) == str_b_c_a, "Order not as expected");
-
- TestFixture::client().order("/a",NOrder::toString(NOrder::ALPHA));
- TestFixture::client().order("/a",NOrder::toString(NOrder::DOWN));
- TestFixture::client().sync_local();
- BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().full_sync(),"Expected incremental sync");
- BOOST_CHECK_MESSAGE(to_string_vec(TestFixture::client().defs()->suiteVec()) == str_b_a_c, "Order not as expected");
-
- TestFixture::client().order("/a",NOrder::toString(NOrder::ALPHA));
- TestFixture::client().order("/c",NOrder::toString(NOrder::UP));
- TestFixture::client().sync_local();
- BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().full_sync(),"Expected incremental sync");
- BOOST_CHECK_MESSAGE(to_string_vec(TestFixture::client().defs()->suiteVec()) == str_a_c_b, "Order not as expected");
- }
- {
- // TEST FAMILY ordering
- TestFixture::client().order("/a/a",NOrder::toString(NOrder::ORDER));
- TestFixture::client().sync_local();
- BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().full_sync(),"Expected incremental sync");
- BOOST_CHECK_MESSAGE(to_string_vec(TestFixture::client().defs()->suiteVec()[0]->nodeVec()) == str_c_b_a, "Order not as expected");
-
-
- TestFixture::client().order("/a/a",NOrder::toString(NOrder::ALPHA));
- TestFixture::client().sync_local();
- BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().full_sync(),"Expected incremental sync");
- BOOST_CHECK_MESSAGE(to_string_vec(TestFixture::client().defs()->suiteVec()[0]->nodeVec()) == str_a_b_c, "Order not as expected");
-
-
- TestFixture::client().order("/a/a",NOrder::toString(NOrder::BOTTOM));
- TestFixture::client().sync_local();
- BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().full_sync(),"Expected incremental sync");
- BOOST_CHECK_MESSAGE(to_string_vec(TestFixture::client().defs()->suiteVec()[0]->nodeVec()) == str_b_c_a, "Order not as expected");
-
- TestFixture::client().order("/a/a",NOrder::toString(NOrder::ALPHA));
- TestFixture::client().order("/a/a",NOrder::toString(NOrder::DOWN));
- TestFixture::client().sync_local();
- BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().full_sync(),"Expected incremental sync");
- BOOST_CHECK_MESSAGE(to_string_vec(TestFixture::client().defs()->suiteVec()[0]->nodeVec()) == str_b_a_c, "Order not as expected");
-
- TestFixture::client().order("/a/a",NOrder::toString(NOrder::ALPHA));
- TestFixture::client().order("/a/c",NOrder::toString(NOrder::UP));
- TestFixture::client().sync_local();
- BOOST_CHECK_MESSAGE(!TestFixture::client().server_reply().full_sync(),"Expected incremental sync");
- BOOST_CHECK_MESSAGE(to_string_vec(TestFixture::client().defs()->suiteVec()[0]->nodeVec()) == str_a_c_b, "Order not as expected");
- }
-}
-
-BOOST_AUTO_TEST_CASE( test_change_order )
-{
- DurationTimer timer;
- cout << "Test:: ...test_change_order " << flush;
- TestClean clean_at_start_and_end;
-
- /// NOT: We *DONT* need to run the jobs for this TEST
- std::vector<std::string> str_a_b_c; str_a_b_c.push_back("a"); str_a_b_c.push_back("b"); str_a_b_c.push_back("c");
- Defs theDefs; {
- for(size_t s = 0; s < str_a_b_c.size(); s++) {
- suite_ptr suite = theDefs.add_suite(str_a_b_c[s]);
- suite->addDefStatus(DState::SUSPENDED); // NO NEED to run jobs for this test:
- for(size_t f = 0; f < str_a_b_c.size(); f++) {
- family_ptr fam = suite->add_family(str_a_b_c[f]);
- for(size_t t = 0; t < str_a_b_c.size(); t++) {
- fam->add_task(str_a_b_c[t]);
- }
- }
- }
- }
-
- // The test harness will create corresponding directory structure & default ecf file
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,
- ServerTestHarness::testDataDefsLocation("test_change_order.def"),
- 1 /*timeout*/,
- false/* don't wait for test to finish */);
-
-
- test_ordering();
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-
-BOOST_AUTO_TEST_CASE( test_handle_change_order )
-{
- DurationTimer timer;
- cout << "Test:: ...test_handle_change_order " << flush;
- TestClean clean_at_start_and_end;
-
- std::vector<std::string> str_a_b_c; str_a_b_c.push_back("a"); str_a_b_c.push_back("b"); str_a_b_c.push_back("c");
- std::vector<std::string> suite_a_b_c_d_e; suite_a_b_c_d_e.push_back("a"); suite_a_b_c_d_e.push_back("b"); suite_a_b_c_d_e.push_back("c");
- suite_a_b_c_d_e.push_back("d"); suite_a_b_c_d_e.push_back("e");
- Defs theDefs; {
- for(size_t s = 0; s < suite_a_b_c_d_e.size(); s++) {
- suite_ptr suite = theDefs.add_suite(suite_a_b_c_d_e[s]);
- suite->addDefStatus(DState::SUSPENDED); // NO NEED to run jobs for this test:
- for(size_t f = 0; f < str_a_b_c.size(); f++) {
- family_ptr fam = suite->add_family(str_a_b_c[f]);
- for(size_t t = 0; t < str_a_b_c.size(); t++) {
- fam->add_task(str_a_b_c[t]);
- }
- }
- }
- }
-
- // The test harness will create corresponding directory structure & default ecf file
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,
- ServerTestHarness::testDataDefsLocation("test_change_order.def"),
- 1 /*timeout*/,
- false/* don't wait for test to finish */);
-
-
- TestFixture::client().set_throw_on_error( true );
- TestFixture::client().sync_local(); // First sync_local will do a full sync
- {
- // register suites a,b,c
- std::vector<std::string> suites_a_b_c; suites_a_b_c.push_back("a"); suites_a_b_c.push_back("b"); suites_a_b_c.push_back("c");
- TestFixture::client().ch_register(false/*add new suites to handle*/,suites_a_b_c);
-
- // Check the sync_local() does a full sync for our handle
- TestFixture::client().sync_local();
- BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().in_sync(),"Expected to be in sync after syn_local()");
- BOOST_CHECK_MESSAGE(TestFixture::client().server_reply().full_sync(),"Expected a full_sync() after registering");
- BOOST_CHECK_MESSAGE(TestFixture::client().defs()->suiteVec().size() == 3,"Expected sync to return 3 suites.");
- }
-
- // Do same test, this time sync_local will only return suite a,b,c (i.e suite d,e not registered and hence left out)
- // Ording should still be applied to the whole suite.
- test_ordering();
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Test/TestRepeat.cpp b/ecflow_4_0_7/Test/TestRepeat.cpp
deleted file mode 100644
index 18274da..0000000
--- a/ecflow_4_0_7/Test/TestRepeat.cpp
+++ /dev/null
@@ -1,338 +0,0 @@
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <iostream>
-#include <fstream>
-#include <stdlib.h>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/test/unit_test.hpp>
-#include <boost/lexical_cast.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include "ServerTestHarness.hpp"
-#include "TestFixture.hpp"
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "DurationTimer.hpp"
-#include "WhyCmd.hpp"
-#include "PrintStyle.hpp"
-#include "Str.hpp"
-
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-using namespace std;
-using namespace ecf;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( TestSuite )
-
-// In the test case we will dynamically create all the test data.
-// The data is created dynamically so that we can stress test the server
-// This test does not have any time dependencies in the def file.
-BOOST_AUTO_TEST_CASE( test_repeat_integer )
-{
- DurationTimer timer;
- cout << "Test:: ...test_repeat_integer " << flush;
- TestClean clean_at_start_and_end;
-
- // ********************************************************************************
- // IMPORTANT: A family will only complete when it has reached the end of the repeats
- // *********************************************************************************
-
- // Create the defs file corresponding to the text below
- // ECF_HOME variable is automatically added by the test harness.
- // ECF_INCLUDE variable is automatically added by the test harness.
- // SLEEPTIME variable is automatically added by the test harness.
- // ECF_CLIENT_EXE_PATH variable is automatically added by the test harness.
- // This is substituted in sms includes
- // Allows test to run without requiring installation
-
- //# Note: we have to use relative paths, since these tests are relocatable
- //suite test_repeat_integer
- // repeat integer VAR 0 1 1 # run at 0, 1 2 times
- // edit SLEEPTIME 1
- // edit ECF_INCLUDE $ECF_HOME/includes
- // family family
- // repeat integer VAR 0 2 1 # run at 0, 1 2 times
- // task t<n>
- // ....
- // endfamily
- //endsuite
-
- // Each task/job should be run *4* times, according to the repeats
- // Mimics nested loops
- Defs theDefs;
- {
- suite_ptr suite = theDefs.add_suite( "test_repeat_integer" );
- suite->addRepeat( RepeatInteger("VAR",0,1,1)); // repeat suite 2 times,
- suite->addVerify( VerifyAttr(NState::COMPLETE,2) );
- family_ptr fam = suite->add_family("family");
- fam->addRepeat( RepeatInteger("VAR",0,1,1)); // repeat family 2 times
- fam->addVerify( VerifyAttr(NState::COMPLETE,4) );
- int taskSize = 2; // on linux 1024 tasks take ~4 seconds for job submission
- for(int i=0; i < taskSize; i++) {
- task_ptr task = fam->add_task ( "t" + boost::lexical_cast<std::string>(i) );
- task->addVerify( VerifyAttr(NState::COMPLETE,4) ); // task should complete 4 times
- }
- }
-
- // The test harness will create corresponding directory structure
- // and populate with standard sms files.
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs, ServerTestHarness::testDataDefsLocation("test_repeat_integer.def"));
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-BOOST_AUTO_TEST_CASE( test_repeat_date )
-{
- DurationTimer timer;
- cout << "Test:: ...test_repeat_date " << flush;
- TestClean clean_at_start_and_end;
-
- // ********************************************************************************
- // IMPORTANT: A family will only complete when it has reached the end of the repeats
- // *********************************************************************************
- //suite test_repeat_date
- // family family
- // repeat date DATE 20110630 20110632
- // task t<n>
- // ....
- // endfamily
- //endsuite
- int taskSize = 2;
- Defs theDefs; {
- suite_ptr suite = theDefs.add_suite("test_repeat_date");
- suite->addVerify( VerifyAttr(NState::COMPLETE,1) );
- family_ptr fam = suite->add_family("family" );
- fam->addRepeat( RepeatDate("DATE",20110630,20110704));
- fam->addVerify( VerifyAttr(NState::COMPLETE,5) );
- for(int i=0; i < taskSize; i++) {
- task_ptr task = fam->add_task( "t" + boost::lexical_cast<std::string>(i) );
- task->addVerify( VerifyAttr(NState::COMPLETE,5) );
- }
- }
-
- // The test harness will create corresponding directory structure
- // and populate with standard sms files.
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs, ServerTestHarness::testDataDefsLocation("test_repeat_date.def"));
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-
-BOOST_AUTO_TEST_CASE( test_repeat_enumerator )
-{
- DurationTimer timer;
- cout << "Test:: ...test_repeat_enumerator " << flush;
- TestClean clean_at_start_and_end;
-
- // ********************************************************************************
- // IMPORTANT: A family will only complete when it has reached the end of the repeats
- // *********************************************************************************
- // suite test_repeat_enumerator
- // family top
- // family plot
- // family iasi_plots
- // repeat enumerated month "200801" "200802"
- // task t1
- // endfamily
- // endfamily
- // endfamily
- // endsuite
-
- Defs theDefs;
- {
- suite_ptr suite = theDefs.add_suite( "test_repeat_enumerator" );
- family_ptr top = suite->add_family("top");
- family_ptr plot = top->add_family("plot");
- family_ptr iasi_plots = plot->add_family("iasi_plots");
- vector<string> months; months.reserve(12); months.push_back("200801"); months.push_back("200802");
- iasi_plots->addRepeat(RepeatEnumerated("month",months));
- task_ptr t1 = iasi_plots->add_task("t1");
- t1->addVerify( VerifyAttr(NState::COMPLETE,2) );
- }
-
- // The test harness will create corresponding directory structure
- // and populate with standard ecf files.
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs, ServerTestHarness::testDataDefsLocation("test_repeat_enumerator.def") );
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-BOOST_AUTO_TEST_CASE( test_repeat_defstatus )
-{
- DurationTimer timer;
- cout << "Test:: ...test_repeat_defstatus " << flush;
- TestClean clean_at_start_and_end;
-
- // TEST SHOULD COMPLETE STRAIGHT AWAY SINCE WE HAVE A DEFSTATUS COMPLETE
- // since the complete state is set on all children of suite.
-
- // Create the defs file corresponding to the text below
- //# Note: we have to use relative paths, since these tests are relocatable
- //suite test_repeat_defstatus
- // defstatus complete
- // repeat integer VAR 0 1 1 # run at 0, 1 2 times
- // edit SLEEPTIME 1
- // edit ECF_INCLUDE $ECF_HOME/includes
- // family family
- // repeat integer VAR 0 2 1 # run at 0, 1 2 times
- // task t<n>
- // ....
- // endfamily
- //endsuite
- int taskSize = 2; // on linux 1024 tasks take ~4 seconds for job submission
- Defs theDefs;
- {
- suite_ptr suite = theDefs.add_suite( "test_repeat_defstatus" );
- suite->addDefStatus(DState::COMPLETE);
- suite->addRepeat( RepeatInteger("VAR",0,1,1));
- suite->addVerify( VerifyAttr(NState::COMPLETE,1) );
-
- family_ptr fam = suite->add_family("family" );
- fam->addRepeat( RepeatInteger("VAR",0,1,1));
- fam->addVerify( VerifyAttr(NState::COMPLETE,1) );
- for(int i=0; i < taskSize; i++) {
-
- task_ptr task = fam->add_task( "t" + boost::lexical_cast<std::string>(i) );
- task->addVerify( VerifyAttr(NState::COMPLETE,1) );
- }
- }
-
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_repeat_defstatus.def"));
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-//#define DEBUG_ME 1
-BOOST_AUTO_TEST_CASE( test_repeat_clears_user_edit )
-{
- // Tests code:: Node::requeueOrSetMostSignificantStateUpNodeTree()
- // In *PARTICULAR* THE REQUE caused by the repeat, this ensures we clear NO_REQUE_IF_SINGLE_TIME_DEP
- // So that the effect of manual run/force complete are negated via automated re-queue caused by a REPEAT
-
- DurationTimer timer;
- cout << "Test:: ...test_repeat_clears_user_edit " << flush;
- TestClean clean_at_start_and_end;
-
- // The functionality where the Repeat requeue clears NO_REQUE_IF_SINGLE_TIME_DEP was added in version 4.0.3
- // Hence we need to disable this test, if the server version is less 403
- // Since these tests can also be used to test backward compatibility. i.e new client old server
- int the_server_version = TestFixture::server_version() ;
- if (the_server_version < 403 ) {
- cout << " SKIPPING, since this test requires server version >= 403, current server version is " << the_server_version << "\n";
- return;
- }
-
- //# Note: we have to use relative paths, since these tests are relocatable
- //suite test_repeat_clears_user_edit
- // edit SLEEPTIME 1
- // edit ECF_INCLUDE $ECF_HOME/includes
- // family family
- // repeat integer VAR 0 3 # run at 0,1,2 i.e 3 times
- // task t<n>
- // time <current time>
- // endfamily
- //endsuite
-
- Defs theDefs;
- task_ptr task;
- {
- boost::posix_time::ptime theLocalTime = boost::posix_time::ptime(date(2010,6,21),time_duration(10,0,0));
- boost::posix_time::ptime time1 = theLocalTime + minutes(3);
-
- suite_ptr suite = theDefs.add_suite( "test_repeat_clears_user_edit" );
- ClockAttr clockAttr(theLocalTime,false);
- suite->addClock( clockAttr );
-
- suite->addDefStatus(DState::SUSPENDED);
- family_ptr fam = suite->add_family("family");
- fam->addRepeat( RepeatInteger("VAR",0,2,1)); // repeat family 3 times
- task = fam->add_task ( "t1" );
- task->addTime( ecf::TimeAttr(ecf::TimeSlot(time1.time_of_day())));
- task->addVerify( VerifyAttr(NState::COMPLETE,3) );
-
- // cout << theDefs << "\n";
- }
-
- // The test harness will create corresponding directory structure
- // and populate with standard sms files.
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs, ServerTestHarness::testDataDefsLocation("test_repeat_integer.def"), 40, false /* waitFortestcompletion */);
-
-#ifdef DEBUG_ME
- PrintStyle::setStyle(PrintStyle::STATE);
- TestFixture::client().sync_local();
- defs_ptr server_defs = TestFixture::client().defs();
- cout << "At start ============================================\n";
- cout << server_defs << "\n";
-#endif
-
- // USER EDIT, on task with a time. The force complete will expire the time.
- // Forcing a task with the time attribute, to complete state, should invalidate/expire the time,
- // Hence it should hold indefinitely, or until it is re-queued manually, or automatically via a Repeat/cron.
- // This Test ensures the the *REQUEUE* via the repeat, resets the time based attribute
- TestFixture::client().force(task->absNodePath(),"complete",true);
- TestFixture::client().force(task->absNodePath(),"complete",true);
-
-
-#ifdef DEBUG_ME
- TestFixture::client().sync_local();
- server_defs = TestFixture::client().defs();
- cout << "After 2 force complete ============================================\n";
- cout << server_defs << "\n";
-
- node_ptr the_task = server_defs->findAbsNode(task->absNodePath());
- BOOST_REQUIRE_MESSAGE(the_task, "Task " << task->absNodePath() << " not found");
- WhyCmd whyCmd( server_defs, the_task->absNodePath());
- std::string reason = whyCmd.why();
- cout << "Why command ============================================\n";
- std::cout << reason << "\n\n";
-#endif
-
- // resume the suspend suite
- TestFixture::client().resume("/test_repeat_clears_user_edit");
-
-#ifdef DEBUG_ME
- TestFixture::client().sync_local();
- server_defs = TestFixture::client().defs();
- cout << "At Resume ============================================\n";
- cout << server_defs << "\n";
-#endif
-
- // Wait for final LOOP of the repeat, and test to finish
- int timeout = 20;
- bool verifyAttrInServer = true;
- defs_ptr serverDefs = serverTestHarness.testWaiter(theDefs,timeout,verifyAttrInServer);
- BOOST_REQUIRE_MESSAGE(serverDefs.get()," Failed to return defs after wait of 20 seconds");
-
-#ifdef DEBUG_ME
- cout << "At test finish ============================================\n";
- cout << serverDefs << "\n";
-#endif
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Test/TestRequeueNode.cpp b/ecflow_4_0_7/Test/TestRequeueNode.cpp
deleted file mode 100644
index 1f98bfe..0000000
--- a/ecflow_4_0_7/Test/TestRequeueNode.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #17 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include "ServerTestHarness.hpp"
-#include "TestFixture.hpp"
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "DurationTimer.hpp"
-#include "PrintStyle.hpp"
-
-#include <boost/test/unit_test.hpp>
-#include <boost/lexical_cast.hpp>
-
-#include <iostream>
-#include <fstream>
-#include <stdlib.h>
-
-using namespace std;
-using namespace ecf;
-
-BOOST_AUTO_TEST_SUITE( TestSuite )
-
-BOOST_AUTO_TEST_CASE( test_requeue_node )
-{
- DurationTimer timer;
- cout << "Test:: ...test_requeue_node " << flush;
- TestClean clean_at_start_and_end;
-
- // Create the defs file corresponding to the text below
- // ECF_HOME variable is automatically added by the test harness.
- // ECF_INCLUDE variable is automatically added by the test harness.
- // SLEEPTIME variable is automatically added by the test harness.
- // ECF_CLIENT_EXE_PATH variable is automatically added by the test harness.
- // This is substituted in sms includes
- // Allows test to run without requiring installation
-
- //# Note: we have to use relative paths, since these tests are relocatable
- //suite test_repeat_integer
- // repeat integer VAR 0 1 1 # run at 0, 1 2 times
- // edit SLEEPTIME 1
- // edit ECF_INCLUDE $ECF_HOME/includes
- // family family
- // repeat integer VAR 0 2 1 # run at 0, 1 2 times
- // task t<n>
- // ....
- // endfamily
- //endsuite
-
- // Each task/job should be run *4* times, according to the repeats Mimics nested loops
- Defs theDefs;
- {
- suite_ptr suite = theDefs.add_suite( "test_reque" );
- suite->addRepeat( RepeatInteger("VAR",0,1,1)); // repeat suite 2 times
- suite->addVerify( VerifyAttr(NState::COMPLETE,2) );
- family_ptr fam = suite->add_family("family" );
- fam->addRepeat( RepeatInteger("VAR",0,1,1)); // repeat family 2 times
- fam->addVerify( VerifyAttr(NState::COMPLETE,4) );
- int taskSize = 2; // on linux 1024 tasks take ~4 seconds for job submission
- for(int i=0; i < taskSize; i++) {
- task_ptr task = fam->add_task( "t" + boost::lexical_cast<std::string>(i));
- task->addVerify( VerifyAttr(NState::COMPLETE,4) ); // task should complete 4 times
- }
- }
-
- // The test harness will create corresponding directory structure
- // and populate with standard sms files.
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_reque.def") );
-
- // Now re-queue the whole suite
- TestFixture::client().set_throw_on_error( true );
- TestFixture::client().requeue("/test_reque");
-
- // Wait for test to finish
- int timeout = 30;
- bool verifyAttrInServer = false;
- defs_ptr serverDefs = serverTestHarness.testWaiter(theDefs,timeout,verifyAttrInServer);
- BOOST_REQUIRE_MESSAGE(serverDefs.get()," Failed to return server after re-queue");
-
-// cout << "Printing Defs \n";
-// std::cout << *serverDefs.get();
-
- // since we requed each task should have completed 8 times
- std::vector<Task*> taskVec;
- serverDefs->getAllTasks(taskVec);
- BOOST_FOREACH(Task* t, taskVec) {
- BOOST_FOREACH(const VerifyAttr& v, t->verifys()) {
- if (v.state() == NState::COMPLETE) {
- BOOST_CHECK_MESSAGE(v.actual() == 8,"Expected task " << t->absNodePath() << " to complete 8 times, due to reque, but it completed only " << v.actual() << " times\n");
- }
- }
- }
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Test/TestRunner.cpp b/ecflow_4_0_7/Test/TestRunner.cpp
deleted file mode 100644
index d4444d9..0000000
--- a/ecflow_4_0_7/Test/TestRunner.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-#define BOOST_TEST_MODULE Test
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include "TestFixture.hpp"
-#include <boost/test/unit_test.hpp>
-
-// Global test fixture. Dues to boost deficiency this can't be accessed. hence
-// TestFixture makes use of global data.
-BOOST_GLOBAL_FIXTURE( TestFixture );
diff --git a/ecflow_4_0_7/Test/TestServer.cpp b/ecflow_4_0_7/Test/TestServer.cpp
deleted file mode 100644
index 7e1530a..0000000
--- a/ecflow_4_0_7/Test/TestServer.cpp
+++ /dev/null
@@ -1,135 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #39 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <iostream>
-#include <fstream>
-#include <stdlib.h>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/test/unit_test.hpp>
-#include <boost/lexical_cast.hpp>
-
-#include "ServerTestHarness.hpp"
-#include "TestFixture.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "DurationTimer.hpp"
-#include "Host.hpp"
-#include "Str.hpp"
-
-using namespace std;
-using namespace ecf;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( TestSuite )
-
-// In the test case we will dynamically create all the test data.
-// The data is created dynamically so that we can stress test the server
-// This test does not have any time dependencies in the def file.
-BOOST_AUTO_TEST_CASE( test_server_job_submission )
-{
- DurationTimer timer;
- cout << "Test:: ...test_server_job_submission "<< flush;
- TestClean clean_at_start_and_end;
-
- //# Note: we have to use relative paths, since these tests are relocatable
- //suite test_server_job_submission
- // edit SLEEPTIME 1
- // edit ECF_INCLUDE $ECF_HOME/includes
- // family family
- // task t<n>
- // ....
- // endfamily
- //endsuite
- Defs theDefs;
- {
- suite_ptr suite = theDefs.add_suite( "test_server_job_submission" );
- family_ptr fam = suite->add_family("family" );
- fam->addVerify( VerifyAttr(NState::COMPLETE,1) );
- int taskSize = 3; // on linux 1024 tasks take ~4 seconds for job submission
- for(int i=0; i < taskSize; i++) {
- task_ptr task = fam->add_task( "t" + boost::lexical_cast<std::string>(i));
- task->addVerify( VerifyAttr(NState::COMPLETE,1) );
- }
- }
-
- // The test harness will create corresponding directory structure and populate with standard ecf files.
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_server_job_submission.def"));
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-BOOST_AUTO_TEST_CASE( test_restore_defs_from_check_pt )
-{
- DurationTimer timer;
- cout << "Test:: ...test_restore_defs_from_check_pt "<< flush;
- TestClean clean_at_start_and_end;
- // **********************************************************************
- // In order for this test to work, we need to disable the automatic
- // check pointing done by the server. Otherwise it will interfere with
- // this test. This is re-enabled at the end of the test
- // ************************************************************************
- Defs theDefs; {
- suite_ptr suite = Suite::create( "test_restore_defs_from_check_pt" );
- suite->addTask( Task::create( "t1" ) );
- theDefs.addSuite( suite );
- }
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_restore_defs_from_check_pt.def"));
-
- TestFixture::client().set_throw_on_error(false);
-
- // Disable server check pointing
- BOOST_REQUIRE_MESSAGE(TestFixture::client().checkPtDefs(ecf::CheckPt::NEVER) == 0,CtsApi::checkPtDefs(ecf::CheckPt::NEVER) << " failed should return 0\n" << TestFixture::client().errorMsg());
-
- Host h;
- std::string check_pt_file_name = h.ecf_checkpt_file(TestFixture::port());
-
- // make sure we have a valid definition with at least one suite before start
- BOOST_REQUIRE_MESSAGE( TestFixture::client().getDefs() == 0, "Expected getDefs() to succeed\n");
- BOOST_REQUIRE_MESSAGE( TestFixture::client().defs()->suiteVec().size() == 1, "Expected 1 suite at the start\n");
-
- // Check pt, make sure file exist on disk and has a non zero file size\n";
- BOOST_REQUIRE_MESSAGE( TestFixture::client().checkPtDefs() == 0,"Expected Check-pt to succeed.\n" << TestFixture::client().errorMsg());
- BOOST_REQUIRE_MESSAGE( fs::exists(check_pt_file_name),CtsApi::checkPtDefs() << " failed file(" << check_pt_file_name << ") not saved");
- BOOST_REQUIRE_MESSAGE( fs::file_size(check_pt_file_name) !=0,"Expected check point file(" << check_pt_file_name << ") to have file size > 0");
-
- // Make sure restore from check pt, only works if server is halted and there are no suites\n";
- BOOST_REQUIRE_MESSAGE( TestFixture::client().restoreDefsFromCheckPt() == 1,"Expected restoreDefsFromCheckPt to *FAIL* since server not halted\n");
- BOOST_REQUIRE_MESSAGE( TestFixture::client().haltServer() == 0,"Expected halt server to succeed\n" << TestFixture::client().errorMsg());
- BOOST_REQUIRE_MESSAGE( TestFixture::client().restoreDefsFromCheckPt() == 1,"Expected restoreDefsFromCheckPt to *FAIL* since definition not deleted yet\n");
- BOOST_REQUIRE_MESSAGE( TestFixture::client().delete_all() == 0,"Expected delete all nodes to succeed\n" << TestFixture::client().errorMsg());
- BOOST_REQUIRE_MESSAGE( TestFixture::client().getDefs() == 0, "Expected getDefs() to succeed, i.e expected empty defs\n");
- BOOST_REQUIRE_MESSAGE( TestFixture::client().defs()->suiteVec().empty(), "Expected no suites, after delete_all()\n");
-
- // make sure check pt file still exists, sanity test\n";
- BOOST_REQUIRE_MESSAGE( fs::exists(check_pt_file_name),CtsApi::checkPtDefs() << " failed file(" << check_pt_file_name << ") not saved");
- BOOST_REQUIRE_MESSAGE( fs::file_size(check_pt_file_name) !=0,"Expected check point file(" << check_pt_file_name << ") to have file size > 0");
-
- // make sure restore actually worked, by retrieving the definition and counting the suites\n";
- BOOST_REQUIRE_MESSAGE( TestFixture::client().restoreDefsFromCheckPt() == 0,"Expected restoreDefsFromCheckPt to *SUCCEED*, since server halted and defs deleted \n" << TestFixture::client().errorMsg());
- BOOST_REQUIRE_MESSAGE( TestFixture::client().getDefs() == 0, "Get defs failed should return 0\n" << TestFixture::client().errorMsg());
- BOOST_REQUIRE_MESSAGE( TestFixture::client().defs()->suiteVec().size() == 1, "Restore from check pt did not work. expected 1 suite but found " << TestFixture::client().defs()->suiteVec().size() );
-
- // restore default check pointing, for test that follow
- BOOST_REQUIRE_MESSAGE(TestFixture::client().checkPtDefs(ecf::CheckPt::ON_TIME,120) == 0,CtsApi::checkPtDefs(ecf::CheckPt::ON_TIME) << " failed should return 0\n" << TestFixture::client().errorMsg());
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Test/TestSingle.cpp b/ecflow_4_0_7/Test/TestSingle.cpp
deleted file mode 100644
index 356caae..0000000
--- a/ecflow_4_0_7/Test/TestSingle.cpp
+++ /dev/null
@@ -1,182 +0,0 @@
-#define BOOST_TEST_MODULE TEST_SINGLE
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #80 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : This is used to INVOKE a SINGLE test.
-// Making it easier for Easier for debugging and development
-//============================================================================
-#include <iostream>
-#include <limits> // for std::numeric_limits<int>::max()
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/lexical_cast.hpp>
-#include <boost/test/unit_test.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include "TestFixture.hpp"
-#include "ServerTestHarness.hpp"
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "DurationTimer.hpp"
-#include "PrintStyle.hpp"
-#include "ClientToServerCmd.hpp"
-#include "DefsStructureParser.hpp"
-#include "AssertTimer.hpp"
-#include "File.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-namespace fs = boost::filesystem;
-
-BOOST_GLOBAL_FIXTURE( TestFixture );
-
-BOOST_AUTO_TEST_SUITE( TestSingleSuite )
-
-
-// DO NOT delete
-// This is used to test large defs. and hence server performance & memory leaks
-// Be sure to comment out defstatus suspended in mega.def
-BOOST_AUTO_TEST_CASE( test_mega_def )
-{
- DurationTimer timer;
-
- // location to mega.def and left over log file
- std::string log_file = File::test_data("AParser/test/data/single_defs/mega.def_log","AParser");
- std::string path = File::test_data("AParser/test/data/single_defs/mega.def","AParser");
-
- cout << "Test:: ..." << path << " log file: " << log_file << flush;
-
- // Remove the log file.
- boost::filesystem::remove(log_file);
-
- // parse in file
- Defs theDefs;
- DefsStructureParser checkPtParser( &theDefs, path);
- std::string errorMsg,warningMsg;
- BOOST_REQUIRE_MESSAGE(checkPtParser.doParse(errorMsg,warningMsg),errorMsg);
-
- ServerTestHarness serverTestHarness;
- serverTestHarness.check_task_duration_less_than_server_poll(false); // Add variable CHECK_TASK_DURATION_LESS_THAN_SERVER_POLL
- serverTestHarness.run(theDefs,path,std::numeric_limits<int>::max()/*timeout*/ );
-
- cout << timer.duration() << "\n";
-}
-
-// DO NOT delete
-// This is used to test with thousands of labels
-//BOOST_AUTO_TEST_CASE( test_large_client_labels_calls )
-//{
-// DurationTimer timer;
-// cout << "Test:: ...test_large_client_labels_calls "<< flush;
-// TestClean clean_at_start_and_end;
-//
-// //# Note: we have to use relative paths, since these tests are relocatable
-// // suite test_large_client_labels_calls
-// // family family
-// // task t1
-// // label name "value"
-// // endfamily
-// // endsuite
-// Defs theDefs;
-// {
-// suite_ptr suite = theDefs.add_suite("test_large_client_labels_calls");
-// family_ptr fam = suite->add_family("family");
-// task_ptr t1 = fam->add_task("t1");
-// t1->addLabel( Label("name","value"));
-// }
-//
-// // Create a custom ecf file for test_large_client_labels_calls/family/t1 to invoke label commands
-// std::string templateEcfFile;
-// templateEcfFile += "%include <head.h>\n";
-// templateEcfFile += "\n";
-// templateEcfFile += "echo do some work\n";
-// templateEcfFile += "i=1\n";
-// templateEcfFile += "while [ \"$i\" -le 10000 ] \n";
-// templateEcfFile += "do\n";
-// templateEcfFile += " %ECF_CLIENT_EXE_PATH% --label=name \"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\"\n";
-// templateEcfFile += " i=$((i+1))\n";
-// templateEcfFile += "done\n";
-// templateEcfFile += "\n";
-// templateEcfFile += "%include <tail.h>\n";
-//
-// // The test harness will create corresponding directory structure
-// // Override the default ECF file, with our custom ECF_ file
-// std::map<std::string,std::string> taskEcfFileMap;
-// taskEcfFileMap.insert(std::make_pair(TestFixture::taskAbsNodePath(theDefs,"t1"),templateEcfFile));
-//
-// // Avoid standard verification since we expect to abort many times
-// ServerTestHarness serverTestHarness;
-// serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_large_client_labels_calls.def"), taskEcfFileMap,1000000);
-//
-// cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n" << endl;
-//}
-//
-
-//// DO NOT delete
-/// The following test verifies that the job generation is largely linear.
-/// Job submission interval was 3 seconds. In release mode.
-///
-/// Test duration is highly dependent on the OS/process handling.
-/// No of tasks Job generation Peak request/sec in server
-/// 10 -
-/// 100 -
-/// 500 - 364
-/// 1000 4 450
-/// 1500 6 550
-/// 2000 9 880
-/// 3000 15 800
-/// 4000 24 923
-/// 5000 29 800
-/// 6000 37 900
-//void time_for_tasks(int tasks) {
-//
-// std::string test_name = "test_stress_" + boost::lexical_cast<std::string>(tasks);
-// cout << "Test:: ..." << test_name << flush;
-//
-// Defs theDefs;
-// {
-// suite_ptr suite = theDefs.add_suite( test_name );
-// family_ptr fam = suite->add_family("fam" );
-// for(int i = 0; i < tasks; i++) {
-// fam->add_task( "t" + boost::lexical_cast<std::string>(i));
-// }
-// // suite->addRepeat( RepeatDate("YMD",19000101,99991201,1) );
-// }
-//
-// ServerTestHarness serverTestHarness;
-// serverTestHarness.check_task_duration_less_than_server_poll(false); // Add variable CHECK_TASK_DURATION_LESS_THAN_SERVER_POLL
-// DurationTimer timer;
-// serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation(test_name + ".def"), std::numeric_limits<int>::max()/*timeout*/ );
-// cout << " " << timer.duration() << "s\n";
-//}
-//
-//// Use to stress test server. i.e continually fire client requests.
-//BOOST_AUTO_TEST_CASE( test_stress )
-//{
-// time_for_tasks(10);
-// time_for_tasks(100);
-// time_for_tasks(500);
-// time_for_tasks(1000);
-// time_for_tasks(1500);
-// time_for_tasks(2000);
-// time_for_tasks(3000);
-// time_for_tasks(4000);
-// time_for_tasks(5000);
-//}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Test/TestSuspend.cpp b/ecflow_4_0_7/Test/TestSuspend.cpp
deleted file mode 100644
index d80b702..0000000
--- a/ecflow_4_0_7/Test/TestSuspend.cpp
+++ /dev/null
@@ -1,228 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #24 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <iostream>
-#include <fstream>
-#include <stdlib.h>
-
-#include <boost/test/unit_test.hpp>
-#include <boost/lexical_cast.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include "ServerTestHarness.hpp"
-#include "TestFixture.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "DurationTimer.hpp"
-#include "PrintStyle.hpp"
-#include "AssertTimer.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-
-#if defined(_AIX)
-static int timeout = 30 ;
-#else
-static int timeout = 20 ;
-#endif
-
-
-BOOST_AUTO_TEST_SUITE( TestSuite )
-
-static void waitForTimeDependenciesToBeFree(int max_time_to_wait)
-{
- // wait for a period of time, while time dependencies fire.
- TestFixture::client().set_throw_on_error( false );
- AssertTimer assertTimer(max_time_to_wait,false); // Bomb out after n seconds, fall back if test fail
- while (1) {
- BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0,"sync_local failed should return 0\n" << TestFixture::client().errorMsg());
- defs_ptr defs = TestFixture::client().defs();
- vector<Task*> tasks; defs->getAllTasks(tasks);
- size_t taskTimeDepIsFree = 0 ;
- BOOST_FOREACH(Task* task, tasks) {
- size_t attSetFree = 0;
- BOOST_FOREACH( const ecf::TimeAttr& timeAttr, task->timeVec()) {
- if (timeAttr.isFree(task->suite()->calendar())) attSetFree++;
- }
- if ( attSetFree == task->timeVec().size()) taskTimeDepIsFree++;
- }
- if ( taskTimeDepIsFree == tasks.size()) break;
-
- BOOST_REQUIRE_MESSAGE(assertTimer.duration() < assertTimer.timeConstraint(),
- "waitForTimeDependenciesToBeFree Test wait " << assertTimer.duration() <<
- " taking longer than time constraint of " << assertTimer.timeConstraint() <<
- " aborting");
- sleep(1);
- }
-}
-
-// test:: suspend/shutdown. During suspend the time dependencies should still
-// be handled. When the server/node is restarted/resumed the task should
-// be submitted straight away.(i.e providing no trigger/complete dependencies)
-BOOST_AUTO_TEST_CASE( test_shutdown )
-{
- DurationTimer timer;
- cout << "Test:: ...test_shutdown " << flush;
- TestClean clean_at_start_and_end;
-
- // Create the defs file corresponding to the text below
- // ECF_HOME variable is automatically added by the test harness.
- // ECF_INCLUDE variable is automatically added by the test harness.
- // SLEEPTIME variable is automatically added by the test harness.
- // ECF_CLIENT_EXE_PATH variable is automatically added by the test harness.
- // This is substituted in sms includes
- // Allows test to run without requiring installation
-
- int taskSize = 2; // on linux 1024 tasks take ~4 seconds for job submission
- Defs theDefs;
- {
- // Initialise clock with todays date and time, then create a time attribute
- // with todays time + minute Avoid adding directly to TimeSlot
- // i.e if local time is 9:59 and we create a TimeSlot like
- // task->addTime( ecf::TimeAttr( ecf::TimeSlot(theTm.tm_hour,theTm.tm_min+3) ) );
- // The the minute will be 62, which is illegal and will not parse
- boost::posix_time::ptime theLocalTime = Calendar::second_clock_time();
-
- // For each 2 seconds of poll in the server update calendar by 1 minute
- // Note: if we use 1 seconds poll to update calendar by 1 minute, then
- // we will find that state change happens at job submission interval,
- // and hence skews time series. Which can leave state in a queued state,
- // and hence test never completes
- suite_ptr suite = theDefs.add_suite("test_shutdown");
- ClockAttr clockAttr(theLocalTime);
- suite->addClock( clockAttr );
-
- family_ptr fam = suite->add_family("family");
- for(int i=0; i < taskSize; i++) {
- task_ptr task = fam->add_task("t" + boost::lexical_cast<std::string>(i));
-
- boost::posix_time::ptime time1 = theLocalTime + minutes(1 + i);
- task->addTime( ecf::TimeAttr( ecf::TimeSlot(time1.time_of_day()) ));
-
- task->addVerify( VerifyAttr(NState::COMPLETE,1) ); // task should complete 1 times
- }
- }
-
- // The test harness will create corresponding directory structure and populate with standard sms files.
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,
- ServerTestHarness::testDataDefsLocation("test_shutdown.def"),
- 1,
- false/* don't wait for test to finish */);
-
-
- // Shutdown the server. The time dependencies *should* still be handled
- // *** If this test fails, in that we fail to restart() server it will mess up
- // *** any following test.
- TestFixture::client().set_throw_on_error( false );
- BOOST_REQUIRE_MESSAGE( TestFixture::client().shutdownServer() == 0,CtsApi::shutdownServer() << " failed should return 0.\n" << TestFixture::client().errorMsg());
-
- // wait for a period of time, while time dependencies fire.
- (void)waitForTimeDependenciesToBeFree(timeout );
-
- // restart server, all jobs should be launched straight away
- BOOST_REQUIRE_MESSAGE( TestFixture::client().restartServer() == 0,CtsApi::restartServer() << " failed should return 0.\n" << TestFixture::client().errorMsg());
-
- // Wait for submitted jobs in restart server to complete
- bool verifyAttrInServer = true;
- defs_ptr serverDefs = serverTestHarness.testWaiter(theDefs,timeout,verifyAttrInServer);
- BOOST_REQUIRE_MESSAGE(serverDefs.get()," Failed to return server after restartServer");
-
- // cout << "Printing Defs \n";
- // std::cout << *serverDefs.get();
-
- cout << timer.duration() << " update-calendar-count(" << serverDefs->updateCalendarCount() << ")\n";
-}
-
-
-// test:: suspend/shutdown. During suspend the time dependencies should still
-// be handled. When the server/node is restarted/resumed the task should
-// be submitted straight away.(i.e providing no trigger/complete dependencies)
-BOOST_AUTO_TEST_CASE( test_suspend_node )
-{
- DurationTimer timer;
- cout << "Test:: ...test_suspend_node " << flush;
- TestClean clean_at_start_and_end;
-
- // Create the defs file corresponding to the text below
- // ECF_HOME variable is automatically added by the test harness.
- // ECF_INCLUDE variable is automatically added by the test harness.
- // SLEEPTIME variable is automatically added by the test harness.
- // ECF_CLIENT_EXE_PATH variable is automatically added by the test harness.
- // This is substituted in sms includes
- // Allows test to run without requiring installation
- Defs theDefs;
- {
- // Initialise clock with todays date and time, then create a time attribute
- // with todays time + minute Avoid adding directly to TimeSlot
- // i.e if local time is 9:59 and we create a TimeSlot like
- // task->addTime( ecf::TimeAttr( ecf::TimeSlot(theTm.tm_hour,theTm.tm_min+3) ) );
- // The the minute will be 62, which is illegal and will not parse
- boost::posix_time::ptime theLocalTime = Calendar::second_clock_time();
-
- suite_ptr suite = theDefs.add_suite("test_suspend_node");
- ClockAttr clockAttr(theLocalTime);
- suite->addClock( clockAttr );
-
- task_ptr t1 = suite->add_task( "t1");
- boost::posix_time::ptime time1 = theLocalTime + minutes(1);
- t1->addTime( ecf::TimeAttr( ecf::TimeSlot(time1.time_of_day()) ));
-
- task_ptr t2 = suite->add_task( "t2");
- boost::posix_time::ptime time2 = theLocalTime + minutes(2);
- t2->addTime( ecf::TimeAttr( ecf::TimeSlot(time2.time_of_day()) ));
-
- family_ptr fam = suite->add_family("family");
- for(int i=0; i < 2; i++) {
- task_ptr task = fam->add_task("t" + boost::lexical_cast<std::string>(i));
- task->addVerify( VerifyAttr(NState::COMPLETE,1) ); // task should complete 1 times
-
- boost::posix_time::ptime time1 = theLocalTime + minutes(1 + i);
- task->addTime( ecf::TimeAttr( ecf::TimeSlot(time1.time_of_day()) ));
- }
- }
-
- // The test harness will create corresponding directory structure and populate with standard sms files.
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,
- ServerTestHarness::testDataDefsLocation("test_suspend_node.def"),
- 1,
- false/* don't wait for test to finish */);
-
- // SUSPEND the family. The time dependencies *should* still be handled
- TestFixture::client().set_throw_on_error( false );
- BOOST_REQUIRE_MESSAGE( TestFixture::client().suspend("/test_suspend_node/family") == 0,CtsApi::to_string(CtsApi::suspend("/test_suspend_node/family")) << " failed should return 0.\n" << TestFixture::client().errorMsg());
-
- // wait for a period of time, while time dependencies fire.
- waitForTimeDependenciesToBeFree(timeout);
-
- // RESUME the family, all jobs should be launched straight away, since time dependencies should be free
- BOOST_REQUIRE_MESSAGE( TestFixture::client().resume("/test_suspend_node/family") == 0,CtsApi::to_string(CtsApi::resume("/test_suspend_node/family")) << " failed should return 0.\n" << TestFixture::client().errorMsg());
-
- // Wait for submitted jobs to complete
- bool verifyAttrInServer = true;
- defs_ptr serverDefs = serverTestHarness.testWaiter(theDefs,timeout,verifyAttrInServer);
- BOOST_REQUIRE_MESSAGE(serverDefs.get()," Failed to return server after restartServer");
-
- // cout << "Printing Defs \n";
- // std::cout << *serverDefs.get();
-
- cout << timer.duration() << " update-calendar-count(" << serverDefs->updateCalendarCount() << ")\n";
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Test/TestToday.cpp b/ecflow_4_0_7/Test/TestToday.cpp
deleted file mode 100644
index 0729c42..0000000
--- a/ecflow_4_0_7/Test/TestToday.cpp
+++ /dev/null
@@ -1,201 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #35 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <iostream>
-#include <fstream>
-#include <stdlib.h>
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/test/unit_test.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include "ServerTestHarness.hpp"
-#include "TestFixture.hpp"
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "DurationTimer.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-
-BOOST_AUTO_TEST_SUITE( TestSuite )
-
-// In the test case we will dynamically create all the test data.
-// The data is created dynamically so that we can stress test the server
-BOOST_AUTO_TEST_CASE( test_today_single_slot )
-{
- DurationTimer timer;
- cout << "Test:: ...test_today_single_slot " << flush;
- TestClean clean_at_start_and_end;
-
- // **************************************************************************
- // It does not really make sense to have multiple today attributes
- // since as soon as one today has expired the task is free to run
- // suite test_today_mutiple_single_slot
- // edit SLEEPTIME 1
- // edit ECF_INCLUDE $ECF_HOME/includes
- // clock real <todays date>
- // family family
- // task t1
- // today 10.01 // after 10.01, the node is free, for 10.02,10.03
- // today 10.04
- // endfamily
- // endsuite
-
- //# Note: we have to use relative paths, since these tests are relocatable
- //suite test_today_single_slot
- // edit SLEEPTIME 1
- // edit ECF_INCLUDE $ECF_HOME/includes
- // clock real <todays date>
- // family family
- // task t1
- // today 11.12
- // endfamily
- //endsuite
- Defs theDefs;
- {
- // Initialise clock with todays date and time, then create a today attribute
- // one hour past the clock todays time. The node should be free to run.
- boost::posix_time::ptime theLocalTime = boost::posix_time::ptime(date(2010,6,21),time_duration(10,0,0));
- boost::posix_time::ptime time_minus_hour = theLocalTime - hours(1);
-
- suite_ptr suite = theDefs.add_suite( "test_today_single_slot");
- ClockAttr clockAttr(theLocalTime,false,true/*positive gain*/);
- suite->addClock( clockAttr );
-
- family_ptr fam = suite->add_family( "family");
- task_ptr task = fam->add_task( "t");
- task->addToday( ecf::TodayAttr(ecf::TimeSlot(time_minus_hour.time_of_day())) );
- }
-
- // The test harness will create corresponding directory structure
- // and populate with standard sms files.
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_today_single_slot.def"));
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-BOOST_AUTO_TEST_CASE( test_today_relative_time_series )
-{
- DurationTimer timer;
- cout << "Test:: ...test_today_relative_time_series " << flush;
- TestClean clean_at_start_and_end;
-
- // SLOW SYSTEMS
- // for each time attribute leave GAP of 3 * job submission interval
- // on slow systems submitted->active->complete > TestFixture::job_submission_interval()
- // Also the task duration must be greater than job_submission_interval, otherwise
- // we will get multiple invocation for the same time step
-
- //# Note: we have to use relative paths, since these tests are relocatable
- //suite test_today_relative_time_series
- // edit SLEEPTIME 1
- // edit ECF_INCLUDE $ECF_HOME/includes
- // clock real <todays date>
- // family family
- // task t1
- // today <start> <finish> <incr>
- // endfamily
- //endsuite
- Defs theDefs;
- {
- // Initialise clock with todays date and time, then create a today attribute
- // with a time series, so that task runs 3 times
- suite_ptr suite = theDefs.add_suite( "test_today_relative_time_series");
- suite->add_variable("SLEEPTIME",boost::lexical_cast<std::string>(TestFixture::job_submission_interval()-1));
- ClockAttr clockAttr(Calendar::second_clock_time(),false);
- suite->addClock( clockAttr );
-
- family_ptr fam = suite->add_family( "family");
- task_ptr task = fam->add_task( "t");
- task->addToday( ecf::TodayAttr(
- ecf::TimeSlot(0,1),
- ecf::TimeSlot(0,7),
- ecf::TimeSlot(0,3),
- true /*relative to suite start*/
- )
- );
- task->addVerify( VerifyAttr(NState::COMPLETE,3) ); // task should complete 3 times
- }
-
- // The test harness will create corresponding directory structure
- // and populate with standard ecf files.
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_today_relative_time_series.def"));
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-BOOST_AUTO_TEST_CASE( test_today_real_time_series )
-{
- DurationTimer timer;
- cout << "Test:: ...test_today_real_time_series " << flush;
- TestClean clean_at_start_and_end;
-
- // SLOW SYSTEMS
- // for each time attribute leave GAP of 3 * job submission interval
- // on slow systems submitted->active->complete > TestFixture::job_submission_interval()
- // Also the task duration must be greater than job_submission_interval, otherwise
- // we will get multiple invocation for the same time step
-
- //# Note: we have to use relative paths, since these tests are relocatable
- //suite test_today_real_time_series
- // edit ECF_INCLUDE $ECF_HOME/includes
- // clock real <todays date>
- // family family
- // task t1
- // today 10:01 10:07 00:03
- // endfamily
- //endsuite
- Defs theDefs;
- {
- // Initialise clock with a fixed date and time, then create a today attribute
- // with a time series, so that task runs 3 times
- boost::posix_time::ptime theLocalTime = boost::posix_time::ptime(date(2010,6,21),time_duration(10,0,0));
- boost::posix_time::ptime time1 = theLocalTime + minutes(1);
- boost::posix_time::ptime time2 = theLocalTime + minutes(7);
-
- suite_ptr suite = theDefs.add_suite( "test_today_real_time_series");
- ClockAttr clockAttr(theLocalTime,false);
- suite->addClock( clockAttr );
- suite->add_variable("SLEEPTIME",boost::lexical_cast<std::string>(TestFixture::job_submission_interval()-1));
- suite->addVerify( VerifyAttr(NState::COMPLETE,1) );
-
- family_ptr fam = suite->add_family( "family");
- fam->addVerify( VerifyAttr(NState::COMPLETE,1) );
- task_ptr task = fam->add_task( "t");
- task->addToday( ecf::TodayAttr(
- ecf::TimeSlot(time1.time_of_day()),
- ecf::TimeSlot(time2.time_of_day()),
- ecf::TimeSlot(0,3)
- )
- );
- task->addVerify( VerifyAttr(NState::COMPLETE,3) ); // task should complete 3 times
- }
-
- // The test harness will create corresponding directory structure
- // and populate with standard ecf files.
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_today_real_time_series.def"));
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Test/TestTrigger.cpp b/ecflow_4_0_7/Test/TestTrigger.cpp
deleted file mode 100644
index 1b25827..0000000
--- a/ecflow_4_0_7/Test/TestTrigger.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #29 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <iostream>
-#include <fstream>
-#include <stdlib.h>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/test/unit_test.hpp>
-#include <boost/lexical_cast.hpp>
-
-#include "ServerTestHarness.hpp"
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "DurationTimer.hpp"
-#include "Str.hpp"
-
-
-using namespace std;
-using namespace ecf;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( TestSuite )
-
-// In the test case we will dynamically create all the test data.
-// The data is created dynamically so that we can stress test the server
-// This test does not have any time dependencies in the def file.
-BOOST_AUTO_TEST_CASE( test_triggers_and_meters )
-{
- DurationTimer timer;
- cout << "Test:: ...test_triggers_and_meters " << flush;
- TestClean clean_at_start_and_end;
-
- //# Note: we have to use relative paths, since these tests are relocatable
- //suite test_triggers_and_meters
- // edit SLEEPTIME 1
- // edit ECF_INCLUDE $ECF_HOME/includes
- // family family
- // task model
- // meter file 0 100 100
- // task t0
- // trigger model:file ge 10
- // task t1
- // trigger model:file ge 20
- // task t2
- // trigger model:file ge 30
- // ....
- // endfamily
- //endsuite
- std::string meterName = "file";
- std::string taskName = "model";
- Defs theDefs;
- {
- suite_ptr suite = theDefs.add_suite( "test_triggers_and_meters");
- suite->addVerify( VerifyAttr(NState::COMPLETE,1) );
- family_ptr fam = suite->add_family( "family");
- fam->addVerify( VerifyAttr(NState::COMPLETE,1) );
-
- task_ptr taskModel = fam->add_task(taskName);
- taskModel->addMeter( Meter(meterName,0,100,100) ); // ServerTestHarness will add correct ecf
-
- int taskSize = 9; // on linux 1024 tasks take ~4 seconds for job submission
- for(int i=0; i < taskSize; i++) {
- task_ptr task = fam->add_task( "t" + boost::lexical_cast<std::string>(i*10 + 10) );
- task->addVerify( VerifyAttr(NState::COMPLETE,1) );
- task->add_trigger( taskName + Str::COLON() + meterName + " ge " + boost::lexical_cast<std::string>(i*10 + 10) );
- }
- }
-
- // The test harness will create corresponding directory structure & default ecf file
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation( "test_triggers_and_meters.def"));
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Test/TestWhyCmd.cpp b/ecflow_4_0_7/Test/TestWhyCmd.cpp
deleted file mode 100644
index c4947ea..0000000
--- a/ecflow_4_0_7/Test/TestWhyCmd.cpp
+++ /dev/null
@@ -1,538 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #27 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <iostream>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/lexical_cast.hpp>
-#include <boost/test/unit_test.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include "ServerTestHarness.hpp"
-#include "TestFixture.hpp"
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "DurationTimer.hpp"
-#include "PrintStyle.hpp"
-#include "ClientToServerCmd.hpp"
-#include "AssertTimer.hpp"
-#include "WhyCmd.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( TestSuite )
-
-static unsigned int waitForWhy(const std::string& path, const std::string& why, int max_time_to_wait)
-{
- unsigned int updateCalendarCount = 0;
- TestFixture::client().set_throw_on_error( false );
- AssertTimer assertTimer(max_time_to_wait,false); // Bomb out after n seconds, fall back if test fail
- while (1) {
-
- /// Why command relies on the Suite serializing the calendar. If this is changed we need to get the full defs
- BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0, "sync_local failed should return 0\n" << TestFixture::client().errorMsg());
- defs_ptr server_defs = TestFixture::client().defs();
- updateCalendarCount = server_defs->updateCalendarCount();
-
- WhyCmd whyCmd( server_defs, path);
- std::string reason = whyCmd.why();
- // std::cout << reason;
-
- if (reason.find(why) != std::string::npos) {
- // see the reason why job is not running
- std::cout << reason;
- break;
- }
-
- BOOST_REQUIRE_MESSAGE(assertTimer.duration() < assertTimer.timeConstraint(),
- "waitForWhy Test wait " << assertTimer.duration() <<
- " taking longer than time constraint of " << assertTimer.timeConstraint() <<
- " aborting\n" << *server_defs);
- sleep(1);
- }
- return updateCalendarCount;
-}
-
-BOOST_AUTO_TEST_CASE( test_why_day )
-{
- DurationTimer timer;
- cout << "Test:: ...test_why_day "<< flush;
- TestClean clean_at_start_and_end;
-
- Defs theDefs;
- {
- boost::posix_time::ptime today = Calendar::second_clock_time();
- suite_ptr suite = Suite::create("test_why_day" ) ;
- family_ptr fam = Family::create( "family" );
- task_ptr task = Task::create( "t1" );
-
- // Dont use hybrid for day dependency as that will force node to complete if days is not the same
- ClockAttr clockAttr(today, false);
- suite->addClock( clockAttr );
-
- // ** add tomorrow days so that node stays queued **
- task->addDay( DayAttr( today.date() + boost::gregorian::date_duration(1 ) ) );
-
- fam->addTask( task );
- suite->addFamily( fam );
- theDefs.addSuite( suite );
- }
-
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,
- ServerTestHarness::testDataDefsLocation("test_why_day.def"),
- 1/*timeout*/,
- false /* waitForTestCompletion*/);
-
- // The job should not be submitted and should stay queued since the day does not match
- // running the why command, should report dependency on day
- unsigned int updateCalendarCount = waitForWhy("/test_why_day/family/t1", "day", 10);
-
- cout << " " << timer.duration() << " update-calendar-count(" << updateCalendarCount << ")\n";
-}
-
-BOOST_AUTO_TEST_CASE( test_why_date )
-{
- DurationTimer timer;
- cout << "Test:: ...test_why_date "<< flush;
-
- Defs theDefs;
- {
- suite_ptr suite = Suite::create("test_why_date" ) ;
- family_ptr fam = Family::create( "family" );
- task_ptr task = Task::create( "t1" );
-
- // Don't use hybrid for date dependency as that will force node to complete if date is not the same
- boost::posix_time::ptime today = Calendar::second_clock_time();
- ClockAttr clockAttr(today, false);
- suite->addClock( clockAttr );
-
- // ** add tomorrow date so that node stays queued **
- task->addDate( DateAttr( today.date() + boost::gregorian::date_duration(1 )) );
- fam->addTask( task );
- suite->addFamily( fam );
- theDefs.addSuite( suite );
- }
-
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,
- ServerTestHarness::testDataDefsLocation("test_why_date.def"),
- 1/*timeout*/,
- false /* waitForTestCompletion*/);
-
- // The job should not be submitted and should stay queued since the day does not match
- // running the why command, should report dependency on day
- unsigned int updateCalendarCount = waitForWhy("/test_why_date/family/t1", "date", 10);
-
- cout << " " << timer.duration() << " update-calendar-count(" << updateCalendarCount << ")\n";
-}
-
-BOOST_AUTO_TEST_CASE( test_why_time )
-{
- DurationTimer timer;
- cout << "Test:: ...test_why_time "<< flush;
-
- Defs theDefs;
- {
- boost::posix_time::ptime theLocalTime = Calendar::second_clock_time();
- boost::posix_time::ptime time1 = theLocalTime - hours(1);
-
- suite_ptr suite = Suite::create("test_why_time" ) ;
- family_ptr fam = Family::create( "family" );
- task_ptr task = Task::create( "t1" );
-
- ClockAttr clockAttr(theLocalTime);
- suite->addClock( clockAttr );
-
- task->addTime( ecf::TimeAttr( ecf::TimeSlot(time1.time_of_day()) ) );
- fam->addTask( task );
- suite->addFamily( fam );
- theDefs.addSuite( suite );
- }
-
-
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,
- ServerTestHarness::testDataDefsLocation("test_why_time.def"),
- 1/*timeout*/,
- false /* waitForTestCompletion*/);
-
- // The job should not be submitted and should stay queued since the time does not match
- // running the why command, should report dependency on time
- unsigned int updateCalendarCount = waitForWhy("/test_why_time/family/t1", "time", 10);
-
- cout << " " << timer.duration() << " update-calendar-count(" << updateCalendarCount << ")\n";
-}
-
-BOOST_AUTO_TEST_CASE( test_why_today )
-{
- DurationTimer timer;
- cout << "Test:: ...test_why_today "<< flush;
-
- Defs theDefs;
- {
- // IMPORTANT: A Node with a today attribute is *free* to run *IF* the suite
- // calendar time is greater than the today date.
- // Hence if we start this test just before midnight i.e 11.20,
- // and add hour , then the today time would be 00:20
- // *i.e node is free to run*
- // This is not what we want for this test. i.e we depend on node being queued
- // in order to test the why command. Also the following tests, start
- // by deleting all nodes. This will fail due to active/submitted tasks
- // Hence can *NOT* use:
- // boost::posix_time::ptime theLocalTime = Calendar::second_clock_time();
- // boost::posix_time::ptime time1 = theLocalTime + hours(1);
-
- // Use a hard coded a time, to avoid failure if test is run just before midnight
- boost::posix_time::ptime theLocalTime(date(2010,2,10), hours(1));
- boost::posix_time::ptime time1 = theLocalTime + hours(1);
-
- suite_ptr suite = theDefs.add_suite("test_why_today" ) ;
- ClockAttr clockAttr(theLocalTime);
- suite->addClock( clockAttr );
-
- family_ptr fam = suite->add_family( "family" );
- task_ptr task = fam->add_task( "t1" );
- task->addToday( ecf::TodayAttr( ecf::TimeSlot(time1.time_of_day()) ) );
- }
-
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,
- ServerTestHarness::testDataDefsLocation("test_why_today.def"),
- 1/*timeout*/,
- false /* waitForTestCompletion*/);
-
- // The job should not be submitted and should stay queued since the time does not match
- // running the why command, should report dependency on time
- unsigned int updateCalendarCount = waitForWhy("/test_why_today/family/t1", "today", 10);
-
- cout << " " << timer.duration() << " update-calendar-count(" << updateCalendarCount << ")\n";
-}
-
-BOOST_AUTO_TEST_CASE( test_why_cron )
-{
- DurationTimer timer;
- cout << "Test:: ...test_why_cron "<< flush;
-
- Defs theDefs;
- {
- boost::posix_time::ptime theLocalTime = boost::posix_time::ptime(date(2010,6,21),time_duration(11,0,0));
- boost::posix_time::ptime time1 = theLocalTime - hours(3);
- boost::posix_time::ptime time2 = theLocalTime - hours(1);
- boost::gregorian::date todaysDate = theLocalTime.date();
-
- suite_ptr suite = Suite::create("test_why_cron" ) ;
- family_ptr fam = Family::create( "family" );
- task_ptr task = Task::create( "t1" );
-
- ClockAttr clockAttr(theLocalTime,false/*real*/);
- suite->addClock( clockAttr );
-
- // ** IMPORTANT **, for a date in the future we must match day of week,
- // *************** day of month, and year, i.e the results are ANDED
- // *************** this can lead to unexpected time in the future
- // *************** if all 3 dependencies are present, as *below*
- ecf::CronAttr cronAttr;
- ecf::TimeSlot start( time1.time_of_day() ); // in the past
- ecf::TimeSlot finish( time2.time_of_day() ); // in the past
- ecf::TimeSlot incr( 0, 5 );
- cronAttr.addTimeSeries(start,finish,incr);
-
- std::vector<int> weekDays; weekDays.push_back(todaysDate.day_of_week().as_number());
- std::vector<int> daysOfMonth; daysOfMonth.push_back( todaysDate.day() );
- std::vector<int> months; months.push_back( todaysDate.month() );
- cronAttr.addWeekDays( weekDays );
- cronAttr.addDaysOfMonth( daysOfMonth );
- cronAttr.addMonths( months );
-
- task->addCron(cronAttr);
-
- fam->addTask( task );
- suite->addFamily( fam );
- theDefs.addSuite( suite );
- }
-
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,
- ServerTestHarness::testDataDefsLocation("test_why_cron.def"),
- 1/*timeout*/,
- false /* waitForTestCompletion*/);
-
- // The job should not be submitted and should stay queued we are past the cron time
- // running the why command, should report dependency on cron
- unsigned int updateCalendarCount = waitForWhy("/test_why_cron/family/t1", "cron", 10);
-
- cout << " " << timer.duration() << " update-calendar-count(" << updateCalendarCount << ")\n";
-}
-
-BOOST_AUTO_TEST_CASE( test_why_limit )
-{
- DurationTimer timer;
- cout << "Test:: ...test_why_limit "<< flush;
-
- // Testing for limits requires that we have least some jobs are submitted.
- // we need to kill these jobs, at the end of test.
-
- // suite test_why_limit
- // limit disk 50
- // family family
- // inlimit /suite1:disk 50
- // task t0
- // task t1
- // task t2
- // task t3
- // task t4
- // task t5
- // endfamily
- // endsuite
- int taskSize = 6;
-
- Defs theDefs;
- {
- std::string suiteName = "test_why_limit";
- std::string pathToLimit = "/" + suiteName;
- suite_ptr suite = theDefs.add_suite(suiteName );
- suite->addVariable( Variable("ECF_TRIES","1") );
- suite->addLimit(Limit("disk",50));
-
- family_ptr fam = suite->add_family( "family");
- fam->addInLimit(InLimit("disk",pathToLimit,50));
- for(int i=0; i < taskSize; i++) {
- fam->addTask( Task::create("t" + boost::lexical_cast<std::string>(i)) );
- }
- }
-
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,
- ServerTestHarness::testDataDefsLocation( "test_why_limit.def" ),
- 1/*timeout*/,
- false /* waitForTestCompletion*/);
-
- // Only one job should be submitted, at a time, we will query on task t5, which
- // should still be queued because the limit is full
- // running the why command, should report dependency on limit
- waitForWhy("/test_why_limit/family/t5", "limit", 10);
-
- // The main check is over. Wait for jobs to complete
- int updateCalendarCount = 0;
- TestFixture::client().set_throw_on_error(false) ;
- {
- AssertTimer assertTimer(50,false); // Bomb out after n seconds, fall back if test fail
- while (1) {
- BOOST_REQUIRE_MESSAGE(TestFixture::client().getDefs() == 0,CtsApi::get() << " failed should return 0\n" << TestFixture::client().errorMsg());
- defs_ptr defs = TestFixture::client().defs();
- updateCalendarCount = defs->updateCalendarCount();
- bool wait = false;
- vector<Task*> tasks; defs->getAllTasks(tasks);
- BOOST_FOREACH(Task* task, tasks) {
- if (task->state() != NState::COMPLETE) wait = true;
- }
- if (!wait) break;
- if ( assertTimer.duration() >= assertTimer.timeConstraint()) {
- cout << "waitFor jobs to complete, wait time of " << assertTimer.duration() <<
- " taking longer than time constraint of " << assertTimer.timeConstraint() <<
- " aborting, ......breaking out\n" << *defs << "\n";
- }
- sleep(1);
- }
- }
- cout << " " << timer.duration() << " update-calendar-count(" << updateCalendarCount << ")\n";
-}
-
-BOOST_AUTO_TEST_CASE( test_why_trigger )
-{
- DurationTimer timer;
- cout << "Test:: ...test_why_trigger "<< flush;
-
- Defs theDefs;
- {
- suite_ptr suite = Suite::create("test_why_trigger" ) ;
- family_ptr fam = Family::create( "family" );
- task_ptr task = Task::create( "t1" );
- task->add_trigger( "1 == 0");
- fam->addTask( task );
- suite->addFamily( fam );
- theDefs.addSuite( suite );
- }
-
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,
- ServerTestHarness::testDataDefsLocation("test_why_trigger.def"),
- 1/*timeout*/,
- false /* waitForTestCompletion*/);
-
- // Waiting for a trigger expression which will never evaluate
- unsigned int updateCalendarCount = waitForWhy("/test_why_trigger/family/t1", "expression", 10);
-
- cout << " " << timer.duration() << " update-calendar-count(" << updateCalendarCount << ")\n";
-}
-
-BOOST_AUTO_TEST_CASE( test_why_meter )
-{
- DurationTimer timer;
- cout << "Test:: ...test_why_meter "<< flush;
-
- Defs theDefs;
- {
- suite_ptr suite = Suite::create("test_why_meter" ) ;
- family_ptr fam = Family::create( "family" );
- fam->addMeter( Meter("meter",0,100,100) );
- task_ptr task = Task::create( "t1" );
- task->add_trigger( "/test_why_meter/family:meter > 20");
- fam->addTask( task );
- suite->addFamily( fam );
- theDefs.addSuite( suite );
- }
-
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,
- ServerTestHarness::testDataDefsLocation("test_why_meter.def"),
- 1/*timeout*/,
- false /* waitForTestCompletion*/);
-
- // Waiting for a trigger expression which references a meter.
- unsigned int updateCalendarCount = waitForWhy("/test_why_meter/family/t1", "/test_why_meter/family:meter", 10);
-
- cout << " " << timer.duration() << " update-calendar-count(" << updateCalendarCount << ")\n";
-}
-
-BOOST_AUTO_TEST_CASE( test_why_event )
-{
- DurationTimer timer;
- cout << "Test:: ...test_why_event "<< flush;
-
- Defs theDefs;
- {
- suite_ptr suite = Suite::create("test_why_event" ) ;
- family_ptr fam = Family::create( "family" );
- task_ptr t1 = Task::create( "t1" );
- task_ptr t2 = Task::create( "t2" );
- t2->addEvent( Event(1,"theEvent") );
- t2->add_trigger( "1 == 0" ); // make sure task t2 never runs
- t1->add_trigger( "/test_why_event/family/t2:theEvent == set" );
- fam->addTask( t1 );
- fam->addTask( t2 );
- suite->addFamily( fam );
- theDefs.addSuite( suite );
- }
-
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,
- ServerTestHarness::testDataDefsLocation("test_why_event.def"),
- 1/*timeout*/,
- false /* waitForTestCompletion*/);
-
- // Task t1, should stay queued because the event on task t2 is never set.
- unsigned int updateCalendarCount = waitForWhy("/test_why_event/family/t1", "/test_why_event/family/t2:theEvent", 10);
-
- cout << " " << timer.duration() << " update-calendar-count(" << updateCalendarCount << ")\n";
-}
-
-BOOST_AUTO_TEST_CASE( test_why_user_var )
-{
- DurationTimer timer;
- cout << "Test:: ...test_why_user_var "<< flush;
-
- Defs theDefs;
- {
- suite_ptr suite = Suite::create("test_why_user_var" ) ;
- family_ptr fam = Family::create( "family" );
- task_ptr t1 = Task::create( "t1" );
- suite->addVariable( Variable("user_var","10") );
- t1->add_trigger( "/test_why_user_var:user_var eq 100" );
- fam->addTask( t1 );
- suite->addFamily( fam );
- theDefs.addSuite( suite );
- }
-
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,
- ServerTestHarness::testDataDefsLocation("test_why_user_var.def"),
- 1/*timeout*/,
- false /* waitForTestCompletion*/);
-
- // Task t1, should stay queued because the user variable 'user_var' value = 10, is not 100
- unsigned int updateCalendarCount = waitForWhy("/test_why_user_var/family/t1", "/test_why_user_var:user_var", 10);
-
- cout << " " << timer.duration() << " update-calendar-count(" << updateCalendarCount << ")\n";
-}
-
-BOOST_AUTO_TEST_CASE( test_why_gen_var )
-{
- DurationTimer timer;
- cout << "Test:: ...test_why_gen_var "<< flush;
-
- Defs theDefs;
- {
- suite_ptr suite = Suite::create("test_why_gen_var" ) ;
- family_ptr fam = Family::create( "family" );
- task_ptr t1 = Task::create( "t1" );
- t1->add_trigger( "/test_why_gen_var/family/t1:ECF_TRYNO eq 100" );
- fam->addTask( t1 );
- suite->addFamily( fam );
- theDefs.addSuite( suite );
- }
-
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,
- ServerTestHarness::testDataDefsLocation("test_why_gen_var.def"),
- 1/*timeout*/,
- false /* waitForTestCompletion*/);
-
- // Task t1, should stay queued because the generated variable 'ECF_TRYNO' value = 0, is not 100
- unsigned int updateCalendarCount = waitForWhy("/test_why_gen_var/family/t1", "/test_why_gen_var/family/t1:ECF_TRYNO", 10);
-
- cout << " " << timer.duration() << " update-calendar-count(" << updateCalendarCount << ")\n";
-}
-
-BOOST_AUTO_TEST_CASE( test_why_repeat )
-{
- DurationTimer timer;
- cout << "Test:: ...test_why_repeat "<< flush;
-
- Defs theDefs;
- {
- suite_ptr suite = Suite::create("test_why_repeat" ) ;
- family_ptr fam = Family::create( "family" );
- task_ptr t1 = Task::create( "t1" );
- suite->addRepeat( RepeatInteger("suite_repeat_var",0,3,1));
- fam->addRepeat( RepeatInteger("family_repeat_var",0,3,1));
- t1->add_trigger( "/test_why_repeat/family:family_repeat_var eq 100 or /test_why_repeat:suite_repeat_var eq 100" );
- fam->addTask( t1 );
- suite->addFamily( fam );
- theDefs.addSuite( suite );
- }
-
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,
- ServerTestHarness::testDataDefsLocation("test_why_repeat.def"),
- 1/*timeout*/,
- false /* waitForTestCompletion*/);
-
- // Task t1, should stay queued because the repeat variable on the suite and family do not match
- unsigned int updateCalendarCount = waitForWhy("/test_why_repeat/family/t1", "/test_why_repeat/family:family_repeat_var", 10);
-
- cout << " " << timer.duration() << " update-calendar-count(" << updateCalendarCount << ")\n";
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/ecflow_4_0_7/Test/TestZombies.cpp b/ecflow_4_0_7/Test/TestZombies.cpp
deleted file mode 100644
index eef145d..0000000
--- a/ecflow_4_0_7/Test/TestZombies.cpp
+++ /dev/null
@@ -1,948 +0,0 @@
-#define BOOST_TEST_MODULE TEST_ZOMBIES
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #58 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : This is used to INVOKE a SINGLE test.
-// Making it easier for Easier for debugging and development
-//============================================================================
-#include <iostream>
-#include <limits> // for std::numeric_limits<int>::max()
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/lexical_cast.hpp>
-#include <boost/test/unit_test.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include "TestFixture.hpp"
-#include "ServerTestHarness.hpp"
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "DurationTimer.hpp"
-#include "PrintStyle.hpp"
-#include "AssertTimer.hpp"
-#include "Child.hpp"
-#include "ZombieUtil.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-namespace fs = boost::filesystem;
-
-// ****************************************************************
-// In the test below we create two sets of process. One of these
-// being a zombie. The test below create a list of user Zombies.
-// In the cases where these test fail
-// The dump of zombies shows that only One call was made.(i.e the initial creation of the Zombie)
-// and that the proces-id is not defined.
-// This implies that at test start, that not all process were started.
-// ??Note sure why?? This can be seen by enabling debug in TaskCmds which
-// shows that the Task INIT command was never received ???
-// Updated these test to detect STALE *user* zombies & remove them
-// i.e. where we have created a user Zombie but there is associated process ??
-// *******************************************************************
-
-//#define DEBUG_ZOMBIE 1
-#define DO_TEST1 1
-#define DO_TEST2 1
-#define DO_TEST3 1
-#define DO_TEST4 1
-#define DO_TEST5 1
-#define DO_TEST6 1
-#define DO_TEST7 1
-#define DO_TEST8 1
-#define DO_TEST9 1
-//#define DO_TEST10 1 Need to make reliable
-#define DO_TEST11 1
-
-static bool ecf_debug_enabled = false; // allow environment to enable debug
-
-
-BOOST_GLOBAL_FIXTURE( TestFixture );
-
-BOOST_AUTO_TEST_SUITE( TestSuite )
-
-enum WaitType { SINGLE, ALL };
-static int timeout = 30;
-static int NUM_OF_TASKS = 5;
-
-static void dump_zombies()
-{
- TestFixture::client().zombieGet();
- std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
- std::cout << Zombie::pretty_print( zombies , 3);
-}
-
-static void dump_tasks(const vector<Task*>& tasks) {
- BOOST_FOREACH(const Task* task, tasks) {
- std::cout << " " << task->absNodePath() << " " << NState::toString(task->state()) << " " << task->jobsPassword() << " " << task->process_or_remote_id() << "\n";
- }
- std::cout << "\n";
-}
-
-static bool waitForTaskStates(WaitType num_of_tasks,NState::State state1,NState::State state2, int max_time_to_wait)
-{
- std::string wait_type_str = (num_of_tasks == SINGLE ) ? "SINGLE" : "ALL";
- if (ecf_debug_enabled) {
- if ( num_of_tasks == SINGLE) {
- if (state1 == state2) std::cout << "\n Waiting for SINGLE task to reach state " << NState::toString(state1) << "\n";
- else std::cout << "\n Waiting for SINGLE task to reach state " << NState::toString(state1) << " || " << NState::toString(state2) << "\n";
- }
- else {
- if (state1 == state2) std::cout << "\n Waiting for ALL tasks to reach state " << NState::toString(state1) << "\n";
- else std::cout << "\n Waiting for ALL tasks to reach state " << NState::toString(state1) << " || " << NState::toString(state2) << "\n";
- }
- }
- AssertTimer assertTimer(max_time_to_wait,false); // Bomb out after n seconds, fall back if test fail
- while (1) {
- BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0, "waitForTaskStates: sync_local failed should return 0\n" << TestFixture::client().errorMsg());
- defs_ptr defs = TestFixture::client().defs();
- vector<Task*> tasks; defs->getAllTasks(tasks);
- if (num_of_tasks == SINGLE) {
- BOOST_FOREACH(Task* task, tasks) {
- if (task->state() == state1 || task->state() == state2 ) {
- if (ecf_debug_enabled) {
- if (task->state() == state1) std::cout << " Found at least one Task with state " << NState::toString(state1) << " returning\n";
- if (state1 != state2 && task->state() == state2) std::cout << " Found at least one Task with state " << NState::toString(state2) << " returning\n";
- dump_zombies();
- }
- return true;
- }
- }
- }
- else {
- size_t count = 0;
- BOOST_FOREACH(Task* task, tasks) { if (task->state() == state1 || task->state() == state2) count++; }
- if (count == tasks.size()) {
- if (ecf_debug_enabled) {
- if (state2 == state1) std::cout << " All tasks(" << tasks.size() << ") have reached state " << NState::toString(state1) << " returning\n";
- else std::cout << " All tasks(" << tasks.size() << ") have reached state " << NState::toString(state1) << " || " << NState::toString(state2) << " returning\n";
- dump_tasks(tasks);
- }
- return true;
- }
- }
-
- if ( assertTimer.duration() >= assertTimer.timeConstraint() ) {
- if (ecf_debug_enabled) {
- dump_zombies();
- dump_tasks(tasks);
- std::cout << "waitForTaskState " << wait_type_str << " reach state " << NState::toString(state1) << " || " << NState::toString(state2)
- << " Test taking longer than time constraint of " << assertTimer.timeConstraint() << " returning false\n";
- }
- break;
- }
- sleep(1);
- }
- return false;
-}
-
-static bool waitForTaskState(WaitType wait_type,NState::State state1, int max_time_to_wait)
-{
- return waitForTaskStates(wait_type, state1, state1, max_time_to_wait);
-}
-
-static bool waitForZombieCreation(size_t no_of_zombies, int max_time_to_wait)
-{
- if (ecf_debug_enabled) std::cout << "\n Waiting for " << no_of_zombies << " zombies to be created\n";
-
- AssertTimer assertTimer(max_time_to_wait,false); // Bomb out after n seconds, fall back if test fail
- while (1) {
- BOOST_REQUIRE_MESSAGE(TestFixture::client().zombieGet() == 0, "zombieGet failed should return 0\n" << TestFixture::client().errorMsg());
- std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
- if (zombies.size() == no_of_zombies) {
- if (ecf_debug_enabled) {
- std::cout << Zombie::pretty_print( zombies , 3);
- std::cout << " Found " << no_of_zombies << " zombies. returning.\n";
- }
- return true;
- }
- if ( assertTimer.duration() >= assertTimer.timeConstraint() ) {
-
- if (zombies.size() > 0) {
- if (ecf_debug_enabled) {
- std::cout << " Timeout out found only " << zombies.size() << " zombies." << "\n";
- std::cout << Zombie::pretty_print( zombies , 3);
- std::cout << " Found " << no_of_zombies << " zombies. returning.\n";
- }
- return true;
- }
-
- BOOST_REQUIRE_MESSAGE(assertTimer.duration() < assertTimer.timeConstraint(),
- "waitForZombieCreation expected " << no_of_zombies
- << " zombies but found " << TestFixture::client().server_reply().zombies().size()
- << " : Test taking longer than time constraint of "
- << assertTimer.timeConstraint() << " aborting\n"
- << Zombie::pretty_print( zombies , 3));
- break;
- }
- sleep(1);
- }
- return false;
-}
-
-static void remove_stale_zombies()
-{
- // Remove those zombies that have only *ONE* call
- // There is no associated process/child command that has updated the zombie
- if (ecf_debug_enabled) cout << "\n remove_stale_zombies \n";
-
- BOOST_REQUIRE_MESSAGE(TestFixture::client().zombieGet() == 0, "zombieGet failed should return 0\n" << TestFixture::client().errorMsg());
- std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
- BOOST_FOREACH(const Zombie& z, zombies) {
- if (z.calls() == 1) {
- cout << "\n **** removing_stale_zombies ***** " << z << "\n";
- cout << " Typically happens when a submitted job, never creates a process ?\n";
- cout << " Since the process never communicated back, the pid is empty.\n";
- TestFixture::client().zombieRemove(z);
- }
- }
-}
-
-static void wait_for_path_zombies(int no_of_tasks, int max_time_to_wait)
-{
- if (ecf_debug_enabled) cout << "\n wait_for_path_zombies\n";
-
- int no_of_path_zombies = 0;
- std::vector<Zombie> zombies;
- AssertTimer assertTimer(max_time_to_wait,false); // Bomb out after n seconds, fall back if test fail
- while (1) {
- BOOST_REQUIRE_MESSAGE(TestFixture::client().zombieGet() == 0, "zombieGet failed should return 0\n" << TestFixture::client().errorMsg());
- zombies = TestFixture::client().server_reply().zombies();
- BOOST_FOREACH(const Zombie& z, zombies) {
- if (z.type() == Child::PATH ) {
- no_of_path_zombies++;
- }
- }
- if (no_of_path_zombies >= no_of_tasks) break;
- // make sure test does not take too long.
- if ( assertTimer.duration() >= assertTimer.timeConstraint() ) {
- // BOOST_WARN_MESSAGE(assertTimer.duration() < assertTimer.timeConstraint(),
- std::cout << "remove_user_zombies_and_wait_for_path_zombies. Expected "
- << no_of_tasks << " PATH zombies, but found " << no_of_path_zombies
- << "\nTest taking longer than time constraint of " << assertTimer.timeConstraint()
- << "\n"
- << Zombie::pretty_print( zombies , 6) << "\n... breaking out\n";
- break;
- }
- sleep(1);
- }
-
- if (ecf_debug_enabled) cout << Zombie::pretty_print( zombies , 6) << "\n";
-}
-
-
-static void check_expected_no_of_zombies(size_t expected)
-{
- TestFixture::client().zombieGet();
- std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
-
- BOOST_CHECK_MESSAGE(zombies.size() == expected ,"Expected " << expected << " zombies but got " << zombies.size());
- if ( zombies.size() != expected) {
- std::cout << Zombie::pretty_print( zombies , 3);
- return;
- }
-}
-
-static void check_at_least_one_zombie()
-{
- TestFixture::client().zombieGet();
- std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
- BOOST_CHECK_MESSAGE(zombies.size() >= 1 ,"Expected at least one zombies but got nothing\n");
-}
-
-static bool wait_for_zombie_termination(int max_time_to_wait)
-{
- if (ecf_debug_enabled) std::cout << "\n wait_for_zombie_termination\n";
-
- AssertTimer assertTimer(max_time_to_wait,false); // Bomb out after n seconds, fall back if test fail
- while (1) {
- TestFixture::client().zombieGet();
- std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
- if (zombies.empty() ) break;
-
- if ( assertTimer.duration() >= assertTimer.timeConstraint() ) {
- if (ecf_debug_enabled) {
- std::cout << "wait_for_zombie_termination: taking longer than time constraint of " << assertTimer.timeConstraint() << " returning\n";
- std::cout << Zombie::pretty_print( zombies , 3);
- }
- return false;
- }
- sleep(1);
- }
- return true;
-}
-
-static void wait_for_zombies_child_cmd(WaitType wait_type,ecf::Child::CmdType child_cmd,int max_time_to_wait, bool do_delete = false)
-{
- if (ecf_debug_enabled) {
- std::cout << "\n Waiting for ";
- if (wait_type == SINGLE) std::cout << "SINGLE";
- else std::cout << "ALL";
- std::cout << " child (" << Child::to_string(child_cmd) << ") cmd; ";
- if (do_delete) std::cout << " then DELETE zombies ";
- std::cout << "=============================================================================================\n";
- }
-
- bool child_type_found = false;
- AssertTimer assertTimer(max_time_to_wait,false); // Bomb out after n seconds, fall back if test fail
- while (1) {
- TestFixture::client().zombieGet();
- std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
- if (ecf_debug_enabled) std::cout << " Get zombies returned " << zombies.size() << "\n";
-
- if (zombies.empty() && child_type_found && do_delete) {
- if (ecf_debug_enabled) std::cout << " No zombies. (do_delete) was set returning\n";
- return;
- }
-
- size_t completed_zombies = 0;
- BOOST_FOREACH(const Zombie& z, zombies) {
- if (ecf_debug_enabled) std::cout << " " << z << "\n";
- if (z.last_child_cmd() == child_cmd) {
- child_type_found = true;
- completed_zombies++;
- if (wait_type == SINGLE) {
- if (ecf_debug_enabled) {
- std::cout << " " << z << "\n";
- std::cout << " Found SINGLE zombie of correct child type returning\n";
- }
- return;
- }
- }
- }
-
- if ( completed_zombies == zombies.size() && child_type_found) {
- if (ecf_debug_enabled) {
- std::cout << " Found ALL(" << completed_zombies << ") zombies of child type " << Child::to_string(child_cmd) << "\n";
- std::cout << Zombie::pretty_print( zombies , 3);
- }
- if (do_delete) {
- BOOST_FOREACH(const Zombie& z, zombies) {
- if (ecf_debug_enabled) std::cout << " deleteing " << z << "\n";
- TestFixture::client().zombieRemove(z);
- }
- }
- return;
- }
-
- // make sure test does not take too long.
- if ( assertTimer.duration() >= assertTimer.timeConstraint() ) {
- std::cout << Zombie::pretty_print( zombies , 3);
- BOOST_REQUIRE_MESSAGE(assertTimer.duration() < assertTimer.timeConstraint(),
- "wait_for_zombies_child_cmd Test wait " << assertTimer.duration() <<
- " taking longer than time constraint of " << assertTimer.timeConstraint() <<
- " aborting\n");
- }
- sleep(1);
- }
-}
-
-static void wait_for_no_zombies(int max_time_to_wait)
-{
- if (ecf_debug_enabled) std::cout << "\n wait_for_no_zombies\n";
-
- AssertTimer assertTimer(max_time_to_wait,false); // Bomb out after n seconds, fall back if test fail
- while (1) {
- TestFixture::client().zombieGet();
- std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
- if (ecf_debug_enabled) {
- std::cout << " Get zombies returned " << zombies.size() << "\n";
- std::cout << Zombie::pretty_print( zombies , 6) << "\n";
- }
- if (zombies.empty()) return;
-
- // make sure test does not take too long.
- if ( assertTimer.duration() >= assertTimer.timeConstraint() ) {
- std::cout << "\n" << Zombie::pretty_print( zombies , 3);
- BOOST_REQUIRE_MESSAGE(assertTimer.duration() < assertTimer.timeConstraint(),
- "wait_for_no_zombies Test wait " << assertTimer.duration() <<
- " taking longer than time constraint of " << assertTimer.timeConstraint() <<
- " aborting\n");
- }
- sleep(2);
- }
-}
-
-static void populate_defs(Defs& theDefs,const std::string& suite_name) {
- suite_ptr suite = theDefs.add_suite(suite_name);
- suite->addVariable(Variable("SLEEPTIME","5")); // sleep for longer than normal to allow for creation of zombies
- family_ptr family = suite->add_family("f");
- for (int i = 0; i < NUM_OF_TASKS; i++) {
- family->add_task( "t" + boost::lexical_cast<std::string>(i) );
- }
- suite->add_variable("CHECK_TASK_DURATION_LESS_THAN_SERVER_POLL","_any_");
-}
-
-
-static void create_and_start_test(Defs& theDefs, const std::string& suite_name, const std::string& create_zombies_with) {
- if (ecf_debug_enabled) {
- std::cout << "\n\n=============================================================================\n";
- std::cout << "create_and_start_test " << suite_name << " using " << create_zombies_with << "\n";
- }
-
- /// Avoid side effects from previous test, by removing all zombies
- TestFixture::client().zombieGet();
- if (!TestFixture::client().server_reply().zombies().empty()) {
- (void)ZombieUtil::do_zombie_user_action(User::REMOVE,TestFixture::client().server_reply().zombies().size(), timeout);
- }
-
- if (ecf_debug_enabled) std::cout << " creating server test harness\n";
-
- // The test harness will create corresponding directory structure & default ecf file
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,
- ServerTestHarness::testDataDefsLocation(suite_name + ".def"),
- 1 /*timeout*/,
- false/* don't wait for test to finish */);
-
- // Wait for a single task to reach state submitted or active, before creating zombies
- waitForTaskStates(SINGLE,NState::SUBMITTED,NState::ACTIVE, timeout);
-
- // ******************************************************************************
- // IMPORTANT: Since 4.0.5, if Job generation takes to long i.e >= next poll
- // then it will TIMEOUT. Hence we may no get the number of zombies
- // that we expected
- // *******************************************************************************
-
- if (create_zombies_with == "delete") {
- if (ecf_debug_enabled) std::cout << " create USER zombies by deleting all the nodes in the server\n";
- TestFixture::client().delete_all( true /* force */);
- }
- else if (create_zombies_with == "begin") {
- /// Begin with force, Should create user zombies. WILL only catch those task that are submitted
- /// It may well be that job submission, may only get a subset, others, which come for submission *later*
- /// on will be ECF zombies.
- /// Note: If we wait for SUMBITTED, then we get the case, where we have two task jobs
- /// with same password, BUT different process id ??????
- /// i.e The begin has regenerate the job file, so we get job started twice.
- /// This should be trapped by the server, as Task should be active
- if (ecf_debug_enabled) std::cout << " Calling begin_all_suites, now have 2 sets of jobs, The first/original set are now zombies\n";
- TestFixture::client().set_throw_on_error(false);
- if (TestFixture::client().begin_all_suites( true /* force */) == 1) {
- std::cout << " Begin raised exception: because " << TestFixture::client().errorMsg() << " ***\n";
- }
- TestFixture::client().set_throw_on_error(true);
- }
- else if (create_zombies_with == "complete") {
-
- if (ecf_debug_enabled) std::cout << " create USER zombies by calling complete\n";
- std::string path = "/" + suite_name;
- TestFixture::client().force(path,"complete",true/*recursive*/);
- }
- else if (create_zombies_with == "aborted") {
-
- if (ecf_debug_enabled) std::cout << " create USER zombies by calling abort\n";
- std::string path = "/" + suite_name;
- TestFixture::client().force(path,"aborted",true/*recursive*/);
- }
- else {
- BOOST_REQUIRE_MESSAGE(false,"Create zombies via " << create_zombies_with << " unrecognised");
- }
-
- /// Wait for all task zombies
- vector<Task*> tasks;
- theDefs.getAllTasks(tasks);
-
- /// When jobs try to communicate with server via child commands they will block the Child commands
- if (waitForZombieCreation(tasks.size(),timeout)) {
-
- /// Check we have zombies and they are of type USER
- std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
- BOOST_CHECK_MESSAGE(zombies.size() > 0," NO zombies created");
- BOOST_FOREACH(const Zombie& z, zombies) {
- if (create_zombies_with == "begin") {
- BOOST_CHECK_MESSAGE(z.type() == Child::USER,"Creating zombies via begin, Expected 'user' zombie type but got: " << z);
- }
- else if (create_zombies_with == "delete") {
- BOOST_CHECK_MESSAGE(z.type() == Child::USER || z.type() == Child::PATH,"Creating zombies via delete, Expected 'user | path' zombie type but got: " << z);
- }
- else {
- BOOST_CHECK_MESSAGE(z.type() == Child::ECF,"Expected 'ecf' zombie type but got: " << z);
- }
- }
- }
-}
-
-static void create_and_start_test(const std::string& suite_name, const std::string& create_zombies_with) {
-
- if (ecf_debug_enabled) std::cout << " Creating defs\n";
- Defs theDefs;
- populate_defs(theDefs,suite_name);
- create_and_start_test(theDefs,suite_name,create_zombies_with );
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-BOOST_AUTO_TEST_CASE( enable_debug_for_ECF_TRY_NO_Greater_than_one)
-{
- BOOST_CHECK_MESSAGE(!ecf_debug_enabled ,"dummy test");
-
- if (getenv("ECF_DEBUG_ZOMBIES")) {
- ecf_debug_enabled = true;
- cout << "Test:: ... debug_enabled" << endl;
- }
-}
-
-#ifdef DO_TEST1
-BOOST_AUTO_TEST_CASE(test_path_zombie_creation)
-{
- DurationTimer timer;
- cout << "Test:: ...test_path_zombie_creation " << flush;
- TestClean clean_at_start_and_end;
-
- // This command creates user zombies up front, these may not have a pid, if task in submitted state
- // User zombies will be converted to path zombies by the server
- create_and_start_test("test_path_zombie_creation","delete"); // create zombie via delete
-
- // expect NUM_OF_TASKS zombies, ie because we have NUM_OF_TASKS tasks
- check_expected_no_of_zombies(NUM_OF_TASKS);
-
- // The server will automatically change existing zombie to be of type PATH
- // when no task nodes exists
- // *Note* in test environment the client invoker will try connecting to the server
- // ****** for 5 seconds, after that an error is returned. This will cause the
- // ****** job to abort.
- wait_for_path_zombies(NUM_OF_TASKS,timeout);
-
- // Fob all the zombies. This will UNBLOCK the child commands allowing them to complete
- // Fobing does *NOT* alter node tree state, however COMPLETE should auto delete the zombie
- // Hence after this command, the number of fobed zombies may *NOT* be the same
- // as the number of tasks. Since the fobed zombies are auto deleted when a complete
- // child command is recieved.
- int no_of_fobed_zombies = ZombieUtil::do_zombie_user_action(User::FOB, NUM_OF_TASKS, timeout);
- BOOST_CHECK_MESSAGE(no_of_fobed_zombies > 0,"Expected some fobed zombies but found none ?");
-
- // Wait for zombies to be deleted in the server
- if (!wait_for_zombie_termination(timeout)) {
- remove_stale_zombies();
- }
-
- // The fob should have forced removal of zombies, in the server. when the COMPLETE child command was recieved
- check_expected_no_of_zombies(0);
-
- cout << timer.duration() << "\n";
-}
-#endif
-
-#ifdef DO_TEST2
-BOOST_AUTO_TEST_CASE( test_user_zombies_for_delete_fob )
-{
- DurationTimer timer;
- cout << "Test:: ...test_user_zombies_for_delete_fob " << flush;
- TestClean clean_at_start_and_end;
-
- // This command creates user zombies up front, these may not have a pid, if task in submitted state
- // User zombies will be converted to path zombies by the server
- create_and_start_test("test_user_zombies_for_delete_fob","delete"); // create zombie via delete
-
- // expect 5 zombies, ie because we have NUM_OF_TASKS tasks
- check_expected_no_of_zombies(NUM_OF_TASKS);
-
- // Fob all the zombies. This will UNBLOCK the child commands allowing them to finish
- // Fobing does *NOT* alter node tree state, however COMPLETE should auto delete the zombie
- // Hence after this command, the number of fobed zombies may *NOT* be the same
- // as the number of tasks. Since the fobed zombies are auto deleted when a complete
- // child command is recieved.
- int no_of_fobed_zombies = ZombieUtil::do_zombie_user_action(User::FOB, NUM_OF_TASKS, timeout);
- BOOST_CHECK_MESSAGE(no_of_fobed_zombies > 0,"Expected some fobed zombies but found none ?");
-
- // Wait for zombies to be deleted in the server
- if (!wait_for_zombie_termination(timeout)) {
- remove_stale_zombies(); // see notes above
- }
-
- // The fob should have forced removal of zombies, in the server. when the COMPLETE child command was recieved
- check_expected_no_of_zombies(0);
-
- cout << timer.duration() << "\n";
-}
-#endif
-
-
-#ifdef DO_TEST3
-BOOST_AUTO_TEST_CASE( test_user_zombies_for_delete_fail )
-{
- DurationTimer timer;
- cout << "Test:: ...test_user_zombies_for_delete_fail " << flush;
- TestClean clean_at_start_and_end;
-
- // This command creates user zombies up front, these may not have a pid, if task in submitted state
- // User zombies will be converted to path zombies by the server
- create_and_start_test("test_user_zombies_for_delete_fail","delete");
-
- check_at_least_one_zombie();
-
- // Fail all the zombies. This will UNBLOCK and terminate the child commands allowing them to finish
- int no_of_failed_zombies = ZombieUtil::do_zombie_user_action(User::FAIL, NUM_OF_TASKS, timeout);
- BOOST_CHECK_MESSAGE(no_of_failed_zombies >0,"Expected > 0 Failed zombies but found none");
-
- check_at_least_one_zombie();
-
- // Wait for zombies to abort, then remove all the zombies
- wait_for_zombies_child_cmd(ALL,ecf::Child::ABORT,timeout, true /* delete */);
-
- check_expected_no_of_zombies(0);
- cout << timer.duration() << "\n";
-}
-#endif
-
-//test_zombies_attr_for_begin/f/t1 user 26 ZzD/ycIW <pid> 1 calls(1) BLOCK INIT
-
-#ifdef DO_TEST4
-BOOST_AUTO_TEST_CASE( test_user_zombies_for_begin )
-{
- DurationTimer timer;
- cout << "Test:: ...test_user_zombies_for_begin " << flush;
- TestClean clean_at_start_and_end;
-
- // This command creates user zombies up front, these may not have a pid, if task in submitted state
- create_and_start_test("test_user_zombies_for_begin","begin");
-
- /// We have two *sets* of jobs, Wait for ALL the tasks(non zombies) to complete
- BOOST_REQUIRE_MESSAGE(waitForTaskState(ALL,NState::COMPLETE,timeout),"Expected non-zombie tasks to complete");
-
- check_at_least_one_zombie();
-
- // Fob all the zombies. This will UNBLOCK the child commands allowing them to finish
- // Hence after this command, the number of fobed zombies may *NOT* be the same
- // as the number of tasks. Since the fobed zombies are auto deleted when a complete
- // child command is received.
- int no_of_fobed_zombies = ZombieUtil::do_zombie_user_action(User::FOB, NUM_OF_TASKS, timeout);
- BOOST_CHECK_MESSAGE(no_of_fobed_zombies > 0,"Expected some fobed zombies but found none ?");
-
- // Fobing does *NOT* alter node tree state, however child COMPLETE should auto delete the zombie
- if (!wait_for_zombie_termination(timeout)) {
- remove_stale_zombies(); // see notes above
- }
-
- // The fob should have forced removal of zombies, in the server. when the COMPLETE child command was recieved
- check_expected_no_of_zombies(0);
-
- cout << timer.duration() << "\n";
-}
-#endif
-
-
-#ifdef DO_TEST5
-BOOST_AUTO_TEST_CASE( test_zombies_attr_for_begin )
-{
- DurationTimer timer;
- std::string suite_name = "test_zombies_attr_for_begin";
- cout << "Test:: ..." << suite_name << " " << flush;
- TestClean clean_at_start_and_end;
-
- // This command creates user zombies up front, these may not have a pid, if task in submitted state
- create_and_start_test(suite_name,"begin"); // create zombies via begin force
-
- /// We have two *sets* of jobs, Wait for ALL the tasks(non zombies) to complete
- BOOST_REQUIRE_MESSAGE(waitForTaskState(ALL,NState::COMPLETE,timeout),"Expected non-zombie tasks to complete");
-
- check_at_least_one_zombie();
-
- /// *** Fobbing will not change state of the node tree ****
- if (ecf_debug_enabled) std::cout << " Add a zombie attribute 'user:fob::' to the suite, which fobs all child commands\n";
- TestFixture::client().alter("/" + suite_name,"add","zombie","user:fob::");
-
- // Fobbing causes auto deletion of zombies, when the Child complete is reached
- if (!wait_for_zombie_termination(timeout)) {
- remove_stale_zombies(); // see notes above
- }
-
- // The fob should have forced removal of zombies, in the server. when the COMPLETE child command was recieved
- check_expected_no_of_zombies(0);
-
- cout << timer.duration() << "\n";
-}
-#endif
-
-
-
-#ifdef DO_TEST6
-BOOST_AUTO_TEST_CASE( test_user_zombies_for_adopt )
-{
- DurationTimer timer;
- std::string suite_name = "test_user_zombies_for_adopt";
- cout << "Test:: ..." << suite_name << " " << flush;
- TestClean clean_at_start_and_end;
-
- // This command creates user zombies up front, these may not have a pid, if task in submitted state
- create_and_start_test(suite_name,"begin");
-
- /// We have two *sets* of jobs, Wait for ALL the tasks(non zombies) to complete
- BOOST_REQUIRE_MESSAGE(waitForTaskState(ALL,NState::COMPLETE,timeout),"Expected non-zombie tasks to complete");
-
- check_at_least_one_zombie();
-
- /// Adopt all the zombies. This will UNBLOCK the child commands allowing them to finish
- /// This test below fail on AIX, its too fast , task's may already be adopted and hence don't fail
- int no_of_adopted_zombied = ZombieUtil::do_zombie_user_action(User::ADOPT, NUM_OF_TASKS, timeout);
- if (ecf_debug_enabled) cout << " found " << no_of_adopted_zombied << " zombies for adoption\n";
-
- /// The blocked zombies are free, start with blocked init command
- /// This may fail on AIX, its too fast , task's may already be complete, hence don't fail
- (void)waitForTaskState(SINGLE,NState::ACTIVE,timeout);
-
- /// Now wait for all tasks to complete
- BOOST_REQUIRE_MESSAGE(waitForTaskState(ALL,NState::COMPLETE,timeout),"Expected zombie tasks to complete");
-
-
- remove_stale_zombies(); // see notes above
-
- // After adoption the zombies should be removed
- check_expected_no_of_zombies(0);
-
- cout << timer.duration() << "\n";
-}
-#endif
-
-
-#ifdef DO_TEST7
-BOOST_AUTO_TEST_CASE( test_zombies_attr_for_adopt )
-{
- DurationTimer timer;
- std::string suite_name = "test_zombies_attr_for_adopt";
- cout << "Test:: ..." << suite_name << " " << flush;
- TestClean clean_at_start_and_end;
-
- // This command creates user zombies up front, these may not have a pid, if task in submitted state
- create_and_start_test(suite_name,"begin");
-
- /// We have two *sets* of jobs, Wait for ALL the tasks(non zombies) to complete
- BOOST_REQUIRE_MESSAGE(waitForTaskState(ALL,NState::COMPLETE,timeout),"Wait for all non-zombie tasks to complete failed");
-
- // expected 5 zombies, ie because we have NUM_OF_TASKS tasks. These should all be blocking
- check_at_least_one_zombie();
-
- if (ecf_debug_enabled) std::cout << " Add a zombie attribute 'user:adopt::' to the suite, which *ADOPTS* all zombies allowing them to complete\n";
- TestFixture::client().alter("/" + suite_name,"add","zombie","user:adopt::");
-
- if (ecf_debug_enabled) dump_zombies();
-
- /// The blocked zombies are free, start with blocked init command
- /// This may fail on AIX, its too fast , task's may already be complete, dont fail
- (void)waitForTaskState(SINGLE,NState::ACTIVE,timeout);
-
- /// Now wait for all tasks to complete. ** They may be complete from last process set **
- BOOST_REQUIRE_MESSAGE(waitForTaskState(ALL,NState::COMPLETE,timeout),"Expected all zombie task to complete after adopt");
-
- remove_stale_zombies(); // see notes above
-
- // After adoption the zombies should be removed
- check_expected_no_of_zombies(0);
-
- cout << timer.duration() << "\n";
-}
-#endif
-
-
-#ifdef DO_TEST8
-BOOST_AUTO_TEST_CASE( test_ecf_zombie_creation_via_complete )
-{
- DurationTimer timer;
- std::string suite_name = "test_ecf_zombie_creation_via_complete";
- cout << "Test:: ..." << suite_name << " " << flush;
- TestClean clean_at_start_and_end;
-
- // This command creates user zombies up front, these may not have a pid, if task in submitted state
- create_and_start_test(suite_name,"complete");
-
- /// Since we have set tasks to complete, we should only have *ONE* set of zombies
- check_at_least_one_zombie();
-
- // Fob all the zombies child commands allowing them to finish
- (void) ZombieUtil::do_zombie_user_action(User::FOB, NUM_OF_TASKS, timeout);
- // int no_of_fobed_zombies = ZombieUtil::do_zombie_user_action(User::FOB, NUM_OF_TASKS, timeout);
- // BOOST_CHECK_MESSAGE(no_of_fobed_zombies == NUM_OF_TASKS,"Expected " << NUM_OF_TASKS << " Fobed zombies but found " << no_of_fobed_zombies);
-
- // Wait for zombies to complete, they should get removed automatically
- wait_for_no_zombies( timeout);
-
- cout << timer.duration() << "\n";
-}
-#endif
-
-#ifdef DO_TEST9
-BOOST_AUTO_TEST_CASE( test_ecf_zombie_creation_via_abort )
-{
- DurationTimer timer;
- std::string suite_name = "test_ecf_zombie_creation_via_abort";
- cout << "Test:: ..." << suite_name << " " << flush;
- TestClean clean_at_start_and_end;
-
- // This command creates user zombies up front, these may not have a pid, if task in submitted state
- create_and_start_test(suite_name,"aborted");
-
- /// Since we have set tasks to complete, we should only have *ONE* set of zombies
- check_at_least_one_zombie();
-
- // Fob all the zombies child commands allowing them to finish
- (void) ZombieUtil::do_zombie_user_action(User::FOB, NUM_OF_TASKS, timeout);
- // int no_of_fobed_zombies = ZombieUtil::do_zombie_user_action(User::FOB, NUM_OF_TASKS, timeout);
- // BOOST_CHECK_MESSAGE(no_of_fobed_zombies == NUM_OF_TASKS,"Expected " << NUM_OF_TASKS << " Fobed zombies but found " << no_of_fobed_zombies);
-
- // Wait for zombies to complete, they should get removed automatically
- wait_for_no_zombies(timeout);
-
- cout << timer.duration() << "\n";
-}
-#endif
-
-
-#ifdef DO_TEST10
-BOOST_AUTO_TEST_CASE( test_zombie_inheritance )
-{
- DurationTimer timer;
- std::string suite_name = "test_zombie_inheritance";
- cout << "Test:: ..." << suite_name << " " << flush;
- TestClean clean_at_start_and_end;
-
- // Add zombie attribute, make sure it inherited
- Defs theDefs;
- populate_defs(theDefs,suite_name);
- suite_ptr suite = theDefs.findSuite(suite_name);
- suite->addZombie( ZombieAttr(ecf::Child::USER, std::vector<ecf::Child::CmdType>(), ecf::User::FOB,-1) );
- suite->addZombie( ZombieAttr(ecf::Child::ECF, std::vector<ecf::Child::CmdType>(), ecf::User::FOB,-1) );
- suite->addZombie( ZombieAttr(ecf::Child::PATH, std::vector<ecf::Child::CmdType>(), ecf::User::FOB,-1) );
-
- create_and_start_test(theDefs,suite_name,"complete" );
-
- /// Since we have set tasks to complete, we should only have *ONE* set of zombies
- // expect NUM_OF_TASKS zombies, ie because we have NUM_OF_TASKS tasks
- TestFixture::client().set_throw_on_error(true);
- TestFixture::client().zombieGet();
- std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
- BOOST_CHECK_MESSAGE(!zombies.empty(),"No zombies found");
- BOOST_FOREACH(const Zombie& z, zombies) {
- BOOST_CHECK_MESSAGE(z.user_action() == ecf::User::FOB, "Expected zombies with user action of type FOB but found " << User::to_string(z.user_action()));
- break;
- }
-
- // Wait for zombies to complete, they should get removed automatically
- wait_for_no_zombies(timeout);
-
- cout << timer.duration() << "\n";
-}
-#endif
-
-
-#ifdef DO_TEST11
-static int wait_for_killed_zombies(int no_of_tasks, int max_time_to_wait)
-{
- if (ecf_debug_enabled) std::cout << "\n wait_for_killed_zombies\n";
- AssertTimer assertTimer(max_time_to_wait,false); // Bomb out after n seconds, fall back if test fail
- while (1) {
- int killed = 0;
- TestFixture::client().zombieGet();
- std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
- BOOST_FOREACH(const Zombie& z, zombies) {
- if (z.kill()) killed++;
- }
- if (ecf_debug_enabled) std::cout << " found " << killed << " killed zombies\n";
-
- if (killed == no_of_tasks) return killed;
-
- if ( assertTimer.duration() >= assertTimer.timeConstraint() ) {
- cout << "wait_for_killed_zombies Test wait " << assertTimer.duration() <<
- " taking longer than time constraint of " << assertTimer.timeConstraint() <<
- " breaking out\n" << Zombie::pretty_print( zombies , 3) << "\n";
- return killed;
- }
- sleep(2);
- }
- return 0;
-}
-
-BOOST_AUTO_TEST_CASE( test_zombie_kill )
-{
- DurationTimer timer;
- std::string suite_name = "test_zombie_kill";
- cout << "Test:: ..." << suite_name << " " << flush;
- TestClean clean_at_start_and_end;
-
- // This command creates user zombies up front, these may not have a pid, if task in submitted state
- create_and_start_test(suite_name,"complete");
-
- check_at_least_one_zombie();
-
- // kill all the zombies, i.e kill -15 on the script
- // This will be trapped by the signal and hence will call abort
- (void) ZombieUtil::do_zombie_user_action(User::KILL, NUM_OF_TASKS, timeout);
-
- // wait for kill zombies. This should eventually lead to process terminating
- int killed = wait_for_killed_zombies(NUM_OF_TASKS,timeout);
- BOOST_CHECK_MESSAGE(killed > 0,"Expected " << NUM_OF_TASKS << " killed ");
-
- {
- // wait for process to be killed: killing is a separate process, we could well
- // have got to the complete, before the process is killed.
- // Once the complete is fobed it terminate the process.
- AssertTimer assertTimer(timeout,false); // Bomb out after n seconds, fall back if test fail
- while (1) {
- int completed = 0; int aborted = 0;
- TestFixture::client().zombieGet();
- std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
- BOOST_FOREACH(const Zombie& z, zombies) {
- if (z.last_child_cmd() == ecf::Child::ABORT) aborted++;
- if (z.last_child_cmd() == ecf::Child::COMPLETE) completed++;
- }
- if (aborted + completed == NUM_OF_TASKS) break;
- if ( assertTimer.duration() >= assertTimer.timeConstraint() ) {
- cout << "wait for for abort: found " << aborted+completed<< " aborted & completed tasks. Test wait "
- << assertTimer.duration() <<
- " taking longer than time constraint of " << assertTimer.timeConstraint() <<
- " breaking out\n" << Zombie::pretty_print( zombies , 3) << "\n";
- break;
- }
- sleep(1);
- }
- }
- bool task_became_blocked = false;
- {
- // wait for process to be die
- AssertTimer assertTimer(timeout,false); // Bomb out after n seconds, fall back if test fail
- while (1) {
- TestFixture::client().zombieGet();
- std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
- BOOST_FOREACH(const Zombie& z, zombies) {
- if (z.block()) { // something went wrong, fob so don't leave process hanging
- TestFixture::client().zombieFob(z);
- task_became_blocked = true;
- cout << "Zombies blocking ?? " << z << "\n";
- }
- }
- if ( assertTimer.duration() >= assertTimer.timeConstraint() ) {
- if ( task_became_blocked ) {
- cout << "Task became blocked, fobing" << assertTimer.duration() <<
- " taking longer than time constraint of " << assertTimer.timeConstraint() <<
- " breaking out\n" << Zombie::pretty_print( zombies , 3) << "\n";
- }
- break;
- }
- sleep(1);
- }
- }
-
- // remove the killed zombies
- (void) ZombieUtil::do_zombie_user_action(User::REMOVE,NUM_OF_TASKS, timeout,false);
-
- wait_for_no_zombies(timeout);
-
- cout << timer.duration() << "\n";
-}
-#endif
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Test/Test_Time.cpp b/ecflow_4_0_7/Test/Test_Time.cpp
deleted file mode 100644
index 05ef888..0000000
--- a/ecflow_4_0_7/Test/Test_Time.cpp
+++ /dev/null
@@ -1,387 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #35 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include <iostream>
-#include <fstream>
-#include <stdlib.h>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/test/unit_test.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include "ServerTestHarness.hpp"
-#include "TestFixture.hpp"
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "DurationTimer.hpp"
-#include "PrintStyle.hpp"
-
-using namespace std;
-using namespace ecf;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-
-BOOST_AUTO_TEST_SUITE( TestSuite )
-
-BOOST_AUTO_TEST_CASE( test_single_real_time )
-{
- DurationTimer timer;
- cout << "Test:: ...test_single_real_time " << flush;
- TestClean clean_at_start_and_end;
-
- // Create the defs file corresponding to the text below
- // ECF_HOME variable is automatically added by the test harness.
- // ECF_INCLUDE variable is automatically added by the test harness.
- // SLEEPTIME variable is automatically added by the test harness.
- // ECF_CLIENT_EXE_PATH variable is automatically added by the test harness.
- // This is substituted in sms includes
- // Allows test to run without requiring installation
-
- //# Note: we have to use relative paths, since these tests are relocatable
- //suite suite
- // edit SLEEPTIME 1
- // edit ECF_INCLUDE $ECF_HOME/includes
- // clock real <todays date>
- // family family
- // task t1
- // time 10:00
- // endfamily
- //endsuite
- Defs theDefs;
- {
- // Initialise clock with fixed date and time, then create a time attribute
- // with todays time + minute
- // Avoid adding directly to TimeSlot
- // i.e if local time is 9:59 and we create a TimeSlot like
- // task->addTime( ecf::TimeAttr( ecf::TimeSlot(theTm.tm_hour,theTm.tm_min+3) ) );
- // The the minute will be 62, which is illegal and will not parse
- boost::posix_time::ptime theLocalTime = boost::posix_time::ptime(date(2010,6,21),time_duration(10,0,0));
- boost::posix_time::ptime time1 = theLocalTime + minutes(1);
-
- // For each 2 seconds of poll in the server update calendar by 1 minute
- // Note: if we use 1 seconds poll to update calendar by 1 minute, then
- // we will find that state change happens at job submission interval,
- // and hence skews time series. Which can leave state in a queued state,
- // and hence test never completes
- suite_ptr suite = theDefs.add_suite("test_single_real_time");
- ClockAttr clockAttr(theLocalTime,false);
- suite->addClock( clockAttr );
-
- family_ptr fam = suite->add_family("family");
- task_ptr task = fam->add_task("t");
- task->addTime( ecf::TimeAttr(ecf::TimeSlot(time1.time_of_day())));
- task->addVerify( VerifyAttr(NState::COMPLETE,1) ); // task should complete 1 times
- }
-
- // The test harness will create corresponding directory structure
- // and populate with standard ecf files.
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_single_real_time.def"));
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-BOOST_AUTO_TEST_CASE( test_time_multiple_single_slot )
-{
- DurationTimer timer;
- cout << "Test:: ...test_time_multiple_single_slot "<< flush;
- TestClean clean_at_start_and_end;
-
- // SLOW SYSTEMS
- // for each time attribute leave GAP of 3 * job submission interval
- // on slow systems submitted->active->complete > TestFixture::job_submission_interval()
- // Also the task duration must be greater than job_submission_interval, otherwise
- // we will get multiple invocation for the same time step.
- // *sometimes* just submitted->active can take many times job submission interval.
-
- //# Note: we have to use relative paths, since these tests are relocatable
- //suite test_time_multiple_single_slot
- // edit ECF_INCLUDE $ECF_HOME/includes
- // clock real <todays date>
- // family family
- // task t1
- // time 10:01
- // time 10:04
- // time 10:07
- // endfamily
- //endsuite
- Defs theDefs;
- {
- // Initialise clock with todays date and time, then create a time attribute
- // with todays time + minute.
- boost::posix_time::ptime theLocalTime = boost::posix_time::ptime(date(2010,6,21),time_duration(10,0,0));
- boost::posix_time::ptime time1 = theLocalTime + minutes(1);
- boost::posix_time::ptime time2 = time1 + minutes(TestFixture::job_submission_interval());
- boost::posix_time::ptime time3 = time2 + minutes(TestFixture::job_submission_interval());
-
- suite_ptr suite = theDefs.add_suite("test_time_multiple_single_slot");
- ClockAttr clockAttr(theLocalTime,false);
- suite->addClock( clockAttr );
- suite->add_variable("SLEEPTIME","1");
-
- family_ptr fam = suite->add_family("family");
- task_ptr task = fam->add_task("t");
- task->addTime( ecf::TimeAttr( ecf::TimeSlot(time1.time_of_day()) ) );
- task->addTime( ecf::TimeAttr( ecf::TimeSlot(time2.time_of_day()) ) );
- task->addTime( ecf::TimeAttr( ecf::TimeSlot(time3.time_of_day()) ) );
- task->addVerify( VerifyAttr(NState::COMPLETE,3) ); // task should complete 3 times
- }
-
- // The test harness will create corresponding directory structure
- // and populate with standard ecf files.
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_time_multiple_single_slot.def"));
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-
-BOOST_AUTO_TEST_CASE( test_time_relative_time_series )
-{
- DurationTimer timer;
- cout << "Test:: ...test_time_relative_time_series " << flush;
- TestClean clean_at_start_and_end;
-
- // SLOW SYSTEMS
- // for each time attribute leave GAP of 3 * job submission interval
- // on slow systems submitted->active->complete > TestFixture::job_submission_interval()
- // Also the task duration must be greater than job_submission_interval, otherwise
- // we will get multiple invocation for the same time step
-
- //# Note: we have to use relative paths, since these tests are relocatable
- //suite test_time_relative_time_series
- // edit SLEEPTIME 1
- // edit ECF_INCLUDE $ECF_HOME/includes
- // clock real <todays date>
- // family family
- // task t1
- // time +<start> <finish> incr
- // endfamily
- //endsuite
- Defs theDefs;
- {
- // Initialise clock with todays date and time, then create a time attribute
- // with a time series, so that task runs 3 times relative to suite start
- suite_ptr suite = theDefs.add_suite("test_time_relative_time_series");
- ClockAttr clockAttr(Calendar::second_clock_time(),false);
- suite->addClock( clockAttr );
- suite->add_variable("SLEEPTIME",boost::lexical_cast<std::string>(TestFixture::job_submission_interval()-1));
-
- family_ptr fam = suite->add_family("family");
- task_ptr task = fam->add_task("t");
- task->addTime( ecf::TimeAttr(
- ecf::TimeSlot(0,1),
- ecf::TimeSlot(0,7),
- ecf::TimeSlot(0,3),
- true /*relative to suite start*/
- )
- );
- task->addVerify( VerifyAttr(NState::COMPLETE,3) ); // task should complete 3 times
- }
-
- // The test harness will create corresponding directory structure
- // and populate with standard ecf files.
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs, ServerTestHarness::testDataDefsLocation("test_time_relative_time_series.def"));
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-BOOST_AUTO_TEST_CASE( test_time_real_series )
-{
- DurationTimer timer;
- cout << "Test:: ...test_time_real_series " << flush;
- TestClean clean_at_start_and_end;
-
- // SLOW SYSTEMS
- // for each time attribute leave GAP of 3 * job submission interval
- // on slow systems submitted->active->complete > TestFixture::job_submission_interval()
- // Also the task duration must be greater than job_submission_interval, otherwise
- // we will get multiple invocation for the same time step
-
- //# Note: we have to use relative paths, since these tests are relocatable
- //suite test_time_real_series
- // edit SLEEPTIME 1
- // edit ECF_INCLUDE $ECF_HOME/includes
- // clock real <date>
- // family family
- // task t1
- // time <start> <finish> <incr>
- // endfamily
- //endsuite
- Defs theDefs;
- {
- // Initialise clock with todays date and time, then create a time attribute
- // with a time series, so that task runs 3 times
- boost::posix_time::ptime theLocalTime = boost::posix_time::ptime(date(2010,6,21),time_duration(10,0,0));
- boost::posix_time::ptime time1 = theLocalTime + minutes(1);
- boost::posix_time::ptime time2 = time1 + minutes(TestFixture::job_submission_interval()*2);
-
- suite_ptr suite = theDefs.add_suite("test_time_real_series");
- suite->add_variable("SLEEPTIME","1");
-
- ClockAttr clockAttr(theLocalTime,false);
- suite->addClock( clockAttr );
-
- family_ptr fam = suite->add_family("family");
- task_ptr task = fam->add_task("t");
- task->addTime( ecf::TimeAttr(
- ecf::TimeSlot(time1.time_of_day()),
- ecf::TimeSlot(time2.time_of_day()),
- ecf::TimeSlot(0,TestFixture::job_submission_interval())
- ));
- task->addVerify( VerifyAttr(NState::COMPLETE,3) ); // task should complete 3 times
- // 1 + 7 + 13
- // 1 + (2*n) + (2*n) = 1 + 4n
- // start = 1, finish = 13, when n=3, when n = job submission interval
- // to complete 3 times, we must use interval of n*2
- }
-
- // The test harness will create corresponding directory structure
- // and populate with standard sms files.
- ServerTestHarness serverTestHarness;
- //serverTestHarness.add_default_sleep_time(false); // avoid missing time steps due to submit->active->complete > job submission interval
- serverTestHarness.run(theDefs, ServerTestHarness::testDataDefsLocation("test_time_real_series.def"));
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-BOOST_AUTO_TEST_CASE( test_single_real_time_near_midnight )
-{
- DurationTimer timer;
- cout << "Test:: ...test_single_real_time_near_midnight " << flush;
- int the_server_version = TestFixture::server_version() ;
- if (the_server_version == 403 ) {
- cout << " SKIPPING, This test does not work with 403, current server version is " << the_server_version << "\n";
- return;
- }
-
- TestClean clean_at_start_and_end;
-
- //# Note: we have to use relative paths, since these tests are relocatable
- //suite suite
- // edit SLEEPTIME 4
- // edit ECF_INCLUDE $ECF_HOME/includes
- // clock real <todays date>
- // family family
- // task t1
- // time 23:59
- // endfamily
- //endsuite
- Defs theDefs;
- {
- // ECFLOW-130
- // Make sure job completes after midnight.
- // The task SHOULD stay complete and *NOT* requeue
- // Since TestHarness requires suite completion, we dont need to do anything.
- boost::posix_time::ptime time_start = boost::posix_time::ptime(date(2010,6,21),time_duration(23,59,0));
- boost::posix_time::ptime clock_start = time_start - minutes(1);
-
- suite_ptr suite = theDefs.add_suite("test_single_real_time_near_midnight");
- ClockAttr clockAttr(clock_start,false);
- suite->addClock( clockAttr );
- suite->add_variable("SLEEPTIME",boost::lexical_cast<string>(TestFixture::job_submission_interval()*2));
-
- family_ptr fam = suite->add_family("family");
- task_ptr task = fam->add_task("t");
- task->addTime( ecf::TimeAttr(ecf::TimeSlot(time_start.time_of_day())));
- task->addVerify( VerifyAttr(NState::COMPLETE,1) ); // task should complete 1 times
- }
-
- // The test harness will create corresponding directory structure and populate with standard ecf files.
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,ServerTestHarness::testDataDefsLocation("test_single_real_time_near_midnight.def"));
-
-#ifdef DEBUG_ME
- BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0, "Could not get the defs from server\n" << TestFixture::client().errorMsg());
- defs_ptr defs = TestFixture::client().defs();
- PrintStyle::setStyle(PrintStyle::STATE);
- std::cout << *defs;
-#endif
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-
-BOOST_AUTO_TEST_CASE( test_time_real_series_near_midnight )
-{
- DurationTimer timer;
- cout << "Test:: ...test_time_real_series_near_midnight " << flush;
- int the_server_version = TestFixture::server_version() ;
- if (the_server_version == 403 ) {
- cout << " SKIPPING, This test does not work with 403, current server version is " << the_server_version << "\n";
- return;
- }
-
- TestClean clean_at_start_and_end;
-
- // SLOW SYSTEMS
- // for each time attribute leave GAP of 3 * job submission interval
- // on slow systems submitted->active->complete > TestFixture::job_submission_interval()
- // Also the task duration must be greater than job_submission_interval, otherwise
- // we will get multiple invocation for the same time step
-
- //# Note: we have to use relative paths, since these tests are relocatable
- //suite test_time_real_series
- // edit SLEEPTIME 1
- // edit ECF_INCLUDE $ECF_HOME/includes
- // clock real <date>
- // family family
- // task t1
- // time <start> <finish> <incr>
- // endfamily
- //endsuite
- Defs theDefs;
- {
- // ECFLOW-130
- // make sure that last job, *runs* and completes after midnight.
- // It should stay complete and not requeue.
- // Test harness, will check suite task->family->suite completes, hence no need to do anything
- boost::posix_time::ptime last_time = boost::posix_time::ptime(date(2010,6,21),time_duration(23,59,0));
- boost::posix_time::ptime first_time = last_time - minutes(TestFixture::job_submission_interval()*2);
- boost::posix_time::ptime clock_start = first_time - minutes(1);
-
- suite_ptr suite = theDefs.add_suite("test_time_real_series_near_midnight");
- suite->add_variable("SLEEPTIME",boost::lexical_cast<string>(TestFixture::job_submission_interval()*2));
-
- ClockAttr clockAttr(clock_start,false);
- suite->addClock( clockAttr );
-
- family_ptr fam = suite->add_family("family");
- task_ptr task = fam->add_task("t");
- task->addTime( ecf::TimeAttr(
- ecf::TimeSlot(first_time.time_of_day()),
- ecf::TimeSlot(last_time.time_of_day()),
- ecf::TimeSlot(0,TestFixture::job_submission_interval()*2)
- ));
- task->addVerify( VerifyAttr(NState::COMPLETE,2) ); // task should complete 2 times
- }
-
- // The test harness will create corresponding directory structure and populate with standard ecf files.
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs, ServerTestHarness::testDataDefsLocation("test_time_real_series_near_midnight.def"));
-
-#ifdef DEBUG_ME
- BOOST_REQUIRE_MESSAGE(TestFixture::client().sync_local() == 0, "Could not get the defs from server\n" << TestFixture::client().errorMsg());
- defs_ptr defs = TestFixture::client().defs();
- PrintStyle::setStyle(PrintStyle::STATE);
- std::cout << *defs;
-#endif
-
- cout << timer.duration() << " update-calendar-count(" << serverTestHarness.serverUpdateCalendarCount() << ")\n";
-}
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/Test/data/.gitignore b/ecflow_4_0_7/Test/data/.gitignore
deleted file mode 100644
index bc0add2..0000000
--- a/ecflow_4_0_7/Test/data/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-/ECF_HOME_debug
-/ECF_HOME_release
diff --git a/ecflow_4_0_7/Test/src/ServerTestHarness.cpp b/ecflow_4_0_7/Test/src/ServerTestHarness.cpp
deleted file mode 100644
index 081760e..0000000
--- a/ecflow_4_0_7/Test/src/ServerTestHarness.cpp
+++ /dev/null
@@ -1,558 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #127 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <iostream>
-#include <fstream>
-#include <stdlib.h> // for getenv()
-
-#include <boost/filesystem.hpp>
-#include <boost/filesystem/operations.hpp>
-#include <boost/test/unit_test.hpp>
-
-#include "ServerTestHarness.hpp"
-#include "TestFixture.hpp"
-#include "DurationTimer.hpp"
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "File.hpp"
-#include "AssertTimer.hpp"
-#include "TestHelper.hpp"
-#include "PrintStyle.hpp"
-#include "WhyCmd.hpp"
-#include "Ecf.hpp"
-#include "Str.hpp"
-
-using namespace std;
-using namespace ecf;
-namespace fs = boost::filesystem;
-
-//#define DEBUG_TEST_WAITER 1
-//#define DEBUG_TEST_WAITER_DEFS 1
-//#define DEBUG_TEST_HARNESS 1
-//#define DEBUG_DIFF 1
-
-ServerTestHarness::ServerTestHarness()
-: generateManFileForNodeContainers_(false),
- check_task_duration_less_than_server_poll_(true),
- add_default_sleep_time_(true),
- serverUpdateCalendarCount_(0)
-{}
-
-void ServerTestHarness::run(
- Defs& theClientDefs,
- const std::string& defs_filename,
- const std::map<std::string,
- std::string>& customTaskSmsMap,
- int timeout,
- bool waitForTestCompletion)
-{
- defs_filename_ = defs_filename;
-
- /// RUN the TEST
- defs_ptr serverDefs = doRun(theClientDefs,customTaskSmsMap,timeout,waitForTestCompletion);
-}
-
-void ServerTestHarness::run(Defs& defs,const std::string& defs_filename, int timeout, bool waitForTestCompletion)
-{
- std::map<std::string,std::string> customTaskSmsMap;
- run(defs,defs_filename,customTaskSmsMap,timeout,waitForTestCompletion);
-}
-
-struct null_deleter { void operator()(void const *) const{} };
-
-defs_ptr
-ServerTestHarness::doRun(Defs& theClientDefs, const std::map<std::string,std::string>& customTaskSmsMap,int timeout,bool waitForTestCompletion)
-{
-#ifdef DEBUG_TEST_HARNESS
- cout << "ServerTestHarness::doRun " << defs_filename_ << " timeout=" << timeout << " waitForTestCompletion = " << waitForTestCompletion << "\n";
-#endif
- BOOST_REQUIRE_MESSAGE(!theClientDefs.suiteVec().empty(), "No suite defined");
-
-
-#ifdef DEBUG_TEST_HARNESS
- cout << " ServerTestHarness::doRun: Get the client exe. This can be client exe on another platform hence cant run here\n";
-#endif
- std::string theClientExePath = TestFixture::theClientExePath();
- BOOST_REQUIRE_MESSAGE(!theClientExePath.empty()," The client program could not be found");
-
-
-#ifdef DEBUG_TEST_HARNESS
- cout << " ServerTestHarness::doRun: Create ECF directory structure corresponding to Node tree\n";
-#endif
- // Automatically add variable ECF_HOME to each suite, before saving to disk
- // This is needed to locate ECF_FILE includes
- std::string ecf_home = testDataLocation( defs_filename_ );
-
- // Most test just define one suite, however the mega.def has up to 26 suites
- // If set this can be used to choose which suite to begin.
- std::string suiteName;
-
- // Create the client early, since we need to determine if environment variable
- // ECF_ALLOW_NEW_CLIENT_OLD_SERVER was set, if it was, we need to update the generated .ecf scripts
- // to embed this variable, this will allow *new child commands* to talk to old servers
- int allow_new_client_old_server = 0;
- if (TestFixture::client().allow_new_client_old_server() != 0) {
- // need export ECF_ALLOW_NEW_CLIENT_OLD_SERVER
- allow_new_client_old_server = TestFixture::client().allow_new_client_old_server();
- }
-
-
- // ECF_CLIENT_EXE_PATH allows dependence on client exe without installation
- // Allow user to add SLEEPTIME, otherwise add a default
- int customSmsCnt = 0;
- int taskSmsMapSize = static_cast<int>(customTaskSmsMap.size());
- BOOST_FOREACH(suite_ptr s, theClientDefs.suiteVec()) {
- if (allow_new_client_old_server != 0) {
- std::string value = "export ECF_ALLOW_NEW_CLIENT_OLD_SERVER=" + boost::lexical_cast<std::string>(allow_new_client_old_server);
- s->addVariable( Variable( "ECF_ALLOW_NEW_CLIENT_OLD_SERVER", value ) );
- }
-
- // Always override these to correctly locate files.
- s->addVariable( Variable( Str::ECF_HOME(), ecf_home ) );
- s->addVariable( Variable( "ECF_CLIENT_EXE_PATH", theClientExePath ) );
- s->addVariable( Variable( Str::ECF_INCLUDE(), TestFixture::includes() ) );
-
- if (s->findVariable("SLEEPTIME").empty()) s->addVariable( Variable( "SLEEPTIME", "1" ) );
-
- if (check_task_duration_less_than_server_poll_) {
- if (s->findVariable("CHECK_TASK_DURATION_LESS_THAN_SERVER_POLL").empty()) s->addVariable( Variable( "CHECK_TASK_DURATION_LESS_THAN_SERVER_POLL", "_any_" ) );
- }
- suiteName = s->name();
-
- // recursively create directory structure from ECF_HOME and populate tasks with sms files
- createDirAndEcfFiles(s.get(),ecf_home,customTaskSmsMap,customSmsCnt);
- }
- BOOST_REQUIRE_MESSAGE( customSmsCnt == taskSmsMapSize,"customSmsCnt:" << customSmsCnt << " does not match " << taskSmsMapSize << " createDirAndEcfFiles did not create all sms file corresponding to tasks");
-
-
- // If the defs has more than one suite, then start them all.
- if ( theClientDefs.suiteVec().size() != 1) {
- suiteName.clear();
-#ifdef DEBUG_TEST_HARNESS
- cout << " ServerTestHarness::doRun: defs has " << theClientDefs.suiteVec().size() << " suites hence will begin all of them\n";
-#endif
- }
-
-
- bool load_defs_from_disk = true;
- {
-#ifdef DEBUG_TEST_HARNESS
- cout << " ServerTestHarness::doRun: Save the Defs file to disk. " << defs_filename_ << "\n";
-#endif
- std::ofstream theClientDefsFile( defs_filename_.c_str() );
- if ( theClientDefsFile.fail()) {
- // The file is *not on disk*, just use in memory defs
- load_defs_from_disk = false;
- }
- else {
- PrintStyle::setStyle(PrintStyle::DEFS); // needed for output
- theClientDefsFile << theClientDefs;
- PrintStyle::setStyle(PrintStyle::STATE); // From now on show state
- }
- }
-
- // Set the location of the new log file. Close the current log file and create new log file
- // The defs file name should have been set to the test location
- // The log file is CLEARED so that previous run is ignored
- std::string new_log_file_path = defs_filename_ + "_log";
-#ifdef DEBUG_TEST_HARNESS
- cout << " ServerTestHarness::new_log_file_path = " << new_log_file_path << "\n";
-#endif
- TestFixture::client().new_log( new_log_file_path );
- TestFixture::client().clearLog();
-
-
-#ifdef DEBUG_TEST_HARNESS
- cout << " ServerTestHarness::doRun: Delete all nodes in server. Using force to allow as many tests as possible\n";
-#endif
- BOOST_REQUIRE_MESSAGE(TestFixture::client().delete_all(true/*force, even if it creates zombies*/) == 0,CtsApi::to_string(CtsApi::delete_node()) << " failed should return 0. Should Delete ALL existing defs in the server\n" << TestFixture::client().errorMsg());
-
-
-#ifdef DEBUG_TEST_HARNESS
- cout << " ServerTestHarness::doRun: Load new defs in the server\n";
-#endif
- if ( load_defs_from_disk ) {
- BOOST_REQUIRE_MESSAGE(TestFixture::client().loadDefs( defs_filename_ ) == 0,"load defs failed should return 0. Should Load defs file " << defs_filename_ << " into the server from current working directory\n" << TestFixture::client().errorMsg());
- }
- else {
- // load expects a defs_ptr
- defs_ptr defs(&theClientDefs,null_deleter());
- BOOST_REQUIRE_MESSAGE(TestFixture::client().load( defs ) == 0,"load defs failed should return 0. Should Load defs file " << defs_filename_ << " into the server\n" << TestFixture::client().errorMsg());
- }
-
-#ifdef DEBUG_TEST_HARNESS
- cout << " ServerTestHarness::doRun: Restart server \n";
-#endif
- BOOST_REQUIRE_MESSAGE(TestFixture::client().restartServer() == 0,CtsApi::restartServer() << " failed should return 0. Should restart the server via a client command\n" << TestFixture::client().errorMsg());
-
-
-#ifdef DEBUG_TEST_HARNESS
- cout << " ServerTestHarness::doRun: Calling begin on suite " << suiteName << "\n";
-#endif
- BOOST_REQUIRE_MESSAGE(TestFixture::client().begin( suiteName ) == 0,CtsApi::begin( suiteName ) << " failed should return 0. Should Begin the suite " << suiteName << "\n" << TestFixture::client().errorMsg());
-
-
- if (waitForTestCompletion) {
-#ifdef DEBUG_TEST_HARNESS
- cout << " ServerTestHarness::doRun: Waiting for test to finish\n";
-#endif
- return testWaiter(theClientDefs,timeout,true /* test against verification attributes on defs */);
- }
- return defs_ptr();
-}
-
-
-static void test_invariants(defs_ptr the_defs, const std::string& title) {
- std::string errorMsg;
- BOOST_CHECK_MESSAGE( the_defs->checkInvariants(errorMsg),title << " Invariants failed " << errorMsg);
-}
-
-bool verify_attribute_verification()
-{
- // In version 4.0.1: We changed the way families changed states. i.e families will now change to state complete
- // before being requeued. See ECFLOW-96 Families with loops(cron/repeat) should log complete
- // This meant that when we run the migration tests, i.e new client with old server (with new test)
- // It would fail some the test, during verify attribute verification. ie. where we count the number of times
- // a node completes. To enable these tests to still run, we will disable verify attribute verification
- static bool allow_verification = true;
-
- if (!allow_verification) {
- //std::cout << "Disable verify attribute verification ------------------------------------------\n";
- return false;
- }
- char* the_env = getenv("DISABLE_VERIFY_ATTRIBUTE_VERIFICATION");
- if (the_env) {
- std::cout << "Disable verify attribute verification *************************************************************\n";
- allow_verification= false;
- return false;
- }
- return true;
-}
-
-defs_ptr
-ServerTestHarness::testWaiter( const Defs& theClientDefs, int timeout, bool verifyAttr)
-{
-#ifdef DEBUG_TEST_WAITER
- cout << "ServerTestHarness::testWaiter \n";
-#endif
-
-#ifdef DEBUG_DIFF
- std::string dump_defs_filename = "test.def";
- int counter = 0;
-#endif
-
- BOOST_REQUIRE_MESSAGE(TestFixture::client().client_handle() == 0,"Client handle expected to be zero but found " << TestFixture::client().client_handle());
-
- /// This function will test sync'ing. by getting the sync and full defs, then comparing them
- AssertTimer assertTimer(timeout,false); // Bomb out after n seconds, fall back if test fail
-
- // test the incremental changes
- defs_ptr incremental_defs;
- defs_ptr full_defs;
-
- int sleepTime = (theClientDefs.suiteVec().size() == 1) ? TestFixture::job_submission_interval() : 10;
- int sleep_fudgeFactor = TestFixture::job_submission_interval();
-
- // How do we terminate this test?
- // The test succeeds if the suite state is complete,
- while( 1 ) {
-#ifdef DEBUG_TEST_WAITER
- std::cout << "sleepTime = " << sleepTime << "\n";
-#endif
- sleep(sleepTime); // avoid calling get excessively, by using sleep
- DurationTimer timer; // automatically adjust sleep time
-
- bool server_changed = false;
- if (!full_defs.get()) {
- server_changed = true;
- // ********************************************************************************
- // Calling getDefs will also force a flush of the log file. This is required since we
- // copy the log file locally on the shared file system for cross platform testing
- // ******************************************************************************
- BOOST_REQUIRE_MESSAGE(TestFixture::client().getDefs() == 0,CtsApi::get() << " failed should return 0 " << TestFixture::client().errorMsg());
- full_defs = TestFixture::client().defs();
- incremental_defs = TestFixture::client().defs();
- BOOST_REQUIRE_MESSAGE( full_defs.get(),"get command failed to get node tree from server");
- BOOST_REQUIRE_MESSAGE( incremental_defs.get(),"get command failed to get node tree from server");
-
- // Ensure that when suite was loaded in server, that others suites were discarded
- BOOST_CHECK_MESSAGE(theClientDefs.suiteVec().size() == full_defs->suiteVec().size(),"mismatch in client suite count " << theClientDefs.suiteVec().size() << " and server " << full_defs->suiteVec().size());
- test_invariants(full_defs,"First time for getting full defs");
- }
- else {
- BOOST_CHECK_MESSAGE(TestFixture::client().news(full_defs) == 0, "news failed should return 0 " << TestFixture::client().errorMsg());
- server_changed = TestFixture::client().get_news();
- // std::cout << "server_changed = " << server_changed << "\n";
- if ( server_changed ) {
-
- // Get the incremental changes **FIRST** and compare this with the full defs later on
- BOOST_REQUIRE_MESSAGE(TestFixture::client().sync(incremental_defs) == 0, "sync failed should return 0 " << TestFixture::client().errorMsg());
- BOOST_CHECK_MESSAGE(TestFixture::client().in_sync(), "in_sync expected to return true, when we have changes in server");
- test_invariants(incremental_defs,"After syncing with incremental defs.");
-
- // get the FULL defs
- BOOST_REQUIRE_MESSAGE(TestFixture::client().getDefs() == 0,CtsApi::get() << " failed should return 0 " << TestFixture::client().errorMsg());
- full_defs = TestFixture::client().defs();
- BOOST_REQUIRE_MESSAGE( full_defs.get(),"get command failed to get node tree from server");
- test_invariants(full_defs,"After getting the full defs.");
-
- // **** NOTE ****: There could have been state change between the calls:
- // **************: TestFixture::client().sync(incremental_defs)
- // **************: TestFixture::client().getDefs()
- // **************: hence we can only compare, incremental and full defs if
- // **************: state and modification numbers are the same:
- BOOST_REQUIRE_MESSAGE(incremental_defs.get() != full_defs.get()," Expected two different defs trees ");
- if ( incremental_defs->state_change_no() == full_defs->state_change_no() &&
- incremental_defs->modify_change_no() == full_defs->modify_change_no()) {
- Ecf::set_debug_equality(true); // only has affect in DEBUG build
- BOOST_CHECK_MESSAGE( *full_defs == *incremental_defs,
- "Full and incremental defs should be the same. (state_change_no,modify_change_no) ("
- << incremental_defs->state_change_no() << "," << incremental_defs->modify_change_no() << ")"
- );
- Ecf::set_debug_equality(false); // only has affect in DEBUG build
- }
- else {
-#ifdef DEBUG_TEST_WAITER
- std::cout << "***** ServerTestHarness::testWaiter: State change between getting incremental and full defs\n";
-#endif
- }
- }
- }
-
- int hasAutoCancel = 0;
- size_t completeSuiteCnt = 0;
- if (server_changed) {
-
-#ifdef DEBUG_DIFF
- {
- PrintStyle::Type_t st = PrintStyle::getStyle();
- PrintStyle::setStyle(PrintStyle::STATE);
- counter++;
- std::string filename = dump_defs_filename + boost::lexical_cast<std::string>(counter);
- std::ofstream theFile( filename.c_str() );
-
- std::vector<Task*> tasks;
- full_defs->getAllTasks(tasks);
- int unknown = 0;
- int complete = 0;
- int queued = 0;
- int aborted = 0;
- int submitted = 0;
- int active = 0;
- size_t password_size = 0;
- size_t process_id_size = 0;
- for(size_t i =0; i < tasks.size(); i++) {
- switch (tasks[i]->state()) {
- case NState::UNKNOWN: unknown++; break;
- case NState::COMPLETE: complete++; break;
- case NState::QUEUED: queued++; break;
- case NState::ABORTED: aborted++; break;
- case NState::SUBMITTED: submitted++; break;
- case NState::ACTIVE: active++; break;
- }
- password_size += tasks[i]->jobsPassword().size();
- process_id_size += tasks[i]->process_or_remote_id().size();
- }
- theFile << "task password_size(" << password_size << ") process_id_size(" << process_id_size << ") total = " << (password_size + process_id_size) << endl;
- theFile << "unknown: " << unknown << "\n";
- theFile << "complete: " << complete << "\n";
- theFile << "queued: " << queued << "\n";
- theFile << "aborted: " << aborted << "\n";
- theFile << "submitted: " << submitted << "\n";
- theFile << "active: " << active << "\n";
- theFile << *full_defs.get();
- PrintStyle::setStyle(st);
- }
-#endif
- std::string errorMsg;
- BOOST_REQUIRE_MESSAGE( full_defs->checkInvariants(errorMsg),"Invariants failed " << errorMsg);
-
- // record the number of times that the server updated the calendar. Allow debug of time dependencies
- serverUpdateCalendarCount_ = full_defs->updateCalendarCount();
-
- BOOST_FOREACH(suite_ptr s, full_defs->suiteVec()) {
- if (s->state() == NState::COMPLETE) completeSuiteCnt++;
- if (s->hasAutoCancel()) hasAutoCancel++;
- }
-
-#ifdef DEBUG_TEST_WAITER_DEFS
- cout << "\nPrinting Defs ==================================================================================\n";
- std::cout << *full_defs.get();
- cout << "completeSuiteCnt = " << completeSuiteCnt
- << " full_defs->suiteVec().size() = " << full_defs->suiteVec().size()
- << " hasAutoCancel = " << hasAutoCancel << "\n";
-#endif
- if ( (full_defs->suiteVec().size() == completeSuiteCnt) && (hasAutoCancel == 0)) {
-
- if ( verifyAttr && verify_attribute_verification()) {
- // Do verification of expected state changes
- string localErrorMessage;
- BOOST_REQUIRE_MESSAGE(full_defs->verification(localErrorMessage),localErrorMessage << "\n" << *full_defs.get());
- }
- return full_defs;
- }
- }
-
- // make sure test does not take too long.
- if ( assertTimer.duration() >= assertTimer.timeConstraint() ) {
- // Give clues why we are not finishing on time, by using Why and by dumping out node tree
- cout << "Test time " << assertTimer.duration() << " taking longer than time constraint of " << assertTimer.timeConstraint() << " aborting\n";
- cout << " completeSuiteCnt = " << completeSuiteCnt << "\n";
- cout << " full_defs->suiteVec().size() = " << full_defs->suiteVec().size() << "\n";
- cout << " hasAutoCancel = " << hasAutoCancel << "\n";
- std::cout << "update-calendar-count(" << serverUpdateCalendarCount_ << ")\n";
- std::cout << "WHY:\n";
- WhyCmd reason(full_defs, "" /* do a top down why */ );
- std::cout << reason.why() << "\n";
- }
- BOOST_REQUIRE_MESSAGE(assertTimer.duration() < assertTimer.timeConstraint(),"\n" << *full_defs);
- if ( assertTimer.duration() >= assertTimer.timeConstraint()) break; // fix warning on AIX
-
- // auto adjust sleep time.
- sleepTime = timer.duration() + sleep_fudgeFactor;
- }
- return defs_ptr();
-}
-
-
-void ServerTestHarness::createDirAndEcfFiles(
- NodeContainer* nc,
- const std::string& smshome,
- const std::map<std::string,std::string>& customTaskSmsMap,
- int& customSmsCnt) const
-{
- std::string directory = smshome + nc->absNodePath();
-#ifdef DEBUG_TEST_HARNESS
- cout << "creating directory " << directory << "\n";
-#endif
-
- if ( !fs::exists( smshome ) ) fs::create_directory( smshome );
- if ( !fs::exists( directory ) ) fs::create_directory( directory );
-
- if ( generateManFileForNodeContainers_ ) {
- std::string manFileName = smshome + nc->absNodePath() + File::MAN_EXTN();
- std::ofstream theManFile( manFileName.c_str() );
- theManFile << "%manual\n";
- theManFile << "This file auto generated by ServerTestHarness::createDirAndEcfFiles for all Node Containers\n";
- theManFile << "%end\n";
- }
-
- BOOST_FOREACH(node_ptr n, nc->nodeVec()) {
-
- Task* t = n->isTask();
- if (t) {
- std::string ecf_file = smshome + t->absNodePath() + File::ECF_EXTN();
-#ifdef DEBUG_TEST_HARNESS
- cout << "creating ecf file " << ecf_file << "\n";
-#endif
- // Create ECF file with default template or custom file.
- std::ofstream theEcfFile( ecf_file.c_str() );
- std::map<std::string,std::string>::const_iterator it = customTaskSmsMap.find(t->absNodePath());
- if (it == customTaskSmsMap.end()) theEcfFile << getDefaultTemplateEcfFile(t);
- else {
- theEcfFile << (*it).second;
- customSmsCnt++;
- }
- }
- else {
- Family* f = n->isFamily();
- assert(f);
- createDirAndEcfFiles(f,smshome,customTaskSmsMap,customSmsCnt);
- }
- }
-}
-
-
-std::string ServerTestHarness::getDefaultTemplateEcfFile(Task* t) const
-{
- std::string templateEcfFile;
-
- templateEcfFile += "%manual\n";
- templateEcfFile += "This is the default ecf script file used for testing\n";
- templateEcfFile += "%end\n";
- templateEcfFile += "%comment\n";
- templateEcfFile += "# Using angle brackets should use ECF_INCLUDE\n";
- templateEcfFile += "%end\n";
- templateEcfFile += "%include <head.h>\n";
- templateEcfFile += "\n";
- BOOST_FOREACH(const Event& e, t->events()) {
- templateEcfFile += "%ECF_CLIENT_EXE_PATH% --event=" + e.name_or_number() + "\n";
- }
- BOOST_FOREACH(const Meter& m, t->meters()) {
- templateEcfFile += "for i in";
- int min = m.min();
- int max = m.max();
- int delta = abs(max -min)/10;
- for(int i = min+delta; i <= max; i = i + delta) {
- templateEcfFile += " ";
- templateEcfFile += boost::lexical_cast<std::string>(i);
- }
- templateEcfFile += "\n";
- templateEcfFile += "do\n";
- templateEcfFile += " %ECF_CLIENT_EXE_PATH% --meter=" + m.name() + " $i\n";
- templateEcfFile += " sleep %SLEEPTIME%\n";
- templateEcfFile += "done\n";
- }
- /// labels require at least 2 arguments,
- BOOST_FOREACH(const Label& label, t->labels()) {
- if (!label.new_value().empty()) {
- templateEcfFile += "%ECF_CLIENT_EXE_PATH% --label=" + label.name() + " " + label.new_value() + "\n";
- }
- else if (!label.value().empty()) {
- templateEcfFile += "%ECF_CLIENT_EXE_PATH% --label=" + label.name() + " " + label.value() + "\n";
- }
- }
- if (add_default_sleep_time_ && t->events().empty() && t->meters().empty()) {
- templateEcfFile += "\n# SLEEPTIME is defined the Client Defs.def file. Test variable substitution\n";
- templateEcfFile += "sleep %SLEEPTIME%\n";
- }
- templateEcfFile += "\n%include <tail.h>\n";
- return templateEcfFile;
-}
-
-std::string ServerTestHarness::testDataDefsLocation( const std::string& defsFile)
-{
- // DefsFile is of the form base_name.def"
- // We want to place the defs and log file in the same location as its test directory
- // test/data/ECF_HOME/base_name/base_name.def
- std::string testData = testDataLocation(defsFile) + "/" + defsFile;
- return testData;
-}
-
-std::string ServerTestHarness::testDataLocation( const std::string& defsFile)
-{
- // DefsFile is of the form:
- // base_name.def
- // /tmp/path/base_name.def
- // We want to place the defs and log file in the same location as its test directory
- // test/data/ECF_HOME/base_name
- //
- std::string base_name = defsFile;
- size_t slash_pos = defsFile.rfind('/',defsFile.length());
- if ( slash_pos != std::string::npos) {
- base_name = base_name.erase(0,slash_pos+1);
- }
-
- size_t dot_pos = base_name.rfind('.',base_name.length());
- assert( dot_pos != std::string::npos); // missing '.'
- base_name = base_name.substr(0,dot_pos);
-
-
- std::string testData = TestFixture::smshome() + "/" + base_name;
- return testData;
-}
diff --git a/ecflow_4_0_7/Test/src/ServerTestHarness.hpp b/ecflow_4_0_7/Test/src/ServerTestHarness.hpp
deleted file mode 100644
index 37c5265..0000000
--- a/ecflow_4_0_7/Test/src/ServerTestHarness.hpp
+++ /dev/null
@@ -1,109 +0,0 @@
-#ifndef SERVERTESTHARNESS_HPP_
-#define SERVERTESTHARNESS_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #46 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-
-#include <boost/noncopyable.hpp>
-#include <boost/shared_ptr.hpp>
-#include <string>
-#include <map>
-#include "NodeFwd.hpp"
-#include "ZombieUtil.hpp"
-class ClientInvoker;
-
-// This class provides a test harness for running defs file in a client server environment
-// To avoid Address in use errors, we can have client/server use a different port number
-// This is more important when doing instrumentation in HP-UX, as that can take a long time.
-//
-// The Server is started/stopped by use of the Global text Fixture
-// See class TestFixture.hpp
-//
-class ServerTestHarness : private boost::noncopyable {
-public:
- // if standardVerification is true, we test task goes through normal life cycle
- // changes. else we compare the log file states with golden log file
- // Comparing log files across platforms is not reliable, and ignored
- ServerTestHarness();
-
- /// generate man files for Suite and family nodes
- void generateManFileForNodeContainers() { generateManFileForNodeContainers_ = true; }
-
- /// Enable/disable checking for server poll being to small.
- /// This test creates dummy .ecf files. Since these tests are run with the server poll
- /// which is less than 60, we need the task duration between submit->active->complete duration to be less
- /// the server poll. Tests with time dependencies of one minute separation will be missed.\n"
- /// Make this configurable since for large defs, when we have 1000's of tasks the
- /// task duration times are not deterministic
- void check_task_duration_less_than_server_poll(bool f) { check_task_duration_less_than_server_poll_ = f;}
-
- /// Sometimes on slow systems we want to disable sleep time.
- /// since the time duration between submit->active->complete is greater than job submission interval
- /// and hence time slots get missed.
- /// The Default is to add the sleep time always for events and meters and when there is NO events or meters
- /// This flags is used for the *specific* case when there is *no* events/meters.
- void add_default_sleep_time(bool f) { add_default_sleep_time_ = f ;}
-
- // Run the following defs file in the test harness.
- // If no map is provided then a default sms file is fabricated, otherwise
- // the map allows a sms file string to be associated with a task path
- // map.first = absolute task path
- // map.second = sms file string
-#if defined(_AIX)
- void run(Defs&, const std::string& defs_file, const std::map<std::string,std::string>&, int timeout = 120, bool waitForTestCompletion = true);
- void run(Defs&, const std::string& defs_file, int timeout = 120,bool waitForTestCompletion = true);
-#elif defined(HPUX)
- void run(Defs&, const std::string& defs_file, const std::map<std::string,std::string>&, int timeout = 100, bool waitForTestCompletion = true);
- void run(Defs&, const std::string& defs_file, int timeout = 100,bool waitForTestCompletion = true);
-#else
- void run(Defs&, const std::string& defs_file, const std::map<std::string,std::string>&, int timeout = 40, bool waitForTestCompletion = true);
- void run(Defs&, const std::string& defs_file, int timeout = 40,bool waitForTestCompletion = true);
-#endif
-
- /// Returns the location of the defs file, such thats it in the test data area
- static std::string testDataDefsLocation( const std::string& defsFile);
-
- /// The test data location
- static std::string testDataLocation( const std::string& defsFile);
-
-
- /// This function is used for waiting for test to finish
- /// returns the defs from the server at test completeion
- defs_ptr testWaiter( const Defs& theClientDefs,// The defs on the client side
- int timeout, // How long should we wait for test to finish
- bool verifyAttr); // Test verification use verify attributes on defs
-
- /// for debug return the number of times the calendar was updated in the server
- unsigned int serverUpdateCalendarCount() const { return serverUpdateCalendarCount_;}
-private:
-
- defs_ptr doRun(Defs&, const std::map<std::string,std::string>&, int sleepTime,bool waitForTestCompletion);
-
- void createDirAndEcfFiles(
- NodeContainer* nc,
- const std::string& smshome,
- const std::map<std::string,std::string>& taskSmsMap,
- int& customSmsCnt) const;
-
- /// default ecf file will cater for events and meters
- std::string getDefaultTemplateEcfFile(Task* t) const;
-
-private:
- bool generateManFileForNodeContainers_;
- bool check_task_duration_less_than_server_poll_;
- bool add_default_sleep_time_;
- int serverUpdateCalendarCount_;
- std::string defs_filename_;
-};
-#endif
diff --git a/ecflow_4_0_7/Test/src/TestFixture.cpp b/ecflow_4_0_7/Test/src/TestFixture.cpp
deleted file mode 100644
index 303135c..0000000
--- a/ecflow_4_0_7/Test/src/TestFixture.cpp
+++ /dev/null
@@ -1,381 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #77 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : This Fixture facilitates the test of client/server on different platforms
-//============================================================================
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/lexical_cast.hpp>
-#include <iostream>
-#include <stdlib.h> // for getenv()
-#include <fstream> // for ofstream
-
-#include "TestFixture.hpp"
-#include "Defs.hpp"
-#include "Task.hpp"
-#include "ClientEnvironment.hpp" // needed for static ClientEnvironment::hostSpecified(); ONLY
-#include "File.hpp"
-#include "TestHelper.hpp"
-#include "Str.hpp"
-#include "CtsApi.hpp"
-#include "PrintStyle.hpp"
-#include "Host.hpp"
-#include "ChangeMgrSingleton.hpp" // keep valgrind happy
-#include "Rtt.hpp"
-#include "EcfPortLock.hpp"
-
-#ifdef DEBUG
-std::string rtt_filename = "rtt.dat";
-#else
-std::string rtt_filename = "rtt_d.dat";
-#endif
-std::string TestFixture::scratchSmsHome_ = "";
-std::string TestFixture::host_;
-std::string TestFixture::port_;
-std::string TestFixture::test_dir_;
-std::string TestFixture::project_test_dir_ = "Test";
-
-using namespace std;
-using namespace ecf;
-namespace fs = boost::filesystem;
-
-// ************************************************************************************************
-// For test purpose the server can be started:
-// 1/ By this test fixture
-// 2/ Externally but on the same machine. by defining env variable: export ECF_NODE=localhost
-// WHY? To test for memory leak. (i.e. with valgrind)
-// 3/ Externally but on a different platform. by defining env variable: export ECF_NODE=itanium
-// In this case we NEED to copy the test data, so that it is
-// accessible by the client AND server
-//
-// When invoking the server Externally _MUST_ use .
-// ./Server/bin/gcc.<version>/debug/server --ecfinterval=2
-// The --ecfinterval=2 is _important_ or test will take a long time
-// ************************************************************************************************
-
-// Uncomment to preserve the files for test
-//#define DEBUG_HOST_SERVER 1
-#define DEBUG_LOCAL_SERVER 1
-
-TestFixture::TestFixture(const std::string& project_test_dir)
-{
- init(project_test_dir);
-}
-
-TestFixture::TestFixture()
-{
- init("Test");
-}
-
-ClientInvoker& TestFixture::client()
-{
- static ClientInvoker theClient_;
- return theClient_;
-}
-
-
-void TestFixture::init(const std::string& project_test_dir)
-{
- TestFixture::project_test_dir_ = project_test_dir;
-
- if ( !fs::exists( local_ecf_home() ) ) fs::create_directory( local_ecf_home() );
-
- // client side file for recording all ClientInvoker round trip times
- boost::filesystem::remove(rtt_filename);
- Rtt::create(rtt_filename);
-
- // ********************************************************
- // Note: Global fixture Constructor can not use BOOST macro
- // ********************************************************
- PrintStyle::setStyle(PrintStyle::STATE);
-
- // Let first see if we need do anything. If ECF_NODE is specified (ie the name
- // of the machine, which has the ecflow server), only then do we need to do anything.
- // The server must have access to the file system specified by ECF_HOME.
- // This becomes an issue when the server is on a different machine
- host_ = ClientEnvironment::hostSpecified();
- port_ = ClientEnvironment::portSpecified(); // returns ECF_PORT, otherwise Str::DEFAULT_PORT_NUMBER
- std::cout << "TestFixture::TestFixture() jobSubmissionInterval = " << job_submission_interval() << "\n";
- if (!host_.empty() && host_ != Str::LOCALHOST()) {
-
- client().set_host_port(host_,port_);
- std::cout << " EXTERNAL SERVER running on _ANOTHER_ PLATFORM, assuming " << host_ << ":" << port_ << " copying test data ...\n";
-
- // Must use a file system accessible from the server. Use $SCRATCH
- // Duplicate test data, required to scratch area and reset ECF_HOME
- char* scratchEnv = getenv("SCRATCH");
- assert(scratchEnv != NULL);
- std::string theSCRATCHArea(scratchEnv);
- assert(!theSCRATCHArea.empty());
-
- theSCRATCHArea += "/test_dir";
- test_dir_ = theSCRATCHArea; // test_dir_ needed in destructor
- if (boost::filesystem::exists(test_dir_)) {
- boost::filesystem::remove_all(test_dir_);
- }
- theSCRATCHArea += "/ECF_HOME";
- scratchSmsHome_ = theSCRATCHArea;
-
- bool ok = File::createDirectories(theSCRATCHArea); assert(ok);
- ok = fs::exists(theSCRATCHArea); assert(ok);
-
- // Ensure that local includes data exists. This needs to be copied to SCRATCH
- ok = fs::exists(includes()); assert(ok);
-
- // Copy over the includes directory to the SCRATCH area.
- std::string scratchIncludes = test_dir_ + "/";
- std::string do_copy = "cp -r " + includes() + " " + scratchIncludes;
- if (system( do_copy.c_str() ) != 0) assert(false);
-
- // clear log file
- clearLog();
- }
- else if (!host_.empty() && host_ == Str::LOCALHOST()) {
-
- client().set_host_port(host_,port_);
- std::cout << " EXTERNAL SERVER running on _SAME_ PLATFORM. Assuming " << host_ << ":" << port_ << "\n";
-
- // log file may have been deleted, by previous tests. Create a new log file
- std::string the_log_file = TestFixture::pathToLogFile();
- if ( !fs::exists( the_log_file )) {
- std::cout << " Log file " << the_log_file << " does NOT exist, attempting to recreate\n";
- std::cout << " Creating new log(via remote server) file " << the_log_file << "\n";
- client().new_log( the_log_file );
- client().logMsg("Created new log file. msg sent to force new log file to be written to disk");
- }
- else std::cout << " Log file " << the_log_file << " already exist\n";
- }
- else {
- // For local host start by removing log file. Server invocation should create a new log file
- boost::filesystem::remove( boost::filesystem::path( pathToLogFile() ) );
- host_ = Str::LOCALHOST();
-
- // Create a unique port number, allowing debug and release to run at the same time
- // Note: linux64 and linux64intel, can run on same machine, on different workspace
- // Hence the lock file is not sufficient. Hence we will make a client server call.
- cout << "Find free port to start server, starting with port " << port_ << "\n";
- int the_port = boost::lexical_cast<int>(port_);
- while (!EcfPortLock::is_free(the_port)) the_port++;
- port_ = ClientInvoker::find_free_port(the_port,true /*show debug output */);
- EcfPortLock::create(port_);
-
- // host_ is empty update to localhost, **since** port may have changed, update ClinetInvoker
- client().set_host_port(host_,port_);
-
- // Remove the generated check point files, at start of test, otherwise server will load check point file
- Host h;
- boost::filesystem::remove(h.ecf_checkpt_file(port_));
- boost::filesystem::remove(h.ecf_backup_checkpt_file(port_));
-
- std::string theServerInvokePath = File::find_ecf_server_path();
- assert(!theServerInvokePath.empty() );
- theServerInvokePath += " --port=" + port_ ;
- theServerInvokePath += " --ecfinterval=" + boost::lexical_cast<std::string>( job_submission_interval() );
- theServerInvokePath += "&";
- if ( system( theServerInvokePath.c_str() ) != 0) assert(false); // " Server invoke failed "
-
- std::cout << " ECF_NODE not specified, starting LOCAL " << theServerInvokePath << "\n";
- }
-
- /// Ping the server to see if its running
- /// Assume remote/local server started on the default port
- /// Either way, we wait for 60 seconds for server, for it to respond to pings
- /// This is important when server is started locally. We must wait for it to come alive.
- if (!client().wait_for_server_reply()) {
- cout << "Ping server on " << host_ << Str::COLON() << port_ << " failed. Is the server running ? " << client().errorMsg() << "\n";
- assert(false);
- }
-
- // Log file must exist, otherwise test will not work. Log file required for comparison
- if ( !fs::exists( TestFixture::pathToLogFile() )) {
- cout << "Log file " << TestFixture::pathToLogFile() << " does not exist\n";
- assert(false);
- }
-}
-
-
-TestFixture::~TestFixture()
-{
- // Note: Global fixture Destructor can not use BOOST macro
- std::cout << "TestFixture::~TestFixture() " << host_ << ":" << port_ << "\n";
-
- // destructors should not allow exception propagation
- try {
-#ifndef DEBUG_HOST_SERVER
- if (!host_.empty() && boost::filesystem::exists(test_dir_)) {
- boost::filesystem::remove_all(test_dir_);
- }
-#endif
-#ifndef DEBUG_LOCAL_SERVER
- if (boost::filesystem::exists(local_ecf_home())) {
- boost::filesystem::remove_all(local_ecf_home());
- }
-#endif
-
- // Print the server suites
- client().set_cli(true); // so server stats are written to standard out
- client().set_throw_on_error( false ); // destructors should not allow exception propagation
- if (client().suites() != 0) {
- std::cout << "TestFixture::~TestFixture(): ClientInvoker " << CtsApi::suites() << " failed: " << client().errorMsg() << "\n";
- }
-
- // Print the server stats
- if (client().stats() != 0) {
- std::cout << "TestFixture::~TestFixture(): ClientInvoker " << CtsApi::stats() << " failed: " << client().errorMsg() << "\n";
- }
-
- // Kill the server, as all suites are complete. will work for local or external
- if (client().terminateServer() != 0) {
- std::cout << "TestFixture::~TestFixture(): ClientInvoker " << CtsApi::terminateServer() << " failed: " << client().errorMsg() << "\n";
- EcfPortLock::remove( port_ );
- assert(false);
- }
- sleep(1); // allow time to update log file
-
- // Remove the generated check point files, at end of test
- Host host;
- boost::filesystem::remove(host.ecf_log_file(port_));
- boost::filesystem::remove(host.ecf_checkpt_file(port_));
- boost::filesystem::remove(host.ecf_backup_checkpt_file(port_));
-
- // remove the lock file
- EcfPortLock::remove( port_ );
-
- // keep valgrind happy
- ChangeMgrSingleton::destroy();
-
- // destroy, so that we flush the rtt_filename
- Rtt::destroy();
-
- cout << "\nTiming: *NOTE*: The child commands *NOT* recorded. Since its a separate exe(ecflow_client), called via .ecf script\n";
- cout << Rtt::analyis(rtt_filename); // report round trip times
- boost::filesystem::remove(rtt_filename);
- }
- catch (std::exception& ex) {
- std::cout << "TestFixture::~TestFixture() caught exception " << ex.what() << "\n";
- }
- catch (...) {
- std::cout << "TestFixture::~TestFixture() caught unknown exception\n";
- }
-}
-
-int TestFixture::job_submission_interval()
-{
- int jobSubmissionInterval = 3 ;
-#if defined(HPUX) || defined(_AIX)
- jobSubmissionInterval += 3;
-#endif
- return jobSubmissionInterval;
-}
-
-std::string TestFixture::smshome()
-{
- if ( serverOnLocalMachine() )
- return local_ecf_home();
- return scratchSmsHome_;
-}
-
-bool TestFixture::serverOnLocalMachine() {
- return (host_.empty() || host_ == Str::LOCALHOST());
-}
-
-std::string TestFixture::theClientExePath()
-{
- if ( serverOnLocalMachine() ) return File::find_ecf_client_path();
-
- char* client_path_p = getenv("ECF_CLIENT_EXE_PATH");
- if ( client_path_p == NULL) {
-
- // Try this before complaining
- std::string path = "/usr/local/apps/ecflow/current/bin/ecflow_client";
- if ( fs::exists(path) ) return path;
-
- cout << "Please set ECF_CLIENT_EXE_PATH. This needs to be set to path to the client executable\n";
- cout << "The client must be the one that was built on the same platform as the server\n";
- assert(false);
- }
- return string(client_path_p);
-}
-
-void TestFixture::clearLog() {
-
- // Can't remove log on remote server, just clear the log file
- client().clearLog();
-}
-
-std::string TestFixture::pathToLogFile()
-{
- if ( serverOnLocalMachine() ) {
- Host host;
- return host.ecf_log_file(port_);
- }
-
- char* pathToRemoteLog_p = getenv("ECF_LOG");
- if ( pathToRemoteLog_p == NULL) {
- cout << "TestFixture::pathToLogFile(): assert failed\n";
- cout << "Please set ECF_LOG. This needs to be set to path to the log file\n";
- cout << "that can be seen by the client and server\n";
- assert(false);
- }
- return std::string(pathToRemoteLog_p);
-}
-
-std::string TestFixture::local_ecf_home()
-{
- std::string rel_path = project_test_dir_;
-#ifdef DEBUG
- rel_path += "/data/ECF_HOME_debug";
-#else
- rel_path += "/data/ECF_HOME_release";
-#endif
-
- std::string absolute_path = File::test_data(rel_path,project_test_dir_);
- return absolute_path;
-}
-
-std::string TestFixture::includes()
-{
- // Get to the root source directory
- std::string includes_path = File::root_source_dir();
- includes_path += "/";
- includes_path += project_test_dir_;
- includes_path += "/data/includes";
- //std::cout << "includes_path = " << includes_path << " ==============================================\n";
- return includes_path;
-}
-
-
-/// Given a task name like "a" find the find the first task matching that name
-/// and returns is abs node path
-std::string TestFixture::taskAbsNodePath(const Defs& theDefs, const std::string& taskName)
-{
- std::vector<Task*> vec;
- theDefs.getAllTasks(vec);
- BOOST_FOREACH(Task* t , vec ) {
- if (t->name() == taskName) return t->absNodePath();
- }
-
- cout << "TestFixture::taskAbsNodePath: assert failed: Could not find task " << taskName << "\n";
- assert(false); // could not find the task ??
- return string();
-}
-
-int TestFixture::server_version()
-{
- client().server_version();
- std::string the_server_version_str = TestFixture::client().get_string();
- //cout << "\nserver_version_str = " << the_server_version_str << "\n";
- BOOST_REQUIRE_MESSAGE( Str::replace_all(the_server_version_str,".",""),"failed to find '.' in server version string " << TestFixture::client().get_string());
- int the_server_version = boost::lexical_cast<int>(the_server_version_str);
- return the_server_version;
-}
diff --git a/ecflow_4_0_7/Test/src/TestFixture.hpp b/ecflow_4_0_7/Test/src/TestFixture.hpp
deleted file mode 100644
index e04e6ac..0000000
--- a/ecflow_4_0_7/Test/src/TestFixture.hpp
+++ /dev/null
@@ -1,103 +0,0 @@
-#ifndef TESTFIXTURE_HPP_
-#define TESTFIXTURE_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #14 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : This Fixture facilitates the test of client/server on different platforms
-//
-// In order to carry out the test, we must have a common file system.
-// We will use $SCRATCH as this is accessible by both client and server.
-// This means copying over the test data
-//
-// When TextFixture is GLOBAL, then we can't seem to call any of the
-// BOOST_REQUIRE_MESSAGE() macro in constructor/descructor as this causes a crash
-// i.e order of initialisation issues
-//============================================================================
-
-#include "ClientInvoker.hpp"
-#include <string>
-class Defs;
-
-//
-// Need to use static data, since with boost global fixture, its not possible to access
-// the global test fixture in each of the test cases
-//
-struct TestFixture {
-
- // Constructor will invoke the server, destructor will kill the server
- // Since this class is static, the constructor/destructor can not call
- // any of BOOST MACRO, since the unit test will not be there.
- // When running across platforms will will assume server is already running
- TestFixture(const std::string& project_test_dir /* Test or view */);
- TestFixture();
- ~TestFixture();
-
- // Configure the server with the job submission interval.
- // i.e for each 'n' seconds of job submission interval the calendar
- // is typically incremented by 1 minute. Hence speeding up the
- // time and thus the testing. See Calendar for further details
- static int job_submission_interval();
-
- /// The location of ECF home will vary. If client/server on same machines we
- /// return test data location. Otherwise we need return a common file system location
- /// that was created in the constructor
- static std::string smshome();
-
- /// Will end up checking to see if ECF_NODE is specified. This specifies the name
- /// of the machine that is running the server. Otherwise return true
- static bool serverOnLocalMachine();
-
- /// If running locally returns location of client exe, if a server is on a remote
- /// machine, we need to determine its location.
- // Several options:
- // a/ Search for hard code path
- // b/ Ask server about test data, i.e. client exe path, log file location , etc
- // More flexible
- static std::string theClientExePath();
-
- /// When multiple tests are run , we need to clear the log file
- static void clearLog();
-
- /// When local just returns ecf.log, when remote return path to log file
- static std::string pathToLogFile();
-
- /// Given a task name like "a" find the find the first task matching that name
- /// and returns is abs node path
- static std::string taskAbsNodePath(const Defs& theDefs, const std::string& taskName);
-
- /// Location of the includes used in the ecf file
- static std::string includes();
-
- /// returns the server version as an integer.
- /// This allows as to ignore some tests, when testing old servers.(with new clients).
- static int server_version();
-
- // Use for all comms with server
- static ClientInvoker& client();
- static std::string port() { return port_;}
-
-private:
-
- static std::string local_ecf_home();
-
- void init(const std::string& project_test_dir);
-
-private:
-
- static std::string scratchSmsHome_;
- static std::string host_;
- static std::string port_;
- static std::string test_dir_; // used when we have an external server, different platform
- static std::string project_test_dir_; // "Test" or "view"
-};
-
-#endif
diff --git a/ecflow_4_0_7/Test/src/ZombieUtil.hpp b/ecflow_4_0_7/Test/src/ZombieUtil.hpp
deleted file mode 100644
index 0426bc3..0000000
--- a/ecflow_4_0_7/Test/src/ZombieUtil.hpp
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef ZOMBIE_UTIL_HPP_
-#define ZOMBIE_UTIL_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #57 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//============================================================================
-
-#include <boost/noncopyable.hpp>
-#include "Child.hpp"
-class ClientInvoker;
-
-//
-class ZombieUtil : private boost::noncopyable {
-public:
- static void test_clean_up(int timeout);
- static int do_zombie_user_action(ecf::User::Action uc,
- int expected_action_cnt,
- int max_time_to_wait,
- bool fail_if_to_long = true);
-};
-
-class TestClean : private boost::noncopyable {
-public:
- TestClean(int timeout = 25) : timeout_(timeout) { ZombieUtil::test_clean_up(timeout);}
- ~TestClean() { ZombieUtil::test_clean_up(timeout_);}
-private:
- int timeout_;
-};
-
-#endif
diff --git a/ecflow_4_0_7/Test/src/ZombieUtill.cpp b/ecflow_4_0_7/Test/src/ZombieUtill.cpp
deleted file mode 100644
index eafd490..0000000
--- a/ecflow_4_0_7/Test/src/ZombieUtill.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #57 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//============================================================================
-
-#include <iostream>
-#include <boost/test/unit_test.hpp>
-
-#include "ZombieUtil.hpp"
-
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "PrintStyle.hpp"
-#include "ClientToServerCmd.hpp"
-#include "AssertTimer.hpp"
-#include "Zombie.hpp"
-#include "TestFixture.hpp"
-
-using namespace std;
-using namespace ecf;
-
-void ZombieUtil::test_clean_up(int timeout) {
-
- // try to tidy up. Avoid leaving zombie process that mess up tests
- TestFixture::client().zombieGet();
- std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
- if (!zombies.empty()) {
- cout << "\n***** test_clean_up: found\n" << Zombie::pretty_print( zombies , 9) << "\n, attempting to *fob* then *remove* ...\n";
-
- int no_fobed = do_zombie_user_action(User::FOB, zombies.size(), timeout, false /* don't fail if it takes to long */);
-
- // In order to FOB, we must wait, till a child command, talks to the server.
- if (no_fobed) {
- int wait = 5;
-#if defined(HPUX) || defined(_AIX)
- wait += 5; // On these platforms wait longer,
-#endif
- cout << " Fobed " << no_fobed << " left over zombies. sleeping for " << wait << "s before attempting to remove\n";
- sleep(wait);
- }
- (void) do_zombie_user_action(User::REMOVE, no_fobed, timeout, false /* don't fail if it takes to long */);
- }
-}
-
-int ZombieUtil::do_zombie_user_action(User::Action uc, int expected_action_cnt, int max_time_to_wait, bool fail_if_to_long)
-{
- /// return the number of zombies set to user action;
- bool ecf_debug_zombies = false;
- if (getenv("ECF_DEBUG_ZOMBIES")) {
- ecf_debug_zombies = true;
- cout << "\n do_zombie_user_action " << User::to_string(uc) << " expected_action_cnt " << expected_action_cnt << "\n";
- }
-
- int action_set = 0;
- std::vector<Zombie> action_set_zombies;
- AssertTimer assertTimer(max_time_to_wait,false); // Bomb out after n seconds, fall back if test fail
- while (1) {
- BOOST_REQUIRE_MESSAGE(TestFixture::client().zombieGet() == 0, "zombieGet failed should return 0\n" << TestFixture::client().errorMsg());
- std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
- bool continue_looping = false;
- BOOST_FOREACH(const Zombie& z, zombies) {
- switch (uc) {
- case User::FOB: {
- if (!z.fob()) {
- TestFixture::client().zombieFob(z); // UNBLOCK, child commands, allow zombie to complete, will clear server_reply().zombies()
- continue_looping = true;
- action_set++;
- action_set_zombies.push_back(z);
- }
- break;
- }
- case User::FAIL: {
- if (!z.fail()) {
- TestFixture::client().zombieFail(z); // UNBLOCK, child commands, allow zombie to complete, will clear server_reply().zombies()
- continue_looping = true;
- action_set++;
- action_set_zombies.push_back(z);
- }
- break;
- }
- case User::ADOPT: {
- if (!z.adopt()) {
- TestFixture::client().zombieAdopt(z); // UNBLOCK, child commands, allow zombie to complete, will clear server_reply().zombies()
- continue_looping = true;
- action_set++;
- action_set_zombies.push_back(z);
- }
- break;
- }
- case User::REMOVE: {
- if (!z.remove()) { // should always return false
- TestFixture::client().zombieRemove(z); // This should be immediate, and is not remembered
- continue_looping = true;
- action_set++;
- action_set_zombies.push_back(z);
- }
- break;
- }
- case User::BLOCK: {
- if (!z.block()) {
- TestFixture::client().zombieBlock(z);
- continue_looping = true;
- action_set++;
- action_set_zombies.push_back(z);
- }
- break;
- }
- case User::KILL: {
- if (!z.kill()) {
- TestFixture::client().zombieKill(z);
- continue_looping = true;
- action_set++;
- action_set_zombies.push_back(z);
- }
- break;
- }
- }
- }
-
- if (expected_action_cnt == action_set) {
- break; // return
- }
-
- if ( !continue_looping && action_set > 0) {
- if (expected_action_cnt == 0) break; // return, some clients set this as 0
- if (expected_action_cnt == action_set) break; // return
- }
-
- // make sure test does not take too long.
- if ( assertTimer.duration() >= assertTimer.timeConstraint() ) {
-
- if (expected_action_cnt > 0 && action_set > 0) {
- if (ecf_debug_zombies) cout << " timeing out after action_set = " << action_set << " expected_action_cnt = " << expected_action_cnt << "\n";
- break;
- }
-
- std::stringstream ss;
- ss << "do_zombie_user_action:\nExpected " << expected_action_cnt
- << " zombies with user action " << User::to_string(uc) << " but found " << action_set << "\naction set zombies\n"
- << Zombie::pretty_print( action_set_zombies , 6)
- << ", Test taking longer than time constraint of "
- << assertTimer.timeConstraint();
- if (fail_if_to_long) {
- BOOST_REQUIRE_MESSAGE(false,ss.str() << " aborting\n" << Zombie::pretty_print( zombies , 6));
- }
- else {
- cout << ss.str() << " breaking out\n" << Zombie::pretty_print( zombies , 6) << "\n";
- break;
- }
- }
- sleep(1);
- }
-
- // return the real state of the server zombies.
- // *** Note: remove is immediate hence z.remove() below is not valid
- action_set = 0;
- BOOST_REQUIRE_MESSAGE(TestFixture::client().zombieGet() == 0, "zombieGet failed should return 0\n" << TestFixture::client().errorMsg());
- std::vector<Zombie> zombies = TestFixture::client().server_reply().zombies();
- BOOST_FOREACH(const Zombie& z, zombies) {
- switch (uc) {
- case User::FOB: { if (z.fob()) action_set++; break; }
- case User::FAIL: { if (z.fail()) action_set++; break; }
- case User::ADOPT: { if (z.adopt()) action_set++; break; }
- case User::REMOVE: { if (z.remove()) action_set++; break; }
- case User::BLOCK: { if (z.block()) action_set++; break; }
- case User::KILL: { if (z.kill()) action_set++; break; }
- }
- }
- if (ecf_debug_zombies) {
- cout << " " << action_set << " zombies set to user action " << User::to_string(uc) << " returning\n";
- cout << Zombie::pretty_print( zombies , 6);
- }
- return action_set;
-}
diff --git a/ecflow_4_0_7/VERSION.cmake b/ecflow_4_0_7/VERSION.cmake
deleted file mode 100644
index 488b1fd..0000000
--- a/ecflow_4_0_7/VERSION.cmake
+++ /dev/null
@@ -1,7 +0,0 @@
-set( ECFLOW_RELEASE "4" )
-set( ECFLOW_MAJOR "0" )
-set( ECFLOW_MINOR "7" )
-
-# use this form to be consistent with other packages, + allow standard extraction of version from scripts
-# could replaced "4.0.7" with "${ECFLOW_RELEASE}.${ECFLOW_MAJOR}.${ECFLOW_MINOR}"
-set( ${PROJECT_NAME}_VERSION_STR "4.0.7" )
diff --git a/ecflow_4_0_7/build/aix_fix/README b/ecflow_4_0_7/build/aix_fix/README
deleted file mode 100644
index 8ad8a5d..0000000
--- a/ecflow_4_0_7/build/aix_fix/README
+++ /dev/null
@@ -1,118 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-Boost 1.44
-=================================================================================
-force_include.hpp needs to be moved to boost/serialization/force_include.hpp
-This file fixes serialization via base ptr bugs, for Boost version < 1.44
-
-
-Boost 1.45, Serialisation crashes in release mode.
-==================================================================================
-
-FROM IBM:
-We have a Boost patch fix that fixes Serialization library runtime problems experienced at -O3
-
-The symptom's root cause is in singleton pattern of Serialization library that uses static object
-that is created but not referenced.
-A trick in the library code is used to make a reference to this object by passing
-it to a function with empty body to keep it around for static initialization.
-Our optimizer aggressively inlines away the function with empty body, eliminating
-this trick of a reference. This explains why turning off inlining also works.
-Ensuring that we don't inline away this function will keep the static object around.
-
-This is a questionable Boost trick which we will advise either not use, or protect under macros.
-The fix is in your Boost header and no compiler changes are needed.
-
-The changes are in two header files attached:
-boost/serialization/force_include.hpp and
-boost/serialization/singleton.hpp
-
-(See attached file: singleton.hpp)(See attached file: force_include.hpp)
-(See attached file: header_diff_item2.txt)
-
-
-Boost 1.45
-=====================================================================================
-1/boost will will not build cleanly due to a compilation error in v3 filesystem
-the work around is to comment out the v3 file system dependencies.
-in $BOOST_ROOT/libs/filesystem/build/Jamfile.v2
-
->>>>>> OR
-
-Change file path.hpp:
-FROM:
- //------------------------------------------------------------------------------------//
- // class path::iterator //
- //------------------------------------------------------------------------------------//
-
- class path::iterator
- : public boost::iterator_facade<
- iterator,
- path const,
- boost::bidirectional_traversal_tag >
- {
- ....
-TO:
- //------------------------------------------------------------------------------------//
- // class path::iterator //
- //------------------------------------------------------------------------------------//
-
- class path::iterator
- : public boost::iterator_facade<
- path::iterator,
- path const,
- boost::bidirectional_traversal_tag >
- {
- ....
-
-ie. since iterator_facade uses CRTP, the iterator is being interperted as "boost::iterator"
- passing "path::iterator" as the template argument fixes the compile error on AIX.
- This should be safe for other platforms as well
-
- This has been registered as a bug. ticket #4912
-
-2/ Problems running python examples, with boost filesystem linked,
-
-
-Python: Effects all boost versions where we want to embed python interpreter in C++
-=====================================================================================
-The following exe's,on AIX, python 2.5 64 bit, acc v11.1,
-raise *hundreds* of warning messages of the type:
- ld: 0711-224 WARNING: Duplicate symbol: _PyObject_New.
-linking with flags -bloadmap:PARM, reveals:
-
- _Py_NoneStruct Objects/object.c(/usr/local/python64/lib/python2.5/config/libpython2.5.a[object.o])
- ** Duplicate ** /usr/local/python64/lib/python2.5/config/python.exp{.}
-.Py_FatalError Python/pythonrun.c(/usr/local/python64/lib/python2.5/config/libpython2.5.a[pythonrun.o])
- ** Duplicate ** /usr/local/python64/lib/python2.5/config/python.exp{.}
-
-It appears that the symbols are defined libpython2.5.a and in the exports file 'python.exp':
-removing the export file: -Wl,-bI:/usr/local/python64/lib/python2.5/config/python.exp
-from the link line removes the warning messages
-
-This can be done explicitly: $BOOST_ROOT/tools/build/v2/tools/python.jam
-Go to line: 992 and comment out <linkflags>-Wl,-bI:$(libraries[1])/python.exp
-
- else if $(target-os) = aix
- {
- alias python_for_extensions
- :
- : $(target-requirements)
- :
- : $(usage-requirements) # <linkflags>-Wl,-bI:$(libraries[1])/python.exp
- ;
- }
-
-
-This is not an absolute requirement, if you can live with warnings messages.
-The notes in python.jam seems to expect them: file python.jam
-
- # the Python framework, even when building extensions. Note that framework
- # builds of Python always use shared libraries, so we do not need to worry
- # about duplicate Python symbols.
-
\ No newline at end of file
diff --git a/ecflow_4_0_7/build/aix_fix/path.hpp b/ecflow_4_0_7/build/aix_fix/path.hpp
deleted file mode 100644
index d50f184..0000000
--- a/ecflow_4_0_7/build/aix_fix/path.hpp
+++ /dev/null
@@ -1,714 +0,0 @@
-// filesystem path.hpp ---------------------------------------------------------------//
-
-// Copyright Beman Dawes 2002-2005, 2009
-// Copyright Vladimir Prus 2002
-
-// Distributed under the Boost Software License, Version 1.0.
-// See http://www.boost.org/LICENSE_1_0.txt
-
-// Library home page: http://www.boost.org/libs/filesystem
-
-// path::stem(), extension(), and replace_extension() are based on
-// basename(), extension(), and change_extension() from the original
-// filesystem/convenience.hpp header by Vladimir Prus.
-
-#ifndef BOOST_FILESYSTEM_PATH_HPP
-#define BOOST_FILESYSTEM_PATH_HPP
-
-#include <boost/config.hpp>
-
-# if defined( BOOST_NO_STD_WSTRING )
-# error Configuration not supported: Boost.Filesystem V3 and later requires std::wstring support
-# endif
-
-#include <boost/filesystem/v3/config.hpp>
-#include <boost/filesystem/v3/path_traits.hpp> // includes <cwchar>
-#include <boost/system/error_code.hpp>
-#include <boost/system/system_error.hpp>
-#include <boost/iterator/iterator_facade.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/io/detail/quoted_manip.hpp>
-#include <boost/static_assert.hpp>
-#include <string>
-#include <iterator>
-#include <cstring>
-#include <iosfwd>
-#include <stdexcept>
-#include <cassert>
-#include <locale>
-#include <algorithm>
-
-#include <boost/config/abi_prefix.hpp> // must be the last #include
-
-namespace boost
-{
-namespace filesystem3
-{
- //------------------------------------------------------------------------------------//
- // //
- // class path //
- // //
- //------------------------------------------------------------------------------------//
-
- class BOOST_FILESYSTEM_DECL path
- {
- public:
-
- // value_type is the character type used by the operating system API to
- // represent paths.
-
-# ifdef BOOST_WINDOWS_API
- typedef wchar_t value_type;
-# else
- typedef char value_type;
-# endif
- typedef std::basic_string<value_type> string_type;
- typedef std::codecvt<wchar_t, char, std::mbstate_t> codecvt_type;
-
-
- // ----- character encoding conversions -----
-
- // Following the principle of least astonishment, path input arguments
- // passed to or obtained from the operating system via objects of
- // class path behave as if they were directly passed to or
- // obtained from the O/S API, unless conversion is explicitly requested.
- //
- // POSIX specfies that path strings are passed unchanged to and from the
- // API. Note that this is different from the POSIX command line utilities,
- // which convert according to a locale.
- //
- // Thus for POSIX, char strings do not undergo conversion. wchar_t strings
- // are converted to/from char using the path locale or, if a conversion
- // argument is given, using a conversion object modeled on
- // std::wstring_convert.
- //
- // The path locale, which is global to the thread, can be changed by the
- // imbue() function. It is initialized to an implementation defined locale.
- //
- // For Windows, wchar_t strings do not undergo conversion. char strings
- // are converted using the "ANSI" or "OEM" code pages, as determined by
- // the AreFileApisANSI() function, or, if a conversion argument is given,
- // using a conversion object modeled on std::wstring_convert.
- //
- // See m_pathname comments for further important rationale.
-
- // TODO: rules needed for operating systems that use / or .
- // differently, or format directory paths differently from file paths.
- //
- // ************************************************************************
- //
- // More work needed: How to handle an operating system that may have
- // slash characters or dot characters in valid filenames, either because
- // it doesn't follow the POSIX standard, or because it allows MBCS
- // filename encodings that may contain slash or dot characters. For
- // example, ISO/IEC 2022 (JIS) encoding which allows switching to
- // JIS x0208-1983 encoding. A valid filename in this set of encodings is
- // 0x1B 0x24 0x42 [switch to X0208-1983] 0x24 0x2F [U+304F Kiragana letter KU]
- // ^^^^
- // Note that 0x2F is the ASCII slash character
- //
- // ************************************************************************
-
- // Supported source arguments: half-open iterator range, container, c-array,
- // and single pointer to null terminated string.
-
- // All source arguments except pointers to null terminated byte strings support
- // multi-byte character strings which may have embedded nulls. Embedded null
- // support is required for some Asian languages on Windows.
-
- // "const codecvt_type& cvt=codecvt()" default arguments are not used because some
- // compilers, such as Microsoft prior to VC++ 10, do not handle defaults correctly
- // in templates.
-
- // ----- constructors -----
-
- path(){}
-
- path(const path& p) : m_pathname(p.m_pathname) {}
-
- template <class Source>
- path(Source const& source,
- typename boost::enable_if<path_traits::is_pathable<
- typename boost::decay<Source>::type> >::type* =0)
- {
- path_traits::dispatch(source, m_pathname, codecvt());
- }
-
- template <class Source>
- path(Source const& source, const codecvt_type& cvt)
- // see note above explaining why codecvt() default arguments are not used
- {
- path_traits::dispatch(source, m_pathname, cvt);
- }
-
- template <class InputIterator>
- path(InputIterator begin, InputIterator end)
- {
- if (begin != end)
- {
- std::basic_string<typename std::iterator_traits<InputIterator>::value_type>
- s(begin, end);
- path_traits::convert(s.c_str(), s.c_str()+s.size(), m_pathname, codecvt());
- }
- }
-
- template <class InputIterator>
- path(InputIterator begin, InputIterator end, const codecvt_type& cvt)
- {
- if (begin != end)
- {
- std::basic_string<typename std::iterator_traits<InputIterator>::value_type>
- s(begin, end);
- path_traits::convert(s.c_str(), s.c_str()+s.size(), m_pathname, cvt);
- }
- }
-
- // ----- assignments -----
-
- path& operator=(const path& p)
- {
- m_pathname = p.m_pathname;
- return *this;
- }
-
- template <class Source>
- typename boost::enable_if<path_traits::is_pathable<
- typename boost::decay<Source>::type>, path&>::type
- operator=(Source const& source)
- {
- m_pathname.clear();
- path_traits::dispatch(source, m_pathname, codecvt());
- return *this;
- }
-
- template <class Source>
- path& assign(Source const& source, const codecvt_type& cvt)
- {
- m_pathname.clear();
- path_traits::dispatch(source, m_pathname, cvt);
- return *this;
- }
-
- template <class InputIterator>
- path& assign(InputIterator begin, InputIterator end)
- {
- return assign(begin, end, codecvt());
- }
-
- template <class InputIterator>
- path& assign(InputIterator begin, InputIterator end, const codecvt_type& cvt)
- {
- m_pathname.clear();
- if (begin != end)
- {
- std::basic_string<typename std::iterator_traits<InputIterator>::value_type>
- s(begin, end);
- path_traits::convert(s.c_str(), s.c_str()+s.size(), m_pathname, cvt);
- }
- return *this;
- }
-
- // ----- appends -----
-
- // if a separator is added, it is the preferred separator for the platform;
- // slash for POSIX, backslash for Windows
-
- path& operator/=(const path& p);
-
- template <class Source>
- typename boost::enable_if<path_traits::is_pathable<
- typename boost::decay<Source>::type>, path&>::type
- operator/=(Source const& source)
- {
- return append(source, codecvt());
- }
-
- template <class Source>
- path& append(Source const& source, const codecvt_type& cvt);
-
- template <class InputIterator>
- path& append(InputIterator begin, InputIterator end)
- {
- return append(begin, end, codecvt());
- }
-
- template <class InputIterator>
- path& append(InputIterator begin, InputIterator end, const codecvt_type& cvt);
-
- // ----- modifiers -----
-
- void clear() { m_pathname.clear(); }
- path& make_preferred()
-# ifdef BOOST_POSIX_API
- { return *this; } // POSIX no effect
-# else // BOOST_WINDOWS_API
- ; // change slashes to backslashes
-# endif
- path& remove_filename();
- path& replace_extension(const path& new_extension = path());
- void swap(path& rhs) { m_pathname.swap(rhs.m_pathname); }
-
- // ----- observers -----
-
- // For operating systems that format file paths differently than directory
- // paths, return values from observers are formatted as file names unless there
- // is a trailing separator, in which case returns are formatted as directory
- // paths. POSIX and Windows make no such distinction.
-
- // Implementations are permitted to return const values or const references.
-
- // The string or path returned by an observer are specified as being formatted
- // as "native" or "generic".
- //
- // For POSIX, these are all the same format; slashes and backslashes are as input and
- // are not modified.
- //
- // For Windows, native: as input; slashes and backslashes are not modified;
- // this is the format of the internally stored string.
- // generic: backslashes are converted to slashes
-
- // ----- native format observers -----
-
- const string_type& native() const { return m_pathname; } // Throws: nothing
- const value_type* c_str() const { return m_pathname.c_str(); } // Throws: nothing
-
- template <class String>
- String string() const;
-
- template <class String>
- String string(const codecvt_type& cvt) const;
-
-# ifdef BOOST_WINDOWS_API
- const std::string string() const { return string(codecvt()); }
- const std::string string(const codecvt_type& cvt) const
- {
- std::string tmp;
- if (!m_pathname.empty())
- path_traits::convert(&*m_pathname.begin(), &*m_pathname.begin()+m_pathname.size(),
- tmp, cvt);
- return tmp;
- }
-
- // string_type is std::wstring, so there is no conversion
- const std::wstring& wstring() const { return m_pathname; }
- const std::wstring& wstring(const codecvt_type&) const { return m_pathname; }
-
-# else // BOOST_POSIX_API
- // string_type is std::string, so there is no conversion
- const std::string& string() const { return m_pathname; }
- const std::string& string(const codecvt_type&) const { return m_pathname; }
-
- const std::wstring wstring() const { return wstring(codecvt()); }
- const std::wstring wstring(const codecvt_type& cvt) const
- {
- std::wstring tmp;
- if (!m_pathname.empty())
- path_traits::convert(&*m_pathname.begin(), &*m_pathname.begin()+m_pathname.size(),
- tmp, cvt);
- return tmp;
- }
-
-# endif
-
- // ----- generic format observers -----
-
- template <class String>
- String generic_string() const;
-
- template <class String>
- String generic_string(const codecvt_type& cvt) const;
-
-# ifdef BOOST_WINDOWS_API
- const std::string generic_string() const { return generic_string(codecvt()); }
- const std::string generic_string(const codecvt_type& cvt) const;
- const std::wstring generic_wstring() const;
- const std::wstring generic_wstring(const codecvt_type&) const { return generic_wstring(); };
-
-# else // BOOST_POSIX_API
- // On POSIX-like systems, the generic format is the same as the native format
- const std::string& generic_string() const { return m_pathname; }
- const std::string& generic_string(const codecvt_type&) const { return m_pathname; }
- const std::wstring generic_wstring() const { return wstring(codecvt()); }
- const std::wstring generic_wstring(const codecvt_type& cvt) const { return wstring(cvt); }
-
-# endif
-
- // ----- decomposition -----
-
- path root_path() const;
- path root_name() const; // returns 0 or 1 element path
- // even on POSIX, root_name() is non-empty() for network paths
- path root_directory() const; // returns 0 or 1 element path
- path relative_path() const;
- path parent_path() const;
- path filename() const; // returns 0 or 1 element path
- path stem() const; // returns 0 or 1 element path
- path extension() const; // returns 0 or 1 element path
-
- // ----- query -----
-
- bool empty() const { return m_pathname.empty(); } // name consistent with std containers
- bool has_root_path() const { return has_root_directory() || has_root_name(); }
- bool has_root_name() const { return !root_name().empty(); }
- bool has_root_directory() const { return !root_directory().empty(); }
- bool has_relative_path() const { return !relative_path().empty(); }
- bool has_parent_path() const { return !parent_path().empty(); }
- bool has_filename() const { return !m_pathname.empty(); }
- bool has_stem() const { return !stem().empty(); }
- bool has_extension() const { return !extension().empty(); }
- bool is_absolute() const
- {
-# ifdef BOOST_WINDOWS_API
- return has_root_name() && has_root_directory();
-# else
- return has_root_directory();
-# endif
- }
- bool is_relative() const { return !is_absolute(); }
-
- // ----- imbue -----
-
- static std::locale imbue(const std::locale& loc);
-
- // ----- codecvt -----
-
- static const codecvt_type& codecvt()
- {
- return *wchar_t_codecvt_facet();
- }
-
- // ----- iterators -----
-
- class iterator;
- typedef iterator const_iterator;
-
- iterator begin() const;
- iterator end() const;
-
- // ----- deprecated functions -----
-
-# if defined(BOOST_FILESYSTEM_DEPRECATED) && defined(BOOST_FILESYSTEM_NO_DEPRECATED)
-# error both BOOST_FILESYSTEM_DEPRECATED and BOOST_FILESYSTEM_NO_DEPRECATED are defined
-# endif
-
-# if !defined(BOOST_FILESYSTEM_NO_DEPRECATED)
- // recently deprecated functions supplied by default
- path& normalize() { return m_normalize(); }
- path& remove_leaf() { return remove_filename(); }
- path leaf() const { return filename(); }
- path branch_path() const { return parent_path(); }
- bool has_leaf() const { return !m_pathname.empty(); }
- bool has_branch_path() const { return !parent_path().empty(); }
- bool is_complete() const { return is_absolute(); }
-# endif
-
-# if defined(BOOST_FILESYSTEM_DEPRECATED)
- // deprecated functions with enough signature or semantic changes that they are
- // not supplied by default
- const std::string file_string() const { return string(); }
- const std::string directory_string() const { return string(); }
- const std::string native_file_string() const { return string(); }
- const std::string native_directory_string() const { return string(); }
- const string_type external_file_string() const { return native(); }
- const string_type external_directory_string() const { return native(); }
-
- // older functions no longer supported
- //typedef bool (*name_check)(const std::string & name);
- //basic_path(const string_type& str, name_check) { operator/=(str); }
- //basic_path(const typename string_type::value_type* s, name_check)
- // { operator/=(s);}
- //static bool default_name_check_writable() { return false; }
- //static void default_name_check(name_check) {}
- //static name_check default_name_check() { return 0; }
- //basic_path& canonize();
-# endif
-
-//--------------------------------------------------------------------------------------//
-// class path private members //
-//--------------------------------------------------------------------------------------//
-
- private:
-# if defined(_MSC_VER)
-# pragma warning(push) // Save warning settings
-# pragma warning(disable : 4251) // disable warning: class 'std::basic_string<_Elem,_Traits,_Ax>'
-# endif // needs to have dll-interface...
-/*
- m_pathname has the type, encoding, and format required by the native
- operating system. Thus for POSIX and Windows there is no conversion for
- passing m_pathname.c_str() to the O/S API or when obtaining a path from the
- O/S API. POSIX encoding is unspecified other than for dot and slash
- characters; POSIX just treats paths as a sequence of bytes. Windows
- encoding is UCS-2 or UTF-16 depending on the version.
-*/
- string_type m_pathname; // Windows: as input; backslashes NOT converted to slashes,
- // slashes NOT converted to backslashes
-# if defined(_MSC_VER)
-# pragma warning(pop) // restore warning settings.
-# endif
-
- string_type::size_type m_append_separator_if_needed();
- // Returns: If separator is to be appended, m_pathname.size() before append. Otherwise 0.
- // Note: An append is never performed if size()==0, so a returned 0 is unambiguous.
-
- void m_erase_redundant_separator(string_type::size_type sep_pos);
- string_type::size_type m_parent_path_end() const;
- void m_portable();
-
- path& m_normalize();
-
- // Was qualified; como433beta8 reports:
- // warning #427-D: qualified name is not allowed in member declaration
- friend class iterator;
- friend bool operator<(const path& lhs, const path& rhs);
-
- // see path::iterator::increment/decrement comment below
- static void m_path_iterator_increment(path::iterator & it);
- static void m_path_iterator_decrement(path::iterator & it);
-
- static const codecvt_type *& wchar_t_codecvt_facet();
-
- }; // class path
-
-# ifndef BOOST_FILESYSTEM_NO_DEPRECATED
- typedef path wpath;
-# endif
-
- //------------------------------------------------------------------------------------//
- // class path::iterator //
- //------------------------------------------------------------------------------------//
-
- class path::iterator
- : public boost::iterator_facade<
- path::iterator,
- path const,
- boost::bidirectional_traversal_tag >
- {
- private:
- friend class boost::iterator_core_access;
- friend class boost::filesystem3::path;
- friend void m_path_iterator_increment(path::iterator & it);
- friend void m_path_iterator_decrement(path::iterator & it);
-
- const path& dereference() const { return m_element; }
-
- bool equal(const iterator & rhs) const
- {
- return m_path_ptr == rhs.m_path_ptr && m_pos == rhs.m_pos;
- }
-
- // iterator_facade derived classes don't seem to like implementations in
- // separate translation unit dll's, so forward to class path static members
- void increment() { m_path_iterator_increment(*this); }
- void decrement() { m_path_iterator_decrement(*this); }
-
- path m_element; // current element
- const path * m_path_ptr; // path being iterated over
- string_type::size_type m_pos; // position of name in
- // m_path_ptr->m_pathname. The
- // end() iterator is indicated by
- // m_pos == m_path_ptr->m_pathname.size()
- }; // path::iterator
-
- //------------------------------------------------------------------------------------//
- // //
- // non-member functions //
- // //
- //------------------------------------------------------------------------------------//
-
- // std::lexicographical_compare would infinately recurse because path iterators
- // yield paths, so provide a path aware version
- inline bool lexicographical_compare(path::iterator first1, path::iterator last1,
- path::iterator first2, path::iterator last2)
- {
- for (; first1 != last1 && first2 != last2 ; ++first1, ++first2)
- {
- if (first1->native() < first2->native()) return true;
- if (first2->native() < first1->native()) return false;
- }
- return first1 == last1 && first2 != last2;
- }
-
- inline bool operator<(const path& lhs, const path& rhs)
- {
- return lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
- }
-
- inline bool operator<=(const path& lhs, const path& rhs) { return !(rhs < lhs); }
- inline bool operator> (const path& lhs, const path& rhs) { return rhs < lhs; }
- inline bool operator>=(const path& lhs, const path& rhs) { return !(lhs < rhs); }
-
- // equality operators act as if comparing generic format strings, to achieve the
- // effect of lexicographical_compare element by element compare.
- // operator==() efficiency is a concern; a user reported the original version 2
- // !(lhs < rhs) && !(rhs < lhs) implementation caused a serious performance problem
- // for a map of 10,000 paths.
-
-# ifdef BOOST_WINDOWS_API
- inline bool operator==(const path& lhs, const path::value_type* rhs)
- {
- const path::value_type* l(lhs.c_str());
- while ((*l == *rhs || (*l == L'\\' && *rhs == L'/') || (*l == L'/' && *rhs == L'\\'))
- && *l) { ++l; ++rhs; }
- return *l == *rhs || (*l == L'\\' && *rhs == L'/') || (*l == L'/' && *rhs == L'\\');
- }
- inline bool operator==(const path& lhs, const path& rhs) { return lhs == rhs.c_str(); }
- inline bool operator==(const path& lhs, const path::string_type& rhs) { return lhs == rhs.c_str(); }
- inline bool operator==(const path::string_type& lhs, const path& rhs) { return rhs == lhs.c_str(); }
- inline bool operator==(const path::value_type* lhs, const path& rhs) { return rhs == lhs; }
-# else // BOOST_POSIX_API
- inline bool operator==(const path& lhs, const path& rhs) { return lhs.native() == rhs.native(); }
- inline bool operator==(const path& lhs, const path::string_type& rhs) { return lhs.native() == rhs; }
- inline bool operator==(const path& lhs, const path::value_type* rhs) { return lhs.native() == rhs; }
- inline bool operator==(const path::string_type& lhs, const path& rhs) { return lhs == rhs.native(); }
- inline bool operator==(const path::value_type* lhs, const path& rhs) { return lhs == rhs.native(); }
-# endif
-
- inline bool operator!=(const path& lhs, const path& rhs) { return !(lhs == rhs); }
- inline bool operator!=(const path& lhs, const path::string_type& rhs) { return !(lhs == rhs); }
- inline bool operator!=(const path& lhs, const path::value_type* rhs) { return !(lhs == rhs); }
- inline bool operator!=(const path::string_type& lhs, const path& rhs) { return !(lhs == rhs); }
- inline bool operator!=(const path::value_type* lhs, const path& rhs) { return !(lhs == rhs); }
-
- inline void swap(path& lhs, path& rhs) { lhs.swap(rhs); }
-
- inline path operator/(const path& lhs, const path& rhs) { return path(lhs) /= rhs; }
-
- // inserters and extractors
- // use boost::io::quoted() to handle spaces in paths
- // use '&' as escape character to ease use for Windows paths
-
- template <class Char, class Traits>
- inline std::basic_ostream<Char, Traits>&
- operator<<(std::basic_ostream<Char, Traits>& os, const path& p)
- {
- return os
- << boost::io::quoted(p.string<std::basic_string<Char> >(), static_cast<Char>('&'));
- }
-
- template <class Char, class Traits>
- inline std::basic_istream<Char, Traits>&
- operator>>(std::basic_istream<Char, Traits>& is, path& p)
- {
- std::basic_string<Char> str;
- is >> boost::io::quoted(str, static_cast<Char>('&'));
- p = str;
- return is;
- }
-
- // name_checks
-
- // These functions are holdovers from version 1. It isn't clear they have much
- // usefulness, or how to generalize them for later versions.
-
- BOOST_FILESYSTEM_DECL bool portable_posix_name(const std::string & name);
- BOOST_FILESYSTEM_DECL bool windows_name(const std::string & name);
- BOOST_FILESYSTEM_DECL bool portable_name(const std::string & name);
- BOOST_FILESYSTEM_DECL bool portable_directory_name(const std::string & name);
- BOOST_FILESYSTEM_DECL bool portable_file_name(const std::string & name);
- BOOST_FILESYSTEM_DECL bool native(const std::string & name);
-
-//--------------------------------------------------------------------------------------//
-// class path member template implementation //
-//--------------------------------------------------------------------------------------//
-
- template <class InputIterator>
- path& path::append(InputIterator begin, InputIterator end, const codecvt_type& cvt)
- {
- if (begin == end)
- return *this;
- string_type::size_type sep_pos(m_append_separator_if_needed());
- std::basic_string<typename std::iterator_traits<InputIterator>::value_type>
- s(begin, end);
- path_traits::convert(s.c_str(), s.c_str()+s.size(), m_pathname, cvt);
- if (sep_pos)
- m_erase_redundant_separator(sep_pos);
- return *this;
- }
-
- template <class Source>
- path& path::append(Source const & source, const codecvt_type& cvt)
- {
- if (path_traits::empty(source))
- return *this;
- string_type::size_type sep_pos(m_append_separator_if_needed());
- path_traits::dispatch(source, m_pathname, cvt);
- if (sep_pos)
- m_erase_redundant_separator(sep_pos);
- return *this;
- }
-
-//--------------------------------------------------------------------------------------//
-// class path member template specializations //
-//--------------------------------------------------------------------------------------//
-
- template <> inline
- std::string path::string<std::string>() const
- { return string(); }
-
- template <> inline
- std::wstring path::string<std::wstring>() const
- { return wstring(); }
-
- template <> inline
- std::string path::string<std::string>(const codecvt_type& cvt) const
- { return string(cvt); }
-
- template <> inline
- std::wstring path::string<std::wstring>(const codecvt_type& cvt) const
- { return wstring(cvt); }
-
- template <> inline
- std::string path::generic_string<std::string>() const
- { return generic_string(); }
-
- template <> inline
- std::wstring path::generic_string<std::wstring>() const
- { return generic_wstring(); }
-
- template <> inline
- std::string path::generic_string<std::string>(const codecvt_type& cvt) const
- { return generic_string(cvt); }
-
- template <> inline
- std::wstring path::generic_string<std::wstring>(const codecvt_type& cvt) const
- { return generic_wstring(cvt); }
-
-
-} // namespace filesystem3
-} // namespace boost
-
-//----------------------------------------------------------------------------//
-
-namespace boost
-{
- namespace filesystem
- {
- using filesystem3::path;
-# ifndef BOOST_FILESYSTEM_NO_DEPRECATED
- using filesystem3::wpath;
-# endif
- using filesystem3::lexicographical_compare;
- using filesystem3::portable_posix_name;
- using filesystem3::windows_name;
- using filesystem3::portable_name;
- using filesystem3::portable_directory_name;
- using filesystem3::portable_file_name;
- using filesystem3::native;
- using filesystem3::swap;
- using filesystem3::operator<;
- using filesystem3::operator==;
- using filesystem3::operator!=;
- using filesystem3::operator>;
- using filesystem3::operator<=;
- using filesystem3::operator>=;
- using filesystem3::operator/;
- using filesystem3::operator<<;
- using filesystem3::operator>>;
- }
-}
-
-//----------------------------------------------------------------------------//
-
-#include <boost/config/abi_suffix.hpp> // pops abi_prefix.hpp pragmas
-
-#endif // BOOST_FILESYSTEM_PATH_HPP
diff --git a/ecflow_4_0_7/build/boost_1_47_fix.sh b/ecflow_4_0_7/build/boost_1_47_fix.sh
deleted file mode 100644
index d533c6d..0000000
--- a/ecflow_4_0_7/build/boost_1_47_fix.sh
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/bin/sh
-
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-# This file is used paths up version of the boost libs
-# This script Use $BOOST_ROOT and $WK environment variable
-# Assumes boost version 1.47
-
-# Check that a command is in the PATH.
-test_path ()
-{
- if `command -v command 1>/dev/null 2>/dev/null`; then
- command -v $1 1>/dev/null 2>/dev/null
- else
- hash $1 1>/dev/null 2>/dev/null
- fi
-}
-
-test_uname ()
-{
- if test_path uname; then
- test `uname` = $*
- fi
-}
-
-if test_uname Linux ; then
-
- echo "Nothing to fix"
-
-elif test_uname HP-UX ; then
-
- # Hack for utf8_codecvt_facet due to compiler build error on ACC
- cp $WK/build/hpux_fix/utf8_codecvt_facet.cpp $BOOST_ROOT/libs/detail/
-
-elif test_uname AIX ; then
-
- # Fix bug where release version crashes due to bug in Serialization/compiler
- # See file $WK/build/aix_fix/README
- cp $WK/build/aix_fix/singleton.hpp $BOOST_ROOT/boost/serialization/
- cp $WK/build/aix_fix/force_include.hpp $BOOST_ROOT/boost/serialization/
-fi
diff --git a/ecflow_4_0_7/build/boost_1_48_fix.sh b/ecflow_4_0_7/build/boost_1_48_fix.sh
deleted file mode 100644
index 71d6f01..0000000
--- a/ecflow_4_0_7/build/boost_1_48_fix.sh
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/bin/sh
-
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-# This file is used paths up version of the boost libs
-# This script Use $BOOST_ROOT and $WK environment variable
-# Assumes boost version 1.48
-
-# Check that a command is in the PATH.
-test_path ()
-{
- if `command -v command 1>/dev/null 2>/dev/null`; then
- command -v $1 1>/dev/null 2>/dev/null
- else
- hash $1 1>/dev/null 2>/dev/null
- fi
-}
-
-test_uname ()
-{
- if test_path uname; then
- test `uname` = $*
- fi
-}
-
-if test_uname Linux ; then
-
- echo "Nothing to fix"
-
-elif test_uname HP-UX ; then
-
- # Hack for utf8_codecvt_facet due to compiler build error on ACC
- cp $WK/build/hpux_fix/utf8_codecvt_facet.cpp $BOOST_ROOT/libs/detail/
-
- # Hack because boost::int8_t was being interpreted as a char,
- # This cause duplicate class definition during template instantiation.
- # in the file ./boost/numeric/conversion/detail/preprocessed/numeric_cast_traits.hpp
- # See:: https://svn.boost.org/trac/boost/attachment/ticket/6158/cstdint_patch.diff
- cp $WK/build/hpux_fix/cstdint.hpp $BOOST_ROOT/boost/
-
-elif test_uname AIX ; then
-
- # Fix bug where release version crashes due to bug in Serialization/compiler
- # See file $WK/build/aix_fix/README
- cp $WK/build/aix_fix/singleton.hpp $BOOST_ROOT/boost/serialization/
- cp $WK/build/aix_fix/force_include.hpp $BOOST_ROOT/boost/serialization/
-fi
diff --git a/ecflow_4_0_7/build/boost_1_51_fix.sh b/ecflow_4_0_7/build/boost_1_51_fix.sh
deleted file mode 100644
index 5ff2d63..0000000
--- a/ecflow_4_0_7/build/boost_1_51_fix.sh
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/bin/sh
-
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-# This file is used paths up version of the boost libs
-# This script Use $BOOST_ROOT and $WK environment variable
-# Assumes boost version 1.51
-
-# Check that a command is in the PATH.
-test_path ()
-{
- if `command -v command 1>/dev/null 2>/dev/null`; then
- command -v $1 1>/dev/null 2>/dev/null
- else
- hash $1 1>/dev/null 2>/dev/null
- fi
-}
-
-test_uname ()
-{
- if test_path uname; then
- test `uname` = $*
- fi
-}
-
-if test_uname HP-UX ; then
-
- # Hack for utf8_codecvt_facet due to compiler build error on ACC
- cp $WK/build/hpux_fix/boost_1_51_0/utf8_codecvt_facet.ipp $BOOST_ROOT/boost/detail/.
-
-fi
diff --git a/ecflow_4_0_7/build/boost_1_53_fix.sh b/ecflow_4_0_7/build/boost_1_53_fix.sh
deleted file mode 100644
index 93955d5..0000000
--- a/ecflow_4_0_7/build/boost_1_53_fix.sh
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/bin/sh
-
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-# This file is used paths up version of the boost libs
-# This script Use $BOOST_ROOT and $WK environment variable
-# Assumes boost version 1.51
-
-# Check that a command is in the PATH.
-test_path ()
-{
- if `command -v command 1>/dev/null 2>/dev/null`; then
- command -v $1 1>/dev/null 2>/dev/null
- else
- hash $1 1>/dev/null 2>/dev/null
- fi
-}
-
-test_uname ()
-{
- if test_path uname; then
- test `uname` = $*
- fi
-}
-
-if test_uname Linux ; then
-
- echo "Nothing to fix"
-
-elif test_uname HP-UX ; then
-
- # Hack for utf8_codecvt_facet due to compiler build error on ACC
- cp $WK/build/hpux_fix/boost_1_53_0/utf8_codecvt_facet.ipp $BOOST_ROOT/boost/detail/.
-
- # Seems to only affect debug build of ecflow(serialisation) on HP-UX
- # Hack because:
- # more than one instance of overloaded function "throw_exception" matches the argument list
- #
- cp $WK/build/hpux_fix/boost_1_53_0/smart_cast.hpp $BOOST_ROOT/boost/serialization/.
-
-elif test_uname AIX ; then
-
- # Fix bug with thread.cpp libs/thread/src/pthread/thread.cpp
- # See file $WK/build/aix_fix/README
- cp $WK/build/aix_fix/boost_1_53_0/thread.cpp $BOOST_ROOT/libs/thread/src/pthread/
-fi
-
-
\ No newline at end of file
diff --git a/ecflow_4_0_7/build/boost_1_56_fix.sh b/ecflow_4_0_7/build/boost_1_56_fix.sh
deleted file mode 100644
index 8e9ded5..0000000
--- a/ecflow_4_0_7/build/boost_1_56_fix.sh
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/sh
-
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-# This script Use $BOOST_ROOT and $WK environment variable
-# Assumes boost version 1.56
-
-# See: https://svn.boost.org/trac/boost/ticket/10348
-cp $WK/build/fix/boost_1_56_0/shared_ptr_helper.hpp $BOOST_ROOT/boost/serialization/.
diff --git a/ecflow_4_0_7/build/boost_1_57_fix.sh b/ecflow_4_0_7/build/boost_1_57_fix.sh
deleted file mode 100644
index 43d3e77..0000000
--- a/ecflow_4_0_7/build/boost_1_57_fix.sh
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/bin/sh
-
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-# Assumes boost version 1.57
-
-# Fix 1:
-# o https://svn.boost.org/trac/boost/ticket/10749
-#
-# This fix was implemented directly on the boost dir, then the tar recreated
-# modify : shared_ptr_helper.hpp
-# to add
-# #include <boost/serialization/type_info_implementation.hpp>
-
-# Fix 2:
-# o maintain compatibility with boost 1.53 server/archives
-# Modified Boost archive version is specified in: $BOOST_ROOT/libs/serialization/src/basic_archive.cpp
-# From 11 -> 10
-#
-# There has not been any changes to boost that affects, text archives.
-# Testing with old version of the servers, and new clients, do not show any issues.
-#
-
-# Fix 1 notes:
-# In file included from /var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr.hpp:29:0,
-# from Base/src/cts/ClientToServerCmd.hpp:25,
-# from Base/test/TestRequeueNodeCmd.cpp:17:
-#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp: In static member function 'static const boost::serialization::extended_type_info* boost::serialization::shared_ptr_helper<SPT>::non_polymorphic::get_object_type(U&)':
-#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:108:39: error: 'type_info_implementation' in namespace 'boost::serialization' does not name a type
-#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:108:63: error: expected template-argument before '<' token
-#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:108:63: error: expected '>' before '<' token
-#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:109:13: error: template argument 1 is invalid
-#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:109:16: error: expected '(' before 'get_const_instance'
-#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:109:16: error: expected ';' before 'get_const_instance'
-#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:109:35: error: there are no arguments to 'get_const_instance' that depend on a template parameter, so a declaration of 'get_const_instance' must be available
-#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:109:35: note: (if you use '-fpermissive', G++ will accept your code, but allowing the use of an undeclared name is deprecated)
-#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp: In static member function 'static const boost::serialization::extended_type_info* boost::serialization::shared_ptr_helper<SPT>::polymorphic::get_object_type(U&)':
-#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:118:39: error: 'type_info_implementation' in namespace 'boost::serialization' does not name a type
-#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:118:63: error: expected template-argument before '<' token
-#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:118:63: error: expected '>' before '<' token
-#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:119:13: error: template argument 1 is invalid
-#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:119:16: error: expected '(' before 'get_const_instance'
-#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:119:16: error: expected ';' before 'get_const_instance'
-#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:119:35: error: there are no arguments to 'get_const_instance' that depend on a template parameter, so a declaration of 'get_const_instance' must be available
-#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp: In member function 'void boost::serialization::shared_ptr_helper<SPT>::reset(SPT<T>&, T*)':
-#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:131:17: error: 'type_info_implementation' is not a member of 'boost::serialization'
-#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:131:67: error: expected primary-expression before '>' token
-#/var/tmp/ma0/boost/boost_1_57_0/boost/serialization/shared_ptr_helper.hpp:131:70: error: '::type' has not been declared
-#...failed gcc.compile.c++ Base/bin/gcc-4.5/release/test/TestRequeueNodeCmd.o...
\ No newline at end of file
diff --git a/ecflow_4_0_7/build/boost_build.sh b/ecflow_4_0_7/build/boost_build.sh
deleted file mode 100755
index b250732..0000000
--- a/ecflow_4_0_7/build/boost_build.sh
+++ /dev/null
@@ -1,152 +0,0 @@
-#!/bin/sh
-
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-# This file is used build the boost libs used by ecflow
-# This script Use $BOOST_ROOT and $WK environment variable
-echo "WK=$WK"
-echo "BOOST_ROOT=$BOOST_ROOT"
-
-#
-# From boost 1.56 > the location of site-config.jam location has changed
-#
-SITE_CONFIG_LOCATION=$BOOST_ROOT/tools/build/v2/site-config.jam
-BOOST_VERSION="$(basename $BOOST_ROOT)"
-if [[ "$BOOST_VERSION" = boost_1_56_0 || "$BOOST_VERSION" = boost_1_57_0 ]] ; then
- SITE_CONFIG_LOCATION=$BOOST_ROOT/tools/build/src/site-config.jam
-fi
-
-tool=
-
-# Check that a command is in the PATH.
-test_path ()
-{
- if `command -v command 1>/dev/null 2>/dev/null`; then
- command -v $1 1>/dev/null 2>/dev/null
- else
- hash $1 1>/dev/null 2>/dev/null
- fi
-}
-
-test_uname ()
-{
- if test_path uname; then
- test `uname` = $*
- fi
-}
-
-#
-# --layout=system -> libboost_system.a (default)
-# --layout=tagged -> libboost_system-mt-d.a(debug) libboost_system-mt.a(release)
-# --layout=versioned -> libboost_system-xlc-mt-d-1.42(debug) libboost_system-xlc-mt-1_42.a(release)
-#
-# for some reason on cray versioned does not embed the compiler name as a part
-# of the library name. However it it does add the boost version.
-# Hence we will use this to distinguish between the g++ and cray boost libs
-# On *CRAY* we can have 3 compilers we will use the versioned for CRAY and INTEL library
-layout=tagged
-
-CXXFLAGS=
-if test_uname Linux ; then
- tool=gcc
- X64=$(uname -m)
- if [ "$X64" = x86_64 ]
- then
- # PE_ENV is defined in cray environment, at least on sandy bridge
- if [ "$PE_ENV" = GNU -o "$PE_ENV" = INTEL -o "$PE_ENV" = CRAY ]
- then
- CXXFLAGS=cxxflags=-fPIC
- layout=versioned
-
- cp $WK/build/site_config/site-config-cray.jam $SITE_CONFIG_LOCATION
- if [ "$PE_ENV" = INTEL ] ; then
- tool=intel
- fi
- if [ "$PE_ENV" = CRAY ] ; then
- tool=cray
- fi
- else
- cp $WK/build/site_config/site-config-Linux64.jam $SITE_CONFIG_LOCATION
- fi
-
- else
- cp $WK/build/site_config/site-config-Linux.jam $SITE_CONFIG_LOCATION
- fi
-
-elif test_uname HP-UX ; then
-
- tool=acc
- cp $WK/build/site_config/site-config-HPUX.jam $SITE_CONFIG_LOCATION
-
-elif test_uname AIX ; then
-
- # on c1a
- tool=vacpp
- cp $WK/build/site_config/site-config-AIX.jam $SITE_CONFIG_LOCATION
-fi
-
-# Only uncomment for debugging this script
-#rm -rf stage
-#rm -rf tmpBuildDir
-
-#
-# Note: if '--build-dir=./tmpBuildDir' is omitted, boost will build the libs in a directory:
-# bin.v2/
-# On completion , the library is copied to:
-# stage/lib/
-#
-
-# We use tagged as that allows the debug and release builds to built together
-#
-echo "using compiler $tool with build $1 variants "
-# ========================================================================
-# Note: boost thread *ONLY* need to test multi-threaded server See: define ECFLOW_MT
-# ========================================================================
-./bjam --build-dir=./tmpBuildDir toolset=$tool $CXXFLAGS stage link=static --layout=$layout --with-system variant=debug -j2
-./bjam --build-dir=./tmpBuildDir toolset=$tool $CXXFLAGS stage link=static --layout=$layout --with-date_time variant=debug -j2
-./bjam --build-dir=./tmpBuildDir toolset=$tool $CXXFLAGS stage link=static --layout=$layout --with-filesystem variant=debug -j2
-./bjam --build-dir=./tmpBuildDir toolset=$tool $CXXFLAGS stage link=static --layout=$layout --with-program_options variant=debug -j2
-./bjam --build-dir=./tmpBuildDir toolset=$tool $CXXFLAGS stage link=static --layout=$layout --with-serialization variant=debug -j2
-./bjam --build-dir=./tmpBuildDir toolset=$tool $CXXFLAGS stage link=static --layout=$layout --with-test variant=debug -j2
-./bjam --build-dir=./tmpBuildDir toolset=$tool $CXXFLAGS stage link=static --layout=$layout --with-thread variant=debug -j2
-
-
-# ========================================================================
-# Note: boost thread *ONLY* need to test multi-threaded server See: define ECFLOW_MT
-# ========================================================================
-./bjam --build-dir=./tmpBuildDir toolset=$tool $CXXFLAGS stage link=static --layout=$layout --with-system variant=release -j2
-./bjam --build-dir=./tmpBuildDir toolset=$tool $CXXFLAGS stage link=static --layout=$layout --with-date_time variant=release -j2
-./bjam --build-dir=./tmpBuildDir toolset=$tool $CXXFLAGS stage link=static --layout=$layout --with-filesystem variant=release -j2
-./bjam --build-dir=./tmpBuildDir toolset=$tool $CXXFLAGS stage link=static --layout=$layout --with-program_options variant=release -j2
-./bjam --build-dir=./tmpBuildDir toolset=$tool $CXXFLAGS stage link=static --layout=$layout --with-serialization variant=release -j2
-./bjam --build-dir=./tmpBuildDir toolset=$tool $CXXFLAGS stage link=static --layout=$layout --with-test variant=release -j2
-./bjam --build-dir=./tmpBuildDir toolset=$tool $CXXFLAGS stage link=static --layout=$layout --with-thread variant=release -j2
-
-
-# Allow python to be disabled
-if [ -n "$ECF_NO_PYTHON" ] ; then
- echo "****************************************************************************"
- echo "Ignore boost python. ECF_NO_PYTHON set."
- echo "****************************************************************************"
-else
- # ================================================================================
- # Build python
- # ================================================================================
- #*** If the boost python HAS not been built, and we build in $WK/Pyext, then it will build
- #*** boost python in $BOOST_ROOT/bin.v2/
- #*** It appears to build boost python single threaded. (i.e you do not see threading-multi) in the directory path.
- #
- # To prebuild the boost python, hence we need to do the following: For now build both variants, keeps cmake happy! (i.e when finding libs)
- #
- ./bjam toolset=$tool link=shared variant=debug $CXXFLAGS stage --layout=$layout threading=multi --with-python -d2 -j2
- ./bjam toolset=$tool link=shared variant=release $CXXFLAGS stage --layout=$layout threading=multi --with-python -d2 -j2
- ./bjam toolset=$tool link=static variant=debug $CXXFLAGS stage --layout=$layout threading=multi --with-python -d2 -j2
- ./bjam toolset=$tool link=static variant=release $CXXFLAGS stage --layout=$layout threading=multi --with-python -d2 -j2
-fi
-
-
diff --git a/ecflow_4_0_7/build/clean.sh b/ecflow_4_0_7/build/clean.sh
deleted file mode 100644
index 299667d..0000000
--- a/ecflow_4_0_7/build/clean.sh
+++ /dev/null
@@ -1,64 +0,0 @@
-#!/bin/sh
-
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-cd $WK
-
-# Remove the bin directories
-rm -rf ACore/bin
-rm -rf ANattr/bin
-rm -rf ANode/bin
-rm -rf AParser/bin
-rm -rf Base/bin
-rm -rf CSim/bin
-rm -rf Client/bin
-rm -rf Server/bin
-rm -rf Test/bin
-rm -rf Pyext/bin
-rm -rf view/bin
-
-# remove generated files
-rm -rf Doc/online/_build/*
-rm -rf Test/data/ECF_HOME_debug*
-rm -rf Test/data/ECF_HOME_release*
-rm -rf view/data/ECF_HOME_debug*
-rm -rf view/data/ECF_HOME_release*
-rm -rf AParser/test/data/single_defs/mega.def_log
-rm -rf Pyext/test.def
-rm -rf Pyext/build
-rm -rf bin
-rm -rf RemoteSystemsTempFiles
-rm -rf *.dat
-rm -rf *.log
-
-find . -name \*~ -exec rm -rf \*~ {} \; -print
-find . -name \*.mk -exec rm -rf \*.mk {} \; -print
-find . -name \*.so -exec rm -rf \*.so {} \; -print
-find . -name \*.tmp -exec rm -rf \*.tmp {} \; -print
-find . -name \*.job\* -exec rm -rf \*.job\* {} \; -print
-find . -name \*.check -exec rm -rf \*.check {} \; -print
-find . -name \*.flat -exec rm -rf \*.flat {} \; -print
-find . -name \*.depth -exec rm -rf \*.depth {} \; -print
-find . -name \*.out -exec rm -rf \*.out {} \; -print
-find . -name \*.pyc -exec rm -rf \*.pyc {} \; -print
-find . -name t\*.1 -exec rm -rf t\*.1 {} \; -print
-find . -name gmon.out -exec rm -rf gmon.out {} \; -print
-find . -name gnuplot.dat -exec rm -rf gnuplot.dat {} \; -print
-find . -name gnuplot.script -exec rm -rf gnuplot.script {} \; -print
-find . -name ecflow.html -exec rm -rf ecflow.html {} \; -print
-find . -name core -exec rm -rf core {} \; -print
-find . -name `hostname`.*.ecf.* -exec rm -rf `hostname`.*.ecf.* {} \; -print
-find . -name callgrind.out.\* -exec rm -rf callgrind.out.\* {} \; -print
-find . -name massif.out.\* -exec rm -rf massif.out.* {} \; -print
-
-# remove any defs file at the workspace level. There should not be any
-rm -rf *.def
-
-# Remove any lock file create by tests which used EcfPortLock.hpp
-rm -rf *.lock
-
diff --git a/ecflow_4_0_7/build/cray_fix/swap.sh b/ecflow_4_0_7/build/cray_fix/swap.sh
deleted file mode 100644
index 4b8578f..0000000
--- a/ecflow_4_0_7/build/cray_fix/swap.sh
+++ /dev/null
@@ -1,100 +0,0 @@
-#!/bin/ksh
-
-# ==================================================================
-# Setup environment on CRAY, allow switch between cray,intel and gnu
-# ==================================================================
-
-#set -e # stop the shell on first error
-#set -u # fail when using an undefined variable
-#set -x # echo script lines as they are executed
-
-if [[ "$#" != 1 ]] ; then
- echo "Expect one of [ gnu, intel, cray ] "
- exit 1
-else
- if [[ "$1" != cray && "$1" != intel && "$1" != gnu ]] ; then
- echo "Expect one of [ gnu, intel, cray ] "
- exit 1
- fi
-fi
-
-echo "STARTING PE_ENV=$PE_ENV"
-
-# access the module functionality
-. /opt/modules/default/etc/modules.sh
-
-# setup boost
-export BOOST_ROOT=/perm/ma/ma0/boost/boost_1_53_0
-cp $WK/build/site_config/site-config-cray.jam $BOOST_ROOT/tools/build/v2/site-config.jam
-
-if [[ "$1" = cray ]] ; then
- if [[ "$PE_ENV" = INTEL ]] ; then
- module swap PrgEnv-intel PrgEnv-cray
- fi
- if [[ "$PE_ENV" = GNU ]] ; then
- module swap PrgEnv-gnu PrgEnv-cray
- fi
-
- module unload cce
- module load cce/8.3.0.186
- export COMPILER_VERSION=$(echo $CRAY_CC_VERSION | sed 's/\.//' | cut -c1-2)
- export WK=/perm/ma/ma0/workspace/$PE_ENV/ecflow
- export BOOST_ROOT=/perm/ma/ma0/boost/boost_1_55_0
- cp $WK/build/site_config/site-config-cray.jam $BOOST_ROOT/tools/build/v2/site-config.jam
- alias bjam='$BOOST_ROOT/bjam cxxflags=-hPIC toolset=cray'
-
- # module cray-libsci interferes with ecflow linking, hence disable
- module unload cray-libsci
-fi
-
-
-if [[ "$1" = intel ]] ; then
- if [[ "$PE_ENV" = CRAY ]] ; then
- module swap PrgEnv-cray PrgEnv-intel
- fi
- if [[ "$PE_ENV" = GNU ]] ; then
- module swap PrgEnv-gnu PrgEnv-intel
- fi
-
- # for compiler version icc -dumpversion
- export COMPILER_VERSION=$(icc -dumpversion | sed 's/\.//' | cut -c1-3)
- export WK=/perm/ma/ma0/workspace/$PE_ENV/ecflow
- alias bjam='$BOOST_ROOT/bjam cxxflags=-fPIC toolset=intel'
-fi
-
-if [[ "$1" = gnu ]] ; then
- if [[ "$PE_ENV" = CRAY ]] ; then
- module swap PrgEnv-cray PrgEnv-gnu
- fi
- if [[ "$PE_ENV" = INTEL ]] ; then
- module swap PrgEnv-intel PrgEnv-gnu
- fi
-
- # for compiler version gcc -dumpversion
- #module load gcc/4.6.3
-
- export COMPILER_VERSION=$(gcc -dumpversion | sed 's/\.//' | cut -c1-2)
- export WK=/perm/ma/ma0/workspace/$PE_ENV/ecflow
- alias bjam='$BOOST_ROOT/bjam cxxflags=-fPIC toolset=gcc'
-fi
-
-
-# =================================================================================================
-# Determine the release,major,minor numbers for this version
-cd $WK
-release=$(cat VERSION.cmake | grep 'set( ECFLOW_RELEASE' | awk '{print $3}'| sed 's/["]//g')
-major=$(cat VERSION.cmake | grep 'set( ECFLOW_MAJOR' | awk '{print $3}'| sed 's/["]//g')
-minor=$(cat VERSION.cmake | grep 'set( ECFLOW_MINOR' | awk '{print $3}'| sed 's/["]//g')
-ECFLOW_VERSION=$release.$major.$minor
-
-export ECFLOW_INSTALL_DIR=/usr/local/apps/ecflow/$release.$major.$minor
-export ECFLOW_PYTHON_INSTALL_DIR=$ECFLOW_INSTALL_DIR/lib/python/2.7/site-packages/ecflow
-
-
-echo "AFTER SWAP PE_ENV=$PE_ENV"
-echo "WK=$WK"
-echo "BOOST_ROOT=$BOOST_ROOT"
-echo "COMPILER_VERSION=$COMPILER_VERSION"
-echo "ECFLOW_INSTALL_DIR=$ECFLOW_INSTALL_DIR"
-echo "ECFLOW_PYTHON_INSTALL_DIR=$ECFLOW_PYTHON_INSTALL_DIR"
-
diff --git a/ecflow_4_0_7/build/cray_fix/update_cray_swap.sh b/ecflow_4_0_7/build/cray_fix/update_cray_swap.sh
deleted file mode 100755
index 0246478..0000000
--- a/ecflow_4_0_7/build/cray_fix/update_cray_swap.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/ksh
-
-# ==================================================================
-# Setup environment on CRAY, allow switch between cray,intel and gnu
-# ==================================================================
-
-scp $WK/build/cray_fix/swap.sh cca:/home/ma/ma0/.
-
-echo "copied swap.sh to cca:/home/ma/ma0/."
diff --git a/ecflow_4_0_7/build/hpux_fix/README b/ecflow_4_0_7/build/hpux_fix/README
deleted file mode 100644
index df744bc..0000000
--- a/ecflow_4_0_7/build/hpux_fix/README
+++ /dev/null
@@ -1,199 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-Compilation problems with: <boost_root>/boost/detail/utf8_codecvt_facet.ipp ( boost 1.53/1.51)
-was prevously file <boost_root>/libs/detail/utf8_codecvt_facet.cpp ( boost 1.42 --> 1.48)
-==========================================================================
-
-This needs to be fixed to boost versions:
- 1.42:
- 1.43:
- 1.44: (not tested)
- 1.45:
- 1.51
- 1.53
-
-Affects filesystem,program_options,serialisation
-
-Work around is to rewrite "get_cont_octet_out_count_impl"
-ignoring the preprocessor directives (which are window specific anyway)
-(see below). This needs to be done for each release as we dont know
-what else has changed.
-
->>>>>>>>
-For 1.42 can no longer build boost on HP-UX.
-File-system, program-options and serialisation all show a similar
-problem
-
-+ bjam --build-dir=./tmpBuildDir toolset=acc stage link=static --with-filesystem variant=debug
-...patience...
-.......
-acc.compile.c++ tmpBuildDir/boost/bin.v2/libs/filesystem/build/acc/debug/link-static/threading-multi/utf8_codecvt_facet.o
-"./libs/detail/utf8_codecvt_facet.cpp", line 255: error #2014-D: extra text after expected end of preprocessing directive
- #elif WCHAR_MAX > 0x10000
-
-
-
-File: <boost_root>/boost/detail/utf8_codecvt_facet.ipp ( boost 1.53/1.51)
-was prevously file <boost_root>/libs/detail/utf8_codecvt_facet.cpp ( boost 1.42 --> 1.48)
-
-appears to have been changed in boost 1.40
-for the function get_cont_octet_out_count_impl
-
-FROM:
-// note the following code will generate on some platforms where
-// wchar_t is defined as UCS2. The warnings are superfluous as
-// the specialization is never instantitiated with such compilers.
-template<>
-int get_cont_octet_out_count_impl<4>(wchar_t word){
- if (word < 0x80) {
- return 0;
- }
- if (word < 0x800) {
- return 1;
- }
- if (word < 0x10000) {
- return 2;
- }
- if (word < 0x200000) {
- return 3;
- }
- if (word < 0x4000000) {
- return 4;
- }
- return 5;
-}
-
-TO:
-
-template<>
-int get_cont_octet_out_count_impl<4>(wchar_t word){
- if (word < 0x80) {
- return 0;
- }
- if (word < 0x800) {
- return 1;
- }
-
- // Note that the following code will generate warnings on some platforms
- // where wchar_t is defined as UCS2. The warnings are superfluous as the
- // specialization is never instantitiated with such compilers, but this
- // can cause problems if warnings are being treated as errors, so we guard
- // against that. Including <boost/detail/utf8_codecvt_facet.hpp> as we do
- // should be enough to get WCHAR_MAX defined.
-#if !defined(WCHAR_MAX)
-# error WCHAR_MAX not defined!
-#endif
- // cope with VC++ 7.1 or earlier having invalid WCHAR_MAX
-#if defined(_MSC_VER) && _MSC_VER <= 1310 // 7.1 or earlier
- return 2;
-#elif WCHAR_MAX > 0x10000
-
- if (word < 0x10000) {
- return 2;
- }
- if (word < 0x200000) {
- return 3;
- }
- if (word < 0x4000000) {
- return 4;
- }
- return 5;
-
-#else
- return 2;
-#endif
-}
-
-
-
-
-
-acc version 6 compiler problems with /boost/asio/detail/socket_ops.hpp
-==================================================================================================
-**** This is required for all boost version < 1.45
-**** Seem to have been fixed in boost 1.45
-
-1/ The asio /boost/asio/detail/socket_ops.hpp (Line 643)
- make a reference to ::pselect which is not defined on HPUX 11.23
-
- In HP_UX 11.11,11.23 select() was defined in <sys/time.h>
- In HP-UX 11.31 select() was moved to <sys/select.h> and pselect() was introduced in the same file
-
- Hence boost/socket_ops.hpp needs a way of distinguishing OS versions.
- for the moment the work around may be to introduce a define like 011.31 | OS_IS_HPUX11_31
-
- // avi>> added ' && defined(OS_IS_HPUX11_31)'
- #if defined(__hpux) && defined(__HP_aCC) && defined(OS_IS_HPUX11_31)
-
- SO THAT WE CHOOSE select and NOT pselect
-
-2/ additionally in 11.23 there are 2 ::select to choose:
-
- #include <sys/time.h>
-
- int select(int nfds, fd_set *readfds, fd_set *writefds,
- fd_set *errorfds, struct timeval *timeout);
-
- For Backward Compatibility Only: (_XOPEN_SOURCE_EXTENDED not defined)
-
- #include <time.h>
-
- int select(size_t nfds, int *readfds, int *writefds,
- int *exceptds, const struct timeval *timeout);
-
-
- to get round the problem had to compile as:
-
- bjam define=_XOPEN_SOURCE_EXTENDED
-
- to choose the right select
-
-
- Compilation problems with boost 1.48
- ==============================================================
- acc.compile.c++ tmpBuildDir/boost/bin.v2/libs/date_time/build/acc/debug/link-static/threading-multi/gregorian/greg_month.o
-"./boost/numeric/conversion/detail/preprocessed/numeric_cast_traits.hpp", line 25: error #2247: class "boost::numeric::numeric_cast_traits<char, char, void>" has already been defined
- struct numeric_cast_traits
- ^
-
-"./boost/numeric/conversion/detail/preprocessed/numeric_cast_traits.hpp", line 158: error #2247: class "boost::numeric::numeric_cast_traits<char, char, void>" has already been defined
- struct numeric_cast_traits
- ^
-
-"./boost/numeric/conversion/detail/preprocessed/numeric_cast_traits.hpp", line 170: error #2247: class "boost::numeric::numeric_cast_traits<char, char, void>" has already been defined
- struct numeric_cast_traits
- ^
-
-"./boost/numeric/conversion/detail/preprocessed/numeric_cast_traits.hpp", line 182: error #2247: class "boost::numeric::numeric_cast_traits<char, uint8_t, void>" has already been defined
- struct numeric_cast_traits
- ^
-
-"./boost/numeric/conversion/detail/preprocessed/numeric_cast_traits.hpp", line 194: error #2247: class "boost::numeric::numeric_cast_traits<char, int16_t, void>" has already been defined
- struct numeric_cast_traits
-
-
- >>>
- >>> See:: https://svn.boost.org/trac/boost/attachment/ticket/6158/cstdint_patch.diff
- >>>
- *****
- ***** Had to apply the same patch: i.e around line 101 of file $BOOST_ROOT/boost/cstdint.hpp
- *****
- 103c103,107
-2 < using ::int8_t;
-3 ---
-4 > #if defined(sun) || defined(__sun)
-5 > typedef signed char int8_t;
-6 > #else
-7 > using ::int8_t;
-8 > #endif
-
- # Hack because boost::int8_t was being interpreted as a char,
- # This cause duplicate class definition during template instantiation.
- # in the file ./boost/numeric/conversion/detail/preprocessed/numeric_cast_traits.hpp
-
-
diff --git a/ecflow_4_0_7/build/hpux_fix/boost_1_51_0/system_clocks.hpp b/ecflow_4_0_7/build/hpux_fix/boost_1_51_0/system_clocks.hpp
deleted file mode 100644
index 0e70f14..0000000
--- a/ecflow_4_0_7/build/hpux_fix/boost_1_51_0/system_clocks.hpp
+++ /dev/null
@@ -1,234 +0,0 @@
-// boost/chrono/system_clocks.hpp --------------------------------------------------------------//
-
-// Copyright 2008 Howard Hinnant
-// Copyright 2008 Beman Dawes
-// Copyright 2009-2011 Vicente J. Botet Escriba
-
-// Distributed under the Boost Software License, Version 1.0.
-// See http://www.boost.org/LICENSE_1_0.txt
-
-/*
-
-This code was derived by Beman Dawes from Howard Hinnant's time2_demo prototype.
-Many thanks to Howard for making his code available under the Boost license.
-The original code was modified to conform to Boost conventions and to section
-20.9 Time utilities [time] of the C++ committee's working paper N2798.
-See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2798.pdf.
-
-time2_demo contained this comment:
-
- Much thanks to Andrei Alexandrescu,
- Walter Brown,
- Peter Dimov,
- Jeff Garland,
- Terry Golubiewski,
- Daniel Krugler,
- Anthony Williams.
-*/
-
-/*
-
-TODO:
-
- * Fully implement error handling, with test cases.
- * Consider issues raised by Michael Marcin:
-
- > In the past I've seen QueryPerformanceCounter give incorrect results,
- > especially with SpeedStep processors on laptops. This was many years ago and
- > might have been fixed by service packs and drivers.
- >
- > Typically you check the results of QPC against GetTickCount to see if the
- > results are reasonable.
- > http://support.microsoft.com/kb/274323
- >
- > I've also heard of problems with QueryPerformanceCounter in multi-processor
- > systems.
- >
- > I know some people SetThreadAffinityMask to 1 for the current thread call
- > their QueryPerformance* functions then restore SetThreadAffinityMask. This
- > seems horrible to me because it forces your program to jump to another
- > physical processor if it isn't already on cpu0 but they claim it worked well
- > in practice because they called the timing functions infrequently.
- >
- > In the past I have chosen to use timeGetTime with timeBeginPeriod(1) for
- > high resolution timers to avoid these issues.
-
-*/
-
-#ifndef BOOST_CHRONO_SYSTEM_CLOCKS_HPP
-#define BOOST_CHRONO_SYSTEM_CLOCKS_HPP
-
-#include <boost/chrono/config.hpp>
-#include <boost/chrono/duration.hpp>
-#include <boost/chrono/time_point.hpp>
-#include <boost/chrono/detail/system.hpp>
-#include <boost/chrono/clock_string.hpp>
-
-#include <ctime>
-
-// avib
-//# if defined( BOOST_CHRONO_POSIX_API )
-//# if ! defined(CLOCK_REALTIME)
-//# error <time.h> does not supply CLOCK_REALTIME
-//# endif
-//# endif
-
-#ifdef BOOST_CHRONO_WINDOWS_API
-// The system_clock tick is 100 nanoseconds
-# define BOOST_SYSTEM_CLOCK_DURATION boost::chrono::duration<boost::int_least64_t, ratio<BOOST_RATIO_INTMAX_C(1), BOOST_RATIO_INTMAX_C(10000000)> >
-#else
-# define BOOST_SYSTEM_CLOCK_DURATION boost::chrono::nanoseconds
-#endif
-
-// this must occur after all of the includes and before any code appears:
-#ifndef BOOST_CHRONO_HEADER_ONLY
-#include <boost/config/abi_prefix.hpp> // must be the last #include
-#endif
-
-
-//----------------------------------------------------------------------------//
-// //
-// 20.9 Time utilities [time] //
-// synopsis //
-// //
-//----------------------------------------------------------------------------//
-
-namespace boost {
-namespace chrono {
-
- // Clocks
- class BOOST_CHRONO_DECL system_clock;
-#ifdef BOOST_CHRONO_HAS_CLOCK_STEADY
- class BOOST_CHRONO_DECL steady_clock;
-#endif
-
-#ifdef BOOST_CHRONO_HAS_CLOCK_STEADY
- typedef steady_clock high_resolution_clock; // as permitted by [time.clock.hires]
-#else
- typedef system_clock high_resolution_clock; // as permitted by [time.clock.hires]
-#endif
-
-//----------------------------------------------------------------------------//
-// //
-// 20.9.5 Clocks [time.clock] //
-// //
-//----------------------------------------------------------------------------//
-
-// If you're porting, clocks are the system-specific (non-portable) part.
-// You'll need to know how to get the current time and implement that under now().
-// You'll need to know what units (tick period) and representation makes the most
-// sense for your clock and set those accordingly.
-// If you know how to map this clock to time_t (perhaps your clock is std::time, which
-// makes that trivial), then you can fill out system_clock's to_time_t() and from_time_t().
-
-//----------------------------------------------------------------------------//
-// 20.9.5.1 Class system_clock [time.clock.system] //
-//----------------------------------------------------------------------------//
-
- class BOOST_CHRONO_DECL system_clock
- {
- public:
- typedef BOOST_SYSTEM_CLOCK_DURATION duration;
- typedef duration::rep rep;
- typedef duration::period period;
- typedef chrono::time_point<system_clock> time_point;
- BOOST_STATIC_CONSTEXPR bool is_steady = false;
-
- static BOOST_CHRONO_INLINE time_point now() BOOST_NOEXCEPT;
-#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING
- static BOOST_CHRONO_INLINE time_point now(system::error_code & ec);
-#endif
-
- static BOOST_CHRONO_INLINE std::time_t to_time_t(const time_point& t) BOOST_NOEXCEPT;
- static BOOST_CHRONO_INLINE time_point from_time_t(std::time_t t) BOOST_NOEXCEPT;
- };
-
-//----------------------------------------------------------------------------//
-// 20.9.5.2 Class steady_clock [time.clock.steady] //
-//----------------------------------------------------------------------------//
-
-// As permitted by [time.clock.steady]
-// The class steady_clock is conditionally supported.
-
-#ifdef BOOST_CHRONO_HAS_CLOCK_STEADY
- class BOOST_CHRONO_DECL steady_clock
- {
- public:
- typedef nanoseconds duration;
- typedef duration::rep rep;
- typedef duration::period period;
- typedef chrono::time_point<steady_clock> time_point;
- BOOST_STATIC_CONSTEXPR bool is_steady = true;
-
- static BOOST_CHRONO_INLINE time_point now() BOOST_NOEXCEPT;
-#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING
- static BOOST_CHRONO_INLINE time_point now(system::error_code & ec);
-#endif
- };
-#endif
-//----------------------------------------------------------------------------//
-// 20.9.5.3 Class high_resolution_clock [time.clock.hires] //
-//----------------------------------------------------------------------------//
-
-// As permitted, steady_clock or system_clock is a typedef for high_resolution_clock.
-// See synopsis.
-
-
- template<class CharT>
- struct clock_string<system_clock, CharT>
- {
- static std::basic_string<CharT> name()
- {
- static const CharT u[] =
- { 's', 'y', 's', 't', 'e', 'm', '_', 'c', 'l', 'o', 'c', 'k' };
- static const std::basic_string<CharT> str(u, u + sizeof(u)
- / sizeof(u[0]));
- return str;
- }
- static std::basic_string<CharT> since()
- {
- static const CharT
- u[] =
- { ' ', 's', 'i', 'n', 'c', 'e', ' ', 'J', 'a', 'n', ' ', '1', ',', ' ', '1', '9', '7', '0' };
- static const std::basic_string<CharT> str(u, u + sizeof(u)
- / sizeof(u[0]));
- return str;
- }
- };
-
-#ifdef BOOST_CHRONO_HAS_CLOCK_STEADY
-
- template<class CharT>
- struct clock_string<steady_clock, CharT>
- {
- static std::basic_string<CharT> name()
- {
- static const CharT
- u[] =
- { 's', 't', 'e', 'a', 'd', 'y', '_', 'c', 'l', 'o', 'c', 'k' };
- static const std::basic_string<CharT> str(u, u + sizeof(u)
- / sizeof(u[0]));
- return str;
- }
- static std::basic_string<CharT> since()
- {
- const CharT u[] =
- { ' ', 's', 'i', 'n', 'c', 'e', ' ', 'b', 'o', 'o', 't' };
- const std::basic_string<CharT> str(u, u + sizeof(u) / sizeof(u[0]));
- return str;
- }
- };
-
-#endif
-
-} // namespace chrono
-} // namespace boost
-
-#ifndef BOOST_CHRONO_HEADER_ONLY
-// the suffix header occurs after all of our code:
-#include <boost/config/abi_suffix.hpp> // pops abi_prefix.hpp pragmas
-#else
-#include <boost/chrono/detail/inlined/chrono.hpp>
-#endif
-
-#endif // BOOST_CHRONO_SYSTEM_CLOCKS_HPP
diff --git a/ecflow_4_0_7/build/install_ecflow.sh b/ecflow_4_0_7/build/install_ecflow.sh
deleted file mode 100755
index ae7e864..0000000
--- a/ecflow_4_0_7/build/install_ecflow.sh
+++ /dev/null
@@ -1,258 +0,0 @@
-#!/bin/ksh
-
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-## This script will install ecflow dependent on the host
-##
-## Expect an optional argument [ debug | release | test ]
-## - debug : install a debug version of ecflow
-## - release : install a release version of ecflow
-## - test : test install
-##
-## ie install_ecflow.sh debug test
-## Will do a test install for debug build of ecflow
-##
-## Date Changed: 23/05/2011
-
-set -e # stop the shell on first error
-set -u # fail when using an undefined variable
-set -x # echo script lines as they are executed
-
-# ====================================================================
-# Check user is logged in as emos
-user="$(whoami)"
-if [[ $user != "emos" ]] && [[ $user != "map" ]] ; then
- echo "Must be logged in as emos to install ecflow"
- exit 1
-fi
-
-# ====================================================================
-# Maximum of 2 arguments expected:
-# o/ platform
-# o/ input parameter
-if [ "$#" -gt 2 ] ; then
- echo "Install expects maximum of two arguments, i.e"
- echo " test debug"
- echo " test release"
- echo " test"
- echo " debug"
- echo " release"
- exit 1
-fi
-
-mode_arg=
-test_arg=
-while [[ "$#" != 0 ]] ; do
- if [[ "$1" != debug && "$1" != release && "$1" != test ]] ; then
- echo "Install expected [ debug | release | test ] but found $1"
- exit 1
- fi
- if [[ "$1" = debug || "$1" = release ]] ; then
- mode_arg=$1
- else
- test_arg=-n
- fi
- # shift remove last argument
- shift
-done
-
-if [ ${#mode_arg} -eq 0 ] ; then
- echo "Install expects mode i.e. debug or release"
- exit 1
-fi
-
-install_arg=install-all
-
-# ==============================================================================
-# Expect $WK and $BOOST_ROOT to be specified
-# ==============================================================================
-if [ "${WK:-unset}" = "unset" ] ; then
- echo "Install expects environment variable WK work space to be defined"
- exit 1
-fi
-if [ "${BOOST_ROOT:-unset}" = "unset" ] ; then
- echo "Install expects environment variable BOOST_ROOT to be defined"
- exit 1
-fi
-echo "WK = $WK"
-echo "BOOST_ROOT = $BOOST_ROOT"
-
-# ==============================================================================
-# In order to embedd boost_python path in the ecflow extension, we need
-# ECFLOW_INSTALL_DIR to be set correctly, when building the extension
-# Hacky work around since, <dll-path> does not work for a relink at install time.
-# Set install directory for ecflow & embedding of boost python extension
-# ===============================================================================
-cd $WK
-
-# Determine the release,major,minor numbers for this version
-release=$(cat VERSION.cmake | grep 'set( ECFLOW_RELEASE' | awk '{print $3}'| sed 's/["]//g')
-major=$(cat VERSION.cmake | grep 'set( ECFLOW_MAJOR' | awk '{print $3}'| sed 's/["]//g')
-minor=$(cat VERSION.cmake | grep 'set( ECFLOW_MINOR' | awk '{print $3}'| sed 's/["]//g')
-ECFLOW_VERSION=$release.$major.$minor
-
-export ECFLOW_INSTALL_DIR=${ECFLOW_INSTALL_DIR:-/usr/local/apps/ecflow/${release}.${major}.${minor}}
-
-# =============================================================================
-# Required for cray, since we allow multiple compilers
-# =============================================================================
-TOOLSET=
-CXXFLAGS=
-
-# ======================================================================
-# We do NOT install on the LOCAL build machine, since that will not have
-# the correct embedded paths with ecflow.so (i.e for boost python )
-# ======================================================================
-
-BOOST_VERSION=boost_1_53_0
-
-if [[ "$user" = "map" ]] # when user emos is commented out
-then
- ARCH=linux
- export BOOST_ROOT=${BOOST_ROOT:-/vol/ecf/opensuse113/boost/$BOOST_VERSION};
- export WK=${WK:-/vol/ecf/opensuse113/ecflow}
-
-elif [[ "$ARCH" = "Linux" ]] || [[ "$ARCH" = "linux" ]]
-then
- # =====================================================================
- # LINUX
- # =====================================================================
-
- # lxop does not define OS_VERSION ?????, hence default to empty string
- : ${OS_VERSION:=""}
-
- if [[ "$OS_VERSION" = opensuse113 ]] ; then
-
- export BOOST_ROOT=/vol/ecf/opensuse113/boost/$BOOST_VERSION;
- export WK=/vol/ecf/opensuse113/ecflow
-
- elif [[ "$OS_VERSION" = opensuse131 ]] ; then
-
- export BOOST_ROOT=/vol/ecf/opensuse131/boost/$BOOST_VERSION;
- export WK=/vol/ecf/opensuse131/ecflow
-
- elif [[ "$OS_VERSION" = opensuse103 ]] ; then
-
- export BOOST_ROOT=/vol/ecf/opensuse103/boost/$BOOST_VERSION;
- export WK=/vol/ecf/opensuse103/ecflow
-
- elif [[ "$OS_VERSION" = rhel6 ]] ; then
-
- export BOOST_ROOT=/vol/ecf/redhat/boost/$BOOST_VERSION;
- export WK=/vol/ecf/redhat/ecflow
-
- elif [[ "$OS_VERSION" = sles11 ]] ; then
-
- # lxab this is still opensuse113
- export BOOST_ROOT=/vol/ecf/cluster/boost/$BOOST_VERSION;
- export WK=/vol/ecf/cluster/ecflow
- case "$HOST" in
- lxc*)
- export BOOST_ROOT=/vol/ecf/lxc/boost/$BOOST_VERSION;
- export WK=/vol/ecf/lxc/ecflow
- ;;
- esac
-
- elif [[ "$OS_VERSION" = "" ]] ; then
-
- # lxop does not define OS_VERSION ?????
- export BOOST_ROOT=/gpfs/lxop/build/builds/boost/$BOOST_VERSION;
- export WK=/gpfs/lxop/build/builds/ecflow
- fi
-
-elif [[ "$ARCH" = cray ]] ; then
-
- TOOLSET=toolset=gcc
- CXXFLAGS=cxxflags=-fPIC
- if [[ "$PE_ENV" = CRAY ]] ; then
- echo "The PE_ENV=CRAY, For ecflow we only support install with PE_ENV=GNU"
- exit 1
- fi
- if [[ "$PE_ENV" = INTEL ]] ; then
- echo "The PE_ENV=INTEL, For ecflow we only support install with PE_ENV=GNU"
- exit 1
- fi
-
- export WK=/perm/ma/ma0/workspace/$PE_ENV/ecflow
- export BOOST_ROOT=/perm/ma/ma0/boost/$BOOST_VERSION
-fi
-
-# =======================================================================================
-# Python
-# ========================================================================================
-export ECFLOW_PYTHON_INSTALL_DIR=$ECFLOW_INSTALL_DIR/lib/python2.7/site-packages/ecflow
-
-
-# ============================================================================
-# INSTALL
-# ============================================================================
-$BOOST_ROOT/bjam $TOOLSET $CXXFLAGS -d2 variant=$mode_arg $test_arg $install_arg
-
-
-#==========================================================================
-echo "...make sure executables have execute permissions for group and others"
-# ============================================================================
-if [[ "$test_arg" = "" ]] ; then
- cd $ECFLOW_INSTALL_DIR/bin
- chmod 755 *
-
- cd $ECFLOW_PYTHON_INSTALL_DIR
- chmod 755 *
-
- #==========================================================================
- echo "...sanity test, make sure exe's exist in the bin directory"
- # ============================================================================
- if [[ ! -r ecflow_client ]] ; then
- echo "ecflow_client not installed !!!!!"
- fi
- if [[ ! -r ecflow_server ]] ; then
- echo "ecflow_server not installed !!!!!"
- fi
- if [[ ! -r ecflowview ]] ; then
- echo "ecflowview not installed !!!!!"
- fi
-fi
-
-# ============================================================================
-# Copy over release from ccb -> cca, or cca ->ccb, depending on the machine
-# *Make* sure destination has a trailing '/.' otherwise you can end up renaming.
-# ============================================================================
-if [[ "$ARCH" = cray ]] ; then
-
- if [[ "$test_arg" = "" ]] ; then
- cd /usr/local/apps/ecflow
-
- if [[ "$EC_CLUSTER" = ccb ]] ; then
-
- scp -r $ECFLOW_VERSION emos at cca:/usr/local/apps/ecflow/.
-
- elif [[ "$EC_CLUSTER" = cca ]] ; then
-
- scp -r $ECFLOW_VERSION emos at ccb:/usr/local/apps/ecflow/.
-
- fi
- fi
-fi
-
-
-# ============================================================================
-# Copy over release from ecgb(redhat) -> sappa and sappb
-# *Make* sure destination has a trailing '/.' otherwise you can end up renaming.
-# ============================================================================
-if [[ "$ARCH" = "Linux" ]] || [[ "$ARCH" = "linux" ]]
-then
- if [ "$OS_VERSION" = rhel6 ] ; then
-
- if [[ "$test_arg" = "" ]] ; then
- # sappa/sappb(rhel63) are same as ecgb/redhat(rhel6)
- cd /usr/local/apps/ecflow
- scp -r $ECFLOW_VERSION emos at sappa:/usr/local/apps/ecflow/.
- scp -r $ECFLOW_VERSION emos at sappb:/usr/local/apps/ecflow/.
- fi
- fi
-fi
\ No newline at end of file
diff --git a/ecflow_4_0_7/build/kill_ecf.sh b/ecflow_4_0_7/build/kill_ecf.sh
deleted file mode 100755
index 52bdd17..0000000
--- a/ecflow_4_0_7/build/kill_ecf.sh
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/bin/sh
-
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-# kill any running test
-ps -ef | grep ma0 | grep gcc | grep log_level=message | cut -c9-14 | xargs kill -9
-ps -ef | grep ma0 | grep test.sh | cut -c9-14 | xargs kill -9
-
-# kill any existing test based server
-ps -ef | grep ma0 | grep ecfinterval | grep ecflow_server | cut -c9-14 | xargs kill -9
-ps -ef | grep ma0 | grep dis_job_gen | grep ecflow_server | cut -c9-14 | xargs kill -9
-ps -ef | grep ma0 | grep ecbuild | grep debug | grep ecflow_server | cut -c9-14 | xargs kill -9
-ps -ef | grep ma0 | grep gcc | grep ecflow_server | cut -c9-14 | xargs kill -9
-ps -ef | grep ma0 | grep gcc | grep ecflow_client | cut -c9-14 | xargs kill -9
-
-ps -ef | grep ma0 | grep clientRoot | grep ecbuild | grep debug | cut -c9-14 | xargs kill -9
-ps -ef | grep ma0 | grep clientRoot | grep ecbuild | grep release | cut -c9-14 | xargs kill -9
-
-# kill any jobs
-ps -ef | grep ma0 | grep job | grep test | cut -c9-14 | xargs kill -9
-
diff --git a/ecflow_4_0_7/build/massif.sh b/ecflow_4_0_7/build/massif.sh
deleted file mode 100755
index d5bc484..0000000
--- a/ecflow_4_0_7/build/massif.sh
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/bin/sh
-
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-cd $WK
-
-# if argument is release test the release version else stick with debug
-mode=debug
-if test "$1" = release
-then
- mode=release
-fi
-
-
-compiler=gcc-$(gcc -dumpversion)
-echo "valgrind: variant=$mode compiler=$compiler"
-
-valgrind --tool=massif ACore/bin/$compiler/$mode/u_acore
-valgrind --tool=massif ANattr/bin/$compiler/$mode/u_anattr
-valgrind --tool=massif ANode/bin/$compiler/$mode/u_anode
-valgrind --tool=massif AParser/bin/$compiler/$mode/u_aparser
-valgrind --tool=massif Base/bin/$compiler/$mode/u_base
-valgrind --tool=massif Client/bin/$compiler/$mode/s_client
-valgrind --tool=massif Server/bin/$compiler/$mode/u_server
-valgrind --tool=massif Test/bin/$compiler/$mode/s_test
-valgrind --tool=massif Simulator/bin/$compiler/$mode/c_csim
-#valgrind --tool=massif AParser/bin/$compiler/$mode/perf_aparser
-
diff --git a/ecflow_4_0_7/build/migrate.sh b/ecflow_4_0_7/build/migrate.sh
deleted file mode 100644
index 4daf15b..0000000
--- a/ecflow_4_0_7/build/migrate.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-prepare_migration() {
- use ecflow
- while read nick host port
- do
- LOG="--host $host --port $port"
- ecflow_client $LOG --ping || continue
- version=$(ecflow_client $LOG --server_version)
- echo $nick $host $port $version
- /usr/local/apps/ecflow/$version/bin/ecflow_client $LOG --migrate > $host.$port.mig
- done < /usr/local/apps/ecflow/current/lib/servers
-}
-
-prepare_migration
diff --git a/ecflow_4_0_7/build/p4_sync.sh b/ecflow_4_0_7/build/p4_sync.sh
deleted file mode 100755
index 640ae4d..0000000
--- a/ecflow_4_0_7/build/p4_sync.sh
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/bin/sh
-
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-# Sync up before export/build
-
-set -e # stop the shell on first error
-set -u # fail when using an undefined variable
-
-
-# P4 login
-cd $HOME
-rm -rf .p4tickets
-p4login
-
-
-# setup for perforce server
-cd $WK
-export P4CLIENT=clientWS
-export P4PORT=p4od:14001
-
-p4 sync
diff --git a/ecflow_4_0_7/build/rmbin.sh b/ecflow_4_0_7/build/rmbin.sh
deleted file mode 100755
index cef5b9d..0000000
--- a/ecflow_4_0_7/build/rmbin.sh
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/sh
-
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-cd $WK
-
-rm -rf ACore/bin
-rm -rf ANattr/bin
-rm -rf ANode/bin
-rm -rf AParser/bin
-rm -rf Base/bin
-rm -rf CSim/bin
-rm -rf Client/bin
-rm -rf Server/bin
-rm -rf Test/bin
-rm -rf Pyext/bin
-rm -rf view/bin
-
diff --git a/ecflow_4_0_7/build/site_config/site-config-AIX.jam b/ecflow_4_0_7/build/site_config/site-config-AIX.jam
deleted file mode 100644
index 4110b13..0000000
--- a/ecflow_4_0_7/build/site_config/site-config-AIX.jam
+++ /dev/null
@@ -1,108 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-#
-# site-config.jam for AIX v11.1 compiler
-# This file should be place in $HOME or $BOOST_ROOT/tools/build/v2/
-#-----------------------------------------------------------------
-
-import os ;
-local BOOST_ROOT = [ os.environ BOOST_ROOT ] ;
-
-# ========================= referenced libs =========================================
-
-# Boost libraries referenced in client/server programs.
-# Assumes --layout=tagged
-#
-lib boost_serialization : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt-d.a ;
-lib boost_system : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt-d.a ;
-lib boost_thread : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt-d.a ;
-lib boost_test : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt-d.a ;
-lib boost_test_monitor : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt-d.a ;
-lib boost_program_options : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt-d.a ;
-lib boost_filesystem : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt-d.a ;
-lib boost_datetime : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt-d.a ;
-lib boost_python : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-d.so ;
-lib boost_python_static : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-d.a ;
-
-# profile uses release libs
-lib boost_serialization : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt.a ;
-lib boost_system : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt.a ;
-lib boost_thread : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt.a ;
-lib boost_test : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt.a ;
-lib boost_test_monitor : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt.a ;
-lib boost_program_options : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt.a ;
-lib boost_filesystem : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt.a ;
-lib boost_datetime : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt.a ;
-lib boost_python : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.so ;
-lib boost_python_static : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.a ;
-
-lib boost_serialization : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt.a ;
-lib boost_system : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt.a ;
-lib boost_thread : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt.a ;
-lib boost_test : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt.a ;
-lib boost_test_monitor : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt.a ;
-lib boost_program_options : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt.a ;
-lib boost_filesystem : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt.a ;
-lib boost_datetime : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt.a ;
-lib boost_python : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.so ;
-lib boost_python_static : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.a ;
-
-
-#======================= project site-config ================================
-
-# -bbigtoc:
-# we get TOC overflow, because compiler/linker has 64k limit on
-# the number of global symbols. Options are use:
-# 0/ Break up shared lib
-# 1/ -bbigtoc to overcome at the cost of performance degradation
-# 2/ --qipa=level=0 if this fails try
-# 3/ --qipa=level=1 if this fails try
-# 4/ --qipa=level=2 if this fails, revert to -bbigtoc
-# Currently option 2-4 didn't work!
-
-# <threading>multi
-# Note: in order to use xlC_r compiler, you have to use either
-# "bjam threading=multi" OR
-# add
-# requirements <threading>multi
-# as below.
-#
-
-# <cxxflags>-qsuppress=1500-029
-# In release mode we get hundreds of 1500-029 warning message, ie failure to inline
-# hence decided to supress this.
-#
-# Suppress 1540-2883 (W) Inline function "<funtion>" given attribute noinline.
-# This was the fix for release mode of the compiler & fixed the serialisation crash
-# Unfortunately it generates hundreds of warnings for each type seralized in each header file
-# "/s1a/emos_esuite/emos_data/sms/boost/boost_1_45_0/boost/serialization/singleton.hpp", line 126.17: 1540-2883 (W) Inline function "void use(const void_caster_primitive<Alias,Submittable> &)" given attribute noinline.
-# "/s1a/emos_esuite/emos_data/sms/boost/boost_1_45_0/boost/serialization/singleton.hpp", line 126.17: 1540-2883 (W) Inline function "void use(const iserializer<boost::archive::text_iarchive,PartExpression> &)" given attribute noinline.
-
-project site-config
- : requirements <include>$(BOOST_ROOT)
- : requirements <threading>multi
- : requirements <cxxflags>-qsuppress=1540-0198 # (W) The omitted keyword "private" is assumed for base class
- : requirements <cxxflags>-qsuppress=1540-2883 # (W) Inline function "<function>" given attribute noinline.
- : requirements <variant>release:<cxxflags>-qsuppress=1500-029 # supress could not be inlined message
- : requirements <linkflags>-bbigtoc
- ;
-
-# using syntax:
-# using toolset-name : version :invocation-command : options ;
-# where options allows <cflags, cxxflags, compileflags and linkflags >
-#
-using vacpp ;
-using testing ;
-
-# ================================================================================
-# Link with FDB (PRODGEN)
-
-lib libfdb
- :
- : <file>/usr/local/lib/libfdb.a
- ;
\ No newline at end of file
diff --git a/ecflow_4_0_7/build/site_config/site-config-HPUX.jam b/ecflow_4_0_7/build/site_config/site-config-HPUX.jam
deleted file mode 100644
index 4635fa2..0000000
--- a/ecflow_4_0_7/build/site_config/site-config-HPUX.jam
+++ /dev/null
@@ -1,113 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-#
-# This file should be changed depending on the new system
-# no other files should need changing
-# This file should be place in $HOME or $BOOST_ROOT/tools/build/v2/
-#-----------------------------------------------------------------
-
-import os ;
-local BOOST_ROOT = [ os.environ BOOST_ROOT ] ;
-
-#
-# Boost libraries referenced in client/server programs
-#
-lib boost_serialization : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt-d.a ;
-lib boost_system : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt-d.a ;
-lib boost_thread : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt-d.a ;
-lib boost_test : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt-d.a ;
-lib boost_test_monitor : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt-d.a ;
-lib boost_program_options : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt-d.a ;
-lib boost_filesystem : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt-d.a ;
-lib boost_datetime : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt-d.a ;
-lib boost_python : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-d.so ;
-lib boost_python_static : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-d.a ;
-
-lib boost_serialization : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt.a ;
-lib boost_system : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt.a ;
-lib boost_thread : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt.a ;
-lib boost_test : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt.a ;
-lib boost_test_monitor : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt.a ;
-lib boost_program_options : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt.a ;
-lib boost_filesystem : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt.a ;
-lib boost_datetime : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt.a ;
-lib boost_python : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.so ;
-lib boost_python_static : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.a ;
-
-# Lib for run time checks, use for debug builds only
-lib rtc : : <variant>debug <file>/opt/langtools/lib/hpux32/librtc.so ;
-
-
-# project wide settings. Please disable requirements <variant>debug:<linkflags>+check=all
-# for release build.
-# Note: _XOPEN_SOURCE_EXTENDED is only needed for Client/Server categories
-# assuming its no harm to define everywhere
-#
-# Boost CHRONO does not work properly with HPUX compiler( boost version 1.51 )
-# hence use of BOOST_THREAD_DONT_USE_CHRONO, See http://www.boost.org/doc/libs/1_51_0/doc/html/thread/build.html
-# Even with this boost thread/chrono does not compile. Kept in case fixed in the future
-#
-project site-config
- : requirements <include>$(BOOST_ROOT)
- : requirements <threading>multi
- : requirements <define>HPUX
- : requirements <define>_XOPEN_SOURCE_EXTENDED
- : requirements <define>BOOST_THREAD_DONT_USE_CHRONO
-# : requirements <library>rtc
-# : requirements <variant>debug:<linkflags>+check=all
- ;
-
-
-# STATIC: Additional Lint type checks.Will drastically slow down compiles, hence optional
-#
-# use <compileflags>+w for additional lint style checking
-# Suppress the most prevalent boost warnings, this allows us to see lint
-# checks in our own code
-#
-# suppress - warning #2261-D: controlling expression is constant
-# - warning #2236-D: controlling expression is constant
-# - remark #4296-D: arithmetic operation on boolean type
-# - remark #2401-D: destructor for base class is not virtual
-# - remark #2340-D: value copied to temporary, reference to temporary use
-# - remark #4255-D: padding size of struct "d1" with 3 bytes to alignment boundary>]" at line 62
-# - remark #4227-D: padding struct with 3 bytes to align member "old_mask_"
-# - remark #2193-D: zero used for undefined preprocessing identifier "__GNUC__"
-# - remark #2324-D: duplicate friend declaration
-# - remark #4285-D: operator= does not have a check for the source and destination addresses being non-identical
-#
-# RUNTIME: Will drastically slow run runs, but will give very useful information, hence optional
-#
-# enable +check=all, to enable all runtime checks:
-# +check=bounds
-# +check=malloc
-# +check=stack:variables
-# +check=uninit -z
-#using acc : : : <compileflags>+w
-# <compileflags>+W2236,2461,2261,2236,4296,2401,2340,4255,4227,2193,2324,4285
-# <compileflags>+check=all
-# ;
-
-
-#
-# suppress - warning #2236-D: controlling expression is constant
-# warning #2461-D: initial value of reference to non-const must be an lvalue
-# warning #2191-D: type qualifier is meaningless on cast type
-# warning #2815-D: type qualifier on return type is meaningless
-# warning #4232-D: conversion from "boost::python::converter::rvalue_from_python_stage1_data *" to a more strictly aligned type "boost::python::converter::rvalue_from_python_storage<boost::shared_ptr<CtsApi>> *" may cause misaligned access
-# warning #4189-D: warning #4189-D: a non-POD class type used in offsetof macro BOOST_STATIC_ASSERT(BOOST_PYTHON_OFFSETOF(rvalue_from_python_storage<T>,stage1) == 0);
-#
-# using syntax:
-# using toolset-name : version : invocation-command : options ;
-# where options allows <cflags, cxxflags, compileflags and linkflags >
-#
-using acc : : : <compileflags>+W2236,2461,2191,2815,4232,4189
- ;
-
-using testing ;
-
-# - If you change python version ,remember to change: $WK/build/install_ecflow.sh: ECFLOW_PYTHON_INSTALL_DIR
diff --git a/ecflow_4_0_7/build/site_config/site-config-Linux.jam b/ecflow_4_0_7/build/site_config/site-config-Linux.jam
deleted file mode 100644
index fe8c23b..0000000
--- a/ecflow_4_0_7/build/site_config/site-config-Linux.jam
+++ /dev/null
@@ -1,91 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-# ===================================================================
-# site-config.jam file for Linux/gcc
-# This file should be placed in $HOME or $BOOST_ROOT/tools/build/v2/
-# ===================================================================
-
-#
-# Pull in environment variables
-#
-import os ;
-local BOOST_ROOT = [ os.environ BOOST_ROOT ] ;
-
-#
-# --layout=system -> libboost_system.a (default)
-# --layout=tagged -> libboost_system-mt-d.a(debug) libboost_system-mt.a(release)
-# --layout=versioned -> libboost_system-xlc-mt-d-1.42(debug) libboost_system-xlc-mt-1_42.a(release)
-#
-# Boost libraries referenced in client/server programs
-# assumes --layout=tagged for the debug release and profile variant
-#
-lib boost_serialization : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt-d.a ;
-lib boost_system : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt-d.a ;
-lib boost_thread : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt-d.a ;
-lib boost_test : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt-d.a ;
-lib boost_test_monitor : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt-d.a ;
-lib boost_program_options : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt-d.a ;
-lib boost_filesystem : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt-d.a ;
-lib boost_datetime : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt-d.a ;
-lib boost_python : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-d.so ;
-lib boost_python_static : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-d.a ;
-
-# profile uses release libs
-lib boost_serialization : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt.a ;
-lib boost_system : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt.a ;
-lib boost_thread : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt.a ;
-lib boost_test : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt.a ;
-lib boost_test_monitor : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt.a ;
-lib boost_program_options : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt.a ;
-lib boost_filesystem : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt.a ;
-lib boost_datetime : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt.a ;
-lib boost_python : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.so ;
-lib boost_python_static : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.a ;
-
-lib boost_serialization : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt.a ;
-lib boost_system : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt.a ;
-lib boost_thread : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt.a ;
-lib boost_test : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt.a ;
-lib boost_test_monitor : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt.a ;
-lib boost_program_options : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt.a ;
-lib boost_filesystem : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt.a ;
-lib boost_datetime : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt.a ;
-lib boost_python : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.so ;
-lib boost_python_static : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.a ;
-
-#
-# Notice: we don't add requirements <library>pthread , because
-# a/ Not all tests require it
-# b/ Can cause links errors
-# Hence left to individual projects/test
-#
-project site-config
- : requirements <include>$(BOOST_ROOT)
- ;
-
-# using syntax:
-# using toolset-name : version : invocation-command : options ;
-# where options allows <cflags, cxxflags, compileflags and linkflags >
-#
-using gcc ;
-using testing ;
-
-# ==================== ECFLOWVIEW =======================================================
-
-local motif_library = [ os.environ MOTIF_LIBRARY ] ;
-motif_library default = "/usr/lib64" ;
-constant MOTIF_LIBRARY : $(motif_library) ;
-
-MOTIF_LIBRARY default = /usr/lib ;
-
-# ================================================================================
-# Link with FDB, (PRODGEN)
-lib libfdb
- :
- : <file>/usr/local/lib/metaps/lib/libfdb.a
- ;
diff --git a/ecflow_4_0_7/build/site_config/site-config-Linux64-clang.jam b/ecflow_4_0_7/build/site_config/site-config-Linux64-clang.jam
deleted file mode 100644
index 053d452..0000000
--- a/ecflow_4_0_7/build/site_config/site-config-Linux64-clang.jam
+++ /dev/null
@@ -1,91 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-# ===================================================================
-# This file should be placed in $HOME or $BOOST_ROOT/tools/build/v2/
-# ===================================================================
-
-#
-# Pull in environment variables
-#
-import os ;
-local BOOST_ROOT = [ os.environ BOOST_ROOT ] ;
-
-#
-# --layout=system -> libboost_system.a (default)
-# --layout=tagged -> libboost_system-mt-d.a(debug) libboost_system-mt.a(release)
-# --layout=versioned -> libboost_system-xlc-mt-d-1.42(debug) libboost_system-xlc-mt-1_42.a(release)
-#
-# Boost libraries referenced in client/server programs
-# assumes --layout=tagged for the debug release and profile variant
-#
-lib boost_serialization : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt-d.a ;
-lib boost_system : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt-d.a ;
-lib boost_thread : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt-d.a ;
-lib boost_test : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt-d.a ;
-lib boost_test_monitor : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt-d.a ;
-lib boost_program_options : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt-d.a ;
-lib boost_filesystem : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt-d.a ;
-lib boost_datetime : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt-d.a ;
-lib boost_python : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-d.so ;
-lib boost_python_static : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-d.a ;
-
-# profile uses release libs
-lib boost_serialization : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt.a ;
-lib boost_system : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt.a ;
-lib boost_thread : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt.a ;
-lib boost_test : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt.a ;
-lib boost_test_monitor : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt.a ;
-lib boost_program_options : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt.a ;
-lib boost_filesystem : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt.a ;
-lib boost_datetime : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt.a ;
-lib boost_python : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.so ;
-lib boost_python_static : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.a ;
-
-lib boost_serialization : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt.a ;
-lib boost_system : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt.a ;
-lib boost_thread : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt.a ;
-lib boost_test : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt.a ;
-lib boost_test_monitor : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt.a ;
-lib boost_program_options : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt.a ;
-lib boost_filesystem : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt.a ;
-lib boost_datetime : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt.a ;
-lib boost_python : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.so ;
-lib boost_python_static : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.a ;
-
-#
-# Notice: we don't add requirements <library>pthread , because
-# a/ Not all tests require it
-# b/ Can cause links errors
-# Hence left to individual projects/test
-#
-project site-config
- : requirements <include>$(BOOST_ROOT)
- ;
-
-# using syntax:
-# using toolset-name : version :invocation-command : options ;
-# where options allows <cflags, cxxflags, compileflags and linkflags >
-#
-# On linux 64, because most of the static library's, are placed in a shared libs(ecflow.so)
-# hence we need to compile with -fPIC
-using clang : : /usr/local/apps/clang/current/bin/clang++ : <cxxflags>-fPIC ;
-
-using testing ;
-
-# ==================== ECFLOWVIEW/install =======================================================
-
-local motif_library = [ os.environ MOTIF_LIBRARY ] ;
-motif_library default = "/usr/lib64" ;
-constant MOTIF_LIBRARY : $(motif_library) ;
-
-# ================================================================================
-# Link with FDB, (PRODGEN)
-lib libfdb
- :
- : <file>/usr/local/lib/metaps/lib/libfdb.a
- ;
diff --git a/ecflow_4_0_7/build/site_config/site-config-Linux64-intel.jam b/ecflow_4_0_7/build/site_config/site-config-Linux64-intel.jam
deleted file mode 100644
index 9e330d3..0000000
--- a/ecflow_4_0_7/build/site_config/site-config-Linux64-intel.jam
+++ /dev/null
@@ -1,98 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-# ===================================================================
-# This file should be placed in $HOME or $BOOST_ROOT/tools/build/v2/
-# ===================================================================
-
-#
-# Pull in environment variables
-#
-import os ;
-local BOOST_ROOT = [ os.environ BOOST_ROOT ] ;
-
-#
-# --layout=system -> libboost_system.a (default)
-# --layout=tagged -> libboost_system-mt-d.a(debug) libboost_system-mt.a(release)
-# --layout=versioned -> libboost_system-xlc-mt-d-1.42(debug) libboost_system-xlc-mt-1_42.a(release)
-#
-# Boost libraries referenced in client/server programs
-# assumes --layout=tagged for the debug release and profile variant
-#
-lib boost_serialization : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt-d.a ;
-lib boost_system : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt-d.a ;
-lib boost_thread : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt-d.a ;
-lib boost_test : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt-d.a ;
-lib boost_test_monitor : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt-d.a ;
-lib boost_program_options : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt-d.a ;
-lib boost_filesystem : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt-d.a ;
-lib boost_datetime : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt-d.a ;
-lib boost_python : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-d.so ;
-lib boost_python_static : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-d.a ;
-
-# profile uses release libs
-lib boost_serialization : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt.a ;
-lib boost_system : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt.a ;
-lib boost_thread : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt.a ;
-lib boost_test : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt.a ;
-lib boost_test_monitor : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt.a ;
-lib boost_program_options : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt.a ;
-lib boost_filesystem : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt.a ;
-lib boost_datetime : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt.a ;
-lib boost_python : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.so ;
-lib boost_python_static : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.a ;
-
-lib boost_serialization : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt.a ;
-lib boost_system : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt.a ;
-lib boost_thread : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt.a ;
-lib boost_test : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt.a ;
-lib boost_test_monitor : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt.a ;
-lib boost_program_options : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt.a ;
-lib boost_filesystem : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt.a ;
-lib boost_datetime : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt.a ;
-lib boost_python : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.so ;
-lib boost_python_static : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.a ;
-
-#
-# Notice: we don't add requirements <library>pthread , because
-# a/ Not all tests require it
-# b/ Can cause links errors
-# Hence left to individual projects/test
-#
-project site-config
- : requirements <include>$(BOOST_ROOT)
- ;
-
-# On linux 64, because most of the static library's, are placed in a shared libs(ecflow.so)
-# hence we need to compile with -fPIC
-#
-# using syntax:
-# using toolset-name : version : invocation-command : options ;
-# where options allows <cflags, cxxflags, compileflags and linkflags >
-#
-# Suppress the following warnings:
-# warning #1875: offsetof applied to non-POD (Plain Old Data) types is nonstandard
-# This warning is mostly from boost python headers
-# warning #1881: argument must be a constant null pointer value
-# This warning is in the vewier, with X-windows
-#
-using intel-linux : : : <cxxflags>-fPIC <compileflags>-wd1875,1881 ;
-
-using testing ;
-
-# ==================== ECFLOWVIEW/install =======================================================
-
-local motif_library = [ os.environ MOTIF_LIBRARY ] ;
-motif_library default = "/usr/lib64" ;
-constant MOTIF_LIBRARY : $(motif_library) ;
-
-# ================================================================================
-# Link with FDB, (PRODGEN)
-lib libfdb
- :
- : <file>/usr/local/lib/metaps/lib/libfdb.a
- ;
diff --git a/ecflow_4_0_7/build/site_config/site-config-Linux64.jam b/ecflow_4_0_7/build/site_config/site-config-Linux64.jam
deleted file mode 100644
index a2e576c..0000000
--- a/ecflow_4_0_7/build/site_config/site-config-Linux64.jam
+++ /dev/null
@@ -1,96 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-# ===================================================================
-# site-config.jam file for Linux/gcc
-# This file should be placed in $HOME or $BOOST_ROOT/tools/build/v2/
-# ===================================================================
-
-#
-# Pull in environment variables
-#
-import os ;
-local BOOST_ROOT = [ os.environ BOOST_ROOT ] ;
-
-#
-# --layout=system -> libboost_system.a (default)
-# --layout=tagged -> libboost_system-mt-d.a(debug) libboost_system-mt.a(release)
-# --layout=versioned -> libboost_system-xlc-mt-d-1.42(debug) libboost_system-xlc-mt-1_42.a(release)
-#
-# Boost libraries referenced in client/server programs
-# assumes --layout=tagged for the debug release and profile variant
-#
-lib boost_serialization : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt-d.a ;
-lib boost_system : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt-d.a ;
-lib boost_thread : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt-d.a ;
-lib boost_test : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt-d.a ;
-lib boost_test_monitor : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt-d.a ;
-lib boost_program_options : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt-d.a ;
-lib boost_filesystem : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt-d.a ;
-lib boost_datetime : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt-d.a ;
-lib boost_python : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-d.so ;
-lib boost_python_static : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-d.a ;
-
-# profile uses release libs
-lib boost_serialization : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt.a ;
-lib boost_system : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt.a ;
-lib boost_thread : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt.a ;
-lib boost_test : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt.a ;
-lib boost_test_monitor : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt.a ;
-lib boost_program_options : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt.a ;
-lib boost_filesystem : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt.a ;
-lib boost_datetime : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt.a ;
-lib boost_python : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.so ;
-lib boost_python_static : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.a ;
-
-lib boost_serialization : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt.a ;
-lib boost_system : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt.a ;
-lib boost_thread : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt.a ;
-lib boost_test : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt.a ;
-lib boost_test_monitor : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt.a ;
-lib boost_program_options : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt.a ;
-lib boost_filesystem : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt.a ;
-lib boost_datetime : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt.a ;
-lib boost_python : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.so ;
-lib boost_python_static : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt.a ;
-
-#
-# Notice: we don't add requirements <library>pthread , because
-# a/ Not all tests require it
-# b/ Can cause links errors
-# Hence left to individual projects/test
-#
-project site-config
- : requirements <include>$(BOOST_ROOT)
- ;
-
-# using syntax:
-# using toolset-name : version :invocation-command : options ;
-# where options allows <cflags, cxxflags, compileflags and linkflags >
-#
-# On linux 64, because most of the static library's, are placed in a shared libs(ecflow.so)
-# hence we need to compile with -fPIC
-using gcc : : : <cxxflags>-fPIC ;
-
-#
-# $BOOST_ROOT/bjam --toolset=gcc cflags="-std=gnu++11" c++-template-depth=512
-# using gcc : 4.7.2 : : <cxxflags>-fPIC <cxxflags>-std=gnu++11 <cxxflags>-ftemplate-depth=512 ;
-
-using testing ;
-
-# ==================== ECFLOWVIEW/install =======================================================
-
-local motif_library = [ os.environ MOTIF_LIBRARY ] ;
-motif_library default = "/usr/lib64" ;
-constant MOTIF_LIBRARY : $(motif_library) ;
-
-# ================================================================================
-# Link with FDB, (PRODGEN)
-lib libfdb
- :
- : <file>/usr/local/lib/metaps/lib/libfdb.a
- ;
diff --git a/ecflow_4_0_7/build/site_config/site-config-cray.jam b/ecflow_4_0_7/build/site_config/site-config-cray.jam
deleted file mode 100644
index b82419e..0000000
--- a/ecflow_4_0_7/build/site_config/site-config-cray.jam
+++ /dev/null
@@ -1,203 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-# ===================================================================
-# site-config.jam file for Linux/cray
-# This file should be placed in $HOME or $BOOST_ROOT/tools/build/v2/
-# ===================================================================
-
-#
-# Pull in environment variables
-#
-import os ;
-local BOOST_ROOT = [ os.environ BOOST_ROOT ] ;
-local MACHINE_NAME = [ os.environ MACHINE_NAME ] ;
-
-#
-# --layout=system -> libboost_system.a (default)
-# --layout=tagged -> libboost_system-mt-d.a(debug) libboost_system-mt.a(release)
-# --layout=versioned -> libboost_system-xlc-mt-d-1.42(debug) libboost_system-xlc-mt-1_42.a(release)
-#
-# Boost libraries referenced in client/server programs
-# assumes --layout=tagged for the debug release and profile variant
-#
-
-GCC_TAG = gcc46 ;
-VERSION_TAG = 1_53 ;
-switch $(BOOST_ROOT) {
- case *boost_1_55_0 : VERSION_TAG = 1_55 ;
- case *boost_1_56_0 : VERSION_TAG = 1_56 ;
- case *boost_1_57_0 : VERSION_TAG = 1_57 ;
-}
-
-switch $(MACHINE_NAME) {
- case cca : GCC_TAG = gcc48 ;
- case ccb : GCC_TAG = gcc48 ;
-}
-
-
-lib boost_serialization : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-$(GCC_TAG)-mt-d-$(VERSION_TAG).a ;
-lib boost_system : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_system-$(GCC_TAG)-mt-d-$(VERSION_TAG).a ;
-lib boost_thread : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_thread-$(GCC_TAG)-mt-d-$(VERSION_TAG).a ;
-lib boost_test : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-$(GCC_TAG)-mt-d-$(VERSION_TAG).a ;
-lib boost_test_monitor : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-$(GCC_TAG)-mt-d-$(VERSION_TAG).a ;
-lib boost_program_options : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-$(GCC_TAG)-mt-d-$(VERSION_TAG).a ;
-lib boost_filesystem : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-$(GCC_TAG)-mt-d-$(VERSION_TAG).a ;
-lib boost_datetime : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-$(GCC_TAG)-mt-d-$(VERSION_TAG).a ;
-lib boost_python : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-$(GCC_TAG)-mt-d-$(VERSION_TAG).so ;
-lib boost_python_static : : <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-$(GCC_TAG)-mt-d-$(VERSION_TAG).a ;
-
-# profile uses release libs
-lib boost_serialization : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
-lib boost_system : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_system-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
-lib boost_thread : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_thread-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
-lib boost_test : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
-lib boost_test_monitor : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
-lib boost_program_options : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
-lib boost_filesystem : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
-lib boost_datetime : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
-lib boost_python : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-$(GCC_TAG)-mt-$(VERSION_TAG).so ;
-lib boost_python_static : : <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
-
-lib boost_serialization : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
-lib boost_system : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_system-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
-lib boost_thread : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_thread-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
-lib boost_test : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
-lib boost_test_monitor : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
-lib boost_program_options : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
-lib boost_filesystem : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
-lib boost_datetime : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
-lib boost_python : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-$(GCC_TAG)-mt-$(VERSION_TAG).so ;
-lib boost_python_static : : <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-$(GCC_TAG)-mt-$(VERSION_TAG).a ;
-
-# INTEL ================================================================================================
-
-lib boost_serialization : : <toolset>intel <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-il-mt-d-$(VERSION_TAG).a ;
-lib boost_system : : <toolset>intel <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_system-il-mt-d-$(VERSION_TAG).a ;
-lib boost_thread : : <toolset>intel <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_thread-il-mt-d-$(VERSION_TAG).a ;
-lib boost_test : : <toolset>intel <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-il-mt-d-$(VERSION_TAG).a ;
-lib boost_test_monitor : : <toolset>intel <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-il-mt-d-$(VERSION_TAG).a ;
-lib boost_program_options : : <toolset>intel <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-il-mt-d-$(VERSION_TAG).a ;
-lib boost_filesystem : : <toolset>intel <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-il-mt-d-$(VERSION_TAG).a ;
-lib boost_datetime : : <toolset>intel <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-il-mt-d-$(VERSION_TAG).a ;
-lib boost_python : : <toolset>intel <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-il-mt-d-$(VERSION_TAG).so ;
-lib boost_python_static : : <toolset>intel <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-il-mt-d-$(VERSION_TAG).a ;
-
-lib boost_serialization : : <toolset>intel <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-il-mt-$(VERSION_TAG).a ;
-lib boost_system : : <toolset>intel <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_system-il-mt-$(VERSION_TAG).a ;
-lib boost_thread : : <toolset>intel <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_thread-il-mt-$(VERSION_TAG).a ;
-lib boost_test : : <toolset>intel <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-il-mt-$(VERSION_TAG).a ;
-lib boost_test_monitor : : <toolset>intel <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-il-mt-$(VERSION_TAG).a ;
-lib boost_program_options : : <toolset>intel <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-il-mt-$(VERSION_TAG).a ;
-lib boost_filesystem : : <toolset>intel <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-il-mt-$(VERSION_TAG).a ;
-lib boost_datetime : : <toolset>intel <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-il-mt-$(VERSION_TAG).a ;
-lib boost_python : : <toolset>intel <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-il-mt-$(VERSION_TAG).so ;
-lib boost_python_static : : <toolset>intel <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-il-mt-$(VERSION_TAG).a ;
-
-lib boost_serialization : : <toolset>intel <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-il-mt-$(VERSION_TAG).a ;
-lib boost_system : : <toolset>intel <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_system-il-mt-$(VERSION_TAG).a ;
-lib boost_thread : : <toolset>intel <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_thread-il-mt-$(VERSION_TAG).a ;
-lib boost_test : : <toolset>intel <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-il-mt-$(VERSION_TAG).a ;
-lib boost_test_monitor : : <toolset>intel <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-il-mt-$(VERSION_TAG).a ;
-lib boost_program_options : : <toolset>intel <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-il-mt-$(VERSION_TAG).a ;
-lib boost_filesystem : : <toolset>intel <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-il-mt-$(VERSION_TAG).a ;
-lib boost_datetime : : <toolset>intel <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-il-mt-$(VERSION_TAG).a ;
-lib boost_python : : <toolset>intel <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-il-mt-$(VERSION_TAG).so ;
-lib boost_python_static : : <toolset>intel <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-il-mt-$(VERSION_TAG).a ;
-
-# CRAY ================================================================================================
-lib boost_serialization : : <toolset>cray <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt-d-$(VERSION_TAG).a ;
-lib boost_system : : <toolset>cray <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt-d-$(VERSION_TAG).a ;
-lib boost_thread : : <toolset>cray <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt-d-$(VERSION_TAG).a ;
-lib boost_test : : <toolset>cray <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt-d-$(VERSION_TAG).a ;
-lib boost_test_monitor : : <toolset>cray <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt-d-$(VERSION_TAG).a ;
-lib boost_program_options : : <toolset>cray <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt-d-$(VERSION_TAG).a ;
-lib boost_filesystem : : <toolset>cray <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt-d-$(VERSION_TAG).a ;
-lib boost_datetime : : <toolset>cray <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt-d-$(VERSION_TAG).a ;
-lib boost_python : : <toolset>cray <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-d-$(VERSION_TAG).so ;
-lib boost_python_static : : <toolset>cray <variant>debug <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-d-$(VERSION_TAG).a ;
-
-lib boost_serialization : : <toolset>cray <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt-$(VERSION_TAG).a ;
-lib boost_system : : <toolset>cray <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt-$(VERSION_TAG).a ;
-lib boost_thread : : <toolset>cray <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt-$(VERSION_TAG).a ;
-lib boost_test : : <toolset>cray <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt-$(VERSION_TAG).a ;
-lib boost_test_monitor : : <toolset>cray <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt-$(VERSION_TAG).a ;
-lib boost_program_options : : <toolset>cray <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt-$(VERSION_TAG).a ;
-lib boost_filesystem : : <toolset>cray <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt-$(VERSION_TAG).a ;
-lib boost_datetime : : <toolset>cray <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt-$(VERSION_TAG).a ;
-lib boost_python : : <toolset>cray <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-$(VERSION_TAG).so ;
-lib boost_python_static : : <toolset>cray <variant>profile <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-$(VERSION_TAG).a ;
-
-lib boost_serialization : : <toolset>cray <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_serialization-mt-$(VERSION_TAG).a ;
-lib boost_system : : <toolset>cray <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_system-mt-$(VERSION_TAG).a ;
-lib boost_thread : : <toolset>cray <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_thread-mt-$(VERSION_TAG).a ;
-lib boost_test : : <toolset>cray <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_unit_test_framework-mt-$(VERSION_TAG).a ;
-lib boost_test_monitor : : <toolset>cray <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_test_exec_monitor-mt-$(VERSION_TAG).a ;
-lib boost_program_options : : <toolset>cray <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_program_options-mt-$(VERSION_TAG).a ;
-lib boost_filesystem : : <toolset>cray <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_filesystem-mt-$(VERSION_TAG).a ;
-lib boost_datetime : : <toolset>cray <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_date_time-mt-$(VERSION_TAG).a ;
-lib boost_python : : <toolset>cray <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-$(VERSION_TAG).so ;
-lib boost_python_static : : <toolset>cray <variant>release <file>$(BOOST_ROOT)/stage/lib/libboost_python-mt-$(VERSION_TAG).a ;
-
-
-# ******************** CRAY Compiler specific ************************************
-# The customer may be able to work around this by adding
-#
-# -DBOOST_ASIO_DISABLE_FENCED_BLOCK=1
-#
-# to the compiler invocation.
-#
-# The issue is that the various compiler macros set are causing a file with gcc
-# inline assembly to be included. CCE does not currently support inline assembly.
-#
-# Note that adding this macro to the command line may cause additional Boost
-# compilation errors to surface.
-#
-# Notice: we don't add requirements <library>pthread , because
-# a/ Not all tests require it
-# b/ Can cause links errors
-# Hence left to individual projects/test
-#
-# ***********************************************************************************
-project site-config
- : requirements <include>$(BOOST_ROOT)
- : requirements <toolset>cray:<define>BOOST_ASIO_DISABLE_FENCED_BLOCK
- ;
-
-# On linux 64, because most of the static library's, are placed in a shared libs(ecflow.so)
-# hence we need to compile with -fPIC
-#
-# using syntax:
-# using toolset-name : version :invocation-command : options ;
-# where options allows <cflags, cxxflags, compileflags and linkflags >
-#
-#using gcc : : : <cxxflags>-fPIC ;
-#using cray : : : <cxxflags>-fPIC ;
-#using intel-linux : : : <cxxflags>-fPIC ;
-
-
-# For cray use the 'CC' wrapper script, however this assumes you linking with MPI, then barf's
-# using gcc : : CC : <cxxflags>-fPIC ;
-#
-#
-# $BOOST_ROOT/bjam --toolset=gcc cflags="-std=gnu++11" c++-template-depth=512
-# using gcc : 4.7.2 : : <cxxflags>-fPIC <cxxflags>-std=gnu++11 <cxxflags>-ftemplate-depth=512 ;
-
-using testing ;
-
-# ==================== ECFLOWVIEW/install =======================================================
-
-local motif_library = [ os.environ MOTIF_LIBRARY ] ;
-motif_library default = "/usr/lib64" ;
-constant MOTIF_LIBRARY : $(motif_library) ;
-
-# ================================================================================
-# Link with FDB, (PRODGEN)
-lib libfdb
- :
- : <file>/usr/local/lib/metaps/lib/libfdb.a
- ;
diff --git a/ecflow_4_0_7/build/tar_ecflow.sh b/ecflow_4_0_7/build/tar_ecflow.sh
deleted file mode 100755
index fd6b595..0000000
--- a/ecflow_4_0_7/build/tar_ecflow.sh
+++ /dev/null
@@ -1,146 +0,0 @@
-#!/bin/sh
-
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-# Tar up ecflow
-# Assumes $WK(root workspace) is defined
-
-set -e # stop the shell on first error
-set -u # fail when using an undefined variable
-
-# ===============================================================================
-# Test/data/ECF_HOME is used by Test to recursively generate directory structure
-# and populate with defs file, and job output, etc, hence exclude this directory
-# ===============================================================================
-cd $WK
-rm -rf *.dat
-rm -rf *lock
-rm -rf *log
-rm -rf *.check
-rm -rf *.def
-rm -rf rtt.dat
-rm -rf Test/data/ECF_HOME_debug*
-rm -rf Test/data/ECF_HOME_release*
-rm -rf view/data/ECF_HOME_debug*
-rm -rf view/data/ECF_HOME_release*
-rm -rf AParser/test/data/single_defs/mega.def_log
-rm -rf Pyext/test.def
-rm -rf Pyext/build
-rm -rf Pyext/test/data/ecf_home_*
-
-# ================================================================================
-# Remove generated files before taring ecFlow
-# Be careful with *.txt extension. i.e do not to delete CMakeList.txt file.
-# ================================================================================
-cd $WK
-
-# exclude log files from hidden files/directories like .metadata
-find . \( ! -regex '.*/\..*' \) -type f -name \*.log -exec rm -rf \*.log {} \; -print
-
-find . -name \*~ -exec rm -rf \*~ {} \; -print
-find . -name \*.mk -exec rm -rf \*.mk {} \; -print
-find . -name \*.so -exec rm -rf \*.so {} \; -print
-find . -name \*.tmp -exec rm -rf \*.tmp {} \; -print
-find . -name \*.job\* -exec rm -rf \*.job\* {} \; -print
-find . -name \*.check -exec rm -rf \*.check {} \; -print
-find . -name \*.flat -exec rm -rf \*.flat {} \; -print
-find . -name \*.depth -exec rm -rf \*.depth {} \; -print
-find . -name \*.out -exec rm -rf \*.out {} \; -print
-find . -name \*.pyc -exec rm -rf \*.pyc {} \; -print
-find . -name t\*.1 -exec rm -rf t\*.1 {} \; -print
-find . -name gmon.out -exec rm -rf gmon.out {} \; -print
-find . -name gnuplot.dat -exec rm -rf gnuplot.dat {} \; -print
-find . -name gnuplot.script -exec rm -rf gnuplot.script {} \; -print
-find . -name ecflow.html -exec rm -rf ecflow.html {} \; -print
-find . -name core -exec rm -rf core {} \; -print
-find . -name `hostname`.*.ecf.* -exec rm -rf `hostname`.*.ecf.* {} \; -print
-find . -name callgrind.out.\* -exec rm -rf callgrind.out.\* {} \; -print
-find . -name massif.out.\* -exec rm -rf massif.out.* {} \; -print
-
-# ======================================================================
-# Create the tar file name based on the version
-# Determine ecflow build directory name: see ACore/doc/extracting_version_number.ddoc
-# ========================================================================
-cd $WK
-
-release=$(cat VERSION.cmake | grep 'set( ECFLOW_RELEASE' | awk '{print $3}'| sed 's/["]//g')
-major=$(cat VERSION.cmake | grep 'set( ECFLOW_MAJOR' | awk '{print $3}'| sed 's/["]//g')
-minor=$(cat VERSION.cmake | grep 'set( ECFLOW_MINOR' | awk '{print $3}'| sed 's/["]//g')
-
-ECFLOW_WS_DIR=ecflow_${release}_${major}_${minor}
-
-# ================================================================================
-# Create ecflow tar file
-# ================================================================================
-cd $WK
-cd ..
-
-# remove old tar files
-ECFLOWTAR=$ECFLOW_WS_DIR.tar
-rm -rf $ECFLOWTAR.gz
-rm -rf $ECFLOWTAR
-
-# temporarily create a symbolic link ECFLOW_WS_DIR, so that tar file directory name has version number in it
-ln -s ecflow $ECFLOW_WS_DIR
-
-# Exclusions from tar file:
-# o/ .pydevproject used by Pydev eclipse plug-in
-# o/ .metadata, .cproject, .project, .settings, csettings are eclipse dir
-# o/ --exclude=SCRATCH - has code for recording stand alone bugs.
-# o/ bin directory contains the build object files and exe's
-# o/ Debug is the eclipse/make dir
-# o/ operations: this consists of the mega defs file used in operations for reference only /AParser/test/data/operations
-# o/ Pyext/ecf/ecflow.so is ecFlow python extension
-# o/ Exclude ddoc file's
-# o/ Exclude *CERTAIN* Documentation directory , this includes the sphinx generated file '_build' ~4 Mb
-# ** STILL NEED Doc/online as this used in the python unit tests.
-# ** STILL NEED user-manual as this is installed
-# o/ Exclude check point and back up check point files, --exclude=*.check --exclude=*.check.b
-# o/ Exclude build/include
-# o/ RemoteSystemsTempFile dir generated by eclipse
-# o/ Xcdp, xcdp old ecflowview dirs
-# o/ exclude ecbuild used for CMAKE. Still needs sorting out
-# o/ exclude Pyext/test/data/CUSTOMER
-# o/ gcc4.5 this directory is under build/, used for CMAKE
-tar --exclude=*.check --exclude=*.check.b \
- --exclude=*.ddoc \
- --exclude=.p4config \
- --exclude=SCRATCH \
- --exclude=New_viewer \
- --exclude=_build --exclude=func_spec --exclude=misc --exclude=newsletter --exclude=presentations --exclude=seminar --exclude=tac --exclude=Thumbs.db \
- --exclude=.pydevproject \
- --exclude=.git \
- --exclude=.metadata --exclude=.cproject --exclude=.project --exclude=.settings --exclude=.csettings \
- --exclude=ecbuild \
- --exclude=bin \
- --exclude=gcc4.5 \
- --exclude=Debug \
- --exclude=operations \
- --exclude=ecflow.so \
- --exclude=profile.sh \
- --exclude=CUSTOMER \
- --exclude=massive.sh \
- --exclude=val.sh \
- --exclude=include \
- --exclude=test_bench \
- --exclude=nightly \
- --exclude=online \
- --exclude=RemoteSystemsTempFiles \
- -cf $ECFLOWTAR $ECFLOW_WS_DIR/.
-
-# Remove the link
-rm $ECFLOW_WS_DIR
-
-# add ecbuild/ into tar file, exclude any .git files
-tar -rvf $ECFLOWTAR --exclude=.git ecbuild/
-
-ls -lh $ECFLOWTAR
-gzip $ECFLOWTAR
-
-# Move tar file to /var/tmp/ma0/clientRoot/workspace
-mv $ECFLOWTAR.gz ../.
diff --git a/ecflow_4_0_7/build/tar_ecflow_doc.sh b/ecflow_4_0_7/build/tar_ecflow_doc.sh
deleted file mode 100644
index d4869a0..0000000
--- a/ecflow_4_0_7/build/tar_ecflow_doc.sh
+++ /dev/null
@@ -1,78 +0,0 @@
-#!/bin/sh
-
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-# tar up ecflow documentation.
-# - consisting of html based online tutorial and python API
-# - user manual in Word and PDF formats
-# Creates a file of the form ecflow_2_0_19_doc.tar.gz in directory $SCRATCH
-# Assumes $WK(root workspace) defined
-# Assumes $SCRATCH is defined
-# Assumes sphinx available to build online documentation
-#
-
-set -e # stop the shell on first error
-set -u # fail when using an undefined variable
-
-# ======================================================================
-# Determine ecflow build directory name: see ACore/doc/extracting_version_number.ddoc
-# ========================================================================
-cd $WK
-
-release=$(cat VERSION.cmake | grep 'set( ECFLOW_RELEASE' | awk '{print $3}'| sed 's/["]//g')
-major=$(cat VERSION.cmake | grep 'set( ECFLOW_MAJOR' | awk '{print $3}'| sed 's/["]//g')
-minor=$(cat VERSION.cmake | grep 'set( ECFLOW_MINOR' | awk '{print $3}'| sed 's/["]//g')
-
-ECFLOW_WS_DIR=ecflow_${release}_${major}_${minor}_doc
-
-
-# ===================================================================================
-# generate online tutorial so the we don't need to add dependency
-# on sphinx build on other platforms
-# ===================================================================================
-cd $WK/Doc/online
-make clean
-make html
-
-
-# ================================================================================
-# remove old doc tar files
-# ================================================================================
-ECFLOWTAR=$ECFLOW_WS_DIR.tar
-rm -rf $SCRATCH/$ECFLOWTAR.gz
-rm -rf $SCRATCH/$ECFLOWTAR
-
-
-# ================================================================================
-# Create a tar of the online and user manual documentation
-# Notice: we don't delete Doc/online/_build as this contains the index.html
-# ================================================================================
-# Exclusions from tar file:
-# o/ func_spec
-# o/ .metadata, .cproject, .project, .settings, csettings are eclipse dir
-# o/ newsletter
-# o/ presentation
-# o/ Tac
-# o/ misc
-#
-cd $WK
-tar --exclude=func_spec \
- --exclude=newsletter \
- --exclude=presentations \
- --exclude=seminar \
- --exclude=ecbuild \
- --exclude=tac \
- --exclude=misc \
- --exclude=.metadata --exclude=.cproject --exclude=.project --exclude=.settings --exclude=.csettings \
- --exclude=Thumbs.db \
- -cf $ECFLOWTAR Doc/
-
-ls -lh $ECFLOWTAR
-gzip $ECFLOWTAR
-mv $ECFLOWTAR.gz $SCRATCH/
-
diff --git a/ecflow_4_0_7/build/test.sh b/ecflow_4_0_7/build/test.sh
deleted file mode 100755
index d9d6416..0000000
--- a/ecflow_4_0_7/build/test.sh
+++ /dev/null
@@ -1,185 +0,0 @@
-#!/bin/sh
-
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-#===================================================================
-# Run all the ecflow tests, note use !/bin/bash to keep rpm happy, it uses bash
-#===================================================================
-
-if [ "$#" -gt 3 ] ; then
- echo "Maximum of 3 arguments expected"
- echo " arg1-mode (optional) default = debug, valid values = [ debug | release ]"
- echo " arg2-compiler(optional) default = linux/gcc-4.2.1"
- echo " arg3-safe (optional) default = no, valid values = [ no | safe ],"
- echo " safe means only run deterministic tests"
- exit 1
-fi
-
-mode=debug
-compiler_arg=
-safe=no
-while [ "$#" -ne 0 ] ; do
- if [ "$1" = debug -o "$1" = release -o "$1" = profile ] ; then
- mode=$1
- elif [ "$1" = safe ] ; then
- safe=yes
- else
- compiler_arg=$1
- fi
- # shift remove last argument
- shift
-done
-
-if [ ${#mode} -eq 0 ] ; then
- echo "test expects mode i.e. debug or release"
- exit 1
-fi
-
-echo "mode=$mode compiler=$compiler_arg safe=$safe"
-#exit 1;
-
-#======================================================================
-# remove python test, so that they are rerun
-cd $WK
-rm -rf Pyext/bin/*.test
-
-# Remove any lock file create by tests which used EcfPortLock.hpp
-# ** However DO *NOT* remove this locks for in ecflow test.ecf
-# ** as they allow the debug and release test to run at the same time.
-rm -rf *.lock
-
-# Check that a command is in the PATH.
-test_path ()
-{
- if `command -v command 1>/dev/null 2>/dev/null`; then
- command -v $1 1>/dev/null 2>/dev/null
- else
- hash $1 1>/dev/null 2>/dev/null
- fi
-}
-
-# Check that the OS name, as returned by "uname", is as given.
-test_uname ()
-{
- if test_path uname; then
- test `uname` = $*
- fi
-}
-
-if test_uname Linux ; then
-
- TOOLSET=
- CXXFLAGS=
- compiler=gcc-$(gcc -dumpversion)
-
- # When on cray check PE_ENV for environment
- if [ "$PE_ENV" = INTEL -o "$PE_ENV" = CRAY -o "$PE_ENV" = GNU ]
- then
- CXXFLAGS=cxxflags=-fPIC
- TOOLSET=toolset=gcc
- if [ "$PE_ENV" = INTEL ] ; then
- compiler=intel-linux
- TOOLSET=toolset=intel
- fi
- if [ "$PE_ENV" = CRAY ] ; then
- compiler=cray
- TOOLSET=toolset=cray
- fi
- fi
-
- # Allow the compiler to be overridden on linux
- if [ ${#compiler_arg} -ne 0 ] ; then
- compiler=$compiler_arg
- fi
-
- echo "*****************************************"
- echo "Testing: variant=$mode compiler=$compiler"
- echo "*****************************************"
-
- ACore/bin/$compiler/$mode/u_acore --log_level=message $TEST_OPTS
- ANattr/bin/$compiler/$mode/u_anattr --log_level=message $TEST_OPTS
- ANode/bin/$compiler/$mode/u_anode --log_level=message $TEST_OPTS
- AParser/bin/$compiler/$mode/u_aparser --log_level=message $TEST_OPTS
- if [ "$safe" = no ] ; then
- AParser/bin/$compiler/$mode/perf_aparser --log_level=message $TEST_OPTS
- fi
- Base/bin/$compiler/$mode/u_base --log_level=message $TEST_OPTS
- Client/bin/$compiler/$mode/s_client --log_level=message $TEST_OPTS
- Server/bin/$compiler/$mode/u_server --log_level=message $TEST_OPTS
- CSim/bin/$compiler/$mode/c_csim --log_level=message $TEST_OPTS
- if [ "$safe" = no ] ; then
- Test/bin/$compiler/$mode/s_test --log_level=message $TEST_OPTS
- Test/bin/$compiler/$mode/s_test_zombies --log_level=message $TEST_OPTS
- fi
-
- if [ "$safe" = no ] ; then
- # run python/C++ test
- cd Pyext
- $BOOST_ROOT/bjam $TOOLSET $CXXFLAGS variant=$mode test-all $TEST_OPTS
- cd ..
- fi
-
- if [ x$DISPLAY = x ]; then
- echo "DISPLAY variable is not defined, ecflowview is not tested..."
- else
- view/bin/$compiler/$mode/test-view --log_level=message $TEST_OPTS
- fi
-
-elif test_uname HP-UX ; then
-
- echo "Testing: variant=$mode"
- ACore/bin/acc/$mode/threading-multi/u_acore --log_level=message $TEST_OPTS
- ANattr/bin/acc/$mode/threading-multi/u_anattr --log_level=message $TEST_OPTS
- ANode/bin/acc/$mode/threading-multi/u_anode --log_level=message $TEST_OPTS
- AParser/bin/acc/$mode/threading-multi/u_aparser --log_level=message $TEST_OPTS
- if [ "$safe" = no ] ; then
- AParser/bin/acc/$mode/threading-multi/perf_aparser --log_level=message $TEST_OPTS
- fi
- Base/bin/acc/$mode/threading-multi/u_base --log_level=message $TEST_OPTS
- Client/bin/acc/$mode/threading-multi/s_client --log_level=message $TEST_OPTS
- Server/bin/acc/$mode/threading-multi/u_server --log_level=message $TEST_OPTS
- CSim/bin/acc/$mode/threading-multi/c_csim --log_level=message $TEST_OPTS
- if [ "$safe" = no ] ; then
- Test/bin/acc/$mode/threading-multi/s_test --log_level=message $TEST_OPTS
- Test/bin/acc/$mode/threading-multi/s_test_zombies --log_level=message $TEST_OPTS
- fi
-
- if [ "$safe" = no ] ; then
- # run python/C++ test, use test to bypass 'with' statement tests
- cd Pyext
- $BOOST_ROOT/bjam variant=$mode test $TEST_OPTS
- cd ..
- fi
-
-elif test_uname AIX ; then
-
- echo "Testing: $ARCH variant=$mode"
-
- ACore/bin/vacpp/$mode/threading-multi/u_acore --log_level=message $TEST_OPTS
- ANattr/bin/vacpp/$mode/threading-multi/u_anattr --log_level=message $TEST_OPTS
- ANode/bin/vacpp/$mode/threading-multi/u_anode --log_level=message $TEST_OPTS
- AParser/bin/vacpp/$mode/threading-multi/u_aparser --log_level=message $TEST_OPTS
- if [ "$safe" = no ] ; then
- AParser/bin/vacpp/$mode/threading-multi/perf_aparser --log_level=message $TEST_OPTS
- fi
- Base/bin/vacpp/$mode/threading-multi/u_base --log_level=message $TEST_OPTS
- Client/bin/vacpp/$mode/threading-multi/s_client --log_level=message $TEST_OPTS
- Server/bin/vacpp/$mode/threading-multi/u_server --log_level=message $TEST_OPTS
- CSim/bin/vacpp/$mode/threading-multi/c_csim --log_level=message $TEST_OPTS
- if [ "$safe" = no ] ; then
- Test/bin/vacpp/$mode/threading-multi/s_test --log_level=message $TEST_OPTS
- Test/bin/vacpp/$mode/threading-multi/s_test_zombies --log_level=message $TEST_OPTS
- fi
-
- if [ "$safe" = no ] ; then
- # run python/C++ test
- cd Pyext
- $BOOST_ROOT/bjam variant=$mode test-all $TEST_OPTS
- cd ..
- fi
-fi
diff --git a/ecflow_4_0_7/build/update_site_config.sh b/ecflow_4_0_7/build/update_site_config.sh
deleted file mode 100644
index fd2e403..0000000
--- a/ecflow_4_0_7/build/update_site_config.sh
+++ /dev/null
@@ -1,83 +0,0 @@
-#!/bin/sh
-
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-# This file is used build the boost libs used by ecflow
-# This script Use $BOOST_ROOT and $WK environment variable
-
-echo "WK=$WK"
-echo "BOOST_ROOT=$BOOST_ROOT"
-
-#
-# From boost 1.56 > the location of site-config.jam location has changed
-#
-SITE_CONFIG_LOCATION=$BOOST_ROOT/tools/build/v2/site-config.jam
-BOOST_VERSION="$(basename $BOOST_ROOT)"
-if [[ "$BOOST_VERSION" = boost_1_56_0 || "$BOOST_VERSION" = boost_1_57_0 ]] ; then
- SITE_CONFIG_LOCATION=$BOOST_ROOT/tools/build/src/site-config.jam
-fi
-
-tool=
-
-# Check that a command is in the PATH.
-test_path ()
-{
- if `command -v command 1>/dev/null 2>/dev/null`; then
- command -v $1 1>/dev/null 2>/dev/null
- else
- hash $1 1>/dev/null 2>/dev/null
- fi
-}
-
-test_uname ()
-{
- if test_path uname; then
- test `uname` = $*
- fi
-}
-
-if test_uname Linux ; then
- tool=gcc
- X64=$(uname -m)
- if [ "$X64" = x86_64 ]
- then
- # PE_ENV is defined in cray environment, at least on sandy bridge
- if [ "$PE_ENV" = GNU -o "$PE_ENV" = INTEL -o "$PE_ENV" = CRAY ]
- then
- CXXFLAGS=cxxflags=-fPIC
- layout=versioned
-
- cp $WK/build/site_config/site-config-cray.jam $SITE_CONFIG_LOCATION
- if [ "$PE_ENV" = INTEL ] ; then
- tool=intel
- fi
- if [ "$PE_ENV" = CRAY ] ; then
- tool=cray
- fi
- else
- cp $WK/build/site_config/site-config-Linux64.jam $SITE_CONFIG_LOCATION
- fi
-
- else
- cp $WK/build/site_config/site-config-Linux.jam $SITE_CONFIG_LOCATION
- fi
-
-elif test_uname HP-UX ; then
-
- tool=acc
- cp $WK/build/site_config/site-config-HPUX.jam $SITE_CONFIG_LOCATION
-
-elif test_uname AIX ; then
-
- # on c1a
- tool=vacpp
- cp $WK/build/site_config/site-config-AIX.jam $SITE_CONFIG_LOCATION
-
-fi
-
-
\ No newline at end of file
diff --git a/ecflow_4_0_7/cmake.sh b/ecflow_4_0_7/cmake.sh
deleted file mode 100755
index 7bb4e57..0000000
--- a/ecflow_4_0_7/cmake.sh
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/bin/sh
-
-# ====================================================================
-# Maximum of 1 arguments expected:
-#
-if [ "$#" -gt 1 ] ; then
- echo "cmake expects 1 argument i.e"
- echo " cmake.sh debug"
- echo " cmake.sh release"
- exit 1
-fi
-if [[ "$1" != debug && "$1" != release ]] ; then
- echo "cmake expected [ debug | release ] but found $1"
- exit 1
-fi
-
-# ==================================================================
-# Error handling
-set -e # stop the shell on first error
-set -u # fail when using an undefined variable
-set -x # echo script lines as they are executed
-
-# ===================================================================
-cd $WK
-release=$(cat VERSION.cmake | grep 'set( ECFLOW_RELEASE' | awk '{print $3}'| sed 's/["]//g')
-major=$(cat VERSION.cmake | grep 'set( ECFLOW_MAJOR' | awk '{print $3}'| sed 's/["]//g')
-minor=$(cat VERSION.cmake | grep 'set( ECFLOW_MINOR' | awk '{print $3}'| sed 's/["]//g')
-
-mkdir -p ecbuild/$1
-cd ecbuild/$1
-
-cmake_build_type=
-if [[ $1 = debug ]] ; then
- cmake_build_type=Debug
-else
- cmake_build_type=Release
-fi
-
-#
-# -DCMAKE_PYTHON_INSTALL_TYPE = [ local | setup ]
-# -DCMAKE_PYTHON_INSTALL_PREFIX should *only* used when using python setup.py (CMAKE_PYTHON_INSTALL_TYPE=setup)
-# *AND* for testing python install to local directory
-#
-# Use:DCMAKE_CXX_FLAGS to set compiler flags
-# -DCMAKE_CXX_FLAGS="-ftemplate-depth-128 -finline-functions -Wno-inline -Wall -fPIC -DNDEBUG" \
-
-
-cmake ../.. -DCMAKE_MODULE_PATH=$WK/../ecbuild/cmake \
- -DCMAKE_BUILD_TYPE=$cmake_build_type \
- -DCMAKE_INSTALL_PREFIX=/var/tmp/ma0/cmake/ecflow/$release.$major.$minor \
- -DCMAKE_PYTHON_INSTALL_TYPE=local
- #-DCMAKE_PYTHON_INSTALL_PREFIX=/var/tmp/ma0/cmake/ecflow/$release.$major.$minor/lib/python2.7/site-packages/ecflow
-
diff --git a/ecflow_4_0_7/configure.sh b/ecflow_4_0_7/configure.sh
deleted file mode 100755
index f8deb30..0000000
--- a/ecflow_4_0_7/configure.sh
+++ /dev/null
@@ -1,69 +0,0 @@
-#!/bin/sh
-
-# ======================================================================
-# Use for install of ecflow using cmake and ecbuild(bundled with ecflow)
-# External requirements: cmake, boost
-# export WK=<source root of ecflow> i.e
-# /var/tmp/fred/ecflow_4_0_7
-
-# assumes ecbuild is parallel to the source
-# Will by default create a build directory parallel to source directory, i.e.
-# /var/tmp/fred/cmake_build_dir
-#
-
-# Requires: users to set INSTALL_PREFIX,
-# This needs to be set to path where you want to install
-INSTALL_PREFIX=/var/tmp/ma0/cmake/ecflow
-
-
-# =====================================================================
-# At least one argument expected:
-if [ "$#" -ne 1 ] ; then
- echo "configure.sh expects 1 argument i.e"
- echo " configure.sh <prefix-dir>"
- echo " configure.sh /usr/local/apps/ecflow"
- exit 1
-fi
-INSTALL_PREFIX=$1
-
-# ==================================================================
-# Error handling
-set -e # stop the shell on first error
-set -u # fail when using an undefined variable
-set -x # echo script lines as they are executed
-
-# ===================================================================
-# Version number
-cd $WK
-release=$(cat VERSION.cmake | grep 'set( ECFLOW_RELEASE' | awk '{print $3}'| sed 's/["]//g')
-major=$(cat VERSION.cmake | grep 'set( ECFLOW_MAJOR' | awk '{print $3}'| sed 's/["]//g')
-minor=$(cat VERSION.cmake | grep 'set( ECFLOW_MINOR' | awk '{print $3}'| sed 's/["]//g')
-
-# ===================================================================
-# Build directory
-cd ..
-mkdir -p cmake_build_dir/ecflow/release
-cd cmake_build_dir/ecflow/release
-
-
-# ===================================================================
-# Configuration
-
-# BOOST_ROOT:
-# By default it looks for environment variable BOOST_ROOT, if not it can specified on the command line. i.e
-# -DBOOST_ROOT=/var/tmp/ma0/boost/boost_1_53_0
-
-# Python:
-# -DCMAKE_PYTHON_INSTALL_TYPE = [ local | setup ]
-# local : this will install to $INSTALL_PREFIX/$release.$major.$minor/lib/python2.7/site-packages/ecflow/
-# setup : experimental only,python way of installing
-#
-# -DCMAKE_PYTHON_INSTALL_PREFIX should *only* used when using python setup.py (CMAKE_PYTHON_INSTALL_TYPE=setup)
-# *AND* for testing python install to local directory
-
-cmake $WK \
- -DCMAKE_MODULE_PATH=$WK/../ecbuild/cmake \
- -DCMAKE_BUILD_TYPE=Release \
- -DCMAKE_INSTALL_PREFIX=$INSTALL_PREFIX/$release.$major.$minor \
- -DCMAKE_PYTHON_INSTALL_TYPE=local
- #-DCMAKE_PYTHON_INSTALL_PREFIX=$INSTALL_PREFIX/$release.$major.$minor/lib/python2.7/site-packages/ecflow
diff --git a/ecflow_4_0_7/tools/ecf_cmd b/ecflow_4_0_7/tools/ecf_cmd
deleted file mode 100755
index f4ee8bb..0000000
--- a/ecflow_4_0_7/tools/ecf_cmd
+++ /dev/null
@@ -1,868 +0,0 @@
-#!/bin/ksh
-#==========================================================================
-##.TITLE EMOS - METAPS utilities
-##.NAME sms_submit
-##.SECTION EMOS
-##.DATE 2005-09-12
-##.VERSION 1.0
-#==========================================================================
-
-##$ sms_submit user host file
-##
-##? Decides according to host argument which submit method to use.
-
-# Modifications:
-
-# Error handling and cleanup
-export SGE_ROOT=/usr/local/apps/sge
-export SLURM_ROOT=/usr/local/apps/slurm/current/bin
-export LL_ROOT=/usr/lpp/LoadL/full/bin
-STANDALONE=/usr/local/apps/sms/bin/standalone
-RUNSHELL=/bin/ksh
-TIMEOUT=300 # timeout period (seconds)
-SSH="ssh -o ConnectTimeout=$TIMEOUT -o BatchMode=yes -o StrictHostKeyChecking=no "
-RSH=rsh
-PROFILE=". $HOME/.profile"
-type rsh > /dev/null || RSH=$SSH
-
-#--------------------------------------------------------------------------
-# Parameters for ecrcmd
-#--------------------------------------------------------------------------
-
-SSH="ssh -o ConnectTimeout=$TIMEOUT -o BatchMode=yes -o StrictHostKeyChecking=no "
-
-ERROR() {
- err=$?
- echo "ERROR $0: $* $? - Exiting."
- # CP_SUB
-
- [[ -f $subfile ]] && grep "has been submitted" $subfile && exit 0
- [[ -f $subfile ]] && grep "Submitted batch job" $subfile && exit 0
-# Unable to run job: failed receiving gdi request # TBD OK
- cat $subfile
- exit $err
-}
-
-kill_submitted_and_abort() {
- # not used while not deterministic: job may run in betweem and
- # become a zombie
- outf=$TMPDIR/kill$$
- if [[ $? == 0 ]] && [[ -d $TMPDIR ]] ; then
- touch $outf
- grep "ECF_NODE=" ${subfile%.sub} > $outf && \
- grep "ECF_PORT=" ${subfile%.sub} >> $outf && \
- grep "ECF_NAME=" ${subfile%.sub} >> $outf && \
- grep "ECF_PASS=" ${subfile%.sub} >> $outf && \
- echo "export ECF_NODE ECF_PORT ECF_NAME ECF_PASS" >>$outf &&\
- echo "ecflow_client --abort || :" >> $outf && . $outf
- grep "^SMSNODE=" ${subfile%.sub} > $outf && \
- grep "^SMS_PROG=" ${subfile%.sub} >> $outf && \
- grep "^SMSNAME=" ${subfile%.sub} >> $outf && \
- grep "^SMSPASS=" ${subfile%.sub} >> $outf && \
- echo "export SMSNODE SMS_PROG SMSNAME SMSPASS " >> $outf && \
- echo "smsabort || :" >> $outf && . $outf
- ksh -x $outf
- rm -f $outf
- fi
-}
-
-kill_nqs() {
- if [[ -s $subfile ]] ; then
- tid=$(tail -1 $subfile | cut -d\. -f1 )
- # tid=`tail -1 $subfile | cut -d\. -f1 `
- # where=`tail -1 $subfile | cut -d\. -f2 `
- $RSH $host -l $user qsig -s 2 $tid || qsig -s 2 $tid
- $RSH $host -l $user qdel -W 10 $tid || qdel -W 10 $tid
-
- elif [[ -s $4 ]] ; then
- tid=$(grep PBS_JOB ${4}.1 | cut -d= -f2)
- $RSH $host -l $user qsig -s 2 $tid
- $RSH $host -l $user qdel -W 10 $tid
-
- else
- # Signal the job
- $RSH $host -l $user qsig -s 2 $smsid
-
- # Remove the job from PBS (give 10 ssmeconds delay for the above to finish)
- $RSH $host -l $user qdel -W 10 $smsid
- fi
-}
-
-kill_vpp() {
- $RSH $host -l $user qdel -2 $smsid
-}
-
-kill_nqs() {
- $RSH $host -l $user qdel -2 $smsid
-}
-
-kill_sge() {
- use sge || :
- QDEL=sge_qdel
- type $QDEL || QDEL="ssh $host $SGE_ROOT/sge6_2u5/bin/lx24-amd64/qdel"
- if [[ -s $subfile ]] then
- tid=$(grep " has been submitted" $subfile | cut -f 3 -d" ")
- $QDEL $tid
- elif [[ -s $4 ]] ; then
- tid=$(grep active_jobs $4 | grep cd | cut -d"." -f 2 | cut -d"/" -f8)
- $QDEL $tid
- else
- $QDEL $smsid
- fi
-}
-
-kill_new_linux() {
- tid=$(grep " has been submitted" $subfile | cut -f 3 -d" ")
- $SSH $host -l $user $SGE_ROOT/sge6_2u5/bin/lx24-amd64/qdel $tid
-}
-
-kill_ll() {
- if [[ -s $subfile ]] then
- tid=$(grep " has been submitted." $subfile | cut -d\" -f2)
- $RSH $host -l $user $LL_ROOT/llcancel $tid
- else
-
- if [[ "$host" == hpc* ]] ; then
- host=$(echo $host | cut -c1-4)
- id=${host}0$(echo $smsid % 1000 | bc).$(echo $smsid / 1000 | bc)
- else
- id=$smsid
- if [[ -f $smsid ]] ; then
- grep "LOADL_STEP_ID=NOT_SET" $subfile && \
- id=$(grep JOB_ID= $subfile | cut -d= -f2) && \
- $RSH $host -l user kill -9 $id
- fi
- fi
-
- $RSH $host -l $user $LL_ROOT/llcancel $id
- fi
-}
-
-kill_slurm() {
- if [[ -s $subfile ]] then
- tid=$(grep "Submitted batch job " $subfile | awk '{print $4}')
- $SSH $host -l $user $SLURM_ROOT/scancel $tid
- else
- id=$smsid
- if [[ -f $smsid ]] ; then
- grep "LOADL_STEP_ID=NOT_SET" $subfile && id=$(grep JOB_ID= $subfile | \
- cut -d= -f2) && \
- $SSH $host -l $user kill -9 $id
- fi
-
- $SSH $host -l $user $SLURM_ROOT/scancel $id
- fi
-}
-
-kill_rsh() {
- $RSH $host -l $user /bin/kill -2 $smsid
- # SGI syntax: kill -signal -pgid
- $RSH $host -l $user kill -15 $smsid || kill -15 $smsid
-}
-
-status_pbs() {
-
- qstat=/usr/local/apps/propbs/bin/qstat
-
- if [[ -s $subfile ]] ; then
- display_subfile
- tid=$(tail -1 $subfile)
- elif [[ -s $smsjob ]] ; then
- tid=$(grep PBS_JOB ${smsjob}.1 | cut -d= -f2)
- else
- tid=$smsid
- fi
-
- banner "** output ** "
- $RSH $host -l $user tail -100 /var/spool/PBS/spool/${tid}* &
- wait
- banner "** qstat ** "
- $RSH $host -l $user $qstat -f $tid | grep $user && OK=OK &
-
-}
-
-status_vpp() {
- $RSH $host -l $user qstat $smsid | grep $user && OK=OK &
-}
-
-status_nqs() {
- $RSH $host -l $user qstat $smsid | grep $user && OK=OK &
-}
-
-status_swarm() {
-# use sge
- task_name=$(basename $smsjob | cut -d\. -f1)
- if [[ -s $subfile ]] then
- display_subfile
- tid=$(grep " has been submitted" $subfile | cut -f 3 -d" ")
- elif [[ -s $smsjob ]] ; then
- tid=$(grep active_jobs $smsjob | grep cd | cut -d"." -f 2 | cut -d"/" -f8)
- else
- tid=$smsrid
- fi
-
- printf "==============================================================\n"
- if [[ $host == @(lxa|lxb|lxab) ]] ; then
- cat $file | $SSH $host $SGR_ROOT/sge6_2u5/bin/lx24-amd64/qstat -u $user -f | \
- grep -E "$task_name|$tid" | grep $user && OK=OK
- cat $file | $SSH $host $SGE_ROOT/sge6_2u5/bin/lx24-amd64/qstat -j $tid && \
- print "$smsjob is there\n" || print "$smsjob not there ... \n"
- else
- qstat -u $user -f | grep -E "$task_name|$tid" | grep $user && OK=OK
- qstat -j $tid && print "$smsjob is there\n" || print "$smsjob not there ... \n"
- fi
- printf "==============================================================\n"
-}
-
-status_new_linux() {
- status_swarm
-}
-
-status_ll() {
- if [[ -s $subfile ]] then
- tid=$(grep " has been submitted." $subfile | cut -d\" -f2)
- host=$(echo $tid | cut -d\. -f1)
- host4=$(echo $host | cut -c1-4)
-
- $RSH $host $LL_ROOT/llq -f %id %jn %o %c %st %nh $tid | grep $user && OK=OK &
-
- else
-
- if [[ -s $smsjob ]] ; then
- host=$(grep HOST= $smsjob | cut -d= -f2)
- fi
-
- if [[ "$host" == hpc* ]] ; then
- host=$(echo $host | cut -c1-4)
- host4=$(echo $host | cut -c1-4)
- id=${host}0$(echo $smsid % 1000 | bc).$( echo $smsid / 1000 | bc)
- else
- id=$host.$smsid
- fi
-
- $RSH $host $LL_ROOT/llq -f %id %jn %o %c %st %nh $tid | grep $user
- fi
-}
-
-status_slurm() {
- if [[ -s $subfile ]] then
- display_subfile
- tid=$(grep "Submitted batch job" $subfile | cut -d' ' -f4)
- $SSH -l $user $host $SLURM_ROOT/scontrol show job -d $tid
- $SSH -l $user $host $SLURM_ROOT/squeue | grep $user | grep " $tid"
- elif [[ $host != $hostname ]] ; then
- $SSH -l $user $host "$0 $user $host $file $uout $smsid status"
- fi
-}
-
-status_rsh() {
- if [[ $smsid == 0 ]]; then echo "too early"; exit 0; fi
- $RSH $host -l $user ps -elf | grep " $user " | grep " $smsid " | grep -v " grep " && \
- $RSH $host -l $user ps --sid $smsid -f
-
- \ps -elf | grep " $user " | grep " $smsid " | grep -v " grep " && OK=OK &
- \ps --sid $smsid -f && OK=OK &
-}
-
-disp_subfile() {
- if [[ -s $subfile ]]; then # && [[ $OK = NOK ]] ; then
- ls -la $subfile
- # echo # grep "^# +++ hpc" $subfile
- cat $subfile
- # && type=ll
-fi
-}
-
-#--------------------------------------------------------------------------
-# Check the number of arguments
-#--------------------------------------------------------------------------
-
-set -x
-echo $0 $*
-
-if [ $# -lt 3 ] ; then
- echo
- echo "usage: $0 <user> <host> file remote_output [node_suffix]"
- echo
- echo "example: $0 uid ecgate task.job1"
- echo "while node_suffix is empty, host-batch node is the target, "
- echo " else \$node\$nodesuffix is the replacement target"
- echo
- exit 1
-fi
-
-set -x
-
-user=$1
-host=$2
-file=$3
-uout=$4
-node_suffix=$5
-smsid=$5
-
-for last; do true; done # last shall be submit status kill only
-case $last in
-submit | status | kill ) echo;;
-*) last="submit" ;;
-esac
-
-subfile=${file}.sub
-
-#--------------------------------------------------------------------------
-# determine queuing system from hostname
-# (can be replaced by a more refined method later...)
-#--------------------------------------------------------------------------
-
-hostname=$(hostname)
-
-case $host in
- bilbo | belegorn | boromir | denethor | faramir | acq | pp1 | diss) type=pbs;;
- vpp* ) type=vppnqs;;
- swarm | linux_cluster | lxa | lxb | lxab ) type=sge_qsub;;
- ecgate1 | ecgb* | ecgt* ) type=slurm;;
- ecgate | ecga* | c2* ) type=ll;;
- $hostname | localhost ) type=local;;
- datasvc) type=ssh;;
- * ) type=rsh;;
-esac
-
-# if [[ $type = "local" ]] && [[ $hostname = @(ecg*|vsms*) ]]; then type=ssh; fi
-
-#--------------------------------------------------------------------------
-# determine job file type and output directory
-#--------------------------------------------------------------------------
-
-output=""
-if egrep -i "^#.*QSUB " $file > /dev/null ; then
- jtype=nqs
- output=$(egrep -i "^#.*QSUB -o" $file | cut -d" " -f 4 | head -1)
-
-elif egrep -i "^#.*@.*queue" $file > /dev/null ; then
- jtype=ll
- output=$(egrep -i "^#.*@.*output" $file | cut -d"=" -f 2 | head -1)
-
-elif [[ $host == @(ecgb*|ecgt0*|ecgate1) ]] ; then
- jtype=slurm
- output=$(egrep -i "^#.*-o" $file | cut -d" " -f 3 | head -1)
-
-elif egrep -i "^#.*PBS " $file > /dev/null ; then
- jtype=pbs
-
-elif egrep -i "^#.*SBATCH " $file > /dev/null ; then
- jtype=slurm
- output=$(egrep -i "^#.*-o" $file | cut -d" " -f 3 | head -1)
- if [[ output == "" ]]; then
- output=$(egrep -i "^#.*-output" $file | cut -d" " -f 3 | head -1)
- fi
- if [[ output == "" ]]; then output=$uout; fi
- if [[ output != "" ]]; then
- head -1 $output && grep "#!/" && RUNSHELL=$(head -1 $output | cut -d! -f2)
- else
- RUNSHELL="/bin/bash"
- fi
- case $RUNSHELL in
- *tcsh) PROFILE=". $HOME/.tcshrc";;
- *csh) PROFILE=". $HOME/.cshrc";;
- esac
-elif [[ $host == @(linux_cluster|lxa|lxb|lxab|swarm) ]] ; then
- jtype=sge_qsub
- output=$(egrep -i "^#.*-o" $file | cut -d" " -f 3 | head -1)
-
-else
- jtype=sh
-
-fi
-
-case $last in
-submit)
-#--------------------------------------------------------------------------
-# File must exist!
-#--------------------------------------------------------------------------
-
-if [[ ! -f $file ]] ; then
- echo "$0: File $file not found?"
- exit 1
-fi
-
-chmod 755 $file
-
-if [[ "$uout" != "" ]]; then output=$uout; mkdir -p $(dirname $uout); fi
-if [[ $output == *0.0 ]]; then echo "filename error $output"; exit 1; fi
-cp $file ${file}.pre
-# mailx -s "o:$output uo:$uout" $USER < /dev/null; exit 0
-
-LC="-c "
-if egrep -qi "^[[:space:]]*#[[:space:]]*@[[:space:]]*environment[[:space:]]*=" $file > /dev/null
-then
- LC="-lc "
-fi
-
-[[ "$output" == "" ]] || outputdir=$(dirname $output)
-if [[ "$outputdir" != "" ]] ; then
-#--------------------------------------------------------------------------
-# Create the output directory if it can be found
-#--------------------------------------------------------------------------
-if [[ ! -d $outputdir ]] ; then
- # don't worry anymore about output directory
- $RSH $host -l $user mkdir -m 775 -p $outputdir || \
- mkdir -m 775 -p $outputdir || /bin/true
-fi
-fi
-;;
-esac
-
-case $type in
-#==========================================================================
-# Submit to hp using PBS
- pbs )
-#==========================================================================
-
-case $last in
-kill) kill_pbs; exit 0;;
-status) status_pbs; exit 0;;
-esac
-
-# get queue-name, job-name
-if [[ $jtype == nqs ]] ; then
- queue=$(grep 'QSUB -q ' $file | cut -d" " -f 4 | head -1)
- jname=$(grep 'QSUB -r ' $file | cut -d" " -f 4 | head -1)
-
-elif [[ $jtype == ll ]] ; then
- queue=$(egrep '^#.*@.*class.*=' $file | cut -d"=" -f 2 | head -1)
- jname=$(egrep '^#.*@.*job_name.*=' $file | cut -d"=" -f 2 | head -1)
-
-elif [[ $jtype != pbs ]] ; then
- ERROR "No conversion available for these types ($jtype -> $type)."
-fi
-
-#--------------------------------------------------------------------------
-# Create the script (${file}__) that will contain the PBS directives
-#--------------------------------------------------------------------------
-
-if [[ $jtype != pbs ]] ; then
-
-cat > ${file}__ <<- EOF
-#!$RUNSHELL
-if [[ -f $HOME/.profile ]]; then
-$PROFILE
-fi
-#PBS -S /bin/ksh
-#PBS -N $jname
-#PBS -V
-#PBS -o /dev/null
-#PBS -e /dev/null
-#PBS -j oe
-#PBS -u $user
-#PBS -q $queue
-EOF
-
- egrep -v '^#.*QSUB -|^:$|^#.*@' $file >> ${file}__
-
- mv -f ${file}__ ${file}
-
-fi
-#--------------------------------------------------------------------------
-# Remote shell to $host and submit from there
-#--------------------------------------------------------------------------
-
-#rsh $host -l $user /usr/local/apps/propbs/bin/pbsqsub < $file || ERROR "Failed to submit job to PBS (possible failure of rsh)."
-
-if [[ $(uname -n) == @(ecgb*|vsms*|sms-map) ]]; then
- $SSH -l $user $host /usr/local/apps/propbs/bin/pbsqsub -f $file > $subfile 2>&1 || \
- ERROR "Failed to submit job to PBS. "
-else
- ecrcmd --timeout=$TIMEOUT < $file $user@$host $LC \
- /usr/local/apps/propbs/bin/pbsqsub -f $file > $subfile || \
- ERROR "Failed to submit job to PBS."
-fi
-
- ;;
-#==========================================================================
-# Submit to vpp using NQS
- vppnqs )
-#==========================================================================
-
-case $last in
-kill) kill_vpp; exit 0;;
-status) status_vpp; exit 0;;
-esac
-
-if [[ $jtype == ll ]] ; then
- /home/ma/emos/bin/ll2nqs.pl $file ${file}__ || ERROR "Conversion ll2nqs.pl failed."
- mv -f ${file}__ $file
-
-elif [[ $jtype != nqs ]] ; then
- ERROR "No conversion available for these types ($jtype -> $type)."
-
-else
- grep -v "QSUB -p" $file | grep -v "QSUB -lh" > ${file}__
- mv -f ${file}__ $file
-fi
-
-#--------------------------------------------------------------------------
-# Send the file using qsub
-# If send failed, sleep a while and try again, until maximum number of
-# tries.
-#--------------------------------------------------------------------------
-
-$SSH $host -l $user /usr/local/bin/vppqsub < $file | grep -i submitted > $subfile || \
- ERROR "Failed to submit $file."
-
- ;;
-#==========================================================================
- sge_qsub ) # swarm linux cluster
-
-case $last in
-kill) kill_sge; exit 0;;
-status) status_sge; exit 0;;
-esac
-
-# get queue-name, job-name
-if [[ $jtype == nqs ]] ; then
- queue=$(grep 'QSUB -q ' $file | cut -d" " -f 4 | head -1)
- jname=$(grep 'QSUB -r ' $file | cut -d" " -f 4 | head -1)
-
-elif [[ $jtype == ll ]] ; then
- queue=$(egrep '^#.*@.*class.*=' $file | cut -d"=" -f 2 | head -1)
- jname=$(egrep '^#.*@.*job_name.*=' $file | cut -d"=" -f 2 | head -1)
-
-elif [[ $jtype != sge_qsub ]] ; then
- ERROR "No conversion available for these types ($jtype -> $type)."
-fi
-
-#--------------------------------------------------------------------------
-# Create the script (${file}__) that will contain the PBS directives
-#--------------------------------------------------------------------------
-
-# if [[ $jtype != sge_qsub ]] ; then
-
- queue=$(grep 'QSUB -q ' $file | cut -d" " -f 4 | head -1)
-
-cat > ${file}__ <<- EOF
-#\$ -S /home/ma/emos/bin/ksh
-#\$ -N ${jname}
-#\$ -V
-#\$ -o $output
-#\$ -j y
-#\$ -u $user
-#\$ -q $queue
-EOF
-
- egrep -v '^#.*QSUB -|^:$|^#.*@' $file >> ${file}__
- chmod 755 ${file}__
- mv -f ${file}__ ${file}
-
-# fi
-
- mkdir -m 775 -p $outputdir || /bin/true
- if [[ $host == @(lxa|lxb|lxab) ]] ; then
- cat $file | $SSH $host \
- $SGE_ROOT/sge6_2u5/bin/lx24-amd64/qsub -notify > $subfile 2>&1 || \
- ERROR "Job submission failed (${file}__)."
- elif [[ $HOST == @(ibis|pikachu) ]] ; then
- cat $file | $RSH drn01 \
- SGE_ROOT=$SGE_ROOT $SGE_ROOT/bin/lx24-amd64/qsub -notify > $subfile 2>&1 || \
- ERROR "Job submission failed (${file}__)."
- elif [[ -d $SGE_ROOT ]]; then
- /usr/local/share/sge_qsub -notify $file > $subfile 2>&1 || \
- ERROR "Job submission failed (${file}__)."
- else
- cat $file | $SSH drn01 \
- ${SGE_ROOT:=/usr/local/apps/sge}/bin/lx24-amd64/qsub -notify > $subfile 2>&1 || \
- cat $file | $SSH drn01 \
- SGE_ROOT=$SGE_ROOT $SGE_ROOT/bin/lx24-amd64/qsub -notify $file > $subfile 2>&1 || \
- ERROR "Job submission failed (${file}__)."
-
- # || ERROR "Job submission failed (${file}__)."
- fi
-# sge_qsub -notify $file > $subfile || ERROR "Job submission failed (${file}__)."
- ;;
-
-#==========================================================================
-# Submit to other workstation using NQS
- nqs )
-#==========================================================================
-
-case $last in
-kill) kill_nqs; exit 0;;
-status) status_nqs; exit 0;;
-esac
-
-#--------------------------------------------------------------------------
-# Create the script (${file}__) that will run the qsub
-#--------------------------------------------------------------------------
-
-cat > ${file}__ <<- EOF
-#!/bin/ksh
-unset WAITQUEUE
-set -e
-EOF
-
-# qsub statement
-echo "/usr/local/share/qsub < ${file}" >> ${file}__
-
-#
-# Create the real request
-#
-grep -v "QSUB -A" $file | grep -v "QSUB -lh" | grep -v "QSUB -p" | grep -v "QSUB -u" > ${file}__.qsub
-mv -f ${file}__.qsub ${file}
-
-#--------------------------------------------------------------------------
-# Remote shell to $host and submit from there
-#--------------------------------------------------------------------------
-chmod +x ${file}__
-$SSH $host -l $user -n "${file}__" || ERROR "Job submission failed (${file}__)."
-
-sleep 10
-/bin/rm -f ${file}__
-
- ;;
-#==========================================================================
-# Submit to IBM server using loadleveler
- ll )
-#==========================================================================
-
-case $last in
-kill) kill_ll; exit 0;;
-status) status_ll; exit 0;;
-esac
-
-if [[ $jtype == nqs ]] ; then
- #
- # Create the real request
- #
- /home/ma/emos/bin/nqs2ll.pl $host $file ${file}__ || ERROR "Conversion nqs2ll.pl failed."
- if [[ "$uout" != "" ]]; then
- cat ${file}__ | sed -e "s:# @ output = .*:# @ output = $output:" | \
- sed -e "s:# @ error .*:# @ error = $output:" > ${file}
- else
- mv -f ${file}__ ${file}
- fi
-
-elif [[ $jtype != ll ]] ; then
- ERROR "No conversion available for these types ($jtype -> $type)."
-fi
-#--------------------------------------------------------------------------
-# Remote shell to $host and submit from there
-#--------------------------------------------------------------------------
-
-if [[ $host == @(c2*) ]] ; then
- # file="/ws$file"
- if [[ $node_suffix == "" ]] ; then
- host="${host}-batch"
- else
- host="${host}${node_suffix}"
- fi
-fi
-
-if [[ $(uname -n) == @(ecgb*|vsms*|sms-map) ]]; then
- $SSH -l $user ${host} \
- "unset WAITQUEUE ; $LL_ROOT/llsubmit - 2>&1 " < $file > $subfile 2>&1 || \
- ERROR "Failed to submit job to LoadLeveler. $?"
-else
- ecrcmd --timeout=$TIMEOUT < $file $user@$host $LC \
- "unset WAITQUEUE ; $LL_ROOT/llsubmit -" > $subfile || \
- ERROR "Failed to submit job to LoadLeveler."
-fi
-
- ;;
-
- slurm ) # swarm linux cluster
-
-case $last in
-kill) kill_slurm; exit 0;;
-status) status_slurm; exit 0;;
-esac
-
-# get queue-name, job-name
-if [[ $jtype == nqs ]] ; then
- queue=$(grep 'QSUB -q ' $file | cut -d" " -f 4 | head -1)
- jname=$(grep 'QSUB -r ' $file | cut -d" " -f 4 | head -1)
-
-# srun sinfo
- cat > ${file}__ <<- EOF
-#!$RUNSHELL
-#SBATCH --output=${output:-/dev/null}
-#SBATCH --error=${output:=/dev/null}
-#SBATCH --time=01:00:00
-#SBATCH --job-name=${jname}
-#SBATCH --get-user-env
-#SBATCH --uid=$user
-##BATCH --qos=normal # express/long
-$PROFILE
-EOF
-# cp $file ${file}.pre
- cat $file | egrep -v '^#.*QSUB -|^:$|^#.*@' | \
- grep -E -v '(^#.*SBATCH --output.*|#.*SBATCH --error.*|^#.*SBATCH --uid.*|^#.*SBATCH --qos.*)' >> ${file}__
- chmod 755 ${file}__
-
-elif [[ $jtype == slurm ]]; then
-
- cat > ${file}__ <<- EOF
-#!$RUNSHELL
-#SBATCH --output=${output:-/dev/null}
-#SBATCH --error=${output:-/dev/null}
-#SBATCH --time=01:00:00
-#SBATCH --job-name=${jname}
-#SBATCH --get-user-env
-#SBATCH --uid=$user
-##BATCH --qos=normal # express/long
-$PROFILE
-EOF
-# cp $file ${file}.pre
- cat $file | egrep -v '^#.*QSUB -|^:$|^#.*@' | \
- grep -E -v '(^#.*SBATCH --output.*|#.*SBATCH --error.*|^#.*SBATCH --uid.*|^#.*SBATCH --qos.*)' >> ${file}__
- chmod 755 ${file}__
-
-elif [[ $jtype == ll ]] ; then
- $PROFILE
- # /usr/local/apps/slurm/utils/bin/ll2slurm
- ll2slurm -q -i $file -o ${file}__ || ERROR "Job conversion to slurm failed (${file})."
-elif [[ $jtype != slurm ]]; then
- ERROR "No conversion available for these types ($jtype -> $type)."
-fi
-
-#--------------------------------------------------------------------------
-# Create the script (${file}__) that will contain the PBS directives
-#--------------------------------------------------------------------------
- mv ${file}__ $file
-
- if [[ $hostname == @(ecgb*|ecgate1) ]]; then
- touch $output
- $SLURM_ROOT/sbatch < ${file} > $subfile 2>&1 \
- || ERROR "Job submission failed (${file})."
- else
- $SSH $host -l $user touch $output
- cat ${file} | $SSH $host -l $user $SLURM_ROOT/sbatch > $subfile 2>&1 \
- || ERROR "Job submission failed (${file})."
- fi
-;;
-#==========================================================================
-# Submit using ssh
-#==========================================================================
- ssh )
-
-case $last in
-kill) kill_ssh; exit 0;;
-status) status_ssh; exit 0;;
-esac
-
- cmd="ssh $user@$host"
-#
-# Add the header with requested shell
-#
-
- cat > ${file}__ <<- EOF
-#!$RUNSHELL
-# output=$output
-$PROFILE
-EOF
-
-#
-# Add the real request removing all qsub statements
-#
-
-if [[ $jtype == ll ]] ; then
- egrep -v '^#.*@|^#!|^:$' $file >> ${file}__
-elif [[ $jtype == nqs ]] ; then
- egrep -v '^#.*QSUB|^#!|^:$' $file >> ${file}__
-elif [[ $jtype == slurm ]] ; then
- egrep -v '^#.*SBATCH|^#!|^:$' $file >> ${file}__
-elif [[ $jtype == pbs ]] ; then
- egrep -v '^#.*PBS|^#!|^:$' $file >> ${file}__
-fi
-
-#
-# Submit the job
-#
-$cmd "/usr/local/bin/standalone -o $output -s $RUNSHELL " < ${file}__ || ERROR "Job submission to ssh standalone failed."
-;;
-
-#==========================================================================
-# Submit to any other workstation using rsh standalone or
-# submit to local workstation using standalone
- rsh | local )
-#==========================================================================
-
-case $last in
-kill) kill_rsh; exit 0;;
-status) status_rsh; exit 0;;
-esac
-
-if [[ $type == local ]] ; then
- cmd=""
-elif [[ $hostname == @(ecgb*|vsms*) ]] ; then
- cmd="$SSH -l $user $host "
-else
- cmd="rsh $host -l $user "
-fi
-
-#
-# Add the header with requested shell
-#
-
-cat > ${file}__ <<- EOF
-#!$RUNSHELL
-# output=$output
-$PROFILE
-EOF
-#
-# Add the real request removing all qsub statements
-#
-
-if [[ $jtype == ll ]] ; then
- egrep -v '^#.*@|^#!|^:$' $file >> ${file}__
-
-elif [[ $jtype == nqs ]] ; then
- egrep -v '^#.*QSUB|^#!|^:$' $file >> ${file}__
-
-elif [[ $jtype == slurm ]] ; then
- egrep -v '^#.*SBATCH|^#!|^:$' $file >> ${file}__
-
-elif [[ $jtype == pbs ]] ; then
- egrep -v '^#.*PBS|^#!|^:$' $file >> ${file}__
-
-fi
-
-mv -f ${file}__ $file
-#
-# Submit the job
-#
-if [[ $type == local ]] ; then
-
- case $hostname in
- ecg* | vsms*) nohup $RUNSHELL -x $file > $output 2>&1 & ;;
- *) standalone -o $output -s $RUNSHELL < $file || ERROR "Job submission to standalone failed."
- ;;
- esac
-else
-
- case $hostname in
- ecg* | vsms*) # $cmd "nohup $RUNSHELL -x $file > $output 2>&1 &"
- $cmd "$STANDALONE -o $output -s $RUNSHELL" < $file > $subfile || \
- ERROR "Job submission to rsh standalone failed."
- ;;
- *)
- $cmd "/usr/local/bin/standalone -o $output -s $RUNSHELL" < $file > $subfile ||\
- ERROR "Job submission to rsh standalone failed."
- ;;
- esac
-fi
-
- ;;
-esac
-
-exit 0
-
-ssh-keygen -t dsa
-scp ~/.ssh/id_dsa.pub ecgate:.ssh/authorized_keys2
-ssh-agent sh -c 'ssh-add < /dev/null && bash'
-
-
-ssh-keygen -t rsa
-ssh server "mkdir .ssh; chmod 0700 .ssh"
-scp .ssh/id_rsa.pub server:.ssh/authorized_keys2
-scp $HOME/.ssh/id_rsa.pub c2a:$HOME/.ssh/authorized_keys2
-scp $HOME/.ssh/id_rsa.pub c2b:$HOME/.ssh/authorized_keys2
-
-cp $HOME/.ssh/id_rsa.pub $HOME/.ssh/authorized_keys2
diff --git a/ecflow_4_0_7/tools/ecf_kill b/ecflow_4_0_7/tools/ecf_kill
deleted file mode 100755
index 03fc5bd..0000000
--- a/ecflow_4_0_7/tools/ecf_kill
+++ /dev/null
@@ -1,243 +0,0 @@
-#!/bin/ksh
-#==========================================================================
-##.TITLE EMOS - METAPS utilities
-##.NAME smskill
-##.SECTION EMOS
-##.AUTHOR Manuel Fuentes
-##.DATE 2001-11-20
-##.VERSION 1.0
-##.FILE ~emos/bin/smskill
-##.ORIGIN wssubmit
-#==========================================================================
-##$ smskill user host
-##
-##? Decides according to host argument which kill method to use.
-
-# Modifications:
-
-#--------------------------------------------------------------------------
-# Check the number of arguments
-#--------------------------------------------------------------------------
-export SLURM_ROOT=/usr/local/apps/slurm/current/bin
-RSH=rsh
-type rsh || RSH=ssh
-
-set -x
-
-if [ $# -lt 3 ] ; then
- echo "usage: $0 <user> <host> <smsid> [ smsjob ]"
- echo "example: $0 emos leda 12345"
- echo "example: $0 emos leda 12345 smsjob"
- exit 1
-fi
-
-user=$1
-host=$2
-smsid=$3
-
-subfile=${4}.sub
-
-#--------------------------------------------------------------------------
-# determine queuing system from hostname
-# (can be replaced by a more refined method later...)
-#--------------------------------------------------------------------------
-
-hostname=$(hostname)
-
-case $host in
- ha-pp | happ | ha_pp | celeborn | elrond | altariel | frodo | bilbo | belegorn | boromir | denethor | faramir | acq | acq2 | pp1 | pp2 | diss | pp3 | hallas )
- type=pbs
- ;;
- vpp* ) type=vppnqs ;;
- icarus ) type=nqs ;;
- ecgate1 | ecgb* ) type=slurm;;
- ecgate | ecga* | c2*) type=ll;;
- lxa | lxb | lxab ) type=new_linux ;;
- swarm | linux_cluster ) type=swarm ;;
- $hostname | localhost )
- type=local
- ;;
- * )
- type=rsh
- ;;
-esac
-
-
-case $type in
-#==========================================================================
-# Kill on hp using PBS
- pbs )
-#==========================================================================
-
- if [[ -s $subfile ]] ; then
- tid=`tail -1 $subfile | cut -d\. -f1 `
- # tid=`tail -1 $subfile | cut -d\. -f1 `
- # where=`tail -1 $subfile | cut -d\. -f2 `
- # rsh $where -l $user qsig -s 2 $tid
- # rsh $where -l $user qdel -W 10 $tid
- qsig -s 2 $tid
- qdel -W 10 $tid
-
- elif [[ -s $4 ]] ; then
- tid=`grep PBS_JOB ${4}.1 | cut -d= -f2`
- $RSH $host -l $user qsig -s 2 $tid
- $RSH $host -l $user qdel -W 10 $tid
-
- else
- # Signal the job
- $RSH $host -l $user qsig -s 2 $smsid
-
- # Remove the job from PBS (give 10 seconds delay for the above to finish)
- $RSH $host -l $user qdel -W 10 $smsid
- fi
-
- ;;
-#==========================================================================
-# Kill on vpp using NQS
- vppnqs )
-#==========================================================================
-
- $RSH $host -l $user qdel -2 $smsid
- ;;
-#==========================================================================
-# Kill on workstations using NQS
- nqs )
-#==========================================================================
-
- $RSH $host -l $user qdel -2 $smsid
-
- ;;
-#==========================================================================
-# Kill on linux cluster
-#==========================================================================
- swarm )
-
- use sge
- if [[ -s $subfile ]] then
- tid=`grep " has been submitted" $subfile | cut -f 3 -d" "`
- sge_qdel $tid
- if [[ $? = 0 ]] && [[ -d $TMPDIR ]] ; then
- touch $TMPDIR/kill$$
- grep "^SMSNODE=" ${subfile%.sub} > $TMPDIR/kill$$ && \
- grep "^SMS_PROG=" ${subfile%.sub} >> $TMPDIR/kill$$ && \
- grep "^SMSNAME=" ${subfile%.sub} >> $TMPDIR/kill$$ && \
- grep "^SMSPASS=" ${subfile%.sub} >> $TMPDIR/kill$$ && \
- echo "export SMSNODE SMS_PROG SMSNAME SMSPASS " >> $TMPDIR/kill$$ && \
- echo "smsabort " >> $TMPDIR/kill$$ && . $TMPDIR/kill$$
- rm -f $TMPDIR/kill$$
- fi
-
- elif [[ -s $4 ]] ; then
- tid=`grep active_jobs $4 | grep cd | cut -d"." -f 2 | cut -d"/" -f8`
- sge_qdel $tid
- else
- sge_qdel $smsid
- fi
-
- ;;
- new_linux )
-
- tid=`grep " has been submitted" $subfile | cut -f 3 -d" "`
- ssh $host /usr/local/apps/sge/sge6_2u5/bin/lx24-amd64/qdel $tid
-
- ;;
-
-#==========================================================================
-# Kill on workstations using load leveler
- ll )
-#==========================================================================
-
- if [[ -s $subfile ]] then
- tid=`grep " has been submitted." $subfile | cut -d\" -f2`
- $RSH $host -l $user /usr/lpp/LoadL/full/bin/llcancel $tid
-
- if [[ $? = 0 ]] && [[ -d $TMPDIR ]] ; then
- touch $TMPDIR/kill$$
- grep "^SMSNODE=" ${subfile%.sub} > $TMPDIR/kill$$ && \
- grep "^SMS_PROG=" ${subfile%.sub} >> $TMPDIR/kill$$ && \
- grep "^SMSNAME=" ${subfile%.sub} >> $TMPDIR/kill$$ && \
- grep "^SMSPASS=" ${subfile%.sub} >> $TMPDIR/kill$$ && \
- echo "export SMSNODE SMS_PROG SMSNAME SMSPASS " >> $TMPDIR/kill$$ && \
- echo "smsabort " >> $TMPDIR/kill$$ && . $TMPDIR/kill$$
- rm -f $TMPDIR/kill$$
- fi
-
- else
-
- if [[ "$host" = hpc* ]] ; then
- host=`echo $host | cut -c1-4`
- id=${host}0`echo $smsid % 1000 | bc`.` echo $smsid / 1000 | bc`
- else
- id=$smsid
- if [[ -f $smsid ]] ; then
- grep "LOADL_STEP_ID=NOT_SET" $subfile && id=`grep JOB_ID= $subfile | cut -d= -f2` && $RSH $host -l user kill -9 $id
- fi
- fi
-
- $RSH $host -l $user /usr/lpp/LoadL/full/bin/llcancel $id
- fi
-
- ;;
-
- slurm )
-#==========================================================================
-
- if [[ -s $subfile ]] then
- tid=`grep "Submitted batch job " $subfile | awk '{print $4}'`
- ssh $host -l $user $SLURM_ROOT/scancel $tid
-
- if [[ $? = 0 ]] && [[ -d $TMPDIR ]] ; then
- touch $TMPDIR/kill$$
- grep "^SMSNODE=" ${subfile%.sub} > $TMPDIR/kill$$ && \
- grep "^SMS_PROG=" ${subfile%.sub} >> $TMPDIR/kill$$ && \
- grep "^SMSNAME=" ${subfile%.sub} >> $TMPDIR/kill$$ && \
- grep "^SMSPASS=" ${subfile%.sub} >> $TMPDIR/kill$$ && \
- echo "export SMSNODE SMS_PROG SMSNAME SMSPASS " >> $TMPDIR/kill$$ && \
- echo "smsabort " >> $TMPDIR/kill$$ && . $TMPDIR/kill$$
- rm -f $TMPDIR/kill$$
- fi
-
- else
-
- id=$smsid
- if [[ -f $smsid ]] ; then
- grep "LOADL_STEP_ID=NOT_SET" $subfile && id=`grep JOB_ID= $subfile | cut -d= -f2` && $RSH $host -l user kill -9 $id
- fi
-
- ssh $host -l $user $SLURM_ROOT/scancel $id
- fi
-
- ;;
-#==========================================================================
-# Kill on any other workstation using rsh standalone
- rsh )
-#==========================================================================
-
-# Testing linux platforms
-if [[ $host = "selene" ]]
-then
- # This doesn't work. COME BACK HERE
- $RSH $host -l $user /bin/kill -s 2 $smsid
-else
- # SGI syntax: kill -signal -pgid
- $RSH $host -l $user kill -15 $smsid
-fi
-
- ;;
-#==========================================================================
-# Kill on local workstation using standalone
- local )
-#==========================================================================
-
- kill -15 $smsid
- ;;
-
-esac
-#-------------
-# Sleep a bit
-#-------------
-
-sleep 2
-
-exit 0
-
diff --git a/ecflow_4_0_7/tools/ecf_status b/ecflow_4_0_7/tools/ecf_status
deleted file mode 100755
index 0f5788f..0000000
--- a/ecflow_4_0_7/tools/ecf_status
+++ /dev/null
@@ -1,209 +0,0 @@
-#!/bin/ksh
-#==========================================================================
-##.TITLE EMOS - METAPS utilities
-##.NAME smsstatus
-##.SECTION EMOS
-##.AUTHOR Axel Bonet
-##.DATE 2006-02-08
-##.VERSION 1.0
-##.FILE ~emos/bin/smsstatus
-##.ORIGIN smskill
-#==========================================================================
-##$ smsstatus user host smsrid smsjob
-##
-##? Decides according to host argument which stat command to use.
-
-# Modifications:
-
-#--------------------------------------------------------------------------
-# Check the number of arguments
-#--------------------------------------------------------------------------
-export SLURM_ROOT=/usr/local/apps/slurm/current/bin
-SSH=ssh
-RSH=rsh
-type rsh || RSH=ssh
-
-echo $0 $* ; # echo ;
-date ; echo
-set -xv
-
-if [ $# -lt 4 ] ; then
- echo "usage: $0 <user> <host> <smsid> <smsjob>"
- echo "example: $0 emos leda 12345 smsjob"
- exit 1
-fi
-
-user=$1
-host=$2
-smsid=$3
-smsjob=$4
-subfile=${smsjob}.sub
-
-#--------------------------------------------------------------------------
-# determine queuing system from hostname
-# (can be replaced by a more refined method later...)
-#--------------------------------------------------------------------------
-
-hostname=$(hostname)
-
-case $host in
- happ | happ2 | celeborn | elrond | altariel | frodo | bilbo | belegorn | boromir | denethor | faramir | hallas | acq | pp1 | diss | acq2 | pp2 | acq3 | pp3 )
- type=pbs;;
- swarm | linux_cluster | lxa | lxb | lxab ) type=swarm;;
-
- ecgate1 | ecgb* ) type=slurm;;
-
- ecgate | ecga* | c2* ) type=ll;;
- $hostname | localhost | diomedes | ariel | osiris | adam | lenny )
- type=local;;
- datasvc | wedit | indigo | cassini | suse91 | stratos | katana | vali | mordred | ablamor | ibis | lenny )
- type=ssh;;
- * )
- type=rsh
- ;;
-esac
-
-OK=NOK
-
-case $type in
-#==========================================================================
- pbs )
-#==========================================================================
-
- qstat=/usr/local/apps/propbs/bin/qstat
-
- if [[ -s $subfile ]] ; then
- tid=$(tail -1 $subfile)
- elif [[ -s $smsjob ]] ; then
- tid=$(grep PBS_JOB ${smsjob}.1 | cut -d= -f2)
- else
- tid=$smsid
- fi
-
- banner "** output ** "
- $RSH $host -l $user tail -100 /var/spool/PBS/spool/${tid}*
- banner "** qstat ** "
- $RSH $host -l $user $qstat -f $tid | grep $user && OK=OK &
- ;;
-#==========================================================================
- vppnqs )
-#==========================================================================
-
- $RSH $host -l $user qstat $smsid | grep $user && OK=OK &
- ;;
-#==========================================================================
- nqs )
-#==========================================================================
-
- $RSH $host -l $user qstat $smsid | grep $user && OK=OK &
- ;;
-
-#==========================================================================
- swarm | linux_cluster | lxa | lxb | lxab )
-#==========================================================================
-# use sge
- task_name=$(basename $smsjob | cut -d\. -f1)
- if [[ -s $subfile ]] then
- tid=$(grep "Submitted batch job" $subfile | cut -f 3 -d" ")
- elif [[ -s $smsjob ]] ; then
- tid=$(grep active_jobs $smsjob | grep cd | cut -d"." -f 2 | cut -d"/" -f8)
- else
- tid=$smsrid
-fi
-
- printf "==============================================================\n"
-
- if [[ $host == @(lxa|lxb|lxab) ]] ; then
- cat $file | ssh $host /usr/local/apps/sge/sge6_2u5/bin/lx24-amd64/qstat -u $user -f | grep -E "$task_name|$tid" | grep $user && OK=OK
- cat $file | ssh $host /usr/local/apps/sge/sge6_2u5/bin/lx24-amd64/qstat -j $tid && print "$smsjob is there\n" || print "$smsjob not there ... \n"
- else
- qstat -u $user -f | grep -E "$task_name|$tid" | grep $user && OK=OK
- qstat -j $tid && print "$smsjob is there\n" || print "$smsjob not there ... \n"
- fi
-
- printf "==============================================================\n"
-
- ;;
-#==========================================================================
- ll )
-#==========================================================================
-
- if [[ -s $subfile ]] then
- tid=$(grep " has been submitted." $subfile | cut -d\" -f2)
- host=$(echo $tid | cut -d\. -f1)
- host4=$(echo $host | cut -c1-4)
-
-
- $RSH $host /usr/lpp/LoadL/full/bin/llq -f %id %jn %o %c %st %nh $tid | grep $user && OK=OK &
-
-else
-
- if [[ -s $smsjob ]] ; then
- host=$(grep HOST= $smsjob | cut -d= -f2)
- fi
-
- if [[ "$host" == hpc* ]] ; then
- host=$(echo $host | cut -c1-4)
- host4=$(echo $host | cut -c1-4)
- id=${host}0$(echo $smsid % 1000 | bc).$(echo $smsid / 1000 | bc)
- else
- id=$host.$smsid
- fi
-
- # rsh $host -l $user /usr/lpp/LoadL/full/bin/llq -x $id && OK=OK &
- $RSH $host /usr/lpp/LoadL/full/bin/llq -f %id %jn %o %c %st %nh $tid | grep $user && OK=OK &
- fi
- ;;
-#==========================================================================
- slurm )
-#==========================================================================
-
- if [[ -s $subfile ]] then
- tid=$(grep " has been submitted." $subfile | cut -d\" -f2)
- host=$(echo $tid | cut -d\. -f1)
- host4=$(echo $host | cut -c1-4)
- fi
-
- if [[ "$hostname" == @(ecgate1|ecgb*) ]] ; then
- $SLURM_ROOT/squeue | grep " $tid" | grep $user && OK=OK &
- else
- ssh -l $user $host $SLURM_ROOT/squeue | grep " $tid" | grep $user && OK=OK &
- fi
- ;;
-#==========================================================================
- rsh )
-#==========================================================================
-
- if [[ $smsid == 0 ]]; then echo "too early"; exit 0; fi
- $RSH $host -l $user ps -elf | grep " $user " | grep " $smsid " | grep -v " grep " && OK=OK 2>/dev/null &
-
- $RSH $host -l $user ps -sid $smsid -f && OK=OK &
-
- ;;
-#==========================================================================
- local )
-#==========================================================================
-
- # \ps -U $user -u $user -lf $smsid &
- if [[ $smsid == 0 ]]; then echo "too early"; exit 0; fi
- \ps -elf | grep " $user " | grep " $smsid " | grep -v " grep " && OK=OK &
- \ps -sid $smsid -f && OK=OK &
- ;;
-
- esac
-
-set +x
-display_subfile() {
- if [[ -s $subfile ]]; then # && [[ $OK = NOK ]] ; then
- ls -la $subfile
- # echo # grep "^# +++ hpc" $subfile
- cat $subfile
- # && type=ll
-fi
-}
-
-echo "$0 $* # $tid"
-display_subfile
-# wait
-
-exit 0
diff --git a/ecflow_4_0_7/tools/ecf_submit b/ecflow_4_0_7/tools/ecf_submit
deleted file mode 100755
index f4ee8bb..0000000
--- a/ecflow_4_0_7/tools/ecf_submit
+++ /dev/null
@@ -1,868 +0,0 @@
-#!/bin/ksh
-#==========================================================================
-##.TITLE EMOS - METAPS utilities
-##.NAME sms_submit
-##.SECTION EMOS
-##.DATE 2005-09-12
-##.VERSION 1.0
-#==========================================================================
-
-##$ sms_submit user host file
-##
-##? Decides according to host argument which submit method to use.
-
-# Modifications:
-
-# Error handling and cleanup
-export SGE_ROOT=/usr/local/apps/sge
-export SLURM_ROOT=/usr/local/apps/slurm/current/bin
-export LL_ROOT=/usr/lpp/LoadL/full/bin
-STANDALONE=/usr/local/apps/sms/bin/standalone
-RUNSHELL=/bin/ksh
-TIMEOUT=300 # timeout period (seconds)
-SSH="ssh -o ConnectTimeout=$TIMEOUT -o BatchMode=yes -o StrictHostKeyChecking=no "
-RSH=rsh
-PROFILE=". $HOME/.profile"
-type rsh > /dev/null || RSH=$SSH
-
-#--------------------------------------------------------------------------
-# Parameters for ecrcmd
-#--------------------------------------------------------------------------
-
-SSH="ssh -o ConnectTimeout=$TIMEOUT -o BatchMode=yes -o StrictHostKeyChecking=no "
-
-ERROR() {
- err=$?
- echo "ERROR $0: $* $? - Exiting."
- # CP_SUB
-
- [[ -f $subfile ]] && grep "has been submitted" $subfile && exit 0
- [[ -f $subfile ]] && grep "Submitted batch job" $subfile && exit 0
-# Unable to run job: failed receiving gdi request # TBD OK
- cat $subfile
- exit $err
-}
-
-kill_submitted_and_abort() {
- # not used while not deterministic: job may run in betweem and
- # become a zombie
- outf=$TMPDIR/kill$$
- if [[ $? == 0 ]] && [[ -d $TMPDIR ]] ; then
- touch $outf
- grep "ECF_NODE=" ${subfile%.sub} > $outf && \
- grep "ECF_PORT=" ${subfile%.sub} >> $outf && \
- grep "ECF_NAME=" ${subfile%.sub} >> $outf && \
- grep "ECF_PASS=" ${subfile%.sub} >> $outf && \
- echo "export ECF_NODE ECF_PORT ECF_NAME ECF_PASS" >>$outf &&\
- echo "ecflow_client --abort || :" >> $outf && . $outf
- grep "^SMSNODE=" ${subfile%.sub} > $outf && \
- grep "^SMS_PROG=" ${subfile%.sub} >> $outf && \
- grep "^SMSNAME=" ${subfile%.sub} >> $outf && \
- grep "^SMSPASS=" ${subfile%.sub} >> $outf && \
- echo "export SMSNODE SMS_PROG SMSNAME SMSPASS " >> $outf && \
- echo "smsabort || :" >> $outf && . $outf
- ksh -x $outf
- rm -f $outf
- fi
-}
-
-kill_nqs() {
- if [[ -s $subfile ]] ; then
- tid=$(tail -1 $subfile | cut -d\. -f1 )
- # tid=`tail -1 $subfile | cut -d\. -f1 `
- # where=`tail -1 $subfile | cut -d\. -f2 `
- $RSH $host -l $user qsig -s 2 $tid || qsig -s 2 $tid
- $RSH $host -l $user qdel -W 10 $tid || qdel -W 10 $tid
-
- elif [[ -s $4 ]] ; then
- tid=$(grep PBS_JOB ${4}.1 | cut -d= -f2)
- $RSH $host -l $user qsig -s 2 $tid
- $RSH $host -l $user qdel -W 10 $tid
-
- else
- # Signal the job
- $RSH $host -l $user qsig -s 2 $smsid
-
- # Remove the job from PBS (give 10 ssmeconds delay for the above to finish)
- $RSH $host -l $user qdel -W 10 $smsid
- fi
-}
-
-kill_vpp() {
- $RSH $host -l $user qdel -2 $smsid
-}
-
-kill_nqs() {
- $RSH $host -l $user qdel -2 $smsid
-}
-
-kill_sge() {
- use sge || :
- QDEL=sge_qdel
- type $QDEL || QDEL="ssh $host $SGE_ROOT/sge6_2u5/bin/lx24-amd64/qdel"
- if [[ -s $subfile ]] then
- tid=$(grep " has been submitted" $subfile | cut -f 3 -d" ")
- $QDEL $tid
- elif [[ -s $4 ]] ; then
- tid=$(grep active_jobs $4 | grep cd | cut -d"." -f 2 | cut -d"/" -f8)
- $QDEL $tid
- else
- $QDEL $smsid
- fi
-}
-
-kill_new_linux() {
- tid=$(grep " has been submitted" $subfile | cut -f 3 -d" ")
- $SSH $host -l $user $SGE_ROOT/sge6_2u5/bin/lx24-amd64/qdel $tid
-}
-
-kill_ll() {
- if [[ -s $subfile ]] then
- tid=$(grep " has been submitted." $subfile | cut -d\" -f2)
- $RSH $host -l $user $LL_ROOT/llcancel $tid
- else
-
- if [[ "$host" == hpc* ]] ; then
- host=$(echo $host | cut -c1-4)
- id=${host}0$(echo $smsid % 1000 | bc).$(echo $smsid / 1000 | bc)
- else
- id=$smsid
- if [[ -f $smsid ]] ; then
- grep "LOADL_STEP_ID=NOT_SET" $subfile && \
- id=$(grep JOB_ID= $subfile | cut -d= -f2) && \
- $RSH $host -l user kill -9 $id
- fi
- fi
-
- $RSH $host -l $user $LL_ROOT/llcancel $id
- fi
-}
-
-kill_slurm() {
- if [[ -s $subfile ]] then
- tid=$(grep "Submitted batch job " $subfile | awk '{print $4}')
- $SSH $host -l $user $SLURM_ROOT/scancel $tid
- else
- id=$smsid
- if [[ -f $smsid ]] ; then
- grep "LOADL_STEP_ID=NOT_SET" $subfile && id=$(grep JOB_ID= $subfile | \
- cut -d= -f2) && \
- $SSH $host -l $user kill -9 $id
- fi
-
- $SSH $host -l $user $SLURM_ROOT/scancel $id
- fi
-}
-
-kill_rsh() {
- $RSH $host -l $user /bin/kill -2 $smsid
- # SGI syntax: kill -signal -pgid
- $RSH $host -l $user kill -15 $smsid || kill -15 $smsid
-}
-
-status_pbs() {
-
- qstat=/usr/local/apps/propbs/bin/qstat
-
- if [[ -s $subfile ]] ; then
- display_subfile
- tid=$(tail -1 $subfile)
- elif [[ -s $smsjob ]] ; then
- tid=$(grep PBS_JOB ${smsjob}.1 | cut -d= -f2)
- else
- tid=$smsid
- fi
-
- banner "** output ** "
- $RSH $host -l $user tail -100 /var/spool/PBS/spool/${tid}* &
- wait
- banner "** qstat ** "
- $RSH $host -l $user $qstat -f $tid | grep $user && OK=OK &
-
-}
-
-status_vpp() {
- $RSH $host -l $user qstat $smsid | grep $user && OK=OK &
-}
-
-status_nqs() {
- $RSH $host -l $user qstat $smsid | grep $user && OK=OK &
-}
-
-status_swarm() {
-# use sge
- task_name=$(basename $smsjob | cut -d\. -f1)
- if [[ -s $subfile ]] then
- display_subfile
- tid=$(grep " has been submitted" $subfile | cut -f 3 -d" ")
- elif [[ -s $smsjob ]] ; then
- tid=$(grep active_jobs $smsjob | grep cd | cut -d"." -f 2 | cut -d"/" -f8)
- else
- tid=$smsrid
- fi
-
- printf "==============================================================\n"
- if [[ $host == @(lxa|lxb|lxab) ]] ; then
- cat $file | $SSH $host $SGR_ROOT/sge6_2u5/bin/lx24-amd64/qstat -u $user -f | \
- grep -E "$task_name|$tid" | grep $user && OK=OK
- cat $file | $SSH $host $SGE_ROOT/sge6_2u5/bin/lx24-amd64/qstat -j $tid && \
- print "$smsjob is there\n" || print "$smsjob not there ... \n"
- else
- qstat -u $user -f | grep -E "$task_name|$tid" | grep $user && OK=OK
- qstat -j $tid && print "$smsjob is there\n" || print "$smsjob not there ... \n"
- fi
- printf "==============================================================\n"
-}
-
-status_new_linux() {
- status_swarm
-}
-
-status_ll() {
- if [[ -s $subfile ]] then
- tid=$(grep " has been submitted." $subfile | cut -d\" -f2)
- host=$(echo $tid | cut -d\. -f1)
- host4=$(echo $host | cut -c1-4)
-
- $RSH $host $LL_ROOT/llq -f %id %jn %o %c %st %nh $tid | grep $user && OK=OK &
-
- else
-
- if [[ -s $smsjob ]] ; then
- host=$(grep HOST= $smsjob | cut -d= -f2)
- fi
-
- if [[ "$host" == hpc* ]] ; then
- host=$(echo $host | cut -c1-4)
- host4=$(echo $host | cut -c1-4)
- id=${host}0$(echo $smsid % 1000 | bc).$( echo $smsid / 1000 | bc)
- else
- id=$host.$smsid
- fi
-
- $RSH $host $LL_ROOT/llq -f %id %jn %o %c %st %nh $tid | grep $user
- fi
-}
-
-status_slurm() {
- if [[ -s $subfile ]] then
- display_subfile
- tid=$(grep "Submitted batch job" $subfile | cut -d' ' -f4)
- $SSH -l $user $host $SLURM_ROOT/scontrol show job -d $tid
- $SSH -l $user $host $SLURM_ROOT/squeue | grep $user | grep " $tid"
- elif [[ $host != $hostname ]] ; then
- $SSH -l $user $host "$0 $user $host $file $uout $smsid status"
- fi
-}
-
-status_rsh() {
- if [[ $smsid == 0 ]]; then echo "too early"; exit 0; fi
- $RSH $host -l $user ps -elf | grep " $user " | grep " $smsid " | grep -v " grep " && \
- $RSH $host -l $user ps --sid $smsid -f
-
- \ps -elf | grep " $user " | grep " $smsid " | grep -v " grep " && OK=OK &
- \ps --sid $smsid -f && OK=OK &
-}
-
-disp_subfile() {
- if [[ -s $subfile ]]; then # && [[ $OK = NOK ]] ; then
- ls -la $subfile
- # echo # grep "^# +++ hpc" $subfile
- cat $subfile
- # && type=ll
-fi
-}
-
-#--------------------------------------------------------------------------
-# Check the number of arguments
-#--------------------------------------------------------------------------
-
-set -x
-echo $0 $*
-
-if [ $# -lt 3 ] ; then
- echo
- echo "usage: $0 <user> <host> file remote_output [node_suffix]"
- echo
- echo "example: $0 uid ecgate task.job1"
- echo "while node_suffix is empty, host-batch node is the target, "
- echo " else \$node\$nodesuffix is the replacement target"
- echo
- exit 1
-fi
-
-set -x
-
-user=$1
-host=$2
-file=$3
-uout=$4
-node_suffix=$5
-smsid=$5
-
-for last; do true; done # last shall be submit status kill only
-case $last in
-submit | status | kill ) echo;;
-*) last="submit" ;;
-esac
-
-subfile=${file}.sub
-
-#--------------------------------------------------------------------------
-# determine queuing system from hostname
-# (can be replaced by a more refined method later...)
-#--------------------------------------------------------------------------
-
-hostname=$(hostname)
-
-case $host in
- bilbo | belegorn | boromir | denethor | faramir | acq | pp1 | diss) type=pbs;;
- vpp* ) type=vppnqs;;
- swarm | linux_cluster | lxa | lxb | lxab ) type=sge_qsub;;
- ecgate1 | ecgb* | ecgt* ) type=slurm;;
- ecgate | ecga* | c2* ) type=ll;;
- $hostname | localhost ) type=local;;
- datasvc) type=ssh;;
- * ) type=rsh;;
-esac
-
-# if [[ $type = "local" ]] && [[ $hostname = @(ecg*|vsms*) ]]; then type=ssh; fi
-
-#--------------------------------------------------------------------------
-# determine job file type and output directory
-#--------------------------------------------------------------------------
-
-output=""
-if egrep -i "^#.*QSUB " $file > /dev/null ; then
- jtype=nqs
- output=$(egrep -i "^#.*QSUB -o" $file | cut -d" " -f 4 | head -1)
-
-elif egrep -i "^#.*@.*queue" $file > /dev/null ; then
- jtype=ll
- output=$(egrep -i "^#.*@.*output" $file | cut -d"=" -f 2 | head -1)
-
-elif [[ $host == @(ecgb*|ecgt0*|ecgate1) ]] ; then
- jtype=slurm
- output=$(egrep -i "^#.*-o" $file | cut -d" " -f 3 | head -1)
-
-elif egrep -i "^#.*PBS " $file > /dev/null ; then
- jtype=pbs
-
-elif egrep -i "^#.*SBATCH " $file > /dev/null ; then
- jtype=slurm
- output=$(egrep -i "^#.*-o" $file | cut -d" " -f 3 | head -1)
- if [[ output == "" ]]; then
- output=$(egrep -i "^#.*-output" $file | cut -d" " -f 3 | head -1)
- fi
- if [[ output == "" ]]; then output=$uout; fi
- if [[ output != "" ]]; then
- head -1 $output && grep "#!/" && RUNSHELL=$(head -1 $output | cut -d! -f2)
- else
- RUNSHELL="/bin/bash"
- fi
- case $RUNSHELL in
- *tcsh) PROFILE=". $HOME/.tcshrc";;
- *csh) PROFILE=". $HOME/.cshrc";;
- esac
-elif [[ $host == @(linux_cluster|lxa|lxb|lxab|swarm) ]] ; then
- jtype=sge_qsub
- output=$(egrep -i "^#.*-o" $file | cut -d" " -f 3 | head -1)
-
-else
- jtype=sh
-
-fi
-
-case $last in
-submit)
-#--------------------------------------------------------------------------
-# File must exist!
-#--------------------------------------------------------------------------
-
-if [[ ! -f $file ]] ; then
- echo "$0: File $file not found?"
- exit 1
-fi
-
-chmod 755 $file
-
-if [[ "$uout" != "" ]]; then output=$uout; mkdir -p $(dirname $uout); fi
-if [[ $output == *0.0 ]]; then echo "filename error $output"; exit 1; fi
-cp $file ${file}.pre
-# mailx -s "o:$output uo:$uout" $USER < /dev/null; exit 0
-
-LC="-c "
-if egrep -qi "^[[:space:]]*#[[:space:]]*@[[:space:]]*environment[[:space:]]*=" $file > /dev/null
-then
- LC="-lc "
-fi
-
-[[ "$output" == "" ]] || outputdir=$(dirname $output)
-if [[ "$outputdir" != "" ]] ; then
-#--------------------------------------------------------------------------
-# Create the output directory if it can be found
-#--------------------------------------------------------------------------
-if [[ ! -d $outputdir ]] ; then
- # don't worry anymore about output directory
- $RSH $host -l $user mkdir -m 775 -p $outputdir || \
- mkdir -m 775 -p $outputdir || /bin/true
-fi
-fi
-;;
-esac
-
-case $type in
-#==========================================================================
-# Submit to hp using PBS
- pbs )
-#==========================================================================
-
-case $last in
-kill) kill_pbs; exit 0;;
-status) status_pbs; exit 0;;
-esac
-
-# get queue-name, job-name
-if [[ $jtype == nqs ]] ; then
- queue=$(grep 'QSUB -q ' $file | cut -d" " -f 4 | head -1)
- jname=$(grep 'QSUB -r ' $file | cut -d" " -f 4 | head -1)
-
-elif [[ $jtype == ll ]] ; then
- queue=$(egrep '^#.*@.*class.*=' $file | cut -d"=" -f 2 | head -1)
- jname=$(egrep '^#.*@.*job_name.*=' $file | cut -d"=" -f 2 | head -1)
-
-elif [[ $jtype != pbs ]] ; then
- ERROR "No conversion available for these types ($jtype -> $type)."
-fi
-
-#--------------------------------------------------------------------------
-# Create the script (${file}__) that will contain the PBS directives
-#--------------------------------------------------------------------------
-
-if [[ $jtype != pbs ]] ; then
-
-cat > ${file}__ <<- EOF
-#!$RUNSHELL
-if [[ -f $HOME/.profile ]]; then
-$PROFILE
-fi
-#PBS -S /bin/ksh
-#PBS -N $jname
-#PBS -V
-#PBS -o /dev/null
-#PBS -e /dev/null
-#PBS -j oe
-#PBS -u $user
-#PBS -q $queue
-EOF
-
- egrep -v '^#.*QSUB -|^:$|^#.*@' $file >> ${file}__
-
- mv -f ${file}__ ${file}
-
-fi
-#--------------------------------------------------------------------------
-# Remote shell to $host and submit from there
-#--------------------------------------------------------------------------
-
-#rsh $host -l $user /usr/local/apps/propbs/bin/pbsqsub < $file || ERROR "Failed to submit job to PBS (possible failure of rsh)."
-
-if [[ $(uname -n) == @(ecgb*|vsms*|sms-map) ]]; then
- $SSH -l $user $host /usr/local/apps/propbs/bin/pbsqsub -f $file > $subfile 2>&1 || \
- ERROR "Failed to submit job to PBS. "
-else
- ecrcmd --timeout=$TIMEOUT < $file $user@$host $LC \
- /usr/local/apps/propbs/bin/pbsqsub -f $file > $subfile || \
- ERROR "Failed to submit job to PBS."
-fi
-
- ;;
-#==========================================================================
-# Submit to vpp using NQS
- vppnqs )
-#==========================================================================
-
-case $last in
-kill) kill_vpp; exit 0;;
-status) status_vpp; exit 0;;
-esac
-
-if [[ $jtype == ll ]] ; then
- /home/ma/emos/bin/ll2nqs.pl $file ${file}__ || ERROR "Conversion ll2nqs.pl failed."
- mv -f ${file}__ $file
-
-elif [[ $jtype != nqs ]] ; then
- ERROR "No conversion available for these types ($jtype -> $type)."
-
-else
- grep -v "QSUB -p" $file | grep -v "QSUB -lh" > ${file}__
- mv -f ${file}__ $file
-fi
-
-#--------------------------------------------------------------------------
-# Send the file using qsub
-# If send failed, sleep a while and try again, until maximum number of
-# tries.
-#--------------------------------------------------------------------------
-
-$SSH $host -l $user /usr/local/bin/vppqsub < $file | grep -i submitted > $subfile || \
- ERROR "Failed to submit $file."
-
- ;;
-#==========================================================================
- sge_qsub ) # swarm linux cluster
-
-case $last in
-kill) kill_sge; exit 0;;
-status) status_sge; exit 0;;
-esac
-
-# get queue-name, job-name
-if [[ $jtype == nqs ]] ; then
- queue=$(grep 'QSUB -q ' $file | cut -d" " -f 4 | head -1)
- jname=$(grep 'QSUB -r ' $file | cut -d" " -f 4 | head -1)
-
-elif [[ $jtype == ll ]] ; then
- queue=$(egrep '^#.*@.*class.*=' $file | cut -d"=" -f 2 | head -1)
- jname=$(egrep '^#.*@.*job_name.*=' $file | cut -d"=" -f 2 | head -1)
-
-elif [[ $jtype != sge_qsub ]] ; then
- ERROR "No conversion available for these types ($jtype -> $type)."
-fi
-
-#--------------------------------------------------------------------------
-# Create the script (${file}__) that will contain the PBS directives
-#--------------------------------------------------------------------------
-
-# if [[ $jtype != sge_qsub ]] ; then
-
- queue=$(grep 'QSUB -q ' $file | cut -d" " -f 4 | head -1)
-
-cat > ${file}__ <<- EOF
-#\$ -S /home/ma/emos/bin/ksh
-#\$ -N ${jname}
-#\$ -V
-#\$ -o $output
-#\$ -j y
-#\$ -u $user
-#\$ -q $queue
-EOF
-
- egrep -v '^#.*QSUB -|^:$|^#.*@' $file >> ${file}__
- chmod 755 ${file}__
- mv -f ${file}__ ${file}
-
-# fi
-
- mkdir -m 775 -p $outputdir || /bin/true
- if [[ $host == @(lxa|lxb|lxab) ]] ; then
- cat $file | $SSH $host \
- $SGE_ROOT/sge6_2u5/bin/lx24-amd64/qsub -notify > $subfile 2>&1 || \
- ERROR "Job submission failed (${file}__)."
- elif [[ $HOST == @(ibis|pikachu) ]] ; then
- cat $file | $RSH drn01 \
- SGE_ROOT=$SGE_ROOT $SGE_ROOT/bin/lx24-amd64/qsub -notify > $subfile 2>&1 || \
- ERROR "Job submission failed (${file}__)."
- elif [[ -d $SGE_ROOT ]]; then
- /usr/local/share/sge_qsub -notify $file > $subfile 2>&1 || \
- ERROR "Job submission failed (${file}__)."
- else
- cat $file | $SSH drn01 \
- ${SGE_ROOT:=/usr/local/apps/sge}/bin/lx24-amd64/qsub -notify > $subfile 2>&1 || \
- cat $file | $SSH drn01 \
- SGE_ROOT=$SGE_ROOT $SGE_ROOT/bin/lx24-amd64/qsub -notify $file > $subfile 2>&1 || \
- ERROR "Job submission failed (${file}__)."
-
- # || ERROR "Job submission failed (${file}__)."
- fi
-# sge_qsub -notify $file > $subfile || ERROR "Job submission failed (${file}__)."
- ;;
-
-#==========================================================================
-# Submit to other workstation using NQS
- nqs )
-#==========================================================================
-
-case $last in
-kill) kill_nqs; exit 0;;
-status) status_nqs; exit 0;;
-esac
-
-#--------------------------------------------------------------------------
-# Create the script (${file}__) that will run the qsub
-#--------------------------------------------------------------------------
-
-cat > ${file}__ <<- EOF
-#!/bin/ksh
-unset WAITQUEUE
-set -e
-EOF
-
-# qsub statement
-echo "/usr/local/share/qsub < ${file}" >> ${file}__
-
-#
-# Create the real request
-#
-grep -v "QSUB -A" $file | grep -v "QSUB -lh" | grep -v "QSUB -p" | grep -v "QSUB -u" > ${file}__.qsub
-mv -f ${file}__.qsub ${file}
-
-#--------------------------------------------------------------------------
-# Remote shell to $host and submit from there
-#--------------------------------------------------------------------------
-chmod +x ${file}__
-$SSH $host -l $user -n "${file}__" || ERROR "Job submission failed (${file}__)."
-
-sleep 10
-/bin/rm -f ${file}__
-
- ;;
-#==========================================================================
-# Submit to IBM server using loadleveler
- ll )
-#==========================================================================
-
-case $last in
-kill) kill_ll; exit 0;;
-status) status_ll; exit 0;;
-esac
-
-if [[ $jtype == nqs ]] ; then
- #
- # Create the real request
- #
- /home/ma/emos/bin/nqs2ll.pl $host $file ${file}__ || ERROR "Conversion nqs2ll.pl failed."
- if [[ "$uout" != "" ]]; then
- cat ${file}__ | sed -e "s:# @ output = .*:# @ output = $output:" | \
- sed -e "s:# @ error .*:# @ error = $output:" > ${file}
- else
- mv -f ${file}__ ${file}
- fi
-
-elif [[ $jtype != ll ]] ; then
- ERROR "No conversion available for these types ($jtype -> $type)."
-fi
-#--------------------------------------------------------------------------
-# Remote shell to $host and submit from there
-#--------------------------------------------------------------------------
-
-if [[ $host == @(c2*) ]] ; then
- # file="/ws$file"
- if [[ $node_suffix == "" ]] ; then
- host="${host}-batch"
- else
- host="${host}${node_suffix}"
- fi
-fi
-
-if [[ $(uname -n) == @(ecgb*|vsms*|sms-map) ]]; then
- $SSH -l $user ${host} \
- "unset WAITQUEUE ; $LL_ROOT/llsubmit - 2>&1 " < $file > $subfile 2>&1 || \
- ERROR "Failed to submit job to LoadLeveler. $?"
-else
- ecrcmd --timeout=$TIMEOUT < $file $user@$host $LC \
- "unset WAITQUEUE ; $LL_ROOT/llsubmit -" > $subfile || \
- ERROR "Failed to submit job to LoadLeveler."
-fi
-
- ;;
-
- slurm ) # swarm linux cluster
-
-case $last in
-kill) kill_slurm; exit 0;;
-status) status_slurm; exit 0;;
-esac
-
-# get queue-name, job-name
-if [[ $jtype == nqs ]] ; then
- queue=$(grep 'QSUB -q ' $file | cut -d" " -f 4 | head -1)
- jname=$(grep 'QSUB -r ' $file | cut -d" " -f 4 | head -1)
-
-# srun sinfo
- cat > ${file}__ <<- EOF
-#!$RUNSHELL
-#SBATCH --output=${output:-/dev/null}
-#SBATCH --error=${output:=/dev/null}
-#SBATCH --time=01:00:00
-#SBATCH --job-name=${jname}
-#SBATCH --get-user-env
-#SBATCH --uid=$user
-##BATCH --qos=normal # express/long
-$PROFILE
-EOF
-# cp $file ${file}.pre
- cat $file | egrep -v '^#.*QSUB -|^:$|^#.*@' | \
- grep -E -v '(^#.*SBATCH --output.*|#.*SBATCH --error.*|^#.*SBATCH --uid.*|^#.*SBATCH --qos.*)' >> ${file}__
- chmod 755 ${file}__
-
-elif [[ $jtype == slurm ]]; then
-
- cat > ${file}__ <<- EOF
-#!$RUNSHELL
-#SBATCH --output=${output:-/dev/null}
-#SBATCH --error=${output:-/dev/null}
-#SBATCH --time=01:00:00
-#SBATCH --job-name=${jname}
-#SBATCH --get-user-env
-#SBATCH --uid=$user
-##BATCH --qos=normal # express/long
-$PROFILE
-EOF
-# cp $file ${file}.pre
- cat $file | egrep -v '^#.*QSUB -|^:$|^#.*@' | \
- grep -E -v '(^#.*SBATCH --output.*|#.*SBATCH --error.*|^#.*SBATCH --uid.*|^#.*SBATCH --qos.*)' >> ${file}__
- chmod 755 ${file}__
-
-elif [[ $jtype == ll ]] ; then
- $PROFILE
- # /usr/local/apps/slurm/utils/bin/ll2slurm
- ll2slurm -q -i $file -o ${file}__ || ERROR "Job conversion to slurm failed (${file})."
-elif [[ $jtype != slurm ]]; then
- ERROR "No conversion available for these types ($jtype -> $type)."
-fi
-
-#--------------------------------------------------------------------------
-# Create the script (${file}__) that will contain the PBS directives
-#--------------------------------------------------------------------------
- mv ${file}__ $file
-
- if [[ $hostname == @(ecgb*|ecgate1) ]]; then
- touch $output
- $SLURM_ROOT/sbatch < ${file} > $subfile 2>&1 \
- || ERROR "Job submission failed (${file})."
- else
- $SSH $host -l $user touch $output
- cat ${file} | $SSH $host -l $user $SLURM_ROOT/sbatch > $subfile 2>&1 \
- || ERROR "Job submission failed (${file})."
- fi
-;;
-#==========================================================================
-# Submit using ssh
-#==========================================================================
- ssh )
-
-case $last in
-kill) kill_ssh; exit 0;;
-status) status_ssh; exit 0;;
-esac
-
- cmd="ssh $user@$host"
-#
-# Add the header with requested shell
-#
-
- cat > ${file}__ <<- EOF
-#!$RUNSHELL
-# output=$output
-$PROFILE
-EOF
-
-#
-# Add the real request removing all qsub statements
-#
-
-if [[ $jtype == ll ]] ; then
- egrep -v '^#.*@|^#!|^:$' $file >> ${file}__
-elif [[ $jtype == nqs ]] ; then
- egrep -v '^#.*QSUB|^#!|^:$' $file >> ${file}__
-elif [[ $jtype == slurm ]] ; then
- egrep -v '^#.*SBATCH|^#!|^:$' $file >> ${file}__
-elif [[ $jtype == pbs ]] ; then
- egrep -v '^#.*PBS|^#!|^:$' $file >> ${file}__
-fi
-
-#
-# Submit the job
-#
-$cmd "/usr/local/bin/standalone -o $output -s $RUNSHELL " < ${file}__ || ERROR "Job submission to ssh standalone failed."
-;;
-
-#==========================================================================
-# Submit to any other workstation using rsh standalone or
-# submit to local workstation using standalone
- rsh | local )
-#==========================================================================
-
-case $last in
-kill) kill_rsh; exit 0;;
-status) status_rsh; exit 0;;
-esac
-
-if [[ $type == local ]] ; then
- cmd=""
-elif [[ $hostname == @(ecgb*|vsms*) ]] ; then
- cmd="$SSH -l $user $host "
-else
- cmd="rsh $host -l $user "
-fi
-
-#
-# Add the header with requested shell
-#
-
-cat > ${file}__ <<- EOF
-#!$RUNSHELL
-# output=$output
-$PROFILE
-EOF
-#
-# Add the real request removing all qsub statements
-#
-
-if [[ $jtype == ll ]] ; then
- egrep -v '^#.*@|^#!|^:$' $file >> ${file}__
-
-elif [[ $jtype == nqs ]] ; then
- egrep -v '^#.*QSUB|^#!|^:$' $file >> ${file}__
-
-elif [[ $jtype == slurm ]] ; then
- egrep -v '^#.*SBATCH|^#!|^:$' $file >> ${file}__
-
-elif [[ $jtype == pbs ]] ; then
- egrep -v '^#.*PBS|^#!|^:$' $file >> ${file}__
-
-fi
-
-mv -f ${file}__ $file
-#
-# Submit the job
-#
-if [[ $type == local ]] ; then
-
- case $hostname in
- ecg* | vsms*) nohup $RUNSHELL -x $file > $output 2>&1 & ;;
- *) standalone -o $output -s $RUNSHELL < $file || ERROR "Job submission to standalone failed."
- ;;
- esac
-else
-
- case $hostname in
- ecg* | vsms*) # $cmd "nohup $RUNSHELL -x $file > $output 2>&1 &"
- $cmd "$STANDALONE -o $output -s $RUNSHELL" < $file > $subfile || \
- ERROR "Job submission to rsh standalone failed."
- ;;
- *)
- $cmd "/usr/local/bin/standalone -o $output -s $RUNSHELL" < $file > $subfile ||\
- ERROR "Job submission to rsh standalone failed."
- ;;
- esac
-fi
-
- ;;
-esac
-
-exit 0
-
-ssh-keygen -t dsa
-scp ~/.ssh/id_dsa.pub ecgate:.ssh/authorized_keys2
-ssh-agent sh -c 'ssh-add < /dev/null && bash'
-
-
-ssh-keygen -t rsa
-ssh server "mkdir .ssh; chmod 0700 .ssh"
-scp .ssh/id_rsa.pub server:.ssh/authorized_keys2
-scp $HOME/.ssh/id_rsa.pub c2a:$HOME/.ssh/authorized_keys2
-scp $HOME/.ssh/id_rsa.pub c2b:$HOME/.ssh/authorized_keys2
-
-cp $HOME/.ssh/id_rsa.pub $HOME/.ssh/authorized_keys2
diff --git a/ecflow_4_0_7/tools/ecflow_logsvr.pl b/ecflow_4_0_7/tools/ecflow_logsvr.pl
deleted file mode 100644
index f412775..0000000
Binary files a/ecflow_4_0_7/tools/ecflow_logsvr.pl and /dev/null differ
diff --git a/ecflow_4_0_7/tools/ecflow_logsvr.sh b/ecflow_4_0_7/tools/ecflow_logsvr.sh
deleted file mode 100644
index 02b15b1..0000000
--- a/ecflow_4_0_7/tools/ecflow_logsvr.sh
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/bin/ksh
-
-if [[ $# -ge 2 ]] ; then
- echo ecflow_logsvr.sh port
- exit -1
-fi
-
-echo "logsvr pid $$"
-
-HOST=`hostname | cut -c 1-4`
-
-# LOGPORT=${1:-9318}
-LOGPORT=${1:-9316}
-USERS="$USER"
-
-if [[ $HOST = hpc* ]] ; then
- LOGPATH=/$HOST/emos_dir:/emos_esuite:/emos_dir
- LOGMAP=/emos_esuite:/emos_esuite:/vol/emos/output:/emos_esuite:/vol/emos/output:/$MACHINE_NAME/emos_dir:/$MACHINE_NAME/emos_dir:/$MACHINE_NAME/emos_dir:/emos_esuite:/emos_esuite:/vol/emos/output:/emos_dir:/emos_dir:/emos_dir
- log=/$HOST/tmp/ma/emos/logsvr.log
-else
-# HP
- LOGPATH=/tmp/output:/pp2/log:/acq2/log:/eacq1/log:/eacq2/log
- LOGMAP=/pp2/log:/pp2/log:/acq2/log:/acq2/log:/eacq1/log:/eacq1/log:/eacq2/log:/eacq2/log
- log=/sms/logsvr.log
-fi
-
-if [[ -x /usr/local/lib/metaps/perl/logsvr.pl ]] ; then
- LOGSVR=/usr/local/lib/metaps/perl/logsvr.pl
-elif [[ -x /usr/local/apps/sms/bin/logsvr.pl ]] ; then
- LOGSVR=/usr/local/apps/sms/bin/logsvr.pl
-elif [[ -x $HOME/bin/logsvr.pl ]] ; then
- LOGSVR=$HOME/bin/logsvr.pl
-elif [[ -x /sms/bin/logsvr.pl ]] ; then
- LOGSVR=/sms/bin/logsvr.pl
-elif [[ -x ./logsvr.pl ]] ; then
- LOGSVR=`pwd`/logsvr.pl
-else
- echo "logsvr.pl not found in expected location"
-fi
-
-echo "using: $LOGSVR"
-export LOGPORT LOGPATH LOGMAP
-n=0
-while [[ $n -lt 1 ]]
-do
- $LOGSVR > $log 2>&1 &
- echo "logsvr pid $!"
- wait
- tail $log | mail -s "logsvr.pl crashed" $USERS
- sleep 10
-done
diff --git a/ecflow_4_0_7/tools/ecflow_start.sh b/ecflow_4_0_7/tools/ecflow_start.sh
deleted file mode 100755
index 0e1616e..0000000
--- a/ecflow_4_0_7/tools/ecflow_start.sh
+++ /dev/null
@@ -1,283 +0,0 @@
-#!/bin/sh
-#set -x
-#set -u
-#==========================================================================
-##.TITLE ECMWF utility for ECFLOW
-##.NAME ecf_start
-##.SECTION ECF
-##.AUTHOR Avi
-## Revision : $Revision: #19 $
-##
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-##
-##.FILE ecflow_start.
-### Will start the ecflow_server in the background, using user id
-### to make a unique port number.
-
-#==========================================================================
-export TZ=GMT LANG= # en_GB.UTF-8 unset, use locale -a to list available locales
-host=$(hostname)
-force=true
-backup_server=false
-verbose=false
-rerun=false
-
-#==========================================================================
-# Syntax
-# ecflow_start [-b] [-d ecf_home_directory] [-f] [-h] [-p port_number ]
-#==========================================================================
-# get command line options if any.
-while getopts hfbd:vp:r option
-do
-case $option in
-f)
-force=true
-;;
-b)
-backup_server=true
-;;
-v)
-verbose=true
-;;
-d)
-ecf_home_directory=$OPTARG
-;;
-p)
-ecf_port=$OPTARG
-;;
-r)
-rerun=true
-;;
-h)
-echo "Usage: $0 [-b] [-d ecf_home directory] [-f] [-h]"
-echo " -b start ECF for backup server or e-suite"
-echo " -d <dir> specify the ECF_HOME directory - default $HOME/ecflow_server"
-echo " -f forces the ECF to be restarted"
-echo " -v verbose mode"
-echo " -h print this help page"
-echo " -p <num> specify server port number(ECF_PORT number) - default 1000+<UID> | 500+<UID> for backup server"
-exit 0
-;;
-*)
-echo "Usage: $0 [-b] [-d ecf_home directory] [-f] [-h]"
-echo " -b start ECF for backup server or e-suite"
-echo " -d <dir> specify the ECF_HOME directory - default $HOME/ecflow_server"
-echo " -f forces the ECF to be restarted"
-echo " -v verbose mode"
-echo " -h print this help page"
-echo " -p <num> specify server port number(ECF_PORT number) - default 1500+<UID> | 1000+<UID> for backup server"
-exit 1
-;;
-esac
-done
-
-
-# =================================================================================
-# port_number is set based on the unique users numeric uid.
-
-username=`id -u`
-
-if [ -z "$ecf_port" ] ; then
-
- if [ $backup_server = "true" ]; then
- base=1000
- else
- base=1500
- fi
- port_number=$((base+username))
-
-else
- port_number=$ecf_port
-fi
-
-export ECF_PORT=$port_number
-
-#===============================================================================
-# if working directory not set then set to current directory
-
-export ECF_HOME=${ecf_home_directory:-$HOME/ecflow_server}
-export ECF_LISTS=${ECF_LISTS:-$ECF_HOME/ecf.lists}
-
-# ===============================================================================
-# Update kill and status command for ecgate
-
-rcdir=$HOME/.ecflowrc
-fname=$rcdir/$(echo $host | cut -c1-5).$USER.$ECF_PORT # OK as long as ecgate node is under 10
-mkdir -p $rcdir
-ecflow_client --port $ECF_PORT --host $(cat $fname) --ping && echo "server is already started" && exit 0 || :
-
-case $host in
- sappa*)
-if [[ $(ssh sappa hostname) != $host ]]; then
- echo "please start ecflow on the generic node only";
- exit 1;
-fi
-
-echo "$host" > $fname
-host=sappa
- file=$HOME/.ecfhostfile_sappa
- touch $file
- grep sappa00 $file || cat >> $file <<EOF
-sappa00
-sappa01
-sappa02
-sappa03
-EOF
-;;
- sappb*)
-if [[ $(ssh sappb hostname) != $host ]]; then
- echo "please start ecflow on the generic node only";
- exit 1;
-fi
-
-echo "$host" > $fname
-host=sappb
- file=$HOME/.ecfhostfile_sappb
- touch $file
- grep sappb00 $file || cat >> $file <<EOF
-sappb00
-sappb01
-sappb02
-sappb03
-EOF
-;;
- ecga*)
- echo "$host" > $fname
- host=ecgate
- ECF_KILL_CMD='${ECF_KILL:=/home/ma/emos/bin/ecfkill} %USER% %HOST% %ECF_RID% %ECF_JOB% > %ECF_JOB%.kill 2>&1'
- ECF_STATUS_CMD='${ECF_STAT:=/home/ma/emos/bin/ecfstatus} %USER% %HOST% %ECF_RID% %ECF_JOB% > %ECF_JOB%.stat 2>&1'
- export ECF_KILL_CMD ECF_STATUS_CMD
-
-# ===============================================================================
-# Update host and create hosts file
-
- file=$HOME/.ecfhostfile
- grep ecga00 $file || ( cat >> $file <<EOF
-ecga00
-ecga01
-ecga02
-ecga03
-ecga04
-ecga05
-EOF
-
- if [ "$USER" != emos ] ; then
- rcp $file $USER at c2a:~/.ecfhostfile || :
- rcp $file $USER at c2b:~/.ecfhostfile || :
- fi
-)
-
- file=$HOME/.ecflowrc/servers
- nick=ecgate1
- grep "^ecgate " $file || echo "ecgate ecgate $ECF_PORT" >> $file
- grep "^$nick " $file || echo "$nick $nick $ECF_PORT" >> $file
-;;
-esac
-
-date -u
-
-# set up default environment variables
-export ECF_NODE=$host
-export ECF_LOG=$host.$ECF_PORT.ecf.log
-export ECF_CHECK=$host.$ECF_PORT.check
-export ECF_CHECKOLD=$host.$ECF_PORT.check.b
-if [ "$verbose" = "false" ]; then
- export ECF_OUT=/dev/null
-else
- export ECF_OUT=$host.$ECF_PORT.ecf.out
-fi
-
-echo
-echo User \"$username\" attempting to start ecf server on \"$host\" using ECF_PORT \"$ECF_PORT\" and with:
-echo "ECF_HOME : \"$ECF_HOME\""
-echo "ECF_LOG : \"$ECF_LOG\""
-echo "ECF_CHECK : \"$ECF_CHECK\""
-echo "ECF_CHECKOLD : \"$ECF_CHECKOLD\""
-if [ "$verbose" = "false" ]; then
- echo "ECF_OUT : \"/dev/null\""
-else
- echo "ECF_OUT : \"$host.$ECF_PORT.ecf.out\""
-fi
-echo
-
-#==========================================================================
-
-echo "client version is $(ecflow_client --version)"
-# echo "server version is $(ecflow_server --version)"
-echo "Checking if the server is already running on $host and port $ECF_PORT"
-ecflow_client --ping
-if [ $? -eq 0 ]; then
- echo "... The server on $host:$ECF_PORT is already running. Use 'netstat -lnptu' for listing active port"
- exit 1
-fi
-
-
-#==========================================================================
-
-echo "";
-echo Backing up check point and log files
-
-if [ ! -d $ECF_HOME ] ;then
- mkdir $ECF_HOME
-fi
-cd $ECF_HOME
-
-if [ ! -d log ] ;then
- mkdir log
-fi
-
-set +e
-
-cp $ECF_CHECK log/ 2>/dev/null
-cp $ECF_CHECKOLD log/ 2>/dev/null
-cp $ECF_LOG log/ 2>/dev/null
-
-if [ -f $host.$ECF_PORT.ecf.out ]; then
- cp $host.$ECF_PORT.ecf.out log/ 2>/dev/null
-fi
-
-set -e
-
-
-# =============================================================================
-# ecFlow server start in the background.
-#
-# o/ nohup is a POSIX command to ignore the HUP (hangup) signal, enabling the command to
-# keep running after the user who issues the command has logged out.
-# The HUP (hangup) signal is by convention the way a terminal warns depending processes of logout.
-#
-# Note that these methods prevent the process from being sent a 'stop' signal on logout,
-# but if input/output is being received for these standard IO files (stdin, stdout, or stderr),
-# they will still hang the terminal
-# This problem can also be overcome by redirecting all three I/O streams:
-#
-# o/ ecflow_server will by default attempt to recover from a check point file if it is there
-# otherwise it will look for the backup check point file
-#
-echo "";
-echo "OK starting ecFlow server..."
-echo "";
-
-nohup ecflow_server > $ECF_OUT 2>&1 < /dev/null &
-
-# the sleep allows time for server to start
-if [ "$force" = "true" ]; then
- echo "Placing server into RESTART mode..."
- sleep 5
- ecflow_client --restart || { echo "restart of server failed" ; exit 1; }
-fi
-
-
-echo
-echo "To view server on ecflowview - goto Edit/Preferences/Servers and enter"
-echo "Name : <unique ecFlow server name>"
-echo "Host : $host"
-echo "Port Number : $ECF_PORT"
-echo
-
-exit 0
diff --git a/ecflow_4_0_7/tools/ecflow_stop.sh b/ecflow_4_0_7/tools/ecflow_stop.sh
deleted file mode 100755
index 32a992d..0000000
--- a/ecflow_4_0_7/tools/ecflow_stop.sh
+++ /dev/null
@@ -1,111 +0,0 @@
-#!/bin/sh
-#==========================================================================
-##.TITLE ECMWF utility for ecFlow
-##.NAME ecf_stop
-##.SECTION ECFLOW
-##.AUTHOR Avi
-## Revision : $Revision: #10 $
-##
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-##
-##.FILE ecf_stop
-##.INFO this file is expected to be located in /usr/local/share
-## it is to be used on ecgate by member states users
-## one ecf server occurence will be generated on ecgate
-#==========================================================================
-
-#set -eux
-
-PATH=/usr/local/bin:/usr/bin:$PATH
-export TZ=GMT LANG=en_GB.UTG-8
-host=$(hostname)
-backup_server=false
-
-case $host in
-sappa*) host=sappa;;
-sappb*) host=sappb;;
-ecga*) host=ecgate;;
-esac
-
-#==========================================================================
-# Syntax
-# ecf_stop [-b] [-p port_number ] [-h]
-#==========================================================================
-# get commane line options if any.
-while getopts b:p: option
-do
-case $option in
-b)
-backup_server=true
-;;
-p)
-ecf_port=$OPTARG
-;;
-h)
-echo "Usage: $0 [-b] [-p port_number ] [-h]"
-echo " -b stop ECF backup server"
-echo " -p <num> specify the ECF_PORT number - default 1000+<UID> | 500+<UID> for backup server"
-echo " -h print this help page"
-exit 0
-;;
-*)
-echo "Usage: $0 [-b] [-p port_number ] [-h]"
-echo " -b stop ECF backup server"
-echo " -p <num> specify the ECF_PORT number - default 1500+<UID> | 1000+<UID> for backup server"
-echo " -h print this help page"
-exit 1
-;;
-esac
-done
-
-#==========================================================================
-# port_number is set based on the unique users numeric uid.
-username=`id -u`
-
-if [ -z "$ecf_port" ] ; then
- if [ $backup_server = "true" ]; then
- base=1000
- else
- base=1500
- fi
- port_number=$((base+username))
-else
- port_number=$ecf_port
-fi
-
-date -u
-echo ""
-echo "User \"$username\" attempting to stop ecf server on $host:$port_number"
-
-#==========================================================================
-echo "";
-echo "Checking if the server is already running on $host:$port_number"
-
-export ECF_PORT=$port_number
-export ECF_NODE=$host
-set -x
-rcdir=$HOME/.ecflowrc
-fname=$rcdir/$(echo $ECF_NODE | cut -c1-5).$USER.$ECF_PORT # OK as long as ecgate node is under 10
-if [[ -f $fname ]]; then host=$(cat $fname); fi
-
-ecflow_client --host $host --ping
-if [ $? -eq 1 ]; then
- echo "";
- echo "... The server on $host:$port_number has already been stopped"
- exit 1
-fi
-
-#==========================================================================
-echo "";
-echo Halting, check pointing and terminating the server
-
-ecflow_client --host $host --halt=yes
-ecflow_client --host $host --check_pt
-ecflow_client --host $host --terminate=yes
-
-exit 0
diff --git a/ecflow_4_0_7/tools/noconnect.sh b/ecflow_4_0_7/tools/noconnect.sh
deleted file mode 100755
index 6e5ee32..0000000
--- a/ecflow_4_0_7/tools/noconnect.sh
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/sh
-# disconnect all hosts to start ecflowview with empty screen
-#==========================================================================
-##.TITLE ECMWF utility for ecFlow
-##.NAME
-##.SECTION ECFLOW
-##.AUTHOR
-## Revision : $Revision: #7 $
-##
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-##
-##.FILE
-##.INFO
-#==========================================================================
-
-d=$HOME/.xcdprc
-d=$HOME/.ecflowrc
-for f in $d/*options
-do
- # echo "## $f"
- if [ `grep "connect:true" $f 2>/dev/null` ]
- then
- # echo "### $f"
- sed -e 's|connect:true|connect:false|' $f > ${f}.tmp
- mv ${f}.tmp $f
- fi
-done
diff --git a/ecflow_4_0_7/view/CMakeLists.txt b/ecflow_4_0_7/view/CMakeLists.txt
deleted file mode 100644
index 11bf442..0000000
--- a/ecflow_4_0_7/view/CMakeLists.txt
+++ /dev/null
@@ -1,278 +0,0 @@
-# =======================================================
-# LIB
-# to list all sources to build use:
-# cd $WK/View
-# find src -name \icon_*.cc -print | sort
-# =======================================================
-
-# Files to exclude
-# src/lister.cc
-# src/extent.cc
-# src/node_alert.cc
-# src/array.cc
-# src/option.cc
-# src/dialog.cc
-# src/ecflowview.cc
-#
-# src/menul.c
-# src/tmpnam.c
-# src/line.c
-# src/x.c
-
-list( APPEND srcs_cc
- src/aborted.cc
- src/alerts.cc
- src/alias.cc
- src/ask.cc
- src/auto_alarm.cc
- src/base.cc
- src/collector.cc
- src/colors_prefs.cc
- src/configurable.cc
- src/confirm.cc
- src/counted.cc
- src/date.cc
- src/depend.cc
- src/directory.cc
- src/dummy_node.cc
- src/ecf_node.cc
- src/ecflow.cc
- src/edit.cc
- src/edit_label.cc
- src/edit_limit.cc
- src/edit_meter.cc
- src/edit_repeat.cc
- src/edit_variable.cc
- src/editor.cc
- src/error.cc
- src/event_node.cc
- src/external.cc
- src/find.cc
- src/flags.cc
- src/fonts_prefs.cc
- src/fsb.cc
- src/globals.cc
- src/graph_layout.cc
- src/gui.cc
- src/history.cc
- src/host.cc
- src/host_prefs.cc
- src/html_lister.cc
- src/http.cc
- src/hyper_lister.cc
- src/icon_Josstatus3.cc
- src/icon_W.cc
- src/icon_byrule.cc
- src/icon_cmd_failed.cc
- src/icon_edit_failed.cc
- src/icon_force_abort.cc
- src/icon_killed.cc
- src/icon_no_script.cc
- src/icon_queuelimit.cc
- src/icon_task_aborted.cc
- src/icon_user_edit.cc
- src/info.cc
- src/init.cc
- src/inlimit_node.cc
- src/input.cc
- src/interface.cc
- src/job.cc
- src/jobcheck_panel.cc
- src/jobstatus.cc
- src/label.cc
- src/late.cc
- src/late_node.cc
- src/layout.cc
- src/limit_node.cc
- src/log_event.cc
- src/logsvr.cc
- src/mail.cc
- src/manual.cc
- src/menu_prefs.cc
- src/menus.cc
- src/messages.cc
- src/meter_node.cc
- src/node.cc
- src/node_editor.cc
- src/node_list.cc
- src/node_window.cc
- src/not_enqueued.cc
- src/observable.cc
- src/observer.cc
- src/option_panel.cc
- src/output.cc
- src/panel.cc
- src/panel_window.cc
- src/parser.cc
- src/passwrd.cc
- src/persist.cc
- src/pixmap.cc
- src/pref_editor.cc
- src/pref_window.cc
- src/prefs.cc
- src/reach.cc
- src/relation.cc
- src/repeat_node.cc
- src/resource.cc
- src/restart.cc
- src/result.cc
- src/runnable.cc
- src/script_panel.cc
- src/scripting.cc
- src/search.cc
- src/searchable.cc
- src/selection.cc
- src/server.cc
- src/servers_prefs.cc
- src/show.cc
- src/simple_node.cc
- src/str.cc
- src/substitute.cc
- src/suites_panel.cc
- src/super_node.cc
- src/task_node.cc
- src/text_layout.cc
- src/text_window.cc
- src/time.cc
- src/timeout.cc
- src/timetable_panel.cc
- src/tip.cc
- src/tmp_file.cc
- src/top.cc
- src/translator.cc
- src/tree.cc
- src/trigger_node.cc
- src/trigger_panel.cc
- src/url.cc
- src/user_prefs.cc
- src/users.cc
- src/variable_node.cc
- src/variables.cc
- src/viewer.cc
- src/why.cc
- src/window.cc
- src/xdxmdialog.cc
- src/xdxtclass.cc
- src/xmstring.cc
- src/xnode.cc
- src/zombies_panel.cc
-)
-
-list( APPEND srcs_c
- src/Hyper.c
- src/SimpleBase.c
- src/SimpleGraph.c
- src/SimpleTime.c
- src/SimpleTree.c
- src/Tab.c
- src/menuy.c
-)
-
-file( GLOB srcs_cpp RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp" )
-file( GLOB libicon_srcs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/libicon/*.cc" )
-file( GLOB libxec_srcs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/libxec/*.c" )
-file( GLOB libui_srcs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/libui/*.cc" )
-
-# ======================================================================================
-
-find_package( X11 )
-debug_var( X11_INCLUDE_DIR )
-debug_var( X11_LIBRARIES )
-debug_var( X11_Xt_INCLUDE_PATH )
-debug_var( X11_Xt_LIB )
-debug_var( X11_Xpm_INCLUDE_PATH )
-debug_var( X11_Xpm_LIB )
-
-find_package( Motif )
-debug_var( MOTIF_INCLUDE_DIR )
-debug_var( MOTIF_LIBRARIES )
-
-
-# =======================================================================================
-find_package( CMath )
-
-set( CMAKE_THREAD_PREFER_PTHREAD TRUE )
-find_package( Threads )
-
-
-# =========================================================================================
-# libecflowview needs to be compiled as dynamic lin otherwise the icons do not appear.
-#
-# Note: -DECFLOW_SHARED_DIR is *ONLY* required for one file view/src/directory.cc
-#
-add_definitions( -D_GNU_SOURCE -DUNIX -Dunix -Dlinux -DECFLOW_SHARED_DIR="${CMAKE_INSTALL_PREFIX}/share/ecflow" )
-
-
-# local includes
-include_directories( src
- src/libicon
- src/libxec
- src/libui
- ../ACore/src
- ../ANattr/src
- ../ANode/src
- ../AParser/src
- ../Base/src
- ../Base/src/cts
- ../Base/src/stc
- ../Client/src
- )
-
-# in ecbuild_add_library INCLUDES is only for external includes
-ecbuild_add_library(TARGET libecflowview
- CONDITION MOTIF_FOUND AND X11_FOUND AND CMAKE_THREAD_LIBS_INIT
- SOURCES
- ${srcs_cc} ${srcs_c} ${srcs_cpp} ${libicon_srcs} ${libxec_srcs} ${libui_srcs}
- TEMPLATES
- src/array.cc
- INCLUDES
- ${X11_INCLUDE_DIR}
- ${MOTIF_INCLUDE_DIR}
- )
-
-# =======================================================================
-# EXE ecflowview
-# o crypt Does not appear to be used ?
-# o Xp libxprint does not appear to be used ?
-# o fl fast lexical analyser generator, not used ?
-# ========================================================================
-
-ecbuild_add_executable( TARGET ecflowview
- SOURCES
- src/ecflowview.cc
- CONDITION
- MOTIF_FOUND AND X11_FOUND AND CMAKE_THREAD_LIBS_INIT
- LIBS
- libecflowview libclient base libparser node nodeattr core
- ${CMAKE_THREAD_LIBS_INIT}
- ${X11_LIBRARIES} ${X11_Xext_LIB} ${MOTIF_LIBRARIES} ${X11_Xpm_LIB} ${X11_Xt_LIB}
- ${CMATH_LIBRARIES}
- INCLUDES
- ${X11_INCLUDE_DIR}
- ${MOTIF_INCLUDE_DIR}
- )
-
-
-# ===================================================================
-# test
-# ===================================================================
-
-ecbuild_add_test( TARGET test-view
- BOOST
- CONDITION MOTIF_FOUND AND X11_FOUND AND CMAKE_THREAD_LIBS_INIT
- SOURCES test/TestRunner.cpp test/TestView.cpp
- LIBS libharness
- INCLUDES ../Test/src
- TEST_DEPENDS s_test_zombies
- )
-
-# ===================================================================
-# install
-# ===================================================================
-
-install ( FILES ${CMAKE_SOURCE_DIR}/view/src/ecflowview.menu
- ${CMAKE_SOURCE_DIR}/view/servers
- DESTINATION share/ecflow
- PERMISSIONS OWNER_READ GROUP_READ WORLD_READ OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE
- )
-
diff --git a/ecflow_4_0_7/view/Jamfile.jam b/ecflow_4_0_7/view/Jamfile.jam
deleted file mode 100644
index 84c793d..0000000
--- a/ecflow_4_0_7/view/Jamfile.jam
+++ /dev/null
@@ -1,117 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-#
-# ecflowview
-#
-project ecflowview ;
-
-use-project theCore : ../ACore ;
-use-project theNodeAttr : ../ANattr ;
-use-project theNode : ../ANode ;
-use-project theBase : ../Base ;
-use-project theClient : ../Client ;
-use-project theTest : ../Test ;
-
-# This should be in the site-config.jam file as a project wide requirement
-# however if this is done, it will not link since, lpthread appears twice
-# on the link line
-#
-lib pthread ;
-
-import os ;
-MOTIF_INCLUDE = [ os.environ MOTIF_INCLUDE ] ;
-MOTIF_INCLUDE default = /usr/include ;
-# MOTIF_LIBRARY = [ os.environ MOTIF_LIBRARY ] ;
-# MOTIF_LIBRARY default = /usr/lib64 ;
-# echo "# MOTIF_LIBRARY = $(MOTIF_LIBRARY)" ;
-
-exe ecflowview
- : [ glob src/*.cc src/*.c src/*cpp
- src/libicon/*.cc src/libxec/*.c src/libui/*.cc :
- src/menul.c src/lister.cc src/tmpnam.c src/line.c src/x.c src/extent.cc
- src/node_alert.cc src/array.cc src/option.cc
- src/dialog.cc src/host.cc ]
- host
- /theCore//core
- /theNodeAttr//nodeattr
- /theNode//node
- /theParser//libparser
- /theBase//base
- /theClient//libclient
- /site-config//boost_system
- /site-config//boost_serialization
- /site-config//boost_filesystem
- /site-config//boost_program_options
- /site-config//boost_datetime
- pthread
- : <variant>debug:<define>DEBUG
-# <variant>release:<cxxflags>-O1
- <toolset>gcc:<include>$(MOTIF_INCLUDE)
- <include>../view/src
- <include>../view/src/libicon
- <include>../view/src/libxec
- <include>../view/src/libui
- <define>_GNU_SOURCE
- <define>linux
- <define>ECFLOW_SHARED_DIR='\"$(ECFLOW_SHARED_DIR)\"'
- <define>UNIX
- <define>unix
- <linkflags>-lm
- <linkflags>-g
- <toolset>gcc:<linkflags>-L$(MOTIF_LIBRARY)
- <dll-path>$(MOTIF_LIBRARY)
- <linkflags>-L/usr/X11R6/lib
- <linkflags>-lXpm
- <linkflags>-lXm
- <linkflags>-lXext
- <linkflags>-lXt
- <linkflags>-lX11
- ;
-
-obj host : src/host.cc
- /theCore//core
- /theNodeAttr//nodeattr
- /theNode//node
- /theParser//libparser
- /theBase//base
- /theClient//libclient
- : # <variant>release:<optimization>off
- <include>../view/src
- <include>../view/src/libicon
- <include>../view/src/libxec
- <include>../view/src/libui
- <define>_GNU_SOURCE
- <define>linux
- <define>ECFLOW_SHARED_DIR='\"$(ECFLOW_SHARED_DIR)\"'
- <define>UNIX
- <define>unix
- ;
-#
-# Test the view
-# This uses /theTest//libharness to setup a server
-#
-exe test-view : [ glob test/*.cpp ]
- pthread
- /theCore//core
- /theNodeAttr//nodeattr
- /theNode//node
- /theParser//libparser
- /theBase//base
- /theClient//libclient
- /theTest//libharness
- /site-config//boost_system
- /site-config//boost_serialization
- /site-config//boost_filesystem
- /site-config//boost_program_options
- /site-config//boost_datetime
- /site-config//boost_test
- : <include>../Base/test
- <include>../Test/src
- <variant>debug:<define>DEBUG
-# <variant>release:<cxxflags>-O1
- ;
diff --git a/ecflow_4_0_7/view/Makefile b/ecflow_4_0_7/view/Makefile
deleted file mode 100644
index f994b71..0000000
--- a/ecflow_4_0_7/view/Makefile
+++ /dev/null
@@ -1,99 +0,0 @@
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-KIND=bin/gcc-4.5
-CLNT=../Client/bin/gcc-4.5/debug/ecflow_client --port 3199
-CLNT=../Client/bin/gcc-4.5/release/ecflow_client --port 3199
-CLNT2=../Client/bin/gcc-4.5/debug/ecflow_client
-DEFS=
-DEFS=
-# DEFS=define=PORTABLE_BINARY_ARCHIVE
-DIRRC=~/.ecflowrc
-BJAM=bjam
-BJAM=$(BOOST_ROOT)/bjam c++-template-depth=512
-VALG=/tmp/map/work/valgrind-3.7.0/coregrind/valgrind
-
-all:
- $(BJAM) -j4 variant=debug $(DEFS) ecflowview
-
-fast:
- $(BJAM) variant=debug $(DEFS) ecflowview
-
-rel:
- $(BJAM) -j4 variant=release $(DEFS) ecflowview
-
-val:
- $(VALG) bin/gcc-4.5/release/ecflowview
-
-vald:
- $(VALG) bin/gcc-4.5/debug/ecflowview
-
-profile:
- $(BJAM) -j4 variant=profile $(DEFS) ecflowview
-
-prof: profile $(KIND)/profile/ecflowview
- date
- - time $(KIND)/profile/ecflowview
- gprof $(KIND)/profile/ecflowview gmon.out >gprof.out
- @cp gprof.out $(SCRATCH)/. # - kprof #
-
-# useful when updating the menu from the sources
-menuclean:
- rm -rf $(DIRRC)
- mkdir $(DIRRC)
-
-parse:
- cd src && lex -t menul.l > menul.c && yacc menuy.y && mv -f y.tab.c menuy.c && cd ../
-
-menu-full: menu parse all rel
-
-menu:
- sh src/menu2c.sh < src/ecflowview.menu > src/ecflowview.menu.h
- cp -f src/ecflowview.menu $(DIRRC)/.
- sh src/menu2c.sh < src/xcdp.menu > src/xcdp.menu.h
- cp -f src/xcdp.menu $(DIRRC)/.
-
-clean-run: menu all
- rm $(DIRRC)/ecflowview.menu || :
- exec ` find bin/ -name ecflowview`
-
-tags:
- etags ../[ABCv]*/src/*.[hcp]
-
-d:
- time $(KIND)/debug/ecflowview
-ddd:
- time ddd $(KIND)/debug/ecflowview
-
-clean:
- -\rm *~ gmon.out
- $(BJAM) clean
-
-calib:
- date; time $(CLNT) --get > /dev/null
- date; time $(CLNT) --get > 3199.tmp
- date; time python tool/timing.py
- date
-
-SUITE=test_suite
-load:
- $(CLNT) --replace /gui tool/test.def
- $(CLNT2) --host badger --port 31415 --group="get; show" > badger.def
- $(CLNT) --load badger.def
-
-boot:
- - $(CLNT) --load tool/3199.exp
-ping:
- - $(CLNT) --ping
-
-relbin:
- $(BJAM) -j4 variant=release define=PORTABLE_BINARY_ARCHIVE ecflowview
-
-t2:
- gcc t2.c -lXm -lX11
-t1:
- gcc t1.c
\ No newline at end of file
diff --git a/ecflow_4_0_7/view/install_server.sh b/ecflow_4_0_7/view/install_server.sh
deleted file mode 100755
index 0a77faf..0000000
--- a/ecflow_4_0_7/view/install_server.sh
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/ksh
-
-rdservers=/home/rd/rdx/ecflow/servers.config
-serv=servers
-cat servers.od > $serv
-cat $rdservers | grep vecf | grep -v -E "^#.*" | awk '{ print $1"\t"$2"\t"$3;}' | sort >> $serv
-
-loc=/usr/local/apps/ecflow/*/share/ecflow
-# loc=/usr/local/apps/ecflow/4.0.6/share/ecflow
-files=$serv
-files=ecflowview.menu
-dests="ibis ablamor opensuse113 opensuse103"
-set +x
-list="$(rsh $dest ls -d $loc | grep -v current)"
-# list=/usr/local/apps/ecflow/4.0.4/share/ecflow
-for dest in $dests; do
- for locs in $list; do
- rcp $files emos@$dest:$locs/. || echo $dest NOK
- done
-done
-
-dests="ecgb vsms1 vsms2 vsms3 lxab lxop opensuse131"
-list="$(ssh $dest ls -d $loc | grep -v current)"
-# list=/usr/local/apps/ecflow/4.0.4/share/ecflow
-for dest in $(echo $dests); do
- for locs in $list; do
- scp $files emos@$dest:$locs/. || echo $dest NOK
- done
-done
diff --git a/ecflow_4_0_7/view/servers b/ecflow_4_0_7/view/servers
deleted file mode 100644
index 0dfaab9..0000000
--- a/ecflow_4_0_7/view/servers
+++ /dev/null
@@ -1,48 +0,0 @@
-eod1 vsms1 32112
-sappa sappa 3141
-sappb sappb 3141
-eod2 vsms1 32222
-eod3 vsms1 43333
-eod4 vsms1 45555
-eode vsms2 31415
-tigge_lam vali 21801
-rdda1 vecfrdda1 11001
-rdda2 vecfrdda2 11002
-rddi1 vecfrddi1 11011
-rddi2 vecfrddi2 11012
-rdecgems1 vecfecgems1 11311
-rdecgems2 vecfecgems2 11312
-rderas1 vecferas1 11111
-rderas2 vecferas2 11112
-rdguest1 vecfrdguest1 11091
-rdna1 vecfrdna1 11021
-rdna2 vecfrdna2 11022
-rdne1 vecfrdne1 11031
-rdne2 vecfrdne2 11032
-rdocx-prod1 vecfocxprod1 11211
-rdocx-prod2 vecfocxprod2 11212
-rdpa1 vecfrdpa1 11041
-rdpa2 vecfrdpa2 11042
-rdst1 vecfrdst1 11051
-rdst2 vecfrdst2 11052
-rdtest1 vecfrdxadmin 12090
-rdx_admin vecfrdxadmin 10091
-xat1 vecfmspifs 21001
-xbe1 vecfmspifs 21011
-xch1 vecfmspifs 21021
-xde1 vecfmspifs 21031
-xdk1 vecfmspifs 21041
-xes1 vecfmspifs 21051
-xfi1 vecfmspifs 21061
-xfr1 vecfmspifs 21071
-xgb1 vecfmspifs 21081
-xge1 vecfmspifs 21091
-xgr1 vecfmspifs 21101
-xie1 vecfmspifs 21111
-xit1 vecfmspifs 21121
-xlu1 vecfmspifs 21131
-xnl1 vecfmspifs 21141
-xno1 vecfmspifs 21151
-xpt1 vecfmspifs 21161
-xse1 vecfmspifs 21171
-xtr1 vecfmspifs 21181
diff --git a/ecflow_4_0_7/view/servers.od b/ecflow_4_0_7/view/servers.od
deleted file mode 100644
index e630711..0000000
--- a/ecflow_4_0_7/view/servers.od
+++ /dev/null
@@ -1,8 +0,0 @@
-eod1 vsms1 32112
-sappa sappa 3141
-sappb sappb 3141
-eod2 vsms1 32222
-eod3 vsms1 43333
-eod4 vsms1 45555
-eode vsms2 31415
-tigge_lam vali 21801
diff --git a/ecflow_4_0_7/view/src/ArrayP.h b/ecflow_4_0_7/view/src/ArrayP.h
deleted file mode 100644
index cd7657d..0000000
--- a/ecflow_4_0_7/view/src/ArrayP.h
+++ /dev/null
@@ -1,60 +0,0 @@
-#ifndef ARRAYP_H
-#define ARRAYP_H
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #4 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-
-#include <Xm/XmP.h>
-#include <Xm/DrawingAP.h>
-
-typedef struct _ArrayClassPart {
- int ignore;
-} ArrayClassPart;
-
-typedef struct _ArrayClassRec {
- CoreClassPart core_class;
- CompositeClassPart composite_class;
- ConstraintClassPart constraint_class;
- XmManagerClassPart manager_class;
- XmDrawingAreaClassPart drawing_area_class;
- ArrayClassPart array_class;
-} ArrayClassRec;
-
-extern ArrayClassRec arrayClassRec;
-
-typedef struct {
- int round;
- int rows;
- int cols;
-} ArrayPart;
-
-
-typedef struct _ArrayRec {
- CorePart core;
- CompositePart composite;
- ConstraintPart constraint;
- XmManagerPart manager;
- XmDrawingAreaPart drawing_area;
- ArrayPart array;
-} ArrayRec;
-
-
-#define XtArrayNumChildren(w) (((ArrayWidget)w) -> composite.num_children)
-#define XtArrayChild(w,i) (((ArrayWidget)w) -> composite.children[i])
-
-#endif /* ARRAYP_H */
-
-
-
diff --git a/ecflow_4_0_7/view/src/Hyper.c b/ecflow_4_0_7/view/src/Hyper.c
deleted file mode 100644
index c3176ea..0000000
--- a/ecflow_4_0_7/view/src/Hyper.c
+++ /dev/null
@@ -1,1589 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : B.Raoult */
-/* Revision : $Revision: #5 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : Hyper text like widget. */
-/*=============================================================================================*/
-
-#include <stdio.h>
-#include <errno.h>
-#include <ctype.h>
-#include <X11/IntrinsicP.h>
-#include <X11/Intrinsic.h>
-#include <X11/StringDefs.h>
-#include <X11/CoreP.h>
-#include <X11/cursorfont.h>
-#include "Hyper.h"
-#include "HyperP.h"
-#include <Xm/ScrollBar.h>
-#include <stdlib.h>
-#include <string.h> /* strerror */
-
-extern void xec_compile(char *w);
-extern int xec_step(char *p);
-
-#ifndef ABS
-#define ABS(a) ((a)>=0?(a):-(a))
-#endif
-#ifndef MIN
-#define MIN(a,b) ((a)>(b)?(b):(a))
-#endif
-
-#define ESIZE 1024
-
-#define NORMAL 0
-#define HIGHLIGHT 1
-#define NEWLINE 2
-
-#define MAX_LINE_SIZE 1024
-
-extern char *xec_loc1, *xec_loc2;
-
-/*
- Private functions
-*/
-
-static void hilite(HyperWidget w,Boolean on);
-static text_segment *find_segment(HyperWidget,int,int);
-static void free_text(text_segment*);
-static void create_gcs(HyperWidget);
-static void create_new_text(HyperWidget);
-static void xselect();
-static void cursor();
-static void activate();
-static void xincrement();
-static void add_to_text ( HyperWidget,char*,int,int);
-static void calc_new_size (HyperWidget);
-static void zoom_open (HyperWidget,text_segment*);
-static void show_selection(HyperWidget);
-static void set_selection(HyperWidget);
-static void clear_selection(HyperWidget);
-static void lowcase(char *p);
-static void find_visible_part(Widget,Position*,Position*,Dimension*,Dimension*);
-static void set_text(HyperWidget,char (*)(XtPointer),XtPointer);
-
-/*
- Widget class methods
-*/
-
-static void Initialize();
-static void Redisplay();
-static void Resize();
-static void Destroy();
-static Boolean SetValues();
-
-static char defaultTranslations[] =
-" <Btn1Down>:select()\n <Btn1Up>: activate()\n\
- <Motion>:cursor()\n\
- <Btn2Down>:select()\n <Btn2Up>: activate() \n\
- Shift<Btn5Down>: increment(1)\n Shift<Btn4Down>: increment(-1) \n\
- <Btn5Down>: increment(10)\n <Btn4Down>: increment(-10) \n";
-
-static XtActionsRec actionsList[] = {
- { "select", (XtActionProc) xselect},
- { "activate", (XtActionProc) activate},
- { "cursor", (XtActionProc) cursor},
- { "increment",(XtActionProc) xincrement},
-};
-
-static XtResource resources[] = {
-
- {XtNhighlightFont, XtCFont, XtRFontStruct, sizeof (XFontStruct *),
- XtOffset(HyperWidget, hyper.highlight_font), XtRString, "fixed"},
-
- {XtNnormalFont, XtCFont, XtRFontStruct, sizeof (XFontStruct *),
- XtOffset(HyperWidget, hyper.normal_font), XtRString, "fixed"},
-
- {XtNhighlightColor, XtCColor, XtRPixel, sizeof (Pixel),
- XtOffset(HyperWidget, hyper.highlight_color),XtRString, "Red"},
-
- {XtNselectColor, XtCColor, XtRPixel, sizeof (Pixel),
- XtOffset(HyperWidget, hyper.select_color),XtRString, "Blue"},
-
- {XtNnormalColor, XtCColor, XtRPixel, sizeof (Pixel),
- XtOffset(HyperWidget, hyper.normal_color),XtRString,"Black"},
-
- {XtNactivateCallback,XtCCallback,XtRCallback,sizeof(caddr_t),
- XtOffset (HyperWidget, hyper.activate),XtRCallback,NULL},
-
- {XtNzoomEffect,XtCZoom,XtRBoolean,sizeof(Boolean),
- XtOffset (HyperWidget, hyper.zoom),XtRImmediate,(XtPointer)TRUE},
-
-#ifndef XDESIGNER
- {XtNstartHighlight,XtCTagChar,XtRUnsignedChar,sizeof(unsigned char),
- XtOffset(HyperWidget,hyper.start_of_highlight),XtRImmediate,
- (XtPointer)'{'},
-
- {XtNendHighlight,XtCTagChar,XtRUnsignedChar,sizeof(unsigned char),
- XtOffset (HyperWidget, hyper.end_of_highlight),XtRImmediate,
- (XtPointer)'}'},
-#endif
-
- {XtNzoomSpeed,XtCZoomSpeed,XtRInt,sizeof(int),
- XtOffset (HyperWidget, hyper.speed),XtRImmediate,(XtPointer)4},
-
- {XtNmargin,XtCMargin,XtRInt,sizeof(int),
- XtOffset (HyperWidget, hyper.margin),XtRImmediate,(XtPointer)10},
-
-};
-
-/*---------------------------------------------------------------*/
-/* Static initialisation of the class record */
-/*---------------------------------------------------------------*/
-
-HyperClassRec hyperClassRec = {
- {
-#ifdef MOTIF
- (WidgetClass) &xmPrimitiveClassRec, /* superclass */
-#else
- (WidgetClass) &widgetClassRec, /* superclass */
-#endif
- "Hyper", /* class_name */
- sizeof(HyperRec), /* widget_size */
- NULL, /* class_initialize */
- NULL, /* class_part_initialize */
- FALSE, /* class_inited */
- Initialize, /* initialize */
- NULL, /* initialize_hook */
- XtInheritRealize, /* realize */
- actionsList, /* actions */
- XtNumber(actionsList), /* num_actions */
- resources, /* resources */
- XtNumber(resources), /* num_resources */
- NULLQUARK, /* xrm_class */
- TRUE, /* compress_motion */
- XtExposeCompressMaximal, /* compress_exposure */
- TRUE, /* compress_enterleave */
- TRUE, /* visible_interest */
- Destroy, /* destroy */
- Resize, /* resize */
- Redisplay, /* expose */
- SetValues, /* set_values */
- NULL, /* set_values_hook */
- XtInheritSetValuesAlmost, /* set_values_almost */
- NULL, /* get_values_hook */
- NULL, /* accept_focus */
- XtVersion, /* version */
- NULL, /* callback private */
- defaultTranslations, /* tm_table */
- NULL, /* query_geometry */
- NULL, /* display_accelerator */
- NULL, /* extension */
- },
-#ifdef MOTIF
- {
- (XtWidgetProc)_XtInherit, /* border_highlight */
- (XtWidgetProc)_XtInherit, /* border_unhighligh */
- XtInheritTranslations, /* translations */
-/*** SOS!!!! Following line was replaced ...... */
-/* (XtWidgetProc)_XtInherit, arm_and_activate */
-#if (XmVersion == 1001)
- (XmArmAndActivate)_XtInherit, /* arm_and_activate */
-#else
- (XtActionProc)_XtInherit, /* arm_and_activate */
-#endif
- NULL, /* syn_resources */
- 0, /* num_syn_resources */
- NULL, /* extension */
- },
-#endif
- {
- 0, /* ignore */
- }
-};
-
-
-
-
-
-
-
-
-
-WidgetClass hyperWidgetClass = (WidgetClass) &hyperClassRec;
-
-/*---------------------------------------------------------------*/
-/* Create the two GCs needed */
-/*---------------------------------------------------------------*/
-
-static void create_gcs(w)
-HyperWidget w;
-{
- XGCValues values;
- XtGCMask valueMask;
-
- valueMask = GCForeground | GCBackground | GCFont;
-
- values.background = w->core.background_pixel;
-
- values.foreground = w->hyper.highlight_color;
- values.font = w->hyper.highlight_font->fid;
- w->hyper.highlight_gc = XtGetGC((Widget)w, valueMask, &values);
-
- values.foreground = w->hyper.select_color;
- w->hyper.select_gc = XtGetGC((Widget)w, valueMask, &values);
-
- values.foreground = w->hyper.normal_color;
- values.font = w->hyper.normal_font->fid;
- w->hyper.normal_gc = XtGetGC((Widget)w, valueMask, &values);
-
-
-
- valueMask = GCBackground|GCForeground|GCFunction|GCGraphicsExposures;
-
- values.background = 0;
- values.foreground = w->hyper.normal_color ^ w->core.background_pixel;
- values.graphics_exposures = False;
- values.function = GXxor;
-
- w->hyper.xor_gc = XtGetGC((Widget)w, valueMask, &values);
-
-
-}
-
-/*--------------------------------------------------------------*/
-/* Initialize: Create the GCs */
-/*--------------------------------------------------------------*/
-
-static void Initialize (request, new)
-HyperWidget request, new;
-{
- /* Check the size of the widget */
-
- if (request->core.width == 0)
- new->core.width = 100;
- if (request->core.height == 0)
- new->core.height = 100;
-
-
- /* Create the GCs */
-
- create_gcs(new);
-
- /* No text yet */
-
- new->hyper.first_seg = new->hyper.last_selected
- = new->hyper.last_cursor = NULL;
- new->hyper.hand = XCreateFontCursor(XtDisplay(new),XC_hand2);
-
- /* Nothing found */
-
- new->hyper.grep_seg = NULL;
- new->hyper.grep_txt = NULL;
- new->hyper.grep_len = 0;
- new->hyper.grep_off = 0;
-
-}
-
-/*--------------------------------------------------------------*/
-/* Free all memory allocated for the text segments */
-/*--------------------------------------------------------------*/
-
-static void free_text(s)
-text_segment *s;
-{
-
- while(s)
- {
- text_segment *p=s->next;
- if(s->text) XtFree((XtPointer)s->text);
- XtFree((XtPointer)s);
- s = p;
- }
-
-}
-
-/*--------------------------------------------------------------*/
-/* Destroy the widget: release all memory alocated */
-/*--------------------------------------------------------------*/
-
-static void Destroy (w)
-HyperWidget w;
-{
- free_text(w->hyper.first_seg);
- XtReleaseGC((Widget)w, w->hyper.normal_gc);
- XtReleaseGC((Widget)w, w->hyper.highlight_gc);
- XtReleaseGC((Widget)w, w->hyper.xor_gc);
- XtReleaseGC((Widget)w, w->hyper.select_gc);
- XtRemoveAllCallbacks ((Widget)w,XtNactivateCallback);
-}
-
-/*--------------------------------------------------------------*/
-/* Resize : not implemented */
-/*--------------------------------------------------------------*/
-
-
-static void Resize (w)
-HyperWidget w;
-{
- /*
- For futur implementation
- May be for text warp ...
- */
-}
-
-/*--------------------------------------------------------------*/
-/* Redisplay : redraw the text */
-/*--------------------------------------------------------------*/
-
-
-static void Redisplay (w, event, region)
-HyperWidget w;
-XEvent *event;
-Region region;
-{
-
- if(w->core.visible)
- {
- text_segment *s = w->hyper.first_seg;
- int x = w->hyper.margin;
- int y = 0;
- Boolean newline = TRUE;
-
- while(s)
- {
-
- /* change line on new lines */
-
- if(newline)
- {
- x = w->hyper.margin;
- y += s->height;
- }
-
- /* redraw only what is needed */
-
- if(XRectInRegion(region,x,y-s->height+s->desc,s->width,s->height)
- != RectangleOut)
- {
-
- XDrawImageString(XtDisplay (w), XtWindow (w),
- s->gc,
- x,
- y,
- s->text,
- s->length);
-
- if(s->type == HIGHLIGHT)
- {
- XDrawLine(XtDisplay (w), XtWindow (w),
- s->gc,
- x,
- y+1,
- x+s->width,
- y+1);
- }
- }
-
- x += s->width;
-
- newline = (s->type == NEWLINE);
-
- s = s->next;
- }
-
-
- if(w->hyper.grep_seg)
- {
- if(XRectInRegion(region,
- w->hyper.grep_x,
- w->hyper.grep_y,
- w->hyper.grep_width,
- w->hyper.grep_height) != RectangleOut)
-
- XFillRectangle(XtDisplay(w),XtWindow(w),
- w->hyper.xor_gc,
- w->hyper.grep_x,
- w->hyper.grep_y,
- w->hyper.grep_width,
- w->hyper.grep_height);
-
- }
- }
-}
-
-/*------------------------------------------------------------------*/
-/* SetValues : redraw only for font or color changes */
-/*------------------------------------------------------------------*/
-
-static Boolean SetValues (current, request, new)
-HyperWidget current, request, new;
-{
- Boolean redraw = FALSE;
-
-#define HAS_CHANGED(a) (new->a != current->a)
-
- if(
- HAS_CHANGED(core.background_pixel) ||
- HAS_CHANGED(hyper.select_color) ||
- HAS_CHANGED(hyper.highlight_color) ||
- HAS_CHANGED(hyper.highlight_font) ||
- HAS_CHANGED(hyper.normal_color) ||
- HAS_CHANGED(hyper.normal_font)
- )
- {
-
- XtReleaseGC((Widget)new, new->hyper.normal_gc);
- XtReleaseGC((Widget)new, new->hyper.highlight_gc);
- XtReleaseGC((Widget)new, new->hyper.xor_gc);
- XtReleaseGC((Widget)new, new->hyper.select_gc);
- create_gcs(new);
-
- /* rebuild text */
-/*
- if(HAS_CHANGED(hyper.normal_font) ||
- HAS_CHANGED(hyper.highlight_font))
- */
- create_new_text(new);
-
- redraw = TRUE;
- }
-
- return (redraw);
-
-#undef HAS_CHANGED
-
-}
-
-/*------------------------------------------------------------------*/
-/* Calculate the size of the widget */
-/*------------------------------------------------------------------*/
-
-static void calc_new_size (w)
-HyperWidget w;
-{
- text_segment *s = w->hyper.first_seg;
- int x = w->hyper.margin;
- int y = 0;
- int last_height = 0;
- Boolean newline = TRUE;
- Dimension maxWidth = w->hyper.margin;
- Dimension maxHeight = w->hyper.margin;
- XtGeometryResult result;
- Dimension replyWidth = 0, replyHeight = 0;
-
- /* Get the size of the widget */
-
- while(s)
- {
- if(newline)
- {
- if (x > (int) maxWidth) maxWidth=x;
- x = w->hyper.margin;
- y += s->height;
- if(y > (int) maxHeight) maxHeight=y;
-
- }
-
- s->x = x;
- s->y = y - s->height;
-
- x += s->width;
-
- newline = (s->type == NEWLINE);
- last_height = s->height;
-
- s = s->next;
- }
-
- x+= w->hyper.margin;
- y+= last_height;
-
- if((Dimension) x > maxWidth ) maxWidth=x;
- if((Dimension) y > maxHeight) maxHeight=y;
-
- /*
- Tell our parent we want a new size
- */
-
- if(w->core.width != maxWidth || w->core.height != maxHeight)
- {
- result = XtMakeResizeRequest((Widget)w,maxWidth,maxHeight,
- &replyWidth, &replyHeight) ;
-
- if (result == XtGeometryAlmost)
- XtMakeResizeRequest ((Widget)w, replyWidth, replyHeight,NULL, NULL);
-
- }
-}
-
-/*-----------------------------------------------------------------------*/
-/* Find the "visible" part of a widget as the intersection of all the */
-/* windows of it's parents' windows */
-/*-----------------------------------------------------------------------*/
-
-static void find_visible_part(w,x,y,width,height)
-Widget w;
-Position *x;
-Position *y;
-Dimension *width;
-Dimension *height;
-{
- Position root_x,root_y;
- Widget p = w;
-
- *width = w->core.width;
- *height = w->core.height;
- XtTranslateCoords(w,0,0,&root_x,&root_y);
-
- *x = 0;
- *y = 0;
-
- while((p = XtParent(p)))
- {
- Position rx,ry;
- Dimension w,h;
-
- /*
- make all computations in the root's
- coordinate system
- */
-
- XtTranslateCoords(p,0,0,&rx,&ry);
-
- w = p->core.width;
- h = p->core.height;
-
- /*
- use the smallest rectangle
- */
-
- if(w < *width) *width = w;
- if(h < *height) *height = h;
-
- if(rx>root_x) root_x = rx;
- if(ry>root_y) root_y = ry;
-
- /* stop when reach a shell,
- don't go to top level shell */
- if(XtIsShell(p)) break;
- }
-
- /* Back to the widget's coordinate system */
-
- XtTranslateCoords(w,0,0,x,y);
- *x = root_x - *x;
- *y = root_y - *y;
-
-
-}
-
-/*-----------------------------------------------------------------------*/
-/* Do a "zoom" effect animation, from the selected text segment to the */
-/* visible part of the widget */
-/*-----------------------------------------------------------------------*/
-
-static void zoom_open(w,s)
-HyperWidget w;
-text_segment *s;
-{
- int dx1,dx2,dy1,dy2;
-
- Position x ;
- Position y ;
- Dimension width ;
- Dimension height ;
-
- /* selected rectangle */
-
- Position xs = s->x;
- Position ys = s->y;
- Dimension ws = s->width;
- Dimension hs = s->height;
-
-
- /* get the rectangle we want to zoom to */
-
- find_visible_part((Widget)w,&x,&y,&width,&height);
-
- /* make sure selected rectangle in visible */
-
- if(xs<x) xs = x;
- if(ys<y) ys = y;
- if((Dimension)(xs+ws) > (Dimension)(x+width)) ws = x+width-xs;
- if((Dimension)(ys+hs) > (Dimension)(y+height)) hs = y+height-ys;
-
- /* get the offsets in each directions */
-
- dx1 = x-xs;
- dy1 = y-ys;
- dx2 = ((x+width)-(xs+ws));
- dy2 = ((y+height)-(ys+hs));
-
- /* in the rectangles are differents */
-
- if(dx1 || dy1 || dx2 || dy2)
- {
- int min = 32000; /* <-- Can be buggy */
-
- /*
- work in "left,top,bottom,right" rectangles (Mac)
- rather than "x,y,width,height" (X)
- It's easier for the animation
- */
-
- int xws = xs+ws;
- int yhs = ys+hs;
-
- /* Get smallest non-null offset */
-
- if(dx1) min = MIN(min,ABS(dx1));
- if(dx2) min = MIN(min,ABS(dx2));
- if(dy1) min = MIN(min,ABS(dy1));
- if(dy2) min = MIN(min,ABS(dy2));
-
- /* Scale offsets so minimun offset is 1 pixel */
-
- dx1 /= min;
- dx2 /= min;
- dy1 /= min;
- dy2 /= min;
-
- /* Use speed .. */
-
- dx1 *= w->hyper.speed;
- dx2 *= w->hyper.speed;
- dy1 *= w->hyper.speed;
- dy2 *= w->hyper.speed;
-
- /* Animate */
-
- while(min--)
- {
- XDrawRectangle(XtDisplay(w),XtWindow(w),
- w->hyper.xor_gc,xs,ys,xws-xs,yhs-ys);
-
- /* Needed, otherwise X calls are buffered */
- XSync(XtDisplay(w),False);
-
- XDrawRectangle(XtDisplay(w),XtWindow(w),
- w->hyper.xor_gc,xs,ys,xws-xs,yhs-ys);
-
- xs += dx1;
- ys += dy1;
-
- xws += dx2;
- yhs += dy2;
-
- }
- }
-
-}
-
-/*----------------------------------------------------------------------*/
-/* Find the text segment at point (x,y) */
-/*----------------------------------------------------------------------*/
-static text_segment *find_segment(w,x,y)
-HyperWidget w;
-int x,y;
-{
- text_segment *s = w->hyper.first_seg;
-
- while(s)
- {
- if( s->type == HIGHLIGHT &&
- x >= s->x &&
- y >= s->y &&
- (Dimension) x <= (Dimension) (s->x + s->width) &&
- (Dimension) y <= (Dimension) (s->y + s->height)
- )
- return s;
- s = s->next;
- }
-
- return NULL;
-}
-
-/*----------------------------------------------------------------------*/
-/* highlight text under cursor */
-/*----------------------------------------------------------------------*/
-static void hilite(HyperWidget w,Boolean on)
-{
-
- text_segment *s = w->hyper.last_selected;
-
- if(s)
- XDrawImageString(XtDisplay (w), XtWindow (w),
- on?w->hyper.select_gc:s->gc,
- s->x,
- s->y+s->height,
- s->text, s->length);
-
-}
-
-/*-----------------------------------------------------------------------*/
-/* Check for mouse down */
-/*-----------------------------------------------------------------------*/
-
-static void xselect (w, event, args, n_args)
-HyperWidget w;
-XEvent *event;
-char *args[];
-int n_args;
-{
- text_segment *s;
-
- /*
- Find if the used clicked in an
- highlighted text
- */
-
- if((s = w->hyper.last_selected = find_segment(w,event->xbutton.x,event->xbutton.y)))
- hilite(w,TRUE);
-}
-
-/*-----------------------------------------------------------------------*/
-/* Check for mouse up */
-/*-----------------------------------------------------------------------*/
-
-static void activate (w, event, args, n_args)
-HyperWidget w;
-XEvent *event;
-char *args[];
-int n_args;
-{
- hyperCallbackStruct cb;
- text_segment *s;
-
- /*
- Find if the user clicked in an
- highlighted text
- */
-
- if((s = find_segment(w,event->xbutton.x,event->xbutton.y))
- && (s == w->hyper.last_selected))
- {
- hilite(w,FALSE);
-
- /* zoom if required */
-
- if(w->hyper.zoom) zoom_open(w,s);
-
- /* Fill callback struct */
-
- cb.text = s->text;
- cb.length = s->length;
- cb.reason = HYPER_REASON;
- cb.event = event;
-
- /* call callbacks */
-
- XtCallCallbacks((Widget)w, XtNactivateCallback, (XtPointer)&cb);
- }
- w->hyper.last_selected = NULL;
-}
-
-/*-----------------------------------------------------------------------*/
-/* Check for mouse moves */
-/*-----------------------------------------------------------------------*/
-
-static void cursor (w, event, args, n_args)
-HyperWidget w;
-XEvent *event;
-char *args[];
-int n_args;
-{
-
- text_segment *s;
-
- s = find_segment(w,event->xbutton.x,event->xbutton.y);
-
- if(s != w->hyper.last_cursor)
- {
- if(s)
- XDefineCursor(XtDisplay(w),XtWindow(w),w->hyper.hand);
- else
- XUndefineCursor(XtDisplay(w),XtWindow(w));
- hilite(w,s == w->hyper.last_selected);
- w->hyper.last_cursor = s;
- }
-
-}
-
-static void xincrement (h, event, args, n_args)
-HyperWidget h;
-XEvent *event;
-char *args[];
-int n_args;
-{
-#ifdef MOTIF
-#define SetArg(a,b) XtSetArg(al[ac],a,b);ac++
-#define GetValues(w) XtGetValues(w,al,ac);ac=0
-#define SetValues(w) XtSetValues(w,al,ac);ac=0
-
- Widget clip = XtParent(h);
- Widget swin;
- Widget v_scroll;
-
- int ac = 0;
-
-// Position x_grep,y_grep;
-// Dimension h_grep,w_grep;
-// Position x_clip,y_clip;
-// Dimension h_clip,w_clip;
-// Position dv=0,dh=0;
-// int min,max;
-// int v_val,v_size,v_inc,v_page;
-// int h_val,h_size,h_inc,h_page;
-// Position x,y;
-
- Position dh=0;
-
- Arg al[5];
-
- // https://software.ecmwf.int/issues/browse/SUP-646
-
- /* printf("## mouse 1\n"); */
- if(!clip) return;
- swin = XtParent(clip);
-
- /* printf("## mouse 2\n"); */
- // if(!swin || !XmIsScrolledWindow(swin)) return;
- if(!swin) return;
-
- /* printf("## mouse 3\n"); */
- // 20131126 if (n_args != 1) return;
- SetArg(XmNverticalScrollBar , &v_scroll);
- GetValues(swin);
-
- {
- int min = 0;
- int max = 80;
- int value = 0;
- int slider_size = 80;
- int inc = 10;
- int page_inc = 100;
- SetArg(XmNminimum,&min); /* ??? */
- SetArg(XmNmaximum,&max);
- SetArg(XmNvalue,&value);
- SetArg(XmNsliderSize,&slider_size);
- SetArg(XmNincrement,&inc);
- /* SetArg(XmNpageIncrement,&page_inc); ??? */
-
- GetValues(v_scroll);
- /* XmScrollBarGetValues(v_scroll, value, slider_size, inc, page_inc); */
-
- int arg = atoi(args[0]);
- dh = (abs(arg) > 5) ? page_inc : inc;
-
- if (arg < 0) {
- if (value - dh < min)
- value = min;
- else
- value -= dh;
- } else {
- if (value + dh > max)
- value = max;
- else
- value += dh;
- }
-
- XmScrollBarSetValues(v_scroll,value,slider_size, inc, page_inc,TRUE);
- }
-#endif
-}
-
-/*-----------------------------------------------------------------------*/
-/* Add a new text segment to the text */
-/*-----------------------------------------------------------------------*/
-/* static void add_to_text(w,word,type) */
-static void add_to_text(w,word,type,offset) /* add offset */
-HyperWidget w;
-char *word;
-int type;
-int offset; /* add offset */
-{
- text_segment *s = XtNew(text_segment);
- XCharStruct char_info;
- int dir,ascent,desc;
- text_segment *p,*q;
-
- s->next = NULL;
- s->text = (word?XtNewString(word):NULL);
- s->type = type;
- s->gc = (type == HIGHLIGHT ? w->hyper.highlight_gc : w->hyper.normal_gc);
- s->x = s->y = s->width = s->height = 0;
- s->length = (word?strlen(word):0);
- if(offset>=0) s->offset = offset; /* add offset */
-
- XTextExtents(
- (type == HIGHLIGHT ? w->hyper.highlight_font : w->hyper.normal_font),
- word,
- s->length,
- &dir,&ascent,&desc,&char_info);
-
- s->height = ascent + desc;
- s->desc = desc;
- s->width = char_info.width;
-
- if((p = w->hyper.first_seg))
- {
- while(p)
- {
- q=p;
- p=p->next;
- }
- q->next = s;
- }
- else w->hyper.first_seg = s;
-}
-
-/*-----------------------------------------------------------------------*/
-/* Rebuild the text structure. Called when the font changes */
-/*-----------------------------------------------------------------------*/
-
-static void create_new_text(w)
-HyperWidget w;
-{
- text_segment *s = w->hyper.first_seg;
-
- w->hyper.first_seg = w->hyper.last_selected = w->hyper.last_cursor = NULL;
-
- while(s)
- {
- /* add_to_text(w,s->text,s->type); */
- add_to_text(w,s->text,s->type, -1); /*don't update offset */
- s = s->next;
- }
- free_text(s);
- calc_new_size(w);
-}
-
-/*-----------------------------------------------------------------------*/
-/* Build the text. Gets the chars from the funtion "get_next_char" */
-/* using "data" as a parameter */
-/*-----------------------------------------------------------------------*/
-
-static void set_text(w,get_next_char,data)
-HyperWidget w;
-char (*get_next_char)(XtPointer);
-XtPointer data;
-{
- char word[MAX_LINE_SIZE];
- int i = 0;
- char soh = w->hyper.start_of_highlight;
- char eoh = w->hyper.end_of_highlight;
- char c;
- int mode = NORMAL;
- int offset = 0; /* add offset */
-
- free_text(w->hyper.first_seg);
- w->hyper.first_seg = w->hyper.last_selected = w->hyper.last_cursor = NULL;
- w->hyper.grep_seg = NULL;
- w->hyper.grep_txt = NULL;
- w->hyper.grep_len = 0;
- w->hyper.grep_off = 0;
-
- while((c = (get_next_char)(&data)))
- {
-
- /* New line */
-
- if(c == '\n')
- {
- word[i]=0;
- /* if(i) add_to_text(w,word,mode); */
- if(i) { /* add offset */
- add_to_text(w,word,mode,offset); /* add offset */
- offset+=i; /* increment offset */
- } /* add offset */
- /* add_to_text(w,NULL,NEWLINE); */
- add_to_text(w,NULL,NEWLINE, offset); /* add offset */
- i = 0;
- }
-
- /* Start of highlight */
-
- else if(c == soh)
- {
- word[i]=0;
- /* if(i) add_to_text(w,word,mode); */
- if(i) { /* add offset */
- add_to_text(w,word,mode,offset); /* add offset */
- offset += i; /* increment offset */
- } /* add offset */
- mode = HIGHLIGHT;
- i = 0;
- }
-
- /* End of highlight */
-
- else if(c == eoh)
- {
- word[i]=0;
- /* if(i) add_to_text(w,word,mode); */
- if(i) { /* add offset */
- add_to_text(w,word,mode,offset); /* add offset */
- offset += i+2; /* increment offset, 2 to iclude tags */
- } /* add offset */
- mode = NORMAL;
- i = 0;
- }
- else
- {
- if(c=='\t') c = ' ';
- word[i++] = c;
- if(i==MAX_LINE_SIZE)
- {
- word[--i]=0;
- /* add_to_text(w,word,mode); */
- add_to_text(w,word,mode,offset); /* add offset */
- i=0;
- word[i++] = c;
- }
- }
- }
-
- /* flush .. */
-
- if(i)
- {
- word[i]=0;
- add_to_text(w,word,mode,offset);
- }
-
- calc_new_size(w);
-
- /* br advised, vk realized 02 Jun 94 */
- if(XtIsRealized((Widget) w))
- XClearArea(XtDisplay(w),XtWindow(w),0,0,0,0,True);
-
-}
-
-/*-----------------------------------------------------------------------*/
-/* Create a new HyperWidget */
-/*-----------------------------------------------------------------------*/
-
-Widget CreateHyper(parent,name,al,ac)
-Widget parent;
-char *name;
-ArgList al;
-int ac;
-{
- return XtCreateWidget(name,hyperWidgetClass,parent,al,ac);
-}
-
-
-/*-----------------------------------------------------------------------*/
-/* Load the text from a file */
-/*-----------------------------------------------------------------------*/
-
-/* provides chars to "set_text" routine */
-
-static char get_from_file(XtPointer d)
-{
- FILE **f = (FILE**)d;
- int n = getc(*f);
- return (n==EOF?0:(char)n);
-}
-
-/* Public routine */
-
-void HyperLoadFile(widget,fname)
-Widget widget;
-char *fname;
-{
-/*#ifndef linux
- extern char *sys_errlist[];
- #endif*/
-
- FILE *f = fopen(fname,"r");
- if(f)
- {
- set_text((HyperWidget)widget,get_from_file,(XtPointer)f);
- fclose(f);
- }
- else
- {
- char msg[1024];
- sprintf(msg,"%s: %s",fname,strerror(errno)); /* sys_errlist[errno]); */
- XtWarning(msg);
- }
-
-}
-
-/*-----------------------------------------------------------------------*/
-/* Load text from memory buffer */
-/*-----------------------------------------------------------------------*/
-
-/* provides chars to "set_text" routine */
-
-static char get_from_buffer(XtPointer d)
-{
- char **buffer = (XtPointer)d;
- char c = **buffer;
- (*buffer)++;
- return c;
-}
-
-/* Public routine */
-
-void HyperSetText(widget,text)
-Widget widget;
-char *text;
-{
- set_text((HyperWidget)widget,get_from_buffer,(XtPointer)text);
-}
-
-/*-----------------------------------------------------------------------*/
-/* Specifies start and end of highlignt chars */
-/*-----------------------------------------------------------------------*/
-
-#ifdef _NO_PROTO
-
-void HyperSetTags(widget,start_highlight,end_highlight)
-Widget widget;
-int start_highlight;
-int end_highlight;
-
-#else
-
-void HyperSetTags(Widget widget,
- int start_highlight,
- int end_highlight)
-
-#endif
-
-{
- ((HyperWidget)widget)->hyper.start_of_highlight = start_highlight;
- ((HyperWidget)widget)->hyper.end_of_highlight = end_highlight;
-}
-
-
-/*-----------------------------------------------------------------------*/
-/* convert a string to lower case */
-/*-----------------------------------------------------------------------*/
-
-static void lowcase(p)
-register char *p;
-{
- while(*p)
- {
- if(isupper(*p)) *p += 32;
- p++;
- }
-}
-
-/*-----------------------------------------------------------------------*/
-/* Returns the text of the widget */
-/* the memory is allocated. It must be freed by the application */
-/* If include_tags if FALSE, the special characters are not returned */
-/*-----------------------------------------------------------------------*/
-
-#ifdef _NO_PROTO
-
-char *HyperGetText(widget,include_tags)
-Widget widget;
-Boolean include_tags;
-
-#else
-
-char *HyperGetText(Widget widget,Boolean include_tags)
-
-#endif
-{
-
- HyperWidget w = (HyperWidget)widget;
- char *p ;
- text_segment *s = w->hyper.first_seg;
- int len = 1;
- char soh[2];
- char eoh[2];
-
- soh[0] = w->hyper.start_of_highlight;
- eoh[0] = w->hyper.end_of_highlight;
-
- soh[1] = eoh[1] = 0;
-
- /* Get size of text */
-
- while(s)
- {
- len += s->length?s->length:1;
- if(include_tags && s->type == HIGHLIGHT)
- len += 2;
- s = s->next;
- }
-
- p = XtMalloc(len);
- *p = 0;
-
- s = w->hyper.first_seg;
- while(s)
- {
- if(s->length)
- {
- if(include_tags && s->type == HIGHLIGHT)
- strcat(p,soh);
- strcat(p,s->text);
- if(include_tags && s->type == HIGHLIGHT)
- strcat(p,eoh);
- }
- else
- strcat(p,"\n");
- s=s->next;
- }
-
- return p;
-
-}
-
-/*-----------------------------------------------------------------------*/
-/* Only for Motif */
-/* If the widget is in a XmScrolledWindow, scroll it so the selection is */
-/* visible */
-/*-----------------------------------------------------------------------*/
-
-static void show_selection(h)
-HyperWidget h;
-{
-#ifdef MOTIF
-
- Widget clip = XtParent(h);
- Widget swin;
-
- Widget h_scroll;
- Widget v_scroll;
-
- int ac = 0;
-
- Position x_grep,y_grep;
- Dimension h_grep,w_grep;
- Position x_clip,y_clip;
- Dimension h_clip,w_clip;
- Position dv=0,dh=0;
- int min,max;
- int v_val,v_size,v_inc,v_page;
- int h_val,h_size,h_inc,h_page;
- Position x,y;
-
- Arg al[5];
-
-
-
- /* check if selection exists */
-
- if(!h->hyper.grep_seg) return;
-
- /* check if the widget is in a scrolled window */
- /* the XnScrolledWindow creates a clip window */
- /* The widget's parent is the clip window */
-
-
- if(!clip) return;
- swin = XtParent(clip);
-
- if(!swin || !XmIsScrolledWindow(swin)) return;
-
- /* Get window scroll bars */
-
- SetArg(XmNhorizontalScrollBar, &h_scroll);
- SetArg(XmNverticalScrollBar , &v_scroll);
- GetValues(swin);
-
- /* Get size of clip window and selection rect */
-
- w_clip = clip->core.width;
- h_clip = clip->core.height;
-
- w_grep = h->hyper.grep_width;
- h_grep = h->hyper.grep_height;
-
- /* Get global coordinates of clip and selection rect */
-
- XtTranslateCoords(clip,0,0,&x_clip,&y_clip);
- XtTranslateCoords((Widget)h,h->hyper.grep_x,h->hyper.grep_y,&x_grep,&y_grep);
-
- /* offset of selection within clip window */
-
- x = x_grep - x_clip;
- y = y_grep - y_clip;
-
-
- /* selection y coordinate is not visible */
-
- if( y < 0 || (Dimension) (y + h_grep) > h_clip)
- {
- /* the widget must be moved verticaly by dv pixels */
-
- dv = (y + h_grep / 2) - h_clip / 2;
-
- SetArg(XmNminimum,&min);
- SetArg(XmNmaximum,&max);
-
- GetValues(v_scroll);
-
- XmScrollBarGetValues(v_scroll,&v_val,&v_size,&v_inc,&v_page);
-
- max -= v_size;
-
- if( dv + v_val > max ) dv = max - v_val;
- if( dv + v_val < min ) dv = min - v_val;
-
-
- }
-
- /* selection x coordinate is not visible */
-
- if( x < 0 || (Dimension) (x + w_grep) > w_clip)
- {
- /* the widget must be moved horizontaly by dh pixels */
-
- dh = (x + w_grep / 2) - w_clip / 2;
-
- SetArg(XmNminimum,&min);
- SetArg(XmNmaximum,&max);
- GetValues(h_scroll);
-
- XmScrollBarGetValues(h_scroll,&h_val,&h_size,&h_inc,&h_page);
-
- max -= h_size;
-
- if( dh + h_val > max ) dh = max - h_val;
- if( dh + h_val < min ) dh = min - h_val;
-
- }
-
- /* if the widget must be moved */
-
- if(dv || dh)
- {
- Position x = h->core.x-dh;
- Position y = h->core.y-dv;
-
- /* move it */
-
- SetArg(XmNx,x);
- SetArg(XmNy,y);
- SetValues((Widget)h);
-
- /* update scroll bars */
-
- if(dv) XmScrollBarSetValues(v_scroll,v_val+dv,v_size,v_inc,
- v_page,TRUE);
- if(dh) XmScrollBarSetValues(h_scroll,h_val+dh,h_size,h_inc,
- h_page,TRUE);
-
-
- }
-
-
-#endif /* MOTIF */
-}
-
-/*-----------------------------------------------------------------------*/
-/* Clear previous selection */
-/*-----------------------------------------------------------------------*/
-
-static void clear_selection(w)
-HyperWidget w;
-{
- if(w->hyper.grep_seg)
- {
- if(XtIsRealized((Widget)w))
-
- /* force a redraw */
-
- XClearArea(XtDisplay(w),XtWindow(w),
- w->hyper.grep_x,
- w->hyper.grep_y,
- w->hyper.grep_width,
- w->hyper.grep_height,
- TRUE);
-
- }
- w->hyper.grep_seg = NULL;
-}
-
-/*-----------------------------------------------------------------------*/
-/* Set the new selection */
-/*-----------------------------------------------------------------------*/
-
-static void set_selection(w)
-HyperWidget w;
-{
- if(w->hyper.grep_seg)
- {
- text_segment *s = w->hyper.grep_seg;
- XCharStruct char_info;
- int dir,ascent,desc;
-
- /* get size of the begining of
- the segment, up to the found string */
-
- XTextExtents(
- (s->type == HIGHLIGHT ?
- w->hyper.highlight_font :
- w->hyper.normal_font),
- s->text,
- w->hyper.grep_off,
- &dir,&ascent,&desc,&char_info);
-
- w->hyper.grep_x = s->x + char_info.width;
- w->hyper.grep_y = s->y + desc;
- w->hyper.grep_height = s->height;
-
- /* Get size of the selection */
-
- XTextExtents(
- (s->type == HIGHLIGHT ?
- w->hyper.highlight_font :
- w->hyper.normal_font),
- w->hyper.grep_txt,
- w->hyper.grep_len,
- &dir,&ascent,&desc,&char_info);
-
-
- w->hyper.grep_width = char_info.width;
-
- /* force update */
-
- if(XtIsRealized((Widget)w))
- XClearArea(XtDisplay(w),XtWindow(w),
- w->hyper.grep_x,
- w->hyper.grep_y,
- w->hyper.grep_width,
- w->hyper.grep_height,
- TRUE);
- }
-}
-
-/*-----------------------------------------------------------------------*/
-/* Select a word in the hyper widget */
-/* word : word to find ( or regular expression if USE_REGEX is defined) */
-/* ignore_case : if TRUE ignore case in comparaison */
-/* from_start : if TRUE search from start of text, else search from */
-/* current selection */
-/* wrap: if TRUE, continue search from the begining of text if the end */
-/* is reached */
-/*-----------------------------------------------------------------------*/
-
-#ifdef _NO_PROTO
-
-Boolean HyperGrep(widget,word,ignore_case,from_start,wrap)
-Widget widget;
-char *word;
-Boolean ignore_case;
-Boolean from_start;
-Boolean wrap;
-
-#else
-
-Boolean HyperGrep(Widget widget,
- char *word,
- Boolean ignore_case,
- Boolean from_start,
- Boolean wrap)
-
-#endif
-
-{
- HyperWidget h = (HyperWidget)widget;
- char *w = word;
- char *p;
- int offset;
- text_segment *s;
-
- if(!h->hyper.first_seg) return False;
-
- if(ignore_case)
- {
- /* if ignore case, change word to lower case */
- w = XtNewString(word);
- lowcase(w);
- }
-
- /* compile the regular expression */
- xec_compile(w);
-
-
- if(ignore_case) XtFree((XtPointer)w);
-
- /* if from_start or no previous selection,
- start from first segment */
-
- if(from_start || h->hyper.grep_seg == NULL)
- {
- offset=0;
- wrap = FALSE;
- s = h->hyper.first_seg;
- }
- else
- {
- /* start from last selection */
-
- offset = h->hyper.grep_off + h->hyper.grep_len;
- s = h->hyper.grep_seg;
- }
-
- for(;;)
- {
- if(s->text)
- {
- if(ignore_case)
- {
- /* if ignore case, change segment to lower case */
- p = XtNewString(s->text);
- lowcase(p);
- }
- else
- p = s->text;
-
- /* search the string */
-
- if(xec_step(p+offset))
- {
- /* if found ...*/
-
- /* clear previous selection */
- clear_selection(h);
-
- h->hyper.grep_seg = s;
- h->hyper.grep_off = offset + (xec_loc1-(p+offset));
- h->hyper.grep_txt = s->text + h->hyper.grep_off;
- h->hyper.grep_len = xec_loc2-xec_loc1;
-
- /* set new selection */
-
- set_selection(h);
-
- /* make it visible */
-
- show_selection(h);
-
- if(ignore_case) XtFree((XtPointer)p);
-
- return TRUE;
- }
-
- if(ignore_case) XtFree((XtPointer)p);
- }
-
- offset = 0;
- s = s->next;
-
- /* if end of text and wrap mode, go to start of text */
- if(!s)
- {
- if(wrap)
- {
- wrap = FALSE;
- s = h->hyper.first_seg;
- }
- else break;
- }
-
- }
-
-
- return FALSE;
-
-}
diff --git a/ecflow_4_0_7/view/src/Hyper.h b/ecflow_4_0_7/view/src/Hyper.h
deleted file mode 100644
index f60f475..0000000
--- a/ecflow_4_0_7/view/src/Hyper.h
+++ /dev/null
@@ -1,119 +0,0 @@
-#ifndef HYPER_H
-#define HYPER_H
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #4 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-
-/*
- If you define MOTIF, the widget will inherit proprieties
- from the XmPrimitive class : Help Callback, user data, ...
-*/
-
-#ifndef MOTIF
-#define MOTIF
-#endif
-
-/*
- If your machine got regexp.h
-*/
-
-
-extern WidgetClass hyperWidgetClass;
-typedef struct _HyperClassRec * HyperWidgetClass;
-typedef struct _HyperRec * HyperWidget;
-
-/*
- * Define resource strings for the Hyper widget.
- */
-
-#define XtNhighlightFont "highlightFont"
-#define XtNnormalFont "normalFont"
-#define XtNhighlightColor "highlightColor"
-#define XtNselectColor "selectColor"
-#define XtNnormalColor "normalColor"
-#define XtNactivateCallback "activateCallback"
-#define XtNzoomEffect "zoomEffect"
-#define XtCZoom "Zoom"
-#define XtNstartHighlight "startHighlight"
-#define XtNendHighlight "endHighlight"
-#define XtCTagChar "TagChar"
-#define XtNzoomSpeed "zoomSpeed"
-#define XtCZoomSpeed "ZoomSpeed"
-#ifndef XtCMargin
-#define XtCMargin "Margin"
-#endif
-#define XtNmargin "margin"
-
-/*
- Callback structure
-*/
-
-#define HYPER_REASON 1
-
-typedef struct {
- int reason; /* always = HYPER_REASON */
- XEvent *event; /* event */
- char *text; /* pointer on highlighted text selected (read only) */
- int length; /* length of selected text */
-} hyperCallbackStruct;
-
-#ifdef _NO_PROTO
-
-extern Widget CreateHyper();
-extern void HyperLoadFile();
-extern void HyperSetText();
-extern void HyperSetTags();
-extern Boolean HyperFind();
-extern char *HyperGetText();
-
-#else
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
- extern Widget CreateHyper(Widget parent,
- char *name,
- ArgList al,
- int ac);
-
- extern void HyperLoadFile(Widget widget,
- char *fname);
-
- extern void HyperSetText(Widget widget,
- char *text);
-
- extern void HyperSetTags (Widget widget,
- int start_highlight,
- int end_highlight);
-
- Boolean HyperGrep(Widget widget,
- char *word,
- Boolean ignore_case,
- Boolean from_start,
- Boolean wrap);
-
- char *HyperGetText(Widget widget,Boolean include_tags);
-
-
-#if defined(__cplusplus) || defined(c_plusplus)
-}
-#endif
-
-#endif /* _NO_PROTO */
-
-#define XtIsHyper(w) XtIsSubclass(w,hyperWidgetClass)
-
-#endif /* HYPER_H */
diff --git a/ecflow_4_0_7/view/src/HyperP.h b/ecflow_4_0_7/view/src/HyperP.h
deleted file mode 100644
index cc0129f..0000000
--- a/ecflow_4_0_7/view/src/HyperP.h
+++ /dev/null
@@ -1,110 +0,0 @@
-#ifndef HYPERP_H
-#define HYPERP_H
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #4 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#ifdef MOTIF
-#include <Xm/XmP.h>
-#if (XmVersion >= 1002)
-#include <Xm/PrimitiveP.h>
-#endif
-#endif
-
-/* Hyper class : no new fileds */
-
-typedef struct _HyperClassPart{
- int ignore;
-} HyperClassPart;
-
-typedef struct _HyperClassRec{
- CoreClassPart core_class;
-#ifdef MOTIF
- XmPrimitiveClassPart primitive_class;
-#endif
- HyperClassPart hyper_class;
-} HyperClassRec;
-
-extern HyperClassRec hyperClassRec;
-
-/* Text segment */
-
-typedef struct text_segment {
-
- struct text_segment *next; /* Next segment */
- int type; /* NEWLINE, NORMAL or HIGHLIGHT */
- char *text; /* pointer to text */
- int length; /* length of text */
- int desc; /* font descent */
- GC gc; /* GC used to draw text */
- Position x,y; /* Position of drawn text */
- Dimension width,height; /* Size of drawn text */
- int offset; /* KELD : offset from start of widget */
-
-} text_segment;
-
-typedef struct _HyperPart {
-
- Cursor hand; /* Selecting cursor shape */
-
- Pixel normal_color; /* Color of the normal text */
- Pixel highlight_color; /* Color of the highlighted text */
- Pixel select_color; /* Color of the selected text */
-
- XFontStruct *normal_font; /* Font of the normal text */
- XFontStruct *highlight_font; /* Font of the highlighted text */
-
- GC normal_gc; /* Gc for the normal text */
- GC highlight_gc; /* Gc for the highlighted text */
-
- GC xor_gc; /* Gc for zoom */
- GC select_gc; /* Gc for select */
-
- Boolean zoom; /* zoom effect when selected */
- int speed; /* zoom speed */
- char start_of_highlight; /* start of highlighted text mark */
- char end_of_highlight; /* end of highlighted text mark */
-
- int margin; /* margins size */
-
-
- text_segment *grep_seg; /* segment where found text is */
-
- char *grep_txt; /* pointer to found text */
- int grep_len; /* length of found text */
- int grep_off; /* offset of found text */
-
- Position grep_x; /* rectangle of founf text*/
- Position grep_y;
- Dimension grep_width;
- Dimension grep_height;
-
- text_segment *first_seg; /* the text segments */
- text_segment *last_selected; /* last selected segment */
- text_segment *last_cursor; /* last under cursor segment */
-
-
- XtCallbackList activate; /* callback list */
-
-} HyperPart;
-
-typedef struct _HyperRec {
- CorePart core;
-#ifdef MOTIF
- XmPrimitivePart primitive;
-#endif
- HyperPart hyper;
-} HyperRec;
-
-#endif /* HYPERP_H */
diff --git a/ecflow_4_0_7/view/src/SimpleBase.c b/ecflow_4_0_7/view/src/SimpleBase.c
deleted file mode 100644
index 1209e62..0000000
--- a/ecflow_4_0_7/view/src/SimpleBase.c
+++ /dev/null
@@ -1,1304 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #10 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-
-#include <X11/Intrinsic.h>
-#include <X11/IntrinsicP.h>
-#include <X11/StringDefs.h>
-#include <X11/CoreP.h>
-#include <X11/CompositeP.h>
-#include <X11/ConstrainP.h>
-#include <Xm/XmP.h>
-#include <Xm/DrawingAP.h>
-#include <Xm/ExtObjectP.h>
-#include <Xm/ScrollBar.h>
-#include "SimpleBase.h"
-#include "SimpleBaseP.h"
-
-static void Initialize();
-static void Destroy();
-static void Realize();
-static Boolean SetValues();
-
-
-#ifdef linux
-/* putting this into comments makes ctrl-left button for collector
- disappear !! */
-static char defaultTranslations[] = "\
- Shift<Btn5Down>: increment(1)\n Shift<Btn4Down>: increment(-1) \n\
- <Btn5Down>: increment(10)\n <Btn4Down>: increment(-10) \n\
-<BtnDown>:DrawingAreaInput()\n <BtnUp>:DrawingAreaInput()\n\
-<Key>osfActivate:DrawingAreaInput()\n\
-~s ~m ~a <Key>Return:DrawingAreaInput()\n\
-~s ~m ~a <Key>space:DrawingAreaInput()\n\
-<Key>F1:DrawingAreaInput()\n\
-<Key>F2:DrawingAreaInput()\n";
-#else
-
-#define defaultTranslations XmInheritTranslations
-
-#endif
-
-static void xincrement();
-static XtActionsRec actionsList[] = {
- { "increment",(XtActionProc) xincrement},
-};
-
-static XtResource resources[] = {
- {XtNblinkColor, XtCBlinkColor, XtRPixel, sizeof (Pixel),
- XtOffset(SimpleBaseWidget, simplebase.blink_color), XtRString,"Black"},
-
- {XtNselected, XtCSelected, XtRInt, sizeof (int),
- XtOffset(SimpleBaseWidget, simplebase.selected), XtRImmediate,(XtPointer)-1},
-
- {"blinkRate", "BlinkRate", XtRInt, sizeof (int),
- XtOffset(SimpleBaseWidget, simplebase.timeout), XtRImmediate,(XtPointer)500},
-
- {XtNgetpsCallback,XtCCallback,XtRCallback,sizeof(caddr_t),
- XtOffset (SimpleBaseWidget, simplebase.getps),XtRCallback,NULL},
-
- {XtNlinkCallback,XtCCallback,XtRCallback,sizeof(caddr_t),
- XtOffset (SimpleBaseWidget, simplebase.link),XtRCallback,NULL},
-
- {XtNpsHeader,XtCPsHeader,XtRString,sizeof(String),
- XtOffset (SimpleBaseWidget, simplebase.header),XtRImmediate,NULL},
-};
-
-
-SimpleBaseClassRec simplebaseClassRec = {
- {
- /* core_class fields */
- (WidgetClass) &xmDrawingAreaClassRec,/* superclass */
- "SimpleBase", /* class_name */
- sizeof(SimpleBaseRec), /* widget_size */
- NULL, /* class_init */
- NULL, /* class_part_init */
- FALSE, /* class_inited */
- Initialize, /* initialize */
- NULL, /* initialize_hook */
- Realize, /* realize */
- actionsList, /* actions */
- XtNumber(actionsList), /* num_actions */
- resources, /* resources */
- XtNumber(resources), /* num_resources */
- NULLQUARK, /* xrm_class */
- TRUE, /* compress_motion */
- XtExposeCompressMaximal, /* compress_exposure */
- TRUE, /* compress_enterleave*/
- TRUE, /* visible_interest */
- Destroy, /* destroy */
- NULL, /* resize */
- NULL, /* expose */
- SetValues, /* set_values */
- NULL, /* set_values_hook */
- XtInheritSetValuesAlmost, /* set_values_almost */
- NULL, /* get_values_hook */
- NULL, /* accept_focus */
- XtVersion, /* version */
- NULL, /* callback_private */
- defaultTranslations, /* tm_table */
- NULL, /* query_geometry */
- XtInheritDisplayAccelerator, /* display_accelerator*/
- NULL, /* extension */
- },
- {
- /* composite_class fields */
- NULL, /* geometry_manager */
- NULL, /* change_managed */
- XtInheritInsertChild, /* insert_child */
- XtInheritDeleteChild, /* delete_child */
- NULL, /* extension */
- },
- {
- /* constraint_class fields */
- NULL, /* subresources */
- 0, /* subresource_count */
- 0, /* constraint_size */
- NULL, /* initialize */
- NULL, /* destroy */
- NULL, /* set_values */
- NULL, /* extension */
- },
- {
- XtInheritTranslations, /* default translations */
- NULL, /* syn_resources */
- 0, /* num_syn_resources */
- NULL, /* syn_cont_resources */
- 0, /* num_syn_cont_resources */
- XmInheritParentProcess, /* parent_process */
- NULL, /* extension */
- },
- {
- NULL,
- },
- {
- /* SimpleBase class fields */
- NULL,
- },
-};
-
-
-#ifndef MIN
-#define MIN(a,b) ((a)>(b)?(b):(a))
-#endif
-
-WidgetClass simplebaseWidgetClass = (WidgetClass) &simplebaseClassRec;
-
-//static void find_visible_part(Widget w,Position *x,Position *y,
-// Dimension* width, Dimension* height)
-//{
-// Position root_x,root_y;
-// Widget p = w;
-//
-// *width = w->core.width;
-// *height = w->core.height;
-// XtTranslateCoords(w,0,0,&root_x,&root_y);
-//
-// *x = 0;
-// *y = 0;
-//
-// while((p = XtParent(p)))
-// {
-// Position rx,ry;
-// Dimension w,h;
-//
-// /*
-// make all computations in the root's coordinate system
-// */
-//
-// XtTranslateCoords(p,0,0,&rx,&ry);
-//
-// w = p->core.width;
-// h = p->core.height;
-//
-// /*
-// use the smallest rectangle
-// */
-//
-// if(w < *width) *width = w;
-// if(h < *height) *height = h;
-//
-// if(rx>root_x) root_x = rx;
-// if(ry>root_y) root_y = ry;
-//
-// /* stop when reach a shell, don't go to top level shell */
-// if(XtIsShell(p)) break;
-// }
-//
-// /* Back to the widget's coordinate system */
-//
-// XtTranslateCoords(w,0,0,x,y);
-// *x = root_x - *x;
-// *y = root_y - *y;
-//}
-
-
-/*-----------------------------------------------------------------*/
-/* Find which gadget was called */
-/*-----------------------------------------------------------------*/
-
-static void button_click(w,cd,event,continue_dispatch)
-SimpleBaseWidget w;
-XtPointer *cd;
-XEvent *event;
-Boolean *continue_dispatch;
-{
- int i;
- Position x,y;
- XmDrawingAreaCallbackStruct cb;
-
- x = event->xbutton.x;
- y = event->xbutton.y;
- // printf("bclick\n");
-
- for (i = 0; i < w -> composite.num_children; i++)
- {
- Widget child = w -> composite.children[i];
-
- if( XtIsManaged(child) &&
- (x >= child->core.x && x <= child->core.x + child->core.width)
- && (y >= child->core.y && y <= child->core.y + child->core.height))
- {
- cb.reason = -1;
- cb.event= event;
- cb.window = (Window)child;
- XtCallCallbacks((Widget)w,XmNinputCallback,(XtPointer)&cb);
- }
- }
-
-}
-
-
-/*-------------------------------------------------------------------*/
-/* Blink current gadget */
-/*-------------------------------------------------------------------*/
-
-#if 0
-static void time_out(SimpleBaseWidget w,XtIntervalId id)
-{
- if( w->simplebase.selected >= 0 && w->simplebase.selected < w->simplebase.count) {
- NodeStruct *n = w->simplebase.nodes + w->simplebase.selected;
-
- if(XtIsRealized((Widget) w) && n->managed)
- {
- /* XFillRectangle */
-
- XDrawRectangle(XtDisplay(w),XtWindow(w),
- w->simplebase.blink_gc,
- n->r.x+1,
- n->r.y+1,
- n->r.width-2,
- n->r.height-2);
- }
- }
- w->simplebase.timeout_id = XtAppAddTimeOut(
- XtWidgetToApplicationContext((Widget)w),
- w->simplebase.timeout,
- (XtTimerCallbackProc)time_out,
- (XtPointer)w);
-}
-#endif
-
-static void clip_input_callback(clip,widget,cb)
-Widget clip;
-Widget widget;
-XtPointer cb;
-{
- XtCallCallbacks(widget,XmNinputCallback,cb);
-}
-
-static XtCallbackRec clipcb[] = {
- { (XtCallbackProc)clip_input_callback, NULL, },
- { NULL,NULL,},
-};
-
-/*----------------------------------------------------*/
-/* Init : create blink gc */
-/*----------------------------------------------------*/
-
-static void Realize(SimpleBaseWidget w,XtValueMask *value_mask,
-XSetWindowAttributes *attributes)
-{
- Widget clip,scroll,ww;
- WidgetClass class = XtClass(w);
-
- while(class != (WidgetClass)simplebaseWidgetClass)
- class = class->core_class.superclass;
- class = class->core_class.superclass;
- (class->core_class.realize) ((Widget) w, value_mask, attributes);
-
- ww = (Widget)w;
- while(ww){
- if((clip = XtParent(ww)))
- if((scroll = XtParent(clip)))
- if(XmIsScrolledWindow(scroll))
- {
- clipcb[0].closure = (XtPointer)w;
- XtAddCallbacks(clip,XmNinputCallback,clipcb);
- }
- ww = clip;
- }
-}
-
-static void Initialize(request, new)
-SimpleBaseWidget request, new;
-{
- XGCValues values;
- XtGCMask valueMask;
-
- /*
- * Make sure the widget's width and height are
- * greater than zero.
- */
- if (request->core.width <= 0)
- new->core.width = 5;
- if (request->core.height <= 0)
- new->core.height = 5;
-
- new->simplebase.gc = XtGetGC((Widget)new,0,0);
-
- valueMask = GCLineWidth ;
- /* GCForeground | GCBackground | GCFunction | | GCGraphicsExposures; */
-
- values.foreground = new->core.background_pixel^new->simplebase.blink_color;
- values.background = values.foreground;
- values.function = GXxor;
- values.graphics_exposures = False;
- values.line_width = 2;
-
- new->simplebase.blink_gc = XtGetGC((Widget)new,valueMask,&values);
-
- XtAddEventHandler((Widget)new,ButtonPressMask,
- False,(XtEventHandler)button_click,(XtPointer)new);
- XtAddEventHandler((Widget)new,KeyPressMask,
- False,(XtEventHandler)button_click,(XtPointer)new);
-
- /* time_out(new,NULL); */
-
- new->simplebase.focus = -1;
- new->simplebase.max = 0;
- new->simplebase.link_max = 0;
- new->simplebase.count = 0;
- new->simplebase.link_count = 0;
- new->simplebase.nodes = NULL;
- new->simplebase.links = NULL;
- new->simplebase.work = 0;
-}
-
-
-/*----------------------------------------------------------*/
-/*----------------------------------------------------------*/
-
-static void Destroy(SimpleBaseWidget w)
-{
- Widget clip,scroll,ww;
-
- //printf("Destroy(SimpleBaseWidget w)\n");
-
- NodeReset((Widget)w);
-
- XtRemoveEventHandler((Widget)w,ButtonPressMask,
- False,(XtEventHandler)button_click,(XtPointer)w);
- XtRemoveEventHandler((Widget)w,KeyPressMask,
- False,(XtEventHandler)button_click,(XtPointer)w);
-
- XtReleaseGC((Widget)w,w->simplebase.blink_gc);
- XtReleaseGC((Widget)w,w->simplebase.gc);
- /* XtRemoveTimeOut(w->simplebase.timeout_id); */
-
- ww = (Widget)w;
- while(ww) {
- if((clip = XtParent(ww)))
- if((scroll = XtParent(clip)))
- if(XmIsScrolledWindow(scroll))
- {
- clipcb[0].closure = (XtPointer)w;
- XtRemoveCallbacks(clip,XmNinputCallback,clipcb);
- }
- ww = clip;
- }
-
- XtFree((char*)w->simplebase.nodes);
- XtFree((char*)w->simplebase.links);
-}
-
-static void selection(SimpleBaseWidget w)
-{
- if( w->simplebase.selected >= 0 && w->simplebase.selected < w->simplebase.count) {
- NodeStruct *n = w->simplebase.nodes + w->simplebase.selected;
- if(n->managed)
- {
- XDrawRectangle(XtDisplay(w),XtWindow(w),
- w->simplebase.blink_gc,
- n->r.x-1,
- n->r.y-1,
- n->r.width+2,
- n->r.height+2);
- }
- }
-}
-
-static void clear(SimpleBaseWidget w)
-{
- if( w->simplebase.selected >= 0 && w->simplebase.selected < w->simplebase.count) {
- NodeStruct *n = w->simplebase.nodes + w->simplebase.selected;
- if(n->managed)
- {
- XClearArea(XtDisplay(w),XtWindow(w),
- n->r.x-3,
- n->r.y-3,
- n->r.width+5,
- n->r.height+5,True);
- }
- }
-}
-
-void NodesRedraw(SimpleBaseWidget w,XEvent *event, Region region)
-{
- int i;
- /* int d = 0,u = 0; */
-
- /* Position x,y; */
- /* Dimension a,h; */
-
- /* find_visible_part(w,&x,&y,&a,&h); */
- /* printf("find_visible_part : %d %d %d %d \n",x,y,a,h); */
-
- for(i = 0; i < w->simplebase.count;i++)
- {
- NodeStruct *n = w->simplebase.nodes + i;
- if(n->managed)
- if(XRectInRegion(region, n->r.x, n->r.y, n->r.width, n->r.height))
- n->draw((Widget)w,&n->r,n->user_data);
- }
-
- /* printf("NodesRedraw %s: draw %d, skip %d\n",XtName(w),d,u); */
-
- /* XSetRegion(XtDisplay(w),w->simplebase.blink_gc,region); */
- selection(w);
- /* XSetClipMask(XtDisplay(w),w->simplebase.blink_gc,None); */
-
-#if 0
- if( w->simplebase.selected >= 0 && w->simplebase.selected < w->simplebase.count) {
- NodeStruct *n = w->simplebase.nodes + w->simplebase.selected;
- if(n->managed)
- if(XRectInRegion(region, n->r.x-1, n->r.y-1, n->r.width+2, n->r.height+2))
- {
- XDrawRectangle(XtDisplay(w),XtWindow(w),
- w->simplebase.blink_gc,
- n->r.x-1,
- n->r.y-1,
- n->r.width+2,
- n->r.height+2);
- }
- }
-#endif
-}
-
-static int new_link_data(SimpleBaseWidget w)
-{
- LinkData *d;
- if(w->simplebase.link_count >= w->simplebase.link_max)
- {
- w->simplebase.link_max += w->simplebase.link_max/2 + 128;
- w->simplebase.links =
- (LinkData*)XtRealloc((XtPointer)w->simplebase.links,
- w->simplebase.link_max*sizeof(LinkData));
- memset(w->simplebase.links + w->simplebase.link_count, 0,
- (w->simplebase.link_max - w->simplebase.link_count)*sizeof(LinkData));
- }
-
- d = &w->simplebase.links[w->simplebase.link_count];
- d->gc = w->simplebase.gc;
- d->user_data = 0;
-
- return w->simplebase.link_count++;
-}
-
-int NodeCreate(Widget _w,DrawProc draw,SizeProc size,void *data)
-{
- SimpleBaseWidget w = (SimpleBaseWidget)_w;
- NodeStruct *n;
- if(w->simplebase.count >= w->simplebase.max)
- {
- w->simplebase.max += w->simplebase.max/2 + 128;
- w->simplebase.nodes =
- (NodeStruct*)XtRealloc((XtPointer)w->simplebase.nodes,
- w->simplebase.max*sizeof(NodeStruct));
- memset(w->simplebase.nodes + w->simplebase.count, 0,
- (w->simplebase.max - w->simplebase.count)*sizeof(NodeStruct));
- }
-
- n = &w->simplebase.nodes[w->simplebase.count];
-#if 0
- n-> group = -1;
-#endif
- n->r.width = 30;
- n->r.height = 20;
- n->draw = draw;
- n->size = size;
- n->user_data = data;
- /* n->size(_w,&n->r,data); */
-
- return w->simplebase.count++;
-}
-
-
-static Boolean manage_proc(SimpleBaseWidget w)
-{
- WidgetClass class = XtClass(w);
- WidgetClass sclass = simplebaseClassRec.core_class.superclass;
-
- long width = w->core.width;
- long height = w->core.height;
- Position pwidth;
- Position pheight;
-
- w->simplebase.work = 0;
-
- while(class != sclass)
- {
- SimpleBaseClassRec *bc = (SimpleBaseClassRec*)class;
-
- if(bc->simplebase_class.layout)
- (*(bc->simplebase_class.layout))((Widget)w,&width,&height);
-
- class = class->core_class.superclass;
-
- }
-
- pwidth = width; if(pwidth != width) pwidth = 0x7f00;
- pheight = height;if(pheight != height) pheight = 0x7f00;
-
- if(pwidth != w->core.width || pheight != w->core.height)
- {
- Dimension replyWidth = 0, replyHeight = 0;
-
- XtGeometryResult result = XtMakeResizeRequest((Widget)w,
- pwidth,pheight,
- &replyWidth, &replyHeight);
-
- if (result == XtGeometryAlmost)
- XtMakeResizeRequest ((Widget)w, replyWidth, replyHeight,
- NULL, NULL);
- }
-
- if(XtIsRealized((Widget) w))
- {
- /* printf("XClearArea 1 %s\n",XtName(w)); */
- XClearArea(XtDisplay(w),XtWindow(w),0,0,0,0,True);
- }
-
- return True;
-
-}
-
-static void enqueue_manage_proc(SimpleBaseWidget w)
-{
- if(w->simplebase.work == 0)
- w->simplebase.work = XtAppAddWorkProc(
- XtWidgetToApplicationContext((Widget)w),
- (XtWorkProc)manage_proc,(XtPointer)w);
-}
-
-void NodeChanged(Widget _w,int node)
-{
- SimpleBaseWidget w = (SimpleBaseWidget)_w;
- if( w == 0 || node < 0 || node >= w->simplebase.count) return;
-
- if(XtIsRealized((Widget)w))
- {
- NodeStruct *p = w->simplebase.nodes + node;
- if(p->managed)
- {
- /* printf("XClearArea 2 %s\n",XtName(w)); */
- XClearArea(XtDisplay(w),XtWindow(w),
- p->r.x,p->r.y,
- p->r.width,p->r.height,True);
- }
- }
-}
-
-void NodeSetFocus(Widget _w,int node)
-{
- SimpleBaseWidget w = (SimpleBaseWidget)_w;
- if( w == 0 || node >= w->simplebase.count) return;
- w->simplebase.focus = node;
- enqueue_manage_proc(w);
-}
-
-void *NodeFind(Widget _w,XEvent *ev)
-{
- SimpleBaseWidget w = (SimpleBaseWidget)_w;
- int i;
- for(i = 0; i < w->simplebase.count;i++)
- {
- NodeStruct *n = w->simplebase.nodes + i;
- if(n->managed)
- if(ev->xbutton.x >= n->r.x && ev->xbutton.x <= n->r.x + n->r.width &&
- ev->xbutton.y >= n->r.y && ev->xbutton.y <= n->r.y + n->r.height)
- return n->user_data;
- }
- return NULL;
-}
-
-void SimpleBaseShow(Widget _w,XRectangle* r,XEvent* ev)
-{
- /* SimpleBaseWidget sw = (SimpleBaseWidget)_w; */
-
- Widget v_scroll,h_scroll;
- Position x_parent,y_parent;
- Position x_clip,y_clip;
- Position x_event,y_event;
- Dimension h_clip,w_clip;
- Position dv=0,dh=0;
- int min,max;
- int v_val,v_size,v_inc,v_page;
- int h_val,h_size,h_inc,h_page;
- Widget clip = NULL;
- Widget scroll_window = NULL;
- Arg al[5];
- int ac;
- /* NodeStruct *w; */
- Position x_node ,y_node;
- Dimension h_node,w_node;
-
- Position x,y;
-
- Widget ww = _w;
- while(ww) {
- if(!(clip = XtParent(ww))) return;
- if(!(scroll_window = XtParent(clip))) return;
- if(XmIsScrolledWindow(scroll_window)) break;
- if(!(ww = XtParent(ww))) return;
-
- }
-
- x_node = r->x;
- y_node = r->y;
- h_node = r->height;
- w_node = r->width;
-
- ac = 0;
- XtSetArg(al[ac],XmNhorizontalScrollBar, &h_scroll );ac++;
- XtSetArg(al[ac],XmNverticalScrollBar, &v_scroll );ac++;
- XtGetValues(scroll_window,al,ac);
-
- ac = 0;
- XtSetArg(al[ac],XmNx,&x_parent);ac++;
- XtSetArg(al[ac],XmNy,&y_parent);ac++;
- XtGetValues(_w,al,ac);
-
- ac = 0;
- XtSetArg(al[ac],XmNclipWindow,&clip);ac++;
- XtGetValues(scroll_window,al,ac);
-
- ac = 0;
- XtSetArg(al[ac],XmNheight,&h_clip);ac++;
- XtSetArg(al[ac],XmNwidth,&w_clip);ac++;
- XtGetValues(clip,al,ac);
-
-
- XtTranslateCoords(_w,x_node,y_node, &x_node,&y_node);
- XtTranslateCoords(clip,0,0,&x_clip,&y_clip);
- if(ev) XtTranslateCoords(_w,ev->xbutton.x,ev->xbutton.y, &x_event,&y_event);
-
-
- x = x_node - x_clip;
- y = y_node - y_clip;
-
-
- if( y < 0 || y + h_node > h_clip || ev)
- {
- if(ev)
- dv = (y + h_node / 2) - (y_event - y_clip);
- else
- dv = (y + h_node / 2) - h_clip / 2;
-
- ac = 0;
- XtSetArg(al[ac],XmNminimum,&min);ac++;
- XtSetArg(al[ac],XmNmaximum,&max);ac++;
- XtGetValues(v_scroll,al,ac);
-
- XmScrollBarGetValues(v_scroll,&v_val,&v_size,&v_inc,&v_page);
-
- max -= v_size;
-
- if( dv + v_val > max ) dv = max - v_val;
- if( dv + v_val < min ) dv = min - v_val;
-
-
- }
- if( x < 0 || x + w_node > w_clip || ev)
- {
- if(ev)
- dh = (x + w_node / 2) - (x_event - x_clip);
- else
- dh = (x + w_node / 2) - w_clip / 2;
-
- ac = 0;
- XtSetArg(al[ac],XmNminimum,&min);ac++;
- XtSetArg(al[ac],XmNmaximum,&max);ac++;
- XtGetValues(h_scroll,al,ac);
-
- XmScrollBarGetValues(h_scroll,&h_val,&h_size,&h_inc,&h_page);
-
- max -= h_size;
-
- if( dh + h_val > max ) dh = max - h_val;
- if( dh + h_val < min ) dh = min - h_val;
-
- }
-
-
- if(dv || dh)
- {
- Position x = x_parent-dh;
- Position y = y_parent-dv;
-
- ac = 0;
- XtSetArg(al[ac],XmNx,x);ac++;
- XtSetArg(al[ac],XmNy,y);ac++;
- XtSetValues(_w,al,ac);
-
-
- if(dv) XmScrollBarSetValues(v_scroll,v_val+dv,
- v_size,v_inc,v_page,TRUE);
- if(dh) XmScrollBarSetValues(h_scroll,h_val+dh,
- h_size,h_inc,h_page,TRUE);
- }
-}
-
-void NodeShow(Widget _w,int node)
-{
- SimpleBaseWidget sw = (SimpleBaseWidget)_w;
- NodeStruct *w;
-
- if( node < 0 || node >= sw->simplebase.count) return;
- w = sw->simplebase.nodes + node;
- if(!w->managed) return;
-
- SimpleBaseShow(_w,&w->r,NULL);
-}
-
-void NodeHideAll(Widget _w)
-{
- SimpleBaseWidget w = (SimpleBaseWidget)_w;
- int i;
- for(i = 0; i < w->simplebase.count;i++)
- {
- NodeStruct *n = w->simplebase.nodes + i;
- n->managed = False;
- }
- NodeUpdate(_w);
-}
-
-Boolean NodeVisibility(Widget _w,int node,Boolean vis)
-{
- SimpleBaseWidget w = (SimpleBaseWidget)_w;
- if (!w) {
- return False;
- }
- NodeStruct *p = w->simplebase.nodes + node;
- if( node < 0 || node >= w->simplebase.count) return vis;
- if (0 == p) {
- fprintf(stderr, "unexpected\n");
- return False;
- }
- if(p->managed == vis) return vis;
-
- /* if(node == w->simplebase.selected) selection(w); */
-
- p->managed = vis;
-
- if(vis && !p->inited)
- {
- p->size(_w,&p->r,p->user_data);
- p->inited = True;
- }
-
- enqueue_manage_proc(w);
- return !vis;
-}
-
-void NodeNewSizeAll(Widget _w)
-{
- int i;
- SimpleBaseWidget w = (SimpleBaseWidget)_w;
- for(i = 0; i < w->simplebase.count;i++)
- NodeNewSize(_w,i);
- if(XtIsRealized(_w))
- XClearArea(XtDisplay(_w),XtWindow(_w),0,0,0,0,True);
-}
-
-void NodeNewSize(Widget _w,int node)
-{
- XRectangle next,old;
- SimpleBaseWidget w = (SimpleBaseWidget)_w;
- NodeStruct *p ;
- if( w == 0 || node < 0 || node >= w->simplebase.count) return;
-
- p = w->simplebase.nodes + node;
-
- if( !p->managed)
- {
- p->inited = False;
- return;
- }
-
-
- old = next = p->r;
- p->size(_w,&next,p->user_data);
-
- if(next.x == p->r.x && next.y == p->r.y &&
- next.width == p->r.width && next.height == p->r.height)
- return;
-
- if(node == w->simplebase.selected) clear(w);
-
- p->r = next;
-
- /* if(node == w->simplebase.selected) selection(w); */
-
- /* if( !p->managed) return; */
-
- if(!XtIsRealized(_w))
- return;
-
- XClearArea(XtDisplay(_w),XtWindow(_w),old.x,old.y,
- old.width,old.height,True);
-
- XClearArea(XtDisplay(_w),XtWindow(_w),p->r.x,p->r.y,
- p->r.width,p->r.height,True);
-
- if(p->managed)
- enqueue_manage_proc(w);
-}
-
-
-
-void NodeUpdate(Widget _w)
-{
- SimpleBaseWidget w = (SimpleBaseWidget)_w;
- if(w->simplebase.work) {
- XtRemoveWorkProc(w->simplebase.work);
- w->simplebase.work = 0;
- }
- /* printf("update\n"); */
- manage_proc(w);
-}
-
-
-
-void NodeReset(Widget _w)
-{
- SimpleBaseWidget w = (SimpleBaseWidget)_w;
- int i;
- for(i = 0; i < w->simplebase.count;i++)
- {
- NodeStruct *n = w->simplebase.nodes + i;
- if(n->parents) XtFree((XtPointer)n->parents);
- if(n->kids) XtFree((XtPointer)n->kids);
- }
- w->simplebase.count = 0;
- w->simplebase.link_count = 0;
- w->simplebase.selected = -1;
- w->simplebase.focus = -1;
- memset(w->simplebase.nodes,0,w->simplebase.max*sizeof(NodeStruct));
- memset(w->simplebase.links,0,w->simplebase.link_max*sizeof(LinkData));
- NodeUpdate(_w);
-}
-
-void NodeReserve(Widget _w,int count)
-{
- SimpleBaseWidget w = (SimpleBaseWidget)_w;
- if(count > w->simplebase.max)
- {
- w->simplebase.max = count;
- w->simplebase.nodes =
- (NodeStruct*)XtRealloc((XtPointer)w->simplebase.nodes,
- w->simplebase.max*sizeof(NodeStruct));
- memset(w->simplebase.nodes + w->simplebase.count, 0,
- (w->simplebase.max - w->simplebase.count)*sizeof(NodeStruct));
- }
-}
-
-
-void NodeAddRelation(Widget _w,int pnode,int knode)
-{
- int i;
- SimpleBaseWidget w = (SimpleBaseWidget)_w;
- NodeStruct *p = w->simplebase.nodes + pnode;
- NodeStruct *k = w->simplebase.nodes + knode;
-
- if( pnode < 0 || pnode >= w->simplebase.count) return;
- if( knode < 0 || knode >= w->simplebase.count) return;
-
- for(i = 0 ; i < p->kcnt; i++)
- if(p->kids[i].node == knode)
- return;
-
- if(k->pcnt >= k->pmax)
- {
- k->pmax += k->pmax/2 + 1;
- k->parents = (Link*)XtRealloc((XtPointer)k->parents,k->pmax*sizeof(Link));
- }
-
- if(p->kcnt >= p->kmax)
- {
- p->kmax += p->kmax/2 + 1;
- p->kids = (Link*)XtRealloc((XtPointer)p->kids,p->kmax*sizeof(Link));
- }
-
- p->kids[p->kcnt].link_data = -1;
- p->kids[p->kcnt++].node = knode;
-
- k->parents[k->pcnt].link_data = -1;
- k->parents[k->pcnt++].node = pnode;
-
- /*printf("NodeAddRelation %d %d (%d)\n",pnode,knode,kind);*/
-}
-
-void* NodeGetRelationData(Widget _w,int pnode,int knode)
-{
- int i;
- SimpleBaseWidget w = (SimpleBaseWidget)_w;
- NodeStruct *p = w->simplebase.nodes + pnode;
- /* NodeStruct *k = w->simplebase.nodes + knode; */
-
- if( pnode < 0 || pnode >= w->simplebase.count) return 0;
- if( knode < 0 || knode >= w->simplebase.count) return 0;
-
- for(i = 0 ; i < p->kcnt; i++)
- if(p->kids[i].node == knode)
- {
- if( p->kids[i].link_data == -1)
- return 0;
- return w->simplebase.links[p->kids[i].link_data].user_data;
- }
-
-
- /* Check for dummies */
- for(i = 0 ; i < p->kcnt; i++)
- {
- NodeStruct* z = &KIDS(w,p,i);
- if(sb_is_dummy(w,z))
- {
- void *d = NodeGetRelationData(_w,NODE_TO_INDEX(w,z),knode);
- if(d) return d;
- }
- }
-
-
- return 0;
-}
-
-void* NodeSetRelationData(Widget _w,int pnode,int knode,void *data)
-{
- int i;
- SimpleBaseWidget w = (SimpleBaseWidget)_w;
- NodeStruct *p = w->simplebase.nodes + pnode;
- /* NodeStruct *k = w->simplebase.nodes + knode; */
-
- if( pnode < 0 || pnode >= w->simplebase.count) return 0;
- if( knode < 0 || knode >= w->simplebase.count) return 0;
-
- for(i = 0 ; i < p->kcnt; i++)
- if(p->kids[i].node == knode)
- {
- void *old = 0;
- if( p->kids[i].link_data == -1)
- p->kids[i].link_data = new_link_data(w);
- else
- old = w->simplebase.links[p->kids[i].link_data].user_data;
- w->simplebase.links[p->kids[i].link_data].user_data = data;
- return old;
- }
-
- return 0;
-}
-
-GC NodeSetRelationGC(Widget _w,int pnode,int knode,GC rgc)
-{
- int i;
- SimpleBaseWidget w = (SimpleBaseWidget)_w;
- NodeStruct *p = w->simplebase.nodes + pnode;
- /* NodeStruct *k = w->simplebase.nodes + knode; */
- GC gc = w->simplebase.gc;
-
- if( pnode < 0 || pnode >= w->simplebase.count) return gc;
- if( knode < 0 || knode >= w->simplebase.count) return gc;
-
- for(i = 0 ; i < p->kcnt; i++)
- if(p->kids[i].node == knode)
- {
- GC old = gc;
- if( p->kids[i].link_data == -1)
- p->kids[i].link_data = new_link_data(w);
- else
- old = w->simplebase.links[p->kids[i].link_data].gc;
- w->simplebase.links[p->kids[i].link_data].gc = rgc;
- enqueue_manage_proc(w);
- return old;
- }
-
- return gc;
-}
-
-
-static Boolean SetValues(SimpleBaseWidget current,
-SimpleBaseWidget request,
-SimpleBaseWidget new)
-{
- int redraw = FALSE;
- XGCValues values;
- XtGCMask valueMask;
-
- if (new->simplebase.blink_color != current->simplebase.blink_color ||
- new->core.background_pixel !=
- current->core.background_pixel){
- valueMask = GCForeground | GCBackground |
- GCFunction | GCLineWidth;
- values.foreground = new->simplebase.blink_color;
- values.background = new->core.background_pixel;
- values.function = GXxor;
- values.line_width = 2;
- XtReleaseGC((Widget)new,new->simplebase.blink_gc);
- new->simplebase.blink_gc = XtGetGC((Widget)new, valueMask, &values);
- redraw = TRUE;
- }
-
- if(XtIsRealized((Widget)new) && XtIsManaged((Widget)new))
- if(new->simplebase.selected != current->simplebase.selected)
- {
- clear(current);
- clear(new);
- }
-
- /* printf("Redraw %d\n",redraw); */
-
- return (redraw);
-}
-
-static void drawDummy(Widget w,XRectangle* r,void* d)
-{
-}
-
-static void sizeDummy(Widget w,XRectangle* r,void* d)
-{
- r->width = r->height = 0;
-}
-
-int sb_new_dummy_node(SimpleBaseWidget gw)
-{
- int i;
- int n = gw->simplebase.count;
- /* int more = 0; */
- NodeStruct* z = 0;
-
- for(i=0; i < n; i++)
- {
- NodeStruct* w = gw->simplebase.nodes + i;
- if(w->draw == drawDummy && !w->managed)
- {
- printf("Recycle dummy %d\n",i);
- z = w;
- break;
- }
- }
-
- if(z == 0)
- {
- printf("Create dummy\n");
- i = NodeCreate((Widget)gw,drawDummy,sizeDummy,0);
- z = INDEX_TO_NODE(gw,i);
- z->kids = XtNew(Link);
- z->parents = XtNew(Link);
- z->kcnt = z->kmax = z->pcnt = z->pmax = 1;
- }
-
- z->r.width = z->r.height = 0;
-
- z->kids[0].node = -1;
- z->parents[0].node = -1;
-
- z->managed = False;
- z->inited = False;
-
- z->kids[0].link_data = -1;
- z->parents[0].link_data = -1;
-
- return NODE_TO_INDEX(gw,z);
-}
-
-void sb_clear_dummy_nodes(SimpleBaseWidget gw)
-{
- int i;
- int n = gw->simplebase.count;
- /* int more = 0; */
- int cnt = 0;
-
- for(i=0; i < n; i++)
- {
- NodeStruct* w = gw->simplebase.nodes + i;
- if(w->draw == drawDummy && w->managed)
- {
- NodeStruct *p = INDEX_TO_NODE(gw,w->parents[0].node);
- NodeStruct *k = INDEX_TO_NODE(gw,w->kids[0].node);
- int j;
-
- cnt++;
-
- j = sb_find_kid_index(gw,p,w);
- if(j == -1) {
- printf("Cannot find dummy in parent\n");
- abort();
- }
- p->kids[j].node = w->kids[0].node;
-
- j = sb_find_parent_index(gw,k,w);
- if(j == -1) {
- printf("Cannot find dummy in kid\n");
- abort();
- }
- k->parents[j].node = w->parents[0].node;
-
- w->kids[0].node = -1;
- w->parents[0].node = -1;
- w->kids[0].link_data = -1;
- w->parents[0].link_data = -1;
- w->managed = False;
-
- }
- }
- // printf("remove_dummy_nodes: %d\n",cnt);
-}
-
-int sb_insert_dummy_node(SimpleBaseWidget gw,int np,int nk)
-{
- NodeStruct *p = INDEX_TO_NODE(gw,np);
- NodeStruct *k = INDEX_TO_NODE(gw,nk);
- int a = sb_find_kid_index(gw,p,k);
- int b = sb_find_parent_index(gw,k,p);
- int x;
- NodeStruct *z;
-
- if(a == -1)
- {
- printf("Cannot find kid in parent\n");
- abort();
- }
-
- if(b == -1)
- {
- printf("Cannot find parent in kid\n");
- abort();
- }
-
- x = sb_new_dummy_node(gw);
- z = INDEX_TO_NODE(gw,x);
-
- /* sb_new_dummy_node may have changed the pointers */
-
- p = INDEX_TO_NODE(gw,np);
- k = INDEX_TO_NODE(gw,nk);
-
- z->managed = True;
-
- p->kids[a].node = x;
- z->parents[0].node = np;
- z->kids[0].link_data = p->kids[a].link_data;;
-
- k->parents[b].node = x;
- z->kids[0].node = nk;
- z->parents[0].link_data = k->parents[b].link_data;
-
- return x;
-}
-
-int sb_find_kid_index(SimpleBaseWidget w,NodeStruct* p,NodeStruct *k)
-{
- int i;
- int x = NODE_TO_INDEX(w,k);
-
- for(i=0;i<p->kcnt;i++)
- if( p->kids[i].node == x)
- return i;
-
- return -1;
-}
-
-int sb_find_parent_index(SimpleBaseWidget w,NodeStruct* k,NodeStruct *p)
-{
- int i;
- int x = NODE_TO_INDEX(w,p);
-
- for(i=0;i<k->pcnt;i++)
- if( k->parents[i].node == x)
- return i;
-
- return -1;
-}
-
-Boolean sb_is_dummy(SimpleBaseWidget w,NodeStruct* n)
-{
- return n->draw == drawDummy;
-}
-
-int NodeNewGroup(Widget _w,DrawProc draw, SizeProc size, void *data)
-{ return 0;
-}
-void NodeSetGroup(Widget _w,int node,int group)
-{
-}
-int NodeGetGroup(Widget _w,int node)
-{
- return -1;
-}
-
-static void xincrement (h, event, args, n_args)
-Widget h;
-XEvent *event;
-char *args[];
-int n_args;
-{
-#ifdef MOTIF
-#define SetArg(a,b) XtSetArg(al[ac],a,b);ac++
-#define GetValues(w) XtGetValues(w,al,ac);ac=0
-#define SetValues(w) XtSetValues(w,al,ac);ac=0
-
- Widget clip = XtParent(h);
- Widget swin;
- Widget v_scroll;
-
- int ac = 0;
-
-// Position x_grep,y_grep;
-// Dimension h_grep,w_grep;
-// Position x_clip,y_clip;
-// Dimension h_clip,w_clip;
-// Position dv=0,dh=0;
-// int min,max;
-// int v_val,v_size,v_inc,v_page;
-// int h_val,h_size,h_inc,h_page;
-// Position x,y;
-
- Arg al[5];
-
- /* printf("## mouse 1\n"); */
- if(!clip) return;
- swin = XtParent(clip);
- /* printf("## mouse 2\n"); */
- if(!swin || !XmIsScrolledWindow(swin)) return;
- /* printf("## mouse 3\n"); */
- if (n_args != 1) return;
-
- SetArg(XmNverticalScrollBar , &v_scroll);
- GetValues(swin);
-
- {
- int min, max, value, slider_size, inc, page_inc;
- SetArg(XmNminimum,&min);
- SetArg(XmNmaximum,&max);
- SetArg(XmNvalue,&value);
- SetArg(XmNsliderSize,&slider_size);
- SetArg(XmNincrement,&inc);
- SetArg(XmNpageIncrement,&page_inc);
-
- GetValues(v_scroll);
- /* XmScrollBarGetValues(v_scroll, value, slider_size, inc, page_inc); */
-
- int arg = atoi(args[0]);
- dh = (abs(arg) > 5) ? page_inc : inc;
-
- if (arg < 0) {
- if (value - dh < min)
- value = min;
- else
- value -= dh;
- } else {
- if (value + dh > max)
- value = max;
- else
- value += dh;
- }
-
- XmScrollBarSetValues(v_scroll,value,slider_size, inc, page_inc,TRUE);
- }
-#endif
-}
diff --git a/ecflow_4_0_7/view/src/SimpleBase.h b/ecflow_4_0_7/view/src/SimpleBase.h
deleted file mode 100644
index c0d170f..0000000
--- a/ecflow_4_0_7/view/src/SimpleBase.h
+++ /dev/null
@@ -1,95 +0,0 @@
-#ifndef SIMPLEBASE_H
-#define SIMPLEBASE_H
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #4 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-
-extern WidgetClass simplebaseWidgetClass;
-
-typedef struct _SimpleBaseClassRec *SimpleBaseWidgetClass;
-typedef struct _SimpleBaseRec *SimpleBaseWidget;
-
-#define XtNselected "selected"
-#define XtCSelected "Selected"
-
-#define XtNblinkRate "blinkRate"
-#define XtCBlinkRate "BlinkRate"
-
-#define XtNblinkColor "blinkColor"
-#define XtCBlinkColor "BlinkColor"
-
-#define XtNpsHeader "psHeader"
-#define XtCPsHeader "PsHeader"
-
-#define XtNgetpsCallback "getps"
-#define XtNlinkCallback "linkCallback"
-
-
-typedef struct {
- Widget widget;
- char *name;
- char *psproc;
-} getpsCallbackStruct;
-
-typedef struct {
- int reason;
- XEvent *event;
- void* data1;
- void* data2;
-} LinkCallbackStruct;
-
-typedef void (*DrawProc)(Widget,XRectangle*,void*);
-typedef void (*SizeProc)(Widget,XRectangle*,void*);
-
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
-
-void NodesRedraw(SimpleBaseWidget w, XEvent *event, Region region);
-int NodeCreate(Widget _w, DrawProc draw, SizeProc size, void *data);
-void NodeChanged(Widget _w, int node);
-void *NodeFind(Widget _w, XEvent *ev);
-void NodeShow(Widget _w, int node);
-void NodeHideAll(Widget _w);
-Boolean NodeVisibility(Widget _w, int node, Boolean vis);
-void NodeNewSize(Widget _w, int node);
-void NodeNewSizeAll(Widget _w);
-void NodeUpdate(Widget _w);
-void NodeReset(Widget _w);
-void NodeReserve(Widget _w, int count);
-
-void NodeInsert(Widget _w,int pnode,int knode,int nnode);
-
-void NodeAddRelation(Widget _w,int pnode,int knode);
-void *NodeGetRelationData(Widget _w,int pnode,int knode);
-void *NodeSetRelationData(Widget _w,int pnode,int knode,void*);
-GC NodeGetRelationGC(Widget _w,int pnode,int knode);
-GC NodeSetRelationGC(Widget _w,int pnode,int knode,GC);
-
-void NodeSetFocus(Widget _w, int node);
-int NodeGetFocus(Widget _w);
-
-int NodeNewGroup(Widget _w,DrawProc draw, SizeProc size, void *data);
-void NodeSetGroup(Widget _w,int node,int group);
-int NodeGetGroup(Widget _w,int node);
-
-#if defined(__cplusplus) || defined(c_plusplus)
-}
-#endif
-
-
-#endif /* SIMPLEBASE_H */
diff --git a/ecflow_4_0_7/view/src/SimpleBaseP.h b/ecflow_4_0_7/view/src/SimpleBaseP.h
deleted file mode 100644
index 46450d9..0000000
--- a/ecflow_4_0_7/view/src/SimpleBaseP.h
+++ /dev/null
@@ -1,133 +0,0 @@
-#ifndef SIMPLEBASEP_H
-#define SIMPLEBASEP_H
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #4 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-
-#include "SimpleBase.h"
-#include <Xm/DrawingAP.h>
-
-typedef void (*PrintProc) (Widget,FILE*);
-typedef void (*LayoutProc)(Widget,long*,long*);
-typedef void (*ResetProc)(Widget);
-
-
-typedef struct LinkData {
- GC gc;
- void* user_data;
-} LinkData;
-
-typedef struct Link {
- int node;
- int link_data;
-} Link;
-
-typedef struct NodeStruct {
- XRectangle r;
- XtPointer user_data;
- DrawProc draw;
- SizeProc size;
- Boolean managed;
- Boolean inited;
- int pmax;
- int pcnt;
- int kmax;
- int kcnt;
- Link *parents;
- Link *kids;
- int tmpx;
- int tmpy;
- int misc[4];
-#if 0
- Boolean is_group;
- int group;
-#endif
-} NodeStruct;
-
-typedef struct _SimpleBaseClassPart {
- PrintProc print;
- LayoutProc layout;
- ResetProc reset;
-} SimpleBaseClassPart;
-
-typedef struct _SimpleBaseClassRec {
- CoreClassPart core_class;
- CompositeClassPart composite_class;
- ConstraintClassPart constraint_class;
- XmManagerClassPart manager_class;
- XmDrawingAreaClassPart drawing_area_class;
- SimpleBaseClassPart simplebase_class;
-} SimpleBaseClassRec;
-
-extern SimpleBaseClassRec simplebaseClassRec;
-
-typedef struct {
-
- int max;
- int count;
- NodeStruct *nodes;
-
- LinkData *links;
- int link_max;
- int link_count;
-
- Pixel blink_color;
- GC blink_gc;
- GC gc;
- int selected;
- int focus;
- XtIntervalId timeout_id;
- int timeout;
- XtCallbackList getps;
- XtCallbackList link;
- String header;
- XtWorkProcId work;
-
-} SimpleBasePart;
-
-
-typedef struct _SimpleBaseRec {
- CorePart core;
- CompositePart composite;
- ConstraintPart constraint;
- XmManagerPart manager;
- XmDrawingAreaPart drawing_area;
- SimpleBasePart simplebase;
-} SimpleBaseRec;
-
-
-#define NODE_TO_INDEX(w,n) ((n)-(w)->simplebase.nodes)
-#define INDEX_TO_NODE(w,i) (&((w)->simplebase.nodes[i]))
-
-
-#define KIDS(w,n,i) (*INDEX_TO_NODE(w,n->kids[i].node))
-#define PARENTS(w,n,i) (*INDEX_TO_NODE(w,n->parents[i].node))
-
-
-int sb_new_dummy_node(SimpleBaseWidget w);
-void sb_clear_dummy_nodes(SimpleBaseWidget w);
-int sb_insert_dummy_node(SimpleBaseWidget w,int p,int k);
-
-int sb_find_kid_index(SimpleBaseWidget w,NodeStruct* p,NodeStruct *k);
-int sb_find_parent_index(SimpleBaseWidget w,NodeStruct* k,NodeStruct *p);
-
-
-Boolean sb_is_dummy(SimpleBaseWidget w,NodeStruct*p);
-
-
-#endif
-
-
-
diff --git a/ecflow_4_0_7/view/src/SimpleGraph.c b/ecflow_4_0_7/view/src/SimpleGraph.c
deleted file mode 100644
index c47ba6f..0000000
--- a/ecflow_4_0_7/view/src/SimpleGraph.c
+++ /dev/null
@@ -1,1324 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #5 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-#include <stdio.h>
-#include <math.h>
-#include <stdlib.h>
-
-#include <X11/X.h>
-#include <X11/Xlib.h>
-#include <X11/Intrinsic.h>
-#include <X11/IntrinsicP.h>
-#include <X11/StringDefs.h>
-#include <X11/CoreP.h>
-#include <X11/CompositeP.h>
-#include <X11/ConstrainP.h>
-#include <Xm/Xm.h>
-#include <Xm/XmP.h>
-#include <Xm/DrawingAP.h>
-#include <Xm/ExtObjectP.h>
-#include "SimpleGraph.h"
-#include "SimpleGraphP.h"
-
-#ifndef MAX
-#define MAX(a,b) ((a) > (b) ? (a) : (b))
-#endif
-#ifndef MIN
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-#endif
-
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
-#define LEVEL 0
-#define ARC 1
-#define VISIT 2
-#define GROUP 3
-
-#define round(X) (((X) >= 0) ? (int)((X)+0.5) : (int)((X)-0.5))
-#define RADIANS(x) (M_PI * (x) / 180.0)
-#define ABS(a) ((a)>0?(a):(-(a)))
-#define C(w) (SIMPLEGRAPH_CONSTRAINT(w)->simplegraph)
-
-
-static void Initialize();
-//static void ConstraintInitialize();
-//static void ConstraintDestroy();
-//static Boolean ConstraintSetValues();
-static void Destroy();
-static Boolean SetValues();
-//static XtGeometryResult GeometryManager();
-//static void ChangeManaged();
-//static Boolean insert_new_node();
-//static void delete_node();
-//static void new_layout();
-static void Redisplay();
-static void compute_positions(SimpleGraphWidget,int);
-static void set_positions(SimpleGraphWidget,long*,long*);
-static void Print();
-static void Layout(Widget,long*,long*);
-static void bezier_find(SimpleGraphWidget,XEvent*);
-
-static XtResource resources[] = {
- {XtNhorizontalSpace,XtCSpace,XtRDimension,sizeof(Dimension),
- XtOffset(SimpleGraphWidget, simplegraph.h_min_space), XtRString,"30" },
- {XtNverticalSpace,XtCSpace, XtRDimension,sizeof (Dimension),
- XtOffset(SimpleGraphWidget, simplegraph.v_min_space), XtRString,"10" },
- {XtNarrowAngle,XtCArrowAngle, XtRDimension,sizeof (Dimension),
- XtOffset(SimpleGraphWidget, simplegraph.arrow_angle), XtRString,"22" },
- {XtNarrowLength,XtCArrowLength, XtRDimension,sizeof (Dimension),
- XtOffset(SimpleGraphWidget, simplegraph.arrow_length), XtRString,"8" },
- {XtNarrowFilled,XtCArrowFilled, XtRBoolean,sizeof (Boolean),
- XtOffset(SimpleGraphWidget, simplegraph.arrow_filled), XtRString,"false" },
- {"round","Round", XtRBoolean,sizeof (Boolean),
- XtOffset(SimpleGraphWidget, simplegraph.mode), XtRString,"false" },
- {XtNarcOnly,XtCArcOnly, XtRPointer,sizeof(Widget),
- XtOffset(SimpleGraphWidget, simplegraph.arc_only), XtRPointer,NULL},
-};
-
-/*
-static XtResource simplegraphConstraintResources[] = {
- {XtNarcNumber,XtCArcNumber, XtRint,sizeof(int),
- XtOffset(SimpleGraphConstraints, simplegraph.misc[ARC]), XtRString,"0" },
-};
-*/
-
-SimpleGraphClassRec simplegraphClassRec = {
- {
- /* core_class fields */
- (WidgetClass) &simplebaseClassRec, /* superclass */
- "SimpleGraph", /* class_name */
- sizeof(SimpleGraphRec), /* widget_size */
- NULL, /* class_init */
- NULL, /* class_part_init */
- FALSE, /* class_inited */
- Initialize, /* initialize */
- NULL, /* initialize_hook */
- XtInheritRealize, /* realize */
- NULL, /* actions */
- 0, /* num_actions */
- resources, /* resources */
- XtNumber(resources), /* num_resources */
- NULLQUARK, /* xrm_class */
- TRUE, /* compress_motion */
- XtExposeCompressMaximal, /* compress_exposure */
- TRUE, /* compress_enterleave*/
- TRUE, /* visible_interest */
- Destroy, /* destroy */
- NULL, /* resize */
- Redisplay, /* expose */
- SetValues, /* set_values */
- NULL, /* set_values_hook */
- XtInheritSetValuesAlmost, /* set_values_almost */
- NULL, /* get_values_hook */
- NULL, /* accept_focus */
- XtVersion, /* version */
- NULL, /* callback_private */
- XtInheritTranslations, /* tm_table */
- NULL, /* query_geometry */
- XtInheritDisplayAccelerator, /* display_accelerator*/
- NULL, /* extension */
- },
- {
- /* simplebase_class fields */
- NULL, /* geometry_manager */
- NULL, /* change_managed */
- XtInheritInsertChild, /* insert_child */
- XtInheritDeleteChild, /* delete_child */
- NULL, /* extension */
- },
- {
- /* constraint_class fields */
- NULL, /* subresources */
- 0, /* subresource_count */
- 0, /* constraint_size */
- NULL, /* initialize */
- NULL, /* destroy */
- NULL, /* set_values */
- NULL, /* extension */
- },
- {
- XtInheritTranslations, /* default translations */
- NULL, /* syn_resources */
- 0, /* num_syn_resources */
- NULL, /* syn_cont_resources */
- 0, /* num_syn_cont_resources */
- XmInheritParentProcess, /* parent_process */
- NULL, /* extension */
-
- },
- {
- NULL,
- },
- {
- Print,
- Layout,
- },
- {
- /* SimpleGraph class fields */
- 0,
- },
-};
-
-#ifdef TOP_BOTTOM
-
-#define TMPX tmpx
-#define TMPY tmpy
-#define WIDTH width
-#define HEIGHT height
-#define H_DIST h_dist
-#define V_DIST v_dist
-#define H_MIN_SPACE h_min_space
-#define V_MIN_SPACE v_min_space
-
-#else
-
-#define TMPX tmpy
-#define TMPY tmpx
-#define WIDTH height
-#define HEIGHT width
-#define H_DIST v_dist
-#define V_DIST h_dist
-#define H_MIN_SPACE v_min_space
-#define V_MIN_SPACE h_min_space
-
-#endif
-
-/* #define MANAGED(n) ((n)->managed && ((n)->group == -1)) */
-#define MANAGED(n) ((n)->managed)
-
-WidgetClass simplegraphWidgetClass = (WidgetClass) &simplegraphClassRec;
-
-static void button_click(w,cd,event,continue_dispatch)
-SimpleGraphWidget w;
-XtPointer *cd;
-XEvent *event;
-Boolean *continue_dispatch;
-{
- bezier_find(w,event);
-}
-
-static void make_gc(SimpleGraphWidget w)
-{
-}
-
-static void delete_gc(SimpleGraphWidget w)
-{
-}
-
-static void Initialize(request, new)
-SimpleGraphWidget request, new;
-{
- /* XGCValues values;
- XtGCMask valueMask;
- int i; */
- /*
- * Make sure the widget's width and height are
- * greater than zero.
- */
- if (request->core.width <= 0)
- new->core.width = 5;
- if (request->core.height <= 0)
- new->core.height = 5;
-
- new->simplegraph.cos_arrow = cos(RADIANS(new->simplegraph.arrow_angle));
- new->simplegraph.sin_arrow = sin(RADIANS(new->simplegraph.arrow_angle));
-
- /*
- * Create a simplegraphics context for the connecting lines.
- */
-
- make_gc(new);
-
- /*
- * Create the hidden root widget.
- */
-
- /*
- * Allocate the tables used by the layout
- * algorithm.
- */
-
- new->simplegraph.gc[0] = new->simplebase.gc;
- new->simplegraph.gc_count = 1;
-
- XtAddEventHandler((Widget)new,ButtonPressMask,
- False,(XtEventHandler)button_click,(XtPointer)new);
-
-}
-
-static void Destroy(w)
-SimpleGraphWidget w;
-{
- delete_gc(w);
- XtRemoveEventHandler((Widget)w,ButtonPressMask,
- False,(XtEventHandler)button_click,(XtPointer)w);
-}
-
-
-
-static Boolean SetValues(current, request, new)
-SimpleGraphWidget current, request, new;
-{
- int redraw = TRUE;
- long w,h;
- /* int i;
- int new_gc = new->core.background_pixel != current->core.background_pixel; */
-
-
- if (new->simplegraph.arrow_angle != current->simplegraph.arrow_angle)
- {
- new->simplegraph.cos_arrow = cos(RADIANS(new->simplegraph.arrow_angle));
- new->simplegraph.sin_arrow = sin(RADIANS(new->simplegraph.arrow_angle));
- }
-
- if (new->simplegraph.arc_only != current->simplegraph.arc_only)
- {
- Layout((Widget)new,&w,&h);
- redraw = FALSE;
- }
-
- /*
- * If the minimum spacing has changed, recalculate the
- * simplegraph layout. new_layout() does a redraw, so we don't
- * need SetValues to do another one.
- */
- if (new->simplegraph.v_min_space != current->simplegraph.v_min_space ||
- new->simplegraph.h_min_space != current->simplegraph.h_min_space){
- Layout((Widget)new,&w,&h);
- redraw = FALSE;
- }
- return (redraw);
-}
-
-
-
-//static int first_kid(SimpleGraphWidget w,NodeStruct *n)
-//{
-// int i;
-// for(i=0;i<n->pcnt;i++)
-// if(MANAGED(&PARENTS(w,n,i)))
-// return i;
-// return -1;
-//}
-//
-//static int last_kid(SimpleGraphWidget w,NodeStruct *n)
-//{
-// int i;
-//
-// if(n->pcnt)
-// for(i= n->pcnt - 1;i>=0;i--)
-// if(MANAGED(&PARENTS(w,n,i)))
-// return i;
-// return -1;
-//}
-
-
-//static void line(SimpleGraphWidget w,int x1,int y1,int x2,int y2,int gc)
-//{
-// GC topGC = w->manager.top_shadow_GC;
-// GC midGC = w->manager.background_GC;
-// GC botGC = w->manager.bottom_shadow_GC;
-// if(gc) midGC = w->simplegraph.gc[gc % GC_COUNT];
-//
-// if(x1 == x2)
-// {
-// /* vertical */
-//
-// XDrawLine(XtDisplay(w),XtWindow(w),
-// topGC,x1-1,y1,x2-1,y2);
-// XDrawLine(XtDisplay(w),XtWindow(w),
-// midGC,x1,y1,x2,y2);
-// XDrawLine(XtDisplay(w),XtWindow(w),
-// botGC,x1+1,y1,x2+1,y2);
-// }
-// else
-// {
-// /* horizontal */
-//
-// XDrawLine(XtDisplay(w),XtWindow(w),
-// topGC,x1,y1-1,x2,y2-1);
-// XDrawLine(XtDisplay(w),XtWindow(w),
-// midGC,x1,y1,x2,y2);
-// XDrawLine(XtDisplay(w),XtWindow(w),
-// botGC,x1,y1+1,x2,y2+1);
-// }
-//}
-
-//static void arrow(SimpleGraphWidget fw,int x1,int y1,int x2,int y2,int gc)
-//{
-// int x;
-// int y;
-// int size = 11;
-// int h = size;
-// int w = size;
-// unsigned int d;
-//
-// GC topGC = fw->manager.top_shadow_GC;
-// GC midGC = fw->manager.background_GC;
-// GC botGC = fw->manager.bottom_shadow_GC;
-// if(gc) midGC = fw->simplegraph.gc[gc % GC_COUNT];
-//
-// if(x1 > x2)
-// {
-// d = XmARROW_LEFT;
-// x = (x1 + x2)/2 - size/2;
-// y = y1 - size/2;
-// }
-// else if(x1 < x2)
-// {
-// d = XmARROW_RIGHT;
-// x = (x2 + x1)/2 - size/2;
-// y = y1 - size/2;
-// }
-// else if(y2 >= y1)
-// {
-// d = XmARROW_DOWN;
-// y = (y2 + y1)/2 - size/2;
-// x = x1 - size/2;
-// }
-// else
-// {
-// d = XmARROW_UP;
-// y = (y1 + y2)/2 - size/2;
-// x = x1 - size/2;
-// }
-//
-//
-// _XmDrawArrow(XtDisplay(fw),XtWindow(fw),
-// topGC,
-// botGC,
-// midGC,
-// x,y,w,h,1,d);
-//
-//}
-//
-//static int minspace = 10;
-
-static void bezier_arrow(Widget w,GC gc,XPoint* p,int npoints)
-{
-#define ASIZE 4
-
- XPoint* f;
- XPoint* t;
- double a,b,l;
- int i;
- XPoint q[3];
-
- double xx[3] = {
- -ASIZE, ASIZE , -ASIZE };
- double yy[3] = {
- ASIZE, 0 , -ASIZE };
-
-
- int n = npoints/2;
- int m = npoints/2+1;
- while(n >= 0 && m < npoints)
- {
- f = &p[n];
- t = &p[m];
-
- a = t->x - f->x;
- b = t->y - f->y;
- l = sqrt(a*a+b*b);
- if(l > ASIZE) break;
-
- n--;
- m++;
- }
-
-
- /* a = -a; */
- b = -b;
-
- for(i = 0 ; i < 3; i++)
- {
- double x = (a*xx[i] + b*yy[i])/l;
- double y = (-b*xx[i] + a*yy[i])/l;
-
- q[i].x = round(x + f->x);
- q[i].y = round(y + f->y);
-
- }
-
- XFillPolygon(XtDisplay(w), XtWindow(w), gc,
- q,3,Convex,CoordModeOrigin);
-
-}
-
-static void bezier(XPoint* p,int npoints,XPoint* control)
-{
- int i;
- for (i = 0; i < npoints; i++)
- {
- double array[4];
- double u, u2, u3, x, y;
- u = (double) i / (double) (npoints - 1);
- u2 = u * u;
- u3 = u2 * u;
- array[0] = -u3 + 3. * u2 - 3. * u + 1.;
- array[1] = 3. * u3 - 6. * u2 + 3. * u;
- array[2] = -3. * u3 + 3. * u2;
- array[3] = u3;
- x = array[0] * control[0].x + array[1] * control[1].x + array[2] * control[2].x + array[3] * control[3].x;
- y = array[0] * control[0].y + array[1] * control[1].y + array[2] * control[2].y + array[3] * control[3].y;
-
- p[i].x = round(x);
- p[i].y = round(y);
- }
-
-}
-
-static void connect(SimpleGraphWidget w,
-XRectangle *from,XRectangle *to,
-int fn, int fc,int tn,int tc,int dm,int link_data)
-{
-
- GC gc = w->simplebase.gc;
-
-#if TOP_BOTTOM
- int fx = from->x + ((fn+1)*from->width)/(fc+1);
- int fy = from->y + from->height;
- int tx = to->x + ((tn+1)*to->width)/(tc+1);
- int ty = to->y;
-#else
- double fx = from->x + from->width;
- double fy = from->y + from->height/2.0;
- double tx = to->x ;
- double ty = to->y + to->height / 2.0;
-#endif
-
-
- /* .cap_style = CapRound; join_style = JoinRound; */
-
-
- XPoint control[4];
- XPoint p[100];
-
- control[0].x = fx;
- control[0].y = fy;
-
- control[1].x = (fx + tx)/2;
- control[1].y = fy;
-
- control[2].x = (fx + tx)/2;
- control[2].y = ty;
-
- control[3].x = tx;
- control[3].y = ty;
-
- bezier(p,XtNumber(p),control);
-
- if(link_data != -1)
- {
- int i;
- gc = w->simplebase.links[link_data].gc;
- for(i = 0; i < w->simplegraph.gc_count; i++)
- if(w->simplegraph.gc[i] == gc)
- break;
- if(i == w->simplegraph.gc_count)
- w->simplegraph.gc[w->simplegraph.gc_count++] = gc;
- }
-
- XDrawLines(XtDisplay(w),XtWindow(w),
- gc,
- p,XtNumber(p),CoordModeOrigin);
-
-
- bezier_arrow((Widget)w,gc,p,XtNumber(p));
-
-}
-
-int close_to(int x,int y, int x1, int y1, int x2, int y2)
-{
- if(x1>x2) {
- int c = x1;
- x1 = x2;
- x2 = c;
- }
- if(y1>y2) {
- int c = y1;
- y1 = y2;
- y2 = c;
- }
-
- x1 -= 3;
- x2 += 3;
- y1 -= 3;
- y2 += 3;
-
- return ( x1 <= x && x <= x2 && y1 <= y && y <= y2);
-}
-
-static int smallest(int x, int y,XPoint* p, int n)
-{
- /* int i; */
- if(n > 1 && close_to(x,y,p[0].x,p[0].y, p[n-1].x,p[n-1].y))
- {
- int m = n/2;
- int a = smallest(x,y,p,m);
- int b = smallest(x,y,p+m,n-m);
- int z = MIN(a,b);
- return MIN(z,n);
- }
- return 32000;
-}
-
-static int line_find(SimpleGraphWidget w,XEvent* event,
-XRectangle *from,XRectangle *to,
-NodeStruct* n1,NodeStruct* n2)
-{
-
-#if TOP_BOTTOM
- int fx = from->x + ((fn+1)*from->width)/(fc+1);
- int fy = from->y + from->height;
- int tx = to->x + ((tn+1)*to->width)/(tc+1);
- int ty = to->y;
-#else
- double fx = from->x + from->width;
- double fy = from->y + from->height/2.0;
- double tx = to->x ;
- double ty = to->y + to->height / 2.0;
-#endif
-
- int x = event->xbutton.x;
- int y = event->xbutton.y;
- /* int i; */
- int value = 32000;
-
- /* .cap_style = CapRound; join_style = JoinRound; */
-
- if( close_to(x,y,fx,fy,tx,ty))
- {
-
-
- XPoint control[4];
- XPoint p[100];
-
- control[0].x = fx;
- control[0].y = fy;
-
- control[1].x = (fx + tx)/2;
- control[1].y = fy;
-
- control[2].x = (fx + tx)/2;
- control[2].y = ty;
-
- control[3].x = tx;
- control[3].y = ty;
-
- bezier(p,XtNumber(p),control);
-
- return smallest(x,y,p,XtNumber(p));
- }
-
- return value;
-
-}
-
-static void Redisplay (SimpleGraphWidget w, XEvent *event, Region region)
-{
- int i, j;
- /* int fkid; */
- int m = 0;
-
- /* XPoint points[3]; */
- Region rg,clip;
-
- XEvent ev;
-
- while(XCheckWindowEvent(XtDisplay(w),XtWindow(w),ExposureMask,&ev))
- XtAddExposureToRegion(&ev,region);
-
- rg = XCreateRegion();
- clip = XCreateRegion();
-
- for (i = 0; i < w -> simplebase.count; i++)
- {
-
- NodeStruct *child = w -> simplebase.nodes + i;
- if((child)->managed)
- XUnionRectWithRegion(&child->r,rg,rg);
- }
- XSubtractRegion(region,rg,clip);
-
- for(i = 0; i < w->simplegraph.gc_count; i++)
- XSetRegion(XtDisplay(w),w->simplegraph.gc[i],clip);
-
-
- for (i = 0; i < w -> simplebase.count; i++)
- {
-
- NodeStruct *n = w -> simplebase.nodes + i;
- if(!n->managed)
- continue;
-
- for (j = 0; j < n->kcnt; j++)
- {
- NodeStruct *c = &KIDS(w,n,j);
- int k = 0;
-
- if(!c->managed)
- continue;
-
- connect(w,&n->r,&c->r,
- j,n->kcnt,
- k,c->pcnt,
- m++,
- n->kids[j].link_data
- );
-
- }
- }
-
- XDestroyRegion(clip);
- XDestroyRegion(rg);
- for(i = 0; i < w->simplegraph.gc_count; i++)
- XSetClipMask(XtDisplay(w),w->simplegraph.gc[i],None);
-
- NodesRedraw((SimpleBaseWidget)w,event,region);
-}
-
-static void bezier_find(SimpleGraphWidget w,XEvent *event)
-{
- int i, j;
- /* int fkid; */
- int m = 0;
- int min = 32000;
- NodeStruct* m1 = 0 ;
- NodeStruct *m2 = 0;
- LinkCallbackStruct cb;
-
- for (i = 0; i < w -> simplebase.count; i++)
- {
- NodeStruct *n = w -> simplebase.nodes + i;
- if(!n->managed)
- continue;
-
- for (j = 0; j < n->kcnt; j++)
- {
- NodeStruct *c = &KIDS(w,n,j);
- if(!c->managed)
- continue;
-
- m = line_find(w,event,&n->r,&c->r,n,c);
- if(m < min)
- {
- min = m;
- m1 = n;
- m2 = c;
-
- }
- }
- }
-
- while(m1 && sb_is_dummy((SimpleBaseWidget)w,m1))
- m1 = &PARENTS(w,m1,0);
-
- while(m2 && sb_is_dummy((SimpleBaseWidget)w,m2))
- m2 = &KIDS(w,m2,0);
-
- cb.reason = 0;
- cb.event = event;
- cb.data1 = m1?m1->user_data:0;
- cb.data2 = m1?m2->user_data:0;
- XtCallCallbacks((Widget)w, XtNlinkCallback, (XtPointer)&cb);
-}
-
-static void Layout(Widget w,long *maxWidth,long *maxHeight)
-{
- SimpleGraphWidget gw = (SimpleGraphWidget)w;
- /* XtGeometryResult result; */
- /* Dimension replyWidth = 0, replyHeight = 0; */
- *maxWidth = 1;
- *maxHeight = 1;
- sb_clear_dummy_nodes((SimpleBaseWidget)gw);
- compute_positions(gw,1);
- set_positions(gw, maxWidth,maxHeight);
-}
-
-
-static int calc_level(SimpleGraphWidget w,NodeStruct *n)
-{
-
- int i;
- int lvl = 0;
-
- if(n->misc[VISIT]) return -1;
-
- n->misc[VISIT] = True;
-
- for(i=0;i<n->pcnt;i++)
- {
- NodeStruct *p = &PARENTS(w,n,i);
- if(MANAGED(p))
- {
- int lev = calc_level(w,p) + 1;
- lvl = MAX(lvl,lev);
- }
- }
-
- n->misc[LEVEL] = lvl;
- n->misc[VISIT] = False;
-
- return lvl;
-
-}
-
-static void set_arc(SimpleGraphWidget w,NodeStruct *n,int arc)
-{
-
- int i;
-
- if(n->misc[VISIT]) return;
- n->misc[VISIT] = True;
-
- n->misc[ARC] = arc;
-
- for(i=0;i<n->pcnt;i++)
- {
- NodeStruct *p = &PARENTS(w,n,i);
- if(MANAGED(p))
- set_arc(w,p,arc);
- }
-
- n->misc[VISIT] = False;
-
-}
-
-static int calc_arc(SimpleGraphWidget w,NodeStruct *n)
-{
-
- int i;
- int a = n->misc[ARC];
-
- if(n->misc[VISIT]) return 0;
- n->misc[VISIT] = True;
-
- if(n->pcnt)
- {
- for(i=0;i<n->pcnt;i++)
- {
- NodeStruct *p = &PARENTS(w,n,i);
- if(MANAGED(p))
- {
- int b = calc_arc(w,p);
- a = MAX(a,b);
- }
- }
- set_arc(w,n,a);
- }
-
- n->misc[VISIT] = False;
- return a;
-}
-
-static SimpleGraphWidget sort;
-
-static int by_arc(const void* n1,const void* n2)
-{
- NodeStruct *w1 = sort->simplebase.nodes + *(int*)n1;
- NodeStruct *w2 = sort->simplebase.nodes + *(int*)n2;
- if(w1->misc[LEVEL] != w2->misc[LEVEL])
- return w1->misc[LEVEL] - w2->misc[LEVEL];
-
- return w1->misc[ARC] - w2->misc[ARC];
-
-}
-
-static int by_x(const void *n1,const void *n2)
-{
- NodeStruct *w1 = sort->simplebase.nodes + *(int*)n1;
- NodeStruct *w2 = sort->simplebase.nodes + *(int*)n2;
-
- if(w1->misc[LEVEL] != w2->misc[LEVEL])
- return w1->misc[LEVEL] - w2->misc[LEVEL];
-
- return w1->TMPX - w2->TMPX;
-
-}
-
-
-static int by_level(const void *n1,const void *n2)
-{
- NodeStruct *w1 = sort->simplebase.nodes + *(int*)n1;
- NodeStruct *w2 = sort->simplebase.nodes + *(int*)n2;
-
- return w1->misc[LEVEL] - w2->misc[LEVEL];
-
-}
-
-
-static int no_parents(SimpleGraphWidget w,NodeStruct *n)
-{
- int i;
-
- for(i=0;i<n->pcnt;i++) {
- NodeStruct *p = &PARENTS(w,n,i);
- if(MANAGED(p)) return FALSE;
- }
-
- return TRUE;
-
-}
-
-static int no_kidss(SimpleGraphWidget w,NodeStruct *n)
-{
- int i;
- for(i=0;i<n->kcnt;i++) {
- NodeStruct *p = &KIDS(w,n,i);
- if(MANAGED(p)) return FALSE;
- }
-
- return TRUE;
-
-}
-
-
-static void calc_level_pass2(SimpleGraphWidget w,NodeStruct *n)
-{
- int i;
- int lvl1 = 12000;
-
- for(i=0;i<n->kcnt;i++)
- {
- NodeStruct *p = &KIDS(w,n,i);
- if(MANAGED(p))
- lvl1 = MIN(lvl1,p->misc[LEVEL]);
- }
- n->misc[LEVEL] = lvl1-1;
-}
-
-static void calc_y(SimpleGraphWidget gw,int *nodes,int *levels,
-int *positions,
-int max_in_a_level,int no_levels,int num_nodes,int v_dist)
-{
- int i;
- int max = max_in_a_level * v_dist;
-
- for(i=0;i<no_levels;i++)
- positions[i] = ((max / levels[i])-
- (max / max_in_a_level))/2;
-
- for(i=0;i<num_nodes;i++)
- {
- NodeStruct *n = gw->simplebase.nodes + nodes[i];
- n->TMPX = positions[n->misc[LEVEL]];
- positions[n->misc[LEVEL]] += (max / levels[n->misc[LEVEL]]);
- }
-
-}
-
-static int add_node(SimpleGraphWidget w,int n,int m,int lvl)
-{
- int x = sb_insert_dummy_node((SimpleBaseWidget)w,n,m);
- INDEX_TO_NODE(w,x)->misc[LEVEL] = lvl;
- return x;
-}
-
-static int add_dummies(SimpleGraphWidget w,NodeStruct *n)
-{
- int i;
- int more = 0;
- int lvl = n->misc[LEVEL];
-
- if(n->misc[VISIT]) return 0;
- n->misc[VISIT] = True;
-
- for(i=0;i<n->kcnt;i++)
- {
- NodeStruct *p = &KIDS(w,n,i);
-
- if(MANAGED(p))
- {
- int klvl = p->misc[LEVEL];
- int d = klvl - lvl;
- int l = lvl;
- int a = NODE_TO_INDEX(w,n);
- int b = NODE_TO_INDEX(w,p);
-
- int x = NODE_TO_INDEX(w,p);
- int y = NODE_TO_INDEX(w,n);
-
- while(d-- > 1)
- {
- a = add_node(w,a,b,++l);
- more = 1;
- }
-
- /* note: creating dummnies may change pointers*/
- p = INDEX_TO_NODE(w,x);
- n = INDEX_TO_NODE(w,y);
-
- }
-
-
- more = add_dummies(w,p) || more;
- }
- n->misc[VISIT] = False;
- return more;
-
-}
-
-static int add_dummy_nodes(SimpleGraphWidget gw)
-{
- int i;
- int n = gw->simplebase.count;
- int more = 0;
-
- for(i=0; i < n; i++)
- {
- NodeStruct *w = gw->simplebase.nodes + i;
- if(MANAGED(w))
- more = add_dummies(gw,w) || more;
- }
-
- return more;
-}
-
-static void compute_positions(SimpleGraphWidget gw,int dummy)
-{
- int i;
- int n = gw->simplebase.count;
- int *levels;
- int *positions;
- int count;
- int max_in_a_level = 0;
- int max_level = 0;
- int arc=0;
- int minx,miny;
-
- int no_levels = 0;
- int num_nodes = 0;
- int *nodes;
- int *widths;
- int *heights;
- int *kids;
- int a;
- int move_it;
- int more;
- int v_dist = 10;
- int h_dist = 10;
- int chg = TRUE;
- NodeStruct* focus = (gw->simplebase.focus>=0)? (gw->simplebase.nodes +
- gw->simplebase.focus) : 0;
-
- sort = gw;
-
-
- num_nodes = 0;
- for(i=0;i<n;i++)
- {
- NodeStruct *w = gw->simplebase.nodes + i;
- if(MANAGED(w)) num_nodes++;
- w->misc[LEVEL] = w->misc[ARC] = -1;
- w->misc[VISIT] = False;
- }
-
- if(!num_nodes) return;
-
- if(focus == 0) focus = gw->simplebase.nodes;
-
-
- levels = (int*)XtCalloc(num_nodes,sizeof(int));
- positions = (int*)XtCalloc(num_nodes,sizeof(int));
- nodes = (int*)XtCalloc(num_nodes,sizeof(int));
- widths = (int*)XtCalloc(num_nodes,sizeof(int));
- heights = (int*)XtCalloc(num_nodes,sizeof(int));
- kids = (int*)XtCalloc(num_nodes,sizeof(int));
-
- num_nodes=0;
- for(i=0;i<n;i++)
- {
- NodeStruct *w = gw->simplebase.nodes + i;
- if(MANAGED(w)) nodes[num_nodes++] = i;
- w->misc[LEVEL] = 0;
- }
- arc = 1;
-
- for(i=0;i<num_nodes;i++)
- {
- NodeStruct *w = gw->simplebase.nodes + nodes[i];
- calc_level(gw,w);
- w->misc[ARC] = arc++;
-
- H_DIST = MAX(H_DIST,w->r.WIDTH);
- V_DIST = MAX(V_DIST,w->r.HEIGHT);
- }
-
- H_DIST += gw->simplegraph.H_MIN_SPACE;
- V_DIST += gw->simplegraph.V_MIN_SPACE;
-
- for(i=0;i<num_nodes;i++)
- {
- NodeStruct *w = gw->simplebase.nodes + nodes[i];
- if (no_parents(gw,w) && !no_kidss(gw,w))
- calc_level_pass2(gw,w);
- }
-
-#if 1
- if(dummy && add_dummy_nodes(gw))
- {
- XtFree((XtPointer)levels);
- XtFree((XtPointer)positions);
- XtFree((XtPointer)nodes);
- XtFree((XtPointer)widths);
- XtFree((XtPointer)heights);
- XtFree((XtPointer)kids);
- compute_positions(gw,0);
- return;
- }
-#endif
-
- qsort(nodes,num_nodes,sizeof(int),by_level);
-
- for(i=0;i<num_nodes;i++)
- {
- NodeStruct *w = gw->simplebase.nodes + nodes[i];
- levels[w->misc[LEVEL]]++;
-
- if(levels[w->misc[LEVEL]] > max_in_a_level)
- {
- max_in_a_level = levels[w->misc[LEVEL]];
- max_level = w->misc[LEVEL];
- }
-
- no_levels = MAX(no_levels,w->misc[LEVEL]);
-
- widths[w->misc[LEVEL]] = MAX(widths[w->misc[LEVEL]],w->r.WIDTH);
- heights[w->misc[LEVEL]] = MAX(heights[w->misc[LEVEL]],w->r.HEIGHT);
- kids[w->misc[LEVEL]] = MAX(kids[w->misc[LEVEL]],w->kcnt);
-
- }
- no_levels++;
-
-
- a = 0;
- for( i = 0 ;i<no_levels;i++)
- {
- int b = heights[i] + gw->simplegraph.V_MIN_SPACE;
-
-
- b += kids[i] * 2 ; /* +5 pixels per node with max kids in level */
- /* printf("level %d = %d %d\n",i,a,heights[i]); */
- heights[i] = a;
- a += b;
- widths[i] += gw->simplegraph.H_MIN_SPACE;
- /* printf("level %d = %d\n",i,a); */
- }
-
- for(i=0;i<num_nodes;i++)
- {
- NodeStruct *w = gw->simplebase.nodes + nodes[i];
- w->TMPY = heights[w->misc[LEVEL]];
- /* printf("node y = %d %d\n",w->misc[LEVEL],w->TMPY); */
- }
-
-
- for(a=0;a<2;a++)
- {
- for(i=0;i<num_nodes;i++) {
- NodeStruct *w = gw->simplebase.nodes + nodes[i];
- if(no_kidss(gw,w)) calc_arc(gw,w);
- }
- for(i=0;i<num_nodes;i++){
- NodeStruct *w = gw->simplebase.nodes + nodes[i];
- if(no_kidss(gw,w)) set_arc(gw,w,w->misc[ARC]);
- }
- }
-
-
- qsort(nodes,num_nodes,sizeof(int),by_arc);
-
- for(a=0;a<no_levels;a++)
- if(levels[a]==0) levels[a]=1;
-
-
- calc_y(gw,nodes,levels,positions,max_in_a_level,no_levels,num_nodes,H_DIST);
-
- move_it = 0;
-
- more = 1;
- qsort(nodes,num_nodes,sizeof(int),by_x);
- while(more--)
- {
-
- count = num_nodes;
- while(count--)
- {
- for(i=0;i<num_nodes;i++)
- {
- int j;
- int n = 0;
- int x = 0;
- NodeStruct *w = gw->simplebase.nodes + nodes[i];
- if( (max_level != w->misc[LEVEL]) ^ move_it)
- {
-
-
- for(j=0;j<w->pcnt;j++)
- {
- NodeStruct *p = &PARENTS(gw,w,j);
- if(MANAGED(p) && p != focus)
- {
- x += p->TMPX;
- n++;
- }
- }
-
-
- for(j=0;j<w->kcnt;j++)
- {
- NodeStruct *p = &KIDS(gw,w,j);
- if(MANAGED(p) && p != focus)
- {
- x += p->TMPX;
- n++;
- }
- }
- w->TMPX = n?x/n:x;
- }
- }
-
-
-
- qsort(nodes,num_nodes,sizeof(int),by_x);
- move_it = !move_it;
-
- chg = TRUE;
- a = 10000;
- while(chg && a--)
- {
- chg = FALSE;
- for(i=1;i<num_nodes;i++) {
- NodeStruct *w = gw->simplebase.nodes + nodes[i];
- NodeStruct *z = gw->simplebase.nodes + nodes[i-1];
- if(z->misc[LEVEL] == w->misc[LEVEL])
- if(w->TMPX-z->TMPX< widths[w->misc[LEVEL]])
- {
- if(z != focus)
- z->TMPX -= widths[w->misc[LEVEL]]/2;
- if(w != focus)
- w->TMPX += widths[w->misc[LEVEL]]/2;
- chg = TRUE;
- }
- }
- }
- }
- }
-
-
- miny = (gw->simplebase.nodes + nodes[0])->tmpy;
- minx = (gw->simplebase.nodes + nodes[0])->tmpx;
-
- for(i=1;i<num_nodes;i++)
- {
- NodeStruct *w = gw->simplebase.nodes + nodes[i];
- if(w->tmpx<minx) minx = w->tmpx;
- if(w->tmpy<miny) miny = w->tmpy;
- }
-
- minx -= 20;
- miny -= 20;
-
- for(i=0;i<num_nodes;i++)
- {
- NodeStruct *w = gw->simplebase.nodes + nodes[i];
- w->tmpx -= minx;
- w->tmpy -= miny;
- }
-
-
- XtFree((XtPointer)levels);
- XtFree((XtPointer)positions);
- XtFree((XtPointer)nodes);
- XtFree((XtPointer)widths);
- XtFree((XtPointer)heights);
- XtFree((XtPointer)kids);
-
-
-}
-
-
-
-static SimpleGraphWidget sort_widget = 0;
-
-static int left_to_right(const void *a,const void *b)
-{
- NodeStruct *na = sort_widget->simplebase.nodes + ((Link*)a)->node;
- NodeStruct *nb = sort_widget->simplebase.nodes + ((Link*)b)->node;
- return na->r.x - nb->r.x;
-}
-
-
-static void set_positions(SimpleGraphWidget gw, long *maxWidth,long *maxHeight)
-{
- int i;
-
- for(i=0;i<gw->simplebase.count;i++)
- {
- NodeStruct *w = gw->simplebase.nodes + i;
- if(w->managed )
- {
- {
- w->r.x = w->tmpx;
- w->r.y = w->tmpy;
- *maxWidth = MAX(*maxWidth,w->tmpx + w->r.width + gw->simplegraph.h_min_space);
- *maxHeight = MAX(*maxHeight,w->tmpy + w->r.height + gw->simplegraph.v_min_space);
-#if 0
- if(w->is_group)
- {
- int j;
- int x = w->r.x;
- int y = w->tmpy;
- for(j=0;j<gw->simplebase.count;j++)
- {
- NodeStruct *v = gw->simplebase.nodes + j;
- if(v->managed && v->group == i)
- {
- v->r.x = x;
- v->r.y = y;
- y += v->r.height;
- }
- }
- }
-#endif
- }
- }
-}
-
-sort_widget = gw;
-for(i=0;i<gw->simplebase.count;i++)
-{
- NodeStruct *w = gw->simplebase.nodes + i;
- qsort(w->parents,w->pcnt,sizeof(Link),left_to_right);
- qsort(w->kids,w->kcnt,sizeof(Link),left_to_right);
-}
-}
-
-Widget CreateGraph(par,nam,al,ac)
-Widget par;
-char *nam;
-ArgList al;
-int ac;
-
-{
- return XtCreateWidget(nam,simplegraphWidgetClass,par,al,ac);
-}
-
-static void Print (SimpleGraphWidget w, FILE *f)
-{
-}
-
diff --git a/ecflow_4_0_7/view/src/SimpleGraph.h b/ecflow_4_0_7/view/src/SimpleGraph.h
deleted file mode 100644
index 9f3cafe..0000000
--- a/ecflow_4_0_7/view/src/SimpleGraph.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef SIMPLEGRAPH_H
-#define SIMPLEGRAPH_H
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #4 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "SimpleBase.h"
-
-extern WidgetClass simplegraphWidgetClass;
-
-typedef struct _SimpleGraphClassRec *SimpleGraphWidgetClass;
-typedef struct _SimpleGraphRec *SimpleGraphWidget;
-
-#define XtNhorizontalSpace "horizontalSpace"
-#define XtNverticalSpace "verticalSpace"
-#define XtCPad "Pad"
-
-#define XtNarcOnly "arcOnly"
-#define XtCArcOnly "ArcOnly"
-
-#define XtNarrowAngle "arrowAngle"
-#define XtNarrowFilled "arrowFilled"
-#define XtNarrowLength "arrowLength"
-#define XtCArrowAngle "ArrowAngle"
-#define XtCArrowFilled "ArrowFilled"
-#define XtCArrowLength "ArrowLength"
-
-Widget CreateGraph(Widget,char*, Arg*,int);
-
-
-#endif /* SIMPLEGRAPH_H */
diff --git a/ecflow_4_0_7/view/src/SimpleGraphP.h b/ecflow_4_0_7/view/src/SimpleGraphP.h
deleted file mode 100644
index fa45aa2..0000000
--- a/ecflow_4_0_7/view/src/SimpleGraphP.h
+++ /dev/null
@@ -1,72 +0,0 @@
-#ifndef SIMPLEGRAPHP_H
-#define SIMPLEGRAPHP_H
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #4 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-
-
-#include <Xm/XmP.h>
-#include <Xm/DrawingAP.h>
-#include "SimpleBaseP.h"
-
-#define GC_COUNT 10
-
-typedef struct _SimpleGraphClassPart {
- int ignore;
-} SimpleGraphClassPart;
-
-typedef struct _SimpleGraphClassRec {
- CoreClassPart core_class;
- CompositeClassPart composite_class;
- ConstraintClassPart constraint_class;
- XmManagerClassPart manager_class;
- XmDrawingAreaClassPart drawing_area_class;
- SimpleBaseClassPart simplebase_part;
- SimpleGraphClassPart simplegraph_class;
-} SimpleGraphClassRec;
-
-extern SimpleGraphClassRec simplegraphClassRec;
-
-
-typedef struct {
- Dimension h_min_space;
- Dimension v_min_space;
- Dimension arrow_length;
- Dimension arrow_angle;
- Boolean arrow_filled;
- int gc_count;
- GC gc[GC_COUNT];
- float cos_arrow;
- float sin_arrow;
- Boolean mode;
- Widget arc_only;
-} SimpleGraphPart;
-
-
-typedef struct _SimpleGraphRec {
- CorePart core;
- CompositePart composite;
- ConstraintPart constraint;
- XmManagerPart manager;
- XmDrawingAreaPart drawing_area;
- SimpleBasePart simplebase;
- SimpleGraphPart simplegraph;
-} SimpleGraphRec;
-
-
-#endif
-
-
-
diff --git a/ecflow_4_0_7/view/src/SimpleTime.c b/ecflow_4_0_7/view/src/SimpleTime.c
deleted file mode 100644
index 618f6fc..0000000
--- a/ecflow_4_0_7/view/src/SimpleTime.c
+++ /dev/null
@@ -1,784 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #4 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include <stdio.h>
-#include <time.h>
-#include <Xm/ScrollBar.h>
-
-#include <X11/Intrinsic.h>
-#include <X11/IntrinsicP.h>
-#include <X11/StringDefs.h>
-#include <X11/CoreP.h>
-#include <X11/CompositeP.h>
-#include <X11/ConstrainP.h>
-#include <Xm/XmP.h>
-#include <Xm/DrawingAP.h>
-#include <Xm/ExtObjectP.h>
-#include "SimpleTime.h"
-#include "SimpleTimeP.h"
-
-#ifndef MAX
-#define MAX(a,b) ((a) > (b) ? (a) : (b))
-#endif
-#ifndef MIN
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-#endif
-
-#define DATE 0
-#define TIME 1
-#define ARC 2
-
-static void Initialize();
-//static void ConstraintInitialize();
-//static Boolean ConstraintSetValues();
-//static void Resize();
-static void Print();
-static void Layout(Widget,long*,long*);
-static void Destroy();
-static Boolean SetValues();
-//static void insert_new_node();
-//static void delete_node();
-//static void new_layout();
-static void Redisplay();
-//static int compute_positions();
-//static void shift_subsimpletime();
-//static void set_positions();
-/* static void reset(); */
-
-void SimpleBaseShow(Widget _w,XRectangle* r,XEvent* ev);
-
-
-static XtResource resources[] = {
- {XtNverticalSpace,XtCSpace, XtRDimension,sizeof (Dimension),
- XtOffset(SimpleTimeWidget, simpletime.v_min_space), XtRImmediate,(XtPointer)8 },
- {XtNpixelSecond,XtCPixelSecond, XtRInt,sizeof (int),
- XtOffset(SimpleTimeWidget, simpletime.second_per_pixel), XtRImmediate,(XtPointer)60 },
- {XtNforeground, XtCForeground, XtRPixel, sizeof (Pixel),
- XtOffset(SimpleTimeWidget, simpletime.foreground), XtRString,"Red"},
- {XtNautoScroll, XtCAutoScroll, XtRBoolean, sizeof (Boolean),
- XtOffset(SimpleTimeWidget, simpletime.auto_scroll), XtRImmediate,(XtPointer)TRUE},
-
- { XmNfontList, XmCFontList, XmRFontList, sizeof (XmFontList),
- XtOffset (SimpleTimeWidget, simpletime.font), XmRString,
- "-*-*-*-*-*-*-7-*-*-*-*-*-*-*"},
-
-
-
-};
-
-
-SimpleTimeClassRec simpletimeClassRec = {
- {
- /* core_class fields */
- (WidgetClass) &simplebaseClassRec,/* superclass */
- "SimpleTime", /* class_name */
- sizeof(SimpleTimeRec), /* widget_size */
- NULL, /* class_init */
- NULL, /* class_part_init */
- FALSE, /* class_inited */
- Initialize, /* initialize */
- NULL, /* initialize_hook */
- XtInheritRealize, /* realize */
- NULL, /* actions */
- 0, /* num_actions */
- resources, /* resources */
- XtNumber(resources), /* num_resources */
- NULLQUARK, /* xrm_class */
- TRUE, /* compress_motion */
- XtExposeCompressMaximal, /* compress_exposure */
- TRUE, /* compress_enterleave*/
- TRUE, /* visible_interest */
- Destroy, /* destroy */
- NULL, /* resize */
- Redisplay, /* expose */
- SetValues, /* set_values */
- NULL, /* set_values_hook */
- XtInheritSetValuesAlmost, /* set_values_almost */
- NULL, /* get_values_hook */
- NULL, /* accept_focus */
- XtVersion, /* version */
- NULL, /* callback_private */
- XtInheritTranslations, /* tm_table */
- NULL, /* query_geometry */
- XtInheritDisplayAccelerator, /* display_accelerator*/
- NULL, /* extension */
- },
- {
- /* simplebase_class fields */
- NULL, /* geometry_manager */
- NULL, /* change_managed */
- XtInheritInsertChild, /* insert_child */
- XtInheritDeleteChild, /* delete_child */
- NULL/*&compext*/, /* extension */
- },
- {
- /* constraint_class fields */
- NULL, /* subresources */
- 0,/* subresource_count */
- 0, /* constraint_size */
- NULL, /* initialize */
- NULL, /* destroy */
- NULL, /* set_values */
- NULL, /* extension */
- },
- {
- XtInheritTranslations, /* default translations */
- NULL, /* syn_resources */
- 0, /* num_syn_resources */
- NULL, /* syn_cont_resources */
- 0, /* num_syn_cont_resources */
- XmInheritParentProcess, /* parent_process */
- NULL, /* extension */
-
- },
- {
- NULL,
- },
- {
- Print,
- Layout,
- },
- {
- /* SimpleTime class fields */
- 0, /* ignore */
- },
-};
-
-
-WidgetClass simpletimeWidgetClass = (WidgetClass) &simpletimeClassRec;
-
-static long time_to_sec(long ddate)
-{
- long hh,mm,ss;
- hh = ddate / 10000; ddate %= 10000;
- mm = ddate / 100; ddate %= 100;
- ss = ddate;
- return hh*60*60 + mm * 60 + ss;
-}
-
-static long sec_to_time(long ddate)
-{
- long hh,mm,ss;
- hh = ddate / (60*60); ddate %= (60*60);
- mm = ddate / 60; ddate %= 60;
- ss = ddate;
- return hh*10000 + mm * 100 + ss;
-}
-
-static long date_to_julian(long ddate)
-{
- long m1,y1,a,b,c,d,j1;
-
- long month,day,year;
-
- year = ddate / 10000;
- ddate %= 10000;
- month = ddate / 100;
- ddate %= 100;
- day = ddate;
-
- if (month > 2)
- {
- m1 = month - 3;
- y1 = year;
- }
- else
- {
- m1 = month + 9;
- y1 = year - 1;
- }
- a = 146097*(y1/100)/4;
- d = y1 % 100;
- b = 1461*d/4;
- c = (153*m1+2)/5+day+1721119;
- j1 = a+b+c;
-
- return(j1);
-}
-
-static long julian_to_date(long jdate)
-{
- long x,y,d,m,e;
- long day,month,year;
-
- x = 4 * jdate - 6884477;
- y = (x / 146097) * 100;
- e = x % 146097;
- d = e / 4;
-
- x = 4 * d + 3;
- y = (x / 1461) + y;
- e = x % 1461;
- d = e / 4 + 1;
-
- x = 5 * d - 3;
- m = x / 153 + 1;
- e = x % 153;
- d = e / 5 + 1;
-
- if( m < 11 )
- month = m + 2;
- else
- month = m - 10;
-
-
- day = d;
- year = y + m / 11;
-
- return year * 10000 + month * 100 + day;
-}
-
-static int x_of(SimpleTimeWidget w,int d,int t)
-{
- double s;
- d = d - w->simpletime.start_date;
- t = t - w->simpletime.start_time;
- s = d * 24.0*60*60 + t;
- return s / w->simpletime.second_per_pixel + 10 + w->simpletime.max_w;
-}
-
-static void time_of(SimpleTimeWidget w,int x,int* d,int* t)
-{
- double s = (x - 10 - w->simpletime.max_w) * w->simpletime.second_per_pixel;
- *d = (s / 24.0/60/60);
- *t = ( s - *d * 24.0*60*60);
- *d = *d + w->simpletime.start_date;
- *t = *t + w->simpletime.start_time;
-}
-
-static void time_out(SimpleTimeWidget w,XtIntervalId id)
-{
- // time_t t = time(0);
- /* struct tm *tt = gmtime(&t); */
-
-
- if(XtIsRealized((Widget)w) && XtIsManaged((Widget)w))
- {
-#if 0
- int n = X(w,w->simpletime.second);
- XClearArea(XtDisplay(w),XtWindow(w),
- n,0,1,w->core.height,TRUE);
-#endif
- }
-
- /* w->simpletime.second = tt->tm_min+tt->tm_hour*60; */
- /* w->simpletime.second = tt->tm_min+tt->tm_hour*60; */
-
- w->simpletime.timeout_id =
- XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)w),
- 60000,
- (XtTimerCallbackProc)time_out,(XtPointer)w);
-
- /* if(w->simpletime.auto_scroll) TimeShowTime((Widget)w,TIME_NOW); */
-}
-
-
-static void Initialize(SimpleTimeWidget request, SimpleTimeWidget new)
-{
- XGCValues values;
- XtGCMask valueMask;
-
- if (request->core.width <= 0)
- new->core.width = 5;
- if (request->core.height <= 0)
- new->core.height = 5;
-
- valueMask = GCForeground | GCBackground;
- values.foreground = new->simpletime.foreground;
- values.background = new->core.background_pixel;
- new->simpletime.gc = XtGetGC((Widget)new, valueMask, &values);
- new->simpletime.start_time = new->simpletime.end_time = 0;
- new->simpletime.start_date = new->simpletime.end_date = 0;
- new->simpletime.inited = 0;
- new->simpletime.arcs = 0;
-
- time_out(new,0);
-
-}
-
-static void Destroy(SimpleTimeWidget w)
-{
- XtReleaseGC((Widget)w, w->simpletime.gc);
- XtRemoveTimeOut(w->simpletime.timeout_id);
-}
-
-
-static Boolean SetValues(SimpleTimeWidget current,SimpleTimeWidget request,
- SimpleTimeWidget new)
-{
- int redraw = FALSE;
-
- /*
- * If the minimum spacing has changed, recalculate the
- * simpletime layout. new_layout() does a redraw, so we don't
- * need SetValues to do another one.
- */
-
- if (new->simpletime.v_min_space != current->simpletime.v_min_space ||
- new->simpletime.second_per_pixel != current->simpletime.second_per_pixel )
- {
- long width,height;
- Layout((Widget)new,&width,&height);
- if(width != new->core.width || height != new->core.height)
- {
- Dimension replyWidth = 0, replyHeight = 0;
-
- XtGeometryResult result = XtMakeResizeRequest((Widget)new,
- width,height,
- &replyWidth, &replyHeight);
-
- if (result == XtGeometryAlmost)
- XtMakeResizeRequest ((Widget)new, replyWidth, replyHeight,
- NULL, NULL);
- }
- redraw = True;
- }
- return (redraw);
-}
-
-
-static void line_in(SimpleTimeWidget w,int x1,int y1,int x2,int y2)
-{
- XDrawLine(XtDisplay(w), XtWindow(w), w->manager.bottom_shadow_GC,
- x1,y1,x2,y2);
- XDrawLine(XtDisplay(w), XtWindow(w), w->manager.top_shadow_GC,
- x1+1,y1+1,x2+1,y2+1);
-}
-
-//static void line_out(SimpleTimeWidget w,int x1,int y1,int x2,int y2)
-//{
-// XDrawLine(XtDisplay(w), XtWindow(w), w->simpletime.gc,
-// x1,y1,x2,y2);
-//}
-
-static void Redisplay (SimpleTimeWidget w, XEvent *event, Region region)
-{
- int i;
- int n;
- int y;
- XEvent ev;
- /* int max = 0; */
-
- int d,t;
- int date = 0;
-
- /*
- * If the SimpleTime widget is visible, visit each managed child.
- */
-
- while(XCheckWindowEvent(XtDisplay(w),XtWindow(w),ExposureMask,&ev))
- XtAddExposureToRegion(&ev,region);
-
- d = w->simpletime.start_date;
- t = w->simpletime.start_time;
-
- t /= 60*60;
- t *= 60*60;
-
- while( d <= w->simpletime.end_date )
- {
- int width;
- n = x_of(w,d,t);
-
- if(n >= w->simpletime.max_w) {
- int hh = sec_to_time(t) / 10000;
- XmString s,z,sdat,stim,sep;
- char dat[80];
- char tim[80];
-
- line_in(w,n,w->simpletime.title,n,w->core.height);
-
- dat[0] = tim[0] = 0;
-
- if(date == 0 || d != date)
- {
- int yy,mm,dd;
- int x = julian_to_date(d);
- yy = x / 10000; x %= 10000;
- mm = x / 100; x %= 100;
- dd = x;
-
- sprintf(dat,"%d-%02d-%02d",yy,mm,dd);
- }
-
- sprintf(tim,"%02dh",hh);
-
- sdat = XmStringCreateSimple(dat);
- stim = XmStringCreateSimple(tim);
- sep = XmStringSeparatorCreate();
-
- z = XmStringConcat(sdat,sep);
- s = XmStringConcat(z,stim);
-
- date = d;
- width = XmStringWidth(w->simpletime.font,s);
-
- XmStringDraw(XtDisplay(w),XtWindow(w),
- w->simpletime.font,
- s,
- w->manager.bottom_shadow_GC,
- n - width / 2,
- 5,
- width,
- XmALIGNMENT_CENTER,
- XmSTRING_DIRECTION_L_TO_R, 0);
-
- XmStringFree(s);
- XmStringFree(z);
- XmStringFree(sdat);
- XmStringFree(stim);
- XmStringFree(sep);
- }
-
- t += 60*60;
- if(t >= 24*60*60)
- {
- d++;
- t -= 24*60*60;
- }
-
- if( d == w->simpletime.end_date && t > w->simpletime.end_time)
- break;
- }
-
- for (i = 0; i < w -> simplebase.count; i++)
- {
-
- NodeStruct *n = w -> simplebase.nodes + i;
- int j;
- if(!n->managed)
- continue;
-
- for (j = 0; j < n->kcnt; j++)
- {
- NodeStruct *c = &KIDS(w,n,j);
-
- if(!c->managed)
- continue;
-
-#if 0
- if(n->kids[j].link_data != -1)
- {
- GC gc = w->simplebase.links[n->kids[j].link_data].gc;
- XDrawLine(XtDisplay(w), XtWindow(w),
- gc,
- n->r.x + n->r.width/2 ,
- n->r.y + n->r.height/2 ,
- c->r.x + c->r.width/2 ,
- c->r.y + c->r.height/2);
- }
-#endif
-
-
- }
-
- }
-
- y = w->simpletime.max_h + w->simpletime.title;
- for (i = 0; i < w ->simpletime.arcs; i++)
- {
- line_in(w,0,y, w->core.width, y);
- y += w->simpletime.max_h;
- }
-
- NodesRedraw((SimpleBaseWidget)w,event,region);
-
-
-}
-
-static void Print(SimpleTimeWidget w,FILE *f)
-{
-}
-
-
-static void calc_arc(SimpleTimeWidget tw,NodeStruct* w,int arc)
-{
- int j;
- if(w->misc[ARC] == -1 && w->managed)
- {
- w->misc[ARC] = arc;
- for (j = 0; j < w->kcnt; j++)
- {
- NodeStruct *c = &KIDS(tw,w,j);
- calc_arc(tw,c,arc);
- }
-
- for (j = 0; j < w->pcnt; j++)
- {
- NodeStruct *c = &PARENTS(tw,w,j);
- calc_arc(tw,c,arc);
- }
-
- }
-}
-
-static void Layout(Widget w,long *maxWidth,long *maxHeight)
-{
- SimpleTimeWidget tw = (SimpleTimeWidget)w;
-// XtGeometryResult result;
-// Dimension replyWidth = 0, replyHeight = 0;
- int i;
-// int nlines = 0;
-// Position *lines;
- int arc = 0;
-
- XmString s = XmStringCreateSimple("0123456789:- ");
- tw->simpletime.title = XmStringHeight(tw->simpletime.font,s)*2 + 10;
- XmStringFree(s);
-
- *maxWidth = *maxHeight = 5;
-
- if(tw->simplebase.count == 0)
- {
- tw->simpletime.inited = 0;
- return;
- }
-
-
- tw->simpletime.max_w = 0;
- tw->simpletime.max_h = 0;
-
- for(i=0;i<tw->simplebase.count;i++)
- {
- NodeStruct *w = tw->simplebase.nodes + i;
- if(!w->managed) continue;
-
- w->misc[ARC] = -1;
- if(w->r.height> tw->simpletime.max_h)
- tw->simpletime.max_h = w->r.height;
-
- if(w->misc[DATE] == 0)
- if(w->r.width > tw->simpletime.max_w)
- tw->simpletime.max_w = w->r.width;
- }
-
- tw->simpletime.max_h += 4;
-
- for(i=0;i<tw->simplebase.count;i++)
- {
- NodeStruct *w = tw->simplebase.nodes + i;
- if(!w->managed) continue;
- if(w->misc[ARC] == -1)
- calc_arc(tw,w,arc++);
- }
-
- tw->simpletime.arcs = arc;
-
- if(tw->simpletime.second_per_pixel<1)
- tw->simpletime.second_per_pixel = 1;
-
- if(1) {
- Widget ww = (Widget)tw;
- Widget clip = 0,scroll = 0;
- while(ww){
- if((clip = XtParent(ww)))
- if((scroll = XtParent(clip))) {
- if(XmIsScrolledWindow(scroll))
- break;
- else
- clip = scroll = 0;
- }
- }
-
- if(clip)
- {
- while(tw->simpletime.second_per_pixel > 1 &&
- x_of(tw,tw->simpletime.end_date,tw->simpletime.end_time) < clip->core.width)
- tw->simpletime.second_per_pixel--;
-
- while(x_of(tw,tw->simpletime.end_date,tw->simpletime.end_time) > clip->core.width)
- tw->simpletime.second_per_pixel++;
- }
- }
-
- while(x_of(tw,tw->simpletime.end_date,tw->simpletime.end_time) > 64000)
- {
-#if 0
- printf("Scaling too large... %d %d %d %d\n",
- tw->simpletime.second_per_pixel,
- tw->simpletime.end_date,tw->simpletime.end_time,
- x_of(tw,tw->simpletime.end_date,tw->simpletime.end_time)
-
- );
-#endif
- tw->simpletime.second_per_pixel++;
- }
-
- for(i=0;i<tw->simplebase.count;i++)
- {
- NodeStruct *w = tw->simplebase.nodes + i;
- if(!w->managed) continue;
-
-
- if(w->misc[DATE] == 0)
- w->r.x = 0;
- else
- w->r.x = x_of(tw,w->misc[DATE],w->misc[TIME]) - w->r.width/2;
-
- w->r.y = tw->simpletime.title +
- w->misc[ARC] * tw->simpletime.max_h +
- (tw->simpletime.max_h - w->r.height)/2;
-
- if(*maxWidth < w->r.x + w->r.width)
- *maxWidth = w->r.x + w->r.width;
-
- if(*maxHeight < w->r.y + w->r.height)
- *maxHeight = w->r.y + w->r.height;
- }
-
-}
-
-
-void TimeSetTime(Widget _w,int n,DateTime dt)
-{
- SimpleTimeWidget tw = (SimpleTimeWidget)_w;
- NodeStruct *w = tw->simplebase.nodes + n;
-
- w->misc[DATE] = date_to_julian(dt.date);
- w->misc[TIME] = time_to_sec(dt.time);
-
- if(!tw->simpletime.inited)
- {
- tw->simpletime.start_date = tw->simpletime.end_date = w->misc[DATE];
- tw->simpletime.start_time = tw->simpletime.end_time = w->misc[TIME];
- tw->simpletime.inited = 1;
- }
-
- if(w->misc[DATE] < tw->simpletime.start_date ||
- ( w->misc[DATE] == tw->simpletime.start_date &&
- w->misc[TIME] < tw->simpletime.start_time))
- {
- tw->simpletime.start_date = w->misc[DATE];
- tw->simpletime.start_time = w->misc[TIME];
- }
-
- if(w->misc[DATE] > tw->simpletime.end_date ||
- ( w->misc[DATE] == tw->simpletime.end_date &&
- w->misc[TIME] > tw->simpletime.end_time))
- {
- tw->simpletime.end_date = w->misc[DATE];
- tw->simpletime.end_time = w->misc[TIME];
- }
-
-#if 0
- printf("TimeSetTime %d %d %d %d\n",
- w->misc[DATE],w->misc[TIME],
- tw->simpletime.end_date, tw->simpletime.end_time
-
- );
-#endif
-}
-
-DateTime TimeGetTime(Widget _w,int n)
-{
- SimpleTimeWidget tw = (SimpleTimeWidget)_w;
- NodeStruct *w = tw->simplebase.nodes + n;
- DateTime dt;
-
- dt.date = julian_to_date(w->misc[DATE]);
- dt.time = sec_to_time(w->misc[TIME]);
-
- return dt;
-}
-
-void TimeAdd(DateTime* dt,int n)
-{
- int dd = date_to_julian(dt->date);
- int tt = time_to_sec(dt->time);
-
- tt += n;
- while(tt < 0) {
- dd++;
- tt += 24*60*60;
- }
-
- while(tt >= 24*60*60)
- {
- dd--;
- tt -= 24*60*60;
- }
-
- /* printf("TimeAdd: %d %d\n",*d,*t); */
-
- dt->date = julian_to_date(dd);
- dt->time = sec_to_time(tt);
- /* printf("TimeAdd: %d %d\n",*d,*t); */
-}
-
-Widget CreateTime(Widget par,char *nam,ArgList al,int ac)
-{
- return XtCreateWidget(nam,simpletimeWidgetClass,par,al, ac);
-}
-
-/*
- Make the simpletime _second_ visible
- If _second_ is equal to TIME_NOW show the current simpletime
-*/
-
-void TimeShowTime(Widget _w,DateTime dt,XEvent* ev)
-{
- SimpleTimeWidget h = (SimpleTimeWidget)_w;
- XRectangle r;
-
-
- int d = date_to_julian(dt.date);
- int t = time_to_sec(dt.time);
-
- r.x = x_of(h,d,t);
- r.y = ev?ev->xbutton.y:0;
- r.width = 1;
- r.height = 1;
-
- SimpleBaseShow(_w,&r,ev);
-}
-
-void TimeEventTime(Widget _w,XEvent* e,DateTime *dt)
-{
- int x = e->xbutton.x;
- int d,t;
- time_of((SimpleTimeWidget)_w,x,&d,&t);
- dt->date = julian_to_date(d);
- dt->time = sec_to_time(t);
-}
-
-int TimeDiff(DateTime dt1,DateTime dt2)
-{
- long long x1,x2;
- int d1 = date_to_julian(dt1.date);
- int d2 = date_to_julian(dt2.date);
- int t1 = time_to_sec(dt1.time);
- int t2 = time_to_sec(dt2.time);
-
- x1 = d1 * 24 * 60 * 60 + t1;
- x2 = d2 * 24 * 60 * 60 + t2;
-
- return x1 - x2;
-}
-
-void *TimeFindByY(Widget _w,XEvent *ev)
-{
- SimpleBaseWidget w = (SimpleBaseWidget)_w;
- int i;
- for(i = 0; i < w->simplebase.count;i++)
- {
- NodeStruct *n = w->simplebase.nodes + i;
- if(n->managed)
- if(
- /* ev->xbutton.x >= n->r.x && ev->xbutton.x <= n->r.x + n->r.width && */
- ev->xbutton.y >= n->r.y && ev->xbutton.y <= n->r.y + n->r.height)
- return n->user_data;
- }
- return NULL;
-}
diff --git a/ecflow_4_0_7/view/src/SimpleTime.h b/ecflow_4_0_7/view/src/SimpleTime.h
deleted file mode 100644
index dfe33e4..0000000
--- a/ecflow_4_0_7/view/src/SimpleTime.h
+++ /dev/null
@@ -1,76 +0,0 @@
-#ifndef SIMPLETIME_H
-#define SIMPLETIME_H
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #4 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "SimpleBase.h"
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
-extern WidgetClass simpletimeWidgetClass;
-
-typedef struct _SimpleTimeClassRec *SimpleTimeWidgetClass;
-typedef struct _SimpleTimeRec *SimpleTimeWidget;
-
-/* constraint resources */
-
-#define XtNstartSimpleTime "startSimpleTime"
-#define XtNendSimpleTime "endSimpleTime"
-#define XtCSimpleTime "SimpleTime"
-
-
-/* Tieme widget resources */
-
-/* Pixel between rows of widgets */
-
-#define XtNverticalSpace "verticalSpace"
-
-/* Scale factor */
-
-#define XtNpixelSecond "pixelSecond"
-#define XtCPixelSecond "PixelSecond"
-
-/* always make current simpletime visible */
-
-#define XtNautoScroll "autoScroll"
-#define XtCAutoScroll "AutoScroll"
-
-extern Widget CreateTime(Widget,char*,Arg*,int);
-
-#define TIME_NOW (-1) /* Used in SimpleTimeShowSimpleTime */
-
-
-typedef struct DateTime {
- int date;
- int time;
-} DateTime ;
-
-void TimeSetTime(Widget,int,DateTime);
-DateTime TimeGetTime(Widget,int);
-void TimeAdd(DateTime*,int);
-int TimeDiff(DateTime,DateTime);
-
-void* TimeFindByY(Widget,XEvent*);
-
-void TimeEventTime(Widget,XEvent*,DateTime*);
-void TimeShowTime(Widget,DateTime,XEvent*);
-void TimeRange(Widget,DateTime*,DateTime*);
-
-#if defined(__cplusplus) || defined(c_plusplus)
-}
-#endif
-#endif
diff --git a/ecflow_4_0_7/view/src/SimpleTimeP.h b/ecflow_4_0_7/view/src/SimpleTimeP.h
deleted file mode 100644
index 9cac613..0000000
--- a/ecflow_4_0_7/view/src/SimpleTimeP.h
+++ /dev/null
@@ -1,74 +0,0 @@
-#ifndef SIMPLETIMEP_H
-#define SIMPLETIMEP_H
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #4 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-
-#include "SimpleBaseP.h"
-#include <Xm/DrawingAP.h>
-
-
-typedef struct _SimpleTimeClassPart {
- int ignore;
-} SimpleTimeClassPart;
-
-typedef struct _SimpleTimeClassRec {
- CoreClassPart core_class;
- CompositeClassPart composite_class;
- ConstraintClassPart constraint_class;
- XmManagerClassPart manager_class;
- XmDrawingAreaClassPart drawing_area_class;
- SimpleBaseClassPart simplebase_class;
- SimpleTimeClassPart simpletime_class;
-} SimpleTimeClassRec;
-
-extern SimpleTimeClassRec simpletimeClassRec;
-
-typedef struct {
- Pixel foreground; /* Color of time line */
- Dimension v_min_space; /* Distance between rows */
- int second_per_pixel;/* Scale factor */
- int minute; /* Current time */
- Boolean auto_scroll; /* Allays show current time line */
- XtIntervalId timeout_id; /* Time out id */
- GC gc; /* Gc for time line */
- int start_date;
- int end_date;
- int start_time;
- int end_time;
- int arcs;
- int inited;
- int max_w;
- int max_h;
- int title;
- XmFontList font;
-} SimpleTimePart;
-
-
-typedef struct _SimpleTimeRec {
- CorePart core;
- CompositePart composite;
- ConstraintPart constraint;
- XmManagerPart manager;
- XmDrawingAreaPart drawing_area;
- SimpleBasePart simplebase;
- SimpleTimePart simpletime;
-} SimpleTimeRec;
-
-
-#endif
-
-
-
diff --git a/ecflow_4_0_7/view/src/SimpleTree.c b/ecflow_4_0_7/view/src/SimpleTree.c
deleted file mode 100644
index 7c571b6..0000000
--- a/ecflow_4_0_7/view/src/SimpleTree.c
+++ /dev/null
@@ -1,656 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #5 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include <stdio.h>
-
-#include <X11/Intrinsic.h>
-#include <X11/IntrinsicP.h>
-#include <X11/StringDefs.h>
-#include <X11/CoreP.h>
-#include <X11/CompositeP.h>
-#include <X11/ConstrainP.h>
-#include <Xm/XmP.h>
-#include <Xm/DrawingAP.h>
-#include <Xm/ExtObjectP.h>
-#include "SimpleTree.h"
-#include "SimpleTreeP.h"
-
-#include <Xm/ScrollBar.h>
-#include <stdlib.h>
-
-#ifndef MAX
-#define MAX(a,b) ((a) > (b) ? (a) : (b))
-#endif
-#ifndef MIN
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-#endif
-
-#define LAYOUT 0
-
-static void Initialize();
-/*static void ConstraintInitialize();
- static Boolean ConstraintSetValues();*/
-static void Destroy();
-static void Print();
-static Boolean SetValues();
-/*static XtGeometryResult GeometryManager();
-static void ChangeManaged();
-static void insert_new_node();
-static void delete_node();*/
-static void Layout(Widget,long*,long*);
-static void Redisplay();
-static void compute_rect(SimpleTreeWidget,NodeStruct*,int,int,int,int,int,XRectangle*);
-static void set_positions(SimpleTreeWidget,long*,long*);
-/* static void change_vertical(SimpleTreeWidget tw, NodeStruct *w,Boolean v); ??? */
-#ifdef linux
-/* putting this into comments makes ctrl-left button for collector
- disappear !! */
-static char defaultTranslations[] = "\
- Shift<Btn5Down>: increment(1)\n Shift<Btn4Down>: increment(-1) \n\
- <Btn5Down>: increment(10)\n <Btn4Down>: increment(-10) \n\
-<BtnDown>:DrawingAreaInput()\n\
-<BtnUp>:DrawingAreaInput()\n\
-<Key>osfActivate:DrawingAreaInput()\n\
-~s ~m ~a <Key>Return:DrawingAreaInput()\n\
-~s ~m ~a <Key>space:DrawingAreaInput()\n\
-<Key>F1:DrawingAreaInput()\n\
-<Key>F2:DrawingAreaInput()\n";
-#else
-
-#define defaultTranslations XmInheritTranslations
-
-#endif
-
-static XtResource resources[] = {
- {XtNhorizontalSpace,XtCSpace,XtRDimension,sizeof(Dimension),
- XtOffset(SimpleTreeWidget, simpletree.h_min_space), XtRString,"6" },
- {XtNverticalSpace,XtCSpace, XtRDimension,sizeof (Dimension),
- XtOffset(SimpleTreeWidget, simpletree.v_min_space), XtRString,"2" },
-
-};
-
-// https://software.ecmwf.int/issues/browse/SUP-646
-static void xincrement();
-static XtActionsRec actionsList[] = {
- { "increment",(XtActionProc) xincrement},
-}; //
-
-SimpleTreeClassRec simpletreeClassRec = {
- {
- /* core_class fields */
- (WidgetClass) &simplebaseClassRec,/* superclass */
- "SimpleTree", /* class_name */
- sizeof(SimpleTreeRec), /* widget_size */
- NULL, /* class_init */
- NULL, /* class_part_init */
- FALSE, /* class_inited */
- Initialize, /* initialize */
- NULL, /* initialize_hook */
- XtInheritRealize, /* realize */
- actionsList, /*NULL, actions */
- XtNumber(actionsList), /* num_actions */
- resources, /* resources */
- XtNumber(resources), /* num_resources */
- NULLQUARK, /* xrm_class */
- TRUE, /* compress_motion */
- /* XtExposeCompressMaximal, */
- True,
- /* compress_exposure */
- TRUE, /* compress_enterleave*/
- TRUE, /* visible_interest */
- Destroy, /* destroy */
- NULL, /* resize */
- Redisplay, /* expose */
- SetValues, /* set_values */
- NULL, /* set_values_hook */
- XtInheritSetValuesAlmost, /* set_values_almost */
- NULL, /* get_values_hook */
- NULL, /* accept_focus */
- XtVersion, /* version */
- NULL, /* callback_private */
- defaultTranslations, /* tm_table */
- /* XtInheritTranslations, tm_table */
- NULL, /* query_geometry */
- XtInheritDisplayAccelerator, /* display_accelerator*/
- NULL, /* extension */
- },
- {
- /* composite_class fields */
- NULL, /* geometry_manager */
- NULL, /* change_managed */
- XtInheritInsertChild, /* insert_child */
- XtInheritDeleteChild, /* delete_child */
- NULL/*&compext*/, /* extension */
- },
- {
- /* constraint_class fields */
- NULL, /* subresources */
- 0,/* subresource_count */
- 0, /* constraint_size */
- NULL, /* initialize */
- NULL, /* destroy */
- NULL, /* set_values */
- NULL, /* extension */
- },
- {
- XtInheritTranslations, /* default translations */
- NULL, /* syn_resources */
- 0, /* num_syn_resources */
- NULL, /* syn_cont_resources */
- 0, /* num_syn_cont_resources */
- XmInheritParentProcess, /* parent_process */
- NULL, /* extension */
-
- },
- {
- NULL,
- },
- {
- Print,
- Layout,
- },
- {
- /* SimpleTree class fields */
- 0, /* ignore */
- },
-};
-
-
-WidgetClass simpletreeWidgetClass = (WidgetClass) &simpletreeClassRec;
-
-static void Initialize(SimpleTreeWidget request, SimpleTreeWidget new)
-{
- if (request->core.width <= 0)
- new->core.width = 5;
- if (request->core.height <= 0)
- new->core.height = 5;
-
-}
-
-static void Destroy(SimpleTreeWidget w)
-{
-}
-
-
-static Boolean SetValues(SimpleTreeWidget current,
-SimpleTreeWidget request, SimpleTreeWidget new)
-{
- int redraw = FALSE;
- long w = 0;
- long h = 0;
-
- if (new->simpletree.v_min_space != current->simpletree.v_min_space ||
- new->simpletree.h_min_space != current->simpletree.h_min_space){
- Layout((Widget)new,&w,&h);
- redraw = True;
- }
-
- /* printf("Redraw tree %d\n",redraw); */
-
- return (redraw);
-}
-
-
-static int first_kid(SimpleTreeWidget w,NodeStruct *n)
-{
- int i;
- for(i=0;i<n->kcnt;i++)
- if(KIDS(w,n,i).managed)
- return i;
- return -1;
-}
-
-static int last_kid(SimpleTreeWidget w,NodeStruct *n)
-{
- int i;
-
- if(n->kcnt)
- for(i= n->kcnt - 1;i>=0;i--)
- if(KIDS(w,n,i).managed)
- return i;
- return -1;
-}
-
-static void line(SimpleTreeWidget w,int x1,int y1,int x2,int y2,Region region )
-{
- int width = x2>x1 ? x2-x1+2 : x1-x2+2;
- int height = y2>y1 ? y2-y1+2 : y1-y2+2;
- int x = x2>x1 ? x1 : x2;
- int y = y2>y1 ? y1 : y2;
-
- if(XRectInRegion(region,x,y,width,height))
- {
-
- XDrawLine(XtDisplay(w), XtWindow(w), w->manager.bottom_shadow_GC,
- x1,y1,x2,y2);
-
- XDrawLine(XtDisplay(w), XtWindow(w), w->manager.top_shadow_GC,
- x1+1,y1+1,x2+1,y2+1);
- }
-}
-
-static void Redisplay (SimpleTreeWidget w, XEvent *event, Region region)
-{
- int i, j;
- int fkid;
- int lkid;
-
-#if 0
- NodeStruct *child;
- XEvent ev;
- XmRegion r = (XmRegion)region;
-
- printf("Before: %p\n",r);
- if(r)
- for(i=0;i<r->numRects;i++)
- {
- XmRegionBox* x = &r->rects[i];
- printf(" %d-%d %d-%d\n", x->x1,x->x2,x->y1,x->y2);
- }
-
- while(XCheckWindowEvent(XtDisplay(w),XtWindow(w),ExposureMask,&ev))
- XtAddExposureToRegion(&ev,region);
-
- printf("After:\n");
- if(r)
- for(i=0;i<r->numRects;i++)
- {
- XmRegionBox* x = &r->rects[i];
- printf(" %d %d %d %d\n", x->x1,x->y1,x->x2,x->y2);
- }
-#endif
-
-
- for (i = 0; i < w -> simplebase.count; i++)
- {
- NodeStruct *child = w -> simplebase.nodes + i;
-
- fkid = first_kid(w,child);
-
- if(!child->misc[LAYOUT]) /* Vertical layout */
- {
-
- if(fkid>=0)
- {
- line(w,
- child->r.x + child->r.width,
- child->r.y + child->r.height / 2,
- KIDS(w,child,fkid).r.x,
- child->r.y + child->r.height / 2
- /* KIDS(w,child,fkid).r.y + */
- /* KIDS(w,child,fkid).r.height/2 */
- ,region);
-
- lkid = last_kid(w,child);
-
- if(lkid != fkid)
- {
- int x = child->r.x + child->r.width +
- (KIDS(w,child,fkid).r.x - (child->r.x + child->r.width)) / 2;
-
- line(w,
- x,
- child->r.y + child->r.height / 2,
- x,
- KIDS(w,child,lkid).r.y +
- KIDS(w,child,lkid).r.height/2,region);
-
- for (j = fkid + 1 ; j < child->kcnt; j++)
- if (KIDS(w,child,j).managed)
- {
-
- line(
- w,
- x,
- KIDS(w,child,j).r.y +
- KIDS(w,child,j).r.height/2,
- KIDS(w,child,j).r.x,
- KIDS(w,child,j).r.y +
- KIDS(w,child,j).r.height/2,region);
-
- }
- }
- }
- }
- else
- {
- fkid = first_kid(w,child);
-
- if(fkid>=0 )
- {
- lkid = last_kid(w,child);
-
- line(w,
- KIDS(w,child,fkid).r.x + KIDS(w,child,fkid).r.width/2,
- child->r.y + child->r.height + w->simpletree.v_min_space/2,
- KIDS(w,child,lkid).r.x + KIDS(w,child,lkid).r.width/2,
- child->r.y + child->r.height + w->simpletree.v_min_space/2,region);
-
- line(
- w,
- KIDS(w,child,fkid).r.x + KIDS(w,child,fkid).r.width/2,
- child->r.y + child->r.height,
- KIDS(w,child,fkid).r.x + KIDS(w,child,fkid).r.width/2,
- KIDS(w,child,fkid).r.y,region);
-
- for (j = fkid + 1; j < child->kcnt; j++)
- if (KIDS(w,child,j).managed)
- {
-
- line(
- w,
- KIDS(w,child,j).r.x + KIDS(w,child,j).r.width/2,
- child->r.y + child->r.height + w->simpletree.v_min_space/2,
- KIDS(w,child,j).r.x + KIDS(w,child,j).r.width/2,
- KIDS(w,child,j).r.y,region);
- }
- }
-
- }
-
- }
-
- NodesRedraw((SimpleBaseWidget)w,event,region);
-}
-
-
-
-static void Layout(Widget w,long *maxWidth,long *maxHeight)
-{
- SimpleTreeWidget tw = (SimpleTreeWidget)w;
- int high = (int)tw->simpletree.v_min_space;
- int i,n;
- int h_max = 0,w_max = 0, dh;
-
- *maxWidth = *maxHeight = 5;
-
- h_max = high;
-
- for(i=0;i<tw->simplebase.count;i++)
- {
- NodeStruct *w = tw->simplebase.nodes + i;
- h_max = MAX(h_max,w->r.height); /* just a try */
- w_max = MAX(w_max,w->r.width);
- }
-
- dh = h_max / 2;
-
- h_max += tw->simpletree.v_min_space;
- w_max += tw->simpletree.h_min_space;
-
- for(n=0;n<tw->simplebase.count;n++)
- {
- for(i=0;i<tw->simplebase.count;i++)
- {
- NodeStruct *w = tw->simplebase.nodes + i;
- if(w->managed && (w->pcnt == 0))
- {
- XRectangle r;
- compute_rect(tw,w,
- (int)tw->simpletree.h_min_space,
- (int)tw->simpletree.h_min_space,
- w->r.width,
- w->r.height,
- w->r.height,
- &r);
- }
- }
-
- set_positions(tw,maxWidth,maxHeight);
-#if 0
- if(*maxWidth == 0 || *maxHeight == 0)
- {
- Boolean v = (*maxWidth == 0);
- for(i=0;i<tw->simplebase.count;i++)
- {
- NodeStruct *w = tw->simplebase.nodes + i;
- if(w->managed && (w->pcnt == 0))
- change_vertical(tw,w,!v);
- }
-
- }
- else
-#endif
- break;
- }
-}
-
-#if 0
-static void change_vertical(SimpleTreeWidget tw, NodeStruct *w,Boolean v)
-{
- int i;
- if(w->misc[LAYOUT] != v )
- w->misc[LAYOUT] = v;
- else
- {
- for(i = 0; i < w->kcnt ; i++)
- if(KIDS(tw,w,i).managed)
- change_vertical(tw,&KIDS(tw,w,i),v);
- }
-}
-#endif
-
-static void union_rect(XRectangle *r1,XRectangle *r2,XRectangle *r3)
-{
- int dx,dy;
-
- dx = MAX(r1->x+r1->width,r2->x+r2->width);
- dy = MAX(r1->y+r1->height,r2->y+r2->height);
- r3->x = MIN(r1->x,r2->x);
- r3->y = MIN(r1->y,r2->y);
-
- r3->width = dx - r3->x;
- r3->height = dy - r3->y;
-
-}
-
-
-static void compute_rect(SimpleTreeWidget tw,NodeStruct *w,
- int x,int y,int dx,int dy,int h,XRectangle *rect)
-{
- int i;
- int mx = 0;
- int my = 0;
-
- *rect = w->r;
- rect->x = w->tmpx = x;
- rect->y = w->tmpy = y; /* + (h - w->r.height) / 2; */
- rect->width += tw->simpletree.h_min_space;
- rect->height += tw->simpletree.v_min_space;
-
- if(h > w->r.height)
- rect->y = w->tmpy = y + (h - w->r.height) / 2;
-
- for(i = 0; i < w->kcnt; i++)
- {
- NodeStruct *z = &KIDS(tw,w,i);
- if(z->managed)
- {
- if(z->kcnt) /* && !w->misc[LAYOUT]) */
- mx = MAX(mx,z->r.width);
- my = MAX(my,z->r.height);
- }
- }
-
- for(i = 0; i < w->kcnt; i++)
- {
- NodeStruct *z = &KIDS(tw,w,i);
- if(z->managed)
- {
- XRectangle r;
- if(!w->misc[LAYOUT])
- {
- compute_rect(tw,z,x + dx + tw->simpletree.h_min_space ,
- y, mx, my, w->r.height,&r);
- union_rect(rect,&r,rect);
- y += r.height;
-
- if(y > 60000)
- {
- y = w->tmpy;
- x += r.width;
- }
- }
- else
- {
- compute_rect(tw,z,x,y + dy
- + tw->simpletree.v_min_space, mx, my, w->r.height,
- &r);
- union_rect(rect,&r,rect);
- x += r.width;
- }
- }
- }
-
-}
-
-
-static void set_positions(SimpleTreeWidget tw,long *maxWidth, long *maxHeight)
-{
- int i;
-
- for(i=0;i<tw->simplebase.count;i++)
- {
- NodeStruct *w = tw->simplebase.nodes + i;
-
- if(w->managed)
- {
-#if 0
- if(w->tmpx != (Position)w->tmpx)
- {
- *maxWidth = 0;
- return;
- }
-
- if(w->tmpy != (Position)w->tmpy)
- {
- *maxHeight = 0;
- return;
- }
-#endif
-
-
-#if 0
- w->r.x = w->tmpx % 64000 + (w->tmpy / 64000) * (w->r.width + 20);
- w->r.y = w->tmpy % 64000 + (w->tmpx / 64000) * (w->r.height + 20);
-#endif
-
- w->r.x = w->tmpx;
- w->r.y = w->tmpy;
-
- *maxWidth = MAX(*maxWidth,
- w->r.x + w->r.width + tw->simpletree.h_min_space);
- *maxHeight = MAX(*maxHeight,
- w->r.y + w->r.height + tw->simpletree.v_min_space);
- }
- }
-}
-
-void NodeTreeFlip(Widget _w,int node)
-{
- SimpleTreeWidget w = (SimpleTreeWidget)_w;
- NodeStruct *p = w->simplebase.nodes + node;
- if( node < 0 || node >= w->simplebase.count) return;
- p->misc[LAYOUT] = !p->misc[LAYOUT];
- NodeNewSize(_w,node);
-}
-
-Widget CreateTree(Widget par,char *nam,ArgList al,int ac)
-{
- return XtCreateWidget(nam,simpletreeWidgetClass,par,al, ac);
-}
-
-static void Print (SimpleTreeWidget w, FILE *f)
-{
-}
-
-static void xincrement (h, event, args, n_args)
-Widget h;
-XEvent *event;
-char *args[];
-int n_args;
-{
-#ifdef MOTIF
-#define SetArg(a,b) XtSetArg(al[ac],a,b);ac++
-#define GetValues(w) XtGetValues(w,al,ac);ac=0
-#define SetValues(w) XtSetValues(w,al,ac);ac=0
-
- Widget clip = XtParent(h);
- Widget swin;
- Widget v_scroll;
-
- int ac = 0, arg;
- Position x_parent,y_parent, dh=0, dv=0;
- Arg al[5];
-
- if(!clip) return;
- swin = XtParent(clip);
-
- if(!(swin = XtParent(swin))) return;
- while (swin && !XmIsScrolledWindow(swin)) {
- swin = XtParent(swin);
- }
-
- /* printf("# SimpleTree swin %s\n",XtName(swin)); */
- /* while (clip) { */
- /* printf("# SimpleTree clip %s\n",XtName(clip)); */
- /* clip = XtParent(clip); */
- /* } */
- if(!swin) return;
- {
- int min, max, value, slider_size, inc, page_inc;
- ac = 0;
- XtSetArg(al[ac],XmNverticalScrollBar, &v_scroll );ac++;
- XtGetValues(swin,al,ac);
-
- ac = 0;
- XtSetArg(al[ac], XmNminimum,&min); ac++;
- XtSetArg(al[ac], XmNmaximum,&max); ac++;
- XtGetValues(v_scroll, al, ac);
- XmScrollBarGetValues(v_scroll,&value,&slider_size,&inc,&page_inc);
-
- ac = 0;
- XtSetArg(al[ac],XmNx,&x_parent);ac++;
- XtSetArg(al[ac],XmNy,&y_parent);ac++;
- XtGetValues(swin,al,ac);
-
- arg = atoi(args[0]);
- dh = (abs(arg) > 5) ? page_inc : inc;
-
- if (arg < 0) {
- if (value - dh < min)
- value = min;
- else
- value -= dh;
- } else {
- if (value + dh > max)
- value = max;
- else
- value += dh;
- }
-
- {
- Position x = x_parent-dh;
- Position y = y_parent-dv;
-
- ac = 0;
- XtSetArg(al[ac],XmNx,x);ac++;
- XtSetArg(al[ac],XmNy,y);ac++;
- XtSetValues(swin,al,ac);
- XmScrollBarSetValues(v_scroll,value,slider_size, inc, page_inc,TRUE);
- }
- }
-#endif
-}
diff --git a/ecflow_4_0_7/view/src/SimpleTree.h b/ecflow_4_0_7/view/src/SimpleTree.h
deleted file mode 100644
index 0797a2b..0000000
--- a/ecflow_4_0_7/view/src/SimpleTree.h
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef SIMPLETREE_H
-#define SIMPLETREE_H
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #4 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-#ifndef MOTIF
-#define MOTIF
-#endif
-
-#include "SimpleBase.h"
-
-extern WidgetClass simpletreeWidgetClass;
-
-typedef struct _SimpleTreeClassRec *SimpleTreeWidgetClass;
-typedef struct _SimpleTreeRec *SimpleTreeWidget;
-
-#define XtNhorizontalSpace "horizontalSpace"
-#define XtNverticalSpace "verticalSpace"
-#define XtNparentNode "parentNode"
-#define XtCParentNode "ParentNode"
-#define XtNselected "selected"
-#define XtCSelected "Selected"
-#define XtNvertical "vertical"
-#define XtCVertical "Vertical"
-
-extern Widget CreateTree(Widget,char*,Arg*,int);
-extern void NodeTreeFlip(Widget,int);
-
-#if defined(__cplusplus) || defined(c_plusplus)
-}
-#endif
-
-#endif
diff --git a/ecflow_4_0_7/view/src/SimpleTreeP.h b/ecflow_4_0_7/view/src/SimpleTreeP.h
deleted file mode 100644
index 50325b2..0000000
--- a/ecflow_4_0_7/view/src/SimpleTreeP.h
+++ /dev/null
@@ -1,60 +0,0 @@
-#ifndef SIMPLETREEP_H
-#define SIMPLETREEP_H
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #4 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-
-#include "SimpleBaseP.h"
-#include <Xm/DrawingAP.h>
-
-
-typedef struct _SimpleTreeClassPart {
- int ignore;
-} SimpleTreeClassPart;
-
-typedef struct _SimpleTreeClassRec {
- CoreClassPart core_class;
- CompositeClassPart composite_class;
- ConstraintClassPart constraint_class;
- XmManagerClassPart manager_class;
- XmDrawingAreaClassPart drawing_area_class;
- SimpleBaseClassPart simplebase_class;
- SimpleTreeClassPart simpletree_class;
-} SimpleTreeClassRec;
-
-extern SimpleTreeClassRec simpletreeClassRec;
-
-typedef struct {
- Dimension h_min_space;
- Dimension v_min_space;
-} SimpleTreePart;
-
-
-typedef struct _SimpleTreeRec {
- CorePart core;
- CompositePart composite;
- ConstraintPart constraint;
- XmManagerPart manager;
- XmDrawingAreaPart drawing_area;
- SimpleBasePart simplebase;
- SimpleTreePart simpletree;
-} SimpleTreeRec;
-
-
-
-#endif
-
-
-
diff --git a/ecflow_4_0_7/view/src/Tab.c b/ecflow_4_0_7/view/src/Tab.c
deleted file mode 100644
index e53a720..0000000
--- a/ecflow_4_0_7/view/src/Tab.c
+++ /dev/null
@@ -1,784 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #6 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include <stdio.h>
-#include <math.h>
-
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
-#define RADIANS(x) (M_PI * (x) / 180.0)
-#define ROUND(X) (((X) >= 0) ? (int)((X)+0.5) : (int)((X)-0.5))
-
-
-#include <X11/Intrinsic.h>
-#include <X11/IntrinsicP.h>
-#include <X11/StringDefs.h>
-#include <X11/CoreP.h>
-#include <X11/CompositeP.h>
-#include <X11/ConstrainP.h>
-#include <Xm/XmP.h>
-#include <Xm/DrawingAP.h>
-#include "Tab.h"
-#include "TabP.h"
-
-#ifndef MAX
-#define MAX(a,b) ((a) > (b) ? (a) : (b))
-#endif
-#ifndef MIN
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-#endif
-
-static void Initialize();
-static void Resize();
-static void Destroy();
-static void ReDisplay();
-static void Click();
-static Boolean SetValues();
-static XtGeometryResult GeometryManager();
-static void ChangeManaged();
-static void new_layout(TabWidget,Boolean);
-
-static XtResource resources[] = {
- {XmNvalueChangedCallback,XmCValueChangedCallback,XtRCallback,
- sizeof(XtPointer), XtOffset(TabWidget,tab.cb), XtRCallback,
- NULL },
-
- {XmNopenCallback,XmCValueChangedCallback,XtRCallback,
- sizeof(XtPointer), XtOffset(TabWidget,tab.open_cb), XtRCallback,
- NULL },
-
- {XmNcloseCallback,XmCValueChangedCallback,XtRCallback,
- sizeof(XtPointer), XtOffset(TabWidget,tab.close_cb), XtRCallback,
- NULL },
-
- {XmNfontList,XmCFontList,XmRFontList,sizeof(XmRFontList),
- XtOffset(TabWidget,tab.font),XmRString,(XtPointer)"fixed" },
-
- { "Back", "back", XmRPixel,sizeof(Pixel),
- XtOffset(TabWidget,tab.back),XmRString,"#bcbcbcbcbcbc"},
-
- { "Blue", "blue", XmRPixel,sizeof(Pixel),
- XtOffset(TabWidget,tab.blue),XmRString,"blue"},
-
- { "drawer", "Drawer", XmRBoolean,sizeof(Boolean),
- XtOffset(TabWidget,tab.drawer),XmRString,"false"},
-};
-
-
-static XtActionsRec actions[] = {
- {"Click",Click}
-};
-
-
-static char translations[] =
-"<Btn1Down>: Click()";
-
-#define USE_MANAGER
-
-TabClassRec tabClassRec = {
- {
- /* core_class fields */
- (WidgetClass) &xmDrawingAreaClassRec,/* superclass */
- "Tab", /* class_name */
- sizeof(TabRec), /* widget_size */
- NULL, /* class_init */
- NULL, /* class_part_init */
- FALSE, /* class_inited */
- Initialize, /* initialize */
- NULL, /* initialize_hook */
- XtInheritRealize, /* realize */
- actions, /* actions */
- XtNumber(actions), /* num_actions */
- resources, /* resources */
- XtNumber(resources), /* num_resources */
- NULLQUARK, /* xrm_class */
- TRUE, /* compress_motion */
- XtExposeCompressMaximal, /* compress_exposure */
- TRUE, /* compress_enterleave*/
- TRUE, /* visible_interest */
- Destroy, /* destroy */
- Resize, /* resize */
- ReDisplay, /* expose */
- SetValues, /* set_values */
- NULL, /* set_values_hook */
- XtInheritSetValuesAlmost, /* set_values_almost */
- NULL, /* get_values_hook */
- NULL, /* accept_focus */
- XtVersion, /* version */
- NULL, /* callback_private */
- translations, /* tm_table */
- NULL, /* query_geometry */
- XtInheritDisplayAccelerator, /* display_accelerator*/
- NULL, /* extension */
- },
- {
- /* composite_class fields */
- GeometryManager, /* geometry_manager */
- ChangeManaged, /* change_managed */
- XtInheritInsertChild, /* insert_child */
- XtInheritDeleteChild, /* delete_child */
- NULL , /* extension */
- },
- {
- /* constraint_class fields */
- NULL, /* subresources */
- 0, /* subresource_count */
- 0, /* constraint_size */
- NULL, /* initialize */
- NULL, /* destroy */
- NULL, /* set_values */
- NULL, /* extension */
- },
- {
- XtInheritTranslations, /* default translations */
- NULL, /* syn_resources */
- 0, /* num_syn_resources */
- NULL, /* syn_cont_resources */
- 0, /* num_syn_cont_resources */
- XmInheritParentProcess, /* parent_process */
- NULL, /* extension */
-
- },
- {
- NULL,
- },
- {
- /* Tab class fields */
- 0, /* ignore */
- },
-};
-
-static void make_visible(TabWidget tw,Widget w);
-
-WidgetClass tabWidgetClass = (WidgetClass) &tabClassRec;
-
-static void Initialize(TabWidget request, TabWidget new)
-{
-
- XGCValues values;
- XtGCMask valueMask = 0;
-
- XFontStruct *fs = (XFontStruct *) NULL;
-
- /*
- * Make sure the widget's width and height are
- * greater than zero.
- */
- if (request->core.width <= 0)
- new->core.width = 5;
- if (request->core.height <= 0)
- new->core.height = 5;
-
- _XmFontListGetDefaultFont(new->tab.font,&fs);
- if(fs != NULL)
- {
- valueMask |= GCFont;
- values.font = fs->fid;
- }
-
- new->tab.gc = XtGetGC((Widget)new,valueMask,&values);
- new->tab.current = 0;
-
- new->tab.hmargin = 8;
- new->tab.vmargin = 3;
-
- new->tab.top = 2;
- new->tab.bottom = 2;
- new->tab.delta = new->tab.hmargin;
-}
-
-static void Destroy(TabWidget w)
-{
- XtReleaseGC((Widget)w,w->tab.gc);
-}
-
-static void Resize(TabWidget w)
-{
- XmDrawingAreaCallbackStruct cb;
- new_layout(w,False);
- cb.reason = XmCR_RESIZE;
- cb.event = NULL;
- cb.window = XtWindow (w);
- XtCallCallbackList((Widget)w,w->drawing_area.resize_callback, &cb);
- make_visible(w,w->tab.current);
- if(XtIsRealized((Widget)w))
- XClearArea(XtDisplay(w),XtWindow(w),0,0,0,0,True);
-}
-
-static Boolean SetValues(TabWidget current, TabWidget request, TabWidget new)
-{
- new_layout(new,False);
- return (False);
-}
-
-static XtGeometryResult GeometryManager(Widget w,
- XtWidgetGeometry *request,
- XtWidgetGeometry *reply)
-{
- new_layout((TabWidget)XtParent(w),True);
- return XtGeometryYes;
-}
-
-static void ChangeManaged(TabWidget tw)
-{
- new_layout(tw,True);
-}
-
-static char* name_of(Widget w)
-{
- if(XmIsScrolledWindow(w))
- {
- static char name[90];
- strcpy(name,XtName(w));
- name[strlen(name)-2] = 0;
- return name;
- }
- else
- return XtName(w);
-
-}
-
-static void new_layout(TabWidget tw,Boolean geometry)
-{
- /* Dimension w = tw->core.width; */
- /* Dimension h = tw->core.height; */
- int t;
- int i;
-
- Dimension mw = 0;
- Dimension mh = 0;
- Dimension ww = 0;
-
- Dimension width = tw->core.width;
- Dimension height = tw->core.height;
-
- tw->tab.title = 0;
-
-
- for(i=0;i<tw->composite.num_children;i++)
- {
- Widget c = tw->composite.children[i];
- if(XtIsManaged(c))
- {
- char *n = name_of(c);
- XmString s = XmStringCreateSimple(n);
- int h = XmStringHeight(tw->tab.font, s) + 2 * tw->tab.vmargin;
- int w = XmStringWidth(tw->tab.font, s) + 2 * tw->tab.hmargin;
- XmStringFree(s);
-
- ww += w;
-
- mh = MAX(mh,c->core.height);
- mw = MAX(mh,c->core.width);
-
- tw->tab.title = MAX(tw->tab.title,h);
-
- }
- }
-
- if(tw->tab.drawer && !geometry )
- height = tw->tab.title;
- else
- height = tw->tab.title + tw->tab.top + tw->tab.bottom + mh;
-
- width = 2 * tw->tab.hmargin + MAX(ww,mw);
-
- if(geometry)
- if(tw->core.width < width || tw->core.height < height)
- {
- Dimension maxWidth = width, maxHeight = height;
- XtGeometryResult result;
- Dimension replyWidth = 0, replyHeight = 0;
-
- result = XtMakeResizeRequest(
- (Widget)tw,
- maxWidth,
- maxHeight,
- &replyWidth, &replyHeight);
-
- if (result == XtGeometryAlmost)
- XtMakeResizeRequest (
- (Widget)tw,
- replyWidth,
- replyHeight,NULL, NULL);
- }
-
-
- width = tw->core.width;
- t = (tw->tab.title + tw->tab.top + tw->tab.bottom);
- height = tw->core.height - t;
-
- for(i=0;i<tw->composite.num_children;i++)
- {
- Widget c = tw->composite.children[i];
- _XmConfigureObject((Widget)c,0,t,width,height,0);
- }
-
-}
-
-static void draw(TabWidget tw, Widget c,int* x,int* y,int k)
-{
- char *n = name_of(c);
- XmString s = XmStringCreateSimple(n);
- XPoint points[10];
- int count = 4;
- int minx = 0;
- int maxx = 0;
- int xx = 0;
- int i;
-
- int sw = XmStringWidth(tw->tab.font, s);
- int step = sw + 2 * tw->tab.hmargin;
-
- points[0].x = *x - tw->tab.hmargin / 2;
- points[0].y = tw->tab.title + tw->tab.top ;
-
- points[1].x = tw->tab.hmargin ;
- points[1].y = -tw->tab.title;
-
- points[2].x = sw + tw->tab.hmargin;
- points[2].y = 0;
-
- points[3].x = tw->tab.hmargin ;
- points[3].y = tw->tab.title;
-
- if(points[0].x + points[1].x + points[2].x + points[3].x > tw->core.width )
- {
- int ww = 5;
- int xx = points[0].x + points[1].x;
-
- points[2].x = tw->core.width - xx - ww;
- points[2].y = 0;
-
- points[3].x = -ww;
- points[3].y = tw->tab.title / 3;
-
- points[4].x = ww;
- points[4].y = tw->tab.title / 3;
-
- points[5].x = -ww;
- points[5].y = tw->tab.title - 2 * (tw->tab.title / 3);
-
- count = 6;
-
- if(k < tw->tab.last)
- tw->tab.last = k;
-
- if(points[2].x < points[1].x)
- {
- (*x) += step;
- return;
- }
- }
-
- if(points[0].x < 0)
- {
- int ww = 5;
-
- points[0].x = 0;
- points[0].y = tw->tab.title + tw->tab.top ;
-
- points[1].x = ww;
- points[1].y = -tw->tab.title / 3;
-
- points[2].x = -ww;
- points[2].y = -tw->tab.title / 3;
-
- points[3].x = ww;
- points[3].y = -tw->tab.title + 2 * (tw->tab.title / 3);
-
- points[4].x = *x - tw->tab.hmargin / 2 + 2*tw->tab.hmargin + sw - ww ;
- points[4].y = 0;
-
- points[5].x = tw->tab.hmargin ;
- points[5].y = tw->tab.title;
-
- count = 6;
-
- if(k > tw->tab.first)
- tw->tab.first = k;
-
- if(points[4].x < 0 )
- {
- (*x) += step;
- return;
- }
- }
-
- minx = points[0].x;
- maxx = points[0].x;
- xx = points[0].x;
-
- for(i = 1; i < count; i++)
- {
- xx += points[i].x;
- if(xx < minx) minx = xx;
- if(xx > maxx) maxx = xx;
- }
-
- XSetForeground(XtDisplay(tw),
- tw->tab.gc,
- (c == tw->tab.current) ?
- tw->core.background_pixel:
- tw->tab.back);
-
- XFillPolygon(
- XtDisplay(tw),
- XtWindow(tw),
- tw->tab.gc,
- points,
- count,
- Convex,
- CoordModePrevious
- );
-
- XSetForeground(XtDisplay(tw),
- tw->tab.gc,
- tw->manager.foreground);
-
- XDrawLines(
- XtDisplay(tw),
- XtWindow(tw),
- /* tw->tab.gc, */
- tw->manager.bottom_shadow_GC,
- points,
- count,
- CoordModePrevious
- );
-
- XSetForeground(XtDisplay(tw),
- tw->tab.gc,
- (c == tw->tab.current) ?
- tw->tab.blue:
- tw->manager.foreground);
-
- {
- char buf[1024];
- int i = strlen(n);
-
- while(--i >= 0 && sw > (maxx - minx - 2 * tw->tab.hmargin))
- {
- XmStringFree(s);
- strncpy(buf,n,i);
- buf[i] = '.';
- buf[i+1] = '.';
- buf[i+2] = '.';
- buf[i+3] = 0;
-
- s = XmStringCreateSimple(buf);
- sw = XmStringWidth(tw->tab.font, s);
- }
-
-
-
- XmStringDraw(XtDisplay(tw),
- XtWindow(tw),
- tw->tab.font,
- s,
- tw->tab.gc,
- minx ,
- tw->tab.vmargin + tw->tab.top + tw->tab.vmargin/3,
- maxx - minx,
- XmALIGNMENT_CENTER,
- XmSTRING_DIRECTION_L_TO_R,
- NULL);
-
- }
-
- XSetForeground(XtDisplay(tw),
- tw->tab.gc,
- tw->manager.foreground);
-
- XmStringFree(s);
-
- (*x) += step;
-}
-
-static void ReDisplay(Widget w, XEvent *event, Region region)
-{
- TabWidget tw = (TabWidget)w;
-
- int x = tw->tab.delta;
- int y = 0;
- int i;
- int cx = 0,cy= 0, ci = 0;
-
- tw->tab.first = -1;
- tw->tab.last = tw->composite.num_children + 1;
-
- for(i=0;i<tw->composite.num_children;i++)
- {
- Widget c = tw->composite.children[i];
- if(XtIsManaged(c))
- {
- if(!tw->tab.current) tw->tab.current = c;
-
- if(c == tw->tab.current) { cx = x; cy = y; ci = i; }
- draw(tw,c,&x,&y,i);
- }
- }
-
- if(tw->tab.current)
- {
- GC gc = tw->tab.gc;
- int t = tw->tab.title + tw->tab.top;
-
- x = cx;
- y = cy;
-
- draw(tw,tw->tab.current,&x,&y,ci);
-
- /*========================*/
-
- XSetForeground(XtDisplay(tw),gc,
- tw->core.background_pixel);
-
- XDrawLine(XtDisplay(tw),
- XtWindow(tw),
- gc, 0, t, tw->core.width, t);
-
- XSetForeground(XtDisplay(tw),
- tw->tab.gc,
- tw->manager.foreground);
-
- /*========================*/
-
- gc = tw->manager.bottom_shadow_GC;
-
- XDrawLine(XtDisplay(tw),
- XtWindow(tw),
- gc,
- 0,
- t,
- cx - tw->tab.hmargin/2,
- t);
-
- XDrawLine(XtDisplay(tw),
- XtWindow(tw),
- gc,
- x + tw->tab.hmargin/2,
- t,
- tw->core.width,
- t);
- }
-
- if(tw->tab.current && XtIsRealized(tw->tab.current))
- XRaiseWindow(XtDisplay(tw->tab.current),XtWindow(tw->tab.current));
-}
-
-
-Widget CreateTab(Widget par,char* nam,Arg* al,int ac)
-{
- return XtCreateWidget(nam,tabWidgetClass,par,al,ac);
-}
-
-Widget TabGetCurrent(Widget w)
-{
- TabWidget tw = (TabWidget)w;
- return tw->tab.current;
-}
-
-static int opened_size(TabWidget tw)
-{
- XtWidgetGeometry preferred;
- int size;
-
- XtQueryGeometry(tw->tab.current,NULL,&preferred);
-
- if((preferred.request_mode & CWHeight) != 0)
- size = preferred.height;
- else
- size = tw->tab.current->core.height;
-
- return size + tw->tab.title + tw->tab.vmargin;
-}
-
-static void open_close_tab(TabWidget tw)
-{
- if(tw->core.height == tw->tab.title)
- XtVaSetValues((Widget)tw,XmNheight,opened_size(tw),NULL);
- else
- XtVaSetValues((Widget)tw,XmNheight,tw->tab.title,NULL);
-}
-
-static void open_full(TabWidget tw)
-{
- int size = opened_size(tw);
- if(tw->core.height < size)
- XtVaSetValues((Widget)tw,XmNheight,size,NULL);
-}
-
-static void set_tab(Widget w,Widget c,Boolean tell,XEvent* ev)
-{
- TabWidget tw = (TabWidget)w;
- TabCallbackStruct cb;
-
- while(c && XtParent(c) != w)
- c = XtParent(c);
-
- if(!c) return;
-
- if(tw->tab.current == c)
- {
- if(tw->tab.drawer) {
- if(ev)
- open_close_tab(tw);
- else
- open_full(tw);
- }
- return;
- }
-
- cb.reason = XmCR_VALUE_CHANGED;
- cb.widget = c;
- cb.event = ev;
-
- if(tell)
- XtCallCallbacks(w, XmNvalueChangedCallback, &cb);
-
- tw->tab.current = cb.widget;
-
- if(tw->tab.drawer)
- open_full(tw);
-
- make_visible(tw,tw->tab.current);
-
- if(XtIsRealized(w))
- XClearArea(XtDisplay(w),XtWindow(w),0,0,0,0,True);
-}
-
-void TabSetCurrent(Widget w,Widget c,Boolean tell)
-{
- set_tab(w,c,tell,NULL);
-}
-
-void TabOpen(Widget w)
-{
- open_full((TabWidget)w);
-}
-
-void TabClose(Widget w)
-{
- TabWidget tw = (TabWidget)w;
- new_layout(tw,True);
- XtVaSetValues(w,XmNheight,tw->tab.title,NULL);
-}
-
-Boolean TabClosed(Widget w)
-{
- TabWidget tw = (TabWidget)w;
- return tw->tab.title == tw->core.height;
-}
-
-static void Click(Widget w, XEvent *event, String *params,Cardinal *nparams)
-{
- TabWidget tw = (TabWidget)w;
-
- int x = tw->tab.delta;
- int i;
-
- for(i=0;i<tw->composite.num_children;i++)
- {
- Widget c = tw->composite.children[i];
- if(XtIsManaged(c))
- {
- char *n = name_of(c);
- XmString s = XmStringCreateSimple(n);
-
- int h = XmStringHeight(tw->tab.font, s) + 2 * tw->tab.vmargin;
- int w = XmStringWidth(tw->tab.font, s) + 2 * tw->tab.hmargin;
-
- XmStringFree(s);
-
- if(event->xbutton.y >= tw->tab.top &&
- event->xbutton.y <= h + tw->tab.top)
- if(event->xbutton.x >= x && event->xbutton.x <= x + w)
- {
-
- if(i <= tw->tab.first || i>= tw->tab.last)
- make_visible(tw,c);
- else
- set_tab((Widget)tw,c,True,event);
- break;
- }
- x += w;
- }
- }
-}
-
-
-static void make_visible(TabWidget tw, Widget wid)
-{
- int x = 0;
- int i;
- int m = 0;
- int j = 0;
-
- int from,to;
-
- int* pos = (int*)XtCalloc(sizeof(int),tw->composite.num_children+1);
-
- for(i=0;i<tw->composite.num_children;i++)
- {
- Widget c = tw->composite.children[i];
- if(XtIsManaged(c))
- {
- char *n = name_of(c);
- XmString s = XmStringCreateSimple(n);
-
- /* int h = XmStringHeight(tw->tab.font, s) + 2 * tw->tab.vmargin; */
- int w = XmStringWidth(tw->tab.font, s) + 2 * tw->tab.hmargin;
-
- XmStringFree(s);
-
- if(c == wid)
- j = m;
- pos[m++] = x;
- x += w;
- }
- }
-
- pos[m] = x;
-
- if(j == 0 || j == m-1)
- {
- from = pos[j] - tw->tab.hmargin;
- to = pos[j+1] + tw->tab.hmargin;;
- }
- else {
- from = (pos[j]+pos[j-1])/2;
- to = (pos[j+2]+pos[j+1])/2;
- }
-
- tw->tab.delta = 5; /* start from first tab */
-
- if(from + tw->tab.delta < 0)
- {
- tw->tab.delta = -from;
- if(XtIsRealized((Widget)tw))
- XClearArea(XtDisplay(tw),XtWindow(tw),0,0,0,0,True);
- }
-
- if(to + tw->tab.delta > tw->core.width )
- {
- tw->tab.delta = -(to-tw->core.width);
- if(XtIsRealized((Widget)tw))
- XClearArea(XtDisplay(tw),XtWindow(tw),0,0,0,0,True);
- }
-
- XtFree((XtPointer)pos);
-}
diff --git a/ecflow_4_0_7/view/src/Tab.h b/ecflow_4_0_7/view/src/Tab.h
deleted file mode 100644
index dd1d9cf..0000000
--- a/ecflow_4_0_7/view/src/Tab.h
+++ /dev/null
@@ -1,66 +0,0 @@
-#ifndef TAB_H
-#define TAB_H
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #4 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-
-#define XtNround "round"
-#define XtCRound "Round"
-#define XtNrows "rows"
-#define XtNcolumns "columns"
-#define XtCRowCol "RowCol"
-
-#define XmNopenCallback "openCallback"
-#define XmNcloseCallback "closeCallback"
-
-extern WidgetClass tabWidgetClass;
-
-typedef struct _TabClassRec *TabWidgetClass;
-typedef struct _TabRec *TabWidget;
-
-#ifdef _NO_PROTO
-
-extern Widget CreateTab();
-
-#else
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
-Widget CreateTab(Widget,String,Arg*,int);
-Widget TabGetCurrent(Widget);
-void TabSetCurrent(Widget,Widget,Boolean);
-
-void TabOpen(Widget);
-void TabClose(Widget);
-
-Boolean TabClosed(Widget);
-
-
-#if defined(__cplusplus) || defined(c_plusplus)
-}
-#endif
-
-#endif /* _NO_PROTO */
-
-typedef struct {
- int reason;
- XEvent *event;
- Widget widget;
-}TabCallbackStruct;
-
-
-#endif /* TAB_H */
diff --git a/ecflow_4_0_7/view/src/TabP.h b/ecflow_4_0_7/view/src/TabP.h
deleted file mode 100644
index e9bc60e..0000000
--- a/ecflow_4_0_7/view/src/TabP.h
+++ /dev/null
@@ -1,80 +0,0 @@
-#ifndef TABP_H
-#define TABP_H
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #4 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-
-#include <Xm/XmP.h>
-#include <Xm/DrawingAP.h>
-
-typedef struct _TabClassPart {
- int ignore;
-} TabClassPart;
-
-typedef struct _TabClassRec {
- CoreClassPart core_class;
- CompositeClassPart composite_class;
- ConstraintClassPart constraint_class;
- XmManagerClassPart manager_class;
- XmDrawingAreaClassPart drawing_area_class;
- TabClassPart tab_class;
-} TabClassRec;
-
-extern TabClassRec tabClassRec;
-
-typedef struct {
- XtCallbackList cb;
- XtCallbackList open_cb;
- XtCallbackList close_cb;
- XmFontList font;
- Widget current;
- GC gc;
- Pixel back;
- Pixel blue;
-
- Dimension hmargin;
- Dimension vmargin;
-
- Dimension title;
- Dimension top;
- Dimension bottom;
-
- int delta;
- int first;
- int last;
-
- Boolean drawer;
- Time last_click;
-
-} TabPart;
-
-
-typedef struct _TabRec {
- CorePart core;
- CompositePart composite;
- ConstraintPart constraint;
- XmManagerPart manager;
- XmDrawingAreaPart drawing_area;
- TabPart tab;
-} TabRec;
-
-
-#define XtTabNumChildren(w) (((TabWidget)w) -> composite.num_children)
-#define XtTabChild(w,i) (((TabWidget)w) -> composite.children[i])
-
-#endif /* TABP_H */
-
-
-
diff --git a/ecflow_4_0_7/view/src/aborted.cc b/ecflow_4_0_7/view/src/aborted.cc
deleted file mode 100644
index 0ed73db..0000000
--- a/ecflow_4_0_7/view/src/aborted.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "aborted.h"
-#include "node.h"
-
-aborted::aborted():
- node_alert<aborted>("Aborted tasks",STATUS_ABORTED)
-{
-}
-
-aborted::~aborted()
-{
-}
-
-
-bool aborted::keep(node* n)
-{
- return n->status() == STATUS_ABORTED;
-}
-
diff --git a/ecflow_4_0_7/view/src/aborted.h b/ecflow_4_0_7/view/src/aborted.h
deleted file mode 100644
index 838d6f6..0000000
--- a/ecflow_4_0_7/view/src/aborted.h
+++ /dev/null
@@ -1,109 +0,0 @@
-#ifndef aborted_H
-#define aborted_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "node_alert.h"
-
-class node;
-
-class aborted : public node_alert<aborted> {
-public:
-
-// -- Exceptions
- // None
-
-// -- Contructors
-
- aborted();
-
-// -- Destructor
-
- ~aborted(); // Change to virtual if base class
-
-// -- Convertors
- // None
-
-// -- Operators
- // None
-
-// -- Methods
- // None
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
-
-
- // Uncomment for persistent, remove otherwise
- // static os_typespec* get_os_typespec();
-
-protected:
-
-// -- Members
- // None
-
-// -- Methods
-
- // void print(ostream&) const; // Change to virtual if base class
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-private:
-
-// No copy allowed
-
- aborted(const aborted&);
- aborted& operator=(const aborted&);
-
-// -- Methods
-
-// -- Overridden methods
-
- virtual bool keep(node*);
-
-// -- Class members
-
-
-// -- Class methods
- // None
-
-// -- Friends
-
- //friend ostream& operator<<(ostream& s,const aborted& p)
- // { p.print(s); return s; }
-
-};
-
-inline void destroy(aborted**) {}
-
-// If persistent, uncomment, otherwise remove
-//#ifdef _ODI_OSSG_
-//OS_MARK_SCHEMA_TYPE(aborted);
-//#endif
-
-#endif
diff --git a/ecflow_4_0_7/view/src/alerts.cc b/ecflow_4_0_7/view/src/alerts.cc
deleted file mode 100644
index 62b31ce..0000000
--- a/ecflow_4_0_7/view/src/alerts.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "to_check.h"
-#include "zombie.h"
-
-to_check::to_check() : node_alert<to_check>("Tasks to check") {}
-to_check::~to_check() {} // Change to virtual if base class
-bool to_check::keep(node* n) { return n->isToBeChecked(); }
-
-zombie::zombie() : node_alert<zombie>("Zombies") {}
-zombie::~zombie() {} // Change to virtual if base class
-bool zombie::keep(node* n) { return n->isZombie(); }
-
diff --git a/ecflow_4_0_7/view/src/alias.cc b/ecflow_4_0_7/view/src/alias.cc
deleted file mode 100644
index 56dd1ac..0000000
--- a/ecflow_4_0_7/view/src/alias.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "task_node.h"
-
-#ifdef BRIDGE
-alias_node::alias_node(host& h,sms_node* n,char b):
- task_node(h,n,b)
-{}
-#endif
-
-alias_node::alias_node(host& h,ecf_node* n):
- task_node(h,n)
-{
-}
-
-alias_node::~alias_node()
-{
-}
-
-
-void alias_node::why(std::ostream& f)
-{
- task_node::why(f);
-}
-
diff --git a/ecflow_4_0_7/view/src/arch.h b/ecflow_4_0_7/view/src/arch.h
deleted file mode 100644
index 320880c..0000000
--- a/ecflow_4_0_7/view/src/arch.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#if defined(__GNUC__) || defined(_AIX) || defined(alpha)
-#define _(z) z
-#else
-#define _(z)
-#endif
diff --git a/ecflow_4_0_7/view/src/array.cc b/ecflow_4_0_7/view/src/array.cc
deleted file mode 100644
index 3b205e8..0000000
--- a/ecflow_4_0_7/view/src/array.cc
+++ /dev/null
@@ -1,79 +0,0 @@
-#ifndef array_H
-#include "array.h"
-#endif
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-template<class T>
-array<T>::array():
- count_(0),
- max_(0),
- values_(0)
-{
-}
-
-template<class T>
-array<T>::array(const array<T>& other):
- count_(other.count_),
- max_(other.count_),
- values_(0)
-{
- values_ = new T[count_];
- for(int i = 0; i< count_; i++)
- values_[i] = other.values_[i];
-}
-
-template<class T>
-array<T>::~array()
-{
- delete[] values_;
-}
-
-template<class T>
-void array<T>::clear()
-{
- count_ = 0;
-}
-
-template<class T>
-void array<T>::add(const T& t)
-{
- //printf("1. array<T>::add( %d %d\n", max_,count_);
- if(count_ == max_)
- {
- max_ += 1 + max_/2;
- T* o = new T[max_];
- for(int i = 0; i< count_; i++)
- o[i] = values_[i];
- delete[] values_;
- values_ = o;
- //printf("2. array<T>::add( %d %d\n", max_,count_);
- }
- //printf("3. array<T>::add( %d %d\n", max_,count_);
- values_[count_++] = t;
-}
-
-template<class T>
-void array<T>::remove(const T& t)
-{
- for(int i = 0; i< count_; i++)
- {
- if(values_[i] == t)
- {
- values_[i] = values_[--count_];
- break;
- }
- }
-}
diff --git a/ecflow_4_0_7/view/src/array.h b/ecflow_4_0_7/view/src/array.h
deleted file mode 100644
index 6e9704f..0000000
--- a/ecflow_4_0_7/view/src/array.h
+++ /dev/null
@@ -1,131 +0,0 @@
-#ifndef array_H
-#define array_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include <stdio.h>
-
-// Headers
-// #ifndef machine_H
-// #include <machine.h>
-// #endif
-
-// Forward declarations
-
-// class ostream;
-// typedef class _Pvts os_typespec; // Remove if not persistant
-
-//
-
-template<class T>
-class array {
-public:
-
-// -- Exceptions
- // None
-
-// -- Contructors
-
- array();
- array(const array<T>&);
-
-// -- Destructor
-
- ~array(); // Change to virtual if base class
-
-// -- Convertors
- // None
-
-// -- Operators
-
- array<T>& operator=(const array<T>&);
-
- T& operator[](int i ) { return values_[i]; }
- int count() { return count_; }
-
-// -- Methods
- // None
-
- void add(const T&);
- void remove(const T&);
- void clear();
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
- // Uncomment for persistent, remove otherwise
- // static os_typespec* get_os_typespec();
-
-protected:
-
-// -- Members
- // None
-
- int count_;
- int max_;
- T* values_;
-
-// -- Methods
-
- // void print(ostream&) const; // Change to virtual if base class
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-private:
-
-// No copy allowed
-
-
-// -- Members
- // None
-
-
-// -- Methods
- // None
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-// -- Friends
-
- //friend ostream& operator<<(ostream& s,const array& p)
- // { p.print(s); return s; }
-
-};
-
-
-#include "array.cc"
-
-#endif
diff --git a/ecflow_4_0_7/view/src/ask.cc b/ecflow_4_0_7/view/src/ask.cc
deleted file mode 100644
index 9bd3332..0000000
--- a/ecflow_4_0_7/view/src/ask.cc
+++ /dev/null
@@ -1,46 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <stdio.h>
-#include <stdarg.h>
-#include "ask.h"
-#include "gui.h"
-#include <Xm/Text.h>
-
-ask::ask()
-{
- create(gui::top());
-}
-
-ask::~ask()
-{
-}
-
-bool ask::show(str& val,std::string msg)
-{
- static std::string m = msg;
- return instance().show(m.c_str(),val);
-}
-
-bool ask::show(const char* msg,str& val)
-{
- XmTextSetString(value_, (char*) val.c_str());
- if (!modal(msg, true))
- return false;
- char *p=XmTextGetString(value_);;
- val = p;
- XtFree(p);
- return true;
-}
diff --git a/ecflow_4_0_7/view/src/ask.h b/ecflow_4_0_7/view/src/ask.h
deleted file mode 100644
index 0552b81..0000000
--- a/ecflow_4_0_7/view/src/ask.h
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef ask_H
-#define ask_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "uiask.h"
-#include "dialog.h"
-#include "str.h"
-#include <string>
-
-class ask : public dialog<ask,ask_shell_c> {
-public:
-
- ask();
-
- ~ask(); // Change to virtual if base class
-
- static bool show(str&,std::string);
-private:
-
- ask(const ask&);
- ask& operator=(const ask&);
-
- bool show(const char*,str&);
-};
-
-inline void destroy(ask**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/autoAlarm.h b/ecflow_4_0_7/view/src/autoAlarm.h
deleted file mode 100644
index d5ea501..0000000
--- a/ecflow_4_0_7/view/src/autoAlarm.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef _AutoAlarm_h
-#define _AutoAlarm_h
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #4 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-
-class AutoAlarm {
- private:
- AutoAlarm (const AutoAlarm&); /* no copy allowed */
- AutoAlarm& operator= (const AutoAlarm&);
-
- typedef void (*proc)(int);
- proc (old_);
- int saveSec_;
-
- static sigjmp_buf env_;
- static bool caught_;
- static int sec_;
-
- static void sigAlarm (int);
-
- public:
- AutoAlarm (int);
-
- ~AutoAlarm ();
-
- static bool caught () { return caught_;};
-};
-
-#endif
diff --git a/ecflow_4_0_7/view/src/auto_alarm.cc b/ecflow_4_0_7/view/src/auto_alarm.cc
deleted file mode 100644
index 71f6565..0000000
--- a/ecflow_4_0_7/view/src/auto_alarm.cc
+++ /dev/null
@@ -1,47 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <signal.h>
-
-#include "ecflowview.h"
-#include "auto_alarm.h"
-
-int auto_alarm::sec_ = 0;
-
-auto_alarm::auto_alarm (int sec)
-{
- printf ("set alarm %d\n",sec);
- old_ = ::signal (SIGALRM, sigAlarm);
- sec_ = sec;
-
- ::alarm (sec);
-};
-
-
-auto_alarm::~auto_alarm ()
-{
- sec_ = saveSec_;
- ::signal (SIGALRM, old_);
- ::alarm (0);
- printf ("reset alarm\n");
-};
-
-
-void auto_alarm::sigAlarm (int)
-{
- printf ("catching\n");
- /* if (recover_jump) */
- // FILL longjmp(ecf_jump_station, 1);
-};
diff --git a/ecflow_4_0_7/view/src/auto_alarm.h b/ecflow_4_0_7/view/src/auto_alarm.h
deleted file mode 100644
index 331cdc7..0000000
--- a/ecflow_4_0_7/view/src/auto_alarm.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef _auto_alarm_h
-#define _auto_alarm_h
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #4 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-
-#include "setjmp.h"
-
-class auto_alarm {
- private:
- auto_alarm (const auto_alarm&); /* no copy allowed */
- auto_alarm& operator= (const auto_alarm&);
-
- typedef void (*proc)(int);
- proc (old_);
- int saveSec_;
-
- static sigjmp_buf env_;
- static bool caught_;
- static int sec_;
-
- static void sigAlarm (int);
-
- public:
- auto_alarm (int);
-
- ~auto_alarm ();
-
- static bool caught () { return caught_;};
-};
-
-#endif
diff --git a/ecflow_4_0_7/view/src/base.cc b/ecflow_4_0_7/view/src/base.cc
deleted file mode 100644
index fde7daa..0000000
--- a/ecflow_4_0_7/view/src/base.cc
+++ /dev/null
@@ -1,203 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #8 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <strings.h>
-#include <Xm/Xm.h>
-// #include <ostream.h>
-
-#include "base.h"
-#include "directory.h"
-#include "str.h"
-
-struct pairs {
-
- pairs* next_;
- str name_;
- str value_;
-
- pairs(const str& n,const str& v, pairs* x):
- next_(x), name_(n),value_(v) {}
-
- ~pairs() { delete next_; }
-};
-
-
-static base* defbase = 0;
-
-base::base(const str& name,const str& dir,bool save,base* p):
- name_(name),
- dir_(dir),
- count_(0),
- pairs_(0),
- parent_(p),
- save_(save)
-{
-}
-
-base::~base()
-{
-}
-
-base* base::lookup(const str& name)
-{
- if(defbase == 0) {
- defbase = new base("user.default",directory::user(),true,
- new base("system.default",directory::system(),true,
- new base(str(),str(),false,0)
- )
- );
- }
-
- base *p = extent<base>::first();
- while(p) {
- if(p->name_ == name)
- return p;
- p = p->extent<base>::next();
- }
-
- return new base(name,directory::user(),true,defbase);
-}
-
-void base::attach()
-{
- if(parent_)
- parent_->attach();
-
- count_++;
-
- if(count_ == 1 && save_) {
- // if(save_) {
- char buf[1024];
- sprintf(buf,"%s/%s.options",dir_.c_str(),name_.c_str());
-
- FILE* f = fopen(buf,"r");
- if(f) {
- while(fgets(buf,sizeof(buf),f)) {
- char *p = buf;
- while(*p && *p != ':') p++;
- if(*p != ':') continue;
-
- buf[strlen(buf)-1] = 0;
- *p = 0;
-
- store(buf,p+1,true);
- }
- fclose(f);
- }
- }
-}
-
-void base::detach()
-{
- if(parent_)
- parent_->detach();
-
- count_--;
-
- if(count_ == 0 && save_)
- save();
-}
-
-void base::save()
-{
- char buf[1024];
- sprintf(buf,"%s/%s.options",dir_.c_str(),name_.c_str());
- // fprintf(stdout, "%s\n", buf);
-
- FILE* f = fopen(buf,"w");
- if(f) {
- pairs* p = pairs_;
- while(p) {
- fprintf(f,"%s:%s\n",p->name_.c_str(),p->value_.c_str());
- p = p->next_;
- }
- fclose(f);
- }
-}
-
-bool base::fetch(const str& key,str& value)
-{
- pairs* p = pairs_;
- while(p) {
- if(p->name_ == key) {
- value = p->value_;
- return true;
- }
- p = p->next_;
- }
-
- if(parent_)
- parent_->fetch(key,value);
- return false;
-}
-
-void base::defaults(const str& key,const str& value)
-{
- if(parent_) {
- parent_->defaults(key,value);
- } else {
- store(key,value,false);
- }
-}
-
-void base::remove(const str& key)
-{
- pairs* p = pairs_;
- pairs* q = 0;
-
- while(p) {
- if(p->name_ == key) {
- if(q) q->next_ = p->next_;
- else pairs_ = p->next_;
- p->next_ = 0;
-
- delete p;
-
- remove(key);
- return;
- }
- q = p;
- p = p->next_;
- }
- enable();
-}
-
-void base::store(const str& key,const str& value,bool replace)
-{
- pairs* p = pairs_;
- enable();
- while(p) {
- if(p->name_ == key) {
- if(replace) {
- p->value_ = value;
- }
- return;
- }
- p = p->next_;
- }
-
- pairs_ = new pairs(key,value,pairs_);
-}
-
-void base::run()
-{
- if(save_)
- save();
- disable();
-}
-
-IMP(base)
diff --git a/ecflow_4_0_7/view/src/base.h b/ecflow_4_0_7/view/src/base.h
deleted file mode 100644
index d4ece74..0000000
--- a/ecflow_4_0_7/view/src/base.h
+++ /dev/null
@@ -1,65 +0,0 @@
-#ifndef base_H
-#define base_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#ifndef extent_H
-#include "extent.h"
-#endif
-
-#ifndef str_H
-#include "str.h"
-#endif
-
-#ifndef runnable_H
-#include "runnable.h"
-#endif
-
-struct pairs;
-
-class base : public extent<base>, public runnable {
-public:
- base(const str&,const str&,bool,base*);
-
- ~base(); // Change to virtual if base class
-
- void attach();
- void detach();
-
- void defaults(const str&,const str&);
- bool fetch(const str&,str&);
- void store(const str&,const str&,bool);
- void remove(const str&);
- void save();
-
- static base* lookup(const str&);
-
-private:
-
- base(const base&);
- base& operator=(const base&);
- virtual void run();
-
- str name_;
- str dir_;
- int count_;
- pairs* pairs_;
- base* parent_;
- bool save_;
-};
-
-inline void destroy(base**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/bool.h b/ecflow_4_0_7/view/src/bool.h
deleted file mode 100644
index 3f0cc52..0000000
--- a/ecflow_4_0_7/view/src/bool.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#ifndef bool_H
-#define bool_H
-
-typedef char xbool;
-
-#define bool xbool
-#define false 0
-#define true 1
-
-#endif
diff --git a/ecflow_4_0_7/view/src/choice.h b/ecflow_4_0_7/view/src/choice.h
deleted file mode 100644
index de44b15..0000000
--- a/ecflow_4_0_7/view/src/choice.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef choice_H
-#define choice_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-class choice {
-public:
-
- choice(int value = 0) : value_(value) {}
- choice(const choice& other) : value_(other.value_) {}
-
- operator int() const { return value_; }
- choice& operator=(int n) { value_ = n; return *this; }
- choice& operator=(const choice& other) { value_ = other.value_; return *this; }
-
-private:
-
- int value_;
-
-};
-
-inline void destroy(choice**) {}
-
-#endif
diff --git a/ecflow_4_0_7/view/src/collector.cc b/ecflow_4_0_7/view/src/collector.cc
deleted file mode 100644
index 593a88f..0000000
--- a/ecflow_4_0_7/view/src/collector.cc
+++ /dev/null
@@ -1,280 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #13 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "collector.h"
-#include "gui.h"
-#include "node.h"
-#include "host.h"
-#include "substitute.h"
-#include "directory.h"
-#include <Xm/List.h>
-#include <Xm/Text.h>
-#include <Xm/Separator.h>
-#include <Xm/PushB.h>
-#include <Xm/Command.h>
-#include <Xm/Xm.h>
-extern "C" {
-#include "xec.h"
-}
-
-collector::collector()
-{
-
- const int commands_nb = 20;
- static char* commands[commands_nb] = {
- (char *) "ecflow_client --zombie_fob <full_name>" ,
- (char *) "ecflow_client --zombie_fail <full_name>" ,
- (char *) "ecflow_client --zombie_adopt <full_name>" ,
- (char *) "ecflow_client --zombie_block <full_name>" ,
- (char *) "ecflow_client --alter clear_flag zombie <full_name>" ,
- (char *) "###",
- (char *) "ecflow_client --suspend <full_name>" ,
- (char *) "ecflow_client --resume <full_name>" ,
- (char *) "ecflow_client --kill <full_name>" ,
- (char *) "ecflow_client --run <full_name>" ,
- (char *) "###",
- (char *) "ecflow_client --delete force yes <full_name>",
- (char *) "###",
- (char *) "ecflow_client --begin <node_name>",
- (char *) "###",
- (char *) "ecflow_client --requeue <full_name>",
- (char *) "ecflow_client --alter change defstatus queued <full_name>",
- (char *) "ecflow_client --alter change defstatus complete <full_name>",
- (char *) "ecflow_client --force complete <full_name>",
- (char *) "ecflow_client --force aborted <full_name>",
- };
-
- create(gui::top());
- set_menu("Collector");
- substitute::fill(blocks_);
- XtManageChild(XmCreateSeparator(blocks_,"-",0,0));
- update();
-
- FILE* f = directory::open("collector.commands","r");
- if(f) {
- char line[1024];
- while(fgets(line,sizeof(line),f))
- {
- line[strlen(line)-1] = 0;
- XtManageChild(XmCreatePushButton(blocks_,line,0,0));
- }
- fclose(f);
- } else {
- /* provide default commands to new users */
-
- for(int i = 0; i < commands_nb; i++)
- XtManageChild(XmCreatePushButton(blocks_,commands[i],0,0));
- }
-
- f = directory::open("collector.history","r");
- if(f)
- {
- char line[1024];
- int n = 0;
- while(fgets(line,sizeof(line),f))
- n++;
-
- rewind(f);
-
- XmString* s = new XmString[n];
- int i = 0;
-
- while(fgets(line,sizeof(line),f))
- {
- line[strlen(line)-1] = 0;
- s[i++] = xec_NewString(line);
- }
- fclose(f);
-
- XtVaSetValues(command_,
- XmNhistoryItems, s,
- XmNhistoryItemCount, n,
- NULL);
-
- for(i = 0; i < n; i++)
- XmStringFree(s[i]);
- delete[] s;
- } else {
- /* provide default commands to new users */
- const int maxCmd = 128;
- XmString* s = new XmString[maxCmd];
- for(int i = 0; i < commands_nb; i++) {
- s[i] = xec_NewString(commands[i]);
- }
-
- XtVaSetValues(command_,
- XmNhistoryItems, s,
- XmNhistoryItemCount, commands_nb,
- NULL);
- for(int i = 0; i < commands_nb; i++) XmStringFree(s[i]);
- delete[] s;
- }
-
-}
-
-collector::~collector()
-{
-
- FILE * f = directory::open("collector.history","w");
- if(f)
- {
- XmString* s = 0;
- int n = 0;
-
- XtVaGetValues(command_,
- XmNhistoryItems, &s,
- XmNhistoryItemCount, &n,
- NULL);
-
- for(int i = 0; i < n; i++)
- {
- char *p = xec_GetString(s[i]);
- fprintf(f,"%s\n",p);
- XtFree(p);
- }
-
- fclose(f);
- }
-}
-
-void collector::show(node& n)
-{
- instance().nodes_.clear();
- instance().add(&n,true);
- instance().update();
-}
-
-void collector::applyCB( Widget, XtPointer data)
-{
- XmCommandCallbackStruct* cb = (XmCommandCallbackStruct*)data;
- nodes_.clear();
-
- char *p = xec_GetString(cb->value);
- send(p);
- XtFree(p);
-}
-
-void collector::removeCB( Widget, XtPointer )
-{
- XmString *items = 0;
- int count = 0;
-
- nodes_.clear();
-
- XtVaGetValues(list_,
- XmNselectedItems,&items,
- XmNselectedItemCount,&count,
- NULL);
-
- XmListDeleteItems(list_,items,count);
- update();
-}
-
-void collector::noneCB( Widget, XtPointer )
-{
- nodes_.clear();
- XmListDeselectAllItems(list_);
- update();
-}
-
-void collector::allCB( Widget, XtPointer )
-{
- nodes_.clear();
- xec_ListSelectAll(list_);
- update();
-}
-
-void collector::selectCB( Widget, XtPointer )
-{
- update();
-}
-
-void collector::update()
-{
- int count = 0;
- int total = 0;
-
- XtVaGetValues(list_,
- XmNselectedItemCount,&count,
- XmNitemCount,&total,
- NULL);
-
- XtSetSensitive(remove_, count != 0);
- XtSetSensitive(command_, count != 0);
- XtSetSensitive(all_, count != total);
- XtSetSensitive(none_, count != 0);
-}
-
-
-void collector::send(const char* cmd)
-{
- XmString* items = 0;
- int count = 0;
-
- XtVaGetValues(list_,
- XmNselectedItems,&items,
- XmNselectedItemCount,&count,
- NULL);
-
- cmd_ = cmd;
- nodes_.clear();
-
- for(int i = 0; i < count ; i++)
- nodes_.add(items[i]);
-
- next_ = 0;
- runnable::enable();
- XtSetSensitive(stop_,true);
-}
-
-
-void collector::run()
-{
- if(next_ >= nodes_.count())
- {
- nodes_.clear();
- runnable::disable();
- XtSetSensitive(stop_,false);
- return;
- }
-
- XmListDeselectItem(list_,nodes_[next_]);
- XmListSetBottomItem(list_,nodes_[next_]);
- node *n = find(nodes_[next_++]);
- if(n) n->command(cmd_.c_str());
- update();
-}
-
-void collector::closeCB(Widget,XtPointer)
-{
- // 201207 ABO warnings? XmListDeleteAllItems(list_);
- XtUnmanageChild(form_);
-}
-
-void collector::entryCB(Widget,XtPointer data)
-{
- XmRowColumnCallbackStruct *cb = (XmRowColumnCallbackStruct *) data;
- xec_ReplaceTextSelection(text_,XtName(cb->widget),False);
-}
-
-bool collector::keep(node*)
-{
- return true;
-}
-
-void collector::stopCB(Widget,XtPointer data)
-{
- nodes_.clear();
-}
diff --git a/ecflow_4_0_7/view/src/collector.h b/ecflow_4_0_7/view/src/collector.h
deleted file mode 100644
index 2626fe5..0000000
--- a/ecflow_4_0_7/view/src/collector.h
+++ /dev/null
@@ -1,100 +0,0 @@
-#ifndef collector_H
-#define collector_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#ifndef window_H
-#include "window.h"
-#endif
-
-#ifndef uicollector_H
-#include "uicollector.h"
-#endif
-
-#ifndef singleton_H
-#include "singleton.h"
-#endif
-
-#ifndef node_list_H
-#include "node_list.h"
-#endif
-
-#ifndef runnable_H
-#include "runnable.h"
-#endif
-
-#ifndef array_H
-#include "array.h"
-#endif
-
-#ifndef str_H
-#include "str.h"
-#endif
-
-#ifndef xmstring_H
-#include "xmstring.h"
-#endif
-
-class node;
-
-class collector : public collector_shell_c, public window,
- public runnable,
- public singleton<collector>, public node_list {
-public:
-
- collector();
-
- ~collector(); // Change to virtual if base class
-
-// -- Overridden methods
-
- virtual Widget shell() { return _xd_rootwidget; }
- virtual Widget list() { return list_; }
- virtual Widget form() { return form_; }
-
-// -- Class members
-
- static void show(node&);
-
-private:
-
- collector(const collector&);
- collector& operator=(const collector&);
-
- str cmd_;
- array<xmstring> nodes_;
- int next_;
-
- void update();
- void send(const char*);
-
- void run();
-
- virtual void closeCB( Widget, XtPointer );
- virtual void applyCB( Widget, XtPointer );
- virtual void removeCB( Widget, XtPointer );
- virtual void noneCB( Widget, XtPointer );
- virtual void allCB( Widget, XtPointer );
- virtual void selectCB( Widget, XtPointer );
- virtual void entryCB( Widget, XtPointer );
- virtual void stopCB( Widget, XtPointer );
-
- virtual bool keep(node*);
-
-};
-
-inline void destroy(collector**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/colors_prefs.cc b/ecflow_4_0_7/view/src/colors_prefs.cc
deleted file mode 100644
index 8eeaa9b..0000000
--- a/ecflow_4_0_7/view/src/colors_prefs.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "colors_prefs.h"
-
-void colors_prefs::create(Widget w,char*)
-{
- colors_form_c::create(w);
- prefs::setup(w);
-}
-
-// static colors_prefs hp;
diff --git a/ecflow_4_0_7/view/src/colors_prefs.h b/ecflow_4_0_7/view/src/colors_prefs.h
deleted file mode 100644
index 7674f5d..0000000
--- a/ecflow_4_0_7/view/src/colors_prefs.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef colors_prefs_H
-#define colors_prefs_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#ifndef prefs_H
-#include "prefs.h"
-#endif
-
-#ifndef uicolors
-#include "uicolors.h"
-#endif
-
-class colors_prefs : public prefs, public colors_form_c {
-public:
-
- colors_prefs() {}
-
- ~colors_prefs() {}
-
- virtual Widget widget() { return _xd_rootwidget; }
-
-private:
-
- colors_prefs(const colors_prefs&);
- colors_prefs& operator=(const colors_prefs&);
-
- virtual void changedCB( Widget w, XtPointer ) { pref_editor::changed(w); }
- virtual void useCB( Widget w, XtPointer ) { pref_editor::use(w); }
-
- virtual void create(Widget w,char*);
-};
-
-inline void destroy(colors_prefs**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/configurable.cc b/ecflow_4_0_7/view/src/configurable.cc
deleted file mode 100644
index 64fe75e..0000000
--- a/ecflow_4_0_7/view/src/configurable.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef configurable_H
-#include "configurable.h"
-#endif
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-configurable::~configurable() {}
-
-void configurable::changed(resource&)
-{
-}
diff --git a/ecflow_4_0_7/view/src/configurable.h b/ecflow_4_0_7/view/src/configurable.h
deleted file mode 100644
index b85d392..0000000
--- a/ecflow_4_0_7/view/src/configurable.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef configurable_H
-#define configurable_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-class configurator;
-class resource;
-
-class configurable {
-public:
- virtual ~configurable();
- virtual void changed(resource&);
-
-#ifdef alpha
- configurable(const char* name): name_(name) {}
- const char* name() const { return name_; }
-private:
- const char* name_;
-#else
- virtual const char* name() const = 0;
-#endif
-};
-
-inline void destroy(configurable**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/configurator.h b/ecflow_4_0_7/view/src/configurator.h
deleted file mode 100644
index 632b340..0000000
--- a/ecflow_4_0_7/view/src/configurator.h
+++ /dev/null
@@ -1,128 +0,0 @@
-#ifndef configurator_H
-#define configurator_H
-
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-// Headers
-// #ifndef machine_H
-// #include <machine.h>
-// #endif
-
-// Forward declarations
-
-// class ostream;
-// typedef class _Pvts os_typespec; // Remove if not persistant
-
-//
-
-template<class T>
-class option;
-
-class str;
-
-class configurator {
-public:
-
-// -- Exceptions
- // None
-
-// -- Contructors
-
- //configurator();
-
-// -- Destructor
-
- //~configurator(); // Change to virtual if base class
-
-// -- Convertors
- // None
-
-// -- Operators
- // None
-
-// -- Methods
- // None
-
- virtual void init(resource&) = 0;
- virtual bool modified(resource&) = 0;
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
- // Uncomment for persistent, remove otherwise
- // static os_typespec* get_os_typespec();
-
-protected:
-
-// -- Members
- // None
-
-// -- Methods
-
- // void print(ostream&) const; // Change to virtual if base class
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-private:
-
-// No copy allowed
-
-// configurator(const configurator&);
-// configurator& operator=(const configurator&);
-
-// -- Members
- // None
-
-// -- Methods
- // None
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-// -- Friends
-
- //friend ostream& operator<<(ostream& s,const configurator& p)
- // { p.print(s); return s; }
-
-};
-
-inline void destroy(configurator**) {}
-
-// If persistent, uncomment, otherwise remove
-//#ifdef _ODI_OSSG_
-//OS_MARK_SCHEMA_TYPE(configurator);
-//#endif
-
-#endif
diff --git a/ecflow_4_0_7/view/src/confirm.cc b/ecflow_4_0_7/view/src/confirm.cc
deleted file mode 100644
index c3df4e2..0000000
--- a/ecflow_4_0_7/view/src/confirm.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <stdio.h>
-#include <stdarg.h>
-#include "confirm.h"
-#include "gui.h"
-
-confirm::confirm()
-{
- create(gui::top());
-}
-
-confirm::~confirm()
-{
-}
-
-Boolean confirm::ask(Boolean def_ok,const char* fmt,...)
-{
- char buf[1024];
- va_list arg;
- va_start(arg,fmt);
- vsprintf(buf,fmt,arg);
- va_end(arg);
-
- return instance().modal(buf, def_ok);
-}
-
-Boolean confirm::ask(Boolean def_ok,str& msg)
-{
- return instance().modal(msg.c_str(), def_ok);
-}
diff --git a/ecflow_4_0_7/view/src/confirm.h b/ecflow_4_0_7/view/src/confirm.h
deleted file mode 100644
index 84cff07..0000000
--- a/ecflow_4_0_7/view/src/confirm.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef confirm_H
-#define confirm_H
-
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "uiconfirm.h"
-#include "dialog.h"
-#include "str.h"
-
-class confirm : public dialog<confirm,confirm_shell_c> {
-public:
-
- confirm();
-
- ~confirm(); // Change to virtual if base class
-
- static Boolean ask(Boolean,const char*,...);
- static Boolean ask(Boolean,str& msg);
-
-private:
-
- confirm(const confirm&);
- confirm& operator=(const confirm&);
-};
-
-inline void destroy(confirm**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/counted.cc b/ecflow_4_0_7/view/src/counted.cc
deleted file mode 100644
index e633749..0000000
--- a/ecflow_4_0_7/view/src/counted.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef counted_H
-#include "counted.h"
-#endif
-
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-counted::counted():
- count_(0)
-{
-}
-
-counted::~counted()
-{
-}
-
-void counted::attach()
-{
- count_++;
-}
-
-void counted::detach()
-{
- if(--count_ == 0) delete this;
-}
diff --git a/ecflow_4_0_7/view/src/counted.h b/ecflow_4_0_7/view/src/counted.h
deleted file mode 100644
index 047776d..0000000
--- a/ecflow_4_0_7/view/src/counted.h
+++ /dev/null
@@ -1,124 +0,0 @@
-#ifndef counted_H
-#define counted_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-// Headers
-// #ifndef machine_H
-// #include <machine.h>
-// #endif
-
-// Forward declarations
-
-// class ostream;
-// typedef class _Pvts os_typespec; // Remove if not persistant
-
-//
-
-class counted {
-public:
-
-// -- Exceptions
- // None
-
-// -- Contructors
-
- counted();
-
-// -- Destructor
-
-
-// -- Convertors
- // None
-
-// -- Operators
- // None
-
-// -- Methods
-
- void attach();
- void detach();
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
- // Uncomment for persistent, remove otherwise
- // static os_typespec* get_os_typespec();
-
-protected:
-
- virtual ~counted(); // Change to virtual if base class
-
-// -- Members
- // None
-
-// -- Methods
-
- // void print(ostream&) const; // Change to virtual if base class
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-private:
-
-// No copy allowed
-
- counted(const counted&);
- counted& operator=(const counted&);
-
-// -- Members
-
- int count_;
-
-// -- Methods
- // None
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-// -- Friends
-
- //friend ostream& operator<<(ostream& s,const counted& p)
- // { p.print(s); return s; }
-
-};
-
-inline void destroy(counted**) {}
-
-// If persistent, uncomment, otherwise remove
-//#ifdef _ODI_OSSG_
-//OS_MARK_SCHEMA_TYPE(counted);
-//#endif
-
-#endif
diff --git a/ecflow_4_0_7/view/src/date.cc b/ecflow_4_0_7/view/src/date.cc
deleted file mode 100644
index 5c7386a..0000000
--- a/ecflow_4_0_7/view/src/date.cc
+++ /dev/null
@@ -1,106 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #11 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "date.h"
-#include "ecf_node.h"
-
-date_node::date_node(host& h,ecf_node* n) : node(h,n) {
- if (!n) return;
- full_name_ = parent()->full_name();
- full_name_ += ":";
- if (n) full_name_ += n->toString();
-}
-
-#ifdef BRIDGE
-static char *week[] = {
- (char*)"sunday", (char*)"monday",(char*)"tuesday",(char*)"wednesday",(char*)"thursday",
- (char*)"friday",(char*)"saturday"};
-
-date_node::date_node(host& h,sms_node* n, char b)
- : node(h,n,b)
-{}
-#endif
-
-char* date_node::string(char *s)
-{
- char buf[1024];
- s[0] = 0;
- if (owner_)
- snprintf(buf, 1024, "%s", owner_->toString().c_str());
-#ifdef BRIDGE
- if (tree_) {
- sms_date *d = (sms_date*)tree_;
-
- char buf[1024];
- s[0] = 0;
-
- if(d->weekdays)
- {
- int flg = 0;
- for( int i=0 ; i<DAY_MAX ; i++ )
- if( d->weekdays & ( 1<<i ) )
- {
- if(flg) {
- strcat(s," ");
- }
- strcat(s,week[i]);
- flg++;
- }
- } else {
- sprintf(buf,d->day<0?"*":"%02d",d->day);
- strcat(s,buf);
- strcat(s,".");
-
- sprintf(buf,d->month<0?"*":"%02d",d->month);
- strcat(s,buf);
- strcat(s,".");
-
- sprintf(buf,d->year<0?"*":"%02d",d->year+1900);
- strcat(s,buf);
- }
- return s;
- }
- else
-#endif
- strcat(s,buf);
- return s;
-}
-
-xmstring date_node::make_label_tree()
-{
- char buf[1024];
- return xmstring(string(buf));
-}
-
-void date_node::perlify(FILE* f)
-{
- char buf[1034];
- perl_member(f,"value",string(buf));
-}
-
-node* date_node::graph_node()
-{
- return &dummy_node::get(full_name());
-}
-
-const std::string& date_node::name() const
-{
- static std::string date_ = "date";
-#ifdef BRIDGE
- if (tree_) return date_;
-#endif
- if (owner_) date_ = owner_->name();
- return date_;
-}
diff --git a/ecflow_4_0_7/view/src/date.h b/ecflow_4_0_7/view/src/date.h
deleted file mode 100644
index 4aa9a42..0000000
--- a/ecflow_4_0_7/view/src/date.h
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef DATE_H
-#define DATE_H
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #10 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "node.h"
-#include "show.h"
-#include "dummy_node.h"
-#
-class date_node : public node {
-
- std::string full_name_;
- virtual bool is_my_parent(node*) const { return false; }
- virtual void info(std::ostream&) {}
-
- virtual xmstring make_label_tree();
- virtual xmstring make_label_trigger() { return make_label_tree(); }
-
- virtual const std::string& name() const;
- const std::string& full_name() const {return full_name_; }
- virtual Boolean menus() { return False; }
- virtual Boolean selectable() { return False; }
-
- virtual Boolean visible() const { return show::want(show::date); }
- virtual node* graph_node();
- char* string(char*);
-
- virtual void perlify(FILE*);
-
-public:
- date_node(host& h,ecf_node* n);
-#ifdef BRIDGE
- date_node(host& h,sms_node* n, char b);
-#endif
-};
-#endif
diff --git a/ecflow_4_0_7/view/src/depend.cc b/ecflow_4_0_7/view/src/depend.cc
deleted file mode 100644
index 951d4a9..0000000
--- a/ecflow_4_0_7/view/src/depend.cc
+++ /dev/null
@@ -1,72 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "depend.h"
-#include "host.h"
-#include "runnable.h"
-#include <Xm/List.h>
-#include <Xm/Text.h>
-#include <Xm/ToggleB.h>
-#include <Xm/PushB.h>
-#include "gui.h"
-#include "extent.h"
-#include "flags.h"
-#include "pixmap.h"
-#include "result.h"
-#include <X11/IntrinsicP.h>
-#include <stdarg.h>
-
-extern "C" {
-#include "xec.h"
-}
-
-depend::depend()
-{
- _xd_rootwidget = 0;
-}
-
-depend::~depend()
-{
- if(_xd_rootwidget)
- XtDestroyWidget(_xd_rootwidget);
-}
-
-void depend::closeCB(Widget,XtPointer)
-{
- hide();
-}
-
-void depend::hide()
-{
- if(_xd_rootwidget) {
- XtUnmanageChild(form_);
- }
-}
-
-void depend::make(Widget top)
-{
- while(!XtIsShell(top))
- top = XtParent(top);
-
- if(!_xd_rootwidget)
- depend_shell_c::create(top);
-}
-
-void depend::raise(Widget top)
-{
- make(top);
- XtManageChild(form_);
- XMapRaised(XtDisplay(_xd_rootwidget),XtWindow(_xd_rootwidget));
-}
diff --git a/ecflow_4_0_7/view/src/depend.h b/ecflow_4_0_7/view/src/depend.h
deleted file mode 100644
index ddc14cd..0000000
--- a/ecflow_4_0_7/view/src/depend.h
+++ /dev/null
@@ -1,126 +0,0 @@
-#ifndef depend_H
-#define depend_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-// Headers
-// #ifndef machine_H
-// #include <machine.h>
-// #endif
-
-// Forward declarations
-
-// class ostream;
-// typedef class _Pvts os_typespec; // Remove if not persistant
-
-class host;
-//
-
-#include "uidepend.h"
-
-
-class depend : public depend_shell_c {
-public:
-
-// -- Exceptions
- // None
-
-// -- Contructors
-
- depend();
-
-// -- Destructor
-
- ~depend(); // Change to virtual if base class
-
-// -- Convertors
- // None
-
-// -- Operators
-
- void make(Widget);
- void raise(Widget);
- void hide();
-
-// -- Methods
-
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
-
-
-protected:
-
-// -- Members
- // None
-
-// -- Methods
-
- // void print(ostream&) const; // Change to virtual if base class
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-private:
-
-// No copy allowed
-
- depend(const depend&);
- depend& operator=(const depend&);
-
-// -- Members
-
-
-// -- Methods
-
-
-
-// -- Overridden methods
-
-
-// -- Class members
-
-
-// -- Class methods
-
- void closeCB(Widget,XtPointer);
-
-// -- Friends
-
- //friend ostream& operator<<(ostream& s,const depend& p)
- // { p.print(s); return s; }
-
-};
-
-inline void destroy(depend**) {}
-
-// If persistent, uncomment, otherwise remove
-//#ifdef _ODI_OSSG_
-//OS_MARK_SCHEMA_TYPE(depend);
-//#endif
-
-#endif
diff --git a/ecflow_4_0_7/view/src/dialog.cc b/ecflow_4_0_7/view/src/dialog.cc
deleted file mode 100644
index 9984685..0000000
--- a/ecflow_4_0_7/view/src/dialog.cc
+++ /dev/null
@@ -1,83 +0,0 @@
-#ifndef dialog_H
-#include "dialog.h"
-#endif
-
-#ifndef SVR4
-#include <stdio.h>
-#endif
-
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-extern "C" {
-#include "xec.h"
-}
-
-
-template<class T,class U>
-void dialog<T,U>::helpCB( Widget, XtPointer )
-{
-}
-
-template<class T,class U>
-void dialog<T,U>::cancelCB( Widget, XtPointer )
-{
- ok_ = False;
- stop_ = True;
-}
-
-template<class T,class U>
-void dialog<T,U>::okCB( Widget, XtPointer )
-{
- ok_ = True;
- stop_ = True;
-}
-
-
-template<class T,class U>
-Boolean dialog<T,U>::modal(const char* message,Boolean def_ok)
-{
- XtVaSetValues(this->form_,
- XmNdefaultButtonType,
- (def_ok? XmDIALOG_OK_BUTTON : XmDIALOG_CANCEL_BUTTON),
- NULL);
-
- if(message)
- xec_SetLabel(this->label_,message);
-
- XtManageChild(this->form_);
-
- stop_ = False;
-
- XEvent event_node;
- XtAppContext ac = XtWidgetToApplicationContext(this->form_);
-
- while(!stop_)
- {
- XtAppNextEvent(ac,&event_node);
- XtDispatchEvent(&event_node);
- }
-
- XtUnmanageChild(this->form_);
-
- return ok_;
-}
-
-template<class T,class U>
-void dialog<T,U>::show()
-{
- XtManageChild(this->form_);
-}
diff --git a/ecflow_4_0_7/view/src/dialog.h b/ecflow_4_0_7/view/src/dialog.h
deleted file mode 100644
index b685e03..0000000
--- a/ecflow_4_0_7/view/src/dialog.h
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef dialog_H
-#define dialog_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#ifndef singleton_H
-#include "singleton.h"
-#endif
-
-template<class T,class U>
-class dialog : public U, public singleton<T> {
-public:
-
- dialog() : stop_(True), ok_(False) {}
-
-protected:
-
- Boolean stop_;
- Boolean ok_;
-
- Boolean modal(const char*,Boolean);
- void show();
-
-private:
-
- dialog(const dialog<T,U>&);
- dialog<T,U>& operator=(const dialog<T,U>&);
-
- virtual void helpCB( Widget, XtPointer ) ;
- virtual void cancelCB( Widget, XtPointer ) ;
- virtual void okCB( Widget, XtPointer ) ;
-};
-
-#if defined(__GNUC__) || defined(hpux) || defined(_AIX)
-#include "dialog.cc"
-#endif
-#endif
diff --git a/ecflow_4_0_7/view/src/directory.cc b/ecflow_4_0_7/view/src/directory.cc
deleted file mode 100644
index aeb171c..0000000
--- a/ecflow_4_0_7/view/src/directory.cc
+++ /dev/null
@@ -1,72 +0,0 @@
-#ifndef directory_H
-#include "directory.h"
-#endif
-
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #8 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include "ecflowview.h"
-
-
-const char* directory::user()
-{
- static char x[1024] = {0};
- if(x[0] == 0)
- {
- const char * rcdir = getenv("ECFLOWRC");
- if (rcdir)
- sprintf(x,"%s",rcdir);
- else
- sprintf(x,"%s/.%s",getenv("HOME"),"ecflowrc");
- mkdir(x,0755);
- fprintf(stdout, "# rcdir: %s\n", x);
- }
- return x;
-}
-
-// ECFLOW_SHARED_DIR is a define, where 'server'file is installed
-const char* directory::system()
-{
- static char x[1024] = {0};
- if(x[0] == 0) {
- if(getenv("ECFLOWVIEW_HOME"))
- strcpy(x,getenv("ECFLOWVIEW_HOME"));
- else
- strcpy(x,ECFLOW_SHARED_DIR);
- }
-
- //std::cout << "system dir = " << x << "\n";
- return x;
-}
-
-
-FILE* directory::open(const char* name,const char *mode)
-{
- FILE* f = 0;
- char buf[1024];
-
- sprintf(buf,"%s/%s",user(),name);
- f = fopen(buf,mode);
- if(f || *mode != 'r') return f;
-
- sprintf(buf,"%s/%s",system(),name);
- return fopen(buf,mode);
-}
diff --git a/ecflow_4_0_7/view/src/directory.h b/ecflow_4_0_7/view/src/directory.h
deleted file mode 100644
index e500f3e..0000000
--- a/ecflow_4_0_7/view/src/directory.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef directory_H
-#define directory_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include <stdio.h>
-
-class directory {
-public:
-
- directory();
-
- ~directory(); // Change to virtual if base class
-
- static FILE* open(const char*,const char*);
- static const char* user();
- static const char* system();
-
-private:
-
- directory(const directory&);
- directory& operator=(const directory&);
-
-};
-
-inline void destroy(directory**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/doer.sh b/ecflow_4_0_7/view/src/doer.sh
deleted file mode 100644
index a36a6ef..0000000
--- a/ecflow_4_0_7/view/src/doer.sh
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/ksh
-#=============================================================================================
-# Name :
-# Author :
-# Revision : $Revision: #3 $
-#
-# Copyright 2009-2012 ECMWF.
-# This software is licensed under the terms of the Apache Licence version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation
-# nor does it submit to any jurisdiction.
-#
-# Description :
-#=============================================================================================
-
-return
-function call {
-grep -l sms_node * > sms_node.list
-
-for f in `cat sms_node.list`; do
- cat $f | sed -e 's:sms_node:ecf_node:' > ${f}.tmp; ;
- mv ${f} ${f}.orig;
- mv ${f}.tmp ${f};
-done
-
- clear; ./env.sh cc 2>&1 | head -50
-
-}
diff --git a/ecflow_4_0_7/view/src/dummy_node.cc b/ecflow_4_0_7/view/src/dummy_node.cc
deleted file mode 100644
index 82944d8..0000000
--- a/ecflow_4_0_7/view/src/dummy_node.cc
+++ /dev/null
@@ -1,58 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #15 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "dummy_node.h"
-#include "host.h"
-
-#ifndef ecf_node_
-#include "ecf_node.h"
-#endif
-#include <boost/shared_ptr.hpp>
-
-static node* head_ = 0;
-static const std::string id = "(dummy_node)";
-const std::string dummy_node::toString() const { return id; }
-
-dummy_node::dummy_node(const std::string name)
- : node(host::dummy(),0)
- , name_ (name)
-{
- next_ = head_;
- head_ = this;
- owner_ = new ecf_concrete_node<dummy_node> (this, 0);
-}
-
-dummy_node::~dummy_node()
-{
-}
-
-dummy_node& dummy_node::get(const std::string name)
-{
- node* e = head_;
- while(e) {
- if(name == e->name())
- return * (dummy_node*) e;
- e = e->next();
- }
- return *(new dummy_node(name));
-}
-
-void dummy_node::info(std::ostream&)
-{
-}
-
-void dummy_node::perlify(FILE* f)
-{
-}
diff --git a/ecflow_4_0_7/view/src/dummy_node.h b/ecflow_4_0_7/view/src/dummy_node.h
deleted file mode 100644
index b00cf32..0000000
--- a/ecflow_4_0_7/view/src/dummy_node.h
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef dummy_node_H
-#define dummy_node_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #11 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "node.h"
-
-class dummy_node : public node {
-public:
-
- dummy_node(const std::string);
- ~dummy_node(); // Change to virtual if base class
-
- virtual Boolean menus() { return False; }
- virtual Boolean selectable() { return False; }
- virtual const std::string& full_name() const { return name();}
- virtual const std::string& name() const { return name_; }
- virtual void info(std::ostream&);
-
- const std::string toString() const;
- virtual const char* type_name() const { return "dummy_node"; }
- virtual const char* status_name() const { return "unknown"; }
- virtual std::ostream& print(std::ostream&s) const { return s << "dummy_node\n";};
-
- static dummy_node& get(const std::string);
-private:
-
- dummy_node(const dummy_node&);
- dummy_node& operator=(const dummy_node&);
-
- const std::string name_;
- // int type_;
- int type() const { return NODE_UNKNOWN; }
- //int status_;
- virtual void perlify(FILE*);
-};
-
-inline void destroy(dummy_node**) {}
-
-#endif
diff --git a/ecflow_4_0_7/view/src/ecf_node.cc b/ecflow_4_0_7/view/src/ecf_node.cc
deleted file mode 100644
index ca51d43..0000000
--- a/ecflow_4_0_7/view/src/ecf_node.cc
+++ /dev/null
@@ -1,1193 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #114 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "ecf_node.h"
-#include "host.h"
-#include "node.h"
-#include "tree.h"
-#include "ChangeMgrSingleton.hpp"
-#include "NodeAttr.hpp"
-#include "Variable.hpp"
-#include "dummy_node.h"
-#include "external.h"
-#include <Str.hpp>
-#ifndef NODE_MAX
-#define NODE_MAX 41
-#endif
-std::map<std::string, ecf_node_maker*>& ecf_node_maker::map()
-{
- static std::map<std::string, ecf_node_maker*> map_;
- return map_;
-}
-
-std::vector<ecf_node_maker*>& ecf_node_maker::builders()
-{
- static std::vector<ecf_node_maker*> builders_((size_t)NODE_MAX,(ecf_node_maker*)0);
- return builders_;
-}
-
-void ecf_node::counter() {
- int count = 0; node* n = 0x0; if (node_) n = node_->kids();
- while (n) {
- std::cerr << "# " << n->full_name() << " " << n->type() << "\n";
- n = n->next();
- count++;
- }
- if (count) {
- std::cerr << "# " << full_name() << " kids: " << count << "\n";
- }
-}
-
-void ecf_node::update(const Node* n, const std::vector<ecf::Aspect::Type>&)
-{
- if (!node_) return;
- /* ok node create through node replace is simple update */
- node_->update(-1, -1, -1);
- node_->notify_observers();
- node_->redraw();
-}
-
-int convert(NState::State state) {
- int rc = STATUS_UNKNOWN;
- switch (state) {
- case NState::UNKNOWN : rc= STATUS_UNKNOWN; break;
- case NState::COMPLETE: rc= STATUS_COMPLETE; break;
- case NState::QUEUED: rc= STATUS_QUEUED; break;
- case NState::ABORTED: rc= STATUS_ABORTED; break;
- case NState::SUBMITTED: rc= STATUS_SUBMITTED;break;
- case NState::ACTIVE: rc= STATUS_ACTIVE; break;
- default: rc = STATUS_UNKNOWN; break;
- }
- return rc;
-}
-
-int convert(DState::State state) {
- int rc = STATUS_UNKNOWN;
- switch (state) {
- case DState::UNKNOWN : rc= STATUS_UNKNOWN; break;
- case DState::COMPLETE: rc= STATUS_COMPLETE; break;
- case DState::QUEUED: rc= STATUS_QUEUED; break;
- case DState::ABORTED: rc= STATUS_ABORTED; break;
- case DState::SUBMITTED: rc= STATUS_SUBMITTED;break;
- case DState::ACTIVE: rc= STATUS_ACTIVE; break;
- default: rc = STATUS_UNKNOWN; break;
- }
- return rc;
-}
-
-void ecf_node::update(const Defs*, const std::vector<ecf::Aspect::Type>&)
-{
- if (!node_) return;
- node_->update(-1, -1, -1);
- node_->notify_observers();
- node_->redraw();
-}
-
-void ecf_node::update_delete(const Node* n) {
- if (!node_) return;
- node_->unlink();
- node *parent = node_->parent();
- node_->visibility(False);
- node_->remove();
- delete node_;
- node_ = 0x0;
- notify_observers();
- if (parent) {
- parent->folded_ = true;
- parent->update(-1, -1, -1);
- parent->notify_observers();
- parent->redraw();
- }
-}
-
-void ecf_node::update_delete(const Defs* n) {
- if (node_) node_->unlink();
- node_ = 0x0;
- notify_observers();
-}
-
-void ecf_node::unlink(bool detach) {
- if (detach) {}
- else if (node_)
- node_->unlink();
- node_ = 0x0;
-}
-
-const Repeat& ecf_node::crd() { static const Repeat REPEAT = Repeat( RepeatInteger("PRB", 1, 1, 1) ); return REPEAT; }
-
-node* ecf_node_maker::make_xnode(host& h, ecf_node* n, std::string type)
-{
- if (!n) return NULL;
- node* out = NULL;
-
- if (n->type() >= 0 && n->type() < NODE_MAX && builders()[n->type()]) {
- if (n->type() == NODE_REPEAT)
- out = map()[type]->make(h, n);
- else
- out = builders()[n->type()]->make(h, n);
- n->set_graphic_ptr(out);
- }
- else {
- std::cout << "!!!" << n->full_name() << n->type() << " " << n->name() << " " << n->type_name() << "\n";
- if (map()[type]) {
- out = map()[type]->make(h, n);
- assert(out);
- n->set_graphic_ptr(out);
- std::cout << "!!!ok\n";
- }
- }
- return out;
-}
-
-ecf_node::ecf_node(ecf_node* parent, const std::string& name, char k)
- : parent_(parent), node_(0), kind_(k)
- , name_(name)
- , trigger_(0)
- , complete_(0)
-{
-}
-
-ecf_node::~ecf_node()
-{
- // std::cerr << "# eode del: " << full_name_ << std::endl;
- nokids(true);
- unlink();
- delete trigger_;
- delete complete_;
-}
-
-node* ecf_node::create_tree(host& h, node* xnode) {
- if (xnode) { node_ = xnode; }
- else if (node_) return node_;
- else if (!(node_ = create_node(h))) { return 0x0; }
- if (get_node())
- get_node()->set_graphic_ptr(node_);
-
- for(std::vector<ecf_node*>::const_iterator
- j = kids_.begin(); j != kids_.end(); ++j)
- if (*j)
- node_->insert((*j)->create_tree(h, 0x0));
-
- return node_;
-}
-
-void ecf_node::add_kid(ecf_node* k) {
- if (k)
- kids_.push_back(k);
-}
-
-template<> const std::string& ecf_concrete_node<Defs>::name() const
-{ return ecf_node::slash(); }
-
-template<>
-void ecf_concrete_node<Node>::why(std::ostream&f) const
-{
- if (!owner_) return;
- std::vector<std::string> theReasonWhy;
- std::vector<std::string>::const_iterator it;
- owner_->bottom_up_why(theReasonWhy);
- for (it=theReasonWhy.begin(); it != theReasonWhy.end(); ++it)
- f << (*it) << "\n";
- }
-
-
-template<>
-void ecf_concrete_node<Suite>::why(std::ostream &f) const
-{
- if (!owner_) return;
- std::vector<std::string> theReasonWhy;
- std::vector<std::string>::const_iterator it;
- owner_->bottom_up_why(theReasonWhy);
- for (it=theReasonWhy.begin(); it != theReasonWhy.end(); ++it)
- f << (*it) << "\n";
- }
-
-template<>
-void ecf_concrete_node<Defs>::why(std::ostream &f) const
-{
- if (!owner_) return;
- std::vector<std::string> theReasonWhy;
- std::vector<std::string>::const_iterator it;
- owner_->why(theReasonWhy);
- for (it=theReasonWhy.begin(); it != theReasonWhy.end(); ++it)
- f << (*it) << "\n";
-}
-
-#define UNLINK(T) template<> void ecf_concrete_node<T>::unlink(bool detach) \
-{ if (!owner_) return; if (detach) ChangeMgrSingleton::instance()->detach(owner_,this); owner_ = 0x0; }
-UNLINK(Alias)
-UNLINK(Task)
-UNLINK(Family)
-UNLINK(Suite)
-UNLINK(Node)
-UNLINK(Defs)
-#undef UNLINK
-
-#define SORT_VAR 1
-#ifdef SORT_VAR
-struct cless_than {
- inline bool operator() (const Variable& v1, const Variable& v2) {
- return (v1.name() < v2.name()); }
-};
-#endif
-
-template<>
-void ecf_concrete_node<Alias>::make_subtree() {
-
- if (!owner_) return;
- Alias* n = owner_;
-
- full_name_ = owner_->absNodePath();
-
- ChangeMgrSingleton::instance()->attach(owner_, this);
- n->update_generated_variables();
-
- std::vector<Variable> gvar;
- n->gen_variables(gvar);
- std::vector<Variable>::const_iterator it;
-#ifdef SORT_VAR
- std::sort(gvar.begin(),gvar.end(),cless_than());
-#endif
-
- for (it = gvar.begin(); it != gvar.end(); ++it)
- if ((*it).name() == "" || !(*it == Variable::EMPTY()))
- add_kid(make_node(*it, this, 'g'));
- else std::cerr << "# empty variable\n";
-
-#ifdef SORT_VAR
- gvar = n->variables(); /* expensive */
- std::sort(gvar.begin(),gvar.end(),cless_than());
- make_kids_list(this,gvar);
-#else
- make_kids_list(this,n->variables());
-#endif
-
- make_kids_list(this,n->labels());
- make_kids_list(this,n->events());
- make_kids_list(this,n->meters());
-}
-
-template<>
-void ecf_concrete_node<Node>::make_subtree() {
-
- if (!owner_) return;
- Node* n = owner_;
-
- full_name_ = owner_->absNodePath();
- ChangeMgrSingleton::instance()->attach(owner_, this);
-
- if (owner_->suite()->begun())
- owner_->update_generated_variables();
-
- std::vector<node_ptr> kids; n->immediateChildren(kids);
- make_kids_list(this,kids);
-
- std::vector<Variable> gvar;
- n->gen_variables(gvar);
-#ifdef SORT_VAR
- std::sort(gvar.begin(),gvar.end(),cless_than());
-#endif
-
- std::vector<Variable>::const_iterator it;
- for (it = gvar.begin(); it != gvar.end(); ++it)
- if (!(*it == Variable::EMPTY()))
- add_kid(make_node(*it, this, 'g'));
- else std::cerr << "# empty variable\n";
-
-#ifdef SORT_VAR
- gvar = n->variables(); /* expensive */
- std::sort(gvar.begin(),gvar.end(),cless_than());
- make_kids_list(this,gvar);
-#else
- make_kids_list(this,n->variables());
-#endif
-
- make_kids_list(this,n->labels());
- make_kids_list(this,n->events());
- make_kids_list(this,n->meters());
-
- make_kids_list(this,n->timeVec());
- make_kids_list(this,n->todayVec());
- make_kids_list(this,n->crons());
-
- make_kids_list(this,n->dates());
- make_kids_list(this,n->days());
-
- make_kids_list(this,n->limits());
- make_kids_list(this,n->inlimits());
-
- if (n->get_trigger()) {
- trigger_ = new ExpressionWrapper(n, 't');
- add_kid(make_node(trigger_, this, 't'));
- }
- if (n->get_complete()) {
- complete_ = new ExpressionWrapper(n, 'c');
- add_kid(make_node(complete_, this, 'c'));
- }
-
- if (n->get_late() != 0x0) { add_kid(make_node(n->get_late(), this)); }
-
- if ((!n->repeat().empty()) && "" != n->repeat().name()) {
- RepeatEnumerated *re;
- RepeatDate *rd;
- RepeatString *rs;
- RepeatInteger *ri;
- RepeatDay *rday;
-
- if ((re = dynamic_cast<RepeatEnumerated *>(n->repeat().repeatBase())))
- add_kid(make_node(re, this));
- else if ((rd = dynamic_cast<RepeatDate *>(n->repeat().repeatBase())))
- add_kid(make_node(rd, this));
- else if ((rs = dynamic_cast<RepeatString *>(n->repeat().repeatBase())))
- add_kid(make_node(rs, this));
- else if ((ri = dynamic_cast<RepeatInteger *>(n->repeat().repeatBase())))
- add_kid(make_node(ri, this));
- else if ((rday = dynamic_cast<RepeatDay *>(n->repeat().repeatBase())))
- {}
- else
- std::cerr << "# ecflfowview does not recognises this repeat item\n";
- }
-}
-
-template<>
-void ecf_concrete_node<Suite>::make_subtree() {
-
- if (!owner_) return;
- Suite* n = owner_;
- if (n->begun())
- n->update_generated_variables();
-
- full_name_ = owner_->absNodePath(); // "/" + n->name();
-
- ChangeMgrSingleton::instance()->attach(owner_, this);
-
- std::vector<node_ptr> kids; n->immediateChildren(kids);
- make_kids_list(this,kids);
-
- std::vector<Variable> gvar;
- n->gen_variables(gvar);
-
- std::vector<Variable>::const_iterator it;
- for (it = gvar.begin(); it != gvar.end(); ++it)
- if (!(*it == Variable::EMPTY()))
- add_kid(make_node(*it, this, 'g'));
- else std::cerr << "# empty variable\n";
-
-#ifdef SORT_VAR
- gvar = n->variables(); /* expensive */
- std::sort(gvar.begin(),gvar.end(),cless_than());
- make_kids_list(this,gvar);
-#else
- make_kids_list(this,n->variables());
-#endif
- make_kids_list(this,n->labels());
- make_kids_list(this,n->events());
- make_kids_list(this,n->meters());
-
- make_kids_list(this,n->timeVec());
- make_kids_list(this,n->todayVec());
- make_kids_list(this,n->crons());
-
- make_kids_list(this,n->dates());
- make_kids_list(this,n->days());
-
- make_kids_list(this,n->limits());
- make_kids_list(this,n->inlimits());
-
- if (n->get_trigger()) {
- trigger_ = new ExpressionWrapper(n, 't');
- add_kid(make_node(trigger_, this, 't'));
- }
- if (n->get_complete()) {
- complete_ = new ExpressionWrapper(n, 'c');
- add_kid(make_node(complete_, this, 'c'));
- }
-
- if (n->get_late() != 0x0) { add_kid(make_node(n->get_late(), this)); }
- if ((!n->repeat().empty())) {
- RepeatEnumerated *re;
- RepeatDate *rd;
- RepeatString *rs;
- RepeatInteger *ri;
- RepeatDay *rday;
-
- if ((re = dynamic_cast<RepeatEnumerated *>(n->repeat().repeatBase())))
- add_kid(make_node(re, this));
- else if ((rd = dynamic_cast<RepeatDate *>(n->repeat().repeatBase())))
- add_kid(make_node(rd, this));
- else if ((rs = dynamic_cast<RepeatString *>(n->repeat().repeatBase())))
- add_kid(make_node(rs, this));
- else if ((ri = dynamic_cast<RepeatInteger *>(n->repeat().repeatBase())))
- add_kid(make_node(ri, this));
- else if ((rday = dynamic_cast<RepeatDay *>(n->repeat().repeatBase())))
- add_kid(make_node(rday, this));
- else
- std::cerr << "# ecflfowview does not recognises this repeat item\n";
- }
-}
-
-template<>
-const std::string& ecf_concrete_node<Defs>::variable(const std::string& name) const
-{
- Defs* n = owner_;
- if (!n) return ecf_node::none();
-
- const Variable & var = owner_->server().findVariable(name);
- if (!var.empty())
- return var.theValue();
-
- return ecf_node::none();
-}
-
-template<>
-const std::string& ecf_concrete_node<Node>::variable(const std::string& name) const
-{
- if (!owner_)
- return ecf_node::none();
-
- const Variable & var = owner_->findVariable(name);
- if (!var.empty())
- return var.theValue();
-
- return ecf_node::none();
-}
-
-template<>
-const std::string& ecf_concrete_node<Suite>::variable(const std::string& name) const
-{
- if (!owner_)
- return ecf_node::none();
-
- const Variable& var = owner_->findVariable(name);
- if (!var.empty())
- return var.theValue();
-
- return ecf_node::none();
-}
-
-template<> ecf_concrete_node<const Variable>::
-ecf_concrete_node(const Variable *owner, ecf_node *parent, const char c)
- : ecf_node(parent, owner->name(), c)
- , owner_(owner)
-{
-}
-
-template<>
-const std::string& ecf_concrete_node<const Event>::full_name() const
-{
- full_name_ = parent()->full_name();
- full_name_ += ":";
- full_name_ += name();
- return full_name_;
-}
-template<>
-const std::string& ecf_concrete_node<const Meter>::full_name() const
-{
- full_name_ = parent()->full_name();
- full_name_ += ":";
- full_name_ += name();
- return full_name_;
-}
-template<>
-const std::string& ecf_concrete_node<const Repeat>::full_name() const
-{
- full_name_ = parent()->full_name();
- full_name_ += ":";
- full_name_ += name();
- return full_name_;
-}
-template<>
-const std::string& ecf_concrete_node<const Variable>::full_name() const
-{
- full_name_ = parent()->full_name();
- full_name_ += ":";
- full_name_ += name();
- return full_name_;
-}
-
-template<>
-const std::string& ecf_concrete_node<const std::pair<std::string, std::string> >
-::full_name() const
-{
- full_name_ = parent()->full_name();
- full_name_ += ":";
- full_name_ += name();
- return full_name_;
-}
-
-template<>
-ecf_concrete_node<const std::pair<std::string, std::string> >::
-ecf_concrete_node(const std::pair<std::string, std::string> *owner,
- ecf_node *parent, const char c)
- : ecf_node(parent, owner->first, c)
- , owner_(owner)
-{
-}
-
-template<>
-std::ostream& ecf_concrete_node<Defs>::print(std::ostream& s) const
-{
- if (owner_)
- owner_->print(s);
- return s;
-}
-
-template<>
-std::ostream& ecf_concrete_node<Node>::print(std::ostream& s) const
-{
- if (owner_)
- owner_->print(s);
- return s;
-}
-
-template<>void ecf_concrete_node<Defs>::print(std::ostream& s){ }
-template<>void ecf_concrete_node<Node>::print(std::ostream& s){ }
-
-template<> const std::string& ecf_concrete_node<Defs>::full_name() const
-{ return ecf_node::slash(); }
-
-void hide(node* n) {
- while (n) {
- n->visibility(False);
- hide(n->kids());
- n = n->next();
- }
-}
-
-void ecf_node::nokids(bool own) {
- if (node_) { node::destroy(node_->kids_); node_->kids_ = 0x0; }
-
- for (size_t i = 0; i < kids_.size(); i++) {
- delete kids_[i];
- }
- kids_.clear();
-}
-
-int redraw_kids(node* node_,
- const std::vector<ecf::Aspect::Type>& aspect) {
- int tot = 0;
- for(std::vector<ecf::Aspect::Type>::const_iterator it = aspect.begin(); it != aspect.end(); ++it) {
- int kind = 0;
- switch ( *it ) {
- case ecf::Aspect::METER:
- kind = NODE_METER;
- break;
- case ecf::Aspect::LABEL:
- kind = NODE_LABEL;
- break;
- case ecf::Aspect::EVENT:
- kind = NODE_EVENT;
- break;
- case ecf::Aspect::LIMIT:
- kind = NODE_LIMIT;
- break;
- default:
- continue;
- }
- ++tot;
- if (kind)
- for(node *xn = node_->kids(); xn; xn = xn->next())
- if (xn) if (xn->type() == kind) {
- xn->update(-1, -1, -1);
- xn->redraw();
- }
- }
- return tot;
-}
-
-template<>
-void ecf_concrete_node<Node>::update(const Node* n,
- const std::vector<ecf::Aspect::Type>& aspect)
-{
- if (!owner_) return;
- if (!node_) return;
- if (is_reset(aspect)) {
- Updating::set_full_redraw();
- return;
- }
-
- node_->delvars();
- if (owner_->suite()->begun()) {
- owner_->update_generated_variables();
- }
- std::vector<Variable> gvar;
- n->gen_variables(gvar);
- std::vector<Variable>::const_iterator it, gvar_end;
- for(it = gvar.begin(); it != gvar.end(); ++it) {
- if ((*it).name() == "" || *it == Variable::EMPTY()) {
- std::cerr << "# empty variable\n";
- continue;
- }
- ecf_node *run = make_node(*it, this, 'g');
- add_kid(run);
- node_->insert(run->create_node(node_->serv()));
- }
-
-#ifdef SORT_VAR
- gvar = n->variables(); /* expensive */
- std::sort(gvar.begin(), gvar.end(), cless_than());
- gvar_end = gvar.end();
- for(it = gvar.begin(); it != gvar_end; ++it) {
-#else
- for (it = n->variables().begin(); it != n->variables().end(); ++it) {
-#endif
- if ((*it).name() == "" || *it == Variable::EMPTY()) {
- std::cerr << "# empty variable\n";
- continue;
- }
- ecf_node *run = make_node(*it, this);
- add_kid(run);
- node_->insert(run->create_node(node_->serv()));
- }
-
- const_cast<Node*>(n)->set_graphic_ptr(xnode());
- if (redraw_kids(node_, aspect) == 1) return;
-
- node_->update(-1, -1, -1); // call pop up window with check
- node_->notify_observers();
- node_->redraw();
-}
-
-template<>
-void ecf_concrete_node<Suite>::update(const Node* n,
- const std::vector<ecf::Aspect::Type>& aspect) {
- if (!owner_) return;
- if (!node_) return;
- assert(xnode());
- const_cast<Node*> (n)->set_graphic_ptr(xnode()); /* ??? */
-
- if (is_reset(aspect)) {
-
- Updating::set_full_redraw();
- return;
- }
-
- if (owner_->begun())
- owner_->update_generated_variables();
-
- if (redraw_kids(node_, aspect) == 1) return;
-
- node_->update(-1, -1, -1);
- node_->notify_observers();
- node_->redraw();
-}
-
-template<>
-bool ecf_concrete_node<Suite>::is_late() {
- if (!owner_) return false;
- return owner_->get_late()
- ? owner_->get_late()->isLate()
- : false;
-}
-
-template<>
-bool ecf_concrete_node<Node>::is_late() {
- if (!owner_) return false;
- return owner_->get_late()
- ? owner_->get_late()->isLate()
- : false;
-}
-
-template<>
-bool ecf_concrete_node<Suite>::hasZombieAttr() {
- if (!owner_) return false;
- return owner_->zombies().size() > 0;
-}
-
-template<>
-bool ecf_concrete_node<Node>::hasZombieAttr() {
- if (!owner_) return false;
- return owner_->zombies().size() > 0;
-}
-
-template<>
-bool ecf_concrete_node<Node>::hasTime() {
- return owner_ ? (owner_->timeVec().size() > 0 ||
- owner_->todayVec().size() > 0 ||
- owner_->crons().size() > 0)
- : false;
-}
-
-template<>
-bool ecf_concrete_node<Suite>::hasTime() {
- return owner_ ? (owner_->timeVec().size() > 0 ||
- owner_->todayVec().size() > 0 ||
- owner_->crons().size() > 0)
- : false;
-}
-
-template<>
-bool ecf_concrete_node<Family>::hasTime() {
- return owner_ ? (owner_->timeVec().size() > 0 ||
- owner_->todayVec().size() > 0 ||
- owner_->crons().size() > 0)
- : false;
-}
-
-template<>
-bool ecf_concrete_node<Node>::hasTrigger() {
- return owner_ ? (owner_->triggerAst() ||
- owner_->completeAst())
- : false;
-}
-
-template<>
-bool ecf_concrete_node<Node>::hasDate() {
- return owner_ ? (owner_->days().size() > 0 ||
- owner_->dates().size() > 0)
- : false;
-}
-
-template<>
-bool ecf_concrete_node<Suite>::hasDate() {
- return owner_ ? (owner_->days().size() > 0 ||
- owner_->dates().size() > 0)
- : false;
-}
-
-template<>
-bool ecf_concrete_node<Family>::hasDate() {
- return owner_ ? (owner_->days().size() > 0 ||
- owner_->dates().size() > 0)
- : false;
-}
-
-
-template<> ecf_concrete_node<const Event>::
-ecf_concrete_node(const Event* owner,ecf_node* parent, const char c)
- : ecf_node(parent, owner ? owner->name_or_number() : ecf_node::none(), c)
- , owner_(owner)
-{}
-
-template<>
-const std::string ecf_concrete_node<ExpressionWrapper>::toString() const
- { if (owner_) return owner_->expression(); return ecf_node::none(); }
-
-template<>
-const std::string ecf_concrete_node<Expression>::toString() const
-{ if (owner_) return owner_->expression();
- return ecf_node::none(); }
-
-template<>
-const std::string ecf_concrete_node<external>::toString() const
-{ return ecf_node::none(); }
-
-template<>
-const std::string ecf_concrete_node<dummy_node>::toString() const
-{ return ecf_node::none(); }
-
-template<>
-const std::string ecf_concrete_node<AstTop>::toString() const
-{ return owner_ ? owner_->expression() : ecf_node::none(); }
-
-template<>
-const std::string ecf_concrete_node<Suite>::toString() const
-{ return owner_ ? owner_->name() : ecf_node::none(); }
-
-template<>
-const std::string ecf_concrete_node<Node>::toString() const
-{ return owner_ ? owner_->name() : ecf_node::none(); }
-
-template<>
-const std::string ecf_concrete_node<Defs>::toString() const
-{ return ecf_node::slash(); }
-
-template<>
-const std::string ecf_concrete_node<RepeatDay>::toString() const
-{ if (parent())
- return parent()->get_repeat().toString();
- return none();
-}
-
-template<>
-const std::string ecf_concrete_node<RepeatDate>::toString() const
-{ if (parent())
- return parent()->get_repeat().toString();
- return none();
-}
-
-template<>
-const std::string ecf_concrete_node<RepeatEnumerated>::toString() const
-{ if (parent())
- return parent()->get_repeat().toString();
- return none();
-}
-
-template<>
-const std::string ecf_concrete_node<RepeatString>::toString() const
-{ if (parent())
- return parent()->get_repeat().toString();
- return none();
-}
-
-template<>
-const std::string ecf_concrete_node<RepeatInteger>::toString() const
-{ if (parent())
- return parent()->get_repeat().toString();
- return none();
-}
-
-template<>
-const std::string ecf_concrete_node<const std::pair<std::string, std::string> >
-::toString() const
-{ if (owner_) return owner_->first + " : " + owner_->second; return "pair"; }
-
-template<> int ecf_concrete_node<const Event>::status() const
-{ return owner_ ? owner_->value() : 0; }
-
-template<> boost::posix_time::ptime ecf_concrete_node<Suite>::status_time() const
-{
- if (owner_) return owner_->state_change_time();
- return boost::posix_time::ptime();
-}
-
-template<> boost::posix_time::ptime ecf_concrete_node<Family>::status_time() const
-{
- if (owner_) return owner_->state_change_time();
- return boost::posix_time::ptime();
-}
-
-template<> boost::posix_time::ptime ecf_concrete_node<Node>::status_time() const
-{
- if (owner_) return owner_->state_change_time();
- return boost::posix_time::ptime();
-}
-
-template<> int ecf_concrete_node<Suite>::status() const
-{
- int rc = STATUS_UNKNOWN;
- if (!owner_) return rc;
- else if (!owner_->begun()) return rc;
- else rc = convert(owner_->state());
- return owner_->isSuspended() ? STATUS_SUSPENDED : rc;
-}
-
-template<> int ecf_concrete_node<Node>::status() const
-{
- int rc = STATUS_UNKNOWN;
- if (!owner_) return rc;
- else rc = convert(owner_->state());
- return owner_->isSuspended() ? STATUS_SUSPENDED : rc;
-}
-
-template<> int ecf_concrete_node<Defs>::status() const
-{
- int rc = STATUS_UNKNOWN;
- if (!owner_) return rc;
- switch (owner_->server().get_state()) {
- case SState::HALTED: rc = STATUS_HALTED; break;
- case SState::SHUTDOWN: rc = STATUS_SHUTDOWN; break;
- case SState::RUNNING: rc = convert(owner_->state()); break;
- }
- return rc;
-}
-
-template<> int ecf_concrete_node<Suite>::defstatus() const
-{
- return owner_ ? convert(owner_->defStatus()) : STATUS_QUEUED;
-}
-
-template<> int ecf_concrete_node<Node>::defstatus() const
-{
- return owner_ ? convert(owner_->defStatus()) : STATUS_QUEUED;
-}
-
-template<>int ecf_concrete_node<Defs>::flags() const {
- return owner_ ? owner_->flag().flag() : 0;
-}
-
-template<>int ecf_concrete_node<Node>::flags() const {
- return owner_ ? owner_->flag().flag() : 0;
-}
-template<>int ecf_concrete_node<Suite>::flags() const {
- return owner_ ? owner_->flag().flag() : 0;
-}
-
-template<>int ecf_concrete_node<Node>::type() const {
- int rc = NODE_UNKNOWN;
- if (!owner_) return rc;
- if (owner_->isFamily()) rc = NODE_FAMILY;
- else if (owner_->isAlias()) rc = NODE_ALIAS;
- else if (owner_->isTask()) rc = NODE_TASK;
- else if (owner_->isSuite()) rc = NODE_SUITE;
- return rc;
-}
-
-template<>int ecf_concrete_node<Alias>::type() const { return NODE_ALIAS; }
-template<>int ecf_concrete_node<Suite>::type() const { return NODE_SUITE; }
-template<>int ecf_concrete_node<Family>::type() const { return NODE_FAMILY; }
-template<>int ecf_concrete_node<Defs>::type() const { return NODE_SUPER; }
-template<>int ecf_concrete_node<const ecf::TimeAttr>::type() const { return NODE_TIME; }
-template<>int ecf_concrete_node<const ecf::TodayAttr>::type() const { return NODE_TIME; }
-template<>int ecf_concrete_node<const ecf::CronAttr>::type() const { return NODE_TIME; }
-template<>int ecf_concrete_node<const DateAttr>::type() const { return NODE_DATE; }
-template<>int ecf_concrete_node<DateAttr>::type() const { return NODE_DATE; }
-template<>int ecf_concrete_node<const DayAttr>::type() const { return NODE_DATE; }
-// template<>int ecf_concrete_node<RepeatBase>::type() const { return NODE_REPEAT; }
-template<>int ecf_concrete_node<RepeatEnumerated>::type() const { return NODE_REPEAT_E; }
-template<>int ecf_concrete_node<RepeatString>::type() const { return NODE_REPEAT_S; }
-template<>int ecf_concrete_node<RepeatDate>::type() const { return NODE_REPEAT_D; }
-template<>int ecf_concrete_node<RepeatInteger>::type() const { return NODE_REPEAT_I; }
-template<>int ecf_concrete_node<RepeatDay>::type() const { return NODE_REPEAT_DAY; }
-template<>int ecf_concrete_node<const ecf::LateAttr>::type() const { return NODE_LATE; }
-template<>int ecf_concrete_node<ecf::LateAttr>::type() const { return NODE_LATE; }
-
-template<>int ecf_concrete_node<const Event>::type() const { return NODE_EVENT; }
-template<>int ecf_concrete_node<const Label>::type() const { return NODE_LABEL; }
-template<>int ecf_concrete_node<const Meter>::type() const { return NODE_METER; }
-
-template<>int ecf_concrete_node<const Variable>::type() const { return NODE_VARIABLE; }
-template<>int ecf_concrete_node<ExpressionWrapper>::type() const { return NODE_TRIGGER; }
-template<>int ecf_concrete_node<Variable>::type() const { return NODE_VARIABLE;}
-template<>int ecf_concrete_node<const std::pair<std::string, std::string> >
-::type() const { return NODE_VARIABLE; }
-
-template<>int ecf_concrete_node<Limit>::type() const { return NODE_LIMIT; }
-template<>int ecf_concrete_node<const InLimit>::type() const
-{ return NODE_INLIMIT; }
-
-template<>int ecf_concrete_node<Expression>::type() const { return NODE_TRIGGER; }
-template<> int ecf_concrete_node<dummy_node>::type() const { return NODE_UNKNOWN; }
-template<> int ecf_concrete_node<dummy_node>::status() const { return STATUS_UNKNOWN; }
-template<> const std::string& ecf_concrete_node<dummy_node>::name() const { return owner_->name(); }
-template<> const std::string& ecf_concrete_node<dummy_node>::full_name() const
-{ return owner_ ? owner_->name() : ecf_node::none(); }
-template<> void ecf_concrete_node<dummy_node>::set_graphic_ptr(node* n){}
-
-template<> int ecf_concrete_node<external>::type() const { return NODE_UNKNOWN; }
-
-template<>
-int ecf_concrete_node<Node>::tryno() {
- int num = -1;
- if (owner_) {
- Submittable* submittable = owner_->isSubmittable();
- if ( submittable )
- num = submittable->try_no();
- }
- return num;
-}
-
-template<>
-void ecf_concrete_node<Suite>::set_graphic_ptr(node* n)
-{ return owner_->set_graphic_ptr(n); }
-
-template<>
-void ecf_concrete_node<Node>::set_graphic_ptr(node* n)
-{ return owner_->set_graphic_ptr(n); }
-
-const std::string& ecf_node::no_owner() { static const std::string NO_OWNER = "(no owner)"; return NO_OWNER; }
-const std::string& ecf_node::none() { static const std::string NONE = "(none)"; return NONE; }
-const std::string& ecf_node::slash() { static const std::string SLASH = "/"; return SLASH; }
-
-ExpressionWrapper::ExpressionWrapper(Node* n, char c) :
- node_(n), kind_(c) {
- if (n) {
- if (c=='c')
- mem = n->completeExpression();
- else
- mem = n->triggerExpression();
- }
-}
-
-const std::string & ExpressionWrapper::name() const
-{
- return ecf_node::none();
-}
-
-const std::string & ExpressionWrapper::full_name() const
-{
- return ecf_node::none();
-}
-const std::string & ExpressionWrapper::toString() const
-{
- return mem;
-}
-
-void ecf_node::delvars() {
- for (size_t i = 0; i < kids_.size(); i++) {
- if (kids_[i]->type() == NODE_VARIABLE) {
- kids_.erase(kids_.begin() + i);
- }
- }
-}
-
-template<>
-std::string ecf_concrete_node<Suite>::get_var(const std::string& name,
- bool is_gen,
- bool substitute)
-{
- if (!is_gen) { // user variable have priority
- const Variable& var = owner_->findVariable(name);
- if (!var.empty()) {
- std::string value = var.theValue();
- if (substitute)
- owner_->variableSubsitution(value);
- return value;
- }
- }
- if ((!owner_->repeat().empty()) && name == owner_->repeat().name()) {
- return owner_->repeat().valueAsString();
- }
- return owner_->findGenVariable(name).theValue();
-}
-
-template<>
-std::string ecf_concrete_node<Node>::get_var(const std::string& name,
- bool is_gen,
- bool substitute)
- {
- if (!is_gen) { // user variable have priority
- const Variable& var = owner_->findVariable(name);
- if (!var.empty()) {
- std::string value = var.theValue();
- if (substitute)
- owner_->variableSubsitution(value);
- return value;
- }
- }
- if ((!owner_->repeat().empty()) && name == owner_->repeat().name()) {
- return owner_->repeat().valueAsString();
- }
- return owner_->findGenVariable(name).theValue();
-}
-
-template<>
-std::string ecf_concrete_node<Defs>::get_var(const std::string& name,
- bool is_gen,
- bool substitute)
-{ if (!is_gen) { // user variable have priority
- const Variable& var = owner_->server().findVariable(name);
- if (!var.empty()) {
- std::string value = var.theValue();
- if (substitute)
- owner_->server().variableSubsitution(value);
- return value;
- }
- }
- return owner_->server().findVariable(name).theValue();
-}
-
-template<>
-Limit* ecf_concrete_node<Limit>::get_limit(const std::string& name)
-{ return owner_; }
-template<>
-const Label& ecf_concrete_node<Node>::get_label(const std::string& name)
-{ return owner_ ? owner_->find_label(name) : Label::EMPTY(); }
-template<>
-const Event& ecf_concrete_node<Node>::get_event(const std::string& name)
-{ return owner_ ? owner_->findEvent(name) : Event::EMPTY(); }
-template<>
-const Meter& ecf_concrete_node<Node>::get_meter(const std::string& name)
-{ return owner_ ? owner_->findMeter(name) : Meter::EMPTY(); }
-template<>
-const Repeat& ecf_concrete_node<Node>::get_repeat()
-{ return owner_ ? owner_->repeat() : crd(); }
-
-template<>
-const Label& ecf_concrete_node<Suite>::get_label(const std::string& name)
-{ return owner_ ? owner_->find_label(name) : Label::EMPTY(); }
-template<>
-const Event& ecf_concrete_node<Suite>::get_event(const std::string& name)
-{ return owner_ ? owner_->findEvent(name) : Event::EMPTY(); }
-template<>
-const Meter& ecf_concrete_node<Suite>::get_meter(const std::string& name)
-{ return owner_ ? owner_->findMeter(name) : Meter::EMPTY(); }
-
-template<>
-const Repeat& ecf_concrete_node<Suite>::get_repeat()
-{
- return owner_ ? owner_->repeat() : crd();
-}
-
-template<>
-Node* ecf_concrete_node<Node>::get_node() const { return owner_; }
-template<>
-Node* ecf_concrete_node<Alias>::get_node() const { return owner_; }
-template<>
-Node* ecf_concrete_node<Suite>::get_node() const { return owner_; }
-template<>
-Node* ecf_concrete_node<Defs>::get_node() const { return 0x0; }
-
-const char* ecf_node_name(int ii) {
-
- static char* types[] = {
- (char*)"list", (char*)"user", (char*)"connection",(char*)"variable",
- (char*)"time", (char*)"date", (char*)"trigger", (char*)"tree",
- (char*)"action", (char*)"event", (char*)"task", (char*)"family",
- (char*)"suite", (char*)"super", (char*)"passwd", (char*)"login",
- (char*)"status", (char*)"reply", (char*)"check", (char*)"nid",
- (char*)"file", (char*)"handle", (char*)"repeat", (char*)"dir",
- (char*)"meter", (char*)"label", (char*)"cancel", (char*)"migrate",
- (char*)"late", (char*)"restore", (char*)"complete", (char*)"nickname",
- (char*)"alias", (char*)"limit", (char*)"inlimit", (char*)"unknown",
- (char*)"repeat-e", (char*)"repeat-s", (char*)"repeat-d", (char*)"repeat-i",
- // (char*)"zombie", (char*)"project", (char*)"object", (char*)"call",
- (char*)"cron",
- NULL};
- int size = sizeof(types) / sizeof(char*);
- if (ii >= size) return "out of bound";
- return (const char*) types[ii];
-}
-
-const std::string ecf_node::type_name() const { return ecf_node_name(type()); }
-
-template<>
-void ecf_concrete_node<Defs>::make_subtree() {
- full_name_ = "/";
- if (!owner_) return;
-
- ChangeMgrSingleton::instance()->attach(owner_, this);
- make_kids_list(this,owner_->suiteVec());
-
- std::vector<Variable> gvar = owner_->server().user_variables();
- std::sort(gvar.begin(),gvar.end(),cless_than());
- make_kids_list(this,gvar);
-
- std::vector<Variable>::const_iterator it;
- gvar = owner_->server().server_variables();
- for (it = gvar.begin(); it != gvar.end(); ++it)
- if (!(*it == Variable::EMPTY()))
- add_kid(make_node(*it, this, 'g'));
- else std::cerr << "# empty variable\n";
-}
-
-
-template<>
-void ecf_concrete_node<Defs>::update(const Defs* n,
- const std::vector<ecf::Aspect::Type>& aspect) {
- if (!owner_) return;
- if (!node_) return;
- if (is_reset(aspect)) {
-
- Updating::set_full_redraw();
-
- XECFDEBUG {
- for (std::vector<suite_ptr>::const_iterator i = n->suiteVec().begin();
- i != n->suiteVec().end(); ++i) {
- std::cout << "suite name " << (*i)->name() << "\n";
- }}
-
- return;
- }
-
- { node_->update(-1, -1, -1); node_->notify_observers(); node_->redraw(); }
-}
-
-ecf_node* ecf_node::dummy_node()
-{
- ecf_concrete_node<external> *n = new ecf_concrete_node<external>(0x0, 0x0, 'e');
- return n;
-}
-
diff --git a/ecflow_4_0_7/view/src/ecf_node.h b/ecflow_4_0_7/view/src/ecf_node.h
deleted file mode 100644
index bf78261..0000000
--- a/ecflow_4_0_7/view/src/ecf_node.h
+++ /dev/null
@@ -1,582 +0,0 @@
-#ifndef ecf_node_H
-#define ecf_node_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #65 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "observable.h"
-class host;
-class ecf_node;
-#include "ecflowview.h"
-#include <iostream>
-#include <deque>
-#include <ChangeMgrSingleton.hpp>
-class node;
-#include <boost/shared_ptr.hpp>
-#include <boost/enable_shared_from_this.hpp>
-
-#if 0
-struct ext_node;
-struct ext_list {
- int type_;
- char *name_;
- struct ext_list *next;
-
- const std::string name() {return name_;}
-};
-
-struct ext_tree {int type_;
- char *name;
- struct ext_tree *left, *right;
- int mtype, level;
- struct ext_tree *math;
-};
-
-struct ext_trigger {
- int type_;
- char *name;
- struct ext_trigger *next_;
- int status_, nid_, num_;
- struct ext_node *parent;
- void* user_ptr;
- int uint_;
- struct ext_node *kids_;
- int mod_no;
- ext_tree* math;
-};
-
-struct ext_node {
- int type_;
- char *name_;
- struct ext_node *next_;
- int status_, nid_, num_;
- struct ext_node *parent;
- void* user_ptr_;
- int uint_;
- struct ext_node *kids_;
- int defs_, svds_, flags;
- ext_node *text, *event, *meter, *label, *time, *date,
- *trigger, *complete, *action, *autocm, *late, *limit,
- *inlimit, *wait;
- int rid, tryno_, alias, count;
- char *passwd;
- ext_node *user, *variable;
- int mod, clk, gain;
- time_t stime, btime;
- ext_node *genvars, *repeat, *log, *restore;
- char* name() const {return name_ ? name_ : getenv("USER");}
- const std::string toString() const {return name();}
- int status() const {return status_;}
- int type() const {return type_;}
- int defComplete() const {return defs_ == STATUS_COMPLETE;}
- const std::string& full_name() {
- static std::string fname;
- if (type_ == NODE_SUPER) {fname = "/";}
- else if (parent) {
- fname = parent->full_name();
- if (type_ == NODE_SUITE) {}
- else if (type_== NODE_FAMILY || type_ == NODE_TASK || type_ == NODE_ALIAS)
- fname += "/";
- else
- fname += ":";
- fname += name_;
- }
- return fname;
- }
-};
-#endif
-const char* ecf_node_name( int ii );
-
-class ecf_node_maker {
- virtual node* make( host&, ecf_node* e ) = 0;
-protected:
- static std::map<std::string, ecf_node_maker*>& map();
- static std::vector<ecf_node_maker*>& builders();
-public:
- static node* make_xnode( host& h, ecf_node* n, std::string type );
-};
-
-template<typename T, class W>
-class ecf_node_builder : public ecf_node_maker {
- virtual node* make( host& h, ecf_node* e )
- {
- return new W(h, e);
- }
-public:
- ecf_node_builder( int type )
- {
- map()[typeid(T).name()] = this;
- builders()[type] = this;
- }
- ~ecf_node_builder()
- {
- }
-};
-
-class ExpressionWrapper {
- Node* node_;
- char kind_;
- std::string mem;
-public:
- ExpressionWrapper( Node* n, char c );
-
- const std::string & name() const;
- const std::string & full_name() const;
- const std::string & toString() const;
-
- std::string expression() const
- {
- if (kind_ == 'c') return node_->completeExpression();
- return node_->triggerExpression();
- }
-
- AstTop* get_ast_top()
- {
- if (kind_ == 'c') return node_->completeAst();
- return node_->triggerAst();
- }
-};
-
-class ecf_node : public boost::enable_shared_from_this<ecf_node>
- , public observable
-{
-private:
- ecf_node* parent_;
-
-protected:
- mutable std::string full_name_;
- std::vector<ecf_node*> kids_;
- node *node_;
- char kind_; // 'c' for complete trigger
-
- const std::string name_;
-
- ExpressionWrapper *trigger_;
- ExpressionWrapper *complete_;
- friend class ecf_node_maker;
-
- void counter();
-
-public:
- ecf_node( ecf_node* parent, const std::string& name, char k );
-
- ~ecf_node();
-
- static const std::string& no_owner();
- static const std::string& none();
- static const std::string& slash();
-
- virtual void set_graphic_ptr( node* )
- {
- }
- virtual node* create_node( host& ) = 0;
- virtual node* create_tree( host& h, node* xnode = 0x0 );
- void adopt( node* n )
- {
- node_ = n;
- }
- void nokids( bool own = false );
-
- void add_kid( ecf_node* k );
-#ifdef BRIDGE
- void* user_ptr;
-#endif
-
- virtual int type() const = 0;
- virtual int flags() const = 0;
- virtual const std::string type_name() const;
- virtual void update( const Node*, const std::vector<ecf::Aspect::Type>& );
- virtual void update( const Defs*, const std::vector<ecf::Aspect::Type>& );
- virtual void update_delete( const Node* );
- virtual void update_delete( const Defs* );
-
- virtual void make_subtree() = 0;
-
- virtual const std::string toString() const
- {
- return none();
- }
- // virtual const std::string substitute(const std::string& cmd) const { return cmd; }
- virtual int status() const
- {
- return STATUS_UNKNOWN;
- }
- virtual boost::posix_time::ptime status_time() const
- {
- return boost::posix_time::ptime();
- }
- virtual int defstatus() const
- {
- return STATUS_QUEUED;
- }
- virtual int tryno()
- {
- return 0;
- }
- virtual const std::string& name() const
- {
- return name_;
- }
- virtual const std::string& full_name() const
- {
- return full_name_;
- }
-
- virtual bool is_late()
- {
- return false;
- }
- virtual bool hasZombieAttr()
- {
- return false;
- }
- virtual bool hasTime()
- {
- return false;
- }
- virtual bool hasDate()
- {
- return false;
- }
- virtual bool hasTrigger()
- {
- return false;
- }
-
- virtual std::ostream& print( std::ostream& s ) const
- {
- return s << none();
- }
- virtual void print( std::ostream& s )
- {
- s << none();
- }
- virtual const std::string& variable( const std::string& name ) const = 0;
- virtual void why( std::ostream & ) const
- {
- }
-
- virtual std::string get_var( const std::string& name, bool is_gen = false,
- bool substitute = false )
- {
- return none();
- }
-
- virtual Limit* get_limit( const std::string& name ) = 0;
- virtual Node* get_node() const = 0;
- virtual const Label& get_label( const std::string& name ) = 0;
- virtual const Event& get_event( const std::string& name ) = 0;
- virtual const Meter& get_meter( const std::string& name ) = 0;
- virtual const Repeat& get_repeat() = 0;
-
- static const Repeat& crd();
-
-private:
- ecf_node( const ecf_node& );
- ecf_node& operator=( const ecf_node& );
-
-public:
- ecf_node* parent() const
- {
- return parent_;
- }
- node* xnode() const
- {
- return node_;
- }
- char kind()
- {
- return kind_;
- }
- static ecf_node* dummy_node();
-
- virtual void unlink( bool detach = true );
- virtual void check() const
- {
- if (parent() == 0x0) std::cerr << "# ecf: no parent: " << name() << "\n";
- if (xnode() == 0x0) std::cerr << "# ecf: no xnode: " << name() << "\n";
- }
-
- void delvars();
-};
-
-template<typename T>
-class ecf_concrete_node : public ecf_node, public AbstractObserver {
-private:
- T* owner_;
-private:
- ecf_concrete_node( const ecf_concrete_node& );
- ecf_concrete_node& operator=( const ecf_concrete_node& );
-
-protected:
- virtual node* create_node( host& h )
- {
- return ecf_node_maker::make_xnode(h, this, type_name());
- }
-
-public:
- ecf_concrete_node( T* owner, ecf_node* parent, char c = 'd' )
- : ecf_node(parent, owner ? owner->name() : ecf_node::none(), c)
- , owner_(owner)
- {
- if (0 && parent) {
- full_name_ = parent->full_name();
- full_name_ += ":";
- full_name_ += name();
- }
- }
-
- ~ecf_concrete_node()
- {
- unlink();
- }
-
- virtual void set_graphic_ptr( node* )
- {
- }
-
- T* get() const
- {
- return owner_;
- }
- virtual const std::string toString() const;
-
- // virtual const std::string substitute(const std::string& cmd) const { return cmd; }
- virtual int status() const
- {
- return STATUS_UNKNOWN;
- }
- virtual int defstatus() const
- {
- return STATUS_QUEUED;
- }
- virtual boost::posix_time::ptime status_time() const
- {
- return boost::posix_time::ptime();
- }
- virtual int tryno()
- {
- return 0;
- }
- virtual int type() const
- {
- return NODE_UNKNOWN;
- }
- virtual int flags() const
- {
- return 0;
- }
- virtual const std::string& name() const
- {
- return ecf_node::name();
- }
- virtual const std::string& full_name() const
- {
- return full_name_;
- }
- virtual bool is_late()
- {
- return false;
- }
- virtual bool hasZombieAttr()
- {
- return false;
- }
- virtual bool hasTime()
- {
- return false;
- }
- virtual bool hasDate()
- {
- return false;
- }
- virtual bool hasTrigger()
- {
- return false;
- }
-
- virtual void make_subtree()
- {
- }
-
- virtual std::ostream& print( std::ostream& s ) const
- {
- return s << none();
- }
- virtual void print( std::ostream& s )
- {
- }
-
- virtual const std::string type_name() const
- {
- return typeid(owner_).name();
- }
-
- virtual void update( const Node* n, const std::vector<ecf::Aspect::Type>& asp )
- {
- if (!owner_) return;
- ecf_node::update(n, asp);
- }
- virtual void update( const Defs* n, const std::vector<ecf::Aspect::Type>& asp )
- {
- if (!owner_) return;
- ecf_node::update(n, asp);
- }
-
- void update_delete( const Node* n )
- {
- unlink();
- ecf_node::update_delete(n);
- }
- void update_delete( const Defs* n )
- {
- unlink();
- ecf_node::update_delete(n);
- }
-
- virtual const std::string& variable( const std::string& ) const
- {
- return none();
- }
- virtual void why( std::ostream & ) const
- {
- }
-
- virtual std::string get_var( const std::string& name, bool is_gen = false,
- bool substitute = false )
- {
- return none();
- }
-
- virtual void unlink( bool detach = true )
- {
- owner_ = 0x0;
- ecf_node::unlink(detach);
- }
- virtual void check() const
- {
- if (get() == 0x0) std::cerr << "# ecf: no owner: " << name() << "\n";
- ecf_node::check();
- }
-
- virtual Limit* get_limit( const std::string& name )
- {
- return 0x0;
- }
- virtual Node* get_node() const
- {
- return 0x0;
- }
- virtual const Label& get_label( const std::string& name )
- {
- return Label::EMPTY();
- }
- virtual const Event& get_event( const std::string& name )
- {
- return Event::EMPTY();
- }
- virtual const Meter& get_meter( const std::string& name )
- {
- return Meter::EMPTY();
- }
- virtual const Repeat& get_repeat()
- {
- return crd();
- }
-
-private:
- bool is_reset( const std::vector<ecf::Aspect::Type>& v ) const
- {
- bool reset = false;
- for(std::vector<ecf::Aspect::Type>::const_iterator it = v.begin(); it != v.end();
- ++it) {
- if (*it == ecf::Aspect::ORDER || *it == ecf::Aspect::ADD_REMOVE_NODE
- || *it == ecf::Aspect::ADD_REMOVE_ATTR) {
- reset = true;
- break;
- }
- }
- return reset;
- }
-};
-
-template<typename T>
-ecf_node* make_node( T* n, ecf_node* parent, char c = 'd' )
-{
- ecf_node* ec = new ecf_concrete_node<T>(n, parent, c);
- if (ec && n) {
- int type = ec->type();
- // gcc 4.7 optimisation issue, keep next line
- XECFDEBUG { if (!ec) std::cerr << "# make node " << type << "\n"; }
- if (!parent || type == NODE_SUPER || type == NODE_SUITE)
- ec->make_subtree();
- else if (type == NODE_FAMILY || type == NODE_TASK || type == NODE_ALIAS) {
- /* temp on demand:: */ec->make_subtree();
- }
- }
- // XECFDEBUG { if (!ec) std::cerr << "# no ecf\n"; if (!n) std::cerr << "# no node\n"; }
- return ec;
-}
-
-template<typename T>
-ecf_node* make_node( T& n, ecf_node* parent, const char c = 'd' )
-{
- return make_node<T>(&n, parent, c);
-}
-
-template<typename T>
-node* make_xnode( T* n, ecf_node* parent, host& h, char c = 'd' )
-{
- ecf_node* ec = make_node<T>(n, parent, c);
- if (ec) {
- node *xnode = ec->create_tree(h);
- ec->adopt(xnode); /* twice ? create is adoption */
- return xnode;
- }
- XECFDEBUG { if (!ec) std::cerr << "# no ecf2\n"; }
- return NULL;
-}
-
-template<typename T>
-node* make_xnode( T& n, ecf_node* parent, host& h, const char c = 'd' )
-{
- return make_xnode<T>(&n, parent, h, c);
-}
-
-template<typename T>
-void make_kids_list( ecf_node* parent, const std::vector<boost::shared_ptr<T> >& v )
-{
- for(typename std::vector<boost::shared_ptr<T> >::const_reverse_iterator j = v.rbegin();
- j != v.rend(); ++j) {
- parent->add_kid(make_node((*j).get(), parent));
- }
-}
-
-template<typename T>
-void make_kids_list( ecf_node* parent, const std::vector<T>& v )
-{
- for(typename std::vector<T>::const_reverse_iterator j = v.rbegin(); j != v.rend();
- ++j) {
- parent->add_kid(make_node(*j, parent));
- }
-}
-
-template<typename T>
-const std::string ecf_concrete_node<T>::toString() const
-{
- if (owner_) return owner_->toString();
- return "";
-}
-
-#endif
diff --git a/ecflow_4_0_7/view/src/ecflow.cc b/ecflow_4_0_7/view/src/ecflow.cc
deleted file mode 100644
index 895cbe6..0000000
--- a/ecflow_4_0_7/view/src/ecflow.cc
+++ /dev/null
@@ -1,289 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #13 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <map>
-// #include <iostream>
-// #include <fstream>
-// #include <sstream>
-#include <boost/lexical_cast.hpp>
-#include "File.hpp"
-#include "Str.hpp"
-# include <sys/file.h>
-#include "ecflow.h"
-#include "directory.h"
-#include "host.h"
-
-using namespace ecf;
-
-ecf_list *ecf_node_create(char *text)
-{
- return new ecf_list(text);
-}
-
-/********************/
-
-static std::map<std::string, ecf_map> servers;
-
-int ecf_nick_read(ecf_map::kind kind)
-{
- FILE *fp;
-#undef MAXLEN
-#define MAXLEN 128
- char buff[MAXLEN];
- char name[MAXLEN];
- char netname[MAXLEN];
- int prog;
- std::string servpath;
-
- if (kind == ecf_map::GLOBAL)
- servpath = directory::system();
- else
- servpath = directory::user();
- servpath += "/servers";
- std::cout << "# servers: " << servpath << "\n";
-
- if( !(fp=fopen(servpath.c_str(),"r")) ) return FALSE;
- while(fgets(buff,MAXLEN,fp)) {
- name[0] = netname[0] = 0;
- sscanf(buff,(char*)"%s %s %d",name,netname,&prog);
-
- if(name[0] != 0 && name[0] != '#' &&
- servers.find(name) == servers.end())
- servers.insert(std::make_pair
- (name, ecf_map(name, netname, prog, kind)));
- }
-
- fclose(fp);
- return 0;
-}
-
-int ecf_nick_load() {
- static bool been_here = false;
- if(been_here) return TRUE;
- else been_here = true;
-
- servers.insert(std::make_pair
- ("localhost",
- ecf_map("local","localhost", 3141,ecf_map::GLOBAL)));
- ecf_nick_read(ecf_map::GLOBAL);
- ecf_nick_read(ecf_map::USER);
-
- for (std::map<std::string, ecf_map>::const_iterator
- it = servers.begin(); it != servers.end(); ++it) {
- host_maker::make_host(it->first,
- it->second.machine(),
- it->second.port());
- }
- return TRUE;
-}
-
-int ecf_nick_write()
-{
- std::string servpath = directory::user();
- servpath += "/servers";
- FILE *f = fopen(servpath.c_str(), "w");
- if(!f) return FALSE;
- for (std::map<std::string, ecf_map>::const_iterator
- it = servers.begin(); it != servers.end(); ++it) {
- fprintf(f, "%s\n", it->second.print().c_str());
- }
- fclose(f);
- return TRUE;
-}
-
-int ecf_nick_origin(const std::string& name)
-{
- std::map<std::string, ecf_map>::iterator found = servers.find(name);
- if (found != servers.end())
- return (int) found->second.from;
- return (int) ecf_map::GLOBAL;
-}
-
-int ecf_nick_delete(const std::string& name)
-{
- if (servers.find(name) != servers.end())
- servers.erase(servers.find(name));
- return TRUE;
-}
-
-int ecf_nick_update(const std::string& name,
- const std::string& machine,
- int port)
-{
- if (servers.find(name) != servers.end())
- servers.erase(servers.find(name));
- servers.insert(std::make_pair
- (name, ecf_map(name, machine, port, ecf_map::USER)));
- ecf_nick_write();
- return TRUE;
-}
-
-
-long ecf_repeat_julian_to_date(long jdate)
-{
- long x,y,d,m,e;
- long day,month,year;
-
- x = 4 * jdate - 6884477;
- y = (x / 146097) * 100;
- e = x % 146097;
- d = e / 4;
-
- x = 4 * d + 3;
- y = (x / 1461) + y;
- e = x % 1461;
- d = e / 4 + 1;
-
- x = 5 * d - 3;
- m = x / 153 + 1;
- e = x % 153;
- d = e / 5 + 1;
-
- if( m < 11 )
- month = m + 2;
- else
- month = m - 10;
-
-
- day = d;
- year = y + m / 11;
-
- return year * 10000 + month * 100 + day;
-}
-
-long ecf_repeat_date_to_julian(long ddate)
-{
- long m1,y1,a,b,c,d,j1;
-
- long month,day,year;
-
- year = ddate / 10000;
- ddate %= 10000;
- month = ddate / 100;
- ddate %= 100;
- day = ddate;
-
- if (month > 2)
- {
- m1 = month - 3;
- y1 = year;
- }
- else
- {
- m1 = month + 9;
- y1 = year - 1;
- }
- a = 146097*(y1/100)/4;
- d = y1 % 100;
- b = 1461*d/4;
- c = (153*m1+2)/5+day+1721119;
- j1 = a+b+c;
-
- return(j1);
-}
-
-char *ecf_string(char *str, char *file, int lineno)
-{
- static const char *null_string = "(null string)";
- return str ? str : const_cast<char *>(null_string);
-}
-static const char* const_ecf_string(const char *str)
-{
- static const char *null_string = "(null string)";
- return str ? str : null_string ;
-}
-
-#undef MAXLEN
-#define MAXLEN 255 /* For temp names, should be big enough */
-#include <sys/stat.h>
-#include <dirent.h>
-
-ecf_dir *ecf_file_dir(char *path, char *pattern, int fullname)
-/**************************************************************************
-? Read the directory and generate the listing
-************************************o*************************************/
-{
- struct dirent *de;
- DIR *dp;
- struct stat st;
-
- ecf_dir *cur = NULL;
- ecf_dir *dir = NULL;
-
- bool ok = true;
-
- if( (dp=opendir(path)) )
- {
- char name[MAXLEN];
- char *s;
-
- strcpy(name,path);
- s = name + strlen(path);
- *s++ = '/';
-
- while( ok && (de=readdir(dp)) != NULL )
- {
- if( de->d_ino != 0 )
- {
- strcpy(s,de->d_name);
-
- if( !pattern || strncmp(de->d_name,pattern,strlen(pattern))==0 )
- if( lstat(name,&st) == 0 )
- {
- if( (cur = new ecf_dir())) // (ecf_dir*) calloc(1,sizeof(ecf_dir))) )
- {
- if(fullname)
- {
- char buff[MAXLEN];
- sprintf(buff,"%s/%s",const_ecf_string(path),const_ecf_string(de->d_name));
- cur->name_ = strdup(buff);
- }
- else
- cur->name_ = strdup(de->d_name);
-
- cur->mode = st.st_mode;
- cur->uid = st.st_uid;
- cur->gid = st.st_gid;
- cur->size = st.st_size;
- cur->atime = st.st_atime;
- cur->mtime = st.st_mtime;
- cur->ctime = st.st_ctime;
-
- ecf_list_add<ecf_dir>(&dir,cur);
- }
- else
- ok = false;
- }
- else {}
- else {} /* Didn't match */
- }
- }
- closedir(dp);
- } else {};
-
- return dir;
-}
-
-bool ecf_map::operator== (const ecf_map& l) const
- {
- return l.name_ == name_
- && l.machine_ == machine_
- && l.port_ == port_;
- }
-
-const std::string ecf_map::print() const {
- std::stringstream i; i << port_;
- return name_ + "\t\t" + machine_ + "\t\t" + i.str();
-}
diff --git a/ecflow_4_0_7/view/src/ecflow.h b/ecflow_4_0_7/view/src/ecflow.h
deleted file mode 100644
index 96b0571..0000000
--- a/ecflow_4_0_7/view/src/ecflow.h
+++ /dev/null
@@ -1,258 +0,0 @@
-#ifndef ecf_H
-#define ecf_H
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #19 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <rpc/rpc.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-#include <stdlib.h>
-
-#if defined(__cplusplus) || defined(c_plusplus)
-#include "std.h"
-#include <sstream>
-#include <extent.h>
-
-#include "Str.hpp"
-#include <inttypes.h>
-
-#define ECF_PROG 3141
-
-class ecf_dir : public extent<ecf_dir> {
- protected:
- bool sort() { return true; }
- ecf_dir(const ecf_dir&);
- ecf_dir operator=(const ecf_dir&);
- public:
- char *name_;
- ecf_dir *next;
-
- int mode;
- int uid;
- int gid;
- int size;
- int atime;
- int mtime;
- int ctime;
-
- ecf_dir() : name_ (0x0), next (0x0) {}
- virtual ~ecf_dir() {}
-
- std::string name() const { return (name_); }
-};
-
-template<class T>
-bool ecf_list_add(T **list, T *kid)
-{
- T **top = list;
- T *run = *top;
- if( !kid ) return false; kid->next = NULL;
- if( run ) {
- while( run->next ) run = run->next;
- run->next = kid;
- } else
- *top = kid;
- return true;
-};
-
-int ecf_nick_update(const std::string& name,
- const std::string& machine,
- int port);
-int ecf_nick_write();
-int ecf_nick_delete(const std::string& name);
-
-class ecf_list {
- public:
- int type_;
- char *name_;
- ecf_list *next;
-
- ecf_list(const char *text,
- ecf_list *n= 0x0) : name_(0x0), next (n) { name_ = strdup(text); }
- virtual ~ecf_list() { if (name_) free(name_); }
-
- std::string name() const { return name_; }
- private:
- ecf_list(ecf_list& );
-};
-
-class ecf_map {
- std::string name_;
- std::string machine_;
- int port_;
-
-public:
- enum kind {GLOBAL, USER, NETWORK};
- kind from;
-
- ecf_map (const std::string n, const std::string m, int p, kind f)
- : name_(n)
- , machine_(m)
- , port_(p)
- , from(f)
- {}
-
- ~ecf_map() {}
-
- std::string name() const { return name_; }
- std::string machine() const { return machine_; }
- int port() const { return port_; }
-
- bool operator== (const std::string& n) const { return name_ == n; }
-
- bool operator== (const ecf_map& l) const;
-
- const std::string print() const;
-};
-
-int ecf_nick_load();
-ecf_list *ecf_node_create(char *text);
-int ecf_nick_origin(const std::string& name);
-
-#include <Suite.hpp>
-#include <Family.hpp>
-#include <Task.hpp>
-#include <ClientInvoker.hpp>
-#include <AbstractObserver.hpp>
-#include "NodeFwd.hpp"
-
-#include "ExprAst.hpp"
-#include "TimeAttr.hpp"
-#include "TodayAttr.hpp"
-#include "NodeAttr.hpp"
-#include "DateAttr.hpp"
-#include "DayAttr.hpp"
-#include "CronAttr.hpp"
-#include "LateAttr.hpp"
-#include "ZombieAttr.hpp"
-#include "RepeatAttr.hpp"
-#include "AutoCancelAttr.hpp"
-
-#include "Node.hpp"
-#include "Defs.hpp"
-
-typedef uint64_t uint64;
-#include <boost/algorithm/string.hpp>
-
-char *ecf_string(char *str, char *file, int lineno);
-ecf_dir *ecf_file_dir(char *path, char *pattern, int fullname);
-
-#endif
-
-#ifndef ECF_NO_DUPLICATE
-#define SMS_PROG 314159
-
-#ifndef NODE_COMPLETE
-#define STR(x) ecf_string((x), __FILE__ , __LINE__ )
-
-#define STATUS_RESUME -1
-#define STATUS_UNKNOWN 0
-#define STATUS_SUSPENDED 1
-#define STATUS_COMPLETE 2
-#define STATUS_QUEUED 3
-#define STATUS_SUBMITTED 4
-#define STATUS_ACTIVE 5
-#define STATUS_ABORTED 6
-#define STATUS_USABLE 7
-#define STATUS_SHUTDOWN 7
-#define STATUS_HALTED 8
-#define STATUS_MAX 9
-
-#define FLAG_FORCE_ABORT 0
-#define FLAG_USER_EDIT 1
-#define FLAG_TASK_ABORTED 2
-#define FLAG_EDIT_FAILED 3
-#define FLAG_CMD_FAILED 4
-#define FLAG_NO_SCRIPT 5
-#define FLAG_KILLED 6
-#define FLAG_MIGRATED 7
-#define FLAG_LATE 8
-#define FLAG_MESSAGE 9
-#define FLAG_BYRULE 10
-#define FLAG_QUEUELIMIT 11
-#define FLAG_WAIT 12
-#define FLAG_LOCKED 13
-#define FLAG_ZOMBIE 14
-#define FLAG_TO_CHECK 15
-#define FLAG_MAX 16
-
-#define ZOMBIE_USER 1
-#define ZOMBIE_NET 2
-#define ZOMBIE_GET 0
-#define ZOMBIE_FOB 1
-#define ZOMBIE_DELETE 2
-#define ZOMBIE_FAIL 3
-#define ZOMBIE_RESCUE 4
-#define ZOMBIE_KILL 5
-
-#define ECF_E_NOTIN 26
-#define ECF_E_IN 27
-#define ECF_E_NONEWS 28 /* Not really an error */
-#define ECF_E_HOST 29
-
-#define NODE_LIST 0
-#define NODE_USER 1
-#define NODE_CONNECTION 2
-#define NODE_VARIABLE 3
-#define NODE_TIME 4
-#define NODE_DATE 5
-#define NODE_TRIGGER 6
-#define NODE_TREE 7
-#define NODE_COMPLETE 30
-#define NODE_EVENT 9
-#define NODE_TASK 10
-#define NODE_FAMILY 11
-#define NODE_SUITE 12
-#define NODE_SUPER 13
-#define NODE_REPEAT 22
-#define NODE_DIR 23
-#define NODE_METER 24
-#define NODE_LABEL 25
-#define NODE_LATE 28
-#define NODE_UNKNOWN 35
-#define NODE_ALIAS 32
-#define NODE_LIMIT 33
-#define NODE_INLIMIT 34
-#define NODE_UNKNOWN 35
-
-#define NODE_REPEAT_E 36
-#define NODE_REPEAT_S 37
-#define NODE_REPEAT_D 38
-#define NODE_REPEAT_I 39
-#define NODE_REPEAT_DAY 40
-
-#define NODE_MAX 41
-
-#define SUITES_LIST 3
-#define SUITES_MINE 4
-#define SUITES_REG 7
-
-#ifndef NIL
-#define NIL -1
-#endif
-
-#ifndef MIN
-#define MIN(a,b) ((a)<=(b)?(a):(b))
-#endif
-#endif /* do not overwrite sms.h */
-
-long ecf_repeat_julian_to_date(long jdate);
-long ecf_repeat_date_to_julian(long ddate);
-#endif /* ECF_NO_DUPLICATE */
-#endif /* ecf_H */
diff --git a/ecflow_4_0_7/view/src/ecflowview.cc b/ecflow_4_0_7/view/src/ecflowview.cc
deleted file mode 100644
index 1d2e50e..0000000
--- a/ecflow_4_0_7/view/src/ecflowview.cc
+++ /dev/null
@@ -1,165 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #30 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <stdlib.h>
-#include <stdio.h>
-
-#define ecflowview_cc
-#include "ecflowview.h"
-
-#include "ecflow.h"
-#include "ecf_node.h"
-
-#include "edit.h"
-#include "edit_label.h"
-#include "edit_limit.h"
-#include "edit_meter.h"
-#include "edit_repeat.h"
-#include "edit_variable.h"
-#include "history.h"
-#include "info.h"
-#include "job.h"
-#include "jobcheck_panel.h"
-#include "jobstatus.h"
-#include "manual.h"
-#include "messages.h"
-#include "option_panel.h"
-#include "output.h"
-#include "script_panel.h"
-#include "suites_panel.h"
-#include "timetable_panel.h"
-#include "trigger_panel.h"
-#include "users.h"
-#include "variables.h"
-#include "why.h"
-#include "zombies_panel.h"
-
-#include "user_prefs.h"
-#include "fonts_prefs.h"
-#include "colors_prefs.h"
-#include "servers_prefs.h"
-#include "host_prefs.h"
-
-#include "simple_node.h"
-#include "date.h"
-#include "event_node.h"
-#include "inlimit_node.h"
-#include "label_node.h"
-#include "late_node.h"
-#include "limit_node.h"
-#include "meter_node.h"
-#include "node.h"
-#include "super_node.h"
-#include "task_node.h"
-#include "time_node.h"
-#include "trigger_node.h"
-#include "variable_node.h"
-/*
-void __cyg_profile_func_enter( void *, void * )
- __attribute__ ((no_instrument_function));
-
-void __cyg_profile_func_enter(void *thisone, void *callsite) {
- printf("E%p\n", (int*)thisone);
-}
-
-void __cyg_profile_func_exit(void *thisone, void *callsite) {
- printf("X%p\n", (int*)thisone);
-}
-*/
-
-extern int xmain(int,char**); /* from uitop.cc */
-extern int wmain(int,char**);
-
-// In label_variable.cc
-static ecf_node_builder<Variable *, variable_node> build_variable(NODE_VARIABLE);
-static ecf_node_builder<const Variable *, variable_node> build_pkvariable(NODE_VARIABLE);
-// In label_node.cc
-static ecf_node_builder< const Label *, label_node> build_plabel(NODE_LABEL);
-// In event_node.cc
-static ecf_node_builder< const Event *, event_node> build_pevent(NODE_EVENT);
-// In meter_node.cc
-static ecf_node_builder< const Meter *, meter_node> build_cmeter(NODE_METER);
-// In time_node.cc
-static ecf_node_builder<const ecf::TimeAttr *, time_node> build_ctime(NODE_TIME);
-static ecf_node_builder<const ecf::TodayAttr *, time_node> build_ctoday(NODE_TIME);
-// In date_node.cc
-static ecf_node_builder<const DateAttr *, date_node> build_cdate(NODE_DATE);
-static ecf_node_builder<const DayAttr *, date_node> build_cday(NODE_DATE);
-static ecf_node_builder<const ecf::CronAttr *, date_node> build_ccron(NODE_DATE);
-// In limit_node.cc
-static ecf_node_builder<Limit * const, limit_node> build_pklimit(NODE_LIMIT);
-static ecf_node_builder<const InLimit *, inlimit_node> build_cinlimit(NODE_INLIMIT);
-static ecf_node_builder<const ecf::LateAttr *, late_node> build_clate(NODE_LATE);
-static ecf_node_builder<ecf::LateAttr *, late_node> build_late(NODE_LATE);
-
-static ecf_node_builder<ExpressionWrapper*, trigger_node> build_trigger(NODE_TRIGGER);
-#include "repeat.h"
-
-static ecf_node_builder<const std::pair<std::string, std::string> *, variable_node> build_pkpvariable(NODE_VARIABLE);
-
-static ecf_node_builder<Suite*,suite_node>build_suite(NODE_SUITE);
-static ecf_node_builder<Defs*,super_node>build_topnode(NODE_SUPER);
-static ecf_node_builder<Node*,family_node>build_simple(NODE_FAMILY);
-static ecf_node_builder<Alias*,alias_node>build_alias(NODE_ALIAS);
-static ecf_node_builder<Task*, task_node> build_task(NODE_TASK);
-static ecf_node_builder<Family*,family_node>build_family(NODE_FAMILY);
-
-static ecf_node_builder<RepeatEnumerated*,repeat_enumerated_node> pprce(NODE_REPEAT_E);
-static ecf_node_builder<RepeatString*,repeat_string_node> prcs(NODE_REPEAT_S);
-static ecf_node_builder<RepeatDate*,repeat_date_node> prcd(NODE_REPEAT_D);
-static ecf_node_builder<RepeatInteger*,repeat_integer_node> prci(NODE_REPEAT_I);
-static ecf_node_builder<RepeatDay*,repeat_day_node> prcday(NODE_REPEAT_DAY);
-
-static panel_maker<info> info_maker(PANEL_INFO);
-static panel_maker<manual> manual_maker(PANEL_MANUAL);
-static panel_maker<script_panel> script_maker(PANEL_SCRIPT);
-static panel_maker<job> job_maker(PANEL_JOB);
-static panel_maker<jobstatus> jobstatus_maker(PANEL_JOBSTATUS);
-static panel_maker<output> output_maker(PANEL_OUTPUT);
-static panel_maker<why> why_maker(PANEL_WHY);
-static panel_maker<trigger_panel> trigger_panel_maker(PANEL_TRIGGER);
-static panel_maker<jobcheck_panel> jobcheck_maker(PANEL_JOBCHECK);
-static panel_maker<timetable_panel> timetable_maker(PANEL_TIMETABLE);
-static panel_maker<variables> variables_maker(PANEL_VARIABLES);
-static panel_maker<edit> edit_maker(PANEL_EDIT_TASK);
-static panel_maker<edit_label> edit_label_maker(PANEL_EDIT_LABEL);
-static panel_maker<edit_limit> edit_limit_maker(PANEL_EDIT_LIMIT);
-static panel_maker<edit_variable> edit_variable_maker(PANEL_EDIT_VARIABLE);
-static panel_maker<edit_meter> edit_meter_maker(PANEL_EDIT_METER);
-static panel_maker<edit_repeat> edit_repeat_maker(PANEL_EDIT_REPEAT);
-static panel_maker<history> history_maker(PANEL_HISTORY);
-static panel_maker<messages> messages_maker(PANEL_MESSAGES);
-static panel_maker<suites_panel> suites_maker(PANEL_SUITES);
-static panel_maker<users> users_maker(PANEL_USERS);
-static panel_maker<zombies_panel> zombies_maker(PANEL_ZOMBIES);
-static panel_maker<option_panel> maker(PANEL_ECF_OPTIONS);
-
-static user_prefs user_hp;
-static colors_prefs colors_hp;
-static fonts_prefs fonts_hp;
-static host_prefs hosts_hp;
-
-#ifdef BRIDGE
-static repeat_node_maker repeat_node_maker_instance;
-late_node::late_node(host& h,sms_node* n, char b) : node(h,n,b), label_(0) {}
-#endif
-
-int main(int argc,char** argv)
-{
- return getenv("ECFLOW_HTTP_PORT") ? wmain(argc,argv) :
- xmain(argc,argv);
- ecf_nick_write();
-}
-
diff --git a/ecflow_4_0_7/view/src/ecflowview.h b/ecflow_4_0_7/view/src/ecflowview.h
deleted file mode 100644
index 5d42a6f..0000000
--- a/ecflow_4_0_7/view/src/ecflowview.h
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef ecflowview_h
-#define ecflowview_h
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #13 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-
-#ifdef hpux
-// hpux X11 headers are wrong
-#undef bcopy
-#undef bzero
-#undef bcmp
-#endif
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#include "ecflow.h"
-
-#define NOTIMP throw "not_implemented"
-#define XECF_SNAP_ENABLED TRUE
-
-#ifdef BRIDGE
-/* #define appName "XCdp - ecFlowview" */
- #define appName "XCdp"
-#else
-#define appName "ecFlowview"
-#endif
-
-#define clientName "ecflow_client"
-#define snapshotName "${TMPDIR:=/tmp}/ecflowview$USER.png"
-#define browserName "${BROWSER:firefox --new-tab}"
-#define urlRef "http://software.ecmwf.int/issues/browse/ECFLOW"
-#define tmpName "ecFlowvw" /* 8 char */
-
-#if 1 // DEBUG
-#define XECFDEBUG if(getenv("XECFLOW_DEBUG"))
-#else
-#define XECFDEBUG if (0)
-#endif
-#endif
diff --git a/ecflow_4_0_7/view/src/ecflowview.menu b/ecflow_4_0_7/view/src/ecflowview.menu
deleted file mode 100644
index b2a1d1d..0000000
--- a/ecflow_4_0_7/view/src/ecflowview.menu
+++ /dev/null
@@ -1,313 +0,0 @@
-!===========================================================
-! Name :
-! Author :
-! Revision : $Revision: #26 $
-!
-! Copyright 2009-2012 ECMWF.
-! This software is licensed under the terms of the Apache Licence version 2.0
-! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-! In applying this licence, ECMWF does not waive the privileges and immunities
-! granted to it by virtue of its status as an intergovernmental organisation
-! nor does it submit to any jurisdiction.
-!
-! Description :
-! this file may be found in
-! - ecflowview sources in order to generate ecflowview.menu.h
-! - ~/.ecflowrc/ecflowview.menu # edit backup remove (reset)
-! - ~/ is preferred to $HOME
-! - menus can call ecflow client command (start with 'ecflow_client')
-! - menus can call system command (start with sh)
-!===========================================================
-!
-! Format
-!-------
-! menu TITLE
-! {
-! (vis flg,enable flg,title,command,question,answer)
-! }
-!
-!===========================================================
-!
-! Values for the status flags
-!----------------------------
-!
-!NONE ALL UNKNOWN SUSPENDED COMPLETE QUEUED SUBMITTED ACTIVE
-!ABORTED CLEAR SET SHUTDOWN HALTED
-!
-! Values for type flags
-!----------------------
-!
-!NONE ALL SERVER SUITE FAMILY TASK EVENT
-!
-! Values for visible flags
-!-------------------------
-!
-!NONE ALL SERVER SUITE FAMILY TASK EVENT
-!
-! Values for special flags
-!-------------------------
-!
-!NONE ALL HAS_TRIGGERS HAS_TIME HAS_DATE
-!
-!===========================================================
-
-!==============================================================================
-! Main menu
-!==============================================================================
-
-version 1 0 0 ;
-
-menu 'MAIN'
-{
- (~SUSPENDED & NODE, ALL, 'Suspend', 'ecflow_client --suspend <full_name>')
- (SUSPENDED & NODE, ALL, 'Resume', 'ecflow_client --resume <full_name>')
-
- ( TASK, ~ACTIVE & ~SUBMITTED, 'Rerun', 'ecflow_client --force queued <full_name>')
-
- (TASK|ALIAS, SUBMITTED|ACTIVE, 'Set complete',
- 'ecflow_client --force complete <full_name>',
- 'Have you checked that the job is not active anymore (jobstatus) ?', YES)
- (TASK|ALIAS, UNKNOWN|QUEUED|ABORTED, 'Set complete',
- 'ecflow_client --force complete <full_name>')
- (TASK|ALIAS, SUBMITTED|ACTIVE, 'Set aborted',
- 'ecflow_client --force aborted <full_name>',
- 'Have you checked that the job is not active anymore (jobstatus) ?', YES)
- (TASK|ALIAS, UNKNOWN|QUEUED|COMPLETE, 'Set aborted',
- 'ecflow_client --force aborted <full_name>')
-
- (TASK|ALIAS, ~ACTIVE & ~SUBMITTED, 'Execute', 'ecflow_client --run <full_name>')
-
- (SUITE|TASK|FAMILY, ~ACTIVE & ~SUBMITTED, 'Requeue',
- 'ecflow_client --requeue force <full_name>',
- 'Confirm requeuing of <full_name>', YES)
-
- (SUITE|FAMILY, ABORTED | SUSPENDED, 'Requeue aborted',
- 'ecflow_client --requeue abort <full_name>',
- 'Confirm requeuing of aborted tasks from <full_name>', YES)
-
- (ALL,ALL,'-',SEPARATOR)
-
- (SUITE|TASK|FAMILY,(QUEUED|SUSPENDED|ACTIVE) & (HAS_TRIGGERS|HAS_TIME|HAS_DATE),'Delete',MENU)
- (NODE | ALIAS, ALL, 'Special', MENU)
- (NODE | ALIAS, ALL, 'Defstatus', MENU)
- (NODE & ADMIN, ALL, 'Force', MENU)
- ((NODE|ALIAS)& ADMIN, ALL,'Order', MENU)
-
- (ALL,ALL,'-',SEPARATOR ,'',YES)
- (SUITE|FAMILY|TASK, ALL, 'Web...', 'ecflow_client --url <full_name> ', '', YES)
- (TASK, ALL, 'Web', MENU)
-
- (ALL,ALL,'-',SEPARATOR)
-
- (SUITE & (OPER|ADMIN) ,UNKNOWN|COMPLETE,'Begin',
- 'ecflow_client --begin <node_name>','',YES)
-
- (SUITE & (OPER|ADMIN) ,~SUBMITTED & ~ACTIVE,'Cancel',
- 'ecflow_client --delete yes <full_name>',
- 'Do you really want to cancel suite <full_name> ?',NO)
-
-! Events
-!---------------------------------
-
- (EVENT, CLEAR, 'Set' ,
- 'ecflow_client --alter change event <node_name> set <parent_name>', '',YES)
- (EVENT, SET, 'Clear',
- 'ecflow_client --alter change event <node_name> clear <parent_name>', '',YES)
-
-!!-----------------------------------
-
- (SERVER & (ADMIN|OPER) & LOCKED , ALL , 'Unlock', 'unlock -y',
- 'Before going further, please check why the server was locked.',NO)
- (ALL,ALL,'-',SEPARATOR,'',YES)
-
-!!-----------------------------------
-
- (SERVER,SHUTDOWN|HALTED, 'Restart',
- 'ecflow_client --restart yes','Restart the server in <node_name>?' ,NO)
- (SERVER,~SHUTDOWN, 'Shutdown',
- 'ecflow_client --shutdown yes','Shutdown the server in <node_name>?',NO)
- (SERVER,~HALTED, 'Halt',
- 'ecflow_client --halt yes','Halt the server in <node_name>?',NO)
- (SERVER,HALTED|UNKNOWN, 'Terminate',
- 'ecflow_client --terminate yes','Terminate the server in <node_name>?',NO)
- (ALL,ALL,'-',SEPARATOR,'',YES)
- (SERVER,ALL, 'Checkpoint','ecflow_client --check_pt','',YES)
- (SERVER,HALTED, 'Recover',
- 'ecflow_client --restore_from_checkpt','Recover the server in <node_name>?',NO)
-
-!!-----------------------------------
-
- (LIMIT , ALL, 'Reset' ,
- 'ecflow_client --alter change limit_value <node_name> 0 <parent_name>',
- 'Confirm resetting <full_name>', YES)
- (ALIAS , ALL, 'Remove', 'ecflow_client --delete yes <full_name>',
- 'Confirm remove alias <full_name>', YES)
-
-!!-----------------------------------
-
- (ALL,ALL,'-',SEPARATOR)
-
- (TASK|LIMIT|LABEL|METER|REPEAT|VARIABLE, ALL , 'Edit...', WINDOW(Edit))
- (TASK|ALIAS, ALL , 'Output...', WINDOW(Output) )
-
- (TASK|ALIAS, SUBMITTED|ACTIVE , 'Status...', WINDOW(Jobstatus))
- (ALIAS, ALL , 'Job...', WINDOW(Job) )
- (TASK|ALIAS, ALL , 'Script...', WINDOW(Script) )
-
- (SERVER, ALL , 'Suites...', WINDOW(Suites) )
- (SERVER, ALL , 'History...', WINDOW(History) )
- (SERVER, ALL , 'Zombies...', WINDOW(Zombies) )
- (ALL,ALL,'-',SEPARATOR)
- (SERVER, ALL , 'Options...', WINDOW(Options) )
- (SERVER, ALL , 'Extra', MENU )
-}
-
-menu 'Web'
-{
- (TASK, ALL, 'Man', 'sh firefox %ECF_URL_BASE%/%ECF_URL%', '', YES)
- (TASK, ALL, 'Script', 'sh xterm -T Script -e vim %ECF_SCRIPT%', '', YES)
- (TASK, ALL, 'Job', 'sh xterm -T Job -e vim %ECF_JOB%', '', YES)
- (TASK, ALL, 'Output', 'sh xterm -T Output -e vim %ECF_JOBOUT%', '', YES)
- (TASK, ALL , 'TimeLine...', WINDOW(Timeline))
- ! request from Lidström Jonas https://software.ecmwf.int/issues/browse/SUP-829
- (TASK, ALL, 'Details', 'sh xterm -T Details-%ECF_NAME% -e "grep %ECF_NAME% %ECF_LOG% ; read"')
-}
-
-!==============================================================================
-! Status submenu
-!==============================================================================
-
-menu 'Status'
-{
- (SUITE|TASK|FAMILY, ~SUSPENDED,'Suspend', 'ecflow_client --suspend <full_name>', '',YES)
- (SUITE|TASK|FAMILY, SUSPENDED ,'Resume', 'ecflow_client --resume <full_name>', '',YES)
-
- (ALL,ALL,'-',SEPARATOR)
-
- (TASK, ~ACTIVE & ~SUBMITTED, 'Rerun', 'ecflow_client --force queued <full_name>', '',YES)
- (TASK, ~COMPLETE, 'Set complete', 'ecflow_client --force complete <full_name>', '',YES)
-
- (SUITE|TASK|FAMILY|ALIAS, ~ACTIVE & ~SUBMITTED,
- 'Requeue','ecflow_client --requeue force <full_name>', 'Confirm requeuing of <full_name>', YES)
-
- (SUITE|FAMILY, ABORTED | SUSPENDED,
- 'Requeue aborted','ecflow_client --requeue abort <full_name>',
- 'Confirm requeuing aborted tasks below <full_name>', YES)
-}
-
-!==============================================================================
-! Suite submenu
-!==============================================================================
-
-menu 'Suite'
-{
- (SUITE,UNKNOWN|COMPLETE,'Begin','ecflow_client --begin <node_name>','',YES)
-
- (SUITE,ALL,'Cancel','ecflow_client --delete yes <full_name>',
- 'Do you really want to cancel <full_name> ?',NO)
-
- (ALL,ALL,'-',SEPARATOR)
-}
-
-!==============================================================================
-! Delete submenu
-!==============================================================================
-
-menu 'Delete'
-{
- (ALL,HAS_TRIGGERS|HAS_TIME|HAS_DATE, 'All dependencies','ecflow_client --free-dep all <full_name>')
- (ALL,HAS_TRIGGERS, 'Trigger dependencies','ecflow_client --free-dep trigger <full_name>')
- (ALL,HAS_TIME, 'Time dependencies','ecflow_client --free-dep time <full_name>')
- (ALL,QUEUED, 'Date dependencies','ecflow_client --free-dep date <full_name>')
-}
-
-menu "Order"
-{
- (ALL,ALL,'Top','ecflow_client --order <full_name> top')
- (ALL,ALL,'Up','ecflow_client --order <full_name> up')
- (ALL,ALL,'Down','ecflow_client --order <full_name> down')
- (ALL,ALL,'Bottom','ecflow_client --order <full_name> bottom')
- (ALL,ALL,'Alphabetically','ecflow_client --order <full_name> alpha')
-}
-
-menu "Force"
-{
- (NODE, ~UNKNOWN, 'Unknown', 'ecflow_client --force unknown recursive <full_name>')
- (NODE, ~COMPLETE & ~ACTIVE & ~SUBMITTED, 'Complete',
- 'ecflow_client --force complete recursive <full_name>',
- 'Check running/queued jobs and Confirm force complete of <full_name>', YES)
- (NODE, ~QUEUED & ~ACTIVE & ~SUBMITTED, 'Queued',
- 'ecflow_client --force queued recursive <full_name>')
- (NODE, ~SUBMITTED & ~ACTIVE,'Submitted',
- 'ecflow_client --force submitted recursive <full_name>')
- (NODE, ~ACTIVE, 'Active', 'ecflow_client --force active recursive <full_name>')
- (NODE, ~ABORTED, 'Aborted', 'ecflow_client --force aborted recursive <full_name>',
- 'Check running/queued jobs and Confirm force submitted of <full_name>', YES)
-}
-
-menu "Defstatus"
-{
-(NODE, ALL, 'Complete', 'ecflow_client --alter change defstatus complete <full_name>')
-(NODE, ALL, 'Queued', 'ecflow_client --alter change defstatus queued <full_name>')
-}
-
-menu "Special"
-{
- (SUITE|FAMILY,(ACTIVE|SUBMITTED|ABORTED),'Kill', 'ecflow_client --kill <full_name>','',YES)
- (TASK|ALIAS,(ACTIVE|SUBMITTED),'Kill','ecflow_client --kill <full_name>','',YES)
- (ALL,ALL,'Check',WINDOW(Check),'',YES)
- (TASK|ALIAS,ALL,'Free password','ecflow_client --alter add variable ECF_PASS FREE <full_name>')
- (TASK|ALIAS,ALL,'ClearZ','ecflow_client --alter clear_flag zombie <full_name>')
- (TASK|ALIAS,ALL,'ClearLate','ecflow_client --alter clear_flag late <full_name>')
-
- (FAMILY, ~ACTIVE & ~SUBMITTED, 'Execute', 'ecflow_client --run <full_name>')
- ((SUITE|FAMILY|TASK), SELECTION, 'Plug into selected node', PLUG)
- (FAMILY|TASK,ALL,'get','ecflow_client --get <full_name>')
- (TASK,ALL,'status','ecflow_client --status <full_name>')
- (SUITE|SERVER, ALL, 'Collect...', WINDOW(Collector))
- (SUITE|FAMILY, ALL, 'Walk', 'ecflow_client --force-dep-eval <full_name>')
-}
-
-menu "Extra"
-{
- (SERVER|SUITE,ALL,'Windows', MENU)
- (ALL,ALL,'-',SEPARATOR)
- (SERVER,ALL,'ClearLate','ecflow_client --alter clear_flag late <full_name>')
- ! (SERVER|SUITE,ALL,'tail log', 'sh /usr/bin/xterm -e rsh %ECF_NODE% tail -f %ECF_HOME%/%ECF_LOG%&')
-(SERVER|SUITE,ALL,'tail log', 'sh /usr/bin/xterm -e tail -f /tmp/$USER/$HOST*.ecf.log&')
- (ALL,ALL,'-',SEPARATOR)
- (SERVER|SUITE,ALL,'overwrite', 'write menu')
- (SERVER|SUITE,ALL,'edit menu', 'sh /usr/bin/xterm -e vi ~/.ecflowrc/ecflowview.menu')
- (SERVER|SUITE,ALL,'bkup menu', 'sh /bin/cp ~/.ecflowrc/ecflowview.menu ~/.ecflowrc/ecflowview.menu.bak')
- (SERVER|SUITE,ALL,'rm menu', 'sh /bin/rm ~/.ecflowrc/ecflowview.menu')
- (ALL,ALL,'-',SEPARATOR)
- (SERVER|SUITE,ALL,'debug on', 'ecflow_client --debug_server_on')
- (SERVER|SUITE,ALL,'debug off','ecflow_client --debug_server_off')
- (ALL,ALL,'-',SEPARATOR)
- (SERVER|SUITE,ALL,'stats','ecflow_client --stats')
- (SERVER|SUITE,ALL,'suites','ecflow_client --suites')
- (ALL,ALL,'-',SEPARATOR)
- (SERVER|SUITE,ALL,'log get','ecflow_client --log get')
- (SERVER|SUITE,ALL,'log clear','ecflow_client --log clear')
- (SERVER|SUITE,ALL,'log new','ecflow_client --log new')
- (ALL,ALL,'-',SEPARATOR)
- (SERVER|SUITE,ALL,'svr load','ecflow_client --server_load')
- (SERVER|SUITE,ALL,'svr load local','ecflow_client --server_load %ECF_HOME%/%ECF_LOG%')
- (ALL,ALL,'-',SEPARATOR)
- (SERVER|SUITE,ALL,'client logging on','ecflow_client --enable_logging')
- (SERVER|SUITE,ALL,'client loggging off','ecflow_client --disable_logging')
-}
-
-menu "Windows"
-{
- (SERVER, ALL , 'Info...', WINDOW(Info))
- (SERVER, ALL , 'Man...', WINDOW(Manual))
- (SERVER, ALL , 'Var...', WINDOW(Variables))
- (SERVER, ALL , 'Msg...', WINDOW(Messages))
- (SERVER, ALL , 'Why...', WINDOW(Why))
- (SERVER, ALL , 'Triggers...', WINDOW(Triggers))
- (SERVER, ALL , 'Check...', WINDOW(Check))
- (SERVER, ALL , 'Jobstatus...', WINDOW(Jobstatus))
- (SERVER, ALL , 'TimeLine...', WINDOW(Timeline))
-}
-
diff --git a/ecflow_4_0_7/view/src/ecflowview.menu.h b/ecflow_4_0_7/view/src/ecflowview.menu.h
deleted file mode 100644
index 5c9992c..0000000
--- a/ecflow_4_0_7/view/src/ecflowview.menu.h
+++ /dev/null
@@ -1,317 +0,0 @@
-(char*) " !=========================================================== ",
-(char*) " ! Name : ",
-(char*) " ! Author : ",
-(char*) " ! Revision : $Revision: #26 $ ",
-(char*) " ! ",
-(char*) " ! Copyright 2009-2012 ECMWF. ",
-(char*) " ! This software is licensed under the terms of the Apache Licence version 2.0 ",
-(char*) " ! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. ",
-(char*) " ! In applying this licence, ECMWF does not waive the privileges and immunities ",
-(char*) " ! granted to it by virtue of its status as an intergovernmental organisation ",
-(char*) " ! nor does it submit to any jurisdiction. ",
-(char*) " ! ",
-(char*) " ! Description : ",
-(char*) " ! this file may be found in ",
-(char*) " ! - ecflowview sources in order to generate ecflowview.menu.h ",
-(char*) " ! - ~/.ecflowrc/ecflowview.menu # edit backup remove (reset) ",
-(char*) " ! - ~/ is preferred to $HOME ",
-(char*) " ! - menus can call ecflow client command (start with 'ecflow_client') ",
-(char*) " ! - menus can call system command (start with sh) ",
-(char*) " !=========================================================== ",
-(char*) " ! ",
-(char*) " ! Format ",
-(char*) " !------- ",
-(char*) " ! menu TITLE ",
-(char*) " ! { ",
-(char*) " ! (vis flg,enable flg,title,command,question,answer) ",
-(char*) " ! } ",
-(char*) " ! ",
-(char*) " !=========================================================== ",
-(char*) " ! ",
-(char*) " ! Values for the status flags ",
-(char*) " !---------------------------- ",
-(char*) " ! ",
-(char*) " !NONE ALL UNKNOWN SUSPENDED COMPLETE QUEUED SUBMITTED ACTIVE ",
-(char*) " !ABORTED CLEAR SET SHUTDOWN HALTED ",
-(char*) " ! ",
-(char*) " ! Values for type flags ",
-(char*) " !---------------------- ",
-(char*) " ! ",
-(char*) " !NONE ALL SERVER SUITE FAMILY TASK EVENT ",
-(char*) " ! ",
-(char*) " ! Values for visible flags ",
-(char*) " !------------------------- ",
-(char*) " ! ",
-(char*) " !NONE ALL SERVER SUITE FAMILY TASK EVENT ",
-(char*) " ! ",
-(char*) " ! Values for special flags ",
-(char*) " !------------------------- ",
-(char*) " ! ",
-(char*) " !NONE ALL HAS_TRIGGERS HAS_TIME HAS_DATE ",
-(char*) " ! ",
-(char*) " !=========================================================== ",
-(char*) " ",
-(char*) " !============================================================================== ",
-(char*) " ! Main menu ",
-(char*) " !============================================================================== ",
-(char*) " ",
-(char*) " version 1 0 0 ; ",
-(char*) " ",
-(char*) " menu 'MAIN' ",
-(char*) " { ",
-(char*) " (~SUSPENDED & NODE, ALL, 'Suspend', 'ecflow_client --suspend <full_name>') ",
-(char*) " (SUSPENDED & NODE, ALL, 'Resume', 'ecflow_client --resume <full_name>') ",
-(char*) " ",
-(char*) " ( TASK, ~ACTIVE & ~SUBMITTED, 'Rerun', 'ecflow_client --force queued <full_name>') ",
-(char*) " ",
-(char*) " (TASK|ALIAS, SUBMITTED|ACTIVE, 'Set complete', ",
-(char*) " 'ecflow_client --force complete <full_name>', ",
-(char*) " 'Have you checked that the job is not active anymore (jobstatus) ?', YES) ",
-(char*) " (TASK|ALIAS, UNKNOWN|QUEUED|ABORTED, 'Set complete', ",
-(char*) " 'ecflow_client --force complete <full_name>') ",
-(char*) " (TASK|ALIAS, SUBMITTED|ACTIVE, 'Set aborted', ",
-(char*) " 'ecflow_client --force aborted <full_name>', ",
-(char*) " 'Have you checked that the job is not active anymore (jobstatus) ?', YES) ",
-(char*) " (TASK|ALIAS, UNKNOWN|QUEUED|COMPLETE, 'Set aborted', ",
-(char*) " 'ecflow_client --force aborted <full_name>') ",
-(char*) " ",
-(char*) " (TASK|ALIAS, ~ACTIVE & ~SUBMITTED, 'Execute', 'ecflow_client --run <full_name>') ",
-(char*) " ",
-(char*) " (SUITE|TASK|FAMILY, ~ACTIVE & ~SUBMITTED, 'Requeue', ",
-(char*) " 'ecflow_client --requeue force <full_name>', ",
-(char*) " 'Confirm requeuing of <full_name>', YES) ",
-(char*) " ",
-(char*) " (SUITE|FAMILY, ABORTED | SUSPENDED, 'Requeue aborted', ",
-(char*) " 'ecflow_client --requeue abort <full_name>', ",
-(char*) " 'Confirm requeuing of aborted tasks from <full_name>', YES) ",
-(char*) " ",
-(char*) " (ALL,ALL,'-',SEPARATOR) ",
-(char*) " ",
-(char*) " (SUITE|TASK|FAMILY,(QUEUED|SUSPENDED|ACTIVE) & (HAS_TRIGGERS|HAS_TIME|HAS_DATE),'Delete',MENU) ",
-(char*) " (NODE | ALIAS, ALL, 'Special', MENU) ",
-(char*) " (NODE | ALIAS, ALL, 'Defstatus', MENU) ",
-(char*) " (NODE & ADMIN, ALL, 'Force', MENU) ",
-(char*) " ((NODE|ALIAS)& ADMIN, ALL,'Order', MENU) ",
-(char*) " ",
-(char*) " (ALL,ALL,'-',SEPARATOR ,'',YES) ",
-(char*) " (SUITE|FAMILY|TASK, ALL, 'Web...', 'ecflow_client --url <full_name> ', '', YES) ",
-(char*) " (TASK, ALL, 'Web', MENU) ",
-(char*) " ",
-(char*) " (ALL,ALL,'-',SEPARATOR) ",
-(char*) " ",
-(char*) " (SUITE & (OPER|ADMIN) ,UNKNOWN|COMPLETE,'Begin', ",
-(char*) " 'ecflow_client --begin <node_name>','',YES) ",
-(char*) " ",
-(char*) " (SUITE & (OPER|ADMIN) ,~SUBMITTED & ~ACTIVE,'Cancel', ",
-(char*) " 'ecflow_client --delete yes <full_name>', ",
-(char*) " 'Do you really want to cancel suite <full_name> ?',NO) ",
-(char*) " ",
-(char*) " ! Events ",
-(char*) " !--------------------------------- ",
-(char*) " ",
-(char*) " (EVENT, CLEAR, 'Set' , ",
-(char*) " 'ecflow_client --alter change event <node_name> set <parent_name>', '',YES) ",
-(char*) " (EVENT, SET, 'Clear', ",
-(char*) " 'ecflow_client --alter change event <node_name> clear <parent_name>', '',YES) ",
-(char*) " ",
-(char*) " !!----------------------------------- ",
-(char*) " ",
-(char*) " (SERVER & (ADMIN|OPER) & LOCKED , ALL , 'Unlock', 'unlock -y', ",
-(char*) " 'Before going further, please check why the server was locked.',NO) ",
-(char*) " (ALL,ALL,'-',SEPARATOR,'',YES) ",
-(char*) " ",
-(char*) " !!----------------------------------- ",
-(char*) " ",
-(char*) " (SERVER,SHUTDOWN|HALTED, 'Restart', ",
-(char*) " 'ecflow_client --restart yes','Restart the server in <node_name>?' ,NO) ",
-(char*) " (SERVER,~SHUTDOWN, 'Shutdown', ",
-(char*) " 'ecflow_client --shutdown yes','Shutdown the server in <node_name>?',NO) ",
-(char*) " (SERVER,~HALTED, 'Halt', ",
-(char*) " 'ecflow_client --halt yes','Halt the server in <node_name>?',NO) ",
-(char*) " (SERVER,HALTED, 'Terminate', ",
-(char*) " 'ecflow_client --terminate yes','Terminate the server in <node_name>?',NO) ",
-(char*) " (ALL,ALL,'-',SEPARATOR,'',YES) ",
-(char*) " (SERVER,ALL, 'Checkpoint','ecflow_client --check_pt','',YES) ",
-(char*) " (SERVER,HALTED, 'Recover', ",
-(char*) " 'ecflow_client --restore_from_checkpt','Recover the server in <node_name>?',NO) ",
-(char*) " ",
-(char*) " !!----------------------------------- ",
-(char*) " ",
-(char*) " (LIMIT , ALL, 'Reset' , ",
-(char*) " 'ecflow_client --alter change limit_value <node_name> 0 <parent_name>', ",
-(char*) " 'Confirm resetting <full_name>', YES) ",
-(char*) " (ALIAS , ALL, 'Remove', 'ecflow_client --delete yes <full_name>', ",
-(char*) " 'Confirm remove alias <full_name>', YES) ",
-(char*) " ",
-(char*) " !!----------------------------------- ",
-(char*) " ",
-(char*) " (ALL,ALL,'-',SEPARATOR) ",
-(char*) " ",
-(char*) " (TASK|LIMIT|LABEL|METER|REPEAT|VARIABLE, ALL , 'Edit...', WINDOW(Edit)) ",
-(char*) " (TASK|ALIAS, ALL , 'Output...', WINDOW(Output) ) ",
-(char*) " ",
-(char*) " (TASK|ALIAS, SUBMITTED|ACTIVE , 'Status...', WINDOW(Jobstatus)) ",
-(char*) " (ALIAS, ALL , 'Job...', WINDOW(Job) ) ",
-(char*) " (TASK|ALIAS, ALL , 'Script...', WINDOW(Script) ) ",
-(char*) " ",
-(char*) " (SERVER, ALL , 'Suites...', WINDOW(Suites) ) ",
-(char*) " (SERVER, ALL , 'History...', WINDOW(History) ) ",
-(char*) " (SERVER, ALL , 'Zombies...', WINDOW(Zombies) ) ",
-(char*) " (ALL,ALL,'-',SEPARATOR) ",
-(char*) " (SERVER, ALL , 'Options...', WINDOW(Options) ) ",
-(char*) " (SERVER, ALL , 'Extra', MENU ) ",
-(char*) " } ",
-(char*) " ",
-(char*) " menu 'Web' ",
-(char*) " { ",
-(char*) " (TASK, ALL, 'Man', 'sh firefox %ECF_URL_BASE%/%ECF_URL%', '', YES) ",
-(char*) " (TASK, ALL, 'Script', 'sh xterm -T Script -e vim %ECF_SCRIPT%', '', YES) ",
-(char*) " (TASK, ALL, 'Job', 'sh xterm -T Job -e vim %ECF_JOB%', '', YES) ",
-(char*) " (TASK, ALL, 'Output', 'sh xterm -T Output -e vim %ECF_JOBOUT%', '', YES) ",
-(char*) " (TASK, ALL , 'TimeLine...', WINDOW(Timeline)) ",
-(char*) " ! request from Lidström Jonas https://software.ecmwf.int/issues/browse/SUP-829 ",
-(char*) " (TASK, ALL, 'Details', 'sh xterm -T Details-%ECF_NAME% -e \"grep %ECF_NAME% %ECF_LOG% ; read\"') ",
-(char*) " } ",
-(char*) " ",
-(char*) " !============================================================================== ",
-(char*) " ! Status submenu ",
-(char*) " !============================================================================== ",
-(char*) " ",
-(char*) " menu 'Status' ",
-(char*) " { ",
-(char*) " (SUITE|TASK|FAMILY, ~SUSPENDED,'Suspend', 'ecflow_client --suspend <full_name>', '',YES) ",
-(char*) " (SUITE|TASK|FAMILY, SUSPENDED ,'Resume', 'ecflow_client --resume <full_name>', '',YES) ",
-(char*) " ",
-(char*) " (ALL,ALL,'-',SEPARATOR) ",
-(char*) " ",
-(char*) " (TASK, ~ACTIVE & ~SUBMITTED, 'Rerun', 'ecflow_client --force queued <full_name>', '',YES) ",
-(char*) " (TASK, ~COMPLETE, 'Set complete', 'ecflow_client --force complete <full_name>', '',YES) ",
-(char*) " ",
-(char*) " (SUITE|TASK|FAMILY|ALIAS, ~ACTIVE & ~SUBMITTED, ",
-(char*) " 'Requeue','ecflow_client --requeue force <full_name>', 'Confirm requeuing of <full_name>', YES) ",
-(char*) " ",
-(char*) " (SUITE|FAMILY, ABORTED | SUSPENDED, ",
-(char*) " 'Requeue aborted','ecflow_client --requeue abort <full_name>', ",
-(char*) " 'Confirm requeuing aborted tasks below <full_name>', YES) ",
-(char*) " } ",
-(char*) " ",
-(char*) " !============================================================================== ",
-(char*) " ! Suite submenu ",
-(char*) " !============================================================================== ",
-(char*) " ",
-(char*) " menu 'Suite' ",
-(char*) " { ",
-(char*) " (SUITE,UNKNOWN|COMPLETE,'Begin','ecflow_client --begin <node_name>','',YES) ",
-(char*) " ",
-(char*) " (SUITE,ALL,'Cancel','ecflow_client --delete yes <full_name>', ",
-(char*) " 'Do you really want to cancel <full_name> ?',NO) ",
-(char*) " ",
-(char*) " (ALL,ALL,'-',SEPARATOR) ",
-(char*) " } ",
-(char*) " ",
-(char*) " !============================================================================== ",
-(char*) " ! Delete submenu ",
-(char*) " !============================================================================== ",
-(char*) " ",
-(char*) " menu 'Delete' ",
-(char*) " { ",
-(char*) " (ALL,HAS_TRIGGERS|HAS_TIME|HAS_DATE, 'All dependencies','ecflow_client --free-dep all <full_name>') ",
-(char*) " (ALL,HAS_TRIGGERS, 'Trigger dependencies','ecflow_client --free-dep trigger <full_name>') ",
-(char*) " (ALL,HAS_TIME, 'Time dependencies','ecflow_client --free-dep time <full_name>') ",
-(char*) " (ALL,QUEUED, 'Date dependencies','ecflow_client --free-dep date <full_name>') ",
-(char*) " } ",
-(char*) " ",
-(char*) " menu \"Order\" ",
-(char*) " { ",
-(char*) " (ALL,ALL,'Top','ecflow_client --order <full_name> top') ",
-(char*) " (ALL,ALL,'Up','ecflow_client --order <full_name> up') ",
-(char*) " (ALL,ALL,'Down','ecflow_client --order <full_name> down') ",
-(char*) " (ALL,ALL,'Bottom','ecflow_client --order <full_name> bottom') ",
-(char*) " (ALL,ALL,'Alphabetically','ecflow_client --order <full_name> alpha') ",
-(char*) " } ",
-(char*) " ",
-(char*) " menu \"Force\" ",
-(char*) " { ",
-(char*) " (NODE, ~UNKNOWN, 'Unknown', 'ecflow_client --force unknown recursive <full_name>') ",
-(char*) " (NODE, ~COMPLETE & ~ACTIVE & ~SUBMITTED, 'Complete', ",
-(char*) " 'ecflow_client --force complete recursive <full_name>', ",
-(char*) " 'Check running/queued jobs and Confirm force complete of <full_name>', YES) ",
-(char*) " (NODE, ~QUEUED & ~ACTIVE & ~SUBMITTED, 'Queued', ",
-(char*) " 'ecflow_client --force queued recursive <full_name>') ",
-(char*) " (NODE, ~SUBMITTED & ~ACTIVE,'Submitted', ",
-(char*) " 'ecflow_client --force submitted recursive <full_name>') ",
-(char*) " (NODE, ~ACTIVE, 'Active', 'ecflow_client --force active recursive <full_name>') ",
-(char*) " (NODE, ~ABORTED, 'Aborted', 'ecflow_client --force aborted recursive <full_name>', ",
-(char*) " 'Check running/queued jobs and Confirm force submitted of <full_name>', YES) ",
-(char*) " } ",
-(char*) " ",
-(char*) " menu \"Defstatus\" ",
-(char*) " { ",
-(char*) " (NODE, ALL, 'Complete', 'ecflow_client --alter change defstatus complete <full_name>') ",
-(char*) " (NODE, ALL, 'Queued', 'ecflow_client --alter change defstatus queued <full_name>') ",
-(char*) " } ",
-(char*) " ",
-(char*) " menu \"Special\" ",
-(char*) " { ",
-(char*) " (SUITE|FAMILY,(ACTIVE|SUBMITTED|ABORTED),'Kill', 'ecflow_client --kill <full_name>','',YES) ",
-(char*) " (TASK|ALIAS,(ACTIVE|SUBMITTED),'Kill','ecflow_client --kill <full_name>','',YES) ",
-(char*) " (ALL,ALL,'Check',WINDOW(Check),'',YES) ",
-(char*) " (TASK|ALIAS,ALL,'Free password','ecflow_client --alter add variable ECF_PASS FREE <full_name>') ",
-(char*) " (TASK|ALIAS,ALL,'ClearZ','ecflow_client --alter clear_flag zombie <full_name>') ",
-(char*) " (TASK|ALIAS,ALL,'ClearLate','ecflow_client --alter clear_flag late <full_name>') ",
-(char*) " ",
-(char*) " (FAMILY, ~ACTIVE & ~SUBMITTED, 'Execute', 'ecflow_client --run <full_name>') ",
-(char*) " ((SUITE|FAMILY|TASK), SELECTION, 'Plug into selected node', PLUG) ",
-(char*) " (TASK|ALIAS, SELECTION, 'Compare Edit (vs selected)', COMP( 'compare' , 'edit' )) ",
-(char*) " (TASK|ALIAS, SELECTION, 'Compare EditPP (vs selected)', COMP( 'compare' , 'editpp')) ",
-(char*) " (TASK|ALIAS, SELECTION, 'Compare output (vs selected)', COMP('compare' , 'output')) ",
-(char*) " (FAMILY|TASK,ALL,'get','ecflow_client --get <full_name>') ",
-(char*) " (TASK,ALL,'status','ecflow_client --status <full_name>') ",
-(char*) " (SUITE|SERVER, ALL, 'Collect...', WINDOW(Collector)) ",
-(char*) " (SUITE|FAMILY, ALL, 'Walk', 'ecflow_client --force-dep-eval <full_name>') ",
-(char*) " } ",
-(char*) " ",
-(char*) " menu \"Extra\" ",
-(char*) " { ",
-(char*) " (SERVER|SUITE,ALL,'Windows', MENU) ",
-(char*) " (ALL,ALL,'-',SEPARATOR) ",
-(char*) " (SERVER,ALL,'ClearLate','ecflow_client --alter clear_flag late <full_name>') ",
-(char*) " ! (SERVER|SUITE,ALL,'tail log', 'sh /usr/bin/xterm -e rsh %ECF_NODE% tail -f %ECF_HOME%/%ECF_LOG%&') ",
-(char*) " (SERVER|SUITE,ALL,'tail log', 'sh /usr/bin/xterm -e tail -f /tmp/$USER/$HOST*.ecf.log&') ",
-(char*) " (ALL,ALL,'-',SEPARATOR) ",
-(char*) " (SERVER|SUITE,ALL,'overwrite', 'write menu') ",
-(char*) " (SERVER|SUITE,ALL,'edit menu', 'sh /usr/bin/xterm -e vi ~/.ecflowrc/ecflowview.menu') ",
-(char*) " (SERVER|SUITE,ALL,'bkup menu', 'sh /bin/cp ~/.ecflowrc/ecflowview.menu ~/.ecflowrc/ecflowview.menu.bak') ",
-(char*) " (SERVER|SUITE,ALL,'rm menu', 'sh /bin/rm ~/.ecflowrc/ecflowview.menu') ",
-(char*) " (ALL,ALL,'-',SEPARATOR) ",
-(char*) " (SERVER|SUITE,ALL,'debug on', 'ecflow_client --debug_server_on') ",
-(char*) " (SERVER|SUITE,ALL,'debug off','ecflow_client --debug_server_off') ",
-(char*) " (ALL,ALL,'-',SEPARATOR) ",
-(char*) " (SERVER|SUITE,ALL,'stats','ecflow_client --stats') ",
-(char*) " (SERVER|SUITE,ALL,'suites','ecflow_client --suites') ",
-(char*) " (ALL,ALL,'-',SEPARATOR) ",
-(char*) " (SERVER|SUITE,ALL,'log get','ecflow_client --log get') ",
-(char*) " (SERVER|SUITE,ALL,'log clear','ecflow_client --log clear') ",
-(char*) " (SERVER|SUITE,ALL,'log new','ecflow_client --log new') ",
-(char*) " (ALL,ALL,'-',SEPARATOR) ",
-(char*) " (SERVER|SUITE,ALL,'svr load','ecflow_client --server_load') ",
-(char*) " (SERVER|SUITE,ALL,'svr load local','ecflow_client --server_load %ECF_HOME%/%ECF_LOG%') ",
-(char*) " (ALL,ALL,'-',SEPARATOR) ",
-(char*) " (SERVER|SUITE,ALL,'client logging on','ecflow_client --enable_logging') ",
-(char*) " (SERVER|SUITE,ALL,'client loggging off','ecflow_client --disable_logging') ",
-(char*) " } ",
-(char*) " ",
-(char*) " menu \"Windows\" ",
-(char*) " { ",
-(char*) " (SERVER, ALL , 'Info...', WINDOW(Info)) ",
-(char*) " (SERVER, ALL , 'Man...', WINDOW(Manual)) ",
-(char*) " (SERVER, ALL , 'Var...', WINDOW(Variables)) ",
-(char*) " (SERVER, ALL , 'Msg...', WINDOW(Messages)) ",
-(char*) " (SERVER, ALL , 'Why...', WINDOW(Why)) ",
-(char*) " (SERVER, ALL , 'Triggers...', WINDOW(Triggers)) ",
-(char*) " (SERVER, ALL , 'Check...', WINDOW(Check)) ",
-(char*) " (SERVER, ALL , 'Jobstatus...', WINDOW(Jobstatus)) ",
-(char*) " (SERVER, ALL , 'TimeLine...', WINDOW(Timeline)) ",
-(char*) " } ",
-(char*) " ",
-NULL
diff --git a/ecflow_4_0_7/view/src/edit.cc b/ecflow_4_0_7/view/src/edit.cc
deleted file mode 100644
index 350a61c..0000000
--- a/ecflow_4_0_7/view/src/edit.cc
+++ /dev/null
@@ -1,264 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #13 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <unistd.h>
-#include "host.h"
-#include "edit.h"
-#include "node.h"
-#include "globals.h"
-#include "input.h"
-#include "error.h"
-#include "lister.h"
-#include "tmp_file.h"
-
-#include <Xm/Label.h>
-#include <Xm/Text.h>
-#include <Xm/ToggleB.h>
-#include <X11/IntrinsicP.h>
-#include <vector>
-
-static const char* micro="%";
-const char* sStart = "comment - ecf user variables";
-const char* sEnd = "end - ecf user variables";
-
-extern "C" {
-#include "xec.h"
-}
-
-edit::edit(panel_window& w):
- panel(w),
- text_window(false),
- loading_(False),
- preproc_(False),
- tmp_(0), kStart(0x0), kEnd(0x0)
-{
- if (kStart==NULL)
- kStart=(char*)calloc(1024, sizeof(char*));
- if (kEnd==NULL)
- kEnd=(char*)calloc(1024, sizeof(char*));
-}
-
-edit::~edit()
-{
- if(tmp_) XtFree(tmp_);
- if (kStart) free(kStart);
- if (kEnd) free(kEnd);
-}
-
-void edit::create (Widget parent, char *widget_name )
-{
- edit_form_c::create(parent,widget_name);
- XmToggleButtonSetState(alias_, globals::get_resource("send_as_alias", 0), FALSE);
-}
-
-void edit::clear()
-{
- loading_ = True;
- XmTextSetString(text_,(char*)"");
- loading_ = False;
-}
-
-void edit::show(node& n)
-{
- loading_ = True;
- XmTextSetString(text_,(char*)"");
-
- // tmp_file v(tmpnam(0), true); FILE *f = fopen(v.c_str(),"w");
- char tmpname[] = "/tmp/xecfXXXXXX";
- int fid = mkstemp(tmpname);
- FILE *f = fdopen(fid, "w");
-
- if(!f) {
- gui::syserr(tmpname);
- return;
- }
-
- std::list<Variable> vl; // FILL handle vl
- tmp_file tmp(NULL);
- tmp = n.serv().edit(n, vl, preproc_);
-
- if(fclose(f)) {
- gui::syserr(tmpname);
- return;
- }
-
- xec_LoadText(text_, tmpname, True);
- xec_LoadText(text_, tmp.c_str(), True);
-
- XmTextSetInsertionPosition(text_,0);
- XmTextShowPosition(text_, 0);
-
- loading_ = False;
-}
-
-void edit::changed(node&)
-{
-}
-
-Boolean edit::enabled(node& n)
-{
- return n.type() == NODE_TASK;
-}
-
-void edit::changedCB(Widget,XtPointer data)
-{
- if(!loading_) freeze();
-}
-
-void edit::preprocCB(Widget,XtPointer data)
-{
- preproc_ = XmToggleButtonGetState(preprocess_);
- if(get_node())
- show(*get_node());
- else
- clear();
-}
-
-static char* strip(char* n)
-{
- int l = strlen(n) - 1;
- while(l >= 0 && n[l] == ' ')
- n[l--] = 0;
-
- char* p = n;
- while(*p && *p == ' ') p++;
-
- return p;
-}
-
-void edit::submitCB(Widget,XtPointer)
-{
- bool alias = XmToggleButtonGetState(alias_);
- bool run = true;
- char line[4096];
- node *nd = get_node();
-
- if(nd) {
- tmp_file t(tmpnam(0), true);
- if(xec_SaveText(text_,(char*)t.c_str())) {
- gui::syserr(t.c_str());
- return;
- }
-
- NameValueVec var;
- FILE *f = fopen(t.c_str(),"r");
- if(!f) {
- gui::syserr(t.c_str());
- return;
- }
-
- const std::string& mv = nd->__node__() ?
- nd->variable("ECF_MICRO") : nd->variable("SMSMICRO");
- const char * mic = (mv.size() == 1) ? mv.c_str() : micro;
- sprintf(kStart, "%s%s", mic, sStart);
- sprintf(kEnd, "%s%s", mic, sEnd);
-
- bool isvars = false;
- while(fgets(line,sizeof(line),f)) {
- line[strlen(line)-1] = 0;
-
- if(isvars) {
- char* p = line;
- while(*p && *p != '=') p++;
- if(*p == '=') {
- *p = 0;
-
- char n[1024];
- char v[1024];
-
- strcpy(n,line);
- strcpy(v,p+1);
-
- var.push_back(std::make_pair(strip(n), strip(v)));
- }
- }
-
- if (strcmp(line,kStart) == 0)
- isvars = true;
- if(strcmp(line,kEnd) == 0)
- break;
- }
-
- if(var.empty()) {
- gui::message("No user variables!");
- // return;
- }
-
- get_node()->serv().send(*get_node(),alias,run,var,t.c_str());
-
- } else
- clear();
-
- if (alias != globals::get_resource("send_as_alias", 0))
- globals::set_resource("send_as_alias", alias);
-
- submit();
-}
-
-void edit::externalCB(Widget,XtPointer)
-{
- if(tmp_) XtFree(tmp_);
- tmp_ = XtNewString(tmpnam(0));
-
- if(xec_SaveText(text_,tmp_))
- {
- gui::syserr(tmp_);
- return;
- }
-
- char cmd[1024];
- const char* xedit = getenv("XEDITOR");
- if (xedit)
- sprintf(cmd,"${XEDITOR:=xterm -e vi} %s",tmp_);
- else
- sprintf(cmd,"xterm -e ${EDITOR:=vi} %s",tmp_);
-
- FILE *f = popen(cmd,"r");
- if(!f) {
- gui::syserr(cmd);
- return;
- }
- XtSetSensitive(text_,False);
- XtSetSensitive(tools_,False);
- XtSetSensitive(tools2_,False);
-
- start(f);
-}
-
-void edit::ready(const char* line)
-{
- gui::error("%s",line);
-}
-
-void edit::done(FILE* f)
-{
- stop();
-
- if(pclose(f)) {
- gui::error("External editor returns error");
- return;
- }
-
- if(xec_LoadText(text_,tmp_,False))
- gui::syserr(tmp_);
-
- unlink(tmp_);
-
- XtSetSensitive(text_,True);
- XtSetSensitive(tools_,True);
- XtSetSensitive(tools2_,True);
-}
-
-// static panel_maker<edit> maker(PANEL_EDIT_TASK);
diff --git a/ecflow_4_0_7/view/src/edit.h b/ecflow_4_0_7/view/src/edit.h
deleted file mode 100644
index c308927..0000000
--- a/ecflow_4_0_7/view/src/edit.h
+++ /dev/null
@@ -1,76 +0,0 @@
-#ifndef edit_H
-#define edit_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "uiedit.h"
-
-#ifndef panel_H
-#include "panel.h"
-#endif
-
-#include "input.h"
-#include "text_window.h"
-
-class edit : public panel, public edit_form_c, public input, public text_window {
-public:
- edit(panel_window&);
-
- ~edit(); // Change to virtual if base class
-
- virtual const char* name() const { return "Edit"; }
- virtual void show(node&);
- virtual void clear();
- virtual Boolean enabled(node&);
- virtual Widget widget() { return edit_form_c::xd_rootwidget(); }
- virtual Widget tools() { return tools_; }
- virtual Widget text() { return text_; }
-
- virtual void create (Widget parent, char *widget_name = NULL);
-
-private:
-
- edit(const edit&);
- edit& operator=(const edit&);
-
- Boolean loading_;
- Boolean preproc_;
- char* tmp_;
-
- char *kStart;
- char *kEnd ;
-
- void ready(const char*);
- void done(FILE*);
-
- virtual void changed(node&);
-
- virtual void changedCB(Widget,XtPointer);
- virtual void preprocCB(Widget,XtPointer);
- virtual void submitCB(Widget,XtPointer);
- virtual void externalCB(Widget,XtPointer);
-
- virtual void searchCB(Widget ,XtPointer )
- { text_window::open_search();}
-
- virtual bool can_print() { return true; }
- virtual bool can_save() { return true; }
- virtual void print() { text_window::print(); }
- virtual void save() { text_window::save(); }
-};
-
-inline void destroy(edit**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/edit_label.cc b/ecflow_4_0_7/view/src/edit_label.cc
deleted file mode 100644
index b240616..0000000
--- a/ecflow_4_0_7/view/src/edit_label.cc
+++ /dev/null
@@ -1,86 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "edit_label.h"
-#include "label_node.h"
-#include "host.h"
-#include <Xm/Text.h>
-extern "C" {
-#include "xec.h"
-}
-
-edit_label::edit_label(panel_window& w):
- panel(w),
- loading_(false)
-{
-}
-
-edit_label::~edit_label()
-{
-}
-
-void edit_label::clear()
-{
- loading_ = true;
- XmTextSetString(value_,"");
- XmTextSetString(default_,"");
- loading_ = false;
-}
-
-void edit_label::show(node& n)
-{
-
- label_node& m = (label_node&)n;
-
- loading_ = true;
- XmTextSetString(value_,(char*)m.value());
- XmTextSetString(default_,(char*)m.def());
-
- loading_ = false;
-}
-
-Boolean edit_label::enabled(node& n)
-{
- return n.type() == NODE_LABEL;
-}
-
-void edit_label::applyCB(Widget,XtPointer)
-{
- // alter -m node value
- if(get_node())
- {
- char *p = XmTextGetString(value_);
- if (get_node()->__node__()) /* ecflow */
- get_node()->serv().command(clientName,"--alter", "change", "label",
- get_node()->name().c_str(), p,
- get_node()->parent_name().c_str(),
- NULL);
- else
- get_node()->serv().command("alter", "-l",
- get_node()->full_name().c_str(), p, NULL);
- XtFree(p);
- }
- else clear();
-
- submit();
-}
-
-void edit_label::changedCB(Widget,XtPointer)
-{
- if(loading_) return;
- freeze();
-}
-
-// static panel_maker<edit_label> maker(PANEL_EDIT_LABEL);
diff --git a/ecflow_4_0_7/view/src/edit_label.h b/ecflow_4_0_7/view/src/edit_label.h
deleted file mode 100644
index 7cce8cc..0000000
--- a/ecflow_4_0_7/view/src/edit_label.h
+++ /dev/null
@@ -1,137 +0,0 @@
-#ifndef edit_label_H
-#define edit_label_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-// Headers
-// #ifndef machine_H
-// #include <machine.h>
-// #endif
-
-// Forward declarations
-
-// class ostream;
-// typedef class _Pvts os_typespec; // Remove if not persistant
-
-
-#include "uiedit_label.h"
-
-#ifndef panel_H
-#include "panel.h"
-#endif
-
-//
-
-class edit_label : public panel, public edit_label_form_c {
-public:
-
-// -- Exceptions
- // None
-
-// -- Contructors
-
- edit_label(panel_window&);
-
-// -- Destructor
-
- ~edit_label(); // Change to virtual if base class
-
-// -- Convertors
- // None
-
-// -- Operators
- // None
-
-// -- Methods
- // None
-
-// -- Overridden methods
-
- virtual const char* name() const { return "Edit"; }
- virtual void show(node&);
- virtual Boolean enabled(node&);
- virtual void clear();
- virtual Widget widget() { return xd_rootwidget(); }
- virtual Widget tools() { return tools_; }
-
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
- // Uncomment for persistent, remove otherwise
- // static os_typespec* get_os_typespec();
-
-protected:
-
-// -- Members
- // None
-
-// -- Methods
-
- // void print(ostream&) const; // Change to virtual if base class
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-private:
-
-// No copy allowed
-
- edit_label(const edit_label&);
- edit_label& operator=(const edit_label&);
-
-// -- Members
- bool loading_;
-
-// -- Methods
- // None
-
-// -- Overridden methods
-
- virtual void applyCB(Widget,XtPointer);
- virtual void changedCB(Widget,XtPointer);
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-// -- Friends
-
- //friend ostream& operator<<(ostream& s,const edit_label& p)
- // { p.print(s); return s; }
-
-};
-
-inline void destroy(edit_label**) {}
-
-// If persistent, uncomment, otherwise remove
-//#ifdef _ODI_OSSG_
-//OS_MARK_SCHEMA_TYPE(edit_label);
-//#endif
-
-
-#endif
diff --git a/ecflow_4_0_7/view/src/edit_limit.cc b/ecflow_4_0_7/view/src/edit_limit.cc
deleted file mode 100644
index c009535..0000000
--- a/ecflow_4_0_7/view/src/edit_limit.cc
+++ /dev/null
@@ -1,146 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "edit_limit.h"
-#include "limit_node.h"
-#include "host.h"
-#include <Xm/Text.h>
-#include <Xm/List.h>
-extern "C" {
-#include "xec.h"
-}
-
-edit_limit::edit_limit(panel_window& w):
- panel(w),
- loading_(false),
- name_(0)
-{
-}
-
-edit_limit::~edit_limit()
-{
- if(name_) XtFree(name_);
-}
-
-void edit_limit::clear()
-{
- loading_ = true;
- XmTextSetString(max_,(char*)"");
- XmListDeleteAllItems(list_);
- XtSetSensitive(remove_,False);
- forget_all();
- loading_ = false;
- if(name_) XtFree(name_);
- name_ = 0;
-}
-
-void edit_limit::show(node& n)
-{
- clear();
-
- limit_node& m = (limit_node&)n;
-
- char buf[80];
- loading_ = true;
-
- sprintf(buf,"%d",m.maximum()); XmTextSetString(max_,buf);
-
- m.nodes(*this);
-
- loading_ = false;
-}
-
-Boolean edit_limit::enabled(node& n)
-{
- return n.type() == NODE_LIMIT;
-}
-
-void edit_limit::applyCB(Widget,XtPointer)
-{
- // alter -m node value
- if(get_node()) {
- char *p = XmTextGetString(max_);
- if (1) {
- if (get_node()->__node__()) /* ecflow */
- get_node()->serv().command(clientName,"--alter", "change","limit_max",
- get_node()->name().c_str(),p,
- get_node()->parent_name().c_str(),
- NULL);
- else
- get_node()->serv().command("alter", "-M",
- get_node()->full_name().c_str(), p, NULL);
- } else {
- std::string cmd;
- if (get_node()->__node__()) { /* ecflow */
- cmd = clientName; cmd+= "--alter change limit_max <node_name> ";
- cmd += p; cmd += " <parent_name>";
- } else {
- cmd = "alter -M <full_name> "; cmd += p;
- }
- get_node()->command(cmd.c_str());
- }
- XtFree(p);
- } else {
- clear();
- }
- submit();
-}
-
-void edit_limit::changedCB(Widget,XtPointer)
-{
- if(loading_) return;
- freeze();
-}
-
-void edit_limit::browseCB(Widget,XtPointer data)
-{
- XmListCallbackStruct *cb = (XmListCallbackStruct *) data;
- char *p = xec_GetString(cb->item);
- if(name_) XtFree(name_);
- name_ = p;
- XtSetSensitive(remove_,True);
-}
-
-void edit_limit::removeCB(Widget,XtPointer data)
-{
- if(get_node()) {
- if(name_) {
- if (get_node()->__node__()) /* ecflow */
- get_node()->serv().command(clientName,"--alter", "delete","limit_path",
- get_node()->name().c_str(), // limit name
- name_,
- get_node()->parent_name().c_str(),
- NULL); // task node name
- else
- get_node()->serv().command("alter", "-N",
- get_node()->full_name().c_str(),
- name_,
- NULL);
- }
- } else {
- clear();
- }
-}
-
-void edit_limit::next(node& n)
-{
- observe(&n);
- xec_AddListItem(list_,(char*)n.full_name().c_str());
-}
-
-void edit_limit::next(const std::string n)
-{
- xec_AddListItem(list_,(char*)n.c_str());
-}
diff --git a/ecflow_4_0_7/view/src/edit_limit.h b/ecflow_4_0_7/view/src/edit_limit.h
deleted file mode 100644
index 4a600ae..0000000
--- a/ecflow_4_0_7/view/src/edit_limit.h
+++ /dev/null
@@ -1,60 +0,0 @@
-#ifndef edit_limit_H
-#define edit_limit_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "uiedit_limit.h"
-
-#ifndef panel_H
-#include "panel.h"
-#endif
-
-#ifndef node_lister_H
-#include "node_lister.h"
-#endif
-
-class edit_limit : public panel, public edit_limit_form_c, public node_lister {
-public:
-
- edit_limit(panel_window&);
-
- ~edit_limit(); // Change to virtual if base class
-
- virtual const char* name() const { return "Edit"; }
- virtual void show(node&);
- virtual Boolean enabled(node&);
- virtual void clear();
- virtual Widget widget() { return xd_rootwidget(); }
- virtual Widget tools() { return tools_; }
-private:
-
- edit_limit(const edit_limit&);
- edit_limit& operator=(const edit_limit&);
-
- bool loading_;
- char* name_;
-
- virtual void applyCB(Widget,XtPointer);
- virtual void changedCB(Widget,XtPointer);
- virtual void removeCB(Widget,XtPointer);
- virtual void browseCB(Widget,XtPointer);
-
- virtual void next(node&);
- virtual void next(const std::string);
-};
-
-inline void destroy(edit_limit**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/edit_meter.cc b/ecflow_4_0_7/view/src/edit_meter.cc
deleted file mode 100644
index 4c5b19e..0000000
--- a/ecflow_4_0_7/view/src/edit_meter.cc
+++ /dev/null
@@ -1,91 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "edit_meter.h"
-#include "meter_node.h"
-#include "host.h"
-#include <Xm/Text.h>
-extern "C" {
-#include "xec.h"
-}
-
-edit_meter::edit_meter(panel_window& w):
- panel(w),
- loading_(false)
-{
-}
-
-edit_meter::~edit_meter()
-{
-}
-
-void edit_meter::clear()
-{
- loading_ = true;
- XmTextSetString(min_,(char*)"");
- XmTextSetString(value_,(char*)"");
- XmTextSetString(max_,(char*)"");
- XmTextSetString(threshold_,(char*)"");
- loading_ = false;
-}
-
-void edit_meter::show(node& n)
-{
- meter_node& m = (meter_node&)n;
-
- char buf[80];
- loading_ = true;
-
- sprintf(buf,"%d",m.minimum()); XmTextSetString(min_,buf);
- sprintf(buf,"%d",m.value()); XmTextSetString(value_,buf);
- sprintf(buf,"%d",m.maximum()); XmTextSetString(max_,buf);
- sprintf(buf,"%d",m.threshold()); XmTextSetString(threshold_,buf);
-
- loading_ = false;
-}
-
-Boolean edit_meter::enabled(node& n)
-{
- return n.type() == NODE_METER;
-}
-
-void edit_meter::applyCB(Widget,XtPointer)
-{
- // alter -m node value
- if(get_node())
- {
- char *p = XmTextGetString(value_);
- if (get_node()->__node__()) /* ecflow */
- get_node()->serv().command(clientName, "--alter", "change", "meter",
- get_node()->name().c_str(), p,
- get_node()->parent_name().c_str(),
- NULL);
- else
- get_node()->serv().command("alter", "-m",
- get_node()->full_name().c_str(), p, NULL);
- XtFree(p);
- }
- else clear();
-
- submit();
-}
-
-void edit_meter::changedCB(Widget,XtPointer)
-{
- if(loading_) return;
- freeze();
-}
-
-// static panel_maker<edit_meter> maker(PANEL_EDIT_METER);
diff --git a/ecflow_4_0_7/view/src/edit_meter.h b/ecflow_4_0_7/view/src/edit_meter.h
deleted file mode 100644
index b8c04b0..0000000
--- a/ecflow_4_0_7/view/src/edit_meter.h
+++ /dev/null
@@ -1,137 +0,0 @@
-#ifndef edit_meter_H
-#define edit_meter_H
-
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-// Headers
-// #ifndef machine_H
-// #include <machine.h>
-// #endif
-
-// Forward declarations
-
-// class ostream;
-// typedef class _Pvts os_typespec; // Remove if not persistant
-
-
-#include "uiedit_meter.h"
-
-#ifndef panel_H
-#include "panel.h"
-#endif
-
-//
-
-class edit_meter : public panel, public edit_meter_form_c {
-public:
-
-// -- Exceptions
- // None
-
-// -- Contructors
-
- edit_meter(panel_window&);
-
-// -- Destructor
-
- ~edit_meter(); // Change to virtual if base class
-
-// -- Convertors
- // None
-
-// -- Operators
- // None
-
-// -- Methods
- // None
-
-// -- Overridden methods
-
- virtual const char* name() const { return "Edit"; }
- virtual void show(node&);
- virtual Boolean enabled(node&);
- virtual void clear();
- virtual Widget widget() { return xd_rootwidget(); }
- virtual Widget tools() { return tools_; }
-
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
- // Uncomment for persistent, remove otherwise
- // static os_typespec* get_os_typespec();
-
-protected:
-
-// -- Members
- // None
-
-// -- Methods
-
- // void print(ostream&) const; // Change to virtual if base class
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-private:
-
-// No copy allowed
-
- edit_meter(const edit_meter&);
- edit_meter& operator=(const edit_meter&);
-
-// -- Members
- bool loading_;
-
-// -- Methods
- // None
-
-// -- Overridden methods
-
- virtual void applyCB(Widget,XtPointer);
- virtual void changedCB(Widget,XtPointer);
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-// -- Friends
-
- //friend ostream& operator<<(ostream& s,const edit_meter& p)
- // { p.print(s); return s; }
-
-};
-
-inline void destroy(edit_meter**) {}
-
-// If persistent, uncomment, otherwise remove
-//#ifdef _ODI_OSSG_
-//OS_MARK_SCHEMA_TYPE(edit_meter);
-//#endif
-
-
-#endif
diff --git a/ecflow_4_0_7/view/src/edit_repeat.cc b/ecflow_4_0_7/view/src/edit_repeat.cc
deleted file mode 100644
index 2113059..0000000
--- a/ecflow_4_0_7/view/src/edit_repeat.cc
+++ /dev/null
@@ -1,140 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #11 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "edit_repeat.h"
-#include "repeat_node.h"
-#include "host.h"
-#include "ecflowview.h"
-#include <Xm/List.h>
-#include <Xm/Text.h>
-extern "C" {
-#include "xec.h"
-}
-
-edit_repeat::edit_repeat(panel_window& w):
- panel(w),
- loading_(false),
- index_(-1),
- indexs_("")
-{
-}
-
-edit_repeat::~edit_repeat()
-{
-}
-
-void edit_repeat::clear()
-{
- loading_ = true;
- XmListDeleteAllItems(list_);
- index_ = -1;
- indexs_ = "";
- loading_ = false;
-}
-
-void edit_repeat::show(node& n)
-{
- repeat_node& m = (repeat_node&)n;
-
- loading_ = true;
-
- str80 buf;
- int end = m.last();
- int cur = m.current();
- int inc = m.step();
- XmListDeleteAllItems(list_);
-
- if(end > 50 && m.can_use_text())
- {
- use_text_ = true;
- char buf[1024];
- char buf1[1024];
- char buf2[1024];
- m.value(buf1,0);
- m.value(buf2,end-1);
- sprintf(buf,"Enter a value between %s and %s (step %d):",buf1,buf2,inc);
- xec_SetLabel(label_,buf);
- XtUnmanageChild(show_list_);
- XtManageChild(show_text_);
- m.value(buf,cur);
- XmTextSetString(text_,buf);
- }
- else
- {
- use_text_ = false;
- XtManageChild(show_list_);
- XtUnmanageChild(show_text_);
-
- for(int i=0 ; i < end ; i++)
- {
- m.value(buf,i);
- xec_AddListItem(list_,buf);
- }
-
- XmListSelectPos(list_,cur+1,True);
- }
-
- loading_ = false;
-}
-
-Boolean edit_repeat::enabled(node& n)
-{
- int i = n.type();
- return i == NODE_REPEAT ||
- i == NODE_REPEAT_E ||
- i == NODE_REPEAT_S ||
- i == NODE_REPEAT_D ||
- i == NODE_REPEAT_I;
-}
-
-void edit_repeat::applyCB(Widget,XtPointer)
-{
- if(get_node()) {
- char *p = 0x0;
- if(use_text_) {
- p = XmTextGetString(text_);
- }
-
- if (get_node()->__node__()) /* ecflow */
- get_node()->serv().command(clientName, "--alter", "change", "repeat",
- p ? p : indexs_.c_str(),
- get_node()->parent_name().c_str(),
- NULL);
- else
- get_node()->serv().command("alter", "-R",
- get_node()->full_name().c_str(), p, NULL);
-
- if (p) XtFree(p);
-
- } else {
- clear();
- }
- submit();
-}
-
-void edit_repeat::browseCB(Widget,XtPointer data)
-{
- XmListCallbackStruct *cb = (XmListCallbackStruct *) data;
- char *p = xec_GetString(cb->item);
- if(get_node())
- indexs_ = p;
- else
- indexs_ = "";
- XtFree(p);
-
- if(loading_) return;
- freeze();
-}
-
diff --git a/ecflow_4_0_7/view/src/edit_repeat.h b/ecflow_4_0_7/view/src/edit_repeat.h
deleted file mode 100644
index 13f1075..0000000
--- a/ecflow_4_0_7/view/src/edit_repeat.h
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef edit_repeat_H
-#define edit_repeat_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "uiedit_repeat.h"
-
-#ifndef panel_H
-#include "panel.h"
-#endif
-
-class edit_repeat : public panel, public edit_repeat_form_c {
-public:
- edit_repeat(panel_window&);
-
- ~edit_repeat(); // Change to virtual if base class
- virtual const char* name() const { return "Edit"; }
- virtual void show(node&);
- virtual Boolean enabled(node&);
- virtual void clear();
- virtual Widget widget() { return xd_rootwidget(); }
- virtual Widget tools() { return tools_; }
-
-private:
-
- edit_repeat(const edit_repeat&);
- edit_repeat& operator=(const edit_repeat&);
-
- bool loading_;
- int index_; std::string indexs_;
- bool use_text_;
-
- virtual void applyCB(Widget,XtPointer);
- virtual void browseCB(Widget,XtPointer);
-};
-
-inline void destroy(edit_repeat**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/edit_variable.cc b/ecflow_4_0_7/view/src/edit_variable.cc
deleted file mode 100644
index 8437765..0000000
--- a/ecflow_4_0_7/view/src/edit_variable.cc
+++ /dev/null
@@ -1,70 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "edit_variable.h"
-#include "host.h"
-#include "node.h"
-#include <Xm/Text.h>
-#include <Xm/List.h>
-extern "C" {
-#include "xec.h"
-}
-
-edit_variable::edit_variable(panel_window& w):
- panel(w),
- loading_(false)
-{
-}
-
-edit_variable::~edit_variable()
-{
-}
-
-void edit_variable::clear()
-{
- loading_ = true;
- xec_SetLabel(name_,"<no name>");
- XmTextSetString(value_,"");
- loading_ = false;
-}
-
-void edit_variable::show(node& n)
-{
- clear();
- n.edit(*this);
- loading_ = false;
-}
-
-Boolean edit_variable::enabled(node& n)
-{
- return n.type() == NODE_VARIABLE;
-}
-
-void edit_variable::applyCB(Widget,XtPointer)
-{
- if(get_node())
- get_node()->apply(*this);
- else
- clear();
- submit();
-}
-
-void edit_variable::changedCB(Widget,XtPointer)
-{
- if(loading_) return;
- freeze();
-}
-
-// static panel_maker<edit_variable> maker(PANEL_EDIT_VARIABLE);
diff --git a/ecflow_4_0_7/view/src/edit_variable.h b/ecflow_4_0_7/view/src/edit_variable.h
deleted file mode 100644
index 118c2eb..0000000
--- a/ecflow_4_0_7/view/src/edit_variable.h
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef edit_variable_H
-#define edit_variable_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "uiedit_variable.h"
-
-#ifndef panel_H
-#include "panel.h"
-#endif
-
-#ifndef node_editor_H
-#include "node_editor.h"
-#endif
-
-class edit_variable : public panel, public edit_variable_form_c,
- public node_editor {
-public:
-
- edit_variable(panel_window&);
-
- ~edit_variable(); // Change to virtual if base class
-
- virtual const char* name() const { return "Edit"; }
- virtual void show(node&);
- virtual Boolean enabled(node&);
- virtual void clear();
- virtual Widget widget() { return xd_rootwidget(); }
- virtual Widget form() { return xd_rootwidget(); }
- virtual Widget tools() { return tools_; }
-
-private:
-
- edit_variable(const edit_variable&);
- edit_variable& operator=(const edit_variable&);
-
- bool loading_;
-
- virtual void applyCB(Widget,XtPointer);
- virtual void changedCB(Widget,XtPointer);
-
-};
-
-inline void destroy(edit_variable**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/editor.cc b/ecflow_4_0_7/view/src/editor.cc
deleted file mode 100644
index 1329d92..0000000
--- a/ecflow_4_0_7/view/src/editor.cc
+++ /dev/null
@@ -1,47 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#ifndef editor_H
-#include "editor.h"
-#endif
-
-
-Widget editor::find(const char* name)
-{
- Widget w = find(name,form());
- return w;
-}
-
-Widget editor::find(const char* name,Widget p)
-{
- Widget w = XtNameToWidget(p,name);
- if(w) return w;
-
- WidgetList wl = 0;
- int count = 0;
-
- XtVaGetValues(p,
- XmNchildren,&wl,
- XtNnumChildren,&count,
- NULL);
-
- for(int i=0; i<count; i++)
- {
- w = find(name,wl[i]);
- if(w) return w;
- }
-
- return 0;
-}
diff --git a/ecflow_4_0_7/view/src/editor.h b/ecflow_4_0_7/view/src/editor.h
deleted file mode 100644
index 841e449..0000000
--- a/ecflow_4_0_7/view/src/editor.h
+++ /dev/null
@@ -1,108 +0,0 @@
-#ifndef editor_H
-#define editor_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-// Headers
-// #ifndef machine_H
-// #include <machine.h>
-// #endif
-
-// Forward declarations
-
-// class ostream;
-// typedef class _Pvts os_typespec; // Remove if not persistant
-
-//
-
-#include <Xm/Xm.h>
-
-
-class editor {
-public:
-
-// -- Methods
-
- virtual Widget form() = 0;
-
-// -- Overridden methods
-
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
- // Uncomment for persistent, remove otherwise
- // static os_typespec* get_os_typespec();
-
-protected:
-
-// -- Members
- // None
-
-// -- Methods
-
- Widget find(const char*,Widget);
- Widget find(const char* n);
-
- // void print(ostream&) const; // Change to virtual if base class
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-private:
-
-// No copy allowed
-
-
-// -- Members
- // None
-
-// -- Methods
- // None
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-// -- Friends
-
- //friend ostream& operator<<(ostream& s,const editor& p)
- // { p.print(s); return s; }
-
-};
-
-inline void destroy(editor**) {}
-
-// If persistent, uncomment, otherwise remove
-//#ifdef _ODI_OSSG_
-//OS_MARK_SCHEMA_TYPE(editor);
-//#endif
-
-#endif
diff --git a/ecflow_4_0_7/view/src/error.cc b/ecflow_4_0_7/view/src/error.cc
deleted file mode 100644
index 855d0fc..0000000
--- a/ecflow_4_0_7/view/src/error.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <stdio.h>
-#include <errno.h>
-#include <stdarg.h>
-#include "error.h"
-#include "gui.h"
-#include "ecflowview.h"
-
-
-error::error()
-{
- create(gui::top());
-}
-
-
-error::~error()
-{
-}
-
-
-void error::show(const char* msg)
-{
- instance().modal(msg,True);
-}
diff --git a/ecflow_4_0_7/view/src/error.h b/ecflow_4_0_7/view/src/error.h
deleted file mode 100644
index 0637474..0000000
--- a/ecflow_4_0_7/view/src/error.h
+++ /dev/null
@@ -1,106 +0,0 @@
-#ifndef error_H
-#define error_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "uierror.h"
-#include "dialog.h"
-
-class error : public dialog<error,error_shell_c> {
-public:
-
-// -- Exceptions
- // None
-
-// -- Contructors
-
- error();
-
-// -- Destructor
-
- ~error(); // Change to virtual if base class
-
-// -- Convertors
- // None
-
-// -- Operators
- // None
-
-// -- Methods
- // None
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
-
- static void show(const char*);
-
-protected:
-
-// -- Members
- // None
-
-// -- Methods
-
- // void print(ostream&) const; // Change to virtual if base class
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-private:
-
-// No copy allowed
-
- error(const error&);
- error& operator=(const error&);
-
-// -- Methods
-
-
-// -- Overridden methods
-
-
-// -- Class members
-
-
-// -- Class methods
- // None
-
-// -- Friends
-
- //friend ostream& operator<<(ostream& s,const error& p)
- // { p.print(s); return s; }
-
-};
-
-inline void destroy(error**) {}
-
-// If persistent, uncomment, otherwise remove
-//#ifdef _ODI_OSSG_
-//OS_MARK_SCHEMA_TYPE(error);
-//#endif
-
-#endif
diff --git a/ecflow_4_0_7/view/src/eval.h b/ecflow_4_0_7/view/src/eval.h
deleted file mode 100644
index 19ef321..0000000
--- a/ecflow_4_0_7/view/src/eval.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
- virtual Boolean is_MENU() { return 0;}
- virtual Boolean is_IDENT() { return 0;}
- virtual Boolean is_NONE() { return 0;}
- virtual Boolean is_ALL() { return 1;}
- virtual Boolean is_UNKNOWN() { return 0;}
- virtual Boolean is_SUSPENDED() { return 0;}
- virtual Boolean is_COMPLETE() { return 0;}
- virtual Boolean is_QUEUED() { return 0;}
- virtual Boolean is_SUBMITTED() { return 0;}
- virtual Boolean is_ACTIVE() { return 0;}
- virtual Boolean is_ABORTED() { return 0;}
- virtual Boolean is_CLEAR() { return 0;}
- virtual Boolean is_SET() { return 0;}
- virtual Boolean is_SHUTDOWN() { return 0;}
- virtual Boolean is_HALTED() { return 0;}
- virtual Boolean is_ECF() { return 0;}
- virtual Boolean is_SUITE() { return 0;}
- virtual Boolean is_FAMILY() { return 0;}
- virtual Boolean is_TASK() { return 0;}
- virtual Boolean is_EVENT() { return 0;}
- virtual Boolean is_LABEL() { return 0;}
- virtual Boolean is_METER() { return 0;}
- virtual Boolean is_REPEAT() { return 0;}
- virtual Boolean is_VARIABLE() { return 0;}
- virtual Boolean is_TRIGGER() { return 0;}
- virtual Boolean is_HAS_TRIGGERS() { return 0;}
- virtual Boolean is_HAS_TIME() { return 0;}
- virtual Boolean is_HAS_DATE() { return 0;}
- virtual Boolean is_SEPARATOR() { return 0;}
- virtual Boolean is_STRING() { return 0;}
- virtual Boolean is_DEFAULT_YES() { return 0;}
- virtual Boolean is_DEFAULT_NO() { return 0;}
- virtual Boolean is_EDIT() { return 0;}
- virtual Boolean is_OUTPUT() { return 0;}
diff --git a/ecflow_4_0_7/view/src/event_node.cc b/ecflow_4_0_7/view/src/event_node.cc
deleted file mode 100644
index a529bdf..0000000
--- a/ecflow_4_0_7/view/src/event_node.cc
+++ /dev/null
@@ -1,75 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "event_node.h"
-
-#ifndef ecf_node_
-#include "ecf_node.h"
-#endif
-
-event_node::event_node(host& h,ecf_node* n) : node(h,n) {}
-
-const char* event_node::status_name() const
-{
- char *event_name[] = { (char*) "clear", (char*) "set", NULL };
- return event_name[owner_->status()];
-}
-
-void event_node::drawNode(Widget w,XRectangle* r,bool tree)
-{
- drawBackground(w,r,tree);
-
- XmString s = tree ? labelTree() : labelTrigger();
- XRectangle x = *r;
-
- x.x += (x.height - 10)/2;
- x.width = x.height = 10;
-
- XFillRectangles
- (XtDisplay(w),XtWindow(w),
- // status() ? blueGC() : colorGC(0), &x,1);
- status() ? gui::colorGC(STATUS_MAX+2) : colorGC(0), &x,1);
-
- shadow(w,&x);
-
- XmStringDraw(XtDisplay(w),XtWindow(w),
- smallfont(),
- s,
- blackGC(),
- r->x + x.width + 4,
- r->y,
- r->width - x.width - 4,
- XmALIGNMENT_CENTER, XmSTRING_DIRECTION_L_TO_R,
- NULL);
-}
-
-void event_node::sizeNode(Widget w,XRectangle* r,bool tree)
-{
- XmString s = tree ? labelTree() : labelTrigger();
- r->height = XmStringHeight(smallfont(),s);
- r->width = XmStringWidth(smallfont(),s) + 14 ;
- if(r->height<10) r->height = 10;
-}
-
-bool event_node::evaluate() const
-{
- return status() != 0;
-}
-
-void event_node::perlify(FILE* f)
-{
- perl_member(f,"status",owner_->status());
-}
-
diff --git a/ecflow_4_0_7/view/src/event_node.h b/ecflow_4_0_7/view/src/event_node.h
deleted file mode 100644
index 23d53b9..0000000
--- a/ecflow_4_0_7/view/src/event_node.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef EVENT_NODE_H
-#define EVENT_NODE_H
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #10 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "node.h"
-#include "show.h"
-
-class event_node : public node {
-
- virtual void info(std::ostream&){}
- virtual bool evaluate() const;
-
- virtual void drawNode(Widget w,XRectangle* r,bool);
- virtual void sizeNode(Widget w,XRectangle* r,bool);
-
- virtual Boolean visible() const { return show::want(show::event); }
-
- const char* status_name() const;
-
- virtual void perlify(FILE*);
-
-public:
- event_node(host& h,ecf_node* n);
-#ifdef BRIDGE
- event_node(host& h,sms_node* n,char b) : node(h,n,b) {}
-#endif
-};
-
-#endif
diff --git a/ecflow_4_0_7/view/src/events.h b/ecflow_4_0_7/view/src/events.h
deleted file mode 100644
index ffdd271..0000000
--- a/ecflow_4_0_7/view/src/events.h
+++ /dev/null
@@ -1,132 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#ifndef events_H
-#define events_H
-
-// Headers
-// #ifndef machine_H
-// #include <machine.h>
-// #endif
-
-// Forward declarations
-
-// class ostream;
-// typedef class _Pvts os_typespec; // Remove if not persistant
-
-//
-
-#ifndef array_H
-#include "array.h"
-#endif
-
-
-class events {
-public:
-
-// -- Exceptions
- // None
-
-// -- Contructors
-
- events() {}
-
-// -- Destructor
-
- ~events() {}
-
-// -- Convertors
- // None
-
-// -- Operators
- // None
-
-// -- Methods
-
- int count() { return time_.count(); }
- int time(int i) { return time_[i]; }
- int status(int i) { return status_[i]; }
-
- void add(int t,int s) { time_.add(t); status_.add(s); }
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
- // Uncomment for persistent, remove otherwise
- // static os_typespec* get_os_typespec();
-
-protected:
-
-// -- Members
- // None
-
-// -- Methods
-
- // void print(ostream&) const; // Change to virtual if base class
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-private:
-
-// No copy allowed
-
- events(const events&);
- events& operator=(const events&);
-
-// -- Members
-
- array<int> time_;
- array<int> status_;
-
-// -- Methods
- // None
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-// -- Friends
-
- //friend ostream& operator<<(ostream& s,const events& p)
- // { p.print(s); return s; }
-
-};
-
-inline void destroy(events**) {}
-
-// If persistent, uncomment, otherwise remove
-//#ifdef _ODI_OSSG_
-//OS_MARK_SCHEMA_TYPE(events);
-//#endif
-
-#endif
diff --git a/ecflow_4_0_7/view/src/extent.h b/ecflow_4_0_7/view/src/extent.h
deleted file mode 100644
index 7865a98..0000000
--- a/ecflow_4_0_7/view/src/extent.h
+++ /dev/null
@@ -1,74 +0,0 @@
-#ifndef extent_H
-#define extent_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-template<class T>
-class extent {
-public:
- extent();
-
- virtual ~extent(); // Change to virtual if base class
-
- static void delete_all();
-
- extent<T>* next_;
- extent<T>* prev_;
-
- static extent<T>* first_;
- static extent<T>* last_;
-
- static T* first() { return (T*)first_; }
- T* next() { return (T*)next_; }
-};
-
-template<class T> extent<T>* extent<T>::first_ = 0;
-template<class T> extent<T>* extent<T>::last_ = 0;
-
-template<class T>
-extent<T>::extent():
- next_(0),
- prev_(last_)
-{
- if(last_)
- last_->next_ = this;
- else
- first_ = this;
- last_ = this;
-}
-
-template<class T>
-extent<T>::~extent()
-{
- if(prev_) prev_->next_ = next_; else first_ = next_;
- if(next_) next_->prev_ = prev_; else last_ = prev_;
-}
-
-
-template<class T>
-void extent<T>::delete_all()
-{
- while(first_) delete first_;
-}
-
-// gcc is broken
-#if defined (__GNUC__) || defined (hpux) || defined(mips) || defined(_AIX)
-#define IMP(T)
-#else
-#define IMP(T) extent<T>* extent<T>::first_;extent<T>* extent<T>::last_;
-#endif
-
-#endif
diff --git a/ecflow_4_0_7/view/src/external.cc b/ecflow_4_0_7/view/src/external.cc
deleted file mode 100644
index c03ea4c..0000000
--- a/ecflow_4_0_7/view/src/external.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #9 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "external.h"
-#include "host.h"
-#include "ecf_node.h"
-
-static external* head_ = 0;
-
-external::external(const char *name):
- node(host::dummy(),ecf_node::dummy_node())
-{
- name_ = name;
- next_ = head_;
- head_ = this;
-}
-
-external::~external()
-{
-}
-
-Boolean external::is_external(const char *name)
-{
- return True;
-}
-
-external& external::get(const char *name)
-{
- external* e = head_;
- while(e) {
- if(strcmp(name,e->name().c_str()) == 0)
- return *e;
- e = (external*)e->next_;
- }
- return *(new external(name));
-}
-
-void external::info(std::ostream&)
-{
-}
-
-void external::perlify(FILE* f)
-{
-}
-
-template<>
-void ecf_concrete_node<external>::set_graphic_ptr(node* n)
-{}
-
-template<>
-void ecf_concrete_node<external>::make_subtree() {}
-
diff --git a/ecflow_4_0_7/view/src/external.h b/ecflow_4_0_7/view/src/external.h
deleted file mode 100644
index 64818fa..0000000
--- a/ecflow_4_0_7/view/src/external.h
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef external_H
-#define external_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #8 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "node.h"
-
-class external : public node {
- std::string name_;
-public:
- external(const char*);
- ~external(); // Change to virtual if base class
-
- virtual Boolean menus() { return False; }
- virtual Boolean selectable() { return False; }
- virtual const std::string& full_name() const { return name(); }
- virtual void info(std::ostream&);
-
- virtual const char* type_name() const { return "external"; }
- virtual const char* status_name() const { return "unknown"; }
- virtual const std::string& name() const { return name_; }
- virtual const std::string toString() const { return name(); }
-
- static Boolean is_external(const std::string& path) { return is_external(path.c_str()); }
- static Boolean is_external(const char*);
- virtual std::ostream& print(std::ostream&s) const { return s << "extern_node\n";};
-
- static external& get(const std::string& path) { return get(path.c_str()); }
- static external& get(const char*);
-
-private:
-
- external(const external&);
- external& operator=(const external&);
-
- virtual void perlify(FILE*);
-};
-
-inline void destroy(external**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/find.cc b/ecflow_4_0_7/view/src/find.cc
deleted file mode 100644
index d1e398a..0000000
--- a/ecflow_4_0_7/view/src/find.cc
+++ /dev/null
@@ -1,173 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <stdarg.h>
-#include "find.h"
-#include "host.h"
-#include "runnable.h"
-#include <Xm/List.h>
-#include <Xm/Text.h>
-#include <Xm/ToggleB.h>
-#include <Xm/PushB.h>
-#include "gui.h"
-#include "extent.h"
-#include "flags.h"
-#include "pixmap.h"
-#include "result.h"
-#include <X11/IntrinsicP.h>
-#include <stdarg.h>
-
-extern "C" {
-#include "xec.h"
-}
-
-struct quick_find : public extent<quick_find> {
-
- str text_;
- str title_;
- bool regexp_;
- bool case_;
-
- quick_find(const str& title,const str& text,bool regexp,bool cas):
- text_(text),
- title_(title), regexp_(regexp),case_(cas) {}
-
- static void init(Widget);
-};
-
-void quick_find::init(Widget m)
-{
- quick_find* f = quick_find::first();
- while(f)
- {
- Widget w = XmCreatePushButton(m,(char*)f->title_.c_str(),0,0);
- xec_SetUserData(w,f);
- XtManageChild(w);
- f = f->next();
- }
-}
-
-static quick_find qf1("An ECF variable","%[^%]+%",true,false);
-static quick_find qf2("A shell variable",
- "(\\$\\{[_a-z0-9]+\\})|(\\$[_a-z0-9]+)",true,false);
-static quick_find qf3("A MARS error","^mars - (ERROR|FATAL)",true,true);
-
-static quick_find qf4("ecflow_client","ecflow_client",false,true);
-static quick_find qf5(" --abort"," --abort",false,true);
-static quick_find qf6(" --complete"," --complete",false,true);
-static quick_find qf7(" --init"," --init",false,true);
-static quick_find qf8("smsabort","smsabort",false,true);
-
-find::find():
- pending_(0)
-{
- _xd_rootwidget = 0;
-}
-
-find::~find()
-{
- if(_xd_rootwidget)
- XtDestroyWidget(_xd_rootwidget);
- delete pending_;
-}
-
-void find::closeCB(Widget,XtPointer)
-{
- hide();
-}
-
-void find::hide()
-{
- if(_xd_rootwidget) {
- no_message();
- XtUnmanageChild(form_);
- }
-}
-
-void find::findCB(Widget,XtPointer)
-{
- char* p = XmTextGetString(find_text_);
- search(p,XmToggleButtonGetState(case_),
- XmToggleButtonGetState(regexp_),
- XmToggleButtonGetState(back_),
- XmToggleButtonGetState(wrap_));
- XtFree(p);
-}
-
-void find::make(Widget top)
-{
- while(!XtIsShell(top))
- top = XtParent(top);
-
- if(!_xd_rootwidget)
- {
- find_shell_c::create(top);
- pixmap::find("QuickFind").set_label(quick_find_);
- quick_find::init(quick_menu_);
- }
-
-}
-
-void find::raise(Widget top)
-{
- make(top);
- XtManageChild(form_);
- XMapRaised(XtDisplay(_xd_rootwidget),XtWindow(_xd_rootwidget));
-}
-
-void find::message(const char* fmt,...)
-{
- if(!_xd_rootwidget)
- return;
-
- char buf[1024];
- va_list args;
- va_start(args,fmt);
- vsprintf(buf,fmt,args);
- xec_SetLabel(message_,buf);
- va_end(args);
-
- XtManageChild(message_);
-}
-
-void find::no_message()
-{
- if(_xd_rootwidget)
- XtUnmanageChild(message_);
-}
-
-void find::regexCB(Widget,XtPointer data)
-{
- XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct*) data;
- if(cb->set)
- XmToggleButtonSetState(back_,False,False);
- else
- XmToggleButtonSetState(case_,True,False);
-
- XtSetSensitive(back_,!cb->set);
- XtSetSensitive(case_, cb->set);
-}
-
-void find::entryCB(Widget,XtPointer data)
-{
- XmRowColumnCallbackStruct *cb = (XmRowColumnCallbackStruct *) data;
- quick_find *w = (quick_find*) xec_GetUserData (cb->widget);
- XmTextSetString(find_text_,(char*)w->text_.c_str());
- XmToggleButtonSetState(regexp_, w->regexp_,True);
- if(w->regexp_)
- XmToggleButtonSetState(case_, w->case_ ,True);
-
-}
-IMP(quick_find)
diff --git a/ecflow_4_0_7/view/src/find.h b/ecflow_4_0_7/view/src/find.h
deleted file mode 100644
index f1a6227..0000000
--- a/ecflow_4_0_7/view/src/find.h
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef find_H
-#define find_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#ifdef NO_BOOL
-#include "bool.h"
-#endif
-
-class host;
-
-#include "uifind.h"
-
-class runnable;
-
-class find : public find_shell_c {
-public:
- find();
-
- ~find(); // Change to virtual if base class
-
- void make(Widget);
- void raise(Widget);
- void hide();
- void message(const char*,...);
- void no_message();
- virtual void search(const char*,bool,bool,bool,bool) = 0;
-
- void pending(runnable* r) { pending_ = r; }
-
-private:
-
- find(const find&);
- find& operator=(const find&);
-
- runnable* pending_;
-
- void closeCB(Widget,XtPointer);
- void findCB(Widget,XtPointer);
- void regexCB(Widget,XtPointer);
- void entryCB(Widget,XtPointer);
-};
-
-inline void destroy(find**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/flags.cc b/ecflow_4_0_7/view/src/flags.cc
deleted file mode 100644
index 5a6a6b3..0000000
--- a/ecflow_4_0_7/view/src/flags.cc
+++ /dev/null
@@ -1,85 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <strings.h>
-#include "ecflowview.h"
-#include "flags.h"
-#include "globals.h"
-#include "str.h"
-#include "selection.h"
-
-#ifdef linux
-extern "C" char *cuserid(char*);
-#endif
-
-flags::~flags()
-{
-}
-
-Boolean eventFlag::eval(node* n)
-{
- if (!n) return False;
- return n->status() == status_;
-}
-
-Boolean statusFlag::eval(node* n)
-{
- if (!n) return False;
- XECFDEBUG printf("statusFlag: %d %d %d \n", n->isSimpleNode() ? 1:0,n->status(),status_);
- return n->isSimpleNode() && (n->status() == status_);
-}
-
-Boolean typeFlag::eval(node* n)
-{
- if (!n) return False;
- if (type_ == NODE_REPEAT) {
- int i = n->type();
- return i == NODE_REPEAT ||
- i == NODE_REPEAT_E || i == NODE_REPEAT_I ||
- i == NODE_REPEAT_S || i == NODE_REPEAT_D;
- }
- return n->type() == type_;
-}
-
-Boolean procFlag::eval(node* n)
-{
- if (!n) return False;
- return (n->*proc_)();
-}
-
-Boolean userFlag::eval(node* n)
-{
- /* static char* names[] = {
- (char*) "CDPUSER",
- (char*) "CDPOPER",
- (char*) "CDPADMIN",
- };
-
- const char* v = n->variable(names[level_]).c_str();
- if(v) {
- static str me(cuserid(0));
- return strcmp(me.c_str(),v) == 0;
- }
- */
- return (globals::user_level() == level_);
-}
-
-Boolean selectionFlag::eval(node* n)
-{
- return selection::current_node() != 0 && selection::current_node() != n;
-}
diff --git a/ecflow_4_0_7/view/src/flags.h b/ecflow_4_0_7/view/src/flags.h
deleted file mode 100644
index 0818f15..0000000
--- a/ecflow_4_0_7/view/src/flags.h
+++ /dev/null
@@ -1,117 +0,0 @@
-#ifndef flags_H
-#define flags_H
-
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#ifndef ecflowview_H
-#include "ecflowview.h"
-#endif
-
-#include "node.h"
-
-class flags {
-public:
- virtual Boolean eval (node *) = 0;
- virtual ~flags();
-};
-
-
-class flagNot : public flags
-{
- flags *f_;
- virtual Boolean eval (node * n) { return !f_->eval (n); }
-public:
- flagNot (flags * f) : f_ (f) { }
- ~flagNot() { delete f_; }
-};
-
-class flagOr : public flags {
- flags *a_;
- flags *b_;
- virtual Boolean eval (node * n) { return a_->eval (n) || b_->eval (n); }
-public:
- flagOr (flags * a, flags * b): a_(a), b_(b) { }
- ~flagOr() { delete a_; delete b_; }
-};
-
-class flagAnd : public flags {
- flags *a_;
- flags *b_;
- virtual Boolean eval (node * n) { return a_->eval (n) && b_->eval (n); }
-public:
- flagAnd (flags * a, flags * b): a_(a), b_(b) { }
- ~flagAnd() { delete a_; delete b_; }
-};
-
-class typeFlag : public flags {
- int type_;
-public:
- virtual Boolean eval(node *);
- typeFlag(int t) : type_(t) {}
-};
-
-class statusFlag : public flags {
- int status_;
-public:
- virtual Boolean eval(node *);
- statusFlag(int t) : status_(t) {}
-};
-
-class eventFlag : public flags {
- int status_;
-public:
- virtual Boolean eval(node *);
- eventFlag(int t) : status_(t) {}
-};
-
-class procFlag : public flags {
- typedef Boolean (node::*Proc)() const;
- Proc proc_;
-public:
- virtual Boolean eval(node *);
- procFlag(Proc p) : proc_(p) {}
-};
-
-class flagAll : public flags {
- virtual Boolean eval (node * n) { return True; }
-};
-
-class flagNone : public flags {
- virtual Boolean eval (node * n) { return False; }
-};
-
-class showFlag : public flags {
- int show_;
-public:
- virtual Boolean eval(node *);
- showFlag(int t) : show_(t) {}
-};
-
-
-class userFlag : public flags {
- int level_;
-public:
- virtual Boolean eval(node *);
- userFlag(int t) : level_(t) {}
-};
-
-class selectionFlag : public flags {
-public:
- virtual Boolean eval(node *);
- selectionFlag() {}
-};
-
-#endif
diff --git a/ecflow_4_0_7/view/src/fonts_prefs.cc b/ecflow_4_0_7/view/src/fonts_prefs.cc
deleted file mode 100644
index ba5a339..0000000
--- a/ecflow_4_0_7/view/src/fonts_prefs.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "fonts_prefs.h"
-
-void fonts_prefs::create(Widget w,char*)
-{
- fonts_form_c::create(w);
- prefs::setup(w);
-}
-
-// static fonts_prefs hp;
diff --git a/ecflow_4_0_7/view/src/fonts_prefs.h b/ecflow_4_0_7/view/src/fonts_prefs.h
deleted file mode 100644
index 3a2f78a..0000000
--- a/ecflow_4_0_7/view/src/fonts_prefs.h
+++ /dev/null
@@ -1,133 +0,0 @@
-#ifndef fonts_prefs_H
-#define fonts_prefs_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-// Headers
-// #ifndef machine_H
-// #include <machine.h>
-// #endif
-
-// Forward declarations
-
-// class ostream;
-// typedef class _Pvts os_typespec; // Remove if not persistant
-
-//
-
-#ifndef prefs_H
-#include "prefs.h"
-#endif
-
-#ifndef uifonts
-#include "uifonts.h"
-#endif
-
-
-class fonts_prefs : public prefs, public fonts_form_c {
-public:
-
-// -- Exceptions
- // None
-
-// -- Contructors
-
- fonts_prefs() {}
-
-// -- Destructor
-
- ~fonts_prefs() {}
-// -- Convertors
- // None
-
-// -- Operators
- // None
-
-// -- Methods
- // None
-
-// -- Overridden methods
-
- virtual Widget widget() { return _xd_rootwidget; }
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
- // Uncomment for persistent, remove otherwise
- // static os_typespec* get_os_typespec();
-
-protected:
-
-// -- Members
- // None
-
-// -- Methods
-
- // void print(ostream&) const; // Change to virtual if base class
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-private:
-
-// No copy allowed
-
- fonts_prefs(const fonts_prefs&);
- fonts_prefs& operator=(const fonts_prefs&);
-
-// -- Members
- // None
-
-// -- Methods
- // None
-
-// -- Overridden methods
- // None
- virtual void changedCB( Widget w, XtPointer ) { pref_editor::changed(w); }
- virtual void useCB( Widget w, XtPointer ) { pref_editor::use(w); }
-
- virtual void create(Widget w,char*);
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-// -- Friends
-
- //friend ostream& operator<<(ostream& s,const fonts_prefs& p)
- // { p.print(s); return s; }
-
-};
-
-inline void destroy(fonts_prefs**) {}
-
-// If persistent, uncomment, otherwise remove
-//#ifdef _ODI_OSSG_
-//OS_MARK_SCHEMA_TYPE(fonts_prefs);
-//#endif
-
-#endif
diff --git a/ecflow_4_0_7/view/src/fsb.cc b/ecflow_4_0_7/view/src/fsb.cc
deleted file mode 100644
index cf787d2..0000000
--- a/ecflow_4_0_7/view/src/fsb.cc
+++ /dev/null
@@ -1,91 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <stdarg.h>
-#include <stdio.h>
-#include "fsb.h"
-#include "gui.h"
-extern "C" {
-#include "xec.h"
-}
-
-fsb::fsb():
- file_(0)
-{
- create(gui::top());
-}
-
-fsb::~fsb()
-{
- if(file_) XtFree(file_);
-}
-
-
-const char* fsb::ask(const char* title,
- const char* file,const char* filter,
- const char* dir)
-{
- return instance().choose(title,file,filter,dir);
-}
-
-
-const char* fsb::choose(const char* title,
- const char* deffile,const char* filter,
- const char* directory)
-
-{
- if(file_) XtFree(file_);
- file_ = 0;
-
- set(XmNdirSpec,deffile);
- set(XmNpattern,filter);
- set(XmNdirectory,directory);
-
- instance().modal(title,True);
-
- return file_;
-
-}
-
-void fsb::set(const char* res,const char* val)
-{
- if(!val) return;
- XmString s = XmStringCreateSimple((char*)val);
- XtVaSetValues(form_,res,s,NULL);
- XmStringFree(s);
-}
-
-void fsb::okCB(Widget,XtPointer data)
-{
- XmFileSelectionBoxCallbackStruct* cb = (XmFileSelectionBoxCallbackStruct*)data;
-
- char buf[1024];
-
- char *f = (char*)xec_GetString(cb->value);
- char *d = (char*)xec_GetString(cb->dir);
-
- if(*f == '/')
- strcpy(buf,f);
- else
- sprintf(buf,"%s%s",d,f);
-
- XtFree(f);
- XtFree(d);
-
- file_ = XtNewString(buf);
-
- ok_ = true;
- stop_ = true;
-}
diff --git a/ecflow_4_0_7/view/src/fsb.h b/ecflow_4_0_7/view/src/fsb.h
deleted file mode 100644
index 6143b3a..0000000
--- a/ecflow_4_0_7/view/src/fsb.h
+++ /dev/null
@@ -1,125 +0,0 @@
-#ifndef fsb_H
-#define fsb_H
-
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#ifdef NO_BOOL
-#include "bool.h"
-#endif
-
-#include "uifsb.h"
-#include "dialog.h"
-
-class fsb : public dialog<fsb,fsb_shell_c> {
-public:
-
-// -- Exceptions
- // None
-
-// -- Contructors
-
- fsb();
-
-// -- Destructor
-
- ~fsb(); // Change to virtual if base class
-
-// -- Convertors
- // None
-
-// -- Operators
- // None
-
-// -- Methods
- // None
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
-
- static const char* ask(const char* title,
- const char* file = 0,
- const char* filter = 0,
- const char* dir = 0);
-
- // Uncomment for persistent, remove otherwise
- // static os_typespec* get_os_typespec();
-
-protected:
-
-// -- Members
- // None
-
-// -- Methods
-
- // void print(ostream&) const; // Change to virtual if base class
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-private:
-
-// No copy allowed
-
- fsb(const fsb&);
- fsb& operator=(const fsb&);
-
-
- char* file_;
-
-// -- Methods
-
- void set(const char*,const char*);
-
- const char* choose(const char*,const char*,
- const char*,const char*);
-
-
-// -- Overridden methods
-
- virtual void okCB( Widget, XtPointer ) ;
-
-// -- Class members
-
-
-// -- Class methods
- // None
-
-// -- Friends
-
- //friend ostream& operator<<(ostream& s,const fsb& p)
- // { p.print(s); return s; }
-
-};
-
-inline void destroy(fsb**) {}
-
-// If persistent, uncomment, otherwise remove
-//#ifdef _ODI_OSSG_
-//OS_MARK_SCHEMA_TYPE(fsb);
-//#endif
-
-#endif
diff --git a/ecflow_4_0_7/view/src/gen_translator.h b/ecflow_4_0_7/view/src/gen_translator.h
deleted file mode 100644
index 780ce49..0000000
--- a/ecflow_4_0_7/view/src/gen_translator.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef gen_translator_H
-#define gen_translator_H
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #4 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-
-template<class From,class To>
-class translator {
-public:
- To operator()(const From& from);
-};
-
-#endif // gen_translator_H
diff --git a/ecflow_4_0_7/view/src/globals.cc b/ecflow_4_0_7/view/src/globals.cc
deleted file mode 100644
index eb4f790..0000000
--- a/ecflow_4_0_7/view/src/globals.cc
+++ /dev/null
@@ -1,92 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <stdio.h>
-#include "globals.h"
-#include "str.h"
-#include "option.h"
-#include "configurator.h"
-#include "choice.h"
-#include "gui.h"
-#include <string>
-
-static option<int> s0(globals::instance(),"timeout",60);
-static option<int> s1(globals::instance(),"maximum",60);
-static option<bool> s3(globals::instance(),"drift",true);
-static option<bool> s4(globals::instance(),"poll",true);
-static option<bool> s5(globals::instance(),"aborted",true);
-static option<bool> s6(globals::instance(),"late",true);
-static option<bool> s7(globals::instance(),"restarted",true);
-static option<bool> s8(globals::instance(),"new_suites",false);
-static option<bool> s9(globals::instance(),"direct_read",true);
-
-static option<bool> s10(globals::instance(),"zombied",false);
-static option<bool> s11(globals::instance(),"aliases",false);
-static option<bool> s13(globals::instance(),"late_family",false);
-
-static option<bool> e1(globals::instance(),"send_as_alias",false);
-static option<int> s12(globals::instance(),"jobfile_length",10000);
-
-// User
-
-static option<choice> u0(globals::instance(),"user_level",0);
-
-
-globals::globals()
-#ifdef alpha
- :configurable("user.default")
-#endif
-{
-}
-
-globals::~globals()
-{
-}
-
-const char* globals::name() const
-{
- return "user.default";
-}
-
-globals* globals::instance()
-{
- static globals* g = new globals();
- return g;
-}
-
-
-void globals::changed(resource& c)
-{
- gui::changed(c);
-}
-
-void globals::set_resource(const str& name,int value)
-{
- option<int> o(instance(),name,value);
- o = value;
- XECFDEBUG std::cout << "# resource: " << name.c_str() << " " << value << std::endl;
-}
-
-int globals::get_resource(const str& name,int value)
-{
- option<int> o(instance(),name,value);
- return o;
-}
-
-int globals::user_level()
-{
- choice c = u0;
- return c;
-}
diff --git a/ecflow_4_0_7/view/src/globals.h b/ecflow_4_0_7/view/src/globals.h
deleted file mode 100644
index 95dd2b3..0000000
--- a/ecflow_4_0_7/view/src/globals.h
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef globals_H
-#define globals_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#ifndef option_H
-#include "option.h"
-#endif
-
-#ifndef configurable_H
-#include "configurable.h"
-#endif
-
-
-class globals : public configurable {
-public:
-
- globals();
-
- ~globals(); // Change to virtual if base class
-
- static globals* instance();
-
- static void set_resource(const str&,int);
- static int get_resource(const str&,int);
-
- static int user_level();
-
-private:
-
- globals(const globals&);
- globals& operator=(const globals&);
-
- virtual const char* name() const;
- virtual void changed(resource&);
-};
-
-inline void destroy(globals**) {}
-
-#endif
diff --git a/ecflow_4_0_7/view/src/graph_layout.cc b/ecflow_4_0_7/view/src/graph_layout.cc
deleted file mode 100644
index 12b1552..0000000
--- a/ecflow_4_0_7/view/src/graph_layout.cc
+++ /dev/null
@@ -1,455 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "arch.h"
-#include "graph_layout.h"
-#include "node.h"
-#include "reach.h"
-#include "observer.h"
-#include "dummy_node.h"
-#include "trigger_panel.h"
-#include "trigger_lister.h"
-#include "selection.h"
-#include "xec.h"
-#include "str.h"
-#include "Hyper.h"
-#include "tmp_file.h"
-#include <Xm/PushBG.h>
-#include <Xm/SeparatoG.h>
-
-class graph_node : public observer, public xnode {
-protected:
-
- graph_layout& owner_;
-
- void notification(observable*) { redraw(); }
- void adoption(observable* o,observable* n) { node_ = (node*)n; }
- void gone(observable*) { owner_.remove(this); delete this; }
-
- void draw(Widget w,XRectangle* r) { node_->drawNode(w,r,false); }
-
- void size(Widget w,XRectangle* r) { node_->sizeNode(w,r,false); }
-
-public:
- graph_node(graph_layout&,node*);
-};
-
-graph_node::graph_node(graph_layout& t,node *n):
- xnode(n),
- owner_(t)
-{
- observe(n);
-}
-
-//===============================================================
-
-struct node_relation {
- node* trigger_;
- node* through_;
- int mode_;
- node_relation* next_;
-
- node_relation(node* tg,node* th,int m):
- trigger_(tg), through_(th), mode_(m), next_(0) {}
-};
-
-//===============================================================
-
-graph_layout::graph_layout(trigger_panel& t,Widget w):
- layout(t,w),
- link_(false)
-{
- add_input_CB();
-}
-
-graph_layout::~graph_layout()
-{
- clear();
-}
-
-Widget graph_layout::menu1()
-{
- if(link_)
- return owner_.linkMenu();
- else
- return owner_.infoMenu();
-}
-
-Widget graph_layout::menu2()
-{
- return menu1();
-}
-
-xnode* graph_layout::xnode_of(node& n)
-{
- for(int i = 0; i < nodes_.count(); i++)
- if(nodes_[i]->get_node() == &n)
- return nodes_[i];
- return 0;
-}
-
-void graph_layout::clear()
-{
- int i;
- NodeReset(widget_);
- for(i = 0; i < nodes_.count(); i++)
- delete nodes_[i];
- nodes_.clear();
-
- for(i = 0; i < relations_.count(); i++)
- delete relations_[i];
- relations_.clear();
-
- link_ = false;
-}
-
-
-
-class nl1 : public trigger_lister {
- int n_;
- graph_layout& t_;
- node* g_;
- bool e_;
-public:
-
- nl1(graph_layout& t,node* g,bool e) : n_(0), t_(t), g_(g), e_(e) {}
-
- void next_node(node& n,node* p,int mode,node* t) {
- t_.relation(&n,g_,p,mode,t);
- n_++;
- }
-
- Boolean parents() { return e_; }
- Boolean kids() { return e_; }
-
- int count() { return n_; }
-};
-
-class nl2 : public trigger_lister {
- int n_;
- graph_layout& t_;
- node* g_;
- bool e_;
-public:
-
- nl2(graph_layout& t,node* g,bool e) : n_(0), t_(t), g_(g), e_(e) {}
- void next_node(node& n,node* p,int mode,node* t) {
- t_.relation(g_,&n,p,mode,t);
- n_++;
- }
- Boolean parents() { return e_; }
- Boolean kids() { return e_; }
-
- int count() { return n_; }
-};
-
-graph_node *graph_layout::get_graph_node(node* n)
-{
- if(!n) return 0;
-
- n = n->graph_node();
-
- graph_node* t = (graph_node*)xnode_of(*n);
- if(t) return t;
-
- t = new graph_node(*this,n);
- t->getBox(widget_);
- t->visibility(True);
-
- nodes_.add(t);
-
- return t;
-}
-
-void graph_layout::remove(graph_node* g)
-{
- nodes_.remove(g);
-}
-
-void graph_layout::click1(node* n,Boolean shift,Boolean control)
-{
- if(n != 0) node_window::click1(n,shift,control);
-}
-
-
-void graph_layout::click2(node* n,Boolean shift,Boolean control)
-{
- grow(n);
-
- if(shift && !control)
- {
- node *p = n->parent();
- if(p) {
- relation(p,n,0,trigger_lister::hierarchy,0);
- grow(p);
- }
- }
-
- if(control)
- {
- grow(n,True);
- }
-
- if(shift && control)
- {
- int count = 0;
- while(count != nodes_.count())
- {
- count = nodes_.count();
- for(int i = 0; i < count; i++)
- grow(nodes_[i]->get_node());
- }
- }
-}
-
-void graph_layout::show(node& n)
-{
- clear();
- grow(&n,False);
-
- graph_node *g = get_graph_node(&n);
- if(g) {
- g->select();
- g->setFocus();
- }
-}
-
-static void clear_menu(Widget menu)
-{
- WidgetList wl = 0;
- int count = 0;
-
- XtVaGetValues(menu,
- XmNchildren,&wl,
- XtNnumChildren,&count,
- NULL);
- XtUnmanageChildren(wl,count);
-}
-
-
-static void add_button(Widget menu,node* n,const char* a,const char* b)
-{
- WidgetList wl = 0;
- int count = 0;
- Widget w = 0;
-
- XtVaGetValues(menu,
- XmNchildren,&wl,
- XtNnumChildren,&count,
- NULL);
-
- for(int i = 0 ; i < count; i++)
- if(!XtIsManaged(wl[i]))
- {
- w = wl[i];
- break;
- }
-
- if(!w)
- w = XmCreatePushButtonGadget(menu,"button",NULL,0);
-
- xmstring s = xmstring(a,"bold") + xmstring(" ") + xmstring(b);
-
- XtVaSetValues(w,
- XmNlabelString, XmString(s),
- XmNuserData, n,
- NULL);
-
- XtManageChild(w);
-}
-
-static void add_separator(Widget menu)
-{
- WidgetList wl = 0;
- int count = 0;
- Widget w = 0;
-
- XtVaGetValues(menu,
- XmNchildren,&wl,
- XtNnumChildren,&count,
- NULL);
-
- for(int i = 0 ; i < count; i++)
- if(!XtIsManaged(wl[i]))
- {
- w = wl[i];
- break;
- }
-
- if(!w) w = XmCreateSeparatorGadget(menu,"button",NULL,0);
- XtManageChild(w);
-}
-
-static void tidy_menu(Widget menu)
-{
- WidgetList wl = 0;
- int count = 0;
- XtVaGetValues(menu, XmNchildren,&wl, XtNnumChildren,&count, NULL);
-
- for(int i = 0 ; i < count; i++)
- if(XmIsPushButtonGadget(wl[i]))
- if(xec_GetUserData(wl[i]) == 0)
- XtUnmanageChild(wl[i]);
-}
-
-void graph_layout::link(XEvent* event_node,node* n1,node* n2)
-{
- graph_node *g1 = get_graph_node(n1);
- graph_node *g2 = get_graph_node(n2);
- node* n = 0;
-
- link_ = false;
-
- if(g1 && g2)
- {
- link_ = true;
-
- node_relation* r = (node_relation*)g1->relation_data(g2);
-
- tmp_file tmp(tmpnam(0));
- FILE *f = fopen(tmp.c_str(),"w");
-
- if(f) {
- fprintf(f,"From: {%s}\n",n1->full_name().c_str());
- fprintf(f,"To : {%s}\n",n2->full_name().c_str());
- }
-
- clear_menu(owner_.linkMenu());
- add_button(owner_.linkMenu(),n1,"From",n1->full_name().c_str());
- add_button(owner_.linkMenu(),n2,"To",n2->full_name().c_str());
-
- while(r)
- {
- if(f) fprintf(f,"\n");
- add_separator(owner_.linkMenu());
-
- if((n = r->trigger_)) {
- if(f) fprintf(f,"Trigger: %s\n",n->definition().c_str());
- add_button(owner_.linkMenu(),n,"Trigger",n->definition().c_str());
- }
- else add_button(owner_.linkMenu(),0,"-","-");
-
- if((n = r->through_)) {
-
- if(f) fprintf(f,"Through: {%s}\n",n->full_name().c_str());
- add_button(owner_.linkMenu(),n,"Through",n->full_name().c_str());
- }
- else add_button(owner_.linkMenu(),0,"-","-");
-
- r = r->next_;
- }
- tidy_menu(owner_.linkMenu());
-
- if(f) fclose(f);
- HyperLoadFile(owner_.dependHyperText(),(char*)tmp.c_str());
- if(event_node->xbutton.button == 1)
- owner_.showDependWindow();
- }
-
- if(!link_) {
- HyperSetText(owner_.dependHyperText(),"");
- owner_.hideDependWindow();
- }
-}
-
-void graph_layout::selectNode(node *n)
-{
- if(n)
- {
- graph_node* g = (graph_node*)xnode_of(*n);
- if(g) g->show();
- selection::notify_new_selection(n);
- }
-}
-
-int graph_layout::grow(node* n,Boolean )
-{
- nl1 l1(*this,n,owner().extended());
- if(owner().triggers()) n->triggers(l1);
-
- nl2 l2(*this,n,owner().extended());
- if(owner().triggered()) n->triggered(l2);
-
- return l1.count() + l2.count();
-}
-
-void graph_layout::relation(node* from, node* to,
- node* through, int mode,node *trigger)
-{
- graph_node* from_g = get_graph_node(from);
- graph_node* to_g = get_graph_node(to);
-
- from_g->relation(to_g);
-
- node_relation* n = (node_relation*)from_g->relation_data(to_g);
- while(n)
- {
- if(n->trigger_ == trigger &&
- n->through_ == through &&
- n->mode_ == mode)
- break;
-
- n = n->next_;
- }
-
- if(n == 0) {
-
- n = new node_relation(trigger,through,mode);
- relations_.add(n);
-
- void* x = from_g->relation_data(to_g,n);
- if(x) n->next_ = (node_relation*)x;
- }
-
- switch(mode)
- {
- case trigger_lister::normal:
- break;
-
- case trigger_lister::child:
- /* from_g->relation_gc(to_g,gui::colorGC(STATUS_SUBMITTED)); */
- from_g->relation_gc(to_g,gui::blueGC());
- break;
-
- case trigger_lister::parent:
- //from_g->relation_gc(to_g,gui::colorGC(STATUS_COMPLETE));
- from_g->relation_gc(to_g,gui::blueGC());
- break;
-
- case trigger_lister::hierarchy:
- from_g->relation_gc(to_g,gui::colorGC(STATUS_ABORTED));
- break;
- }
-}
-
-class graph_layout_reacher : public reach_lister {
- graph_layout& g_;
-public:
- graph_layout_reacher(graph_layout& g) : g_(g) {}
-
- void next(node* from, node* to,node* through, int mode,node *trigger)
- {
- g_.relation(from,to,through,mode,trigger);
- }
-};
-
-void graph_layout::reach(node* n1,node* n2)
-{
- graph_layout_reacher rl(*this);
- clear();
- reach::join(n1,n2,rl);
-}
-
-//====================================================================
diff --git a/ecflow_4_0_7/view/src/graph_layout.h b/ecflow_4_0_7/view/src/graph_layout.h
deleted file mode 100644
index a9c2712..0000000
--- a/ecflow_4_0_7/view/src/graph_layout.h
+++ /dev/null
@@ -1,74 +0,0 @@
-#ifndef graph_layout_H
-#define graph_layout_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "array.h"
-
-#ifndef node_window_H
-#include "node_window.h"
-#endif
-
-#ifndef layout_H
-#include "layout.h"
-#endif
-
-class graph_node;
-struct node_relation;
-
-class graph_layout : public layout,
- public node_window {
-public:
- graph_layout(trigger_panel&,Widget);
-
- ~graph_layout(); // Change to virtual if base class
-
- graph_node* get_graph_node(node*);
- int grow(node*,Boolean = False);
- void siblings(node*);
-
- virtual void show(node&);
- virtual void clear();
- virtual void reach(node*,node*);
- virtual void selectNode(node*);
- virtual xnode* xnode_of(node&);
- virtual void click1(node*,Boolean,Boolean);
- virtual void click2(node*,Boolean,Boolean);
-
- Widget node_widget() { return widget_; }
- void remove(graph_node*);
-
- void relation(node*,node*,node*,int,node*);
-
-private:
-
- graph_layout(const graph_layout&);
- graph_layout& operator=(const graph_layout&);
-
- array<graph_node*> nodes_;
- array<node_relation*> relations_;
- bool link_;
-
- void scan(node*,node*);
-
- virtual Widget menu1();
- virtual Widget menu2();
-
- virtual void link(XEvent*,node*,node*);
-};
-
-inline void destroy(graph_layout**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/gui.cc b/ecflow_4_0_7/view/src/gui.cc
deleted file mode 100644
index 335d006..0000000
--- a/ecflow_4_0_7/view/src/gui.cc
+++ /dev/null
@@ -1,377 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #8 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <stdarg.h>
-#include <stdio.h>
-#include "gui.h"
-#include "top.h"
-#include "str.h"
-#include "option.h"
-#include "host.h"
-#include "globals.h"
-#include "Str.hpp"
-
-#include <string.h> /* strerror */
-using namespace ecf;
-
-static interface* intf_= 0;
-
-// Colors
-
-static resource* gui_resources[] = {
- new option<str>(globals::instance(),"color_black","black"),
- new option<str>(globals::instance(),"color_blue","blue"),
- new option<str>(globals::instance(),"color_red","red"),
-
- new option<str>(globals::instance(),"color_unknown", "grey"),
- new option<str>(globals::instance(),"color_suspended", "orange"),
- new option<str>(globals::instance(),"color_complete", "yellow"),
- new option<str>(globals::instance(),"color_queued", "lightblue"),
- new option<str>(globals::instance(),"color_submitted", "turquoise"),
- new option<str>(globals::instance(),"color_active", "green"),
- new option<str>(globals::instance(),"color_aborted", "red"),
- new option<str>(globals::instance(),"color_shutdown", "pink"),
- new option<str>(globals::instance(),"color_halted", "violet"),
-
- new option<str>(globals::instance(),"color_meter_low", "blue"),
- new option<str>(globals::instance(),"color_threshold", "blue"),
- new option<str>(globals::instance(),"color_event", "blue"),
-
- new option<str>(globals::instance(),"normal_font_plain",
- "-*-helvetica-medium-r-normal-*-12-*-*-*-*-*-*-*"),
-
- new option<str>(globals::instance(),"normal_font_bold",
- "-*-helvetica-bold-r-normal-*-12-*-*-*-*-*-*-*"),
-
- new option<str>(globals::instance(),"small_font_plain",
- "-*-helvetica-medium-r-normal-*-11-*-*-*-*-*-*-*"),
-
- new option<str>(globals::instance(),"small_font_bold",
- "-*-helvetica-bold-r-normal-*-11-*-*-*-*-*-*-*"),
-
- new option<str>(globals::instance(),"tiny_font_plain",
- "-*-*-*-*-*-*-7-*-*-*-*-*-*-*"),
-
- new option<str>(globals::instance(),"tiny_font_bold",
- "-*-*-bold-*-*-*-7-*-*-*-*-*-*-*"),
-};
-
-class tidy_gui_resources {
-public:
- ~tidy_gui_resources() {
- for(unsigned int i = 0; i < XtNumber(gui_resources) ; i++)
- delete gui_resources[i];
- }
-};
-
-void split_msg(std::string& msg) {
- std::vector< std::string > lineTokens;
- Str::split(msg, lineTokens);
- msg.clear();
- for (size_t i=0; i<lineTokens.size(); ++i) {
- msg += lineTokens[i];
- if (i%10 == 0) msg += "\n";
- else msg += " ";
- }
-}
-
-#if !defined(_AIX)
-static tidy_gui_resources tgr;
-#endif
-
-void gui::login(const char* host)
-{
- if (intf_) intf_->login(host);
-}
-
-void gui::logout(const char* host)
-{
- if (intf_) intf_->logout(host);
-}
-
-void gui::add_host(const std::string& host)
-{
- if (intf_) intf_->add_host(host);
-}
-
-void gui::message(const char* fmt,...)
-{
- char buf[1024];
- va_list args;
- va_start(args,fmt);
- vsprintf(buf,fmt,args);
- intf_->message(buf);
- va_end(args);
-
- va_start(args,fmt);
- va_end(args);
-}
-
-void gui::raise()
-{
- Widget w = top();
- if(w && XtIsRealized(w))
- XMapRaised(XtDisplay(w),XtWindow(w));
-}
-
-Widget gui::top()
-{
- return intf_->top_shell();
-}
-
-Widget gui::trees()
-{
- return intf_->trees();
-}
-
-Widget gui::windows()
-{
- return intf_->windows();
-}
-
-void gui::watch(Boolean)
-{
-}
-
-void gui::clear()
-{
- intf_->clear();
-}
-
-
-Pixel gui::pixel(const char* name)
-{
- static str grey("grey");
-
- char buf[1024];
-
- sprintf(buf,"color_%s",name);
-
- str s = option<str>(globals::instance(),buf,grey);
-
- XrmValue from_value, to_value;
-
- from_value.addr = (char*)s.c_str();
- from_value.size = strlen(from_value.addr) + 1;
-
- Pixel p = 0;
-
- to_value.addr = (char*)&p;
- to_value.size = sizeof(Pixel);
-
- XtConvertAndStore(gui::top(),
- XmRString, &from_value,
- XmRPixel, &to_value);
-
- return p;
-}
-
-
-static GC makegc(Pixel p)
-{
- XGCValues values;
- XtGCMask valuemask = GCForeground;
- values.foreground = p;
-
- Widget w = gui::top();
- return XCreateGC(XtDisplay(w),XtWindow(w),valuemask,&values);
-}
-
-static XmFontList makefont(const char* name)
-{
- XrmValue from_value, to_value;
-
- from_value.addr = (char*)name;
- from_value.size = strlen( from_value.addr ) + 1;
-
- XmFontList p = 0;
-
- to_value.addr = (char*)&p;
- to_value.size = sizeof(XmFontList);
-
- XtConvertAndStore(gui::top(),
- XmRString, &from_value,
- XmRFontList, &to_value);
-
- return p;
-}
-
-static XmFontList font(const char* name)
-{
- char buf[1024];
-
- sprintf(buf,"%s_plain",name);
- str plain = option<str>(globals::instance(),buf,"fixed");
-
- sprintf(buf,"%s_bold",name);
- str bold = option<str>(globals::instance(),buf,"fixed");
-
- str f = plain + str("=normal,") + bold + str("=bold");
- return makefont(f.c_str());
-}
-
-inline GC makegc(const char* p)
-{
- return makegc(gui::pixel(p));
-}
-
-static Pixel *status_colors = 0;
-
-char *ecf_colors_name[]
-= { (char*)"unknown", (char*)"suspended", (char*)"complete", (char*)"queued", (char*)"submitted", (char*)"active",
- (char*)"aborted", (char*)"shutdown", (char*)"halted" ,
- (char*)"meter_low",(char*)"threshold" , (char*)"event" ,
- NULL };
-
-Pixel gui::colors(unsigned int n)
-{
- if(status_colors == 0)
- {
- status_colors = new Pixel[XtNumber(::ecf_colors_name)];
- for(unsigned int i = 0 ; i < XtNumber(::ecf_colors_name); i++)
- status_colors[i] = gui::pixel(::ecf_colors_name[i]);
- }
- return status_colors[n];
-}
-
-static XmFontList normalFont = 0;
-static XmFontList smallFont = 0;
-static XmFontList tinyFont = 0;
-
-XmFontList gui::fontlist(void)
-{
- if(normalFont == 0)
- normalFont = font("normal_font");
- return normalFont;
-}
-
-XmFontList gui::smallfont(void)
-{
- if(smallFont == 0)
- smallFont = font("small_font");
- return smallFont;
-}
-
-XmFontList gui::tinyfont(void)
-{
- if(tinyFont == 0)
- tinyFont = font("tiny_font");
- return tinyFont;
-}
-
-GC gui::blackGC(void)
-{
- static GC gc = makegc("black");
- return gc;
-}
-
-GC gui::blueGC(void)
-{
- static GC gc = makegc("blue");
- return gc;
-}
-
-GC gui::redGC(void)
-{
- static GC gc = makegc("red");
- return gc;
-}
-
-static GC* status_gc = 0;
-GC gui::colorGC(unsigned int n)
-{
- if(status_gc == 0)
- {
- status_gc = new GC[XtNumber(::ecf_colors_name)];
- for(unsigned int i = 0 ; i < XtNumber(::ecf_colors_name); i++)
- status_gc[i] = makegc(colors(i));
- }
- if(n < 0 || n>= XtNumber(::ecf_colors_name)) return blackGC();
- return status_gc[n];
-}
-
-
-void gui::changed(resource& c)
-{
- for(unsigned int i = 0; i < XtNumber(gui_resources) ; i++)
- {
- if(&c == gui_resources[i])
- {
- delete[] status_colors; status_colors = 0;
- delete[] status_gc; status_gc = 0;
-
- normalFont = 0;
- smallFont = 0;
-
- host::redraw_all();
- break;
- }
- }
-}
-
-void gui::rename_host(const std::string& a,const std::string& b)
-{
- intf_->rename_host(a,b);
-}
-
-void gui::remove_host(const std::string& a)
-{
- intf_->remove_host(a);
-}
-
-void gui::set_interface(interface* i)
-{
- intf_= i;
-}
-
-void gui::error(const char* fmt,...)
-{
- char buf[10240];
- va_list arg;
- va_start(arg,fmt);
-
- vsprintf(buf,fmt,arg);
- va_end(arg);
-
- std::string msg = buf;
- split_msg(msg);
- intf_->error(msg.c_str());
-}
-
-void gui::error(ecf_list *l)
-{
- // char buf[10240];
- char buf[240];
- buf[0] = 0;
- while(l)
- {
- if(strlen(l->name().c_str()) + 2 >= sizeof(buf))
- break;
- if(buf[0]) strcat(buf,"\n");
- strcat(buf,l->name().c_str());
- l = l->next;
- }
- intf_->error(buf);
-}
-
-void gui::syserr(const char* msg)
-{
- gui::error("%s",msg);
-}
-
-bool gui::visible()
-{
- return intf_->visible();
-}
diff --git a/ecflow_4_0_7/view/src/gui.h b/ecflow_4_0_7/view/src/gui.h
deleted file mode 100644
index c1ddd6a..0000000
--- a/ecflow_4_0_7/view/src/gui.h
+++ /dev/null
@@ -1,83 +0,0 @@
-#ifndef gui_H
-#define gui_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "ecflowview.h"
-#include <Xm/Xm.h>
-#include <string>
-
-class resource;
-class interface;
-class node;
-
-class gui {
-public:
-
- gui() {}
-
- static void clear();
- static void message(const char* fmt,...);
- static void watch(Boolean);
-
- static void add_host(const std::string&);
- static void rename_host(const std::string&,const std::string&);
- static void remove_host(const std::string&);
-
- static void login(const char*);
- static void logout(const char*);
-
- static Widget top();
- static Widget trees();
- static Widget windows();
-
- static void raise();
-
- //--------------------------------------
-
- static void changed(resource&);
-
- static GC blackGC();
- static GC blueGC();
- static GC redGC();
-
- static XmFontList smallfont();
- static XmFontList fontlist();
- static XmFontList tinyfont();
- static Pixel colors(unsigned int);
- static GC colorGC(unsigned int);
-
- static void set_interface(interface*);
- static Pixel pixel(const char* name);
-
-
- //------------------------------------------------------
-
- static bool visible();
-
- static void error(const char*,...);
- void error(ecf_list *l);
- static void syserr(const char*);
-
-private:
-
- gui(const gui&);
- gui& operator=(const gui&);
-
-};
-
-inline void destroy(gui**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/history.cc b/ecflow_4_0_7/view/src/history.cc
deleted file mode 100644
index 2a7f623..0000000
--- a/ecflow_4_0_7/view/src/history.cc
+++ /dev/null
@@ -1,116 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "history.h"
-#include "node.h"
-#include "host.h"
-#include "selection.h"
-#include <Xm/List.h>
-extern "C" {
-#include "xec.h"
-}
-
-const int kMaxLines = 400;
-
-history::history(panel_window& w):
- panel(w),
- timeout(30),
- last_("")
-{
- panel::detach();
-}
-
-history::~history()
-{
-}
-
-void history::clear()
-{
- last_ = "";
- XmListDeleteAllItems(list_);
- timeout::disable();
-}
-
-void history::show(node& n)
-{
- timeout::enable();
- add(n.serv());
-}
-
-void history::run()
-{
- if(get_node())
- add(get_node()->serv());
- else
- clear();
-}
-
-Boolean history::enabled(node& n)
-{
- return n.type() == NODE_SUPER;
-}
-
-void history::browseCB(Widget,XtPointer data)
-{
- XmListCallbackStruct* cb = (XmListCallbackStruct*)data;
- char *p = (char*)xec_GetString(cb->item);
-
- if(get_node())
- {
- node* n = get_node()->find_match(p);
- if(n) selection::notify_new_selection(n);
- }
- else
- clear();
-
- XtFree(p);
-}
-
-void history::add(host& h)
-{
- std::list<std::string>& l = h.history(last_);
- int pos = 0;
- XtVaGetValues(list_,XmNitemCount,&pos,NULL);
- std::string prev = last_;
- std::list<std::string>::const_iterator j;
- for(j = l.begin(); j != l.end() ; ++j)
- {
- if (j->empty()) {}
- else if (*j == "") {}
- /* filter out line with time stamp older than last */
- else if (last_ != "" && strcmp(j->c_str()+3, last_.c_str()+3) <= 0) {}
- /* filter out some commands */
- else if (j->find("command:LogCmd") != std::string::npos) {}
- else if (j->find("--log=get") != std::string::npos) {}
- else if (j->find("--news") != std::string::npos) {}
- /* add interesting lines */
- else {
- if(pos >= kMaxLines)
- XmListDeletePos(list_,1);
- else
- pos++;
-
- int err = j->substr(0, 4)=="ERR:"; /* bold ? */
- xec_AddFontListItem(list_,(char*)j->c_str(),err);
- prev = *j;
- }
- }
-
- XmListSetBottomPos(list_,pos);
- l.clear();
- last_ = prev;
-}
-
-// static panel_maker<history> maker(PANEL_HISTORY);
diff --git a/ecflow_4_0_7/view/src/history.h b/ecflow_4_0_7/view/src/history.h
deleted file mode 100644
index 87794cb..0000000
--- a/ecflow_4_0_7/view/src/history.h
+++ /dev/null
@@ -1,59 +0,0 @@
-#ifndef history_H
-#define history_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#ifndef panel_H
-#include "panel.h"
-#endif
-
-#include "timeout.h"
-#include "ecflowview.h"
-#include "uihistory.h"
-
-class host;
-
-class history : public panel, public history_form_c, public timeout {
-public:
-
- history(panel_window&);
-
- ~history(); // Change to virtual if base class
-
- virtual const char* name() const { return "History"; }
- virtual void show(node&);
- virtual Boolean enabled(node&);
- virtual void clear();
- virtual Widget widget() { return xd_rootwidget(); }
-
-private:
-
- history(const history&);
- history& operator=(const history&);
-
- std::string last_;
-
- void run();
- void add(host&);
- void update() {}
-
- virtual void browseCB(Widget,XtPointer);
-
-};
-
-inline void destroy(history**) {}
-
-#endif
diff --git a/ecflow_4_0_7/view/src/host.cc b/ecflow_4_0_7/view/src/host.cc
deleted file mode 100644
index ec91213..0000000
--- a/ecflow_4_0_7/view/src/host.cc
+++ /dev/null
@@ -1,1791 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #122 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string>
-#include <list>
-#include <algorithm>
-#include <boost/lexical_cast.hpp>
-#include "UrlCmd.hpp"
-#include <time.h>
-
-#include "ecflowview.h"
-#include "ecflow.h"
-#include "super_node.h"
-#include <ostream>
-
-#include "show.h"
-#include "edit.h"
-
-#ifndef scripting_H
-#include "scripting.h"
-#endif
-
-#ifndef late_H
-#include "late.h"
-#endif
-
-#ifndef zombie_H
-#include "zombie.h"
-#endif
-
-#ifndef ecf_node_
-#include "ecf_node.h"
-#endif
-
-#ifndef to_check_H
-#include "to_check.h"
-#endif
-
-#ifndef directory_H
-#include "directory.h"
-#endif
-
-#ifndef aborted_H
-#include "aborted.h"
-#endif
-
-#ifndef restart_H
-#include "restart.h"
-#endif
-
-#ifndef host_H
-#include "host.h"
-#endif
-
-#ifndef passwrd_H
-#include "passwrd.h"
-#endif
-
-#ifndef error_H
-#include "error.h"
-#endif
-
-#ifndef confirm_H
-#include "confirm.h"
-#endif
-
-#ifndef selection_H
-#include "selection.h"
-#endif
-
-#ifndef init_H
-#include "init.h"
-#endif
-
-#ifndef tree_H
-#include "tree.h"
-#endif
-
-#ifndef gui_H
-#include "gui.h"
-#endif
-
-#ifndef mail_H
-#include "mail.h"
-#endif
-
-#ifndef configurator_H
-#include "configurator.h"
-#endif
-
-#ifndef node_H
-#include "node.h"
-#endif
-
-#ifndef logsvr_H
-#include "logsvr.h"
-#endif
-
-#include "Version.hpp"
-#include "ChangeMgrSingleton.hpp"
-
-#include "panel_window.h"
-#include <stdio.h>
-#include <assert.h>
-#include <boost/bind.hpp>
-
-#include "menus.h"
-/* #include <proc/readproc.h> */
-
-bool Updating::do_full_redraw_ = false;
-
-class SelectNode {
-public:
- SelectNode(const std::string& name)
- {
- node* n = selection::current_node();
- if (!n) return;
- if (name == n->serv().name()) {
- hostname_ = n->serv().name();
- current_ = selection::current_path();
- }
- }
-
- ~SelectNode()
- {
- if (hostname_.empty()) return;
- host* h = host::find(hostname_);
- if (h && !current_.empty()) {
- node *n = h->top()->find(current_);
- if (n) {
- selection::notify_new_selection(n);
- }
- }
- }
-
-private:
- std::string current_, hostname_;
-};
-
-host::host( const std::string& name, const std::string& host, int number )
- : timeout(5)
-#ifdef alpha
- , configurable(name),
-#endif
- , observable()
- , host_(host)
- , number_(number)
- , name_(name)
- , connected_(false)
- , after_command_(true)
- , passwd_("-none-")
- , timeout_(this, "timeout", 5)
- , maximum_(this, "maximum", 60)
- , drift_(this, "drift", true)
- , connect_(this, "connect", false)
- , suites_(this, "suites", std::vector<std::string>())
- , aborted_(this, "aborted", true)
- , restarted_(this, "restarted", true)
- , late_(this, "late", true)
- , poll_(this, "poll", true)
- , direct_read_(this, "direct_read", true)
- , new_suites_(this, "new_suites", true)
- , zombie_(this, "zombie", false)
- , aliases_(this, "aliases", false)
- , late_family_(this, "late_family", false)
- , to_check_(this, "to_check", false)
- , chkmail_(true)
- , top_(0)
- , tree_(0)
- , mail_(0)
- , last_(0)
- , history_len_(100)
- , updating_(false)
- , jobfile_length_(this, "jobfile_length", 10000)
-{
- if (number < 1) return; // dummy server OK;
-
- if (number_) {
- tree_ = tree::new_tree(this);
- gui::add_host(name);
- }
-
- if (timeout_ < 1) timeout_ = 1;
- if (maximum_ < 1) maximum_ = 1;
-
- frequency(timeout_);
-}
-
-host::~host()
-{
- if (tree_) {
- delete tree_;
- }
-}
-
-ehost::ehost( const std::string& name, const std::string& h, int number )
- : host(name, h, number)
-{
- try {
- std::string port = boost::lexical_cast<std::string>(number);
- client_.set_host_port(host_.c_str(), port);
- client_.set_retry_connection_period(1);
- }
- catch ( std::exception& e ) {
- gui::message("# Exception caught in host::host ");
- gui::message(e.what());
- }
- if (connect_) login();
-}
-
-ehost::~ehost()
-{
- connect_ = connected_;
- logout();
-}
-
-void host::remove_host( const std::string& name )
-{
- gui::remove_host(name);
- ecf_nick_delete(name);
- ecf_nick_write();
- host* h = host::find(name);
- if (h) {
- h->logout();
- delete h;
- }
-}
-
-void host::broadcast( bool save )
-{
- if (save) ecf_nick_write();
-}
-
-void host::login( const std::string& name )
-{
- host* h = host::find(name);
- if (h) h->login();
-}
-
-void host::logout( const std::string& name )
-{
- host* h = host::find(name);
- if (h) h->logout();
-}
-
-host* host::find( const std::string& machine, int number )
-{
- host *h = extent < host > ::first();
- while ( h ) {
- if (h->host_ == machine && h->number_ == number) return h;
- h = h->extent < host > ::next();
- }
- return 0x0;
-}
-
-host* host::find( const std::string& name )
-{
- host *h = extent < host > ::first();
- while ( h ) {
- if (h->name() && h->name() == name) return h;
- h = h->extent < host > ::next();
- }
- return 0;
-}
-
-node* host::find( const std::string& hostname, const std::string& n )
-{
- host* h = find(hostname);
- if (h && h->top_)
- return h->top_->find(n.c_str());
-
- return 0x0;
-}
-
-void host::status( Boolean force )
-{
- host *h = extent < host > ::first();
- while ( h ) {
- if (force) h->reset(force);
- h->status();
- h = h->extent < host > ::next();
- }
-}
-
-void host::redraw_all()
-{
- host *h = extent < host > ::first();
- while ( h ) {
- h->redraw();
- h = h->extent < host > ::next();
- }
-}
-
-void host::search( node_lister& s )
-{
- if (top_) top_->search(s);
-}
-
-void host::logout()
-{
- if (connected_) gui::logout(name());
- searchable::active(False);
- connected_ = false;
-
- if (tree_) {
- tree_->connected(False);
- tree_->xd_hide();
- }
-
- destroy_top(top_);
- top_ = 0x0;
-
- notify_observers();
-}
-
-void host::destroy_top(node* the_top) const
-{
- if (the_top) {
- if (the_top->__node__()) {
- the_top->__node__()->nokids(); // Suites + all children
- the_top->__node__()->unlink();
- delete the_top->__node__(); // Defs
- }
- node::destroy(the_top);
- }
-}
-
-void ehost::logout()
-{
- if (!connected_) return;
-
- try { client_.ch1_drop(); }
- catch ( std::exception &e ) {
- gui::message("host::logout-error: %s", e.what());
- }
-
- host::logout();
-}
-
-void host::run()
-{
- if (!poll_) return;
- update();
- if (drift_) drift(5, maximum_ * 60);
-}
-
-tmp_file host::file( node& n, std::string name )
-{
- return tmp_file(NULL);
-}
-
-tmp_file host::edit( node& n, std::list<Variable>& l, Boolean preproc )
-{
- return tmp_file(NULL);
-}
-
-tmp_file host::jobcheck( node& n, const std::string &cmd )
-{
- return tmp_file(NULL);
-}
-
-tmp_file ehost::jobcheck( node& n, const std::string &cmd )
-{
- std::string subcmd = n.variable(cmd);
- //std::string user = n.variable("USER");
- std::string job = n.variable("ECF_JOB");
- std::string stat = job + ".stat";
- if (n.__node__())
- if (n.__node__()->get_node())
- n.__node__()->get_node()->variableSubsitution(subcmd);
- std::string check = "sh " + subcmd;
- command(check);
- return tmp_file(stat.c_str(), false);
-}
-
-tmp_file host::jobstatus( node& n, const std::string &cmd )
-{
- return tmp_file(0);
-}
-
-tmp_file ehost::jobstatus( node& n, const std::string &cmd )
-{
- command(clientName, "--status", n.full_name().c_str(), 0x0);
- return tmp_file(0);
-}
-
-bool host::zombies( int mode, const char* name )
-{
- return false;
-}
-
-const std::vector<std::string>& ehost::messages( const node&n ) const
-{
- try {
- client_.edit_history(n.full_name());
- }
- catch ( std::exception &e ) {
- gui::message("host::messages: %s", e.what());
- }
- return client_.server_reply().get_string_vec();
-}
-
-const std::vector<std::string>& host::messages( const node&n ) const
-{
- static std::vector<std::string> vct;
- return vct;
-}
-
-bool host::get_zombies_list( std::vector<std::string>& list )
-{
- return true;
-}
-
-bool ehost::get_zombies_list( std::vector<std::string>& list )
-{
- gui::message("%s: fetching zombies_panel", this->name());
- try {
- client_.zombieGet();
- }
- catch ( std::exception &e ) {
- gui::message("host::zombies-error: %s", e.what());
- return false;
- }
- std::vector<Zombie> vect = client_.server_reply().zombies();
-
- if (vect.size() == 0) {
- gui::message("%s: No zombies at the moment", this->name());
- return false;
- }
-
- std::sort(
- vect.begin(),
- vect.end(),
- boost::bind(std::less<int>(), boost::bind(&Zombie::calls, _1),
- boost::bind(&Zombie::calls, _2)));
- Zombie::pretty_print(vect, list);
- return true;
-}
-
-bool ehost::zombies( int mode, const char* name )
-{
-
- if (!name) return false;
-
- try {
- gui::message("%s: updating zombies_panel", this->name());
- switch ( mode ) {
- case 1:
- client_.zombieFobCli(name);
- break;
- case 2:
- client_.zombieRemoveCli(name);
- break;
- case 3:
- client_.zombieFailCli(name);
- break;
- case 4:
- client_.zombieAdoptCli(name);
- break;
- case 5:
- client_.zombieKillCli(name);
- break;
- // case X: client_.zombieBlockCli(name); break; // ???
- default:
- break;
- }
- }
- catch ( std::exception &e ) {
- gui::message("host::zombies-error: %s", e.what());
- return false;
- }
- return true;
-}
-
-void ehost::dir( node& n, const char* path, lister<ecf_dir>& l )
-{
- loghost_ = n.variable("ECF_LOGHOST", true);
- logport_ = n.variable("ECF_LOGPORT");
- if (loghost_ == ecf_node::none()) {
- loghost_ = n.variable("LOGHOST", true);
- logport_ = n.variable("LOGPORT");
- }
- std::string::size_type pos = loghost_.find(n.variable("ECF_MICRO"));
- if (std::string::npos != pos) return;
- host::dir(n, path, l);
-}
-
-void host::dir( node& n, const char* path, lister<ecf_dir>& l )
-{
- gui::message("%s: fetching file list", name());
- if (loghost_ != ecf_node::none()) {
- logsvr the_log_server(loghost_, logport_);
-
- if (the_log_server.ok()) {
- std::auto_ptr<ecf_dir> dir(the_log_server.getdir(path));
-
- if (dir.get()) {
- l.scan(dir.get());
- return;
- }
- }
- }
-
- if (path && direct_read_) {
-
- const char* p = path;
- const char* q = 0;
-
- while ( *p ) {
- if (*p == '/') q = p;
- p++;
- }
-
- if (q) {
- char basename[1024];
- char dirname[1024];
- strcpy(dirname, path);
- dirname[q - path] = 0;
- strcpy(basename, q + 1);
-
- char* c = basename;
- while ( *c ) {
- if (*c == '.') {
- if (*(c + 1)) {
- *(c + 1) = 0;
- break;
- } /* 201311 Pontus Request */
- else {
- *c = 0;
- }
- }
- c++;
- }
-
- std::auto_ptr<ecf_dir> dir(ecf_file_dir(dirname, basename, true));
- if (dir.get()) {
- l.scan(dir.get());
- }
- }
- }
-}
-
-tmp_file host::script( node& n )
-{
- return file(n, "ECF_SCRIPT");
-}
-
-tmp_file host::output( node& n )
-{
- return file(n, "ECF_JOBOUT");
-}
-
-tmp_file host::job( node& n )
-{
- return file(n, "ECF_JOB");
-}
-
-int host::status()
-{
- int e = update();
- frequency(timeout_);
- return e;
-}
-
-void host::check_mail()
-{
-}
-
-int ehost::command( const char* cmd, ... )
-{
- int ac = 0;
- char *av[100], *s;
- va_list ap;
-
- va_start(ap, cmd);
- av[ac++] = strdup(cmd);
- while ( (s = va_arg(ap, char*)) )
- av[ac++] = strdup(s);
- va_end(ap);
-
- return command(ac, av);
-}
-
-int ehost::command( const std::string& str )
-{
- const char *cmd = str.c_str();
- if (!cmd) return -1;
-
- if (str.substr(0, 3) == "sh ") {
- int pid = 0;
- if ((pid = fork()) == 0) /* the child */{
- execl("/bin/sh", "sh", "-c", str.substr(3).c_str(), NULL);
- _exit(127);
- return 0;
- }
- if (pid == -1)
- return 1;
- else
- return 0;
- }
- else if (str == "write menu") {
- menus::write();
- return 0;
- }
-
- int e = 0, ac = 0;
- char* av[100];
- char* line = strdup(cmd);
-
- char *c = (char*) "\"";
- char* s = strtok(line, c);
- if (s == 0)
- e = command(1, &line);
- else {
- c = (char*) "'";
- s = strtok(line, c);
- if (s == 0)
- e = command(1, &line);
- else {
- c = (char*) " ";
- s = strtok(line, c);
- }
- }
- do {
- av[ac++] = s;
- s = strtok(NULL, c);
- }
- while ( s != NULL );
- e = command(ac, av);
-
- if (line) free(line);
- return e;
-}
-
-int host::maxLines = 25000;
-
-class init_hosts : public init {
- void run( int argc, char **argv )
- {
- scripting::init();
- host::init();
- }
-};
-
-void host::chat()
-{
-}
-
-void host::check_all_mail()
-{
- host *h = extent < host > ::first();
- while ( h ) {
- h->check_mail();
- h = h->extent < host > ::next();
- }
-}
-
-#include <fstream>
-
-void mem_use( double& vmu, double& res )
-{
- using std::ios_base;
- using std::ifstream;
- using std::string;
- unsigned long vsize;
- long rss;
- vmu = 0.0;
- res = 0.0;
- std::ifstream stat("/proc/self/stat", std::ios_base::in);
- std::string pid, comm, state, ppid, pgrp, session, tty_nr, tpgid, flags, minflt, cminflt;
- std::string majflt, cmajflt, utime, stime, cstime, priority, nice, O, itrealvalue, starttime;
- stat >> pid >> comm >> state >> ppid >> pgrp >> session >> tty_nr >> tpgid >> flags >> minflt
- >> cminflt >> majflt >> cmajflt >> utime >> stime >> cstime >> priority >> nice >> O
- >> itrealvalue >> starttime >> vsize >> rss;
- stat.close();
- long page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024;
- vmu = vsize / 1024.0;
- res = rss * page_size_kb;
-}
-
-bool ehost::create_tree( int hh, int min, int sec )
-{
- int then_sec = 0;
- XECFDEBUG {
- time_t now;
- time(&now);
- struct tm* then = localtime(&now);
- then_sec = then->tm_sec;
- gui::message("%s: build %02d:%02d:%02d", name(), then->tm_hour, then->tm_min, then->tm_sec);
- if (sec != then->tm_sec) {
- printf("# time get: %02d:%02d:%02d %s\n", hh, min, sec, name());
- printf("# time got: %02d:%02d:%02d %s\n", then->tm_hour, then->tm_min, then->tm_sec,
- name());
- }
- }
-
- node *top = make_xnode<Defs>(client_.defs().get(), 0x0, *this);
-
- XECFDEBUG {
- time_t nnow;
- time(&nnow);
- struct tm* next = localtime(&nnow);
- if (then_sec != next->tm_sec) printf("# time blt: %02d:%02d:%02d %s\n", next->tm_hour,
- next->tm_min, next->tm_sec, name());
- gui::message("%s: built %02d:%02d:%02d", name(), next->tm_hour, next->tm_min, next->tm_sec);
- }
-
- if (!top) {
- // XECFDEBUG { std::cout << "# no top\n"; }
- return false;
- }
- if (top_) {
- top->scan(top_);
- destroy_top(top_);
- }
- top_ = top;
- top_->active(poll_);
- notify_observers();
- top_->up_to_date();
-
- redraw();
- XECFDEBUG {
- double vmu, res;
- mem_use(vmu, res);
- if (top) {
- int num = 0; node *n = top->kids();
- while (n) { num += 1; n = n->next(); }
- // std::cout << "# num " << num << "\n";
- }
- std::cout << "# usage: " << vmu << " " << res << "\n";
- }
- return true;
-}
-
-void ehost::reset( bool full, bool sync )
-{
- if (!connected_ || !connect_) return;
- time_t now;
- time(&now);
- struct tm* curr = localtime(&now);
- gui::message("%s: full tree %02d:%02d:%02d", name(), curr->tm_hour, curr->tm_min, curr->tm_sec);
- SelectNode select(this->name());
- try {
- if (!tree_) tree_ = tree::new_tree(this);
-
- if (full) {
- XECFDEBUG std::cerr << "# reset full\n";
- const std::vector<std::string>& s = suites_;
- destroy_top(top_);
- top_ = 0x0;
- notify_observers();
-
- if (!s.empty()) {
- // /* registering with empty set would lead
- // to retrieve all server content,
- // opposive of expected result */
- // } else
- // get all suite previously registered in GUI, and register
- // them with the server The associated handle is retained in
- // client_
- try { client_.ch1_drop(); }
- catch ( std::exception &e ) {
- std::cout << "# no drop possible: " << e.what() << "\n";
- }
-
- client_.reset(); // reset client handle + defs
- // This will add a new handle to client_
- client_.ch_register(new_suites_, s);
- }
- }
- }
- catch ( std::exception &e ) {
- XECFDEBUG std::cerr << "# reset exception " << e.what() << "\n";
- if (client_.defs().get()) {
- gui::error("host::reset-reg-error: %s", e.what());
- }
- }
-
- int hour = 0, min = 0, sec = 0;
- XECFDEBUG {
- time_t now;
- time(&now);
- struct tm* curr = localtime(&now);
- hour = curr->tm_hour, min = curr->tm_min, sec = curr->tm_sec;
- gui::message("%s: start %02d:%02d:%02d", name(), hour, min, sec);
- }
-
- try {
- if (sync) client_.sync_local(); // this returns full defs
- searchable::active(False);
- create_tree(hour, min, sec);
- XECFDEBUG std::cerr << "# reset create tree\n";
- }
- catch ( std::exception &e ) {
- // XECFDEBUG
- std::cerr << "# sync exception " << e.what() << "\n";
- gui::error("host::reset-sync-error: %s", e.what());
- const std::vector<std::string>& s = suites_;
- /* load one set
- then another
- checkpoint
- kill the server
- then restart the server
- + view update command */
- try {
- client_.reset();
- client_.ch_register(new_suites_, s);
- }
- catch ( std::exception &e ) {
- gui::error("host::reset-register-error: %s", e.what());
- }
- }
- searchable::active(True);
-}
-
-void host::aborted( node& n )
-{
- if (n.type() == NODE_ALIAS) {
- if (aliases_) aborted::show(n);
- }
- else if (aborted_) aborted::show(n);
-}
-
-void host::restarted( node& n )
-{
- if (n.type() == NODE_ALIAS) {
- if (aliases_) restart::show(n);
- }
- else if (restarted_) restart::show(n);
-}
-
-void host::late( node& n )
-{
- if (late_family_ && n.type() == NODE_FAMILY)
- late::show(n);
- else if (late_) late::show(n);
-}
-
-void host::zombie( node& n )
-{
- if (zombie_) zombie::show(n);
-}
-
-void host::to_check( node& n )
-{
- if (to_check_) to_check::show(n);
-}
-
-void host::changed( resource& r )
-{
- if (&r == &timeout_) frequency(timeout_);
-}
-
-void ehost::changed( resource& r )
-{
- host::changed(r);
- if (&r == &poll_) {
- if (top_) top_->active(poll_);
- client_.set_host_port(machine(), boost::lexical_cast<std::string>(number()));
- connect_mngt(true);
- if (connected_ && poll_) status();
- }
-
- if ((&r == &new_suites_) && connected_) {
- // ch1_auto_add is used to control whether suites are
- // automatically added to handle. It should only be called if
- // suites had previously been registered
- try {
- if (client_.client_handle()) {
- client_.ch1_auto_add(new_suites_);
- }
- else {
- XECFDEBUG std::cerr << "# No suites previously registered ?";
- }
- }
- catch ( std::exception &e ) {
- gui::message("host::server-error: %s", e.what());
- }
- }
-}
-
-void host::redraw( bool create )
-{
- if (create) {
- SelectNode select(this->name());
- XECFDEBUG {
- std::cout << ChangeMgrSingleton::instance()->no_of_node_observers() << std::endl
- << ChangeMgrSingleton::instance()->no_of_def_observers() << std::endl;
- }
-
- if (top_) top_->unlink(true);
- XECFDEBUG {
- std::cout << ChangeMgrSingleton::instance()->no_of_node_observers() << std::endl
- << ChangeMgrSingleton::instance()->no_of_def_observers() << std::endl;
- // assert(ChangeMgrSingleton::instance()->no_of_node_observers() == 0);
- // assert(ChangeMgrSingleton::instance()->no_of_def_observers() == 0);
- }
- create_tree(0, 0, 0);
- }
- else if (tree_) tree_->update_tree(true);
- if (top_) top_->reset();
-}
-
-str host::logfile() const
-{
- char buf[1024];
- buf[0] = 0;
- return str(buf);
-}
-
-str ehost::logfile() const
-{
- const char* home = top_ ? top_->variable("ECF_HOME").c_str() : 0;
- const char* log = top_ ? top_->variable("ECF_LOG").c_str() : 0;
- char buf[1024];
- buf[0] = 0;
-
- if (log) {
- if (log[0] != '/' && home)
- sprintf(buf, "%s/%s", home, log);
- else
- strcpy(buf, log);
- }
- return str(buf);
-}
-
-host& host::dummy()
-{
- static host* h = new host("user.default", "user.default", 0);
- return *h;
-}
-
-void host::plug( node* from )
-{
- do_plug(selection::current_node(), from);
-}
-
-void host::comp( node* from, const char* a, const char* b )
-{
- do_comp(selection::current_node(), from, a, b);
-}
-
-int host::do_comp( node* into, node* from, const std::string& a, const std::string& b )
-{
- if (!into || !from) return 0;
- std::stringstream out;
- out << "${COMPARE:=/home/ma/map/bin/compare.sh} " << from->full_name() << ":";
- if (from->variable("ECF_NODE") != "(none)") {
- out << from->variable("ECF_NODE") << ":" << from->variable("ECF_PORT") << ":"
- << from->variable("ECF_LOGHOST", true) << ":" << from->variable("ECF_LOGPORT", true)
- << ":" << from->variable("ECF_JOBOUT", true) << " \t";
- }
- else {
- out << from->variable("SMSNODE") << ":" << from->variable("SMS_PROG") << ":"
- << from->variable("SMSLOGHOST", true) << ":" << from->variable("SMSLOGPORT", true) << ":"
- << from->variable("SMSJOBOUT", true) << " \t";
- }
-
- out << into->full_name() << ":";
- if (into->variable("ECF_NODE") != "(none)") {
- out << into->variable("ECF_NODE") << ":" << into->variable("ECF_PORT") << ":"
- << into->variable("ECF_LOGHOST", true) << ":" << into->variable("ECF_LOGPORT", true)
- << ":" << into->variable("ECF_JOBOUT", true) << " \t";
- }
- else {
- out << into->variable("SMSNODE") << ":" << into->variable("SMS_PROG") << ":"
- << into->variable("SMSLOGHOST", true) << ":" << into->variable("SMSLOGPORT", true) << ":"
- << into->variable("SMSJOBOUT", true) << " \t";
- }
- out << a << " \t" << b << "\n";
- const std::string cmd = out.str();
- std::cout << cmd;
-
- int pid = fork();
- if (pid == 0) { /* the child */
- execl("/bin/sh", "sh", "-c", cmd.c_str(), NULL);
- _exit(127);
- return 0;
- }
- if (pid == -1) return 1;
- return 0;
-}
-
-int host::do_plug( node* into, node* from )
-{
- if (!into || !from) return 1;
-
- str sf(from->full_name().c_str());
- str si(into->full_name().c_str());
- str sn = si + str("/") + str(from->name());
-
- host *destination = &into->serv();
- host *source = &from->serv();
-
- if (destination == source) {
- gui::error("# Node cannot be pluged to the same server");
- return 1;
- }
-
- if (!confirm::ask(false, "You are about pluging %s %s of %s into %s %s of %s.\n"
- "Note that you will have to resume %s in the ECF %s.\n"
- "Proceed?",
- from->type_name(), sf.c_str(), source->name(), into->type_name(), si.c_str(),
- destination->name(), sn.c_str(), destination->name())) return 1;
-
- str sp(from->parent()->full_name().c_str());
- if (sp != si) {
- if (!confirm::ask(false, "You are about to move the %s '%s' from a sub-tree named '%s' to\n"
- "a sub-tree named '%s'. This may cause some problems,\n"
- "specially if there are any active tasks. Do you want to proceed?",
- from->type_name(), from->name().c_str(), sp.c_str(), si.c_str())) return 1;
- }
-
- if (destination->status()) {
- gui::error("# Cannot get status for %s. Pluging aborted.", destination->name());
- return 1;
- }
- if (source->status()) {
- gui::error("Cannot get status for %s. Pluging aborted.", source->name());
- return 1;
- }
-
- node *nfrom = source->top()->find(sf.c_str());
- std::string cmd;
-
- if (!(nfrom->status() == STATUS_SUSPENDED)) {
- if (source->command(clientName, "--suspend", nfrom->full_name().c_str(), 0x0)) {
- gui::error("Cannot suspend %s. Pluging aborted", sf.c_str());
- return 1;
- }
- }
-
- if (nfrom == 0) {
- cmd = "One of the node is gone after status.\n";
- cmd += "It must have been canceled. Pluging aborted.";
- gui::error(cmd.c_str());
- return 1;
- }
-
- gui::message("Pluging from %s to %s", source->name(), destination->name());
- cmd = "//";
- cmd += destination->machine();
- cmd += ":";
- cmd += (boost::lexical_cast<std::string>(destination->number())).c_str();
- cmd += si.c_str();
- if (source->command(clientName, "--plug", sf.c_str(), cmd.c_str(), 0x0)) {
- gui::error("Pluging aborted.");
- return 1;
- }
-
- source->status();
- destination->status();
- return 0;
-}
-
-tmp_file ehost::sfile( node& n, std::string name )
-{
- loghost_ = n.variable("ECF_LOGHOST", true);
- logport_ = n.variable("ECF_LOGPORT");
- if (loghost_ == ecf_node::none()) {
- loghost_ = n.variable("LOGHOST", true);
- logport_ = n.variable("LOGPORT");
- }
- return host::sfile(n, name);
-}
-
-tmp_file host::sfile( node& n, std::string name )
-{
- if (name == ecf_node::none()) return tmp_file((const char*) NULL);
- const char *cname = name.c_str();
-
- std::string::size_type pos = loghost_.find(n.variable("ECF_MICRO"));
- if (std::string::npos == pos && loghost_ != ecf_node::none()) {
- logsvr log_server(loghost_, logport_);
- if (log_server.ok()) {
- tmp_file tmp = log_server.getfile(name);
- if (access(tmp.c_str(), R_OK) == 0) return tmp;
- }
- }
-
- if ((access(cname, R_OK) == 0)) {
- return tmp_file(cname, false);
- }
-
- try {
- n.serv().command(clientName, "--file", "-n", cname, host::maxLines, 0x0);
- } catch ( std::exception &e ) {
- gui::error("cannot get file from server: %s", e.what());
- }
-
- return tmp_file(cname, false);
- // return tmp_file((const char*) NULL); // FIXME
-}
-
-const str& host::timefile()
-{
- if (timefile_.c_str()[0] == 0)
- timefile_ = logfile();
- else if (!strncmp("(none)/(none)", timefile_.c_str(), 13)) timefile_ = logfile();
- return timefile_;
-}
-
-void host::hosts( host_lister& l )
-{
- host *h = extent < host > ::first();
- while ( h ) {
- l.next(*h);
- h = h->extent < host > ::next();
- }
-}
-
-void host::change( const std::string& name, const std::string& machine, int number )
-{
- bool logged = false;
-
- if (connected_) {
- logout();
- logged = true;
- }
-
- gui::rename_host(this->name(), name);
-
- ecf_nick_update(name, machine, number);
-
- name_ = name;
- host_ = machine;
- number_ = number;
- if (logged) login();
-}
-
-int host::origin() const
-{
- return ecf_nick_origin(name());
-}
-
-static init_hosts init_hosts_instance;
-std::map<int, host_maker*> host_maker::map_;
-int host_maker::port_max = 65535;
-static host_builder<ehost> ehost_builder_instance(0);
-
-host* host::new_host( const std::string& p, const std::string& m, int n )
-{
- ecf_nick_update(p, m, n);
- return host_maker::make_host(p, m, n);
-}
-
-IMP(host)
-
-void host::login()
-{
-}
-
-bool check_version( const char* v1, const char* v2 )
-{
- int num = 0;
- while ( v1 && v2 && num < 2 ) {
- if (*v1 == '.') num++;
- if (*v1 != *v2) return false;
- v1++;
- v2++;
- }
- return true;
-}
-
-void get_server_version( ClientInvoker& client, std::string& server_version )
-{
- // ECF_ALLOW_NEW_CLIENT_OLD_SERVER allows each client ('client.allow_new_client_old_server')
- // to have its own archive version, hence FIRST: go with what ever was set
- // See notes: ACore/src/boost_archive.hpp
-
- for(int av = ecf::boost_archive::version()-1; av >= ecf::boost_archive::version_1_47(); --av) {
-
- // First time in loop, go with what ever was set, including if client.allow_new_client_old_server() !=0
- try {
- client.server_version();
- server_version = client.server_reply().get_string();
- if (!server_version.empty()) return;
- }
- catch ( ... ) {}
-
- client.allow_new_client_old_server(av);
- }
-}
-
-void ehost::login()
-{
- gui::message("Login to %s", name());
- host::logout();
- host::login();
- reset(true, true);
-
- client_.set_throw_on_error(true);
- try {
- client_.set_host_port(machine(), boost::lexical_cast<std::string>(number()));
- if (!connect_mngt(true)) {
- gui::message("%s: no reply", name());
- logout();
- connected_ = false; // tree_->connected(false);
- connect_ = false;
- return;
- }
-
- // if we can not get the server version, attempt backward compatibility
- std::string server_version;
- get_server_version(client_, server_version);
- if (server_version.empty()) {
- if (!confirm::ask( false, "%s (%s@%d): Could not connect\nTry again ?", name(), machine(), number())) {
- connect_ = false;
- connected_ = false;
- return;
- }
- }
- else {
- if (!check_version(server_version.c_str(), ecf::Version::raw().c_str())) {
- if (!confirm::ask(
- false,
- "%s (%s@%d): version mismatch, server is %s, client is %s\ntry to connect anyway?",
- name(), machine(), number(), server_version.c_str(),
- ecf::Version::raw().c_str())) {
- connect_ = false;
- connected_ = false;
- return;
- }
- }
- }
- connect_ = true;
- connected_ = true;
-
- if (!tree_) tree_ = tree::new_tree(this);
- reset(true); // done later with update (test empty server)
-
- enable();
- if (tree_ != 0x0) {
- tree_->xd_show();
- tree_->connected(True);
- redraw();
- }
- gui::login(name());
- searchable::active(True);
- }
- catch ( std::exception& e ) {
- searchable::active(False);
- gui::error("Login to %s failed (%s)", name(), e.what());
- if (!tree_) return;
- if (connected_) {
- tree_->update_tree(false);
- }
- else {
- tree_->connected(False);
- if (!top_)
- top_ = make_xnode<Defs>(0x0, 0, *this);
- }
- }
-
- update();
-}
-
-tmp_file ehost::file( node& n, std::string name )
-{
- std::string error;
- bool read = direct_read_;
- if (name == "ECF_SCRIPT") {
- error = "no script!\n"
- "check ECF_FILES or ECF_HOME directories, for read access\n"
- "check for file presence and read access below files directory\n"
- "or this may be a 'dummy' task.\n";
- } else if (name == "ECF_JOB") {
- std::string filename = n.variable(name);
- if (read && (access(filename.c_str(), R_OK) == 0))
- return tmp_file(filename.c_str(), false);
-
- if (std::string::npos != filename.find(".job0")) {
- error = "job0: no job to be generated yet!";
- return tmp_file(error);
- } else
- error = "no script!\n"
- "check ECF_HOME,directory for read/write access\n"
- "check for file presence and read access below\n"
- "The file may have been deleted\n"
- "or this may be a 'dummy' task.\n";
- } else if (boost::algorithm::ends_with(name, ".0")) {
- error = "no output to be expected when TRYNO is 0!\n";
- return tmp_file(error);
- } else if (name != ecf_node::none()) { // Try logserver
- loghost_ = n.variable("ECF_LOGHOST", true);
- logport_ = n.variable("ECF_LOGPORT");
- if (loghost_ == ecf_node::none()) {
- loghost_ = n.variable("LOGHOST", true);
- logport_ = n.variable("LOGPORT");
- }
- std::string::size_type pos = loghost_.find(n.variable("ECF_MICRO"));
- if (std::string::npos == pos && loghost_ != ecf_node::none()) {
- logsvr the_log_server(loghost_, logport_);
- if (the_log_server.ok()) {
- tmp_file tmp = the_log_server.getfile(name); // allow more than latest output
- if (access(tmp.c_str(), R_OK) == 0) return tmp;
- }
- }
- }
- if (read && (access(name.c_str(), R_OK) == 0)) {
- return tmp_file(name.c_str(), false);
- } else {
- gui::message("%s: fetching %s", this->name(), name.c_str());
- try {
- if (name == "ECF_SCRIPT")
- client_.file(n.full_name(), "script");
- else if (name == "ECF_JOB") {
- client_.file(n.full_name(), "job",
- boost::lexical_cast<std::string>(jobfile_length_));
- }
- else if (name == "ECF_JOBOUT")
- client_.file(n.full_name(), "jobout");
- else {
- client_.file(n.full_name(), "jobout");
- }
-
- // Do *not* assign 'client_.server_reply().get_string()' to a separate string, since
- // in the case of job output the string could be several megabytes.
- return tmp_file( client_.server_reply().get_string()
- + "\n# file is served by ecflow-server\n" );
- } catch ( std::exception &e ) {
- std::cerr << "host::file-error:" << e.what() << "\n";
- gui::message("host::file-error: %s", e.what());
- }
- }
-
- return tmp_file(error);
-}
-
-tmp_file ehost::edit( node& n, std::list<Variable>& l, Boolean preproc )
-{
- gui::message("%s: fetching source", name());
- try {
- if (preproc)
- client_.edit_script_preprocess(n.full_name());
- else
- client_.edit_script_edit(n.full_name());
- return tmp_file(client_.server_reply().get_string());
- } catch ( std::exception &e ) {
- gui::error("host::edit-error: %s", e.what());
- } catch ( ... ) {
- gui::error("host::edit-error");
- }
- std::string error = "no script!\n"
-"\n"
-"check server->History:\n"
-"\tsome suite variable may be 'unterminated' (micro character missing) in script or include files\n"
-"\tcheck duplicate occurences of micro character when it is expected in the job (%% becomes %)\n"
-"\tuse %nopp ... %end or %includenopp <file.h> to disable job preprocessing where needed\n"
-"\tan include file may not be found\n"
-"check ECF_FILE directory is accessible, by opening the Script panel\n"
-"check ECF_INCLUDE directory is accessible from the server\n"
-"\tit must contain the included files (or links)\n"
-"client must be capable to create temporary file:\n"
-"\tcheck /tmp directory with write access, and space available,\n"
-"or preprocessed file may be truncated beyond some size.\n";
- return tmp_file(error);
-}
-
-tmp_file host::manual( node& n )
-{
- std::string man = "no manual...";
- return tmp_file(man);
-}
-
-tmp_file ehost::manual( node& n )
-{
- gui::message("%s: fetching manual", name());
- try {
- client_.file(n.full_name(), "manual");
- if (client_.server_reply().get_string().empty()) {
- std::string man = "no manual...";
- return tmp_file(man);
- }
- return tmp_file(client_.server_reply().get_string());
- }
- catch ( std::exception &e ) {
- gui::message("host::manual-error: %s", e.what());
- }
-
- std::string man = "no manual...";
- return tmp_file(man);
-}
-
-void host::send( node& n, Boolean alias, Boolean run, NameValueVec& v,
- const char* file )
-{
-}
-
-void ehost::send( node& n, Boolean alias, Boolean run, NameValueVec& v,
- const char* file )
-{
- std::vector<std::string> content;
- char line[4096];
- FILE *f = fopen(file, "r");
- if (!f) {
- gui::syserr(file);
- return;
- }
- while ( fgets(line, sizeof(line), f) ) {
- line[strlen(line) - 1] = 0;
- content.push_back(line);
- }
- gui::message("%s: sending script_panel", name());
-
- try {
- client_.edit_script_submit(n.full_name(), v, content, alias, run);
- }
- catch ( std::exception &e ) {
- gui::error("host::send-error: %s", e.what());
- }
- status();
- fclose(f);
-}
-
-const std::vector<std::string>& host::suites() const
-{
- return suites_;
-}
-
-void ehost::suites( int which, std::vector<std::string>& l )
-/* Menu Suites..., or Suites tab */
-{
- try {
- switch ( which ) {
- case SUITES_LIST:
- client_.suites();
- l = client_.server_reply().get_string_vec();
- break;
- case SUITES_MINE:
- l = suites_;
- break;
- case SUITES_REG:
- gui::message("%s: registering to suites", name());
- suites_ = l;
- try {
- if (l.empty()) {
- try { client_.ch1_drop(); }
- catch ( std::exception &e ) {
- std::cout << "# no drop possible: " << e.what() << "\n";
- }
-
- // reset handle to zero , and clear the defs
- client_.reset();
- }
- client_.ch_register(new_suites_, suites_);
- status();
- redraw();
- }
- catch ( std::exception &e ) {
- gui::error("host::suites-reg-error: %s", e.what());
- }
- break;
- default:
- gui::message("%s: suites, what?");
- break;
- }
- }
- catch ( std::exception &e ) {
- if (client_.defs().get()) { /* ignore empty server */
- gui::error("host::suites-error: %s", e.what());
- }
- }
-}
-
-void host::suites( node* n, bool one )
-/* register only one suite with menu hide-other-suites (right-mouse-button,
- on the server area, close to server node, not on the node itself */
-{
- while ( n ) {
- if (n->type() == NODE_SUITE) {
- static std::vector<std::string> l;
- if (!one) l = suites_;
- l.push_back(n->name());
- suites(SUITES_REG, l);
- break;
- }
- n = n->parent();
- }
-}
-
-int host::update()
-{
- return TRUE;
-}
-extern XtAppContext app_context;
-
-void ehost::update_reg_suites( bool get_ch_suites )
-{
- if (new_suites_) { // SUP-398 // temporary add higher load on the server
- if (get_ch_suites) {
- try {
- client_.ch_suites();
- }
- catch ( std::exception& e ) {
- gui::message("host::update-reg-suite-error: %s", e.what());
- }
- const std::vector<std::pair<unsigned int, std::vector<std::string> > >& vct = client_.server_reply().get_client_handle_suites();
- for(size_t i = 0; i < vct.size(); ++i) {
- if (vct[i].first == (unsigned int) client_.client_handle()) {
- suites_ = vct[i].second;
- break;
- }
- }
- }
- else {
- const std::vector<suite_ptr>& suites_vec = client_.defs()->suiteVec();
- std::vector<std::string> suites;
- suites.reserve(suites_vec.size());
- for(size_t i = 0; i < suites_vec.size(); ++i) {
- suites.push_back(suites_vec[i]->name());
- }
- suites_ = suites;
- }
- }
-}
-
-int ehost::update()
-{
- int err = -1;
- if (!connected_) return err;
-
- SelectNode select(this->name());
- if (updating_) return 0; // SUP-423
- Updating update(this); // SUP-423
- gui::watch(True);
- last_ = ::time(0);
-
- try {
- if (app_context) XtAppAddTimeOut(app_context, 20 * 1000, NULL, NULL);
-
- time_t now;
- time(&now);
- struct tm* curr = localtime(&now);
- gui::message("%s: checking status %02d:%02d:%02d", name(), curr->tm_hour, curr->tm_min,
- curr->tm_sec);
- client_.news_local(); // call the server
- if (tree_) tree_->connected(True);
-
- XECFDEBUG {
- struct tm* next;
- time_t now;
- time(&now);
- next = localtime(&now);
- if (curr->tm_sec != next->tm_sec) {
- printf("# time chk: %02d:%02d:%02d %s\n", curr->tm_hour, curr->tm_min, curr->tm_sec,
- name());
- printf("# time nws: %02d:%02d:%02d %s\n", next->tm_hour, next->tm_min, next->tm_sec,
- name());
- }
- }
- switch ( client_.server_reply().get_news() ) {
- case ServerReply::NO_NEWS:
- gui::message("::nonews\n");
- if (top_) top_->up_to_date();
- return 0;
- break;
- case ServerReply::DO_FULL_SYNC: // 4 calls to the server:
- /* ch_suites + drop + reg_suites + sync_local */
- gui::message("::fullsync\n");
- if (top_) top_->up_to_date();
- update_reg_suites(true);
- reset(true);
- return 0;
- break;
- case ServerReply::NO_DEFS:
- reset(true);
- return 0;
- break;
- case ServerReply::NEWS:
- // there were some kind of changes in the server
- // request the changes from the server & sync with
- // defs on client_
-
- client_.sync_local();
- // full_sync==true: no notification on the GUI side
-
- // full_sync==false: incremental change, notification
- // received through ::update (ecf_node)
-
- gui::message("%s: receiving status", name());
-
- if (client_.server_reply().full_sync()) {
- update_reg_suites(false); // new suite may have been added
- reset(false, false); // SUP-398
- }
- else {
- gui::message("%s: updating status", name());
- XECFDEBUG std::cout << "# " << name() << ": small update\n";
-
- if (Updating::full_redraw()) {
- redraw(true);
- }
- else if (tree_) tree_->update_tree(false);
- // fp:60043 Issue with Ecflow updating on console VM
- // redraw(false); // too much blinking with this
- }
- err = 0;
- break;
- default:
- break;
- }
- }
- catch ( std::exception& e ) {
- if (tree_ != 0x0) tree_->connected(False);
- err = -1;
- gui::message("host::news-error: %s", e.what());
- XECFDEBUG std::cerr << "# host::news-error: " << e.what() << "\n";
- }
- return err;
-}
-
-int ehost::command( int argc, char **argv )
-{
- int result = -1;
-
- if (argc < 1) return FALSE;
-
- if (!strcmp(argv[1], "--enable_logging")) {
- client_.enable_logging("ecflow_client.log");
- return true;
- }
- if (!strcmp(argv[1], "--disable_logging")) {
- client_.disable_logging();
- return true;
- }
- else if (!strcmp(argv[1], "--url")) {
- if (argc == 3) {
- UrlCmd urlCmd(client_.defs(), argv[2]);
- try {
- urlCmd.execute();
- }
- catch ( ... ) {
- gui::error("cannot-open-url or substitution-error\n%s", argv[2]);
- }
- return true;
- }
- }
-
- gui::message("command issued ...");
- if (!strcmp(argv[0], clientName)) {
- try {
- int i = 0;
- std::cout << "# CMD: ";
- while ( i < argc )
- std::cout << argv[i++] << " ";
- result = client_.invoke(argc, argv);
- std::cout << "--port " << number() << " --host " << machine() << " # ack\n";
- }
- catch ( std::exception &e ) {
- gui::error("host::command-error:\n%s\n", e.what());
- }
- }
- else {
- int pid = fork();
- if (pid == 0) { /* the child */
- execl("/bin/sh", "sh", "-c", argv, NULL);
- _exit(127);
- return 0;
- }
- if (pid == -1) return 1;
- }
- if (after_command_) status();
-
- return result;
-}
-
-std::list<std::string>& host::history( std::string& last )
-{
- return hist_;
-}
-
-std::list<std::string>& ehost::history( std::string& last )
-{
- gui::message("%s: fetching history", name());
- try {
- client_.getLog(history_len_);
- boost::split(hist_, client_.server_reply().get_string(), boost::is_any_of("\n"));
- }
- catch ( std::exception& e ) {
- gui::message("history failed: ", e.what());
- }
- return hist_;
-}
-
-bool host::connect_mngt( bool connect )
-{
- return true;
-}
-
-bool ehost::connect_mngt( bool connect )
-{
- if (!connect) return true;
- if (!connect_) return true;
- bool rc = true;
- try {
- gui::message("%s: ping", name());
- client_.pingServer();
-
- if (connect) {
- rc = true;
- connected_ = true;
- }
- else {
- connected_ = false;
- rc = false;
- }
- }
- catch ( std::exception &e ) {
- connected_ = false;
- rc = false;
- gui::message("# Exception caught in ehost::connect_mngt");
- gui::message(e.what());
- }
-
- if (tree_) tree_->connected(rc);
- if (!rc) gui::logout(name());
- return rc;
-}
-
-const std::string host::reply() const
-{
- return "";
-}
-
-const std::string ehost::reply() const
-{
- return client_.server_reply().get_string();
-}
-
-void host::init()
-{
- ecf_nick_load();
-}
-
-host* host_maker::make_host( std::string name, std::string machine, int port )
-{
- std::map<int, host_maker*>::const_iterator it = map_.begin();
- host * out = 0x0;
- if (port < host_maker::port_max) {
- it = map_.find(0);
- if (it != map_.end())
- out = it->second->make(name, machine, port);
- else XECFDEBUG std::cerr << "# cannot create ehost\n";
- }
- else {
- it = map_.find(1);
- if (it != map_.end())
- out = it->second->make(name, machine, port);
- else XECFDEBUG std::cerr << "# cannot create shost " << name << "\t" << machine << "\t"
- << port << "\n";
- }
-
- return out;
-}
-
-void host::login( const std::string& name, int num )
-{
- host *h = NULL;
- if (num) h = host::find(name, num);
- if (!h) h = host::find(name, ECF_PROG);
- if (!h) h = host::find(name, SMS_PROG);
- if (!h) h = host_maker::make_host(name, name, num);
- if (h) h->login();
-}
-
-void ehost::stats( std::ostream& buf )
-{
- gui::message("%s: fetching stats", name());
- try {
- client_.stats();
- client_.server_reply().stats().show(buf);
- }
- catch ( std::exception& e ) {
- }
-}
diff --git a/ecflow_4_0_7/view/src/host.h b/ecflow_4_0_7/view/src/host.h
deleted file mode 100644
index f7b9410..0000000
--- a/ecflow_4_0_7/view/src/host.h
+++ /dev/null
@@ -1,353 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #33 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#ifndef host_H
-#define host_H
-
-#include <time.h>
-#include <stdio.h>
-
-#include "ecf_node.h"
-#ifndef extent_H
-#include "extent.h"
-#endif
-
-#ifndef timeout_H
-#include "timeout.h"
-#endif
-
-#ifndef tmp_file_H
-#include "tmp_file.h"
-#endif
-
-#ifndef searchable_H
-#include "searchable.h"
-#endif
-
-#ifndef observable_H
-#include "observable.h"
-#endif
-#include "text_lister.h"
-
-class node;
-class tree;
-#ifndef lister_H
-#include "lister.h"
-#endif
-
-#ifndef option_H
-#include "option.h"
-#endif
-
-#ifndef configurable_H
-#include "configurable.h"
-#endif
-
-#ifndef str_H
-#include "str.h"
-#endif
-
-#ifdef NO_BOOL
-#include "bool.h"
-#endif
-
-#ifndef SINGLETON_H
-#include "singleton.h"
-#endif
-
-class Client;
-class configurator;
-class host;
-class url;
-#include <map>
-
-class host_maker {
- virtual host* make(const std::string& name, const std::string& machine, int port) = 0;
-protected:
- static std::map<int, host_maker*> map_;
- static int port_max;
-public:
- static host* make_host(std::string name, std::string machine, int port);
- virtual ~host_maker() {}
-};
-
-template<typename T>
-class host_builder : public host_maker {
- virtual host* make(const std::string& name, const std::string& machine, int port)
- { return new T(name, machine, port); }
-public:
- host_builder(int port_max) { map_[port_max] = this; }
-};
-
-class host_lister {
-public:
- virtual void next(host&) = 0;
- virtual ~host_lister() {}
-};
-
-
-class host : public extent<host>
-, public timeout
- , public searchable
- , public configurable
- , public observable
-{
- public:
- static void status(Boolean);
- static void login(const std::string&,int);
- static void login(const std::string&);
- static void logout(const std::string&);
- static void broadcast(bool = false);
- static void check_all_mail();
-
- static node* find(const std::string&,const std::string&);
- static host* find(const std::string&);
- static void redraw_all();
- static void plug(node*);
- static void comp(node*, const char* a, const char* b );
- static host* new_host(const std::string&,const std::string&,int);
- static void remove_host(const std::string&);
- static host& dummy();
- static void chat();
-
- protected:
- static host* find(const std::string&,int);
- void update_reg_suites(bool ) {};
-
- static void hosts(host_lister&);
- static int maxLines;
- host( const std::string& name, const std::string& host, int number );
-
- public:
- virtual const std::string reply() const;
-
- virtual ~host();
-
- void call_after_commands(bool b) { after_command_ = b; }
-
- static void init();
-
- virtual void login();
- virtual void logout();
- int status();
- void check_mail();
-
- virtual int update();
- virtual int command(const std::string& str) { return TRUE; };
- virtual int command(const char*,...) { return TRUE; };
- virtual int command(int,char**) { return TRUE; };
- virtual std::list<std::string>& history(std::string&);
- node* top() { return top_; }
- tree* where() { return tree_; }
-
- virtual tmp_file file(node& n,std::string name);
- virtual tmp_file sfile( node& n, std::string name );
- virtual tmp_file manual(node&);
- virtual tmp_file script(node&);
- virtual tmp_file output(node&);
- virtual tmp_file job(node&);
- virtual tmp_file jobstatus(node&, const std::string &);
- virtual tmp_file jobcheck(node&, const std::string &);
-
- virtual tmp_file edit(node& n,std::list<Variable>& l,Boolean preproc);
- virtual void send(node& n,Boolean alias,Boolean run,NameValueVec& v,const char* file);
- virtual void dir(node&,const char*,lister<ecf_dir>&);
-
- void send(const char*,std::vector< std::string >&);
-
- virtual bool zombies(int mode,const char* name);
- virtual bool get_zombies_list(std::vector<std::string>& list);
-
- const std::vector<std::string>& suites() const;
- virtual void suites(int, std::vector<std::string>&) {};
- void suites(node*,bool=true);
-
- void redraw(bool create=false);
- virtual bool create_tree(int hh=0, int min=0, int sec=0) { return false; }
- time_t last() { return last_; }
-
- virtual void change(const std::string&,const std::string&,int);
-
- void aborted(node&);
- void restarted(node&);
- void late(node&);
- void zombie(node&);
- void to_check(node&);
-
- void changed(resource&);
-
- virtual str logfile() const ;
- static int do_plug(node*,node*);
- static int do_comp(node*,node*,
- const std::string& kind, const std::string& meth);
-
- // From timeout
- void run();
-
- // From searchable
- inline const char* name() const { return name_.c_str(); }
- const std::string& name_ref() const { return name_; }
-
- const char* machine() const { return host_.c_str(); }
- int number() const { return number_; }
- void search(node_lister&);
-
- void timefile(const str& s) { timefile_ = s; }
- const str& timefile();
-
- virtual const std::vector<std::string>& messages(const node&n) const;
-
- protected:
- host(const host&);
- host& operator=(const host&);
-
- void destroy_top(node*) const;
-
- str host_;
- int number_;
-
- std::string name_;
-
- bool connected_;
- bool after_command_;
-
- str user_;
- str passwd_;
- virtual int origin() const;
-
- option<int> timeout_;
- option<int> maximum_;
- option<bool> drift_;
- option<bool> connect_;
- option<std::vector<std::string> > suites_;
-
- option<bool> aborted_;
-
- option<bool> restarted_;
- option<bool> late_;
- option<bool> poll_;
-
- option<bool> direct_read_;
- option<bool> new_suites_;
-
- option<bool> zombie_;
- option<bool> aliases_;
- option<bool> late_family_;
- option<bool> to_check_;
-
- bool chkmail_;
-
- node* top_;
- tree* tree_;
- int mail_;
- time_t last_;
- str timefile_;
- std::list<std::string> hist_;
- int history_len_;
- std::string loghost_;
- std::string logport_;
-
- virtual void reset(bool full=false, bool sync=true) {};
- virtual bool connect_mngt(bool connect);
-
- bool updating_; // SUP-423
- option<int> jobfile_length_;
- public:
- void updating(bool b) { updating_ = b; }
- virtual void stats(std::ostream& f) { };
-};
-
-class ehost : public host {
- public:
- ehost( const std::string& name,const std::string& h,int number );
- virtual ~ehost();
- virtual void dir(node&,const char*,lister<ecf_dir>&);
-
- bool zombies(int mode, const char *name);
- bool get_zombies_list(std::vector<std::string>& list);
-
- void login();
- void logout();
- void changed( resource& r );
- virtual std::list<std::string>& history(std::string&);
-
- virtual str logfile() const ;
- virtual int command(int argc, char **argv);
- int command(const std::string& str);
- int command(const char* cmd, ... );
-
- virtual tmp_file edit(node& n,std::list<Variable>& l,Boolean preproc);
- virtual void send(node& n,Boolean alias,Boolean run,NameValueVec& v,const char* file);
- virtual void suites(int, std::vector<std::string>&) ;
- tmp_file sfile(node&,std::string);
- tmp_file file(node& n,std::string name);
- tmp_file manual( node& n );
- tmp_file jobcheck( node& n, const std::string &cmd );
- tmp_file jobstatus( node& n, const std::string &cmd );
-
- const std::string reply() const;
- virtual int update();
-
- virtual const std::vector<std::string>& messages(const node&n) const;
-
- void stats(std::ostream& f);
- protected:
- virtual bool connect_mngt(bool connect);
- ClientInvoker client_;
- bool create_tree(int hh=0, int min=0, int sec=0);
-
- virtual void reset(bool full=false, bool sync=true);
- protected:
- void update_reg_suites(bool get_ch_suites);
-
- ehost(const ehost&);
- ehost& operator=(const ehost&);
-};
-struct host_locker {
-protected:
- host* host_;
- int e_;
-public:
- host_locker( host* h );
- ~host_locker();
- int err() { return e_; }
-};
-
-class Updating {
-public:
- Updating(host* h) : host_(h) {
- do_full_redraw_ = false;
- host_->updating(true);
- }
-
- ~Updating() {
- host_->updating(false);
- }
-
- static void set_full_redraw() {
- do_full_redraw_ = true;
- }
-
- static bool full_redraw() {
- return do_full_redraw_;
- }
-
-private:
- host* host_;
- static bool do_full_redraw_;
-};
-
-#endif
-
diff --git a/ecflow_4_0_7/view/src/host_prefs.cc b/ecflow_4_0_7/view/src/host_prefs.cc
deleted file mode 100644
index 99261da..0000000
--- a/ecflow_4_0_7/view/src/host_prefs.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "host_prefs.h"
-
-void host_prefs::create(Widget w,char*)
-{
- option_form_c::create(w);
- prefs::setup(w);
-}
-
-// static host_prefs hp;
diff --git a/ecflow_4_0_7/view/src/host_prefs.h b/ecflow_4_0_7/view/src/host_prefs.h
deleted file mode 100644
index 8824b69..0000000
--- a/ecflow_4_0_7/view/src/host_prefs.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef host_prefs_H
-#define host_prefs_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#ifndef prefs_H
-#include "prefs.h"
-#endif
-
-#ifndef uioption_H
-#include "uioption.h"
-#endif
-
-class host_prefs : public prefs, public option_form_c {
-public:
- host_prefs() {}
-
- ~host_prefs() {}
-
- virtual Widget widget() { return _xd_rootwidget; }
-
-private:
-
- host_prefs(const host_prefs&);
- host_prefs& operator=(const host_prefs&);
-
- virtual void changedCB( Widget w, XtPointer ) { pref_editor::changed(w); }
- virtual void useCB( Widget w, XtPointer ) { pref_editor::use(w); }
- virtual void create(Widget w,char*);
-};
-
-inline void destroy(host_prefs**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/html_lister.cc b/ecflow_4_0_7/view/src/html_lister.cc
deleted file mode 100644
index 2503eb5..0000000
--- a/ecflow_4_0_7/view/src/html_lister.cc
+++ /dev/null
@@ -1,72 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <stdarg.h>
-#include "html_lister.h"
-
-html_lister::html_lister(node *n):
- node_(n),
- nodes_(0),
- cancels_(0)
-{
- buf_[0] = 0;
-}
-
-html_lister::~html_lister()
-{
-}
-
-void html_lister::push(node* n)
-{
- char buf[1024];
- sprintf(buf,"<a href=\"%s\">%s</a>",
- n->net_name().c_str(), // TODO +1,
- n->node_name().c_str());
- strcat(buf_,buf);
- nodes_++;
-}
-
-void html_lister::push(const char* p,...)
-{
- char buf[1024];
- va_list arg;
- va_start(arg,p);
- vsprintf(buf,p,arg);
- va_end(arg);
- strcat(buf_,buf);
-}
-
-void html_lister::cancel()
-{
- cancels_++;
-}
-
-void html_lister::endline()
-{
- if(cancels_) {
- if(cancels_ >= nodes_)
- {
- //printf("Canceling line %s\n",buf_);
- buf_[0] = 0;
- }
- else
- {
- //printf("Not canceling line %s\n",buf_);
- }
- }
- line(buf_);
- buf_[0] = 0;
- nodes_ = cancels_ = 0;
-}
diff --git a/ecflow_4_0_7/view/src/html_lister.h b/ecflow_4_0_7/view/src/html_lister.h
deleted file mode 100644
index 8dd62db..0000000
--- a/ecflow_4_0_7/view/src/html_lister.h
+++ /dev/null
@@ -1,133 +0,0 @@
-#ifndef html_lister_H
-#define html_lister_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-// Headers
-// #ifndef machine_H
-// #include <machine.h>
-// #endif
-
-// Forward declarations
-
-// class ostream;
-// typedef class _Pvts os_typespec; // Remove if not persistant
-
-//
-
-#include "node.h"
-#include "text_lister.h"
-
-class html_lister : public text_lister {
-public:
-
-// -- Exceptions
- // None
-
-// -- Contructors
-
- html_lister(node*);
-
-// -- Destructor
-
- virtual ~html_lister(); // Change to virtual if base class
-
-// -- Convertors
- // None
-
-// -- Operators
- // None
-
-// -- Methods
-
- virtual void line(const char*) = 0;
-
-// -- Overridden methods
-
- void push(node* n);
- void push(const char* p,...);
- void endline();
- void cancel();
- node* source() const { return node_; }
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
- // Uncomment for persistent, remove otherwise
- // static os_typespec* get_os_typespec();
-
-protected:
-
-// -- Members
- // None
-
-// -- Methods
-
- // void print(ostream&) const; // Change to virtual if base class
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-private:
-
-// No copy allowed
-
- html_lister(const html_lister&);
- html_lister& operator=(const html_lister&);
-
-// -- Members
-
- node* node_;
- int nodes_;
- int cancels_;
- char buf_[1024];
-
-// -- Methods
- // None
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-// -- Friends
-
- //friend ostream& operator<<(ostream& s,const html_lister& p)
- // { p.print(s); return s; }
-
-};
-
-inline void destroy(html_lister**) {}
-
-// If persistent, uncomment, otherwise remove
-//#ifdef _ODI_OSSG_
-//OS_MARK_SCHEMA_TYPE(html_lister);
-//#endif
-
-#endif
diff --git a/ecflow_4_0_7/view/src/http.cc b/ecflow_4_0_7/view/src/http.cc
deleted file mode 100644
index 468be9c..0000000
--- a/ecflow_4_0_7/view/src/http.cc
+++ /dev/null
@@ -1,112 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <string.h>
-
-#ifndef http_H
-#include "http.h"
-#endif
-
-#ifndef init_H
-#include "init.h"
-#endif
-
-#ifndef host_H
-#include "host.h"
-#endif
-
-#ifndef node_H
-#include "node.h"
-#endif
-
-#ifndef url_H
-#include "url.h"
-#endif
-
-
-http::http(int port,int argc,char** argv):
- server(port)
-{
- init::initialize(argc,argv);
-}
-
-http::~http()
-{
-}
-
-static const char *json = getenv("ECFLOW_JSON");
-
-void http::serve(int soc)
-{
- url u(soc);
-
- char what[1024];
- char serv[128];
- char from[1024];
- char suit[128] = {0, };
- strncpy(what,u.what(), 1024);
-
- char *p = strtok(what,"/");
- strncpy(serv,p?p:"", 128);
-
- p = strtok(0,"/");
- snprintf(suit,128, "%s",p?p:"");
-
- p = strtok(0,"?");
- snprintf(from,1024, "/%s/%s",suit,p?p:"");
-
- if (json) { // set by environment variable
- node::is_json = true;
- } else {
- node::is_json = false;
- }
- if (strlen(suit) > 5) {
- if (!strncmp(".json", suit+strlen(from) - 5, 5)) {
- suit[strlen(suit) - 5] = '\0';
- }
- }
- if (strlen(from) > 5) {
- if (!strncmp(".json", from+strlen(from) - 5, 5)) {
- from[strlen(from) - 5] = '\0';
- node::is_json = true; // set by url name
- }
- }
- printf("get [%s] [%s] [%s]\n",serv,suit,from);
-
- // host::login(serv);
-
- host* ho = host::find(serv);
- if(ho) {
- if (suit[0] != 0) {
- std::vector<std::string> regist;
- regist.push_back(suit);
- ho->suites(SUITES_REG, regist);
- }
- ho->login();
- ho->status();
- }
- node* n = host::find(serv,from);
-
- u.process(n);
-
-}
-
-int wmain(int argc,char** argv)
-{
- char *p = getenv("ECFLOW_HTTP_PORT");
- http s(atol(p),argc,argv);
- s.run();
- return 0;
-}
diff --git a/ecflow_4_0_7/view/src/http.h b/ecflow_4_0_7/view/src/http.h
deleted file mode 100644
index d9a8bc8..0000000
--- a/ecflow_4_0_7/view/src/http.h
+++ /dev/null
@@ -1,143 +0,0 @@
-#ifndef http_H
-#define http_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include <stdio.h>
-
-#ifndef server_H
-#include "server.h"
-#endif
-
-#ifndef interface_H
-#include "interface.h"
-#endif
-
-
-class http : public interface , public server {
-public:
-
-// -- Exceptions
- // None
-
-// -- Contructors
-
- http(int,int,char**);
-
-// -- Destructor
-
- ~http(); // Change to virtual if base class
-
-// -- Convertors
- // None
-
-// -- Operators
- // None
-
-// -- Methods
- // None
-
-// -- Overridden methods
-
- // From server
-
- virtual void serve(int);
-
-
- // From interface
-
- virtual void clear() {}
- virtual void message(const char* p) { fprintf(stderr,"-> %s\n",p); }
- virtual void watch(Boolean) {}
-
- virtual void add_host(const std::string&) {}
- virtual void remove_host(const std::string&) {}
- virtual void rename_host(const std::string&, const std::string&) {}
-
- virtual void login(const char*) {}
- virtual void logout(const char*) {}
-
- virtual Widget top_shell() { return 0; }
- virtual Widget trees() { return 0; }
- virtual Widget windows() { return 0; }
-
- virtual void error(const char*) {}
-
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
- // Uncomment for persistent, remove otherwise
- // static os_typespec* get_os_typespec();
-
-protected:
-
-// -- Members
- // None
-
-// -- Methods
-
- // void print(ostream&) const; // Change to virtual if base class
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-private:
-
-// No copy allowed
-
- http(const http&);
- http& operator=(const http&);
-
-// -- Members
- // None
-
-// -- Methods
- // None
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-// -- Friends
-
- //friend ostream& operator<<(ostream& s,const http& p)
- // { p.print(s); return s; }
-
-};
-
-inline void destroy(http**) {}
-
-// If persistent, uncomment, otherwise remove
-//#ifdef _ODI_OSSG_
-//OS_MARK_SCHEMA_TYPE(http);
-//#endif
-
-#endif
diff --git a/ecflow_4_0_7/view/src/hyper_lister.cc b/ecflow_4_0_7/view/src/hyper_lister.cc
deleted file mode 100644
index efdd2cd..0000000
--- a/ecflow_4_0_7/view/src/hyper_lister.cc
+++ /dev/null
@@ -1,73 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <stdarg.h>
-#include "hyper_lister.h"
-
-const int hyper_lister::dim_ = 1024;
-
-hyper_lister::hyper_lister(panel& o,node *n):
- owner_(o),
- node_(n),
- nodes_(0),
- cancels_(0)
-{
- buf_[0] = 0;
-}
-
-hyper_lister::~hyper_lister()
-{
-}
-
-void hyper_lister::push(node* n)
-{
- char buf[dim_];
- snprintf(buf,dim_,"{%s}",n->node_name().c_str());
- strcat(buf_,buf);
- nodes_++;
-
- owner_.observe(n);
-}
-
-void hyper_lister::push(const char* p,...)
-{
- char buf[dim_];
- va_list arg;
- va_start(arg,p);
- vsnprintf(buf,dim_,p,arg);
- va_end(arg);
- strcat(buf_,buf);
-}
-
-void hyper_lister::cancel()
-{
- cancels_++;
-}
-
-void hyper_lister::endline()
-{
- if(cancels_) {
- if(cancels_ >= nodes_) {
- //printf("Canceling line %s\n",buf_);
- buf_[0] = 0;
- }
- else {
- //printf("Not canceling line %s\n",buf_);
- }
- }
- line(buf_);
- buf_[0] = 0;
- nodes_ = cancels_ = 0;
-}
diff --git a/ecflow_4_0_7/view/src/hyper_lister.h b/ecflow_4_0_7/view/src/hyper_lister.h
deleted file mode 100644
index 9ef0bb9..0000000
--- a/ecflow_4_0_7/view/src/hyper_lister.h
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef hyper_lister_H
-#define hyper_lister_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "node.h"
-#include "panel.h"
-#include "text_lister.h"
-
-
-class hyper_lister : public text_lister {
-public:
-
- hyper_lister(panel&,node*);
-
- virtual ~hyper_lister(); // Change to virtual if base class
-
- virtual void line(const char*) = 0;
-
- void push(node* n);
- void push(const char* p,...);
- void endline();
- void cancel();
- node* source() const { return node_; }
-
-private:
- static const int dim_;
-
- hyper_lister(const hyper_lister&);
- hyper_lister& operator=(const hyper_lister&);
-
- panel& owner_;
- node* node_;
- int nodes_;
- int cancels_;
- char buf_[1024];
-
- protected:
- panel& owner() { return owner_; }
-};
-
-inline void destroy(hyper_lister**) {}
-
-#endif
diff --git a/ecflow_4_0_7/view/src/icon_Josstatus3.cc b/ecflow_4_0_7/view/src/icon_Josstatus3.cc
deleted file mode 100644
index 2a9b2bd..0000000
--- a/ecflow_4_0_7/view/src/icon_Josstatus3.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-#include "pixmap.h"
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static const char * bits[] = {
-"16 16 5 1",
-" c None",
-". c #000000",
-"+ c #0000FF",
-"@ c #00FF00",
-"# c #FF0000",
-"................",
-".+++++++@@@@###.",
-".+++++++@@@@###.",
-".+++++++@@@@###.",
-".+++++++@@@@###.",
-"................",
-".+++++++@@#####.",
-".+++++++@@#####.",
-".+++++++@@#####.",
-".+++++++@@#####.",
-"................",
-".+++++++++++###.",
-".+++++++++++###.",
-".+++++++++++###.",
-".+++++++++++###.",
-"................"};
-static pixmap p("Josstatus3",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/icon_W.cc b/ecflow_4_0_7/view/src/icon_W.cc
deleted file mode 100644
index 3184a5f..0000000
--- a/ecflow_4_0_7/view/src/icon_W.cc
+++ /dev/null
@@ -1,86 +0,0 @@
-#include "pixmap.h"
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static const char * bits[] = {
-"16 16 50 1",
-" c None",
-". c #E7E7E7",
-"+ c #E7E3E3",
-"@ c #E9CDCD",
-"# c #EEA3A3",
-"$ c #FF0000",
-"% c #FA2A2A",
-"& c #F64E4E",
-"* c #F93434",
-"= c #FB1C1C",
-"- c #F46464",
-"; c #FD0E0E",
-"> c #EDA9A9",
-", c #E8D7D7",
-"' c #FB2222",
-") c #FE0606",
-"! c #ECB5B5",
-"~ c #FA2727",
-"{ c #EDABAB",
-"] c #F83E3E",
-"^ c #EF9494",
-"/ c #E7E5E5",
-"( c #EE9F9F",
-"_ c #F36D6D",
-": c #F08D8D",
-"< c #F74646",
-"[ c #ECB0B0",
-"} c #FE0404",
-"| c #FA2828",
-"1 c #E8DBDB",
-"2 c #E9CACA",
-"3 c #FD1313",
-"4 c #FD1212",
-"5 c #EACACA",
-"6 c #E7E6E6",
-"7 c #F65555",
-"8 c #E7DFDF",
-"9 c #E8DCDC",
-"0 c #FA2929",
-"a c #ECAFAF",
-"b c #F18484",
-"c c #F74949",
-"d c #E7E0E0",
-"e c #F27D7D",
-"f c #FE0101",
-"g c #F46868",
-"h c #F93939",
-"i c #F93131",
-"j c #FD0B0B",
-"k c #EDA6A6",
-"................",
-"................",
-"....+@@@@@@@@...",
-"....#$$%&*$$=...",
-"....-;>.,'$)!...",
-"....~{.+]$$^....",
-".../(..-$$_.....",
-"......:$$</.....",
-".....[}$|1......",
-"....23$45.678...",
-"...90$}a..b0....",
-"...c$$:.defg....",
-"...$$)hij$$k....",
-"................",
-"................",
-"................"};
-static pixmap p("W",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/info.cc b/ecflow_4_0_7/view/src/info.cc
deleted file mode 100644
index 81e868b..0000000
--- a/ecflow_4_0_7/view/src/info.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "info.h"
-#include "node.h"
-#include "error.h"
-#include "selection.h"
-#include "Hyper.h"
-#include <stdio.h>
-#include "ecf_node.h"
-
-info::info(panel_window& w):
- panel(w)
-{
-}
-
-info::~info()
-{
-}
-
-void info::clear()
-{
- forget_all();
- HyperSetText(text_,(char*)"No node selected.");
-}
-
-void info::show(node& n)
-{
- forget_all();
- std::stringstream ss;
- n.info(ss);
- HyperSetText(text_,(char*) ss.str().c_str());
-}
-
-void info::hyperCB(Widget w,XtPointer data)
-{
- panel::hyper(w,data);
-}
-
-Boolean info::enabled(node& n)
-{
- return n.hasInfo();
-}
diff --git a/ecflow_4_0_7/view/src/info.h b/ecflow_4_0_7/view/src/info.h
deleted file mode 100644
index 11da7ce..0000000
--- a/ecflow_4_0_7/view/src/info.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef info_H
-#define info_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "uiinfo.h"
-
-#ifndef panel_H
-#include "panel.h"
-#endif
-
-class info : public panel, public info_form_c {
-public:
- info(panel_window&);
-
- ~info(); // Change to virtual if base class
-
- virtual const char* name() const { return "Info"; }
- virtual void show(node&);
- virtual void clear();
- virtual Widget widget() { return xd_rootwidget(); }
- virtual Boolean enabled(node&);
-
-private:
-
- info(const info&);
- info& operator=(const info&);
-
- virtual void hyperCB(Widget,XtPointer);
-};
-
-inline void destroy(info**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/init.cc b/ecflow_4_0_7/view/src/init.cc
deleted file mode 100644
index 9a84a8d..0000000
--- a/ecflow_4_0_7/view/src/init.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "init.h"
-
-init::init()
-{
-}
-
-init::~init()
-{
-}
-
-void init::initialize(int argc,char** argv)
-{
- init* p = first();
- while(p) {
- p->run(argc,argv);
- p = p->next();
- }
-}
-
-IMP(init)
-
diff --git a/ecflow_4_0_7/view/src/init.h b/ecflow_4_0_7/view/src/init.h
deleted file mode 100644
index 9a4e9af..0000000
--- a/ecflow_4_0_7/view/src/init.h
+++ /dev/null
@@ -1,127 +0,0 @@
-#ifndef init_H
-#define init_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-// Headers
-// #ifndef machine_H
-// #include <machine.h>
-// #endif
-
-// Forward declarations
-
-// class ostream;
-// typedef class _Pvts os_typespec; // Remove if not persistant
-
-
-#ifndef extent_H
-#include "extent.h"
-#endif
-
-//
-
-class init : public extent<init> {
-public:
-
-// -- Exceptions
- // None
-
-// -- Contructors
-
- init();
-
-// -- Destructor
-
- virtual ~init(); // Change to virtual if base class
-
-// -- Convertors
- // None
-
-// -- Operators
- // None
-
-// -- Methods
-
- virtual void run(int,char**) = 0;
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
-
- static void initialize(int,char**);
-
- // Uncomment for persistent, remove otherwise
- // static os_typespec* get_os_typespec();
-
-protected:
-
-// -- Members
- // None
-
-// -- Methods
-
- // void print(ostream&) const; // Change to virtual if base class
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-private:
-
-// No copy allowed
-
- init(const init&);
- init& operator=(const init&);
-
-// -- Members
- // None
-
-// -- Methods
- // None
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-// -- Friends
-
- //friend ostream& operator<<(ostream& s,const init& p)
- // { p.print(s); return s; }
-
-};
-
-inline void destroy(init**) {}
-
-// If persistent, uncomment, otherwise remove
-//#ifdef _ODI_OSSG_
-//OS_MARK_SCHEMA_TYPE(init);
-//#endif
-
-#endif
diff --git a/ecflow_4_0_7/view/src/inlimit_node.cc b/ecflow_4_0_7/view/src/inlimit_node.cc
deleted file mode 100644
index 2518535..0000000
--- a/ecflow_4_0_7/view/src/inlimit_node.cc
+++ /dev/null
@@ -1,71 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "inlimit_node.h"
-#include "ecf_node.h"
-#include "NodeAttr.hpp"
-
-inlimit_node::inlimit_node(host& h,ecf_node* n)
- : node(h,n)
- , buf_()
- {
- if (owner_) buf_ = owner_->toString();
- full_name_ = parent()->full_name();
- full_name_ += ":";
- full_name_ += buf_;
-}
-
-#ifdef BRIDGE
-extern "C" {
-#define new _new
-#define delete _delete
-#include "smsproto.h"
-}
-inlimit_node::inlimit_node(host& h,sms_node* n, char b)
- : node(h,n,b)
- , buf_("limited by: ")
- , full_name_ ("inlimit: ")
-{
- if (n) { buf_ += n->name;
- full_name_ = sms_node_full_name(n);
- }
-}
-#endif
-
-inlimit_node::~inlimit_node() {
-}
-
-xmstring inlimit_node::make_label_tree()
-{
- char buf[1024];
- sprintf(buf,"%s",buf_.c_str());
- return xmstring(buf);
-}
-
-void inlimit_node::perlify(FILE* f)
-{
- perl_member(f,"limit",owner_->name().c_str());
- // perl_member(f,"usage",owner_->usage());
-}
-
-bool inlimit_node::match(const char* p)
-{
- return strstr(owner_->name().c_str(), p) != 0;
-}
-
-const std::string& inlimit_node::full_name() const
-{
- return full_name_;
-}
diff --git a/ecflow_4_0_7/view/src/inlimit_node.h b/ecflow_4_0_7/view/src/inlimit_node.h
deleted file mode 100644
index d42cd5e..0000000
--- a/ecflow_4_0_7/view/src/inlimit_node.h
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef INLIMIT_NODE_H
-#define INLIMIT_NODE_H
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #10 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-
-#include "node.h"
-#include "show.h"
-
-class inlimit_node : public node {
-
- std::string buf_, full_name_;
- virtual bool match(const char*);
-
- virtual void info(std::ostream&) {}
- virtual xmstring make_label_tree();
-
- virtual const std::string& name() const { return buf_; }
- virtual const std::string& full_name() const;
- virtual Boolean menus() { return False; }
- virtual Boolean selectable() { return True; }
-
- virtual Boolean visible() const { return show::want(show::inlimit); }
-
- virtual void triggered(trigger_lister&) {}
- virtual void triggers(trigger_lister&) {}
- virtual void perlify(FILE*);
-
-public:
- inlimit_node(host& h,ecf_node* n);
-#ifdef BRIDGE
- inlimit_node(host& h,sms_node* n, char b); // : node(h,n,b) {}
-#endif
- ~inlimit_node();
-};
-
-#endif
diff --git a/ecflow_4_0_7/view/src/input.cc b/ecflow_4_0_7/view/src/input.cc
deleted file mode 100644
index 70940eb..0000000
--- a/ecflow_4_0_7/view/src/input.cc
+++ /dev/null
@@ -1,67 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <stdio.h>
-#include <strings.h>
-#include "ecflowview.h"
-#include "input.h"
-
-extern XtAppContext app_context;
-
-void input::inputCB(XtPointer data,int*,XtInputId* id)
-{
- input* p = ((input*)data);
- char buf[1024];
-
- if(fgets(buf,sizeof(buf),p->file_))
- {
- if(buf[0]) buf[strlen(buf)-1] = 0;
- p->ready(buf);
- }
- else
- p->done(p->file_);
-}
-
-input::input():
- id_(0),
- file_(0)
-{
-}
-
-input::~input()
-{
- stop();
-}
-
-void input::stop()
-{
- if(file_)
- {
- XtRemoveInput(id_);
- file_ = 0;
- }
-}
-
-void input::start(FILE* f)
-{
- if(file_ == 0)
- {
- file_ = f;
- id_ = XtAppAddInput(app_context,fileno(f),
- XtPointer(XtInputReadMask),
- inputCB,this);
- }
-}
-
diff --git a/ecflow_4_0_7/view/src/input.h b/ecflow_4_0_7/view/src/input.h
deleted file mode 100644
index d224682..0000000
--- a/ecflow_4_0_7/view/src/input.h
+++ /dev/null
@@ -1,127 +0,0 @@
-#ifndef input_H
-#define input_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include <Xm/Xm.h>
-
-// Headers
-// #ifndef machine_H
-// #include <machine.h>
-// #endif
-
-// Forward declarations
-
-// class ostream;
-// typedef class _Pvts os_typespec; // Remove if not persistant
-
-
-//
-
-#include <stdio.h>
-
-class input {
-public:
-
-// -- Exceptions
- // None
-
-// -- Contructors
-
- input();
-
-// -- Destructor
-
- virtual ~input(); // Change to virtual if base class
-
-// -- Convertors
- // None
-
-// -- Operators
- // None
-
-// -- Methods
- // None
-
- void start(FILE*);
- void stop();
-
- virtual void ready(const char*) = 0;
- virtual void done(FILE*) = 0;
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
- // Uncomment for persistent, remove otherwise
- // static os_typespec* get_os_typespec();
-
-protected:
-
-// -- Members
-
-
-// -- Methods
-
- // void print(ostream&) const; // Change to virtual if base class
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-private:
-
-// No copy allowed
-
- input(const input&);
- input& operator=(const input&);
-
-// -- Members
-
- XtInputId id_;
- FILE* file_;
-
-// -- Methods
- // None
-
-// -- Overridden methods
- // None
-
-// -- Class members
-
-// -- Class methods
- // None
- static void inputCB(XtPointer,int*,XtInputId*);
-
-// -- Friends
-
- //friend ostream& operator<<(ostream& s,const input& p)
- // { p.print(s); return s; }
-
-};
-
-
-#endif
diff --git a/ecflow_4_0_7/view/src/interface.cc b/ecflow_4_0_7/view/src/interface.cc
deleted file mode 100644
index 6894fc3..0000000
--- a/ecflow_4_0_7/view/src/interface.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "interface.h"
-#include "gui.h"
-
-interface::interface()
-{
- gui::set_interface(this);
-}
-
-interface::~interface()
-{
-}
diff --git a/ecflow_4_0_7/view/src/interface.h b/ecflow_4_0_7/view/src/interface.h
deleted file mode 100644
index 90fb8c7..0000000
--- a/ecflow_4_0_7/view/src/interface.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef interface_H
-#define interface_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include <Xm/Xm.h>
-#include <string>
-
-class interface {
-public:
-
- interface();
-
- ~interface(); // Change to virtual if base class
-
- virtual void clear() = 0;
- virtual void message(const char*) = 0;
- virtual void watch(Boolean) = 0;
-
- virtual void add_host(const std::string&) = 0;
- virtual void remove_host(const std::string&) = 0;
- virtual void rename_host(const std::string&,const std::string&) = 0;
-
- virtual void login(const char*) = 0;
- virtual void logout(const char*) = 0;
-
- virtual Widget top_shell() = 0;
- virtual Widget trees() = 0;
- virtual Widget windows() = 0;
-
- virtual bool visible() { return top_shell() != 0; }
- virtual void error(const char*) = 0;
-private:
-
- interface(const interface&);
- interface& operator=(const interface&);
-
-};
-
-inline void destroy(interface**) {}
-
-#endif
diff --git a/ecflow_4_0_7/view/src/job.cc b/ecflow_4_0_7/view/src/job.cc
deleted file mode 100644
index 1f671aa..0000000
--- a/ecflow_4_0_7/view/src/job.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #8 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "job.h"
-#include "node.h"
-#include "host.h"
-#include "ecf_node.h"
-#include <Xm/Text.h>
-extern "C" {
-#include "xec.h"
-}
-
-job::job(panel_window& w):
- panel(w),
- text_window(false)
-{
-}
-
-job::~job()
-{
-}
-
-void job::clear()
-{
- XmTextSetString(name_,"");
- text_window::clear();
-}
-
-void job::show(node& n)
-{
- const std::string& job = n.__node__() ?
- n.variable("ECF_JOB") : n.variable("SMSJOB");
- XmTextSetString(name_, (char*) job.c_str());
- load(n.serv().job(n));
-}
-
-Boolean job::enabled(node& n)
-{
- if (n.type() != NODE_TASK && n.type() != NODE_ALIAS) return False;
- const std::string& job = n.__node__() ?
- n.variable("ECF_JOB") : n.variable("SMSJOB");
- return job.size() > 7;
-}
-
-void job::create (Widget parent, char *widget_name )
-{
- job_form_c::create(parent,widget_name);
-}
-
diff --git a/ecflow_4_0_7/view/src/job.h b/ecflow_4_0_7/view/src/job.h
deleted file mode 100644
index 337b087..0000000
--- a/ecflow_4_0_7/view/src/job.h
+++ /dev/null
@@ -1,65 +0,0 @@
-#ifndef job_H
-#define job_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "uijob.h"
-
-#ifndef panel_H
-#include "panel.h"
-#endif
-
-#ifndef text_window_H
-#include "text_window.h"
-#endif
-
-class job : public panel, public job_form_c, public text_window {
-public:
-
- job(panel_window&);
-
- ~job(); // Change to virtual if base class
-
- virtual const char* name() const { return "Job"; }
- virtual void show(node&);
- virtual Boolean enabled(node&);
- virtual void clear();
- virtual Widget widget() { return job_form_c::xd_rootwidget(); }
-
- virtual Widget tools() { return tools_; }
- virtual Widget text() { return text_; }
- virtual void create (Widget parent, char *widget_name = 0 );
-
-private:
-
- job(const job&);
- job& operator=(const job&);
-
- virtual void externalCB(Widget ,XtPointer )
- { text_window::open_viewer();}
-
- virtual void searchCB(Widget ,XtPointer )
- { text_window::open_search();}
-
- virtual bool can_print() { return true; }
- virtual bool can_save() { return true; }
- virtual void print() { text_window::print(); }
- virtual void save() { text_window::save(); }
-};
-
-inline void destroy(job**) {}
-
-#endif
diff --git a/ecflow_4_0_7/view/src/jobcheck_panel.cc b/ecflow_4_0_7/view/src/jobcheck_panel.cc
deleted file mode 100644
index 64c6fb9..0000000
--- a/ecflow_4_0_7/view/src/jobcheck_panel.cc
+++ /dev/null
@@ -1,92 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #9 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "jobcheck_panel.h"
-#include "node.h"
-#include "host.h"
-#include <Xm/Text.h>
-extern "C" {
-#include "xec.h"
-}
-
-static const std::string cmd_str_ecf = "ECF_CHECK_CMD";
-static const std::string cmd_str_sms = "SMS_CHECK_CMD";
-
-jobcheck_panel::jobcheck_panel(panel_window& w):
- panel(w),
- text_window(false)
-{
-}
-
-jobcheck_panel::~jobcheck_panel()
-{
-}
-
-void jobcheck_panel::clear()
-{
- text_window::clear();
-}
-
-void jobcheck_panel::show(node& n)
-{
- const std::string& cmd = n.__node__() ? cmd_str_ecf : cmd_str_sms;
- const char* p = n.variable(cmd).c_str();
-
- if(p)
- XmTextSetString(name_,(char*)p);
- else
- XmTextSetString(name_,(char*)"");
-
- if (n.type() != NODE_TASK && n.type() != NODE_ALIAS)
- return;
- if (n.status() != STATUS_SUBMITTED &&
- n.status() != STATUS_ACTIVE &&
- n.status() != STATUS_SUSPENDED)
- return;
- tmp_file f = n.serv().jobcheck(n, cmd);
- text_window::load(f);
-}
-
-Boolean jobcheck_panel::enabled(node& n)
-{
- if (n.type() != NODE_TASK && n.type() != NODE_ALIAS) return False;
- if (n.status() != STATUS_SUBMITTED && n.status() != STATUS_ACTIVE) return False;
- const std::string& cmd = n.__node__() ? cmd_str_ecf : cmd_str_sms;
- return n.variable(cmd).size() > 7;
-}
-
-void jobcheck_panel::create (Widget parent, char *widget_name )
-{
- jobcheck_form_c::create(parent,widget_name);
-}
-
-void jobcheck_panel::update()
-{
-}
-
-void jobcheck_panel::changed(node &)
-{
- clear();
-}
-
-void jobcheck_panel::refresh()
-{
- node* n = get_node();
- if(n)
- show(*n);
- else
- clear();
-}
-
diff --git a/ecflow_4_0_7/view/src/jobcheck_panel.h b/ecflow_4_0_7/view/src/jobcheck_panel.h
deleted file mode 100644
index ff69cbe..0000000
--- a/ecflow_4_0_7/view/src/jobcheck_panel.h
+++ /dev/null
@@ -1,66 +0,0 @@
-#ifndef jobcheck_panel_H
-#define jobcheck_panel_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "uijobcheck.h"
-
-#ifndef panel_H
-#include "panel.h"
-#endif
-
-#ifndef text_window_H
-#include "text_window.h"
-#endif
-
-class jobcheck_panel : public panel
- , public jobcheck_form_c
- , public text_window
-{
-public:
- jobcheck_panel(panel_window&);
-
- ~jobcheck_panel(); // Change to virtual if base class
-
- void refresh();
-
- virtual const char* name() const { return "Check"; }
- virtual void show(node&);
- virtual Boolean enabled(node&);
- virtual void clear();
- virtual Widget widget() { return jobcheck_form_c::xd_rootwidget(); }
- virtual Widget tools() { return tools_; }
- virtual Widget text() { return text_; }
- virtual void create (Widget parent, char *widget_name = 0 );
-
-private:
-
- jobcheck_panel(const jobcheck_panel&);
- jobcheck_panel& operator=(const jobcheck_panel&);
-
- virtual void update();
- virtual void changed(node&);
-
- virtual void refreshCB(Widget, XtPointer ) { refresh();}
-
- virtual bool can_print() { return true; }
- virtual bool can_save() { return true; }
- virtual void print() { text_window::print(); }
- virtual void save() { text_window::save(); }
-};
-
-inline void destroy(jobcheck_panel**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/jobstatus.cc b/ecflow_4_0_7/view/src/jobstatus.cc
deleted file mode 100644
index e585e71..0000000
--- a/ecflow_4_0_7/view/src/jobstatus.cc
+++ /dev/null
@@ -1,109 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #13 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "jobstatus.h"
-#include "node.h"
-#include "host.h"
-#include <Xm/Text.h>
-#include "ecf_node.h"
-extern "C" {
-#include "xec.h"
-}
-
-static const std::string cmd_str_ecf = "ECF_STATUS_CMD";
-static const std::string cmd_str_sms = "SMSSTATUSCMD";
-
-jobstatus::jobstatus(panel_window& w):
- panel(w),
- text_window(false)
- , reload_(true)
-{
-}
-
-jobstatus::~jobstatus()
-{
-}
-
-void jobstatus::clear()
-{
- XmTextSetString(name_,(char*)"");
- text_window::clear();
-}
-
-void jobstatus::show(node& n)
-{
- ecf_node* ecf = n.__node__();
- const std::string& scmd = ecf ? cmd_str_ecf : cmd_str_sms;
- const std::string var = n.variable(scmd, true);
- const std::string& job = ecf ? n.variable("ECF_JOB") : n.variable("SMSJOB");
-
- // const char *p = var.c_str();
- // const std::string cmd = (ecf && p) ? ecf->substitute(var) : var;
- std::string stat = job + ".stat";
-
- if (!var.empty())
- XmTextSetString(name_,(char*)var.c_str());
- else if(!scmd.empty())
- XmTextSetString(name_,(char*)scmd.c_str());
- else {
- std::string cmd = scmd + "%s variable does not exist";
- XmTextSetString(name_,(char*)cmd.c_str());
- }
- if (n.type() != NODE_TASK && n.type() != NODE_ALIAS) {
- XmTextSetString(name_,(char*)"not a task");
- return;
- }
- if (n.status() != STATUS_SUBMITTED &&
- n.status() != STATUS_ACTIVE &&
- n.status() != STATUS_SUSPENDED) {
- XmTextSetString(name_,(char*)"not submitted not active");
- return;
- }
- if (reload_) { reload_ = false; ;
- tmp_file (n.serv().jobstatus(n, ""));
- }
- tmp_file f (stat.c_str(), false);
- text_window::load(f);
-}
-
-void jobstatus::updateCB(Widget,XtPointer data)
-{
- reload_ = true;
- if(get_node())
- show(*get_node());
- else
- clear();
- XmTextShowPosition(text_,XmTextGetLastPosition(text_));
-}
-
-Boolean jobstatus::enabled(node& n)
-{
-
- if (n.type() != NODE_TASK && n.type() != NODE_ALIAS)
- return False;
-
- if (n.status() != STATUS_SUBMITTED &&
- n.status() != STATUS_ACTIVE &&
- n.status() != STATUS_SUSPENDED)
- return False;
-
- const std::string& cmd = n.__node__() ? cmd_str_ecf : cmd_str_sms;
- return n.variable(cmd).size() > 6;
-}
-
-void jobstatus::create (Widget parent, char *widget_name )
-{
- jobstatus_form_c::create(parent,widget_name);
-}
diff --git a/ecflow_4_0_7/view/src/jobstatus.h b/ecflow_4_0_7/view/src/jobstatus.h
deleted file mode 100644
index 77e5d96..0000000
--- a/ecflow_4_0_7/view/src/jobstatus.h
+++ /dev/null
@@ -1,71 +0,0 @@
-#ifndef jobstatus_H
-#define jobstatus_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "uijobstatus.h"
-
-#ifndef panel_H
-#include "panel.h"
-#endif
-
-#ifndef text_window_H
-#include "text_window.h"
-#endif
-
-class jobstatus : public panel
- , public jobstatus_form_c
- , public text_window {
-public:
-
- jobstatus(panel_window&);
-
- ~jobstatus(); // Change to virtual if base class
-
- virtual const char* name() const { return "Jobstatus"; }
- virtual void show(node&);
- virtual Boolean enabled(node&);
- virtual void clear();
- virtual Widget widget() { return jobstatus_form_c::xd_rootwidget(); }
-
- virtual Widget tools() { return tools_; }
- virtual Widget text() { return text_; }
- virtual void create (Widget parent, char *widget_name = 0 );
-
-private:
-
- jobstatus(const jobstatus&);
- jobstatus& operator=(const jobstatus&);
-
- virtual void updateCB(Widget,XtPointer);
-
- virtual void externalCB(Widget w,XtPointer p)
- { text_window::open_viewer();}
-
- virtual void searchCB(Widget w,XtPointer p)
- { text_window::open_search();}
-
- virtual bool can_print() { return true; }
- virtual bool can_save() { return true; }
- virtual void print() { text_window::print(); }
- virtual void save() { text_window::save(); }
-
- int reload_;
-};
-
-inline void destroy(jobstatus**) {}
-
-#endif
diff --git a/ecflow_4_0_7/view/src/label.cc b/ecflow_4_0_7/view/src/label.cc
deleted file mode 100644
index acad886..0000000
--- a/ecflow_4_0_7/view/src/label.cc
+++ /dev/null
@@ -1,89 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #15 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "label_node.h"
-#include "show.h"
-#include "text_lister.h"
-
-#ifndef ecf_node_
-#include "ecf_node.h"
-#endif
-
-const Label& label_node::get() {
- ecf_concrete_node<const Label>* base =
- dynamic_cast<ecf_concrete_node<const Label>*> (owner_);
- if (base) return *(base->get());
- if (parent() && parent()->__node__())
- return parent()->__node__()->get_label(name());
- return Label::EMPTY();
-}
-
-xmstring label_node::make_label_tree()
-{
- return xmstring(name().c_str(),"bold") + xmstring(": ","bold")
- + xmstring(value());
-}
-
-void label_node::drawNode(Widget w,XRectangle* r,bool)
-{
- XmStringDraw(XtDisplay(w),XtWindow(w),
- smallfont(),
- labelTree(),
- blackGC(),
- r->x+2,
- r->y+2,
- r->width,
- XmALIGNMENT_BEGINNING, XmSTRING_DIRECTION_L_TO_R, r);
- shadow(w,r);
-}
-
-void label_node::info(std::ostream& f)
-{
- node::info(f);
- f << "\nText:\n";
- f << "-----\n";
- f << value();
- f << "\n\nDefault:\n";
- f << "-------\n";
- f << def() << "\n";
-}
-
-void label_node::perlify(FILE* f)
-{
- perl_member(f,"value", value());
- perl_member(f,"default",def());
-}
-
-const char* label_node::value()
-{
- // static bool prb = false; if (prb) return 0x0; prb = true;
-#ifdef BRIDGE
- if (tree_) return ((sms_label*) tree_)->value;
-#endif
- const Label& lab = get();
- if (lab.new_value().empty() || lab.new_value() == "")
- return def();
- return lab.new_value().c_str();
-}
-
-const char* label_node::def()
-{
-#ifdef BRIDGE
- if (tree_) return ((sms_label*) tree_)->def;
-#endif
- return get().value().c_str();
-}
-
-Boolean label_node::visible() const { return show::want(show::label); }
diff --git a/ecflow_4_0_7/view/src/label_node.h b/ecflow_4_0_7/view/src/label_node.h
deleted file mode 100644
index 00957de..0000000
--- a/ecflow_4_0_7/view/src/label_node.h
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef label_node_H
-#define label_node_H
-
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #9 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "node.h"
-
-class label_node : public node {
-public:
-
- label_node(host& h,ecf_node* n) : node(h,n) {}
-#ifdef BRIDGE
- label_node(host& h,sms_node* n, char b) : node(h,n,b) {}
-#endif
- const char* value();
- const char* def();
-
-protected:
-
-private:
-
- label_node(const label_node&);
- label_node& operator=(const label_node&);
-
- const Label& get();
-
- virtual void info(std::ostream&);
- virtual xmstring make_label_tree();
- virtual void drawNode(Widget,XRectangle*,bool);
-
- virtual Boolean visible() const;
- virtual void triggered(trigger_lister&) {}
- virtual void triggers(trigger_lister&) {}
-
- virtual void perlify(FILE*);
-};
-
-inline void destroy(label_node**) {}
-
-#endif
diff --git a/ecflow_4_0_7/view/src/late.cc b/ecflow_4_0_7/view/src/late.cc
deleted file mode 100644
index e6ae595..0000000
--- a/ecflow_4_0_7/view/src/late.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "late.h"
-#include "node.h"
-
-
-late::late():
- node_alert<late>("Late nodes")
-{
-}
-
-late::~late()
-{
-}
-
-bool late::keep(node* n)
-{
- return n->isLate();
-}
diff --git a/ecflow_4_0_7/view/src/late.h b/ecflow_4_0_7/view/src/late.h
deleted file mode 100644
index 6a15017..0000000
--- a/ecflow_4_0_7/view/src/late.h
+++ /dev/null
@@ -1,109 +0,0 @@
-#ifndef late_H
-#define late_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "node_alert.h"
-
-class node;
-
-class late : public node_alert<late> {
-public:
-
-// -- Exceptions
- // None
-
-// -- Contructors
-
- late();
-
-// -- Destructor
-
- ~late(); // Change to virtual if base class
-
-// -- Convertors
- // None
-
-// -- Operators
- // None
-
-// -- Methods
- // None
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
-
- // Uncomment for persistent, remove otherwise
- // static os_typespec* get_os_typespec();
-
-protected:
-
-// -- Members
- // None
-
-// -- Methods
-
- // void print(ostream&) const; // Change to virtual if base class
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-private:
-
-// No copy allowed
-
- late(const late&);
- late& operator=(const late&);
-
-// -- Methods
-
-
-// -- Overridden methods
-
- virtual bool keep(node*);
-
-// -- Class members
-
-
-// -- Class methods
- // None
-
-// -- Friends
-
- //friend ostream& operator<<(ostream& s,const late& p)
- // { p.print(s); return s; }
-
-};
-
-inline void destroy(late**) {}
-
-// If persistent, uncomment, otherwise remove
-//#ifdef _ODI_OSSG_
-//OS_MARK_SCHEMA_TYPE(late);
-//#endif
-
-#endif
diff --git a/ecflow_4_0_7/view/src/late_node.cc b/ecflow_4_0_7/view/src/late_node.cc
deleted file mode 100644
index 524ee57..0000000
--- a/ecflow_4_0_7/view/src/late_node.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "late_node.h"
-
-xmstring late_node::make_label_tree()
-{
- if (!owner_) return xmstring("late: ","bold") + xmstring(label_.c_str());
- return xmstring(label_.c_str());
-}
-
-void late_node::perlify(FILE* f)
-{
- perl_member(f,"value",label_.c_str());
-}
-
-const std::string& late_node::name() const { return label_; }
diff --git a/ecflow_4_0_7/view/src/late_node.h b/ecflow_4_0_7/view/src/late_node.h
deleted file mode 100644
index 0119648..0000000
--- a/ecflow_4_0_7/view/src/late_node.h
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef LATE_NODE_H
-#define LATE_NODE_H
-
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #11 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "node.h"
-#include "show.h"
-
-class late_node : public node {
-
- virtual bool is_my_parent(node*) const { return false; }
- virtual void info(std::ostream&) {}
-
- virtual xmstring make_label_tree();
-
- virtual const std::string& name() const;
- virtual const std::string& full_name() const { return name(); }
- virtual Boolean menus() { return False; }
- virtual Boolean selectable() { return False; }
-
- virtual Boolean visible() const {
- return show::want(show::late); }
-
- virtual void perlify(FILE* f);
-
-public:
- late_node(host& h,ecf_node* n) : node(h,n), label_(n ? n->toString() : "late") {}
-#ifdef BRIDGE
- late_node(host& h,sms_node* n, char b);
-#endif
-
-protected:
- const std::string label_;
-};
-
-#endif
diff --git a/ecflow_4_0_7/view/src/layout.cc b/ecflow_4_0_7/view/src/layout.cc
deleted file mode 100644
index e968a27..0000000
--- a/ecflow_4_0_7/view/src/layout.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "layout.h"
-
-layout::layout(trigger_panel& o,Widget w):
- widget_(w),
- owner_(o)
-{
-}
-
-layout::~layout()
-{
-}
diff --git a/ecflow_4_0_7/view/src/layout.h b/ecflow_4_0_7/view/src/layout.h
deleted file mode 100644
index 8dbbf9e..0000000
--- a/ecflow_4_0_7/view/src/layout.h
+++ /dev/null
@@ -1,134 +0,0 @@
-#ifndef layout_H
-#define layout_H
-
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-// Headers
-// #ifndef machine_H
-// #include <machine.h>
-// #endif
-
-// Forward declarations
-
-// class ostream;
-// typedef class _Pvts os_typespec; // Remove if not persistant
-
-//
-
-#include <Xm/Xm.h>
-
-class node;
-class trigger_panel;
-
-class layout {
-public:
-
-// -- Exceptions
- // None
-
-// -- Contructors
-
- layout(trigger_panel&,Widget);
-
-// -- Destructor
-
- virtual ~layout(); // Change to virtual if base class
-
-// -- Convertors
- // None
-
-// -- Operators
- // None
-
-// -- Methods
-
- virtual void clear() = 0;
- virtual void show(node&) = 0 ;
- virtual void reach(node*,node*) = 0;
- virtual void selectNode(node*) {}
-
- trigger_panel& owner() { return owner_; }
- Widget layout_widget() { return widget_; }
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
- // Uncomment for persistent, remove otherwise
- // static os_typespec* get_os_typespec();
-
-protected:
-
-// -- Members
-
- Widget widget_;
- trigger_panel& owner_;
-
-// -- Methods
-
- // void print(ostream&) const; // Change to virtual if base class
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-private:
-
-// No copy allowed
-
- layout(const layout&);
- layout& operator=(const layout&);
-
-// -- Members
- // None
-
-// -- Methods
- // None
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-// -- Friends
-
- //friend ostream& operator<<(ostream& s,const layout& p)
- // { p.print(s); return s; }
-
-};
-
-inline void destroy(layout**) {}
-
-// If persistent, uncomment, otherwise remove
-//#ifdef _ODI_OSSG_
-//OS_MARK_SCHEMA_TYPE(layout);
-//#endif
-
-#endif
diff --git a/ecflow_4_0_7/view/src/lexyacc.h b/ecflow_4_0_7/view/src/lexyacc.h
deleted file mode 100644
index 31e71ef..0000000
--- a/ecflow_4_0_7/view/src/lexyacc.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #5 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include <Xm/Xm.h>
-#include "SimpleTime.h"
-
-typedef struct _flags flags;
-typedef struct _menu menu;
-typedef struct _item item;
-typedef struct _action action;
-typedef struct _node node;
-
-#ifdef hpux
-/* hpux X11 headers are wromg */
-#undef bcopy
-#undef bzero
-#undef bcmp
-#endif
-
-int menus_version(int rel, int maj, int min);
-menu* menus_chain_menus(menu *a,menu *b);
-item* menus_chain_items(item *a,item *b);
-void menus_root(menu *m);
-menu* menus_create_2(char* a,item* b);
-item* menus_create_6(flags* a,flags* b,char* c,action* d,char* e,int f);
-
-action* menus_command(char* a);
-action* menus_window(char* a);
-action* menus_separator();
-action* menus_sub_menu();
-
-flags* new_flagNone();
-flags* new_typeFlag(int a);
-flags* new_flagNot(flags* a);
-flags* new_flagOr(flags* a,flags* b);
-flags* new_flagAnd(flags* a,flags* b);
-
-flags* new_flagAll();
-flags* new_eventFlag(int a);
-flags* new_selectionFlag();
-flags* new_statusFlag(int a);
-flags* new_userFlag(int a);
-
-flags* new_procFlag_node_hasTriggers();
-flags* new_procFlag_node_hasDate();
-flags* new_procFlag_node_hasTime();
-flags* new_procFlag_node_hasText();
-flags* new_procFlag_node_isMigrated();
-flags* new_procFlag_node_isLocked();
-flags* new_procFlag_node_isZombie();
-
-action* menus_internal_host_plug();
-action* menus_internal_host_compare(char*a, char*b);
-
-void log_event_meter_event(DateTime* a,node* b,int c);
-void log_event_event_event(DateTime* a,node* b,int c);
-void log_event_status_event(DateTime* a,node* b,int c);
-node *log_event_find(char* a);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Apply.cc b/ecflow_4_0_7/view/src/libicon/icon_Apply.cc
deleted file mode 100644
index 064c8b0..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Apply.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #5 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 6 1",
-" c #E79DE79DE79D",
-". c #0000EFBE0000",
-"X c #0000FFFF0000",
-"o c #000000000000",
-"O c #FFFFFFFFFFFF",
-"+ c #00008A280000",
-" ",
-" ",
-" ",
-" ",
-" .... ",
-" .XXXXo ",
-" .XOXXXX+ ",
-" .XXXXXX+ ",
-" .XXXXXX+ ",
-" .XXXXXX+ ",
-" +XXXX+ ",
-" ++++ ",
-" ",
-" ",
-" ",
-" "};
-static pixmap p("Apply",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Apply.xpm b/ecflow_4_0_7/view/src/libicon/icon_Apply.xpm
deleted file mode 100644
index 09df84e..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Apply.xpm
+++ /dev/null
@@ -1,40 +0,0 @@
-/* XPM */
-static char * Apply_xpm[] = {
-"16 16 6 1",
-" c #E79DE79DE79D",
-". c #0000EFBE0000",
-"X c #0000FFFF0000",
-"o c #000000000000",
-"O c #FFFFFFFFFFFF",
-"+ c #00008A280000",
-" ",
-" ",
-" ",
-" ",
-" .... ",
-" .XXXXo ",
-" .XOXXXX+ ",
-" .XXXXXX+ ",
-" .XXXXXX+ ",
-" .XXXXXX+ ",
-" +XXXX+ ",
-" ++++ ",
-" ",
-" ",
-" ",
-" "};
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #4 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Chat.cc b/ecflow_4_0_7/view/src/libicon/icon_Chat.cc
deleted file mode 100644
index 514323d..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Chat.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #8 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 5 1",
-" c None",
-". c #E7E7E7",
-"+ c #000000",
-"@ c #CECECE",
-"# c #808080",
-"................",
-"...........++...",
-"..........+@@+..",
-".........+@@@+..",
-"........+@@@@@+.",
-"........+@@@@@+.",
-".........+@@@@+.",
-"..........+@@@+.",
-"...........+@#+.",
-"...++.....+@@+..",
-"..+@@+...+@@#+..",
-".+@@@@+.+@@#+...",
-"+#@@@@@+@@#+....",
-"+###@@@@##+.....",
-".++#####++......",
-"...+++++........"};
-static pixmap p("Chat",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Chat.xpm b/ecflow_4_0_7/view/src/libicon/icon_Chat.xpm
deleted file mode 100644
index 10b1aa5..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Chat.xpm
+++ /dev/null
@@ -1,39 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * Chat_xpm[] = {
-"16 16 5 1",
-" c #E7E7E7E7E7E7",
-". c #000000000000",
-"X c #CECECECECECE",
-"o c #7B7B7B7B7B7B",
-"O c #8C8C8C8C8C8C",
-" ",
-" .. ",
-" . . ",
-" .XX . ",
-" .XXXX . ",
-" .oXXX . ",
-" .oXX . ",
-" ..X . ",
-" .X . ",
-" .. . X. ",
-" . . . XX. ",
-" .XXXX. . XX. ",
-".oXXXX..XXX. ",
-".OOXXXXXXX. ",
-" ..oOoXX.. ",
-" ..... "};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Check.cc b/ecflow_4_0_7/view/src/libicon/icon_Check.cc
deleted file mode 100644
index 72d5092..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Check.cc
+++ /dev/null
@@ -1,71 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #5 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 35 1",
-" c None",
-". c #E7E7E7",
-"+ c #C1C1C1",
-"@ c #959595",
-"# c #CECECE",
-"$ c #808080",
-"% c #D6D6D6",
-"& c #7E7E7E",
-"* c #C5C5C5",
-"= c #D4D4D4",
-"- c #7A7A7A",
-"; c #DDDDDD",
-"> c #C6C6C6",
-", c #E5E5E5",
-"' c #A0A0A0",
-") c #AEAEAE",
-"! c #B3B3B3",
-"~ c #939393",
-"{ c #D2D2D2",
-"] c #9E9E9E",
-"^ c #DBDBDB",
-"/ c #DFDFDF",
-"( c #8B8B8B",
-"_ c #B5B5B5",
-": c #999999",
-"< c #B7B7B7",
-"[ c #DADADA",
-"} c #E1E1E1",
-"| c #767676",
-"1 c #D8D8D8",
-"2 c #C3C3C3",
-"3 c #B1B1B1",
-"4 c #AAAAAA",
-"5 c #828282",
-"6 c #B9B9B9",
-"................",
-".............+ at .",
-"............#$%.",
-"...........#&*..",
-"..........=-*...",
-".........;$>....",
-"........,').....",
-"........!~,.....",
-"{]*....=&^......",
-"/+(_...:<.......",
-"..[$>.;&}.......",
-"...#|12'........",
-"....345#........",
-"..../$(.........",
-".....6>.........",
-"................"};
-static pixmap p("Check",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Check.xpm b/ecflow_4_0_7/view/src/libicon/icon_Check.xpm
deleted file mode 100644
index 09f87d0..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Check.xpm
+++ /dev/null
@@ -1,69 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * icon_Check_xpm[] = {
-"16 16 35 1",
-" c None",
-". c #E7E7E7",
-"+ c #C1C1C1",
-"@ c #959595",
-"# c #CECECE",
-"$ c #808080",
-"% c #D6D6D6",
-"& c #7E7E7E",
-"* c #C5C5C5",
-"= c #D4D4D4",
-"- c #7A7A7A",
-"; c #DDDDDD",
-"> c #C6C6C6",
-", c #E5E5E5",
-"' c #A0A0A0",
-") c #AEAEAE",
-"! c #B3B3B3",
-"~ c #939393",
-"{ c #D2D2D2",
-"] c #9E9E9E",
-"^ c #DBDBDB",
-"/ c #DFDFDF",
-"( c #8B8B8B",
-"_ c #B5B5B5",
-": c #999999",
-"< c #B7B7B7",
-"[ c #DADADA",
-"} c #E1E1E1",
-"| c #767676",
-"1 c #D8D8D8",
-"2 c #C3C3C3",
-"3 c #B1B1B1",
-"4 c #AAAAAA",
-"5 c #828282",
-"6 c #B9B9B9",
-"................",
-".............+ at .",
-"............#$%.",
-"...........#&*..",
-"..........=-*...",
-".........;$>....",
-"........,').....",
-"........!~,.....",
-"{]*....=&^......",
-"/+(_...:<.......",
-"..[$>.;&}.......",
-"...#|12'........",
-"....345#........",
-"..../$(.........",
-".....6>.........",
-"................"};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Edit.cc b/ecflow_4_0_7/view/src/libicon/icon_Edit.cc
deleted file mode 100644
index e40ff98..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Edit.cc
+++ /dev/null
@@ -1,47 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #8 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 11 1",
-" c None",
-". c #E7E7E7",
-"+ c #000000",
-"@ c #5F5F5F",
-"# c #FFFFFF",
-"$ c #DFDFDF",
-"% c #FF0000",
-"& c #A0A09C",
-"* c #FFEB00",
-"= c #EDDA00",
-"- c #7B7B7B",
-".......++ at ......",
-"......@##+......",
-".....@##+.......",
-"....@##+#+$...%%",
-"...@##+###+..&%%",
-"..++++##..#+&*=&",
-"..+-###.##.&*=&.",
-"..+###.##.&*=&..",
-"...+####.&*=&+..",
-"....+##.&*=&#+..",
-".....+##+=&#+...",
-"......+#+&#+....",
-".......+##+.....",
-"......-+#+......",
-".....--++.......",
-"......++........"};
-static pixmap p("Edit",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Edit.xpm b/ecflow_4_0_7/view/src/libicon/icon_Edit.xpm
deleted file mode 100644
index 0576202..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Edit.xpm
+++ /dev/null
@@ -1,43 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * Edit_xpm[] = {
-"16 16 9 1",
-" c #E7E7E7E7E7E7",
-". c #000000000000",
-"X c #FFFFFFFFFFFF",
-"o c #CECECECECECE",
-"O c #8C8C8C8C8C8C",
-"+ c #FFFF73739494",
-"@ c #FFFFFFFF0000",
-"# c #BDBDB5B5B5B5",
-"$ c #FFFFCECE9C9C",
-" ... ",
-" .XXo. ..",
-" .XXoO. .+.",
-" .XXoO. . at . ",
-" .XXoO.O.... at . ",
-"...oO.O#.$. at . ",
-".OO..O#.$. at .$. ",
-".Oo.O#o.....$$..",
-" .Xo o .$$$$$$..",
-" .Xo ....$$$$..",
-" .Xo.Xo#......",
-" .Xoo#. ..",
-" ...o#. ",
-" .O#.#. ",
-" .#o.. ",
-" ... "};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Info.cc b/ecflow_4_0_7/view/src/libicon/icon_Info.cc
deleted file mode 100644
index 16391cf..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Info.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #8 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 4 1",
-" c None",
-". c #E7E7E7",
-"+ c #ABF0FF",
-"@ c #0000FF",
-"................",
-"................",
-".......+ at +......",
-".......@@@......",
-".......+ at +......",
-"................",
-"......@@@@......",
-".......@@@......",
-".......@@@......",
-".......@@@......",
-".......@@@......",
-".......@@@......",
-"......@@@@@.....",
-"................",
-"................",
-"................"};
-static pixmap p("Info",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Info.xpm b/ecflow_4_0_7/view/src/libicon/icon_Info.xpm
deleted file mode 100644
index 9c144a5..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Info.xpm
+++ /dev/null
@@ -1,39 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * Info_xpm[] = {
-"16 16 5 1",
-" c #E7E7E7E7E7E7",
-". c #00000000FFFF",
-"X c #BDBDB5B5B5B5",
-"o c #7B7B7B7B7B7B",
-"O c #8C8C8C8C8C8C",
-" ",
-" ",
-" .X ",
-" ...o ",
-" .O ",
-" o ",
-" .... ",
-" ...o ",
-" ...O ",
-" ...O ",
-" ...o ",
-" ...O ",
-" .....o ",
-" oOOOO ",
-" ",
-" "};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Jobstatus.cc b/ecflow_4_0_7/view/src/libicon/icon_Jobstatus.cc
deleted file mode 100644
index d344bd3..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Jobstatus.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #5 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 5 1",
-" c None",
-". c #000000",
-"+ c #0000FF",
-"@ c #00FF00",
-"# c #FF0000",
-"................",
-".+++++++@@@@###.",
-".+++++++@@@@###.",
-".+++++++@@@@###.",
-".+++++++@@@@###.",
-"................",
-".+++++++@@#####.",
-".+++++++@@#####.",
-".+++++++@@#####.",
-".+++++++@@#####.",
-"................",
-".+++++++++++###.",
-".+++++++++++###.",
-".+++++++++++###.",
-".+++++++++++###.",
-"................"};
-static pixmap p("Jobstatus",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Jobstatus.xpm b/ecflow_4_0_7/view/src/libicon/icon_Jobstatus.xpm
deleted file mode 100644
index 66471eb..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Jobstatus.xpm
+++ /dev/null
@@ -1,39 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * icon_Josstatus_xpm[] = {
-"16 16 5 1",
-" c None",
-". c #000000",
-"+ c #0000FF",
-"@ c #00FF00",
-"# c #FF0000",
-"................",
-".+++++++@@@@###.",
-".+++++++@@@@###.",
-".+++++++@@@@###.",
-".+++++++@@@@###.",
-"................",
-".+++++++@@#####.",
-".+++++++@@#####.",
-".+++++++@@#####.",
-".+++++++@@#####.",
-"................",
-".+++++++++++###.",
-".+++++++++++###.",
-".+++++++++++###.",
-".+++++++++++###.",
-"................"};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Josstatus3.xpm b/ecflow_4_0_7/view/src/libicon/icon_Josstatus3.xpm
deleted file mode 100644
index 66471eb..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Josstatus3.xpm
+++ /dev/null
@@ -1,39 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * icon_Josstatus_xpm[] = {
-"16 16 5 1",
-" c None",
-". c #000000",
-"+ c #0000FF",
-"@ c #00FF00",
-"# c #FF0000",
-"................",
-".+++++++@@@@###.",
-".+++++++@@@@###.",
-".+++++++@@@@###.",
-".+++++++@@@@###.",
-"................",
-".+++++++@@#####.",
-".+++++++@@#####.",
-".+++++++@@#####.",
-".+++++++@@#####.",
-"................",
-".+++++++++++###.",
-".+++++++++++###.",
-".+++++++++++###.",
-".+++++++++++###.",
-"................"};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Load.cc b/ecflow_4_0_7/view/src/libicon/icon_Load.cc
deleted file mode 100644
index fd904a4..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Load.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #5 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 4 1",
-" c #E7E7E7E7E7E7",
-". c #E5E5E5E5E5E5",
-"X c #000000000000",
-"o c #FFFFFFFFFFFF",
-" ",
-" ",
-" ...XXXXXXX ",
-" ..XXoooooX ",
-" .XoXoooooX ",
-" XXXXoooooX. ",
-" XooooooooX. ",
-" XooooooooX ",
-" XooooooooX ",
-" XooooooooX ",
-" XooooooooX ",
-" XooooooooX ",
-" XooooooooX ",
-" XXXXXXXXXX ",
-" ",
-" "};
-static pixmap p("Load",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Load.xpm b/ecflow_4_0_7/view/src/libicon/icon_Load.xpm
deleted file mode 100644
index 1e0d2c4..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Load.xpm
+++ /dev/null
@@ -1,38 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * Load_xpm[] = {
-"16 16 4 1",
-" c #E7E7E7E7E7E7",
-". c #E5E5E5E5E5E5",
-"X c #000000000000",
-"o c #FFFFFFFFFFFF",
-" ",
-" ",
-" ...XXXXXXX ",
-" ..XXoooooX ",
-" .XoXoooooX ",
-" XXXXoooooX. ",
-" XooooooooX. ",
-" XooooooooX ",
-" XooooooooX ",
-" XooooooooX ",
-" XooooooooX ",
-" XooooooooX ",
-" XooooooooX ",
-" XXXXXXXXXX ",
-" ",
-" "};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Manual.cc b/ecflow_4_0_7/view/src/libicon/icon_Manual.cc
deleted file mode 100644
index b7b898e..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Manual.cc
+++ /dev/null
@@ -1,56 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #5 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 20 1",
-" c #E7E7E7E7E7E7",
-". c #CECECECECECE",
-"X c #BDBDB5B5B5B5",
-"o c #94949C9C9C9C",
-"O c #73738C8C7B7B",
-"+ c #5A5A73736363",
-"@ c #42425A5A4A4A",
-"# c #EFEFC6C6CECE",
-"$ c #C6C69C9CA5A5",
-"% c #9C9C73737B7B",
-"& c #737342425252",
-"* c #7B7B7B7B7B7B",
-"= c #4A4A5A5A5A5A",
-"- c #52525A5A5A5A",
-"; c #84848C8C8C8C",
-": c #A5A584848C8C",
-"> c #B5B58C8C9494",
-", c #DEDEDEDEDEDE",
-"< c #A5A5A5A5A5A5",
-"1 c #A5A57B7B8484",
-" .XoO+@ ",
-"#$%& .XoO+@ ",
-"#$%& .X+O+@ .o*=",
-"#%%& .X-O+@ .;*-",
-"#%%& .X-O+@ X=;=",
-"#:%& .X=O+@ .@*=",
-"#:%& .X=O+@ .@*=",
-"#%%& .X+O+@ X@*-",
-"#*%& .X;;+@ .-*=",
-"#>%& .X;O+@ .;*=",
-"#>%& .XoO+@ .o*=",
-"#$%& .XoO+@,.<*=",
-"#$%& .XoO+@ .o*=",
-"#>%& .<;O+@ .;*=",
-"#1%& .XOO+@ .+*=",
-"#:%& .Xo;+@,.;*="};
-static pixmap p("Manual",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Manual.xpm b/ecflow_4_0_7/view/src/libicon/icon_Manual.xpm
deleted file mode 100644
index 62a20e0..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Manual.xpm
+++ /dev/null
@@ -1,54 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * Manual_xpm[] = {
-"16 16 20 1",
-" c #E7E7E7E7E7E7",
-". c #CECECECECECE",
-"X c #BDBDB5B5B5B5",
-"o c #94949C9C9C9C",
-"O c #73738C8C7B7B",
-"+ c #5A5A73736363",
-"@ c #42425A5A4A4A",
-"# c #EFEFC6C6CECE",
-"$ c #C6C69C9CA5A5",
-"% c #9C9C73737B7B",
-"& c #737342425252",
-"* c #7B7B7B7B7B7B",
-"= c #4A4A5A5A5A5A",
-"- c #52525A5A5A5A",
-"; c #84848C8C8C8C",
-": c #A5A584848C8C",
-"> c #B5B58C8C9494",
-", c #DEDEDEDEDEDE",
-"< c #A5A5A5A5A5A5",
-"1 c #A5A57B7B8484",
-" .XoO+@ ",
-"#$%& .XoO+@ ",
-"#$%& .X+O+@ .o*=",
-"#%%& .X-O+@ .;*-",
-"#%%& .X-O+@ X=;=",
-"#:%& .X=O+@ .@*=",
-"#:%& .X=O+@ .@*=",
-"#%%& .X+O+@ X@*-",
-"#*%& .X;;+@ .-*=",
-"#>%& .X;O+@ .;*=",
-"#>%& .XoO+@ .o*=",
-"#$%& .XoO+@,.<*=",
-"#$%& .XoO+@ .o*=",
-"#>%& .<;O+@ .;*=",
-"#1%& .XOO+@ .+*=",
-"#:%& .Xo;+@,.;*="};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Merge.cc b/ecflow_4_0_7/view/src/libicon/icon_Merge.cc
deleted file mode 100644
index 4e13d48..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Merge.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #5 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 4 1",
-" c #FFFFFFFFFFFF",
-". c #E7E7E7E7E7E7",
-"X c #E5E5E5E5E5E5",
-"o c #000000000000",
-" ...............",
-" ...XXXooooooo..",
-" ...XXoo o..",
-" .XXXoooooo o..",
-" .XXoo o oX.",
-" .Xo o o oX.",
-" .oooo o o..",
-" .o o o..",
-" .o o o..",
-" .o o o..",
-" .o o o..",
-" .o o o..",
-" .o oooo..",
-" .o o.....",
-" ..oooooooo.....",
-" "};
-static pixmap p("Merge",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Merge.xpm b/ecflow_4_0_7/view/src/libicon/icon_Merge.xpm
deleted file mode 100644
index 212eea1..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Merge.xpm
+++ /dev/null
@@ -1,38 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * Merge_xpm[] = {
-"16 16 4 1",
-" c #FFFFFFFFFFFF",
-". c #E7E7E7E7E7E7",
-"X c #E5E5E5E5E5E5",
-"o c #000000000000",
-" ...............",
-" ...XXXooooooo..",
-" ...XXoo o..",
-" .XXXoooooo o..",
-" .XXoo o oX.",
-" .Xo o o oX.",
-" .oooo o o..",
-" .o o o..",
-" .o o o..",
-" .o o o..",
-" .o o o..",
-" .o o o..",
-" .o oooo..",
-" .o o.....",
-" ..oooooooo.....",
-" "};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Messages.cc b/ecflow_4_0_7/view/src/libicon/icon_Messages.cc
deleted file mode 100644
index 2058e8d..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Messages.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #8 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 4 1",
-" c None",
-". c #E5E5E5",
-"+ c #000000",
-"@ c #F5F97A",
-"................",
-"................",
-"................",
-"..+++++++++++...",
-"..+@@@@@@@@@+...",
-"..+@@@@@@@@@+...",
-"..+@@@@@@@@@+...",
-"..+@@@@@@@@@+...",
-"..+@@@@@@@@@+...",
-"..+@@@@@@@@@+...",
-"..+@@@@@+++++...",
-"..+@@@@@+@@+....",
-"..+@@@@@+ at +.....",
-"..++++++++......",
-"................",
-"................"};
-static pixmap p("Messages",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Messages.xpm b/ecflow_4_0_7/view/src/libicon/icon_Messages.xpm
deleted file mode 100644
index dffbc2f..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Messages.xpm
+++ /dev/null
@@ -1,41 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * message_xpm[] = {
-"16 16 7 1",
-" c #E5E5E5E5E5E5",
-". c #000000000000",
-"X c #C9C9CDCD4C4C",
-"o c #FFFFFFFFFFFF",
-"O c #F5F5F9F97A7A",
-"+ c #545454545454",
-"@ c #98989B9B3838",
-" ",
-" ",
-" ",
-" ........... ",
-" .XXXXXXXXX. ",
-" .XXXXXXXXX. ",
-" .oOOOOOOOO. ",
-" .oOOOOOOOO. ",
-" .oOOOOOOOO. ",
-" .oOOOOOOOO. ",
-" .oOOOX..... ",
-" .oOOXX+OO. ",
-" .oXXX.O at + ",
-" .....++ ",
-" ",
-" "};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Output.cc b/ecflow_4_0_7/view/src/libicon/icon_Output.cc
deleted file mode 100644
index 56eca3f..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Output.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #8 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 9 1",
-" c None",
-". c #E7E7E7",
-"+ c #7B7B7B",
-"@ c #000000",
-"# c #CECECE",
-"$ c #DEDEDE",
-"% c #A5A5A5",
-"& c #BDB5B5",
-"* c #949C9C",
-".++++++++++++++.",
-".+............+.",
-".+............+.",
-".+.@#$%%#%%&@.+.",
-".+....##.$$...+.",
-".+.@##%%#..#@.+.",
-".+....$$......+.",
-".+.@#..#$$$#@.+.",
-".+....$%**%#..+.",
-".+.@#..$$$##@.+.",
-".+....$#..$...+.",
-".+.@#$%%$$&&@.+.",
-".+....##$#$...+.",
-".+.@#.$%*%$#@.+.",
-".+............+.",
-".++++++++++++++."};
-static pixmap p("Output",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Output.xpm b/ecflow_4_0_7/view/src/libicon/icon_Output.xpm
deleted file mode 100644
index 5b811c2..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Output.xpm
+++ /dev/null
@@ -1,42 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * Output_xpm[] = {
-"16 16 8 1",
-" c #E7E7E7E7E7E7",
-". c #7B7B7B7B7B7B",
-"X c #CECECECECECE",
-"o c #DEDEDEDEDEDE",
-"O c #000000000000",
-"+ c #A5A5A5A5A5A5",
-"@ c #BDBDB5B5B5B5",
-"# c #94949C9C9C9C",
-" .............. ",
-" . XXXXXXXX . ",
-" . Xo Xo . ",
-" . OXo++X++ at O . ",
-" . XX oo . ",
-" . OXX++X XO . ",
-" . oo . ",
-" . OX XoooXO . ",
-" . o+##+X . ",
-" . OX oooXXO . ",
-" . oX o . ",
-" . OXo++oo@@O . ",
-" . XXoXo . ",
-" . OX o+#+oXO . ",
-" . XXX@@@XX . ",
-" .............. "};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_QuickFind.cc b/ecflow_4_0_7/view/src/libicon/icon_QuickFind.cc
deleted file mode 100644
index 5f664ce..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_QuickFind.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #5 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 2 1",
-" c #E7E7E7E7E7E7",
-". c #000000000000",
-" ",
-" ",
-" ",
-" ",
-" ........ ",
-" ........ ",
-" ...... ",
-" ...... ",
-" .... ",
-" .... ",
-" .. ",
-" .. ",
-" ",
-" ",
-" ",
-" "};
-static pixmap p("QuickFind",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_QuickFind.xpm b/ecflow_4_0_7/view/src/libicon/icon_QuickFind.xpm
deleted file mode 100644
index 8ae9918..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_QuickFind.xpm
+++ /dev/null
@@ -1,36 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * QuickFind_xpm[] = {
-"16 16 2 1",
-" c #E7E7E7E7E7E7",
-". c #000000000000",
-" ",
-" ",
-" ",
-" ",
-" ........ ",
-" ........ ",
-" ...... ",
-" ...... ",
-" .... ",
-" .... ",
-" .. ",
-" .. ",
-" ",
-" ",
-" ",
-" "};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Script.cc b/ecflow_4_0_7/view/src/libicon/icon_Script.cc
deleted file mode 100644
index 519e807..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Script.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #8 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 7 1",
-" c None",
-". c #E7E7E7",
-"+ c #000000",
-"@ c #5F5F5F",
-"# c #FFFFFF",
-"$ c #DFDFDF",
-"% c #7B7B7B",
-".......++ at ......",
-"......@##+......",
-".....@##+.......",
-"....@##+#+$.....",
-"...@##+###+.....",
-"..++++##..#+....",
-"..+%###.##.#+...",
-"..+###.##.###+..",
-"...+####.##.#+..",
-"....+##.##.##+..",
-".....+###.##+...",
-"......+#.##+....",
-".......+##+.....",
-"......%+#+......",
-".....%%++.......",
-"......++........"};
-static pixmap p("Script",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Script.xpm b/ecflow_4_0_7/view/src/libicon/icon_Script.xpm
deleted file mode 100644
index 9dc7aec..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Script.xpm
+++ /dev/null
@@ -1,41 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * Script_xpm[] = {
-"16 16 7 1",
-" c #E79DE79DE79D",
-". c #DF7DDF7DDF7D",
-"X c #000000000000",
-"o c #FFFFFFFFFFFF",
-"O c #CF3CCF3CFFFF",
-"+ c #8A288A288A28",
-"@ c #AAAAAAAAAAAA",
-" .XXX. ",
-" .XooOX ",
-" .XooO+X ",
-" .XooO+X. ",
-" .XooO+X+X. ",
-" XXXO+X++ at X. ",
-" X++XX++O. at X. ",
-" X+OXO+O.Oo+X ",
-" XoO.O.OoO at X ",
-" XoO.OoOO at X ",
-" XoOoOO at X ",
-" XoOO at X ",
-" XXXO at X ",
-" X+ at X@X ",
-" X at OXX ",
-" XXX "};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Search.cc b/ecflow_4_0_7/view/src/libicon/icon_Search.cc
deleted file mode 100644
index 8c3c228..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Search.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #8 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 13 1",
-" c None",
-". c #E7E7E7",
-"+ c #7B7B7B",
-"@ c #000000",
-"# c #4A4239",
-"$ c #8C8C8C",
-"% c #FFFFFF",
-"& c #CECECE",
-"* c #BDB5B5",
-"= c #E8E8E8",
-"- c #C9C7C7",
-"; c #8C5A39",
-"> c #FFCE9C",
-"................",
-"................",
-"....+@##$.......",
-"...++%%%++......",
-"...#%%%%%+&.....",
-"..*+%%%%=+*.....",
-"..*+%%%=-+*.....",
-"...#%===-+&.....",
-"...$#---+$......",
-"....$@#@++*.....",
-".........;;>....",
-"..........;;>...",
-"...........;;*..",
-"............;;..",
-".............&..",
-"................"};
-static pixmap p("Search",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Search.xpm b/ecflow_4_0_7/view/src/libicon/icon_Search.xpm
deleted file mode 100644
index 5ada9e7..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Search.xpm
+++ /dev/null
@@ -1,45 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * Search_xpm[] = {
-"16 16 11 1",
-" c #E7E7E7E7E7E7",
-". c #7B7B7B7B7B7B",
-"X c #000000000000",
-"o c #4A4A42423939",
-"O c #8C8C8C8C8C8C",
-"+ c #BDBDB5B5B5B5",
-"@ c #CECECECECECE",
-"# c #F7F7EFEFDEDE",
-"$ c #FFFFFFFFFFFF",
-"% c #8C8C5A5A3939",
-"& c #FFFFCECE9C9C",
-" ",
-" ",
-" .XooO ",
-" ..+@@.. ",
-" oO++ .@ ",
-" +.#+@@$.+ ",
-" +.$ @@$.+ ",
-" o $$$@.@ ",
-" Oo+ at +.O ",
-" OXoX..+ ",
-" %%& ",
-" # %%& ",
-" %%+ ",
-" $O& ",
-" #@# ",
-" "};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Status.cc b/ecflow_4_0_7/view/src/libicon/icon_Status.cc
deleted file mode 100644
index a9140a7..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Status.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #5 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 14 1",
-" c #E7E7E7E7E7E7",
-". c #FFFFFFFFFFFF",
-"X c #FFFFCECE9C9C",
-"o c #FFFF73739494",
-"O c #FFFF29292929",
-"+ c #FFFF00000000",
-"@ c #8C8C5A5A3939",
-"# c #CECECECECECE",
-"$ c #8C8C8C8C8C8C",
-"% c #F7F7EFEFDEDE",
-"& c #000000000000",
-"* c #4A4A42423939",
-"= c #BDBDB5B5B5B5",
-"- c #7B7B7B7B7B7B",
-" ",
-" .XoX ",
-" XO++@# ",
-" X+++++$ ",
-" %++++O&$ ",
-" o+++**$ .o% ",
-"%+++** o+O ",
-" +++*# ++++o ",
-"%O++* +++++++",
-".+++ at . X+++*$",
-" o+++= O++@* ",
-" %O+++ooo++++&$ ",
-" X+++++++++** ",
-" oO++++++**= ",
-" =@@+****# ",
-" .=$-$=. "};
-static pixmap p("Status",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Status.xpm b/ecflow_4_0_7/view/src/libicon/icon_Status.xpm
deleted file mode 100644
index e66705d..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Status.xpm
+++ /dev/null
@@ -1,48 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * Status_xpm[] = {
-"16 16 14 1",
-" c #E7E7E7E7E7E7",
-". c #FFFFFFFFFFFF",
-"X c #FFFFCECE9C9C",
-"o c #FFFF73739494",
-"O c #FFFF29292929",
-"+ c #FFFF00000000",
-"@ c #8C8C5A5A3939",
-"# c #CECECECECECE",
-"$ c #8C8C8C8C8C8C",
-"% c #F7F7EFEFDEDE",
-"& c #000000000000",
-"* c #4A4A42423939",
-"= c #BDBDB5B5B5B5",
-"- c #7B7B7B7B7B7B",
-" ",
-" .XoX ",
-" XO++@# ",
-" X+++++$ ",
-" %++++O&$ ",
-" o+++**$ .o% ",
-"%+++** o+O ",
-" +++*# ++++o ",
-"%O++* +++++++",
-".+++ at . X+++*$",
-" o+++= O++@* ",
-" %O+++ooo++++&$ ",
-" X+++++++++** ",
-" oO++++++**= ",
-" =@@+****# ",
-" .=$-$=. "};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Submit.cc b/ecflow_4_0_7/view/src/libicon/icon_Submit.cc
deleted file mode 100644
index 9251a93..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Submit.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #5 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 6 1",
-" c #E79DE79DE79D",
-". c #0000EFBE0000",
-"X c #0000FFFF0000",
-"o c #000000000000",
-"O c #FFFFFFFFFFFF",
-"+ c #00008A280000",
-" ",
-" ",
-" ",
-" ",
-" .... ",
-" .XXXXo ",
-" .XOXXXX+ ",
-" .XXXXXX+ ",
-" .XXXXXX+ ",
-" .XXXXXX+ ",
-" +XXXX+ ",
-" ++++ ",
-" ",
-" ",
-" ",
-" "};
-static pixmap p("Submit",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Submit.xpm b/ecflow_4_0_7/view/src/libicon/icon_Submit.xpm
deleted file mode 100644
index 6bda407..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Submit.xpm
+++ /dev/null
@@ -1,40 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-* XPM */
-static char * Submit_xpm[] = {
-"16 16 6 1",
-" c #E79DE79DE79D",
-". c #0000EFBE0000",
-"X c #0000FFFF0000",
-"o c #000000000000",
-"O c #FFFFFFFFFFFF",
-"+ c #00008A280000",
-" ",
-" ",
-" ",
-" ",
-" .... ",
-" .XXXXo ",
-" .XOXXXX+ ",
-" .XXXXXX+ ",
-" .XXXXXX+ ",
-" .XXXXXX+ ",
-" +XXXX+ ",
-" ++++ ",
-" ",
-" ",
-" ",
-" "};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Time_line.cc b/ecflow_4_0_7/view/src/libicon/icon_Time_line.cc
deleted file mode 100644
index e83043a..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Time_line.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #8 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 6 1",
-" c None",
-". c #E5E5E5",
-"+ c #888888",
-"@ c #000000",
-"# c #CCCCCC",
-"$ c #837B7B",
-"................",
-"....+@@@@@+.....",
-"...@@#####@@....",
-"..@####@####@...",
-".+@####@####@+..",
-".@#####@#####@..",
-".@#####@#####@..",
-".@#$###@###$#@..",
-".@######@####@..",
-".@#######@###@..",
-".+@#########@+..",
-"..@####$####@...",
-"...@@#####@@....",
-"....+@@@@@+.....",
-"................",
-"................"};
-static pixmap p("Time_line",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Time_line.xpm b/ecflow_4_0_7/view/src/libicon/icon_Time_line.xpm
deleted file mode 100644
index 5fb6e28..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Time_line.xpm
+++ /dev/null
@@ -1,40 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * clock_xpm[] = {
-"16 16 6 1",
-" c #E5E5E5E5E5E5",
-". c #888888888888",
-"X c #000000000000",
-"o c #CCCCCCCCCCCC",
-"O c #FFFFFFFFFFFF",
-"+ c #444444444444",
-" ",
-" .XXXXX. ",
-" XXoooooXX ",
-" XoooOXOoOoX ",
-" .XooOOXOOoOX. ",
-" XooOOOXOOOoOX ",
-" XoOOOoXoOoOoX ",
-" Xo+OoOXOoO+OX ",
-" XoOOOoOXOoOoX ",
-" XooOoOoOXOoOX ",
-" .XoOOoOoOoOX. ",
-" XooOO+OoOOX ",
-" XXooOoOXX ",
-" .XXXXX. ",
-" ",
-" "};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Triggers.cc b/ecflow_4_0_7/view/src/libicon/icon_Triggers.cc
deleted file mode 100644
index 807b45b..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Triggers.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #5 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 3 1",
-" c #E7E7E7E7E7E7",
-". c #FFFFFFFFFFFF",
-"X c #7B7B7B7B7B7B",
-" ......X ",
-" . X ",
-" . X ",
-" .XXXXXX ",
-" X ",
-" X ",
-" X ",
-" X ",
-" XXXXXXXXXX ",
-" X X ",
-" X X ",
-" X X ",
-" .....X .....X ",
-" . X . X ",
-" . X . X ",
-" .XXXXX .XXXXX "};
-static pixmap p("Triggers",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Triggers.xpm b/ecflow_4_0_7/view/src/libicon/icon_Triggers.xpm
deleted file mode 100644
index 28b7457..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Triggers.xpm
+++ /dev/null
@@ -1,37 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * Triggers_xpm[] = {
-"16 16 3 1",
-" c #E7E7E7E7E7E7",
-". c #FFFFFFFFFFFF",
-"X c #7B7B7B7B7B7B",
-" ......X ",
-" . X ",
-" . X ",
-" .XXXXXX ",
-" X ",
-" X ",
-" X ",
-" X ",
-" XXXXXXXXXX ",
-" X X ",
-" X X ",
-" X X ",
-" .....X .....X ",
-" . X . X ",
-" . X . X ",
-" .XXXXX .XXXXX "};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Update.cc b/ecflow_4_0_7/view/src/libicon/icon_Update.cc
deleted file mode 100644
index 0840f0c..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Update.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #5 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 14 1",
-" c #E7E7E7E7E7E7",
-". c #FFFFFFFFFFFF",
-"X c #FFFFCECE9C9C",
-"o c #FFFF73739494",
-"O c #FFFF29292929",
-"+ c #FFFF00000000",
-"@ c #8C8C5A5A3939",
-"# c #CECECECECECE",
-"$ c #8C8C8C8C8C8C",
-"% c #F7F7EFEFDEDE",
-"& c #000000000000",
-"* c #4A4A42423939",
-"= c #BDBDB5B5B5B5",
-"- c #7B7B7B7B7B7B",
-" ",
-" .XoX ",
-" XO++@# ",
-" X+++++$ ",
-" %++++O&$ ",
-" o+++**$ .o% ",
-"%+++** o+O ",
-" +++*# ++++o ",
-"%O++* +++++++",
-".+++ at . X+++*$",
-" o+++= O++@* ",
-" %O+++ooo++++&$ ",
-" X+++++++++** ",
-" oO++++++**= ",
-" =@@+****# ",
-" .=$-$=. "};
-static pixmap p("Update",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Update.xpm b/ecflow_4_0_7/view/src/libicon/icon_Update.xpm
deleted file mode 100644
index e66705d..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Update.xpm
+++ /dev/null
@@ -1,48 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * Status_xpm[] = {
-"16 16 14 1",
-" c #E7E7E7E7E7E7",
-". c #FFFFFFFFFFFF",
-"X c #FFFFCECE9C9C",
-"o c #FFFF73739494",
-"O c #FFFF29292929",
-"+ c #FFFF00000000",
-"@ c #8C8C5A5A3939",
-"# c #CECECECECECE",
-"$ c #8C8C8C8C8C8C",
-"% c #F7F7EFEFDEDE",
-"& c #000000000000",
-"* c #4A4A42423939",
-"= c #BDBDB5B5B5B5",
-"- c #7B7B7B7B7B7B",
-" ",
-" .XoX ",
-" XO++@# ",
-" X+++++$ ",
-" %++++O&$ ",
-" o+++**$ .o% ",
-"%+++** o+O ",
-" +++*# ++++o ",
-"%O++* +++++++",
-".+++ at . X+++*$",
-" o+++= O++@* ",
-" %O+++ooo++++&$ ",
-" X+++++++++** ",
-" oO++++++**= ",
-" =@@+****# ",
-" .=$-$=. "};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Use_external_editor.cc b/ecflow_4_0_7/view/src/libicon/icon_Use_external_editor.cc
deleted file mode 100644
index 62e7ae4..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Use_external_editor.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #8 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 7 1",
-" c None",
-". c #E5E5E5",
-"+ c #000000",
-"@ c #FF0505",
-"# c #A9A9A9",
-"$ c #FFFFFF",
-"% c #D3D3D3",
-"................",
-"................",
-"..........++....",
-".........+@@+...",
-".........+#@+...",
-"........+$#+....",
-"........+%#+....",
-".......+$#+.....",
-".......+%#+.....",
-"......+$#+......",
-"......+%#+......",
-".....+%#+.......",
-".....+##+.......",
-".....+#+........",
-".....++.........",
-"................"};
-static pixmap p("Use_external_editor",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Use_external_editor.xpm b/ecflow_4_0_7/view/src/libicon/icon_Use_external_editor.xpm
deleted file mode 100644
index c0edf3e..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Use_external_editor.xpm
+++ /dev/null
@@ -1,43 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * pen_xpm[] = {
-"16 16 9 1",
-" c #E5E5E5E5E5E5",
-". c #000000000000",
-"X c #FFFF6666CCCC",
-"o c #999966669999",
-"O c #FFFFFFFFCCCC",
-"+ c #FFFFCCCC9999",
-"@ c #FFFF66663333",
-"# c #AAAAAAAAAAAA",
-"$ c #555555555555",
-" ",
-" ",
-" .. ",
-" .XX. ",
-" ..o. ",
-" .O.. ",
-" .+ at . ",
-" .O at . ",
-" .+ at . ",
-" .O at . ",
-" .+ at . ",
-" ... ",
-" .. ",
-"#o$o$#. ",
-" ",
-" "};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Use_external_viewer.cc b/ecflow_4_0_7/view/src/libicon/icon_Use_external_viewer.cc
deleted file mode 100644
index 91e5cd7..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Use_external_viewer.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #8 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 6 1",
-" c None",
-". c #E5E5E5",
-"+ c #000000",
-"@ c #FFFFFF",
-"# c #DED9D9",
-"$ c #CAC6C6",
-"................",
-"................",
-"................",
-"................",
-"....++.......++.",
-"...+..+.....+..+",
-"..+........+....",
-".+++...++++.....",
-"+@##+.+@##+.....",
-"+##$+++##$+.....",
-"+#$$+.+#$$+.....",
-".+++...+++......",
-"................",
-"................",
-"................",
-"................"};
-static pixmap p("Use_external_viewer",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Use_external_viewer.xpm b/ecflow_4_0_7/view/src/libicon/icon_Use_external_viewer.xpm
deleted file mode 100644
index a55da81..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Use_external_viewer.xpm
+++ /dev/null
@@ -1,40 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * viewer_xpm[] = {
-"16 16 6 1",
-" c #E5E5E5E5E5E5",
-". c #000000000000",
-"X c #FFFFFFFFFFFF",
-"o c #CCCCCCCCFFFF",
-"O c #66666666CCCC",
-"+ c #99999999FFFF",
-" ",
-" ",
-" ",
-" ",
-" .. .. ",
-" . . . .",
-" . . . .",
-" ... .... ",
-".XoO. .XoO. ",
-".oX+...oX+. ",
-".O++. .O++. ",
-" ... ... ",
-" ",
-" ",
-" ",
-" "};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Variables.cc b/ecflow_4_0_7/view/src/libicon/icon_Variables.cc
deleted file mode 100644
index 0ef2e06..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Variables.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #5 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 2 1",
-" c #E7E7E7E7E7E7",
-". c #000000000000",
-" ",
-" ",
-" ",
-" ",
-" ",
-" .. .. ",
-" . . . ",
-" . . .... . ",
-" .... . ",
-" . . .... . ",
-" . . ... ",
-" ",
-" ",
-" ",
-" ",
-" "};
-static pixmap p("Variables",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Variables.xpm b/ecflow_4_0_7/view/src/libicon/icon_Variables.xpm
deleted file mode 100644
index 770591d..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Variables.xpm
+++ /dev/null
@@ -1,36 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * Variables_xpm[] = {
-"16 16 2 1",
-" c #E7E7E7E7E7E7",
-". c #000000000000",
-" ",
-" ",
-" ",
-" ",
-" ",
-" .. .. ",
-" . . . ",
-" . . .... . ",
-" .... . ",
-" . . .... . ",
-" . . ... ",
-" ",
-" ",
-" ",
-" ",
-" "};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_W.xpm b/ecflow_4_0_7/view/src/libicon/icon_W.xpm
deleted file mode 100644
index 53a05fb..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_W.xpm
+++ /dev/null
@@ -1,84 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * icon_W_xpm[] = {
-"16 16 50 1",
-" c None",
-". c #E7E7E7",
-"+ c #E7E3E3",
-"@ c #E9CDCD",
-"# c #EEA3A3",
-"$ c #FF0000",
-"% c #FA2A2A",
-"& c #F64E4E",
-"* c #F93434",
-"= c #FB1C1C",
-"- c #F46464",
-"; c #FD0E0E",
-"> c #EDA9A9",
-", c #E8D7D7",
-"' c #FB2222",
-") c #FE0606",
-"! c #ECB5B5",
-"~ c #FA2727",
-"{ c #EDABAB",
-"] c #F83E3E",
-"^ c #EF9494",
-"/ c #E7E5E5",
-"( c #EE9F9F",
-"_ c #F36D6D",
-": c #F08D8D",
-"< c #F74646",
-"[ c #ECB0B0",
-"} c #FE0404",
-"| c #FA2828",
-"1 c #E8DBDB",
-"2 c #E9CACA",
-"3 c #FD1313",
-"4 c #FD1212",
-"5 c #EACACA",
-"6 c #E7E6E6",
-"7 c #F65555",
-"8 c #E7DFDF",
-"9 c #E8DCDC",
-"0 c #FA2929",
-"a c #ECAFAF",
-"b c #F18484",
-"c c #F74949",
-"d c #E7E0E0",
-"e c #F27D7D",
-"f c #FE0101",
-"g c #F46868",
-"h c #F93939",
-"i c #F93131",
-"j c #FD0B0B",
-"k c #EDA6A6",
-"................",
-"................",
-"....+@@@@@@@@...",
-"....#$$%&*$$=...",
-"....-;>.,'$)!...",
-"....~{.+]$$^....",
-".../(..-$$_.....",
-"......:$$</.....",
-".....[}$|1......",
-"....23$45.678...",
-"...90$}a..b0....",
-"...c$$:.defg....",
-"...$$)hij$$k....",
-"................",
-"................",
-"................"};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Why_.cc b/ecflow_4_0_7/view/src/libicon/icon_Why_.cc
deleted file mode 100644
index fadb700..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Why_.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #5 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 6 1",
-" c #E7E7E7E7E7E7",
-". c #BDBDB5B5B5B5",
-"X c #4A4A42423939",
-"o c #7B7B7B7B7B7B",
-"O c #CECECECECECE",
-"+ c #8C8C8C8C8C8C",
-" ",
-" ",
-" ",
-" .XXXo ",
-" .XO XO ",
-" o. o+ ",
-" . .X ",
-" .XO ",
-" .XO ",
-" XO ",
-" .o ",
-" ",
-" .O ",
-" o. ",
-" ",
-" "};
-static pixmap p("Why_",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Z.cc b/ecflow_4_0_7/view/src/libicon/icon_Z.cc
deleted file mode 100644
index bebc1bd..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_Z.cc
+++ /dev/null
@@ -1,86 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 50 1",
-" c None",
-". c #E7E7E7",
-"+ c #E7E3E3",
-"@ c #E9CDCD",
-"# c #EEA3A3",
-"$ c #FF0000",
-"% c #FA2A2A",
-"& c #F64E4E",
-"* c #F93434",
-"= c #FB1C1C",
-"- c #F46464",
-"; c #FD0E0E",
-"> c #EDA9A9",
-", c #E8D7D7",
-"' c #FB2222",
-") c #FE0606",
-"! c #ECB5B5",
-"~ c #FA2727",
-"{ c #EDABAB",
-"] c #F83E3E",
-"^ c #EF9494",
-"/ c #E7E5E5",
-"( c #EE9F9F",
-"_ c #F36D6D",
-": c #F08D8D",
-"< c #F74646",
-"[ c #ECB0B0",
-"} c #FE0404",
-"| c #FA2828",
-"1 c #E8DBDB",
-"2 c #E9CACA",
-"3 c #FD1313",
-"4 c #FD1212",
-"5 c #EACACA",
-"6 c #E7E6E6",
-"7 c #F65555",
-"8 c #E7DFDF",
-"9 c #E8DCDC",
-"0 c #FA2929",
-"a c #ECAFAF",
-"b c #F18484",
-"c c #F74949",
-"d c #E7E0E0",
-"e c #F27D7D",
-"f c #FE0101",
-"g c #F46868",
-"h c #F93939",
-"i c #F93131",
-"j c #FD0B0B",
-"k c #EDA6A6",
-"................",
-"................",
-"....+@@@@@@@@...",
-"....#$$%&*$$=...",
-"....-;>.,'$)!...",
-"....~{.+]$$^....",
-".../(..-$$_.....",
-"......:$$</.....",
-".....[}$|1......",
-"....23$45.678...",
-"...90$}a..b0....",
-"...c$$:.defg....",
-"...$$)hij$$k....",
-"................",
-"................",
-"................"};
-static pixmap p("Z",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_calendar.cc b/ecflow_4_0_7/view/src/libicon/icon_calendar.cc
deleted file mode 100644
index f03c4d5..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_calendar.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 4 1",
-" c None",
-". c #E7E7E7",
-"+ c #000000",
-"@ c #F7FB79",
-"................",
-"..++++++++++++..",
-"..+@@@@@@@@@@+..",
-"..+@@@@@@@@@@+..",
-"..+@@@@@@@@@@+..",
-"..+@@@@++@@@@+..",
-"..+@@@+++@@@@+..",
-"..+@@@@++@@@@+..",
-"..+@@@@++@@@@+..",
-"..+@@@@++@@@@+..",
-"..+@@@@++@@@@+..",
-"..+@@@++++@@@+..",
-"..+@@@@@@@@@@+..",
-"...+@@@@@@@@@+..",
-"....++++++++++..",
-"................"};
-static pixmap p("calendar",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_calendar.xpm b/ecflow_4_0_7/view/src/libicon/icon_calendar.xpm
deleted file mode 100644
index 08e4401..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_calendar.xpm
+++ /dev/null
@@ -1,38 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * calendar_xpm[] = {
-"16 16 4 1",
-" c #E79DE79DE79D",
-". c #AAAAAAAAAAAA",
-"X c #000000000000",
-"o c #F7DEFBEE79E7",
-" ",
-" .......... ",
-" XXXXXXXXXX. ",
-" XooooooooX. ",
-" XooooooooX. ",
-" XooooXoooX. ",
-" XooXXXoooX. ",
-" XoooXXoooX. ",
-" XoooXXoooX. ",
-" XoooXXoooX. ",
-" XoooXXoooX. ",
-" XooXXXXooX. ",
-" XooooooooX. ",
-" XoooooooX. ",
-" XXXXXXXX ",
-" "};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_clock.cc b/ecflow_4_0_7/view/src/libicon/icon_clock.cc
deleted file mode 100644
index e962a11..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_clock.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 6 1",
-" c None",
-". c #E5E5E5",
-"+ c #888888",
-"@ c #000000",
-"# c #CCCCCC",
-"$ c #837B7B",
-"................",
-"....+@@@@@+.....",
-"...@@#####@@....",
-"..@####@####@...",
-".+@####@####@+..",
-".@#####@#####@..",
-".@#####@#####@..",
-".@#$###@###$#@..",
-".@######@####@..",
-".@#######@###@..",
-".+@#########@+..",
-"..@####$####@...",
-"...@@#####@@....",
-"....+@@@@@+.....",
-"................",
-"................"};
-static pixmap p("clock",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_clock.xpm b/ecflow_4_0_7/view/src/libicon/icon_clock.xpm
deleted file mode 100644
index 452f5d4..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_clock.xpm
+++ /dev/null
@@ -1,40 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * clock_xpm[] = {
-"16 16 6 1",
-" c #E5E5E5E5E5E5",
-". c #888888888888",
-"X c #000000000000",
-"o c #CCCCCCCCCCCC",
-"O c #FFFFFFFFFFFF",
-"+ c #444444444444",
-" ",
-" .XXXXX. ",
-" XXoooooXX ",
-" XoooOXOoOoX ",
-" .XooOOXOOoOX. ",
-" XooOOOXOOOoOX ",
-" XoOOOoXoOoOoX ",
-" Xo+OoOXOoO+OX ",
-" XoOOOoOXOoOoX ",
-" XooOoOoOXOoOX ",
-" .XoOOoOoOoOX. ",
-" XooOO+OoOOX ",
-" XXooOoOXX ",
-" .XXXXX. ",
-" ",
-" "};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_clock_free.cc b/ecflow_4_0_7/view/src/libicon/icon_clock_free.cc
deleted file mode 100644
index 6b1acca..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_clock_free.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 6 1",
-" c None",
-". c #E5E5E5",
-"+ c #888888",
-"@ c #000000",
-"# c #F7FB79",
-"$ c #837B7B",
-"................",
-"....+@@@@@+.....",
-"...@@#####@@....",
-"..@####@####@...",
-".+@####@####@+..",
-".@#####@#####@..",
-".@#####@#####@..",
-".@#$###@###$#@..",
-".@######@####@..",
-".@#######@###@..",
-".+@#########@+..",
-"..@####$####@...",
-"...@@#####@@....",
-"....+@@@@@+.....",
-"................",
-"................"};
-static pixmap p("clock_free",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_complete.cc b/ecflow_4_0_7/view/src/libicon/icon_complete.cc
deleted file mode 100644
index 042a666..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_complete.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-/*
-static char * bits[] = {
-"16 16 2 1",
-" c #E7E7E7E7E7E7",
-". c #000000000000",
-" ... ... . . ",
-". .. ... .. ",
-". . .. . . ",
-". . .. . ",
-". .. .. . ",
-" ... ... . . ",
-".... . .... ",
-". . . . ",
-".... . ... ",
-". . . ",
-". .... .... ",
-"..... .... ",
-" . . ",
-" . ... ",
-" . . ",
-" . .... "};
-*/
-static const char * bits[] = {
-"16 16 3 1",
-" c #E5E5E5E5E5E5",
-". c #FFFFFF",
-"# c #FF0000",
-" ...... ",
-" ..######.. ",
-" .##########. ",
-" .############. ",
-" .############. ",
-".##############.",
-".##############.",
-".#............#.",
-".#............#.",
-".##############.",
-".##############.",
-" .############. ",
-" .############. ",
-" .##########. ",
-" ..######.. ",
-" ...... "};
-
-
-
-
-static pixmap p("complete",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_complete.xpm b/ecflow_4_0_7/view/src/libicon/icon_complete.xpm
deleted file mode 100644
index 4d70781..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_complete.xpm
+++ /dev/null
@@ -1,57 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-/*
-static char * complete_xpm[] = {
-"16 16 2 1",
-" c #E7E7E7E7E7E7",
-". c #000000000000",
-" ... ... . . ",
-". .. ... .. ",
-". . .. . . ",
-". . .. . ",
-". .. .. . ",
-" ... ... . . ",
-".... . .... ",
-". . . . ",
-".... . ... ",
-". . . ",
-". .... .... ",
-"..... .... "," . . ",
-" . ... ",
-" . . ",
-" . .... "};
-*/
-static char * icon_complete_xpm[] = {
-"16 16 5 1",
-" c None",
-". c #FFFFFF",
-"+ c #0000FF",
-"@ c #00FF00",
-"# c #FF0000",
-" ........ "
-" .########. "
-" .##########. "
-".##..#...###...."
-".#.##.#.#....#..#"
-".#.####.#.#....."
-".###.##.#.#..##."
-".#.##.#.#.#..##."
-" .#..##.#....#. "
-" .#########. "
-" ........ "};
-
-
diff --git a/ecflow_4_0_7/view/src/libicon/icon_defstatus.cc b/ecflow_4_0_7/view/src/libicon/icon_defstatus.cc
deleted file mode 100644
index ca39e0c..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_defstatus.cc
+++ /dev/null
@@ -1,164 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 128 2",
-" c #E5E5E5",
-". c #D6D8BA",
-"+ c #C2BF70",
-"@ c #B6B04A",
-"# c #A89D12",
-"$ c #A89B12",
-"% c #E7E377",
-"& c #F3F489",
-"* c #F4F387",
-"= c #F4F484",
-"- c #F2F381",
-"; c #F0F37E",
-"> c #F0F37B",
-", c #EFF379",
-"' c #EFF376",
-") c #EDF373",
-"! c #EDF271",
-"~ c #E0E35F",
-"{ c #B7B14A",
-"] c #F1F58F",
-"^ c #ECF277",
-"/ c #E3EE5D",
-"( c #E2ED5C",
-"_ c #E1EC5B",
-": c #DFEA59",
-"< c #DDE858",
-"[ c #DCE756",
-"} c #DAE654",
-"| c #D9E453",
-"1 c #E1EA64",
-"2 c #E9F274",
-"3 c #C7C46C",
-"4 c #F0F592",
-"5 c #E1EF66",
-"6 c #DFEE62",
-"7 c #F4F8CD",
-"8 c #E3EE78",
-"9 c #D6E852",
-"0 c #D5E651",
-"a c #DEE975",
-"b c #F2F6CB",
-"c c #D6E35C",
-"d c #D2E154",
-"e c #E6F278",
-"f c #C3C054",
-"g c #EEF491",
-"h c #E1EE66",
-"i c #F6F9CE",
-"j c #FFFFFF",
-"k c #FDF8F5",
-"l c #E0EC77",
-"m c #DFEA77",
-"n c #F1F5CC",
-"o c #CEDE4F",
-"p c #E5F276",
-"q c #C3C051",
-"r c #ECF48E",
-"s c #DFED64",
-"t c #E2EE79",
-"u c #DCE675",
-"v c #E5F274",
-"w c #F0F386",
-"x c #E5E750",
-"y c #DFE340",
-"z c #E6E767",
-"A c #FDF7F3",
-"B c #DFDE63",
-"C c #D6D73B",
-"D c #D3D539",
-"E c #E7EF69",
-"F c #C2BE4E",
-"G c #F0ED7A",
-"H c #E3E049",
-"I c #DEDB38",
-"J c #E4E063",
-"K c #DDD960",
-"L c #D3CD33",
-"M c #D1CC31",
-"N c #EAEC5C",
-"O c #C0BB47",
-"P c #EFE976",
-"Q c #E1DD48",
-"R c #E3DF62",
-"S c #FCF7F3",
-"T c #DBD65F",
-"U c #D0CA31",
-"V c #EAEB56",
-"W c #BEB73C",
-"X c #EFEA73",
-"Y c #DFDB46",
-"Z c #F3F2C5",
-"` c #DEDB60",
-" . c #F0EEC4",
-".. c #CFC930",
-"+. c #E9EB52",
-"@. c #BEB83A",
-"#. c #EFEB70",
-"$. c #DDD943",
-"%. c #DAD643",
-"&. c #D5D134",
-"*. c #D4D033",
-"=. c #D2CC40",
-"-. c #D1CD34",
-";. c #E7EA4F",
-">. c #BEB739",
-",. c #BCB656",
-"'. c #EEEA6D",
-"). c #E5E157",
-"!. c #DAD63E",
-"~. c #D5D034",
-"{. c #D2CD31",
-"]. c #D1CB31",
-"^. c #D3CF36",
-"/. c #DFDE43",
-"(. c #E8EA4C",
-"_. c #C7C369",
-":. c #CBC888",
-"<. c #E1DD5B",
-"[. c #EEEB68",
-"}. c #EEEB65",
-"|. c #EDEB62",
-"1. c #EDEB5F",
-"2. c #ECEA5C",
-"3. c #ECEB59",
-"4. c #DCDD3F",
-"5. c #E0E0D0",
-"6. c #CBC789",
-"7. c #BDB658",
-" ",
-" . + @ # # # # # # $ # @ + . ",
-" + % & * = - ; > , ' ) ! ~ + ",
-" { ] ^ / ( _ : < [ } | 1 2 3 ",
-" $ 4 5 6 7 8 9 0 a b c d e f ",
-" # g h i j k l m k j n o p q ",
-" # r s t k j k k j k u o v q ",
-" # w x y z A j j A B C D E F ",
-" # G H I J A j j A K L M N O ",
-" # P Q R A j A A j S T U V W ",
-" # X Y Z j A ` K S j ...+. at . ",
-" # #.$.%.Z K &.*.T .=.-.;.>. ",
-" ,.'.).!.~.*.L {.]...^./.(._. ",
-" :.<.[.}.|.1.2.3.V +.;.(.4.:. ",
-" 5.6.7.$ # # $ # # # $ 7.6.5. ",
-" "};
-static pixmap p("defstatus",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_defstatus.xpm b/ecflow_4_0_7/view/src/libicon/icon_defstatus.xpm
deleted file mode 100644
index 0737c5f..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_defstatus.xpm
+++ /dev/null
@@ -1,162 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * defstatus_xpm[] = {
-"16 16 128 2",
-" c #E5E5E5",
-". c #D6D8BA",
-"+ c #C2BF70",
-"@ c #B6B04A",
-"# c #A89D12",
-"$ c #A89B12",
-"% c #E7E377",
-"& c #F3F489",
-"* c #F4F387",
-"= c #F4F484",
-"- c #F2F381",
-"; c #F0F37E",
-"> c #F0F37B",
-", c #EFF379",
-"' c #EFF376",
-") c #EDF373",
-"! c #EDF271",
-"~ c #E0E35F",
-"{ c #B7B14A",
-"] c #F1F58F",
-"^ c #ECF277",
-"/ c #E3EE5D",
-"( c #E2ED5C",
-"_ c #E1EC5B",
-": c #DFEA59",
-"< c #DDE858",
-"[ c #DCE756",
-"} c #DAE654",
-"| c #D9E453",
-"1 c #E1EA64",
-"2 c #E9F274",
-"3 c #C7C46C",
-"4 c #F0F592",
-"5 c #E1EF66",
-"6 c #DFEE62",
-"7 c #F4F8CD",
-"8 c #E3EE78",
-"9 c #D6E852",
-"0 c #D5E651",
-"a c #DEE975",
-"b c #F2F6CB",
-"c c #D6E35C",
-"d c #D2E154",
-"e c #E6F278",
-"f c #C3C054",
-"g c #EEF491",
-"h c #E1EE66",
-"i c #F6F9CE",
-"j c #FFFFFF",
-"k c #FDF8F5",
-"l c #E0EC77",
-"m c #DFEA77",
-"n c #F1F5CC",
-"o c #CEDE4F",
-"p c #E5F276",
-"q c #C3C051",
-"r c #ECF48E",
-"s c #DFED64",
-"t c #E2EE79",
-"u c #DCE675",
-"v c #E5F274",
-"w c #F0F386",
-"x c #E5E750",
-"y c #DFE340",
-"z c #E6E767",
-"A c #FDF7F3",
-"B c #DFDE63",
-"C c #D6D73B",
-"D c #D3D539",
-"E c #E7EF69",
-"F c #C2BE4E",
-"G c #F0ED7A",
-"H c #E3E049",
-"I c #DEDB38",
-"J c #E4E063",
-"K c #DDD960",
-"L c #D3CD33",
-"M c #D1CC31",
-"N c #EAEC5C",
-"O c #C0BB47",
-"P c #EFE976",
-"Q c #E1DD48",
-"R c #E3DF62",
-"S c #FCF7F3",
-"T c #DBD65F",
-"U c #D0CA31",
-"V c #EAEB56",
-"W c #BEB73C",
-"X c #EFEA73",
-"Y c #DFDB46",
-"Z c #F3F2C5",
-"` c #DEDB60",
-" . c #F0EEC4",
-".. c #CFC930",
-"+. c #E9EB52",
-"@. c #BEB83A",
-"#. c #EFEB70",
-"$. c #DDD943",
-"%. c #DAD643",
-"&. c #D5D134",
-"*. c #D4D033",
-"=. c #D2CC40",
-"-. c #D1CD34",
-";. c #E7EA4F",
-">. c #BEB739",
-",. c #BCB656",
-"'. c #EEEA6D",
-"). c #E5E157",
-"!. c #DAD63E",
-"~. c #D5D034",
-"{. c #D2CD31",
-"]. c #D1CB31",
-"^. c #D3CF36",
-"/. c #DFDE43",
-"(. c #E8EA4C",
-"_. c #C7C369",
-":. c #CBC888",
-"<. c #E1DD5B",
-"[. c #EEEB68",
-"}. c #EEEB65",
-"|. c #EDEB62",
-"1. c #EDEB5F",
-"2. c #ECEA5C",
-"3. c #ECEB59",
-"4. c #DCDD3F",
-"5. c #E0E0D0",
-"6. c #CBC789",
-"7. c #BDB658",
-" ",
-" . + @ # # # # # # $ # @ + . ",
-" + % & * = - ; > , ' ) ! ~ + ",
-" { ] ^ / ( _ : < [ } | 1 2 3 ",
-" $ 4 5 6 7 8 9 0 a b c d e f ",
-" # g h i j k l m k j n o p q ",
-" # r s t k j k k j k u o v q ",
-" # w x y z A j j A B C D E F ",
-" # G H I J A j j A K L M N O ",
-" # P Q R A j A A j S T U V W ",
-" # X Y Z j A ` K S j ...+. at . ",
-" # #.$.%.Z K &.*.T .=.-.;.>. ",
-" ,.'.).!.~.*.L {.]...^./.(._. ",
-" :.<.[.}.|.1.2.3.V +.;.(.4.:. ",
-" 5.6.7.$ # # $ # # # $ 7.6.5. ",
-" "};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_folded.cc b/ecflow_4_0_7/view/src/libicon/icon_folded.cc
deleted file mode 100644
index 0eeb150..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_folded.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 3 1",
-" c #E5E5E5E5E5E5",
-". c #7E7E7E7E7E7E",
-"X c #FFFFFFFFFFFF",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-".. ... ... ..",
-"XX XXX XXX XX",
-" ",
-" ",
-" ",
-" ",
-" ",
-" "};
-static pixmap p("folded",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_folded.xpm b/ecflow_4_0_7/view/src/libicon/icon_folded.xpm
deleted file mode 100644
index e39a4e5..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_folded.xpm
+++ /dev/null
@@ -1,37 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * folded_xpm[] = {
-"16 16 3 1",
-" c #E5E5E5E5E5E5",
-". c #7E7E7E7E7E7E",
-"X c #FFFFFFFFFFFF",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-".. ... ... ..",
-"XX XXX XXX XX",
-" ",
-" ",
-" ",
-" ",
-" ",
-" "};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_late.cc b/ecflow_4_0_7/view/src/libicon/icon_late.cc
deleted file mode 100644
index 7cec98a..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_late.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 3 1",
-" c #E5E5E5E5E5E5",
-". c #000000000000",
-"X c #F5F5F9F97A7A",
-" . ",
-" .X. ",
-" .X. ",
-" .XXX. ",
-" .X.X. ",
-" .XX.XX. ",
-" .XX.XX. ",
-" .XXX.XXX. ",
-" .XXX.XXX. ",
-" .XXXX.XXXX. ",
-" .XXXXXXXXX. ",
-" .XXXXX.XXXXX. ",
-" .XXXXX.XXXXX. ",
-".XXXXXXXXXXXXX. ",
-"............... ",
-" "};
-static pixmap p("late",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_late.xpm b/ecflow_4_0_7/view/src/libicon/icon_late.xpm
deleted file mode 100644
index 070ead2..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_late.xpm
+++ /dev/null
@@ -1,37 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * late_xpm[] = {
-"16 16 3 1",
-" c #E5E5E5E5E5E5",
-". c #000000000000",
-"X c #F5F5F9F97A7A",
-" . ",
-" .X. ",
-" .X. ",
-" .XXX. ",
-" .X.X. ",
-" .XX.XX. ",
-" .XX.XX. ",
-" .XXX.XXX. ",
-" .XXX.XXX. ",
-" .XXXX.XXXX. ",
-" .XXXXXXXXX. ",
-" .XXXXX.XXXXX. ",
-" .XXXXX.XXXXX. ",
-".XXXXXXXXXXXXX. ",
-"............... ",
-" "};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_limit0.cc b/ecflow_4_0_7/view/src/libicon/icon_limit0.cc
deleted file mode 100644
index bc4aca6..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_limit0.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"8 8 4 1",
-" c #E5E5E5E5E5E5",
-". c #FFFFFFFFFFFF",
-"X c #000000000000",
-"o c #7E7E7E7E7E7E",
-" .... ",
-" . X ",
-". . o",
-". o",
-". o",
-". o",
-" o o ",
-" oooo "};
-static pixmap p("limit0",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_limit0.xpm b/ecflow_4_0_7/view/src/libicon/icon_limit0.xpm
deleted file mode 100644
index 0f00646..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_limit0.xpm
+++ /dev/null
@@ -1,30 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * limit0_xpm[] = {
-"8 8 4 1",
-" c #E5E5E5E5E5E5",
-". c #FFFFFFFFFFFF",
-"X c #000000000000",
-"o c #7E7E7E7E7E7E",
-" .... ",
-" . X ",
-". . o",
-". o",
-". o",
-". o",
-" o o ",
-" oooo "};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_limit1.cc b/ecflow_4_0_7/view/src/libicon/icon_limit1.cc
deleted file mode 100644
index ce1a5cf..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_limit1.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"8 8 6 1",
-" c #E5E5E5E5E5E5",
-". c #0000EEEE0000",
-"X c #0000FFFF0000",
-"o c #000000000000",
-"O c #FFFFFFFFFFFF",
-"+ c #000088880000",
-" .... ",
-" .XXXXo ",
-".XOXXXX+",
-".XXXXXX+",
-".XXXXXX+",
-".XXXXXX+",
-" +XXXX+ ",
-" ++++ "};
-static pixmap p("limit1",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_limit1.xpm b/ecflow_4_0_7/view/src/libicon/icon_limit1.xpm
deleted file mode 100644
index 9286c0d..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_limit1.xpm
+++ /dev/null
@@ -1,32 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * limit1_xpm[] = {
-"8 8 6 1",
-" c #E5E5E5E5E5E5",
-". c #0000EEEE0000",
-"X c #0000FFFF0000",
-"o c #000000000000",
-"O c #FFFFFFFFFFFF",
-"+ c #000088880000",
-" .... ",
-" .XXXXo ",
-".XOXXXX+",
-".XXXXXX+",
-".XXXXXX+",
-".XXXXXX+",
-" +XXXX+ ",
-" ++++ "};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_limit2.cc b/ecflow_4_0_7/view/src/libicon/icon_limit2.cc
deleted file mode 100644
index 43c18ad..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_limit2.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"8 8 6 1",
-" c #E5E5E5E5E5E5",
-". c #00000000EEEE",
-"X c #00000000FFFF",
-"o c #000000000000",
-"O c #FFFFFFFFFFFF",
-"+ c #000000008888",
-" .... ",
-" .XXXXo ",
-".XOXXXX+",
-".XXXXXX+",
-".XXXXXX+",
-".XXXXXX+",
-" +XXXX+ ",
-" ++++ "};
-static pixmap p("limit2",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_limit2.xpm b/ecflow_4_0_7/view/src/libicon/icon_limit2.xpm
deleted file mode 100644
index ddd2743..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_limit2.xpm
+++ /dev/null
@@ -1,32 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * limit2_xpm[] = {
-"8 8 6 1",
-" c #E5E5E5E5E5E5",
-". c #00000000EEEE",
-"X c #00000000FFFF",
-"o c #000000000000",
-"O c #FFFFFFFFFFFF",
-"+ c #000000008888",
-" .... ",
-" .XXXXo ",
-".XOXXXX+",
-".XXXXXX+",
-".XXXXXX+",
-".XXXXXX+",
-" +XXXX+ ",
-" ++++ "};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_locked.cc b/ecflow_4_0_7/view/src/libicon/icon_locked.cc
deleted file mode 100644
index 727c981..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_locked.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 4 1",
-" c #E5E5E5E5E5E5",
-". c #282828282828",
-"X c #FFFFFFFFFFFF",
-"o c #ADADADADADAD",
-" ",
-" .... ",
-" .. .. ",
-" . . ",
-" . . ",
-" XXXXXXXXXXX. ",
-" Xoooooooooo. ",
-" Xoooo..oooo. ",
-" Xooo....ooo. ",
-" Xoooo..oooo. ",
-" Xoooo..oooo. ",
-" Xoooo..oooo. ",
-" Xoooooooooo. ",
-" Xoooooooooo. ",
-" ............ ",
-" XXXXXXXXXXXX "};
-static pixmap p("locked",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_locked.xpm b/ecflow_4_0_7/view/src/libicon/icon_locked.xpm
deleted file mode 100644
index d8cd614..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_locked.xpm
+++ /dev/null
@@ -1,38 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * locked_xpm[] = {
-"16 16 4 1",
-" c #E5E5E5E5E5E5",
-". c #282828282828",
-"X c #FFFFFFFFFFFF",
-"o c #ADADADADADAD",
-" ",
-" .... ",
-" .. .. ",
-" . . ",
-" . . ",
-" XXXXXXXXXXX. ",
-" Xoooooooooo. ",
-" Xoooo..oooo. ",
-" Xooo....ooo. ",
-" Xoooo..oooo. ",
-" Xoooo..oooo. ",
-" Xoooo..oooo. ",
-" Xoooooooooo. ",
-" Xoooooooooo. ",
-" ............ ",
-" XXXXXXXXXXXX "};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_memo.cc b/ecflow_4_0_7/view/src/libicon/icon_memo.cc
deleted file mode 100644
index f25cb76..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_memo.cc
+++ /dev/null
@@ -1,15 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-#include "pixmap.h"
diff --git a/ecflow_4_0_7/view/src/libicon/icon_memo.xpm b/ecflow_4_0_7/view/src/libicon/icon_memo.xpm
deleted file mode 100644
index 81590a6..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_memo.xpm
+++ /dev/null
@@ -1,67 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * icon_memo_xpm[] = {
-"32 32 17 1",
-" c None",
-". c #000000",
-"+ c #800000",
-"@ c #008000",
-"# c #808000",
-"$ c #000080",
-"% c #800080",
-"& c #008080",
-"* c #808080",
-"= c #C0C0C0",
-"- c #FF0000",
-"; c #00FF00",
-"> c #FFFF00",
-", c #0000FF",
-"' c #FF00FF",
-") c #00FFFF",
-"! c #FFFFFF",
-" * * * * * ",
-" * * * * * * * * * * ",
-" ...*...*...*...*...*...",
-" .>!*!>!*!>!*!>!*!>!*!>.",
-" .>!>!>!>!>!>!>!>!>!>!>..",
-" .!>!>!>!>!>!>!>!>!>!>!..",
-" .!>!>!>.........>!>!>!.=.",
-" .>!>!>!.!!!!!!!.!>!>!>.=.",
-" .>!>!>!.!!....!.!>!>!>.=!.",
-" .!>!>!>.!.!..!!.>!>!>!.=!.",
-" .!>!>!>.!!!!!!!.>!>!>!.*!!.",
-" .>!>!>!.........!>!>!>.=!!.",
-" .>!>!>!>!>!>!>!>!>!>!>.=!>!.",
-" .!>!>!>!>!>!>!>!>!>!>!.=!!!.",
-" .!>!>!>!>!>!>!>!>!>!>!.***!!.",
-" .>!>!>!>!>!>!>!>!>!>!>.=!!!!.",
-" .>!>!>!>!>!>!>!>!>!>!>.=!!!>!.",
-" .!>!>!>!>!>!>!>!>!>!>!.=!!!!!.",
-" .!>!>!>!>!>!>!>!>!>!>!.*****!!.",
-" .>!>!>!>!>!>!>!>!>!>!>.=!!!!!!.",
-".>!>!>!>!>!>!>!>!>!>!>.=!>!!!>!.",
-".......................=!!!!!!!.",
-" .==*****************!!.",
-" .!!!!!!!!!!!!!!!!!!!!!.",
-" .!!!>!!!>!!!>!!!>!!!>!.",
-" .!!!!!!!!!!!!!!!!!!!!!.",
-" .!>*****************!!.",
-" .!!!!!!!!!!!!!!!!!!!!!.",
-" .!!!>!!!>!!!>!!!>!!!>!.",
-" .!!!!!!!!!!!!!!!!!!!!!.",
-" .!>!!!>!!!>!!!>!!!>!!!.",
-" ......................."};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_message.cc b/ecflow_4_0_7/view/src/libicon/icon_message.cc
deleted file mode 100644
index eeff47c..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_message.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 4 1",
-" c None",
-". c #E5E5E5",
-"+ c #000000",
-"@ c #F5F97A",
-"................",
-"................",
-"................",
-"..+++++++++++...",
-"..+@@@@@@@@@+...",
-"..+@@@@@@@@@+...",
-"..+@@@@@@@@@+...",
-"..+@@@@@@@@@+...",
-"..+@@@@@@@@@+...",
-"..+@@@@@@@@@+...",
-"..+@@@@@+++++...",
-"..+@@@@@+@@+....",
-"..+@@@@@+ at +.....",
-"..++++++++......",
-"................",
-"................"};
-static pixmap p("message",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_message.xpm b/ecflow_4_0_7/view/src/libicon/icon_message.xpm
deleted file mode 100644
index aa3ddb5..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_message.xpm
+++ /dev/null
@@ -1,41 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * message_xpm[] = {
-"16 16 7 1",
-" c #E5E5E5E5E5E5",
-". c #000000000000",
-"X c #C9C9CDCD4C4C",
-"o c #FFFFFFFFFFFF",
-"O c #F5F5F9F97A7A",
-"+ c #545454545454",
-"@ c #98989B9B3838",
-" ",
-" ",
-" ",
-" ........... ",
-" .XXXXXXXXX. ",
-" .XXXXXXXXX. ",
-" .oOOOOOOOO. ",
-" .oOOOOOOOO. ",
-" .oOOOOOOOO. ",
-" .oOOOOOOOO. ",
-" .oOOOX..... ",
-" .oOOXX+OO. ",
-" .oXXX.O at + ",
-" .....++ ",
-" ",
-" "};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_migrated.cc b/ecflow_4_0_7/view/src/libicon/icon_migrated.cc
deleted file mode 100644
index a8757d2..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_migrated.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 3 1",
-" c #E79DE79DE79D",
-". c #000000000000",
-"X c #F7DEFBEE79E7",
-" ",
-" ..... ",
-" .XXXXX. ",
-" .XXXXXXX. ",
-" .XXXXXXXXX. ",
-" .XXXXXXXXXXX. ",
-" .XXXX...XXXX. ",
-" .XXXX. .XXXX. ",
-" .XXXX...XXXX. ",
-" .XXXXXXXXXXX. ",
-" .XXXXXXXXX. ",
-" .XXXXXXX. ",
-" .XXXXX. ",
-" ......... ",
-" ",
-" "};
-static pixmap p("migrated",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_migrated.xpm b/ecflow_4_0_7/view/src/libicon/icon_migrated.xpm
deleted file mode 100644
index 251d828..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_migrated.xpm
+++ /dev/null
@@ -1,37 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * migrated_xpm[] = {
-"16 16 3 1",
-" c #E79DE79DE79D",
-". c #000000000000",
-"X c #F7DEFBEE79E7",
-" ",
-" ..... ",
-" .XXXXX. ",
-" .XXXXXXX. ",
-" .XXXXXXXXX. ",
-" .XXXXXXXXXXX. ",
-" .XXXX...XXXX. ",
-" .XXXX. .XXXX. ",
-" .XXXX...XXXX. ",
-" .XXXXXXXXXXX. ",
-" .XXXXXXXXX. ",
-" .XXXXXXX. ",
-" .XXXXX. ",
-" ......... ",
-" ",
-" "};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_noway.cc b/ecflow_4_0_7/view/src/libicon/icon_noway.cc
deleted file mode 100644
index cf56c8b..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_noway.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-// Description :
-//=============================================================================================
-
-#include "pixmap.h"
-/* XPM */
-/*
-static const char * bits[] = {
-"16 16 2 1",
-" c #E7E7E7E7E7E7",
-". c #000000000000",
-" ... ... . . ",
-". .. ... .. ",
-". . .. . . ",
-". . .. . ",
-". .. .. . ",
-" ... ... . . ",
-".... . .... ",
-". . . . ",
-".... . ... ",
-". . . ",
-". .... .... ",
-"..... .... ",
-" . . ",
-" . ... ",
-" . . ",
-" . .... "};
-*/
-static const char * bits[] = {
-"16 16 3 1",
-" c #E5E5E5E5E5E5",
-". c #FFFFFF",
-"# c #FF0000",
-" ...... ",
-" ..######.. ",
-" .##########. ",
-" .############. ",
-" .############. ",
-".##############.",
-".##############.",
-".#............#.",
-".#............#.",
-".##############.",
-".##############.",
-" .############. ",
-" .############. ",
-" .##########. ",
-" ..######.. ",
-" ...... "};
-
-
-
-
-static pixmap p("noway",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_noway.xpm b/ecflow_4_0_7/view/src/libicon/icon_noway.xpm
deleted file mode 100644
index e1804fb..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_noway.xpm
+++ /dev/null
@@ -1,63 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-/*
-static char * icon_complete[] = {
-"16 16 2 1",
-" c #E7E7E7E7E7E7",
-". c #000000000000",
-" ... ... . . ",
-". .. ... .. ",
-". . .. . . ",
-". . .. . ",
-". .. .. . ",
-" ... ... . . ",
-".... . .... ",
-". . . . ",
-".... . ... ",
-". . . ",
-". .... .... ",
-"..... .... ",
-" . . ",
-" . ... ",
-" . . ",
-" . .... "};
-*/
-static char * icon_noway_xpm[] = {
-"16 16 3 1",
-" c #E5E5E5E5E5E5",
-". c #FFFFFF",
-"# c #FF0000",
-" ...... ",
-" ..######.. ",
-" .##########. ",
-" .############. ",
-" .############. ",
-".##############.",
-".##############.",
-".#............#.",
-".#............#.",
-".##############.",
-".##############.",
-" .############. ",
-" .############. ",
-" .##########. ",
-" ..######.. ",
-" ...... "};
-
-
-
-
diff --git a/ecflow_4_0_7/view/src/libicon/icon_rerun.cc b/ecflow_4_0_7/view/src/libicon/icon_rerun.cc
deleted file mode 100644
index ac631f0..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_rerun.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #1 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 3 1",
-" c #E5E5E5E5E5E5",
-". c #000000000000",
-"X c #F5F5F3F35454",
-" ",
-" ..... ",
-" ..XXXXX.. ",
-" .XXXXXXXXX. ",
-" .XXXXXXXXXXX. ",
-" .XXX.XXX.XXX. ",
-".XXX...X...XXX. ",
-".XXXX.XXX.XXXX. ",
-".XXXXXXXXXXXXX. ",
-".XXXXX...XXXXX. ",
-".XXXX.XXX.XXXX. ",
-" .XX.XXXXX.XX. ",
-" .XXXXXXXXXXX. ",
-" .XXXXXXXXX. ",
-" ..XXXXX.. ",
-" ..... "};
-static pixmap p("rerun",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_rerun.xpm b/ecflow_4_0_7/view/src/libicon/icon_rerun.xpm
deleted file mode 100644
index c7be610..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_rerun.xpm
+++ /dev/null
@@ -1,37 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * rerun_xpm[] = {
-"16 16 3 1",
-" c #E5E5E5E5E5E5",
-". c #000000000000",
-"X c #F5F5F3F35454",
-" ",
-" ..... ",
-" ..XXXXX.. ",
-" .XXXXXXXXX. ",
-" .XXXXXXXXXXX. ",
-" .XXX.XXX.XXX. ",
-".XXX...X...XXX. ",
-".XXXX.XXX.XXXX. ",
-".XXXXXXXXXXXXX. ",
-".XXXXX...XXXXX. ",
-".XXXX.XXX.XXXX. ",
-" .XX.XXXXX.XX. ",
-" .XXXXXXXXXXX. ",
-" .XXXXXXXXX. ",
-" ..XXXXX.. ",
-" ..... "};
diff --git a/ecflow_4_0_7/view/src/libicon/icon_waiting.cc b/ecflow_4_0_7/view/src/libicon/icon_waiting.cc
deleted file mode 100644
index 7eed8ac..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_waiting.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "pixmap.h"
-/* XPM */
-static const char * bits[] = {
-"16 16 2 1",
-" c #E5E5E5E5E5E5",
-". c #000000000000",
-" ",
-" .......",
-" .. ...",
-" . .. ",
-" .. ",
-" .. ",
-" .... .. ",
-" . . .. .",
-" . ... ..",
-" . .......",
-" . . ",
-" ... .... ",
-" . ",
-" . ",
-" ... ",
-" "};
-static pixmap p("waiting",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_waiting.xpm b/ecflow_4_0_7/view/src/libicon/icon_waiting.xpm
deleted file mode 100644
index 1dc3ed6..0000000
--- a/ecflow_4_0_7/view/src/libicon/icon_waiting.xpm
+++ /dev/null
@@ -1,36 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* XPM */
-static char * waiting_xpm[] = {
-"16 16 2 1",
-" c #E5E5E5E5E5E5",
-". c #000000000000",
-" ",
-" .......",
-" .. ...",
-" . .. ",
-" .. ",
-" .. ",
-" .... .. ",
-" . . .. .",
-" . ... ..",
-" . .......",
-" . . ",
-" ... .... ",
-" . ",
-" . ",
-" ... ",
-" "};
diff --git a/ecflow_4_0_7/view/src/libui/uiask.cc b/ecflow_4_0_7/view/src/libui/uiask.cc
deleted file mode 100644
index 4638cf2..0000000
--- a/ecflow_4_0_7/view/src/libui/uiask.cc
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
-** Generated by X-Designer
-*/
-/*
-**LIBS: -lXm -lXt -lX11
-*/
-
-#include <stdlib.h>
-#include <X11/Xatom.h>
-#include <X11/Intrinsic.h>
-#include <X11/Shell.h>
-
-#include <Xm/Xm.h>
-#include <Xm/DialogS.h>
-#include <Xm/MessageB.h>
-#include <Xm/TextF.h>
-#include <Xm/LabelG.h>
-#include <Xm/PushBG.h>
-#include <Xm/SeparatoG.h>
-
-
-#include "uiask.h"
-
-ask_shell_p ask_shell = (ask_shell_p) NULL;
-
-
-
-void ask_shell_c::create (Widget parent, char *widget_name)
-{
- Widget children[7]; /* Children to manage */
- Arg al[64]; /* Arg List */
- register int ac = 0; /* Arg Count */
- Widget button20 = (Widget)NULL;
- Widget button21 = (Widget)NULL;
- Widget button22 = (Widget)NULL;
-
- if ( !widget_name )
- widget_name = "ask_shell";
-
- XtSetArg(al[ac], XmNallowShellResize, TRUE); ac++;
- XtSetArg(al[ac], XmNtransient, TRUE); ac++;
- ask_shell = XmCreateDialogShell ( parent, widget_name, al, ac );
- ac = 0;
- _xd_rootwidget = ask_shell;
- XtSetArg(al[ac], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); ac++;
- XtSetArg(al[ac], XmNdialogType, XmDIALOG_QUESTION); ac++;
- XtSetArg(al[ac], XmNmessageAlignment, XmALIGNMENT_CENTER); ac++;
- XtSetArg(al[ac], XmNdefaultButtonType, XmDIALOG_CANCEL_BUTTON); ac++;
- form_ = XmCreateMessageBox ( ask_shell, "form_", al, ac );
- ac = 0;
- button20 = XmMessageBoxGetChild ( form_, XmDIALOG_CANCEL_BUTTON );
- button21 = XmMessageBoxGetChild ( form_, XmDIALOG_HELP_BUTTON );
- label_ = XmMessageBoxGetChild ( form_, XmDIALOG_MESSAGE_LABEL );
- button22 = XmMessageBoxGetChild ( form_, XmDIALOG_OK_BUTTON );
- XtSetArg(al[ac], XmNsensitive, FALSE); ac++;
- XtSetValues ( button21,al, ac );
- ac = 0;
- value_ = XmCreateTextField ( form_, "value_", al, ac );
- XtAddCallback (form_, XmNokCallback,&ask_shell_c:: okCB, (XtPointer) this);
- XtAddCallback (form_, XmNcancelCallback,&ask_shell_c:: cancelCB, (XtPointer) this);
- XtAddCallback (form_, XmNhelpCallback,&ask_shell_c:: helpCB, (XtPointer) this);
- children[ac++] = value_;
- XtManageChildren(children, ac);
- ac = 0;
-}
-
-void ask_shell_c::helpCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- ask_shell_p instance = (ask_shell_p) client_data;
- instance->helpCB ( widget, call_data );
-}
-
-void ask_shell_c::cancelCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- ask_shell_p instance = (ask_shell_p) client_data;
- instance->cancelCB ( widget, call_data );
-}
-
-void ask_shell_c::okCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- ask_shell_p instance = (ask_shell_p) client_data;
- instance->okCB ( widget, call_data );
-}
-
diff --git a/ecflow_4_0_7/view/src/libui/uiconfirm.cc b/ecflow_4_0_7/view/src/libui/uiconfirm.cc
deleted file mode 100644
index 865877a..0000000
--- a/ecflow_4_0_7/view/src/libui/uiconfirm.cc
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
-** Generated by X-Designer
-*/
-/*
-**LIBS: -lXm -lXt -lX11
-*/
-
-#include <stdlib.h>
-#include <X11/Xatom.h>
-#include <X11/Intrinsic.h>
-#include <X11/Shell.h>
-
-#include <Xm/Xm.h>
-#include <Xm/DialogS.h>
-#include <Xm/MessageB.h>
-#include <Xm/LabelG.h>
-#include <Xm/PushBG.h>
-#include <Xm/SeparatoG.h>
-
-
-#include "uiconfirm.h"
-
-confirm_shell_p confirm_shell = (confirm_shell_p) NULL;
-
-
-
-void confirm_shell_c::create (Widget parent, char *widget_name)
-{
- /* Widget children[6]; // Children to manage */
- Arg al[64]; /* Arg List */
- register int ac = 0; /* Arg Count */
- Widget button20 = (Widget)NULL;
- Widget button21 = (Widget)NULL;
- Widget button22 = (Widget)NULL;
-
- if ( !widget_name )
- widget_name = "confirm_shell";
-
- XtSetArg(al[ac], XmNallowShellResize, TRUE); ac++;
- XtSetArg(al[ac], XmNtransient, TRUE); ac++;
- confirm_shell = XmCreateDialogShell ( parent, widget_name, al, ac );
- ac = 0;
- _xd_rootwidget = confirm_shell;
- XtSetArg(al[ac], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); ac++;
- XtSetArg(al[ac], XmNdialogType, XmDIALOG_QUESTION); ac++;
- XtSetArg(al[ac], XmNmessageAlignment, XmALIGNMENT_CENTER); ac++;
- XtSetArg(al[ac], XmNdefaultButtonType, XmDIALOG_CANCEL_BUTTON); ac++;
- form_ = XmCreateMessageBox ( confirm_shell, "form_", al, ac );
- ac = 0;
- button20 = XmMessageBoxGetChild ( form_, XmDIALOG_CANCEL_BUTTON );
- button21 = XmMessageBoxGetChild ( form_, XmDIALOG_HELP_BUTTON );
- label_ = XmMessageBoxGetChild ( form_, XmDIALOG_MESSAGE_LABEL );
- button22 = XmMessageBoxGetChild ( form_, XmDIALOG_OK_BUTTON );
- XtSetArg(al[ac], XmNsensitive, FALSE); ac++;
- XtSetValues ( button21,al, ac );
- ac = 0;
- XtAddCallback (form_, XmNhelpCallback,&confirm_shell_c:: helpCB, (XtPointer) this);
- XtAddCallback (form_, XmNcancelCallback,&confirm_shell_c:: cancelCB, (XtPointer) this);
- XtAddCallback (form_, XmNokCallback,&confirm_shell_c:: okCB, (XtPointer) this);
-}
-
-void confirm_shell_c::helpCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- confirm_shell_p instance = (confirm_shell_p) client_data;
- instance->helpCB ( widget, call_data );
-}
-
-void confirm_shell_c::cancelCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- confirm_shell_p instance = (confirm_shell_p) client_data;
- instance->cancelCB ( widget, call_data );
-}
-
-void confirm_shell_c::okCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- confirm_shell_p instance = (confirm_shell_p) client_data;
- instance->okCB ( widget, call_data );
-}
-
diff --git a/ecflow_4_0_7/view/src/libui/uiedit_label.cc b/ecflow_4_0_7/view/src/libui/uiedit_label.cc
deleted file mode 100644
index 75be6f9..0000000
--- a/ecflow_4_0_7/view/src/libui/uiedit_label.cc
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
-** Generated by X-Designer
-*/
-/*
-**LIBS: -lXm -lXt -lX11
-*/
-
-#include <stdlib.h>
-#include <X11/Xatom.h>
-#include <X11/Intrinsic.h>
-#include <X11/Shell.h>
-
-#include <Xm/Xm.h>
-#include <Xm/DialogS.h>
-#include <Xm/Form.h>
-#include <Xm/Frame.h>
-#include <Xm/Label.h>
-#include <Xm/PushB.h>
-#include <Xm/RowColumn.h>
-#include <Xm/ScrollBar.h>
-#include <Xm/Text.h>
-
-
-#include "uiedit_label.h"
-
-edit_label_p edit_label_form = (edit_label_p) NULL;
-
-
-
-void edit_label_form_c::create (Widget parent, char *widget_name)
-{
- Widget children[3]; /* Children to manage */
- Arg al[64]; /* Arg List */
- register int ac = 0; /* Arg Count */
- Widget button1 = (Widget)NULL;
- Widget form1 = (Widget)NULL;
- Widget frame1 = (Widget)NULL;
- Widget scrolledText1 = (Widget)NULL;
- Widget label1 = (Widget)NULL;
- Widget frame2 = (Widget)NULL;
- Widget scrolledText2 = (Widget)NULL;
- Widget label2 = (Widget)NULL;
-
- if ( !widget_name )
- widget_name = "edit_label_form";
-
- XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
- edit_label_form = XmCreateForm ( parent, widget_name, al, ac );
- ac = 0;
- _xd_rootwidget = edit_label_form;
- tools_ = XmCreateRowColumn ( edit_label_form, "tools_", al, ac );
- button1 = XmCreatePushButton ( tools_, "Apply", al, ac );
- form1 = XmCreateForm ( edit_label_form, "form1", al, ac );
- frame1 = XmCreateFrame ( form1, "frame1", al, ac );
- XtSetArg(al[ac], XmNeditMode, XmMULTI_LINE_EDIT); ac++;
- value_ = XmCreateScrolledText ( frame1, "value_", al, ac );
- ac = 0;
- scrolledText1 = XtParent ( value_ );
-
- XtSetArg(al[ac], XmNchildType, XmFRAME_TITLE_CHILD); ac++;
- label1 = XmCreateLabel ( frame1, "Value:", al, ac );
- ac = 0;
- frame2 = XmCreateFrame ( form1, "frame2", al, ac );
- XtSetArg(al[ac], XmNsensitive, FALSE); ac++;
- XtSetArg(al[ac], XmNeditable, FALSE); ac++;
- XtSetArg(al[ac], XmNeditMode, XmMULTI_LINE_EDIT); ac++;
- default_ = XmCreateScrolledText ( frame2, "default_", al, ac );
- ac = 0;
- scrolledText2 = XtParent ( default_ );
-
- XtSetArg(al[ac], XmNchildType, XmFRAME_TITLE_CHILD); ac++;
- label2 = XmCreateLabel ( frame2, "Default:", al, ac );
- ac = 0;
-
- XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
- XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
- XtSetValues ( tools_,al, ac );
- ac = 0;
-
- XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
- XtSetArg(al[ac], XmNtopWidget, tools_); ac++;
- XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
- XtSetValues ( form1,al, ac );
- ac = 0;
- XtAddCallback (button1, XmNactivateCallback,&edit_label_form_c:: applyCB, (XtPointer) this);
- children[ac++] = button1;
- XtManageChildren(children, ac);
- ac = 0;
-
- XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_POSITION); ac++;
- XtSetArg(al[ac], XmNbottomPosition, 50); ac++;
- XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
- XtSetValues ( frame1,al, ac );
- ac = 0;
-
- XtSetArg(al[ac], XmNtopAttachment, XmATTACH_POSITION); ac++;
- XtSetArg(al[ac], XmNtopPosition, 50); ac++;
- XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
- XtSetValues ( frame2,al, ac );
- ac = 0;
- XtAddCallback (value_, XmNvalueChangedCallback,&edit_label_form_c:: changedCB, (XtPointer) this);
- XtManageChild(value_);
- children[ac++] = label1;
- XtManageChildren(children, ac);
- ac = 0;
- XtAddCallback (default_, XmNvalueChangedCallback,&edit_label_form_c:: changedCB, (XtPointer) this);
- XtManageChild(default_);
- children[ac++] = label2;
- XtManageChildren(children, ac);
- ac = 0;
- children[ac++] = frame1;
- children[ac++] = frame2;
- XtManageChildren(children, ac);
- ac = 0;
- children[ac++] = tools_;
- children[ac++] = form1;
- XtManageChildren(children, ac);
- ac = 0;
-}
-
-void edit_label_form_c::changedCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- edit_label_form_p instance = (edit_label_form_p) client_data;
- instance->changedCB ( widget, call_data );
-}
-
-void edit_label_form_c::applyCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- edit_label_form_p instance = (edit_label_form_p) client_data;
- instance->applyCB ( widget, call_data );
-}
-
diff --git a/ecflow_4_0_7/view/src/libui/uierror.cc b/ecflow_4_0_7/view/src/libui/uierror.cc
deleted file mode 100644
index c7af749..0000000
--- a/ecflow_4_0_7/view/src/libui/uierror.cc
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
-** Generated by X-Designer
-*/
-/*
-**LIBS: -lXm -lXt -lX11
-*/
-
-#include <stdlib.h>
-#include <X11/Xatom.h>
-#include <X11/Intrinsic.h>
-#include <X11/Shell.h>
-
-#include <Xm/Xm.h>
-#include <Xm/DialogS.h>
-#include <Xm/MessageB.h>
-#include <Xm/LabelG.h>
-#include <Xm/PushBG.h>
-#include <Xm/SeparatoG.h>
-
-
-#include "uierror.h"
-
-error_shell_p error_shell = (error_shell_p) NULL;
-
-
-
-void error_shell_c::create (Widget parent, char *widget_name)
-{
- /* Widget children[6]; // Children to manage */
- Arg al[64]; /* Arg List */
- register int ac = 0; /* Arg Count */
- Widget button28 = (Widget)NULL;
- Widget button30 = (Widget)NULL;
-
- if ( !widget_name )
- widget_name = "error_shell";
-
- XtSetArg(al[ac], XmNallowShellResize, TRUE); ac++;
- XtSetArg(al[ac], XmNtransient, TRUE); ac++;
- error_shell = XmCreateDialogShell ( parent, widget_name, al, ac );
- ac = 0;
- _xd_rootwidget = error_shell;
- XtSetArg(al[ac], XmNdialogType, XmDIALOG_ERROR); ac++;
- form_ = XmCreateMessageBox ( error_shell, "form_", al, ac );
- ac = 0;
- button28 = XmMessageBoxGetChild ( form_, XmDIALOG_CANCEL_BUTTON );
- label_ = XmMessageBoxGetChild ( form_, XmDIALOG_MESSAGE_LABEL );
- button30 = XmMessageBoxGetChild ( form_, XmDIALOG_OK_BUTTON );
- XtAddCallback (form_, XmNokCallback,&error_shell_c:: okCB, (XtPointer) this);
- XtAddCallback (form_, XmNcancelCallback,&error_shell_c:: cancelCB, (XtPointer) this);
- XtAddCallback (form_, XmNhelpCallback,&error_shell_c:: helpCB, (XtPointer) this);
- XtUnmanageChild ( button28 );
-}
-
-void error_shell_c::helpCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- error_shell_p instance = (error_shell_p) client_data;
- instance->helpCB ( widget, call_data );
-}
-
-void error_shell_c::cancelCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- error_shell_p instance = (error_shell_p) client_data;
- instance->cancelCB ( widget, call_data );
-}
-
-void error_shell_c::okCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- error_shell_p instance = (error_shell_p) client_data;
- instance->okCB ( widget, call_data );
-}
-
diff --git a/ecflow_4_0_7/view/src/libui/uifsb.cc b/ecflow_4_0_7/view/src/libui/uifsb.cc
deleted file mode 100644
index 8942ff7..0000000
--- a/ecflow_4_0_7/view/src/libui/uifsb.cc
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
-** Generated by X-Designer
-*/
-/*
-**LIBS: -lXm -lXt -lX11
-*/
-
-#include <stdlib.h>
-#include <X11/Xatom.h>
-#include <X11/Intrinsic.h>
-#include <X11/Shell.h>
-
-#include <Xm/Xm.h>
-#include <Xm/DialogS.h>
-#include <Xm/FileSB.h>
-#include <Xm/Label.h>
-#include <Xm/List.h>
-#include <Xm/ScrollBar.h>
-#include <Xm/SelectioB.h>
-#include <Xm/TextF.h>
-#include <Xm/LabelG.h>
-#include <Xm/PushBG.h>
-#include <Xm/SeparatoG.h>
-
-
-#include "uifsb.h"
-
-fsb_shell_p fsb_shell = (fsb_shell_p) NULL;
-
-
-
-void fsb_shell_c::create (Widget parent, char *widget_name)
-{
- Widget children[14]; /* Children to manage */
- Arg al[64]; /* Arg List */
- register int ac = 0; /* Arg Count */
- Widget button42 = (Widget)NULL;
- Widget button44 = (Widget)NULL;
-
- if ( !widget_name )
- widget_name = "fsb_shell";
-
- XtSetArg(al[ac], XmNallowShellResize, TRUE); ac++;
- fsb_shell = XmCreateDialogShell ( parent, widget_name, al, ac );
- ac = 0;
- _xd_rootwidget = fsb_shell;
- XtSetArg(al[ac], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); ac++;
- form_ = XmCreateFileSelectionBox ( fsb_shell, "form_", al, ac );
- ac = 0;
- button42 = XmSelectionBoxGetChild ( form_, XmDIALOG_CANCEL_BUTTON );
- button44 = XmSelectionBoxGetChild ( form_, XmDIALOG_OK_BUTTON );
-
-
- label_ = XmCreateLabel ( form_, "label_", al, ac );
- XtAddCallback (form_, XmNokCallback,&fsb_shell_c:: okCB, (XtPointer) this);
- XtAddCallback (form_, XmNcancelCallback,&fsb_shell_c:: cancelCB, (XtPointer) this);
- XtAddCallback (form_, XmNhelpCallback,&fsb_shell_c:: helpCB, (XtPointer) this);
- children[ac++] = label_;
- XtManageChildren(children, ac);
- ac = 0;
-}
-
-void fsb_shell_c::helpCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- fsb_shell_p instance = (fsb_shell_p) client_data;
- instance->helpCB ( widget, call_data );
-}
-
-void fsb_shell_c::cancelCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- fsb_shell_p instance = (fsb_shell_p) client_data;
- instance->cancelCB ( widget, call_data );
-}
-
-void fsb_shell_c::okCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- fsb_shell_p instance = (fsb_shell_p) client_data;
- instance->okCB ( widget, call_data );
-}
-
diff --git a/ecflow_4_0_7/view/src/libui/uijobstatus.cc b/ecflow_4_0_7/view/src/libui/uijobstatus.cc
deleted file mode 100644
index 90da896..0000000
--- a/ecflow_4_0_7/view/src/libui/uijobstatus.cc
+++ /dev/null
@@ -1,150 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #1 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-/*
-** Generated by X-Designer // edited in the lack of X-Designer
-*/
-/*
-**LIBS: -lXm -lXt -lX11
-*/
-
-#include <stdlib.h>
-#include <X11/Xatom.h>
-#include <X11/Intrinsic.h>
-#include <X11/Shell.h>
-
-#include <Xm/Xm.h>
-#include <Xm/DialogS.h>
-#include <Xm/Form.h>
-#include <Xm/PushB.h>
-#include <Xm/RowColumn.h>
-#include <Xm/ScrollBar.h>
-#include <Xm/Text.h>
-#include <Xm/TextF.h>
-
-
-#include "uijobstatus.h"
-
-script_p jobstatus_form = (script_p) NULL;
-
-
-
-void jobstatus_form_c::create (Widget parent, char *widget_name)
-{
- Widget children[4]; /* Children to manage */
- Arg al[64]; /* Arg List */
- register int ac = 0; /* Arg Count */
- Widget scrolledText1 = (Widget)NULL;
- Widget button2 = (Widget)NULL;
- Widget button3 = (Widget)NULL;
- Widget button1 = (Widget)NULL;
-
- if ( !widget_name )
- widget_name = "jobstatus_form";
-
- XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
- jobstatus_form = XmCreateForm ( parent, widget_name, al, ac );
- ac = 0;
- _xd_rootwidget = jobstatus_form;
- XtSetArg(al[ac], XmNeditable, FALSE); ac++;
- XtSetArg(al[ac], XmNcursorPositionVisible, FALSE); ac++;
- XtSetArg(al[ac], XmNeditMode, XmMULTI_LINE_EDIT); ac++;
- text_ = XmCreateScrolledText ( jobstatus_form, "text_", al, ac );
- ac = 0;
- scrolledText1 = XtParent ( text_ );
-
- XtSetArg(al[ac], XmNhighlightThickness, 1); ac++;
- XtSetArg(al[ac], XmNshadowThickness, 1); ac++;
- XtSetArg(al[ac], XmNeditable, FALSE); ac++;
- XtSetArg(al[ac], XmNcursorPositionVisible, FALSE); ac++;
- name_ = XmCreateTextField ( jobstatus_form, "name_", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNspacing, 0); ac++;
- XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
- XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
- XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++;
- tools_ = XmCreateRowColumn ( jobstatus_form, "tools_", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
- XtSetArg(al[ac], XmNmarginHeight, 2); ac++;
- XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
- button2 = XmCreatePushButton ( tools_, "Use external viewer", al, ac );
- ac = 0;
- button3 = XmCreatePushButton ( tools_, "Search", al, ac );
- XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
- XtSetArg(al[ac], XmNmarginHeight, 2); ac++;
- XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
- button1 = XmCreatePushButton ( tools_, "Update", al, ac );
- ac = 0;
-
- XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
- XtSetArg(al[ac], XmNtopWidget, name_); ac++;
- XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
- XtSetValues ( scrolledText1,al, ac );
- ac = 0;
-
- XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
- XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNrightAttachment, XmATTACH_WIDGET); ac++;
- XtSetArg(al[ac], XmNrightOffset, 0); ac++;
- XtSetArg(al[ac], XmNrightWidget, tools_); ac++;
- XtSetValues ( name_,al, ac );
- ac = 0;
-
- XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNtopOffset, 0); ac++;
- XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
- XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
- XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNrightOffset, 0); ac++;
- XtSetValues ( tools_,al, ac );
- ac = 0;
- XtManageChild(text_);
- XtAddCallback (button2, XmNactivateCallback,&jobstatus_form_c:: externalCB, (XtPointer) this);
- XtAddCallback (button3, XmNactivateCallback,&jobstatus_form_c:: searchCB, (XtPointer) this);
- XtAddCallback (button1, XmNactivateCallback,&jobstatus_form_c:: updateCB, (XtPointer) this);
- children[ac++] = button2;
- children[ac++] = button3;
- children[ac++] = button1;
- XtManageChildren(children, ac);
- ac = 0;
- children[ac++] = name_;
- children[ac++] = tools_;
- XtManageChildren(children, ac);
- ac = 0;
-}
-
-void jobstatus_form_c::searchCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- jobstatus_form_p instance = (jobstatus_form_p) client_data;
- instance->searchCB ( widget, call_data );
-}
-
-void jobstatus_form_c::externalCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- jobstatus_form_p instance = (jobstatus_form_p) client_data;
- instance->externalCB ( widget, call_data );
-}
-
-void jobstatus_form_c::updateCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- jobstatus_form_p instance = (jobstatus_form_p) client_data;
- instance->updateCB ( widget, call_data );
-}
-
diff --git a/ecflow_4_0_7/view/src/libui/uijobstatus.h b/ecflow_4_0_7/view/src/libui/uijobstatus.h
deleted file mode 100644
index 1c80d76..0000000
--- a/ecflow_4_0_7/view/src/libui/uijobstatus.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#ifndef _uijobstatus_h
-#define _uijobstatus_h
-
-#define XD_MOTIF
-
-#include <xdclass.h>
-
-class jobstatus_form_c: public xd_XmForm_c {
-public:
- virtual void create (Widget parent, char *widget_name = NULL);
-protected:
- Widget jobstatus_form;
- Widget text_;
- Widget name_;
- Widget tools_;
-public:
- static void searchCB( Widget, XtPointer, XtPointer );
- virtual void searchCB( Widget, XtPointer ) = 0;
- static void externalCB( Widget, XtPointer, XtPointer );
- virtual void externalCB( Widget, XtPointer ) = 0;
- static void updateCB( Widget, XtPointer, XtPointer );
- virtual void updateCB( Widget, XtPointer ) = 0;
-};
-
-typedef jobstatus_form_c *jobstatus_form_p;
-class script;
-typedef script *script_p;
-
-
-extern script_p jobstatus_form;
-
-
-#endif
diff --git a/ecflow_4_0_7/view/src/libui/uimenu.cc b/ecflow_4_0_7/view/src/libui/uimenu.cc
deleted file mode 100644
index 1c197a1..0000000
--- a/ecflow_4_0_7/view/src/libui/uimenu.cc
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
-** Generated by X-Designer
-*/
-/*
-**LIBS: -lXm -lXt -lX11
-*/
-
-#include <stdlib.h>
-#include <X11/Xatom.h>
-#include <X11/Intrinsic.h>
-#include <X11/Shell.h>
-
-#include <Xm/Xm.h>
-#include <Xm/DialogS.h>
-#include <Xm/Form.h>
-#include <Xm/Label.h>
-#include <Xm/List.h>
-#include <Xm/PushB.h>
-#include <Xm/RowColumn.h>
-#include <Xm/ScrollBar.h>
-#include <Xm/Separator.h>
-#include <Xm/TextF.h>
-#include <Xm/CascadeBG.h>
-#include <Xm/LabelG.h>
-
-
-#include "uimenu.h"
-
-menu_form_p menu_form = (menu_form_p) NULL;
-
-
-
-void menu_form_c::create (Widget parent, char *widget_name)
-{
- Widget children[4]; /* Children to manage */
- Arg al[64]; /* Arg List */
- register int ac = 0; /* Arg Count */
- Widget scrolledList1 = (Widget)NULL;
- Widget form1 = (Widget)NULL;
- Widget rowcol1 = (Widget)NULL;
- Widget rowcol2 = (Widget)NULL;
- Widget label1 = (Widget)NULL;
- Widget optionMenu1 = (Widget)NULL;
- Widget label2 = (Widget)NULL;
- Widget cascade1 = (Widget)NULL;
- Widget button1 = (Widget)NULL;
- Widget button2 = (Widget)NULL;
- Widget button3 = (Widget)NULL;
- Widget button4 = (Widget)NULL;
- Widget separator2 = (Widget)NULL;
-
- if ( !widget_name )
- widget_name = "Command menus";
-
- XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
- menu_form = XmCreateForm ( parent, widget_name, al, ac );
- ac = 0;
- _xd_rootwidget = menu_form;
- XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
- form_ = XmCreateForm ( menu_form, "form_", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNvisibleItemCount, 17); ac++;
- XtSetArg(al[ac], XmNlistSizePolicy, XmCONSTANT); ac++;
- list_ = XmCreateScrolledList ( form_, "list_", al, ac );
- ac = 0;
- scrolledList1 = XtParent ( list_ );
-
- form1 = XmCreateForm ( form_, "form1", al, ac );
- XtSetArg(al[ac], XmNentryAlignment, XmALIGNMENT_CENTER); ac++;
- rowcol1 = XmCreateRowColumn ( form1, "rowcol1", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNsensitive, FALSE); ac++;
- add_ = XmCreatePushButton ( rowcol1, "Add", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNsensitive, FALSE); ac++;
- update_ = XmCreatePushButton ( rowcol1, "Update", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNsensitive, FALSE); ac++;
- remove_ = XmCreatePushButton ( rowcol1, "Remove", al, ac );
- ac = 0;
- rowcol2 = XmCreateRowColumn ( form1, "rowcol2", al, ac );
- label1 = XmCreateLabel ( rowcol2, "Title:", al, ac );
- title_ = XmCreateTextField ( rowcol2, "title_", al, ac );
- optionMenu1 = XmCreateOptionMenu ( rowcol2, "optionMenu1", al, ac );
- label2 = XmOptionLabelGadget ( optionMenu1 );
- cascade1 = XmOptionButtonGadget ( optionMenu1 );
- actions_ = XmCreatePulldownMenu ( optionMenu1, "actions_", al, ac );
- button1 = XmCreatePushButton ( actions_, "Ecf command", al, ac );
- button2 = XmCreatePushButton ( actions_, "Separator", al, ac );
- button3 = XmCreatePushButton ( actions_, "Window", al, ac );
- button4 = XmCreatePushButton ( actions_, "Internal", al, ac );
- separator2 = XmCreateSeparator ( form1, "separator2", al, ac );
-
- XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
- XtSetValues ( form_,al, ac );
- ac = 0;
-
- XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNtopOffset, 5); ac++;
- XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNbottomOffset, 5); ac++;
- XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNleftOffset, 5); ac++;
- XtSetArg(al[ac], XmNrightAttachment, XmATTACH_WIDGET); ac++;
- XtSetArg(al[ac], XmNrightOffset, 5); ac++;
- XtSetArg(al[ac], XmNrightWidget, form1); ac++;
- XtSetValues ( scrolledList1,al, ac );
- ac = 0;
-
- XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNtopOffset, 5); ac++;
- XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNbottomOffset, 5); ac++;
- XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
- XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNrightOffset, 5); ac++;
- XtSetValues ( form1,al, ac );
- ac = 0;
-
- XtAddCallback (list_, XmNbrowseSelectionCallback,&menu_form_c:: browseCB, (XtPointer) this);
- XtManageChild(list_);
-
- XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
- XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNbottomOffset, 0); ac++;
- XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNleftOffset, 0); ac++;
- XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNrightOffset, 0); ac++;
- XtSetValues ( rowcol1,al, ac );
- ac = 0;
-
- XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNtopOffset, 0); ac++;
- XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
- XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNleftOffset, 0); ac++;
- XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNrightOffset, 0); ac++;
- XtSetValues ( rowcol2,al, ac );
- ac = 0;
-
- XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
- XtSetArg(al[ac], XmNtopOffset, 0); ac++;
- XtSetArg(al[ac], XmNtopWidget, rowcol2); ac++;
- XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
- XtSetArg(al[ac], XmNbottomOffset, 0); ac++;
- XtSetArg(al[ac], XmNbottomWidget, rowcol1); ac++;
- XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNleftOffset, 0); ac++;
- XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNrightOffset, 0); ac++;
- XtSetValues ( separator2,al, ac );
- ac = 0;
- XtAddCallback (add_, XmNactivateCallback,&menu_form_c:: addCB, (XtPointer) this);
- XtAddCallback (update_, XmNactivateCallback,&menu_form_c:: updateCB, (XtPointer) this);
- XtAddCallback (remove_, XmNactivateCallback,&menu_form_c:: removeCB, (XtPointer) this);
- children[ac++] = add_;
- children[ac++] = update_;
- children[ac++] = remove_;
- XtManageChildren(children, ac);
- ac = 0;
- XtAddCallback (title_, XmNvalueChangedCallback,&menu_form_c:: changedCB, (XtPointer) this);
- children[ac++] = button1;
- children[ac++] = button2;
- children[ac++] = button3;
- children[ac++] = button4;
- XtManageChildren(children, ac);
- ac = 0;
- XtSetArg(al[ac], XmNsubMenuId, actions_); ac++;
- XtSetValues ( cascade1, al, ac );
- ac = 0;
- children[ac++] = label1;
- children[ac++] = title_;
- children[ac++] = optionMenu1;
- XtManageChildren(children, ac);
- ac = 0;
- children[ac++] = rowcol1;
- children[ac++] = rowcol2;
- children[ac++] = separator2;
- XtManageChildren(children, ac);
- ac = 0;
- children[ac++] = form1;
- XtManageChildren(children, ac);
- ac = 0;
- children[ac++] = form_;
- XtManageChildren(children, ac);
- ac = 0;
-}
-
-void menu_form_c::updateCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- menu_form_p instance = (menu_form_p) client_data;
- instance->updateCB ( widget, call_data );
-}
-
-void menu_form_c::changedCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- menu_form_p instance = (menu_form_p) client_data;
- instance->changedCB ( widget, call_data );
-}
-
-void menu_form_c::browseCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- menu_form_p instance = (menu_form_p) client_data;
- instance->browseCB ( widget, call_data );
-}
-
-void menu_form_c::removeCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- menu_form_p instance = (menu_form_p) client_data;
- instance->removeCB ( widget, call_data );
-}
-
-void menu_form_c::addCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- menu_form_p instance = (menu_form_p) client_data;
- instance->addCB ( widget, call_data );
-}
-
-void menu_form_c::menuCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- menu_form_p instance = (menu_form_p) client_data;
- instance->menuCB ( widget, call_data );
-}
-
diff --git a/ecflow_4_0_7/view/src/libui/uitop.cc b/ecflow_4_0_7/view/src/libui/uitop.cc
deleted file mode 100644
index a6bd8f0..0000000
--- a/ecflow_4_0_7/view/src/libui/uitop.cc
+++ /dev/null
@@ -1,1053 +0,0 @@
-/*
-** Generated by X-Designer
-*/
-/*
-**LIBS: -lXm -lXt -lX11
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <X11/Xatom.h>
-#include <X11/Intrinsic.h>
-#include <X11/Shell.h>
-
-#include <Xm/Xm.h>
-#include <Xm/RepType.h>
-#include <Xm/CascadeB.h>
-#include <Xm/DialogS.h>
-#include <Xm/DrawingA.h>
-#include <Xm/Form.h>
-#include <Xm/Label.h>
-#include <Xm/PushB.h>
-#include <Xm/RowColumn.h>
-#include <Xm/ScrollBar.h>
-#include <Xm/ScrolledW.h>
-#include <Xm/Separator.h>
-#include <Xm/ToggleB.h>
-#include <Xm/PushBG.h>
-
-#define XDESIGNER
-#include "ecflowview.h"
-#include "SimpleTree.h"
-#include "show.h"
-#include "top.h"
-#include <Xm/Protocols.h>
-#define main xmain
-#include "Version.hpp"
-
-#include "uitop.h"
-
-XmStringCharSet char_set=XmSTRING_DEFAULT_CHARSET;
-
-void add_accelerator(Widget w,char * acc_text,char * key)
-/* adds an accelerator to a menu option. */
-{
- int ac;
- Arg al[10];
-
- ac=0;
- XtSetArg(al[ac],XmNacceleratorText,
- XmStringCreate(acc_text,XmSTRING_DEFAULT_CHARSET)); ac++;
- XtSetArg(al[ac],XmNaccelerator,key); ac++;
- XtSetValues(w,al,ac);
-}
-/* */
-
-void XDmanage_link ( Widget, XtPointer client_data, XtPointer )
-{
- if ( client_data && *(Widget *)client_data )
- XtManageChild ( *(Widget *)client_data );
-}
-
-void XDunmanage_link ( Widget, XtPointer client_data, XtPointer )
-{
- if ( client_data && *(Widget *)client_data )
- XtUnmanageChild ( *(Widget *)client_data );
-}
-
-void XDpopup_link ( Widget, XtPointer client_data, XtPointer )
-{
- if ( client_data && *(Widget *)client_data )
- XtPopup ( *(Widget *)client_data, XtGrabNone );
-}
-
-void XDpopdown_link ( Widget, XtPointer client_data, XtPointer )
-{
- if ( client_data && *(Widget *)client_data )
- XtPopdown ( *(Widget *)client_data );
-}
-
-void XDmap_link ( Widget, XtPointer client_data, XtPointer )
-{
- if ( client_data && *(Widget *)client_data )
- XtMapWidget (*(Widget *)client_data);
-}
-
-void XDunmap_link ( Widget, XtPointer client_data, XtPointer )
-{
- if ( client_data && *(Widget *)client_data )
- XtUnmapWidget (*(Widget *)client_data);
-}
-
-void XDenable_link ( Widget, XtPointer client_data, XtPointer )
-{
- if ( client_data && *(Widget *)client_data )
- XtSetSensitive (*(Widget *)client_data, TRUE);
-}
-
-void XDdisable_link ( Widget, XtPointer client_data, XtPointer )
-{
- if ( client_data && *(Widget *)client_data )
- XtSetSensitive (*(Widget *)client_data, FALSE);
-}
-
-
-top_p top_shell = (top_p) NULL;
-
-
-
-void top_shell_c::create (Display *display, char *app_name, int app_argc, char **app_argv, char *app_class_name)
-{
- Widget children[17]; /* Children to manage */
- Arg al[64]; /* Arg List */
- register int ac = 0; /* Arg Count */
- XmString xmstrings[16]; /* temporary storage for XmStrings */
- Widget form2 = (Widget)NULL;
- Widget button184 = (Widget)NULL;
- Widget button5 = (Widget)NULL;
- Widget button10 = (Widget)NULL;
- Widget button99 = (Widget)NULL;
- Widget button4 = (Widget)NULL;
- Widget button11 = (Widget)NULL;
- Widget button9 = (Widget)NULL;
- Widget button16 = (Widget)NULL;
- Widget button13 = (Widget)NULL;
- Widget button7 = (Widget)NULL;
- Widget button14 = (Widget)NULL;
- Widget button6 = (Widget)NULL;
- Widget drawingArea1 = (Widget)NULL;
- Widget button8 = (Widget)NULL;
- Widget button177 = (Widget)NULL;
- Widget drawingArea2 = (Widget)NULL;
- Widget button189 = (Widget)NULL;
- Widget scrolledWin1 = (Widget)NULL;
- Widget scrollbar61 = (Widget)NULL;
- Widget scrollbar62 = (Widget)NULL;
- Widget cascade55 = (Widget)NULL;
- Widget menu52 = (Widget)NULL;
- Widget button15 = (Widget)NULL;
- Widget button1 = (Widget)NULL;
- Widget separator3 = (Widget)NULL;
- Widget button194 = (Widget)NULL;
- Widget cascade1 = (Widget)NULL;
- Widget menu1 = (Widget)NULL;
- Widget button2 = (Widget)NULL;
- Widget button3 = (Widget)NULL;
- Widget separator7 = (Widget)NULL;
- Widget button12 = (Widget)NULL;
- Widget snapshot = (Widget)NULL;
- Widget cascade56 = (Widget)NULL;
- Widget separator64 = (Widget)NULL;
- Widget separator65 = (Widget)NULL;
- Widget cascade4 = (Widget)NULL;
- Widget toggle15 = (Widget)NULL;
- Widget toggle16 = (Widget)NULL;
- Widget toggle17 = (Widget)NULL;
- // Widget toggle18 = (Widget)NULL;
- Widget toggle19 = (Widget)NULL;
- Widget toggle20 = (Widget)NULL;
- Widget cascade5 = (Widget)NULL;
- Widget toggle7 = (Widget)NULL;
- Widget toggle8 = (Widget)NULL;
- Widget toggle9 = (Widget)NULL;
- Widget toggle10 = (Widget)NULL;
- Widget toggle11 = (Widget)NULL;
- Widget toggle12 = (Widget)NULL;
- Widget toggle13 = (Widget)NULL;
- Widget toggle14 = (Widget)NULL;
- Widget toggle39 = (Widget)NULL;
- Widget toggle40 = (Widget)NULL;
- Widget toggle73 = (Widget)NULL;
- Widget toggle41 = (Widget)NULL;
- Widget cascade6 = (Widget)NULL;
- // Widget cascade7 = (Widget)NULL;
- Widget toggle66 = (Widget)NULL;
- Widget toggle67 = (Widget)NULL;
- Widget toggle68 = (Widget)NULL;
- Widget toggle69 = (Widget)NULL;
- Widget toggle70 = (Widget)NULL;
- // Widget toggle71 = (Widget)NULL;
- Widget toggle72 = (Widget)NULL;
- // Widget toggle74 = (Widget)NULL; Widget toggle75 = (Widget)NULL; Widget toggle76 = (Widget)NULL; Widget toggle77 = (Widget)NULL;
- Widget toggle78 = (Widget)NULL;
- Widget toggle79 = (Widget)NULL;
- Widget cascade58 = (Widget)NULL;
- Widget cascade3 = (Widget)NULL;
- Widget menu53 = (Widget)NULL;
- Widget button197 = (Widget)NULL;
- Widget button198 = (Widget)NULL;
- Widget separator5 = (Widget)NULL;
-
- if ( !app_class_name )
- app_class_name = appName;
-
- std::string title = appName;
- title += " (" + ecf::Version::raw();
-#ifdef DEBUG
- title += "-debug";
-#endif
- title += ")";
-
- XtSetArg(al[ac], XmNallowShellResize, FALSE); ac++;
- XtSetArg(al[ac], XmNtitle, title.c_str()); ac++;
- XtSetArg(al[ac], XmNiconName, appName); ac++;
- XtSetArg(al[ac], XmNargc, app_argc); ac++;
- XtSetArg(al[ac], XmNargv, app_argv); ac++;
- top_shell = XtAppCreateShell ( app_name, app_class_name, applicationShellWidgetClass, display, al, ac );
- ac = 0;
- _xd_rootwidget = top_shell;
- XmAddWMProtocolCallback( top_shell, XmInternAtom(XtDisplay(top_shell), "WM_DELETE_WINDOW", False),&top_shell_c:: quitCB, (XtPointer) this);
- XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
- form_ = XmCreateForm ( top_shell, "form_", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
- form2 = XmCreateForm ( form_, "form2", al, ac );
- ac = 0;
- xmstrings[0] = XmStringCreateLtoR ( "-\n", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
- message_ = XmCreateLabel ( form2, "message_", al, ac );
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNspacing, 0); ac++;
- XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
- XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
- XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++;
- XtSetArg(al[ac], XmNentryAlignment, XmALIGNMENT_CENTER); ac++;
- tools_ = XmCreateRowColumn ( form2, "tools_", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
- XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
- XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
-
- button184 = XmCreatePushButton ( tools_, "Info", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
- XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
- XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
-XtSetArg(al[ac],XmNmnemonic,'i'); ac++; /* mnemonic */
-
-
- button5 = XmCreatePushButton ( tools_, "Script", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
- XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
- XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
-XtSetArg(al[ac],XmNmnemonic,'s'); ac++; /* mnemonic */
-
- button10 = XmCreatePushButton ( tools_, "Manual", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
- XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
- XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
-XtSetArg(al[ac],XmNmnemonic,'m'); ac++; /* mnemonic */
-
- button99 = XmCreatePushButton ( tools_, "Jobstatus", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
- XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
- XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
- button4 = XmCreatePushButton ( tools_, "Output", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
- XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
- XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
- button11 = XmCreatePushButton ( tools_, "Triggers", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
- XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
- XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
- button9 = XmCreatePushButton ( tools_, "Why?", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
- XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
- XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
- button16 = XmCreatePushButton ( tools_, "Check", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
- XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
- XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
- button13 = XmCreatePushButton ( tools_, "Time line", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
- XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
- XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
- button7 = XmCreatePushButton ( tools_, "Variables", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
- XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
- XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
- button14 = XmCreatePushButton ( tools_, "Messages", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
- XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
- XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
- button6 = XmCreatePushButton ( tools_, "Edit", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNwidth, 10); ac++;
- XtSetArg(al[ac], XmNheight, 10); ac++;
- drawingArea1 = XmCreateDrawingArea ( tools_, "drawingArea1", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
- XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
- XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
- button8 = XmCreatePushButton ( tools_, "Chat", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
- XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
- XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
- button177 = XmCreatePushButton ( tools_, "Search", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNwidth, 10); ac++;
- XtSetArg(al[ac], XmNheight, 10); ac++;
- drawingArea2 = XmCreateDrawingArea ( tools_, "drawingArea2", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
- XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
- XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
- button189 = XmCreatePushButton ( tools_, "Status", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNscrollingPolicy, XmAUTOMATIC); ac++;
- scrolledWin1 = XmCreateScrolledWindow ( form_, "scrolledWin1", al, ac );
- ac = 0;
-
- XtSetArg(al[ac], XmNhorizontalScrollBar, &scrollbar61 ); ac++;
- XtSetArg(al[ac], XmNverticalScrollBar, &scrollbar62 ); ac++;
- XtGetValues(scrolledWin1, al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
- XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
- trees_ = XmCreateRowColumn ( scrolledWin1, "trees_", al, ac );
- ac = 0;
- menu_bar = XmCreateMenuBar ( form_, "menu_bar", al, ac );
-
- cascade55 = XmCreateCascadeButton ( menu_bar, "File", al, ac );
-
- if (1) {
- XmString label_str = XmStringCreateLocalized ("File");
- XtSetArg(al[ac], XmNmnemonic, XStringToKeysym("F")); ac++;
- XtSetArg(al[ac], XmNlabelString, label_str); ac++;
- XtSetArg(al[ac], XmNaccelerator, "Ctrl<Key>F"); ac++;
- XtSetArg(al[ac], XmNacceleratorText,
- XmStringCreateLocalized("Ctrl+F")); ac++;
- // XmStringFree(label_str);
- }
-
- XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++;
- menu52 = XmCreatePulldownMenu ( menu_bar, "m_file", al, ac );
- ac = 0;
- button15 = XmCreatePushButton ( menu52, "Login", al, ac );
- add_accelerator(button15, "Ctrl+L", "Ctrl<Key>L");
-
- XtSetArg(al[ac], XmNsensitive, FALSE); ac++;
- button1 = XmCreatePushButton ( menu52, "Scan network...", al, ac );
- // add_accelerator(button1, "Ctrl+S", "Ctrl<Key>S");
-
- XtSetArg(al[ac], XmNheight, 2); ac++;
- XtSetArg(al[ac], XmNmargin, 0); ac++;
- separator3 = XmCreateSeparator ( menu52, "separator3", al, ac );
- ac = 0;
- if (1) {
- XmString label_str = XmStringCreateLocalized ("Quit");
- XtSetArg(al[ac], XmNmnemonic, XStringToKeysym("Q")); ac++;
- XtSetArg(al[ac], XmNlabelString, label_str); ac++;
- XtSetArg(al[ac], XmNaccelerator, "Ctrl<Key>Q"); ac++;
- XtSetArg(al[ac], XmNacceleratorText,
- XmStringCreateLocalized("Ctrl+Q")); ac++;
- }
- button194 = XmCreatePushButtonGadget ( menu52, "Quit", al, ac );
- // add_accelerator(button194, "Ctrl+Q", "Ctrl<Key>Q");
-
- if (1) { ac = 0;
- XmString label_str = XmStringCreateLocalized ("Edit");
- XtSetArg(al[ac], XmNmnemonic, XStringToKeysym("E")); ac++;
- XtSetArg(al[ac], XmNlabelString, label_str); ac++;
- XtSetArg(al[ac], XmNaccelerator, "Ctrl<Key>E"); ac++;
- XtSetArg(al[ac], XmNacceleratorText, XmStringCreateLocalized("Ctrl+E")); ac++;
- }
- cascade1 = XmCreateCascadeButton ( menu_bar, "Edit", al, ac );
- // add_accelerator(cascade1, "Ctrl+E", "Ctrl<Key>E");
-
- XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++;
- menu1 = XmCreatePulldownMenu ( menu_bar, "menu1", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNsensitive, FALSE); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Servers menu...", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- button2 = XmCreatePushButton ( menu1, "button2", al, ac );
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNsensitive, FALSE); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Command menu...", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- button3 = XmCreatePushButton ( menu1, "button3", al, ac );
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- separator7 = XmCreateSeparator ( menu1, "separator7", al, ac );
- xmstrings[0] = XmStringCreateLtoR ( "Preferences...", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- button12 = XmCreatePushButton ( menu1, "pref", al, ac );
-
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- // separator7 = XmCreateSeparator ( menu1, "separator7", al, ac );
- xmstrings[0] = XmStringCreateLtoR ( "Snapshot", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- snapshot = XmCreatePushButton ( menu1, "snap", al, ac );
-
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
-
- cascade56 = XmCreateCascadeButton ( menu_bar, "Show", al, ac );
- // add_accelerator(cascade56, "Ctrl<Key>S", "Ctrl+S");
-
- XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++;
- show0_ = XmCreatePulldownMenu ( menu_bar, "show0_", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNuserData, new show(show::unknown)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Unknown", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- show_unknown = XmCreateToggleButton ( show0_, "unknown", al, ac );
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::suspended)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Suspended", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- show_suspended = XmCreateToggleButton ( show0_, "suspended", al, ac );
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::complete)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Complete", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- show_complete = XmCreateToggleButton ( show0_, "complete", al, ac );
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::queued)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Queued", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- show_queued = XmCreateToggleButton ( show0_, "queued", al, ac );
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::submitted)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Submitted", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- show_submitted = XmCreateToggleButton ( show0_, "submitted", al, ac );
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::active)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Active", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- show_active = XmCreateToggleButton ( show0_, "active", al, ac );
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::aborted)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Aborted", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- show_aborted = XmCreateToggleButton ( show0_, "aborted", al, ac );
-
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- separator64 = XmCreateSeparator ( show0_, "separator64", al, ac );
- cascade4 = XmCreateCascadeButton ( show0_, "Special", al, ac );
- XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++;
- show2_ = XmCreatePulldownMenu ( show0_, "show2_", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNuserData, new show(show::time_dependant)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Time dependent", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- toggle15 = XmCreateToggleButton ( show2_, "toggle15", al, ac );
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::late_nodes)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Late nodes", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- toggle16 = XmCreateToggleButton ( show2_, "toggle16", al, ac );
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::waiting_nodes)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Waiting nodes", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- toggle17 = XmCreateToggleButton ( show2_, "toggle17", al, ac );
- /* ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::migrated_nodes)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Migrated nodes", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- toggle18 = XmCreateToggleButton ( show2_, "toggle18", al, ac ); */
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::rerun_tasks)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Rerun tasks", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- toggle19 = XmCreateToggleButton ( show2_, "toggle19", al, ac );
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::nodes_with_messages)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Nodes with messages", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- toggle20 = XmCreateToggleButton ( show2_, "toggle20", al, ac );
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- cascade5 = XmCreateCascadeButton ( show0_, "Type", al, ac );
- XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++;
- show1_ = XmCreatePulldownMenu ( show0_, "show1_", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNuserData, new show(show::label)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Labels", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- toggle7 = XmCreateToggleButton ( show1_, "toggle7", al, ac );
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::meter)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Meters", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- toggle8 = XmCreateToggleButton ( show1_, "toggle8", al, ac );
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::event)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Events", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- toggle9 = XmCreateToggleButton ( show1_, "toggle9", al, ac );
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::repeat)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Repeats", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- toggle10 = XmCreateToggleButton ( show1_, "toggle10", al, ac );
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::time)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Times", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- toggle11 = XmCreateToggleButton ( show1_, "toggle11", al, ac );
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::date)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Dates", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- toggle12 = XmCreateToggleButton ( show1_, "toggle12", al, ac );
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::trigger)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Triggers", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- toggle13 = XmCreateToggleButton ( show1_, "toggle13", al, ac );
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::variable)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Variables", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- toggle14 = XmCreateToggleButton ( show1_, "toggle14", al, ac );
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::genvar)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Generated variables", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- toggle39 = XmCreateToggleButton ( show1_, "toggle39", al, ac );
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::late)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Late", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- toggle40 = XmCreateToggleButton ( show1_, "toggle40", al, ac );
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::limit)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Limits", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- toggle73 = XmCreateToggleButton ( show1_, "toggle73", al, ac );
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::inlimit)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Limiters", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- toggle41 = XmCreateToggleButton ( show1_, "toggle41", al, ac );
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- cascade6 = XmCreateCascadeButton ( show0_, "Icons", al, ac );
- XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++;
- show3_ = XmCreatePulldownMenu ( show0_, "show3_", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNuserData, new show(show::time_icon)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Time icons", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- toggle66 = XmCreateToggleButton ( show3_, "time_icon", al, ac );
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::date_icon)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Date icons", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- toggle67 = XmCreateToggleButton ( show3_, "date_icon", al, ac );
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::late_icon)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Late icons", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- toggle68 = XmCreateToggleButton ( show3_, "late_icon", al, ac );
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::waiting_icon)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Waiting icons", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- toggle69 = XmCreateToggleButton ( show3_, "waiting_icon", al, ac );
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::rerun_icon)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Rerun icons", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- toggle70 = XmCreateToggleButton ( show3_, "rerun_icon", al, ac );
- /* ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::migrated_icon)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Migrated icons", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- toggle71 = XmCreateToggleButton ( show3_, "migrated_icon", al, ac ); */
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::message_icon)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Message icons", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- toggle72 = XmCreateToggleButton ( show3_, "message_icon", al, ac );
-
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::defstatus_icon)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Complete icons", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- toggle78 = XmCreateToggleButton ( show3_, "defstatus_icon", al, ac );
-
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::zombie_icon)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Zombie icons", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- toggle79 = XmCreateToggleButton ( show3_, "zombie_icon", al, ac );
-
- /* 20110125 */
- separator65 = XmCreateSeparator ( show0_, "separator65", al, ac );
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::all)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "all", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- show_all = XmCreateToggleButton ( show0_, "all", al, ac );
- // show_all = XmCreatePushButton ( show0_, "all", al, ac );
- // XtAddCallback (show_all, XmNactivateCallback,&top_shell_c::show2CB, (XtPointer) this);
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNuserData, new show(show::none)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "none", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- show_none = XmCreateToggleButton ( show0_, "none", al, ac );
- // show_none = XmCreatePushButton ( show0_, "none", al, ac );
- // XtAddCallback (show_none, XmNactivateCallback,&top_shell_c::show2CB, (XtPointer) this);
-
- /* ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- XtSetArg(al[ac], XmNsensitive, XCDP_COMPARE_ENABLED); ac++;
- XtSetArg(al[ac], XmNsensitive, getenv("XCDP_COMPARE_ENABLED")); ac++;
- cascade7 = XmCreateCascadeButton ( show0_, "Compare", al, ac );
- XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++;
- show4_ = XmCreatePulldownMenu ( show0_, "show4_", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNuserData, new show(show::compare_variables)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Variables", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- toggle75 = XmCreateToggleButton ( show4_, "compare_variables", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNuserData, new show(show::compare_scripts)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Scripts", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- toggle74 = XmCreateToggleButton ( show4_, "compare_scripts", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNuserData, new show(show::compare_includes)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Includes", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- toggle76 = XmCreateToggleButton ( show4_, "compare_includes", al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNuserData, new show(show::compare_outputs)); ac++;
- xmstrings[0] = XmStringCreateLtoR ( "Outputs", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
- XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
- toggle77 = XmCreateToggleButton ( show4_, "compare_outputs", al, ac );
- */
- ac = 0;
- XmStringFree ( xmstrings [ 0 ] );
- cascade58 = XmCreateCascadeButton ( menu_bar, "Servers", al, ac );
- XtSetArg(al[ac], XmNnumColumns, 3); ac++;
- XtSetArg(al[ac], XmNpacking, XmPACK_COLUMN); ac++;
- XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++;
- XtSetArg(al[ac], XmNradioAlwaysOne, TRUE); ac++;
- XtSetArg(al[ac], XmNradioBehavior, FALSE); ac++;
- servers_menu_ = XmCreatePulldownMenu ( menu_bar, "servers_menu_", al, ac );
- ac = 0;
- cascade3 = XmCreateCascadeButton ( menu_bar, "Windows", al, ac );
- XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++;
- windows_menu_ = XmCreatePulldownMenu ( menu_bar, "windows_menu_", al, ac );
- ac = 0;
- help = XmCreateCascadeButton ( menu_bar, "Help", al, ac );
- XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++;
- menu53 = XmCreatePulldownMenu ( menu_bar, "menu53", al, ac );
- ac = 0;
- button197 = XmCreatePushButton ( menu53, "Help", al, ac );
- XtSetArg(al[ac], XmNmenuHelpWidget, help); ac++;
- button198 = XmCreatePushButton ( menu53, "Version", al, ac );
- XtSetValues ( menu_bar,al, ac );
-
- ac = 0;
- separator5 = XmCreateSeparator ( form_, "separator5", al, ac );
-
- XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
- XtSetArg(al[ac], XmNtopOffset, 0); ac++;
- XtSetArg(al[ac], XmNtopWidget, menu_bar); ac++;
- XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
- XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNleftOffset, 0); ac++;
- XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
- XtSetValues ( form2,al, ac );
- ac = 0;
-
- XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
- XtSetArg(al[ac], XmNtopWidget, separator5); ac++;
- XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
- XtSetValues ( scrolledWin1,al, ac );
- ac = 0;
-
- XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNtopOffset, 0); ac++;
- XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
- XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNleftOffset, 0); ac++;
- XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNrightOffset, 0); ac++;
- XtSetValues ( menu_bar,al, ac );
- ac = 0;
-
- XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
- XtSetArg(al[ac], XmNtopWidget, form2); ac++;
- XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
- XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
- XtSetValues ( separator5,al, ac );
- ac = 0;
-
- XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
- XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNrightAttachment, XmATTACH_WIDGET); ac++;
- XtSetArg(al[ac], XmNrightWidget, tools_); ac++;
- XtSetValues ( message_,al, ac );
- ac = 0;
-
- XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
- XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
- XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
- XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
- XtSetValues ( tools_,al, ac );
- ac = 0;
- XtAddCallback (button184, XmNactivateCallback,&top_shell_c:: windowCB, (XtPointer) this);
- XtAddCallback (button5, XmNactivateCallback,&top_shell_c:: windowCB, (XtPointer) this);
- XtAddCallback (button10, XmNactivateCallback,&top_shell_c:: windowCB, (XtPointer) this);
- XtAddCallback (button99, XmNactivateCallback,&top_shell_c:: windowCB, (XtPointer) this);
- XtAddCallback (button4, XmNactivateCallback,&top_shell_c:: windowCB, (XtPointer) this);
- XtAddCallback (button11, XmNactivateCallback,&top_shell_c:: windowCB, (XtPointer) this);
- XtAddCallback (button9, XmNactivateCallback,&top_shell_c:: windowCB, (XtPointer) this);
- XtAddCallback (button16, XmNactivateCallback,&top_shell_c:: windowCB, (XtPointer) this);
- XtAddCallback (button13, XmNactivateCallback,&top_shell_c:: windowCB, (XtPointer) this);
- XtAddCallback (button7, XmNactivateCallback,&top_shell_c:: windowCB, (XtPointer) this);
- XtAddCallback (button14, XmNactivateCallback,&top_shell_c:: windowCB, (XtPointer) this);
- XtAddCallback (button6, XmNactivateCallback,&top_shell_c:: windowCB, (XtPointer) this);
- // XtAddCallback (button8, XmNactivateCallback,&top_shell_c:: chatCB, (XtPointer) this);
- XtAddCallback (button177, XmNactivateCallback,&top_shell_c:: searchCB, (XtPointer) this);
- XtAddCallback (button189, XmNactivateCallback,&top_shell_c:: statusCB, (XtPointer) this);
- children[ac++] = button184;
- children[ac++] = button5;
- children[ac++] = button10;
- children[ac++] = button99;
- children[ac++] = button4;
- children[ac++] = button11;
- children[ac++] = button9;
- children[ac++] = button16;
- children[ac++] = button13;
- children[ac++] = button7;
- children[ac++] = button14;
- children[ac++] = button6;
- children[ac++] = drawingArea1;
- // children[ac++] = button8;
- children[ac++] = button177;
- children[ac++] = drawingArea2;
- children[ac++] = button189;
- XtManageChildren(children, ac);
- ac = 0;
- children[ac++] = message_;
- children[ac++] = tools_;
- XtManageChildren(children, ac);
- ac = 0;
- children[ac++] = trees_;
- XtManageChildren(children, ac);
- ac = 0;
- XmScrolledWindowSetAreas(scrolledWin1, scrollbar61, scrollbar62, trees_ );
- XtAddCallback (button15, XmNactivateCallback,&top_shell_c:: loginCB, (XtPointer) this);
- XtAddCallback (button1, XmNactivateCallback,&top_shell_c:: serverCB, (XtPointer) this);
- XtAddCallback (button194, XmNactivateCallback,&top_shell_c:: quitCB, (XtPointer) this);
- children[ac++] = button15;
- children[ac++] = button1;
- children[ac++] = separator3;
- children[ac++] = button194;
- XtManageChildren(children, ac);
- ac = 0;
- XtSetArg(al[ac], XmNsubMenuId, menu52); ac++;
- XtSetValues ( cascade55, al, ac );
- ac = 0;
- XtAddCallback (button12, XmNactivateCallback,&top_shell_c:: prefCB, (XtPointer) this);
- XtAddCallback (snapshot, XmNactivateCallback,&top_shell_c:: snapshotCB, (XtPointer) this);
- children[ac++] = button2;
- children[ac++] = button3;
- children[ac++] = separator7;
- children[ac++] = button12;
- children[ac++] = snapshot;
- XtManageChildren(children, ac);
- ac = 0;
- XtSetArg(al[ac], XmNsubMenuId, menu1); ac++;
- XtSetValues ( cascade1, al, ac );
- ac = 0;
- XtAddCallback (show0_, XmNentryCallback,&top_shell_c:: showCB, (XtPointer) this);
- XtAddCallback (show2_, XmNentryCallback,&top_shell_c:: showCB, (XtPointer) this);
- children[ac++] = toggle15;
- children[ac++] = toggle16;
- children[ac++] = toggle17;
- // children[ac++] = toggle18;
- children[ac++] = toggle19;
- children[ac++] = toggle20;
- XtManageChildren(children, ac);
- ac = 0;
- XtSetArg(al[ac], XmNsubMenuId, show2_); ac++;
- XtSetValues ( cascade4, al, ac );
- ac = 0;
- XtAddCallback (show1_, XmNentryCallback,&top_shell_c:: showCB, (XtPointer) this);
- children[ac++] = toggle7;
- children[ac++] = toggle8;
- children[ac++] = toggle9;
- children[ac++] = toggle10;
- children[ac++] = toggle11;
- children[ac++] = toggle12;
- children[ac++] = toggle13;
- children[ac++] = toggle14;
- children[ac++] = toggle39;
- children[ac++] = toggle40;
- children[ac++] = toggle73;
- children[ac++] = toggle41;
- XtManageChildren(children, ac);
- ac = 0;
- XtSetArg(al[ac], XmNsubMenuId, show1_); ac++;
- XtSetValues ( cascade5, al, ac );
- ac = 0;
- XtAddCallback (show3_, XmNentryCallback,&top_shell_c:: showCB, (XtPointer) this);
- children[ac++] = toggle66;
- children[ac++] = toggle67;
- children[ac++] = toggle68;
- children[ac++] = toggle69;
- children[ac++] = toggle70;
- // children[ac++] = toggle71;
- children[ac++] = toggle72;
- children[ac++] = toggle78;
- children[ac++] = toggle79;
- XtManageChildren(children, ac);
- ac = 0;
- XtSetArg(al[ac], XmNsubMenuId, show3_); ac++;
- XtSetValues ( cascade6, al, ac );
-
- /* ac = 0;
- XtAddCallback (show4_, XmNentryCallback,&top_shell_c:: showCB, (XtPointer) this);
- children[ac++] = toggle74;
- children[ac++] = toggle75;
- children[ac++] = toggle76;
- children[ac++] = toggle77;
- XtManageChildren(children, ac);
- ac = 0;
- XtSetArg(al[ac], XmNsubMenuId, show4_); ac++;
- XtSetValues ( cascade7, al, ac ); */
-
- ac = 0;
- children[ac++] = show_unknown;
- children[ac++] = show_suspended;
- children[ac++] = show_complete;
- children[ac++] = show_queued;
- children[ac++] = show_submitted;
- children[ac++] = show_active;
- children[ac++] = show_aborted;
- children[ac++] = separator64;
- children[ac++] = cascade4;
- children[ac++] = cascade5;
- children[ac++] = cascade6;
-
- children[ac++] = separator65;
- children[ac++] = show_all;
- children[ac++] = show_none;
-
- // children[ac++] = cascade7;
- XtManageChildren(children, ac);
- ac = 0;
- XtSetArg(al[ac], XmNsubMenuId, show0_); ac++;
- XtSetValues ( cascade56, al, ac );
- ac = 0;
- XtSetArg(al[ac], XmNsubMenuId, servers_menu_); ac++;
- XtSetValues ( cascade58, al, ac );
- ac = 0;
- XtAddCallback (windows_menu_, XmNentryCallback,&top_shell_c:: windowsCB, (XtPointer) this);
- XtSetArg(al[ac], XmNsubMenuId, windows_menu_); ac++;
- XtSetValues ( cascade3, al, ac );
- ac = 0;
- XtAddCallback (button197, XmNactivateCallback,&top_shell_c:: helpCB, (XtPointer) this);
- XtAddCallback (button198, XmNactivateCallback,&top_shell_c:: releaseCB, (XtPointer) this);
- children[ac++] = button197;
- children[ac++] = button198;
- XtManageChildren(children, ac);
- ac = 0;
- XtSetArg(al[ac], XmNsubMenuId, menu53); ac++;
- XtSetValues ( help, al, ac );
- ac = 0;
- children[ac++] = cascade55;
- children[ac++] = cascade1;
- children[ac++] = cascade56;
- children[ac++] = cascade58;
- children[ac++] = cascade3;
- children[ac++] = help;
- XtManageChildren(children, ac);
- ac = 0;
- children[ac++] = form2;
- children[ac++] = scrolledWin1;
- children[ac++] = menu_bar;
- children[ac++] = separator5;
- XtManageChildren(children, ac);
- ac = 0;
- XtManageChild ( form_);
-}
-
-void top_shell_c::loginCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- top_shell_p instance = (top_shell_p) client_data;
- instance->loginCB ( widget, call_data );
-}
-
-void top_shell_c::prefCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- top_shell_p instance = (top_shell_p) client_data;
- instance->prefCB ( widget, call_data );
-}
-
-void top_shell_c::helpCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- top_shell_p instance = (top_shell_p) client_data;
- instance->helpCB ( widget, call_data );
-}
-
-void top_shell_c::releaseCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- top_shell_p instance = (top_shell_p) client_data;
- instance->releaseCB ( widget, call_data );
-}
-
-void top_shell_c::searchCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- top_shell_p instance = (top_shell_p) client_data;
- instance->searchCB ( widget, call_data );
-}
-
-void top_shell_c::windowsCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- top_shell_p instance = (top_shell_p) client_data;
- instance->windowsCB ( widget, call_data );
-}
-
-void top_shell_c::chatCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- top_shell_p instance = (top_shell_p) client_data;
- instance->chatCB ( widget, call_data );
-}
-
-void top_shell_c::showCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- top_shell_p instance = (top_shell_p) client_data;
- instance->showCB ( widget, call_data );
-}
-
-void top_shell_c::serverCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- top_shell_p instance = (top_shell_p) client_data;
- instance->serverCB ( widget, call_data );
-}
-
-void top_shell_c::statusCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- top_shell_p instance = (top_shell_p) client_data;
- instance->statusCB ( widget, call_data );
-}
-
-void top_shell_c::snapshotCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- top_shell_p instance = (top_shell_p) client_data;
- instance->snapshotCB ( widget, call_data );
-}
-
-void top_shell_c::windowCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- top_shell_p instance = (top_shell_p) client_data;
- instance->windowCB ( widget, call_data );
-}
-
-void top_shell_c::quitCB( Widget widget, XtPointer client_data, XtPointer call_data )
-{
- top_shell_p instance = (top_shell_p) client_data;
- instance->quitCB ( widget, call_data );
-}
-
-XtAppContext app_context;
-Display *display;
-// sym_entry_type *rp = NULL;
-
-int main(int argc, char **argv)
-{
- XtSetLanguageProc ((XtAppContext) NULL,
- (XtLanguageProc) NULL,
- (XtPointer) NULL);
- XtToolkitInitialize ();
- app_context = XtCreateApplicationContext ();
- display = XtOpenDisplay (app_context, NULL, argv[0], appName,
- NULL, 0, &argc, argv);
- if (!display) {
- printf("%s: can't open display, exiting...\n", argv[0]);
- exit (-1);
- }
-
- XmRepTypeInstallTearOffModelConverter();
-
- top_shell = new top;
- top_shell->create ( display, argv[0], argc, argv, appName );
- XtRealizeWidget (top_shell->xd_rootwidget());
- // UilDumpSymbolTable(rp);
-
- XtAppMainLoop (app_context);
-
- exit (0);
-
- return 0;
-
- /*
- ./bin/gcc-4.5/debug/ecflowview -geometry=640x880+620+240
- -display -bg -fg
- */
-
-}
-
diff --git a/ecflow_4_0_7/view/src/libxec/xec_Cursor.c b/ecflow_4_0_7/view/src/libxec/xec_Cursor.c
deleted file mode 100644
index 294ab68..0000000
--- a/ecflow_4_0_7/view/src/libxec/xec_Cursor.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include <X11/X.h>
-#include <X11/cursorfont.h>
-#include <Xm/Xm.h>
-
-/*----------------------------------------------------
-
- Set the cursor to a watch shape.
- Usualy pass the Top Shell as argument.
-
-----------------------------------------------------*/
-
-void xec_SetWatchCursor(w)
-Widget w;
-{
- static Cursor watch = 0;
-
- if(!watch)
- watch = XCreateFontCursor(XtDisplay(w),XC_watch);
-
- XDefineCursor(XtDisplay(w),XtWindow(w),watch);
- XmUpdateDisplay(w);
-}
-
-/*----------------------------------------------------
-
- Reset the cursor to its default shape.
- Usualy pass the Top Shell as argument.
-
-----------------------------------------------------*/
-
-void xec_ResetCursor(w)
-Widget w;
-{
- XUndefineCursor(XtDisplay(w),XtWindow(w));
- XmUpdateDisplay(w);
-}
-
diff --git a/ecflow_4_0_7/view/src/libxec/xec_Label.c b/ecflow_4_0_7/view/src/libxec/xec_Label.c
deleted file mode 100644
index 2c724b5..0000000
--- a/ecflow_4_0_7/view/src/libxec/xec_Label.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <Xm/Xm.h>
-#include "xec.h"
-
-/*-----------------------------------------------
-
- Change the title of a Label or Button
-
--------------------------------------------------*/
-
-void xec_SetLabel(Widget w,const char *title)
-{
- XmString s = xec_NewString(title);
- XtVaSetValues(w,XmNlabelString,s,NULL);
- XmStringFree(s);
-}
-
-void xec_VaSetLabel(Widget w,const char *fmt,...)
-{
- va_list args;
- char str[1000]; /* DANGER: Fixed buffer size */
- va_start(args,fmt);
- vsprintf(str, fmt, args);
- xec_SetLabel(w,str);
- va_end(args);
-}
diff --git a/ecflow_4_0_7/view/src/libxec/xec_List.c b/ecflow_4_0_7/view/src/libxec/xec_List.c
deleted file mode 100644
index f1ae405..0000000
--- a/ecflow_4_0_7/view/src/libxec/xec_List.c
+++ /dev/null
@@ -1,276 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #2 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include <Xm/Xm.h>
-#include <Xm/ListP.h>
-#include <stdio.h>
-#include <errno.h>
-#include <stdarg.h>
-#include "xec.h"
-
-
-/*-----------------------------------------------------
-
- Remove one line to a list
-
-------------------------------------------------------*/
-
-void xec_RemoveListItem(Widget w,char *p)
-{
- XmString item= XmStringCreateSimple(p);
- XmListDeleteItem(w,item);
- XmStringFree(item);
-}
-
-void xec_ListItemSelect(Widget w,const char* p)
-{
- XmString item= XmStringCreateSimple((char*)p);
- int n = XmListItemPos(w,item);
-
- XmListDeselectAllItems(w);
- if(n) {
- int vis_count;
- XtVaGetValues(w,XmNvisibleItemCount,&vis_count,NULL);
- XmListSelectPos(w,n,False);
- if(n<((XmListWidget)w)->list.top_position ||
- n > ((XmListWidget)w)->list.top_position + vis_count)
- XmListSetPos(w,n);
- }
-
- XmStringFree(item);
-}
-
-#if 0
-/*----------------------------------------------------
-
- Add to a list with max number of items
-
------------------------------------------------------*/
-
-void xec_AddListMax(Widget w,int max,char* p)
-{
- ARG_DEF(1);
- int n;
-
- SetArg(XmNitemCount,&n);
- GetValues(w);
- if(n>=max) XmListDeletePos(w,1);
- xec_AddListItem(w,p);
-
- SetArg(XmNitemCount,&n);
- GetValues(w);
- XmListSetBottomPos(w,n);
-}
-
-void xec_VaAddListMax(Widget w,int max,char *fmt,...)
-{
- va_list args;
- char str[1000]; /* DANGER: Fixed buffer size */
-
- va_start(args,fmt);
- vsprintf(str, fmt, args);
- xec_AddListMax(w,max,str);
- va_end(args);
-}
-
-#endif
-
-void xec_ListSelectAll(Widget w)
-{
- int n,i;
- XtVaGetValues(w,XmNitemCount,&n,NULL);
- XmListDeselectAllItems(w);
- for(i=1;i<=n;i++) XmListSelectPos(w,i,False);
-
-}
-
-
-/*-----------------------------------------------------
-
- Add one line to a list
-
-------------------------------------------------------*/
-
-void xec_AddListItem(Widget w,char *p)
-{
- XmString item= XmStringCreateSimple(p);
- XmListAddItemUnselected(w,item,0);
- XmStringFree(item);
-}
-
-Boolean xec_AddListItemUnique(Widget w,char *p,Boolean sel)
-{
- XmString item= XmStringCreateSimple(p);
- int added = 0;
- if(!XmListItemExists(w,item))
- {
- XmListAddItemUnselected(w,item,0);
- if(sel) XmListSelectItem(w,item,0);
- added = 1;
- }
- XmStringFree(item);
- return added;
-}
-
-
-void xec_VaAddListItem(Widget w,char *fmt,...)
-{
- va_list args;
- char str[1000]; /* DANGER: Fixed buffer size */
-
- va_start(args,fmt);
- vsprintf(str, fmt, args);
- xec_AddListItem(w,str);
- va_end(args);
-}
-
-void xec_ReplaceListItem(Widget w,const char* from,const char* to)
-{
- XmString a= XmStringCreateSimple((char*)from);
- XmString b= XmStringCreateSimple((char*)to);
- XmListReplaceItems(w,&a,1,&b);
- XmStringFree(a);
- XmStringFree(b);
-}
-
-#if 0
-
-/*-----------------------------------------------------
-
- Replace all items in a list
-
-------------------------------------------------------*/
-void xec_SetListItems(Widget w,XmString list[],int count)
-{
- ARG_DEF(2);
-
- SetArg(XmNitems, list );
- SetArg(XmNitemCount, count );
- SetValues(w);
-
-}
-
-/*---------------------------------------------------*/
-int xec_DumpList(FILE *f,char *fmt,Widget w)
-{
- ARG_DEF(2);
- int count;
- XmString *list;
- int i;
- int ret = 0;
-
- SetArg(XmNitems,&list);
- SetArg(XmNitemCount,&count);
- GetValues(w);
-
- for(i=0;i<count;i++)
- {
- char *p = (char*)xec_GetString(list[i]);
- fprintf(f,fmt,p);
- if(errno) ret = errno;
- XtFree((XtPointer)p);
- }
- return errno = ret;
-}
-/*-----------------------------------------------------*/
-
-/*--------------------------------------------------
-
- Search the regexp 'word' in the list 'w'.
- Return TRUE in the text was found.
- if 'nocase' is TRUE the search is not case sensitive.
- if 'fromstart' is TRUE the search start from the
- fisrt char, else from the current position.
- if 'wrap' is TRUE the search is done all the text.
-
- ---------------------------------------------------*/
-
-Boolean xec_ListSearch(Widget w,char *word,Boolean nocase,Boolean fromstart,Boolean wrap)
-{
- // ARG_DEF(5);
- int first = 0;
- int count,sel_count,vis_count;
- XmString *items,*sel_items;
- char *p;
- int from,to,i;
-
- SetArg(XmNitemCount,&count);
- SetArg(XmNselectedItemCount,&sel_count);
- SetArg(XmNitems,&items);
- SetArg(XmNselectedItems,&sel_items);
- SetArg(XmNvisibleItemCount,&vis_count);
- GetValues(w);
-
- if(!fromstart)
- if(sel_count) first = ((XmListWidget)w)->list.selectedIndices[0];
-
- while(TRUE)
- {
- for(i=first;i<count;i++)
- {
- p = xec_GetString(items[i]);
- if(regexp_find(word,p,nocase,&from,&to))
- {
- int n = i+1;
-
- XmListDeselectAllItems(w);
- XmListSelectPos(w,n,False);
- if(n<((XmListWidget)w)->list.top_position ||
- n > ((XmListWidget)w)->list.top_position + vis_count)
- XmListSetPos(w,n);
- XtFree((XtPointer)p);
- return TRUE;
- }
- XtFree((XtPointer)p);
- }
- if(!wrap) break;
- first = 0;
- wrap = FALSE;
- }
- return FALSE;
-}
-
-void xec_ListSelect(Widget w,int n)
-{
- ARG_DEF(5);
- int vis_count;
-
- SetArg(XmNvisibleItemCount,&vis_count);
- GetValues(w);
-
- XmListDeselectAllItems(w);
- XmListSelectPos(w,n,False);
-
- /* printf("xec_ListSelect %d\n",n); */
-
- if(n<((XmListWidget)w)->list.top_position ||
- n > ((XmListWidget)w)->list.top_position + vis_count)
-
- XmListSetPos(w,n);
-}
-
-#endif
-
-static char *fonts[] = {
- "normal","bold", };
-
-void xec_AddFontListItem(Widget list,char *buffer,Boolean bold)
-{
- int index = (bold) ? 1 : 0 ;
- XmString s = XmStringCreateLtoR(buffer,fonts[index]);
- XmListAddItem(list,s,0);
- XmStringFree(s);
-}
-
diff --git a/ecflow_4_0_7/view/src/libxec/xec_Regexp.c b/ecflow_4_0_7/view/src/libxec/xec_Regexp.c
deleted file mode 100644
index 4fe540a..0000000
--- a/ecflow_4_0_7/view/src/libxec/xec_Regexp.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/*=====================
-
-Include regexp once for compatibility
-
-======================*/
-
-#include <stdio.h>
-
-#define ESIZE 1024
-
-#ifdef NO_REGEXP
-
-static char *loc1,*loc2;
-static int len;
-
-static compile(w,buf,end,dummy)
-char *w,*buf;
-int end;
-int dummy;
-{
- strcpy(buf,w);
- len = strlen(w);
-}
-
-static step(w,buf)
-char *w;
-char *buf;
-{
- loc1 = w;
- while(*loc1)
- {
- if(strncmp(loc1,buf,len) == 0)
- {
- loc2 = loc1+len;
- return 1;
- }
- loc1++;
- }
- return 0;
-}
-
-
-#else
-
-/* size of regexp buffer */
-
-
-#define INIT register char *sp = instring;
-#define GETC() (*sp++)
-#define PEEKC() (*sp)
-#define UNGETC(c) (--sp)
-#define RETURN(c) return;
-#define ERROR(c) fprintf(stderr,"Warning regexp error %d\n",c)
-
-#include <regexp.h>
-
-#endif
-
-static char expbuf[ESIZE];
-char *xec_loc1;
-char *xec_loc2;
-
-void xec_compile(w)
-char *w;
-{
- compile(w,expbuf,&expbuf[ESIZE],'\0');
-}
-
-int xec_step(p)
-char *p;
-{
- int s = step(p,expbuf);
- xec_loc1 = loc1;
- xec_loc2 = loc2;
- return s;
-}
diff --git a/ecflow_4_0_7/view/src/libxec/xec_Strings.c b/ecflow_4_0_7/view/src/libxec/xec_Strings.c
deleted file mode 100644
index 88f2c13..0000000
--- a/ecflow_4_0_7/view/src/libxec/xec_Strings.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-#include <Xm/Xm.h>
-#include <string.h>
-#include <malloc.h>
-
-/*-----------------------------------------------------
-
- Create a new XmString from a char*
-
- This function can deal with embedded 'newline' and
- is equivalent to the obsolete XmStringCreateLtoR,
- except it does not use non AES compliant charset
- XmSTRING_DEFAULT_CHARSET
-
-------------------------------------------------------*/
-
-
-XmString xec_NewString(const char* s)
-{
- XmString xms1;
- XmString xms2;
- XmString line;
- XmString separator;
- char *p;
- char *t = XtNewString(s); /* Make a copy for strtok not to */
- /* damage the original string */
-
- separator = XmStringSeparatorCreate();
- p = strtok(t,"\n");
- xms1 = XmStringCreateSimple(p);
-
- while ((p = strtok(NULL,"\n")))
- {
- line = XmStringCreateSimple(p);
- xms2 = XmStringConcat(xms1,separator);
- XmStringFree(xms1);
- xms1 = XmStringConcat(xms2,line);
- XmStringFree(xms2);
- XmStringFree(line);
- }
-
- XmStringFree(separator);
- XtFree(t);
- return xms1;
-}
-
-
-/*-----------------------------------------------------
-
- Build an XmString list from char*
-
-------------------------------------------------------*/
-
-void xec_BuildXmStringList(XmString** list, char* p, int *count)
-{
- XmString *l = *list;
-
- if(!l) {
- *count = 0;
- l = (XmString*)malloc(0);
- }
-
- (*count)++;
- l = (XmString*)XtRealloc((char*) l,sizeof(XmString)*(*count));
- l[(*count-1)] = xec_NewString(p);
-
- *list = l;
-}
-
-/*-----------------------------------------------------
-
- Free an XmString list
-
-------------------------------------------------------*/
-
-void xec_FreeXmStringList(XmString* list, int count)
-{
- int i;
-
- if(list)
- {
- for(i=0;i<count;i++) XmStringFree(list[i]);
- XtFree((XtPointer)list);
- }
-}
-
-char *xec_GetString(XmString string)
-{
- XmStringContext context;
- char *text;
- XmStringCharSet charset;
- XmStringDirection dir;
- Boolean separator;
- char *buf = NULL;
- int done = FALSE;
-
- XmStringInitContext (&context, string);
- while (!done)
- if(XmStringGetNextSegment (context, &text, &charset, &dir, &separator))
- {
- if(separator) /* Stop when next segment is a separator */
- done = TRUE;
-
- if(buf)
- {
- buf = XtRealloc(buf, strlen(buf) + strlen(text) + 2);
- strcat(buf, text);
- }
- else
- buf = XtNewString(text);
-
- XtFree((XtPointer)charset);
- XtFree((XtPointer)text);
- }
- else
- done = TRUE;
-
- XmStringFreeContext (context);
- return buf;
-
-}
diff --git a/ecflow_4_0_7/view/src/libxec/xec_Text.c b/ecflow_4_0_7/view/src/libxec/xec_Text.c
deleted file mode 100644
index 7bbf9c8..0000000
--- a/ecflow_4_0_7/view/src/libxec/xec_Text.c
+++ /dev/null
@@ -1,551 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #2 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <X11/X.h>
-#include <X11/Xlib.h>
-#include <Xm/Xm.h>
-#include <Xm/Text.h>
-#include <Xm/TextP.h>
-#include <Xm/Form.h>
-#include <Xm/TextStrSoP.h>
-#include <Xm/CutPaste.h>
-#include "xec.h"
-#include <sys/types.h>
-#include <sys/mman.h>
-#include <regex.h>
-#include <setjmp.h>
-#include <signal.h>
-
-/* Avi: Added to fix: warning: implicit declaration of function ‘_XmTextUpdateLineTable’ */
-extern void _XmTextUpdateLineTable(
- Widget widget,
- XmTextPosition start,
- XmTextPosition end,
- XmTextBlock block,
- // int update) ; // JIRA:ECFLOW-48
- Boolean update) ; // JIRA:ECFLOW-48
-
-#ifndef MAP_FAILED
-#define MAP_FAILED ((void *)(-1))
-#endif
-
-int regexp_find(const char *word,const char *buffer,
- int nocase,int *from,int *to)
-{
- regex_t re;
- regmatch_t pmatch[1];
- int e;
-
- if((e = regcomp(&re,word,REG_NEWLINE | REG_EXTENDED | (nocase? REG_ICASE : 0) )))
- {
- char buf[1024];
- regerror(e,&re,buf,sizeof(buf));
- return False;
- }
-
- if((e = regexec(&re,buffer,XtNumber(pmatch),pmatch,0)))
- {
- char buf[1024];
- regerror(e,&re,buf,sizeof(buf));
- regfree(&re);
- return False;
- }
-
- *from = pmatch[0].rm_so;
- *to = pmatch[0].rm_eo;
-
- regfree(&re);
-
- return True;
-}
-
-char* xec_TextGetString(Widget w,long *length)
-{
-#if 0
- return XmTextGetString(w);
-#else
- XmTextSource s = XmTextGetSource(w);
- *length = s->data->length;
- return s->data->ptr;
-#endif
-}
-
-void xec_TextFreeString(char* p)
-{
-#if 0
- XtFree(p);
-#endif
-}
-
-static jmp_buf env;
-
-static void catch_sigv(int sig)
-{
- fprintf(stderr,"SIGV received...\n");
- longjmp(env,1);
-}
-
-/*--------------------------------------------------
----------------------------------------------------*/
-
-/*--------------------------------------------------
-
- Search the regexp 'word' in the text 'w'.
- Return TRUE in the text was found.
- if 'nocase' is TRUE the search is not case sensitive.
- if 'fromstart' is TRUE the search start from the
- fisrt char, else from the current position.
- if 'wrap' is TRUE the search is done all the text.
-
----------------------------------------------------*/
-
-Boolean xec_TextSearch(Widget w,char *word,
- Boolean nocase,
- Boolean regex,
- Boolean back,
- Boolean fromstart,
- Boolean wrap)
-{
-
- Boolean success,more;
- XmTextPosition offset,dummy;
- int from,to;
- long length = 0;
- char *p=xec_TextGetString(w,&length);
-
- if(fromstart)
- {
- offset = (!regex && back) ? XmTextGetLastPosition(w) - strlen(word) : 0;
- wrap = FALSE;
- }
- else
- {
- XmTextGetSelectionPosition(w,&dummy,&offset);
- if(dummy == offset) offset = XmTextGetInsertionPosition(w);
-
- if(back) {
- if(dummy)
- offset = dummy-1;
- else if(wrap)
- {
- offset = XmTextGetLastPosition(w) - strlen(word);
- }
- }
- }
-
- do
- {
-
- if(regex)
- {
- success = regexp_find(word,p+offset,nocase,&from,&to);
- if(success && ((from+offset > length) || (to + offset > length)))
- success = False;
- }
- else {
-
- success = 0;
-
- /* Because we use mmap, XmTextFindString may crash */
-
- signal(SIGSEGV,catch_sigv);
- if(setjmp(env) == 0)
- {
- success = XmTextFindString(w,offset,word,
- back ? XmTEXT_BACKWARD : XmTEXT_FORWARD,&dummy);
- }
- signal(SIGSEGV,SIG_DFL);
-
-
-
- if(success) {
-
- from = dummy - offset;
- to = from + strlen(word);
-
- }
- }
-
-
- if(success)
- {
- XmTextShowPosition(w,to+offset);
- XmTextSetSelection(w,from+offset,to+offset,CurrentTime);
- }
-
- more = wrap && !success;
-
- if(wrap)
- {
- wrap = FALSE;
- offset = (!regex && back) ? XmTextGetLastPosition(w) - strlen(word): 0;
- }
-
- }while(more);
-
- xec_TextFreeString(p);
-
- return success;
-
-}
-
-
-
-/*-------------------------------------------------
-
- Copy the content of a Text in a buffer.
-
---------------------------------------------------*/
-
-char *xec_GetText(w,buf)
-Widget w;
-char buf[];
-{
- char *q = (char*)XmTextGetString(w);
-
- strcpy(buf,q);
- XtFree((XtPointer)q);
-
- return buf;
-}
-
-
-/*-------------------------------------------------
-
- Load a file into a text widget.
- if include is TRUE the text if included.
-
---------------------------------------------------*/
-
-int xec_LoadText(Widget Text,const char *fname,Boolean include)
-{
- FILE *fp = NULL;
- char *p;
- long length;
- int ret = 0;
-
-
- errno = 0;
-
- if (!fname) return -1;
-
- if ((fp = fopen(fname,"r")))
- {
- fseek(fp,0L,2);
- if (errno)
- {
- ret = errno;
- fclose(fp);
- return errno = ret;
- }
-
- length=ftell(fp);
- if (errno)
- {
- ret = errno;
- fclose(fp);
- return errno = ret;
- }
-
- fseek(fp,0L,0);
- if (errno)
- {
- ret = errno;
- fclose(fp);
- return errno = ret;
- }
-
- p = (char*)XtMalloc(length+1);
- p[length] = 0;
-
- fread(p,length,1,fp);
- if (errno)
- {
- ret = errno;
- fclose(fp);
- return errno = ret;
- }
-
- XmTextDisableRedisplay(Text);
- if (include)
- xec_ReplaceTextSelection(Text,p,FALSE);
- else
- {
- XmTextSetInsertionPosition(Text,0);
- XmTextSetSelection(Text,0,0,CurrentTime);
- XmTextSetString(Text,p);
- }
- XmTextEnableRedisplay(Text);
-
- XtFree(p);
- fclose(fp);
- }
- else
- {
- perror(fname);
- ret = errno;
- if (!include) XmTextSetString(Text,"");
- }
- return errno = ret;
-
-}
-
-/* ================================================== */
-
-
-typedef struct mapped_text {
- XmTextSource source_;
- FILE* file_;
- Widget text_;
- XmSourceDataRec save_;
-} mapped_text;
-
-void* xec_MapText(Widget w,const char *fname,int* z)
-{
- FILE *fp = NULL;
- long length;
- int ret = 0;
- char *m;
- mapped_text *p;
- XEvent ev;
- XmTextBlockRec block;
- int i;
-
-
- errno = 0;
-
- if (!fname) return NULL;
-
- if ((fp = fopen(fname,"r")))
- {
- fseek(fp,0L,2);
- if (errno)
- {
- ret = errno;
- fclose(fp);
- return NULL;
- }
-
- length=ftell(fp);
- if (errno)
- {
- ret = errno;
- fclose(fp);
- return NULL;
- }
-
- fseek(fp,0L,0);
- if (errno)
- {
- ret = errno;
- fclose(fp);
- return NULL;
- }
-
- /* f = w; */
- /* while(f && !XmIsForm(f)) */
- /* f = XtParent(f); */
-
- /* if(!f) return NULL; */
-
-
- m = mmap(NULL,length,PROT_READ,MAP_SHARED,fileno(fp),0);
- if((void*)m == MAP_FAILED)
- {
- perror(fname);
- return NULL;
- }
- (*z) = 0;
- for(i = 0 ; i < length; i++)
- if(m[i] == 0) (*z)++;
-
- XmTextDisableRedisplay(w);
- XmTextClearSelection(w,CurrentTime);
- XmTextSetInsertionPosition(w,0);
- XmTextSetTopCharacter(w,0);
- XmTextShowPosition(w,0);
- XmTextEnableRedisplay(w);
- XmTextSetString(w,"");
-
- p = XtNew(mapped_text);
-
- /* p->text1_ = XmCreateText(f,"dummy",0,0); */
- /* p->text2_ = XmCreateText(f,"dummy",0,0); */
-
- p->source_ = XmTextGetSource(w);
- p->file_ = fp;
- p->text_ = w;
- p->save_ = *p->source_->data;
-
- p->source_->data->ptr = m;
- p->source_->data->length = length;
- p->source_->data->maxlength = length;
- p->source_->data->value = m;
- p->source_->data->old_length = length;
- p->source_->data->gap_start = 0;
- p->source_->data->gap_end = 0;
-
-
- ((XmTextWidget)w)->text.needs_refigure_lines = True;
- /* _XmTextNumLines((XmTextWidget)w); */
-
- block.ptr = m;
- block.length = length;
- block.format = XmFMT_8_BIT;
-
- _XmTextUpdateLineTable(w,0, XmTextGetLastPosition(w),&block,1);
-
-#if 1
- /* ((XmTextWidget)w)->text.needs_refigure_lines = True; */
- /* printf("Num lines : %d\n",_XmTextNumLines((XmTextWidget)w)); */
- /* _XmTextValueChanged((XmTextWidget)w,&ev); */
-
- memset(&ev,0,sizeof(ev));
- ev.type = Expose;
- ev.xexpose.display = XtDisplay(w);
- ev.xexpose.window = XtWindow(w);
-
- XSendEvent(XtDisplay(w),XtWindow(w),True,ExposureMask,&ev);
-#endif
-
- return p;
-
- }
- return NULL;
-
-}
-
-void xec_UnmapText(void *x)
-{
- if(x)
- {
- XmTextBlockRec block;
- mapped_text* p = (mapped_text*)x;
- Widget w = p->text_;
-
- ((XmTextWidget)w)->text.needs_refigure_lines = True;
- /* _XmTextNumLines((XmTextWidget)w); */
-
- block.ptr = NULL;
- block.length = 0;
- block.format = XmFMT_8_BIT;
- _XmTextUpdateLineTable(w,0, XmTextGetLastPosition(w),&block,1);
-
- XmTextDisableRedisplay(w);
- XmTextClearSelection(w,CurrentTime);
- XmTextSetInsertionPosition(w,0);
- XmTextSetTopCharacter(w,0);
- XmTextShowPosition(w,0);
-
- XmTextEnableRedisplay(w);
-
- munmap(p->source_->data->ptr,p->source_->data->length);
- *p->source_->data = p->save_;
- fclose(p->file_);
-
- XtFree((char*)p);
-
- XmTextSetString(w,"");
- }
-
-}
-
-/*-------------------------------------------------
-
- Save a text into a file
-
---------------------------------------------------*/
-
-/* Open file, save text and close file */
-
-int xec_SaveText(Widget w,char *fname)
-{
- FILE *fp = NULL;
- char *p = XmTextGetString(w);
- int ret;
-
- errno = 0;
-
- if (!fname) return -1;
-
- if ((fp = fopen(fname,"w")))
- if (fwrite(p,strlen(p),1,fp)) fclose(fp);
-
- ret = errno;
- XtFree(p);
- return errno = ret;
-}
-
-
-/* File is already opened: just save text */
-
-int xec_DumpText(FILE *fp,Widget w)
-{
- char *p = XmTextGetString(w);
-
- errno = 0;
- fwrite(p,strlen(p),1,fp);
- XtFree((XtPointer)p);
- return errno;
-}
-
-
-/*-------------------------------------------------
-
- Print a text
-
---------------------------------------------------*/
-
-void xec_PrintText(Widget w,char * cmd)
-{
- char *tmp = tmpnam(NULL);
- char buf[1024];
-
- xec_SaveText(w,tmp);
- if(cmd)
- sprintf(buf,"%s %s",cmd,tmp);
- else
- sprintf(buf,"lpr %s",tmp);
-
- system(buf);
- unlink(tmp);
-
-
-}
-
-/*-------------------------------------------------
-
- Replace the selection by a char*
- If sel the inserted text is selected
-
---------------------------------------------------*/
-
-void xec_ReplaceTextSelection(Widget w,char *p,Boolean sel)
-{
- XmTextPosition from,to;
-
- XmTextGetSelectionPosition(w,&from,&to);
- if(from == to) from = to = XmTextGetInsertionPosition(w);
- XmTextReplace(w,from,to,p);
- if(sel)
- XmTextSetSelection(w,from,from+strlen(p),CurrentTime);
- else
- XmTextSetSelection(w,from+strlen(p),from+strlen(p),CurrentTime);
- XmTextSetInsertionPosition(w,from+strlen(p));
-}
-
diff --git a/ecflow_4_0_7/view/src/libxec/xec_Toggle.c b/ecflow_4_0_7/view/src/libxec/xec_Toggle.c
deleted file mode 100644
index c2e502c..0000000
--- a/ecflow_4_0_7/view/src/libxec/xec_Toggle.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-#include <Xm/Xm.h>
-#include <stdio.h>
-#include "xec.h"
-
-/*-----------------------------------------------
-
- Set or reset a toggle button
-
--------------------------------------------------*/
-
-void xec_SetToggle(Widget w,int set)
-{
- Arg arg;
-
- XtSetArg(arg,XmNset,set?1:0);
- XtSetValues(w,&arg,1);
-}
-
-int xec_GetToggle(Widget w)
-{
- Boolean set;Arg arg;
-
- XtSetArg(arg,XmNset, &set);
- XtGetValues(w,&arg,1);
-
- return set;
-}
diff --git a/ecflow_4_0_7/view/src/libxec/xec_Widget.c b/ecflow_4_0_7/view/src/libxec/xec_Widget.c
deleted file mode 100644
index 3814bbd..0000000
--- a/ecflow_4_0_7/view/src/libxec/xec_Widget.c
+++ /dev/null
@@ -1,215 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #1 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-#include <stdio.h>
-#include <Xm/Xm.h>
-#include <Xm/ScrolledW.h>
-#include <Xm/ScrollBar.h>
-#include <X11/IntrinsicP.h>
-#include "xec.h"
-
-
-void *xec_GetUserData(Widget w)
-{
- void *p;
- XtVaGetValues(w,XmNuserData,&p,NULL);
- return p;
-}
-
-/*-------------------------------------------------
-
- Attach a pointer to a widget
-
--------------------------------------------------*/
-
-void xec_SetUserData(Widget w, void* p)
-{
- XtVaSetValues(w,XmNuserData,p,NULL);
-}
-
-/*-------------------------------------------------
-
- Sets a color
-
---------------------------------------------------*/
-
-
-void xec_SetColor(Widget w, Pixel p, const char* which)
-{
- XtVaSetValues(w,which,p,NULL);
-}
-
-/*-------------------------------------------------
-
- Scroll a window to make a widget visible
-
---------------------------------------------------*/
-
-#if 1
-
-void xec_ShowWidget(Widget w)
-{
-
- Widget v_scroll,h_scroll;
-
-
- Position x_parent,y_parent;
- Position x_widget,y_widget;
- Dimension h_widget,w_widget;
- Position x_clip,y_clip;
- Dimension h_clip,w_clip;
- Position dv=0,dh=0;
- int min,max;
- int v_val,v_size,v_inc,v_page;
- int h_val,h_size,h_inc,h_page;
- Widget clip;
- Widget parent;
- Widget scroll_window;
-
- Position x,y;
-
-
- if(!XtIsManaged(w)) return;
-
- if(!(parent = XtParent(w))) return;
- if(!(clip = XtParent(parent))) return;
- if(!(scroll_window = XtParent(clip))) return;
-
- if(!XmIsScrolledWindow(scroll_window)) return;
-
- XtVaGetValues(scroll_window,
- XmNhorizontalScrollBar, &h_scroll,
- XmNverticalScrollBar, &v_scroll ,
- NULL);
-
-
- XtVaGetValues(parent,
- XmNx,&x_parent,
- XmNy,&y_parent,
- NULL);
-
-
- XtVaGetValues(w,
- XmNheight,&h_widget,
- XmNwidth,&w_widget,
- NULL);
-
-
- XtVaGetValues(scroll_window,
- XmNclipWindow,&clip,
- NULL);
-
- XtVaGetValues(clip,
- XmNheight,&h_clip,
- XmNwidth,&w_clip,
- NULL);
-
-
- XtTranslateCoords(w,0,0, &x_widget,&y_widget);
- XtTranslateCoords(clip,0,0,&x_clip,&y_clip);
-
-
- x = x_widget - x_clip;
- y = y_widget - y_clip;
-
-
- if( y < 0 || (Dimension) (y + h_widget) > h_clip)
- {
- dv = (y + h_widget / 2) - h_clip / 2;
-
- XtVaGetValues(v_scroll,
- XmNminimum,&min,
- XmNmaximum,&max,
- NULL);
-
- XmScrollBarGetValues(v_scroll,&v_val,&v_size,&v_inc,&v_page);
-
- max -= v_size;
-
- if( dv + v_val > max ) dv = max - v_val;
- if( dv + v_val < min ) dv = min - v_val;
-
-
- }
-
- if( x < 0 || (Dimension) (x + w_widget) > w_clip)
- {
- dh = (x + w_widget / 2) - w_clip / 2;
-
- XtVaGetValues(h_scroll,
- XmNminimum,&min,
- XmNmaximum,&max,
- NULL);
-
- XmScrollBarGetValues(h_scroll,&h_val,&h_size,&h_inc,&h_page);
-
- max -= h_size;
-
- if( dh + h_val > max ) dh = max - h_val;
- if( dh + h_val < min ) dh = min - h_val;
-
- }
-
-
- if(dv || dh)
- {
- Position x = x_parent-dh;
- Position y = y_parent-dv;
-
- XtVaSetValues(parent,
- XmNx,x,
- XmNy,y,
- NULL);
-
- /*
- XtMoveWidget(parent,x_parent-dh,y_parent-dv);
- */
-
- if(dv) XmScrollBarSetValues(v_scroll,v_val+dv,v_size,v_inc,v_page,TRUE);
- if(dh) XmScrollBarSetValues(h_scroll,h_val+dh,h_size,h_inc,h_page,TRUE);
-
-
- /* force redraw */
- /*
-
- XtUnmanageChild(parent);
- XtManageChild(parent);
- */
- }
-
-
-}
-
-#endif
-void xec_Invert(Widget w)
-{
- Pixel fg,bg;
- XtVaGetValues(w,XmNbackground,&bg,XmNforeground,&fg,NULL);
- XtVaSetValues(w,XmNbackground,fg,XmNforeground,bg,NULL);
-}
-
-void xec_ManageAll(Widget w)
-{
- CompositeWidget c = (CompositeWidget)w;
- XtManageChildren(c->composite.children,
- c->composite.num_children);
-}
-
-void xec_UnmanageAll(Widget w)
-{
- CompositeWidget c = (CompositeWidget)w;
- XtUnmanageChildren(c->composite.children,
- c->composite.num_children);
-}
-
diff --git a/ecflow_4_0_7/view/src/limit_node.cc b/ecflow_4_0_7/view/src/limit_node.cc
deleted file mode 100644
index 3de1d57..0000000
--- a/ecflow_4_0_7/view/src/limit_node.cc
+++ /dev/null
@@ -1,459 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #15 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "node.h"
-#include "show.h"
-#include "pixmap.h"
-#include <math.h>
-// #include "text_lister.h"
-#include "node_lister.h"
-#include "limit_node.h"
-#include <Xm/ManagerP.h>
-#include "ecf_node.h"
-
-#ifndef M_PI_2
-#define M_PI_2 1.57079632679489661923
-#endif
-
-static Pixmap images[3] = {XmUNSPECIFIED_PIXMAP, };
-
-Limit* limit_node::get() const {
-#ifdef BRIDGE
- if (tree_) return 0x0;
-#endif
- if (!owner_) return 0x0;
- return dynamic_cast<ecf_concrete_node<Limit>*>(owner_)->get();
- /* ecf_concrete_node<const Limit>* base =
- dynamic_cast<ecf_concrete_node<const Limit>*> (owner_);
- if (base) return *(base->get());
- if (parent() && parent()->__node__())
- return parent()->__node__()->get_limit(name_);
- return 0x0; */
-}
-
-xmstring limit_node::make_label_tree()
-{
- if (get()) {
- char buf[30];
- xmstring s(owner_->name().c_str(),"bold");
- sprintf(buf,"%d/%d", get()->value(), get()->theLimit());
- s += xmstring(": ","bold");
- s += xmstring(buf);
- return s;
- }
-#ifdef BRIDGE
- else if (!tree_) return xmstring ("nolimit");
- sms_limit* n = (sms_limit*) tree_;
- xmstring s(n->name,"bold");
- s += xmstring(": ","bold");
-
- char buf[80];
-
- if(n->base)
- sprintf(buf,"%d - %d - %d",n->base,n->status,n->limit);
- else
- sprintf(buf,"%d/%d",n->status,n->limit);
-
- s += xmstring(buf);
-
- if(n->unit)
- {
- sprintf(buf," (%s)",n->unit);
- s += xmstring(buf);
- }
-
- return s;
-#endif
- return xmstring(": ","bold");
-}
-
-const int kPixSize = 8;
-const int kHMargins = 4;
-const int kVMargins = 2;
-
-inline int max(int a,int b) { return a>b?a:b; }
-
-void limit_node::drawNode(Widget w,XRectangle* r,bool tree)
-{
- int m = 0, v = 0;
- if (get()) {
- m = get()->theLimit();
- v = get()->value();
- }
-
- XmString s = labelTree();
- XRectangle x = *r;
- x.width = XmStringWidth(smallfont(),s) + 2*kHMargins;
-
- XmStringDraw(XtDisplay(w),XtWindow(w),
- smallfont(),
- s,
- blackGC(),
- r->x,
- r->y,
- x.width,
- XmALIGNMENT_CENTER, XmSTRING_DIRECTION_L_TO_R, NULL);
-
- for(int i = 0; i < max(m, v); i++)
- XCopyArea(XtDisplay(w),
- images[(i<v)?(i>=m?2:1):0],XtWindow(w),
- blackGC(),
- 0,0,kPixSize,kPixSize,
- r->x + x.width + (i*kPixSize),
- r->y + (r->height - kPixSize) / 2);
-
- sizeNode( w, r, tree);
-}
-
-
-void limit_node::sizeNode(Widget w,XRectangle* r,bool tree)
-{
- int m = maximum(), v = value();
- if(images[0] == XmUNSPECIFIED_PIXMAP) {
- images[0] = pixmap::find("limit0").pixels();
- images[1] = pixmap::find("limit1").pixels();
- images[2] = pixmap::find("limit2").pixels();
- }
-
- XmString s = labelTree();
- r->height = XmStringHeight(smallfont(),s);
- r->width = XmStringWidth(smallfont(),s) + 2*kHMargins + max(m,v) * kPixSize;
- if(r->height < kPixSize) r->height = kPixSize;
-}
-
-void limit_node::perlify(FILE* f)
-{
- perl_member(f,"value",value());
- perl_member(f,"maximum",maximum());
- // FILL perl_member(f,"tasks",n->tasks);
-}
-
-void limit_node::info(std::ostream& f)
-{
- Limit* n= get(); if (n) {
- const std::set<std::string>& list = n->paths();
- std::set<std::string>::const_iterator it;
- node::info(f);
-
- f << "value : " << value() << "\n";
- f << "maximum : " << maximum() << "\n";
- // 1234567890
-
- if(!list.empty())
- f << "\nNodes in this limit_node:" << "\n-------------------------\n";
-
- for (it = list.begin(); it != list.end(); ++it) {
- f << *it;
- node* p = find(*it);
- if(p)
- f << " " << p->type_name() << ' '
- << " (" << p->status_name() << ")\n";
- }
- }
-#ifdef BRIDGE
-else if (tree_) {
- sms_limit *n = (sms_limit*)tree_; if (!n) return;
- sms_list* l = n->tasks;
-
- node::info(f);
-
- f << "value : " << n->status << "\n";
- f << "maximum : " << n->limit << "\n";
- // 1234567890
-
- if(l)
- f << "\nNodes in this limit_node:"
- << "\n--------------------\n";
- while(l)
- {
- node* p = find(l->name);
- if(p)
- f << p->type_name() << ' ' << p << " ("
- << p->status_name() << ')';
- else
- f << l->name;
- f << "\n";
- l = l->next;
- }
- }
-#endif
-}
-
-const char* limit_node::status_name() const
-{
- static char buf[20];
- if(value() >= maximum()) return "full";
- if(value() <= 0 ) return "empty";
- sprintf(buf,"%d%%",int((value()*100.0/maximum())+0.5));
- return buf;
-}
-
-bool limit_node::evaluate() const
-{
- return (value() >= maximum());
-}
-
-int limit_node::maximum() const
-{
- Limit* n= get();
- if (n) return n->theLimit();
-#ifdef BRIDGE
- if (tree_) return ((sms_limit*) tree_)->limit;
-#endif
- return 0;
-}
-
-int limit_node::value() const
-{
- if (get()) return get()->value();
-#ifdef BRIDGE
- if (tree_) return ((sms_limit*) tree_)->status;
-#endif
- return 0;
-}
-
-void limit_node::nodes(node_lister& node_list)
-{
- Limit* n= get();
- if (n) {
- const std::set<std::string>& list = n->paths();
- std::set<std::string>::const_iterator it;
- for (it = list.begin(); it != list.end(); ++it) {
- node* p = find(*it);
- if(p) node_list.next(*p);
- else node_list.next(*it);
- }
- return;
- } else {
-#ifdef BRIDGE
- sms_limit *n = (sms_limit*)tree_; if (!n) return;
- sms_list* l = n->tasks;
-
- while(l) {
- node* p = find(l->name);
- if(p) node_list.next(*p);
- l = l->next;
- }
-#endif
- }
-}
-
-bool limit_node::match(const char* p)
-{
- return p == parent()->full_name() + ":" + name();
-}
-
-//===============================================================
-
-const double kLength = 30;
-const double kMark = 5;
-const double kVuHeight = 2 + (kLength + kMark);
-const double kVuWidth = (kLength + kMark)*2.0;
-
-
-
-void limit_integer_node::sizeNode(Widget w,XRectangle* r,bool)
-{
-#if 1
- XmString s = labelTree();
- r->width = XmStringWidth(smallfont(),s) + 2 * kHMargins ;
- r->height = XmStringHeight(smallfont(),s) + 2 * kVMargins + kVuHeight;
-
- if(r->width < kVuWidth) r->width = kVuWidth;
-#else
- r->width = kVuWidth;
- r->height = 2 * kVMargins + kVuHeight;
-#endif
-}
-
-void limit_integer_node::drawNode(Widget w,XRectangle* r,bool)
-{
- XRectangle y = *r;
- y.width = kVuWidth;
- y.height = kVuHeight;
- y.y += kVMargins;
- drawMeter(w,&y);
-
- char buffer[1024];
- if (get()) sprintf(buffer,"%s",get()->name().c_str());
-#ifdef BRIDGE
- else if (tree_) sprintf(buffer,"%s",((sms_limit*)tree_)->name);
-#endif
- xmstring s(buffer);
- XmFontList f = gui::tinyfont();
-
- XmStringDraw(XtDisplay(w),XtWindow(w),
- f,
- s,
- blackGC(),
- r->x,
- r->y + (r->height - XmStringHeight(f,s)) / 2 ,
- r->width,
- XmALIGNMENT_CENTER, XmSTRING_DIRECTION_L_TO_R, r);
-#if 0
- y = *r;
- y.y += kVuHeight + kVMargins;
-
- XmString s = labelTree();
- XmStringDraw(XtDisplay(w),XtWindow(w),
- smallfont(),
- s,
- blackGC(),
- y.x,
- y.y,
- y.width,
- XmALIGNMENT_CENTER, XmSTRING_DIRECTION_L_TO_R, NULL);
-
- /* shadow(w,r); */
-#endif
- node::update(-1,-1,-1);notify_observers();
-}
-
-void limit_integer_node::drawMeter(Widget w,XRectangle* r)
-{
-#if 0
- int xcenter = 80;
- int ycenter = 55;
- int lastxs = xcenter;
- int lastys = ycenter;
-
- double min_ = 0;
- double max_ = 5000;
- double v_ = 15;
-
- int length = 30;
- int mark = 5;
-
- int ticks = 5;
-#endif
- const double round = 20;
-
- const double angle = 120;
- const double pi2 = M_PI_2;
- const double twopi = M_PI * 2.0;
- const int ticks = 5;
-
- const double a = angle / 360.0 * twopi;
-
- double maxval = maximum(); // n->limit;
- double minval = 0.0; // n->min;
- double curval = value(); // n->status;
-
- double xcenter = r->width / 2.0;
- double ycenter = r->height;
-
- double d = (maxval - minval);
- double c = (curval - minval)/d*a - a/2.0;
-
- if(c > pi2) c = pi2;
-
- int xs = cos(c - pi2) * kLength + xcenter;
- int ys = sin(c - pi2) * kLength + ycenter;
-
- GC gc = (curval > maxval) ? redGC() : blueGC();
-
- XSetLineAttributes(XtDisplay(w),gc, 2,0,0,0);
-
- XDrawLine(XtDisplay(w),XtWindow(w),
- gc,
- r->x + xcenter, r->y + ycenter-1, r->x + xs, r->y + ys);
-
- XSetLineAttributes(XtDisplay(w),gc, 1,0,0,0);
- /*
- // --- base
- if(n->base) {
-
- double c1 = - a/2.0;
- double c2 = (n->base - minval)/d*a - a/2.0;
-
- c1 = twopi - c1 + pi2;
- c2 = twopi - c2 + pi2;
- // c1 -= pi2;
- // c2 -= pi2;
-
- double size = kLength+kMark + 2;
-
- XFillArc(XtDisplay(w),XtWindow(w),
- XmParentBottomShadowGC(w),
- r->x + xcenter - size,
- r->y + ycenter - size,
- size * 2,
- size * 2,
-
- (c1 / twopi * 360) * 64,
- (c2 / twopi * 360) * 64 - (c1 / twopi * 360) * 64);
- }
- */
-#if 0
- g.setColor(Color.gray);
- g.fillArc(xcenter-round/2,ycenter-round/2,round,round,0,180);
-#endif
-
- for(int i = 0 ; i < ticks ; i++)
- {
- double v = i*d/(ticks-1);
- c = v/d*a - a/2;
- int x1 = cos(c - pi2) * kLength + xcenter;
- int y1 = sin(c - pi2) * kLength + ycenter;
-
- int x2 = cos(c - pi2) * (kLength+kMark) + xcenter;
- int y2 = sin(c - pi2) * (kLength+kMark) + ycenter;
-
- XDrawLine(XtDisplay(w),XtWindow(w),
- blackGC(),r->x + x1,r->y + y1, r->x + x2, r->y + y2);
- }
-
- XFillArc(XtDisplay(w),XtWindow(w),
- XmParentBackgroundGC(w),
- r->x + xcenter-round/2,
- r->y + ycenter-round/2,
- round,
- round,0,180*64);
-
- const int drop_shadow = 10;
- XDrawArc(XtDisplay(w),XtWindow(w),XmParentBottomShadowGC(w),
- r->x + xcenter-round/2,
- r->y + ycenter-round/2,round,round,64,(90-drop_shadow) * 64);
-
- XDrawArc(XtDisplay(w),XtWindow(w),XmParentTopShadowGC(w),
- r->x + xcenter-round/2,
- r->y + ycenter-round/2,round,round, (90+drop_shadow)*64,180*64 - (90+drop_shadow)*64);
-
-
- char buf[80];
- sprintf(buf,"%d",value());
-
- xmstring t(buf);
- XmFontList f = gui::tinyfont();
-
- XmStringDraw(XtDisplay(w),XtWindow(w),
- f,
- t,
- (curval > maxval) ? redGC() : blueGC(),
- r->x + xcenter-round/2 + 2,
- r->y + ycenter-round/2 + 3,
- round,
- XmALIGNMENT_CENTER, XmSTRING_DIRECTION_L_TO_R, NULL);
-
- shadow(w,r,false);
-}
-
-//===============================================================
-
-
-//===============================================================
-
-Boolean limit_node::visible() const { return show::want(show::limit); }
-
diff --git a/ecflow_4_0_7/view/src/limit_node.h b/ecflow_4_0_7/view/src/limit_node.h
deleted file mode 100644
index 5f2445d..0000000
--- a/ecflow_4_0_7/view/src/limit_node.h
+++ /dev/null
@@ -1,74 +0,0 @@
-#ifndef limit_node_H
-#define limit_node_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #8 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "node.h"
-class Limit;
-
-class limit_node : public node {
-public:
-
- limit_node(host& h,ecf_node* n) : node(h,n) {}
-#ifdef BRIDGE
- limit_node(host& h,sms_node* n,char b) : node(h,n,b) {}
-#endif
- int maximum() const;
- int value() const;
- void nodes(node_lister&);
- protected:
- Limit* get() const;
-
-private:
-
- limit_node(const limit_node&);
- limit_node& operator=(const limit_node&);
-
- virtual bool evaluate() const;
- virtual void drawNode(Widget w,XRectangle* r,bool);
- virtual void sizeNode(Widget w,XRectangle* r,bool);
- virtual xmstring make_label_tree();
-
- virtual void info(std::ostream&);
- virtual const char* status_name() const;
- virtual Boolean visible() const;
- virtual bool match(const char*);
-
- virtual void perlify(FILE*);
-};
-
-class limit_integer_node : public limit_node {
- void sizeNode(Widget w,XRectangle* r,bool);
- void drawNode(Widget w,XRectangle* r,bool);
- void drawMeter(Widget w,XRectangle* r);
-public:
- limit_integer_node(host& h,ecf_node* n): limit_node(h,n) {}
-#ifdef BRIDGE
- limit_integer_node(host& h,sms_node* n,char b) : limit_node(h,n,b) {}
-#endif
-};
-
-class limit_boolean_node : public limit_node {
-public:
- limit_boolean_node(host& h,ecf_node* n): limit_node(h,n) {}
-#ifdef BRIDGE
- limit_boolean_node(host& h,sms_node* n,char b) : limit_node(h,n,b) {}
-#endif
-};
-
-inline void destroy(limit_node**) {}
-
-#endif
diff --git a/ecflow_4_0_7/view/src/line.c b/ecflow_4_0_7/view/src/line.c
deleted file mode 100644
index 1afd42e..0000000
--- a/ecflow_4_0_7/view/src/line.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include <stdio.h>
-
-main(int argc,char **argv)
-{
- FILE* f = argc>2 ? fopen(argv[2],"r"):stdin;
- int l = atol(argv[1]);
- int n = 0;
-
- char line[1024];
-
- if(!f)
- {
- perror(argv[2]);
- exit(1);
- }
-
- while(fgets(line,sizeof(line),f))
- if(++n == l)
- {
- printf("%s\n",line);
- exit(0);
- }
-
-
- exit(1);
-
-}
diff --git a/ecflow_4_0_7/view/src/lister.cc b/ecflow_4_0_7/view/src/lister.cc
deleted file mode 100644
index dd32505..0000000
--- a/ecflow_4_0_7/view/src/lister.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-/*
-#ifndef lister_H
-#include "lister.h"
-#endif
-*/
-
-template<class T>
-T* lister<T>::scan(T* first)
-{
- if(sort())
- {
- int swap = 1;
-
- while(swap)
- {
- T *d = first;
- T *p = 0;
- T *n = d?d->next:0;
- swap = 0;
-
- while(d && n)
- {
- if(compare(*n,*d))
- {
- T* q = n->next;
-
- n->next = d;
- d->next = q;
-
- if(p) p->next = n;
- else first = n;
-
- swap++;
- break;
- }
-
- p = d;
- d = n;
- n = n->next;
- }
- }
- }
- T *d = first;
- while(d)
- {
- next(*d);
- d = d->next;
- }
- return first;
-}
diff --git a/ecflow_4_0_7/view/src/lister.h b/ecflow_4_0_7/view/src/lister.h
deleted file mode 100644
index 8454931..0000000
--- a/ecflow_4_0_7/view/src/lister.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef lister_H
-#define lister_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-template<class T>
-class lister {
-public:
- virtual void next(T&) = 0;
- virtual bool sort() { return false; }
- virtual bool compare(T& a,T& b);
- virtual T* scan(T*);
-};
-
-template<class T>
-bool lister<T>::compare(T& a,T& b)
-{ return strcmp(a.name().c_str(),b.name().c_str()) < 0; }
-
-#if defined(__GNUC__) || defined(hpux) || defined(_AIX)
-#include "lister.cc"
-#endif
-
-/*
-#ifdef AIX
-#pragma implementation("lister.cc")
-#endif
-*/
-
-#endif
diff --git a/ecflow_4_0_7/view/src/log_event.cc b/ecflow_4_0_7/view/src/log_event.cc
deleted file mode 100644
index 41a88be..0000000
--- a/ecflow_4_0_7/view/src/log_event.cc
+++ /dev/null
@@ -1,355 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #10 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <stdlib.h>
-#include "log_event.h"
-#include "ecflowview.h"
-#include "gui.h"
-#include "host.h"
-#include "node.h"
-#include "parser.h"
-#include "array.h"
-#include "ecf_node.h"
-
-const int boxSize = 3;
-
-namespace status {
-const char *status_name[10]= {
- (char*)"unknown", (char*)"suspended", (char*)"complete", (char*)"queued",
- (char*)"submitted", (char*)"active", (char*)"aborted", (char*)"shutdown",
- (char*)"halted" , NULL };
-}
-
-static event_sorter* sorter = 0;
-
-class log_cache : public array<log_event*> {
-public:
- void reset();
- void sort();
- ~log_cache() { reset(); }
-};
-
-static log_cache cache;
-static str cached;
-
-void log_cache::reset()
-{
- int c = count();
- for(int i = 0; i < c ; i++)
- (*this)[i]->detach();
- clear();
-}
-
-static int compare(const void* a,const void* b)
-{
- log_event** ea = (log_event**)a;
- log_event** eb = (log_event**)b;
- return sorter->compare(*ea,*eb);
-}
-
-void log_cache::sort()
-{
- qsort(values_,count_,sizeof(log_event*),compare);
-}
-
-static node* gn = 0;
-
-log_event::log_event(node* n,const DateTime& time):
- time_(time),
- node_(n)
-{
- attach();
- cache.add(this);
- observe(n);
-}
-
-log_event::~log_event()
-{
-}
-
-
-void log_event::load(host& h,const char* name,bool reset)
-{
- if(reset)
- {
- cache.reset();
- cached = str();
- }
-
- if(str(name) != cached)
- {
- gn = h.top();
- std::string varlog = gn->variable("ECF_LOG");
- std::string varhom = gn->variable("ECF_HOME");
- std::string varnod = gn->variable("ECF_NODE");
-
- if (gn->variable("ECF_PORT") == ecf_node::none()) {
- varlog = gn->variable("SMSLOG");
- varhom = gn->variable("SMSHOME");
- varnod = gn->variable("SMSNODE");
- }
- char* vartmp = getenv("TMPDIR");
-
- char buf[1024];
- const char* p = name;
-
- while(*p)
- {
- int i = 0;
- while(*p && *p != ' ')
- buf[i++] = *p++;
- buf[i] = 0;
-
- if(i) {
- struct stat st;
- if (stat(buf, &st) == (-1)) {
- if (vartmp) {
- char cmd[1024];
-
- sprintf(cmd,"%s/%s",vartmp,varlog.c_str());
- if (stat(cmd, &st) == (-1)) {
- sprintf(cmd,"rcp %s:%s/%s %s/.", varnod.c_str(), varhom.c_str(), varlog.c_str(),
- getenv((char*)"TMPDIR"));
- printf("%s\n", cmd);
- system(cmd);
-
- ::sleep(1);
- sprintf(cmd,"%s/%s",vartmp,varlog.c_str());
- { if (stat(cmd, &st) == (-1)) {
- sprintf(cmd,"scp %s:%s/%s %s/.", varnod.c_str(), varhom.c_str(), varlog.c_str(),
- getenv((char*)"TMPDIR"));
- printf("%s\n", cmd);
- system(cmd);
- }
- sprintf(cmd,"%s/%s",vartmp,varlog.c_str());
- ::sleep(1);
- }
-
- if (stat(cmd, &st) != (-1)) parser::parse(cmd);
- } else {
- parser::parse(cmd);
- };
- }
- } else {
- parser::parse(buf);
- }
- }
- if(*p) p++;
- }
-
- gn = 0;
- cached = name;
- }
-}
-
-void log_event::sort(event_sorter& l)
-{
- sorter = &l;
- cache.sort();
- sorter = 0;
-}
-
-void log_event::scan(node* n,event_lister& l)
-{
- int c = cache.count();
- for(int i = 0; i < c ; i++)
- if(cache[i]->node_ != 0)
- if(cache[i]->node_->is_my_parent(n))
- l.next(cache[i]);
-}
-
-const node* log_event::find(const char* name)
-{
- return gn?gn->find(name):0;
-}
-
-
-void log_event::size(Widget,XRectangle* r)
-{
- r->width = r->height = 2*boxSize;
-}
-
-void log_event::draw(Widget w,XRectangle* r)
-{
- GC gc = gui::blackGC();
- XFillRectangles(XtDisplay(w), XtWindow(w), gc, r, 1); // was comment
- XDrawLine(XtDisplay(w), XtWindow(w), gc,
- r->x,
- r->y,
- r->x + r->width,
- r->y + r->height);
-
- XDrawLine(XtDisplay(w), XtWindow(w), gc,
- r->x,
- r->y + r->height,
- r->x + r->width,
- r->y);
-}
-
-class status_event : public log_event {
- int status_;
- virtual void draw(Widget,XRectangle*);
-
- virtual bool start();
- virtual bool end();
- virtual char* text(char*);
-
- virtual int status() { return status_; }
-
-public:
- status_event(node* n,const DateTime& time,int status):
- log_event(n,time), status_(status) {}
-};
-
-char* status_event::text(char* buf)
-{
- sprintf(buf,"%s %s is %s",node_->type_name(),node_->full_name().c_str(),
- status::status_name[status_]);
- return buf;
-}
-
-class event_event : public log_event {
- bool set_;
- virtual node* owner() { return node_->parent(); }
- virtual void draw(Widget,XRectangle*);
- virtual char* text(char*);
-public:
- event_event(node* n,const DateTime& time,bool s): log_event(n,time), set_(s) {}
-};
-
-char* event_event::text(char* buf)
-{
- sprintf(buf,"event %s is %s",
- node_->full_name().c_str(),
- set_?"set":"cleared");
- return buf;
-}
-
-//===========================================
-void event_event::draw(Widget w,XRectangle* r)
-{
- if(set_)
- XFillRectangles(XtDisplay(w),XtWindow(w),
- gui::blueGC(),r,1);
- else
- XDrawRectangles(XtDisplay(w),XtWindow(w),
- gui::blueGC(),r,1);
-}
-
-//===========================================
-class meter_event : public log_event {
- int step_;
- virtual node* owner() { return node_->parent(); }
- virtual void draw(Widget,XRectangle*);
- virtual char* text(char*);
-public:
- meter_event(node* n,const DateTime& time,int s): log_event(n,time), step_(s) {}
-};
-
-char* meter_event::text(char* buf)
-{
- sprintf(buf,"meter %s reaches %d",node_->full_name().c_str(),step_);
- return buf;
-}
-
-void meter_event::draw(Widget w,XRectangle* r)
-{
- XDrawArc(XtDisplay(w),
- XtWindow(w),
- gui::blackGC(),
- r->x,
- r->y,
- r->height,
- r->height,
- 0,360*64);
-#if 0
- char buf[80];
- sprintf(buf,"%d",step_);
- xmstring s(buf);
- XmStringDraw(XtDisplay(w),XtWindow(w),
- gui::tinyfont(),
- s,
- gui::blackGC(),
- r->x,
- r->y,
- r->width,
- XmALIGNMENT_CENTER, XmSTRING_DIRECTION_L_TO_R, r);
-#endif
-}
-
-bool status_event::start()
-{
- return status_ == STATUS_SUBMITTED;
-}
-
-bool status_event::end()
-{
- return status_ == STATUS_COMPLETE;
-}
-
-//=========================================================
-
-void status_event::draw(Widget w,XRectangle* r)
-{
- GC gc = gui::colorGC(status_);
-#if 1
- XFillArc(XtDisplay(w),
- XtWindow(w),
- gc,
- r->x,
- r->y,
- r->height,
- r->height,
- 0,360*64);
-#else
- XDrawLine(XtDisplay(w), XtWindow(w), gc,
- r->x,
- r->y,
- r->x + r->width,
- r->y + r->height);
-
- XDrawLine(XtDisplay(w), XtWindow(w), gc,
- r->x,
- r->y + r->height,
- r->x + r->width,
- r->y);
-#endif
-}
-
-void log_event::status_event(const DateTime& t,node* n,int s)
-{
- if (0) {
- if (n)
- std::cout << "# event: " << t.date << " " << t.time << " " << n->full_name() << " " << status::status_name[s] << "\n";
- else
- std::cout << "# event: " << t.date << " " << t.time << " no path " << status::status_name[s] << "\n";
- }
- if(n) new ::status_event(n,t,s);
-}
-
-void log_event::event_event(const DateTime& t,node* n,bool set)
-{
- if(n) new ::event_event(n,t,set);
-}
-
-void log_event::meter_event(const DateTime& t,node* n,int s)
-{
- if(n) new ::meter_event(n,t,s);
-}
-
-void log_event::gone(observable*)
-{
- node_ = 0;
-}
diff --git a/ecflow_4_0_7/view/src/log_event.h b/ecflow_4_0_7/view/src/log_event.h
deleted file mode 100644
index 6f8f53a..0000000
--- a/ecflow_4_0_7/view/src/log_event.h
+++ /dev/null
@@ -1,132 +0,0 @@
-#ifndef log_event_H
-#define log_event_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#ifdef NO_BOOL
-#include "bool.h"
-#endif
-
-#ifndef counted_H
-#include "counted.h"
-#endif
-
-#ifndef observer_H
-#include "observer.h"
-#endif
-
-#include <Xm/Xm.h>
-#include "SimpleTime.h"
-
-class node;
-class host;
-class log_event;
-class str;
-
-class event_lister {
-public:
- virtual void next(log_event*) = 0;
-};
-
-class event_sorter {
-public:
- virtual int compare(log_event*,log_event*) = 0;
-};
-
-inline
-bool operator<(const DateTime& d1,const DateTime& d2)
-{
- return d1.date < d2.date || (d1.date == d2.date && d1.time < d2.time);
-}
-
-inline
-bool operator>(const DateTime& d1,const DateTime& d2)
-{
- return d2 < d1;
-}
-
-inline
-bool operator<=(const DateTime& d1,const DateTime& d2)
-{
- return d1.date <= d2.date || (d1.date == d2.date && d1.time <= d2.time);
-}
-
-
-inline
-bool operator==(const DateTime& d1,const DateTime& d2)
-{
- return (d1.date == d2.date) && (d1.time == d2.time);
-}
-
-inline
-bool operator!=(const DateTime& d1,const DateTime& d2)
-{
- return !(d1==d2);
-}
-
-const DateTime kSmallDate = { 19000101, 0};
-const DateTime kLargeDate = { 21000101, 0};
-
-class log_event : public counted, public observer {
-public:
-
- log_event(node*,const DateTime&);
-
- const DateTime& time() const { return time_; }
-
- virtual bool start() { return false; }
- virtual bool end() { return false; }
-
- virtual node* owner() { return node_; }
- virtual node* get_node() { return node_; }
-
- virtual int status() { return -1; }
-
- virtual char* text(char*) = 0;
-
- virtual void draw(Widget,XRectangle*);
- virtual void size(Widget,XRectangle*);
-
- static void status_event(const DateTime&,node*,int);
- static void event_event(const DateTime&,node*,bool);
- static void meter_event(const DateTime&,node*,int);
-
- static void load(host&,const char*,bool = false);
- static void scan(node*,event_lister&);
- static void sort(event_sorter&);
- static const node* find(const char*);
-
- static int compare(const log_event*,const log_event*);
-
-protected:
-
- virtual ~log_event(); // Change to virtual if base class
-
- DateTime time_;
- node* node_;
-
-private:
-
- log_event(const log_event&);
- log_event& operator=(const log_event&);
-
- void notification(observable*) { }
- void adoption(observable* o,observable* n) { node_ = (node*)n; }
- void gone(observable*);
-};
-
-
-#endif
diff --git a/ecflow_4_0_7/view/src/log_file.h b/ecflow_4_0_7/view/src/log_file.h
deleted file mode 100644
index e689aec..0000000
--- a/ecflow_4_0_7/view/src/log_file.h
+++ /dev/null
@@ -1,129 +0,0 @@
-#ifndef log_file_H
-#define log_file_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#ifndef input_H
-#include "input.h"
-#endif
-
-#include "stl.h"
-
-
-class host;
-class log_event;
-
-class log_file : public input {
-public:
-
-
-// -- Exceptions
- // None
-
-// -- Contructors
-
- log_file(host&,const char*);
-
-// -- Destructor
-
- ~log_file(); // Change to virtual if base class
-
-// -- Convertors
- // None
-
-// -- Operators
- // None
-
-// -- Methods
-
- bool update();
-
-// -- Overridden methods
-
-
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
- // Uncomment for persistent, remove otherwise
- // static os_typespec* get_os_typespec();
-
-protected:
-
-// -- Members
- // None
-
-// -- Methods
-
- // void print(ostream&) const; // Change to virtual if base class
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-private:
-
-// No copy allowed
-
- log_file(const log_file&);
- log_file& operator=(const log_file&);
-
-// -- Members
-
- string path_;
- bool loading_;
- bool ready_;
- time_t last_;
- host& owner_;
-
-// -- Methods
-
- void cleanup();
-
-// -- Overridden methods
-
- void ready(const char*);
- void done(FILE*);
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-// -- Friends
-
- //friend ostream& operator<<(ostream& s,const log_file& p)
- // { p.print(s); return s; }
-
-};
-
-inline void destroy(log_file**) {}
-
-// If persistent, uncomment, otherwise remove
-//#ifdef _ODI_OSSG_
-//OS_MARK_SCHEMA_TYPE(log_file);
-//#endif
-
-#endif
diff --git a/ecflow_4_0_7/view/src/logsvr.cc b/ecflow_4_0_7/view/src/logsvr.cc
deleted file mode 100644
index 3991e94..0000000
--- a/ecflow_4_0_7/view/src/logsvr.cc
+++ /dev/null
@@ -1,246 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#ifndef logsvr_H
-#include "logsvr.h"
-#endif
-
-#ifndef gui_H
-#include "gui.h"
-#endif
-
-#include "tmp_file.h"
-
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/param.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-
-#ifdef AIX
-#include <memory.h>
-#endif
-
-#include "auto_alarm.h"
-
-#define FAIL(a) do { perror(a); exit(1); } while(0)
-
-logsvr::logsvr(std::string host,std::string cport)
- : soc_(-1)
- , host_ (host)
- , port_ (cport)
-{
- struct hostent *ht = gethostbyname( host.c_str() );
- if (ht == NULL) { soc_ = -1; return; }
- connect(host,!cport.empty() ? atoi(cport.c_str()) : 19999);
-}
-
-static jmp_buf env;
-/* static void (*old_alarm)(int); */
-
-static void catch_alarm(int)
-{
- printf("got alarm\n");
- /* longjmp(env,1); */
-}
-
-void logsvr::connect(std::string host,int port)
-{
- /* typedef unsigned long addr_type; */
- typedef in_addr_t addr_type;
-
- /* addr_type none = (addr_type)-1; */
- addr_type addr;
-
- struct sockaddr_in s_in;
- struct hostent *him;
-
- soc_ = socket(AF_INET, SOCK_STREAM, 0);
- if(soc_ < 0)
- {
- gui::syserr("Cannot create socket");
- return;
- }
-
- bzero(&s_in,sizeof(s_in));
-
- s_in.sin_port = htons(port);
- s_in.sin_family = AF_INET;
- addr = inet_addr(host.c_str());
- s_in.sin_addr.s_addr = addr;
-#ifdef SVR4
- if(addr == (in_addr_t) 0xffffffff)
-#else
- if(addr == INADDR_NONE)
-#endif
- {
- if ((him=gethostbyname(host.c_str()))==NULL)
- {
- gui::error("Unknown Host %s",host.c_str());
- return;
- }
- s_in.sin_family = him->h_addrtype;
- bcopy(him->h_addr_list[0],&s_in.sin_addr,him->h_length);
- }
-
- char* timeout = getenv ("ECFLOWVIEW_LOGTIMEOUT");
- int time_out = timeout ? atoi(timeout) : 3;
-
- struct sigaction sa = { { 0, }, };
- struct sigaction old;
- sa.sa_handler = catch_alarm;
- sigemptyset(&sa.sa_mask);
-
- if(sigaction(SIGALRM, &sa, &old))
- perror("sigaction");
-
- ::alarm(time_out);
- perror("alarm");
-
- if(setjmp(env) == 0)
- {
- printf("connect %s\n",host.c_str());
- if(::connect(soc_,(struct sockaddr*)&s_in,sizeof(s_in)) < 0)
- {
- perror("connect");
- close(soc_);
- soc_ = -1;
- }
- }
- else
- {
- printf("cleanup up\n");
- close(soc_);
- soc_ = -1;
- }
- ::alarm(0);
- sigaction(SIGALRM, &old, &sa);
-
-}
-
-logsvr::~logsvr()
-{
- close(soc_);
-}
-
-tmp_file logsvr::getfile(std::string name)
-{
- tmp_file empty((char*)"",false);
- if(soc_ < 0)
- return empty;
-
- write(soc_,"get ",4);
- write(soc_,name.c_str(),name.size());
- write(soc_,"\n",1);
-
- const int size = 64*1204;
- char buf[size];
- unsigned int len = 0;
- int total = 0;
-
- tmp_file out(tmpnam(NULL));
- FILE *f = fopen(out.c_str(),"w");
-
- if(!f)
- {
- char buf[2048];
- sprintf(buf,"Cannot create %s",out.c_str());
- gui::syserr(buf);
- return empty;
- }
-
- while( (len = read(soc_,buf,size)) > 0)
- {
- if(fwrite(buf,1,len,f) != len)
- {
- char buf[2048];
- sprintf(buf,"Write error on %s",out.c_str());
- gui::syserr(buf);
- fclose(f);
- return empty;
- }
- total += len;
- }
-
- sprintf(buf, "\n# served by %s@%s # telnet %s %s # get %s",
- host_.c_str(), port_.c_str(),
- host_.c_str(), port_.c_str(),
- name.c_str());
- fwrite(buf,1,size,f);
-
- if(fclose(f))
- {
- char buf[2048];
- sprintf(buf,"Write error on %s",out.c_str());
- gui::syserr(buf);
- return empty;
- }
-
- if(total)
- return out;
-
- return empty;
-}
-
-ecf_dir *logsvr::getdir(const char* name)
-{
- if(soc_ < 0)
- return 0;
-
- write(soc_,"list ",5);
- write(soc_,name,strlen(name));
- write(soc_,"\n",1);
-
- FILE* f = fdopen(soc_,"r");
-
- char buf[2048];
-
- ecf_dir* dir = 0;
-
- while(fgets(buf,sizeof(buf),f))
- {
- ecf_dir *s;
- if( (s = new ecf_dir()))
- {
- s->next = 0x0;
- char name[2048];
- sscanf(buf,"%d %d %d %d %d %d %d %s",
- & s->mode,
- & s->uid,
- & s->gid,
- & s->size,
- & s->atime,
- & s->mtime,
- & s->ctime,
- name);
-
- s->name_ = strdup(name);
- // ecf_list_add(&dir,s);
- if (dir) {
- s->next = dir->next;
- dir->next = s;
- } else dir = s;
- }
- }
-
- return dir;
-}
diff --git a/ecflow_4_0_7/view/src/logsvr.h b/ecflow_4_0_7/view/src/logsvr.h
deleted file mode 100644
index 4377618..0000000
--- a/ecflow_4_0_7/view/src/logsvr.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef logsvr_H
-#define logsvr_H
-
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#ifndef ecflowview_H
-#include "ecflowview.h"
-#endif
-
-
-#ifndef tmp_file_H
-#include "tmp_file.h"
-#endif
-
-
-class logsvr {
-public:
-
- logsvr(std::string host,std::string port);
-
- ~logsvr(); // Change to virtual if base class
-
- tmp_file getfile(std::string name);
- ecf_dir* getdir(const char* name);
- bool ok() const { return soc_ >= 0; }
-
-private:
-
- logsvr(const logsvr&);
- logsvr& operator=(const logsvr&);
-
- int soc_;
-
- void connect(std::string,int);
-
- std::string host_, port_;
-};
-
-inline void destroy(logsvr**) {}
-
-#endif
diff --git a/ecflow_4_0_7/view/src/mail.cc b/ecflow_4_0_7/view/src/mail.cc
deleted file mode 100644
index cf05ab0..0000000
--- a/ecflow_4_0_7/view/src/mail.cc
+++ /dev/null
@@ -1,246 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "mail.h"
-#include "host.h"
-#include "runnable.h"
-#include <Xm/List.h>
-#include <Xm/Text.h>
-#include "gui.h"
-#include "extent.h"
-
-extern "C" {
-#include "xec.h"
-}
-
-
-class mail_user : public extent<mail_user> {
- char *host_;
- char *user_;
- bool mark_;
-public:
-
- mail_user(const char* h,const char* u):
- host_(XtNewString(h)),
- user_(XtNewString(u)),
- mark_(true)
- {
- }
-
- ~mail_user()
- {
- XtFree(host_);
- XtFree(user_);
- }
-
- static void add(mail&,const char*,const char*);
- static void remove(mail&,const char*);
-
- static void mark();
- static void sweep(mail&,const char*);
-};
-
-void mail_user::mark()
-{
- mail_user *p = first();
- while(p)
- {
- p->mark_ = false;
- p = p->next();
- }
-}
-
-void mail_user::add(mail& m,const char* h,const char* u)
-{
- mail_user *p = first();
- while(p)
- {
- if(strcmp(p->host_,h) == 0 && strcmp(p->user_,u) == 0)
- {
- p->mark_ = true;
- return;
- }
- p = p->next();
- }
- new mail_user(h,u);
- m.add(h,u);
-}
-
-void mail_user::remove(mail& m,const char* h)
-{
- mail_user *p = first();
- while(p)
- {
- mail_user* n = p->next();
- if(strcmp(p->host_,h) == 0)
- {
- m.remove(p->host_,p->user_);
- delete p;
- }
- p = n;
- }
-}
-
-void mail_user::sweep(mail& m,const char* h)
-{
- mail_user *p = first();
- while(p)
- {
- mail_user* n = p->next();
- if(strcmp(p->host_,h) == 0 && !p->mark_)
- {
- m.remove(p->host_,p->user_);
- delete p;
- }
- p = n;
- }
-}
-
-mail& mail::instance()
-{
- static mail *m = new mail();
- return *m;
-}
-
-mail::mail():
- timeout(1)
-{
- create(gui::top());
-}
-
-mail::~mail()
-{
-}
-
-void mail::run()
-{
- //printf("mail::run\n");
- host::check_all_mail();
- drift(1,3600*24);
-}
-
-void mail::recieved(host* h,std::list< std::string >&l,bool show)
-{
- instance().new_mail(h,l,show);
-}
-
-class show_mail : public runnable {
- Widget widget_;
- void run() { XtManageChild(widget_); disable(); gui::raise(); }
-public:
- show_mail() : widget_(0) {}
- void show(Widget w) { widget_ = w; enable(); }
-};
-
-
-void mail::add(const char* buf)
-{
- long len = XmTextGetLastPosition(text_);
- XmTextSetInsertionPosition(text_,len);
- XmTextReplace(text_,len,len,(char*)buf);
- len += strlen(buf);
- XmTextSetInsertionPosition(text_,len);
- XmTextShowPosition(text_,len);
-}
-
-
-void mail::new_mail(host* h,std::list<std::string>& l,bool show)
-{
- mail_user::mark();
-
- static show_mail s;
- observe(h);
- if(show) {
- s.show(form_);
- enable();
- }
-
- mail_user::sweep(*this,h->name());
-}
-
-void mail::sendCB(Widget,XtPointer)
-{
- int count;
- XtVaGetValues(list_,XmNselectedItemCount,&count,NULL);
- if(count == 0)
- {
- /* xec_ListSelectAll(list_); */
- /* XtVaGetValues(list_,XmNselectedItemCount,&count,0); */
- gui::error("No recipient selected");
- return;
- }
-
- XmString *items;
- XtVaGetValues(list_,XmNselectedItems,&items,NULL);
-
- char* p = XmTextGetString(input_);
- XmTextSetString(input_,"");
-
- for(int i = 0 ; i < count; i++)
- {
- char *u = xec_GetString(items[i]);
- char *q = u;
- while(*q && *q != '@') q++;
- *q = 0;
-
- (void)host::find(q+1);
- XtFree(u);
- }
-
- add(p);
- add("\n");
-
- XtFree(p);
- run();
- frequency(1);
-}
-
-void mail::closeCB(Widget,XtPointer)
-{
- disable();
- XtUnmanageChild(form_);
-}
-
-void mail::gone(observable* h)
-{
- mail_user::remove(*this,((host*)h)->name());
-}
-
-void mail::add(const char* h,const char* u)
-{
- char buf[1024];
- sprintf(buf,"%s@%s",u,h);
- xec_AddListItem(list_,buf);
-}
-
-void mail::remove(const char* h,const char* u)
-{
- char buf[1024];
- sprintf(buf,"%s@%s",u,h);
- xec_RemoveListItem(list_,buf);
-}
-
-
-void mail::login(const char* n)
-{
- // FILL recieved(host::find(n),0,false);
-}
-
-void mail::logout(const char* n)
-{
- instance().gone(host::find(n));
-}
-
-IMP(mail_user)
diff --git a/ecflow_4_0_7/view/src/mail.h b/ecflow_4_0_7/view/src/mail.h
deleted file mode 100644
index 45aef5d..0000000
--- a/ecflow_4_0_7/view/src/mail.h
+++ /dev/null
@@ -1,67 +0,0 @@
-#ifndef mail_H
-#define mail_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include<list>
-#include "uimail.h"
-#include "observer.h"
-#include "timeout.h"
-
-#ifdef NO_BOOL
-#include "bool.h"
-#endif
-
-#include <string>
-
-class host;
-
-class mail : public observer, public mail_shell_c, public timeout {
-public:
-
- mail();
-
- ~mail(); // Change to virtual if base class
-
- void add(const char*,const char*);
- void remove(const char*,const char*);
-
- static void recieved(host*,std::list< std::string >&,bool = true);
- static void login(const char*);
- static void logout(const char*);
-
-private:
-
- mail(const mail&);
- mail& operator=(const mail&);
-
- void new_mail(host* h,std::list<std::string>& l,bool show);
- // void new_mail(host*,std::list< std::string >&,bool);
- void add(const char*);
-
- virtual void run();
- virtual void adoption(observable*,observable*) {}
- virtual void notification(observable*) {}
- virtual void gone(observable*);
-
- static mail& instance();
-
- void sendCB(Widget,XtPointer);
- void closeCB(Widget,XtPointer);
-};
-
-inline void destroy(mail**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/manual.cc b/ecflow_4_0_7/view/src/manual.cc
deleted file mode 100644
index 12e5b6c..0000000
--- a/ecflow_4_0_7/view/src/manual.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "manual.h"
-#include "host.h"
-#include "node.h"
-#include <Xm/Text.h>
-
-extern "C" {
-#include "xec.h"
-}
-
-manual::manual(panel_window& w):
- panel(w),
- text_window(false)
-{
-}
-
-manual::~manual()
-{
-}
-
-void manual::clear()
-{
- text_window::clear();
-}
-
-void manual::show(node& n)
-{
- load(n.serv().manual(n));
-}
-
-Boolean manual::enabled(node& n)
-{
- return n.hasManual();
-}
-
-void manual::create (Widget parent, char *widget_name )
-{
- manual_form_c::create(parent,widget_name);
-}
diff --git a/ecflow_4_0_7/view/src/manual.h b/ecflow_4_0_7/view/src/manual.h
deleted file mode 100644
index a920f2b..0000000
--- a/ecflow_4_0_7/view/src/manual.h
+++ /dev/null
@@ -1,66 +0,0 @@
-#ifndef manual_H
-#define manual_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "uimanual.h"
-
-#ifndef panel_H
-#include "panel.h"
-#endif
-
-#ifndef text_window_H
-#include "text_window.h"
-#endif
-
-class manual : public panel, public manual_form_c, public text_window {
-public:
-
- manual(panel_window&);
-
- ~manual(); // Change to virtual if base class
-
- virtual const char* name() const { return "Manual"; }
- virtual void show(node&);
- virtual Boolean enabled(node&);
- virtual void clear();
- virtual Widget widget() { return manual_form_c::xd_rootwidget(); }
-
- virtual Widget tools() { return tools_; }
- virtual Widget text() { return text_; }
- virtual void create (Widget parent, char *widget_name = 0 );
-
-private:
-
- manual(const manual&);
- manual& operator=(const manual&);
-
- virtual void externalCB(Widget ,XtPointer )
- { text_window::open_viewer();}
-
- virtual void searchCB(Widget ,XtPointer )
- { text_window::open_search();}
-
- virtual bool can_print() { return true; }
- virtual bool can_save() { return true; }
- virtual void print() { text_window::print(); }
- virtual void save() { text_window::save(); }
-
-};
-
-inline void destroy(manual**) {}
-
-#endif
diff --git a/ecflow_4_0_7/view/src/menu2c.sh b/ecflow_4_0_7/view/src/menu2c.sh
deleted file mode 100644
index 5276576..0000000
--- a/ecflow_4_0_7/view/src/menu2c.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/ksh
-
-## Copyright 2009-2012 ECMWF.
-## This software is licensed under the terms of the Apache Licence version 2.0
-## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-## In applying this licence, ECMWF does not waive the privileges and immunities
-## granted to it by virtue of its status as an intergovernmental organisation
-## nor does it submit to any jurisdiction.
-
-
-# cat ecflowview.menu | menu2c.sh > ecflowview.menu.h
-while read -r line ; do
- l=$(echo $line | sed -e 's:":\\":gi')
- echo "(char*) \" $l \","
-done
-echo NULL
diff --git a/ecflow_4_0_7/view/src/menu_prefs.cc b/ecflow_4_0_7/view/src/menu_prefs.cc
deleted file mode 100644
index 3e0889a..0000000
--- a/ecflow_4_0_7/view/src/menu_prefs.cc
+++ /dev/null
@@ -1,75 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "arch.h"
-#include "menu_prefs.h"
-#include "gui.h"
-#include "xec.h"
-#include "extent.h"
-#include <ctype.h>
-#include <Xm/Text.h>
-#include <Xm/ToggleB.h>
-#include <Xm/List.h>
-#include "menus.h"
-
-void menu_prefs::create(Widget w,char*)
-{
- menu_form_c::create(w);
- prefs::setup(w);
- build_list();
-}
-
-void menu_prefs::build_list()
-{
- XmListDeleteAllItems(list_);
- menus::fillList(list_);
-}
-
-void menu_prefs::menuCB(Widget,XtPointer)
-{
-}
-
-void menu_prefs::addCB(Widget,XtPointer)
-{
-
-}
-
-void menu_prefs::removeCB(Widget,XtPointer)
-{
-
-}
-
-void menu_prefs::check_remove()
-{
-}
-
-void menu_prefs::browseCB(Widget,XtPointer data)
-{
- XmListCallbackStruct *cb = (XmListCallbackStruct *) data;
- char *p = xec_GetString(cb->item);
- char *q = p;
- while(*q && *q == ' ') q++;
- XmTextSetString(title_,q);
- XtFree(p);
-}
-
-
-void menu_prefs::changedCB(Widget,XtPointer data)
-{
-}
-
-void menu_prefs::updateCB(Widget,XtPointer data)
-{
-}
diff --git a/ecflow_4_0_7/view/src/menu_prefs.h b/ecflow_4_0_7/view/src/menu_prefs.h
deleted file mode 100644
index 1f9f794..0000000
--- a/ecflow_4_0_7/view/src/menu_prefs.h
+++ /dev/null
@@ -1,60 +0,0 @@
-#ifndef menu_prefs_H
-#define menu_prefs_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#ifndef prefs_H
-#include "prefs.h"
-#endif
-
-#ifndef uimenu
-#include "uimenu.h"
-#endif
-
-class menu_prefs : public prefs, public menu_form_c {
-public:
- menu_prefs() : changing_(false) {}
-
- ~menu_prefs() {}
-
- void check_remove();
-
- virtual Widget widget() { return _xd_rootwidget; }
-
- static void add_host(const char*);
-
-private:
-
- menu_prefs(const menu_prefs&);
- menu_prefs& operator=(const menu_prefs&);
-
- bool changing_;
-
- void build_list();
-
- virtual void browseCB( Widget w, XtPointer );
-
- virtual void menuCB( Widget w, XtPointer );
- virtual void addCB( Widget w, XtPointer );
- virtual void removeCB( Widget w, XtPointer );
- virtual void updateCB( Widget w, XtPointer );
- virtual void changedCB( Widget w, XtPointer );
-
- virtual void create(Widget w,char*);
-};
-
-inline void destroy(menu_prefs**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/menul.c b/ecflow_4_0_7/view/src/menul.c
deleted file mode 100644
index 9d519bf..0000000
--- a/ecflow_4_0_7/view/src/menul.c
+++ /dev/null
@@ -1,3230 +0,0 @@
-
-#line 3 "<stdout>"
-
-#define YY_INT_ALIGNED short int
-
-/* A lexical scanner generated by flex */
-
-#define FLEX_SCANNER
-#define YY_FLEX_MAJOR_VERSION 2
-#define YY_FLEX_MINOR_VERSION 5
-#define YY_FLEX_SUBMINOR_VERSION 35
-#if YY_FLEX_SUBMINOR_VERSION > 0
-#define FLEX_BETA
-#endif
-
-/* First, we deal with platform-specific or compiler-specific issues. */
-
-/* begin standard C headers. */
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
-
-/* end standard C headers. */
-
-/* flex integer type definitions */
-
-#ifndef FLEXINT_H
-#define FLEXINT_H
-
-/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
-
-#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
-
-/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
- * if you want the limit (max/min) macros for int types.
- */
-#ifndef __STDC_LIMIT_MACROS
-#define __STDC_LIMIT_MACROS 1
-#endif
-
-#include <inttypes.h>
-typedef int8_t flex_int8_t;
-typedef uint8_t flex_uint8_t;
-typedef int16_t flex_int16_t;
-typedef uint16_t flex_uint16_t;
-typedef int32_t flex_int32_t;
-typedef uint32_t flex_uint32_t;
-#else
-typedef signed char flex_int8_t;
-typedef short int flex_int16_t;
-typedef int flex_int32_t;
-typedef unsigned char flex_uint8_t;
-typedef unsigned short int flex_uint16_t;
-typedef unsigned int flex_uint32_t;
-#endif /* ! C99 */
-
-/* Limits of integral types. */
-#ifndef INT8_MIN
-#define INT8_MIN (-128)
-#endif
-#ifndef INT16_MIN
-#define INT16_MIN (-32767-1)
-#endif
-#ifndef INT32_MIN
-#define INT32_MIN (-2147483647-1)
-#endif
-#ifndef INT8_MAX
-#define INT8_MAX (127)
-#endif
-#ifndef INT16_MAX
-#define INT16_MAX (32767)
-#endif
-#ifndef INT32_MAX
-#define INT32_MAX (2147483647)
-#endif
-#ifndef UINT8_MAX
-#define UINT8_MAX (255U)
-#endif
-#ifndef UINT16_MAX
-#define UINT16_MAX (65535U)
-#endif
-#ifndef UINT32_MAX
-#define UINT32_MAX (4294967295U)
-#endif
-
-#endif /* ! FLEXINT_H */
-
-#ifdef __cplusplus
-
-/* The "const" storage-class-modifier is valid. */
-#define YY_USE_CONST
-
-#else /* ! __cplusplus */
-
-/* C99 requires __STDC__ to be defined as 1. */
-#if defined (__STDC__)
-
-#define YY_USE_CONST
-
-#endif /* defined (__STDC__) */
-#endif /* ! __cplusplus */
-
-#ifdef YY_USE_CONST
-#define yyconst const
-#else
-#define yyconst
-#endif
-
-/* Returned upon end-of-file. */
-#define YY_NULL 0
-
-/* Promotes a possibly negative, possibly signed char to an unsigned
- * integer for use as an array index. If the signed char is negative,
- * we want to instead treat it as an 8-bit unsigned char, hence the
- * double cast.
- */
-#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
-
-/* Enter a start condition. This macro really ought to take a parameter,
- * but we do it the disgusting crufty way forced on us by the ()-less
- * definition of BEGIN.
- */
-#define BEGIN (yy_start) = 1 + 2 *
-
-/* Translate the current start state into a value that can be later handed
- * to BEGIN to return to the state. The YYSTATE alias is for lex
- * compatibility.
- */
-#define YY_START (((yy_start) - 1) / 2)
-#define YYSTATE YY_START
-
-/* Action number for EOF rule of a given start state. */
-#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
-
-/* Special action meaning "start processing a new file". */
-#define YY_NEW_FILE yyrestart(yyin )
-
-#define YY_END_OF_BUFFER_CHAR 0
-
-/* Size of default input buffer. */
-#ifndef YY_BUF_SIZE
-#define YY_BUF_SIZE 16384
-#endif
-
-/* The state buf must be large enough to hold one state per character in the main buffer.
- */
-#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
-
-#ifndef YY_TYPEDEF_YY_BUFFER_STATE
-#define YY_TYPEDEF_YY_BUFFER_STATE
-typedef struct yy_buffer_state *YY_BUFFER_STATE;
-#endif
-
-extern int yyleng;
-
-extern FILE *yyin, *yyout;
-
-#define EOB_ACT_CONTINUE_SCAN 0
-#define EOB_ACT_END_OF_FILE 1
-#define EOB_ACT_LAST_MATCH 2
-
- /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires
- * access to the local variable yy_act. Since yyless() is a macro, it would break
- * existing scanners that call yyless() from OUTSIDE yylex.
- * One obvious solution it to make yy_act a global. I tried that, and saw
- * a 5% performance hit in a non-yylineno scanner, because yy_act is
- * normally declared as a register variable-- so it is not worth it.
- */
- #define YY_LESS_LINENO(n) \
- do { \
- int yyl;\
- for ( yyl = n; yyl < yyleng; ++yyl )\
- if ( yytext[yyl] == '\n' )\
- --yylineno;\
- }while(0)
-
-/* Return all but the first "n" matched characters back to the input stream. */
-#define yyless(n) \
- do \
- { \
- /* Undo effects of setting up yytext. */ \
- int yyless_macro_arg = (n); \
- YY_LESS_LINENO(yyless_macro_arg);\
- *yy_cp = (yy_hold_char); \
- YY_RESTORE_YY_MORE_OFFSET \
- (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
- YY_DO_BEFORE_ACTION; /* set up yytext again */ \
- } \
- while ( 0 )
-
-#define unput(c) yyunput( c, (yytext_ptr) )
-
-#ifndef YY_TYPEDEF_YY_SIZE_T
-#define YY_TYPEDEF_YY_SIZE_T
-typedef size_t yy_size_t;
-#endif
-
-#ifndef YY_STRUCT_YY_BUFFER_STATE
-#define YY_STRUCT_YY_BUFFER_STATE
-struct yy_buffer_state
- {
- FILE *yy_input_file;
-
- char *yy_ch_buf; /* input buffer */
- char *yy_buf_pos; /* current position in input buffer */
-
- /* Size of input buffer in bytes, not including room for EOB
- * characters.
- */
- yy_size_t yy_buf_size;
-
- /* Number of characters read into yy_ch_buf, not including EOB
- * characters.
- */
- int yy_n_chars;
-
- /* Whether we "own" the buffer - i.e., we know we created it,
- * and can realloc() it to grow it, and should free() it to
- * delete it.
- */
- int yy_is_our_buffer;
-
- /* Whether this is an "interactive" input source; if so, and
- * if we're using stdio for input, then we want to use getc()
- * instead of fread(), to make sure we stop fetching input after
- * each newline.
- */
- int yy_is_interactive;
-
- /* Whether we're considered to be at the beginning of a line.
- * If so, '^' rules will be active on the next match, otherwise
- * not.
- */
- int yy_at_bol;
-
- int yy_bs_lineno; /**< The line count. */
- int yy_bs_column; /**< The column count. */
-
- /* Whether to try to fill the input buffer when we reach the
- * end of it.
- */
- int yy_fill_buffer;
-
- int yy_buffer_status;
-
-#define YY_BUFFER_NEW 0
-#define YY_BUFFER_NORMAL 1
- /* When an EOF's been seen but there's still some text to process
- * then we mark the buffer as YY_EOF_PENDING, to indicate that we
- * shouldn't try reading from the input source any more. We might
- * still have a bunch of tokens to match, though, because of
- * possible backing-up.
- *
- * When we actually see the EOF, we change the status to "new"
- * (via yyrestart()), so that the user can continue scanning by
- * just pointing yyin at a new input file.
- */
-#define YY_BUFFER_EOF_PENDING 2
-
- };
-#endif /* !YY_STRUCT_YY_BUFFER_STATE */
-
-/* Stack of input buffers. */
-static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
-static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
-static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
-
-/* We provide macros for accessing buffer states in case in the
- * future we want to put the buffer states in a more general
- * "scanner state".
- *
- * Returns the top of the stack, or NULL.
- */
-#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
- ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
- : NULL)
-
-/* Same as previous macro, but useful when we know that the buffer stack is not
- * NULL or when we need an lvalue. For internal use only.
- */
-#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
-
-/* yy_hold_char holds the character lost when yytext is formed. */
-static char yy_hold_char;
-static int yy_n_chars; /* number of characters read into yy_ch_buf */
-int yyleng;
-
-/* Points to current character in buffer. */
-static char *yy_c_buf_p = (char *) 0;
-static int yy_init = 0; /* whether we need to initialize */
-static int yy_start = 0; /* start state number */
-
-/* Flag which is used to allow yywrap()'s to do buffer switches
- * instead of setting up a fresh yyin. A bit of a hack ...
- */
-static int yy_did_buffer_switch_on_eof;
-
-void yyrestart (FILE *input_file );
-void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer );
-YY_BUFFER_STATE yy_create_buffer (FILE *file,int size );
-void yy_delete_buffer (YY_BUFFER_STATE b );
-void yy_flush_buffer (YY_BUFFER_STATE b );
-void yypush_buffer_state (YY_BUFFER_STATE new_buffer );
-void yypop_buffer_state (void );
-
-static void yyensure_buffer_stack (void );
-static void yy_load_buffer_state (void );
-static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file );
-
-#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER )
-
-YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size );
-YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str );
-YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len );
-
-void *yyalloc (yy_size_t );
-void *yyrealloc (void *,yy_size_t );
-void yyfree (void * );
-
-#define yy_new_buffer yy_create_buffer
-
-#define yy_set_interactive(is_interactive) \
- { \
- if ( ! YY_CURRENT_BUFFER ){ \
- yyensure_buffer_stack (); \
- YY_CURRENT_BUFFER_LVALUE = \
- yy_create_buffer(yyin,YY_BUF_SIZE ); \
- } \
- YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
- }
-
-#define yy_set_bol(at_bol) \
- { \
- if ( ! YY_CURRENT_BUFFER ){\
- yyensure_buffer_stack (); \
- YY_CURRENT_BUFFER_LVALUE = \
- yy_create_buffer(yyin,YY_BUF_SIZE ); \
- } \
- YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
- }
-
-#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
-
-typedef unsigned char YY_CHAR;
-
-FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
-
-typedef int yy_state_type;
-
-#define YY_FLEX_LEX_COMPAT
-extern int yylineno;
-
-int yylineno = 1;
-
-extern char yytext[];
-
-static yy_state_type yy_get_previous_state (void );
-static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
-static int yy_get_next_buffer (void );
-static void yy_fatal_error (yyconst char msg[] );
-
-/* Done after the current pattern has been matched and before the
- * corresponding action - sets up yytext.
- */
-#define YY_DO_BEFORE_ACTION \
- (yytext_ptr) = yy_bp; \
- yyleng = (size_t) (yy_cp - yy_bp); \
- (yy_hold_char) = *yy_cp; \
- *yy_cp = '\0'; \
- if ( yyleng + (yy_more_offset) >= YYLMAX ) \
- YY_FATAL_ERROR( "token too large, exceeds YYLMAX" ); \
- yy_flex_strncpy( &yytext[(yy_more_offset)], (yytext_ptr), yyleng + 1 ); \
- yyleng += (yy_more_offset); \
- (yy_prev_more_offset) = (yy_more_offset); \
- (yy_more_offset) = 0; \
- (yy_c_buf_p) = yy_cp;
-
-#define YY_NUM_RULES 139
-#define YY_END_OF_BUFFER 140
-/* This struct is not used in this scanner,
- but its presence is necessary. */
-struct yy_trans_info
- {
- flex_int32_t yy_verify;
- flex_int32_t yy_nxt;
- };
-static yyconst flex_int16_t yy_acclist[903] =
- { 0,
- 140, 135, 139, 134, 135, 139, 136, 139, 135, 139,
- 16385, 69, 135, 139, 135, 138, 139, 70, 135, 139,
- 68, 135, 139, 68, 135, 139, 68, 135, 139, 68,
- 135, 139, 68, 135, 139, 68, 135, 139, 68, 135,
- 139, 68, 135, 139, 68, 135, 139, 68, 135, 139,
- 68, 135, 139, 68, 135, 139, 68, 135, 139, 68,
- 135, 139, 68, 135, 139, 68, 135, 139, 68, 135,
- 139, 68, 135, 139, 68, 135, 139, 68, 135, 139,
- 68, 135, 139, 68, 135, 139, 135, 139, 68, 135,
- 139, 68, 135, 139, 68, 135, 139, 68, 135, 139,
-
- 68, 135, 139, 133, 139, 132, 133, 139, 132, 133,
- 139, 133, 139,16385, 133, 138, 139, 133, 139, 131,
- 133, 139, 129, 130, 133, 139, 130, 133, 139, 130,
- 133, 139, 130, 133, 139, 130, 133, 139, 130, 133,
- 139, 130, 133, 139, 130, 133, 139, 130, 133, 139,
- 130, 133, 139, 130, 133, 139, 130, 133, 139, 130,
- 133, 139, 130, 133, 139, 130, 133, 139, 130, 133,
- 139, 130, 133, 139, 130, 133, 139, 130, 133, 139,
- 130, 133, 139, 130, 133, 139, 130, 133, 139, 130,
- 133, 139, 133, 139, 130, 133, 139,16385, 8193, 68,
-
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 40, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68, 131, 129,
- 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
- 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
- 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
- 130, 130, 130, 130, 130, 130, 130, 130, 130, 68,
- 68, 68, 68, 6, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
-
- 68, 68, 68, 68, 68, 68, 68, 15, 68, 68,
- 20, 68, 68, 68, 68, 68, 68, 68, 68, 68,
- 39, 68, 68, 68, 68, 68, 68, 68, 68, 130,
- 130, 130, 130,16504, 130, 130, 130, 130, 130, 130,
- 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
- 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
- 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
- 130, 130, 130, 130, 68, 68, 68, 68, 68, 43,
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 4,
- 68, 68, 68, 21, 68, 5, 68, 46, 68, 42,
-
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
- 24, 68, 68, 45, 68, 68, 68, 3, 68, 68,
- 16434,16435, 48,16433,16436,16444,16445,16443,16504, 8312,
- 130,16504,16446, 130, 130, 130, 130, 130, 130, 130,
- 130, 130, 130, 130, 130,16484, 130, 130, 130, 130,
- 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
- 130, 130, 130,16474, 130, 79, 130, 130, 130,16508,
- 130, 130, 130, 58, 68, 68, 47, 68, 31, 68,
- 14, 68, 68, 25, 68, 68, 68, 68, 68, 68,
- 27, 68, 26, 68, 68, 28, 68, 68, 68, 68,
-
- 68, 68, 68, 68, 68, 22, 68, 68, 68, 68,
- 68, 68,16434, 8242,16435, 8243,16433, 8241,16436, 8244,
- 16444, 8252,16445, 8253,16443, 8251,16446, 8254, 130, 130,
- 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
- 130,16484, 8292,16491, 130, 130,16489, 130, 130, 130,
- 16497, 130, 130, 130, 130, 130,16495, 130, 130, 130,
- 130, 130,16474, 8282, 130,16485,16486, 130, 130, 130,
- 16508, 8316,16487, 130, 130, 130, 68, 12, 68, 68,
- 23, 68, 17, 68, 68, 68, 68, 68, 68, 18,
- 68, 68, 10, 68, 30, 68, 68, 68, 19, 68,
-
- 68, 68, 68, 68, 68, 41, 68, 68, 55, 56,
- 53, 54, 57,16507,16506,16470, 130, 130,16499, 130,
- 130,16496, 130,16467, 130, 80, 130, 130, 130, 130,
- 16491, 8299, 130,16500,16489, 8297, 130,16493,16494, 130,
- 16469,16497, 8305,16476, 130, 130, 130,16475,16495, 8303,
- 130, 130, 130, 130, 130,16486,16485,16486, 8293, 8294,
- 16485,16486,16501, 130, 130,16487, 8295, 130, 130,16512,
- 130, 63, 13, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 7, 68, 68, 2,
- 68,16505,16507, 8315,16506, 8314,16470, 8278, 130, 73,
-
- 16499, 8307, 130, 130,16496, 8304, 81,16467, 8275, 130,
- 130, 130,16498, 130, 130,16500, 8308,16494,16493,16494,
- 8301, 8302,16493,16494, 130,16469, 8277,16476, 8284,16477,
- 16488, 130,16475, 8283, 72, 130, 130, 130,16482,16486,
- 8294,16486,16501, 8309, 130, 130, 130, 130,16512, 8320,
- 130, 9, 68, 35, 68, 36, 68, 34, 68, 68,
- 68, 32, 68, 68, 68, 16, 68, 68, 68, 29,
- 68, 126,16505, 8313, 78, 130, 130, 130,16466,16511,
- 130,16498, 8306, 130, 130,16494, 8302,16494, 130,16477,
- 8285,16488, 8296, 130,16478,16480, 130,16482, 8290, 130,
-
- 16481,16483, 130, 76, 68, 37, 68, 44, 68, 38,
- 68, 11, 68, 8, 68, 130, 130, 130,16466,16511,
- 8274, 8319,16466,16511,16466,16511, 71, 130,16490,16521,
- 16471,16478, 8286,16480, 8288,16479, 130,16481, 8289,16483,
- 8291, 130, 65, 66, 64, 67, 68, 130, 130, 130,
- 16466,16511,16466,16511, 130,16490, 8298,16521, 8329,16471,
- 8279,16479, 8287, 77,16503,16492, 68,16473,16468,16466,
- 16511,16466,16511, 130,16503, 8311,16492, 8300, 33, 68,
- 16473, 8281,16468, 8276,16466,16511,16466,16511, 130, 75,
- 16466,16511, 74,16466,16511,16502,16502, 8310,16472,16472,
-
- 8280, 125
- } ;
-
-static yyconst flex_int16_t yy_accept[802] =
- { 0,
- 1, 1, 1, 1, 1, 2, 4, 7, 9, 12,
- 15, 18, 21, 24, 27, 30, 33, 36, 39, 42,
- 45, 48, 51, 54, 57, 60, 63, 66, 69, 72,
- 75, 78, 81, 84, 87, 89, 92, 95, 98, 101,
- 104, 106, 109, 112, 115, 118, 120, 123, 127, 130,
- 133, 136, 139, 142, 145, 148, 151, 154, 157, 160,
- 163, 166, 169, 172, 175, 178, 181, 184, 187, 190,
- 193, 195, 198, 199, 200, 201, 202, 203, 204, 205,
- 206, 207, 208, 209, 210, 211, 212, 213, 214, 215,
- 216, 218, 219, 220, 221, 222, 223, 224, 225, 226,
-
- 227, 228, 229, 230, 231, 232, 233, 234, 234, 235,
- 236, 237, 238, 239, 239, 239, 239, 240, 242, 243,
- 244, 245, 246, 247, 248, 249, 250, 251, 252, 253,
- 254, 255, 256, 257, 258, 259, 260, 261, 262, 263,
- 264, 265, 266, 267, 268, 269, 270, 271, 272, 273,
- 274, 275, 276, 277, 278, 279, 279, 280, 281, 282,
- 283, 284, 286, 287, 288, 289, 290, 291, 292, 293,
- 294, 295, 296, 297, 298, 299, 300, 301, 302, 303,
- 304, 305, 306, 307, 308, 310, 311, 313, 314, 315,
- 316, 317, 318, 319, 320, 321, 323, 324, 325, 325,
-
- 325, 325, 325, 325, 326, 327, 328, 329, 330, 330,
- 330, 330, 330, 330, 331, 332, 333, 335, 336, 337,
- 338, 339, 340, 341, 342, 343, 344, 345, 346, 347,
- 348, 349, 350, 351, 352, 353, 354, 355, 356, 357,
- 358, 359, 360, 361, 362, 363, 364, 365, 366, 367,
- 368, 369, 370, 371, 372, 373, 374, 374, 374, 374,
- 374, 374, 375, 376, 377, 378, 379, 380, 382, 383,
- 384, 385, 386, 387, 388, 389, 390, 392, 393, 394,
- 396, 398, 400, 402, 403, 404, 405, 406, 407, 408,
- 409, 410, 411, 413, 414, 416, 417, 418, 420, 421,
-
- 421, 421, 421, 421, 421, 422, 423, 424, 425, 426,
- 426, 426, 426, 426, 426, 427, 428, 429, 430, 431,
- 433, 434, 435, 436, 437, 438, 439, 440, 441, 442,
- 443, 444, 445, 446, 447, 448, 449, 450, 451, 452,
- 453, 454, 455, 456, 457, 458, 459, 460, 461, 462,
- 463, 464, 465, 466, 467, 468, 469, 470, 471, 472,
- 473, 473, 474, 474, 474, 474, 474, 474, 475, 476,
- 477, 479, 481, 483, 484, 486, 487, 488, 489, 490,
- 491, 493, 495, 496, 498, 499, 500, 501, 502, 503,
- 504, 505, 506, 508, 509, 510, 511, 512, 513, 513,
-
- 513, 513, 513, 513, 514, 515, 516, 517, 518, 519,
- 520, 521, 521, 521, 521, 521, 521, 522, 523, 524,
- 525, 526, 527, 528, 529, 530, 531, 532, 533, 534,
- 535, 536, 537, 538, 539, 540, 541, 542, 543, 544,
- 545, 546, 547, 548, 549, 550, 551, 552, 553, 554,
- 555, 556, 557, 558, 559, 560, 561, 562, 563, 564,
- 565, 565, 566, 568, 569, 570, 571, 572, 573, 573,
- 574, 575, 576, 576, 577, 577, 577, 577, 577, 577,
- 578, 580, 581, 583, 585, 586, 587, 588, 589, 590,
- 592, 593, 595, 597, 598, 599, 601, 602, 603, 604,
-
- 605, 606, 608, 609, 610, 611, 612, 613, 614, 614,
- 614, 614, 615, 616, 617, 618, 619, 620, 621, 622,
- 623, 624, 625, 626, 627, 628, 629, 630, 631, 632,
- 633, 634, 635, 636, 637, 637, 638, 640, 641, 642,
- 643, 644, 645, 646, 647, 648, 649, 650, 651, 652,
- 653, 654, 655, 656, 657, 659, 661, 663, 664, 665,
- 666, 666, 667, 668, 669, 670, 671, 672, 672, 672,
- 673, 673, 673, 675, 676, 677, 678, 679, 680, 681,
- 682, 683, 684, 685, 686, 687, 689, 690, 692, 692,
- 692, 693, 694, 695, 696, 697, 698, 699, 700, 701,
-
- 702, 703, 704, 705, 706, 707, 708, 709, 710, 711,
- 712, 713, 714, 715, 716, 717, 718, 719, 721, 723,
- 725, 726, 727, 728, 729, 730, 731, 732, 733, 734,
- 735, 736, 737, 738, 739, 740, 741, 742, 743, 744,
- 745, 746, 747, 747, 748, 749, 750, 751, 752, 752,
- 752, 752, 752, 754, 756, 758, 760, 761, 762, 764,
- 765, 766, 768, 769, 770, 772, 772, 773, 774, 775,
- 776, 777, 778, 779, 781, 782, 783, 784, 785, 786,
- 787, 788, 789, 790, 791, 792, 793, 794, 795, 796,
- 797, 798, 799, 800, 801, 802, 802, 803, 804, 805,
-
- 805, 805, 805, 805, 806, 808, 810, 812, 814, 816,
- 816, 817, 818, 819, 821, 823, 825, 827, 828, 829,
- 830, 831, 832, 833, 834, 835, 836, 837, 838, 839,
- 840, 840, 841, 842, 843, 844, 845, 846, 847, 848,
- 848, 849, 850, 851, 853, 855, 856, 857, 858, 859,
- 860, 861, 862, 863, 864, 865, 866, 867, 868, 868,
- 869, 869, 870, 872, 874, 875, 876, 877, 878, 879,
- 881, 881, 882, 883, 883, 884, 885, 887, 889, 890,
- 890, 890, 893, 896, 897, 897, 897, 898, 899, 899,
- 899, 899, 900, 900, 901, 902, 902, 902, 902, 903,
-
- 903
- } ;
-
-static yyconst flex_int32_t yy_ec[256] =
- { 0,
- 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 4, 5, 6, 7, 8, 9, 1, 10, 1,
- 1, 11, 1, 1, 12, 13, 14, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 16, 1, 17,
- 1, 1, 1, 1, 18, 19, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
- 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
- 1, 1, 1, 1, 44, 1, 45, 46, 47, 48,
-
- 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
- 59, 60, 61, 62, 63, 64, 65, 66, 67, 27,
- 68, 69, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1
- } ;
-
-static yyconst flex_int32_t yy_meta[70] =
- { 0,
- 1, 1, 2, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 3, 4, 3, 1, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4
- } ;
-
-static yyconst flex_int16_t yy_base[863] =
- { 0,
- 0, 63, 103, 65, 1222, 1223, 1223, 1223, 1218, 1223,
- 1223, 1223, 0, 54, 47, 1181, 1201, 1200, 1181, 63,
- 56, 1184, 1182, 1185, 1175, 1190, 151, 1193, 55, 1192,
- 1183, 1186, 1158, 1157, 1201, 1185, 61, 156, 157, 62,
- 1223, 1223, 158, 1200, 1223, 1190, 0, 1186, 0, 1181,
- 1164, 1162, 1171, 1178, 131, 1146, 139, 48, 137, 18,
- 1135, 135, 45, 1131, 1136, 1126, 137, 141, 139, 1132,
- 1185, 1156, 1184, 1223, 0, 1154, 1148, 1154, 73, 1161,
- 1152, 1159, 1150, 176, 1135, 1159, 1147, 1156, 177, 1151,
- 178, 1152, 1135, 1150, 1138, 182, 1132, 1133, 194, 1132,
-
- 1139, 1144, 1130, 1133, 1127, 1104, 1099, 202, 1136, 1124,
- 198, 1134, 1122, 1144, 1087, 175, 0, 1139, 0, 1129,
- 1117, 1127, 1129, 1114, 1089, 1083, 1082, 1081, 1093, 1085,
- 1093, 1092, 1083, 178, 1077, 1085, 1088, 1080, 1073, 1088,
- 164, 1082, 1074, 1083, 1082, 1084, 1079, 180, 1069, 181,
- 183, 1064, 1068, 176, 1069, 226, 1099, 1087, 1095, 1094,
- 1101, 0, 1100, 1084, 1085, 1089, 1077, 1069, 1069, 1089,
- 1084, 1081, 1070, 1085, 1071, 1083, 1082, 1068, 1078, 1063,
- 1078, 1077, 1080, 1058, 0, 1059, 0, 1065, 1057, 1060,
- 1064, 1060, 1055, 1063, 1067, 0, 1022, 1023, 1066, 1049,
-
- 1051, 1046, 1063, 1064, 1063, 1062, 1061, 1060, 1063, 1070,
- 1014, 1023, 1018, 1054, 1053, 1052, 266, 1051, 1004, 1012,
- 1015, 1004, 1009, 1014, 1013, 1014, 140, 1009, 1008, 1040,
- 991, 996, 1004, 1005, 1007, 1001, 1000, 198, 983, 989,
- 997, 977, 979, 984, 977, 976, 1024, 991, 200, 981,
- 977, 1020, 986, 976, 1021, 974, 1012, 995, 997, 992,
- 1009, 1010, 988, 985, 992, 986, 986, 991, 982, 989,
- 995, 215, 984, 986, 977, 991, 0, 977, 993, 0,
- 0, 0, 0, 988, 991, 988, 972, 984, 984, 978,
- 981, 980, 0, 969, 0, 982, 967, 0, 945, 973,
-
- 961, 971, 970, 958, 989, 988, 1223, 987, 986, 976,
- 925, 924, 918, 926, 980, 979, 978, 977, 1223, 283,
- 976, 914, 911, 914, 203, 917, 925, 918, 910, 926,
- 914, 905, 910, 964, 210, 902, 949, 915, 900, 906,
- 945, 902, 894, 913, 904, 894, 939, 905, 887, 903,
- 207, 948, 300, 1223, 884, 896, 899, 944, 303, 883,
- 887, 885, 919, 907, 917, 916, 904, 1223, 916, 915,
- 0, 0, 0, 914, 0, 893, 913, 915, 296, 902,
- 0, 0, 910, 0, 893, 908, 891, 890, 908, 890,
- 892, 886, 0, 891, 881, 901, 879, 859, 901, 900,
-
- 899, 898, 897, 909, 1223, 908, 1223, 907, 1223, 906,
- 1223, 904, 842, 859, 842, 853, 900, 1223, 899, 1223,
- 898, 1223, 897, 1223, 287, 850, 882, 852, 847, 879,
- 838, 221, 877, 834, 842, 841, 841, 885, 1223, 884,
- 833, 869, 881, 362, 830, 866, 878, 864, 815, 822,
- 826, 860, 872, 826, 824, 807, 814, 821, 866, 1223,
- 852, 379, 317, 851, 802, 807, 861, 1223, 798, 859,
- 796, 804, 800, 791, 841, 840, 839, 838, 837, 831,
- 0, 814, 0, 0, 813, 808, 818, 821, 827, 0,
- 823, 0, 0, 818, 806, 0, 802, 804, 819, 808,
-
- 809, 0, 779, 1223, 1223, 1223, 1223, 1223, 773, 779,
- 785, 830, 829, 828, 782, 813, 825, 769, 766, 822,
- 808, 820, 763, 1223, 773, 756, 803, 769, 814, 1223,
- 760, 812, 811, 1223, 797, 396, 318, 743, 808, 807,
- 1223, 806, 792, 791, 754, 802, 801, 1223, 787, 740,
- 752, 747, 783, 321, 322, 1223, 323, 795, 733, 748,
- 732, 791, 1223, 729, 747, 788, 732, 776, 775, 1223,
- 774, 773, 0, 763, 762, 746, 760, 757, 754, 758,
- 746, 745, 745, 753, 752, 0, 751, 0, 708, 722,
- 767, 766, 1223, 765, 1223, 764, 1223, 750, 1223, 762,
-
- 1223, 717, 714, 759, 1223, 1223, 758, 1223, 707, 629,
- 556, 590, 519, 470, 515, 1223, 324, 325, 1223, 326,
- 468, 513, 1223, 512, 1223, 511, 510, 448, 508, 1223,
- 1223, 494, 493, 444, 504, 327, 1223, 329, 502, 1223,
- 455, 487, 453, 485, 436, 494, 1223, 480, 484, 483,
- 482, 481, 0, 0, 0, 0, 467, 468, 0, 458,
- 453, 0, 466, 465, 0, 432, 1223, 84, 1223, 1223,
- 191, 209, 200, 396, 243, 258, 1223, 215, 247, 332,
- 1223, 341, 282, 320, 1223, 343, 1223, 331, 346, 347,
- 335, 349, 1223, 305, 351, 307, 353, 309, 1223, 351,
-
- 352, 353, 357, 355, 0, 0, 0, 0, 0, 326,
- 338, 347, 350, 412, 1223, 413, 414, 1223, 366, 417,
- 418, 419, 420, 1223, 421, 1223, 422, 411, 425, 1223,
- 413, 427, 1223, 415, 1223, 1223, 1223, 1223, 397, 377,
- 418, 431, 420, 434, 435, 390, 437, 1223, 438, 1223,
- 439, 1223, 440, 1223, 1223, 441, 442, 410, 443, 445,
- 401, 447, 448, 449, 390, 451, 1223, 452, 1223, 0,
- 393, 454, 1223, 413, 456, 1223, 457, 458, 446, 399,
- 401, 463, 464, 465, 406, 421, 468, 1223, 412, 457,
- 425, 472, 418, 474, 1223, 430, 431, 433, 1223, 1223,
-
- 521, 478, 523, 480, 527, 531, 535, 539, 543, 547,
- 551, 555, 559, 563, 567, 571, 575, 579, 583, 587,
- 591, 595, 599, 603, 607, 611, 615, 619, 623, 627,
- 631, 635, 639, 643, 647, 651, 655, 659, 663, 667,
- 671, 675, 679, 683, 687, 691, 695, 699, 703, 707,
- 711, 715, 719, 723, 727, 731, 735, 739, 743, 747,
- 751, 755
- } ;
-
-static yyconst flex_int16_t yy_def[863] =
- { 0,
- 800, 1, 800, 3, 800, 800, 800, 800, 801, 800,
- 800, 800, 802, 802, 802, 802, 802, 802, 802, 802,
- 802, 802, 802, 802, 802, 802, 802, 802, 802, 802,
- 802, 802, 802, 802, 800, 802, 802, 802, 802, 802,
- 800, 800, 800, 801, 800, 800, 803, 804, 804, 804,
- 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
- 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
- 800, 804, 801, 800, 802, 802, 802, 802, 802, 802,
- 802, 802, 802, 802, 802, 802, 802, 802, 802, 802,
- 802, 802, 802, 802, 802, 802, 802, 802, 802, 802,
-
- 802, 802, 802, 802, 802, 802, 802, 800, 802, 802,
- 802, 802, 802, 800, 800, 800, 803, 804, 804, 804,
- 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
- 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
- 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
- 804, 804, 804, 804, 804, 800, 804, 802, 802, 802,
- 802, 802, 802, 802, 802, 802, 802, 802, 802, 802,
- 802, 802, 802, 802, 802, 802, 802, 802, 802, 802,
- 802, 802, 802, 802, 802, 802, 802, 802, 802, 802,
- 802, 802, 802, 802, 802, 802, 802, 802, 800, 800,
-
- 800, 800, 800, 802, 802, 802, 802, 802, 800, 800,
- 800, 800, 800, 804, 804, 804, 805, 804, 804, 804,
- 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
- 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
- 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
- 804, 804, 804, 804, 804, 804, 800, 800, 800, 800,
- 800, 804, 802, 802, 802, 802, 802, 802, 802, 802,
- 802, 802, 802, 802, 802, 802, 802, 802, 802, 802,
- 802, 802, 802, 802, 802, 802, 802, 802, 802, 802,
- 802, 802, 802, 802, 802, 802, 802, 802, 802, 800,
-
- 800, 800, 800, 800, 806, 807, 800, 808, 809, 800,
- 800, 800, 800, 800, 810, 811, 812, 813, 800, 805,
- 814, 804, 804, 804, 804, 804, 804, 804, 804, 804,
- 804, 804, 804, 815, 804, 804, 804, 804, 804, 804,
- 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
- 804, 816, 817, 800, 804, 804, 804, 818, 804, 804,
- 800, 804, 800, 800, 800, 800, 800, 800, 802, 802,
- 802, 802, 802, 802, 802, 802, 802, 802, 802, 802,
- 802, 802, 802, 802, 802, 802, 802, 802, 802, 802,
- 802, 802, 802, 802, 802, 802, 802, 802, 800, 800,
-
- 800, 800, 800, 806, 800, 807, 800, 808, 800, 809,
- 800, 800, 800, 800, 800, 800, 810, 800, 811, 800,
- 812, 800, 814, 800, 804, 804, 804, 804, 804, 804,
- 804, 804, 804, 804, 804, 804, 804, 815, 800, 819,
- 804, 804, 820, 821, 804, 804, 822, 804, 804, 804,
- 804, 804, 823, 804, 804, 804, 804, 804, 816, 800,
- 824, 817, 825, 804, 804, 804, 818, 800, 800, 826,
- 804, 804, 800, 804, 800, 800, 800, 800, 800, 802,
- 802, 802, 802, 802, 802, 802, 802, 802, 802, 802,
- 802, 802, 802, 802, 802, 802, 802, 802, 802, 802,
-
- 802, 802, 802, 800, 800, 800, 800, 800, 800, 800,
- 800, 827, 828, 829, 804, 804, 830, 804, 804, 831,
- 804, 832, 804, 800, 804, 804, 804, 804, 819, 800,
- 804, 833, 820, 800, 834, 821, 835, 804, 836, 822,
- 800, 837, 804, 804, 804, 838, 823, 800, 804, 804,
- 804, 804, 804, 839, 825, 800, 825, 840, 804, 804,
- 800, 826, 800, 804, 804, 841, 804, 800, 800, 800,
- 800, 800, 802, 802, 802, 802, 802, 802, 802, 802,
- 802, 802, 802, 802, 802, 802, 802, 802, 800, 800,
- 842, 827, 800, 828, 800, 829, 800, 804, 800, 830,
-
- 800, 804, 804, 831, 800, 800, 832, 800, 804, 804,
- 804, 843, 804, 804, 833, 800, 844, 835, 800, 835,
- 804, 836, 800, 837, 800, 845, 846, 804, 838, 800,
- 800, 804, 804, 804, 847, 839, 800, 839, 840, 800,
- 804, 804, 800, 804, 804, 841, 800, 804, 800, 800,
- 800, 800, 802, 802, 802, 802, 802, 802, 802, 802,
- 802, 802, 802, 802, 802, 800, 800, 842, 800, 800,
- 804, 804, 804, 848, 804, 843, 800, 804, 804, 844,
- 800, 844, 804, 845, 800, 846, 800, 804, 849, 850,
- 804, 847, 800, 804, 851, 800, 852, 804, 800, 800,
-
- 800, 800, 800, 802, 802, 802, 802, 802, 802, 800,
- 804, 804, 804, 848, 800, 848, 848, 800, 804, 853,
- 854, 855, 849, 800, 850, 800, 856, 804, 851, 800,
- 800, 852, 800, 804, 800, 800, 800, 800, 802, 800,
- 804, 804, 804, 848, 848, 804, 853, 800, 854, 800,
- 855, 800, 856, 800, 800, 857, 858, 802, 800, 859,
- 800, 860, 848, 848, 804, 857, 800, 858, 800, 802,
- 800, 859, 800, 800, 860, 800, 848, 848, 804, 800,
- 800, 848, 848, 861, 800, 800, 861, 800, 800, 800,
- 800, 862, 800, 862, 800, 800, 800, 800, 800, 0,
-
- 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
- 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
- 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
- 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
- 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
- 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
- 800, 800
- } ;
-
-static yyconst flex_int16_t yy_nxt[1293] =
- { 0,
- 6, 7, 8, 7, 9, 10, 6, 6, 11, 12,
- 6, 6, 6, 6, 13, 6, 6, 14, 13, 15,
- 13, 16, 17, 13, 18, 19, 13, 13, 20, 21,
- 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 13, 32, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 33, 13, 13, 13,
- 13, 13, 13, 13, 13, 34, 13, 13, 13, 35,
- 138, 71, 76, 77, 78, 80, 139, 89, 81, 113,
- 86, 90, 79, 36, 37, 101, 669, 104, 87, 143,
- 102, 38, 39, 72, 88, 110, 134, 144, 161, 82,
-
- 135, 162, 40, 41, 42, 8, 43, 44, 41, 41,
- 41, 45, 41, 41, 46, 41, 47, 48, 41, 41,
- 49, 49, 49, 50, 51, 49, 49, 49, 49, 49,
- 49, 49, 52, 49, 49, 53, 49, 49, 49, 49,
- 49, 49, 54, 49, 49, 49, 49, 55, 56, 57,
- 58, 59, 60, 49, 49, 49, 61, 49, 62, 63,
- 49, 64, 65, 66, 67, 68, 69, 70, 49, 49,
- 49, 49, 96, 86, 114, 97, 125, 126, 89, 141,
- 98, 87, 90, 130, 136, 148, 127, 111, 99, 150,
- 131, 153, 112, 142, 132, 128, 330, 133, 176, 331,
-
- 154, 149, 137, 115, 167, 151, 152, 173, 177, 236,
- 182, 168, 188, 174, 183, 354, 184, 172, 185, 189,
- 254, 206, 199, 200, 211, 440, 244, 237, 250, 190,
- 201, 202, 212, 228, 213, 378, 522, 229, 248, 711,
- 245, 203, 246, 255, 249, 251, 257, 258, 355, 428,
- 342, 379, 457, 712, 259, 260, 343, 713, 718, 441,
- 677, 719, 720, 458, 429, 261, 318, 318, 319, 318,
- 318, 318, 318, 318, 318, 318, 318, 318, 318, 318,
- 523, 318, 318, 318, 318, 319, 318, 318, 318, 318,
- 318, 318, 318, 318, 318, 318, 318, 721, 318, 318,
-
- 461, 461, 514, 461, 461, 461, 461, 461, 461, 461,
- 461, 461, 461, 461, 469, 463, 461, 486, 470, 556,
- 619, 487, 685, 637, 556, 556, 681, 619, 619, 637,
- 488, 637, 557, 620, 681, 515, 638, 557, 557, 682,
- 620, 620, 638, 681, 638, 687, 722, 682, 724, 726,
- 727, 693, 728, 730, 731, 733, 682, 734, 735, 736,
- 737, 471, 535, 535, 738, 535, 535, 535, 535, 535,
- 535, 535, 535, 535, 535, 535, 739, 537, 535, 461,
- 461, 740, 461, 461, 461, 461, 461, 461, 461, 461,
- 461, 461, 461, 741, 554, 461, 535, 535, 715, 535,
-
- 535, 535, 535, 535, 535, 535, 535, 535, 535, 535,
- 742, 617, 535, 743, 715, 715, 715, 716, 746, 748,
- 750, 752, 724, 726, 754, 717, 755, 730, 756, 733,
- 757, 758, 759, 760, 761, 762, 715, 715, 765, 748,
- 750, 752, 754, 767, 769, 770, 771, 773, 774, 776,
- 715, 715, 779, 767, 769, 780, 773, 781, 776, 715,
- 715, 784, 745, 785, 786, 715, 715, 788, 789, 790,
- 788, 791, 792, 793, 795, 796, 795, 797, 744, 798,
- 799, 75, 763, 119, 710, 709, 708, 707, 706, 705,
- 704, 703, 702, 701, 700, 699, 647, 778, 764, 698,
-
- 697, 696, 695, 694, 640, 777, 693, 691, 690, 689,
- 630, 688, 687, 685, 625, 623, 683, 616, 679, 783,
- 782, 73, 73, 73, 73, 117, 117, 320, 320, 320,
- 320, 404, 404, 404, 404, 406, 406, 406, 406, 408,
- 408, 408, 408, 410, 410, 410, 410, 417, 417, 417,
- 417, 419, 419, 419, 419, 421, 421, 421, 421, 318,
- 318, 318, 318, 423, 423, 423, 423, 438, 438, 438,
- 438, 459, 459, 459, 459, 462, 678, 462, 462, 467,
- 467, 467, 467, 529, 529, 529, 529, 533, 533, 533,
- 533, 536, 677, 536, 536, 540, 540, 540, 540, 547,
-
- 547, 547, 547, 461, 675, 461, 461, 555, 555, 555,
- 555, 562, 562, 562, 562, 592, 592, 592, 592, 594,
- 594, 594, 594, 596, 596, 596, 596, 600, 600, 600,
- 600, 604, 604, 604, 604, 607, 607, 607, 607, 615,
- 615, 615, 615, 535, 674, 535, 535, 618, 618, 618,
- 618, 622, 622, 622, 622, 624, 624, 624, 624, 629,
- 629, 629, 629, 636, 636, 636, 636, 639, 639, 639,
- 639, 646, 646, 646, 646, 668, 668, 668, 668, 676,
- 676, 676, 676, 680, 680, 680, 680, 684, 684, 684,
- 684, 686, 686, 686, 686, 692, 692, 692, 692, 714,
-
- 714, 714, 714, 723, 723, 723, 723, 725, 725, 725,
- 725, 729, 729, 729, 729, 732, 732, 732, 732, 747,
- 747, 747, 747, 749, 749, 749, 749, 751, 751, 751,
- 751, 753, 753, 753, 753, 766, 766, 766, 766, 768,
- 768, 768, 768, 772, 772, 772, 772, 775, 775, 775,
- 775, 787, 787, 787, 787, 794, 794, 794, 794, 673,
- 608, 605, 672, 671, 601, 670, 597, 595, 593, 669,
- 667, 666, 665, 664, 663, 662, 661, 660, 659, 658,
- 657, 656, 655, 654, 653, 652, 651, 650, 649, 648,
- 647, 645, 644, 563, 643, 642, 641, 640, 635, 634,
-
- 633, 632, 631, 548, 630, 628, 627, 626, 625, 541,
- 623, 621, 617, 534, 616, 614, 530, 613, 612, 611,
- 610, 609, 608, 606, 605, 603, 602, 601, 599, 598,
- 597, 595, 593, 591, 590, 589, 588, 587, 586, 585,
- 584, 583, 582, 581, 580, 579, 578, 577, 576, 575,
- 574, 573, 572, 571, 570, 569, 568, 567, 566, 565,
- 564, 563, 561, 468, 560, 559, 558, 554, 460, 553,
- 552, 551, 550, 549, 548, 546, 545, 544, 543, 542,
- 541, 539, 538, 534, 532, 531, 530, 439, 528, 527,
- 526, 525, 524, 521, 520, 519, 518, 517, 516, 424,
-
- 422, 420, 418, 513, 512, 511, 510, 509, 411, 409,
- 407, 405, 508, 507, 506, 505, 504, 503, 502, 501,
- 500, 499, 498, 497, 496, 495, 494, 493, 492, 491,
- 490, 489, 485, 484, 483, 482, 481, 480, 479, 478,
- 477, 476, 475, 474, 473, 472, 468, 466, 465, 464,
- 460, 456, 455, 454, 453, 452, 451, 450, 449, 448,
- 447, 446, 445, 444, 443, 442, 439, 437, 436, 435,
- 434, 433, 432, 431, 430, 427, 426, 425, 424, 319,
- 422, 420, 418, 416, 415, 414, 413, 412, 411, 409,
- 407, 405, 403, 402, 401, 400, 399, 398, 397, 396,
-
- 395, 394, 393, 392, 391, 390, 389, 388, 387, 386,
- 385, 384, 383, 382, 381, 380, 377, 376, 375, 374,
- 373, 372, 371, 370, 369, 368, 367, 366, 365, 364,
- 363, 362, 361, 360, 359, 358, 357, 356, 353, 352,
- 351, 350, 349, 348, 347, 346, 345, 344, 341, 340,
- 339, 338, 337, 336, 335, 334, 333, 332, 329, 328,
- 327, 326, 325, 324, 323, 322, 321, 317, 316, 315,
- 314, 313, 312, 311, 310, 309, 308, 307, 306, 305,
- 304, 303, 302, 301, 300, 299, 298, 297, 296, 295,
- 294, 293, 292, 291, 290, 289, 288, 287, 286, 285,
-
- 284, 283, 282, 281, 280, 279, 278, 277, 276, 275,
- 274, 273, 272, 271, 270, 269, 268, 267, 266, 265,
- 264, 263, 262, 256, 253, 252, 247, 243, 242, 241,
- 240, 239, 238, 235, 234, 233, 232, 231, 230, 227,
- 226, 225, 224, 223, 222, 221, 220, 219, 218, 217,
- 216, 215, 214, 118, 210, 209, 208, 207, 205, 204,
- 198, 197, 196, 195, 194, 193, 192, 191, 187, 186,
- 181, 180, 179, 178, 175, 172, 171, 170, 169, 166,
- 165, 164, 163, 160, 159, 158, 74, 157, 156, 155,
- 147, 146, 145, 140, 129, 124, 123, 122, 121, 120,
-
- 118, 116, 74, 109, 108, 107, 106, 105, 104, 103,
- 100, 95, 94, 93, 92, 91, 85, 84, 83, 82,
- 74, 800, 5, 800, 800, 800, 800, 800, 800, 800,
- 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
- 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
- 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
- 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
- 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
- 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
- 800, 800
-
- } ;
-
-static yyconst flex_int16_t yy_chk[1293] =
- { 0,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
- 60, 4, 14, 14, 14, 15, 60, 21, 15, 40,
- 20, 21, 14, 2, 2, 29, 668, 40, 20, 63,
- 29, 2, 2, 4, 20, 37, 58, 63, 79, 37,
-
- 58, 79, 2, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 27, 38, 43, 27, 55, 55, 39, 62,
- 27, 38, 39, 57, 59, 67, 55, 38, 27, 68,
- 57, 69, 39, 62, 57, 55, 227, 57, 91, 227,
-
- 69, 67, 59, 43, 84, 68, 68, 89, 91, 141,
- 96, 84, 99, 89, 96, 249, 96, 111, 96, 99,
- 154, 111, 108, 108, 116, 335, 148, 141, 151, 99,
- 108, 108, 116, 134, 116, 272, 432, 134, 150, 671,
- 148, 108, 148, 154, 150, 151, 156, 156, 249, 325,
- 238, 272, 351, 672, 156, 156, 238, 673, 675, 335,
- 676, 678, 679, 351, 325, 156, 217, 217, 217, 217,
- 217, 217, 217, 217, 217, 217, 217, 217, 217, 217,
- 432, 217, 217, 320, 320, 320, 320, 320, 320, 320,
- 320, 320, 320, 320, 320, 320, 320, 683, 320, 320,
-
- 353, 353, 425, 353, 353, 353, 353, 353, 353, 353,
- 353, 353, 353, 353, 359, 353, 353, 379, 359, 463,
- 537, 379, 684, 554, 555, 557, 617, 618, 620, 636,
- 379, 638, 463, 537, 680, 425, 554, 555, 557, 617,
- 618, 620, 636, 682, 638, 686, 688, 680, 689, 690,
- 691, 692, 694, 695, 696, 697, 682, 698, 700, 701,
- 702, 359, 444, 444, 703, 444, 444, 444, 444, 444,
- 444, 444, 444, 444, 444, 444, 704, 444, 444, 462,
- 462, 710, 462, 462, 462, 462, 462, 462, 462, 462,
- 462, 462, 462, 711, 462, 462, 536, 536, 674, 536,
-
- 536, 536, 536, 536, 536, 536, 536, 536, 536, 536,
- 712, 536, 536, 713, 714, 716, 717, 674, 719, 720,
- 721, 722, 723, 725, 727, 674, 728, 729, 731, 732,
- 734, 739, 740, 741, 742, 743, 744, 745, 746, 747,
- 749, 751, 753, 756, 757, 758, 759, 760, 761, 762,
- 763, 764, 765, 766, 768, 771, 772, 774, 775, 777,
- 778, 779, 717, 780, 781, 782, 783, 784, 785, 786,
- 787, 789, 790, 791, 792, 793, 794, 796, 716, 797,
- 798, 802, 744, 804, 666, 664, 663, 661, 660, 658,
- 657, 652, 651, 650, 649, 648, 646, 764, 745, 645,
-
- 644, 643, 642, 641, 639, 763, 635, 634, 633, 632,
- 629, 628, 627, 626, 624, 622, 621, 615, 614, 778,
- 777, 801, 801, 801, 801, 803, 803, 805, 805, 805,
- 805, 806, 806, 806, 806, 807, 807, 807, 807, 808,
- 808, 808, 808, 809, 809, 809, 809, 810, 810, 810,
- 810, 811, 811, 811, 811, 812, 812, 812, 812, 813,
- 813, 813, 813, 814, 814, 814, 814, 815, 815, 815,
- 815, 816, 816, 816, 816, 817, 613, 817, 817, 818,
- 818, 818, 818, 819, 819, 819, 819, 820, 820, 820,
- 820, 821, 612, 821, 821, 822, 822, 822, 822, 823,
-
- 823, 823, 823, 824, 611, 824, 824, 825, 825, 825,
- 825, 826, 826, 826, 826, 827, 827, 827, 827, 828,
- 828, 828, 828, 829, 829, 829, 829, 830, 830, 830,
- 830, 831, 831, 831, 831, 832, 832, 832, 832, 833,
- 833, 833, 833, 834, 610, 834, 834, 835, 835, 835,
- 835, 836, 836, 836, 836, 837, 837, 837, 837, 838,
- 838, 838, 838, 839, 839, 839, 839, 840, 840, 840,
- 840, 841, 841, 841, 841, 842, 842, 842, 842, 843,
- 843, 843, 843, 844, 844, 844, 844, 845, 845, 845,
- 845, 846, 846, 846, 846, 847, 847, 847, 847, 848,
-
- 848, 848, 848, 849, 849, 849, 849, 850, 850, 850,
- 850, 851, 851, 851, 851, 852, 852, 852, 852, 853,
- 853, 853, 853, 854, 854, 854, 854, 855, 855, 855,
- 855, 856, 856, 856, 856, 857, 857, 857, 857, 858,
- 858, 858, 858, 859, 859, 859, 859, 860, 860, 860,
- 860, 861, 861, 861, 861, 862, 862, 862, 862, 609,
- 607, 604, 603, 602, 600, 598, 596, 594, 592, 591,
- 590, 589, 587, 585, 584, 583, 582, 581, 580, 579,
- 578, 577, 576, 575, 574, 572, 571, 569, 568, 567,
- 566, 565, 564, 562, 561, 560, 559, 558, 553, 552,
-
- 551, 550, 549, 547, 546, 545, 544, 543, 542, 540,
- 539, 538, 535, 533, 532, 531, 529, 528, 527, 526,
- 525, 523, 522, 521, 520, 519, 518, 517, 516, 515,
- 514, 513, 512, 511, 510, 509, 503, 501, 500, 499,
- 498, 497, 495, 494, 491, 489, 488, 487, 486, 485,
- 482, 480, 479, 478, 477, 476, 475, 474, 473, 472,
- 471, 470, 469, 467, 466, 465, 464, 461, 459, 458,
- 457, 456, 455, 454, 453, 452, 451, 450, 449, 448,
- 447, 446, 445, 443, 442, 441, 440, 438, 437, 436,
- 435, 434, 433, 431, 430, 429, 428, 427, 426, 423,
-
- 421, 419, 417, 416, 415, 414, 413, 412, 410, 408,
- 406, 404, 403, 402, 401, 400, 399, 398, 397, 396,
- 395, 394, 392, 391, 390, 389, 388, 387, 386, 385,
- 383, 380, 378, 377, 376, 374, 370, 369, 367, 366,
- 365, 364, 363, 362, 361, 360, 358, 357, 356, 355,
- 352, 350, 349, 348, 347, 346, 345, 344, 343, 342,
- 341, 340, 339, 338, 337, 336, 334, 333, 332, 331,
- 330, 329, 328, 327, 326, 324, 323, 322, 321, 318,
- 317, 316, 315, 314, 313, 312, 311, 310, 309, 308,
- 306, 305, 304, 303, 302, 301, 300, 299, 297, 296,
-
- 294, 292, 291, 290, 289, 288, 287, 286, 285, 284,
- 279, 278, 276, 275, 274, 273, 271, 270, 269, 268,
- 267, 266, 265, 264, 263, 262, 261, 260, 259, 258,
- 257, 256, 255, 254, 253, 252, 251, 250, 248, 247,
- 246, 245, 244, 243, 242, 241, 240, 239, 237, 236,
- 235, 234, 233, 232, 231, 230, 229, 228, 226, 225,
- 224, 223, 222, 221, 220, 219, 218, 216, 215, 214,
- 213, 212, 211, 210, 209, 208, 207, 206, 205, 204,
- 203, 202, 201, 200, 199, 198, 197, 195, 194, 193,
- 192, 191, 190, 189, 188, 186, 184, 183, 182, 181,
-
- 180, 179, 178, 177, 176, 175, 174, 173, 172, 171,
- 170, 169, 168, 167, 166, 165, 164, 163, 161, 160,
- 159, 158, 157, 155, 153, 152, 149, 147, 146, 145,
- 144, 143, 142, 140, 139, 138, 137, 136, 135, 133,
- 132, 131, 130, 129, 128, 127, 126, 125, 124, 123,
- 122, 121, 120, 118, 115, 114, 113, 112, 110, 109,
- 107, 106, 105, 104, 103, 102, 101, 100, 98, 97,
- 95, 94, 93, 92, 90, 88, 87, 86, 85, 83,
- 82, 81, 80, 78, 77, 76, 73, 72, 71, 70,
- 66, 65, 64, 61, 56, 54, 53, 52, 51, 50,
-
- 48, 46, 44, 36, 35, 34, 33, 32, 31, 30,
- 28, 26, 25, 24, 23, 22, 19, 18, 17, 16,
- 9, 5, 800, 800, 800, 800, 800, 800, 800, 800,
- 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
- 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
- 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
- 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
- 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
- 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
- 800, 800
-
- } ;
-
-/* Table of booleans, true if rule could match eol. */
-static yyconst flex_int32_t yy_rule_can_match_eol[140] =
- { 0,
-0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
- };
-
-extern int yy_flex_debug;
-int yy_flex_debug = 0;
-
-static yy_state_type *yy_state_buf=0, *yy_state_ptr=0;
-static char *yy_full_match;
-static int yy_lp;
-static int yy_looking_for_trail_begin = 0;
-static int yy_full_lp;
-static int *yy_full_state;
-#define YY_TRAILING_MASK 0x2000
-#define YY_TRAILING_HEAD_MASK 0x4000
-#define REJECT \
-{ \
-*yy_cp = (yy_hold_char); /* undo effects of setting up yytext */ \
-yy_cp = (yy_full_match); /* restore poss. backed-over text */ \
-(yy_lp) = (yy_full_lp); /* restore orig. accepting pos. */ \
-(yy_state_ptr) = (yy_full_state); /* restore orig. state */ \
-yy_current_state = *(yy_state_ptr); /* restore curr. state */ \
-++(yy_lp); \
-goto find_rule; \
-}
-
-static int yy_more_offset = 0;
-static int yy_prev_more_offset = 0;
-#define yymore() ((yy_more_offset) = yy_flex_strlen( yytext ))
-#define YY_NEED_STRLEN
-#define YY_MORE_ADJ 0
-#define YY_RESTORE_YY_MORE_OFFSET \
- { \
- (yy_more_offset) = (yy_prev_more_offset); \
- yyleng -= (yy_more_offset); \
- }
-#ifndef YYLMAX
-#define YYLMAX 8192
-#endif
-
-char yytext[YYLMAX];
-char *yytext_ptr;
-#line 1 "menul.l"
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #11 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-#line 17 "menul.l"
-#if defined(linux) || defined(mips) || defined(hpux) || defined(_AIX)
-int yylineno;
-#define NEWLINE yylineno++
-#else
-#define NEWLINE
-#endif
-
-#undef ECHO
-/* #define ECHO printf("<%s>",yytext) */
-#define ECHO /**/
-
-/*
-on HP lex -Xa10000
-p4 edit src/menul.c src/menuy.c && cd src && lex -t menul.l > menul.c && yacc menuy.y && mv -f y.tab.c menuy.c && cd ../ && make menu && make prof # ./env.sh cc
-
-ecflow_client | xargs addr2line -e ecflow_client -f
-*/
-
-#if defined (linux) || defined(alpha) || defined(SVR4) || defined(SGI) || defined(_AIX)
-#define yyinput input
-#endif
-
-
-
-#line 1211 "<stdout>"
-
-#define INITIAL 0
-#define LOGFILE 1
-
-#ifndef YY_NO_UNISTD_H
-/* Special case for "unistd.h", since it is non-ANSI. We include it way
- * down here because we want the user's section 1 to have been scanned first.
- * The user has a chance to override it with an option.
- */
-#include <unistd.h>
-#endif
-
-#ifndef YY_EXTRA_TYPE
-#define YY_EXTRA_TYPE void *
-#endif
-
-static int yy_init_globals (void );
-
-/* Accessor methods to globals.
- These are made visible to non-reentrant scanners for convenience. */
-
-int yylex_destroy (void );
-
-int yyget_debug (void );
-
-void yyset_debug (int debug_flag );
-
-YY_EXTRA_TYPE yyget_extra (void );
-
-void yyset_extra (YY_EXTRA_TYPE user_defined );
-
-FILE *yyget_in (void );
-
-void yyset_in (FILE * in_str );
-
-FILE *yyget_out (void );
-
-void yyset_out (FILE * out_str );
-
-int yyget_leng (void );
-
-char *yyget_text (void );
-
-int yyget_lineno (void );
-
-void yyset_lineno (int line_number );
-
-/* Macros after this point can all be overridden by user definitions in
- * section 1.
- */
-
-#ifndef YY_SKIP_YYWRAP
-#ifdef __cplusplus
-extern "C" int yywrap (void );
-#else
-extern int yywrap (void );
-#endif
-#endif
-
- static void yyunput (int c,char *buf_ptr );
-
-#ifndef yytext_ptr
-static void yy_flex_strncpy (char *,yyconst char *,int );
-#endif
-
-#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (yyconst char * );
-#endif
-
-#ifndef YY_NO_INPUT
-
-#ifdef __cplusplus
-static int yyinput (void );
-#else
-static int input (void );
-#endif
-
-#endif
-
-/* Amount of stuff to slurp up with each read. */
-#ifndef YY_READ_BUF_SIZE
-#define YY_READ_BUF_SIZE 8192
-#endif
-
-/* Copy whatever the last rule matched to the standard output. */
-#ifndef ECHO
-/* This used to be an fputs(), but since the string might contain NUL's,
- * we now use fwrite().
- */
-#define ECHO fwrite( yytext, yyleng, 1, yyout )
-#endif
-
-/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
- * is returned in "result".
- */
-#ifndef YY_INPUT
-#define YY_INPUT(buf,result,max_size) \
- if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
- { \
- int c = '*'; \
- int n; \
- for ( n = 0; n < max_size && \
- (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
- buf[n] = (char) c; \
- if ( c == '\n' ) \
- buf[n++] = (char) c; \
- if ( c == EOF && ferror( yyin ) ) \
- YY_FATAL_ERROR( "input in flex scanner failed" ); \
- result = n; \
- } \
- else \
- { \
- errno=0; \
- while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
- { \
- if( errno != EINTR) \
- { \
- YY_FATAL_ERROR( "input in flex scanner failed" ); \
- break; \
- } \
- errno=0; \
- clearerr(yyin); \
- } \
- }\
-\
-
-#endif
-
-/* No semi-colon after return; correct usage is to write "yyterminate();" -
- * we don't want an extra ';' after the "return" because that will cause
- * some compilers to complain about unreachable statements.
- */
-#ifndef yyterminate
-#define yyterminate() return YY_NULL
-#endif
-
-/* Number of entries by which start-condition stack grows. */
-#ifndef YY_START_STACK_INCR
-#define YY_START_STACK_INCR 25
-#endif
-
-/* Report a fatal error. */
-#ifndef YY_FATAL_ERROR
-#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
-#endif
-
-/* end tables serialization structures and prototypes */
-
-/* Default declaration of generated scanner - a define so the user can
- * easily add parameters.
- */
-#ifndef YY_DECL
-#define YY_DECL_IS_OURS 1
-
-extern int yylex (void);
-
-#define YY_DECL int yylex (void)
-#endif /* !YY_DECL */
-
-/* Code executed at the beginning of each rule, after yytext and yyleng
- * have been set up.
- */
-#ifndef YY_USER_ACTION
-#define YY_USER_ACTION
-#endif
-
-/* Code executed at the end of each rule. */
-#ifndef YY_BREAK
-#define YY_BREAK break;
-#endif
-
-#define YY_RULE_SETUP \
- if ( yyleng > 0 ) \
- YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \
- (yytext[yyleng - 1] == '\n'); \
- YY_USER_ACTION
-
-/** The main scanner function which does all the work.
- */
-YY_DECL
-{
- register yy_state_type yy_current_state;
- register char *yy_cp, *yy_bp;
- register int yy_act;
-
-#line 56 "menul.l"
-
-
-#line 1400 "<stdout>"
-
- if ( !(yy_init) )
- {
- (yy_init) = 1;
-
-#ifdef YY_USER_INIT
- YY_USER_INIT;
-#endif
-
- /* Create the reject buffer large enough to save one state per allowed character. */
- if ( ! (yy_state_buf) )
- (yy_state_buf) = (yy_state_type *)yyalloc(YY_STATE_BUF_SIZE );
- if ( ! (yy_state_buf) )
- YY_FATAL_ERROR( "out of dynamic memory in yylex()" );
-
- if ( ! (yy_start) )
- (yy_start) = 1; /* first start state */
-
- if ( ! yyin )
- yyin = stdin;
-
- if ( ! yyout )
- yyout = stdout;
-
- if ( ! YY_CURRENT_BUFFER ) {
- yyensure_buffer_stack ();
- YY_CURRENT_BUFFER_LVALUE =
- yy_create_buffer(yyin,YY_BUF_SIZE );
- }
-
- yy_load_buffer_state( );
- }
-
- while ( 1 ) /* loops until end-of-file is reached */
- {
- yy_cp = (yy_c_buf_p);
-
- /* Support of yytext. */
- *yy_cp = (yy_hold_char);
-
- /* yy_bp points to the position in yy_ch_buf of the start of
- * the current run.
- */
- yy_bp = yy_cp;
-
- yy_current_state = (yy_start);
- yy_current_state += YY_AT_BOL();
-
- (yy_state_ptr) = (yy_state_buf);
- *(yy_state_ptr)++ = yy_current_state;
-
-yy_match:
- do
- {
- register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
- while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
- {
- yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 801 )
- yy_c = yy_meta[(unsigned int) yy_c];
- }
- yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
- *(yy_state_ptr)++ = yy_current_state;
- ++yy_cp;
- }
- while ( yy_base[yy_current_state] != 1223 );
-
-yy_find_action:
- yy_current_state = *--(yy_state_ptr);
- (yy_lp) = yy_accept[yy_current_state];
-find_rule: /* we branch to this label when backing up */
- for ( ; ; ) /* until we find what rule we matched */
- {
- if ( (yy_lp) && (yy_lp) < yy_accept[yy_current_state + 1] )
- {
- yy_act = yy_acclist[(yy_lp)];
- if ( yy_act & YY_TRAILING_HEAD_MASK ||
- (yy_looking_for_trail_begin) )
- {
- if ( yy_act == (yy_looking_for_trail_begin) )
- {
- (yy_looking_for_trail_begin) = 0;
- yy_act &= ~YY_TRAILING_HEAD_MASK;
- break;
- }
- }
- else if ( yy_act & YY_TRAILING_MASK )
- {
- (yy_looking_for_trail_begin) = yy_act & ~YY_TRAILING_MASK;
- (yy_looking_for_trail_begin) |= YY_TRAILING_HEAD_MASK;
- (yy_full_match) = yy_cp;
- (yy_full_state) = (yy_state_ptr);
- (yy_full_lp) = (yy_lp);
- }
- else
- {
- (yy_full_match) = yy_cp;
- (yy_full_state) = (yy_state_ptr);
- (yy_full_lp) = (yy_lp);
- break;
- }
- ++(yy_lp);
- goto find_rule;
- }
- --yy_cp;
- yy_current_state = *--(yy_state_ptr);
- (yy_lp) = yy_accept[yy_current_state];
- }
-
- YY_DO_BEFORE_ACTION;
-
- if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] )
- {
- int yyl;
- for ( yyl = (yy_prev_more_offset); yyl < yyleng; ++yyl )
- if ( yytext[yyl] == '\n' )
-
- yylineno++;
-;
- }
-
-do_action: /* This label is used only to access EOF actions. */
-
- switch ( yy_act )
- { /* beginning of action switch */
-case 1:
-YY_RULE_SETUP
-#line 58 "menul.l"
-;
- YY_BREAK
-case 2:
-YY_RULE_SETUP
-#line 60 "menul.l"
-return VERSION;
- YY_BREAK
-case 3:
-YY_RULE_SETUP
-#line 61 "menul.l"
-return MENU;
- YY_BREAK
-case 4:
-YY_RULE_SETUP
-#line 62 "menul.l"
-return MENU;
- YY_BREAK
-case 5:
-YY_RULE_SETUP
-#line 63 "menul.l"
-return NONE;
- YY_BREAK
-case 6:
-YY_RULE_SETUP
-#line 64 "menul.l"
-return ALL;
- YY_BREAK
-case 7:
-YY_RULE_SETUP
-#line 65 "menul.l"
-return UNKNOWN;
- YY_BREAK
-case 8:
-YY_RULE_SETUP
-#line 66 "menul.l"
-return SUSPENDED;
- YY_BREAK
-case 9:
-YY_RULE_SETUP
-#line 67 "menul.l"
-return COMPLETE;
- YY_BREAK
-case 10:
-YY_RULE_SETUP
-#line 68 "menul.l"
-return QUEUED;
- YY_BREAK
-case 11:
-YY_RULE_SETUP
-#line 69 "menul.l"
-return SUBMITTED;
- YY_BREAK
-case 12:
-YY_RULE_SETUP
-#line 70 "menul.l"
-return ACTIVE;
- YY_BREAK
-case 13:
-YY_RULE_SETUP
-#line 71 "menul.l"
-return ABORTED;
- YY_BREAK
-case 14:
-YY_RULE_SETUP
-#line 72 "menul.l"
-return CLEAR;
- YY_BREAK
-case 15:
-YY_RULE_SETUP
-#line 73 "menul.l"
-return SET;
- YY_BREAK
-case 16:
-YY_RULE_SETUP
-#line 74 "menul.l"
-return SHUTDOWN;
- YY_BREAK
-case 17:
-YY_RULE_SETUP
-#line 75 "menul.l"
-return HALTED;
- YY_BREAK
-case 18:
-YY_RULE_SETUP
-#line 76 "menul.l"
-return LOCKED;
- YY_BREAK
-case 19:
-YY_RULE_SETUP
-#line 77 "menul.l"
-return SERVER;
- YY_BREAK
-case 20:
-YY_RULE_SETUP
-#line 78 "menul.l"
-return SMS;
- YY_BREAK
-case 21:
-YY_RULE_SETUP
-#line 79 "menul.l"
-return NODE;
- YY_BREAK
-case 22:
-YY_RULE_SETUP
-#line 80 "menul.l"
-return SUITE;
- YY_BREAK
-case 23:
-YY_RULE_SETUP
-#line 81 "menul.l"
-return FAMILY;
- YY_BREAK
-case 24:
-YY_RULE_SETUP
-#line 82 "menul.l"
-return TASK;
- YY_BREAK
-case 25:
-YY_RULE_SETUP
-#line 83 "menul.l"
-return EVENT;
- YY_BREAK
-case 26:
-YY_RULE_SETUP
-#line 84 "menul.l"
-return LIMIT;
- YY_BREAK
-case 27:
-YY_RULE_SETUP
-#line 85 "menul.l"
-return LABEL;
- YY_BREAK
-case 28:
-YY_RULE_SETUP
-#line 86 "menul.l"
-return METER;
- YY_BREAK
-case 29:
-YY_RULE_SETUP
-#line 87 "menul.l"
-return VARIABLE;
- YY_BREAK
-case 30:
-YY_RULE_SETUP
-#line 88 "menul.l"
-return REPEAT;
- YY_BREAK
-case 31:
-YY_RULE_SETUP
-#line 89 "menul.l"
-return ALIAS;
- YY_BREAK
-case 32:
-YY_RULE_SETUP
-#line 90 "menul.l"
-return MIGRATED;
- YY_BREAK
-case 33:
-YY_RULE_SETUP
-#line 91 "menul.l"
-return HAS_TRIGGERS;
- YY_BREAK
-case 34:
-YY_RULE_SETUP
-#line 92 "menul.l"
-return HAS_TIME;
- YY_BREAK
-case 35:
-YY_RULE_SETUP
-#line 93 "menul.l"
-return HAS_DATE;
- YY_BREAK
-case 36:
-YY_RULE_SETUP
-#line 94 "menul.l"
-return HAS_TEXT;
- YY_BREAK
-case 37:
-YY_RULE_SETUP
-#line 95 "menul.l"
-return IS_ZOMBIE;
- YY_BREAK
-case 38:
-YY_RULE_SETUP
-#line 96 "menul.l"
-return SEPARATOR;
- YY_BREAK
-case 39:
-YY_RULE_SETUP
-#line 97 "menul.l"
-return DEFAULT_YES;
- YY_BREAK
-case 40:
-YY_RULE_SETUP
-#line 98 "menul.l"
-return DEFAULT_NO;
- YY_BREAK
-case 41:
-YY_RULE_SETUP
-#line 99 "menul.l"
-return WINDOW;
- YY_BREAK
-case 42:
-YY_RULE_SETUP
-#line 100 "menul.l"
-return PLUG;
- YY_BREAK
-case 43:
-YY_RULE_SETUP
-#line 101 "menul.l"
-return COMP;
- YY_BREAK
-case 44:
-YY_RULE_SETUP
-#line 102 "menul.l"
-return SELECTION;
- YY_BREAK
-case 45:
-YY_RULE_SETUP
-#line 104 "menul.l"
-return USER;
- YY_BREAK
-case 46:
-YY_RULE_SETUP
-#line 105 "menul.l"
-return OPER;
- YY_BREAK
-case 47:
-YY_RULE_SETUP
-#line 106 "menul.l"
-return ADMIN;
- YY_BREAK
-case 48:
-YY_RULE_SETUP
-#line 108 "menul.l"
-{ BEGIN LOGFILE; }
- YY_BREAK
-case 49:
-YY_RULE_SETUP
-#line 109 "menul.l"
-{ return JUNK; }
- YY_BREAK
-case 50:
-YY_RULE_SETUP
-#line 110 "menul.l"
-{ return JUNK; }
- YY_BREAK
-case 51:
-YY_RULE_SETUP
-#line 111 "menul.l"
-{ return JUNK; }
- YY_BREAK
-case 52:
-YY_RULE_SETUP
-#line 112 "menul.l"
-{ return JUNK; }
- YY_BREAK
-case 53:
-YY_RULE_SETUP
-#line 113 "menul.l"
-{ ECHO; BEGIN LOGFILE; }
- YY_BREAK
-case 54:
-YY_RULE_SETUP
-#line 114 "menul.l"
-{ ECHO; BEGIN LOGFILE; }
- YY_BREAK
-case 55:
-YY_RULE_SETUP
-#line 115 "menul.l"
-{ ECHO; BEGIN LOGFILE; }
- YY_BREAK
-case 56:
-YY_RULE_SETUP
-#line 116 "menul.l"
-{ ECHO; BEGIN LOGFILE; }
- YY_BREAK
-case 57:
-YY_RULE_SETUP
-#line 117 "menul.l"
-{ ECHO; BEGIN LOGFILE; }
- YY_BREAK
-case 58:
-YY_RULE_SETUP
-#line 119 "menul.l"
-{ }
- YY_BREAK
-case 59:
-YY_RULE_SETUP
-#line 120 "menul.l"
-{ return JUNK; }
- YY_BREAK
-case 60:
-YY_RULE_SETUP
-#line 121 "menul.l"
-{ return JUNK; }
- YY_BREAK
-case 61:
-YY_RULE_SETUP
-#line 122 "menul.l"
-{ return JUNK; }
- YY_BREAK
-case 62:
-YY_RULE_SETUP
-#line 123 "menul.l"
-{ return JUNK; }
- YY_BREAK
-case 63:
-YY_RULE_SETUP
-#line 125 "menul.l"
-ECHO;
- YY_BREAK
-case 64:
-YY_RULE_SETUP
-#line 126 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 65:
-YY_RULE_SETUP
-#line 127 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 66:
-YY_RULE_SETUP
-#line 128 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 67:
-YY_RULE_SETUP
-#line 129 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 68:
-YY_RULE_SETUP
-#line 132 "menul.l"
-return IDENT;
- YY_BREAK
-case 69:
-YY_RULE_SETUP
-#line 134 "menul.l"
-{
- int c,q = yytext[0];
- yyleng = 0;
- while((c = yyinput()) && c != q && c != '\n')
- if(c == '\\') {
- yytext[yyleng++] = c;
- yytext[yyleng++] = yyinput();
- } else
- yytext[yyleng++] = c;
- yytext[yyleng++] = 0;
- return STRING;
- }
- YY_BREAK
-case 70:
-YY_RULE_SETUP
-#line 147 "menul.l"
-{
- int c,q = yytext[0];
- yyleng = 0;
- while((c = yyinput()) && c != q && c != '\n')
- if(c == '\\') {
- yytext[yyleng++] = c;
- yytext[yyleng++] = yyinput();
- } else
- yytext[yyleng++] = c;
- yytext[yyleng++] = 0;
- return STRING;
- }
- YY_BREAK
-case 71:
-YY_RULE_SETUP
-#line 159 "menul.l"
-{ ECHO; return COMPLETE; }
- YY_BREAK
-case 72:
-YY_RULE_SETUP
-#line 160 "menul.l"
-{ ECHO; return QUEUED; }
- YY_BREAK
-case 73:
-YY_RULE_SETUP
-#line 161 "menul.l"
-{ ECHO; return ACTIVE; }
- YY_BREAK
-case 74:
-YY_RULE_SETUP
-#line 162 "menul.l"
-{ ECHO; return METER; }
- YY_BREAK
-case 75:
-YY_RULE_SETUP
-#line 163 "menul.l"
-{ ECHO; return EVENT; }
- YY_BREAK
-case 76:
-YY_RULE_SETUP
-#line 164 "menul.l"
-{ return UNKNOWN; }
- YY_BREAK
-case 77:
-YY_RULE_SETUP
-#line 165 "menul.l"
-{ ECHO; return SUBMITTED; }
- YY_BREAK
-case 78:
-YY_RULE_SETUP
-#line 166 "menul.l"
-{ ECHO; return ABORTED; }
- YY_BREAK
-case 79:
-YY_RULE_SETUP
-#line 167 "menul.l"
-{ ECHO; return SET; }
- YY_BREAK
-case 80:
-YY_RULE_SETUP
-#line 168 "menul.l"
-{ ECHO; return CLEAR; }
- YY_BREAK
-case 81:
-YY_RULE_SETUP
-#line 169 "menul.l"
-{ ECHO; return CANCEL; }
- YY_BREAK
-case 82:
-YY_RULE_SETUP
-#line 171 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 83:
-YY_RULE_SETUP
-#line 172 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 84:
-YY_RULE_SETUP
-#line 173 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 85:
-YY_RULE_SETUP
-#line 174 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 86:
-YY_RULE_SETUP
-#line 175 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 87:
-YY_RULE_SETUP
-#line 176 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 88:
-YY_RULE_SETUP
-#line 177 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 89:
-YY_RULE_SETUP
-#line 178 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 90:
-YY_RULE_SETUP
-#line 179 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 91:
-YY_RULE_SETUP
-#line 180 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 92:
-YY_RULE_SETUP
-#line 181 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 93:
-YY_RULE_SETUP
-#line 182 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 94:
-YY_RULE_SETUP
-#line 183 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 95:
-YY_RULE_SETUP
-#line 184 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 96:
-YY_RULE_SETUP
-#line 185 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 97:
-YY_RULE_SETUP
-#line 186 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 98:
-YY_RULE_SETUP
-#line 187 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 99:
-YY_RULE_SETUP
-#line 188 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 100:
-YY_RULE_SETUP
-#line 189 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 101:
-YY_RULE_SETUP
-#line 190 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 102:
-YY_RULE_SETUP
-#line 191 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 103:
-YY_RULE_SETUP
-#line 192 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 104:
-YY_RULE_SETUP
-#line 193 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 105:
-YY_RULE_SETUP
-#line 194 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 106:
-YY_RULE_SETUP
-#line 195 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 107:
-YY_RULE_SETUP
-#line 196 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 108:
-YY_RULE_SETUP
-#line 197 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 109:
-YY_RULE_SETUP
-#line 198 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 110:
-YY_RULE_SETUP
-#line 199 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 111:
-YY_RULE_SETUP
-#line 200 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 112:
-YY_RULE_SETUP
-#line 201 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 113:
-YY_RULE_SETUP
-#line 202 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 114:
-YY_RULE_SETUP
-#line 203 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 115:
-YY_RULE_SETUP
-#line 204 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 116:
-YY_RULE_SETUP
-#line 205 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 117:
-YY_RULE_SETUP
-#line 206 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 118:
-YY_RULE_SETUP
-#line 207 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 119:
-YY_RULE_SETUP
-#line 208 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 120:
-YY_RULE_SETUP
-#line 209 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 121:
-YY_RULE_SETUP
-#line 210 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 122:
-YY_RULE_SETUP
-#line 211 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 123:
-YY_RULE_SETUP
-#line 212 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 124:
-YY_RULE_SETUP
-#line 213 "menul.l"
-{ ECHO; return JUNK; }
- YY_BREAK
-case 125:
-YY_RULE_SETUP
-#line 215 "menul.l"
-;
- YY_BREAK
-case 126:
-YY_RULE_SETUP
-#line 216 "menul.l"
-;
- YY_BREAK
-case 127:
-YY_RULE_SETUP
-#line 217 "menul.l"
-{ return JUNK; }
- YY_BREAK
-case 128:
-YY_RULE_SETUP
-#line 218 "menul.l"
-{ return JUNK; }
- YY_BREAK
-case 129:
-YY_RULE_SETUP
-#line 220 "menul.l"
-{ ECHO; return NUMBER; }
- YY_BREAK
-case 130:
-YY_RULE_SETUP
-#line 221 "menul.l"
-{ ECHO; return IDENT;}
- YY_BREAK
-case 131:
-YY_RULE_SETUP
-#line 222 "menul.l"
-{ ECHO; return NODE_NAME;}
- YY_BREAK
-case 132:
-YY_RULE_SETUP
-#line 223 "menul.l"
-ECHO;
- YY_BREAK
-case 133:
-YY_RULE_SETUP
-#line 224 "menul.l"
-{ ECHO; return *yytext; }
- YY_BREAK
-case 134:
-YY_RULE_SETUP
-#line 225 "menul.l"
-;
- YY_BREAK
-case 135:
-YY_RULE_SETUP
-#line 226 "menul.l"
-return *yytext;
- YY_BREAK
-case 136:
-/* rule 136 can match eol */
-YY_RULE_SETUP
-#line 227 "menul.l"
-{ BEGIN INITIAL; NEWLINE; }
- YY_BREAK
-case 137:
-YY_RULE_SETUP
-#line 228 "menul.l"
-{ return ANY; }
- YY_BREAK
-case 138:
-YY_RULE_SETUP
-#line 230 "menul.l"
-
- YY_BREAK
-case 139:
-YY_RULE_SETUP
-#line 231 "menul.l"
-ECHO;
- YY_BREAK
-#line 2244 "<stdout>"
- case YY_STATE_EOF(INITIAL):
- case YY_STATE_EOF(LOGFILE):
- yyterminate();
-
- case YY_END_OF_BUFFER:
- {
- /* Amount of text matched not including the EOB char. */
- int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
-
- /* Undo the effects of YY_DO_BEFORE_ACTION. */
- *yy_cp = (yy_hold_char);
- YY_RESTORE_YY_MORE_OFFSET
-
- if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
- {
- /* We're scanning a new file or input source. It's
- * possible that this happened because the user
- * just pointed yyin at a new source and called
- * yylex(). If so, then we have to assure
- * consistency between YY_CURRENT_BUFFER and our
- * globals. Here is the right place to do so, because
- * this is the first action (other than possibly a
- * back-up) that will match for the new input source.
- */
- (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
- YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
- YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
- }
-
- /* Note that here we test for yy_c_buf_p "<=" to the position
- * of the first EOB in the buffer, since yy_c_buf_p will
- * already have been incremented past the NUL character
- * (since all states make transitions on EOB to the
- * end-of-buffer state). Contrast this with the test
- * in input().
- */
- if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
- { /* This was really a NUL. */
- yy_state_type yy_next_state;
-
- (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
-
- yy_current_state = yy_get_previous_state( );
-
- /* Okay, we're now positioned to make the NUL
- * transition. We couldn't have
- * yy_get_previous_state() go ahead and do it
- * for us because it doesn't know how to deal
- * with the possibility of jamming (and we don't
- * want to build jamming into it because then it
- * will run more slowly).
- */
-
- yy_next_state = yy_try_NUL_trans( yy_current_state );
-
- yy_bp = (yytext_ptr) + YY_MORE_ADJ;
-
- if ( yy_next_state )
- {
- /* Consume the NUL. */
- yy_cp = ++(yy_c_buf_p);
- yy_current_state = yy_next_state;
- goto yy_match;
- }
-
- else
- {
- yy_cp = (yy_c_buf_p);
- goto yy_find_action;
- }
- }
-
- else switch ( yy_get_next_buffer( ) )
- {
- case EOB_ACT_END_OF_FILE:
- {
- (yy_did_buffer_switch_on_eof) = 0;
-
- if ( yywrap( ) )
- {
- /* Note: because we've taken care in
- * yy_get_next_buffer() to have set up
- * yytext, we can now set up
- * yy_c_buf_p so that if some total
- * hoser (like flex itself) wants to
- * call the scanner after we return the
- * YY_NULL, it'll still work - another
- * YY_NULL will get returned.
- */
- (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
-
- yy_act = YY_STATE_EOF(YY_START);
- goto do_action;
- }
-
- else
- {
- if ( ! (yy_did_buffer_switch_on_eof) )
- YY_NEW_FILE;
- }
- break;
- }
-
- case EOB_ACT_CONTINUE_SCAN:
- (yy_c_buf_p) =
- (yytext_ptr) + yy_amount_of_matched_text;
-
- yy_current_state = yy_get_previous_state( );
-
- yy_cp = (yy_c_buf_p);
- yy_bp = (yytext_ptr) + YY_MORE_ADJ;
- goto yy_match;
-
- case EOB_ACT_LAST_MATCH:
- (yy_c_buf_p) =
- &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
-
- yy_current_state = yy_get_previous_state( );
-
- yy_cp = (yy_c_buf_p);
- yy_bp = (yytext_ptr) + YY_MORE_ADJ;
- goto yy_find_action;
- }
- break;
- }
-
- default:
- YY_FATAL_ERROR(
- "fatal flex scanner internal error--no action found" );
- } /* end of action switch */
- } /* end of scanning one token */
-} /* end of yylex */
-
-/* yy_get_next_buffer - try to read in a new buffer
- *
- * Returns a code representing an action:
- * EOB_ACT_LAST_MATCH -
- * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
- * EOB_ACT_END_OF_FILE - end of file
- */
-static int yy_get_next_buffer (void)
-{
- register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
- register char *source = (yytext_ptr);
- register int number_to_move, i;
- int ret_val;
-
- if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
- YY_FATAL_ERROR(
- "fatal flex scanner internal error--end of buffer missed" );
-
- if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
- { /* Don't try to fill the buffer, so this is an EOF. */
- if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
- {
- /* We matched a single character, the EOB, so
- * treat this as a final EOF.
- */
- return EOB_ACT_END_OF_FILE;
- }
-
- else
- {
- /* We matched some text prior to the EOB, first
- * process it.
- */
- return EOB_ACT_LAST_MATCH;
- }
- }
-
- /* Try to read more data. */
-
- /* First move last chars to start of buffer. */
- number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
-
- for ( i = 0; i < number_to_move; ++i )
- *(dest++) = *(source++);
-
- if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
- /* don't do the read, it's not guaranteed to return an EOF,
- * just force an EOF
- */
- YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
-
- else
- {
- int num_to_read =
- YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
-
- while ( num_to_read <= 0 )
- { /* Not enough room in the buffer - grow it. */
-
- YY_FATAL_ERROR(
-"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
-
- }
-
- if ( num_to_read > YY_READ_BUF_SIZE )
- num_to_read = YY_READ_BUF_SIZE;
-
- /* Read in more data. */
- YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
- (yy_n_chars), (size_t) num_to_read );
-
- YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
- }
-
- if ( (yy_n_chars) == 0 )
- {
- if ( number_to_move == YY_MORE_ADJ )
- {
- ret_val = EOB_ACT_END_OF_FILE;
- yyrestart(yyin );
- }
-
- else
- {
- ret_val = EOB_ACT_LAST_MATCH;
- YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
- YY_BUFFER_EOF_PENDING;
- }
- }
-
- else
- ret_val = EOB_ACT_CONTINUE_SCAN;
-
- if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
- /* Extend the array by 50%, plus the number we really need. */
- yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
- YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size );
- if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
- YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
- }
-
- (yy_n_chars) += number_to_move;
- YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
- YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
-
- (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
-
- return ret_val;
-}
-
-/* yy_get_previous_state - get the state just before the EOB char was reached */
-
- static yy_state_type yy_get_previous_state (void)
-{
- register yy_state_type yy_current_state;
- register char *yy_cp;
-
- yy_current_state = (yy_start);
- yy_current_state += YY_AT_BOL();
-
- (yy_state_ptr) = (yy_state_buf);
- *(yy_state_ptr)++ = yy_current_state;
-
- for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
- {
- register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
- while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
- {
- yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 801 )
- yy_c = yy_meta[(unsigned int) yy_c];
- }
- yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
- *(yy_state_ptr)++ = yy_current_state;
- }
-
- return yy_current_state;
-}
-
-/* yy_try_NUL_trans - try to make a transition on the NUL character
- *
- * synopsis
- * next_state = yy_try_NUL_trans( current_state );
- */
- static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
-{
- register int yy_is_jam;
-
- register YY_CHAR yy_c = 1;
- while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
- {
- yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 801 )
- yy_c = yy_meta[(unsigned int) yy_c];
- }
- yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
- yy_is_jam = (yy_current_state == 800);
- if ( ! yy_is_jam )
- *(yy_state_ptr)++ = yy_current_state;
-
- return yy_is_jam ? 0 : yy_current_state;
-}
-
- static void yyunput (int c, register char * yy_bp )
-{
- register char *yy_cp;
-
- yy_cp = (yy_c_buf_p);
-
- /* undo effects of setting up yytext */
- *yy_cp = (yy_hold_char);
-
- if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
- { /* need to shift things up to make room */
- /* +2 for EOB chars. */
- register int number_to_move = (yy_n_chars) + 2;
- register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
- YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
- register char *source =
- &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
-
- while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
- *--dest = *--source;
-
- yy_cp += (int) (dest - source);
- yy_bp += (int) (dest - source);
- YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
- (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
-
- if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
- YY_FATAL_ERROR( "flex scanner push-back overflow" );
- }
-
- *--yy_cp = (char) c;
-
- if ( c == '\n' ){
- --yylineno;
- }
-
- (yytext_ptr) = yy_bp;
- (yy_hold_char) = *yy_cp;
- (yy_c_buf_p) = yy_cp;
-}
-
-#ifndef YY_NO_INPUT
-#ifdef __cplusplus
- static int yyinput (void)
-#else
- static int input (void)
-#endif
-
-{
- int c;
-
- *(yy_c_buf_p) = (yy_hold_char);
-
- if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
- {
- /* yy_c_buf_p now points to the character we want to return.
- * If this occurs *before* the EOB characters, then it's a
- * valid NUL; if not, then we've hit the end of the buffer.
- */
- if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
- /* This was really a NUL. */
- *(yy_c_buf_p) = '\0';
-
- else
- { /* need more input */
- int offset = (yy_c_buf_p) - (yytext_ptr);
- ++(yy_c_buf_p);
-
- switch ( yy_get_next_buffer( ) )
- {
- case EOB_ACT_LAST_MATCH:
- /* This happens because yy_g_n_b()
- * sees that we've accumulated a
- * token and flags that we need to
- * try matching the token before
- * proceeding. But for input(),
- * there's no matching to consider.
- * So convert the EOB_ACT_LAST_MATCH
- * to EOB_ACT_END_OF_FILE.
- */
-
- /* Reset buffer status. */
- yyrestart(yyin );
-
- /*FALLTHROUGH*/
-
- case EOB_ACT_END_OF_FILE:
- {
- if ( yywrap( ) )
- return EOF;
-
- if ( ! (yy_did_buffer_switch_on_eof) )
- YY_NEW_FILE;
-#ifdef __cplusplus
- return yyinput();
-#else
- return input();
-#endif
- }
-
- case EOB_ACT_CONTINUE_SCAN:
- (yy_c_buf_p) = (yytext_ptr) + offset;
- break;
- }
- }
- }
-
- c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */
- *(yy_c_buf_p) = '\0'; /* preserve yytext */
- (yy_hold_char) = *++(yy_c_buf_p);
-
- YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n');
- if ( YY_CURRENT_BUFFER_LVALUE->yy_at_bol )
-
- yylineno++;
-;
-
- return c;
-}
-#endif /* ifndef YY_NO_INPUT */
-
-/** Immediately switch to a different input stream.
- * @param input_file A readable stream.
- *
- * @note This function does not reset the start condition to @c INITIAL .
- */
- void yyrestart (FILE * input_file )
-{
-
- if ( ! YY_CURRENT_BUFFER ){
- yyensure_buffer_stack ();
- YY_CURRENT_BUFFER_LVALUE =
- yy_create_buffer(yyin,YY_BUF_SIZE );
- }
-
- yy_init_buffer(YY_CURRENT_BUFFER,input_file );
- yy_load_buffer_state( );
-}
-
-/** Switch to a different input buffer.
- * @param new_buffer The new input buffer.
- *
- */
- void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer )
-{
-
- /* TODO. We should be able to replace this entire function body
- * with
- * yypop_buffer_state();
- * yypush_buffer_state(new_buffer);
- */
- yyensure_buffer_stack ();
- if ( YY_CURRENT_BUFFER == new_buffer )
- return;
-
- if ( YY_CURRENT_BUFFER )
- {
- /* Flush out information for old buffer. */
- *(yy_c_buf_p) = (yy_hold_char);
- YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
- YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
- }
-
- YY_CURRENT_BUFFER_LVALUE = new_buffer;
- yy_load_buffer_state( );
-
- /* We don't actually know whether we did this switch during
- * EOF (yywrap()) processing, but the only time this flag
- * is looked at is after yywrap() is called, so it's safe
- * to go ahead and always set it.
- */
- (yy_did_buffer_switch_on_eof) = 1;
-}
-
-static void yy_load_buffer_state (void)
-{
- (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
- (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
- yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
- (yy_hold_char) = *(yy_c_buf_p);
-}
-
-/** Allocate and initialize an input buffer state.
- * @param file A readable stream.
- * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
- *
- * @return the allocated buffer state.
- */
- YY_BUFFER_STATE yy_create_buffer (FILE * file, int size )
-{
- YY_BUFFER_STATE b;
-
- b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
- if ( ! b )
- YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
-
- b->yy_buf_size = size;
-
- /* yy_ch_buf has to be 2 characters longer than the size given because
- * we need to put in 2 end-of-buffer characters.
- */
- b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 );
- if ( ! b->yy_ch_buf )
- YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
-
- b->yy_is_our_buffer = 1;
-
- yy_init_buffer(b,file );
-
- return b;
-}
-
-/** Destroy the buffer.
- * @param b a buffer created with yy_create_buffer()
- *
- */
- void yy_delete_buffer (YY_BUFFER_STATE b )
-{
-
- if ( ! b )
- return;
-
- if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
- YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
-
- if ( b->yy_is_our_buffer )
- yyfree((void *) b->yy_ch_buf );
-
- yyfree((void *) b );
-}
-
-#ifndef __cplusplus
-extern int isatty (int );
-#endif /* __cplusplus */
-
-/* Initializes or reinitializes a buffer.
- * This function is sometimes called more than once on the same buffer,
- * such as during a yyrestart() or at EOF.
- */
- static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file )
-
-{
- int oerrno = errno;
-
- yy_flush_buffer(b );
-
- b->yy_input_file = file;
- b->yy_fill_buffer = 1;
-
- /* If b is the current buffer, then yy_init_buffer was _probably_
- * called from yyrestart() or through yy_get_next_buffer.
- * In that case, we don't want to reset the lineno or column.
- */
- if (b != YY_CURRENT_BUFFER){
- b->yy_bs_lineno = 1;
- b->yy_bs_column = 0;
- }
-
- b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
-
- errno = oerrno;
-}
-
-/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
- * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
- *
- */
- void yy_flush_buffer (YY_BUFFER_STATE b )
-{
- if ( ! b )
- return;
-
- b->yy_n_chars = 0;
-
- /* We always need two end-of-buffer characters. The first causes
- * a transition to the end-of-buffer state. The second causes
- * a jam in that state.
- */
- b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
- b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
-
- b->yy_buf_pos = &b->yy_ch_buf[0];
-
- b->yy_at_bol = 1;
- b->yy_buffer_status = YY_BUFFER_NEW;
-
- if ( b == YY_CURRENT_BUFFER )
- yy_load_buffer_state( );
-}
-
-/** Pushes the new state onto the stack. The new state becomes
- * the current state. This function will allocate the stack
- * if necessary.
- * @param new_buffer The new state.
- *
- */
-void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
-{
- if (new_buffer == NULL)
- return;
-
- yyensure_buffer_stack();
-
- /* This block is copied from yy_switch_to_buffer. */
- if ( YY_CURRENT_BUFFER )
- {
- /* Flush out information for old buffer. */
- *(yy_c_buf_p) = (yy_hold_char);
- YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
- YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
- }
-
- /* Only push if top exists. Otherwise, replace top. */
- if (YY_CURRENT_BUFFER)
- (yy_buffer_stack_top)++;
- YY_CURRENT_BUFFER_LVALUE = new_buffer;
-
- /* copied from yy_switch_to_buffer. */
- yy_load_buffer_state( );
- (yy_did_buffer_switch_on_eof) = 1;
-}
-
-/** Removes and deletes the top of the stack, if present.
- * The next element becomes the new top.
- *
- */
-void yypop_buffer_state (void)
-{
- if (!YY_CURRENT_BUFFER)
- return;
-
- yy_delete_buffer(YY_CURRENT_BUFFER );
- YY_CURRENT_BUFFER_LVALUE = NULL;
- if ((yy_buffer_stack_top) > 0)
- --(yy_buffer_stack_top);
-
- if (YY_CURRENT_BUFFER) {
- yy_load_buffer_state( );
- (yy_did_buffer_switch_on_eof) = 1;
- }
-}
-
-/* Allocates the stack if it does not exist.
- * Guarantees space for at least one push.
- */
-static void yyensure_buffer_stack (void)
-{
- int num_to_alloc;
-
- if (!(yy_buffer_stack)) {
-
- /* First allocation is just for 2 elements, since we don't know if this
- * scanner will even need a stack. We use 2 instead of 1 to avoid an
- * immediate realloc on the next call.
- */
- num_to_alloc = 1;
- (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
- (num_to_alloc * sizeof(struct yy_buffer_state*)
- );
- if ( ! (yy_buffer_stack) )
- YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
-
- memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
-
- (yy_buffer_stack_max) = num_to_alloc;
- (yy_buffer_stack_top) = 0;
- return;
- }
-
- if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
-
- /* Increase the buffer to prepare for a possible push. */
- int grow_size = 8 /* arbitrary grow size */;
-
- num_to_alloc = (yy_buffer_stack_max) + grow_size;
- (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
- ((yy_buffer_stack),
- num_to_alloc * sizeof(struct yy_buffer_state*)
- );
- if ( ! (yy_buffer_stack) )
- YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
-
- /* zero only the new slots.*/
- memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
- (yy_buffer_stack_max) = num_to_alloc;
- }
-}
-
-/** Setup the input buffer state to scan directly from a user-specified character buffer.
- * @param base the character buffer
- * @param size the size in bytes of the character buffer
- *
- * @return the newly allocated buffer state object.
- */
-YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size )
-{
- YY_BUFFER_STATE b;
-
- if ( size < 2 ||
- base[size-2] != YY_END_OF_BUFFER_CHAR ||
- base[size-1] != YY_END_OF_BUFFER_CHAR )
- /* They forgot to leave room for the EOB's. */
- return 0;
-
- b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
- if ( ! b )
- YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
-
- b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
- b->yy_buf_pos = b->yy_ch_buf = base;
- b->yy_is_our_buffer = 0;
- b->yy_input_file = 0;
- b->yy_n_chars = b->yy_buf_size;
- b->yy_is_interactive = 0;
- b->yy_at_bol = 1;
- b->yy_fill_buffer = 0;
- b->yy_buffer_status = YY_BUFFER_NEW;
-
- yy_switch_to_buffer(b );
-
- return b;
-}
-
-/** Setup the input buffer state to scan a string. The next call to yylex() will
- * scan from a @e copy of @a str.
- * @param yystr a NUL-terminated string to scan
- *
- * @return the newly allocated buffer state object.
- * @note If you want to scan bytes that may contain NUL values, then use
- * yy_scan_bytes() instead.
- */
-YY_BUFFER_STATE yy_scan_string (yyconst char * yystr )
-{
-
- return yy_scan_bytes(yystr,strlen(yystr) );
-}
-
-/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
- * scan from a @e copy of @a bytes.
- * @param bytes the byte buffer to scan
- * @param len the number of bytes in the buffer pointed to by @a bytes.
- *
- * @return the newly allocated buffer state object.
- */
-YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len )
-{
- YY_BUFFER_STATE b;
- char *buf;
- yy_size_t n;
- int i;
-
- /* Get memory for full buffer, including space for trailing EOB's. */
- n = _yybytes_len + 2;
- buf = (char *) yyalloc(n );
- if ( ! buf )
- YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
-
- for ( i = 0; i < _yybytes_len; ++i )
- buf[i] = yybytes[i];
-
- buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
-
- b = yy_scan_buffer(buf,n );
- if ( ! b )
- YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
-
- /* It's okay to grow etc. this buffer, and we should throw it
- * away when we're done.
- */
- b->yy_is_our_buffer = 1;
-
- return b;
-}
-
-#ifndef YY_EXIT_FAILURE
-#define YY_EXIT_FAILURE 2
-#endif
-
-static void yy_fatal_error (yyconst char* msg )
-{
- (void) fprintf( stderr, "%s\n", msg );
- exit( YY_EXIT_FAILURE );
-}
-
-/* Redefine yyless() so it works in section 3 code. */
-
-#undef yyless
-#define yyless(n) \
- do \
- { \
- /* Undo effects of setting up yytext. */ \
- int yyless_macro_arg = (n); \
- YY_LESS_LINENO(yyless_macro_arg);\
- yytext[yyleng] = (yy_hold_char); \
- (yy_c_buf_p) = yytext + yyless_macro_arg; \
- (yy_hold_char) = *(yy_c_buf_p); \
- *(yy_c_buf_p) = '\0'; \
- yyleng = yyless_macro_arg; \
- } \
- while ( 0 )
-
-/* Accessor methods (get/set functions) to struct members. */
-
-/** Get the current line number.
- *
- */
-int yyget_lineno (void)
-{
-
- return yylineno;
-}
-
-/** Get the input stream.
- *
- */
-FILE *yyget_in (void)
-{
- return yyin;
-}
-
-/** Get the output stream.
- *
- */
-FILE *yyget_out (void)
-{
- return yyout;
-}
-
-/** Get the length of the current token.
- *
- */
-int yyget_leng (void)
-{
- return yyleng;
-}
-
-/** Get the current token.
- *
- */
-
-char *yyget_text (void)
-{
- return yytext;
-}
-
-/** Set the current line number.
- * @param line_number
- *
- */
-void yyset_lineno (int line_number )
-{
-
- yylineno = line_number;
-}
-
-/** Set the input stream. This does not discard the current
- * input buffer.
- * @param in_str A readable stream.
- *
- * @see yy_switch_to_buffer
- */
-void yyset_in (FILE * in_str )
-{
- yyin = in_str ;
-}
-
-void yyset_out (FILE * out_str )
-{
- yyout = out_str ;
-}
-
-int yyget_debug (void)
-{
- return yy_flex_debug;
-}
-
-void yyset_debug (int bdebug )
-{
- yy_flex_debug = bdebug ;
-}
-
-static int yy_init_globals (void)
-{
- /* Initialization is the same as for the non-reentrant scanner.
- * This function is called from yylex_destroy(), so don't allocate here.
- */
-
- /* We do not touch yylineno unless the option is enabled. */
- yylineno = 1;
-
- (yy_buffer_stack) = 0;
- (yy_buffer_stack_top) = 0;
- (yy_buffer_stack_max) = 0;
- (yy_c_buf_p) = (char *) 0;
- (yy_init) = 0;
- (yy_start) = 0;
-
- (yy_state_buf) = 0;
- (yy_state_ptr) = 0;
- (yy_full_match) = 0;
- (yy_lp) = 0;
-
-/* Defined in main.c */
-#ifdef YY_STDINIT
- yyin = stdin;
- yyout = stdout;
-#else
- yyin = (FILE *) 0;
- yyout = (FILE *) 0;
-#endif
-
- /* For future reference: Set errno on error, since we are called by
- * yylex_init()
- */
- return 0;
-}
-
-/* yylex_destroy is for both reentrant and non-reentrant scanners. */
-int yylex_destroy (void)
-{
-
- /* Pop the buffer stack, destroying each element. */
- while(YY_CURRENT_BUFFER){
- yy_delete_buffer(YY_CURRENT_BUFFER );
- YY_CURRENT_BUFFER_LVALUE = NULL;
- yypop_buffer_state();
- }
-
- /* Destroy the stack itself. */
- yyfree((yy_buffer_stack) );
- (yy_buffer_stack) = NULL;
-
- yyfree ( (yy_state_buf) );
- (yy_state_buf) = NULL;
-
- /* Reset the globals. This is important in a non-reentrant scanner so the next time
- * yylex() is called, initialization will occur. */
- yy_init_globals( );
-
- return 0;
-}
-
-/*
- * Internal utility routines.
- */
-
-#ifndef yytext_ptr
-static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
-{
- register int i;
- for ( i = 0; i < n; ++i )
- s1[i] = s2[i];
-}
-#endif
-
-#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (yyconst char * s )
-{
- register int n;
- for ( n = 0; s[n]; ++n )
- ;
-
- return n;
-}
-#endif
-
-void *yyalloc (yy_size_t size )
-{
- return (void *) malloc( size );
-}
-
-void *yyrealloc (void * ptr, yy_size_t size )
-{
- /* The cast to (char *) in the following accommodates both
- * implementations that use char* generic pointers, and those
- * that use void* generic pointers. It works with the latter
- * because both ANSI C and C++ allow castless assignment from
- * any pointer type to void*, and deal with argument conversions
- * as though doing an assignment.
- */
- return (void *) realloc( (char *) ptr, size );
-}
-
-void yyfree (void * ptr )
-{
- free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
-}
-
-#define YYTABLES_NAME "yytables"
-
-#line 231 "menul.l"
diff --git a/ecflow_4_0_7/view/src/menul.l b/ecflow_4_0_7/view/src/menul.l
deleted file mode 100644
index 44af199..0000000
--- a/ecflow_4_0_7/view/src/menul.l
+++ /dev/null
@@ -1,230 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #11 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-%{
-#if defined(linux) || defined(mips) || defined(hpux) || defined(_AIX)
-int yylineno;
-#define NEWLINE yylineno++
-#else
-#define NEWLINE
-#endif
-
-#undef ECHO
-/* #define ECHO printf("<%s>",yytext) */
-#define ECHO /**/
-
-/*
-on HP lex -Xa10000
-p4 edit src/menul.c src/menuy.c && cd src && lex -t menul.l > menul.c && yacc menuy.y && mv -f y.tab.c menuy.c && cd ../ && make menu && make prof # ./env.sh cc
-
-ecflow_client | xargs addr2line -e ecflow_client -f
-*/
-
-#if defined (linux) || defined(alpha) || defined(SVR4) || defined(SGI) || defined(_AIX)
-#define yyinput input
-#endif
-
-
-%}
-
-IDENT [_0-9A-Za-z]+
-NUMBER [0-9]+
-NODE \/[_0-9A-Za-z:\/]*
-
-%option yylineno
-%array
-
-%s LOGFILE
-%e 1600
-%p 8000
-%a 15000
-%n 5000
-%o 10000
-
-%%
-
-!.*$ ;
-
-<INITIAL>version return VERSION;
-<INITIAL>menu return MENU;
-<INITIAL>MENU return MENU;
-<INITIAL>NONE return NONE;
-<INITIAL>ALL return ALL;
-<INITIAL>UNKNOWN return UNKNOWN;
-<INITIAL>SUSPENDED return SUSPENDED;
-<INITIAL>COMPLETE return COMPLETE;
-<INITIAL>QUEUED return QUEUED;
-<INITIAL>SUBMITTED return SUBMITTED;
-<INITIAL>ACTIVE return ACTIVE;
-<INITIAL>ABORTED return ABORTED;
-<INITIAL>CLEAR return CLEAR;
-<INITIAL>SET return SET;
-<INITIAL>SHUTDOWN return SHUTDOWN;
-<INITIAL>HALTED return HALTED;
-<INITIAL>LOCKED return LOCKED;
-<INITIAL>SERVER return SERVER;
-<INITIAL>SMS return SMS;
-<INITIAL>NODE return NODE;
-<INITIAL>SUITE return SUITE;
-<INITIAL>FAMILY return FAMILY;
-<INITIAL>TASK return TASK;
-<INITIAL>EVENT return EVENT;
-<INITIAL>LIMIT return LIMIT;
-<INITIAL>LABEL return LABEL;
-<INITIAL>METER return METER;
-<INITIAL>VARIABLE return VARIABLE;
-<INITIAL>REPEAT return REPEAT;
-<INITIAL>ALIAS return ALIAS;
-<INITIAL>MIGRATED return MIGRATED;
-<INITIAL>HAS_TRIGGERS return HAS_TRIGGERS;
-<INITIAL>HAS_TIME return HAS_TIME;
-<INITIAL>HAS_DATE return HAS_DATE;
-<INITIAL>HAS_TEXT return HAS_TEXT;
-<INITIAL>IS_ZOMBIE return IS_ZOMBIE;
-<INITIAL>SEPARATOR return SEPARATOR;
-<INITIAL>YES return DEFAULT_YES;
-<INITIAL>NO return DEFAULT_NO;
-<INITIAL>WINDOW return WINDOW;
-<INITIAL>PLUG return PLUG;
-<INITIAL>COMP return COMP;
-<INITIAL>SELECTION return SELECTION;
-
-<INITIAL>USER return USER;
-<INITIAL>OPER return OPER;
-<INITIAL>ADMIN return ADMIN;
-
-<INITIAL>^LOG: { BEGIN LOGFILE; }
-<INITIAL>^MSG:.*$ { return JUNK; }
-<INITIAL>^DBG:.*$ { return JUNK; }
-<INITIAL>^ERR:.*$ { return JUNK; }
-<INITIAL>^WAR:.*$ { return JUNK; }
-<INITIAL>^"# LOG:" { ECHO; BEGIN LOGFILE; }
-<INITIAL>^"# MSG:" { ECHO; BEGIN LOGFILE; }
-<INITIAL>^"# DBG:" { ECHO; BEGIN LOGFILE; }
-<INITIAL>^"# ERR:" { ECHO; BEGIN LOGFILE; }
-<INITIAL>^"# WAR:" { ECHO; BEGIN LOGFILE; }
-
-<LOGFILE>^LOG: { }
-<LOGFILE>MSG:.*$ { return JUNK; }
-<LOGFILE>DBG:.*$ { return JUNK; }
-<LOGFILE>ERR:.*$ { return JUNK; }
-<LOGFILE>WAR:.*$ { return JUNK; }
-
-<LOGFILE>^"# LOG:" ECHO;
-<LOGFILE>^"# MSG:.*$" { ECHO; return JUNK; }
-<LOGFILE>^"# DBG:.*$" { ECHO; return JUNK; }
-<LOGFILE>^"# ERR:.*$" { ECHO; return JUNK; }
-<LOGFILE>^"# WAR:.*$" { ECHO; return JUNK; }
-
-
-<INITIAL>{IDENT} return IDENT;
-
-<INITIAL>\" {
- int c,q = yytext[0];
- yyleng = 0;
- while((c = yyinput()) && c != q && c != '\n')
- if(c == '\\') {
- yytext[yyleng++] = c;
- yytext[yyleng++] = yyinput();
- } else
- yytext[yyleng++] = c;
- yytext[yyleng++] = 0;
- return STRING;
- }
-
-<INITIAL>\' {
- int c,q = yytext[0];
- yyleng = 0;
- while((c = yyinput()) && c != q && c != '\n')
- if(c == '\\') {
- yytext[yyleng++] = c;
- yytext[yyleng++] = yyinput();
- } else
- yytext[yyleng++] = c;
- yytext[yyleng++] = 0;
- return STRING;
- }
-<LOGFILE>complete: { ECHO; return COMPLETE; }
-<LOGFILE>queued: { ECHO; return QUEUED; }
-<LOGFILE>active: { ECHO; return ACTIVE; }
-<LOGFILE>command:Meter { ECHO; return METER; }
-<LOGFILE>command:Event { ECHO; return EVENT; }
-<LOGFILE>unknown: { return UNKNOWN; }
-<LOGFILE>submitted: { ECHO; return SUBMITTED; }
-<LOGFILE>aborted: { ECHO; return ABORTED; }
-<LOGFILE>set: { ECHO; return SET; }
-<LOGFILE>clear: { ECHO; return CLEAR; }
-<LOGFILE>cancel: { ECHO; return CANCEL; }
-
-<LOGFILE>command:.*$ { ECHO; return JUNK; }
-<LOGFILE>check:.*$ { ECHO; return JUNK; }
-<LOGFILE>checkpoint:.*$ { ECHO; return JUNK; }
-<LOGFILE>label:.*$ { ECHO; return JUNK; }
-<LOGFILE>abort:.*$ { ECHO; return JUNK; }
-<LOGFILE>midnight:.*$ { ECHO; return JUNK; }
-<LOGFILE>"autorepeat date":.*$ { ECHO; return JUNK; }
-<LOGFILE>autocancel:.*$ { ECHO; return JUNK; }
-<LOGFILE>run:.*$ { ECHO; return JUNK; }
-<LOGFILE>order:.*$ { ECHO; return JUNK; }
-<LOGFILE>login:.*$ { ECHO; return JUNK; }
-<LOGFILE>logout:.*$ { ECHO; return JUNK; }
-<LOGFILE>recover:.*$ { ECHO; return JUNK; }
-<LOGFILE>resubmit:.*$ { ECHO; return JUNK; }
-<LOGFILE>requeue:.*$ { ECHO; return JUNK; }
-<LOGFILE>suspend:.*$ { ECHO; return JUNK; }
-<LOGFILE>resume:.*$ { ECHO; return JUNK; }
-<LOGFILE>timeout:.*$ { ECHO; return JUNK; }
-<LOGFILE>dir:.*$ { ECHO; return JUNK; }
-<LOGFILE>send:.*$ { ECHO; return JUNK; }
-<LOGFILE>send(.*):.*$ { ECHO; return JUNK; }
-<LOGFILE>time:.*$ { ECHO; return JUNK; }
-<LOGFILE>manual:.*$ { ECHO; return JUNK; }
-<LOGFILE>file:.*$ { ECHO; return JUNK; }
-<LOGFILE>editfile:.*$ { ECHO; return JUNK; }
-<LOGFILE>edit:.*$ { ECHO; return JUNK; }
-<LOGFILE>translate:.*$ { ECHO; return JUNK; }
-<LOGFILE>force:.*$ { ECHO; return JUNK; }
-<LOGFILE>force(.*):.*$ { ECHO; return JUNK; }
-<LOGFILE>play:.*$ { ECHO; return JUNK; }
-<LOGFILE>begin:.*$ { ECHO; return JUNK; }
-<LOGFILE>late:.*$ { ECHO; return JUNK; }
-<LOGFILE>delete:.*$ { ECHO; return JUNK; }
-<LOGFILE>alter:.*$ { ECHO; return JUNK; }
-<LOGFILE>event:.*$ { ECHO; return JUNK; }
-<LOGFILE>setev:.*$ { ECHO; return JUNK; }
-<LOGFILE>dependencies:.*$ { ECHO; return JUNK; }
-<LOGFILE>time-used:.*$ { ECHO; return JUNK; }
-<LOGFILE>PID.*$ { ECHO; return JUNK; }
-<LOGFILE>--force.*$ { ECHO; return JUNK; }
-<LOGFILE>--ping.*$ { ECHO; return JUNK; }
-<LOGFILE>--news.*$ { ECHO; return JUNK; }
-<LOGFILE>svr:.*$ { ECHO; return JUNK; }
-
-<LOGFILE>" <--- still suspended" ;
-<LOGFILE>" by rule" ;
-<LOGFILE>command:.*$ { return JUNK; }
-<LOGFILE>try-no.*$ { return JUNK; }
-
-<LOGFILE>{NUMBER} { ECHO; return NUMBER; }
-<LOGFILE>{IDENT} { ECHO; return IDENT;}
-<LOGFILE>{NODE} { ECHO; return NODE_NAME;}
-<LOGFILE>[ \t] ECHO;
-<LOGFILE>. { ECHO; return *yytext; }
-<INITIAL>[ \t] ;
-<INITIAL>. return *yytext;
-\n { BEGIN INITIAL; NEWLINE; }
-<LOGFILE>job_size:.*$ { return ANY; }
-
-%
diff --git a/ecflow_4_0_7/view/src/menus.cc b/ecflow_4_0_7/view/src/menus.cc
deleted file mode 100644
index c4f6296..0000000
--- a/ecflow_4_0_7/view/src/menus.cc
+++ /dev/null
@@ -1,796 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #17 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#ifndef menus_H
-#include "menus.h"
-#endif
-
-#ifndef selection_H
-#include "selection.h"
-#endif
-
-#ifndef flags_H
-#include "flags.h"
-#endif
-
-#ifndef tip_H
-#include "tip.h"
-#endif
-
-#ifndef xec_H
-#include "xec.h"
-#endif
-
-#ifndef collector_H
-#include "collector.h"
-#endif
-
-#ifndef confirm_H
-#include "confirm.h"
-#endif
-
-#ifndef panel_window_H
-#include "panel_window.h"
-#endif
-
-#ifndef parser_H
-#include "parser.h"
-#endif
-
-#ifndef directory_H
-#include "directory.h"
-#endif
-
-#include "log_event.h"
-
-#include <unistd.h>
-#include <fstream>
-#include <iostream>
-
-#include <Xm/Label.h>
-#include <Xm/PushB.h>
-#include <Xm/RowColumn.h>
-#include <Xm/Separator.h>
-#include <Xm/CascadeBG.h>
-#include <Xm/PushBG.h>
-#include <Xm/SeparatoG.h>
-#include <Xm/ToggleBG.h>
-#include <Xm/RowColumnP.h>
-
-extern "C"
-{
-#include "xec.h"
-}
-
-#ifndef node_H
-#include "node.h"
-#endif
-
-#ifndef host_H
-#include "host.h"
-#endif
-
-#include "ecflowview.h"
-#undef XECFDEBUG
-#define XECFDEBUG if(0)
-#define MENU_REL 1
-#define MENU_MAJ 0
-#define MENU_MIN 0
-
-#define NUM_MENUS 2
-static Widget cmd_menu_popup[NUM_MENUS] = { 0, 0, };
-static Widget cmd_menu_name[NUM_MENUS] = { 0, 0, };
-
-static char* defaultMenu[] = {
-#include "ecflowview.menu.h"
-};
-
-static char* xcdpMenu[] = {
-#include "xcdp.menu.h"
-};
-
-/* #define YYDEBUG 1 */
-
-class node;
-class item;
-#include <string>
-class menu {
- friend int script_menus(node*, const char *cmd);
- static menu *root_[NUM_MENUS];
- std::string name_;
- item *item_;
- menu *next_;
- Widget widget_;
- int page_;
- static int init(int page, bool def);
-public:
- static int num_;
-
- menu(std::string name, item * i)
- : name_(name), item_(i), next_(0), widget_(0), page_(num_)
- { XECFDEBUG printf("# menu creation: %s\n", name.c_str());
- if (root_[page_] == NULL) root_[page_] = this; }
-
- menu *chain(menu * n);
- void create(Widget);
- void update(node *);
- void merge(item *);
- void fill(Widget list,int depth);
-
- static menu *find(const char *, int page=-1, bool verb=true);
- static void root(menu *m);
-};
-
-menu *menu::chain(menu * n)
-{
- if (n) {
- menu *m = menu::find(n->name_.c_str(), n->page_, false);
- if (m) {
- m->merge(n->item_); delete n;
- XECFDEBUG printf("# menu already there (chain) %s\n", n->name_.c_str());
- } else if (n->page_ == page_)
- next_ = n;
- }
- return this;
-}
-
-void menu::root(menu *m) {
- if (root_[num_] == NULL) root_[num_] = m;
- else if (m) {
- menu *men = menu::find(m->name_.c_str(), m->page_);
- XECFDEBUG {
- if (!men) printf("# menu chained %s\n", m->name_.c_str());
- else printf("# menu already there %s\n", m->name_.c_str()); }
- }
-}
-
-class action {
-protected:
- Widget widget_;
- item* item_;
-
- action() : widget_(0),item_(0) {}
-public:
- virtual ~action() {}
- void owner(item* i) { item_ = i; }
-
- virtual void create(Widget, item *) = 0;
- virtual void fill(Widget, int) {}
-
- Widget widget() { return widget_; }
- virtual void run(node *) { }
-};
-
-class command : public action {
- char *name_;
- virtual void create(Widget, item *);
-public:
- command(char *name): name_(name) { }
- virtual void run(node *);
-};
-
-class window_cmd : public action {
- char *name_;
- virtual void create(Widget, item *);
-public:
- window_cmd(char *name): name_(name) { }
- virtual void run(node *);
-};
-
-typedef void (*nodeproc)(node*);
-typedef void (*nodeproc_a_b)(node*, const char* a, const char* b);
-
-class internal: public action {
- nodeproc proc_;
- virtual void create(Widget, item *);
-public:
- internal(nodeproc p): proc_(p) { }
- virtual void run(node *);
-};
-
-class internal_a_b: public action {
- nodeproc_a_b proc_;
- const std::string a_, b_;
- virtual void create(Widget, item *);
-public:
- internal_a_b(nodeproc_a_b p, const char* a, const char*b)
- : proc_(p)
- , a_(a)
- , b_(b)
- { }
- virtual void run(node *);
-};
-
-
-class sub_menu : public action {
- virtual void create(Widget, item *);
- virtual void fill(Widget, int);
-public:
- sub_menu() { }
-};
-
-class separator : public action {
- virtual void create(Widget, item *);
-};
-
-menu *menu::root_[NUM_MENUS] = { 0, 0, };
-
-class item {
-public:
- item *next_;
-private:
- friend int script_menus(node*, const char *cmd);
- flags *visible_;
- flags *enabled_;
- char *title_;
- action *action_;
- char *question_;
- Boolean answer_;
- int page_;
-
-public:
-
- int page() const { return page_; }
-
- item(flags * visible,flags * enabled,
- char *title, action * action, char *question, Boolean answer)
- : next_(0), visible_(visible), enabled_(enabled)
- , title_(title), action_(action), question_(question)
- , answer_(answer), page_(menu::num_)
- { if(action_) action_->owner(this); }
-
- void update(node *);
-
- void create(Widget parent)
- {
- action_->create(parent, this);
- if(next_)
- next_->create(parent);
- }
-
- item *chain(item * n)
- {
- if (n->page_ == page_)
- next_ = n;
- return this;
- }
-
- char *title() { return title_; }
-
- item *find(const char* name);
-
- void run(node * n)
- {
- str question = n->substitute(question_);
- if(question_[0] == 0 || confirm::ask(answer_,question))
- action_->run(n);
- }
-
- void fill(Widget list,int depth)
- {
- XECFDEBUG printf("# item::fill %p %d\n",list,depth);
- char buf[1024];
- memset(buf,' ',depth);
- sprintf(buf+depth,"%s",title_);
- xec_AddListItem(list,buf);
- action_->fill(list,depth);
- if(next_)
- next_->fill(list,depth);
- }
-};
-
-item* item::find(const char* title)
-{
- for (item* run=this; run; run=run->next_)
- if (!strcmp(run->title(),title)) return run;
- return 0;
-}
-
-menus::menus()
-{
-}
-
-menus::~menus()
-{
-}
-
-void menus::write()
-{
- int lineno = 0;
- char *line;
- std::ofstream outfile;
- std::string fname = directory::user() + std::string("/ecflowview.menu");
- outfile.open(fname.c_str());
- std::cerr << "# creating menu file " << fname << "\n";
- while ((line = defaultMenu[lineno])) {
- outfile << line << "\n";
- lineno++;
- }
-}
-
-void menus::fillList(Widget list)
-{
- XECFDEBUG printf("# menus::fill %p\n",list);
- menu *m = menu::find("MAIN"); if(m) m->fill(list,0);
-}
-
-void menu::fill(Widget list,int depth)
-{
- item_->fill(list,depth);
-}
-
-void menus::show(Widget parent, XEvent * event_node, node * n)
-{
-
- if (parent==NULL) fprintf(stderr, "menus::show null widget\n");
- if(n == 0 || !n->menus())
- {
- selection::menu_node(0);
- return;
- }
-
- selection::menu_node(n);
- int page = n->__node__() ? 0 : 1;
-
- if(cmd_menu_popup[page] == 0)
- {
- cmd_menu_popup[page] = XmCreatePopupMenu(parent, "cmd_menu_popup", 0, 0);
- cmd_menu_name[page] = XmCreateLabel(cmd_menu_popup[page], "name", 0, 0);
- Widget w = XmCreateSeparator(cmd_menu_popup[page], "-", 0, 0);
-
- XtManageChild(cmd_menu_name[page]);
- XtManageChild(w);
-
- XtAddCallback(cmd_menu_popup[page], XmNentryCallback, menus::entryCB, 0);
- tip::makeTips(cmd_menu_popup[page]);
- }
-
- menu *m = menu::find("MAIN", page);
- if(m)
- {
- m->create(cmd_menu_popup[page]);
- m->update(n);
- }
-
- xec_VaSetLabel(cmd_menu_name[page], "%s %s",n->type_name(),n->node_name().c_str());
- xec_SetColor(cmd_menu_name[page], n->color(), XmNbackground);
-
- XmMenuPosition(cmd_menu_popup[page],(XButtonPressedEvent *) event_node);
- XtManageChild(cmd_menu_popup[page]);
-
-}
-
-int menu::num_ = 0;
-
-int menus::version(int rel, int maj, int min) {
- if (rel > MENU_REL || (rel == MENU_REL && maj > MENU_MAJ)) {
- std::cerr << "# menus definition file(s) shall be upgraded\n";
- std::cerr << "# app is "
- << MENU_REL << " "
- << MENU_MAJ << " "
- << MENU_MIN;
- std::cerr << "\n# file is " << rel << " " << maj << " " << min;
- std::cerr << "\n";
-
- return 1;
- } // else { std::cout << "# menus version compatible " << rel << " " << maj << " " << min << "\n"; }
- return 0;
-}
-
-int menu::init(int page, bool def) {
-#ifndef BRIDGE
- page = 0;
-#endif
- const char* name = page ? "xcdp.menu" : "ecflowview.menu";
- bool read = false;
- num_ = page;
- /* 0: ecflowview menu
- 1: xcdp menu
-
- system\user 0 1
- 0 tmp user
- 1 sys both, user overwrites
- */
- std::string path = directory::user();
- path += "/";
- path += name;
- const char* fname = path.c_str();
- if(!def && !access(fname,F_OK)) {
- std::cout << "# reading menu file: " << fname << "\n";
- parser::parse(fname);
- read = true;
- } else std::cerr << "# menu file not found: " << fname << "\n";
-
- path = directory::system();
- path += "/";
- path += name;
- fname = path.c_str();
-
- if (!def && !access(fname,F_OK)) {
- std::cout << "# reading menu file: " << fname << "\n";
- parser::parse(fname);
- read = true;
- } else std::cerr << "# menu file not found: " << fname << "\n";
-
- if(!read) {
- char* tmp = getenv("TMPDIR");
- path = tmp ? tmp : "/tmp";
- path += "/";
- path += name;
- fname = path.c_str();
-
- // if(access(fname,F_OK)) /* create if not already there */
- { /* create always */
- std::cerr << "# creating menu file " << fname << "\n";
- std::ofstream outfile;
- outfile.open(fname);
- int lineno = 0;
- char *line;
- while ((line = (page ? xcdpMenu[lineno] : defaultMenu[lineno]))) {
- outfile << line << "\n";
- lineno++;
- }
- outfile.close();
- }
- std::cout << "# menu file read: " << fname << "\n";
- parser::parse(fname);
- }
- return TRUE;
-}
-
-menu *menu::find(const char *name, int page, bool verb)
-{
-#ifndef BRIDGE
- page = 0;
-#endif
- if (page >= NUM_MENUS || page < 0) page = 0;
-
- if(root_[page] == NULL) init(page, false);
- if(root_[page] == NULL) init(page, true);
- menu *m = root_[page];
- while(m) {
- if(m->name_ == name)
- return m;
- m = m->next_;
- }
- if (verb) printf("# Cannot find menu called %s\n", name);
- return 0;
-}
-
-void menu::create(Widget parent)
-{
- widget_ = parent;
- XECFDEBUG printf("# menu::create %p %p\n",widget_,parent);
- if(item_)
- item_->create(parent);
- tip::makeTips(parent);
-}
-
-void sub_menu::create(Widget parent, item * i)
-{
- if(widget_ == 0) {
- Arg arg;
- Widget sub = XmCreatePulldownMenu(parent, i->title(), 0, 0);
- menu *m = menu::find(i->title(), i->page());
- if(m)
- m->create(sub);
- XtSetArg(arg, XmNsubMenuId, sub);
- widget_ = XmCreateCascadeButtonGadget(parent, i->title(), &arg, 1);
- XtManageChild(widget_);
- xec_SetUserData(widget_, i);
- XtAddCallback(sub, XmNentryCallback, menus::entryCB, 0);
- }
-}
-
-void sub_menu::fill(Widget list,int depth)
-{
- menu *m = menu::find(item_->title(), item_->page());
- if(m)
- m->fill(list,depth+3);
-}
-
-void command::create(Widget parent, item * i)
-{
- if(widget_ == 0) {
- widget_ = XmCreatePushButtonGadget(parent, i->title(), 0, 0);
- XtManageChild(widget_);
- xec_SetUserData(widget_, i);
- }
-}
-
-void window_cmd::create(Widget parent, item * i)
-{
- if(widget_ == 0) {
- widget_ = XmCreatePushButtonGadget(parent, i->title(), 0, 0);
- XtManageChild(widget_);
- xec_SetUserData(widget_, i);
- }
-}
-
-void internal::create(Widget parent, item * i)
-{
- if(widget_ == 0) {
- widget_ = XmCreatePushButtonGadget(parent, i->title(), 0, 0);
- XtManageChild(widget_);
- xec_SetUserData(widget_, i);
- }
-}
-
-void internal_a_b::create(Widget parent, item * i) /* internal:: */
-{
- if(widget_ == 0) {
- widget_ = XmCreatePushButtonGadget(parent, i->title(), 0, 0);
- XtManageChild(widget_);
- xec_SetUserData(widget_, i);
- }
-}
-
-void separator::create(Widget parent, item * i)
-{
- if(widget_ == 0) {
- widget_ = XmCreateSeparatorGadget(parent, "-", 0, 0);
- XtManageChild(widget_);
- xec_SetUserData(widget_, i);
- }
-}
-
-void menu::update(node * n)
-{
- if(item_) item_->update(n);
- if(next_) next_->update(n);
- if(!widget_) return;
-
- int cnt = 0;
- Widget last = 0;
-
- CompositeWidget c = CompositeWidget(widget_);
-
- XECFDEBUG printf("# menu::update %d\n",c->composite.num_children);
-
- for(unsigned i = 0 ; i < c->composite.num_children; i++)
- {
- Widget p = c->composite.children[i];
- if(!XtIsManaged(p)) continue;
-
- XECFDEBUG printf("# %s ",XtName(p));
-
- if(XtName(p)[0] == '-')
- {
- XtUnmanageChild(p);
- last = p;
- XECFDEBUG printf("# sep\n");
- }
- else
- {
- if(last)
- {
- XECFDEBUG printf("# (%d) ",cnt);
- if(cnt) XtManageChild(last);
- cnt = 0;
- last = 0;
- }
- cnt++;
- XECFDEBUG printf("# %d\n",cnt);
- }
- }
- XECFDEBUG printf("# menu::update\n");
-}
-
-void item::update(node * n)
-{
- if(!action_->widget())
- return;
- int page = n->__node__() ? 0 : 1;
-#ifndef BRIDGE
- page = 0;
-#endif
- if (page_ != page) XtUnmanageChild(action_->widget()); else
- if(visible_->eval(n))
- XtManageChild(action_->widget());
- else
- XtUnmanageChild(action_->widget());
-
- XtSetSensitive(action_->widget(),enabled_->eval(n));
-
- if(next_) next_->update(n);
-}
-
-void menus::entryCB(Widget w, XtPointer, XtPointer cb_data)
-{
- XmRowColumnCallbackStruct *cb =(XmRowColumnCallbackStruct *) cb_data;
- item *i =(item *) xec_GetUserData(cb->widget);
- if(i && selection::menu_node())
- i->run(selection::menu_node());
-}
-
-void command::run(node* n)
-{
- n->command(name_);
-}
-
-void window_cmd::run(node* n)
-{
- if (n != 0 && strncmp("Collect", name_, 7) == 0) collector::show(*n); else
- panel_window::new_window(n,name_,true,true);
-}
-
-void internal::run(node* n)
-{
- proc_(n);
-}
-
-void internal_a_b::run(node* n)
-{
- proc_(n, a_.c_str(), b_.c_str());
-}
-
-void menus::root(menu* m)
-{
- menu::root(m);
-}
-
-menu* menus::chain(menu* a,menu* b)
-{
- return a->chain(b);
-}
-
-item* menus::chain(item* a,item* b)
-{
- return a->chain(b);
-}
-
-menu* menus::create(char* a,item* b)
-{
- XECFDEBUG printf("# create menus %s\n", a);
- return new menu(a,b);
-}
-
-item* menus::create(flags* a,flags* b,char* c,action* d,char* e,bool f)
-{
- XECFDEBUG printf("# create item %d %d %s %s %d\n",
- a->eval(0) ? 1 : 0, b->eval(0) ? 1 : 0,
- c, e, f ? 1:0);
- return new item(a,b,c,d,e,f);
-}
-
-action* menus::command(char* a)
-{
- return new ::command(a);
-}
-
-action* menus::separator()
-{
- return new ::separator();
-}
-
-action* menus::sub_menu()
-{
- return new ::sub_menu();
-}
-
-action* menus::window(char* a)
-{
- return new ::window_cmd(a);
-}
-
-action* menus::internal(nodeproc a)
-{
- return new ::internal(a);
-}
-
-action* menus::internal_a_b(nodeproc_a_b a, const char*b, const char *c)
-{
- return new ::internal_a_b(a, b, c);
-}
-
-void menu::merge(item *i) {
- if (!i) return;
- /* menu is old original menu,
- its items are moved away,
- new items take place
- only the old items not found are kept */
- if (!item_) { item_ = i; return; }
- item *run, *next, *old = item_, *last = i;
- while (last->next_) { last = last->next_; }
- item_ = i;
- for (run = old; run; ) {
- next = run->next_; run->next_ = 0;
- if (!item_->find(run->title())) { last->next_ = run; last = run; }
- run = next;
- }
- last->next_ = 0;
-}
-
-extern "C" {
-// The stuff is here because in some os, lex and yacc are broken with c++
-
-int menus_version(int rel, int maj, int min) { return menus::version(rel, maj, min); }
-menu* menus_chain_menus(menu *a,menu *b) { return menus::chain(a,b); }
-item* menus_chain_items(item *a,item *b) { return menus::chain(a,b); }
-void menus_root(menu *m) { menus::root(m); }
-menu* menus_create_2(char* a,item* b) { return menus::create(a,b); }
-item* menus_create_6(flags* a,flags* b,char* c,action* d,char* e,int f)
- { return menus::create(a,b,c,d,e,f); }
-
-action* menus_command(char* a) { return menus::command(a); }
-action* menus_window(char* a) { return menus::window(a); }
-action* menus_separator() { return menus::separator(); }
-action* menus_sub_menu() { return menus::sub_menu(); }
-
-flags* new_flagNone() { return new flagNone(); }
-flags* new_typeFlag(int a) { return new typeFlag(a); }
-flags* new_flagNot(flags* a) { return new flagNot(a); }
-flags* new_flagOr(flags* a,flags* b) { return new flagOr(a,b); }
-flags* new_flagAnd(flags* a,flags* b) { return new flagAnd(a,b); }
-
-flags* new_flagAll() { return new flagAll(); }
-flags* new_eventFlag(int a) { return new eventFlag(a); }
-flags* new_selectionFlag() { return new selectionFlag(); }
-flags* new_statusFlag(int a) { return new statusFlag(a); }
-flags* new_userFlag(int a) { return new userFlag(a); }
-
-flags* new_procFlag_node_hasTriggers() { return new procFlag(&node::hasTriggers); }
-flags* new_procFlag_node_hasDate() { return new procFlag(&node::hasDate); }
-flags* new_procFlag_node_hasTime() { return new procFlag(&node::hasTimeHolding); }
-flags* new_procFlag_node_isMigrated() { return new procFlag(&node::isMigrated); }
-flags* new_procFlag_node_isLocked() { return new procFlag(&node::isLocked); }
-flags* new_procFlag_node_hasText() { return new procFlag(&node::hasText); }
-flags* new_procFlag_node_isZombie() { return new procFlag(&node::isZombie); }
-
-action* menus_internal_host_plug() { return menus::internal(&host::plug); }
-action* menus_internal_host_comp(const char*a, const char*b) {
- return menus::internal_a_b(&host::comp, a, b); }
-
-void log_event_meter_event(const DateTime& a,node* b,int c) {
- log_event::meter_event(a,b,c); }
-void log_event_event_event(const DateTime& a,node* b,int c) {
- log_event::event_event(a,b,c); }
-void log_event_status_event(const DateTime& a,node* b,int c) {
- log_event::status_event(a,b,c); }
-const node *log_event_find(char* a) { return log_event::find(a); }
-}
-
-int script_menus(node*, const char *cmd)
-{
- menu *m = menu::find("MAIN");
- if (!m) { std::cerr << "# no menu available!"; return 1; }
- node *n = selection::current_node();
- const char* arg = cmd + 5;
- unsigned int size = arg? strlen(arg) : 0;
- if (!n) { std::cerr << "# no node selected!"; return 1; }
- while (m) {
- item *i = m->item_;
- while (i) {
- if (i->visible_ && i->visible_->eval(n)) {
- if (i->enabled_ && i->enabled_->eval(n)) {
- if (i->action_) {
- if (size && !strncasecmp(arg, i->title_, size)) {
- std::cout << "# cmd issued: " << i->title_ << "\n";
- i->action_->run(n);
- } else
- std::cout << "# item: " << i->title_ << "\n";
- } else
- std::cout << "# item enabled: " << i->title_ << "\n";
- } else
- std::cout << "# item visible: " << i->title_ << "\n";
- }
- i = i->next_;
- }
- m = m->next_;
- }
-
- return 0;
-}
-
diff --git a/ecflow_4_0_7/view/src/menus.h b/ecflow_4_0_7/view/src/menus.h
deleted file mode 100644
index 1217a7c..0000000
--- a/ecflow_4_0_7/view/src/menus.h
+++ /dev/null
@@ -1,73 +0,0 @@
-#ifndef menus_H
-#define menus_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #9 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#ifdef NO_BOOL
-#include "bool.h"
-#endif
-
-#include <Xm/Xm.h>
-
-class node;
-class menu;
-class item;
-class action;
-class flags;
-
-class menus {
-public:
-
- menus();
- ~menus(); // Change to virtual if base class
-
- static void entryCB(Widget,XtPointer,XtPointer);
-
- static void show(Widget,XEvent*,node*);
-
- static void root(menu*);
- static menu* chain(menu*,menu*);
- static item* chain(item*,item*);
- static menu* create(char*,item*);
- static item* create(flags*,flags*,char*,action*,char*,bool);
- static action* command(char*);
- static action* separator();
- static action* sub_menu();
- static action* internal( void (*)(node*) );
- static action* internal_a_b( void (*)(node*, const char*, const char*),
- const char *a, const char *b);
- static action* window(char*);
-
- static void install(Widget,const char*);
-
- static void fillList(Widget);
-
- static void realize();
- static void write();
-
- static int version(int rel, int maj, int min);
-
-private:
-
- menus(const menus&);
- menus& operator=(const menus&);
-};
-
-inline void destroy(menus**) {}
-
-int script_menus(node*, const char *cmd);
-
-#endif
diff --git a/ecflow_4_0_7/view/src/menuy.c b/ecflow_4_0_7/view/src/menuy.c
deleted file mode 100644
index 56ed1a9..0000000
--- a/ecflow_4_0_7/view/src/menuy.c
+++ /dev/null
@@ -1,2428 +0,0 @@
-
-/* A Bison parser, made by GNU Bison 2.4.1. */
-
-/* Skeleton implementation for Bison's Yacc-like parsers in C
-
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
- Free Software Foundation, Inc.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-/* As a special exception, you may create a larger work that contains
- part or all of the Bison parser skeleton and distribute that work
- under terms of your choice, so long as that work isn't itself a
- parser generator using the skeleton or a modified version thereof
- as a parser skeleton. Alternatively, if you modify or redistribute
- the parser skeleton itself, you may (at your option) remove this
- special exception, which will cause the skeleton and the resulting
- Bison output files to be licensed under the GNU General Public
- License without this special exception.
-
- This special exception was added by the Free Software Foundation in
- version 2.2 of Bison. */
-
-/* C LALR(1) parser skeleton written by Richard Stallman, by
- simplifying the original so-called "semantic" parser. */
-
-/* All symbols defined below should begin with yy or YY, to avoid
- infringing on user name space. This should be done even for local
- variables, as they might otherwise be expanded by user macros.
- There are some unavoidable exceptions within include files to
- define necessary library symbols; they are noted "INFRINGES ON
- USER NAME SPACE" below. */
-
-/* Identify Bison output. */
-#define YYBISON 1
-
-/* Bison version. */
-#define YYBISON_VERSION "2.4.1"
-
-/* Skeleton name. */
-#define YYSKELETON_NAME "yacc.c"
-
-/* Pure parsers. */
-#define YYPURE 0
-
-/* Push parsers. */
-#define YYPUSH 0
-
-/* Pull parsers. */
-#define YYPULL 1
-
-/* Using locations. */
-#define YYLSP_NEEDED 0
-
-
-
-/* Copy the first part of user declarations. */
-
-/* Line 189 of yacc.c */
-#line 16 "menuy.y"
-
-#include "lexyacc.h"
-#include "ecflow.h"
-int yyone = 0;
-extern int yylineno;
-
-#ifdef __cplusplus
- void yylex(void);
-#endif
-
-#if defined(_AIX)
- extern char yytext[];
- int yydebug;
-#elif defined(hpux)
- void yyerror(char * msg);
- int yydebug;
-#elif defined(YYBISON)
- extern char yytext[]; /* ARRAY */
- void yyerror(char * msg);
- int yydebug;
-#elif defined (linux)
- extern char yytext[];
- void yyerror(char * msg);
- int yydebug;
-#elif defined(alpha) || defined(SGI)
- extern char yytext[]; /* ARRAY */
-#elif defined(SVR4)
- extern char yytext[]; /* ARRAY */
-#elif defined(alpha)
- extern unsigned char yytext[];
-#else
- extern char yytext[];
- void yyerror(char * msg);
- int yydebug;
-#endif
-
-
-/* Line 189 of yacc.c */
-#line 111 "y.tab.c"
-
-/* Enabling traces. */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-
-/* Enabling verbose error messages. */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
-#else
-# define YYERROR_VERBOSE 0
-#endif
-
-/* Enabling the token table. */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
-#endif
-
-
-/* Tokens. */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
- /* Put the tokens into the symbol table, so that GDB and other debuggers
- know about them. */
- enum yytokentype {
- VERSION = 258,
- MENU = 259,
- IDENT = 260,
- NONE = 261,
- ALL = 262,
- UNKNOWN = 263,
- SUSPENDED = 264,
- COMPLETE = 265,
- QUEUED = 266,
- SUBMITTED = 267,
- ACTIVE = 268,
- ABORTED = 269,
- CLEAR = 270,
- SET = 271,
- SHUTDOWN = 272,
- HALTED = 273,
- LOCKED = 274,
- MIGRATED = 275,
- SELECTION = 276,
- SERVER = 277,
- SMS = 278,
- NODE = 279,
- SUITE = 280,
- FAMILY = 281,
- TASK = 282,
- EVENT = 283,
- LABEL = 284,
- METER = 285,
- REPEAT = 286,
- VARIABLE = 287,
- TRIGGER = 288,
- LIMIT = 289,
- ALIAS = 290,
- HAS_TRIGGERS = 291,
- HAS_TIME = 292,
- HAS_DATE = 293,
- HAS_TEXT = 294,
- IS_ZOMBIE = 295,
- SEPARATOR = 296,
- STRING = 297,
- DEFAULT_YES = 298,
- DEFAULT_NO = 299,
- WINDOW = 300,
- PLUG = 301,
- COMP = 302,
- USER = 303,
- OPER = 304,
- ADMIN = 305,
- NUMBER = 306,
- JUNK = 307,
- EOL = 308,
- NODE_NAME = 309,
- CANCEL = 310,
- ANY = 311
- };
-#endif
-/* Tokens. */
-#define VERSION 258
-#define MENU 259
-#define IDENT 260
-#define NONE 261
-#define ALL 262
-#define UNKNOWN 263
-#define SUSPENDED 264
-#define COMPLETE 265
-#define QUEUED 266
-#define SUBMITTED 267
-#define ACTIVE 268
-#define ABORTED 269
-#define CLEAR 270
-#define SET 271
-#define SHUTDOWN 272
-#define HALTED 273
-#define LOCKED 274
-#define MIGRATED 275
-#define SELECTION 276
-#define SERVER 277
-#define SMS 278
-#define NODE 279
-#define SUITE 280
-#define FAMILY 281
-#define TASK 282
-#define EVENT 283
-#define LABEL 284
-#define METER 285
-#define REPEAT 286
-#define VARIABLE 287
-#define TRIGGER 288
-#define LIMIT 289
-#define ALIAS 290
-#define HAS_TRIGGERS 291
-#define HAS_TIME 292
-#define HAS_DATE 293
-#define HAS_TEXT 294
-#define IS_ZOMBIE 295
-#define SEPARATOR 296
-#define STRING 297
-#define DEFAULT_YES 298
-#define DEFAULT_NO 299
-#define WINDOW 300
-#define PLUG 301
-#define COMP 302
-#define USER 303
-#define OPER 304
-#define ADMIN 305
-#define NUMBER 306
-#define JUNK 307
-#define EOL 308
-#define NODE_NAME 309
-#define CANCEL 310
-#define ANY 311
-
-
-
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
-{
-
-/* Line 214 of yacc.c */
-#line 140 "menuy.y"
-
- char *str;
- long num;
- flags *flg;
- item *itm;
- menu *men;
- action *act;
- node* nod;
- double dbl;
- DateTime dti;
-
-
-
-/* Line 214 of yacc.c */
-#line 273 "y.tab.c"
-} YYSTYPE;
-# define YYSTYPE_IS_TRIVIAL 1
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-#endif
-
-
-/* Copy the second part of user declarations. */
-
-
-/* Line 264 of yacc.c */
-#line 285 "y.tab.c"
-
-#ifdef short
-# undef short
-#endif
-
-#ifdef YYTYPE_UINT8
-typedef YYTYPE_UINT8 yytype_uint8;
-#else
-typedef unsigned char yytype_uint8;
-#endif
-
-#ifdef YYTYPE_INT8
-typedef YYTYPE_INT8 yytype_int8;
-#elif (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-typedef signed char yytype_int8;
-#else
-typedef short int yytype_int8;
-#endif
-
-#ifdef YYTYPE_UINT16
-typedef YYTYPE_UINT16 yytype_uint16;
-#else
-typedef unsigned short int yytype_uint16;
-#endif
-
-#ifdef YYTYPE_INT16
-typedef YYTYPE_INT16 yytype_int16;
-#else
-typedef short int yytype_int16;
-#endif
-
-#ifndef YYSIZE_T
-# ifdef __SIZE_TYPE__
-# define YYSIZE_T __SIZE_TYPE__
-# elif defined size_t
-# define YYSIZE_T size_t
-# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
-# define YYSIZE_T size_t
-# else
-# define YYSIZE_T unsigned int
-# endif
-#endif
-
-#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
-
-#ifndef YY_
-# if YYENABLE_NLS
-# if ENABLE_NLS
-# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-# define YY_(msgid) dgettext ("bison-runtime", msgid)
-# endif
-# endif
-# ifndef YY_
-# define YY_(msgid) msgid
-# endif
-#endif
-
-/* Suppress unused-variable warnings by "using" E. */
-#if ! defined lint || defined __GNUC__
-# define YYUSE(e) ((void) (e))
-#else
-# define YYUSE(e) /* empty */
-#endif
-
-/* Identity function, used to suppress warnings about constant conditions. */
-#ifndef lint
-# define YYID(n) (n)
-#else
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static int
-YYID (int yyi)
-#else
-static int
-YYID (yyi)
- int yyi;
-#endif
-{
- return yyi;
-}
-#endif
-
-#if ! defined yyoverflow || YYERROR_VERBOSE
-
-/* The parser invokes alloca or malloc; define the necessary symbols. */
-
-# ifdef YYSTACK_USE_ALLOCA
-# if YYSTACK_USE_ALLOCA
-# ifdef __GNUC__
-# define YYSTACK_ALLOC __builtin_alloca
-# elif defined __BUILTIN_VA_ARG_INCR
-# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
-# elif defined _AIX
-# define YYSTACK_ALLOC __alloca
-# elif defined _MSC_VER
-# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
-# define alloca _alloca
-# else
-# define YYSTACK_ALLOC alloca
-# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef _STDLIB_H
-# define _STDLIB_H 1
-# endif
-# endif
-# endif
-# endif
-# endif
-
-# ifdef YYSTACK_ALLOC
- /* Pacify GCC's `empty if-body' warning. */
-# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
-# ifndef YYSTACK_ALLOC_MAXIMUM
- /* The OS might guarantee only one guard page at the bottom of the stack,
- and a page size can be as small as 4096 bytes. So we cannot safely
- invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
- to allow for a few compiler-allocated temporary stack slots. */
-# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
-# endif
-# else
-# define YYSTACK_ALLOC YYMALLOC
-# define YYSTACK_FREE YYFREE
-# ifndef YYSTACK_ALLOC_MAXIMUM
-# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
-# endif
-# if (defined __cplusplus && ! defined _STDLIB_H \
- && ! ((defined YYMALLOC || defined malloc) \
- && (defined YYFREE || defined free)))
-# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef _STDLIB_H
-# define _STDLIB_H 1
-# endif
-# endif
-# ifndef YYMALLOC
-# define YYMALLOC malloc
-# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
-# endif
-# endif
-# ifndef YYFREE
-# define YYFREE free
-# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-void free (void *); /* INFRINGES ON USER NAME SPACE */
-# endif
-# endif
-# endif
-#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
-
-
-#if (! defined yyoverflow \
- && (! defined __cplusplus \
- || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
-
-/* A type that is properly aligned for any stack member. */
-union yyalloc
-{
- yytype_int16 yyss_alloc;
- YYSTYPE yyvs_alloc;
-};
-
-/* The size of the maximum gap between one aligned stack and the next. */
-# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
-
-/* The size of an array large to enough to hold all stacks, each with
- N elements. */
-# define YYSTACK_BYTES(N) \
- ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
- + YYSTACK_GAP_MAXIMUM)
-
-/* Copy COUNT objects from FROM to TO. The source and destination do
- not overlap. */
-# ifndef YYCOPY
-# if defined __GNUC__ && 1 < __GNUC__
-# define YYCOPY(To, From, Count) \
- __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
-# else
-# define YYCOPY(To, From, Count) \
- do \
- { \
- YYSIZE_T yyi; \
- for (yyi = 0; yyi < (Count); yyi++) \
- (To)[yyi] = (From)[yyi]; \
- } \
- while (YYID (0))
-# endif
-# endif
-
-/* Relocate STACK from its old location to the new one. The
- local variables YYSIZE and YYSTACKSIZE give the old and new number of
- elements in the stack, and YYPTR gives the new location of the
- stack. Advance YYPTR to a properly aligned location for the next
- stack. */
-# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
- do \
- { \
- YYSIZE_T yynewbytes; \
- YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
- Stack = &yyptr->Stack_alloc; \
- yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
- yyptr += yynewbytes / sizeof (*yyptr); \
- } \
- while (YYID (0))
-
-#endif
-
-/* YYFINAL -- State number of the termination state. */
-#define YYFINAL 22
-/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 200
-
-/* YYNTOKENS -- Number of terminals. */
-#define YYNTOKENS 70
-/* YYNNTS -- Number of nonterminals. */
-#define YYNNTS 22
-/* YYNRULES -- Number of rules. */
-#define YYNRULES 91
-/* YYNRULES -- Number of states. */
-#define YYNSTATES 153
-
-/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
-#define YYUNDEFTOK 2
-#define YYMAXUTOK 311
-
-#define YYTRANSLATE(YYX) \
- ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
-
-/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
-static const yytype_uint8 yytranslate[] =
-{
- 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 65, 2,
- 60, 62, 2, 2, 61, 2, 68, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 67, 57,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 66, 2, 69, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 58, 64, 59, 63, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
- 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
- 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
- 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
- 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
- 55, 56
-};
-
-#if YYDEBUG
-/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
- YYRHS. */
-static const yytype_uint16 yyprhs[] =
-{
- 0, 0, 3, 6, 8, 10, 12, 18, 21, 23,
- 26, 32, 34, 36, 39, 41, 55, 65, 68, 70,
- 72, 74, 76, 78, 80, 82, 84, 86, 88, 90,
- 92, 94, 96, 98, 100, 102, 104, 106, 108, 110,
- 112, 114, 116, 118, 120, 122, 124, 126, 128, 130,
- 132, 134, 136, 138, 140, 142, 144, 148, 152, 156,
- 158, 160, 162, 164, 166, 171, 173, 180, 182, 184,
- 186, 188, 190, 193, 194, 198, 200, 202, 215, 219,
- 223, 227, 232, 236, 240, 244, 248, 252, 260, 263,
- 265, 267
-};
-
-/* YYRHS -- A `-1'-separated list of the rules' RHS. */
-static const yytype_int8 yyrhs[] =
-{
- 71, 0, -1, 72, 73, -1, 73, -1, 89, -1,
- 84, -1, 3, 75, 75, 75, 57, -1, 74, 73,
- -1, 74, -1, 74, 1, -1, 4, 75, 58, 76,
- 59, -1, 5, -1, 42, -1, 77, 76, -1, 77,
- -1, 60, 79, 61, 79, 61, 80, 61, 81, 61,
- 82, 61, 83, 62, -1, 60, 79, 61, 79, 61,
- 80, 61, 81, 62, -1, 63, 78, -1, 6, -1,
- 7, -1, 8, -1, 9, -1, 10, -1, 11, -1,
- 12, -1, 13, -1, 14, -1, 15, -1, 16, -1,
- 17, -1, 18, -1, 22, -1, 23, -1, 25, -1,
- 26, -1, 27, -1, 24, -1, 28, -1, 29, -1,
- 30, -1, 31, -1, 32, -1, 33, -1, 35, -1,
- 34, -1, 36, -1, 38, -1, 37, -1, 39, -1,
- 40, -1, 20, -1, 19, -1, 48, -1, 49, -1,
- 50, -1, 21, -1, 60, 79, 62, -1, 78, 64,
- 79, -1, 78, 65, 79, -1, 78, -1, 42, -1,
- 42, -1, 41, -1, 4, -1, 45, 60, 75, 62,
- -1, 46, -1, 47, 60, 75, 61, 75, 62, -1,
- 42, -1, 43, -1, 44, -1, 85, -1, 86, -1,
- 85, 86, -1, -1, 88, 91, 91, -1, 89, -1,
- 1, -1, 66, 91, 67, 91, 67, 91, 91, 68,
- 91, 68, 91, 69, -1, 87, 10, 90, -1, 87,
- 11, 90, -1, 87, 13, 90, -1, 87, 12, 90,
- 56, -1, 87, 12, 90, -1, 87, 14, 90, -1,
- 87, 8, 90, -1, 87, 16, 90, -1, 87, 15,
- 90, -1, 87, 30, 66, 90, 91, 90, 69, -1,
- 87, 52, -1, 52, -1, 54, -1, 51, -1
-};
-
-/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
-static const yytype_uint16 yyrline[] =
-{
- 0, 155, 155, 156, 157, 158, 161, 165, 166, 167,
- 170, 173, 174, 177, 178, 181, 183, 187, 188, 189,
- 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
- 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
- 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
- 220, 221, 222, 223, 224, 225, 226, 229, 230, 231,
- 234, 237, 238, 239, 240, 241, 242, 245, 248, 249,
- 254, 257, 258, 261, 262, 263, 264, 267, 274, 275,
- 276, 277, 279, 281, 282, 283, 284, 285, 288, 289,
- 292, 295
-};
-#endif
-
-#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
-/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
- First, the terminals, then, starting at YYNTOKENS, nonterminals. */
-static const char *const yytname[] =
-{
- "$end", "error", "$undefined", "VERSION", "MENU", "IDENT", "NONE",
- "ALL", "UNKNOWN", "SUSPENDED", "COMPLETE", "QUEUED", "SUBMITTED",
- "ACTIVE", "ABORTED", "CLEAR", "SET", "SHUTDOWN", "HALTED", "LOCKED",
- "MIGRATED", "SELECTION", "SERVER", "SMS", "NODE", "SUITE", "FAMILY",
- "TASK", "EVENT", "LABEL", "METER", "REPEAT", "VARIABLE", "TRIGGER",
- "LIMIT", "ALIAS", "HAS_TRIGGERS", "HAS_TIME", "HAS_DATE", "HAS_TEXT",
- "IS_ZOMBIE", "SEPARATOR", "STRING", "DEFAULT_YES", "DEFAULT_NO",
- "WINDOW", "PLUG", "COMP", "USER", "OPER", "ADMIN", "NUMBER", "JUNK",
- "EOL", "NODE_NAME", "CANCEL", "ANY", "';'", "'{'", "'}'", "'('", "','",
- "')'", "'~'", "'|'", "'&'", "'['", "':'", "'.'", "']'", "$accept",
- "first", "version", "menus", "menu", "name", "menu_items", "menu_item",
- "flag", "flags", "title", "action", "question", "answer", "logfile",
- "loglines", "logline", "date", "event", "junk", "node_name", "number", 0
-};
-#endif
-
-# ifdef YYPRINT
-/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
- token YYLEX-NUM. */
-static const yytype_uint16 yytoknum[] =
-{
- 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
- 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
- 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
- 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
- 295, 296, 297, 298, 299, 300, 301, 302, 303, 304,
- 305, 306, 307, 308, 309, 310, 311, 59, 123, 125,
- 40, 44, 41, 126, 124, 38, 91, 58, 46, 93
-};
-# endif
-
-/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
-static const yytype_uint8 yyr1[] =
-{
- 0, 70, 71, 71, 71, 71, 72, 73, 73, 73,
- 74, 75, 75, 76, 76, 77, 77, 78, 78, 78,
- 78, 78, 78, 78, 78, 78, 78, 78, 78, 78,
- 78, 78, 78, 78, 78, 78, 78, 78, 78, 78,
- 78, 78, 78, 78, 78, 78, 78, 78, 78, 78,
- 78, 78, 78, 78, 78, 78, 78, 79, 79, 79,
- 80, 81, 81, 81, 81, 81, 81, 82, 83, 83,
- 84, 85, 85, 86, 86, 86, 86, 87, 88, 88,
- 88, 88, 88, 88, 88, 88, 88, 88, 89, 89,
- 90, 91
-};
-
-/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
-static const yytype_uint8 yyr2[] =
-{
- 0, 2, 2, 1, 1, 1, 5, 2, 1, 2,
- 5, 1, 1, 2, 1, 13, 9, 2, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 3, 3, 3, 1,
- 1, 1, 1, 1, 4, 1, 6, 1, 1, 1,
- 1, 1, 2, 0, 3, 1, 1, 12, 3, 3,
- 3, 4, 3, 3, 3, 3, 3, 7, 2, 1,
- 1, 1
-};
-
-/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
- STATE-NUM when YYTABLE doesn't specify something else to do. Zero
- means the default is an error. */
-static const yytype_uint8 yydefact[] =
-{
- 0, 76, 0, 0, 89, 0, 0, 0, 3, 0,
- 5, 0, 71, 0, 0, 75, 11, 12, 0, 0,
- 91, 0, 1, 2, 9, 7, 72, 75, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 88, 0, 0,
- 0, 0, 90, 84, 78, 79, 82, 80, 83, 86,
- 85, 0, 74, 0, 0, 0, 14, 0, 81, 0,
- 6, 18, 19, 20, 21, 22, 23, 24, 25, 26,
- 27, 28, 29, 30, 51, 50, 55, 31, 32, 36,
- 33, 34, 35, 37, 38, 39, 40, 41, 42, 44,
- 43, 45, 47, 46, 48, 49, 52, 53, 54, 0,
- 0, 59, 0, 10, 13, 0, 0, 0, 17, 0,
- 0, 0, 0, 0, 56, 57, 58, 0, 0, 87,
- 0, 0, 60, 0, 0, 0, 0, 63, 62, 61,
- 0, 65, 0, 0, 0, 0, 0, 0, 16, 77,
- 0, 0, 67, 0, 64, 0, 0, 0, 68, 69,
- 0, 66, 15
-};
-
-/* YYDEFGOTO[NTERM-NUM]. */
-static const yytype_int16 yydefgoto[] =
-{
- -1, 6, 7, 8, 9, 18, 55, 56, 101, 102,
- 123, 133, 143, 150, 10, 11, 12, 13, 14, 15,
- 43, 21
-};
-
-/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
- STATE-NUM. */
-#define YYPACT_NINF -47
-static const yytype_int16 yypact[] =
-{
- 9, -47, 6, 6, -47, -31, 26, 33, -47, 18,
- -47, 16, -47, 19, -31, 44, -47, -47, 6, -11,
- -47, -22, -47, -47, -47, -47, -47, -47, -4, -4,
- -4, -4, -4, -4, -4, -4, -12, -47, -31, 6,
- -2, -31, -47, -47, -47, -47, 3, -47, -47, -47,
- -47, -4, -47, 5, 137, 1, -2, 0, -47, -31,
- -47, -47, -47, -47, -47, -47, -47, -47, -47, -47,
- -47, -47, -47, -47, -47, -47, -47, -47, -47, -47,
- -47, -47, -47, -47, -47, -47, -47, -47, -47, -47,
- -47, -47, -47, -47, -47, -47, -47, -47, -47, 137,
- 137, -26, 8, -47, -47, -31, -4, 4, -47, 137,
- 137, 137, -31, 7, -47, -47, -47, 11, 2, -47,
- 31, -31, -47, 13, 12, 10, -31, -47, -47, -47,
- 17, -47, 21, -21, 15, 6, 6, 36, -47, -47,
- 23, 22, -47, 25, -47, 6, -1, 27, -47, -47,
- 28, -47, -47
-};
-
-/* YYPGOTO[NTERM-NUM]. */
-static const yytype_int8 yypgoto[] =
-{
- -47, -47, -47, 14, -47, -3, 32, -47, -9, -46,
- -47, -47, -47, -47, -47, -47, 76, -47, -47, 82,
- -27, -13
-};
-
-/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
- positive, shift that token. If negative, reduce the rule which
- number is the opposite. If zero, do what YYDEFACT says.
- If YYTABLE_NINF, syntax error. */
-#define YYTABLE_NINF -74
-static const yytype_int16 yytable[] =
-{
- 19, 38, 44, 45, 46, 47, 48, 49, 50, -73,
- 1, 16, 2, 3, 127, 39, -70, 1, -8, 24,
- 20, 23, 3, 25, 59, 52, 22, 28, 57, 29,
- 30, 31, 32, 33, 34, 35, 53, 3, 109, 110,
- 137, 138, 148, 149, -4, 41, 106, 40, 17, 36,
- 42, 128, 129, 107, 51, 130, 131, 132, 54, 58,
- 103, 4, 60, 115, 116, 117, 114, 105, 4, 111,
- 121, 37, 120, 122, 125, 5, 119, 135, 142, 113,
- 126, 136, 5, 145, 139, 144, 146, 26, 104, 151,
- 152, 108, 112, 27, 0, 0, 0, 0, 0, 118,
- 0, 0, 0, 0, 0, 0, 0, 0, 124, 0,
- 0, 0, 0, 134, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 140, 141, 0, 0, 0, 0, 0, 0,
- 0, 0, 147, 61, 62, 63, 64, 65, 66, 67,
- 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
- 78, 79, 80, 81, 82, 83, 84, 85, 86, 87,
- 88, 89, 90, 91, 92, 93, 94, 95, 0, 0,
- 0, 0, 0, 0, 0, 96, 97, 98, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 99, 0, 0,
- 100
-};
-
-static const yytype_int16 yycheck[] =
-{
- 3, 14, 29, 30, 31, 32, 33, 34, 35, 0,
- 1, 5, 3, 4, 4, 18, 0, 1, 0, 1,
- 51, 7, 4, 9, 51, 38, 0, 8, 41, 10,
- 11, 12, 13, 14, 15, 16, 39, 4, 64, 65,
- 61, 62, 43, 44, 0, 67, 59, 58, 42, 30,
- 54, 41, 42, 99, 66, 45, 46, 47, 60, 56,
- 59, 52, 57, 109, 110, 111, 62, 67, 52, 61,
- 68, 52, 61, 42, 61, 66, 69, 60, 42, 106,
- 68, 60, 66, 61, 69, 62, 61, 11, 56, 62,
- 62, 100, 105, 11, -1, -1, -1, -1, -1, 112,
- -1, -1, -1, -1, -1, -1, -1, -1, 121, -1,
- -1, -1, -1, 126, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, 135, 136, -1, -1, -1, -1, -1, -1,
- -1, -1, 145, 6, 7, 8, 9, 10, 11, 12,
- 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
- 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
- 33, 34, 35, 36, 37, 38, 39, 40, -1, -1,
- -1, -1, -1, -1, -1, 48, 49, 50, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, 60, -1, -1,
- 63
-};
-
-/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
- symbol of state STATE-NUM. */
-static const yytype_uint8 yystos[] =
-{
- 0, 1, 3, 4, 52, 66, 71, 72, 73, 74,
- 84, 85, 86, 87, 88, 89, 5, 42, 75, 75,
- 51, 91, 0, 73, 1, 73, 86, 89, 8, 10,
- 11, 12, 13, 14, 15, 16, 30, 52, 91, 75,
- 58, 67, 54, 90, 90, 90, 90, 90, 90, 90,
- 90, 66, 91, 75, 60, 76, 77, 91, 56, 90,
- 57, 6, 7, 8, 9, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
- 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
- 35, 36, 37, 38, 39, 40, 48, 49, 50, 60,
- 63, 78, 79, 59, 76, 67, 91, 79, 78, 64,
- 65, 61, 91, 90, 62, 79, 79, 79, 91, 69,
- 61, 68, 42, 80, 91, 61, 68, 4, 41, 42,
- 45, 46, 47, 81, 91, 60, 60, 61, 62, 69,
- 75, 75, 42, 82, 62, 61, 61, 75, 43, 44,
- 83, 62, 62
-};
-
-#define yyerrok (yyerrstatus = 0)
-#define yyclearin (yychar = YYEMPTY)
-#define YYEMPTY (-2)
-#define YYEOF 0
-
-#define YYACCEPT goto yyacceptlab
-#define YYABORT goto yyabortlab
-#define YYERROR goto yyerrorlab
-
-
-/* Like YYERROR except do call yyerror. This remains here temporarily
- to ease the transition to the new meaning of YYERROR, for GCC.
- Once GCC version 2 has supplanted version 1, this can go. */
-
-#define YYFAIL goto yyerrlab
-
-#define YYRECOVERING() (!!yyerrstatus)
-
-#define YYBACKUP(Token, Value) \
-do \
- if (yychar == YYEMPTY && yylen == 1) \
- { \
- yychar = (Token); \
- yylval = (Value); \
- yytoken = YYTRANSLATE (yychar); \
- YYPOPSTACK (1); \
- goto yybackup; \
- } \
- else \
- { \
- yyerror (YY_("syntax error: cannot back up")); \
- YYERROR; \
- } \
-while (YYID (0))
-
-
-#define YYTERROR 1
-#define YYERRCODE 256
-
-
-/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
- If N is 0, then set CURRENT to the empty location which ends
- the previous symbol: RHS[0] (always defined). */
-
-#define YYRHSLOC(Rhs, K) ((Rhs)[K])
-#ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N) \
- do \
- if (YYID (N)) \
- { \
- (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
- (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
- (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
- (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
- } \
- else \
- { \
- (Current).first_line = (Current).last_line = \
- YYRHSLOC (Rhs, 0).last_line; \
- (Current).first_column = (Current).last_column = \
- YYRHSLOC (Rhs, 0).last_column; \
- } \
- while (YYID (0))
-#endif
-
-
-/* YY_LOCATION_PRINT -- Print the location on the stream.
- This macro was not mandated originally: define only if we know
- we won't break user code: when these are the locations we know. */
-
-#ifndef YY_LOCATION_PRINT
-# if YYLTYPE_IS_TRIVIAL
-# define YY_LOCATION_PRINT(File, Loc) \
- fprintf (File, "%d.%d-%d.%d", \
- (Loc).first_line, (Loc).first_column, \
- (Loc).last_line, (Loc).last_column)
-# else
-# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
-# endif
-#endif
-
-
-/* YYLEX -- calling `yylex' with the right arguments. */
-
-#ifdef YYLEX_PARAM
-# define YYLEX yylex (YYLEX_PARAM)
-#else
-# define YYLEX yylex ()
-#endif
-
-/* Enable debugging if requested. */
-#if YYDEBUG
-
-# ifndef YYFPRINTF
-# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
-# define YYFPRINTF fprintf
-# endif
-
-# define YYDPRINTF(Args) \
-do { \
- if (yydebug) \
- YYFPRINTF Args; \
-} while (YYID (0))
-
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
-do { \
- if (yydebug) \
- { \
- YYFPRINTF (stderr, "%s ", Title); \
- yy_symbol_print (stderr, \
- Type, Value); \
- YYFPRINTF (stderr, "\n"); \
- } \
-} while (YYID (0))
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT. |
-`--------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_value_print (yyoutput, yytype, yyvaluep)
- FILE *yyoutput;
- int yytype;
- YYSTYPE const * const yyvaluep;
-#endif
-{
- if (!yyvaluep)
- return;
-# ifdef YYPRINT
- if (yytype < YYNTOKENS)
- YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
-# else
- YYUSE (yyoutput);
-# endif
- switch (yytype)
- {
- default:
- break;
- }
-}
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT. |
-`--------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_print (yyoutput, yytype, yyvaluep)
- FILE *yyoutput;
- int yytype;
- YYSTYPE const * const yyvaluep;
-#endif
-{
- if (yytype < YYNTOKENS)
- YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
- else
- YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
-
- yy_symbol_value_print (yyoutput, yytype, yyvaluep);
- YYFPRINTF (yyoutput, ")");
-}
-
-/*------------------------------------------------------------------.
-| yy_stack_print -- Print the state stack from its BOTTOM up to its |
-| TOP (included). |
-`------------------------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
-#else
-static void
-yy_stack_print (yybottom, yytop)
- yytype_int16 *yybottom;
- yytype_int16 *yytop;
-#endif
-{
- YYFPRINTF (stderr, "Stack now");
- for (; yybottom <= yytop; yybottom++)
- {
- int yybot = *yybottom;
- YYFPRINTF (stderr, " %d", yybot);
- }
- YYFPRINTF (stderr, "\n");
-}
-
-# define YY_STACK_PRINT(Bottom, Top) \
-do { \
- if (yydebug) \
- yy_stack_print ((Bottom), (Top)); \
-} while (YYID (0))
-
-
-/*------------------------------------------------.
-| Report that the YYRULE is going to be reduced. |
-`------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
-#else
-static void
-yy_reduce_print (yyvsp, yyrule)
- YYSTYPE *yyvsp;
- int yyrule;
-#endif
-{
- int yynrhs = yyr2[yyrule];
- int yyi;
- unsigned long int yylno = yyrline[yyrule];
- YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
- yyrule - 1, yylno);
- /* The symbols being reduced. */
- for (yyi = 0; yyi < yynrhs; yyi++)
- {
- YYFPRINTF (stderr, " $%d = ", yyi + 1);
- yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
- &(yyvsp[(yyi + 1) - (yynrhs)])
- );
- YYFPRINTF (stderr, "\n");
- }
-}
-
-# define YY_REDUCE_PRINT(Rule) \
-do { \
- if (yydebug) \
- yy_reduce_print (yyvsp, Rule); \
-} while (YYID (0))
-
-/* Nonzero means print parse trace. It is left uninitialized so that
- multiple parsers can coexist. */
-int yydebug;
-#else /* !YYDEBUG */
-# define YYDPRINTF(Args)
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
-# define YY_STACK_PRINT(Bottom, Top)
-# define YY_REDUCE_PRINT(Rule)
-#endif /* !YYDEBUG */
-
-
-/* YYINITDEPTH -- initial size of the parser's stacks. */
-#ifndef YYINITDEPTH
-# define YYINITDEPTH 200
-#endif
-
-/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
- if the built-in stack extension method is used).
-
- Do not make this value too large; the results are undefined if
- YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
- evaluated with infinite-precision integer arithmetic. */
-
-#ifndef YYMAXDEPTH
-# define YYMAXDEPTH 10000
-#endif
-
-
-
-#if YYERROR_VERBOSE
-
-# ifndef yystrlen
-# if defined __GLIBC__ && defined _STRING_H
-# define yystrlen strlen
-# else
-/* Return the length of YYSTR. */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static YYSIZE_T
-yystrlen (const char *yystr)
-#else
-static YYSIZE_T
-yystrlen (yystr)
- const char *yystr;
-#endif
-{
- YYSIZE_T yylen;
- for (yylen = 0; yystr[yylen]; yylen++)
- continue;
- return yylen;
-}
-# endif
-# endif
-
-# ifndef yystpcpy
-# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
-# define yystpcpy stpcpy
-# else
-/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
- YYDEST. */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static char *
-yystpcpy (char *yydest, const char *yysrc)
-#else
-static char *
-yystpcpy (yydest, yysrc)
- char *yydest;
- const char *yysrc;
-#endif
-{
- char *yyd = yydest;
- const char *yys = yysrc;
-
- while ((*yyd++ = *yys++) != '\0')
- continue;
-
- return yyd - 1;
-}
-# endif
-# endif
-
-# ifndef yytnamerr
-/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
- quotes and backslashes, so that it's suitable for yyerror. The
- heuristic is that double-quoting is unnecessary unless the string
- contains an apostrophe, a comma, or backslash (other than
- backslash-backslash). YYSTR is taken from yytname. If YYRES is
- null, do not copy; instead, return the length of what the result
- would have been. */
-static YYSIZE_T
-yytnamerr (char *yyres, const char *yystr)
-{
- if (*yystr == '"')
- {
- YYSIZE_T yyn = 0;
- char const *yyp = yystr;
-
- for (;;)
- switch (*++yyp)
- {
- case '\'':
- case ',':
- goto do_not_strip_quotes;
-
- case '\\':
- if (*++yyp != '\\')
- goto do_not_strip_quotes;
- /* Fall through. */
- default:
- if (yyres)
- yyres[yyn] = *yyp;
- yyn++;
- break;
-
- case '"':
- if (yyres)
- yyres[yyn] = '\0';
- return yyn;
- }
- do_not_strip_quotes: ;
- }
-
- if (! yyres)
- return yystrlen (yystr);
-
- return yystpcpy (yyres, yystr) - yyres;
-}
-# endif
-
-/* Copy into YYRESULT an error message about the unexpected token
- YYCHAR while in state YYSTATE. Return the number of bytes copied,
- including the terminating null byte. If YYRESULT is null, do not
- copy anything; just return the number of bytes that would be
- copied. As a special case, return 0 if an ordinary "syntax error"
- message will do. Return YYSIZE_MAXIMUM if overflow occurs during
- size calculation. */
-static YYSIZE_T
-yysyntax_error (char *yyresult, int yystate, int yychar)
-{
- int yyn = yypact[yystate];
-
- if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
- return 0;
- else
- {
- int yytype = YYTRANSLATE (yychar);
- YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
- YYSIZE_T yysize = yysize0;
- YYSIZE_T yysize1;
- int yysize_overflow = 0;
- enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
- char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
- int yyx;
-
-# if 0
- /* This is so xgettext sees the translatable formats that are
- constructed on the fly. */
- YY_("syntax error, unexpected %s");
- YY_("syntax error, unexpected %s, expecting %s");
- YY_("syntax error, unexpected %s, expecting %s or %s");
- YY_("syntax error, unexpected %s, expecting %s or %s or %s");
- YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
-# endif
- char *yyfmt;
- char const *yyf;
- static char const yyunexpected[] = "syntax error, unexpected %s";
- static char const yyexpecting[] = ", expecting %s";
- static char const yyor[] = " or %s";
- char yyformat[sizeof yyunexpected
- + sizeof yyexpecting - 1
- + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
- * (sizeof yyor - 1))];
- char const *yyprefix = yyexpecting;
-
- /* Start YYX at -YYN if negative to avoid negative indexes in
- YYCHECK. */
- int yyxbegin = yyn < 0 ? -yyn : 0;
-
- /* Stay within bounds of both yycheck and yytname. */
- int yychecklim = YYLAST - yyn + 1;
- int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
- int yycount = 1;
-
- yyarg[0] = yytname[yytype];
- yyfmt = yystpcpy (yyformat, yyunexpected);
-
- for (yyx = yyxbegin; yyx < yyxend; ++yyx)
- if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
- {
- if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
- {
- yycount = 1;
- yysize = yysize0;
- yyformat[sizeof yyunexpected - 1] = '\0';
- break;
- }
- yyarg[yycount++] = yytname[yyx];
- yysize1 = yysize + yytnamerr (0, yytname[yyx]);
- yysize_overflow |= (yysize1 < yysize);
- yysize = yysize1;
- yyfmt = yystpcpy (yyfmt, yyprefix);
- yyprefix = yyor;
- }
-
- yyf = YY_(yyformat);
- yysize1 = yysize + yystrlen (yyf);
- yysize_overflow |= (yysize1 < yysize);
- yysize = yysize1;
-
- if (yysize_overflow)
- return YYSIZE_MAXIMUM;
-
- if (yyresult)
- {
- /* Avoid sprintf, as that infringes on the user's name space.
- Don't have undefined behavior even if the translation
- produced a string with the wrong number of "%s"s. */
- char *yyp = yyresult;
- int yyi = 0;
- while ((*yyp = *yyf) != '\0')
- {
- if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
- {
- yyp += yytnamerr (yyp, yyarg[yyi++]);
- yyf += 2;
- }
- else
- {
- yyp++;
- yyf++;
- }
- }
- }
- return yysize;
- }
-}
-#endif /* YYERROR_VERBOSE */
-
-
-/*-----------------------------------------------.
-| Release the memory associated to this symbol. |
-`-----------------------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
-#else
-static void
-yydestruct (yymsg, yytype, yyvaluep)
- const char *yymsg;
- int yytype;
- YYSTYPE *yyvaluep;
-#endif
-{
- YYUSE (yyvaluep);
-
- if (!yymsg)
- yymsg = "Deleting";
- YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
-
- switch (yytype)
- {
-
- default:
- break;
- }
-}
-
-/* Prevent warnings from -Wmissing-prototypes. */
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void *YYPARSE_PARAM);
-#else
-int yyparse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void);
-#else
-int yyparse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
-
-
-/* The lookahead symbol. */
-int yychar;
-
-/* The semantic value of the lookahead symbol. */
-YYSTYPE yylval;
-
-/* Number of syntax errors so far. */
-int yynerrs;
-
-
-
-/*-------------------------.
-| yyparse or yypush_parse. |
-`-------------------------*/
-
-#ifdef YYPARSE_PARAM
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void *YYPARSE_PARAM)
-#else
-int
-yyparse (YYPARSE_PARAM)
- void *YYPARSE_PARAM;
-#endif
-#else /* ! YYPARSE_PARAM */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void)
-#else
-int
-yyparse ()
-
-#endif
-#endif
-{
-
-
- int yystate;
- /* Number of tokens to shift before error messages enabled. */
- int yyerrstatus;
-
- /* The stacks and their tools:
- `yyss': related to states.
- `yyvs': related to semantic values.
-
- Refer to the stacks thru separate pointers, to allow yyoverflow
- to reallocate them elsewhere. */
-
- /* The state stack. */
- yytype_int16 yyssa[YYINITDEPTH];
- yytype_int16 *yyss;
- yytype_int16 *yyssp;
-
- /* The semantic value stack. */
- YYSTYPE yyvsa[YYINITDEPTH];
- YYSTYPE *yyvs;
- YYSTYPE *yyvsp;
-
- YYSIZE_T yystacksize;
-
- int yyn;
- int yyresult;
- /* Lookahead token as an internal (translated) token number. */
- int yytoken;
- /* The variables used to return semantic value and location from the
- action routines. */
- YYSTYPE yyval;
-
-#if YYERROR_VERBOSE
- /* Buffer for error messages, and its allocated size. */
- char yymsgbuf[128];
- char *yymsg = yymsgbuf;
- YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
-#endif
-
-#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
-
- /* The number of symbols on the RHS of the reduced rule.
- Keep to zero when no symbol should be popped. */
- int yylen = 0;
-
- yytoken = 0;
- yyss = yyssa;
- yyvs = yyvsa;
- yystacksize = YYINITDEPTH;
-
- YYDPRINTF ((stderr, "Starting parse\n"));
-
- yystate = 0;
- yyerrstatus = 0;
- yynerrs = 0;
- yychar = YYEMPTY; /* Cause a token to be read. */
-
- /* Initialize stack pointers.
- Waste one element of value and location stack
- so that they stay on the same level as the state stack.
- The wasted elements are never initialized. */
- yyssp = yyss;
- yyvsp = yyvs;
-
- goto yysetstate;
-
-/*------------------------------------------------------------.
-| yynewstate -- Push a new state, which is found in yystate. |
-`------------------------------------------------------------*/
- yynewstate:
- /* In all cases, when you get here, the value and location stacks
- have just been pushed. So pushing a state here evens the stacks. */
- yyssp++;
-
- yysetstate:
- *yyssp = yystate;
-
- if (yyss + yystacksize - 1 <= yyssp)
- {
- /* Get the current used size of the three stacks, in elements. */
- YYSIZE_T yysize = yyssp - yyss + 1;
-
-#ifdef yyoverflow
- {
- /* Give user a chance to reallocate the stack. Use copies of
- these so that the &'s don't force the real ones into
- memory. */
- YYSTYPE *yyvs1 = yyvs;
- yytype_int16 *yyss1 = yyss;
-
- /* Each stack pointer address is followed by the size of the
- data in use in that stack, in bytes. This used to be a
- conditional around just the two extra args, but that might
- be undefined if yyoverflow is a macro. */
- yyoverflow (YY_("memory exhausted"),
- &yyss1, yysize * sizeof (*yyssp),
- &yyvs1, yysize * sizeof (*yyvsp),
- &yystacksize);
-
- yyss = yyss1;
- yyvs = yyvs1;
- }
-#else /* no yyoverflow */
-# ifndef YYSTACK_RELOCATE
- goto yyexhaustedlab;
-# else
- /* Extend the stack our own way. */
- if (YYMAXDEPTH <= yystacksize)
- goto yyexhaustedlab;
- yystacksize *= 2;
- if (YYMAXDEPTH < yystacksize)
- yystacksize = YYMAXDEPTH;
-
- {
- yytype_int16 *yyss1 = yyss;
- union yyalloc *yyptr =
- (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
- if (! yyptr)
- goto yyexhaustedlab;
- YYSTACK_RELOCATE (yyss_alloc, yyss);
- YYSTACK_RELOCATE (yyvs_alloc, yyvs);
-# undef YYSTACK_RELOCATE
- if (yyss1 != yyssa)
- YYSTACK_FREE (yyss1);
- }
-# endif
-#endif /* no yyoverflow */
-
- yyssp = yyss + yysize - 1;
- yyvsp = yyvs + yysize - 1;
-
- YYDPRINTF ((stderr, "Stack size increased to %lu\n",
- (unsigned long int) yystacksize));
-
- if (yyss + yystacksize - 1 <= yyssp)
- YYABORT;
- }
-
- YYDPRINTF ((stderr, "Entering state %d\n", yystate));
-
- if (yystate == YYFINAL)
- YYACCEPT;
-
- goto yybackup;
-
-/*-----------.
-| yybackup. |
-`-----------*/
-yybackup:
-
- /* Do appropriate processing given the current state. Read a
- lookahead token if we need one and don't already have one. */
-
- /* First try to decide what to do without reference to lookahead token. */
- yyn = yypact[yystate];
- if (yyn == YYPACT_NINF)
- goto yydefault;
-
- /* Not known => get a lookahead token if don't already have one. */
-
- /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
- if (yychar == YYEMPTY)
- {
- YYDPRINTF ((stderr, "Reading a token: "));
- yychar = YYLEX;
- }
-
- if (yychar <= YYEOF)
- {
- yychar = yytoken = YYEOF;
- YYDPRINTF ((stderr, "Now at end of input.\n"));
- }
- else
- {
- yytoken = YYTRANSLATE (yychar);
- YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
- }
-
- /* If the proper action on seeing token YYTOKEN is to reduce or to
- detect an error, take that action. */
- yyn += yytoken;
- if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
- goto yydefault;
- yyn = yytable[yyn];
- if (yyn <= 0)
- {
- if (yyn == 0 || yyn == YYTABLE_NINF)
- goto yyerrlab;
- yyn = -yyn;
- goto yyreduce;
- }
-
- /* Count tokens shifted since error; after three, turn off error
- status. */
- if (yyerrstatus)
- yyerrstatus--;
-
- /* Shift the lookahead token. */
- YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
-
- /* Discard the shifted token. */
- yychar = YYEMPTY;
-
- yystate = yyn;
- *++yyvsp = yylval;
-
- goto yynewstate;
-
-
-/*-----------------------------------------------------------.
-| yydefault -- do the default action for the current state. |
-`-----------------------------------------------------------*/
-yydefault:
- yyn = yydefact[yystate];
- if (yyn == 0)
- goto yyerrlab;
- goto yyreduce;
-
-
-/*-----------------------------.
-| yyreduce -- Do a reduction. |
-`-----------------------------*/
-yyreduce:
- /* yyn is the number of a rule to reduce with. */
- yylen = yyr2[yyn];
-
- /* If YYLEN is nonzero, implement the default value of the action:
- `$$ = $1'.
-
- Otherwise, the following line sets YYVAL to garbage.
- This behavior is undocumented and Bison
- users should not rely upon it. Assigning to YYVAL
- unconditionally makes the parser a bit smaller, and it avoids a
- GCC warning that YYVAL may be used uninitialized. */
- yyval = yyvsp[1-yylen];
-
-
- YY_REDUCE_PRINT (yyn);
- switch (yyn)
- {
- case 2:
-
-/* Line 1455 of yacc.c */
-#line 155 "menuy.y"
- { menus_root((yyvsp[(2) - (2)].men)); }
- break;
-
- case 3:
-
-/* Line 1455 of yacc.c */
-#line 156 "menuy.y"
- { menus_root((yyvsp[(1) - (1)].men)); }
- break;
-
- case 6:
-
-/* Line 1455 of yacc.c */
-#line 162 "menuy.y"
- { (yyval.num) = menus_version(atol((yyvsp[(2) - (5)].str)), atol((yyvsp[(3) - (5)].str)), atol((yyvsp[(4) - (5)].str))); }
- break;
-
- case 7:
-
-/* Line 1455 of yacc.c */
-#line 165 "menuy.y"
- { (yyval.men) = menus_chain_menus((yyvsp[(1) - (2)].men),(yyvsp[(2) - (2)].men)); }
- break;
-
- case 9:
-
-/* Line 1455 of yacc.c */
-#line 167 "menuy.y"
- { (yyval.men) = (yyvsp[(1) - (2)].men); }
- break;
-
- case 10:
-
-/* Line 1455 of yacc.c */
-#line 170 "menuy.y"
- { (yyval.men) = menus_create_2((yyvsp[(2) - (5)].str),(yyvsp[(4) - (5)].itm)); }
- break;
-
- case 11:
-
-/* Line 1455 of yacc.c */
-#line 173 "menuy.y"
- { (yyval.str) = strdup(yytext); }
- break;
-
- case 12:
-
-/* Line 1455 of yacc.c */
-#line 174 "menuy.y"
- { (yyval.str) = strdup(yytext); }
- break;
-
- case 13:
-
-/* Line 1455 of yacc.c */
-#line 177 "menuy.y"
- { (yyval.itm) = menus_chain_items((yyvsp[(1) - (2)].itm),(yyvsp[(2) - (2)].itm)); }
- break;
-
- case 15:
-
-/* Line 1455 of yacc.c */
-#line 182 "menuy.y"
- { (yyval.itm) = menus_create_6((yyvsp[(2) - (13)].flg),(yyvsp[(4) - (13)].flg),(yyvsp[(6) - (13)].str),(yyvsp[(8) - (13)].act),(yyvsp[(10) - (13)].str),(yyvsp[(12) - (13)].num)); }
- break;
-
- case 16:
-
-/* Line 1455 of yacc.c */
-#line 184 "menuy.y"
- { (yyval.itm) = menus_create_6((yyvsp[(2) - (9)].flg),(yyvsp[(4) - (9)].flg),(yyvsp[(6) - (9)].str),(yyvsp[(8) - (9)].act),"",1); }
- break;
-
- case 17:
-
-/* Line 1455 of yacc.c */
-#line 187 "menuy.y"
- { (yyval.flg) = new_flagNot((yyvsp[(2) - (2)].flg)); }
- break;
-
- case 18:
-
-/* Line 1455 of yacc.c */
-#line 188 "menuy.y"
- { (yyval.flg) = new_flagNone(); }
- break;
-
- case 19:
-
-/* Line 1455 of yacc.c */
-#line 189 "menuy.y"
- { (yyval.flg) = new_flagAll(); }
- break;
-
- case 20:
-
-/* Line 1455 of yacc.c */
-#line 190 "menuy.y"
- { (yyval.flg) = new_statusFlag(STATUS_UNKNOWN); }
- break;
-
- case 21:
-
-/* Line 1455 of yacc.c */
-#line 191 "menuy.y"
- { (yyval.flg) = new_statusFlag(STATUS_SUSPENDED); }
- break;
-
- case 22:
-
-/* Line 1455 of yacc.c */
-#line 192 "menuy.y"
- { (yyval.flg) = new_statusFlag(STATUS_COMPLETE); }
- break;
-
- case 23:
-
-/* Line 1455 of yacc.c */
-#line 193 "menuy.y"
- { (yyval.flg) = new_statusFlag(STATUS_QUEUED); }
- break;
-
- case 24:
-
-/* Line 1455 of yacc.c */
-#line 194 "menuy.y"
- { (yyval.flg) = new_statusFlag(STATUS_SUBMITTED); }
- break;
-
- case 25:
-
-/* Line 1455 of yacc.c */
-#line 195 "menuy.y"
- { (yyval.flg) = new_statusFlag(STATUS_ACTIVE); }
- break;
-
- case 26:
-
-/* Line 1455 of yacc.c */
-#line 196 "menuy.y"
- { (yyval.flg) = new_statusFlag(STATUS_ABORTED); }
- break;
-
- case 27:
-
-/* Line 1455 of yacc.c */
-#line 197 "menuy.y"
- { (yyval.flg) = new_eventFlag(0); }
- break;
-
- case 28:
-
-/* Line 1455 of yacc.c */
-#line 198 "menuy.y"
- { (yyval.flg) = new_eventFlag(1); }
- break;
-
- case 29:
-
-/* Line 1455 of yacc.c */
-#line 199 "menuy.y"
- { (yyval.flg) = new_statusFlag(STATUS_SHUTDOWN); }
- break;
-
- case 30:
-
-/* Line 1455 of yacc.c */
-#line 200 "menuy.y"
- { (yyval.flg) = new_statusFlag(STATUS_HALTED); }
- break;
-
- case 31:
-
-/* Line 1455 of yacc.c */
-#line 201 "menuy.y"
- { (yyval.flg) = new_typeFlag(NODE_SUPER) ; }
- break;
-
- case 32:
-
-/* Line 1455 of yacc.c */
-#line 202 "menuy.y"
- { (yyval.flg) = new_typeFlag(NODE_SUPER) ; }
- break;
-
- case 33:
-
-/* Line 1455 of yacc.c */
-#line 203 "menuy.y"
- { (yyval.flg) = new_typeFlag(NODE_SUITE) ; }
- break;
-
- case 34:
-
-/* Line 1455 of yacc.c */
-#line 204 "menuy.y"
- { (yyval.flg) = new_typeFlag(NODE_FAMILY) ; }
- break;
-
- case 35:
-
-/* Line 1455 of yacc.c */
-#line 205 "menuy.y"
- { (yyval.flg) = new_typeFlag(NODE_TASK) ; }
- break;
-
- case 36:
-
-/* Line 1455 of yacc.c */
-#line 206 "menuy.y"
- { (yyval.flg) = new_flagOr(new_flagOr(new_typeFlag(NODE_SUITE),new_typeFlag(NODE_FAMILY)),new_typeFlag(NODE_TASK)); }
- break;
-
- case 37:
-
-/* Line 1455 of yacc.c */
-#line 207 "menuy.y"
- { (yyval.flg) = new_typeFlag(NODE_EVENT) ; }
- break;
-
- case 38:
-
-/* Line 1455 of yacc.c */
-#line 208 "menuy.y"
- { (yyval.flg) = new_typeFlag(NODE_LABEL) ; }
- break;
-
- case 39:
-
-/* Line 1455 of yacc.c */
-#line 209 "menuy.y"
- { (yyval.flg) = new_typeFlag(NODE_METER) ; }
- break;
-
- case 40:
-
-/* Line 1455 of yacc.c */
-#line 210 "menuy.y"
- { (yyval.flg) = new_typeFlag(NODE_REPEAT) ; }
- break;
-
- case 41:
-
-/* Line 1455 of yacc.c */
-#line 211 "menuy.y"
- { (yyval.flg) = new_typeFlag(NODE_VARIABLE) ; }
- break;
-
- case 42:
-
-/* Line 1455 of yacc.c */
-#line 212 "menuy.y"
- { (yyval.flg) = new_typeFlag(NODE_TRIGGER) ; }
- break;
-
- case 43:
-
-/* Line 1455 of yacc.c */
-#line 213 "menuy.y"
- { (yyval.flg) = new_typeFlag(NODE_ALIAS) ; }
- break;
-
- case 44:
-
-/* Line 1455 of yacc.c */
-#line 214 "menuy.y"
- { (yyval.flg) = new_typeFlag(NODE_LIMIT) ; }
- break;
-
- case 45:
-
-/* Line 1455 of yacc.c */
-#line 215 "menuy.y"
- { (yyval.flg) = new_procFlag_node_hasTriggers(); }
- break;
-
- case 46:
-
-/* Line 1455 of yacc.c */
-#line 216 "menuy.y"
- { (yyval.flg) = new_procFlag_node_hasDate(); }
- break;
-
- case 47:
-
-/* Line 1455 of yacc.c */
-#line 217 "menuy.y"
- { (yyval.flg) = new_procFlag_node_hasTime(); }
- break;
-
- case 48:
-
-/* Line 1455 of yacc.c */
-#line 218 "menuy.y"
- { (yyval.flg) = new_procFlag_node_hasText(); }
- break;
-
- case 49:
-
-/* Line 1455 of yacc.c */
-#line 219 "menuy.y"
- { (yyval.flg) = new_procFlag_node_isZombie(); }
- break;
-
- case 50:
-
-/* Line 1455 of yacc.c */
-#line 220 "menuy.y"
- { (yyval.flg) = new_procFlag_node_isMigrated(); }
- break;
-
- case 51:
-
-/* Line 1455 of yacc.c */
-#line 221 "menuy.y"
- { (yyval.flg) = new_procFlag_node_isLocked(); }
- break;
-
- case 52:
-
-/* Line 1455 of yacc.c */
-#line 222 "menuy.y"
- { (yyval.flg) = new_userFlag(0); }
- break;
-
- case 53:
-
-/* Line 1455 of yacc.c */
-#line 223 "menuy.y"
- { (yyval.flg) = new_userFlag(1); }
- break;
-
- case 54:
-
-/* Line 1455 of yacc.c */
-#line 224 "menuy.y"
- { (yyval.flg) = new_userFlag(2); }
- break;
-
- case 55:
-
-/* Line 1455 of yacc.c */
-#line 225 "menuy.y"
- { (yyval.flg) = new_selectionFlag(); }
- break;
-
- case 56:
-
-/* Line 1455 of yacc.c */
-#line 226 "menuy.y"
- { (yyval.flg) = (yyvsp[(2) - (3)].flg); }
- break;
-
- case 57:
-
-/* Line 1455 of yacc.c */
-#line 229 "menuy.y"
- { (yyval.flg) = new_flagOr((yyvsp[(1) - (3)].flg),(yyvsp[(3) - (3)].flg)); }
- break;
-
- case 58:
-
-/* Line 1455 of yacc.c */
-#line 230 "menuy.y"
- { (yyval.flg) = new_flagAnd((yyvsp[(1) - (3)].flg),(yyvsp[(3) - (3)].flg)); }
- break;
-
- case 60:
-
-/* Line 1455 of yacc.c */
-#line 234 "menuy.y"
- { (yyval.str) = strdup(yytext); }
- break;
-
- case 61:
-
-/* Line 1455 of yacc.c */
-#line 237 "menuy.y"
- { (yyval.act) = menus_command(strdup(yytext)); }
- break;
-
- case 62:
-
-/* Line 1455 of yacc.c */
-#line 238 "menuy.y"
- { (yyval.act) = menus_separator(); }
- break;
-
- case 63:
-
-/* Line 1455 of yacc.c */
-#line 239 "menuy.y"
- { (yyval.act) = menus_sub_menu(); }
- break;
-
- case 64:
-
-/* Line 1455 of yacc.c */
-#line 240 "menuy.y"
- { (yyval.act) = menus_window((yyvsp[(3) - (4)].str)); }
- break;
-
- case 65:
-
-/* Line 1455 of yacc.c */
-#line 241 "menuy.y"
- { (yyval.act) = menus_internal_host_plug(); }
- break;
-
- case 66:
-
-/* Line 1455 of yacc.c */
-#line 242 "menuy.y"
- { (yyval.act) = menus_internal_host_comp((yyvsp[(3) - (6)].str), (yyvsp[(5) - (6)].str)); }
- break;
-
- case 67:
-
-/* Line 1455 of yacc.c */
-#line 245 "menuy.y"
- { (yyval.str) = strdup(yytext); }
- break;
-
- case 68:
-
-/* Line 1455 of yacc.c */
-#line 248 "menuy.y"
- { (yyval.num) = 1; }
- break;
-
- case 69:
-
-/* Line 1455 of yacc.c */
-#line 249 "menuy.y"
- { (yyval.num) = 0; }
- break;
-
- case 74:
-
-/* Line 1455 of yacc.c */
-#line 262 "menuy.y"
- { if(yyone) return 0; }
- break;
-
- case 76:
-
-/* Line 1455 of yacc.c */
-#line 264 "menuy.y"
- { /* extern int yylineno; printf("error line %d [%s]\n",yylineno, yytext); */ }
- break;
-
- case 77:
-
-/* Line 1455 of yacc.c */
-#line 268 "menuy.y"
- {
- (yyval.dti).date = ((yyvsp[(11) - (12)].num) * 10000 + (yyvsp[(9) - (12)].num) * 100 + (yyvsp[(7) - (12)].num));
- (yyval.dti).time = ((yyvsp[(2) - (12)].num) * 10000 + (yyvsp[(4) - (12)].num) * 100 + (yyvsp[(6) - (12)].num));
- }
- break;
-
- case 78:
-
-/* Line 1455 of yacc.c */
-#line 274 "menuy.y"
- { log_event_status_event(&(yyvsp[(1) - (3)].dti),(yyvsp[(3) - (3)].nod),STATUS_COMPLETE); }
- break;
-
- case 79:
-
-/* Line 1455 of yacc.c */
-#line 275 "menuy.y"
- { log_event_status_event(&(yyvsp[(1) - (3)].dti),(yyvsp[(3) - (3)].nod),STATUS_QUEUED); }
- break;
-
- case 80:
-
-/* Line 1455 of yacc.c */
-#line 276 "menuy.y"
- { log_event_status_event(&(yyvsp[(1) - (3)].dti),(yyvsp[(3) - (3)].nod),STATUS_ACTIVE); }
- break;
-
- case 81:
-
-/* Line 1455 of yacc.c */
-#line 278 "menuy.y"
- { log_event_status_event(&(yyvsp[(1) - (4)].dti),(yyvsp[(3) - (4)].nod),STATUS_SUBMITTED); }
- break;
-
- case 82:
-
-/* Line 1455 of yacc.c */
-#line 280 "menuy.y"
- { log_event_status_event(&(yyvsp[(1) - (3)].dti),(yyvsp[(3) - (3)].nod),STATUS_SUBMITTED); }
- break;
-
- case 83:
-
-/* Line 1455 of yacc.c */
-#line 281 "menuy.y"
- { log_event_status_event(&(yyvsp[(1) - (3)].dti),(yyvsp[(3) - (3)].nod),STATUS_ABORTED);}
- break;
-
- case 84:
-
-/* Line 1455 of yacc.c */
-#line 282 "menuy.y"
- { log_event_status_event(&(yyvsp[(1) - (3)].dti),(yyvsp[(3) - (3)].nod),STATUS_UNKNOWN);}
- break;
-
- case 85:
-
-/* Line 1455 of yacc.c */
-#line 283 "menuy.y"
- { log_event_event_event(&(yyvsp[(1) - (3)].dti),(yyvsp[(3) - (3)].nod),1); }
- break;
-
- case 86:
-
-/* Line 1455 of yacc.c */
-#line 284 "menuy.y"
- { log_event_event_event(&(yyvsp[(1) - (3)].dti),(yyvsp[(3) - (3)].nod),0); }
- break;
-
- case 87:
-
-/* Line 1455 of yacc.c */
-#line 285 "menuy.y"
- { log_event_meter_event(&(yyvsp[(1) - (7)].dti),(yyvsp[(6) - (7)].nod),(yyvsp[(5) - (7)].num)); }
- break;
-
- case 90:
-
-/* Line 1455 of yacc.c */
-#line 292 "menuy.y"
- { (yyval.nod) = log_event_find(yytext); }
- break;
-
- case 91:
-
-/* Line 1455 of yacc.c */
-#line 295 "menuy.y"
- { (yyval.num) = atol(yytext); }
- break;
-
-
-
-/* Line 1455 of yacc.c */
-#line 2185 "y.tab.c"
- default: break;
- }
- YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
-
- YYPOPSTACK (yylen);
- yylen = 0;
- YY_STACK_PRINT (yyss, yyssp);
-
- *++yyvsp = yyval;
-
- /* Now `shift' the result of the reduction. Determine what state
- that goes to, based on the state we popped back to and the rule
- number reduced by. */
-
- yyn = yyr1[yyn];
-
- yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
- if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
- yystate = yytable[yystate];
- else
- yystate = yydefgoto[yyn - YYNTOKENS];
-
- goto yynewstate;
-
-
-/*------------------------------------.
-| yyerrlab -- here on detecting error |
-`------------------------------------*/
-yyerrlab:
- /* If not already recovering from an error, report this error. */
- if (!yyerrstatus)
- {
- ++yynerrs;
-#if ! YYERROR_VERBOSE
- yyerror (YY_("syntax error"));
-#else
- {
- YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
- if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
- {
- YYSIZE_T yyalloc = 2 * yysize;
- if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
- yyalloc = YYSTACK_ALLOC_MAXIMUM;
- if (yymsg != yymsgbuf)
- YYSTACK_FREE (yymsg);
- yymsg = (char *) YYSTACK_ALLOC (yyalloc);
- if (yymsg)
- yymsg_alloc = yyalloc;
- else
- {
- yymsg = yymsgbuf;
- yymsg_alloc = sizeof yymsgbuf;
- }
- }
-
- if (0 < yysize && yysize <= yymsg_alloc)
- {
- (void) yysyntax_error (yymsg, yystate, yychar);
- yyerror (yymsg);
- }
- else
- {
- yyerror (YY_("syntax error"));
- if (yysize != 0)
- goto yyexhaustedlab;
- }
- }
-#endif
- }
-
-
-
- if (yyerrstatus == 3)
- {
- /* If just tried and failed to reuse lookahead token after an
- error, discard it. */
-
- if (yychar <= YYEOF)
- {
- /* Return failure if at end of input. */
- if (yychar == YYEOF)
- YYABORT;
- }
- else
- {
- yydestruct ("Error: discarding",
- yytoken, &yylval);
- yychar = YYEMPTY;
- }
- }
-
- /* Else will try to reuse lookahead token after shifting the error
- token. */
- goto yyerrlab1;
-
-
-/*---------------------------------------------------.
-| yyerrorlab -- error raised explicitly by YYERROR. |
-`---------------------------------------------------*/
-yyerrorlab:
-
- /* Pacify compilers like GCC when the user code never invokes
- YYERROR and the label yyerrorlab therefore never appears in user
- code. */
- if (/*CONSTCOND*/ 0)
- goto yyerrorlab;
-
- /* Do not reclaim the symbols of the rule which action triggered
- this YYERROR. */
- YYPOPSTACK (yylen);
- yylen = 0;
- YY_STACK_PRINT (yyss, yyssp);
- yystate = *yyssp;
- goto yyerrlab1;
-
-
-/*-------------------------------------------------------------.
-| yyerrlab1 -- common code for both syntax error and YYERROR. |
-`-------------------------------------------------------------*/
-yyerrlab1:
- yyerrstatus = 3; /* Each real token shifted decrements this. */
-
- for (;;)
- {
- yyn = yypact[yystate];
- if (yyn != YYPACT_NINF)
- {
- yyn += YYTERROR;
- if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
- {
- yyn = yytable[yyn];
- if (0 < yyn)
- break;
- }
- }
-
- /* Pop the current state because it cannot handle the error token. */
- if (yyssp == yyss)
- YYABORT;
-
-
- yydestruct ("Error: popping",
- yystos[yystate], yyvsp);
- YYPOPSTACK (1);
- yystate = *yyssp;
- YY_STACK_PRINT (yyss, yyssp);
- }
-
- *++yyvsp = yylval;
-
-
- /* Shift the error token. */
- YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
-
- yystate = yyn;
- goto yynewstate;
-
-
-/*-------------------------------------.
-| yyacceptlab -- YYACCEPT comes here. |
-`-------------------------------------*/
-yyacceptlab:
- yyresult = 0;
- goto yyreturn;
-
-/*-----------------------------------.
-| yyabortlab -- YYABORT comes here. |
-`-----------------------------------*/
-yyabortlab:
- yyresult = 1;
- goto yyreturn;
-
-#if !defined(yyoverflow) || YYERROR_VERBOSE
-/*-------------------------------------------------.
-| yyexhaustedlab -- memory exhaustion comes here. |
-`-------------------------------------------------*/
-yyexhaustedlab:
- yyerror (YY_("memory exhausted"));
- yyresult = 2;
- /* Fall through. */
-#endif
-
-yyreturn:
- if (yychar != YYEMPTY)
- yydestruct ("Cleanup: discarding lookahead",
- yytoken, &yylval);
- /* Do not reclaim the symbols of the rule which action triggered
- this YYABORT or YYACCEPT. */
- YYPOPSTACK (yylen);
- YY_STACK_PRINT (yyss, yyssp);
- while (yyssp != yyss)
- {
- yydestruct ("Cleanup: popping",
- yystos[*yyssp], yyvsp);
- YYPOPSTACK (1);
- }
-#ifndef yyoverflow
- if (yyss != yyssa)
- YYSTACK_FREE (yyss);
-#endif
-#if YYERROR_VERBOSE
- if (yymsg != yymsgbuf)
- YYSTACK_FREE (yymsg);
-#endif
- /* Make sure YYID is used. */
- return YYID (yyresult);
-}
-
-
-
-/* Line 1675 of yacc.c */
-#line 298 "menuy.y"
-
-
-#include "menul.c"
-
-int yywrap() {
- return 1;
-}
-
-#ifdef AIX
-int yyerror(char * msg)
-#else
-void yyerror(char * msg)
-#endif
-{
- /* printf("!menu parsing issue?\n");
- printf("%s line %d last token <%s>\n",msg,yylineno,yytext); */
- if (!strncmp("MSG:", yytext, 4)) {}
- else if (!strncmp("DBG:", yytext, 4)) {}
- else if (!strncmp("ERR:", yytext, 4)) {}
- else if (!strncmp("WAR:", yytext, 4)) {}
- else if (!strncmp("try-no:", yytext, 6)) {}
- else if (!strncmp("File", yytext, 4)) {}
- else if (!strncmp("Variable", yytext, 8)) {}
- else if (!strncmp("Directory", yytext, 9)) {}
- else if (!strncmp("Search", yytext, 6)) {}
- else if (*yytext == '[') {}
- else if (*yytext == ':') {}
- else if (*yytext == '/') {}
- else printf("!%s:%d:<%s>\n",msg,yylineno,yytext);
-}
-
-
diff --git a/ecflow_4_0_7/view/src/menuy.y b/ecflow_4_0_7/view/src/menuy.y
deleted file mode 100644
index f460398..0000000
--- a/ecflow_4_0_7/view/src/menuy.y
+++ /dev/null
@@ -1,328 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #17 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-%{
-#include "lexyacc.h"
-#include "ecflow.h"
-int yyone = 0;
-extern int yylineno;
-
-#ifdef __cplusplus
- void yylex(void);
-#endif
-
-#if defined(_AIX)
- extern char yytext[];
- int yydebug;
-#elif defined(hpux)
- void yyerror(char * msg);
- int yydebug;
-#elif defined(YYBISON)
- extern char yytext[]; /* ARRAY */
- void yyerror(char * msg);
- int yydebug;
-#elif defined (linux)
- extern char yytext[];
- void yyerror(char * msg);
- int yydebug;
-#elif defined(alpha) || defined(SGI)
- extern char yytext[]; /* ARRAY */
-#elif defined(SVR4)
- extern char yytext[]; /* ARRAY */
-#elif defined(alpha)
- extern unsigned char yytext[];
-#else
- extern char yytext[];
- void yyerror(char * msg);
- int yydebug;
-#endif
-%}
-
-%token VERSION
-%token MENU
-%token IDENT
-%token NONE
-%token ALL
-%token UNKNOWN
-%token SUSPENDED
-%token COMPLETE
-%token QUEUED
-%token SUBMITTED
-%token ACTIVE
-%token ABORTED
-%token CLEAR
-%token SET
-%token SHUTDOWN
-%token HALTED
-%token LOCKED
-%token MIGRATED
-%token SELECTION
-
-%token SERVER
-%token SMS
-%token NODE
-%token SUITE
-%token FAMILY
-%token TASK
-%token EVENT
-%token LABEL
-%token METER
-%token REPEAT
-%token VARIABLE
-%token TRIGGER
-%token LIMIT
-%token ALIAS
-
-%token HAS_TRIGGERS
-%token HAS_TIME
-%token HAS_DATE
-%token HAS_TEXT
-
-%token IS_ZOMBIE
-
-%token SEPARATOR
-%token STRING
-%token DEFAULT_YES
-%token DEFAULT_NO
-
-%token WINDOW
-%token PLUG
-%token COMP
-
-%token USER
-%token OPER
-%token ADMIN
-
-
-%token NUMBER
-%token JUNK
-%token EOL
-%token NODE_NAME
-%token CANCEL
-%token ANY
-
-%type<flg> flags;
-%type<flg> flag;
-
-%type<str> question;
-%type<str> title;
-%type<act> action;
-%type<str> name;
-%type<num> answer;
-%type<num> version;
-
-%type<itm> menu_items;
-%type<itm> menu_item;
-
-%type<men> menu;
-%type<men> menus;
-
-%type<nod> node_name;
-%type<num> number;
-
-%type<dti> date;
-
-
-%start first
-
-%union {
- char *str;
- long num;
- flags *flg;
- item *itm;
- menu *men;
- action *act;
- node* nod;
- double dbl;
- DateTime dti;
-};
-
-
-%%
-
-first : version menus { menus_root($2); }
- | menus { menus_root($1); }
- | junk
- | logfile
- ;
-
-version : VERSION name name name ';'
- { $$ = menus_version(atol($2), atol($3), atol($4)); }
- ;
-
-menus : menu menus { $$ = menus_chain_menus($1,$2); }
- | menu
- | menu error { $$ = $1; }
- ;
-
-menu : MENU name '{' menu_items '}' { $$ = menus_create_2($2,$4); }
- ;
-
-name : IDENT { $$ = strdup(yytext); }
- | STRING { $$ = strdup(yytext); }
- ;
-
-menu_items : menu_item menu_items { $$ = menus_chain_items($1,$2); }
- | menu_item
- ;
-
-menu_item : '(' flags ',' flags ',' title ',' action ',' question ',' answer ')'
- { $$ = menus_create_6($2,$4,$6,$8,$10,$12); }
- | '(' flags ',' flags ',' title ',' action ')'
- { $$ = menus_create_6($2,$4,$6,$8,"",1); }
- ;
-
-flag : '~' flag { $$ = new_flagNot($2); }
- | NONE { $$ = new_flagNone(); }
- | ALL { $$ = new_flagAll(); }
- | UNKNOWN { $$ = new_statusFlag(STATUS_UNKNOWN); }
- | SUSPENDED { $$ = new_statusFlag(STATUS_SUSPENDED); }
- | COMPLETE { $$ = new_statusFlag(STATUS_COMPLETE); }
- | QUEUED { $$ = new_statusFlag(STATUS_QUEUED); }
- | SUBMITTED { $$ = new_statusFlag(STATUS_SUBMITTED); }
- | ACTIVE { $$ = new_statusFlag(STATUS_ACTIVE); }
- | ABORTED { $$ = new_statusFlag(STATUS_ABORTED); }
- | CLEAR { $$ = new_eventFlag(0); }
- | SET { $$ = new_eventFlag(1); }
- | SHUTDOWN { $$ = new_statusFlag(STATUS_SHUTDOWN); }
- | HALTED { $$ = new_statusFlag(STATUS_HALTED); }
- | SERVER { $$ = new_typeFlag(NODE_SUPER) ; }
- | SMS { $$ = new_typeFlag(NODE_SUPER) ; }
- | SUITE { $$ = new_typeFlag(NODE_SUITE) ; }
- | FAMILY { $$ = new_typeFlag(NODE_FAMILY) ; }
- | TASK { $$ = new_typeFlag(NODE_TASK) ; }
- | NODE { $$ = new_flagOr(new_flagOr(new_typeFlag(NODE_SUITE),new_typeFlag(NODE_FAMILY)),new_typeFlag(NODE_TASK)); }
- | EVENT { $$ = new_typeFlag(NODE_EVENT) ; }
- | LABEL { $$ = new_typeFlag(NODE_LABEL) ; }
- | METER { $$ = new_typeFlag(NODE_METER) ; }
- | REPEAT { $$ = new_typeFlag(NODE_REPEAT) ; }
- | VARIABLE { $$ = new_typeFlag(NODE_VARIABLE) ; }
- | TRIGGER { $$ = new_typeFlag(NODE_TRIGGER) ; }
- | ALIAS { $$ = new_typeFlag(NODE_ALIAS) ; }
- | LIMIT { $$ = new_typeFlag(NODE_LIMIT) ; }
- | HAS_TRIGGERS { $$ = new_procFlag_node_hasTriggers(); }
- | HAS_DATE { $$ = new_procFlag_node_hasDate(); }
- | HAS_TIME { $$ = new_procFlag_node_hasTime(); }
- | HAS_TEXT { $$ = new_procFlag_node_hasText(); }
- | IS_ZOMBIE { $$ = new_procFlag_node_isZombie(); }
- | MIGRATED { $$ = new_procFlag_node_isMigrated(); }
- | LOCKED { $$ = new_procFlag_node_isLocked(); }
- | USER { $$ = new_userFlag(0); }
- | OPER { $$ = new_userFlag(1); }
- | ADMIN { $$ = new_userFlag(2); }
- | SELECTION { $$ = new_selectionFlag(); }
- | '(' flags ')' { $$ = $2; }
-;
-
-flags : flag '|' flags { $$ = new_flagOr($1,$3); }
- | flag '&' flags { $$ = new_flagAnd($1,$3); }
- | flag
- ;
-
-title : STRING { $$ = strdup(yytext); }
- ;
-
-action : STRING { $$ = menus_command(strdup(yytext)); }
- | SEPARATOR { $$ = menus_separator(); }
- | MENU { $$ = menus_sub_menu(); }
- | WINDOW '(' name ')' { $$ = menus_window($3); }
- | PLUG { $$ = menus_internal_host_plug(); }
- | COMP '(' name ',' name ')' { $$ = menus_internal_host_comp($3, $5); }
- ;
-
-question: STRING { $$ = strdup(yytext); }
- ;
-
-answer : DEFAULT_YES { $$ = 1; }
- | DEFAULT_NO { $$ = 0; }
- ;
-
-/*-------------------------------------------------------------*/
-
-logfile : loglines
- ;
-
-loglines: logline
- | loglines logline
- ;
-
-logline :
-| event number number { if(yyone) return 0; }
-| junk
-| error { /* extern int yylineno; printf("error line %d [%s]\n",yylineno, yytext); */ }
-;
-
-date : '[' number ':' number ':' number number '.' number '.' number ']'
- {
- $$.date = ($11 * 10000 + $9 * 100 + $7);
- $$.time = ($2 * 10000 + $4 * 100 + $6);
- }
- ;
-
-event : date COMPLETE node_name { log_event_status_event(&$1,$3,STATUS_COMPLETE); }
- | date QUEUED node_name { log_event_status_event(&$1,$3,STATUS_QUEUED); }
- | date ACTIVE node_name { log_event_status_event(&$1,$3,STATUS_ACTIVE); }
- | date SUBMITTED node_name ANY
- { log_event_status_event(&$1,$3,STATUS_SUBMITTED); }
- | date SUBMITTED node_name
- { log_event_status_event(&$1,$3,STATUS_SUBMITTED); }
- | date ABORTED node_name { log_event_status_event(&$1,$3,STATUS_ABORTED);}
- | date UNKNOWN node_name { log_event_status_event(&$1,$3,STATUS_UNKNOWN);}
- | date SET node_name { log_event_event_event(&$1,$3,1); }
- | date CLEAR node_name { log_event_event_event(&$1,$3,0); }
- | date METER '[' node_name number node_name ']' { log_event_meter_event(&$1,$6,$5); }
-;
-
-junk : date JUNK
- | JUNK
- ;
-
-node_name : NODE_NAME { $$ = log_event_find(yytext); }
- ;
-
-number : NUMBER { $$ = atol(yytext); }
- ;
-
-%%
-
-#include "menul.c"
-
-int yywrap() {
- return 1;
-}
-
-#ifdef AIX
-int yyerror(char * msg)
-#else
-void yyerror(char * msg)
-#endif
-{
- /* printf("!menu parsing issue?\n");
- printf("%s line %d last token <%s>\n",msg,yylineno,yytext); */
- if (!strncmp("MSG:", yytext, 4)) {}
- else if (!strncmp("DBG:", yytext, 4)) {}
- else if (!strncmp("ERR:", yytext, 4)) {}
- else if (!strncmp("WAR:", yytext, 4)) {}
- else if (!strncmp("try-no:", yytext, 6)) {}
- else if (!strncmp("File", yytext, 4)) {}
- else if (!strncmp("Variable", yytext, 8)) {}
- else if (!strncmp("Directory", yytext, 9)) {}
- else if (!strncmp("Search", yytext, 6)) {}
- else if (*yytext == '[') {}
- else if (*yytext == ':') {}
- else if (*yytext == '/') {}
- else printf("!%s:%d:<%s>\n",msg,yylineno,yytext);
-}
-
diff --git a/ecflow_4_0_7/view/src/messages.cc b/ecflow_4_0_7/view/src/messages.cc
deleted file mode 100644
index 7ecbb66..0000000
--- a/ecflow_4_0_7/view/src/messages.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "messages.h"
-#include "node.h"
-#include "host.h"
-#include "selection.h"
-#include "tmp_file.h"
-#include "Hyper.h"
-#include <stdio.h>
-extern "C" {
-#include "xec.h"
-}
-
-messages::messages(panel_window& w)
- :panel(w)
- ,text_window(false)
-{
-}
-
-messages::~messages()
-{
-}
-
-void messages::create (Widget parent, char *widget_name )
-{
- messages_form_c::create(parent,widget_name);
-}
-
-
-void messages::clear()
-{
- text_window::clear();
-}
-
-struct ml : public lister<ecf_list> {
- FILE* f_;
- void next(ecf_list& l) { if (f_) fprintf(f_,"%s\n",l.name().c_str()); }
-public:
- ml(FILE* f): f_(f) {}
-};
-
-void messages::show(node& n)
-{
- tmp_file tmp(tmpnam(0));
- FILE *f = fopen(tmp.c_str(),"w");
- if(!f) { return; }
-
- const std::vector<std::string>& l = n.messages();
- std::vector<std::string>::const_iterator it = l.begin();
-
- while (it != l.end()) {
- fprintf(f, "%s\n", it->c_str());
- ++it;
- }
- fclose(f);
-
- load(tmp);
-}
-
-Boolean messages::enabled(node& n)
-{
- return n.hasMessages();
-}
-
-// static panel_maker<messages> maker(PANEL_MESSAGES);
diff --git a/ecflow_4_0_7/view/src/messages.h b/ecflow_4_0_7/view/src/messages.h
deleted file mode 100644
index b6d7237..0000000
--- a/ecflow_4_0_7/view/src/messages.h
+++ /dev/null
@@ -1,68 +0,0 @@
-#ifndef messages_H
-#define messages_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "uimessages.h"
-
-#ifndef panel_H
-#include "panel.h"
-#endif
-
-#ifndef text_window_H
-#include "text_window.h"
-#endif
-
-//
-
-class messages : public panel, public messages_form_c, public text_window {
-public:
-
- messages(panel_window&);
-
- ~messages(); // Change to virtual if base class
-
- virtual const char* name() const { return "Messages"; }
- virtual void show(node&);
- virtual void clear();
- virtual Widget widget() { return messages_form_c::xd_rootwidget(); }
- virtual Boolean enabled(node&);
-
- virtual Widget tools() { return tools_; }
- virtual Widget text() { return text_; }
- virtual void create (Widget parent, char *widget_name = 0 );
-
-
-
-private:
-
- messages(const messages&);
- messages& operator=(const messages&);
-
- virtual void externalCB(Widget ,XtPointer )
- { text_window::open_viewer();}
-
- virtual void searchCB(Widget ,XtPointer )
- { text_window::open_search();}
-
- virtual bool can_print() { return true; }
- virtual bool can_save() { return true; }
- virtual void print() { text_window::print(); }
- virtual void save() { text_window::save(); }
-};
-
-inline void destroy(messages**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/meter_node.cc b/ecflow_4_0_7/view/src/meter_node.cc
deleted file mode 100644
index d60b3bc..0000000
--- a/ecflow_4_0_7/view/src/meter_node.cc
+++ /dev/null
@@ -1,160 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #22 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "show.h"
-#include "meter_node.h"
-#include "text_lister.h"
-#include "ecf_node.h"
-#include "ecflowview.h"
-#include "NodeAttr.hpp"
-
-#ifdef BRIDGE
-meter_node::meter_node(host& h,sms_node* n, char b)
- : node (h,n,b)
- , name_ (n ? n->name : "STEP")
-{}
-#endif
-
-meter_node::meter_node(host& h,ecf_node* n)
- : node (h,n)
- , name_ (n ? n->name() : "STEP")
-{
-}
-
-const Meter& meter_node::get() const {
- ecf_concrete_node<const Meter>* base =
- dynamic_cast<ecf_concrete_node<const Meter>*> (owner_);
- if (base) return *(base->get());
- if (parent() && parent()->__node__())
- return parent()->__node__()->get_meter(name_);
- return Meter::EMPTY();
-}
-
-xmstring meter_node::make_label_tree()
-{
- char buff[80], name[80];
- snprintf(name,80, " %s: ", name_.c_str());
- snprintf(buff,80, "%d", value());
- return xmstring(name,"bold") + xmstring(buff);
-}
-
-void meter_node::drawNode(Widget w,XRectangle* r,bool tree)
-{
- drawBackground(w,r,tree);
-
- XmString s = tree?labelTree():labelTrigger();
- XRectangle x = *r;
- int width,mark;
-
- x.x += (x.height - 10)/2;
- x.height = 10;
- x.width = 50;
-
- width = (float)x.width / (float)(maximum() - minimum())
- * (float)(value() - minimum());
-
- mark = (float)x.width / (float)(maximum() - minimum())
- * (float)(threshold() - minimum());
-
- XFillRectangles(XtDisplay(w),XtWindow(w),colorGC(0),&x,1);
-
- if (value() > threshold())
- XFillRectangle(XtDisplay(w),XtWindow(w),gui::colorGC(STATUS_MAX+1),x.x,x.y,width,x.height);
- else
- XFillRectangle(XtDisplay(w),XtWindow(w),gui::colorGC(STATUS_MAX),x.x,x.y,width,x.height);
-
- shadow(w,&x);
-
- if(mark < width)
- {
- x.width = mark;
- shadow(w,&x);
- }
-
- XmStringDraw(XtDisplay(w),XtWindow(w),
- smallfont(),
- s,
- blackGC(),
- r->x + 52,
- r->y,
- r->width - 52,
- XmALIGNMENT_CENTER, XmSTRING_DIRECTION_L_TO_R, NULL);
-
- node::update(-1,-1,-1);
-}
-
-void meter_node::sizeNode(Widget w,XRectangle* r,bool tree)
-{
- XmString s = tree?labelTree():labelTrigger();
- r->height = XmStringHeight(smallfont(),s);
- r->width = XmStringWidth(smallfont(),s) + 54 ;
- if(r->height<10) r->height = 10;
-}
-
-const char* meter_node::status_name() const
-{
- static char buf[10];
- sprintf(buf,"%d",value());
- return buf;
-}
-
-void meter_node::info(std::ostream& f)
-{
- node::info(f);
- f << "value : " << value() << "\n";
- f << "minimum : " << minimum() << "\n";
- f << "maximum : " << maximum() << "\n";
- f << "threshold: " << threshold() << "\n";
-}
-
-int meter_node::minimum()
-{
-#ifdef BRIDGE
- if (tree_) return ((sms_meter*) tree_)->min;
-#endif
- return get().min();
-}
-
-int meter_node::maximum()
-{
-#ifdef BRIDGE
- if (tree_) return ((sms_meter*) tree_)->max;
-#endif
- return get().max();
-}
-
-int meter_node::value() const
-{
-#ifdef BRIDGE
- if (tree_) return ((sms_meter*) tree_)-> status;
-#endif
- return get().value();
-}
-
-int meter_node::threshold()
-{
-#ifdef BRIDGE
- if (tree_) return ((sms_meter*) tree_)->color;
-#endif
- return get().colorChange();
-}
-
-void meter_node::perlify(FILE* f)
-{
-}
-
-Boolean meter_node::visible() const { return show::want(show::meter); }
-
-
diff --git a/ecflow_4_0_7/view/src/meter_node.h b/ecflow_4_0_7/view/src/meter_node.h
deleted file mode 100644
index 8f1d914..0000000
--- a/ecflow_4_0_7/view/src/meter_node.h
+++ /dev/null
@@ -1,59 +0,0 @@
-#ifndef meter_node_H
-#define meter_node_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #11 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#ifndef node_H
-#include "node.h"
-#endif
-
-
-class meter_node : public node {
-public:
-
- const std::string name_;
- meter_node(host& h,ecf_node* n);
-#ifdef BRIDGE
- meter_node(host& h,sms_node* n, char b);
-#endif
- int minimum();
- int maximum();
- int value() const;
- int threshold();
-
-protected:
-
- virtual void perlify(FILE*);
-
-private:
-
- meter_node(const meter_node&);
- meter_node& operator=(const meter_node&);
-
- virtual void info(std::ostream&);
- virtual void drawNode(Widget w,XRectangle* r,bool);
- virtual void sizeNode(Widget w,XRectangle* r,bool);
- virtual xmstring make_label_tree();
-
- virtual Boolean visible() const;
- virtual const char* status_name() const;
-
- const Meter& get() const;
-};
-
-inline void destroy(meter_node**) {}
-
-#endif
diff --git a/ecflow_4_0_7/view/src/node.cc b/ecflow_4_0_7/view/src/node.cc
deleted file mode 100644
index 7c90ee1..0000000
--- a/ecflow_4_0_7/view/src/node.cc
+++ /dev/null
@@ -1,1086 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #49 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "node.h"
-#include "gui.h"
-#include <Xm/ManagerP.h>
-#include <Xm/DrawP.h>
-#include <algorithm>
-#include <typeinfo>
-#include <Flag.hpp>
-
-#ifndef node_lister_H
-#include "node_lister.h"
-#endif
-
-#include "dummy_node.h"
-#include "variable_node.h"
-
-#ifndef ecf_node_
-#include "ecf_node.h"
-#endif
-
-#ifndef globals_H
-#include "globals.h"
-#endif
-
-#ifndef host_H
-#include "host.h"
-#endif
-
-#include "trigger_lister.h"
-#include "selection.h"
-#include "substitute.h"
-#include "relation.h"
-#include "str.h"
-#include "option.h"
-#include "array.h"
-#include <Suite.hpp>
-
-class node_data {
-
- xmstring labelTrigger_;
- array<node*> triggered_;
- array<node*> triggers_;
- array<node_info*> info_;
-
-public:
- node_data();
- ~node_data();
-
- const xmstring& labelTrigger() { return labelTrigger_; }
- void labelTrigger(const xmstring&);
-
- void add_triggered(node*,node*);
- void triggered(trigger_lister&);
-
- void add(node_info*);
- void remove(node_info*);
- void remove(const str& s) { remove(get(s)); }
- node_info* get(const str&);
-};
-
-
-node_data::node_data():
- labelTrigger_()
-{
-}
-
-node_data::~node_data()
-{
- labelTrigger(xmstring());
- for(int i = 0; i < info_.count(); i++)
- delete info_[i];
-}
-
-void node_data::add(node_info* n)
-{
- for(int i = 0; i < info_.count(); i++)
- {
- if(info_[i]->name() == n->name())
- {
- delete info_[i];
- info_[i] = n;
- return;
- }
- }
- info_.add(n);
-}
-
-void node_data::remove(node_info *n)
-{
- info_.remove(n);
-}
-
-node_info* node_data::get(const str& s)
-{
- for(int i = 0; i < info_.count(); i++)
- if(info_[i]->name() == s)
- return info_[i];
- return 0;
-}
-
-
-void node_data::labelTrigger(const xmstring& s)
-{
- labelTrigger_ = s;
-}
-
-void node_data::add_triggered(node* n,node* t)
-{
- triggered_.add(n);
- triggers_.add(t);
-}
-
-void node_data::triggered(trigger_lister& l)
-{
- for(int i = 0; i < triggered_.count(); i++)
- l.next_node(*triggered_[i],0,trigger_lister::normal,triggers_[i]);
-}
-
-int node::status() const
-{
-#ifdef BRIDGE
- if (tree_) return tree_->status;
-#endif
- return owner_ ? owner_->status() : STATUS_UNKNOWN;
-}
-
-node_data* node::get_node_data()
-{
- if(data_ == 0)
- data_ = new node_data();
- return data_;
-}
-
-template<class T>
-inline node* _node_of(T* n)
-{
- return n ? n->xnode() : 0x0;
-}
-
-node::node(host& h,ecf_node* owner)
- :
- xnode(this)
- ,type_(owner ? owner->type() : NODE_UNKNOWN)
- ,tree_(0) // BRIDGE
- ,next_(0)
- ,kids_(0)
- ,owner_(owner)
- ,host_(h)
- ,folded_(True)
- ,labelTree_()
- ,helper_(0)
- ,data_(0)
- ,triggered_(false)
-{
-}
-
-node::~node()
-{
- // std::cerr << "# node del: " << full_name() << std::endl;
- if (data_) delete data_;
- data_ = 0x0;
-}
-
-void node::reset()
-{
- if(data_)
- data_->labelTrigger(xmstring());
-
- labelTree_ = xmstring();
-
- if(kids_) kids_->reset();
- if(next_) next_->reset();
-
- redraw();
-}
-
-void node::scan(node* first,node *current)
-{
- node *n = current;
- if (n)
- if(n && n->name() != name()) {
- n = first;
- while(n && n->name() != name()) {
- n = n->next_;
- }
- }
-
- if(n) {
- adopt(n);
- if(kids_)
- kids_->scan(n->kids_,n->kids_);
- } else {
- create();
- if(kids_)
- kids_->scan(0,0);
- }
-
- if(next_)
- next_->scan(first,n);
-}
-
-void node::adopt(node* old)
-{
- folded_ = old->folded_;
- old->notify_adoption(this);
- notify_observers();
-}
-
-void node::create()
-{
-}
-
-#ifdef BRIDGE
-node_builder* node_builder::builders_[NODE_MAX] = { 0, };
-
-node* node::find(sms_node* n)
-{ return (node*) (n ? n->user_ptr : 0x0); }
-
-node::node(host& h,sms_node* owner,char b)
- : xnode(this)
- , type_(owner ? owner->type : NODE_UNKNOWN)
- , name_ (owner->name ? owner->name : "/")
- , full_name_ (sms_node_full_name(owner))
- , tree_(owner)
- , next_(0)
- , kids_(0)
- , owner_(new ecf_concrete_node<node>((int)0, 0))
- , host_(h)
- , folded_(True)
- , labelTree_()
- , helper_(0)
- , data_(0)
- , triggered_(false)
-{
- if (owner) {
- // if (owner->name) name_ = owner->name;
- kids_ = node::create(h,owner->kids,b);
- next_ = node::create(h,owner->next,b);
- owner->user_ptr = this;
- }
-}
-
-node* node_builder::build(host& h,sms_node* n,char b)
-{
- if(n->type >= 0 &&
- n->type < NODE_MAX && builders_[n->type] != 0) {
- if (builders_[n->type] != 0x0)
- return builders_[n->type]->make(h,n,b);
- else
- std::cerr << "unregistered type " << n->type << "\n";
- }
- return 0;
-}
-
-node* node::create(host& h, sms_node* n, char b)
-{
- if(!n) return 0x0;
- node* p = node_builder::build(h,n,b);
- return p?p:node::create(h,n->next,b);
-}
-
-void node::schanged(sms_node *n,int oldstatus,int oldtryno,int oldflags,void*)
-{
- node* p = 0x0;
- if (n) p = (node*) n->user_ptr;
- if(p) {
- try {
- p->update(oldstatus,oldtryno,oldflags);
- p->notify_observers();
- p->redraw();
- } catch (...) {
- printf(" exception in node::changed\n");
- }
- } else {
- if (n->type >= NODE_MAX) return;
- printf("# Got NID for %s",::ecf_node_name(n->type));
- // while(n) {printf("# %s",n->full_name().c_str()); n = n->parent; }
- printf("# --- \n");
- }
-}
-
-#endif
-
-void node::destroy(node* n)
-{
- while(n) {
- Widget w = n->widget();
- node* next = n->next_;
- CompositeWidget c = (CompositeWidget)w;
- if (c) XtUnmanageChildren(c->composite.children,
- c->composite.num_children);
-
- destroy(n->kids_);
- n->kids_ = 0x0;
- if (n->owner_)
- n->owner_->adopt(0x0);
-
- delete n;
- n = next;
- }
- // n = 0x0;
-}
-
-void node::drawBackground(Widget w,XRectangle* r,bool tree)
-{
- if(!tree)
- XClearArea(XtDisplay(w),XtWindow(w),
- r->x,r->y,r->width,r->height,False);
-}
-
-void node::drawNode(Widget w,XRectangle* r,bool tree)
-{
- drawBackground(w,r,tree);
-
- XmString s = tree ? labelTree() : labelTrigger();
- XmFontList f = smallfont();
-
- XmStringDraw(XtDisplay(w),XtWindow(w),
- f,
- s,
- blackGC(),
- r->x,
- r->y+2,
- r->width,
- XmALIGNMENT_CENTER, XmSTRING_DIRECTION_L_TO_R, r);
-}
-
-void node::sizeNode(Widget w,XRectangle* r,bool tree)
-{
- XmString s = tree ? labelTree() : labelTrigger();
- XmFontList f = smallfont();
- r->width = XmStringWidth(f,s) + 4;
- r->height = XmStringHeight(f,s) + 4;
-}
-
-void node::shadow(Widget w,XRectangle *r,bool out)
-{
- XmManagerWidget m = (XmManagerWidget)w;
- _XmDrawShadows(XtDisplay(w),XtWindow(w),
- m->manager.top_shadow_GC,
- m->manager.bottom_shadow_GC,
- r->x,
- r->y,
- r->width,
- r->height,
- 1,out?XmSHADOW_OUT:XmSHADOW_IN);
-}
-
-
-const xmstring& node::labelTree()
-{
- if(labelTree_ == 0)
- labelTree_ = make_label_tree();
- return labelTree_;
-}
-
-xmstring node::make_label_tree()
-{
- return xmstring(name().c_str());
-}
-
-const xmstring& node::labelTrigger()
-{
- node_data* d = get_node_data();
- if(d->labelTrigger() == 0)
- d->labelTrigger(make_label_trigger());
- return d->labelTrigger();
-}
-
-xmstring node::make_label_trigger()
-{
- return xmstring(full_name().c_str());
-}
-
-void node::append(node* n)
-{
- if (!n) return;
- node *k = kids_;
- node *p = 0;
- while(k) {
- p = k;
- k = k->next_;
- }
- if(p) p->next_ = n;
- else kids_ = n;
-}
-
-void node::insert(node* n)
-{
- if (!n) return;
- node* k = kids_; kids_ = n; append(k);
-}
-
-void node::changed(ecf_node *n,int oldstatus,int oldtryno,int oldflags,void*)
-{
- node* p = _node_of(n);
- if (!n) return;
- if(p) {
- try {
- p->update(oldstatus,oldtryno,oldflags);
- p->notify_observers();
- p->redraw();
- } catch (...) { printf(" exception in node::changed\n"); }
- } else {
-#ifdef BRIDGE
- if (n->type() >= NODE_MAX) return;
- printf("# Got NID for %s",::ecf_node_name(n->type()));
- while(n) {
- printf("# %s",n->full_name().c_str());
- n = n->parent();
- }
- printf("# --- \n");
-#endif
- }
-}
-
-void node::update(int,int,int)
-{
- labelTree_ = xmstring();
- if(data_) data_->labelTrigger(xmstring());
-}
-
-Boolean node::visible() const
-{
- return True;
-}
-
-int node::type() const {
- return type_;
-}
-
-Boolean node::show_it() const
-{
- return this == selection::current_node();
-}
-
-const std::string& node::name() const
-{
-#ifdef BRIDGE
- if (tree_) { return name_; }
-#endif
- if (owner_) return owner_->name();
- return ecf_node::no_owner();
-}
-
-const std::string& node::full_name() const
-{
-#ifdef BRIDGE
- if (tree_) { return full_name_; }
-#endif
- if (owner_) return owner_->full_name();
- return ecf_node::no_owner();
-}
-
-const std::string& node::net_name() const
-{
-#ifdef BRIDGE
- if (tree_) { static std::string fn = sms_node_full_name(tree_); return fn; }
-#endif
- if (owner_) return owner_->full_name();
- return ecf_node::no_owner();
-}
-
-Pixel node::color() const
-{
- return colors(STATUS_UNKNOWN);
-}
-
-
-void node::search(node_lister& s)
-{
- node *n = this;
- while(n) {
- s.next(*n);
- node* k = n->kids();
- if(k) k->search(s);
- n = n->next();
- }
-}
-
-std::string node::variable(const std::string& name, bool subsitute)
-{
- for (node* run = kids(); run; run = run->next())
- if (run->type() == NODE_VARIABLE && run->name() == name) {
- return ((variable_node*) run)->get_var(subsitute);
- }
-
- return ecf_node::none();
-}
-
-node* node::find(ecf_node* n)
-{
- return _node_of(n);
-}
-
-static node* finder(const std::string& name, const node* start) {
- node *n = const_cast<node*> (start);
- while (n) {
- if (n->type() == NODE_TRIGGER || n->type() == NODE_COMPLETE) {
- if (n->definition() == name)
- return n;
- else if (n->__node__()->name() == name)
- return n;
- else if (n->__node__()->toString() == name)
- return n;
- ecf_node *owner = n->__node__();
- if (owner) {
- ExpressionWrapper *exp = dynamic_cast<ecf_concrete_node<ExpressionWrapper>*> (owner)
- ->get();
- if (exp && exp->expression() == name)
- return n;
- }
- }
- node *k = 0;
- if ((k = finder(name, n->kids())))
- return k;
- n = n->next();
- }
- return 0;
-}
-
-node* node::find_trigger(const std::string& name) const
-{
- node* k = finder(name, this);
- return k ? k : &dummy_node::get(name);
-}
-
-node* node::find_limit(const std::string& path, const std::string& name)
-{
- node *f = this;
- // if (!strncmp("/", path.c_str(), 1))
- if (!path.empty() && path[0] == '/')
- if (! (f = serv().top()->find(path)))
- return &dummy_node::get(path + ":" + name);
-
- for (node *n = f->kids(); n != 0; n = n->next()) {
- if (n->type() == NODE_LIMIT && n->name() == name)
- return n;
- }
-
- for (node *p = f->parent()->kids(); p != 0; p = p->next()) {
- if (p->type() == NODE_FAMILY || p->type() == NODE_TASK || p->type() == NODE_SUITE)
- if (p->name() == path.substr(0, p->name().size())) {
- std::string::size_type next = path.find('/');
- if (next != std::string::npos)
- return p->find_limit(path.substr(next+1, path.size()), name);
- }
- }
-
- return &dummy_node::get(path + ":" + name);
-}
-
-// Trigger proccessing
-
-struct triggered_lister : public trigger_lister {
- node* n_;
-public:
- triggered_lister(node* n) : n_(n) {}
-
- void next_node(node& n,node*,int,node* t)
- { n.add_triggered(n_,t); }
-};
-
-void node::add_triggered(node* n,node* t)
-{
- if(data_ == 0) data_ = new node_data();
- data_->add_triggered(n,t);
-}
-
-void node::gather_triggered(node* p)
-{
- while(p) {
- triggered_lister tl(p);
- p->triggers(tl);
- p->triggered_ = true;
- gather_triggered(p->kids());
- p = p->next();
- }
-}
-
-struct kids_triggered_lister : public trigger_lister {
- trigger_lister& l_;
- node* k_;
- node* n_;
-public:
- kids_triggered_lister(node *n, node* k,trigger_lister& l):
- l_(l), k_(k), n_(n) {}
-
- void next_node(node& n,node* p,int,node* t) {
- if(!n.is_my_parent(n_))
- l_.next_node(n,k_,trigger_lister::child,t);
- }
-};
-
-static void triggered_by_kids(node* n,node *k,trigger_lister& l)
-{
- while(k) {
- kids_triggered_lister ktl(n,k,l);
- k->triggered(ktl);
- triggered_by_kids(n,k->kids(),l);
- k = k->next();
- }
-}
-
-struct parent_triggered_lister : public trigger_lister {
- node* n_;
- node* p_;
- trigger_lister& l_;
-public:
- parent_triggered_lister(node *n, node* p,trigger_lister& l):
- n_(n), p_(p), l_(l) {}
-
- void next_node(node& n,node* p,int,node* t) {
- l_.next_node(n,p_,trigger_lister::parent,t);
- }
-};
-
-static void triggered_by_parent(node* n,node *p,trigger_lister& l)
-{
- while(p) {
- parent_triggered_lister ptl(n,p,l);
- p->triggered(ptl);
- p = p->parent();
- }
-}
-
-void node::triggered(trigger_lister& l)
-{
- if(!triggered_) // Scan all tree
- gather_triggered(serv().top());
-
- if(data_) data_->triggered(l);
-
- if(l.kids()) triggered_by_kids(this,kids(),l);
- if(l.parents()) triggered_by_parent(this,parent(),l);
-}
-
-void node::triggers(trigger_lister&)
-{
-}
-
-//============================================================
-
-const std::vector<std::string>& node::messages() const
-{
-#ifdef BRIDGE
- if (tree_) return serv().messages(*this);
-#endif
- return serv().messages(*this);
-}
-
-//============================================================
-node* node_find(node* n, std::string path) {
- std::string::size_type pos = path.find("/");
- std::string::size_type beg = 0;
- if (!n) return n;
- while (path[beg] == '/') ++beg;
- node *kid = n->kids();
- while (kid) {
- if (kid->type() != NODE_SUITE &&
- kid->type() != NODE_FAMILY &&
- kid->type() != NODE_TASK ) {kid = kid->next(); continue;}
- if (kid->name() == path.substr(beg, pos-beg)) {
- if (pos == std::string::npos)
- return kid;
- else
- return node_find(kid, path.substr(pos));
- }
- kid = kid->next();
- }
- return kid;
-}
-
-node* node::find(const std::string name)
-{
- node * top = 0x0;
- node_ptr ptr;
- std::string::size_type pos = name.find(":");
- if (pos == std::string::npos) { // not an attribute
- ecf_concrete_node<Defs> * ecfn = 0x0;
- if (0x0 != (top = serv().top())) {
- ecfn = dynamic_cast<ecf_concrete_node<Defs>*>(top->__node__());
- if (0x0 != ecfn) // ok with a node, NOK with attribute
- try {
- if (const_cast<Defs*>(ecfn->get()))
- ptr = const_cast<Defs*>(ecfn->get())->findAbsNode(name);
- } catch (...) {
- fprintf(stderr, "exception with node.cc:find %s\n", name.c_str());
- }
- }
- } else {
- const char* fname = full_name().c_str();
- size_t len1 = name.size(), len2 = strlen(fname);
- if (len1==len2 && !strcmp(name.c_str(), fname)) return this;
- if (len2 < len1 && !strncmp(name.c_str(), fname, len2)
- && kids_) return kids_->find(name);
- if (next_) return next_->find(name);
- return 0x0;
- }
- if (0x0 != ptr.get()) {
- return (node*) ptr.get()->graphic_ptr();
- }
- else if (name == "/")
- return serv().top();
-
- return node_find(serv().top(), name);
- /* if (item == 0x0)
- std::cout << "# not found:" << name << "\n";
- return item; */
-}
-
-//============================================================
-
-node* node::parent() const
-{
-#ifdef BRIDGE
- if (tree_) if (tree_->parent) return (node*) tree_->parent->user_ptr;
-#endif
- if (owner_) {
- ecf_node *p = owner_->parent();
- return p ? p->xnode() : 0x0;
- }
- return 0x0;
-}
-
-const char* node::type_name() const
-{
-
- return ecf_node_name(type());
-}
-
-const char* node::status_name() const
-{
- return "??";
-}
-
-//============================================================
-
-node* node::variableOwner(const char *name)
-{
- std::vector<Variable>::const_iterator it;
- node *m = this;
- while(m) {
- { std::vector<Variable> var; m->variables(var);
- for (it = var.begin(); it != var.end(); ++it)
- if (it->name() == name) return m;
- }
- { std::vector<Variable> var; m->genvars(var);
- for (it = var.begin(); it != var.end(); ++it)
- if (it->name() == name) return m;
- }
- m = m->parent();
- }
- return 0;
-}
-
-Boolean node::isGenVariable(const char *name) { return False; }
-
-void node::folded(Boolean f)
-{
- if(f) {
- folded_ = false;
- node *k = kids_;
- while(k) {
- if(k->visible() || k->show_it()) {
- folded_ = true;
- break;
- }
- k = k->next();
- }
- } else
- folded_ = f;
-
- redraw();
-}
-
-void node::why(std::ostream&)
-{
-}
-
-bool node::evaluate() const
-{
- return false;
-}
-
-void node::tell_me_why(std::ostream&)
-{
-}
-
-void node::suspended(std::ostream&)
-{
-}
-
-void node::aborted(std::ostream&)
-{
-}
-
-void node::queued(std::ostream&)
-{
-}
-
-bool node::is_my_parent(node* p) const
-{
- const node* n = this;
- while(n) {
- if(n == p)
- return true;
- n = n->parent();
- }
- return false;
-}
-
-#include <boost/date_time/posix_time/posix_time.hpp>
-void node::info(std::ostream& f)
-{
- using namespace boost::posix_time;
- using namespace boost::gregorian;
-
- f << "name : " << name() << "\n";
- f << "type : " << type_name() << "\n";
- f << "status : " << status_name() << "\n";
-
- if (owner_) {
- // if (owner_->type() == NODE_TASKtas )
- {
- boost::posix_time::ptime state_change_time = owner_->status_time();
- if (!state_change_time.is_special()) {
- f << "at : " << to_simple_string(state_change_time) << "\n"; // https://software.ecmwf.int/issues/browse/SUP-649
- }
- }
- }
- f << "----------\n";
- // 1234567890
-}
-
-const std::string node::toString() const
-{
-#ifdef BRIDGE
- if (tree_) { return sms_node_full_name(tree_); }
-#endif
- if (owner_) return owner_->toString();
- return ecf_node::none();
-}
-
-node* node::find_match(const char* p)
-{
- if (p == NULL) return 0;
- const char* found = find_name(p);
- if (found == NULL) return 0;
- return find(found);
-}
-
-const char* node::find_name(const char* p)
-{
- static char name[1024];
- strcpy(name,p);
-
- char *q = name;
-
- while(*q && *q != '/') q++;
- if(*q) {
- char* r = q;
- while(*q && *q != ' ' && *q != '\t') q++;
- *q = 0;
- return r;
- }
- return 0;
-}
-
-time_t node::suite_time()
-{
- node *xnode = this;
- while(xnode) {
- if(xnode->type() == NODE_SUITE)
- return 0; // FILL
- xnode = xnode->parent();
- }
- return 0;
-}
-
-bool node::match(const char* n)
-{
- return strstr(name().c_str(),n) != 0;
-}
-
-void node::command(const char* cmd)
-{
- serv().command(substitute(cmd));
-}
-
-std::string node::substitute(const char* cmd)
-{
- try {
- return substitute::scan(cmd,this);
- } catch ( std::exception& e ) {
- return cmd;
- }
-
-}
-
-void node::edit(node_editor&)
-{
-}
-
-void node::apply(node_editor&)
-{
-}
-
-node_info* node::get_node_info(const str& s)
-{
- return data_?data_->get(s):0;
-}
-
-void node::add_node_info(node_info* n)
-{
- get_node_data()->add(n);
-}
-
-void node::remove_node_info(node_info* n)
-{
- if(data_) data_->remove(n);
-}
-
-void node::remove_node_info(const str& n)
-{
- if(data_) data_->remove(n);
-}
-
-const char* node::html_page(url& u)
-{
- return "node.html";
-}
-
-void node::html_name(FILE* f,url& u)
-{
- fprintf(f,"<a href=\"%s\">%s</a>",net_name().c_str()+1,name().c_str());
-}
-
-void node::html_title(FILE* f,url& u)
-{
- if(parent()) parent()->html_title(f,u);
- fprintf(f,"/<a href=\"%s\">%s</a>",net_name().c_str()+1,name().c_str());
-}
-
-bool node::is_json = false; // set by url.cc
-void node::as_perl(FILE* f,bool full)
-{
- if (node::is_json) {
- fprintf(f,"{\n");
- } else
- fprintf(f,"bless({\n");
-
- perl_member(f,"name",name());
- perl_member(f,"full", full_name());
- perl_member(f,"status", status());
- perl_member(f,"status_name", status_name());
-
- if(full) perlify(f);
-
- if (node::is_json) {
- fprintf(f,"\"class\": \"%s\" }", perl_class());
- } else fprintf(f,"},'ecf::node::%s')",perl_class());
-}
-
-void node::perl_member(FILE* f,const char* p,const char* v)
-{
- if(v) {
- if (node::is_json) {
- unsigned int i = 0; char *c; char bak[1024]; strncpy(bak, v, 1024);
- for (c = bak; i<strlen(v) && i<1024; c++, i++) {
- if (*c == '"') *c = '\'';
- }
- fprintf(f,"\"%s\": \"%s\",\n",p,bak); } else
- fprintf(f,"%s=>'%s',\n",p,v);
- }
-}
-
-void node::perl_member(FILE* f,const std::string& p,const std::string&v)
-{
- perl_member(f, p.c_str(), v.c_str()); /*
- if (node::is_json) {
- std::string bak = v;
- for (unsigned int i=0; i<bak.size(); i++) {
- if (bak[i] == '"') bak[i] = '\'';
- }
- fprintf(f,"\"%s\": \"%s\",\n",p.c_str(),bak.c_str()); } else
- { fprintf(f,"%s=>%s,\n",p.c_str(),v.c_str()); } */
-}
-
-void node::perl_member(FILE* f,const char * p, int v)
-{
- if (node::is_json) fprintf(f,"\"%s\": \"%d\",\n",p,v); else
- fprintf(f,"%s=>%d,\n",p,v);
-}
-
-void node::perl_member(FILE* f,const char* p,ecf_list* v)
-{
- if (node::is_json) {
- fprintf(f,"\"%s\": [\n",p);
- while(v) {
- fprintf(f,"'name': '%s',\n",v->name().c_str());
- v = v->next;
- }
- fprintf(f,"\n],\n");
- return; }
-
- fprintf(f,"%s=>[\n",p);
- while(v) {
- fprintf(f,"'%s',",v->name().c_str());
- v = v->next;
- }
- fprintf(f,"\n],\n");
-}
-
-static proc_substitute s_full_name("<full_name>",&node::full_name);
-static proc_substitute s_node_name("<node_name>",&node::node_name);
-static proc_substitute s_parent_name("<parent_name>",&node::parent_name);
-
-void node::check() {
- if (__node__() == 0x0)
- std::cerr << "# node: no owner: " << name() << "\n";
- if (parent() == 0x0)
- std::cerr << "# node: no parent: " << name() << "\n";
- node *n;
- for(n = kids(); n; n = n->next())
- { n->check(); }
- if ((n = next())) n->check();
-}
-
-bool node::ondemand(bool full)
-{
- // ecf_node *ec = owner_;
- // if (0 == ec) return false;
- // else if (0 != kids()) return false; // gen variables at least
- // printf("demanding\n");
- // ec->make_subtree(); node *xnode = ec->create_tree(serv()); ec->adopt(xnode);
- // serv().redraw();
- return false;
-}
-
-const std::string& node::parent_name() const
-{
- if (parent())
- return parent()->full_name();
- return ecf_node::none();
-}
-
-void node::delvars() {
-}
-
-void node::unlink(bool detach) {
- if (__node__()) __node__()->unlink(detach);
- for (node *run = kids(); run; run = run->next())
- { run->unlink(detach); }
-}
-
-void node::remove() {
- node *top = parent();
- if (!top) return;
- node *run = top->kids_;
-
- if (run == this) {
- top->kids_ = this->next_;
- } else
- while (run) {
- if (run->next_ == this) {
- run->next_ = this->next_;
- break;
- }
- run = run->next_;
- }
-}
diff --git a/ecflow_4_0_7/view/src/node.h b/ecflow_4_0_7/view/src/node.h
deleted file mode 100644
index cf70f28..0000000
--- a/ecflow_4_0_7/view/src/node.h
+++ /dev/null
@@ -1,350 +0,0 @@
-#ifndef node_H
-#define node_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #33 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "ecflowview.h"
-
-class host;
-class node;
-class trigger_lister;
-class node_lister;
-class node_editor;
-class node_data;
-class ostream;
-class url;
-#include "ecf_node.h" // class ecf_node;
-
-#ifndef xnode_H
-#include "xnode.h"
-#endif
-
-#ifndef observable_H
-#include "observable.h"
-#endif
-
-#ifndef gui_H
-#include "gui.h"
-#endif
-
-#ifndef str_H
-#include "str.h"
-#endif
-
-#ifndef xmstring_H
-#include "xmstring.h"
-#endif
-
-#ifdef BRIDGE
-extern "C" {
-#define new _new
-#define delete _delete
-#undef NODE_MAX
-#include "sms.h"
-#include "smsproto.h"
-#undef new
-#undef delete
-}
-#endif
-
-template<class T>
-class lister;
-
-class node_info {
-public:
- virtual ~node_info() {}
- virtual const str& name() = 0;
-};
-
-class node : public observable, public xnode {
- friend class ecf_node;
- friend class tree;
- int type_;
-public:
-
- static bool is_json;
-
- void scan(node* n) { scan(n,n); }
-
- virtual void update(int,int,int);
- void remove();
-
- node* next() const { return next_; }
- node* kids() const { return kids_; }
- host& serv() const { return host_; }
-
- virtual node* parent() const;
-
- virtual Boolean visible() const;
- virtual Boolean show_it() const;
- virtual Boolean visible_kid() const { return false; }
-
- virtual Boolean menus() { return True; }
- virtual Boolean selectable() { return True; }
-
- virtual const std::string& name() const;
- virtual const std::string& full_name() const;
- virtual const std::string& node_name() const { return name(); }
- virtual const std::string& net_name() const;
- virtual const std::string& parent_name() const;
- virtual const std::string& definition() const { return full_name(); }
-
- virtual void adopt(node*);
- virtual void create();
-
-#ifdef BRIDGE
- const std::string name_;
- const std::string full_name_;
- static node* create(host&h,sms_node* n,char = 0);
- static void schanged(sms_node*,int,int,int,void*);
- static node* find(sms_node*);
-
- protected:
- node(host& h,sms_node* owner, char b);
- sms_node
-#else
- protected:
- void
-#endif
- *tree_;
- public:
- virtual void reset();
- void delvars();
-
- virtual void search(node_lister&);
- virtual void info(std::ostream&);
- virtual const std::string toString() const;
- virtual std::string substitute(const char*);
- virtual void command(const char*);
-
- virtual void tell_me_why(std::ostream&);
- virtual void why(std::ostream&);
- virtual bool evaluate() const;
- virtual void suspended(std::ostream&);
- virtual void aborted(std::ostream&);
- virtual void queued(std::ostream&);
-
- virtual void triggers(trigger_lister&);
- virtual void triggered(trigger_lister&);
-
- Boolean folded() { return folded_; }
- virtual void folded(Boolean f);
-
- virtual Boolean ecfFlag(int) const { return False; }
-
- virtual void genvars(std::vector<Variable>&) {};
- virtual void variables(std::vector<Variable>&) {};
-
- virtual const char* type_name() const;
- virtual const char* status_name() const;
-
- void insert(node*);
-
- virtual int type() const;
- virtual int status() const;
- virtual boost::posix_time::ptime status_time() const
- { return boost::posix_time::ptime(); }
-
- virtual int tryno() const { return 0; }
- virtual int flags() const { return 0; }
- const std::vector<std::string>& messages() const;
-
- virtual Boolean isSimpleNode()const { return False; }
- virtual Boolean hasTriggers() const { return False; }
- virtual Boolean hasDate() const { return False; }
- virtual Boolean hasTime() const { return False; }
-
- virtual Boolean hasTimeHolding() const { return False; }
-
- virtual Boolean hasManual() const { return False; }
- virtual Boolean hasInfo() const { return True; }
- virtual Boolean isMigrated() const { return False; }
- virtual Boolean isLate() const { return False; }
- virtual Boolean isWaiting() const { return False; }
- virtual Boolean hasMessages() const { return False; }
- virtual Boolean isTimeDependent() const { return False; }
- virtual Boolean isRerun() const { return False; }
- virtual Boolean isLocked() const { return False; }
-
- virtual Boolean isDefComplete() const { return False; }
- virtual Boolean isZombie() const { return False; }
- virtual Boolean hasZombieAttr() const { return False; }
- virtual Boolean isToBeChecked() const { return False; }
- virtual Boolean hasText() const { return False; }
-
- virtual Boolean isForceAbort() const { return False; }
- virtual Boolean isUserEdit() const { return False; }
- virtual Boolean isTaskAbort() const { return False; }
- virtual Boolean isEditFailed() const { return False; }
- virtual Boolean isCmdFailed() const { return False; }
- virtual Boolean isScriptMissing() const { return False; }
- virtual Boolean isKilled() const { return False; }
- virtual Boolean isByRule() const { return False; }
- virtual Boolean isQueueLimit() const { return False; }
-
- Boolean isFolded() const { return folded_; }
-
- virtual void active(bool) {}
- virtual void up_to_date() {}
-
- virtual bool trigger_kids() const { return false; }
- virtual bool trigger_parent() const { return false; }
- virtual bool show_in_dependancies() const { return false; }
- virtual void add_triggered(node*,node*);
- void unlink(bool detach=true);
-
- void check();
-// ---------------------------
-
- time_t suite_time();
- node* find_trigger(const std::string& name) const;
- node* find_limit(const std::string& path, const std::string& name);
- node* find(const std::string n);
- static const char* find_name(const char* name);
- node* find_match(const char* name);
-
-// ---------------------------
-
- virtual Pixel color() const;
-
- virtual void drawNode(Widget,XRectangle*,bool);
- virtual void sizeNode(Widget,XRectangle*,bool);
- virtual void drawBackground(Widget,XRectangle*,bool);
-
-// ---------------
-
- virtual void edit(node_editor&);
- virtual void apply(node_editor&);
-
-// ---------------
-
- virtual std::string variable(const std::string&, bool substitute=false);
- virtual node* variableOwner(const char*);
- virtual Boolean isGenVariable(const char*);
-
- virtual bool is_my_parent(node*) const;
-
- virtual bool match(const char*);
-
- virtual node* graph_node() { return this; }
-
-// ----------------
-
- virtual bool show_in_html(url&) { return false; }
-
- virtual const char* html_page(url&);
-
- virtual void html_name(FILE*,url&);
- virtual void html_title(FILE*,url&);
-
- virtual void html_why(FILE*,url&) {}
- virtual void html_output(FILE*,url&) {}
- virtual void html_manual(FILE*,url&) {}
- virtual void html_script(FILE*,url&) {}
- virtual void html_job(FILE*,url&) {}
- virtual void html_jobstatus(FILE*,url&) {}
- virtual void html_kids(FILE*,url&) {}
- virtual void html_variables(FILE*,url&) {}
-
- // ------------------------------
- virtual void as_perl(FILE*,bool);
- virtual void perlify(FILE*) = 0;
- virtual const char* perl_class() { return type_name(); }
-
- void perl_member(FILE*,const char*,const char*);
- void perl_member(FILE*,const std::string&,const std::string&);
- void perl_member(FILE*,const char*,int);
- void perl_member(FILE*,const char*,ecf_list*);
-
- static void destroy(node*);
- static void changed(ecf_node*,int a=-1,int b=-1,int c=-1,void *d=0x0);
- static node* find(ecf_node*);
-
- static GC blackGC() { return gui::blackGC(); }
- static GC blueGC() { return gui::blueGC(); }
- static GC redGC() { return gui::redGC(); }
- static XmFontList smallfont() { return gui::smallfont(); }
- static XmFontList fontlist() { return gui::fontlist(); }
- static Pixel colors(int n) { return gui::colors(n); }
- static GC colorGC(int n) { return gui::colorGC(n); }
-
- void helper(void* h) { helper_ = h; }
- void* helper() { return helper_; }
-
- node_info* get_node_info(const str&);
- void add_node_info(node_info*);
- void remove_node_info(const str&);
- void remove_node_info(node_info*);
-
- ecf_node* __node__() const { if (tree_) return 0x0; return owner_; }
- bool ondemand(bool full=false);
-protected:
- node(host&,ecf_node*);
-
- virtual ~node(); // Change to virtual if base class
-
- node* next_;
- node* kids_;
- ecf_node *owner_;
- host& host_;
- Boolean folded_;
-
- void append(node*);
- const xmstring& labelTree();
- const xmstring& labelTrigger();
- static void shadow(Widget,XRectangle*,bool = true);
-
- protected:
- xmstring labelTree_;
-
-private:
-
- node(const node&);
- node& operator=(const node&);
-
- void* helper_;
- node_data* data_;
- bool triggered_;
-
- node_data* get_node_data();
-
- void scan(node*,node*);
- void gather_triggered(node*);
-
- virtual xmstring make_label_tree();
- virtual xmstring make_label_trigger();
-
- virtual void draw(Widget w,XRectangle* r) { drawNode(w,r,true); }
- virtual void size(Widget w,XRectangle* r) { sizeNode(w,r,true); }
-};
-
-#ifdef BRIDGE
-class node_builder {
-protected:
- static node_builder* builders_[NODE_MAX];
-public:
- virtual node* make(host&,sms_node* n,char) = 0;
- static node* build(host& h,sms_node* n,char b);
-};
-
-template<class T> class node_maker : public node_builder {
-public:
- node_maker(int n) { builders_[n] = this; }
- virtual node* make(host& h,sms_node* n,char b) { return new T(h,n,b); }
-};
-#endif
-#endif
-
diff --git a/ecflow_4_0_7/view/src/node_alert.cc b/ecflow_4_0_7/view/src/node_alert.cc
deleted file mode 100644
index 1eebe2e..0000000
--- a/ecflow_4_0_7/view/src/node_alert.cc
+++ /dev/null
@@ -1,112 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <stdio.h>
-#include <stdarg.h>
-#include "node_alert.h"
-#include "gui.h"
-#include "ecflowview.h"
-#include "node.h"
-#include "host.h"
-#include "selection.h"
-#include "collector.h"
-#include <Xm/List.h>
-extern "C" {
-#include "xec.h"
-}
-
-template<class T>
-node_alert<T>::node_alert(const char* title,int bg)
- : alert_(getenv("ecflow_view_alert"))
- , title_(title)
- , bg_ (bg)
-{
- create(gui::top());
- set_menu(title);
- XtVaSetValues(_xd_rootwidget,XmNtitle,title,NULL);
- xec_SetLabel(label_,title);
- if(bg != -1) {
- XtVaSetValues(label_,XmNbackground,gui::colors(bg),NULL);
- /* XtVaSetValues(form_,XmNforeground,gui::colors(bg),0); */
- /* XtVaSetValues(list_,XmNbackground,gui::colors(bg),0); */
- /* XtVaSetValues(list_,XmNforeground,gui::colors(bg),0); */
- }
-}
-
-
-template<class T>
-node_alert<T>::~node_alert()
-{}
-
-
-template<class T>
-void node_alert<T>::browseCB(Widget,XtPointer data)
-{
- XmListCallbackStruct *cb = (XmListCallbackStruct *) data;
- selection::notify_new_selection(find(cb->item));
-}
-
-
-
-template<class T>
-void node_alert<T>::clearCloseCB(Widget,XtPointer)
-{
- reset();
- XtUnmanageChild(form_);
-}
-
-template<class T>
-void node_alert<T>::closeCB(Widget,XtPointer)
-{
- XtUnmanageChild(form_);
-}
-
-template<class T>
-void node_alert<T>::collectCB(Widget,XtPointer)
-{
- XmString* items = 0;
- int count = 0;
-
- XtVaGetValues(list_,XmNitems,&items,XmNitemCount,&count,NULL);
-
- for(int i = 0; i < count ; i++)
- {
- node *n = find(items[i]);
- if(n) collector::show(*n);
- }
-}
-
-template<class T>
-void node_alert<T>::notify_system(node* n) {
-#ifdef linux
-/*
- export ecflow_view_alert=1
- notify-send -i 'dialog-information' 'Summary' \
- '<b><font color=red>Message body.'
- */
- if(1 && alert_) {
- char buff[1024];
- const char *cmd = "kdialog --title ecFlowview::%s --passivepopup '<b><font color=%s> %s' 5; %s";
- const char *sound = "play -q /usr/share/xemacs/xemacs-packages/etc/sounds/boing.wav";
- snprintf(buff, 1024, cmd,
- title_.c_str(),
- bg_ == STATUS_ABORTED ? "red" : "black",
- n ? name(n) : "",
- bg_ == STATUS_ABORTED ? sound : ""
- );
- if (system(buff)) { std::cerr << "#node_alert!\n"; }
- }
-#endif
- }
diff --git a/ecflow_4_0_7/view/src/node_alert.h b/ecflow_4_0_7/view/src/node_alert.h
deleted file mode 100644
index 7cd41bd..0000000
--- a/ecflow_4_0_7/view/src/node_alert.h
+++ /dev/null
@@ -1,76 +0,0 @@
-#ifndef node_alert_H
-#define node_alert_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "uinode_alert.h"
-#include "window.h"
-#include "singleton.h"
-#include "node_list.h"
-#include "gui.h"
-#include "node.h"
-
-class node;
-
-template<class T>
-class node_alert : public node_alert_shell_c, public window,
- public singleton<T>, public node_list {
-
- const char* alert_;
- void notify_system(node* n);
- public:
-
- node_alert(const char*,int = -1);
-
- virtual ~node_alert(); // Change to virtual if base class
-
- virtual Widget shell() { return _xd_rootwidget; }
- virtual Widget list() { return list_; }
- virtual Widget form() { return form_; }
-
- // HP compiler wants the 'singleton<T>::' specifier :-(
- static void show()
- { if(gui::visible()) { singleton<T>::instance().add(0);singleton<T>::instance().notify_system(0);}}
-
- static void show(node& n)
- { if(gui::visible()) { singleton<T>::instance().add(&n);singleton<T>::instance().notify_system(&n); }}
-
- static void hide(node& n)
- { if(gui::visible()) singleton<T>::instance().remove(&n); }
-
- static void clear()
- { if(gui::visible()) singleton<T>::instance().reset(); }
-
-private:
-
- node_alert(const node_alert<T>&);
- node_alert<T>& operator=(const node_alert<T>&);
-
- std::string title_;
- int bg_;
-
- void browseCB(Widget,XtPointer);
- void clearCloseCB( Widget, XtPointer ) ;
- void closeCB( Widget, XtPointer ) ;
- void collectCB( Widget, XtPointer ) ;
-};
-
-
-#if defined(__GNUC__) || defined(hpux) || defined(_AIX)
-#include "node_alert.cc"
-#endif
-
-#endif
diff --git a/ecflow_4_0_7/view/src/node_editor.cc b/ecflow_4_0_7/view/src/node_editor.cc
deleted file mode 100644
index 3f77fc6..0000000
--- a/ecflow_4_0_7/view/src/node_editor.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "node_editor.h"
-
-#ifndef translator_H
-#include "translator.h"
-#endif
-
-#include <Xm/Text.h>
-#include <Xm/TextF.h>
-#include <Xm/Label.h>
-#include "xec.h"
-
-template<class T>
-static void node_editor_set(node_editor& e,const char* name, const T& t)
-{
- str v = translator<T,str>()(t);
- e.set(name,v);
-}
-
-template<class T>
-static void node_editor_get(node_editor& e,const char* name, T& t)
-{
- str v;
- e.get(name,v);
- t = translator<str,T>()(v);
-}
-
-void node_editor::set(const char* name,int value)
-{
- node_editor_set(*this,name,value);
-}
-
-void node_editor::get(const char* name,int& value)
-{
- node_editor_get(*this,name,value);
-}
-
-void node_editor::set(const char* name,const str& value)
-{
- Widget w = find(name); if(!w) return;
- if(XmIsLabel(w)) xec_SetLabel(w,(char*)value.c_str());
- if(XmIsText(w)) XmTextSetString(w,(char*)value.c_str());
- if(XmIsTextField(w)) XmTextSetString(w,(char*)value.c_str());
-}
-
-void node_editor::get(const char* name,str& value)
-{
- Widget w = find(name); if(!w) return;
- char* p = XmTextGetString(w);
- value = str(p);
- XtFree(p);
-}
diff --git a/ecflow_4_0_7/view/src/node_editor.h b/ecflow_4_0_7/view/src/node_editor.h
deleted file mode 100644
index a8f389f..0000000
--- a/ecflow_4_0_7/view/src/node_editor.h
+++ /dev/null
@@ -1,134 +0,0 @@
-#ifndef node_editor_H
-#define node_editor_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-// Headers
-// #ifndef machine_H
-// #include <machine.h>
-// #endif
-
-// Forward declarations
-
-// class ostream;
-// typedef class _Pvts os_typespec; // Remove if not persistant
-
-//
-
-#ifndef str_H
-#include "str.h"
-#endif
-
-#ifndef editor_H
-#include "editor.h"
-#endif
-
-
-class node_editor : public editor {
-public:
-
-// -- Exceptions
- // None
-
-// -- Contructors
-
- node_editor() {}
-
-// -- Destructor
-
- virtual ~node_editor() {} // Change to virtual if base class
-
-// -- Convertors
- // None
-
-// -- Operators
- // None
-
-// -- Methods
-
- virtual void set(const char*,const str&);
- virtual void get(const char*,str&);
-
- virtual void set(const char*,int);
- virtual void get(const char*,int&);
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
- // Uncomment for persistent, remove otherwise
- // static os_typespec* get_os_typespec();
-
-protected:
-
-// -- Members
- // None
-
-// -- Methods
-
- // void print(ostream&) const; // Change to virtual if base class
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-private:
-
-// No copy allowed
-
- node_editor(const node_editor&);
- node_editor& operator=(const node_editor&);
-
-// -- Members
- // None
-
-// -- Methods
- // None
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-// -- Friends
-
- //friend ostream& operator<<(ostream& s,const node_editor& p)
- // { p.print(s); return s; }
-
-};
-
-inline void destroy(node_editor**) {}
-
-// If persistent, uncomment, otherwise remove
-//#ifdef _ODI_OSSG_
-//OS_MARK_SCHEMA_TYPE(node_editor);
-//#endif
-
-#endif
diff --git a/ecflow_4_0_7/view/src/node_list.cc b/ecflow_4_0_7/view/src/node_list.cc
deleted file mode 100644
index 001d28f..0000000
--- a/ecflow_4_0_7/view/src/node_list.cc
+++ /dev/null
@@ -1,129 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #8 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "node_list.h"
-#include "opener.h"
-#include "node.h"
-#include "host.h"
-#include "str.h"
-#include "gui.h"
-#include "relation.h"
-#include "counted.h"
-#include "opener.h"
-#include <Xm/List.h>
-
-extern "C" {
-#include "xec.h"
-}
-
-class node_list_data : public counted {
- str name_;
-public:
- node_list_data(const char* n) : name_(n) {}
- const char* name() { return name_.c_str(); }
-};
-
-node_list::node_list()
-{
-}
-
-node_list::~node_list()
-{
-}
-
-
-void node_list::remove(node* n)
-{
- if (forget(n))
- xec_RemoveListItem(list(),(char*)name(n));
-}
-
-
-void node_list::add(node* n,bool sel)
-{
- if(n) {
- const char *p = name(n);
- if(xec_AddListItemUnique(list(),(char*)p,sel)) {
- observe(n);
- relation::set_data(this,n,new node_list_data(p));
- }
- }
-
- static opener o;
- o.show(form());
- gui::raise();
-}
-
-
-void node_list::reset()
-{
- forget_all();
- XmListDeleteAllItems(list());
-}
-
-
-node* node_list::find(XmString s)
-{
- char *p = xec_GetString(s);
- char *q = p;
-
- while(*q != ' ') q++;
- *q = 0; q++;
- while(*q == ' ') *q++ = 0;
-
- node* n = host::find(p,q);
-
- if(!n) {
- printf("node_list::find cannot find <%s> <%s>\n",p,q);
- }
-
- XtFree(p);
- return n;
-}
-
-node* node_list::find(const char *p)
-{
- xmstring s(p);
- return find(s);
-}
-
-
-const char* node_list::name(node* n)
-{
- static char buf[1024];
- sprintf(buf,"%-8s %s",n->serv().name(),n->full_name().c_str());
- return buf;
-}
-
-
-void node_list::notification(observable* o)
-{
- node* n = (node*)o;
- if(!keep(n))
- remove(n);
-}
-
-void node_list::adoption(observable*,observable* o)
-{
- node* n = (node*)o;
- if(!keep(n))
- remove(n);
-}
-
-void node_list::gone(observable* o)
-{
- node_list_data* p = (node_list_data*)relation::get_data(this,o);
- if(p) xec_RemoveListItem(list(),(char*)p->name());
-}
diff --git a/ecflow_4_0_7/view/src/node_list.h b/ecflow_4_0_7/view/src/node_list.h
deleted file mode 100644
index d45efd1..0000000
--- a/ecflow_4_0_7/view/src/node_list.h
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef node_list_H
-#define node_list_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#ifdef NO_BOOL
-#include "bool.h"
-#endif
-
-class node;
-
-#include <Xm/Xm.h>
-#ifndef observer_H
-#include "observer.h"
-#endif
-
-class node_list : public observer {
-public:
-
- node_list();
-
- ~node_list(); // Change to virtual if base class
-
- virtual Widget list() = 0;
- virtual Widget form() = 0;
- virtual bool keep(node*) = 0;
-
- virtual void add(node* n,bool sel = false);
- virtual void remove(node* n);
- virtual void reset();
-
-protected:
-
- node* find(XmString);
- node* find(const char*);
- const char* name(node*);
-
-private:
-
- node_list(const node_list&);
- node_list& operator=(const node_list&);
-
- virtual void notification(observable*);
- virtual void adoption(observable*,observable*);
- virtual void gone(observable*);
-};
-
-inline void destroy(node_list**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/node_lister.h b/ecflow_4_0_7/view/src/node_lister.h
deleted file mode 100644
index 069dfea..0000000
--- a/ecflow_4_0_7/view/src/node_lister.h
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef node_lister_H
-#define node_lister_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#ifndef observer_H
-#include "observer.h"
-#endif
-
-#include <string>
-class node;
-
-class node_lister {
-public:
-
- node_lister() {}
-
- virtual ~node_lister() {}
-
- virtual void next(node&) = 0;
- virtual void next(const std::string) {}
-private:
- node_lister(const node_lister&);
- node_lister& operator=(const node_lister&);
-};
-
-inline void destroy(node_lister**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/node_window.cc b/ecflow_4_0_7/view/src/node_window.cc
deleted file mode 100644
index af7f674..0000000
--- a/ecflow_4_0_7/view/src/node_window.cc
+++ /dev/null
@@ -1,253 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "node_window.h"
-#include "menus.h"
-#include <Xm/Frame.h>
-#include <Xm/Label.h>
-#include <Xm/RowColumn.h>
-#include "xnode.h"
-#include "collector.h"
-#include "host.h"
-#ifdef AIX
-#include <X11/keysym.h>
-#endif
-node_window::node_window()
-{
-}
-
-node_window::~node_window()
-{
-}
-
-void node_window::linkCB(Widget w,XtPointer from,XtPointer cb_data)
-{
- LinkCallbackStruct* cb = (LinkCallbackStruct*)cb_data;
- node_window* t = (node_window*)from;
-
-
- xnode* x1 = (xnode*)cb->data1;
- xnode* x2 = (xnode*)cb->data2;
-
- node* n1 = x1?x1->get_node():0;
- node* n2 = x2?x2->get_node():0;
-
- t->link(cb->event,n1,n2);
-}
-
-void node_window::inputCB(Widget w,XtPointer from,XtPointer cb_data)
-{
- XmDrawingAreaCallbackStruct* cb = (XmDrawingAreaCallbackStruct*)cb_data;
-
- // printf("inputCB %d\n", cb->event->type);
- if(cb->event->type == ButtonPress || cb->event->type == KeyPress) {
- node_window* t = (node_window*)from;
- t->click(cb->event);
- }
-}
-
-void node_window::click1(node* n,Boolean shift,Boolean control)
-{
- // printf("raw_click1 %p %d %d\n",n,shift,control);
- if(control && n) collector::show(*n);
- else if (shift && n) this->click2(n,0,control);
- else selection::notify_new_selection(n);
-}
-
-void node_window::click2(node* n,Boolean shift,Boolean control)
-{
-}
-
-void node_window::click3(node* n,Boolean shift,Boolean control)
-{
-}
-
-void node_window::raw_click1(XEvent* event,xnode* x)
-{
- node* n = x ? x->get_node() : 0;
- selection::menu_node(n);
- unsigned int modifiers = event->xbutton.state;
- Boolean shift = (modifiers & ShiftMask) != 0;
- Boolean control = (modifiers & ControlMask) != 0;
- click1(n,shift,control);
-}
-
-void node_window::raw_click2(XEvent* event,xnode* x)
-{
- node* n = x ? x->get_node() : 0;
- selection::menu_node(n);
- unsigned int modifiers = event->xbutton.state;
- Boolean shift = (modifiers & ShiftMask) != 0;
- Boolean control = (modifiers & ControlMask) != 0;
- if(n) this->click2(n,shift,control);
-}
-
-void node_window::raw_click3(XEvent* event,xnode* x)
-{
- node* n = x ? x->get_node() : 0;
- selection::menu_node(n);
- unsigned int modifiers = event->xbutton.state;
- Boolean shift = (modifiers & ShiftMask) != 0;
- Boolean control = (modifiers & ControlMask) != 0;
-
- if(n) click3(n,shift,control);
- if( shift && n)
- {
- XmMenuPosition(menu2(),(XButtonPressedEvent*)event);
- XtManageChild(menu2());
- }
- else if(n)
- {
- // menus::show(node_widget(),event,n); // 20141119
- menus::show(menu1(),event,n);
- //XmMenuPosition(g_cmd_menu,(XButtonPressedEvent*)event);
- //XtManageChild(g_cmd_menu);
- } else {
- XmMenuPosition(menu1(),(XButtonPressedEvent*)event);
- XtManageChild(menu1());
- }
-}
-
-node* next_node(node* n)
-{
- node *out = n;
- while (n) {
- if (n->type() == NODE_TASK ||
- n->type() == NODE_FAMILY ||
- n->type() == NODE_SUITE ||
- n->type() == NODE_ALIAS)
- return n;
- n = n->next();
- }
- return out;
-}
-
-node* next_host(node* n, bool first) {
- host *h = 0x0;
- if (!n) return n;
- if (first) h = extent<host>::first();
- else h = &n->serv();
- while ((h= h->extent<host>::next())) {
- if (h->top())
- return h->top();
- }
- if (first) return n;
- return next_host(n, true);
-}
-
-void node_window::keypress(XEvent* event)
-{
- xnode* x = (xnode*)NodeFind(node_widget(),event);
- node* n = 0x0;
- KeySym keysym = XLookupKeysym(&(event->xkey), 0);
-
- if (keysym == XK_KP_Space || keysym == XK_space) {
- raw_click1(event,x);
- // } else if (keysym == XK_F2) { raw_click2(event,x);
- } else if (keysym == XK_KP_Enter || keysym == XK_Return) {
- if ((event->xbutton.state & ShiftMask) != 0)
- n = selection::current_node();
- if (n)
- menus::show(node_widget(),event,n);
- else
- raw_click3(event,x);
- } else if (keysym == XK_Up) {
- node* first = n = selection::current_node();
- if (!n) return;
- n = n->parent();
-
- if (!n) /* reach server node */
- n = next_host(selection::current_node(), true);
-
- if (!n) return;
- selection::notify_new_selection(n);
-
- n = n->kids();
- if (n==first) n = n->parent();
-
- if (n) click1(n,0,0);
- } else if (keysym == XK_Down) {
- n = selection::current_node();
- if (!n) return;
- n = n->next();
- if (!n) {
- n = selection::current_node()->parent();
- if (n) n = n->next();
- }
- if (!n) /* reach server node */
- n = next_host(selection::current_node(), false);
- if (n) click1(n,0,0);
- } else if (keysym == XK_Left) {
- n = selection::current_node();
- if (!n) return;
- n = n->parent();
- if (!n) /* reach server node */
- n = next_host(selection::current_node(), true);
- if (!n) return;
- click2(n,0,0);
- click1(n,0,0);
- } else if (keysym == XK_Right) {
- n = selection::current_node();
- if (!n) return;
- click2(n,0,0);
- if (n->kids()) n = n->kids();
- else n = n->next();
- n = next_node(n);
- if (n) click1(n,0,0);
- }
-}
-
-void node_window::click(XEvent* event)
-{
- int button = event->xbutton.button;
- xnode* x = (xnode*)NodeFind(node_widget(),event);
-
- switch(button) {
- case 1: raw_click1(event,x); break;
- case 2: raw_click2(event,x); break;
- case 3: raw_click3(event,x); break;
- default: keypress(event);
- }
-}
-
-void node_window::show_node(node&)
-{
-}
-
-void node_window::new_selection(node& n)
-{
- xnode* x = xnode_of(n);
- if(x && x->widget() == node_widget() ) {
- show_node(n);
- x->select();
- }
- else
- selection_cleared();
-}
-
-void node_window::selection_cleared()
-{
- XtVaSetValues(node_widget(),XtNselected,-1,NULL);
-}
-
-void node_window::add_input_CB()
-{
- XtAddCallback( node_widget(), XmNinputCallback, inputCB, this);
- XtAddCallback( node_widget(), XtNlinkCallback, linkCB, this);
-}
-
-void node_window::link(XEvent*,node*,node*)
-{
-}
diff --git a/ecflow_4_0_7/view/src/node_window.h b/ecflow_4_0_7/view/src/node_window.h
deleted file mode 100644
index c37712f..0000000
--- a/ecflow_4_0_7/view/src/node_window.h
+++ /dev/null
@@ -1,73 +0,0 @@
-#ifndef node_window_H
-#define node_window_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#ifndef node_H
-#include "node.h"
-#endif
-
-#ifndef selection_H
-#include "selection.h"
-#endif
-
-class xnode;
-
-class node_window : public selection {
-public:
- node_window();
-
- ~node_window(); // Change to virtual if base class
-
- void add_input_CB();
-
- virtual xnode* xnode_of(node&) = 0;
- virtual Widget node_widget() = 0;
-
- virtual void new_selection(node&);
- virtual void selection_cleared();
-
-protected:
-
- virtual void show_node(node&);
- virtual void click(XEvent*);
-
- virtual void link(XEvent*,node*,node*);
-
- virtual void keypress(XEvent* event);
- virtual void click1(node*,Boolean,Boolean);
- virtual void click2(node*,Boolean,Boolean);
- virtual void click3(node*,Boolean,Boolean);
-
- virtual void raw_click1(XEvent* event,xnode*);
- virtual void raw_click2(XEvent* event,xnode*);
- virtual void raw_click3(XEvent* event,xnode*);
-
- virtual Widget menu1() = 0;
- virtual Widget menu2() = 0;
-
- static void inputCB(Widget,XtPointer,XtPointer);
- static void linkCB(Widget,XtPointer,XtPointer);
-
-private:
-
- node_window(const node_window&);
- node_window& operator=(const node_window&);
-
-};
-
-inline void destroy(node_window**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/not_enqueued.cc b/ecflow_4_0_7/view/src/not_enqueued.cc
deleted file mode 100644
index d5e8658..0000000
--- a/ecflow_4_0_7/view/src/not_enqueued.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "not_enqueued.h"
-#include "node.h"
-
-
-not_enqueued::not_enqueued(): node_alert<not_enqueued>("Not_Enqueued tasks")
-{
-}
-
-not_enqueued::~not_enqueued()
-{
-}
-
-bool not_enqueued::keep(node* n)
-{
- return false; // return n->isNotEnqueued();
-}
diff --git a/ecflow_4_0_7/view/src/not_enqueued.h b/ecflow_4_0_7/view/src/not_enqueued.h
deleted file mode 100644
index a5daed8..0000000
--- a/ecflow_4_0_7/view/src/not_enqueued.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef not_enqueued_H
-#define not_enqueued_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "node_alert.h"
-
-class node;
-
-class not_enqueued : public node_alert<not_enqueued> {
-public:
- not_enqueued();
- ~not_enqueued(); // Change to virtual if base class
-
-protected:
-
-private:
-
-// No copy allowed
-
- not_enqueued(const not_enqueued&);
- not_enqueued& operator=(const not_enqueued&);
-
- //
-
- virtual bool keep(node*);
-
-};
-
-inline void destroy(not_enqueued**) {}
-
-#endif
diff --git a/ecflow_4_0_7/view/src/observable.cc b/ecflow_4_0_7/view/src/observable.cc
deleted file mode 100644
index b7074ac..0000000
--- a/ecflow_4_0_7/view/src/observable.cc
+++ /dev/null
@@ -1,79 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#ifndef observable_H
-#include "observable.h"
-#endif
-
-#ifndef relation_H
-#include "relation.h"
-#endif
-
-#include "observer.h"
-
-observable::observable()
- : observed_(false)
-{
-}
-
-struct gone_iter : public observer_iterator {
- observable* o_;
- void next(observer* o) { o->gone(o_); }
-public:
- gone_iter(observable* o) : o_(o) {}
-};
-
-observable::~observable()
-{
- if(observed_) {
- gone_iter gi(this);
- relation::scan(this,gi);
- relation::remove(this);
- }
-}
-
-
-struct notify_iter : public observer_iterator {
- observable* o_;
- void next(observer* o) { o->notification(o_); }
-public:
- notify_iter(observable* o) : o_(o) {}
-};
-
-void observable::notify_observers()
-{
- if(observed_) {
- notify_iter ni(this);
- relation::scan(this,ni);
- }
-}
-
-struct adopt_iter : public observer_iterator {
- observable* o_;
- observable* n_;
- void next(observer* o) { o->adoption(o_,n_); }
-public:
- adopt_iter(observable* o,observable* n) : o_(o), n_(n) {}
-};
-
-void observable::notify_adoption(observable* n)
-{
- if(observed_ && n) {
- adopt_iter ai(this,n);
- relation::scan(this,ai);
- relation::replace(this,n);
- n->observed_ = true;
- }
-}
diff --git a/ecflow_4_0_7/view/src/observable.h b/ecflow_4_0_7/view/src/observable.h
deleted file mode 100644
index cfabbe4..0000000
--- a/ecflow_4_0_7/view/src/observable.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef observable_H
-#define observable_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#ifdef NO_BOOL
-#include "bool.h"
-#endif
-
-class observable {
-public:
-
- observable();
-
- virtual ~observable(); // Change to virtual if base class
-
- void notify_observers();
- void notify_adoption(observable*);
-
-private:
-
- observable(const observable&);
- observable& operator=(const observable&);
-
- bool observed_;
-
- friend class relation;
-};
-
-/* #include "observable.cc" */
-
-#endif
diff --git a/ecflow_4_0_7/view/src/observer.cc b/ecflow_4_0_7/view/src/observer.cc
deleted file mode 100644
index 31f7750..0000000
--- a/ecflow_4_0_7/view/src/observer.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#ifndef observer_H
-#include "observer.h"
-#endif
-
-#ifndef relation_H
-#include "relation.h"
-#endif
-
-
-observer::observer()
-{
-}
-
-observer::~observer()
-{
- relation::remove(this);
-}
-
-void observer::observe(observable* t)
-{
- relation::add(this,t);
-}
-
-int observer::forget(observable* t)
-{
- return relation::remove(this,t);
-}
-
-void observer::forget_all()
-{
- relation::remove(this);
-}
-
diff --git a/ecflow_4_0_7/view/src/observer.h b/ecflow_4_0_7/view/src/observer.h
deleted file mode 100644
index 99b535b..0000000
--- a/ecflow_4_0_7/view/src/observer.h
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef observer_H
-#define observer_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-class observable;
-class relation_data;
-
-class observer {
-public:
-
- observer();
-
- virtual ~observer(); // Change to virtual if base class
-
- void observe(observable*);
- int forget(observable*);
- void forget_all();
-
- virtual void notification(observable*) = 0;
- virtual void adoption(observable*,observable*) = 0;
- virtual void gone(observable*) = 0;
-
- void set_data(observable*,relation_data*);
- relation_data* get_data(observable*);
-
-private:
-
- observer(const observer&);
- observer& operator=(const observer&);
-};
-
-/* #include "observer.cc" */
-
-#endif
diff --git a/ecflow_4_0_7/view/src/opener.h b/ecflow_4_0_7/view/src/opener.h
deleted file mode 100644
index 3b5bea3..0000000
--- a/ecflow_4_0_7/view/src/opener.h
+++ /dev/null
@@ -1,126 +0,0 @@
-#ifndef opener_H
-#define opener_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-// Headers
-// #ifndef machine_H
-// #include <machine.h>
-// #endif
-
-// Forward declarations
-
-// class ostream;
-// typedef class _Pvts os_typespec; // Remove if not persistant
-
-//
-
-#include <Xm/Xm.h>
-#include "runnable.h"
-
-class opener : public runnable {
-public:
-
-// -- Exceptions
- // None
-
-// -- Contructors
-
- opener() : widget_(0) {}
-
-// -- Destructor
-
-
-// -- Convertors
- // None
-
-// -- Operators
- // None
-
-// -- Methods
-
- void show(Widget w) { widget_ = w; enable(); }
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
- // Uncomment for persistent, remove otherwise
- // static os_typespec* get_os_typespec();
-
-protected:
-
-// -- Members
- // None
-
-// -- Methods
-
- // void print(ostream&) const; // Change to virtual if base class
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-private:
-
-// No copy allowed
-
- opener(const opener&);
- opener& operator=(const opener&);
-
-// -- Members
-
- Widget widget_;
-
-// -- Methods
- // None
-
-// -- Overridden methods
-
- void run() { if(!XtIsManaged(widget_)) XtManageChild(widget_); disable();}
-
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-// -- Friends
-
- //friend ostream& operator<<(ostream& s,const opener& p)
- // { p.print(s); return s; }
-
-};
-
-inline void destroy(opener**) {}
-
-// If persistent, uncomment, otherwise remove
-//#ifdef _ODI_OSSG_
-//OS_MARK_SCHEMA_TYPE(opener);
-//#endif
-
-#endif
diff --git a/ecflow_4_0_7/view/src/option.cc b/ecflow_4_0_7/view/src/option.cc
deleted file mode 100644
index c411710..0000000
--- a/ecflow_4_0_7/view/src/option.cc
+++ /dev/null
@@ -1,205 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <stdlib.h>
-#include <inttypes.h>
-#include <string>
-#include <list>
-
-#ifndef option_H
-#include "option.h"
-#endif
-
-#ifndef translator_H
-#include "translator.h"
-#endif
-
-#ifndef choice_H
-#include "choice.h"
-#endif
-
-
-#include <Xm/Text.h>
-#include <Xm/ToggleB.h>
-
-#ifdef NO_BOOL
-#include "bool.h"
-#endif
-
-#include "ecflow.h"
-
-template<class T>
-option<T>::option(configurable* o,const str& name,const T& val):
- resource(o,name,translator<T,str>()(val))
-{
- value_ = translator<str,T>()(get());
-}
-
-template<class T>
-option<T>::~option()
-{
-}
-
-template<class T>
-bool option<T>::changed()
-{
- T old = value_;
- value_ = translator<str,T>()(get());
- return old != value_;
-}
-
-
-template<class T>
-void option<T>::put(const T& v)
-{
- set(translator<T,str>()(v));
-}
-
-//==========================================================
-
-inline
-void init_widget(Widget w,const str& s)
-{
- XmTextSetString(w,(char*)s.c_str());
-}
-
-inline
-void init_widget(Widget w,int n)
-{
- str s = translator<int,str>()(n);
- XmTextSetString(w,(char*)s.c_str());
-}
-
-inline
-void init_widget(Widget w,long n)
-{
- str s = translator<long,str>()(n);
- XmTextSetString(w,(char*)s.c_str());
-}
-
-inline
-void init_widget(Widget w,uint64_t n)
-{
- str s = translator<uint64_t,str>()(n);
- XmTextSetString(w,(char*)s.c_str());
-}
-
-inline
-void init_widget(Widget w,bool v)
-{
- XmToggleButtonSetState(w,v,False);
-}
-
-inline
-void init_widget(Widget,std::vector< std::string >&)
-{
-}
-
-inline
-void init_widget(Widget w,const choice& c)
-{
- WidgetList wl = 0;
- int count = 0;
-
- XtVaGetValues(w, XmNchildren,&wl, XtNnumChildren,&count, NULL);
-
- for(int i = 0; i < count; i++)
- XmToggleButtonSetState(wl[i],i == c,False);
-}
-
-
-inline
-str read_widget(Widget w,const str&)
-{
- char* p = XmTextGetString(w);
- str b(p);
- XtFree(p);
- return b;
-}
-
-inline
-int read_widget(Widget w,int)
-{
- char* p = XmTextGetString(w);
- int n = atol(p);
- XtFree(p);
- return n;
-}
-
-inline
-long read_widget(Widget w,long)
-{
- char* p = XmTextGetString(w);
- long n = atol(p);
- XtFree(p);
- return n;
-}
-
-inline
-long read_widget(Widget w,uint64_t)
-{
- char* p = XmTextGetString(w);
- uint64_t n = atoll(p);
- XtFree(p);
- return n;
-}
-
-inline
-bool read_widget(Widget w,bool)
-{
- return XmToggleButtonGetState(w);
-}
-
-inline
-ecf_list* read_widget(Widget,ecf_list*)
-{
- return 0;
-}
-
-inline
-std::vector< std::string > read_widget(Widget,std::vector< std::string >&)
-{
- std::vector< std::string > out;
- return out;
-}
-
-inline
-int read_widget(Widget w,const choice& c)
-{
- WidgetList wl = 0;
- int count = 0;
-
- XtVaGetValues(w, XmNchildren,&wl, XtNnumChildren,&count, NULL);
-
- for(int i = 0; i < count; i++)
- if(XmToggleButtonGetState(wl[i]) )
- return i;
- return c;
-}
-
-template<class T>
-void option<T>::initWidget(Widget w)
-{
- init_widget(w,value_);
-}
-
-template<class T>
-bool option<T>::readWidget(Widget w)
-{
- T b = read_widget(w,value_);
- bool x = (b != value_);
- if(x) put(b);
- return x;
-}
diff --git a/ecflow_4_0_7/view/src/option.h b/ecflow_4_0_7/view/src/option.h
deleted file mode 100644
index 6865c59..0000000
--- a/ecflow_4_0_7/view/src/option.h
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef option_H
-#define option_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "resource.h"
-
-template<class T>
-class option : public resource {
-public:
- option(configurable*,const str&,const T&);
-
- ~option(); // Change to virtual if base class
-
- operator const T&() const { return value_; }
- const T& operator=(const T& v) { put(v); return value_; }
-
- virtual void initWidget(Widget);
- virtual bool readWidget(Widget);
- virtual bool changed();
-
-private:
-
- option(const option<T>&);
- option<T>& operator=(const option<T>&);
-
- T value_;
-
- void put(const T&);
-};
-
-#if defined(__GNUC__) || defined(hpux) || defined(_AIX)
-#include "option.cc"
-#endif
-#endif
diff --git a/ecflow_4_0_7/view/src/option_panel.cc b/ecflow_4_0_7/view/src/option_panel.cc
deleted file mode 100644
index 64c55f8..0000000
--- a/ecflow_4_0_7/view/src/option_panel.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "option_panel.h"
-#include "node.h"
-#include "host.h"
-#include "ecflowview.h"
-#include <Xm/Label.h>
-#include <Xm/Text.h>
-#include <Xm/ToggleB.h>
-extern "C" {
-#include "xec.h"
-}
-
-option_panel::option_panel(panel_window& w):
- panel(w)
-{
-}
-
-option_panel::~option_panel()
-{
-}
-
-void option_panel::create (Widget parent, char *widget_name )
-{
- option_form_c::create(parent,widget_name);
-}
-
-void option_panel::clear()
-{
-}
-
-void option_panel::show(node& n)
-{
- resource::init(n.serv(),*this);
- freeze();
-}
-
-Boolean option_panel::enabled(node& n)
-{
- return n.type() == NODE_SUPER;
-}
-
-configurable* option_panel::owner()
-{
- return get_node() ? &(get_node()->serv()) : 0;
-}
-
diff --git a/ecflow_4_0_7/view/src/option_panel.h b/ecflow_4_0_7/view/src/option_panel.h
deleted file mode 100644
index 8c25aad..0000000
--- a/ecflow_4_0_7/view/src/option_panel.h
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef option_panel_H
-#define option_panel_H
-
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "uioption.h"
-
-#ifndef panel_H
-#include "panel.h"
-#endif
-
-#ifndef pref_editor_H
-#include "pref_editor.h"
-#endif
-
-class option_panel : public panel, public option_form_c , public pref_editor{
-public:
-
- option_panel(panel_window&);
-
- ~option_panel(); // Change to virtual if base class
-
- virtual const char* name() const { return "Options"; }
- virtual void show(node&);
- virtual void clear();
- virtual Boolean enabled(node&);
-
- virtual Widget widget() { return option_form_c::xd_rootwidget(); }
-
- virtual void create (Widget parent, char *widget_name = NULL);
-
-private:
-
- option_panel(const option_panel&);
- option_panel& operator=(const option_panel&);
-
- virtual void changedCB( Widget w, XtPointer ) { pref_editor::changed(w); }
- virtual void useCB( Widget w, XtPointer ) { pref_editor::use(w); }
-
- virtual Widget form() { return form_; }
- virtual configurable* owner();
-};
-
-inline void destroy(option_panel**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/output.cc b/ecflow_4_0_7/view/src/output.cc
deleted file mode 100644
index 6fb2084..0000000
--- a/ecflow_4_0_7/view/src/output.cc
+++ /dev/null
@@ -1,221 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #18 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "output.h"
-#include "node.h"
-#include "host.h"
-#include <Xm/Text.h>
-#include <Xm/TextStrSoP.h>
-#include <Xm/List.h>
-#include "ecf_node.h"
-extern "C" {
-#include "xec.h"
-}
-
-#include <sys/types.h>
-#include <sys/stat.h>
-
-output::output(panel_window& w):
- text_window(true),
- panel(w),
- file_(0x0)
-{
-}
-
-output::~output()
-{
- if(file_)
- free(file_);
-}
-
-void output::create (Widget parent, char *widget_name )
-{
- output_form_c::create(parent,widget_name);
-}
-
-void output::clear()
-{
- if(file_) free(file_);
- file_ = 0x0;
- XmTextSetString(name_,(char*) "");
- XmListDeleteAllItems(list_);
- //active(False);
- text_window::clear();
-}
-
-class output_lister : public lister<ecf_dir> {
- Widget list_;
- bool sort() { return true; }
- bool compare(ecf_dir&,ecf_dir&);
- void next(ecf_dir&);
-public:
- output_lister(Widget l) : list_(l) {}
-};
-
-void output_lister::next(ecf_dir& d)
-{
- if(S_ISREG(d.mode))
- {
- time_t t = d.mtime;
- time_t now = time(0);
-
- int delta = now - t;
- if(delta<0) delta = 0;
-
- char buf[80];
- strcpy(buf,"Right now");
-
- if(delta >=1 && delta < 60)
- {
- sprintf(buf,"%d second%s ago",delta,delta>1?"s":"");
- }
-
- if(delta >= 60 && delta < 60*60)
- {
- sprintf(buf,"%d minute%s ago",delta/60,delta/60>1?"s":"");
- }
-
- if(delta >= 60*60 && delta < 60*60*24)
- {
- sprintf(buf,"%d hour%s ago",delta/60/60,delta/60/60>1?"s":"");
- }
-
- if(delta >= 60*60*24)
- {
- sprintf(buf,"%d day%s ago",delta/60/60/24,delta/60/60/24>1?"s":"");
- }
-
- xec_VaAddListItem(list_,(char*) "%-60s (%s)",d.name_,buf);
- }
-}
-
-bool output_lister::compare(ecf_dir& a,ecf_dir& b)
-{
- return a.mtime > b.mtime;
-}
-
-class search_me : public runnable {
- find& find_;
-
- void run() {
- /* text case regexp back wrap */
- find_.search("System Billing Units",true,false,false,true);
- find_.search("smscomplete",true,false,false,true);
- find_.search("smsabort",true,false,false,true);
- // display init but not appreciated when updating for tail:
- // find_.search("ecflow_client",true,false,false,true);
- find_.search("xcomplete",true,false,false,true);
- find_.search("xabort",true,false,false,true);
- find_.search(" --complete",true,false,false,true);
- find_.search(" --abort",true,false,false,true);
- find_.no_message();
- find_.pending(0);
- delete this;
- }
-
-public:
- search_me(find& f) : find_(f) { find_.pending(this); enable();}
-};
-
-void output::show(node& n)
-{
- std::string jobout = n.variable("ECF_JOBOUT");
- if (!n.__node__())
- jobout = n.variable("SMSJOBOUT");
- else if (!n.__node__()) return;
- else if (!n.__node__()->get_node()) return;
- else n.__node__()->get_node()->variableSubsitution(jobout);
-
- if(jobout == ecf_node::none()) {
- clear();
- return;
- }
-
- /* output variable may contain micro */
-
- if(file_) free(file_);
- file_ = strdup(jobout.c_str());
- load(n);
- XmListDeleteAllItems(list_);
-
- output_lister ol(list_);
- n.serv().dir(n,file_,ol);
-
- std::string remote = n.variable("ECF_OUT");
- std::string job = n.variable("ECF_JOB");
- if (!n.__node__()) {
- remote = n.variable("SMSOUT");
- job = n.variable("SMSJOB");
- }
- if (!remote.empty() && !job.empty()) {
- /* display both remote and local dir */
- if (remote == job) {
- output_lister rem(list_);
- n.serv().dir(n,job.c_str(),rem);
- }
- }
- new search_me(*this);
-}
-
-void output::load(node& n)
-{
- if(file_)
- XmTextSetString(name_,(char*)file_);
- else
- clear();
-
- if(file_) {
- tmp_file f = n.serv().file(n,file_);
- text_window::load(f);
- } else {
- tmp_file f = n.serv().output(n);
- text_window::load(f);
- }
-}
-
-void output::updateCB(Widget,XtPointer data)
-{
- if(get_node())
- show(*get_node());
- else
- clear();
- XmTextShowPosition(text_,XmTextGetLastPosition(text_));
-}
-
-void output::browseCB(Widget,XtPointer data)
-{
- XmListCallbackStruct *cb = (XmListCallbackStruct *) data;
- if(file_) free(file_);
-
- char *p = xec_GetString(cb->item);
- char buf[1024];
- sscanf(p,"%s",buf);
- XtFree(p);
-
- file_ = strdup(buf);
-
- if(get_node())
- load(*get_node());
- else
- clear();
-}
-
-Boolean output::enabled(node& n)
-{
- if (n.type() != NODE_TASK && n.type() != NODE_ALIAS) return False;
- if (!n.__node__())
- return n.variable("SMSJOBOUT") != ecf_node::none();
- return n.variable("ECF_JOBOUT") != ecf_node::none();
-}
diff --git a/ecflow_4_0_7/view/src/output.h b/ecflow_4_0_7/view/src/output.h
deleted file mode 100644
index 63d9350..0000000
--- a/ecflow_4_0_7/view/src/output.h
+++ /dev/null
@@ -1,67 +0,0 @@
-#ifndef output_H
-#define output_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "uioutput.h"
-
-#ifndef panel_H
-#include "panel.h"
-#endif
-
-#include "host.h"
-#include "text_window.h"
-
-
-class output : public output_form_c, public text_window, public panel {
-public:
- output(panel_window&);
-
- ~output(); // Change to virtual if base class
-
- virtual const char* name() const { return "Output"; }
- virtual void show(node&);
- virtual void clear();
- virtual Boolean enabled(node&);
- virtual Widget widget() { return output_form_c::xd_rootwidget(); }
-
- virtual Widget tools() { return tools_; }
- virtual Widget text() { return text_; }
- virtual void create (Widget parent, char *widget_name = 0 );
-
-private:
- output(const output&);
- output& operator=(const output&);
-
- char *file_;
-
- void load(node&);
-
- virtual void browseCB(Widget,XtPointer);
- virtual void updateCB(Widget,XtPointer);
- virtual void externalCB(Widget ,XtPointer )
- { text_window::open_viewer();}
- virtual void searchCB(Widget ,XtPointer )
- { text_window::open_search();}
-
- virtual bool can_print() { return true; }
- virtual bool can_save() { return true; }
- virtual void print() { text_window::print(); }
- virtual void save() { text_window::save(); }
-};
-
-inline void destroy(output**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/panel.cc b/ecflow_4_0_7/view/src/panel.cc
deleted file mode 100644
index ad81de3..0000000
--- a/ecflow_4_0_7/view/src/panel.cc
+++ /dev/null
@@ -1,125 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <stdio.h>
-#include <Xm/Xm.h>
-#include "Hyper.h"
-
-
-#include "panel.h"
-#include "node.h"
-#include "host.h"
-#include "panel_window.h"
-#include "tip.h"
-extern "C" {
-#include "xec.h"
-}
-
-panel::panel(panel_window& owner):
- next_(0),
- node_(0),
- owner_(owner)
-{
-}
-
-panel::~panel()
-{
- delete next_;
-}
-
-panel_factory* panel_factory::factories_[PANEL_MAX_FACTORIES];
-
-panel_factory::panel_factory(int n)
-{
- if(n < 0 || n >= PANEL_MAX_FACTORIES || factories_[n])
- fprintf(stderr, "panel_factory::panel_factory: internal error %d\n",n);
- factories_[n] = this;
-}
-
-panel* panel_factory::create_all(panel_window& w,Widget parent)
-{
- panel *first = 0;
- for(int i = 0; i < PANEL_MAX_FACTORIES ; i++)
- if(factories_[i])
- {
- panel* x = factories_[i]->create(w,parent);
- XtManageChild(x->widget());
-
- if(x->tools())
- tip::makeTips(x->tools());
-
- x->next_ = first;
- first = x;
- }
- return first;
-}
-
-void panel::update()
-{
- if(owner_.frozen())
- return;
-
- if(node_)
- show(*node_);
- else
- clear();
-}
-
-void panel::post_update()
-{
- if(!owner_.frozen())
- enable();
-}
-
-void panel::run()
-{
- update();
- disable();
-}
-
-void panel::detach()
-{
- owner_.detach();
-}
-
-void panel::freeze()
-{
- owner_.freeze();
-}
-
-void panel::hyper(Widget,XtPointer data,node *n)
-{
- hyperCallbackStruct* cb = (hyperCallbackStruct*)data;
- if(n == 0) n = get_node();
- if(n) n = n->find(cb->text);
-
- if(n == 0)
- {
- host* h = host::find(cb->text);
- if(h) n = h->top();
- }
-
- if(n) {
- if(cb->event->xbutton.button == 2)
- owner_.new_window(n);
- else
- selection::notify_new_selection(n);
- }
-}
-
-void panel::submit()
-{
- owner_.submit();
-}
diff --git a/ecflow_4_0_7/view/src/panel.h b/ecflow_4_0_7/view/src/panel.h
deleted file mode 100644
index 3c19b08..0000000
--- a/ecflow_4_0_7/view/src/panel.h
+++ /dev/null
@@ -1,110 +0,0 @@
-#ifndef panel_H
-#define panel_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "ecflowview.h"
-#include "runnable.h"
-#include "observer.h"
-
-class node;
-class panel_window;
-
-class panel : public runnable, public observer {
-public:
-
- panel(panel_window&);
-
- virtual ~panel(); // Change to virtual if base class
-
- virtual void update();
- virtual void detach();
- virtual void freeze();
- virtual void submit();
- virtual void post_update();
-
- virtual void copy(panel*) {}
-
- virtual void clear() = 0;
- virtual void show(node&) = 0;
- virtual void changed(node& n) { show(n); }
- virtual Boolean enabled(node& n) { return False; }
-
- virtual const char* name() const { return "(none)"; };
- virtual Widget widget() = 0;
- virtual Widget menus(Widget) { return 0; }
- virtual Widget tools() { return 0; }
-
-
- virtual void print() {}
- virtual void save() {}
-
- virtual bool can_print() { return false; }
- virtual bool can_save() { return false; }
-
-protected:
-
- node* get_node() { return node_; }
- void hyper(Widget,XtPointer, node* = 0);
-
-private:
-
- panel(const panel&);
- panel& operator=(const panel&);
-
- panel* next_;
- node* node_;
- panel_window& owner_;
-
- void run();
- void notification(observable*) { post_update(); }
- void gone(observable*) { post_update(); }
- void adoption(observable*,observable*) { post_update(); }
-
- friend class panel_factory;
- friend class panel_window;
-};
-
-inline void destroy(panel**) {}
-
-#ifndef panel_factories_H
-#include "panel_factories.h"
-#endif
-
-class panel_factory {
- static panel_factory* factories_[PANEL_MAX_FACTORIES];
-public:
- panel_factory(int);
- virtual panel* create(panel_window&,Widget) = 0;
- static panel* create_all(panel_window&,Widget);
-};
-
-template<class T>
-class panel_maker : public panel_factory {
-public:
- panel_maker(int n) : panel_factory(n) {}
- virtual panel* create(panel_window&,Widget);
-};
-
-template<class T>
-panel* panel_maker<T>::create(panel_window& w,Widget parent)
-{
- T* p = new T(w);
- p->create(parent,(char*)p->name());
- return p;
-}
-
-#endif
diff --git a/ecflow_4_0_7/view/src/panel_factories.h b/ecflow_4_0_7/view/src/panel_factories.h
deleted file mode 100644
index c646cca..0000000
--- a/ecflow_4_0_7/view/src/panel_factories.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #4 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#define PANEL_INFO 0
-#define PANEL_MANUAL (PANEL_INFO+1)
-#define PANEL_SCRIPT (PANEL_MANUAL+1)
-#define PANEL_JOB (PANEL_SCRIPT+1)
-#define PANEL_JOBSTATUS (PANEL_JOB+1)
-#define PANEL_OUTPUT (PANEL_JOBSTATUS+1)
-#define PANEL_WHY (PANEL_OUTPUT+1)
-#define PANEL_TRIGGER (PANEL_WHY+1)
-#define PANEL_JOBCHECK (PANEL_TRIGGER+1)
-#define PANEL_TIMETABLE (PANEL_JOBCHECK+1)
-#define PANEL_VARIABLES (PANEL_TIMETABLE+1)
-#define PANEL_EDIT_TASK (PANEL_VARIABLES+1)
-#define PANEL_EDIT_LABEL (PANEL_EDIT_TASK+1)
-#define PANEL_EDIT_LIMIT (PANEL_EDIT_LABEL+1)
-#define PANEL_EDIT_VARIABLE (PANEL_EDIT_LIMIT+1)
-#define PANEL_EDIT_METER (PANEL_EDIT_VARIABLE+1)
-#define PANEL_EDIT_REPEAT (PANEL_EDIT_METER+1)
-#define PANEL_HISTORY (PANEL_EDIT_REPEAT+1)
-#define PANEL_MESSAGES (PANEL_HISTORY+1)
-#define PANEL_SUITES (PANEL_MESSAGES+1)
-#define PANEL_USERS (PANEL_SUITES+1)
-#define PANEL_ZOMBIES (PANEL_USERS+1)
-#define PANEL_ECF_OPTIONS (PANEL_ZOMBIES+1)
-
-#define PANEL_MAX_FACTORIES (PANEL_ECF_OPTIONS+1)
diff --git a/ecflow_4_0_7/view/src/panel_window.cc b/ecflow_4_0_7/view/src/panel_window.cc
deleted file mode 100644
index 3eddf9e..0000000
--- a/ecflow_4_0_7/view/src/panel_window.cc
+++ /dev/null
@@ -1,432 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <stdio.h>
-#include "gui.h"
-#include "panel_window.h"
-#include "panel.h"
-#include "node.h"
-#include "globals.h"
-#include "Tab.h"
-#include <Xm/ToggleB.h>
-#include <Xm/PushB.h>
-
-const char* kDefault = "Info";
-
-extern "C" {
-#include "xec.h"
-}
-
-panel_window::panel_window():
- panels_(0),
- node_(0),
- current_(0)
-{
- create(gui::top());
- set_node(0,"Info",true);
- load_size();
- XtRealizeWidget(panel_top);
-}
-
-panel_window::panel_window(panel_window* other):
- panels_(0),
- node_(0),
- current_(0)
-{
- create(gui::top());
-
- panel* p = panels_;
- panel* o = other->panels_;
-
- while(p && o)
- {
- p->copy(o);
- p = p->next_;
- o = o->next_;
- }
-
- other->save_size();
- set_node(other->node_,XtName(TabGetCurrent(other->tab_)),true);
- load_size();
- XtRealizeWidget(panel_top);
- XmToggleButtonSetState(detached_,other->detached(),True);
- XmToggleButtonSetState(frozen_,other->frozen(),True);
- XmToggleButtonSetState(close_on_apply_,
- XmToggleButtonGetState(other->close_on_apply_),True);
-}
-
-panel_window::panel_window(node* n,bool detached,bool frozen,const char* tab):
- panels_(0),
- node_(0),
- current_(0)
-{
- create(gui::top());
- set_node(n,tab,true);
- load_size();
- XtRealizeWidget(panel_top);
- XmToggleButtonSetState(detached_,detached,True);
- XmToggleButtonSetState(frozen_,frozen,True);
-}
-
-panel_window::panel_window(panel_window* other,node* n,bool detached,bool frozen):
- panels_(0),
- node_(0),
- current_(0)
-{
- create(gui::top());
-
- panel* p = panels_;
- panel* o = other->panels_;
-
- while(p && o)
- {
- p->copy(o);
- p = p->next_;
- o = o->next_;
- }
-
- other->save_size();
- set_node(n,XtName(TabGetCurrent(other->tab_)),true);
- load_size();
- XtRealizeWidget(panel_top);
- XmToggleButtonSetState(detached_,detached,True);
- XmToggleButtonSetState(frozen_,frozen,True);
-}
-
-
-panel_window::~panel_window()
-{
- save_size();
- delete panels_;
- XtDestroyWidget(xd_rootwidget());
-}
-
-void panel_window::save_size()
-{
- Dimension w,h;
-
- XtVaGetValues(form_,
- XmNwidth, &w,
- XmNheight,&h,
- NULL);
-
- char *n = XtName(TabGetCurrent(tab_));
- char wname[1024]; sprintf(wname,"panel_%s_width", n);
- char hname[1024]; sprintf(hname,"panel_%s_heigth",n);
-
- globals::set_resource(wname,w);
- globals::set_resource(hname,h);
-}
-
-void panel_window::load_size()
-{
- Dimension w,h;
-
- char *n = XtName(TabGetCurrent(tab_));
- char wname[1024]; sprintf(wname,"panel_%s_width", n);
- char hname[1024]; sprintf(hname,"panel_%s_heigth",n);
-
- w = globals::get_resource(wname,500);
- h = globals::get_resource(hname,500);
-
- XtVaSetValues(form_,
- XmNwidth, w,
- XmNheight,h,
- NULL);
-}
-
-void panel_window::create (Widget parent, char *widget_name)
-{
- panel_top_c::create(parent,widget_name);
- panels_ = panel_factory::create_all(*this,tab_);
- XtAddCallback(tab_, XmNvalueChangedCallback, tabCB, this);
-}
-
-void panel_window::tabCB(Widget w,XtPointer call)
-{
- TabCallbackStruct* cb = (TabCallbackStruct*)call;
- set(find(cb->widget));
- if (!current_) return;
- if(node_)
- current_->show(*node_);
- else
- current_->clear();
-}
-
-void panel_window::set_tab(const char* tab)
-{
- panel *p = find(tab);
- if (p) {
- TabSetCurrent(tab_,p->widget(),False);
- current_ = p;
- }
-}
-
-void panel_window::tabCB(Widget w, XtPointer client, XtPointer call)
-{
- panel_window* i = (panel_window*)client;
- i->tabCB(w,call);
-}
-
-void panel_window::selection_cleared()
-{
- if(detached()) return;
- set_node(0,0,true);
-}
-
-void panel_window::title()
-{
- std::string name;
- name = node_ ? node_->node_name() : "-";
- if(detached()) name += " (detached)";
- if(frozen()) name += " (frozen)";
- XtVaSetValues(xd_rootwidget(),XmNtitle,name.c_str(),NULL);
-
- if (!current_) return;
-
- name = std::string(current_->name()) + ":";
- if (node_)
- name += node_->node_name();
- else
- name += "-";
- set_menu(name.c_str());
-}
-
-void panel_window::new_selection(node& n)
-{
- if(detached()) return;
- set_node(&n,0,true);
-}
-
-void panel_window::set(panel* c)
-{
- if (!c) return;
-
- if(current_ && current_ != c)
- current_->clear();
-
- current_ = c;
-
- XtUnmanageChild(tab_);
-
- Widget w = current_->widget();
-
- panel* p = panels_;
- while(p) {
-
- bool ok = (node_?p->enabled(*node_):false);
- if(ok)
- XtManageChild(p->widget());
- else
- XtUnmanageChild(p->widget());
- p = p->next_;
- }
-
- if(w && !XtIsManaged(w))
- {
- current_ = find(kDefault);
- w = current_->widget();
- XtManageChild(w);
- }
-
- TabSetCurrent(tab_,w,False);
-
- p = panels_;
- while(p) {
- Widget m = p->menus(menubar_);
- if(m) {
- if(p == current_)
- XtManageChild(m);
- else
- XtUnmanageChild(m);
- }
- p = p->next_;
- }
-
- XtManageChild(tab_);
-
- XtSetSensitive(save_,current_->can_save());
- XtSetSensitive(print_,current_->can_print());
-}
-
-void panel_window::cloneCB(Widget w,XtPointer)
-{
- panel_window *p = new panel_window(this);
- p->xd_show();
-}
-
-void panel_window::unmapCB(Widget,XtPointer)
-{
- delete this;
-}
-
-void panel_window::mapCB(Widget,XtPointer)
-{
-}
-
-void panel_window::nodeCB(Widget,XtPointer data)
-{
-// XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct*) data;
- /* detached_ = !cb->set; */
- title();
-}
-
-void panel_window::freezeCB(Widget,XtPointer data)
-{
-// XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct*) data;
- /* frozen_ = !cb->set; */
- title();
-}
-
-void panel_window::xd_show()
-{
- Map();
-}
-
-void panel_window::notification(observable* n)
-{
- set(current_);
- current_->changed(*node_);
-}
-
-void panel_window::gone(observable* n)
-{
- set_node(0,0,true);
-}
-
-void panel_window::adoption(observable* o,observable *n)
-{
- set_node((node*)n,0,!frozen());
-}
-
-panel* panel_window::find(Widget w)
-{
- if(!w) w = TabGetCurrent(tab_);
- panel* p = panels_;
- while(p)
- {
- if(p->widget() == w)
- return p;
- p = p->next_;
- }
- return 0;
-}
-
-void panel_window::set_node(node* n,const char* tab,bool update)
-{
- // if(n == node_) return;
-
- forget(node_);
-
- panel* p = panels_;
- while(p)
- {
- p->node_ = n;
- p = p->next_;
- }
- node_ = n;
- observe(node_);
-
- if(tab) set_tab(tab);
- if(n && !current_->enabled(*n))
- set_tab(kDefault);
-
- if(update) {
- if(n)
- current_->show(*n);
- else
- current_->clear();
- set(current_);
- title();
- }
-}
-
-void panel_window::detach()
-{
- XmToggleButtonSetState(detached_,True, True);
-}
-
-void panel_window::freeze()
-{
- XmToggleButtonSetState(detached_,True, True);
- XmToggleButtonSetState(frozen_,True,True);
-}
-
-
-void panel_window::new_window(node* n,const char* tab,bool detached,bool frozen)
-{
- panel_window *p = new panel_window(n,detached,frozen,tab);
- p->xd_show();
-}
-
-void panel_window::new_window(node* n)
-{
- panel_window *p = new panel_window(this,n,true,true);
- p->xd_show();
-}
-
-panel* panel_window::find(const char* name)
-{
- panel* p = panels_;
- while(p)
- {
- bool ok = node_?p->enabled(*node_):false;
- if(ok && (strcmp(p->name(),name) == 0))
- return p;
- p = p->next_;
- }
-
- p = panels_;
- while(p)
- {
- if(strcmp(p->name(),kDefault) == 0)
- return p;
- p = p->next_;
- }
-
- abort();
- return 0;
-}
-
-void panel_window::submit()
-{
- if(XmToggleButtonGetState(close_on_apply_))
- delete this;
-}
-
-void panel_window::resizeCB(Widget,XtPointer)
-{
- save_size();
-}
-
-bool panel_window::frozen()
-{
- return XmToggleButtonGetState(frozen_);
-}
-
-bool panel_window::detached()
-{
- return XmToggleButtonGetState(detached_);
-}
-
-void panel_window::printCB(Widget,XtPointer)
-{
- current_->print();
-}
-
-void panel_window::saveCB(Widget,XtPointer)
-{
- current_->save();
-}
diff --git a/ecflow_4_0_7/view/src/panel_window.h b/ecflow_4_0_7/view/src/panel_window.h
deleted file mode 100644
index 78b5520..0000000
--- a/ecflow_4_0_7/view/src/panel_window.h
+++ /dev/null
@@ -1,118 +0,0 @@
-#ifndef panel_window_H
-#define panel_window_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#ifndef uipanel_H
-#include "uipanel.h"
-#endif
-
-#ifndef selection_H
-#include "selection.h"
-#endif
-
-#ifndef panel_H
-#include "panel.h"
-#endif
-
-#ifndef observer_H
-#include "observer.h"
-#endif
-
-#ifndef window_H
-#include "window.h"
-#endif
-
-
-class panel_window
- : public panel_top_c
- , public selection
- , public observer
- , public window
-{
-public:
- panel_window();
- panel_window(node*,bool,bool,const char*);
- panel_window(panel_window*);
- panel_window(panel_window*,node*,bool,bool);
-
- ~panel_window(); // Change to virtual if base class
-
- bool frozen();
- bool detached();
-
- void detach();
- void freeze();
-
- void title();
- void show(const char*);
- void new_window( node*);
- void submit();
-
- virtual void create (Widget parent, char *widget_name = 0);
- virtual Widget shell() { return _xd_rootwidget; }
-
- // From selection
- virtual void new_selection(node&);
- virtual void selection_cleared();
-
- // From panel_top_c
- void cloneCB(Widget,XtPointer);
- void unmapCB(Widget,XtPointer);
- void mapCB(Widget,XtPointer);
- void nodeCB(Widget,XtPointer);
- void freezeCB(Widget,XtPointer);
- void resizeCB(Widget,XtPointer);
-
- virtual void xd_show();
-
- static panel_window* find(node*);
- static void new_window(node*,const char*,bool,bool);
-
-private:
- panel_window(const panel_window&);
- panel_window& operator=(const panel_window&);
-
- panel* panels_;
- node* node_;
- panel* current_;
-
- void set(panel*);
- void set_tab(const char*);
- void copy(panel_window&);
- virtual void tabCB(Widget,XtPointer);
-
- void set_node(node*,const char*,bool);
-
- panel* find(const char*);
- panel* find(Widget);
-
- void save_size();
- void load_size();
-
- // From observer<node>
- virtual void notification(observable*);
- virtual void gone(observable*);
- virtual void adoption(observable*,observable*);
-
- virtual void printCB(Widget,XtPointer);
- virtual void saveCB(Widget,XtPointer);
-
- static void tabCB(Widget,XtPointer,XtPointer);
-};
-
-inline void destroy(panel_window**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/parser.cc b/ecflow_4_0_7/view/src/parser.cc
deleted file mode 100644
index ee5dcec..0000000
--- a/ecflow_4_0_7/view/src/parser.cc
+++ /dev/null
@@ -1,101 +0,0 @@
-
-#ifndef parser_H
-#include "parser.h"
-#endif
-
-#ifndef gui_H
-#include "gui.h"
-#endif
-
-#ifndef menus_H
-#include "menus.h"
-#endif
-
-#ifndef log_event_H
-#include "log_event.h"
-#endif
-
-#if 0
-#ifndef __sgi
-inline const char* gettxt(const char* a,const char* b) { return b; }
-#endif
-#endif
-
-/* #define YYDEBUG */
-/* #ifdef linux
-#undef YYDEBUG
-#endif
-*/
-#ifndef error_H
-#include "error.h"
-#endif
-
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-extern "C" {
- extern int yylineno;
- extern int yydebug;
- extern int yyone;
- extern FILE* yyin;
- extern int yyparse();
-}
-
-void parser::parse(const char* fname)
-{
- char buf[1024];
-
- yydebug = getenv("YYDEBUG") != 0;
- yylineno = 0;
-
- int z = strlen(fname);
- if(fname[z-1] == 'Z' && fname[z-2] == '.')
- {
- sprintf(buf,"|zcat %s",fname);
- fname = buf;
- }
-
- if(fname[z-1] == 'z' && fname[z-2] == 'g' && fname[z-3] == '.')
- {
- sprintf(buf,"|zcat %s",fname);
- fname = buf;
- }
-
- yyin = (fname[0] == '|') ? popen(fname+1,"r") : fopen(fname, "r");
- if(yyin)
- {
- yyparse();
- if(fname[0] == '|') pclose(yyin); else fclose(yyin);
- }
- else gui::syserr(fname);
-}
-
-void parser::parse(FILE *f)
-{
- extern int yylineno;
- yylineno = 0;
- yydebug = getenv("YYDEBUG") != 0;
- yyin = f;
- yyparse();
-}
-
-void parser::parse1(FILE *f)
-{
- yyone = 1;
- yydebug = getenv("YYDEBUG") != 0;
- yyparse();
- yyone = 0;
-}
diff --git a/ecflow_4_0_7/view/src/parser.h b/ecflow_4_0_7/view/src/parser.h
deleted file mode 100644
index 54756a6..0000000
--- a/ecflow_4_0_7/view/src/parser.h
+++ /dev/null
@@ -1,125 +0,0 @@
-#ifndef parser_H
-#define parser_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-// Headers
-// #ifndef machine_H
-// #include <machine.h>
-// #endif
-
-// Forward declarations
-
-// class ostream;
-// typedef class _Pvts os_typespec; // Remove if not persistant
-
-//
-
-#include <stdio.h>
-
-class parser {
-public:
-
-// -- Exceptions
- // None
-
-// -- Contructors
-
- parser();
-
-// -- Destructor
-
- ~parser(); // Change to virtual if base class
-
-// -- Convertors
- // None
-
-// -- Operators
- // None
-
-// -- Methods
- // None
-
-// -- Overridden methods
- // None
-
-// -- Class members
-
- static void parse(const char*);
- static void parse(FILE*);
- static void parse1(FILE*);
-
-// -- Class methods
- // None
-
- // Uncomment for persistent, remove otherwise
- // static os_typespec* get_os_typespec();
-
-protected:
-
-// -- Members
- // None
-
-// -- Methods
-
- // void print(ostream&) const; // Change to virtual if base class
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-private:
-
-// No copy allowed
-
- parser(const parser&);
- parser& operator=(const parser&);
-
-// -- Members
- // None
-
-// -- Methods
- // None
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-// -- Friends
-
- //friend ostream& operator<<(ostream& s,const parser& p)
- // { p.print(s); return s; }
-
-};
-
-inline void destroy(parser**) {}
-
-// If persistent, uncomment, otherwise remove
-//#ifdef _ODI_OSSG_
-//OS_MARK_SCHEMA_TYPE(parser);
-//#endif
-
-#endif
diff --git a/ecflow_4_0_7/view/src/passwrd.cc b/ecflow_4_0_7/view/src/passwrd.cc
deleted file mode 100644
index 932eb1a..0000000
--- a/ecflow_4_0_7/view/src/passwrd.cc
+++ /dev/null
@@ -1,71 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <stdio.h>
-#include <stdarg.h>
-#include "passwrd.h"
-#include "gui.h"
-#include "str.h"
-extern "C" {
-#include "xec.h"
-}
-#include "ecflowview.h"
-
-#include <Xm/Text.h>
-
-#ifdef linux
-extern "C" char* cuserid(char*);
-#endif
-
-
-passwrd::passwrd()
-{
- create(gui::top());
-}
-
-passwrd::~passwrd()
-{
-}
-
-
-Boolean passwrd::ask(const str& title,str& user,str& pass)
-{
- return instance().prompt(title,user,pass);
-}
-
-Boolean passwrd::prompt(const str& title,str& user,str& pass)
-{
-
- XmTextSetString(user_,(char*)(user.c_str()[0]?user.c_str():cuserid(0)));
- XmTextSetString(passwd_,(char*)(pass.c_str()));
-
- if(modal(title.c_str(),True))
- {
- char *p = XmTextGetString(user_);
- user = p;
- XtFree(p);
-
- p = XmTextGetString(passwd_);
- pass = p;
- XtFree(p);
- return True;
- }
-
- return False;
-}
-
-void passwrd::modifyCB( Widget, XtPointer )
-{
-}
diff --git a/ecflow_4_0_7/view/src/passwrd.h b/ecflow_4_0_7/view/src/passwrd.h
deleted file mode 100644
index 4332a8c..0000000
--- a/ecflow_4_0_7/view/src/passwrd.h
+++ /dev/null
@@ -1,116 +0,0 @@
-#ifndef passwrd_H
-#define passwrd_H
-
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "uipasswd.h"
-#include "dialog.h"
-
-class str;
-
-class passwrd : public dialog<passwrd,passwd_shell_c> {
-public:
-
-// -- Exceptions
- // None
-
-// -- Contructors
-
- passwrd();
-
-// -- Destructor
-
- ~passwrd(); // Change to virtual if base class
-
-// -- Convertors
- // None
-
-// -- Operators
- // None
-
-// -- Methods
- // None
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
-
- static Boolean ask(const str&,str&,str&);
-
- // Uncomment for persistent, remove otherwise
- // static os_typespec* get_os_typespec();
-
-protected:
-
-// -- Members
- // None
-
-// -- Methods
-
- // void print(ostream&) const; // Change to virtual if base class
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-private:
-
-// No copy allowed
-
- passwrd(const passwrd&);
- passwrd& operator=(const passwrd&);
-
-
-
-// -- Methods
-
- Boolean prompt(const str&,str&,str&);
-
-// -- Overridden methods
-
- virtual void modifyCB( Widget, XtPointer );
-
-// -- Class members
-
-
-// -- Class methods
- // None
-
-// -- Friends
-
- //friend ostream& operator<<(ostream& s,const passwrd& p)
- // { p.print(s); return s; }
-
-};
-
-inline void destroy(passwrd**) {}
-
-// If persistent, uncomment, otherwise remove
-//#ifdef _ODI_OSSG_
-//OS_MARK_SCHEMA_TYPE(passwrd);
-//#endif
-
-#endif
diff --git a/ecflow_4_0_7/view/src/persist.cc b/ecflow_4_0_7/view/src/persist.cc
deleted file mode 100644
index 1df0e24..0000000
--- a/ecflow_4_0_7/view/src/persist.cc
+++ /dev/null
@@ -1,149 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "ecflowview.h"
-#include "persist.h"
-
-persist::persist(const char* kind,const char* name):
- kind_(kind),
- name_(name),
- f_(0),
- write_(0)
-{
-}
-
-persist::~persist()
-{
- close();
-}
-
-void persist::close()
-{
- if(f_) {
- if(fclose(f_))
- perror("persist::~persist");
- }
-}
-
-bool persist::open(bool w)
-{
- if(w != write_ || f_ == 0)
- {
- close();
-
- char buf[1024];
- const char * rcdir = getenv("ECFLOWRC") ? getenv("ECFLOWRC") : "ecflowrc";
-
- sprintf(buf,"%s/.%s/%s.%s",rcdir, getenv("HOME"),kind_,name_);
-
- f_ = fopen(buf, w ? "w" : "r");
- if(!f_) perror(buf);
-
- write_ = w;
-
- }
- return f_ != 0;
-}
-
-
-void persist::set(const char* p,int n)
-{
- if(!open(true)) return;
- fprintf(f_,"%s: %d\n",p,n);
-}
-
-void persist::set(const char* p,const char* s)
-{
- if(!open(true)) return;
- fprintf(f_,"%s: %s\n",p,s);
-}
-
-/*
-void persist::set(const char* p,sms_list* l)
-{
- if(!open(true)) return;
-
- while(l)
- {
- fprintf(f_,"%s: %s\n",p,l->name);
- l = l->next;
- }
-}
-
-bool persist::get(const char* p,sms_list*& l)
-{
- if(!open(false)) return false;
- rewind(f_);
-
- l = 0;
- const char* x;
- while(( x = read(p)))
- {
- sms_list *m = (sms_list*)ecf_node_create((char*)x);
- m->next = l;
- l = m;
- }
-
- return l != 0;
-
-}
-*/
-
-bool persist::get(const char* p,int& n)
-{
- if(!open(false)) return false;
- rewind(f_);
-
- const char* x;
-
- if(( x = read(p)))
- {
- n = atoi(x);
- return true;
- }
- return false;
-}
-
-bool persist::get(const char* p, char* n)
-{
- if(!open(false)) return false;
- rewind(f_);
- const char* x;
- if(( x = read(p)))
- {
- strcpy(n,x);
- return true;
- }
- return false;
-}
-
-const char* persist::read(const char* p)
-{
-
- static char line[1024];
- int len = strlen(p);
-
- for(;;)
- {
- if(!fgets(line,sizeof(line),f_))
- return 0;
-
- line[strlen(line)-1] = 0;
-
- if(line[len] == ':' && strncmp(line,p,len) == 0)
- return line + len + 2;
-
- }
-}
diff --git a/ecflow_4_0_7/view/src/persist.h b/ecflow_4_0_7/view/src/persist.h
deleted file mode 100644
index b4401f5..0000000
--- a/ecflow_4_0_7/view/src/persist.h
+++ /dev/null
@@ -1,139 +0,0 @@
-#ifndef persist_H
-#define persist_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-// Headers
-// #ifndef machine_H
-// #include <machine.h>
-// #endif
-
-// Forward declarations
-
-// class ostream;
-// typedef class _Pvts os_typespec; // Remove if not persistant
-
-//
-#ifdef NO_BOOL
-#include "bool.h"
-#endif
-
-struct sms_list;
-
-class persist {
-public:
-
-// -- Exceptions
- // None
-
-// -- Contructors
-
- persist(const char* kind,const char* name);
-
-// -- Destructor
-
- ~persist(); // Change to virtual if base class
-
-// -- Convertors
- // None
-
-// -- Operators
- // None
-
-// -- Methods
-
- void set(const char*,const char*);
- void set(const char*,int);
- void set(const char*,sms_list*);
-
- bool get(const char*,char*);
- bool get(const char*,int&);
- bool get(const char*,sms_list*&);
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
- // Uncomment for persistent, remove otherwise
- // static os_typespec* get_os_typespec();
-
-protected:
-
-// -- Members
- // None
-
-// -- Methods
-
- // void print(ostream&) const; // Change to virtual if base class
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-private:
-
-// No copy allowed
-
- persist(const persist&);
- persist& operator=(const persist&);
-
-// -- Members
-
- const char* kind_;
- const char* name_;
- FILE *f_;
- bool write_;
-
-// -- Methods
-
- bool open(bool);
- void close();
- const char* read(const char*);
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-// -- Friends
-
- //friend ostream& operator<<(ostream& s,const persist& p)
- // { p.print(s); return s; }
-
-};
-
-inline void destroy(persist**) {}
-
-// If persistent, uncomment, otherwise remove
-//#ifdef _ODI_OSSG_
-//OS_MARK_SCHEMA_TYPE(persist);
-//#endif
-
-#endif
diff --git a/ecflow_4_0_7/view/src/pixmap.cc b/ecflow_4_0_7/view/src/pixmap.cc
deleted file mode 100644
index 1ebcaee..0000000
--- a/ecflow_4_0_7/view/src/pixmap.cc
+++ /dev/null
@@ -1,103 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <X11/xpm.h>
-#include <ctype.h>
-#include "pixmap.h"
-#include "gui.h"
-#include "directory.h"
-
-pixmap::pixmap(const char* name):
- pixmap_(0),
- name_(clean(name)),
- bits_(0)
-{
-}
-
-pixmap::pixmap(const char* name,const char** bits):
- pixmap_(0),
- name_(clean(name)),
- bits_(bits)
-{
-}
-
-
-pixmap::~pixmap()
-{
-}
-
-pixmap& pixmap::find(const char* name)
-{
- pixmap *r = first();
- const char* n = clean(name);
- while(r)
- {
- if(strcmp(n,r->name_.c_str()) == 0)
- return *r;
- r = r->next();
- }
- return *(new pixmap(name));
-}
-
-void pixmap::set_label(Widget w)
-{
- XtVaSetValues(w,
- XmNlabelType, XmPIXMAP,
- XmNlabelPixmap,pixels(),
- NULL);
-}
-
-Pixmap pixmap::pixels()
-{
- if(pixmap_) return pixmap_;
-
- XpmAttributes xpm_attributes;
- xpm_attributes.valuemask = XpmCloseness;
- xpm_attributes.closeness = 65535;
-
- Display* dpy = XtDisplay(gui::top());
-
- if(bits_)
- {
- if(XpmCreatePixmapFromData(dpy,
- DefaultRootWindow(dpy),
- (char**)bits_,&pixmap_,0,&xpm_attributes))
- pixmap_ = XmUNSPECIFIED_PIXMAP;
- }
- else {
- char buf[1024];
- sprintf(buf,"%s/icons/%s.xpm",directory::system(),name_.c_str());
-
- if(XpmReadFileToPixmap(dpy,
- DefaultRootWindow(dpy),
- buf, &pixmap_, 0, &xpm_attributes))
- {
- pixmap_ = XmUNSPECIFIED_PIXMAP;
- }
- }
-
- return pixmap_;
-}
-
-const char* pixmap::clean(const char* s)
-{
- static char n[1024];
- strcpy(n,s);
- char *p = n;
- while(*p) { if(!isalnum(*p)) *p = '_'; p++; }
- return n;
-}
-
-IMP(pixmap)
diff --git a/ecflow_4_0_7/view/src/pixmap.h b/ecflow_4_0_7/view/src/pixmap.h
deleted file mode 100644
index 9c565a3..0000000
--- a/ecflow_4_0_7/view/src/pixmap.h
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef pixmap_H
-#define pixmap_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include <Xm/Xm.h>
-
-#ifndef extent_H
-#include "extent.h"
-#endif
-
-#ifndef str_H
-#include "str.h"
-#endif
-
-
-class pixmap : public extent<pixmap> {
-public:
- pixmap(const char*);
- pixmap(const char*,const char**);
- ~pixmap(); // Change to virtual if base class
-
- Pixmap pixels();
- void set_label(Widget);
-
- static pixmap& find(const char*);
-
-private:
- pixmap(const pixmap&);
- pixmap& operator=(const pixmap&);
-
- Pixmap pixmap_;
- str name_;
- const char** bits_;
-
- static const char* clean(const char*);
-};
-
-inline void destroy(pixmap**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/pref_editor.cc b/ecflow_4_0_7/view/src/pref_editor.cc
deleted file mode 100644
index d87f524..0000000
--- a/ecflow_4_0_7/view/src/pref_editor.cc
+++ /dev/null
@@ -1,87 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "pref_editor.h"
-#include "node.h"
-#include "host.h"
-#include "ecflowview.h"
-#include "str.h"
-#include <Xm/Label.h>
-#include <Xm/Text.h>
-#include <Xm/ToggleB.h>
-extern "C" {
-#include "xec.h"
-}
-
-
-void pref_editor::init(resource& x)
-{
- Widget w = find(x.name().c_str()); if(!w) return;
- x.initWidget(w);
- sensitive(w,x.name().c_str(),x.isSet());
-}
-
-void pref_editor::sensitive(Widget w, const char* n, bool set)
-{
- Widget p = toggle(n); if(!p) return;
- XtSetSensitive(w,set);
- XmToggleButtonSetState(p,!set,False);
-}
-
-Widget pref_editor::toggle(const char* n)
-{
- char buf[1024];
- sprintf(buf,"@%s",n);
- return find(buf);
-}
-
-bool pref_editor::modified(resource& x)
-{
- Widget w = find(x.name().c_str()); if(!w) return false;
- bool on = XtIsSensitive(w);
-
- if(on != x.isSet())
- {
- x.setset(on);
- if(on) x.readWidget(w);
- return true;
- }
-
-
- return on ? x.readWidget(w) : false;
-}
-
-void pref_editor::changed(Widget w)
-{
- configurable* c = owner();
- if(c)
- {
- resource::modified(*c,*this);
- resource::init(*c,*this);
- }
-}
-
-void pref_editor::use(Widget w)
-{
- bool s = XmToggleButtonGetState(w);
- char* p = XtName(w);
-
-
- Widget z = find(p+1);
- if(z) XtSetSensitive(z,!s);
-
- changed(w);
-}
-
diff --git a/ecflow_4_0_7/view/src/pref_editor.h b/ecflow_4_0_7/view/src/pref_editor.h
deleted file mode 100644
index ebbbcac..0000000
--- a/ecflow_4_0_7/view/src/pref_editor.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef pref_editor_H
-#define pref_editor_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include <Xm/Xm.h>
-
-#ifndef option_H
-#include "option.h"
-#endif
-
-#ifndef configurator_H
-#include "configurator.h"
-#endif
-
-#ifndef editor_H
-#include "editor.h"
-#endif
-
-class configurable;
-
-class pref_editor : public configurator, public editor {
-public:
-
- virtual configurable* owner() = 0;
-
- virtual void init(resource&);
- virtual bool modified(resource&);
-
-protected:
-
- void changed(Widget);
- void use(Widget);
-
-private:
-
- void sensitive(Widget,const char*,bool);
- Widget toggle(const char* n);
-};
-
-inline void destroy(pref_editor**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/pref_window.cc b/ecflow_4_0_7/view/src/pref_window.cc
deleted file mode 100644
index 9f974d3..0000000
--- a/ecflow_4_0_7/view/src/pref_window.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "pref_window.h"
-#include "gui.h"
-#include "prefs.h"
-
-pref_window& pref_window::instance()
-{
- static pref_window *m = new pref_window();
- return *m;
-}
-
-pref_window::pref_window()
-{
- create(gui::top());
- prefs::create_all(tab_);
-}
-
-pref_window::~pref_window()
-{
-}
-
-void pref_window::closeCB(Widget,XtPointer)
-{
- XtUnmanageChild(form_);
-}
-
-void pref_window::mapCB(Widget,XtPointer)
-{
-}
-
-void pref_window::raise()
-{
- XtManageChild(form_);
- XMapRaised(XtDisplay(_xd_rootwidget),XtWindow(_xd_rootwidget));
-}
-
-void pref_window::show()
-{
- instance().raise();
-}
diff --git a/ecflow_4_0_7/view/src/pref_window.h b/ecflow_4_0_7/view/src/pref_window.h
deleted file mode 100644
index 5445700..0000000
--- a/ecflow_4_0_7/view/src/pref_window.h
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef pref_window_H
-#define pref_window_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "uipref.h"
-
-class pref_window : public pref_shell_c {
-public:
-
- pref_window();
-
- ~pref_window(); // Change to virtual if base class
-
- static void show();
-
-private:
-
- pref_window(const pref_window&);
- pref_window& operator=(const pref_window&);
-
- void raise();
-
- static pref_window& instance();
-
- void closeCB(Widget,XtPointer);
- void mapCB(Widget,XtPointer);
-
- /* void searchCB(Widget,XtPointer); */
- /* void whatCB(Widget,XtPointer); */
- /* void whereCB(Widget,XtPointer); */
- /* void statusCB(Widget,XtPointer); */
- /* void typeCB(Widget,XtPointer); */
- /* void specialCB(Widget,XtPointer); */
-};
-
-inline void destroy(pref_window**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/prefs.cc b/ecflow_4_0_7/view/src/prefs.cc
deleted file mode 100644
index 3840049..0000000
--- a/ecflow_4_0_7/view/src/prefs.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "prefs.h"
-#include "globals.h"
-#include "resource.h"
-
-void prefs::create_all(Widget w)
-{
- prefs* p = first();
- while(p)
- {
- p->create(w);
- XtManageChild(p->widget());
- p = p->next();
- }
-}
-
-void prefs::setup(Widget w)
-{
- resource::init(*owner(),*this);
-}
-
-configurable* prefs::owner()
-{
- return globals::instance();
-}
-
-IMP(prefs)
diff --git a/ecflow_4_0_7/view/src/prefs.h b/ecflow_4_0_7/view/src/prefs.h
deleted file mode 100644
index c6dc853..0000000
--- a/ecflow_4_0_7/view/src/prefs.h
+++ /dev/null
@@ -1,126 +0,0 @@
-#ifndef prefs_H
-#define prefs_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-// Headers
-// #ifndef machine_H
-// #include <machine.h>
-// #endif
-
-// Forward declarations
-
-// class ostream;
-// typedef class _Pvts os_typespec; // Remove if not persistant
-
-//
-
-#ifndef extent_H
-#include "extent.h"
-#endif
-
-#ifndef pref_editor_H
-#include "pref_editor.h"
-#endif
-
-
-class prefs : public extent<prefs>, public pref_editor {
-public:
-
-// -- Exceptions
- // None
-
-// -- Contructors
-
- prefs() {};
-
-// -- Destructor
-
-
-// -- Convertors
- // None
-
-// -- Operators
- // None
-
-// -- Methods
-
- virtual void create(Widget,char* = 0) = 0;
- virtual Widget widget() = 0;
-
-
- void setup(Widget);
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
-
- static void create_all(Widget);
-
- // Uncomment for persistent, remove otherwise
- // static os_typespec* get_os_typespec();
-
-protected:
-
-// -- Members
-
-
-// -- Methods
-
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-private:
-
-// No copy allowed
-
- prefs(const prefs&);
- prefs& operator=(const prefs&);
-
-// -- Members
-
-// -- Methods
-
-
-// -- Overridden methods
- // None
-
- virtual Widget form() { return widget(); }
- virtual configurable* owner();
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-// -- Friends
-
-
-};
-
-#endif
diff --git a/ecflow_4_0_7/view/src/re.h b/ecflow_4_0_7/view/src/re.h
deleted file mode 100644
index aa6ae75..0000000
--- a/ecflow_4_0_7/view/src/re.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#if defined(linux) || defined(alpha)
-#include <regex.h>
-
-
-class re {
- regex_t re_;
- char *loc_;
-public:
- re(const char* r): loc_(0) { regcomp(&re_,r,0); }
-
- ~re() { regfree(&re_); }
-
- char* match(char* a,char* b)
- {
- regmatch_t pmatch;
- if(!regexec(&re_,a,1,&pmatch,0))
- return 0;
-
- loc_ = a+pmatch.rm_so;
- return a+pmatch.rm_eo;
- }
-
- char* loc() { return loc_; }
-};
-
-#else
-#include <stdlib.h>
-#include <libgen.h>
-
-class re {
- char *re_;
-public:
- re(const char* r) : re_(::regcmp(r,0)) {}
- ~re() { ::free(re_); }
- char* match(char* a,char* b) { return ::regex(a,b); }
- char* loc() { return ::__loc1; }
-};
-
-#endif
diff --git a/ecflow_4_0_7/view/src/reach.cc b/ecflow_4_0_7/view/src/reach.cc
deleted file mode 100644
index e129c66..0000000
--- a/ecflow_4_0_7/view/src/reach.cc
+++ /dev/null
@@ -1,255 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "arch.h"
-#include "reach.h"
-#include "node.h"
-#include "array.h"
-#include "node_lister.h"
-#include "trigger_lister.h"
-#include "host.h"
-
-struct path {
-
- bool use_;
- bool mark_;
- bool ignore_;
-
- node* from_;
- node* to_;
- node* through_;
- int mode_;
- node* trigger_;
-
- path(node* from = 0, node* to = 0,node* through = 0, int mode = 0,node *trigger = 0):
- use_(false), mark_(false), ignore_(false), from_(from),to_(to),through_(through),mode_(mode), trigger_(trigger)
- {}
-
-#ifdef AIX
- bool operator==(const path&) { return 0; }
-#endif
-};
-
-struct trigger_collector : public trigger_lister {
-
-static array<path> paths_;
-
- array<node*> nodes_;
- int count_;
- bool triggered_;
- node* current_;
-
- trigger_collector(node *n): count_(0),triggered_(0),current_(0)
- { add(n); add_all(n->kids()); }
-
- void next_node(node& n,node*,int,node*);
- void add(node*);
- void add_all(node*);
- void add(node*,node*,node*,int,node*);
-
- void mode(node* c,bool t) { current_ = c; triggered_ = t; }
-
- Boolean kids() { return True; }
- Boolean parents() { return True; }
-};
-
-array<path> trigger_collector::paths_;
-
-void trigger_collector::next_node(node& n,node* th,int mode,node* tr)
-{
- add(&n);
- if(triggered_)
- add(current_,&n,th,mode,tr);
- else
- add(&n,current_,th,mode,tr);
-}
-
-void trigger_collector::add(node* from, node* to,node* through, int mode,node *trigger)
-{
-#if 0
- if(through)
- {
- if(from->is_my_parent(through) || through->is_my_parent(from))
- paths_.add( path(from,through,0,trigger_lister::hierarchy,0) );
- else
- paths_.add( path(from,through,0,mode,trigger) );
-
- if(to->is_my_parent(through) || through->is_my_parent(to))
- paths_.add( path(through,to,0,trigger_lister::hierarchy,0) );
- else
- paths_.add( path(through,to,0,mode,trigger) );
-
- }
- else
-#endif
- paths_.add( path(from,to,through,mode,trigger) );
-}
-
-void trigger_collector::add(node* n)
-{
- for(int i = 0; i < nodes_.count(); i++)
- if(nodes_[i] == n)
- return;
- nodes_.add(n);
-}
-
-void trigger_collector::add_all(node* k)
-{
- while(k)
- {
- add(k);
- add_all(k->kids());
- k = k->next();
- }
-}
-
-/*
-static bool sect(trigger_collector& a,trigger_collector& b)
-{
- for(int i = 0; i < a.nodes_.count(); i++)
- for(int j = 0; j < b.nodes_.count(); j++)
- if(a.nodes_[i] == b.nodes_[j])
- return true;
- return false;
-}
-*/
-static bool can_reach(node* from,node* to)
-{
- bool ok = false;
-
- if(from == to)
- return true;
-
- for(int i = 0; i < trigger_collector::paths_.count(); i++)
- {
- path& p = trigger_collector::paths_[i];
- if(!p.ignore_ && !p.mark_ && from == p.from_) {
- if(p.use_)
- ok = true;
- else
- {
- p.mark_ = true;
- if(can_reach(p.to_,to))
- ok = p.use_ = true;
- else
- p.ignore_ = true;
- p.mark_ = false;
- }
- }
- }
- return ok;
-}
-
-// Not used ?
-//static void fill(node* p,node* k)
-//{
-// while(k)
-// {
-//
-// trigger_collector::paths_.add( path(p,k,0,
-// trigger_lister::hierarchy,0) );
-// trigger_collector::paths_.add( path(k,p,0,
-// trigger_lister::hierarchy,0) );
-// fill(k,k->kids());
-// k = k->next();
-// }
-//}
-
-bool reach::join(node* a,node* b,reach_lister& rl)
-{
-
- if(!a || !b) return false;
-
- trigger_collector::paths_.clear();
-
- node* top = a->serv().top();
- if(top != b->serv().top())
- return false;
-
- trigger_collector ta(a);
- trigger_collector tb(b);
-
- /* while( ! sect(ta,tb) ) */
- for(;;)
- {
- printf("0\n");
-
- int abefore = ta.count_;
- int bbefore = tb.count_;
-
- ta.count_ = ta.nodes_.count();
- tb.count_ = tb.nodes_.count();
-
- int aafter = ta.count_;
- int bafter = tb.count_;
- int i;
-
- for(i = abefore ; i < aafter; i++)
- {
- ta.mode(ta.nodes_[i],true);
- ta.nodes_[i]->triggered(ta);
- }
-
- for(i = bbefore ; i < bafter; i++)
- {
- tb.mode(tb.nodes_[i],false);
- tb.nodes_[i]->triggers(tb);
- }
-
- printf("%d %d %d %d\n",abefore,aafter,bbefore,bafter);
-
- if(abefore == aafter && bbefore == bafter)
- {
- /* trigger_collector::paths_.clear(); */
- break;
- //return false;
- }
- }
-
-
- printf("1\n");
- can_reach(a,b);
- printf("2\n");
-#if 0
- for(int i = 0; i < ta.nodes_.count(); i++)
- rl.next(ta.nodes_[i]);
-
- for( i = 0; i < tb.nodes_.count(); i++)
- rl.next(tb.nodes_[i]);
-#endif
-
- int x =0;
- int i;
- for(i = 0; i < trigger_collector::paths_.count(); i++)
- {
- path& p = trigger_collector::paths_[i];
- if(p.use_)
- x++;
- }
-
- printf("paths %d\n",x);
-
- for(i = 0; i < trigger_collector::paths_.count(); i++)
- {
- path& p = trigger_collector::paths_[i];
- if(p.use_)
- rl.next(p.from_,p.to_,p.through_,p.mode_,p.trigger_);
-
- }
- trigger_collector::paths_.clear();
- return false;
-}
-
-
diff --git a/ecflow_4_0_7/view/src/reach.h b/ecflow_4_0_7/view/src/reach.h
deleted file mode 100644
index c3f85c2..0000000
--- a/ecflow_4_0_7/view/src/reach.h
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef reach_H
-#define reach_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#ifdef NO_BOOL
-#include "bool.h"
-#endif
-
-// Headers
-// #ifndef machine_H
-// #include <machine.h>
-// #endif
-
-// Forward declarations
-
-// class ostream;
-// typedef class _Pvts os_typespec; // Remove if not persistant
-
-//
-
-class node;
-class reach_lister {
-public:
- virtual void next(node*,node*,node*,int,node*) = 0;
-};
-
-class reach {
-public:
-
- static bool join(node*,node*,reach_lister&);
-
-};
-
-#endif
diff --git a/ecflow_4_0_7/view/src/relation.cc b/ecflow_4_0_7/view/src/relation.cc
deleted file mode 100644
index 4baca77..0000000
--- a/ecflow_4_0_7/view/src/relation.cc
+++ /dev/null
@@ -1,186 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "runnable.h"
-#include "relation.h"
-#include "observable.h"
-#include "counted.h"
-#include <stdio.h>
-
-class run_gc : public runnable {
- void run() { if(!relation::gc()) disable();}
-};
-
-
-static run_gc dogc;
-
-relation::relation(observer* a,observable* b):
- observer_(a),
- observable_(b),
- data_(0),
- valid_(true)
-{
-}
-
-relation::~relation()
-{
- if(data_)
- data_->detach();
-}
-
-void relation::add(observer* a,observable* b)
-{
- if(a && b) {
- b->observed_ = true;
- new relation(a,b);
- }
-}
-
-void relation::stats(const char* p)
-{
- relation* r = first();
- int c = 0; int v = 0;
- while(r) {
- relation* n = r->next();
- c++;
- if(r->valid_) v++;
- r = n;
- }
-
- // printf("relation::stat %s %d relation(s) %d valid(s)\n",p,c,v);
-}
-
-int relation::remove(observer* a,observable* b)
-{
- int rc = 0;
- relation* r = first();
- while(r) {
- relation* n = r->next();
- if(r->observer_ == a && r->observable_ == b) {
- r->valid_ = false;
- rc++;
- }
- r = n;
- }
-
- dogc.enable();
- return rc;
-}
-
-int relation::remove(observer* a)
-{
- int rc = 0;
- relation* r = first();
- while(r) {
- relation* n = r->next();
- if(r->observer_ == a) {
- r->valid_ = false;
- rc++;
- }
- r = n;
- }
-
- dogc.enable();
- return rc;
-}
-
-int relation::remove(observable* b)
-{
- int rc = 0;
- relation* r = first();
- while(r) {
- relation* n = r->next();
- if(r->observable_ == b) {
- r->valid_ = false;
- rc++;
- }
- r = n;
- }
-
- dogc.enable();
- return rc;
-}
-
-void relation::replace(observable* o,observable* x)
-{
- relation* r = first();
- while(r) {
- relation* n = r->next();
- if(r->observable_ == o)
- r->observable_ = x;
- r = n;
- }
-}
-
-void relation::scan(observable* b,observer_iterator& i)
-{
- relation* r = first();
-
- while(r) {
- relation* n = r->next();
- if(r->observable_ == b && r->valid_)
- i.next(r->observer_);
- r = n;
- }
-}
-
-bool relation::gc()
-{
- relation* r = first();
-
- stats("relation::gc");
-
- while(r) {
- relation* n = r->next();
- if(!r->valid_) {
- delete r;
- return true;
- }
- r = n;
- }
-
- return false;
-}
-
-void relation::set_data(observer* a,observable* b,counted* x)
-{
- relation* r = first();
- while(r) {
- relation* n = r->next();
- if(r->observer_ == a && r->observable_ == b) {
- if(x != r->data_) {
- if(r->data_) r->data_->detach();
- r->data_ = x;
- if(r->data_) r->data_->attach();
- }
- return;
- }
- r = n;
- }
-}
-
-counted* relation::get_data(observer* a,observable* b)
-{
- relation* r = first();
- while(r) {
- relation* n = r->next();
- if(r->observer_ == a && r->observable_ == b)
- return r->data_;
- r = n;
- }
- return 0;
-}
-
-IMP(relation)
diff --git a/ecflow_4_0_7/view/src/relation.h b/ecflow_4_0_7/view/src/relation.h
deleted file mode 100644
index 07a1ea3..0000000
--- a/ecflow_4_0_7/view/src/relation.h
+++ /dev/null
@@ -1,74 +0,0 @@
-#ifndef relation_H
-#define relation_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#ifdef NO_BOOL
-#include "bool.h"
-#endif
-
-#ifndef extent_H
-#include "extent.h"
-#endif
-
-class observer;
-class observable;
-class counted;
-
-class observer_iterator {
-public:
- virtual void next(observer*) = 0;
-};
-
-class observable_iterator {
-public:
- virtual void next(observable*) = 0;
-};
-
-
-class relation : public extent<relation> {
-public:
- relation(observer*,observable*);
-
- ~relation(); // Change to virtual if base class
-
- static void add(observer*,observable*);
- static int remove(observer*,observable*);
- static int remove(observer*);
- static int remove(observable*);
- static void replace(observable*,observable*);
-
- static void scan(observer*, observable_iterator&);
- static void scan(observable*,observer_iterator& );
- static bool gc();
-
-
- static void set_data(observer*,observable*,counted*);
- static counted* get_data(observer*,observable*);
-
- static void stats(const char*);
-
-private:
-
- relation(const relation&);
- relation& operator=(const relation&);
-
- observer* observer_;
- observable* observable_;
- counted* data_;
- bool valid_;
-};
-#endif
diff --git a/ecflow_4_0_7/view/src/repeat.h b/ecflow_4_0_7/view/src/repeat.h
deleted file mode 100644
index e95a353..0000000
--- a/ecflow_4_0_7/view/src/repeat.h
+++ /dev/null
@@ -1,151 +0,0 @@
-#ifndef REPEAT_H
-#define REPEAT_H
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #23 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include "repeat_node.h"
-
-/**********************************************/
-class repeat_date_node : public repeat_node {
- virtual int last() const {
- return (ecf_repeat_date_to_julian(repeat_node::last()) -
- ecf_repeat_date_to_julian(repeat_node::start())) / step() + ink;
- }
-
- virtual int current() const {
- if (owner_ && get()) {
- return (ecf_repeat_date_to_julian(get()->index_or_value()) -
- ecf_repeat_date_to_julian(start())) / step();
- }
- return repeat_node::current(); }
-
- virtual void value(char* n,int i) const {
- if (n)
- sprintf(n,"%ld",
- (ecf_repeat_julian_to_date
- (ecf_repeat_date_to_julian(start()) + i * step())));
- }
- virtual const char* perl_class() {
- return "repeat::date"; }
-
-public:
- repeat_date_node(host& h,ecf_node* r) : repeat_node(h,r) {}
-};
-
-/**********************************************/
-class repeat_integer_node : public repeat_node {
- virtual int last() const {
- return (repeat_node::last() - repeat_node::start()) / step() + ink; }
- virtual int current() const {
- return (repeat_node::current() - repeat_node::start()) / step(); }
- virtual void value(char*n,int i) const {
- if (n) sprintf(n,"%d",start() + i*step()); }
- virtual const char* perl_class() {
- return "repeat::integer"; }
-
-public:
- repeat_integer_node(host& h,ecf_node* r) : repeat_node(h,r) {}
-};
-
-/**********************************************/
-class repeat_day_node : public repeat_node {
- virtual int last() const {
- return (repeat_node::last() - repeat_node::start()) / step() + ink; }
- virtual int current() const {
- return step(); }
- virtual void value(char*n,int i) const {
- if (n) sprintf(n,"%d",step()); }
- virtual const char* perl_class() {
- return "repeat::day"; }
-
-public:
- repeat_day_node(host& h,ecf_node* r) : repeat_node(h,r) {}
-};
-
-/**********************************************/
-class repeat_string_node : public repeat_node {
- virtual int last() const {
- if (owner_)
- return repeat_node::last() + ink;
- return repeat_node::last(); }
- virtual int current() const {
- return repeat_node::current(); }
- virtual void value(char* n,int i) const {
- if (n && get())
- sprintf(n,"%s",get()->value_as_string(i).c_str()); }
- virtual int index(const char*) const {
- return current(); }
- virtual bool can_use_text() {
- return false; }
- virtual void perlify(FILE* f) {
- if (get())
- perl_member(f, "values",get()->toString().c_str());
- repeat_node::perlify(f); }
- virtual const char* perl_class() {
- return "repeat::string"; }
-
-public:
- repeat_string_node(host& h,ecf_node* r) : repeat_node(h,r) {}
-};
-
-/**********************************************/
-class repeat_enumerated_node : public repeat_node {
- virtual int last() const {
- if (owner_)
- return repeat_node::last() + ink;
- return repeat_node::last(); }
- virtual int current() const {
- return repeat_node::current(); }
- virtual void value(char* n,int i) const {
- if (n && get()) sprintf(n,"%s",get()->value_as_string(i).c_str()); }
- virtual int index(const char*) const {
- return current(); }
- virtual bool can_use_text() {
- return false; }
-
- virtual void perlify(FILE* f) {
- if (get())
- perl_member(f, "values",get()->toString().c_str());
- repeat_node::perlify(f); }
-
- virtual const char* perl_class() {
- return "repeat::enumerated"; }
-
-public:
- repeat_enumerated_node(host& h,ecf_node *r) : repeat_node(h,r) {}
-};
-
-/**********************************************/
-#ifdef BRIDGE
-class repeat_node_maker : public node_maker<repeat_node> {
- protected:
- static std::map<std::string, repeat_node_maker*> map_;
- public:
- repeat_node_maker() : node_maker<repeat_node>(NODE_REPEAT) {}
- virtual node* make(host& h,ecf_node* n) {
- return map_[n->type_name()]->make(h, n); }
-};
-
-std::map<std::string, repeat_node_maker*> repeat_node_maker::map_;
-
-template <class T, class W>
-class repeat_node_builder : public repeat_node_maker {
-public:
- repeat_node_builder() {
- map_[typeid(T).name()] = this; }
- ~repeat_node_builder() {}
-};
-#endif
-#endif
diff --git a/ecflow_4_0_7/view/src/repeat_node.cc b/ecflow_4_0_7/view/src/repeat_node.cc
deleted file mode 100644
index 9456449..0000000
--- a/ecflow_4_0_7/view/src/repeat_node.cc
+++ /dev/null
@@ -1,308 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #36 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-// .AUTHOR Baudouin Raoult
-// .DATE 28-JUN-2001 / 28-JUN-2001
-
-#include "arch.h"
-#include "repeat_node.h"
-#include "show.h"
-// #include "text_lister.h"
-#include "host.h"
-const int REPEAT_SHOWN = 3;
-#include "ecflowview.h"
-
-#ifndef ecf_node_
-#include "ecf_node.h"
-#endif
-
-const int kPixSize = 8;
-const int kHMargins = 4;
-const int kVMargins = 2;
-
-repeat_node::repeat_node(host& h,ecf_node* n)
- : node(h,n)
- , name_("none")
-{
- if (get())
- name_ = get()->name();
- else if (n)
- name_ = n->name();
- if (n) {
- if (n->parent() && n->parent()->get_node())
- full_name_ = n->parent()->get_node()->absNodePath();
- full_name_ += ":";
- full_name_ += n->name();
- }
-}
-
-#ifdef BRIDGE
-repeat_node::repeat_node(host& h,sms_node* n,char b)
- : node(h,n,b)
- , name_(n ? n->name : "unknown")
-{
- full_name_ = n ? sms_node_full_name(n) : "unknown";
-}
-#endif
-
-/**********************************************/
-
-RepeatBase* repeat_node::get() const
-{
- if (parent())
- if (parent()->__node__())
- return parent()->__node__()->get_repeat().repeatBase();
- Node * nnn = 0x0;
-
- if (nnn)
- return nnn->findRepeat(full_name_).repeatBase();
- return 0x0;
-}
-
- void repeat_node::drawNode(Widget w,XRectangle* r,bool tree) {
- node::update(-1,-1,-1);
- node::drawNode(w,r,true);
- sizeNode(w,r,tree);
-}
-
-void repeat_node::sizeNode(Widget w,XRectangle* r,bool tree) {
- int extra = 0;
- XmString s = tree?labelTree():labelTrigger();
- r->width = XmStringWidth(smallfont(),s) + 2*kHMargins + extra * kPixSize;
- r->height = XmStringHeight(smallfont(),s) + 2*kVMargins;
- if(r->height < kPixSize + 2*kVMargins) r->height = kPixSize + 2*kVMargins;
-}
-
-int repeat_node::start() const
-{
-#ifdef BRIDGE
- if (tree_)
- return ((sms_repeat*) tree_)->start;
-#endif
- if (get())
- return get()->start();
- return 0;
-}
-
-int repeat_node::last() const
-{
-#ifdef BRIDGE
- if (tree_) {
- sms_repeat* r = (sms_repeat*)tree_;
- switch (r->mode) {
- case REPEAT_INTEGER:
- return (r->end - r->start)/r->step + 1;
- case REPEAT_ENUMERATED:
- case REPEAT_STRING: { int n = 0; sms_list *l = r->str;
- while(l) { n++; l = l->next; }
- return n; }
- case REPEAT_DATE: {
- return (ecf_repeat_date_to_julian(r->end) -
- ecf_repeat_date_to_julian(r->start))/
- r->step + 1; }
- default:
- return r->end;
- }
- }
-#endif
- if (get())
- return get()->end();
- return 0;
-}
-
-int repeat_node::step() const
-{
-#ifdef BRIDGE
- if (tree_)
- return ((sms_repeat*) tree_)->step;
-#endif
- if (get())
- return get()->step() > 0 ? get()->step() : 1;
- return 1;
-}
-
-int repeat_node::current() const
-{
-#ifdef BRIDGE
- if (tree_) {
- sms_repeat* r = (sms_repeat*)tree_;
- switch (r->mode) {
- case REPEAT_INTEGER:
- return (r->status - r->start)/r->step;
- case REPEAT_ENUMERATED: { int rc = 0;
- sms_list *item = r->str;
- char current[255];
- while (item) {
- sprintf(current,"%d",r->status);
- if (!strcmp(item->name, current))
- return rc;
- rc++; item = item->next;
- }
- return rc; }
- case REPEAT_STRING:
- return r->status;
- case REPEAT_DATE:
- return (ecf_repeat_date_to_julian(r->status) -
- ecf_repeat_date_to_julian(r->start))/r->step;
- default:
- return r->status;
- }
- }
-#endif
- if (get())
- return get()->index_or_value();
- return 0;
-}
-
-void repeat_node::value(char* n,int i) const
-{
-#ifdef BRIDGE
- if (tree_) {
- sms_repeat* r = (sms_repeat*)tree_;
- switch (r->mode) {
- case REPEAT_INTEGER: {
- sprintf(n,"%d",r->start + i*r->step);
- return; }
- case REPEAT_ENUMERATED:
- case REPEAT_STRING: { int j = 0; sms_list *l = r->str;
- while(l && j != i) { j++; l = l->next; } if(l) strcpy(n,l->name);
- return; }
- case REPEAT_DATE: {
- sprintf(n,"%ld",ecf_repeat_julian_to_date
- (ecf_repeat_date_to_julian(r->start) + i*r->step));
- return; }
- default:
- return;
- }
- }
-#endif
- if (get() && n)
- sprintf(n,"%s",get()->value_as_string(i).c_str());
-}
-
-//===============================================================
-
-xmstring repeat_node::make_label_tree()
-{
- str80 vals[REPEAT_SHOWN];
- str80 buf;
- int end = last();
- int curr = current();
- int first = curr - REPEAT_SHOWN/2;
- static xmstring space(" ");
- {
- if(first<0) first = 0;
- if(end -first<REPEAT_SHOWN) first = end - REPEAT_SHOWN;
- if(end <=REPEAT_SHOWN) first = 0;
-
- int m = MIN(REPEAT_SHOWN,end);
- int i;
-
- for(i = 0 ; i < REPEAT_SHOWN ; i++)
- vals[i][0] = 0;
-
- for(i=0 ; i < m ; i++)
- value(vals[i],i+first);
-
- if(first>0)
- strcpy(vals[0], "...");
-
- if( first+REPEAT_SHOWN < end)
- strcpy(vals[REPEAT_SHOWN-1],"...");
-
- curr = curr - first;
-
- strcpy(buf,name_.c_str());
- strcat(buf,"=");
-
- xmstring s(buf);
-
- m = 0;
- for(i = 0; i < REPEAT_SHOWN ; i ++)
- {
- if(m != 0)
- s += space;
-
- s += xmstring(vals[i], (i==curr)?"bold":"normal" );
-
- m = strlen(vals[i]);
- }
-
- return s;
- }
-}
-
-void repeat_node::info(std::ostream& f)
-{
- if (get()) {
- f << get()->toString() << "\n";
- }
- f << "Values are:\n";
- f << "-----------\n";
-
- str80 buf;
-
- int end = last();
- int cur = current();
- int i;
-
- if(end > 50) {
- for(i=0 ; i < 22 ; i++) {
- value(buf,i);
- f << char( (i == cur) ? '>' : ' ') << buf << "\n";
- }
-
- f << "...\n";
-
- for(i= end-22 ; i < end ; i++) {
- value(buf,i);
- f << char( (i == cur) ? '>' : ' ') << buf << "\n";
- }
- return;
- }
-
- for(i=0 ; i < end ; i++) {
- value(buf,i);
- f << char( (i == cur) ? '>' : ' ') << buf << "\n";
- }
- f << "-----------" << "\n";
-}
-
-const char* repeat_node::status_name() const
-{
- static char buf[80];
- int end = last();
- int cur = current();
-
- if(cur < 0)
- return "not started";
- if(cur >= end)
- return "finished";
-
- value(buf,cur);
- return buf;
-}
-
-void repeat_node::perlify(FILE* f)
-{
- perl_member(f,"start", start());
- perl_member(f,"end", last());
- perl_member(f,"step", step());
- perl_member(f,"current",current());
-}
-
-Boolean repeat_node::visible() const {
- return show::want(show::repeat);
-}
diff --git a/ecflow_4_0_7/view/src/repeat_node.h b/ecflow_4_0_7/view/src/repeat_node.h
deleted file mode 100644
index 472e759..0000000
--- a/ecflow_4_0_7/view/src/repeat_node.h
+++ /dev/null
@@ -1,66 +0,0 @@
-#ifndef repeat_node_H
-#define repeat_node_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #18 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#ifndef node_H
-#include "node.h"
-#endif
-typedef char str80[80];
-#include <RepeatAttr.hpp>
-class repeat_node : public node {
-public:
- // const Repeat& get();
- RepeatBase* get() const;
-
- repeat_node(host& h,ecf_node* n);
-#ifdef BRIDGE
- repeat_node(host& h,sms_node* n,char b);
-#endif
- virtual int start() const;
- virtual int last() const;
- virtual int step() const;
- virtual int current() const;
- virtual void value(char*,int) const;
- virtual int index(const char* p) const { return atol(p); }
- virtual bool can_use_text() { return true; }
- virtual void perlify(FILE*);
-
- virtual void drawNode(Widget w,XRectangle* r,bool);
- virtual void sizeNode(Widget w,XRectangle* r,bool);
-
- protected:
- static const int ink = 1;
-private:
- std::string name_,full_name_;
-
- repeat_node(const repeat_node&);
- repeat_node& operator=(const repeat_node&);
-
- virtual void info(std::ostream&);
- virtual xmstring make_label_tree();
-
- virtual const char* status_name() const;
-
- virtual const std::string& full_name() const { return full_name_; }
- virtual const std::string& name() const { return name_; }
-
- virtual bool is_my_parent(node*) const { return false; }
- virtual Boolean visible() const;
-};
-
-inline void destroy(repeat_node**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/resource.cc b/ecflow_4_0_7/view/src/resource.cc
deleted file mode 100644
index 9db79c8..0000000
--- a/ecflow_4_0_7/view/src/resource.cc
+++ /dev/null
@@ -1,112 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <strings.h>
-
-#ifndef option_H
-#include "option.h"
-#endif
-
-#ifndef base_H
-#include "base.h"
-#endif
-
-#include "configurable.h"
-#include "configurator.h"
-
-resource::resource(configurable* o,const str& name,const str& value):
- owner_(o),
- base_(base::lookup(o->name())),
- name_(name),
- value_(value),
- set_(0)
-{
- base_->attach();
- base_->defaults(name_,value_);
- set_ = base_->fetch(name_,value_);
-}
-
-resource::~resource()
-{
- base_->detach();
-}
-
-void resource::setset(bool on)
-{
- set_ = on;
-
- if(on)
- base_->store(name_,value_,true);
- else
- base_->remove(name_);
-
- base_->fetch(name_,value_);
-
- resource* r = first();
- while(r)
- {
- if(r->name() == name_)
- if(r->changed())
- r->owner_->changed(*r);
- r = r->next();
- }
-}
-
-void resource::set(const str& v)
-{
-
- value_ = v;
- base_->store(name_,value_,true);
- set_ = true;
-
- resource* r = first();
- while(r)
- {
- if(r->name() == name_)
- if(r->changed())
- r->owner_->changed(*r);
- r = r->next();
- }
-}
-
-const str& resource::get()
-{
- base_->fetch(name_,value_);
- return value_;
-}
-
-void resource::init(configurable& a, configurator& c)
-{
- resource* r = first();
- while(r)
- {
- if(r->owner_ == &a) c.init(*r);
- r = r->next();
- }
-}
-
-void resource::modified(configurable& a, configurator& c)
-{
- resource* r = first();
- while(r)
- {
- if(r->owner_ == &a)
- if(c.modified(*r))
- a.changed(*r);
- r = r->next();
- }
-}
-
-IMP(resource)
diff --git a/ecflow_4_0_7/view/src/resource.h b/ecflow_4_0_7/view/src/resource.h
deleted file mode 100644
index 38c4812..0000000
--- a/ecflow_4_0_7/view/src/resource.h
+++ /dev/null
@@ -1,71 +0,0 @@
-#ifndef resource_H
-#define resource_H
-
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#ifndef configurable_H
-#include "configurable.h"
-#endif
-
-#ifndef str_H
-#include "str.h"
-#endif
-
-#include <Xm/Xm.h>
-
-class base;
-
-#ifndef resource_H
-#include "resource.h"
-#endif
-#include "extent.h"
-
-class resource : public extent<resource> {
-public:
-
- resource(configurable*,const str&,const str&);
-
- virtual ~resource(); // Change to virtual if base class
-
- const str name() const { return name_; }
-
- virtual void initWidget(Widget) = 0;
- virtual bool readWidget(Widget) = 0;
- virtual bool changed() = 0;
-
- virtual void set(const str&);
- virtual const str& get();
-
- virtual bool isSet() { return set_; }
- virtual void setset(bool);
-
- static void init(configurable&,configurator&);
- static void modified(configurable&,configurator&);
-
-private:
-
- resource(const resource&);
- resource& operator=(const resource&);
-
- configurable* owner_;
- base* base_;
- str name_;
- str value_;
- bool set_;
-};
-
-inline void destroy(resource**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/restart.cc b/ecflow_4_0_7/view/src/restart.cc
deleted file mode 100644
index 9424adf..0000000
--- a/ecflow_4_0_7/view/src/restart.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "restart.h"
-#include "node.h"
-
-
-restart::restart():
- node_alert<restart>("Restarted tasks",STATUS_SUBMITTED)
-{
-}
-
-restart::~restart()
-{
-}
-
-bool restart::keep(node* n)
-{
- return n->isRerun();
-}
diff --git a/ecflow_4_0_7/view/src/restart.h b/ecflow_4_0_7/view/src/restart.h
deleted file mode 100644
index 2cd63e8..0000000
--- a/ecflow_4_0_7/view/src/restart.h
+++ /dev/null
@@ -1,109 +0,0 @@
-#ifndef restart_H
-#define restart_H
-
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "node_alert.h"
-
-class node;
-
-class restart : public node_alert<restart> {
-public:
-
-// -- Exceptions
- // None
-
-// -- Contructors
-
- restart();
-
-// -- Destructor
-
- ~restart(); // Change to virtual if base class
-
-// -- Convertors
- // None
-
-// -- Operators
- // None
-
-// -- Methods
- // None
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
-
- // Uncomment for persistent, remove otherwise
- // static os_typespec* get_os_typespec();
-
-protected:
-
-// -- Members
- // None
-
-// -- Methods
-
- // void print(ostream&) const; // Change to virtual if base class
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-private:
-
-// No copy allowed
-
- restart(const restart&);
- restart& operator=(const restart&);
-
-// -- Methods
-
-
-// -- Overridden methods
-
- virtual bool keep(node*);
-
-// -- Class members
-
-
-// -- Class methods
- // None
-
-// -- Friends
-
- //friend ostream& operator<<(ostream& s,const restart& p)
- // { p.print(s); return s; }
-
-};
-
-inline void destroy(restart**) {}
-
-// If persistent, uncomment, otherwise remove
-//#ifdef _ODI_OSSG_
-//OS_MARK_SCHEMA_TYPE(restart);
-//#endif
-
-#endif
diff --git a/ecflow_4_0_7/view/src/result.cc b/ecflow_4_0_7/view/src/result.cc
deleted file mode 100644
index 040a27a..0000000
--- a/ecflow_4_0_7/view/src/result.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "result.h"
-
-result::result():
- node_alert<result>("Search results")
-{
-}
-
-result::~result()
-{
-}
-
-
-bool result::keep(node* n)
-{
- return true;
-}
-
diff --git a/ecflow_4_0_7/view/src/result.h b/ecflow_4_0_7/view/src/result.h
deleted file mode 100644
index a679fda..0000000
--- a/ecflow_4_0_7/view/src/result.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef result_H
-#define result_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "node_alert.h"
-
-class node;
-
-class result : public node_alert<result> {
-public:
-
- result();
- ~result(); // Change to virtual if base class
-
-private:
-
- result(const result&);
- result& operator=(const result&);
-
- virtual bool keep(node*);
-};
-
-inline void destroy(result**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/runnable.cc b/ecflow_4_0_7/view/src/runnable.cc
deleted file mode 100644
index 12dc670..0000000
--- a/ecflow_4_0_7/view/src/runnable.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "ecflowview.h"
-#include "runnable.h"
-
-/* do a process in the "background" */
-
-Boolean runnable::workCB(XtPointer)
-{
- runnable *p = first();
- int active = 0;
- while(p) {
- runnable* n = p->next();
-
- if(p->actived_) {
- active++;
- p->run();
- }
-
- p = n;
- }
- return (active == 0);
-}
-
-runnable::runnable():
- actived_(False)
-{
-}
-
-runnable::~runnable()
-{
-}
-
-void runnable::enable()
-{
- if(actived_) return;
-
- extern XtAppContext app_context;
- if(app_context != 0)
- XtAppAddWorkProc(app_context,workCB,NULL);
-
- actived_ = True;
-}
-
-
-void runnable::disable()
-{
- actived_ = False;
-}
-
-IMP(runnable)
diff --git a/ecflow_4_0_7/view/src/runnable.h b/ecflow_4_0_7/view/src/runnable.h
deleted file mode 100644
index 614f4ec..0000000
--- a/ecflow_4_0_7/view/src/runnable.h
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef runnable_H
-#define runnable_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include <Xm/Xm.h>
-
-#ifdef NO_BOOL
-#include "bool.h"
-#endif
-
-#ifndef extent_H
-#include "extent.h"
-#endif
-
-class runnable : public extent<runnable> {
-public:
- runnable();
-
- virtual ~runnable(); // Change to virtual if base class
-
- void enable();
- void disable();
- bool actived() { return actived_; }
-
- virtual void run() = 0;
-
-private:
- runnable(const runnable&);
- runnable& operator=(const runnable&);
-
- Boolean actived_;
-
- static Boolean workCB(XtPointer);
-};
-#endif
diff --git a/ecflow_4_0_7/view/src/script_panel.cc b/ecflow_4_0_7/view/src/script_panel.cc
deleted file mode 100644
index a1c8768..0000000
--- a/ecflow_4_0_7/view/src/script_panel.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "script_panel.h"
-#include "node.h"
-#include "host.h"
-#include "ecf_node.h"
-#include "variable_node.h"
-#include <Xm/Text.h>
-extern "C" {
-#include "xec.h"
-}
-
-script_panel::script_panel(panel_window& w)
- :panel(w)
- ,text_window(false)
-{
-}
-
-script_panel::~script_panel()
-{
-}
-
-void script_panel::clear()
-{
- XmTextSetString(name_,(char*)"");
- text_window::clear();
-}
-
-void script_panel::show(node& n)
-{
- std::string p = n.variable("ECF_SCRIPT");
- if (!n.__node__()) p = n.variable("SMSSCRIPT");
- XmTextSetString(name_,p.empty() ? (char*) "" : (char*)p.c_str());
- load(n.serv().script(n));
-}
-
-Boolean script_panel::enabled(node& n)
-{
- if (n.type() != NODE_TASK && n.type() != NODE_ALIAS) return False;
- if (!n.__node__())
- return n.variable("SMSSCRIPT").size() > 7;
- return n.variable("ECF_SCRIPT").size() > 7;
-}
-
-void script_panel::create (Widget parent, char *widget_name )
-{
- script_form_c::create(parent,widget_name);
-}
diff --git a/ecflow_4_0_7/view/src/script_panel.h b/ecflow_4_0_7/view/src/script_panel.h
deleted file mode 100644
index 8a17007..0000000
--- a/ecflow_4_0_7/view/src/script_panel.h
+++ /dev/null
@@ -1,64 +0,0 @@
-#ifndef script_panel_H
-#define script_panel_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "uiscript.h"
-
-#ifndef panel_H
-#include "panel.h"
-#endif
-
-#ifndef text_window_H
-#include "text_window.h"
-#endif
-
-class script_panel : public panel, public script_form_c, public text_window {
-public:
-
- script_panel(panel_window&);
-
- ~script_panel(); // Change to virtual if base class
-
- virtual const char* name() const { return "Script"; }
- virtual void show(node&);
- virtual Boolean enabled(node&);
- virtual void clear();
- virtual Widget widget() { return script_form_c::xd_rootwidget(); }
- virtual Widget tools() { return tools_; }
- virtual Widget text() { return text_; }
- virtual void create (Widget parent, char *widget_name = 0 );
-
-private:
-
- script_panel(const script_panel&);
- script_panel& operator=(const script_panel&);
-
- virtual void externalCB(Widget ,XtPointer )
- { text_window::open_viewer();}
-
- virtual void searchCB(Widget ,XtPointer )
- { text_window::open_search();}
-
- virtual bool can_print() { return true; }
- virtual bool can_save() { return true; }
- virtual void print() { text_window::print(); }
- virtual void save() { text_window::save(); }
-};
-
-inline void destroy(script_panel**) {}
-
-#endif
diff --git a/ecflow_4_0_7/view/src/scripting.cc b/ecflow_4_0_7/view/src/scripting.cc
deleted file mode 100644
index 3b1ad1e..0000000
--- a/ecflow_4_0_7/view/src/scripting.cc
+++ /dev/null
@@ -1,390 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #11 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <stdio.h>
-#include <strings.h>
-#include "ecflowview.h"
-#include "scripting.h"
-#include "directory.h"
-#include "input.h"
-// cmd
-#include "gui.h"
-#include "node.h"
-#include "host.h"
-#include "selection.h"
-#include "panel_window.h"
-#include "uitop.h"
-#include "menus.h"
-
-// #include <sys/types.h>
-// #include <sys/stat.h>
-#include <fcntl.h>
-#include "ecflowview.h"
-
-int select_cmd(const char *host_name, const char *node_name)
-{
- gui::raise();
- host::login(host_name);
- node* n = host::find(host_name,node_name);
- if(n) selection::notify_new_selection(n);
- return True;
-}
-
-int order_cmd(const char *path, const char *kind)
-{
- gui::raise();
- char *c = (char*) path; // host:/path
- const char* host_name = 0x0;
- const char* node_name = path;
- while (c) {
- if (*c == ':') { *c = '\0'; node_name = ++c; } else {++c;}}
- if (!host_name) host_name="localhost";
- host::login(host_name);
- node* xnode = host::find(host_name,node_name);
- if(xnode) {
- selection::notify_new_selection(xnode);
- xnode->serv().command(clientName, "--order", node_name, kind, NULL);
- }
- return True;
-}
-
-int menu_cmd(const char *cmd)
-{
- return script_menus(0, cmd);
-}
-
-int window_cmd(const char *name, int detached, int frozen)
-{
- panel_window::new_window(selection::current_node(),name,detached,frozen);
- return True;
-}
-
-int login_cmd(const char *name)
-{
- host::login(name);
- return True;
-}
-
-int logout_cmd(const char *name)
-{
- host::logout(name);
- return True;
-}
-
-int quit_cmd()
-{
- top_shell_c::quitCB(0x0, 0x0, 0x0);
- return True;
-}
-
-int process_command(const char *cmd) {
- if (!cmd) return 1;
-
- if (!strncmp("select", cmd, 6)) {
- char host[80] = { 0, };
- char node[1024] = { 0, };
- sscanf(cmd, "select %s %s", host, node);
- if (host[0] != 0 && node[0] != 0) {
- select_cmd(host, node);
- } else {
- std::cerr << "#CMD (scripting): err: " << cmd << "\n";
- return 1;
- }
-
- } else if (!strncmp("order", cmd, 5)) {
- char kind[80] = { 0, };
- char node[1024] = { 0, };
- sscanf(cmd, "order %s %s", node, kind);
- if (kind[0] != 0 && node[0] != 0) {
- order_cmd(node, kind);
- } else {
- std::cerr << "#CMD (scripting): err: " << cmd << "\n";
- return 1;
- }
-
- } else if (!strncmp("menu", cmd, 4)) {
- menu_cmd(cmd);
-
- } else if (!strncmp("quit", cmd, 4)) {
- quit_cmd();
-
- } else if (!strncmp("login", cmd, 5)) {
- char host[80] = { 0, };
- sscanf(cmd, "login %s", host);
- if (host[0] != 0) {
- login_cmd(host);
- }
-
- } else if (!strncmp("logout", cmd, 6)) {
- char host[80] = { 0, };
- sscanf(cmd, "logout %s", host);
- if (host[0] != 0) {
- logout_cmd(host);
- }
-
- } else if (!strncmp("window", cmd, 6)) {
- int detached = 0;
- int frozen = 0;
- int len;
- char name[32] = { 0, };
- const char *ptr = cmd;
- while ((sscanf(ptr, "%31[^ ]%n", name, &len) == 1)) {
- std::cerr << "#field: " << name << "\n";
- ptr += len;
- if (!strncmp("-d", name, 2)) detached = 1;
- if (!strncmp("-f", name, 2)) frozen = 1;
- if (*ptr != ' ') { break; /* skip separator */ }
- ptr++;
- std::cerr << "#CMD (scripting): process: " << name << "\n";
- }
- if (name[0] != 0) {
- window_cmd(name, detached, frozen);
- } else {
- std::cerr << "#CMD (scripting): err: " << cmd << "\n";
- return 1;
- }
- } else if (!strncmp("\n", cmd, 1)) {
-
- } else {
- std::cerr << "#CMD (scripting): ignored: " << cmd << "\n";
- return 1;
- }
-
- std::cout << "#CMD (scripting): " << cmd << "\n";
- return 0;
-}
-
-#undef SCRIPT_PYTHON
-#ifdef SCRIPT_PYTHON
-#ifdef linux
-#undef _POSIX_C_SOURCE
-#undef _XOPEN_SOURCE
-#include <boost/python.hpp>
-#include <boost/python/module.hpp>
-#include <boost/detail/lightweight_test.hpp>
-using namespace boost::python;
-namespace python = boost::python;
-
-void runit(std::string const &script)
-{
- python::dict global;
- // python::object result =
- python::exec(oost::python::str(script), global, global);
- // BOOST_TEST(python::extract<int>(global["number"]) == 42);
-}
-
-BOOST_PYTHON_MODULE(ecflowView)
-{
- def("window", window_cmd, args("name", "detached", "frozen"), "open a window detached/frozen");
- def("select", select_cmd, args("host", "node"), "select a node");
-}
-
-#endif
-#endif
-
-extern XtAppContext app_context;
-
-class ecflowview_input {
- std::string name_;
- XtInputId id_;
- int fd_;
- std::string line_;
-
-public:
-
- ecflowview_input(const char* name):
- name_(name),
- fd_(-1)
- {
- open();
- }
-
- ~ecflowview_input()
- {
- if(fd_ >= 0) XtRemoveInput(id_);
- }
-
- void done()
- {
- if(fd_ >= 0) XtRemoveInput(id_);
- ::close(fd_);
- fd_ = -1;
- // We should check if its a pipe
-
- struct stat st;
- if(stat(name_.c_str(),&st) == 0)
- {
- if(S_ISFIFO(st.st_mode))
- open();
- else
- delete this;
- }
- else {
- perror(name_.c_str());
- delete this;
- }
- }
-
- void open()
- {
- fd_ = ::open(name_.c_str(),O_RDONLY|O_NONBLOCK); // |O_NDELAY);
- if(fd_ < 0) {
- perror(name_.c_str());
- delete this;
- return;
- }
-
- id_ = XtAppAddInput(app_context,fd_, XtPointer(XtInputReadMask),
- inputCB,this);
- }
-
- void input()
- {
- char c[2];
- if(::read(fd_,&c[0],1) != 1)
- {
- done();
- }
- if(c[0] == '\n')
- {
-#ifdef SCRIPT_PYTHON
-#ifdef linux
- // Py_Initialize();
- init_module_ecflowView(); // thanks to boost macro
- bool error_expected = false;
- // Py_InitModule("ecflowView", ecflowViewMethods);
- std::cout << line_.c_str() << "\n";
- if ( // python::handle_exception(exec_test) ||
- python::handle_exception(boost::bind(runit, line_)))
- {
- if (PyErr_Occurred())
- {
- if (!error_expected)
- std::cerr << "Python Error detected";
- PyErr_Print();
- }
- else
- {
- std::cerr << "A C++ exception was thrown for which "
- << "there was no exception translator registered.";
- }
- }
- // Boost.Python doesn't support Py_Finalize yet, so don't call it!
- line_ = "";
- return; // boost::report_errors();
- // PyRun_SimpleString(line_.c_str());
- // Py_Finalize(); // not supported by Boost
-#endif
-#else
- process_command(line_.c_str());
- line_ = "";
- return;
-#endif
- }
- else {
- c[1] = 0;
- line_ += c;
- }
- }
-
- static void inputCB(XtPointer data,int*,XtInputId*)
- {
- ecflowview_input* p = ((ecflowview_input*)data);
- p->input();
- }
-};
-
-scripting::scripting(const char* name):
- name_(name)
-{
-}
-
-scripting::~scripting()
-{
-}
-
-void scripting::init()
-{
- char buf[1024];
-
- sprintf(buf,"%s/startup.script",directory::system());
- run(buf);
-
- sprintf(buf,"%s/startup.script",directory::user());
- run(buf);
-
- const char* file = getenv("ECFLOWVIEW_INPUT");
- if(file != 0) { new ecflowview_input(file);
- std::cout << "# ecflowview listening: " << file << "\n";
- }
-}
-
-void scripting::run(const char* file)
-{
- FILE* f = fopen(file,"r");
- if(!f) {
- //perror(file);
- return;
- }
-
- char line[1024];
- while(fgets(line,sizeof(line),f))
- {
- if(line[0]) line[strlen(line)-1] = 0;
- execute(line);
- }
- fclose(f);
-}
-
-void scripting::execute(const char* cmd)
-{
-#ifdef SCRIPT_PYTHON
-#ifdef linux
- // Py_Initialize();
- init_module_ecflowView();
- // Py_InitModule("ecflowView", ecflowViewMethods);
- std::cout << cmd << "\n";
- python::handle_exception(boost::bind(runit, cmd));
- // PyRun_SimpleString(cmd);
- // Py_Finalize();
-#endif
-#else
-
- process_command(cmd);
-
-#endif
-}
-
-scripting* scripting::find(const char* name)
-{
- scripting* s = first();
- while(s)
- {
- if(strcmp(s->name_,name) == 0)
- return s;
- s = s->next();
- }
- return 0;
-}
-
-int scripting::dispatch(int argc,char **argv)
-{
- scripting* s = find(argv[0]);
- if(s) return s->execute(argc,argv);
- fprintf(stderr,"cannot find command %s\n",argv[0]);
- return 1;
-}
-
-IMP(scripting)
diff --git a/ecflow_4_0_7/view/src/scripting.h b/ecflow_4_0_7/view/src/scripting.h
deleted file mode 100644
index 4b9d50a..0000000
--- a/ecflow_4_0_7/view/src/scripting.h
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef scripting_H
-#define scripting_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#ifndef extent_H
-#include "extent.h"
-#endif
-
-class scripting : public extent<scripting> {
-public:
-
- scripting(const char*);
-
- ~scripting(); // Change to virtual if base class
-
- virtual int execute(int,char**) = 0;
-
- static void init();
- static void run(const char*);
- static void execute(const char*);
-
- static scripting* find(const char* name);
-
- static int dispatch(int,char**);
-
-private:
-
- scripting(const scripting&);
- scripting& operator=(const scripting&);
-
- const char* name_;
-};
-
-inline void destroy(scripting**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/search.cc b/ecflow_4_0_7/view/src/search.cc
deleted file mode 100644
index 2e41b41..0000000
--- a/ecflow_4_0_7/view/src/search.cc
+++ /dev/null
@@ -1,288 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-//=============================================================================================
-
-#include "search.h"
-#include "host.h"
-#include "runnable.h"
-#include <Xm/List.h>
-#include <Xm/Text.h>
-#include <Xm/ToggleB.h>
-#include "gui.h"
-#include "extent.h"
-#include "flags.h"
-#include "result.h"
-#include <X11/IntrinsicP.h>
-
-
-extern "C" {
-#include "xec.h"
-}
-
-search& search::instance()
-{
- static search *m = new search();
- return *m;
-}
-
-search::search():
- name_(0)
- , timed_since_(0)
- , timed_from_(86400*3) // 3 days
-{
- create(gui::top());
-}
-
-search::~search()
-{
-}
-
-
-void search::searchCB(Widget,XtPointer)
-{
- if(name_) XtFree(name_);
- name_ = 0;
-
- if(XmToggleButtonGetState(what_)) {
- char* p = XmTextGetString(what_text_);
- if(*p)
- name_ = XtNewString(p);
- else
- name_ = 0;
- XtFree(p);
- }
-
- type_flags_.clear();
- if(XmToggleButtonGetState(type_))
- scan(type_rowcol_,type_flags_);
-
- status_flags_.clear();
- if(XmToggleButtonGetState(status_))
- scan(status_rowcol_,status_flags_);
-
- special_flags_.clear();
- if(XmToggleButtonGetState(special_))
- scan(special_rowcol_,special_flags_);
-
- if(XmToggleButtonGetState(timed_)) {
- char *since = XmTextGetString(timed_text_since_);
- char *from = XmTextGetString(timed_text_from_);
- if(since)
- timed_since_ = atoi(since);
- if(from)
- timed_from_ = atoi(from);
- fprintf (stdout, "# from: %d\tsince: %d\n", timed_from_, timed_since_);
- XtFree(since);
- XtFree(from);
- } else {
- timed_from_ = 86400;
- timed_since_ = 0;
- }
-
- if(XmToggleButtonGetState(misc_)) {
- icas_ = XmToggleButtonGetState(icase_);
- rege_ = XmToggleButtonGetState(toggle11_);
- glob_ = XmToggleButtonGetState(toggle12_);
- subs_ = XmToggleButtonGetState(toggle13_);
- } else { icas_ = true; subs_ = true; rege_ = glob_ = false; }
-
- result::clear();
- searchable::look_for(*this, !XmToggleButtonGetState(where_));
- result::show();
-}
-
-void search::closeCB(Widget,XtPointer)
-{
- XtUnmanageChild(form_);
-}
-
-void search::mapCB(Widget,XtPointer)
-{
- searchable::parent(where_rowcol_);
-}
-
-void search::raise()
-{
- XtManageChild(form_);
- XMapRaised(XtDisplay(_xd_rootwidget),XtWindow(_xd_rootwidget));
-}
-
-void search::show()
-{
- instance().raise();
-}
-
-#include <sys/types.h>
-#include <regex.h>
-#include <boost/algorithm/string.hpp>
-#include <fnmatch.h>
-
-void search::next(node& n)
-{
- bool ok = true;
- ok &= check(n,type_flags_);
- if (ok) ok &= check(n,status_flags_);
- if (ok) ok &= check(n,special_flags_);
- if (ok && name_) {
- if (subs_) {
- bool res = n.match(name_);
- if (icas_)
- res |= !strncasecmp(name_, n.name().c_str(), strlen(name_));
- else
- res |= !strncmp(name_, n.name().c_str(), strlen(name_));
- ok &= res;
- } else if (glob_) {
- std::string path (n.name());
- std::string pattern (name_);
- if (name_[0] == '/')
- path = n.full_name();
- if (icas_) {
- boost::algorithm::to_lower(path);
- boost::algorithm::to_lower(pattern);
- }
- ok &= 0==fnmatch(pattern.c_str(), path.c_str(), 0);
- } else if (rege_) {
- regex_t exp; int flags = REG_EXTENDED;
- std::string path (n.name());
- std::string pattern (name_);
- if (name_[0] == '/')
- path = n.full_name();
- if (icas_)
- flags &= REG_ICASE;
- int rv = regcomp(&exp, pattern.c_str(), flags);
- if (rv!=0)
- std::cerr << "regcomp failed %d" << rv << "\n";
- else
- ok &= 0==regexec(&exp, path.c_str(), 0, NULL, 0);
- regfree(&exp);
- } else if (icas_) { // ignore case
- ok &= strcasestr(n.name().c_str(),name_) != 0;
- } else { // case sensitive, accept longest names
- ok &= n.match(name_);
- }
- // }
- }
- if (ok && XmToggleButtonGetState(timed_))
- if (n.type() == NODE_TASK || n.type() == NODE_FAMILY || n.type() == NODE_SUITE) {
- boost::posix_time::ptime now(boost::posix_time::second_clock::local_time());
- int diff = (now - n.status_time()).total_seconds();
- ok &= (-1 < timed_since_ && timed_since_ < diff) && diff < timed_from_;
- }
- if(ok) result::show(n);
-}
-
-bool search::check(node& n,array<flags*>& f)
-{
- int c = f.count();
- bool ok = (c == 0);
- for(int i = 0; i < c ; i++)
- ok = ok || f[i]->eval(&n);
- return ok;
-}
-
-
-void search::whatCB(Widget,XtPointer)
-{
- if(XmToggleButtonGetState(what_))
- XtManageChild(what_text_);
- else
- XtUnmanageChild(what_text_);
-}
-
-void search::whereCB(Widget,XtPointer)
-{
- if(XmToggleButtonGetState(where_))
- XtManageChild(where_rowcol_);
- else
- XtUnmanageChild(where_rowcol_);
-}
-
-void search::statusCB(Widget,XtPointer)
-{
- if(XmToggleButtonGetState(status_))
- XtManageChild(status_rowcol_);
- else
- XtUnmanageChild(status_rowcol_);
-}
-
-void search::typeCB(Widget,XtPointer)
-{
- if(XmToggleButtonGetState(type_))
- XtManageChild(type_rowcol_);
- else
- XtUnmanageChild(type_rowcol_);
-}
-
-void search::specialCB(Widget,XtPointer)
-{
- if(XmToggleButtonGetState(special_))
- XtManageChild(special_rowcol_);
- else
- XtUnmanageChild(special_rowcol_);
-}
-
-void search::timedCB(Widget,XtPointer)
-{
- if(XmToggleButtonGetState(timed_)) {
- XtManageChild(timed_rowcol_);
- XtManageChild(timed_text_from_);
- XtManageChild(timed_text_since_);
- } else {
- XtUnmanageChild(timed_rowcol_);
- XtUnmanageChild(timed_text_from_);
- XtUnmanageChild(timed_text_since_);
- }
-}
-
-void search::radioCB(Widget w, XtPointer data) {
- rege_ = XmToggleButtonGetState(toggle11_);
- glob_ = XmToggleButtonGetState(toggle12_);
- subs_ = XmToggleButtonGetState(toggle13_);
-}
-
-void search::miscCB(Widget,XtPointer)
-{
- if(XmToggleButtonGetState(misc_)) {
- XmToggleButtonSetState(icase_, True, False);
- // XmToggleButtonSetState(toggle12_, True, False); // glob
- XmToggleButtonSetState(toggle13_, True, False); // substring
- XtManageChild(misc_rowcol_);
- XtManageChild(fname_);
- XtManageChild(icase_);
- } else {
- XtUnmanageChild(misc_rowcol_);
- XtUnmanageChild(icase_);
- XtUnmanageChild(fname_);
- }
-}
-
-void search::scan(Widget w,array<flags*>& f)
-{
- f.clear();
- CompositeWidget c = (CompositeWidget)w;
- for(unsigned int i = 0 ; i < c->composite.num_children; i++) {
- Widget p = c->composite.children[i];
- if(XmIsToggleButton(p)) {
- flags *s = (flags*)xec_GetUserData(p);
- if(s && XmToggleButtonGetState(p)) {
- f.add(s);
- }
- }
- }
-}
-/*
-^[^#]\s*\w+\s*:(?<data>.*?)$
-
-*/
diff --git a/ecflow_4_0_7/view/src/search.h b/ecflow_4_0_7/view/src/search.h
deleted file mode 100644
index c00d823..0000000
--- a/ecflow_4_0_7/view/src/search.h
+++ /dev/null
@@ -1,82 +0,0 @@
-#ifndef search_H
-#define search_H
-
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#ifdef NO_BOOL
-#include "bool.h"
-#endif
-
-#include "uisearch.h"
-#include "node_lister.h"
-#include "array.h"
-
-class flags;
-
-class search : public search_shell_c, public node_lister {
-public:
-
- search();
-
- ~search(); // Change to virtual if base class
-
- static void show();
-
-private:
-
- search(const search&);
- search& operator=(const search&);
-
- char *name_;
- array<flags*> status_flags_;
- array<flags*> special_flags_;
- array<flags*> type_flags_;
- int timed_since_, timed_from_, subs_, rege_, icas_, glob_ ;
-
-// -- Methods
-
- void raise();
- void scan(Widget,array<flags*>&);
-
-
-// -- Overridden methods
-
- void next(node&);
- bool check(node&,array<flags*>&);
-
-// -- Class members
-
- static search& instance();
-
-// -- Class methods
-
- void closeCB(Widget,XtPointer);
- void searchCB(Widget,XtPointer);
- void mapCB(Widget,XtPointer);
-
- void whatCB(Widget,XtPointer);
- void whereCB(Widget,XtPointer);
- void statusCB(Widget,XtPointer);
- void typeCB(Widget,XtPointer);
- void specialCB(Widget,XtPointer);
- void timedCB(Widget,XtPointer);
- void miscCB(Widget,XtPointer);
- void radioCB(Widget,XtPointer);
-};
-
-inline void destroy(search**) {}
-
-#endif
diff --git a/ecflow_4_0_7/view/src/searchable.cc b/ecflow_4_0_7/view/src/searchable.cc
deleted file mode 100644
index 2f0730b..0000000
--- a/ecflow_4_0_7/view/src/searchable.cc
+++ /dev/null
@@ -1,151 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "top.h"
-#include "searchable.h"
-#include <Xm/Text.h>
-#include <Xm/ToggleB.h>
-
-Widget searchable::parent_ = 0;
-
-searchable::searchable():
- toggle_(0),
- active_(False)
-{
-}
-
-searchable::~searchable()
-{
- if(toggle_)
- XtDestroyWidget(toggle_);
-}
-
-void searchable::look_for(node_lister& p,bool all)
-{
- searchable* s = first();
- while(s)
- {
- if( all || (s->toggle_ && XtIsManaged(s->toggle_) &&
- XmToggleButtonGetState(s->toggle_)))
- s->search(p);
- s = s->next();
- }
-}
-
-void searchable::parent(Widget w)
-{
- parent_ = w;
-
- searchable* s = first();
- while(s)
- {
- if(s->toggle_ == 0)
- {
- s->toggle_ = XmCreateToggleButton(parent_,(char*)s->name(),0,0);
- if(s->active_) XtManageChild(s->toggle_);
- }
- s = s->next();
- }
-}
-
-void searchable::active(Boolean a)
-{
- active_ = a;
-
- if(!toggle_ && parent_)
- parent(parent_);
-
- if(toggle_) {
- if(active_)
- XtManageChild(toggle_);
- else
- XtUnmanageChild(toggle_);
- }
-}
-
-IMP(searchable)
-
-
-
-#if 0
-static char sccsid[] = "%W% %E% B.Raoult";
-
-#include "ecflowview.h"
-#include <Xm/List.h>
-#include <Xm/Text.h>
-
-static Widget text;
-static int ignorecase = TRUE;
-static Widget last_shell = NULL;
-
-void search_set_text_callback(Widget w,Widget t,XtPointer cb)
-{
- char *p;
- Arg arg;
-
- text = t;
- while(!XtIsShell(t))
- t = XtParent(t);
-
- last_shell = t;
-
- XtSetArg(arg,XmNtitle,&p);
- XtGetValues(t,&arg,1);
-
- xec_SetLabel(label_search_text,p);
-
- XtManageChild(search_form);
- XMapRaised(XtDisplay(search),XtWindow(search));
-
-}
-
-void hide_search_callback(Widget w,XtPointer cd,XtPointer cb)
-{
-
- while(!XtIsShell(w))
- w = XtParent(w);
-
- if(last_shell == w)
- {
- XtUnmanageChild(search_form);
- last_shell = NULL;
- }
-}
-
-
-void search_case_callback(Widget w,int nocase,
-XmToggleButtonCallbackStruct *cb)
-{
- if(cb->set) ignorecase = nocase;
-}
-
-void search_next_callback(Widget w,XtPointer cd,XtPointer cb)
-{
- char *p = (char*)XmTextGetString(search_text);
- Boolean (*f)(Widget,char*,Boolean,Boolean,Boolean);
-
- if(!*p) return;
- if(XmIsList(text))
- f = xec_ListSearch;
- else
- if(XmIsText(text))
- f = xec_TextSearch;
- else f = help_search;
-
- if(!(*f)(text,p,ignorecase,FALSE,TRUE)) ring(1);
-
- XtFree((XtPointer)p);
-}
-#endif
diff --git a/ecflow_4_0_7/view/src/searchable.h b/ecflow_4_0_7/view/src/searchable.h
deleted file mode 100644
index 6a3bde0..0000000
--- a/ecflow_4_0_7/view/src/searchable.h
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef searchable_H
-#define searchable_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#ifdef NO_BOOL
-#include "bool.h"
-#endif
-
-#ifndef ecflowview_H
-#include "ecflowview.h"
-#endif
-
-#ifndef extent_H
-#include "extent.h"
-#endif
-
-class node_lister;
-
-class searchable : public extent<searchable> {
-public:
- searchable();
-
- virtual ~searchable(); // Change to virtual if base class
-
- void active(Boolean);
-
- virtual const char* name() const = 0;
- virtual void search(node_lister&) = 0;
-
- static void look_for(node_lister&,bool);
- static void parent(Widget);
-
-protected:
-
- Widget toggle_;
- Boolean active_;
-
-private:
-
- searchable(const searchable&);
- searchable& operator=(const searchable&);
-
- static Widget parent_;
-};
-
-inline void destroy(searchable**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/selection.cc b/ecflow_4_0_7/view/src/selection.cc
deleted file mode 100644
index e90d322..0000000
--- a/ecflow_4_0_7/view/src/selection.cc
+++ /dev/null
@@ -1,153 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #9 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "selection.h"
-#include "node.h"
-#include "observer.h"
-#include "host.h"
-
-class selection_observer :public observer {
- node* n_;
- void gone(observable*);
- void adoption(observable*,observable*);
- void notification(observable*);
-
- std::string location, top;
-
-public:
-
- selection_observer() : n_(0), location ("") {}
- void set(node*);
- node* get() { return n_; }
- const std::string path() { return location; }
- const std::string server() { return top; }
-};
-
-static selection_observer current;
-static selection_observer menu;
-
-void selection_observer::set(node* n)
-{
- if(n == n_)
- return;
-
- if(n_)
- forget(&(n_->serv()));
-
- forget(n_);
- n_ = n;
- observe(n_);
-
- if(n_) {
- observe((&n_->serv()));
- top = n_->serv().name();
- location = n_->full_name();
- }
-}
-
-void selection_observer::adoption(observable* o,observable* n)
-{
- if(o == n_)
- n_ = (node*)n;
- else
- fprintf(stderr, "Selection adoption: bad value\n");
-}
-
-void selection_observer::gone(observable*)
-{
- // printf("Selection gone\n");
- n_ = 0;
-}
-
-void selection_observer::notification(observable*)
-{
-}
-
-
-selection::selection()
-{
-}
-
-selection::~selection()
-{
-}
-
-void selection::notify_new_selection(node* n)
-{
- if(n == current.get())
- return;
-
- if(n == 0) {
- notify_selection_cleared();
- return;
- }
-
- // printf("selection is %s %s %02d\n", n->full_name().c_str(), n->type_name(), n->type());
-
- // if(!n->selectable()) return;
-
- selection* w = first();
-
- current.set(n);
-
- while(w) {
- w->new_selection(*n);
- w = w->next();
- }
-}
-
-void selection::notify_selection_cleared()
-{
- if(current.get() == 0)
- return;
-
- // printf("selection is cleared\n");
-
- selection* w = first();
-
- current.set(0);
-
- while(w)
- {
- w->selection_cleared();
- w = w->next();
- }
-}
-
-void selection::menu_node(node* n)
-{
- menu.set(n);
-}
-
-node *selection::menu_node()
-{
- return menu.get();
-}
-
-node *selection::current_node()
-{
- return current.get();
-}
-
-const std::string selection::current_path()
-{
- return current.path();
-}
-
-const std::string selection::server()
-{
- return current.server();
-}
-IMP(selection)
diff --git a/ecflow_4_0_7/view/src/selection.h b/ecflow_4_0_7/view/src/selection.h
deleted file mode 100644
index 7260444..0000000
--- a/ecflow_4_0_7/view/src/selection.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef selection_H
-#define selection_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#ifndef extent_H
-#include "extent.h"
-#endif
-#include <string>
-
-class host;
-class node;
-class ecf_node;
-
-class selection : public extent<selection> {
-public:
-
- selection();
-
- virtual ~selection(); // Change to virtual if base class
-
- virtual void selection_cleared() = 0;
- virtual void new_selection(node&) = 0;
-
- static void notify_new_selection(node*);
- static void notify_selection_cleared();
-
- static node* menu_node();
- static void menu_node(node*);
- static node* current_node();
- static const std::string current_path();
- static const std::string server();
-
-private:
-
- selection(const selection&);
- selection& operator=(const selection&);
-
- friend class selection_observer;
-};
-
-inline void destroy(selection**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/server.cc b/ecflow_4_0_7/view/src/server.cc
deleted file mode 100644
index d1d60af..0000000
--- a/ecflow_4_0_7/view/src/server.cc
+++ /dev/null
@@ -1,179 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#ifndef server_H
-#include "server.h"
-#endif
-
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/param.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <string.h>
-
-
-#ifdef AIX
-#include <memory.h>
-#endif
-
-#define FAIL(a) do { perror(a); exit(1); } while(0)
-
-server::server(int port):
- soc_(-1)
-{
- int flg;
- struct sockaddr_in sin;
-
-#ifdef SO_LINGER
- struct linger ling;
-#endif
-
- soc_ = socket(AF_INET, SOCK_STREAM, 0);
-
- if (soc_ < 0)
- FAIL("socket");
-
- flg = 1 ;
- if(setsockopt(soc_, SOL_SOCKET, SO_REUSEADDR, &flg, sizeof(flg))<0)
- FAIL("setsockopt SO_REUSEADDR");
-
- flg = 1 ;
- if(setsockopt(soc_, SOL_SOCKET, SO_KEEPALIVE, &flg, sizeof(flg))<0)
- FAIL("setsockopt SO_KEEPALIVE");
-
-#ifdef SO_REUSEPORT
- flg = 1 ;
- if(setsockopt(soc_, SOL_SOCKET, SO_REUSEPORT, &flg, sizeof(flg))<0)
- FAIL("setsockopt SO_REUSEPORT");
-#endif
-
-#ifdef SO_LINGER
- ling.l_onoff = 0;
- ling.l_linger = 0;
- if(setsockopt(soc_, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling))<0)
- FAIL("setsockopt SO_LINGER");
-#else
-#ifdef SO_DONTLINGER
- if(setsockopt(soc_, SOL_SOCKET, SO_DONTLINGER, NULL, 0)<0)
- FAIL("setsockopt SO_DONTLINGER");
-#endif
-#endif
-
-
- memset(&sin, 0, sizeof(struct sockaddr_in));
- sin.sin_port = htons(port);
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = INADDR_ANY;
-
- while (bind(soc_, (struct sockaddr*)&sin, sizeof(struct sockaddr_in)) == -1)
- {
- FAIL("bind");
- sleep(5);
- }
-
- /* socket_buffers(s); */
-
- if(listen(soc_, 5)==-1)
- {
- close(soc_);
- FAIL("listen");
- }
-
- signal(SIGPIPE,SIG_IGN);
-}
-
-server::~server()
-{
- close(soc_);
-}
-
-void server::run()
-{
- struct sockaddr_in from;
-//#ifdef AIX
-// unsigned long fromlen;
-//#else
- socklen_t fromlen; // int fromlen;
-//#endif
- int cnt = 0;
- int clients = 0;
-
- /* Start real server */
-
- if(soc_ < 0) FAIL("Exiting server");
-
- /* Dont't get killed by pipes */
- signal(SIGPIPE,SIG_IGN);
-
- /* Ignore hang up */
- signal(SIGHUP,SIG_IGN);
-
- for(;;)
- {
- int snew;
- fromlen = sizeof(from);
- if((snew = accept(soc_, (struct sockaddr*)&from, &fromlen))<0)
- {
- if(errno != EINTR)
- /* Interrupted system call : got on SIGCHLD signals */
- FAIL("accept");
- }
- else
- {
-
- if(from.sin_family != AF_INET)
- {
- FAIL("connection is not from internet");
- close(snew);
- continue;
- }
-
- fflush(0);
- sighold(SIGCHLD);
-
- if(!fork_)
- {
- serve(snew);
- close(snew);
- }
- else switch(fork())
- {
- case 0:
- close(soc_);
- serve(snew);
- exit(0);
- break;
-
- case -1:
- FAIL("Cannot fork");
- close(snew);
- break;
-
- default:
- cnt++;
- clients++;
- close(snew);
- break;
- }
- sigrelse(SIGCHLD);
- }
- }
-}
diff --git a/ecflow_4_0_7/view/src/server.h b/ecflow_4_0_7/view/src/server.h
deleted file mode 100644
index 82dd217..0000000
--- a/ecflow_4_0_7/view/src/server.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef server_H
-#define server_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-class server {
-public:
-
- server(int port);
- virtual ~server();
-
- void run();
- virtual void serve(int) = 0;
-
-private:
-
- server(const server&);
- server& operator=(const server&);
-
- int soc_;
- bool fork_;
-
-};
-
-inline void destroy(server**) {}
-
-#endif
diff --git a/ecflow_4_0_7/view/src/servers_prefs.cc b/ecflow_4_0_7/view/src/servers_prefs.cc
deleted file mode 100644
index 708a259..0000000
--- a/ecflow_4_0_7/view/src/servers_prefs.cc
+++ /dev/null
@@ -1,259 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #8 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "servers_prefs.h"
-#include "host.h"
-#include "observer.h"
-#include "gui.h"
-#include "xec.h"
-#include "extent.h"
-#include <ctype.h>
-#include <Xm/Text.h>
-#include <Xm/ToggleB.h>
-#include <Xm/List.h>
-
-/* user hosts are added in map order in the 'servers' file:
- order then appears as different according to creation order and
- alphabetic/map order
-*/
-static bool valid_name(const str& n)
-{
- const char* p = n.c_str();
-
- if(*p == 0) return true;
-
- while(*p) {
- if(*p != '_' && !isalnum(*p))
- return false;
- p++;
- }
-
- return true;
-}
-
-static bool valid_host(const str& n)
-{
- const char* p = n.c_str();
-
- if(*p == 0) return false;
-
- while(*p) {
- if(*p != '-' && *p != '.' && !isalnum(*p))
- return false;
- p++;
- }
-
- return true;
-}
-
-static bool valid_num(int)
-{
- return true;
-}
-
-void servers_prefs::add_host(const std::string& h)
-{
- str host = h;
- instance().add(host);
-}
-
-void servers_prefs::create(Widget w,char*)
-{
- servers_form_c::create(w);
- prefs::setup(w);
- build_list();
-}
-
-void servers_prefs::build_list()
-{
- XmListDeleteAllItems(list_);
-
- array<str> x = hosts_;
- hosts_.clear();
-
- for(int i = 0; i < x.count(); i++) {
- add(x[i]);
- }
- xec_ListItemSelect(list_,current_.c_str());
-}
-
-void servers_prefs::add(str&h)
-{
- hosts_.add(h);
- if(_xd_rootwidget == 0)
- return;
-
- host *x = host::find(h.c_str());
- if(x)
- xec_AddListItem(list_,(char*)h.c_str());
-}
-
-void servers_prefs::serversCB(Widget,XtPointer)
-{
- host::broadcast(true);
-}
-
-str servers_prefs::name()
-{
- char *p = XmTextGetString(name_);
- char *h = XmTextGetString(host_);
-
- str x(*p?p:h);
-
- XtFree(p);
- XtFree(h);
-
- return x;
-}
-
-str servers_prefs::machine()
-{
- char *p = XmTextGetString(name_);
- char *h = XmTextGetString(host_);
-
- str x(*h?h:p);
-
- XtFree(p);
- XtFree(h);
-
- return x;
-}
-
-int servers_prefs::number()
-{
-
- char *n = XmTextGetString(number_);
- int x = atol(n);
- XtFree(n);
-
- return x?x: 3141 ;
-}
-
-void servers_prefs::addCB(Widget,XtPointer)
-{
- str p = name();
- str h = machine();
- int n = number();
-
- host* y = host::find(p.c_str());
-
- int v = valid_name(p) && valid_host(h) && valid_num(n);
-
- if(v && (y == 0))
- {
- host::new_host(p.c_str(),h.c_str(),n);
- current_ = p;
- xec_ListItemSelect(list_,p.c_str());
-
- build_list(); // TBD
- XtSetSensitive(update_,false);
- XtSetSensitive(add_,false);
- XtSetSensitive(remove_,true);
- ecf_nick_write(); // TBD
- }
-}
-
-void servers_prefs::removeCB(Widget,XtPointer)
-{
- xec_RemoveListItem(list_,(char*)current_.c_str());
- host::remove_host(current_.c_str());
-
- hosts_.remove(current_);
- current_ = "";
-
- XtSetSensitive(remove_,false);
- XtSetSensitive(update_,false);
- XtSetSensitive(add_,false);
-
- XmTextSetString(name_,"");
- XmTextSetString(host_,"");
- XmTextSetString(number_,"");
-
- ecf_nick_write();
-}
-
-void servers_prefs::check_remove()
-{
-}
-
-void servers_prefs::browseCB(Widget,XtPointer data)
-{
- XmListCallbackStruct *cb = (XmListCallbackStruct *) data;
- char *p = xec_GetString(cb->item);
-
- current_ = p;
-
- host *x = host::find(p);
- if(x)
- {
- changing_ = true;
- XmTextSetString(name_,(char*)x->name());
- XmTextSetString(host_,(char*)x->machine());
-
- char buf[80];
- sprintf(buf,"%d",x->number());
- XmTextSetString(number_,buf);
- changing_ = false;
- }
-
- XtFree(p);
-
- XtSetSensitive(remove_,true);
- XtSetSensitive(update_,false);
- XtSetSensitive(add_,false);
-}
-
-void servers_prefs::changedCB(Widget,XtPointer data)
-{
- if(changing_) return;
-
- str p = name();
- str h = machine();
- int n = number();
-
- host* x = host::find(current_.c_str());
- host* y = host::find(p.c_str());
-
- int v = valid_name(p) && valid_host(h) && valid_num(n);
-
- if(x) {
- bool c = (current_ != p) || (h != str(x->machine())) ||
- (n != x->number());
- XtSetSensitive(update_,v && (y == x || y == 0) && c);
- }
-
- XtSetSensitive(add_,v && (y == 0));
-}
-
-void servers_prefs::updateCB(Widget,XtPointer data)
-{
- str p = name();
- str h = machine();
- int n = number();
-
- host* x = host::find(current_.c_str());
- host* y = host::find(p.c_str());
-
- int v = valid_name(p) && valid_host(h) && valid_num(n);
- if(v && x && (x == y || y == 0))
- {
- x->change(p.c_str(),h.c_str(),n);
- xec_ReplaceListItem(list_,current_.c_str(),p.c_str());
- xec_ListItemSelect(list_,p.c_str());
- current_ = p;
- XtSetSensitive(update_,false);
- XtSetSensitive(add_,false);
- }
-}
diff --git a/ecflow_4_0_7/view/src/servers_prefs.h b/ecflow_4_0_7/view/src/servers_prefs.h
deleted file mode 100644
index 21adc06..0000000
--- a/ecflow_4_0_7/view/src/servers_prefs.h
+++ /dev/null
@@ -1,79 +0,0 @@
-#ifndef servers_prefs_H
-#define servers_prefs_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#ifndef prefs_H
-#include "prefs.h"
-#endif
-
-#ifndef uiservers
-#include "uiservers.h"
-#endif
-
-#ifndef str_H
-#include "str.h"
-#endif
-
-#ifndef array_H
-#include "array.h"
-#endif
-
-#ifndef Singleton_H
-#include "singleton.h"
-#endif
-
-class servers_prefs : public singleton<servers_prefs>, public prefs
- , public servers_form_c {
-public:
-
- servers_prefs() : changing_(false) {}
-
- ~servers_prefs() {}
-
- void check_remove();
-
- virtual Widget widget() { return _xd_rootwidget; }
-
- static void add_host(const std::string&);
-private:
-
- servers_prefs(const servers_prefs&);
- servers_prefs& operator=(const servers_prefs&);
-
- array<str> hosts_;
- bool changing_;
- str current_;
-
- int number();
- str name();
- str machine();
-
- void add(str&);
- void build_list();
-
- virtual void browseCB( Widget w, XtPointer );
- virtual void serversCB( Widget w, XtPointer );
- virtual void addCB( Widget w, XtPointer );
- virtual void removeCB( Widget w, XtPointer );
- virtual void updateCB( Widget w, XtPointer );
- virtual void changedCB( Widget w, XtPointer );
- virtual void create(Widget w,char*);
-};
-
-inline void destroy(servers_prefs**) {}
-
-#endif
diff --git a/ecflow_4_0_7/view/src/show.cc b/ecflow_4_0_7/view/src/show.cc
deleted file mode 100644
index 536e6b9..0000000
--- a/ecflow_4_0_7/view/src/show.cc
+++ /dev/null
@@ -1,93 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "show.h"
-#include "globals.h"
-option<int> show::status32_ (globals::instance(), "show_mask32", 0);
-
-option<int> show::status_ (globals::instance(), "show_mask",
- (1<<show::unknown)
- |(1<<show::suspended)
- |(1<<show::complete)
- |(1<<show::queued)
- |(1<<show::submitted)
- |(1<<show::active)
- |(1<<show::aborted)
- |(1<<show::time_dependant)
- |(1<<show::late_nodes)
- // |(1<<show::migrated_nodes)
- |(1<<show::rerun_tasks)
- |(1<<show::nodes_with_messages)
- |(1<<show::label)
- |(1<<show::meter)
- |(1<<show::event)
- |(1<<show::repeat)
- |(1<<show::time)
- |(1<<show::date)
- |(1<<show::late)
- |(1<<show::inlimit)
- |(1<<show::limit)
- |(1<<show::trigger)
- // & (~(1<<show::variable))
- // & (~(1<<show::genvar))
- |(1<<show::time_icon)
- |(1<<show::date_icon)
- |(1<<show::late_icon)
- |(1<<show::waiting_icon)
- |(1<<show::rerun_icon)
- // |(1<<show::migrated_icon)
- |(1<<show::message_icon)
- // & (~(1<<show::defstatus_icon)) & (~(1<<show::zombie_icon))
- );
-
-show::show(int f) : flag_(f) {
- status_ = status_ & (~(1<<show::variable));
- status_ = status_ & (~(1<<show::genvar));
-}
-
-show::~show() {}
-
-void show::on()
-{
- if (flag_ > 31) {
- status32_ = int(status32_) | (1<<(flag_-32));
- } else {
- status_ = int(status_ ) | (1<<(flag_));
- }
-}
-
-void show::off()
-{
- if (flag_ == show::all) {
- status_ = 0xFFFF ; status32_ = 0xFFFF;
- status32_ = (int) (status32_) & (~(1<<(show::none-32)));
- status32_ = (int) (status32_) & (~(1<<(show::all -32)));
- } else if (flag_ == show::none) {
- status_ = 0; status32_ = 0;
- } else if (flag_ > 31) {
- status32_ = int(status32_) & (~(1<<(flag_-32)));
- } else {
- status_ = int(status_) & (~(1<<flag_));
- }
-}
-
-bool show::wanted()
-{
- if (flag_ > 31) {
- return (int(status32_) & (1<<(flag_-32))) != 0;
- } else {
- return (int(status_ ) & (1<<flag_)) != 0;
- }
-}
diff --git a/ecflow_4_0_7/view/src/show.h b/ecflow_4_0_7/view/src/show.h
deleted file mode 100644
index b439e31..0000000
--- a/ecflow_4_0_7/view/src/show.h
+++ /dev/null
@@ -1,104 +0,0 @@
-#ifndef show_H
-#define show_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-// #include <inttypes.h>
-
-#ifndef option_H
-#include "option.h"
-#endif
-
-#ifdef WITH_INT128
-#define VLONG uint128
-#else
-// #define VLONG uint64_t
-// #define VLONG unsigned long long
-// #define VLONG __int64
-#define VLONG int
-#endif
-
-
-class show {
- int flag_;
- static option< VLONG > status_;
- static option< VLONG > status32_;
-
-public:
-
- enum {
- unknown ,
- suspended ,
- complete ,
- queued ,
- submitted ,
- active ,
- aborted ,
- time_dependant ,
- late_nodes ,
- waiting_nodes ,
- migrated_nodes ,
- rerun_tasks ,
- nodes_with_messages ,
- label ,
- meter,
- event ,
- repeat ,
- time ,
- date ,
- late ,
- trigger,
- variable,
- genvar,
- limit,
- inlimit,
- time_icon,
- date_icon,
- late_icon,
- waiting_icon,
- rerun_icon,
- migrated_icon,
- message_icon,
-
- defstatus_icon, zombie_icon, // time_holding_icon, date_holding_icon
- all, none
- };
-
- // show(int f) : flag_(f) {};
- show(int f);
- ~show();
-
- void on();
- void off();
- bool wanted();
-
- static inline bool want(int flag) {
- return (flag > 31) ?
- (int(status32_) & (1<<(flag-32))) != 0 :
- (int(status_) & (1<<flag))!=0; }
-
- static inline bool want32(int flag)
- { return (flag > 31) ?
- (int(status32_) & (1<<(flag-32))) != 0 :
- false; }
-
- static inline VLONG status() { return int(status_); }
-
- VLONG flag() const { return flag_; }
-private:
- show(const show&);
- show& operator=(const show&);
-};
-#endif
diff --git a/ecflow_4_0_7/view/src/simple_node.cc b/ecflow_4_0_7/view/src/simple_node.cc
deleted file mode 100644
index ef9f7dc..0000000
--- a/ecflow_4_0_7/view/src/simple_node.cc
+++ /dev/null
@@ -1,1062 +0,0 @@
-//===================================================================================(variable_node* run==========
-// Name :
-// Author :
-// Revision : $Revision: #53 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "arch.h"
-#include "simple_node.h"
-#include "host.h"
-#include "show.h"
-#include "flags.h"
-#include "external.h"
-#include "selection.h"
-#include "pixmap.h"
-#include "url.h"
-#include "tree.h"
-#include "variable_node.h"
-#include "tip.h"
-
-#ifndef FLAG_HPP_
-#include "Flag.hpp"
-#endif
-#include "RepeatAttr.hpp"
-
-#include <X11/X.h>
-#include <Xm/ManagerP.h>
-#include <Xm/DrawP.h>
-#include <sstream>
-
-#include "trigger_lister.h"
-#include "text_lister.h"
-#include "html_lister.h"
-
-#ifndef events_H
-#include "events.h"
-#endif
-#include "dummy_node.h"
-
-#ifndef ecf_node_
-#include "ecf_node.h"
-#endif
-
-namespace ecf {
-const char *status_name[10]
- = { "unknown", "suspended", "complete", "queued", "submitted", "active",
- "aborted", "shutdown", "halted" , NULL };
-}
-
-const int kHMargins = 4;
-const int kVMargins = 1;
-
-static struct {
- char* name_;
- int vers_;
- pixmap* pixmap_;
- flags* flag_;
- int show_;
-} pix[] = {
- {(char*)"waiting", 0, 0, new procFlag(&node::isWaiting), show::waiting_icon},
-
- {(char*)"clock", 0, 0, new procFlag(&node::hasTimeHolding), show::time_icon},
- {(char*)"calendar", 0, 0, new procFlag(&node::hasDate), show::date_icon},
-
- {(char*)"late", 0, 0, new procFlag(&node::isLate), show::late_icon},
-
- {(char*)"rerun", 0, 0, new procFlag(&node::isRerun), show::rerun_icon},
-
- {(char*)"migrated", 0, 0, new procFlag(&node::isMigrated),
- show::migrated_icon},
-
- {(char*)"message", 0, 0, new procFlag(&node::hasMessages),
- show::message_icon},
-
- {(char*)"defstatus", 0, 0, new procFlag(&node::isDefComplete),
- show::defstatus_icon},
-
- {(char*)"Zbw", 1, 0, new procFlag(&node::hasZombieAttr), show::zombie_icon},
-
- {(char*)"Z", 1, 0, new procFlag(&node::isZombie), show::zombie_icon},
-
- {(char*)"force_abort", 1, 0, new procFlag(&node::isForceAbort), 1},
- {(char*)"user_edit", 1, 0, new procFlag(&node::isUserEdit), 1},
- {(char*)"task_aborted", 1, 0, new procFlag(&node::isTaskAbort), 1},
- {(char*)"edit_failed", 1, 0, new procFlag(&node::isEditFailed), 1},
- {(char*)"cmd_failed", 1, 0, new procFlag(&node::isCmdFailed), 1},
- {(char*)"no_script", 1, 0, new procFlag(&node::isScriptMissing), 1},
- {(char*)"killed", 1, 0, new procFlag(&node::isKilled), 1},
- {(char*)"byrule", 1, 0, new procFlag(&node::isByRule), 1},
- {(char*)"queuelimit", 1, 0, new procFlag(&node::isQueueLimit), 1},
-
- {(char*)"folded", 0, 0, new procFlag(&node::isFolded), 0},
-
- {(char*)"locked", 0, 0, new procFlag(&node::isLocked), 0}, /* --- shall appear last */
-
- {(char*)"clock_free", 0, 0, new procFlag(&node::hasTime), show::time_icon},
-
-};
-
-simple_node::simple_node(host& h,ecf_node* n) : node(h,n)
- , old_status_(-1)
- , old_tryno_(-1)
- , old_flags_(-1)
-{
- old_flags_ = flags();
- old_status_ = status();
- old_tryno_ = tryno();
-}
-
-const int kPixSize = 16;
-
-#ifdef BRIDGE
-simple_node::simple_node(host& h,sms_node* n, char b)
- : node(h,n,b)
- , old_status_(-1)
- , old_tryno_(-1)
- , old_flags_(-1)
-{
- insert(node::create(h,(sms_node*)n->label));
- insert(node::create(h,(sms_node*)n->meter));
- insert(node::create(h,(sms_node*)n->event));
- if (n->complete)
- insert(node::create(h,(sms_node*)n->complete,'c'));
- insert(node::create(h,(sms_node*)n->trigger, 't'));
-
- insert(node::create(h,(sms_node*)n->repeat));
- insert(node::create(h,(sms_node*)n->genvars,'g'));
- insert(node::create(h,(sms_node*)n->variable));
-
- insert(node::create(h,(sms_node*)n->limit));
- insert(node::create(h,(sms_node*)n->inlimit));
-
- insert(node::create(h,(sms_node*)n->date));
- insert(node::create(h,(sms_node*)n->time));
- insert(node::create(h,(sms_node*)n->autocm,'c'));
-
- // if(n->late) n->late->parent = owner_;
- insert(node::create(h,(sms_node*)n->late,'l'));
-}
-
-/* void simple_node::scan(sms_tree* m,text_lister& f,bool b) {} */
-
- void simple_node::scan(sms_tree* m,trigger_lister& f,bool b) {}
-
-#endif
-
-simple_node::~simple_node()
-{
-}
-
-inline bool wanted(int n)
-{
- return (n == 0 || show::want(n));
-}
-
-void simple_node::sizeNode(Widget w,XRectangle* r,bool tree)
-{
- if(!tree) {
- node::sizeNode(w,r,false);
- return;
- }
-
- int extra = 0;
- unsigned int i;
-
- if(pix[0].pixmap_ == 0)
- {
- for(i = 0; i < XtNumber(pix); i++)
- pix[i].pixmap_ = &(pixmap::find(pix[i].name_));
- }
-
- for(i = 0; i < XtNumber(pix) ; i++)
- if(wanted(pix[i].show_) && pix[i].flag_->eval(this))
- extra++;
-
- XmString s = tree?labelTree():labelTrigger();
- XmFontList f = tree?fontlist():smallfont();
-
- r->width = XmStringWidth(f,s) + 2*kHMargins + extra * kPixSize;
- r->height = XmStringHeight(f,s) + 2*kVMargins;
- if(r->height < kPixSize + 2*kVMargins) r->height = kPixSize + 2*kVMargins;
-}
-
-void simple_node::drawBackground(Widget w,XRectangle* r,bool tree)
-{
- node::drawBackground(w,r,tree);
- GC gc = colorGC(status());
- XFillRectangles(XtDisplay(w),XtWindow(w),gc,r,1);
-}
-
-void simple_node::drawNode(Widget w,XRectangle* r,bool tree)
-{
- if(!tree) {
- node::drawNode(w,r,tree);
- shadow(w,r);
- return;
- }
-
- unsigned int extra = 0;
- Pixmap images[XtNumber(pix)];
-
- XmString s = tree?labelTree():labelTrigger();
- XmFontList f = tree?fontlist():smallfont();
- unsigned int i;
-
- for(i = 0; i < XtNumber(pix) ; i++)
- if(wanted(pix[i].show_) && pix[i].flag_->eval(this))
- images[extra++] = pix[i].pixmap_->pixels();
-
- XRectangle x = *r;
- x.width = XmStringWidth(f,s) + 2*kHMargins;
- XRectangle y = x; // *r;
-
- drawBackground(w,&y,tree);
-
-
- XmStringDraw(XtDisplay(w),XtWindow(w),
- f,
- s,
- blackGC(),
- r->x /*+ kHMargins*/,
- r->y + kVMargins,
- x.width,
- XmALIGNMENT_CENTER,
- XmSTRING_DIRECTION_L_TO_R, r);
-
- for(i = 0 ; i < extra ; i++)
- {
- /* XSetClipMask(XtDisplay(w),blackGC(),masks[i]); */
- XCopyArea(XtDisplay(w),
- images[i],
- XtWindow(w),
- blackGC(),
- 0,0,kPixSize,kPixSize,
- r->x + x.width + (i*kPixSize),
- r->y + (r->height - kPixSize) / 2);
- /* XSetClipMask(XtDisplay(w),blackGC(),None); */
- }
-
- shadow(w,&y);
-}
-
-
-Pixel simple_node::color() const
-{
- return colors(status());
-}
-
-int simple_node::tryno() const {
-#ifdef BRIDGE
- if (tree_) return tree_->tryno;
-#endif
- return owner_ ? owner_->tryno() : -1;
-}
-
-Boolean simple_node::hasTriggers() const
-{
-#ifdef BRIDGE
- if (tree_) return tree_->trigger != 0;
-#endif
- return owner_ ? owner_->hasTrigger() : False;
-}
-
-Boolean simple_node::hasTime() const /* time is free , yellow background icon */
-{
-#ifdef BRIDGE
- if (tree_) return tree_->time != 0;
-#endif
- if (hasTimeHolding()) return False;
- return owner_ ? owner_->hasTime() : False;
-}
-
-Boolean simple_node::hasDate() const
-{
-#ifdef BRIDGE
- if (tree_) return tree_->date != 0;
-#endif
- return owner_ ? owner_->hasDate() : False;
-}
-
-Boolean simple_node::hasTimeHolding() const /* grey */
-{
- if (owner_)
- if (owner_->hasTime()) {
- Node *node = owner_->get_node();
- if (!node) return False;
- TimeDepAttrs *attr = node->get_time_dep_attrs();
- if (!attr) return False;
- return !attr->time_today_cron_is_free();
- }
- return False;
-}
-
-Boolean simple_node::hasZombieAttr() const
-{
-#ifdef BRIDGE
- if (tree_) return ecfFlag(FLAG_ZOMBIE);
-#endif
- return owner_ ? owner_->hasZombieAttr() : False;
-}
-
-Boolean simple_node::hasManual() const
-{ return True; }
-
-Boolean simple_node::isDefComplete() const {
-#ifdef BRIDGE
- if (tree_) {
- if (tree_->defstatus == STATUS_COMPLETE)
- return True;
- // else if (tree_ && sms_variable_getvar("SMSNOSCRIPT", tree_))
- // return True;
- else if (tree_->complete != 0 &&
- (sms_status_trigger(tree_->complete) == FALSE))
- return True;
- }
-#endif
- if (!owner_) return False;
- else if (!owner_)
- return False;
- else if (owner_->defstatus() == STATUS_COMPLETE)
- return True;
- Node* ecf = __node__() ? __node__()->get_node() : 0;
- if (ecf) {
- AstTop* t = ecf->completeAst();
- if (t)
- if (t->evaluate())
- return True;
- }
- return False;
-}
-
-std::string simple_node::variable(const std::string& name, bool substitute)
-{
- if (__node__())
- if (__node__()->get_node()) {
- const Variable & var = __node__()->get_node()->findVariable(name);
- if (!var.empty()) {
- std::string value = var.theValue();
- if (substitute)
- __node__()->get_node()->variableSubsitution(value);
- return value;
- } // return var.theValue();
- }
- for (node *run = kids(); run; run = run->next()) {
- if (run->type() == NODE_VARIABLE && run->name() == name) {
- variable_node *nvar = (variable_node*) run;
- if (nvar->get_var() != ecf_node::none())
- return nvar->get_var();
- }
- }
- if (!parent())
- return ecf_node::none();
- return parent()->variable(name, substitute);
-}
-
-void simple_node::info(std::ostream& f)
-{
- static const std::string inc = " ";
- node::info(f);
- f << type_name() << " " << name() << "\n";
- {
- if (owner_) {
-
- if (owner_->type() == NODE_SUITE) {
- Suite* suite = dynamic_cast<Suite*>(owner_->get_node());
- // f << "clock : ";
- if (suite->clockAttr()) {
- suite->clockAttr().get()->print(f); // f << "\n";
- }
- }
-
- int defs = owner_->defstatus();
- if (defs != STATUS_QUEUED && defs != STATUS_UNKNOWN)
- f << inc << "defstatus " << ecf::status_name[defs] << "\n";
-
- Node* node = owner_->get_node();
- if (node) {
- // if (node->repeat().toString() != "") // repeat // duplicated on suite node
- // f << inc << node->repeat().toString() << "\n";
-
- /* zombies attribute */
- const std::vector<ZombieAttr> & vect = node->zombies();
- std::vector<ZombieAttr>::const_iterator it;
- for (it = vect.begin(); it != vect.end(); ++it)
- f << inc << it->toString() << "\n";
-
- /* autocancel */
- if (node->hasAutoCancel() && node->get_autocancel())
- f << inc << node->get_autocancel()->toString() << "\n";
- }
- }
- if(status() == STATUS_SUSPENDED)
- f << inc << "# " << type_name() << " " << this->name() << " is " << status_name()
- << "\n";
- }
- {
- std::vector<Variable> gvar;
- std::vector<Variable>::const_iterator it, gvar_end;
- ecf_node* prox = __node__();
- if (!prox) return;
-
- Defs* defs = 0;
- Node* ecf = 0;
- if (dynamic_cast<ecf_concrete_node<Node>*>(prox)) {
- ecf = dynamic_cast<ecf_concrete_node<Node>*>(prox)->get();
- }
- else if (dynamic_cast<ecf_concrete_node<Task>*>(prox)) {
- ecf = dynamic_cast<ecf_concrete_node<Task>*>(prox)->get();
- }
- else if (dynamic_cast<ecf_concrete_node<Family>*>(prox)) {
- ecf = dynamic_cast<ecf_concrete_node<Family>*>(prox)->get();
- }
- else if (dynamic_cast<ecf_concrete_node<Suite>*>(prox)) {
- ecf = dynamic_cast<ecf_concrete_node<Suite>*>(prox)->get();
- }
- else if (dynamic_cast<ecf_concrete_node<Defs>*>(prox)) {
- defs = dynamic_cast<ecf_concrete_node<Defs>*>(prox)->get();
- }
- if (!ecf && !defs) {
- return;
- }
-
- if (ecf ) {
- gvar.clear();
-
- if (ecf->hasTimeDependencies()) {
- f << inc << "# time-date-dependencies: ";
- if (ecf->isTimeFree()) f << "free\n";
- else f << "holding\n";
- }
- ecf->gen_variables(gvar);
- for(it = gvar.begin(); it != gvar.end(); ++it) {
- f << inc << "# edit " << (*it).name() << " '" << (*it).theValue() << "'\n";
- }
-
- gvar = ecf->variables();
- for(it = gvar.begin(); it != gvar.end(); ++it) {
- f << inc << "edit " << (*it).name() << " '" << (*it).theValue() << "'\n";
- }
- }
- if (defs) {
- const std::vector<Variable>& gvar = defs->server().user_variables();
- for(it = gvar.begin(); it != gvar.end(); ++it) {
- f << inc << "# edit " << (*it).name() << " '" << (*it).theValue() << "'\n";
- }
- const std::vector<Variable>& var = defs->server().server_variables();
- for(it = var.begin(); it != var.end(); ++it) {
- f << inc << "edit " << (*it).name() << " '" << (*it).theValue() << "'\n";
- }
- }}
-
- for (node *run=kids(); run; run=run->next())
- if (run->type() == NODE_VARIABLE) {
- /* variable_node *var = dynamic_cast<variable_node*> (run);
- if (var && var->name() == "") { f << inc << "# empty variable!" << "\n"; continue; }
- if (var->isGenVariable(0x0))
- f << inc << "# edit " << run->name() << " '" << var->get_var() << "'" << "\n";
- else
- f << inc << "edit " << run->name() << " '" << var->get_var() << "'" << "\n";*/
- } else {
- f << inc;
- int i = run->type();
- if (!owner_ || (i == NODE_SUITE || i == NODE_FAMILY ||
- i == NODE_TASK || i == NODE_ALIAS))
- f << run->type_name() << " ";
- f << run->toString() << "\n";
- // f << run->dump() << "\n";
- }
- f << "end" << type_name() << " # " << name() << "\n";
-}
-
-void simple_node::scan(Ast *m,trigger_lister& tlr,node* trg)
-{
- if(!m) return;
- std::string path = "";
- { AstNode *an = dynamic_cast<AstNode*> (m);
- if(an) { path = an->nodePath(); path = m->expression(); } }
- { AstVariable *an = dynamic_cast<AstVariable*> (m);
- if(an) { path = an->nodePath(); path = m->expression(); } }
-
- if (path != "") {
- node* n = parent() ? parent()->find(path) : node::find(path);
-
- if(n) {
- tlr.next_node(*n,0,trigger_lister::normal,trg);
- } else if (external::is_external(path))
- tlr.next_node(external::get(path),0,trigger_lister::normal,trg);
- }
- {
- scan(m->left(), tlr,trg);
- scan(m->right(),tlr,trg);
- }
-}
-
-/*******************************/
-
-class fik : public trigger_lister {
- node* n_;
- node* k_;
- trigger_lister& l_;
-public:
-
- fik(node* n,node* k,trigger_lister& l): n_(n),k_(k),l_(l) {};
-
- void next_node(node& n, node*,int type,node *t) {
- if(!n.is_my_parent(n_)) {
- // k is a kid of n whose trigger_panel is outside its subtree
- l_.next_node(n,k_,trigger_lister::child,t);
- }
- }
-};
-
-class fip : public trigger_lister {
- node* p_;
- trigger_lister& l_;
-
-public:
- fip(node* p,trigger_lister& l) : p_(p), l_(l) {}
-
- void next_node(node& n, node*,int type,node *t)
- { l_.next_node(n,p_,trigger_lister::parent,t); }
-};
-
-/*******************************/
-
-static void find_in_kids(node& n,node* k,trigger_lister& tlr)
-{
- while(k) {
- fik f(&n,k,tlr);
- k->triggers(f);
- find_in_kids(n,k->kids(),tlr);
- k = k->next();
- }
-}
-#include <ExprAstVisitor.hpp>
-
-class AstCollateXNodesVisitor : public ecf::ExprAstVisitor {
-public:
- AstCollateXNodesVisitor( std::set<node*>& );
- virtual ~AstCollateXNodesVisitor();
-
- virtual void visitTop(AstTop*){}
- virtual void visitRoot(AstRoot*){}
- virtual void visitAnd(AstAnd*){}
- virtual void visitNot(AstNot*){}
- virtual void visitPlus(AstPlus*){}
- virtual void visitMinus(AstMinus*){}
- virtual void visitDivide(AstDivide*){}
- virtual void visitMultiply(AstMultiply*){}
- virtual void visitModulo(AstModulo*){}
- virtual void visitOr(AstOr*){}
- virtual void visitEqual(AstEqual*){}
- virtual void visitNotEqual(AstNotEqual*){}
- virtual void visitLessEqual(AstLessEqual*){}
- virtual void visitGreaterEqual(AstGreaterEqual*){}
- virtual void visitGreaterThan(AstGreaterThan*){}
- virtual void visitLessThan(AstLessThan*){}
- virtual void visitLeaf(AstLeaf*){}
- virtual void visitInteger(AstInteger*){}
- virtual void visitString(AstString*){}
- virtual void visitNodeState(AstNodeState*){}
- virtual void visitEventState(AstEventState*);
- virtual void visitNode(AstNode*);
- virtual void visitVariable(AstVariable*);
-
-private:
- std::set<node*>& theSet_;
-};
-
-
-AstCollateXNodesVisitor::AstCollateXNodesVisitor( std::set<node*>& s) : theSet_(s) {}
-AstCollateXNodesVisitor::~AstCollateXNodesVisitor() {}
-
-void AstCollateXNodesVisitor::visitEventState(AstEventState* astNode)
-{
-}
-
-void AstCollateXNodesVisitor::visitNode(AstNode* astNode)
-{
- Node* referencedNode = astNode->referencedNode();
- node* xnode = NULL;
- if (referencedNode)
- xnode = (node*) referencedNode->graphic_ptr();
- if ( xnode ) theSet_.insert(xnode);
-}
-
-void AstCollateXNodesVisitor::visitVariable(AstVariable* astVar)
-{
- Node* referencedNode = astVar->referencedNode();
- if (referencedNode) {
- simple_node* xnode = (simple_node*) referencedNode->graphic_ptr();
- if (0 == xnode) return;
-
- int type;
- node* run;
- for (run = xnode->kids(); 0 != run; run = run->next()) {
- if (run->name() == astVar->name()) {
- type = run->type();
- if (type == NODE_EVENT
- || type == NODE_METER
- || type == NODE_VARIABLE) {
- theSet_.insert(run);
- }
- }
- }
- }
-}
-
-void simple_node::triggers(trigger_lister& tlr)
-{
- if(tlr.self()) {
-#ifdef BRIDGE
- if (tree_) {
- sms_node* ow = tree_;
- if(ow->trigger)
- scan(((sms_trigger*)ow->trigger)->math,tlr,node::find((sms_node*) ow->trigger));
-
- if(ow->complete)
- scan(((sms_trigger*)ow->complete)->math,tlr,node::find((sms_node*) ow->complete));
-
- sms_limit* x = (sms_limit*) (ow->inlimit);
- while(x)
- {
- node* n = node::find((sms_node*) x->limit);
- if(n) tlr.next_node(*n,0,trigger_lister::normal,n);
- x = x->next;
- }
-
- sms_date* d = ow->date;
- while(d) {
- node* n = node::find((sms_node*) d);
- if(n) tlr.next_node(*n,0,trigger_lister::normal,n);
- d = d->next;
- }
-
- sms_time* t = ow->time;
- while(t) {
- node* n = node::find((sms_node*) t);
- if(n) tlr.next_node(*n,0,trigger_lister::normal,n);
- t = t->next;
- }
- }
- else
-#endif
- if (owner_) {
- if (type() != NODE_SUPER && type() != NODE_SUITE) {
- Node* ecf = __node__() ? __node__()->get_node() : 0;
- std::set<node*> theSet;
- std::set<node*>::iterator sit;
- AstCollateXNodesVisitor astVisitor(theSet);
-
- if (ecf) {
- if (ecf->completeAst()) {
- ecf->completeAst()->accept(astVisitor);
- }
- if (ecf->triggerAst()) {
- ecf->triggerAst()->accept(astVisitor);
- }
- }
- for (sit = theSet.begin(); sit != theSet.end(); ++sit)
- tlr.next_node( *(*sit), 0, trigger_lister::normal, *sit);
- }
-
- for (node *n = this->kids(); n ; n = n->next()) {
- int type = n->type();
- {
- ecf_concrete_node<InLimit const> *c =
- dynamic_cast<ecf_concrete_node<InLimit const>*> (n->__node__());
- InLimit const * i = c ? c->get() : 0;
- if (i) {
- node *xn = 0;
- if ((xn = find_limit(i->pathToNode(), i->name())))
- tlr.next_node(*xn,0,trigger_lister::normal,xn);
- }
- }
- if (type == NODE_DATE || type == NODE_TIME)
- tlr.next_node(*n,0,trigger_lister::normal,n);
- }
- }
- }
- if(tlr.parents()) {
- node* p = parent();
- while(p) {
- fip f(p,tlr);
- p->triggers(f);
- p = p->parent();
- }
- }
-
- if(tlr.kids())
- find_in_kids(*this,kids(),tlr);
- }
-
-boost::posix_time::ptime simple_node::status_time() const {
- if (owner_) return owner_->status_time();
- return boost::posix_time::ptime();
-}
-
-int simple_node::flags() const {
-#ifdef BRIDGE
- if (tree_) return tree_->flags;
-#endif
- // FIXME defs
- return owner_ ? owner_->flags() : 0;
-}
-
-Boolean simple_node::ecfFlag(int n) const
-{
- return (flags() & (1<<n)) != 0;
-}
-
-Boolean simple_node::show_it() const
-{
- if(((node*)this) == selection::current_node())
- return True;
-
- if(show::want(show::time_dependant) && (hasDate() || hasTime()))
- return True;
-
- if(show::want(show::late_nodes) && isLate())
- return True;
-
- if(show::want(show::migrated_nodes) && isMigrated())
- return True;
-
- if(show::want(show::rerun_tasks) && tryno() > 1)
- return True;
-
- if(show::want(show::nodes_with_messages) && hasMessages())
- return True;
-
- if(show::want(show::waiting_nodes) && isWaiting())
- return True;
-
- if(show::want(show::defstatus_icon) && isDefComplete())
- return True;
-
- if(show::want(show::zombie_icon) && isZombie())
- return True;
-
- node* k = kids();
- while(k) {
- if(k->show_it())
- return True;
- k = k->next();
- }
-
- return False;
-}
-
-Boolean simple_node::visible() const
-{
- int wanted = status() - STATUS_UNKNOWN + show::unknown;
- if((wanted < 32 && (show::want(wanted))) || show::want32(wanted))
- return True;
-
- node* n = kids_;
- while(n) {
- if(n->visible_kid()) return True;
- n = n->next();
- }
- return False;
-}
-
-Boolean simple_node::visible_kid() const
-{
- return visible();
-}
-
-
-const char* simple_node::status_name() const
-{
-#ifdef BRIDGE
- if (tree_) return ecf::status_name[tree_->status];
-#endif
- return ecf::status_name[owner_ ? owner_->status() : 0];
-}
-
-void simple_node::why(std::ostream& f)
-{
- if (owner_)
- owner_->why(f);
- else if(status() == STATUS_SUSPENDED) {
- f << type_name() << " " << this << " is " << status_name() << "\n";
- }
-}
-
-void simple_node::scan_limit(Ast* m,std::ostream& f)
-{
- if(!m) return;
-
- AstNode *an = dynamic_cast<AstNode*> (m);
- if(an) {
- const node* n = node::find(an->nodePath());
- if(!n)
- f << "limit_node not found??\n";
- else if(n->evaluate())
- f << n->type_name() << " " << n->name() << " is " << n->status_name() << "\n";
- } else {
- scan_limit(m->left(),f);
- scan_limit(m->right(),f);
- }
-}
-
-int kind(Ast *t) {
- int rc = 0;
- if (!t) return rc;
-
- ++rc ; if (t->type() == "or") return rc;
- ++rc ; if (t->type() == "and") return rc;
- ++rc ; if (t->type() == "equal") return rc;
- ++rc ; if (t->type() == "not-equal") return rc;
- ++rc ; if (t->type() == "less-than") return rc;
- ++rc ; if (t->type() == "less-equal") return rc;
- ++rc ; if (t->type() == "greater-than") return rc;
- ++rc ; if (t->type() == "greater-equal") return rc;
- ++rc ; if (t->type() == "plus") return rc;
- ++rc ; if (t->type() == "minus") return rc;
- ++rc ; // if (t->type == "multiply") return rc;
- ++rc ; // if (t->type == "divide") return rc;
- ++rc ; // if (t->type == "mod") return rc;
- ++rc ; // if (t->type == "pow") return rc;
- ++rc ; if (t->type() == "not") return rc;
- ++rc ; if (t->type() == "unary") return rc;
- ++rc ; if (t->type() == "open") return rc;
- ++rc ; if (t->type() == "close") return rc;
- ++rc ; if (t->type() == "node") return rc;
- if (t->type() == "variable") return rc;
- if (t->type() == "event_state") return rc;
- return 0;
-}
-
-static struct {
- int eval_;
- int print_;
- char* pos_;
- char* neg_;
-} names [] = {
- {0,0,(char*)"",(char*)"",}, // M_NIL
- {1,0,(char*)"",(char*)"",}, // M_OR
- {1,0,(char*)"",(char*)"",}, // M_AND
- {1,1,(char*)"is", (char*)"is not",}, // M_EQ
- {1,1,(char*)"is not", (char*)"is",}, // M_NE
- {1,1,(char*)"is less than", (char*)"is greater or equal to",}, // M_LT
- {1,1,(char*)"is less or equal to", (char*)"is greater than",}, // M_LE
- {1,1,(char*)"is greater than", (char*)"is less or equal to",}, // M_GT
- {1,1,(char*)"is greater or equal to",(char*)"is less than",}, // M_GE
- {0,1,(char*)" + ",(char*)" + ",}, // M_ADD
- {0,1,(char*)" - ",(char*)" - ",}, // M_SUB
- {0,0,(char*)"",(char*)"",}, // M_MUL
- {0,0,(char*)"",(char*)"",}, // M_DIV
- {0,0,(char*)"",(char*)"",}, // M_MOD
- {0,0,(char*)"",(char*)"",}, // M_POW
- {0,0,(char*)"",(char*)"",}, // M_NOT
- {0,0,(char*)"",(char*)"",}, // M_UNARY
- {0,0,(char*)"",(char*)"",}, // M_OPEN
- {0,0,(char*)"",(char*)"",}, // M_CLOSE
- {0,0,(char*)"",(char*)"",}, // M_NAME
-};
-
-void simple_node::scan(Ast* m,std::ostream& f,bool b)
-{
- if(m == 0) return;
- std::cout << "# scan:" << m->expression() << "\n";
- std::string cp = "";
-
- { AstNode *an = dynamic_cast<AstNode*> (m);
- if(an) { cp = an->nodePath(); cp = m->expression();} }
- { AstVariable *an = dynamic_cast<AstVariable*> (m);
- if(an) { cp = an->nodePath(); cp = m->expression();} }
-
- if(cp != "") {
- const node* n = node::find(cp);
- if(!n) {
- if(external::is_external(cp))
- f << " (unknown)";
- else
- f << cp << " (not found?)";
- return;
- }
-
- f << n->type_name() << ' ' << n->name() << '(' << n->status_name() << ')';
- // node* s = f.source(); if(s && n->is_my_parent(s)) f << cancel;
- } else {
- if(external::is_external(cp))
- f << " (unknown)";
- }
-
- if(m->type() == "not")
- b = !b;
-
- scan(m->left(),f,b);
-
- f << ' ' << (b ? names[kind(m)].pos_ : names[kind(m)].neg_) << ' ';
-
- scan(m->right(),f,b);
-
- if(names[kind(m)].print_)
- f << "\n";
-}
-
-class why_triggers : public trigger_lister {
- std::ostream& f_;
-
-public:
-
- virtual Boolean self() { return False; }
- virtual Boolean kids() { return True; }
- virtual Boolean parents() { return True; }
-
- why_triggers(std::ostream& f) : f_(f) {}
-
- void next_node(node& n, node* p,int type,node*) {
- if(p && p->status() == STATUS_QUEUED)
- p->why(f_);
- }
-};
-
-void simple_node::tell_me_why(std::ostream& f)
-{
- this->why(f);
- // if (0x0 != parent()) parent()->tell_me_why(f);
-}
-
-void simple_node::queued(std::ostream& f)
-{
- // Check parents
- node* p = this;
- p->why(f);
-
- // Check for suspended kids
- suspended(f);
-
- // Other triggers
- why_triggers wp(f);
- triggers(wp);
-}
-
-void simple_node::aborted(std::ostream& f)
-{
- node* k = kids();
- while(k) {
- k->aborted(f);
- k = k->next();
- }
-}
-
-void simple_node::suspended(std::ostream& f)
-{
- if (type() != NODE_FAMILY && type() != NODE_TASK)
- return;
-
- if(status() == STATUS_SUSPENDED)
- f << " # " << type_name() << ' ' << this->name() << " is suspended\n";
-
- node* k = kids();
- while(k) {
- k->suspended(f);
- k = k->next();
- }
-}
-
-void simple_node::perlify(FILE* f)
-{
- if (node::is_json)
- fprintf(f,"\"kids\": [\n");
- else
- fprintf(f,"kids => [\n");
-
- node* k = kids();
- while(k) {
- k->as_perl(f,!k->isSimpleNode());
- fprintf(f,",\n");
- k = k->next();
- }
-
- if (node::is_json)
- fprintf(f,"{} ],\n");
- else
- fprintf(f,"],\n");
-}
-
-Boolean simple_node::isZombie() const
-{
- return ecfFlag(FLAG_ZOMBIE);
-}
-
-Boolean simple_node::isToBeChecked() const
-{
- int s = status();
- return s == STATUS_SUSPENDED || s == STATUS_ACTIVE || s == STATUS_SUBMITTED;
-}
-
-Boolean suite_node::visible () const { return show_it() ; }
-
-Boolean suite_node::show_it() const {
- if (serv().suites().empty())
- return True; // show_all
-
- std::vector<std::string>::const_iterator it;
- for (it = serv().suites().begin(); it != serv().suites().end(); ++it)
- if (*it == name())
- return simple_node::visible();
-
- return False;
-}
-
-Boolean simple_node::isGenVariable(const char *name) {
- for (node *run = kids(); 0 != run; run = run->next()) {
- if (run->type() == NODE_VARIABLE)
- if (run->name() == name)
- return run->isGenVariable(name);
- }
- return False;
-}
-
-void simple_node::genvars(std::vector<Variable>& var)
-{
- for (node *run = kids(); run; run = run->next()) {
- if (run->type() == NODE_VARIABLE) {
- if (run->name() == "") std::cerr << "# empty variable!\n";
- else if (run->isGenVariable(0))
- var.push_back(Variable(run->name(), ((variable_node*) run)->get_var(), false/*dont check names*/));
- }
- }
- return;
-}
-
-void simple_node::variables(std::vector<Variable>& var)
-{
- for (node *run = kids(); 0 != run; run = run->next()) {
- if (run->type() == NODE_VARIABLE){
- if (run->name() == "") std::cerr << "# empty variable!\n";
- else if (!run->isGenVariable(0)) {
- var.push_back(Variable(run->name(), ((variable_node*) run)->get_var(), false/*dont check names*/));
- }
- }
-}
-}
-
-Boolean simple_node::hasMessages() const
-{
- if (ecfFlag(FLAG_MESSAGE)) return True;
- // FIXME // cannot call this below while it is called during node redraw
- if (type() == NODE_SUPER)
- return True;
- // return serv().messages(*this).size() > 0;
- return False; // serv().messages(*this).size() > 0;
-}
-
-// void simple_node::unlink() {
-// if (__node__()) __node__()->unlink();
-// for (node *run = kids(); run; run = run->next()) { run->unlink(); }
-// }
diff --git a/ecflow_4_0_7/view/src/simple_node.h b/ecflow_4_0_7/view/src/simple_node.h
deleted file mode 100644
index b230947..0000000
--- a/ecflow_4_0_7/view/src/simple_node.h
+++ /dev/null
@@ -1,158 +0,0 @@
-#ifndef simple_node_H
-#define simple_node_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #18 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#ifndef node_H
-#include "node.h"
-#endif
-
-class simple_node : public node {
-public:
- simple_node(host&,ecf_node*);
-#ifdef BRIDGE
- simple_node(host&,sms_node*,char);
-#endif
- ~simple_node();
-
- virtual std::string variable(const std::string&, bool substitute=false);
- virtual const char* status_name() const;
-
- virtual void info(std::ostream&);
- virtual void triggers(trigger_lister&);
-
- virtual Boolean hasTriggers() const;
- virtual Boolean hasDate() const;
- virtual Boolean hasTime() const;
-
- virtual Boolean hasTimeHolding() const;
-
- virtual Boolean hasManual() const;
- virtual Boolean isSimpleNode() const { return True; }
- virtual Boolean isGenVariable(const char*);
- virtual void genvars(std::vector<Variable>&);
- virtual void variables(std::vector<Variable>&);
-
- virtual Boolean visible() const;
- virtual Boolean visible_kid() const;
- virtual Boolean show_it() const;
-
- virtual void tell_me_why(std::ostream&);
- virtual void why(std::ostream&);
- virtual void suspended(std::ostream&);
- virtual void aborted(std::ostream&);
- virtual void queued(std::ostream&);
-
- virtual int tryno() const;
- virtual int flags() const;
- virtual boost::posix_time::ptime status_time() const;
-
- virtual Boolean isMigrated() const { return ecfFlag(FLAG_MIGRATED); }
- virtual Boolean isLate() const { return ecfFlag(FLAG_LATE); }
- virtual Boolean isWaiting() const { return ecfFlag(FLAG_WAIT); }
- virtual Boolean hasMessages() const;
-
- virtual Boolean isTimeDependent() const { return hasDate() || hasTime(); }
-
- virtual Boolean isForceAbort() const { return ecfFlag(FLAG_FORCE_ABORT); }
- virtual Boolean isUserEdit() const { return ecfFlag(FLAG_USER_EDIT); }
- virtual Boolean isTaskAbort() const { return ecfFlag(FLAG_TASK_ABORTED); }
- virtual Boolean isEditFailed() const { return ecfFlag(FLAG_EDIT_FAILED); }
- virtual Boolean isCmdFailed() const { return ecfFlag(FLAG_CMD_FAILED); }
- virtual Boolean isScriptMissing() const { return ecfFlag(FLAG_NO_SCRIPT); }
- virtual Boolean isKilled() const { return ecfFlag(FLAG_KILLED); }
- virtual Boolean isByRule() const { return ecfFlag(FLAG_BYRULE); }
- virtual Boolean isQueueLimit() const { return ecfFlag(FLAG_QUEUELIMIT); }
-
- virtual Boolean isRerun() const { return tryno() > 1; }
- virtual Boolean isZombie() const;
- virtual Boolean hasZombieAttr() const;
- virtual Boolean isToBeChecked() const;
- virtual Boolean isDefComplete() const;
-
- virtual bool trigger_kids() const { return true; }
- virtual bool trigger_parent() const { return true; }
-
- virtual Boolean ecfFlag(int) const;
-
- // void unlink();
-
- protected:
-
- virtual void perlify(FILE*);
- int old_status_, old_tryno_, old_flags_;
- private:
-
- simple_node(const simple_node&);
- simple_node& operator=(const simple_node&);
-
- virtual void drawNode(Widget,XRectangle*,bool);
- virtual void sizeNode(Widget,XRectangle*,bool);
- virtual void drawBackground(Widget,XRectangle*,bool);
-
- void scan(Ast*,trigger_lister&,node*);
- void scan(Ast*,std::ostream&,bool);
- void scan(node*,std::ostream&);
-#ifdef BRIDGE
- void scan(sms_tree* m,trigger_lister& f,bool b);
- void scan(sms_tree* m,std::ostream& f,bool b);
- // void scan(sms_tree* m,std::ostream& f,bool b);
-#endif
- void scan_limit(Ast*,std::ostream&);
-
- virtual Pixel color() const;
-};
-
-inline void destroy(simple_node**) {}
-
-class suite_node : public simple_node {
- public:
- suite_node(host& h,ecf_node* n) : simple_node(h,n) {}
-#ifdef BRIDGE
- suite_node(host& h,sms_node* n,char b) : simple_node(h,n,b) {}
-#endif
- virtual Boolean show_it() const;
- virtual Boolean visible() const;
-
- // virtual void info(std::ostream&);
-};
-#define FLAG_ISSET(flag) (1<<(flag))
-#include "late.h"
-
-class family_node : public simple_node {
- virtual bool trigger_kids() const { return false; }
- virtual bool trigger_parent() const { return false; }
-public:
- family_node(host& h,ecf_node* n) : simple_node(h,n) {}
-#ifdef BRIDGE
- family_node(host& h,sms_node* n,char b) : simple_node(h,n,b) {}
-#endif
- void update(int oldstatus,int oldtryno,int oldflags) {
- bool is_late = flags() & FLAG_ISSET(FLAG_LATE);
- bool was_late = old_flags_ & FLAG_ISSET(FLAG_LATE);
- simple_node::update(oldstatus,oldtryno,oldflags);
- if(is_late != was_late) {
- if(is_late)
- serv().late(*this);
- else
- late::hide(*this);
- }
- old_flags_ = flags();
-}
-
-};
-
-#endif
diff --git a/ecflow_4_0_7/view/src/singleton.h b/ecflow_4_0_7/view/src/singleton.h
deleted file mode 100644
index ef3344f..0000000
--- a/ecflow_4_0_7/view/src/singleton.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef singleton_H
-#define singleton_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-template<class T>
-class singleton {
-public:
- static T& instance();
-};
-
-template<class T>
-T& singleton<T>::instance()
-{
- static T p;
- return p;
-}
-
-#endif
diff --git a/ecflow_4_0_7/view/src/str.cc b/ecflow_4_0_7/view/src/str.cc
deleted file mode 100644
index 2581635..0000000
--- a/ecflow_4_0_7/view/src/str.cc
+++ /dev/null
@@ -1,99 +0,0 @@
-#ifndef str_H
-#include "str.h"
-#endif
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <string.h>
-#include <strings.h>
-#include <stdio.h>
-
-str_imp::str_imp(const char* p):
- str_ (new char[strlen(p) + 1])
-{
- //if(!str_) { printf("Out of memory"); exit(1); }
- strcpy(str_,p);
-}
-
-str_imp::~str_imp()
-{
- delete[] str_;
-}
-
-
-str::str()
-{
- static str empty("");
- imp_ = empty.imp_;
- imp_->attach();
-}
-
-str::~str()
-{
- imp_->detach();
-}
-
-str::str(const char* n):
- imp_(new str_imp(n))
-{
- imp_->attach();
-}
-
-str::str(const str& other):
- imp_(other.imp_)
-{
- imp_->attach();
-}
-
-str::str(const std::string& other):
- imp_(new str_imp(other.c_str()))
-{
- imp_->attach();
-}
-
-str& str::operator=(const str& other)
-{
- other.imp_->attach();
- imp_->detach();
- imp_ = other.imp_;
- return *this;
-}
-
-
-bool str::operator==(const str& other) const
-{
- return strcmp(c_str(),other.c_str()) == 0;
-}
-
-bool str::operator!=(const str& other) const
-{
- return strcmp(c_str(),other.c_str()) != 0;
-}
-
-str operator+(const str& a,const str& b)
-{
- char* p = new char[strlen(a.c_str()) + strlen(b.c_str()) + 1 ];
- strcpy(p,a.c_str());
- strcat(p,b.c_str());
- str s(p);
- delete[] p;
- return s;
-}
-
-str& str::operator+=(const str& s)
-{
- *this = *this + s;
- return *this;
-}
diff --git a/ecflow_4_0_7/view/src/str.h b/ecflow_4_0_7/view/src/str.h
deleted file mode 100644
index d6655b0..0000000
--- a/ecflow_4_0_7/view/src/str.h
+++ /dev/null
@@ -1,59 +0,0 @@
-#ifndef str_H
-#define str_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include <string>
-#ifdef NO_BOOL
-#include "bool.h"
-#endif
-
-#include "counted.h"
-
-struct str_imp : public counted {
- char* str_;
- str_imp(const char*);
- ~str_imp();
-};
-
-class str {
-public:
- str();
- str(const char*);
- str(const str&);
- str(const std::string&);
-
- ~str(); // Change to virtual if base class
-
- str& operator=(const str&);
-
- bool operator==(const str&) const;
- bool operator!=(const str&) const;
-
- str& operator+=(const str&);
-
- const char* c_str() const { return imp_->str_; }
-
-private:
-
- str_imp* imp_;
-};
-
-str operator+(const str&,const str&);
-str operator+(const char*,const str&);
-str operator+(const str&,const char*);
-
-#endif
diff --git a/ecflow_4_0_7/view/src/substitute.cc b/ecflow_4_0_7/view/src/substitute.cc
deleted file mode 100644
index 52f0609..0000000
--- a/ecflow_4_0_7/view/src/substitute.cc
+++ /dev/null
@@ -1,139 +0,0 @@
-
-#ifndef substitute_H
-#include "substitute.h"
-#endif
-
-#ifndef node_H
-#include "node.h"
-#endif
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <strings.h>
-
-#include <Xm/PushB.h>
-
-extern "C" {
-#include "xec.h"
-}
-
-static char* debug = getenv("DEBUG");
-substitute::substitute(const std::string& name):
- name_(name)
-{
-}
-
-substitute::~substitute()
-{
-}
-
-const char* substitute::scan(const char* cmd,node* n)
-{
- static char buf[1024];
- int i = 0, j = 0, k= 0, cont = 1;
- char word[1024], edit[1024];
- bool var = false, col = false;
- substitute* s;
- word[0] = 0; edit[0] = 0;
-
- if (debug) std::cout << "# substituted1:" << cmd << "\n";
- std::string replace (cmd);
- if (replace.find("%") != std::string::npos) {
- if (n->__node__()) {
- if (n->__node__()->type() == NODE_SUPER) {
- ecf_concrete_node<Defs> *ecfn = dynamic_cast<ecf_concrete_node<Defs>*>(n->__node__());
- if (0x0 != ecfn) // ok with a node, NOK with attribute
- if (const_cast<Defs*>(ecfn->get())) {
- const_cast<Defs*>(ecfn->get())-> variableSubsitution(replace);
- strcat(buf, replace.c_str());
- return buf;
- }
- } else if (n->__node__()-> get_node()) {
- n->__node__()-> get_node()-> variableSubsitution(replace);
- strcat(buf, replace.c_str());
- if (debug) std::cout << "# substituted2:" << replace << "\n";
- if (debug) std::cout << "# substituted2:" << buf << "\n";
- return buf;
- }
- }
- return cmd;
- }
-
- while(*cmd && cont) {
- switch(*cmd) {
- case '<':
- var = true;
- j = 0;
- word[j++] = '<';
- break;
-
- case '>':
- var = false;
- word[j++] = '>';
- word[j] = 0;
-
- s = first();
- while(s) {
- if(s->name_ == word) {
- strcpy(word,s->eval(n).c_str());
- break;
- }
- s = s->next();
- }
-
- buf[i] = 0;
- strcat(buf,word);
- i += strlen(word);
- if (debug) std::cout << "# substituted:" << buf << "-" << word <<"-\n";
- j = 0;
- break;
-
- default:
- if (col) edit[k++] = *cmd;
- else if(var)
- word[j++] = *cmd;
- else
- buf[i++] = *cmd;
- break;
- }
-
- cmd++;
- }
-
- if(k) {
- buf[i] = 0;
- strcat(buf,edit);
- i += strlen(edit);
- } else if(j) {
- buf[i] = 0;
- strcat(buf,word);
- i += strlen(word);
- }
-
- if (debug) std::cout << "# substituted:" << buf << "-" << word << "-" << edit <<"-\n";
- buf[i] = 0;
- return buf;
-}
-
-void substitute::fill(Widget w)
-{
- substitute* s = first();
- while(s) {
- XtManageChild(XmCreatePushButton(w,(char*)s->name_.c_str(),0,0));
- s = s->next();
- }
-}
-
-IMP(substitute)
diff --git a/ecflow_4_0_7/view/src/substitute.h b/ecflow_4_0_7/view/src/substitute.h
deleted file mode 100644
index fd4d470..0000000
--- a/ecflow_4_0_7/view/src/substitute.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef substitute_H
-#define substitute_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#ifndef extent_H
-#include "extent.h"
-#endif
-
-#include <Xm/Xm.h>
-
-#ifndef node_H
-#include "node.h"
-#endif
-
-class substitute : public extent<substitute> {
-public:
- substitute(const std::string&);
-
- ~substitute(); // Change to virtual if base class
- virtual const std::string eval(node*) = 0;
-
- static const char* scan(const char*, node*);
- static void fill(Widget);
-
-private:
- substitute(const substitute&);
- substitute& operator=(const substitute&);
-
- const std::string name_;
-};
-
-inline void destroy(substitute**) {}
-
-class proc_substitute : public substitute {
- typedef const std::string& (node::*procc)() const; procc procc_;
- const std::string eval(node* n) { return (n->*procc_)(); }
-public:
- proc_substitute(const std::string& name,procc p): substitute(name), procc_(p)
- {}
-};
-#endif
diff --git a/ecflow_4_0_7/view/src/suites_panel.cc b/ecflow_4_0_7/view/src/suites_panel.cc
deleted file mode 100644
index a557c1e..0000000
--- a/ecflow_4_0_7/view/src/suites_panel.cc
+++ /dev/null
@@ -1,146 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #9 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "suites_panel.h"
-#include "node.h"
-#include "host.h"
-#include "ecflowview.h"
-#include <Xm/Label.h>
-#include <Xm/Text.h>
-#include <Xm/List.h>
-extern "C" {
-#include "xec.h"
-}
-
-suites_panel::suites_panel(panel_window& w):
- panel(w)
- , done (false)
-{
-}
-
-suites_panel::~suites_panel()
-{
-}
-
-void suites_panel::create (Widget parent, char *widget_name )
-{
- suites_form_c::create(parent,widget_name);
-}
-
-void suites_panel::clear()
-{
- if (done) return;
- XmListDeleteAllItems(list_);
-}
-
-struct suite_lister1 {
- Widget list_;
- unsigned int pos_;
- std::vector<std::string> suites_;
- void next(suite_lister1&);
- std::string name()
- { return (pos_ < suites_.size()) ? suites_[pos_] : ""; }
- void run()
- { for (unsigned int i=0; i<suites_.size(); ++i) next(*this); }
-
-public:
- suite_lister1(Widget list, std::vector<std::string> suites)
- : list_(list), pos_(0), suites_(suites) {
- std::sort(suites_.begin(), suites_.end());
- }
-};
-
-void suite_lister1::next(suite_lister1& l)
-{
- if (pos_ < suites_.size() && suites_[pos_] != "*") {
- xec_AddListItem(list_,(char*)name().c_str());
- }
- ++pos_;
-}
-
-struct suite_lister2 {
- Widget list_;
- unsigned int pos_;
- std::vector<std::string> suites_;
- void next(suite_lister2& l);
- std::string name()
- { return (pos_ < suites_.size()) ? suites_[pos_] : ""; }
- void run()
- { for (unsigned int i=0; i<suites_.size(); ++i) next(*this); };
-
-public:
- suite_lister2(Widget list, std::vector<std::string> suites)
- : list_(list), pos_(0), suites_(suites) {}
-};
-
-void suite_lister2::next(suite_lister2&)
-{
- if (pos_ < suites_.size() && suites_[pos_] != "*") {
- XmString s = XmStringCreateSimple((char*)name().c_str());
- XmListSelectItem(list_,s,False);
- XmStringFree(s);
- }
- ++pos_;
-}
-
-void suites_panel::show(node& n)
-{
- if (done) return; done = true; clear();
- // XmListDeleteAllItems(list_);
- { std::vector<std::string> sv1; n.serv().suites(SUITES_LIST,sv1);
- suite_lister1 sl1(list_, sv1); sl1.run(); }
- { std::vector<std::string> sv2; n.serv().suites(SUITES_MINE,sv2);
- suite_lister2 sl2(list_, sv2); sl2.run(); }
-}
-
-Boolean suites_panel::enabled(node& n)
-{
- return n.type() == NODE_SUPER;
-}
-
-void suites_panel::tellCB( Widget, XtPointer )
-{
- XmString *items;
- int count;
- std::vector<std::string> l;
-
- XtVaGetValues(list_,
- XmNselectedItems, &items,
- XmNselectedItemCount,&count,
- NULL);
-
- for(int i = 0; i < count ; ++i) {
- char* p = xec_GetString(items[i]);
- l.push_back(std::string (p));
- XtFree(p);
- }
- if(get_node())
- get_node()->serv().suites(SUITES_REG, l);
- else
- clear();
- submit();
-}
-
-void suites_panel::offCB( Widget, XtPointer )
-{
- XmListDeselectAllItems(list_);
-}
-
-void suites_panel::onCB( Widget, XtPointer )
-{
- xec_ListSelectAll(list_);
-}
-
-// static panel_maker<suites_panel> maker(PANEL_SUITES);
diff --git a/ecflow_4_0_7/view/src/suites_panel.h b/ecflow_4_0_7/view/src/suites_panel.h
deleted file mode 100644
index 241de11..0000000
--- a/ecflow_4_0_7/view/src/suites_panel.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef suites_panel_H
-#define suites_panel_H
-
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "uisuites.h"
-
-#ifndef panel_H
-#include "panel.h"
-#endif
-
-class suites_panel : public panel, public suites_form_c {
-public:
-
- suites_panel(panel_window&);
-
- ~suites_panel(); // Change to virtual if base class
-
- virtual const char* name() const { return "Suites"; }
- virtual void show(node&);
- virtual void clear();
- virtual Boolean enabled(node&);
- virtual Widget widget() { return suites_form_c::xd_rootwidget(); }
- virtual Widget tools() { return tools_; }
-
- virtual void create (Widget parent, char *widget_name = NULL);
-
-private:
-
- bool done;
-
- suites_panel(const suites_panel&);
- suites_panel& operator=(const suites_panel&);
-
- virtual void tellCB( Widget, XtPointer );
- virtual void offCB( Widget, XtPointer );
- virtual void onCB( Widget, XtPointer );
-};
-
-inline void destroy(suites_panel**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/super_node.cc b/ecflow_4_0_7/view/src/super_node.cc
deleted file mode 100644
index e554672..0000000
--- a/ecflow_4_0_7/view/src/super_node.cc
+++ /dev/null
@@ -1,96 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "simple_node.h"
-#include "host.h"
-#include "timeout.h"
-
-#include "super_node.h"
-
-void super_node::why(std::ostream &w)
-{
- if(isLocked())
- w << "The server " << this << " is locked\n";
- if (owner_)
- owner_->why(w);
-}
-
-void super_node::run()
-{
- decay_++;
- /* printf("node run .. %s %d\n",node_name(),decay_); */
- redraw();
-}
-
-void super_node::active(bool b)
-{
- /* printf("node activate %s %d\n",node_name(),int(b)); */
- if(b != active_) {
- active_ = b;
- redraw();
- }
-}
-
-void super_node::up_to_date()
-{
- frequency(60); // This will reset the timeout
- if(decay_) {
- decay_ = 0;
- redraw();
- }
-}
-
-void super_node::drawBackground(Widget w,XRectangle* r,bool)
-{
- if(true /*active_*/ ) {
- XRectangle a = *r;
-
- // All grey after 1 hours
- double x = a.width * ( decay_ / 60.0 );
-
- if(x > a.width) x = a.width;
-
- a.width -= x;
-
- /* printf("%d %d\n",r->width,a.width); */
- /* a.width -= x + 0.5; a.x += x/2.0 + 0.5; */
- /* a.height -= y + 0.5; a.y += y/2.0 + 0.5; */
-
-#if 0
- printf("%d x y = %g %g %d.%d.%d.%d %d.%d.%d.%d\n", decay_, x , y ,
- r->x,r->y,r->width,r->height,
- a.x,a.y,a.width,a.height
- );
-#endif
-
- GC gc = colorGC(STATUS_UNKNOWN);
- XFillRectangles(XtDisplay(w),XtWindow(w),gc,r,1);
-
- gc = colorGC(status());
- XFillRectangles(XtDisplay(w),XtWindow(w),gc,&a,1);
- }
- else {
- GC gc = colorGC(STATUS_UNKNOWN);
- XFillRectangles(XtDisplay(w),XtWindow(w),gc,r,1);
- }
-}
-
-void super_node::info(std::ostream& f)
-{
- serv().stats(f);
- simple_node::info(f);
-}
-
-// static node_maker<super_node> super_maker(NODE_SUPER);
diff --git a/ecflow_4_0_7/view/src/super_node.h b/ecflow_4_0_7/view/src/super_node.h
deleted file mode 100644
index 04d7e1a..0000000
--- a/ecflow_4_0_7/view/src/super_node.h
+++ /dev/null
@@ -1,72 +0,0 @@
-#ifndef super_node_H
-#define super_node_H
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #12 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-
-#ifndef simple_node_H
-#include "simple_node.h"
-#endif
-#ifndef host_H
-#include "host.h"
-#endif
-#ifndef timeout_H
-#include "timeout.h"
-#endif
-class super_node : public simple_node, public timeout {
- virtual void why(std::ostream&);
- virtual Boolean visible() const { return True; }
- virtual Boolean show_it() const { return True; }
- virtual const std::string& name() const { return serv().name_ref(); }
- virtual const std::string& node_name() const { return serv().name_ref(); }
- virtual const char* type_name() const { return "server"; }
- virtual void run();
- virtual void up_to_date();
- virtual void active(bool);
- virtual void drawBackground(Widget w,XRectangle* r,bool);
- virtual void info(std::ostream&);
-
- virtual bool trigger_kids() const { return false; }
- virtual bool trigger_parent() const { return false; }
- virtual bool timeTable() { return true; }
-
- Boolean isLocked() const { return ecfFlag(FLAG_LOCKED); }
-
- virtual Boolean hasManual() const { return False; }
- virtual Boolean hasTriggers() const { return False; }
- virtual Boolean hasInfo() const { return True; }
-
- bool active_;
- int decay_;
-
-public:
- super_node(host& h,ecf_node* n)
- : simple_node(h,n)
- , timeout(60)
- , active_(true)
- , decay_(0)
- { folded_ = False; enable(); }
-
-#ifdef BRIDGE
- super_node(host& h,sms_node* n, char b)
- : simple_node(h,n,b)
- , timeout(60)
- , active_(true)
- , decay_(0)
- { folded_ = False; enable(); }
-#endif
-};
-
-#endif
diff --git a/ecflow_4_0_7/view/src/task_node.cc b/ecflow_4_0_7/view/src/task_node.cc
deleted file mode 100644
index f8a23de..0000000
--- a/ecflow_4_0_7/view/src/task_node.cc
+++ /dev/null
@@ -1,281 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #15 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "task_node.h"
-#include "text_lister.h"
-#include "late.h"
-#include "zombie.h"
-#include "to_check.h"
-#include "host.h"
-#include "url.h"
-#include "re.h"
-#include "ecf_node.h"
-
-char *ecf_flag_name[] = { (char*)"has been forced to aborted",
- (char*)"user edit failed",
- (char*)"the job failed",
- (char*)"editing failed (.job file can not be created)",
- (char*)"job could not be submitted (ECF_CMD failed)",
- (char*)"ECF could not find the script",
- (char*)"killed by user",
- (char*)"", // has been migrated",
- (char*)"is late",
- (char*)"has user messages",
- (char*)"complete by rule",
- (char*)"queue limit reached",
- (char*)"running task is waiting for trigger",
- (char*)"node is locked by a user",
- (char*)"zombie is trying to communicate",
- (char*)"task is submitted or active (ecf) but not matching job visible",
- NULL };
-
-#ifdef BRIDGE
-task_node::task_node(host& h,sms_node* n, char b):
- simple_node(h,n, b)
-{}
-#endif
-
-task_node::task_node(host& h,ecf_node* n):
- simple_node(h,n)
-{
- if (kids_ == 0x0) {
- folded_ = False;
- } else {
- folded_ = True;
- }
-}
-
-
-task_node::~task_node()
-{
-}
-
-void task_node::info(std::ostream& f) {
- simple_node::info(f);
- if (0 == owner_) return;
- if (status() == STATUS_ABORTED && owner_->get_node()) {
- f << owner_->get_node()->abortedReason() << "\n";
- }
- f << owner_->toString() << "\n";
-}
-
-void task_node::update(int oldstatus,int oldtryno,int oldflags)
-{
- simple_node::update(oldstatus,oldtryno,oldflags);
- check(oldstatus,oldtryno,oldflags);
-}
-
-void task_node::adopt(node* n)
-{
- simple_node::adopt(n);
- check(0,0,0);
-}
-
-void task_node::create()
-{
- simple_node::create();
- check(0,0,0);
-}
-
-#ifdef FLAG_ISSET
-#undef FLAG_ISSET
-#endif
-#define FLAG_ISSET(flag) (1<<(flag))
-inline bool is_late(int f) { return (f & FLAG_ISSET(FLAG_LATE)); }
-inline bool is_zombie(int f) { return (f & FLAG_ISSET(FLAG_ZOMBIE)); }
-inline bool is_to_check(int f) { return (f& FLAG_ISSET(FLAG_TO_CHECK));}
-
-void task_node::check(int,int,int)
-{
- int new_status = status();
- int new_flags = flags();
- int new_try_no = tryno();
-
- if(new_status != old_status_ && new_status == STATUS_ABORTED)
- serv().aborted(*this);
-
- if(new_try_no > 1 && new_try_no != old_tryno_ && (
- new_status == STATUS_SUBMITTED ||
- new_status == STATUS_ACTIVE))
- serv().restarted(*this);
-
- bool new_is_late = is_late(new_flags);
- if(new_is_late != is_late(old_flags_)) {
- if(new_is_late)
- serv().late(*this);
- else
- late::hide(*this);
- }
-
- bool new_is_zombie = is_zombie(new_flags);
- if(new_is_zombie != is_zombie(old_flags_)) {
- if(new_is_zombie)
- serv().zombie(*this);
- else
- zombie::hide(*this);
- }
-
-//
-// if(is_to_check(new_flags) != is_to_check(old_flags_)) {
-// if(is_to_check(new_flags))
-// serv().to_check(*this);
-// else
-// to_check::hide(*this);
-// }
-
- old_flags_ = new_flags;
- old_status_ = new_status;
- old_tryno_ = new_try_no;
-}
-
-void task_node::aborted(std::ostream& f)
-{
- if(status() == STATUS_ABORTED)
- {
- f << "task " << this << " is aborted";
- long flg = flags();
- int i = 0;
- while(flg>0)
- {
- if(flg%2)
- {
- f << " (" << ::ecf_flag_name[i] << ")";
- }
- flg /= 2;
- i++;
- }
- f << "\n";
- }
- simple_node::aborted(f);
-}
-
-const char* task_node::html_page(url& u)
-{
- return "node.html";
-}
-
-
-void task_node::html_name(FILE* f,url& u)
-{
- node::html_name(f,u);
-}
-
-
-class cpp_translator: public url_translator {
- re re_;
- node* n_;
-public:
- cpp_translator(node* n);
- ~cpp_translator();
-
- virtual void save(FILE*,const char *line);
-};
-
-cpp_translator::cpp_translator(node* n):
- re_("%([^%]+)$0%"),
- n_(n)
-{
-}
-
-cpp_translator::~cpp_translator()
-{
-}
-
-void cpp_translator::save(FILE* f,const char *line)
-{
- if(strncmp(line,"%manual",7) == 0)
- {
- fprintf(f,"<b>");
- url_translator::save(f,line);
- fprintf(f,"</b>");
- fprintf(f,"<i>");
- return;
- }
-
- if(strncmp(line,"%end",4) == 0)
- {
- fprintf(f,"</i>");
- fprintf(f,"<b>");
- url_translator::save(f,line);
- fprintf(f,"</b>");
- return;
- }
-
- if(strncmp(line,"%include",8) == 0)
- {
- fprintf(f,"<b>");
- url_translator::save(f,line);
- fprintf(f,"</b>");
- return;
- }
-
-
- char val[1024];
- char buf[1024];
-
- strcpy(buf,line);
- char *p = buf;
- char *q;
-
- while((q = re_.match(p,val)))
- {
- char *loc = re_.loc();
- char w = *loc;
- *loc = 0;
- url_translator::save(f,p);
- *loc = w;
-
- node *n = n_->variableOwner(val);
- if(n == 0) n = n_;
-
- // TODO fprintf(f,"<b><a href=\"%s:%s\">%%",n->html_url(),val);
- url_translator::save(f,val);
- fprintf(f,"%%</a></b>");
- p = q;
- }
-
- url_translator::save(f,p);
-}
-
-void task_node::html_script(FILE* f,url& u)
-{
- cpp_translator cpp(this);
- tmp_file tmp = serv().script(*this);
- u.add(tmp,cpp);
-}
-
-void task_node::html_output(FILE* f,url& u)
-{
- url_translator t;
- tmp_file tmp = serv().output(*this);
- u.add(tmp,t);
-}
-
-void task_node::html_job(FILE* f,url& u)
-{
- url_translator t;
- tmp_file tmp = serv().job(*this);
- u.add(tmp,t);
-}
-
-void task_node::html_jobstatus(FILE* f,url& u)
-{
- url_translator t;
- std::string job = variable("ECF_JOB");
- std::string stat = job + ".stat";
- serv().jobstatus(*this, "");
- tmp_file tmp (stat);
- u.add(tmp,t);
-}
diff --git a/ecflow_4_0_7/view/src/task_node.h b/ecflow_4_0_7/view/src/task_node.h
deleted file mode 100644
index e1f4ee8..0000000
--- a/ecflow_4_0_7/view/src/task_node.h
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef task_node_H
-#define task_node_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #8 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "simple_node.h"
-
-class task_node : public simple_node {
-public:
- task_node(host& h,ecf_node* n);
-#ifdef BRIDGE
- task_node(host& h,sms_node* n, char b);
-#endif
- ~task_node(); // Change to virtual if base class
-
-private:
- task_node(const task_node&);
- task_node& operator=(const task_node&);
-
- virtual void adopt(node*);
- virtual void create();
- virtual void update(int,int,int);
- virtual void check(int,int,int);
- virtual void info(std::ostream&);
-
- virtual void aborted(std::ostream&);
- virtual void html_output(FILE*,url&);
- virtual void html_script(FILE*,url&);
- virtual void html_job(FILE*,url&);
- virtual void html_jobstatus(FILE*,url&);
- virtual void html_name(FILE*,url&);
- virtual const char* html_page(url&);
-};
-
-class alias_node : public task_node {
- void why(std::ostream&);
-public:
- alias_node(host& h,ecf_node* n);
-#ifdef BRIDGE
- alias_node(host& h,sms_node* n, char b);
-#endif
- ~alias_node();
-};
-
-#endif
diff --git a/ecflow_4_0_7/view/src/text_layout.cc b/ecflow_4_0_7/view/src/text_layout.cc
deleted file mode 100644
index dfc7139..0000000
--- a/ecflow_4_0_7/view/src/text_layout.cc
+++ /dev/null
@@ -1,123 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "text_layout.h"
-#include "node.h"
-#include "trigger_panel.h"
-#include "Hyper.h"
-#include "tmp_file.h"
-#include <stdio.h>
-#include "error.h"
-#include "trigger_lister.h"
-
-text_layout::text_layout(trigger_panel& t,Widget w):
- layout(t,w)
-{
-}
-
-text_layout::~text_layout()
-{
-}
-
-void text_layout::clear()
-{
- owner().forget_all();
- HyperSetText(widget_,"");
-}
-
-struct info_lister : public trigger_lister {
- panel& p_;
- FILE* f_;
- char* t_;
- Boolean e_;
-public:
- info_lister(panel& p,FILE* f,char *t,Boolean e) : p_(p),f_(f), t_(t), e_(e) {}
- void next_node(node& n, node*,int,node*);
- Boolean parents() { return e_; }
- Boolean kids() { return e_; }
-};
-
-void info_lister::next_node(node& n, node* p,int mode,node*)
-{
- // Title
- if(t_) {
- int n = fprintf(f_,"\n%s:\n",t_) - 2;
- while(n--) fputc('-',f_);
- fputc('\n',f_);
- t_ = 0;
- }
-
- p_.observe(&n);
- fprintf(f_,"%s {%s}",n.type_name(), n.full_name().c_str());
- if(p) {
- fprintf(f_," through ");
- p_.observe(p);
-
- switch(mode)
- {
- case trigger_lister::parent: fprintf(f_,"parent "); break;
- case trigger_lister::child: fprintf(f_,"child "); break;
- }
-
- fprintf(f_,"%s {%s}",p->type_name(),p->full_name().c_str());
- }
- fputc('\n',f_);
-}
-
-
-void text_layout::show(node& n)
-{
- owner().forget_all();
-
- tmp_file tmp(tmpnam(0));
-
- FILE *f = fopen(tmp.c_str(),"w");
-
- if(!f)
- {
- gui::syserr(tmp.c_str());
- return;
- }
-
- info_lister i1(owner(),f,"Nodes triggering this node",owner().extended());
- if(owner().triggers())
- n.triggers(i1);
-
- info_lister i2(owner(),f,"Nodes triggered by this node",owner().extended());
- if(owner().triggered())
- n.triggered(i2);
-
- fclose(f);
-
- HyperLoadFile(widget_,(char*)tmp.c_str());
-}
-
-void text_layout::adoption(observable*,observable*)
-{
-}
-
-void text_layout::gone(observable*)
-{
-}
-
-void text_layout::notification(observable*)
-{
-}
-
-void text_layout::reach(node* n1,node* n2)
-{
- clear();
- HyperSetText(widget_,"This functionality is only available in graphic mode.");
-}
diff --git a/ecflow_4_0_7/view/src/text_layout.h b/ecflow_4_0_7/view/src/text_layout.h
deleted file mode 100644
index 6704fd7..0000000
--- a/ecflow_4_0_7/view/src/text_layout.h
+++ /dev/null
@@ -1,143 +0,0 @@
-#ifndef text_layout_H
-#define text_layout_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-// Headers
-// #ifndef machine_H
-// #include <machine.h>
-// #endif
-
-// Forward declarations
-
-// class ostream;
-// typedef class _Pvts os_typespec; // Remove if not persistant
-
-
-
-#ifndef layout_H
-#include "layout.h"
-#endif
-
-#ifndef observer_H
-#include "observer.h"
-#endif
-
-
-//
-
-class text_layout : public layout, public observer {
-public:
-
-// -- Exceptions
- // None
-
-// -- Contructors
-
- text_layout(trigger_panel&,Widget);
-
-// -- Destructor
-
- ~text_layout(); // Change to virtual if base class
-
-// -- Convertors
- // None
-
-// -- Operators
- // None
-
-// -- Methods
- // None
-
-
-// -- Overridden methods
-
- virtual void show(node&);
- virtual void clear();
- virtual void reach(node*,node*);
-
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
- // Uncomment for persistent, remove otherwise
- // static os_typespec* get_os_typespec();
-
-protected:
-
-// -- Members
- // None
-
-// -- Methods
-
- // void print(ostream&) const; // Change to virtual if base class
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-private:
-
-// No copy allowed
-
- text_layout(const text_layout&);
- text_layout& operator=(const text_layout&);
-
-// -- Members
-
-
-// -- Methods
-
-
- void notification(observable*);
- void adoption(observable*,observable*);
- void gone(observable*);
-
-// -- Overridden methods
-
- // From triigers_menu_c
-
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-// -- Friends
-
- //friend ostream& operator<<(ostream& s,const text_layout& p)
- // { p.print(s); return s; }
-
-};
-
-inline void destroy(text_layout**) {}
-
-// If persistent, uncomment, otherwise remove
-//#ifdef _ODI_OSSG_
-//OS_MARK_SCHEMA_TYPE(text_layout);
-//#endif
-
-
-#endif
diff --git a/ecflow_4_0_7/view/src/text_lister.h b/ecflow_4_0_7/view/src/text_lister.h
deleted file mode 100644
index d3c876f..0000000
--- a/ecflow_4_0_7/view/src/text_lister.h
+++ /dev/null
@@ -1,79 +0,0 @@
-#ifndef text_lister_H
-#define text_lister_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #9 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include <stdio.h>
-
-class node;
-
-class text_lister {
-public:
-
- text_lister() {}
-
- virtual node* source() const = 0;
- virtual void push(node*) = 0;
- // virtual void pusher(node*) = 0;
- virtual void push(const char*,...) = 0;
- virtual void push(const std::string&) = 0;
- virtual void endline() = 0;
- virtual void cancel() = 0;
-
- virtual FILE* file() { return 0; }
-
-private:
-
- text_lister(const text_lister&);
- text_lister& operator=(const text_lister&);
-};
-
-inline
-text_lister& operator<<(text_lister& s,int n)
-{ s.push("%d",n); return s; }
-
-inline
-text_lister& operator<<(text_lister& s,char n)
-{ s.push("%c",n); return s; }
-
-inline
-text_lister& operator<<(text_lister& s,double n)
-{ s.push("%g",n); return s; }
-
-inline
-text_lister& operator<<(text_lister& s,const char* n)
-{ s.push("%s",n); return s; }
-inline
-text_lister& operator<<(text_lister& s,const std::string n)
-{ s.push("%s",n.c_str()); return s; }
-
-inline
-text_lister& operator<<(text_lister& s,node* n)
-{ s.push(n); return s; }
-
-inline
-text_lister& operator<<(text_lister& s,node& n)
-{ s.push(&n); return s; }
-
-inline
-text_lister& operator<<(text_lister& s, void (*proc)(text_lister&))
-{ proc(s); return s; }
-
-inline void cancel(text_lister& s) { s.cancel(); }
-inline void endl(text_lister& s) { s.endline(); }
-
-
-#endif
diff --git a/ecflow_4_0_7/view/src/text_window.cc b/ecflow_4_0_7/view/src/text_window.cc
deleted file mode 100644
index 24fe02e..0000000
--- a/ecflow_4_0_7/view/src/text_window.cc
+++ /dev/null
@@ -1,194 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "text_window.h"
-#include <string>
-#include "viewer.h"
-#include "fsb.h"
-#include "ask.h"
-#include "globals.h"
-#include <Xm/Text.h>
-extern "C" {
-#include "xec.h"
-}
-
-text_window::text_window(bool map_it):
- file_(0,false),
- text_map_(0),
- map_it_(map_it)
-{
-#if 1
- map_it_ = 0;
-#endif
-}
-
-
-text_window::~text_window()
-{
- xec_UnmapText(text_map_);
- text_map_ = 0;
-}
-
-void text_window::clear()
-{
- find::hide();
- xec_UnmapText(text_map_);
- text_map_ = 0;
- XmTextSetString(text(),"");
- file_ = tmp_file(0,false);
-}
-
-
-void text_window::load(const tmp_file& x)
-{
- file_ = x;
- xec_UnmapText(text_map_); text_map_ = 0;
- const int MAXLEN = 512;
- char cmsg[MAXLEN];
- snprintf(cmsg, MAXLEN, "Could not load file %s", file_.c_str());
-
- if(file_.c_str())
- {
- int zeros = 0;
- if(map_it_) {
- text_map_ = xec_MapText(text(),file_.c_str(),&zeros);
- if(text_map_ == 0)
- XmTextSetString(text(),cmsg);
- if(zeros) {
- find::make(text());
- find::message("This file contains %d null character%s.\n"
- "The find will not work properly.",
- zeros,
- zeros>1?"s":""
- );
- }
- else {
- find::no_message();
- }
- }
- else {
- int err = xec_LoadText(text(),file_.c_str(),False);
- if(err)
- XmTextSetString(text(),cmsg);
- }
- }
- else
- XmTextSetString(text(),cmsg);
-}
-
-class text_viewer : public viewer {
- tmp_file tmp_;
-public:
- text_viewer(const tmp_file& t);
-};
-
-text_viewer::text_viewer(const tmp_file& t)
- : tmp_(t)
-{
- if (!tmp_.c_str()) return;
- char buf[1024];
- const char* xpager = getenv("XPAGER");
- if (xpager)
- sprintf(buf,"${XPAGER:=xterm -e more} %s",tmp_.c_str());
- else
- sprintf(buf,"xterm -e ${PAGER:=more} %s",tmp_.c_str());
- FILE *f = popen(buf,"r");
- if(!f) {
- std::cerr << "# error: " << buf << "\n";
- return;
- }
- start(f);
-}
-
-void text_window::open_viewer()
-{
- new text_viewer(file_);
-}
-
-
-void text_window::search(const char* p,bool case_sens,bool regex,
- bool back,bool wrap)
-{
-
- bool found = xec_TextSearch(text(),(char*)p,!case_sens,regex,back,
- false,wrap);
-
- if(!found)
- message("Text not found");
- else
- no_message();
-}
-
-
-void text_window::open_search()
-{
- find::raise(text());
-}
-
-
-//-------------------------------------------------------
-
-class text_saver : public viewer {
- tmp_file tmp_;
-public:
- text_saver(const tmp_file& t);
-};
-
-text_saver::text_saver(const tmp_file& t):
- tmp_(t)
-{
- const char* p = fsb::ask("Save as:");
- if(p)
- {
- char buf[2048];
- sprintf(buf,"cp %s %s 2>&1",tmp_.c_str(),p);
- show(buf);
- }
- else delete this;
-}
-
-void text_window::save()
-{
- new text_saver(file_);
-}
-
-//-------------------------------------------------------
-
-class text_printer : public viewer {
- tmp_file tmp_;
-public:
- text_printer(const tmp_file& t);
-};
-
-text_printer::text_printer(const tmp_file& t):
- tmp_(t)
-{
- static option<str> cmd(globals::instance(),"print_command","lpr");
-
- str c = cmd;
-
- if(ask::show(c,"Print command:"))
- {
- cmd = c;
- char buf[2048];
- sprintf(buf,"%s %s 2>&1",c.c_str(),tmp_.c_str());
- show(buf);
- }
-}
-
-void text_window::print()
-{
- new text_printer(file_);
-}
diff --git a/ecflow_4_0_7/view/src/text_window.h b/ecflow_4_0_7/view/src/text_window.h
deleted file mode 100644
index 254b372..0000000
--- a/ecflow_4_0_7/view/src/text_window.h
+++ /dev/null
@@ -1,65 +0,0 @@
-#ifndef text_window_H
-#define text_window_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#ifndef panel_H
-#include "panel.h"
-#endif
-
-#ifndef find_H
-#include "find.h"
-#endif
-
-#ifndef tmp_file_H
-#include "tmp_file.h"
-#endif
-
-
-class text_window : public find {
-public:
-
- text_window(bool);
-
- ~text_window(); // Change to virtual if base class
-
- void load(const tmp_file&);
- void clear();
-
- void print();
- void save();
-
- virtual Widget text() = 0;
-
-protected:
-
- void open_search();
- void open_viewer();
-
- virtual void search(const char*,bool,bool,bool,bool);
-
-private:
-
- text_window(const text_window&);
- text_window& operator=(const text_window&);
-
- tmp_file file_;
- void* text_map_;
- bool map_it_;
-
-};
-
-#endif
diff --git a/ecflow_4_0_7/view/src/time.cc b/ecflow_4_0_7/view/src/time.cc
deleted file mode 100644
index 4990fdc..0000000
--- a/ecflow_4_0_7/view/src/time.cc
+++ /dev/null
@@ -1,163 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #14 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <string>
-#include "time_node.h"
-
-#ifndef ecf_node_
-#include "ecf_node.h"
-#endif
-
-#ifdef BRIDGE
-
-static char *week[] = {
- (char*)"sunday",(char*) "monday",(char*)"tueday",
- (char*)"wednesday",(char*)"thursday", (char*)"friday",
- (char*)"saturday"};
-
-static char *month[] = {
- (char*)"january", (char*)"february", (char*)"march",
- (char*)"april", (char*)"may", (char*)"june",
- (char*)"july", (char*)"august", (char*)"september",
- (char*)"october", (char*)"november", (char*)"december",
-};
-
-static char* ext[] = {
- (char*)"st",(char*)"nd",(char*)"rd",(char*)"th",(char*)"th",
- (char*)"th",(char*)"th",(char*)"th",(char*)"th",(char*)"th",
- (char*)"th",(char*)"th",(char*)"th",(char*)"th",(char*)"th",
- (char*)"th",(char*)"th",(char*)"th",(char*)"th",(char*)"th",
- (char*)"st",(char*)"nd",(char*)"rd",(char*)"th",(char*)"th",
- (char*)"th",(char*)"th",(char*)"th",(char*)"th",(char*)"th",
- (char*)"st",
-};
-
-time_node::time_node(host& h,sms_node* n, char b)
- : node(h,n,b)
- , time_("time")
-{
-}
-#endif
-
-time_node::time_node(host& h,ecf_node* n)
- : node(h,n)
- , time_("time")
-{
- full_name_ = parent()->full_name();
- full_name_ += ":";
- if (owner_) full_name_ += owner_->toString();
-}
-
-char* time_node::string(char* s)
-{
- s[0] = 0;
-#ifdef BRIDGE
- if (tree_) {
- sms_time *t = (sms_time*)tree_;
-
- char buf[1024];
- s[0] = 0;
-
- sprintf(buf,t->hour[0]<0?"*":"%02d",t->hour[0]);
- strcat(s,buf);
-
- strcat(s,":");
-
- sprintf(buf,t->minute[0]<0?"*":"%02d",t->minute[0]);
- strcat(s,buf);
-
- if(t->repeat)
- {
- sprintf(buf," to %02d:%02d",t->hour[1],t->minute[1]);
- strcat(s,buf);
-
- sprintf(buf," by %02d:%02d",t->hour[2],t->minute[2]);
- strcat(s,buf);
- }
-
-
- if(t->iscron)
- {
- long w = t->weekdays;
- int n = 0;
- while(w)
- {
- if(w%2)
- {
- sprintf(buf," %s",week[n]);
- strcat(s,buf);
- }
- w >>= 1;
- n++;
- }
-
- w = t->monthdays;
- n = 0;
- while(w)
- {
- if(w%2)
- {
- sprintf(buf," %d%s",n+1,ext[n]);
- strcat(s,buf);
- }
- n++;
- w >>= 1;
- }
-
- w = t->months;
- n = 0;
- while(w)
- {
- if(w%2)
- {
- sprintf(buf," %s",month[n]);
- strcat(s,buf);
- }
- w >>= 1;
- n++;
- }
- }
- return s;
-}
-#endif
- if (owner_) { sprintf(s, owner_->toString().c_str()); return s; }
- return s;
-}
-
-xmstring time_node::make_label_tree()
-{
- char s[1024];
-#ifdef BRIDGE
- sms_time *t = (sms_time*)tree_;
- if (t && t->iscron)
- {
- xmstring c("cron: ","bold");
- xmstring x(this->string(s));
- return c + x;
- }
-#endif
- return xmstring(this->string(s));
-}
-
-void time_node::perlify(FILE* f)
-{
- char buf[1034];
- perl_member(f,"value",string(buf));
-}
-
-node* time_node::graph_node()
-{
- return &dummy_node::get(full_name());
-}
diff --git a/ecflow_4_0_7/view/src/time_node.h b/ecflow_4_0_7/view/src/time_node.h
deleted file mode 100644
index 246343c..0000000
--- a/ecflow_4_0_7/view/src/time_node.h
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef TIME_H
-#define TIME_H
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #10 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-#include "node.h"
-#include "show.h"
-#include "dummy_node.h"
-
-class time_node : public node {
- std::string time_, full_name_;
- virtual node* graph_node();
-
- virtual bool is_my_parent(node*) const { return false; }
- virtual void info(std::ostream&) {}
-
- virtual xmstring make_label_tree();
- virtual xmstring make_label_trigger() {
- return make_label_tree();
- }
-
- virtual const std::string& name() const { return time_; }
- const std::string& full_name() const { return full_name_; }
- virtual Boolean menus() { return False; }
- virtual Boolean selectable() { return False; }
-
- virtual Boolean visible() const { return show::want(show::time); }
-
- char* string(char*);
- virtual void perlify(FILE*);
-
-public:
- time_node(host& h,ecf_node* n);
-#ifdef BRIDGE
- time_node(host& h,sms_node* n, char b);
-#endif
-};
-#endif
diff --git a/ecflow_4_0_7/view/src/timeout.cc b/ecflow_4_0_7/view/src/timeout.cc
deleted file mode 100644
index 32ae490..0000000
--- a/ecflow_4_0_7/view/src/timeout.cc
+++ /dev/null
@@ -1,86 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "ecflowview.h"
-#include "timeout.h"
-
-extern XtAppContext app_context;
-
-void timeout::timeoutCB(XtPointer data,XtIntervalId* id)
-{
- timeout* t = (timeout*)data;
-
- if(t->actived_)
- {
- t->running_ = True;
- t->run();
- t->running_ = False;
- }
-
- if(t->actived_)
- t->id_ = XtAppAddTimeOut(app_context,t->frequency_*1000,timeoutCB,t);
-}
-
-timeout::timeout(double frequency):
- actived_(False),
- frequency_(frequency),
- id_(0),
- running_(False)
-{
-}
-
-timeout::~timeout()
-{
- disable();
-}
-
-void timeout::enable()
-{
- if(!actived_ && app_context)
- {
- id_ = XtAppAddTimeOut(app_context,frequency_*1000,timeoutCB,this);
- actived_ = True;
- }
-}
-
-
-void timeout::disable()
-{
- if(actived_ && id_)
- {
- XtRemoveTimeOut(id_);
- id_ = 0;
- actived_ = False;
- }
-}
-
-void timeout::frequency(double n)
-{
- frequency_ = n;
- if(!running_ && actived_)
- {
- disable();
- enable();
- }
-}
-
-void timeout::drift(double n,double maximum)
-{
- double x = frequency_ + n;
- if(x>maximum) x = maximum;
- frequency(x);
-}
-
-IMP(timeout)
diff --git a/ecflow_4_0_7/view/src/timeout.h b/ecflow_4_0_7/view/src/timeout.h
deleted file mode 100644
index 264272b..0000000
--- a/ecflow_4_0_7/view/src/timeout.h
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef timeout_H
-#define timeout_H
-
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <Xm/Xm.h>
-
-#ifndef extent_H
-#include "extent.h"
-#endif
-
-class timeout : public extent<timeout> {
-public:
-
- timeout(double);
-
- virtual ~timeout(); // Change to virtual if base class
-
- void enable();
- void disable();
- void frequency(double);
- void drift(double,double);
-
- virtual void run() = 0;
-
-private:
-
- timeout(const timeout&);
- timeout& operator=(const timeout&);
-
- Boolean actived_;
- double frequency_;
- XtIntervalId id_;
- int running_;
-
- static void timeoutCB(XtPointer,XtIntervalId*);
-
-};
-
-#endif
diff --git a/ecflow_4_0_7/view/src/timetable_panel.cc b/ecflow_4_0_7/view/src/timetable_panel.cc
deleted file mode 100644
index 2cdea84..0000000
--- a/ecflow_4_0_7/view/src/timetable_panel.cc
+++ /dev/null
@@ -1,731 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #7 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <stdlib.h>
-#include "arch.h"
-#include "timetable_panel.h"
-#include "node.h"
-#include "host.h"
-#include "fsb.h"
-#include "gui.h"
-#include "xnode.h"
-#include "xmstring.h"
-#include "globals.h"
-#include "tmp_file.h"
-#include <Xm/Text.h>
-#include <Xm/ToggleB.h>
-
-#include "log_event.h"
-extern "C" {
-#include "SimpleTime.h"
-#include "Hyper.h"
-}
-
-namespace timetatble_status {
-const char *status_name[10]
- = { "unknown", "suspended", "complete", "queued", "submitted", "active",
- "aborted", "shutdown", "halted" , NULL };
-}
-
-extern "C" {
-#include "xec.h"
-}
-static void date2str(char* buf,const DateTime& dt)
-{
- int ddd = dt.date;
- int ttt = dt.time;
-
- int yy = ddd / 10000; ddd %= 10000;
- int mm = ddd / 100; ddd %= 100;
- int dd = ddd;
- int HH = ttt / 10000; ttt %= 10000;
- int MM = ttt / 100; ttt %= 100;
- int ss = ttt ;
- sprintf(buf,"%04d-%02d-%02d %02d:%02d:%02d",
- yy,mm,dd,HH,MM,ss);
-}
-
-
-static int sec2str(char* buf,int s)
-{
- buf[0] = 0;
- if(s) {
-
- long x = s>0?s:-s;
- long n;
- char sec[20];
- char min[20];
- char hou[20];
- char day[20];
-
- *sec = *min = *hou = *day = 0;
- if((n = x % 60)) sprintf(sec,"%ld sec ",n);
- x /= 60;
- if((n = x % 60)) sprintf(min,"%ld min ",n);
- x /= 60;
- if((n = x % 24)) sprintf(hou,"%ld hour ",n);
- x /= 24;
- if((n = x)) sprintf(day,"%ld day ",n);
-
- sprintf(buf,"%s%s%s%s", day,hou,min,sec);
- }
- return s;
-}
-
-static int range2str(char* buf,const DateTime& dt1,const DateTime& dt2)
-{
- return sec2str(buf,TimeDiff(dt1,dt2));
-}
-
-static void date2widget(Widget w,DateTime& x)
-{
- char buf[80];
- if(x == kSmallDate)
- strcpy(buf,"-infinite");
- else if(x == kLargeDate)
- strcpy(buf,"+infinite");
- else
- {
- TimeAdd(&x,0);
- date2str(buf,x);
- }
-
- XmTextSetString(w,buf);
-}
-
-class timetable_node : public xnode {
-#if 1
- // important: and alos in log_event
- void notification(observable*) { redraw(); }
- void adoption(observable* o,observable* n) { node_ = (node*)n; }
- void gone(observable*) { owner_.remove(this); delete this; }
-#endif
-protected:
- timetable_panel& owner_;
- log_event* event_;
-public:
- timetable_node(Widget w,timetable_panel& t,log_event* e);
- virtual ~timetable_node();
- log_event* event() { return event_; }
- virtual DateTime date() { return event_->time(); }
- virtual char* text(char* b) { return event_->text(b); }
- virtual bool is_name() { return false; }
- virtual bool change_fold() { return false; }
-};
-
-timetable_node::timetable_node(Widget w,timetable_panel& o,log_event* e):
- xnode(e->get_node()), owner_(o), event_(e)
-{
- event_->attach();
-}
-
-timetable_node::~timetable_node()
-{
- event_->detach();
-}
-
-//====================================================================
-
-class time_event_node : public timetable_node {
-protected:
-
- void draw(Widget w,XRectangle* r) { event_->draw(w,r); }
- void size(Widget w,XRectangle* r) { event_->size(w,r); }
-
-public:
- time_event_node(Widget w,timetable_panel&,log_event*);
- ~time_event_node() {}
-};
-
-time_event_node::time_event_node(Widget w,timetable_panel& o,log_event* e):
- timetable_node(w,o,e)
-{
- TimeSetTime(w,getBox(w),e->time());
-}
-
-//====================================================================
-
-class time_name_node : public timetable_node {
- bool fold_;
- void draw(Widget w,XRectangle* r);
- void size(Widget w,XRectangle* r);
-public:
- time_name_node(Widget w,timetable_panel&,log_event*);
- ~time_name_node() {}
- virtual char* text(char* b) {
- strcpy(b,node_->full_name().c_str());return b; }
- virtual bool is_name() { return true; }
- virtual bool change_fold() { fold_ = !fold_; redraw(); return fold_; }
-};
-
-time_name_node::time_name_node(Widget w,timetable_panel& o,log_event* e):
- timetable_node(w,o,e),
- fold_(false)
-{
- node_ = e->owner();
- getBox(w);
-}
-
-void time_name_node::draw(Widget w,XRectangle* r)
-{
- xmstring s(node_->full_name().c_str(),fold_?"bold":"normal");
-
- XmFontList f = gui::tinyfont();
- XmStringDraw(XtDisplay(w),XtWindow(w),
- f,
- s,
- gui::blackGC(),
- r->x,
- r->y,
- r->width,
- XmALIGNMENT_CENTER, XmSTRING_DIRECTION_L_TO_R, r);
-}
-
-void time_name_node::size(Widget w,XRectangle* r)
-{
- xmstring s(node_->full_name().c_str(),fold_?"bold":"normal");
-
- XmFontList f = gui::tinyfont();
- r->width = XmStringWidth(f,s);
- r->height = XmStringHeight(f,s);
-}
-
-
-//====================================================================
-
-timetable_panel::timetable_panel(panel_window& w):
- panel(w),
- last_(kSmallDate),
- min_time_(kSmallDate),
- max_time_(kLargeDate)
-{
- sorted_by_time_ = globals::get_resource("timeline_sorted_by_time",false);
- tasks_only_ = globals::get_resource("timeline_tasks_only",false);
-}
-
-timetable_panel::~timetable_panel()
-{
- clear();
-}
-
-void timetable_panel::create(Widget parent, char *widget_name )
-{
- timetable_form_c::create(parent,widget_name);
-
- add_input_CB();
-
- date2widget(from_,min_time_);
- date2widget(to_,max_time_);
-
- XmToggleButtonSetState(by_time_,sorted_by_time_,False);
- XmToggleButtonSetState(by_name_,!sorted_by_time_,False);
-
- XmToggleButtonSetState(all_,!tasks_only_,False);
- XmToggleButtonSetState(tasks_,tasks_only_,False);
-}
-
-void timetable_panel::clear()
-{
- NodeReset(time_);
- for(int i = 0; i < nodes_.count(); i++)
- delete nodes_[i];
- nodes_.clear();
- XmTextSetString(file_,"");
- last_ = kSmallDate;
- depend::hide();
-}
-
-void timetable_panel::show(node& n)
-{
- clear();
- reload(false);
-}
-
-void timetable_panel::reload(bool reset)
-{
- if(get_node())
- load(get_node()->serv().timefile().c_str(),reset);
- else
- clear();
-}
-
-void timetable_panel::changed(node& n)
-{
-}
-
-void timetable_panel::remove(timetable_node *t)
-{
- nodes_.remove(t);
-}
-
-void timetable_panel::next(log_event* n)
-{
- if(n->time() < min_time_ || n->time() > max_time_)
- return;
-
- if(tasks_only_ && n->owner()->type() != NODE_TASK) return;
-
- time_event_node *t = new time_event_node(time_,*this,n);
- int c = nodes_.count();
- bool found = false;
-
- for(int i = c-1 ; i >= 0; i--)
- if(nodes_[i]->event()->owner() == n->owner())
- {
- nodes_[i]->relation(t);
- found = true;
- break;
- }
-
- if(!found) {
- time_name_node *x = new time_name_node(time_,*this,n);
- nodes_.add(x);
- x->relation(t);
- x->visibility(true);
- }
-
- t->visibility(true);
- nodes_.add(t);
-
-}
-
-Boolean timetable_panel::enabled(node& n)
-{
- return TRUE;
-}
-
-struct sort_by_name : public event_sorter {
-public:
- int compare(log_event* a,log_event* b) {
- char sa[1024];
- char sb[1024];
-
- node *nodea = a->get_node();
- node *nodeb = b->get_node();
-
- const char *ca = nodea ? nodea->full_name().c_str() : "none";
- const char *cb = nodeb ? nodeb->full_name().c_str() : "none";
-
- strcpy(sa,ca);
- strcpy(sb,cb);
- return strcmp(sa,sb);
- }
-};
-
-struct sort_by_time : public event_sorter {
-public:
- int compare(log_event* a,log_event* b) {
- return TimeDiff(a->time(),b->time());
- }
-};
-
-
-static DateTime widget2date(Widget w)
-{
- char *p = XmTextGetString(w);
- char buf[80];
- char *q = p;
- int i = 0;
- int j = 0;
-
- while(*q)
- {
- if(*q >= '0' && *q <= '9') buf[i++] = *q;
- if(*q == ' ') { buf[i++] = 0; j = i; }
- q++;
- }
-
- buf[i] = 0;
- XtFree(p);
-
- DateTime dt;
- dt.date = atol(buf);
- dt.time = atol(buf+j);
-
- TimeAdd(&dt,0);
-
- return dt;
-}
-
-void timetable_panel::load(const char* fname,bool reset)
-{
- clear();
- if(get_node())
- {
- str path = fname;
-
- if(!reset && path != get_node()->serv().timefile())
- path = path + str(" ") + str(fname);
-
- get_node()->serv().timefile(path);
-
- min_time_ = widget2date(from_);
- max_time_ = widget2date(to_);
-
- if(min_time_ < kSmallDate) min_time_ = kSmallDate;
- if(max_time_ < kSmallDate) max_time_ = kLargeDate;
-
- date2widget(from_,min_time_);
- date2widget(to_,max_time_);
-
-
- XmTextSetString(file_,(char*)path.c_str());
- log_event::load(get_node()->serv(),path.c_str(),reset);
-
-
- if(sorted_by_time_)
- {
- sort_by_time sbt;
- log_event::sort(sbt);
- }
- else
- {
- sort_by_name sbn;
- log_event::sort(sbn);
- }
-
- log_event::scan(get_node(),*this);
-
- }
-}
-
-void timetable_panel::load(bool reset)
-{
- const char* p = 0;
- if((p = fsb::ask("Load a timefile")))
- load(p,reset);
-}
-
-void timetable_panel::chooseCB( Widget, XtPointer data)
-{
- load(true);
-}
-
-void timetable_panel::loadCB( Widget, XtPointer data)
-{
- load(true);
-}
-
-void timetable_panel::mergeCB( Widget, XtPointer data)
-{
- load(false);
-}
-
-void timetable_panel::activateCB(Widget w, XtPointer data)
-{
- char* p = XmTextGetString(file_);
- load(p, w == file_);
- str s(p);
- XtFree(p);
-}
-
-
-void timetable_panel::updateCB( Widget, XtPointer data)
-{
- reload(true);
-}
-
-
-void timetable_panel::hyperCB(Widget w, XtPointer data)
-{
- panel::hyper(w,data);
-}
-
-static int compare(const void* a,const void *b)
-{
- timetable_node** ta = (timetable_node**)a;
- timetable_node** tb = (timetable_node**)b;
-
- return TimeDiff( (*ta)->event()->time(), (*tb)->event()->time());
-}
-
-void timetable_panel::raw_click1(XEvent* e,xnode* x)
-{
- char buf[1024];
-
- if(x == 0) x = (xnode*)TimeFindByY(time_,e);
-
- timetable_node* t = main((timetable_node*)x);
- if(!t) return;
-
-
- node *m = t->get_node();
-
- tmp_file tmp(tmpnam(0));
- FILE *f = fopen(tmp.c_str(),"w");
- if(!f) return;
-
- range(t,dt1_,dt2_);
-
- if (m) fprintf(f,"{%s}",m->full_name().c_str());
- if(range2str(buf,dt1_,dt2_))
- fprintf(f," total time: %s",buf);
- fprintf(f,"\n\n");
-
- timetable_node** nodes = new timetable_node*[nodes_.count()];
- int count = 0;
- int i;
-
- for(i = 0; i < nodes_.count(); i++)
- if(!nodes_[i]->is_name() && nodes_[i]->event()->owner() == m)
- nodes[count++] = nodes_[i];
-
- qsort(nodes,count,sizeof(nodes[0]),compare);
-
-
- bool ok = false;
- int elapsed[STATUS_MAX];
- for(i = 0; i < STATUS_MAX; i++)
- elapsed[i] = 0;
-
- int prev_i = -1;
-
- for(i = 0; i < count; i++)
- {
- date2str(buf,nodes[i]->event()->time());
- fprintf(f,"%s",buf);
- fprintf(f," %s",nodes[i]->text(buf));
-
- if(i)
- {
- if(range2str(buf,
- nodes[i-1]->event()->time(),
- nodes[i]->event()->time()))
- fprintf(f," (%slater)",buf);
-
- }
-
- if(prev_i >= 0 && nodes[i]->event()->status() >= 0)
- {
- elapsed[nodes[prev_i]->event()->status()] +=
- TimeDiff(nodes[i]->event()->time(),
- nodes[prev_i]->event()->time());
- ok = true;
- }
-
- int s = nodes[i]->event()->status();
- if(s >= 0) prev_i = i;
-
- fprintf(f,"\n");
- }
-
- delete[] nodes;
-
- if(ok) {
- fprintf(f,"\nSummary:");
- fprintf(f,"\n--------\n");
-
- for(i = 0; i < STATUS_MAX; i++)
- if(elapsed[i])
- {
- sec2str(buf,elapsed[i]);
- fprintf(f,"%-10s: %s\n",timetatble_status::status_name[i],buf);
- }
- }
-
- fclose(f);
- depend::make(widget());
- HyperLoadFile(hyper_,(char*)tmp.c_str());
- depend::raise(widget());
-}
-
-void timetable_panel::setToCB(Widget,XtPointer)
-{
- date2widget(to_,dt2_);
- reload(false);
-}
-
-void timetable_panel::setFromCB(Widget,XtPointer)
-{
- date2widget(from_,dt1_);
- reload(false);
-}
-
-void timetable_panel::setBothCB(Widget,XtPointer)
-{
- date2widget(from_,dt1_);
- date2widget(to_,dt2_);
- reload(false);
-}
-
-void timetable_panel::resetCB(Widget w,XtPointer d)
-{
- dt1_ = kSmallDate; dt2_ = kLargeDate;
- setBothCB(w,d);
-}
-
-void timetable_panel::raw_click2(XEvent* e,xnode* x)
-{
- timetable_node *t = (timetable_node*)x;
-
- if(t && t->is_name())
- {
- node *m = t->get_node();
- bool x = !t->change_fold();
-
- for(int i = 0; i < nodes_.count(); i++)
- if(nodes_[i]->get_node() != m)
- if(nodes_[i]->get_node())
- if(nodes_[i]->get_node()->is_my_parent(m))
- nodes_[i]->visibility(x);
- NodeUpdate(time_);
- }
- else {
- }
-}
-
-timetable_node* timetable_panel::main(timetable_node* t)
-{
- if(!t) return 0;
-
- node *m = t->get_node();
- for(int i = 0; i < nodes_.count(); i++)
- if(nodes_[i]->is_name() && nodes_[i]->get_node() == m)
- return nodes_[i];
- return 0;
-}
-
-
-
-void timetable_panel::range(timetable_node* z,DateTime& dt1,DateTime& dt2)
-{
-
- dt1 = dt2 = z->event()->time();
-
- if(z->is_name())
- {
-
- node *m = z->get_node();
-
- for(int i = 0; i < nodes_.count(); i++)
- if(!nodes_[i]->is_name() && nodes_[i]->get_node() == m)
- {
- DateTime t = nodes_[i]->event()->time();
- if(t < dt1) dt1 = t;
- if(t > dt2) dt2 = t;
- }
- }
-
-}
-
-void timetable_panel::raw_click3(XEvent* e,xnode* x)
-{
- char buf[1024];
-
-
- timetable_node* z = (timetable_node*)x;
-
- xmstring s("-");
- static xmstring cr("\n");
-
- XtUnmanageChild(set_both_);
- XtManageChild(set_to_);
- XtManageChild(set_from_);
-
-
- if(z) {
-
- z->text(buf);
- range(z,dt1_,dt2_);
-
- s = xmstring(buf);
-
- if(z->is_name())
- {
- date2str(buf,dt1_);
- s += cr;
- s += xmstring("From : ","bold");
- s += xmstring(buf);
-
- date2str(buf,dt2_);
- s += cr;
- s += xmstring("To : ","bold");
- s += xmstring(buf);
-
- if(range2str(buf,dt1_,dt2_))
- {
- s += cr;
- s += xmstring("Elapsed: ","bold");
- s += xmstring(buf);
- }
-
- XtManageChild(set_both_);
- XtUnmanageChild(set_to_);
- XtUnmanageChild(set_from_);
-
- }
- else {
-
- date2str(buf,dt1_);
- s = xmstring(buf) + cr + s;
-
- if(last_ != kSmallDate)
- {
- if(range2str(buf,last_,dt1_))
- {
- s += cr;
- s += xmstring("From last click: ","bold");
- s += xmstring(buf);
- }
- }
-
- last_ = dt1_;
-
- }
- }
- else {
- TimeEventTime(time_,e,&dt1_);
- date2str(buf,dt1_);
- s = xmstring(buf);
- dt2_ = dt1_;
- last_ = kSmallDate;
- }
-
- XtVaSetValues(label_, XmNlabelString, XmString(s), NULL);
-
- node_window::raw_click3(e,0);
-}
-
-
-Widget timetable_panel::menu1()
-{
- return menu_;
-}
-
-Widget timetable_panel::menu2()
-{
- return menu1();
-}
-
-xnode* timetable_panel::xnode_of(node& n)
-{
-#if 0
- for(int i = 0; i < nodes_.count(); i++)
- if(nodes_[i]->get_node() == &n)
- return nodes_[i];
-#endif
- return 0;
-}
-
-void timetable_panel::optionsCB(Widget,XtPointer)
-{
- globals::set_resource("timeline_sorted_by_time",
- sorted_by_time_ = XmToggleButtonGetState(by_time_));
-
- globals::set_resource("timeline_tasks_only",
- tasks_only_ = XmToggleButtonGetState(tasks_));
-
- reload(false);
-}
diff --git a/ecflow_4_0_7/view/src/timetable_panel.h b/ecflow_4_0_7/view/src/timetable_panel.h
deleted file mode 100644
index 5fbb4cb..0000000
--- a/ecflow_4_0_7/view/src/timetable_panel.h
+++ /dev/null
@@ -1,123 +0,0 @@
-#ifndef timetable_panel_H
-#define timetable_panel_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "uitimetable.h"
-
-#ifndef panel_H
-#include "panel.h"
-#endif
-
-#ifndef node_window_H
-#include "node_window.h"
-#endif
-
-#ifndef str_H
-#include "str.h"
-#endif
-
-#ifndef array_H
-#include "array.h"
-#endif
-
-#ifndef log_event_H
-#include "log_event.h"
-#endif
-
-#ifndef depend_H
-#include "depend.h"
-#endif
-
-class layout;
-class host;
-class timetable_node;
-
-class timetable_panel : public panel
- , public node_window
- , public depend
- , public event_lister
- , public timetable_form_c {
-public:
-
- timetable_panel(panel_window&);
-
- ~timetable_panel(); // Change to virtual if base class
-
- void remove(timetable_node*);
-
- virtual void create (Widget parent, char *widget_name = NULL);
- virtual void show(node&);
- virtual void changed(node&);
- virtual Boolean enabled(node&);
- virtual void clear();
- virtual const char* name() const { return "Time line"; }
- virtual Widget widget() { return timetable_form_c::xd_rootwidget(); }
- virtual Widget tools() { return tools_; }
-
-private:
-
- timetable_panel(const timetable_panel&);
- timetable_panel& operator=(const timetable_panel&);
-
- array<timetable_node*> nodes_;
-
- DateTime last_;
- DateTime min_time_;
- DateTime max_time_;
-
- bool sorted_by_time_;
- bool tasks_only_;
-
- DateTime dt1_;
- DateTime dt2_;
-
- void load(bool);
- void load(const char*,bool);
- timetable_node* add(log_event*);
- void range(timetable_node*,DateTime&,DateTime&);
- timetable_node* main(timetable_node*);
-
- void reload(bool);
-
- virtual void chooseCB( Widget, XtPointer );
- virtual void loadCB( Widget, XtPointer );
- virtual void mergeCB( Widget, XtPointer );
- virtual void updateCB( Widget, XtPointer );
- virtual void activateCB( Widget, XtPointer );
- virtual void optionsCB( Widget, XtPointer );
-
- virtual void setFromCB( Widget, XtPointer );
- virtual void setToCB( Widget, XtPointer );
- virtual void setBothCB( Widget, XtPointer );
- virtual void resetCB( Widget, XtPointer );
- virtual void hyperCB( Widget, XtPointer );
-
- // From node_window
- virtual xnode* xnode_of(node &);
- virtual Widget node_widget() { return time_; }
- virtual Widget menu1();
- virtual Widget menu2();
-
- virtual void raw_click1(XEvent*,xnode*);
- virtual void raw_click2(XEvent*,xnode*);
- virtual void raw_click3(XEvent*,xnode*);
-
- virtual void next(log_event*);
-};
-
-inline void destroy(timetable_panel**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/tip.cc b/ecflow_4_0_7/view/src/tip.cc
deleted file mode 100644
index c46f47b..0000000
--- a/ecflow_4_0_7/view/src/tip.cc
+++ /dev/null
@@ -1,114 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #9 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <X11/IntrinsicP.h>
-#include <Xm/Xm.h>
-#include <Xm/PushB.h>
-#include <stdio.h>
-#include "tip.h"
-#include "gui.h"
-#include "pixmap.h"
-extern "C" {
-#include "xec.h"
-}
-
-tip::tip(Widget w):
- timeout(0.5),
- in_(false),
- widget_(w)
-{
- if(XmIsPushButton(w)) {
- XtAddEventHandler(w,EnterWindowMask,False,enterCB,this);
- XtAddEventHandler(w,LeaveWindowMask|ButtonPressMask,False,leaveCB,this);
- }
-
- create(gui::top(),NULL);
- xec_SetLabel(label_,XtName(w));
- XtRealizeWidget(_xd_rootwidget);
-
- pixmap::find(XtName(w)).set_label(w);
-}
-
-tip::~tip()
-{
-}
-
-void tip::enter()
-{
- if (1) {
- in_ = true;
- enable();
- }
- else
- in_ = false;
-}
-
-void tip::leave()
-{
- in_ = false;
- disable();
- XUnmapWindow(XtDisplay(_xd_rootwidget),XtWindow(_xd_rootwidget));
-}
-
-void tip::enterCB(Widget w,XtPointer data,XEvent*,Boolean*)
-{
- ((tip*)data)->enter();
-}
-
-void tip::leaveCB(Widget w,XtPointer data,XEvent*,Boolean*)
-{
- ((tip*)data)->leave();
-}
-
-#include <Xm/XmP.h>
-
-void tip::makeTips(Widget w)
-{
- CompositeWidget c = (CompositeWidget)w;
- for(unsigned int i = 0 ; i < c->composite.num_children; i++)
- {
- Widget p = c->composite.children[i];
- if(XmIsPushButton(p)) new tip(p);
- // else { printf("# xtname: %s\n", XtName(p)); new tip(p); }
- }
-}
-
-void tip::run()
-{
- Position x,y;
- Dimension h,w,lw,lh;
- XmString ls;
-
- if (widget_==NULL) return;
- XtTranslateCoords(widget_,0,0,&x,&y);
-
- if (0) {
- XtVaGetValues(widget_,XmNheight,&h,NULL);
- XtVaSetValues(tip_shell,XmNx,x,XmNy,y + h, NULL);
- } else {
- XmFontList fl = NULL;
- XtVaGetValues(widget_, XmNfontList, &fl, NULL);
- if (fl == NULL) return; /* ??? 20120119 */
- ls = XmStringCreateSimple(XtName(widget_));
- lw = XmStringWidth(fl, ls)+6;
- lh = XmStringHeight(fl, ls)+6;
- XmStringFree(ls);
- XtVaGetValues(widget_,XmNheight,&h,XmNwidth,&w,NULL);
- XtVaSetValues(tip_shell, XmNx,x + w,XmNy,y + h,
- XmNwidth,lw,XmNheight,lh,NULL);
- }
- XMapRaised(XtDisplay(_xd_rootwidget),XtWindow(_xd_rootwidget));
- disable();
-}
diff --git a/ecflow_4_0_7/view/src/tip.h b/ecflow_4_0_7/view/src/tip.h
deleted file mode 100644
index 23df961..0000000
--- a/ecflow_4_0_7/view/src/tip.h
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef tip_H
-#define tip_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#ifndef timeout_H
-#include "timeout.h"
-#endif
-
-#include "uitip.h"
-
-class tip : public timeout, public tip_shell_c {
-public:
-
- tip(Widget);
-
- ~tip(); // Change to virtual if base class
-
- static void makeTips(Widget);
-
-private:
-
- tip(const tip&);
- tip& operator=(const tip&);
-
- Boolean in_;
- Widget widget_;
-
- void enter();
- void leave();
- void run();
-
- static void enterCB(Widget,XtPointer,XEvent*,Boolean*);
- static void leaveCB(Widget,XtPointer,XEvent*,Boolean*);
-};
-
-inline void destroy(tip**) {}
-
-#endif
diff --git a/ecflow_4_0_7/view/src/tmp_file.cc b/ecflow_4_0_7/view/src/tmp_file.cc
deleted file mode 100644
index 14b4f0b..0000000
--- a/ecflow_4_0_7/view/src/tmp_file.cc
+++ /dev/null
@@ -1,109 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "tmp_file.h"
-#include <iostream>
-#include <fstream>
-#include <ecflowview.h>
-
-tmp_file_imp::tmp_file_imp(const char* p,bool del):
- str_(p ? strdup(p) : 0),
- del_(del)
-{
-}
-
-tmp_file_imp::~tmp_file_imp()
-{
- if(str_) {
- if(del_) {
- unlink(str_);
- }
- free(str_);
- }
-}
-
-const char* tmp_file_imp::str()
-{
- return str_;
-}
-
-tmp_file::tmp_file(const char* p,bool del):
- imp_(new tmp_file_imp(p,del))
-{
- imp_->attach();
-}
-
-tmp_file::tmp_file(const std::string& p,bool del):
- imp_(new tmp_file_imp(tmpnam((char*)tmpName),del))
-{
- imp_->attach();
- std::ofstream f (imp_->str());
- if (f.is_open())
- {
- f << p;
- f.close();
- }
-}
-
-const char* tmp_file::c_str() {
- if (imp_) return imp_->str();
- return 0x0;
-}
-
-tmp_file::~tmp_file()
-{
- if(imp_)
- imp_->detach();
-}
-
-tmp_file::tmp_file(const tmp_file& other):
- imp_(other.imp_)
-{
- imp_->attach();
-}
-
-tmp_file& tmp_file::operator=(const tmp_file& other)
-{
- if (other.imp_)
- other.imp_->attach();
- if (imp_) {
- imp_->detach();
- }
- imp_ = other.imp_;
- return *this;
-}
-
-#if defined(linux) || defined(_AIX)
-
-char * tmpnam(char *) __THROW {
- char *path = getenv("SCRATCH");
- char *s = (char*) malloc(128);
- if (!path || !access(path, R_OK))
- path=getenv("TMPDIR");
- if (!path || !access(path, R_OK))
- path=(char*)"/tmp";
- snprintf(s, 128, "%s/%sXXXXXX", path, appName);
- // int fid =
- mkstemp(s);
- // return s = tempnam(path, appName);
- return s;
-}
-
-#endif
-
diff --git a/ecflow_4_0_7/view/src/tmp_file.h b/ecflow_4_0_7/view/src/tmp_file.h
deleted file mode 100644
index 46ce765..0000000
--- a/ecflow_4_0_7/view/src/tmp_file.h
+++ /dev/null
@@ -1,83 +0,0 @@
-#ifndef tmp_file_H
-#define tmp_file_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#ifdef NO_BOOL
-#include "bool.h"
-#endif
-
-#ifndef counted_H
-#include "counted.h"
-#endif
-
-#include <string>
-
-/** char * tmpnam(s) char *s;
- * enable P_tmpdir local definition to change default /tmp directory
- * enable using new location up to 44 char
- */
-
-#ifndef __THROW
-#define __THROW
-#endif
-#ifdef linux
-
-extern "C" {
- extern char * tempnam(const char *d, const char* s) __THROW;
-}
-
-#ifndef tmpnam1
-#include <stdlib.h>
-#define tmpnam1
-char * tmpnam(char *) __THROW;
-#endif
-
-#endif
-
-class tmp_file_imp : public counted {
- char* str_;
- bool del_;
-public:
- tmp_file_imp(const char*,bool);
- ~tmp_file_imp();
- const char* str();
-};
-
-class tmp_file {
- public:
-
- tmp_file(const char* str,bool = true);
-
- // str input IS the file content, not filename
- tmp_file(const std::string& str,bool = true);
- tmp_file(const tmp_file&);
-
- ~tmp_file();
-
- tmp_file& operator=(const tmp_file&);
-
- const char* c_str(); /* { if (imp_) return imp_->str();
- return load.c_str();} */
-
-private:
-
- tmp_file_imp* imp_;
-};
-
-inline void destroy(tmp_file**) {}
-
-#endif
diff --git a/ecflow_4_0_7/view/src/tmpnam.c b/ecflow_4_0_7/view/src/tmpnam.c
deleted file mode 100644
index efa2ef9..0000000
--- a/ecflow_4_0_7/view/src/tmpnam.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/file.h>
-#include <stdio.h>
-
-/*
- * Use /tmp instead of /usr/tmp, because L_tmpname is only 14 chars
- * on some machines (like NeXT machines) and /usr/tmp will cause
- * buffer overflows.
- */
-
-#ifdef P_tmpdir
-# undef P_tmpdir
-#endif
-#define P_tmpdir "/tmp"
-
-char *
-tmpnam(s)
- char *s;
-{
- static char name[50];
- char * file_name;
- char *mktemp();
-
- if (!s)
- s = name;
-
- file_name = getenv ("TMPDIR");
-
- if (file_name && strlen (file_name) < 42)
- (void)sprintf(s, "%s/XXXXXX", file_name);
- else
- (void)sprintf(s, "%s/XXXXXX", P_tmpdir);
-
- if (mkstemp(s))
- return s;
- else
- return NULL;
-}
-
-#if UTEST
-
-int main (int argc, char ** argv)
-{
- char *name = tmpnam (NULL);
- printf ("%s\n", name);
-};
-#endif
diff --git a/ecflow_4_0_7/view/src/to_check.h b/ecflow_4_0_7/view/src/to_check.h
deleted file mode 100644
index 6251272..0000000
--- a/ecflow_4_0_7/view/src/to_check.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef to_check_H
-#define to_check_H
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #4 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-
-#include "node_alert.h"
-
-class node;
-
-class to_check : public node_alert<to_check> {
-public:
- to_check();
-
- ~to_check(); // Change to virtual if base class
-
-private:
-
- to_check(const to_check&);
- to_check& operator=(const to_check&);
-
- virtual bool keep(node* n);
-
-};
-
-inline void destroy(to_check**) {}
-
-#endif
diff --git a/ecflow_4_0_7/view/src/top.cc b/ecflow_4_0_7/view/src/top.cc
deleted file mode 100644
index d86f9cc..0000000
--- a/ecflow_4_0_7/view/src/top.cc
+++ /dev/null
@@ -1,512 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #20 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "top.h"
-#include "ecflowview.h"
-#include "gui.h"
-#include "mail.h"
-#include "servers_prefs.h"
-#ifndef tree_H
-#include "tree.h"
-#endif
-#include <Xm/PushB.h>
-
-#ifndef panel_window_H
-#include "panel_window.h"
-#endif
-
-#ifndef window_H
-#include "window.h"
-#endif
-
-#ifndef error_H
-#include "error.h"
-#endif
-
-
-#ifndef runnable_H
-#include "runnable.h"
-#endif
-
-#ifndef init_H
-#include "init.h"
-#endif
-
-#ifndef show_H
-#include "show.h"
-#endif
-
-#ifndef host_H
-#include "host.h"
-#endif
-
-#ifndef tip_H
-#include "tip.h"
-#endif
-
-#ifndef search_H
-#include "search.h"
-#endif
-
-#ifndef option_H
-#include "option.h"
-#endif
-
-#ifndef pref_window_H
-#include "pref_window.h"
-#endif
-
-#ifndef ask_H
-#include "ask.h"
-#endif
-
-
-#ifndef error_H
-#include "error.h"
-#endif
-
-
-#include "late.h"
-#include "restart.h"
-#include "aborted.h"
-
-extern "C" {
-#include "xec.h"
-}
-
-#include <X11/IntrinsicP.h>
-#include <Xm/ToggleB.h>
-
-#ifndef globals_H
-#include "globals.h"
-#endif
-
-#include "Version.hpp"
-
-static option<int> top_width(globals::instance(), "top_width",500);
-static option<int> top_height(globals::instance(),"top_height",500);
-static option<int> top_xoff(globals::instance(),"top_xoff",0);
-static option<int> top_yoff(globals::instance(),"top_yoff",0);
-
-top::top():
- timeout(60)
-{
-}
-
-
-top::~top()
-{
- Dimension w,h;
- Position x,y;
-
- XtVaGetValues(this->form_,
- XmNwidth, &w,
- XmNheight,&h,
- XmNx,&x,
- XmNy,&y,
- NULL);
-
- top_width = w;
- top_height = h;
- top_xoff = x;
- top_yoff = y;
-}
-
-class initor : public runnable {
-
- int argc_;
- char **argv_;
-
- void run() {
- disable();
- init::initialize(argc_,argv_);
- delete this;
- }
-
-public:
- initor(int argc,char** argv) : argc_(argc),argv_(argv) { enable(); }
-};
-
-static void set_show(Widget w, int flag)
-{
- CompositeWidget c = CompositeWidget(w);
- for(unsigned i = 0 ; i < c->composite.num_children; i++) {
- Widget p = c->composite.children[i];
- if(XmIsToggleButton(p)) {
- show *s = (show*)xec_GetUserData(p);
- Boolean b = False;
- bool wanted = s->wanted();
- if (flag == show::all) {
- b = True; wanted = true; }
- if ((s->flag() == show::all) || (s->flag() == show::none)) {
- b = False; wanted = false; }
- XmToggleButtonSetState(p,wanted,b);
- }
- }
-}
-
-static int xerror(Display *d, XErrorEvent *e)
-{
- char buf[1024];
- XGetErrorText(d,e->error_code,buf,sizeof(buf));
- printf("xerror %s\n",buf);
- return 0;
-}
-
-void top::create(Display *display, char *app_name,
- int app_argc, char **app_argv, char *app_class_name)
-{
-
-#if 1
- // XSynchronize should *only* be enabled for debug, it should not be enabled in the production build.
- // See: [JIRA] (SUP-349) ecflowview performance slow with ecflow 3_1_rc1
- // It can cause refresh issues when displaying synchronisation enabled.
- // XSynchronize(display,1);
- XSetErrorHandler(xerror);
-#endif
-
-#include "xresources.h"
-
- XrmDatabase db = XrmGetStringDatabase(xresources);
- XrmSetDatabase(display,db);
-
- top_shell_c::create(display,app_name,app_argc,app_argv,app_class_name);
-
- Dimension w,h;
- Position x,y, ac = 0;
- char color[20];
- snprintf(color, 20, "#e5e5e5e5e5e5");
-
- w = top_width;
- h = top_height;
- x = top_xoff;
- y = top_yoff;
-
- while (ac < app_argc) {
- /* accept command line directives for display */
- if (!strncmp("-geometry=",app_argv[ac],10)) {
- int ww=0, hh=0, xx=0, yy=0;
- sscanf(app_argv[ac], "-geometry=%dx%d+%d+%d", &ww, &hh, &xx, &yy);
- fprintf(stdout, "# geometry: %dx%d+%d+%d\n", ww, hh, xx, yy);
- w=ww; h=hh; x=xx; y=yy;
- } else if (!strncmp("-b",app_argv[ac],2)) {
- if (!strncmp("-bg=",app_argv[ac],4)) {
- sscanf(app_argv[ac], "-bg=%s", color);
- } else if (!strncmp("-background=",app_argv[ac],12)) {
- sscanf(app_argv[ac], "-background=%s", color);
- }
-
- std::string res = "ecFlowview*background: ";
- res += color;
- std::cout << "# bg color change: " << res << "\n";
- db = XrmGetStringDatabase(res.c_str());
- XrmSetDatabase(display,db);
- } else if (!strncmp("-rc=",app_argv[ac],4)) {
- char rcdir[1024] = { 0 };
- sscanf(app_argv[1], "-rc=%s", rcdir);
- if (rcdir[0] != 0) {
- std::string var = "ECFLOWRC="; var += rcdir;
- putenv((char*) var.c_str());
- fprintf(stdout, "# rcdir: %s\n", rcdir);
- }
- }
- ac++;
- }
-
- XtVaSetValues(this->form_,
- XmNwidth, w,
- XmNheight,h,
- XmNx, x,
- XmNy, y,
-// XmNbackground, (int)pixel(color),
-// XtVaTypedArg, XmNbackground, XmRString, color.c_str(), size, // 201403
- NULL);
-#if 0
- XtGetApplicationResources(_xd_rootwidget,
- (XtPointer)&globals,
- resources,
- XtNumber(resources),
- NULL,NULL);
-
- XtGCMask valuemask = (GCForeground | GCFont);
- XFontStruct* font = XLoadQueryFont(XtDisplay(_xd_rootwidget),"fixed");
-
- XGCValues values;
- values.font = font->fid;
- values.foreground = globals.black;
-
- globals.blackGC = XtGetGC(_xd_rootwidget,valuemask,&values);
- values.foreground = globals.blue;
- globals.blueGC = XtGetGC(_xd_rootwidget,valuemask,&values);
-
- for(int j=0;j<STATUS_MAX;j++)
- {
- values.foreground = globals.colors[j];
- globals.colGC[j] = XtGetGC(_xd_rootwidget,valuemask,&values);
- }
-#endif
- set_show(show0_,0); set_show(show1_,0);
- set_show(show2_,0); set_show(show3_,0);
-
- tip::makeTips(tools_);
- //==========================================
-
- new initor(app_argc,app_argv);
-
- // Update and start clock
- run();
- enable();
-}
-
-void top::serverCB(Widget,XtPointer)
-{
- host::broadcast();
-}
-
-static void hostCB(Widget w,XtPointer,XtPointer cb_data)
-{
- XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct*)cb_data;
- char* name = XtName(w);
- if(cb->set)
- host::login(name);
- else
- host::logout(name);
-}
-
-void top::add_host(const std::string& host)
-{
- Widget w;
- if(!(w=XtNameToWidget(servers_menu_,host.c_str())))
- {
- w = XmCreateToggleButton(servers_menu_,
- (char*)host.c_str(),NULL,0);
- XtAddCallback(w,XmNvalueChangedCallback,hostCB,NULL);
- }
- XtManageChild(w);
- servers_prefs::add_host(host);
-}
-
-void top::remove_host(const std::string& host)
-{
- Widget w = XtNameToWidget(servers_menu_,host.c_str());
- XtUnmanageChild(w);
-}
-
-void top::login(const char* host)
-{
- Widget w = XtNameToWidget(servers_menu_,host);
- if(w)
- XmToggleButtonSetState(w,True,False);
- mail::login(host);
-}
-
-void top::logout(const char* host)
-{
- Widget w = XtNameToWidget(servers_menu_,host);
- if(w) XmToggleButtonSetState(w,False,False);
- mail::logout(host);
-}
-
-class reset_message : public runnable {
- void run() { gui::clear(); disable(); }
-};
-
-void top::clear()
-{
- run();
-}
-
-void top::message(const char* buf)
-{
- static reset_message reset;
- xec_SetLabel(message_,buf);
- XmUpdateDisplay(message_);
- reset.enable();
-}
-
-
-Widget top::top_shell()
-{
- return xd_rootwidget();
-}
-
-Widget top::trees()
-{
- return trees_;
-}
-
-Widget top::windows()
-{
- return windows_menu_;
-}
-
-void top::run()
-{
- time_t t = time(0);
- char buf[1024];
- // strftime(buf,sizeof(buf),"%Y-%m-%d %H:%M" ,gmtime(&t));
- strftime(buf,sizeof(buf),"%Y-%m-%d %H:%M:%S" ,gmtime(&t));
- xec_SetLabel(message_,buf);
-}
-
-void top::watch(Boolean)
-{
-}
-
-void top::quitCB(Widget,XtPointer)
-{
- extent<host>::delete_all();
- delete this;
- exit(0);
-}
-
-void top::snapshotCB( Widget w, XtPointer p )
-{
- char cmd[1024];
- FILE *f = 0;
-
- gui::message("using SNAPSHOT ; press button \n");
- sprintf(cmd,"${SNAPSHOT:=import} %s\n", snapshotName);
-
- f = popen(cmd,"r");
- if(!f) {
- gui::error("Cannot create snapshot : %s", cmd);
- return;
- }
- else if (!pclose(f)) {
- gui::message("%s # generated\n", snapshotName);
- sprintf(cmd,"${SNAPVISU:=firefox} %s\n", snapshotName);
- f = popen(cmd,"r");
- }
- else {
- gui::error("Cannot create snapshot : %s", cmd);
- return;
- }
-}
-
-void top::statusCB(Widget,XtPointer data)
-{
- XmPushButtonCallbackStruct* cb = (XmPushButtonCallbackStruct*)data;
- host::status((cb->event->xbutton.state & ShiftMask) != 0);
-}
-
-void top::windowCB(Widget w,XtPointer data)
-{
- XmPushButtonCallbackStruct *cb = (XmPushButtonCallbackStruct *) data;
-
- panel_window::new_window
- (selection::current_node(),
- XtName(w),
- (cb->event->xbutton.state & ShiftMask) != 0,
- (cb->event->xbutton.state & ShiftMask) != 0
- );
-}
-
-void top::showCB(Widget w,XtPointer data)
-{
- XmRowColumnCallbackStruct *cb = (XmRowColumnCallbackStruct *) data;
- show *s = (show*)xec_GetUserData(cb->widget);
- if(s && XmIsToggleButton(cb->widget)) {
- int flag = s->flag();
- if (((flag == show::none) | (flag == show::all))) {
- s->off();
- set_show(show0_, flag); set_show(show1_, flag);
- set_show(show2_, flag); set_show(show3_, flag);
- XmToggleButtonSetState(cb->widget,false,False);
- } else if (XmToggleButtonGetState(cb->widget))
- s->on();
- else
- s->off();
- tree::update_all(true);
- }
-}
-
-void top::chatCB(Widget w,XtPointer)
-{
- host::chat();
-}
-
-void top::windowsCB(Widget,XtPointer data)
-{
- XmRowColumnCallbackStruct *cb = (XmRowColumnCallbackStruct *) data;
- window *w = (window*) xec_GetUserData (cb->widget);
- w->raise();
-}
-
-void top::searchCB(Widget w,XtPointer)
-{
- search::show();
-}
-
-void top::releaseCB(Widget w,XtPointer)
-{
- std::string version = "version " + ecf::Version::raw();
- gui::message(version.c_str());
- char cmd[1024];
- snprintf(cmd, 1024, "${ECFLOWVIEW_HELP:=firefox --new-tab %s}\n", urlRef);
- // snprintf(cmd, 1024, "%s %s\n", browserName, urlRef);
- std::cerr << "#INF: " << cmd;
- if (system(cmd)) { std::cerr << "#ERR release\n"; }
- // execlp(browserName, urlRef, NULL);
- sleep (1);
-}
-
-void top::helpCB(Widget w,XtPointer)
-{
- const char *link="http://intra.ecmwf.int/metapps/manuals/ecflow/index.html";
- // const char *jira="http://software.ecmwf.int/issues/browse/ECFLOW";
- // const char *link="http://wedit.ecmwf.int/publications/manuals/ecFlow";
- char cmd[1024];
-
- gui::message("ecFlowView help (ECFLOWVIEW_HELP); press button\n");
- snprintf(cmd, 1024, "${ECFLOWVIEW_HELP:=firefox --new-tab %s}\n", link);
- std::cerr << "#INF: " << cmd;
-
- if (1) {
- if (system(cmd)) { std::cerr << "#ERR system\n"; }
- } else {
- FILE* f = popen(cmd,"r");
- if(!f) {
- gui::error("Cannot access : %s", link);
- return;
- } else if (!pclose(f)) {
- } else {
- gui::error("Cannot access : %s", link);
- return;
- }
- }
-}
-
-void top::prefCB(Widget w,XtPointer)
-{
- pref_window::show();
-}
-
-void top::loginCB(Widget w,XtPointer)
-{
- static str s;
- if(ask::show(s,"Login to (host [port]): ")) {
- char h[80] = { 0 };
- int n = 3141;
- sscanf(s.c_str(),"%s %d",h,&n);
- if (h[0] != 0)
- host::login(h,n);
- }
-}
-
-void top::error(const char* msg)
-{
- error::show(msg);
-}
diff --git a/ecflow_4_0_7/view/src/top.h b/ecflow_4_0_7/view/src/top.h
deleted file mode 100644
index 13ad50c..0000000
--- a/ecflow_4_0_7/view/src/top.h
+++ /dev/null
@@ -1,72 +0,0 @@
-#ifndef top_H
-#define top_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "uitop.h"
-#include "timeout.h"
-#include "interface.h"
-
-class top : public top_shell_c, public timeout, public interface {
-public:
-
- top();
- ~top(); // Change to virtual if base class
-
- virtual void create (Display *display, char *app_name,
- int app_argc, char **app_argv,
- char *app_class_name = NULL);
-
- virtual void run();
-
- virtual void clear();
- virtual void message(const char*);
- virtual void watch(Boolean);
-
- virtual void add_host(const std::string&);
- virtual void remove_host(const std::string&);
- virtual void rename_host(const std::string&,const std::string&) {}
-
- virtual void login(const char*);
- virtual void logout(const char*);
-
- virtual Widget top_shell();
- virtual Widget trees();
- virtual Widget windows();
-
- virtual void error(const char*);
-private:
-
- top(const top&);
- top& operator=(const top&);
-
- virtual void quitCB(Widget,XtPointer);
- virtual void serverCB(Widget,XtPointer);
- virtual void statusCB(Widget,XtPointer);
- virtual void windowCB(Widget,XtPointer);
- virtual void showCB(Widget,XtPointer);
- virtual void chatCB(Widget,XtPointer);
- virtual void windowsCB(Widget,XtPointer);
- virtual void searchCB(Widget,XtPointer);
- virtual void helpCB(Widget,XtPointer);
- virtual void prefCB(Widget,XtPointer);
- virtual void loginCB(Widget,XtPointer);
- virtual void releaseCB(Widget,XtPointer);
- virtual void snapshotCB(Widget,XtPointer);
-};
-
-inline void destroy(top**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/translator.cc b/ecflow_4_0_7/view/src/translator.cc
deleted file mode 100644
index c4a106f..0000000
--- a/ecflow_4_0_7/view/src/translator.cc
+++ /dev/null
@@ -1,211 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#ifndef translator_H
-#include "translator.h"
-#endif
-
-#ifndef str_H
-#include "str.h"
-#endif
-
-#ifndef choice_H
-#include "choice.h"
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string>
-
-str translator<int,str>::operator()(int n)
-{
- char buf[80];
- sprintf(buf,"%d",n);
- return str(buf);
-}
-
-const str& translator<str,str>::operator()(const str& x)
-{
- return x;
-}
-
-int translator<str,int>::operator()(const str& x)
-{
- return atol(x.c_str());
-}
-
-str translator<long long int,str>::operator()(long long int n)
-{
- char buf[80];
- sprintf(buf,"%lld",n);
- return str(buf);
-}
-
-long long int translator<str,long long int>::operator()(const str& x)
-{
- return atoll(x.c_str());
-}
-
-str translator<uint64_t,str>::operator()(uint64_t n)
-{
- char buf[80];
- sprintf(buf,"%ld",n);
- return str(buf);
-}
-
-uint64_t translator<str,uint64_t>::operator()(const str& x)
-{
- return atoll(x.c_str());
-}
-
-#ifdef WITH_INT128
-str translator<uint128,str>::operator()(uint128 n)
-{
- char buf[80];
- sprintf(buf,"%lld",n);
- return str(buf);
-}
-
-uint128 translator<str,uint128>::operator()(const str& x)
-{
- return atoll(x.c_str());
-}
-#endif
-
-str translator<ULL,str>::operator()(ULL n)
-{
- char buf[80];
- sprintf(buf,"%ulld",n);
- return str(buf);
-}
-ULL translator<str,ULL>::operator()(const str& x)
-{
- return atoll(x.c_str());
-}
-
-
-const str& translator<bool,str>::operator()(bool n)
-{
- static str t("true");
- static str f("false");
-
- return n ? t : f;
-}
-
-bool translator<str,bool>::operator()(const str& x)
-{
- char z = x.c_str()[0];
- return z == 't' || z == 'T' || z == '1';
-}
-
-ecf_list* translator<str,ecf_list*>::operator()(const str& x)
-{
- ecf_list* l = 0;
- const char* p = x.c_str();
- char word[1024];
- int i = 0;
-
- while(*p)
- {
- if(*p == ' ')
- {
- word[i] = 0;
- if(i) {
- ecf_list *z = ecf_node_create(word);
- z->next = l;
- l = z;
- }
- i = 0;
- }
- else {
- word[i++] = *p;
- }
- p++;
-
- }
-
- word[i] = 0;
- if(i) {
- ecf_list *z = ecf_node_create(word);
- z->next = l;
- l = z;
- }
- return l;
-}
-
-str translator<ecf_list*,str>::operator()(ecf_list* x)
-{
- str s;
- str space = " ";
- while(x)
- {
- s = s + str(x->name().c_str());
- if(x->next) s = s + space;
- x = x->next;
- }
- return s;
-}
-
-#define t_vs std::vector<std::string>
-t_vs translator<str,t_vs >::operator()(const str& x)
-{
- t_vs l;
- const char* p = x.c_str();
- char word[1024];
- int i = 0;
-
- while(*p) {
- if(*p == ' ') {
- word[i] = 0;
- if(i) {
- l.push_back(std::string(word));
- }
- i = 0;
- } else {
- word[i++] = *p;
- }
- p++;
- }
-
- word[i] = 0;
- if(i) {
- l.push_back(std::string(word));
- }
- return l;
-}
-
-// translator<str, std::vector<std::string> >::operator()(str const&)
-
-str translator<t_vs, str>::operator()(t_vs x)
-{
- str s, space = " ";
- t_vs::iterator j;
- for (j = x.begin(); j != x.end(); ++j) {
- s += str(j->c_str());
- if(j != x.end())
- s += space;
- }
- return s;
-}
-
-str translator<choice,str>::operator()(const choice& n)
-{
- return translator<int,str>()(n);
-}
-
-choice translator<str,choice>::operator()(const str& x)
-{
- return choice(atol(x.c_str()));
-}
diff --git a/ecflow_4_0_7/view/src/translator.h b/ecflow_4_0_7/view/src/translator.h
deleted file mode 100644
index ee1c92c..0000000
--- a/ecflow_4_0_7/view/src/translator.h
+++ /dev/null
@@ -1,114 +0,0 @@
-#ifndef translator_H
-#define translator_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include <vector>
-// #include <inttypes.h>
-
-#ifdef NO_BOOL
-#include "bool.h"
-#endif
-#include "ecflow.h"
-class str;
-class choice;
-#include "gen_translator.h"
-
-template<> class translator<str,str> {
-public:
- const str& operator()(const str& x);
-};
-
-template<> class translator<str,bool> {
-public:
- bool operator()(const str&);
-};
-
-template<> class translator<bool,str> {
-public:
- const str& operator()(bool x);
-};
-
-template<> class translator<str,int> {
-public:
- int operator()(const str&);
-};
-
-template<> class translator<int,str> {
-public:
- str operator()(int x);
-};
-
-template<> class translator<str,long long int> {
-public:
- long long int operator()(const str&);
-};
-template<> class translator<long long int,str> {
-public:
- str operator()(long long int x);
-};
-
-// #define ULL long long
-// #define ULL uint64_t
-#define ULL unsigned int
-template<> class translator<str,ULL> {public: ULL operator()(const str&); };
-template<> class translator<ULL,str> {public: str operator()(ULL x); };
-
-template<> class translator<str,uint64_t> {
-public:
- uint64_t operator()(const str&);
-};
-template<> class translator<uint64_t,str> {
-public:
- str operator()(uint64_t x);
-};
-
-#ifdef WITH_INT128
-template<> class translator<uint128,str> {public: str operator()(uint128 x);};
-template<> class translator<str,uint128> {public: uint128 operator()(const str&); };
-#endif
-
-template<> class translator<str,std::vector<std::string> > {
-public:
- std::vector<std::string> operator()(const str&);
-};
-
-template<> class translator<std::vector<std::string> ,str> {
-public:
- str operator()(std::vector<std::string> );
-};
-
-template<> class translator<str,ecf_list*> {
-public:
- ecf_list* operator()(const str&);
-};
-
-template<> class translator<ecf_list*,str> {
-public:
- str operator()(ecf_list*);
-};
-
-template<> class translator<str,choice> {
-public:
- choice operator()(const str&);
-};
-
-template<> class translator<choice,str> {
-public:
- str operator()(const choice&);
-};
-
-#endif
diff --git a/ecflow_4_0_7/view/src/tree.cc b/ecflow_4_0_7/view/src/tree.cc
deleted file mode 100644
index ce4b942..0000000
--- a/ecflow_4_0_7/view/src/tree.cc
+++ /dev/null
@@ -1,340 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #11 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <stdio.h>
-
-#ifndef tree_H
-#include "tree.h"
-#endif
-
-#ifndef init_H
-#include "init.h"
-#endif
-
-#ifndef ecflowview_H
-#include "ecflowview.h"
-#endif
-
-#ifndef host_H
-#include "host.h"
-#endif
-
-#ifndef menus_H
-#include "menus.h"
-#endif
-
-#ifndef gui_H
-#include "gui.h"
-#endif
-
-#ifndef tmp_file_H
-#include "tmp_file.h"
-#endif
-#ifndef globals_H
-#include "globals.h"
-#endif
-
-#include "ecf_node.h"
-
-extern "C" {
-#include "xec.h"
-#include "SimpleTree.h"
-}
-
-#include <Xm/Frame.h>
-#include <Xm/Label.h>
-#include <Xm/RowColumn.h>
-
-
-//===========================================
-
-
-tree::tree(host* h):
- host_(h)
-{
- observe(h);
-
-#if 0
- XtAddCallback( tree, XmNhelpCallback, help_callback,
- (XtPointer) 0 );
-#endif
-
- tree_c::create(gui::trees(),(char*)h->name());
-
- add_input_CB();
-}
-
-tree::~tree()
-{
- XtDestroyWidget(tree_);
-}
-
-void tree::xd_show()
-{
- XtManageChild(tree_);
-}
-
-void tree::xd_hide()
-{
- XtUnmanageChild(tree_);
-}
-
-void tree::build_tree(node* n,int p)
-{
- while(n) {
- int w = n->getBox(tree_);
- NodeAddRelation(tree_,p,w);
- build_tree(n->kids(),w);
- n = n->next();
- }
-}
-
-int tree::count(node* n)
-{
- int c = 0;
- while(n)
- {
- c += count(n->kids()) + 1;
- n = n->next();
- }
- return c;
-}
-
-void tree::notification(observable* o)
-{
- host* h = (host*)o;
-
- NodeReset(tree_);
-
- NodeReserve(tree_,count(h->top()));
-
- build_tree(h->top(),-1);
-
- if (!h->top()) return;
- if (h->name() == selection::server()) {
- node* n = h->top()->find(selection::current_path());
- if(n) show_node(*n);
- }
- update_all(false);
-}
-
-void tree::selection_cleared()
-{
- XtSetSensitive(show_current_,False);
- XtSetSensitive(fold_around_,False);
- XtSetSensitive(hide_other_,False);
- node_window::selection_cleared();
-}
-
-void tree::new_selection(node& n)
-{
- XtSetSensitive(show_current_,True);
- XtSetSensitive(fold_around_,True);
- XtSetSensitive(hide_other_,True);
- node_window::new_selection(n);
-}
-
-tree* tree::new_tree(host* h)
-{
- if(gui::trees() == 0)
- return 0;
-
- Widget w = XtNameToWidget(gui::trees(),h->name());
- tree* t = 0;
-
- if(w == 0)
- t = new tree(h);
- else
- t = (tree*)xec_GetUserData(w);
-
- return t;
-}
-
-long tree::update_tree(node* n,bool visible)
-{
- long changes = 0;
-
- while(n) {
- Boolean vis = visible && ( n->visible() || n->show_it());
- Boolean old = n->visibility(vis);
-
- if(old != vis) changes++;
-
- changes += update_tree(n->kids(),vis && !n->folded());
-
- n = n->next();
- }
-
- return changes;
-}
-
-void tree::update_tree(bool redraw)
-{
- long changes = host_ ? update_tree(host_->top(),True) : 0;
- if(redraw) NodeNewSizeAll(tree_);
- if(changes) NodeUpdate(tree_);
-}
-
-void tree::fold_unfold_all(node *n,Boolean folding)
-{
- while(n) {
- n->folded(folding);
- // n->ondemand(false); // 20120705
- fold_unfold_all(n->kids(),folding);
- n = n->next();
- }
-}
-
-void tree::click2(node* n,Boolean shift,Boolean control)
-{
- if(!n) return;
-
- // n->ondemand(true); build_tree(n, -1); update_tree(true); // 20120705
-
- if (shift && control)
- fold_unfold_all(n,!n->folded());
- else if(shift) {
- tmp_file f = n->serv().host::output(*n);
- char buf[10240];
- const char *p = getenv("PAGER");
- const char *fname = f.c_str();
- if (!fname) return;
- sprintf(buf,"xterm -e %s %s&",p?p:"more",fname);
- system(buf);
- return;
- }
- else if(control)
- NodeTreeFlip(tree_,n->getBox(tree_));
- else n->folded(!n->folded());
-
- update_tree(false);
-}
-
-xnode* tree::xnode_of(node& n)
-{
- return &n;
-}
-
-void tree::show_node(node& n)
-{
- node* p = n.parent();
- while(p)
- {
- p->folded(False);
- // 201207 update_tree(true); // p->serv().redraw(); // 201107
- p = p->parent();
- }
- update_tree(false);
- n.select();
-}
-void tree::hideOtherCB( Widget w, XtPointer p )
-{
- node* n = selection::current_node();
- if(!n) return;
-
- if(n->serv().where() != this)
- n->serv().where()->hideOtherCB(w,p);
- else
- n->serv().suites(n);
-}
-
-void tree::snapshotCB( Widget w, XtPointer p )
-{
- char cmd[1024];
- FILE *f = 0;
-
- gui::message("using SNAPSHOT ; press button \n");
- sprintf(cmd,"${SNAPSHOT:=import} %s\n", snapshotName);
-
- f = popen(cmd,"r");
- if(!f) {
- gui::error("Cannot create snapshot : %s", cmd);
- return;
- } else if (!pclose(f)) {
- gui::message("%s # generated\n", snapshotName);
- sprintf(cmd,"${SNAPVISU:=firefox} %s\n", snapshotName);
- f = popen(cmd,"r");
- }
- else {
- gui::error("Cannot create snapshot : %s", cmd);
- return;
- }
-}
-
-void tree::aroundCB( Widget w, XtPointer p)
-{
- node* n = selection::current_node();
- if(!n) return;
-
- if(n->serv().where() != this)
- n->serv().where()->aroundCB(w,p);
- else
- {
- if (host_) fold_unfold_all(host_->top(),True);
- show_node(*n);
- fold_unfold_all(n,False);
- n->select();
- update_tree(false);
- }
-}
-
-void tree::foldCB( Widget, XtPointer )
-{
- if (host_) fold_unfold_all(host_->top(),True);
- update_tree(false);
-}
-
-void tree::unfoldCB( Widget, XtPointer )
-{
- if (host_) {
- fold_unfold_all(host_->top(),False);
- // 201207 build_tree(host_->top(), -1);
- }
- update_tree(true);
-}
-
-void tree::showCB( Widget, XtPointer )
-{
- node* n = selection::current_node();
- if(n) {
- tree* t = n->serv().where();
- t->show_node(*n);
- n->select();
- }
-}
-
-void tree::connected(Boolean ok)
-{
- if(ok) {
- XtVaSetValues(tree_,XmNbackgroundPixmap,XmUNSPECIFIED_PIXMAP,NULL);
- } else {
- Pixel fg,bg;
- XtVaGetValues(tree_,XmNforeground, &fg, XmNbackground, &bg,NULL);
- XtVaSetValues(tree_,XmNbackgroundPixmap,
- XmGetPixmap(XtScreen(tree_),"25_foreground",fg,bg),NULL);
- }
-}
-
-void tree::update_all(bool redraw)
-{
- tree *t = extent<tree>::first();
- while(t)
- {
- t->update_tree(redraw);
- t = t->extent<tree>::next();
- }
-}
-
-IMP(tree)
diff --git a/ecflow_4_0_7/view/src/tree.h b/ecflow_4_0_7/view/src/tree.h
deleted file mode 100644
index 8cb7bb2..0000000
--- a/ecflow_4_0_7/view/src/tree.h
+++ /dev/null
@@ -1,105 +0,0 @@
-#ifndef tree_H
-#define tree_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #8 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "uitop.h"
-
-#ifndef node_H
-#include "node.h"
-#endif
-
-#ifndef node_window_H
-#include "node_window.h"
-#endif
-
-#ifndef observer_H
-#include "observer.h"
-#endif
-
-#ifndef uitree_H
-#include "uitree.h"
-#endif
-
-#ifndef extent_H
-#include "extent.h"
-#endif
-
-class tree_node;
-
-class tree : public node_window
- , public tree_c
- , public extent<tree>
- , public observer {
- public:
- tree(host*);
-
- ~tree(); // Change to virtual if base class
-
- void xd_show();
- void xd_hide();
-
- void connected(Boolean);
- void update_tree(bool);
-
- virtual xnode* xnode_of(node& n);
-
- static tree* new_tree(host*);
- static void update_all(bool);
-
- virtual void click2(node*,Boolean,Boolean);
-private:
- // void ondemand(node&, bool full=false);
-
- tree(const tree&);
- tree& operator=(const tree&);
-
- host* host_;
-
- void build_tree(node*,int);
- int count(node*);
-
- void fold_unfold_all(node*,Boolean);
- long update_tree(node*,bool);
-
- // From node window
- virtual void show_node(node&);
-
- virtual Widget menu1() { return see_menu_; }
- virtual Widget menu2() { return why_menu_; }
-
- // From observer<host>
- void notification(observable*);
-
- void gone(observable*) {}
- void adoption(observable*,observable*) {}
-
- virtual void new_selection(node&);
- virtual void selection_cleared();
-
- Widget node_widget() { return tree_; }
-
- virtual void hideOtherCB( Widget, XtPointer );
- virtual void aroundCB( Widget, XtPointer );
- virtual void foldCB( Widget, XtPointer );
- virtual void unfoldCB( Widget, XtPointer );
- virtual void showCB( Widget, XtPointer );
-
- virtual void snapshotCB( Widget, XtPointer );
-};
-
-inline void destroy(tree**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/trigger_lister.h b/ecflow_4_0_7/view/src/trigger_lister.h
deleted file mode 100644
index 1953c66..0000000
--- a/ecflow_4_0_7/view/src/trigger_lister.h
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef trigger_lister_H
-#define trigger_lister_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-class trigger_lister {
-public:
-
- trigger_lister() {}
-
- enum { normal = 0, // Normal trigger_node
- parent = 1, // Through parent
- child = 2, // Through child
- hierarchy = 3 // Through child
- };
-
- virtual void next_node(node&, node*,int,node*) = 0;
- virtual Boolean parents() { return False; }
- virtual Boolean kids() { return False; }
- virtual Boolean self() { return True; }
-
-private:
- trigger_lister(const trigger_lister&);
- trigger_lister& operator=(const trigger_lister&);
-};
-
-inline void destroy(trigger_lister**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/trigger_node.cc b/ecflow_4_0_7/view/src/trigger_node.cc
deleted file mode 100644
index 54d3d05..0000000
--- a/ecflow_4_0_7/view/src/trigger_node.cc
+++ /dev/null
@@ -1,274 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #17 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "trigger_node.h"
-#include "ExprAst.hpp"
-// #include "text_lister.h"
-
-trigger_node::trigger_node(host& h,ecf_node* n)
- : node(h,n)
- , expression_ ("empty")
- , full_name_ ("empty")
- , complete_ (false)
-{
- if (!n) return;
- complete_ = (n->kind() == 'c');
- expression_ = n->toString();
- full_name_ = n->parent()->full_name();
- full_name_ += ":trigger";
-}
-
-const AstTop* trigger_node::get() const
-{
- if (!owner_) return 0x0;
- return dynamic_cast<ecf_concrete_node<ExpressionWrapper>*>
- (owner_)->get()->get_ast_top();
-}
-
-xmstring trigger_node::make_label_tree()
-{
- int inc = 0;
- if (expression_.size() > 9) {
- inc = complete_ ? 9 : 8;
- }
-#ifdef BRIDGE
- if (tree_) inc = 0;
-#endif
- return xmstring(expression_.c_str() + inc);
-}
-
-void trigger_node::drawNode(Widget w,XRectangle* r,bool tree)
-{
- XmStringDraw(XtDisplay(w),XtWindow(w),
- smallfont(),
- tree?labelTree():labelTrigger(),
- complete_?blueGC():blackGC(),
- r->x+2,
- r->y+2,
- r->width,
- XmALIGNMENT_BEGINNING, XmSTRING_DIRECTION_L_TO_R, NULL);
-
- shadow(w,r);
-}
-
-void trigger_node::info(std::ostream& f)
-{
- const AstTop *ast = get();
- if (ast) {
- std::string str = ast->expression(true);
- f << str << "\n";
- }
-}
-
-// const std::string& trigger_node::definition() const { return expression_; }
-
-const std::string& trigger_node::name() const
-{
- static std::string trigger_ = "trigger";
- return trigger_;
-}
-
-void trigger_node::perlify(FILE* f)
-{
- perl_member(f, "math", expression_.c_str());
-}
-
-#ifdef BRIDGE
-#define K_NIL 0
-#define K_OR 1
-#define K_AND 2
-#define K_EQ 3
-#define K_NE 4
-#define K_LT 5
-#define K_LE 6
-#define K_GT 7
-#define K_GE 8
-#define K_ADD 9
-#define K_SUB 10
-#define K_MUL 11
-#define K_DIV 12
-#define K_MOD 13
-#define K_POW 14
-#define K_NOT 15
-#define K_UNARY 16
-#define K_OPEN 17
-#define K_CLOSE 18
-#define K_NAME 19
-#define K_PRECEDENCE 9
-
-static std::string buf;
-
-inline void add(char* s,char* p,Boolean done)
-{
- strcat(s,p);
-}
-
-static bool match_math(const Ast *m, sms_tree *t, const char* n)
-{
- if (m) return m->evaluate();
- else if (t) {
- if (t->mtype == K_NAME) return strstr(t->name, n) != 0;
- return match_math(0, t->left, n) || match_math(0, t->right, n);
- }
- return false;
-}
-
-bool trigger_node::match(const char* n)
-{
- return match_math(get(),(sms_tree*)tree_, n);
-}
-
-static void print_math(char* s,sms_tree *m,Boolean done)
-{
- if(!m) return;
-
- if(m->mtype == K_NAME) {
- add(s,m->name,done);
- return;
- }
-
- switch(m->mtype) {
-
- case K_NAME:
- add(s,m->name,done);
- break;
-
- case K_OR :
- print_math(s,m->left,done);
- add(s,(char*)" or ",done);
- print_math(s,m->right,done);
- break;
-
- case K_AND :
- print_math(s,m->left,done);
- add(s,(char*)" and ",done);
- print_math(s,m->right,done);
- break;
-
- case K_EQ :
- print_math(s,m->left,done);
- add(s,(char*)" == ",done);
- print_math(s,m->right,done);
- break;
-
- case K_NE :
- print_math(s,m->left,done);
- add(s,(char*)" != ",done);
- print_math(s,m->right,done);
- break;
-
- case K_LT :
- print_math(s,m->left,done);
- add(s,(char*)" < ",done);
- print_math(s,m->right,done);
- break;
-
- case K_LE :
- print_math(s,m->left,done);
- add(s,(char*)" <= ",done);
- print_math(s,m->right,done);
- break;
-
- case K_GT :
- print_math(s,m->left,done);
- add(s,(char*)" > ",done);
- print_math(s,m->right,done);
- break;
-
- case K_GE :
- print_math(s,m->left,done);
- add(s,(char*)" >= ",done);
- print_math(s,m->right,done);
- break;
-
- case K_ADD :
- print_math(s,m->left,done);
- add(s,(char*)" + ",done);
- print_math(s,m->right,done);
- break;
-
- case K_SUB :
- print_math(s,m->left,done);
- add(s,(char*)" - ",done);
- print_math(s,m->right,done);
- break;
-
- case K_MUL :
- print_math(s,m->left,done);
- add(s,(char*)" * ",done);
- print_math(s,m->right,done);
- break;
-
- case K_DIV :
- print_math(s,m->left,done);
- add(s,(char*)" / ",done);
- print_math(s,m->right,done);
- break;
-
- case K_MOD :
- print_math(s,m->left,done);
- add(s,(char*)" % ",done);
- print_math(s,m->right,done);
- break;
-
- case K_POW :
- print_math(s,m->left,done);
- add(s,(char*)" ** ",done);
- print_math(s,m->right,done);
- break;
-
- case K_NOT :
- add(s,(char*)"not ",done);
- print_math(s,m->right,done);
- break;
-
- case K_UNARY:
- add(s,(char*)"- ",done);
- print_math(s,m->right,done);
- break;
-
- case K_OPEN :
- add(s,(char*)"(",done);
- print_math(s,m->right,done);
- add(s,(char*)")",done);
- break;
-
- default :
- add(s,(char*)"--\?\?\?--",done);
- break;
- }
-}
-
-extern "C" {
-#define new _new
-#define delete _delete
-#include "smsproto.h"
-}
-
-trigger_node::trigger_node(host& h,sms_node* n, char b)
- : node(h,n,b)
- , expression_ ()
- , complete_ (b == 'c')
-{
- char buf[10240] = { 0 };
- sms_trigger* trg = (sms_trigger*) n;
- if (!trg) return;
- tree_ = (sms_node*) trg->math;
- print_math(buf, (sms_tree*) trg->math, False);
- expression_ = buf;
- full_name_ = sms_node_full_name(n->parent);
- full_name_ += ":trigger";
-}
-#endif
diff --git a/ecflow_4_0_7/view/src/trigger_node.h b/ecflow_4_0_7/view/src/trigger_node.h
deleted file mode 100644
index 70ae70e..0000000
--- a/ecflow_4_0_7/view/src/trigger_node.h
+++ /dev/null
@@ -1,59 +0,0 @@
-#ifndef TRIGGER_NODE_H
-#define TRIGGER_NODE_H
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #13 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-
-#include "node.h"
-#include "show.h"
-
-#ifndef ecf_node_
-#include "ecf_node.h"
-#endif
-
-class trigger_node : public node {
- std::string expression_;
- std::string full_name_;
- bool complete_;
-
- const AstTop* get() const;
-
- virtual xmstring make_label_tree();
- void drawNode(Widget w,XRectangle* r,bool);
-
- virtual const std::string& name() const;
- virtual const std::string& full_name() const { return full_name_; }
- virtual const std::string& definition() const { return expression_; }
- virtual Boolean menus() { return False; }
- virtual Boolean selectable() { return True; }
-
- virtual Boolean visible() const { return show::want(show::trigger); }
-
- virtual void triggered(trigger_lister&) {}
- virtual void triggers(trigger_lister&) {}
- virtual void perlify(FILE*);
-
-public:
- trigger_node(host& h,ecf_node* n);
- ~trigger_node() {}
-
- virtual void info(std::ostream&);
-
-#ifdef BRIDGE
- virtual bool match(const char*);
- trigger_node(host& h,sms_node* n, char b);
-#endif
-};
-#endif
diff --git a/ecflow_4_0_7/view/src/trigger_panel.cc b/ecflow_4_0_7/view/src/trigger_panel.cc
deleted file mode 100644
index fb63b90..0000000
--- a/ecflow_4_0_7/view/src/trigger_panel.cc
+++ /dev/null
@@ -1,160 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "trigger_panel.h"
-#include "node.h"
-#include "graph_layout.h"
-#include "text_layout.h"
-#include "selection.h"
-#include "Hyper.h"
-#include <Xm/ToggleB.h>
-
-extern "C" {
-#include "xec.h"
-}
-
-trigger_panel::trigger_panel(panel_window& w):
- panel(w),
- full_(True),
- triggers_(True),
- triggered_(True),
- depend_(False),
- layout_(0)
-{
-}
-
-trigger_panel::~trigger_panel()
-{
- delete (layout*)xec_GetUserData(tgraph_);
- delete (layout*)xec_GetUserData(ttext_);
-}
-
-void trigger_panel::create(Widget parent, char *widget_name )
-{
- triggers_form_c::create(parent,widget_name);
- xec_SetUserData(tgraph_,layout_ = new graph_layout(*this,graph_));
- xec_SetUserData(ttext_,new text_layout(*this,text_));
-}
-
-void trigger_panel::clear()
-{
- layout_->clear();
- hide();
-}
-
-void trigger_panel::show(node& n)
-{
- layout_->show(n);
-}
-
-Boolean trigger_panel::enabled(node& n)
-{
- return True;
-}
-
-Widget trigger_panel::menus(Widget bar)
-{
- if(triggers_menu_c::xd_rootwidget() == 0)
- triggers_menu_c::create(bar,(char*)name());
- return triggers_menu_c::xd_rootwidget();
-}
-
-void trigger_panel::fullCB( Widget, XtPointer data)
-{
- XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct*) data;
- full_ = cb->set;
- update();
-}
-
-void trigger_panel::triggeredCB( Widget, XtPointer data)
-{
- XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct*) data;
- triggered_ = cb->set;
- update();
-}
-
-void trigger_panel::triggersCB( Widget, XtPointer data)
-{
- XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct*) data;
- triggers_ = cb->set;
- update();
-}
-
-void trigger_panel::dependCB( Widget, XtPointer data)
-{
- XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct*) data;
- depend_ = cb->set;
- clear();
- update();
-}
-
-void trigger_panel::entryCB(Widget, XtPointer data)
-{
- XmRowColumnCallbackStruct* cb = (XmRowColumnCallbackStruct*)data;
-
- if(XmToggleButtonGetState(cb->widget))
- {
- layout *l = (layout*)xec_GetUserData(cb->widget);
- XtUnmanageChild(layout_->layout_widget());
- XtManageChild(l->layout_widget());
- layout_ = l;
- if(get_node())
- l->show(*get_node());
- else
- l->clear();
- }
- hide();
-}
-
-void trigger_panel::hyperCB(Widget w,XtPointer data)
-{
- panel::hyper(w,data);
-}
-
-void trigger_panel::reachCB(Widget w,XtPointer data)
-{
- XmToggleButtonSetState(dependencies_button_,True,False);
- XmToggleButtonSetState(triggers_button_,True,False);
- XmToggleButtonSetState(triggered_button_,True,False);
-
- depend_ = triggers_ = triggered_ = true;
- clear();
- layout_->reach(get_node(),selection::current_node());
-}
-
-void trigger_panel::linkCB(Widget w,XtPointer data)
-{
- XmRowColumnCallbackStruct* cb = (XmRowColumnCallbackStruct*)data;
- node* n = (node*)xec_GetUserData(cb->widget);
- layout_->selectNode(n);
-}
-
-void trigger_panel::showDependWindow()
-{
- depend::raise(widget());
-}
-
-Widget trigger_panel::dependHyperText()
-{
- depend::make(widget());
- return depend::hyper_;
-}
-
-void trigger_panel::hideDependWindow()
-{
- depend::hide();
-}
-
-// static panel_maker<trigger_panel> maker(PANEL_TRIGGER);
diff --git a/ecflow_4_0_7/view/src/trigger_panel.h b/ecflow_4_0_7/view/src/trigger_panel.h
deleted file mode 100644
index fd11fb0..0000000
--- a/ecflow_4_0_7/view/src/trigger_panel.h
+++ /dev/null
@@ -1,85 +0,0 @@
-#ifndef trigger_panel_H
-#define trigger_panel_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "uitriggers.h"
-
-#ifndef panel_H
-#include "panel.h"
-#endif
-
-#ifndef node_window_H
-#include "node_window.h"
-#endif
-
-#ifndef depend_H
-#include "depend.h"
-#endif
-
-class layout;
-
-class trigger_panel : public panel,
- public depend,
- public triggers_form_c ,
- public triggers_menu_c {
-public:
- trigger_panel(panel_window&);
-
- ~trigger_panel(); // Change to virtual if base class
-
- virtual void create (Widget parent, char *widget_name = NULL);
- virtual void show(node&);
- virtual Boolean enabled(node&);
- virtual void clear();
- virtual const char* name() const { return "Triggers"; }
- Widget menus(Widget);
- virtual Widget widget() { return triggers_form_c::xd_rootwidget(); }
-
- Boolean triggers() { return triggers_; }
- Boolean triggered() { return triggered_; }
- Boolean extended() { return depend_; }
-
- Widget infoMenu() { return info_menu_; }
- Widget linkMenu() { return link_menu_; }
-
- void showDependWindow();
- void hideDependWindow();
- Widget dependHyperText();
-
-private:
-
- trigger_panel(const trigger_panel&);
- trigger_panel& operator=(const trigger_panel&);
-
- Boolean full_;
- Boolean triggers_;
- Boolean triggered_;
- Boolean depend_;
- layout* layout_;
-
- virtual void fullCB( Widget, XtPointer );
- virtual void triggeredCB( Widget, XtPointer );
- virtual void triggersCB( Widget, XtPointer );
- virtual void dependCB( Widget, XtPointer );
- virtual void entryCB( Widget, XtPointer );
- virtual void hyperCB( Widget, XtPointer );
- virtual void reachCB( Widget, XtPointer );
-
- virtual void linkCB( Widget, XtPointer );
-};
-
-inline void destroy(trigger_panel**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/url.cc b/ecflow_4_0_7/view/src/url.cc
deleted file mode 100644
index e50108b..0000000
--- a/ecflow_4_0_7/view/src/url.cc
+++ /dev/null
@@ -1,240 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "url.h"
-#include "re.h"
-#include "tmp_file.h"
-#include "str.h"
-#include "node.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-url::url(int soc):
- soc_(soc),
- code_(200),
- in_(fdopen(soc_,"r")),
- out_(fdopen(soc_,"w")),
- tmp_(tmpfile())
-{
- char line[1024];
- method_[0] = what_[0] = 0;
-
- while(fgets(line,sizeof(line),in_))
- {
- if(method_[0] == 0)
- sscanf(line,"%s %s",method_,what_);
- printf("url->%s<-",line);
- if(strlen(line) == 2) break;
- }
-
- char *p = what_;
- char *s = what_;
-
- while(*s)
- {
- if(*s == '+')
- {
- *p = ' ';
- }
- else if(*s == '%')
- {
- char h = s[1]; if(!h) break;
- char l = s[2]; if(!l) break;
-
- unsigned int a = (h>='A')?(h-'A'+10):(h-'0');
- unsigned int b = (l>='A')?(l-'A'+10):(l-'0');
-
- *p = char(a * 16 + b);
- s += 2;
- }
- else *p = *s;
-
- p++;
- s++;
- }
- *p = 0;
-}
-
-void url::process(node* n)
-{
- if (! node::is_json) {
-
- fprintf(out_,"\nHTTP/1.0 %d Document follows\r\n",code_);
- fprintf(out_,"MIME-Version: 1.0\r\n");
- fprintf(out_,"Content-Type: text/html\r\n");
- fprintf(out_,"\r\n");
-
- if(n) {
- n->as_perl(out_,true);
- } else
- fprintf(out_,"bless({},'ecflow::node::error')");
- } else {
- if (n) {
- n->as_perl(out_,true);
- } else
- fprintf(out_,"{ }");
- }
-
- fflush(out_);
-}
-
-url::~url()
-{
-
- fflush(tmp_);
- long len = ftell(tmp_);
- rewind(tmp_);
-
- if (!node::is_json) {
- fprintf(out_,"\n");
- fprintf(out_,"HTTP/1.0 %d Document follows\r\n",code_);
- fprintf(out_,"MIME-Version: 1.0\r\n");
- fprintf(out_,"Content-Type: text/html\r\n");
- fprintf(out_,"Content-Length: %ld\r\n",len);
- fprintf(out_,"\r\n");
- }
- copy(tmp_,out_);
-
- fflush(out_);
-
- if(in_) fclose(in_);
- if(out_) fclose(out_);
- if(tmp_) fclose(tmp_);
-}
-
-
-void url::add(tmp_file& t,text_translator& trans)
-{
- FILE* f = fopen(t.c_str(),"r");
- if(f)
- {
- char line[1024];
- while(fgets(line,sizeof(line),f))
- trans.save(tmp_,line);
- fclose(f);
- }
- else {
- fprintf(tmp_,"Cannot open %s\n",t.c_str());
- }
-}
-
-void url::add(tmp_file& t)
-{
- url_translator trans;
- add(t,trans);
-}
-
-void url::copy(FILE* in,FILE* out)
-{
- char line[1024];
- long len;
-
- while( (len = fread(line,1,sizeof(line),in)) > 0)
- fwrite(line,1,len,out);
-}
-
-void url_translator::save(FILE* f,const char* p)
-{
- while(*p)
- {
- switch(*p)
- {
- /* case '\n': fprintf(f,"<br>\n"); break; */
-
- case '<': fprintf(f,"<"); break;
- case '>': fprintf(f,">"); break;
- case '&': fprintf(f,"&"); break;
-
- default: fputc(*p,f); break;
- }
-
- p++;
-
- }
-}
-
-class scan_translator: public text_translator {
- re re_;
- node* n_;
- url& u_;
-public:
- scan_translator(node* n,url& u);
- ~scan_translator();
-
- virtual void save(FILE*,const char *line);
-};
-
-scan_translator::scan_translator(node* n,url& u):
- re_("<!-- wcdp ([^ ]*)$0 -->"),
- n_(n),
- u_(u)
-{
-}
-
-scan_translator::~scan_translator()
-{
-}
-
-void scan_translator::save(FILE* f,const char *line)
-{
- char val[1024];
- char buf[1024];
-
- strcpy(buf,line);
- char *p = buf;
- char *q;
-
- while((q = re_.match(p,val)))
- {
- char *loc = re_.loc();
- char w = *loc;
- *loc = 0;
- fprintf(f,"%s",buf);
- *loc = w;
-
- // We need a factory here
-
- if(strcmp(val,"title") == 0) n_->html_title(u_,u_);
- if(strcmp(val,"kids") == 0) n_->html_kids(u_,u_);
- if(strcmp(val,"output") == 0) n_->html_output(u_,u_);
- if(strcmp(val,"script") == 0) n_->html_script(u_,u_);
- if(strcmp(val,"name") == 0) n_->html_name(u_,u_);
- if(strcmp(val,"why") == 0) n_->html_why(u_,u_);
-
-
- p = q;
- }
- fprintf(f,"%s",p);
-}
-
-void url::scan(node* n)
-{
- tmp_file page(n->html_page(*this),false);
- scan_translator s(n,*this);
- add(page,s);
-}
-
-
-/*
-perl -e'print q|{"foo":"XX","bar":1234567890000000000000000}|' |\
- json_pp -f json -t dumper -json_opt pretty,utf8,allow_bignum
-
-wget http://127.0.0.1:8081/lhost/elaw_37r3
-cat elaw_37r3 | grep -v -E '(HTTP|MIME|Content-)' | json_pp -f eval -t json -json_opt pretty,utf8,allow_bignum
-
-/tmp/map/work/PythonWeb.org/examples/ecflow
-
-*/
diff --git a/ecflow_4_0_7/view/src/url.h b/ecflow_4_0_7/view/src/url.h
deleted file mode 100644
index dda6f6b..0000000
--- a/ecflow_4_0_7/view/src/url.h
+++ /dev/null
@@ -1,142 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#ifndef url_H
-#define url_H
-
-#include <stdio.h>
-class tmp_file;
-class node;
-
-class text_translator {
-public:
- virtual ~text_translator() {}
- virtual void save(FILE*,const char*) = 0;
-};
-
-class url_translator: public text_translator {
-public:
- virtual void save(FILE*,const char*);
-};
-
-class url {
-public:
-
-// -- Exceptions
- // None
-
-// -- Contructors
-
- url(int);
-
-// -- Destructor
-
- ~url(); // Change to virtual if base class
-
-// -- Convertors
- // None
-
-// -- Operators
-
- operator FILE*() { return tmp_; }
-
-// -- Methods
-
- void process(node*);
- void scan(node*);
-
- const char* method() const { return method_; }
- const char* what() const { return what_; }
-
- void not_found() { code_ = 404; }
-
- void add(tmp_file&);
- void add(tmp_file&,text_translator&);
- void copy(FILE*,FILE*);
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
- // Uncomment for persistent, remove otherwise
- // static os_typespec* get_os_typespec();
-
-protected:
-
-// -- Members
- // None
-
-// -- Methods
-
- // void print(ostream&) const; // Change to virtual if base class
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-private:
-
-// No copy allowed
-
- url(const url&);
- url& operator=(const url&);
-
-// -- Members
-
- char method_[1024];
- char what_[1024];
- int soc_;
- int code_;
- FILE* in_;
- FILE* out_;
- FILE* tmp_;
-
-// -- Methods
- // None
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-// -- Friends
-
- //friend ostream& operator<<(ostream& s,const url& p)
- // { p.print(s); return s; }
-
-};
-
-inline void destroy(url**) {}
-
-// If persistent, uncomment, otherwise remove
-//#ifdef _ODI_OSSG_
-//OS_MARK_SCHEMA_TYPE(url);
-//#endif
-
-#endif
diff --git a/ecflow_4_0_7/view/src/user_prefs.cc b/ecflow_4_0_7/view/src/user_prefs.cc
deleted file mode 100644
index a03e7ae..0000000
--- a/ecflow_4_0_7/view/src/user_prefs.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "user_prefs.h"
-
-void user_prefs::create(Widget w,char*)
-{
- user_form_c::create(w);
- prefs::setup(w);
-}
-
-// static user_prefs hp;
diff --git a/ecflow_4_0_7/view/src/user_prefs.h b/ecflow_4_0_7/view/src/user_prefs.h
deleted file mode 100644
index eacf05c..0000000
--- a/ecflow_4_0_7/view/src/user_prefs.h
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef user_prefs_H
-#define user_prefs_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#ifndef prefs_H
-#include "prefs.h"
-#endif
-
-#ifndef uiuser
-#include "uiuser.h"
-#endif
-
-
-class user_prefs : public prefs, public user_form_c {
-public:
-
- user_prefs() {}
-
- ~user_prefs() {}
-
- virtual Widget widget() { return _xd_rootwidget; }
-
-private:
-
- user_prefs(const user_prefs&);
- user_prefs& operator=(const user_prefs&);
-
- virtual void changedCB( Widget w, XtPointer ) { pref_editor::changed(w); }
- virtual void useCB( Widget w, XtPointer ) { pref_editor::use(w); }
-
- virtual void create(Widget w,char*);
-};
-
-inline void destroy(user_prefs**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/users.cc b/ecflow_4_0_7/view/src/users.cc
deleted file mode 100644
index b99fb1b..0000000
--- a/ecflow_4_0_7/view/src/users.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "users.h"
-#include "node.h"
-#include "host.h"
-#include "ecflowview.h"
-#include <Xm/Label.h>
-#include <Xm/Text.h>
-#include <Xm/List.h>
-extern "C" {
-#include "xec.h"
-}
-
-users::users(panel_window& w):
- panel(w)
-{
-}
-
-users::~users()
-{
-}
-
-void users::create (Widget parent, char *widget_name )
-{
- users_form_c::create(parent,widget_name);
-}
-
-void users::clear()
-{
- XmListDeleteAllItems(list_);
-}
-
-void users::show(node& n)
-{
- XmListDeleteAllItems(list_);
-}
-
-Boolean users::enabled(node& n)
-{
- return False;
- // return n.type() == NODE_SUPER;
-}
-
-
-void users::sendCB( Widget, XtPointer )
-{
-}
-
-// static panel_maker<users> maker(PANEL_USERS);
diff --git a/ecflow_4_0_7/view/src/users.h b/ecflow_4_0_7/view/src/users.h
deleted file mode 100644
index 3994161..0000000
--- a/ecflow_4_0_7/view/src/users.h
+++ /dev/null
@@ -1,136 +0,0 @@
-#ifndef users_H
-#define users_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-// Headers
-// #ifndef machine_H
-// #include <machine.h>
-// #endif
-
-// Forward declarations
-
-// class ostream;
-// typedef class _Pvts os_typespec; // Remove if not persistant
-
-
-#include "uiusers.h"
-
-#ifndef panel_H
-#include "panel.h"
-#endif
-
-//
-
-class users : public panel, public users_form_c {
-public:
-
-// -- Exceptions
- // None
-
-// -- Contructors
-
- users(panel_window&);
-
-// -- Destructor
-
- ~users(); // Change to virtual if base class
-
-// -- Convertors
- // None
-
-// -- Operators
- // None
-
-// -- Methods
- // None
-
-// -- Overridden methods
-
- virtual const char* name() const { return "Users"; }
- virtual void show(node&);
- virtual void clear();
- virtual Boolean enabled(node&);
- virtual Widget widget() { return users_form_c::xd_rootwidget(); }
-
- virtual void create (Widget parent, char *widget_name = NULL);
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
- // Uncomment for persistent, remove otherwise
- // static os_typespec* get_os_typespec();
-
-protected:
-
-// -- Members
- // None
-
-// -- Methods
-
- // void print(ostream&) const; // Change to virtual if base class
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-private:
-
-// No copy allowed
-
- users(const users&);
- users& operator=(const users&);
-
-// -- Members
-
-
-// -- Methods
- // None
-
-// -- Overridden methods
-
- virtual void sendCB( Widget, XtPointer );
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-// -- Friends
-
- //friend ostream& operator<<(ostream& s,const users& p)
- // { p.print(s); return s; }
-
-};
-
-inline void destroy(users**) {}
-
-// If persistent, uncomment, otherwise remove
-//#ifdef _ODI_OSSG_
-//OS_MARK_SCHEMA_TYPE(users);
-//#endif
-
-
-#endif
diff --git a/ecflow_4_0_7/view/src/variable_node.cc b/ecflow_4_0_7/view/src/variable_node.cc
deleted file mode 100644
index 8d7556d..0000000
--- a/ecflow_4_0_7/view/src/variable_node.cc
+++ /dev/null
@@ -1,135 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #17 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "variable_node.h"
-
-#ifndef ecf_node_
-#include "ecf_node.h"
-#endif
-struct ecf_variable {
- int type;
- char *name;
- struct ecf_variable *next;
- int status;
- int nid;
- int act_no;
- class ecf_node *parent;
- void* user_ptr;
- int user_int;
- class ecf_node *kids;
- char *value;
-};
-typedef struct ecf_variable ecf_variable;
-
-const xmstring& variable_node::labelTree()
-{
- labelTree_ = make_label_tree();
- return labelTree_;
-}
-
-#ifdef BRIDGE
-variable_node::variable_node(host& h,sms_node* n, char b)
- : node(h,n,b)
- , generated_(b == 'g')
-{}
-#endif
-
-variable_node::variable_node(host& h,ecf_node* n)
- : node(h,n)
- , generated_(false)
-{
- generated_ = n ? (n->kind() == 'g') : false;
-}
-
-std::string variable_node::get_var(bool substitute) {
-#ifdef BRIDGE
- if (tree_) {
- ecf_variable *var = (ecf_variable*) tree_;
- if (var) return var->value;
- } else
-#endif
- if (parent())
- if (parent()->__node__())
- return parent()->__node__()->get_var(name(),
- generated_,
- substitute);
- return ecf_node::none();
-}
-
-xmstring variable_node::make_label_tree()
-{
- const std::string& v = get_var();
- return xmstring(name().c_str()) + xmstring("=") + xmstring(v.c_str());
-}
-
-void variable_node::drawNode(Widget w,XRectangle *r,bool)
-{
- XmStringDraw(XtDisplay(w),XtWindow(w),
- smallfont(),
- labelTree(),
- generated_?blueGC():blackGC(),
- r->x+2,
- r->y+2,
- r->width,
- XmALIGNMENT_BEGINNING, XmSTRING_DIRECTION_L_TO_R, NULL);
- /* shadow(w,r); */
-}
-
-Boolean variable_node::visible() const
-{
- return
- generated_ ?
- show::want(show::genvar) :
- show::want(show::variable);
-}
-
-void variable_node::info(std::ostream&f)
-{
- if (generated_)
- f << " # ( " << name() << "\t: " << get_var() + ")\n";
- else
- f << " edit " << name() << "\t" << get_var() << "\n";
-}
-
-bool variable_node::match(const char* p)
-{
- return (strstr(name().c_str(),p) != 0)
- || (strstr(get_var().c_str(),p) != 0);
-}
-
-void variable_node::edit(node_editor& e)
-{
- e.set("name", str(name()));
- e.set("value",str(get_var()));
-}
-
-void variable_node::apply(node_editor& e)
-{
- str value;
- e.get("value",value);
- const char* name = this->name().c_str();
- const char* kind = "add";
- for (node* n = parent()->kids(); n; n = n->next())
- if (n->type() == NODE_VARIABLE && n->name() == name)
- { kind = "change"; break; }
- serv().command(clientName,"--alter", kind, "variable",
- name, value.c_str(), parent()->full_name().c_str(),
- NULL);
-}
-
-void variable_node::perlify(FILE* f)
-{
- perl_member(f,"value",get_var().c_str());
-}
diff --git a/ecflow_4_0_7/view/src/variable_node.h b/ecflow_4_0_7/view/src/variable_node.h
deleted file mode 100644
index 28f5a6a..0000000
--- a/ecflow_4_0_7/view/src/variable_node.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef VARIABLE_NODE
-#define VARIABLE_NODE
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #12 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-
-#include "node.h"
-#include "show.h"
-#include "host.h"
-#include "node_editor.h"
-
-class variable_node : public node {
-
- bool generated_;
-
- virtual void info(std::ostream&);
- virtual const xmstring& labelTree();
- virtual xmstring make_label_tree();
- virtual void drawNode(Widget w,XRectangle *r,bool);
-
- virtual Boolean visible() const;
- virtual bool match(const char*);
-
- virtual void edit(node_editor&);
- virtual void apply(node_editor&);
-
- virtual void triggered(trigger_lister&) {}
- virtual void triggers(trigger_lister&) {}
-
- virtual void perlify(FILE*);
-
-public:
- variable_node(host& h,ecf_node* n);
- Boolean isGenVariable(const char *name) { return generated_; }
- std::string get_var(bool subsitute=false);
-#ifdef BRIDGE
- variable_node(host& h,sms_node* n, char b);
-#endif
-
-};
-
-#endif
diff --git a/ecflow_4_0_7/view/src/variables.cc b/ecflow_4_0_7/view/src/variables.cc
deleted file mode 100644
index 0dfc3a2..0000000
--- a/ecflow_4_0_7/view/src/variables.cc
+++ /dev/null
@@ -1,417 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #19 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "variables.h"
-#include "variable_node.h"
-#include "node.h"
-#include "host.h"
-#include "ecf_node.h"
-
-#include <Xm/List.h>
-#include <Xm/Text.h>
-#include "confirm.h"
-
-extern "C" {
-#include "xec.h"
-}
-
-variables::variables( panel_window& w )
- : panel(w), loading_(false)
-{
-}
-
-variables::~variables()
-{
- clear();
-}
-
-void variables::clear()
-{
- loading_ = true;
- XmListDeleteAllItems(list_);
- XtSetSensitive(edit_, False);
- XmTextSetString(name_, (char*) "");
- XmTextSetString(value_, (char*) "");
- loading_ = false;
-}
-
-struct cless_than {
- inline bool operator()( const Variable& v1, const Variable& v2 )
- {
- return (v1.name() < v2.name());
- }
-};
-
-void variables::show( node& n )
-{
- loading_ = true;
-
- int varsize = 0;
- int valsize = 0;
- char fmt1[256];
- char fmt2[256];
- node* m = &n;
-
- XtSetSensitive(edit_, True);
- XmListDeleteAllItems(list_);
- std::vector<Variable> gvar;
- std::vector<Variable>::const_iterator it, gvar_end;
- ecf_node* prox;
-
- while ( m != 0 ) {
- /* for (node* run = m->kids(); run; run = run->next())
- if (run->type() == NODE_VARIABLE) {
- varsize = std::max(varsize, (int) run->name().size());
- valsize = std::max(valsize, (int) ((variable_node*) run)->get_var().size());
- } */
- {
- prox = m->__node__();
- if (!prox) return;
-
- Defs* defs = 0;
- Node* ecf = 0;
- if (dynamic_cast<ecf_concrete_node<Node>*>(prox)) {
- ecf = dynamic_cast<ecf_concrete_node<Node>*>(prox)->get();
- }
- else if (dynamic_cast<ecf_concrete_node<Task>*>(prox)) {
- ecf = dynamic_cast<ecf_concrete_node<Task>*>(prox)->get();
- }
- else if (dynamic_cast<ecf_concrete_node<Family>*>(prox)) {
- ecf = dynamic_cast<ecf_concrete_node<Family>*>(prox)->get();
- }
- else if (dynamic_cast<ecf_concrete_node<Suite>*>(prox)) {
- ecf = dynamic_cast<ecf_concrete_node<Suite>*>(prox)->get();
- }
- else if (dynamic_cast<ecf_concrete_node<Defs>*>(prox)) {
- defs = dynamic_cast<ecf_concrete_node<Defs>*>(prox)->get();
- }
- if (!ecf && !defs) {
- break;
- }
-
- if (ecf ) {
- gvar.clear();
- ecf->gen_variables(gvar);
- for(it = gvar.begin(); it != gvar.end(); ++it) {
- varsize = std::max(varsize, (int) (*it).name().size());
- valsize = std::max(valsize, (int) (*it).theValue().size());
- }
-
- gvar = ecf->variables();
- for(it = gvar.begin(); it != gvar.end(); ++it) {
- varsize = std::max(varsize, (int) (*it).name().size());
- valsize = std::max(valsize, (int) (*it).theValue().size());
- }
- }
- if (defs) {
- const std::vector<Variable>& gvar = defs->server().user_variables();
- for(it = gvar.begin(); it != gvar.end(); ++it) {
- varsize = std::max(varsize, (int) (*it).name().size());
- valsize = std::max(valsize, (int) (*it).theValue().size());
- }
- const std::vector<Variable>& var = defs->server().server_variables();
- for(it = var.begin(); it != var.end(); ++it) {
- varsize = std::max(varsize, (int) (*it).name().size());
- valsize = std::max(valsize, (int) (*it).theValue().size());
- }
- }
- }
- m = m->parent();
- }
-
- if (!varsize) return;
- snprintf(fmt1, 256, "(%%-%ds = %%-%ds)", varsize, valsize);
- snprintf(fmt2, 256, " %%-%ds = %%-%ds ", varsize, valsize);
- {
- char buffer[1024];
- node *m = &n;
- while ( m != 0 ) {
- snprintf(buffer, 1024, "Variables defined for %s %s", m->type_name(), m->name().c_str());
- xec_AddFontListItem(list_, buffer, 1);
- {
- prox = m->__node__();
- if (!prox) break;
-
- Defs* defs = 0;
- Node* ecf = 0;
- if (dynamic_cast<ecf_concrete_node<Node>*>(prox)) {
- ecf = dynamic_cast<ecf_concrete_node<Node>*>(prox)->get();
- }
- else if (dynamic_cast<ecf_concrete_node<Task>*>(prox)) {
- ecf = dynamic_cast<ecf_concrete_node<Task>*>(prox)->get();
- }
- else if (dynamic_cast<ecf_concrete_node<Family>*>(prox)) {
- ecf = dynamic_cast<ecf_concrete_node<Family>*>(prox)->get();
- }
- else if (dynamic_cast<ecf_concrete_node<Suite>*>(prox)) {
- ecf = dynamic_cast<ecf_concrete_node<Suite>*>(prox)->get();
- }
- else if (dynamic_cast<ecf_concrete_node<Defs>*>(prox)) {
- defs = dynamic_cast<ecf_concrete_node<Defs>*>(prox)->get();
- }
- if (!ecf && !defs) break;
-
- if (ecf) {
- gvar.clear();
- ecf->gen_variables(gvar);
- for(it = gvar.begin(); it != gvar.end(); ++it) {
- if ((*it).name() == "" ||
- *it == Variable::EMPTY() ||
- (*it).name() == "ECF_PASS")
- continue;
- snprintf(buffer, 1024, fmt1, (*it).name().c_str(), (*it).theValue().c_str());
- xec_AddFontListItem(list_, buffer, 0);
- }
-
- gvar = ecf->variables();
- std::sort(gvar.begin(), gvar.end(), cless_than());
- gvar_end = gvar.end();
- for(it = gvar.begin(); it != gvar_end; ++it) {
- snprintf(buffer, 1024, fmt2, (*it).name().c_str(), (*it).theValue().c_str());
- xec_AddFontListItem(list_, buffer, 0);
- }
- }
- if (defs) {
- gvar = defs->server().server_variables();
- for(it = gvar.begin(); it != gvar.end(); ++it) {
- snprintf(buffer, 1024, fmt1, (*it).name().c_str(), (*it).theValue().c_str());
- xec_AddFontListItem(list_, buffer, 0);
- }
-
- gvar = defs->server().user_variables();
- std::sort(gvar.begin(), gvar.end(), cless_than());
- for(it = gvar.begin(); it != gvar.end(); ++it) {
- snprintf(buffer, 1024, fmt2, (*it).name().c_str(), (*it).theValue().c_str());
- xec_AddFontListItem(list_, buffer, 0);
- }
- }
- }
- m = m->parent();
- }
- }
- loading_ = false;
-}
-
-Boolean variables::enabled( node& n )
-{
- int type = n.type();
- if (type == NODE_SUPER || type == NODE_FAMILY || type == NODE_TASK || type == NODE_ALIAS) return True;
- for(node* run = n.kids(); run; run = run->next())
- if (run->type() == NODE_VARIABLE) return True;
- return False;
-}
-
-void variables::browseCB( Widget w, XtPointer data )
-{
- XmListCallbackStruct *cb = (XmListCallbackStruct *) data;
- char *p = xec_GetString(cb->item);
- if (*p == 'V') {
- XmTextSetString(name_, (char*) "");
- XmTextSetString(value_, (char*) "");
- }
- else {
- char *q = p + 1;
- char *r = p + 1;
-
- while ( *r && *r != '=' )
- r++;
-
- *r = 0;
-
- while ( *q && q[strlen(q) - 1] == ' ' )
- q[strlen(q) - 1] = 0;
-
- r += 2;
-
- if (*p == '(') r[strlen(r) - 1] = 0;
-
- while ( *r && r[strlen(r) - 1] == ' ' )
- r[strlen(r) - 1] = 0;
-
- XmTextSetString(name_, q);
- XmTextSetString(value_, r);
- }
- nameCB(w, data);
- valueCB(w, data);
-
- XtFree(p);
-}
-
-/* from: http://www.ist.co.uk/motif/books/vol6A/ch-13.fm.html */
-/* find the item in the list that matches the specified pattern */
-#include <Xm/TextF.h>
-#define _REGEX_RE_COMP
-#include <regex.h>
-void search_item( Widget text_w, XtPointer client_data, XtPointer call_data, Widget nam,
- Widget val )
-{
- Widget list_w = (Widget) client_data;
- char *exp, *text, *newtext = XmTextFieldGetString(text_w);
- XmString *strlist, *selectlist = NULL;
- int cnt, j = 0;
-
- if (!newtext || !*newtext) {
- XtFree(newtext);
- return;
- }
-
- if ((exp = re_comp(newtext))) {
- printf("Error with re_comp(%s): %s\n", newtext, exp);
- XtFree(newtext);
- return;
- }
-
- XtVaGetValues(list_w, XmNitemCount, &cnt, XmNitems, &strlist, NULL);
-
- while ( cnt-- ) {
- if (!(text = (char *) xec_GetString(strlist[cnt]))) break;
-
- if (re_exec(text) > 0) {
- selectlist = (XmString *) XtRealloc((char *) selectlist, (j + 1) * (sizeof(XmString *)));
- selectlist[j++] = XmStringCopy(strlist[cnt]);
-
- char *p = xec_GetString(strlist[cnt]);
- char *q = p + 1;
- char *r = p + 1;
- while ( *r && *r != '=' )
- r++;
- *r = 0;
- while ( *q && q[strlen(q) - 1] == ' ' )
- q[strlen(q) - 1] = 0;
- r += 2;
- if (*p == '(') r[strlen(r) - 1] = 0;
- while ( *r && r[strlen(r) - 1] == ' ' )
- r[strlen(r) - 1] = 0;
- XmTextSetString(nam, q);
- XmTextSetString(val, r);
- *r = '=';
- XtFree(p);
- }
- XtFree(text);
- }
- free(exp);
- XtFree(newtext);
-
- XtVaSetValues(list_w, XmNselectedItems, selectlist, XmNselectedItemCount, j, NULL);
-
- while ( j-- )
- XmStringFree(selectlist[j]);
- // XmTextFieldSetString (text_w, "");
-}
-/* */
-
-void variables::findCB( Widget, XtPointer )
-{
- char *name = XmTextGetString(name_);
- search_item(name_, list_, NULL, name_, value_);
- XtFree(name);
-}
-
-void variables::deleteCB( Widget, XtPointer )
-{
- if (get_node()) {
- char *name = XmTextGetString(name_);
- const char* fullname = get_node()->full_name().c_str();
- if (confirm::ask(False, "Delete variable %s for node %s", name, fullname)) {
- // repeat get_node while suite may have been cancelled by another
- // while answering this question
- if (get_node()) {
- if (get_node()->__node__()) /* ecflow */
- get_node()->serv().command(clientName, "--alter", "delete", "variable", name,
- fullname, NULL);
- else
- get_node()->serv().command("alter", "-vr", fullname, name, NULL);
- }
- }
- XtFree(name);
- update();
- }
- else
- clear();
-}
-
-void variables::setCB( Widget, XtPointer )
-{
- if (get_node()) {
-
- char *name = XmTextGetString(name_);
- char *value = XmTextGetString(value_);
- Boolean ok = True;
- node* n = get_node()->variableOwner(name);
-
- if (n != 0 && n != get_node()) {
- ok = confirm::ask(True, "This variable is already defined in the %s %s\n"
- "A new variable will be created for the selected node\n"
- "and hide the previous one\n"
- "Do you want to proceed?",
- n->type_name(), n->full_name().c_str());
- }
-
- if (n != 0 && n->isGenVariable(name) && ok) {
- ok = confirm::ask(True, "This variable is a generated variable\n"
- "Do you want to proceed?");
- }
-
- if (ok) {
- bool add = true;
- if (get_node()->__node__()) add = get_node()->__node__()->variable(name)
- == ecf_node::none();
- if (get_node()->__node__())
- get_node()->serv().command(clientName, "--alter", add ? "add" : "change", "variable",
- name, value, get_node()->full_name().c_str(), NULL);
- else
- get_node()->serv().command("alter", "-v", get_node()->full_name().c_str(), name, value,
- NULL);
- if (add) update();
- }
- XtFree(name);
- XtFree(value);
- }
- else
- clear();
-}
-
-void variables::nameCB( Widget, XtPointer )
-{
- if (loading_) return;
-
- char *p = XmTextGetString(name_);
- if (get_node()) {
- node *n = get_node()->variableOwner(p);
- XtSetSensitive(delete_, n != 0 && (!n->isGenVariable(p) || n != get_node()));
- }
- else {
- clear();
- }
- XtFree(p);
-}
-
-void variables::valueCB( Widget, XtPointer )
-{
- if (loading_) return;
-
- char *p = XmTextGetString(name_);
- char *v = XmTextGetString(value_);
- if (get_node()) {
- const char *x = get_node()->variable(p).c_str();
- XtSetSensitive(set_, (x == 0 || strcmp(x, v) != 0) && v[0] != 0);
- }
- else {
- clear();
- }
- XtFree(v);
- XtFree(p);
-}
-
diff --git a/ecflow_4_0_7/view/src/variables.h b/ecflow_4_0_7/view/src/variables.h
deleted file mode 100644
index 89c8b97..0000000
--- a/ecflow_4_0_7/view/src/variables.h
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef variables_H
-#define variables_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "uivariables.h"
-
-#ifndef panel_H
-#include "panel.h"
-#endif
-
-//
-
-class variables : public panel, public variables_form_c {
-public:
-
- variables(panel_window&);
-
- ~variables(); // Change to virtual if base class
-
- virtual const char* name() const { return "Variables"; }
- virtual void show(node&);
- virtual Boolean enabled(node&);
- virtual void clear();
- virtual Widget widget() { return xd_rootwidget(); }
-
-private:
-
- variables(const variables&);
- variables& operator=(const variables&);
-
- bool loading_;
-
- virtual void browseCB( Widget, XtPointer ) ;
- virtual void deleteCB( Widget, XtPointer ) ;
- virtual void nameCB( Widget, XtPointer ) ;
- virtual void setCB( Widget, XtPointer ) ;
- virtual void valueCB( Widget, XtPointer ) ;
- virtual void findCB( Widget, XtPointer ) ;
-
-};
-
-inline void destroy(variables**) {}
-
-#endif
diff --git a/ecflow_4_0_7/view/src/viewer.cc b/ecflow_4_0_7/view/src/viewer.cc
deleted file mode 100644
index 8cd0a5d..0000000
--- a/ecflow_4_0_7/view/src/viewer.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#ifndef viewer_H
-#include "viewer.h"
-#endif
-
-#ifndef gui_H
-#include "gui.h"
-#endif
-
-
-viewer::viewer()
-{
-}
-
-bool viewer::show(const char* cmd)
-{
- FILE *f = popen(cmd,"r");
- if(!f) {
- gui::syserr(cmd);
- return false;
- }
- start(f);
- return true;
-}
-
-void viewer::ready(const char* line)
-{
- gui::error("%s",line);
-}
-
-void viewer::done(FILE* f)
-{
- end(pclose(f));
-}
-
-void viewer::end(bool)
-{
- delete this;
-}
-
-viewer::~viewer()
-{
-}
diff --git a/ecflow_4_0_7/view/src/viewer.h b/ecflow_4_0_7/view/src/viewer.h
deleted file mode 100644
index 6029806..0000000
--- a/ecflow_4_0_7/view/src/viewer.h
+++ /dev/null
@@ -1,134 +0,0 @@
-#ifndef viewer_H
-#define viewer_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#ifdef NO_BOOL
-#include "bool.h"
-#endif
-
-#ifndef input_H
-#include "input.h"
-#endif
-
-
-
-// Headers
-// #ifndef machine_H
-// #include <machine.h>
-// #endif
-
-// Forward declarations
-
-// class ostream;
-// typedef class _Pvts os_typespec; // Remove if not persistant
-
-//
-
-class viewer : public input {
-public:
-
-// -- Exceptions
- // None
-
-// -- Contructors
-
- viewer();
-
-// -- Destructor
-
- virtual ~viewer();
-
-// -- Convertors
- // None
-
-// -- Operators
- // None
-
-// -- Methods
-
- virtual bool show(const char*);
- virtual void end(bool);
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
- // Uncomment for persistent, remove otherwise
- // static os_typespec* get_os_typespec();
-
-protected:
-
-
-// -- Members
- // None
-
-// -- Methods
-
- // void print(ostream&) const; // Change to virtual if base class
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-private:
-
-// No copy allowed
-
- viewer(const viewer&);
- viewer& operator=(const viewer&);
-
-// -- Members
-
-// -- Methods
- // None
-
-// -- Overridden methods
-
- void ready(const char*);
- void done(FILE*);
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-// -- Friends
-
- //friend ostream& operator<<(ostream& s,const viewer& p)
- // { p.print(s); return s; }
-
-};
-
-inline void destroy(viewer**) {}
-
-// If persistent, uncomment, otherwise remove
-//#ifdef _ODI_OSSG_
-//OS_MARK_SCHEMA_TYPE(viewer);
-//#endif
-
-#endif
diff --git a/ecflow_4_0_7/view/src/why.cc b/ecflow_4_0_7/view/src/why.cc
deleted file mode 100644
index 742d6b4..0000000
--- a/ecflow_4_0_7/view/src/why.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #11 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "why.h"
-#include "node.h"
-#include "error.h"
-#include "selection.h"
-#include "tmp_file.h"
-#include "Hyper.h"
-#include <stdio.h>
-#include <stdarg.h>
-
-/***********************************/
-
-why::why(panel_window& w):
- panel(w)
-{
-}
-
-why::~why()
-{
- forget_all();
-}
-
-void why::clear()
-{
- forget_all();
- HyperSetText(text_,"");
-}
-
-void why::show(node& n)
-{
- forget_all();
- node* parent = n.parent(); // SUP-421
- while (parent) {
- observe(parent);
- parent = parent->parent();
- }
- std::stringstream ss;
- n.why(ss);
- HyperSetText(text_,(char*) ss.str().c_str());
-}
-
-void why::hyperCB(Widget w,XtPointer data)
-{
- panel::hyper(w,data);
-}
-
-Boolean why::enabled(node& n)
-{
- return n.isSimpleNode();
-}
diff --git a/ecflow_4_0_7/view/src/why.h b/ecflow_4_0_7/view/src/why.h
deleted file mode 100644
index fa9acb1..0000000
--- a/ecflow_4_0_7/view/src/why.h
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef why_H
-#define why_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "uiwhy.h"
-
-#ifndef panel_H
-#include "panel.h"
-#endif
-
-#ifndef node_H
-#include "node.h"
-#endif
-
-class why : public panel, public why_form_c {
-public:
- why(panel_window&);
-
- ~why(); // Change to virtual if base class
-
- virtual const char* name() const { return "Why?"; }
- virtual void show(node&);
- virtual void clear();
- virtual Widget widget() { return xd_rootwidget(); }
- virtual Boolean enabled(node&);
-
-private:
- why(const why&);
- why& operator=(const why&);
-
- virtual void hyperCB(Widget,XtPointer);
-};
-
-inline void destroy(why**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/window.cc b/ecflow_4_0_7/view/src/window.cc
deleted file mode 100644
index 31f7922..0000000
--- a/ecflow_4_0_7/view/src/window.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <stdio.h>
-#include "window.h"
-#include <Xm/PushB.h>
-#include <X11/IntrinsicP.h>
-
-
-extern "C" {
-#include "xec.h"
-}
-#include "gui.h"
-
-
-window::window()
- : menu_(0)
-{
-}
-
-window::~window()
-{
- if(menu_)
- XtDestroyWidget(menu_);
-}
-
-void window::raise()
-{
- CompositeWidget c = (CompositeWidget)shell();
- for(unsigned int i = 0 ; i < c->composite.num_children; i++)
- XtManageChild(c->composite.children[i]);
-
- XMapRaised(XtDisplay(shell()),XtWindow(shell()));
-}
-
-void window::set_menu(const char* name)
-{
- if(!menu_)
- {
- menu_ = XmCreatePushButton(gui::windows(),(char*)"menu",0,0);
- xec_SetUserData(menu_,this);
- XtManageChild(menu_);
- }
- xec_SetLabel(menu_,name);
-}
-
-IMP(window)
diff --git a/ecflow_4_0_7/view/src/window.h b/ecflow_4_0_7/view/src/window.h
deleted file mode 100644
index ec2ec8a..0000000
--- a/ecflow_4_0_7/view/src/window.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef window_H
-#define window_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <Xm/Xm.h>
-
-#include "extent.h"
-
-class window : public extent<window> {
-public:
-
- window();
-
- ~window(); // Change to virtual if base class
-
- void raise();
- virtual Widget shell() = 0;
-
- void set_menu(const char*);
-
-private:
-
- window(const window&);
- window& operator=(const window&);
-
- Widget menu_;
-};
-
-inline void destroy(window**) {}
-
-#endif
diff --git a/ecflow_4_0_7/view/src/x.c b/ecflow_4_0_7/view/src/x.c
deleted file mode 100644
index f8c5aeb..0000000
--- a/ecflow_4_0_7/view/src/x.c
+++ /dev/null
@@ -1,19 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-void main()
-{
- printf("hello\n");
-}
diff --git a/ecflow_4_0_7/view/src/xcdp.menu b/ecflow_4_0_7/view/src/xcdp.menu
deleted file mode 100644
index 471f9c8..0000000
--- a/ecflow_4_0_7/view/src/xcdp.menu
+++ /dev/null
@@ -1,257 +0,0 @@
-!===========================================================
-! Name :
-! Author :
-! Revision : $Revision: #17 $
-!
-! Copyright 2009-2012 ECMWF.
-! This software is licensed under the terms of the Apache Licence version 2.0
-! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-! In applying this licence, ECMWF does not waive the privileges and immunities
-! granted to it by virtue of its status as an intergovernmental organisation
-! nor does it submit to any jurisdiction.
-!
-! Description :
-! this file may be found in
-! - sources in order to generate xcdp.menu.h
-! - ~/.ecflowrc/xcdp.menu # edit backup remove (reset)
-! - ~/ is preferred to $HOME
-! - menus can call system command
-!===========================================================
-!
-! Format
-!-------
-! menu TITLE
-! {
-! (vis flg,enable flg,title,command,question,answer)
-! }
-!
-!===========================================================
-!
-! Values for the status flags
-!----------------------------
-!
-!NONE ALL UNKNOWN SUSPENDED COMPLETE QUEUED SUBMITTED ACTIVE
-!ABORTED CLEAR SET SHUTDOWN HALTED
-!
-! Values for type flags
-!----------------------
-!
-!NONE ALL SERVER SUITE FAMILY TASK EVENT
-!
-! Values for visible flags
-!-------------------------
-!
-!NONE ALL SERVER SUITE FAMILY TASK EVENT
-!
-! Values for special flags
-!-------------------------
-!
-!NONE ALL HAS_TRIGGERS HAS_TIME HAS_DATE
-!
-!===========================================================
-
-!==============================================================================
-! Main menu
-!==============================================================================
-
-version 1 0 0 ;
-
-menu 'MAIN'
-{
- (~SUSPENDED & NODE, ALL, 'Suspend', 'suspend <full_name>')
- (SUSPENDED & NODE, ALL, 'Resume', 'resume <full_name>')
-
- ( TASK, ~ACTIVE & ~SUBMITTED, 'Rerun', 'force queued <full_name>')
- ( FAMILY, ~ACTIVE & ~SUBMITTED, 'Rerun', 'run <full_name>')
-
- (TASK|ALIAS, SUBMITTED|ACTIVE, 'Set complete',
- 'force complete <full_name>',
- 'Have you checked that the job is not active anymore (jobstatus) ?', YES)
- (TASK|ALIAS, UNKNOWN|QUEUED|ABORTED, 'Set complete',
- 'force complete <full_name>')
- (TASK|ALIAS, SUBMITTED|ACTIVE, 'Set aborted',
- 'force aborted <full_name>',
- 'Have you checked that the job is not active anymore (jobstatus) ?', YES)
- (TASK|ALIAS, UNKNOWN|QUEUED|COMPLETE, 'Set aborted',
- 'force aborted <full_name>')
-
- (TASK|ALIAS, ~ACTIVE & ~SUBMITTED, 'Execute', 'run <full_name>')
-
- (SUITE|TASK|FAMILY, ~ACTIVE & ~SUBMITTED, 'Requeue',
- 'requeue -f <full_name>',
- 'Confirm requeuing of <full_name>', YES)
-
- (SUITE|FAMILY, ABORTED | SUSPENDED, 'Requeue aborted',
- 'requeue -a <full_name>',
- 'Confirm requeuing of aborted tasks from <full_name>', YES)
-
- (ALL,ALL,'-',SEPARATOR)
-
- (SUITE|TASK|FAMILY,(QUEUED) & (HAS_TRIGGERS|HAS_TIME|HAS_DATE),'Delete',MENU)
- (NODE|ALIAS,ALL,'Special', MENU)
- (NODE& ADMIN, ALL,'Force', MENU)
- ((NODE|ALIAS)& ADMIN, ALL,'Order', MENU)
-
- (ALL,ALL,'-',SEPARATOR ,'',YES)
- (SUITE|FAMILY|TASK, ALL, 'Web...', 'url <full_name> ', '', YES)
-
- (ALL,ALL,'-',SEPARATOR)
-
- (SUITE & (OPER|ADMIN) ,UNKNOWN|COMPLETE,'Begin',
- 'begin <full_name>','',YES)
-
- (SUITE & (OPER|ADMIN) ,~SUBMITTED & ~ACTIVE,'Cancel',
- 'cancel -y <full_name>',
- 'Do you really want to cancel suite <full_name> ?',NO)
-
-! Events
-!---------------------------------
-
- (EVENT, CLEAR, 'Set' , 'force set <full_name>', '',YES)
- (EVENT, SET, 'Clear', 'force clear <full_name>', '',YES)
-
-!!-----------------------------------
-
- (SERVER & (ADMIN|OPER) & LOCKED , ALL , 'Unlock', 'unlock -y',
- 'Before going further, please check why the server was locked.',NO)
- (ALL,ALL,'-',SEPARATOR,'',YES)
-
-!!-----------------------------------
-
- (SERVER,SHUTDOWN|HALTED, 'Restart',
- 'restart -y','Restart the server in <node_name>?' ,NO)
- (SERVER,~SHUTDOWN, 'Shutdown',
- 'shutdown -y','Shutdown the server in <node_name>?',NO)
- (SERVER,~HALTED, 'Halt',
- 'halt -y','Halt the server in <node_name>?',NO)
- (SERVER,HALTED, 'Terminate',
- 'terminate -y','Terminate the server in <node_name>?',NO)
- (ALL,ALL,'-',SEPARATOR,'',YES)
- (SERVER,ALL, 'Checkpoint','check','',YES)
- (SERVER,HALTED, 'Recover',
- 'recover -y','Recover the server in <node_name>?',NO)
-
-!!-----------------------------------
-
- (LIMIT , ALL, 'Reset' ,
- 'reset <full_name>', 'Confirm resetting <full_name>', YES)
- (ALIAS , ALL, 'Remove',
- 'cancel -y <full_name>', 'Confirm remove alias <full_name>', YES)
-
-!!-----------------------------------
-
- (ALL,ALL,'-',SEPARATOR)
-
- (TASK|LIMIT|LABEL|METER|REPEAT|VARIABLE, ALL , 'Edit...', WINDOW(Edit))
- (TASK|ALIAS, ALL , 'Output...', WINDOW(Output) )
-
- (TASK|ALIAS, SUBMITTED|ACTIVE , 'Status...', WINDOW(Jobstatus))
- (ALIAS, ALL , 'Job...', WINDOW(Job) )
- (TASK|ALIAS, ALL , 'Script...', WINDOW(Script) )
-
- (SERVER, ALL , 'Suites...', WINDOW(Suites) )
- (SERVER, ALL , 'History...', WINDOW(History) )
- (SERVER, ALL , 'Zombies...', WINDOW(Zombies) )
- (ALL,ALL,'-',SEPARATOR)
- (SERVER, ALL , 'Options...', WINDOW(Options) )
-}
-
-!==============================================================================
-! Status submenu
-!==============================================================================
-
-menu 'Status'
-{
- (SUITE|TASK|FAMILY, ~SUSPENDED,'Suspend', 'suspend <full_name>', '',YES)
- (SUITE|TASK|FAMILY, SUSPENDED ,'Resume', 'resume <full_name>', '',YES)
-
- (ALL,ALL,'-',SEPARATOR)
-
- (TASK, ~ACTIVE & ~SUBMITTED, 'Rerun', 'force queued <full_name>', '',YES)
- (TASK, ~COMPLETE, 'Set complete', 'force complete <full_name>', '',YES)
-
- (SUITE|TASK|FAMILY|ALIAS, ~ACTIVE & ~SUBMITTED,
- 'Requeue','requeue -f <full_name>', 'Confirm requeuing of <full_name>', YES)
-
- (SUITE|FAMILY, ABORTED | SUSPENDED,
- 'Requeue aborted','requeue -a <full_name>',
- 'Confirm requeuing aborted tasks below <full_name>', YES)
-}
-
-!==============================================================================
-! Suite submenu
-!==============================================================================
-
-menu 'Suite'
-{
- (SUITE,UNKNOWN|COMPLETE,'Begin','begin <full_name>','',YES)
-
- (SUITE,ALL,'Cancel','cancel -y <full_name>',
- 'Do you really want to cancel <full_name> ?',NO)
-
- (ALL,ALL,'-',SEPARATOR)
-}
-
-!==============================================================================
-! Delete submenu
-!==============================================================================
-
-menu 'Delete'
-{
- (ALL,HAS_TRIGGERS|HAS_TIME|HAS_DATE, 'All dependencies',
- 'delete -tdT <full_name>')
- (ALL,HAS_TRIGGERS, 'Trigger dependencies','delete -T <full_name>')
- (ALL,HAS_TIME, 'Time dependencies','delete -t <full_name>')
- (ALL,QUEUED, 'Date dependencies','delete -d <full_name>')
-}
-
-menu "Order"
-{
- (ALL,ALL,'Top','order -t top <full_name>')
- (ALL,ALL,'Up','order -t up <full_name>')
- (ALL,ALL,'Down','order -t down <full_name>')
- (ALL,ALL,'Bottom','order -t bottom <full_name>')
- (ALL,ALL,'Alphabetically','order -t alphabetical <full_name>')
-}
-
-menu "Force"
-{
- (NODE, ~UNKNOWN, 'Unknown', 'force -q -r unknown <full_name>')
- (NODE, ~COMPLETE & ~ACTIVE & ~SUBMITTED, 'Complete',
- 'force =q -r complete <full_name>',
- 'Check running/queued jobs and Confirm force complete of <full_name>', YES)
- (NODE, ~QUEUED & ~ACTIVE & ~SUBMITTED, 'Queued',
- 'force -q -r queued <full_name>')
- (NODE, ~SUBMITTED & ~ACTIVE,'Submitted',
- 'force -q -r submitted <full_name>')
- (NODE, ~ACTIVE, 'Active', 'force -q -r active <full_name>')
- (NODE, ~ABORTED, 'Aborted', 'force -q -r aborted <full_name>',
- 'Check running/queued jobs and Confirm force submitted of <full_name>', YES)
-}
-
-menu "Special"
-{
- (SUITE|FAMILY,(ACTIVE|SUBMITTED|ABORTED),'Kill',
- 'kill <full_name>','',YES)
- (TASK|ALIAS,(ACTIVE|SUBMITTED),'Kill','kill <full_name>','',YES)
-
- (ALL,ALL,'Check',WINDOW(Check),'',YES)
- (TASK|ALIAS,ALL,'Free password','alter -v <full_name> SMSPASS FREE')
- (TASK|ALIAS,ALL,'ClearZ','alter -F zombie <full_name>')
- ((SUITE|FAMILY), SELECTION, 'Plug into selected node', PLUG)
- (SUITE|SERVER, ALL, 'Collect...', WINDOW(Collector))
- (SERVER|SUITE,ALL,'Windows', MENU)
- (ALL,ALL,'echo', 'sh echo ok')
-}
-
-menu "Windows"
-{
- (SERVER, ALL , 'Info...', WINDOW(Info))
- (SERVER, ALL , 'Man...', WINDOW(Manual))
- (SERVER, ALL , 'Var...', WINDOW(Variables))
- (SERVER, ALL , 'Msg...', WINDOW(Messages))
- (SERVER, ALL , 'Why...', WINDOW(Why))
- (SERVER, ALL , 'Triggers...', WINDOW(Triggers))
- (SERVER, ALL , 'Check...', WINDOW(Check))
- (SERVER, ALL , 'Jobstatus...', WINDOW(Jobstatus))
-}
diff --git a/ecflow_4_0_7/view/src/xcdp.menu.h b/ecflow_4_0_7/view/src/xcdp.menu.h
deleted file mode 100644
index d4515e2..0000000
--- a/ecflow_4_0_7/view/src/xcdp.menu.h
+++ /dev/null
@@ -1,258 +0,0 @@
-(char*) " !=========================================================== ",
-(char*) " ! Name : ",
-(char*) " ! Author : ",
-(char*) " ! Revision : $Revision: #17 $ ",
-(char*) " ! ",
-(char*) " ! Copyright 2009-2012 ECMWF. ",
-(char*) " ! This software is licensed under the terms of the Apache Licence version 2.0 ",
-(char*) " ! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. ",
-(char*) " ! In applying this licence, ECMWF does not waive the privileges and immunities ",
-(char*) " ! granted to it by virtue of its status as an intergovernmental organisation ",
-(char*) " ! nor does it submit to any jurisdiction. ",
-(char*) " ! ",
-(char*) " ! Description : ",
-(char*) " ! this file may be found in ",
-(char*) " ! - sources in order to generate xcdp.menu.h ",
-(char*) " ! - ~/.ecflowrc/xcdp.menu # edit backup remove (reset) ",
-(char*) " ! - ~/ is preferred to $HOME ",
-(char*) " ! - menus can call system command ",
-(char*) " !=========================================================== ",
-(char*) " ! ",
-(char*) " ! Format ",
-(char*) " !------- ",
-(char*) " ! menu TITLE ",
-(char*) " ! { ",
-(char*) " ! (vis flg,enable flg,title,command,question,answer) ",
-(char*) " ! } ",
-(char*) " ! ",
-(char*) " !=========================================================== ",
-(char*) " ! ",
-(char*) " ! Values for the status flags ",
-(char*) " !---------------------------- ",
-(char*) " ! ",
-(char*) " !NONE ALL UNKNOWN SUSPENDED COMPLETE QUEUED SUBMITTED ACTIVE ",
-(char*) " !ABORTED CLEAR SET SHUTDOWN HALTED ",
-(char*) " ! ",
-(char*) " ! Values for type flags ",
-(char*) " !---------------------- ",
-(char*) " ! ",
-(char*) " !NONE ALL SERVER SUITE FAMILY TASK EVENT ",
-(char*) " ! ",
-(char*) " ! Values for visible flags ",
-(char*) " !------------------------- ",
-(char*) " ! ",
-(char*) " !NONE ALL SERVER SUITE FAMILY TASK EVENT ",
-(char*) " ! ",
-(char*) " ! Values for special flags ",
-(char*) " !------------------------- ",
-(char*) " ! ",
-(char*) " !NONE ALL HAS_TRIGGERS HAS_TIME HAS_DATE ",
-(char*) " ! ",
-(char*) " !=========================================================== ",
-(char*) " ",
-(char*) " !============================================================================== ",
-(char*) " ! Main menu ",
-(char*) " !============================================================================== ",
-(char*) " ",
-(char*) " version 1 0 0 ; ",
-(char*) " ",
-(char*) " menu 'MAIN' ",
-(char*) " { ",
-(char*) " (~SUSPENDED & NODE, ALL, 'Suspend', 'suspend <full_name>') ",
-(char*) " (SUSPENDED & NODE, ALL, 'Resume', 'resume <full_name>') ",
-(char*) " ",
-(char*) " ( TASK, ~ACTIVE & ~SUBMITTED, 'Rerun', 'force queued <full_name>') ",
-(char*) " ( FAMILY, ~ACTIVE & ~SUBMITTED, 'Rerun', 'run <full_name>') ",
-(char*) " ",
-(char*) " (TASK|ALIAS, SUBMITTED|ACTIVE, 'Set complete', ",
-(char*) " 'force complete <full_name>', ",
-(char*) " 'Have you checked that the job is not active anymore (jobstatus) ?', YES) ",
-(char*) " (TASK|ALIAS, UNKNOWN|QUEUED|ABORTED, 'Set complete', ",
-(char*) " 'force complete <full_name>') ",
-(char*) " (TASK|ALIAS, SUBMITTED|ACTIVE, 'Set aborted', ",
-(char*) " 'force aborted <full_name>', ",
-(char*) " 'Have you checked that the job is not active anymore (jobstatus) ?', YES) ",
-(char*) " (TASK|ALIAS, UNKNOWN|QUEUED|COMPLETE, 'Set aborted', ",
-(char*) " 'force aborted <full_name>') ",
-(char*) " ",
-(char*) " (TASK|ALIAS, ~ACTIVE & ~SUBMITTED, 'Execute', 'run <full_name>') ",
-(char*) " ",
-(char*) " (SUITE|TASK|FAMILY, ~ACTIVE & ~SUBMITTED, 'Requeue', ",
-(char*) " 'requeue -f <full_name>', ",
-(char*) " 'Confirm requeuing of <full_name>', YES) ",
-(char*) " ",
-(char*) " (SUITE|FAMILY, ABORTED | SUSPENDED, 'Requeue aborted', ",
-(char*) " 'requeue -a <full_name>', ",
-(char*) " 'Confirm requeuing of aborted tasks from <full_name>', YES) ",
-(char*) " ",
-(char*) " (ALL,ALL,'-',SEPARATOR) ",
-(char*) " ",
-(char*) " (SUITE|TASK|FAMILY,(QUEUED) & (HAS_TRIGGERS|HAS_TIME|HAS_DATE),'Delete',MENU) ",
-(char*) " (NODE|ALIAS,ALL,'Special', MENU) ",
-(char*) " (NODE& ADMIN, ALL,'Force', MENU) ",
-(char*) " ((NODE|ALIAS)& ADMIN, ALL,'Order', MENU) ",
-(char*) " ",
-(char*) " (ALL,ALL,'-',SEPARATOR ,'',YES) ",
-(char*) " (SUITE|FAMILY|TASK, ALL, 'Web...', 'url <full_name> ', '', YES) ",
-(char*) " ",
-(char*) " (ALL,ALL,'-',SEPARATOR) ",
-(char*) " ",
-(char*) " (SUITE & (OPER|ADMIN) ,UNKNOWN|COMPLETE,'Begin', ",
-(char*) " 'begin <full_name>','',YES) ",
-(char*) " ",
-(char*) " (SUITE & (OPER|ADMIN) ,~SUBMITTED & ~ACTIVE,'Cancel', ",
-(char*) " 'cancel -y <full_name>', ",
-(char*) " 'Do you really want to cancel suite <full_name> ?',NO) ",
-(char*) " ",
-(char*) " ! Events ",
-(char*) " !--------------------------------- ",
-(char*) " ",
-(char*) " (EVENT, CLEAR, 'Set' , 'force set <full_name>', '',YES) ",
-(char*) " (EVENT, SET, 'Clear', 'force clear <full_name>', '',YES) ",
-(char*) " ",
-(char*) " !!----------------------------------- ",
-(char*) " ",
-(char*) " (SERVER & (ADMIN|OPER) & LOCKED , ALL , 'Unlock', 'unlock -y', ",
-(char*) " 'Before going further, please check why the server was locked.',NO) ",
-(char*) " (ALL,ALL,'-',SEPARATOR,'',YES) ",
-(char*) " ",
-(char*) " !!----------------------------------- ",
-(char*) " ",
-(char*) " (SERVER,SHUTDOWN|HALTED, 'Restart', ",
-(char*) " 'restart -y','Restart the server in <node_name>?' ,NO) ",
-(char*) " (SERVER,~SHUTDOWN, 'Shutdown', ",
-(char*) " 'shutdown -y','Shutdown the server in <node_name>?',NO) ",
-(char*) " (SERVER,~HALTED, 'Halt', ",
-(char*) " 'halt -y','Halt the server in <node_name>?',NO) ",
-(char*) " (SERVER,HALTED, 'Terminate', ",
-(char*) " 'terminate -y','Terminate the server in <node_name>?',NO) ",
-(char*) " (ALL,ALL,'-',SEPARATOR,'',YES) ",
-(char*) " (SERVER,ALL, 'Checkpoint','check','',YES) ",
-(char*) " (SERVER,HALTED, 'Recover', ",
-(char*) " 'recover -y','Recover the server in <node_name>?',NO) ",
-(char*) " ",
-(char*) " !!----------------------------------- ",
-(char*) " ",
-(char*) " (LIMIT , ALL, 'Reset' , ",
-(char*) " 'reset <full_name>', 'Confirm resetting <full_name>', YES) ",
-(char*) " (ALIAS , ALL, 'Remove', ",
-(char*) " 'cancel -y <full_name>', 'Confirm remove alias <full_name>', YES) ",
-(char*) " ",
-(char*) " !!----------------------------------- ",
-(char*) " ",
-(char*) " (ALL,ALL,'-',SEPARATOR) ",
-(char*) " ",
-(char*) " (TASK|LIMIT|LABEL|METER|REPEAT|VARIABLE, ALL , 'Edit...', WINDOW(Edit)) ",
-(char*) " (TASK|ALIAS, ALL , 'Output...', WINDOW(Output) ) ",
-(char*) " ",
-(char*) " (TASK|ALIAS, SUBMITTED|ACTIVE , 'Status...', WINDOW(Jobstatus)) ",
-(char*) " (ALIAS, ALL , 'Job...', WINDOW(Job) ) ",
-(char*) " (TASK|ALIAS, ALL , 'Script...', WINDOW(Script) ) ",
-(char*) " ",
-(char*) " (SERVER, ALL , 'Suites...', WINDOW(Suites) ) ",
-(char*) " (SERVER, ALL , 'History...', WINDOW(History) ) ",
-(char*) " (SERVER, ALL , 'Zombies...', WINDOW(Zombies) ) ",
-(char*) " (ALL,ALL,'-',SEPARATOR) ",
-(char*) " (SERVER, ALL , 'Options...', WINDOW(Options) ) ",
-(char*) " } ",
-(char*) " ",
-(char*) " !============================================================================== ",
-(char*) " ! Status submenu ",
-(char*) " !============================================================================== ",
-(char*) " ",
-(char*) " menu 'Status' ",
-(char*) " { ",
-(char*) " (SUITE|TASK|FAMILY, ~SUSPENDED,'Suspend', 'suspend <full_name>', '',YES) ",
-(char*) " (SUITE|TASK|FAMILY, SUSPENDED ,'Resume', 'resume <full_name>', '',YES) ",
-(char*) " ",
-(char*) " (ALL,ALL,'-',SEPARATOR) ",
-(char*) " ",
-(char*) " (TASK, ~ACTIVE & ~SUBMITTED, 'Rerun', 'force queued <full_name>', '',YES) ",
-(char*) " (TASK, ~COMPLETE, 'Set complete', 'force complete <full_name>', '',YES) ",
-(char*) " ",
-(char*) " (SUITE|TASK|FAMILY|ALIAS, ~ACTIVE & ~SUBMITTED, ",
-(char*) " 'Requeue','requeue -f <full_name>', 'Confirm requeuing of <full_name>', YES) ",
-(char*) " ",
-(char*) " (SUITE|FAMILY, ABORTED | SUSPENDED, ",
-(char*) " 'Requeue aborted','requeue -a <full_name>', ",
-(char*) " 'Confirm requeuing aborted tasks below <full_name>', YES) ",
-(char*) " } ",
-(char*) " ",
-(char*) " !============================================================================== ",
-(char*) " ! Suite submenu ",
-(char*) " !============================================================================== ",
-(char*) " ",
-(char*) " menu 'Suite' ",
-(char*) " { ",
-(char*) " (SUITE,UNKNOWN|COMPLETE,'Begin','begin <full_name>','',YES) ",
-(char*) " ",
-(char*) " (SUITE,ALL,'Cancel','cancel -y <full_name>', ",
-(char*) " 'Do you really want to cancel <full_name> ?',NO) ",
-(char*) " ",
-(char*) " (ALL,ALL,'-',SEPARATOR) ",
-(char*) " } ",
-(char*) " ",
-(char*) " !============================================================================== ",
-(char*) " ! Delete submenu ",
-(char*) " !============================================================================== ",
-(char*) " ",
-(char*) " menu 'Delete' ",
-(char*) " { ",
-(char*) " (ALL,HAS_TRIGGERS|HAS_TIME|HAS_DATE, 'All dependencies', ",
-(char*) " 'delete -tdT <full_name>') ",
-(char*) " (ALL,HAS_TRIGGERS, 'Trigger dependencies','delete -T <full_name>') ",
-(char*) " (ALL,HAS_TIME, 'Time dependencies','delete -t <full_name>') ",
-(char*) " (ALL,QUEUED, 'Date dependencies','delete -d <full_name>') ",
-(char*) " } ",
-(char*) " ",
-(char*) " menu \"Order\" ",
-(char*) " { ",
-(char*) " (ALL,ALL,'Top','order -t top <full_name>') ",
-(char*) " (ALL,ALL,'Up','order -t up <full_name>') ",
-(char*) " (ALL,ALL,'Down','order -t down <full_name>') ",
-(char*) " (ALL,ALL,'Bottom','order -t bottom <full_name>') ",
-(char*) " (ALL,ALL,'Alphabetically','order -t alphabetical <full_name>') ",
-(char*) " } ",
-(char*) " ",
-(char*) " menu \"Force\" ",
-(char*) " { ",
-(char*) " (NODE, ~UNKNOWN, 'Unknown', 'force -q -r unknown <full_name>') ",
-(char*) " (NODE, ~COMPLETE & ~ACTIVE & ~SUBMITTED, 'Complete', ",
-(char*) " 'force =q -r complete <full_name>', ",
-(char*) " 'Check running/queued jobs and Confirm force complete of <full_name>', YES) ",
-(char*) " (NODE, ~QUEUED & ~ACTIVE & ~SUBMITTED, 'Queued', ",
-(char*) " 'force -q -r queued <full_name>') ",
-(char*) " (NODE, ~SUBMITTED & ~ACTIVE,'Submitted', ",
-(char*) " 'force -q -r submitted <full_name>') ",
-(char*) " (NODE, ~ACTIVE, 'Active', 'force -q -r active <full_name>') ",
-(char*) " (NODE, ~ABORTED, 'Aborted', 'force -q -r aborted <full_name>', ",
-(char*) " 'Check running/queued jobs and Confirm force submitted of <full_name>', YES) ",
-(char*) " } ",
-(char*) " ",
-(char*) " menu \"Special\" ",
-(char*) " { ",
-(char*) " (SUITE|FAMILY,(ACTIVE|SUBMITTED|ABORTED),'Kill', ",
-(char*) " 'kill <full_name>','',YES) ",
-(char*) " (TASK|ALIAS,(ACTIVE|SUBMITTED),'Kill','kill <full_name>','',YES) ",
-(char*) " ",
-(char*) " (ALL,ALL,'Check',WINDOW(Check),'',YES) ",
-(char*) " (TASK|ALIAS,ALL,'Free password','alter -v <full_name> SMSPASS FREE') ",
-(char*) " (TASK|ALIAS,ALL,'ClearZ','alter -F zombie <full_name>') ",
-(char*) " ((SUITE|FAMILY), SELECTION, 'Plug into selected node', PLUG) ",
-(char*) " (SUITE|SERVER, ALL, 'Collect...', WINDOW(Collector)) ",
-(char*) " (SERVER|SUITE,ALL,'Windows', MENU) ",
-(char*) " (ALL,ALL,'echo', 'sh echo ok') ",
-(char*) " } ",
-(char*) " ",
-(char*) " menu \"Windows\" ",
-(char*) " { ",
-(char*) " (SERVER, ALL , 'Info...', WINDOW(Info)) ",
-(char*) " (SERVER, ALL , 'Man...', WINDOW(Manual)) ",
-(char*) " (SERVER, ALL , 'Var...', WINDOW(Variables)) ",
-(char*) " (SERVER, ALL , 'Msg...', WINDOW(Messages)) ",
-(char*) " (SERVER, ALL , 'Why...', WINDOW(Why)) ",
-(char*) " (SERVER, ALL , 'Triggers...', WINDOW(Triggers)) ",
-(char*) " (SERVER, ALL , 'Check...', WINDOW(Check)) ",
-(char*) " (SERVER, ALL , 'Jobstatus...', WINDOW(Jobstatus)) ",
-(char*) " } ",
-NULL
diff --git a/ecflow_4_0_7/view/src/xdclass.h b/ecflow_4_0_7/view/src/xdclass.h
deleted file mode 100644
index bbe8c55..0000000
--- a/ecflow_4_0_7/view/src/xdclass.h
+++ /dev/null
@@ -1,225 +0,0 @@
-#ifndef XDCLASS_H
-#define XDCLASS_H
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #4 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#ifdef __cplusplus
-
-#include <Xm/Xm.h>
-#include <stdlib.h>
-#pragma GCC diagnostic ignored "-Wwrite-strings"
-
-class xd_base_c
-{
- public:
- xd_base_c() {_xd_rootwidget=NULL;}
- Widget xd_rootwidget() const {return _xd_rootwidget;}
- protected:
- Widget _xd_rootwidget;
- private:
- void operator=(xd_base_c&); // No assignment
- // Certain C++ compilers (eg gcc 2.5) require there to be an
- // implementation of the copy constructor. If your application
- // fails to link try using the second version of the constructor
- //xd_base_c(xd_base_c&) ; // No default copy
- xd_base_c(xd_base_c&) { abort();} // No default copy
-};
-
-class xd_XtWidget_c: public xd_base_c
-{
- public:
- xd_XtWidget_c();
- void SetValue(String name, XtArgVal value);
- void SetValues(ArgList args, Cardinal num_args);
- void VaSetValues(String name,...);
- void GetValue(String name, void *value);
- void GetValues(ArgList args, Cardinal num_args);
- void VaGetValues(String name,...);
- void Map();
- void Unmap();
- virtual void xd_enable();
- virtual void xd_disable();
- virtual void xd_destroy();
-};
-
-class xd_TopLevelShell_c: public xd_XtWidget_c
-{
-};
-
-class xd_ApplicationShell_c: public xd_TopLevelShell_c
-{
- public:
- void xd_exit(int status=0);
- void Realize();
-};
-
-class xd_ChildWidget_c: public xd_XtWidget_c
-{
- public:
- virtual void xd_show()=0;
- virtual void xd_hide()=0;
- void Manage();
- void Unmanage();
-};
-
-class xd_XmDialog_c: public xd_ChildWidget_c
-{
- public:
- xd_XmDialog_c();
- virtual void xd_show();
- virtual void xd_hide();
- void Raise();
- protected:
- Widget xd_getchildwidget();
- Widget xd_childwidget;
-};
-
-class xd_NonShellWidget_c: public xd_ChildWidget_c
-{
- public:
- virtual void xd_show();
- virtual void xd_hide();
-};
-
-class xd_XmLabel_c: public xd_NonShellWidget_c
-{
-};
-
-class xd_XmCascadeButton_c: public xd_NonShellWidget_c
-{
-};
-
-class xd_XmDrawnButton_c: public xd_NonShellWidget_c
-{
-};
-
-class xd_XmPushButton_c: public xd_NonShellWidget_c
-{
-};
-
-class xd_XmToggleButton_c: public xd_NonShellWidget_c
-{
-};
-
-class xd_XmArrowButton_c: public xd_NonShellWidget_c
-{
-};
-
-class xd_XmList_c: public xd_NonShellWidget_c
-{
-};
-
-class xd_XmScrollBar_c: public xd_NonShellWidget_c
-{
-};
-
-class xd_XmSeparator_c: public xd_NonShellWidget_c
-{
-};
-
-class xd_XmText_c: public xd_NonShellWidget_c
-{
-};
-
-class xd_XmTextField_c: public xd_NonShellWidget_c
-{
-};
-
-class xd_XmBulletinBoard_c: public xd_NonShellWidget_c
-{
-};
-
-class xd_XmRowColumn_c: public xd_NonShellWidget_c
-{
-};
-
-class xd_XmRadioBox_c: public xd_NonShellWidget_c
-{
-};
-
-class xd_XmDrawingArea_c: public xd_NonShellWidget_c
-{
-};
-
-class xd_XmPanedWindow_c: public xd_NonShellWidget_c
-{
-};
-
-class xd_XmFrame_c: public xd_NonShellWidget_c
-{
-};
-
-class xd_XmScale_c: public xd_NonShellWidget_c
-{
-};
-
-class xd_XmScrolledWindow_c: public xd_NonShellWidget_c
-{
-};
-
-class xd_XmScrolledText_c: public xd_NonShellWidget_c
-{
-};
-
-class xd_XmScrolledList_c: public xd_NonShellWidget_c
-{
-};
-
-class xd_XmMainWindow: public xd_NonShellWidget_c
-{
-};
-
-class xd_XmSelectionBox_c: public xd_NonShellWidget_c
-{
-};
-
-class xd_XmFileSelectionBox_c: public xd_NonShellWidget_c
-{
-};
-
-class xd_XmCommand_c: public xd_NonShellWidget_c
-{
-};
-
-class xd_XmMessageBox_c: public xd_NonShellWidget_c
-{
-};
-
-class xd_XmMainWindow_c: public xd_NonShellWidget_c
-{
-};
-
-class xd_XmForm_c: public xd_NonShellWidget_c
-{
-};
-
-class xd_XmMenuBar_c: public xd_NonShellWidget_c
-{
-};
-
-class xd_XmPulldownMenu_c: public xd_NonShellWidget_c
-{
-};
-
-class xd_XmPopupMenu_c: public xd_NonShellWidget_c
-{
-};
-
-class xd_XmOptionMenu_c: public xd_NonShellWidget_c
-{
-};
-
-#endif /*__cplusplus*/
-#endif /*XDCLASS_H*/
diff --git a/ecflow_4_0_7/view/src/xdxmdialog.cc b/ecflow_4_0_7/view/src/xdxmdialog.cc
deleted file mode 100644
index e65f691..0000000
--- a/ecflow_4_0_7/view/src/xdxmdialog.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <Xm/DialogS.h>
-
-#include <xdclass.h>
-
-xd_XmDialog_c::xd_XmDialog_c()
-{
- xd_childwidget=0;
- return;
-}
-
-Widget xd_XmDialog_c::xd_getchildwidget()
-{
- if (!xd_childwidget)
- {
- Cardinal numchildren;
- GetValue(XmNnumChildren, &numchildren);
- if (numchildren!=0)
- {
- WidgetList children;
- GetValue(XmNchildren, &children);
- xd_childwidget=*children;
- }
- }
- return xd_childwidget;
-}
-
-void xd_XmDialog_c::xd_show()
-{
- if (!_xd_rootwidget) // Nothing to show
- return;
- if (!xd_getchildwidget()) // Nothing to show
- return;
- XtManageChild(xd_childwidget);
- return;
-}
-
-void xd_XmDialog_c::xd_hide()
-{
- if (!_xd_rootwidget) // Nothing to hide
- return;
- if (!xd_getchildwidget()) // Nothing to hide
- return;
- XtUnmanageChild(xd_childwidget);
- return;
-}
-
-void xd_XmDialog_c::Raise()
-{
- (void) XRaiseWindow(XtDisplay(_xd_rootwidget), XtWindow(_xd_rootwidget));
- return;
-}
diff --git a/ecflow_4_0_7/view/src/xdxtclass.cc b/ecflow_4_0_7/view/src/xdxtclass.cc
deleted file mode 100644
index 4bd9ee5..0000000
--- a/ecflow_4_0_7/view/src/xdxtclass.cc
+++ /dev/null
@@ -1,223 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdlib.h>
-
-#include <xdclass.h>
-
-xd_XtWidget_c::xd_XtWidget_c()
-{
- _xd_rootwidget=0;
- return;
-}
-
-void xd_XtWidget_c::SetValue(String name, XtArgVal value)
-{
- Arg al[1];
- Cardinal ac=0;
- XtSetArg(al[ac], name, value); ac++;
- XtSetValues(_xd_rootwidget, al, ac);
- return;
-}
-
-void xd_XtWidget_c::SetValues(ArgList args, Cardinal num_args)
-{
- XtSetValues(_xd_rootwidget, args, num_args);
- return;
-}
-
-void xd_XtWidget_c::VaSetValues(String name,...)
-{
- String attr;
- int count=1;
- va_list ap;
-
- /* Ignore empty argument list */
- if (name==NULL)
- return;
-
- /* First count the (non-empty) argument list */
- va_start(ap, name);
-
- va_arg(ap, XtArgVal); // Pop first value
- for (attr = va_arg(ap, String); attr != NULL;
- attr = va_arg(ap, String))
- {
- va_arg(ap, XtArgVal); // Pop value
- ++count;
- }
- va_end(ap);
-
- /* Now transfer values into an ArgList and throw at XtSetValues*/
-
- ArgList al=new Arg[count];
- XtArgVal value;
- Cardinal ac=0;
-
- va_start(ap, name);
- value=va_arg(ap, XtArgVal);
- XtSetArg(al[ac], name, value); ac++;
- for (attr = va_arg(ap, String); attr != NULL;
- attr = va_arg(ap, String))
- {
- value=va_arg(ap, XtArgVal);
- if (value)
- {
- XtSetArg(al[ac], attr, value); ac++;
- }
- }
- va_end(ap);
- XtSetValues(_xd_rootwidget, al, ac);
-
- /* Tidy up - commented out version is for aged compilers */
- //delete [count]al;
- delete []al;
- return;
-}
-
-void xd_XtWidget_c::GetValue(String name, void* value)
-{
- Arg al[1];
- Cardinal ac=0;
- XtSetArg(al[ac], name, value); ac++;
- XtGetValues(_xd_rootwidget, al, ac);
- return;
-}
-
-void xd_XtWidget_c::GetValues(ArgList args, Cardinal num_args)
-{
- XtGetValues(_xd_rootwidget, args, num_args);
- return;
-}
-
-void xd_XtWidget_c::VaGetValues(String name,...)
-{
- String attr;
- int count=1;
- va_list ap;
-
- /* Ignore empty argument list */
- if (name==NULL)
- return;
-
- /* First count the (non-empty) argument list */
- va_start(ap, name);
-
- va_arg(ap, XtArgVal); // Pop first value
- for (attr = va_arg(ap, String); attr != NULL;
- attr = va_arg(ap, String))
- {
- va_arg(ap, XtArgVal); // Pop value
- ++count;
- }
- va_end(ap);
-
- /* Now transfer values into an ArgList and throw at XtGetValues*/
-
- ArgList al=new Arg[count];
- XtArgVal value;
- Cardinal ac=0;
-
- va_start(ap, name);
- value=va_arg(ap, XtArgVal);
- XtSetArg(al[ac], name, value); ac++;
- for (attr = va_arg(ap, String); attr != NULL;
- attr = va_arg(ap, String))
- {
- value=va_arg(ap, XtArgVal);
- if (value)
- {
- XtSetArg(al[ac], attr, value); ac++;
- }
- }
- va_end(ap);
- XtGetValues(_xd_rootwidget, al, ac);
-
- /* Tidy up - commented out version is for aged compilers */
- //delete [count]al;
- delete []al;
- return;
-}
-
-void xd_XtWidget_c::Map()
-{
- XtMapWidget(_xd_rootwidget);
- return;
-}
-
-void xd_XtWidget_c::Unmap()
-{
- XtUnmapWidget(_xd_rootwidget);
- return;
-}
-
-void xd_XtWidget_c::xd_enable()
-{
- XtSetSensitive(_xd_rootwidget, TRUE);
- return;
-}
-
-void xd_XtWidget_c::xd_disable()
-{
- XtSetSensitive(_xd_rootwidget, FALSE);
- return;
-}
-
-void xd_XtWidget_c::xd_destroy()
-{
- if (_xd_rootwidget){
- XtDestroyWidget(_xd_rootwidget);
- _xd_rootwidget=0;
- }
- return;
-}
-
-void xd_ApplicationShell_c::xd_exit(int status)
-{
- exit(status);
- return;
-}
-
-void xd_ApplicationShell_c::Realize()
-{
- XtRealizeWidget(_xd_rootwidget);
- return;
-}
-
-void xd_ChildWidget_c::Manage()
-{
- XtManageChild(_xd_rootwidget);
- return;
-}
-
-void xd_ChildWidget_c::Unmanage()
-{
- XtUnmanageChild(_xd_rootwidget);
- return;
-}
-
-void xd_NonShellWidget_c::xd_show()
-{
- Map();
- return;
-}
-
-void xd_NonShellWidget_c::xd_hide()
-{
- Unmap();
- return;
-}
diff --git a/ecflow_4_0_7/view/src/xec.h b/ecflow_4_0_7/view/src/xec.h
deleted file mode 100644
index 996048f..0000000
--- a/ecflow_4_0_7/view/src/xec.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#include <stdio.h>
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-#include "xecp.h"
-#if defined(__cplusplus) || defined(c_plusplus)
-}
-#endif
-
diff --git a/ecflow_4_0_7/view/src/xecp.h b/ecflow_4_0_7/view/src/xecp.h
deleted file mode 100644
index f2a37a0..0000000
--- a/ecflow_4_0_7/view/src/xecp.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #3 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-/* xec_Cursor.c */
-void xec_SetWatchCursor(Widget w);
-void xec_ResetCursor(Widget w);
-
-/* xec_Label.c */
-void xec_SetLabel(Widget w, const char *title);
-void xec_VaSetLabel(Widget w, const char *fmt, ...);
-
-/* xec_List.c */
-void xec_RemoveListItem(Widget w, char *p);
-void xec_AddListMax(Widget w, int max, char *p);
-void xec_VaAddListMax(Widget w, int max, char *fmt, ...);
-void xec_ListSelectAll(Widget w);
-void xec_AddListItem(Widget w, char *p);
-Boolean xec_AddListItemUnique(Widget w, char *p, Boolean sel);
-void xec_VaAddListItem(Widget w, char *fmt, ...);
-void xec_SetListItems(Widget w, XmString list[], int count);
-int xec_DumpList(FILE *f, char *fmt, Widget w);
-Boolean xec_ListSearch(Widget w, char *word, Boolean nocase, Boolean fromstart, Boolean wrap);
-void xec_ListSelect(Widget w, int n);
-void xec_ListItemSelect(Widget w, const char*);
-void xec_AddFontListItem(Widget list, char *buffer, Boolean bold);
-void xec_ReplaceListItem(Widget w,const char* from,const char* to);
-
-/* xec_Regexp.c */
-int xec_compile(char *w);
-int xec_step(char *p);
-
-/* xec_Strings.c */
-XmString xec_NewString(const char *s);
-int xec_BuildXmStringList(XmString **list, char *p, int *count);
-int xec_FreeXmStringList(XmString *list, int count);
-char *xec_GetString(XmString string);
-
-/* xec_Text.c */
-int regexp_find(const char *word, const char *buffer, int nocase, int *from, int *to);
-char *xec_TextGetString(Widget w, long *length);
-void xec_TextFreeString(char *p);
-Boolean xec_TextSearch(Widget w, char *word, Boolean nocase, Boolean regex, Boolean back, Boolean fromstart, Boolean wrap);
-char *xec_GetText(Widget w, char buf[]);
-int xec_LoadText(Widget Text, const char *fname, Boolean include);
-void *xec_MapText(Widget w, const char *fname, int *z);
-void xec_UnmapText(void *x);
-int xec_SaveText(Widget w, char *fname);
-int xec_DumpText(FILE *fp, Widget w);
-void xec_PrintText(Widget w, char *cmd);
-void xec_ReplaceTextSelection(Widget w, char *p, Boolean sel);
-
-/* xec_Toggle.c */
-void xec_SetToggle(Widget w, int set);
-int xec_GetToggle(Widget w);
-
-/* xec_Widget.c */
-void *xec_GetUserData(Widget w);
-void xec_SetUserData(Widget w, void *p);
-void xec_SetColor(Widget w, Pixel p, const char *which);
-void xec_ShowWidget(Widget w);
-void xec_Invert(Widget w);
-void xec_ManageAll(Widget w);
-void xec_UnmanageAll(Widget w);
diff --git a/ecflow_4_0_7/view/src/xmstring.cc b/ecflow_4_0_7/view/src/xmstring.cc
deleted file mode 100644
index 44ee4e5..0000000
--- a/ecflow_4_0_7/view/src/xmstring.cc
+++ /dev/null
@@ -1,107 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "xmstring.h"
-
-
-xmstring::xmstring(const char* s,const char* font):
- str_(0)
-{
-
- if(!s) return;
-
- if(font == 0) font = "normal";
-
-
- if(*s == '\n')
- {
- str_ = XmStringSeparatorCreate();
- *this += xmstring(s+1,font);
- return;
- }
-
-
- if(strchr(s,'\n'))
- {
-
- XmString xms1;
- XmString xms2;
- XmString line;
- XmString separator;
- char *p;
- char *t = XtNewString(s); /* Make a copy for strtok not to */
- /* damage the original string */
-
- separator = XmStringSeparatorCreate();
- p = strtok(t,"\n");
- xms1 = XmStringCreateLtoR(p,(char*)font);
-
- while ((p = strtok(NULL,"\n")))
- {
- line = XmStringCreateLtoR(p,(char*)font);
- xms2 = XmStringConcat(xms1,separator);
- XmStringFree(xms1);
- xms1 = XmStringConcat(xms2,line);
- XmStringFree(xms2);
- XmStringFree(line);
- }
-
- XmStringFree(separator);
- XtFree(t);
-
- str_ = xms1;
- }
- else str_ = XmStringCreateLtoR((char*)s,(char*)font);
-}
-
-xmstring::~xmstring()
-{
- if(str_)
- XmStringFree(str_);
-}
-
-xmstring::xmstring(XmString s):
- str_(XmStringCopy(s))
-{
-}
-
-xmstring::xmstring(const xmstring& other):
- str_(other.str_?XmStringCopy(other.str_):0)
-{
-}
-
-xmstring& xmstring::operator=(const xmstring& other)
-{
- if(str_) XmStringFree(str_);
- str_ = 0;
- if(other.str_) str_ = XmStringCopy(other.str_);
- return *this;
-}
-
-xmstring xmstring::operator+(const xmstring& other) const
-{
- if(!other.str_) return *this;
- if(!str_) return other;
-
- xmstring x;
- x.str_ = XmStringConcat(str_,other.str_);
- return x;
-}
-
-xmstring& xmstring::operator+=(const xmstring& other)
-{
- *this = *this + other;
- return *this;
-}
diff --git a/ecflow_4_0_7/view/src/xmstring.h b/ecflow_4_0_7/view/src/xmstring.h
deleted file mode 100644
index 4ded974..0000000
--- a/ecflow_4_0_7/view/src/xmstring.h
+++ /dev/null
@@ -1,128 +0,0 @@
-#ifndef xmstring_H
-#define xmstring_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-// Headers
-// #ifndef machine_H
-// #include <machine.h>
-// #endif
-
-// Forward declarations
-
-// class ostream;
-// typedef class _Pvts os_typespec; // Remove if not persistant
-
-//
-
-#include <Xm/Xm.h>
-
-class xmstring {
-public:
-
-// -- Exceptions
- // None
-
-// -- Contructors
-
- xmstring(const char* = 0, const char* set = 0);
- xmstring(XmString);
- xmstring(const xmstring&);
- xmstring& operator=(const xmstring&);
-
-// -- Destructor
-
- ~xmstring();
-
-// -- Convertors
- // None
-
-// -- Operators
-
- operator XmString() const { return str_; }
-
- xmstring operator+(const xmstring&) const;
- xmstring& operator+=(const xmstring&);
-
-// -- Methods
- // None
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
- // Uncomment for persistent, remove otherwise
- // static os_typespec* get_os_typespec();
-
-protected:
-
-// -- Members
- // None
-
-// -- Methods
-
- // void print(ostream&) const; // Change to virtual if base class
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-private:
-
-// No copy allowed
-
-
-// -- Members
-
- XmString str_;
-
-// -- Methods
- // None
-
-// -- Overridden methods
- // None
-
-// -- Class members
- // None
-
-// -- Class methods
- // None
-
-// -- Friends
-
- //friend ostream& operator<<(ostream& s,const xmstring& p)
- // { p.print(s); return s; }
-
-};
-
-inline void destroy(xmstring**) {}
-
-// If persistent, uncomment, otherwise remove
-//#ifdef _ODI_OSSG_
-//OS_MARK_SCHEMA_TYPE(xmstring);
-//#endif
-
-#endif
diff --git a/ecflow_4_0_7/view/src/xnode.cc b/ecflow_4_0_7/view/src/xnode.cc
deleted file mode 100644
index d13ea84..0000000
--- a/ecflow_4_0_7/view/src/xnode.cc
+++ /dev/null
@@ -1,56 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-#include "xnode.h"
-
-xnode::xnode(node *n):
- widget_(0),
- node_(n),
- box_(-1)
-{
-}
-
-xnode::~xnode()
-{
-}
-
-int xnode::getBox(Widget w)
-{
- if(widget_ && widget_ != w)
- return -1;
-
- if(box_ == -1)
- {
- widget_ = w;
- box_ = NodeCreate(w,drawCB,sizeCB,this);
- }
- return box_;
-}
-
-void xnode::drawCB(Widget w,XRectangle* r,void *data)
-{
- if (data) ((xnode*)data)->draw(w,r);
-}
-
-void xnode::sizeCB(Widget w,XRectangle* r,void *data)
-{
- if (data) ((xnode*)data)->size(w,r);
-}
-
-void xnode::select()
-{
- XtVaSetValues(widget_,XtNselected,box_,NULL);
- NodeShow(widget_,box_);
-}
diff --git a/ecflow_4_0_7/view/src/xnode.h b/ecflow_4_0_7/view/src/xnode.h
deleted file mode 100644
index 41eb6be..0000000
--- a/ecflow_4_0_7/view/src/xnode.h
+++ /dev/null
@@ -1,85 +0,0 @@
-#ifndef xnode_H
-#define xnode_H
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #6 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include <Xm/Xm.h>
-extern "C" {
-#include "SimpleBase.h"
-}
-
-class node;
-
-class xnode {
-public:
- xnode(node*);
-
- virtual ~xnode(); // Change to virtual if base class
-
- node* get_node() { return node_; }
-
- virtual int getBox(Widget) ;
-
- virtual void draw(Widget,XRectangle*) = 0;
- virtual void size(Widget,XRectangle*) = 0;
-
- void select();
-
- Widget widget() { return widget_; }
-
- Boolean visibility(Boolean vis)
- { return NodeVisibility(widget_,box_,vis); }
-
- void relation(xnode* o)
- { NodeAddRelation(widget_,box_,o->box_); }
-
- void* relation_data(xnode* o)
- { return NodeGetRelationData(widget_,box_,o->box_); }
-
- void* relation_data(xnode* o,void *d)
- { return NodeSetRelationData(widget_,box_,o->box_,d); }
-
- GC relation_gc(xnode* o,GC gc)
- { return NodeSetRelationGC(widget_,box_,o->box_,gc); }
-
- void redraw() { NodeNewSize(widget_,box_);NodeChanged(widget_,box_); }
- void show() { NodeShow(widget_,box_); }
-
- void setFocus() { NodeSetFocus(widget_,box_); }
-
- int group() { return NodeGetGroup(widget_,box_); }
- void group(int g) { NodeSetGroup(widget_,box_,g); }
-
- static void drawCB(Widget,XRectangle*,XtPointer);
- static void sizeCB(Widget,XRectangle*,XtPointer);
-
- void *operator new(size_t n) { return XtMalloc(n); }
- void operator delete(void* d) { XtFree((char*)d); }
-
-protected:
-
- Widget widget_;
- node* node_;
- int box_;
-
-private:
-
- xnode(const xnode&);
- xnode& operator=(const xnode&);
-};
-
-inline void destroy(xnode**) {}
-#endif
diff --git a/ecflow_4_0_7/view/src/xresources.h b/ecflow_4_0_7/view/src/xresources.h
deleted file mode 100644
index d9d5301..0000000
--- a/ecflow_4_0_7/view/src/xresources.h
+++ /dev/null
@@ -1,628 +0,0 @@
-/*=============================================================================================*/
-/* Name : */
-/* Author : */
-/* Revision : $Revision: #18 $ */
-/* */
-/* Copyright 2009-2012 ECMWF. */
-/* This software is licensed under the terms of the Apache Licence version 2.0 */
-/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
-/* In applying this licence, ECMWF does not waive the privileges and immunities */
-/* granted to it by virtue of its status as an intergovernmental organisation */
-/* nor does it submit to any jurisdiction. */
-/* */
-/* Description : */
-/*=============================================================================================*/
-
-#ifndef BRIDGE
-
-static char* xresources = (char*) "\n"
-"ecFlowview*File.accelerator: Ctrl<Key>f\n"
-"ecFlowview*File.mnemonic: F\n"
-"ecFlowview*Info.accelerator: Ctrl<Key>I\n"
-"ecFlowview*Script.accelerator: Ctrl<Key>S\n"
-"ecFlowview*Manual.accelerator: Ctrl<Key>M\n"
-"ecFlowview*Jobstatus.accelerator: Ctrl<Key>j\n"
-"ecFlowview*Job.accelerator: Ctrl<Key>J\n"
-"ecFlowview*Triggers.accelerator: Ctrl<Key>T\n"
-"ecFlowview*Why?.accelerator: Ctrl<Key>y\n"
-"ecFlowview*Variables.accelerator: Ctrl<Key>V\n"
-"ecFlowview*Messages.accelerator: Ctrl<Key>M\n"
-"ecFlowview*Edit.accelerator: Ctrl<Key>E\n"
-"ecFlowview*Search.accelerator: Ctrl<Key>c\n"
-"ecFlowview*Status.accelerator: Space<Key>\n"
-"ecFlowview*Login.accelerator: Ctrl<Key>L\n"
-"ecFlowview*Login.acceleratorText: Ctrl+L\n"
-"ecFlowview*Login.mnemonic: L\n"
-"ecFlowview*Login.title: Login...\n"
-"ecFlowview*Quit.accelerator: Ctrl<Key>Q\n"
-"ecFlowview*Quit.acceleratorText: Ctrl+Q\n"
-"ecFlowview*Quit.mnemonic: Q\n"
-"ecFlowview*Edit.accelerator: Ctrl<Key>E\n"
-"ecFlowview*Edit.mnemonic: E\n"
-"ecFlowview*pref.accelerator: Ctrl<Key>e\n"
-"ecFlowview*pref.mnemonic: e\n"
-"ecFlowview*pref.title: User preferences...\n"
-
-"ecFlowview*pref_shell.title: Preferences\n"
-
-"ecFlowview*Show.accelerator: Ctrl<Key>S\n"
-"ecFlowview*Show.mnemonic: S\n"
-"ecFlowview*Servers.accelerator: Ctrl<Key>v\n"
-"ecFlowview*Servers.mnemonic: v\n"
-"ecFlowview*Windows.accelerator: Ctrl<Key>W\n"
-"ecFlowview*Windows.mnemonic: W\n"
-"ecFlowview*Help.accelerator: Ctrl<Key>H\n"
-"ecFlowview*Help.mnemonic: H\n"
-
-"ecFlowview*Version.accelerator: Ctrl<Key>V\n"
-"ecFlowview*Version.mnemonic: V\n"
-
-"ecFlowview*file_menu.labelString: File\n"
-"ecFlowview*file_menu.mnemonic: F\n"
-"ecFlowview*Option.mnemonic: O\n"
-"ecFlowview*Print*.mnemonic: P\n"
-"ecFlowview*Save*.mnemonic: S\n"
-"ecFlowview*Close.mnemonic: C\n"
-"ecFlowview*help_menu.mnemonic: H\n"
-
-"ecFlowview*snapshot.accelerator: Ctrl<Key>t\n"
-"ecFlowview*snapshot.labelString: Snapshot\n"
-
-"ecFlowview*file_menu.title: File\n"
-"ecFlowview*file_menu.accelerator: Ctrl<Key>F\n"
-
-"ecFlowview*options_menu.labelString: Options\n"
-"ecFlowview*options_menu.mnemonic: O\n"
-
-"ecFlowview.*SimpleBase.baseTranslations: #augment \
- Shift<Btn5Down>: increment(-1) \\n\
- Shift<Btn4Down>: increment(1) \\n\
- <Btn5Down>: increment(-10) \\n\
- <Btn4Down>: increment(10) \n"
-
-"ecFlowview.*Hyper.baseTranslations: #augment \
- Shift<Btn5Down>: increment(-1) \\n\
- Shift<Btn4Down>: increment(1) \\n\
- <Btn5Down>: increment(-10) \\n\
- <Btn4Down>: increment(10) \n"
-
-"ecFlowview.*XmList.baseTranslations: #augment \
- Shift<Btn5Down>: ListNextPage() \\n\
- Shift<Btn4Down>: ListPrevPage() \\n\
- <Btn5Down>: ListNextItem() \\n\
- <Btn4Down>: ListPrevItem() \n"
-
-"ecFlowview.*XmScrollBar.baseTranslations: #augment \
- Shift<Btn5Down>: IncrementDownOrRight(0) IncrementDownOrRight(1) \\n\
- Shift<Btn4Down>: IncrementUpOrLeft(0) IncrementUpOrLeft(1) \\n\
- <Btn5Down>: PageDownOrRight(0) PageDownOrRight(1) \\n\
- <Btn4Down>: PageUpOrLeft(0) PageUpOrLeft(1) \n"
-
-"ecFlowview.*XmText.baseTranslations: #augment \
- <Key>osfUp: scroll-one-line-up()\\n\
- <Key>osfDown: scroll-one-line-down()\\n\
- <KeyUp>Prior: previous-page()\\n\
- <KeyUp>Next: next-page()\\n\
- <Key>Up: scroll-one-line-up() \\n\
- <Key>Down: scroll-one-line-down() \\n\
- <KeyUp>KP_Prior: previous-page()\\n\
- <KeyUp>KP_Next: next-page()\\n\
- <KeyUp>KP_Up: scroll-one-line-up() \\n\
- <KeyUp>KP_Down: scroll-one-line-down() \n\
- Shift<Btn5Down>: previous-page() \\n\
- Shift<Btn4Down>: next-page() \\n\
- <Btn5Down>: scroll-one-line-up() \\n\
- <Btn4Down>: scroll-one-line-down() \n"
-
-"ecFlowview.*DrawingAreaInput.baseTranslations: #augment \
- <Key>osfUp: scroll-one-line-up()\\n\
- <Key>osfDown: scroll-one-line-down()\\n\
- <KeyUp>Prior: previous-page()\\n\
- <KeyUp>Next: next-page()\\n\
- <Key>Up: scroll-one-line-up() \\n\
- <Key>Down: scroll-one-line-down() \\n\
- <KeyUp>KP_Prior: previous-page()\\n\
- <KeyUp>KP_Next: next-page()\\n\
- <KeyUp>KP_Up: scroll-one-line-up() \\n\
- <KeyUp>KP_Down: scroll-one-line-down() \n\
- Shift<Btn5Down>: previous-page() \\n\
- Shift<Btn4Down>: next-page() \\n\
- <Btn5Down>: scroll-one-line-up() \\n\
- <Btn4Down>: scroll-one-line-down() \n"
-"*XmSpinBox.accelerators: #augment \
- <Btn5Down>: SpinBPrior()\\n\
- <Btn5Up>:SpinBDisarm()\\n\
- <Btn4Down>: SpinBNext()\\n\
- <Btn4Up>: SpinBDisarm()\\n\
- <Key>osfUp:SpinBNext()\\n\
- <Key>osfDown: SpinBPrior()\\n\
- <KeyUp>osfUp: SpinBDisarm()\\n\
- <KeyUp>osfDown: SpinBDisarm()\\n\
- <Key>osfLeft: SpinBLeft()\\n\
- <Key>osfRight: SpinBRight()\\n\
- <KeyUp>osfLeft: SpinBDisarm()\\n\
- <KeyUp>osfRight: SpinBDisarm()\\n\
- <Key>osfBeginLine: SpinBFirst()\\n\
- <Key>osfEndLine: SpinBLast()\n"
-
-"ecFlowview*@zombied.labelString: Use default settings\n"
-"ecFlowview*@aliases.labelString: Use default settings\n"
-"ecFlowview*@late_family.labelString: Use default settings\n"
-"ecFlowview*zombied.labelString: Zombies\n"
-"ecFlowview*aliases.labelString: Aborted or restarted aliases\n"
-"ecFlowview*late_family.labelString: Late family\n"
-
-"ecFlowview*File.labelString: File\n"
-"ecFlowview*.XmText.background: OldLace\n"
-"ecFlowview*.XmTextField.background: OldLace\n"
-"ecFlowview*.scrollBarDisplayPolicy: STATIC\n"
-"ecFlowview*@aborted.labelString: Use default settings\n"
-"ecFlowview*@color_aborted.labelString: Use default settings\n"
-"ecFlowview*@color_active.labelString: Use default settings\n"
-"ecFlowview*@color_complete.labelString: Use default settings\n"
-"ecFlowview*@color_halted.labelString: Use default settings\n"
-"ecFlowview*@color_queued.labelString: Use default settings\n"
-"ecFlowview*@color_shutdown.labelString: Use default settings\n"
-"ecFlowview*@color_submitted.labelString: Use default settings\n"
-"ecFlowview*@color_suspended.labelString: Use default settings\n"
-"ecFlowview*@color_unknown.labelString: Use default settings\n"
-"ecFlowview*@color_meter_low.labelString: Use default settings\n"
-"ecFlowview*@color_threshold.labelString: Use default settings\n"
-"ecFlowview*@color_event.labelString: Use default settings\n"
-"ecFlowview*@direct_read.labelString: Use default settings\n"
-"ecFlowview*@drift.labelString: Use default settings\n"
-"ecFlowview*@late.labelString: Use default settings\n"
-"ecFlowview*@maximum.labelString: Use default settings\n"
-"ecFlowview*@jobfile_length.labelString: Use default settings\n"
-"ecFlowview*@new_suites.labelString: Use default settings\n"
-"ecFlowview*@normal_font_bold.labelString: Use default settings\n"
-"ecFlowview*@normal_font_plain.labelString: Use default settings\n"
-"ecFlowview*@poll.labelString: Use default settings\n"
-"ecFlowview*@restarted.labelString: Use default settings\n"
-"ecFlowview*@small_font_bold.labelString: Use default settings\n"
-"ecFlowview*@small_font_plain.labelString: Use default settings\n"
-"ecFlowview*@timeout.labelString: Use default settings\n"
-"ecFlowview*@timed_text_since.labelString: 600\n"
-"ecFlowview*@timed_text_from.labelString: 0\n"
-"ecFlowview*timed_text_from.labelString: 0\n"
-"ecFlowview*Aborted.labelString: Aborted\n"
-"ecFlowview*Active.labelString: Active\n"
-"ecFlowview*Apply.labelString: Apply\n"
-"ecFlowview*Backwards.labelString: Backwards\n"
-"ecFlowview*Colours.labelString: Colors\n"
-"ecFlowview*Complete.labelString: Complete\n"
-"ecFlowview*Get server status:.labelString: Getting server status\n"
-"ecFlowview*Hyper*highlightColor: Blue\n"
-"ecFlowview*Hyper*highlightFont: 7x13\n"
-"ecFlowview*Hyper*highlightOnEnter : false\n"
-"ecFlowview*Hyper*highlightThickness : 0\n"
-"ecFlowview*Hyper*navigationType : NONE\n"
-"ecFlowview*Hyper*normalFont: 7x13\n"
-"ecFlowview*Queued.labelString: Queued\n"
-"ecFlowview*Regular expression.labelString: Regular expression\n"
-"ecFlowview*SimpleTime.fontList: -*-*-*-*-*-*-7-*-*-*-*-*-*-*\n"
-"ecFlowview*Submitted.labelString: Submitted\n"
-"ecFlowview*Suspended.labelString: Suspended\n"
-"ecFlowview*Unknown.labelString: Unknown\n"
-"ecFlowview*Update.labelString: Update\n"
-"ecFlowview*Use external editor.labelString: External editor...\n"
-"ecFlowview*Use external viewer.labelString: External viewer...\n"
-"ecFlowview*Waiting nodes.labelString: Waiting nodes\n"
-"ecFlowview*XmList.fontList: 7x13=normal,7x13bold=bold\n"
-"ecFlowview*XmText.fontList: 7x13\n"
-"ecFlowview*XmToggleButton.fillOnSelect: true\n"
-"ecFlowview*XmToggleButton.selectColor: Blue\n"
-"ecFlowview*XmToggleButtonGadget.fillOnSelect: true\n"
-"ecFlowview*XmToggleButtonGadget.fontList: -*-helvetica-medium-r-normal-*-12-*-*-*-*-*-*-*\n"
-"ecFlowview*XmToggleButtonGadget.selectColor: Green\n"
-"ecFlowview*aborted.labelString: Aborted tasks\n"
-"ecFlowview*alias_.labelString: Send as alias\n"
-"ecFlowview*all_off.labelString: All off\n"
-"ecFlowview*all_on.labelString: All on\n"
-"ecFlowview*ask_shell.title: ask\n"
-"ecFlowview*background: #e5e5e5e5e5e5\n"
-"ecFlowview*bottomShadowColor: #7e7e7e7e7e7e\n"
-"ecFlowview*button3.labelString: Help...\n"
-"ecFlowview*button_close.labelString: Close\n"
-"ecFlowview*button_find.labelString: Find...\n"
-"ecFlowview*button_search.labelString: Search...\n"
-"ecFlowview*close.labelString: Close\n"
-"ecFlowview*close_on_apply_.labelString: Close on Apply/Submit\n"
-"ecFlowview*collector_shell.title: Collector (ctrl-click1)\n"
- /* "ecFlowview*collector_shell.title: Collector\n" */
-"ecFlowview*confirm_shell.title: Confirm\n"
-"ecFlowview*current_node.labelString: Frozen\n"
-"ecFlowview*delete_.labelString: Delete\n"
-"ecFlowview*find_.labelString: Find\n"
-"ecFlowview*depend_shell.title: Details\n"
-"ecFlowview*dependencies_button_.labelString: Dependencies\n"
-"ecFlowview*detached_.labelString: Detached\n"
-"ecFlowview*direct_read.labelString: Read files from disk when possible.\n"
-"ecFlowview*drift.labelString: Reduce call frequency when inactive\n"
-"ecFlowview*error_shell.title: Error\n"
-"ecFlowview*find_message.fontList: -*-helvetica-bold-r-normal-*-12-*-*-*-*-*-*-*\n"
-"ecFlowview*find_message.foreground: red\n"
-"ecFlowview*find_message.labelString: -\n"
-"ecFlowview*find_shell.title: Find...\n"
-"ecFlowview*fold_around_.labelString: Fold around\n"
-"ecFlowview*XmList.fontList: 7x13=normal,7x13bold=bold\n"
-"ecFlowview*XmText.fontList: 7x13\n"
-"ecFlowview*help_menu.labelString: Help\n"
-"ecFlowview*hide_other_.labelString: Hide other suites\n"
-"ecFlowview*indicatorSize: 12\n"
-"ecFlowview*late.labelString: Late tasks\n"
-"ecFlowview*mail_shell.title: Chat\n"
-"ecFlowview*menu_fold_all.labelString: Fold all\n"
-"ecFlowview*menu_show_current.labelString: Show selected node\n"
-"ecFlowview*menu_unfold_all.accelerator: Ctrl<Key>U\n"
-"ecFlowview*menu_unfold_all.labelString: Unfold all\n"
-"ecFlowview*new_suites.labelString: Register to new suites\n"
-"ecFlowview*new_window.labelString: New window...\n"
-"ecFlowview*optionMenu1.labelString: Action:\n"
-"ecFlowview*poll.labelString: Get server status regularly\n"
-"ecFlowview*preprocess_.labelString: Pre-process\n"
-"ecFlowview*restarted.labelString: Restarted tasks\n"
-"ecFlowview*search_shell.title: Search...\n"
-"ecFlowview*set_.labelString: Set\n"
-"ecFlowview*timeline_label.fontList : 7x13=normal,7x13bold=bold\n"
-"ecFlowview*toggle2.labelString: Limits\n"
-"ecFlowview*toggle21.labelString: Suites\n"
-"ecFlowview*toggle22.labelString: Families\n"
-"ecFlowview*toggle23.labelString: Tasks\n"
-"ecFlowview*toggle24.labelString: Aliases\n"
-"ecFlowview*toggle25.labelString: Labels\n"
-"ecFlowview*toggle26.labelString: Meters\n"
-"ecFlowview*toggle27.labelString: Events\n"
-"ecFlowview*toggle28.labelString: Repeats\n"
-"ecFlowview*toggle29.labelString: Times\n"
-"ecFlowview*toggle3.labelString: Full names\n"
-"ecFlowview*toggle3.labelString: Limiters\n"
-"ecFlowview*toggle30.labelString: Dates\n"
-"ecFlowview*toggle31.labelString: Triggers\n"
-"ecFlowview*toggle32.labelString: Variables\n"
-"ecFlowview*toggle41.labelString: Time dependent\n"
-"ecFlowview*toggle42.labelString: Late nodes\n"
-"ecFlowview*toggle43.labelString: Zombie\n"
-"ecFlowview*toggle44.labelString: Rerun tasks\n"
-"ecFlowview*toggle45.labelString: Nodes with messages\n"
-"ecFlowview*toggle66.labelString: Servers\n"
-"ecFlowview*tools_*shadowThickness:1 \n"
-"ecFlowview*topShadowColor: white\n"
-"ecFlowview*triggered.labelString: Show triggered nodes\n"
-"ecFlowview*triggers.labelString: Show triggering nodes\n"
-"ecFlowview*vname.labelString: Variable name:\n"
-"ecFlowview*vvalue.labelString: Variable value:\n"
-"ecFlowview*warn.labelString: Don't forget to hit <return> when you enter a value in a text field.\n"
-"ecFlowview*warn2.labelString: Don't forget to hit <return> when you enter a value in a text field.\n"
-"ecFlowview*what_.labelString: What:\n"
-"ecFlowview*where_.labelString: Where:\n"
-"ecFlowview*why_label_.labelString: Use the Info window...\n"
-"ecFlowview.smallFont: -*-helvetica-medium-r-normal-*-10-*-*-*-*-*-*-*\n"
-"ecFlowview.normalFont: -*-helvetica-medium-r-normal-*-12-*-*-*-*-*-*-*\n"
-"ecFlowview*tools_.Info.accelerator: I\n"
-"ecFlowview*tools_.Script.accelerator: S\n"
-"ecFlowview*tools_.Manual.accelerator: M\n"
-"ecFlowview*tools_.JobStatus.accelerator: J\n"
-"ecFlowview*tools_.Output.accelerator: O\n"
-"ecFlowview*tools_.Triggers.accelerator: T\n"
-"ecFlowview*tools_.Why?.accelerator: W\n"
-"ecFlowview*tools_.Variables.accelerator: V\n"
-"ecFlowview*tools_.Messages.accelerator: M\n"
-"ecFlowview*tools_.Edit.accelerator: E\n"
-"ecFlowview*tools_.Status.accelerator: Return<Key>\n"
-"ecFlowview*tree_.accelerator: C\n"
-"ecFlowview*tree_.accelerator: Z\n"
-"ecFlowview*tree_.baseTranslations: #augment \
-C: collector::show(selection::current_node())\\n\
-A: selection::notify_new_selection(0)\\n\
-"
-
-;
-
-#else
-
-static char* xresources = (char*) "\n"
-"XCdp*File.accelerator: Ctrl<Key>f\n"
-"XCdp*File.mnemonic: F\n"
-"XCdp*Info.accelerator: Ctrl<Key>I\n"
-"XCdp*Script.accelerator: Ctrl<Key>S\n"
-"XCdp*Manual.accelerator: Ctrl<Key>M\n"
-"XCdp*Jobstatus.accelerator: Ctrl<Key>j\n"
-"XCdp*Job.accelerator: Ctrl<Key>J\n"
-"XCdp*Triggers.accelerator: Ctrl<Key>T\n"
-"XCdp*Why?.accelerator: Ctrl<Key>y\n"
-"XCdp*Variables.accelerator: Ctrl<Key>V\n"
-"XCdp*Messages.accelerator: Ctrl<Key>M\n"
-"XCdp*Edit.accelerator: Ctrl<Key>E\n"
-"XCdp*Search.accelerator: Ctrl<Key>c\n"
-"XCdp*Status.accelerator: Space<Key>\n"
-"XCdp*Login.accelerator: Ctrl<Key>L\n"
-"XCdp*Login.acceleratorText: Ctrl+L\n"
-"XCdp*Login.mnemonic: L\n"
-"XCdp*Login.title: Login...\n"
-"XCdp*Quit.accelerator: Ctrl<Key>Q\n"
-"XCdp*Quit.acceleratorText: Ctrl+Q\n"
-"XCdp*Quit.mnemonic: Q\n"
-"XCdp*Edit.accelerator: Ctrl<Key>E\n"
-"XCdp*Edit.mnemonic: E\n"
-"XCdp*pref.accelerator: Ctrl<Key>e\n"
-"XCdp*pref.mnemonic: e\n"
-"XCdp*pref.title: User preferences...\n"
-
-"XCdp*pref_shell.title: Preferences\n"
-
-"XCdp*Show.accelerator: Ctrl<Key>S\n"
-"XCdp*Show.mnemonic: S\n"
-"XCdp*Servers.accelerator: Ctrl<Key>v\n"
-"XCdp*Servers.mnemonic: v\n"
-"XCdp*Windows.accelerator: Ctrl<Key>W\n"
-"XCdp*Windows.mnemonic: W\n"
-"XCdp*Help.accelerator: Ctrl<Key>H\n"
-"XCdp*Help.mnemonic: H\n"
-
-"XCdp*Version.accelerator: Ctrl<Key>V\n"
-"XCdp*Version.mnemonic: V\n"
-
-"XCdp*file_menu.labelString: File\n"
-"XCdp*file_menu.mnemonic: F\n"
-"XCdp*Option.mnemonic: O\n"
-"XCdp*Print*.mnemonic: P\n"
-"XCdp*Save*.mnemonic: S\n"
-"XCdp*close.mnemonic: C\n"
-"XCdp*help_menu.mnemonic: H\n"
-
-"XCdp*snapshot.accelerator: Ctrl<Key>t\n"
-"XCdp*snapshot.labelString: Snapshot\n"
-
-"XCdp*file_menu.title: File\n"
-"XCdp*file_menu.accelerator: Ctrl<Key>F\n"
-
-"XCdp*options_menu.labelString: Options\n"
-"XCdp*options_menu.mnemonic: O\n"
-
-"XCdp.*SimpleBase.baseTranslations: #augment \
- Shift<Btn5Down>: increment(-1) \\n\
- Shift<Btn4Down>: increment(1) \\n\
- <Btn5Down>: increment(-10) \\n\
- <Btn4Down>: increment(10) \n"
-
-"XCdp.*Hyper.baseTranslations: #augment \
- Shift<Btn5Down>: increment(-1) \\n\
- Shift<Btn4Down>: increment(1) \\n\
- <Btn5Down>: increment(-10) \\n\
- <Btn4Down>: increment(10) \n"
-
-"XCdp.*XmList.baseTranslations: #augment \
- Shift<Btn5Down>: ListNextPage() \\n\
- Shift<Btn4Down>: ListPrevPage() \\n\
- <Btn5Down>: ListNextItem() \\n\
- <Btn4Down>: ListPrevItem() \n"
-
-"XCdp.*XmScrollBar.baseTranslations: #augment \
- Shift<Btn5Down>: IncrementDownOrRight(0) IncrementDownOrRight(1) \\n\
- Shift<Btn4Down>: IncrementUpOrLeft(0) IncrementUpOrLeft(1) \\n\
- <Btn5Down>: PageDownOrRight(0) PageDownOrRight(1) \\n\
- <Btn4Down>: PageUpOrLeft(0) PageUpOrLeft(1) \n"
-
-"XCdp.*XmText.baseTranslations: #augment \
- <Key>osfUp: scroll-one-line-up()\\n\
- <Key>osfDown: scroll-one-line-down()\\n\
- <KeyUp>Prior: previous-page()\\n\
- <KeyUp>Next: next-page()\\n\
- <Key>Up: scroll-one-line-up() \\n\
- <Key>Down: scroll-one-line-down() \\n\
- <KeyUp>KP_Prior: previous-page()\\n\
- <KeyUp>KP_Next: next-page()\\n\
- <KeyUp>KP_Up: scroll-one-line-up() \\n\
- <KeyUp>KP_Down: scroll-one-line-down() \n\
- Shift<Btn5Down>: previous-page() \\n\
- Shift<Btn4Down>: next-page() \\n\
- <Btn5Down>: scroll-one-line-up() \\n\
- <Btn4Down>: scroll-one-line-down() \n"
-
-"XCdp.*DrawingAreaInput.baseTranslations: #augment \
- <Key>osfUp: scroll-one-line-up()\\n\
- <Key>osfDown: scroll-one-line-down()\\n\
- <KeyUp>Prior: previous-page()\\n\
- <KeyUp>Next: next-page()\\n\
- <Key>Up: scroll-one-line-up() \\n\
- <Key>Down: scroll-one-line-down() \\n\
- <KeyUp>KP_Prior: previous-page()\\n\
- <KeyUp>KP_Next: next-page()\\n\
- <KeyUp>KP_Up: scroll-one-line-up() \\n\
- <KeyUp>KP_Down: scroll-one-line-down() \n\
- Shift<Btn5Down>: previous-page() \\n\
- Shift<Btn4Down>: next-page() \\n\
- <Btn5Down>: scroll-one-line-up() \\n\
- <Btn4Down>: scroll-one-line-down() \n"
-
-"*XmSpinBox.accelerators: #augment \
- <Btn5Down>: SpinBPrior()\\n\
- <Btn5Up>:SpinBDisarm()\\n\
- <Btn4Down>: SpinBNext()\\n\
- <Btn4Up>: SpinBDisarm()\\n\
- <Key>osfUp:SpinBNext()\\n\
- <Key>osfDown: SpinBPrior()\\n\
- <KeyUp>osfUp: SpinBDisarm()\\n\
- <KeyUp>osfDown: SpinBDisarm()\\n\
- <Key>osfLeft: SpinBLeft()\\n\
- <Key>osfRight: SpinBRight()\\n\
- <KeyUp>osfLeft: SpinBDisarm()\\n\
- <KeyUp>osfRight: SpinBDisarm()\\n\
- <Key>osfBeginLine: SpinBFirst()\\n\
- <Key>osfEndLine: SpinBLast()\n"
-
-"XCdp*@zombied.labelString: Use default settings\n"
-"XCdp*@aliases.labelString: Use default settings\n"
-"XCdp*@late_family.labelString: Use default settings\n"
-"XCdp*zombied.labelString: Zombies\n"
-"XCdp*aliases.labelString: Aborted or restarted aliases\n"
-"XCdp*late_family.labelString: Late family\n"
-
-"XCdp*File.labelString: File\n"
-"XCdp*.XmText.background: OldLace\n"
-"XCdp*.XmTextField.background: OldLace\n"
-"XCdp*.scrollBarDisplayPolicy: STATIC\n"
-"XCdp*@aborted.labelString: Use default settings\n"
-"XCdp*@color_aborted.labelString: Use default settings\n"
-"XCdp*@color_active.labelString: Use default settings\n"
-"XCdp*@color_complete.labelString: Use default settings\n"
-"XCdp*@color_halted.labelString: Use default settings\n"
-"XCdp*@color_queued.labelString: Use default settings\n"
-"XCdp*@color_shutdown.labelString: Use default settings\n"
-"XCdp*@color_submitted.labelString: Use default settings\n"
-"XCdp*@color_suspended.labelString: Use default settings\n"
-"XCdp*@color_unknown.labelString: Use default settings\n"
-"XCdp*@color_meter_low.labelString: Use default settings\n"
-"XCdp*@color_threshold.labelString: Use default settings\n"
-"XCdp*@color_event.labelString: Use default settings\n"
-"XCdp*@direct_read.labelString: Use default settings\n"
-"XCdp*@drift.labelString: Use default settings\n"
-"XCdp*@late.labelString: Use default settings\n"
-"XCdp*@maximum.labelString: Use default settings\n"
-"XCdp*@jobfile_length.labelString: Use default settings\n"
-"XCdp*@new_suites.labelString: Use default settings\n"
-"XCdp*@normal_font_bold.labelString: Use default settings\n"
-"XCdp*@normal_font_plain.labelString: Use default settings\n"
-"XCdp*@poll.labelString: Use default settings\n"
-"XCdp*@restarted.labelString: Use default settings\n"
-"XCdp*@small_font_bold.labelString: Use default settings\n"
-"XCdp*@small_font_plain.labelString: Use default settings\n"
-"XCdp*@timeout.labelString: Use default settings\n"
-"XCdp*Aborted.labelString: Aborted\n"
-"XCdp*Active.labelString: Active\n"
-"XCdp*Apply.labelString: Apply\n"
-"XCdp*Backwards.labelString: Backwards\n"
-"XCdp*Colours.labelString: Colors\n"
-"XCdp*Complete.labelString: Complete\n"
-"XCdp*Get server status:.labelString: Getting server status\n"
-"XCdp*Hyper*highlightColor: Blue\n"
-"XCdp*Hyper*highlightFont: 7x13\n"
-"XCdp*Hyper*highlightOnEnter : false\n"
-"XCdp*Hyper*highlightThickness : 0\n"
-"XCdp*Hyper*navigationType : NONE\n"
-"XCdp*Hyper*normalFont: 7x13\n"
-"XCdp*Queued.labelString: Queued\n"
-"XCdp*Regular expression.labelString: Regular expression\n"
-"XCdp*SimpleTime.fontList: -*-*-*-*-*-*-7-*-*-*-*-*-*-*\n"
-"XCdp*Submitted.labelString: Submitted\n"
-"XCdp*Suspended.labelString: Suspended\n"
-"XCdp*Unknown.labelString: Unknown\n"
-"XCdp*Update.labelString: Update\n"
-"XCdp*Use external editor.labelString: External editor...\n"
-"XCdp*Use external viewer.labelString: External viewer...\n"
-"XCdp*Waiting nodes.labelString: Waiting nodes\n"
-"XCdp*XmToggleButton.fillOnSelect: true\n"
-"XCdp*XmToggleButton.selectColor: Blue\n"
-"XCdp*XmToggleButtonGadget.fillOnSelect: true\n"
-"XCdp*XmToggleButtonGadget.fontList:-*-helvetica-normal-r-normal-*-12-*-*-*-*-*-*-*\n"
-"XCdp*XmToggleButtonGadget.selectColor: Green\n"
-"XCdp*aborted.labelString: Aborted tasks\n"
-"XCdp*alias_.labelString: Send as alias\n"
-"XCdp*all_off.labelString: All off\n"
-"XCdp*all_on.labelString: All on\n"
-"XCdp*ask_shell.title: ask\n"
-"XCdp*background: #e5e5e5e5e5e5\n"
-"XCdp*bottomShadowColor: #7e7e7e7e7e7e\n"
-"XCdp*button3.labelString: Help...\n"
-"XCdp*button_close.labelString: Close\n"
-"XCdp*button_find.labelString: Find...\n"
-"XCdp*button_search.labelString: Search...\n"
-"XCdp*close.labelString: Close\n"
-"XCdp*close_on_apply_.labelString: Close on Apply/Submit\n"
-"XCdp*collector_shell.title: Collector (ctrl-click1)\n"
- /* "XCdp*collector_shell.title: Collector\n" */
-"XCdp*confirm_shell.title: Confirm\n"
-"XCdp*current_node.labelString: Frozen\n"
-"XCdp*delete_.labelString: Delete\n"
-"XCdp*find_.labelString: Find\n"
-"XCdp*depend_shell.title: Details\n"
-"XCdp*dependencies_button_.labelString: Dependencies\n"
-"XCdp*detached_.labelString: Detached\n"
-"XCdp*direct_read.labelString: Read output and other files from disk when possible.\n"
-"XCdp*drift.labelString: Reduce call frequency when inactive\n"
-"XCdp*error_shell.title: Error\n"
-"XCdp*find_message.fontList:-*-helvetica-bold-*-normal-*-12-*-*-*-*-*-*-*\n"
-"XCdp*find_message.foreground: red\n"
-"XCdp*find_message.labelString: -\n"
-"XCdp*find_shell.title: Find...\n"
-"XCdp*fold_around_.labelString: Fold around\n"
-"XCdp*XmList.fontList: 7x13=normal,7x13bold=bold\n"
-"XCdp*XmText.fontList: 7x13\n"
-"XCdp*XmText.font*: -*-helvetica-medium-*-normal-*-12-*-*-*-*-*-*-*\n"
-"XCdp*fontList: -*-helvetica-normal-r-normal-*-12-*-*-*-*-*-*-*\n"
-"XCdp*help_menu.labelString: Help\n"
-"XCdp*hide_other_.labelString: Hide other suites\n"
-"XCdp*indicatorSize: 12\n"
-"XCdp*late.labelString: Late tasks\n"
-"XCdp*mail_shell.title: Chat\n"
-"XCdp*menu_fold_all.labelString: Fold all\n"
-"XCdp*menu_show_current.labelString: Show selected node\n"
-"XCdp*menu_unfold_all.accelerator: Ctrl<Key>U\n"
-"XCdp*menu_unfold_all.labelString: Unfold all\n"
-"XCdp*new_suites.labelString: Register to new suites\n"
-"XCdp*new_window.labelString: New window...\n"
-"XCdp*optionMenu1.labelString: Action:\n"
-"XCdp*poll.labelString: Get server status regularly\n"
-"XCdp*preprocess_.labelString: Pre-process\n"
-"XCdp*restarted.labelString: Restarted tasks\n"
-"XCdp*search_shell.title: Search...\n"
-"XCdp*set_.labelString: Set\n"
-"XCdp*timeline_label.fontList : 7x13=normal,7x13bold=bold\n"
-"XCdp*toggle2.labelString: Limits\n"
-"XCdp*toggle21.labelString: Suites\n"
-"XCdp*toggle22.labelString: Families\n"
-"XCdp*toggle23.labelString: Tasks\n"
-"XCdp*toggle24.labelString: Aliases\n"
-"XCdp*toggle25.labelString: Labels\n"
-"XCdp*toggle26.labelString: Meters\n"
-"XCdp*toggle27.labelString: Events\n"
-"XCdp*toggle28.labelString: Repeats\n"
-"XCdp*toggle29.labelString: Times\n"
-"XCdp*toggle3.labelString: Full names\n"
-"XCdp*toggle3.labelString: Limiters\n"
-"XCdp*toggle30.labelString: Dates\n"
-"XCdp*toggle31.labelString: Triggers\n"
-"XCdp*toggle32.labelString: Variables\n"
-"XCdp*toggle41.labelString: Time dependent\n"
-"XCdp*toggle42.labelString: Late nodes\n"
-"XCdp*toggle43.labelString: Zombie\n"
-"XCdp*toggle44.labelString: Rerun tasks\n"
-"XCdp*toggle45.labelString: Nodes with messages\n"
-"XCdp*toggle66.labelString: Servers\n"
-"XCdp*tools_*shadowThickness:1 \n"
-"XCdp*topShadowColor: white\n"
-"XCdp*triggered.labelString: Show triggered nodes\n"
-"XCdp*triggers.labelString: Show triggering nodes\n"
-"XCdp*vname.labelString: Variable name:\n"
-"XCdp*vvalue.labelString: Variable value:\n"
-"XCdp*warn.labelString: Don't forget to hit <return> when you enter a value in a text field.\n"
-"XCdp*warn2.labelString: Don't forget to hit <return> when you enter a value in a text field.\n"
-"XCdp*what_.labelString: What:\n"
-"XCdp*where_.labelString: Where:\n"
-"XCdp*why_label_.labelString: Use the Info window...\n"
-"XCdp.smallFont: -*-helvetica-medium-r-normal-*-11-*-*-*-*-*-*-*\n"
-"XCdp*tools_.Info.accelerator: I\n"
-"XCdp*tools_.Script.accelerator: S\n"
-"XCdp*tools_.Manual.accelerator: M\n"
-"XCdp*tools_.JobStatus.accelerator: J\n"
-"XCdp*tools_.Output.accelerator: O\n"
-"XCdp*tools_.Triggers.accelerator: T\n"
-"XCdp*tools_.Why?.accelerator: W\n"
-"XCdp*tools_.Variables.accelerator: V\n"
-"XCdp*tools_.Messages.accelerator: M\n"
-"XCdp*tools_.Edit.accelerator: E\n"
-"XCdp*tools_.Status.accelerator: Return<Key>\n"
-"XCdp*tree_.accelerator: C\n"
-"XCdp*tree_.accelerator: Z\n"
-"XCdp*tree_.baseTranslations: #augment \
-C: collector::show(selection::current_node())\\n\
-A: selection::notify_new_selection(0)\\n\
-"
-
-;
-
-/*
- xrdb -merge ~/.Xdefaults
-*/
-#endif
diff --git a/ecflow_4_0_7/view/src/zombie.h b/ecflow_4_0_7/view/src/zombie.h
deleted file mode 100644
index 8f4f906..0000000
--- a/ecflow_4_0_7/view/src/zombie.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef zombie_H
-#define zombie_H
-
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #3 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "node_alert.h"
-#include "node.h"
-
-class zombie : public node_alert<zombie> {
-public:
- zombie() ;
- ~zombie();
-
-private:
-
- zombie(const zombie&);
- zombie& operator=(const zombie&);
-
- virtual bool keep(node* n); // { return n->isZombie(); }
-
-};
-
-inline void destroy(zombie**) {}
-
-#endif
diff --git a/ecflow_4_0_7/view/src/zombies_panel.cc b/ecflow_4_0_7/view/src/zombies_panel.cc
deleted file mode 100644
index 1703574..0000000
--- a/ecflow_4_0_7/view/src/zombies_panel.cc
+++ /dev/null
@@ -1,125 +0,0 @@
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #11 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-
-#include "zombies_panel.h"
-#include "node.h"
-#include "host.h"
-#include "ecflowview.h"
-#include <Xm/Label.h>
-#include <Xm/Text.h>
-#include <Xm/List.h>
-extern "C" {
-#include "xec.h"
-}
-// #include <sstream>
-
-zombies_panel::zombies_panel(panel_window& w):
- panel(w),
- name_(0)
-{
-}
-
-zombies_panel::~zombies_panel()
-{
- XtFree(name_);
-}
-
-void zombies_panel::create (Widget parent, char *widget_name )
-{
- zombies_form_c::create(parent,widget_name);
-}
-
-void zombies_panel::clear()
-{
- selection_.clear();
- XmListDeleteAllItems(list_);
- XtSetSensitive(buttons_,False);
-}
-
-void zombies_panel::show(node& n)
-{
- std::vector<std::string> list;
- if (!n.serv().get_zombies_list(list)) {
- return;
- }
- clear();
-
- xec_AddFontListItem(list_,(char*)list[0].c_str(),true);
- for(unsigned int i= 1; i < list.size(); ++i)
- xec_AddListItem(list_,(char*)list[i].c_str());
-}
-
-
-Boolean zombies_panel::enabled(node& n)
-{
- return n.type() == NODE_SUPER;
-}
-
-
-void zombies_panel::browseCB( Widget, XtPointer data)
-{
- XmListCallbackStruct *cb = (XmListCallbackStruct *) data;
- char *p = xec_GetString(cb->item);
- if(name_) XtFree(name_);
- name_ = XtNewString(node::find_name(p));
- if (name_)
- selection_.insert(name_);
- XtSetSensitive(buttons_,name_ != 0);
- XtFree(p);
-}
-
-void zombies_panel::deleteCB( Widget, XtPointer data)
-{
- call(ZOMBIE_DELETE, data);
-}
-
-void zombies_panel::acceptCB( Widget, XtPointer data)
-{
- call(ZOMBIE_FOB, data);
-}
-
-void zombies_panel::rescueCB( Widget, XtPointer data)
-{
- call(ZOMBIE_RESCUE, data);
-}
-
-void zombies_panel::terminateCB( Widget, XtPointer data)
-{
- call(ZOMBIE_FAIL, data);
-}
-
-void zombies_panel::killCB( Widget, XtPointer data)
-{
- call(ZOMBIE_KILL, data);
-}
-
-void zombies_panel::call(int mode, XtPointer data)
-{
- if(!name_)
- XtSetSensitive(buttons_,false);
-
- if(get_node()) {
- std::set<std::string>::const_iterator item;
- for (item = selection_.begin(); item != selection_.end(); ++item)
- get_node()->serv().zombies(mode, (*item).c_str());
-
- } else
- clear();
-
- post_update();
-}
-
-// static panel_maker<zombies_panel> maker(PANEL_ZOMBIES);
diff --git a/ecflow_4_0_7/view/src/zombies_panel.h b/ecflow_4_0_7/view/src/zombies_panel.h
deleted file mode 100644
index e499bf2..0000000
--- a/ecflow_4_0_7/view/src/zombies_panel.h
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef zombies_panel_H
-#define zombies_panel_H
-
-#include "uizombies.h"
-
-#ifndef panel_H
-#include "panel.h"
-#endif
-
-#include <set>
-
-//=============================================================================================
-// Name :
-// Author :
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//=============================================================================================
-
-class zombies_panel : public panel, public zombies_form_c {
-public:
-
- zombies_panel(panel_window&);
-
- ~zombies_panel(); // Change to virtual if base class
-
- virtual const char* name() const { return "Zombies"; }
- virtual void show(node&);
- virtual void clear();
- virtual Boolean enabled(node&);
- virtual Widget widget() { return zombies_form_c::xd_rootwidget(); }
-
- virtual void create (Widget parent, char *widget_name = NULL);
-
-private:
-
- zombies_panel(const zombies_panel&);
- zombies_panel& operator=(const zombies_panel&);
-
- char* name_;
-
- void call(int, XtPointer);
-
- virtual void browseCB( Widget, XtPointer );
- virtual void deleteCB( Widget, XtPointer );
- virtual void acceptCB( Widget, XtPointer );
- virtual void rescueCB( Widget, XtPointer );
- virtual void terminateCB( Widget, XtPointer );
- virtual void killCB( Widget, XtPointer );
-
- std::set<std::string> selection_;
-};
-
-inline void destroy(zombies_panel**) {}
-#endif
diff --git a/ecflow_4_0_7/view/test/TestRunner.cpp b/ecflow_4_0_7/view/test/TestRunner.cpp
deleted file mode 100644
index 071c110..0000000
--- a/ecflow_4_0_7/view/test/TestRunner.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-#define BOOST_TEST_MODULE TestView
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #4 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description :
-//============================================================================
-#include "ViewTestFixture.hpp"
-#include <boost/test/unit_test.hpp>
-
-// Global test fixture. Dues to boost deficiency this can't be accessed. hence
-// TestFixture makes use of global data.
-BOOST_GLOBAL_FIXTURE( ViewTestFixture );
diff --git a/ecflow_4_0_7/view/test/TestView.cpp b/ecflow_4_0_7/view/test/TestView.cpp
deleted file mode 100644
index 0f3ea16..0000000
--- a/ecflow_4_0_7/view/test/TestView.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #5 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//============================================================================
-#include <iostream>
-#include <limits> // for std::numeric_limits<int>::max()
-#include <fstream>
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <fcntl.h>
-
-#include "boost/filesystem/operations.hpp"
-#include "boost/filesystem/path.hpp"
-#include <boost/test/unit_test.hpp>
-#include "ServerTestHarness.hpp"
-#include "DurationTimer.hpp"
-#include "Defs.hpp"
-#include "Suite.hpp"
-#include "Family.hpp"
-#include "Task.hpp"
-#include "File.hpp"
-
-using namespace std;
-using namespace ecf;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE( TestView )
-
-static std::string ECFLOWVIEW_NAME = "ecflowview";
-
-std::string find_ecflowview_path()
-{
- std::string binDir;
- fs::path current_path = fs::current_path();
- if ( current_path.stem() == "Test"
- || current_path.stem() == "view")
- binDir = "../view/bin/";
- else binDir = "view/bin/";
-
- // We have 3 variants debug,release,profile
-#ifdef DEBUG
- return File::findPath( binDir, ECFLOWVIEW_NAME, "debug" );
-#else
- std::string path = File::findPath( binDir, ECFLOWVIEW_NAME, "release" );
- if (path.empty()) {
- path = File::findPath( binDir, ECFLOWVIEW_NAME, "profile" );
- }
- return path;
-#endif
-}
-
-void send_cmd(int fd, char* cmd) {
- std::cout << cmd;
- write(fd, cmd, strlen(cmd));
- ::sleep(2);
-}
-
-BOOST_AUTO_TEST_CASE( test_view )
-{
- DurationTimer timer;
- cout << "View:: ...test_view\n"<< flush;
-
- std::string theViewInvokePath = find_ecflowview_path();
- if (theViewInvokePath.empty()) {
- std::cout << "ecflowview is not generated, test stops silently\n";
- return;
- }
-
- Defs theDefs; {
- suite_ptr suite = theDefs.add_suite( "test_view" ) ;
- suite->add_variable("SLEEPTIME","0");
- task_ptr task_a = suite->add_task("task_a");
- task_a->addMeter( Meter("meter",0,20,20) );
- task_a->addEvent( Event(1,"event") );
- task_a->addLabel( Label("task_a_label","Label1") );
- }
-
- // Start server if not already started, load the defs, and start playing
- // The test harness will create corresponding directory structure & default ecf file
- ServerTestHarness serverTestHarness;
- serverTestHarness.run(theDefs,
- ServerTestHarness::testDataDefsLocation("test_view.def"),
- 30, // timeout
- false // do not wait for test completion
- );
-
- // Ecflowview set up
- std::string HOME = getenv("HOME");
- std::string rcdir = HOME + "/.ecflowrc_test";
- if ( !fs::exists( rcdir ) ) fs::create_directory(rcdir);
-
- std::string pipename = "/tmp/ecflowview_pipe";
- std::string servers = rcdir + "/servers";
- std::string options = rcdir + "/localhost.options";
-
- std::string cmd = "echo localhost localhost ${ECF_PORT:-3141} > " + servers;
- cmd += "\necho -e 'connect:false\nsuites: test_view\n' > " + options;
- cmd += "\nexport ECFLOWVIEW_INPUT=" + pipename + " ECFLOWRC=" + rcdir;
- cmd += "\nif [ ! -p $ECFLOWVIEW_INPUT ]; then rm -f $ECFLOWVIEW_INPUT; mknod $ECFLOWVIEW_INPUT p; fi;\n";
- cmd += theViewInvokePath;
- cmd += "&";
-
-// std::cout << cmd;
- if ( system( cmd.c_str() ) != 0) assert(false); // failed
- ::sleep(2);
- int fd = open(pipename.c_str(), O_WRONLY);
- send_cmd(fd, (char*)"login localhost\n");
- send_cmd(fd, (char*)"logout localhost\n");
- send_cmd(fd, (char*)"quit\n");
-
- // remove generated data
- fs::remove(pipename.c_str());
- fs::remove_all(rcdir);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/ecflow_4_0_7/view/test/ViewTestFixture.hpp b/ecflow_4_0_7/view/test/ViewTestFixture.hpp
deleted file mode 100644
index 6c9c012..0000000
--- a/ecflow_4_0_7/view/test/ViewTestFixture.hpp
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef VIEWTESTFIXTURE_HPP_
-#define VIEWTESTFIXTURE_HPP_
-//============================================================================
-// Name :
-// Author : Avi
-// Revision : $Revision: #13 $
-//
-// Copyright 2009-2012 ECMWF.
-// This software is licensed under the terms of the Apache Licence version 2.0
-// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-// In applying this licence, ECMWF does not waive the privileges and immunities
-// granted to it by virtue of its status as an intergovernmental organisation
-// nor does it submit to any jurisdiction.
-//
-// Description : This Fixture facilitates the test of client/server on different platforms
-//
-//============================================================================
-
-#include <string>
-#include "TestFixture.hpp"
-class Defs;
-
-struct ViewTestFixture : public TestFixture {
-
- // Constructor will invoke the server, destructor will kill the server
- // Since this class is static, the constructor/destructor can not call
- // any of BOOST MACRO, since the unit test will not be there.
- // When running across platforms will will assume server is already running
- ViewTestFixture() : TestFixture("view") {}
- ~ViewTestFixture() {}
-};
-
-#endif
diff --git a/install.sh b/install.sh
new file mode 100755
index 0000000..1492279
--- /dev/null
+++ b/install.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+# ==================================================================
+# Error handling
+set -e # stop the shell on first error
+set -u # fail when using an undefined variable
+
+# ====================================================================
+show_error_and_exit() {
+ echo "install.sh "
+ echo " install.sh [prefix]"
+ echo " "
+ echo " prefix - prefix directory for install"
+ exit 1
+}
+
+prefix_arg=/var/tmp/$USER/install/cmake/ecflow
+if [[ "$#" = 1 ]] ; then
+ prefix_arg=$1
+fi
+
+set -x # echo script lines as they are executed
+
+#==========================================================================================
+mkdir -p build
+cd build
+
+#=======================================================================================
+# -DCMAKE_PYTHON_INSTALL_TYPE
+# -DCMAKE_PYTHON_INSTALL_TYPE = [ local | setup ] # if not specified defaults to local.
+# -DCMAKE_PYTHON_INSTALL_PREFIX should *only* used when using python setup.py (CMAKE_PYTHON_INSTALL_TYPE=setup)
+# *AND* for testing python install to local directory.
+# Using make -j8 may fail when using '-DCMAKE_PYTHON_INSTALL_TYPE=setup' use:
+# > make # OR
+# > make -j8 -k
+#
+# Boost:
+# By default it looks for environment variable BOOST_ROOT, if not it can specified on the command line. i.e
+# -DBOOST_ROOT=/var/tmp/ma0/boost/boost_1_53_0
+#
+# -DCMAKE_BUILD_TYPE: The default build is RelWithDebInfo for ecbuild, this has been
+# overridden in the top level CMakeLists.txt to Release
+# It can still be overridden specifying on the command line.
+# Be sure to remove cache first.
+
+cmake .. -DCMAKE_INSTALL_PREFIX=$prefix_arg \
+ # -DCMAKE_BUILD_TYPE=Release
+ # -DENABLE_GUI=OFF \
+ # -DENABLE_UI=OFF \
+ # -DENABLE_PYTHON=OFF \
+ # -DENABLE_ALL_TESTS=ON \
+ # -DCMAKE_PYTHON_INSTALL_TYPE=local \
+ # -DCMAKE_PREFIX_PATH="/usr/local/apps/qt/5.5.0/5.5/gcc_64/" \
+ # -DCMAKE_CXX_FLAGS="-Wall -Wno-unused-local-typedefs" \
+ # -DCMAKE_CXX_COMPILER=xlC_r"
+ # -DBOOST_ROOT=/var/tmp/$USER/boost/boost_1_53_0
+
+make -j8 -k
+make install
+
\ No newline at end of file
diff --git a/ecflow_4_0_7/project_summary.cmake b/project_summary.cmake
similarity index 100%
rename from ecflow_4_0_7/project_summary.cmake
rename to project_summary.cmake
diff --git a/share/CMakeLists.txt b/share/CMakeLists.txt
new file mode 100644
index 0000000..a4a5284
--- /dev/null
+++ b/share/CMakeLists.txt
@@ -0,0 +1,3 @@
+
+add_subdirectory(ecflow/etc)
+add_subdirectory(ecflow/etc/sounds)
\ No newline at end of file
diff --git a/share/ecbuild/toolchains/ecmwf-XC30-Cray.cmake b/share/ecbuild/toolchains/ecmwf-XC30-Cray.cmake
new file mode 100644
index 0000000..52924b9
--- /dev/null
+++ b/share/ecbuild/toolchains/ecmwf-XC30-Cray.cmake
@@ -0,0 +1,56 @@
+####################################################################
+# ARCHITECTURE
+####################################################################
+set( CMAKE_SIZEOF_VOID_P 8 )
+
+# Disable relative rpaths as aprun does not respect it
+set( ENABLE_RELATIVE_RPATHS OFF CACHE STRING "Disable relative rpaths" FORCE )
+
+####################################################################
+# COMPILER
+####################################################################
+
+include(CMakeForceCompiler)
+
+CMAKE_FORCE_C_COMPILER ( cc Cray )
+CMAKE_FORCE_CXX_COMPILER ( CC Cray )
+CMAKE_FORCE_Fortran_COMPILER ( ftn Cray )
+
+set( ECBUILD_FIND_MPI OFF )
+set( ECBUILD_TRUST_FLAGS ON )
+
+####################################################################
+# MPI
+####################################################################
+
+set( MPIEXEC "aprun" )
+set( MPIEXEC_NUMPROC_FLAG "-n" )
+set( MPIEXEC_NUMTHREAD_FLAG "-d" )
+
+####################################################################
+# OpenMP FLAGS
+####################################################################
+
+set( OMP_C_FLAGS "-homp" )
+set( OMP_CXX_FLAGS "-homp" )
+set( OMP_Fortran_FLAGS "-homp" )
+
+set( OMPSTUBS_C_FLAGS "-hnoomp" )
+set( OMPSTUBS_CXX_FLAGS "-hnoomp" )
+set( OMPSTUBS_Fortran_FLAGS "-hnoomp" )
+
+####################################################################
+# Fortran FLAGS
+####################################################################
+
+# -emf activates .mods and uses lower case -rmoid produces a listing file
+set( ECBUILD_Fortran_FLAGS "-emf -rmoid" )
+
+####################################################################
+# LINK FLAGS
+####################################################################
+
+set( ECBUILD_C_LINK_FLAGS "-Wl,-Map,loadmap -Wl,--as-needed -Ktrap=fp" )
+set( ECBUILD_CXX_LINK_FLAGS "-Wl,-Map,loadmap -Wl,--as-needed -Ktrap=fp" )
+set( ECBUILD_Fortran_LINK_FLAGS "-Wl,-Map,loadmap -Wl,--as-needed -Ktrap=fp" )
+set( ECBUILD_CXX_IMPLICIT_LINK_LIBRARIES "$ENV{CC_X86_64}/lib/x86-64/libcray-c++-rts.so" CACHE STRING "" )
diff --git a/share/ecbuild/toolchains/ecmwf-XC30-GNU.cmake b/share/ecbuild/toolchains/ecmwf-XC30-GNU.cmake
new file mode 100644
index 0000000..3f69f06
--- /dev/null
+++ b/share/ecbuild/toolchains/ecmwf-XC30-GNU.cmake
@@ -0,0 +1,52 @@
+####################################################################
+# ARCHITECTURE
+####################################################################
+set( CMAKE_SIZEOF_VOID_P 8 )
+
+# Disable relative rpaths as aprun does not respect it
+set( ENABLE_RELATIVE_RPATHS OFF CACHE STRING "Disable relative rpaths" FORCE )
+
+####################################################################
+# COMPILER
+####################################################################
+
+include(CMakeForceCompiler)
+
+CMAKE_FORCE_C_COMPILER ( cc GNU )
+CMAKE_FORCE_CXX_COMPILER ( CC GNU )
+CMAKE_FORCE_Fortran_COMPILER ( ftn GNU )
+
+set( ECBUILD_FIND_MPI OFF )
+set( ECBUILD_TRUST_FLAGS ON )
+
+####################################################################
+# MPI
+####################################################################
+
+set( MPIEXEC "aprun" )
+set( MPIEXEC_NUMPROC_FLAG "-n" )
+set( MPIEXEC_NUMTHREAD_FLAG "-d" )
+
+####################################################################
+# OpenMP FLAGS
+####################################################################
+
+set( OMP_C_FLAGS "-fopenmp" )
+set( OMP_CXX_FLAGS "-fopenmp" )
+set( OMP_Fortran_FLAGS "-fopenmp" )
+
+####################################################################
+# DEBUG FLAGS
+####################################################################
+
+set( ECBUILD_C_FLAGS_DEBUG "-O0 -g -ftrapv" )
+set( ECBUILD_CXX_FLAGS_DEBUG "-O0 -g -ftrapv" )
+set( ECBUILD_Fortran_FLAGS_DEBUG "-ffree-line-length-none -O0 -g -fcheck=bounds -fbacktrace -finit-real=snan -ffpe-trap=invalid,zero,overflow" )
+
+####################################################################
+# LINK FLAGS
+####################################################################
+
+set( ECBUILD_C_LINK_FLAGS "-Wl,-Map,load.map -Wl,--as-needed" )
+set( ECBUILD_CXX_LINK_FLAGS "-Wl,-Map,load.map -Wl,--as-needed" )
+set( ECBUILD_Fortran_LINK_FLAGS "-Wl,-Map,load.map -Wl,--as-needed" )
diff --git a/share/ecbuild/toolchains/ecmwf-XC30-Intel.cmake b/share/ecbuild/toolchains/ecmwf-XC30-Intel.cmake
new file mode 100644
index 0000000..01c6267
--- /dev/null
+++ b/share/ecbuild/toolchains/ecmwf-XC30-Intel.cmake
@@ -0,0 +1,73 @@
+####################################################################
+# ARCHITECTURE
+####################################################################
+set( CMAKE_SIZEOF_VOID_P 8 )
+
+# Disable relative rpaths as aprun does not respect it
+set( ENABLE_RELATIVE_RPATHS OFF CACHE STRING "Disable relative rpaths" FORCE )
+
+
+####################################################################
+# COMPILER
+####################################################################
+
+include(CMakeForceCompiler)
+
+CMAKE_FORCE_C_COMPILER ( cc Intel )
+CMAKE_FORCE_CXX_COMPILER ( CC Intel )
+CMAKE_FORCE_Fortran_COMPILER ( ftn Intel )
+
+set( ECBUILD_FIND_MPI OFF )
+set( ECBUILD_TRUST_FLAGS ON )
+
+####################################################################
+# MPI
+####################################################################
+
+set( MPIEXEC "aprun" )
+set( MPIEXEC_NUMPROC_FLAG "-n" )
+set( MPIEXEC_NUMTHREAD_FLAG "-d" )
+
+####################################################################
+# OpenMP FLAGS
+####################################################################
+
+set( OMP_C_FLAGS "-openmp -openmp-threadprivate=compat" )
+set( OMP_CXX_FLAGS "-openmp -openmp-threadprivate=compat" )
+set( OMP_Fortran_FLAGS "-openmp -openmp-threadprivate=compat" )
+
+####################################################################
+# COMMON FLAGS
+####################################################################
+
+# for diagnostics:
+# -diag-enable=vec -diag-file -Winline
+
+set( ECBUILD_C_FLAGS "-fp-speculation=strict -fp-model precise -traceback")
+set( ECBUILD_CXX_FLAGS "-fp-speculation=strict -fp-model precise -traceback" )
+set( ECBUILD_Fortran_FLAGS "-fp-speculation=strict -fp-model source -convert big_endian -assume byterecl -traceback -fpe0" )
+
+####################################################################
+# BIT REPRODUCIBLE FLAGS
+####################################################################
+
+set( ECBUILD_C_FLAGS_BIT "-O2 -xAVX -finline-function -finline-limit=500" )
+set( ECBUILD_CXX_FLAGS_BIT "-O2 -xAVX -finline-function -finline-limit=500" )
+set( ECBUILD_Fortran_FLAGS_BIT "-O2 -xAVX -finline-function -finline-limit=500 -align array64byte" )
+
+####################################################################
+# DEBUG FLAGS
+####################################################################
+
+set( ECBUILD_C_FLAGS_DEBUG "-O0 -g -traceback -fp-trap=common" )
+set( ECBUILD_CXX_FLAGS_DEBUG "-O0 -g -traceback -fp-trap=common" )
+# -check all implies -check bounds
+set( ECBUILD_Fortran_FLAGS_DEBUG "-O0 -g -traceback -warn all -heap-arrays -fpe-all=0 -fpe:0 -check all" )
+
+####################################################################
+# LINK FLAGS
+####################################################################
+
+set( ECBUILD_C_LINK_FLAGS "-Wl,-Map,load.map -Wl,--as-needed" )
+set( ECBUILD_CXX_LINK_FLAGS "-Wl,-Map,load.map -Wl,--as-needed" )
+set( ECBUILD_Fortran_LINK_FLAGS "-Wl,-Map,load.map -Wl,--as-needed" )
diff --git a/share/ecflow/etc/CMakeLists.txt b/share/ecflow/etc/CMakeLists.txt
new file mode 100644
index 0000000..a14ddab
--- /dev/null
+++ b/share/ecflow/etc/CMakeLists.txt
@@ -0,0 +1,27 @@
+
+# the list of files we want to install
+set (files ecflowview_menus.json
+ ecflowview_attribute_conf.json
+ ecflowview_gui.json
+ ecflowview_gui_server.json
+ ecflowview_highlighter.json
+ ecflowview_icon_conf.json
+ ecflowview_notification_conf.json
+ ecflowview_nstate_conf.json
+ ecflowview_palette.json
+ ecflowview_panels.json
+ ecflowview_panel_conf.json
+ ecflowview_sstate_conf.json
+ ecflowview_server_conf.json
+ ecflowview_view_conf.json
+ viewer.qss)
+
+# for each file, copy it into the build directory at build time
+# and install it into the installation directory at install time (!)
+foreach( f ${files} )
+ configure_file(${f} ${CMAKE_CURRENT_BINARY_DIR} COPYONLY)
+
+ install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${f}
+ DESTINATION share/ecflow/etc
+ PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)
+endforeach()
diff --git a/share/ecflow/etc/ecflowview_attribute_conf.json b/share/ecflow/etc/ecflowview_attribute_conf.json
new file mode 100644
index 0000000..f82a84a
--- /dev/null
+++ b/share/ecflow/etc/ecflowview_attribute_conf.json
@@ -0,0 +1,51 @@
+{
+ "attribute" : {
+
+ "label" : "Attributes",
+
+ "label" : {
+ "label" : "Labels"
+ },
+ "meter" : {
+ "label" : "Meters",
+ "unset_colour" : {
+ "label" : "Unset colour",
+ "default" : "rgb(200,200,200)"
+ },
+ "set_colour" : {
+ "label" : "Set colour",
+ "default" : "rgb(200,200,200)"
+ }
+ },
+ "event" : {
+ "label" : "Events"
+ },
+ "repeat" : {
+ "label" : "Repeats"
+ },
+ "time" : {
+ "label" : "Times"
+ },
+ "date" : {
+ "label" : "Dates"
+ },
+ "trigger" : {
+ "label" : "Triggers"
+ },
+ "var" : {
+ "label" : "Variables"
+ },
+ "genvar" : {
+ "label" : "Generated variables"
+ },
+ "late" : {
+ "label" : "Late"
+ },
+ "limit" : {
+ "label" : "Limits"
+ },
+ "limiter" : {
+ "label" : "Limiters"
+ }
+ }
+}
diff --git a/share/ecflow/etc/ecflowview_gui.json b/share/ecflow/etc/ecflowview_gui.json
new file mode 100644
index 0000000..1e31c4b
--- /dev/null
+++ b/share/ecflow/etc/ecflowview_gui.json
@@ -0,0 +1,462 @@
+{
+ "gui" : {
+
+ "hidden" : {
+ "visible" : "false",
+ "line" : "panel.variable.showShadowed"
+ },
+
+ "appearance": {
+ "label": "Appearance",
+ "desc" : "Appearance",
+ "icon" : "colour.svg",
+
+ "tabs" : {
+ "tab" : {
+ "label" : "Status",
+
+ "group" : {
+ "title" : "Status rendering options",
+ "prefix" : "view.common",
+ "line" : "node_gradient"
+ },
+
+ "grid" : {
+ "title" : "Status colours",
+ "h1" : "Node cell",
+ "h2" : "Name in cell",
+ "h3" : "Type in cell",
+
+ "row" : {
+ "label" : "Unknown",
+ "prefix" : "nstate.unknown",
+ "line" : "fill_colour",
+ "line" : "font_colour",
+ "line" : "type_colour"
+ },
+ "row" : {
+ "label" : "Complete",
+ "prefix" : "nstate.complete",
+ "line" : "fill_colour",
+ "line" : "font_colour",
+ "line" : "type_colour"
+ },
+ "row" : {
+ "label" : "Queued",
+ "prefix" : "nstate.queued",
+ "line" : "fill_colour",
+ "line" : "font_colour",
+ "line" : "type_colour"
+ },
+ "row" : {
+ "label" : "Aborted",
+ "prefix" : "nstate.aborted",
+ "line" : "fill_colour",
+ "line" : "font_colour",
+ "line" : "type_colour"
+ },
+ "row" : {
+ "label" : "Submitted",
+ "prefix" : "nstate.submitted",
+ "line" : "fill_colour",
+ "line" : "font_colour",
+ "line" : "type_colour"
+ },
+ "row" : {
+ "label" : "Active",
+ "prefix" : "nstate.active",
+ "line" : "fill_colour",
+ "line" : "font_colour",
+ "line" : "type_colour"
+ },
+ "row" : {
+ "label" : "Suspended ",
+ "prefix" : "nstate.suspended",
+ "line" : "fill_colour",
+ "line" : "font_colour",
+ "line" : "type_colour"
+ },
+
+ "note" : {
+ "default" : "the states below are only valid for <b>servers</b>"
+ },
+
+ "row" : {
+ "label" : "Halted",
+ "prefix" : "sstate.halted",
+ "line" : "fill_colour",
+ "line" : "font_colour"
+ },
+ "row" : {
+ "label" : "Shutdown ",
+ "prefix" : "sstate.shutdown",
+ "line" : "fill_colour",
+ "line" : "font_colour"
+ },
+ "row" : {
+ "label" : "Running",
+ "prefix" : "sstate.running",
+ "line" : "fill_colour",
+ "line" : "font_colour"
+ }
+
+ }
+ },
+
+ "tab" : {
+
+ "label" : "Tree view",
+
+ "group" : {
+ "title" : "Options",
+ "prefix" : "view",
+
+ "line" : "common.node_style",
+ "line" : "tree.displayNodeType",
+ "line" : "tree.display_child_count",
+ "line" : "tree.indentation",
+ "line" : "tree.drawBranchLine",
+ "line" : "tree.background"
+ },
+ "group" : {
+ "title" : "Tooltips",
+ "prefix" : "view.tree",
+
+ "line" : "serverToolTip",
+ "line" : "nodeToolTip",
+ "line" : "attributeToolTip"
+ },
+ "group" : {
+ "title" : "Attributes",
+ "prefix" : "view.tree",
+
+ "line" : "attributesPolicy",
+ "line" : "defaultAttributes"
+ }
+ },
+
+ "tab" : {
+
+ "label" : "Table view",
+
+ "group" : {
+ "title" : "Options",
+ "prefix" : "view.table",
+
+ "line" : "background"
+ }
+ },
+ "tab" : {
+
+ "label" : "Attributes",
+
+ "group" : {
+ "title" : "Options",
+ "prefix" : "view.attribute",
+
+ "line" : "eventFillColour",
+ "line" : "meterFillColour",
+ "line" : "meterThresholdColour",
+ "line" : "limitFillColour"
+ }
+ }
+
+ }
+ },
+
+ "font": {
+ "label": "Fonts",
+ "desc" : "Fonts",
+ "icon" : "font.svg",
+
+ "group" : {
+ "title" : "Tree view",
+ "prefix" : "view.tree",
+
+ "line" : "nodeFont",
+ "line" : "attributeFont"
+ },
+
+ "group" : {
+ "title" : "Table view",
+ "prefix" : "view.table",
+
+ "line" : "font"
+ },
+
+ "group" : {
+ "title" : "Info panel text browsers",
+ "prefix" : "panel",
+
+ "line" : "overview.font",
+ "line" : "manual.font",
+ "line" : "script.font",
+ "line" : "job.font",
+ "line" : "output.font",
+ "line" : "why.font",
+ "line" : "edit.font"
+ }
+ },
+
+ "notification": {
+ "visible" : "true",
+ "label": "Notifications",
+ "desc" : "Notifications",
+ "icon" : "notification.svg",
+
+ "line" : "notification.settings.max_item_num",
+
+ "custom-notification" : {
+ "title" : "Notification types",
+ "group" : "true",
+
+ "row" : {
+ "label" : "Aborted",
+ "root" : "notification.aborted",
+ "group" : {
+ "title" : "Main settings",
+ "line" : "server.notification.aborted.enabled",
+ "line" : "server.notification.aborted.popup",
+ "line" : "server.notification.aborted.sound",
+ "note" : {
+ "default" : "These settings can be customised for each server separately"
+ }
+
+ },
+ "group" : {
+ "title" : "Colour",
+ "line" : "notification.aborted.count_fill_colour",
+ "line" : "notification.aborted.count_text_colour",
+ "note" : {
+ "default" : "For aborted notifications the background and text colours <br> are taken from the <u>Status</u> colour settings"
+ }
+ },
+ "group" : {
+ "title" : "Sound",
+ "line" : "notification.aborted.sound_file_type",
+ "line" : {
+ "link" : "notification.aborted.sound_system_file",
+ "helpers" : "notification.aborted.sound_volume/notification.aborted.sound_loop"
+ },
+ "line" : "notification.aborted.sound_user_file",
+ "line" : "notification.aborted.sound_volume_tmp",
+ "line" : "notification.aborted.sound_loop"
+ }
+ },
+ "row" : {
+ "label" : "Restarted",
+ "root" : "notification.restarted",
+ "group" : {
+ "title" : "Settings",
+ "line" : "server.notification.restarted.enabled",
+ "line" : "server.notification.restarted.popup",
+ "line" : "server.notification.restarted.sound",
+ "note" : {
+ "default" : "These settings can be customised for each server separately"
+ }
+ },
+ "group" : {
+ "title" : "Colour",
+ "line" : "notification.restarted.fill_colour",
+ "line" : "notification.restarted.text_colour",
+ "line" : "notification.restarted.count_fill_colour",
+ "line" : "notification.restarted.count_text_colour"
+ },
+ "group" : {
+ "title" : "Sound",
+ "line" : "notification.restarted.sound_file_type",
+ "line" : {
+ "link" : "notification.restarted.sound_system_file",
+ "helpers" : "notification.restarted.sound_volume/notification.restarted.sound_loop"
+ },
+ "line" : "notification.restarted.sound_user_file",
+ "line" : "notification.restarted.sound_volume_tmp",
+ "line" : "notification.restarted.sound_loop"
+ }
+ },
+ "row" : {
+ "label" : "Late",
+ "root" : "notification.late",
+ "group" : {
+ "title" : "Settings",
+ "line" : "server.notification.late.enabled",
+ "line" : "server.notification.late.popup",
+ "line" : "server.notification.late.sound",
+ "note" : {
+ "default" : "These settings can be customised for each server separately"
+ }
+ },
+ "group" : {
+ "title" : "Colour",
+ "line" : "notification.late.fill_colour",
+ "line" : "notification.late.text_colour",
+ "line" : "notification.late.count_fill_colour",
+ "line" : "notification.late.count_text_colour"
+ },
+ "group" : {
+ "title" : "Sound",
+ "line" : "notification.late.sound_file_type",
+ "line" : {
+ "link" : "notification.late.sound_system_file",
+ "helpers" : "notification.late.sound_volume/notification.late.sound_loop"
+ },
+ "line" : "notification.late.sound_user_file",
+ "line" : "notification.late.sound_volume_tmp",
+ "line" : "notification.late.sound_loop"
+ }
+ },
+ "row" : {
+ "label" : "Zombies",
+ "root" : "notification.zombie",
+ "group" : {
+ "title" : "Settings",
+ "line" : "server.notification.zombie.enabled",
+ "line" : "server.notification.zombie.popup",
+ "line" : "server.notification.zombie.sound",
+ "note" : {
+ "default" : "These settings can be customised for each server separately"
+ }
+ },
+ "group" : {
+ "title" : "Colour",
+ "line" : "notification.zombie.fill_colour",
+ "line" : "notification.zombie.text_colour",
+ "line" : "notification.zombie.count_fill_colour",
+ "line" : "notification.zombie.count_text_colour"
+ },
+ "group" : {
+ "title" : "Sound",
+ "line" : "notification.zombie.sound_file_type",
+ "line" : {
+ "link" : "notification.zombie.sound_system_file",
+ "helpers" : "notification.zombie.sound_volume/notification.zombie.sound_loop"
+ },
+ "line" : "notification.zombie.sound_user_file",
+ "line" : "notification.zombie.sound_volume_tmp",
+ "line" : "notification.zombie.sound_loop"
+ }
+ },
+ "row" : {
+ "label" : "Aliases",
+ "root" : "notification.alias",
+ "group" : {
+ "title" : "Settings",
+ "line" : "server.notification.alias.enabled",
+ "line" : "server.notification.alias.popup",
+ "line" : "server.notification.alias.sound",
+ "note" : {
+ "default" : "These settings can be customised for each server separately"
+ }
+ },
+ "group" : {
+ "title" : "Colour",
+ "line" : "notification.alias.fill_colour",
+ "line" : "notification.alias.text_colour",
+ "line" : "notification.alias.count_fill_colour",
+ "line" : "notification.alias.count_text_colour"
+ },
+ "group" : {
+ "title" : "Sound",
+ "line" : "notification.alias.sound_file_type",
+ "line" : {
+ "link" : "notification.alias.sound_system_file",
+ "helpers" : "notification.alias.sound_volume/notification.alias.sound_loop"
+ },
+ "line" : "notification.alias.sound_user_file",
+ "line" : "notification.alias.sound_volume_tmp",
+ "line" : "notification.alias.sound_loop"
+ }
+ }
+ }
+
+ },
+
+ "server": {
+ "label" : "Server options",
+ "desc" : "Server options",
+ "icon" : "server.svg",
+ "group" : {
+
+ "title" : "Update",
+ "prefix" : "server.update",
+
+ "line" : "autoUpdate",
+ "line" : "updateRateInSec",
+ "line" : "adaptiveUpdate",
+ "note" : {
+ "default": "When enabled the server update period is <u>increased at every automatic update</u> until the maximum period is reached. If the user in the meantime updates the server manually the update period is set back to its original value and whole process starts again."
+ },
+ "line" : "adaptiveUpdateIncrementInSec",
+ "line" : "maxAdaptiveUpdateRateInMin"
+ },
+
+ "group" : {
+
+ "title" : "Files (manual, script, job and job output)",
+ "prefix" : "server.files",
+
+ "line" : "readFilesFromDisk",
+ "line" : "maxOutputFileLines"
+ },
+
+ "grid-hidden" : {
+ "title" : "Notifications",
+
+ "h1" : "Show in status bar",
+ "h2" : "Popup dialog",
+ "h3" : "Play sound",
+
+ "row" : {
+ "label" : "Aborted",
+ "prefix" : "server.notification.aborted",
+ "line" : "enabled",
+ "line" : "popup",
+ "line" : "sound",
+ "line" : "soundFile"
+ },
+ "row" : {
+ "label" : "Restarted",
+ "prefix" : "server.notification.restarted",
+ "line" : "enabled",
+ "line" : "popup",
+ "line" : "sound",
+ "line" : "soundFile"
+ },
+ "row" : {
+ "label" : "Late tasks",
+ "prefix" : "server.notification.late",
+ "line" : "enabled",
+ "line" : "popup",
+ "line" : "sound",
+ "line" : "soundFile"
+ },
+ "row" : {
+ "label" : "Zombies",
+ "prefix" : "server.notification.zombie",
+ "line" : "enabled",
+ "line" : "popup",
+ "line" : "sound",
+ "line" : "soundFile"
+ },
+ "row" : {
+ "label" : "Restarted or aborted aliases",
+ "prefix" : "server.notification.alias",
+ "line" : "enabled",
+ "line" : "popup",
+ "line" : "sound",
+ "line" : "soundFile"
+ }
+ }
+
+ },
+
+ "Tree view" : {
+ "visible" : "false",
+ "desc" : "Tree view options",
+
+ "line" : "view.tree.font",
+ "line" : "view.tree.nodeRectRadius",
+ "line" : "view.tree.displayChildCount"
+ }
+ }
+}
diff --git a/share/ecflow/etc/ecflowview_gui_server.json b/share/ecflow/etc/ecflowview_gui_server.json
new file mode 100644
index 0000000..894f71e
--- /dev/null
+++ b/share/ecflow/etc/ecflowview_gui_server.json
@@ -0,0 +1,74 @@
+{
+ "gui_server" : {
+
+ "server": {
+ "label" : "Server options",
+ "icon" : "server.svg",
+
+ "note" : {
+ "default" : "These are the <i>Server options</i> and <i>Notifications</i> parameters specifically set for server %SERVER%."
+ },
+
+ "group" : {
+
+ "title" : "Update",
+ "prefix" : "server.update",
+
+ "line" : "autoUpdate",
+ "line" : "updateRateInSec",
+ "line" : "adaptiveUpdate",
+ "note" : {
+ "default": "When enabled the server update period is <u>increased at every automatic update</u> until the maximum period is reached. If the user in the meantime updates the server manually the update period is set back to its original value and whole process starts again."
+ },
+ "line" : "adaptiveUpdateIncrementInSec",
+ "line" : "maxAdaptiveUpdateRateInMin"
+ },
+
+ "group" : {
+ "title" : "Files",
+ "prefix" : "server.files",
+
+ "line" : "readFilesFromDisk",
+ "line" : "maxOutputFileLines"
+ },
+
+ "custom-notification" : {
+ "title" : "Notifications",
+ "group" : "true",
+
+ "row" : {
+ "label" : "Aborted",
+ "line" : "server.notification.aborted.enabled",
+ "line" : "server.notification.aborted.popup",
+ "line" : "server.notification.aborted.sound"
+
+ },
+ "row" : {
+ "label" : "Restarted",
+ "line" : "server.notification.restarted.enabled",
+ "line" : "server.notification.restarted.popup",
+ "line" : "server.notification.restarted.sound"
+
+ },
+ "row" : {
+ "label" : "Late tasks",
+ "line" : "server.notification.late.enabled",
+ "line" : "server.notification.late.popup",
+ "line" : "server.notification.late.sound"
+ },
+ "row" : {
+ "label" : "Zombies",
+ "line" : "server.notification.zombie.enabled",
+ "line" : "server.notification.zombie.popup",
+ "line" : "server.notification.zombie.sound"
+ },
+ "row" : {
+ "label" : "Restarted or aborted aliases",
+ "line" : "server.notification.alias.enabled",
+ "line" : "server.notification.alias.popup",
+ "line" : "server.notification.alias.sound"
+ }
+ }
+ }
+ }
+}
diff --git a/share/ecflow/etc/ecflowview_highlighter.json b/share/ecflow/etc/ecflowview_highlighter.json
new file mode 100644
index 0000000..169749b
--- /dev/null
+++ b/share/ecflow/etc/ecflowview_highlighter.json
@@ -0,0 +1,251 @@
+{
+ "info" : {
+
+ "main" : {
+ "pattern" : "^\\s*(name|type|status|at)\\s+:",
+ "colour" : "rgb(0,0,128)",
+ "bold" : "true"
+
+ },
+
+ "def" : {
+ "pattern" : "^(task|endtask|suite|endsuite|family|endfamily|server|endserver)",
+ "colour" : "rgb(0,0,0)",
+ "bold" : "true"
+ },
+
+ "keyword" : {
+ "pattern" : "(edit|cron|label|event|defstatus)",
+ "colour" : "rgb(136,0,136)",
+ "bold" : "true"
+ },
+
+ "comment" : {
+ "pattern" : "(#[^\n]*)",
+ "colour" : "rgb(100,100,100)",
+ "italic" : "true"
+ }
+
+ },
+
+ "script" : {
+
+ "preproc" : {
+ "pattern" : "^\\s*(%include\\s*<\\S*>|%manual|%comment|%nopp|%end|%ecfmicro \\S+)",
+ "colour" : "rgb(0,140,0)"
+
+ },
+
+ "keyword" : {
+ "pattern" : "\\b(if|then|elif|else|fi|case|esac|set|for|in|done|do|while|try:)\\b",
+ "colour" : "rgb(0,0,0)",
+ "bold" : "true"
+ },
+
+ "ecfcommand" : {
+ "pattern" : "\\b(ecflow_client)\\b",
+ "colour" : "rgb(204,0,204)",
+ "bold" : "true"
+ },
+
+ "oper" : {
+ "pattern" : "(=|!=|-gt|-ge|-eq|-lt|-le)",
+ "colour" : "rgb(0,110,40)"
+ },
+
+ "heredoc" : {
+ "pattern" : "(<<\\s*\\S+\\s*>|EOF)",
+ "colour" : "rgb(34,51,136)",
+ "bold" : "true"
+ },
+
+ "ecfvar" : {
+ "pattern" : "(%\\S+%)",
+ "colour" : "rgb(16,40,170)",
+ "bold" : "true"
+ },
+
+ "leftvalue" : {
+ "pattern" : "(\\S+)\\s*=",
+ "colour" : "rgb(0,110,40)"
+ },
+
+ "shellvar" : {
+ "pattern" : "(\\$\\S+|\\))",
+ "colour" : "rgb(0,110,40)"
+ },
+
+
+ "command" : {
+ "pattern" : "\\b(awk|banner|cat|cd|chmod|chown|cp|echo|exit|export|find|grep|hostname|ln|ls|mkdir|mv|printf|pwd|return|rm|sed|sleep|sort|trap|true|uname|wait)\\b",
+ "colour" : "rgb(136,0,136)",
+ "bold" : "true"
+ },
+
+ "othercommand" : {
+ "pattern" : "\\b(cmake|ctest|git|module)\\b",
+ "colour" : "rgb(204,0,204)",
+ "bold" : "true"
+ },
+
+ "function" : {
+ "pattern" : "(\\S+\\s*\\(\\))",
+ "colour" : "rgb(16,40,170)"
+ },
+
+ "string" : {
+ "pattern" : "(\"[^\"]*\"|'[^']*')",
+ "colour" : "rgb(191,3,3)"
+ },
+
+ "shell-syntax" : {
+ "pattern" : "(\\[|\\]|;)",
+ "colour" : "rgb(0,0,0)",
+ "bold" : "true"
+ },
+
+ "comment" : {
+ "pattern" : "(#[^\n]*)",
+ "colour" : "rgb(100,100,100)",
+ "italic" : "true"
+ }
+
+
+ },
+
+ "job" : {
+
+ "keyword" : {
+ "pattern" : "\\b(if|then|elif|else|fi|case|esac|set|for|in|done|do|while|try:)\\b",
+ "colour" : "rgb(0,0,0)",
+ "bold" : "true"
+ },
+
+ "ecfcommand" : {
+ "pattern" : "\\b(ecflow_client)\\b",
+ "colour" : "rgb(204,0,204)",
+ "bold" : "true"
+ },
+
+ "oper" : {
+ "pattern" : "(=|!=|-gt|-ge|-eq|-lt|-le)",
+ "colour" : "rgb(0,110,40)"
+ },
+
+ "heredoc" : {
+ "pattern" : "(<<\\s*\\S+\\s*>|EOF)",
+ "colour" : "rgb(34,51,136)",
+ "bold" : "true"
+ },
+
+
+ "leftvalue" : {
+ "pattern" : "(\\S+)\\s*=",
+ "colour" : "rgb(0,110,40)"
+ },
+
+ "shellvar" : {
+ "pattern" : "(\\$\\S+|\\))",
+ "colour" : "rgb(0,110,40)"
+ },
+
+ "command" : {
+ "pattern" : "\\b(awk|banner|cat|cd|chmod|chown|cp|echo|eval|exec|exit|export|find|grep|hostname|ln|ls|mkdir|mv|printf|pwd|return|rm|sed|sleep|sort|trap|true|uname|wait)\\b",
+ "colour" : "rgb(136,0,136)",
+ "bold" : "true"
+ },
+
+ "othercommand" : {
+ "pattern" : "\\b(cmake|ctest|git|module)\\b",
+ "colour" : "rgb(204,0,204)",
+ "bold" : "true"
+ },
+
+ "function" : {
+ "pattern" : "(\\S+\\s*\\(\\))",
+ "colour" : "rgb(16,40,170)"
+ },
+
+ "string" : {
+ "pattern" : "(\"[^\"]*\"|'[^']*')",
+ "colour" : "rgb(191,3,3)"
+ },
+
+ "shell-syntax" : {
+ "pattern" : "(\\[|\\]|;)",
+ "colour" : "rgb(0,0,0)",
+ "bold" : "true"
+ },
+
+ "comment" : {
+ "pattern" : "(#[^\n]*)",
+ "colour" : "rgb(100,100,100)",
+ "italic" : "true"
+ }
+ },
+
+ "query" : {
+
+ "oper" : {
+ "pattern" : "(=|~)",
+ "colour" : "rgb(0,110,40)"
+ },
+ "logical" : {
+ "pattern" : "(or|and)",
+ "colour" : "rgb(40,40,40)",
+ "bold" : "false"
+ },
+ "keyword" : {
+ "pattern" : "(scope|scope:|nodes|nodes:|options|options:)",
+ "colour" : "rgb(73,73,73)",
+ "bold" : "true"
+ },
+ "node" : {
+ "pattern" : "\\b(node_path|node_name)\\b",
+ "colour" : "rgb(102,43,130)",
+ "bold" : "true"
+ },
+ "state" : {
+ "pattern" : "\\b(aborted|active|queued|complete|submitted|suspended|unknown)\\b",
+ "colour" : "rgb(102,43,130)",
+ "bold" : "true"
+ },
+ "type" : {
+ "pattern" : "\\b(server|suite|family|task|alias)\\b",
+ "colour" : "rgb(102,43,130)",
+ "bold" : "true"
+ },
+ "flag" : {
+ "pattern" : "\\b(is_late|has_date|has_message|has_time|is_rerun|is_waiting|is_zombie)\\b",
+ "colour" : "rgb(102,43,130)",
+ "bold" : "true"
+ },
+ "attr" : {
+ "pattern" : "\\b(date|date_name|event|event_name|label|label_name|label_value|late|late_name|limit|limit_name|limit_value|limit_max|limiter|limiter_name|meter|meter_name|repeat|repeat_name|repeat_value|time|time_name|trigger|trigger_expression|variable|variable_name|variable_value)\\b",
+ "colour" : "rgb(102,43,130)",
+ "bold" : "true"
+ },
+ "server" : {
+ "pattern" : "\\b(servers|root_node)\\b",
+ "colour" : "rgb(102,43,130)",
+ "bold" : "false"
+ },
+ "option" : {
+ "pattern" : "\\b(max_results|case_sensitive|case_insensitive)\\b",
+ "colour" : "rgb(102,43,130)"
+ },
+ "int" : {
+ "pattern" : "(\\d+)",
+ "colour" : "rgb(0,110,40)"
+ },
+ "string" : {
+ "pattern" : "(\"[^\"]*\"|'[^']*')",
+ "colour" : "rgb(0,0,230)"
+ },
+ "any" : {
+ "pattern" : "(ANY)",
+ "colour" : "rgb(16,16,16)"
+ }
+ }
+}
+
diff --git a/share/ecflow/etc/ecflowview_icon_conf.json b/share/ecflow/etc/ecflowview_icon_conf.json
new file mode 100644
index 0000000..686f75f
--- /dev/null
+++ b/share/ecflow/etc/ecflowview_icon_conf.json
@@ -0,0 +1,80 @@
+{
+ "icon" : {
+
+ "label" : "Node state",
+ "editable" : "false",
+
+ "wait" : {
+ "label" : "Waiting",
+ "tooltip" : "A running task is waiting for a trigger.",
+ "shortDesc" : "Waiting for a trigger",
+ "icon" : {
+ "default" : "icon_waiting.svg"
+ }
+ },
+ "rerun" : {
+ "label" : "Rerun",
+ "tooltip" : "Task has been restarted",
+ "shortDesc" : "Has been restarted",
+ "icon" : {
+ "default" : "icon_rerun.svg"
+ }
+ },
+ "message" : {
+ "label" : "Has node log entry",
+ "shortDesc" : "Has node log entry",
+ "tooltip" : "There are log entries for this node. Users have issued commands since the last begin.",
+ "icon" : {
+ "default": "icon_node_log.svg"
+ }
+ },
+ "complete" : {
+ "label" : "Complete",
+ "tooltip" : "",
+ "shortDesc" : "Complete by default status or by complete expression",
+ "icon" : {
+ "default" : "icon_complete.svg"
+ }
+ },
+ "time" : {
+ "label" : "Time",
+ "tooltip" : "Node has a time dependency.",
+ "shortDesc" : "Has time dependency",
+ "icon" : {
+ "default" : "icon_clock.svg"
+ }
+ },
+ "date" : {
+ "label" : "Date",
+ "tooltip" : "Node has date or day dependency.",
+ "shortDesc" : "Has date or day dependency",
+ "icon" : {
+ "default" : "icon_calendar.svg"
+ }
+ },
+ "zombie" : {
+ "label" : "Zombie",
+ "shortDesc" : "Is a zombie",
+ "tooltip" : "",
+ "icon" : {
+ "default" :"icon_zombie.svg"
+ }
+ },
+ "late" : {
+ "label" : "Late",
+ "tooltip" : "Node is late.",
+ "shortDesc" : "Is late",
+ "icon" : {
+ "default" : "icon_late.svg"
+ }
+ },
+ "slow" : {
+ "label" : "Slow server write",
+ "tooltip" : "Slow chekpoint file or job file writing.",
+ "shortDesc" : "Slow writing",
+ "icon" : {
+ "default" : "icon_slow.svg"
+ }
+ }
+ }
+}
diff --git a/share/ecflow/etc/ecflowview_menus.json b/share/ecflow/etc/ecflowview_menus.json
new file mode 100644
index 0000000..75c3479
--- /dev/null
+++ b/share/ecflow/etc/ecflowview_menus.json
@@ -0,0 +1,720 @@
+{
+ "file_id" : "ecflowview menu configuration",
+
+ "file_version" : "1.0",
+
+ "menus" :
+ [
+ {
+ "name" : "Node",
+ "modes" : ["Context", "Bar"],
+ "parent" : "None"
+ },
+
+ {
+ "name" : "Delete",
+ "modes" : ["Submenu"]
+ },
+
+ {
+ "name" : "Order",
+ "modes" : ["Submenu"]
+ },
+
+ {
+ "name" : "Force",
+ "modes" : ["Submenu"]
+ },
+
+ {
+ "name" : "Defstatus",
+ "modes" : ["Submenu"]
+ },
+
+ {
+ "name" : "Special",
+ "modes" : ["Submenu"]
+ },
+
+ {
+ "name" : "Custom",
+ "modes" : ["Submenu"]
+ }
+
+
+ ],
+
+
+
+ "menu_items" :
+ [
+
+
+ {
+ "menu" : "Node",
+ "name" : "Suspend",
+ "visible_for" : "not suspended and node",
+ "command" : "ecflow_client --suspend <full_name>",
+ "status_tip" : "__cmd__"
+ },
+
+ {
+ "menu" : "Node",
+ "name" : "Resume",
+ "visible_for" : "suspended and node",
+ "command" : "ecflow_client --resume <full_name>",
+ "status_tip" : "__cmd__"
+ },
+
+ {
+ "menu" : "Node",
+ "name" : "Rerun",
+ "visible_for" : "task",
+ "enabled_for" : "(not active) and (not submitted)",
+ "command" : "ecflow_client --force queued <full_name>",
+ "status_tip" : "__cmd__"
+ },
+
+ {
+ "menu" : "Node",
+ "name" : "Set complete",
+ "visible_for" : "task or alias",
+ "enabled_for" : "submitted or active or unknown or queued or aborted",
+ "command" : "ecflow_client --force=complete <full_name>",
+ "question_for" : "submitted or active",
+ "question" : "Have you checked that the job is not active anymore (jobstatus)?",
+ "default_answer" : "Yes",
+ "status_tip" : "__cmd__"
+ },
+
+ {
+ "menu" : "Node",
+ "name" : "Set aborted",
+ "visible_for" : "task or alias",
+ "enabled_for" : "submitted or active or unknown or queued or complete",
+ "command" : "ecflow_client --force=aborted <full_name>",
+ "question_for" : "submitted or active",
+ "question" : "Have you checked that the job is not active anymore (jobstatus)?",
+ "default_answer" : "Yes",
+ "status_tip" : "__cmd__"
+ },
+
+ {
+ "menu" : "Node",
+ "name" : "Execute",
+ "visible_for" : "task or alias",
+ "enabled_for" : "(not active) and (not submitted)",
+ "command" : "ecflow_client --run <full_name>",
+ "status_tip" : "__cmd__"
+ },
+
+ {
+ "menu" : "Node",
+ "name" : "Requeue",
+ "visible_for" : "task or suite or family",
+ "enabled_for" : "(not active) and (not submitted)",
+ "command" : "ecflow_client --requeue=force <full_name>",
+ "question" : "Confirm requeuing of <full_name>",
+ "default_answer" : "Yes",
+ "status_tip" : "__cmd__"
+ },
+
+ {
+ "menu" : "Node",
+ "name" : "Requeue aborted",
+ "visible_for" : "suite or family",
+ "enabled_for" : "aborted or suspended",
+ "command" : "ecflow_client --requeue=abort <full_name>",
+ "question" : "Confirm requeuing of aborted tasks from <full_name>",
+ "default_answer" : "Yes",
+ "status_tip" : "__cmd__"
+ },
+
+ {
+ "menu" : "Node",
+ "name" : "-"
+ },
+
+ {
+ "menu" : "Node",
+ "name" : "Delete",
+ "type" : "Submenu",
+ "visible_for" : "suite or task or family",
+ "enabled_for" : "(queued or suspended or active) and (has_triggers or has_time or has_date)",
+ "command" : "None"
+ },
+
+ {
+ "name" : "Defstatus",
+ "type" : "Submenu",
+ "menu" : "Node",
+ "visible_for" : "node or alias",
+ "command" : "None"
+ },
+
+ {
+ "menu" : "Node",
+ "name" : "Force",
+ "type" : "Submenu",
+ "visible_for" : "node and admin",
+ "command" : "None"
+ },
+
+ {
+ "menu" : "Node",
+ "name" : "Order",
+ "type" : "Submenu",
+ "visible_for" : "(node or alias) and admin",
+ "command" : "None"
+ },
+
+ {
+ "menu" : "Node",
+ "name" : "Special",
+ "type" : "Submenu",
+ "visible_for" : "node or alias",
+ "command" : "None"
+ },
+
+ {
+ "name" : "-",
+ "menu" : "Node"
+ },
+
+ {
+ "menu" : "Node",
+ "name" : "Begin",
+ "visible_for" : "suite and (oper or admin)",
+ "enabled_for" : "unknown or complete",
+ "command" : "ecflow_client --begin <node_name>",
+ "status_tip" : "__cmd__"
+ },
+
+ {
+ "menu" : "Node",
+ "name" : "Cancel",
+ "visible_for" : "suite and (oper or admin)",
+ "enabled_for" : "(not active) and (not submitted)",
+ "command" : "ecflow_client --delete=yes <full_name>",
+ "question" : "Do you really want to cancel suite <full_name> ?",
+ "default_answer" : "No",
+ "status_tip" : "__cmd__"
+ },
+
+
+ {
+ "menu" : "Node",
+ "name" : "Set",
+ "visible_for" : "event",
+ "enabled_for" : "event_clear",
+ "command" : "ecflow_client --alter change event <node_name> set <parent_name>",
+ "status_tip" : "__cmd__"
+ },
+ {
+ "menu" : "Node",
+ "name" : "Clear",
+ "visible_for" : "event",
+ "enabled_for" : "event_set",
+ "command" : "ecflow_client --alter change event <node_name> clear <parent_name>",
+ "status_tip" : "__cmd__"
+ },
+
+
+
+ {
+ "menu" : "Node",
+ "name" : "Unlock",
+ "visible_for" : "server and (oper or admin) and locked",
+ "command" : "unlock -y",
+ "question" : "Before going further, please check why the server was locked.",
+ "default_answer" : "No",
+ "status_tip" : "__cmd__"
+ },
+
+ {
+ "menu" : "Node",
+ "name" : "Restart",
+ "visible_for" : "server",
+ "enabled_for" : "shutdown or halted",
+ "command" : "ecflow_client --restart",
+ "question" : "Restart the server in <node_name>?",
+ "default_answer" : "No",
+ "status_tip" : "__cmd__"
+ },
+
+ {
+ "menu" : "Node",
+ "name" : "Shutdown",
+ "visible_for" : "server",
+ "enabled_for" : "not shutdown",
+ "command" : "ecflow_client --shutdown=yes",
+ "question" : "Shutdown the server in <node_name>?",
+ "default_answer" : "No",
+ "status_tip" : "__cmd__"
+ },
+
+ {
+ "menu" : "Node",
+ "name" : "Halt",
+ "visible_for" : "server",
+ "enabled_for" : "not halted",
+ "command" : "ecflow_client --halt=yes",
+ "question" : "Halt the server in <node_name>?",
+ "default_answer" : "No",
+ "status_tip" : "__cmd__"
+ },
+
+ {
+ "menu" : "Node",
+ "name" : "Terminate",
+ "visible_for" : "server",
+ "enabled_for" : "halted or unknown",
+ "command" : "ecflow_client --terminate=yes",
+ "question" : "Terminate the server in <node_name>?",
+ "default_answer" : "No",
+ "status_tip" : "__cmd__"
+ },
+
+ {
+ "menu" : "Node",
+ "name" : "-"
+ },
+
+ {
+ "menu" : "Node",
+ "name" : "Checkpoint",
+ "visible_for" : "server",
+ "command" : "ecflow_client --check_pt",
+ "status_tip" : "__cmd__"
+ },
+
+ {
+ "menu" : "Node",
+ "name" : "Recover",
+ "visible_for" : "server",
+ "enabled_for" : "halted",
+ "command" : "ecflow_client --restore_from_checkpt",
+ "question" : "Recover the server in <node_name>?",
+ "default_answer" : "No",
+ "status_tip" : "__cmd__"
+ },
+
+
+
+
+ {
+ "menu" : "Node",
+ "name" : "Reset",
+ "visible_for" : "limit",
+ "command" : "ecflow_client --alter=change limit_value <node_name> 0 <parent_name>",
+ "question" : "Confirm resetting limit <node_name>",
+ "default_answer" : "Yes",
+ "status_tip" : "__cmd__"
+ },
+
+ {
+ "menu" : "Node",
+ "name" : "Remove",
+ "visible_for" : "alias",
+ "command" : "ecflow_client --delete=yes <full_name>",
+ "question" : "Confirm remove alias <full_name>",
+ "default_answer" : "Yes",
+ "status_tip" : "__cmd__"
+ },
+
+
+ {
+ "menu" : "Node",
+ "name" : "-"
+ },
+
+
+
+
+
+
+
+
+
+ {
+ "menu" : "Node",
+ "name" : "-"
+ },
+
+ {
+ "menu" : "Node",
+ "name" : "Set as root",
+ "enabled_for" : "suite or task or family",
+ "hidden" : "true"
+ },
+
+ {
+ "menu" : "Node",
+ "name" : "-"
+ },
+
+
+
+
+ {
+ "name" : "Custom",
+ "type" : "Submenu",
+ "menu" : "Node",
+ "command" : "None",
+ "visible_for" : "server or node"
+ },
+
+
+
+
+
+ {
+ "menu" : "Delete",
+ "name" : "All dependencies",
+ "enabled_for" : "has_triggers or has_time or has_date",
+ "command" : "ecflow_client --free-dep all <full_name>",
+ "status_tip" : "__cmd__"
+ },
+ {
+ "menu" : "Delete",
+ "name" : "Trigger dependencies",
+ "enabled_for" : "has_triggers",
+ "command" : "ecflow_client --free-dep trigger <full_name>",
+ "status_tip" : "__cmd__"
+ },
+ {
+ "menu" : "Delete",
+ "name" : "Time dependencies",
+ "enabled_for" : "has_time",
+ "command" : "ecflow_client --free-dep time <full_name>",
+ "status_tip" : "__cmd__"
+ },
+ {
+ "menu" : "Delete",
+ "name" : "Date dependencies",
+ "enabled_for" : "has_date",
+ "command" : "ecflow_client --free-dep date <full_name>",
+ "status_tip" : "__cmd__"
+ },
+
+ {
+ "menu" : "Order",
+ "name" : "Top",
+ "command" : "ecflow_client --order <full_name> top",
+ "status_tip" : "__cmd__"
+ },
+ {
+ "menu" : "Order",
+ "name" : "Up",
+ "command" : "ecflow_client --order <full_name> up",
+ "status_tip" : "__cmd__"
+ },
+ {
+ "menu" : "Order",
+ "name" : "Down",
+ "command" : "ecflow_client --order <full_name> down",
+ "status_tip" : "__cmd__"
+ },
+ {
+ "menu" : "Order",
+ "name" : "Bottom",
+ "command" : "ecflow_client --order <full_name> bottom",
+ "status_tip" : "__cmd__"
+ },
+ {
+ "menu" : "Order",
+ "name" : "Alphabetically",
+ "command" : "ecflow_client --order <full_name> alpha",
+ "status_tip" : "__cmd__"
+ },
+
+
+ {
+ "menu" : "Special",
+ "name" : "Kill",
+ "visible_for" : "(suite or family)",
+ "enabled_for" : "(active or submitted or aborted)",
+ "command" : "ecflow_client --kill <full_name>",
+ "question" : "Confirm kill of <full_name>",
+ "default_answer" : "Yes",
+ "status_tip" : "__cmd__"
+ },
+
+ {
+ "menu" : "Special",
+ "name" : "Kill",
+ "visible_for" : "(task or alias)",
+ "enabled_for" : "(active or submitted)",
+ "command" : "ecflow_client --kill <full_name>",
+ "question" : "Confirm kill <full_name>",
+ "default_answer" : "Yes",
+ "status_tip" : "__cmd__"
+ },
+
+ {
+ "menu" : "Special",
+ "name" : "Free password",
+ "visible_for" : "(task or alias)",
+ "command" : "ecflow_client --alter add variable ECF_PASS FREE <full_name>",
+ "status_tip" : "__cmd__"
+ },
+
+ {
+ "menu" : "Special",
+ "name" : "Clear zombie flag",
+ "visible_for" : "(task or alias)",
+ "command" : "ecflow_client --alter clear_flag zombie <full_name>",
+ "status_tip" : "__cmd__"
+ },
+
+ {
+ "menu" : "Special",
+ "name" : "Clear late flag",
+ "visible_for" : "(task or alias)",
+ "command" : "ecflow_client --alter clear_flag late <full_name>",
+ "status_tip" : "__cmd__"
+ },
+
+ {
+ "menu" : "Special",
+ "name" : "Clear killed flag",
+ "visible_for" : "(task or alias)",
+ "command" : "ecflow_client --alter clear_flag killed <full_name>",
+ "status_tip" : "__cmd__"
+ },
+
+ {
+ "menu" : "Special",
+ "name" : "Execute",
+ "visible_for" : "family",
+ "enabled_for" : "(not active) and (not submitted)",
+ "command" : "ecflow_client --run <full_name>",
+ "status_tip" : "__cmd__"
+ },
+
+ {
+ "menu" : "Special",
+ "name" : "Walk",
+ "visible_for" : "(suite or family)",
+ "command" : "ecflow_client --force-dep-eval <full_name>",
+ "status_tip" : "__cmd__"
+ },
+
+
+
+ {
+ "menu" : "Force",
+ "name" : "Unknown",
+ "visible_for" : "node",
+ "enabled_for" : "not unknown",
+ "command" : "ecflow_client --force unknown recursive <full_name>",
+ "status_tip" : "__cmd__"
+ },
+ {
+ "menu" : "Force",
+ "name" : "Complete",
+ "visible_for" : "node",
+ "enabled_for" : "not complete and not active and not submitted",
+ "command" : "ecflow_client --force=complete recursive <full_name>",
+ "question" : "Check running/queued jobs and Confirm force complete of <full_name>",
+ "default_answer" : "No",
+ "status_tip" : "__cmd__"
+ },
+ {
+ "menu" : "Force",
+ "name" : "Queued",
+ "visible_for" : "node",
+ "enabled_for" : "not queued and not active and not submitted",
+ "command" : "ecflow_client --force queued recursive <full_name>",
+ "status_tip" : "__cmd__"
+ },
+ {
+ "menu" : "Force",
+ "name" : "Submitted",
+ "visible_for" : "node",
+ "enabled_for" : "not submitted and not active",
+ "command" : "ecflow_client --force submitted recursive <full_name>",
+ "status_tip" : "__cmd__"
+ },
+ {
+ "menu" : "Force",
+ "name" : "Active",
+ "visible_for" : "node",
+ "enabled_for" : "not active",
+ "command" : "ecflow_client --force active recursive <full_name>",
+ "status_tip" : "__cmd__"
+ },
+ {
+ "menu" : "Force",
+ "name" : "Aborted",
+ "visible_for" : "node",
+ "enabled_for" : "not active",
+ "command" : "ecflow_client --force=aborted recursive <full_name>",
+ "question" : "Check running/queued jobs and Confirm force submitted of <full_name>",
+ "default_answer" : "Yes",
+ "status_tip" : "__cmd__"
+ },
+
+
+
+ {
+ "menu" : "Defstatus",
+ "name" : "Complete",
+ "visible_for" : "node",
+ "command" : "ecflow_client --alter change defstatus complete <full_name>",
+ "status_tip" : "__cmd__"
+ },
+ {
+ "menu" : "Defstatus",
+ "name" : "Queued",
+ "visible_for" : "node",
+ "command" : "ecflow_client --alter change defstatus queued <full_name>",
+ "status_tip" : "__cmd__"
+ },
+ {
+ "menu" : "Node",
+ "name" : "-"
+ },
+ {
+ "menu" : "Node",
+ "name" : "Search ...",
+ "visible_for" : "server or node",
+ "command" : "search",
+ "handler" : "dashboard",
+ "view" : "tree/table",
+ "icon" : "search.svg"
+ },
+ {
+ "menu" : "Node",
+ "name" : "-"
+ },
+ {
+ "menu" : "Node",
+ "name" : "Server log ...",
+ "visible_for" : "server",
+ "command" : "history",
+ "handler" : "info_panel",
+ "icon" : "server_log.svg"
+ },
+ {
+ "menu" : "Node",
+ "name" : "Suite filter ...",
+ "visible_for" : "server",
+ "command" : "suite",
+ "handler" : "info_panel",
+ "icon" : "filter.svg"
+ },
+ {
+ "menu" : "Node",
+ "name" : "Zombies ...",
+ "visible_for" : "server",
+ "command" : "zombie",
+ "handler" : "info_panel",
+ "icon" : "zombie.svg"
+ },
+ {
+ "menu" : "Node",
+ "name" : "Settings ...",
+ "visible_for" : "server",
+ "command" : "server_settings",
+ "handler" : "info_panel",
+ "icon" : "configure.svg"
+ },
+ {
+ "menu" : "Node",
+ "name" : "Info ...",
+ "visible_for" : "server or node",
+ "command" : "overview",
+ "handler" : "info_panel",
+ "icon" : "overview.svg"
+ },
+
+ {
+ "menu" : "Node",
+ "name" : "Edit ...",
+ "visible_for" : "task or alias",
+ "command" : "edit",
+ "handler" : "info_panel",
+ "icon" : "edit.svg"
+ },
+ {
+ "menu" : "Node",
+ "name" : "Output ...",
+ "visible_for" : "task or alias",
+ "command" : "output",
+ "handler" : "info_panel",
+ "icon" : "output.svg"
+ },
+ {
+ "menu" : "Node",
+ "name" : "Variables ...",
+ "visible_for" : "server or node",
+ "command" : "variable",
+ "handler" : "info_panel",
+ "icon" : "variable.svg"
+ },
+ {
+ "menu" : "Node",
+ "name" : "Script ...",
+ "visible_for" : "task or alias",
+ "command" : "script",
+ "handler" : "info_panel",
+ "icon" : "script.svg"
+ },
+ {
+ "menu" : "Node",
+ "name" : "Job ...",
+ "visible_for" : "task or alias",
+ "command" : "job",
+ "handler" : "info_panel",
+ "icon" : "job.svg"
+ },
+ {
+ "menu" : "Node",
+ "name" : "-"
+ },
+ {
+ "menu" : "Node",
+ "name" : "Copy node path",
+ "visible_for" : "server or node",
+ "command" : "copy"
+ },
+ {
+ "menu" : "Node",
+ "name" : "-"
+ },
+ {
+ "menu" : "Node",
+ "name" : "Expand all children",
+ "visible_for" : "server or node",
+ "command" : "expand",
+ "handler" : "tree",
+ "view" : "tree"
+ },
+ {
+ "menu" : "Node",
+ "name" : "Collapse all children",
+ "visible_for" : "server or node",
+ "command" : "collapse",
+ "handler" : "tree",
+ "view" : "tree"
+ },
+ {
+ "menu" : "Node",
+ "name" : "Edit ...",
+ "visible_for" : "label or meter or limit",
+ "command" : "edit",
+ "handler" : "tree",
+ "view" : "tree"
+ },
+ {
+ "menu" : "Node",
+ "name" : "Edit ...",
+ "visible_for" : "repeat and not repeat_day",
+ "command" : "edit",
+ "handler" : "tree",
+ "view" : "tree"
+ }
+ ]
+
+}
diff --git a/share/ecflow/etc/ecflowview_notification_conf.json b/share/ecflow/etc/ecflowview_notification_conf.json
new file mode 100644
index 0000000..531724b
--- /dev/null
+++ b/share/ecflow/etc/ecflowview_notification_conf.json
@@ -0,0 +1,297 @@
+{
+ "notification": {
+
+ "settings" : {
+ "max_item_num" : {
+ "label" : "Maximum notification list size",
+ "default" : "200",
+ "min" : "10",
+ "max" : "500",
+ "suffix": "items"
+ }
+ },
+ "aborted": {
+ "fill_colour" : {
+ "label" : "Backgorund colour",
+ "default": "rgb(255,0,0)"
+ },
+ "text_colour" : {
+ "label" : "Text colour",
+ "default": "rgb(0,0,0)"
+ },
+ "count_fill_colour" : {
+ "label" : "Notification count background colour",
+ "default": "rgb(58,126,194))"
+ },
+ "count_text_colour" : {
+ "label" : "Notification count text colour",
+ "default": "rgb(255,255,255)"
+ },
+ "sound_file_type" : {
+ "label" : "Sound file type",
+ "default" : "system",
+ "values" : "system",
+ "values_label" : "Built in"
+ },
+ "sound_system_file" : {
+ "label" : "Built in sound",
+ "default" : "tone.ogg",
+ "values" : ""
+ },
+ "sound_user_file" : {
+ "label" : "Sound file",
+ "default" : "*.ogg",
+ "default_dir" : "/usr/share/sounds"
+ },
+ "sound_volume" : {
+ "label" : "Volume",
+ "default" : "5",
+ "min" : "1",
+ "max" : "10"
+ },
+ "sound_loop" : {
+ "label" : "Sound loop count",
+ "default" : "1",
+ "values" : "1/2/3/4/5"
+ },
+ "border": "rgb(200,200,200)",
+ "title" : "Change: aborted tasks",
+ "labelText" : "Aborted",
+ "widgetText" : "A",
+ "tooltip" : "Notifications for tasks which have been <b>aborted</b>",
+ "description" : "Notify when a task becomes aborted"
+ },
+
+ "restarted": {
+ "fill_colour" : {
+ "label" : "Backgorund colour",
+ "default": "rgb(64,224,208)"
+ },
+ "text_colour" : {
+ "label" : "Text colour",
+ "default": "rgb(0,0,0)"
+ },
+ "count_fill_colour" : {
+ "label" : "Notification count background colour",
+ "default": "rgb(58,126,194))"
+ },
+ "count_text_colour" : {
+ "label" : "Notification count text colour",
+ "default": "rgb(255,255,255)"
+ },
+ "sound_file_type" : {
+ "label" : "Sound file type",
+ "default" : "system",
+ "values" : "system",
+ "values_label" : "Built in"
+ },
+ "sound_system_file" : {
+ "label" : "Built in sound",
+ "default" : "tone.ogg",
+ "values" : ""
+ },
+ "sound_user_file" : {
+ "label" : "Sound file",
+ "default" : "*.ogg",
+ "default_dir" : "/usr/share/sounds"
+ },
+ "sound_volume" : {
+ "label" : "Volume",
+ "default" : "5",
+ "min" : "1",
+ "max" : "10"
+ },
+ "sound_loop" : {
+ "label" : "Sound loop count",
+ "default" : "1",
+ "values" : "1/2/3/4/5"
+ },
+
+ "border": "rgb(200,200,200)",
+ "title" : "Change: restarted tasks",
+ "labelText" : "Restarted",
+ "widgetText" : "Re",
+ "tooltip" : "Notifications for tasks which have been <b>restarted</b>",
+ "description" : "Notify when a task is restarted"
+ },
+ "late": {
+ "fill_colour" : {
+ "label" : "Backgorund colour",
+ "default": "rgb(64,224,208)"
+ },
+ "text_colour" : {
+ "label" : "Text colour",
+ "default": "rgb(0,0,0)"
+ },
+ "count_fill_colour" : {
+ "label" : "Notification count background colour",
+ "default": "rgb(58,126,194))"
+ },
+ "count_text_colour" : {
+ "label" : "Notification count text colour",
+ "default": "rgb(255,255,255)"
+ },
+ "sound_file_type" : {
+ "label" : "Sound file type",
+ "default" : "system",
+ "values" : "system",
+ "values_label" : "Built in"
+ },
+ "sound_system_file" : {
+ "label" : "Built in sound",
+ "default" : "tone.ogg",
+ "values" : ""
+ },
+ "sound_user_file" : {
+ "label" : "Sound file",
+ "default" : "*.ogg",
+ "default_dir" : "/usr/share/sounds"
+ },
+ "sound_volume" : {
+ "label" : "Volume",
+ "default" : "5",
+ "min" : "1",
+ "max" : "10"
+ },
+ "sound_loop" : {
+ "label" : "Sound loop count",
+ "default" : "1",
+ "values" : "1/2/3/4/5"
+ },
+ "border": "rgb(200,200,200)",
+ "title" : "Change: late tasks",
+ "labelText" : "Late",
+ "widgetText" : "L",
+ "tooltip" : "Notifications for tasks which have become <b>late</b>",
+ "description" : "Notify when a task becomes late"
+ },
+ "zombie": {
+ "fill_colour" : {
+ "label" : "Backgorund colour",
+ "default": "rgb(64,224,208)"
+ },
+ "text_colour" : {
+ "label" : "Text colour",
+ "default": "rgb(0,0,0)"
+ },
+ "count_fill_colour" : {
+ "label" : "Notification count background colour",
+ "default": "rgb(58,126,194))"
+ },
+ "count_text_colour" : {
+ "label" : "Notification count text colour",
+ "default": "rgb(255,255,255)"
+ },
+ "sound_file_type" : {
+ "label" : "Sound file type",
+ "default" : "system",
+ "values" : "system",
+ "values_label" : "Built in"
+ },
+ "sound_system_file" : {
+ "label" : "Built in sound",
+ "default" : "tone.ogg",
+ "values" : ""
+ },
+ "sound_user_file" : {
+ "label" : "Sound file",
+ "default" : "*.ogg",
+ "default_dir" : "/usr/share/sounds"
+ },
+ "sound_volume" : {
+ "label" : "Volume",
+ "default" : "5",
+ "min" : "1",
+ "max" : "10"
+ },
+ "sound_loop" : {
+ "label" : "Sound loop count",
+ "default" : "1",
+ "values" : "1/2/3/4/5"
+ },
+ "border": "rgb(200,200,200)",
+ "title" : "Change: zombies",
+ "labelText" : "Zombies",
+ "widgetText" : "Z",
+ "tooltip" : "Notifications for tasks which have become <b>zombies</b>",
+ "description" : "Notify when a task becomes a zombie"
+ },
+ "alias": {
+ "fill_colour" : {
+ "label" : "Backgorund colour",
+ "default": "rgb(64,224,208)"
+ },
+ "text_colour" : {
+ "label" : "Text colour",
+ "default": "rgb(0,0,0)"
+ },
+ "count_fill_colour" : {
+ "label" : "Notification count background colour",
+ "default": "rgb(58,126,194))"
+ },
+ "count_text_colour" : {
+ "label" : "Notification count text colour",
+ "default": "rgb(255,255,255)"
+ },
+ "sound_file_type" : {
+ "label" : "Sound file type",
+ "default" : "system",
+ "values" : "system",
+ "values_label" : "Built in"
+ },
+ "sound_system_file" : {
+ "label" : "Built in sound",
+ "default" : "tone.ogg",
+ "values" : ""
+ },
+ "sound_user_file" : {
+ "label" : "Sound file",
+ "default" : "*.ogg",
+ "default_dir" : "/usr/share/sounds"
+ },
+ "sound_volume" : {
+ "label" : "Volume",
+ "default" : "5",
+ "min" : "1",
+ "max" : "10"
+ },
+ "sound_loop" : {
+ "label" : "Sound loop count",
+ "default" : "1",
+ "values" : "1/2/3/4/5"
+ },
+ "border": "rgb(200,200,200)",
+ "title" : "Change: aliases",
+ "labelText" : "Aliases",
+ "widgetText" : "As",
+ "tooltip" : "Notifications for <b>aliases</b> which have become <b>aborted</b> or have been <b>restarted</b>",
+ "description" : "Notify when an alias becomes aborted or is restarted"
+ }
+
+ },
+ "sound" : {
+
+ "sound_sys_folder" : "%SHAREDIR%/sound",
+ "sound_user_folder" : "%CONFDIR%/sound",
+
+ "player" : {
+ "label" : "Sound player",
+ "default" : "play",
+ "values" : "built-in/play"
+ },
+
+ "players" : {
+ "built-in" : {
+ "type" : "internal"
+ },
+
+ "play" : {
+ "type" : "external",
+ "command" : "play -q %FILE% repeat %REPEAT%"
+ }
+ }
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/share/ecflow/etc/ecflowview_nstate_conf.json b/share/ecflow/etc/ecflowview_nstate_conf.json
new file mode 100644
index 0000000..445c2b4
--- /dev/null
+++ b/share/ecflow/etc/ecflowview_nstate_conf.json
@@ -0,0 +1,123 @@
+{
+ "nstate": {
+
+ "unknown": {
+ "label": "Unknown",
+ "tooltip": "unknown",
+ "fill_colour" : {
+ "label" : "Colour",
+ "default": "rgb(220,220,220)"
+ },
+ "font_colour" : {
+ "label" : "Font colour",
+ "default": "rgb(0,0,0)"
+ },
+ "type_colour" : {
+ "label" : "Type colour",
+ "default": "rgb(0,0,0)"
+ }
+ },
+
+ "complete": {
+ "label": "Complete",
+ "tooltip": "complete",
+ "fill_colour" : {
+ "label" : "Colour",
+ "default": "rgb(255,238,1)"
+ },
+ "font_colour" : {
+ "label" : "Font colour",
+ "default": "rgb(0,0,0)"
+ },
+ "type_colour" : {
+ "label" : "Type colour",
+ "default": "rgb(110,110,110)"
+ }
+ },
+
+ "queued": {
+ "label": "Queued",
+ "tooltip": "queued",
+ "fill_colour" : {
+ "label" : "Colour",
+ "default": "rgb(173,216,230)"
+ },
+ "font_colour" : {
+ "label" : "Font colour",
+ "default": "rgb(0,0,0)"
+ },
+ "type_colour" : {
+ "label" : "Type colour",
+ "default": "rgb(90,90,90)"
+ }
+ },
+
+ "aborted": {
+ "label": "Aborted",
+ "tooltip": "aborted",
+ "fill_colour" : {
+ "label" : "Colour",
+ "default": "rgb(255,59,53)"
+ },
+ "font_colour" : {
+ "label" : "Font colour",
+ "default": "rgb(0,0,0)"
+ },
+ "type_colour" : {
+ "label" : "Type colour",
+ "default": "rgb(255,255,255)"
+ }
+ },
+
+ "submitted": {
+ "label": "Submitted",
+ "tooltip": "submitted",
+ "fill_colour" : {
+ "label" : "Colour",
+ "default": "rgb(64,224,208)"
+ },
+ "font_colour" : {
+ "label" : "Font colour",
+ "default": "rgb(0,0,0)"
+ },
+ "type_colour" : {
+ "label" : "Type colour",
+ "default": "rgb(90,90,90)"
+ }
+ },
+
+ "active": {
+ "label": "Active",
+ "tooltip": "active",
+ "fill_colour" : {
+ "label" : "Colour",
+ "default": "rgb(74,255,61)"
+ },
+ "font_colour" : {
+ "label" : "Font colour",
+ "default": "rgb(0,0,0)"
+ },
+ "type_colour" : {
+ "label" : "Type colour",
+ "default": "rgb(90,90,90)"
+ }
+ },
+
+ "suspended": {
+ "label": "Suspended",
+ "tooltip": "suspended",
+ "fill_colour" : {
+ "label" : "Colour",
+ "default": "rgb(239,191,0)"
+ },
+ "font_colour" : {
+ "label" : "Font colour",
+ "default": "rgb(0,0,0)"
+ },
+ "type_colour" : {
+ "label" : "Type colour",
+ "default": "rgb(90,90,90)"
+ }
+ }
+ }
+}
diff --git a/share/ecflow/etc/ecflowview_palette.json b/share/ecflow/etc/ecflowview_palette.json
new file mode 100644
index 0000000..2e7e2f0
--- /dev/null
+++ b/share/ecflow/etc/ecflowview_palette.json
@@ -0,0 +1,54 @@
+{
+ "active" : {
+ "window" : "rgb(224,223,222)",
+ "windowtext" : "rgb(20,19,18)",
+ "base" : "rgb(255,255,255)",
+ "alternatebase" : "rgb(241,241,240)",
+ "text" : "rgb(20,19,18)",
+ "button" : "rgb(232,231,230)",
+ "buttontext" : "rgb(20,19,18)",
+ "brighttext" : "rgb(255,255,255)",
+ "light" : "rgb(255,255,255)",
+ "midlight" : "rgb(255,255,255)",
+ "dark" : "rgb(116,115,115)",
+ "mid" : "rgb(155,154,153)",
+ "shadow" : "rgb(118,116,114)",
+ "highligt" : "rgb(65,139,212)",
+ "highligtedtext" : "rgb(255,255,255)"
+ },
+
+ "inactive" : {
+ "window" : "rgb(224,223,222)",
+ "windowtext" : "rgb(20,19,18)",
+ "base" : "rgb(255,255,255)",
+ "alternatebase" : "rgb(241,241,240)",
+ "text" : "rgb(20,19,18)",
+ "button" : "rgb(232,231,230)",
+ "buttontext" : "rgb(20,19,18)",
+ "brighttext" : "rgb(255,255,255)",
+ "light" : "rgb(255,255,255)",
+ "midlight" : "rgb(255,255,255)",
+ "dark" : "rgb(116,115,115)",
+ "mid" : "rgb(155,154,153)",
+ "shadow" : "rgb(118,116,114)",
+ "highligt" : "rgb(65,139,212)",
+ "highligtedtext" : "rgb(255,255,255)"
+ },
+ "disabled" : {
+ "window" : "rgb(210,211,212)",
+ "windowtext" : "rgb(146,145,144)",
+ "base" : "rgb(244,244,244)",
+ "alternatebase" : "rgb(241,241,240)",
+ "text" : "rgb(165,164,164)",
+ "button" : "rgb(242,241,240)",
+ "buttontext" : "rgb(181,180,189)",
+ "brighttext" : "rgb(255,255,255)",
+ "light" : "rgb(245,245,245)",
+ "midlight" : "rgb(234,233,232)",
+ "dark" : "rgb(139,138,137)",
+ "mid" : "rgb(219,218,216)",
+ "shadow" : "rgb(70,69,68)",
+ "highligt" : "rgb(214,213,211)",
+ "highligtedtext" : "rgb(146,145,144)"
+ }
+}
diff --git a/share/ecflow/etc/ecflowview_panel_conf.json b/share/ecflow/etc/ecflowview_panel_conf.json
new file mode 100644
index 0000000..5903340
--- /dev/null
+++ b/share/ecflow/etc/ecflowview_panel_conf.json
@@ -0,0 +1,68 @@
+{
+ "panel": {
+
+ "search" : {
+ "highlightColour" : {
+ "label" : "Highlight colour",
+ "default" : "rgb(250,250,50)"
+ }
+ },
+
+
+ "overview": {
+ "font" : {
+ "label" : "Info tab",
+ "default": "font(Monospace,)"
+ }
+ },
+ "manual" : {
+
+ "font" : {
+ "label" : "Manual tab",
+ "default": "font(Monospace,)"
+ }
+ },
+ "job" : {
+
+ "font" : {
+ "label" : "Job tab",
+ "default": "font(Monospace,)"
+ }
+ },
+ "script" : {
+
+ "font" : {
+ "label" : "Script tab",
+ "default": "font(Monospace,)"
+ }
+ },
+ "output" : {
+
+ "font" : {
+ "label" : "Output tab",
+ "default": "font(Monospace,)"
+ }
+ },
+ "why" : {
+
+ "font" : {
+ "label" : "Why tab",
+ "default": "font(Monospace,)"
+ }
+ },
+ "edit" : {
+
+ "font" : {
+ "label" : "Edit tab",
+ "default": "font(Monospace,)"
+ }
+ },
+ "variable" : {
+
+ "showShadowed" : {
+ "label" : "Show shadowed",
+ "default" : "true"
+ }
+ }
+ }
+}
diff --git a/share/ecflow/etc/ecflowview_panels.json b/share/ecflow/etc/ecflowview_panels.json
new file mode 100644
index 0000000..f86696b
--- /dev/null
+++ b/share/ecflow/etc/ecflowview_panels.json
@@ -0,0 +1,152 @@
+{
+ "file_id" : "ecflowview menu configuration",
+
+ "file_version" : "1.0",
+
+ "info_panel" :
+ [
+ {
+ "name" : "overview",
+ "label" : "Info",
+ "icon" : "overview.svg",
+ "dock_icon" : "overview.svg",
+ "show" : "toolbar",
+ "tooltip" : "Open <b>info</b> tab in a new Info Panel dialog",
+ "visible_for" : "server or node"
+ },
+
+ {
+ "name" : "manual",
+ "label" : "Manual",
+ "icon" : "manual.svg",
+ "dock_icon" : "manual_dock.svg",
+ "show" : "toolbar",
+ "tooltip" : "Open <b>manual</b> tab in a new Info Panel dialog",
+ "visible_for" : "node"
+ },
+
+ {
+ "name" : "script",
+ "label" : "Script",
+ "icon" : "script.svg",
+ "dock_icon" : "script_dock.svg",
+ "show" : "toolbar",
+ "tooltip" : "Open <b>script</b> tab in a new Info Panel dialog",
+ "visible_for" : "task or alias"
+ },
+
+ {
+ "name" : "job",
+ "label" : "Job",
+ "icon" : "job.svg",
+ "dock_icon" : "job_dock.svg",
+ "show" : "toolbar",
+ "tooltip" : "Open <b>job</b> tab in a new Info Panel dialog",
+ "visible_for" : "task or alias"
+ },
+
+ {
+ "name" : "output",
+ "label" : "Output",
+ "icon" : "output.svg",
+ "dock_icon" : "output_dock.svg",
+ "show" : "toolbar",
+ "tooltip" : "Open <b>output</b> tab in a new Info Panel dialog",
+ "visible_for" : "task or alias"
+ },
+
+ {
+ "name" : "why",
+ "label" : "Why",
+ "icon" : "why.svg",
+ "dock_icon" : "why_dock.svg",
+ "show" : "toolbar",
+ "tooltip" : "Open <b>why</b> tab in a new Info Panel dialog",
+ "visible_for" : "server or node"
+ },
+
+ {
+ "name" : "triggers",
+ "label" : "Triggers",
+ "visible_for" : "node",
+ "hidden" : "1"
+ },
+
+ {
+ "name" : "time",
+ "label" : "Time line",
+ "hidden" : "1",
+ "visible_for" : "server or node"
+ },
+
+ {
+ "name" : "variable",
+ "label" : "Variables",
+ "icon" : "variable.svg",
+ "dock_icon" : "variable_dock.svg",
+ "show" : "toolbar",
+ "tooltip" : "Open <b>variables</b> tab in a new Info Panel dialog",
+ "visible_for" : "server or node"
+
+ },
+
+ {
+ "name" : "edit",
+ "label" : "Edit",
+ "icon" : "edit.svg",
+ "dock_icon" : "edit.svg",
+ "show" : "toolbar",
+ "tooltip" : "Open <b>edit</b> tab in a new Info Panel dialog",
+ "visible_for" : "task or alias"
+ } ,
+
+ {
+ "name" : "history",
+ "label" : "Server log",
+ "icon" : "server_log.svg",
+ "dock_icon" : "log.svg",
+ "show" : "toolbar",
+ "tooltip" : "Open <b>server log</b> tab in a new Info Panel dialog",
+ "visible_for" : "server"
+
+ },
+
+ {
+ "name" : "message",
+ "label" : "Node log",
+ "icon" : "node_log.svg",
+ "show" : "toolbar",
+ "tooltip" : "Open <b>Node log</b> tab in a new Info Panel dialog",
+ "visible_for" : "server or node"
+
+ },
+
+ {
+ "name" : "zombie",
+ "label" : "Zombies",
+ "icon" : "zombie.svg",
+ "dock_icon" : "zombie_dock.svg",
+ "show" : "toolbar",
+ "tooltip" : "Open <b>zombies</b> tab in a new Info Panel dialog",
+ "visible_for" : "server"
+
+ },
+
+ {
+ "name" : "suite",
+ "label" : "Suite filter",
+ "icon" : "filter.svg",
+ "visible_for" : "server"
+
+ },
+
+ {
+ "name" : "server_settings",
+ "label" : "Settings",
+ "icon" : "configure.svg",
+ "visible_for" : "server"
+
+ }
+
+ ]
+}
diff --git a/share/ecflow/etc/ecflowview_server_conf.json b/share/ecflow/etc/ecflowview_server_conf.json
new file mode 100644
index 0000000..f4c3123
--- /dev/null
+++ b/share/ecflow/etc/ecflowview_server_conf.json
@@ -0,0 +1,160 @@
+{
+ "server": {
+
+ "label" : "Server options",
+
+ "update": {
+ "label" : "Update",
+ "tooltip" : "update",
+
+ "autoUpdate": {
+ "label": "Update server state automatically",
+ "tooltip" : "When enabled the server is queried for updates at regular intervals.",
+ "default": "true"
+ },
+
+ "updateRateInSec": {
+ "label": "Server update period",
+ "suffix" : "seconds",
+ "tooltip": "Defines the automatic server update period.",
+ "default": "60",
+ "min" : "0"
+ },
+
+ "adaptiveUpdate": {
+ "label": "Increase server update period when inactive",
+ "tooltip" : "When enabled the server update period is <b>increased at every automatic update</b> until the maximum period is reached. If the user in the meantime updates the server manually the update period is set back to its original value and whole process starts again.",
+ "default": "true"
+ },
+
+ "adaptiveUpdateIncrementInSec": {
+ "label": "Server update period increment",
+ "suffix" : "seconds",
+ "tooltip": "Defines by how many seconds the server update period is <b>increased</b> at every automatic update.",
+ "default": "5",
+ "min" : "0"
+ },
+ "maxAdaptiveUpdateRateInMin": {
+ "label": "Do not increase server update period over",
+ "suffix" : "minutes",
+ "tooltip": "Defines the <b>maximum</b> server update period. When it is reached the update period is not increased any more.",
+ "default": "60",
+ "min" : "0"
+ }
+ },
+
+ "files": {
+ "label" : "Files",
+ "tooltip" : "files",
+
+ "readFilesFromDisk": {
+ "label": "Read files from disk when appropriate",
+ "tooltip": "The following steps are tried to fetch the files: <ol><li>fetch the files from the logserver (if defined)</li><li>read from disk (if option is <b>enabled</b> and file is accessible)</li><li>fetch from the ecflow server</li></ul>",
+ "default": "true"
+ },
+
+ "maxOutputFileLines": {
+ "label": "Fetch the last",
+ "suffix" : "lines of files from the server",
+ "tooltip": "",
+ "default": "15000",
+ "min" : "0"
+ }
+ },
+
+ "notification": {
+ "label" : "Popup notifications",
+ "tooltip" : "Popup notifications",
+
+ "aborted" : {
+ "label" : "Aborted",
+
+ "enabled" : {
+ "label" : "Enabled",
+ "default" : "true"
+ },
+ "popup" : {
+ "label" : "Popup dialog",
+ "default" : "true"
+ },
+ "sound" : {
+ "label": "Play sound",
+ "tooltip": "Play sound",
+ "default": "false"
+ }
+ },
+ "restarted" : {
+ "label" : "Restarted",
+
+ "enabled" : {
+ "label" : "Enabled",
+ "default" : "true"
+
+ },
+ "popup" : {
+ "label" : "Popup dialog",
+ "default" : "true"
+ },
+ "sound" : {
+ "label": "Play sound",
+ "tooltip": "Play sound",
+ "default": "false"
+ }
+ },
+ "late" : {
+ "label" : "Late tasks",
+
+ "enabled" : {
+ "label" : "Enabled",
+ "default" : "true"
+ },
+ "popup" : {
+ "label" : "Popup dialog",
+ "default" : "true"
+ },
+ "sound" : {
+ "label": "Play sound",
+ "tooltip": "Play sound",
+ "default": "false"
+ }
+ },
+ "zombie" : {
+ "label" : "Zombies",
+
+ "enabled" : {
+ "label" : "Enabled",
+ "default" : "false"
+
+ },
+ "popup" : {
+ "label" : "Popup dialog",
+ "default" : "false"
+ },
+ "sound" : {
+ "label": "Play sound",
+ "tooltip": "Play sound",
+ "default": "false"
+ }
+ },
+ "alias" : {
+ "label" : "Aborted or restarted aliases",
+
+ "enabled" : {
+ "label" : "Enabled",
+ "default" : "false"
+
+ },
+ "popup" : {
+ "label" : "Popup dialog",
+ "default" : "false"
+ },
+ "sound" : {
+ "label": "Play sound",
+ "default": "false"
+ }
+ }
+
+ }
+
+ }
+}
diff --git a/share/ecflow/etc/ecflowview_sstate_conf.json b/share/ecflow/etc/ecflowview_sstate_conf.json
new file mode 100644
index 0000000..c1de029
--- /dev/null
+++ b/share/ecflow/etc/ecflowview_sstate_conf.json
@@ -0,0 +1,57 @@
+{
+ "sstate": {
+
+ "halted": {
+ "label": "Halted",
+ "tooltip": "halted",
+ "fill_colour" : {
+ "label" : "Colour",
+ "default": "rgb(238,130,238)"
+ },
+ "font_colour" : {
+ "label" : "Font colour",
+ "default": "rgb(0,0,0)"
+ }
+ },
+
+ "shutdown": {
+ "label": "Shutdown",
+ "tooltip": "shutdown",
+ "fill_colour" : {
+ "label" : "Colour",
+ "default": "rgb(255,192,203)"
+ },
+ "font_colour" : {
+ "label" : "Font colour",
+ "default": "rgb(0,0,0)"
+ }
+ },
+
+ "running": {
+ "label": "Running",
+ "tooltip": "running",
+ "fill_colour" : {
+ "label" : "Colour",
+ "default": "rgb(0,255,0)"
+ },
+ "font_colour" : {
+ "label" : "Font colour",
+ "default": "rgb(0,0,0)"
+ }
+ },
+ "disconnected": {
+ "label": "Disconnected",
+ "tooltip": "disconnected",
+ "fill_colour" : {
+ "label" : "Colour",
+ "default": "rgb(200,200,200)"
+ },
+ "font_colour" : {
+ "label" : "Font colour",
+ "default": "rgb(0,0,0)"
+ }
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/share/ecflow/etc/ecflowview_view_conf.json b/share/ecflow/etc/ecflowview_view_conf.json
new file mode 100644
index 0000000..67dbadd
--- /dev/null
+++ b/share/ecflow/etc/ecflowview_view_conf.json
@@ -0,0 +1,233 @@
+{
+ "view": {
+
+ "common" : {
+ "node_style" : {
+ "label" : "Node rendering style",
+ "default" : "modern",
+ "values" : "classic/modern",
+ "values_label" : "Text in status rectangle (classic)/Separate text and status rectangle"
+ },
+ "node_gradient" : {
+ "label" : "Use gradient shading",
+ "default" : "true"
+ },
+ "fontSize" : {
+ "label": "Application",
+ "suffix" : "points",
+ "default": "9",
+ "min" : "7",
+ "max" : "20"
+ }
+ },
+ "tree": {
+
+ "nodeFont" : {
+ "label" : "Nodes",
+ "default": "font(,)"
+ },
+
+ "attributeFont" : {
+ "label" : "Attributes",
+ "default": "font(,)"
+ },
+
+ "display_child_count" : {
+ "label" : "Display number of children for servers/suites",
+ "default": "true"
+ },
+
+ "displayNodeType" : {
+ "label" : "Display node type",
+ "default": "true"
+ },
+
+ "background" : {
+ "label" : "Background colour",
+ "default" : "rgb(250,250,250)"
+ },
+ "indentation" : {
+ "label" : "Indentation",
+ "suffix" : "pixels",
+ "default" : "10",
+ "min" : "0",
+ "max" : "100"
+ },
+ "drawBranchLine" : {
+ "label" : "Draw branch lines",
+ "default": "false"
+ },
+ "defaultAttributes" : {
+ "label" : "Default visible attributes",
+ "default" : "meter/event/repeat/trigger/label/time/date/limit/limiter/late",
+ "multi" : "true",
+ "values" : "meter/event/repeat/trigger/label/time/date/limit/limiter/late/var/genvar",
+ "values_label" : "Meters/Events/Repeats/Triggers/Labels/Times/Dates/Limits/Limiters/Late/Variables/Generated variables"
+ },
+ "attributesPolicy" : {
+ "label" : "In new tree views show",
+ "default" : "default",
+ "values" : "default/last",
+ "values_label" : "default visible attributes/attributes from last modified view"
+ },
+ "serverToolTip" : {
+ "label" : "Show tooltip on servers",
+ "default": "true"
+ },
+ "nodeToolTip" : {
+ "label" : "Show tooltip on nodes",
+ "default": "true"
+ },
+ "attributeToolTip" : {
+ "label" : "Show tooltip on attributes",
+ "default": "true"
+ }
+ },
+
+ "table": {
+
+ "background" : {
+ "label" : "Background colour",
+ "default" : "rgb(250,250,250)"
+ },
+ "font" : {
+ "label" : "Font",
+ "default": "font(,)"
+ }
+ },
+
+ "attribute" : {
+
+ "eventFillColour" : {
+ "label" : "Event set colour",
+ "default" : "rgb(0,0,255)"
+ },
+ "meterFillColour" : {
+ "label" : "Meter colour",
+ "default" : "rgb(0,0,255)"
+ },
+ "meterThresholdColour" : {
+ "label" : "Meter threshold colour",
+ "default" : "rgb(0,0,255)"
+ },
+ "limitFillColour" : {
+ "label" : "Limit colour",
+ "default" : "rgb(0,255,0)"
+ }
+ },
+
+ "textEdit" : {
+
+ "numAreaBackground" : {
+ "label": "Line number area background",
+ "default": "rgb(232,231,230)"
+ },
+ "numAreaFontColour" : {
+ "label": "Line number area font colour",
+ "default": "rgb(102,102,102)"
+ },
+ "numAreaSeparator" : {
+ "label": "Line number area separtor colour",
+ "default": "rgb(210,210,210)"
+ },
+ "numAreaCurrent" : {
+ "label": "Line number area current line colour",
+ "default": "rgb(212,212,255)"
+ }
+ }
+
+ },
+
+ "query_columns": {
+
+ "server" : {
+ "label" : "Server",
+ "tooltip" : "Server"
+ },
+ "path" : {
+ "label" : "Node",
+ "tooltip" : "Node"
+ },
+ "status" : {
+ "label" : "State",
+ "tooltip" : "Node status"
+ },
+ "type" : {
+ "label" : "Type",
+ "tooltip" : "Node type"
+ },
+ "attribute" : {
+ "label" : "Attribute"
+ }
+ },
+
+ "table_columns": {
+
+ "path" : {
+ "label" : "Node",
+ "tooltip" : "Node"
+ },
+ "status" : {
+ "label" : "Status"
+ },
+ "type" : {
+ "label" : "Type"
+ },
+ "trigger" : {
+ "label" : "Trigger"
+ },
+ "label" : {
+ "label" : "Label"
+ },
+ "event" : {
+ "label" : "Event"
+ },
+ "meter" : {
+ "label" : "Meter"
+ }
+ },
+
+ "zombie_columns": {
+
+ "path" : {
+ "label" : "Path",
+ "tooltip" : "Path of task node"
+ },
+ "type" : {
+ "label" : "Type",
+ "tooltip" : "Type of zombie"
+ },
+ "duration" : {
+ "label" : "Duration",
+ "tooltip" : "Duration"
+ },
+ "allowed" : {
+ "label" : "Allowed",
+ "tooltip" : "The age the zombie is allowed to live. Server typically checks every 60 seconds, hence this is lowest valid value that has effect"
+ },
+ "password" : {
+ "label" : "Password",
+ "tooltip" : "Password of the job"
+ },
+ "pid" : {
+ "label" : "Pid",
+ "tooltip" : "Process or remote id"
+ },
+ "tryno" : {
+ "label" : "Try no",
+ "tooltip" : "Try number"
+ },
+ "action" : {
+ "label" : "Action",
+ "tooltip" : "User action"
+ },
+ "child" : {
+ "label" : "Child cmd",
+ "tooltip" : "Child command"
+ },
+ "calls" : {
+ "label" : "Calls",
+ "tooltip" : "password of the job"
+ }
+ }
+}
diff --git a/share/ecflow/etc/sounds/CMakeLists.txt b/share/ecflow/etc/sounds/CMakeLists.txt
new file mode 100644
index 0000000..d164e3e
--- /dev/null
+++ b/share/ecflow/etc/sounds/CMakeLists.txt
@@ -0,0 +1,13 @@
+
+# the list of files we want to install
+set (files tone.ogg)
+
+# for each file, copy it into the build directory at build time
+# and install it into the installation directory at install time (!)
+foreach( f ${files} )
+ configure_file(${f} ${CMAKE_CURRENT_BINARY_DIR} COPYONLY)
+
+ install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${f}
+ DESTINATION share/ecflow/etc/sounds
+ PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)
+endforeach()
diff --git a/share/ecflow/etc/sounds/tone.ogg b/share/ecflow/etc/sounds/tone.ogg
new file mode 100644
index 0000000..7b3a1f3
Binary files /dev/null and b/share/ecflow/etc/sounds/tone.ogg differ
diff --git a/share/ecflow/etc/viewer.qss b/share/ecflow/etc/viewer.qss
new file mode 100644
index 0000000..8e3d90f
--- /dev/null
+++ b/share/ecflow/etc/viewer.qss
@@ -0,0 +1,370 @@
+/*----------------------------
+ Mainwindow
+------------------------------*/
+
+QMainWindow {
+ icon-size: 18px;
+}
+
+/*QToolBar {
+ top-padding: 1px;
+ bottom-padding: 1px;
+ icon-size: 20px;
+}*/
+
+QToolBar > QToolButton {
+ padding: 1px;
+}
+
+QToolTip { color: black; background-color: rgb(192,218,255); border: 1px solid rgb(60,59,58);}
+
+/* ----------------------------
+ Breadcrumbs
+-------------------------------*/
+
+QWidget[breadcrumbs="1"] {
+ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 rgb(255,255,255), stop: 1 rgb(255,255,255));
+ border-radius: 0px;
+ border: 1px solid rgb(140,140,140);
+ /*border-top-width: 4px;*/
+}
+
+QToolButton#pathNameTb {
+ border-radius: 0px;
+ padding: 0px;
+ color: black;
+ }
+
+QToolButton#pathNameTb:hover{
+ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #deebf6, stop: 1 #bed8ee);
+ border: 1px solid rgb(160, 160, 160);
+ border-radius: 0px;
+ padding: 0px;
+ }
+
+QToolButton#pathIconTb{
+ border: none;
+ padding: 0px;
+ }
+
+QToolButton#pathIconTb:hover{
+ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 rgb(253,253,253), stop: 1 rgb(227,227,227));
+ border: 1px solid rgb(180, 180, 180);
+ border-radius: 0px;
+ padding: 0px;
+ }
+
+QToolButton#pathMenuTb{
+ image: url(":/viewer/path_arrow.svg");
+ border: none;
+ padding: 0px;
+}
+
+QToolButton#pathMenuTb:hover{
+ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 blue, stop 0.5 red, stop: 1 white);
+ border: 1px solid rgb(160, 160, 160);
+ border-radius: 0px;
+ padding: 0px;
+}
+
+QLabel[previewLabel="1"] {
+ padding: 2px;
+ border-radius: 4px;
+ background: rgb(234,215,150);
+ border: 2px solid rgb(210,210,210);
+}
+
+/* Property editor */
+
+QToolButton[colorTb="1"] {
+ border-radius: 2px;
+ padding: 0px;
+}
+
+/*-----------------------------
+ Notifications
+------------------------------*/
+
+QToolButton[notify="1"] {
+ padding: 1px;
+}
+
+QTabBar[notify="1"]::tab {
+ padding : 2px;
+}
+
+/*----------------------------
+ Icon folder view
+------------------------------*/
+
+/* QGraphicsview cannot be set from qss, only its
+baseclass QFrame. So we need to set QFrame here! */
+QFrame[breadcrumbs="1"] {
+ background: rgb(252, 252, 252);
+ border: 0;
+}
+
+/*----------------------------
+ TreeNodeView
+------------------------------*/
+
+/*QTreeView[style="nodeView"] {
+ background: rgb(250,250,250);
+}
+
+QTreeView[style="nodeView"]::item {
+ alternate-background-color: rgb(248,247,246);
+}*/
+
+/*
+QTreeView[style="nodeView"]::branch:has-siblings:!adjoins-item {
+ border-image: none;
+}
+
+QTreeView[style="nodeView"]::branch:!has-children:has-siblings:adjoins-item {
+ border-image: url(:/viewer/tree_branch_more.png) 0;
+}
+
+
+QTreeView[style="nodeView"]::branch:!has-children:!has-siblings:adjoins-item {
+ border-image: url(:/viewer/tree_branch_end.png) 0;
+}
+*/
+
+
+/*-----------------------------
+ Log
+------------------------------*/
+
+/*QTreeView {
+ selection-background-color: transparent;
+ outline: 0;
+}*/
+
+QTreeView::item:selected
+{
+ background: rgb(180,204,234);
+ color: black;
+ /*border-top: 1px solid rgb(8,117,182);
+ border-bottom: 1px solid rgb(8,117,182);
+ border-left-color: transparent;
+ border-right-color: transparent;*/
+
+}
+
+/*
+QTreeView[log="1"]::item:selected {
+ background: rgb(245,245,245);
+ border-top: 1px solid rgb(200,200,200);
+ border-bottom: 1px solid rgb(180,180,180);
+ color: black;
+ border-left-color: transparent;
+ border-right-color: transparent;
+
+}
+
+QTreeView[log="1"]::item {
+ border: 1px solid rgb(230,230,230);
+ border-top-color: transparent;
+ border-left-color: transparent;
+ border-right-color: 1px solid rgb(230,230,230);
+}
+*/
+
+/*----------------------------
+ Info panel text
+------------------------------*/
+
+QPlainTextEdit[form="1"][readOnly="false"] {
+ background-color: rgb(255,255,255);
+}
+
+QPlainTextEdit[edit="1"][readOnly="false"] {
+ background-color: rgb(245,245,245);
+}
+
+QPlainTextEdit[readOnly="true"] {
+ background-color: rgb(245,245,245);
+}
+
+QLineEdit[readOnly="true"] {
+ background-color: rgb(245,245,245);
+}
+
+QAbstractScrollArea[pager="1"] {
+ background-color: rgb(245,245,245);
+}
+
+/*----------------------------
+ File info label
+------------------------------*/
+
+QLabel[fileInfo="1"] {
+ border: 1px solid rgb(216,210,200);
+ /*background: rgb(252, 241, 219); */
+ background: rgb(244, 239, 216);
+}
+
+/*----------------------------
+ Editor info label
+------------------------------*/
+
+QLabel[editorInfo="1"] {
+ border: 1px solid rgb(206,209,196);
+ /*background: rgb(252, 241, 219); */
+ background: rgb(242, 242, 242);
+}
+
+
+/*----------------------------
+ Property editor
+------------------------------*/
+
+QWidget[editorHeader="1"] {
+ background: rgb(253, 253, 253);
+ border: 1px solid rgb(160,160,160);
+}
+
+QLabel#headerLabel_ {
+ border: none;
+ color: rgb(40, 41, 42);
+ font-weight: bold;
+ font-size: 11pt;
+}
+
+QLabel[editorNotifyHeader="1"] {
+ background: rgb(253, 253, 253);
+ /*border: 1px solid rgb(160,160,160); */
+ /*color: rgb(40, 41, 42);
+ font-weight: bold;
+ font-size: 11pt;*/
+}
+
+QGroupBox#editorGroupBox {
+
+ font-weight: normal;
+}
+
+QScrollArea[editor="1"] {
+ border: none;
+}
+
+QWidget[editorArea="1"] {
+ background-color: rgb(245,244,244);
+}
+
+
+/*----------------------------
+ Dock widget
+------------------------------*/
+
+QWidget[dockTitle="11"] {
+ background: rgb(26, 246, 246);
+}
+
+QToolButton[docktitle="1"] {
+ border-radius: 0px;
+ padding: 0px;
+ icon-size: 18px;
+ background: transparent;
+}
+
+QToolButton[docktitle="1"]:!focus {
+ border-radius: 0px;
+ padding: 0px;
+ icon-size: 18px;
+ background: transparent;
+}
+
+QToolButton[docktitle="1"]:hover {
+ border-radius: 0px;
+ padding: 0px;
+ icon-size: 18px;
+ background: rgb(140,140,140);
+}
+
+QToolButton[docktitle="1"]::menu-indicator {
+ image: url(:/viewer/dock_menu_indicator.png);
+}
+
+/*----------------------------
+ Variable tree view
+------------------------------*/
+
+QTreeView[var="1"]::item {
+ alternate-background-color: rgb(250,250,250);
+}
+
+/*---------------------------------
+ Tab widget
+------------------------------------*/
+/*QTabBar[change="1"]::tab {
+ padding : 2px;
+}*/
+
+
+/*QTreeView[var="1"]::branch:!has-children {
+ background: white;
+ border: 1px solid #BBBBBB;
+ border-top-color: transparent;
+ border-left-color: transparent;
+ border-right-color: transparent;
+}
+
+
+QTreeView[var="1"]::branch:!has-children {
+ image: none;
+}
+
+QTreeView[var="1"]::branch:!has-children:alternate {
+ background: rgb(200,0,0);
+}
+ */
+/*
+QTreeView[var="1"]::branch:alternate {
+ background: rgb(248,247,246);
+}
+*/
+
+/*
+QTreeView[var="1"]::item:has-children {
+ background: rgb(122,122,122);
+ color: white;
+}
+*/
+
+/*
+QTreeView[var="1"]::branch:has-children {
+ background: rgb(122,122,122);
+}
+*/
+/*
+QTreeView[var="1"]::branch:has-children:closed {
+ border-image: none;
+ image: url(":/viewer/drawer_close.svg");
+}
+
+QTreeView[var="1"]::branch:has-children:open {
+ border-image: none;
+ image: url(":/viewer/drawer_open.svg");
+}
+*/
+
+/*QAbstractItemView {
+ alternate-background-color: #FFE6BF;
+ background: #FFF2DE;
+ selection-background-color: rgb(194, 221, 255);
+}*/
+
+/*
+QTreeView[var="1"]::item {
+ border: 1px solid #BBBBBB;
+ border-top-color: transparent;
+ border-left-color: transparent;
+ border-right-color: transparent;
+ }
+
+QTreeView::item:selected[var="1"] {
+ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #f0f7fd, stop: 1 #b9cfec);
+}
+*/
diff --git a/tools/ecf_cmd b/tools/ecf_cmd
new file mode 100755
index 0000000..2b6918f
--- /dev/null
+++ b/tools/ecf_cmd
@@ -0,0 +1,859 @@
+#!/bin/ksh
+#==========================================================================
+##.TITLE EMOS - METAPS utilities
+##.NAME ecf_cmd
+##.SECTION EMOS
+##.DATE 2005-09-12
+##.VERSION 1.0
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+#==========================================================================
+
+##$ sms_submit user host file
+##
+##? Decides according to host argument which submit method to use.
+
+# Modifications:
+
+# Error handling and cleanup
+export SGE_ROOT=/usr/local/apps/sge
+export SLURM_ROOT=/usr/local/apps/slurm/current/bin
+export LL_ROOT=/usr/lpp/LoadL/full/bin
+STANDALONE=/usr/local/apps/sms/bin/standalone
+RUNSHELL=/bin/ksh
+TIMEOUT=300 # timeout period (seconds)
+SSH="ssh -o ConnectTimeout=$TIMEOUT -o BatchMode=yes -o StrictHostKeyChecking=no "
+RSH=rsh
+PROFILE=". $HOME/.profile"
+type rsh > /dev/null || RSH=$SSH
+
+#--------------------------------------------------------------------------
+# Parameters for ecrcmd
+#--------------------------------------------------------------------------
+
+SSH="ssh -o ConnectTimeout=$TIMEOUT -o BatchMode=yes -o StrictHostKeyChecking=no "
+
+ERROR() {
+ err=$?
+ echo "ERROR $0: $* $? - Exiting."
+ # CP_SUB
+
+ [[ -f $subfile ]] && grep "has been submitted" $subfile && exit 0
+ [[ -f $subfile ]] && grep "Submitted batch job" $subfile && exit 0
+# Unable to run job: failed receiving gdi request # TBD OK
+ cat $subfile
+ exit $err
+}
+
+kill_submitted_and_abort() {
+ # not used while not deterministic: job may run in betweem and
+ # become a zombie
+ outf=$TMPDIR/kill$$
+ if [[ $? == 0 ]] && [[ -d $TMPDIR ]] ; then
+ touch $outf
+ grep "ECF_NODE=" ${subfile%.sub} > $outf && \
+ grep "ECF_PORT=" ${subfile%.sub} >> $outf && \
+ grep "ECF_NAME=" ${subfile%.sub} >> $outf && \
+ grep "ECF_PASS=" ${subfile%.sub} >> $outf && \
+ echo "export ECF_NODE ECF_PORT ECF_NAME ECF_PASS" >>$outf &&\
+ echo "ecflow_client --abort || :" >> $outf && . $outf
+ grep "^SMSNODE=" ${subfile%.sub} > $outf && \
+ grep "^SMS_PROG=" ${subfile%.sub} >> $outf && \
+ grep "^SMSNAME=" ${subfile%.sub} >> $outf && \
+ grep "^SMSPASS=" ${subfile%.sub} >> $outf && \
+ echo "export SMSNODE SMS_PROG SMSNAME SMSPASS " >> $outf && \
+ echo "smsabort || :" >> $outf && . $outf
+ ksh -x $outf
+ rm -f $outf
+ fi
+}
+
+kill_nqs() {
+ if [[ -s $subfile ]] ; then
+ tid=$(tail -1 $subfile | cut -d\. -f1 )
+ # tid=`tail -1 $subfile | cut -d\. -f1 `
+ # where=`tail -1 $subfile | cut -d\. -f2 `
+ $RSH $host -l $user qsig -s 2 $tid || qsig -s 2 $tid
+ $RSH $host -l $user qdel -W 10 $tid || qdel -W 10 $tid
+
+ elif [[ -s $4 ]] ; then
+ tid=$(grep PBS_JOB ${4}.1 | cut -d= -f2)
+ $RSH $host -l $user qsig -s 2 $tid
+ $RSH $host -l $user qdel -W 10 $tid
+
+ else
+ # Signal the job
+ $RSH $host -l $user qsig -s 2 $smsid
+
+ # Remove the job from PBS (give 10 ssmeconds delay for the above to finish)
+ $RSH $host -l $user qdel -W 10 $smsid
+ fi
+}
+
+kill_vpp() {
+ $RSH $host -l $user qdel -2 $smsid
+}
+
+kill_nqs() {
+ $RSH $host -l $user qdel -2 $smsid
+}
+
+kill_sge() {
+ use sge || :
+ QDEL=sge_qdel
+ type $QDEL || QDEL="ssh $host $SGE_ROOT/sge6_2u5/bin/lx24-amd64/qdel"
+ if [[ -s $subfile ]] then
+ tid=$(grep " has been submitted" $subfile | cut -f 3 -d" ")
+ $QDEL $tid
+ elif [[ -s $4 ]] ; then
+ tid=$(grep active_jobs $4 | grep cd | cut -d"." -f 2 | cut -d"/" -f8)
+ $QDEL $tid
+ else
+ $QDEL $smsid
+ fi
+}
+
+kill_new_linux() {
+ tid=$(grep " has been submitted" $subfile | cut -f 3 -d" ")
+ $SSH $host -l $user $SGE_ROOT/sge6_2u5/bin/lx24-amd64/qdel $tid
+}
+
+kill_ll() {
+ if [[ -s $subfile ]] then
+ tid=$(grep " has been submitted." $subfile | cut -d\" -f2)
+ $RSH $host -l $user $LL_ROOT/llcancel $tid
+ else
+
+ if [[ "$host" == hpc* ]] ; then
+ host=$(echo $host | cut -c1-4)
+ id=${host}0$(echo $smsid % 1000 | bc).$(echo $smsid / 1000 | bc)
+ else
+ id=$smsid
+ if [[ -f $smsid ]] ; then
+ grep "LOADL_STEP_ID=NOT_SET" $subfile && \
+ id=$(grep JOB_ID= $subfile | cut -d= -f2) && \
+ $RSH $host -l user kill -9 $id
+ fi
+ fi
+
+ $RSH $host -l $user $LL_ROOT/llcancel $id
+ fi
+}
+
+kill_slurm() {
+ if [[ -s $subfile ]] then
+ tid=$(grep "Submitted batch job " $subfile | awk '{print $4}')
+ $SSH $host -l $user $SLURM_ROOT/scancel $tid
+ else
+ id=$smsid
+ if [[ -f $smsid ]] ; then
+ grep "LOADL_STEP_ID=NOT_SET" $subfile && id=$(grep JOB_ID= $subfile | \
+ cut -d= -f2) && \
+ $SSH $host -l $user kill -9 $id
+ fi
+
+ $SSH $host -l $user $SLURM_ROOT/scancel $id
+ fi
+}
+
+kill_rsh() {
+ $RSH $host -l $user /bin/kill -2 $smsid
+ # SGI syntax: kill -signal -pgid
+ $RSH $host -l $user kill -15 $smsid || kill -15 $smsid
+}
+
+status_pbs() {
+
+ qstat=/usr/local/apps/propbs/bin/qstat
+
+ if [[ -s $subfile ]] ; then
+ display_subfile
+ tid=$(tail -1 $subfile)
+ elif [[ -s $smsjob ]] ; then
+ tid=$(grep PBS_JOB ${smsjob}.1 | cut -d= -f2)
+ else
+ tid=$smsid
+ fi
+
+ banner "** output ** "
+ $RSH $host -l $user tail -100 /var/spool/PBS/spool/${tid}* &
+ wait
+ banner "** qstat ** "
+ $RSH $host -l $user $qstat -f $tid | grep $user && OK=OK &
+
+}
+
+status_vpp() {
+ $RSH $host -l $user qstat $smsid | grep $user && OK=OK &
+}
+
+status_nqs() {
+ $RSH $host -l $user qstat $smsid | grep $user && OK=OK &
+}
+
+status_swarm() {
+# use sge
+ task_name=$(basename $smsjob | cut -d\. -f1)
+ if [[ -s $subfile ]] then
+ display_subfile
+ tid=$(grep " has been submitted" $subfile | cut -f 3 -d" ")
+ elif [[ -s $smsjob ]] ; then
+ tid=$(grep active_jobs $smsjob | grep cd | cut -d"." -f 2 | cut -d"/" -f8)
+ else
+ tid=$smsrid
+ fi
+
+ printf "==============================================================\n"
+ if [[ $host == @(lxa|lxb|lxab) ]] ; then
+ cat $file | $SSH $host $SGR_ROOT/sge6_2u5/bin/lx24-amd64/qstat -u $user -f | \
+ grep -E "$task_name|$tid" | grep $user && OK=OK
+ cat $file | $SSH $host $SGE_ROOT/sge6_2u5/bin/lx24-amd64/qstat -j $tid && \
+ print "$smsjob is there\n" || print "$smsjob not there ... \n"
+ else
+ qstat -u $user -f | grep -E "$task_name|$tid" | grep $user && OK=OK
+ qstat -j $tid && print "$smsjob is there\n" || print "$smsjob not there ... \n"
+ fi
+ printf "==============================================================\n"
+}
+
+status_new_linux() {
+ status_swarm
+}
+
+status_ll() {
+ if [[ -s $subfile ]] then
+ tid=$(grep " has been submitted." $subfile | cut -d\" -f2)
+ host=$(echo $tid | cut -d\. -f1)
+ host4=$(echo $host | cut -c1-4)
+
+ $RSH $host $LL_ROOT/llq -f %id %jn %o %c %st %nh $tid | grep $user && OK=OK &
+
+ else
+
+ if [[ -s $smsjob ]] ; then
+ host=$(grep HOST= $smsjob | cut -d= -f2)
+ fi
+
+ if [[ "$host" == hpc* ]] ; then
+ host=$(echo $host | cut -c1-4)
+ host4=$(echo $host | cut -c1-4)
+ id=${host}0$(echo $smsid % 1000 | bc).$( echo $smsid / 1000 | bc)
+ else
+ id=$host.$smsid
+ fi
+
+ $RSH $host $LL_ROOT/llq -f %id %jn %o %c %st %nh $tid | grep $user
+ fi
+}
+
+status_slurm() {
+ if [[ -s $subfile ]] then
+ display_subfile
+ tid=$(grep "Submitted batch job" $subfile | cut -d' ' -f4)
+ $SSH -l $user $host $SLURM_ROOT/scontrol show job -d $tid
+ $SSH -l $user $host $SLURM_ROOT/squeue | grep $user | grep " $tid"
+ elif [[ $host != $hostname ]] ; then
+ $SSH -l $user $host "$0 $user $host $file $uout $smsid status"
+ fi
+}
+
+status_rsh() {
+ if [[ $smsid == 0 ]]; then echo "too early"; exit 0; fi
+ $RSH $host -l $user ps -elf | grep " $user " | grep " $smsid " | grep -v " grep " && \
+ $RSH $host -l $user ps --sid $smsid -f
+
+ \ps -elf | grep " $user " | grep " $smsid " | grep -v " grep " && OK=OK &
+ \ps --sid $smsid -f && OK=OK &
+}
+
+disp_subfile() {
+ if [[ -s $subfile ]]; then # && [[ $OK = NOK ]] ; then
+ ls -la $subfile
+ # echo # grep "^# +++ hpc" $subfile
+ cat $subfile
+ # && type=ll
+fi
+}
+
+#--------------------------------------------------------------------------
+# Check the number of arguments
+#--------------------------------------------------------------------------
+
+set -x
+echo $0 $*
+
+if [ $# -lt 3 ] ; then
+ echo
+ echo "usage: $0 <user> <host> file remote_output [node_suffix]"
+ echo
+ echo "example: $0 uid host task.job1"
+ echo "while node_suffix is empty, host-batch node is the target, "
+ echo " else \$node\$nodesuffix is the replacement target"
+ echo
+ exit 1
+fi
+
+set -x
+
+user=$1
+host=$2
+file=$3
+uout=$4
+node_suffix=$5
+smsid=$5
+
+for last; do true; done # last shall be submit status kill only
+case $last in
+submit | status | kill ) echo;;
+*) last="submit" ;;
+esac
+
+subfile=${file}.sub
+
+#--------------------------------------------------------------------------
+# determine queuing system from hostname
+# (can be replaced by a more refined method later...)
+#--------------------------------------------------------------------------
+
+hostname=$(hostname)
+
+case $host in
+ xxx_pbs) type=pbs;;
+ vpp* ) type=vppnqs;;
+ xxx_sge ) type=sge_qsub;;
+ xxx_slurm ) type=slurm;;
+ xxx_ll* ) type=ll;;
+ $hostname | localhost ) type=local;;
+ xxx_rsh) type=rsh;;
+ * ) type=ssh;;
+esac
+
+#--------------------------------------------------------------------------
+# determine job file type and output directory
+#--------------------------------------------------------------------------
+
+output=""
+if egrep -i "^#.*QSUB " $file > /dev/null ; then
+ jtype=nqs
+ output=$(egrep -i "^#.*QSUB -o" $file | cut -d" " -f 4 | head -1)
+
+elif egrep -i "^#.*@.*queue" $file > /dev/null ; then
+ jtype=ll
+ output=$(egrep -i "^#.*@.*output" $file | cut -d"=" -f 2 | head -1)
+
+elif [[ $host == @(xxx_slurm) ]] ; then
+ jtype=slurm
+ output=$(egrep -i "^#.*-o" $file | cut -d" " -f 3 | head -1)
+
+elif egrep -i "^#.*PBS " $file > /dev/null ; then
+ jtype=pbs
+
+elif egrep -i "^#.*SBATCH " $file > /dev/null ; then
+ jtype=slurm
+ output=$(egrep -i "^#.*-o" $file | cut -d" " -f 3 | head -1)
+ if [[ output == "" ]]; then
+ output=$(egrep -i "^#.*-output" $file | cut -d" " -f 3 | head -1)
+ fi
+ if [[ output == "" ]]; then output=$uout; fi
+ if [[ output != "" ]]; then
+ head -1 $output && grep "#!/" && RUNSHELL=$(head -1 $output | cut -d! -f2)
+ else
+ RUNSHELL="/bin/bash"
+ fi
+ case $RUNSHELL in
+ *tcsh) PROFILE=". $HOME/.tcshrc";;
+ *csh) PROFILE=". $HOME/.cshrc";;
+ esac
+elif [[ $host == @(linux_cluster|lxa|lxb|lxab|swarm) ]] ; then
+ jtype=sge_qsub
+ output=$(egrep -i "^#.*-o" $file | cut -d" " -f 3 | head -1)
+
+else
+ jtype=sh
+
+fi
+
+case $last in
+submit)
+#--------------------------------------------------------------------------
+# File must exist!
+#--------------------------------------------------------------------------
+
+if [[ ! -f $file ]] ; then
+ echo "$0: File $file not found?"
+ exit 1
+fi
+
+chmod 755 $file
+
+if [[ "$uout" != "" ]]; then output=$uout; mkdir -p $(dirname $uout); fi
+if [[ $output == *0.0 ]]; then echo "filename error $output"; exit 1; fi
+cp $file ${file}.pre
+# mailx -s "o:$output uo:$uout" $USER < /dev/null; exit 0
+
+LC="-c "
+if egrep -qi "^[[:space:]]*#[[:space:]]*@[[:space:]]*environment[[:space:]]*=" $file > /dev/null
+then
+ LC="-lc "
+fi
+
+[[ "$output" == "" ]] || outputdir=$(dirname $output)
+if [[ "$outputdir" != "" ]] ; then
+#--------------------------------------------------------------------------
+# Create the output directory if it can be found
+#--------------------------------------------------------------------------
+if [[ ! -d $outputdir ]] ; then
+ # don't worry anymore about output directory
+ $RSH $host -l $user mkdir -m 775 -p $outputdir || \
+ mkdir -m 775 -p $outputdir || /bin/true
+fi
+fi
+;;
+esac
+
+case $type in
+#==========================================================================
+# Submit to hp using PBS
+ pbs )
+#==========================================================================
+
+case $last in
+kill) kill_pbs; exit 0;;
+status) status_pbs; exit 0;;
+esac
+
+# get queue-name, job-name
+if [[ $jtype == nqs ]] ; then
+ queue=$(grep 'QSUB -q ' $file | cut -d" " -f 4 | head -1)
+ jname=$(grep 'QSUB -r ' $file | cut -d" " -f 4 | head -1)
+
+elif [[ $jtype == ll ]] ; then
+ queue=$(egrep '^#.*@.*class.*=' $file | cut -d"=" -f 2 | head -1)
+ jname=$(egrep '^#.*@.*job_name.*=' $file | cut -d"=" -f 2 | head -1)
+
+elif [[ $jtype != pbs ]] ; then
+ ERROR "No conversion available for these types ($jtype -> $type)."
+fi
+
+#--------------------------------------------------------------------------
+# Create the script (${file}__) that will contain the PBS directives
+#--------------------------------------------------------------------------
+
+if [[ $jtype != pbs ]] ; then
+
+cat > ${file}__ <<- EOF
+#!$RUNSHELL
+if [[ -f $HOME/.profile ]]; then
+$PROFILE
+fi
+#PBS -S /bin/ksh
+#PBS -N $jname
+#PBS -V
+#PBS -o /dev/null
+#PBS -e /dev/null
+#PBS -j oe
+#PBS -u $user
+#PBS -q $queue
+EOF
+
+ egrep -v '^#.*QSUB -|^:$|^#.*@' $file >> ${file}__
+
+ mv -f ${file}__ ${file}
+
+fi
+#--------------------------------------------------------------------------
+# Remote shell to $host and submit from there
+#--------------------------------------------------------------------------
+
+#rsh $host -l $user /usr/local/apps/propbs/bin/pbsqsub < $file || ERROR "Failed to submit job to PBS (possible failure of rsh)."
+
+if [[ $(uname -n) == @(xxx_slurm) ]]; then
+ $SSH -l $user $host /usr/local/apps/propbs/bin/pbsqsub -f $file > $subfile 2>&1 || \
+ ERROR "Failed to submit job to PBS. "
+else
+ ecrcmd --timeout=$TIMEOUT < $file $user@$host $LC \
+ /usr/local/apps/propbs/bin/pbsqsub -f $file > $subfile || \
+ ERROR "Failed to submit job to PBS."
+fi
+
+ ;;
+#==========================================================================
+# Submit to vpp using NQS
+ vppnqs )
+#==========================================================================
+
+case $last in
+kill) kill_vpp; exit 0;;
+status) status_vpp; exit 0;;
+esac
+
+if [[ $jtype == ll ]] ; then
+ /home/ma/emos/bin/ll2nqs.pl $file ${file}__ || ERROR "Conversion ll2nqs.pl failed."
+ mv -f ${file}__ $file
+
+elif [[ $jtype != nqs ]] ; then
+ ERROR "No conversion available for these types ($jtype -> $type)."
+
+else
+ grep -v "QSUB -p" $file | grep -v "QSUB -lh" > ${file}__
+ mv -f ${file}__ $file
+fi
+
+#--------------------------------------------------------------------------
+# Send the file using qsub
+# If send failed, sleep a while and try again, until maximum number of
+# tries.
+#--------------------------------------------------------------------------
+
+$SSH $host -l $user /usr/local/bin/vppqsub < $file | grep -i submitted > $subfile || \
+ ERROR "Failed to submit $file."
+
+ ;;
+#==========================================================================
+ sge_qsub ) # swarm linux cluster
+
+case $last in
+kill) kill_sge; exit 0;;
+status) status_sge; exit 0;;
+esac
+
+# get queue-name, job-name
+if [[ $jtype == nqs ]] ; then
+ queue=$(grep 'QSUB -q ' $file | cut -d" " -f 4 | head -1)
+ jname=$(grep 'QSUB -r ' $file | cut -d" " -f 4 | head -1)
+
+elif [[ $jtype == ll ]] ; then
+ queue=$(egrep '^#.*@.*class.*=' $file | cut -d"=" -f 2 | head -1)
+ jname=$(egrep '^#.*@.*job_name.*=' $file | cut -d"=" -f 2 | head -1)
+
+elif [[ $jtype != sge_qsub ]] ; then
+ ERROR "No conversion available for these types ($jtype -> $type)."
+fi
+
+#--------------------------------------------------------------------------
+# Create the script (${file}__) that will contain the PBS directives
+#--------------------------------------------------------------------------
+
+# if [[ $jtype != sge_qsub ]] ; then
+
+ queue=$(grep 'QSUB -q ' $file | cut -d" " -f 4 | head -1)
+
+cat > ${file}__ <<- EOF
+#\$ -S /home/ma/emos/bin/ksh
+#\$ -N ${jname}
+#\$ -V
+#\$ -o $output
+#\$ -j y
+#\$ -u $user
+#\$ -q $queue
+EOF
+
+ egrep -v '^#.*QSUB -|^:$|^#.*@' $file >> ${file}__
+ chmod 755 ${file}__
+ mv -f ${file}__ ${file}
+
+# fi
+
+ mkdir -m 775 -p $outputdir || /bin/true
+ if [[ $host == @(lxa|lxb|lxab) ]] ; then
+ cat $file | $SSH $host \
+ $SGE_ROOT/sge6_2u5/bin/lx24-amd64/qsub -notify > $subfile 2>&1 || \
+ ERROR "Job submission failed (${file}__)."
+ elif [[ $HOST == @(ibis|pikachu) ]] ; then
+ cat $file | $RSH drn01 \
+ SGE_ROOT=$SGE_ROOT $SGE_ROOT/bin/lx24-amd64/qsub -notify > $subfile 2>&1 || \
+ ERROR "Job submission failed (${file}__)."
+ elif [[ -d $SGE_ROOT ]]; then
+ /usr/local/share/sge_qsub -notify $file > $subfile 2>&1 || \
+ ERROR "Job submission failed (${file}__)."
+ else
+ cat $file | $SSH drn01 \
+ ${SGE_ROOT:=/usr/local/apps/sge}/bin/lx24-amd64/qsub -notify > $subfile 2>&1 || \
+ cat $file | $SSH drn01 \
+ SGE_ROOT=$SGE_ROOT $SGE_ROOT/bin/lx24-amd64/qsub -notify $file > $subfile 2>&1 || \
+ ERROR "Job submission failed (${file}__)."
+
+ # || ERROR "Job submission failed (${file}__)."
+ fi
+# sge_qsub -notify $file > $subfile || ERROR "Job submission failed (${file}__)."
+ ;;
+
+#==========================================================================
+# Submit to other workstation using NQS
+ nqs )
+#==========================================================================
+
+case $last in
+kill) kill_nqs; exit 0;;
+status) status_nqs; exit 0;;
+esac
+
+#--------------------------------------------------------------------------
+# Create the script (${file}__) that will run the qsub
+#--------------------------------------------------------------------------
+
+cat > ${file}__ <<- EOF
+#!/bin/ksh
+unset WAITQUEUE
+set -e
+EOF
+
+# qsub statement
+echo "/usr/local/share/qsub < ${file}" >> ${file}__
+
+#
+# Create the real request
+#
+grep -v "QSUB -A" $file | grep -v "QSUB -lh" | grep -v "QSUB -p" | grep -v "QSUB -u" > ${file}__.qsub
+mv -f ${file}__.qsub ${file}
+
+#--------------------------------------------------------------------------
+# Remote shell to $host and submit from there
+#--------------------------------------------------------------------------
+chmod +x ${file}__
+$SSH $host -l $user -n "${file}__" || ERROR "Job submission failed (${file}__)."
+
+sleep 10
+/bin/rm -f ${file}__
+
+ ;;
+#==========================================================================
+# Submit to IBM server using loadleveler
+ ll )
+#==========================================================================
+
+case $last in
+kill) kill_ll; exit 0;;
+status) status_ll; exit 0;;
+esac
+
+if [[ $jtype == nqs ]] ; then
+ #
+ # Create the real request
+ #
+ /home/ma/emos/bin/nqs2ll.pl $host $file ${file}__ || ERROR "Conversion nqs2ll.pl failed."
+ if [[ "$uout" != "" ]]; then
+ cat ${file}__ | sed -e "s:# @ output = .*:# @ output = $output:" | \
+ sed -e "s:# @ error .*:# @ error = $output:" > ${file}
+ else
+ mv -f ${file}__ ${file}
+ fi
+
+elif [[ $jtype != ll ]] ; then
+ ERROR "No conversion available for these types ($jtype -> $type)."
+fi
+#--------------------------------------------------------------------------
+# Remote shell to $host and submit from there
+#--------------------------------------------------------------------------
+
+if [[ $host == @(c2*) ]] ; then
+ # file="/ws$file"
+ if [[ $node_suffix == "" ]] ; then
+ host="${host}-batch"
+ else
+ host="${host}${node_suffix}"
+ fi
+fi
+
+if [[ $(uname -n) == @(xxx_slurm) ]]; then
+ $SSH -l $user ${host} \
+ "unset WAITQUEUE ; $LL_ROOT/llsubmit - 2>&1 " < $file > $subfile 2>&1 || \
+ ERROR "Failed to submit job to LoadLeveler. $?"
+else
+ ecrcmd --timeout=$TIMEOUT < $file $user@$host $LC \
+ "unset WAITQUEUE ; $LL_ROOT/llsubmit -" > $subfile || \
+ ERROR "Failed to submit job to LoadLeveler."
+fi
+
+ ;;
+
+ slurm ) # swarm linux cluster
+
+case $last in
+kill) kill_slurm; exit 0;;
+status) status_slurm; exit 0;;
+esac
+
+# get queue-name, job-name
+if [[ $jtype == nqs ]] ; then
+ queue=$(grep 'QSUB -q ' $file | cut -d" " -f 4 | head -1)
+ jname=$(grep 'QSUB -r ' $file | cut -d" " -f 4 | head -1)
+
+# srun sinfo
+ cat > ${file}__ <<- EOF
+#!$RUNSHELL
+#SBATCH --output=${output:-/dev/null}
+#SBATCH --error=${output:=/dev/null}
+#SBATCH --time=01:00:00
+#SBATCH --job-name=${jname}
+#SBATCH --get-user-env
+#SBATCH --uid=$user
+##BATCH --qos=normal # express/long
+$PROFILE
+EOF
+# cp $file ${file}.pre
+ cat $file | egrep -v '^#.*QSUB -|^:$|^#.*@' | \
+ grep -E -v '(^#.*SBATCH --output.*|#.*SBATCH --error.*|^#.*SBATCH --uid.*|^#.*SBATCH --qos.*)' >> ${file}__
+ chmod 755 ${file}__
+
+elif [[ $jtype == slurm ]]; then
+
+ cat > ${file}__ <<- EOF
+#!$RUNSHELL
+#SBATCH --output=${output:-/dev/null}
+#SBATCH --error=${output:-/dev/null}
+#SBATCH --time=01:00:00
+#SBATCH --job-name=${jname}
+#SBATCH --get-user-env
+#SBATCH --uid=$user
+##BATCH --qos=normal # express/long
+$PROFILE
+EOF
+# cp $file ${file}.pre
+ cat $file | egrep -v '^#.*QSUB -|^:$|^#.*@' | \
+ grep -E -v '(^#.*SBATCH --output.*|#.*SBATCH --error.*|^#.*SBATCH --uid.*|^#.*SBATCH --qos.*)' >> ${file}__
+ chmod 755 ${file}__
+
+elif [[ $jtype == ll ]] ; then
+ $PROFILE
+ # /usr/local/apps/slurm/utils/bin/ll2slurm
+ ll2slurm -q -i $file -o ${file}__ || ERROR "Job conversion to slurm failed (${file})."
+elif [[ $jtype != slurm ]]; then
+ ERROR "No conversion available for these types ($jtype -> $type)."
+fi
+
+#--------------------------------------------------------------------------
+# Create the script (${file}__) that will contain the PBS directives
+#--------------------------------------------------------------------------
+ mv ${file}__ $file
+
+ if [[ $hostname == @(xxx_slurm) ]]; then
+ touch $output
+ $SLURM_ROOT/sbatch < ${file} > $subfile 2>&1 \
+ || ERROR "Job submission failed (${file})."
+ else
+ $SSH $host -l $user touch $output
+ cat ${file} | $SSH $host -l $user $SLURM_ROOT/sbatch > $subfile 2>&1 \
+ || ERROR "Job submission failed (${file})."
+ fi
+;;
+#==========================================================================
+# Submit using ssh
+#==========================================================================
+ ssh )
+
+case $last in
+kill) kill_ssh; exit 0;;
+status) status_ssh; exit 0;;
+esac
+
+ cmd="ssh $user@$host"
+#
+# Add the header with requested shell
+#
+
+ cat > ${file}__ <<- EOF
+#!$RUNSHELL
+# output=$output
+$PROFILE
+EOF
+
+#
+# Add the real request removing all qsub statements
+#
+
+if [[ $jtype == ll ]] ; then
+ egrep -v '^#.*@|^#!|^:$' $file >> ${file}__
+elif [[ $jtype == nqs ]] ; then
+ egrep -v '^#.*QSUB|^#!|^:$' $file >> ${file}__
+elif [[ $jtype == slurm ]] ; then
+ egrep -v '^#.*SBATCH|^#!|^:$' $file >> ${file}__
+elif [[ $jtype == pbs ]] ; then
+ egrep -v '^#.*PBS|^#!|^:$' $file >> ${file}__
+fi
+
+#
+# Submit the job
+#
+$cmd "/usr/local/bin/standalone -o $output -s $RUNSHELL " < ${file}__ || ERROR "Job submission to ssh standalone failed."
+;;
+
+#==========================================================================
+# Submit to any other workstation using rsh standalone or
+# submit to local workstation using standalone
+ rsh | local )
+#==========================================================================
+
+case $last in
+kill) kill_rsh; exit 0;;
+status) status_rsh; exit 0;;
+esac
+
+if [[ $type == local ]] ; then
+ cmd=""
+elif [[ $hostname == @(xxx_slurm) ]] ; then
+ cmd="$SSH -l $user $host "
+else
+ cmd="rsh $host -l $user "
+fi
+
+#
+# Add the header with requested shell
+#
+
+cat > ${file}__ <<- EOF
+#!$RUNSHELL
+# output=$output
+$PROFILE
+EOF
+#
+# Add the real request removing all qsub statements
+#
+
+if [[ $jtype == ll ]] ; then
+ egrep -v '^#.*@|^#!|^:$' $file >> ${file}__
+
+elif [[ $jtype == nqs ]] ; then
+ egrep -v '^#.*QSUB|^#!|^:$' $file >> ${file}__
+
+elif [[ $jtype == slurm ]] ; then
+ egrep -v '^#.*SBATCH|^#!|^:$' $file >> ${file}__
+
+elif [[ $jtype == pbs ]] ; then
+ egrep -v '^#.*PBS|^#!|^:$' $file >> ${file}__
+
+fi
+
+mv -f ${file}__ $file
+#
+# Submit the job
+#
+if [[ $type == local ]] ; then
+
+ case $hostname in
+ xxx_slurm ) nohup $RUNSHELL -x $file > $output 2>&1 & ;;
+ *) standalone -o $output -s $RUNSHELL < $file || ERROR "Job submission to standalone failed."
+ ;;
+ esac
+else
+
+ case $hostname in
+ xxx_slurm ) # $cmd "nohup $RUNSHELL -x $file > $output 2>&1 &"
+ $cmd "$STANDALONE -o $output -s $RUNSHELL" < $file > $subfile || \
+ ERROR "Job submission to rsh standalone failed."
+ ;;
+ *)
+ $cmd "/usr/local/bin/standalone -o $output -s $RUNSHELL" < $file > $subfile ||\
+ ERROR "Job submission to rsh standalone failed."
+ ;;
+ esac
+fi
+
+ ;;
+esac
+
+exit 0
diff --git a/tools/ecflow_fuse.py b/tools/ecflow_fuse.py
new file mode 100644
index 0000000..ace140d
--- /dev/null
+++ b/tools/ecflow_fuse.py
@@ -0,0 +1,591 @@
+#!/usr/bin/env python
+import os
+import sys
+import time
+from errno import ENOENT
+from stat import S_IFDIR, S_IFREG, S_IFBLK
+from sys import argv, exit
+from fuse import FUSE, Operations, LoggingMixIn, FuseOSError, fuse_get_context
+
+try: import ecflow
+except:
+ loc = "/usr/local/apps/ecflow/current/lib/python2.7/site-packages/ecflow"
+ sys.path.append(loc)
+ import ecflow
+
+"""
+another ecFlow python client example
+
+######### environment setup:
+virtualenv venv ; source ./venv/bin/activate; pip install fusepy
+
+python $0 $ECF_HOST $ECF_PORT mnt_point
+
+https://github.com/libfuse/libfuse
+
+commands=" autocancel
+clock complete cron date day defstatus
+edit endfamily endsuite endtask event extern
+family inlimit label late limit meter
+ repeat suite task time
+today trigger "
+
+# status OK, .XXX file
+# suspended OK, additional .sus file
+# label OK new_value
+# meter OK value
+# event OK value
+# trigger evaluate NOK
+# complete evaluate NOK
+# limit value OK + node_paths NOK
+# job, output OK check time stamp
+# remote output NOK
+# time stamp as status update NOK
+# server load stat png history zombies OK
+# begin
+
+"""
+FILESIZE = 10000
+UPDATE = "time"
+UPDATE = "always"
+ECFLOW_CLIENT = "/usr/local/apps/ecflow/current/bin/ecflow_client"
+
+ignore = ("bdmv", "inf", )
+
+cmds = { # "log": "--log=get",
+ "history": "--log=get",
+ "stats": "--stats",
+ "png": "--server_load",
+ "why": "--group='get; why %s'",
+ # + "=%s.%s.png; " % (self.host, self.port),
+ # ) + "cat %s.%s.png" % (self.host, self.port),
+ "zombies": "--zombie_get" }
+
+ECF_EXTN = "sms"
+ECF_EXTN = "ecf"
+exts = { key: None for key in cmds.keys() }
+task_exts = {
+ ECF_EXTN: "script", "man": "manual", "out": "jobout", "job": "job",
+ # "nop": None,
+ "att": None,
+}
+exts.update(task_exts)
+
+statuses = {
+ -1: "unknown",
+ 0: "unknown",
+ 1: "suspended",
+ 2: "complete",
+ 3: "queued",
+ 4: "submitted",
+ 5: "active",
+ 6: "aborted",
+ 7: "shutdown",
+ 8: "halted",
+ 9: "unknown", }
+
+state3 = ("unk", "que", "sub", "act", "com", "abo", "sus", "hal", "shu", "sus")
+
+def list_dir(node):
+ item = node
+ res = []
+ if isinstance(item, ecflow.Task):
+ res.extend([ ".%s" % key for key in task_exts.keys() ])
+ else: res = [ ".att", ]
+
+ name = item.name()
+ if node.is_suspended():
+ # res.extend([ name + ".sus"]) # another item???
+ sus = ".sus"
+ else: sus = ""
+ state = ".%03s" % item.get_state()
+ res.extend([ state[:4] + sus])
+
+ for item in node.nodes:
+ name = item.name()
+ if node.is_suspended():
+ # res.extend([ name + ".sus"]) # another item???
+ sus = ".sus"
+ else: sus = ""
+ state = ".%03s" % item.get_state()
+ # res.extend([ name + state[:4] + sus])
+
+ # if isinstance(item, ecflow.Task):
+ # res.extend([ name + ".%s" % key for key in task_exts.keys() ])
+ # else: res.extend([ name, name + ".att"])
+
+ return res
+
+def list_att(node):
+ import pprint
+
+ if node is None: return "none"
+ attr = dict()
+
+ kinds = { ecflow.Defs: "defs",
+ ecflow.Suite: "suite",
+ ecflow.Family: "family",
+ ecflow.Task: "task",
+ ecflow.Alias: "alias", }
+
+ try: attr['kind'] = kinds[type(node)]
+ except: print "what?", type(node); attr['kind'] = "unknown"
+
+ if isinstance(node, ecflow.Defs):
+ attr['gvar'] = []
+ attr['edit'] = []
+ for item in node.server_variables:
+ attr['gvar'] += [ (item.name(), item.value()) ]
+ for item in node.user_variables:
+ attr['edit'] += [ (item.name(), item.value())]
+ pp = pprint.PrettyPrinter(indent=4)
+ return pp.pformat(attr)
+
+ elif isinstance(node, ecflow.Suite):
+ clock = node.get_clock()
+ if clock: attr['clock']= "%s" % clock
+ attr['begin']= node.begun()
+
+ attr['status'] = "%s" % node.get_state()
+ try:
+ attr['update'] = "%s" % node.get_state_change_time()
+ except: pass
+
+ if node.is_suspended():
+ attr['suspended'] = "true"
+
+ if node.has_time_dependencies():
+ attr['has_time_dependencies'] = "%s" % node.has_time_dependencies()
+
+ defstatus = node.get_defstatus()
+ if defstatus != ecflow.DState.queued:
+ attr['defstatus'] = "%s" % defstatus
+
+ autocancel = node.get_autocancel()
+ if autocancel: attr['autocancel']= "%s" % autocancel
+
+ repeat = node.get_repeat()
+ if not repeat.empty(): attr['repeat']= "%s # value:%s" % (repeat,
+ repeat.value())
+
+ late = node.get_late()
+ if late: attr['late']= "%s" % late
+
+ complete_expr = node.get_complete()
+ if complete_expr:
+ for part_expr in complete_expr.parts:
+ trig = "complete "
+ if part_expr.and_expr(): trig = trig + "-a "
+ if part_expr.or_expr(): trig = trig + "-o "
+ attr['complete']= "%s" % trig + " %s" % \
+ part_expr.get_expression() + "\n"
+ trigger_expr = node.get_trigger()
+ if trigger_expr:
+ for part_expr in trigger_expr.parts:
+ trig = "trigger "
+ if part_expr.and_expr(): trig = trig + "-a "
+ if part_expr.or_expr(): trig = trig + "-o "
+ attr['trigger'] = "%s" % trig + " %s" % \
+ part_expr.get_expression() + "\n"
+
+ gvar = ecflow.VariableList()
+ node.get_generated_variables(gvar)
+ attr['gvar'] = []
+ for item in gvar:
+ attr['gvar'] += [ (item.name(), item.value()) ]
+ attr['edit'] = [ (item.name(), item.value())
+ for item in node.variables ]
+
+ addit(node.meters, attr, 'meter')
+ addit(node.events, attr, 'event')
+ addit(node.labels, attr, 'label')
+ addit(node.limits, attr, 'limit')
+ addit(node.inlimits, attr, 'inlimits')
+ addit(node.times, attr, 'time')
+ addit(node.todays, attr, 'today')
+ addit(node.dates, attr, 'date')
+ addit(node.days, attr, "day")
+ addit(node.crons, attr, "cron")
+ addit(node.zombies, attr, "zombies")
+
+ pp = pprint.PrettyPrinter(indent=4)
+ return pp.pformat(attr) + "\n"
+
+def set_att(fpath, dct, att=('st_size', ), dft=FILESIZE, ext="job"):
+ print "set_att", fpath
+ # if ext == "out": fpath = fpath.replace(".job", ".")
+ if os.path.exists(fpath):
+ print "'FOUND", fpath, "\n", os.lstat(fpath)
+ for key in att:
+ if "uid" in att or "gid" in att: continue
+ dct[key] = getattr(os.lstat(fpath), key)
+ print fpath, key, dct[key]
+ else: dct['st_size'] = FILESIZE
+
+def remote_file(node, fname, gvar, res):
+ print "####### REMOTE"
+ # gvar = ecflow.VariableList()
+ for item in gvar:
+ print item
+ if item.name() == "ECF_JOBOUT":
+ fname = item.value()
+ break
+
+ import paramiko, base64
+ ssh = paramiko.SSHClient()
+ HOST = None
+ if "ccb" in res: HOST = "ccb-il2"
+ if "cca" in res: HOST = "cca-il2"
+ if not HOST: return res
+ #key = paramiko.RSAKey(data=base64. decodestring(' '))
+ #ssh.get_host_keys().add(HOST, 'ssh-rsa', key)
+ ssh.set_missing_host_key_policy(
+ paramiko.AutoAddPolicy())
+ ssh.connect(HOST, username="emos") # , password=)
+ cmd = "ls %s.running && tail -20 %s.running || " % (
+ fname, fname) + "tail -20 %s" % fname
+ stdin, stdout, stderr = ssh.exec_command(cmd)
+ print "#MSG: live output: ", HOST, cmd
+ for line in stdout:
+ print line,
+ res += "%s" % line
+ return res
+
+def addit(array, cont, name):
+ rc = []
+ for item in array:
+ load = "%s" % item
+ if name == "label": load += " # value:%s" % item.new_value()
+ elif name in ("meter", "event"):
+ load += " # value:%s" % item.value()
+ elif name in ("limit",):
+ if item.value() > 0:
+ load += " # value:%s" % item.value()
+ print item.node_paths
+ for idx, val in enumerate(item.node_paths):
+ print idx, val
+ load += " %s " % val # ???
+ rc.append(load)
+ if len(rc) > 0: cont[name] = rc
+
+def trunc(res, size, offset):
+ print "offset", offset, size
+ if len(res) > size:
+ return "#TRUNCATED\n" + res[offset:offset+size-30] + "\n"
+ return res + "\n"
+
+class FuseEcflow(LoggingMixIn, Operations):
+ '''
+ A simple Ecflow python client example
+ '''
+
+ def __init__(self, host="localhost", port=31415, path='.'):
+ self.client = ecflow.Client(host, port)
+ self.client.sync_local()
+ self.host = host
+ self.port = port
+ self.update = int(time.strftime("%H%M"))
+ self.defs = self.client.get_defs()
+ self.root = path
+ print "#MSG: connected to %s " % host + port
+ if 0:
+ for s in self.defs.suites: print s.name(),
+ print
+
+ def chmod(self, path, mode):
+ raise FuseOSError(ENOENT)
+
+ def chown(self, path, uid, gid):
+ raise FuseOSError(ENOENT)
+
+ def create(self, path, mode):
+ raise FuseOSError(ENOENT)
+
+ def destroy(self, path): pass
+
+ def server_cmd(self, ext, run=1):
+ if not ext: return ""
+ if not ext in cmds.keys():
+ print "server cmd: what?", ext
+ return ""
+ cmd = ECFLOW_CLIENT + " --port %s --host %s " % (self.port, self.host
+ ) + cmds[ext]
+ if ext == "png":
+ if not run: return " " * FILESIZE
+ cmd += "=%s.%s.png; " % (self.host, self.port)
+
+ import commands
+ print cmd
+ (rc, res) = commands.getstatusoutput( cmd )
+
+ if ext == "png":
+ (rc, res) = commands.getstatusoutput("cat %s.%s.png" % (
+ self.host, self.port))
+ return res
+
+ def getattr(self, path, fh=None):
+ uid, gid, pid = fuse_get_context()
+ print "getattr", path, fh
+
+ cur = os.lstat(".")
+ # print "cur", cur
+ st = dict((key, getattr(cur, key)) for key in (
+ 'st_size', 'st_gid', 'st_uid',
+ 'st_mode', 'st_mtime', 'st_atime', 'st_ctime', ))
+
+ if path == '/':
+ st['st_mode'] = 0 # (protection bits)
+ st['st_ino'] = 0 # (inode number)
+ st['st_dev'] = 0 # (device)
+ st['st_nlink'] = 0 # (number of hard links)
+ # st['st_uid'] = 500 # (user ID of owner)
+ # st['st_gid'] = 500 # (group ID of owner)
+ st['st_size'] = 0 # (size of file, in bytes)
+ st['st_atime'] = 0 # (time of most recent access)
+ st['st_mtime'] = 0 # (time of most recent content modification)
+ st['st_ctime'] = 0 # (time of most recent metadata change)
+
+ st['st_mode'] = (S_IFDIR | 0755)
+ st['st_nlink']=2
+ return st
+
+ if '.' in path:
+ st['st_mode'] = (S_IFREG | 0444)
+ ext = ""
+ try:
+ path, ext = path.split(".")
+ if "@" in path: node = self.client.get_defs()
+ else: node = self.client.get_defs().find_abs_node(str(path))
+ except Exception as e: print e; node = None; return st
+
+ if ext == "att":
+ st['st_size'] = len(list_att(node))
+
+ elif "@" in path:
+ res = self.server_cmd(ext, 0)
+ st['st_size'] = len(res)
+
+ elif ext in ("job", "out"):
+ st['st_size'] = FILESIZE
+ gvar = ecflow.VariableList()
+ node.get_generated_variables(gvar)
+ item = None
+ for item in gvar:
+ if item.name() == "ECF_JOB": break
+ if item:
+ fname = item.value()
+ if ext == "out": fname = fname.replace(".job", ".")
+ set_att(fname, st, ('st_size', 'st_atime', 'st_mtime',
+ 'st_ctime'),
+ ext=ext)
+
+ elif 1:
+ st['st_mode'] = (S_IFDIR | 0444)
+ st['st_size'] = 1
+
+ else:
+ raise FuseOSError(ENOENT)
+ st['st_ctime'] = st['st_mtime'] = st['st_atime'] = time.time()
+ return st
+
+ def mkdir(self, path, mode):
+ raise FuseOSError(ENOENT)
+
+ def refresh(self):
+ curr = int(time.strftime("%H%M"))
+ if curr - self.update > 5 or UPDATE == "always":
+ self.client.sync_local()
+ self.update = curr
+
+ def read(self, path, size, offset, fh):
+ ext = None # "nop"
+ if "." in path:
+ path, ext = path.split(".")
+
+ self.refresh()
+
+ print "read", path, size, offset, fh, ext
+ if "@" in path and ext != "att":
+ res = self.server_cmd(ext)
+ return trunc(res, size, offset)
+
+ if ext in state3:
+ node = self.client.get_defs().find_abs_node(str(path))
+ suspended = ""
+ if node.is_suspended(): suspended = " # node is suspended"
+ return "node %s state is %s%s\n" % (node.get_abs_node_path(),
+ node.get_state(), suspended)
+ elif ext in ignore: return "-ignored-"
+ elif ext and not ext in exts.keys():
+ print "what?", ext; return "-empty-"
+
+ elif ext in ("job", "out"):
+ node = self.client.get_defs().find_abs_node(str(path))
+ gvar = ecflow.VariableList()
+ node.get_generated_variables(gvar)
+ fname = path
+ for item in gvar:
+ if item.name() == "ECF_JOB":
+ fname = item.value()
+ break
+
+ if os.path.exists(fname + ".sub"):
+ with open(fname + ".sub") as f:
+ res = f.read()
+
+ if ext == "out": fname = fname.replace(".job", ".")
+ if os.path.exists(fname):
+ if ext == "out":
+ jobtime = os.path.getmtime(item.value())
+ outtime = os.path.getmtime(fname)
+ if jobtime > outtime:
+ res += "output older than jobfile, %s\n" % item.value()
+ try: res += remote_file(node, fname, gvar, res)
+ except Exception as e: print e
+ return trunc(res, size, offset)
+
+ f = open(fname)
+ f.seek(offset, 0)
+ buf = f.read(size)
+ f.close()
+ return buf
+ else:
+ try: res += remote_file(node, fname, gvar, res)
+ except Exception as e: print e
+ return trunc(res, size, offset)
+
+ try: res = "%s" % self.client.get_file(str(path), exts[ext])
+ except Exception as e: print e; res = "%s" % e
+ return trunc(res, size, offset)
+
+ elif ext in ("why", ):
+ print "##############", ext
+ cmd = ECFLOW_CLIENT + " --port %s --host %s " % (self.port, self.host
+ ) + cmds[ext] % path
+
+ import commands
+ print cmd
+ (rc, res) = commands.getstatusoutput( cmd )
+ return trunc(res, size, offset)
+
+ elif ext in (ECF_EXTN, "man"):
+ print "##############", ext
+ res = "%s" % self.client.get_file(str(path), exts[ext])
+ return trunc(res, size, offset)
+
+ elif "@" in path: node = self.client.get_defs()
+ else: node = self.client.get_defs().find_abs_node(str(path))
+ res = ""
+
+ if path == '/':
+ for s in self.defs.suites: res += "%s " % s.name()
+ return res
+
+ elif node is None: return "-empty-node is none"
+
+ elif ext == "att":
+ res = "%s" % list_att(node)
+ return trunc(res, size, offset)
+
+ elif 1:
+ for s in node.nodes: res += "%s\n" % s.name()
+ return res
+
+ else: raise FuseOSError(ENOENT)
+
+ f = open(path)
+ f.seek(offset, 0)
+ buf = f.read(size)
+ f.close()
+ return buf
+
+ def readdir(self, path='/', fh=None):
+ ext = None
+ if "." in path:
+ path, ext = path.split(".")
+ if ext and not ext in exts.keys():
+ print "readdir: what?", ext;
+ return [ "/" ]
+
+ print "readdir", path, fh, path, ext
+
+ self.refresh()
+
+ if ext: # != "nop":
+ return [ ".", "..", "ok", path.replace("/", "_"), ext ]
+ else:
+ # if path[-1] == '/': path[-1] = ''
+ node = self.client.get_defs().find_abs_node(str(path))
+ res = []
+
+ if path == '/':
+ node = self.client.get_defs()
+ nick = '%s@%s' % (self.host, self.port)
+ res = ['.', '..', nick + "." + 'att' ]
+ res += [ nick + ".%s" % key for key in cmds.keys()
+ if key != "why" ]
+ res += [ nick + '.%s' % ( node.get_server_state()) ]
+ for s in node.suites:
+ sus = ""
+ if s.is_suspended(): sus = ".sus"
+ state = ".%.3s" % s.get_state()
+ res += [ "%s" % s.name(), s.name() + state + sus ]
+ return res
+
+ elif node is None:
+ print "#ERR: not found", path
+ return [ "..", "." ]
+ # raise BaseException()
+ # return ["-empty-%s" % path.replace("/", "_") ]
+
+ else:
+ res = ['.', '..', ".why" ]
+ res += [ "%s" % n.name() for n in node.nodes ]
+ res += list_dir(node)
+ return res
+
+ def readlink(self, path):
+ raise FuseOSError(ENOENT)
+
+ def rename(self, old, new):
+ raise FuseOSError(ENOENT)
+
+ def rmdir(self, path):
+ raise FuseOSError(ENOENT)
+
+ def symlink(self, target, source):
+ raise FuseOSError(ENOENT)
+
+ def truncate(self, path, length, fh=None):
+ raise FuseOSError(ENOENT)
+
+ def unlink(self, path):
+ raise FuseOSError(ENOENT)
+
+ def utimens(self, path, times=None):
+ raise FuseOSError(ENOENT)
+
+ def write(self, path, data, offset, fh):
+ raise FuseOSError(ENOENT)
+
+if __name__ == '__main__':
+ if len(argv) < 4:
+ print('usage: %s <host> <port> <mountpoint>' % argv[0])
+ exit(1)
+
+ fuse = FUSE(FuseEcflow(argv[1], argv[2]), argv[3],
+ foreground=True, nothreads=True,
+ # allow_root=True, # echo user_allow_other >> /etc/fuse.conf
+ # allow_other=True,
+ )
+
+"""
+python ecflow_fuse.py $ECF_NODE $ECF_PORT eod3
+
+ecflow_client --server_load --port $ECF_PORT --host $ECF_NODE
+xdg-open ${ECF_NODE}.${ECF_PORT}.png
+
+dircolors -p
+LS_COLORS+="*.abo=41:*.com=43:*.sus=01;45:*.que=44:*.sub=01;46:*.unk=47:*.act=01;42:"
+
+"""
diff --git a/tools/ecflow_load.sh b/tools/ecflow_load.sh
new file mode 100755
index 0000000..c90c2eb
--- /dev/null
+++ b/tools/ecflow_load.sh
@@ -0,0 +1,55 @@
+#!/bin/bash
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+# =====================================================================
+# Show server load
+# =====================================================================
+set -x
+ECF_PORT=$(($(id -u) + 1500))
+ECF_NODE=$(uname -n)
+ECF_LOG=${ECF_NODE}.${ECF_PORT}.log
+ECF_HOME=
+USAGE="$0 -p <ecf_port> -n <ecf_node> -h <ecf_home> -l <ecf_log> -v <viewer>"
+SSH="ssh"
+# VIEWER="eog"; VIEWER="viewnior"; VIEWER="xv"; VIEWER=gwenview; VIEWER=ristretto
+VIEWER="xdg-open"
+
+while getopts h:l:n:p:v:? option
+do
+ case $option in
+ h) ECF_HOME=$OPTARG;;
+ l) ECF_LOG=$OPTARG;;
+ n) ECF_NODE=$OPTARG;;
+ p) ECF_PORT=$OPTARG;;
+ v) VIEWER=$OPTARG;;
+ \? | *) echo $USAGE; exit 2;;
+ esac
+done
+
+client="ecflow_client --host=$ECF_NODE --port=$ECF_PORT"
+which ecflow_client || module load ecflow
+if [[ -f $ECF_LOG ]]; then
+ ecflow_client --server_load=$ECF_LOG
+elif [[ "$ECF_LOG" = /* ]]; then
+ $SSH $ECF_NODE $O -p $ECF_PORT -l $ECF_LOG -n $ECF_NODE -h $ECF_HOME
+elif [[ -f $ECF_HOME/$ECF_LOG ]]; then
+ ecflow_client --server_load=$ECF_HOME/$ECF_LOG
+elif ! `$client --ping`; then
+ echo "server is not responding"
+ exit 1
+elif [[ $ECF_NODE != $(uname -n) ]]; then # try remote
+ $SSH $ECF_NODE $O -p $ECF_PORT -l $ECF_LOG -n $ECF_NODE -h $ECF_HOME
+else
+ $client --server_load || $client --server_load=$ECF_LOG || $client --server_load=$ECF_HOME/$ECF_LOG
+fi
+
+$VIEWER ${ECF_NODE}.${ECF_PORT}.png
+
+echoxx() {
+echo """
+"""
+}
diff --git a/tools/ecflow_logsvr.pl b/tools/ecflow_logsvr.pl
new file mode 100755
index 0000000..13a613a
Binary files /dev/null and b/tools/ecflow_logsvr.pl differ
diff --git a/tools/ecflow_logsvr.sh b/tools/ecflow_logsvr.sh
new file mode 100644
index 0000000..46ece15
--- /dev/null
+++ b/tools/ecflow_logsvr.sh
@@ -0,0 +1,57 @@
+#!/bin/ksh
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+if [[ $# -ge 2 ]] ; then
+ echo ecflow_logsvr.sh port
+ exit -1
+fi
+
+echo "logsvr pid $$"
+
+HOST=`hostname | cut -c 1-4`
+
+# LOGPORT=${1:-9318}
+LOGPORT=${1:-9316}
+USERS="$USER"
+
+if [[ $HOST = hpc* ]] ; then
+ LOGPATH=/$HOST/emos_dir:/emos_esuite:/emos_dir
+ LOGMAP=/emos_esuite:/emos_esuite:/vol/emos/output:/emos_esuite:/vol/emos/output:/$MACHINE_NAME/emos_dir:/$MACHINE_NAME/emos_dir:/$MACHINE_NAME/emos_dir:/emos_esuite:/emos_esuite:/vol/emos/output:/emos_dir:/emos_dir:/emos_dir
+ log=/$HOST/tmp/ma/emos/logsvr.log
+else
+# HP
+ LOGPATH=/tmp/output:/pp2/log:/acq2/log:/eacq1/log:/eacq2/log
+ LOGMAP=/pp2/log:/pp2/log:/acq2/log:/acq2/log:/eacq1/log:/eacq1/log:/eacq2/log:/eacq2/log
+ log=/sms/logsvr.log
+fi
+
+if [[ -x /usr/local/lib/metaps/perl/logsvr.pl ]] ; then
+ LOGSVR=/usr/local/lib/metaps/perl/logsvr.pl
+elif [[ -x /usr/local/apps/sms/bin/logsvr.pl ]] ; then
+ LOGSVR=/usr/local/apps/sms/bin/logsvr.pl
+elif [[ -x $HOME/bin/logsvr.pl ]] ; then
+ LOGSVR=$HOME/bin/logsvr.pl
+elif [[ -x /sms/bin/logsvr.pl ]] ; then
+ LOGSVR=/sms/bin/logsvr.pl
+elif [[ -x ./logsvr.pl ]] ; then
+ LOGSVR=`pwd`/logsvr.pl
+else
+ echo "logsvr.pl not found in expected location"
+fi
+
+echo "using: $LOGSVR"
+export LOGPORT LOGPATH LOGMAP
+n=0
+while [[ $n -lt 1 ]]
+do
+ $LOGSVR > $log 2>&1 &
+ echo "logsvr pid $!"
+ wait
+ tail $log | mail -s "logsvr.pl crashed" $USERS
+ sleep 10
+done
diff --git a/tools/ecflow_show_load.sh b/tools/ecflow_show_load.sh
new file mode 100755
index 0000000..583cbc6
--- /dev/null
+++ b/tools/ecflow_show_load.sh
@@ -0,0 +1,87 @@
+#!/bin/bash
+USAGE="$0 -n <ecf_node> -p <ecf_port> -h <ecf_home> -l <ecf_log>
+ -r [retrieve_log_file]
+ -z [run remotely, and retrieve plot file]
+ -g [debug]"
+OPT="[-author map]"
+OPT="[-copyright?Copyright ECMWF]"
+OPT="[+NAME?ecflow_show_load.sh]"
+OPT="[+DESCRIPTION?retrieve server log file, call client server_load, and display load]"
+OPT="[g][n:ecf_node][h:ecf_home][p:ecf_port][?][l:ecf_log][r][z]"
+# OPT=":n:p:h:?"
+ECF_PORT=$((1500 + $(id -u)))
+ECF_NODE=$(uname -n) # ssh may not like localhost
+ECF_HOME=
+ECF_LOG=$ECF_NODE.$ECF_PORT.log
+PNG=$ECF_NODE.$ECF_PORT.png
+RETRIEVE=0
+DEBUG=0
+REMOTE=0
+LOCALH=$(uname -n)
+
+while getopts "$OPT" options
+do
+ [[ $DEBUG == 1 ]] && echo "options:" $options ${OPTARG:-}
+ case $options in
+ g) DEBUG=1; set -eux;;
+ p) ECF_PORT=$OPTARG;;
+ n) ECF_NODE=$OPTARG;;
+ h) ECF_HOME=$OPTARG;;
+ l) ECF_LOG=$OPTARG;;
+ r) RETRIEVE=1;;
+ z) REMOTE=1;;
+ \?) echo $USAGE; exit 2;;
+ * ) echo $USAGE; exit 2;;
+ esac
+done
+
+which ecflow_client > /dev/null || module load ecflow
+client=$(which ecflow_client)
+test=/tmp/map/work/git/cmake_build_dir/ecflow/debug/bin/ecflow_client && \
+ [[ -f $test ]] && client=$test
+client="$client --host $ECF_NODE --port $ECF_PORT --server_load"
+
+case $ECF_LOG in
+./* ) if [[ ! -f $ECF_LOG ]]; then
+ echo "#WAR local file not found";
+ exit 1;
+ fi
+;;
+/* ) if [[ ! -f $ECF_LOG ]] && [[ $DEBUG == 1 ]]; then echo "#WAR absolute path"; fi
+;;
+*) [[ -n "$ECF_HOME" ]] && ECF_LOG=$ECF_HOME/$ECF_LOG
+;;
+esac
+echo "#MSG: ECF_LOG is $ECF_LOG "
+
+rm -f $PNG || :
+if [[ 1 == $REMOTE ]]; then
+ ssh $ECF_NODE -l $USER ($client && scp $ECF_NODE.$ECF_PORT.png $USER:$LOCALH:$PNG)
+ # ssh -l $USER $ECF_NODE $client; scp $USER@$ECF_NODE:$ECF_NODE.$ECF_PORT.png .
+ [[ -f $PNG ]] && ${EOG:-eog} $PNG || echo "#ERR: could not display $PNG"
+ exit 0
+
+elif [[ 1 == $RETRIEVE ]]; then
+ TMPDIR=/tmp/$USER
+ mkdir -p $TMPDIR || :
+ TMPLOG=$TMPDIR/$ECF_NODE.$ECF_PORT.log
+ # NO: avoid scp log-file, it is better is issue the command remotely and retrieve the plot
+ # scp $USER@$ECF_NODE:$ECF_LOG $TMPLOG || rcp $USER@$ECF_NODE:$ECF_LOG $TMPLOG
+
+ ECF_LOG=$TMPLOG
+fi
+
+if [[ -f $ECF_LOG ]]; then
+ echo "#MSG: direct access # $client $ECF_LOG"
+ $client $ECF_LOG
+
+else
+ ssh $ECF_NODE -l $USER ($client && scp $ECF_NODE.$ECF_PORT.png $USER:$LOCALH:$(pwd))
+ # leave remote png behind? clean?
+fi
+
+[[ -f $PNG ]] && ${EOG:-eog} $PNG || echo "#ERR: could not display $PNG"
+
+exit 0
+load=./ecflow_show_load.sh
+$load -p $ECF_PORT -n $ECF_NODE -h $TMPDIR/. -l ${ECF_NODE}.ecf.${ECF_PORT}.log -z
diff --git a/tools/ecflow_start.sh b/tools/ecflow_start.sh
new file mode 100755
index 0000000..1524861
--- /dev/null
+++ b/tools/ecflow_start.sh
@@ -0,0 +1,238 @@
+#!/bin/sh
+#set -x
+#set -u
+#==========================================================================
+##.TITLE ECMWF utility for ECFLOW
+##.NAME ecflow_start.sh
+##.SECTION ECF
+##.AUTHOR Avi
+## Revision : $Revision: #19 $
+##
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+##
+##.FILE ecflow_start.sh
+### Will start the ecflow_server in the background, using user id
+### to make a unique port number.
+
+#==========================================================================
+export TZ=GMT LANG= # en_GB.UTF-8 unset, use locale -a to list available locales
+host=$(hostname)
+force=true
+backup_server=false
+verbose=false
+rerun=false
+
+#==========================================================================
+# Syntax
+# ecflow_start [-b] [-d ecf_home_directory] [-f] [-h] [-p port_number ]
+#==========================================================================
+# get command line options if any.
+while getopts hfbd:vp:r option
+do
+case $option in
+f)
+force=true
+;;
+b)
+backup_server=true
+;;
+v)
+verbose=true
+;;
+d)
+ecf_home_directory=$OPTARG
+;;
+p)
+ecf_port=$OPTARG
+;;
+r)
+rerun=true
+;;
+h)
+echo "Usage: $0 [-b] [-d ecf_home directory] [-f] [-h]"
+echo " -b start ECF for backup server or e-suite"
+echo " -d <dir> specify the ECF_HOME directory - default $HOME/ecflow_server"
+echo " -f forces the ECF to be restarted"
+echo " -v verbose mode"
+echo " -h print this help page"
+echo " -p <num> specify server port number(ECF_PORT number) - default 1000+<UID> | 500+<UID> for backup server"
+exit 0
+;;
+*)
+echo "Usage: $0 [-b] [-d ecf_home directory] [-f] [-h]"
+echo " -b start ECF for backup server or e-suite"
+echo " -d <dir> specify the ECF_HOME directory - default $HOME/ecflow_server"
+echo " -f forces the ECF to be restarted"
+echo " -v verbose mode"
+echo " -h print this help page"
+echo " -p <num> specify server port number(ECF_PORT number) - default 1500+<UID> | 1000+<UID> for backup server"
+exit 1
+;;
+esac
+done
+
+# =================================================================================
+# port_number is set based on the unique users numeric uid.
+
+username=`id -u`
+
+if [ -z "$ecf_port" ] ; then
+
+ if [ $backup_server = "true" ]; then
+ base=1000
+ else
+ base=1500
+ fi
+ port_number=$((base+username))
+
+else
+ port_number=$ecf_port
+fi
+
+export ECF_PORT=$port_number
+
+#===============================================================================
+# Setup ECF_HOME
+
+export ECF_HOME=${ecf_home_directory:-$HOME/ecflow_server}
+export ECF_LISTS=${ECF_LISTS:-$ECF_HOME/ecf.lists}
+
+# ===============================================================================
+# If server is already started then exit
+
+rcdir=$HOME/.ecflowrc
+fname=$rcdir/$(echo $host | cut -c1-4).$USER.$ECF_PORT
+# cut is useful when the server may be moved from node to node
+# 4 is common string here, so that the same file is used for all nodes
+
+if [ -f $fname ]; then host=$(cat $fname); fi
+
+mkdir -p $rcdir
+ecflow_client --port=$ECF_PORT --host=$host --ping && echo "server is already started" && exit 0 || :
+
+servers=$HOME/.ecflowrc/servers
+localh=$(uname -n)
+
+# =================================================================================
+# site specific settings come here
+#
+if [ -f /home/ma/emos/bin/ecflow_site.sh ] ; then
+. /home/ma/emos/bin/ecflow_site.sh
+fi
+
+
+# ==================================================================================
+# create one line in servers file so that viewer shows this server among servers list
+#
+case $host in
+$localh )
+ grep "^$localh" $servers || echo "$localh $localh $ECF_PORT" >> $servers
+;;
+esac
+
+date -u
+
+# ======================================================================================
+# set up default environment variables
+#
+export ECF_NODE=$host
+export ECF_LOG=$ECF_NODE.$ECF_PORT.ecf.log
+export ECF_CHECK=$ECF_NODE.$ECF_PORT.check
+export ECF_CHECKOLD=$ECF_NODE.$ECF_PORT.check.b
+if [ "$verbose" = "false" ]; then
+ export ECF_OUT=/dev/null
+else
+ export ECF_OUT=$ECF_NODE.$ECF_PORT.ecf.out
+fi
+
+echo
+echo User \"$username\" attempting to start ecf server on \"$ECF_NODE\" using ECF_PORT \"$ECF_PORT\" and with:
+echo "ECF_HOME : \"$ECF_HOME\""
+echo "ECF_LOG : \"$ECF_LOG\""
+echo "ECF_CHECK : \"$ECF_CHECK\""
+echo "ECF_CHECKOLD : \"$ECF_CHECKOLD\""
+if [ "$verbose" = "false" ]; then
+ echo "ECF_OUT : \"/dev/null\""
+else
+ echo "ECF_OUT : \"$ECF_NODE.$ECF_PORT.ecf.out\""
+fi
+echo
+
+#==========================================================================
+
+echo "client version is $(ecflow_client --version)"
+echo "Checking if the server is already running on $ECF_NODE and port $ECF_PORT"
+ecflow_client --ping
+if [ $? -eq 0 ]; then
+ echo "... The server on $ECF_NODE:$ECF_PORT is already running. Use 'netstat -lnptu' for listing active port"
+ exit 1
+fi
+
+#==========================================================================
+#
+echo "";
+echo Backing up check point and log files
+
+if [ ! -d $ECF_HOME ] ;then
+ mkdir $ECF_HOME
+fi
+cd $ECF_HOME
+
+if [ ! -d log ] ;then
+ mkdir log
+fi
+
+set +e
+
+cp $ECF_CHECK log/ 2>/dev/null
+cp $ECF_CHECKOLD log/ 2>/dev/null
+cp $ECF_LOG log/ 2>/dev/null
+
+if [ -f $ECF_NODE.$ECF_PORT.ecf.out ]; then
+ cp $ECF_NODE.$ECF_PORT.ecf.out log/ 2>/dev/null
+fi
+
+set -e
+
+# =============================================================================
+# ecFlow server start in the background.
+#
+# o/ nohup is a POSIX command to ignore the HUP (hangup) signal, enabling the command to
+# keep running after the user who issues the command has logged out.
+# The HUP (hangup) signal is by convention the way a terminal warns depending processes of logout.
+#
+# Note that these methods prevent the process from being sent a 'stop' signal on logout,
+# but if input/output is being received for these standard IO files (stdin, stdout, or stderr),
+# they will still hang the terminal
+# This problem can also be overcome by redirecting all three I/O streams:
+#
+# o/ ecflow_server will by default attempt to recover from a check point file if it is there
+# otherwise it will look for the backup check point file
+#
+echo "";
+echo "OK starting ecFlow server..."
+echo "";
+
+nohup ecflow_server > $ECF_OUT 2>&1 < /dev/null &
+
+# the sleep allows time for server to start
+if [ "$force" = "true" ]; then
+ echo "Placing server into RESTART mode..."
+ sleep 5
+ ecflow_client --restart || { echo "restart of server failed" ; exit 1; }
+fi
+
+
+echo
+echo "To view server on ecflowview - goto Edit/Preferences/Servers and enter"
+echo "Name : <unique ecFlow server name>"
+echo "Host : $ECF_NODE"
+echo "Port Number : $ECF_PORT"
+echo
+
+exit 0
diff --git a/tools/ecflow_stop.sh b/tools/ecflow_stop.sh
new file mode 100755
index 0000000..001ad46
--- /dev/null
+++ b/tools/ecflow_stop.sh
@@ -0,0 +1,114 @@
+#!/bin/sh
+#==========================================================================
+##.TITLE ECMWF utility for ecFlow
+##.NAME ecflow_stop.sh
+##.SECTION ECFLOW
+##.AUTHOR Avi
+## Revision : $Revision: #10 $
+##
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+##
+##.FILE ecflow_stop.sh
+##.INFO this file is expected to be located in /usr/local/share
+## it is to be used on ecgate by member states users
+## one ecf server occurrence will be generated on ecgate
+#==========================================================================
+
+#set -eux
+
+PATH=/usr/local/bin:/usr/bin:$PATH
+export TZ=GMT LANG=en_GB.UTG-8
+host=$(hostname)
+backup_server=false
+
+# =========================================================================
+# Update host, site specific
+. /home/ma/emos/bin/ecflow_site.sh || : # site specific settings come here
+
+#==========================================================================
+# Syntax
+# ecf_stop [-b] [-p port_number ] [-h]
+# get command line options if any.
+#==========================================================================
+while getopts b:p: option
+do
+case $option in
+b)
+backup_server=true
+;;
+p)
+ecf_port=$OPTARG
+;;
+h)
+echo "Usage: $0 [-b] [-p port_number ] [-h]"
+echo " -b stop ECF backup server"
+echo " -p <num> specify the ECF_PORT number - default 1000+<UID> | 500+<UID> for backup server"
+echo " -h print this help page"
+exit 0
+;;
+*)
+echo "Usage: $0 [-b] [-p port_number ] [-h]"
+echo " -b stop ECF backup server"
+echo " -p <num> specify the ECF_PORT number - default 1500+<UID> | 1000+<UID> for backup server"
+echo " -h print this help page"
+exit 1
+;;
+esac
+done
+
+#==========================================================================
+# PORT NUMBER is set based on the unique users numeric uid.
+username=`id -u`
+
+if [ -z "$ecf_port" ] ; then
+ if [ $backup_server = "true" ]; then
+ base=1000
+ else
+ base=1500
+ fi
+ port_number=$((base+username))
+else
+ port_number=$ecf_port
+fi
+
+export ECF_PORT=$port_number
+
+#==========================================================================
+# HOST
+date -u
+
+rcdir=$HOME/.ecflowrc
+fname=$rcdir/$(echo $host | cut -c1-4).$USER.$ECF_PORT
+# cut is useful when the server may be moved from node to node
+# 4 is common string here, so that the same file is used for all nodes
+
+if [[ -f $fname ]]; then host=$(cat $fname); fi
+
+echo ""
+echo "User \"$username\" attempting to stop ecf server on $host:$port_number"
+echo "";
+echo "Checking if the server is running on $host:$port_number"
+
+export ECF_NODE=$host
+
+ecflow_client --ping
+if [ $? -eq 1 ]; then
+ echo "";
+ echo "... The server on $host:$port_number has already been stopped"
+ exit 1
+fi
+
+#==========================================================================
+echo "";
+echo Halting, check pointing and terminating the server
+
+ecflow_client --halt=yes
+ecflow_client --check_pt
+ecflow_client --terminate=yes
+
+exit 0
diff --git a/tools/ecflow_suite_gen.sh b/tools/ecflow_suite_gen.sh
new file mode 100755
index 0000000..afbcdcc
--- /dev/null
+++ b/tools/ecflow_suite_gen.sh
@@ -0,0 +1,159 @@
+#!/bin/bash
+exec 3> /dev/stdout
+commands=" autocancel
+clock complete cron date day defstatus
+edit endfamily endsuite endtask event extern
+family inlimit label late limit meter
+repeat suite task time today trigger "
+
+# enable -n time || : # shell builtin removed
+for fname in $commands; do
+source /dev/stdin <<EOF
+function $fname()
+{
+ echo $fname "\${*}" >&3
+}
+EOF
+done
+
+alias time="echo time \"\${*}\" >&3"
+init="ECF_NAME=%ECF_NAME% ECF_PASS=%ECF_PASS% ecflow_client --init;"
+complete="ECF_NAME=%ECF_NAME% ECF_PASS=%ECF_PASS% ecflow_client --complete;"
+
+ensemble() {
+num=0
+tot=10
+family ensemble
+limit lim 5
+inlimit ensemble:lim
+while (( num <= tot)); do
+ family $(printf "%02d" $num)
+ task model; edit MEMBER $num; (( num += 1))
+ endfamily
+done
+endfamily
+
+family process
+ for param in "z" "u" "v" "t" "q"; do
+ task $param; edit PARAM $param;
+ done
+endfamily # process
+
+family seq
+ for num in $(seq 1 9); do
+ family $(printf "%02d" $num)
+ task model; edit MEMBER $num; (( num += 1))
+ endfamily
+ done
+endfamily
+}
+
+producer() {
+ family producer
+ repeat date YMD 20160101 20321212
+ family produce
+ edit PRODUCE 1
+ edit CONSUME 0
+ task generic
+ event p
+ event c
+ meter step -1 100 90
+ endfamily # produce
+
+ family consume
+ edit PRODUCE 0
+ complete produce:CONSUME eq 1
+ trigger produce/generic:p or produce==complete
+ task generic
+ endfamily # consume
+
+ family consume2
+ repeat integer STEP 0 100
+ edit PRODUCE 0
+ complete produce:CONSUME eq 1
+ trigger produce/generic:step gt consume2:STEP or produce==complete
+ task generic
+ endfamily # consume2
+ endfamily # producer
+}
+
+test_suite() {
+extern /limits:tasks
+
+suite $SUITE_NAME
+ defstatus suspended
+ autocancel +10
+ clock real
+
+ family limits
+ limit tasks 10
+ defstatus complete
+ endfamily
+ inlimit /limits:tasks
+
+ producer # function defined upper
+
+ ensemble
+
+ task cron
+ cron 00:00 23:59 01:00
+ late -s 00:05 -c 00:10
+
+ task day
+ day monday
+
+ family fam
+ time 12:00
+ date "1.*.*"
+ task t1
+ event 1
+ meter step -1 100 90
+ label info nop
+}
+
+usage() {
+echo <<EOF
+$0 -p <ECF_PORT> -n <ECF_NODE> -s <suite_name> -r <path>
+ -l: load
+ -r: replace path
+ -t: test suite generated
+EOF
+}
+
+LOAD=0
+REPL=0
+
+while getopts dln:p:r:s:t option
+do
+case $option in
+ d) DEBUG=1; set -eux;;
+ l) LOAD=1;;
+ n) ECF_NODE=$OPTARG;; # NODE HOST
+ p) ECF_PORT=$OPTARG;; # PORT
+ r) REPL=$OPTARG;;
+ s) SUITE_NAME=$OPTARG;;
+ t) TEST=1;;
+ ?|*) usage; exit 2 ;;
+esac
+done
+
+sdef=${SUITE_NAME:=test}.exp
+exec 3> $sdef
+if [[ $TEST == 1 ]]; then
+ test_suite
+else
+ echo "#ERR: insert your suite definition HERE $0 $LINENO"
+ exit 2
+fi
+
+CLIENT="ecflow_client --port ${ECF_PORT:=31415} --host ${ECF_NODE:=localhost}"
+if [[ $REPL != 0 ]]; then
+ $CLIENT --replace $REPL $sdef
+ echo "#MSG: node $REPL was replaced as defined in $sdef" \
+ " on ${ECF_NODE:=localhost} ${ECF_PORT:=31415}"
+elif [[ $LOAD != 0 ]]; then
+ $CLIENT --load $sdef
+else
+ cat $sdef
+ echo "#MSG: suite was created in file $sdef"
+fi
diff --git a/tools/noconnect.sh b/tools/noconnect.sh
new file mode 100755
index 0000000..c8ff878
--- /dev/null
+++ b/tools/noconnect.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+# disconnect all hosts to start ecflowview with empty screen
+#==========================================================================
+##.TITLE ECMWF utility for ecFlow
+##.NAME
+##.SECTION ECFLOW
+##.AUTHOR
+## Revision : $Revision: #7 $
+##
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+##
+##.FILE
+##.INFO
+#==========================================================================
+
+d=$HOME/.xcdprc
+d=$HOME/.ecflowrc
+for f in $d/*options
+do
+ # echo "## $f"
+ if [ `grep "connect:true" $f 2>/dev/null` ]
+ then
+ # echo "### $f"
+ sed -e 's|connect:true|connect:false|' $f > ${f}.tmp
+ mv ${f}.tmp $f
+ fi
+done
diff --git a/ecflow_4_0_7/version.sh b/version.sh
similarity index 100%
rename from ecflow_4_0_7/version.sh
rename to version.sh
diff --git a/view/CMakeLists.txt b/view/CMakeLists.txt
new file mode 100644
index 0000000..3cb2dab
--- /dev/null
+++ b/view/CMakeLists.txt
@@ -0,0 +1,264 @@
+# =======================================================
+# LIB
+# to list all sources to build use:
+# cd $WK/View
+# find src -name \icon_*.cc -print | sort
+# =======================================================
+
+# Files to exclude
+# src/lister.cc
+# src/extent.cc
+# src/node_alert.cc
+# src/array.cc
+# src/option.cc
+# src/dialog.cc
+# src/ecflowview.cc
+#
+# src/menul.c
+# src/tmpnam.c
+# src/line.c
+# src/x.c
+
+list( APPEND srcs_cc
+ src/aborted.cc
+ src/alerts.cc
+ src/alias.cc
+ src/ask.cc
+ src/auto_alarm.cc
+ src/base.cc
+ src/collector.cc
+ src/colors_prefs.cc
+ src/configurable.cc
+ src/confirm.cc
+ src/counted.cc
+ src/date.cc
+ src/depend.cc
+ src/directory.cc
+ src/dummy_node.cc
+ src/ecf_node.cc
+ src/ecflow.cc
+ src/edit.cc
+ src/edit_label.cc
+ src/edit_limit.cc
+ src/edit_meter.cc
+ src/edit_repeat.cc
+ src/edit_variable.cc
+ src/editor.cc
+ src/error.cc
+ src/event_node.cc
+ src/external.cc
+ src/find.cc
+ src/flags.cc
+ src/fonts_prefs.cc
+ src/fsb.cc
+ src/globals.cc
+ src/graph_layout.cc
+ src/gui.cc
+ src/history.cc
+ src/host.cc
+ src/host_prefs.cc
+ src/html_lister.cc
+ src/http.cc
+ src/hyper_lister.cc
+ src/icon_Josstatus3.cc
+ src/icon_W.cc
+ src/icon_byrule.cc
+ src/icon_cmd_failed.cc
+ src/icon_edit_failed.cc
+ src/icon_force_abort.cc
+ src/icon_killed.cc
+ src/icon_no_script.cc
+ src/icon_queuelimit.cc
+ src/icon_task_aborted.cc
+ src/icon_user_edit.cc
+ src/info.cc
+ src/init.cc
+ src/inlimit_node.cc
+ src/input.cc
+ src/interface.cc
+ src/job.cc
+ src/jobcheck_panel.cc
+ src/jobstatus.cc
+ src/label.cc
+ src/late.cc
+ src/late_node.cc
+ src/layout.cc
+ src/limit_node.cc
+ src/log_event.cc
+ src/logsvr.cc
+ src/mail.cc
+ src/manual.cc
+ src/menu_prefs.cc
+ src/menus.cc
+ src/messages.cc
+ src/meter_node.cc
+ src/node.cc
+ src/node_editor.cc
+ src/node_list.cc
+ src/node_window.cc
+ src/not_enqueued.cc
+ src/observable.cc
+ src/observer.cc
+ src/option_panel.cc
+ src/output.cc
+ src/panel.cc
+ src/panel_window.cc
+ src/parser.cc
+ src/passwrd.cc
+ src/persist.cc
+ src/pixmap.cc
+ src/pref_editor.cc
+ src/pref_window.cc
+ src/prefs.cc
+ src/reach.cc
+ src/relation.cc
+ src/repeat_node.cc
+ src/resource.cc
+ src/restart.cc
+ src/result.cc
+ src/runnable.cc
+ src/script_panel.cc
+ src/scripting.cc
+ src/search.cc
+ src/searchable.cc
+ src/selection.cc
+ src/server.cc
+ src/servers_prefs.cc
+ src/show.cc
+ src/simple_node.cc
+ src/str.cc
+ src/substitute.cc
+ src/suites_panel.cc
+ src/super_node.cc
+ src/task_node.cc
+ src/text_layout.cc
+ src/text_window.cc
+ src/time.cc
+ src/timeout.cc
+ src/timetable_panel.cc
+ src/tip.cc
+ src/tmp_file.cc
+ src/top.cc
+ src/translator.cc
+ src/tree.cc
+ src/trigger_node.cc
+ src/trigger_panel.cc
+ src/url.cc
+ src/user_prefs.cc
+ src/users.cc
+ src/variable_node.cc
+ src/variables.cc
+ src/viewer.cc
+ src/why.cc
+ src/window.cc
+ src/xdxmdialog.cc
+ src/xdxtclass.cc
+ src/xmstring.cc
+ src/xnode.cc
+ src/zombies_panel.cc
+)
+
+list( APPEND srcs_c
+ src/Hyper.c
+ src/SimpleBase.c
+ src/SimpleGraph.c
+ src/SimpleTime.c
+ src/SimpleTree.c
+ src/Tab.c
+ src/menuy.c
+)
+
+file( GLOB srcs_cpp RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp" )
+file( GLOB libicon_srcs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/libicon/*.cc" )
+file( GLOB libxec_srcs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/libxec/*.c" )
+file( GLOB libui_srcs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/libui/*.cc" )
+
+# =======================================================================================
+find_package( CMath )
+
+set( CMAKE_THREAD_PREFER_PTHREAD TRUE )
+find_package( Threads )
+
+
+# =========================================================================================
+# libecflowview needs to be compiled as dynamic lin otherwise the icons do not appear.
+#
+# Note: -DECFLOW_SHARED_DIR is *ONLY* required for one file view/src/directory.cc
+#
+add_definitions( -D_GNU_SOURCE -DUNIX -Dunix -Dlinux -DECFLOW_SHARED_DIR="${CMAKE_INSTALL_PREFIX}/share/ecflow" )
+
+
+# local includes
+include_directories( src
+ src/libicon
+ src/libxec
+ src/libui
+ ../ACore/src
+ ../ANattr/src
+ ../ANode/src
+ ../AParser/src
+ ../Base/src
+ ../Base/src/cts
+ ../Base/src/stc
+ ../Client/src
+ )
+
+# in ecbuild_add_library INCLUDES is only for external includes
+ecbuild_add_library(TARGET libecflowview
+ CONDITION MOTIF_FOUND AND X11_FOUND AND CMAKE_THREAD_LIBS_INIT
+ SOURCES
+ ${srcs_cc} ${srcs_c} ${srcs_cpp} ${libicon_srcs} ${libxec_srcs} ${libui_srcs}
+ TEMPLATES
+ src/array.cc
+ INCLUDES
+ ${X11_INCLUDE_DIR}
+ ${MOTIF_INCLUDE_DIR}
+ )
+
+# =======================================================================
+# EXE ecflowview
+# o crypt Does not appear to be used ?
+# o Xp libxprint does not appear to be used ?
+# o fl fast lexical analyser generator, not used ?
+# ========================================================================
+# ECFLOW-143 SUP-1212
+SET_SOURCE_FILES_PROPERTIES(src/host.cc PROPERTIES COMPILE_FLAGS "-O0")
+
+ecbuild_add_executable( TARGET ecflowview
+ SOURCES
+ src/ecflowview.cc
+ CONDITION
+ MOTIF_FOUND AND X11_FOUND AND CMAKE_THREAD_LIBS_INIT
+ LIBS
+ libecflowview libclient base libparser node nodeattr core
+ ${CMAKE_THREAD_LIBS_INIT}
+ ${X11_LIBRARIES} ${X11_Xext_LIB} ${MOTIF_LIBRARIES} ${X11_Xpm_LIB} ${X11_Xt_LIB}
+ ${CMATH_LIBRARIES}
+ INCLUDES
+ ${X11_INCLUDE_DIR}
+ ${MOTIF_INCLUDE_DIR}
+ )
+
+
+# ===================================================================
+# test
+# ===================================================================
+
+ecbuild_add_test( TARGET test-view
+ BOOST
+ CONDITION MOTIF_FOUND AND X11_FOUND AND CMAKE_THREAD_LIBS_INIT
+ SOURCES test/TestRunner.cpp test/TestView.cpp
+ LIBS libharness
+ INCLUDES ../Test/src
+ TEST_DEPENDS s_test_zombies
+ )
+
+# ===================================================================
+# install
+# ===================================================================
+
+install ( FILES ${CMAKE_SOURCE_DIR}/view/src/ecflowview.menu
+ ${CMAKE_SOURCE_DIR}/view/servers
+ DESTINATION share/ecflow
+ PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE
+ )
diff --git a/view/Jamfile.jam b/view/Jamfile.jam
new file mode 100644
index 0000000..5c39ce0
--- /dev/null
+++ b/view/Jamfile.jam
@@ -0,0 +1,118 @@
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+#
+# ecflowview
+#
+project ecflowview ;
+
+use-project theCore : ../ACore ;
+use-project theNodeAttr : ../ANattr ;
+use-project theNode : ../ANode ;
+use-project theBase : ../Base ;
+use-project theClient : ../Client ;
+use-project theTest : ../Test ;
+
+# This should be in the site-config.jam file as a project wide requirement
+# however if this is done, it will not link since, lpthread appears twice
+# on the link line
+#
+lib pthread ;
+
+import os ;
+MOTIF_INCLUDE = [ os.environ MOTIF_INCLUDE ] ;
+MOTIF_INCLUDE default = /usr/include ;
+# MOTIF_LIBRARY = [ os.environ MOTIF_LIBRARY ] ;
+# MOTIF_LIBRARY default = /usr/lib64 ;
+# echo "# MOTIF_LIBRARY = $(MOTIF_LIBRARY)" ;
+
+exe ecflowview
+ : [ glob src/*.cc src/*.c src/*cpp
+ src/libicon/*.cc src/libxec/*.c src/libui/*.cc :
+ src/menul.c src/lister.cc src/tmpnam.c src/line.c src/x.c src/extent.cc
+ src/node_alert.cc src/array.cc src/option.cc
+ src/dialog.cc src/host.cc ]
+ host
+ /theCore//core
+ /theNodeAttr//nodeattr
+ /theNode//node
+ /theParser//libparser
+ /theBase//base
+ /theClient//libclient
+ /site-config//boost_system
+ /site-config//boost_serialization
+ /site-config//boost_filesystem
+ /site-config//boost_program_options
+ /site-config//boost_datetime
+ pthread
+ : <variant>debug:<define>DEBUG
+# <variant>release:<cxxflags>-O1
+ <toolset>gcc:<include>$(MOTIF_INCLUDE)
+ <include>../view/src
+ <include>../view/src/libicon
+ <include>../view/src/libxec
+ <include>../view/src/libui
+ <define>_GNU_SOURCE
+ <define>linux
+ <define>ECFLOW_SHARED_DIR='\"$(ECFLOW_SHARED_DIR)\"'
+ <define>UNIX
+ <define>unix
+ <linkflags>-lm
+ <linkflags>-g
+ <toolset>gcc:<linkflags>-L$(MOTIF_LIBRARY)
+ <dll-path>$(MOTIF_LIBRARY)
+ <linkflags>-L/usr/X11R6/lib
+ <linkflags>-lXpm
+ <linkflags>-lXm
+ <linkflags>-lXext
+ <linkflags>-lXt
+ <linkflags>-lX11
+ ;
+
+obj host : src/host.cc
+ /theCore//core
+ /theNodeAttr//nodeattr
+ /theNode//node
+ /theParser//libparser
+ /theBase//base
+ /theClient//libclient
+ : <variant>release:<optimization>off
+ <include>../view/src
+ <include>../view/src/libicon
+ <include>../view/src/libxec
+ <include>../view/src/libui
+ <define>_GNU_SOURCE
+ <define>linux
+ <define>ECFLOW_SHARED_DIR='\"$(ECFLOW_SHARED_DIR)\"'
+ <define>UNIX
+ <define>unix
+ ;
+#
+# Test the view
+# This uses /theTest//libharness to setup a server
+#
+exe test-view : [ glob test/*.cpp ]
+ pthread
+ /theCore//core
+ /theNodeAttr//nodeattr
+ /theNode//node
+ /theParser//libparser
+ /theBase//base
+ /theClient//libclient
+ /theTest//libharness
+ /site-config//boost_system
+ /site-config//boost_serialization
+ /site-config//boost_filesystem
+ /site-config//boost_program_options
+ /site-config//boost_datetime
+ /site-config//boost_test
+ : <include>../Base/test
+ <include>../Test/src
+ <variant>debug:<define>DEBUG
+# <variant>release:<cxxflags>-O1
+ ;
+# bjam -j8 release c++-template-depth=512
diff --git a/ecflow_4_0_7/view/data/includes/head.h b/view/data/includes/head.h
similarity index 100%
rename from ecflow_4_0_7/view/data/includes/head.h
rename to view/data/includes/head.h
diff --git a/ecflow_4_0_7/view/data/includes/tail.h b/view/data/includes/tail.h
similarity index 100%
rename from ecflow_4_0_7/view/data/includes/tail.h
rename to view/data/includes/tail.h
diff --git a/view/servers b/view/servers
new file mode 100644
index 0000000..3b5c80d
--- /dev/null
+++ b/view/servers
@@ -0,0 +1,9 @@
+#
+# This file is copied over to <install-directory>/share/ecflow/.
+# Use this file to list the servers you want to make visible
+#
+# <server-name> <host> <port>
+# test1 machine1 31415
+# test2 machine1 31416
+# operation hostxx 3147
+localhost localhost 3141
\ No newline at end of file
diff --git a/view/src/ArrayP.h b/view/src/ArrayP.h
new file mode 100644
index 0000000..ef47280
--- /dev/null
+++ b/view/src/ArrayP.h
@@ -0,0 +1,60 @@
+#ifndef ARRAYP_H
+#define ARRAYP_H
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #4 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+
+#include <Xm/XmP.h>
+#include <Xm/DrawingAP.h>
+
+typedef struct _ArrayClassPart {
+ int ignore;
+} ArrayClassPart;
+
+typedef struct _ArrayClassRec {
+ CoreClassPart core_class;
+ CompositeClassPart composite_class;
+ ConstraintClassPart constraint_class;
+ XmManagerClassPart manager_class;
+ XmDrawingAreaClassPart drawing_area_class;
+ ArrayClassPart array_class;
+} ArrayClassRec;
+
+extern ArrayClassRec arrayClassRec;
+
+typedef struct {
+ int round;
+ int rows;
+ int cols;
+} ArrayPart;
+
+
+typedef struct _ArrayRec {
+ CorePart core;
+ CompositePart composite;
+ ConstraintPart constraint;
+ XmManagerPart manager;
+ XmDrawingAreaPart drawing_area;
+ ArrayPart array;
+} ArrayRec;
+
+
+#define XtArrayNumChildren(w) (((ArrayWidget)w) -> composite.num_children)
+#define XtArrayChild(w,i) (((ArrayWidget)w) -> composite.children[i])
+
+#endif /* ARRAYP_H */
+
+
+
diff --git a/view/src/Hyper.c b/view/src/Hyper.c
new file mode 100644
index 0000000..9328fb7
--- /dev/null
+++ b/view/src/Hyper.c
@@ -0,0 +1,1585 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : B.Raoult */
+/* Revision : $Revision: #5 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : Hyper text like widget. */
+/*=============================================================================================*/
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <X11/IntrinsicP.h>
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/CoreP.h>
+#include <X11/cursorfont.h>
+#include "Hyper.h"
+#include "HyperP.h"
+#include <Xm/ScrollBar.h>
+#include <stdlib.h>
+#include <string.h> /* strerror */
+
+extern void xec_compile(char *w);
+extern int xec_step(char *p);
+
+#ifndef ABS
+#define ABS(a) ((a)>=0?(a):-(a))
+#endif
+#ifndef MIN
+#define MIN(a,b) ((a)>(b)?(b):(a))
+#endif
+
+#define ESIZE 1024
+
+#define NORMAL 0
+#define HIGHLIGHT 1
+#define NEWLINE 2
+
+#define MAX_LINE_SIZE 1024
+
+extern char *xec_loc1, *xec_loc2;
+
+/*
+ Private functions
+*/
+
+static void hilite(HyperWidget w,Boolean on);
+static text_segment *find_segment(HyperWidget,int,int);
+static void free_text(text_segment*);
+static void create_gcs(HyperWidget);
+static void create_new_text(HyperWidget);
+static void xselect();
+static void cursor();
+static void activate();
+static void xincrement();
+static void add_to_text ( HyperWidget,char*,int,int);
+static void calc_new_size (HyperWidget);
+static void zoom_open (HyperWidget,text_segment*);
+static void show_selection(HyperWidget);
+static void set_selection(HyperWidget);
+static void clear_selection(HyperWidget);
+static void lowcase(char *p);
+static void find_visible_part(Widget,Position*,Position*,Dimension*,Dimension*);
+static void set_text(HyperWidget,char (*)(XtPointer),XtPointer);
+
+/*
+ Widget class methods
+*/
+
+static void Initialize();
+static void Redisplay();
+static void Resize();
+static void Destroy();
+static Boolean SetValues();
+
+static char defaultTranslations[] =
+" <Btn1Down>:select()\n <Btn1Up>: activate()\n\
+ <Motion>:cursor()\n\
+ <Btn2Down>:select()\n <Btn2Up>: activate() \n\
+ Shift<Btn5Down>: increment(1)\n Shift<Btn4Down>: increment(-1) \n\
+ <Btn5Down>: increment(10)\n <Btn4Down>: increment(-10) \n";
+
+static XtActionsRec actionsList[] = {
+ { "select", (XtActionProc) xselect},
+ { "activate", (XtActionProc) activate},
+ { "cursor", (XtActionProc) cursor},
+ { "increment",(XtActionProc) xincrement},
+};
+
+static XtResource resources[] = {
+
+ {XtNhighlightFont, XtCFont, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset(HyperWidget, hyper.highlight_font), XtRString, "fixed"},
+
+ {XtNnormalFont, XtCFont, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset(HyperWidget, hyper.normal_font), XtRString, "fixed"},
+
+ {XtNhighlightColor, XtCColor, XtRPixel, sizeof (Pixel),
+ XtOffset(HyperWidget, hyper.highlight_color),XtRString, "Red"},
+
+ {XtNselectColor, XtCColor, XtRPixel, sizeof (Pixel),
+ XtOffset(HyperWidget, hyper.select_color),XtRString, "Blue"},
+
+ {XtNnormalColor, XtCColor, XtRPixel, sizeof (Pixel),
+ XtOffset(HyperWidget, hyper.normal_color),XtRString,"Black"},
+
+ {XtNactivateCallback,XtCCallback,XtRCallback,sizeof(caddr_t),
+ XtOffset (HyperWidget, hyper.activate),XtRCallback,NULL},
+
+ {XtNzoomEffect,XtCZoom,XtRBoolean,sizeof(Boolean),
+ XtOffset (HyperWidget, hyper.zoom),XtRImmediate,(XtPointer)TRUE},
+
+#ifndef XDESIGNER
+ {XtNstartHighlight,XtCTagChar,XtRUnsignedChar,sizeof(unsigned char),
+ XtOffset(HyperWidget,hyper.start_of_highlight),XtRImmediate,
+ (XtPointer)'{'},
+
+ {XtNendHighlight,XtCTagChar,XtRUnsignedChar,sizeof(unsigned char),
+ XtOffset (HyperWidget, hyper.end_of_highlight),XtRImmediate,
+ (XtPointer)'}'},
+#endif
+
+ {XtNzoomSpeed,XtCZoomSpeed,XtRInt,sizeof(int),
+ XtOffset (HyperWidget, hyper.speed),XtRImmediate,(XtPointer)4},
+
+ {XtNmargin,XtCMargin,XtRInt,sizeof(int),
+ XtOffset (HyperWidget, hyper.margin),XtRImmediate,(XtPointer)10},
+
+};
+
+/*---------------------------------------------------------------*/
+/* Static initialisation of the class record */
+/*---------------------------------------------------------------*/
+
+HyperClassRec hyperClassRec = {
+ {
+#ifdef MOTIF
+ (WidgetClass) &xmPrimitiveClassRec, /* superclass */
+#else
+ (WidgetClass) &widgetClassRec, /* superclass */
+#endif
+ "Hyper", /* class_name */
+ sizeof(HyperRec), /* widget_size */
+ NULL, /* class_initialize */
+ NULL, /* class_part_initialize */
+ FALSE, /* class_inited */
+ Initialize, /* initialize */
+ NULL, /* initialize_hook */
+ XtInheritRealize, /* realize */
+ actionsList, /* actions */
+ XtNumber(actionsList), /* num_actions */
+ resources, /* resources */
+ XtNumber(resources), /* num_resources */
+ NULLQUARK, /* xrm_class */
+ TRUE, /* compress_motion */
+ XtExposeCompressMaximal, /* compress_exposure */
+ TRUE, /* compress_enterleave */
+ TRUE, /* visible_interest */
+ Destroy, /* destroy */
+ Resize, /* resize */
+ Redisplay, /* expose */
+ SetValues, /* set_values */
+ NULL, /* set_values_hook */
+ XtInheritSetValuesAlmost, /* set_values_almost */
+ NULL, /* get_values_hook */
+ NULL, /* accept_focus */
+ XtVersion, /* version */
+ NULL, /* callback private */
+ defaultTranslations, /* tm_table */
+ NULL, /* query_geometry */
+ NULL, /* display_accelerator */
+ NULL, /* extension */
+ },
+#ifdef MOTIF
+ {
+ (XtWidgetProc)_XtInherit, /* border_highlight */
+ (XtWidgetProc)_XtInherit, /* border_unhighligh */
+ XtInheritTranslations, /* translations */
+/*** SOS!!!! Following line was replaced ...... */
+/* (XtWidgetProc)_XtInherit, arm_and_activate */
+#if (XmVersion == 1001)
+ (XmArmAndActivate)_XtInherit, /* arm_and_activate */
+#else
+ (XtActionProc)_XtInherit, /* arm_and_activate */
+#endif
+ NULL, /* syn_resources */
+ 0, /* num_syn_resources */
+ NULL, /* extension */
+ },
+#endif
+ {
+ 0, /* ignore */
+ }
+};
+
+
+
+
+
+
+
+
+
+WidgetClass hyperWidgetClass = (WidgetClass) &hyperClassRec;
+
+/*---------------------------------------------------------------*/
+/* Create the two GCs needed */
+/*---------------------------------------------------------------*/
+
+static void create_gcs(w)
+HyperWidget w;
+{
+ XGCValues values;
+ XtGCMask valueMask;
+
+ valueMask = GCForeground | GCBackground | GCFont;
+
+ values.background = w->core.background_pixel;
+
+ values.foreground = w->hyper.highlight_color;
+ values.font = w->hyper.highlight_font->fid;
+ w->hyper.highlight_gc = XtGetGC((Widget)w, valueMask, &values);
+
+ values.foreground = w->hyper.select_color;
+ w->hyper.select_gc = XtGetGC((Widget)w, valueMask, &values);
+
+ values.foreground = w->hyper.normal_color;
+ values.font = w->hyper.normal_font->fid;
+ w->hyper.normal_gc = XtGetGC((Widget)w, valueMask, &values);
+
+
+
+ valueMask = GCBackground|GCForeground|GCFunction|GCGraphicsExposures;
+
+ values.background = 0;
+ values.foreground = w->hyper.normal_color ^ w->core.background_pixel;
+ values.graphics_exposures = False;
+ values.function = GXxor;
+
+ w->hyper.xor_gc = XtGetGC((Widget)w, valueMask, &values);
+
+
+}
+
+/*--------------------------------------------------------------*/
+/* Initialize: Create the GCs */
+/*--------------------------------------------------------------*/
+
+static void Initialize (request, new)
+HyperWidget request, new;
+{
+ /* Check the size of the widget */
+
+ if (request->core.width == 0)
+ new->core.width = 100;
+ if (request->core.height == 0)
+ new->core.height = 100;
+
+
+ /* Create the GCs */
+
+ create_gcs(new);
+
+ /* No text yet */
+
+ new->hyper.first_seg = new->hyper.last_selected
+ = new->hyper.last_cursor = NULL;
+ new->hyper.hand = XCreateFontCursor(XtDisplay(new),XC_hand2);
+
+ /* Nothing found */
+
+ new->hyper.grep_seg = NULL;
+ new->hyper.grep_txt = NULL;
+ new->hyper.grep_len = 0;
+ new->hyper.grep_off = 0;
+
+}
+
+/*--------------------------------------------------------------*/
+/* Free all memory allocated for the text segments */
+/*--------------------------------------------------------------*/
+
+static void free_text(s)
+text_segment *s;
+{
+
+ while(s)
+ {
+ text_segment *p=s->next;
+ if(s->text) XtFree((XtPointer)s->text);
+ XtFree((XtPointer)s);
+ s = p;
+ }
+
+}
+
+/*--------------------------------------------------------------*/
+/* Destroy the widget: release all memory alocated */
+/*--------------------------------------------------------------*/
+
+static void Destroy (w)
+HyperWidget w;
+{
+ free_text(w->hyper.first_seg);
+ XtReleaseGC((Widget)w, w->hyper.normal_gc);
+ XtReleaseGC((Widget)w, w->hyper.highlight_gc);
+ XtReleaseGC((Widget)w, w->hyper.xor_gc);
+ XtReleaseGC((Widget)w, w->hyper.select_gc);
+ XtRemoveAllCallbacks ((Widget)w,XtNactivateCallback);
+}
+
+/*--------------------------------------------------------------*/
+/* Resize : not implemented */
+/*--------------------------------------------------------------*/
+
+
+static void Resize (w)
+HyperWidget w;
+{
+ /*
+ For futur implementation
+ May be for text warp ...
+ */
+}
+
+/*--------------------------------------------------------------*/
+/* Redisplay : redraw the text */
+/*--------------------------------------------------------------*/
+
+
+static void Redisplay (w, event, region)
+HyperWidget w;
+XEvent *event;
+Region region;
+{
+
+ if(w->core.visible)
+ {
+ text_segment *s = w->hyper.first_seg;
+ int x = w->hyper.margin;
+ int y = 0;
+ Boolean newline = TRUE;
+
+ while(s)
+ {
+
+ /* change line on new lines */
+
+ if(newline)
+ {
+ x = w->hyper.margin;
+ y += s->height;
+ }
+
+ /* redraw only what is needed */
+
+ if(XRectInRegion(region,x,y-s->height+s->desc,s->width,s->height)
+ != RectangleOut)
+ {
+
+ XDrawImageString(XtDisplay (w), XtWindow (w),
+ s->gc,
+ x,
+ y,
+ s->text,
+ s->length);
+
+ if(s->type == HIGHLIGHT)
+ {
+ XDrawLine(XtDisplay (w), XtWindow (w),
+ s->gc,
+ x,
+ y+1,
+ x+s->width,
+ y+1);
+ }
+ }
+
+ x += s->width;
+
+ newline = (s->type == NEWLINE);
+
+ s = s->next;
+ }
+
+
+ if(w->hyper.grep_seg)
+ {
+ if(XRectInRegion(region,
+ w->hyper.grep_x,
+ w->hyper.grep_y,
+ w->hyper.grep_width,
+ w->hyper.grep_height) != RectangleOut)
+
+ XFillRectangle(XtDisplay(w),XtWindow(w),
+ w->hyper.xor_gc,
+ w->hyper.grep_x,
+ w->hyper.grep_y,
+ w->hyper.grep_width,
+ w->hyper.grep_height);
+
+ }
+ }
+}
+
+/*------------------------------------------------------------------*/
+/* SetValues : redraw only for font or color changes */
+/*------------------------------------------------------------------*/
+
+static Boolean SetValues (current, request, new)
+HyperWidget current, request, new;
+{
+ Boolean redraw = FALSE;
+
+#define HAS_CHANGED(a) (new->a != current->a)
+
+ if(
+ HAS_CHANGED(core.background_pixel) ||
+ HAS_CHANGED(hyper.select_color) ||
+ HAS_CHANGED(hyper.highlight_color) ||
+ HAS_CHANGED(hyper.highlight_font) ||
+ HAS_CHANGED(hyper.normal_color) ||
+ HAS_CHANGED(hyper.normal_font)
+ )
+ {
+
+ XtReleaseGC((Widget)new, new->hyper.normal_gc);
+ XtReleaseGC((Widget)new, new->hyper.highlight_gc);
+ XtReleaseGC((Widget)new, new->hyper.xor_gc);
+ XtReleaseGC((Widget)new, new->hyper.select_gc);
+ create_gcs(new);
+
+ /* rebuild text */
+/*
+ if(HAS_CHANGED(hyper.normal_font) ||
+ HAS_CHANGED(hyper.highlight_font))
+ */
+ create_new_text(new);
+
+ redraw = TRUE;
+ }
+
+ return (redraw);
+
+#undef HAS_CHANGED
+
+}
+
+/*------------------------------------------------------------------*/
+/* Calculate the size of the widget */
+/*------------------------------------------------------------------*/
+
+static void calc_new_size (w)
+HyperWidget w;
+{
+ text_segment *s = w->hyper.first_seg;
+ int x = w->hyper.margin;
+ int y = 0;
+ int last_height = 0;
+ Boolean newline = TRUE;
+ Dimension maxWidth = w->hyper.margin;
+ Dimension maxHeight = w->hyper.margin;
+ XtGeometryResult result;
+ Dimension replyWidth = 0, replyHeight = 0;
+
+ /* Get the size of the widget */
+
+ while(s)
+ {
+ if(newline)
+ {
+ if (x > (int) maxWidth) maxWidth=x;
+ x = w->hyper.margin;
+ y += s->height;
+ if(y > (int) maxHeight) maxHeight=y;
+
+ }
+
+ s->x = x;
+ s->y = y - s->height;
+
+ x += s->width;
+
+ newline = (s->type == NEWLINE);
+ last_height = s->height;
+
+ s = s->next;
+ }
+
+ x+= w->hyper.margin;
+ y+= last_height;
+
+ if((Dimension) x > maxWidth ) maxWidth=x;
+ if((Dimension) y > maxHeight) maxHeight=y;
+
+ /*
+ Tell our parent we want a new size
+ */
+
+ if(w->core.width != maxWidth || w->core.height != maxHeight)
+ {
+ result = XtMakeResizeRequest((Widget)w,maxWidth,maxHeight,
+ &replyWidth, &replyHeight) ;
+
+ if (result == XtGeometryAlmost)
+ XtMakeResizeRequest ((Widget)w, replyWidth, replyHeight,NULL, NULL);
+
+ }
+}
+
+/*-----------------------------------------------------------------------*/
+/* Find the "visible" part of a widget as the intersection of all the */
+/* windows of it's parents' windows */
+/*-----------------------------------------------------------------------*/
+
+static void find_visible_part(w,x,y,width,height)
+Widget w;
+Position *x;
+Position *y;
+Dimension *width;
+Dimension *height;
+{
+ Position root_x,root_y;
+ Widget p = w;
+
+ *width = w->core.width;
+ *height = w->core.height;
+ XtTranslateCoords(w,0,0,&root_x,&root_y);
+
+ *x = 0;
+ *y = 0;
+
+ while((p = XtParent(p)))
+ {
+ Position rx,ry;
+ Dimension w,h;
+
+ /*
+ make all computations in the root's
+ coordinate system
+ */
+
+ XtTranslateCoords(p,0,0,&rx,&ry);
+
+ w = p->core.width;
+ h = p->core.height;
+
+ /*
+ use the smallest rectangle
+ */
+
+ if(w < *width) *width = w;
+ if(h < *height) *height = h;
+
+ if(rx>root_x) root_x = rx;
+ if(ry>root_y) root_y = ry;
+
+ /* stop when reach a shell,
+ don't go to top level shell */
+ if(XtIsShell(p)) break;
+ }
+
+ /* Back to the widget's coordinate system */
+
+ XtTranslateCoords(w,0,0,x,y);
+ *x = root_x - *x;
+ *y = root_y - *y;
+
+
+}
+
+/*-----------------------------------------------------------------------*/
+/* Do a "zoom" effect animation, from the selected text segment to the */
+/* visible part of the widget */
+/*-----------------------------------------------------------------------*/
+
+static void zoom_open(w,s)
+HyperWidget w;
+text_segment *s;
+{
+ int dx1,dx2,dy1,dy2;
+
+ Position x ;
+ Position y ;
+ Dimension width ;
+ Dimension height ;
+
+ /* selected rectangle */
+
+ Position xs = s->x;
+ Position ys = s->y;
+ Dimension ws = s->width;
+ Dimension hs = s->height;
+
+
+ /* get the rectangle we want to zoom to */
+
+ find_visible_part((Widget)w,&x,&y,&width,&height);
+
+ /* make sure selected rectangle in visible */
+
+ if(xs<x) xs = x;
+ if(ys<y) ys = y;
+ if((Dimension)(xs+ws) > (Dimension)(x+width)) ws = x+width-xs;
+ if((Dimension)(ys+hs) > (Dimension)(y+height)) hs = y+height-ys;
+
+ /* get the offsets in each directions */
+
+ dx1 = x-xs;
+ dy1 = y-ys;
+ dx2 = ((x+width)-(xs+ws));
+ dy2 = ((y+height)-(ys+hs));
+
+ /* in the rectangles are differents */
+
+ if(dx1 || dy1 || dx2 || dy2)
+ {
+ int min = 32000; /* <-- Can be buggy */
+
+ /*
+ work in "left,top,bottom,right" rectangles (Mac)
+ rather than "x,y,width,height" (X)
+ It's easier for the animation
+ */
+
+ int xws = xs+ws;
+ int yhs = ys+hs;
+
+ /* Get smallest non-null offset */
+
+ if(dx1) min = MIN(min,ABS(dx1));
+ if(dx2) min = MIN(min,ABS(dx2));
+ if(dy1) min = MIN(min,ABS(dy1));
+ if(dy2) min = MIN(min,ABS(dy2));
+
+ /* Scale offsets so minimun offset is 1 pixel */
+
+ dx1 /= min;
+ dx2 /= min;
+ dy1 /= min;
+ dy2 /= min;
+
+ /* Use speed .. */
+
+ dx1 *= w->hyper.speed;
+ dx2 *= w->hyper.speed;
+ dy1 *= w->hyper.speed;
+ dy2 *= w->hyper.speed;
+
+ /* Animate */
+
+ while(min--)
+ {
+ XDrawRectangle(XtDisplay(w),XtWindow(w),
+ w->hyper.xor_gc,xs,ys,xws-xs,yhs-ys);
+
+ /* Needed, otherwise X calls are buffered */
+ XSync(XtDisplay(w),False);
+
+ XDrawRectangle(XtDisplay(w),XtWindow(w),
+ w->hyper.xor_gc,xs,ys,xws-xs,yhs-ys);
+
+ xs += dx1;
+ ys += dy1;
+
+ xws += dx2;
+ yhs += dy2;
+
+ }
+ }
+
+}
+
+/*----------------------------------------------------------------------*/
+/* Find the text segment at point (x,y) */
+/*----------------------------------------------------------------------*/
+static text_segment *find_segment(w,x,y)
+HyperWidget w;
+int x,y;
+{
+ text_segment *s = w->hyper.first_seg;
+
+ while(s)
+ {
+ if( s->type == HIGHLIGHT &&
+ x >= s->x &&
+ y >= s->y &&
+ (Dimension) x <= (Dimension) (s->x + s->width) &&
+ (Dimension) y <= (Dimension) (s->y + s->height)
+ )
+ return s;
+ s = s->next;
+ }
+
+ return NULL;
+}
+
+/*----------------------------------------------------------------------*/
+/* highlight text under cursor */
+/*----------------------------------------------------------------------*/
+static void hilite(HyperWidget w,Boolean on)
+{
+
+ text_segment *s = w->hyper.last_selected;
+
+ if(s)
+ XDrawImageString(XtDisplay (w), XtWindow (w),
+ on?w->hyper.select_gc:s->gc,
+ s->x,
+ s->y+s->height,
+ s->text, s->length);
+
+}
+
+/*-----------------------------------------------------------------------*/
+/* Check for mouse down */
+/*-----------------------------------------------------------------------*/
+
+static void xselect (w, event, args, n_args)
+HyperWidget w;
+XEvent *event;
+char *args[];
+int n_args;
+{
+ text_segment *s;
+
+ /*
+ Find if the used clicked in an
+ highlighted text
+ */
+
+ if((s = w->hyper.last_selected = find_segment(w,event->xbutton.x,event->xbutton.y)))
+ hilite(w,TRUE);
+}
+
+/*-----------------------------------------------------------------------*/
+/* Check for mouse up */
+/*-----------------------------------------------------------------------*/
+
+static void activate (w, event, args, n_args)
+HyperWidget w;
+XEvent *event;
+char *args[];
+int n_args;
+{
+ hyperCallbackStruct cb;
+ text_segment *s;
+
+ /*
+ Find if the user clicked in an
+ highlighted text
+ */
+
+ if((s = find_segment(w,event->xbutton.x,event->xbutton.y))
+ && (s == w->hyper.last_selected))
+ {
+ hilite(w,FALSE);
+
+ /* zoom if required */
+
+ if(w->hyper.zoom) zoom_open(w,s);
+
+ /* Fill callback struct */
+
+ cb.text = s->text;
+ cb.length = s->length;
+ cb.reason = HYPER_REASON;
+ cb.event = event;
+
+ /* call callbacks */
+
+ XtCallCallbacks((Widget)w, XtNactivateCallback, (XtPointer)&cb);
+ }
+ w->hyper.last_selected = NULL;
+}
+
+/*-----------------------------------------------------------------------*/
+/* Check for mouse moves */
+/*-----------------------------------------------------------------------*/
+
+static void cursor (w, event, args, n_args)
+HyperWidget w;
+XEvent *event;
+char *args[];
+int n_args;
+{
+
+ text_segment *s;
+
+ s = find_segment(w,event->xbutton.x,event->xbutton.y);
+
+ if(s != w->hyper.last_cursor)
+ {
+ if(s)
+ XDefineCursor(XtDisplay(w),XtWindow(w),w->hyper.hand);
+ else
+ XUndefineCursor(XtDisplay(w),XtWindow(w));
+ hilite(w,s == w->hyper.last_selected);
+ w->hyper.last_cursor = s;
+ }
+
+}
+
+static void xincrement (h, event, args, n_args)
+HyperWidget h;
+XEvent *event;
+char *args[];
+int n_args;
+{
+#ifdef MOTIF
+#define SetArg(a,b) XtSetArg(al[ac],a,b);ac++
+#define GetValues(w) XtGetValues(w,al,ac);ac=0
+#define SetValues(w) XtSetValues(w,al,ac);ac=0
+
+ Widget clip = XtParent(h);
+ Widget swin;
+ Widget v_scroll;
+
+ int ac = 0;
+ Position dh=0;
+
+ Arg al[5];
+
+ /* https://software.ecmwf.int/issues/browse/SUP-646 */
+
+ printf("## mouse 1\n");
+ if(!clip) return;
+ swin = XtParent(clip);
+
+ printf("## mouse 2\n");
+ /* if(!swin || !XmIsScrolledWindow(swin)) return; */
+ if(!swin) return;
+
+ printf("## mouse 3\n");
+ /* 20131126 if (n_args != 1) return; */
+ SetArg(XmNverticalScrollBar , &v_scroll);
+ GetValues(swin);
+
+ {
+ Position x_parent,y_parent; Position x,y;
+ int min= 0, max= 80, value= 0, slider_size = 80, inc = 10, page_inc = 100;
+ int arg = atoi(args[0]);
+ /* SetArg(XmNminimum,&min);
+ SetArg(XmNmaximum,&max);
+ SetArg(XmNvalue,&value);
+ SetArg(XmNsliderSize,&slider_size);
+ SetArg(XmNincrement,&inc); */
+ /* SetArg(XmNpageIncrement,&page_inc); ??? */
+ ac = 0;
+ XtSetArg(al[ac],XmNverticalScrollBar, &v_scroll );ac++;
+ XtGetValues(swin,al,ac);
+
+ ac = 0;
+ XtSetArg(al[ac], XmNminimum,&min); ac++;
+ XtSetArg(al[ac], XmNmaximum,&max); ac++;
+ XtGetValues(v_scroll, al, ac);
+ XmScrollBarGetValues(v_scroll,&value,&slider_size,&inc,&page_inc);
+
+ ac = 0;
+ XtSetArg(al[ac],XmNx,&x_parent);ac++;
+ XtSetArg(al[ac],XmNy,&y_parent);ac++;
+ XtGetValues(swin,al,ac);
+
+ /* GetValues(v_scroll);
+ XmScrollBarGetValues(v_scroll, value, slider_size, inc, page_inc); */
+
+ dh = (abs(arg) > 5) ? page_inc : inc;
+
+ if (arg < 0) {
+ if (value - dh < min)
+ value = min;
+ else
+ value -= dh;
+ } else {
+ if (value + dh > max)
+ value = max;
+ else
+ value += dh;
+ }
+ ac = 0;
+ XtSetArg(al[ac],XmNx,x);ac++;
+ XtSetArg(al[ac],XmNy,y);ac++;
+ XtSetValues(swin,al,ac);
+ XmScrollBarSetValues(v_scroll,value,slider_size, inc, page_inc,TRUE);
+ }
+#endif
+}
+
+/*-----------------------------------------------------------------------*/
+/* Add a new text segment to the text */
+/*-----------------------------------------------------------------------*/
+/* static void add_to_text(w,word,type) */
+static void add_to_text(w,word,type,offset) /* add offset */
+HyperWidget w;
+char *word;
+int type;
+int offset; /* add offset */
+{
+ text_segment *s = XtNew(text_segment);
+ XCharStruct char_info;
+ int dir,ascent,desc;
+ text_segment *p,*q;
+
+ s->next = NULL;
+ s->text = (word?XtNewString(word):NULL);
+ s->type = type;
+ s->gc = (type == HIGHLIGHT ? w->hyper.highlight_gc : w->hyper.normal_gc);
+ s->x = s->y = s->width = s->height = 0;
+ s->length = (word?strlen(word):0);
+ if(offset>=0) s->offset = offset; /* add offset */
+
+ XTextExtents(
+ (type == HIGHLIGHT ? w->hyper.highlight_font : w->hyper.normal_font),
+ word,
+ s->length,
+ &dir,&ascent,&desc,&char_info);
+
+ s->height = ascent + desc;
+ s->desc = desc;
+ s->width = char_info.width;
+
+ if((p = w->hyper.first_seg))
+ {
+ while(p)
+ {
+ q=p;
+ p=p->next;
+ }
+ q->next = s;
+ }
+ else w->hyper.first_seg = s;
+}
+
+/*-----------------------------------------------------------------------*/
+/* Rebuild the text structure. Called when the font changes */
+/*-----------------------------------------------------------------------*/
+
+static void create_new_text(w)
+HyperWidget w;
+{
+ text_segment *s = w->hyper.first_seg;
+
+ w->hyper.first_seg = w->hyper.last_selected = w->hyper.last_cursor = NULL;
+
+ while(s)
+ {
+ /* add_to_text(w,s->text,s->type); */
+ add_to_text(w,s->text,s->type, -1); /*don't update offset */
+ s = s->next;
+ }
+ free_text(s);
+ calc_new_size(w);
+}
+
+/*-----------------------------------------------------------------------*/
+/* Build the text. Gets the chars from the funtion "get_next_char" */
+/* using "data" as a parameter */
+/*-----------------------------------------------------------------------*/
+
+static void set_text(w,get_next_char,data)
+HyperWidget w;
+char (*get_next_char)(XtPointer);
+XtPointer data;
+{
+ char word[MAX_LINE_SIZE];
+ int i = 0;
+ char soh = w->hyper.start_of_highlight;
+ char eoh = w->hyper.end_of_highlight;
+ char c;
+ int mode = NORMAL;
+ int offset = 0; /* add offset */
+
+ free_text(w->hyper.first_seg);
+ w->hyper.first_seg = w->hyper.last_selected = w->hyper.last_cursor = NULL;
+ w->hyper.grep_seg = NULL;
+ w->hyper.grep_txt = NULL;
+ w->hyper.grep_len = 0;
+ w->hyper.grep_off = 0;
+
+ while((c = (get_next_char)(&data)))
+ {
+ /* New line */
+ if(c == '\n')
+ {
+ word[i]=0;
+ /* if(i) add_to_text(w,word,mode); */
+ if(i) { /* add offset */
+ add_to_text(w,word,mode,offset); /* add offset */
+ offset+=i; /* increment offset */
+ } /* add offset */
+ /* add_to_text(w,NULL,NEWLINE); */
+ add_to_text(w,NULL,NEWLINE, offset); /* add offset */
+ i = 0;
+ }
+
+ /* Start of highlight */
+
+ else if(c == soh)
+ {
+ word[i]=0;
+ /* if(i) add_to_text(w,word,mode); */
+ if(i) { /* add offset */
+ add_to_text(w,word,mode,offset); /* add offset */
+ offset += i; /* increment offset */
+ } /* add offset */
+ mode = HIGHLIGHT;
+ i = 0;
+ }
+
+ /* End of highlight */
+
+ else if(c == eoh)
+ {
+ word[i]=0;
+ /* if(i) add_to_text(w,word,mode); */
+ if(i) { /* add offset */
+ add_to_text(w,word,mode,offset); /* add offset */
+ offset += i+2; /* increment offset, 2 to iclude tags */
+ } /* add offset */
+ mode = NORMAL;
+ i = 0;
+ }
+ else
+ {
+ if(c=='\t') c = ' ';
+ word[i++] = c;
+ if(i==MAX_LINE_SIZE)
+ {
+ word[--i]=0;
+ /* add_to_text(w,word,mode); */
+ add_to_text(w,word,mode,offset); /* add offset */
+ i=0;
+ word[i++] = c;
+ }
+ }
+ }
+
+ /* flush .. */
+
+ if(i)
+ {
+ word[i]=0;
+ add_to_text(w,word,mode,offset);
+ }
+
+ calc_new_size(w);
+
+ /* br advised, vk realized 02 Jun 94 */
+ if(XtIsRealized((Widget) w))
+ XClearArea(XtDisplay(w),XtWindow(w),0,0,0,0,True);
+
+}
+
+/*-----------------------------------------------------------------------*/
+/* Create a new HyperWidget */
+/*-----------------------------------------------------------------------*/
+
+Widget CreateHyper(parent,name,al,ac)
+Widget parent;
+char *name;
+ArgList al;
+int ac;
+{
+ return XtCreateWidget(name,hyperWidgetClass,parent,al,ac);
+}
+
+
+/*-----------------------------------------------------------------------*/
+/* Load the text from a file */
+/*-----------------------------------------------------------------------*/
+
+/* provides chars to "set_text" routine */
+
+static char get_from_file(XtPointer d)
+{
+ FILE **f = (FILE**)d;
+ int n = getc(*f);
+ return (n==EOF?0:(char)n);
+}
+
+/* Public routine */
+
+void HyperLoadFile(widget,fname)
+Widget widget;
+char *fname;
+{
+/*#ifndef linux
+ extern char *sys_errlist[];
+ #endif*/
+
+ FILE *f = fopen(fname,"r");
+ if(f)
+ {
+ set_text((HyperWidget)widget,get_from_file,(XtPointer)f);
+ fclose(f);
+ }
+ else
+ {
+ char msg[1024];
+ sprintf(msg,"%s: %s",fname,strerror(errno)); /* sys_errlist[errno]); */
+ XtWarning(msg);
+ }
+
+}
+
+/*-----------------------------------------------------------------------*/
+/* Load text from memory buffer */
+/*-----------------------------------------------------------------------*/
+
+/* provides chars to "set_text" routine */
+
+static char get_from_buffer(XtPointer d)
+{
+ char **buffer = (XtPointer)d;
+ char c = **buffer;
+ (*buffer)++;
+ return c;
+}
+
+/* Public routine */
+
+void HyperSetText(widget,text)
+Widget widget;
+char *text;
+{
+ set_text((HyperWidget)widget,get_from_buffer,(XtPointer)text);
+}
+
+/*-----------------------------------------------------------------------*/
+/* Specifies start and end of highlignt chars */
+/*-----------------------------------------------------------------------*/
+
+#ifdef _NO_PROTO
+
+void HyperSetTags(widget,start_highlight,end_highlight)
+Widget widget;
+int start_highlight;
+int end_highlight;
+
+#else
+
+void HyperSetTags(Widget widget,
+ int start_highlight,
+ int end_highlight)
+
+#endif
+
+{
+ ((HyperWidget)widget)->hyper.start_of_highlight = start_highlight;
+ ((HyperWidget)widget)->hyper.end_of_highlight = end_highlight;
+}
+
+
+/*-----------------------------------------------------------------------*/
+/* convert a string to lower case */
+/*-----------------------------------------------------------------------*/
+
+static void lowcase(p)
+register char *p;
+{
+ while(*p)
+ {
+ if(isupper(*p)) *p += 32;
+ p++;
+ }
+}
+
+/*-----------------------------------------------------------------------*/
+/* Returns the text of the widget */
+/* the memory is allocated. It must be freed by the application */
+/* If include_tags if FALSE, the special characters are not returned */
+/*-----------------------------------------------------------------------*/
+
+#ifdef _NO_PROTO
+
+char *HyperGetText(widget,include_tags)
+Widget widget;
+Boolean include_tags;
+
+#else
+
+char *HyperGetText(Widget widget,Boolean include_tags)
+
+#endif
+{
+
+ HyperWidget w = (HyperWidget)widget;
+ char *p ;
+ text_segment *s = w->hyper.first_seg;
+ int len = 1;
+ char soh[2];
+ char eoh[2];
+
+ soh[0] = w->hyper.start_of_highlight;
+ eoh[0] = w->hyper.end_of_highlight;
+
+ soh[1] = eoh[1] = 0;
+
+ /* Get size of text */
+
+ while(s)
+ {
+ len += s->length?s->length:1;
+ if(include_tags && s->type == HIGHLIGHT)
+ len += 2;
+ s = s->next;
+ }
+
+ p = XtMalloc(len);
+ *p = 0;
+
+ s = w->hyper.first_seg;
+ while(s)
+ {
+ if(s->length)
+ {
+ if(include_tags && s->type == HIGHLIGHT)
+ strcat(p,soh);
+ strcat(p,s->text);
+ if(include_tags && s->type == HIGHLIGHT)
+ strcat(p,eoh);
+ }
+ else
+ strcat(p,"\n");
+ s=s->next;
+ }
+
+ return p;
+
+}
+
+/*-----------------------------------------------------------------------*/
+/* Only for Motif */
+/* If the widget is in a XmScrolledWindow, scroll it so the selection is */
+/* visible */
+/*-----------------------------------------------------------------------*/
+
+static void show_selection(h)
+HyperWidget h;
+{
+#ifdef MOTIF
+
+ Widget clip = XtParent(h);
+ Widget swin;
+
+ Widget h_scroll;
+ Widget v_scroll;
+
+ int ac = 0;
+
+ Position x_grep,y_grep;
+ Dimension h_grep,w_grep;
+ Position x_clip,y_clip;
+ Dimension h_clip,w_clip;
+ Position dv=0,dh=0;
+ int min,max;
+ int v_val,v_size,v_inc,v_page;
+ int h_val,h_size,h_inc,h_page;
+ Position x,y;
+
+ Arg al[5];
+
+
+
+ /* check if selection exists */
+
+ if(!h->hyper.grep_seg) return;
+
+ /* check if the widget is in a scrolled window */
+ /* the XnScrolledWindow creates a clip window */
+ /* The widget's parent is the clip window */
+
+
+ if(!clip) return;
+ swin = XtParent(clip);
+
+ if(!swin || !XmIsScrolledWindow(swin)) return;
+
+ /* Get window scroll bars */
+
+ SetArg(XmNhorizontalScrollBar, &h_scroll);
+ SetArg(XmNverticalScrollBar , &v_scroll);
+ GetValues(swin);
+
+ /* Get size of clip window and selection rect */
+
+ w_clip = clip->core.width;
+ h_clip = clip->core.height;
+
+ w_grep = h->hyper.grep_width;
+ h_grep = h->hyper.grep_height;
+
+ /* Get global coordinates of clip and selection rect */
+
+ XtTranslateCoords(clip,0,0,&x_clip,&y_clip);
+ XtTranslateCoords((Widget)h,h->hyper.grep_x,h->hyper.grep_y,&x_grep,&y_grep);
+
+ /* offset of selection within clip window */
+
+ x = x_grep - x_clip;
+ y = y_grep - y_clip;
+
+
+ /* selection y coordinate is not visible */
+
+ if( y < 0 || (Dimension) (y + h_grep) > h_clip)
+ {
+ /* the widget must be moved verticaly by dv pixels */
+
+ dv = (y + h_grep / 2) - h_clip / 2;
+
+ SetArg(XmNminimum,&min);
+ SetArg(XmNmaximum,&max);
+
+ GetValues(v_scroll);
+
+ XmScrollBarGetValues(v_scroll,&v_val,&v_size,&v_inc,&v_page);
+
+ max -= v_size;
+
+ if( dv + v_val > max ) dv = max - v_val;
+ if( dv + v_val < min ) dv = min - v_val;
+
+
+ }
+
+ /* selection x coordinate is not visible */
+
+ if( x < 0 || (Dimension) (x + w_grep) > w_clip)
+ {
+ /* the widget must be moved horizontaly by dh pixels */
+
+ dh = (x + w_grep / 2) - w_clip / 2;
+
+ SetArg(XmNminimum,&min);
+ SetArg(XmNmaximum,&max);
+ GetValues(h_scroll);
+
+ XmScrollBarGetValues(h_scroll,&h_val,&h_size,&h_inc,&h_page);
+
+ max -= h_size;
+
+ if( dh + h_val > max ) dh = max - h_val;
+ if( dh + h_val < min ) dh = min - h_val;
+
+ }
+
+ /* if the widget must be moved */
+
+ if(dv || dh)
+ {
+ Position x = h->core.x-dh;
+ Position y = h->core.y-dv;
+
+ /* move it */
+
+ SetArg(XmNx,x);
+ SetArg(XmNy,y);
+ SetValues((Widget)h);
+
+ /* update scroll bars */
+
+ if(dv) XmScrollBarSetValues(v_scroll,v_val+dv,v_size,v_inc,
+ v_page,TRUE);
+ if(dh) XmScrollBarSetValues(h_scroll,h_val+dh,h_size,h_inc,
+ h_page,TRUE);
+ }
+
+#endif /* MOTIF */
+}
+
+/*-----------------------------------------------------------------------*/
+/* Clear previous selection */
+/*-----------------------------------------------------------------------*/
+
+static void clear_selection(w)
+HyperWidget w;
+{
+ if(w->hyper.grep_seg)
+ {
+ if(XtIsRealized((Widget)w))
+
+ /* force a redraw */
+
+ XClearArea(XtDisplay(w),XtWindow(w),
+ w->hyper.grep_x,
+ w->hyper.grep_y,
+ w->hyper.grep_width,
+ w->hyper.grep_height,
+ TRUE);
+
+ }
+ w->hyper.grep_seg = NULL;
+}
+
+/*-----------------------------------------------------------------------*/
+/* Set the new selection */
+/*-----------------------------------------------------------------------*/
+
+static void set_selection(w)
+HyperWidget w;
+{
+ if(w->hyper.grep_seg)
+ {
+ text_segment *s = w->hyper.grep_seg;
+ XCharStruct char_info;
+ int dir,ascent,desc;
+
+ /* get size of the begining of
+ the segment, up to the found string */
+
+ XTextExtents(
+ (s->type == HIGHLIGHT ?
+ w->hyper.highlight_font :
+ w->hyper.normal_font),
+ s->text,
+ w->hyper.grep_off,
+ &dir,&ascent,&desc,&char_info);
+
+ w->hyper.grep_x = s->x + char_info.width;
+ w->hyper.grep_y = s->y + desc;
+ w->hyper.grep_height = s->height;
+
+ /* Get size of the selection */
+
+ XTextExtents(
+ (s->type == HIGHLIGHT ?
+ w->hyper.highlight_font :
+ w->hyper.normal_font),
+ w->hyper.grep_txt,
+ w->hyper.grep_len,
+ &dir,&ascent,&desc,&char_info);
+
+
+ w->hyper.grep_width = char_info.width;
+
+ /* force update */
+
+ if(XtIsRealized((Widget)w))
+ XClearArea(XtDisplay(w),XtWindow(w),
+ w->hyper.grep_x,
+ w->hyper.grep_y,
+ w->hyper.grep_width,
+ w->hyper.grep_height,
+ TRUE);
+ }
+}
+
+/*-----------------------------------------------------------------------*/
+/* Select a word in the hyper widget */
+/* word : word to find ( or regular expression if USE_REGEX is defined) */
+/* ignore_case : if TRUE ignore case in comparaison */
+/* from_start : if TRUE search from start of text, else search from */
+/* current selection */
+/* wrap: if TRUE, continue search from the begining of text if the end */
+/* is reached */
+/*-----------------------------------------------------------------------*/
+
+#ifdef _NO_PROTO
+
+Boolean HyperGrep(widget,word,ignore_case,from_start,wrap)
+Widget widget;
+char *word;
+Boolean ignore_case;
+Boolean from_start;
+Boolean wrap;
+
+#else
+
+Boolean HyperGrep(Widget widget,
+ char *word,
+ Boolean ignore_case,
+ Boolean from_start,
+ Boolean wrap)
+#endif
+
+{
+ HyperWidget h = (HyperWidget)widget;
+ char *w = word;
+ char *p;
+ int offset;
+ text_segment *s;
+
+ if(!h->hyper.first_seg) return False;
+
+ if(ignore_case)
+ {
+ /* if ignore case, change word to lower case */
+ w = XtNewString(word);
+ lowcase(w);
+ }
+
+ /* compile the regular expression */
+ xec_compile(w);
+
+
+ if(ignore_case) XtFree((XtPointer)w);
+
+ /* if from_start or no previous selection,
+ start from first segment */
+
+ if(from_start || h->hyper.grep_seg == NULL)
+ {
+ offset=0;
+ wrap = FALSE;
+ s = h->hyper.first_seg;
+ }
+ else
+ {
+ /* start from last selection */
+
+ offset = h->hyper.grep_off + h->hyper.grep_len;
+ s = h->hyper.grep_seg;
+ }
+
+ for(;;)
+ {
+ if(s->text)
+ {
+ if(ignore_case)
+ {
+ /* if ignore case, change segment to lower case */
+ p = XtNewString(s->text);
+ lowcase(p);
+ }
+ else
+ p = s->text;
+
+ /* search the string */
+
+ if(xec_step(p+offset))
+ {
+ /* if found ...*/
+
+ /* clear previous selection */
+ clear_selection(h);
+
+ h->hyper.grep_seg = s;
+ h->hyper.grep_off = offset + (xec_loc1-(p+offset));
+ h->hyper.grep_txt = s->text + h->hyper.grep_off;
+ h->hyper.grep_len = xec_loc2-xec_loc1;
+
+ /* set new selection */
+
+ set_selection(h);
+
+ /* make it visible */
+
+ show_selection(h);
+
+ if(ignore_case) XtFree((XtPointer)p);
+
+ return TRUE;
+ }
+
+ if(ignore_case) XtFree((XtPointer)p);
+ }
+
+ offset = 0;
+ s = s->next;
+
+ /* if end of text and wrap mode, go to start of text */
+ if(!s)
+ {
+ if(wrap)
+ {
+ wrap = FALSE;
+ s = h->hyper.first_seg;
+ }
+ else break;
+ }
+
+ }
+
+
+ return FALSE;
+
+}
diff --git a/view/src/Hyper.h b/view/src/Hyper.h
new file mode 100644
index 0000000..4973ea0
--- /dev/null
+++ b/view/src/Hyper.h
@@ -0,0 +1,119 @@
+#ifndef HYPER_H
+#define HYPER_H
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #4 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+
+/*
+ If you define MOTIF, the widget will inherit proprieties
+ from the XmPrimitive class : Help Callback, user data, ...
+*/
+
+#ifndef MOTIF
+#define MOTIF
+#endif
+
+/*
+ If your machine got regexp.h
+*/
+
+
+extern WidgetClass hyperWidgetClass;
+typedef struct _HyperClassRec * HyperWidgetClass;
+typedef struct _HyperRec * HyperWidget;
+
+/*
+ * Define resource strings for the Hyper widget.
+ */
+
+#define XtNhighlightFont "highlightFont"
+#define XtNnormalFont "normalFont"
+#define XtNhighlightColor "highlightColor"
+#define XtNselectColor "selectColor"
+#define XtNnormalColor "normalColor"
+#define XtNactivateCallback "activateCallback"
+#define XtNzoomEffect "zoomEffect"
+#define XtCZoom "Zoom"
+#define XtNstartHighlight "startHighlight"
+#define XtNendHighlight "endHighlight"
+#define XtCTagChar "TagChar"
+#define XtNzoomSpeed "zoomSpeed"
+#define XtCZoomSpeed "ZoomSpeed"
+#ifndef XtCMargin
+#define XtCMargin "Margin"
+#endif
+#define XtNmargin "margin"
+
+/*
+ Callback structure
+*/
+
+#define HYPER_REASON 1
+
+typedef struct {
+ int reason; /* always = HYPER_REASON */
+ XEvent *event; /* event */
+ char *text; /* pointer on highlighted text selected (read only) */
+ int length; /* length of selected text */
+} hyperCallbackStruct;
+
+#ifdef _NO_PROTO
+
+extern Widget CreateHyper();
+extern void HyperLoadFile();
+extern void HyperSetText();
+extern void HyperSetTags();
+extern Boolean HyperFind();
+extern char *HyperGetText();
+
+#else
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+ extern Widget CreateHyper(Widget parent,
+ char *name,
+ ArgList al,
+ int ac);
+
+ extern void HyperLoadFile(Widget widget,
+ char *fname);
+
+ extern void HyperSetText(Widget widget,
+ char *text);
+
+ extern void HyperSetTags (Widget widget,
+ int start_highlight,
+ int end_highlight);
+
+ Boolean HyperGrep(Widget widget,
+ char *word,
+ Boolean ignore_case,
+ Boolean from_start,
+ Boolean wrap);
+
+ char *HyperGetText(Widget widget,Boolean include_tags);
+
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif /* _NO_PROTO */
+
+#define XtIsHyper(w) XtIsSubclass(w,hyperWidgetClass)
+
+#endif /* HYPER_H */
diff --git a/view/src/HyperP.h b/view/src/HyperP.h
new file mode 100644
index 0000000..72666a7
--- /dev/null
+++ b/view/src/HyperP.h
@@ -0,0 +1,110 @@
+#ifndef HYPERP_H
+#define HYPERP_H
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #4 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#ifdef MOTIF
+#include <Xm/XmP.h>
+#if (XmVersion >= 1002)
+#include <Xm/PrimitiveP.h>
+#endif
+#endif
+
+/* Hyper class : no new fileds */
+
+typedef struct _HyperClassPart{
+ int ignore;
+} HyperClassPart;
+
+typedef struct _HyperClassRec{
+ CoreClassPart core_class;
+#ifdef MOTIF
+ XmPrimitiveClassPart primitive_class;
+#endif
+ HyperClassPart hyper_class;
+} HyperClassRec;
+
+extern HyperClassRec hyperClassRec;
+
+/* Text segment */
+
+typedef struct text_segment {
+
+ struct text_segment *next; /* Next segment */
+ int type; /* NEWLINE, NORMAL or HIGHLIGHT */
+ char *text; /* pointer to text */
+ int length; /* length of text */
+ int desc; /* font descent */
+ GC gc; /* GC used to draw text */
+ Position x,y; /* Position of drawn text */
+ Dimension width,height; /* Size of drawn text */
+ int offset; /* KELD : offset from start of widget */
+
+} text_segment;
+
+typedef struct _HyperPart {
+
+ Cursor hand; /* Selecting cursor shape */
+
+ Pixel normal_color; /* Color of the normal text */
+ Pixel highlight_color; /* Color of the highlighted text */
+ Pixel select_color; /* Color of the selected text */
+
+ XFontStruct *normal_font; /* Font of the normal text */
+ XFontStruct *highlight_font; /* Font of the highlighted text */
+
+ GC normal_gc; /* Gc for the normal text */
+ GC highlight_gc; /* Gc for the highlighted text */
+
+ GC xor_gc; /* Gc for zoom */
+ GC select_gc; /* Gc for select */
+
+ Boolean zoom; /* zoom effect when selected */
+ int speed; /* zoom speed */
+ char start_of_highlight; /* start of highlighted text mark */
+ char end_of_highlight; /* end of highlighted text mark */
+
+ int margin; /* margins size */
+
+
+ text_segment *grep_seg; /* segment where found text is */
+
+ char *grep_txt; /* pointer to found text */
+ int grep_len; /* length of found text */
+ int grep_off; /* offset of found text */
+
+ Position grep_x; /* rectangle of founf text*/
+ Position grep_y;
+ Dimension grep_width;
+ Dimension grep_height;
+
+ text_segment *first_seg; /* the text segments */
+ text_segment *last_selected; /* last selected segment */
+ text_segment *last_cursor; /* last under cursor segment */
+
+
+ XtCallbackList activate; /* callback list */
+
+} HyperPart;
+
+typedef struct _HyperRec {
+ CorePart core;
+#ifdef MOTIF
+ XmPrimitivePart primitive;
+#endif
+ HyperPart hyper;
+} HyperRec;
+
+#endif /* HYPERP_H */
diff --git a/view/src/SimpleBase.c b/view/src/SimpleBase.c
new file mode 100644
index 0000000..e73b119
--- /dev/null
+++ b/view/src/SimpleBase.c
@@ -0,0 +1,1296 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #10 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include <X11/Intrinsic.h>
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/CoreP.h>
+#include <X11/CompositeP.h>
+#include <X11/ConstrainP.h>
+#include <Xm/XmP.h>
+#include <Xm/DrawingAP.h>
+#include <Xm/ExtObjectP.h>
+#include <Xm/ScrollBar.h>
+#include "SimpleBase.h"
+#include "SimpleBaseP.h"
+
+static void Initialize();
+static void Destroy();
+static void Realize();
+static Boolean SetValues();
+
+
+#ifdef linux
+/* putting this into comments makes ctrl-left button for collector
+ disappear !! */
+static char defaultTranslations[] = "\
+ Shift<Btn5Down>: increment(1)\n Shift<Btn4Down>: increment(-1) \n\
+ <Btn5Down>: increment(10)\n <Btn4Down>: increment(-10) \n\
+<BtnDown>:DrawingAreaInput()\n <BtnUp>:DrawingAreaInput()\n\
+<Key>osfActivate:DrawingAreaInput()\n\
+~s ~m ~a <Key>Return:DrawingAreaInput()\n\
+~s ~m ~a <Key>space:DrawingAreaInput()\n\
+<Key>F1:DrawingAreaInput()\n\
+<Key>F2:DrawingAreaInput()\n";
+#else
+
+#define defaultTranslations XmInheritTranslations
+
+#endif
+
+static void xincrement();
+static XtActionsRec actionsList[] = {
+ { "increment",(XtActionProc) xincrement},
+};
+
+static XtResource resources[] = {
+ {XtNblinkColor, XtCBlinkColor, XtRPixel, sizeof (Pixel),
+ XtOffset(SimpleBaseWidget, simplebase.blink_color), XtRString,"Black"},
+
+ {XtNselected, XtCSelected, XtRInt, sizeof (int),
+ XtOffset(SimpleBaseWidget, simplebase.selected), XtRImmediate,(XtPointer)-1},
+
+ {"blinkRate", "BlinkRate", XtRInt, sizeof (int),
+ XtOffset(SimpleBaseWidget, simplebase.timeout), XtRImmediate,(XtPointer)500},
+
+ {XtNgetpsCallback,XtCCallback,XtRCallback,sizeof(caddr_t),
+ XtOffset (SimpleBaseWidget, simplebase.getps),XtRCallback,NULL},
+
+ {XtNlinkCallback,XtCCallback,XtRCallback,sizeof(caddr_t),
+ XtOffset (SimpleBaseWidget, simplebase.link),XtRCallback,NULL},
+
+ {XtNpsHeader,XtCPsHeader,XtRString,sizeof(String),
+ XtOffset (SimpleBaseWidget, simplebase.header),XtRImmediate,NULL},
+};
+
+
+SimpleBaseClassRec simplebaseClassRec = {
+ {
+ /* core_class fields */
+ (WidgetClass) &xmDrawingAreaClassRec,/* superclass */
+ "SimpleBase", /* class_name */
+ sizeof(SimpleBaseRec), /* widget_size */
+ NULL, /* class_init */
+ NULL, /* class_part_init */
+ FALSE, /* class_inited */
+ Initialize, /* initialize */
+ NULL, /* initialize_hook */
+ Realize, /* realize */
+ actionsList, /* actions */
+ XtNumber(actionsList), /* num_actions */
+ resources, /* resources */
+ XtNumber(resources), /* num_resources */
+ NULLQUARK, /* xrm_class */
+ TRUE, /* compress_motion */
+ XtExposeCompressMaximal, /* compress_exposure */
+ TRUE, /* compress_enterleave*/
+ TRUE, /* visible_interest */
+ Destroy, /* destroy */
+ NULL, /* resize */
+ NULL, /* expose */
+ SetValues, /* set_values */
+ NULL, /* set_values_hook */
+ XtInheritSetValuesAlmost, /* set_values_almost */
+ NULL, /* get_values_hook */
+ NULL, /* accept_focus */
+ XtVersion, /* version */
+ NULL, /* callback_private */
+ defaultTranslations, /* tm_table */
+ NULL, /* query_geometry */
+ XtInheritDisplayAccelerator, /* display_accelerator*/
+ NULL, /* extension */
+ },
+ {
+ /* composite_class fields */
+ NULL, /* geometry_manager */
+ NULL, /* change_managed */
+ XtInheritInsertChild, /* insert_child */
+ XtInheritDeleteChild, /* delete_child */
+ NULL, /* extension */
+ },
+ {
+ /* constraint_class fields */
+ NULL, /* subresources */
+ 0, /* subresource_count */
+ 0, /* constraint_size */
+ NULL, /* initialize */
+ NULL, /* destroy */
+ NULL, /* set_values */
+ NULL, /* extension */
+ },
+ {
+ XtInheritTranslations, /* default translations */
+ NULL, /* syn_resources */
+ 0, /* num_syn_resources */
+ NULL, /* syn_cont_resources */
+ 0, /* num_syn_cont_resources */
+ XmInheritParentProcess, /* parent_process */
+ NULL, /* extension */
+ },
+ {
+ NULL,
+ },
+ {
+ /* SimpleBase class fields */
+ NULL,
+ },
+};
+
+
+#ifndef MIN
+#define MIN(a,b) ((a)>(b)?(b):(a))
+#endif
+
+WidgetClass simplebaseWidgetClass = (WidgetClass) &simplebaseClassRec;
+
+/*
+static void find_visible_part(Widget w,Position *x,Position *y,
+ Dimension* width, Dimension* height)
+{
+ Position root_x,root_y;
+ Widget p = w;
+
+ *width = w->core.width;
+ *height = w->core.height;
+ XtTranslateCoords(w,0,0,&root_x,&root_y);
+
+ *x = 0;
+ *y = 0;
+
+ while((p = XtParent(p)))
+ {
+ Position rx,ry;
+ Dimension w,h;
+
+ XtTranslateCoords(p,0,0,&rx,&ry);
+
+ w = p->core.width;
+ h = p->core.height;
+
+ if(w < *width) *width = w;
+ if(h < *height) *height = h;
+
+ if(rx>root_x) root_x = rx;
+ if(ry>root_y) root_y = ry;
+
+ if(XtIsShell(p)) break;
+ }
+
+ XtTranslateCoords(w,0,0,x,y);
+ *x = root_x - *x;
+ *y = root_y - *y;
+}
+*/
+
+/*-----------------------------------------------------------------*/
+/* Find which gadget was called */
+/*-----------------------------------------------------------------*/
+
+static void button_click(w,cd,event,continue_dispatch)
+SimpleBaseWidget w;
+XtPointer *cd;
+XEvent *event;
+Boolean *continue_dispatch;
+{
+ int i;
+ Position x,y;
+ XmDrawingAreaCallbackStruct cb;
+
+ x = event->xbutton.x;
+ y = event->xbutton.y;
+ /* printf("bclick\n"); */
+
+ for (i = 0; i < w -> composite.num_children; i++)
+ {
+ Widget child = w -> composite.children[i];
+
+ if( XtIsManaged(child) &&
+ (x >= child->core.x && x <= child->core.x + child->core.width)
+ && (y >= child->core.y && y <= child->core.y + child->core.height))
+ {
+ cb.reason = -1;
+ cb.event= event;
+ cb.window = (Window)child;
+ XtCallCallbacks((Widget)w,XmNinputCallback,(XtPointer)&cb);
+ }
+ }
+
+}
+
+
+/*-------------------------------------------------------------------*/
+/* Blink current gadget */
+/*-------------------------------------------------------------------*/
+
+#if 0
+static void time_out(SimpleBaseWidget w,XtIntervalId id)
+{
+ if( w->simplebase.selected >= 0 && w->simplebase.selected < w->simplebase.count) {
+ NodeStruct *n = w->simplebase.nodes + w->simplebase.selected;
+
+ if(XtIsRealized((Widget) w) && n->managed)
+ {
+ /* XFillRectangle */
+
+ XDrawRectangle(XtDisplay(w),XtWindow(w),
+ w->simplebase.blink_gc,
+ n->r.x+1,
+ n->r.y+1,
+ n->r.width-2,
+ n->r.height-2);
+ }
+ }
+ w->simplebase.timeout_id = XtAppAddTimeOut(
+ XtWidgetToApplicationContext((Widget)w),
+ w->simplebase.timeout,
+ (XtTimerCallbackProc)time_out,
+ (XtPointer)w);
+}
+#endif
+
+static void clip_input_callback(clip,widget,cb)
+Widget clip;
+Widget widget;
+XtPointer cb;
+{
+ XtCallCallbacks(widget,XmNinputCallback,cb);
+}
+
+static XtCallbackRec clipcb[] = {
+ { (XtCallbackProc)clip_input_callback, NULL, },
+ { NULL,NULL,},
+};
+
+/*----------------------------------------------------*/
+/* Init : create blink gc */
+/*----------------------------------------------------*/
+
+static void Realize(SimpleBaseWidget w,XtValueMask *value_mask,
+XSetWindowAttributes *attributes)
+{
+ Widget clip,scroll,ww;
+ WidgetClass class = XtClass(w);
+
+ while(class != (WidgetClass)simplebaseWidgetClass)
+ class = class->core_class.superclass;
+ class = class->core_class.superclass;
+ (class->core_class.realize) ((Widget) w, value_mask, attributes);
+
+ ww = (Widget)w;
+ while(ww){
+ if((clip = XtParent(ww)))
+ if((scroll = XtParent(clip)))
+ if(XmIsScrolledWindow(scroll))
+ {
+ clipcb[0].closure = (XtPointer)w;
+ XtAddCallbacks(clip,XmNinputCallback,clipcb);
+ }
+ ww = clip;
+ }
+}
+
+static void Initialize(request, new)
+SimpleBaseWidget request, new;
+{
+ XGCValues values;
+ XtGCMask valueMask;
+
+ /*
+ * Make sure the widget's width and height are
+ * greater than zero.
+ */
+ if (request->core.width <= 0)
+ new->core.width = 5;
+ if (request->core.height <= 0)
+ new->core.height = 5;
+
+ new->simplebase.gc = XtGetGC((Widget)new,0,0);
+
+ valueMask = GCLineWidth ;
+ /* GCForeground | GCBackground | GCFunction | | GCGraphicsExposures; */
+
+ values.foreground = new->core.background_pixel^new->simplebase.blink_color;
+ values.background = values.foreground;
+ values.function = GXxor;
+ values.graphics_exposures = False;
+ values.line_width = 2;
+
+ new->simplebase.blink_gc = XtGetGC((Widget)new,valueMask,&values);
+
+ XtAddEventHandler((Widget)new,ButtonPressMask,
+ False,(XtEventHandler)button_click,(XtPointer)new);
+ XtAddEventHandler((Widget)new,KeyPressMask,
+ False,(XtEventHandler)button_click,(XtPointer)new);
+
+ /* time_out(new,NULL); */
+
+ new->simplebase.focus = -1;
+ new->simplebase.max = 0;
+ new->simplebase.link_max = 0;
+ new->simplebase.count = 0;
+ new->simplebase.link_count = 0;
+ new->simplebase.nodes = NULL;
+ new->simplebase.links = NULL;
+ new->simplebase.work = 0;
+}
+
+
+/*----------------------------------------------------------*/
+/*----------------------------------------------------------*/
+
+static void Destroy(SimpleBaseWidget w)
+{
+ Widget clip,scroll,ww;
+ /* printf("Destroy(SimpleBaseWidget w)\n"); */
+
+ NodeReset((Widget)w);
+
+ XtRemoveEventHandler((Widget)w,ButtonPressMask,
+ False,(XtEventHandler)button_click,(XtPointer)w);
+ XtRemoveEventHandler((Widget)w,KeyPressMask,
+ False,(XtEventHandler)button_click,(XtPointer)w);
+
+ XtReleaseGC((Widget)w,w->simplebase.blink_gc);
+ XtReleaseGC((Widget)w,w->simplebase.gc);
+ /* XtRemoveTimeOut(w->simplebase.timeout_id); */
+
+ ww = (Widget)w;
+ while(ww) {
+ if((clip = XtParent(ww)))
+ if((scroll = XtParent(clip)))
+ if(XmIsScrolledWindow(scroll))
+ {
+ clipcb[0].closure = (XtPointer)w;
+ XtRemoveCallbacks(clip,XmNinputCallback,clipcb);
+ }
+ ww = clip;
+ }
+
+ XtFree((char*)w->simplebase.nodes);
+ XtFree((char*)w->simplebase.links);
+}
+
+static void selection(SimpleBaseWidget w)
+{
+ if( w->simplebase.selected >= 0 && w->simplebase.selected < w->simplebase.count) {
+ NodeStruct *n = w->simplebase.nodes + w->simplebase.selected;
+ if(n->managed)
+ {
+ XDrawRectangle(XtDisplay(w),XtWindow(w),
+ w->simplebase.blink_gc,
+ n->r.x-1,
+ n->r.y-1,
+ n->r.width+2,
+ n->r.height+2);
+ }
+ }
+}
+
+static void clear(SimpleBaseWidget w)
+{
+ if( w->simplebase.selected >= 0 && w->simplebase.selected < w->simplebase.count) {
+ NodeStruct *n = w->simplebase.nodes + w->simplebase.selected;
+ if(n->managed)
+ {
+ XClearArea(XtDisplay(w),XtWindow(w),
+ n->r.x-3,
+ n->r.y-3,
+ n->r.width+5,
+ n->r.height+5,True);
+ }
+ }
+}
+
+void NodesRedraw(SimpleBaseWidget w,XEvent *event, Region region)
+{
+ int i;
+ /* int d = 0,u = 0; */
+
+ /* Position x,y; */
+ /* Dimension a,h; */
+
+ /* find_visible_part(w,&x,&y,&a,&h); */
+ /* printf("find_visible_part : %d %d %d %d \n",x,y,a,h); */
+
+ for(i = 0; i < w->simplebase.count;i++)
+ {
+ NodeStruct *n = w->simplebase.nodes + i;
+ if(n->managed)
+ if(XRectInRegion(region, n->r.x, n->r.y, n->r.width, n->r.height))
+ n->draw((Widget)w,&n->r,n->user_data);
+ }
+
+ /* printf("NodesRedraw %s: draw %d, skip %d\n",XtName(w),d,u); */
+
+ /* XSetRegion(XtDisplay(w),w->simplebase.blink_gc,region); */
+ selection(w);
+ /* XSetClipMask(XtDisplay(w),w->simplebase.blink_gc,None); */
+
+#if 0
+ if( w->simplebase.selected >= 0 && w->simplebase.selected < w->simplebase.count) {
+ NodeStruct *n = w->simplebase.nodes + w->simplebase.selected;
+ if(n->managed)
+ if(XRectInRegion(region, n->r.x-1, n->r.y-1, n->r.width+2, n->r.height+2))
+ {
+ XDrawRectangle(XtDisplay(w),XtWindow(w),
+ w->simplebase.blink_gc,
+ n->r.x-1,
+ n->r.y-1,
+ n->r.width+2,
+ n->r.height+2);
+ }
+ }
+#endif
+}
+
+static int new_link_data(SimpleBaseWidget w)
+{
+ LinkData *d;
+ if(w->simplebase.link_count >= w->simplebase.link_max)
+ {
+ w->simplebase.link_max += w->simplebase.link_max/2 + 128;
+ w->simplebase.links =
+ (LinkData*)XtRealloc((XtPointer)w->simplebase.links,
+ w->simplebase.link_max*sizeof(LinkData));
+ memset(w->simplebase.links + w->simplebase.link_count, 0,
+ (w->simplebase.link_max - w->simplebase.link_count)*sizeof(LinkData));
+ }
+
+ d = &w->simplebase.links[w->simplebase.link_count];
+ d->gc = w->simplebase.gc;
+ d->user_data = 0;
+
+ return w->simplebase.link_count++;
+}
+
+int NodeCreate(Widget _w,DrawProc draw,SizeProc size,void *data)
+{
+ SimpleBaseWidget w = (SimpleBaseWidget)_w;
+ NodeStruct *n;
+ if(w->simplebase.count >= w->simplebase.max)
+ {
+ w->simplebase.max += w->simplebase.max/2 + 128;
+ w->simplebase.nodes =
+ (NodeStruct*)XtRealloc((XtPointer)w->simplebase.nodes,
+ w->simplebase.max*sizeof(NodeStruct));
+ memset(w->simplebase.nodes + w->simplebase.count, 0,
+ (w->simplebase.max - w->simplebase.count)*sizeof(NodeStruct));
+ }
+
+ n = &w->simplebase.nodes[w->simplebase.count];
+#if 0
+ n-> group = -1;
+#endif
+ n->r.width = 30;
+ n->r.height = 20;
+ n->draw = draw;
+ n->size = size;
+ n->user_data = data;
+ /* n->size(_w,&n->r,data); */
+
+ return w->simplebase.count++;
+}
+
+
+static Boolean manage_proc(SimpleBaseWidget w)
+{
+ WidgetClass class = XtClass(w);
+ WidgetClass sclass = simplebaseClassRec.core_class.superclass;
+
+ long width = w->core.width;
+ long height = w->core.height;
+ Position pwidth;
+ Position pheight;
+
+ w->simplebase.work = 0;
+
+ while(class != sclass)
+ {
+ SimpleBaseClassRec *bc = (SimpleBaseClassRec*)class;
+
+ if(bc->simplebase_class.layout)
+ (*(bc->simplebase_class.layout))((Widget)w,&width,&height);
+
+ class = class->core_class.superclass;
+
+ }
+
+ pwidth = width; if(pwidth != width) pwidth = 0x7f00;
+ pheight = height;if(pheight != height) pheight = 0x7f00;
+
+ if(pwidth != w->core.width || pheight != w->core.height)
+ {
+ Dimension replyWidth = 0, replyHeight = 0;
+
+ XtGeometryResult result = XtMakeResizeRequest((Widget)w,
+ pwidth,pheight,
+ &replyWidth, &replyHeight);
+
+ if (result == XtGeometryAlmost)
+ XtMakeResizeRequest ((Widget)w, replyWidth, replyHeight,
+ NULL, NULL);
+ }
+
+ if(XtIsRealized((Widget) w))
+ {
+ /* printf("XClearArea 1 %s\n",XtName(w)); */
+ XClearArea(XtDisplay(w),XtWindow(w),0,0,0,0,True);
+ }
+
+ return True;
+
+}
+
+static void enqueue_manage_proc(SimpleBaseWidget w)
+{
+ if(w->simplebase.work == 0)
+ w->simplebase.work = XtAppAddWorkProc(
+ XtWidgetToApplicationContext((Widget)w),
+ (XtWorkProc)manage_proc,(XtPointer)w);
+}
+
+void NodeChanged(Widget _w,int node)
+{
+ SimpleBaseWidget w = (SimpleBaseWidget)_w;
+ if( w == 0 || node < 0 || node >= w->simplebase.count) return;
+
+ if(XtIsRealized((Widget)w))
+ {
+ NodeStruct *p = w->simplebase.nodes + node;
+ if(p->managed)
+ {
+ /* printf("XClearArea 2 %s\n",XtName(w)); */
+ XClearArea(XtDisplay(w),XtWindow(w),
+ p->r.x,p->r.y,
+ p->r.width,p->r.height,True);
+ }
+ }
+}
+
+void NodeSetFocus(Widget _w,int node)
+{
+ SimpleBaseWidget w = (SimpleBaseWidget)_w;
+ if( w == 0 || node >= w->simplebase.count) return;
+ w->simplebase.focus = node;
+ enqueue_manage_proc(w);
+}
+
+void *NodeFind(Widget _w,XEvent *ev)
+{
+ SimpleBaseWidget w = (SimpleBaseWidget)_w;
+ int i;
+ for(i = 0; i < w->simplebase.count;i++)
+ {
+ NodeStruct *n = w->simplebase.nodes + i;
+ if(n->managed)
+ if(ev->xbutton.x >= n->r.x && ev->xbutton.x <= n->r.x + n->r.width &&
+ ev->xbutton.y >= n->r.y && ev->xbutton.y <= n->r.y + n->r.height)
+ return n->user_data;
+ }
+ return NULL;
+}
+
+void SimpleBaseShow(Widget _w,XRectangle* r,XEvent* ev)
+{
+ /* SimpleBaseWidget sw = (SimpleBaseWidget)_w; */
+
+ Widget v_scroll,h_scroll;
+ Position x_parent,y_parent;
+ Position x_clip,y_clip;
+ Position x_event,y_event;
+ Dimension h_clip,w_clip;
+ Position dv=0,dh=0;
+ int min,max;
+ int v_val,v_size,v_inc,v_page;
+ int h_val,h_size,h_inc,h_page;
+ Widget clip = NULL;
+ Widget scroll_window = NULL;
+ Arg al[5];
+ int ac;
+ /* NodeStruct *w; */
+ Position x_node ,y_node;
+ Dimension h_node,w_node;
+
+ Position x,y;
+
+ Widget ww = _w;
+ while(ww) {
+ if(!(clip = XtParent(ww))) return;
+ if(!(scroll_window = XtParent(clip))) return;
+ if(XmIsScrolledWindow(scroll_window)) break;
+ if(!(ww = XtParent(ww))) return;
+
+ }
+
+ x_node = r->x;
+ y_node = r->y;
+ h_node = r->height;
+ w_node = r->width;
+
+ ac = 0;
+ XtSetArg(al[ac],XmNhorizontalScrollBar, &h_scroll );ac++;
+ XtSetArg(al[ac],XmNverticalScrollBar, &v_scroll );ac++;
+ XtGetValues(scroll_window,al,ac);
+
+ ac = 0;
+ XtSetArg(al[ac],XmNx,&x_parent);ac++;
+ XtSetArg(al[ac],XmNy,&y_parent);ac++;
+ XtGetValues(_w,al,ac);
+
+ ac = 0;
+ XtSetArg(al[ac],XmNclipWindow,&clip);ac++;
+ XtGetValues(scroll_window,al,ac);
+
+ ac = 0;
+ XtSetArg(al[ac],XmNheight,&h_clip);ac++;
+ XtSetArg(al[ac],XmNwidth,&w_clip);ac++;
+ XtGetValues(clip,al,ac);
+
+
+ XtTranslateCoords(_w,x_node,y_node, &x_node,&y_node);
+ XtTranslateCoords(clip,0,0,&x_clip,&y_clip);
+ if(ev) XtTranslateCoords(_w,ev->xbutton.x,ev->xbutton.y, &x_event,&y_event);
+
+
+ x = x_node - x_clip;
+ y = y_node - y_clip;
+
+
+ if( y < 0 || y + h_node > h_clip || ev)
+ {
+ if(ev)
+ dv = (y + h_node / 2) - (y_event - y_clip);
+ else
+ dv = (y + h_node / 2) - h_clip / 2;
+
+ ac = 0;
+ XtSetArg(al[ac],XmNminimum,&min);ac++;
+ XtSetArg(al[ac],XmNmaximum,&max);ac++;
+ XtGetValues(v_scroll,al,ac);
+
+ XmScrollBarGetValues(v_scroll,&v_val,&v_size,&v_inc,&v_page);
+
+ max -= v_size;
+
+ if( dv + v_val > max ) dv = max - v_val;
+ if( dv + v_val < min ) dv = min - v_val;
+
+
+ }
+ if( x < 0 || x + w_node > w_clip || ev)
+ {
+ if(ev)
+ dh = (x + w_node / 2) - (x_event - x_clip);
+ else
+ dh = (x + w_node / 2) - w_clip / 2;
+
+ ac = 0;
+ XtSetArg(al[ac],XmNminimum,&min);ac++;
+ XtSetArg(al[ac],XmNmaximum,&max);ac++;
+ XtGetValues(h_scroll,al,ac);
+
+ XmScrollBarGetValues(h_scroll,&h_val,&h_size,&h_inc,&h_page);
+
+ max -= h_size;
+
+ if( dh + h_val > max ) dh = max - h_val;
+ if( dh + h_val < min ) dh = min - h_val;
+
+ }
+
+
+ if(dv || dh)
+ {
+ Position x = x_parent-dh;
+ Position y = y_parent-dv;
+
+ ac = 0;
+ XtSetArg(al[ac],XmNx,x);ac++;
+ XtSetArg(al[ac],XmNy,y);ac++;
+ XtSetValues(_w,al,ac);
+
+
+ if(dv) XmScrollBarSetValues(v_scroll,v_val+dv,
+ v_size,v_inc,v_page,TRUE);
+ if(dh) XmScrollBarSetValues(h_scroll,h_val+dh,
+ h_size,h_inc,h_page,TRUE);
+ }
+}
+
+void NodeShow(Widget _w,int node)
+{
+ SimpleBaseWidget sw = (SimpleBaseWidget)_w;
+ NodeStruct *w;
+
+ if( node < 0 || node >= sw->simplebase.count) return;
+ w = sw->simplebase.nodes + node;
+ if(!w->managed) return;
+
+ SimpleBaseShow(_w,&w->r,NULL);
+}
+
+void NodeHideAll(Widget _w)
+{
+ SimpleBaseWidget w = (SimpleBaseWidget)_w;
+ int i;
+ for(i = 0; i < w->simplebase.count;i++)
+ {
+ NodeStruct *n = w->simplebase.nodes + i;
+ n->managed = False;
+ }
+ NodeUpdate(_w);
+}
+
+Boolean NodeVisibility(Widget _w,int node,Boolean vis)
+{
+ SimpleBaseWidget w = (SimpleBaseWidget)_w;
+ NodeStruct *p = w ? w->simplebase.nodes + node : NULL;
+ if (!w)
+ return False;
+
+ if( node < 0 || node >= w->simplebase.count) return vis;
+ if (0 == p) {
+ fprintf(stderr, "unexpected\n");
+ return False;
+ }
+ if(p->managed == vis) return vis;
+
+ /* if(node == w->simplebase.selected) selection(w); */
+
+ p->managed = vis;
+
+ if(vis && !p->inited)
+ {
+ p->size(_w,&p->r,p->user_data);
+ p->inited = True;
+ }
+
+ enqueue_manage_proc(w);
+ return !vis;
+}
+
+void NodeNewSizeAll(Widget _w)
+{
+ int i;
+ SimpleBaseWidget w = (SimpleBaseWidget)_w;
+ for(i = 0; i < w->simplebase.count;i++)
+ NodeNewSize(_w,i);
+ if(XtIsRealized(_w))
+ XClearArea(XtDisplay(_w),XtWindow(_w),0,0,0,0,True);
+}
+
+void NodeNewSize(Widget _w,int node)
+{
+ XRectangle next,old;
+ SimpleBaseWidget w = (SimpleBaseWidget)_w;
+ NodeStruct *p ;
+ if( w == 0 || node < 0 || node >= w->simplebase.count) return;
+
+ p = w->simplebase.nodes + node;
+
+ if( !p->managed)
+ {
+ p->inited = False;
+ return;
+ }
+
+
+ old = next = p->r;
+ p->size(_w,&next,p->user_data);
+
+ if(next.x == p->r.x && next.y == p->r.y &&
+ next.width == p->r.width && next.height == p->r.height)
+ return;
+
+ if(node == w->simplebase.selected) clear(w);
+
+ p->r = next;
+
+ /* if(node == w->simplebase.selected) selection(w); */
+
+ /* if( !p->managed) return; */
+
+ if(!XtIsRealized(_w))
+ return;
+
+ XClearArea(XtDisplay(_w),XtWindow(_w),old.x,old.y,
+ old.width,old.height,True);
+
+ XClearArea(XtDisplay(_w),XtWindow(_w),p->r.x,p->r.y,
+ p->r.width,p->r.height,True);
+
+ if(p->managed)
+ enqueue_manage_proc(w);
+}
+
+
+
+void NodeUpdate(Widget _w)
+{
+ SimpleBaseWidget w = (SimpleBaseWidget)_w;
+ if(w->simplebase.work) {
+ XtRemoveWorkProc(w->simplebase.work);
+ w->simplebase.work = 0;
+ }
+ /* printf("update\n"); */
+ manage_proc(w);
+}
+
+
+
+void NodeReset(Widget _w)
+{
+ SimpleBaseWidget w = (SimpleBaseWidget)_w;
+ int i;
+ for(i = 0; i < w->simplebase.count;i++)
+ {
+ NodeStruct *n = w->simplebase.nodes + i;
+ if(n->parents) XtFree((XtPointer)n->parents);
+ if(n->kids) XtFree((XtPointer)n->kids);
+ }
+ w->simplebase.count = 0;
+ w->simplebase.link_count = 0;
+ w->simplebase.selected = -1;
+ w->simplebase.focus = -1;
+ memset(w->simplebase.nodes,0,w->simplebase.max*sizeof(NodeStruct));
+ memset(w->simplebase.links,0,w->simplebase.link_max*sizeof(LinkData));
+ NodeUpdate(_w);
+}
+
+void NodeReserve(Widget _w,int count)
+{
+ SimpleBaseWidget w = (SimpleBaseWidget)_w;
+ if(count > w->simplebase.max)
+ {
+ w->simplebase.max = count;
+ w->simplebase.nodes =
+ (NodeStruct*)XtRealloc((XtPointer)w->simplebase.nodes,
+ w->simplebase.max*sizeof(NodeStruct));
+ memset(w->simplebase.nodes + w->simplebase.count, 0,
+ (w->simplebase.max - w->simplebase.count)*sizeof(NodeStruct));
+ }
+}
+
+
+void NodeAddRelation(Widget _w,int pnode,int knode)
+{
+ int i;
+ SimpleBaseWidget w = (SimpleBaseWidget)_w;
+ NodeStruct *p = w->simplebase.nodes + pnode;
+ NodeStruct *k = w->simplebase.nodes + knode;
+
+ if( pnode < 0 || pnode >= w->simplebase.count) return;
+ if( knode < 0 || knode >= w->simplebase.count) return;
+
+ for(i = 0 ; i < p->kcnt; i++)
+ if(p->kids[i].node == knode)
+ return;
+
+ if(k->pcnt >= k->pmax)
+ {
+ k->pmax += k->pmax/2 + 1;
+ k->parents = (Link*)XtRealloc((XtPointer)k->parents,k->pmax*sizeof(Link));
+ }
+
+ if(p->kcnt >= p->kmax)
+ {
+ p->kmax += p->kmax/2 + 1;
+ p->kids = (Link*)XtRealloc((XtPointer)p->kids,p->kmax*sizeof(Link));
+ }
+
+ p->kids[p->kcnt].link_data = -1;
+ p->kids[p->kcnt++].node = knode;
+
+ k->parents[k->pcnt].link_data = -1;
+ k->parents[k->pcnt++].node = pnode;
+
+ /*printf("NodeAddRelation %d %d (%d)\n",pnode,knode,kind);*/
+}
+
+void* NodeGetRelationData(Widget _w,int pnode,int knode)
+{
+ int i;
+ SimpleBaseWidget w = (SimpleBaseWidget)_w;
+ NodeStruct *p = w->simplebase.nodes + pnode;
+ /* NodeStruct *k = w->simplebase.nodes + knode; */
+
+ if( pnode < 0 || pnode >= w->simplebase.count) return 0;
+ if( knode < 0 || knode >= w->simplebase.count) return 0;
+
+ for(i = 0 ; i < p->kcnt; i++)
+ if(p->kids[i].node == knode)
+ {
+ if( p->kids[i].link_data == -1)
+ return 0;
+ return w->simplebase.links[p->kids[i].link_data].user_data;
+ }
+
+
+ /* Check for dummies */
+ for(i = 0 ; i < p->kcnt; i++)
+ {
+ NodeStruct* z = &KIDS(w,p,i);
+ if(sb_is_dummy(w,z))
+ {
+ void *d = NodeGetRelationData(_w,NODE_TO_INDEX(w,z),knode);
+ if(d) return d;
+ }
+ }
+
+
+ return 0;
+}
+
+void* NodeSetRelationData(Widget _w,int pnode,int knode,void *data)
+{
+ int i;
+ SimpleBaseWidget w = (SimpleBaseWidget)_w;
+ NodeStruct *p = w->simplebase.nodes + pnode;
+ /* NodeStruct *k = w->simplebase.nodes + knode; */
+
+ if( pnode < 0 || pnode >= w->simplebase.count) return 0;
+ if( knode < 0 || knode >= w->simplebase.count) return 0;
+
+ for(i = 0 ; i < p->kcnt; i++)
+ if(p->kids[i].node == knode)
+ {
+ void *old = 0;
+ if( p->kids[i].link_data == -1)
+ p->kids[i].link_data = new_link_data(w);
+ else
+ old = w->simplebase.links[p->kids[i].link_data].user_data;
+ w->simplebase.links[p->kids[i].link_data].user_data = data;
+ return old;
+ }
+
+ return 0;
+}
+
+GC NodeSetRelationGC(Widget _w,int pnode,int knode,GC rgc)
+{
+ int i;
+ SimpleBaseWidget w = (SimpleBaseWidget)_w;
+ NodeStruct *p = w->simplebase.nodes + pnode;
+ /* NodeStruct *k = w->simplebase.nodes + knode; */
+ GC gc = w->simplebase.gc;
+
+ if( pnode < 0 || pnode >= w->simplebase.count) return gc;
+ if( knode < 0 || knode >= w->simplebase.count) return gc;
+
+ for(i = 0 ; i < p->kcnt; i++)
+ if(p->kids[i].node == knode)
+ {
+ GC old = gc;
+ if( p->kids[i].link_data == -1)
+ p->kids[i].link_data = new_link_data(w);
+ else
+ old = w->simplebase.links[p->kids[i].link_data].gc;
+ w->simplebase.links[p->kids[i].link_data].gc = rgc;
+ enqueue_manage_proc(w);
+ return old;
+ }
+
+ return gc;
+}
+
+
+static Boolean SetValues(SimpleBaseWidget current,
+SimpleBaseWidget request,
+SimpleBaseWidget new)
+{
+ int redraw = FALSE;
+ XGCValues values;
+ XtGCMask valueMask;
+
+ if (new->simplebase.blink_color != current->simplebase.blink_color ||
+ new->core.background_pixel !=
+ current->core.background_pixel){
+ valueMask = GCForeground | GCBackground |
+ GCFunction | GCLineWidth;
+ values.foreground = new->simplebase.blink_color;
+ values.background = new->core.background_pixel;
+ values.function = GXxor;
+ values.line_width = 2;
+ XtReleaseGC((Widget)new,new->simplebase.blink_gc);
+ new->simplebase.blink_gc = XtGetGC((Widget)new, valueMask, &values);
+ redraw = TRUE;
+ }
+
+ if(XtIsRealized((Widget)new) && XtIsManaged((Widget)new))
+ if(new->simplebase.selected != current->simplebase.selected)
+ {
+ clear(current);
+ clear(new);
+ }
+
+ /* printf("Redraw %d\n",redraw); */
+
+ return (redraw);
+}
+
+static void drawDummy(Widget w,XRectangle* r,void* d)
+{
+}
+
+static void sizeDummy(Widget w,XRectangle* r,void* d)
+{
+ r->width = r->height = 0;
+}
+
+int sb_new_dummy_node(SimpleBaseWidget gw)
+{
+ int i;
+ int n = gw->simplebase.count;
+ /* int more = 0; */
+ NodeStruct* z = 0;
+
+ for(i=0; i < n; i++)
+ {
+ NodeStruct* w = gw->simplebase.nodes + i;
+ if(w->draw == drawDummy && !w->managed)
+ {
+ printf("Recycle dummy %d\n",i);
+ z = w;
+ break;
+ }
+ }
+
+ if(z == 0)
+ {
+ printf("Create dummy\n");
+ i = NodeCreate((Widget)gw,drawDummy,sizeDummy,0);
+ z = INDEX_TO_NODE(gw,i);
+ z->kids = XtNew(Link);
+ z->parents = XtNew(Link);
+ z->kcnt = z->kmax = z->pcnt = z->pmax = 1;
+ }
+
+ z->r.width = z->r.height = 0;
+
+ z->kids[0].node = -1;
+ z->parents[0].node = -1;
+
+ z->managed = False;
+ z->inited = False;
+
+ z->kids[0].link_data = -1;
+ z->parents[0].link_data = -1;
+
+ return NODE_TO_INDEX(gw,z);
+}
+
+void sb_clear_dummy_nodes(SimpleBaseWidget gw)
+{
+ int i;
+ int n = gw->simplebase.count;
+ /* int more = 0; */
+ int cnt = 0;
+
+ for(i=0; i < n; i++)
+ {
+ NodeStruct* w = gw->simplebase.nodes + i;
+ if(w->draw == drawDummy && w->managed)
+ {
+ NodeStruct *p = INDEX_TO_NODE(gw,w->parents[0].node);
+ NodeStruct *k = INDEX_TO_NODE(gw,w->kids[0].node);
+ int j;
+
+ cnt++;
+
+ j = sb_find_kid_index(gw,p,w);
+ if(j == -1) {
+ printf("Cannot find dummy in parent\n");
+ abort();
+ }
+ p->kids[j].node = w->kids[0].node;
+
+ j = sb_find_parent_index(gw,k,w);
+ if(j == -1) {
+ printf("Cannot find dummy in kid\n");
+ abort();
+ }
+ k->parents[j].node = w->parents[0].node;
+
+ w->kids[0].node = -1;
+ w->parents[0].node = -1;
+ w->kids[0].link_data = -1;
+ w->parents[0].link_data = -1;
+ w->managed = False;
+
+ }
+ }
+ /* printf("remove_dummy_nodes: %d\n",cnt); */
+}
+
+int sb_insert_dummy_node(SimpleBaseWidget gw,int np,int nk)
+{
+ NodeStruct *p = INDEX_TO_NODE(gw,np);
+ NodeStruct *k = INDEX_TO_NODE(gw,nk);
+ int a = sb_find_kid_index(gw,p,k);
+ int b = sb_find_parent_index(gw,k,p);
+ int x;
+ NodeStruct *z;
+
+ if(a == -1)
+ {
+ printf("Cannot find kid in parent\n");
+ abort();
+ }
+
+ if(b == -1)
+ {
+ printf("Cannot find parent in kid\n");
+ abort();
+ }
+
+ x = sb_new_dummy_node(gw);
+ z = INDEX_TO_NODE(gw,x);
+
+ /* sb_new_dummy_node may have changed the pointers */
+
+ p = INDEX_TO_NODE(gw,np);
+ k = INDEX_TO_NODE(gw,nk);
+
+ z->managed = True;
+
+ p->kids[a].node = x;
+ z->parents[0].node = np;
+ z->kids[0].link_data = p->kids[a].link_data;;
+
+ k->parents[b].node = x;
+ z->kids[0].node = nk;
+ z->parents[0].link_data = k->parents[b].link_data;
+
+ return x;
+}
+
+int sb_find_kid_index(SimpleBaseWidget w,NodeStruct* p,NodeStruct *k)
+{
+ int i;
+ int x = NODE_TO_INDEX(w,k);
+
+ for(i=0;i<p->kcnt;i++)
+ if( p->kids[i].node == x)
+ return i;
+
+ return -1;
+}
+
+int sb_find_parent_index(SimpleBaseWidget w,NodeStruct* k,NodeStruct *p)
+{
+ int i;
+ int x = NODE_TO_INDEX(w,p);
+
+ for(i=0;i<k->pcnt;i++)
+ if( k->parents[i].node == x)
+ return i;
+
+ return -1;
+}
+
+Boolean sb_is_dummy(SimpleBaseWidget w,NodeStruct* n)
+{
+ return n->draw == drawDummy;
+}
+
+int NodeNewGroup(Widget _w,DrawProc draw, SizeProc size, void *data)
+{ return 0;
+}
+void NodeSetGroup(Widget _w,int node,int group)
+{
+}
+int NodeGetGroup(Widget _w,int node)
+{
+ return -1;
+}
+
+static void xincrement (h, event, args, n_args)
+Widget h;
+XEvent *event;
+char *args[];
+int n_args;
+{
+#ifdef MOTIF
+#define SetArg(a,b) XtSetArg(al[ac],a,b);ac++
+#define GetValues(w) XtGetValues(w,al,ac);ac=0
+#define SetValues(w) XtSetValues(w,al,ac);ac=0
+
+ Widget clip = XtParent(h);
+ Widget swin;
+ Widget v_scroll;
+
+ int ac = 0;
+ Arg al[5];
+
+ /* printf("## mouse 1\n"); */
+ if(!clip) return;
+ swin = XtParent(clip);
+ /* printf("## mouse 2\n"); */
+ if(!swin || !XmIsScrolledWindow(swin)) return;
+ /* printf("## mouse 3\n"); */
+ if (n_args != 1) return;
+
+ SetArg(XmNverticalScrollBar , &v_scroll);
+ GetValues(swin);
+
+ {
+ int min, max, value, slider_size, inc, page_inc;
+
+ ac = 0;
+ XtSetArg(al[ac], XmNminimum,&min); ac++;
+ XtSetArg(al[ac], XmNmaximum,&max); ac++;
+ XtGetValues(v_scroll, al, ac);
+ XmScrollBarGetValues(v_scroll,&value,&slider_size,&inc,&page_inc);
+
+ /* SetArg(XmNvalue,&value);
+ SetArg(XmNsliderSize,&slider_size);
+ SetArg(XmNincrement,&inc);
+ SetArg(XmNpageIncrement,&page_inc); */
+
+ /* GetValues(v_scroll);
+ XmScrollBarGetValues(v_scroll, value, slider_size, inc, page_inc); */
+
+ ac = 0;
+ XtSetArg(al[ac],XmNx,&x_parent);ac++;
+ XtSetArg(al[ac],XmNy,&y_parent);ac++;
+ XtGetValues(swin,al,ac);
+
+ int arg = atoi(args[0]);
+ dh = (abs(arg) > 5) ? page_inc : inc;
+
+ if (arg < 0) {
+ if (value - dh < min)
+ value = min;
+ else
+ value -= dh;
+ } else {
+ if (value + dh > max)
+ value = max;
+ else
+ value += dh;
+ }
+
+ ac = 0;
+ XtSetArg(al[ac],XmNx,x);ac++;
+ XtSetArg(al[ac],XmNy,y);ac++;
+ XtSetValues(swin,al,ac);
+ XmScrollBarSetValues(v_scroll,value,slider_size, inc, page_inc,TRUE);
+ }
+#endif
+}
diff --git a/view/src/SimpleBase.h b/view/src/SimpleBase.h
new file mode 100644
index 0000000..a17ac82
--- /dev/null
+++ b/view/src/SimpleBase.h
@@ -0,0 +1,95 @@
+#ifndef SIMPLEBASE_H
+#define SIMPLEBASE_H
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #4 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+
+extern WidgetClass simplebaseWidgetClass;
+
+typedef struct _SimpleBaseClassRec *SimpleBaseWidgetClass;
+typedef struct _SimpleBaseRec *SimpleBaseWidget;
+
+#define XtNselected "selected"
+#define XtCSelected "Selected"
+
+#define XtNblinkRate "blinkRate"
+#define XtCBlinkRate "BlinkRate"
+
+#define XtNblinkColor "blinkColor"
+#define XtCBlinkColor "BlinkColor"
+
+#define XtNpsHeader "psHeader"
+#define XtCPsHeader "PsHeader"
+
+#define XtNgetpsCallback "getps"
+#define XtNlinkCallback "linkCallback"
+
+
+typedef struct {
+ Widget widget;
+ char *name;
+ char *psproc;
+} getpsCallbackStruct;
+
+typedef struct {
+ int reason;
+ XEvent *event;
+ void* data1;
+ void* data2;
+} LinkCallbackStruct;
+
+typedef void (*DrawProc)(Widget,XRectangle*,void*);
+typedef void (*SizeProc)(Widget,XRectangle*,void*);
+
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+
+void NodesRedraw(SimpleBaseWidget w, XEvent *event, Region region);
+int NodeCreate(Widget _w, DrawProc draw, SizeProc size, void *data);
+void NodeChanged(Widget _w, int node);
+void *NodeFind(Widget _w, XEvent *ev);
+void NodeShow(Widget _w, int node);
+void NodeHideAll(Widget _w);
+Boolean NodeVisibility(Widget _w, int node, Boolean vis);
+void NodeNewSize(Widget _w, int node);
+void NodeNewSizeAll(Widget _w);
+void NodeUpdate(Widget _w);
+void NodeReset(Widget _w);
+void NodeReserve(Widget _w, int count);
+
+void NodeInsert(Widget _w,int pnode,int knode,int nnode);
+
+void NodeAddRelation(Widget _w,int pnode,int knode);
+void *NodeGetRelationData(Widget _w,int pnode,int knode);
+void *NodeSetRelationData(Widget _w,int pnode,int knode,void*);
+GC NodeGetRelationGC(Widget _w,int pnode,int knode);
+GC NodeSetRelationGC(Widget _w,int pnode,int knode,GC);
+
+void NodeSetFocus(Widget _w, int node);
+int NodeGetFocus(Widget _w);
+
+int NodeNewGroup(Widget _w,DrawProc draw, SizeProc size, void *data);
+void NodeSetGroup(Widget _w,int node,int group);
+int NodeGetGroup(Widget _w,int node);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+
+#endif /* SIMPLEBASE_H */
diff --git a/view/src/SimpleBaseP.h b/view/src/SimpleBaseP.h
new file mode 100644
index 0000000..3fe8f2f
--- /dev/null
+++ b/view/src/SimpleBaseP.h
@@ -0,0 +1,133 @@
+#ifndef SIMPLEBASEP_H
+#define SIMPLEBASEP_H
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #4 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+
+#include "SimpleBase.h"
+#include <Xm/DrawingAP.h>
+
+typedef void (*PrintProc) (Widget,FILE*);
+typedef void (*LayoutProc)(Widget,long*,long*);
+typedef void (*ResetProc)(Widget);
+
+
+typedef struct LinkData {
+ GC gc;
+ void* user_data;
+} LinkData;
+
+typedef struct Link {
+ int node;
+ int link_data;
+} Link;
+
+typedef struct NodeStruct {
+ XRectangle r;
+ XtPointer user_data;
+ DrawProc draw;
+ SizeProc size;
+ Boolean managed;
+ Boolean inited;
+ int pmax;
+ int pcnt;
+ int kmax;
+ int kcnt;
+ Link *parents;
+ Link *kids;
+ int tmpx;
+ int tmpy;
+ int misc[4];
+#if 0
+ Boolean is_group;
+ int group;
+#endif
+} NodeStruct;
+
+typedef struct _SimpleBaseClassPart {
+ PrintProc print;
+ LayoutProc layout;
+ ResetProc reset;
+} SimpleBaseClassPart;
+
+typedef struct _SimpleBaseClassRec {
+ CoreClassPart core_class;
+ CompositeClassPart composite_class;
+ ConstraintClassPart constraint_class;
+ XmManagerClassPart manager_class;
+ XmDrawingAreaClassPart drawing_area_class;
+ SimpleBaseClassPart simplebase_class;
+} SimpleBaseClassRec;
+
+extern SimpleBaseClassRec simplebaseClassRec;
+
+typedef struct {
+
+ int max;
+ int count;
+ NodeStruct *nodes;
+
+ LinkData *links;
+ int link_max;
+ int link_count;
+
+ Pixel blink_color;
+ GC blink_gc;
+ GC gc;
+ int selected;
+ int focus;
+ XtIntervalId timeout_id;
+ int timeout;
+ XtCallbackList getps;
+ XtCallbackList link;
+ String header;
+ XtWorkProcId work;
+
+} SimpleBasePart;
+
+
+typedef struct _SimpleBaseRec {
+ CorePart core;
+ CompositePart composite;
+ ConstraintPart constraint;
+ XmManagerPart manager;
+ XmDrawingAreaPart drawing_area;
+ SimpleBasePart simplebase;
+} SimpleBaseRec;
+
+
+#define NODE_TO_INDEX(w,n) ((n)-(w)->simplebase.nodes)
+#define INDEX_TO_NODE(w,i) (&((w)->simplebase.nodes[i]))
+
+
+#define KIDS(w,n,i) (*INDEX_TO_NODE(w,n->kids[i].node))
+#define PARENTS(w,n,i) (*INDEX_TO_NODE(w,n->parents[i].node))
+
+
+int sb_new_dummy_node(SimpleBaseWidget w);
+void sb_clear_dummy_nodes(SimpleBaseWidget w);
+int sb_insert_dummy_node(SimpleBaseWidget w,int p,int k);
+
+int sb_find_kid_index(SimpleBaseWidget w,NodeStruct* p,NodeStruct *k);
+int sb_find_parent_index(SimpleBaseWidget w,NodeStruct* k,NodeStruct *p);
+
+
+Boolean sb_is_dummy(SimpleBaseWidget w,NodeStruct*p);
+
+
+#endif
+
+
+
diff --git a/view/src/SimpleGraph.c b/view/src/SimpleGraph.c
new file mode 100644
index 0000000..1df3c72
--- /dev/null
+++ b/view/src/SimpleGraph.c
@@ -0,0 +1,1313 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #5 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/Intrinsic.h>
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/CoreP.h>
+#include <X11/CompositeP.h>
+#include <X11/ConstrainP.h>
+#include <Xm/Xm.h>
+#include <Xm/XmP.h>
+#include <Xm/DrawingAP.h>
+#include <Xm/ExtObjectP.h>
+#include "SimpleGraph.h"
+#include "SimpleGraphP.h"
+
+#ifndef MAX
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#define LEVEL 0
+#define ARC 1
+#define VISIT 2
+#define GROUP 3
+
+#define round(X) (((X) >= 0) ? (int)((X)+0.5) : (int)((X)-0.5))
+#define RADIANS(x) (M_PI * (x) / 180.0)
+#define ABS(a) ((a)>0?(a):(-(a)))
+#define C(w) (SIMPLEGRAPH_CONSTRAINT(w)->simplegraph)
+
+
+static void Initialize();
+static void Destroy();
+static Boolean SetValues();
+static void Redisplay();
+static void compute_positions(SimpleGraphWidget,int);
+static void set_positions(SimpleGraphWidget,long*,long*);
+static void Print();
+static void Layout(Widget,long*,long*);
+static void bezier_find(SimpleGraphWidget,XEvent*);
+
+static XtResource resources[] = {
+ {XtNhorizontalSpace,XtCSpace,XtRDimension,sizeof(Dimension),
+ XtOffset(SimpleGraphWidget, simplegraph.h_min_space), XtRString,"30" },
+ {XtNverticalSpace,XtCSpace, XtRDimension,sizeof (Dimension),
+ XtOffset(SimpleGraphWidget, simplegraph.v_min_space), XtRString,"10" },
+ {XtNarrowAngle,XtCArrowAngle, XtRDimension,sizeof (Dimension),
+ XtOffset(SimpleGraphWidget, simplegraph.arrow_angle), XtRString,"22" },
+ {XtNarrowLength,XtCArrowLength, XtRDimension,sizeof (Dimension),
+ XtOffset(SimpleGraphWidget, simplegraph.arrow_length), XtRString,"8" },
+ {XtNarrowFilled,XtCArrowFilled, XtRBoolean,sizeof (Boolean),
+ XtOffset(SimpleGraphWidget, simplegraph.arrow_filled), XtRString,"false" },
+ {"round","Round", XtRBoolean,sizeof (Boolean),
+ XtOffset(SimpleGraphWidget, simplegraph.mode), XtRString,"false" },
+ {XtNarcOnly,XtCArcOnly, XtRPointer,sizeof(Widget),
+ XtOffset(SimpleGraphWidget, simplegraph.arc_only), XtRPointer,NULL},
+};
+
+/*
+static XtResource simplegraphConstraintResources[] = {
+ {XtNarcNumber,XtCArcNumber, XtRint,sizeof(int),
+ XtOffset(SimpleGraphConstraints, simplegraph.misc[ARC]), XtRString,"0" },
+};
+*/
+
+SimpleGraphClassRec simplegraphClassRec = {
+ {
+ /* core_class fields */
+ (WidgetClass) &simplebaseClassRec, /* superclass */
+ "SimpleGraph", /* class_name */
+ sizeof(SimpleGraphRec), /* widget_size */
+ NULL, /* class_init */
+ NULL, /* class_part_init */
+ FALSE, /* class_inited */
+ Initialize, /* initialize */
+ NULL, /* initialize_hook */
+ XtInheritRealize, /* realize */
+ NULL, /* actions */
+ 0, /* num_actions */
+ resources, /* resources */
+ XtNumber(resources), /* num_resources */
+ NULLQUARK, /* xrm_class */
+ TRUE, /* compress_motion */
+ XtExposeCompressMaximal, /* compress_exposure */
+ TRUE, /* compress_enterleave*/
+ TRUE, /* visible_interest */
+ Destroy, /* destroy */
+ NULL, /* resize */
+ Redisplay, /* expose */
+ SetValues, /* set_values */
+ NULL, /* set_values_hook */
+ XtInheritSetValuesAlmost, /* set_values_almost */
+ NULL, /* get_values_hook */
+ NULL, /* accept_focus */
+ XtVersion, /* version */
+ NULL, /* callback_private */
+ XtInheritTranslations, /* tm_table */
+ NULL, /* query_geometry */
+ XtInheritDisplayAccelerator, /* display_accelerator*/
+ NULL, /* extension */
+ },
+ {
+ /* simplebase_class fields */
+ NULL, /* geometry_manager */
+ NULL, /* change_managed */
+ XtInheritInsertChild, /* insert_child */
+ XtInheritDeleteChild, /* delete_child */
+ NULL, /* extension */
+ },
+ {
+ /* constraint_class fields */
+ NULL, /* subresources */
+ 0, /* subresource_count */
+ 0, /* constraint_size */
+ NULL, /* initialize */
+ NULL, /* destroy */
+ NULL, /* set_values */
+ NULL, /* extension */
+ },
+ {
+ XtInheritTranslations, /* default translations */
+ NULL, /* syn_resources */
+ 0, /* num_syn_resources */
+ NULL, /* syn_cont_resources */
+ 0, /* num_syn_cont_resources */
+ XmInheritParentProcess, /* parent_process */
+ NULL, /* extension */
+
+ },
+ {
+ NULL,
+ },
+ {
+ Print,
+ Layout,
+ },
+ {
+ /* SimpleGraph class fields */
+ 0,
+ },
+};
+
+#ifdef TOP_BOTTOM
+
+#define TMPX tmpx
+#define TMPY tmpy
+#define WIDTH width
+#define HEIGHT height
+#define H_DIST h_dist
+#define V_DIST v_dist
+#define H_MIN_SPACE h_min_space
+#define V_MIN_SPACE v_min_space
+
+#else
+
+#define TMPX tmpy
+#define TMPY tmpx
+#define WIDTH height
+#define HEIGHT width
+#define H_DIST v_dist
+#define V_DIST h_dist
+#define H_MIN_SPACE v_min_space
+#define V_MIN_SPACE h_min_space
+
+#endif
+
+/* #define MANAGED(n) ((n)->managed && ((n)->group == -1)) */
+#define MANAGED(n) ((n)->managed)
+
+WidgetClass simplegraphWidgetClass = (WidgetClass) &simplegraphClassRec;
+
+static void button_click(w,cd,event,continue_dispatch)
+SimpleGraphWidget w;
+XtPointer *cd;
+XEvent *event;
+Boolean *continue_dispatch;
+{
+ bezier_find(w,event);
+}
+
+static void make_gc(SimpleGraphWidget w)
+{
+}
+
+static void delete_gc(SimpleGraphWidget w)
+{
+}
+
+static void Initialize(request, new)
+SimpleGraphWidget request, new;
+{
+ /* XGCValues values;
+ XtGCMask valueMask;
+ int i; */
+ /*
+ * Make sure the widget's width and height are
+ * greater than zero.
+ */
+ if (request->core.width <= 0)
+ new->core.width = 5;
+ if (request->core.height <= 0)
+ new->core.height = 5;
+
+ new->simplegraph.cos_arrow = cos(RADIANS(new->simplegraph.arrow_angle));
+ new->simplegraph.sin_arrow = sin(RADIANS(new->simplegraph.arrow_angle));
+
+ /*
+ * Create a simplegraphics context for the connecting lines.
+ */
+
+ make_gc(new);
+
+ /*
+ * Create the hidden root widget.
+ */
+
+ /*
+ * Allocate the tables used by the layout
+ * algorithm.
+ */
+
+ new->simplegraph.gc[0] = new->simplebase.gc;
+ new->simplegraph.gc_count = 1;
+
+ XtAddEventHandler((Widget)new,ButtonPressMask,
+ False,(XtEventHandler)button_click,(XtPointer)new);
+
+}
+
+static void Destroy(w)
+SimpleGraphWidget w;
+{
+ delete_gc(w);
+ XtRemoveEventHandler((Widget)w,ButtonPressMask,
+ False,(XtEventHandler)button_click,(XtPointer)w);
+}
+
+
+
+static Boolean SetValues(current, request, new)
+SimpleGraphWidget current, request, new;
+{
+ int redraw = TRUE;
+ long w,h;
+ /* int i;
+ int new_gc = new->core.background_pixel != current->core.background_pixel; */
+
+
+ if (new->simplegraph.arrow_angle != current->simplegraph.arrow_angle)
+ {
+ new->simplegraph.cos_arrow = cos(RADIANS(new->simplegraph.arrow_angle));
+ new->simplegraph.sin_arrow = sin(RADIANS(new->simplegraph.arrow_angle));
+ }
+
+ if (new->simplegraph.arc_only != current->simplegraph.arc_only)
+ {
+ Layout((Widget)new,&w,&h);
+ redraw = FALSE;
+ }
+
+ /*
+ * If the minimum spacing has changed, recalculate the
+ * simplegraph layout. new_layout() does a redraw, so we don't
+ * need SetValues to do another one.
+ */
+ if (new->simplegraph.v_min_space != current->simplegraph.v_min_space ||
+ new->simplegraph.h_min_space != current->simplegraph.h_min_space){
+ Layout((Widget)new,&w,&h);
+ redraw = FALSE;
+ }
+ return (redraw);
+}
+
+
+/*
+static int first_kid(SimpleGraphWidget w,NodeStruct *n)
+{
+ int i;
+ for(i=0;i<n->pcnt;i++)
+ if(MANAGED(&PARENTS(w,n,i)))
+ return i;
+ return -1;
+}
+
+static int last_kid(SimpleGraphWidget w,NodeStruct *n)
+{
+ int i;
+
+ if(n->pcnt)
+ for(i= n->pcnt - 1;i>=0;i--)
+ if(MANAGED(&PARENTS(w,n,i)))
+ return i;
+ return -1;
+ }
+
+
+static void line(SimpleGraphWidget w,int x1,int y1,int x2,int y2,int gc)
+{
+ GC topGC = w->manager.top_shadow_GC;
+ GC midGC = w->manager.background_GC;
+ GC botGC = w->manager.bottom_shadow_GC;
+ if(gc) midGC = w->simplegraph.gc[gc % GC_COUNT];
+
+ if(x1 == x2)
+ {
+ XDrawLine(XtDisplay(w),XtWindow(w),
+ topGC,x1-1,y1,x2-1,y2);
+ XDrawLine(XtDisplay(w),XtWindow(w),
+ midGC,x1,y1,x2,y2);
+ XDrawLine(XtDisplay(w),XtWindow(w),
+ botGC,x1+1,y1,x2+1,y2);
+ }
+ else
+ {
+ XDrawLine(XtDisplay(w),XtWindow(w),
+ topGC,x1,y1-1,x2,y2-1);
+ XDrawLine(XtDisplay(w),XtWindow(w),
+ midGC,x1,y1,x2,y2);
+ XDrawLine(XtDisplay(w),XtWindow(w),
+ botGC,x1,y1+1,x2,y2+1);
+ }
+}
+
+static void arrow(SimpleGraphWidget fw,int x1,int y1,int x2,int y2,int gc)
+{
+ int x;
+ int y;
+ int size = 11;
+ int h = size;
+ int w = size;
+ unsigned int d;
+
+ GC topGC = fw->manager.top_shadow_GC;
+ GC midGC = fw->manager.background_GC;
+ GC botGC = fw->manager.bottom_shadow_GC;
+ if(gc) midGC = fw->simplegraph.gc[gc % GC_COUNT];
+
+ if(x1 > x2)
+ {
+ d = XmARROW_LEFT;
+ x = (x1 + x2)/2 - size/2;
+ y = y1 - size/2;
+ }
+ else if(x1 < x2)
+ {
+ d = XmARROW_RIGHT;
+ x = (x2 + x1)/2 - size/2;
+ y = y1 - size/2;
+ }
+ else if(y2 >= y1)
+ {
+ d = XmARROW_DOWN;
+ y = (y2 + y1)/2 - size/2;
+ x = x1 - size/2;
+ }
+ else
+ {
+ d = XmARROW_UP;
+ y = (y1 + y2)/2 - size/2;
+ x = x1 - size/2;
+ }
+
+
+ _XmDrawArrow(XtDisplay(fw),XtWindow(fw),
+ topGC,
+ botGC,
+ midGC,
+ x,y,w,h,1,d);
+
+}
+
+static int minspace = 10;
+*/
+
+static void bezier_arrow(Widget w,GC gc,XPoint* p,int npoints)
+{
+#define ASIZE 4
+
+ XPoint* f;
+ XPoint* t;
+ double a,b,l;
+ int i;
+ XPoint q[3];
+
+ double xx[3] = {
+ -ASIZE, ASIZE , -ASIZE };
+ double yy[3] = {
+ ASIZE, 0 , -ASIZE };
+
+
+ int n = npoints/2;
+ int m = npoints/2+1;
+ while(n >= 0 && m < npoints)
+ {
+ f = &p[n];
+ t = &p[m];
+
+ a = t->x - f->x;
+ b = t->y - f->y;
+ l = sqrt(a*a+b*b);
+ if(l > ASIZE) break;
+
+ n--;
+ m++;
+ }
+
+
+ /* a = -a; */
+ b = -b;
+
+ for(i = 0 ; i < 3; i++)
+ {
+ double x = (a*xx[i] + b*yy[i])/l;
+ double y = (-b*xx[i] + a*yy[i])/l;
+
+ q[i].x = round(x + f->x);
+ q[i].y = round(y + f->y);
+
+ }
+
+ XFillPolygon(XtDisplay(w), XtWindow(w), gc,
+ q,3,Convex,CoordModeOrigin);
+
+}
+
+static void bezier(XPoint* p,int npoints,XPoint* control)
+{
+ int i;
+ for (i = 0; i < npoints; i++)
+ {
+ double array[4];
+ double u, u2, u3, x, y;
+ u = (double) i / (double) (npoints - 1);
+ u2 = u * u;
+ u3 = u2 * u;
+ array[0] = -u3 + 3. * u2 - 3. * u + 1.;
+ array[1] = 3. * u3 - 6. * u2 + 3. * u;
+ array[2] = -3. * u3 + 3. * u2;
+ array[3] = u3;
+ x = array[0] * control[0].x + array[1] * control[1].x + array[2] * control[2].x + array[3] * control[3].x;
+ y = array[0] * control[0].y + array[1] * control[1].y + array[2] * control[2].y + array[3] * control[3].y;
+
+ p[i].x = round(x);
+ p[i].y = round(y);
+ }
+
+}
+
+static void connect(SimpleGraphWidget w,
+XRectangle *from,XRectangle *to,
+int fn, int fc,int tn,int tc,int dm,int link_data)
+{
+
+ GC gc = w->simplebase.gc;
+
+#if TOP_BOTTOM
+ int fx = from->x + ((fn+1)*from->width)/(fc+1);
+ int fy = from->y + from->height;
+ int tx = to->x + ((tn+1)*to->width)/(tc+1);
+ int ty = to->y;
+#else
+ double fx = from->x + from->width;
+ double fy = from->y + from->height/2.0;
+ double tx = to->x ;
+ double ty = to->y + to->height / 2.0;
+#endif
+
+
+ /* .cap_style = CapRound; join_style = JoinRound; */
+
+
+ XPoint control[4];
+ XPoint p[100];
+
+ control[0].x = fx;
+ control[0].y = fy;
+
+ control[1].x = (fx + tx)/2;
+ control[1].y = fy;
+
+ control[2].x = (fx + tx)/2;
+ control[2].y = ty;
+
+ control[3].x = tx;
+ control[3].y = ty;
+
+ bezier(p,XtNumber(p),control);
+
+ if(link_data != -1)
+ {
+ int i;
+ gc = w->simplebase.links[link_data].gc;
+ for(i = 0; i < w->simplegraph.gc_count; i++)
+ if(w->simplegraph.gc[i] == gc)
+ break;
+ if(i == w->simplegraph.gc_count)
+ w->simplegraph.gc[w->simplegraph.gc_count++] = gc;
+ }
+
+ XDrawLines(XtDisplay(w),XtWindow(w),
+ gc,
+ p,XtNumber(p),CoordModeOrigin);
+
+
+ bezier_arrow((Widget)w,gc,p,XtNumber(p));
+
+}
+
+int close_to(int x,int y, int x1, int y1, int x2, int y2)
+{
+ if(x1>x2) {
+ int c = x1;
+ x1 = x2;
+ x2 = c;
+ }
+ if(y1>y2) {
+ int c = y1;
+ y1 = y2;
+ y2 = c;
+ }
+
+ x1 -= 3;
+ x2 += 3;
+ y1 -= 3;
+ y2 += 3;
+
+ return ( x1 <= x && x <= x2 && y1 <= y && y <= y2);
+}
+
+static int smallest(int x, int y,XPoint* p, int n)
+{
+ /* int i; */
+ if(n > 1 && close_to(x,y,p[0].x,p[0].y, p[n-1].x,p[n-1].y))
+ {
+ int m = n/2;
+ int a = smallest(x,y,p,m);
+ int b = smallest(x,y,p+m,n-m);
+ int z = MIN(a,b);
+ return MIN(z,n);
+ }
+ return 32000;
+}
+
+static int line_find(SimpleGraphWidget w,XEvent* event,
+XRectangle *from,XRectangle *to,
+NodeStruct* n1,NodeStruct* n2)
+{
+
+#if TOP_BOTTOM
+ int fx = from->x + ((fn+1)*from->width)/(fc+1);
+ int fy = from->y + from->height;
+ int tx = to->x + ((tn+1)*to->width)/(tc+1);
+ int ty = to->y;
+#else
+ double fx = from->x + from->width;
+ double fy = from->y + from->height/2.0;
+ double tx = to->x ;
+ double ty = to->y + to->height / 2.0;
+#endif
+
+ int x = event->xbutton.x;
+ int y = event->xbutton.y;
+ /* int i; */
+ int value = 32000;
+
+ /* .cap_style = CapRound; join_style = JoinRound; */
+
+ if( close_to(x,y,fx,fy,tx,ty))
+ {
+
+
+ XPoint control[4];
+ XPoint p[100];
+
+ control[0].x = fx;
+ control[0].y = fy;
+
+ control[1].x = (fx + tx)/2;
+ control[1].y = fy;
+
+ control[2].x = (fx + tx)/2;
+ control[2].y = ty;
+
+ control[3].x = tx;
+ control[3].y = ty;
+
+ bezier(p,XtNumber(p),control);
+
+ return smallest(x,y,p,XtNumber(p));
+ }
+
+ return value;
+
+}
+
+static void Redisplay (SimpleGraphWidget w, XEvent *event, Region region)
+{
+ int i, j;
+ /* int fkid; */
+ int m = 0;
+
+ /* XPoint points[3]; */
+ Region rg,clip;
+
+ XEvent ev;
+
+ while(XCheckWindowEvent(XtDisplay(w),XtWindow(w),ExposureMask,&ev))
+ XtAddExposureToRegion(&ev,region);
+
+ rg = XCreateRegion();
+ clip = XCreateRegion();
+
+ for (i = 0; i < w -> simplebase.count; i++)
+ {
+
+ NodeStruct *child = w -> simplebase.nodes + i;
+ if((child)->managed)
+ XUnionRectWithRegion(&child->r,rg,rg);
+ }
+ XSubtractRegion(region,rg,clip);
+
+ for(i = 0; i < w->simplegraph.gc_count; i++)
+ XSetRegion(XtDisplay(w),w->simplegraph.gc[i],clip);
+
+
+ for (i = 0; i < w -> simplebase.count; i++)
+ {
+
+ NodeStruct *n = w -> simplebase.nodes + i;
+ if(!n->managed)
+ continue;
+
+ for (j = 0; j < n->kcnt; j++)
+ {
+ NodeStruct *c = &KIDS(w,n,j);
+ int k = 0;
+
+ if(!c->managed)
+ continue;
+
+ connect(w,&n->r,&c->r,
+ j,n->kcnt,
+ k,c->pcnt,
+ m++,
+ n->kids[j].link_data
+ );
+
+ }
+ }
+
+ XDestroyRegion(clip);
+ XDestroyRegion(rg);
+ for(i = 0; i < w->simplegraph.gc_count; i++)
+ XSetClipMask(XtDisplay(w),w->simplegraph.gc[i],None);
+
+ NodesRedraw((SimpleBaseWidget)w,event,region);
+}
+
+static void bezier_find(SimpleGraphWidget w,XEvent *event)
+{
+ int i, j;
+ /* int fkid; */
+ int m = 0;
+ int min = 32000;
+ NodeStruct* m1 = 0 ;
+ NodeStruct *m2 = 0;
+ LinkCallbackStruct cb;
+
+ for (i = 0; i < w -> simplebase.count; i++)
+ {
+ NodeStruct *n = w -> simplebase.nodes + i;
+ if(!n->managed)
+ continue;
+
+ for (j = 0; j < n->kcnt; j++)
+ {
+ NodeStruct *c = &KIDS(w,n,j);
+ if(!c->managed)
+ continue;
+
+ m = line_find(w,event,&n->r,&c->r,n,c);
+ if(m < min)
+ {
+ min = m;
+ m1 = n;
+ m2 = c;
+
+ }
+ }
+ }
+
+ while(m1 && sb_is_dummy((SimpleBaseWidget)w,m1))
+ m1 = &PARENTS(w,m1,0);
+
+ while(m2 && sb_is_dummy((SimpleBaseWidget)w,m2))
+ m2 = &KIDS(w,m2,0);
+
+ cb.reason = 0;
+ cb.event = event;
+ cb.data1 = m1?m1->user_data:0;
+ cb.data2 = m1?m2->user_data:0;
+ XtCallCallbacks((Widget)w, XtNlinkCallback, (XtPointer)&cb);
+}
+
+static void Layout(Widget w,long *maxWidth,long *maxHeight)
+{
+ SimpleGraphWidget gw = (SimpleGraphWidget)w;
+ /* XtGeometryResult result; */
+ /* Dimension replyWidth = 0, replyHeight = 0; */
+ *maxWidth = 1;
+ *maxHeight = 1;
+ sb_clear_dummy_nodes((SimpleBaseWidget)gw);
+ compute_positions(gw,1);
+ set_positions(gw, maxWidth,maxHeight);
+}
+
+
+static int calc_level(SimpleGraphWidget w,NodeStruct *n)
+{
+
+ int i;
+ int lvl = 0;
+
+ if(n->misc[VISIT]) return -1;
+
+ n->misc[VISIT] = True;
+
+ for(i=0;i<n->pcnt;i++)
+ {
+ NodeStruct *p = &PARENTS(w,n,i);
+ if(MANAGED(p))
+ {
+ int lev = calc_level(w,p) + 1;
+ lvl = MAX(lvl,lev);
+ }
+ }
+
+ n->misc[LEVEL] = lvl;
+ n->misc[VISIT] = False;
+
+ return lvl;
+
+}
+
+static void set_arc(SimpleGraphWidget w,NodeStruct *n,int arc)
+{
+
+ int i;
+
+ if(n->misc[VISIT]) return;
+ n->misc[VISIT] = True;
+
+ n->misc[ARC] = arc;
+
+ for(i=0;i<n->pcnt;i++)
+ {
+ NodeStruct *p = &PARENTS(w,n,i);
+ if(MANAGED(p))
+ set_arc(w,p,arc);
+ }
+
+ n->misc[VISIT] = False;
+
+}
+
+static int calc_arc(SimpleGraphWidget w,NodeStruct *n)
+{
+
+ int i;
+ int a = n->misc[ARC];
+
+ if(n->misc[VISIT]) return 0;
+ n->misc[VISIT] = True;
+
+ if(n->pcnt)
+ {
+ for(i=0;i<n->pcnt;i++)
+ {
+ NodeStruct *p = &PARENTS(w,n,i);
+ if(MANAGED(p))
+ {
+ int b = calc_arc(w,p);
+ a = MAX(a,b);
+ }
+ }
+ set_arc(w,n,a);
+ }
+
+ n->misc[VISIT] = False;
+ return a;
+}
+
+static SimpleGraphWidget sort;
+
+static int by_arc(const void* n1,const void* n2)
+{
+ NodeStruct *w1 = sort->simplebase.nodes + *(int*)n1;
+ NodeStruct *w2 = sort->simplebase.nodes + *(int*)n2;
+ if(w1->misc[LEVEL] != w2->misc[LEVEL])
+ return w1->misc[LEVEL] - w2->misc[LEVEL];
+
+ return w1->misc[ARC] - w2->misc[ARC];
+
+}
+
+static int by_x(const void *n1,const void *n2)
+{
+ NodeStruct *w1 = sort->simplebase.nodes + *(int*)n1;
+ NodeStruct *w2 = sort->simplebase.nodes + *(int*)n2;
+
+ if(w1->misc[LEVEL] != w2->misc[LEVEL])
+ return w1->misc[LEVEL] - w2->misc[LEVEL];
+
+ return w1->TMPX - w2->TMPX;
+
+}
+
+
+static int by_level(const void *n1,const void *n2)
+{
+ NodeStruct *w1 = sort->simplebase.nodes + *(int*)n1;
+ NodeStruct *w2 = sort->simplebase.nodes + *(int*)n2;
+
+ return w1->misc[LEVEL] - w2->misc[LEVEL];
+
+}
+
+
+static int no_parents(SimpleGraphWidget w,NodeStruct *n)
+{
+ int i;
+
+ for(i=0;i<n->pcnt;i++) {
+ NodeStruct *p = &PARENTS(w,n,i);
+ if(MANAGED(p)) return FALSE;
+ }
+
+ return TRUE;
+
+}
+
+static int no_kidss(SimpleGraphWidget w,NodeStruct *n)
+{
+ int i;
+ for(i=0;i<n->kcnt;i++) {
+ NodeStruct *p = &KIDS(w,n,i);
+ if(MANAGED(p)) return FALSE;
+ }
+
+ return TRUE;
+
+}
+
+
+static void calc_level_pass2(SimpleGraphWidget w,NodeStruct *n)
+{
+ int i;
+ int lvl1 = 12000;
+
+ for(i=0;i<n->kcnt;i++)
+ {
+ NodeStruct *p = &KIDS(w,n,i);
+ if(MANAGED(p))
+ lvl1 = MIN(lvl1,p->misc[LEVEL]);
+ }
+ n->misc[LEVEL] = lvl1-1;
+}
+
+static void calc_y(SimpleGraphWidget gw,int *nodes,int *levels,
+int *positions,
+int max_in_a_level,int no_levels,int num_nodes,int v_dist)
+{
+ int i;
+ int max = max_in_a_level * v_dist;
+
+ for(i=0;i<no_levels;i++)
+ positions[i] = ((max / levels[i])-
+ (max / max_in_a_level))/2;
+
+ for(i=0;i<num_nodes;i++)
+ {
+ NodeStruct *n = gw->simplebase.nodes + nodes[i];
+ n->TMPX = positions[n->misc[LEVEL]];
+ positions[n->misc[LEVEL]] += (max / levels[n->misc[LEVEL]]);
+ }
+
+}
+
+static int add_node(SimpleGraphWidget w,int n,int m,int lvl)
+{
+ int x = sb_insert_dummy_node((SimpleBaseWidget)w,n,m);
+ INDEX_TO_NODE(w,x)->misc[LEVEL] = lvl;
+ return x;
+}
+
+static int add_dummies(SimpleGraphWidget w,NodeStruct *n)
+{
+ int i;
+ int more = 0;
+ int lvl = n->misc[LEVEL];
+
+ if(n->misc[VISIT]) return 0;
+ n->misc[VISIT] = True;
+
+ for(i=0;i<n->kcnt;i++)
+ {
+ NodeStruct *p = &KIDS(w,n,i);
+
+ if(MANAGED(p))
+ {
+ int klvl = p->misc[LEVEL];
+ int d = klvl - lvl;
+ int l = lvl;
+ int a = NODE_TO_INDEX(w,n);
+ int b = NODE_TO_INDEX(w,p);
+
+ int x = NODE_TO_INDEX(w,p);
+ int y = NODE_TO_INDEX(w,n);
+
+ while(d-- > 1)
+ {
+ a = add_node(w,a,b,++l);
+ more = 1;
+ }
+
+ /* note: creating dummnies may change pointers*/
+ p = INDEX_TO_NODE(w,x);
+ n = INDEX_TO_NODE(w,y);
+
+ }
+
+
+ more = add_dummies(w,p) || more;
+ }
+ n->misc[VISIT] = False;
+ return more;
+
+}
+
+static int add_dummy_nodes(SimpleGraphWidget gw)
+{
+ int i;
+ int n = gw->simplebase.count;
+ int more = 0;
+
+ for(i=0; i < n; i++)
+ {
+ NodeStruct *w = gw->simplebase.nodes + i;
+ if(MANAGED(w))
+ more = add_dummies(gw,w) || more;
+ }
+
+ return more;
+}
+
+static void compute_positions(SimpleGraphWidget gw,int dummy)
+{
+ int i;
+ int n = gw->simplebase.count;
+ int *levels;
+ int *positions;
+ int count;
+ int max_in_a_level = 0;
+ int max_level = 0;
+ int arc=0;
+ int minx,miny;
+
+ int no_levels = 0;
+ int num_nodes = 0;
+ int *nodes;
+ int *widths;
+ int *heights;
+ int *kids;
+ int a;
+ int move_it;
+ int more;
+ int v_dist = 10;
+ int h_dist = 10;
+ int chg = TRUE;
+ NodeStruct* focus = (gw->simplebase.focus>=0)? (gw->simplebase.nodes +
+ gw->simplebase.focus) : 0;
+
+ sort = gw;
+
+
+ num_nodes = 0;
+ for(i=0;i<n;i++)
+ {
+ NodeStruct *w = gw->simplebase.nodes + i;
+ if(MANAGED(w)) num_nodes++;
+ w->misc[LEVEL] = w->misc[ARC] = -1;
+ w->misc[VISIT] = False;
+ }
+
+ if(!num_nodes) return;
+
+ if(focus == 0) focus = gw->simplebase.nodes;
+
+
+ levels = (int*)XtCalloc(num_nodes,sizeof(int));
+ positions = (int*)XtCalloc(num_nodes,sizeof(int));
+ nodes = (int*)XtCalloc(num_nodes,sizeof(int));
+ widths = (int*)XtCalloc(num_nodes,sizeof(int));
+ heights = (int*)XtCalloc(num_nodes,sizeof(int));
+ kids = (int*)XtCalloc(num_nodes,sizeof(int));
+
+ num_nodes=0;
+ for(i=0;i<n;i++)
+ {
+ NodeStruct *w = gw->simplebase.nodes + i;
+ if(MANAGED(w)) nodes[num_nodes++] = i;
+ w->misc[LEVEL] = 0;
+ }
+ arc = 1;
+
+ for(i=0;i<num_nodes;i++)
+ {
+ NodeStruct *w = gw->simplebase.nodes + nodes[i];
+ calc_level(gw,w);
+ w->misc[ARC] = arc++;
+
+ H_DIST = MAX(H_DIST,w->r.WIDTH);
+ V_DIST = MAX(V_DIST,w->r.HEIGHT);
+ }
+
+ H_DIST += gw->simplegraph.H_MIN_SPACE;
+ V_DIST += gw->simplegraph.V_MIN_SPACE;
+
+ for(i=0;i<num_nodes;i++)
+ {
+ NodeStruct *w = gw->simplebase.nodes + nodes[i];
+ if (no_parents(gw,w) && !no_kidss(gw,w))
+ calc_level_pass2(gw,w);
+ }
+
+#if 1
+ if(dummy && add_dummy_nodes(gw))
+ {
+ XtFree((XtPointer)levels);
+ XtFree((XtPointer)positions);
+ XtFree((XtPointer)nodes);
+ XtFree((XtPointer)widths);
+ XtFree((XtPointer)heights);
+ XtFree((XtPointer)kids);
+ compute_positions(gw,0);
+ return;
+ }
+#endif
+
+ qsort(nodes,num_nodes,sizeof(int),by_level);
+
+ for(i=0;i<num_nodes;i++)
+ {
+ NodeStruct *w = gw->simplebase.nodes + nodes[i];
+ levels[w->misc[LEVEL]]++;
+
+ if(levels[w->misc[LEVEL]] > max_in_a_level)
+ {
+ max_in_a_level = levels[w->misc[LEVEL]];
+ max_level = w->misc[LEVEL];
+ }
+
+ no_levels = MAX(no_levels,w->misc[LEVEL]);
+
+ widths[w->misc[LEVEL]] = MAX(widths[w->misc[LEVEL]],w->r.WIDTH);
+ heights[w->misc[LEVEL]] = MAX(heights[w->misc[LEVEL]],w->r.HEIGHT);
+ kids[w->misc[LEVEL]] = MAX(kids[w->misc[LEVEL]],w->kcnt);
+
+ }
+ no_levels++;
+
+
+ a = 0;
+ for( i = 0 ;i<no_levels;i++)
+ {
+ int b = heights[i] + gw->simplegraph.V_MIN_SPACE;
+
+
+ b += kids[i] * 2 ; /* +5 pixels per node with max kids in level */
+ /* printf("level %d = %d %d\n",i,a,heights[i]); */
+ heights[i] = a;
+ a += b;
+ widths[i] += gw->simplegraph.H_MIN_SPACE;
+ /* printf("level %d = %d\n",i,a); */
+ }
+
+ for(i=0;i<num_nodes;i++)
+ {
+ NodeStruct *w = gw->simplebase.nodes + nodes[i];
+ w->TMPY = heights[w->misc[LEVEL]];
+ /* printf("node y = %d %d\n",w->misc[LEVEL],w->TMPY); */
+ }
+
+
+ for(a=0;a<2;a++)
+ {
+ for(i=0;i<num_nodes;i++) {
+ NodeStruct *w = gw->simplebase.nodes + nodes[i];
+ if(no_kidss(gw,w)) calc_arc(gw,w);
+ }
+ for(i=0;i<num_nodes;i++){
+ NodeStruct *w = gw->simplebase.nodes + nodes[i];
+ if(no_kidss(gw,w)) set_arc(gw,w,w->misc[ARC]);
+ }
+ }
+
+
+ qsort(nodes,num_nodes,sizeof(int),by_arc);
+
+ for(a=0;a<no_levels;a++)
+ if(levels[a]==0) levels[a]=1;
+
+
+ calc_y(gw,nodes,levels,positions,max_in_a_level,no_levels,num_nodes,H_DIST);
+
+ move_it = 0;
+
+ more = 1;
+ qsort(nodes,num_nodes,sizeof(int),by_x);
+ while(more--)
+ {
+
+ count = num_nodes;
+ while(count--)
+ {
+ for(i=0;i<num_nodes;i++)
+ {
+ int j;
+ int n = 0;
+ int x = 0;
+ NodeStruct *w = gw->simplebase.nodes + nodes[i];
+ if( (max_level != w->misc[LEVEL]) ^ move_it)
+ {
+
+
+ for(j=0;j<w->pcnt;j++)
+ {
+ NodeStruct *p = &PARENTS(gw,w,j);
+ if(MANAGED(p) && p != focus)
+ {
+ x += p->TMPX;
+ n++;
+ }
+ }
+
+
+ for(j=0;j<w->kcnt;j++)
+ {
+ NodeStruct *p = &KIDS(gw,w,j);
+ if(MANAGED(p) && p != focus)
+ {
+ x += p->TMPX;
+ n++;
+ }
+ }
+ w->TMPX = n?x/n:x;
+ }
+ }
+
+
+
+ qsort(nodes,num_nodes,sizeof(int),by_x);
+ move_it = !move_it;
+
+ chg = TRUE;
+ a = 10000;
+ while(chg && a--)
+ {
+ chg = FALSE;
+ for(i=1;i<num_nodes;i++) {
+ NodeStruct *w = gw->simplebase.nodes + nodes[i];
+ NodeStruct *z = gw->simplebase.nodes + nodes[i-1];
+ if(z->misc[LEVEL] == w->misc[LEVEL])
+ if(w->TMPX-z->TMPX< widths[w->misc[LEVEL]])
+ {
+ if(z != focus)
+ z->TMPX -= widths[w->misc[LEVEL]]/2;
+ if(w != focus)
+ w->TMPX += widths[w->misc[LEVEL]]/2;
+ chg = TRUE;
+ }
+ }
+ }
+ }
+ }
+
+
+ miny = (gw->simplebase.nodes + nodes[0])->tmpy;
+ minx = (gw->simplebase.nodes + nodes[0])->tmpx;
+
+ for(i=1;i<num_nodes;i++)
+ {
+ NodeStruct *w = gw->simplebase.nodes + nodes[i];
+ if(w->tmpx<minx) minx = w->tmpx;
+ if(w->tmpy<miny) miny = w->tmpy;
+ }
+
+ minx -= 20;
+ miny -= 20;
+
+ for(i=0;i<num_nodes;i++)
+ {
+ NodeStruct *w = gw->simplebase.nodes + nodes[i];
+ w->tmpx -= minx;
+ w->tmpy -= miny;
+ }
+
+
+ XtFree((XtPointer)levels);
+ XtFree((XtPointer)positions);
+ XtFree((XtPointer)nodes);
+ XtFree((XtPointer)widths);
+ XtFree((XtPointer)heights);
+ XtFree((XtPointer)kids);
+
+
+}
+
+
+
+static SimpleGraphWidget sort_widget = 0;
+
+static int left_to_right(const void *a,const void *b)
+{
+ NodeStruct *na = sort_widget->simplebase.nodes + ((Link*)a)->node;
+ NodeStruct *nb = sort_widget->simplebase.nodes + ((Link*)b)->node;
+ return na->r.x - nb->r.x;
+}
+
+
+static void set_positions(SimpleGraphWidget gw, long *maxWidth,long *maxHeight)
+{
+ int i;
+
+ for(i=0;i<gw->simplebase.count;i++)
+ {
+ NodeStruct *w = gw->simplebase.nodes + i;
+ if(w->managed )
+ {
+ {
+ w->r.x = w->tmpx;
+ w->r.y = w->tmpy;
+ *maxWidth = MAX(*maxWidth,w->tmpx + w->r.width + gw->simplegraph.h_min_space);
+ *maxHeight = MAX(*maxHeight,w->tmpy + w->r.height + gw->simplegraph.v_min_space);
+#if 0
+ if(w->is_group)
+ {
+ int j;
+ int x = w->r.x;
+ int y = w->tmpy;
+ for(j=0;j<gw->simplebase.count;j++)
+ {
+ NodeStruct *v = gw->simplebase.nodes + j;
+ if(v->managed && v->group == i)
+ {
+ v->r.x = x;
+ v->r.y = y;
+ y += v->r.height;
+ }
+ }
+ }
+#endif
+ }
+ }
+}
+
+sort_widget = gw;
+for(i=0;i<gw->simplebase.count;i++)
+{
+ NodeStruct *w = gw->simplebase.nodes + i;
+ qsort(w->parents,w->pcnt,sizeof(Link),left_to_right);
+ qsort(w->kids,w->kcnt,sizeof(Link),left_to_right);
+}
+}
+
+Widget CreateGraph(par,nam,al,ac)
+Widget par;
+char *nam;
+ArgList al;
+int ac;
+
+{
+ return XtCreateWidget(nam,simplegraphWidgetClass,par,al,ac);
+}
+
+static void Print (SimpleGraphWidget w, FILE *f)
+{
+}
+
diff --git a/view/src/SimpleGraph.h b/view/src/SimpleGraph.h
new file mode 100644
index 0000000..9f5a97f
--- /dev/null
+++ b/view/src/SimpleGraph.h
@@ -0,0 +1,42 @@
+#ifndef SIMPLEGRAPH_H
+#define SIMPLEGRAPH_H
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #4 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "SimpleBase.h"
+
+extern WidgetClass simplegraphWidgetClass;
+
+typedef struct _SimpleGraphClassRec *SimpleGraphWidgetClass;
+typedef struct _SimpleGraphRec *SimpleGraphWidget;
+
+#define XtNhorizontalSpace "horizontalSpace"
+#define XtNverticalSpace "verticalSpace"
+#define XtCPad "Pad"
+
+#define XtNarcOnly "arcOnly"
+#define XtCArcOnly "ArcOnly"
+
+#define XtNarrowAngle "arrowAngle"
+#define XtNarrowFilled "arrowFilled"
+#define XtNarrowLength "arrowLength"
+#define XtCArrowAngle "ArrowAngle"
+#define XtCArrowFilled "ArrowFilled"
+#define XtCArrowLength "ArrowLength"
+
+Widget CreateGraph(Widget,char*, Arg*,int);
+
+
+#endif /* SIMPLEGRAPH_H */
diff --git a/view/src/SimpleGraphP.h b/view/src/SimpleGraphP.h
new file mode 100644
index 0000000..1fe152a
--- /dev/null
+++ b/view/src/SimpleGraphP.h
@@ -0,0 +1,72 @@
+#ifndef SIMPLEGRAPHP_H
+#define SIMPLEGRAPHP_H
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #4 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+
+
+#include <Xm/XmP.h>
+#include <Xm/DrawingAP.h>
+#include "SimpleBaseP.h"
+
+#define GC_COUNT 10
+
+typedef struct _SimpleGraphClassPart {
+ int ignore;
+} SimpleGraphClassPart;
+
+typedef struct _SimpleGraphClassRec {
+ CoreClassPart core_class;
+ CompositeClassPart composite_class;
+ ConstraintClassPart constraint_class;
+ XmManagerClassPart manager_class;
+ XmDrawingAreaClassPart drawing_area_class;
+ SimpleBaseClassPart simplebase_part;
+ SimpleGraphClassPart simplegraph_class;
+} SimpleGraphClassRec;
+
+extern SimpleGraphClassRec simplegraphClassRec;
+
+
+typedef struct {
+ Dimension h_min_space;
+ Dimension v_min_space;
+ Dimension arrow_length;
+ Dimension arrow_angle;
+ Boolean arrow_filled;
+ int gc_count;
+ GC gc[GC_COUNT];
+ float cos_arrow;
+ float sin_arrow;
+ Boolean mode;
+ Widget arc_only;
+} SimpleGraphPart;
+
+
+typedef struct _SimpleGraphRec {
+ CorePart core;
+ CompositePart composite;
+ ConstraintPart constraint;
+ XmManagerPart manager;
+ XmDrawingAreaPart drawing_area;
+ SimpleBasePart simplebase;
+ SimpleGraphPart simplegraph;
+} SimpleGraphRec;
+
+
+#endif
+
+
+
diff --git a/view/src/SimpleTime.c b/view/src/SimpleTime.c
new file mode 100644
index 0000000..51047b8
--- /dev/null
+++ b/view/src/SimpleTime.c
@@ -0,0 +1,767 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #4 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include <stdio.h>
+#include <time.h>
+#include <Xm/ScrollBar.h>
+
+#include <X11/Intrinsic.h>
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/CoreP.h>
+#include <X11/CompositeP.h>
+#include <X11/ConstrainP.h>
+#include <Xm/XmP.h>
+#include <Xm/DrawingAP.h>
+#include <Xm/ExtObjectP.h>
+#include "SimpleTime.h"
+#include "SimpleTimeP.h"
+
+#ifndef MAX
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#define DATE 0
+#define TIME 1
+#define ARC 2
+
+static void Initialize();
+static void Print();
+static void Layout(Widget,long*,long*);
+static void Destroy();
+static Boolean SetValues();
+static void Redisplay();
+
+void SimpleBaseShow(Widget _w,XRectangle* r,XEvent* ev);
+
+
+static XtResource resources[] = {
+ {XtNverticalSpace,XtCSpace, XtRDimension,sizeof (Dimension),
+ XtOffset(SimpleTimeWidget, simpletime.v_min_space), XtRImmediate,(XtPointer)8 },
+ {XtNpixelSecond,XtCPixelSecond, XtRInt,sizeof (int),
+ XtOffset(SimpleTimeWidget, simpletime.second_per_pixel), XtRImmediate,(XtPointer)60 },
+ {XtNforeground, XtCForeground, XtRPixel, sizeof (Pixel),
+ XtOffset(SimpleTimeWidget, simpletime.foreground), XtRString,"Red"},
+ {XtNautoScroll, XtCAutoScroll, XtRBoolean, sizeof (Boolean),
+ XtOffset(SimpleTimeWidget, simpletime.auto_scroll), XtRImmediate,(XtPointer)TRUE},
+
+ { XmNfontList, XmCFontList, XmRFontList, sizeof (XmFontList),
+ XtOffset (SimpleTimeWidget, simpletime.font), XmRString,
+ "-*-*-*-*-*-*-7-*-*-*-*-*-*-*"},
+
+
+
+};
+
+
+SimpleTimeClassRec simpletimeClassRec = {
+ {
+ /* core_class fields */
+ (WidgetClass) &simplebaseClassRec,/* superclass */
+ "SimpleTime", /* class_name */
+ sizeof(SimpleTimeRec), /* widget_size */
+ NULL, /* class_init */
+ NULL, /* class_part_init */
+ FALSE, /* class_inited */
+ Initialize, /* initialize */
+ NULL, /* initialize_hook */
+ XtInheritRealize, /* realize */
+ NULL, /* actions */
+ 0, /* num_actions */
+ resources, /* resources */
+ XtNumber(resources), /* num_resources */
+ NULLQUARK, /* xrm_class */
+ TRUE, /* compress_motion */
+ XtExposeCompressMaximal, /* compress_exposure */
+ TRUE, /* compress_enterleave*/
+ TRUE, /* visible_interest */
+ Destroy, /* destroy */
+ NULL, /* resize */
+ Redisplay, /* expose */
+ SetValues, /* set_values */
+ NULL, /* set_values_hook */
+ XtInheritSetValuesAlmost, /* set_values_almost */
+ NULL, /* get_values_hook */
+ NULL, /* accept_focus */
+ XtVersion, /* version */
+ NULL, /* callback_private */
+ XtInheritTranslations, /* tm_table */
+ NULL, /* query_geometry */
+ XtInheritDisplayAccelerator, /* display_accelerator*/
+ NULL, /* extension */
+ },
+ {
+ /* simplebase_class fields */
+ NULL, /* geometry_manager */
+ NULL, /* change_managed */
+ XtInheritInsertChild, /* insert_child */
+ XtInheritDeleteChild, /* delete_child */
+ NULL/*&compext*/, /* extension */
+ },
+ {
+ /* constraint_class fields */
+ NULL, /* subresources */
+ 0,/* subresource_count */
+ 0, /* constraint_size */
+ NULL, /* initialize */
+ NULL, /* destroy */
+ NULL, /* set_values */
+ NULL, /* extension */
+ },
+ {
+ XtInheritTranslations, /* default translations */
+ NULL, /* syn_resources */
+ 0, /* num_syn_resources */
+ NULL, /* syn_cont_resources */
+ 0, /* num_syn_cont_resources */
+ XmInheritParentProcess, /* parent_process */
+ NULL, /* extension */
+
+ },
+ {
+ NULL,
+ },
+ {
+ Print,
+ Layout,
+ },
+ {
+ /* SimpleTime class fields */
+ 0, /* ignore */
+ },
+};
+
+
+WidgetClass simpletimeWidgetClass = (WidgetClass) &simpletimeClassRec;
+
+static long time_to_sec(long ddate)
+{
+ long hh,mm,ss;
+ hh = ddate / 10000; ddate %= 10000;
+ mm = ddate / 100; ddate %= 100;
+ ss = ddate;
+ return hh*60*60 + mm * 60 + ss;
+}
+
+static long sec_to_time(long ddate)
+{
+ long hh,mm,ss;
+ hh = ddate / (60*60); ddate %= (60*60);
+ mm = ddate / 60; ddate %= 60;
+ ss = ddate;
+ return hh*10000 + mm * 100 + ss;
+}
+
+static long date_to_julian(long ddate)
+{
+ long m1,y1,a,b,c,d,j1;
+
+ long month,day,year;
+
+ year = ddate / 10000;
+ ddate %= 10000;
+ month = ddate / 100;
+ ddate %= 100;
+ day = ddate;
+
+ if (month > 2)
+ {
+ m1 = month - 3;
+ y1 = year;
+ }
+ else
+ {
+ m1 = month + 9;
+ y1 = year - 1;
+ }
+ a = 146097*(y1/100)/4;
+ d = y1 % 100;
+ b = 1461*d/4;
+ c = (153*m1+2)/5+day+1721119;
+ j1 = a+b+c;
+
+ return(j1);
+}
+
+static long julian_to_date(long jdate)
+{
+ long x,y,d,m,e;
+ long day,month,year;
+
+ x = 4 * jdate - 6884477;
+ y = (x / 146097) * 100;
+ e = x % 146097;
+ d = e / 4;
+
+ x = 4 * d + 3;
+ y = (x / 1461) + y;
+ e = x % 1461;
+ d = e / 4 + 1;
+
+ x = 5 * d - 3;
+ m = x / 153 + 1;
+ e = x % 153;
+ d = e / 5 + 1;
+
+ if( m < 11 )
+ month = m + 2;
+ else
+ month = m - 10;
+
+
+ day = d;
+ year = y + m / 11;
+
+ return year * 10000 + month * 100 + day;
+}
+
+static int x_of(SimpleTimeWidget w,int d,int t)
+{
+ double s;
+ d = d - w->simpletime.start_date;
+ t = t - w->simpletime.start_time;
+ s = d * 24.0*60*60 + t;
+ return s / w->simpletime.second_per_pixel + 10 + w->simpletime.max_w;
+}
+
+static void time_of(SimpleTimeWidget w,int x,int* d,int* t)
+{
+ double s = (x - 10 - w->simpletime.max_w) * w->simpletime.second_per_pixel;
+ *d = (s / 24.0/60/60);
+ *t = ( s - *d * 24.0*60*60);
+ *d = *d + w->simpletime.start_date;
+ *t = *t + w->simpletime.start_time;
+}
+
+static void time_out(SimpleTimeWidget w,XtIntervalId id)
+{
+ if(XtIsRealized((Widget)w) && XtIsManaged((Widget)w))
+ {
+#if 0
+ int n = X(w,w->simpletime.second);
+ XClearArea(XtDisplay(w),XtWindow(w),
+ n,0,1,w->core.height,TRUE);
+#endif
+ }
+
+ /* w->simpletime.second = tt->tm_min+tt->tm_hour*60; */
+ /* w->simpletime.second = tt->tm_min+tt->tm_hour*60; */
+
+ w->simpletime.timeout_id =
+ XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)w),
+ 60000,
+ (XtTimerCallbackProc)time_out,(XtPointer)w);
+
+ /* if(w->simpletime.auto_scroll) TimeShowTime((Widget)w,TIME_NOW); */
+}
+
+
+static void Initialize(SimpleTimeWidget request, SimpleTimeWidget new)
+{
+ XGCValues values;
+ XtGCMask valueMask;
+
+ if (request->core.width <= 0)
+ new->core.width = 5;
+ if (request->core.height <= 0)
+ new->core.height = 5;
+
+ valueMask = GCForeground | GCBackground;
+ values.foreground = new->simpletime.foreground;
+ values.background = new->core.background_pixel;
+ new->simpletime.gc = XtGetGC((Widget)new, valueMask, &values);
+ new->simpletime.start_time = new->simpletime.end_time = 0;
+ new->simpletime.start_date = new->simpletime.end_date = 0;
+ new->simpletime.inited = 0;
+ new->simpletime.arcs = 0;
+
+ time_out(new,0);
+
+}
+
+static void Destroy(SimpleTimeWidget w)
+{
+ XtReleaseGC((Widget)w, w->simpletime.gc);
+ XtRemoveTimeOut(w->simpletime.timeout_id);
+}
+
+
+static Boolean SetValues(SimpleTimeWidget current,SimpleTimeWidget request,
+ SimpleTimeWidget new)
+{
+ int redraw = FALSE;
+
+ /*
+ * If the minimum spacing has changed, recalculate the
+ * simpletime layout. new_layout() does a redraw, so we don't
+ * need SetValues to do another one.
+ */
+
+ if (new->simpletime.v_min_space != current->simpletime.v_min_space ||
+ new->simpletime.second_per_pixel != current->simpletime.second_per_pixel )
+ {
+ long width,height;
+ Layout((Widget)new,&width,&height);
+ if(width != new->core.width || height != new->core.height)
+ {
+ Dimension replyWidth = 0, replyHeight = 0;
+
+ XtGeometryResult result = XtMakeResizeRequest((Widget)new,
+ width,height,
+ &replyWidth, &replyHeight);
+
+ if (result == XtGeometryAlmost)
+ XtMakeResizeRequest ((Widget)new, replyWidth, replyHeight,
+ NULL, NULL);
+ }
+ redraw = True;
+ }
+ return (redraw);
+}
+
+
+static void line_in(SimpleTimeWidget w,int x1,int y1,int x2,int y2)
+{
+ XDrawLine(XtDisplay(w), XtWindow(w), w->manager.bottom_shadow_GC,
+ x1,y1,x2,y2);
+ XDrawLine(XtDisplay(w), XtWindow(w), w->manager.top_shadow_GC,
+ x1+1,y1+1,x2+1,y2+1);
+}
+
+/*static void line_out(SimpleTimeWidget w,int x1,int y1,int x2,int y2)
+{
+ XDrawLine(XtDisplay(w), XtWindow(w), w->simpletime.gc,
+ x1,y1,x2,y2);
+ } */
+
+static void Redisplay (SimpleTimeWidget w, XEvent *event, Region region)
+{
+ int i;
+ int n;
+ int y;
+ XEvent ev;
+ /* int max = 0; */
+
+ int d,t;
+ int date = 0;
+
+ /*
+ * If the SimpleTime widget is visible, visit each managed child.
+ */
+
+ while(XCheckWindowEvent(XtDisplay(w),XtWindow(w),ExposureMask,&ev))
+ XtAddExposureToRegion(&ev,region);
+
+ d = w->simpletime.start_date;
+ t = w->simpletime.start_time;
+
+ t /= 60*60;
+ t *= 60*60;
+
+ while( d <= w->simpletime.end_date )
+ {
+ int width;
+ n = x_of(w,d,t);
+
+ if(n >= w->simpletime.max_w) {
+ int hh = sec_to_time(t) / 10000;
+ XmString s,z,sdat,stim,sep;
+ char dat[80];
+ char tim[80];
+
+ line_in(w,n,w->simpletime.title,n,w->core.height);
+
+ dat[0] = tim[0] = 0;
+
+ if(date == 0 || d != date)
+ {
+ int yy,mm,dd;
+ int x = julian_to_date(d);
+ yy = x / 10000; x %= 10000;
+ mm = x / 100; x %= 100;
+ dd = x;
+
+ sprintf(dat,"%d-%02d-%02d",yy,mm,dd);
+ }
+
+ sprintf(tim,"%02dh",hh);
+
+ sdat = XmStringCreateSimple(dat);
+ stim = XmStringCreateSimple(tim);
+ sep = XmStringSeparatorCreate();
+
+ z = XmStringConcat(sdat,sep);
+ s = XmStringConcat(z,stim);
+
+ date = d;
+ width = XmStringWidth(w->simpletime.font,s);
+
+ XmStringDraw(XtDisplay(w),XtWindow(w),
+ w->simpletime.font,
+ s,
+ w->manager.bottom_shadow_GC,
+ n - width / 2,
+ 5,
+ width,
+ XmALIGNMENT_CENTER,
+ XmSTRING_DIRECTION_L_TO_R, 0);
+
+ XmStringFree(s);
+ XmStringFree(z);
+ XmStringFree(sdat);
+ XmStringFree(stim);
+ XmStringFree(sep);
+ }
+
+ t += 60*60;
+ if(t >= 24*60*60)
+ {
+ d++;
+ t -= 24*60*60;
+ }
+
+ if( d == w->simpletime.end_date && t > w->simpletime.end_time)
+ break;
+ }
+
+ for (i = 0; i < w -> simplebase.count; i++)
+ {
+
+ NodeStruct *n = w -> simplebase.nodes + i;
+ int j;
+ if(!n->managed)
+ continue;
+
+ for (j = 0; j < n->kcnt; j++)
+ {
+ NodeStruct *c = &KIDS(w,n,j);
+
+ if(!c->managed)
+ continue;
+
+#if 0
+ if(n->kids[j].link_data != -1)
+ {
+ GC gc = w->simplebase.links[n->kids[j].link_data].gc;
+ XDrawLine(XtDisplay(w), XtWindow(w),
+ gc,
+ n->r.x + n->r.width/2 ,
+ n->r.y + n->r.height/2 ,
+ c->r.x + c->r.width/2 ,
+ c->r.y + c->r.height/2);
+ }
+#endif
+
+
+ }
+
+ }
+
+ y = w->simpletime.max_h + w->simpletime.title;
+ for (i = 0; i < w ->simpletime.arcs; i++)
+ {
+ line_in(w,0,y, w->core.width, y);
+ y += w->simpletime.max_h;
+ }
+
+ NodesRedraw((SimpleBaseWidget)w,event,region);
+
+
+}
+
+static void Print(SimpleTimeWidget w,FILE *f)
+{
+}
+
+
+static void calc_arc(SimpleTimeWidget tw,NodeStruct* w,int arc)
+{
+ int j;
+ if(w->misc[ARC] == -1 && w->managed)
+ {
+ w->misc[ARC] = arc;
+ for (j = 0; j < w->kcnt; j++)
+ {
+ NodeStruct *c = &KIDS(tw,w,j);
+ calc_arc(tw,c,arc);
+ }
+
+ for (j = 0; j < w->pcnt; j++)
+ {
+ NodeStruct *c = &PARENTS(tw,w,j);
+ calc_arc(tw,c,arc);
+ }
+
+ }
+}
+
+static void Layout(Widget w,long *maxWidth,long *maxHeight)
+{
+ SimpleTimeWidget tw = (SimpleTimeWidget)w;
+ int i;
+ int arc = 0;
+
+ XmString s = XmStringCreateSimple("0123456789:- ");
+ tw->simpletime.title = XmStringHeight(tw->simpletime.font,s)*2 + 10;
+ XmStringFree(s);
+
+ *maxWidth = *maxHeight = 5;
+
+ if(tw->simplebase.count == 0)
+ {
+ tw->simpletime.inited = 0;
+ return;
+ }
+
+
+ tw->simpletime.max_w = 0;
+ tw->simpletime.max_h = 0;
+
+ for(i=0;i<tw->simplebase.count;i++)
+ {
+ NodeStruct *w = tw->simplebase.nodes + i;
+ if(!w->managed) continue;
+
+ w->misc[ARC] = -1;
+ if(w->r.height> tw->simpletime.max_h)
+ tw->simpletime.max_h = w->r.height;
+
+ if(w->misc[DATE] == 0)
+ if(w->r.width > tw->simpletime.max_w)
+ tw->simpletime.max_w = w->r.width;
+ }
+
+ tw->simpletime.max_h += 4;
+
+ for(i=0;i<tw->simplebase.count;i++)
+ {
+ NodeStruct *w = tw->simplebase.nodes + i;
+ if(!w->managed) continue;
+ if(w->misc[ARC] == -1)
+ calc_arc(tw,w,arc++);
+ }
+
+ tw->simpletime.arcs = arc;
+
+ if(tw->simpletime.second_per_pixel<1)
+ tw->simpletime.second_per_pixel = 1;
+
+ if(1) {
+ Widget ww = (Widget)tw;
+ Widget clip = 0,scroll = 0;
+ while(ww){
+ if((clip = XtParent(ww)))
+ if((scroll = XtParent(clip))) {
+ if(XmIsScrolledWindow(scroll))
+ break;
+ else
+ clip = scroll = 0;
+ }
+ }
+
+ if(clip)
+ {
+ while(tw->simpletime.second_per_pixel > 1 &&
+ x_of(tw,tw->simpletime.end_date,tw->simpletime.end_time) < clip->core.width)
+ tw->simpletime.second_per_pixel--;
+
+ while(x_of(tw,tw->simpletime.end_date,tw->simpletime.end_time) > clip->core.width)
+ tw->simpletime.second_per_pixel++;
+ }
+ }
+
+ while(x_of(tw,tw->simpletime.end_date,tw->simpletime.end_time) > 64000)
+ {
+#if 0
+ printf("Scaling too large... %d %d %d %d\n",
+ tw->simpletime.second_per_pixel,
+ tw->simpletime.end_date,tw->simpletime.end_time,
+ x_of(tw,tw->simpletime.end_date,tw->simpletime.end_time)
+
+ );
+#endif
+ tw->simpletime.second_per_pixel++;
+ }
+
+ for(i=0;i<tw->simplebase.count;i++)
+ {
+ NodeStruct *w = tw->simplebase.nodes + i;
+ if(!w->managed) continue;
+
+
+ if(w->misc[DATE] == 0)
+ w->r.x = 0;
+ else
+ w->r.x = x_of(tw,w->misc[DATE],w->misc[TIME]) - w->r.width/2;
+
+ w->r.y = tw->simpletime.title +
+ w->misc[ARC] * tw->simpletime.max_h +
+ (tw->simpletime.max_h - w->r.height)/2;
+
+ if(*maxWidth < w->r.x + w->r.width)
+ *maxWidth = w->r.x + w->r.width;
+
+ if(*maxHeight < w->r.y + w->r.height)
+ *maxHeight = w->r.y + w->r.height;
+ }
+
+}
+
+
+void TimeSetTime(Widget _w,int n,DateTime dt)
+{
+ SimpleTimeWidget tw = (SimpleTimeWidget)_w;
+ NodeStruct *w = tw->simplebase.nodes + n;
+
+ w->misc[DATE] = date_to_julian(dt.date);
+ w->misc[TIME] = time_to_sec(dt.time);
+
+ if(!tw->simpletime.inited)
+ {
+ tw->simpletime.start_date = tw->simpletime.end_date = w->misc[DATE];
+ tw->simpletime.start_time = tw->simpletime.end_time = w->misc[TIME];
+ tw->simpletime.inited = 1;
+ }
+
+ if(w->misc[DATE] < tw->simpletime.start_date ||
+ ( w->misc[DATE] == tw->simpletime.start_date &&
+ w->misc[TIME] < tw->simpletime.start_time))
+ {
+ tw->simpletime.start_date = w->misc[DATE];
+ tw->simpletime.start_time = w->misc[TIME];
+ }
+
+ if(w->misc[DATE] > tw->simpletime.end_date ||
+ ( w->misc[DATE] == tw->simpletime.end_date &&
+ w->misc[TIME] > tw->simpletime.end_time))
+ {
+ tw->simpletime.end_date = w->misc[DATE];
+ tw->simpletime.end_time = w->misc[TIME];
+ }
+
+#if 0
+ printf("TimeSetTime %d %d %d %d\n",
+ w->misc[DATE],w->misc[TIME],
+ tw->simpletime.end_date, tw->simpletime.end_time
+
+ );
+#endif
+}
+
+DateTime TimeGetTime(Widget _w,int n)
+{
+ SimpleTimeWidget tw = (SimpleTimeWidget)_w;
+ NodeStruct *w = tw->simplebase.nodes + n;
+ DateTime dt;
+
+ dt.date = julian_to_date(w->misc[DATE]);
+ dt.time = sec_to_time(w->misc[TIME]);
+
+ return dt;
+}
+
+void TimeAdd(DateTime* dt,int n)
+{
+ int dd = date_to_julian(dt->date);
+ int tt = time_to_sec(dt->time);
+
+ tt += n;
+ while(tt < 0) {
+ dd++;
+ tt += 24*60*60;
+ }
+
+ while(tt >= 24*60*60)
+ {
+ dd--;
+ tt -= 24*60*60;
+ }
+
+ /* printf("TimeAdd: %d %d\n",*d,*t); */
+
+ dt->date = julian_to_date(dd);
+ dt->time = sec_to_time(tt);
+ /* printf("TimeAdd: %d %d\n",*d,*t); */
+}
+
+Widget CreateTime(Widget par,char *nam,ArgList al,int ac)
+{
+ return XtCreateWidget(nam,simpletimeWidgetClass,par,al, ac);
+}
+
+/*
+ Make the simpletime _second_ visible
+ If _second_ is equal to TIME_NOW show the current simpletime
+*/
+
+void TimeShowTime(Widget _w,DateTime dt,XEvent* ev)
+{
+ SimpleTimeWidget h = (SimpleTimeWidget)_w;
+ XRectangle r;
+
+
+ int d = date_to_julian(dt.date);
+ int t = time_to_sec(dt.time);
+
+ r.x = x_of(h,d,t);
+ r.y = ev?ev->xbutton.y:0;
+ r.width = 1;
+ r.height = 1;
+
+ SimpleBaseShow(_w,&r,ev);
+}
+
+void TimeEventTime(Widget _w,XEvent* e,DateTime *dt)
+{
+ int x = e->xbutton.x;
+ int d,t;
+ time_of((SimpleTimeWidget)_w,x,&d,&t);
+ dt->date = julian_to_date(d);
+ dt->time = sec_to_time(t);
+}
+
+int TimeDiff(DateTime dt1,DateTime dt2)
+{
+ /* long long x1,x2; */
+ long x1,x2;
+ int d1 = date_to_julian(dt1.date);
+ int d2 = date_to_julian(dt2.date);
+ int t1 = time_to_sec(dt1.time);
+ int t2 = time_to_sec(dt2.time);
+
+ x1 = d1 * 24 * 60 * 60 + t1;
+ x2 = d2 * 24 * 60 * 60 + t2;
+
+ return x1 - x2;
+}
+
+void *TimeFindByY(Widget _w,XEvent *ev)
+{
+ SimpleBaseWidget w = (SimpleBaseWidget)_w;
+ int i;
+ for(i = 0; i < w->simplebase.count;i++)
+ {
+ NodeStruct *n = w->simplebase.nodes + i;
+ if(n->managed)
+ if(
+ /* ev->xbutton.x >= n->r.x && ev->xbutton.x <= n->r.x + n->r.width && */
+ ev->xbutton.y >= n->r.y && ev->xbutton.y <= n->r.y + n->r.height)
+ return n->user_data;
+ }
+ return NULL;
+}
diff --git a/view/src/SimpleTime.h b/view/src/SimpleTime.h
new file mode 100644
index 0000000..563877d
--- /dev/null
+++ b/view/src/SimpleTime.h
@@ -0,0 +1,76 @@
+#ifndef SIMPLETIME_H
+#define SIMPLETIME_H
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #4 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "SimpleBase.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+extern WidgetClass simpletimeWidgetClass;
+
+typedef struct _SimpleTimeClassRec *SimpleTimeWidgetClass;
+typedef struct _SimpleTimeRec *SimpleTimeWidget;
+
+/* constraint resources */
+
+#define XtNstartSimpleTime "startSimpleTime"
+#define XtNendSimpleTime "endSimpleTime"
+#define XtCSimpleTime "SimpleTime"
+
+
+/* Tieme widget resources */
+
+/* Pixel between rows of widgets */
+
+#define XtNverticalSpace "verticalSpace"
+
+/* Scale factor */
+
+#define XtNpixelSecond "pixelSecond"
+#define XtCPixelSecond "PixelSecond"
+
+/* always make current simpletime visible */
+
+#define XtNautoScroll "autoScroll"
+#define XtCAutoScroll "AutoScroll"
+
+extern Widget CreateTime(Widget,char*,Arg*,int);
+
+#define TIME_NOW (-1) /* Used in SimpleTimeShowSimpleTime */
+
+
+typedef struct DateTime {
+ int date;
+ int time;
+} DateTime ;
+
+void TimeSetTime(Widget,int,DateTime);
+DateTime TimeGetTime(Widget,int);
+void TimeAdd(DateTime*,int);
+int TimeDiff(DateTime,DateTime);
+
+void* TimeFindByY(Widget,XEvent*);
+
+void TimeEventTime(Widget,XEvent*,DateTime*);
+void TimeShowTime(Widget,DateTime,XEvent*);
+void TimeRange(Widget,DateTime*,DateTime*);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+#endif
diff --git a/view/src/SimpleTimeP.h b/view/src/SimpleTimeP.h
new file mode 100644
index 0000000..d7b8851
--- /dev/null
+++ b/view/src/SimpleTimeP.h
@@ -0,0 +1,74 @@
+#ifndef SIMPLETIMEP_H
+#define SIMPLETIMEP_H
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #4 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+
+#include "SimpleBaseP.h"
+#include <Xm/DrawingAP.h>
+
+
+typedef struct _SimpleTimeClassPart {
+ int ignore;
+} SimpleTimeClassPart;
+
+typedef struct _SimpleTimeClassRec {
+ CoreClassPart core_class;
+ CompositeClassPart composite_class;
+ ConstraintClassPart constraint_class;
+ XmManagerClassPart manager_class;
+ XmDrawingAreaClassPart drawing_area_class;
+ SimpleBaseClassPart simplebase_class;
+ SimpleTimeClassPart simpletime_class;
+} SimpleTimeClassRec;
+
+extern SimpleTimeClassRec simpletimeClassRec;
+
+typedef struct {
+ Pixel foreground; /* Color of time line */
+ Dimension v_min_space; /* Distance between rows */
+ int second_per_pixel;/* Scale factor */
+ int minute; /* Current time */
+ Boolean auto_scroll; /* Allays show current time line */
+ XtIntervalId timeout_id; /* Time out id */
+ GC gc; /* Gc for time line */
+ int start_date;
+ int end_date;
+ int start_time;
+ int end_time;
+ int arcs;
+ int inited;
+ int max_w;
+ int max_h;
+ int title;
+ XmFontList font;
+} SimpleTimePart;
+
+
+typedef struct _SimpleTimeRec {
+ CorePart core;
+ CompositePart composite;
+ ConstraintPart constraint;
+ XmManagerPart manager;
+ XmDrawingAreaPart drawing_area;
+ SimpleBasePart simplebase;
+ SimpleTimePart simpletime;
+} SimpleTimeRec;
+
+
+#endif
+
+
+
diff --git a/view/src/SimpleTree.c b/view/src/SimpleTree.c
new file mode 100644
index 0000000..996ebcd
--- /dev/null
+++ b/view/src/SimpleTree.c
@@ -0,0 +1,656 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #5 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include <stdio.h>
+
+#include <X11/Intrinsic.h>
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/CoreP.h>
+#include <X11/CompositeP.h>
+#include <X11/ConstrainP.h>
+#include <Xm/XmP.h>
+#include <Xm/DrawingAP.h>
+#include <Xm/ExtObjectP.h>
+#include "SimpleTree.h"
+#include "SimpleTreeP.h"
+
+#include <Xm/ScrollBar.h>
+#include <stdlib.h>
+
+#ifndef MAX
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#define LAYOUT 0
+
+static void Initialize();
+/*static void ConstraintInitialize();
+ static Boolean ConstraintSetValues();*/
+static void Destroy();
+static void Print();
+static Boolean SetValues();
+/*static XtGeometryResult GeometryManager();
+static void ChangeManaged();
+static void insert_new_node();
+static void delete_node();*/
+static void Layout(Widget,long*,long*);
+static void Redisplay();
+static void compute_rect(SimpleTreeWidget,NodeStruct*,int,int,int,int,int,XRectangle*);
+static void set_positions(SimpleTreeWidget,long*,long*);
+/* static void change_vertical(SimpleTreeWidget tw, NodeStruct *w,Boolean v); ??? */
+#ifdef linux
+/* putting this into comments makes ctrl-left button for collector
+ disappear !! */
+static char defaultTranslations[] = "\
+ Shift<Btn5Down>: increment(10)\n Shift<Btn4Down>: increment(-10) \n\
+ <Btn5Down>: increment(1)\n <Btn4Down>: increment(-1) \n\
+<BtnDown>:DrawingAreaInput()\n\
+<BtnUp>:DrawingAreaInput()\n\
+<Key>osfActivate:DrawingAreaInput()\n\
+~s ~m ~a <Key>Return:DrawingAreaInput()\n\
+~s ~m ~a <Key>space:DrawingAreaInput()\n\
+<Key>F1:DrawingAreaInput()\n\
+<Key>F2:DrawingAreaInput()\n";
+#else
+
+#define defaultTranslations XmInheritTranslations
+
+#endif
+
+static XtResource resources[] = {
+ {XtNhorizontalSpace,XtCSpace,XtRDimension,sizeof(Dimension),
+ XtOffset(SimpleTreeWidget, simpletree.h_min_space), XtRString,"6" },
+ {XtNverticalSpace,XtCSpace, XtRDimension,sizeof (Dimension),
+ XtOffset(SimpleTreeWidget, simpletree.v_min_space), XtRString,"2" },
+
+};
+
+/* https://software.ecmwf.int/issues/browse/SUP-646 */
+static void xincrement();
+static XtActionsRec actionsList[] = {
+ { "increment",(XtActionProc) xincrement},
+}; /* */
+
+SimpleTreeClassRec simpletreeClassRec = {
+ {
+ /* core_class fields */
+ (WidgetClass) &simplebaseClassRec,/* superclass */
+ "SimpleTree", /* class_name */
+ sizeof(SimpleTreeRec), /* widget_size */
+ NULL, /* class_init */
+ NULL, /* class_part_init */
+ FALSE, /* class_inited */
+ Initialize, /* initialize */
+ NULL, /* initialize_hook */
+ XtInheritRealize, /* realize */
+ actionsList, /*NULL, actions */
+ XtNumber(actionsList), /* num_actions */
+ resources, /* resources */
+ XtNumber(resources), /* num_resources */
+ NULLQUARK, /* xrm_class */
+ TRUE, /* compress_motion */
+ /* XtExposeCompressMaximal, */
+ True,
+ /* compress_exposure */
+ TRUE, /* compress_enterleave*/
+ TRUE, /* visible_interest */
+ Destroy, /* destroy */
+ NULL, /* resize */
+ Redisplay, /* expose */
+ SetValues, /* set_values */
+ NULL, /* set_values_hook */
+ XtInheritSetValuesAlmost, /* set_values_almost */
+ NULL, /* get_values_hook */
+ NULL, /* accept_focus */
+ XtVersion, /* version */
+ NULL, /* callback_private */
+ defaultTranslations, /* tm_table */
+ /* XtInheritTranslations, tm_table */
+ NULL, /* query_geometry */
+ XtInheritDisplayAccelerator, /* display_accelerator*/
+ NULL, /* extension */
+ },
+ {
+ /* composite_class fields */
+ NULL, /* geometry_manager */
+ NULL, /* change_managed */
+ XtInheritInsertChild, /* insert_child */
+ XtInheritDeleteChild, /* delete_child */
+ NULL/*&compext*/, /* extension */
+ },
+ {
+ /* constraint_class fields */
+ NULL, /* subresources */
+ 0,/* subresource_count */
+ 0, /* constraint_size */
+ NULL, /* initialize */
+ NULL, /* destroy */
+ NULL, /* set_values */
+ NULL, /* extension */
+ },
+ {
+ XtInheritTranslations, /* default translations */
+ NULL, /* syn_resources */
+ 0, /* num_syn_resources */
+ NULL, /* syn_cont_resources */
+ 0, /* num_syn_cont_resources */
+ XmInheritParentProcess, /* parent_process */
+ NULL, /* extension */
+
+ },
+ {
+ NULL,
+ },
+ {
+ Print,
+ Layout,
+ },
+ {
+ /* SimpleTree class fields */
+ 0, /* ignore */
+ },
+};
+
+
+WidgetClass simpletreeWidgetClass = (WidgetClass) &simpletreeClassRec;
+
+static void Initialize(SimpleTreeWidget request, SimpleTreeWidget new)
+{
+ if (request->core.width <= 0)
+ new->core.width = 5;
+ if (request->core.height <= 0)
+ new->core.height = 5;
+
+}
+
+static void Destroy(SimpleTreeWidget w)
+{
+}
+
+
+static Boolean SetValues(SimpleTreeWidget current,
+SimpleTreeWidget request, SimpleTreeWidget new)
+{
+ int redraw = FALSE;
+ long w = 0;
+ long h = 0;
+
+ if (new->simpletree.v_min_space != current->simpletree.v_min_space ||
+ new->simpletree.h_min_space != current->simpletree.h_min_space){
+ Layout((Widget)new,&w,&h);
+ redraw = True;
+ }
+
+ /* printf("Redraw tree %d\n",redraw); */
+
+ return (redraw);
+}
+
+
+static int first_kid(SimpleTreeWidget w,NodeStruct *n)
+{
+ int i;
+ for(i=0;i<n->kcnt;i++)
+ if(KIDS(w,n,i).managed)
+ return i;
+ return -1;
+}
+
+static int last_kid(SimpleTreeWidget w,NodeStruct *n)
+{
+ int i;
+
+ if(n->kcnt)
+ for(i= n->kcnt - 1;i>=0;i--)
+ if(KIDS(w,n,i).managed)
+ return i;
+ return -1;
+}
+
+static void line(SimpleTreeWidget w,int x1,int y1,int x2,int y2,Region region )
+{
+ int width = x2>x1 ? x2-x1+2 : x1-x2+2;
+ int height = y2>y1 ? y2-y1+2 : y1-y2+2;
+ int x = x2>x1 ? x1 : x2;
+ int y = y2>y1 ? y1 : y2;
+
+ if(XRectInRegion(region,x,y,width,height))
+ {
+
+ XDrawLine(XtDisplay(w), XtWindow(w), w->manager.bottom_shadow_GC,
+ x1,y1,x2,y2);
+
+ XDrawLine(XtDisplay(w), XtWindow(w), w->manager.top_shadow_GC,
+ x1+1,y1+1,x2+1,y2+1);
+ }
+}
+
+static void Redisplay (SimpleTreeWidget w, XEvent *event, Region region)
+{
+ int i, j;
+ int fkid;
+ int lkid;
+
+#if 0
+ NodeStruct *child;
+ XEvent ev;
+ XmRegion r = (XmRegion)region;
+
+ printf("Before: %p\n",r);
+ if(r)
+ for(i=0;i<r->numRects;i++)
+ {
+ XmRegionBox* x = &r->rects[i];
+ printf(" %d-%d %d-%d\n", x->x1,x->x2,x->y1,x->y2);
+ }
+
+ while(XCheckWindowEvent(XtDisplay(w),XtWindow(w),ExposureMask,&ev))
+ XtAddExposureToRegion(&ev,region);
+
+ printf("After:\n");
+ if(r)
+ for(i=0;i<r->numRects;i++)
+ {
+ XmRegionBox* x = &r->rects[i];
+ printf(" %d %d %d %d\n", x->x1,x->y1,x->x2,x->y2);
+ }
+#endif
+
+
+ for (i = 0; i < w -> simplebase.count; i++)
+ {
+ NodeStruct *child = w -> simplebase.nodes + i;
+
+ fkid = first_kid(w,child);
+
+ if(!child->misc[LAYOUT]) /* Vertical layout */
+ {
+
+ if(fkid>=0)
+ {
+ line(w,
+ child->r.x + child->r.width,
+ child->r.y + child->r.height / 2,
+ KIDS(w,child,fkid).r.x,
+ child->r.y + child->r.height / 2
+ /* KIDS(w,child,fkid).r.y + */
+ /* KIDS(w,child,fkid).r.height/2 */
+ ,region);
+
+ lkid = last_kid(w,child);
+
+ if(lkid != fkid)
+ {
+ int x = child->r.x + child->r.width +
+ (KIDS(w,child,fkid).r.x - (child->r.x + child->r.width)) / 2;
+
+ line(w,
+ x,
+ child->r.y + child->r.height / 2,
+ x,
+ KIDS(w,child,lkid).r.y +
+ KIDS(w,child,lkid).r.height/2,region);
+
+ for (j = fkid + 1 ; j < child->kcnt; j++)
+ if (KIDS(w,child,j).managed)
+ {
+
+ line(
+ w,
+ x,
+ KIDS(w,child,j).r.y +
+ KIDS(w,child,j).r.height/2,
+ KIDS(w,child,j).r.x,
+ KIDS(w,child,j).r.y +
+ KIDS(w,child,j).r.height/2,region);
+
+ }
+ }
+ }
+ }
+ else
+ {
+ fkid = first_kid(w,child);
+
+ if(fkid>=0 )
+ {
+ lkid = last_kid(w,child);
+
+ line(w,
+ KIDS(w,child,fkid).r.x + KIDS(w,child,fkid).r.width/2,
+ child->r.y + child->r.height + w->simpletree.v_min_space/2,
+ KIDS(w,child,lkid).r.x + KIDS(w,child,lkid).r.width/2,
+ child->r.y + child->r.height + w->simpletree.v_min_space/2,region);
+
+ line(
+ w,
+ KIDS(w,child,fkid).r.x + KIDS(w,child,fkid).r.width/2,
+ child->r.y + child->r.height,
+ KIDS(w,child,fkid).r.x + KIDS(w,child,fkid).r.width/2,
+ KIDS(w,child,fkid).r.y,region);
+
+ for (j = fkid + 1; j < child->kcnt; j++)
+ if (KIDS(w,child,j).managed)
+ {
+
+ line(
+ w,
+ KIDS(w,child,j).r.x + KIDS(w,child,j).r.width/2,
+ child->r.y + child->r.height + w->simpletree.v_min_space/2,
+ KIDS(w,child,j).r.x + KIDS(w,child,j).r.width/2,
+ KIDS(w,child,j).r.y,region);
+ }
+ }
+
+ }
+
+ }
+
+ NodesRedraw((SimpleBaseWidget)w,event,region);
+}
+
+
+
+static void Layout(Widget w,long *maxWidth,long *maxHeight)
+{
+ SimpleTreeWidget tw = (SimpleTreeWidget)w;
+ int high = (int)tw->simpletree.v_min_space;
+ int i,n;
+ int h_max = 0,w_max = 0;
+
+ *maxWidth = *maxHeight = 5;
+
+ h_max = high;
+
+ for(i=0;i<tw->simplebase.count;i++)
+ {
+ NodeStruct *w = tw->simplebase.nodes + i;
+ h_max = MAX(h_max,w->r.height); /* just a try */
+ w_max = MAX(w_max,w->r.width);
+ }
+
+ /* int dh = h_max / 2; */
+
+ h_max += tw->simpletree.v_min_space;
+ w_max += tw->simpletree.h_min_space;
+
+ for(n=0;n<tw->simplebase.count;n++)
+ {
+ for(i=0;i<tw->simplebase.count;i++)
+ {
+ NodeStruct *w = tw->simplebase.nodes + i;
+ if(w->managed && (w->pcnt == 0))
+ {
+ XRectangle r;
+ compute_rect(tw,w,
+ (int)tw->simpletree.h_min_space,
+ (int)tw->simpletree.h_min_space,
+ w->r.width,
+ w->r.height,
+ w->r.height,
+ &r);
+ }
+ }
+
+ set_positions(tw,maxWidth,maxHeight);
+#if 0
+ if(*maxWidth == 0 || *maxHeight == 0)
+ {
+ Boolean v = (*maxWidth == 0);
+ for(i=0;i<tw->simplebase.count;i++)
+ {
+ NodeStruct *w = tw->simplebase.nodes + i;
+ if(w->managed && (w->pcnt == 0))
+ change_vertical(tw,w,!v);
+ }
+
+ }
+ else
+#endif
+ break;
+ }
+}
+
+#if 0
+static void change_vertical(SimpleTreeWidget tw, NodeStruct *w,Boolean v)
+{
+ int i;
+ if(w->misc[LAYOUT] != v )
+ w->misc[LAYOUT] = v;
+ else
+ {
+ for(i = 0; i < w->kcnt ; i++)
+ if(KIDS(tw,w,i).managed)
+ change_vertical(tw,&KIDS(tw,w,i),v);
+ }
+}
+#endif
+
+static void union_rect(XRectangle *r1,XRectangle *r2,XRectangle *r3)
+{
+ int dx,dy;
+
+ dx = MAX(r1->x+r1->width,r2->x+r2->width);
+ dy = MAX(r1->y+r1->height,r2->y+r2->height);
+ r3->x = MIN(r1->x,r2->x);
+ r3->y = MIN(r1->y,r2->y);
+
+ r3->width = dx - r3->x;
+ r3->height = dy - r3->y;
+
+}
+
+
+static void compute_rect(SimpleTreeWidget tw,NodeStruct *w,
+ int x,int y,int dx,int dy,int h,XRectangle *rect)
+{
+ int i;
+ int mx = 0;
+ int my = 0;
+
+ *rect = w->r;
+ rect->x = w->tmpx = x;
+ rect->y = w->tmpy = y; /* + (h - w->r.height) / 2; */
+ rect->width += tw->simpletree.h_min_space;
+ rect->height += tw->simpletree.v_min_space;
+
+ if(h > w->r.height)
+ rect->y = w->tmpy = y + (h - w->r.height) / 2;
+
+ for(i = 0; i < w->kcnt; i++)
+ {
+ NodeStruct *z = &KIDS(tw,w,i);
+ if(z->managed)
+ {
+ if(z->kcnt) /* && !w->misc[LAYOUT]) */
+ mx = MAX(mx,z->r.width);
+ my = MAX(my,z->r.height);
+ }
+ }
+
+ for(i = 0; i < w->kcnt; i++)
+ {
+ NodeStruct *z = &KIDS(tw,w,i);
+ if(z->managed)
+ {
+ XRectangle r;
+ if(!w->misc[LAYOUT])
+ {
+ compute_rect(tw,z,x + dx + tw->simpletree.h_min_space ,
+ y, mx, my, w->r.height,&r);
+ union_rect(rect,&r,rect);
+ y += r.height;
+
+ if(y > 60000)
+ {
+ y = w->tmpy;
+ x += r.width;
+ }
+ }
+ else
+ {
+ compute_rect(tw,z,x,y + dy
+ + tw->simpletree.v_min_space, mx, my, w->r.height,
+ &r);
+ union_rect(rect,&r,rect);
+ x += r.width;
+ }
+ }
+ }
+
+}
+
+
+static void set_positions(SimpleTreeWidget tw,long *maxWidth, long *maxHeight)
+{
+ int i;
+
+ for(i=0;i<tw->simplebase.count;i++)
+ {
+ NodeStruct *w = tw->simplebase.nodes + i;
+
+ if(w->managed)
+ {
+#if 0
+ if(w->tmpx != (Position)w->tmpx)
+ {
+ *maxWidth = 0;
+ return;
+ }
+
+ if(w->tmpy != (Position)w->tmpy)
+ {
+ *maxHeight = 0;
+ return;
+ }
+#endif
+
+
+#if 0
+ w->r.x = w->tmpx % 64000 + (w->tmpy / 64000) * (w->r.width + 20);
+ w->r.y = w->tmpy % 64000 + (w->tmpx / 64000) * (w->r.height + 20);
+#endif
+
+ w->r.x = w->tmpx;
+ w->r.y = w->tmpy;
+
+ *maxWidth = MAX(*maxWidth,
+ w->r.x + w->r.width + tw->simpletree.h_min_space);
+ *maxHeight = MAX(*maxHeight,
+ w->r.y + w->r.height + tw->simpletree.v_min_space);
+ }
+ }
+}
+
+void NodeTreeFlip(Widget _w,int node)
+{
+ SimpleTreeWidget w = (SimpleTreeWidget)_w;
+ NodeStruct *p = w->simplebase.nodes + node;
+ if( node < 0 || node >= w->simplebase.count) return;
+ p->misc[LAYOUT] = !p->misc[LAYOUT];
+ NodeNewSize(_w,node);
+}
+
+Widget CreateTree(Widget par,char *nam,ArgList al,int ac)
+{
+ return XtCreateWidget(nam,simpletreeWidgetClass,par,al, ac);
+}
+
+static void Print (SimpleTreeWidget w, FILE *f)
+{
+}
+
+static void xincrement (h, event, args, n_args)
+Widget h;
+XEvent *event;
+char *args[];
+int n_args;
+{
+#ifdef MOTIF
+#define SetArg(a,b) XtSetArg(al[ac],a,b);ac++
+#define GetValues(w) XtGetValues(w,al,ac);ac=0
+#define SetValues(w) XtSetValues(w,al,ac);ac=0
+
+ Widget clip = XtParent(h);
+ Widget swin;
+ Widget v_scroll;
+
+ int ac = 0, arg;
+ Position x_parent,y_parent, dh=0, dv=0;
+ Arg al[5];
+
+ if(!clip) return;
+ swin = XtParent(clip);
+
+ if(!(swin = XtParent(swin))) return;
+ while (swin && !XmIsScrolledWindow(swin)) {
+ swin = XtParent(swin);
+ }
+
+ /* printf("# SimpleTree swin %s\n",XtName(swin)); */
+ /* while (clip) { */
+ /* printf("# SimpleTree clip %s\n",XtName(clip)); */
+ /* clip = XtParent(clip); */
+ /* } */
+ if(!swin) return;
+ {
+ int min, max, value, slider_size, inc, page_inc;
+ ac = 0;
+ XtSetArg(al[ac],XmNverticalScrollBar, &v_scroll );ac++;
+ XtGetValues(swin,al,ac);
+
+ ac = 0;
+ XtSetArg(al[ac], XmNminimum,&min); ac++;
+ XtSetArg(al[ac], XmNmaximum,&max); ac++;
+ XtGetValues(v_scroll, al, ac);
+ XmScrollBarGetValues(v_scroll,&value,&slider_size,&inc,&page_inc);
+
+ ac = 0;
+ XtSetArg(al[ac],XmNx,&x_parent);ac++;
+ XtSetArg(al[ac],XmNy,&y_parent);ac++;
+ XtGetValues(swin,al,ac);
+
+ arg = atoi(args[0]);
+ dh = (abs(arg) > 5) ? page_inc : inc;
+
+ if (arg < 0) {
+ if (value - dh < min)
+ value = min;
+ else
+ value -= dh;
+ } else {
+ if (value + dh > max)
+ value = max;
+ else
+ value += dh;
+ }
+
+ {
+ Position x = x_parent-dh;
+ Position y = y_parent-dv;
+
+ ac = 0;
+ XtSetArg(al[ac],XmNx,x);ac++;
+ XtSetArg(al[ac],XmNy,y);ac++;
+ XtSetValues(swin,al,ac);
+ XmScrollBarSetValues(v_scroll,value,slider_size, inc, page_inc,TRUE);
+ }
+ }
+#endif
+}
diff --git a/view/src/SimpleTree.h b/view/src/SimpleTree.h
new file mode 100644
index 0000000..18d1418
--- /dev/null
+++ b/view/src/SimpleTree.h
@@ -0,0 +1,49 @@
+#ifndef SIMPLETREE_H
+#define SIMPLETREE_H
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #4 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+#ifndef MOTIF
+#define MOTIF
+#endif
+
+#include "SimpleBase.h"
+
+extern WidgetClass simpletreeWidgetClass;
+
+typedef struct _SimpleTreeClassRec *SimpleTreeWidgetClass;
+typedef struct _SimpleTreeRec *SimpleTreeWidget;
+
+#define XtNhorizontalSpace "horizontalSpace"
+#define XtNverticalSpace "verticalSpace"
+#define XtNparentNode "parentNode"
+#define XtCParentNode "ParentNode"
+#define XtNselected "selected"
+#define XtCSelected "Selected"
+#define XtNvertical "vertical"
+#define XtCVertical "Vertical"
+
+extern Widget CreateTree(Widget,char*,Arg*,int);
+extern void NodeTreeFlip(Widget,int);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/view/src/SimpleTreeP.h b/view/src/SimpleTreeP.h
new file mode 100644
index 0000000..5f9ed68
--- /dev/null
+++ b/view/src/SimpleTreeP.h
@@ -0,0 +1,60 @@
+#ifndef SIMPLETREEP_H
+#define SIMPLETREEP_H
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #4 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+
+#include "SimpleBaseP.h"
+#include <Xm/DrawingAP.h>
+
+
+typedef struct _SimpleTreeClassPart {
+ int ignore;
+} SimpleTreeClassPart;
+
+typedef struct _SimpleTreeClassRec {
+ CoreClassPart core_class;
+ CompositeClassPart composite_class;
+ ConstraintClassPart constraint_class;
+ XmManagerClassPart manager_class;
+ XmDrawingAreaClassPart drawing_area_class;
+ SimpleBaseClassPart simplebase_class;
+ SimpleTreeClassPart simpletree_class;
+} SimpleTreeClassRec;
+
+extern SimpleTreeClassRec simpletreeClassRec;
+
+typedef struct {
+ Dimension h_min_space;
+ Dimension v_min_space;
+} SimpleTreePart;
+
+
+typedef struct _SimpleTreeRec {
+ CorePart core;
+ CompositePart composite;
+ ConstraintPart constraint;
+ XmManagerPart manager;
+ XmDrawingAreaPart drawing_area;
+ SimpleBasePart simplebase;
+ SimpleTreePart simpletree;
+} SimpleTreeRec;
+
+
+
+#endif
+
+
+
diff --git a/view/src/Tab.c b/view/src/Tab.c
new file mode 100644
index 0000000..4c46871
--- /dev/null
+++ b/view/src/Tab.c
@@ -0,0 +1,784 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #6 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include <stdio.h>
+#include <math.h>
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#define RADIANS(x) (M_PI * (x) / 180.0)
+#define ROUND(X) (((X) >= 0) ? (int)((X)+0.5) : (int)((X)-0.5))
+
+
+#include <X11/Intrinsic.h>
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/CoreP.h>
+#include <X11/CompositeP.h>
+#include <X11/ConstrainP.h>
+#include <Xm/XmP.h>
+#include <Xm/DrawingAP.h>
+#include "Tab.h"
+#include "TabP.h"
+
+#ifndef MAX
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+static void Initialize();
+static void Resize();
+static void Destroy();
+static void ReDisplay();
+static void Click();
+static Boolean SetValues();
+static XtGeometryResult GeometryManager();
+static void ChangeManaged();
+static void new_layout(TabWidget,Boolean);
+
+static XtResource resources[] = {
+ {XmNvalueChangedCallback,XmCValueChangedCallback,XtRCallback,
+ sizeof(XtPointer), XtOffset(TabWidget,tab.cb), XtRCallback,
+ NULL },
+
+ {XmNopenCallback,XmCValueChangedCallback,XtRCallback,
+ sizeof(XtPointer), XtOffset(TabWidget,tab.open_cb), XtRCallback,
+ NULL },
+
+ {XmNcloseCallback,XmCValueChangedCallback,XtRCallback,
+ sizeof(XtPointer), XtOffset(TabWidget,tab.close_cb), XtRCallback,
+ NULL },
+
+ {XmNfontList,XmCFontList,XmRFontList,sizeof(XmRFontList),
+ XtOffset(TabWidget,tab.font),XmRString,(XtPointer)"fixed" },
+
+ { "Back", "back", XmRPixel,sizeof(Pixel),
+ XtOffset(TabWidget,tab.back),XmRString,"#bcbcbcbcbcbc"},
+
+ { "Blue", "blue", XmRPixel,sizeof(Pixel),
+ XtOffset(TabWidget,tab.blue),XmRString,"blue"},
+
+ { "drawer", "Drawer", XmRBoolean,sizeof(Boolean),
+ XtOffset(TabWidget,tab.drawer),XmRString,"false"},
+};
+
+
+static XtActionsRec actions[] = {
+ {"Click",Click}
+};
+
+
+static char translations[] =
+"<Btn1Down>: Click()";
+
+#define USE_MANAGER
+
+TabClassRec tabClassRec = {
+ {
+ /* core_class fields */
+ (WidgetClass) &xmDrawingAreaClassRec,/* superclass */
+ "Tab", /* class_name */
+ sizeof(TabRec), /* widget_size */
+ NULL, /* class_init */
+ NULL, /* class_part_init */
+ FALSE, /* class_inited */
+ Initialize, /* initialize */
+ NULL, /* initialize_hook */
+ XtInheritRealize, /* realize */
+ actions, /* actions */
+ XtNumber(actions), /* num_actions */
+ resources, /* resources */
+ XtNumber(resources), /* num_resources */
+ NULLQUARK, /* xrm_class */
+ TRUE, /* compress_motion */
+ XtExposeCompressMaximal, /* compress_exposure */
+ TRUE, /* compress_enterleave*/
+ TRUE, /* visible_interest */
+ Destroy, /* destroy */
+ Resize, /* resize */
+ ReDisplay, /* expose */
+ SetValues, /* set_values */
+ NULL, /* set_values_hook */
+ XtInheritSetValuesAlmost, /* set_values_almost */
+ NULL, /* get_values_hook */
+ NULL, /* accept_focus */
+ XtVersion, /* version */
+ NULL, /* callback_private */
+ translations, /* tm_table */
+ NULL, /* query_geometry */
+ XtInheritDisplayAccelerator, /* display_accelerator*/
+ NULL, /* extension */
+ },
+ {
+ /* composite_class fields */
+ GeometryManager, /* geometry_manager */
+ ChangeManaged, /* change_managed */
+ XtInheritInsertChild, /* insert_child */
+ XtInheritDeleteChild, /* delete_child */
+ NULL , /* extension */
+ },
+ {
+ /* constraint_class fields */
+ NULL, /* subresources */
+ 0, /* subresource_count */
+ 0, /* constraint_size */
+ NULL, /* initialize */
+ NULL, /* destroy */
+ NULL, /* set_values */
+ NULL, /* extension */
+ },
+ {
+ XtInheritTranslations, /* default translations */
+ NULL, /* syn_resources */
+ 0, /* num_syn_resources */
+ NULL, /* syn_cont_resources */
+ 0, /* num_syn_cont_resources */
+ XmInheritParentProcess, /* parent_process */
+ NULL, /* extension */
+
+ },
+ {
+ NULL,
+ },
+ {
+ /* Tab class fields */
+ 0, /* ignore */
+ },
+};
+
+static void make_visible(TabWidget tw,Widget w);
+
+WidgetClass tabWidgetClass = (WidgetClass) &tabClassRec;
+
+static void Initialize(TabWidget request, TabWidget new)
+{
+
+ XGCValues values;
+ XtGCMask valueMask = 0;
+
+ XFontStruct *fs = (XFontStruct *) NULL;
+
+ /*
+ * Make sure the widget's width and height are
+ * greater than zero.
+ */
+ if (request->core.width <= 0)
+ new->core.width = 5;
+ if (request->core.height <= 0)
+ new->core.height = 5;
+
+ _XmFontListGetDefaultFont(new->tab.font,&fs);
+ if(fs != NULL)
+ {
+ valueMask |= GCFont;
+ values.font = fs->fid;
+ }
+
+ new->tab.gc = XtGetGC((Widget)new,valueMask,&values);
+ new->tab.current = 0;
+
+ new->tab.hmargin = 8;
+ new->tab.vmargin = 3;
+
+ new->tab.top = 2;
+ new->tab.bottom = 2;
+ new->tab.delta = new->tab.hmargin;
+}
+
+static void Destroy(TabWidget w)
+{
+ XtReleaseGC((Widget)w,w->tab.gc);
+}
+
+static void Resize(TabWidget w)
+{
+ XmDrawingAreaCallbackStruct cb;
+ new_layout(w,False);
+ cb.reason = XmCR_RESIZE;
+ cb.event = NULL;
+ cb.window = XtWindow (w);
+ XtCallCallbackList((Widget)w,w->drawing_area.resize_callback, &cb);
+ make_visible(w,w->tab.current);
+ if(XtIsRealized((Widget)w))
+ XClearArea(XtDisplay(w),XtWindow(w),0,0,0,0,True);
+}
+
+static Boolean SetValues(TabWidget current, TabWidget request, TabWidget new)
+{
+ new_layout(new,False);
+ return (False);
+}
+
+static XtGeometryResult GeometryManager(Widget w,
+ XtWidgetGeometry *request,
+ XtWidgetGeometry *reply)
+{
+ new_layout((TabWidget)XtParent(w),True);
+ return XtGeometryYes;
+}
+
+static void ChangeManaged(TabWidget tw)
+{
+ new_layout(tw,True);
+}
+
+static char* name_of(Widget w)
+{
+ if(XmIsScrolledWindow(w))
+ {
+ static char name[90];
+ strcpy(name,XtName(w));
+ name[strlen(name)-2] = 0;
+ return name;
+ }
+ else
+ return XtName(w);
+
+}
+
+static void new_layout(TabWidget tw,Boolean geometry)
+{
+ /* Dimension w = tw->core.width; */
+ /* Dimension h = tw->core.height; */
+ int t;
+ int i;
+
+ Dimension mw = 0;
+ Dimension mh = 0;
+ Dimension ww = 0;
+
+ Dimension width = tw->core.width;
+ Dimension height = tw->core.height;
+
+ tw->tab.title = 0;
+
+
+ for(i=0;i<tw->composite.num_children;i++)
+ {
+ Widget c = tw->composite.children[i];
+ if(XtIsManaged(c))
+ {
+ char *n = name_of(c);
+ XmString s = XmStringCreateSimple(n);
+ int h = XmStringHeight(tw->tab.font, s) + 2 * tw->tab.vmargin;
+ int w = XmStringWidth(tw->tab.font, s) + 2 * tw->tab.hmargin;
+ XmStringFree(s);
+
+ ww += w;
+
+ mh = MAX(mh,c->core.height);
+ mw = MAX(mh,c->core.width);
+
+ tw->tab.title = MAX(tw->tab.title,h);
+
+ }
+ }
+
+ if(tw->tab.drawer && !geometry )
+ height = tw->tab.title;
+ else
+ height = tw->tab.title + tw->tab.top + tw->tab.bottom + mh;
+
+ width = 2 * tw->tab.hmargin + MAX(ww,mw);
+
+ if(geometry)
+ if(tw->core.width < width || tw->core.height < height)
+ {
+ Dimension maxWidth = width, maxHeight = height;
+ XtGeometryResult result;
+ Dimension replyWidth = 0, replyHeight = 0;
+
+ result = XtMakeResizeRequest(
+ (Widget)tw,
+ maxWidth,
+ maxHeight,
+ &replyWidth, &replyHeight);
+
+ if (result == XtGeometryAlmost)
+ XtMakeResizeRequest (
+ (Widget)tw,
+ replyWidth,
+ replyHeight,NULL, NULL);
+ }
+
+
+ width = tw->core.width;
+ t = (tw->tab.title + tw->tab.top + tw->tab.bottom);
+ height = tw->core.height - t;
+
+ for(i=0;i<tw->composite.num_children;i++)
+ {
+ Widget c = tw->composite.children[i];
+ _XmConfigureObject((Widget)c,0,t,width,height,0);
+ }
+
+}
+
+static void draw(TabWidget tw, Widget c,int* x,int* y,int k)
+{
+ char *n = name_of(c);
+ XmString s = XmStringCreateSimple(n);
+ XPoint points[10];
+ int count = 4;
+ int minx = 0;
+ int maxx = 0;
+ int xx = 0;
+ int i;
+
+ int sw = XmStringWidth(tw->tab.font, s);
+ int step = sw + 2 * tw->tab.hmargin;
+
+ points[0].x = *x - tw->tab.hmargin / 2;
+ points[0].y = tw->tab.title + tw->tab.top ;
+
+ points[1].x = tw->tab.hmargin ;
+ points[1].y = -tw->tab.title;
+
+ points[2].x = sw + tw->tab.hmargin;
+ points[2].y = 0;
+
+ points[3].x = tw->tab.hmargin ;
+ points[3].y = tw->tab.title;
+
+ if(points[0].x + points[1].x + points[2].x + points[3].x > tw->core.width )
+ {
+ int ww = 5;
+ int xx = points[0].x + points[1].x;
+
+ points[2].x = tw->core.width - xx - ww;
+ points[2].y = 0;
+
+ points[3].x = -ww;
+ points[3].y = tw->tab.title / 3;
+
+ points[4].x = ww;
+ points[4].y = tw->tab.title / 3;
+
+ points[5].x = -ww;
+ points[5].y = tw->tab.title - 2 * (tw->tab.title / 3);
+
+ count = 6;
+
+ if(k < tw->tab.last)
+ tw->tab.last = k;
+
+ if(points[2].x < points[1].x)
+ {
+ (*x) += step;
+ return;
+ }
+ }
+
+ if(points[0].x < 0)
+ {
+ int ww = 5;
+
+ points[0].x = 0;
+ points[0].y = tw->tab.title + tw->tab.top ;
+
+ points[1].x = ww;
+ points[1].y = -tw->tab.title / 3;
+
+ points[2].x = -ww;
+ points[2].y = -tw->tab.title / 3;
+
+ points[3].x = ww;
+ points[3].y = -tw->tab.title + 2 * (tw->tab.title / 3);
+
+ points[4].x = *x - tw->tab.hmargin / 2 + 2*tw->tab.hmargin + sw - ww ;
+ points[4].y = 0;
+
+ points[5].x = tw->tab.hmargin ;
+ points[5].y = tw->tab.title;
+
+ count = 6;
+
+ if(k > tw->tab.first)
+ tw->tab.first = k;
+
+ if(points[4].x < 0 )
+ {
+ (*x) += step;
+ return;
+ }
+ }
+
+ minx = points[0].x;
+ maxx = points[0].x;
+ xx = points[0].x;
+
+ for(i = 1; i < count; i++)
+ {
+ xx += points[i].x;
+ if(xx < minx) minx = xx;
+ if(xx > maxx) maxx = xx;
+ }
+
+ XSetForeground(XtDisplay(tw),
+ tw->tab.gc,
+ (c == tw->tab.current) ?
+ tw->core.background_pixel:
+ tw->tab.back);
+
+ XFillPolygon(
+ XtDisplay(tw),
+ XtWindow(tw),
+ tw->tab.gc,
+ points,
+ count,
+ Convex,
+ CoordModePrevious
+ );
+
+ XSetForeground(XtDisplay(tw),
+ tw->tab.gc,
+ tw->manager.foreground);
+
+ XDrawLines(
+ XtDisplay(tw),
+ XtWindow(tw),
+ /* tw->tab.gc, */
+ tw->manager.bottom_shadow_GC,
+ points,
+ count,
+ CoordModePrevious
+ );
+
+ XSetForeground(XtDisplay(tw),
+ tw->tab.gc,
+ (c == tw->tab.current) ?
+ tw->tab.blue:
+ tw->manager.foreground);
+
+ {
+ char buf[1024];
+ int i = strlen(n);
+
+ while(--i >= 0 && sw > (maxx - minx - 2 * tw->tab.hmargin))
+ {
+ XmStringFree(s);
+ strncpy(buf,n,i);
+ buf[i] = '.';
+ buf[i+1] = '.';
+ buf[i+2] = '.';
+ buf[i+3] = 0;
+
+ s = XmStringCreateSimple(buf);
+ sw = XmStringWidth(tw->tab.font, s);
+ }
+
+
+
+ XmStringDraw(XtDisplay(tw),
+ XtWindow(tw),
+ tw->tab.font,
+ s,
+ tw->tab.gc,
+ minx ,
+ tw->tab.vmargin + tw->tab.top + tw->tab.vmargin/3,
+ maxx - minx,
+ XmALIGNMENT_CENTER,
+ XmSTRING_DIRECTION_L_TO_R,
+ NULL);
+
+ }
+
+ XSetForeground(XtDisplay(tw),
+ tw->tab.gc,
+ tw->manager.foreground);
+
+ XmStringFree(s);
+
+ (*x) += step;
+}
+
+static void ReDisplay(Widget w, XEvent *event, Region region)
+{
+ TabWidget tw = (TabWidget)w;
+
+ int x = tw->tab.delta;
+ int y = 0;
+ int i;
+ int cx = 0,cy= 0, ci = 0;
+
+ tw->tab.first = -1;
+ tw->tab.last = tw->composite.num_children + 1;
+
+ for(i=0;i<tw->composite.num_children;i++)
+ {
+ Widget c = tw->composite.children[i];
+ if(XtIsManaged(c))
+ {
+ if(!tw->tab.current) tw->tab.current = c;
+
+ if(c == tw->tab.current) { cx = x; cy = y; ci = i; }
+ draw(tw,c,&x,&y,i);
+ }
+ }
+
+ if(tw->tab.current)
+ {
+ GC gc = tw->tab.gc;
+ int t = tw->tab.title + tw->tab.top;
+
+ x = cx;
+ y = cy;
+
+ draw(tw,tw->tab.current,&x,&y,ci);
+
+ /*========================*/
+
+ XSetForeground(XtDisplay(tw),gc,
+ tw->core.background_pixel);
+
+ XDrawLine(XtDisplay(tw),
+ XtWindow(tw),
+ gc, 0, t, tw->core.width, t);
+
+ XSetForeground(XtDisplay(tw),
+ tw->tab.gc,
+ tw->manager.foreground);
+
+ /*========================*/
+
+ gc = tw->manager.bottom_shadow_GC;
+
+ XDrawLine(XtDisplay(tw),
+ XtWindow(tw),
+ gc,
+ 0,
+ t,
+ cx - tw->tab.hmargin/2,
+ t);
+
+ XDrawLine(XtDisplay(tw),
+ XtWindow(tw),
+ gc,
+ x + tw->tab.hmargin/2,
+ t,
+ tw->core.width,
+ t);
+ }
+
+ if(tw->tab.current && XtIsRealized(tw->tab.current))
+ XRaiseWindow(XtDisplay(tw->tab.current),XtWindow(tw->tab.current));
+}
+
+
+Widget CreateTab(Widget par,char* nam,Arg* al,int ac)
+{
+ return XtCreateWidget(nam,tabWidgetClass,par,al,ac);
+}
+
+Widget TabGetCurrent(Widget w)
+{
+ TabWidget tw = (TabWidget)w;
+ return tw->tab.current;
+}
+
+static int opened_size(TabWidget tw)
+{
+ XtWidgetGeometry preferred;
+ int size;
+
+ XtQueryGeometry(tw->tab.current,NULL,&preferred);
+
+ if((preferred.request_mode & CWHeight) != 0)
+ size = preferred.height;
+ else
+ size = tw->tab.current->core.height;
+
+ return size + tw->tab.title + tw->tab.vmargin;
+}
+
+static void open_close_tab(TabWidget tw)
+{
+ if(tw->core.height == tw->tab.title)
+ XtVaSetValues((Widget)tw,XmNheight,opened_size(tw),NULL);
+ else
+ XtVaSetValues((Widget)tw,XmNheight,tw->tab.title,NULL);
+}
+
+static void open_full(TabWidget tw)
+{
+ int size = opened_size(tw);
+ if(tw->core.height < size)
+ XtVaSetValues((Widget)tw,XmNheight,size,NULL);
+}
+
+static void set_tab(Widget w,Widget c,Boolean tell,XEvent* ev)
+{
+ TabWidget tw = (TabWidget)w;
+ TabCallbackStruct cb;
+
+ while(c && XtParent(c) != w)
+ c = XtParent(c);
+
+ if(!c) return;
+
+ if(tw->tab.current == c)
+ {
+ if(tw->tab.drawer) {
+ if(ev)
+ open_close_tab(tw);
+ else
+ open_full(tw);
+ }
+ return;
+ }
+
+ cb.reason = XmCR_VALUE_CHANGED;
+ cb.widget = c;
+ cb.event = ev;
+
+ if(tell)
+ XtCallCallbacks(w, XmNvalueChangedCallback, &cb);
+
+ tw->tab.current = cb.widget;
+
+ if(tw->tab.drawer)
+ open_full(tw);
+
+ make_visible(tw,tw->tab.current);
+
+ if(XtIsRealized(w))
+ XClearArea(XtDisplay(w),XtWindow(w),0,0,0,0,True);
+}
+
+void TabSetCurrent(Widget w,Widget c,Boolean tell)
+{
+ set_tab(w,c,tell,NULL);
+}
+
+void TabOpen(Widget w)
+{
+ open_full((TabWidget)w);
+}
+
+void TabClose(Widget w)
+{
+ TabWidget tw = (TabWidget)w;
+ new_layout(tw,True);
+ XtVaSetValues(w,XmNheight,tw->tab.title,NULL);
+}
+
+Boolean TabClosed(Widget w)
+{
+ TabWidget tw = (TabWidget)w;
+ return tw->tab.title == tw->core.height;
+}
+
+static void Click(Widget w, XEvent *event, String *params,Cardinal *nparams)
+{
+ TabWidget tw = (TabWidget)w;
+
+ int x = tw->tab.delta;
+ int i;
+
+ for(i=0;i<tw->composite.num_children;i++)
+ {
+ Widget c = tw->composite.children[i];
+ if(XtIsManaged(c))
+ {
+ char *n = name_of(c);
+ XmString s = XmStringCreateSimple(n);
+
+ int h = XmStringHeight(tw->tab.font, s) + 2 * tw->tab.vmargin;
+ int w = XmStringWidth(tw->tab.font, s) + 2 * tw->tab.hmargin;
+
+ XmStringFree(s);
+
+ if(event->xbutton.y >= tw->tab.top &&
+ event->xbutton.y <= h + tw->tab.top)
+ if(event->xbutton.x >= x && event->xbutton.x <= x + w)
+ {
+
+ if(i <= tw->tab.first || i>= tw->tab.last)
+ make_visible(tw,c);
+ else
+ set_tab((Widget)tw,c,True,event);
+ break;
+ }
+ x += w;
+ }
+ }
+}
+
+
+static void make_visible(TabWidget tw, Widget wid)
+{
+ int x = 0;
+ int i;
+ int m = 0;
+ int j = 0;
+
+ int from,to;
+
+ int* pos = (int*)XtCalloc(sizeof(int),tw->composite.num_children+1);
+
+ for(i=0;i<tw->composite.num_children;i++)
+ {
+ Widget c = tw->composite.children[i];
+ if(XtIsManaged(c))
+ {
+ char *n = name_of(c);
+ XmString s = XmStringCreateSimple(n);
+
+ /* int h = XmStringHeight(tw->tab.font, s) + 2 * tw->tab.vmargin; */
+ int w = XmStringWidth(tw->tab.font, s) + 2 * tw->tab.hmargin;
+
+ XmStringFree(s);
+
+ if(c == wid)
+ j = m;
+ pos[m++] = x;
+ x += w;
+ }
+ }
+
+ pos[m] = x;
+
+ if(j == 0 || j == m-1)
+ {
+ from = pos[j] - tw->tab.hmargin;
+ to = pos[j+1] + tw->tab.hmargin;;
+ }
+ else {
+ from = (pos[j]+pos[j-1])/2;
+ to = (pos[j+2]+pos[j+1])/2;
+ }
+
+ tw->tab.delta = 5; /* start from first tab */
+
+ if(from + tw->tab.delta < 0)
+ {
+ tw->tab.delta = -from;
+ if(XtIsRealized((Widget)tw))
+ XClearArea(XtDisplay(tw),XtWindow(tw),0,0,0,0,True);
+ }
+
+ if(to + tw->tab.delta > tw->core.width )
+ {
+ tw->tab.delta = -(to-tw->core.width);
+ if(XtIsRealized((Widget)tw))
+ XClearArea(XtDisplay(tw),XtWindow(tw),0,0,0,0,True);
+ }
+
+ XtFree((XtPointer)pos);
+}
diff --git a/view/src/Tab.h b/view/src/Tab.h
new file mode 100644
index 0000000..8c0dc63
--- /dev/null
+++ b/view/src/Tab.h
@@ -0,0 +1,66 @@
+#ifndef TAB_H
+#define TAB_H
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #4 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+
+#define XtNround "round"
+#define XtCRound "Round"
+#define XtNrows "rows"
+#define XtNcolumns "columns"
+#define XtCRowCol "RowCol"
+
+#define XmNopenCallback "openCallback"
+#define XmNcloseCallback "closeCallback"
+
+extern WidgetClass tabWidgetClass;
+
+typedef struct _TabClassRec *TabWidgetClass;
+typedef struct _TabRec *TabWidget;
+
+#ifdef _NO_PROTO
+
+extern Widget CreateTab();
+
+#else
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+Widget CreateTab(Widget,String,Arg*,int);
+Widget TabGetCurrent(Widget);
+void TabSetCurrent(Widget,Widget,Boolean);
+
+void TabOpen(Widget);
+void TabClose(Widget);
+
+Boolean TabClosed(Widget);
+
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif /* _NO_PROTO */
+
+typedef struct {
+ int reason;
+ XEvent *event;
+ Widget widget;
+}TabCallbackStruct;
+
+
+#endif /* TAB_H */
diff --git a/view/src/TabP.h b/view/src/TabP.h
new file mode 100644
index 0000000..5d4675a
--- /dev/null
+++ b/view/src/TabP.h
@@ -0,0 +1,80 @@
+#ifndef TABP_H
+#define TABP_H
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #4 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+
+#include <Xm/XmP.h>
+#include <Xm/DrawingAP.h>
+
+typedef struct _TabClassPart {
+ int ignore;
+} TabClassPart;
+
+typedef struct _TabClassRec {
+ CoreClassPart core_class;
+ CompositeClassPart composite_class;
+ ConstraintClassPart constraint_class;
+ XmManagerClassPart manager_class;
+ XmDrawingAreaClassPart drawing_area_class;
+ TabClassPart tab_class;
+} TabClassRec;
+
+extern TabClassRec tabClassRec;
+
+typedef struct {
+ XtCallbackList cb;
+ XtCallbackList open_cb;
+ XtCallbackList close_cb;
+ XmFontList font;
+ Widget current;
+ GC gc;
+ Pixel back;
+ Pixel blue;
+
+ Dimension hmargin;
+ Dimension vmargin;
+
+ Dimension title;
+ Dimension top;
+ Dimension bottom;
+
+ int delta;
+ int first;
+ int last;
+
+ Boolean drawer;
+ Time last_click;
+
+} TabPart;
+
+
+typedef struct _TabRec {
+ CorePart core;
+ CompositePart composite;
+ ConstraintPart constraint;
+ XmManagerPart manager;
+ XmDrawingAreaPart drawing_area;
+ TabPart tab;
+} TabRec;
+
+
+#define XtTabNumChildren(w) (((TabWidget)w) -> composite.num_children)
+#define XtTabChild(w,i) (((TabWidget)w) -> composite.children[i])
+
+#endif /* TABP_H */
+
+
+
diff --git a/view/src/aborted.cc b/view/src/aborted.cc
new file mode 100644
index 0000000..41b395a
--- /dev/null
+++ b/view/src/aborted.cc
@@ -0,0 +1,33 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "aborted.h"
+#include "node.h"
+
+aborted::aborted():
+ node_alert<aborted>("Aborted tasks",STATUS_ABORTED)
+{
+}
+
+aborted::~aborted()
+{
+}
+
+
+bool aborted::keep(node* n)
+{
+ return n->status() == STATUS_ABORTED;
+}
+
diff --git a/view/src/aborted.h b/view/src/aborted.h
new file mode 100644
index 0000000..6de57dd
--- /dev/null
+++ b/view/src/aborted.h
@@ -0,0 +1,109 @@
+#ifndef aborted_H
+#define aborted_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "node_alert.h"
+
+class node;
+
+class aborted : public node_alert<aborted> {
+public:
+
+// -- Exceptions
+ // None
+
+// -- Contructors
+
+ aborted();
+
+// -- Destructor
+
+ ~aborted(); // Change to virtual if base class
+
+// -- Convertors
+ // None
+
+// -- Operators
+ // None
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+
+
+ // Uncomment for persistent, remove otherwise
+ // static os_typespec* get_os_typespec();
+
+protected:
+
+// -- Members
+ // None
+
+// -- Methods
+
+ // void print(ostream&) const; // Change to virtual if base class
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+private:
+
+// No copy allowed
+
+ aborted(const aborted&);
+ aborted& operator=(const aborted&);
+
+// -- Methods
+
+// -- Overridden methods
+
+ virtual bool keep(node*);
+
+// -- Class members
+
+
+// -- Class methods
+ // None
+
+// -- Friends
+
+ //friend ostream& operator<<(ostream& s,const aborted& p)
+ // { p.print(s); return s; }
+
+};
+
+inline void destroy(aborted**) {}
+
+// If persistent, uncomment, otherwise remove
+//#ifdef _ODI_OSSG_
+//OS_MARK_SCHEMA_TYPE(aborted);
+//#endif
+
+#endif
diff --git a/view/src/alerts.cc b/view/src/alerts.cc
new file mode 100644
index 0000000..4532af3
--- /dev/null
+++ b/view/src/alerts.cc
@@ -0,0 +1,26 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "to_check.h"
+#include "zombie.h"
+
+to_check::to_check() : node_alert<to_check>("Tasks to check") {}
+to_check::~to_check() {} // Change to virtual if base class
+bool to_check::keep(node* n) { return n->isToBeChecked(); }
+
+zombie::zombie() : node_alert<zombie>("Zombies") {}
+zombie::~zombie() {} // Change to virtual if base class
+bool zombie::keep(node* n) { return n->isZombie(); }
+
diff --git a/view/src/alias.cc b/view/src/alias.cc
new file mode 100644
index 0000000..c37977a
--- /dev/null
+++ b/view/src/alias.cc
@@ -0,0 +1,38 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "task_node.h"
+
+#ifdef BRIDGE
+alias_node::alias_node(host& h,sms_node* n,char b):
+ task_node(h,n,b)
+{}
+#endif
+
+alias_node::alias_node(host& h,ecf_node* n):
+ task_node(h,n)
+{
+}
+
+alias_node::~alias_node()
+{
+}
+
+
+void alias_node::why(std::ostream& f)
+{
+ task_node::why(f);
+}
+
diff --git a/view/src/arch.h b/view/src/arch.h
new file mode 100644
index 0000000..4a02730
--- /dev/null
+++ b/view/src/arch.h
@@ -0,0 +1,20 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#if defined(__GNUC__) || defined(_AIX) || defined(alpha)
+#define _(z) z
+#else
+#define _(z)
+#endif
diff --git a/view/src/array.cc b/view/src/array.cc
new file mode 100644
index 0000000..cae135c
--- /dev/null
+++ b/view/src/array.cc
@@ -0,0 +1,79 @@
+#ifndef array_H
+#include "array.h"
+#endif
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+template<class T>
+array<T>::array():
+ count_(0),
+ max_(0),
+ values_(0)
+{
+}
+
+template<class T>
+array<T>::array(const array<T>& other):
+ count_(other.count_),
+ max_(other.count_),
+ values_(0)
+{
+ values_ = new T[count_];
+ for(int i = 0; i< count_; i++)
+ values_[i] = other.values_[i];
+}
+
+template<class T>
+array<T>::~array()
+{
+ delete[] values_;
+}
+
+template<class T>
+void array<T>::clear()
+{
+ count_ = 0;
+}
+
+template<class T>
+void array<T>::add(const T& t)
+{
+ //printf("1. array<T>::add( %d %d\n", max_,count_);
+ if(count_ == max_)
+ {
+ max_ += 1 + max_/2;
+ T* o = new T[max_];
+ for(int i = 0; i< count_; i++)
+ o[i] = values_[i];
+ delete[] values_;
+ values_ = o;
+ //printf("2. array<T>::add( %d %d\n", max_,count_);
+ }
+ //printf("3. array<T>::add( %d %d\n", max_,count_);
+ values_[count_++] = t;
+}
+
+template<class T>
+void array<T>::remove(const T& t)
+{
+ for(int i = 0; i< count_; i++)
+ {
+ if(values_[i] == t)
+ {
+ values_[i] = values_[--count_];
+ break;
+ }
+ }
+}
diff --git a/view/src/array.h b/view/src/array.h
new file mode 100644
index 0000000..8349766
--- /dev/null
+++ b/view/src/array.h
@@ -0,0 +1,131 @@
+#ifndef array_H
+#define array_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include <stdio.h>
+
+// Headers
+// #ifndef machine_H
+// #include <machine.h>
+// #endif
+
+// Forward declarations
+
+// class ostream;
+// typedef class _Pvts os_typespec; // Remove if not persistant
+
+//
+
+template<class T>
+class array {
+public:
+
+// -- Exceptions
+ // None
+
+// -- Contructors
+
+ array();
+ array(const array<T>&);
+
+// -- Destructor
+
+ ~array(); // Change to virtual if base class
+
+// -- Convertors
+ // None
+
+// -- Operators
+
+ array<T>& operator=(const array<T>&);
+
+ T& operator[](int i ) { return values_[i]; }
+ int count() { return count_; }
+
+// -- Methods
+ // None
+
+ void add(const T&);
+ void remove(const T&);
+ void clear();
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+ // Uncomment for persistent, remove otherwise
+ // static os_typespec* get_os_typespec();
+
+protected:
+
+// -- Members
+ // None
+
+ int count_;
+ int max_;
+ T* values_;
+
+// -- Methods
+
+ // void print(ostream&) const; // Change to virtual if base class
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+private:
+
+// No copy allowed
+
+
+// -- Members
+ // None
+
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+// -- Friends
+
+ //friend ostream& operator<<(ostream& s,const array& p)
+ // { p.print(s); return s; }
+
+};
+
+
+#include "array.cc"
+
+#endif
diff --git a/view/src/ask.cc b/view/src/ask.cc
new file mode 100644
index 0000000..efcf733
--- /dev/null
+++ b/view/src/ask.cc
@@ -0,0 +1,46 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <stdio.h>
+#include <stdarg.h>
+#include "ask.h"
+#include "gui.h"
+#include <Xm/Text.h>
+
+ask::ask()
+{
+ create(gui::top());
+}
+
+ask::~ask()
+{
+}
+
+bool ask::show(str& val,std::string msg)
+{
+ static std::string m = msg;
+ return instance().show(m.c_str(),val);
+}
+
+bool ask::show(const char* msg,str& val)
+{
+ XmTextSetString(value_, (char*) val.c_str());
+ if (!modal(msg, true))
+ return false;
+ char *p=XmTextGetString(value_);;
+ val = p;
+ XtFree(p);
+ return true;
+}
diff --git a/view/src/ask.h b/view/src/ask.h
new file mode 100644
index 0000000..711207d
--- /dev/null
+++ b/view/src/ask.h
@@ -0,0 +1,41 @@
+#ifndef ask_H
+#define ask_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "uiask.h"
+#include "dialog.h"
+#include "str.h"
+#include <string>
+
+class ask : public dialog<ask,ask_shell_c> {
+public:
+
+ ask();
+
+ ~ask(); // Change to virtual if base class
+
+ static bool show(str&,std::string);
+private:
+
+ ask(const ask&);
+ ask& operator=(const ask&);
+
+ bool show(const char*,str&);
+};
+
+inline void destroy(ask**) {}
+#endif
diff --git a/view/src/autoAlarm.h b/view/src/autoAlarm.h
new file mode 100644
index 0000000..0c0668a
--- /dev/null
+++ b/view/src/autoAlarm.h
@@ -0,0 +1,42 @@
+#ifndef _AutoAlarm_h
+#define _AutoAlarm_h
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #4 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+
+class AutoAlarm {
+ private:
+ AutoAlarm (const AutoAlarm&); /* no copy allowed */
+ AutoAlarm& operator= (const AutoAlarm&);
+
+ typedef void (*proc)(int);
+ proc (old_);
+ int saveSec_;
+
+ static sigjmp_buf env_;
+ static bool caught_;
+ static int sec_;
+
+ static void sigAlarm (int);
+
+ public:
+ AutoAlarm (int);
+
+ ~AutoAlarm ();
+
+ static bool caught () { return caught_;};
+};
+
+#endif
diff --git a/view/src/auto_alarm.cc b/view/src/auto_alarm.cc
new file mode 100644
index 0000000..5531165
--- /dev/null
+++ b/view/src/auto_alarm.cc
@@ -0,0 +1,47 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <signal.h>
+
+#include "ecflowview.h"
+#include "auto_alarm.h"
+
+int auto_alarm::sec_ = 0;
+
+auto_alarm::auto_alarm (int sec)
+{
+ printf ("set alarm %d\n",sec);
+ old_ = ::signal (SIGALRM, sigAlarm);
+ sec_ = sec;
+
+ ::alarm (sec);
+};
+
+
+auto_alarm::~auto_alarm ()
+{
+ sec_ = saveSec_;
+ ::signal (SIGALRM, old_);
+ ::alarm (0);
+ printf ("reset alarm\n");
+};
+
+
+void auto_alarm::sigAlarm (int)
+{
+ printf ("catching\n");
+ /* if (recover_jump) */
+ // FILL longjmp(ecf_jump_station, 1);
+};
diff --git a/view/src/auto_alarm.h b/view/src/auto_alarm.h
new file mode 100644
index 0000000..5ab2927
--- /dev/null
+++ b/view/src/auto_alarm.h
@@ -0,0 +1,44 @@
+#ifndef _auto_alarm_h
+#define _auto_alarm_h
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #4 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+
+#include "setjmp.h"
+
+class auto_alarm {
+ private:
+ auto_alarm (const auto_alarm&); /* no copy allowed */
+ auto_alarm& operator= (const auto_alarm&);
+
+ typedef void (*proc)(int);
+ proc (old_);
+ int saveSec_;
+
+ static sigjmp_buf env_;
+ static bool caught_;
+ static int sec_;
+
+ static void sigAlarm (int);
+
+ public:
+ auto_alarm (int);
+
+ ~auto_alarm ();
+
+ static bool caught () { return caught_;};
+};
+
+#endif
diff --git a/view/src/base.cc b/view/src/base.cc
new file mode 100644
index 0000000..34c50a2
--- /dev/null
+++ b/view/src/base.cc
@@ -0,0 +1,203 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #8 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <Xm/Xm.h>
+// #include <ostream.h>
+
+#include "base.h"
+#include "directory.h"
+#include "str.h"
+
+struct pairs {
+
+ pairs* next_;
+ str name_;
+ str value_;
+
+ pairs(const str& n,const str& v, pairs* x):
+ next_(x), name_(n),value_(v) {}
+
+ ~pairs() { delete next_; }
+};
+
+
+static base* defbase = 0;
+
+base::base(const str& name,const str& dir,bool save,base* p):
+ name_(name),
+ dir_(dir),
+ count_(0),
+ pairs_(0),
+ parent_(p),
+ save_(save)
+{
+}
+
+base::~base()
+{
+}
+
+base* base::lookup(const str& name)
+{
+ if(defbase == 0) {
+ defbase = new base("user.default",directory::user(),true,
+ new base("system.default",directory::system(),true,
+ new base(str(),str(),false,0)
+ )
+ );
+ }
+
+ base *p = extent<base>::first();
+ while(p) {
+ if(p->name_ == name)
+ return p;
+ p = p->extent<base>::next();
+ }
+
+ return new base(name,directory::user(),true,defbase);
+}
+
+void base::attach()
+{
+ if(parent_)
+ parent_->attach();
+
+ count_++;
+
+ if(count_ == 1 && save_) {
+ // if(save_) {
+ char buf[1024];
+ sprintf(buf,"%s/%s.options",dir_.c_str(),name_.c_str());
+
+ FILE* f = fopen(buf,"r");
+ if(f) {
+ while(fgets(buf,sizeof(buf),f)) {
+ char *p = buf;
+ while(*p && *p != ':') p++;
+ if(*p != ':') continue;
+
+ buf[strlen(buf)-1] = 0;
+ *p = 0;
+
+ store(buf,p+1,true);
+ }
+ fclose(f);
+ }
+ }
+}
+
+void base::detach()
+{
+ if(parent_)
+ parent_->detach();
+
+ count_--;
+
+ if(count_ == 0 && save_)
+ save();
+}
+
+void base::save()
+{
+ char buf[1024];
+ sprintf(buf,"%s/%s.options",dir_.c_str(),name_.c_str());
+ // fprintf(stdout, "%s\n", buf);
+
+ FILE* f = fopen(buf,"w");
+ if(f) {
+ pairs* p = pairs_;
+ while(p) {
+ fprintf(f,"%s:%s\n",p->name_.c_str(),p->value_.c_str());
+ p = p->next_;
+ }
+ fclose(f);
+ }
+}
+
+bool base::fetch(const str& key,str& value)
+{
+ pairs* p = pairs_;
+ while(p) {
+ if(p->name_ == key) {
+ value = p->value_;
+ return true;
+ }
+ p = p->next_;
+ }
+
+ if(parent_)
+ parent_->fetch(key,value);
+ return false;
+}
+
+void base::defaults(const str& key,const str& value)
+{
+ if(parent_) {
+ parent_->defaults(key,value);
+ } else {
+ store(key,value,false);
+ }
+}
+
+void base::remove(const str& key)
+{
+ pairs* p = pairs_;
+ pairs* q = 0;
+
+ while(p) {
+ if(p->name_ == key) {
+ if(q) q->next_ = p->next_;
+ else pairs_ = p->next_;
+ p->next_ = 0;
+
+ delete p;
+
+ remove(key);
+ return;
+ }
+ q = p;
+ p = p->next_;
+ }
+ enable();
+}
+
+void base::store(const str& key,const str& value,bool replace)
+{
+ pairs* p = pairs_;
+ enable();
+ while(p) {
+ if(p->name_ == key) {
+ if(replace) {
+ p->value_ = value;
+ }
+ return;
+ }
+ p = p->next_;
+ }
+
+ pairs_ = new pairs(key,value,pairs_);
+}
+
+void base::run()
+{
+ if(save_)
+ save();
+ disable();
+}
+
+IMP(base)
diff --git a/view/src/base.h b/view/src/base.h
new file mode 100644
index 0000000..7ca8602
--- /dev/null
+++ b/view/src/base.h
@@ -0,0 +1,65 @@
+#ifndef base_H
+#define base_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#ifndef extent_H
+#include "extent.h"
+#endif
+
+#ifndef str_H
+#include "str.h"
+#endif
+
+#ifndef runnable_H
+#include "runnable.h"
+#endif
+
+struct pairs;
+
+class base : public extent<base>, public runnable {
+public:
+ base(const str&,const str&,bool,base*);
+
+ ~base(); // Change to virtual if base class
+
+ void attach();
+ void detach();
+
+ void defaults(const str&,const str&);
+ bool fetch(const str&,str&);
+ void store(const str&,const str&,bool);
+ void remove(const str&);
+ void save();
+
+ static base* lookup(const str&);
+
+private:
+
+ base(const base&);
+ base& operator=(const base&);
+ virtual void run();
+
+ str name_;
+ str dir_;
+ int count_;
+ pairs* pairs_;
+ base* parent_;
+ bool save_;
+};
+
+inline void destroy(base**) {}
+#endif
diff --git a/view/src/bool.h b/view/src/bool.h
new file mode 100644
index 0000000..5ae2d35
--- /dev/null
+++ b/view/src/bool.h
@@ -0,0 +1,25 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#ifndef bool_H
+#define bool_H
+
+typedef char xbool;
+
+#define bool xbool
+#define false 0
+#define true 1
+
+#endif
diff --git a/ecflow_4_0_7/view/src/cdp.cmd b/view/src/cdp.cmd
similarity index 100%
rename from ecflow_4_0_7/view/src/cdp.cmd
rename to view/src/cdp.cmd
diff --git a/view/src/choice.h b/view/src/choice.h
new file mode 100644
index 0000000..5a97307
--- /dev/null
+++ b/view/src/choice.h
@@ -0,0 +1,37 @@
+#ifndef choice_H
+#define choice_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+class choice {
+public:
+
+ choice(int value = 0) : value_(value) {}
+ choice(const choice& other) : value_(other.value_) {}
+
+ operator int() const { return value_; }
+ choice& operator=(int n) { value_ = n; return *this; }
+ choice& operator=(const choice& other) { value_ = other.value_; return *this; }
+
+private:
+
+ int value_;
+
+};
+
+inline void destroy(choice**) {}
+
+#endif
diff --git a/view/src/collector.cc b/view/src/collector.cc
new file mode 100644
index 0000000..83397c0
--- /dev/null
+++ b/view/src/collector.cc
@@ -0,0 +1,282 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #13 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "collector.h"
+#include "gui.h"
+#include "node.h"
+#include "host.h"
+#include "substitute.h"
+#include "directory.h"
+#include <Xm/List.h>
+#include <Xm/Text.h>
+#include <Xm/Separator.h>
+#include <Xm/PushB.h>
+#include <Xm/Command.h>
+#include <Xm/Xm.h>
+extern "C" {
+#include "xec.h"
+}
+
+collector::collector()
+{
+
+ const int commands_nb = 22;
+ static char* commands[commands_nb] = {
+ (char *) "ecflow_client --zombie_fob=<full_name>" ,
+ (char *) "ecflow_client --zombie_fail=<full_name>" ,
+ (char *) "ecflow_client --zombie_adopt=<full_name>" ,
+ (char *) "ecflow_client --zombie_block=<full_name>" ,
+ (char *) "ecflow_client --alter clear_flag zombie=<full_name>" ,
+ (char *) "###",
+ (char *) "ecflow_client --suspend=<full_name>" ,
+ (char *) "ecflow_client --resume=<full_name>" ,
+ (char *) "ecflow_client --kill=<full_name>" ,
+ (char *) "ecflow_client --run=<full_name>" ,
+ (char *) "###",
+ (char *) "ecflow_client --delete=force yes <full_name>",
+ (char *) "###",
+ (char *) "ecflow_client --begin=<node_name>",
+ (char *) "###",
+ (char *) "ecflow_client --requeue=<full_name>",
+ (char *) "ecflow_client --alter=change defstatus queued <full_name>",
+ (char *) "ecflow_client --alter=change defstatus complete <full_name>",
+ (char *) "ecflow_client --force=complete <full_name>",
+ (char *) "ecflow_client --force=aborted <full_name>",
+ (char *) "###",
+ (char *) "sh python %PYDEF:0% %SUITE% <full_name> %ECF_NODE% # aka replace",
+ };
+
+ create(gui::top());
+ set_menu("Collector");
+ substitute::fill(blocks_);
+ XtManageChild(XmCreateSeparator(blocks_,"-",0,0));
+ update();
+
+ FILE* f = directory::open("collector.commands","r");
+ if(f) {
+ char line[1024];
+ while(fgets(line,sizeof(line),f))
+ {
+ line[strlen(line)-1] = 0;
+ XtManageChild(XmCreatePushButton(blocks_,line,0,0));
+ }
+ fclose(f);
+ } else {
+ /* provide default commands to new users */
+
+ for(int i = 0; i < commands_nb; i++)
+ XtManageChild(XmCreatePushButton(blocks_,commands[i],0,0));
+ }
+
+ f = directory::open("collector.history","r");
+ if(f)
+ {
+ char line[1024];
+ int n = 0;
+ while(fgets(line,sizeof(line),f))
+ n++;
+
+ rewind(f);
+
+ XmString* s = new XmString[n];
+ int i = 0;
+
+ while(fgets(line,sizeof(line),f))
+ {
+ line[strlen(line)-1] = 0;
+ s[i++] = xec_NewString(line);
+ }
+ fclose(f);
+
+ XtVaSetValues(command_,
+ XmNhistoryItems, s,
+ XmNhistoryItemCount, n,
+ NULL);
+
+ for(i = 0; i < n; i++)
+ XmStringFree(s[i]);
+ delete[] s;
+ } else {
+ /* provide default commands to new users */
+ const int maxCmd = 128;
+ XmString* s = new XmString[maxCmd];
+ for(int i = 0; i < commands_nb; i++) {
+ s[i] = xec_NewString(commands[i]);
+ }
+
+ XtVaSetValues(command_,
+ XmNhistoryItems, s,
+ XmNhistoryItemCount, commands_nb,
+ NULL);
+ for(int i = 0; i < commands_nb; i++) XmStringFree(s[i]);
+ delete[] s;
+ }
+
+}
+
+collector::~collector()
+{
+
+ FILE * f = directory::open("collector.history","w");
+ if(f)
+ {
+ XmString* s = 0;
+ int n = 0;
+
+ XtVaGetValues(command_,
+ XmNhistoryItems, &s,
+ XmNhistoryItemCount, &n,
+ NULL);
+
+ for(int i = 0; i < n; i++)
+ {
+ char *p = xec_GetString(s[i]);
+ fprintf(f,"%s\n",p);
+ XtFree(p);
+ }
+
+ fclose(f);
+ }
+}
+
+void collector::show(node& n)
+{
+ instance().nodes_.clear();
+ instance().add(&n,true);
+ instance().update();
+}
+
+void collector::applyCB( Widget, XtPointer data)
+{
+ XmCommandCallbackStruct* cb = (XmCommandCallbackStruct*)data;
+ nodes_.clear();
+
+ char *p = xec_GetString(cb->value);
+ send(p);
+ XtFree(p);
+}
+
+void collector::removeCB( Widget, XtPointer )
+{
+ XmString *items = 0;
+ int count = 0;
+
+ nodes_.clear();
+
+ XtVaGetValues(list_,
+ XmNselectedItems,&items,
+ XmNselectedItemCount,&count,
+ NULL);
+
+ XmListDeleteItems(list_,items,count);
+ update();
+}
+
+void collector::noneCB( Widget, XtPointer )
+{
+ nodes_.clear();
+ XmListDeselectAllItems(list_);
+ update();
+}
+
+void collector::allCB( Widget, XtPointer )
+{
+ nodes_.clear();
+ xec_ListSelectAll(list_);
+ update();
+}
+
+void collector::selectCB( Widget, XtPointer )
+{
+ update();
+}
+
+void collector::update()
+{
+ int count = 0;
+ int total = 0;
+
+ XtVaGetValues(list_,
+ XmNselectedItemCount,&count,
+ XmNitemCount,&total,
+ NULL);
+
+ XtSetSensitive(remove_, count != 0);
+ XtSetSensitive(command_, count != 0);
+ XtSetSensitive(all_, count != total);
+ XtSetSensitive(none_, count != 0);
+}
+
+
+void collector::send(const char* cmd)
+{
+ XmString* items = 0;
+ int count = 0;
+
+ XtVaGetValues(list_,
+ XmNselectedItems,&items,
+ XmNselectedItemCount,&count,
+ NULL);
+
+ cmd_ = cmd;
+ nodes_.clear();
+
+ for(int i = 0; i < count ; i++)
+ nodes_.add(items[i]);
+
+ next_ = 0;
+ runnable::enable();
+ XtSetSensitive(stop_,true);
+}
+
+
+void collector::run()
+{
+ if(next_ >= nodes_.count())
+ {
+ nodes_.clear();
+ runnable::disable();
+ XtSetSensitive(stop_,false);
+ return;
+ }
+
+ XmListDeselectItem(list_,nodes_[next_]);
+ XmListSetBottomItem(list_,nodes_[next_]);
+ node *n = find(nodes_[next_++]);
+ if(n) n->command(cmd_.c_str());
+ update();
+}
+
+void collector::closeCB(Widget,XtPointer)
+{
+ // 201207 ABO warnings? XmListDeleteAllItems(list_);
+ XtUnmanageChild(form_);
+}
+
+void collector::entryCB(Widget,XtPointer data)
+{
+ XmRowColumnCallbackStruct *cb = (XmRowColumnCallbackStruct *) data;
+ xec_ReplaceTextSelection(text_,XtName(cb->widget),False);
+}
+
+bool collector::keep(node*)
+{
+ return true;
+}
+
+void collector::stopCB(Widget,XtPointer data)
+{
+ nodes_.clear();
+}
diff --git a/view/src/collector.h b/view/src/collector.h
new file mode 100644
index 0000000..18de3e9
--- /dev/null
+++ b/view/src/collector.h
@@ -0,0 +1,100 @@
+#ifndef collector_H
+#define collector_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#ifndef window_H
+#include "window.h"
+#endif
+
+#ifndef uicollector_H
+#include "uicollector.h"
+#endif
+
+#ifndef singleton_H
+#include "singleton.h"
+#endif
+
+#ifndef node_list_H
+#include "node_list.h"
+#endif
+
+#ifndef runnable_H
+#include "runnable.h"
+#endif
+
+#ifndef array_H
+#include "array.h"
+#endif
+
+#ifndef str_H
+#include "str.h"
+#endif
+
+#ifndef xmstring_H
+#include "xmstring.h"
+#endif
+
+class node;
+
+class collector : public collector_shell_c, public window,
+ public runnable,
+ public singleton<collector>, public node_list {
+public:
+
+ collector();
+
+ ~collector(); // Change to virtual if base class
+
+// -- Overridden methods
+
+ virtual Widget shell() { return _xd_rootwidget; }
+ virtual Widget list() { return list_; }
+ virtual Widget form() { return form_; }
+
+// -- Class members
+
+ static void show(node&);
+
+private:
+
+ collector(const collector&);
+ collector& operator=(const collector&);
+
+ str cmd_;
+ array<xmstring> nodes_;
+ int next_;
+
+ void update();
+ void send(const char*);
+
+ void run();
+
+ virtual void closeCB( Widget, XtPointer );
+ virtual void applyCB( Widget, XtPointer );
+ virtual void removeCB( Widget, XtPointer );
+ virtual void noneCB( Widget, XtPointer );
+ virtual void allCB( Widget, XtPointer );
+ virtual void selectCB( Widget, XtPointer );
+ virtual void entryCB( Widget, XtPointer );
+ virtual void stopCB( Widget, XtPointer );
+
+ virtual bool keep(node*);
+
+};
+
+inline void destroy(collector**) {}
+#endif
diff --git a/view/src/colors_prefs.cc b/view/src/colors_prefs.cc
new file mode 100644
index 0000000..37f40c4
--- /dev/null
+++ b/view/src/colors_prefs.cc
@@ -0,0 +1,24 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "colors_prefs.h"
+
+void colors_prefs::create(Widget w,char*)
+{
+ colors_form_c::create(w);
+ prefs::setup(w);
+}
+
+// static colors_prefs hp;
diff --git a/view/src/colors_prefs.h b/view/src/colors_prefs.h
new file mode 100644
index 0000000..e71706e
--- /dev/null
+++ b/view/src/colors_prefs.h
@@ -0,0 +1,47 @@
+#ifndef colors_prefs_H
+#define colors_prefs_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#ifndef prefs_H
+#include "prefs.h"
+#endif
+
+#ifndef uicolors
+#include "uicolors.h"
+#endif
+
+class colors_prefs : public prefs, public colors_form_c {
+public:
+
+ colors_prefs() {}
+
+ ~colors_prefs() {}
+
+ virtual Widget widget() { return _xd_rootwidget; }
+
+private:
+
+ colors_prefs(const colors_prefs&);
+ colors_prefs& operator=(const colors_prefs&);
+
+ virtual void changedCB( Widget w, XtPointer ) { pref_editor::changed(w); }
+ virtual void useCB( Widget w, XtPointer ) { pref_editor::use(w); }
+
+ virtual void create(Widget w,char*);
+};
+
+inline void destroy(colors_prefs**) {}
+#endif
diff --git a/view/src/configurable.cc b/view/src/configurable.cc
new file mode 100644
index 0000000..e30cd89
--- /dev/null
+++ b/view/src/configurable.cc
@@ -0,0 +1,23 @@
+#ifndef configurable_H
+#include "configurable.h"
+#endif
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+configurable::~configurable() {}
+
+void configurable::changed(resource&)
+{
+}
diff --git a/view/src/configurable.h b/view/src/configurable.h
new file mode 100644
index 0000000..353af50
--- /dev/null
+++ b/view/src/configurable.h
@@ -0,0 +1,38 @@
+#ifndef configurable_H
+#define configurable_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+class configurator;
+class resource;
+
+class configurable {
+public:
+ virtual ~configurable();
+ virtual void changed(resource&);
+
+#ifdef alpha
+ configurable(const char* name): name_(name) {}
+ const char* name() const { return name_; }
+private:
+ const char* name_;
+#else
+ virtual const char* name() const = 0;
+#endif
+};
+
+inline void destroy(configurable**) {}
+#endif
diff --git a/view/src/configurator.h b/view/src/configurator.h
new file mode 100644
index 0000000..99be923
--- /dev/null
+++ b/view/src/configurator.h
@@ -0,0 +1,128 @@
+#ifndef configurator_H
+#define configurator_H
+
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+// Headers
+// #ifndef machine_H
+// #include <machine.h>
+// #endif
+
+// Forward declarations
+
+// class ostream;
+// typedef class _Pvts os_typespec; // Remove if not persistant
+
+//
+
+template<class T>
+class option;
+
+class str;
+
+class configurator {
+public:
+
+// -- Exceptions
+ // None
+
+// -- Contructors
+
+ //configurator();
+
+// -- Destructor
+
+ //~configurator(); // Change to virtual if base class
+
+// -- Convertors
+ // None
+
+// -- Operators
+ // None
+
+// -- Methods
+ // None
+
+ virtual void init(resource&) = 0;
+ virtual bool modified(resource&) = 0;
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+ // Uncomment for persistent, remove otherwise
+ // static os_typespec* get_os_typespec();
+
+protected:
+
+// -- Members
+ // None
+
+// -- Methods
+
+ // void print(ostream&) const; // Change to virtual if base class
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+private:
+
+// No copy allowed
+
+// configurator(const configurator&);
+// configurator& operator=(const configurator&);
+
+// -- Members
+ // None
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+// -- Friends
+
+ //friend ostream& operator<<(ostream& s,const configurator& p)
+ // { p.print(s); return s; }
+
+};
+
+inline void destroy(configurator**) {}
+
+// If persistent, uncomment, otherwise remove
+//#ifdef _ODI_OSSG_
+//OS_MARK_SCHEMA_TYPE(configurator);
+//#endif
+
+#endif
diff --git a/view/src/confirm.cc b/view/src/confirm.cc
new file mode 100644
index 0000000..c9bd479
--- /dev/null
+++ b/view/src/confirm.cc
@@ -0,0 +1,44 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <stdio.h>
+#include <stdarg.h>
+#include "confirm.h"
+#include "gui.h"
+
+confirm::confirm()
+{
+ create(gui::top());
+}
+
+confirm::~confirm()
+{
+}
+
+Boolean confirm::ask(Boolean def_ok,const char* fmt,...)
+{
+ char buf[1024];
+ va_list arg;
+ va_start(arg,fmt);
+ vsprintf(buf,fmt,arg);
+ va_end(arg);
+
+ return instance().modal(buf, def_ok);
+}
+
+Boolean confirm::ask(Boolean def_ok,str& msg)
+{
+ return instance().modal(msg.c_str(), def_ok);
+}
diff --git a/view/src/confirm.h b/view/src/confirm.h
new file mode 100644
index 0000000..12ee595
--- /dev/null
+++ b/view/src/confirm.h
@@ -0,0 +1,40 @@
+#ifndef confirm_H
+#define confirm_H
+
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "uiconfirm.h"
+#include "dialog.h"
+#include "str.h"
+
+class confirm : public dialog<confirm,confirm_shell_c> {
+public:
+
+ confirm();
+
+ ~confirm(); // Change to virtual if base class
+
+ static Boolean ask(Boolean,const char*,...);
+ static Boolean ask(Boolean,str& msg);
+
+private:
+
+ confirm(const confirm&);
+ confirm& operator=(const confirm&);
+};
+
+inline void destroy(confirm**) {}
+#endif
diff --git a/view/src/counted.cc b/view/src/counted.cc
new file mode 100644
index 0000000..848f1f0
--- /dev/null
+++ b/view/src/counted.cc
@@ -0,0 +1,37 @@
+#ifndef counted_H
+#include "counted.h"
+#endif
+
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+counted::counted():
+ count_(0)
+{
+}
+
+counted::~counted()
+{
+}
+
+void counted::attach()
+{
+ count_++;
+}
+
+void counted::detach()
+{
+ if(--count_ == 0) delete this;
+}
diff --git a/view/src/counted.h b/view/src/counted.h
new file mode 100644
index 0000000..6f0ef34
--- /dev/null
+++ b/view/src/counted.h
@@ -0,0 +1,124 @@
+#ifndef counted_H
+#define counted_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+// Headers
+// #ifndef machine_H
+// #include <machine.h>
+// #endif
+
+// Forward declarations
+
+// class ostream;
+// typedef class _Pvts os_typespec; // Remove if not persistant
+
+//
+
+class counted {
+public:
+
+// -- Exceptions
+ // None
+
+// -- Contructors
+
+ counted();
+
+// -- Destructor
+
+
+// -- Convertors
+ // None
+
+// -- Operators
+ // None
+
+// -- Methods
+
+ void attach();
+ void detach();
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+ // Uncomment for persistent, remove otherwise
+ // static os_typespec* get_os_typespec();
+
+protected:
+
+ virtual ~counted(); // Change to virtual if base class
+
+// -- Members
+ // None
+
+// -- Methods
+
+ // void print(ostream&) const; // Change to virtual if base class
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+private:
+
+// No copy allowed
+
+ counted(const counted&);
+ counted& operator=(const counted&);
+
+// -- Members
+
+ int count_;
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+// -- Friends
+
+ //friend ostream& operator<<(ostream& s,const counted& p)
+ // { p.print(s); return s; }
+
+};
+
+inline void destroy(counted**) {}
+
+// If persistent, uncomment, otherwise remove
+//#ifdef _ODI_OSSG_
+//OS_MARK_SCHEMA_TYPE(counted);
+//#endif
+
+#endif
diff --git a/view/src/date.cc b/view/src/date.cc
new file mode 100644
index 0000000..e8c9c03
--- /dev/null
+++ b/view/src/date.cc
@@ -0,0 +1,106 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #11 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "date.h"
+#include "ecf_node.h"
+
+date_node::date_node(host& h,ecf_node* n) : node(h,n) {
+ if (!n) return;
+ full_name_ = parent()->full_name();
+ full_name_ += ":";
+ if (n) full_name_ += n->toString();
+}
+
+#ifdef BRIDGE
+static char *week[] = {
+ (char*)"sunday", (char*)"monday",(char*)"tuesday",(char*)"wednesday",(char*)"thursday",
+ (char*)"friday",(char*)"saturday"};
+
+date_node::date_node(host& h,sms_node* n, char b)
+ : node(h,n,b)
+{}
+#endif
+
+char* date_node::string(char *s)
+{
+ char buf[1024];
+ s[0] = 0;
+ if (owner_)
+ snprintf(buf, 1024, "%s", owner_->toString().c_str());
+#ifdef BRIDGE
+ if (tree_) {
+ sms_date *d = (sms_date*)tree_;
+
+ char buf[1024];
+ s[0] = 0;
+
+ if(d->weekdays)
+ {
+ int flg = 0;
+ for( int i=0 ; i<DAY_MAX ; i++ )
+ if( d->weekdays & ( 1<<i ) )
+ {
+ if(flg) {
+ strcat(s," ");
+ }
+ strcat(s,week[i]);
+ flg++;
+ }
+ } else {
+ sprintf(buf,d->day<0?"*":"%02d",d->day);
+ strcat(s,buf);
+ strcat(s,".");
+
+ sprintf(buf,d->month<0?"*":"%02d",d->month);
+ strcat(s,buf);
+ strcat(s,".");
+
+ sprintf(buf,d->year<0?"*":"%02d",d->year+1900);
+ strcat(s,buf);
+ }
+ return s;
+ }
+ else
+#endif
+ strcat(s,buf);
+ return s;
+}
+
+xmstring date_node::make_label_tree()
+{
+ char buf[1024];
+ return xmstring(string(buf));
+}
+
+void date_node::perlify(FILE* f)
+{
+ char buf[1034];
+ perl_member(f,"value",string(buf));
+}
+
+node* date_node::graph_node()
+{
+ return &dummy_node::get(full_name());
+}
+
+const std::string& date_node::name() const
+{
+ static std::string date_ = "date";
+#ifdef BRIDGE
+ if (tree_) return date_;
+#endif
+ if (owner_) date_ = owner_->name();
+ return date_;
+}
diff --git a/view/src/date.h b/view/src/date.h
new file mode 100644
index 0000000..0da7ef7
--- /dev/null
+++ b/view/src/date.h
@@ -0,0 +1,48 @@
+#ifndef DATE_H
+#define DATE_H
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #10 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "node.h"
+#include "show.h"
+#include "dummy_node.h"
+#
+class date_node : public node {
+
+ std::string full_name_;
+ virtual bool is_my_parent(node*) const { return false; }
+ virtual void info(std::ostream&) {}
+
+ virtual xmstring make_label_tree();
+ virtual xmstring make_label_trigger() { return make_label_tree(); }
+
+ virtual const std::string& name() const;
+ const std::string& full_name() const {return full_name_; }
+ virtual Boolean menus() { return False; }
+ virtual Boolean selectable() { return False; }
+
+ virtual Boolean visible() const { return show::want(show::date); }
+ virtual node* graph_node();
+ char* string(char*);
+
+ virtual void perlify(FILE*);
+
+public:
+ date_node(host& h,ecf_node* n);
+#ifdef BRIDGE
+ date_node(host& h,sms_node* n, char b);
+#endif
+};
+#endif
diff --git a/view/src/depend.cc b/view/src/depend.cc
new file mode 100644
index 0000000..789f0ef
--- /dev/null
+++ b/view/src/depend.cc
@@ -0,0 +1,72 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "depend.h"
+#include "host.h"
+#include "runnable.h"
+#include <Xm/List.h>
+#include <Xm/Text.h>
+#include <Xm/ToggleB.h>
+#include <Xm/PushB.h>
+#include "gui.h"
+#include "extent.h"
+#include "flags.h"
+#include "pixmap.h"
+#include "result.h"
+#include <X11/IntrinsicP.h>
+#include <stdarg.h>
+
+extern "C" {
+#include "xec.h"
+}
+
+depend::depend()
+{
+ _xd_rootwidget = 0;
+}
+
+depend::~depend()
+{
+ if(_xd_rootwidget)
+ XtDestroyWidget(_xd_rootwidget);
+}
+
+void depend::closeCB(Widget,XtPointer)
+{
+ hide();
+}
+
+void depend::hide()
+{
+ if(_xd_rootwidget) {
+ XtUnmanageChild(form_);
+ }
+}
+
+void depend::make(Widget top)
+{
+ while(!XtIsShell(top))
+ top = XtParent(top);
+
+ if(!_xd_rootwidget)
+ depend_shell_c::create(top);
+}
+
+void depend::raise(Widget top)
+{
+ make(top);
+ XtManageChild(form_);
+ XMapRaised(XtDisplay(_xd_rootwidget),XtWindow(_xd_rootwidget));
+}
diff --git a/view/src/depend.h b/view/src/depend.h
new file mode 100644
index 0000000..bd19a15
--- /dev/null
+++ b/view/src/depend.h
@@ -0,0 +1,126 @@
+#ifndef depend_H
+#define depend_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+// Headers
+// #ifndef machine_H
+// #include <machine.h>
+// #endif
+
+// Forward declarations
+
+// class ostream;
+// typedef class _Pvts os_typespec; // Remove if not persistant
+
+class host;
+//
+
+#include "uidepend.h"
+
+
+class depend : public depend_shell_c {
+public:
+
+// -- Exceptions
+ // None
+
+// -- Contructors
+
+ depend();
+
+// -- Destructor
+
+ ~depend(); // Change to virtual if base class
+
+// -- Convertors
+ // None
+
+// -- Operators
+
+ void make(Widget);
+ void raise(Widget);
+ void hide();
+
+// -- Methods
+
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+
+
+protected:
+
+// -- Members
+ // None
+
+// -- Methods
+
+ // void print(ostream&) const; // Change to virtual if base class
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+private:
+
+// No copy allowed
+
+ depend(const depend&);
+ depend& operator=(const depend&);
+
+// -- Members
+
+
+// -- Methods
+
+
+
+// -- Overridden methods
+
+
+// -- Class members
+
+
+// -- Class methods
+
+ void closeCB(Widget,XtPointer);
+
+// -- Friends
+
+ //friend ostream& operator<<(ostream& s,const depend& p)
+ // { p.print(s); return s; }
+
+};
+
+inline void destroy(depend**) {}
+
+// If persistent, uncomment, otherwise remove
+//#ifdef _ODI_OSSG_
+//OS_MARK_SCHEMA_TYPE(depend);
+//#endif
+
+#endif
diff --git a/view/src/dialog.cc b/view/src/dialog.cc
new file mode 100644
index 0000000..4970526
--- /dev/null
+++ b/view/src/dialog.cc
@@ -0,0 +1,83 @@
+#ifndef dialog_H
+#include "dialog.h"
+#endif
+
+#ifndef SVR4
+#include <stdio.h>
+#endif
+
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+extern "C" {
+#include "xec.h"
+}
+
+
+template<class T,class U>
+void dialog<T,U>::helpCB( Widget, XtPointer )
+{
+}
+
+template<class T,class U>
+void dialog<T,U>::cancelCB( Widget, XtPointer )
+{
+ ok_ = False;
+ stop_ = True;
+}
+
+template<class T,class U>
+void dialog<T,U>::okCB( Widget, XtPointer )
+{
+ ok_ = True;
+ stop_ = True;
+}
+
+
+template<class T,class U>
+Boolean dialog<T,U>::modal(const char* message,Boolean def_ok)
+{
+ XtVaSetValues(this->form_,
+ XmNdefaultButtonType,
+ (def_ok? XmDIALOG_OK_BUTTON : XmDIALOG_CANCEL_BUTTON),
+ NULL);
+
+ if(message)
+ xec_SetLabel(this->label_,message);
+
+ XtManageChild(this->form_);
+
+ stop_ = False;
+
+ XEvent event_node;
+ XtAppContext ac = XtWidgetToApplicationContext(this->form_);
+
+ while(!stop_)
+ {
+ XtAppNextEvent(ac,&event_node);
+ XtDispatchEvent(&event_node);
+ }
+
+ XtUnmanageChild(this->form_);
+
+ return ok_;
+}
+
+template<class T,class U>
+void dialog<T,U>::show()
+{
+ XtManageChild(this->form_);
+}
diff --git a/view/src/dialog.h b/view/src/dialog.h
new file mode 100644
index 0000000..698096b
--- /dev/null
+++ b/view/src/dialog.h
@@ -0,0 +1,50 @@
+#ifndef dialog_H
+#define dialog_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#ifndef singleton_H
+#include "singleton.h"
+#endif
+
+template<class T,class U>
+class dialog : public U, public singleton<T> {
+public:
+
+ dialog() : stop_(True), ok_(False) {}
+
+protected:
+
+ Boolean stop_;
+ Boolean ok_;
+
+ Boolean modal(const char*,Boolean);
+ void show();
+
+private:
+
+ dialog(const dialog<T,U>&);
+ dialog<T,U>& operator=(const dialog<T,U>&);
+
+ virtual void helpCB( Widget, XtPointer ) ;
+ virtual void cancelCB( Widget, XtPointer ) ;
+ virtual void okCB( Widget, XtPointer ) ;
+};
+
+#if defined(__GNUC__) || defined(hpux) || defined(_AIX)
+#include "dialog.cc"
+#endif
+#endif
diff --git a/view/src/directory.cc b/view/src/directory.cc
new file mode 100644
index 0000000..d8fb243
--- /dev/null
+++ b/view/src/directory.cc
@@ -0,0 +1,72 @@
+#ifndef directory_H
+#include "directory.h"
+#endif
+
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #8 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include "ecflowview.h"
+
+
+const char* directory::user()
+{
+ static char x[1024] = {0};
+ if(x[0] == 0)
+ {
+ const char * rcdir = getenv("ECFLOWRC");
+ if (rcdir)
+ sprintf(x,"%s",rcdir);
+ else
+ sprintf(x,"%s/.%s",getenv("HOME"),"ecflowrc");
+ mkdir(x,0755);
+ fprintf(stdout, "# rcdir: %s\n", x);
+ }
+ return x;
+}
+
+// ECFLOW_SHARED_DIR is a define, where 'server'file is installed
+const char* directory::system()
+{
+ static char x[1024] = {0};
+ if(x[0] == 0) {
+ if(getenv("ECFLOWVIEW_HOME"))
+ strcpy(x,getenv("ECFLOWVIEW_HOME"));
+ else
+ strcpy(x,ECFLOW_SHARED_DIR);
+ }
+
+ //std::cout << "system dir = " << x << "\n";
+ return x;
+}
+
+
+FILE* directory::open(const char* name,const char *mode)
+{
+ FILE* f = 0;
+ char buf[1024];
+
+ sprintf(buf,"%s/%s",user(),name);
+ f = fopen(buf,mode);
+ if(f || *mode != 'r') return f;
+
+ sprintf(buf,"%s/%s",system(),name);
+ return fopen(buf,mode);
+}
diff --git a/view/src/directory.h b/view/src/directory.h
new file mode 100644
index 0000000..d334f2b
--- /dev/null
+++ b/view/src/directory.h
@@ -0,0 +1,40 @@
+#ifndef directory_H
+#define directory_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include <stdio.h>
+
+class directory {
+public:
+
+ directory();
+
+ ~directory(); // Change to virtual if base class
+
+ static FILE* open(const char*,const char*);
+ static const char* user();
+ static const char* system();
+
+private:
+
+ directory(const directory&);
+ directory& operator=(const directory&);
+
+};
+
+inline void destroy(directory**) {}
+#endif
diff --git a/view/src/doer.sh b/view/src/doer.sh
new file mode 100644
index 0000000..b9decee
--- /dev/null
+++ b/view/src/doer.sh
@@ -0,0 +1,29 @@
+#!/bin/ksh
+#=============================================================================================
+# Name :
+# Author :
+# Revision : $Revision: #3 $
+#
+# Copyright 2009-2016 ECMWF.
+# This software is licensed under the terms of the Apache Licence version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+#
+# Description :
+#=============================================================================================
+
+return
+function call {
+grep -l sms_node * > sms_node.list
+
+for f in `cat sms_node.list`; do
+ cat $f | sed -e 's:sms_node:ecf_node:' > ${f}.tmp; ;
+ mv ${f} ${f}.orig;
+ mv ${f}.tmp ${f};
+done
+
+ clear; ./env.sh cc 2>&1 | head -50
+
+}
diff --git a/view/src/dummy_node.cc b/view/src/dummy_node.cc
new file mode 100644
index 0000000..2e06c0f
--- /dev/null
+++ b/view/src/dummy_node.cc
@@ -0,0 +1,58 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #15 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "dummy_node.h"
+#include "host.h"
+
+#ifndef ecf_node_
+#include "ecf_node.h"
+#endif
+#include <boost/shared_ptr.hpp>
+
+static node* head_ = 0;
+static const std::string id = "(dummy_node)";
+const std::string dummy_node::toString() const { return id; }
+
+dummy_node::dummy_node(const std::string name)
+ : node(host::dummy(),0)
+ , name_ (name)
+{
+ next_ = head_;
+ head_ = this;
+ owner_ = new ecf_concrete_node<dummy_node> (this, 0);
+}
+
+dummy_node::~dummy_node()
+{
+}
+
+dummy_node& dummy_node::get(const std::string name)
+{
+ node* e = head_;
+ while(e) {
+ if(name == e->name())
+ return * (dummy_node*) e;
+ e = e->next();
+ }
+ return *(new dummy_node(name));
+}
+
+void dummy_node::info(std::ostream&)
+{
+}
+
+void dummy_node::perlify(FILE* f)
+{
+}
diff --git a/view/src/dummy_node.h b/view/src/dummy_node.h
new file mode 100644
index 0000000..9551b88
--- /dev/null
+++ b/view/src/dummy_node.h
@@ -0,0 +1,53 @@
+#ifndef dummy_node_H
+#define dummy_node_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #11 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "node.h"
+
+class dummy_node : public node {
+public:
+
+ dummy_node(const std::string);
+ ~dummy_node(); // Change to virtual if base class
+
+ virtual Boolean menus() { return False; }
+ virtual Boolean selectable() { return False; }
+ virtual const std::string& full_name() const { return name();}
+ virtual const std::string& name() const { return name_; }
+ virtual void info(std::ostream&);
+
+ const std::string toString() const;
+ virtual const char* type_name() const { return "dummy_node"; }
+ virtual const char* status_name() const { return "unknown"; }
+ virtual std::ostream& print(std::ostream&s) const { return s << "dummy_node\n";};
+
+ static dummy_node& get(const std::string);
+private:
+
+ dummy_node(const dummy_node&);
+ dummy_node& operator=(const dummy_node&);
+
+ const std::string name_;
+ // int type_;
+ int type() const { return NODE_UNKNOWN; }
+ //int status_;
+ virtual void perlify(FILE*);
+};
+
+inline void destroy(dummy_node**) {}
+
+#endif
diff --git a/ecflow_4_0_7/view/src/ecf.cmd b/view/src/ecf.cmd
similarity index 100%
rename from ecflow_4_0_7/view/src/ecf.cmd
rename to view/src/ecf.cmd
diff --git a/view/src/ecf_node.cc b/view/src/ecf_node.cc
new file mode 100644
index 0000000..9ac75db
--- /dev/null
+++ b/view/src/ecf_node.cc
@@ -0,0 +1,1497 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #114 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "ecf_node.h"
+#include "host.h"
+#include "node.h"
+#include "tree.h"
+#include "NodeAttr.hpp"
+#include "Variable.hpp"
+#include "dummy_node.h"
+#include "external.h"
+#include <Str.hpp>
+#ifndef NODE_MAX
+#define NODE_MAX 41
+#endif
+
+#include <iostream>
+#include <locale>
+#include <string>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/date_time/posix_time/posix_time_io.hpp>
+static int nb_tasks = 0;
+static int nb_attrs = 0;
+static char* info_label = getenv("ECFLOWVIEW_INFO_LABEL");
+
+std::map<std::string, ecf_node_maker*>& ecf_node_maker::map()
+{
+ static std::map<std::string, ecf_node_maker*> map_;
+ return map_;
+}
+
+std::vector<ecf_node_maker*>& ecf_node_maker::builders()
+{
+ static std::vector<ecf_node_maker*> builders_((size_t) NODE_MAX, (ecf_node_maker*) 0);
+ return builders_;
+}
+
+void ecf_node::counter()
+{
+ int count = 0;
+ node* n = 0x0;
+ if (node_) n = node_->kids();
+ while ( n ) {
+ std::cerr << "# " << n->full_name() << " " << n->type() << "\n";
+ n = n->next();
+ count++;
+ }
+ if (count) {
+ std::cerr << "# " << full_name() << " kids: " << count << "\n";
+ }
+}
+
+void ecf_node::update( const Node* n, const std::vector<ecf::Aspect::Type>& )
+{
+ if (!node_) return;
+ /* ok node create through node replace is simple update */
+ node_->update(-1, -1, -1);
+ node_->notify_observers();
+ node_->redraw();
+}
+
+int convert( NState::State state )
+{
+ int rc = STATUS_UNKNOWN;
+ switch ( state ) {
+ case NState::UNKNOWN:
+ rc = STATUS_UNKNOWN;
+ break;
+ case NState::COMPLETE:
+ rc = STATUS_COMPLETE;
+ break;
+ case NState::QUEUED:
+ rc = STATUS_QUEUED;
+ break;
+ case NState::ABORTED:
+ rc = STATUS_ABORTED;
+ break;
+ case NState::SUBMITTED:
+ rc = STATUS_SUBMITTED;
+ break;
+ case NState::ACTIVE:
+ rc = STATUS_ACTIVE;
+ break;
+ default:
+ rc = STATUS_UNKNOWN;
+ break;
+ }
+ return rc;
+}
+
+int convert( DState::State state )
+{
+ int rc = STATUS_UNKNOWN;
+ switch ( state ) {
+ case DState::UNKNOWN:
+ rc = STATUS_UNKNOWN;
+ break;
+ case DState::COMPLETE:
+ rc = STATUS_COMPLETE;
+ break;
+ case DState::QUEUED:
+ rc = STATUS_QUEUED;
+ break;
+ case DState::ABORTED:
+ rc = STATUS_ABORTED;
+ break;
+ case DState::SUBMITTED:
+ rc = STATUS_SUBMITTED;
+ break;
+ case DState::ACTIVE:
+ rc = STATUS_ACTIVE;
+ break;
+ default:
+ rc = STATUS_UNKNOWN;
+ break;
+ }
+ return rc;
+}
+
+void ecf_node::update( const Defs*, const std::vector<ecf::Aspect::Type>& )
+{
+ if (!node_) return;
+ node_->update(-1, -1, -1);
+ node_->notify_observers();
+ node_->redraw();
+}
+
+void ecf_node::update_delete( const Node* n )
+{
+ if (!node_) return;
+ node_->unlink();
+ node *parent = node_->parent();
+ node_->visibility(False);
+ node_->remove();
+ delete node_;
+ node_ = 0x0;
+ notify_observers();
+ if (parent) {
+ parent->folded_ = true;
+ parent->update(-1, -1, -1);
+ parent->notify_observers();
+ parent->redraw();
+ }
+}
+
+void ecf_node::update_delete( const Defs* n )
+{
+ if (node_) node_->unlink();
+ node_ = 0x0;
+ notify_observers();
+}
+
+void ecf_node::unlink( bool detach )
+{
+ if (detach) {
+ }
+ else if (node_) node_->unlink();
+ node_ = 0x0;
+}
+
+const Repeat& ecf_node::crd()
+{
+ static const Repeat REPEAT = Repeat(RepeatInteger("PRB", 1, 1, 1));
+ return REPEAT;
+}
+
+node* ecf_node_maker::make_xnode( host& h, ecf_node* n, std::string type )
+{
+ if (!n) return NULL;
+ node* out = NULL;
+
+ if (n->type() >= 0 && n->type() < NODE_MAX && builders()[n->type()]) {
+ if (n->type() == NODE_REPEAT) out = map()[type]->make(h, n);
+ else out = builders()[n->type()]->make(h, n);
+ n->set_graphic_ptr(out);
+ }
+ else {
+ std::cout << "!!!" << n->full_name() << n->type() << " " << n->name() << " " << n->type_name()
+ << "\n";
+ if (map()[type]) {
+ out = map()[type]->make(h, n);
+ assert(out);
+ n->set_graphic_ptr(out);
+ std::cout << "!!!ok\n";
+ }
+ }
+ return out;
+}
+
+ecf_node::ecf_node( ecf_node* parent, const std::string& name, char k ) :
+ parent_(parent), node_(0), kind_(k), name_(name), trigger_(0), complete_(0)
+{
+}
+
+ecf_node::~ecf_node()
+{
+ // std::cerr << "# eode del: " << full_name_ << std::endl;
+ nokids(true);
+ unlink();
+ delete trigger_;
+ delete complete_;
+}
+
+node* ecf_node::create_tree( host& h, node* xnode )
+{
+ if (xnode) {
+ node_ = xnode;
+ }
+ else if (node_) return node_;
+ else if (!(node_ = create_node(h))) {
+ return 0x0;
+ }
+ if (get_node()) get_node()->set_graphic_ptr(node_);
+
+ for(std::vector<ecf_node*>::const_iterator j = kids_.begin(); j != kids_.end(); ++j)
+ if (*j) node_->insert((*j)->create_tree(h, 0x0));
+
+ return node_;
+}
+
+void ecf_node::add_kid( ecf_node* k )
+{
+ if (k) {
+ kids_.push_back(k);
+
+ if (k->type() == NODE_TASK) {
+ nb_tasks++;
+ // kids_.push_back(make_node(new Label("time", to_simple_string(k->status_time())), k));
+ } else if (k->type() == NODE_FAMILY) {}
+ else nb_attrs++;
+ }
+}
+
+template<> const std::string& ecf_concrete_node<Defs>::name() const
+{
+ return ecf_node::slash();
+}
+
+template<>
+void ecf_concrete_node<Node>::why( std::ostream&f ) const
+{
+ if (!owner_) return;
+ std::vector<std::string> theReasonWhy;
+ std::vector<std::string>::const_iterator it;
+ owner_->bottom_up_why(theReasonWhy);
+ for(it = theReasonWhy.begin(); it != theReasonWhy.end(); ++it)
+ f << (*it) << "\n";
+}
+
+template<>
+void ecf_concrete_node<Suite>::why( std::ostream &f ) const
+{
+ if (!owner_) return;
+ std::vector<std::string> theReasonWhy;
+ std::vector<std::string>::const_iterator it;
+ owner_->bottom_up_why(theReasonWhy);
+ for(it = theReasonWhy.begin(); it != theReasonWhy.end(); ++it)
+ f << (*it) << "\n";
+}
+
+template<>
+void ecf_concrete_node<Defs>::why( std::ostream &f ) const
+{
+ if (!owner_) return;
+ std::vector<std::string> theReasonWhy;
+ std::vector<std::string>::const_iterator it;
+ owner_->why(theReasonWhy);
+ for(it = theReasonWhy.begin(); it != theReasonWhy.end(); ++it)
+ f << (*it) << "\n";
+}
+
+#define UNLINK(T) template<> void ecf_concrete_node<T>::unlink(bool detach) \
+{ if (!owner_) return; if (detach) owner_->detach(this); owner_ = 0x0; }
+UNLINK(Alias)
+UNLINK(Task)
+UNLINK(Family)
+UNLINK(Suite)
+UNLINK(Node)
+UNLINK(Defs)
+#undef UNLINK
+
+#define SORT_VAR 1
+#ifdef SORT_VAR
+struct cless_than {
+ inline bool operator()( const Variable& v1, const Variable& v2 )
+ {
+ return (v1.name() < v2.name());
+ }
+};
+#endif
+
+template<>
+void ecf_concrete_node<Alias>::make_subtree()
+{
+
+ if (!owner_) return;
+ Alias* n = owner_;
+
+ full_name_ = owner_->absNodePath();
+
+ owner_->attach(this);
+ n->update_generated_variables();
+
+ std::vector<Variable> gvar;
+ n->gen_variables(gvar);
+ std::vector<Variable>::const_iterator it;
+#ifdef SORT_VAR
+ std::sort(gvar.begin(), gvar.end(), cless_than());
+#endif
+
+ for(it = gvar.begin(); it != gvar.end(); ++it)
+ if ((*it).name() == "" || !(*it == Variable::EMPTY())) add_kid(make_node(*it, this, 'g'));
+ else std::cerr << "# empty variable\n";
+
+#ifdef SORT_VAR
+ gvar = n->variables(); /* expensive */
+ std::sort(gvar.begin(), gvar.end(), cless_than());
+ make_kids_list(this, gvar);
+#else
+ make_kids_list(this,n->variables());
+#endif
+
+ make_kids_list(this, n->labels());
+ make_kids_list(this, n->events());
+ make_kids_list(this, n->meters());
+}
+
+template<>
+void ecf_concrete_node<Node>::make_subtree()
+{
+
+ if (!owner_) return;
+ Node* n = owner_;
+
+ full_name_ = owner_->absNodePath();
+ owner_->attach(this);
+
+ if (owner_->suite()->begun()) owner_->update_generated_variables();
+
+ std::vector<node_ptr> kids;
+ n->immediateChildren(kids);
+ make_kids_list(this, kids);
+
+ std::vector<Variable> gvar;
+ n->gen_variables(gvar);
+#ifdef SORT_VAR
+ std::sort(gvar.begin(), gvar.end(), cless_than());
+#endif
+
+ std::vector<Variable>::const_iterator it;
+ for(it = gvar.begin(); it != gvar.end(); ++it)
+ if (!(*it == Variable::EMPTY()))
+ add_kid(make_node(*it, this, 'g'));
+ else std::cerr << "# empty variable\n";
+
+#ifdef SORT_VAR
+ gvar = n->variables(); /* expensive */
+ std::sort(gvar.begin(), gvar.end(), cless_than());
+ make_kids_list(this, gvar);
+#else
+ make_kids_list(this,n->variables());
+#endif
+
+ make_kids_list(this, n->labels());
+ make_kids_list(this, n->events());
+ make_kids_list(this, n->meters());
+
+ make_kids_list(this, n->timeVec());
+ make_kids_list(this, n->todayVec());
+ make_kids_list(this, n->crons());
+
+ make_kids_list(this, n->dates());
+ make_kids_list(this, n->days());
+
+ make_kids_list(this, n->limits());
+ make_kids_list(this, n->inlimits());
+
+ if (n->get_trigger()) {
+ trigger_ = new ExpressionWrapper(n, 't');
+ add_kid(make_node(trigger_, this, 't'));
+ }
+ if (n->get_complete()) {
+ complete_ = new ExpressionWrapper(n, 'c');
+ add_kid(make_node(complete_, this, 'c'));
+ }
+
+ if (n->get_late() != 0x0) {
+ add_kid(make_node(n->get_late(), this));
+ }
+
+ if ((!n->repeat().empty()) && "" != n->repeat().name()) {
+ RepeatEnumerated *re;
+ RepeatDate *rd;
+ RepeatString *rs;
+ RepeatInteger *ri;
+ RepeatDay *rday;
+
+ if ((re = dynamic_cast<RepeatEnumerated *>(n->repeat().repeatBase()))) add_kid(
+ make_node(re, this));
+ else if ((rd = dynamic_cast<RepeatDate *>(n->repeat().repeatBase()))) add_kid(
+ make_node(rd, this));
+ else if ((rs = dynamic_cast<RepeatString *>(n->repeat().repeatBase()))) add_kid(
+ make_node(rs, this));
+ else if ((ri = dynamic_cast<RepeatInteger *>(n->repeat().repeatBase()))) add_kid(
+ make_node(ri, this));
+ else if ((rday = dynamic_cast<RepeatDay *>(n->repeat().repeatBase()))) {
+ }
+ else std::cerr << "# ecflfowview does not recognises this repeat item\n";
+ }
+}
+
+template<>
+void ecf_concrete_node<Suite>::make_subtree()
+{
+
+ if (!owner_) return;
+ Suite* n = owner_;
+
+ nb_tasks = 0;
+ nb_attrs = 0;
+
+ if (n->begun()) n->update_generated_variables();
+
+ full_name_ = owner_->absNodePath(); // "/" + n->name();
+
+ owner_->attach(this);
+
+ std::vector<node_ptr> kids;
+ n->immediateChildren(kids);
+ make_kids_list(this, kids);
+
+ std::vector<Variable> gvar;
+ n->gen_variables(gvar);
+
+ std::vector<Variable>::const_iterator it;
+ for(it = gvar.begin(); it != gvar.end(); ++it)
+ if (!(*it == Variable::EMPTY()))
+ add_kid(make_node(*it, this, 'g'));
+ else std::cerr << "# empty variable\n";
+
+ std::string info = "";
+#ifdef SORT_VAR
+ gvar = n->variables(); /* expensive */
+ std::sort(gvar.begin(), gvar.end(), cless_than());
+ make_kids_list(this, gvar);
+ if (info_label) for(it = gvar.begin(); it != gvar.end(); ++it) {
+ // if ((*it).name().find("HOST") != std::string::npos) info += ", " + (*it).theValue(); else
+ if ("ECF_JOB_CMD" == (*it).name() || "HOST" == (*it).name() || "WSHOST" == (*it).name()
+ || "SCHOST" == (*it).name()) info += ", " + (*it).theValue();
+ }
+#else
+ make_kids_list(this,n->variables());
+#endif
+
+ make_kids_list(this, n->labels());
+ make_kids_list(this, n->events());
+ make_kids_list(this, n->meters());
+
+ make_kids_list(this, n->timeVec());
+ make_kids_list(this, n->todayVec());
+ make_kids_list(this, n->crons());
+
+ make_kids_list(this, n->dates());
+ make_kids_list(this, n->days());
+
+ make_kids_list(this, n->limits());
+ make_kids_list(this, n->inlimits());
+
+ if (n->get_trigger()) {
+ trigger_ = new ExpressionWrapper(n, 't');
+ add_kid(make_node(trigger_, this, 't'));
+ }
+ if (n->get_complete()) {
+ complete_ = new ExpressionWrapper(n, 'c');
+ add_kid(make_node(complete_, this, 'c'));
+ }
+
+ if (n->get_late() != 0x0) {
+ add_kid(make_node(n->get_late(), this));
+ }
+ if ((!n->repeat().empty())) {
+ RepeatEnumerated *re;
+ RepeatDate *rd;
+ RepeatString *rs;
+ RepeatInteger *ri;
+ RepeatDay *rday;
+
+ if ((re = dynamic_cast<RepeatEnumerated *>(n->repeat().repeatBase()))) add_kid(
+ make_node(re, this));
+ else if ((rd = dynamic_cast<RepeatDate *>(n->repeat().repeatBase()))) add_kid(
+ make_node(rd, this));
+ else if ((rs = dynamic_cast<RepeatString *>(n->repeat().repeatBase()))) add_kid(
+ make_node(rs, this));
+ else if ((ri = dynamic_cast<RepeatInteger *>(n->repeat().repeatBase()))) add_kid(
+ make_node(ri, this));
+ else if ((rday = dynamic_cast<RepeatDay *>(n->repeat().repeatBase()))) add_kid(
+ make_node(rday, this));
+ else std::cerr << "# ecflfowview does not recognises this repeat item\n";
+ }
+
+ /* INT-67 */
+ if (info_label) try {
+ char msg[400];
+ snprintf(msg, 400, "nb_tasks %d, nb_attrs %d%s", nb_tasks, nb_attrs, info.c_str());
+ const Label * labt = new Label("info", msg);
+ add_kid(make_node(labt, this));
+ XECFDEBUG {
+ std::cout << "#MSG suite " << this->name() << msg << "\n";
+ }
+ }
+ catch ( ... ) {
+ }
+}
+
+template<>
+const std::string& ecf_concrete_node<Defs>::variable( const std::string& name ) const
+{
+ Defs* n = owner_;
+ if (!n) return ecf_node::none();
+
+ const Variable & var = owner_->server().findVariable(name);
+ if (!var.empty()) return var.theValue();
+
+ return ecf_node::none();
+}
+
+template<>
+const std::string& ecf_concrete_node<Node>::variable( const std::string& name ) const
+{
+ if (!owner_) return ecf_node::none();
+
+ const Variable & var = owner_->findVariable(name);
+ if (!var.empty()) return var.theValue();
+
+ return ecf_node::none();
+}
+
+template<>
+const std::string& ecf_concrete_node<Suite>::variable( const std::string& name ) const
+{
+ if (!owner_) return ecf_node::none();
+
+ const Variable& var = owner_->findVariable(name);
+ if (!var.empty()) return var.theValue();
+
+ return ecf_node::none();
+}
+
+template<> ecf_concrete_node<const Variable>::ecf_concrete_node( const Variable *owner,
+ ecf_node *parent, const char c ) :
+ ecf_node(parent, owner->name(), c), owner_(owner)
+{
+}
+
+template<>
+const std::string& ecf_concrete_node<const Event>::full_name() const
+{
+ full_name_ = parent()->full_name();
+ full_name_ += ":";
+ full_name_ += name();
+ return full_name_;
+}
+template<>
+const std::string& ecf_concrete_node<const Meter>::full_name() const
+{
+ full_name_ = parent()->full_name();
+ full_name_ += ":";
+ full_name_ += name();
+ return full_name_;
+}
+template<>
+const std::string& ecf_concrete_node<const Repeat>::full_name() const
+{
+ full_name_ = parent()->full_name();
+ full_name_ += ":";
+ full_name_ += name();
+ return full_name_;
+}
+template<>
+const std::string& ecf_concrete_node<const Variable>::full_name() const
+{
+ full_name_ = parent()->full_name();
+ full_name_ += ":";
+ full_name_ += name();
+ return full_name_;
+}
+
+template<>
+const std::string& ecf_concrete_node<const std::pair<std::string, std::string> >::full_name() const
+{
+ full_name_ = parent()->full_name();
+ full_name_ += ":";
+ full_name_ += name();
+ return full_name_;
+}
+
+template<>
+ecf_concrete_node<const std::pair<std::string, std::string> >::ecf_concrete_node(
+ const std::pair<std::string, std::string> *owner, ecf_node *parent, const char c ) :
+ ecf_node(parent, owner->first, c), owner_(owner)
+{
+}
+
+template<>
+std::ostream& ecf_concrete_node<Defs>::print( std::ostream& s ) const
+{
+ if (owner_) owner_->print(s);
+ return s;
+}
+
+template<>
+std::ostream& ecf_concrete_node<Node>::print( std::ostream& s ) const
+{
+ if (owner_) owner_->print(s);
+ return s;
+}
+
+template<> void ecf_concrete_node<Defs>::print( std::ostream& s )
+{
+}
+template<> void ecf_concrete_node<Node>::print( std::ostream& s )
+{
+}
+
+template<> const std::string& ecf_concrete_node<Defs>::full_name() const
+{
+ return ecf_node::slash();
+}
+
+void hide( node* n )
+{
+ while ( n ) {
+ n->visibility(False);
+ hide(n->kids());
+ n = n->next();
+ }
+}
+
+void ecf_node::nokids( bool own )
+{
+ if (node_) {
+ node::destroy(node_->kids_);
+ node_->kids_ = 0x0;
+ }
+
+ for(size_t i = 0; i < kids_.size(); i++) {
+ delete kids_[i];
+ }
+ kids_.clear();
+}
+
+int redraw_kids( node* node_, const std::vector<ecf::Aspect::Type>& aspect )
+{
+ int tot = 0;
+ for(std::vector<ecf::Aspect::Type>::const_iterator it = aspect.begin(); it != aspect.end();
+ ++it) {
+ int kind = 0;
+ switch ( *it ) {
+ case ecf::Aspect::METER:
+ kind = NODE_METER;
+ break;
+ case ecf::Aspect::EVENT:
+ kind = NODE_EVENT;
+ break;
+ case ecf::Aspect::LABEL:
+ kind = NODE_LABEL;
+ break;
+ case ecf::Aspect::LIMIT:
+ kind = NODE_LIMIT;
+ break;
+ case ecf::Aspect::REPEAT:
+ kind = NODE_REPEAT;
+ // node_->update(-1, -1, -1); node_->redraw(); break;
+ case ecf::Aspect::STATE:
+ node_->update(-1, -1, -1);
+ node_->redraw();
+ kind = NODE_FAMILY;
+ break;
+ case ecf::Aspect::SERVER_VARIABLE:
+#undef NODE_VARIABLE
+ case ecf::Aspect::NODE_VARIABLE:
+#define NODE_VARIABLE 3
+ kind = NODE_VARIABLE;
+ default:
+ continue;
+ }
+ ++tot;
+ if (kind) {
+ node_->update(-1, -1, -1); node_->redraw();
+ for(node *xn = node_->kids(); xn; xn = xn->next())
+ if (xn) if (xn->type() == kind
+ || (xn->type() == NODE_TASK && kind == NODE_FAMILY)
+ ) {
+ xn->update(-1, -1, -1);
+ xn->redraw();
+ }
+ }
+ }
+ return tot;
+}
+
+void update_status_time( node* xnode, const Node* n, ecf_node* ecf )
+{
+ if (!n) return;
+ if (!ecf) return;
+ if (!(ecf->type() == NODE_TASK)) return;
+ if (!xnode) return;
+ /*
+ for (std::vector<ecf_node*>::iterator it = ecf->kids_.begin(); it != ecf->kids_.end(); ++it)
+ if ((*it)->type() == NODE_LABEL && (*it)->name() == "time") {
+ Label* lb = dynamic_cast<Label *>(n->findLabel("time"));
+ if (lb) lb->set_new_value(to_simple_string(ecf->state_time())); */
+}
+
+template<>
+void ecf_concrete_node<Node>::update( const Node* n, const std::vector<ecf::Aspect::Type>& aspect )
+{
+ if (!owner_) return;
+ if (!node_) return;
+ if (is_reset(aspect)) {
+ Updating::set_full_redraw();
+ return;
+ }
+
+ node_->delvars();
+ if (owner_->suite()->begun()) {
+ owner_->update_generated_variables();
+ }
+ std::vector<Variable> gvar;
+ n->gen_variables(gvar);
+ std::vector<Variable>::const_iterator it, gvar_end;
+ for(it = gvar.begin(); it != gvar.end(); ++it) {
+ if ((*it).name() == "" || *it == Variable::EMPTY()) {
+ std::cerr << "# empty variable\n";
+ continue;
+ }
+ ecf_node *run = make_node(*it, this, 'g');
+ add_kid(run);
+ node_->insert(run->create_node(node_->serv()));
+ }
+
+#ifdef SORT_VAR
+ gvar = n->variables(); /* expensive */
+ std::sort(gvar.begin(), gvar.end(), cless_than());
+ gvar_end = gvar.end();
+ for(it = gvar.begin(); it != gvar_end; ++it) {
+#else
+ for (it = n->variables().begin(); it != n->variables().end(); ++it) {
+#endif
+ if ((*it).name() == "" || *it == Variable::EMPTY()) {
+ std::cerr << "# empty variable\n";
+ continue;
+ }
+ ecf_node *run = make_node(*it, this);
+ add_kid(run);
+ node_->insert(run->create_node(node_->serv()));
+ }
+
+ const_cast<Node*>(n)->set_graphic_ptr(xnode());
+ if (redraw_kids(node_, aspect) == 1) return;
+
+ if (info_label) update_status_time(node_, n, this);
+
+ node_->update(-1, -1, -1); // call pop up window with check
+ node_->notify_observers();
+ node_->redraw();
+}
+
+template<>
+void ecf_concrete_node<Suite>::update( const Node* n, const std::vector<ecf::Aspect::Type>& aspect )
+{
+ if (!owner_) return;
+ if (!node_) return;
+ assert(xnode());
+ const_cast<Node*>(n)->set_graphic_ptr(xnode()); /* ??? */
+
+ if (is_reset(aspect)) {
+
+ Updating::set_full_redraw();
+ return;
+ }
+
+ if (owner_->begun()) owner_->update_generated_variables();
+
+ if (redraw_kids(node_, aspect) == 1) return;
+
+ node_->update(-1, -1, -1);
+ node_->notify_observers();
+ node_->redraw();
+}
+
+template<>
+bool ecf_concrete_node<Suite>::is_late()
+{
+ if (!owner_) return false;
+ return owner_->get_late() ? owner_->get_late()->isLate() : false;
+}
+
+template<>
+bool ecf_concrete_node<Node>::is_late()
+{
+ if (!owner_) return false;
+ return owner_->get_late() ? owner_->get_late()->isLate() : false;
+}
+
+template<>
+bool ecf_concrete_node<Suite>::hasZombieAttr()
+{
+ if (!owner_) return false;
+ return owner_->zombies().size() > 0;
+}
+
+template<>
+bool ecf_concrete_node<Node>::hasZombieAttr()
+{
+ if (!owner_) return false;
+ return owner_->zombies().size() > 0;
+}
+
+template<>
+bool ecf_concrete_node<Node>::hasTime()
+{
+ return owner_ ?
+ (owner_->timeVec().size() > 0 || owner_->todayVec().size() > 0
+ || owner_->crons().size() > 0) : false;
+}
+
+template<>
+bool ecf_concrete_node<Suite>::hasTime()
+{
+ return owner_ ?
+ (owner_->timeVec().size() > 0 || owner_->todayVec().size() > 0
+ || owner_->crons().size() > 0) : false;
+}
+
+template<>
+bool ecf_concrete_node<Family>::hasTime()
+{
+ return owner_ ?
+ (owner_->timeVec().size() > 0 || owner_->todayVec().size() > 0
+ || owner_->crons().size() > 0) : false;
+}
+
+template<>
+bool ecf_concrete_node<Node>::hasTrigger()
+{
+ return owner_ ? (owner_->triggerAst() || owner_->completeAst()) : false;
+}
+
+template<>
+bool ecf_concrete_node<Node>::hasDate()
+{
+ return owner_ ? (owner_->days().size() > 0 || owner_->dates().size() > 0) : false;
+}
+
+template<>
+bool ecf_concrete_node<Suite>::hasDate()
+{
+ return owner_ ? (owner_->days().size() > 0 || owner_->dates().size() > 0) : false;
+}
+
+template<>
+bool ecf_concrete_node<Family>::hasDate()
+{
+ return owner_ ? (owner_->days().size() > 0 || owner_->dates().size() > 0) : false;
+}
+
+template<> ecf_concrete_node<const Event>::ecf_concrete_node( const Event* owner, ecf_node* parent,
+ const char c ) :
+ ecf_node(parent, owner ? owner->name_or_number() : ecf_node::none(), c), owner_(owner)
+{
+}
+
+template<>
+const std::string ecf_concrete_node<ExpressionWrapper>::toString() const
+{
+ if (owner_) return owner_->expression();
+ return ecf_node::none();
+}
+
+template<>
+const std::string ecf_concrete_node<Expression>::toString() const
+{
+ if (owner_) return owner_->expression();
+ return ecf_node::none();
+}
+
+template<>
+const std::string ecf_concrete_node<external>::toString() const
+{
+ return ecf_node::none();
+}
+
+template<>
+const std::string ecf_concrete_node<dummy_node>::toString() const
+{
+ return ecf_node::none();
+}
+
+template<>
+const std::string ecf_concrete_node<AstTop>::toString() const
+{
+ return owner_ ? owner_->expression() : ecf_node::none();
+}
+
+template<>
+const std::string ecf_concrete_node<Suite>::toString() const
+{
+ return owner_ ? owner_->name() : ecf_node::none();
+}
+
+template<>
+const std::string ecf_concrete_node<Node>::toString() const
+{
+ return owner_ ? owner_->name() : ecf_node::none();
+}
+
+template<>
+const std::string ecf_concrete_node<Defs>::toString() const
+{
+ return ecf_node::slash();
+}
+
+template<>
+const std::string ecf_concrete_node<RepeatDay>::toString() const
+{
+ if (parent()) return parent()->get_repeat().toString();
+ return none();
+}
+
+/*template<>
+ const std::string ecf_concrete_node<Label>::toString() const
+ { if (parent())
+ return parent()->get_label().toString();
+ return none();
+ }*/
+
+template<>
+const std::string ecf_concrete_node<RepeatDate>::toString() const
+{
+ if (parent()) return parent()->get_repeat().toString();
+ return none();
+}
+
+template<>
+const std::string ecf_concrete_node<RepeatEnumerated>::toString() const
+{
+ if (parent()) return parent()->get_repeat().toString();
+ return none();
+}
+
+template<>
+const std::string ecf_concrete_node<RepeatString>::toString() const
+{
+ if (parent()) return parent()->get_repeat().toString();
+ return none();
+}
+
+template<>
+const std::string ecf_concrete_node<RepeatInteger>::toString() const
+{
+ if (parent()) return parent()->get_repeat().toString();
+ return none();
+}
+
+template<>
+const std::string ecf_concrete_node<const std::pair<std::string, std::string> >::toString() const
+{
+ if (owner_) return owner_->first + " : " + owner_->second;
+ return "pair";
+}
+
+template<> int ecf_concrete_node<const Event>::status() const
+{
+ return owner_ ? owner_->value() : 0;
+}
+
+template<> boost::posix_time::ptime ecf_concrete_node<Suite>::status_time() const
+{
+ if (owner_) return owner_->state_change_time();
+ return boost::posix_time::ptime();
+}
+
+template<> boost::posix_time::ptime ecf_concrete_node<Family>::status_time() const
+{
+ if (owner_) return owner_->state_change_time();
+ return boost::posix_time::ptime();
+}
+
+template<> boost::posix_time::ptime ecf_concrete_node<Node>::status_time() const
+{
+ if (owner_) return owner_->state_change_time();
+ return boost::posix_time::ptime();
+}
+
+template<> int ecf_concrete_node<Suite>::status() const
+{
+ int rc = STATUS_UNKNOWN;
+ if (!owner_) return rc;
+ else if (!owner_->begun()) return rc;
+ else rc = convert(owner_->state());
+ return owner_->isSuspended() ? STATUS_SUSPENDED : rc;
+}
+
+template<> int ecf_concrete_node<Node>::status() const
+{
+ int rc = STATUS_UNKNOWN;
+ if (!owner_) return rc;
+ else rc = convert(owner_->state());
+ return owner_->isSuspended() ? STATUS_SUSPENDED : rc;
+}
+
+template<> int ecf_concrete_node<Defs>::status() const
+{
+ int rc = STATUS_UNKNOWN;
+ if (!owner_) return rc;
+ switch ( owner_->server().get_state() ) {
+ case SState::HALTED:
+ rc = STATUS_HALTED;
+ break;
+ case SState::SHUTDOWN:
+ rc = STATUS_SHUTDOWN;
+ break;
+ case SState::RUNNING:
+ rc = convert(owner_->state());
+ break;
+ }
+ return rc;
+}
+
+template<> int ecf_concrete_node<Suite>::defstatus() const
+{
+ return owner_ ? convert(owner_->defStatus()) : STATUS_QUEUED;
+}
+
+template<> int ecf_concrete_node<Node>::defstatus() const
+{
+ return owner_ ? convert(owner_->defStatus()) : STATUS_QUEUED;
+}
+
+template<> int ecf_concrete_node<Defs>::flags() const
+{
+ return owner_ ? owner_->flag().flag() : 0;
+}
+
+template<> int ecf_concrete_node<Node>::flags() const
+{
+ return owner_ ? owner_->flag().flag() : 0;
+}
+template<> int ecf_concrete_node<Suite>::flags() const
+{
+ return owner_ ? owner_->flag().flag() : 0;
+}
+
+template<> int ecf_concrete_node<Node>::type() const
+{
+ int rc = NODE_UNKNOWN;
+ if (!owner_) return rc;
+ if (owner_->isFamily()) rc = NODE_FAMILY;
+ else if (owner_->isAlias()) rc = NODE_ALIAS;
+ else if (owner_->isTask()) rc = NODE_TASK;
+ else if (owner_->isSuite()) rc = NODE_SUITE;
+ return rc;
+}
+
+template<> int ecf_concrete_node<Alias>::type() const
+{
+ return NODE_ALIAS;
+}
+template<> int ecf_concrete_node<Suite>::type() const
+{
+ return NODE_SUITE;
+}
+template<> int ecf_concrete_node<Family>::type() const
+{
+ return NODE_FAMILY;
+}
+template<> int ecf_concrete_node<Defs>::type() const
+{
+ return NODE_SUPER;
+}
+template<> int ecf_concrete_node<const ecf::TimeAttr>::type() const
+{
+ return NODE_TIME;
+}
+template<> int ecf_concrete_node<const ecf::TodayAttr>::type() const
+{
+ return NODE_TIME;
+}
+template<> int ecf_concrete_node<const ecf::CronAttr>::type() const
+{
+ return NODE_TIME;
+}
+template<> int ecf_concrete_node<const DateAttr>::type() const
+{
+ return NODE_DATE;
+}
+template<> int ecf_concrete_node<DateAttr>::type() const
+{
+ return NODE_DATE;
+}
+template<> int ecf_concrete_node<const DayAttr>::type() const
+{
+ return NODE_DATE;
+}
+// template<>int ecf_concrete_node<RepeatBase>::type() const { return NODE_REPEAT; }
+template<> int ecf_concrete_node<RepeatEnumerated>::type() const
+{
+ return NODE_REPEAT_E;
+}
+template<> int ecf_concrete_node<RepeatString>::type() const
+{
+ return NODE_REPEAT_S;
+}
+template<> int ecf_concrete_node<RepeatDate>::type() const
+{
+ return NODE_REPEAT_D;
+}
+template<> int ecf_concrete_node<RepeatInteger>::type() const
+{
+ return NODE_REPEAT_I;
+}
+template<> int ecf_concrete_node<RepeatDay>::type() const
+{
+ return NODE_REPEAT_DAY;
+}
+template<> int ecf_concrete_node<const ecf::LateAttr>::type() const
+{
+ return NODE_LATE;
+}
+template<> int ecf_concrete_node<ecf::LateAttr>::type() const
+{
+ return NODE_LATE;
+}
+
+template<> int ecf_concrete_node<const Event>::type() const
+{
+ return NODE_EVENT;
+}
+template<> int ecf_concrete_node<const Label>::type() const
+{
+ return NODE_LABEL;
+}
+template<> int ecf_concrete_node<const Meter>::type() const
+{
+ return NODE_METER;
+}
+
+template<> int ecf_concrete_node<const Variable>::type() const
+{
+ return NODE_VARIABLE;
+}
+template<> int ecf_concrete_node<ExpressionWrapper>::type() const
+{
+ return NODE_TRIGGER;
+}
+template<> int ecf_concrete_node<Variable>::type() const
+{
+ return NODE_VARIABLE;
+}
+template<> int ecf_concrete_node<const std::pair<std::string, std::string> >::type() const
+{
+ return NODE_VARIABLE;
+}
+
+template<> int ecf_concrete_node<Limit>::type() const
+{
+ return NODE_LIMIT;
+}
+template<> int ecf_concrete_node<const InLimit>::type() const
+{
+ return NODE_INLIMIT;
+}
+
+template<> int ecf_concrete_node<Expression>::type() const
+{
+ return NODE_TRIGGER;
+}
+template<> int ecf_concrete_node<dummy_node>::type() const
+{
+ return NODE_UNKNOWN;
+}
+template<> int ecf_concrete_node<dummy_node>::status() const
+{
+ return STATUS_UNKNOWN;
+}
+template<> const std::string& ecf_concrete_node<dummy_node>::name() const
+{
+ return owner_->name();
+}
+template<> const std::string& ecf_concrete_node<dummy_node>::full_name() const
+{
+ return owner_ ? owner_->name() : ecf_node::none();
+}
+template<> void ecf_concrete_node<dummy_node>::set_graphic_ptr( node* n )
+{
+}
+
+template<> int ecf_concrete_node<external>::type() const
+{
+ return NODE_UNKNOWN;
+}
+
+template<>
+int ecf_concrete_node<Node>::tryno()
+{
+ int num = -1;
+ if (owner_) {
+ Submittable* submittable = owner_->isSubmittable();
+ if (submittable) num = submittable->try_no();
+ }
+ return num;
+}
+
+template<>
+void ecf_concrete_node<Suite>::set_graphic_ptr( node* n )
+{
+ return owner_->set_graphic_ptr(n);
+}
+
+template<>
+void ecf_concrete_node<Node>::set_graphic_ptr( node* n )
+{
+ return owner_->set_graphic_ptr(n);
+}
+
+const std::string& ecf_node::no_owner()
+{
+ static const std::string NO_OWNER = "(no owner)";
+ return NO_OWNER;
+}
+const std::string& ecf_node::none()
+{
+ static const std::string NONE = "(none)";
+ return NONE;
+}
+const std::string& ecf_node::slash()
+{
+ static const std::string SLASH = "/";
+ return SLASH;
+}
+
+ExpressionWrapper::ExpressionWrapper( Node* n, char c ) :
+ node_(n), kind_(c)
+{
+ if (n) {
+ if (c == 'c') mem = n->completeExpression();
+ else mem = n->triggerExpression();
+ }
+}
+
+const std::string & ExpressionWrapper::name() const
+{
+ return ecf_node::none();
+}
+
+const std::string & ExpressionWrapper::full_name() const
+{
+ return ecf_node::none();
+}
+const std::string & ExpressionWrapper::toString() const
+{
+ return mem;
+}
+
+void ecf_node::delvars()
+{
+ for(size_t i = 0; i < kids_.size(); i++) {
+ if (kids_[i]->type() == NODE_VARIABLE) {
+ kids_.erase(kids_.begin() + i);
+ }
+ }
+}
+
+template<>
+std::string ecf_concrete_node<Suite>::get_var( const std::string& name, bool is_gen,
+ bool substitute )
+{
+ if (!is_gen) { // user variable have priority
+ const Variable& var = owner_->findVariable(name);
+ if (!var.empty()) {
+ std::string value = var.theValue();
+ if (substitute) {
+ owner_->update_generated_variables();
+ owner_->variableSubsitution(value);
+ }
+ return value;
+ }
+ }
+ if ((!owner_->repeat().empty()) && name == owner_->repeat().name()) {
+ return owner_->repeat().valueAsString();
+ }
+ return owner_->findGenVariable(name).theValue();
+}
+
+template<>
+std::string ecf_concrete_node<Node>::get_var( const std::string& name, bool is_gen,
+ bool substitute )
+{
+ if (!is_gen) { // user variable have priority
+ const Variable& var = owner_->findVariable(name);
+ if (!var.empty()) {
+ std::string value = var.theValue();
+ if (substitute) {
+ owner_->update_generated_variables();
+ owner_->variableSubsitution(value);
+ }
+ return value;
+ }
+ }
+ if ((!owner_->repeat().empty()) && name == owner_->repeat().name()) {
+ return owner_->repeat().valueAsString();
+ }
+ return owner_->findGenVariable(name).theValue();
+}
+
+template<>
+std::string ecf_concrete_node<Defs>::get_var( const std::string& name, bool is_gen,
+ bool substitute )
+{
+ if (!is_gen) { // user variable have priority
+ const Variable& var = owner_->server().findVariable(name);
+ if (!var.empty()) {
+ std::string value = var.theValue();
+ if (substitute) {
+ // owner_->update_generated_variables();
+ owner_->server().variableSubsitution(value);
+ }
+ return value;
+ }
+ }
+ return owner_->server().findVariable(name).theValue();
+}
+
+template<>
+Limit* ecf_concrete_node<Limit>::get_limit( const std::string& name )
+{
+ return owner_;
+}
+template<>
+const Label& ecf_concrete_node<Node>::get_label( const std::string& name )
+{
+ return owner_ ? owner_->find_label(name) : Label::EMPTY();
+}
+template<>
+const Event& ecf_concrete_node<Node>::get_event( const std::string& name )
+{
+ return owner_ ? owner_->findEvent(name) : Event::EMPTY();
+}
+template<>
+const Meter& ecf_concrete_node<Node>::get_meter( const std::string& name )
+{
+ return owner_ ? owner_->findMeter(name) : Meter::EMPTY();
+}
+template<>
+const Repeat& ecf_concrete_node<Node>::get_repeat()
+{
+ return owner_ ? owner_->repeat() : crd();
+}
+
+template<>
+const Label& ecf_concrete_node<Suite>::get_label( const std::string& name )
+{
+ return owner_ ? owner_->find_label(name) : Label::EMPTY();
+}
+template<>
+const Event& ecf_concrete_node<Suite>::get_event( const std::string& name )
+{
+ return owner_ ? owner_->findEvent(name) : Event::EMPTY();
+}
+template<>
+const Meter& ecf_concrete_node<Suite>::get_meter( const std::string& name )
+{
+ return owner_ ? owner_->findMeter(name) : Meter::EMPTY();
+}
+
+template<>
+const Repeat& ecf_concrete_node<Suite>::get_repeat()
+{
+ return owner_ ? owner_->repeat() : crd();
+}
+
+template<>
+Node* ecf_concrete_node<Node>::get_node() const
+{
+ return owner_;
+}
+template<>
+Node* ecf_concrete_node<Alias>::get_node() const
+{
+ return owner_;
+}
+template<>
+Node* ecf_concrete_node<Suite>::get_node() const
+{
+ return owner_;
+}
+template<>
+Node* ecf_concrete_node<Defs>::get_node() const
+{
+ return 0x0;
+}
+
+const char* ecf_node_name( int ii )
+{
+
+ static char* types[] = { (char*) "list", (char*) "user", (char*) "connection",
+ (char*) "variable", (char*) "time", (char*) "date", (char*) "trigger",
+ (char*) "tree", (char*) "action", (char*) "event", (char*) "task",
+ (char*) "family", (char*) "suite", (char*) "super", (char*) "passwd",
+ (char*) "login", (char*) "status", (char*) "reply", (char*) "check",
+ (char*) "nid", (char*) "file", (char*) "handle", (char*) "repeat",
+ (char*) "dir", (char*) "meter", (char*) "label", (char*) "cancel",
+ (char*) "migrate", (char*) "late", (char*) "restore",
+ (char*) "complete", (char*) "nickname", (char*) "alias",
+ (char*) "limit", (char*) "inlimit", (char*) "unknown",
+ (char*) "repeat-e", (char*) "repeat-s", (char*) "repeat-d",
+ (char*) "repeat-i",
+ // (char*)"zombie", (char*)"project", (char*)"object", (char*)"call",
+ (char*) "cron",
+ NULL };
+ int size = sizeof(types) / sizeof(char*);
+ if (ii >= size) return "out of bound";
+ return (const char*) types[ii];
+}
+
+const std::string ecf_node::type_name() const
+{
+ return ecf_node_name(type());
+}
+
+template<>
+void ecf_concrete_node<Defs>::make_subtree()
+{
+ full_name_ = "/";
+ if (!owner_) return;
+
+ owner_->attach(this);
+ make_kids_list(this, owner_->suiteVec());
+
+ std::vector<Variable> gvar = owner_->server().server_variables();
+ std::vector<Variable>::const_iterator it;
+ for(it = gvar.begin(); it != gvar.end(); ++it)
+ if (!(*it == Variable::EMPTY()))
+ add_kid(make_node(*it, this, 'g'));
+ else std::cerr << "# empty variable\n";
+
+ gvar = owner_->server().user_variables();
+ std::sort(gvar.begin(), gvar.end(), cless_than());
+ make_kids_list(this, gvar);
+
+}
+
+template<>
+void ecf_concrete_node<Defs>::update( const Defs* n, const std::vector<ecf::Aspect::Type>& aspect )
+{
+ if (!owner_) return;
+ if (!node_) return;
+ if (is_reset(aspect)) {
+
+ Updating::set_full_redraw();
+
+ XECFDEBUG {
+ for(std::vector<suite_ptr>::const_iterator i = n->suiteVec().begin();
+ i != n->suiteVec().end(); ++i) {
+ std::cout << "suite name " << (*i)->name() << "\n";
+ }
+ }
+
+ return;
+ }
+
+ {
+ node_->update(-1, -1, -1);
+ node_->notify_observers();
+ node_->redraw();
+ }
+}
+
+ecf_node* ecf_node::dummy_node()
+{
+ ecf_concrete_node<external> *n = new ecf_concrete_node<external>(0x0, 0x0, 'e');
+ return n;
+}
+
diff --git a/view/src/ecf_node.h b/view/src/ecf_node.h
new file mode 100644
index 0000000..b3b74eb
--- /dev/null
+++ b/view/src/ecf_node.h
@@ -0,0 +1,582 @@
+#ifndef ecf_node_H
+#define ecf_node_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #65 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "observable.h"
+class host;
+class ecf_node;
+#include "ecflowview.h"
+#include <iostream>
+#include <deque>
+class node;
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+
+#if 0
+struct ext_node;
+struct ext_list {
+ int type_;
+ char *name_;
+ struct ext_list *next;
+
+ const std::string name() {return name_;}
+};
+
+struct ext_tree {int type_;
+ char *name;
+ struct ext_tree *left, *right;
+ int mtype, level;
+ struct ext_tree *math;
+};
+
+struct ext_trigger {
+ int type_;
+ char *name;
+ struct ext_trigger *next_;
+ int status_, nid_, num_;
+ struct ext_node *parent;
+ void* user_ptr;
+ int uint_;
+ struct ext_node *kids_;
+ int mod_no;
+ ext_tree* math;
+};
+
+struct ext_node {
+ int type_;
+ char *name_;
+ struct ext_node *next_;
+ int status_, nid_, num_;
+ struct ext_node *parent;
+ void* user_ptr_;
+ int uint_;
+ struct ext_node *kids_;
+ int defs_, svds_, flags;
+ ext_node *text, *event, *meter, *label, *time, *date,
+ *trigger, *complete, *action, *autocm, *late, *limit,
+ *inlimit, *wait;
+ int rid, tryno_, alias, count;
+ char *passwd;
+ ext_node *user, *variable;
+ int mod, clk, gain;
+ time_t stime, btime;
+ ext_node *genvars, *repeat, *log, *restore;
+ char* name() const {return name_ ? name_ : getenv("USER");}
+ const std::string toString() const {return name();}
+ int status() const {return status_;}
+ int type() const {return type_;}
+ int defComplete() const {return defs_ == STATUS_COMPLETE;}
+ const std::string& full_name() {
+ static std::string fname;
+ if (type_ == NODE_SUPER) {fname = "/";}
+ else if (parent) {
+ fname = parent->full_name();
+ if (type_ == NODE_SUITE) {}
+ else if (type_== NODE_FAMILY || type_ == NODE_TASK || type_ == NODE_ALIAS)
+ fname += "/";
+ else
+ fname += ":";
+ fname += name_;
+ }
+ return fname;
+ }
+};
+#endif
+const char* ecf_node_name( int ii );
+
+class ecf_node_maker {
+ virtual node* make( host&, ecf_node* e ) = 0;
+protected:
+ static std::map<std::string, ecf_node_maker*>& map();
+ static std::vector<ecf_node_maker*>& builders();
+public:
+ static node* make_xnode( host& h, ecf_node* n, std::string type );
+};
+
+template<typename T, class W>
+class ecf_node_builder : public ecf_node_maker {
+ virtual node* make( host& h, ecf_node* e )
+ {
+ return new W(h, e);
+ }
+public:
+ ecf_node_builder( int type )
+ {
+ map()[typeid(T).name()] = this;
+ builders()[type] = this;
+ }
+ ~ecf_node_builder()
+ {
+ }
+};
+
+class ExpressionWrapper {
+ Node* node_;
+ char kind_;
+ std::string mem;
+public:
+ ExpressionWrapper( Node* n, char c );
+
+ const std::string & name() const;
+ const std::string & full_name() const;
+ const std::string & toString() const;
+
+ std::string expression() const
+ {
+ if (kind_ == 'c') return node_->completeExpression();
+ return node_->triggerExpression();
+ }
+
+ AstTop* get_ast_top()
+ {
+ if (kind_ == 'c') return node_->completeAst();
+ return node_->triggerAst();
+ }
+};
+
+class ecf_node : public boost::enable_shared_from_this<ecf_node>
+ , public observable
+{
+private:
+ ecf_node* parent_;
+
+protected:
+ mutable std::string full_name_;
+ std::vector<ecf_node*> kids_;
+ node *node_;
+ char kind_; // 'c' for complete trigger
+ friend void update_status_time(node*, const Node* , ecf_node*);
+ const std::string name_;
+
+ ExpressionWrapper *trigger_;
+ ExpressionWrapper *complete_;
+ friend class ecf_node_maker;
+
+ void counter();
+
+public:
+ ecf_node( ecf_node* parent, const std::string& name, char k );
+
+ ~ecf_node();
+
+ static const std::string& no_owner();
+ static const std::string& none();
+ static const std::string& slash();
+
+ virtual void set_graphic_ptr( node* )
+ {
+ }
+ virtual node* create_node( host& ) = 0;
+ virtual node* create_tree( host& h, node* xnode = 0x0 );
+ void adopt( node* n )
+ {
+ node_ = n;
+ }
+ void nokids( bool own = false );
+
+ void add_kid( ecf_node* k );
+#ifdef BRIDGE
+ void* user_ptr;
+#endif
+
+ virtual int type() const = 0;
+ virtual int flags() const = 0;
+ virtual const std::string type_name() const;
+ virtual void update( const Node*, const std::vector<ecf::Aspect::Type>& );
+ virtual void update( const Defs*, const std::vector<ecf::Aspect::Type>& );
+ virtual void update_delete( const Node* );
+ virtual void update_delete( const Defs* );
+
+ virtual void make_subtree() = 0;
+
+ virtual const std::string toString() const
+ {
+ return none();
+ }
+ // virtual const std::string substitute(const std::string& cmd) const { return cmd; }
+ virtual int status() const
+ {
+ return STATUS_UNKNOWN;
+ }
+ virtual boost::posix_time::ptime status_time() const
+ {
+ return boost::posix_time::ptime();
+ }
+ virtual int defstatus() const
+ {
+ return STATUS_QUEUED;
+ }
+ virtual int tryno()
+ {
+ return 0;
+ }
+ virtual const std::string& name() const
+ {
+ return name_;
+ }
+ virtual const std::string& full_name() const
+ {
+ return full_name_;
+ }
+
+ virtual bool is_late()
+ {
+ return false;
+ }
+ virtual bool hasZombieAttr()
+ {
+ return false;
+ }
+ virtual bool hasTime()
+ {
+ return false;
+ }
+ virtual bool hasDate()
+ {
+ return false;
+ }
+ virtual bool hasTrigger()
+ {
+ return false;
+ }
+
+ virtual std::ostream& print( std::ostream& s ) const
+ {
+ return s << none();
+ }
+ virtual void print( std::ostream& s )
+ {
+ s << none();
+ }
+ virtual const std::string& variable( const std::string& name ) const = 0;
+ virtual void why( std::ostream & ) const
+ {
+ }
+
+ virtual std::string get_var( const std::string& name, bool is_gen = false,
+ bool substitute = false )
+ {
+ return none();
+ }
+
+ virtual Limit* get_limit( const std::string& name ) = 0;
+ virtual Node* get_node() const = 0;
+ virtual const Label& get_label( const std::string& name ) = 0;
+ virtual const Event& get_event( const std::string& name ) = 0;
+ virtual const Meter& get_meter( const std::string& name ) = 0;
+ virtual const Repeat& get_repeat() = 0;
+
+ static const Repeat& crd();
+
+private:
+ ecf_node( const ecf_node& );
+ ecf_node& operator=( const ecf_node& );
+
+public:
+ ecf_node* parent() const
+ {
+ return parent_;
+ }
+ node* xnode() const
+ {
+ return node_;
+ }
+ char kind()
+ {
+ return kind_;
+ }
+ static ecf_node* dummy_node();
+
+ virtual void unlink( bool detach = true );
+ virtual void check() const
+ {
+ if (parent() == 0x0) std::cerr << "# ecf: no parent: " << name() << "\n";
+ if (xnode() == 0x0) std::cerr << "# ecf: no xnode: " << name() << "\n";
+ }
+
+ void delvars();
+};
+
+template<typename T>
+class ecf_concrete_node : public ecf_node, public AbstractObserver {
+private:
+ T* owner_;
+private:
+ ecf_concrete_node( const ecf_concrete_node& );
+ ecf_concrete_node& operator=( const ecf_concrete_node& );
+
+protected:
+ virtual node* create_node( host& h )
+ {
+ return ecf_node_maker::make_xnode(h, this, type_name());
+ }
+
+public:
+ ecf_concrete_node( T* owner, ecf_node* parent, char c = 'd' )
+ : ecf_node(parent, owner ? owner->name() : ecf_node::none(), c)
+ , owner_(owner)
+ {
+ if (0 && parent) {
+ full_name_ = parent->full_name();
+ full_name_ += ":";
+ full_name_ += name();
+ }
+ }
+
+ ~ecf_concrete_node()
+ {
+ unlink();
+ }
+
+ virtual void set_graphic_ptr( node* )
+ {
+ }
+
+ T* get() const
+ {
+ return owner_;
+ }
+ virtual const std::string toString() const;
+
+ // virtual const std::string substitute(const std::string& cmd) const { return cmd; }
+ virtual int status() const
+ {
+ return STATUS_UNKNOWN;
+ }
+ virtual int defstatus() const
+ {
+ return STATUS_QUEUED;
+ }
+ virtual boost::posix_time::ptime status_time() const
+ {
+ return boost::posix_time::ptime();
+ }
+ virtual int tryno()
+ {
+ return 0;
+ }
+ virtual int type() const
+ {
+ return NODE_UNKNOWN;
+ }
+ virtual int flags() const
+ {
+ return 0;
+ }
+ virtual const std::string& name() const
+ {
+ return ecf_node::name();
+ }
+ virtual const std::string& full_name() const
+ {
+ return full_name_;
+ }
+ virtual bool is_late()
+ {
+ return false;
+ }
+ virtual bool hasZombieAttr()
+ {
+ return false;
+ }
+ virtual bool hasTime()
+ {
+ return false;
+ }
+ virtual bool hasDate()
+ {
+ return false;
+ }
+ virtual bool hasTrigger()
+ {
+ return false;
+ }
+
+ virtual void make_subtree()
+ {
+ }
+
+ virtual std::ostream& print( std::ostream& s ) const
+ {
+ return s << none();
+ }
+ virtual void print( std::ostream& s )
+ {
+ }
+
+ virtual const std::string type_name() const
+ {
+ return typeid(owner_).name();
+ }
+
+ virtual void update( const Node* n, const std::vector<ecf::Aspect::Type>& asp )
+ {
+ if (!owner_) return;
+ ecf_node::update(n, asp);
+ }
+ virtual void update( const Defs* n, const std::vector<ecf::Aspect::Type>& asp )
+ {
+ if (!owner_) return;
+ ecf_node::update(n, asp);
+ }
+
+ void update_delete( const Node* n )
+ {
+ unlink();
+ ecf_node::update_delete(n);
+ }
+ void update_delete( const Defs* n )
+ {
+ unlink();
+ ecf_node::update_delete(n);
+ }
+
+ virtual const std::string& variable( const std::string& ) const
+ {
+ return none();
+ }
+ virtual void why( std::ostream & ) const
+ {
+ }
+
+ virtual std::string get_var( const std::string& name, bool is_gen = false,
+ bool substitute = false )
+ {
+ return none();
+ }
+
+ virtual void unlink( bool detach = true )
+ {
+ owner_ = 0x0;
+ ecf_node::unlink(detach);
+ }
+ virtual void check() const
+ {
+ if (get() == 0x0) std::cerr << "# ecf: no owner: " << name() << "\n";
+ ecf_node::check();
+ }
+
+ virtual Limit* get_limit( const std::string& name )
+ {
+ return 0x0;
+ }
+ virtual Node* get_node() const
+ {
+ return 0x0;
+ }
+ virtual const Label& get_label( const std::string& name )
+ {
+ return Label::EMPTY();
+ }
+ virtual const Event& get_event( const std::string& name )
+ {
+ return Event::EMPTY();
+ }
+ virtual const Meter& get_meter( const std::string& name )
+ {
+ return Meter::EMPTY();
+ }
+ virtual const Repeat& get_repeat()
+ {
+ return crd();
+ }
+
+private:
+ bool is_reset( const std::vector<ecf::Aspect::Type>& v ) const
+ {
+ bool reset = false;
+ for(std::vector<ecf::Aspect::Type>::const_iterator it = v.begin(); it != v.end();
+ ++it) {
+ if (*it == ecf::Aspect::ORDER || *it == ecf::Aspect::ADD_REMOVE_NODE
+ || *it == ecf::Aspect::ADD_REMOVE_ATTR) {
+ reset = true;
+ break;
+ }
+ }
+ return reset;
+ }
+};
+
+template<typename T>
+ecf_node* make_node( T* n, ecf_node* parent, char c = 'd' )
+{
+ ecf_node* ec = new ecf_concrete_node<T>(n, parent, c);
+ if (ec && n) {
+ int type = ec->type();
+ // gcc 4.7 optimisation issue, keep next line
+ // XECFDEBUG { if (!ec) std::cerr << "# make node " << type << "\n"; }
+ if (!parent || type == NODE_SUPER || type == NODE_SUITE)
+ ec->make_subtree();
+ else if (type == NODE_FAMILY || type == NODE_TASK || type == NODE_ALIAS) {
+ /* temp on demand:: */ec->make_subtree();
+ }
+ }
+ // XECFDEBUG { if (!ec) std::cerr << "# no ecf\n"; if (!n) std::cerr << "# no node\n"; }
+ return ec;
+}
+
+template<typename T>
+ecf_node* make_node( T& n, ecf_node* parent, const char c = 'd' )
+{
+ return make_node<T>(&n, parent, c);
+}
+
+template<typename T>
+node* make_xnode( T* n, ecf_node* parent, host& h, char c = 'd' )
+{
+ ecf_node* ec = make_node<T>(n, parent, c);
+ if (ec) {
+ node *xnode = ec->create_tree(h);
+ ec->adopt(xnode); /* twice ? create is adoption */
+ return xnode;
+ }
+ XECFDEBUG { if (!ec) std::cerr << "# no ecf2\n"; }
+ return NULL;
+}
+
+template<typename T>
+node* make_xnode( T& n, ecf_node* parent, host& h, const char c = 'd' )
+{
+ return make_xnode<T>(&n, parent, h, c);
+}
+
+template<typename T>
+void make_kids_list( ecf_node* parent, const std::vector<boost::shared_ptr<T> >& v )
+{
+ for(typename std::vector<boost::shared_ptr<T> >::const_reverse_iterator j = v.rbegin();
+ j != v.rend(); ++j) {
+ parent->add_kid(make_node((*j).get(), parent));
+ }
+}
+
+template<typename T>
+void make_kids_list( ecf_node* parent, const std::vector<T>& v )
+{
+ for(typename std::vector<T>::const_reverse_iterator j = v.rbegin(); j != v.rend();
+ ++j) {
+ parent->add_kid(make_node(*j, parent));
+ }
+}
+
+template<typename T>
+const std::string ecf_concrete_node<T>::toString() const
+{
+ if (owner_)
+ return owner_->toString();
+ return "";
+}
+
+#endif
diff --git a/view/src/ecflow.cc b/view/src/ecflow.cc
new file mode 100644
index 0000000..7289912
--- /dev/null
+++ b/view/src/ecflow.cc
@@ -0,0 +1,297 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #13 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <map>
+// #include <iostream>
+// #include <fstream>
+// #include <sstream>
+#include <boost/lexical_cast.hpp>
+#include "File.hpp"
+#include "Str.hpp"
+# include <sys/file.h>
+#include "ecflow.h"
+#include "directory.h"
+#include "host.h"
+
+using namespace ecf;
+
+ecf_list *ecf_node_create(char *text)
+{
+ return new ecf_list(text);
+}
+
+/********************/
+
+static std::map<std::string, ecf_map> servers;
+
+int ecf_nick_read(ecf_map::kind kind)
+{
+ FILE *fp;
+#undef MAXLEN
+#define MAXLEN 128
+ char buff[MAXLEN];
+ char name[MAXLEN];
+ char netname[MAXLEN];
+ int prog;
+ std::string servpath;
+
+ if (kind == ecf_map::GLOBAL)
+ servpath = directory::system();
+ else
+ servpath = directory::user();
+ servpath += "/servers";
+ std::cout << "# servers: " << servpath << "\n";
+
+ if( !(fp=fopen(servpath.c_str(),"r")) ) return FALSE;
+ while(fgets(buff,MAXLEN,fp)) {
+ name[0] = netname[0] = 0;
+ sscanf(buff,(char*)"%s %s %d",name,netname,&prog);
+
+ if(name[0] != 0 && name[0] != '#' &&
+ servers.find(name) == servers.end())
+ servers.insert(std::make_pair
+ (name, ecf_map(name, netname, prog, kind)));
+ }
+
+ fclose(fp);
+ return 0;
+}
+
+int ecf_nick_load() {
+ static bool been_here = false;
+ if(been_here) return TRUE;
+ else been_here = true;
+
+ servers.insert(std::make_pair
+ ("localhost",
+ ecf_map("local","localhost", 3141,ecf_map::GLOBAL)));
+ ecf_nick_read(ecf_map::GLOBAL);
+ ecf_nick_read(ecf_map::USER);
+
+ for (std::map<std::string, ecf_map>::const_iterator
+ it = servers.begin(); it != servers.end(); ++it) {
+ host_maker::make_host(it->first,
+ it->second.machine(),
+ it->second.port());
+ }
+ return TRUE;
+}
+
+int ecf_nick_write()
+{
+ std::string servpath = directory::user();
+ servpath += "/servers";
+ FILE *f = fopen(servpath.c_str(), "w");
+ if(!f) return FALSE;
+ for (std::map<std::string, ecf_map>::const_iterator
+ it = servers.begin(); it != servers.end(); ++it) {
+ fprintf(f, "%s\n", it->second.print().c_str());
+ }
+ fclose(f);
+ return TRUE;
+}
+
+int ecf_nick_origin(const std::string& name)
+{
+ std::map<std::string, ecf_map>::iterator found = servers.find(name);
+ if (found != servers.end())
+ return (int) found->second.from;
+ return (int) ecf_map::GLOBAL;
+}
+
+int ecf_nick_delete(const std::string& name)
+{
+ if (servers.find(name) != servers.end())
+ servers.erase(servers.find(name));
+ return TRUE;
+}
+
+int ecf_nick_update(const std::string& name,
+ const std::string& machine,
+ int port)
+{
+ if (servers.find(name) != servers.end())
+ servers.erase(servers.find(name));
+ servers.insert(std::make_pair
+ (name, ecf_map(name, machine, port, ecf_map::USER)));
+ ecf_nick_write();
+ return TRUE;
+}
+
+
+long ecf_repeat_julian_to_date(long jdate)
+{
+ long x,y,d,m,e;
+ long day,month,year;
+
+ x = 4 * jdate - 6884477;
+ y = (x / 146097) * 100;
+ e = x % 146097;
+ d = e / 4;
+
+ x = 4 * d + 3;
+ y = (x / 1461) + y;
+ e = x % 1461;
+ d = e / 4 + 1;
+
+ x = 5 * d - 3;
+ m = x / 153 + 1;
+ e = x % 153;
+ d = e / 5 + 1;
+
+ if( m < 11 )
+ month = m + 2;
+ else
+ month = m - 10;
+
+
+ day = d;
+ year = y + m / 11;
+
+ return year * 10000 + month * 100 + day;
+}
+
+long ecf_repeat_date_to_julian(long ddate)
+{
+ long m1,y1,a,b,c,d,j1;
+
+ long month,day,year;
+
+ year = ddate / 10000;
+ ddate %= 10000;
+ month = ddate / 100;
+ ddate %= 100;
+ day = ddate;
+
+ if (0) {
+ a = (14 - month) / 12;
+ y1 = year + 4800 - a;
+ m1 = month + 12*a - 3;
+ j1 = day + (153*m1 + 2)/5 + 365*y1 + y1/4 - y1/100 + y1/400 - 32045;
+ return j1 - 0.5;
+ }
+
+ if (month > 2)
+ {
+ m1 = month - 3;
+ y1 = year;
+ }
+ else
+ {
+ m1 = month + 9;
+ y1 = year - 1;
+ }
+ a = 146097*(y1/100)/4;
+ d = y1 % 100;
+ b = 1461*d/4;
+ c = (153*m1+2)/5+day+1721119;
+ j1 = a+b+c;
+
+ return(j1);
+}
+
+char *ecf_string(char *str, char *file, int lineno)
+{
+ static const char *null_string = "(null string)";
+ return str ? str : const_cast<char *>(null_string);
+}
+static const char* const_ecf_string(const char *str)
+{
+ static const char *null_string = "(null string)";
+ return str ? str : null_string ;
+}
+
+#undef MAXLEN
+#define MAXLEN 255 /* For temp names, should be big enough */
+#include <sys/stat.h>
+#include <dirent.h>
+
+ecf_dir *ecf_file_dir(char *path, char *pattern, int fullname)
+/**************************************************************************
+? Read the directory and generate the listing
+************************************o*************************************/
+{
+ struct dirent *de;
+ DIR *dp;
+ struct stat st;
+
+ ecf_dir *cur = NULL;
+ ecf_dir *dir = NULL;
+
+ bool ok = true;
+
+ if( (dp=opendir(path)) )
+ {
+ char name[MAXLEN];
+ char *s;
+
+ strcpy(name,path);
+ s = name + strlen(path);
+ *s++ = '/';
+
+ while( ok && (de=readdir(dp)) != NULL )
+ {
+ if( de->d_ino != 0 )
+ {
+ strcpy(s,de->d_name);
+
+ if( !pattern || strncmp(de->d_name,pattern,strlen(pattern))==0 )
+ if( lstat(name,&st) == 0 )
+ {
+ if( (cur = new ecf_dir())) // (ecf_dir*) calloc(1,sizeof(ecf_dir))) )
+ {
+ if(fullname)
+ {
+ char buff[MAXLEN];
+ sprintf(buff,"%s/%s",const_ecf_string(path),const_ecf_string(de->d_name));
+ cur->name_ = strdup(buff);
+ }
+ else
+ cur->name_ = strdup(de->d_name);
+
+ cur->mode = st.st_mode;
+ cur->uid = st.st_uid;
+ cur->gid = st.st_gid;
+ cur->size = st.st_size;
+ cur->atime = st.st_atime;
+ cur->mtime = st.st_mtime;
+ cur->ctime = st.st_ctime;
+
+ ecf_list_add<ecf_dir>(&dir,cur);
+ }
+ else
+ ok = false;
+ }
+ else {}
+ else {} /* Didn't match */
+ }
+ }
+ closedir(dp);
+ } else {};
+
+ return dir;
+}
+
+bool ecf_map::operator== (const ecf_map& l) const
+ {
+ return l.name_ == name_
+ && l.machine_ == machine_
+ && l.port_ == port_;
+ }
+
+const std::string ecf_map::print() const {
+ std::stringstream i; i << port_;
+ return name_ + "\t\t" + machine_ + "\t\t" + i.str();
+}
diff --git a/view/src/ecflow.h b/view/src/ecflow.h
new file mode 100644
index 0000000..40ffa90
--- /dev/null
+++ b/view/src/ecflow.h
@@ -0,0 +1,258 @@
+#ifndef ecf_H
+#define ecf_H
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #19 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <rpc/rpc.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+
+#if defined(__cplusplus) || defined(c_plusplus)
+#include "std.h"
+#include <sstream>
+#include <extent.h>
+
+#include "Str.hpp"
+#include <inttypes.h>
+
+#define ECF_PROG 3141
+
+class ecf_dir : public extent<ecf_dir> {
+ protected:
+ bool sort() { return true; }
+ ecf_dir(const ecf_dir&);
+ ecf_dir operator=(const ecf_dir&);
+ public:
+ char *name_;
+ ecf_dir *next;
+
+ int mode;
+ int uid;
+ int gid;
+ int size;
+ int atime;
+ int mtime;
+ int ctime;
+
+ ecf_dir() : name_ (0x0), next (0x0) {}
+ virtual ~ecf_dir() {}
+
+ std::string name() const { return (name_); }
+};
+
+template<class T>
+bool ecf_list_add(T **list, T *kid)
+{
+ T **top = list;
+ T *run = *top;
+ if( !kid ) return false; kid->next = NULL;
+ if( run ) {
+ while( run->next ) run = run->next;
+ run->next = kid;
+ } else
+ *top = kid;
+ return true;
+};
+
+int ecf_nick_update(const std::string& name,
+ const std::string& machine,
+ int port);
+int ecf_nick_write();
+int ecf_nick_delete(const std::string& name);
+
+class ecf_list {
+ public:
+ int type_;
+ char *name_;
+ ecf_list *next;
+
+ ecf_list(const char *text,
+ ecf_list *n= 0x0) : name_(0x0), next (n) { name_ = strdup(text); }
+ virtual ~ecf_list() { if (name_) free(name_); }
+
+ std::string name() const { return name_; }
+ private:
+ ecf_list(ecf_list& );
+};
+
+class ecf_map {
+ std::string name_;
+ std::string machine_;
+ int port_;
+
+public:
+ enum kind {GLOBAL, USER, NETWORK};
+ kind from;
+
+ ecf_map (const std::string n, const std::string m, int p, kind f)
+ : name_(n)
+ , machine_(m)
+ , port_(p)
+ , from(f)
+ {}
+
+ ~ecf_map() {}
+
+ std::string name() const { return name_; }
+ std::string machine() const { return machine_; }
+ int port() const { return port_; }
+
+ bool operator== (const std::string& n) const { return name_ == n; }
+
+ bool operator== (const ecf_map& l) const;
+
+ const std::string print() const;
+};
+
+int ecf_nick_load();
+ecf_list *ecf_node_create(char *text);
+int ecf_nick_origin(const std::string& name);
+
+#include <Suite.hpp>
+#include <Family.hpp>
+#include <Task.hpp>
+#include <ClientInvoker.hpp>
+#include <AbstractObserver.hpp>
+#include "NodeFwd.hpp"
+
+#include "ExprAst.hpp"
+#include "TimeAttr.hpp"
+#include "TodayAttr.hpp"
+#include "NodeAttr.hpp"
+#include "DateAttr.hpp"
+#include "DayAttr.hpp"
+#include "CronAttr.hpp"
+#include "LateAttr.hpp"
+#include "ZombieAttr.hpp"
+#include "RepeatAttr.hpp"
+#include "AutoCancelAttr.hpp"
+
+#include "Node.hpp"
+#include "Defs.hpp"
+
+typedef uint64_t uint64;
+#include <boost/algorithm/string.hpp>
+
+char *ecf_string(char *str, char *file, int lineno);
+ecf_dir *ecf_file_dir(char *path, char *pattern, int fullname);
+
+#endif
+
+#ifndef ECF_NO_DUPLICATE
+#define SMS_PROG 314159
+
+#ifndef NODE_COMPLETE
+#define STR(x) ecf_string((x), __FILE__ , __LINE__ )
+
+#define STATUS_RESUME -1
+#define STATUS_UNKNOWN 0
+#define STATUS_SUSPENDED 1
+#define STATUS_COMPLETE 2
+#define STATUS_QUEUED 3
+#define STATUS_SUBMITTED 4
+#define STATUS_ACTIVE 5
+#define STATUS_ABORTED 6
+#define STATUS_USABLE 7
+#define STATUS_SHUTDOWN 7
+#define STATUS_HALTED 8
+#define STATUS_MAX 9
+
+#define FLAG_FORCE_ABORT 0
+#define FLAG_USER_EDIT 1
+#define FLAG_TASK_ABORTED 2
+#define FLAG_EDIT_FAILED 3
+#define FLAG_CMD_FAILED 4
+#define FLAG_NO_SCRIPT 5
+#define FLAG_KILLED 6
+#define FLAG_MIGRATED 7
+#define FLAG_LATE 8
+#define FLAG_MESSAGE 9
+#define FLAG_BYRULE 10
+#define FLAG_QUEUELIMIT 11
+#define FLAG_WAIT 12
+#define FLAG_LOCKED 13
+#define FLAG_ZOMBIE 14
+#define FLAG_TO_CHECK 15
+#define FLAG_MAX 16
+
+#define ZOMBIE_USER 1
+#define ZOMBIE_NET 2
+#define ZOMBIE_GET 0
+#define ZOMBIE_FOB 1
+#define ZOMBIE_DELETE 2
+#define ZOMBIE_FAIL 3
+#define ZOMBIE_RESCUE 4
+#define ZOMBIE_KILL 5
+
+#define ECF_E_NOTIN 26
+#define ECF_E_IN 27
+#define ECF_E_NONEWS 28 /* Not really an error */
+#define ECF_E_HOST 29
+
+#define NODE_LIST 0
+#define NODE_USER 1
+#define NODE_CONNECTION 2
+#define NODE_VARIABLE 3
+#define NODE_TIME 4
+#define NODE_DATE 5
+#define NODE_TRIGGER 6
+#define NODE_TREE 7
+#define NODE_COMPLETE 30
+#define NODE_EVENT 9
+#define NODE_TASK 10
+#define NODE_FAMILY 11
+#define NODE_SUITE 12
+#define NODE_SUPER 13
+#define NODE_REPEAT 22
+#define NODE_DIR 23
+#define NODE_METER 24
+#define NODE_LABEL 25
+#define NODE_LATE 28
+#define NODE_UNKNOWN 35
+#define NODE_ALIAS 32
+#define NODE_LIMIT 33
+#define NODE_INLIMIT 34
+#define NODE_UNKNOWN 35
+
+#define NODE_REPEAT_E 36
+#define NODE_REPEAT_S 37
+#define NODE_REPEAT_D 38
+#define NODE_REPEAT_I 39
+#define NODE_REPEAT_DAY 40
+
+#define NODE_MAX 41
+
+#define SUITES_LIST 3
+#define SUITES_MINE 4
+#define SUITES_REG 7
+
+#ifndef NIL
+#define NIL -1
+#endif
+
+#ifndef MIN
+#define MIN(a,b) ((a)<=(b)?(a):(b))
+#endif
+#endif /* do not overwrite sms.h */
+
+long ecf_repeat_julian_to_date(long jdate);
+long ecf_repeat_date_to_julian(long ddate);
+#endif /* ECF_NO_DUPLICATE */
+#endif /* ecf_H */
diff --git a/view/src/ecflowview.cc b/view/src/ecflowview.cc
new file mode 100644
index 0000000..550e5a6
--- /dev/null
+++ b/view/src/ecflowview.cc
@@ -0,0 +1,165 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #30 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#define ecflowview_cc
+#include "ecflowview.h"
+
+#include "ecflow.h"
+#include "ecf_node.h"
+
+#include "edit.h"
+#include "edit_label.h"
+#include "edit_limit.h"
+#include "edit_meter.h"
+#include "edit_repeat.h"
+#include "edit_variable.h"
+#include "history.h"
+#include "info.h"
+#include "job.h"
+#include "jobcheck_panel.h"
+#include "jobstatus.h"
+#include "manual.h"
+#include "messages.h"
+#include "option_panel.h"
+#include "output.h"
+#include "script_panel.h"
+#include "suites_panel.h"
+#include "timetable_panel.h"
+#include "trigger_panel.h"
+#include "users.h"
+#include "variables.h"
+#include "why.h"
+#include "zombies_panel.h"
+
+#include "user_prefs.h"
+#include "fonts_prefs.h"
+#include "colors_prefs.h"
+#include "servers_prefs.h"
+#include "host_prefs.h"
+
+#include "simple_node.h"
+#include "date.h"
+#include "event_node.h"
+#include "inlimit_node.h"
+#include "label_node.h"
+#include "late_node.h"
+#include "limit_node.h"
+#include "meter_node.h"
+#include "node.h"
+#include "super_node.h"
+#include "task_node.h"
+#include "time_node.h"
+#include "trigger_node.h"
+#include "variable_node.h"
+/*
+void __cyg_profile_func_enter( void *, void * )
+ __attribute__ ((no_instrument_function));
+
+void __cyg_profile_func_enter(void *thisone, void *callsite) {
+ printf("E%p\n", (int*)thisone);
+}
+
+void __cyg_profile_func_exit(void *thisone, void *callsite) {
+ printf("X%p\n", (int*)thisone);
+}
+*/
+
+extern int xmain(int,char**); /* from uitop.cc */
+extern int wmain(int,char**);
+
+// In label_variable.cc
+static ecf_node_builder<Variable *, variable_node> build_variable(NODE_VARIABLE);
+static ecf_node_builder<const Variable *, variable_node> build_pkvariable(NODE_VARIABLE);
+// In label_node.cc
+static ecf_node_builder< const Label *, label_node> build_plabel(NODE_LABEL);
+// In event_node.cc
+static ecf_node_builder< const Event *, event_node> build_pevent(NODE_EVENT);
+// In meter_node.cc
+static ecf_node_builder< const Meter *, meter_node> build_cmeter(NODE_METER);
+// In time_node.cc
+static ecf_node_builder<const ecf::TimeAttr *, time_node> build_ctime(NODE_TIME);
+static ecf_node_builder<const ecf::TodayAttr *, time_node> build_ctoday(NODE_TIME);
+// In date_node.cc
+static ecf_node_builder<const DateAttr *, date_node> build_cdate(NODE_DATE);
+static ecf_node_builder<const DayAttr *, date_node> build_cday(NODE_DATE);
+static ecf_node_builder<const ecf::CronAttr *, date_node> build_ccron(NODE_DATE);
+// In limit_node.cc
+static ecf_node_builder<Limit * const, limit_node> build_pklimit(NODE_LIMIT);
+static ecf_node_builder<const InLimit *, inlimit_node> build_cinlimit(NODE_INLIMIT);
+static ecf_node_builder<const ecf::LateAttr *, late_node> build_clate(NODE_LATE);
+static ecf_node_builder<ecf::LateAttr *, late_node> build_late(NODE_LATE);
+
+static ecf_node_builder<ExpressionWrapper*, trigger_node> build_trigger(NODE_TRIGGER);
+#include "repeat.h"
+
+static ecf_node_builder<const std::pair<std::string, std::string> *, variable_node> build_pkpvariable(NODE_VARIABLE);
+
+static ecf_node_builder<Suite*,suite_node>build_suite(NODE_SUITE);
+static ecf_node_builder<Defs*,super_node>build_topnode(NODE_SUPER);
+static ecf_node_builder<Node*,family_node>build_simple(NODE_FAMILY);
+static ecf_node_builder<Alias*,alias_node>build_alias(NODE_ALIAS);
+static ecf_node_builder<Task*, task_node> build_task(NODE_TASK);
+static ecf_node_builder<Family*,family_node>build_family(NODE_FAMILY);
+
+static ecf_node_builder<RepeatEnumerated*,repeat_enumerated_node> pprce(NODE_REPEAT_E);
+static ecf_node_builder<RepeatString*,repeat_string_node> prcs(NODE_REPEAT_S);
+static ecf_node_builder<RepeatDate*,repeat_date_node> prcd(NODE_REPEAT_D);
+static ecf_node_builder<RepeatInteger*,repeat_integer_node> prci(NODE_REPEAT_I);
+static ecf_node_builder<RepeatDay*,repeat_day_node> prcday(NODE_REPEAT_DAY);
+
+static panel_maker<info> info_maker(PANEL_INFO);
+static panel_maker<manual> manual_maker(PANEL_MANUAL);
+static panel_maker<script_panel> script_maker(PANEL_SCRIPT);
+static panel_maker<job> job_maker(PANEL_JOB);
+static panel_maker<jobstatus> jobstatus_maker(PANEL_JOBSTATUS);
+static panel_maker<output> output_maker(PANEL_OUTPUT);
+static panel_maker<why> why_maker(PANEL_WHY);
+static panel_maker<trigger_panel> trigger_panel_maker(PANEL_TRIGGER);
+static panel_maker<jobcheck_panel> jobcheck_maker(PANEL_JOBCHECK);
+static panel_maker<timetable_panel> timetable_maker(PANEL_TIMETABLE);
+static panel_maker<variables> variables_maker(PANEL_VARIABLES);
+static panel_maker<edit> edit_maker(PANEL_EDIT_TASK);
+static panel_maker<edit_label> edit_label_maker(PANEL_EDIT_LABEL);
+static panel_maker<edit_limit> edit_limit_maker(PANEL_EDIT_LIMIT);
+static panel_maker<edit_variable> edit_variable_maker(PANEL_EDIT_VARIABLE);
+static panel_maker<edit_meter> edit_meter_maker(PANEL_EDIT_METER);
+static panel_maker<edit_repeat> edit_repeat_maker(PANEL_EDIT_REPEAT);
+static panel_maker<history> history_maker(PANEL_HISTORY);
+static panel_maker<messages> messages_maker(PANEL_MESSAGES);
+static panel_maker<suites_panel> suites_maker(PANEL_SUITES);
+static panel_maker<users> users_maker(PANEL_USERS);
+static panel_maker<zombies_panel> zombies_maker(PANEL_ZOMBIES);
+static panel_maker<option_panel> maker(PANEL_ECF_OPTIONS);
+
+static user_prefs user_hp;
+static colors_prefs colors_hp;
+static fonts_prefs fonts_hp;
+static host_prefs hosts_hp;
+
+#ifdef BRIDGE
+static repeat_node_maker repeat_node_maker_instance;
+late_node::late_node(host& h,sms_node* n, char b) : node(h,n,b), label_(0) {}
+#endif
+
+int main(int argc,char** argv)
+{
+ return getenv("ECFLOW_HTTP_PORT") ? wmain(argc,argv) :
+ xmain(argc,argv);
+ ecf_nick_write();
+}
+
diff --git a/view/src/ecflowview.h b/view/src/ecflowview.h
new file mode 100644
index 0000000..ff9fc6f
--- /dev/null
+++ b/view/src/ecflowview.h
@@ -0,0 +1,53 @@
+#ifndef ecflowview_h
+#define ecflowview_h
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #13 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+
+#ifdef hpux
+// hpux X11 headers are wrong
+#undef bcopy
+#undef bzero
+#undef bcmp
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "ecflow.h"
+
+#define NOTIMP throw "not_implemented"
+#define XECF_SNAP_ENABLED TRUE
+
+#ifdef BRIDGE
+/* #define appName "XCdp - ecFlowview" */
+ #define appName "XCdp"
+#else
+#define appName "ecFlowview"
+#endif
+
+#define clientName "ecflow_client"
+#define snapshotName "${TMPDIR:=/tmp}/ecflowview$USER.png"
+#define browserName "${BROWSER:firefox --new-tab}"
+#define urlRef "http://software.ecmwf.int/issues/browse/ECFLOW"
+#define tmpName "ecFlowvw" /* 8 char */
+
+#if 1 // DEBUG
+#define XECFDEBUG if(getenv("XECFLOW_DEBUG"))
+#else
+#define XECFDEBUG if (0)
+#endif
+#endif
diff --git a/view/src/ecflowview.menu b/view/src/ecflowview.menu
new file mode 100644
index 0000000..f08ae77
--- /dev/null
+++ b/view/src/ecflowview.menu
@@ -0,0 +1,350 @@
+!===========================================================
+! Name :
+! Author :
+! Revision : $Revision: #26 $
+!
+! Copyright 2009-2016 ECMWF.
+! This software is licensed under the terms of the Apache Licence version 2.0
+! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+! In applying this licence, ECMWF does not waive the privileges and immunities
+! granted to it by virtue of its status as an intergovernmental organisation
+! nor does it submit to any jurisdiction.
+!
+! Description :
+! this file may be found in
+! - ecflowview sources in order to generate ecflowview.menu.h
+! - ~/.ecflowrc/ecflowview.menu # edit backup remove (reset)
+! - ~/ is preferred to $HOME
+! - menus can call ecflow client command (start with 'ecflow_client')
+! - menus can call system command (start with sh)
+!===========================================================
+!
+! Format
+!-------
+! menu TITLE
+! {
+! (vis flg,enable flg,title,command,question,answer)
+! }
+!
+!===========================================================
+!
+! Values for the status flags
+!----------------------------
+!
+!NONE ALL UNKNOWN SUSPENDED COMPLETE QUEUED SUBMITTED ACTIVE
+!ABORTED CLEAR SET SHUTDOWN HALTED
+!
+! Values for type flags
+!----------------------
+!
+!NONE ALL SERVER SUITE FAMILY TASK EVENT
+!
+! Values for visible flags
+!-------------------------
+!
+!NONE ALL SERVER SUITE FAMILY TASK EVENT
+!
+! Values for special flags
+!-------------------------
+!
+!NONE ALL HAS_TRIGGERS HAS_TIME HAS_DATE
+!
+!===========================================================
+
+!==============================================================================
+! Main menu
+!==============================================================================
+
+version 1 0 0 ;
+
+menu 'MAIN'
+{
+ (~SUSPENDED & NODE, ALL, 'Suspend', 'ecflow_client --suspend <full_name>')
+ (SUSPENDED & NODE, ALL, 'Resume', 'ecflow_client --resume <full_name>')
+
+ ( TASK, ~ACTIVE & ~SUBMITTED, 'Rerun', 'ecflow_client --force queued <full_name>')
+
+ (TASK | ALIAS, ALL, 'Set', MENU)
+
+ (TASK|ALIAS, ~ACTIVE & ~SUBMITTED, 'Execute', 'ecflow_client --run <full_name>')
+
+ (SUITE|TASK|FAMILY, ~ACTIVE & ~SUBMITTED, 'Requeue',
+ 'ecflow_client --requeue force <full_name>',
+ 'Confirm requeuing of <full_name>', YES)
+
+ (SUITE|FAMILY, ABORTED | SUSPENDED, 'Requeue aborted',
+ 'ecflow_client --requeue abort <full_name>',
+ 'Confirm requeuing of aborted tasks from <full_name>', YES)
+
+ (ALL,ALL,'-',SEPARATOR)
+
+ (SUITE|TASK|FAMILY,(QUEUED|SUSPENDED|ACTIVE) & (HAS_TRIGGERS|HAS_TIME|HAS_DATE),'Delete',MENU)
+ (NODE | ALIAS, ALL, 'Special', MENU)
+ (NODE | ALIAS, ALL, 'Defstatus', MENU)
+ (NODE & ADMIN, ALL, 'Force', MENU)
+ ((NODE|ALIAS)& ADMIN, ALL,'Order', MENU)
+
+ (ALL,ALL,'-',SEPARATOR ,'',YES)
+ (SUITE|FAMILY, ALL, 'Web...', 'ecflow_client --url <full_name> ', '', YES)
+ (TASK, ALL, 'Web', MENU)
+
+ (ALL,ALL,'-',SEPARATOR)
+
+ (SUITE & (OPER|ADMIN) ,UNKNOWN|COMPLETE,'Begin',
+ 'ecflow_client --begin <node_name>','',YES)
+
+ (SUITE & (OPER|ADMIN) ,~SUBMITTED & ~ACTIVE,'Cancel',
+ 'ecflow_client --delete yes <full_name>',
+ 'Do you really want to cancel suite <full_name> ?',NO)
+
+! Events
+!---------------------------------
+
+ (EVENT, CLEAR, 'Set' ,
+ 'ecflow_client --alter change event <node_name> set <parent_name>', '',YES)
+ (EVENT, SET, 'Clear',
+ 'ecflow_client --alter change event <node_name> clear <parent_name>', '',YES)
+
+!!-----------------------------------
+
+ (SERVER & (ADMIN|OPER) & LOCKED , ALL , 'Unlock', 'unlock -y',
+ 'Before going further, please check why the server was locked.',NO)
+ (ALL,ALL,'-',SEPARATOR,'',YES)
+
+!!-----------------------------------
+
+ (SERVER,SHUTDOWN|HALTED, 'Restart',
+ 'ecflow_client --restart yes','Restart the server in <node_name>?' ,NO)
+ (SERVER,~SHUTDOWN, 'Shutdown',
+ 'ecflow_client --shutdown yes','Shutdown the server in <node_name>?',NO)
+ (SERVER,~HALTED, 'Halt',
+ 'ecflow_client --halt yes','Halt the server in <node_name>?',NO)
+ (SERVER,HALTED|UNKNOWN, 'Terminate',
+ 'ecflow_client --terminate yes','Terminate the server in <node_name>?',NO)
+ (ALL,ALL,'-',SEPARATOR,'',YES)
+ (SERVER,ALL, 'Checkpoint','ecflow_client --check_pt','',YES)
+ (SERVER,HALTED, 'Recover',
+ 'ecflow_client --restore_from_checkpt','Recover the server in <node_name>?',NO)
+
+!!-----------------------------------
+
+ (LIMIT , ALL, 'Reset' ,
+ 'ecflow_client --alter change limit_value <node_name> 0 <parent_name>',
+ 'Confirm resetting <full_name>', YES)
+ (ALIAS , ALL, 'Remove', 'ecflow_client --delete yes <full_name>',
+ 'Confirm remove alias <full_name>', YES)
+
+!!-----------------------------------
+
+ (ALL,ALL,'-',SEPARATOR)
+
+ (TASK|LIMIT|LABEL|METER|REPEAT|VARIABLE, ALL , 'Edit...', WINDOW(Edit))
+ (TASK|ALIAS, ALL , 'Output...', WINDOW(Output) )
+
+ (TASK|ALIAS, SUBMITTED|ACTIVE , 'Status...', WINDOW(Jobstatus))
+ (ALIAS, ALL , 'Job...', WINDOW(Job) )
+ (TASK|ALIAS, ALL , 'Script...', WINDOW(Script) )
+
+ (SERVER, ALL , 'Suites...', WINDOW(Suites) )
+ (SERVER, ALL , 'History...', WINDOW(History) )
+ (SERVER, ALL , 'Zombies...', WINDOW(Zombies) )
+ (ALL,ALL,'-',SEPARATOR)
+ (SERVER, ALL , 'Options...', WINDOW(Options) )
+ (SERVER, ALL , 'Extra', MENU )
+ (SERVER, ALL , 'Ping', 'sh ecflow_client --port %ECF_PORT% --host %ECF_NODE% --ping' )
+ (SERVER, ALL , 'Stat', 'sh ecflow_client --port %ECF_PORT% --host %ECF_NODE% --stats' )
+}
+
+menu 'Set'
+{
+ (TASK|ALIAS, SUBMITTED|ACTIVE, 'Set complete',
+ 'ecflow_client --force complete <full_name>',
+ 'Have you checked that the job is not active anymore (jobstatus) ?', YES)
+ (TASK|ALIAS, UNKNOWN|QUEUED|ABORTED, 'Set complete',
+ 'ecflow_client --force complete <full_name>')
+ (TASK|ALIAS, SUBMITTED|ACTIVE, 'Set aborted',
+ 'ecflow_client --force aborted <full_name>',
+ 'Have you checked that the job is not active anymore (jobstatus) ?', YES)
+ (TASK|ALIAS, UNKNOWN|QUEUED|COMPLETE, 'Set aborted',
+ 'ecflow_client --force aborted <full_name>')
+}
+
+menu 'Web'
+{
+! (TASK, ALL, 'Web...', 'ecflow_client --url <full_name> ', '', YES)
+ (NODE, ALL , 'WebM', MENU )
+ (NODE, ALL , 'WebW', MENU )
+}
+
+menu 'WebM'
+{
+ (TASK, ALL, 'Web...', 'ecflow_client --url <full_name> ', '', YES)
+ (TASK, ALL, 'Man', 'sh firefox %ECF_URL_BASE%/%ECF_URL%', '', YES)
+ (TASK, ALL, 'Script', 'sh xterm -T Script -e vim %ECF_SCRIPT%', '', YES)
+ (TASK, ALL, 'Job', 'sh xterm -T Job -e vim %ECF_JOB%', '', YES)
+ (TASK, ALL, 'Output', 'sh xterm -T Output -e vim %ECF_JOBOUT%', '', YES)
+ (TASK, ALL , 'TimeLine...', WINDOW(Timeline))
+ ! request from Lidström Jonas https://software.ecmwf.int/issues/browse/SUP-829
+ (TASK, ALL, 'Details', 'sh xterm -T Details-%ECF_NAME% -e "grep %ECF_NAME% %ECF_LOG% ; read"')
+}
+
+menu 'WebW'
+{
+ (TASK, ALL, 'WMan', 'sh firefox ${ECFLOW_WEB:-http://eurus.ecmwf.int:8000/api/v1/ecflow}/%ECF_NODE:%/%ECF_PORT:%/man/%ECF_NAME:%', '', YES)
+ (TASK, ALL, 'WScript', 'sh firefox ${ECFLOW_WEB:-http://eurus.ecmwf.int:8000/api/v1/ecflow}/%ECF_NODE:%/%ECF_PORT:%/script/%ECF_NAME:%', '', YES)
+ (TASK, ALL, 'WJob', 'sh firefox ${ECFLOW_WEB:-http://eurus.ecmwf.int:8000/api/v1/ecflow}/%ECF_NODE:%/%ECF_PORT:%/job/%ECF_NAME:%', '', YES)
+ (TASK, ALL, 'WOut', 'sh firefox ${ECFLOW_WEB:-http://eurus.ecmwf.int:8000/api/v1/ecflow}/%ECF_NODE:%/%ECF_PORT:%/output/%ECF_NAME:%', '', YES)
+ (TASK, ALL, 'Suites', 'sh firefox ${ECFLOW_WEB:-http://eurus.ecmwf.int:8000/api/v1/ecflow}/%ECF_NODE:%/%ECF_PORT:%/suites', '', YES)
+ (TASK, ALL, 'Treemap', 'sh firefox ${ECFLOW_WEB:-http://eurus.ecmwf.int:8000/api/v1/ecflow}/%ECF_NODE:%/%ECF_PORT:%/suite/treemap/SAR/none/7/%SUITE:%', '', YES)
+ (TASK, ALL, 'Flask', 'sh firefox ${ECFLOW_WEB_MONITOR:-http://eurus.ecmwf.int:5001}', '', YES)
+}
+
+!==============================================================================
+! Status submenu
+!==============================================================================
+
+menu 'Status'
+{
+ (SUITE|TASK|FAMILY, ~SUSPENDED,'Suspend', 'ecflow_client --suspend <full_name>', '',YES)
+ (SUITE|TASK|FAMILY, SUSPENDED ,'Resume', 'ecflow_client --resume <full_name>', '',YES)
+
+ (ALL,ALL,'-',SEPARATOR)
+
+ (TASK, ~ACTIVE & ~SUBMITTED, 'Rerun', 'ecflow_client --force queued <full_name>', '',YES)
+ (TASK, ~COMPLETE, 'Set complete', 'ecflow_client --force complete <full_name>', '',YES)
+
+ (SUITE|TASK|FAMILY|ALIAS, ~ACTIVE & ~SUBMITTED,
+ 'Requeue','ecflow_client --requeue force <full_name>', 'Confirm requeuing of <full_name>', YES)
+
+ (SUITE|FAMILY, ABORTED | SUSPENDED,
+ 'Requeue aborted','ecflow_client --requeue abort <full_name>',
+ 'Confirm requeuing aborted tasks below <full_name>', YES)
+}
+
+!==============================================================================
+! Suite submenu
+!==============================================================================
+
+menu 'Suite'
+{
+ (SUITE,UNKNOWN|COMPLETE,'Begin','ecflow_client --begin <node_name>','',YES)
+
+ (SUITE,ALL,'Cancel','ecflow_client --delete yes <full_name>',
+ 'Do you really want to cancel <full_name> ?',NO)
+
+ (ALL,ALL,'-',SEPARATOR)
+}
+
+!==============================================================================
+! Delete submenu
+!==============================================================================
+
+menu 'Delete'
+{
+ (ALL,HAS_TRIGGERS|HAS_TIME|HAS_DATE, 'All dependencies','ecflow_client --free-dep all <full_name>')
+ (ALL,HAS_TRIGGERS, 'Trigger dependencies','ecflow_client --free-dep trigger <full_name>')
+ (ALL,HAS_TIME, 'Time dependencies','ecflow_client --free-dep time <full_name>')
+ (ALL,QUEUED, 'Date dependencies','ecflow_client --free-dep date <full_name>')
+}
+
+menu "Order"
+{
+ (ALL,ALL,'Top','ecflow_client --order <full_name> top')
+ (ALL,ALL,'Up','ecflow_client --order <full_name> up')
+ (ALL,ALL,'Down','ecflow_client --order <full_name> down')
+ (ALL,ALL,'Bottom','ecflow_client --order <full_name> bottom')
+ (ALL,ALL,'Alphabetically','ecflow_client --order <full_name> alpha')
+}
+
+menu "Force"
+{
+ (NODE, ~UNKNOWN, 'Unknown', 'ecflow_client --force unknown recursive <full_name>')
+ (NODE, ~COMPLETE & ~ACTIVE & ~SUBMITTED, 'Complete',
+ 'ecflow_client --force complete recursive <full_name>',
+ 'Check running/queued jobs and Confirm force complete of <full_name>', YES)
+ (NODE, ~QUEUED & ~ACTIVE & ~SUBMITTED, 'Queued',
+ 'ecflow_client --force queued recursive <full_name>')
+ (NODE, ~SUBMITTED & ~ACTIVE,'Submitted',
+ 'ecflow_client --force submitted recursive <full_name>')
+ (NODE, ~ACTIVE, 'Active', 'ecflow_client --force active recursive <full_name>')
+ (NODE, ~ABORTED, 'Aborted', 'ecflow_client --force aborted recursive <full_name>',
+ 'Check running/queued jobs and Confirm force submitted of <full_name>', YES)
+}
+
+menu "Defstatus"
+{
+(NODE, ALL, 'Complete', 'ecflow_client --alter change defstatus complete <full_name>')
+(NODE, ALL, 'Queued', 'ecflow_client --alter change defstatus queued <full_name>')
+}
+
+menu "Special"
+{
+ (SUITE|FAMILY,(ACTIVE|SUBMITTED|ABORTED),'Kill', 'ecflow_client --kill <full_name>','',YES)
+ (TASK|ALIAS,(ACTIVE|SUBMITTED),'Kill','ecflow_client --kill <full_name>','',YES)
+ (ALL,ALL,'Check',WINDOW(Check),'',YES)
+ (TASK|ALIAS,ALL,'Free password','ecflow_client --alter add variable ECF_PASS FREE <full_name>')
+ (TASK|ALIAS,ALL,'ClearZ','ecflow_client --alter clear_flag zombie <full_name>')
+ (TASK|ALIAS,ALL,'ClearLate','ecflow_client --alter clear_flag late <full_name>')
+ (TASK|ALIAS,ALL,'ClearKill','ecflow_client --alter clear_flag killed <full_name>')
+
+ (FAMILY, ~ACTIVE & ~SUBMITTED, 'Execute', 'ecflow_client --run <full_name>')
+ ((SUITE|FAMILY|TASK), SELECTION, 'Plug into selected node', PLUG)
+ (FAMILY|TASK,ALL,'get','ecflow_client --get <full_name>')
+ (TASK,ALL,'status','ecflow_client --status <full_name>')
+ (SUITE|SERVER, ALL, 'Collect...', WINDOW(Collector))
+ (SUITE|FAMILY, ALL, 'Walk', 'ecflow_client --force-dep-eval <full_name>')
+}
+
+menu "Extra"
+{
+ (SERVER|SUITE,ALL,'Windows', MENU)
+ (ALL,ALL,'-',SEPARATOR)
+ (SERVER,ALL,'ClearLate','ecflow_client --alter clear_flag late <full_name>')
+ ! (SERVER|SUITE,ALL,'tail log', 'sh /usr/bin/xterm -e rsh %ECF_NODE% tail -f %ECF_HOME%/%ECF_LOG%&')
+(SERVER|SUITE,ALL,'tail log', 'sh /usr/bin/xterm -e tail -f /tmp/$USER/$HOST*.ecf.log&')
+ (ALL,ALL,'-',SEPARATOR)
+ (SERVER|SUITE,ALL,'svr load','ecflow_load.sh -h %ECF_HOME% -l %ECF_LOG% -n %ECF_NODE% -p %ECF_PORT%')
+! (SERVER|SUITE,ALL,'svr load','ecflow_client --server_load')
+! (SERVER|SUITE,ALL,'svr load log','ecflow_client --server_load %ECF_LOG%')
+! (SERVER|SUITE,ALL,'svr load home/log','ecflow_client --server_load %ECF_HOME%/%ECF_LOG%')
+! (SERVER|SUITE,ALL,'show png','sh ${EOG:-eog} %ECF_NODE%.%ECF_PORT%.png')
+! one menu to replace four previous when it works
+! (SERVER|SUITE,ALL,'show load','sh ecflow_show_load.sh -n %ECF_NODE% -p %ECF_PORT% -h %ECF_HOME% %ECF_LOG%')
+
+ (ALL,ALL,'-',SEPARATOR)
+ (SERVER|SUITE,ALL,'overwrite', 'write menu')
+ (SERVER|SUITE,ALL,'edit menu', 'sh /usr/bin/xterm -e vi ~/.ecflowrc/ecflowview.menu')
+ (SERVER|SUITE,ALL,'bkup menu', 'sh /bin/cp ~/.ecflowrc/ecflowview.menu ~/.ecflowrc/ecflowview.menu.bak')
+ (SERVER|SUITE,ALL,'rm menu', 'sh /bin/rm ~/.ecflowrc/ecflowview.menu')
+ (ALL,ALL,'-',SEPARATOR)
+ (SERVER|SUITE,ALL,'debug on', 'ecflow_client --debug_server_on')
+ (SERVER|SUITE,ALL,'debug off','ecflow_client --debug_server_off')
+ (ALL,ALL,'-',SEPARATOR)
+ (SERVER|SUITE,ALL,'stats','ecflow_client --stats')
+ (SERVER|SUITE,ALL,'suites','ecflow_client --suites')
+ (ALL,ALL,'-',SEPARATOR)
+ (SERVER|SUITE,ALL,'log get','ecflow_client --log get')
+ (SERVER|SUITE,ALL,'log clear','ecflow_client --log clear')
+ (SERVER|SUITE,ALL,'log new','ecflow_client --log new')
+ (ALL,ALL,'-',SEPARATOR)
+ (SERVER|SUITE,ALL,'client logging on','ecflow_client --enable_logging')
+ (SERVER|SUITE,ALL,'client loggging off','ecflow_client --disable_logging')
+}
+
+menu "Windows"
+{
+ (SERVER, ALL , 'Info...', WINDOW(Info))
+ (SERVER, ALL , 'Man...', WINDOW(Manual))
+ (SERVER, ALL , 'Var...', WINDOW(Variables))
+ (SERVER, ALL , 'Msg...', WINDOW(Messages))
+ (SERVER, ALL , 'Why...', WINDOW(Why))
+ (SERVER, ALL , 'Triggers...', WINDOW(Triggers))
+ (SERVER, ALL , 'Check...', WINDOW(Check))
+ (SERVER, ALL , 'Jobstatus...', WINDOW(Jobstatus))
+ (SERVER, ALL , 'TimeLine...', WINDOW(Timeline))
+}
+
+! DIRRC=~/.ecflowrc; rm -rf $DIRRC; mkdir $DIRRC
+
+! lm=src/ecflowview.menu; um=$HOME/.ecflowrc/ecflowview.menu; rm $um
+! sh src/menu2c.sh < $lm > ${lm}.h && cp -f $lm $um
diff --git a/view/src/ecflowview.menu.h b/view/src/ecflowview.menu.h
new file mode 100644
index 0000000..3a7b374
--- /dev/null
+++ b/view/src/ecflowview.menu.h
@@ -0,0 +1,351 @@
+(char*) " !=========================================================== ",
+(char*) " ! Name : ",
+(char*) " ! Author : ",
+(char*) " ! Revision : $Revision: #26 $ ",
+(char*) " ! ",
+(char*) " ! Copyright 2009-2016 ECMWF. ",
+(char*) " ! This software is licensed under the terms of the Apache Licence version 2.0 ",
+(char*) " ! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. ",
+(char*) " ! In applying this licence, ECMWF does not waive the privileges and immunities ",
+(char*) " ! granted to it by virtue of its status as an intergovernmental organisation ",
+(char*) " ! nor does it submit to any jurisdiction. ",
+(char*) " ! ",
+(char*) " ! Description : ",
+(char*) " ! this file may be found in ",
+(char*) " ! - ecflowview sources in order to generate ecflowview.menu.h ",
+(char*) " ! - ~/.ecflowrc/ecflowview.menu # edit backup remove (reset) ",
+(char*) " ! - ~/ is preferred to $HOME ",
+(char*) " ! - menus can call ecflow client command (start with 'ecflow_client') ",
+(char*) " ! - menus can call system command (start with sh) ",
+(char*) " !=========================================================== ",
+(char*) " ! ",
+(char*) " ! Format ",
+(char*) " !------- ",
+(char*) " ! menu TITLE ",
+(char*) " ! { ",
+(char*) " ! (vis flg,enable flg,title,command,question,answer) ",
+(char*) " ! } ",
+(char*) " ! ",
+(char*) " !=========================================================== ",
+(char*) " ! ",
+(char*) " ! Values for the status flags ",
+(char*) " !---------------------------- ",
+(char*) " ! ",
+(char*) " !NONE ALL UNKNOWN SUSPENDED COMPLETE QUEUED SUBMITTED ACTIVE ",
+(char*) " !ABORTED CLEAR SET SHUTDOWN HALTED ",
+(char*) " ! ",
+(char*) " ! Values for type flags ",
+(char*) " !---------------------- ",
+(char*) " ! ",
+(char*) " !NONE ALL SERVER SUITE FAMILY TASK EVENT ",
+(char*) " ! ",
+(char*) " ! Values for visible flags ",
+(char*) " !------------------------- ",
+(char*) " ! ",
+(char*) " !NONE ALL SERVER SUITE FAMILY TASK EVENT ",
+(char*) " ! ",
+(char*) " ! Values for special flags ",
+(char*) " !------------------------- ",
+(char*) " ! ",
+(char*) " !NONE ALL HAS_TRIGGERS HAS_TIME HAS_DATE ",
+(char*) " ! ",
+(char*) " !=========================================================== ",
+(char*) " ",
+(char*) " !============================================================================== ",
+(char*) " ! Main menu ",
+(char*) " !============================================================================== ",
+(char*) " ",
+(char*) " version 1 0 0 ; ",
+(char*) " ",
+(char*) " menu 'MAIN' ",
+(char*) " { ",
+(char*) " (~SUSPENDED & NODE, ALL, 'Suspend', 'ecflow_client --suspend <full_name>') ",
+(char*) " (SUSPENDED & NODE, ALL, 'Resume', 'ecflow_client --resume <full_name>') ",
+(char*) " ",
+(char*) " ( TASK, ~ACTIVE & ~SUBMITTED, 'Rerun', 'ecflow_client --force queued <full_name>') ",
+(char*) " ",
+(char*) " (TASK | ALIAS, ALL, 'Set', MENU) ",
+(char*) " ",
+(char*) " (TASK|ALIAS, ~ACTIVE & ~SUBMITTED, 'Execute', 'ecflow_client --run <full_name>') ",
+(char*) " ",
+(char*) " (SUITE|TASK|FAMILY, ~ACTIVE & ~SUBMITTED, 'Requeue', ",
+(char*) " 'ecflow_client --requeue force <full_name>', ",
+(char*) " 'Confirm requeuing of <full_name>', YES) ",
+(char*) " ",
+(char*) " (SUITE|FAMILY, ABORTED | SUSPENDED, 'Requeue aborted', ",
+(char*) " 'ecflow_client --requeue abort <full_name>', ",
+(char*) " 'Confirm requeuing of aborted tasks from <full_name>', YES) ",
+(char*) " ",
+(char*) " (ALL,ALL,'-',SEPARATOR) ",
+(char*) " ",
+(char*) " (SUITE|TASK|FAMILY,(QUEUED|SUSPENDED|ACTIVE) & (HAS_TRIGGERS|HAS_TIME|HAS_DATE),'Delete',MENU) ",
+(char*) " (NODE | ALIAS, ALL, 'Special', MENU) ",
+(char*) " (NODE | ALIAS, ALL, 'Defstatus', MENU) ",
+(char*) " (NODE & ADMIN, ALL, 'Force', MENU) ",
+(char*) " ((NODE|ALIAS)& ADMIN, ALL,'Order', MENU) ",
+(char*) " ",
+(char*) " (ALL,ALL,'-',SEPARATOR ,'',YES) ",
+(char*) " (SUITE|FAMILY, ALL, 'Web...', 'ecflow_client --url <full_name> ', '', YES) ",
+(char*) " (TASK, ALL, 'Web', MENU) ",
+(char*) " ",
+(char*) " (ALL,ALL,'-',SEPARATOR) ",
+(char*) " ",
+(char*) " (SUITE & (OPER|ADMIN) ,UNKNOWN|COMPLETE,'Begin', ",
+(char*) " 'ecflow_client --begin <node_name>','',YES) ",
+(char*) " ",
+(char*) " (SUITE & (OPER|ADMIN) ,~SUBMITTED & ~ACTIVE,'Cancel', ",
+(char*) " 'ecflow_client --delete yes <full_name>', ",
+(char*) " 'Do you really want to cancel suite <full_name> ?',NO) ",
+(char*) " ",
+(char*) " ! Events ",
+(char*) " !--------------------------------- ",
+(char*) " ",
+(char*) " (EVENT, CLEAR, 'Set' , ",
+(char*) " 'ecflow_client --alter change event <node_name> set <parent_name>', '',YES) ",
+(char*) " (EVENT, SET, 'Clear', ",
+(char*) " 'ecflow_client --alter change event <node_name> clear <parent_name>', '',YES) ",
+(char*) " ",
+(char*) " !!----------------------------------- ",
+(char*) " ",
+(char*) " (SERVER & (ADMIN|OPER) & LOCKED , ALL , 'Unlock', 'unlock -y', ",
+(char*) " 'Before going further, please check why the server was locked.',NO) ",
+(char*) " (ALL,ALL,'-',SEPARATOR,'',YES) ",
+(char*) " ",
+(char*) " !!----------------------------------- ",
+(char*) " ",
+(char*) " (SERVER,SHUTDOWN|HALTED, 'Restart', ",
+(char*) " 'ecflow_client --restart yes','Restart the server in <node_name>?' ,NO) ",
+(char*) " (SERVER,~SHUTDOWN, 'Shutdown', ",
+(char*) " 'ecflow_client --shutdown yes','Shutdown the server in <node_name>?',NO) ",
+(char*) " (SERVER,~HALTED, 'Halt', ",
+(char*) " 'ecflow_client --halt yes','Halt the server in <node_name>?',NO) ",
+(char*) " (SERVER,HALTED|UNKNOWN, 'Terminate', ",
+(char*) " 'ecflow_client --terminate yes','Terminate the server in <node_name>?',NO) ",
+(char*) " (ALL,ALL,'-',SEPARATOR,'',YES) ",
+(char*) " (SERVER,ALL, 'Checkpoint','ecflow_client --check_pt','',YES) ",
+(char*) " (SERVER,HALTED, 'Recover', ",
+(char*) " 'ecflow_client --restore_from_checkpt','Recover the server in <node_name>?',NO) ",
+(char*) " ",
+(char*) " !!----------------------------------- ",
+(char*) " ",
+(char*) " (LIMIT , ALL, 'Reset' , ",
+(char*) " 'ecflow_client --alter change limit_value <node_name> 0 <parent_name>', ",
+(char*) " 'Confirm resetting <full_name>', YES) ",
+(char*) " (ALIAS , ALL, 'Remove', 'ecflow_client --delete yes <full_name>', ",
+(char*) " 'Confirm remove alias <full_name>', YES) ",
+(char*) " ",
+(char*) " !!----------------------------------- ",
+(char*) " ",
+(char*) " (ALL,ALL,'-',SEPARATOR) ",
+(char*) " ",
+(char*) " (TASK|LIMIT|LABEL|METER|REPEAT|VARIABLE, ALL , 'Edit...', WINDOW(Edit)) ",
+(char*) " (TASK|ALIAS, ALL , 'Output...', WINDOW(Output) ) ",
+(char*) " ",
+(char*) " (TASK|ALIAS, SUBMITTED|ACTIVE , 'Status...', WINDOW(Jobstatus)) ",
+(char*) " (ALIAS, ALL , 'Job...', WINDOW(Job) ) ",
+(char*) " (TASK|ALIAS, ALL , 'Script...', WINDOW(Script) ) ",
+(char*) " ",
+(char*) " (SERVER, ALL , 'Suites...', WINDOW(Suites) ) ",
+(char*) " (SERVER, ALL , 'History...', WINDOW(History) ) ",
+(char*) " (SERVER, ALL , 'Zombies...', WINDOW(Zombies) ) ",
+(char*) " (ALL,ALL,'-',SEPARATOR) ",
+(char*) " (SERVER, ALL , 'Options...', WINDOW(Options) ) ",
+(char*) " (SERVER, ALL , 'Extra', MENU ) ",
+(char*) " (SERVER, ALL , 'Ping', 'sh ecflow_client --port %ECF_PORT% --host %ECF_NODE% --ping' ) ",
+(char*) " (SERVER, ALL , 'Stat', 'sh ecflow_client --port %ECF_PORT% --host %ECF_NODE% --stats' ) ",
+(char*) " } ",
+(char*) " ",
+(char*) " menu 'Set' ",
+(char*) " { ",
+(char*) " (TASK|ALIAS, SUBMITTED|ACTIVE, 'Set complete', ",
+(char*) " 'ecflow_client --force complete <full_name>', ",
+(char*) " 'Have you checked that the job is not active anymore (jobstatus) ?', YES) ",
+(char*) " (TASK|ALIAS, UNKNOWN|QUEUED|ABORTED, 'Set complete', ",
+(char*) " 'ecflow_client --force complete <full_name>') ",
+(char*) " (TASK|ALIAS, SUBMITTED|ACTIVE, 'Set aborted', ",
+(char*) " 'ecflow_client --force aborted <full_name>', ",
+(char*) " 'Have you checked that the job is not active anymore (jobstatus) ?', YES) ",
+(char*) " (TASK|ALIAS, UNKNOWN|QUEUED|COMPLETE, 'Set aborted', ",
+(char*) " 'ecflow_client --force aborted <full_name>') ",
+(char*) " } ",
+(char*) " ",
+(char*) " menu 'Web' ",
+(char*) " { ",
+(char*) " ! (TASK, ALL, 'Web...', 'ecflow_client --url <full_name> ', '', YES) ",
+(char*) " (NODE, ALL , 'WebM', MENU ) ",
+(char*) " (NODE, ALL , 'WebW', MENU ) ",
+(char*) " } ",
+(char*) " ",
+(char*) " menu 'WebM' ",
+(char*) " { ",
+(char*) " (TASK, ALL, 'Web...', 'ecflow_client --url <full_name> ', '', YES) ",
+(char*) " (TASK, ALL, 'Man', 'sh firefox %ECF_URL_BASE%/%ECF_URL%', '', YES) ",
+(char*) " (TASK, ALL, 'Script', 'sh xterm -T Script -e vim %ECF_SCRIPT%', '', YES) ",
+(char*) " (TASK, ALL, 'Job', 'sh xterm -T Job -e vim %ECF_JOB%', '', YES) ",
+(char*) " (TASK, ALL, 'Output', 'sh xterm -T Output -e vim %ECF_JOBOUT%', '', YES) ",
+(char*) " (TASK, ALL , 'TimeLine...', WINDOW(Timeline)) ",
+(char*) " ! request from Lidström Jonas https://software.ecmwf.int/issues/browse/SUP-829 ",
+(char*) " (TASK, ALL, 'Details', 'sh xterm -T Details-%ECF_NAME% -e \"grep %ECF_NAME% %ECF_LOG% ; read\"') ",
+(char*) " } ",
+(char*) " ",
+(char*) " menu 'WebW' ",
+(char*) " { ",
+(char*) " (TASK, ALL, 'WMan', 'sh firefox ${ECFLOW_WEB:-http://eurus.ecmwf.int:8000/api/v1/ecflow}/%ECF_NODE:%/%ECF_PORT:%/man/%ECF_NAME:%', '', YES) ",
+(char*) " (TASK, ALL, 'WScript', 'sh firefox ${ECFLOW_WEB:-http://eurus.ecmwf.int:8000/api/v1/ecflow}/%ECF_NODE:%/%ECF_PORT:%/script/%ECF_NAME:%', '', YES) ",
+(char*) " (TASK, ALL, 'WJob', 'sh firefox ${ECFLOW_WEB:-http://eurus.ecmwf.int:8000/api/v1/ecflow}/%ECF_NODE:%/%ECF_PORT:%/job/%ECF_NAME:%', '', YES) ",
+(char*) " (TASK, ALL, 'WOut', 'sh firefox ${ECFLOW_WEB:-http://eurus.ecmwf.int:8000/api/v1/ecflow}/%ECF_NODE:%/%ECF_PORT:%/output/%ECF_NAME:%', '', YES) ",
+(char*) " (TASK, ALL, 'Suites', 'sh firefox ${ECFLOW_WEB:-http://eurus.ecmwf.int:8000/api/v1/ecflow}/%ECF_NODE:%/%ECF_PORT:%/suites', '', YES) ",
+(char*) " (TASK, ALL, 'Treemap', 'sh firefox ${ECFLOW_WEB:-http://eurus.ecmwf.int:8000/api/v1/ecflow}/%ECF_NODE:%/%ECF_PORT:%/suite/treemap/SAR/none/7/%SUITE:%', '', YES) ",
+(char*) " (TASK, ALL, 'Flask', 'sh firefox ${ECFLOW_WEB_MONITOR:-http://eurus.ecmwf.int:5001}', '', YES) ",
+(char*) " } ",
+(char*) " ",
+(char*) " !============================================================================== ",
+(char*) " ! Status submenu ",
+(char*) " !============================================================================== ",
+(char*) " ",
+(char*) " menu 'Status' ",
+(char*) " { ",
+(char*) " (SUITE|TASK|FAMILY, ~SUSPENDED,'Suspend', 'ecflow_client --suspend <full_name>', '',YES) ",
+(char*) " (SUITE|TASK|FAMILY, SUSPENDED ,'Resume', 'ecflow_client --resume <full_name>', '',YES) ",
+(char*) " ",
+(char*) " (ALL,ALL,'-',SEPARATOR) ",
+(char*) " ",
+(char*) " (TASK, ~ACTIVE & ~SUBMITTED, 'Rerun', 'ecflow_client --force queued <full_name>', '',YES) ",
+(char*) " (TASK, ~COMPLETE, 'Set complete', 'ecflow_client --force complete <full_name>', '',YES) ",
+(char*) " ",
+(char*) " (SUITE|TASK|FAMILY|ALIAS, ~ACTIVE & ~SUBMITTED, ",
+(char*) " 'Requeue','ecflow_client --requeue force <full_name>', 'Confirm requeuing of <full_name>', YES) ",
+(char*) " ",
+(char*) " (SUITE|FAMILY, ABORTED | SUSPENDED, ",
+(char*) " 'Requeue aborted','ecflow_client --requeue abort <full_name>', ",
+(char*) " 'Confirm requeuing aborted tasks below <full_name>', YES) ",
+(char*) " } ",
+(char*) " ",
+(char*) " !============================================================================== ",
+(char*) " ! Suite submenu ",
+(char*) " !============================================================================== ",
+(char*) " ",
+(char*) " menu 'Suite' ",
+(char*) " { ",
+(char*) " (SUITE,UNKNOWN|COMPLETE,'Begin','ecflow_client --begin <node_name>','',YES) ",
+(char*) " ",
+(char*) " (SUITE,ALL,'Cancel','ecflow_client --delete yes <full_name>', ",
+(char*) " 'Do you really want to cancel <full_name> ?',NO) ",
+(char*) " ",
+(char*) " (ALL,ALL,'-',SEPARATOR) ",
+(char*) " } ",
+(char*) " ",
+(char*) " !============================================================================== ",
+(char*) " ! Delete submenu ",
+(char*) " !============================================================================== ",
+(char*) " ",
+(char*) " menu 'Delete' ",
+(char*) " { ",
+(char*) " (ALL,HAS_TRIGGERS|HAS_TIME|HAS_DATE, 'All dependencies','ecflow_client --free-dep all <full_name>') ",
+(char*) " (ALL,HAS_TRIGGERS, 'Trigger dependencies','ecflow_client --free-dep trigger <full_name>') ",
+(char*) " (ALL,HAS_TIME, 'Time dependencies','ecflow_client --free-dep time <full_name>') ",
+(char*) " (ALL,QUEUED, 'Date dependencies','ecflow_client --free-dep date <full_name>') ",
+(char*) " } ",
+(char*) " ",
+(char*) " menu \"Order\" ",
+(char*) " { ",
+(char*) " (ALL,ALL,'Top','ecflow_client --order <full_name> top') ",
+(char*) " (ALL,ALL,'Up','ecflow_client --order <full_name> up') ",
+(char*) " (ALL,ALL,'Down','ecflow_client --order <full_name> down') ",
+(char*) " (ALL,ALL,'Bottom','ecflow_client --order <full_name> bottom') ",
+(char*) " (ALL,ALL,'Alphabetically','ecflow_client --order <full_name> alpha') ",
+(char*) " } ",
+(char*) " ",
+(char*) " menu \"Force\" ",
+(char*) " { ",
+(char*) " (NODE, ~UNKNOWN, 'Unknown', 'ecflow_client --force unknown recursive <full_name>') ",
+(char*) " (NODE, ~COMPLETE & ~ACTIVE & ~SUBMITTED, 'Complete', ",
+(char*) " 'ecflow_client --force complete recursive <full_name>', ",
+(char*) " 'Check running/queued jobs and Confirm force complete of <full_name>', YES) ",
+(char*) " (NODE, ~QUEUED & ~ACTIVE & ~SUBMITTED, 'Queued', ",
+(char*) " 'ecflow_client --force queued recursive <full_name>') ",
+(char*) " (NODE, ~SUBMITTED & ~ACTIVE,'Submitted', ",
+(char*) " 'ecflow_client --force submitted recursive <full_name>') ",
+(char*) " (NODE, ~ACTIVE, 'Active', 'ecflow_client --force active recursive <full_name>') ",
+(char*) " (NODE, ~ABORTED, 'Aborted', 'ecflow_client --force aborted recursive <full_name>', ",
+(char*) " 'Check running/queued jobs and Confirm force submitted of <full_name>', YES) ",
+(char*) " } ",
+(char*) " ",
+(char*) " menu \"Defstatus\" ",
+(char*) " { ",
+(char*) " (NODE, ALL, 'Complete', 'ecflow_client --alter change defstatus complete <full_name>') ",
+(char*) " (NODE, ALL, 'Queued', 'ecflow_client --alter change defstatus queued <full_name>') ",
+(char*) " } ",
+(char*) " ",
+(char*) " menu \"Special\" ",
+(char*) " { ",
+(char*) " (SUITE|FAMILY,(ACTIVE|SUBMITTED|ABORTED),'Kill', 'ecflow_client --kill <full_name>','',YES) ",
+(char*) " (TASK|ALIAS,(ACTIVE|SUBMITTED),'Kill','ecflow_client --kill <full_name>','',YES) ",
+(char*) " (ALL,ALL,'Check',WINDOW(Check),'',YES) ",
+(char*) " (TASK|ALIAS,ALL,'Free password','ecflow_client --alter add variable ECF_PASS FREE <full_name>') ",
+(char*) " (TASK|ALIAS,ALL,'ClearZ','ecflow_client --alter clear_flag zombie <full_name>') ",
+(char*) " (TASK|ALIAS,ALL,'ClearLate','ecflow_client --alter clear_flag late <full_name>') ",
+(char*) " (TASK|ALIAS,ALL,'ClearKill','ecflow_client --alter clear_flag killed <full_name>') ",
+(char*) " ",
+(char*) " (FAMILY, ~ACTIVE & ~SUBMITTED, 'Execute', 'ecflow_client --run <full_name>') ",
+(char*) " ((SUITE|FAMILY|TASK), SELECTION, 'Plug into selected node', PLUG) ",
+(char*) " (FAMILY|TASK,ALL,'get','ecflow_client --get <full_name>') ",
+(char*) " (TASK,ALL,'status','ecflow_client --status <full_name>') ",
+(char*) " (SUITE|SERVER, ALL, 'Collect...', WINDOW(Collector)) ",
+(char*) " (SUITE|FAMILY, ALL, 'Walk', 'ecflow_client --force-dep-eval <full_name>') ",
+(char*) " } ",
+(char*) " ",
+(char*) " menu \"Extra\" ",
+(char*) " { ",
+(char*) " (SERVER|SUITE,ALL,'Windows', MENU) ",
+(char*) " (ALL,ALL,'-',SEPARATOR) ",
+(char*) " (SERVER,ALL,'ClearLate','ecflow_client --alter clear_flag late <full_name>') ",
+(char*) " ! (SERVER|SUITE,ALL,'tail log', 'sh /usr/bin/xterm -e rsh %ECF_NODE% tail -f %ECF_HOME%/%ECF_LOG%&') ",
+(char*) " (SERVER|SUITE,ALL,'tail log', 'sh /usr/bin/xterm -e tail -f /tmp/$USER/$HOST*.ecf.log&') ",
+(char*) " (ALL,ALL,'-',SEPARATOR) ",
+(char*) " (SERVER|SUITE,ALL,'svr load','ecflow_load.sh -h %ECF_HOME% -l %ECF_LOG% -n %ECF_NODE% -p %ECF_PORT%') ",
+(char*) " ! (SERVER|SUITE,ALL,'svr load','ecflow_client --server_load') ",
+(char*) " ! (SERVER|SUITE,ALL,'svr load log','ecflow_client --server_load %ECF_LOG%') ",
+(char*) " ! (SERVER|SUITE,ALL,'svr load home/log','ecflow_client --server_load %ECF_HOME%/%ECF_LOG%') ",
+(char*) " ! (SERVER|SUITE,ALL,'show png','sh ${EOG:-eog} %ECF_NODE%.%ECF_PORT%.png') ",
+(char*) " ! one menu to replace four previous when it works ",
+(char*) " ! (SERVER|SUITE,ALL,'show load','sh ecflow_show_load.sh -n %ECF_NODE% -p %ECF_PORT% -h %ECF_HOME% %ECF_LOG%') ",
+(char*) " ",
+(char*) " (ALL,ALL,'-',SEPARATOR) ",
+(char*) " (SERVER|SUITE,ALL,'overwrite', 'write menu') ",
+(char*) " (SERVER|SUITE,ALL,'edit menu', 'sh /usr/bin/xterm -e vi ~/.ecflowrc/ecflowview.menu') ",
+(char*) " (SERVER|SUITE,ALL,'bkup menu', 'sh /bin/cp ~/.ecflowrc/ecflowview.menu ~/.ecflowrc/ecflowview.menu.bak') ",
+(char*) " (SERVER|SUITE,ALL,'rm menu', 'sh /bin/rm ~/.ecflowrc/ecflowview.menu') ",
+(char*) " (ALL,ALL,'-',SEPARATOR) ",
+(char*) " (SERVER|SUITE,ALL,'debug on', 'ecflow_client --debug_server_on') ",
+(char*) " (SERVER|SUITE,ALL,'debug off','ecflow_client --debug_server_off') ",
+(char*) " (ALL,ALL,'-',SEPARATOR) ",
+(char*) " (SERVER|SUITE,ALL,'stats','ecflow_client --stats') ",
+(char*) " (SERVER|SUITE,ALL,'suites','ecflow_client --suites') ",
+(char*) " (ALL,ALL,'-',SEPARATOR) ",
+(char*) " (SERVER|SUITE,ALL,'log get','ecflow_client --log get') ",
+(char*) " (SERVER|SUITE,ALL,'log clear','ecflow_client --log clear') ",
+(char*) " (SERVER|SUITE,ALL,'log new','ecflow_client --log new') ",
+(char*) " (ALL,ALL,'-',SEPARATOR) ",
+(char*) " (SERVER|SUITE,ALL,'client logging on','ecflow_client --enable_logging') ",
+(char*) " (SERVER|SUITE,ALL,'client loggging off','ecflow_client --disable_logging') ",
+(char*) " } ",
+(char*) " ",
+(char*) " menu \"Windows\" ",
+(char*) " { ",
+(char*) " (SERVER, ALL , 'Info...', WINDOW(Info)) ",
+(char*) " (SERVER, ALL , 'Man...', WINDOW(Manual)) ",
+(char*) " (SERVER, ALL , 'Var...', WINDOW(Variables)) ",
+(char*) " (SERVER, ALL , 'Msg...', WINDOW(Messages)) ",
+(char*) " (SERVER, ALL , 'Why...', WINDOW(Why)) ",
+(char*) " (SERVER, ALL , 'Triggers...', WINDOW(Triggers)) ",
+(char*) " (SERVER, ALL , 'Check...', WINDOW(Check)) ",
+(char*) " (SERVER, ALL , 'Jobstatus...', WINDOW(Jobstatus)) ",
+(char*) " (SERVER, ALL , 'TimeLine...', WINDOW(Timeline)) ",
+(char*) " } ",
+(char*) " ",
+(char*) " ! DIRRC=~/.ecflowrc; rm -rf $DIRRC; mkdir $DIRRC ",
+(char*) " ",
+(char*) " ! lm=src/ecflowview.menu; um=$HOME/.ecflowrc/ecflowview.menu; rm $um ",
+(char*) " ! sh src/menu2c.sh < $lm > ${lm}.h && cp -f $lm $um ",
+NULL
diff --git a/view/src/edit.cc b/view/src/edit.cc
new file mode 100644
index 0000000..b5947a0
--- /dev/null
+++ b/view/src/edit.cc
@@ -0,0 +1,265 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #13 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <unistd.h>
+#include "host.h"
+#include "edit.h"
+#include "node.h"
+#include "globals.h"
+#include "input.h"
+#include "error.h"
+#include "lister.h"
+#include "tmp_file.h"
+
+#include <Xm/Label.h>
+#include <Xm/Text.h>
+#include <Xm/ToggleB.h>
+#include <X11/IntrinsicP.h>
+#include <vector>
+
+static const char* micro="%";
+const char* sStart = "comment - ecf user variables";
+const char* sEnd = "end - ecf user variables";
+
+extern "C" {
+#include "xec.h"
+}
+
+edit::edit(panel_window& w):
+ panel(w),
+ text_window(false),
+ loading_(False),
+ preproc_(False),
+ tmp_(0), kStart(0x0), kEnd(0x0)
+{
+ if (kStart==NULL)
+ kStart=(char*)calloc(1024, sizeof(char*));
+ if (kEnd==NULL)
+ kEnd=(char*)calloc(1024, sizeof(char*));
+}
+
+edit::~edit()
+{
+ if(tmp_) XtFree(tmp_);
+ if (kStart) free(kStart);
+ if (kEnd) free(kEnd);
+}
+
+void edit::create (Widget parent, char *widget_name )
+{
+ edit_form_c::create(parent,widget_name);
+ XmToggleButtonSetState(alias_, globals::get_resource("send_as_alias", 0), FALSE);
+}
+
+void edit::clear()
+{
+ loading_ = True;
+ XmTextSetString(text_,(char*)"");
+ loading_ = False;
+}
+
+void edit::show(node& n)
+{
+ loading_ = True;
+ XmTextSetString(text_,(char*)"");
+
+ // tmp_file v(tmpnam(0), true); FILE *f = fopen(v.c_str(),"w");
+ char tmpname[] = "/tmp/xecfXXXXXX";
+ int fid = mkstemp(tmpname);
+ FILE *f = fdopen(fid, "w");
+
+ if(!f) {
+ gui::syserr(tmpname);
+ return;
+ }
+
+ std::list<Variable> vl; // FILL handle vl
+ tmp_file tmp(NULL);
+ tmp = n.serv().edit(n, vl, preproc_);
+
+ if(fclose(f)) {
+ gui::syserr(tmpname);
+ return;
+ }
+
+ try {
+ xec_LoadText(text_, tmpname, True);
+ xec_LoadText(text_, tmp.c_str(), True);
+
+ XmTextSetInsertionPosition(text_,0);
+ XmTextShowPosition(text_, 0);
+ } catch (...) { std::cerr << "# WAR: cannot load " << tmpname << "\n";}
+ loading_ = False;
+}
+
+void edit::changed(node&)
+{
+}
+
+Boolean edit::enabled(node& n)
+{
+ return n.type() == NODE_TASK;
+}
+
+void edit::changedCB(Widget,XtPointer data)
+{
+ if(!loading_) freeze();
+}
+
+void edit::preprocCB(Widget,XtPointer data)
+{
+ preproc_ = XmToggleButtonGetState(preprocess_);
+ if(get_node())
+ show(*get_node());
+ else
+ clear();
+}
+
+static char* strip(char* n)
+{
+ int l = strlen(n) - 1;
+ while(l >= 0 && n[l] == ' ')
+ n[l--] = 0;
+
+ char* p = n;
+ while(*p && *p == ' ') p++;
+
+ return p;
+}
+
+void edit::submitCB(Widget,XtPointer)
+{
+ bool alias = XmToggleButtonGetState(alias_);
+ bool run = true;
+ char line[4096];
+ node *nd = get_node();
+
+ if(nd) {
+ tmp_file t(tmpnam(0), true);
+ if(xec_SaveText(text_,(char*)t.c_str())) {
+ gui::syserr(t.c_str());
+ return;
+ }
+
+ NameValueVec var;
+ FILE *f = fopen(t.c_str(),"r");
+ if(!f) {
+ gui::syserr(t.c_str());
+ return;
+ }
+
+ const std::string& mv = nd->__node__() ?
+ nd->variable("ECF_MICRO") : nd->variable("SMSMICRO");
+ const char * mic = (mv.size() == 1) ? mv.c_str() : micro;
+ sprintf(kStart, "%s%s", mic, sStart);
+ sprintf(kEnd, "%s%s", mic, sEnd);
+
+ bool isvars = false;
+ while(fgets(line,sizeof(line),f)) {
+ line[strlen(line)-1] = 0;
+
+ if(isvars) {
+ char* p = line;
+ while(*p && *p != '=') p++;
+ if(*p == '=') {
+ *p = 0;
+
+ char n[1024];
+ char v[1024];
+
+ strcpy(n,line);
+ strcpy(v,p+1);
+
+ var.push_back(std::make_pair(strip(n), strip(v)));
+ }
+ }
+
+ if (strcmp(line,kStart) == 0)
+ isvars = true;
+ if(strcmp(line,kEnd) == 0)
+ break;
+ }
+
+ if(var.empty()) {
+ gui::message("No user variables!");
+ // return;
+ }
+
+ get_node()->serv().send(*get_node(),alias,run,var,t.c_str());
+
+ } else
+ clear();
+
+ if (alias != globals::get_resource("send_as_alias", 0))
+ globals::set_resource("send_as_alias", alias);
+
+ submit();
+}
+
+void edit::externalCB(Widget,XtPointer)
+{
+ if(tmp_) XtFree(tmp_);
+ tmp_ = XtNewString(tmpnam(0));
+
+ if(xec_SaveText(text_,tmp_))
+ {
+ gui::syserr(tmp_);
+ return;
+ }
+
+ char cmd[1024];
+ const char* xedit = getenv("XEDITOR");
+ if (xedit)
+ sprintf(cmd,"${XEDITOR:=xterm -e vi} %s",tmp_);
+ else
+ sprintf(cmd,"xterm -e ${EDITOR:=vi} %s",tmp_);
+
+ FILE *f = popen(cmd,"r");
+ if(!f) {
+ gui::syserr(cmd);
+ return;
+ }
+ XtSetSensitive(text_,False);
+ XtSetSensitive(tools_,False);
+ XtSetSensitive(tools2_,False);
+
+ start(f);
+}
+
+void edit::ready(const char* line)
+{
+ gui::error("%s",line);
+}
+
+void edit::done(FILE* f)
+{
+ stop();
+
+ if(pclose(f)) {
+ gui::error("External editor returns error");
+ return;
+ }
+
+ if(xec_LoadText(text_,tmp_,False))
+ gui::syserr(tmp_);
+
+ unlink(tmp_);
+
+ XtSetSensitive(text_,True);
+ XtSetSensitive(tools_,True);
+ XtSetSensitive(tools2_,True);
+}
+
+// static panel_maker<edit> maker(PANEL_EDIT_TASK);
diff --git a/view/src/edit.h b/view/src/edit.h
new file mode 100644
index 0000000..3af1699
--- /dev/null
+++ b/view/src/edit.h
@@ -0,0 +1,76 @@
+#ifndef edit_H
+#define edit_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "uiedit.h"
+
+#ifndef panel_H
+#include "panel.h"
+#endif
+
+#include "input.h"
+#include "text_window.h"
+
+class edit : public panel, public edit_form_c, public input, public text_window {
+public:
+ edit(panel_window&);
+
+ ~edit(); // Change to virtual if base class
+
+ virtual const char* name() const { return "Edit"; }
+ virtual void show(node&);
+ virtual void clear();
+ virtual Boolean enabled(node&);
+ virtual Widget widget() { return edit_form_c::xd_rootwidget(); }
+ virtual Widget tools() { return tools_; }
+ virtual Widget text() { return text_; }
+
+ virtual void create (Widget parent, char *widget_name = NULL);
+
+private:
+
+ edit(const edit&);
+ edit& operator=(const edit&);
+
+ Boolean loading_;
+ Boolean preproc_;
+ char* tmp_;
+
+ char *kStart;
+ char *kEnd ;
+
+ void ready(const char*);
+ void done(FILE*);
+
+ virtual void changed(node&);
+
+ virtual void changedCB(Widget,XtPointer);
+ virtual void preprocCB(Widget,XtPointer);
+ virtual void submitCB(Widget,XtPointer);
+ virtual void externalCB(Widget,XtPointer);
+
+ virtual void searchCB(Widget ,XtPointer )
+ { text_window::open_search();}
+
+ virtual bool can_print() { return true; }
+ virtual bool can_save() { return true; }
+ virtual void print() { text_window::print(); }
+ virtual void save() { text_window::save(); }
+};
+
+inline void destroy(edit**) {}
+#endif
diff --git a/view/src/edit_label.cc b/view/src/edit_label.cc
new file mode 100644
index 0000000..28c7e73
--- /dev/null
+++ b/view/src/edit_label.cc
@@ -0,0 +1,86 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "edit_label.h"
+#include "label_node.h"
+#include "host.h"
+#include <Xm/Text.h>
+extern "C" {
+#include "xec.h"
+}
+
+edit_label::edit_label(panel_window& w):
+ panel(w),
+ loading_(false)
+{
+}
+
+edit_label::~edit_label()
+{
+}
+
+void edit_label::clear()
+{
+ loading_ = true;
+ XmTextSetString(value_,"");
+ XmTextSetString(default_,"");
+ loading_ = false;
+}
+
+void edit_label::show(node& n)
+{
+
+ label_node& m = (label_node&)n;
+
+ loading_ = true;
+ XmTextSetString(value_,(char*)m.value());
+ XmTextSetString(default_,(char*)m.def());
+
+ loading_ = false;
+}
+
+Boolean edit_label::enabled(node& n)
+{
+ return n.type() == NODE_LABEL;
+}
+
+void edit_label::applyCB(Widget,XtPointer)
+{
+ // alter -m node value
+ if(get_node())
+ {
+ char *p = XmTextGetString(value_);
+ if (get_node()->__node__()) /* ecflow */
+ get_node()->serv().command(clientName,"--alter", "change", "label",
+ get_node()->name().c_str(), p,
+ get_node()->parent_name().c_str(),
+ NULL);
+ else
+ get_node()->serv().command("alter", "-l",
+ get_node()->full_name().c_str(), p, NULL);
+ XtFree(p);
+ }
+ else clear();
+
+ submit();
+}
+
+void edit_label::changedCB(Widget,XtPointer)
+{
+ if(loading_) return;
+ freeze();
+}
+
+// static panel_maker<edit_label> maker(PANEL_EDIT_LABEL);
diff --git a/view/src/edit_label.h b/view/src/edit_label.h
new file mode 100644
index 0000000..90eb7d6
--- /dev/null
+++ b/view/src/edit_label.h
@@ -0,0 +1,137 @@
+#ifndef edit_label_H
+#define edit_label_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+// Headers
+// #ifndef machine_H
+// #include <machine.h>
+// #endif
+
+// Forward declarations
+
+// class ostream;
+// typedef class _Pvts os_typespec; // Remove if not persistant
+
+
+#include "uiedit_label.h"
+
+#ifndef panel_H
+#include "panel.h"
+#endif
+
+//
+
+class edit_label : public panel, public edit_label_form_c {
+public:
+
+// -- Exceptions
+ // None
+
+// -- Contructors
+
+ edit_label(panel_window&);
+
+// -- Destructor
+
+ ~edit_label(); // Change to virtual if base class
+
+// -- Convertors
+ // None
+
+// -- Operators
+ // None
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+
+ virtual const char* name() const { return "Edit"; }
+ virtual void show(node&);
+ virtual Boolean enabled(node&);
+ virtual void clear();
+ virtual Widget widget() { return xd_rootwidget(); }
+ virtual Widget tools() { return tools_; }
+
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+ // Uncomment for persistent, remove otherwise
+ // static os_typespec* get_os_typespec();
+
+protected:
+
+// -- Members
+ // None
+
+// -- Methods
+
+ // void print(ostream&) const; // Change to virtual if base class
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+private:
+
+// No copy allowed
+
+ edit_label(const edit_label&);
+ edit_label& operator=(const edit_label&);
+
+// -- Members
+ bool loading_;
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+
+ virtual void applyCB(Widget,XtPointer);
+ virtual void changedCB(Widget,XtPointer);
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+// -- Friends
+
+ //friend ostream& operator<<(ostream& s,const edit_label& p)
+ // { p.print(s); return s; }
+
+};
+
+inline void destroy(edit_label**) {}
+
+// If persistent, uncomment, otherwise remove
+//#ifdef _ODI_OSSG_
+//OS_MARK_SCHEMA_TYPE(edit_label);
+//#endif
+
+
+#endif
diff --git a/view/src/edit_limit.cc b/view/src/edit_limit.cc
new file mode 100644
index 0000000..c2def92
--- /dev/null
+++ b/view/src/edit_limit.cc
@@ -0,0 +1,146 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "edit_limit.h"
+#include "limit_node.h"
+#include "host.h"
+#include <Xm/Text.h>
+#include <Xm/List.h>
+extern "C" {
+#include "xec.h"
+}
+
+edit_limit::edit_limit(panel_window& w):
+ panel(w),
+ loading_(false),
+ name_(0)
+{
+}
+
+edit_limit::~edit_limit()
+{
+ if(name_) XtFree(name_);
+}
+
+void edit_limit::clear()
+{
+ loading_ = true;
+ XmTextSetString(max_,(char*)"");
+ XmListDeleteAllItems(list_);
+ XtSetSensitive(remove_,False);
+ forget_all();
+ loading_ = false;
+ if(name_) XtFree(name_);
+ name_ = 0;
+}
+
+void edit_limit::show(node& n)
+{
+ clear();
+
+ limit_node& m = (limit_node&)n;
+
+ char buf[80];
+ loading_ = true;
+
+ sprintf(buf,"%d",m.maximum()); XmTextSetString(max_,buf);
+
+ m.nodes(*this);
+
+ loading_ = false;
+}
+
+Boolean edit_limit::enabled(node& n)
+{
+ return n.type() == NODE_LIMIT;
+}
+
+void edit_limit::applyCB(Widget,XtPointer)
+{
+ // alter -m node value
+ if(get_node()) {
+ char *p = XmTextGetString(max_);
+ if (1) {
+ if (get_node()->__node__()) /* ecflow */
+ get_node()->serv().command(clientName,"--alter", "change","limit_max",
+ get_node()->name().c_str(),p,
+ get_node()->parent_name().c_str(),
+ NULL);
+ else
+ get_node()->serv().command("alter", "-M",
+ get_node()->full_name().c_str(), p, NULL);
+ } else {
+ std::string cmd;
+ if (get_node()->__node__()) { /* ecflow */
+ cmd = clientName; cmd+= "--alter change limit_max <node_name> ";
+ cmd += p; cmd += " <parent_name>";
+ } else {
+ cmd = "alter -M <full_name> "; cmd += p;
+ }
+ get_node()->command(cmd.c_str());
+ }
+ XtFree(p);
+ } else {
+ clear();
+ }
+ submit();
+}
+
+void edit_limit::changedCB(Widget,XtPointer)
+{
+ if(loading_) return;
+ freeze();
+}
+
+void edit_limit::browseCB(Widget,XtPointer data)
+{
+ XmListCallbackStruct *cb = (XmListCallbackStruct *) data;
+ char *p = xec_GetString(cb->item);
+ if(name_) XtFree(name_);
+ name_ = p;
+ XtSetSensitive(remove_,True);
+}
+
+void edit_limit::removeCB(Widget,XtPointer data)
+{
+ if(get_node()) {
+ if(name_) {
+ if (get_node()->__node__()) /* ecflow */
+ get_node()->serv().command(clientName,"--alter", "delete","limit_path",
+ get_node()->name().c_str(), // limit name
+ name_,
+ get_node()->parent_name().c_str(),
+ NULL); // task node name
+ else
+ get_node()->serv().command("alter", "-N",
+ get_node()->full_name().c_str(),
+ name_,
+ NULL);
+ }
+ } else {
+ clear();
+ }
+}
+
+void edit_limit::next(node& n)
+{
+ observe(&n);
+ xec_AddListItem(list_,(char*)n.full_name().c_str());
+}
+
+void edit_limit::next(const std::string n)
+{
+ xec_AddListItem(list_,(char*)n.c_str());
+}
diff --git a/view/src/edit_limit.h b/view/src/edit_limit.h
new file mode 100644
index 0000000..9b2fc17
--- /dev/null
+++ b/view/src/edit_limit.h
@@ -0,0 +1,60 @@
+#ifndef edit_limit_H
+#define edit_limit_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "uiedit_limit.h"
+
+#ifndef panel_H
+#include "panel.h"
+#endif
+
+#ifndef node_lister_H
+#include "node_lister.h"
+#endif
+
+class edit_limit : public panel, public edit_limit_form_c, public node_lister {
+public:
+
+ edit_limit(panel_window&);
+
+ ~edit_limit(); // Change to virtual if base class
+
+ virtual const char* name() const { return "Edit"; }
+ virtual void show(node&);
+ virtual Boolean enabled(node&);
+ virtual void clear();
+ virtual Widget widget() { return xd_rootwidget(); }
+ virtual Widget tools() { return tools_; }
+private:
+
+ edit_limit(const edit_limit&);
+ edit_limit& operator=(const edit_limit&);
+
+ bool loading_;
+ char* name_;
+
+ virtual void applyCB(Widget,XtPointer);
+ virtual void changedCB(Widget,XtPointer);
+ virtual void removeCB(Widget,XtPointer);
+ virtual void browseCB(Widget,XtPointer);
+
+ virtual void next(node&);
+ virtual void next(const std::string);
+};
+
+inline void destroy(edit_limit**) {}
+#endif
diff --git a/view/src/edit_meter.cc b/view/src/edit_meter.cc
new file mode 100644
index 0000000..e32845f
--- /dev/null
+++ b/view/src/edit_meter.cc
@@ -0,0 +1,91 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "edit_meter.h"
+#include "meter_node.h"
+#include "host.h"
+#include <Xm/Text.h>
+extern "C" {
+#include "xec.h"
+}
+
+edit_meter::edit_meter(panel_window& w):
+ panel(w),
+ loading_(false)
+{
+}
+
+edit_meter::~edit_meter()
+{
+}
+
+void edit_meter::clear()
+{
+ loading_ = true;
+ XmTextSetString(min_,(char*)"");
+ XmTextSetString(value_,(char*)"");
+ XmTextSetString(max_,(char*)"");
+ XmTextSetString(threshold_,(char*)"");
+ loading_ = false;
+}
+
+void edit_meter::show(node& n)
+{
+ meter_node& m = (meter_node&)n;
+
+ char buf[80];
+ loading_ = true;
+
+ sprintf(buf,"%d",m.minimum()); XmTextSetString(min_,buf);
+ sprintf(buf,"%d",m.value()); XmTextSetString(value_,buf);
+ sprintf(buf,"%d",m.maximum()); XmTextSetString(max_,buf);
+ sprintf(buf,"%d",m.threshold()); XmTextSetString(threshold_,buf);
+
+ loading_ = false;
+}
+
+Boolean edit_meter::enabled(node& n)
+{
+ return n.type() == NODE_METER;
+}
+
+void edit_meter::applyCB(Widget,XtPointer)
+{
+ // alter -m node value
+ if(get_node())
+ {
+ char *p = XmTextGetString(value_);
+ if (get_node()->__node__()) /* ecflow */
+ get_node()->serv().command(clientName, "--alter", "change", "meter",
+ get_node()->name().c_str(), p,
+ get_node()->parent_name().c_str(),
+ NULL);
+ else
+ get_node()->serv().command("alter", "-m",
+ get_node()->full_name().c_str(), p, NULL);
+ XtFree(p);
+ }
+ else clear();
+
+ submit();
+}
+
+void edit_meter::changedCB(Widget,XtPointer)
+{
+ if(loading_) return;
+ freeze();
+}
+
+// static panel_maker<edit_meter> maker(PANEL_EDIT_METER);
diff --git a/view/src/edit_meter.h b/view/src/edit_meter.h
new file mode 100644
index 0000000..9c32685
--- /dev/null
+++ b/view/src/edit_meter.h
@@ -0,0 +1,137 @@
+#ifndef edit_meter_H
+#define edit_meter_H
+
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+// Headers
+// #ifndef machine_H
+// #include <machine.h>
+// #endif
+
+// Forward declarations
+
+// class ostream;
+// typedef class _Pvts os_typespec; // Remove if not persistant
+
+
+#include "uiedit_meter.h"
+
+#ifndef panel_H
+#include "panel.h"
+#endif
+
+//
+
+class edit_meter : public panel, public edit_meter_form_c {
+public:
+
+// -- Exceptions
+ // None
+
+// -- Contructors
+
+ edit_meter(panel_window&);
+
+// -- Destructor
+
+ ~edit_meter(); // Change to virtual if base class
+
+// -- Convertors
+ // None
+
+// -- Operators
+ // None
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+
+ virtual const char* name() const { return "Edit"; }
+ virtual void show(node&);
+ virtual Boolean enabled(node&);
+ virtual void clear();
+ virtual Widget widget() { return xd_rootwidget(); }
+ virtual Widget tools() { return tools_; }
+
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+ // Uncomment for persistent, remove otherwise
+ // static os_typespec* get_os_typespec();
+
+protected:
+
+// -- Members
+ // None
+
+// -- Methods
+
+ // void print(ostream&) const; // Change to virtual if base class
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+private:
+
+// No copy allowed
+
+ edit_meter(const edit_meter&);
+ edit_meter& operator=(const edit_meter&);
+
+// -- Members
+ bool loading_;
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+
+ virtual void applyCB(Widget,XtPointer);
+ virtual void changedCB(Widget,XtPointer);
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+// -- Friends
+
+ //friend ostream& operator<<(ostream& s,const edit_meter& p)
+ // { p.print(s); return s; }
+
+};
+
+inline void destroy(edit_meter**) {}
+
+// If persistent, uncomment, otherwise remove
+//#ifdef _ODI_OSSG_
+//OS_MARK_SCHEMA_TYPE(edit_meter);
+//#endif
+
+
+#endif
diff --git a/view/src/edit_repeat.cc b/view/src/edit_repeat.cc
new file mode 100644
index 0000000..8e465c0
--- /dev/null
+++ b/view/src/edit_repeat.cc
@@ -0,0 +1,140 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #11 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "edit_repeat.h"
+#include "repeat_node.h"
+#include "host.h"
+#include "ecflowview.h"
+#include <Xm/List.h>
+#include <Xm/Text.h>
+extern "C" {
+#include "xec.h"
+}
+
+edit_repeat::edit_repeat(panel_window& w):
+ panel(w),
+ loading_(false),
+ index_(-1),
+ indexs_("")
+{
+}
+
+edit_repeat::~edit_repeat()
+{
+}
+
+void edit_repeat::clear()
+{
+ loading_ = true;
+ XmListDeleteAllItems(list_);
+ index_ = -1;
+ indexs_ = "";
+ loading_ = false;
+}
+
+void edit_repeat::show(node& n)
+{
+ repeat_node& m = (repeat_node&)n;
+
+ loading_ = true;
+
+ str80 buf;
+ int end = m.last();
+ int cur = m.current();
+ int inc = m.step();
+ XmListDeleteAllItems(list_);
+
+ if(end > 50 && m.can_use_text())
+ {
+ use_text_ = true;
+ char buf[1024];
+ char buf1[1024];
+ char buf2[1024];
+ m.value(buf1,0);
+ m.value(buf2,end-1);
+ sprintf(buf,"Enter a value between %s and %s (step %d):",buf1,buf2,inc);
+ xec_SetLabel(label_,buf);
+ XtUnmanageChild(show_list_);
+ XtManageChild(show_text_);
+ m.value(buf,cur);
+ XmTextSetString(text_,buf);
+ }
+ else
+ {
+ use_text_ = false;
+ XtManageChild(show_list_);
+ XtUnmanageChild(show_text_);
+
+ for(int i=0 ; i < end ; i++)
+ {
+ m.value(buf,i);
+ xec_AddListItem(list_,buf);
+ }
+
+ XmListSelectPos(list_,cur+1,True);
+ }
+
+ loading_ = false;
+}
+
+Boolean edit_repeat::enabled(node& n)
+{
+ int i = n.type();
+ return i == NODE_REPEAT ||
+ i == NODE_REPEAT_E ||
+ i == NODE_REPEAT_S ||
+ i == NODE_REPEAT_D ||
+ i == NODE_REPEAT_I;
+}
+
+void edit_repeat::applyCB(Widget,XtPointer)
+{
+ if(get_node()) {
+ char *p = 0x0;
+ if(use_text_) {
+ p = XmTextGetString(text_);
+ }
+
+ if (get_node()->__node__()) /* ecflow */
+ get_node()->serv().command(clientName, "--alter", "change", "repeat",
+ p ? p : indexs_.c_str(),
+ get_node()->parent_name().c_str(),
+ NULL);
+ else
+ get_node()->serv().command("alter", "-R",
+ get_node()->full_name().c_str(), p, NULL);
+
+ if (p) XtFree(p);
+
+ } else {
+ clear();
+ }
+ submit();
+}
+
+void edit_repeat::browseCB(Widget,XtPointer data)
+{
+ XmListCallbackStruct *cb = (XmListCallbackStruct *) data;
+ char *p = xec_GetString(cb->item);
+ if(get_node())
+ indexs_ = p;
+ else
+ indexs_ = "";
+ XtFree(p);
+
+ if(loading_) return;
+ freeze();
+}
+
diff --git a/view/src/edit_repeat.h b/view/src/edit_repeat.h
new file mode 100644
index 0000000..f133ce2
--- /dev/null
+++ b/view/src/edit_repeat.h
@@ -0,0 +1,51 @@
+#ifndef edit_repeat_H
+#define edit_repeat_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "uiedit_repeat.h"
+
+#ifndef panel_H
+#include "panel.h"
+#endif
+
+class edit_repeat : public panel, public edit_repeat_form_c {
+public:
+ edit_repeat(panel_window&);
+
+ ~edit_repeat(); // Change to virtual if base class
+ virtual const char* name() const { return "Edit"; }
+ virtual void show(node&);
+ virtual Boolean enabled(node&);
+ virtual void clear();
+ virtual Widget widget() { return xd_rootwidget(); }
+ virtual Widget tools() { return tools_; }
+
+private:
+
+ edit_repeat(const edit_repeat&);
+ edit_repeat& operator=(const edit_repeat&);
+
+ bool loading_;
+ int index_; std::string indexs_;
+ bool use_text_;
+
+ virtual void applyCB(Widget,XtPointer);
+ virtual void browseCB(Widget,XtPointer);
+};
+
+inline void destroy(edit_repeat**) {}
+#endif
diff --git a/view/src/edit_variable.cc b/view/src/edit_variable.cc
new file mode 100644
index 0000000..703907a
--- /dev/null
+++ b/view/src/edit_variable.cc
@@ -0,0 +1,70 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "edit_variable.h"
+#include "host.h"
+#include "node.h"
+#include <Xm/Text.h>
+#include <Xm/List.h>
+extern "C" {
+#include "xec.h"
+}
+
+edit_variable::edit_variable(panel_window& w):
+ panel(w),
+ loading_(false)
+{
+}
+
+edit_variable::~edit_variable()
+{
+}
+
+void edit_variable::clear()
+{
+ loading_ = true;
+ xec_SetLabel(name_,"<no name>");
+ XmTextSetString(value_,"");
+ loading_ = false;
+}
+
+void edit_variable::show(node& n)
+{
+ clear();
+ n.edit(*this);
+ loading_ = false;
+}
+
+Boolean edit_variable::enabled(node& n)
+{
+ return n.type() == NODE_VARIABLE;
+}
+
+void edit_variable::applyCB(Widget,XtPointer)
+{
+ if(get_node())
+ get_node()->apply(*this);
+ else
+ clear();
+ submit();
+}
+
+void edit_variable::changedCB(Widget,XtPointer)
+{
+ if(loading_) return;
+ freeze();
+}
+
+// static panel_maker<edit_variable> maker(PANEL_EDIT_VARIABLE);
diff --git a/view/src/edit_variable.h b/view/src/edit_variable.h
new file mode 100644
index 0000000..e8ea86f
--- /dev/null
+++ b/view/src/edit_variable.h
@@ -0,0 +1,58 @@
+#ifndef edit_variable_H
+#define edit_variable_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "uiedit_variable.h"
+
+#ifndef panel_H
+#include "panel.h"
+#endif
+
+#ifndef node_editor_H
+#include "node_editor.h"
+#endif
+
+class edit_variable : public panel, public edit_variable_form_c,
+ public node_editor {
+public:
+
+ edit_variable(panel_window&);
+
+ ~edit_variable(); // Change to virtual if base class
+
+ virtual const char* name() const { return "Edit"; }
+ virtual void show(node&);
+ virtual Boolean enabled(node&);
+ virtual void clear();
+ virtual Widget widget() { return xd_rootwidget(); }
+ virtual Widget form() { return xd_rootwidget(); }
+ virtual Widget tools() { return tools_; }
+
+private:
+
+ edit_variable(const edit_variable&);
+ edit_variable& operator=(const edit_variable&);
+
+ bool loading_;
+
+ virtual void applyCB(Widget,XtPointer);
+ virtual void changedCB(Widget,XtPointer);
+
+};
+
+inline void destroy(edit_variable**) {}
+#endif
diff --git a/view/src/editor.cc b/view/src/editor.cc
new file mode 100644
index 0000000..e1dc765
--- /dev/null
+++ b/view/src/editor.cc
@@ -0,0 +1,47 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#ifndef editor_H
+#include "editor.h"
+#endif
+
+
+Widget editor::find(const char* name)
+{
+ Widget w = find(name,form());
+ return w;
+}
+
+Widget editor::find(const char* name,Widget p)
+{
+ Widget w = XtNameToWidget(p,name);
+ if(w) return w;
+
+ WidgetList wl = 0;
+ int count = 0;
+
+ XtVaGetValues(p,
+ XmNchildren,&wl,
+ XtNnumChildren,&count,
+ NULL);
+
+ for(int i=0; i<count; i++)
+ {
+ w = find(name,wl[i]);
+ if(w) return w;
+ }
+
+ return 0;
+}
diff --git a/view/src/editor.h b/view/src/editor.h
new file mode 100644
index 0000000..4d2e6ac
--- /dev/null
+++ b/view/src/editor.h
@@ -0,0 +1,108 @@
+#ifndef editor_H
+#define editor_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+// Headers
+// #ifndef machine_H
+// #include <machine.h>
+// #endif
+
+// Forward declarations
+
+// class ostream;
+// typedef class _Pvts os_typespec; // Remove if not persistant
+
+//
+
+#include <Xm/Xm.h>
+
+
+class editor {
+public:
+
+// -- Methods
+
+ virtual Widget form() = 0;
+
+// -- Overridden methods
+
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+ // Uncomment for persistent, remove otherwise
+ // static os_typespec* get_os_typespec();
+
+protected:
+
+// -- Members
+ // None
+
+// -- Methods
+
+ Widget find(const char*,Widget);
+ Widget find(const char* n);
+
+ // void print(ostream&) const; // Change to virtual if base class
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+private:
+
+// No copy allowed
+
+
+// -- Members
+ // None
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+// -- Friends
+
+ //friend ostream& operator<<(ostream& s,const editor& p)
+ // { p.print(s); return s; }
+
+};
+
+inline void destroy(editor**) {}
+
+// If persistent, uncomment, otherwise remove
+//#ifdef _ODI_OSSG_
+//OS_MARK_SCHEMA_TYPE(editor);
+//#endif
+
+#endif
diff --git a/view/src/error.cc b/view/src/error.cc
new file mode 100644
index 0000000..e7274f8
--- /dev/null
+++ b/view/src/error.cc
@@ -0,0 +1,38 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdarg.h>
+#include "error.h"
+#include "gui.h"
+#include "ecflowview.h"
+
+
+error::error()
+{
+ create(gui::top());
+}
+
+
+error::~error()
+{
+}
+
+
+void error::show(const char* msg)
+{
+ instance().modal(msg,True);
+}
diff --git a/view/src/error.h b/view/src/error.h
new file mode 100644
index 0000000..625f5a9
--- /dev/null
+++ b/view/src/error.h
@@ -0,0 +1,106 @@
+#ifndef error_H
+#define error_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "uierror.h"
+#include "dialog.h"
+
+class error : public dialog<error,error_shell_c> {
+public:
+
+// -- Exceptions
+ // None
+
+// -- Contructors
+
+ error();
+
+// -- Destructor
+
+ ~error(); // Change to virtual if base class
+
+// -- Convertors
+ // None
+
+// -- Operators
+ // None
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+
+ static void show(const char*);
+
+protected:
+
+// -- Members
+ // None
+
+// -- Methods
+
+ // void print(ostream&) const; // Change to virtual if base class
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+private:
+
+// No copy allowed
+
+ error(const error&);
+ error& operator=(const error&);
+
+// -- Methods
+
+
+// -- Overridden methods
+
+
+// -- Class members
+
+
+// -- Class methods
+ // None
+
+// -- Friends
+
+ //friend ostream& operator<<(ostream& s,const error& p)
+ // { p.print(s); return s; }
+
+};
+
+inline void destroy(error**) {}
+
+// If persistent, uncomment, otherwise remove
+//#ifdef _ODI_OSSG_
+//OS_MARK_SCHEMA_TYPE(error);
+//#endif
+
+#endif
diff --git a/view/src/eval.h b/view/src/eval.h
new file mode 100644
index 0000000..6d89459
--- /dev/null
+++ b/view/src/eval.h
@@ -0,0 +1,49 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+ virtual Boolean is_MENU() { return 0;}
+ virtual Boolean is_IDENT() { return 0;}
+ virtual Boolean is_NONE() { return 0;}
+ virtual Boolean is_ALL() { return 1;}
+ virtual Boolean is_UNKNOWN() { return 0;}
+ virtual Boolean is_SUSPENDED() { return 0;}
+ virtual Boolean is_COMPLETE() { return 0;}
+ virtual Boolean is_QUEUED() { return 0;}
+ virtual Boolean is_SUBMITTED() { return 0;}
+ virtual Boolean is_ACTIVE() { return 0;}
+ virtual Boolean is_ABORTED() { return 0;}
+ virtual Boolean is_CLEAR() { return 0;}
+ virtual Boolean is_SET() { return 0;}
+ virtual Boolean is_SHUTDOWN() { return 0;}
+ virtual Boolean is_HALTED() { return 0;}
+ virtual Boolean is_ECF() { return 0;}
+ virtual Boolean is_SUITE() { return 0;}
+ virtual Boolean is_FAMILY() { return 0;}
+ virtual Boolean is_TASK() { return 0;}
+ virtual Boolean is_EVENT() { return 0;}
+ virtual Boolean is_LABEL() { return 0;}
+ virtual Boolean is_METER() { return 0;}
+ virtual Boolean is_REPEAT() { return 0;}
+ virtual Boolean is_VARIABLE() { return 0;}
+ virtual Boolean is_TRIGGER() { return 0;}
+ virtual Boolean is_HAS_TRIGGERS() { return 0;}
+ virtual Boolean is_HAS_TIME() { return 0;}
+ virtual Boolean is_HAS_DATE() { return 0;}
+ virtual Boolean is_SEPARATOR() { return 0;}
+ virtual Boolean is_STRING() { return 0;}
+ virtual Boolean is_DEFAULT_YES() { return 0;}
+ virtual Boolean is_DEFAULT_NO() { return 0;}
+ virtual Boolean is_EDIT() { return 0;}
+ virtual Boolean is_OUTPUT() { return 0;}
diff --git a/view/src/event_node.cc b/view/src/event_node.cc
new file mode 100644
index 0000000..3684f05
--- /dev/null
+++ b/view/src/event_node.cc
@@ -0,0 +1,75 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "event_node.h"
+
+#ifndef ecf_node_
+#include "ecf_node.h"
+#endif
+
+event_node::event_node(host& h,ecf_node* n) : node(h,n) {}
+
+const char* event_node::status_name() const
+{
+ char *event_name[] = { (char*) "clear", (char*) "set", NULL };
+ return event_name[owner_->status()];
+}
+
+void event_node::drawNode(Widget w,XRectangle* r,bool tree)
+{
+ drawBackground(w,r,tree);
+
+ XmString s = tree ? labelTree() : labelTrigger();
+ XRectangle x = *r;
+
+ x.x += (x.height - 10)/2;
+ x.width = x.height = 10;
+
+ XFillRectangles
+ (XtDisplay(w),XtWindow(w),
+ // status() ? blueGC() : colorGC(0), &x,1);
+ status() ? gui::colorGC(STATUS_MAX+2) : colorGC(0), &x,1);
+
+ shadow(w,&x);
+
+ XmStringDraw(XtDisplay(w),XtWindow(w),
+ smallfont(),
+ s,
+ blackGC(),
+ r->x + x.width + 4,
+ r->y,
+ r->width - x.width - 4,
+ XmALIGNMENT_CENTER, XmSTRING_DIRECTION_L_TO_R,
+ NULL);
+}
+
+void event_node::sizeNode(Widget w,XRectangle* r,bool tree)
+{
+ XmString s = tree ? labelTree() : labelTrigger();
+ r->height = XmStringHeight(smallfont(),s);
+ r->width = XmStringWidth(smallfont(),s) + 14 ;
+ if(r->height<10) r->height = 10;
+}
+
+bool event_node::evaluate() const
+{
+ return status() != 0;
+}
+
+void event_node::perlify(FILE* f)
+{
+ perl_member(f,"status",owner_->status());
+}
+
diff --git a/view/src/event_node.h b/view/src/event_node.h
new file mode 100644
index 0000000..f7db7b7
--- /dev/null
+++ b/view/src/event_node.h
@@ -0,0 +1,42 @@
+#ifndef EVENT_NODE_H
+#define EVENT_NODE_H
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #10 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "node.h"
+#include "show.h"
+
+class event_node : public node {
+
+ virtual void info(std::ostream&){}
+ virtual bool evaluate() const;
+
+ virtual void drawNode(Widget w,XRectangle* r,bool);
+ virtual void sizeNode(Widget w,XRectangle* r,bool);
+
+ virtual Boolean visible() const { return show::want(show::event); }
+
+ const char* status_name() const;
+
+ virtual void perlify(FILE*);
+
+public:
+ event_node(host& h,ecf_node* n);
+#ifdef BRIDGE
+ event_node(host& h,sms_node* n,char b) : node(h,n,b) {}
+#endif
+};
+
+#endif
diff --git a/view/src/events.h b/view/src/events.h
new file mode 100644
index 0000000..e722840
--- /dev/null
+++ b/view/src/events.h
@@ -0,0 +1,132 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#ifndef events_H
+#define events_H
+
+// Headers
+// #ifndef machine_H
+// #include <machine.h>
+// #endif
+
+// Forward declarations
+
+// class ostream;
+// typedef class _Pvts os_typespec; // Remove if not persistant
+
+//
+
+#ifndef array_H
+#include "array.h"
+#endif
+
+
+class events {
+public:
+
+// -- Exceptions
+ // None
+
+// -- Contructors
+
+ events() {}
+
+// -- Destructor
+
+ ~events() {}
+
+// -- Convertors
+ // None
+
+// -- Operators
+ // None
+
+// -- Methods
+
+ int count() { return time_.count(); }
+ int time(int i) { return time_[i]; }
+ int status(int i) { return status_[i]; }
+
+ void add(int t,int s) { time_.add(t); status_.add(s); }
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+ // Uncomment for persistent, remove otherwise
+ // static os_typespec* get_os_typespec();
+
+protected:
+
+// -- Members
+ // None
+
+// -- Methods
+
+ // void print(ostream&) const; // Change to virtual if base class
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+private:
+
+// No copy allowed
+
+ events(const events&);
+ events& operator=(const events&);
+
+// -- Members
+
+ array<int> time_;
+ array<int> status_;
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+// -- Friends
+
+ //friend ostream& operator<<(ostream& s,const events& p)
+ // { p.print(s); return s; }
+
+};
+
+inline void destroy(events**) {}
+
+// If persistent, uncomment, otherwise remove
+//#ifdef _ODI_OSSG_
+//OS_MARK_SCHEMA_TYPE(events);
+//#endif
+
+#endif
diff --git a/view/src/extent.h b/view/src/extent.h
new file mode 100644
index 0000000..1c40c47
--- /dev/null
+++ b/view/src/extent.h
@@ -0,0 +1,74 @@
+#ifndef extent_H
+#define extent_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+template<class T>
+class extent {
+public:
+ extent();
+
+ virtual ~extent(); // Change to virtual if base class
+
+ static void delete_all();
+
+ extent<T>* next_;
+ extent<T>* prev_;
+
+ static extent<T>* first_;
+ static extent<T>* last_;
+
+ static T* first() { return (T*)first_; }
+ T* next() { return (T*)next_; }
+};
+
+template<class T> extent<T>* extent<T>::first_ = 0;
+template<class T> extent<T>* extent<T>::last_ = 0;
+
+template<class T>
+extent<T>::extent():
+ next_(0),
+ prev_(last_)
+{
+ if(last_)
+ last_->next_ = this;
+ else
+ first_ = this;
+ last_ = this;
+}
+
+template<class T>
+extent<T>::~extent()
+{
+ if(prev_) prev_->next_ = next_; else first_ = next_;
+ if(next_) next_->prev_ = prev_; else last_ = prev_;
+}
+
+
+template<class T>
+void extent<T>::delete_all()
+{
+ while(first_) delete first_;
+}
+
+// gcc is broken
+#if defined (__GNUC__) || defined (hpux) || defined(mips) || defined(_AIX)
+#define IMP(T)
+#else
+#define IMP(T) extent<T>* extent<T>::first_;extent<T>* extent<T>::last_;
+#endif
+
+#endif
diff --git a/view/src/external.cc b/view/src/external.cc
new file mode 100644
index 0000000..79ec14b
--- /dev/null
+++ b/view/src/external.cc
@@ -0,0 +1,64 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #9 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "external.h"
+#include "host.h"
+#include "ecf_node.h"
+
+static external* head_ = 0;
+
+external::external(const char *name):
+ node(host::dummy(),ecf_node::dummy_node())
+{
+ name_ = name;
+ next_ = head_;
+ head_ = this;
+}
+
+external::~external()
+{
+}
+
+Boolean external::is_external(const char *name)
+{
+ return True;
+}
+
+external& external::get(const char *name)
+{
+ external* e = head_;
+ while(e) {
+ if(strcmp(name,e->name().c_str()) == 0)
+ return *e;
+ e = (external*)e->next_;
+ }
+ return *(new external(name));
+}
+
+void external::info(std::ostream&)
+{
+}
+
+void external::perlify(FILE* f)
+{
+}
+
+template<>
+void ecf_concrete_node<external>::set_graphic_ptr(node* n)
+{}
+
+template<>
+void ecf_concrete_node<external>::make_subtree() {}
+
diff --git a/view/src/external.h b/view/src/external.h
new file mode 100644
index 0000000..fdc705c
--- /dev/null
+++ b/view/src/external.h
@@ -0,0 +1,53 @@
+#ifndef external_H
+#define external_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #8 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "node.h"
+
+class external : public node {
+ std::string name_;
+public:
+ external(const char*);
+ ~external(); // Change to virtual if base class
+
+ virtual Boolean menus() { return False; }
+ virtual Boolean selectable() { return False; }
+ virtual const std::string& full_name() const { return name(); }
+ virtual void info(std::ostream&);
+
+ virtual const char* type_name() const { return "external"; }
+ virtual const char* status_name() const { return "unknown"; }
+ virtual const std::string& name() const { return name_; }
+ virtual const std::string toString() const { return name(); }
+
+ static Boolean is_external(const std::string& path) { return is_external(path.c_str()); }
+ static Boolean is_external(const char*);
+ virtual std::ostream& print(std::ostream&s) const { return s << "extern_node\n";};
+
+ static external& get(const std::string& path) { return get(path.c_str()); }
+ static external& get(const char*);
+
+private:
+
+ external(const external&);
+ external& operator=(const external&);
+
+ virtual void perlify(FILE*);
+};
+
+inline void destroy(external**) {}
+#endif
diff --git a/view/src/find.cc b/view/src/find.cc
new file mode 100644
index 0000000..9f70aa5
--- /dev/null
+++ b/view/src/find.cc
@@ -0,0 +1,173 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <stdarg.h>
+#include "find.h"
+#include "host.h"
+#include "runnable.h"
+#include <Xm/List.h>
+#include <Xm/Text.h>
+#include <Xm/ToggleB.h>
+#include <Xm/PushB.h>
+#include "gui.h"
+#include "extent.h"
+#include "flags.h"
+#include "pixmap.h"
+#include "result.h"
+#include <X11/IntrinsicP.h>
+#include <stdarg.h>
+
+extern "C" {
+#include "xec.h"
+}
+
+struct quick_find : public extent<quick_find> {
+
+ str text_;
+ str title_;
+ bool regexp_;
+ bool case_;
+
+ quick_find(const str& title,const str& text,bool regexp,bool cas):
+ text_(text),
+ title_(title), regexp_(regexp),case_(cas) {}
+
+ static void init(Widget);
+};
+
+void quick_find::init(Widget m)
+{
+ quick_find* f = quick_find::first();
+ while(f)
+ {
+ Widget w = XmCreatePushButton(m,(char*)f->title_.c_str(),0,0);
+ xec_SetUserData(w,f);
+ XtManageChild(w);
+ f = f->next();
+ }
+}
+
+static quick_find qf1("An ECF variable","%[^%]+%",true,false);
+static quick_find qf2("A shell variable",
+ "(\\$\\{[_a-z0-9]+\\})|(\\$[_a-z0-9]+)",true,false);
+static quick_find qf3("A MARS error","^mars - (ERROR|FATAL)",true,true);
+
+static quick_find qf4("ecflow_client","ecflow_client",false,true);
+static quick_find qf5(" --abort"," --abort",false,true);
+static quick_find qf6(" --complete"," --complete",false,true);
+static quick_find qf7(" --init"," --init",false,true);
+static quick_find qf8("smsabort","smsabort",false,true);
+
+find::find():
+ pending_(0)
+{
+ _xd_rootwidget = 0;
+}
+
+find::~find()
+{
+ if(_xd_rootwidget)
+ XtDestroyWidget(_xd_rootwidget);
+ delete pending_;
+}
+
+void find::closeCB(Widget,XtPointer)
+{
+ hide();
+}
+
+void find::hide()
+{
+ if(_xd_rootwidget) {
+ no_message();
+ XtUnmanageChild(form_);
+ }
+}
+
+void find::findCB(Widget,XtPointer)
+{
+ char* p = XmTextGetString(find_text_);
+ search(p,XmToggleButtonGetState(case_),
+ XmToggleButtonGetState(regexp_),
+ XmToggleButtonGetState(back_),
+ XmToggleButtonGetState(wrap_));
+ XtFree(p);
+}
+
+void find::make(Widget top)
+{
+ while(!XtIsShell(top))
+ top = XtParent(top);
+
+ if(!_xd_rootwidget)
+ {
+ find_shell_c::create(top);
+ pixmap::find("QuickFind").set_label(quick_find_);
+ quick_find::init(quick_menu_);
+ }
+
+}
+
+void find::raise(Widget top)
+{
+ make(top);
+ XtManageChild(form_);
+ XMapRaised(XtDisplay(_xd_rootwidget),XtWindow(_xd_rootwidget));
+}
+
+void find::message(const char* fmt,...)
+{
+ if(!_xd_rootwidget)
+ return;
+
+ char buf[1024];
+ va_list args;
+ va_start(args,fmt);
+ vsprintf(buf,fmt,args);
+ xec_SetLabel(message_,buf);
+ va_end(args);
+
+ XtManageChild(message_);
+}
+
+void find::no_message()
+{
+ if(_xd_rootwidget)
+ XtUnmanageChild(message_);
+}
+
+void find::regexCB(Widget,XtPointer data)
+{
+ XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct*) data;
+ if(cb->set)
+ XmToggleButtonSetState(back_,False,False);
+ else
+ XmToggleButtonSetState(case_,True,False);
+
+ XtSetSensitive(back_,!cb->set);
+ XtSetSensitive(case_, cb->set);
+}
+
+void find::entryCB(Widget,XtPointer data)
+{
+ XmRowColumnCallbackStruct *cb = (XmRowColumnCallbackStruct *) data;
+ quick_find *w = (quick_find*) xec_GetUserData (cb->widget);
+ XmTextSetString(find_text_,(char*)w->text_.c_str());
+ XmToggleButtonSetState(regexp_, w->regexp_,True);
+ if(w->regexp_)
+ XmToggleButtonSetState(case_, w->case_ ,True);
+
+}
+IMP(quick_find)
diff --git a/view/src/find.h b/view/src/find.h
new file mode 100644
index 0000000..e39bf39
--- /dev/null
+++ b/view/src/find.h
@@ -0,0 +1,58 @@
+#ifndef find_H
+#define find_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#ifdef NO_BOOL
+#include "bool.h"
+#endif
+
+class host;
+
+#include "uifind.h"
+
+class runnable;
+
+class find : public find_shell_c {
+public:
+ find();
+
+ ~find(); // Change to virtual if base class
+
+ void make(Widget);
+ void raise(Widget);
+ void hide();
+ void message(const char*,...);
+ void no_message();
+ virtual void search(const char*,bool,bool,bool,bool) = 0;
+
+ void pending(runnable* r) { pending_ = r; }
+
+private:
+
+ find(const find&);
+ find& operator=(const find&);
+
+ runnable* pending_;
+
+ void closeCB(Widget,XtPointer);
+ void findCB(Widget,XtPointer);
+ void regexCB(Widget,XtPointer);
+ void entryCB(Widget,XtPointer);
+};
+
+inline void destroy(find**) {}
+#endif
diff --git a/view/src/flags.cc b/view/src/flags.cc
new file mode 100644
index 0000000..9418082
--- /dev/null
+++ b/view/src/flags.cc
@@ -0,0 +1,85 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <strings.h>
+#include "ecflowview.h"
+#include "flags.h"
+#include "globals.h"
+#include "str.h"
+#include "selection.h"
+
+#ifdef linux
+extern "C" char *cuserid(char*);
+#endif
+
+flags::~flags()
+{
+}
+
+Boolean eventFlag::eval(node* n)
+{
+ if (!n) return False;
+ return n->status() == status_;
+}
+
+Boolean statusFlag::eval(node* n)
+{
+ if (!n) return False;
+ XECFDEBUG printf("statusFlag: %d %d %d \n", n->isSimpleNode() ? 1:0,n->status(),status_);
+ return n->isSimpleNode() && (n->status() == status_);
+}
+
+Boolean typeFlag::eval(node* n)
+{
+ if (!n) return False;
+ if (type_ == NODE_REPEAT) {
+ int i = n->type();
+ return i == NODE_REPEAT ||
+ i == NODE_REPEAT_E || i == NODE_REPEAT_I ||
+ i == NODE_REPEAT_S || i == NODE_REPEAT_D;
+ }
+ return n->type() == type_;
+}
+
+Boolean procFlag::eval(node* n)
+{
+ if (!n) return False;
+ return (n->*proc_)();
+}
+
+Boolean userFlag::eval(node* n)
+{
+ /* static char* names[] = {
+ (char*) "CDPUSER",
+ (char*) "CDPOPER",
+ (char*) "CDPADMIN",
+ };
+
+ const char* v = n->variable(names[level_]).c_str();
+ if(v) {
+ static str me(cuserid(0));
+ return strcmp(me.c_str(),v) == 0;
+ }
+ */
+ return (globals::user_level() == level_);
+}
+
+Boolean selectionFlag::eval(node* n)
+{
+ return selection::current_node() != 0 && selection::current_node() != n;
+}
diff --git a/view/src/flags.h b/view/src/flags.h
new file mode 100644
index 0000000..8d19890
--- /dev/null
+++ b/view/src/flags.h
@@ -0,0 +1,117 @@
+#ifndef flags_H
+#define flags_H
+
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#ifndef ecflowview_H
+#include "ecflowview.h"
+#endif
+
+#include "node.h"
+
+class flags {
+public:
+ virtual Boolean eval (node *) = 0;
+ virtual ~flags();
+};
+
+
+class flagNot : public flags
+{
+ flags *f_;
+ virtual Boolean eval (node * n) { return !f_->eval (n); }
+public:
+ flagNot (flags * f) : f_ (f) { }
+ ~flagNot() { delete f_; }
+};
+
+class flagOr : public flags {
+ flags *a_;
+ flags *b_;
+ virtual Boolean eval (node * n) { return a_->eval (n) || b_->eval (n); }
+public:
+ flagOr (flags * a, flags * b): a_(a), b_(b) { }
+ ~flagOr() { delete a_; delete b_; }
+};
+
+class flagAnd : public flags {
+ flags *a_;
+ flags *b_;
+ virtual Boolean eval (node * n) { return a_->eval (n) && b_->eval (n); }
+public:
+ flagAnd (flags * a, flags * b): a_(a), b_(b) { }
+ ~flagAnd() { delete a_; delete b_; }
+};
+
+class typeFlag : public flags {
+ int type_;
+public:
+ virtual Boolean eval(node *);
+ typeFlag(int t) : type_(t) {}
+};
+
+class statusFlag : public flags {
+ int status_;
+public:
+ virtual Boolean eval(node *);
+ statusFlag(int t) : status_(t) {}
+};
+
+class eventFlag : public flags {
+ int status_;
+public:
+ virtual Boolean eval(node *);
+ eventFlag(int t) : status_(t) {}
+};
+
+class procFlag : public flags {
+ typedef Boolean (node::*Proc)() const;
+ Proc proc_;
+public:
+ virtual Boolean eval(node *);
+ procFlag(Proc p) : proc_(p) {}
+};
+
+class flagAll : public flags {
+ virtual Boolean eval (node * n) { return True; }
+};
+
+class flagNone : public flags {
+ virtual Boolean eval (node * n) { return False; }
+};
+
+class showFlag : public flags {
+ int show_;
+public:
+ virtual Boolean eval(node *);
+ showFlag(int t) : show_(t) {}
+};
+
+
+class userFlag : public flags {
+ int level_;
+public:
+ virtual Boolean eval(node *);
+ userFlag(int t) : level_(t) {}
+};
+
+class selectionFlag : public flags {
+public:
+ virtual Boolean eval(node *);
+ selectionFlag() {}
+};
+
+#endif
diff --git a/view/src/fonts_prefs.cc b/view/src/fonts_prefs.cc
new file mode 100644
index 0000000..2ee4b04
--- /dev/null
+++ b/view/src/fonts_prefs.cc
@@ -0,0 +1,24 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "fonts_prefs.h"
+
+void fonts_prefs::create(Widget w,char*)
+{
+ fonts_form_c::create(w);
+ prefs::setup(w);
+}
+
+// static fonts_prefs hp;
diff --git a/view/src/fonts_prefs.h b/view/src/fonts_prefs.h
new file mode 100644
index 0000000..b2ff4a8
--- /dev/null
+++ b/view/src/fonts_prefs.h
@@ -0,0 +1,133 @@
+#ifndef fonts_prefs_H
+#define fonts_prefs_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+// Headers
+// #ifndef machine_H
+// #include <machine.h>
+// #endif
+
+// Forward declarations
+
+// class ostream;
+// typedef class _Pvts os_typespec; // Remove if not persistant
+
+//
+
+#ifndef prefs_H
+#include "prefs.h"
+#endif
+
+#ifndef uifonts
+#include "uifonts.h"
+#endif
+
+
+class fonts_prefs : public prefs, public fonts_form_c {
+public:
+
+// -- Exceptions
+ // None
+
+// -- Contructors
+
+ fonts_prefs() {}
+
+// -- Destructor
+
+ ~fonts_prefs() {}
+// -- Convertors
+ // None
+
+// -- Operators
+ // None
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+
+ virtual Widget widget() { return _xd_rootwidget; }
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+ // Uncomment for persistent, remove otherwise
+ // static os_typespec* get_os_typespec();
+
+protected:
+
+// -- Members
+ // None
+
+// -- Methods
+
+ // void print(ostream&) const; // Change to virtual if base class
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+private:
+
+// No copy allowed
+
+ fonts_prefs(const fonts_prefs&);
+ fonts_prefs& operator=(const fonts_prefs&);
+
+// -- Members
+ // None
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+ // None
+ virtual void changedCB( Widget w, XtPointer ) { pref_editor::changed(w); }
+ virtual void useCB( Widget w, XtPointer ) { pref_editor::use(w); }
+
+ virtual void create(Widget w,char*);
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+// -- Friends
+
+ //friend ostream& operator<<(ostream& s,const fonts_prefs& p)
+ // { p.print(s); return s; }
+
+};
+
+inline void destroy(fonts_prefs**) {}
+
+// If persistent, uncomment, otherwise remove
+//#ifdef _ODI_OSSG_
+//OS_MARK_SCHEMA_TYPE(fonts_prefs);
+//#endif
+
+#endif
diff --git a/view/src/fsb.cc b/view/src/fsb.cc
new file mode 100644
index 0000000..79f3edd
--- /dev/null
+++ b/view/src/fsb.cc
@@ -0,0 +1,91 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <stdarg.h>
+#include <stdio.h>
+#include "fsb.h"
+#include "gui.h"
+extern "C" {
+#include "xec.h"
+}
+
+fsb::fsb():
+ file_(0)
+{
+ create(gui::top());
+}
+
+fsb::~fsb()
+{
+ if(file_) XtFree(file_);
+}
+
+
+const char* fsb::ask(const char* title,
+ const char* file,const char* filter,
+ const char* dir)
+{
+ return instance().choose(title,file,filter,dir);
+}
+
+
+const char* fsb::choose(const char* title,
+ const char* deffile,const char* filter,
+ const char* directory)
+
+{
+ if(file_) XtFree(file_);
+ file_ = 0;
+
+ set(XmNdirSpec,deffile);
+ set(XmNpattern,filter);
+ set(XmNdirectory,directory);
+
+ instance().modal(title,True);
+
+ return file_;
+
+}
+
+void fsb::set(const char* res,const char* val)
+{
+ if(!val) return;
+ XmString s = XmStringCreateSimple((char*)val);
+ XtVaSetValues(form_,res,s,NULL);
+ XmStringFree(s);
+}
+
+void fsb::okCB(Widget,XtPointer data)
+{
+ XmFileSelectionBoxCallbackStruct* cb = (XmFileSelectionBoxCallbackStruct*)data;
+
+ char buf[1024];
+
+ char *f = (char*)xec_GetString(cb->value);
+ char *d = (char*)xec_GetString(cb->dir);
+
+ if(*f == '/')
+ strcpy(buf,f);
+ else
+ sprintf(buf,"%s%s",d,f);
+
+ XtFree(f);
+ XtFree(d);
+
+ file_ = XtNewString(buf);
+
+ ok_ = true;
+ stop_ = true;
+}
diff --git a/view/src/fsb.h b/view/src/fsb.h
new file mode 100644
index 0000000..52c613b
--- /dev/null
+++ b/view/src/fsb.h
@@ -0,0 +1,125 @@
+#ifndef fsb_H
+#define fsb_H
+
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#ifdef NO_BOOL
+#include "bool.h"
+#endif
+
+#include "uifsb.h"
+#include "dialog.h"
+
+class fsb : public dialog<fsb,fsb_shell_c> {
+public:
+
+// -- Exceptions
+ // None
+
+// -- Contructors
+
+ fsb();
+
+// -- Destructor
+
+ ~fsb(); // Change to virtual if base class
+
+// -- Convertors
+ // None
+
+// -- Operators
+ // None
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+
+ static const char* ask(const char* title,
+ const char* file = 0,
+ const char* filter = 0,
+ const char* dir = 0);
+
+ // Uncomment for persistent, remove otherwise
+ // static os_typespec* get_os_typespec();
+
+protected:
+
+// -- Members
+ // None
+
+// -- Methods
+
+ // void print(ostream&) const; // Change to virtual if base class
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+private:
+
+// No copy allowed
+
+ fsb(const fsb&);
+ fsb& operator=(const fsb&);
+
+
+ char* file_;
+
+// -- Methods
+
+ void set(const char*,const char*);
+
+ const char* choose(const char*,const char*,
+ const char*,const char*);
+
+
+// -- Overridden methods
+
+ virtual void okCB( Widget, XtPointer ) ;
+
+// -- Class members
+
+
+// -- Class methods
+ // None
+
+// -- Friends
+
+ //friend ostream& operator<<(ostream& s,const fsb& p)
+ // { p.print(s); return s; }
+
+};
+
+inline void destroy(fsb**) {}
+
+// If persistent, uncomment, otherwise remove
+//#ifdef _ODI_OSSG_
+//OS_MARK_SCHEMA_TYPE(fsb);
+//#endif
+
+#endif
diff --git a/ecflow_4_0_7/view/src/gen.sh b/view/src/gen.sh
similarity index 100%
rename from ecflow_4_0_7/view/src/gen.sh
rename to view/src/gen.sh
diff --git a/view/src/gen_translator.h b/view/src/gen_translator.h
new file mode 100644
index 0000000..ba2174c
--- /dev/null
+++ b/view/src/gen_translator.h
@@ -0,0 +1,25 @@
+#ifndef gen_translator_H
+#define gen_translator_H
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #4 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+
+template<class From,class To>
+class translator {
+public:
+ To operator()(const From& from);
+};
+
+#endif // gen_translator_H
diff --git a/view/src/globals.cc b/view/src/globals.cc
new file mode 100644
index 0000000..26f9541
--- /dev/null
+++ b/view/src/globals.cc
@@ -0,0 +1,92 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <stdio.h>
+#include "globals.h"
+#include "str.h"
+#include "option.h"
+#include "configurator.h"
+#include "choice.h"
+#include "gui.h"
+#include <string>
+
+static option<int> s0(globals::instance(),"timeout",60);
+static option<int> s1(globals::instance(),"maximum",60);
+static option<bool> s3(globals::instance(),"drift",true);
+static option<bool> s4(globals::instance(),"poll",true);
+static option<bool> s5(globals::instance(),"aborted",true);
+static option<bool> s6(globals::instance(),"late",true);
+static option<bool> s7(globals::instance(),"restarted",true);
+static option<bool> s8(globals::instance(),"new_suites",false);
+static option<bool> s9(globals::instance(),"direct_read",true);
+
+static option<bool> s10(globals::instance(),"zombied",false);
+static option<bool> s11(globals::instance(),"aliases",false);
+static option<bool> s13(globals::instance(),"late_family",false);
+
+static option<bool> e1(globals::instance(),"send_as_alias",false);
+static option<int> s12(globals::instance(),"jobfile_length",10000);
+
+// User
+
+static option<choice> u0(globals::instance(),"user_level",0);
+
+
+globals::globals()
+#ifdef alpha
+ :configurable("user.default")
+#endif
+{
+}
+
+globals::~globals()
+{
+}
+
+const char* globals::name() const
+{
+ return "user.default";
+}
+
+globals* globals::instance()
+{
+ static globals* g = new globals();
+ return g;
+}
+
+
+void globals::changed(resource& c)
+{
+ gui::changed(c);
+}
+
+void globals::set_resource(const str& name,int value)
+{
+ option<int> o(instance(),name,value);
+ o = value;
+ XECFDEBUG std::cout << "# resource: " << name.c_str() << " " << value << std::endl;
+}
+
+int globals::get_resource(const str& name,int value)
+{
+ option<int> o(instance(),name,value);
+ return o;
+}
+
+int globals::user_level()
+{
+ choice c = u0;
+ return c;
+}
diff --git a/view/src/globals.h b/view/src/globals.h
new file mode 100644
index 0000000..ee4cbd3
--- /dev/null
+++ b/view/src/globals.h
@@ -0,0 +1,53 @@
+#ifndef globals_H
+#define globals_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#ifndef option_H
+#include "option.h"
+#endif
+
+#ifndef configurable_H
+#include "configurable.h"
+#endif
+
+
+class globals : public configurable {
+public:
+
+ globals();
+
+ ~globals(); // Change to virtual if base class
+
+ static globals* instance();
+
+ static void set_resource(const str&,int);
+ static int get_resource(const str&,int);
+
+ static int user_level();
+
+private:
+
+ globals(const globals&);
+ globals& operator=(const globals&);
+
+ virtual const char* name() const;
+ virtual void changed(resource&);
+};
+
+inline void destroy(globals**) {}
+
+#endif
diff --git a/view/src/graph_layout.cc b/view/src/graph_layout.cc
new file mode 100644
index 0000000..51d4f1e
--- /dev/null
+++ b/view/src/graph_layout.cc
@@ -0,0 +1,455 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "arch.h"
+#include "graph_layout.h"
+#include "node.h"
+#include "reach.h"
+#include "observer.h"
+#include "dummy_node.h"
+#include "trigger_panel.h"
+#include "trigger_lister.h"
+#include "selection.h"
+#include "xec.h"
+#include "str.h"
+#include "Hyper.h"
+#include "tmp_file.h"
+#include <Xm/PushBG.h>
+#include <Xm/SeparatoG.h>
+
+class graph_node : public observer, public xnode {
+protected:
+
+ graph_layout& owner_;
+
+ void notification(observable*) { redraw(); }
+ void adoption(observable* o,observable* n) { node_ = (node*)n; }
+ void gone(observable*) { owner_.remove(this); delete this; }
+
+ void draw(Widget w,XRectangle* r) { node_->drawNode(w,r,false); }
+
+ void size(Widget w,XRectangle* r) { node_->sizeNode(w,r,false); }
+
+public:
+ graph_node(graph_layout&,node*);
+};
+
+graph_node::graph_node(graph_layout& t,node *n):
+ xnode(n),
+ owner_(t)
+{
+ observe(n);
+}
+
+//===============================================================
+
+struct node_relation {
+ node* trigger_;
+ node* through_;
+ int mode_;
+ node_relation* next_;
+
+ node_relation(node* tg,node* th,int m):
+ trigger_(tg), through_(th), mode_(m), next_(0) {}
+};
+
+//===============================================================
+
+graph_layout::graph_layout(trigger_panel& t,Widget w):
+ layout(t,w),
+ link_(false)
+{
+ add_input_CB();
+}
+
+graph_layout::~graph_layout()
+{
+ clear();
+}
+
+Widget graph_layout::menu1()
+{
+ if(link_)
+ return owner_.linkMenu();
+ else
+ return owner_.infoMenu();
+}
+
+Widget graph_layout::menu2()
+{
+ return menu1();
+}
+
+xnode* graph_layout::xnode_of(node& n)
+{
+ for(int i = 0; i < nodes_.count(); i++)
+ if(nodes_[i]->get_node() == &n)
+ return nodes_[i];
+ return 0;
+}
+
+void graph_layout::clear()
+{
+ int i;
+ NodeReset(widget_);
+ for(i = 0; i < nodes_.count(); i++)
+ delete nodes_[i];
+ nodes_.clear();
+
+ for(i = 0; i < relations_.count(); i++)
+ delete relations_[i];
+ relations_.clear();
+
+ link_ = false;
+}
+
+
+
+class nl1 : public trigger_lister {
+ int n_;
+ graph_layout& t_;
+ node* g_;
+ bool e_;
+public:
+
+ nl1(graph_layout& t,node* g,bool e) : n_(0), t_(t), g_(g), e_(e) {}
+
+ void next_node(node& n,node* p,int mode,node* t) {
+ t_.relation(&n,g_,p,mode,t);
+ n_++;
+ }
+
+ Boolean parents() { return e_; }
+ Boolean kids() { return e_; }
+
+ int count() { return n_; }
+};
+
+class nl2 : public trigger_lister {
+ int n_;
+ graph_layout& t_;
+ node* g_;
+ bool e_;
+public:
+
+ nl2(graph_layout& t,node* g,bool e) : n_(0), t_(t), g_(g), e_(e) {}
+ void next_node(node& n,node* p,int mode,node* t) {
+ t_.relation(g_,&n,p,mode,t);
+ n_++;
+ }
+ Boolean parents() { return e_; }
+ Boolean kids() { return e_; }
+
+ int count() { return n_; }
+};
+
+graph_node *graph_layout::get_graph_node(node* n)
+{
+ if(!n) return 0;
+
+ n = n->graph_node();
+
+ graph_node* t = (graph_node*)xnode_of(*n);
+ if(t) return t;
+
+ t = new graph_node(*this,n);
+ t->getBox(widget_);
+ t->visibility(True);
+
+ nodes_.add(t);
+
+ return t;
+}
+
+void graph_layout::remove(graph_node* g)
+{
+ nodes_.remove(g);
+}
+
+void graph_layout::click1(node* n,Boolean shift,Boolean control)
+{
+ if(n != 0) node_window::click1(n,shift,control);
+}
+
+
+void graph_layout::click2(node* n,Boolean shift,Boolean control)
+{
+ grow(n);
+
+ if(shift && !control)
+ {
+ node *p = n->parent();
+ if(p) {
+ relation(p,n,0,trigger_lister::hierarchy,0);
+ grow(p);
+ }
+ }
+
+ if(control)
+ {
+ grow(n,True);
+ }
+
+ if(shift && control)
+ {
+ int count = 0;
+ while(count != nodes_.count())
+ {
+ count = nodes_.count();
+ for(int i = 0; i < count; i++)
+ grow(nodes_[i]->get_node());
+ }
+ }
+}
+
+void graph_layout::show(node& n)
+{
+ clear();
+ grow(&n,False);
+
+ graph_node *g = get_graph_node(&n);
+ if(g) {
+ g->select();
+ g->setFocus();
+ }
+}
+
+static void clear_menu(Widget menu)
+{
+ WidgetList wl = 0;
+ int count = 0;
+
+ XtVaGetValues(menu,
+ XmNchildren,&wl,
+ XtNnumChildren,&count,
+ NULL);
+ XtUnmanageChildren(wl,count);
+}
+
+
+static void add_button(Widget menu,node* n,const char* a,const char* b)
+{
+ WidgetList wl = 0;
+ int count = 0;
+ Widget w = 0;
+
+ XtVaGetValues(menu,
+ XmNchildren,&wl,
+ XtNnumChildren,&count,
+ NULL);
+
+ for(int i = 0 ; i < count; i++)
+ if(!XtIsManaged(wl[i]))
+ {
+ w = wl[i];
+ break;
+ }
+
+ if(!w)
+ w = XmCreatePushButtonGadget(menu,"button",NULL,0);
+
+ xmstring s = xmstring(a,"bold") + xmstring(" ") + xmstring(b);
+
+ XtVaSetValues(w,
+ XmNlabelString, XmString(s),
+ XmNuserData, n,
+ NULL);
+
+ XtManageChild(w);
+}
+
+static void add_separator(Widget menu)
+{
+ WidgetList wl = 0;
+ int count = 0;
+ Widget w = 0;
+
+ XtVaGetValues(menu,
+ XmNchildren,&wl,
+ XtNnumChildren,&count,
+ NULL);
+
+ for(int i = 0 ; i < count; i++)
+ if(!XtIsManaged(wl[i]))
+ {
+ w = wl[i];
+ break;
+ }
+
+ if(!w) w = XmCreateSeparatorGadget(menu,"button",NULL,0);
+ XtManageChild(w);
+}
+
+static void tidy_menu(Widget menu)
+{
+ WidgetList wl = 0;
+ int count = 0;
+ XtVaGetValues(menu, XmNchildren,&wl, XtNnumChildren,&count, NULL);
+
+ for(int i = 0 ; i < count; i++)
+ if(XmIsPushButtonGadget(wl[i]))
+ if(xec_GetUserData(wl[i]) == 0)
+ XtUnmanageChild(wl[i]);
+}
+
+void graph_layout::link(XEvent* event_node,node* n1,node* n2)
+{
+ graph_node *g1 = get_graph_node(n1);
+ graph_node *g2 = get_graph_node(n2);
+ node* n = 0;
+
+ link_ = false;
+
+ if(g1 && g2)
+ {
+ link_ = true;
+
+ node_relation* r = (node_relation*)g1->relation_data(g2);
+
+ tmp_file tmp(tmpnam(0));
+ FILE *f = fopen(tmp.c_str(),"w");
+
+ if(f) {
+ fprintf(f,"From: {%s}\n",n1->full_name().c_str());
+ fprintf(f,"To : {%s}\n",n2->full_name().c_str());
+ }
+
+ clear_menu(owner_.linkMenu());
+ add_button(owner_.linkMenu(),n1,"From",n1->full_name().c_str());
+ add_button(owner_.linkMenu(),n2,"To",n2->full_name().c_str());
+
+ while(r)
+ {
+ if(f) fprintf(f,"\n");
+ add_separator(owner_.linkMenu());
+
+ if((n = r->trigger_)) {
+ if(f) fprintf(f,"Trigger: %s\n",n->definition().c_str());
+ add_button(owner_.linkMenu(),n,"Trigger",n->definition().c_str());
+ }
+ else add_button(owner_.linkMenu(),0,"-","-");
+
+ if((n = r->through_)) {
+
+ if(f) fprintf(f,"Through: {%s}\n",n->full_name().c_str());
+ add_button(owner_.linkMenu(),n,"Through",n->full_name().c_str());
+ }
+ else add_button(owner_.linkMenu(),0,"-","-");
+
+ r = r->next_;
+ }
+ tidy_menu(owner_.linkMenu());
+
+ if(f) fclose(f);
+ HyperLoadFile(owner_.dependHyperText(),(char*)tmp.c_str());
+ if(event_node->xbutton.button == 1)
+ owner_.showDependWindow();
+ }
+
+ if(!link_) {
+ HyperSetText(owner_.dependHyperText(),"");
+ owner_.hideDependWindow();
+ }
+}
+
+void graph_layout::selectNode(node *n)
+{
+ if(n)
+ {
+ graph_node* g = (graph_node*)xnode_of(*n);
+ if(g) g->show();
+ selection::notify_new_selection(n);
+ }
+}
+
+int graph_layout::grow(node* n,Boolean )
+{
+ nl1 l1(*this,n,owner().extended());
+ if(owner().triggers()) n->triggers(l1);
+
+ nl2 l2(*this,n,owner().extended());
+ if(owner().triggered()) n->triggered(l2);
+
+ return l1.count() + l2.count();
+}
+
+void graph_layout::relation(node* from, node* to,
+ node* through, int mode,node *trigger)
+{
+ graph_node* from_g = get_graph_node(from);
+ graph_node* to_g = get_graph_node(to);
+
+ from_g->relation(to_g);
+
+ node_relation* n = (node_relation*)from_g->relation_data(to_g);
+ while(n)
+ {
+ if(n->trigger_ == trigger &&
+ n->through_ == through &&
+ n->mode_ == mode)
+ break;
+
+ n = n->next_;
+ }
+
+ if(n == 0) {
+
+ n = new node_relation(trigger,through,mode);
+ relations_.add(n);
+
+ void* x = from_g->relation_data(to_g,n);
+ if(x) n->next_ = (node_relation*)x;
+ }
+
+ switch(mode)
+ {
+ case trigger_lister::normal:
+ break;
+
+ case trigger_lister::child:
+ /* from_g->relation_gc(to_g,gui::colorGC(STATUS_SUBMITTED)); */
+ from_g->relation_gc(to_g,gui::blueGC());
+ break;
+
+ case trigger_lister::parent:
+ //from_g->relation_gc(to_g,gui::colorGC(STATUS_COMPLETE));
+ from_g->relation_gc(to_g,gui::blueGC());
+ break;
+
+ case trigger_lister::hierarchy:
+ from_g->relation_gc(to_g,gui::colorGC(STATUS_ABORTED));
+ break;
+ }
+}
+
+class graph_layout_reacher : public reach_lister {
+ graph_layout& g_;
+public:
+ graph_layout_reacher(graph_layout& g) : g_(g) {}
+
+ void next(node* from, node* to,node* through, int mode,node *trigger)
+ {
+ g_.relation(from,to,through,mode,trigger);
+ }
+};
+
+void graph_layout::reach(node* n1,node* n2)
+{
+ graph_layout_reacher rl(*this);
+ clear();
+ reach::join(n1,n2,rl);
+}
+
+//====================================================================
diff --git a/view/src/graph_layout.h b/view/src/graph_layout.h
new file mode 100644
index 0000000..b27d306
--- /dev/null
+++ b/view/src/graph_layout.h
@@ -0,0 +1,74 @@
+#ifndef graph_layout_H
+#define graph_layout_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "array.h"
+
+#ifndef node_window_H
+#include "node_window.h"
+#endif
+
+#ifndef layout_H
+#include "layout.h"
+#endif
+
+class graph_node;
+struct node_relation;
+
+class graph_layout : public layout,
+ public node_window {
+public:
+ graph_layout(trigger_panel&,Widget);
+
+ ~graph_layout(); // Change to virtual if base class
+
+ graph_node* get_graph_node(node*);
+ int grow(node*,Boolean = False);
+ void siblings(node*);
+
+ virtual void show(node&);
+ virtual void clear();
+ virtual void reach(node*,node*);
+ virtual void selectNode(node*);
+ virtual xnode* xnode_of(node&);
+ virtual void click1(node*,Boolean,Boolean);
+ virtual void click2(node*,Boolean,Boolean);
+
+ Widget node_widget() { return widget_; }
+ void remove(graph_node*);
+
+ void relation(node*,node*,node*,int,node*);
+
+private:
+
+ graph_layout(const graph_layout&);
+ graph_layout& operator=(const graph_layout&);
+
+ array<graph_node*> nodes_;
+ array<node_relation*> relations_;
+ bool link_;
+
+ void scan(node*,node*);
+
+ virtual Widget menu1();
+ virtual Widget menu2();
+
+ virtual void link(XEvent*,node*,node*);
+};
+
+inline void destroy(graph_layout**) {}
+#endif
diff --git a/view/src/gui.cc b/view/src/gui.cc
new file mode 100644
index 0000000..74ecebf
--- /dev/null
+++ b/view/src/gui.cc
@@ -0,0 +1,377 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #8 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <stdarg.h>
+#include <stdio.h>
+#include "gui.h"
+#include "top.h"
+#include "str.h"
+#include "option.h"
+#include "host.h"
+#include "globals.h"
+#include "Str.hpp"
+
+#include <string.h> /* strerror */
+using namespace ecf;
+
+static interface* intf_= 0;
+
+// Colors
+
+static resource* gui_resources[] = {
+ new option<str>(globals::instance(),"color_black","black"),
+ new option<str>(globals::instance(),"color_blue","blue"),
+ new option<str>(globals::instance(),"color_red","red"),
+
+ new option<str>(globals::instance(),"color_unknown", "grey"),
+ new option<str>(globals::instance(),"color_suspended", "orange"),
+ new option<str>(globals::instance(),"color_complete", "yellow"),
+ new option<str>(globals::instance(),"color_queued", "lightblue"),
+ new option<str>(globals::instance(),"color_submitted", "turquoise"),
+ new option<str>(globals::instance(),"color_active", "green"),
+ new option<str>(globals::instance(),"color_aborted", "red"),
+ new option<str>(globals::instance(),"color_shutdown", "pink"),
+ new option<str>(globals::instance(),"color_halted", "violet"),
+
+ new option<str>(globals::instance(),"color_meter_low", "blue"),
+ new option<str>(globals::instance(),"color_threshold", "blue"),
+ new option<str>(globals::instance(),"color_event", "blue"),
+
+ new option<str>(globals::instance(),"normal_font_plain",
+ "-*-helvetica-medium-r-normal-*-12-*-*-*-*-*-*-*"),
+
+ new option<str>(globals::instance(),"normal_font_bold",
+ "-*-helvetica-bold-r-normal-*-12-*-*-*-*-*-*-*"),
+
+ new option<str>(globals::instance(),"small_font_plain",
+ "-*-helvetica-medium-r-normal-*-11-*-*-*-*-*-*-*"),
+
+ new option<str>(globals::instance(),"small_font_bold",
+ "-*-helvetica-bold-r-normal-*-11-*-*-*-*-*-*-*"),
+
+ new option<str>(globals::instance(),"tiny_font_plain",
+ "-*-*-*-*-*-*-7-*-*-*-*-*-*-*"),
+
+ new option<str>(globals::instance(),"tiny_font_bold",
+ "-*-*-bold-*-*-*-7-*-*-*-*-*-*-*"),
+};
+
+class tidy_gui_resources {
+public:
+ ~tidy_gui_resources() {
+ for(unsigned int i = 0; i < XtNumber(gui_resources) ; i++)
+ delete gui_resources[i];
+ }
+};
+
+void split_msg(std::string& msg) {
+ std::vector< std::string > lineTokens;
+ Str::split(msg, lineTokens);
+ msg.clear();
+ for (size_t i=0; i<lineTokens.size(); ++i) {
+ msg += lineTokens[i];
+ if (i%10 == 0) msg += "\n";
+ else msg += " ";
+ }
+}
+
+#if !defined(_AIX)
+static tidy_gui_resources tgr;
+#endif
+
+void gui::login(const char* host)
+{
+ if (intf_) intf_->login(host);
+}
+
+void gui::logout(const char* host)
+{
+ if (intf_) intf_->logout(host);
+}
+
+void gui::add_host(const std::string& host)
+{
+ if (intf_) intf_->add_host(host);
+}
+
+void gui::message(const char* fmt,...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args,fmt);
+ vsprintf(buf,fmt,args);
+ intf_->message(buf);
+ va_end(args);
+
+ va_start(args,fmt);
+ va_end(args);
+}
+
+void gui::raise()
+{
+ Widget w = top();
+ if(w && XtIsRealized(w))
+ XMapRaised(XtDisplay(w),XtWindow(w));
+}
+
+Widget gui::top()
+{
+ return intf_->top_shell();
+}
+
+Widget gui::trees()
+{
+ return intf_->trees();
+}
+
+Widget gui::windows()
+{
+ return intf_->windows();
+}
+
+void gui::watch(Boolean)
+{
+}
+
+void gui::clear()
+{
+ intf_->clear();
+}
+
+
+Pixel gui::pixel(const char* name)
+{
+ static str grey("grey");
+
+ char buf[1024];
+
+ sprintf(buf,"color_%s",name);
+
+ str s = option<str>(globals::instance(),buf,grey);
+
+ XrmValue from_value, to_value;
+
+ from_value.addr = (char*)s.c_str();
+ from_value.size = strlen(from_value.addr) + 1;
+
+ Pixel p = 0;
+
+ to_value.addr = (char*)&p;
+ to_value.size = sizeof(Pixel);
+
+ XtConvertAndStore(gui::top(),
+ XmRString, &from_value,
+ XmRPixel, &to_value);
+
+ return p;
+}
+
+
+static GC makegc(Pixel p)
+{
+ XGCValues values;
+ XtGCMask valuemask = GCForeground;
+ values.foreground = p;
+
+ Widget w = gui::top();
+ return XCreateGC(XtDisplay(w),XtWindow(w),valuemask,&values);
+}
+
+static XmFontList makefont(const char* name)
+{
+ XrmValue from_value, to_value;
+
+ from_value.addr = (char*)name;
+ from_value.size = strlen( from_value.addr ) + 1;
+
+ XmFontList p = 0;
+
+ to_value.addr = (char*)&p;
+ to_value.size = sizeof(XmFontList);
+
+ XtConvertAndStore(gui::top(),
+ XmRString, &from_value,
+ XmRFontList, &to_value);
+
+ return p;
+}
+
+static XmFontList font(const char* name)
+{
+ char buf[1024];
+
+ sprintf(buf,"%s_plain",name);
+ str plain = option<str>(globals::instance(),buf,"fixed");
+
+ sprintf(buf,"%s_bold",name);
+ str bold = option<str>(globals::instance(),buf,"fixed");
+
+ str f = plain + str("=normal,") + bold + str("=bold");
+ return makefont(f.c_str());
+}
+
+inline GC makegc(const char* p)
+{
+ return makegc(gui::pixel(p));
+}
+
+static Pixel *status_colors = 0;
+
+char *ecf_colors_name[]
+= { (char*)"unknown", (char*)"suspended", (char*)"complete", (char*)"queued", (char*)"submitted", (char*)"active",
+ (char*)"aborted", (char*)"shutdown", (char*)"halted" ,
+ (char*)"meter_low",(char*)"threshold" , (char*)"event" ,
+ NULL };
+
+Pixel gui::colors(unsigned int n)
+{
+ if(status_colors == 0)
+ {
+ status_colors = new Pixel[XtNumber(::ecf_colors_name)];
+ for(unsigned int i = 0 ; i < XtNumber(::ecf_colors_name); i++)
+ status_colors[i] = gui::pixel(::ecf_colors_name[i]);
+ }
+ return status_colors[n];
+}
+
+static XmFontList normalFont = 0;
+static XmFontList smallFont = 0;
+static XmFontList tinyFont = 0;
+
+XmFontList gui::fontlist(void)
+{
+ if(normalFont == 0)
+ normalFont = font("normal_font");
+ return normalFont;
+}
+
+XmFontList gui::smallfont(void)
+{
+ if(smallFont == 0)
+ smallFont = font("small_font");
+ return smallFont;
+}
+
+XmFontList gui::tinyfont(void)
+{
+ if(tinyFont == 0)
+ tinyFont = font("tiny_font");
+ return tinyFont;
+}
+
+GC gui::blackGC(void)
+{
+ static GC gc = makegc("black");
+ return gc;
+}
+
+GC gui::blueGC(void)
+{
+ static GC gc = makegc("blue");
+ return gc;
+}
+
+GC gui::redGC(void)
+{
+ static GC gc = makegc("red");
+ return gc;
+}
+
+static GC* status_gc = 0;
+GC gui::colorGC(unsigned int n)
+{
+ if(status_gc == 0)
+ {
+ status_gc = new GC[XtNumber(::ecf_colors_name)];
+ for(unsigned int i = 0 ; i < XtNumber(::ecf_colors_name); i++)
+ status_gc[i] = makegc(colors(i));
+ }
+ if(n>= XtNumber(::ecf_colors_name)) return blackGC();
+ return status_gc[n];
+}
+
+
+void gui::changed(resource& c)
+{
+ for(unsigned int i = 0; i < XtNumber(gui_resources) ; i++)
+ {
+ if(&c == gui_resources[i])
+ {
+ delete[] status_colors; status_colors = 0;
+ delete[] status_gc; status_gc = 0;
+
+ normalFont = 0;
+ smallFont = 0;
+
+ host::redraw_all();
+ break;
+ }
+ }
+}
+
+void gui::rename_host(const std::string& a,const std::string& b)
+{
+ intf_->rename_host(a,b);
+}
+
+void gui::remove_host(const std::string& a)
+{
+ intf_->remove_host(a);
+}
+
+void gui::set_interface(interface* i)
+{
+ intf_= i;
+}
+
+void gui::error(const char* fmt,...)
+{
+ char buf[10240];
+ va_list arg;
+ va_start(arg,fmt);
+
+ vsprintf(buf,fmt,arg);
+ va_end(arg);
+
+ std::string msg = buf;
+ split_msg(msg);
+ intf_->error(msg.c_str());
+}
+
+void gui::error(ecf_list *l)
+{
+ // char buf[10240];
+ char buf[240];
+ buf[0] = 0;
+ while(l)
+ {
+ if(strlen(l->name().c_str()) + 2 >= sizeof(buf))
+ break;
+ if(buf[0]) strcat(buf,"\n");
+ strcat(buf,l->name().c_str());
+ l = l->next;
+ }
+ intf_->error(buf);
+}
+
+void gui::syserr(const char* msg)
+{
+ gui::error("%s",msg);
+}
+
+bool gui::visible()
+{
+ return intf_->visible();
+}
diff --git a/view/src/gui.h b/view/src/gui.h
new file mode 100644
index 0000000..363cc4e
--- /dev/null
+++ b/view/src/gui.h
@@ -0,0 +1,83 @@
+#ifndef gui_H
+#define gui_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "ecflowview.h"
+#include <Xm/Xm.h>
+#include <string>
+
+class resource;
+class interface;
+class node;
+
+class gui {
+public:
+
+ gui() {}
+
+ static void clear();
+ static void message(const char* fmt,...);
+ static void watch(Boolean);
+
+ static void add_host(const std::string&);
+ static void rename_host(const std::string&,const std::string&);
+ static void remove_host(const std::string&);
+
+ static void login(const char*);
+ static void logout(const char*);
+
+ static Widget top();
+ static Widget trees();
+ static Widget windows();
+
+ static void raise();
+
+ //--------------------------------------
+
+ static void changed(resource&);
+
+ static GC blackGC();
+ static GC blueGC();
+ static GC redGC();
+
+ static XmFontList smallfont();
+ static XmFontList fontlist();
+ static XmFontList tinyfont();
+ static Pixel colors(unsigned int);
+ static GC colorGC(unsigned int);
+
+ static void set_interface(interface*);
+ static Pixel pixel(const char* name);
+
+
+ //------------------------------------------------------
+
+ static bool visible();
+
+ static void error(const char*,...);
+ void error(ecf_list *l);
+ static void syserr(const char*);
+
+private:
+
+ gui(const gui&);
+ gui& operator=(const gui&);
+
+};
+
+inline void destroy(gui**) {}
+#endif
diff --git a/view/src/history.cc b/view/src/history.cc
new file mode 100644
index 0000000..699888d
--- /dev/null
+++ b/view/src/history.cc
@@ -0,0 +1,116 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "history.h"
+#include "node.h"
+#include "host.h"
+#include "selection.h"
+#include <Xm/List.h>
+extern "C" {
+#include "xec.h"
+}
+
+const int kMaxLines = 400;
+
+history::history(panel_window& w):
+ panel(w),
+ timeout(30),
+ last_("")
+{
+ panel::detach();
+}
+
+history::~history()
+{
+}
+
+void history::clear()
+{
+ last_ = "";
+ XmListDeleteAllItems(list_);
+ timeout::disable();
+}
+
+void history::show(node& n)
+{
+ timeout::enable();
+ add(n.serv());
+}
+
+void history::run()
+{
+ if(get_node())
+ add(get_node()->serv());
+ else
+ clear();
+}
+
+Boolean history::enabled(node& n)
+{
+ return n.type() == NODE_SUPER;
+}
+
+void history::browseCB(Widget,XtPointer data)
+{
+ XmListCallbackStruct* cb = (XmListCallbackStruct*)data;
+ char *p = (char*)xec_GetString(cb->item);
+
+ if(get_node())
+ {
+ node* n = get_node()->find_match(p);
+ if(n) selection::notify_new_selection(n);
+ }
+ else
+ clear();
+
+ XtFree(p);
+}
+
+void history::add(host& h)
+{
+ std::list<std::string>& l = h.history(last_);
+ int pos = 0;
+ XtVaGetValues(list_,XmNitemCount,&pos,NULL);
+ std::string prev = last_;
+ std::list<std::string>::const_iterator j;
+ for(j = l.begin(); j != l.end() ; ++j)
+ {
+ if (j->empty()) {}
+ else if (*j == "") {}
+ /* filter out line with time stamp older than last */
+ else if (last_ != "" && strcmp(j->c_str()+3, last_.c_str()+3) <= 0) {}
+ /* filter out some commands */
+ else if (j->find("command:LogCmd") != std::string::npos) {}
+ else if (j->find("--log=get") != std::string::npos) {}
+ else if (j->find("--news") != std::string::npos) {}
+ /* add interesting lines */
+ else {
+ if(pos >= kMaxLines)
+ XmListDeletePos(list_,1);
+ else
+ pos++;
+
+ int err = j->substr(0, 4)=="ERR:"; /* bold ? */
+ xec_AddFontListItem(list_,(char*)j->c_str(),err);
+ prev = *j;
+ }
+ }
+
+ XmListSetBottomPos(list_,pos);
+ l.clear();
+ last_ = prev;
+}
+
+// static panel_maker<history> maker(PANEL_HISTORY);
diff --git a/view/src/history.h b/view/src/history.h
new file mode 100644
index 0000000..69eaec8
--- /dev/null
+++ b/view/src/history.h
@@ -0,0 +1,59 @@
+#ifndef history_H
+#define history_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#ifndef panel_H
+#include "panel.h"
+#endif
+
+#include "timeout.h"
+#include "ecflowview.h"
+#include "uihistory.h"
+
+class host;
+
+class history : public panel, public history_form_c, public timeout {
+public:
+
+ history(panel_window&);
+
+ ~history(); // Change to virtual if base class
+
+ virtual const char* name() const { return "History"; }
+ virtual void show(node&);
+ virtual Boolean enabled(node&);
+ virtual void clear();
+ virtual Widget widget() { return xd_rootwidget(); }
+
+private:
+
+ history(const history&);
+ history& operator=(const history&);
+
+ std::string last_;
+
+ void run();
+ void add(host&);
+ void update() {}
+
+ virtual void browseCB(Widget,XtPointer);
+
+};
+
+inline void destroy(history**) {}
+
+#endif
diff --git a/view/src/host.cc b/view/src/host.cc
new file mode 100644
index 0000000..19d83f0
--- /dev/null
+++ b/view/src/host.cc
@@ -0,0 +1,1892 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #122 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <iostream> // shared_ptr
+#include <memory>
+#include <unistd.h>
+#include <string>
+#include <list>
+#include <algorithm>
+#include <boost/lexical_cast.hpp>
+#include "UrlCmd.hpp"
+#include <time.h>
+
+#include "ecflowview.h"
+#include "ecflow.h"
+#include "super_node.h"
+#include <ostream>
+
+#include "show.h"
+#include "edit.h"
+
+#ifndef scripting_H
+#include "scripting.h"
+#endif
+
+#ifndef late_H
+#include "late.h"
+#endif
+
+#ifndef zombie_H
+#include "zombie.h"
+#endif
+
+#ifndef ecf_node_
+#include "ecf_node.h"
+#endif
+
+#ifndef to_check_H
+#include "to_check.h"
+#endif
+
+#ifndef directory_H
+#include "directory.h"
+#endif
+
+#ifndef aborted_H
+#include "aborted.h"
+#endif
+
+#ifndef restart_H
+#include "restart.h"
+#endif
+
+#ifndef host_H
+#include "host.h"
+#endif
+
+#ifndef passwrd_H
+#include "passwrd.h"
+#endif
+
+#ifndef error_H
+#include "error.h"
+#endif
+
+#ifndef confirm_H
+#include "confirm.h"
+#endif
+
+#ifndef selection_H
+#include "selection.h"
+#endif
+
+#ifndef init_H
+#include "init.h"
+#endif
+
+#ifndef tree_H
+#include "tree.h"
+#endif
+
+#ifndef gui_H
+#include "gui.h"
+#endif
+
+#ifndef mail_H
+#include "mail.h"
+#endif
+
+#ifndef configurator_H
+#include "configurator.h"
+#endif
+
+#ifndef node_H
+#include "node.h"
+#endif
+
+#ifndef logsvr_H
+#include "logsvr.h"
+#endif
+
+#include "Version.hpp"
+
+#include "panel_window.h"
+#include <stdio.h>
+#include <assert.h>
+#include <boost/bind.hpp>
+
+#include "menus.h"
+/* #include <proc/readproc.h> */
+
+using namespace std;
+
+bool Updating::do_full_redraw_ = false;
+
+class SelectNode {
+public:
+ SelectNode(const std::string& name)
+ {
+ node* n = selection::current_node();
+ if (!n) return;
+ if (name == n->serv().name()) {
+ hostname_ = n->serv().name();
+ current_ = selection::current_path();
+ }
+ }
+
+ ~SelectNode()
+ {
+ if (hostname_.empty()) return;
+ host* h = host::find(hostname_);
+ if (h && !current_.empty()) {
+ node *n = h->top()->find(current_);
+ if (n) {
+ selection::notify_new_selection(n);
+ }
+ }
+ }
+
+private:
+ std::string current_, hostname_;
+};
+
+host::host( const std::string& name, const std::string& host, int number )
+ : timeout(5)
+#ifdef alpha
+ , configurable(name),
+#endif
+ , observable()
+ , host_(host)
+ , number_(number)
+ , name_(name)
+ , connected_(false)
+ , after_command_(true)
+ , passwd_("-none-")
+ , timeout_(this, "timeout", 5)
+ , maximum_(this, "maximum", 60)
+ , drift_(this, "drift", true)
+ , connect_(this, "connect", false)
+ , suites_(this, "suites", std::vector<std::string>())
+ , aborted_(this, "aborted", true)
+ , restarted_(this, "restarted", true)
+ , late_(this, "late", true)
+ , poll_(this, "poll", true)
+ , direct_read_(this, "direct_read", true)
+ , new_suites_(this, "new_suites", true)
+ , zombie_(this, "zombie", false)
+ , aliases_(this, "aliases", false)
+ , late_family_(this, "late_family", false)
+ , to_check_(this, "to_check", false)
+ , chkmail_(true)
+ , top_(0)
+ , tree_(0)
+ , mail_(0)
+ , last_(0)
+ , history_len_(100)
+ , updating_(false)
+ , jobfile_length_(this, "jobfile_length", 10000)
+{
+ if (number < 1) return; // dummy server OK;
+
+ if (number_) {
+ tree_ = tree::new_tree(this);
+ gui::add_host(name);
+ }
+
+ if (timeout_ < 1) timeout_ = 1;
+ if (maximum_ < 1) maximum_ = 1;
+
+ frequency(timeout_);
+}
+
+host::~host()
+{
+ if (tree_) {
+ delete tree_;
+ }
+}
+
+ehost::ehost( const std::string& name, const std::string& h, int number )
+ : host(name, h, number)
+{
+ try {
+ std::string port = boost::lexical_cast<std::string>(number);
+ client_.set_host_port(host_.c_str(), port);
+ client_.set_retry_connection_period(1);
+ }
+ catch ( std::exception& e ) {
+ gui::message("# Exception caught in host::host ");
+ gui::message(e.what());
+ }
+ if (connect_) login();
+}
+
+ehost::~ehost()
+{
+ connect_ = connected_;
+ logout();
+}
+
+void host::remove_host( const std::string& name )
+{
+ gui::remove_host(name);
+ ecf_nick_delete(name);
+ ecf_nick_write();
+ host* h = host::find(name);
+ if (h) {
+ h->logout();
+ delete h;
+ }
+}
+
+void host::broadcast( bool save )
+{
+ if (save) ecf_nick_write();
+}
+
+void host::login( const std::string& name )
+{
+ host* h = host::find(name);
+ if (h) h->login();
+}
+
+void host::logout( const std::string& name )
+{
+ host* h = host::find(name);
+ if (h) h->logout();
+}
+
+host* host::find( const std::string& machine, int number )
+{
+ host *h = extent < host > ::first();
+ while ( h ) {
+ if (h->host_ == machine && h->number_ == number) return h;
+ h = h->extent < host > ::next();
+ }
+ return 0x0;
+}
+
+host* host::find( const std::string& name )
+{
+ host *h = extent < host > ::first();
+ while ( h ) {
+ if (h->name() && h->name() == name) return h;
+ h = h->extent < host > ::next();
+ }
+ return 0;
+}
+
+node* host::find( const std::string& hostname, const std::string& n )
+{
+ host* h = find(hostname);
+ if (h && h->top_)
+ return h->top_->find(n.c_str());
+
+ return 0x0;
+}
+
+void host::status( Boolean force )
+{
+ host *h = extent < host > ::first();
+ while ( h ) {
+ if (force) h->reset(force);
+ h->status();
+ h = h->extent < host > ::next();
+ }
+}
+
+void host::redraw_all()
+{
+ host *h = extent < host > ::first();
+ while ( h ) {
+ h->redraw();
+ h = h->extent < host > ::next();
+ }
+}
+
+void host::search( node_lister& s )
+{
+ if (top_) top_->search(s);
+}
+
+void host::logout()
+{
+ if (connected_) gui::logout(name());
+ searchable::active(False);
+ connected_ = false;
+
+ if (tree_) {
+ tree_->connected(False);
+ tree_->xd_hide();
+ }
+
+ destroy_top(top_);
+ top_ = 0x0;
+
+ notify_observers();
+}
+
+void host::destroy_top(node* the_top) const
+{
+ if (the_top) {
+ if (the_top->__node__()) {
+ the_top->__node__()->nokids(); // Suites + all children
+ the_top->__node__()->unlink();
+ delete the_top->__node__(); // Defs
+ }
+ node::destroy(the_top);
+ }
+}
+
+void ehost::logout()
+{
+ if (!connected_) return;
+
+ try { client_.ch1_drop(); }
+ catch ( std::exception &e ) {
+ gui::message("host::logout-error: %s", e.what());
+ }
+
+ host::logout();
+}
+
+void host::run()
+{
+ if (!poll_) return;
+ update();
+ if (drift_) drift(5, maximum_ * 60);
+}
+
+tmp_file host::file(node& n, std::string name)
+{
+ return tmp_file(NULL);
+}
+
+tmp_file host::edit( node& n, std::list<Variable>& l, Boolean preproc )
+{
+ return tmp_file(NULL);
+}
+
+tmp_file host::jobcheck( node& n, const std::string &cmd )
+{
+ return tmp_file(NULL);
+}
+
+tmp_file ehost::jobcheck( node& n, const std::string &cmd )
+{
+ std::string subcmd = n.variable(cmd);
+ std::string job = n.variable("ECF_JOB");
+ std::string stat = job + ".stat";
+ if (n.__node__())
+ if (n.__node__()->get_node())
+ n.__node__()->get_node()->variableSubsitution(subcmd);
+ std::string check = "sh " + subcmd;
+
+ // tmp_file out(NULL);
+ char *tmp = tmpnam("ecf_checkXXXX");
+ command(check + " > " + tmp);
+ return tmp_file(tmp);
+ // return tmp_file(stat.c_str(), false);
+}
+
+tmp_file host::jobstatus( node& n, const std::string &cmd )
+{
+ return tmp_file(0x0);
+}
+
+tmp_file ehost::jobstatus( node& n, const std::string &cmd )
+{
+ command(clientName, "--status", n.full_name().c_str(), 0x0);
+ return tmp_file(0x0);
+}
+
+bool host::zombies( int mode, const char* name )
+{
+ return false;
+}
+
+const std::vector<std::string>& ehost::messages( const node&n ) const
+{
+ try {
+ client_.edit_history(n.full_name());
+ }
+ catch ( std::exception &e ) {
+ gui::message("host::messages: %s", e.what());
+ }
+ return client_.server_reply().get_string_vec();
+}
+
+const std::vector<std::string>& host::messages( const node&n ) const
+{
+ static std::vector<std::string> vct;
+ return vct;
+}
+
+bool host::get_zombies_list( std::vector<std::string>& list )
+{
+ return true;
+}
+
+bool ehost::get_zombies_list( std::vector<std::string>& list )
+{
+ gui::message("%s: fetching zombies_panel", this->name());
+ try {
+ client_.zombieGet();
+ }
+ catch ( std::exception &e ) {
+ gui::message("host::zombies-error: %s", e.what());
+ return false;
+ }
+ std::vector<Zombie> vect = client_.server_reply().zombies();
+
+ if (vect.size() == 0) {
+ gui::message("%s: No zombies at the moment", this->name());
+ return false;
+ }
+
+ std::sort(
+ vect.begin(),
+ vect.end(),
+ boost::bind(std::less<int>(), boost::bind(&Zombie::calls, _1),
+ boost::bind(&Zombie::calls, _2)));
+ Zombie::pretty_print(vect, list);
+ return true;
+}
+
+bool ehost::zombies( int mode, const char* name )
+{
+
+ if (!name) return false;
+
+ try {
+ gui::message("%s: updating zombies_panel", this->name());
+ switch ( mode ) {
+ case 1:
+ client_.zombieFobCli(name);
+ break;
+ case 2:
+ client_.zombieRemoveCli(name);
+ break;
+ case 3:
+ client_.zombieFailCli(name);
+ break;
+ case 4:
+ client_.zombieAdoptCli(name);
+ break;
+ case 5:
+ client_.zombieKillCli(name);
+ break;
+ // case X: client_.zombieBlockCli(name); break; // ???
+ default:
+ break;
+ }
+ }
+ catch ( std::exception &e ) {
+ gui::message("host::zombies-error: %s", e.what());
+ return false;
+ }
+ return true;
+}
+
+void host::set_loghost(node& n)
+{
+ loghost_ = n.variable("ECF_LOGHOST", true);
+ logport_ = n.variable("ECF_LOGPORT");
+ if (loghost_ == ecf_node::none()) {
+ loghost_ = n.variable("LOGHOST", true);
+ logport_ = n.variable("LOGPORT");
+ }
+ /* dynamic submission with load balacing may lead to
+ ECF_LOGHOST incorrect: let's fix that */
+ std::string host = n.variable("SCHOST", true);
+ std::string bkup = n.variable("SCHOST_BKUP", true);
+ if (bkup == ecf_node::none()) { /* ECMWF specific below; a better way? */
+ if (host == "cca") bkup = "ccb";
+ else if (host == "ccb") bkup = "cca";
+ }
+ if (bkup == ecf_node::none()) return;
+
+ std::string rid = n.variable("ECF_RID");
+ if (rid == ecf_node::none()) return;
+
+ bool use_altern = (rid.find(bkup) != std::string::npos);
+ if (!use_altern) return;
+
+ size_t beg = loghost_.find(host);
+ if (beg == std::string::npos) return; // not found
+ loghost_ = n.variable("ECF_LOGHOST", true).replace(beg, host.length(), bkup);
+ std::cout << "#MSG: using alternative loghost " + loghost_ << "\n";
+}
+
+void ehost::dir( node& n, const char* path, lister<ecf_dir>& l )
+{
+ set_loghost(n);
+ std::string::size_type pos = loghost_.find(n.variable("ECF_MICRO"));
+ if (std::string::npos != pos) return;
+ host::dir(n, path, l);
+}
+
+bool use_ecf_out_cmd(node&n, std::string path, ecf_dir *dir, std::string& content)
+{
+ /* used in conjonction with, for example:
+ edit ECF_OUTPUT_CMD "/home/ma/map/bin/trimurti-out.sh -u %USER:0% -h %SCHOST:0% -j %ECF_JOB:0% -o %ECF_JOBOUT:0% -r %ECF_RID:0%"
+ */
+ char buf[2048];
+ std::string cmd = n.variable("ECF_OUTPUT_CMD", true);
+ if (cmd == ecf_node::none()) return false;
+ else if (cmd.length() < 3) return false; // may be empty space characters, ignore cmd
+ else if (dir) cmd += " -d";
+ else if (!path.empty()) cmd += " -f " + path;
+
+ FILE *pipe = popen(cmd.c_str(), "r");
+ if (!pipe) return false;
+
+ while (!feof(pipe)) {
+ if (fgets(buf, sizeof(buf), pipe) != NULL) {
+ if (dir) {
+ dir->next = 0x0;
+ char name[1200];
+ sscanf(buf,"%d %d %d %d %d %d %d %s",
+ & dir->mode,
+ & dir->uid,
+ & dir->gid,
+ & dir->size,
+ & dir->atime,
+ & dir->mtime,
+ & dir->ctime,
+ name);
+
+ dir->name_ = strdup(name);
+ dir->next = new ecf_dir();
+ dir = dir->next;
+
+ XECFDEBUG std::cout << "#MSG:" << buf << " # " << name << "\n";
+ } else { content += buf; }
+ }
+ }
+ pclose(pipe);
+ return true;
+}
+
+void host::dir( node& n, const char* path, lister<ecf_dir>& l )
+{
+ gui::message("%s: fetching file list", this->name());
+ std::string content;
+ std::auto_ptr<ecf_dir> dir(new ecf_dir());
+ if (use_ecf_out_cmd(n, path, dir.get(), content))
+ { if (dir.get()) l.scan(dir.get()); }
+ else if (loghost_ != ecf_node::none()) {
+ logsvr log_server(loghost_, logport_);
+
+ if (log_server.ok()) {
+ std::auto_ptr<ecf_dir> dir(log_server.getdir(path));
+ if (dir.get()) {
+ l.scan(dir.get());
+ // return; // 20151115 add both remote + local?
+ }
+ }
+ }
+
+ if (path && direct_read_) {
+
+ const char* p = path;
+ const char* q = 0;
+
+ while ( *p ) {
+ if (*p == '/') q = p;
+ p++;
+ }
+
+ if (q) {
+ char basename[1024];
+ char dirname[1024];
+ strcpy(dirname, path);
+ dirname[q - path] = 0;
+ strcpy(basename, q + 1);
+
+ char* c = basename;
+ while ( *c ) {
+ if (*c == '.') {
+ if (*(c + 1)) {
+ *(c + 1) = 0;
+ break;
+ } /* 201311 Pontus Request */
+ else {
+ *c = 0;
+ }
+ }
+ c++;
+ }
+
+ std::auto_ptr<ecf_dir> dir(ecf_file_dir(dirname, basename, true));
+ if (dir.get()) {
+ l.scan(dir.get());
+ }
+ }
+ }
+}
+
+tmp_file host::script( node& n )
+{
+ return file(n, "ECF_SCRIPT");
+}
+
+tmp_file host::output( node& n )
+{
+ return file(n, "ECF_JOBOUT");
+}
+
+tmp_file host::job( node& n )
+{
+ return file(n, "ECF_JOB");
+}
+
+int host::status()
+{
+ int e = update();
+ frequency(timeout_);
+ return e;
+}
+
+void host::check_mail()
+{
+}
+
+int ehost::command( const char* cmd, ... )
+{
+ int ac = 0;
+ char *av[100], *s;
+ va_list ap;
+
+ va_start(ap, cmd);
+ av[ac++] = strdup(cmd);
+ while ( (s = va_arg(ap, char*)) )
+ av[ac++] = strdup(s);
+ va_end(ap);
+
+ return command(ac, av);
+}
+
+int ehost::command( const std::string& str )
+{
+ const char *cmd = str.c_str();
+ if (!cmd) return -1;
+
+ if (str.substr(0, 3) == "sh ") {
+ int pid = 0;
+ if ((pid = fork()) == 0) /* the child */{
+ execl("/bin/sh", "sh", "-c", str.substr(3).c_str(), NULL);
+ _exit(127);
+ return 0;
+ }
+ if (pid == -1)
+ return 1;
+ else
+ return 0;
+ }
+ else if (str == "write menu") {
+ menus::write();
+ return 0;
+ }
+
+ int e = 0, ac = 0;
+ char* av[100];
+ char* line = strdup(cmd);
+
+ char *c = (char*) "\"";
+ char* s = strtok(line, c);
+ if (s == 0)
+ e = command(1, &line);
+ else {
+ c = (char*) "'";
+ s = strtok(line, c);
+ if (s == 0)
+ e = command(1, &line);
+ else {
+ c = (char*) " ";
+ s = strtok(line, c);
+ }
+ }
+ do {
+ av[ac++] = s;
+ s = strtok(NULL, c);
+ }
+ while ( s != NULL );
+ e = command(ac, av);
+
+ if (line) free(line);
+ return e;
+}
+
+int host::maxLines = 25000;
+
+class init_hosts : public init {
+ void run( int argc, char **argv )
+ {
+ scripting::init();
+ host::init();
+ }
+};
+
+void host::chat()
+{
+}
+
+void host::check_all_mail()
+{
+ host *h = extent < host > ::first();
+ while ( h ) {
+ h->check_mail();
+ h = h->extent < host > ::next();
+ }
+}
+
+#include <fstream>
+
+void mem_use( double& vmu, double& res )
+{
+ using std::ios_base;
+ using std::ifstream;
+ using std::string;
+ unsigned long vsize;
+ long rss;
+ vmu = 0.0;
+ res = 0.0;
+ std::ifstream stat("/proc/self/stat", std::ios_base::in);
+ std::string pid, comm, state, ppid, pgrp, session, tty_nr, tpgid, flags,
+ minflt, cminflt, majflt, cmajflt, utime, stime, cstime, priority, nice,
+ O, itrealvalue, starttime;
+ stat >> pid >> comm >> state >> ppid >> pgrp >> session >> tty_nr >> tpgid
+ >> flags >> minflt >> cminflt >> majflt >> cmajflt >> utime >> stime
+ >> cstime >> priority >> nice >> O >> itrealvalue >> starttime >> vsize
+ >> rss;
+ stat.close();
+ long page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024;
+ vmu = vsize / 1024.0;
+ res = rss * page_size_kb;
+}
+
+bool ehost::create_tree( int hh, int min, int sec )
+{
+ int then_sec = 0;
+ XECFDEBUG {
+ time_t now;
+ time(&now);
+ struct tm* then = localtime(&now);
+ then_sec = then->tm_sec;
+ gui::message("%s: build %02d:%02d:%02d",
+ this->name(), then->tm_hour, then->tm_min, then->tm_sec);
+ if (sec != then->tm_sec) {
+ printf("# time get: %02d:%02d:%02d %s\n", hh, min, sec, this->name());
+ printf("# time got: %02d:%02d:%02d %s\n",
+ then->tm_hour, then->tm_min, then->tm_sec, this->name());
+ }
+ }
+
+ node *top = make_xnode<Defs>(client_.defs().get(), 0x0, *this);
+
+ XECFDEBUG {
+ time_t nnow;
+ time(&nnow);
+ struct tm* next = localtime(&nnow);
+ if (then_sec != next->tm_sec)
+ printf("# time blt: %02d:%02d:%02d %s\n",
+ next->tm_hour, next->tm_min, next->tm_sec, this->name());
+ gui::message("%s: built %02d:%02d:%02d",
+ this->name(), next->tm_hour, next->tm_min, next->tm_sec);
+ }
+
+ if (!top) {
+ return false;
+ }
+ if (top_) {
+ top->scan(top_);
+ destroy_top(top_);
+ }
+ top_ = top;
+ top_->active(poll_);
+ notify_observers();
+ top_->up_to_date();
+
+ redraw();
+ XECFDEBUG {
+ double vmu, res;
+ mem_use(vmu, res);
+ if (top) {
+ int num = 0; node *n = top->kids();
+ while (n) { num += 1; n = n->next(); }
+ }
+ std::cout << "# usage: " << vmu << " " << res << "\n";
+ }
+ return true;
+}
+
+void ehost::reset( bool full, bool sync )
+{
+ if (!connected_ || !connect_) return;
+ time_t now;
+ time(&now);
+ struct tm* curr = localtime(&now);
+ gui::message("%s: full tree %02d:%02d:%02d",
+ this->name(), curr->tm_hour, curr->tm_min, curr->tm_sec);
+ SelectNode select(this->name());
+ try {
+ if (!tree_) tree_ = tree::new_tree(this);
+
+ if (full) {
+ XECFDEBUG std::cerr << "# reset full\n";
+ const std::vector<std::string>& s = suites_;
+ destroy_top(top_);
+ top_ = 0x0;
+ notify_observers();
+
+ if (!s.empty()) {
+ // /* registering with empty set would lead
+ // to retrieve all server content,
+ // opposive of expected result */
+ // } else
+ // get all suite previously registered in GUI, and register
+ // them with the server The associated handle is retained in
+ // client_
+ try { client_.ch1_drop(); }
+ catch ( std::exception &e ) {
+ std::cout << "# no drop possible: " << e.what() << "\n";
+ }
+
+ client_.reset(); // reset client handle + defs
+ // This will add a new handle to client_
+ client_.ch_register(new_suites_, s);
+ }
+ }
+ }
+ catch ( std::exception &e ) {
+ XECFDEBUG std::cerr << "# reset exception " << e.what() << "\n";
+ if (client_.defs().get()) {
+ gui::error("host::reset-reg-error: %s", e.what());
+ }
+ }
+
+ int hour = 0, min = 0, sec = 0;
+ XECFDEBUG {
+ time_t now;
+ time(&now);
+ struct tm* curr = localtime(&now);
+ hour = curr->tm_hour, min = curr->tm_min, sec = curr->tm_sec;
+ gui::message("%s: start %02d:%02d:%02d", this->name(), hour, min, sec);
+ }
+
+ try {
+ if (sync) client_.sync_local(); // this returns full defs
+ searchable::active(False);
+ create_tree(hour, min, sec);
+ XECFDEBUG std::cerr << "# reset create tree\n";
+ }
+ catch ( std::exception &e ) {
+ // XECFDEBUG
+ std::cerr << "# sync exception " << e.what() << "\n";
+ gui::error("host::reset-sync-error: %s", e.what());
+ const std::vector<std::string>& s = suites_;
+ /* load one set
+ then another
+ checkpoint
+ kill the server
+ then restart the server
+ + view update command */
+ try {
+ client_.reset();
+ client_.ch_register(new_suites_, s);
+ }
+ catch ( std::exception &e ) {
+ gui::error("host::reset-register-error: %s", e.what());
+ }
+ }
+ searchable::active(True);
+}
+
+void host::aborted( node& n )
+{
+ if (n.type() == NODE_ALIAS) {
+ if (aliases_) aborted::show(n);
+ }
+ else if (aborted_) aborted::show(n);
+}
+
+void host::restarted( node& n )
+{
+ if (n.type() == NODE_ALIAS) {
+ if (aliases_) restart::show(n);
+ }
+ else if (restarted_) restart::show(n);
+}
+
+void host::late( node& n )
+{
+ if (late_family_ && n.type() == NODE_FAMILY)
+ late::show(n);
+ else if (late_) late::show(n);
+}
+
+void host::zombie( node& n )
+{
+ if (zombie_) zombie::show(n);
+}
+
+void host::to_check( node& n )
+{
+ if (to_check_) to_check::show(n);
+}
+
+void host::changed( resource& r )
+{
+ if (&r == &timeout_) frequency(timeout_);
+}
+
+void ehost::changed( resource& r )
+{
+ host::changed(r);
+ if (&r == &poll_) {
+ if (top_) top_->active(poll_);
+ client_.set_host_port(machine(), boost::lexical_cast<std::string>(number()));
+ connect_mngt(true);
+ if (connected_ && poll_) status();
+ }
+
+ if ((&r == &new_suites_) && connected_) {
+ // ch1_auto_add is used to control whether suites are
+ // automatically added to handle. It should only be called if
+ // suites had previously been registered
+ try {
+ if (client_.client_handle()) {
+ client_.ch1_auto_add(new_suites_);
+ }
+ else {
+ XECFDEBUG std::cerr << "# No suites previously registered ?";
+ }
+ }
+ catch ( std::exception &e ) {
+ gui::message("host::server-error: %s", e.what());
+ }
+ }
+}
+
+void host::redraw( bool create )
+{
+ if (create) {
+ SelectNode select(this->name());
+
+ if (top_) top_->unlink(true);
+ create_tree(0, 0, 0);
+ }
+ else if (tree_) tree_->update_tree(true);
+ if (top_) top_->reset();
+}
+
+str host::logfile() const
+{
+ char buf[1024];
+ buf[0] = 0;
+ return str(buf);
+}
+
+str ehost::logfile() const
+{
+ const char* home = top_ ? top_->variable("ECF_HOME").c_str() : 0;
+ const char* log = top_ ? top_->variable("ECF_LOG").c_str() : 0;
+ char buf[1024];
+ buf[0] = 0;
+
+ if (log) {
+ if (log[0] != '/' && home)
+ sprintf(buf, "%s/%s", home, log);
+ else
+ strcpy(buf, log);
+ }
+ return str(buf);
+}
+
+host& host::dummy()
+{
+ static host* h = new host("user.default", "user.default", 0);
+ return *h;
+}
+
+void host::plug( node* from )
+{
+ do_plug(selection::current_node(), from);
+}
+
+void host::comp( node* from, const char* a, const char* b )
+{
+ do_comp(selection::current_node(), from, a, b);
+}
+
+int host::do_comp( node* into, node* from, const std::string& a, const std::string& b )
+{
+ if (!into || !from) return 0;
+ std::stringstream out;
+ out << "${COMPARE:=/home/ma/map/bin/compare.sh} "
+ << from->full_name() << ":";
+ if (from->variable("ECF_NODE") != "(none)") {
+ out << from->variable("ECF_NODE") << ":"
+ << from->variable("ECF_PORT") << ":"
+
+ << from->variable("ECF_LOGHOST", true) << ":"
+ << from->variable("ECF_LOGPORT", true)
+
+ << ":" << from->variable("ECF_JOBOUT", true) << " \t";
+ }
+ else {
+ out << from->variable("SMSNODE") << ":"
+ << from->variable("SMS_PROG") << ":"
+
+ << from->variable("SMSLOGHOST", true) << ":"
+ << from->variable("SMSLOGPORT", true) << ":"
+
+ << from->variable("SMSJOBOUT", true) << " \t";
+ }
+
+ out << into->full_name() << ":";
+ if (into->variable("ECF_NODE") != "(none)") {
+ out << into->variable("ECF_NODE") << ":"
+ << into->variable("ECF_PORT") << ":"
+ << into->variable("ECF_LOGHOST", true) << ":"
+ << into->variable("ECF_LOGPORT", true)
+ << ":" << into->variable("ECF_JOBOUT", true) << " \t";
+ }
+ else {
+ out << into->variable("SMSNODE") << ":"
+ << into->variable("SMS_PROG") << ":"
+ << into->variable("SMSLOGHOST", true) << ":"
+ << into->variable("SMSLOGPORT", true) << ":"
+ << into->variable("SMSJOBOUT", true) << " \t";
+ }
+ out << a << " \t" << b << "\n";
+ const std::string cmd = out.str();
+ std::cout << cmd;
+
+ int pid = fork();
+ if (pid == 0) { /* the child */
+ execl("/bin/sh", "sh", "-c", cmd.c_str(), NULL);
+ _exit(127);
+ return 0;
+ }
+ if (pid == -1) return 1;
+ return 0;
+}
+
+int host::do_plug( node* into, node* from )
+{
+ if (!into || !from) return 1;
+
+ str sf(from->full_name().c_str());
+ str si(into->full_name().c_str());
+ str sn = si + str("/") + str(from->name());
+
+ host *destination = &into->serv();
+ host *source = &from->serv();
+
+ if (destination == source) {
+ gui::error("# Node cannot be pluged to the same server");
+ return 1;
+ }
+
+ if (!confirm::ask(false, "You are about pluging %s %s of %s into %s %s of %s.\n"
+ "Note that you will have to resume %s in the ECF %s.\n"
+ "Proceed?",
+ from->type_name(), sf.c_str(), source->name(), into->type_name(), si.c_str(),
+ destination->name(), sn.c_str(), destination->name())) return 1;
+
+ str sp(from->parent()->full_name().c_str());
+ if (sp != si) {
+ if (!confirm::ask(false, "You are about to move the %s '%s' from a sub-tree named '%s' to\n"
+ "a sub-tree named '%s'. This may cause some problems,\n"
+ "specially if there are any active tasks. Do you want to proceed?",
+ from->type_name(), from->name().c_str(), sp.c_str(), si.c_str())) return 1;
+ }
+
+ if (destination->status()) {
+ gui::error("# Cannot get status for %s. Pluging aborted.", destination->name());
+ return 1;
+ }
+ if (source->status()) {
+ gui::error("Cannot get status for %s. Pluging aborted.", source->name());
+ return 1;
+ }
+
+ node *nfrom = source->top()->find(sf.c_str());
+ std::string cmd;
+
+ if (!(nfrom->status() == STATUS_SUSPENDED)) {
+ if (source->command(clientName, "--suspend", nfrom->full_name().c_str(), 0x0)) {
+ gui::error("Cannot suspend %s. Pluging aborted", sf.c_str());
+ return 1;
+ }
+ }
+
+ if (nfrom == 0) {
+ cmd = "One of the node is gone after status.\n";
+ cmd += "It must have been canceled. Pluging aborted.";
+ gui::error(cmd.c_str());
+ return 1;
+ }
+
+ gui::message("Pluging from %s to %s", source->name(), destination->name());
+ cmd = "//";
+ cmd += destination->machine();
+ cmd += ":";
+ cmd += (boost::lexical_cast<std::string>(destination->number())).c_str();
+ cmd += si.c_str();
+ if (source->command(clientName, "--plug", sf.c_str(), cmd.c_str(), 0x0)) {
+ gui::error("Pluging aborted.");
+ return 1;
+ }
+
+ source->status();
+ destination->status();
+ return 0;
+}
+
+struct dup_slash { // INT-74
+ bool operator() (char x, char y) const {
+ return x=='/' && y=='/';
+ };
+};
+
+tmp_file ehost::sfile( node& n, std::string name )
+{
+ // set_loghost(n);
+ return host::sfile(n, name);
+}
+
+tmp_file host::sfile( node& n, std::string name )
+{
+ if (name == ecf_node::none()) return tmp_file((const char*) NULL);
+ name.erase(std::unique(name.begin(), name.end(), dup_slash()), name.end()); // INT-74
+ const char *cname = name.c_str();
+
+ std::string::size_type pos = loghost_.find(n.variable("ECF_MICRO"));
+ if (std::string::npos == pos && loghost_ != ecf_node::none()) {
+ logsvr log_server(loghost_, logport_);
+ if (log_server.ok()) {
+ tmp_file tmp = log_server.getfile(name);
+ if (access(tmp.c_str(), R_OK) == 0) return tmp;
+ }
+ }
+
+ if ((access(cname, R_OK) == 0)) {
+ return tmp_file(cname, false);
+ }
+
+ try {
+ n.serv().command(clientName, "--file", "-n", cname, host::maxLines, 0x0);
+ }
+ catch ( std::exception &e ) {
+ gui::error("cannot get file from server: %s", e.what());
+ }
+
+ return tmp_file(cname, false);
+}
+
+const str& host::timefile()
+{
+ if (timefile_.c_str()[0] == 0)
+ timefile_ = logfile();
+ else if (!strncmp("(none)/(none)", timefile_.c_str(), 13)) timefile_ = logfile();
+ return timefile_;
+}
+
+void host::hosts( host_lister& l )
+{
+ host *h = extent < host > ::first();
+ while ( h ) {
+ l.next(*h);
+ h = h->extent < host > ::next();
+ }
+}
+
+void host::change( const std::string& name, const std::string& machine, int number )
+{
+ bool logged = false;
+
+ if (connected_) {
+ logout();
+ logged = true;
+ }
+
+ gui::rename_host(this->name(), name);
+
+ ecf_nick_update(name, machine, number);
+
+ name_ = name;
+ host_ = machine;
+ number_ = number;
+ if (logged) login();
+}
+
+int host::origin() const
+{
+ return ecf_nick_origin(name());
+}
+
+static init_hosts init_hosts_instance;
+std::map<int, host_maker*> host_maker::map_;
+int host_maker::port_max = 65535;
+static host_builder<ehost> ehost_builder_instance(0);
+
+host* host::new_host( const std::string& p, const std::string& m, int n )
+{
+ ecf_nick_update(p, m, n);
+ return host_maker::make_host(p, m, n);
+}
+
+IMP(host)
+
+void host::login()
+{
+}
+
+bool check_version( const std::string& server_version, const std::string& viewer_version )
+{
+ // We know viewer version 4.1.0 is still compatible with old server versions 4.0.x
+// cout << "server version '" << server_version << "'\n";
+// cout << "viewer version '" << viewer_version << "'\n";
+ if (viewer_version == "4.1.0" && server_version.find("4.0.") != std::string::npos) {
+ return true;
+ }
+
+ const char* v1 = server_version.c_str();
+ const char* v2 = viewer_version.c_str();
+ int num = 0;
+ while ( v1 && v2 && num < 2 ) {
+ if (*v1 == '.') num++;
+ if (*v1 != *v2) return false;
+ v1++;
+ v2++;
+ }
+ return true;
+}
+
+void get_server_version( ClientInvoker& client, std::string& server_version )
+{
+ // ECF_ALLOW_NEW_CLIENT_OLD_SERVER allows each client ('client.allow_new_client_old_server')
+ // to have its own archive version, hence FIRST: go with what ever was set
+ // See notes: ACore/src/boost_archive.hpp
+
+ for(int av = ecf::boost_archive::version()-1; av >= ecf::boost_archive::version_1_47(); --av) {
+
+ // First time in loop, go with what ever was set, including if client.allow_new_client_old_server() !=0
+ try {
+ client.server_version();
+ server_version = client.server_reply().get_string();
+ if (!server_version.empty()) return;
+ }
+ catch ( ... ) {}
+
+ client.allow_new_client_old_server(av);
+ }
+}
+
+void ehost::login()
+{
+ gui::message("Login to %s", this->name());
+ host::logout();
+ host::login();
+ reset(true, true);
+
+ client_.set_throw_on_error(true);
+ try {
+ client_.set_host_port(machine(), boost::lexical_cast<std::string>(number()));
+ if (!connect_mngt(true)) {
+ gui::message("%s: no reply", this->name());
+ logout();
+ connected_ = false;
+ connect_ = false;
+ return;
+ }
+
+ // if we can not get the server version, attempt backward compatibility
+ std::string server_version;
+ get_server_version(client_, server_version);
+ if (server_version.empty()) {
+ if (!confirm::ask( false, "%s (%s@%d): Could not connect\nTry again ?",
+ this->name(), machine(), number())) {
+ connect_ = false;
+ connected_ = false;
+ return;
+ }
+ }
+ else {
+ if (!check_version(server_version, ecf::Version::raw())) {
+ if (!confirm::ask(
+ false,
+ "%s (%s@%d): version mismatch, server is %s, client is %s\ntry to connect anyway?",
+ this->name(), machine(), number(), server_version.c_str(),
+ ecf::Version::raw().c_str())) {
+ connect_ = false;
+ connected_ = false;
+ return;
+ }
+ }
+ }
+ connect_ = true;
+ connected_ = true;
+
+ if (!tree_) tree_ = tree::new_tree(this);
+ reset(true); // done later with update (test empty server)
+
+ enable();
+ if (tree_ != 0x0) {
+ tree_->xd_show();
+ tree_->connected(True);
+ redraw();
+ }
+ gui::login(name());
+ searchable::active(True);
+ }
+ catch ( std::exception& e ) {
+ searchable::active(False);
+ gui::error("Login to %s failed (%s)", this->name(), e.what());
+ if (!tree_) return;
+ if (connected_) {
+ tree_->update_tree(false);
+ }
+ else {
+ tree_->connected(False);
+ if (!top_)
+ top_ = make_xnode<Defs>(0x0, 0, *this);
+ }
+ }
+
+ update();
+}
+
+tmp_file ehost::file(node& n, std::string name)
+{
+ std::string error;
+ bool read = direct_read_;
+ name.erase(std::unique(name.begin(), name.end(), dup_slash()), name.end()); // INT-74
+
+ if (name == "ECF_SCRIPT") {
+ error = "no script!\n"
+ "check ECF_FILES or ECF_HOME directories, for read access\n"
+ "check for file presence and read access below files directory\n"
+ "or this may be a 'dummy' task.\n";
+ } else if (name == "ECF_JOB") {
+ std::string filename = n.variable(name);
+ if (read && (access(filename.c_str(), R_OK) == 0))
+ return tmp_file(filename.c_str(), false);
+
+ if (std::string::npos != filename.find(".job0")) {
+ error = "job0: no job to be generated yet!";
+ return tmp_file(error);
+ } else
+ error = "no script!\n"
+ "check ECF_HOME,directory for read/write access\n"
+ "check for file presence and read access below\n"
+ "The file may have been deleted\n"
+ "or this may be a 'dummy' task.\n";
+ } else if (boost::algorithm::ends_with(name, ".0")) {
+ error = "no output to be expected when TRYNO is 0!\n";
+ return tmp_file(error);
+ } else if (name != ecf_node::none()) { // Try logserver
+ // set_loghost(n);
+ std::string::size_type pos = loghost_.find(n.variable("ECF_MICRO"));
+ std::string content;
+ if (use_ecf_out_cmd(n, name, NULL, content)) {
+ tmp_file tmp(content); // tmpnam(NULL));
+ // tmp << content;
+ return tmp;
+ } else if (std::string::npos == pos && loghost_ != ecf_node::none()) {
+ logsvr log_server(loghost_, logport_);
+ if (log_server.ok()) {
+ tmp_file tmp = log_server.getfile(name); // allow more than latest output
+ if (access(tmp.c_str(), R_OK) == 0) return tmp;
+ }
+ }
+ }
+ if (read && (access(name.c_str(), R_OK) == 0)) {
+ return tmp_file(name.c_str(), false);
+ } else {
+ gui::message("%s: fetching %s", this->name(), name.c_str());
+ try {
+ if (name == "ECF_SCRIPT")
+ client_.file(n.full_name(), "script");
+ else if (name == "ECF_JOB") {
+ client_.file(n.full_name(), "job",
+ boost::lexical_cast<std::string>(jobfile_length_));
+ }
+ else if (name == "ECF_JOBOUT")
+ client_.file(n.full_name(), "jobout");
+ else {
+ client_.file(n.full_name(), "jobout");
+ }
+
+ // Do *not* assign 'client_.server_reply().get_string()' to a separate string, since
+ // in the case of job output the string could be several megabytes.
+ return tmp_file( client_.server_reply().get_string()
+ + "\n# file is served by ecflow-server\n" );
+ }
+ catch ( std::exception &e ) {
+ std::cerr << "host::file-error:" << e.what() << "\n";
+ gui::message("host::file-error: %s", e.what());
+ }
+ }
+
+ return tmp_file(error);
+}
+
+tmp_file ehost::edit( node& n, std::list<Variable>& l, Boolean preproc )
+{
+ gui::message("%s: fetching source", this->name());
+ try {
+ if (preproc)
+ client_.edit_script_preprocess(n.full_name());
+ else
+ client_.edit_script_edit(n.full_name());
+ return tmp_file(client_.server_reply().get_string());
+ }
+ catch ( std::exception &e ) {
+ gui::error("host::edit-error: %s", e.what());
+ }
+ catch ( ... ) {
+ gui::error("host::edit-error");
+ }
+ std::string error = "no script!\n"
+"\n"
+"check server->History:\n"
+"\tsome suite variable may be 'unterminated' (micro character missing) in script or include files\n"
+"\tcheck duplicate occurences of micro character when it is expected in the job (%% becomes %)\n"
+"\tuse %nopp ... %end or %includenopp <file.h> to disable job preprocessing where needed\n"
+"\tan include file may not be found\n"
+"check ECF_FILE directory is accessible, by opening the Script panel\n"
+"check ECF_INCLUDE directory is accessible from the server\n"
+"\tit must contain the included files (or links)\n"
+"client must be capable to create temporary file:\n"
+"\tcheck /tmp directory with write access, and space available,\n"
+"or preprocessed file may be truncated beyond some size.\n";
+ return tmp_file(error);
+}
+
+tmp_file host::manual( node& n )
+{
+ std::string man = "no manual...";
+ return tmp_file(man);
+}
+
+tmp_file ehost::manual( node& n )
+{
+ gui::message("%s: fetching manual", this->name());
+ try {
+ client_.file(n.full_name(), "manual");
+ if (client_.server_reply().get_string().empty()) {
+ std::string man = "no manual...";
+ return tmp_file(man);
+ }
+ return tmp_file(client_.server_reply().get_string());
+ }
+ catch ( std::exception &e ) {
+ gui::message("host::manual-error: %s", e.what());
+ }
+
+ std::string man = "no manual...";
+ return tmp_file(man);
+}
+
+void host::send( node& n, Boolean alias, Boolean run, NameValueVec& v,
+ const char* file )
+{
+}
+
+void ehost::send( node& n, Boolean alias, Boolean run, NameValueVec& v,
+ const char* file )
+{
+ std::vector<std::string> content;
+ char line[4096];
+ FILE *f = fopen(file, "r");
+ if (!f) {
+ gui::syserr(file);
+ return;
+ }
+ while ( fgets(line, sizeof(line), f) ) {
+ line[strlen(line) - 1] = 0;
+ content.push_back(line);
+ }
+ gui::message("%s: sending script_panel", this->name());
+
+ try {
+ client_.edit_script_submit(n.full_name(), v, content, alias, run);
+ }
+ catch ( std::exception &e ) {
+ gui::error("host::send-error: %s", e.what());
+ }
+ status();
+ fclose(f);
+}
+
+const std::vector<std::string>& host::suites() const
+{
+ return suites_;
+}
+
+void ehost::suites( int which, std::vector<std::string>& l )
+/* Menu Suites..., or Suites tab */
+{
+ try {
+ switch ( which ) {
+ case SUITES_LIST:
+ client_.suites();
+ l = client_.server_reply().get_string_vec();
+ break;
+ case SUITES_MINE:
+ l = suites_;
+ break;
+ case SUITES_REG:
+ gui::message("%s: registering to suites", this->name());
+ suites_ = l;
+ try {
+ if (l.empty()) {
+ try { client_.ch1_drop(); }
+ catch ( std::exception &e ) {
+ std::cout << "# no drop possible: " << e.what() << "\n";
+ }
+
+ // reset handle to zero , and clear the defs
+ client_.reset();
+ }
+ client_.ch_register(new_suites_, suites_);
+ status();
+ redraw();
+ }
+ catch ( std::exception &e ) {
+ gui::error("host::suites-reg-error: %s", e.what());
+ }
+ break;
+ default:
+ gui::message("%s: suites, what?");
+ break;
+ }
+ }
+ catch ( std::exception &e ) {
+ if (client_.defs().get()) { /* ignore empty server */
+ gui::error("host::suites-error: %s", e.what());
+ }
+ }
+}
+
+void host::suites( node* n, bool one )
+/* register only one suite with menu hide-other-suites (right-mouse-button,
+ on the server area, close to server node, not on the node itself */
+{
+ while ( n ) {
+ if (n->type() == NODE_SUITE) {
+ static std::vector<std::string> l;
+ if (!one) l = suites_;
+ l.push_back(n->name());
+ suites(SUITES_REG, l);
+ break;
+ }
+ n = n->parent();
+ }
+}
+
+int host::update()
+{
+ return TRUE;
+}
+extern XtAppContext app_context;
+
+void ehost::update_reg_suites( bool get_ch_suites )
+{
+ if (new_suites_) { // SUP-398 // temporary add higher load on the server
+ if (get_ch_suites) {
+ try {
+ client_.ch_suites();
+ }
+ catch ( std::exception& e ) {
+ gui::message("host::update-reg-suite-error: %s", e.what());
+ }
+ const std::vector<std::pair<unsigned int, std::vector<std::string> > >& vct = client_.server_reply().get_client_handle_suites();
+ for(size_t i = 0; i < vct.size(); ++i) {
+ if (vct[i].first == (unsigned int) client_.client_handle()) {
+ suites_ = vct[i].second;
+ break;
+ }
+ }
+ }
+ else {
+ const std::vector<suite_ptr>& suites_vec = client_.defs()->suiteVec();
+ std::vector<std::string> suites;
+ suites.reserve(suites_vec.size());
+ for(size_t i = 0; i < suites_vec.size(); ++i) {
+ suites.push_back(suites_vec[i]->name());
+ }
+ suites_ = suites;
+ }
+ }
+}
+
+int ehost::update()
+{
+ int err = -1;
+ if (!connected_) return err;
+
+ SelectNode select(this->name());
+ if (updating_) return 0; // SUP-423
+ Updating update(this); // SUP-423
+ gui::watch(True);
+ last_ = ::time(0);
+
+ try {
+ if (app_context) XtAppAddTimeOut(app_context, 20 * 1000, NULL, NULL);
+
+ time_t now;
+ time(&now);
+ struct tm* curr = localtime(&now);
+ gui::message("%s: checking status %02d:%02d:%02d",
+ this->name(), curr->tm_hour, curr->tm_min, curr->tm_sec);
+ client_.news_local(); // call the server
+ if (tree_) tree_->connected(True);
+
+ XECFDEBUG {
+ struct tm* next;
+ time_t now;
+ time(&now);
+ next = localtime(&now);
+ if (curr->tm_sec != next->tm_sec) {
+ printf("# time chk: %02d:%02d:%02d %s\n",
+ curr->tm_hour, curr->tm_min, curr->tm_sec, this->name());
+ printf("# time nws: %02d:%02d:%02d %s\n",
+ next->tm_hour, next->tm_min, next->tm_sec, this->name());
+ }
+ }
+ switch ( client_.server_reply().get_news() ) {
+ case ServerReply::NO_NEWS:
+ gui::message("::nonews\n");
+ if (top_) top_->up_to_date();
+ return 0;
+ break;
+ case ServerReply::DO_FULL_SYNC: // 4 calls to the server:
+ /* ch_suites + drop + reg_suites + sync_local */
+ gui::message("::fullsync\n");
+ if (top_) top_->up_to_date();
+ update_reg_suites(true);
+ reset(true);
+ return 0;
+ break;
+ case ServerReply::NO_DEFS:
+ reset(true);
+ return 0;
+ break;
+ case ServerReply::NEWS:
+ // there were some kind of changes in the server
+ // request the changes from the server & sync with
+ // defs on client_
+
+ client_.sync_local();
+ // full_sync==true: no notification on the GUI side
+
+ // full_sync==false: incremental change, notification
+ // received through ::update (ecf_node)
+
+ gui::message("%s: receiving status", this->name());
+
+ if (client_.server_reply().full_sync()) {
+ update_reg_suites(false); // new suite may have been added
+ reset(false, false); // SUP-398
+ }
+ else {
+ gui::message("%s: updating status", this->name());
+ XECFDEBUG std::cout << "# " << name() << ": small update\n";
+
+ if (Updating::full_redraw()) {
+ redraw(true);
+ }
+ else if (tree_) tree_->update_tree(false);
+ // fp:60043 Issue with Ecflow updating on console VM
+ // redraw(false); // too much blinking with this
+ }
+ err = 0;
+ break;
+ default:
+ break;
+ }
+ }
+ catch ( std::exception& e ) {
+ if (tree_ != 0x0) tree_->connected(False);
+ err = -1;
+ gui::message("host::news-error: %s", e.what());
+ XECFDEBUG std::cerr << "# host::news-error: " << e.what() << "\n";
+ }
+ return err;
+}
+
+int ehost::command( int argc, char **argv )
+{
+ int result = -1;
+
+ if (argc < 1) return FALSE;
+
+ if (!strcmp(argv[1], "--enable_logging")) {
+ client_.enable_logging("ecflow_client.log");
+ return true;
+ }
+ if (!strcmp(argv[1], "--disable_logging")) {
+ client_.disable_logging();
+ return true;
+ }
+ else if (!strcmp(argv[1], "--url")) {
+ if (argc == 3) {
+ UrlCmd urlCmd(client_.defs(), argv[2]);
+ try {
+ urlCmd.execute();
+ }
+ catch ( ... ) {
+ gui::error("cannot-open-url or substitution-error\n%s", argv[2]);
+ }
+ return true;
+ }
+ }
+
+ gui::message("command issued ...");
+ if (!strcmp(argv[0], clientName)) {
+ try {
+ int i = 0;
+ std::cout << "# CMD: ";
+ while ( i < argc )
+ std::cout << argv[i++] << " ";
+ result = client_.invoke(argc, argv);
+ std::cout << "--port " << number() << " --host " << machine() << " # ack\n";
+ }
+ catch ( std::exception &e ) {
+ gui::error("host::command-error:\n%s\n", e.what());
+ }
+ }
+ else {
+ int pid = fork();
+ if (pid == 0) { /* the child */
+ execl("/bin/sh", "sh", "-c", argv, NULL);
+ _exit(127);
+ return 0;
+ }
+ if (pid == -1) return 1;
+ }
+ if (after_command_) status();
+
+ return result;
+}
+
+std::list<std::string>& host::history( std::string& last )
+{
+ return hist_;
+}
+
+std::list<std::string>& ehost::history( std::string& last )
+{
+ gui::message("%s: fetching history", this->name());
+ try {
+ client_.getLog(history_len_);
+ boost::split(hist_, client_.server_reply().get_string(),
+ boost::is_any_of("\n"));
+ }
+ catch ( std::exception& e ) {
+ gui::message("history failed: ", e.what());
+ }
+ return hist_;
+}
+
+bool host::connect_mngt( bool connect )
+{
+ return true;
+}
+
+bool ehost::connect_mngt( bool connect )
+{
+ if (!connect) return true;
+ if (!connect_) return true;
+ bool rc = true;
+ try {
+ gui::message("%s: ping", this->name());
+ client_.pingServer();
+
+ if (connect) {
+ rc = true;
+ connected_ = true;
+ }
+ else {
+ connected_ = false;
+ rc = false;
+ }
+ }
+ catch ( std::exception &e ) {
+ connected_ = false;
+ rc = false;
+ gui::message("# Exception caught in ehost::connect_mngt");
+ gui::message(e.what());
+ }
+
+ if (tree_) tree_->connected(rc);
+ if (!rc) gui::logout(name());
+ return rc;
+}
+
+const std::string host::reply() const
+{
+ return "";
+}
+
+const std::string ehost::reply() const
+{
+ return client_.server_reply().get_string();
+}
+
+void host::init()
+{
+ ecf_nick_load();
+}
+
+host* host_maker::make_host( std::string name, std::string machine, int port )
+{
+ std::map<int, host_maker*>::const_iterator it = map_.begin();
+ host * out = 0x0;
+ if (port < host_maker::port_max) {
+ it = map_.find(0);
+ if (it != map_.end())
+ out = it->second->make(name, machine, port);
+ else XECFDEBUG std::cerr << "# cannot create ehost\n";
+ }
+ else {
+ it = map_.find(1);
+ if (it != map_.end())
+ out = it->second->make(name, machine, port);
+ else XECFDEBUG std::cerr << "# cannot create shost " << name << "\t" << machine << "\t"
+ << port << "\n";
+ }
+
+ return out;
+}
+
+void host::login( const std::string& name, int num )
+{
+ host *h = NULL;
+ if (num) h = host::find(name, num);
+ if (!h) h = host::find(name, ECF_PROG);
+ if (!h) h = host::find(name, SMS_PROG);
+ if (!h) h = host_maker::make_host(name, name, num);
+ if (h) h->login();
+}
+
+void ehost::stats( std::ostream& buf )
+{
+ gui::message("%s: fetching stats", this->name());
+ try {
+ client_.stats();
+ client_.server_reply().stats().show(buf);
+ }
+ catch ( std::exception& e ) {
+ }
+}
diff --git a/view/src/host.h b/view/src/host.h
new file mode 100644
index 0000000..7be224c
--- /dev/null
+++ b/view/src/host.h
@@ -0,0 +1,354 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #33 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#ifndef host_H
+#define host_H
+
+#include <time.h>
+#include <stdio.h>
+
+#include "ecf_node.h"
+#ifndef extent_H
+#include "extent.h"
+#endif
+
+#ifndef timeout_H
+#include "timeout.h"
+#endif
+
+#ifndef tmp_file_H
+#include "tmp_file.h"
+#endif
+
+#ifndef searchable_H
+#include "searchable.h"
+#endif
+
+#ifndef observable_H
+#include "observable.h"
+#endif
+#include "text_lister.h"
+
+class node;
+class tree;
+#ifndef lister_H
+#include "lister.h"
+#endif
+
+#ifndef option_H
+#include "option.h"
+#endif
+
+#ifndef configurable_H
+#include "configurable.h"
+#endif
+
+#ifndef str_H
+#include "str.h"
+#endif
+
+#ifdef NO_BOOL
+#include "bool.h"
+#endif
+
+#ifndef SINGLETON_H
+#include "singleton.h"
+#endif
+
+class Client;
+class configurator;
+class host;
+class url;
+#include <map>
+
+class host_maker {
+ virtual host* make(const std::string& name, const std::string& machine, int port) = 0;
+protected:
+ static std::map<int, host_maker*> map_;
+ static int port_max;
+public:
+ static host* make_host(std::string name, std::string machine, int port);
+ virtual ~host_maker() {}
+};
+
+template<typename T>
+class host_builder : public host_maker {
+ virtual host* make(const std::string& name, const std::string& machine, int port)
+ { return new T(name, machine, port); }
+public:
+ host_builder(int port_max) { map_[port_max] = this; }
+};
+
+class host_lister {
+public:
+ virtual void next(host&) = 0;
+ virtual ~host_lister() {}
+};
+
+
+class host : public extent<host>
+, public timeout
+ , public searchable
+ , public configurable
+ , public observable
+{
+ public:
+ static void status(Boolean);
+ static void login(const std::string&,int);
+ static void login(const std::string&);
+ static void logout(const std::string&);
+ static void broadcast(bool = false);
+ static void check_all_mail();
+
+ static node* find(const std::string&,const std::string&);
+ static host* find(const std::string&);
+ static void redraw_all();
+ static void plug(node*);
+ static void comp(node*, const char* a, const char* b );
+ static host* new_host(const std::string&,const std::string&,int);
+ static void remove_host(const std::string&);
+ static host& dummy();
+ static void chat();
+
+ protected:
+ static host* find(const std::string&,int);
+ void update_reg_suites(bool ) {};
+
+ static void hosts(host_lister&);
+ static int maxLines;
+ host( const std::string& name, const std::string& host, int number );
+
+ public:
+ virtual const std::string reply() const;
+
+ virtual ~host();
+
+ void call_after_commands(bool b) { after_command_ = b; }
+
+ static void init();
+
+ virtual void login();
+ virtual void logout();
+ int status();
+ void check_mail();
+
+ virtual int update();
+ virtual int command(const std::string& str) { return TRUE; };
+ virtual int command(const char*,...) { return TRUE; };
+ virtual int command(int,char**) { return TRUE; };
+ virtual std::list<std::string>& history(std::string&);
+ node* top() { return top_; }
+ tree* where() { return tree_; }
+
+ virtual tmp_file file(node& n,std::string name);
+ virtual tmp_file sfile( node& n, std::string name );
+ virtual tmp_file manual(node&);
+ virtual tmp_file script(node&);
+ virtual tmp_file output(node&);
+ virtual tmp_file job(node&);
+ virtual tmp_file jobstatus(node&, const std::string &);
+ virtual tmp_file jobcheck(node&, const std::string &);
+
+ virtual tmp_file edit(node& n,std::list<Variable>& l,Boolean preproc);
+ virtual void send(node& n,Boolean alias,Boolean run,NameValueVec& v,const char* file);
+ virtual void dir(node&,const char*,lister<ecf_dir>&);
+
+ void send(const char*,std::vector< std::string >&);
+
+ virtual bool zombies(int mode,const char* name);
+ virtual bool get_zombies_list(std::vector<std::string>& list);
+
+ const std::vector<std::string>& suites() const;
+ virtual void suites(int, std::vector<std::string>&) {};
+ void suites(node*,bool=true);
+
+ void redraw(bool create=false);
+ virtual bool create_tree(int hh=0, int min=0, int sec=0) { return false; }
+ time_t last() { return last_; }
+
+ virtual void change(const std::string&,const std::string&,int);
+
+ void aborted(node&);
+ void restarted(node&);
+ void late(node&);
+ void zombie(node&);
+ void to_check(node&);
+
+ void changed(resource&);
+
+ virtual str logfile() const ;
+ static int do_plug(node*,node*);
+ static int do_comp(node*,node*,
+ const std::string& kind, const std::string& meth);
+
+ // From timeout
+ void run();
+
+ // From searchable
+ inline const char* name() const { return name_.c_str(); }
+ const std::string& name_ref() const { return name_; }
+
+ const char* machine() const { return host_.c_str(); }
+ int number() const { return number_; }
+ void search(node_lister&);
+
+ void timefile(const str& s) { timefile_ = s; }
+ const str& timefile();
+
+ virtual const std::vector<std::string>& messages(const node&n) const;
+
+ protected:
+ host(const host&);
+ host& operator=(const host&);
+
+ void destroy_top(node*) const;
+
+ str host_;
+ int number_;
+
+ std::string name_;
+
+ bool connected_;
+ bool after_command_;
+
+ str user_;
+ str passwd_;
+ virtual int origin() const;
+
+ option<int> timeout_;
+ option<int> maximum_;
+ option<bool> drift_;
+ option<bool> connect_;
+ option<std::vector<std::string> > suites_;
+
+ option<bool> aborted_;
+
+ option<bool> restarted_;
+ option<bool> late_;
+ option<bool> poll_;
+
+ option<bool> direct_read_;
+ option<bool> new_suites_;
+
+ option<bool> zombie_;
+ option<bool> aliases_;
+ option<bool> late_family_;
+ option<bool> to_check_;
+
+ bool chkmail_;
+
+ node* top_;
+ tree* tree_;
+ int mail_;
+ time_t last_;
+ str timefile_;
+ std::list<std::string> hist_;
+ int history_len_;
+ std::string loghost_;
+ std::string logport_;
+
+ virtual void reset(bool full=false, bool sync=true) {};
+ virtual bool connect_mngt(bool connect);
+ void set_loghost(node& n);
+
+ bool updating_; // SUP-423
+ option<int> jobfile_length_;
+ public:
+ void updating(bool b) { updating_ = b; }
+ virtual void stats(std::ostream& f) { };
+};
+
+class ehost : public host {
+ public:
+ ehost( const std::string& name,const std::string& h,int number );
+ virtual ~ehost();
+ virtual void dir(node&,const char*,lister<ecf_dir>&);
+
+ bool zombies(int mode, const char *name);
+ bool get_zombies_list(std::vector<std::string>& list);
+
+ void login();
+ void logout();
+ void changed( resource& r );
+ virtual std::list<std::string>& history(std::string&);
+
+ virtual str logfile() const ;
+ virtual int command(int argc, char **argv);
+ int command(const std::string& str);
+ int command(const char* cmd, ... );
+
+ virtual tmp_file edit(node& n,std::list<Variable>& l,Boolean preproc);
+ virtual void send(node& n,Boolean alias,Boolean run,NameValueVec& v,const char* file);
+ virtual void suites(int, std::vector<std::string>&) ;
+ tmp_file sfile(node&,std::string);
+ tmp_file file(node& n,std::string name);
+ tmp_file manual( node& n );
+ tmp_file jobcheck( node& n, const std::string &cmd );
+ tmp_file jobstatus( node& n, const std::string &cmd );
+
+ const std::string reply() const;
+ virtual int update();
+
+ virtual const std::vector<std::string>& messages(const node&n) const;
+
+ void stats(std::ostream& f);
+ protected:
+ virtual bool connect_mngt(bool connect);
+ ClientInvoker client_;
+ bool create_tree(int hh=0, int min=0, int sec=0);
+
+ virtual void reset(bool full=false, bool sync=true);
+ protected:
+ void update_reg_suites(bool get_ch_suites);
+
+ ehost(const ehost&);
+ ehost& operator=(const ehost&);
+};
+struct host_locker {
+protected:
+ host* host_;
+ int e_;
+public:
+ host_locker( host* h );
+ ~host_locker();
+ int err() { return e_; }
+};
+
+class Updating {
+public:
+ Updating(host* h) : host_(h) {
+ do_full_redraw_ = false;
+ host_->updating(true);
+ }
+
+ ~Updating() {
+ host_->updating(false);
+ }
+
+ static void set_full_redraw() {
+ do_full_redraw_ = true;
+ }
+
+ static bool full_redraw() {
+ return do_full_redraw_;
+ }
+
+private:
+ host* host_;
+ static bool do_full_redraw_;
+};
+
+#endif
+
diff --git a/view/src/host_prefs.cc b/view/src/host_prefs.cc
new file mode 100644
index 0000000..273753a
--- /dev/null
+++ b/view/src/host_prefs.cc
@@ -0,0 +1,24 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "host_prefs.h"
+
+void host_prefs::create(Widget w,char*)
+{
+ option_form_c::create(w);
+ prefs::setup(w);
+}
+
+// static host_prefs hp;
diff --git a/view/src/host_prefs.h b/view/src/host_prefs.h
new file mode 100644
index 0000000..8990c8a
--- /dev/null
+++ b/view/src/host_prefs.h
@@ -0,0 +1,46 @@
+#ifndef host_prefs_H
+#define host_prefs_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#ifndef prefs_H
+#include "prefs.h"
+#endif
+
+#ifndef uioption_H
+#include "uioption.h"
+#endif
+
+class host_prefs : public prefs, public option_form_c {
+public:
+ host_prefs() {}
+
+ ~host_prefs() {}
+
+ virtual Widget widget() { return _xd_rootwidget; }
+
+private:
+
+ host_prefs(const host_prefs&);
+ host_prefs& operator=(const host_prefs&);
+
+ virtual void changedCB( Widget w, XtPointer ) { pref_editor::changed(w); }
+ virtual void useCB( Widget w, XtPointer ) { pref_editor::use(w); }
+ virtual void create(Widget w,char*);
+};
+
+inline void destroy(host_prefs**) {}
+#endif
diff --git a/view/src/html_lister.cc b/view/src/html_lister.cc
new file mode 100644
index 0000000..1f57a37
--- /dev/null
+++ b/view/src/html_lister.cc
@@ -0,0 +1,72 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <stdarg.h>
+#include "html_lister.h"
+
+html_lister::html_lister(node *n):
+ node_(n),
+ nodes_(0),
+ cancels_(0)
+{
+ buf_[0] = 0;
+}
+
+html_lister::~html_lister()
+{
+}
+
+void html_lister::push(node* n)
+{
+ char buf[1024];
+ sprintf(buf,"<a href=\"%s\">%s</a>",
+ n->net_name().c_str(), // TODO +1,
+ n->node_name().c_str());
+ strcat(buf_,buf);
+ nodes_++;
+}
+
+void html_lister::push(const char* p,...)
+{
+ char buf[1024];
+ va_list arg;
+ va_start(arg,p);
+ vsprintf(buf,p,arg);
+ va_end(arg);
+ strcat(buf_,buf);
+}
+
+void html_lister::cancel()
+{
+ cancels_++;
+}
+
+void html_lister::endline()
+{
+ if(cancels_) {
+ if(cancels_ >= nodes_)
+ {
+ //printf("Canceling line %s\n",buf_);
+ buf_[0] = 0;
+ }
+ else
+ {
+ //printf("Not canceling line %s\n",buf_);
+ }
+ }
+ line(buf_);
+ buf_[0] = 0;
+ nodes_ = cancels_ = 0;
+}
diff --git a/view/src/html_lister.h b/view/src/html_lister.h
new file mode 100644
index 0000000..53b48fc
--- /dev/null
+++ b/view/src/html_lister.h
@@ -0,0 +1,133 @@
+#ifndef html_lister_H
+#define html_lister_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+// Headers
+// #ifndef machine_H
+// #include <machine.h>
+// #endif
+
+// Forward declarations
+
+// class ostream;
+// typedef class _Pvts os_typespec; // Remove if not persistant
+
+//
+
+#include "node.h"
+#include "text_lister.h"
+
+class html_lister : public text_lister {
+public:
+
+// -- Exceptions
+ // None
+
+// -- Contructors
+
+ html_lister(node*);
+
+// -- Destructor
+
+ virtual ~html_lister(); // Change to virtual if base class
+
+// -- Convertors
+ // None
+
+// -- Operators
+ // None
+
+// -- Methods
+
+ virtual void line(const char*) = 0;
+
+// -- Overridden methods
+
+ void push(node* n);
+ void push(const char* p,...);
+ void endline();
+ void cancel();
+ node* source() const { return node_; }
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+ // Uncomment for persistent, remove otherwise
+ // static os_typespec* get_os_typespec();
+
+protected:
+
+// -- Members
+ // None
+
+// -- Methods
+
+ // void print(ostream&) const; // Change to virtual if base class
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+private:
+
+// No copy allowed
+
+ html_lister(const html_lister&);
+ html_lister& operator=(const html_lister&);
+
+// -- Members
+
+ node* node_;
+ int nodes_;
+ int cancels_;
+ char buf_[1024];
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+// -- Friends
+
+ //friend ostream& operator<<(ostream& s,const html_lister& p)
+ // { p.print(s); return s; }
+
+};
+
+inline void destroy(html_lister**) {}
+
+// If persistent, uncomment, otherwise remove
+//#ifdef _ODI_OSSG_
+//OS_MARK_SCHEMA_TYPE(html_lister);
+//#endif
+
+#endif
diff --git a/view/src/http.cc b/view/src/http.cc
new file mode 100644
index 0000000..a8efeb3
--- /dev/null
+++ b/view/src/http.cc
@@ -0,0 +1,112 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <string.h>
+
+#ifndef http_H
+#include "http.h"
+#endif
+
+#ifndef init_H
+#include "init.h"
+#endif
+
+#ifndef host_H
+#include "host.h"
+#endif
+
+#ifndef node_H
+#include "node.h"
+#endif
+
+#ifndef url_H
+#include "url.h"
+#endif
+
+
+http::http(int port,int argc,char** argv):
+ server(port)
+{
+ init::initialize(argc,argv);
+}
+
+http::~http()
+{
+}
+
+static const char *json = getenv("ECFLOW_JSON");
+
+void http::serve(int soc)
+{
+ url u(soc);
+
+ char what[1024];
+ char serv[128];
+ char from[1024];
+ char suit[128] = {0, };
+ strncpy(what,u.what(), 1024);
+
+ char *p = strtok(what,"/");
+ strncpy(serv,p?p:"", 128);
+
+ p = strtok(0,"/");
+ snprintf(suit,128, "%s",p?p:"");
+
+ p = strtok(0,"?");
+ snprintf(from,1024, "/%s/%s",suit,p?p:"");
+
+ if (json) { // set by environment variable
+ node::is_json = true;
+ } else {
+ node::is_json = false;
+ }
+ if (strlen(suit) > 5) {
+ if (!strncmp(".json", suit+strlen(from) - 5, 5)) {
+ suit[strlen(suit) - 5] = '\0';
+ }
+ }
+ if (strlen(from) > 5) {
+ if (!strncmp(".json", from+strlen(from) - 5, 5)) {
+ from[strlen(from) - 5] = '\0';
+ node::is_json = true; // set by url name
+ }
+ }
+ printf("get [%s] [%s] [%s]\n",serv,suit,from);
+
+ // host::login(serv);
+
+ host* ho = host::find(serv);
+ if(ho) {
+ if (suit[0] != 0) {
+ std::vector<std::string> regist;
+ regist.push_back(suit);
+ ho->suites(SUITES_REG, regist);
+ }
+ ho->login();
+ ho->status();
+ }
+ node* n = host::find(serv,from);
+
+ u.process(n);
+
+}
+
+int wmain(int argc,char** argv)
+{
+ char *p = getenv("ECFLOW_HTTP_PORT");
+ http s(atol(p),argc,argv);
+ s.run();
+ return 0;
+}
diff --git a/view/src/http.h b/view/src/http.h
new file mode 100644
index 0000000..926d447
--- /dev/null
+++ b/view/src/http.h
@@ -0,0 +1,143 @@
+#ifndef http_H
+#define http_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include <stdio.h>
+
+#ifndef server_H
+#include "server.h"
+#endif
+
+#ifndef interface_H
+#include "interface.h"
+#endif
+
+
+class http : public interface , public server {
+public:
+
+// -- Exceptions
+ // None
+
+// -- Contructors
+
+ http(int,int,char**);
+
+// -- Destructor
+
+ ~http(); // Change to virtual if base class
+
+// -- Convertors
+ // None
+
+// -- Operators
+ // None
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+
+ // From server
+
+ virtual void serve(int);
+
+
+ // From interface
+
+ virtual void clear() {}
+ virtual void message(const char* p) { fprintf(stderr,"-> %s\n",p); }
+ virtual void watch(Boolean) {}
+
+ virtual void add_host(const std::string&) {}
+ virtual void remove_host(const std::string&) {}
+ virtual void rename_host(const std::string&, const std::string&) {}
+
+ virtual void login(const char*) {}
+ virtual void logout(const char*) {}
+
+ virtual Widget top_shell() { return 0; }
+ virtual Widget trees() { return 0; }
+ virtual Widget windows() { return 0; }
+
+ virtual void error(const char*) {}
+
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+ // Uncomment for persistent, remove otherwise
+ // static os_typespec* get_os_typespec();
+
+protected:
+
+// -- Members
+ // None
+
+// -- Methods
+
+ // void print(ostream&) const; // Change to virtual if base class
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+private:
+
+// No copy allowed
+
+ http(const http&);
+ http& operator=(const http&);
+
+// -- Members
+ // None
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+// -- Friends
+
+ //friend ostream& operator<<(ostream& s,const http& p)
+ // { p.print(s); return s; }
+
+};
+
+inline void destroy(http**) {}
+
+// If persistent, uncomment, otherwise remove
+//#ifdef _ODI_OSSG_
+//OS_MARK_SCHEMA_TYPE(http);
+//#endif
+
+#endif
diff --git a/view/src/hyper_lister.cc b/view/src/hyper_lister.cc
new file mode 100644
index 0000000..a2b3456
--- /dev/null
+++ b/view/src/hyper_lister.cc
@@ -0,0 +1,73 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <stdarg.h>
+#include "hyper_lister.h"
+
+const int hyper_lister::dim_ = 1024;
+
+hyper_lister::hyper_lister(panel& o,node *n):
+ owner_(o),
+ node_(n),
+ nodes_(0),
+ cancels_(0)
+{
+ buf_[0] = 0;
+}
+
+hyper_lister::~hyper_lister()
+{
+}
+
+void hyper_lister::push(node* n)
+{
+ char buf[dim_];
+ snprintf(buf,dim_,"{%s}",n->node_name().c_str());
+ strcat(buf_,buf);
+ nodes_++;
+
+ owner_.observe(n);
+}
+
+void hyper_lister::push(const char* p,...)
+{
+ char buf[dim_];
+ va_list arg;
+ va_start(arg,p);
+ vsnprintf(buf,dim_,p,arg);
+ va_end(arg);
+ strcat(buf_,buf);
+}
+
+void hyper_lister::cancel()
+{
+ cancels_++;
+}
+
+void hyper_lister::endline()
+{
+ if(cancels_) {
+ if(cancels_ >= nodes_) {
+ //printf("Canceling line %s\n",buf_);
+ buf_[0] = 0;
+ }
+ else {
+ //printf("Not canceling line %s\n",buf_);
+ }
+ }
+ line(buf_);
+ buf_[0] = 0;
+ nodes_ = cancels_ = 0;
+}
diff --git a/view/src/hyper_lister.h b/view/src/hyper_lister.h
new file mode 100644
index 0000000..4a16ea1
--- /dev/null
+++ b/view/src/hyper_lister.h
@@ -0,0 +1,57 @@
+#ifndef hyper_lister_H
+#define hyper_lister_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "node.h"
+#include "panel.h"
+#include "text_lister.h"
+
+
+class hyper_lister : public text_lister {
+public:
+
+ hyper_lister(panel&,node*);
+
+ virtual ~hyper_lister(); // Change to virtual if base class
+
+ virtual void line(const char*) = 0;
+
+ void push(node* n);
+ void push(const char* p,...);
+ void endline();
+ void cancel();
+ node* source() const { return node_; }
+
+private:
+ static const int dim_;
+
+ hyper_lister(const hyper_lister&);
+ hyper_lister& operator=(const hyper_lister&);
+
+ panel& owner_;
+ node* node_;
+ int nodes_;
+ int cancels_;
+ char buf_[1024];
+
+ protected:
+ panel& owner() { return owner_; }
+};
+
+inline void destroy(hyper_lister**) {}
+
+#endif
diff --git a/view/src/icon_Josstatus3.cc b/view/src/icon_Josstatus3.cc
new file mode 100644
index 0000000..b028cdc
--- /dev/null
+++ b/view/src/icon_Josstatus3.cc
@@ -0,0 +1,41 @@
+#include "pixmap.h"
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static const char * bits[] = {
+"16 16 5 1",
+" c None",
+". c #000000",
+"+ c #0000FF",
+"@ c #00FF00",
+"# c #FF0000",
+"................",
+".+++++++@@@@###.",
+".+++++++@@@@###.",
+".+++++++@@@@###.",
+".+++++++@@@@###.",
+"................",
+".+++++++@@#####.",
+".+++++++@@#####.",
+".+++++++@@#####.",
+".+++++++@@#####.",
+"................",
+".+++++++++++###.",
+".+++++++++++###.",
+".+++++++++++###.",
+".+++++++++++###.",
+"................"};
+static pixmap p("Josstatus3",(const char**)bits);
diff --git a/view/src/icon_W.cc b/view/src/icon_W.cc
new file mode 100644
index 0000000..cb55b79
--- /dev/null
+++ b/view/src/icon_W.cc
@@ -0,0 +1,86 @@
+#include "pixmap.h"
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static const char * bits[] = {
+"16 16 50 1",
+" c None",
+". c #E7E7E7",
+"+ c #E7E3E3",
+"@ c #E9CDCD",
+"# c #EEA3A3",
+"$ c #FF0000",
+"% c #FA2A2A",
+"& c #F64E4E",
+"* c #F93434",
+"= c #FB1C1C",
+"- c #F46464",
+"; c #FD0E0E",
+"> c #EDA9A9",
+", c #E8D7D7",
+"' c #FB2222",
+") c #FE0606",
+"! c #ECB5B5",
+"~ c #FA2727",
+"{ c #EDABAB",
+"] c #F83E3E",
+"^ c #EF9494",
+"/ c #E7E5E5",
+"( c #EE9F9F",
+"_ c #F36D6D",
+": c #F08D8D",
+"< c #F74646",
+"[ c #ECB0B0",
+"} c #FE0404",
+"| c #FA2828",
+"1 c #E8DBDB",
+"2 c #E9CACA",
+"3 c #FD1313",
+"4 c #FD1212",
+"5 c #EACACA",
+"6 c #E7E6E6",
+"7 c #F65555",
+"8 c #E7DFDF",
+"9 c #E8DCDC",
+"0 c #FA2929",
+"a c #ECAFAF",
+"b c #F18484",
+"c c #F74949",
+"d c #E7E0E0",
+"e c #F27D7D",
+"f c #FE0101",
+"g c #F46868",
+"h c #F93939",
+"i c #F93131",
+"j c #FD0B0B",
+"k c #EDA6A6",
+"................",
+"................",
+"....+@@@@@@@@...",
+"....#$$%&*$$=...",
+"....-;>.,'$)!...",
+"....~{.+]$$^....",
+".../(..-$$_.....",
+"......:$$</.....",
+".....[}$|1......",
+"....23$45.678...",
+"...90$}a..b0....",
+"...c$$:.defg....",
+"...$$)hij$$k....",
+"................",
+"................",
+"................"};
+static pixmap p("W",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/icon_byrule.cc b/view/src/icon_byrule.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/icon_byrule.cc
rename to view/src/icon_byrule.cc
diff --git a/ecflow_4_0_7/view/src/icon_cmd_failed.cc b/view/src/icon_cmd_failed.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/icon_cmd_failed.cc
rename to view/src/icon_cmd_failed.cc
diff --git a/ecflow_4_0_7/view/src/icon_edit_failed.cc b/view/src/icon_edit_failed.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/icon_edit_failed.cc
rename to view/src/icon_edit_failed.cc
diff --git a/ecflow_4_0_7/view/src/icon_force_abort.cc b/view/src/icon_force_abort.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/icon_force_abort.cc
rename to view/src/icon_force_abort.cc
diff --git a/ecflow_4_0_7/view/src/icon_killed.cc b/view/src/icon_killed.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/icon_killed.cc
rename to view/src/icon_killed.cc
diff --git a/ecflow_4_0_7/view/src/icon_no_script.cc b/view/src/icon_no_script.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/icon_no_script.cc
rename to view/src/icon_no_script.cc
diff --git a/ecflow_4_0_7/view/src/icon_queuelimit.cc b/view/src/icon_queuelimit.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/icon_queuelimit.cc
rename to view/src/icon_queuelimit.cc
diff --git a/ecflow_4_0_7/view/src/icon_task_aborted.cc b/view/src/icon_task_aborted.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/icon_task_aborted.cc
rename to view/src/icon_task_aborted.cc
diff --git a/ecflow_4_0_7/view/src/icon_user_edit.cc b/view/src/icon_user_edit.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/icon_user_edit.cc
rename to view/src/icon_user_edit.cc
diff --git a/view/src/info.cc b/view/src/info.cc
new file mode 100644
index 0000000..ab6340f
--- /dev/null
+++ b/view/src/info.cc
@@ -0,0 +1,55 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "info.h"
+#include "node.h"
+#include "error.h"
+#include "selection.h"
+#include "Hyper.h"
+#include <stdio.h>
+#include "ecf_node.h"
+
+info::info(panel_window& w):
+ panel(w)
+{
+}
+
+info::~info()
+{
+}
+
+void info::clear()
+{
+ forget_all();
+ HyperSetText(text_,(char*)"No node selected.");
+}
+
+void info::show(node& n)
+{
+ forget_all();
+ std::stringstream ss;
+ n.info(ss);
+ HyperSetText(text_,(char*) ss.str().c_str());
+}
+
+void info::hyperCB(Widget w,XtPointer data)
+{
+ panel::hyper(w,data);
+}
+
+Boolean info::enabled(node& n)
+{
+ return n.hasInfo();
+}
diff --git a/view/src/info.h b/view/src/info.h
new file mode 100644
index 0000000..89aac31
--- /dev/null
+++ b/view/src/info.h
@@ -0,0 +1,46 @@
+#ifndef info_H
+#define info_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "uiinfo.h"
+
+#ifndef panel_H
+#include "panel.h"
+#endif
+
+class info : public panel, public info_form_c {
+public:
+ info(panel_window&);
+
+ ~info(); // Change to virtual if base class
+
+ virtual const char* name() const { return "Info"; }
+ virtual void show(node&);
+ virtual void clear();
+ virtual Widget widget() { return xd_rootwidget(); }
+ virtual Boolean enabled(node&);
+
+private:
+
+ info(const info&);
+ info& operator=(const info&);
+
+ virtual void hyperCB(Widget,XtPointer);
+};
+
+inline void destroy(info**) {}
+#endif
diff --git a/view/src/init.cc b/view/src/init.cc
new file mode 100644
index 0000000..c320362
--- /dev/null
+++ b/view/src/init.cc
@@ -0,0 +1,36 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "init.h"
+
+init::init()
+{
+}
+
+init::~init()
+{
+}
+
+void init::initialize(int argc,char** argv)
+{
+ init* p = first();
+ while(p) {
+ p->run(argc,argv);
+ p = p->next();
+ }
+}
+
+IMP(init)
+
diff --git a/view/src/init.h b/view/src/init.h
new file mode 100644
index 0000000..55274c5
--- /dev/null
+++ b/view/src/init.h
@@ -0,0 +1,127 @@
+#ifndef init_H
+#define init_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+// Headers
+// #ifndef machine_H
+// #include <machine.h>
+// #endif
+
+// Forward declarations
+
+// class ostream;
+// typedef class _Pvts os_typespec; // Remove if not persistant
+
+
+#ifndef extent_H
+#include "extent.h"
+#endif
+
+//
+
+class init : public extent<init> {
+public:
+
+// -- Exceptions
+ // None
+
+// -- Contructors
+
+ init();
+
+// -- Destructor
+
+ virtual ~init(); // Change to virtual if base class
+
+// -- Convertors
+ // None
+
+// -- Operators
+ // None
+
+// -- Methods
+
+ virtual void run(int,char**) = 0;
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+
+ static void initialize(int,char**);
+
+ // Uncomment for persistent, remove otherwise
+ // static os_typespec* get_os_typespec();
+
+protected:
+
+// -- Members
+ // None
+
+// -- Methods
+
+ // void print(ostream&) const; // Change to virtual if base class
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+private:
+
+// No copy allowed
+
+ init(const init&);
+ init& operator=(const init&);
+
+// -- Members
+ // None
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+// -- Friends
+
+ //friend ostream& operator<<(ostream& s,const init& p)
+ // { p.print(s); return s; }
+
+};
+
+inline void destroy(init**) {}
+
+// If persistent, uncomment, otherwise remove
+//#ifdef _ODI_OSSG_
+//OS_MARK_SCHEMA_TYPE(init);
+//#endif
+
+#endif
diff --git a/view/src/inlimit_node.cc b/view/src/inlimit_node.cc
new file mode 100644
index 0000000..f004916
--- /dev/null
+++ b/view/src/inlimit_node.cc
@@ -0,0 +1,71 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "inlimit_node.h"
+#include "ecf_node.h"
+#include "NodeAttr.hpp"
+
+inlimit_node::inlimit_node(host& h,ecf_node* n)
+ : node(h,n)
+ , buf_()
+ {
+ if (owner_) buf_ = owner_->toString();
+ full_name_ = parent()->full_name();
+ full_name_ += ":";
+ full_name_ += buf_;
+}
+
+#ifdef BRIDGE
+extern "C" {
+#define new _new
+#define delete _delete
+#include "smsproto.h"
+}
+inlimit_node::inlimit_node(host& h,sms_node* n, char b)
+ : node(h,n,b)
+ , buf_("limited by: ")
+ , full_name_ ("inlimit: ")
+{
+ if (n) { buf_ += n->name;
+ full_name_ = sms_node_full_name(n);
+ }
+}
+#endif
+
+inlimit_node::~inlimit_node() {
+}
+
+xmstring inlimit_node::make_label_tree()
+{
+ char buf[1024];
+ sprintf(buf,"%s",buf_.c_str());
+ return xmstring(buf);
+}
+
+void inlimit_node::perlify(FILE* f)
+{
+ perl_member(f,"limit",owner_->name().c_str());
+ // perl_member(f,"usage",owner_->usage());
+}
+
+bool inlimit_node::match(const char* p)
+{
+ return strstr(owner_->name().c_str(), p) != 0;
+}
+
+const std::string& inlimit_node::full_name() const
+{
+ return full_name_;
+}
diff --git a/view/src/inlimit_node.h b/view/src/inlimit_node.h
new file mode 100644
index 0000000..e2dd2ef
--- /dev/null
+++ b/view/src/inlimit_node.h
@@ -0,0 +1,49 @@
+#ifndef INLIMIT_NODE_H
+#define INLIMIT_NODE_H
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #10 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+
+#include "node.h"
+#include "show.h"
+
+class inlimit_node : public node {
+
+ std::string buf_, full_name_;
+ virtual bool match(const char*);
+
+ virtual void info(std::ostream&) {}
+ virtual xmstring make_label_tree();
+
+ virtual const std::string& name() const { return buf_; }
+ virtual const std::string& full_name() const;
+ virtual Boolean menus() { return False; }
+ virtual Boolean selectable() { return True; }
+
+ virtual Boolean visible() const { return show::want(show::inlimit); }
+
+ virtual void triggered(trigger_lister&) {}
+ virtual void triggers(trigger_lister&) {}
+ virtual void perlify(FILE*);
+
+public:
+ inlimit_node(host& h,ecf_node* n);
+#ifdef BRIDGE
+ inlimit_node(host& h,sms_node* n, char b); // : node(h,n,b) {}
+#endif
+ ~inlimit_node();
+};
+
+#endif
diff --git a/view/src/input.cc b/view/src/input.cc
new file mode 100644
index 0000000..af1084c
--- /dev/null
+++ b/view/src/input.cc
@@ -0,0 +1,67 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <stdio.h>
+#include <strings.h>
+#include "ecflowview.h"
+#include "input.h"
+
+extern XtAppContext app_context;
+
+void input::inputCB(XtPointer data,int*,XtInputId* id)
+{
+ input* p = ((input*)data);
+ char buf[1024];
+
+ if(fgets(buf,sizeof(buf),p->file_))
+ {
+ if(buf[0]) buf[strlen(buf)-1] = 0;
+ p->ready(buf);
+ }
+ else
+ p->done(p->file_);
+}
+
+input::input():
+ id_(0),
+ file_(0)
+{
+}
+
+input::~input()
+{
+ stop();
+}
+
+void input::stop()
+{
+ if(file_)
+ {
+ XtRemoveInput(id_);
+ file_ = 0;
+ }
+}
+
+void input::start(FILE* f)
+{
+ if(file_ == 0)
+ {
+ file_ = f;
+ id_ = XtAppAddInput(app_context,fileno(f),
+ XtPointer(XtInputReadMask),
+ inputCB,this);
+ }
+}
+
diff --git a/view/src/input.h b/view/src/input.h
new file mode 100644
index 0000000..07b31d8
--- /dev/null
+++ b/view/src/input.h
@@ -0,0 +1,127 @@
+#ifndef input_H
+#define input_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include <Xm/Xm.h>
+
+// Headers
+// #ifndef machine_H
+// #include <machine.h>
+// #endif
+
+// Forward declarations
+
+// class ostream;
+// typedef class _Pvts os_typespec; // Remove if not persistant
+
+
+//
+
+#include <stdio.h>
+
+class input {
+public:
+
+// -- Exceptions
+ // None
+
+// -- Contructors
+
+ input();
+
+// -- Destructor
+
+ virtual ~input(); // Change to virtual if base class
+
+// -- Convertors
+ // None
+
+// -- Operators
+ // None
+
+// -- Methods
+ // None
+
+ void start(FILE*);
+ void stop();
+
+ virtual void ready(const char*) = 0;
+ virtual void done(FILE*) = 0;
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+ // Uncomment for persistent, remove otherwise
+ // static os_typespec* get_os_typespec();
+
+protected:
+
+// -- Members
+
+
+// -- Methods
+
+ // void print(ostream&) const; // Change to virtual if base class
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+private:
+
+// No copy allowed
+
+ input(const input&);
+ input& operator=(const input&);
+
+// -- Members
+
+ XtInputId id_;
+ FILE* file_;
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+
+// -- Class methods
+ // None
+ static void inputCB(XtPointer,int*,XtInputId*);
+
+// -- Friends
+
+ //friend ostream& operator<<(ostream& s,const input& p)
+ // { p.print(s); return s; }
+
+};
+
+
+#endif
diff --git a/view/src/interface.cc b/view/src/interface.cc
new file mode 100644
index 0000000..d4679c6
--- /dev/null
+++ b/view/src/interface.cc
@@ -0,0 +1,26 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "interface.h"
+#include "gui.h"
+
+interface::interface()
+{
+ gui::set_interface(this);
+}
+
+interface::~interface()
+{
+}
diff --git a/view/src/interface.h b/view/src/interface.h
new file mode 100644
index 0000000..b0c28d6
--- /dev/null
+++ b/view/src/interface.h
@@ -0,0 +1,55 @@
+#ifndef interface_H
+#define interface_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include <Xm/Xm.h>
+#include <string>
+
+class interface {
+public:
+
+ interface();
+
+ ~interface(); // Change to virtual if base class
+
+ virtual void clear() = 0;
+ virtual void message(const char*) = 0;
+ virtual void watch(Boolean) = 0;
+
+ virtual void add_host(const std::string&) = 0;
+ virtual void remove_host(const std::string&) = 0;
+ virtual void rename_host(const std::string&,const std::string&) = 0;
+
+ virtual void login(const char*) = 0;
+ virtual void logout(const char*) = 0;
+
+ virtual Widget top_shell() = 0;
+ virtual Widget trees() = 0;
+ virtual Widget windows() = 0;
+
+ virtual bool visible() { return top_shell() != 0; }
+ virtual void error(const char*) = 0;
+private:
+
+ interface(const interface&);
+ interface& operator=(const interface&);
+
+};
+
+inline void destroy(interface**) {}
+
+#endif
diff --git a/view/src/job.cc b/view/src/job.cc
new file mode 100644
index 0000000..ad0f26b
--- /dev/null
+++ b/view/src/job.cc
@@ -0,0 +1,61 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #8 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "job.h"
+#include "node.h"
+#include "host.h"
+#include "ecf_node.h"
+#include <Xm/Text.h>
+extern "C" {
+#include "xec.h"
+}
+
+job::job(panel_window& w):
+ panel(w),
+ text_window(false)
+{
+}
+
+job::~job()
+{
+}
+
+void job::clear()
+{
+ XmTextSetString(name_,"");
+ text_window::clear();
+}
+
+void job::show(node& n)
+{
+ const std::string& job = n.__node__() ?
+ n.variable("ECF_JOB") : n.variable("SMSJOB");
+ XmTextSetString(name_, (char*) job.c_str());
+ load(n.serv().job(n));
+}
+
+Boolean job::enabled(node& n)
+{
+ if (n.type() != NODE_TASK && n.type() != NODE_ALIAS) return False;
+ const std::string& job = n.__node__() ?
+ n.variable("ECF_JOB") : n.variable("SMSJOB");
+ return job.size() > 7;
+}
+
+void job::create (Widget parent, char *widget_name )
+{
+ job_form_c::create(parent,widget_name);
+}
+
diff --git a/view/src/job.h b/view/src/job.h
new file mode 100644
index 0000000..8500a4f
--- /dev/null
+++ b/view/src/job.h
@@ -0,0 +1,65 @@
+#ifndef job_H
+#define job_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "uijob.h"
+
+#ifndef panel_H
+#include "panel.h"
+#endif
+
+#ifndef text_window_H
+#include "text_window.h"
+#endif
+
+class job : public panel, public job_form_c, public text_window {
+public:
+
+ job(panel_window&);
+
+ ~job(); // Change to virtual if base class
+
+ virtual const char* name() const { return "Job"; }
+ virtual void show(node&);
+ virtual Boolean enabled(node&);
+ virtual void clear();
+ virtual Widget widget() { return job_form_c::xd_rootwidget(); }
+
+ virtual Widget tools() { return tools_; }
+ virtual Widget text() { return text_; }
+ virtual void create (Widget parent, char *widget_name = 0 );
+
+private:
+
+ job(const job&);
+ job& operator=(const job&);
+
+ virtual void externalCB(Widget ,XtPointer )
+ { text_window::open_viewer();}
+
+ virtual void searchCB(Widget ,XtPointer )
+ { text_window::open_search();}
+
+ virtual bool can_print() { return true; }
+ virtual bool can_save() { return true; }
+ virtual void print() { text_window::print(); }
+ virtual void save() { text_window::save(); }
+};
+
+inline void destroy(job**) {}
+
+#endif
diff --git a/view/src/jobcheck_panel.cc b/view/src/jobcheck_panel.cc
new file mode 100644
index 0000000..3dd0068
--- /dev/null
+++ b/view/src/jobcheck_panel.cc
@@ -0,0 +1,93 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #9 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "jobcheck_panel.h"
+#include "node.h"
+#include "host.h"
+#include <Xm/Text.h>
+extern "C" {
+#include "xec.h"
+}
+
+static const std::string cmd_str_ecf = "ECF_CHECK_CMD";
+static const std::string cmd_str_sms = "SMS_CHECK_CMD";
+
+jobcheck_panel::jobcheck_panel(panel_window& w):
+ panel(w),
+ text_window(false)
+{
+}
+
+jobcheck_panel::~jobcheck_panel()
+{
+}
+
+void jobcheck_panel::clear()
+{
+ text_window::clear();
+}
+
+void jobcheck_panel::show(node& n)
+{
+ const std::string& cmd = n.__node__() ? cmd_str_ecf : cmd_str_sms;
+ const char* p = n.variable(cmd).c_str();
+
+ if(p)
+ XmTextSetString(name_,(char*)p);
+ else
+ XmTextSetString(name_,(char*)"");
+
+ if (n.type() != NODE_TASK && n.type() != NODE_ALIAS)
+ return;
+ if (n.status() != STATUS_SUBMITTED &&
+ n.status() != STATUS_ACTIVE &&
+ n.status() != STATUS_SUSPENDED)
+ return;
+ tmp_file f = n.serv().jobcheck(n, cmd);
+ text_window::load(f);
+}
+
+Boolean jobcheck_panel::enabled(node& n)
+{
+ if (n.type() != NODE_TASK && n.type() != NODE_ALIAS) return False;
+ if (n.status() != STATUS_SUBMITTED && n.status() != STATUS_ACTIVE)
+ return False;
+ const std::string& cmd = n.__node__() ? cmd_str_ecf : cmd_str_sms;
+ return n.variable(cmd).size() > 7;
+}
+
+void jobcheck_panel::create (Widget parent, char *widget_name )
+{
+ jobcheck_form_c::create(parent,widget_name);
+}
+
+void jobcheck_panel::update()
+{
+}
+
+void jobcheck_panel::changed(node &)
+{
+ clear();
+}
+
+void jobcheck_panel::refresh()
+{
+ node* n = get_node();
+ if(n)
+ show(*n);
+ else
+ clear();
+}
+
diff --git a/view/src/jobcheck_panel.h b/view/src/jobcheck_panel.h
new file mode 100644
index 0000000..7fe9f8b
--- /dev/null
+++ b/view/src/jobcheck_panel.h
@@ -0,0 +1,66 @@
+#ifndef jobcheck_panel_H
+#define jobcheck_panel_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "uijobcheck.h"
+
+#ifndef panel_H
+#include "panel.h"
+#endif
+
+#ifndef text_window_H
+#include "text_window.h"
+#endif
+
+class jobcheck_panel : public panel
+ , public jobcheck_form_c
+ , public text_window
+{
+public:
+ jobcheck_panel(panel_window&);
+
+ ~jobcheck_panel(); // Change to virtual if base class
+
+ void refresh();
+
+ virtual const char* name() const { return "Check"; }
+ virtual void show(node&);
+ virtual Boolean enabled(node&);
+ virtual void clear();
+ virtual Widget widget() { return jobcheck_form_c::xd_rootwidget(); }
+ virtual Widget tools() { return tools_; }
+ virtual Widget text() { return text_; }
+ virtual void create (Widget parent, char *widget_name = 0 );
+
+private:
+
+ jobcheck_panel(const jobcheck_panel&);
+ jobcheck_panel& operator=(const jobcheck_panel&);
+
+ virtual void update();
+ virtual void changed(node&);
+
+ virtual void refreshCB(Widget, XtPointer ) { refresh();}
+
+ virtual bool can_print() { return true; }
+ virtual bool can_save() { return true; }
+ virtual void print() { text_window::print(); }
+ virtual void save() { text_window::save(); }
+};
+
+inline void destroy(jobcheck_panel**) {}
+#endif
diff --git a/view/src/jobstatus.cc b/view/src/jobstatus.cc
new file mode 100644
index 0000000..7d7756c
--- /dev/null
+++ b/view/src/jobstatus.cc
@@ -0,0 +1,109 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #13 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "jobstatus.h"
+#include "node.h"
+#include "host.h"
+#include <Xm/Text.h>
+#include "ecf_node.h"
+extern "C" {
+#include "xec.h"
+}
+
+static const std::string cmd_str_ecf = "ECF_STATUS_CMD";
+static const std::string cmd_str_sms = "SMSSTATUSCMD";
+
+jobstatus::jobstatus(panel_window& w):
+ panel(w),
+ text_window(false)
+ , reload_(true)
+{
+}
+
+jobstatus::~jobstatus()
+{
+}
+
+void jobstatus::clear()
+{
+ XmTextSetString(name_,(char*)"");
+ text_window::clear();
+}
+
+void jobstatus::show(node& n)
+{
+ ecf_node* ecf = n.__node__();
+ const std::string& scmd = ecf ? cmd_str_ecf : cmd_str_sms;
+ const std::string var = n.variable(scmd, true);
+ const std::string& job = ecf ? n.variable("ECF_JOB") : n.variable("SMSJOB");
+
+ // const char *p = var.c_str();
+ // const std::string cmd = (ecf && p) ? ecf->substitute(var) : var;
+ std::string stat = job + ".stat";
+
+ if (!var.empty())
+ XmTextSetString(name_,(char*)var.c_str());
+ else if(!scmd.empty())
+ XmTextSetString(name_,(char*)scmd.c_str());
+ else {
+ std::string cmd = scmd + "%s variable does not exist";
+ XmTextSetString(name_,(char*)cmd.c_str());
+ }
+ if (n.type() != NODE_TASK && n.type() != NODE_ALIAS) {
+ XmTextSetString(name_,(char*)"not a task");
+ return;
+ }
+ if (n.status() != STATUS_SUBMITTED &&
+ n.status() != STATUS_ACTIVE &&
+ n.status() != STATUS_SUSPENDED) {
+ XmTextSetString(name_,(char*)"not submitted not active");
+ return;
+ }
+ if (reload_) { reload_ = false; ;
+ tmp_file (n.serv().jobstatus(n, ""));
+ }
+ tmp_file f (stat.c_str(), false);
+ text_window::load(f);
+}
+
+void jobstatus::updateCB(Widget,XtPointer data)
+{
+ reload_ = true;
+ if(get_node())
+ show(*get_node());
+ else
+ clear();
+ XmTextShowPosition(text_,XmTextGetLastPosition(text_));
+}
+
+Boolean jobstatus::enabled(node& n)
+{
+
+ if (n.type() != NODE_TASK && n.type() != NODE_ALIAS)
+ return False;
+
+ if (n.status() != STATUS_SUBMITTED &&
+ n.status() != STATUS_ACTIVE &&
+ n.status() != STATUS_SUSPENDED)
+ return False;
+
+ const std::string& cmd = n.__node__() ? cmd_str_ecf : cmd_str_sms;
+ return n.variable(cmd).size() > 6;
+}
+
+void jobstatus::create (Widget parent, char *widget_name )
+{
+ jobstatus_form_c::create(parent,widget_name);
+}
diff --git a/view/src/jobstatus.h b/view/src/jobstatus.h
new file mode 100644
index 0000000..5a04d01
--- /dev/null
+++ b/view/src/jobstatus.h
@@ -0,0 +1,71 @@
+#ifndef jobstatus_H
+#define jobstatus_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "uijobstatus.h"
+
+#ifndef panel_H
+#include "panel.h"
+#endif
+
+#ifndef text_window_H
+#include "text_window.h"
+#endif
+
+class jobstatus : public panel
+ , public jobstatus_form_c
+ , public text_window {
+public:
+
+ jobstatus(panel_window&);
+
+ ~jobstatus(); // Change to virtual if base class
+
+ virtual const char* name() const { return "Jobstatus"; }
+ virtual void show(node&);
+ virtual Boolean enabled(node&);
+ virtual void clear();
+ virtual Widget widget() { return jobstatus_form_c::xd_rootwidget(); }
+
+ virtual Widget tools() { return tools_; }
+ virtual Widget text() { return text_; }
+ virtual void create (Widget parent, char *widget_name = 0 );
+
+private:
+
+ jobstatus(const jobstatus&);
+ jobstatus& operator=(const jobstatus&);
+
+ virtual void updateCB(Widget,XtPointer);
+
+ virtual void externalCB(Widget w,XtPointer p)
+ { text_window::open_viewer();}
+
+ virtual void searchCB(Widget w,XtPointer p)
+ { text_window::open_search();}
+
+ virtual bool can_print() { return true; }
+ virtual bool can_save() { return true; }
+ virtual void print() { text_window::print(); }
+ virtual void save() { text_window::save(); }
+
+ int reload_;
+};
+
+inline void destroy(jobstatus**) {}
+
+#endif
diff --git a/view/src/label.cc b/view/src/label.cc
new file mode 100644
index 0000000..421e992
--- /dev/null
+++ b/view/src/label.cc
@@ -0,0 +1,94 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #15 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+#include <boost/algorithm/string.hpp>
+
+#include "label_node.h"
+#include "show.h"
+#include "text_lister.h"
+
+#ifndef ecf_node_
+#include "ecf_node.h"
+#endif
+
+const Label& label_node::get() {
+ ecf_concrete_node<const Label>* base =
+ dynamic_cast<ecf_concrete_node<const Label>*> (owner_);
+ if (base) return *(base->get());
+ if (parent() && parent()->__node__())
+ return parent()->__node__()->get_label(name());
+ return Label::EMPTY();
+}
+
+xmstring label_node::make_label_tree()
+{
+ return xmstring(name().c_str(),"bold") + xmstring(": ","bold")
+ + xmstring(value());
+}
+
+void label_node::drawNode(Widget w,XRectangle* r,bool)
+{
+ std::string msg = value();
+ boost::algorithm::to_lower(msg);
+ bool red = std::string::npos != msg.find("error");
+
+ XmStringDraw(XtDisplay(w),XtWindow(w),
+ smallfont(),
+ labelTree(),
+ red ? redGC() : blackGC(),
+ r->x+2,
+ r->y+2,
+ r->width,
+ XmALIGNMENT_BEGINNING, XmSTRING_DIRECTION_L_TO_R, r);
+ shadow(w,r);
+}
+
+void label_node::info(std::ostream& f)
+{
+ node::info(f);
+ f << "\nText:\n";
+ f << "-----\n";
+ f << value();
+ f << "\n\nDefault:\n";
+ f << "-------\n";
+ f << def() << "\n";
+}
+
+void label_node::perlify(FILE* f)
+{
+ perl_member(f,"value", value());
+ perl_member(f,"default",def());
+}
+
+const char* label_node::value()
+{
+ // static bool prb = false; if (prb) return 0x0; prb = true;
+#ifdef BRIDGE
+ if (tree_) return ((sms_label*) tree_)->value;
+#endif
+ const Label& lab = get();
+ if (lab.new_value().empty() || lab.new_value() == "")
+ return def();
+ return lab.new_value().c_str();
+}
+
+const char* label_node::def()
+{
+#ifdef BRIDGE
+ if (tree_) return ((sms_label*) tree_)->def;
+#endif
+ return get().value().c_str();
+}
+
+Boolean label_node::visible() const { return show::want(show::label); }
diff --git a/view/src/label_node.h b/view/src/label_node.h
new file mode 100644
index 0000000..26e1b4d
--- /dev/null
+++ b/view/src/label_node.h
@@ -0,0 +1,53 @@
+#ifndef label_node_H
+#define label_node_H
+
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #9 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "node.h"
+
+class label_node : public node {
+public:
+
+ label_node(host& h,ecf_node* n) : node(h,n) {}
+#ifdef BRIDGE
+ label_node(host& h,sms_node* n, char b) : node(h,n,b) {}
+#endif
+ const char* value();
+ const char* def();
+
+protected:
+
+private:
+
+ label_node(const label_node&);
+ label_node& operator=(const label_node&);
+
+ const Label& get();
+
+ virtual void info(std::ostream&);
+ virtual xmstring make_label_tree();
+ virtual void drawNode(Widget,XRectangle*,bool);
+
+ virtual Boolean visible() const;
+ virtual void triggered(trigger_lister&) {}
+ virtual void triggers(trigger_lister&) {}
+
+ virtual void perlify(FILE*);
+};
+
+inline void destroy(label_node**) {}
+
+#endif
diff --git a/view/src/late.cc b/view/src/late.cc
new file mode 100644
index 0000000..fff896e
--- /dev/null
+++ b/view/src/late.cc
@@ -0,0 +1,32 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "late.h"
+#include "node.h"
+
+
+late::late():
+ node_alert<late>("Late nodes")
+{
+}
+
+late::~late()
+{
+}
+
+bool late::keep(node* n)
+{
+ return n->isLate();
+}
diff --git a/view/src/late.h b/view/src/late.h
new file mode 100644
index 0000000..6704466
--- /dev/null
+++ b/view/src/late.h
@@ -0,0 +1,109 @@
+#ifndef late_H
+#define late_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "node_alert.h"
+
+class node;
+
+class late : public node_alert<late> {
+public:
+
+// -- Exceptions
+ // None
+
+// -- Contructors
+
+ late();
+
+// -- Destructor
+
+ ~late(); // Change to virtual if base class
+
+// -- Convertors
+ // None
+
+// -- Operators
+ // None
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+
+ // Uncomment for persistent, remove otherwise
+ // static os_typespec* get_os_typespec();
+
+protected:
+
+// -- Members
+ // None
+
+// -- Methods
+
+ // void print(ostream&) const; // Change to virtual if base class
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+private:
+
+// No copy allowed
+
+ late(const late&);
+ late& operator=(const late&);
+
+// -- Methods
+
+
+// -- Overridden methods
+
+ virtual bool keep(node*);
+
+// -- Class members
+
+
+// -- Class methods
+ // None
+
+// -- Friends
+
+ //friend ostream& operator<<(ostream& s,const late& p)
+ // { p.print(s); return s; }
+
+};
+
+inline void destroy(late**) {}
+
+// If persistent, uncomment, otherwise remove
+//#ifdef _ODI_OSSG_
+//OS_MARK_SCHEMA_TYPE(late);
+//#endif
+
+#endif
diff --git a/view/src/late_node.cc b/view/src/late_node.cc
new file mode 100644
index 0000000..85ab116
--- /dev/null
+++ b/view/src/late_node.cc
@@ -0,0 +1,29 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "late_node.h"
+
+xmstring late_node::make_label_tree()
+{
+ if (!owner_) return xmstring("late: ","bold") + xmstring(label_.c_str());
+ return xmstring(label_.c_str());
+}
+
+void late_node::perlify(FILE* f)
+{
+ perl_member(f,"value",label_.c_str());
+}
+
+const std::string& late_node::name() const { return label_; }
diff --git a/view/src/late_node.h b/view/src/late_node.h
new file mode 100644
index 0000000..b38cd82
--- /dev/null
+++ b/view/src/late_node.h
@@ -0,0 +1,49 @@
+#ifndef LATE_NODE_H
+#define LATE_NODE_H
+
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #11 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "node.h"
+#include "show.h"
+
+class late_node : public node {
+
+ virtual bool is_my_parent(node*) const { return false; }
+ virtual void info(std::ostream&) {}
+
+ virtual xmstring make_label_tree();
+
+ virtual const std::string& name() const;
+ virtual const std::string& full_name() const { return name(); }
+ virtual Boolean menus() { return False; }
+ virtual Boolean selectable() { return False; }
+
+ virtual Boolean visible() const {
+ return show::want(show::late); }
+
+ virtual void perlify(FILE* f);
+
+public:
+ late_node(host& h,ecf_node* n) : node(h,n), label_(n ? n->toString() : "late") {}
+#ifdef BRIDGE
+ late_node(host& h,sms_node* n, char b);
+#endif
+
+protected:
+ const std::string label_;
+};
+
+#endif
diff --git a/view/src/layout.cc b/view/src/layout.cc
new file mode 100644
index 0000000..eaac0c1
--- /dev/null
+++ b/view/src/layout.cc
@@ -0,0 +1,26 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "layout.h"
+
+layout::layout(trigger_panel& o,Widget w):
+ widget_(w),
+ owner_(o)
+{
+}
+
+layout::~layout()
+{
+}
diff --git a/view/src/layout.h b/view/src/layout.h
new file mode 100644
index 0000000..f35394b
--- /dev/null
+++ b/view/src/layout.h
@@ -0,0 +1,134 @@
+#ifndef layout_H
+#define layout_H
+
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+// Headers
+// #ifndef machine_H
+// #include <machine.h>
+// #endif
+
+// Forward declarations
+
+// class ostream;
+// typedef class _Pvts os_typespec; // Remove if not persistant
+
+//
+
+#include <Xm/Xm.h>
+
+class node;
+class trigger_panel;
+
+class layout {
+public:
+
+// -- Exceptions
+ // None
+
+// -- Contructors
+
+ layout(trigger_panel&,Widget);
+
+// -- Destructor
+
+ virtual ~layout(); // Change to virtual if base class
+
+// -- Convertors
+ // None
+
+// -- Operators
+ // None
+
+// -- Methods
+
+ virtual void clear() = 0;
+ virtual void show(node&) = 0 ;
+ virtual void reach(node*,node*) = 0;
+ virtual void selectNode(node*) {}
+
+ trigger_panel& owner() { return owner_; }
+ Widget layout_widget() { return widget_; }
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+ // Uncomment for persistent, remove otherwise
+ // static os_typespec* get_os_typespec();
+
+protected:
+
+// -- Members
+
+ Widget widget_;
+ trigger_panel& owner_;
+
+// -- Methods
+
+ // void print(ostream&) const; // Change to virtual if base class
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+private:
+
+// No copy allowed
+
+ layout(const layout&);
+ layout& operator=(const layout&);
+
+// -- Members
+ // None
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+// -- Friends
+
+ //friend ostream& operator<<(ostream& s,const layout& p)
+ // { p.print(s); return s; }
+
+};
+
+inline void destroy(layout**) {}
+
+// If persistent, uncomment, otherwise remove
+//#ifdef _ODI_OSSG_
+//OS_MARK_SCHEMA_TYPE(layout);
+//#endif
+
+#endif
diff --git a/view/src/lexyacc.h b/view/src/lexyacc.h
new file mode 100644
index 0000000..1bdc9aa
--- /dev/null
+++ b/view/src/lexyacc.h
@@ -0,0 +1,70 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #5 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include <Xm/Xm.h>
+#include "SimpleTime.h"
+
+typedef struct _flags flags;
+typedef struct _menu menu;
+typedef struct _item item;
+typedef struct _action action;
+typedef struct _node node;
+
+#ifdef hpux
+/* hpux X11 headers are wromg */
+#undef bcopy
+#undef bzero
+#undef bcmp
+#endif
+
+int menus_version(int rel, int maj, int min);
+menu* menus_chain_menus(menu *a,menu *b);
+item* menus_chain_items(item *a,item *b);
+void menus_root(menu *m);
+menu* menus_create_2(char* a,item* b);
+item* menus_create_6(flags* a,flags* b,char* c,action* d,char* e,int f);
+
+action* menus_command(char* a);
+action* menus_window(char* a);
+action* menus_separator();
+action* menus_sub_menu();
+
+flags* new_flagNone();
+flags* new_typeFlag(int a);
+flags* new_flagNot(flags* a);
+flags* new_flagOr(flags* a,flags* b);
+flags* new_flagAnd(flags* a,flags* b);
+
+flags* new_flagAll();
+flags* new_eventFlag(int a);
+flags* new_selectionFlag();
+flags* new_statusFlag(int a);
+flags* new_userFlag(int a);
+
+flags* new_procFlag_node_hasTriggers();
+flags* new_procFlag_node_hasDate();
+flags* new_procFlag_node_hasTime();
+flags* new_procFlag_node_hasText();
+flags* new_procFlag_node_isMigrated();
+flags* new_procFlag_node_isLocked();
+flags* new_procFlag_node_isZombie();
+
+action* menus_internal_host_plug();
+action* menus_internal_host_compare(char*a, char*b);
+
+void log_event_meter_event(DateTime* a,node* b,int c);
+void log_event_event_event(DateTime* a,node* b,int c);
+void log_event_status_event(DateTime* a,node* b,int c);
+node *log_event_find(char* a);
diff --git a/view/src/libicon/icon_Apply.cc b/view/src/libicon/icon_Apply.cc
new file mode 100644
index 0000000..267a187
--- /dev/null
+++ b/view/src/libicon/icon_Apply.cc
@@ -0,0 +1,42 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #5 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 6 1",
+" c #E79DE79DE79D",
+". c #0000EFBE0000",
+"X c #0000FFFF0000",
+"o c #000000000000",
+"O c #FFFFFFFFFFFF",
+"+ c #00008A280000",
+" ",
+" ",
+" ",
+" ",
+" .... ",
+" .XXXXo ",
+" .XOXXXX+ ",
+" .XXXXXX+ ",
+" .XXXXXX+ ",
+" .XXXXXX+ ",
+" +XXXX+ ",
+" ++++ ",
+" ",
+" ",
+" ",
+" "};
+static pixmap p("Apply",(const char**)bits);
diff --git a/view/src/libicon/icon_Apply.xpm b/view/src/libicon/icon_Apply.xpm
new file mode 100644
index 0000000..9b5d0b3
--- /dev/null
+++ b/view/src/libicon/icon_Apply.xpm
@@ -0,0 +1,40 @@
+/* XPM */
+static char * Apply_xpm[] = {
+"16 16 6 1",
+" c #E79DE79DE79D",
+". c #0000EFBE0000",
+"X c #0000FFFF0000",
+"o c #000000000000",
+"O c #FFFFFFFFFFFF",
+"+ c #00008A280000",
+" ",
+" ",
+" ",
+" ",
+" .... ",
+" .XXXXo ",
+" .XOXXXX+ ",
+" .XXXXXX+ ",
+" .XXXXXX+ ",
+" .XXXXXX+ ",
+" +XXXX+ ",
+" ++++ ",
+" ",
+" ",
+" ",
+" "};
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #4 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
diff --git a/view/src/libicon/icon_Chat.cc b/view/src/libicon/icon_Chat.cc
new file mode 100644
index 0000000..865b707
--- /dev/null
+++ b/view/src/libicon/icon_Chat.cc
@@ -0,0 +1,41 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #8 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 5 1",
+" c None",
+". c #E7E7E7",
+"+ c #000000",
+"@ c #CECECE",
+"# c #808080",
+"................",
+"...........++...",
+"..........+@@+..",
+".........+@@@+..",
+"........+@@@@@+.",
+"........+@@@@@+.",
+".........+@@@@+.",
+"..........+@@@+.",
+"...........+@#+.",
+"...++.....+@@+..",
+"..+@@+...+@@#+..",
+".+@@@@+.+@@#+...",
+"+#@@@@@+@@#+....",
+"+###@@@@##+.....",
+".++#####++......",
+"...+++++........"};
+static pixmap p("Chat",(const char**)bits);
diff --git a/view/src/libicon/icon_Chat.xpm b/view/src/libicon/icon_Chat.xpm
new file mode 100644
index 0000000..1e5faf1
--- /dev/null
+++ b/view/src/libicon/icon_Chat.xpm
@@ -0,0 +1,39 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * Chat_xpm[] = {
+"16 16 5 1",
+" c #E7E7E7E7E7E7",
+". c #000000000000",
+"X c #CECECECECECE",
+"o c #7B7B7B7B7B7B",
+"O c #8C8C8C8C8C8C",
+" ",
+" .. ",
+" . . ",
+" .XX . ",
+" .XXXX . ",
+" .oXXX . ",
+" .oXX . ",
+" ..X . ",
+" .X . ",
+" .. . X. ",
+" . . . XX. ",
+" .XXXX. . XX. ",
+".oXXXX..XXX. ",
+".OOXXXXXXX. ",
+" ..oOoXX.. ",
+" ..... "};
diff --git a/view/src/libicon/icon_Check.cc b/view/src/libicon/icon_Check.cc
new file mode 100644
index 0000000..deeafac
--- /dev/null
+++ b/view/src/libicon/icon_Check.cc
@@ -0,0 +1,71 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #5 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 35 1",
+" c None",
+". c #E7E7E7",
+"+ c #C1C1C1",
+"@ c #959595",
+"# c #CECECE",
+"$ c #808080",
+"% c #D6D6D6",
+"& c #7E7E7E",
+"* c #C5C5C5",
+"= c #D4D4D4",
+"- c #7A7A7A",
+"; c #DDDDDD",
+"> c #C6C6C6",
+", c #E5E5E5",
+"' c #A0A0A0",
+") c #AEAEAE",
+"! c #B3B3B3",
+"~ c #939393",
+"{ c #D2D2D2",
+"] c #9E9E9E",
+"^ c #DBDBDB",
+"/ c #DFDFDF",
+"( c #8B8B8B",
+"_ c #B5B5B5",
+": c #999999",
+"< c #B7B7B7",
+"[ c #DADADA",
+"} c #E1E1E1",
+"| c #767676",
+"1 c #D8D8D8",
+"2 c #C3C3C3",
+"3 c #B1B1B1",
+"4 c #AAAAAA",
+"5 c #828282",
+"6 c #B9B9B9",
+"................",
+".............+ at .",
+"............#$%.",
+"...........#&*..",
+"..........=-*...",
+".........;$>....",
+"........,').....",
+"........!~,.....",
+"{]*....=&^......",
+"/+(_...:<.......",
+"..[$>.;&}.......",
+"...#|12'........",
+"....345#........",
+"..../$(.........",
+".....6>.........",
+"................"};
+static pixmap p("Check",(const char**)bits);
diff --git a/view/src/libicon/icon_Check.xpm b/view/src/libicon/icon_Check.xpm
new file mode 100644
index 0000000..2b5a338
--- /dev/null
+++ b/view/src/libicon/icon_Check.xpm
@@ -0,0 +1,69 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * icon_Check_xpm[] = {
+"16 16 35 1",
+" c None",
+". c #E7E7E7",
+"+ c #C1C1C1",
+"@ c #959595",
+"# c #CECECE",
+"$ c #808080",
+"% c #D6D6D6",
+"& c #7E7E7E",
+"* c #C5C5C5",
+"= c #D4D4D4",
+"- c #7A7A7A",
+"; c #DDDDDD",
+"> c #C6C6C6",
+", c #E5E5E5",
+"' c #A0A0A0",
+") c #AEAEAE",
+"! c #B3B3B3",
+"~ c #939393",
+"{ c #D2D2D2",
+"] c #9E9E9E",
+"^ c #DBDBDB",
+"/ c #DFDFDF",
+"( c #8B8B8B",
+"_ c #B5B5B5",
+": c #999999",
+"< c #B7B7B7",
+"[ c #DADADA",
+"} c #E1E1E1",
+"| c #767676",
+"1 c #D8D8D8",
+"2 c #C3C3C3",
+"3 c #B1B1B1",
+"4 c #AAAAAA",
+"5 c #828282",
+"6 c #B9B9B9",
+"................",
+".............+ at .",
+"............#$%.",
+"...........#&*..",
+"..........=-*...",
+".........;$>....",
+"........,').....",
+"........!~,.....",
+"{]*....=&^......",
+"/+(_...:<.......",
+"..[$>.;&}.......",
+"...#|12'........",
+"....345#........",
+"..../$(.........",
+".....6>.........",
+"................"};
diff --git a/view/src/libicon/icon_Edit.cc b/view/src/libicon/icon_Edit.cc
new file mode 100644
index 0000000..90b80c9
--- /dev/null
+++ b/view/src/libicon/icon_Edit.cc
@@ -0,0 +1,47 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #8 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 11 1",
+" c None",
+". c #E7E7E7",
+"+ c #000000",
+"@ c #5F5F5F",
+"# c #FFFFFF",
+"$ c #DFDFDF",
+"% c #FF0000",
+"& c #A0A09C",
+"* c #FFEB00",
+"= c #EDDA00",
+"- c #7B7B7B",
+".......++ at ......",
+"......@##+......",
+".....@##+.......",
+"....@##+#+$...%%",
+"...@##+###+..&%%",
+"..++++##..#+&*=&",
+"..+-###.##.&*=&.",
+"..+###.##.&*=&..",
+"...+####.&*=&+..",
+"....+##.&*=&#+..",
+".....+##+=&#+...",
+"......+#+&#+....",
+".......+##+.....",
+"......-+#+......",
+".....--++.......",
+"......++........"};
+static pixmap p("Edit",(const char**)bits);
diff --git a/view/src/libicon/icon_Edit.xpm b/view/src/libicon/icon_Edit.xpm
new file mode 100644
index 0000000..63cc675
--- /dev/null
+++ b/view/src/libicon/icon_Edit.xpm
@@ -0,0 +1,43 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * Edit_xpm[] = {
+"16 16 9 1",
+" c #E7E7E7E7E7E7",
+". c #000000000000",
+"X c #FFFFFFFFFFFF",
+"o c #CECECECECECE",
+"O c #8C8C8C8C8C8C",
+"+ c #FFFF73739494",
+"@ c #FFFFFFFF0000",
+"# c #BDBDB5B5B5B5",
+"$ c #FFFFCECE9C9C",
+" ... ",
+" .XXo. ..",
+" .XXoO. .+.",
+" .XXoO. . at . ",
+" .XXoO.O.... at . ",
+"...oO.O#.$. at . ",
+".OO..O#.$. at .$. ",
+".Oo.O#o.....$$..",
+" .Xo o .$$$$$$..",
+" .Xo ....$$$$..",
+" .Xo.Xo#......",
+" .Xoo#. ..",
+" ...o#. ",
+" .O#.#. ",
+" .#o.. ",
+" ... "};
diff --git a/view/src/libicon/icon_Info.cc b/view/src/libicon/icon_Info.cc
new file mode 100644
index 0000000..7753be9
--- /dev/null
+++ b/view/src/libicon/icon_Info.cc
@@ -0,0 +1,40 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #8 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 4 1",
+" c None",
+". c #E7E7E7",
+"+ c #ABF0FF",
+"@ c #0000FF",
+"................",
+"................",
+".......+ at +......",
+".......@@@......",
+".......+ at +......",
+"................",
+"......@@@@......",
+".......@@@......",
+".......@@@......",
+".......@@@......",
+".......@@@......",
+".......@@@......",
+"......@@@@@.....",
+"................",
+"................",
+"................"};
+static pixmap p("Info",(const char**)bits);
diff --git a/view/src/libicon/icon_Info.xpm b/view/src/libicon/icon_Info.xpm
new file mode 100644
index 0000000..48dd952
--- /dev/null
+++ b/view/src/libicon/icon_Info.xpm
@@ -0,0 +1,39 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * Info_xpm[] = {
+"16 16 5 1",
+" c #E7E7E7E7E7E7",
+". c #00000000FFFF",
+"X c #BDBDB5B5B5B5",
+"o c #7B7B7B7B7B7B",
+"O c #8C8C8C8C8C8C",
+" ",
+" ",
+" .X ",
+" ...o ",
+" .O ",
+" o ",
+" .... ",
+" ...o ",
+" ...O ",
+" ...O ",
+" ...o ",
+" ...O ",
+" .....o ",
+" oOOOO ",
+" ",
+" "};
diff --git a/view/src/libicon/icon_Jobstatus.cc b/view/src/libicon/icon_Jobstatus.cc
new file mode 100644
index 0000000..c15f9ff
--- /dev/null
+++ b/view/src/libicon/icon_Jobstatus.cc
@@ -0,0 +1,41 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #5 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 5 1",
+" c None",
+". c #000000",
+"+ c #0000FF",
+"@ c #00FF00",
+"# c #FF0000",
+"................",
+".+++++++@@@@###.",
+".+++++++@@@@###.",
+".+++++++@@@@###.",
+".+++++++@@@@###.",
+"................",
+".+++++++@@#####.",
+".+++++++@@#####.",
+".+++++++@@#####.",
+".+++++++@@#####.",
+"................",
+".+++++++++++###.",
+".+++++++++++###.",
+".+++++++++++###.",
+".+++++++++++###.",
+"................"};
+static pixmap p("Jobstatus",(const char**)bits);
diff --git a/view/src/libicon/icon_Jobstatus.xpm b/view/src/libicon/icon_Jobstatus.xpm
new file mode 100644
index 0000000..11c9b21
--- /dev/null
+++ b/view/src/libicon/icon_Jobstatus.xpm
@@ -0,0 +1,39 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * icon_Josstatus_xpm[] = {
+"16 16 5 1",
+" c None",
+". c #000000",
+"+ c #0000FF",
+"@ c #00FF00",
+"# c #FF0000",
+"................",
+".+++++++@@@@###.",
+".+++++++@@@@###.",
+".+++++++@@@@###.",
+".+++++++@@@@###.",
+"................",
+".+++++++@@#####.",
+".+++++++@@#####.",
+".+++++++@@#####.",
+".+++++++@@#####.",
+"................",
+".+++++++++++###.",
+".+++++++++++###.",
+".+++++++++++###.",
+".+++++++++++###.",
+"................"};
diff --git a/view/src/libicon/icon_Josstatus3.xpm b/view/src/libicon/icon_Josstatus3.xpm
new file mode 100644
index 0000000..11c9b21
--- /dev/null
+++ b/view/src/libicon/icon_Josstatus3.xpm
@@ -0,0 +1,39 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * icon_Josstatus_xpm[] = {
+"16 16 5 1",
+" c None",
+". c #000000",
+"+ c #0000FF",
+"@ c #00FF00",
+"# c #FF0000",
+"................",
+".+++++++@@@@###.",
+".+++++++@@@@###.",
+".+++++++@@@@###.",
+".+++++++@@@@###.",
+"................",
+".+++++++@@#####.",
+".+++++++@@#####.",
+".+++++++@@#####.",
+".+++++++@@#####.",
+"................",
+".+++++++++++###.",
+".+++++++++++###.",
+".+++++++++++###.",
+".+++++++++++###.",
+"................"};
diff --git a/view/src/libicon/icon_Load.cc b/view/src/libicon/icon_Load.cc
new file mode 100644
index 0000000..9f8116d
--- /dev/null
+++ b/view/src/libicon/icon_Load.cc
@@ -0,0 +1,39 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #5 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 4 1",
+" c #E7E7E7E7E7E7",
+". c #E5E5E5E5E5E5",
+"X c #000000000000",
+"o c #FFFFFFFFFFFF",
+" ",
+" ",
+" ...XXXXXXX ",
+" ..XXoooooX ",
+" .XoXoooooX ",
+" XXXXoooooX. ",
+" XooooooooX. ",
+" XooooooooX ",
+" XooooooooX ",
+" XooooooooX ",
+" XooooooooX ",
+" XooooooooX ",
+" XooooooooX ",
+" XXXXXXXXXX ",
+" ",
+" "};
+static pixmap p("Load",(const char**)bits);
diff --git a/view/src/libicon/icon_Load.xpm b/view/src/libicon/icon_Load.xpm
new file mode 100644
index 0000000..1cc18d0
--- /dev/null
+++ b/view/src/libicon/icon_Load.xpm
@@ -0,0 +1,38 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * Load_xpm[] = {
+"16 16 4 1",
+" c #E7E7E7E7E7E7",
+". c #E5E5E5E5E5E5",
+"X c #000000000000",
+"o c #FFFFFFFFFFFF",
+" ",
+" ",
+" ...XXXXXXX ",
+" ..XXoooooX ",
+" .XoXoooooX ",
+" XXXXoooooX. ",
+" XooooooooX. ",
+" XooooooooX ",
+" XooooooooX ",
+" XooooooooX ",
+" XooooooooX ",
+" XooooooooX ",
+" XooooooooX ",
+" XXXXXXXXXX ",
+" ",
+" "};
diff --git a/view/src/libicon/icon_Manual.cc b/view/src/libicon/icon_Manual.cc
new file mode 100644
index 0000000..e996106
--- /dev/null
+++ b/view/src/libicon/icon_Manual.cc
@@ -0,0 +1,56 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #5 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 20 1",
+" c #E7E7E7E7E7E7",
+". c #CECECECECECE",
+"X c #BDBDB5B5B5B5",
+"o c #94949C9C9C9C",
+"O c #73738C8C7B7B",
+"+ c #5A5A73736363",
+"@ c #42425A5A4A4A",
+"# c #EFEFC6C6CECE",
+"$ c #C6C69C9CA5A5",
+"% c #9C9C73737B7B",
+"& c #737342425252",
+"* c #7B7B7B7B7B7B",
+"= c #4A4A5A5A5A5A",
+"- c #52525A5A5A5A",
+"; c #84848C8C8C8C",
+": c #A5A584848C8C",
+"> c #B5B58C8C9494",
+", c #DEDEDEDEDEDE",
+"< c #A5A5A5A5A5A5",
+"1 c #A5A57B7B8484",
+" .XoO+@ ",
+"#$%& .XoO+@ ",
+"#$%& .X+O+@ .o*=",
+"#%%& .X-O+@ .;*-",
+"#%%& .X-O+@ X=;=",
+"#:%& .X=O+@ .@*=",
+"#:%& .X=O+@ .@*=",
+"#%%& .X+O+@ X@*-",
+"#*%& .X;;+@ .-*=",
+"#>%& .X;O+@ .;*=",
+"#>%& .XoO+@ .o*=",
+"#$%& .XoO+@,.<*=",
+"#$%& .XoO+@ .o*=",
+"#>%& .<;O+@ .;*=",
+"#1%& .XOO+@ .+*=",
+"#:%& .Xo;+@,.;*="};
+static pixmap p("Manual",(const char**)bits);
diff --git a/view/src/libicon/icon_Manual.xpm b/view/src/libicon/icon_Manual.xpm
new file mode 100644
index 0000000..4843186
--- /dev/null
+++ b/view/src/libicon/icon_Manual.xpm
@@ -0,0 +1,54 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * Manual_xpm[] = {
+"16 16 20 1",
+" c #E7E7E7E7E7E7",
+". c #CECECECECECE",
+"X c #BDBDB5B5B5B5",
+"o c #94949C9C9C9C",
+"O c #73738C8C7B7B",
+"+ c #5A5A73736363",
+"@ c #42425A5A4A4A",
+"# c #EFEFC6C6CECE",
+"$ c #C6C69C9CA5A5",
+"% c #9C9C73737B7B",
+"& c #737342425252",
+"* c #7B7B7B7B7B7B",
+"= c #4A4A5A5A5A5A",
+"- c #52525A5A5A5A",
+"; c #84848C8C8C8C",
+": c #A5A584848C8C",
+"> c #B5B58C8C9494",
+", c #DEDEDEDEDEDE",
+"< c #A5A5A5A5A5A5",
+"1 c #A5A57B7B8484",
+" .XoO+@ ",
+"#$%& .XoO+@ ",
+"#$%& .X+O+@ .o*=",
+"#%%& .X-O+@ .;*-",
+"#%%& .X-O+@ X=;=",
+"#:%& .X=O+@ .@*=",
+"#:%& .X=O+@ .@*=",
+"#%%& .X+O+@ X@*-",
+"#*%& .X;;+@ .-*=",
+"#>%& .X;O+@ .;*=",
+"#>%& .XoO+@ .o*=",
+"#$%& .XoO+@,.<*=",
+"#$%& .XoO+@ .o*=",
+"#>%& .<;O+@ .;*=",
+"#1%& .XOO+@ .+*=",
+"#:%& .Xo;+@,.;*="};
diff --git a/view/src/libicon/icon_Merge.cc b/view/src/libicon/icon_Merge.cc
new file mode 100644
index 0000000..c76dd77
--- /dev/null
+++ b/view/src/libicon/icon_Merge.cc
@@ -0,0 +1,40 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #5 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 4 1",
+" c #FFFFFFFFFFFF",
+". c #E7E7E7E7E7E7",
+"X c #E5E5E5E5E5E5",
+"o c #000000000000",
+" ...............",
+" ...XXXooooooo..",
+" ...XXoo o..",
+" .XXXoooooo o..",
+" .XXoo o oX.",
+" .Xo o o oX.",
+" .oooo o o..",
+" .o o o..",
+" .o o o..",
+" .o o o..",
+" .o o o..",
+" .o o o..",
+" .o oooo..",
+" .o o.....",
+" ..oooooooo.....",
+" "};
+static pixmap p("Merge",(const char**)bits);
diff --git a/view/src/libicon/icon_Merge.xpm b/view/src/libicon/icon_Merge.xpm
new file mode 100644
index 0000000..6a70f54
--- /dev/null
+++ b/view/src/libicon/icon_Merge.xpm
@@ -0,0 +1,38 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * Merge_xpm[] = {
+"16 16 4 1",
+" c #FFFFFFFFFFFF",
+". c #E7E7E7E7E7E7",
+"X c #E5E5E5E5E5E5",
+"o c #000000000000",
+" ...............",
+" ...XXXooooooo..",
+" ...XXoo o..",
+" .XXXoooooo o..",
+" .XXoo o oX.",
+" .Xo o o oX.",
+" .oooo o o..",
+" .o o o..",
+" .o o o..",
+" .o o o..",
+" .o o o..",
+" .o o o..",
+" .o oooo..",
+" .o o.....",
+" ..oooooooo.....",
+" "};
diff --git a/view/src/libicon/icon_Messages.cc b/view/src/libicon/icon_Messages.cc
new file mode 100644
index 0000000..b4088f2
--- /dev/null
+++ b/view/src/libicon/icon_Messages.cc
@@ -0,0 +1,40 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #8 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 4 1",
+" c None",
+". c #E5E5E5",
+"+ c #000000",
+"@ c #F5F97A",
+"................",
+"................",
+"................",
+"..+++++++++++...",
+"..+@@@@@@@@@+...",
+"..+@@@@@@@@@+...",
+"..+@@@@@@@@@+...",
+"..+@@@@@@@@@+...",
+"..+@@@@@@@@@+...",
+"..+@@@@@@@@@+...",
+"..+@@@@@+++++...",
+"..+@@@@@+@@+....",
+"..+@@@@@+ at +.....",
+"..++++++++......",
+"................",
+"................"};
+static pixmap p("Messages",(const char**)bits);
diff --git a/view/src/libicon/icon_Messages.xpm b/view/src/libicon/icon_Messages.xpm
new file mode 100644
index 0000000..4e78af4
--- /dev/null
+++ b/view/src/libicon/icon_Messages.xpm
@@ -0,0 +1,41 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * message_xpm[] = {
+"16 16 7 1",
+" c #E5E5E5E5E5E5",
+". c #000000000000",
+"X c #C9C9CDCD4C4C",
+"o c #FFFFFFFFFFFF",
+"O c #F5F5F9F97A7A",
+"+ c #545454545454",
+"@ c #98989B9B3838",
+" ",
+" ",
+" ",
+" ........... ",
+" .XXXXXXXXX. ",
+" .XXXXXXXXX. ",
+" .oOOOOOOOO. ",
+" .oOOOOOOOO. ",
+" .oOOOOOOOO. ",
+" .oOOOOOOOO. ",
+" .oOOOX..... ",
+" .oOOXX+OO. ",
+" .oXXX.O at + ",
+" .....++ ",
+" ",
+" "};
diff --git a/view/src/libicon/icon_Output.cc b/view/src/libicon/icon_Output.cc
new file mode 100644
index 0000000..84a7af9
--- /dev/null
+++ b/view/src/libicon/icon_Output.cc
@@ -0,0 +1,45 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #8 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 9 1",
+" c None",
+". c #E7E7E7",
+"+ c #7B7B7B",
+"@ c #000000",
+"# c #CECECE",
+"$ c #DEDEDE",
+"% c #A5A5A5",
+"& c #BDB5B5",
+"* c #949C9C",
+".++++++++++++++.",
+".+............+.",
+".+............+.",
+".+.@#$%%#%%&@.+.",
+".+....##.$$...+.",
+".+.@##%%#..#@.+.",
+".+....$$......+.",
+".+.@#..#$$$#@.+.",
+".+....$%**%#..+.",
+".+.@#..$$$##@.+.",
+".+....$#..$...+.",
+".+.@#$%%$$&&@.+.",
+".+....##$#$...+.",
+".+.@#.$%*%$#@.+.",
+".+............+.",
+".++++++++++++++."};
+static pixmap p("Output",(const char**)bits);
diff --git a/view/src/libicon/icon_Output.xpm b/view/src/libicon/icon_Output.xpm
new file mode 100644
index 0000000..29c8a32
--- /dev/null
+++ b/view/src/libicon/icon_Output.xpm
@@ -0,0 +1,42 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * Output_xpm[] = {
+"16 16 8 1",
+" c #E7E7E7E7E7E7",
+". c #7B7B7B7B7B7B",
+"X c #CECECECECECE",
+"o c #DEDEDEDEDEDE",
+"O c #000000000000",
+"+ c #A5A5A5A5A5A5",
+"@ c #BDBDB5B5B5B5",
+"# c #94949C9C9C9C",
+" .............. ",
+" . XXXXXXXX . ",
+" . Xo Xo . ",
+" . OXo++X++ at O . ",
+" . XX oo . ",
+" . OXX++X XO . ",
+" . oo . ",
+" . OX XoooXO . ",
+" . o+##+X . ",
+" . OX oooXXO . ",
+" . oX o . ",
+" . OXo++oo@@O . ",
+" . XXoXo . ",
+" . OX o+#+oXO . ",
+" . XXX@@@XX . ",
+" .............. "};
diff --git a/view/src/libicon/icon_QuickFind.cc b/view/src/libicon/icon_QuickFind.cc
new file mode 100644
index 0000000..7d7c56d
--- /dev/null
+++ b/view/src/libicon/icon_QuickFind.cc
@@ -0,0 +1,38 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #5 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 2 1",
+" c #E7E7E7E7E7E7",
+". c #000000000000",
+" ",
+" ",
+" ",
+" ",
+" ........ ",
+" ........ ",
+" ...... ",
+" ...... ",
+" .... ",
+" .... ",
+" .. ",
+" .. ",
+" ",
+" ",
+" ",
+" "};
+static pixmap p("QuickFind",(const char**)bits);
diff --git a/view/src/libicon/icon_QuickFind.xpm b/view/src/libicon/icon_QuickFind.xpm
new file mode 100644
index 0000000..ea5dd97
--- /dev/null
+++ b/view/src/libicon/icon_QuickFind.xpm
@@ -0,0 +1,36 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * QuickFind_xpm[] = {
+"16 16 2 1",
+" c #E7E7E7E7E7E7",
+". c #000000000000",
+" ",
+" ",
+" ",
+" ",
+" ........ ",
+" ........ ",
+" ...... ",
+" ...... ",
+" .... ",
+" .... ",
+" .. ",
+" .. ",
+" ",
+" ",
+" ",
+" "};
diff --git a/view/src/libicon/icon_Script.cc b/view/src/libicon/icon_Script.cc
new file mode 100644
index 0000000..3a709eb
--- /dev/null
+++ b/view/src/libicon/icon_Script.cc
@@ -0,0 +1,43 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #8 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 7 1",
+" c None",
+". c #E7E7E7",
+"+ c #000000",
+"@ c #5F5F5F",
+"# c #FFFFFF",
+"$ c #DFDFDF",
+"% c #7B7B7B",
+".......++ at ......",
+"......@##+......",
+".....@##+.......",
+"....@##+#+$.....",
+"...@##+###+.....",
+"..++++##..#+....",
+"..+%###.##.#+...",
+"..+###.##.###+..",
+"...+####.##.#+..",
+"....+##.##.##+..",
+".....+###.##+...",
+"......+#.##+....",
+".......+##+.....",
+"......%+#+......",
+".....%%++.......",
+"......++........"};
+static pixmap p("Script",(const char**)bits);
diff --git a/view/src/libicon/icon_Script.xpm b/view/src/libicon/icon_Script.xpm
new file mode 100644
index 0000000..fd05d03
--- /dev/null
+++ b/view/src/libicon/icon_Script.xpm
@@ -0,0 +1,41 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * Script_xpm[] = {
+"16 16 7 1",
+" c #E79DE79DE79D",
+". c #DF7DDF7DDF7D",
+"X c #000000000000",
+"o c #FFFFFFFFFFFF",
+"O c #CF3CCF3CFFFF",
+"+ c #8A288A288A28",
+"@ c #AAAAAAAAAAAA",
+" .XXX. ",
+" .XooOX ",
+" .XooO+X ",
+" .XooO+X. ",
+" .XooO+X+X. ",
+" XXXO+X++ at X. ",
+" X++XX++O. at X. ",
+" X+OXO+O.Oo+X ",
+" XoO.O.OoO at X ",
+" XoO.OoOO at X ",
+" XoOoOO at X ",
+" XoOO at X ",
+" XXXO at X ",
+" X+ at X@X ",
+" X at OXX ",
+" XXX "};
diff --git a/view/src/libicon/icon_Search.cc b/view/src/libicon/icon_Search.cc
new file mode 100644
index 0000000..f11b6b4
--- /dev/null
+++ b/view/src/libicon/icon_Search.cc
@@ -0,0 +1,49 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #8 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 13 1",
+" c None",
+". c #E7E7E7",
+"+ c #7B7B7B",
+"@ c #000000",
+"# c #4A4239",
+"$ c #8C8C8C",
+"% c #FFFFFF",
+"& c #CECECE",
+"* c #BDB5B5",
+"= c #E8E8E8",
+"- c #C9C7C7",
+"; c #8C5A39",
+"> c #FFCE9C",
+"................",
+"................",
+"....+@##$.......",
+"...++%%%++......",
+"...#%%%%%+&.....",
+"..*+%%%%=+*.....",
+"..*+%%%=-+*.....",
+"...#%===-+&.....",
+"...$#---+$......",
+"....$@#@++*.....",
+".........;;>....",
+"..........;;>...",
+"...........;;*..",
+"............;;..",
+".............&..",
+"................"};
+static pixmap p("Search",(const char**)bits);
diff --git a/view/src/libicon/icon_Search.xpm b/view/src/libicon/icon_Search.xpm
new file mode 100644
index 0000000..f66adbb
--- /dev/null
+++ b/view/src/libicon/icon_Search.xpm
@@ -0,0 +1,45 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * Search_xpm[] = {
+"16 16 11 1",
+" c #E7E7E7E7E7E7",
+". c #7B7B7B7B7B7B",
+"X c #000000000000",
+"o c #4A4A42423939",
+"O c #8C8C8C8C8C8C",
+"+ c #BDBDB5B5B5B5",
+"@ c #CECECECECECE",
+"# c #F7F7EFEFDEDE",
+"$ c #FFFFFFFFFFFF",
+"% c #8C8C5A5A3939",
+"& c #FFFFCECE9C9C",
+" ",
+" ",
+" .XooO ",
+" ..+@@.. ",
+" oO++ .@ ",
+" +.#+@@$.+ ",
+" +.$ @@$.+ ",
+" o $$$@.@ ",
+" Oo+ at +.O ",
+" OXoX..+ ",
+" %%& ",
+" # %%& ",
+" %%+ ",
+" $O& ",
+" #@# ",
+" "};
diff --git a/view/src/libicon/icon_Status.cc b/view/src/libicon/icon_Status.cc
new file mode 100644
index 0000000..cf07d7b
--- /dev/null
+++ b/view/src/libicon/icon_Status.cc
@@ -0,0 +1,50 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #5 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 14 1",
+" c #E7E7E7E7E7E7",
+". c #FFFFFFFFFFFF",
+"X c #FFFFCECE9C9C",
+"o c #FFFF73739494",
+"O c #FFFF29292929",
+"+ c #FFFF00000000",
+"@ c #8C8C5A5A3939",
+"# c #CECECECECECE",
+"$ c #8C8C8C8C8C8C",
+"% c #F7F7EFEFDEDE",
+"& c #000000000000",
+"* c #4A4A42423939",
+"= c #BDBDB5B5B5B5",
+"- c #7B7B7B7B7B7B",
+" ",
+" .XoX ",
+" XO++@# ",
+" X+++++$ ",
+" %++++O&$ ",
+" o+++**$ .o% ",
+"%+++** o+O ",
+" +++*# ++++o ",
+"%O++* +++++++",
+".+++ at . X+++*$",
+" o+++= O++@* ",
+" %O+++ooo++++&$ ",
+" X+++++++++** ",
+" oO++++++**= ",
+" =@@+****# ",
+" .=$-$=. "};
+static pixmap p("Status",(const char**)bits);
diff --git a/view/src/libicon/icon_Status.xpm b/view/src/libicon/icon_Status.xpm
new file mode 100644
index 0000000..94c9861
--- /dev/null
+++ b/view/src/libicon/icon_Status.xpm
@@ -0,0 +1,48 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * Status_xpm[] = {
+"16 16 14 1",
+" c #E7E7E7E7E7E7",
+". c #FFFFFFFFFFFF",
+"X c #FFFFCECE9C9C",
+"o c #FFFF73739494",
+"O c #FFFF29292929",
+"+ c #FFFF00000000",
+"@ c #8C8C5A5A3939",
+"# c #CECECECECECE",
+"$ c #8C8C8C8C8C8C",
+"% c #F7F7EFEFDEDE",
+"& c #000000000000",
+"* c #4A4A42423939",
+"= c #BDBDB5B5B5B5",
+"- c #7B7B7B7B7B7B",
+" ",
+" .XoX ",
+" XO++@# ",
+" X+++++$ ",
+" %++++O&$ ",
+" o+++**$ .o% ",
+"%+++** o+O ",
+" +++*# ++++o ",
+"%O++* +++++++",
+".+++ at . X+++*$",
+" o+++= O++@* ",
+" %O+++ooo++++&$ ",
+" X+++++++++** ",
+" oO++++++**= ",
+" =@@+****# ",
+" .=$-$=. "};
diff --git a/view/src/libicon/icon_Submit.cc b/view/src/libicon/icon_Submit.cc
new file mode 100644
index 0000000..1e326bc
--- /dev/null
+++ b/view/src/libicon/icon_Submit.cc
@@ -0,0 +1,42 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #5 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 6 1",
+" c #E79DE79DE79D",
+". c #0000EFBE0000",
+"X c #0000FFFF0000",
+"o c #000000000000",
+"O c #FFFFFFFFFFFF",
+"+ c #00008A280000",
+" ",
+" ",
+" ",
+" ",
+" .... ",
+" .XXXXo ",
+" .XOXXXX+ ",
+" .XXXXXX+ ",
+" .XXXXXX+ ",
+" .XXXXXX+ ",
+" +XXXX+ ",
+" ++++ ",
+" ",
+" ",
+" ",
+" "};
+static pixmap p("Submit",(const char**)bits);
diff --git a/view/src/libicon/icon_Submit.xpm b/view/src/libicon/icon_Submit.xpm
new file mode 100644
index 0000000..c6511a6
--- /dev/null
+++ b/view/src/libicon/icon_Submit.xpm
@@ -0,0 +1,40 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+* XPM */
+static char * Submit_xpm[] = {
+"16 16 6 1",
+" c #E79DE79DE79D",
+". c #0000EFBE0000",
+"X c #0000FFFF0000",
+"o c #000000000000",
+"O c #FFFFFFFFFFFF",
+"+ c #00008A280000",
+" ",
+" ",
+" ",
+" ",
+" .... ",
+" .XXXXo ",
+" .XOXXXX+ ",
+" .XXXXXX+ ",
+" .XXXXXX+ ",
+" .XXXXXX+ ",
+" +XXXX+ ",
+" ++++ ",
+" ",
+" ",
+" ",
+" "};
diff --git a/view/src/libicon/icon_Time_line.cc b/view/src/libicon/icon_Time_line.cc
new file mode 100644
index 0000000..194bb36
--- /dev/null
+++ b/view/src/libicon/icon_Time_line.cc
@@ -0,0 +1,42 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #8 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 6 1",
+" c None",
+". c #E5E5E5",
+"+ c #888888",
+"@ c #000000",
+"# c #CCCCCC",
+"$ c #837B7B",
+"................",
+"....+@@@@@+.....",
+"...@@#####@@....",
+"..@####@####@...",
+".+@####@####@+..",
+".@#####@#####@..",
+".@#####@#####@..",
+".@#$###@###$#@..",
+".@######@####@..",
+".@#######@###@..",
+".+@#########@+..",
+"..@####$####@...",
+"...@@#####@@....",
+"....+@@@@@+.....",
+"................",
+"................"};
+static pixmap p("Time_line",(const char**)bits);
diff --git a/view/src/libicon/icon_Time_line.xpm b/view/src/libicon/icon_Time_line.xpm
new file mode 100644
index 0000000..96683ae
--- /dev/null
+++ b/view/src/libicon/icon_Time_line.xpm
@@ -0,0 +1,40 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * clock_xpm[] = {
+"16 16 6 1",
+" c #E5E5E5E5E5E5",
+". c #888888888888",
+"X c #000000000000",
+"o c #CCCCCCCCCCCC",
+"O c #FFFFFFFFFFFF",
+"+ c #444444444444",
+" ",
+" .XXXXX. ",
+" XXoooooXX ",
+" XoooOXOoOoX ",
+" .XooOOXOOoOX. ",
+" XooOOOXOOOoOX ",
+" XoOOOoXoOoOoX ",
+" Xo+OoOXOoO+OX ",
+" XoOOOoOXOoOoX ",
+" XooOoOoOXOoOX ",
+" .XoOOoOoOoOX. ",
+" XooOO+OoOOX ",
+" XXooOoOXX ",
+" .XXXXX. ",
+" ",
+" "};
diff --git a/view/src/libicon/icon_Triggers.cc b/view/src/libicon/icon_Triggers.cc
new file mode 100644
index 0000000..3d78b60
--- /dev/null
+++ b/view/src/libicon/icon_Triggers.cc
@@ -0,0 +1,39 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #5 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 3 1",
+" c #E7E7E7E7E7E7",
+". c #FFFFFFFFFFFF",
+"X c #7B7B7B7B7B7B",
+" ......X ",
+" . X ",
+" . X ",
+" .XXXXXX ",
+" X ",
+" X ",
+" X ",
+" X ",
+" XXXXXXXXXX ",
+" X X ",
+" X X ",
+" X X ",
+" .....X .....X ",
+" . X . X ",
+" . X . X ",
+" .XXXXX .XXXXX "};
+static pixmap p("Triggers",(const char**)bits);
diff --git a/view/src/libicon/icon_Triggers.xpm b/view/src/libicon/icon_Triggers.xpm
new file mode 100644
index 0000000..3fafcc6
--- /dev/null
+++ b/view/src/libicon/icon_Triggers.xpm
@@ -0,0 +1,37 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * Triggers_xpm[] = {
+"16 16 3 1",
+" c #E7E7E7E7E7E7",
+". c #FFFFFFFFFFFF",
+"X c #7B7B7B7B7B7B",
+" ......X ",
+" . X ",
+" . X ",
+" .XXXXXX ",
+" X ",
+" X ",
+" X ",
+" X ",
+" XXXXXXXXXX ",
+" X X ",
+" X X ",
+" X X ",
+" .....X .....X ",
+" . X . X ",
+" . X . X ",
+" .XXXXX .XXXXX "};
diff --git a/view/src/libicon/icon_Update.cc b/view/src/libicon/icon_Update.cc
new file mode 100644
index 0000000..355218b
--- /dev/null
+++ b/view/src/libicon/icon_Update.cc
@@ -0,0 +1,50 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #5 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 14 1",
+" c #E7E7E7E7E7E7",
+". c #FFFFFFFFFFFF",
+"X c #FFFFCECE9C9C",
+"o c #FFFF73739494",
+"O c #FFFF29292929",
+"+ c #FFFF00000000",
+"@ c #8C8C5A5A3939",
+"# c #CECECECECECE",
+"$ c #8C8C8C8C8C8C",
+"% c #F7F7EFEFDEDE",
+"& c #000000000000",
+"* c #4A4A42423939",
+"= c #BDBDB5B5B5B5",
+"- c #7B7B7B7B7B7B",
+" ",
+" .XoX ",
+" XO++@# ",
+" X+++++$ ",
+" %++++O&$ ",
+" o+++**$ .o% ",
+"%+++** o+O ",
+" +++*# ++++o ",
+"%O++* +++++++",
+".+++ at . X+++*$",
+" o+++= O++@* ",
+" %O+++ooo++++&$ ",
+" X+++++++++** ",
+" oO++++++**= ",
+" =@@+****# ",
+" .=$-$=. "};
+static pixmap p("Update",(const char**)bits);
diff --git a/view/src/libicon/icon_Update.xpm b/view/src/libicon/icon_Update.xpm
new file mode 100644
index 0000000..94c9861
--- /dev/null
+++ b/view/src/libicon/icon_Update.xpm
@@ -0,0 +1,48 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * Status_xpm[] = {
+"16 16 14 1",
+" c #E7E7E7E7E7E7",
+". c #FFFFFFFFFFFF",
+"X c #FFFFCECE9C9C",
+"o c #FFFF73739494",
+"O c #FFFF29292929",
+"+ c #FFFF00000000",
+"@ c #8C8C5A5A3939",
+"# c #CECECECECECE",
+"$ c #8C8C8C8C8C8C",
+"% c #F7F7EFEFDEDE",
+"& c #000000000000",
+"* c #4A4A42423939",
+"= c #BDBDB5B5B5B5",
+"- c #7B7B7B7B7B7B",
+" ",
+" .XoX ",
+" XO++@# ",
+" X+++++$ ",
+" %++++O&$ ",
+" o+++**$ .o% ",
+"%+++** o+O ",
+" +++*# ++++o ",
+"%O++* +++++++",
+".+++ at . X+++*$",
+" o+++= O++@* ",
+" %O+++ooo++++&$ ",
+" X+++++++++** ",
+" oO++++++**= ",
+" =@@+****# ",
+" .=$-$=. "};
diff --git a/view/src/libicon/icon_Use_external_editor.cc b/view/src/libicon/icon_Use_external_editor.cc
new file mode 100644
index 0000000..d37407b
--- /dev/null
+++ b/view/src/libicon/icon_Use_external_editor.cc
@@ -0,0 +1,43 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #8 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 7 1",
+" c None",
+". c #E5E5E5",
+"+ c #000000",
+"@ c #FF0505",
+"# c #A9A9A9",
+"$ c #FFFFFF",
+"% c #D3D3D3",
+"................",
+"................",
+"..........++....",
+".........+@@+...",
+".........+#@+...",
+"........+$#+....",
+"........+%#+....",
+".......+$#+.....",
+".......+%#+.....",
+"......+$#+......",
+"......+%#+......",
+".....+%#+.......",
+".....+##+.......",
+".....+#+........",
+".....++.........",
+"................"};
+static pixmap p("Use_external_editor",(const char**)bits);
diff --git a/view/src/libicon/icon_Use_external_editor.xpm b/view/src/libicon/icon_Use_external_editor.xpm
new file mode 100644
index 0000000..f3c2610
--- /dev/null
+++ b/view/src/libicon/icon_Use_external_editor.xpm
@@ -0,0 +1,43 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * pen_xpm[] = {
+"16 16 9 1",
+" c #E5E5E5E5E5E5",
+". c #000000000000",
+"X c #FFFF6666CCCC",
+"o c #999966669999",
+"O c #FFFFFFFFCCCC",
+"+ c #FFFFCCCC9999",
+"@ c #FFFF66663333",
+"# c #AAAAAAAAAAAA",
+"$ c #555555555555",
+" ",
+" ",
+" .. ",
+" .XX. ",
+" ..o. ",
+" .O.. ",
+" .+ at . ",
+" .O at . ",
+" .+ at . ",
+" .O at . ",
+" .+ at . ",
+" ... ",
+" .. ",
+"#o$o$#. ",
+" ",
+" "};
diff --git a/view/src/libicon/icon_Use_external_viewer.cc b/view/src/libicon/icon_Use_external_viewer.cc
new file mode 100644
index 0000000..e74b602
--- /dev/null
+++ b/view/src/libicon/icon_Use_external_viewer.cc
@@ -0,0 +1,42 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #8 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 6 1",
+" c None",
+". c #E5E5E5",
+"+ c #000000",
+"@ c #FFFFFF",
+"# c #DED9D9",
+"$ c #CAC6C6",
+"................",
+"................",
+"................",
+"................",
+"....++.......++.",
+"...+..+.....+..+",
+"..+........+....",
+".+++...++++.....",
+"+@##+.+@##+.....",
+"+##$+++##$+.....",
+"+#$$+.+#$$+.....",
+".+++...+++......",
+"................",
+"................",
+"................",
+"................"};
+static pixmap p("Use_external_viewer",(const char**)bits);
diff --git a/view/src/libicon/icon_Use_external_viewer.xpm b/view/src/libicon/icon_Use_external_viewer.xpm
new file mode 100644
index 0000000..d7c9b78
--- /dev/null
+++ b/view/src/libicon/icon_Use_external_viewer.xpm
@@ -0,0 +1,40 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * viewer_xpm[] = {
+"16 16 6 1",
+" c #E5E5E5E5E5E5",
+". c #000000000000",
+"X c #FFFFFFFFFFFF",
+"o c #CCCCCCCCFFFF",
+"O c #66666666CCCC",
+"+ c #99999999FFFF",
+" ",
+" ",
+" ",
+" ",
+" .. .. ",
+" . . . .",
+" . . . .",
+" ... .... ",
+".XoO. .XoO. ",
+".oX+...oX+. ",
+".O++. .O++. ",
+" ... ... ",
+" ",
+" ",
+" ",
+" "};
diff --git a/view/src/libicon/icon_Variables.cc b/view/src/libicon/icon_Variables.cc
new file mode 100644
index 0000000..0f551e2
--- /dev/null
+++ b/view/src/libicon/icon_Variables.cc
@@ -0,0 +1,38 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #5 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 2 1",
+" c #E7E7E7E7E7E7",
+". c #000000000000",
+" ",
+" ",
+" ",
+" ",
+" ",
+" .. .. ",
+" . . . ",
+" . . .... . ",
+" .... . ",
+" . . .... . ",
+" . . ... ",
+" ",
+" ",
+" ",
+" ",
+" "};
+static pixmap p("Variables",(const char**)bits);
diff --git a/view/src/libicon/icon_Variables.xpm b/view/src/libicon/icon_Variables.xpm
new file mode 100644
index 0000000..c268de2
--- /dev/null
+++ b/view/src/libicon/icon_Variables.xpm
@@ -0,0 +1,36 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * Variables_xpm[] = {
+"16 16 2 1",
+" c #E7E7E7E7E7E7",
+". c #000000000000",
+" ",
+" ",
+" ",
+" ",
+" ",
+" .. .. ",
+" . . . ",
+" . . .... . ",
+" .... . ",
+" . . .... . ",
+" . . ... ",
+" ",
+" ",
+" ",
+" ",
+" "};
diff --git a/view/src/libicon/icon_W.xpm b/view/src/libicon/icon_W.xpm
new file mode 100644
index 0000000..cf11d9a
--- /dev/null
+++ b/view/src/libicon/icon_W.xpm
@@ -0,0 +1,84 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * icon_W_xpm[] = {
+"16 16 50 1",
+" c None",
+". c #E7E7E7",
+"+ c #E7E3E3",
+"@ c #E9CDCD",
+"# c #EEA3A3",
+"$ c #FF0000",
+"% c #FA2A2A",
+"& c #F64E4E",
+"* c #F93434",
+"= c #FB1C1C",
+"- c #F46464",
+"; c #FD0E0E",
+"> c #EDA9A9",
+", c #E8D7D7",
+"' c #FB2222",
+") c #FE0606",
+"! c #ECB5B5",
+"~ c #FA2727",
+"{ c #EDABAB",
+"] c #F83E3E",
+"^ c #EF9494",
+"/ c #E7E5E5",
+"( c #EE9F9F",
+"_ c #F36D6D",
+": c #F08D8D",
+"< c #F74646",
+"[ c #ECB0B0",
+"} c #FE0404",
+"| c #FA2828",
+"1 c #E8DBDB",
+"2 c #E9CACA",
+"3 c #FD1313",
+"4 c #FD1212",
+"5 c #EACACA",
+"6 c #E7E6E6",
+"7 c #F65555",
+"8 c #E7DFDF",
+"9 c #E8DCDC",
+"0 c #FA2929",
+"a c #ECAFAF",
+"b c #F18484",
+"c c #F74949",
+"d c #E7E0E0",
+"e c #F27D7D",
+"f c #FE0101",
+"g c #F46868",
+"h c #F93939",
+"i c #F93131",
+"j c #FD0B0B",
+"k c #EDA6A6",
+"................",
+"................",
+"....+@@@@@@@@...",
+"....#$$%&*$$=...",
+"....-;>.,'$)!...",
+"....~{.+]$$^....",
+".../(..-$$_.....",
+"......:$$</.....",
+".....[}$|1......",
+"....23$45.678...",
+"...90$}a..b0....",
+"...c$$:.defg....",
+"...$$)hij$$k....",
+"................",
+"................",
+"................"};
diff --git a/view/src/libicon/icon_Why_.cc b/view/src/libicon/icon_Why_.cc
new file mode 100644
index 0000000..f4931a5
--- /dev/null
+++ b/view/src/libicon/icon_Why_.cc
@@ -0,0 +1,42 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #5 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 6 1",
+" c #E7E7E7E7E7E7",
+". c #BDBDB5B5B5B5",
+"X c #4A4A42423939",
+"o c #7B7B7B7B7B7B",
+"O c #CECECECECECE",
+"+ c #8C8C8C8C8C8C",
+" ",
+" ",
+" ",
+" .XXXo ",
+" .XO XO ",
+" o. o+ ",
+" . .X ",
+" .XO ",
+" .XO ",
+" XO ",
+" .o ",
+" ",
+" .O ",
+" o. ",
+" ",
+" "};
+static pixmap p("Why_",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Why_.xpm b/view/src/libicon/icon_Why_.xpm
similarity index 100%
rename from ecflow_4_0_7/view/src/libicon/icon_Why_.xpm
rename to view/src/libicon/icon_Why_.xpm
diff --git a/view/src/libicon/icon_Z.cc b/view/src/libicon/icon_Z.cc
new file mode 100644
index 0000000..fd0e768
--- /dev/null
+++ b/view/src/libicon/icon_Z.cc
@@ -0,0 +1,86 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 50 1",
+" c None",
+". c #E7E7E7",
+"+ c #E7E3E3",
+"@ c #E9CDCD",
+"# c #EEA3A3",
+"$ c #FF0000",
+"% c #FA2A2A",
+"& c #F64E4E",
+"* c #F93434",
+"= c #FB1C1C",
+"- c #F46464",
+"; c #FD0E0E",
+"> c #EDA9A9",
+", c #E8D7D7",
+"' c #FB2222",
+") c #FE0606",
+"! c #ECB5B5",
+"~ c #FA2727",
+"{ c #EDABAB",
+"] c #F83E3E",
+"^ c #EF9494",
+"/ c #E7E5E5",
+"( c #EE9F9F",
+"_ c #F36D6D",
+": c #F08D8D",
+"< c #F74646",
+"[ c #ECB0B0",
+"} c #FE0404",
+"| c #FA2828",
+"1 c #E8DBDB",
+"2 c #E9CACA",
+"3 c #FD1313",
+"4 c #FD1212",
+"5 c #EACACA",
+"6 c #E7E6E6",
+"7 c #F65555",
+"8 c #E7DFDF",
+"9 c #E8DCDC",
+"0 c #FA2929",
+"a c #ECAFAF",
+"b c #F18484",
+"c c #F74949",
+"d c #E7E0E0",
+"e c #F27D7D",
+"f c #FE0101",
+"g c #F46868",
+"h c #F93939",
+"i c #F93131",
+"j c #FD0B0B",
+"k c #EDA6A6",
+"................",
+"................",
+"....+@@@@@@@@...",
+"....#$$%&*$$=...",
+"....-;>.,'$)!...",
+"....~{.+]$$^....",
+".../(..-$$_.....",
+"......:$$</.....",
+".....[}$|1......",
+"....23$45.678...",
+"...90$}a..b0....",
+"...c$$:.defg....",
+"...$$)hij$$k....",
+"................",
+"................",
+"................"};
+static pixmap p("Z",(const char**)bits);
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Z.xpm b/view/src/libicon/icon_Z.xpm
similarity index 100%
rename from ecflow_4_0_7/view/src/libicon/icon_Z.xpm
rename to view/src/libicon/icon_Z.xpm
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Zbw.cc b/view/src/libicon/icon_Zbw.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libicon/icon_Zbw.cc
rename to view/src/libicon/icon_Zbw.cc
diff --git a/ecflow_4_0_7/view/src/libicon/icon_Zbw.xpm b/view/src/libicon/icon_Zbw.xpm
similarity index 100%
rename from ecflow_4_0_7/view/src/libicon/icon_Zbw.xpm
rename to view/src/libicon/icon_Zbw.xpm
diff --git a/view/src/libicon/icon_calendar.cc b/view/src/libicon/icon_calendar.cc
new file mode 100644
index 0000000..8918e13
--- /dev/null
+++ b/view/src/libicon/icon_calendar.cc
@@ -0,0 +1,40 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 4 1",
+" c None",
+". c #E7E7E7",
+"+ c #000000",
+"@ c #F7FB79",
+"................",
+"..++++++++++++..",
+"..+@@@@@@@@@@+..",
+"..+@@@@@@@@@@+..",
+"..+@@@@@@@@@@+..",
+"..+@@@@++@@@@+..",
+"..+@@@+++@@@@+..",
+"..+@@@@++@@@@+..",
+"..+@@@@++@@@@+..",
+"..+@@@@++@@@@+..",
+"..+@@@@++@@@@+..",
+"..+@@@++++@@@+..",
+"..+@@@@@@@@@@+..",
+"...+@@@@@@@@@+..",
+"....++++++++++..",
+"................"};
+static pixmap p("calendar",(const char**)bits);
diff --git a/view/src/libicon/icon_calendar.xpm b/view/src/libicon/icon_calendar.xpm
new file mode 100644
index 0000000..442dc5b
--- /dev/null
+++ b/view/src/libicon/icon_calendar.xpm
@@ -0,0 +1,38 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * calendar_xpm[] = {
+"16 16 4 1",
+" c #E79DE79DE79D",
+". c #AAAAAAAAAAAA",
+"X c #000000000000",
+"o c #F7DEFBEE79E7",
+" ",
+" .......... ",
+" XXXXXXXXXX. ",
+" XooooooooX. ",
+" XooooooooX. ",
+" XooooXoooX. ",
+" XooXXXoooX. ",
+" XoooXXoooX. ",
+" XoooXXoooX. ",
+" XoooXXoooX. ",
+" XoooXXoooX. ",
+" XooXXXXooX. ",
+" XooooooooX. ",
+" XoooooooX. ",
+" XXXXXXXX ",
+" "};
diff --git a/view/src/libicon/icon_clock.cc b/view/src/libicon/icon_clock.cc
new file mode 100644
index 0000000..a718c50
--- /dev/null
+++ b/view/src/libicon/icon_clock.cc
@@ -0,0 +1,42 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 6 1",
+" c None",
+". c #E5E5E5",
+"+ c #888888",
+"@ c #000000",
+"# c #CCCCCC",
+"$ c #837B7B",
+"................",
+"....+@@@@@+.....",
+"...@@#####@@....",
+"..@####@####@...",
+".+@####@####@+..",
+".@#####@#####@..",
+".@#####@#####@..",
+".@#$###@###$#@..",
+".@######@####@..",
+".@#######@###@..",
+".+@#########@+..",
+"..@####$####@...",
+"...@@#####@@....",
+"....+@@@@@+.....",
+"................",
+"................"};
+static pixmap p("clock",(const char**)bits);
diff --git a/view/src/libicon/icon_clock.xpm b/view/src/libicon/icon_clock.xpm
new file mode 100644
index 0000000..e241a4c
--- /dev/null
+++ b/view/src/libicon/icon_clock.xpm
@@ -0,0 +1,40 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * clock_xpm[] = {
+"16 16 6 1",
+" c #E5E5E5E5E5E5",
+". c #888888888888",
+"X c #000000000000",
+"o c #CCCCCCCCCCCC",
+"O c #FFFFFFFFFFFF",
+"+ c #444444444444",
+" ",
+" .XXXXX. ",
+" XXoooooXX ",
+" XoooOXOoOoX ",
+" .XooOOXOOoOX. ",
+" XooOOOXOOOoOX ",
+" XoOOOoXoOoOoX ",
+" Xo+OoOXOoO+OX ",
+" XoOOOoOXOoOoX ",
+" XooOoOoOXOoOX ",
+" .XoOOoOoOoOX. ",
+" XooOO+OoOOX ",
+" XXooOoOXX ",
+" .XXXXX. ",
+" ",
+" "};
diff --git a/view/src/libicon/icon_clock_free.cc b/view/src/libicon/icon_clock_free.cc
new file mode 100644
index 0000000..3a71a73
--- /dev/null
+++ b/view/src/libicon/icon_clock_free.cc
@@ -0,0 +1,42 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 6 1",
+" c None",
+". c #E5E5E5",
+"+ c #888888",
+"@ c #000000",
+"# c #F7FB79",
+"$ c #837B7B",
+"................",
+"....+@@@@@+.....",
+"...@@#####@@....",
+"..@####@####@...",
+".+@####@####@+..",
+".@#####@#####@..",
+".@#####@#####@..",
+".@#$###@###$#@..",
+".@######@####@..",
+".@#######@###@..",
+".+@#########@+..",
+"..@####$####@...",
+"...@@#####@@....",
+"....+@@@@@+.....",
+"................",
+"................"};
+static pixmap p("clock_free",(const char**)bits);
diff --git a/view/src/libicon/icon_complete.cc b/view/src/libicon/icon_complete.cc
new file mode 100644
index 0000000..a1a82e6
--- /dev/null
+++ b/view/src/libicon/icon_complete.cc
@@ -0,0 +1,65 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+/*
+static char * bits[] = {
+"16 16 2 1",
+" c #E7E7E7E7E7E7",
+". c #000000000000",
+" ... ... . . ",
+". .. ... .. ",
+". . .. . . ",
+". . .. . ",
+". .. .. . ",
+" ... ... . . ",
+".... . .... ",
+". . . . ",
+".... . ... ",
+". . . ",
+". .... .... ",
+"..... .... ",
+" . . ",
+" . ... ",
+" . . ",
+" . .... "};
+*/
+static const char * bits[] = {
+"16 16 3 1",
+" c #E5E5E5E5E5E5",
+". c #FFFFFF",
+"# c #FF0000",
+" ...... ",
+" ..######.. ",
+" .##########. ",
+" .############. ",
+" .############. ",
+".##############.",
+".##############.",
+".#............#.",
+".#............#.",
+".##############.",
+".##############.",
+" .############. ",
+" .############. ",
+" .##########. ",
+" ..######.. ",
+" ...... "};
+
+
+
+
+static pixmap p("complete",(const char**)bits);
diff --git a/view/src/libicon/icon_complete.xpm b/view/src/libicon/icon_complete.xpm
new file mode 100644
index 0000000..d018e59
--- /dev/null
+++ b/view/src/libicon/icon_complete.xpm
@@ -0,0 +1,57 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+/*
+static char * complete_xpm[] = {
+"16 16 2 1",
+" c #E7E7E7E7E7E7",
+". c #000000000000",
+" ... ... . . ",
+". .. ... .. ",
+". . .. . . ",
+". . .. . ",
+". .. .. . ",
+" ... ... . . ",
+".... . .... ",
+". . . . ",
+".... . ... ",
+". . . ",
+". .... .... ",
+"..... .... "," . . ",
+" . ... ",
+" . . ",
+" . .... "};
+*/
+static char * icon_complete_xpm[] = {
+"16 16 5 1",
+" c None",
+". c #FFFFFF",
+"+ c #0000FF",
+"@ c #00FF00",
+"# c #FF0000",
+" ........ "
+" .########. "
+" .##########. "
+".##..#...###...."
+".#.##.#.#....#..#"
+".#.####.#.#....."
+".###.##.#.#..##."
+".#.##.#.#.#..##."
+" .#..##.#....#. "
+" .#########. "
+" ........ "};
+
+
diff --git a/view/src/libicon/icon_defstatus.cc b/view/src/libicon/icon_defstatus.cc
new file mode 100644
index 0000000..4f6745a
--- /dev/null
+++ b/view/src/libicon/icon_defstatus.cc
@@ -0,0 +1,164 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 128 2",
+" c #E5E5E5",
+". c #D6D8BA",
+"+ c #C2BF70",
+"@ c #B6B04A",
+"# c #A89D12",
+"$ c #A89B12",
+"% c #E7E377",
+"& c #F3F489",
+"* c #F4F387",
+"= c #F4F484",
+"- c #F2F381",
+"; c #F0F37E",
+"> c #F0F37B",
+", c #EFF379",
+"' c #EFF376",
+") c #EDF373",
+"! c #EDF271",
+"~ c #E0E35F",
+"{ c #B7B14A",
+"] c #F1F58F",
+"^ c #ECF277",
+"/ c #E3EE5D",
+"( c #E2ED5C",
+"_ c #E1EC5B",
+": c #DFEA59",
+"< c #DDE858",
+"[ c #DCE756",
+"} c #DAE654",
+"| c #D9E453",
+"1 c #E1EA64",
+"2 c #E9F274",
+"3 c #C7C46C",
+"4 c #F0F592",
+"5 c #E1EF66",
+"6 c #DFEE62",
+"7 c #F4F8CD",
+"8 c #E3EE78",
+"9 c #D6E852",
+"0 c #D5E651",
+"a c #DEE975",
+"b c #F2F6CB",
+"c c #D6E35C",
+"d c #D2E154",
+"e c #E6F278",
+"f c #C3C054",
+"g c #EEF491",
+"h c #E1EE66",
+"i c #F6F9CE",
+"j c #FFFFFF",
+"k c #FDF8F5",
+"l c #E0EC77",
+"m c #DFEA77",
+"n c #F1F5CC",
+"o c #CEDE4F",
+"p c #E5F276",
+"q c #C3C051",
+"r c #ECF48E",
+"s c #DFED64",
+"t c #E2EE79",
+"u c #DCE675",
+"v c #E5F274",
+"w c #F0F386",
+"x c #E5E750",
+"y c #DFE340",
+"z c #E6E767",
+"A c #FDF7F3",
+"B c #DFDE63",
+"C c #D6D73B",
+"D c #D3D539",
+"E c #E7EF69",
+"F c #C2BE4E",
+"G c #F0ED7A",
+"H c #E3E049",
+"I c #DEDB38",
+"J c #E4E063",
+"K c #DDD960",
+"L c #D3CD33",
+"M c #D1CC31",
+"N c #EAEC5C",
+"O c #C0BB47",
+"P c #EFE976",
+"Q c #E1DD48",
+"R c #E3DF62",
+"S c #FCF7F3",
+"T c #DBD65F",
+"U c #D0CA31",
+"V c #EAEB56",
+"W c #BEB73C",
+"X c #EFEA73",
+"Y c #DFDB46",
+"Z c #F3F2C5",
+"` c #DEDB60",
+" . c #F0EEC4",
+".. c #CFC930",
+"+. c #E9EB52",
+"@. c #BEB83A",
+"#. c #EFEB70",
+"$. c #DDD943",
+"%. c #DAD643",
+"&. c #D5D134",
+"*. c #D4D033",
+"=. c #D2CC40",
+"-. c #D1CD34",
+";. c #E7EA4F",
+">. c #BEB739",
+",. c #BCB656",
+"'. c #EEEA6D",
+"). c #E5E157",
+"!. c #DAD63E",
+"~. c #D5D034",
+"{. c #D2CD31",
+"]. c #D1CB31",
+"^. c #D3CF36",
+"/. c #DFDE43",
+"(. c #E8EA4C",
+"_. c #C7C369",
+":. c #CBC888",
+"<. c #E1DD5B",
+"[. c #EEEB68",
+"}. c #EEEB65",
+"|. c #EDEB62",
+"1. c #EDEB5F",
+"2. c #ECEA5C",
+"3. c #ECEB59",
+"4. c #DCDD3F",
+"5. c #E0E0D0",
+"6. c #CBC789",
+"7. c #BDB658",
+" ",
+" . + @ # # # # # # $ # @ + . ",
+" + % & * = - ; > , ' ) ! ~ + ",
+" { ] ^ / ( _ : < [ } | 1 2 3 ",
+" $ 4 5 6 7 8 9 0 a b c d e f ",
+" # g h i j k l m k j n o p q ",
+" # r s t k j k k j k u o v q ",
+" # w x y z A j j A B C D E F ",
+" # G H I J A j j A K L M N O ",
+" # P Q R A j A A j S T U V W ",
+" # X Y Z j A ` K S j ...+. at . ",
+" # #.$.%.Z K &.*.T .=.-.;.>. ",
+" ,.'.).!.~.*.L {.]...^./.(._. ",
+" :.<.[.}.|.1.2.3.V +.;.(.4.:. ",
+" 5.6.7.$ # # $ # # # $ 7.6.5. ",
+" "};
+static pixmap p("defstatus",(const char**)bits);
diff --git a/view/src/libicon/icon_defstatus.xpm b/view/src/libicon/icon_defstatus.xpm
new file mode 100644
index 0000000..b60f4bb
--- /dev/null
+++ b/view/src/libicon/icon_defstatus.xpm
@@ -0,0 +1,162 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * defstatus_xpm[] = {
+"16 16 128 2",
+" c #E5E5E5",
+". c #D6D8BA",
+"+ c #C2BF70",
+"@ c #B6B04A",
+"# c #A89D12",
+"$ c #A89B12",
+"% c #E7E377",
+"& c #F3F489",
+"* c #F4F387",
+"= c #F4F484",
+"- c #F2F381",
+"; c #F0F37E",
+"> c #F0F37B",
+", c #EFF379",
+"' c #EFF376",
+") c #EDF373",
+"! c #EDF271",
+"~ c #E0E35F",
+"{ c #B7B14A",
+"] c #F1F58F",
+"^ c #ECF277",
+"/ c #E3EE5D",
+"( c #E2ED5C",
+"_ c #E1EC5B",
+": c #DFEA59",
+"< c #DDE858",
+"[ c #DCE756",
+"} c #DAE654",
+"| c #D9E453",
+"1 c #E1EA64",
+"2 c #E9F274",
+"3 c #C7C46C",
+"4 c #F0F592",
+"5 c #E1EF66",
+"6 c #DFEE62",
+"7 c #F4F8CD",
+"8 c #E3EE78",
+"9 c #D6E852",
+"0 c #D5E651",
+"a c #DEE975",
+"b c #F2F6CB",
+"c c #D6E35C",
+"d c #D2E154",
+"e c #E6F278",
+"f c #C3C054",
+"g c #EEF491",
+"h c #E1EE66",
+"i c #F6F9CE",
+"j c #FFFFFF",
+"k c #FDF8F5",
+"l c #E0EC77",
+"m c #DFEA77",
+"n c #F1F5CC",
+"o c #CEDE4F",
+"p c #E5F276",
+"q c #C3C051",
+"r c #ECF48E",
+"s c #DFED64",
+"t c #E2EE79",
+"u c #DCE675",
+"v c #E5F274",
+"w c #F0F386",
+"x c #E5E750",
+"y c #DFE340",
+"z c #E6E767",
+"A c #FDF7F3",
+"B c #DFDE63",
+"C c #D6D73B",
+"D c #D3D539",
+"E c #E7EF69",
+"F c #C2BE4E",
+"G c #F0ED7A",
+"H c #E3E049",
+"I c #DEDB38",
+"J c #E4E063",
+"K c #DDD960",
+"L c #D3CD33",
+"M c #D1CC31",
+"N c #EAEC5C",
+"O c #C0BB47",
+"P c #EFE976",
+"Q c #E1DD48",
+"R c #E3DF62",
+"S c #FCF7F3",
+"T c #DBD65F",
+"U c #D0CA31",
+"V c #EAEB56",
+"W c #BEB73C",
+"X c #EFEA73",
+"Y c #DFDB46",
+"Z c #F3F2C5",
+"` c #DEDB60",
+" . c #F0EEC4",
+".. c #CFC930",
+"+. c #E9EB52",
+"@. c #BEB83A",
+"#. c #EFEB70",
+"$. c #DDD943",
+"%. c #DAD643",
+"&. c #D5D134",
+"*. c #D4D033",
+"=. c #D2CC40",
+"-. c #D1CD34",
+";. c #E7EA4F",
+">. c #BEB739",
+",. c #BCB656",
+"'. c #EEEA6D",
+"). c #E5E157",
+"!. c #DAD63E",
+"~. c #D5D034",
+"{. c #D2CD31",
+"]. c #D1CB31",
+"^. c #D3CF36",
+"/. c #DFDE43",
+"(. c #E8EA4C",
+"_. c #C7C369",
+":. c #CBC888",
+"<. c #E1DD5B",
+"[. c #EEEB68",
+"}. c #EEEB65",
+"|. c #EDEB62",
+"1. c #EDEB5F",
+"2. c #ECEA5C",
+"3. c #ECEB59",
+"4. c #DCDD3F",
+"5. c #E0E0D0",
+"6. c #CBC789",
+"7. c #BDB658",
+" ",
+" . + @ # # # # # # $ # @ + . ",
+" + % & * = - ; > , ' ) ! ~ + ",
+" { ] ^ / ( _ : < [ } | 1 2 3 ",
+" $ 4 5 6 7 8 9 0 a b c d e f ",
+" # g h i j k l m k j n o p q ",
+" # r s t k j k k j k u o v q ",
+" # w x y z A j j A B C D E F ",
+" # G H I J A j j A K L M N O ",
+" # P Q R A j A A j S T U V W ",
+" # X Y Z j A ` K S j ...+. at . ",
+" # #.$.%.Z K &.*.T .=.-.;.>. ",
+" ,.'.).!.~.*.L {.]...^./.(._. ",
+" :.<.[.}.|.1.2.3.V +.;.(.4.:. ",
+" 5.6.7.$ # # $ # # # $ 7.6.5. ",
+" "};
diff --git a/view/src/libicon/icon_folded.cc b/view/src/libicon/icon_folded.cc
new file mode 100644
index 0000000..b44518b
--- /dev/null
+++ b/view/src/libicon/icon_folded.cc
@@ -0,0 +1,39 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 3 1",
+" c #E5E5E5E5E5E5",
+". c #7E7E7E7E7E7E",
+"X c #FFFFFFFFFFFF",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+".. ... ... ..",
+"XX XXX XXX XX",
+" ",
+" ",
+" ",
+" ",
+" ",
+" "};
+static pixmap p("folded",(const char**)bits);
diff --git a/view/src/libicon/icon_folded.xpm b/view/src/libicon/icon_folded.xpm
new file mode 100644
index 0000000..918b774
--- /dev/null
+++ b/view/src/libicon/icon_folded.xpm
@@ -0,0 +1,37 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * folded_xpm[] = {
+"16 16 3 1",
+" c #E5E5E5E5E5E5",
+". c #7E7E7E7E7E7E",
+"X c #FFFFFFFFFFFF",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+".. ... ... ..",
+"XX XXX XXX XX",
+" ",
+" ",
+" ",
+" ",
+" ",
+" "};
diff --git a/view/src/libicon/icon_late.cc b/view/src/libicon/icon_late.cc
new file mode 100644
index 0000000..7b11ba2
--- /dev/null
+++ b/view/src/libicon/icon_late.cc
@@ -0,0 +1,39 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 3 1",
+" c #E5E5E5E5E5E5",
+". c #000000000000",
+"X c #F5F5F9F97A7A",
+" . ",
+" .X. ",
+" .X. ",
+" .XXX. ",
+" .X.X. ",
+" .XX.XX. ",
+" .XX.XX. ",
+" .XXX.XXX. ",
+" .XXX.XXX. ",
+" .XXXX.XXXX. ",
+" .XXXXXXXXX. ",
+" .XXXXX.XXXXX. ",
+" .XXXXX.XXXXX. ",
+".XXXXXXXXXXXXX. ",
+"............... ",
+" "};
+static pixmap p("late",(const char**)bits);
diff --git a/view/src/libicon/icon_late.xpm b/view/src/libicon/icon_late.xpm
new file mode 100644
index 0000000..d513a46
--- /dev/null
+++ b/view/src/libicon/icon_late.xpm
@@ -0,0 +1,37 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * late_xpm[] = {
+"16 16 3 1",
+" c #E5E5E5E5E5E5",
+". c #000000000000",
+"X c #F5F5F9F97A7A",
+" . ",
+" .X. ",
+" .X. ",
+" .XXX. ",
+" .X.X. ",
+" .XX.XX. ",
+" .XX.XX. ",
+" .XXX.XXX. ",
+" .XXX.XXX. ",
+" .XXXX.XXXX. ",
+" .XXXXXXXXX. ",
+" .XXXXX.XXXXX. ",
+" .XXXXX.XXXXX. ",
+".XXXXXXXXXXXXX. ",
+"............... ",
+" "};
diff --git a/view/src/libicon/icon_limit0.cc b/view/src/libicon/icon_limit0.cc
new file mode 100644
index 0000000..3e9f594
--- /dev/null
+++ b/view/src/libicon/icon_limit0.cc
@@ -0,0 +1,32 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"8 8 4 1",
+" c #E5E5E5E5E5E5",
+". c #FFFFFFFFFFFF",
+"X c #000000000000",
+"o c #7E7E7E7E7E7E",
+" .... ",
+" . X ",
+". . o",
+". o",
+". o",
+". o",
+" o o ",
+" oooo "};
+static pixmap p("limit0",(const char**)bits);
diff --git a/view/src/libicon/icon_limit0.xpm b/view/src/libicon/icon_limit0.xpm
new file mode 100644
index 0000000..401fae9
--- /dev/null
+++ b/view/src/libicon/icon_limit0.xpm
@@ -0,0 +1,30 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * limit0_xpm[] = {
+"8 8 4 1",
+" c #E5E5E5E5E5E5",
+". c #FFFFFFFFFFFF",
+"X c #000000000000",
+"o c #7E7E7E7E7E7E",
+" .... ",
+" . X ",
+". . o",
+". o",
+". o",
+". o",
+" o o ",
+" oooo "};
diff --git a/view/src/libicon/icon_limit1.cc b/view/src/libicon/icon_limit1.cc
new file mode 100644
index 0000000..8f3d1ff
--- /dev/null
+++ b/view/src/libicon/icon_limit1.cc
@@ -0,0 +1,34 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"8 8 6 1",
+" c #E5E5E5E5E5E5",
+". c #0000EEEE0000",
+"X c #0000FFFF0000",
+"o c #000000000000",
+"O c #FFFFFFFFFFFF",
+"+ c #000088880000",
+" .... ",
+" .XXXXo ",
+".XOXXXX+",
+".XXXXXX+",
+".XXXXXX+",
+".XXXXXX+",
+" +XXXX+ ",
+" ++++ "};
+static pixmap p("limit1",(const char**)bits);
diff --git a/view/src/libicon/icon_limit1.xpm b/view/src/libicon/icon_limit1.xpm
new file mode 100644
index 0000000..754086d
--- /dev/null
+++ b/view/src/libicon/icon_limit1.xpm
@@ -0,0 +1,32 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * limit1_xpm[] = {
+"8 8 6 1",
+" c #E5E5E5E5E5E5",
+". c #0000EEEE0000",
+"X c #0000FFFF0000",
+"o c #000000000000",
+"O c #FFFFFFFFFFFF",
+"+ c #000088880000",
+" .... ",
+" .XXXXo ",
+".XOXXXX+",
+".XXXXXX+",
+".XXXXXX+",
+".XXXXXX+",
+" +XXXX+ ",
+" ++++ "};
diff --git a/view/src/libicon/icon_limit2.cc b/view/src/libicon/icon_limit2.cc
new file mode 100644
index 0000000..84d819e
--- /dev/null
+++ b/view/src/libicon/icon_limit2.cc
@@ -0,0 +1,34 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"8 8 6 1",
+" c #E5E5E5E5E5E5",
+". c #00000000EEEE",
+"X c #00000000FFFF",
+"o c #000000000000",
+"O c #FFFFFFFFFFFF",
+"+ c #000000008888",
+" .... ",
+" .XXXXo ",
+".XOXXXX+",
+".XXXXXX+",
+".XXXXXX+",
+".XXXXXX+",
+" +XXXX+ ",
+" ++++ "};
+static pixmap p("limit2",(const char**)bits);
diff --git a/view/src/libicon/icon_limit2.xpm b/view/src/libicon/icon_limit2.xpm
new file mode 100644
index 0000000..4caced4
--- /dev/null
+++ b/view/src/libicon/icon_limit2.xpm
@@ -0,0 +1,32 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * limit2_xpm[] = {
+"8 8 6 1",
+" c #E5E5E5E5E5E5",
+". c #00000000EEEE",
+"X c #00000000FFFF",
+"o c #000000000000",
+"O c #FFFFFFFFFFFF",
+"+ c #000000008888",
+" .... ",
+" .XXXXo ",
+".XOXXXX+",
+".XXXXXX+",
+".XXXXXX+",
+".XXXXXX+",
+" +XXXX+ ",
+" ++++ "};
diff --git a/view/src/libicon/icon_locked.cc b/view/src/libicon/icon_locked.cc
new file mode 100644
index 0000000..cd7c444
--- /dev/null
+++ b/view/src/libicon/icon_locked.cc
@@ -0,0 +1,40 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 4 1",
+" c #E5E5E5E5E5E5",
+". c #282828282828",
+"X c #FFFFFFFFFFFF",
+"o c #ADADADADADAD",
+" ",
+" .... ",
+" .. .. ",
+" . . ",
+" . . ",
+" XXXXXXXXXXX. ",
+" Xoooooooooo. ",
+" Xoooo..oooo. ",
+" Xooo....ooo. ",
+" Xoooo..oooo. ",
+" Xoooo..oooo. ",
+" Xoooo..oooo. ",
+" Xoooooooooo. ",
+" Xoooooooooo. ",
+" ............ ",
+" XXXXXXXXXXXX "};
+static pixmap p("locked",(const char**)bits);
diff --git a/view/src/libicon/icon_locked.xpm b/view/src/libicon/icon_locked.xpm
new file mode 100644
index 0000000..ad020c9
--- /dev/null
+++ b/view/src/libicon/icon_locked.xpm
@@ -0,0 +1,38 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * locked_xpm[] = {
+"16 16 4 1",
+" c #E5E5E5E5E5E5",
+". c #282828282828",
+"X c #FFFFFFFFFFFF",
+"o c #ADADADADADAD",
+" ",
+" .... ",
+" .. .. ",
+" . . ",
+" . . ",
+" XXXXXXXXXXX. ",
+" Xoooooooooo. ",
+" Xoooo..oooo. ",
+" Xooo....ooo. ",
+" Xoooo..oooo. ",
+" Xoooo..oooo. ",
+" Xoooo..oooo. ",
+" Xoooooooooo. ",
+" Xoooooooooo. ",
+" ............ ",
+" XXXXXXXXXXXX "};
diff --git a/view/src/libicon/icon_memo.cc b/view/src/libicon/icon_memo.cc
new file mode 100644
index 0000000..462b19c
--- /dev/null
+++ b/view/src/libicon/icon_memo.cc
@@ -0,0 +1,15 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+#include "pixmap.h"
diff --git a/view/src/libicon/icon_memo.xpm b/view/src/libicon/icon_memo.xpm
new file mode 100644
index 0000000..9436e05
--- /dev/null
+++ b/view/src/libicon/icon_memo.xpm
@@ -0,0 +1,67 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * icon_memo_xpm[] = {
+"32 32 17 1",
+" c None",
+". c #000000",
+"+ c #800000",
+"@ c #008000",
+"# c #808000",
+"$ c #000080",
+"% c #800080",
+"& c #008080",
+"* c #808080",
+"= c #C0C0C0",
+"- c #FF0000",
+"; c #00FF00",
+"> c #FFFF00",
+", c #0000FF",
+"' c #FF00FF",
+") c #00FFFF",
+"! c #FFFFFF",
+" * * * * * ",
+" * * * * * * * * * * ",
+" ...*...*...*...*...*...",
+" .>!*!>!*!>!*!>!*!>!*!>.",
+" .>!>!>!>!>!>!>!>!>!>!>..",
+" .!>!>!>!>!>!>!>!>!>!>!..",
+" .!>!>!>.........>!>!>!.=.",
+" .>!>!>!.!!!!!!!.!>!>!>.=.",
+" .>!>!>!.!!....!.!>!>!>.=!.",
+" .!>!>!>.!.!..!!.>!>!>!.=!.",
+" .!>!>!>.!!!!!!!.>!>!>!.*!!.",
+" .>!>!>!.........!>!>!>.=!!.",
+" .>!>!>!>!>!>!>!>!>!>!>.=!>!.",
+" .!>!>!>!>!>!>!>!>!>!>!.=!!!.",
+" .!>!>!>!>!>!>!>!>!>!>!.***!!.",
+" .>!>!>!>!>!>!>!>!>!>!>.=!!!!.",
+" .>!>!>!>!>!>!>!>!>!>!>.=!!!>!.",
+" .!>!>!>!>!>!>!>!>!>!>!.=!!!!!.",
+" .!>!>!>!>!>!>!>!>!>!>!.*****!!.",
+" .>!>!>!>!>!>!>!>!>!>!>.=!!!!!!.",
+".>!>!>!>!>!>!>!>!>!>!>.=!>!!!>!.",
+".......................=!!!!!!!.",
+" .==*****************!!.",
+" .!!!!!!!!!!!!!!!!!!!!!.",
+" .!!!>!!!>!!!>!!!>!!!>!.",
+" .!!!!!!!!!!!!!!!!!!!!!.",
+" .!>*****************!!.",
+" .!!!!!!!!!!!!!!!!!!!!!.",
+" .!!!>!!!>!!!>!!!>!!!>!.",
+" .!!!!!!!!!!!!!!!!!!!!!.",
+" .!>!!!>!!!>!!!>!!!>!!!.",
+" ......................."};
diff --git a/view/src/libicon/icon_message.cc b/view/src/libicon/icon_message.cc
new file mode 100644
index 0000000..c822c93
--- /dev/null
+++ b/view/src/libicon/icon_message.cc
@@ -0,0 +1,40 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 4 1",
+" c None",
+". c #E5E5E5",
+"+ c #000000",
+"@ c #F5F97A",
+"................",
+"................",
+"................",
+"..+++++++++++...",
+"..+@@@@@@@@@+...",
+"..+@@@@@@@@@+...",
+"..+@@@@@@@@@+...",
+"..+@@@@@@@@@+...",
+"..+@@@@@@@@@+...",
+"..+@@@@@@@@@+...",
+"..+@@@@@+++++...",
+"..+@@@@@+@@+....",
+"..+@@@@@+ at +.....",
+"..++++++++......",
+"................",
+"................"};
+static pixmap p("message",(const char**)bits);
diff --git a/view/src/libicon/icon_message.xpm b/view/src/libicon/icon_message.xpm
new file mode 100644
index 0000000..6ef47b3
--- /dev/null
+++ b/view/src/libicon/icon_message.xpm
@@ -0,0 +1,41 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * message_xpm[] = {
+"16 16 7 1",
+" c #E5E5E5E5E5E5",
+". c #000000000000",
+"X c #C9C9CDCD4C4C",
+"o c #FFFFFFFFFFFF",
+"O c #F5F5F9F97A7A",
+"+ c #545454545454",
+"@ c #98989B9B3838",
+" ",
+" ",
+" ",
+" ........... ",
+" .XXXXXXXXX. ",
+" .XXXXXXXXX. ",
+" .oOOOOOOOO. ",
+" .oOOOOOOOO. ",
+" .oOOOOOOOO. ",
+" .oOOOOOOOO. ",
+" .oOOOX..... ",
+" .oOOXX+OO. ",
+" .oXXX.O at + ",
+" .....++ ",
+" ",
+" "};
diff --git a/view/src/libicon/icon_migrated.cc b/view/src/libicon/icon_migrated.cc
new file mode 100644
index 0000000..7d7dccb
--- /dev/null
+++ b/view/src/libicon/icon_migrated.cc
@@ -0,0 +1,40 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 3 1",
+" c #E79DE79DE79D",
+". c #000000000000",
+"X c #F7DEFBEE79E7",
+" ",
+" ..... ",
+" .XXXXX. ",
+" .XXXXXXX. ",
+" .XXXXXXXXX. ",
+" .XXXXXXXXXXX. ",
+" .XXXX...XXXX. ",
+" .XXXX. .XXXX. ",
+" .XXXX...XXXX. ",
+" .XXXXXXXXXXX. ",
+" .XXXXXXXXX. ",
+" .XXXXXXX. ",
+" .XXXXX. ",
+" ......... ",
+" ",
+" "};
+static pixmap p("migrated",(const char**)bits);
diff --git a/view/src/libicon/icon_migrated.xpm b/view/src/libicon/icon_migrated.xpm
new file mode 100644
index 0000000..8c67491
--- /dev/null
+++ b/view/src/libicon/icon_migrated.xpm
@@ -0,0 +1,37 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * migrated_xpm[] = {
+"16 16 3 1",
+" c #E79DE79DE79D",
+". c #000000000000",
+"X c #F7DEFBEE79E7",
+" ",
+" ..... ",
+" .XXXXX. ",
+" .XXXXXXX. ",
+" .XXXXXXXXX. ",
+" .XXXXXXXXXXX. ",
+" .XXXX...XXXX. ",
+" .XXXX. .XXXX. ",
+" .XXXX...XXXX. ",
+" .XXXXXXXXXXX. ",
+" .XXXXXXXXX. ",
+" .XXXXXXX. ",
+" .XXXXX. ",
+" ......... ",
+" ",
+" "};
diff --git a/view/src/libicon/icon_noway.cc b/view/src/libicon/icon_noway.cc
new file mode 100644
index 0000000..b3473ee
--- /dev/null
+++ b/view/src/libicon/icon_noway.cc
@@ -0,0 +1,65 @@
+//=============================================================================================
+// Name :
+// Author :
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+// Description :
+//=============================================================================================
+
+#include "pixmap.h"
+/* XPM */
+/*
+static const char * bits[] = {
+"16 16 2 1",
+" c #E7E7E7E7E7E7",
+". c #000000000000",
+" ... ... . . ",
+". .. ... .. ",
+". . .. . . ",
+". . .. . ",
+". .. .. . ",
+" ... ... . . ",
+".... . .... ",
+". . . . ",
+".... . ... ",
+". . . ",
+". .... .... ",
+"..... .... ",
+" . . ",
+" . ... ",
+" . . ",
+" . .... "};
+*/
+static const char * bits[] = {
+"16 16 3 1",
+" c #E5E5E5E5E5E5",
+". c #FFFFFF",
+"# c #FF0000",
+" ...... ",
+" ..######.. ",
+" .##########. ",
+" .############. ",
+" .############. ",
+".##############.",
+".##############.",
+".#............#.",
+".#............#.",
+".##############.",
+".##############.",
+" .############. ",
+" .############. ",
+" .##########. ",
+" ..######.. ",
+" ...... "};
+
+
+
+
+static pixmap p("noway",(const char**)bits);
diff --git a/view/src/libicon/icon_noway.xpm b/view/src/libicon/icon_noway.xpm
new file mode 100644
index 0000000..caa8a74
--- /dev/null
+++ b/view/src/libicon/icon_noway.xpm
@@ -0,0 +1,63 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+/*
+static char * icon_complete[] = {
+"16 16 2 1",
+" c #E7E7E7E7E7E7",
+". c #000000000000",
+" ... ... . . ",
+". .. ... .. ",
+". . .. . . ",
+". . .. . ",
+". .. .. . ",
+" ... ... . . ",
+".... . .... ",
+". . . . ",
+".... . ... ",
+". . . ",
+". .... .... ",
+"..... .... ",
+" . . ",
+" . ... ",
+" . . ",
+" . .... "};
+*/
+static char * icon_noway_xpm[] = {
+"16 16 3 1",
+" c #E5E5E5E5E5E5",
+". c #FFFFFF",
+"# c #FF0000",
+" ...... ",
+" ..######.. ",
+" .##########. ",
+" .############. ",
+" .############. ",
+".##############.",
+".##############.",
+".#............#.",
+".#............#.",
+".##############.",
+".##############.",
+" .############. ",
+" .############. ",
+" .##########. ",
+" ..######.. ",
+" ...... "};
+
+
+
+
diff --git a/view/src/libicon/icon_rerun.cc b/view/src/libicon/icon_rerun.cc
new file mode 100644
index 0000000..3055fd4
--- /dev/null
+++ b/view/src/libicon/icon_rerun.cc
@@ -0,0 +1,39 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #1 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 3 1",
+" c #E5E5E5E5E5E5",
+". c #000000000000",
+"X c #F5F5F3F35454",
+" ",
+" ..... ",
+" ..XXXXX.. ",
+" .XXXXXXXXX. ",
+" .XXXXXXXXXXX. ",
+" .XXX.XXX.XXX. ",
+".XXX...X...XXX. ",
+".XXXX.XXX.XXXX. ",
+".XXXXXXXXXXXXX. ",
+".XXXXX...XXXXX. ",
+".XXXX.XXX.XXXX. ",
+" .XX.XXXXX.XX. ",
+" .XXXXXXXXXXX. ",
+" .XXXXXXXXX. ",
+" ..XXXXX.. ",
+" ..... "};
+static pixmap p("rerun",(const char**)bits);
diff --git a/view/src/libicon/icon_rerun.xpm b/view/src/libicon/icon_rerun.xpm
new file mode 100644
index 0000000..73d4f81
--- /dev/null
+++ b/view/src/libicon/icon_rerun.xpm
@@ -0,0 +1,37 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * rerun_xpm[] = {
+"16 16 3 1",
+" c #E5E5E5E5E5E5",
+". c #000000000000",
+"X c #F5F5F3F35454",
+" ",
+" ..... ",
+" ..XXXXX.. ",
+" .XXXXXXXXX. ",
+" .XXXXXXXXXXX. ",
+" .XXX.XXX.XXX. ",
+".XXX...X...XXX. ",
+".XXXX.XXX.XXXX. ",
+".XXXXXXXXXXXXX. ",
+".XXXXX...XXXXX. ",
+".XXXX.XXX.XXXX. ",
+" .XX.XXXXX.XX. ",
+" .XXXXXXXXXXX. ",
+" .XXXXXXXXX. ",
+" ..XXXXX.. ",
+" ..... "};
diff --git a/view/src/libicon/icon_waiting.cc b/view/src/libicon/icon_waiting.cc
new file mode 100644
index 0000000..1810277
--- /dev/null
+++ b/view/src/libicon/icon_waiting.cc
@@ -0,0 +1,38 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "pixmap.h"
+/* XPM */
+static const char * bits[] = {
+"16 16 2 1",
+" c #E5E5E5E5E5E5",
+". c #000000000000",
+" ",
+" .......",
+" .. ...",
+" . .. ",
+" .. ",
+" .. ",
+" .... .. ",
+" . . .. .",
+" . ... ..",
+" . .......",
+" . . ",
+" ... .... ",
+" . ",
+" . ",
+" ... ",
+" "};
+static pixmap p("waiting",(const char**)bits);
diff --git a/view/src/libicon/icon_waiting.xpm b/view/src/libicon/icon_waiting.xpm
new file mode 100644
index 0000000..d214afb
--- /dev/null
+++ b/view/src/libicon/icon_waiting.xpm
@@ -0,0 +1,36 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* XPM */
+static char * waiting_xpm[] = {
+"16 16 2 1",
+" c #E5E5E5E5E5E5",
+". c #000000000000",
+" ",
+" .......",
+" .. ...",
+" . .. ",
+" .. ",
+" .. ",
+" .... .. ",
+" . . .. .",
+" . ... ..",
+" . .......",
+" . . ",
+" ... .... ",
+" . ",
+" . ",
+" ... ",
+" "};
diff --git a/ecflow_4_0_7/view/src/libicon/xpm2cc b/view/src/libicon/xpm2cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libicon/xpm2cc
rename to view/src/libicon/xpm2cc
diff --git a/view/src/libui/uiask.cc b/view/src/libui/uiask.cc
new file mode 100644
index 0000000..724e57f
--- /dev/null
+++ b/view/src/libui/uiask.cc
@@ -0,0 +1,86 @@
+/*
+** Generated by X-Designer
+*/
+/*
+**LIBS: -lXm -lXt -lX11
+*/
+
+#include <stdlib.h>
+#include <X11/Xatom.h>
+#include <X11/Intrinsic.h>
+#include <X11/Shell.h>
+
+#include <Xm/Xm.h>
+#include <Xm/DialogS.h>
+#include <Xm/MessageB.h>
+#include <Xm/TextF.h>
+#include <Xm/LabelG.h>
+#include <Xm/PushBG.h>
+#include <Xm/SeparatoG.h>
+
+
+#include "uiask.h"
+
+ask_shell_p ask_shell = (ask_shell_p) NULL;
+
+
+
+void ask_shell_c::create (Widget parent, char *widget_name)
+{
+ Widget children[7]; /* Children to manage */
+ Arg al[64]; /* Arg List */
+ register int ac = 0; /* Arg Count */
+ // Widget button20 = (Widget)NULL; /* 20150819 */
+ Widget button21 = (Widget)NULL;
+ // Widget button22 = (Widget)NULL;
+
+ if ( !widget_name )
+ widget_name = "ask_shell";
+
+ XtSetArg(al[ac], XmNallowShellResize, TRUE); ac++;
+ XtSetArg(al[ac], XmNtransient, TRUE); ac++;
+ ask_shell = XmCreateDialogShell ( parent, widget_name, al, ac );
+ ac = 0;
+ _xd_rootwidget = ask_shell;
+ XtSetArg(al[ac], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); ac++;
+ XtSetArg(al[ac], XmNdialogType, XmDIALOG_QUESTION); ac++;
+ XtSetArg(al[ac], XmNmessageAlignment, XmALIGNMENT_CENTER); ac++;
+ XtSetArg(al[ac], XmNdefaultButtonType, XmDIALOG_CANCEL_BUTTON); ac++;
+ form_ = XmCreateMessageBox ( ask_shell, "form_", al, ac );
+ ac = 0;
+ // button20 =
+ XmMessageBoxGetChild ( form_, XmDIALOG_CANCEL_BUTTON );
+ button21 = XmMessageBoxGetChild ( form_, XmDIALOG_HELP_BUTTON );
+ label_ = XmMessageBoxGetChild ( form_, XmDIALOG_MESSAGE_LABEL );
+ // button22 =
+ XmMessageBoxGetChild ( form_, XmDIALOG_OK_BUTTON );
+ XtSetArg(al[ac], XmNsensitive, FALSE); ac++;
+ XtSetValues ( button21,al, ac );
+ ac = 0;
+ value_ = XmCreateTextField ( form_, "value_", al, ac );
+ XtAddCallback (form_, XmNokCallback,&ask_shell_c:: okCB, (XtPointer) this);
+ XtAddCallback (form_, XmNcancelCallback,&ask_shell_c:: cancelCB, (XtPointer) this);
+ XtAddCallback (form_, XmNhelpCallback,&ask_shell_c:: helpCB, (XtPointer) this);
+ children[ac++] = value_;
+ XtManageChildren(children, ac);
+ ac = 0;
+}
+
+void ask_shell_c::helpCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ ask_shell_p instance = (ask_shell_p) client_data;
+ instance->helpCB ( widget, call_data );
+}
+
+void ask_shell_c::cancelCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ ask_shell_p instance = (ask_shell_p) client_data;
+ instance->cancelCB ( widget, call_data );
+}
+
+void ask_shell_c::okCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ ask_shell_p instance = (ask_shell_p) client_data;
+ instance->okCB ( widget, call_data );
+}
+
diff --git a/ecflow_4_0_7/view/src/libui/uiask.h b/view/src/libui/uiask.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uiask.h
rename to view/src/libui/uiask.h
diff --git a/ecflow_4_0_7/view/src/libui/uicollector.cc b/view/src/libui/uicollector.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uicollector.cc
rename to view/src/libui/uicollector.cc
diff --git a/ecflow_4_0_7/view/src/libui/uicollector.h b/view/src/libui/uicollector.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uicollector.h
rename to view/src/libui/uicollector.h
diff --git a/ecflow_4_0_7/view/src/libui/uicolors.cc b/view/src/libui/uicolors.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uicolors.cc
rename to view/src/libui/uicolors.cc
diff --git a/ecflow_4_0_7/view/src/libui/uicolors.h b/view/src/libui/uicolors.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uicolors.h
rename to view/src/libui/uicolors.h
diff --git a/view/src/libui/uiconfirm.cc b/view/src/libui/uiconfirm.cc
new file mode 100644
index 0000000..54eeed5
--- /dev/null
+++ b/view/src/libui/uiconfirm.cc
@@ -0,0 +1,81 @@
+/*
+** Generated by X-Designer
+*/
+/*
+**LIBS: -lXm -lXt -lX11
+*/
+
+#include <stdlib.h>
+#include <X11/Xatom.h>
+#include <X11/Intrinsic.h>
+#include <X11/Shell.h>
+
+#include <Xm/Xm.h>
+#include <Xm/DialogS.h>
+#include <Xm/MessageB.h>
+#include <Xm/LabelG.h>
+#include <Xm/PushBG.h>
+#include <Xm/SeparatoG.h>
+
+
+#include "uiconfirm.h"
+
+confirm_shell_p confirm_shell = (confirm_shell_p) NULL;
+
+
+
+void confirm_shell_c::create (Widget parent, char *widget_name)
+{
+ /* Widget children[6]; // Children to manage */
+ Arg al[64]; /* Arg List */
+ register int ac = 0; /* Arg Count */
+ // Widget button20 = (Widget)NULL;
+ Widget button21 = (Widget)NULL;
+ // Widget button22 = (Widget)NULL;
+
+ if ( !widget_name )
+ widget_name = "confirm_shell";
+
+ XtSetArg(al[ac], XmNallowShellResize, TRUE); ac++;
+ XtSetArg(al[ac], XmNtransient, TRUE); ac++;
+ confirm_shell = XmCreateDialogShell ( parent, widget_name, al, ac );
+ ac = 0;
+ _xd_rootwidget = confirm_shell;
+ XtSetArg(al[ac], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); ac++;
+ XtSetArg(al[ac], XmNdialogType, XmDIALOG_QUESTION); ac++;
+ XtSetArg(al[ac], XmNmessageAlignment, XmALIGNMENT_CENTER); ac++;
+ XtSetArg(al[ac], XmNdefaultButtonType, XmDIALOG_CANCEL_BUTTON); ac++;
+ form_ = XmCreateMessageBox ( confirm_shell, "form_", al, ac );
+ ac = 0;
+ // button20 =
+ XmMessageBoxGetChild ( form_, XmDIALOG_CANCEL_BUTTON );
+ button21 = XmMessageBoxGetChild ( form_, XmDIALOG_HELP_BUTTON );
+ label_ = XmMessageBoxGetChild ( form_, XmDIALOG_MESSAGE_LABEL );
+ // button22 =
+ XmMessageBoxGetChild ( form_, XmDIALOG_OK_BUTTON );
+ XtSetArg(al[ac], XmNsensitive, FALSE); ac++;
+ XtSetValues ( button21,al, ac );
+ ac = 0;
+ XtAddCallback (form_, XmNhelpCallback,&confirm_shell_c:: helpCB, (XtPointer) this);
+ XtAddCallback (form_, XmNcancelCallback,&confirm_shell_c:: cancelCB, (XtPointer) this);
+ XtAddCallback (form_, XmNokCallback,&confirm_shell_c:: okCB, (XtPointer) this);
+}
+
+void confirm_shell_c::helpCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ confirm_shell_p instance = (confirm_shell_p) client_data;
+ instance->helpCB ( widget, call_data );
+}
+
+void confirm_shell_c::cancelCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ confirm_shell_p instance = (confirm_shell_p) client_data;
+ instance->cancelCB ( widget, call_data );
+}
+
+void confirm_shell_c::okCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ confirm_shell_p instance = (confirm_shell_p) client_data;
+ instance->okCB ( widget, call_data );
+}
+
diff --git a/ecflow_4_0_7/view/src/libui/uiconfirm.h b/view/src/libui/uiconfirm.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uiconfirm.h
rename to view/src/libui/uiconfirm.h
diff --git a/ecflow_4_0_7/view/src/libui/uidepend.cc b/view/src/libui/uidepend.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uidepend.cc
rename to view/src/libui/uidepend.cc
diff --git a/ecflow_4_0_7/view/src/libui/uidepend.h b/view/src/libui/uidepend.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uidepend.h
rename to view/src/libui/uidepend.h
diff --git a/ecflow_4_0_7/view/src/libui/uiedit.cc b/view/src/libui/uiedit.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uiedit.cc
rename to view/src/libui/uiedit.cc
diff --git a/ecflow_4_0_7/view/src/libui/uiedit.h b/view/src/libui/uiedit.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uiedit.h
rename to view/src/libui/uiedit.h
diff --git a/view/src/libui/uiedit_label.cc b/view/src/libui/uiedit_label.cc
new file mode 100644
index 0000000..434ab60
--- /dev/null
+++ b/view/src/libui/uiedit_label.cc
@@ -0,0 +1,141 @@
+/*
+** Generated by X-Designer
+*/
+/*
+**LIBS: -lXm -lXt -lX11
+*/
+
+#include <stdlib.h>
+#include <X11/Xatom.h>
+#include <X11/Intrinsic.h>
+#include <X11/Shell.h>
+
+#include <Xm/Xm.h>
+#include <Xm/DialogS.h>
+#include <Xm/Form.h>
+#include <Xm/Frame.h>
+#include <Xm/Label.h>
+#include <Xm/PushB.h>
+#include <Xm/RowColumn.h>
+#include <Xm/ScrollBar.h>
+#include <Xm/Text.h>
+
+
+#include "uiedit_label.h"
+
+edit_label_p edit_label_form = (edit_label_p) NULL;
+
+
+
+void edit_label_form_c::create (Widget parent, char *widget_name)
+{
+ Widget children[3]; /* Children to manage */
+ Arg al[64]; /* Arg List */
+ register int ac = 0; /* Arg Count */
+ Widget button1 = (Widget)NULL;
+ Widget form1 = (Widget)NULL;
+ Widget frame1 = (Widget)NULL;
+ Widget scrolledText1 = (Widget)NULL;
+ Widget label1 = (Widget)NULL;
+ Widget frame2 = (Widget)NULL;
+ Widget scrolledText2 = (Widget)NULL;
+ Widget label2 = (Widget)NULL;
+
+ if ( !widget_name )
+ widget_name = "edit_label_form";
+
+ XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
+ edit_label_form = XmCreateForm ( parent, widget_name, al, ac );
+ ac = 0;
+ _xd_rootwidget = edit_label_form;
+ tools_ = XmCreateRowColumn ( edit_label_form, "tools_", al, ac );
+ button1 = XmCreatePushButton ( tools_, "Apply", al, ac );
+ form1 = XmCreateForm ( edit_label_form, "form1", al, ac );
+ frame1 = XmCreateFrame ( form1, "frame1", al, ac );
+ XtSetArg(al[ac], XmNeditMode, XmMULTI_LINE_EDIT); ac++;
+ value_ = XmCreateScrolledText ( frame1, "value_", al, ac );
+ ac = 0;
+ scrolledText1 = XtParent ( value_ );
+
+ XtSetArg(al[ac], XmNchildType, XmFRAME_TITLE_CHILD); ac++;
+ label1 = XmCreateLabel ( frame1, "Value:", al, ac );
+ ac = 0;
+ frame2 = XmCreateFrame ( form1, "frame2", al, ac );
+ XtSetArg(al[ac], XmNsensitive, FALSE); ac++;
+ XtSetArg(al[ac], XmNeditable, FALSE); ac++;
+ XtSetArg(al[ac], XmNeditMode, XmMULTI_LINE_EDIT); ac++;
+ default_ = XmCreateScrolledText ( frame2, "default_", al, ac );
+ ac = 0;
+ scrolledText2 = XtParent ( default_ );
+
+ XtSetArg(al[ac], XmNchildType, XmFRAME_TITLE_CHILD); ac++;
+ label2 = XmCreateLabel ( frame2, "Default:", al, ac );
+ ac = 0;
+
+ XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
+ XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+ XtSetValues ( tools_,al, ac );
+ ac = 0;
+
+ XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
+ XtSetArg(al[ac], XmNtopWidget, tools_); ac++;
+ XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+ XtSetValues ( form1,al, ac );
+ ac = 0;
+ XtAddCallback (button1, XmNactivateCallback,&edit_label_form_c:: applyCB, (XtPointer) this);
+ children[ac++] = button1;
+ XtManageChildren(children, ac);
+ ac = 0;
+
+ XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_POSITION); ac++;
+ XtSetArg(al[ac], XmNbottomPosition, 50); ac++;
+ XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+ XtSetValues ( frame1,al, ac );
+ ac = 0;
+
+ XtSetArg(al[ac], XmNtopAttachment, XmATTACH_POSITION); ac++;
+ XtSetArg(al[ac], XmNtopPosition, 50); ac++;
+ XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+ XtSetValues ( frame2,al, ac );
+ ac = 0;
+ XtAddCallback (value_, XmNvalueChangedCallback,&edit_label_form_c:: changedCB, (XtPointer) this);
+ XtManageChild(value_);
+ children[ac++] = label1;
+ children[ac++] = scrolledText1; /* 20150819 */
+ children[ac++] = scrolledText2; /* 20150819 */
+ XtManageChildren(children, ac);
+ ac = 0;
+ XtAddCallback (default_, XmNvalueChangedCallback,&edit_label_form_c:: changedCB, (XtPointer) this);
+ XtManageChild(default_);
+ children[ac++] = label2;
+ XtManageChildren(children, ac);
+ ac = 0;
+ children[ac++] = frame1;
+ children[ac++] = frame2;
+ XtManageChildren(children, ac);
+ ac = 0;
+ children[ac++] = tools_;
+ children[ac++] = form1;
+ XtManageChildren(children, ac);
+ ac = 0;
+}
+
+void edit_label_form_c::changedCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ edit_label_form_p instance = (edit_label_form_p) client_data;
+ instance->changedCB ( widget, call_data );
+}
+
+void edit_label_form_c::applyCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ edit_label_form_p instance = (edit_label_form_p) client_data;
+ instance->applyCB ( widget, call_data );
+}
+
diff --git a/ecflow_4_0_7/view/src/libui/uiedit_label.h b/view/src/libui/uiedit_label.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uiedit_label.h
rename to view/src/libui/uiedit_label.h
diff --git a/ecflow_4_0_7/view/src/libui/uiedit_limit.cc b/view/src/libui/uiedit_limit.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uiedit_limit.cc
rename to view/src/libui/uiedit_limit.cc
diff --git a/ecflow_4_0_7/view/src/libui/uiedit_limit.h b/view/src/libui/uiedit_limit.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uiedit_limit.h
rename to view/src/libui/uiedit_limit.h
diff --git a/ecflow_4_0_7/view/src/libui/uiedit_meter.cc b/view/src/libui/uiedit_meter.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uiedit_meter.cc
rename to view/src/libui/uiedit_meter.cc
diff --git a/ecflow_4_0_7/view/src/libui/uiedit_meter.h b/view/src/libui/uiedit_meter.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uiedit_meter.h
rename to view/src/libui/uiedit_meter.h
diff --git a/ecflow_4_0_7/view/src/libui/uiedit_repeat.cc b/view/src/libui/uiedit_repeat.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uiedit_repeat.cc
rename to view/src/libui/uiedit_repeat.cc
diff --git a/ecflow_4_0_7/view/src/libui/uiedit_repeat.h b/view/src/libui/uiedit_repeat.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uiedit_repeat.h
rename to view/src/libui/uiedit_repeat.h
diff --git a/ecflow_4_0_7/view/src/libui/uiedit_variable.cc b/view/src/libui/uiedit_variable.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uiedit_variable.cc
rename to view/src/libui/uiedit_variable.cc
diff --git a/ecflow_4_0_7/view/src/libui/uiedit_variable.h b/view/src/libui/uiedit_variable.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uiedit_variable.h
rename to view/src/libui/uiedit_variable.h
diff --git a/view/src/libui/uierror.cc b/view/src/libui/uierror.cc
new file mode 100644
index 0000000..75c4261
--- /dev/null
+++ b/view/src/libui/uierror.cc
@@ -0,0 +1,73 @@
+/*
+** Generated by X-Designer
+*/
+/*
+**LIBS: -lXm -lXt -lX11
+*/
+
+#include <stdlib.h>
+#include <X11/Xatom.h>
+#include <X11/Intrinsic.h>
+#include <X11/Shell.h>
+
+#include <Xm/Xm.h>
+#include <Xm/DialogS.h>
+#include <Xm/MessageB.h>
+#include <Xm/LabelG.h>
+#include <Xm/PushBG.h>
+#include <Xm/SeparatoG.h>
+
+
+#include "uierror.h"
+
+error_shell_p error_shell = (error_shell_p) NULL;
+
+
+
+void error_shell_c::create (Widget parent, char *widget_name)
+{
+ /* Widget children[6]; // Children to manage */
+ Arg al[64]; /* Arg List */
+ register int ac = 0; /* Arg Count */
+ Widget button28 = (Widget)NULL;
+ Widget button30 = (Widget)NULL;
+
+ if ( !widget_name )
+ widget_name = "error_shell";
+
+ XtSetArg(al[ac], XmNallowShellResize, TRUE); ac++;
+ XtSetArg(al[ac], XmNtransient, TRUE); ac++;
+ error_shell = XmCreateDialogShell ( parent, widget_name, al, ac );
+ ac = 0;
+ _xd_rootwidget = error_shell;
+ XtSetArg(al[ac], XmNdialogType, XmDIALOG_ERROR); ac++;
+ form_ = XmCreateMessageBox ( error_shell, "form_", al, ac );
+ ac = 0;
+ button28 = XmMessageBoxGetChild ( form_, XmDIALOG_CANCEL_BUTTON );
+ label_ = XmMessageBoxGetChild ( form_, XmDIALOG_MESSAGE_LABEL );
+ button30 = XmMessageBoxGetChild ( form_, XmDIALOG_OK_BUTTON );
+ XtAddCallback (form_, XmNokCallback,&error_shell_c:: okCB, (XtPointer) this);
+ XtAddCallback (form_, XmNcancelCallback,&error_shell_c:: cancelCB, (XtPointer) this);
+ XtAddCallback (form_, XmNhelpCallback,&error_shell_c:: helpCB, (XtPointer) this);
+ XtUnmanageChild ( button28 );
+ XtUnmanageChild ( button30 );
+}
+
+void error_shell_c::helpCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ error_shell_p instance = (error_shell_p) client_data;
+ instance->helpCB ( widget, call_data );
+}
+
+void error_shell_c::cancelCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ error_shell_p instance = (error_shell_p) client_data;
+ instance->cancelCB ( widget, call_data );
+}
+
+void error_shell_c::okCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ error_shell_p instance = (error_shell_p) client_data;
+ instance->okCB ( widget, call_data );
+}
+
diff --git a/ecflow_4_0_7/view/src/libui/uierror.h b/view/src/libui/uierror.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uierror.h
rename to view/src/libui/uierror.h
diff --git a/ecflow_4_0_7/view/src/libui/uifind.cc b/view/src/libui/uifind.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uifind.cc
rename to view/src/libui/uifind.cc
diff --git a/ecflow_4_0_7/view/src/libui/uifind.h b/view/src/libui/uifind.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uifind.h
rename to view/src/libui/uifind.h
diff --git a/ecflow_4_0_7/view/src/libui/uifonts.cc b/view/src/libui/uifonts.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uifonts.cc
rename to view/src/libui/uifonts.cc
diff --git a/ecflow_4_0_7/view/src/libui/uifonts.h b/view/src/libui/uifonts.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uifonts.h
rename to view/src/libui/uifonts.h
diff --git a/view/src/libui/uifsb.cc b/view/src/libui/uifsb.cc
new file mode 100644
index 0000000..a1b5812
--- /dev/null
+++ b/view/src/libui/uifsb.cc
@@ -0,0 +1,80 @@
+/*
+** Generated by X-Designer
+*/
+/*
+**LIBS: -lXm -lXt -lX11
+*/
+
+#include <stdlib.h>
+#include <X11/Xatom.h>
+#include <X11/Intrinsic.h>
+#include <X11/Shell.h>
+
+#include <Xm/Xm.h>
+#include <Xm/DialogS.h>
+#include <Xm/FileSB.h>
+#include <Xm/Label.h>
+#include <Xm/List.h>
+#include <Xm/ScrollBar.h>
+#include <Xm/SelectioB.h>
+#include <Xm/TextF.h>
+#include <Xm/LabelG.h>
+#include <Xm/PushBG.h>
+#include <Xm/SeparatoG.h>
+
+
+#include "uifsb.h"
+
+fsb_shell_p fsb_shell = (fsb_shell_p) NULL;
+
+
+
+void fsb_shell_c::create (Widget parent, char *widget_name)
+{
+ Widget children[14]; /* Children to manage */
+ Arg al[64]; /* Arg List */
+ register int ac = 0; /* Arg Count */
+ Widget button42 = (Widget)NULL;
+ Widget button44 = (Widget)NULL;
+
+ if ( !widget_name )
+ widget_name = "fsb_shell";
+
+ XtSetArg(al[ac], XmNallowShellResize, TRUE); ac++;
+ fsb_shell = XmCreateDialogShell ( parent, widget_name, al, ac );
+ ac = 0;
+ _xd_rootwidget = fsb_shell;
+ XtSetArg(al[ac], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); ac++;
+ form_ = XmCreateFileSelectionBox ( fsb_shell, "form_", al, ac );
+ ac = 0;
+ button42 = XmSelectionBoxGetChild ( form_, XmDIALOG_CANCEL_BUTTON );
+ button44 = XmSelectionBoxGetChild ( form_, XmDIALOG_OK_BUTTON );
+ label_ = XmCreateLabel ( form_, "label_", al, ac );
+ XtAddCallback (form_, XmNokCallback,&fsb_shell_c:: okCB, (XtPointer) this);
+ XtAddCallback (form_, XmNcancelCallback,&fsb_shell_c:: cancelCB, (XtPointer) this);
+ XtAddCallback (form_, XmNhelpCallback,&fsb_shell_c:: helpCB, (XtPointer) this);
+ children[ac++] = label_;
+ children[ac++] = button42; /* 20150819 */
+ children[ac++] = button44; /* 20150819 */
+ XtManageChildren(children, ac);
+ ac = 0;
+}
+
+void fsb_shell_c::helpCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ fsb_shell_p instance = (fsb_shell_p) client_data;
+ instance->helpCB ( widget, call_data );
+}
+
+void fsb_shell_c::cancelCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ fsb_shell_p instance = (fsb_shell_p) client_data;
+ instance->cancelCB ( widget, call_data );
+}
+
+void fsb_shell_c::okCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ fsb_shell_p instance = (fsb_shell_p) client_data;
+ instance->okCB ( widget, call_data );
+}
+
diff --git a/ecflow_4_0_7/view/src/libui/uifsb.h b/view/src/libui/uifsb.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uifsb.h
rename to view/src/libui/uifsb.h
diff --git a/ecflow_4_0_7/view/src/libui/uihistory.cc b/view/src/libui/uihistory.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uihistory.cc
rename to view/src/libui/uihistory.cc
diff --git a/ecflow_4_0_7/view/src/libui/uihistory.h b/view/src/libui/uihistory.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uihistory.h
rename to view/src/libui/uihistory.h
diff --git a/ecflow_4_0_7/view/src/libui/uiinfo.cc b/view/src/libui/uiinfo.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uiinfo.cc
rename to view/src/libui/uiinfo.cc
diff --git a/ecflow_4_0_7/view/src/libui/uiinfo.h b/view/src/libui/uiinfo.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uiinfo.h
rename to view/src/libui/uiinfo.h
diff --git a/ecflow_4_0_7/view/src/libui/uijob.cc b/view/src/libui/uijob.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uijob.cc
rename to view/src/libui/uijob.cc
diff --git a/ecflow_4_0_7/view/src/libui/uijob.h b/view/src/libui/uijob.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uijob.h
rename to view/src/libui/uijob.h
diff --git a/ecflow_4_0_7/view/src/libui/uijobcheck.cc b/view/src/libui/uijobcheck.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uijobcheck.cc
rename to view/src/libui/uijobcheck.cc
diff --git a/ecflow_4_0_7/view/src/libui/uijobcheck.h b/view/src/libui/uijobcheck.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uijobcheck.h
rename to view/src/libui/uijobcheck.h
diff --git a/view/src/libui/uijobstatus.cc b/view/src/libui/uijobstatus.cc
new file mode 100644
index 0000000..caf947d
--- /dev/null
+++ b/view/src/libui/uijobstatus.cc
@@ -0,0 +1,150 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #1 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+/*
+** Generated by X-Designer // edited in the lack of X-Designer
+*/
+/*
+**LIBS: -lXm -lXt -lX11
+*/
+
+#include <stdlib.h>
+#include <X11/Xatom.h>
+#include <X11/Intrinsic.h>
+#include <X11/Shell.h>
+
+#include <Xm/Xm.h>
+#include <Xm/DialogS.h>
+#include <Xm/Form.h>
+#include <Xm/PushB.h>
+#include <Xm/RowColumn.h>
+#include <Xm/ScrollBar.h>
+#include <Xm/Text.h>
+#include <Xm/TextF.h>
+
+
+#include "uijobstatus.h"
+
+script_p jobstatus_form = (script_p) NULL;
+
+
+
+void jobstatus_form_c::create (Widget parent, char *widget_name)
+{
+ Widget children[4]; /* Children to manage */
+ Arg al[64]; /* Arg List */
+ register int ac = 0; /* Arg Count */
+ Widget scrolledText1 = (Widget)NULL;
+ Widget button2 = (Widget)NULL;
+ Widget button3 = (Widget)NULL;
+ Widget button1 = (Widget)NULL;
+
+ if ( !widget_name )
+ widget_name = "jobstatus_form";
+
+ XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
+ jobstatus_form = XmCreateForm ( parent, widget_name, al, ac );
+ ac = 0;
+ _xd_rootwidget = jobstatus_form;
+ XtSetArg(al[ac], XmNeditable, FALSE); ac++;
+ XtSetArg(al[ac], XmNcursorPositionVisible, FALSE); ac++;
+ XtSetArg(al[ac], XmNeditMode, XmMULTI_LINE_EDIT); ac++;
+ text_ = XmCreateScrolledText ( jobstatus_form, "text_", al, ac );
+ ac = 0;
+ scrolledText1 = XtParent ( text_ );
+
+ XtSetArg(al[ac], XmNhighlightThickness, 1); ac++;
+ XtSetArg(al[ac], XmNshadowThickness, 1); ac++;
+ XtSetArg(al[ac], XmNeditable, FALSE); ac++;
+ XtSetArg(al[ac], XmNcursorPositionVisible, FALSE); ac++;
+ name_ = XmCreateTextField ( jobstatus_form, "name_", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNspacing, 0); ac++;
+ XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
+ XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
+ XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++;
+ tools_ = XmCreateRowColumn ( jobstatus_form, "tools_", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
+ XtSetArg(al[ac], XmNmarginHeight, 2); ac++;
+ XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
+ button2 = XmCreatePushButton ( tools_, "Use external viewer", al, ac );
+ ac = 0;
+ button3 = XmCreatePushButton ( tools_, "Search", al, ac );
+ XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
+ XtSetArg(al[ac], XmNmarginHeight, 2); ac++;
+ XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
+ button1 = XmCreatePushButton ( tools_, "Update", al, ac );
+ ac = 0;
+
+ XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
+ XtSetArg(al[ac], XmNtopWidget, name_); ac++;
+ XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+ XtSetValues ( scrolledText1,al, ac );
+ ac = 0;
+
+ XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
+ XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNrightAttachment, XmATTACH_WIDGET); ac++;
+ XtSetArg(al[ac], XmNrightOffset, 0); ac++;
+ XtSetArg(al[ac], XmNrightWidget, tools_); ac++;
+ XtSetValues ( name_,al, ac );
+ ac = 0;
+
+ XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNtopOffset, 0); ac++;
+ XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
+ XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
+ XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNrightOffset, 0); ac++;
+ XtSetValues ( tools_,al, ac );
+ ac = 0;
+ XtManageChild(text_);
+ XtAddCallback (button2, XmNactivateCallback,&jobstatus_form_c:: externalCB, (XtPointer) this);
+ XtAddCallback (button3, XmNactivateCallback,&jobstatus_form_c:: searchCB, (XtPointer) this);
+ XtAddCallback (button1, XmNactivateCallback,&jobstatus_form_c:: updateCB, (XtPointer) this);
+ children[ac++] = button2;
+ children[ac++] = button3;
+ children[ac++] = button1;
+ XtManageChildren(children, ac);
+ ac = 0;
+ children[ac++] = name_;
+ children[ac++] = tools_;
+ XtManageChildren(children, ac);
+ ac = 0;
+}
+
+void jobstatus_form_c::searchCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ jobstatus_form_p instance = (jobstatus_form_p) client_data;
+ instance->searchCB ( widget, call_data );
+}
+
+void jobstatus_form_c::externalCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ jobstatus_form_p instance = (jobstatus_form_p) client_data;
+ instance->externalCB ( widget, call_data );
+}
+
+void jobstatus_form_c::updateCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ jobstatus_form_p instance = (jobstatus_form_p) client_data;
+ instance->updateCB ( widget, call_data );
+}
+
diff --git a/view/src/libui/uijobstatus.h b/view/src/libui/uijobstatus.h
new file mode 100644
index 0000000..d2e93b8
--- /dev/null
+++ b/view/src/libui/uijobstatus.h
@@ -0,0 +1,48 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#ifndef _uijobstatus_h
+#define _uijobstatus_h
+
+#define XD_MOTIF
+
+#include <xdclass.h>
+
+class jobstatus_form_c: public xd_XmForm_c {
+public:
+ virtual void create (Widget parent, char *widget_name = NULL);
+protected:
+ Widget jobstatus_form;
+ Widget text_;
+ Widget name_;
+ Widget tools_;
+public:
+ static void searchCB( Widget, XtPointer, XtPointer );
+ virtual void searchCB( Widget, XtPointer ) = 0;
+ static void externalCB( Widget, XtPointer, XtPointer );
+ virtual void externalCB( Widget, XtPointer ) = 0;
+ static void updateCB( Widget, XtPointer, XtPointer );
+ virtual void updateCB( Widget, XtPointer ) = 0;
+};
+
+typedef jobstatus_form_c *jobstatus_form_p;
+class script;
+typedef script *script_p;
+
+
+extern script_p jobstatus_form;
+
+
+#endif
diff --git a/ecflow_4_0_7/view/src/libui/uimail.cc b/view/src/libui/uimail.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uimail.cc
rename to view/src/libui/uimail.cc
diff --git a/ecflow_4_0_7/view/src/libui/uimail.h b/view/src/libui/uimail.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uimail.h
rename to view/src/libui/uimail.h
diff --git a/ecflow_4_0_7/view/src/libui/uimanual.cc b/view/src/libui/uimanual.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uimanual.cc
rename to view/src/libui/uimanual.cc
diff --git a/ecflow_4_0_7/view/src/libui/uimanual.h b/view/src/libui/uimanual.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uimanual.h
rename to view/src/libui/uimanual.h
diff --git a/view/src/libui/uimenu.cc b/view/src/libui/uimenu.cc
new file mode 100644
index 0000000..8a22a4a
--- /dev/null
+++ b/view/src/libui/uimenu.cc
@@ -0,0 +1,229 @@
+/*
+** Generated by X-Designer
+*/
+/*
+**LIBS: -lXm -lXt -lX11
+*/
+
+#include <stdlib.h>
+#include <X11/Xatom.h>
+#include <X11/Intrinsic.h>
+#include <X11/Shell.h>
+
+#include <Xm/Xm.h>
+#include <Xm/DialogS.h>
+#include <Xm/Form.h>
+#include <Xm/Label.h>
+#include <Xm/List.h>
+#include <Xm/PushB.h>
+#include <Xm/RowColumn.h>
+#include <Xm/ScrollBar.h>
+#include <Xm/Separator.h>
+#include <Xm/TextF.h>
+#include <Xm/CascadeBG.h>
+#include <Xm/LabelG.h>
+
+
+#include "uimenu.h"
+
+menu_form_p menu_form = (menu_form_p) NULL;
+
+
+
+void menu_form_c::create (Widget parent, char *widget_name)
+{
+ Widget children[4]; /* Children to manage */
+ Arg al[64]; /* Arg List */
+ register int ac = 0; /* Arg Count */
+ Widget scrolledList1 = (Widget)NULL;
+ Widget form1 = (Widget)NULL;
+ Widget rowcol1 = (Widget)NULL;
+ Widget rowcol2 = (Widget)NULL;
+ Widget label1 = (Widget)NULL;
+ Widget optionMenu1 = (Widget)NULL;
+ // Widget label2 = (Widget)NULL;
+ Widget cascade1 = (Widget)NULL;
+ Widget button1 = (Widget)NULL;
+ Widget button2 = (Widget)NULL;
+ Widget button3 = (Widget)NULL;
+ Widget button4 = (Widget)NULL;
+ Widget separator2 = (Widget)NULL;
+
+ if ( !widget_name )
+ widget_name = "Command menus";
+
+ XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
+ menu_form = XmCreateForm ( parent, widget_name, al, ac );
+ ac = 0;
+ _xd_rootwidget = menu_form;
+ XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
+ form_ = XmCreateForm ( menu_form, "form_", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNvisibleItemCount, 17); ac++;
+ XtSetArg(al[ac], XmNlistSizePolicy, XmCONSTANT); ac++;
+ list_ = XmCreateScrolledList ( form_, "list_", al, ac );
+ ac = 0;
+ scrolledList1 = XtParent ( list_ );
+
+ form1 = XmCreateForm ( form_, "form1", al, ac );
+ XtSetArg(al[ac], XmNentryAlignment, XmALIGNMENT_CENTER); ac++;
+ rowcol1 = XmCreateRowColumn ( form1, "rowcol1", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNsensitive, FALSE); ac++;
+ add_ = XmCreatePushButton ( rowcol1, "Add", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNsensitive, FALSE); ac++;
+ update_ = XmCreatePushButton ( rowcol1, "Update", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNsensitive, FALSE); ac++;
+ remove_ = XmCreatePushButton ( rowcol1, "Remove", al, ac );
+ ac = 0;
+ rowcol2 = XmCreateRowColumn ( form1, "rowcol2", al, ac );
+ label1 = XmCreateLabel ( rowcol2, "Title:", al, ac );
+ title_ = XmCreateTextField ( rowcol2, "title_", al, ac );
+ optionMenu1 = XmCreateOptionMenu ( rowcol2, "optionMenu1", al, ac );
+ // label2 = XmOptionLabelGadget ( optionMenu1 ); /* 20150819 */
+ cascade1 = XmOptionButtonGadget ( optionMenu1 );
+ actions_ = XmCreatePulldownMenu ( optionMenu1, "actions_", al, ac );
+ button1 = XmCreatePushButton ( actions_, "Ecf command", al, ac );
+ button2 = XmCreatePushButton ( actions_, "Separator", al, ac );
+ button3 = XmCreatePushButton ( actions_, "Window", al, ac );
+ button4 = XmCreatePushButton ( actions_, "Internal", al, ac );
+ separator2 = XmCreateSeparator ( form1, "separator2", al, ac );
+
+ XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+ XtSetValues ( form_,al, ac );
+ ac = 0;
+
+ XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNtopOffset, 5); ac++;
+ XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNbottomOffset, 5); ac++;
+ XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNleftOffset, 5); ac++;
+ XtSetArg(al[ac], XmNrightAttachment, XmATTACH_WIDGET); ac++;
+ XtSetArg(al[ac], XmNrightOffset, 5); ac++;
+ XtSetArg(al[ac], XmNrightWidget, form1); ac++;
+ XtSetValues ( scrolledList1,al, ac );
+ ac = 0;
+
+ XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNtopOffset, 5); ac++;
+ XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNbottomOffset, 5); ac++;
+ XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
+ XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNrightOffset, 5); ac++;
+ XtSetValues ( form1,al, ac );
+ ac = 0;
+
+ XtAddCallback (list_, XmNbrowseSelectionCallback,&menu_form_c:: browseCB, (XtPointer) this);
+ XtManageChild(list_);
+
+ XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
+ XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNbottomOffset, 0); ac++;
+ XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNleftOffset, 0); ac++;
+ XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNrightOffset, 0); ac++;
+ XtSetValues ( rowcol1,al, ac );
+ ac = 0;
+
+ XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNtopOffset, 0); ac++;
+ XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
+ XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNleftOffset, 0); ac++;
+ XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNrightOffset, 0); ac++;
+ XtSetValues ( rowcol2,al, ac );
+ ac = 0;
+
+ XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
+ XtSetArg(al[ac], XmNtopOffset, 0); ac++;
+ XtSetArg(al[ac], XmNtopWidget, rowcol2); ac++;
+ XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
+ XtSetArg(al[ac], XmNbottomOffset, 0); ac++;
+ XtSetArg(al[ac], XmNbottomWidget, rowcol1); ac++;
+ XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNleftOffset, 0); ac++;
+ XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNrightOffset, 0); ac++;
+ XtSetValues ( separator2,al, ac );
+ ac = 0;
+ XtAddCallback (add_, XmNactivateCallback,&menu_form_c:: addCB, (XtPointer) this);
+ XtAddCallback (update_, XmNactivateCallback,&menu_form_c:: updateCB, (XtPointer) this);
+ XtAddCallback (remove_, XmNactivateCallback,&menu_form_c:: removeCB, (XtPointer) this);
+ children[ac++] = add_;
+ children[ac++] = update_;
+ children[ac++] = remove_;
+ XtManageChildren(children, ac);
+ ac = 0;
+ XtAddCallback (title_, XmNvalueChangedCallback,&menu_form_c:: changedCB, (XtPointer) this);
+ children[ac++] = button1;
+ children[ac++] = button2;
+ children[ac++] = button3;
+ children[ac++] = button4;
+ XtManageChildren(children, ac);
+ ac = 0;
+ XtSetArg(al[ac], XmNsubMenuId, actions_); ac++;
+ XtSetValues ( cascade1, al, ac );
+ ac = 0;
+ children[ac++] = label1;
+ children[ac++] = title_;
+ children[ac++] = optionMenu1;
+ XtManageChildren(children, ac);
+ ac = 0;
+ children[ac++] = rowcol1;
+ children[ac++] = rowcol2;
+ children[ac++] = separator2;
+ XtManageChildren(children, ac);
+ ac = 0;
+ children[ac++] = form1;
+ XtManageChildren(children, ac);
+ ac = 0;
+ children[ac++] = form_;
+ XtManageChildren(children, ac);
+ ac = 0;
+}
+
+void menu_form_c::updateCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ menu_form_p instance = (menu_form_p) client_data;
+ instance->updateCB ( widget, call_data );
+}
+
+void menu_form_c::changedCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ menu_form_p instance = (menu_form_p) client_data;
+ instance->changedCB ( widget, call_data );
+}
+
+void menu_form_c::browseCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ menu_form_p instance = (menu_form_p) client_data;
+ instance->browseCB ( widget, call_data );
+}
+
+void menu_form_c::removeCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ menu_form_p instance = (menu_form_p) client_data;
+ instance->removeCB ( widget, call_data );
+}
+
+void menu_form_c::addCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ menu_form_p instance = (menu_form_p) client_data;
+ instance->addCB ( widget, call_data );
+}
+
+void menu_form_c::menuCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ menu_form_p instance = (menu_form_p) client_data;
+ instance->menuCB ( widget, call_data );
+}
+
diff --git a/ecflow_4_0_7/view/src/libui/uimenu.h b/view/src/libui/uimenu.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uimenu.h
rename to view/src/libui/uimenu.h
diff --git a/ecflow_4_0_7/view/src/libui/uimessages.cc b/view/src/libui/uimessages.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uimessages.cc
rename to view/src/libui/uimessages.cc
diff --git a/ecflow_4_0_7/view/src/libui/uimessages.h b/view/src/libui/uimessages.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uimessages.h
rename to view/src/libui/uimessages.h
diff --git a/ecflow_4_0_7/view/src/libui/uinode_alert.cc b/view/src/libui/uinode_alert.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uinode_alert.cc
rename to view/src/libui/uinode_alert.cc
diff --git a/ecflow_4_0_7/view/src/libui/uinode_alert.h b/view/src/libui/uinode_alert.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uinode_alert.h
rename to view/src/libui/uinode_alert.h
diff --git a/ecflow_4_0_7/view/src/libui/uioption.cc b/view/src/libui/uioption.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uioption.cc
rename to view/src/libui/uioption.cc
diff --git a/ecflow_4_0_7/view/src/libui/uioption.h b/view/src/libui/uioption.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uioption.h
rename to view/src/libui/uioption.h
diff --git a/ecflow_4_0_7/view/src/libui/uioutput.cc b/view/src/libui/uioutput.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uioutput.cc
rename to view/src/libui/uioutput.cc
diff --git a/ecflow_4_0_7/view/src/libui/uioutput.h b/view/src/libui/uioutput.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uioutput.h
rename to view/src/libui/uioutput.h
diff --git a/ecflow_4_0_7/view/src/libui/uipanel.cc b/view/src/libui/uipanel.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uipanel.cc
rename to view/src/libui/uipanel.cc
diff --git a/ecflow_4_0_7/view/src/libui/uipanel.h b/view/src/libui/uipanel.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uipanel.h
rename to view/src/libui/uipanel.h
diff --git a/ecflow_4_0_7/view/src/libui/uipasswd.cc b/view/src/libui/uipasswd.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uipasswd.cc
rename to view/src/libui/uipasswd.cc
diff --git a/ecflow_4_0_7/view/src/libui/uipasswd.h b/view/src/libui/uipasswd.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uipasswd.h
rename to view/src/libui/uipasswd.h
diff --git a/ecflow_4_0_7/view/src/libui/uipref.cc b/view/src/libui/uipref.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uipref.cc
rename to view/src/libui/uipref.cc
diff --git a/ecflow_4_0_7/view/src/libui/uipref.h b/view/src/libui/uipref.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uipref.h
rename to view/src/libui/uipref.h
diff --git a/ecflow_4_0_7/view/src/libui/uiscript.cc b/view/src/libui/uiscript.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uiscript.cc
rename to view/src/libui/uiscript.cc
diff --git a/ecflow_4_0_7/view/src/libui/uiscript.h b/view/src/libui/uiscript.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uiscript.h
rename to view/src/libui/uiscript.h
diff --git a/ecflow_4_0_7/view/src/libui/uisearch.cc b/view/src/libui/uisearch.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uisearch.cc
rename to view/src/libui/uisearch.cc
diff --git a/ecflow_4_0_7/view/src/libui/uisearch.h b/view/src/libui/uisearch.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uisearch.h
rename to view/src/libui/uisearch.h
diff --git a/ecflow_4_0_7/view/src/libui/uiservers.cc b/view/src/libui/uiservers.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uiservers.cc
rename to view/src/libui/uiservers.cc
diff --git a/ecflow_4_0_7/view/src/libui/uiservers.h b/view/src/libui/uiservers.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uiservers.h
rename to view/src/libui/uiservers.h
diff --git a/ecflow_4_0_7/view/src/libui/uisuites.cc b/view/src/libui/uisuites.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uisuites.cc
rename to view/src/libui/uisuites.cc
diff --git a/ecflow_4_0_7/view/src/libui/uisuites.h b/view/src/libui/uisuites.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uisuites.h
rename to view/src/libui/uisuites.h
diff --git a/ecflow_4_0_7/view/src/libui/uitimetable.cc b/view/src/libui/uitimetable.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uitimetable.cc
rename to view/src/libui/uitimetable.cc
diff --git a/ecflow_4_0_7/view/src/libui/uitimetable.h b/view/src/libui/uitimetable.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uitimetable.h
rename to view/src/libui/uitimetable.h
diff --git a/ecflow_4_0_7/view/src/libui/uitip.cc b/view/src/libui/uitip.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uitip.cc
rename to view/src/libui/uitip.cc
diff --git a/ecflow_4_0_7/view/src/libui/uitip.h b/view/src/libui/uitip.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uitip.h
rename to view/src/libui/uitip.h
diff --git a/view/src/libui/uitop.cc b/view/src/libui/uitop.cc
new file mode 100644
index 0000000..349e5c6
--- /dev/null
+++ b/view/src/libui/uitop.cc
@@ -0,0 +1,1056 @@
+/*
+** Generated by X-Designer
+*/
+/*
+**LIBS: -lXm -lXt -lX11
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <X11/Xatom.h>
+#include <X11/Intrinsic.h>
+#include <X11/Shell.h>
+
+#include <Xm/Xm.h>
+#include <Xm/RepType.h>
+#include <Xm/CascadeB.h>
+#include <Xm/DialogS.h>
+#include <Xm/DrawingA.h>
+#include <Xm/Form.h>
+#include <Xm/Label.h>
+#include <Xm/PushB.h>
+#include <Xm/RowColumn.h>
+#include <Xm/ScrollBar.h>
+#include <Xm/ScrolledW.h>
+#include <Xm/Separator.h>
+#include <Xm/ToggleB.h>
+#include <Xm/PushBG.h>
+
+#define XDESIGNER
+#include "ecflowview.h"
+#include "SimpleTree.h"
+#include "show.h"
+#include "top.h"
+#include <Xm/Protocols.h>
+#define main xmain
+#include "Version.hpp"
+
+#include "uitop.h"
+
+XmStringCharSet char_set=XmSTRING_DEFAULT_CHARSET;
+
+void add_accelerator(Widget w,char * acc_text,char * key)
+/* adds an accelerator to a menu option. */
+{
+ int ac;
+ Arg al[10];
+
+ ac=0;
+ XtSetArg(al[ac],XmNacceleratorText,
+ XmStringCreate(acc_text,XmSTRING_DEFAULT_CHARSET)); ac++;
+ XtSetArg(al[ac],XmNaccelerator,key); ac++;
+ XtSetValues(w,al,ac);
+}
+/* */
+
+void XDmanage_link ( Widget, XtPointer client_data, XtPointer )
+{
+ if ( client_data && *(Widget *)client_data )
+ XtManageChild ( *(Widget *)client_data );
+}
+
+void XDunmanage_link ( Widget, XtPointer client_data, XtPointer )
+{
+ if ( client_data && *(Widget *)client_data )
+ XtUnmanageChild ( *(Widget *)client_data );
+}
+
+void XDpopup_link ( Widget, XtPointer client_data, XtPointer )
+{
+ if ( client_data && *(Widget *)client_data )
+ XtPopup ( *(Widget *)client_data, XtGrabNone );
+}
+
+void XDpopdown_link ( Widget, XtPointer client_data, XtPointer )
+{
+ if ( client_data && *(Widget *)client_data )
+ XtPopdown ( *(Widget *)client_data );
+}
+
+void XDmap_link ( Widget, XtPointer client_data, XtPointer )
+{
+ if ( client_data && *(Widget *)client_data )
+ XtMapWidget (*(Widget *)client_data);
+}
+
+void XDunmap_link ( Widget, XtPointer client_data, XtPointer )
+{
+ if ( client_data && *(Widget *)client_data )
+ XtUnmapWidget (*(Widget *)client_data);
+}
+
+void XDenable_link ( Widget, XtPointer client_data, XtPointer )
+{
+ if ( client_data && *(Widget *)client_data )
+ XtSetSensitive (*(Widget *)client_data, TRUE);
+}
+
+void XDdisable_link ( Widget, XtPointer client_data, XtPointer )
+{
+ if ( client_data && *(Widget *)client_data )
+ XtSetSensitive (*(Widget *)client_data, FALSE);
+}
+
+
+top_p top_shell = (top_p) NULL;
+
+
+
+void top_shell_c::create (Display *display, char *app_name, int app_argc, char **app_argv, char *app_class_name)
+{
+ Widget children[17]; /* Children to manage */
+ Arg al[64]; /* Arg List */
+ register int ac = 0; /* Arg Count */
+ XmString xmstrings[16]; /* temporary storage for XmStrings */
+ Widget form2 = (Widget)NULL;
+ Widget button184 = (Widget)NULL;
+ Widget button5 = (Widget)NULL;
+ Widget button10 = (Widget)NULL;
+ Widget button99 = (Widget)NULL;
+ Widget button4 = (Widget)NULL;
+ Widget button11 = (Widget)NULL;
+ Widget button9 = (Widget)NULL;
+ Widget button16 = (Widget)NULL;
+ Widget button13 = (Widget)NULL;
+ Widget button7 = (Widget)NULL;
+ Widget button14 = (Widget)NULL;
+ Widget button6 = (Widget)NULL;
+ Widget drawingArea1 = (Widget)NULL;
+ /* Widget button8 = (Widget)NULL; */
+ Widget button177 = (Widget)NULL;
+ Widget drawingArea2 = (Widget)NULL;
+ Widget button189 = (Widget)NULL;
+ Widget scrolledWin1 = (Widget)NULL;
+ Widget scrollbar61 = (Widget)NULL;
+ Widget scrollbar62 = (Widget)NULL;
+ Widget cascade55 = (Widget)NULL;
+ Widget menu52 = (Widget)NULL;
+ Widget button15 = (Widget)NULL;
+ Widget button1 = (Widget)NULL;
+ Widget separator3 = (Widget)NULL;
+ Widget button194 = (Widget)NULL;
+ Widget cascade1 = (Widget)NULL;
+ Widget menu1 = (Widget)NULL;
+ Widget button2 = (Widget)NULL;
+ Widget button3 = (Widget)NULL;
+ Widget separator7 = (Widget)NULL;
+ Widget button12 = (Widget)NULL;
+ Widget snapshot = (Widget)NULL;
+ Widget cascade56 = (Widget)NULL;
+ Widget separator64 = (Widget)NULL;
+ Widget separator65 = (Widget)NULL;
+ Widget cascade4 = (Widget)NULL;
+ Widget toggle15 = (Widget)NULL;
+ Widget toggle16 = (Widget)NULL;
+ Widget toggle17 = (Widget)NULL;
+ // Widget toggle18 = (Widget)NULL;
+ Widget toggle19 = (Widget)NULL;
+ Widget toggle20 = (Widget)NULL;
+ Widget cascade5 = (Widget)NULL;
+ Widget toggle7 = (Widget)NULL;
+ Widget toggle8 = (Widget)NULL;
+ Widget toggle9 = (Widget)NULL;
+ Widget toggle10 = (Widget)NULL;
+ Widget toggle11 = (Widget)NULL;
+ Widget toggle12 = (Widget)NULL;
+ Widget toggle13 = (Widget)NULL;
+ Widget toggle14 = (Widget)NULL;
+ Widget toggle39 = (Widget)NULL;
+ Widget toggle40 = (Widget)NULL;
+ Widget toggle73 = (Widget)NULL;
+ Widget toggle41 = (Widget)NULL;
+ Widget cascade6 = (Widget)NULL;
+ // Widget cascade7 = (Widget)NULL;
+ Widget toggle66 = (Widget)NULL;
+ Widget toggle67 = (Widget)NULL;
+ Widget toggle68 = (Widget)NULL;
+ Widget toggle69 = (Widget)NULL;
+ Widget toggle70 = (Widget)NULL;
+ // Widget toggle71 = (Widget)NULL;
+ Widget toggle72 = (Widget)NULL;
+ // Widget toggle74 = (Widget)NULL; Widget toggle75 = (Widget)NULL; Widget toggle76 = (Widget)NULL; Widget toggle77 = (Widget)NULL;
+ Widget toggle78 = (Widget)NULL;
+ Widget toggle79 = (Widget)NULL;
+ Widget cascade58 = (Widget)NULL;
+ Widget cascade3 = (Widget)NULL;
+ Widget menu53 = (Widget)NULL;
+ Widget button197 = (Widget)NULL;
+ Widget button198 = (Widget)NULL;
+ Widget separator5 = (Widget)NULL;
+
+ if ( !app_class_name )
+ app_class_name = appName;
+
+ std::string title = appName;
+ if (getenv("ECFLOWVIEW_TITLE"))
+ title = getenv("ECFLOWVIEW_TITLE");
+
+ title += " (" + ecf::Version::raw();
+#ifdef DEBUG
+ title += "-debug";
+#endif
+ title += ")";
+
+ XtSetArg(al[ac], XmNallowShellResize, FALSE); ac++;
+ XtSetArg(al[ac], XmNtitle, title.c_str()); ac++;
+ XtSetArg(al[ac], XmNiconName, appName); ac++;
+ XtSetArg(al[ac], XmNargc, app_argc); ac++;
+ XtSetArg(al[ac], XmNargv, app_argv); ac++;
+ top_shell = XtAppCreateShell ( app_name, app_class_name, applicationShellWidgetClass, display, al, ac );
+ ac = 0;
+ _xd_rootwidget = top_shell;
+ XmAddWMProtocolCallback( top_shell, XmInternAtom(XtDisplay(top_shell), "WM_DELETE_WINDOW", False),&top_shell_c:: quitCB, (XtPointer) this);
+ XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
+ form_ = XmCreateForm ( top_shell, "form_", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
+ form2 = XmCreateForm ( form_, "form2", al, ac );
+ ac = 0;
+ xmstrings[0] = XmStringCreateLtoR ( "-\n", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
+ message_ = XmCreateLabel ( form2, "message_", al, ac );
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNspacing, 0); ac++;
+ XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
+ XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
+ XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++;
+ XtSetArg(al[ac], XmNentryAlignment, XmALIGNMENT_CENTER); ac++;
+ tools_ = XmCreateRowColumn ( form2, "tools_", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
+ XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
+ XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
+
+ button184 = XmCreatePushButton ( tools_, "Info", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
+ XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
+ XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
+XtSetArg(al[ac],XmNmnemonic,'i'); ac++; /* mnemonic */
+
+
+ button5 = XmCreatePushButton ( tools_, "Script", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
+ XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
+ XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
+XtSetArg(al[ac],XmNmnemonic,'s'); ac++; /* mnemonic */
+
+ button10 = XmCreatePushButton ( tools_, "Manual", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
+ XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
+ XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
+XtSetArg(al[ac],XmNmnemonic,'m'); ac++; /* mnemonic */
+
+ button99 = XmCreatePushButton ( tools_, "Jobstatus", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
+ XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
+ XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
+ button4 = XmCreatePushButton ( tools_, "Output", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
+ XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
+ XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
+ button11 = XmCreatePushButton ( tools_, "Triggers", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
+ XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
+ XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
+ button9 = XmCreatePushButton ( tools_, "Why?", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
+ XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
+ XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
+ button16 = XmCreatePushButton ( tools_, "Check", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
+ XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
+ XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
+ button13 = XmCreatePushButton ( tools_, "Time line", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
+ XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
+ XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
+ button7 = XmCreatePushButton ( tools_, "Variables", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
+ XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
+ XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
+ button14 = XmCreatePushButton ( tools_, "Messages", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
+ XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
+ XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
+ button6 = XmCreatePushButton ( tools_, "Edit", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNwidth, 10); ac++;
+ XtSetArg(al[ac], XmNheight, 10); ac++;
+ drawingArea1 = XmCreateDrawingArea ( tools_, "drawingArea1", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
+ XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
+ XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
+ /* button8 = XmCreatePushButton ( tools_, "Chat", al, ac ); */
+ ac = 0;
+ XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
+ XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
+ XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
+ button177 = XmCreatePushButton ( tools_, "Search", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNwidth, 10); ac++;
+ XtSetArg(al[ac], XmNheight, 10); ac++;
+ drawingArea2 = XmCreateDrawingArea ( tools_, "drawingArea2", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
+ XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
+ XtSetArg(al[ac], XmNdefaultButtonShadowThickness, 0); ac++;
+ button189 = XmCreatePushButton ( tools_, "Status", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNscrollingPolicy, XmAUTOMATIC); ac++;
+ scrolledWin1 = XmCreateScrolledWindow ( form_, "scrolledWin1", al, ac );
+ ac = 0;
+
+ XtSetArg(al[ac], XmNhorizontalScrollBar, &scrollbar61 ); ac++;
+ XtSetArg(al[ac], XmNverticalScrollBar, &scrollbar62 ); ac++;
+ XtGetValues(scrolledWin1, al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
+ XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
+ trees_ = XmCreateRowColumn ( scrolledWin1, "trees_", al, ac );
+ ac = 0;
+ menu_bar = XmCreateMenuBar ( form_, "menu_bar", al, ac );
+
+ cascade55 = XmCreateCascadeButton ( menu_bar, "File", al, ac );
+
+ if (1) {
+ XmString label_str = XmStringCreateLocalized ("File");
+ XtSetArg(al[ac], XmNmnemonic, XStringToKeysym("F")); ac++;
+ XtSetArg(al[ac], XmNlabelString, label_str); ac++;
+ XtSetArg(al[ac], XmNaccelerator, "Ctrl<Key>F"); ac++;
+ XtSetArg(al[ac], XmNacceleratorText,
+ XmStringCreateLocalized("Ctrl+F")); ac++;
+ // XmStringFree(label_str);
+ }
+
+ XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++;
+ menu52 = XmCreatePulldownMenu ( menu_bar, "m_file", al, ac );
+ ac = 0;
+ button15 = XmCreatePushButton ( menu52, "Login", al, ac );
+ add_accelerator(button15, "Ctrl+L", "Ctrl<Key>L");
+
+ XtSetArg(al[ac], XmNsensitive, FALSE); ac++;
+ button1 = XmCreatePushButton ( menu52, "Scan network...", al, ac );
+ // add_accelerator(button1, "Ctrl+S", "Ctrl<Key>S");
+
+ XtSetArg(al[ac], XmNheight, 2); ac++;
+ XtSetArg(al[ac], XmNmargin, 0); ac++;
+ separator3 = XmCreateSeparator ( menu52, "separator3", al, ac );
+ ac = 0;
+ if (1) {
+ XmString label_str = XmStringCreateLocalized ("Quit");
+ XtSetArg(al[ac], XmNmnemonic, XStringToKeysym("Q")); ac++;
+ XtSetArg(al[ac], XmNlabelString, label_str); ac++;
+ XtSetArg(al[ac], XmNaccelerator, "Ctrl<Key>Q"); ac++;
+ XtSetArg(al[ac], XmNacceleratorText,
+ XmStringCreateLocalized("Ctrl+Q")); ac++;
+ }
+ button194 = XmCreatePushButtonGadget ( menu52, "Quit", al, ac );
+ // add_accelerator(button194, "Ctrl+Q", "Ctrl<Key>Q");
+
+ if (1) { ac = 0;
+ XmString label_str = XmStringCreateLocalized ("Edit");
+ XtSetArg(al[ac], XmNmnemonic, XStringToKeysym("E")); ac++;
+ XtSetArg(al[ac], XmNlabelString, label_str); ac++;
+ XtSetArg(al[ac], XmNaccelerator, "Ctrl<Key>E"); ac++;
+ XtSetArg(al[ac], XmNacceleratorText, XmStringCreateLocalized("Ctrl+E")); ac++;
+ }
+ cascade1 = XmCreateCascadeButton ( menu_bar, "Edit", al, ac );
+ // add_accelerator(cascade1, "Ctrl+E", "Ctrl<Key>E");
+
+ XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++;
+ menu1 = XmCreatePulldownMenu ( menu_bar, "menu1", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNsensitive, FALSE); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Servers menu...", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ button2 = XmCreatePushButton ( menu1, "button2", al, ac );
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNsensitive, FALSE); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Command menu...", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ button3 = XmCreatePushButton ( menu1, "button3", al, ac );
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ separator7 = XmCreateSeparator ( menu1, "separator7", al, ac );
+ xmstrings[0] = XmStringCreateLtoR ( "Preferences...", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ button12 = XmCreatePushButton ( menu1, "pref", al, ac );
+
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ // separator7 = XmCreateSeparator ( menu1, "separator7", al, ac );
+ xmstrings[0] = XmStringCreateLtoR ( "Snapshot", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ snapshot = XmCreatePushButton ( menu1, "snap", al, ac );
+
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+
+ cascade56 = XmCreateCascadeButton ( menu_bar, "Show", al, ac );
+ // add_accelerator(cascade56, "Ctrl<Key>S", "Ctrl+S");
+
+ XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++;
+ show0_ = XmCreatePulldownMenu ( menu_bar, "show0_", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNuserData, new show(show::unknown)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Unknown", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ show_unknown = XmCreateToggleButton ( show0_, "unknown", al, ac );
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::suspended)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Suspended", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ show_suspended = XmCreateToggleButton ( show0_, "suspended", al, ac );
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::complete)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Complete", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ show_complete = XmCreateToggleButton ( show0_, "complete", al, ac );
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::queued)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Queued", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ show_queued = XmCreateToggleButton ( show0_, "queued", al, ac );
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::submitted)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Submitted", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ show_submitted = XmCreateToggleButton ( show0_, "submitted", al, ac );
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::active)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Active", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ show_active = XmCreateToggleButton ( show0_, "active", al, ac );
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::aborted)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Aborted", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ show_aborted = XmCreateToggleButton ( show0_, "aborted", al, ac );
+
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ separator64 = XmCreateSeparator ( show0_, "separator64", al, ac );
+ cascade4 = XmCreateCascadeButton ( show0_, "Special", al, ac );
+ XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++;
+ show2_ = XmCreatePulldownMenu ( show0_, "show2_", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNuserData, new show(show::time_dependant)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Time dependent", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ toggle15 = XmCreateToggleButton ( show2_, "toggle15", al, ac );
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::late_nodes)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Late nodes", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ toggle16 = XmCreateToggleButton ( show2_, "toggle16", al, ac );
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::waiting_nodes)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Waiting nodes", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ toggle17 = XmCreateToggleButton ( show2_, "toggle17", al, ac );
+ /* ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::migrated_nodes)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Migrated nodes", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ toggle18 = XmCreateToggleButton ( show2_, "toggle18", al, ac ); */
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::rerun_tasks)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Rerun tasks", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ toggle19 = XmCreateToggleButton ( show2_, "toggle19", al, ac );
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::nodes_with_messages)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Nodes with messages", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ toggle20 = XmCreateToggleButton ( show2_, "toggle20", al, ac );
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ cascade5 = XmCreateCascadeButton ( show0_, "Type", al, ac );
+ XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++;
+ show1_ = XmCreatePulldownMenu ( show0_, "show1_", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNuserData, new show(show::label)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Labels", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ toggle7 = XmCreateToggleButton ( show1_, "toggle7", al, ac );
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::meter)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Meters", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ toggle8 = XmCreateToggleButton ( show1_, "toggle8", al, ac );
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::event)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Events", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ toggle9 = XmCreateToggleButton ( show1_, "toggle9", al, ac );
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::repeat)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Repeats", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ toggle10 = XmCreateToggleButton ( show1_, "toggle10", al, ac );
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::time)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Times", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ toggle11 = XmCreateToggleButton ( show1_, "toggle11", al, ac );
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::date)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Dates", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ toggle12 = XmCreateToggleButton ( show1_, "toggle12", al, ac );
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::trigger)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Triggers", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ toggle13 = XmCreateToggleButton ( show1_, "toggle13", al, ac );
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::variable)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Variables", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ toggle14 = XmCreateToggleButton ( show1_, "toggle14", al, ac );
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::genvar)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Generated variables", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ toggle39 = XmCreateToggleButton ( show1_, "toggle39", al, ac );
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::late)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Late", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ toggle40 = XmCreateToggleButton ( show1_, "toggle40", al, ac );
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::limit)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Limits", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ toggle73 = XmCreateToggleButton ( show1_, "toggle73", al, ac );
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::inlimit)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Limiters", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ toggle41 = XmCreateToggleButton ( show1_, "toggle41", al, ac );
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ cascade6 = XmCreateCascadeButton ( show0_, "Icons", al, ac );
+ XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++;
+ show3_ = XmCreatePulldownMenu ( show0_, "show3_", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNuserData, new show(show::time_icon)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Time icons", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ toggle66 = XmCreateToggleButton ( show3_, "time_icon", al, ac );
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::date_icon)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Date icons", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ toggle67 = XmCreateToggleButton ( show3_, "date_icon", al, ac );
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::late_icon)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Late icons", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ toggle68 = XmCreateToggleButton ( show3_, "late_icon", al, ac );
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::waiting_icon)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Waiting icons", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ toggle69 = XmCreateToggleButton ( show3_, "waiting_icon", al, ac );
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::rerun_icon)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Rerun icons", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ toggle70 = XmCreateToggleButton ( show3_, "rerun_icon", al, ac );
+ /* ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::migrated_icon)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Migrated icons", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ toggle71 = XmCreateToggleButton ( show3_, "migrated_icon", al, ac ); */
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::message_icon)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Message icons", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ toggle72 = XmCreateToggleButton ( show3_, "message_icon", al, ac );
+
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::defstatus_icon)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Complete icons", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ toggle78 = XmCreateToggleButton ( show3_, "defstatus_icon", al, ac );
+
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::zombie_icon)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Zombie icons", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ toggle79 = XmCreateToggleButton ( show3_, "zombie_icon", al, ac );
+
+ /* 20110125 */
+ separator65 = XmCreateSeparator ( show0_, "separator65", al, ac );
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::all)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "all", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ show_all = XmCreateToggleButton ( show0_, "all", al, ac );
+ // show_all = XmCreatePushButton ( show0_, "all", al, ac );
+ // XtAddCallback (show_all, XmNactivateCallback,&top_shell_c::show2CB, (XtPointer) this);
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNuserData, new show(show::none)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "none", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ show_none = XmCreateToggleButton ( show0_, "none", al, ac );
+ // show_none = XmCreatePushButton ( show0_, "none", al, ac );
+ // XtAddCallback (show_none, XmNactivateCallback,&top_shell_c::show2CB, (XtPointer) this);
+
+ /* ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ XtSetArg(al[ac], XmNsensitive, XCDP_COMPARE_ENABLED); ac++;
+ XtSetArg(al[ac], XmNsensitive, getenv("XCDP_COMPARE_ENABLED")); ac++;
+ cascade7 = XmCreateCascadeButton ( show0_, "Compare", al, ac );
+ XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++;
+ show4_ = XmCreatePulldownMenu ( show0_, "show4_", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNuserData, new show(show::compare_variables)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Variables", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ toggle75 = XmCreateToggleButton ( show4_, "compare_variables", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNuserData, new show(show::compare_scripts)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Scripts", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ toggle74 = XmCreateToggleButton ( show4_, "compare_scripts", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNuserData, new show(show::compare_includes)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Includes", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ toggle76 = XmCreateToggleButton ( show4_, "compare_includes", al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNuserData, new show(show::compare_outputs)); ac++;
+ xmstrings[0] = XmStringCreateLtoR ( "Outputs", (XmStringCharSet)XmFONTLIST_DEFAULT_TAG );
+ XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+ toggle77 = XmCreateToggleButton ( show4_, "compare_outputs", al, ac );
+ */
+ ac = 0;
+ XmStringFree ( xmstrings [ 0 ] );
+ cascade58 = XmCreateCascadeButton ( menu_bar, "Servers", al, ac );
+ XtSetArg(al[ac], XmNnumColumns, 3); ac++;
+ XtSetArg(al[ac], XmNpacking, XmPACK_COLUMN); ac++;
+ XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++;
+ XtSetArg(al[ac], XmNradioAlwaysOne, TRUE); ac++;
+ XtSetArg(al[ac], XmNradioBehavior, FALSE); ac++;
+ servers_menu_ = XmCreatePulldownMenu ( menu_bar, "servers_menu_", al, ac );
+ ac = 0;
+ cascade3 = XmCreateCascadeButton ( menu_bar, "Windows", al, ac );
+ XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++;
+ windows_menu_ = XmCreatePulldownMenu ( menu_bar, "windows_menu_", al, ac );
+ ac = 0;
+ help = XmCreateCascadeButton ( menu_bar, "Help", al, ac );
+ XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++;
+ menu53 = XmCreatePulldownMenu ( menu_bar, "menu53", al, ac );
+ ac = 0;
+ button197 = XmCreatePushButton ( menu53, "Help", al, ac );
+ XtSetArg(al[ac], XmNmenuHelpWidget, help); ac++;
+ button198 = XmCreatePushButton ( menu53, "Version", al, ac );
+ XtSetValues ( menu_bar,al, ac );
+
+ ac = 0;
+ separator5 = XmCreateSeparator ( form_, "separator5", al, ac );
+
+ XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
+ XtSetArg(al[ac], XmNtopOffset, 0); ac++;
+ XtSetArg(al[ac], XmNtopWidget, menu_bar); ac++;
+ XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
+ XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNleftOffset, 0); ac++;
+ XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+ XtSetValues ( form2,al, ac );
+ ac = 0;
+
+ XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
+ XtSetArg(al[ac], XmNtopWidget, separator5); ac++;
+ XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+ XtSetValues ( scrolledWin1,al, ac );
+ ac = 0;
+
+ XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNtopOffset, 0); ac++;
+ XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
+ XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNleftOffset, 0); ac++;
+ XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNrightOffset, 0); ac++;
+ XtSetValues ( menu_bar,al, ac );
+ ac = 0;
+
+ XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
+ XtSetArg(al[ac], XmNtopWidget, form2); ac++;
+ XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
+ XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+ XtSetValues ( separator5,al, ac );
+ ac = 0;
+
+ XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
+ XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNrightAttachment, XmATTACH_WIDGET); ac++;
+ XtSetArg(al[ac], XmNrightWidget, tools_); ac++;
+ XtSetValues ( message_,al, ac );
+ ac = 0;
+
+ XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
+ XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
+ XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+ XtSetValues ( tools_,al, ac );
+ ac = 0;
+ XtAddCallback (button184, XmNactivateCallback,&top_shell_c:: windowCB, (XtPointer) this);
+ XtAddCallback (button5, XmNactivateCallback,&top_shell_c:: windowCB, (XtPointer) this);
+ XtAddCallback (button10, XmNactivateCallback,&top_shell_c:: windowCB, (XtPointer) this);
+ XtAddCallback (button99, XmNactivateCallback,&top_shell_c:: windowCB, (XtPointer) this);
+ XtAddCallback (button4, XmNactivateCallback,&top_shell_c:: windowCB, (XtPointer) this);
+ XtAddCallback (button11, XmNactivateCallback,&top_shell_c:: windowCB, (XtPointer) this);
+ XtAddCallback (button9, XmNactivateCallback,&top_shell_c:: windowCB, (XtPointer) this);
+ XtAddCallback (button16, XmNactivateCallback,&top_shell_c:: windowCB, (XtPointer) this);
+ XtAddCallback (button13, XmNactivateCallback,&top_shell_c:: windowCB, (XtPointer) this);
+ XtAddCallback (button7, XmNactivateCallback,&top_shell_c:: windowCB, (XtPointer) this);
+ XtAddCallback (button14, XmNactivateCallback,&top_shell_c:: windowCB, (XtPointer) this);
+ XtAddCallback (button6, XmNactivateCallback,&top_shell_c:: windowCB, (XtPointer) this);
+ // XtAddCallback (button8, XmNactivateCallback,&top_shell_c:: chatCB, (XtPointer) this);
+ XtAddCallback (button177, XmNactivateCallback,&top_shell_c:: searchCB, (XtPointer) this);
+ XtAddCallback (button189, XmNactivateCallback,&top_shell_c:: statusCB, (XtPointer) this);
+ children[ac++] = button184;
+ children[ac++] = button5;
+ children[ac++] = button10;
+ children[ac++] = button99;
+ children[ac++] = button4;
+ children[ac++] = button11;
+ children[ac++] = button9;
+ children[ac++] = button16;
+ children[ac++] = button13;
+ children[ac++] = button7;
+ children[ac++] = button14;
+ children[ac++] = button6;
+ children[ac++] = drawingArea1;
+ /* children[ac++] = button8; */
+ children[ac++] = button177;
+ children[ac++] = drawingArea2;
+ children[ac++] = button189;
+ XtManageChildren(children, ac);
+ ac = 0;
+ children[ac++] = message_;
+ children[ac++] = tools_;
+ XtManageChildren(children, ac);
+ ac = 0;
+ children[ac++] = trees_;
+ XtManageChildren(children, ac);
+ ac = 0;
+ XmScrolledWindowSetAreas(scrolledWin1, scrollbar61, scrollbar62, trees_ );
+ XtAddCallback (button15, XmNactivateCallback,&top_shell_c:: loginCB, (XtPointer) this);
+ XtAddCallback (button1, XmNactivateCallback,&top_shell_c:: serverCB, (XtPointer) this);
+ XtAddCallback (button194, XmNactivateCallback,&top_shell_c:: quitCB, (XtPointer) this);
+ children[ac++] = button15;
+ children[ac++] = button1;
+ children[ac++] = separator3;
+ children[ac++] = button194;
+ XtManageChildren(children, ac);
+ ac = 0;
+ XtSetArg(al[ac], XmNsubMenuId, menu52); ac++;
+ XtSetValues ( cascade55, al, ac );
+ ac = 0;
+ XtAddCallback (button12, XmNactivateCallback,&top_shell_c:: prefCB, (XtPointer) this);
+ XtAddCallback (snapshot, XmNactivateCallback,&top_shell_c:: snapshotCB, (XtPointer) this);
+ children[ac++] = button2;
+ children[ac++] = button3;
+ children[ac++] = separator7;
+ children[ac++] = button12;
+ children[ac++] = snapshot;
+ XtManageChildren(children, ac);
+ ac = 0;
+ XtSetArg(al[ac], XmNsubMenuId, menu1); ac++;
+ XtSetValues ( cascade1, al, ac );
+ ac = 0;
+ XtAddCallback (show0_, XmNentryCallback,&top_shell_c:: showCB, (XtPointer) this);
+ XtAddCallback (show2_, XmNentryCallback,&top_shell_c:: showCB, (XtPointer) this);
+ children[ac++] = toggle15;
+ children[ac++] = toggle16;
+ children[ac++] = toggle17;
+ // children[ac++] = toggle18;
+ children[ac++] = toggle19;
+ children[ac++] = toggle20;
+ XtManageChildren(children, ac);
+ ac = 0;
+ XtSetArg(al[ac], XmNsubMenuId, show2_); ac++;
+ XtSetValues ( cascade4, al, ac );
+ ac = 0;
+ XtAddCallback (show1_, XmNentryCallback,&top_shell_c:: showCB, (XtPointer) this);
+ children[ac++] = toggle7;
+ children[ac++] = toggle8;
+ children[ac++] = toggle9;
+ children[ac++] = toggle10;
+ children[ac++] = toggle11;
+ children[ac++] = toggle12;
+ children[ac++] = toggle13;
+ children[ac++] = toggle14;
+ children[ac++] = toggle39;
+ children[ac++] = toggle40;
+ children[ac++] = toggle73;
+ children[ac++] = toggle41;
+ XtManageChildren(children, ac);
+ ac = 0;
+ XtSetArg(al[ac], XmNsubMenuId, show1_); ac++;
+ XtSetValues ( cascade5, al, ac );
+ ac = 0;
+ XtAddCallback (show3_, XmNentryCallback,&top_shell_c:: showCB, (XtPointer) this);
+ children[ac++] = toggle66;
+ children[ac++] = toggle67;
+ children[ac++] = toggle68;
+ children[ac++] = toggle69;
+ children[ac++] = toggle70;
+ // children[ac++] = toggle71;
+ children[ac++] = toggle72;
+ children[ac++] = toggle78;
+ children[ac++] = toggle79;
+ XtManageChildren(children, ac);
+ ac = 0;
+ XtSetArg(al[ac], XmNsubMenuId, show3_); ac++;
+ XtSetValues ( cascade6, al, ac );
+
+ /* ac = 0;
+ XtAddCallback (show4_, XmNentryCallback,&top_shell_c:: showCB, (XtPointer) this);
+ children[ac++] = toggle74;
+ children[ac++] = toggle75;
+ children[ac++] = toggle76;
+ children[ac++] = toggle77;
+ XtManageChildren(children, ac);
+ ac = 0;
+ XtSetArg(al[ac], XmNsubMenuId, show4_); ac++;
+ XtSetValues ( cascade7, al, ac ); */
+
+ ac = 0;
+ children[ac++] = show_unknown;
+ children[ac++] = show_suspended;
+ children[ac++] = show_complete;
+ children[ac++] = show_queued;
+ children[ac++] = show_submitted;
+ children[ac++] = show_active;
+ children[ac++] = show_aborted;
+ children[ac++] = separator64;
+ children[ac++] = cascade4;
+ children[ac++] = cascade5;
+ children[ac++] = cascade6;
+
+ children[ac++] = separator65;
+ children[ac++] = show_all;
+ children[ac++] = show_none;
+
+ // children[ac++] = cascade7;
+ XtManageChildren(children, ac);
+ ac = 0;
+ XtSetArg(al[ac], XmNsubMenuId, show0_); ac++;
+ XtSetValues ( cascade56, al, ac );
+ ac = 0;
+ XtSetArg(al[ac], XmNsubMenuId, servers_menu_); ac++;
+ XtSetValues ( cascade58, al, ac );
+ ac = 0;
+ XtAddCallback (windows_menu_, XmNentryCallback,&top_shell_c:: windowsCB, (XtPointer) this);
+ XtSetArg(al[ac], XmNsubMenuId, windows_menu_); ac++;
+ XtSetValues ( cascade3, al, ac );
+ ac = 0;
+ XtAddCallback (button197, XmNactivateCallback,&top_shell_c:: helpCB, (XtPointer) this);
+ XtAddCallback (button198, XmNactivateCallback,&top_shell_c:: releaseCB, (XtPointer) this);
+ children[ac++] = button197;
+ children[ac++] = button198;
+ XtManageChildren(children, ac);
+ ac = 0;
+ XtSetArg(al[ac], XmNsubMenuId, menu53); ac++;
+ XtSetValues ( help, al, ac );
+ ac = 0;
+ children[ac++] = cascade55;
+ children[ac++] = cascade1;
+ children[ac++] = cascade56;
+ children[ac++] = cascade58;
+ children[ac++] = cascade3;
+ children[ac++] = help;
+ XtManageChildren(children, ac);
+ ac = 0;
+ children[ac++] = form2;
+ children[ac++] = scrolledWin1;
+ children[ac++] = menu_bar;
+ children[ac++] = separator5;
+ XtManageChildren(children, ac);
+ ac = 0;
+ XtManageChild ( form_);
+}
+
+void top_shell_c::loginCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ top_shell_p instance = (top_shell_p) client_data;
+ instance->loginCB ( widget, call_data );
+}
+
+void top_shell_c::prefCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ top_shell_p instance = (top_shell_p) client_data;
+ instance->prefCB ( widget, call_data );
+}
+
+void top_shell_c::helpCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ top_shell_p instance = (top_shell_p) client_data;
+ instance->helpCB ( widget, call_data );
+}
+
+void top_shell_c::releaseCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ top_shell_p instance = (top_shell_p) client_data;
+ instance->releaseCB ( widget, call_data );
+}
+
+void top_shell_c::searchCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ top_shell_p instance = (top_shell_p) client_data;
+ instance->searchCB ( widget, call_data );
+}
+
+void top_shell_c::windowsCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ top_shell_p instance = (top_shell_p) client_data;
+ instance->windowsCB ( widget, call_data );
+}
+
+void top_shell_c::chatCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ top_shell_p instance = (top_shell_p) client_data;
+ instance->chatCB ( widget, call_data );
+}
+
+void top_shell_c::showCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ top_shell_p instance = (top_shell_p) client_data;
+ instance->showCB ( widget, call_data );
+}
+
+void top_shell_c::serverCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ top_shell_p instance = (top_shell_p) client_data;
+ instance->serverCB ( widget, call_data );
+}
+
+void top_shell_c::statusCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ top_shell_p instance = (top_shell_p) client_data;
+ instance->statusCB ( widget, call_data );
+}
+
+void top_shell_c::snapshotCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ top_shell_p instance = (top_shell_p) client_data;
+ instance->snapshotCB ( widget, call_data );
+}
+
+void top_shell_c::windowCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ top_shell_p instance = (top_shell_p) client_data;
+ instance->windowCB ( widget, call_data );
+}
+
+void top_shell_c::quitCB( Widget widget, XtPointer client_data, XtPointer call_data )
+{
+ top_shell_p instance = (top_shell_p) client_data;
+ instance->quitCB ( widget, call_data );
+}
+
+XtAppContext app_context;
+Display *display;
+// sym_entry_type *rp = NULL;
+
+int main(int argc, char **argv)
+{
+ XtSetLanguageProc ((XtAppContext) NULL,
+ (XtLanguageProc) NULL,
+ (XtPointer) NULL);
+ XtToolkitInitialize ();
+ app_context = XtCreateApplicationContext ();
+ display = XtOpenDisplay (app_context, NULL, argv[0], appName,
+ NULL, 0, &argc, argv);
+ if (!display) {
+ printf("%s: can't open display, exiting...\n", argv[0]);
+ exit (-1);
+ }
+
+ XmRepTypeInstallTearOffModelConverter();
+
+ top_shell = new top;
+ top_shell->create ( display, argv[0], argc, argv, appName );
+ XtRealizeWidget (top_shell->xd_rootwidget());
+ // UilDumpSymbolTable(rp);
+
+ XtAppMainLoop (app_context);
+
+ exit (0);
+
+ return 0;
+
+ /*
+ ./bin/gcc-4.5/debug/ecflowview -geometry=640x880+620+240
+ -display -bg -fg
+ */
+
+}
+
diff --git a/ecflow_4_0_7/view/src/libui/uitop.h b/view/src/libui/uitop.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uitop.h
rename to view/src/libui/uitop.h
diff --git a/ecflow_4_0_7/view/src/libui/uitree.cc b/view/src/libui/uitree.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uitree.cc
rename to view/src/libui/uitree.cc
diff --git a/ecflow_4_0_7/view/src/libui/uitree.h b/view/src/libui/uitree.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uitree.h
rename to view/src/libui/uitree.h
diff --git a/ecflow_4_0_7/view/src/libui/uitriggers.cc b/view/src/libui/uitriggers.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uitriggers.cc
rename to view/src/libui/uitriggers.cc
diff --git a/ecflow_4_0_7/view/src/libui/uitriggers.h b/view/src/libui/uitriggers.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uitriggers.h
rename to view/src/libui/uitriggers.h
diff --git a/ecflow_4_0_7/view/src/libui/uiuser.cc b/view/src/libui/uiuser.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uiuser.cc
rename to view/src/libui/uiuser.cc
diff --git a/ecflow_4_0_7/view/src/libui/uiuser.h b/view/src/libui/uiuser.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uiuser.h
rename to view/src/libui/uiuser.h
diff --git a/ecflow_4_0_7/view/src/libui/uiusers.cc b/view/src/libui/uiusers.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uiusers.cc
rename to view/src/libui/uiusers.cc
diff --git a/ecflow_4_0_7/view/src/libui/uiusers.h b/view/src/libui/uiusers.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uiusers.h
rename to view/src/libui/uiusers.h
diff --git a/ecflow_4_0_7/view/src/libui/uivariables.cc b/view/src/libui/uivariables.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uivariables.cc
rename to view/src/libui/uivariables.cc
diff --git a/ecflow_4_0_7/view/src/libui/uivariables.h b/view/src/libui/uivariables.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uivariables.h
rename to view/src/libui/uivariables.h
diff --git a/ecflow_4_0_7/view/src/libui/uiwhy.cc b/view/src/libui/uiwhy.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uiwhy.cc
rename to view/src/libui/uiwhy.cc
diff --git a/ecflow_4_0_7/view/src/libui/uiwhy.h b/view/src/libui/uiwhy.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uiwhy.h
rename to view/src/libui/uiwhy.h
diff --git a/ecflow_4_0_7/view/src/libui/uizombies.cc b/view/src/libui/uizombies.cc
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uizombies.cc
rename to view/src/libui/uizombies.cc
diff --git a/ecflow_4_0_7/view/src/libui/uizombies.h b/view/src/libui/uizombies.h
similarity index 100%
rename from ecflow_4_0_7/view/src/libui/uizombies.h
rename to view/src/libui/uizombies.h
diff --git a/view/src/libxec/xec_Cursor.c b/view/src/libxec/xec_Cursor.c
new file mode 100644
index 0000000..0bb3194
--- /dev/null
+++ b/view/src/libxec/xec_Cursor.c
@@ -0,0 +1,52 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include <X11/X.h>
+#include <X11/cursorfont.h>
+#include <Xm/Xm.h>
+
+/*----------------------------------------------------
+
+ Set the cursor to a watch shape.
+ Usualy pass the Top Shell as argument.
+
+----------------------------------------------------*/
+
+void xec_SetWatchCursor(w)
+Widget w;
+{
+ static Cursor watch = 0;
+
+ if(!watch)
+ watch = XCreateFontCursor(XtDisplay(w),XC_watch);
+
+ XDefineCursor(XtDisplay(w),XtWindow(w),watch);
+ XmUpdateDisplay(w);
+}
+
+/*----------------------------------------------------
+
+ Reset the cursor to its default shape.
+ Usualy pass the Top Shell as argument.
+
+----------------------------------------------------*/
+
+void xec_ResetCursor(w)
+Widget w;
+{
+ XUndefineCursor(XtDisplay(w),XtWindow(w));
+ XmUpdateDisplay(w);
+}
+
diff --git a/view/src/libxec/xec_Label.c b/view/src/libxec/xec_Label.c
new file mode 100644
index 0000000..fcdb765
--- /dev/null
+++ b/view/src/libxec/xec_Label.c
@@ -0,0 +1,42 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <Xm/Xm.h>
+#include "xec.h"
+
+/*-----------------------------------------------
+
+ Change the title of a Label or Button
+
+-------------------------------------------------*/
+
+void xec_SetLabel(Widget w,const char *title)
+{
+ XmString s = xec_NewString(title);
+ XtVaSetValues(w,XmNlabelString,s,NULL);
+ XmStringFree(s);
+}
+
+void xec_VaSetLabel(Widget w,const char *fmt,...)
+{
+ va_list args;
+ char str[1000]; /* DANGER: Fixed buffer size */
+ va_start(args,fmt);
+ vsprintf(str, fmt, args);
+ xec_SetLabel(w,str);
+ va_end(args);
+}
diff --git a/view/src/libxec/xec_List.c b/view/src/libxec/xec_List.c
new file mode 100644
index 0000000..c8ac6b2
--- /dev/null
+++ b/view/src/libxec/xec_List.c
@@ -0,0 +1,276 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #2 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include <Xm/Xm.h>
+#include <Xm/ListP.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdarg.h>
+#include "xec.h"
+
+
+/*-----------------------------------------------------
+
+ Remove one line to a list
+
+------------------------------------------------------*/
+
+void xec_RemoveListItem(Widget w,char *p)
+{
+ XmString item= XmStringCreateSimple(p);
+ XmListDeleteItem(w,item);
+ XmStringFree(item);
+}
+
+void xec_ListItemSelect(Widget w,const char* p)
+{
+ XmString item= XmStringCreateSimple((char*)p);
+ int n = XmListItemPos(w,item);
+
+ XmListDeselectAllItems(w);
+ if(n) {
+ int vis_count;
+ XtVaGetValues(w,XmNvisibleItemCount,&vis_count,NULL);
+ XmListSelectPos(w,n,False);
+ if(n<((XmListWidget)w)->list.top_position ||
+ n > ((XmListWidget)w)->list.top_position + vis_count)
+ XmListSetPos(w,n);
+ }
+
+ XmStringFree(item);
+}
+
+#if 0
+/*----------------------------------------------------
+
+ Add to a list with max number of items
+
+-----------------------------------------------------*/
+
+void xec_AddListMax(Widget w,int max,char* p)
+{
+ ARG_DEF(1);
+ int n;
+
+ SetArg(XmNitemCount,&n);
+ GetValues(w);
+ if(n>=max) XmListDeletePos(w,1);
+ xec_AddListItem(w,p);
+
+ SetArg(XmNitemCount,&n);
+ GetValues(w);
+ XmListSetBottomPos(w,n);
+}
+
+void xec_VaAddListMax(Widget w,int max,char *fmt,...)
+{
+ va_list args;
+ char str[1000]; /* DANGER: Fixed buffer size */
+
+ va_start(args,fmt);
+ vsprintf(str, fmt, args);
+ xec_AddListMax(w,max,str);
+ va_end(args);
+}
+
+#endif
+
+void xec_ListSelectAll(Widget w)
+{
+ int n,i;
+ XtVaGetValues(w,XmNitemCount,&n,NULL);
+ XmListDeselectAllItems(w);
+ for(i=1;i<=n;i++) XmListSelectPos(w,i,False);
+
+}
+
+
+/*-----------------------------------------------------
+
+ Add one line to a list
+
+------------------------------------------------------*/
+
+void xec_AddListItem(Widget w,char *p)
+{
+ XmString item= XmStringCreateSimple(p);
+ XmListAddItemUnselected(w,item,0);
+ XmStringFree(item);
+}
+
+Boolean xec_AddListItemUnique(Widget w,char *p,Boolean sel)
+{
+ XmString item= XmStringCreateSimple(p);
+ int added = 0;
+ if(!XmListItemExists(w,item))
+ {
+ XmListAddItemUnselected(w,item,0);
+ if(sel) XmListSelectItem(w,item,0);
+ added = 1;
+ }
+ XmStringFree(item);
+ return added;
+}
+
+
+void xec_VaAddListItem(Widget w,char *fmt,...)
+{
+ va_list args;
+ char str[1000]; /* DANGER: Fixed buffer size */
+
+ va_start(args,fmt);
+ vsprintf(str, fmt, args);
+ xec_AddListItem(w,str);
+ va_end(args);
+}
+
+void xec_ReplaceListItem(Widget w,const char* from,const char* to)
+{
+ XmString a= XmStringCreateSimple((char*)from);
+ XmString b= XmStringCreateSimple((char*)to);
+ XmListReplaceItems(w,&a,1,&b);
+ XmStringFree(a);
+ XmStringFree(b);
+}
+
+#if 0
+
+/*-----------------------------------------------------
+
+ Replace all items in a list
+
+------------------------------------------------------*/
+void xec_SetListItems(Widget w,XmString list[],int count)
+{
+ ARG_DEF(2);
+
+ SetArg(XmNitems, list );
+ SetArg(XmNitemCount, count );
+ SetValues(w);
+
+}
+
+/*---------------------------------------------------*/
+int xec_DumpList(FILE *f,char *fmt,Widget w)
+{
+ ARG_DEF(2);
+ int count;
+ XmString *list;
+ int i;
+ int ret = 0;
+
+ SetArg(XmNitems,&list);
+ SetArg(XmNitemCount,&count);
+ GetValues(w);
+
+ for(i=0;i<count;i++)
+ {
+ char *p = (char*)xec_GetString(list[i]);
+ fprintf(f,fmt,p);
+ if(errno) ret = errno;
+ XtFree((XtPointer)p);
+ }
+ return errno = ret;
+}
+/*-----------------------------------------------------*/
+
+/*--------------------------------------------------
+
+ Search the regexp 'word' in the list 'w'.
+ Return TRUE in the text was found.
+ if 'nocase' is TRUE the search is not case sensitive.
+ if 'fromstart' is TRUE the search start from the
+ fisrt char, else from the current position.
+ if 'wrap' is TRUE the search is done all the text.
+
+ ---------------------------------------------------*/
+
+Boolean xec_ListSearch(Widget w,char *word,Boolean nocase,Boolean fromstart,Boolean wrap)
+{
+ /* ARG_DEF(5); */
+ int first = 0;
+ int count,sel_count,vis_count;
+ XmString *items,*sel_items;
+ char *p;
+ int from,to,i;
+
+ SetArg(XmNitemCount,&count);
+ SetArg(XmNselectedItemCount,&sel_count);
+ SetArg(XmNitems,&items);
+ SetArg(XmNselectedItems,&sel_items);
+ SetArg(XmNvisibleItemCount,&vis_count);
+ GetValues(w);
+
+ if(!fromstart)
+ if(sel_count) first = ((XmListWidget)w)->list.selectedIndices[0];
+
+ while(TRUE)
+ {
+ for(i=first;i<count;i++)
+ {
+ p = xec_GetString(items[i]);
+ if(regexp_find(word,p,nocase,&from,&to))
+ {
+ int n = i+1;
+
+ XmListDeselectAllItems(w);
+ XmListSelectPos(w,n,False);
+ if(n<((XmListWidget)w)->list.top_position ||
+ n > ((XmListWidget)w)->list.top_position + vis_count)
+ XmListSetPos(w,n);
+ XtFree((XtPointer)p);
+ return TRUE;
+ }
+ XtFree((XtPointer)p);
+ }
+ if(!wrap) break;
+ first = 0;
+ wrap = FALSE;
+ }
+ return FALSE;
+}
+
+void xec_ListSelect(Widget w,int n)
+{
+ ARG_DEF(5);
+ int vis_count;
+
+ SetArg(XmNvisibleItemCount,&vis_count);
+ GetValues(w);
+
+ XmListDeselectAllItems(w);
+ XmListSelectPos(w,n,False);
+
+ /* printf("xec_ListSelect %d\n",n); */
+
+ if(n<((XmListWidget)w)->list.top_position ||
+ n > ((XmListWidget)w)->list.top_position + vis_count)
+
+ XmListSetPos(w,n);
+}
+
+#endif
+
+static char *fonts[] = {
+ "normal","bold", };
+
+void xec_AddFontListItem(Widget list,char *buffer,Boolean bold)
+{
+ int index = (bold) ? 1 : 0 ;
+ XmString s = XmStringCreateLtoR(buffer,fonts[index]);
+ XmListAddItem(list,s,0);
+ XmStringFree(s);
+}
+
diff --git a/view/src/libxec/xec_Regexp.c b/view/src/libxec/xec_Regexp.c
new file mode 100644
index 0000000..7ae794b
--- /dev/null
+++ b/view/src/libxec/xec_Regexp.c
@@ -0,0 +1,91 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/*=====================
+
+Include regexp once for compatibility
+
+======================*/
+
+#include <stdio.h>
+
+#define ESIZE 1024
+
+#ifdef NO_REGEXP
+
+static char *loc1,*loc2;
+static int len;
+
+static compile(w,buf,end,dummy)
+char *w,*buf;
+int end;
+int dummy;
+{
+ strcpy(buf,w);
+ len = strlen(w);
+}
+
+static step(w,buf)
+char *w;
+char *buf;
+{
+ loc1 = w;
+ while(*loc1)
+ {
+ if(strncmp(loc1,buf,len) == 0)
+ {
+ loc2 = loc1+len;
+ return 1;
+ }
+ loc1++;
+ }
+ return 0;
+}
+
+
+#else
+
+/* size of regexp buffer */
+
+
+#define INIT register char *sp = instring;
+#define GETC() (*sp++)
+#define PEEKC() (*sp)
+#define UNGETC(c) (--sp)
+#define RETURN(c) return NULL;
+#define ERROR(c) fprintf(stderr,"Warning regexp error %d\n",c)
+
+#include <regexp.h>
+
+#endif
+
+static char expbuf[ESIZE];
+char *xec_loc1;
+char *xec_loc2;
+
+void xec_compile(w)
+char *w;
+{
+ compile(w,expbuf,&expbuf[ESIZE],'\0');
+}
+
+int xec_step(p)
+char *p;
+{
+ int s = step(p,expbuf);
+ xec_loc1 = loc1;
+ xec_loc2 = loc2;
+ return s;
+}
diff --git a/view/src/libxec/xec_Strings.c b/view/src/libxec/xec_Strings.c
new file mode 100644
index 0000000..4817918
--- /dev/null
+++ b/view/src/libxec/xec_Strings.c
@@ -0,0 +1,134 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+#include <Xm/Xm.h>
+#include <string.h>
+#include <malloc.h>
+
+/*-----------------------------------------------------
+
+ Create a new XmString from a char*
+
+ This function can deal with embedded 'newline' and
+ is equivalent to the obsolete XmStringCreateLtoR,
+ except it does not use non AES compliant charset
+ XmSTRING_DEFAULT_CHARSET
+
+------------------------------------------------------*/
+
+
+XmString xec_NewString(const char* s)
+{
+ XmString xms1;
+ XmString xms2;
+ XmString line;
+ XmString separator;
+ char *p;
+ char *t = XtNewString(s); /* Make a copy for strtok not to */
+ /* damage the original string */
+
+ separator = XmStringSeparatorCreate();
+ p = strtok(t,"\n");
+ xms1 = XmStringCreateSimple(p);
+
+ while ((p = strtok(NULL,"\n")))
+ {
+ line = XmStringCreateSimple(p);
+ xms2 = XmStringConcat(xms1,separator);
+ XmStringFree(xms1);
+ xms1 = XmStringConcat(xms2,line);
+ XmStringFree(xms2);
+ XmStringFree(line);
+ }
+
+ XmStringFree(separator);
+ XtFree(t);
+ return xms1;
+}
+
+
+/*-----------------------------------------------------
+
+ Build an XmString list from char*
+
+------------------------------------------------------*/
+
+void xec_BuildXmStringList(XmString** list, char* p, int *count)
+{
+ XmString *l = *list;
+
+ if(!l) {
+ *count = 0;
+ l = (XmString*)malloc(0);
+ }
+
+ (*count)++;
+ l = (XmString*)XtRealloc((char*) l,sizeof(XmString)*(*count));
+ l[(*count-1)] = xec_NewString(p);
+
+ *list = l;
+}
+
+/*-----------------------------------------------------
+
+ Free an XmString list
+
+------------------------------------------------------*/
+
+void xec_FreeXmStringList(XmString* list, int count)
+{
+ int i;
+
+ if(list)
+ {
+ for(i=0;i<count;i++) XmStringFree(list[i]);
+ XtFree((XtPointer)list);
+ }
+}
+
+char *xec_GetString(XmString string)
+{
+ XmStringContext context;
+ char *text;
+ XmStringCharSet charset;
+ XmStringDirection dir;
+ Boolean separator;
+ char *buf = NULL;
+ int done = FALSE;
+
+ XmStringInitContext (&context, string);
+ while (!done)
+ if(XmStringGetNextSegment (context, &text, &charset, &dir, &separator))
+ {
+ if(separator) /* Stop when next segment is a separator */
+ done = TRUE;
+
+ if(buf)
+ {
+ buf = XtRealloc(buf, strlen(buf) + strlen(text) + 2);
+ strcat(buf, text);
+ }
+ else
+ buf = XtNewString(text);
+
+ XtFree((XtPointer)charset);
+ XtFree((XtPointer)text);
+ }
+ else
+ done = TRUE;
+
+ XmStringFreeContext (context);
+ return buf;
+
+}
diff --git a/view/src/libxec/xec_Text.c b/view/src/libxec/xec_Text.c
new file mode 100644
index 0000000..6bc3ced
--- /dev/null
+++ b/view/src/libxec/xec_Text.c
@@ -0,0 +1,547 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #2 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <Xm/Xm.h>
+#include <Xm/Text.h>
+#include <Xm/TextP.h>
+#include <Xm/Form.h>
+#include <Xm/TextStrSoP.h>
+#include <Xm/CutPaste.h>
+#include "xec.h"
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <regex.h>
+#include <setjmp.h>
+#include <signal.h>
+
+/* Avi: Added to fix: warning: implicit declaration of function ‘_XmTextUpdateLineTable’ */
+extern void _XmTextUpdateLineTable(
+ Widget widget,
+ XmTextPosition start,
+ XmTextPosition end,
+ XmTextBlock block,
+ Boolean update) ;
+/* JIRA:ECFLOW-48 int update) ; */
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *)(-1))
+#endif
+
+int regexp_find(const char *word,const char *buffer,
+ int nocase,int *from,int *to)
+{
+ regex_t re;
+ regmatch_t pmatch[1];
+ int e;
+
+ if((e = regcomp(&re,word,REG_NEWLINE | REG_EXTENDED | (nocase? REG_ICASE : 0) )))
+ {
+ char buf[1024];
+ regerror(e,&re,buf,sizeof(buf));
+ return False;
+ }
+
+ if((e = regexec(&re,buffer,XtNumber(pmatch),pmatch,0)))
+ {
+ char buf[1024];
+ regerror(e,&re,buf,sizeof(buf));
+ regfree(&re);
+ return False;
+ }
+
+ *from = pmatch[0].rm_so;
+ *to = pmatch[0].rm_eo;
+
+ regfree(&re);
+
+ return True;
+}
+
+char* xec_TextGetString(Widget w,long *length)
+{
+#if 0
+ return XmTextGetString(w);
+#else
+ XmTextSource s = XmTextGetSource(w);
+ *length = s->data->length;
+ return s->data->ptr;
+#endif
+}
+
+void xec_TextFreeString(char* p)
+{
+#if 0
+ XtFree(p);
+#endif
+}
+
+static jmp_buf env;
+
+static void catch_sigv(int sig)
+{
+ fprintf(stderr,"SIGV received...\n");
+ longjmp(env,1);
+}
+
+/*--------------------------------------------------
+---------------------------------------------------*/
+
+/*--------------------------------------------------
+
+ Search the regexp 'word' in the text 'w'.
+ Return TRUE in the text was found.
+ if 'nocase' is TRUE the search is not case sensitive.
+ if 'fromstart' is TRUE the search start from the
+ fisrt char, else from the current position.
+ if 'wrap' is TRUE the search is done all the text.
+
+---------------------------------------------------*/
+
+Boolean xec_TextSearch(Widget w,char *word,
+ Boolean nocase,
+ Boolean regex,
+ Boolean back,
+ Boolean fromstart,
+ Boolean wrap)
+{
+
+ Boolean success,more;
+ XmTextPosition offset,dummy;
+ int from,to;
+ long length = 0;
+ char *p=xec_TextGetString(w,&length);
+
+ if(fromstart)
+ {
+ offset = (!regex && back) ? XmTextGetLastPosition(w) - strlen(word) : 0;
+ wrap = FALSE;
+ }
+ else
+ {
+ XmTextGetSelectionPosition(w,&dummy,&offset);
+ if(dummy == offset) offset = XmTextGetInsertionPosition(w);
+
+ if(back) {
+ if(dummy)
+ offset = dummy-1;
+ else if(wrap)
+ {
+ offset = XmTextGetLastPosition(w) - strlen(word);
+ }
+ }
+ }
+
+ do
+ {
+
+ if(regex)
+ {
+ success = regexp_find(word,p+offset,nocase,&from,&to);
+ if(success && ((from+offset > length) || (to + offset > length)))
+ success = False;
+ }
+ else {
+
+ success = 0;
+
+ /* Because we use mmap, XmTextFindString may crash */
+
+ signal(SIGSEGV,catch_sigv);
+ if(setjmp(env) == 0)
+ {
+ success = XmTextFindString(w,offset,word,
+ back ? XmTEXT_BACKWARD : XmTEXT_FORWARD,&dummy);
+ }
+ signal(SIGSEGV,SIG_DFL);
+
+
+
+ if(success) {
+
+ from = dummy - offset;
+ to = from + strlen(word);
+
+ }
+ }
+
+
+ if(success)
+ {
+ XmTextShowPosition(w,to+offset);
+ XmTextSetSelection(w,from+offset,to+offset,CurrentTime);
+ }
+
+ more = wrap && !success;
+
+ if(wrap)
+ {
+ wrap = FALSE;
+ offset = (!regex && back) ? XmTextGetLastPosition(w) - strlen(word): 0;
+ }
+
+ }while(more);
+
+ xec_TextFreeString(p);
+
+ return success;
+
+}
+
+
+
+/*-------------------------------------------------
+
+ Copy the content of a Text in a buffer.
+
+--------------------------------------------------*/
+
+char *xec_GetText(w,buf)
+Widget w;
+char buf[];
+{
+ char *q = (char*)XmTextGetString(w);
+
+ strcpy(buf,q);
+ XtFree((XtPointer)q);
+
+ return buf;
+}
+
+
+/*-------------------------------------------------
+
+ Load a file into a text widget.
+ if include is TRUE the text if included.
+
+--------------------------------------------------*/
+
+int xec_LoadText(Widget Text,const char *fname,Boolean include)
+{
+ FILE *fp = NULL;
+ char *p;
+ long length;
+ int ret = 0;
+
+
+ errno = 0;
+
+ if (!fname) return -1;
+
+ if ((fp = fopen(fname,"r")))
+ {
+ fseek(fp,0L,2);
+ if (errno)
+ {
+ ret = errno;
+ fclose(fp);
+ return errno = ret;
+ }
+
+ length=ftell(fp);
+ if (errno)
+ {
+ ret = errno;
+ fclose(fp);
+ return errno = ret;
+ }
+
+ fseek(fp,0L,0);
+ if (errno)
+ {
+ ret = errno;
+ fclose(fp);
+ return errno = ret;
+ }
+
+ p = (char*)XtMalloc(length+1);
+ p[length] = 0;
+
+ fread(p,length,1,fp);
+ if (errno)
+ {
+ ret = errno;
+ fclose(fp);
+ return errno = ret;
+ }
+
+ XmTextDisableRedisplay(Text);
+ if (include)
+ xec_ReplaceTextSelection(Text,p,FALSE);
+ else
+ {
+ XmTextSetInsertionPosition(Text,0);
+ XmTextSetSelection(Text,0,0,CurrentTime);
+ XmTextSetString(Text,p);
+ }
+ XmTextEnableRedisplay(Text);
+
+ XtFree(p);
+ fclose(fp);
+ }
+ else
+ {
+ perror(fname);
+ ret = errno;
+ if (!include) XmTextSetString(Text,"");
+ }
+ return errno = ret;
+
+}
+
+/* ================================================== */
+
+
+typedef struct mapped_text {
+ XmTextSource source_;
+ FILE* file_;
+ Widget text_;
+ XmSourceDataRec save_;
+} mapped_text;
+
+void* xec_MapText(Widget w,const char *fname,int* z)
+{
+ FILE *fp = NULL;
+ long length;
+ /*int ret = 0; warning: variable ‘ret’ set but not used [-Wunused-but-set-variable] */
+ char *m;
+ mapped_text *p;
+ XEvent ev;
+ XmTextBlockRec block;
+ int i;
+
+
+ errno = 0;
+
+ if (!fname) return NULL;
+
+ if ((fp = fopen(fname,"r")))
+ {
+ fseek(fp,0L,2);
+ if (errno)
+ {
+ fclose(fp);
+ return NULL;
+ }
+
+ length=ftell(fp);
+ if (errno)
+ {
+ fclose(fp);
+ return NULL;
+ }
+
+ fseek(fp,0L,0);
+ if (errno)
+ {
+ fclose(fp);
+ return NULL;
+ }
+
+ /* f = w;
+ while(f && !XmIsForm(f))
+ f = XtParent(f);
+ if(!f) return NULL; */
+
+
+ m = mmap(NULL,length,PROT_READ,MAP_SHARED,fileno(fp),0);
+ if((void*)m == MAP_FAILED)
+ {
+ perror(fname);
+ return NULL;
+ }
+ (*z) = 0;
+ for(i = 0 ; i < length; i++)
+ if(m[i] == 0) (*z)++;
+
+ XmTextDisableRedisplay(w);
+ XmTextClearSelection(w,CurrentTime);
+ XmTextSetInsertionPosition(w,0);
+ XmTextSetTopCharacter(w,0);
+ XmTextShowPosition(w,0);
+ XmTextEnableRedisplay(w);
+ XmTextSetString(w,"");
+
+ p = XtNew(mapped_text);
+
+ /* p->text1_ = XmCreateText(f,"dummy",0,0); */
+ /* p->text2_ = XmCreateText(f,"dummy",0,0); */
+
+ p->source_ = XmTextGetSource(w);
+ p->file_ = fp;
+ p->text_ = w;
+ p->save_ = *p->source_->data;
+
+ p->source_->data->ptr = m;
+ p->source_->data->length = length;
+ p->source_->data->maxlength = length;
+ p->source_->data->value = m;
+ p->source_->data->old_length = length;
+ p->source_->data->gap_start = 0;
+ p->source_->data->gap_end = 0;
+
+
+ ((XmTextWidget)w)->text.needs_refigure_lines = True;
+ /* _XmTextNumLines((XmTextWidget)w); */
+
+ block.ptr = m;
+ block.length = length;
+ block.format = XmFMT_8_BIT;
+
+ _XmTextUpdateLineTable(w,0, XmTextGetLastPosition(w),&block,1);
+
+#if 1
+ /* ((XmTextWidget)w)->text.needs_refigure_lines = True; */
+ /* printf("Num lines : %d\n",_XmTextNumLines((XmTextWidget)w)); */
+ /* _XmTextValueChanged((XmTextWidget)w,&ev); */
+
+ memset(&ev,0,sizeof(ev));
+ ev.type = Expose;
+ ev.xexpose.display = XtDisplay(w);
+ ev.xexpose.window = XtWindow(w);
+
+ XSendEvent(XtDisplay(w),XtWindow(w),True,ExposureMask,&ev);
+#endif
+
+ return p;
+
+ }
+ return NULL;
+
+}
+
+void xec_UnmapText(void *x)
+{
+ if(x)
+ {
+ XmTextBlockRec block;
+ mapped_text* p = (mapped_text*)x;
+ Widget w = p->text_;
+
+ ((XmTextWidget)w)->text.needs_refigure_lines = True;
+ /* _XmTextNumLines((XmTextWidget)w); */
+
+ block.ptr = NULL;
+ block.length = 0;
+ block.format = XmFMT_8_BIT;
+ _XmTextUpdateLineTable(w,0, XmTextGetLastPosition(w),&block,1);
+
+ XmTextDisableRedisplay(w);
+ XmTextClearSelection(w,CurrentTime);
+ XmTextSetInsertionPosition(w,0);
+ XmTextSetTopCharacter(w,0);
+ XmTextShowPosition(w,0);
+
+ XmTextEnableRedisplay(w);
+
+ munmap(p->source_->data->ptr,p->source_->data->length);
+ *p->source_->data = p->save_;
+ fclose(p->file_);
+
+ XtFree((char*)p);
+
+ XmTextSetString(w,"");
+ }
+
+}
+
+/*-------------------------------------------------
+
+ Save a text into a file
+
+--------------------------------------------------*/
+
+/* Open file, save text and close file */
+
+int xec_SaveText(Widget w,char *fname)
+{
+ FILE *fp = NULL;
+ char *p = XmTextGetString(w);
+ int ret;
+
+ errno = 0;
+
+ if (!fname) return -1;
+
+ if ((fp = fopen(fname,"w")))
+ if (fwrite(p,strlen(p),1,fp)) fclose(fp);
+
+ ret = errno;
+ XtFree(p);
+ return errno = ret;
+}
+
+
+/* File is already opened: just save text */
+
+int xec_DumpText(FILE *fp,Widget w)
+{
+ char *p = XmTextGetString(w);
+
+ errno = 0;
+ fwrite(p,strlen(p),1,fp);
+ XtFree((XtPointer)p);
+ return errno;
+}
+
+
+/*-------------------------------------------------
+
+ Print a text
+
+--------------------------------------------------*/
+
+void xec_PrintText(Widget w,char * cmd)
+{
+ char *tmp = tmpnam(NULL);
+ char buf[1024];
+
+ xec_SaveText(w,tmp);
+ if(cmd)
+ sprintf(buf,"%s %s",cmd,tmp);
+ else
+ sprintf(buf,"lpr %s",tmp);
+
+ system(buf);
+ unlink(tmp);
+
+
+}
+
+/*-------------------------------------------------
+
+ Replace the selection by a char*
+ If sel the inserted text is selected
+
+--------------------------------------------------*/
+
+void xec_ReplaceTextSelection(Widget w,char *p,Boolean sel)
+{
+ XmTextPosition from,to;
+
+ XmTextGetSelectionPosition(w,&from,&to);
+ if(from == to) from = to = XmTextGetInsertionPosition(w);
+ XmTextReplace(w,from,to,p);
+ if(sel)
+ XmTextSetSelection(w,from,from+strlen(p),CurrentTime);
+ else
+ XmTextSetSelection(w,from+strlen(p),from+strlen(p),CurrentTime);
+ XmTextSetInsertionPosition(w,from+strlen(p));
+}
+
diff --git a/view/src/libxec/xec_Toggle.c b/view/src/libxec/xec_Toggle.c
new file mode 100644
index 0000000..86f1c1d
--- /dev/null
+++ b/view/src/libxec/xec_Toggle.c
@@ -0,0 +1,41 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+#include <Xm/Xm.h>
+#include <stdio.h>
+#include "xec.h"
+
+/*-----------------------------------------------
+
+ Set or reset a toggle button
+
+-------------------------------------------------*/
+
+void xec_SetToggle(Widget w,int set)
+{
+ Arg arg;
+
+ XtSetArg(arg,XmNset,set?1:0);
+ XtSetValues(w,&arg,1);
+}
+
+int xec_GetToggle(Widget w)
+{
+ Boolean set;Arg arg;
+
+ XtSetArg(arg,XmNset, &set);
+ XtGetValues(w,&arg,1);
+
+ return set;
+}
diff --git a/view/src/libxec/xec_Widget.c b/view/src/libxec/xec_Widget.c
new file mode 100644
index 0000000..8af1279
--- /dev/null
+++ b/view/src/libxec/xec_Widget.c
@@ -0,0 +1,215 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #1 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+#include <stdio.h>
+#include <Xm/Xm.h>
+#include <Xm/ScrolledW.h>
+#include <Xm/ScrollBar.h>
+#include <X11/IntrinsicP.h>
+#include "xec.h"
+
+
+void *xec_GetUserData(Widget w)
+{
+ void *p;
+ XtVaGetValues(w,XmNuserData,&p,NULL);
+ return p;
+}
+
+/*-------------------------------------------------
+
+ Attach a pointer to a widget
+
+-------------------------------------------------*/
+
+void xec_SetUserData(Widget w, void* p)
+{
+ XtVaSetValues(w,XmNuserData,p,NULL);
+}
+
+/*-------------------------------------------------
+
+ Sets a color
+
+--------------------------------------------------*/
+
+
+void xec_SetColor(Widget w, Pixel p, const char* which)
+{
+ XtVaSetValues(w,which,p,NULL);
+}
+
+/*-------------------------------------------------
+
+ Scroll a window to make a widget visible
+
+--------------------------------------------------*/
+
+#if 1
+
+void xec_ShowWidget(Widget w)
+{
+
+ Widget v_scroll,h_scroll;
+
+
+ Position x_parent,y_parent;
+ Position x_widget,y_widget;
+ Dimension h_widget,w_widget;
+ Position x_clip,y_clip;
+ Dimension h_clip,w_clip;
+ Position dv=0,dh=0;
+ int min,max;
+ int v_val,v_size,v_inc,v_page;
+ int h_val,h_size,h_inc,h_page;
+ Widget clip;
+ Widget parent;
+ Widget scroll_window;
+
+ Position x,y;
+
+
+ if(!XtIsManaged(w)) return;
+
+ if(!(parent = XtParent(w))) return;
+ if(!(clip = XtParent(parent))) return;
+ if(!(scroll_window = XtParent(clip))) return;
+
+ if(!XmIsScrolledWindow(scroll_window)) return;
+
+ XtVaGetValues(scroll_window,
+ XmNhorizontalScrollBar, &h_scroll,
+ XmNverticalScrollBar, &v_scroll ,
+ NULL);
+
+
+ XtVaGetValues(parent,
+ XmNx,&x_parent,
+ XmNy,&y_parent,
+ NULL);
+
+
+ XtVaGetValues(w,
+ XmNheight,&h_widget,
+ XmNwidth,&w_widget,
+ NULL);
+
+
+ XtVaGetValues(scroll_window,
+ XmNclipWindow,&clip,
+ NULL);
+
+ XtVaGetValues(clip,
+ XmNheight,&h_clip,
+ XmNwidth,&w_clip,
+ NULL);
+
+
+ XtTranslateCoords(w,0,0, &x_widget,&y_widget);
+ XtTranslateCoords(clip,0,0,&x_clip,&y_clip);
+
+
+ x = x_widget - x_clip;
+ y = y_widget - y_clip;
+
+
+ if( y < 0 || (Dimension) (y + h_widget) > h_clip)
+ {
+ dv = (y + h_widget / 2) - h_clip / 2;
+
+ XtVaGetValues(v_scroll,
+ XmNminimum,&min,
+ XmNmaximum,&max,
+ NULL);
+
+ XmScrollBarGetValues(v_scroll,&v_val,&v_size,&v_inc,&v_page);
+
+ max -= v_size;
+
+ if( dv + v_val > max ) dv = max - v_val;
+ if( dv + v_val < min ) dv = min - v_val;
+
+
+ }
+
+ if( x < 0 || (Dimension) (x + w_widget) > w_clip)
+ {
+ dh = (x + w_widget / 2) - w_clip / 2;
+
+ XtVaGetValues(h_scroll,
+ XmNminimum,&min,
+ XmNmaximum,&max,
+ NULL);
+
+ XmScrollBarGetValues(h_scroll,&h_val,&h_size,&h_inc,&h_page);
+
+ max -= h_size;
+
+ if( dh + h_val > max ) dh = max - h_val;
+ if( dh + h_val < min ) dh = min - h_val;
+
+ }
+
+
+ if(dv || dh)
+ {
+ Position x = x_parent-dh;
+ Position y = y_parent-dv;
+
+ XtVaSetValues(parent,
+ XmNx,x,
+ XmNy,y,
+ NULL);
+
+ /*
+ XtMoveWidget(parent,x_parent-dh,y_parent-dv);
+ */
+
+ if(dv) XmScrollBarSetValues(v_scroll,v_val+dv,v_size,v_inc,v_page,TRUE);
+ if(dh) XmScrollBarSetValues(h_scroll,h_val+dh,h_size,h_inc,h_page,TRUE);
+
+
+ /* force redraw */
+ /*
+
+ XtUnmanageChild(parent);
+ XtManageChild(parent);
+ */
+ }
+
+
+}
+
+#endif
+void xec_Invert(Widget w)
+{
+ Pixel fg,bg;
+ XtVaGetValues(w,XmNbackground,&bg,XmNforeground,&fg,NULL);
+ XtVaSetValues(w,XmNbackground,fg,XmNforeground,bg,NULL);
+}
+
+void xec_ManageAll(Widget w)
+{
+ CompositeWidget c = (CompositeWidget)w;
+ XtManageChildren(c->composite.children,
+ c->composite.num_children);
+}
+
+void xec_UnmanageAll(Widget w)
+{
+ CompositeWidget c = (CompositeWidget)w;
+ XtUnmanageChildren(c->composite.children,
+ c->composite.num_children);
+}
+
diff --git a/view/src/limit_node.cc b/view/src/limit_node.cc
new file mode 100644
index 0000000..1ff5e4b
--- /dev/null
+++ b/view/src/limit_node.cc
@@ -0,0 +1,459 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #15 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "node.h"
+#include "show.h"
+#include "pixmap.h"
+#include <math.h>
+// #include "text_lister.h"
+#include "node_lister.h"
+#include "limit_node.h"
+#include <Xm/ManagerP.h>
+#include "ecf_node.h"
+
+#ifndef M_PI_2
+#define M_PI_2 1.57079632679489661923
+#endif
+
+static Pixmap images[3] = {XmUNSPECIFIED_PIXMAP, };
+
+Limit* limit_node::get() const {
+#ifdef BRIDGE
+ if (tree_) return 0x0;
+#endif
+ if (!owner_) return 0x0;
+ return dynamic_cast<ecf_concrete_node<Limit>*>(owner_)->get();
+ /* ecf_concrete_node<const Limit>* base =
+ dynamic_cast<ecf_concrete_node<const Limit>*> (owner_);
+ if (base) return *(base->get());
+ if (parent() && parent()->__node__())
+ return parent()->__node__()->get_limit(name_);
+ return 0x0; */
+}
+
+xmstring limit_node::make_label_tree()
+{
+ if (get()) {
+ char buf[30];
+ xmstring s(owner_->name().c_str(),"bold");
+ sprintf(buf,"%d/%d", get()->value(), get()->theLimit());
+ s += xmstring(": ","bold");
+ s += xmstring(buf);
+ return s;
+ }
+#ifdef BRIDGE
+ else if (!tree_) return xmstring ("nolimit");
+ sms_limit* n = (sms_limit*) tree_;
+ xmstring s(n->name,"bold");
+ s += xmstring(": ","bold");
+
+ char buf[80];
+
+ if(n->base)
+ sprintf(buf,"%d - %d - %d",n->base,n->status,n->limit);
+ else
+ sprintf(buf,"%d/%d",n->status,n->limit);
+
+ s += xmstring(buf);
+
+ if(n->unit)
+ {
+ sprintf(buf," (%s)",n->unit);
+ s += xmstring(buf);
+ }
+
+ return s;
+#endif
+ return xmstring(": ","bold");
+}
+
+const int kPixSize = 8;
+const int kHMargins = 4;
+const int kVMargins = 2;
+
+inline int max(int a,int b) { return a>b?a:b; }
+
+void limit_node::drawNode(Widget w,XRectangle* r,bool tree)
+{
+ int m = 0, v = 0;
+ if (get()) {
+ m = get()->theLimit();
+ v = get()->value();
+ }
+
+ XmString s = labelTree();
+ XRectangle x = *r;
+ x.width = XmStringWidth(smallfont(),s) + 2*kHMargins;
+
+ XmStringDraw(XtDisplay(w),XtWindow(w),
+ smallfont(),
+ s,
+ blackGC(),
+ r->x,
+ r->y,
+ x.width,
+ XmALIGNMENT_CENTER, XmSTRING_DIRECTION_L_TO_R, NULL);
+
+ for(int i = 0; i < max(m, v); i++)
+ XCopyArea(XtDisplay(w),
+ images[(i<v)?(i>=m?2:1):0],XtWindow(w),
+ blackGC(),
+ 0,0,kPixSize,kPixSize,
+ r->x + x.width + (i*kPixSize),
+ r->y + (r->height - kPixSize) / 2);
+
+ sizeNode( w, r, tree);
+}
+
+
+void limit_node::sizeNode(Widget w,XRectangle* r,bool tree)
+{
+ int m = maximum(), v = value();
+ if(images[0] == XmUNSPECIFIED_PIXMAP) {
+ images[0] = pixmap::find("limit0").pixels();
+ images[1] = pixmap::find("limit1").pixels();
+ images[2] = pixmap::find("limit2").pixels();
+ }
+
+ XmString s = labelTree();
+ r->height = XmStringHeight(smallfont(),s);
+ r->width = XmStringWidth(smallfont(),s) + 2*kHMargins + max(m,v) * kPixSize;
+ if(r->height < kPixSize) r->height = kPixSize;
+}
+
+void limit_node::perlify(FILE* f)
+{
+ perl_member(f,"value",value());
+ perl_member(f,"maximum",maximum());
+ // FILL perl_member(f,"tasks",n->tasks);
+}
+
+void limit_node::info(std::ostream& f)
+{
+ Limit* n= get(); if (n) {
+ const std::set<std::string>& list = n->paths();
+ std::set<std::string>::const_iterator it;
+ node::info(f);
+
+ f << "value : " << value() << "\n";
+ f << "maximum : " << maximum() << "\n";
+ // 1234567890
+
+ if(!list.empty())
+ f << "\nNodes in this limit_node:" << "\n-------------------------\n";
+
+ for (it = list.begin(); it != list.end(); ++it) {
+ f << *it;
+ node* p = find(*it);
+ if(p)
+ f << " " << p->type_name() << ' '
+ << " (" << p->status_name() << ")\n";
+ }
+ }
+#ifdef BRIDGE
+else if (tree_) {
+ sms_limit *n = (sms_limit*)tree_; if (!n) return;
+ sms_list* l = n->tasks;
+
+ node::info(f);
+
+ f << "value : " << n->status << "\n";
+ f << "maximum : " << n->limit << "\n";
+ // 1234567890
+
+ if(l)
+ f << "\nNodes in this limit_node:"
+ << "\n--------------------\n";
+ while(l)
+ {
+ node* p = find(l->name);
+ if(p)
+ f << p->type_name() << ' ' << p << " ("
+ << p->status_name() << ')';
+ else
+ f << l->name;
+ f << "\n";
+ l = l->next;
+ }
+ }
+#endif
+}
+
+const char* limit_node::status_name() const
+{
+ static char buf[20];
+ if(value() >= maximum()) return "full";
+ if(value() <= 0 ) return "empty";
+ sprintf(buf,"%d%%",int((value()*100.0/maximum())+0.5));
+ return buf;
+}
+
+bool limit_node::evaluate() const
+{
+ return (value() >= maximum());
+}
+
+int limit_node::maximum() const
+{
+ Limit* n= get();
+ if (n) return n->theLimit();
+#ifdef BRIDGE
+ if (tree_) return ((sms_limit*) tree_)->limit;
+#endif
+ return 0;
+}
+
+int limit_node::value() const
+{
+ if (get()) return get()->value();
+#ifdef BRIDGE
+ if (tree_) return ((sms_limit*) tree_)->status;
+#endif
+ return 0;
+}
+
+void limit_node::nodes(node_lister& node_list)
+{
+ Limit* n= get();
+ if (n) {
+ const std::set<std::string>& list = n->paths();
+ std::set<std::string>::const_iterator it;
+ for (it = list.begin(); it != list.end(); ++it) {
+ node* p = find(*it);
+ if(p) node_list.next(*p);
+ else node_list.next(*it);
+ }
+ return;
+ } else {
+#ifdef BRIDGE
+ sms_limit *n = (sms_limit*)tree_; if (!n) return;
+ sms_list* l = n->tasks;
+
+ while(l) {
+ node* p = find(l->name);
+ if(p) node_list.next(*p);
+ l = l->next;
+ }
+#endif
+ }
+}
+
+bool limit_node::match(const char* p)
+{
+ return p == parent()->full_name() + ":" + name();
+}
+
+//===============================================================
+
+const double kLength = 30;
+const double kMark = 5;
+const double kVuHeight = 2 + (kLength + kMark);
+const double kVuWidth = (kLength + kMark)*2.0;
+
+
+
+void limit_integer_node::sizeNode(Widget w,XRectangle* r,bool)
+{
+#if 1
+ XmString s = labelTree();
+ r->width = XmStringWidth(smallfont(),s) + 2 * kHMargins ;
+ r->height = XmStringHeight(smallfont(),s) + 2 * kVMargins + kVuHeight;
+
+ if(r->width < kVuWidth) r->width = kVuWidth;
+#else
+ r->width = kVuWidth;
+ r->height = 2 * kVMargins + kVuHeight;
+#endif
+}
+
+void limit_integer_node::drawNode(Widget w,XRectangle* r,bool)
+{
+ XRectangle y = *r;
+ y.width = kVuWidth;
+ y.height = kVuHeight;
+ y.y += kVMargins;
+ drawMeter(w,&y);
+
+ char buffer[1024];
+ if (get()) sprintf(buffer,"%s",get()->name().c_str());
+#ifdef BRIDGE
+ else if (tree_) sprintf(buffer,"%s",((sms_limit*)tree_)->name);
+#endif
+ xmstring s(buffer);
+ XmFontList f = gui::tinyfont();
+
+ XmStringDraw(XtDisplay(w),XtWindow(w),
+ f,
+ s,
+ blackGC(),
+ r->x,
+ r->y + (r->height - XmStringHeight(f,s)) / 2 ,
+ r->width,
+ XmALIGNMENT_CENTER, XmSTRING_DIRECTION_L_TO_R, r);
+#if 0
+ y = *r;
+ y.y += kVuHeight + kVMargins;
+
+ XmString s = labelTree();
+ XmStringDraw(XtDisplay(w),XtWindow(w),
+ smallfont(),
+ s,
+ blackGC(),
+ y.x,
+ y.y,
+ y.width,
+ XmALIGNMENT_CENTER, XmSTRING_DIRECTION_L_TO_R, NULL);
+
+ /* shadow(w,r); */
+#endif
+ node::update(-1,-1,-1);notify_observers();
+}
+
+void limit_integer_node::drawMeter(Widget w,XRectangle* r)
+{
+#if 0
+ int xcenter = 80;
+ int ycenter = 55;
+ int lastxs = xcenter;
+ int lastys = ycenter;
+
+ double min_ = 0;
+ double max_ = 5000;
+ double v_ = 15;
+
+ int length = 30;
+ int mark = 5;
+
+ int ticks = 5;
+#endif
+ const double round = 20;
+
+ const double angle = 120;
+ const double pi2 = M_PI_2;
+ const double twopi = M_PI * 2.0;
+ const int ticks = 5;
+
+ const double a = angle / 360.0 * twopi;
+
+ double maxval = maximum(); // n->limit;
+ double minval = 0.0; // n->min;
+ double curval = value(); // n->status;
+
+ double xcenter = r->width / 2.0;
+ double ycenter = r->height;
+
+ double d = (maxval - minval);
+ double c = (curval - minval)/d*a - a/2.0;
+
+ if(c > pi2) c = pi2;
+
+ int xs = cos(c - pi2) * kLength + xcenter;
+ int ys = sin(c - pi2) * kLength + ycenter;
+
+ GC gc = (curval > maxval) ? redGC() : blueGC();
+
+ XSetLineAttributes(XtDisplay(w),gc, 2,0,0,0);
+
+ XDrawLine(XtDisplay(w),XtWindow(w),
+ gc,
+ r->x + xcenter, r->y + ycenter-1, r->x + xs, r->y + ys);
+
+ XSetLineAttributes(XtDisplay(w),gc, 1,0,0,0);
+ /*
+ // --- base
+ if(n->base) {
+
+ double c1 = - a/2.0;
+ double c2 = (n->base - minval)/d*a - a/2.0;
+
+ c1 = twopi - c1 + pi2;
+ c2 = twopi - c2 + pi2;
+ // c1 -= pi2;
+ // c2 -= pi2;
+
+ double size = kLength+kMark + 2;
+
+ XFillArc(XtDisplay(w),XtWindow(w),
+ XmParentBottomShadowGC(w),
+ r->x + xcenter - size,
+ r->y + ycenter - size,
+ size * 2,
+ size * 2,
+
+ (c1 / twopi * 360) * 64,
+ (c2 / twopi * 360) * 64 - (c1 / twopi * 360) * 64);
+ }
+ */
+#if 0
+ g.setColor(Color.gray);
+ g.fillArc(xcenter-round/2,ycenter-round/2,round,round,0,180);
+#endif
+
+ for(int i = 0 ; i < ticks ; i++)
+ {
+ double v = i*d/(ticks-1);
+ c = v/d*a - a/2;
+ int x1 = cos(c - pi2) * kLength + xcenter;
+ int y1 = sin(c - pi2) * kLength + ycenter;
+
+ int x2 = cos(c - pi2) * (kLength+kMark) + xcenter;
+ int y2 = sin(c - pi2) * (kLength+kMark) + ycenter;
+
+ XDrawLine(XtDisplay(w),XtWindow(w),
+ blackGC(),r->x + x1,r->y + y1, r->x + x2, r->y + y2);
+ }
+
+ XFillArc(XtDisplay(w),XtWindow(w),
+ XmParentBackgroundGC(w),
+ r->x + xcenter-round/2,
+ r->y + ycenter-round/2,
+ round,
+ round,0,180*64);
+
+ const int drop_shadow = 10;
+ XDrawArc(XtDisplay(w),XtWindow(w),XmParentBottomShadowGC(w),
+ r->x + xcenter-round/2,
+ r->y + ycenter-round/2,round,round,64,(90-drop_shadow) * 64);
+
+ XDrawArc(XtDisplay(w),XtWindow(w),XmParentTopShadowGC(w),
+ r->x + xcenter-round/2,
+ r->y + ycenter-round/2,round,round, (90+drop_shadow)*64,180*64 - (90+drop_shadow)*64);
+
+
+ char buf[80];
+ sprintf(buf,"%d",value());
+
+ xmstring t(buf);
+ XmFontList f = gui::tinyfont();
+
+ XmStringDraw(XtDisplay(w),XtWindow(w),
+ f,
+ t,
+ (curval > maxval) ? redGC() : blueGC(),
+ r->x + xcenter-round/2 + 2,
+ r->y + ycenter-round/2 + 3,
+ round,
+ XmALIGNMENT_CENTER, XmSTRING_DIRECTION_L_TO_R, NULL);
+
+ shadow(w,r,false);
+}
+
+//===============================================================
+
+
+//===============================================================
+
+Boolean limit_node::visible() const { return show::want(show::limit); }
+
diff --git a/view/src/limit_node.h b/view/src/limit_node.h
new file mode 100644
index 0000000..7a2c30e
--- /dev/null
+++ b/view/src/limit_node.h
@@ -0,0 +1,74 @@
+#ifndef limit_node_H
+#define limit_node_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #8 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "node.h"
+class Limit;
+
+class limit_node : public node {
+public:
+
+ limit_node(host& h,ecf_node* n) : node(h,n) {}
+#ifdef BRIDGE
+ limit_node(host& h,sms_node* n,char b) : node(h,n,b) {}
+#endif
+ int maximum() const;
+ int value() const;
+ void nodes(node_lister&);
+ protected:
+ Limit* get() const;
+
+private:
+
+ limit_node(const limit_node&);
+ limit_node& operator=(const limit_node&);
+
+ virtual bool evaluate() const;
+ virtual void drawNode(Widget w,XRectangle* r,bool);
+ virtual void sizeNode(Widget w,XRectangle* r,bool);
+ virtual xmstring make_label_tree();
+
+ virtual void info(std::ostream&);
+ virtual const char* status_name() const;
+ virtual Boolean visible() const;
+ virtual bool match(const char*);
+
+ virtual void perlify(FILE*);
+};
+
+class limit_integer_node : public limit_node {
+ void sizeNode(Widget w,XRectangle* r,bool);
+ void drawNode(Widget w,XRectangle* r,bool);
+ void drawMeter(Widget w,XRectangle* r);
+public:
+ limit_integer_node(host& h,ecf_node* n): limit_node(h,n) {}
+#ifdef BRIDGE
+ limit_integer_node(host& h,sms_node* n,char b) : limit_node(h,n,b) {}
+#endif
+};
+
+class limit_boolean_node : public limit_node {
+public:
+ limit_boolean_node(host& h,ecf_node* n): limit_node(h,n) {}
+#ifdef BRIDGE
+ limit_boolean_node(host& h,sms_node* n,char b) : limit_node(h,n,b) {}
+#endif
+};
+
+inline void destroy(limit_node**) {}
+
+#endif
diff --git a/view/src/line.c b/view/src/line.c
new file mode 100644
index 0000000..17f2309
--- /dev/null
+++ b/view/src/line.c
@@ -0,0 +1,42 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include <stdio.h>
+
+main(int argc,char **argv)
+{
+ FILE* f = argc>2 ? fopen(argv[2],"r"):stdin;
+ int l = atol(argv[1]);
+ int n = 0;
+
+ char line[1024];
+
+ if(!f)
+ {
+ perror(argv[2]);
+ exit(1);
+ }
+
+ while(fgets(line,sizeof(line),f))
+ if(++n == l)
+ {
+ printf("%s\n",line);
+ exit(0);
+ }
+
+
+ exit(1);
+
+}
diff --git a/view/src/lister.cc b/view/src/lister.cc
new file mode 100644
index 0000000..d9c1850
--- /dev/null
+++ b/view/src/lister.cc
@@ -0,0 +1,65 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+/*
+#ifndef lister_H
+#include "lister.h"
+#endif
+*/
+
+template<class T>
+T* lister<T>::scan(T* first)
+{
+ if(sort())
+ {
+ int swap = 1;
+
+ while(swap)
+ {
+ T *d = first;
+ T *p = 0;
+ T *n = d?d->next:0;
+ swap = 0;
+
+ while(d && n)
+ {
+ if(compare(*n,*d))
+ {
+ T* q = n->next;
+
+ n->next = d;
+ d->next = q;
+
+ if(p) p->next = n;
+ else first = n;
+
+ swap++;
+ break;
+ }
+
+ p = d;
+ d = n;
+ n = n->next;
+ }
+ }
+ }
+ T *d = first;
+ while(d)
+ {
+ next(*d);
+ d = d->next;
+ }
+ return first;
+}
diff --git a/view/src/lister.h b/view/src/lister.h
new file mode 100644
index 0000000..77357fd
--- /dev/null
+++ b/view/src/lister.h
@@ -0,0 +1,42 @@
+#ifndef lister_H
+#define lister_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+template<class T>
+class lister {
+public:
+ virtual void next(T&) = 0;
+ virtual bool sort() { return false; }
+ virtual bool compare(T& a,T& b);
+ virtual T* scan(T*);
+};
+
+template<class T>
+bool lister<T>::compare(T& a,T& b)
+{ return strcmp(a.name().c_str(),b.name().c_str()) < 0; }
+
+#if defined(__GNUC__) || defined(hpux) || defined(_AIX)
+#include "lister.cc"
+#endif
+
+/*
+#ifdef AIX
+#pragma implementation("lister.cc")
+#endif
+*/
+
+#endif
diff --git a/view/src/log_event.cc b/view/src/log_event.cc
new file mode 100644
index 0000000..4f7d411
--- /dev/null
+++ b/view/src/log_event.cc
@@ -0,0 +1,355 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #10 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <stdlib.h>
+#include "log_event.h"
+#include "ecflowview.h"
+#include "gui.h"
+#include "host.h"
+#include "node.h"
+#include "parser.h"
+#include "array.h"
+#include "ecf_node.h"
+
+const int boxSize = 3;
+
+namespace status {
+const char *status_name[10]= {
+ (char*)"unknown", (char*)"suspended", (char*)"complete", (char*)"queued",
+ (char*)"submitted", (char*)"active", (char*)"aborted", (char*)"shutdown",
+ (char*)"halted" , NULL };
+}
+
+static event_sorter* sorter = 0;
+
+class log_cache : public array<log_event*> {
+public:
+ void reset();
+ void sort();
+ ~log_cache() { reset(); }
+};
+
+static log_cache cache;
+static str cached;
+
+void log_cache::reset()
+{
+ int c = count();
+ for(int i = 0; i < c ; i++)
+ (*this)[i]->detach();
+ clear();
+}
+
+static int compare(const void* a,const void* b)
+{
+ log_event** ea = (log_event**)a;
+ log_event** eb = (log_event**)b;
+ return sorter->compare(*ea,*eb);
+}
+
+void log_cache::sort()
+{
+ qsort(values_,count_,sizeof(log_event*),compare);
+}
+
+static node* gn = 0;
+
+log_event::log_event(node* n,const DateTime& time):
+ time_(time),
+ node_(n)
+{
+ attach();
+ cache.add(this);
+ observe(n);
+}
+
+log_event::~log_event()
+{
+}
+
+
+void log_event::load(host& h,const char* name,bool reset)
+{
+ if(reset)
+ {
+ cache.reset();
+ cached = str();
+ }
+
+ if(str(name) != cached)
+ {
+ gn = h.top();
+ std::string varlog = gn->variable("ECF_LOG");
+ std::string varhom = gn->variable("ECF_HOME");
+ std::string varnod = gn->variable("ECF_NODE");
+
+ if (gn->variable("ECF_PORT") == ecf_node::none()) {
+ varlog = gn->variable("SMSLOG");
+ varhom = gn->variable("SMSHOME");
+ varnod = gn->variable("SMSNODE");
+ }
+ char* vartmp = getenv("TMPDIR");
+
+ char buf[1024];
+ const char* p = name;
+
+ while(*p)
+ {
+ int i = 0;
+ while(*p && *p != ' ')
+ buf[i++] = *p++;
+ buf[i] = 0;
+
+ if(i) {
+ struct stat st;
+ if (stat(buf, &st) == (-1)) {
+ if (vartmp) {
+ char cmd[1024];
+
+ sprintf(cmd,"%s/%s",vartmp,varlog.c_str());
+ if (stat(cmd, &st) == (-1)) {
+ sprintf(cmd,"scp %s:%s/%s %s/.", varnod.c_str(), varhom.c_str(), varlog.c_str(),
+ getenv((char*)"TMPDIR"));
+ printf("%s\n", cmd);
+ system(cmd);
+
+ ::sleep(1);
+ sprintf(cmd,"%s/%s",vartmp,varlog.c_str());
+ { if (stat(cmd, &st) == (-1)) {
+ sprintf(cmd,"rcp %s:%s/%s %s/.", varnod.c_str(), varhom.c_str(), varlog.c_str(),
+ getenv((char*)"TMPDIR"));
+ printf("%s\n", cmd);
+ system(cmd);
+ }
+ sprintf(cmd,"%s/%s",vartmp,varlog.c_str());
+ ::sleep(1);
+ }
+
+ if (stat(cmd, &st) != (-1)) parser::parse(cmd);
+ } else {
+ parser::parse(cmd);
+ };
+ }
+ } else {
+ parser::parse(buf);
+ }
+ }
+ if(*p) p++;
+ }
+
+ gn = 0;
+ cached = name;
+ }
+}
+
+void log_event::sort(event_sorter& l)
+{
+ sorter = &l;
+ cache.sort();
+ sorter = 0;
+}
+
+void log_event::scan(node* n,event_lister& l)
+{
+ int c = cache.count();
+ for(int i = 0; i < c ; i++)
+ if(cache[i]->node_ != 0)
+ if(cache[i]->node_->is_my_parent(n))
+ l.next(cache[i]);
+}
+
+const node* log_event::find(const char* name)
+{
+ return gn?gn->find(name):0;
+}
+
+
+void log_event::size(Widget,XRectangle* r)
+{
+ r->width = r->height = 2*boxSize;
+}
+
+void log_event::draw(Widget w,XRectangle* r)
+{
+ GC gc = gui::blackGC();
+ XFillRectangles(XtDisplay(w), XtWindow(w), gc, r, 1); // was comment
+ XDrawLine(XtDisplay(w), XtWindow(w), gc,
+ r->x,
+ r->y,
+ r->x + r->width,
+ r->y + r->height);
+
+ XDrawLine(XtDisplay(w), XtWindow(w), gc,
+ r->x,
+ r->y + r->height,
+ r->x + r->width,
+ r->y);
+}
+
+class status_event : public log_event {
+ int status_;
+ virtual void draw(Widget,XRectangle*);
+
+ virtual bool start();
+ virtual bool end();
+ virtual char* text(char*);
+
+ virtual int status() { return status_; }
+
+public:
+ status_event(node* n,const DateTime& time,int status):
+ log_event(n,time), status_(status) {}
+};
+
+char* status_event::text(char* buf)
+{
+ sprintf(buf,"%s %s is %s",node_->type_name(),node_->full_name().c_str(),
+ status::status_name[status_]);
+ return buf;
+}
+
+class event_event : public log_event {
+ bool set_;
+ virtual node* owner() { return node_->parent(); }
+ virtual void draw(Widget,XRectangle*);
+ virtual char* text(char*);
+public:
+ event_event(node* n,const DateTime& time,bool s): log_event(n,time), set_(s) {}
+};
+
+char* event_event::text(char* buf)
+{
+ sprintf(buf,"event %s is %s",
+ node_->full_name().c_str(),
+ set_?"set":"cleared");
+ return buf;
+}
+
+//===========================================
+void event_event::draw(Widget w,XRectangle* r)
+{
+ if(set_)
+ XFillRectangles(XtDisplay(w),XtWindow(w),
+ gui::blueGC(),r,1);
+ else
+ XDrawRectangles(XtDisplay(w),XtWindow(w),
+ gui::blueGC(),r,1);
+}
+
+//===========================================
+class meter_event : public log_event {
+ int step_;
+ virtual node* owner() { return node_->parent(); }
+ virtual void draw(Widget,XRectangle*);
+ virtual char* text(char*);
+public:
+ meter_event(node* n,const DateTime& time,int s): log_event(n,time), step_(s) {}
+};
+
+char* meter_event::text(char* buf)
+{
+ sprintf(buf,"meter %s reaches %d",node_->full_name().c_str(),step_);
+ return buf;
+}
+
+void meter_event::draw(Widget w,XRectangle* r)
+{
+ XDrawArc(XtDisplay(w),
+ XtWindow(w),
+ gui::blackGC(),
+ r->x,
+ r->y,
+ r->height,
+ r->height,
+ 0,360*64);
+#if 0
+ char buf[80];
+ sprintf(buf,"%d",step_);
+ xmstring s(buf);
+ XmStringDraw(XtDisplay(w),XtWindow(w),
+ gui::tinyfont(),
+ s,
+ gui::blackGC(),
+ r->x,
+ r->y,
+ r->width,
+ XmALIGNMENT_CENTER, XmSTRING_DIRECTION_L_TO_R, r);
+#endif
+}
+
+bool status_event::start()
+{
+ return status_ == STATUS_SUBMITTED;
+}
+
+bool status_event::end()
+{
+ return status_ == STATUS_COMPLETE;
+}
+
+//=========================================================
+
+void status_event::draw(Widget w,XRectangle* r)
+{
+ GC gc = gui::colorGC(status_);
+#if 1
+ XFillArc(XtDisplay(w),
+ XtWindow(w),
+ gc,
+ r->x,
+ r->y,
+ r->height,
+ r->height,
+ 0,360*64);
+#else
+ XDrawLine(XtDisplay(w), XtWindow(w), gc,
+ r->x,
+ r->y,
+ r->x + r->width,
+ r->y + r->height);
+
+ XDrawLine(XtDisplay(w), XtWindow(w), gc,
+ r->x,
+ r->y + r->height,
+ r->x + r->width,
+ r->y);
+#endif
+}
+
+void log_event::status_event(const DateTime& t,node* n,int s)
+{
+ if (0) {
+ if (n)
+ std::cout << "# event: " << t.date << " " << t.time << " " << n->full_name() << " " << status::status_name[s] << "\n";
+ else
+ std::cout << "# event: " << t.date << " " << t.time << " no path " << status::status_name[s] << "\n";
+ }
+ if(n) new ::status_event(n,t,s);
+}
+
+void log_event::event_event(const DateTime& t,node* n,bool set)
+{
+ if(n) new ::event_event(n,t,set);
+}
+
+void log_event::meter_event(const DateTime& t,node* n,int s)
+{
+ if(n) new ::meter_event(n,t,s);
+}
+
+void log_event::gone(observable*)
+{
+ node_ = 0;
+}
diff --git a/view/src/log_event.h b/view/src/log_event.h
new file mode 100644
index 0000000..f92c122
--- /dev/null
+++ b/view/src/log_event.h
@@ -0,0 +1,132 @@
+#ifndef log_event_H
+#define log_event_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#ifdef NO_BOOL
+#include "bool.h"
+#endif
+
+#ifndef counted_H
+#include "counted.h"
+#endif
+
+#ifndef observer_H
+#include "observer.h"
+#endif
+
+#include <Xm/Xm.h>
+#include "SimpleTime.h"
+
+class node;
+class host;
+class log_event;
+class str;
+
+class event_lister {
+public:
+ virtual void next(log_event*) = 0;
+};
+
+class event_sorter {
+public:
+ virtual int compare(log_event*,log_event*) = 0;
+};
+
+inline
+bool operator<(const DateTime& d1,const DateTime& d2)
+{
+ return d1.date < d2.date || (d1.date == d2.date && d1.time < d2.time);
+}
+
+inline
+bool operator>(const DateTime& d1,const DateTime& d2)
+{
+ return d2 < d1;
+}
+
+inline
+bool operator<=(const DateTime& d1,const DateTime& d2)
+{
+ return d1.date <= d2.date || (d1.date == d2.date && d1.time <= d2.time);
+}
+
+
+inline
+bool operator==(const DateTime& d1,const DateTime& d2)
+{
+ return (d1.date == d2.date) && (d1.time == d2.time);
+}
+
+inline
+bool operator!=(const DateTime& d1,const DateTime& d2)
+{
+ return !(d1==d2);
+}
+
+const DateTime kSmallDate = { 19000101, 0};
+const DateTime kLargeDate = { 21000101, 0};
+
+class log_event : public counted, public observer {
+public:
+
+ log_event(node*,const DateTime&);
+
+ const DateTime& time() const { return time_; }
+
+ virtual bool start() { return false; }
+ virtual bool end() { return false; }
+
+ virtual node* owner() { return node_; }
+ virtual node* get_node() { return node_; }
+
+ virtual int status() { return -1; }
+
+ virtual char* text(char*) = 0;
+
+ virtual void draw(Widget,XRectangle*);
+ virtual void size(Widget,XRectangle*);
+
+ static void status_event(const DateTime&,node*,int);
+ static void event_event(const DateTime&,node*,bool);
+ static void meter_event(const DateTime&,node*,int);
+
+ static void load(host&,const char*,bool = false);
+ static void scan(node*,event_lister&);
+ static void sort(event_sorter&);
+ static const node* find(const char*);
+
+ static int compare(const log_event*,const log_event*);
+
+protected:
+
+ virtual ~log_event(); // Change to virtual if base class
+
+ DateTime time_;
+ node* node_;
+
+private:
+
+ log_event(const log_event&);
+ log_event& operator=(const log_event&);
+
+ void notification(observable*) { }
+ void adoption(observable* o,observable* n) { node_ = (node*)n; }
+ void gone(observable*);
+};
+
+
+#endif
diff --git a/view/src/log_file.h b/view/src/log_file.h
new file mode 100644
index 0000000..3dc31da
--- /dev/null
+++ b/view/src/log_file.h
@@ -0,0 +1,129 @@
+#ifndef log_file_H
+#define log_file_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#ifndef input_H
+#include "input.h"
+#endif
+
+#include "stl.h"
+
+
+class host;
+class log_event;
+
+class log_file : public input {
+public:
+
+
+// -- Exceptions
+ // None
+
+// -- Contructors
+
+ log_file(host&,const char*);
+
+// -- Destructor
+
+ ~log_file(); // Change to virtual if base class
+
+// -- Convertors
+ // None
+
+// -- Operators
+ // None
+
+// -- Methods
+
+ bool update();
+
+// -- Overridden methods
+
+
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+ // Uncomment for persistent, remove otherwise
+ // static os_typespec* get_os_typespec();
+
+protected:
+
+// -- Members
+ // None
+
+// -- Methods
+
+ // void print(ostream&) const; // Change to virtual if base class
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+private:
+
+// No copy allowed
+
+ log_file(const log_file&);
+ log_file& operator=(const log_file&);
+
+// -- Members
+
+ string path_;
+ bool loading_;
+ bool ready_;
+ time_t last_;
+ host& owner_;
+
+// -- Methods
+
+ void cleanup();
+
+// -- Overridden methods
+
+ void ready(const char*);
+ void done(FILE*);
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+// -- Friends
+
+ //friend ostream& operator<<(ostream& s,const log_file& p)
+ // { p.print(s); return s; }
+
+};
+
+inline void destroy(log_file**) {}
+
+// If persistent, uncomment, otherwise remove
+//#ifdef _ODI_OSSG_
+//OS_MARK_SCHEMA_TYPE(log_file);
+//#endif
+
+#endif
diff --git a/view/src/logsvr.cc b/view/src/logsvr.cc
new file mode 100644
index 0000000..77c1e56
--- /dev/null
+++ b/view/src/logsvr.cc
@@ -0,0 +1,244 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#ifndef logsvr_H
+#include "logsvr.h"
+#endif
+
+#ifndef gui_H
+#include "gui.h"
+#endif
+
+#include "tmp_file.h"
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#ifdef AIX
+#include <memory.h>
+#endif
+
+#include "auto_alarm.h"
+
+#define FAIL(a) do { perror(a); exit(1); } while(0)
+
+logsvr::logsvr(std::string host,std::string cport)
+ : soc_(-1)
+ , host_ (host)
+ , port_ (cport)
+{
+ struct hostent *ht = gethostbyname( host.c_str() );
+ if (ht == NULL) { soc_ = -1; return; }
+ connect(host,!cport.empty() ? atoi(cport.c_str()) : 19999);
+}
+
+static jmp_buf env;
+/* static void (*old_alarm)(int); */
+
+static void catch_alarm(int)
+{
+ printf("got alarm\n");
+ /* longjmp(env,1); */
+}
+
+void logsvr::connect(std::string host,int port)
+{
+ /* typedef unsigned long addr_type; */
+ typedef in_addr_t addr_type;
+
+ /* addr_type none = (addr_type)-1; */
+ addr_type addr;
+
+ struct sockaddr_in s_in;
+ struct hostent *him;
+
+ soc_ = socket(AF_INET, SOCK_STREAM, 0);
+ if(soc_ < 0)
+ {
+ gui::syserr("Cannot create socket");
+ return;
+ }
+
+ bzero(&s_in,sizeof(s_in));
+
+ s_in.sin_port = htons(port);
+ s_in.sin_family = AF_INET;
+ addr = inet_addr(host.c_str());
+ s_in.sin_addr.s_addr = addr;
+#ifdef SVR4
+ if(addr == (in_addr_t) 0xffffffff)
+#else
+ if(addr == INADDR_NONE)
+#endif
+ {
+ if ((him=gethostbyname(host.c_str()))==NULL)
+ {
+ gui::error("Unknown Host %s",host.c_str());
+ return;
+ }
+ s_in.sin_family = him->h_addrtype;
+ bcopy(him->h_addr_list[0],&s_in.sin_addr,him->h_length);
+ }
+
+ char* timeout = getenv ("ECFLOWVIEW_LOGTIMEOUT");
+ int time_out = timeout ? atoi(timeout) : 3;
+
+ struct sigaction sa = { { 0, }, };
+ struct sigaction old;
+ sa.sa_handler = catch_alarm;
+ sigemptyset(&sa.sa_mask);
+
+ if(sigaction(SIGALRM, &sa, &old))
+ perror("sigaction");
+
+ ::alarm(time_out);
+ perror("alarm");
+
+ if(setjmp(env) == 0)
+ {
+ printf("connect %s\n",host.c_str());
+ if(::connect(soc_,(struct sockaddr*)&s_in,sizeof(s_in)) < 0)
+ {
+ perror("connect");
+ close(soc_);
+ soc_ = -1;
+ }
+ }
+ else
+ {
+ printf("cleanup up\n");
+ close(soc_);
+ soc_ = -1;
+ }
+ ::alarm(0);
+ sigaction(SIGALRM, &old, &sa);
+}
+
+logsvr::~logsvr()
+{
+ close(soc_);
+}
+
+tmp_file logsvr::getfile(std::string name)
+{
+ tmp_file empty((char*)"",false);
+ if(soc_ < 0)
+ return empty;
+
+ write(soc_,"get ",4);
+ write(soc_,name.c_str(),name.size());
+ write(soc_,"\n",1);
+
+ const int size = 64*1204;
+ char buf[size];
+ unsigned int len = 0;
+ int total = 0;
+
+ tmp_file out(tmpnam(NULL));
+ FILE *f = fopen(out.c_str(),"w");
+
+ if(!f)
+ {
+ char buf[2048];
+ sprintf(buf,"Cannot create %s",out.c_str());
+ gui::syserr(buf);
+ return empty;
+ }
+
+ while( (len = read(soc_,buf,size)) > 0)
+ {
+ if(fwrite(buf,1,len,f) != len)
+ {
+ char buf[2048];
+ sprintf(buf,"Write error on %s",out.c_str());
+ gui::syserr(buf);
+ fclose(f);
+ return empty;
+ }
+ total += len;
+ }
+
+ sprintf(buf, "\n# served by %s@%s # telnet %s %s # get %s",
+ host_.c_str(), port_.c_str(),
+ host_.c_str(), port_.c_str(),
+ name.c_str());
+ fwrite(buf,1,size,f);
+
+ if(fclose(f))
+ {
+ char buf[2048];
+ sprintf(buf,"Write error on %s",out.c_str());
+ gui::syserr(buf);
+ return empty;
+ }
+
+ if(total)
+ return out;
+
+ return empty;
+}
+
+ecf_dir *logsvr::getdir(const char* name)
+{
+ if(soc_ < 0)
+ return 0;
+
+ write(soc_,"list ",5);
+ write(soc_,name,strlen(name));
+ write(soc_,"\n",1);
+
+ FILE* f = fdopen(soc_,"r");
+
+ char buf[2048];
+
+ ecf_dir* dir = 0;
+
+ while(fgets(buf,sizeof(buf),f))
+ {
+ ecf_dir *s;
+ if( (s = new ecf_dir()))
+ {
+ s->next = 0x0;
+ char name[2048];
+ sscanf(buf,"%d %d %d %d %d %d %d %s",
+ & s->mode,
+ & s->uid,
+ & s->gid,
+ & s->size,
+ & s->atime,
+ & s->mtime,
+ & s->ctime,
+ name);
+
+ s->name_ = strdup(name);
+ if (dir) {
+ s->next = dir->next;
+ dir->next = s;
+ } else dir = s;
+ }
+ }
+
+ return dir;
+}
diff --git a/view/src/logsvr.h b/view/src/logsvr.h
new file mode 100644
index 0000000..406c4b5
--- /dev/null
+++ b/view/src/logsvr.h
@@ -0,0 +1,54 @@
+#ifndef logsvr_H
+#define logsvr_H
+
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#ifndef ecflowview_H
+#include "ecflowview.h"
+#endif
+
+
+#ifndef tmp_file_H
+#include "tmp_file.h"
+#endif
+
+
+class logsvr {
+public:
+
+ logsvr(std::string host,std::string port);
+
+ ~logsvr(); // Change to virtual if base class
+
+ tmp_file getfile(std::string name);
+ ecf_dir* getdir(const char* name);
+ bool ok() const { return soc_ >= 0; }
+
+private:
+
+ logsvr(const logsvr&);
+ logsvr& operator=(const logsvr&);
+
+ int soc_;
+
+ void connect(std::string,int);
+
+ std::string host_, port_;
+};
+
+inline void destroy(logsvr**) {}
+
+#endif
diff --git a/view/src/mail.cc b/view/src/mail.cc
new file mode 100644
index 0000000..a3f3b12
--- /dev/null
+++ b/view/src/mail.cc
@@ -0,0 +1,246 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "mail.h"
+#include "host.h"
+#include "runnable.h"
+#include <Xm/List.h>
+#include <Xm/Text.h>
+#include "gui.h"
+#include "extent.h"
+
+extern "C" {
+#include "xec.h"
+}
+
+
+class mail_user : public extent<mail_user> {
+ char *host_;
+ char *user_;
+ bool mark_;
+public:
+
+ mail_user(const char* h,const char* u):
+ host_(XtNewString(h)),
+ user_(XtNewString(u)),
+ mark_(true)
+ {
+ }
+
+ ~mail_user()
+ {
+ XtFree(host_);
+ XtFree(user_);
+ }
+
+ static void add(mail&,const char*,const char*);
+ static void remove(mail&,const char*);
+
+ static void mark();
+ static void sweep(mail&,const char*);
+};
+
+void mail_user::mark()
+{
+ mail_user *p = first();
+ while(p)
+ {
+ p->mark_ = false;
+ p = p->next();
+ }
+}
+
+void mail_user::add(mail& m,const char* h,const char* u)
+{
+ mail_user *p = first();
+ while(p)
+ {
+ if(strcmp(p->host_,h) == 0 && strcmp(p->user_,u) == 0)
+ {
+ p->mark_ = true;
+ return;
+ }
+ p = p->next();
+ }
+ new mail_user(h,u);
+ m.add(h,u);
+}
+
+void mail_user::remove(mail& m,const char* h)
+{
+ mail_user *p = first();
+ while(p)
+ {
+ mail_user* n = p->next();
+ if(strcmp(p->host_,h) == 0)
+ {
+ m.remove(p->host_,p->user_);
+ delete p;
+ }
+ p = n;
+ }
+}
+
+void mail_user::sweep(mail& m,const char* h)
+{
+ mail_user *p = first();
+ while(p)
+ {
+ mail_user* n = p->next();
+ if(strcmp(p->host_,h) == 0 && !p->mark_)
+ {
+ m.remove(p->host_,p->user_);
+ delete p;
+ }
+ p = n;
+ }
+}
+
+mail& mail::instance()
+{
+ static mail *m = new mail();
+ return *m;
+}
+
+mail::mail():
+ timeout(1)
+{
+ create(gui::top());
+}
+
+mail::~mail()
+{
+}
+
+void mail::run()
+{
+ //printf("mail::run\n");
+ host::check_all_mail();
+ drift(1,3600*24);
+}
+
+void mail::recieved(host* h,std::list< std::string >&l,bool show)
+{
+ instance().new_mail(h,l,show);
+}
+
+class show_mail : public runnable {
+ Widget widget_;
+ void run() { XtManageChild(widget_); disable(); gui::raise(); }
+public:
+ show_mail() : widget_(0) {}
+ void show(Widget w) { widget_ = w; enable(); }
+};
+
+
+void mail::add(const char* buf)
+{
+ long len = XmTextGetLastPosition(text_);
+ XmTextSetInsertionPosition(text_,len);
+ XmTextReplace(text_,len,len,(char*)buf);
+ len += strlen(buf);
+ XmTextSetInsertionPosition(text_,len);
+ XmTextShowPosition(text_,len);
+}
+
+
+void mail::new_mail(host* h,std::list<std::string>& l,bool show)
+{
+ mail_user::mark();
+
+ static show_mail s;
+ observe(h);
+ if(show) {
+ s.show(form_);
+ enable();
+ }
+
+ mail_user::sweep(*this,h->name());
+}
+
+void mail::sendCB(Widget,XtPointer)
+{
+ int count;
+ XtVaGetValues(list_,XmNselectedItemCount,&count,NULL);
+ if(count == 0)
+ {
+ /* xec_ListSelectAll(list_); */
+ /* XtVaGetValues(list_,XmNselectedItemCount,&count,0); */
+ gui::error("No recipient selected");
+ return;
+ }
+
+ XmString *items;
+ XtVaGetValues(list_,XmNselectedItems,&items,NULL);
+
+ char* p = XmTextGetString(input_);
+ XmTextSetString(input_,"");
+
+ for(int i = 0 ; i < count; i++)
+ {
+ char *u = xec_GetString(items[i]);
+ char *q = u;
+ while(*q && *q != '@') q++;
+ *q = 0;
+
+ (void)host::find(q+1);
+ XtFree(u);
+ }
+
+ add(p);
+ add("\n");
+
+ XtFree(p);
+ run();
+ frequency(1);
+}
+
+void mail::closeCB(Widget,XtPointer)
+{
+ disable();
+ XtUnmanageChild(form_);
+}
+
+void mail::gone(observable* h)
+{
+ mail_user::remove(*this,((host*)h)->name());
+}
+
+void mail::add(const char* h,const char* u)
+{
+ char buf[1024];
+ sprintf(buf,"%s@%s",u,h);
+ xec_AddListItem(list_,buf);
+}
+
+void mail::remove(const char* h,const char* u)
+{
+ char buf[1024];
+ sprintf(buf,"%s@%s",u,h);
+ xec_RemoveListItem(list_,buf);
+}
+
+
+void mail::login(const char* n)
+{
+ // FILL recieved(host::find(n),0,false);
+}
+
+void mail::logout(const char* n)
+{
+ instance().gone(host::find(n));
+}
+
+IMP(mail_user)
diff --git a/view/src/mail.h b/view/src/mail.h
new file mode 100644
index 0000000..04599ff
--- /dev/null
+++ b/view/src/mail.h
@@ -0,0 +1,67 @@
+#ifndef mail_H
+#define mail_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include<list>
+#include "uimail.h"
+#include "observer.h"
+#include "timeout.h"
+
+#ifdef NO_BOOL
+#include "bool.h"
+#endif
+
+#include <string>
+
+class host;
+
+class mail : public observer, public mail_shell_c, public timeout {
+public:
+
+ mail();
+
+ ~mail(); // Change to virtual if base class
+
+ void add(const char*,const char*);
+ void remove(const char*,const char*);
+
+ static void recieved(host*,std::list< std::string >&,bool = true);
+ static void login(const char*);
+ static void logout(const char*);
+
+private:
+
+ mail(const mail&);
+ mail& operator=(const mail&);
+
+ void new_mail(host* h,std::list<std::string>& l,bool show);
+ // void new_mail(host*,std::list< std::string >&,bool);
+ void add(const char*);
+
+ virtual void run();
+ virtual void adoption(observable*,observable*) {}
+ virtual void notification(observable*) {}
+ virtual void gone(observable*);
+
+ static mail& instance();
+
+ void sendCB(Widget,XtPointer);
+ void closeCB(Widget,XtPointer);
+};
+
+inline void destroy(mail**) {}
+#endif
diff --git a/view/src/manual.cc b/view/src/manual.cc
new file mode 100644
index 0000000..9c5d0c7
--- /dev/null
+++ b/view/src/manual.cc
@@ -0,0 +1,53 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "manual.h"
+#include "host.h"
+#include "node.h"
+#include <Xm/Text.h>
+
+extern "C" {
+#include "xec.h"
+}
+
+manual::manual(panel_window& w):
+ panel(w),
+ text_window(false)
+{
+}
+
+manual::~manual()
+{
+}
+
+void manual::clear()
+{
+ text_window::clear();
+}
+
+void manual::show(node& n)
+{
+ load(n.serv().manual(n));
+}
+
+Boolean manual::enabled(node& n)
+{
+ return n.hasManual();
+}
+
+void manual::create (Widget parent, char *widget_name )
+{
+ manual_form_c::create(parent,widget_name);
+}
diff --git a/view/src/manual.h b/view/src/manual.h
new file mode 100644
index 0000000..2aace95
--- /dev/null
+++ b/view/src/manual.h
@@ -0,0 +1,66 @@
+#ifndef manual_H
+#define manual_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "uimanual.h"
+
+#ifndef panel_H
+#include "panel.h"
+#endif
+
+#ifndef text_window_H
+#include "text_window.h"
+#endif
+
+class manual : public panel, public manual_form_c, public text_window {
+public:
+
+ manual(panel_window&);
+
+ ~manual(); // Change to virtual if base class
+
+ virtual const char* name() const { return "Manual"; }
+ virtual void show(node&);
+ virtual Boolean enabled(node&);
+ virtual void clear();
+ virtual Widget widget() { return manual_form_c::xd_rootwidget(); }
+
+ virtual Widget tools() { return tools_; }
+ virtual Widget text() { return text_; }
+ virtual void create (Widget parent, char *widget_name = 0 );
+
+private:
+
+ manual(const manual&);
+ manual& operator=(const manual&);
+
+ virtual void externalCB(Widget ,XtPointer )
+ { text_window::open_viewer();}
+
+ virtual void searchCB(Widget ,XtPointer )
+ { text_window::open_search();}
+
+ virtual bool can_print() { return true; }
+ virtual bool can_save() { return true; }
+ virtual void print() { text_window::print(); }
+ virtual void save() { text_window::save(); }
+
+};
+
+inline void destroy(manual**) {}
+
+#endif
diff --git a/view/src/menu2c.sh b/view/src/menu2c.sh
new file mode 100644
index 0000000..845807a
--- /dev/null
+++ b/view/src/menu2c.sh
@@ -0,0 +1,16 @@
+#!/bin/ksh
+
+## Copyright 2009-2016 ECMWF.
+## This software is licensed under the terms of the Apache Licence version 2.0
+## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+## In applying this licence, ECMWF does not waive the privileges and immunities
+## granted to it by virtue of its status as an intergovernmental organisation
+## nor does it submit to any jurisdiction.
+
+
+# cat ecflowview.menu | menu2c.sh > ecflowview.menu.h
+while read -r line ; do
+ l=$(echo $line | sed -e 's:":\\":gi')
+ echo "(char*) \" $l \","
+done
+echo NULL
diff --git a/view/src/menu_prefs.cc b/view/src/menu_prefs.cc
new file mode 100644
index 0000000..8cf059f
--- /dev/null
+++ b/view/src/menu_prefs.cc
@@ -0,0 +1,75 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "arch.h"
+#include "menu_prefs.h"
+#include "gui.h"
+#include "xec.h"
+#include "extent.h"
+#include <ctype.h>
+#include <Xm/Text.h>
+#include <Xm/ToggleB.h>
+#include <Xm/List.h>
+#include "menus.h"
+
+void menu_prefs::create(Widget w,char*)
+{
+ menu_form_c::create(w);
+ prefs::setup(w);
+ build_list();
+}
+
+void menu_prefs::build_list()
+{
+ XmListDeleteAllItems(list_);
+ menus::fillList(list_);
+}
+
+void menu_prefs::menuCB(Widget,XtPointer)
+{
+}
+
+void menu_prefs::addCB(Widget,XtPointer)
+{
+
+}
+
+void menu_prefs::removeCB(Widget,XtPointer)
+{
+
+}
+
+void menu_prefs::check_remove()
+{
+}
+
+void menu_prefs::browseCB(Widget,XtPointer data)
+{
+ XmListCallbackStruct *cb = (XmListCallbackStruct *) data;
+ char *p = xec_GetString(cb->item);
+ char *q = p;
+ while(*q && *q == ' ') q++;
+ XmTextSetString(title_,q);
+ XtFree(p);
+}
+
+
+void menu_prefs::changedCB(Widget,XtPointer data)
+{
+}
+
+void menu_prefs::updateCB(Widget,XtPointer data)
+{
+}
diff --git a/view/src/menu_prefs.h b/view/src/menu_prefs.h
new file mode 100644
index 0000000..cab89ca
--- /dev/null
+++ b/view/src/menu_prefs.h
@@ -0,0 +1,60 @@
+#ifndef menu_prefs_H
+#define menu_prefs_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#ifndef prefs_H
+#include "prefs.h"
+#endif
+
+#ifndef uimenu
+#include "uimenu.h"
+#endif
+
+class menu_prefs : public prefs, public menu_form_c {
+public:
+ menu_prefs() : changing_(false) {}
+
+ ~menu_prefs() {}
+
+ void check_remove();
+
+ virtual Widget widget() { return _xd_rootwidget; }
+
+ static void add_host(const char*);
+
+private:
+
+ menu_prefs(const menu_prefs&);
+ menu_prefs& operator=(const menu_prefs&);
+
+ bool changing_;
+
+ void build_list();
+
+ virtual void browseCB( Widget w, XtPointer );
+
+ virtual void menuCB( Widget w, XtPointer );
+ virtual void addCB( Widget w, XtPointer );
+ virtual void removeCB( Widget w, XtPointer );
+ virtual void updateCB( Widget w, XtPointer );
+ virtual void changedCB( Widget w, XtPointer );
+
+ virtual void create(Widget w,char*);
+};
+
+inline void destroy(menu_prefs**) {}
+#endif
diff --git a/view/src/menul.c b/view/src/menul.c
new file mode 100644
index 0000000..48e39c9
--- /dev/null
+++ b/view/src/menul.c
@@ -0,0 +1,3227 @@
+
+#line 3 "<stdout>"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 37
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart(yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+extern yy_size_t yyleng;
+
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires
+ * access to the local variable yy_act. Since yyless() is a macro, it would break
+ * existing scanners that call yyless() from OUTSIDE yylex.
+ * One obvious solution it to make yy_act a global. I tried that, and saw
+ * a 5% performance hit in a non-yylineno scanner, because yy_act is
+ * normally declared as a register variable-- so it is not worth it.
+ */
+ #define YY_LESS_LINENO(n) \
+ do { \
+ int yyl;\
+ for ( yyl = n; yyl < yyleng; ++yyl )\
+ if ( yytext[yyl] == '\n' )\
+ --yylineno;\
+ }while(0)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = (yy_hold_char); \
+ YY_RESTORE_YY_MORE_OFFSET \
+ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr) )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ yy_size_t yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+ : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */
+yy_size_t yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart (FILE *input_file );
+void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer );
+YY_BUFFER_STATE yy_create_buffer (FILE *file,int size );
+void yy_delete_buffer (YY_BUFFER_STATE b );
+void yy_flush_buffer (YY_BUFFER_STATE b );
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer );
+void yypop_buffer_state (void );
+
+static void yyensure_buffer_stack (void );
+static void yy_load_buffer_state (void );
+static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file );
+
+#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size );
+YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str );
+YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len );
+
+void *yyalloc (yy_size_t );
+void *yyrealloc (void *,yy_size_t );
+void yyfree (void * );
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ yyensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer(yyin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ yyensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer(yyin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+typedef unsigned char YY_CHAR;
+
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+
+typedef int yy_state_type;
+
+#define YY_FLEX_LEX_COMPAT
+extern int yylineno;
+
+int yylineno = 1;
+
+extern char yytext[];
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[] );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ (yytext_ptr) = yy_bp; \
+ yyleng = (size_t) (yy_cp - yy_bp); \
+ (yy_hold_char) = *yy_cp; \
+ *yy_cp = '\0'; \
+ if ( yyleng + (yy_more_offset) >= YYLMAX ) \
+ YY_FATAL_ERROR( "token too large, exceeds YYLMAX" ); \
+ yy_flex_strncpy( &yytext[(yy_more_offset)], (yytext_ptr), yyleng + 1 ); \
+ yyleng += (yy_more_offset); \
+ (yy_prev_more_offset) = (yy_more_offset); \
+ (yy_more_offset) = 0; \
+ (yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 139
+#define YY_END_OF_BUFFER 140
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static yyconst flex_int16_t yy_acclist[903] =
+ { 0,
+ 140, 135, 139, 134, 135, 139, 136, 139, 135, 139,
+ 16385, 69, 135, 139, 135, 138, 139, 70, 135, 139,
+ 68, 135, 139, 68, 135, 139, 68, 135, 139, 68,
+ 135, 139, 68, 135, 139, 68, 135, 139, 68, 135,
+ 139, 68, 135, 139, 68, 135, 139, 68, 135, 139,
+ 68, 135, 139, 68, 135, 139, 68, 135, 139, 68,
+ 135, 139, 68, 135, 139, 68, 135, 139, 68, 135,
+ 139, 68, 135, 139, 68, 135, 139, 68, 135, 139,
+ 68, 135, 139, 68, 135, 139, 135, 139, 68, 135,
+ 139, 68, 135, 139, 68, 135, 139, 68, 135, 139,
+
+ 68, 135, 139, 133, 139, 132, 133, 139, 132, 133,
+ 139, 133, 139,16385, 133, 138, 139, 133, 139, 131,
+ 133, 139, 129, 130, 133, 139, 130, 133, 139, 130,
+ 133, 139, 130, 133, 139, 130, 133, 139, 130, 133,
+ 139, 130, 133, 139, 130, 133, 139, 130, 133, 139,
+ 130, 133, 139, 130, 133, 139, 130, 133, 139, 130,
+ 133, 139, 130, 133, 139, 130, 133, 139, 130, 133,
+ 139, 130, 133, 139, 130, 133, 139, 130, 133, 139,
+ 130, 133, 139, 130, 133, 139, 130, 133, 139, 130,
+ 133, 139, 133, 139, 130, 133, 139,16385, 8193, 68,
+
+ 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 40, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68, 131, 129,
+ 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
+ 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
+ 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
+ 130, 130, 130, 130, 130, 130, 130, 130, 130, 68,
+ 68, 68, 68, 6, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+
+ 68, 68, 68, 68, 68, 68, 68, 15, 68, 68,
+ 20, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+ 39, 68, 68, 68, 68, 68, 68, 68, 68, 130,
+ 130, 130, 130,16504, 130, 130, 130, 130, 130, 130,
+ 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
+ 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
+ 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
+ 130, 130, 130, 130, 68, 68, 68, 68, 68, 43,
+ 68, 68, 68, 68, 68, 68, 68, 68, 68, 4,
+ 68, 68, 68, 21, 68, 5, 68, 46, 68, 42,
+
+ 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+ 24, 68, 68, 45, 68, 68, 68, 3, 68, 68,
+ 16434,16435, 48,16433,16436,16444,16445,16443,16504, 8312,
+ 130,16504,16446, 130, 130, 130, 130, 130, 130, 130,
+ 130, 130, 130, 130, 130,16484, 130, 130, 130, 130,
+ 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
+ 130, 130, 130,16474, 130, 79, 130, 130, 130,16508,
+ 130, 130, 130, 58, 68, 68, 47, 68, 31, 68,
+ 14, 68, 68, 25, 68, 68, 68, 68, 68, 68,
+ 27, 68, 26, 68, 68, 28, 68, 68, 68, 68,
+
+ 68, 68, 68, 68, 68, 22, 68, 68, 68, 68,
+ 68, 68,16434, 8242,16435, 8243,16433, 8241,16436, 8244,
+ 16444, 8252,16445, 8253,16443, 8251,16446, 8254, 130, 130,
+ 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
+ 130,16484, 8292,16491, 130, 130,16489, 130, 130, 130,
+ 16497, 130, 130, 130, 130, 130,16495, 130, 130, 130,
+ 130, 130,16474, 8282, 130,16485,16486, 130, 130, 130,
+ 16508, 8316,16487, 130, 130, 130, 68, 12, 68, 68,
+ 23, 68, 17, 68, 68, 68, 68, 68, 68, 18,
+ 68, 68, 10, 68, 30, 68, 68, 68, 19, 68,
+
+ 68, 68, 68, 68, 68, 41, 68, 68, 55, 56,
+ 53, 54, 57,16507,16506,16470, 130, 130,16499, 130,
+ 130,16496, 130,16467, 130, 80, 130, 130, 130, 130,
+ 16491, 8299, 130,16500,16489, 8297, 130,16493,16494, 130,
+ 16469,16497, 8305,16476, 130, 130, 130,16475,16495, 8303,
+ 130, 130, 130, 130, 130,16486,16485,16486, 8293, 8294,
+ 16485,16486,16501, 130, 130,16487, 8295, 130, 130,16512,
+ 130, 63, 13, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 7, 68, 68, 2,
+ 68,16505,16507, 8315,16506, 8314,16470, 8278, 130, 73,
+
+ 16499, 8307, 130, 130,16496, 8304, 81,16467, 8275, 130,
+ 130, 130,16498, 130, 130,16500, 8308,16494,16493,16494,
+ 8301, 8302,16493,16494, 130,16469, 8277,16476, 8284,16477,
+ 16488, 130,16475, 8283, 72, 130, 130, 130,16482,16486,
+ 8294,16486,16501, 8309, 130, 130, 130, 130,16512, 8320,
+ 130, 9, 68, 35, 68, 36, 68, 34, 68, 68,
+ 68, 32, 68, 68, 68, 16, 68, 68, 68, 29,
+ 68, 126,16505, 8313, 78, 130, 130, 130,16466,16511,
+ 130,16498, 8306, 130, 130,16494, 8302,16494, 130,16477,
+ 8285,16488, 8296, 130,16478,16480, 130,16482, 8290, 130,
+
+ 16481,16483, 130, 76, 68, 37, 68, 44, 68, 38,
+ 68, 11, 68, 8, 68, 130, 130, 130,16466,16511,
+ 8274, 8319,16466,16511,16466,16511, 71, 130,16490,16521,
+ 16471,16478, 8286,16480, 8288,16479, 130,16481, 8289,16483,
+ 8291, 130, 65, 66, 64, 67, 68, 130, 130, 130,
+ 16466,16511,16466,16511, 130,16490, 8298,16521, 8329,16471,
+ 8279,16479, 8287, 77,16503,16492, 68,16473,16468,16466,
+ 16511,16466,16511, 130,16503, 8311,16492, 8300, 33, 68,
+ 16473, 8281,16468, 8276,16466,16511,16466,16511, 130, 75,
+ 16466,16511, 74,16466,16511,16502,16502, 8310,16472,16472,
+
+ 8280, 125
+ } ;
+
+static yyconst flex_int16_t yy_accept[802] =
+ { 0,
+ 1, 1, 1, 1, 1, 2, 4, 7, 9, 12,
+ 15, 18, 21, 24, 27, 30, 33, 36, 39, 42,
+ 45, 48, 51, 54, 57, 60, 63, 66, 69, 72,
+ 75, 78, 81, 84, 87, 89, 92, 95, 98, 101,
+ 104, 106, 109, 112, 115, 118, 120, 123, 127, 130,
+ 133, 136, 139, 142, 145, 148, 151, 154, 157, 160,
+ 163, 166, 169, 172, 175, 178, 181, 184, 187, 190,
+ 193, 195, 198, 199, 200, 201, 202, 203, 204, 205,
+ 206, 207, 208, 209, 210, 211, 212, 213, 214, 215,
+ 216, 218, 219, 220, 221, 222, 223, 224, 225, 226,
+
+ 227, 228, 229, 230, 231, 232, 233, 234, 234, 235,
+ 236, 237, 238, 239, 239, 239, 239, 240, 242, 243,
+ 244, 245, 246, 247, 248, 249, 250, 251, 252, 253,
+ 254, 255, 256, 257, 258, 259, 260, 261, 262, 263,
+ 264, 265, 266, 267, 268, 269, 270, 271, 272, 273,
+ 274, 275, 276, 277, 278, 279, 279, 280, 281, 282,
+ 283, 284, 286, 287, 288, 289, 290, 291, 292, 293,
+ 294, 295, 296, 297, 298, 299, 300, 301, 302, 303,
+ 304, 305, 306, 307, 308, 310, 311, 313, 314, 315,
+ 316, 317, 318, 319, 320, 321, 323, 324, 325, 325,
+
+ 325, 325, 325, 325, 326, 327, 328, 329, 330, 330,
+ 330, 330, 330, 330, 331, 332, 333, 335, 336, 337,
+ 338, 339, 340, 341, 342, 343, 344, 345, 346, 347,
+ 348, 349, 350, 351, 352, 353, 354, 355, 356, 357,
+ 358, 359, 360, 361, 362, 363, 364, 365, 366, 367,
+ 368, 369, 370, 371, 372, 373, 374, 374, 374, 374,
+ 374, 374, 375, 376, 377, 378, 379, 380, 382, 383,
+ 384, 385, 386, 387, 388, 389, 390, 392, 393, 394,
+ 396, 398, 400, 402, 403, 404, 405, 406, 407, 408,
+ 409, 410, 411, 413, 414, 416, 417, 418, 420, 421,
+
+ 421, 421, 421, 421, 421, 422, 423, 424, 425, 426,
+ 426, 426, 426, 426, 426, 427, 428, 429, 430, 431,
+ 433, 434, 435, 436, 437, 438, 439, 440, 441, 442,
+ 443, 444, 445, 446, 447, 448, 449, 450, 451, 452,
+ 453, 454, 455, 456, 457, 458, 459, 460, 461, 462,
+ 463, 464, 465, 466, 467, 468, 469, 470, 471, 472,
+ 473, 473, 474, 474, 474, 474, 474, 474, 475, 476,
+ 477, 479, 481, 483, 484, 486, 487, 488, 489, 490,
+ 491, 493, 495, 496, 498, 499, 500, 501, 502, 503,
+ 504, 505, 506, 508, 509, 510, 511, 512, 513, 513,
+
+ 513, 513, 513, 513, 514, 515, 516, 517, 518, 519,
+ 520, 521, 521, 521, 521, 521, 521, 522, 523, 524,
+ 525, 526, 527, 528, 529, 530, 531, 532, 533, 534,
+ 535, 536, 537, 538, 539, 540, 541, 542, 543, 544,
+ 545, 546, 547, 548, 549, 550, 551, 552, 553, 554,
+ 555, 556, 557, 558, 559, 560, 561, 562, 563, 564,
+ 565, 565, 566, 568, 569, 570, 571, 572, 573, 573,
+ 574, 575, 576, 576, 577, 577, 577, 577, 577, 577,
+ 578, 580, 581, 583, 585, 586, 587, 588, 589, 590,
+ 592, 593, 595, 597, 598, 599, 601, 602, 603, 604,
+
+ 605, 606, 608, 609, 610, 611, 612, 613, 614, 614,
+ 614, 614, 615, 616, 617, 618, 619, 620, 621, 622,
+ 623, 624, 625, 626, 627, 628, 629, 630, 631, 632,
+ 633, 634, 635, 636, 637, 637, 638, 640, 641, 642,
+ 643, 644, 645, 646, 647, 648, 649, 650, 651, 652,
+ 653, 654, 655, 656, 657, 659, 661, 663, 664, 665,
+ 666, 666, 667, 668, 669, 670, 671, 672, 672, 672,
+ 673, 673, 673, 675, 676, 677, 678, 679, 680, 681,
+ 682, 683, 684, 685, 686, 687, 689, 690, 692, 692,
+ 692, 693, 694, 695, 696, 697, 698, 699, 700, 701,
+
+ 702, 703, 704, 705, 706, 707, 708, 709, 710, 711,
+ 712, 713, 714, 715, 716, 717, 718, 719, 721, 723,
+ 725, 726, 727, 728, 729, 730, 731, 732, 733, 734,
+ 735, 736, 737, 738, 739, 740, 741, 742, 743, 744,
+ 745, 746, 747, 747, 748, 749, 750, 751, 752, 752,
+ 752, 752, 752, 754, 756, 758, 760, 761, 762, 764,
+ 765, 766, 768, 769, 770, 772, 772, 773, 774, 775,
+ 776, 777, 778, 779, 781, 782, 783, 784, 785, 786,
+ 787, 788, 789, 790, 791, 792, 793, 794, 795, 796,
+ 797, 798, 799, 800, 801, 802, 802, 803, 804, 805,
+
+ 805, 805, 805, 805, 806, 808, 810, 812, 814, 816,
+ 816, 817, 818, 819, 821, 823, 825, 827, 828, 829,
+ 830, 831, 832, 833, 834, 835, 836, 837, 838, 839,
+ 840, 840, 841, 842, 843, 844, 845, 846, 847, 848,
+ 848, 849, 850, 851, 853, 855, 856, 857, 858, 859,
+ 860, 861, 862, 863, 864, 865, 866, 867, 868, 868,
+ 869, 869, 870, 872, 874, 875, 876, 877, 878, 879,
+ 881, 881, 882, 883, 883, 884, 885, 887, 889, 890,
+ 890, 890, 893, 896, 897, 897, 897, 898, 899, 899,
+ 899, 899, 900, 900, 901, 902, 902, 902, 902, 903,
+
+ 903
+ } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 4, 5, 6, 7, 8, 9, 1, 10, 1,
+ 1, 11, 1, 1, 12, 13, 14, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 16, 1, 17,
+ 1, 1, 1, 1, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
+ 1, 1, 1, 1, 44, 1, 45, 46, 47, 48,
+
+ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
+ 59, 60, 61, 62, 63, 64, 65, 66, 67, 27,
+ 68, 69, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int32_t yy_meta[70] =
+ { 0,
+ 1, 1, 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 3, 4, 3, 1, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4
+ } ;
+
+static yyconst flex_int16_t yy_base[863] =
+ { 0,
+ 0, 63, 103, 65, 1222, 1223, 1223, 1223, 1218, 1223,
+ 1223, 1223, 0, 54, 47, 1181, 1201, 1200, 1181, 63,
+ 56, 1184, 1182, 1185, 1175, 1190, 151, 1193, 55, 1192,
+ 1183, 1186, 1158, 1157, 1201, 1185, 61, 156, 157, 62,
+ 1223, 1223, 158, 1200, 1223, 1190, 0, 1186, 0, 1181,
+ 1164, 1162, 1171, 1178, 131, 1146, 139, 48, 137, 18,
+ 1135, 135, 45, 1131, 1136, 1126, 137, 141, 139, 1132,
+ 1185, 1156, 1184, 1223, 0, 1154, 1148, 1154, 73, 1161,
+ 1152, 1159, 1150, 176, 1135, 1159, 1147, 1156, 177, 1151,
+ 178, 1152, 1135, 1150, 1138, 182, 1132, 1133, 194, 1132,
+
+ 1139, 1144, 1130, 1133, 1127, 1104, 1099, 202, 1136, 1124,
+ 198, 1134, 1122, 1144, 1087, 175, 0, 1139, 0, 1129,
+ 1117, 1127, 1129, 1114, 1089, 1083, 1082, 1081, 1093, 1085,
+ 1093, 1092, 1083, 178, 1077, 1085, 1088, 1080, 1073, 1088,
+ 164, 1082, 1074, 1083, 1082, 1084, 1079, 180, 1069, 181,
+ 183, 1064, 1068, 176, 1069, 226, 1099, 1087, 1095, 1094,
+ 1101, 0, 1100, 1084, 1085, 1089, 1077, 1069, 1069, 1089,
+ 1084, 1081, 1070, 1085, 1071, 1083, 1082, 1068, 1078, 1063,
+ 1078, 1077, 1080, 1058, 0, 1059, 0, 1065, 1057, 1060,
+ 1064, 1060, 1055, 1063, 1067, 0, 1022, 1023, 1066, 1049,
+
+ 1051, 1046, 1063, 1064, 1063, 1062, 1061, 1060, 1063, 1070,
+ 1014, 1023, 1018, 1054, 1053, 1052, 266, 1051, 1004, 1012,
+ 1015, 1004, 1009, 1014, 1013, 1014, 140, 1009, 1008, 1040,
+ 991, 996, 1004, 1005, 1007, 1001, 1000, 198, 983, 989,
+ 997, 977, 979, 984, 977, 976, 1024, 991, 200, 981,
+ 977, 1020, 986, 976, 1021, 974, 1012, 995, 997, 992,
+ 1009, 1010, 988, 985, 992, 986, 986, 991, 982, 989,
+ 995, 215, 984, 986, 977, 991, 0, 977, 993, 0,
+ 0, 0, 0, 988, 991, 988, 972, 984, 984, 978,
+ 981, 980, 0, 969, 0, 982, 967, 0, 945, 973,
+
+ 961, 971, 970, 958, 989, 988, 1223, 987, 986, 976,
+ 925, 924, 918, 926, 980, 979, 978, 977, 1223, 283,
+ 976, 914, 911, 914, 203, 917, 925, 918, 910, 926,
+ 914, 905, 910, 964, 210, 902, 949, 915, 900, 906,
+ 945, 902, 894, 913, 904, 894, 939, 905, 887, 903,
+ 207, 948, 300, 1223, 884, 896, 899, 944, 303, 883,
+ 887, 885, 919, 907, 917, 916, 904, 1223, 916, 915,
+ 0, 0, 0, 914, 0, 893, 913, 915, 296, 902,
+ 0, 0, 910, 0, 893, 908, 891, 890, 908, 890,
+ 892, 886, 0, 891, 881, 901, 879, 859, 901, 900,
+
+ 899, 898, 897, 909, 1223, 908, 1223, 907, 1223, 906,
+ 1223, 904, 842, 859, 842, 853, 900, 1223, 899, 1223,
+ 898, 1223, 897, 1223, 287, 850, 882, 852, 847, 879,
+ 838, 221, 877, 834, 842, 841, 841, 885, 1223, 884,
+ 833, 869, 881, 362, 830, 866, 878, 864, 815, 822,
+ 826, 860, 872, 826, 824, 807, 814, 821, 866, 1223,
+ 852, 379, 317, 851, 802, 807, 861, 1223, 798, 859,
+ 796, 804, 800, 791, 841, 840, 839, 838, 837, 831,
+ 0, 814, 0, 0, 813, 808, 818, 821, 827, 0,
+ 823, 0, 0, 818, 806, 0, 802, 804, 819, 808,
+
+ 809, 0, 779, 1223, 1223, 1223, 1223, 1223, 773, 779,
+ 785, 830, 829, 828, 782, 813, 825, 769, 766, 822,
+ 808, 820, 763, 1223, 773, 756, 803, 769, 814, 1223,
+ 760, 812, 811, 1223, 797, 396, 318, 743, 808, 807,
+ 1223, 806, 792, 791, 754, 802, 801, 1223, 787, 740,
+ 752, 747, 783, 321, 322, 1223, 323, 795, 733, 748,
+ 732, 791, 1223, 729, 747, 788, 732, 776, 775, 1223,
+ 774, 773, 0, 763, 762, 746, 760, 757, 754, 758,
+ 746, 745, 745, 753, 752, 0, 751, 0, 708, 722,
+ 767, 766, 1223, 765, 1223, 764, 1223, 750, 1223, 762,
+
+ 1223, 717, 714, 759, 1223, 1223, 758, 1223, 707, 629,
+ 556, 590, 519, 470, 515, 1223, 324, 325, 1223, 326,
+ 468, 513, 1223, 512, 1223, 511, 510, 448, 508, 1223,
+ 1223, 494, 493, 444, 504, 327, 1223, 329, 502, 1223,
+ 455, 487, 453, 485, 436, 494, 1223, 480, 484, 483,
+ 482, 481, 0, 0, 0, 0, 467, 468, 0, 458,
+ 453, 0, 466, 465, 0, 432, 1223, 84, 1223, 1223,
+ 191, 209, 200, 396, 243, 258, 1223, 215, 247, 332,
+ 1223, 341, 282, 320, 1223, 343, 1223, 331, 346, 347,
+ 335, 349, 1223, 305, 351, 307, 353, 309, 1223, 351,
+
+ 352, 353, 357, 355, 0, 0, 0, 0, 0, 326,
+ 338, 347, 350, 412, 1223, 413, 414, 1223, 366, 417,
+ 418, 419, 420, 1223, 421, 1223, 422, 411, 425, 1223,
+ 413, 427, 1223, 415, 1223, 1223, 1223, 1223, 397, 377,
+ 418, 431, 420, 434, 435, 390, 437, 1223, 438, 1223,
+ 439, 1223, 440, 1223, 1223, 441, 442, 410, 443, 445,
+ 401, 447, 448, 449, 390, 451, 1223, 452, 1223, 0,
+ 393, 454, 1223, 413, 456, 1223, 457, 458, 446, 399,
+ 401, 463, 464, 465, 406, 421, 468, 1223, 412, 457,
+ 425, 472, 418, 474, 1223, 430, 431, 433, 1223, 1223,
+
+ 521, 478, 523, 480, 527, 531, 535, 539, 543, 547,
+ 551, 555, 559, 563, 567, 571, 575, 579, 583, 587,
+ 591, 595, 599, 603, 607, 611, 615, 619, 623, 627,
+ 631, 635, 639, 643, 647, 651, 655, 659, 663, 667,
+ 671, 675, 679, 683, 687, 691, 695, 699, 703, 707,
+ 711, 715, 719, 723, 727, 731, 735, 739, 743, 747,
+ 751, 755
+ } ;
+
+static yyconst flex_int16_t yy_def[863] =
+ { 0,
+ 800, 1, 800, 3, 800, 800, 800, 800, 801, 800,
+ 800, 800, 802, 802, 802, 802, 802, 802, 802, 802,
+ 802, 802, 802, 802, 802, 802, 802, 802, 802, 802,
+ 802, 802, 802, 802, 800, 802, 802, 802, 802, 802,
+ 800, 800, 800, 801, 800, 800, 803, 804, 804, 804,
+ 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
+ 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
+ 800, 804, 801, 800, 802, 802, 802, 802, 802, 802,
+ 802, 802, 802, 802, 802, 802, 802, 802, 802, 802,
+ 802, 802, 802, 802, 802, 802, 802, 802, 802, 802,
+
+ 802, 802, 802, 802, 802, 802, 802, 800, 802, 802,
+ 802, 802, 802, 800, 800, 800, 803, 804, 804, 804,
+ 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
+ 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
+ 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
+ 804, 804, 804, 804, 804, 800, 804, 802, 802, 802,
+ 802, 802, 802, 802, 802, 802, 802, 802, 802, 802,
+ 802, 802, 802, 802, 802, 802, 802, 802, 802, 802,
+ 802, 802, 802, 802, 802, 802, 802, 802, 802, 802,
+ 802, 802, 802, 802, 802, 802, 802, 802, 800, 800,
+
+ 800, 800, 800, 802, 802, 802, 802, 802, 800, 800,
+ 800, 800, 800, 804, 804, 804, 805, 804, 804, 804,
+ 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
+ 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
+ 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
+ 804, 804, 804, 804, 804, 804, 800, 800, 800, 800,
+ 800, 804, 802, 802, 802, 802, 802, 802, 802, 802,
+ 802, 802, 802, 802, 802, 802, 802, 802, 802, 802,
+ 802, 802, 802, 802, 802, 802, 802, 802, 802, 802,
+ 802, 802, 802, 802, 802, 802, 802, 802, 802, 800,
+
+ 800, 800, 800, 800, 806, 807, 800, 808, 809, 800,
+ 800, 800, 800, 800, 810, 811, 812, 813, 800, 805,
+ 814, 804, 804, 804, 804, 804, 804, 804, 804, 804,
+ 804, 804, 804, 815, 804, 804, 804, 804, 804, 804,
+ 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
+ 804, 816, 817, 800, 804, 804, 804, 818, 804, 804,
+ 800, 804, 800, 800, 800, 800, 800, 800, 802, 802,
+ 802, 802, 802, 802, 802, 802, 802, 802, 802, 802,
+ 802, 802, 802, 802, 802, 802, 802, 802, 802, 802,
+ 802, 802, 802, 802, 802, 802, 802, 802, 800, 800,
+
+ 800, 800, 800, 806, 800, 807, 800, 808, 800, 809,
+ 800, 800, 800, 800, 800, 800, 810, 800, 811, 800,
+ 812, 800, 814, 800, 804, 804, 804, 804, 804, 804,
+ 804, 804, 804, 804, 804, 804, 804, 815, 800, 819,
+ 804, 804, 820, 821, 804, 804, 822, 804, 804, 804,
+ 804, 804, 823, 804, 804, 804, 804, 804, 816, 800,
+ 824, 817, 825, 804, 804, 804, 818, 800, 800, 826,
+ 804, 804, 800, 804, 800, 800, 800, 800, 800, 802,
+ 802, 802, 802, 802, 802, 802, 802, 802, 802, 802,
+ 802, 802, 802, 802, 802, 802, 802, 802, 802, 802,
+
+ 802, 802, 802, 800, 800, 800, 800, 800, 800, 800,
+ 800, 827, 828, 829, 804, 804, 830, 804, 804, 831,
+ 804, 832, 804, 800, 804, 804, 804, 804, 819, 800,
+ 804, 833, 820, 800, 834, 821, 835, 804, 836, 822,
+ 800, 837, 804, 804, 804, 838, 823, 800, 804, 804,
+ 804, 804, 804, 839, 825, 800, 825, 840, 804, 804,
+ 800, 826, 800, 804, 804, 841, 804, 800, 800, 800,
+ 800, 800, 802, 802, 802, 802, 802, 802, 802, 802,
+ 802, 802, 802, 802, 802, 802, 802, 802, 800, 800,
+ 842, 827, 800, 828, 800, 829, 800, 804, 800, 830,
+
+ 800, 804, 804, 831, 800, 800, 832, 800, 804, 804,
+ 804, 843, 804, 804, 833, 800, 844, 835, 800, 835,
+ 804, 836, 800, 837, 800, 845, 846, 804, 838, 800,
+ 800, 804, 804, 804, 847, 839, 800, 839, 840, 800,
+ 804, 804, 800, 804, 804, 841, 800, 804, 800, 800,
+ 800, 800, 802, 802, 802, 802, 802, 802, 802, 802,
+ 802, 802, 802, 802, 802, 800, 800, 842, 800, 800,
+ 804, 804, 804, 848, 804, 843, 800, 804, 804, 844,
+ 800, 844, 804, 845, 800, 846, 800, 804, 849, 850,
+ 804, 847, 800, 804, 851, 800, 852, 804, 800, 800,
+
+ 800, 800, 800, 802, 802, 802, 802, 802, 802, 800,
+ 804, 804, 804, 848, 800, 848, 848, 800, 804, 853,
+ 854, 855, 849, 800, 850, 800, 856, 804, 851, 800,
+ 800, 852, 800, 804, 800, 800, 800, 800, 802, 800,
+ 804, 804, 804, 848, 848, 804, 853, 800, 854, 800,
+ 855, 800, 856, 800, 800, 857, 858, 802, 800, 859,
+ 800, 860, 848, 848, 804, 857, 800, 858, 800, 802,
+ 800, 859, 800, 800, 860, 800, 848, 848, 804, 800,
+ 800, 848, 848, 861, 800, 800, 861, 800, 800, 800,
+ 800, 862, 800, 862, 800, 800, 800, 800, 800, 0,
+
+ 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
+ 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
+ 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
+ 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
+ 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
+ 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
+ 800, 800
+ } ;
+
+static yyconst flex_int16_t yy_nxt[1293] =
+ { 0,
+ 6, 7, 8, 7, 9, 10, 6, 6, 11, 12,
+ 6, 6, 6, 6, 13, 6, 6, 14, 13, 15,
+ 13, 16, 17, 13, 18, 19, 13, 13, 20, 21,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 13, 32, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 33, 13, 13, 13,
+ 13, 13, 13, 13, 13, 34, 13, 13, 13, 35,
+ 138, 71, 76, 77, 78, 80, 139, 89, 81, 113,
+ 86, 90, 79, 36, 37, 101, 669, 104, 87, 143,
+ 102, 38, 39, 72, 88, 110, 134, 144, 161, 82,
+
+ 135, 162, 40, 41, 42, 8, 43, 44, 41, 41,
+ 41, 45, 41, 41, 46, 41, 47, 48, 41, 41,
+ 49, 49, 49, 50, 51, 49, 49, 49, 49, 49,
+ 49, 49, 52, 49, 49, 53, 49, 49, 49, 49,
+ 49, 49, 54, 49, 49, 49, 49, 55, 56, 57,
+ 58, 59, 60, 49, 49, 49, 61, 49, 62, 63,
+ 49, 64, 65, 66, 67, 68, 69, 70, 49, 49,
+ 49, 49, 96, 86, 114, 97, 125, 126, 89, 141,
+ 98, 87, 90, 130, 136, 148, 127, 111, 99, 150,
+ 131, 153, 112, 142, 132, 128, 330, 133, 176, 331,
+
+ 154, 149, 137, 115, 167, 151, 152, 173, 177, 236,
+ 182, 168, 188, 174, 183, 354, 184, 172, 185, 189,
+ 254, 206, 199, 200, 211, 440, 244, 237, 250, 190,
+ 201, 202, 212, 228, 213, 378, 522, 229, 248, 711,
+ 245, 203, 246, 255, 249, 251, 257, 258, 355, 428,
+ 342, 379, 457, 712, 259, 260, 343, 713, 718, 441,
+ 677, 719, 720, 458, 429, 261, 318, 318, 319, 318,
+ 318, 318, 318, 318, 318, 318, 318, 318, 318, 318,
+ 523, 318, 318, 318, 318, 319, 318, 318, 318, 318,
+ 318, 318, 318, 318, 318, 318, 318, 721, 318, 318,
+
+ 461, 461, 514, 461, 461, 461, 461, 461, 461, 461,
+ 461, 461, 461, 461, 469, 463, 461, 486, 470, 556,
+ 619, 487, 685, 637, 556, 556, 681, 619, 619, 637,
+ 488, 637, 557, 620, 681, 515, 638, 557, 557, 682,
+ 620, 620, 638, 681, 638, 687, 722, 682, 724, 726,
+ 727, 693, 728, 730, 731, 733, 682, 734, 735, 736,
+ 737, 471, 535, 535, 738, 535, 535, 535, 535, 535,
+ 535, 535, 535, 535, 535, 535, 739, 537, 535, 461,
+ 461, 740, 461, 461, 461, 461, 461, 461, 461, 461,
+ 461, 461, 461, 741, 554, 461, 535, 535, 715, 535,
+
+ 535, 535, 535, 535, 535, 535, 535, 535, 535, 535,
+ 742, 617, 535, 743, 715, 715, 715, 716, 746, 748,
+ 750, 752, 724, 726, 754, 717, 755, 730, 756, 733,
+ 757, 758, 759, 760, 761, 762, 715, 715, 765, 748,
+ 750, 752, 754, 767, 769, 770, 771, 773, 774, 776,
+ 715, 715, 779, 767, 769, 780, 773, 781, 776, 715,
+ 715, 784, 745, 785, 786, 715, 715, 788, 789, 790,
+ 788, 791, 792, 793, 795, 796, 795, 797, 744, 798,
+ 799, 75, 763, 119, 710, 709, 708, 707, 706, 705,
+ 704, 703, 702, 701, 700, 699, 647, 778, 764, 698,
+
+ 697, 696, 695, 694, 640, 777, 693, 691, 690, 689,
+ 630, 688, 687, 685, 625, 623, 683, 616, 679, 783,
+ 782, 73, 73, 73, 73, 117, 117, 320, 320, 320,
+ 320, 404, 404, 404, 404, 406, 406, 406, 406, 408,
+ 408, 408, 408, 410, 410, 410, 410, 417, 417, 417,
+ 417, 419, 419, 419, 419, 421, 421, 421, 421, 318,
+ 318, 318, 318, 423, 423, 423, 423, 438, 438, 438,
+ 438, 459, 459, 459, 459, 462, 678, 462, 462, 467,
+ 467, 467, 467, 529, 529, 529, 529, 533, 533, 533,
+ 533, 536, 677, 536, 536, 540, 540, 540, 540, 547,
+
+ 547, 547, 547, 461, 675, 461, 461, 555, 555, 555,
+ 555, 562, 562, 562, 562, 592, 592, 592, 592, 594,
+ 594, 594, 594, 596, 596, 596, 596, 600, 600, 600,
+ 600, 604, 604, 604, 604, 607, 607, 607, 607, 615,
+ 615, 615, 615, 535, 674, 535, 535, 618, 618, 618,
+ 618, 622, 622, 622, 622, 624, 624, 624, 624, 629,
+ 629, 629, 629, 636, 636, 636, 636, 639, 639, 639,
+ 639, 646, 646, 646, 646, 668, 668, 668, 668, 676,
+ 676, 676, 676, 680, 680, 680, 680, 684, 684, 684,
+ 684, 686, 686, 686, 686, 692, 692, 692, 692, 714,
+
+ 714, 714, 714, 723, 723, 723, 723, 725, 725, 725,
+ 725, 729, 729, 729, 729, 732, 732, 732, 732, 747,
+ 747, 747, 747, 749, 749, 749, 749, 751, 751, 751,
+ 751, 753, 753, 753, 753, 766, 766, 766, 766, 768,
+ 768, 768, 768, 772, 772, 772, 772, 775, 775, 775,
+ 775, 787, 787, 787, 787, 794, 794, 794, 794, 673,
+ 608, 605, 672, 671, 601, 670, 597, 595, 593, 669,
+ 667, 666, 665, 664, 663, 662, 661, 660, 659, 658,
+ 657, 656, 655, 654, 653, 652, 651, 650, 649, 648,
+ 647, 645, 644, 563, 643, 642, 641, 640, 635, 634,
+
+ 633, 632, 631, 548, 630, 628, 627, 626, 625, 541,
+ 623, 621, 617, 534, 616, 614, 530, 613, 612, 611,
+ 610, 609, 608, 606, 605, 603, 602, 601, 599, 598,
+ 597, 595, 593, 591, 590, 589, 588, 587, 586, 585,
+ 584, 583, 582, 581, 580, 579, 578, 577, 576, 575,
+ 574, 573, 572, 571, 570, 569, 568, 567, 566, 565,
+ 564, 563, 561, 468, 560, 559, 558, 554, 460, 553,
+ 552, 551, 550, 549, 548, 546, 545, 544, 543, 542,
+ 541, 539, 538, 534, 532, 531, 530, 439, 528, 527,
+ 526, 525, 524, 521, 520, 519, 518, 517, 516, 424,
+
+ 422, 420, 418, 513, 512, 511, 510, 509, 411, 409,
+ 407, 405, 508, 507, 506, 505, 504, 503, 502, 501,
+ 500, 499, 498, 497, 496, 495, 494, 493, 492, 491,
+ 490, 489, 485, 484, 483, 482, 481, 480, 479, 478,
+ 477, 476, 475, 474, 473, 472, 468, 466, 465, 464,
+ 460, 456, 455, 454, 453, 452, 451, 450, 449, 448,
+ 447, 446, 445, 444, 443, 442, 439, 437, 436, 435,
+ 434, 433, 432, 431, 430, 427, 426, 425, 424, 319,
+ 422, 420, 418, 416, 415, 414, 413, 412, 411, 409,
+ 407, 405, 403, 402, 401, 400, 399, 398, 397, 396,
+
+ 395, 394, 393, 392, 391, 390, 389, 388, 387, 386,
+ 385, 384, 383, 382, 381, 380, 377, 376, 375, 374,
+ 373, 372, 371, 370, 369, 368, 367, 366, 365, 364,
+ 363, 362, 361, 360, 359, 358, 357, 356, 353, 352,
+ 351, 350, 349, 348, 347, 346, 345, 344, 341, 340,
+ 339, 338, 337, 336, 335, 334, 333, 332, 329, 328,
+ 327, 326, 325, 324, 323, 322, 321, 317, 316, 315,
+ 314, 313, 312, 311, 310, 309, 308, 307, 306, 305,
+ 304, 303, 302, 301, 300, 299, 298, 297, 296, 295,
+ 294, 293, 292, 291, 290, 289, 288, 287, 286, 285,
+
+ 284, 283, 282, 281, 280, 279, 278, 277, 276, 275,
+ 274, 273, 272, 271, 270, 269, 268, 267, 266, 265,
+ 264, 263, 262, 256, 253, 252, 247, 243, 242, 241,
+ 240, 239, 238, 235, 234, 233, 232, 231, 230, 227,
+ 226, 225, 224, 223, 222, 221, 220, 219, 218, 217,
+ 216, 215, 214, 118, 210, 209, 208, 207, 205, 204,
+ 198, 197, 196, 195, 194, 193, 192, 191, 187, 186,
+ 181, 180, 179, 178, 175, 172, 171, 170, 169, 166,
+ 165, 164, 163, 160, 159, 158, 74, 157, 156, 155,
+ 147, 146, 145, 140, 129, 124, 123, 122, 121, 120,
+
+ 118, 116, 74, 109, 108, 107, 106, 105, 104, 103,
+ 100, 95, 94, 93, 92, 91, 85, 84, 83, 82,
+ 74, 800, 5, 800, 800, 800, 800, 800, 800, 800,
+ 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
+ 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
+ 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
+ 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
+ 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
+ 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
+ 800, 800
+
+ } ;
+
+static yyconst flex_int16_t yy_chk[1293] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+ 60, 4, 14, 14, 14, 15, 60, 21, 15, 40,
+ 20, 21, 14, 2, 2, 29, 668, 40, 20, 63,
+ 29, 2, 2, 4, 20, 37, 58, 63, 79, 37,
+
+ 58, 79, 2, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 27, 38, 43, 27, 55, 55, 39, 62,
+ 27, 38, 39, 57, 59, 67, 55, 38, 27, 68,
+ 57, 69, 39, 62, 57, 55, 227, 57, 91, 227,
+
+ 69, 67, 59, 43, 84, 68, 68, 89, 91, 141,
+ 96, 84, 99, 89, 96, 249, 96, 111, 96, 99,
+ 154, 111, 108, 108, 116, 335, 148, 141, 151, 99,
+ 108, 108, 116, 134, 116, 272, 432, 134, 150, 671,
+ 148, 108, 148, 154, 150, 151, 156, 156, 249, 325,
+ 238, 272, 351, 672, 156, 156, 238, 673, 675, 335,
+ 676, 678, 679, 351, 325, 156, 217, 217, 217, 217,
+ 217, 217, 217, 217, 217, 217, 217, 217, 217, 217,
+ 432, 217, 217, 320, 320, 320, 320, 320, 320, 320,
+ 320, 320, 320, 320, 320, 320, 320, 683, 320, 320,
+
+ 353, 353, 425, 353, 353, 353, 353, 353, 353, 353,
+ 353, 353, 353, 353, 359, 353, 353, 379, 359, 463,
+ 537, 379, 684, 554, 555, 557, 617, 618, 620, 636,
+ 379, 638, 463, 537, 680, 425, 554, 555, 557, 617,
+ 618, 620, 636, 682, 638, 686, 688, 680, 689, 690,
+ 691, 692, 694, 695, 696, 697, 682, 698, 700, 701,
+ 702, 359, 444, 444, 703, 444, 444, 444, 444, 444,
+ 444, 444, 444, 444, 444, 444, 704, 444, 444, 462,
+ 462, 710, 462, 462, 462, 462, 462, 462, 462, 462,
+ 462, 462, 462, 711, 462, 462, 536, 536, 674, 536,
+
+ 536, 536, 536, 536, 536, 536, 536, 536, 536, 536,
+ 712, 536, 536, 713, 714, 716, 717, 674, 719, 720,
+ 721, 722, 723, 725, 727, 674, 728, 729, 731, 732,
+ 734, 739, 740, 741, 742, 743, 744, 745, 746, 747,
+ 749, 751, 753, 756, 757, 758, 759, 760, 761, 762,
+ 763, 764, 765, 766, 768, 771, 772, 774, 775, 777,
+ 778, 779, 717, 780, 781, 782, 783, 784, 785, 786,
+ 787, 789, 790, 791, 792, 793, 794, 796, 716, 797,
+ 798, 802, 744, 804, 666, 664, 663, 661, 660, 658,
+ 657, 652, 651, 650, 649, 648, 646, 764, 745, 645,
+
+ 644, 643, 642, 641, 639, 763, 635, 634, 633, 632,
+ 629, 628, 627, 626, 624, 622, 621, 615, 614, 778,
+ 777, 801, 801, 801, 801, 803, 803, 805, 805, 805,
+ 805, 806, 806, 806, 806, 807, 807, 807, 807, 808,
+ 808, 808, 808, 809, 809, 809, 809, 810, 810, 810,
+ 810, 811, 811, 811, 811, 812, 812, 812, 812, 813,
+ 813, 813, 813, 814, 814, 814, 814, 815, 815, 815,
+ 815, 816, 816, 816, 816, 817, 613, 817, 817, 818,
+ 818, 818, 818, 819, 819, 819, 819, 820, 820, 820,
+ 820, 821, 612, 821, 821, 822, 822, 822, 822, 823,
+
+ 823, 823, 823, 824, 611, 824, 824, 825, 825, 825,
+ 825, 826, 826, 826, 826, 827, 827, 827, 827, 828,
+ 828, 828, 828, 829, 829, 829, 829, 830, 830, 830,
+ 830, 831, 831, 831, 831, 832, 832, 832, 832, 833,
+ 833, 833, 833, 834, 610, 834, 834, 835, 835, 835,
+ 835, 836, 836, 836, 836, 837, 837, 837, 837, 838,
+ 838, 838, 838, 839, 839, 839, 839, 840, 840, 840,
+ 840, 841, 841, 841, 841, 842, 842, 842, 842, 843,
+ 843, 843, 843, 844, 844, 844, 844, 845, 845, 845,
+ 845, 846, 846, 846, 846, 847, 847, 847, 847, 848,
+
+ 848, 848, 848, 849, 849, 849, 849, 850, 850, 850,
+ 850, 851, 851, 851, 851, 852, 852, 852, 852, 853,
+ 853, 853, 853, 854, 854, 854, 854, 855, 855, 855,
+ 855, 856, 856, 856, 856, 857, 857, 857, 857, 858,
+ 858, 858, 858, 859, 859, 859, 859, 860, 860, 860,
+ 860, 861, 861, 861, 861, 862, 862, 862, 862, 609,
+ 607, 604, 603, 602, 600, 598, 596, 594, 592, 591,
+ 590, 589, 587, 585, 584, 583, 582, 581, 580, 579,
+ 578, 577, 576, 575, 574, 572, 571, 569, 568, 567,
+ 566, 565, 564, 562, 561, 560, 559, 558, 553, 552,
+
+ 551, 550, 549, 547, 546, 545, 544, 543, 542, 540,
+ 539, 538, 535, 533, 532, 531, 529, 528, 527, 526,
+ 525, 523, 522, 521, 520, 519, 518, 517, 516, 515,
+ 514, 513, 512, 511, 510, 509, 503, 501, 500, 499,
+ 498, 497, 495, 494, 491, 489, 488, 487, 486, 485,
+ 482, 480, 479, 478, 477, 476, 475, 474, 473, 472,
+ 471, 470, 469, 467, 466, 465, 464, 461, 459, 458,
+ 457, 456, 455, 454, 453, 452, 451, 450, 449, 448,
+ 447, 446, 445, 443, 442, 441, 440, 438, 437, 436,
+ 435, 434, 433, 431, 430, 429, 428, 427, 426, 423,
+
+ 421, 419, 417, 416, 415, 414, 413, 412, 410, 408,
+ 406, 404, 403, 402, 401, 400, 399, 398, 397, 396,
+ 395, 394, 392, 391, 390, 389, 388, 387, 386, 385,
+ 383, 380, 378, 377, 376, 374, 370, 369, 367, 366,
+ 365, 364, 363, 362, 361, 360, 358, 357, 356, 355,
+ 352, 350, 349, 348, 347, 346, 345, 344, 343, 342,
+ 341, 340, 339, 338, 337, 336, 334, 333, 332, 331,
+ 330, 329, 328, 327, 326, 324, 323, 322, 321, 318,
+ 317, 316, 315, 314, 313, 312, 311, 310, 309, 308,
+ 306, 305, 304, 303, 302, 301, 300, 299, 297, 296,
+
+ 294, 292, 291, 290, 289, 288, 287, 286, 285, 284,
+ 279, 278, 276, 275, 274, 273, 271, 270, 269, 268,
+ 267, 266, 265, 264, 263, 262, 261, 260, 259, 258,
+ 257, 256, 255, 254, 253, 252, 251, 250, 248, 247,
+ 246, 245, 244, 243, 242, 241, 240, 239, 237, 236,
+ 235, 234, 233, 232, 231, 230, 229, 228, 226, 225,
+ 224, 223, 222, 221, 220, 219, 218, 216, 215, 214,
+ 213, 212, 211, 210, 209, 208, 207, 206, 205, 204,
+ 203, 202, 201, 200, 199, 198, 197, 195, 194, 193,
+ 192, 191, 190, 189, 188, 186, 184, 183, 182, 181,
+
+ 180, 179, 178, 177, 176, 175, 174, 173, 172, 171,
+ 170, 169, 168, 167, 166, 165, 164, 163, 161, 160,
+ 159, 158, 157, 155, 153, 152, 149, 147, 146, 145,
+ 144, 143, 142, 140, 139, 138, 137, 136, 135, 133,
+ 132, 131, 130, 129, 128, 127, 126, 125, 124, 123,
+ 122, 121, 120, 118, 115, 114, 113, 112, 110, 109,
+ 107, 106, 105, 104, 103, 102, 101, 100, 98, 97,
+ 95, 94, 93, 92, 90, 88, 87, 86, 85, 83,
+ 82, 81, 80, 78, 77, 76, 73, 72, 71, 70,
+ 66, 65, 64, 61, 56, 54, 53, 52, 51, 50,
+
+ 48, 46, 44, 36, 35, 34, 33, 32, 31, 30,
+ 28, 26, 25, 24, 23, 22, 19, 18, 17, 16,
+ 9, 5, 800, 800, 800, 800, 800, 800, 800, 800,
+ 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
+ 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
+ 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
+ 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
+ 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
+ 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
+ 800, 800
+
+ } ;
+
+/* Table of booleans, true if rule could match eol. */
+static yyconst flex_int32_t yy_rule_can_match_eol[140] =
+ { 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+ };
+
+extern int yy_flex_debug;
+int yy_flex_debug = 0;
+
+static yy_state_type *yy_state_buf=0, *yy_state_ptr=0;
+static char *yy_full_match;
+static int yy_lp;
+static int yy_looking_for_trail_begin = 0;
+static int yy_full_lp;
+static int *yy_full_state;
+#define YY_TRAILING_MASK 0x2000
+#define YY_TRAILING_HEAD_MASK 0x4000
+#define REJECT \
+{ \
+*yy_cp = (yy_hold_char); /* undo effects of setting up yytext */ \
+yy_cp = (yy_full_match); /* restore poss. backed-over text */ \
+(yy_lp) = (yy_full_lp); /* restore orig. accepting pos. */ \
+(yy_state_ptr) = (yy_full_state); /* restore orig. state */ \
+yy_current_state = *(yy_state_ptr); /* restore curr. state */ \
+++(yy_lp); \
+goto find_rule; \
+}
+
+static int yy_more_offset = 0;
+static int yy_prev_more_offset = 0;
+#define yymore() ((yy_more_offset) = yy_flex_strlen( yytext ))
+#define YY_NEED_STRLEN
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET \
+ { \
+ (yy_more_offset) = (yy_prev_more_offset); \
+ yyleng -= (yy_more_offset); \
+ }
+#ifndef YYLMAX
+#define YYLMAX 8192
+#endif
+
+char yytext[YYLMAX];
+char *yytext_ptr;
+#line 1 "menul.l"
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #11 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+#line 17 "menul.l"
+#if defined(linux) || defined(mips) || defined(hpux) || defined(_AIX)
+int yylineno;
+#define NEWLINE yylineno++
+#else
+#define NEWLINE
+#endif
+
+#undef ECHO
+/* #define ECHO printf("<%s>",yytext) */
+#define ECHO /**/
+
+/*
+on HP lex -Xa10000
+p4 edit src/menul.c src/menuy.c && cd src && lex -t menul.l > menul.c && yacc menuy.y && mv -f y.tab.c menuy.c && cd ../ && make menu && make prof # ./env.sh cc
+
+ecflow_client | xargs addr2line -e ecflow_client -f
+*/
+
+#if defined (linux) || defined(alpha) || defined(SVR4) || defined(SGI) || defined(_AIX)
+#define yyinput input
+#endif
+
+
+
+#line 1212 "<stdout>"
+
+#define INITIAL 0
+#define LOGFILE 1
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy (void );
+
+int yyget_debug (void );
+
+void yyset_debug (int debug_flag );
+
+YY_EXTRA_TYPE yyget_extra (void );
+
+void yyset_extra (YY_EXTRA_TYPE user_defined );
+
+FILE *yyget_in (void );
+
+void yyset_in (FILE * in_str );
+
+FILE *yyget_out (void );
+
+void yyset_out (FILE * out_str );
+
+yy_size_t yyget_leng (void );
+
+char *yyget_text (void );
+
+int yyget_lineno (void );
+
+void yyset_lineno (int line_number );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap (void );
+#else
+extern int yywrap (void );
+#endif
+#endif
+
+ static void yyunput (int c,char *buf_ptr );
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ size_t n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (void);
+
+#define YY_DECL int yylex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ if ( yyleng > 0 ) \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \
+ (yytext[yyleng - 1] == '\n'); \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+#line 56 "menul.l"
+
+
+#line 1401 "<stdout>"
+
+ if ( !(yy_init) )
+ {
+ (yy_init) = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ /* Create the reject buffer large enough to save one state per allowed character. */
+ if ( ! (yy_state_buf) )
+ (yy_state_buf) = (yy_state_type *)yyalloc(YY_STATE_BUF_SIZE );
+ if ( ! (yy_state_buf) )
+ YY_FATAL_ERROR( "out of dynamic memory in yylex()" );
+
+ if ( ! (yy_start) )
+ (yy_start) = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ yyensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer(yyin,YY_BUF_SIZE );
+ }
+
+ yy_load_buffer_state( );
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = (yy_c_buf_p);
+
+ /* Support of yytext. */
+ *yy_cp = (yy_hold_char);
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = (yy_start);
+ yy_current_state += YY_AT_BOL();
+
+ (yy_state_ptr) = (yy_state_buf);
+ *(yy_state_ptr)++ = yy_current_state;
+
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 801 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ *(yy_state_ptr)++ = yy_current_state;
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 1223 );
+
+yy_find_action:
+ yy_current_state = *--(yy_state_ptr);
+ (yy_lp) = yy_accept[yy_current_state];
+find_rule: /* we branch to this label when backing up */
+ for ( ; ; ) /* until we find what rule we matched */
+ {
+ if ( (yy_lp) && (yy_lp) < yy_accept[yy_current_state + 1] )
+ {
+ yy_act = yy_acclist[(yy_lp)];
+ if ( yy_act & YY_TRAILING_HEAD_MASK ||
+ (yy_looking_for_trail_begin) )
+ {
+ if ( yy_act == (yy_looking_for_trail_begin) )
+ {
+ (yy_looking_for_trail_begin) = 0;
+ yy_act &= ~YY_TRAILING_HEAD_MASK;
+ break;
+ }
+ }
+ else if ( yy_act & YY_TRAILING_MASK )
+ {
+ (yy_looking_for_trail_begin) = yy_act & ~YY_TRAILING_MASK;
+ (yy_looking_for_trail_begin) |= YY_TRAILING_HEAD_MASK;
+ (yy_full_match) = yy_cp;
+ (yy_full_state) = (yy_state_ptr);
+ (yy_full_lp) = (yy_lp);
+ }
+ else
+ {
+ (yy_full_match) = yy_cp;
+ (yy_full_state) = (yy_state_ptr);
+ (yy_full_lp) = (yy_lp);
+ break;
+ }
+ ++(yy_lp);
+ goto find_rule;
+ }
+ --yy_cp;
+ yy_current_state = *--(yy_state_ptr);
+ (yy_lp) = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+ if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] )
+ {
+ int yyl;
+ for ( yyl = (yy_prev_more_offset); yyl < yyleng; ++yyl )
+ if ( yytext[yyl] == '\n' )
+
+ yylineno++;
+;
+ }
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+case 1:
+YY_RULE_SETUP
+#line 58 "menul.l"
+;
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 60 "menul.l"
+return VERSION;
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 61 "menul.l"
+return MENU;
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 62 "menul.l"
+return MENU;
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 63 "menul.l"
+return NONE;
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 64 "menul.l"
+return ALL;
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 65 "menul.l"
+return UNKNOWN;
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 66 "menul.l"
+return SUSPENDED;
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 67 "menul.l"
+return COMPLETE;
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 68 "menul.l"
+return QUEUED;
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 69 "menul.l"
+return SUBMITTED;
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 70 "menul.l"
+return ACTIVE;
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 71 "menul.l"
+return ABORTED;
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 72 "menul.l"
+return CLEAR;
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 73 "menul.l"
+return SET;
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 74 "menul.l"
+return SHUTDOWN;
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 75 "menul.l"
+return HALTED;
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 76 "menul.l"
+return LOCKED;
+ YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 77 "menul.l"
+return SERVER;
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 78 "menul.l"
+return SMS;
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 79 "menul.l"
+return NODE;
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 80 "menul.l"
+return SUITE;
+ YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 81 "menul.l"
+return FAMILY;
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 82 "menul.l"
+return TASK;
+ YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 83 "menul.l"
+return EVENT;
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 84 "menul.l"
+return LIMIT;
+ YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 85 "menul.l"
+return LABEL;
+ YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 86 "menul.l"
+return METER;
+ YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 87 "menul.l"
+return VARIABLE;
+ YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 88 "menul.l"
+return REPEAT;
+ YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 89 "menul.l"
+return ALIAS;
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 90 "menul.l"
+return MIGRATED;
+ YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 91 "menul.l"
+return HAS_TRIGGERS;
+ YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 92 "menul.l"
+return HAS_TIME;
+ YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 93 "menul.l"
+return HAS_DATE;
+ YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 94 "menul.l"
+return HAS_TEXT;
+ YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 95 "menul.l"
+return IS_ZOMBIE;
+ YY_BREAK
+case 38:
+YY_RULE_SETUP
+#line 96 "menul.l"
+return SEPARATOR;
+ YY_BREAK
+case 39:
+YY_RULE_SETUP
+#line 97 "menul.l"
+return DEFAULT_YES;
+ YY_BREAK
+case 40:
+YY_RULE_SETUP
+#line 98 "menul.l"
+return DEFAULT_NO;
+ YY_BREAK
+case 41:
+YY_RULE_SETUP
+#line 99 "menul.l"
+return WINDOW;
+ YY_BREAK
+case 42:
+YY_RULE_SETUP
+#line 100 "menul.l"
+return PLUG;
+ YY_BREAK
+case 43:
+YY_RULE_SETUP
+#line 101 "menul.l"
+return COMP;
+ YY_BREAK
+case 44:
+YY_RULE_SETUP
+#line 102 "menul.l"
+return SELECTION;
+ YY_BREAK
+case 45:
+YY_RULE_SETUP
+#line 104 "menul.l"
+return USER;
+ YY_BREAK
+case 46:
+YY_RULE_SETUP
+#line 105 "menul.l"
+return OPER;
+ YY_BREAK
+case 47:
+YY_RULE_SETUP
+#line 106 "menul.l"
+return ADMIN;
+ YY_BREAK
+case 48:
+YY_RULE_SETUP
+#line 108 "menul.l"
+{ BEGIN LOGFILE; }
+ YY_BREAK
+case 49:
+YY_RULE_SETUP
+#line 109 "menul.l"
+{ return JUNK; }
+ YY_BREAK
+case 50:
+YY_RULE_SETUP
+#line 110 "menul.l"
+{ return JUNK; }
+ YY_BREAK
+case 51:
+YY_RULE_SETUP
+#line 111 "menul.l"
+{ return JUNK; }
+ YY_BREAK
+case 52:
+YY_RULE_SETUP
+#line 112 "menul.l"
+{ return JUNK; }
+ YY_BREAK
+case 53:
+YY_RULE_SETUP
+#line 113 "menul.l"
+{ ECHO; BEGIN LOGFILE; }
+ YY_BREAK
+case 54:
+YY_RULE_SETUP
+#line 114 "menul.l"
+{ ECHO; BEGIN LOGFILE; }
+ YY_BREAK
+case 55:
+YY_RULE_SETUP
+#line 115 "menul.l"
+{ ECHO; BEGIN LOGFILE; }
+ YY_BREAK
+case 56:
+YY_RULE_SETUP
+#line 116 "menul.l"
+{ ECHO; BEGIN LOGFILE; }
+ YY_BREAK
+case 57:
+YY_RULE_SETUP
+#line 117 "menul.l"
+{ ECHO; BEGIN LOGFILE; }
+ YY_BREAK
+case 58:
+YY_RULE_SETUP
+#line 119 "menul.l"
+{ }
+ YY_BREAK
+case 59:
+YY_RULE_SETUP
+#line 120 "menul.l"
+{ return JUNK; }
+ YY_BREAK
+case 60:
+YY_RULE_SETUP
+#line 121 "menul.l"
+{ return JUNK; }
+ YY_BREAK
+case 61:
+YY_RULE_SETUP
+#line 122 "menul.l"
+{ return JUNK; }
+ YY_BREAK
+case 62:
+YY_RULE_SETUP
+#line 123 "menul.l"
+{ return JUNK; }
+ YY_BREAK
+case 63:
+YY_RULE_SETUP
+#line 125 "menul.l"
+ECHO;
+ YY_BREAK
+case 64:
+YY_RULE_SETUP
+#line 126 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 65:
+YY_RULE_SETUP
+#line 127 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 66:
+YY_RULE_SETUP
+#line 128 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 67:
+YY_RULE_SETUP
+#line 129 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 68:
+YY_RULE_SETUP
+#line 132 "menul.l"
+return IDENT;
+ YY_BREAK
+case 69:
+YY_RULE_SETUP
+#line 134 "menul.l"
+{
+ int c,q = yytext[0];
+ yyleng = 0;
+ while((c = yyinput()) && c != q && c != '\n')
+ if(c == '\\') {
+ yytext[yyleng++] = c;
+ yytext[yyleng++] = yyinput();
+ } else
+ yytext[yyleng++] = c;
+ yytext[yyleng++] = 0;
+ return STRING;
+ }
+ YY_BREAK
+case 70:
+YY_RULE_SETUP
+#line 147 "menul.l"
+{
+ int c,q = yytext[0];
+ yyleng = 0;
+ while((c = yyinput()) && c != q && c != '\n')
+ if(c == '\\') {
+ yytext[yyleng++] = c;
+ yytext[yyleng++] = yyinput();
+ } else
+ yytext[yyleng++] = c;
+ yytext[yyleng++] = 0;
+ return STRING;
+ }
+ YY_BREAK
+case 71:
+YY_RULE_SETUP
+#line 159 "menul.l"
+{ ECHO; return COMPLETE; }
+ YY_BREAK
+case 72:
+YY_RULE_SETUP
+#line 160 "menul.l"
+{ ECHO; return QUEUED; }
+ YY_BREAK
+case 73:
+YY_RULE_SETUP
+#line 161 "menul.l"
+{ ECHO; return ACTIVE; }
+ YY_BREAK
+case 74:
+YY_RULE_SETUP
+#line 162 "menul.l"
+{ ECHO; return METER; }
+ YY_BREAK
+case 75:
+YY_RULE_SETUP
+#line 163 "menul.l"
+{ ECHO; return EVENT; }
+ YY_BREAK
+case 76:
+YY_RULE_SETUP
+#line 164 "menul.l"
+{ return UNKNOWN; }
+ YY_BREAK
+case 77:
+YY_RULE_SETUP
+#line 165 "menul.l"
+{ ECHO; return SUBMITTED; }
+ YY_BREAK
+case 78:
+YY_RULE_SETUP
+#line 166 "menul.l"
+{ ECHO; return ABORTED; }
+ YY_BREAK
+case 79:
+YY_RULE_SETUP
+#line 167 "menul.l"
+{ ECHO; return SET; }
+ YY_BREAK
+case 80:
+YY_RULE_SETUP
+#line 168 "menul.l"
+{ ECHO; return CLEAR; }
+ YY_BREAK
+case 81:
+YY_RULE_SETUP
+#line 169 "menul.l"
+{ ECHO; return CANCEL; }
+ YY_BREAK
+case 82:
+YY_RULE_SETUP
+#line 171 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 83:
+YY_RULE_SETUP
+#line 172 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 84:
+YY_RULE_SETUP
+#line 173 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 85:
+YY_RULE_SETUP
+#line 174 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 86:
+YY_RULE_SETUP
+#line 175 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 87:
+YY_RULE_SETUP
+#line 176 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 88:
+YY_RULE_SETUP
+#line 177 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 89:
+YY_RULE_SETUP
+#line 178 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 90:
+YY_RULE_SETUP
+#line 179 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 91:
+YY_RULE_SETUP
+#line 180 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 92:
+YY_RULE_SETUP
+#line 181 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 93:
+YY_RULE_SETUP
+#line 182 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 94:
+YY_RULE_SETUP
+#line 183 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 95:
+YY_RULE_SETUP
+#line 184 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 96:
+YY_RULE_SETUP
+#line 185 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 97:
+YY_RULE_SETUP
+#line 186 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 98:
+YY_RULE_SETUP
+#line 187 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 99:
+YY_RULE_SETUP
+#line 188 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 100:
+YY_RULE_SETUP
+#line 189 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 101:
+YY_RULE_SETUP
+#line 190 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 102:
+YY_RULE_SETUP
+#line 191 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 103:
+YY_RULE_SETUP
+#line 192 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 104:
+YY_RULE_SETUP
+#line 193 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 105:
+YY_RULE_SETUP
+#line 194 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 106:
+YY_RULE_SETUP
+#line 195 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 107:
+YY_RULE_SETUP
+#line 196 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 108:
+YY_RULE_SETUP
+#line 197 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 109:
+YY_RULE_SETUP
+#line 198 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 110:
+YY_RULE_SETUP
+#line 199 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 111:
+YY_RULE_SETUP
+#line 200 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 112:
+YY_RULE_SETUP
+#line 201 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 113:
+YY_RULE_SETUP
+#line 202 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 114:
+YY_RULE_SETUP
+#line 203 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 115:
+YY_RULE_SETUP
+#line 204 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 116:
+YY_RULE_SETUP
+#line 205 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 117:
+YY_RULE_SETUP
+#line 206 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 118:
+YY_RULE_SETUP
+#line 207 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 119:
+YY_RULE_SETUP
+#line 208 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 120:
+YY_RULE_SETUP
+#line 209 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 121:
+YY_RULE_SETUP
+#line 210 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 122:
+YY_RULE_SETUP
+#line 211 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 123:
+YY_RULE_SETUP
+#line 212 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 124:
+YY_RULE_SETUP
+#line 213 "menul.l"
+{ ECHO; return JUNK; }
+ YY_BREAK
+case 125:
+YY_RULE_SETUP
+#line 215 "menul.l"
+;
+ YY_BREAK
+case 126:
+YY_RULE_SETUP
+#line 216 "menul.l"
+;
+ YY_BREAK
+case 127:
+YY_RULE_SETUP
+#line 217 "menul.l"
+{ return JUNK; }
+ YY_BREAK
+case 128:
+YY_RULE_SETUP
+#line 218 "menul.l"
+{ return JUNK; }
+ YY_BREAK
+case 129:
+YY_RULE_SETUP
+#line 220 "menul.l"
+{ ECHO; return NUMBER; }
+ YY_BREAK
+case 130:
+YY_RULE_SETUP
+#line 221 "menul.l"
+{ ECHO; return IDENT;}
+ YY_BREAK
+case 131:
+YY_RULE_SETUP
+#line 222 "menul.l"
+{ ECHO; return NODE_NAME;}
+ YY_BREAK
+case 132:
+YY_RULE_SETUP
+#line 223 "menul.l"
+ECHO;
+ YY_BREAK
+case 133:
+YY_RULE_SETUP
+#line 224 "menul.l"
+{ ECHO; return *yytext; }
+ YY_BREAK
+case 134:
+YY_RULE_SETUP
+#line 225 "menul.l"
+;
+ YY_BREAK
+case 135:
+YY_RULE_SETUP
+#line 226 "menul.l"
+return *yytext;
+ YY_BREAK
+case 136:
+/* rule 136 can match eol */
+YY_RULE_SETUP
+#line 227 "menul.l"
+{ BEGIN INITIAL; NEWLINE; }
+ YY_BREAK
+case 137:
+YY_RULE_SETUP
+#line 228 "menul.l"
+{ return ANY; }
+ YY_BREAK
+case 138:
+YY_RULE_SETUP
+#line 230 "menul.l"
+
+ YY_BREAK
+case 139:
+YY_RULE_SETUP
+#line 231 "menul.l"
+ECHO;
+ YY_BREAK
+#line 2245 "<stdout>"
+ case YY_STATE_EOF(INITIAL):
+ case YY_STATE_EOF(LOGFILE):
+ yyterminate();
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = (yy_hold_char);
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++(yy_c_buf_p);
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = (yy_c_buf_p);
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ (yy_did_buffer_switch_on_eof) = 0;
+
+ if ( yywrap( ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) =
+ (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ (yy_c_buf_p) =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+} /* end of yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+ register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ register char *source = (yytext_ptr);
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+ else
+ {
+ yy_size_t num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ (yy_n_chars), num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ if ( (yy_n_chars) == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart(yyin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ }
+
+ (yy_n_chars) += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+ (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (void)
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+
+ yy_current_state = (yy_start);
+ yy_current_state += YY_AT_BOL();
+
+ (yy_state_ptr) = (yy_state_buf);
+ *(yy_state_ptr)++ = yy_current_state;
+
+ for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 801 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ *(yy_state_ptr)++ = yy_current_state;
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
+{
+ register int yy_is_jam;
+
+ register YY_CHAR yy_c = 1;
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 801 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 800);
+ if ( ! yy_is_jam )
+ *(yy_state_ptr)++ = yy_current_state;
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+ static void yyunput (int c, register char * yy_bp )
+{
+ register char *yy_cp;
+
+ yy_cp = (yy_c_buf_p);
+
+ /* undo effects of setting up yytext */
+ *yy_cp = (yy_hold_char);
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ register yy_size_t number_to_move = (yy_n_chars) + 2;
+ register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+ register char *source =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+ while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--yy_cp = (char) c;
+
+ if ( c == '\n' ){
+ --yylineno;
+ }
+
+ (yytext_ptr) = yy_bp;
+ (yy_hold_char) = *yy_cp;
+ (yy_c_buf_p) = yy_cp;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (void)
+#else
+ static int input (void)
+#endif
+
+{
+ int c;
+
+ *(yy_c_buf_p) = (yy_hold_char);
+
+ if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ /* This was really a NUL. */
+ *(yy_c_buf_p) = '\0';
+
+ else
+ { /* need more input */
+ yy_size_t offset = (yy_c_buf_p) - (yytext_ptr);
+ ++(yy_c_buf_p);
+
+ switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart(yyin );
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap( ) )
+ return EOF;
+
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) = (yytext_ptr) + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */
+ *(yy_c_buf_p) = '\0'; /* preserve yytext */
+ (yy_hold_char) = *++(yy_c_buf_p);
+
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n');
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_at_bol )
+
+ yylineno++;
+;
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ *
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void yyrestart (FILE * input_file )
+{
+
+ if ( ! YY_CURRENT_BUFFER ){
+ yyensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer(yyin,YY_BUF_SIZE );
+ }
+
+ yy_init_buffer(YY_CURRENT_BUFFER,input_file );
+ yy_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ *
+ */
+ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer )
+{
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * yypop_buffer_state();
+ * yypush_buffer_state(new_buffer);
+ */
+ yyensure_buffer_stack ();
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ yy_load_buffer_state( );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void yy_load_buffer_state (void)
+{
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ (yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ *
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size )
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer(b,file );
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ *
+ */
+ void yy_delete_buffer (YY_BUFFER_STATE b )
+{
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yyfree((void *) b->yy_ch_buf );
+
+ yyfree((void *) b );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file )
+
+{
+ int oerrno = errno;
+
+ yy_flush_buffer(b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then yy_init_buffer was _probably_
+ * called from yyrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ *
+ */
+ void yy_flush_buffer (YY_BUFFER_STATE b )
+{
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ yy_load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ *
+ */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+ if (new_buffer == NULL)
+ return;
+
+ yyensure_buffer_stack();
+
+ /* This block is copied from yy_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ (yy_buffer_stack_top)++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from yy_switch_to_buffer. */
+ yy_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ *
+ */
+void yypop_buffer_state (void)
+{
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ yy_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if ((yy_buffer_stack_top) > 0)
+ --(yy_buffer_stack_top);
+
+ if (YY_CURRENT_BUFFER) {
+ yy_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void yyensure_buffer_stack (void)
+{
+ yy_size_t num_to_alloc;
+
+ if (!(yy_buffer_stack)) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1;
+ (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ (yy_buffer_stack_max) = num_to_alloc;
+ (yy_buffer_stack_top) = 0;
+ return;
+ }
+
+ if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ int grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = (yy_buffer_stack_max) + grow_size;
+ (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
+ ((yy_buffer_stack),
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+ (yy_buffer_stack_max) = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size )
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer(b );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ *
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (yyconst char * yystr )
+{
+
+ return yy_scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len )
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+ buf = (char *) yyalloc(n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer(buf,n );
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = (yy_hold_char); \
+ (yy_c_buf_p) = yytext + yyless_macro_arg; \
+ (yy_hold_char) = *(yy_c_buf_p); \
+ *(yy_c_buf_p) = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ *
+ */
+int yyget_lineno (void)
+{
+
+ return yylineno;
+}
+
+/** Get the input stream.
+ *
+ */
+FILE *yyget_in (void)
+{
+ return yyin;
+}
+
+/** Get the output stream.
+ *
+ */
+FILE *yyget_out (void)
+{
+ return yyout;
+}
+
+/** Get the length of the current token.
+ *
+ */
+yy_size_t yyget_leng (void)
+{
+ return yyleng;
+}
+
+/** Get the current token.
+ *
+ */
+
+char *yyget_text (void)
+{
+ return yytext;
+}
+
+/** Set the current line number.
+ * @param line_number
+ *
+ */
+void yyset_lineno (int line_number )
+{
+
+ yylineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ *
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE * in_str )
+{
+ yyin = in_str ;
+}
+
+void yyset_out (FILE * out_str )
+{
+ yyout = out_str ;
+}
+
+int yyget_debug (void)
+{
+ return yy_flex_debug;
+}
+
+void yyset_debug (int bdebug )
+{
+ yy_flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from yylex_destroy(), so don't allocate here.
+ */
+
+ /* We do not touch yylineno unless the option is enabled. */
+ yylineno = 1;
+
+ (yy_buffer_stack) = 0;
+ (yy_buffer_stack_top) = 0;
+ (yy_buffer_stack_max) = 0;
+ (yy_c_buf_p) = (char *) 0;
+ (yy_init) = 0;
+ (yy_start) = 0;
+
+ (yy_state_buf) = 0;
+ (yy_state_ptr) = 0;
+ (yy_full_match) = 0;
+ (yy_lp) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = (FILE *) 0;
+ yyout = (FILE *) 0;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * yylex_init()
+ */
+ return 0;
+}
+
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy (void)
+{
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ yy_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ yypop_buffer_state();
+ }
+
+ /* Destroy the stack itself. */
+ yyfree((yy_buffer_stack) );
+ (yy_buffer_stack) = NULL;
+
+ yyfree ( (yy_state_buf) );
+ (yy_state_buf) = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * yylex() is called, initialization will occur. */
+ yy_init_globals( );
+
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *yyalloc (yy_size_t size )
+{
+ return (void *) malloc( size );
+}
+
+void *yyrealloc (void * ptr, yy_size_t size )
+{
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+}
+
+void yyfree (void * ptr )
+{
+ free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 231 "menul.l"
diff --git a/view/src/menul.l b/view/src/menul.l
new file mode 100644
index 0000000..8496450
--- /dev/null
+++ b/view/src/menul.l
@@ -0,0 +1,230 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #11 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+%{
+#if defined(linux) || defined(mips) || defined(hpux) || defined(_AIX)
+int yylineno;
+#define NEWLINE yylineno++
+#else
+#define NEWLINE
+#endif
+
+#undef ECHO
+/* #define ECHO printf("<%s>",yytext) */
+#define ECHO /**/
+
+/*
+on HP lex -Xa10000
+p4 edit src/menul.c src/menuy.c && cd src && lex -t menul.l > menul.c && yacc menuy.y && mv -f y.tab.c menuy.c && cd ../ && make menu && make prof # ./env.sh cc
+
+ecflow_client | xargs addr2line -e ecflow_client -f
+*/
+
+#if defined (linux) || defined(alpha) || defined(SVR4) || defined(SGI) || defined(_AIX)
+#define yyinput input
+#endif
+
+
+%}
+
+IDENT [_0-9A-Za-z]+
+NUMBER [0-9]+
+NODE \/[_0-9A-Za-z:\/]*
+
+%option yylineno
+%array
+
+%s LOGFILE
+%e 1600
+%p 8000
+%a 15000
+%n 5000
+%o 10000
+
+%%
+
+!.*$ ;
+
+<INITIAL>version return VERSION;
+<INITIAL>menu return MENU;
+<INITIAL>MENU return MENU;
+<INITIAL>NONE return NONE;
+<INITIAL>ALL return ALL;
+<INITIAL>UNKNOWN return UNKNOWN;
+<INITIAL>SUSPENDED return SUSPENDED;
+<INITIAL>COMPLETE return COMPLETE;
+<INITIAL>QUEUED return QUEUED;
+<INITIAL>SUBMITTED return SUBMITTED;
+<INITIAL>ACTIVE return ACTIVE;
+<INITIAL>ABORTED return ABORTED;
+<INITIAL>CLEAR return CLEAR;
+<INITIAL>SET return SET;
+<INITIAL>SHUTDOWN return SHUTDOWN;
+<INITIAL>HALTED return HALTED;
+<INITIAL>LOCKED return LOCKED;
+<INITIAL>SERVER return SERVER;
+<INITIAL>SMS return SMS;
+<INITIAL>NODE return NODE;
+<INITIAL>SUITE return SUITE;
+<INITIAL>FAMILY return FAMILY;
+<INITIAL>TASK return TASK;
+<INITIAL>EVENT return EVENT;
+<INITIAL>LIMIT return LIMIT;
+<INITIAL>LABEL return LABEL;
+<INITIAL>METER return METER;
+<INITIAL>VARIABLE return VARIABLE;
+<INITIAL>REPEAT return REPEAT;
+<INITIAL>ALIAS return ALIAS;
+<INITIAL>MIGRATED return MIGRATED;
+<INITIAL>HAS_TRIGGERS return HAS_TRIGGERS;
+<INITIAL>HAS_TIME return HAS_TIME;
+<INITIAL>HAS_DATE return HAS_DATE;
+<INITIAL>HAS_TEXT return HAS_TEXT;
+<INITIAL>IS_ZOMBIE return IS_ZOMBIE;
+<INITIAL>SEPARATOR return SEPARATOR;
+<INITIAL>YES return DEFAULT_YES;
+<INITIAL>NO return DEFAULT_NO;
+<INITIAL>WINDOW return WINDOW;
+<INITIAL>PLUG return PLUG;
+<INITIAL>COMP return COMP;
+<INITIAL>SELECTION return SELECTION;
+
+<INITIAL>USER return USER;
+<INITIAL>OPER return OPER;
+<INITIAL>ADMIN return ADMIN;
+
+<INITIAL>^LOG: { BEGIN LOGFILE; }
+<INITIAL>^MSG:.*$ { return JUNK; }
+<INITIAL>^DBG:.*$ { return JUNK; }
+<INITIAL>^ERR:.*$ { return JUNK; }
+<INITIAL>^WAR:.*$ { return JUNK; }
+<INITIAL>^"# LOG:" { ECHO; BEGIN LOGFILE; }
+<INITIAL>^"# MSG:" { ECHO; BEGIN LOGFILE; }
+<INITIAL>^"# DBG:" { ECHO; BEGIN LOGFILE; }
+<INITIAL>^"# ERR:" { ECHO; BEGIN LOGFILE; }
+<INITIAL>^"# WAR:" { ECHO; BEGIN LOGFILE; }
+
+<LOGFILE>^LOG: { }
+<LOGFILE>MSG:.*$ { return JUNK; }
+<LOGFILE>DBG:.*$ { return JUNK; }
+<LOGFILE>ERR:.*$ { return JUNK; }
+<LOGFILE>WAR:.*$ { return JUNK; }
+
+<LOGFILE>^"# LOG:" ECHO;
+<LOGFILE>^"# MSG:.*$" { ECHO; return JUNK; }
+<LOGFILE>^"# DBG:.*$" { ECHO; return JUNK; }
+<LOGFILE>^"# ERR:.*$" { ECHO; return JUNK; }
+<LOGFILE>^"# WAR:.*$" { ECHO; return JUNK; }
+
+
+<INITIAL>{IDENT} return IDENT;
+
+<INITIAL>\" {
+ int c,q = yytext[0];
+ yyleng = 0;
+ while((c = yyinput()) && c != q && c != '\n')
+ if(c == '\\') {
+ yytext[yyleng++] = c;
+ yytext[yyleng++] = yyinput();
+ } else
+ yytext[yyleng++] = c;
+ yytext[yyleng++] = 0;
+ return STRING;
+ }
+
+<INITIAL>\' {
+ int c,q = yytext[0];
+ yyleng = 0;
+ while((c = yyinput()) && c != q && c != '\n')
+ if(c == '\\') {
+ yytext[yyleng++] = c;
+ yytext[yyleng++] = yyinput();
+ } else
+ yytext[yyleng++] = c;
+ yytext[yyleng++] = 0;
+ return STRING;
+ }
+<LOGFILE>complete: { ECHO; return COMPLETE; }
+<LOGFILE>queued: { ECHO; return QUEUED; }
+<LOGFILE>active: { ECHO; return ACTIVE; }
+<LOGFILE>command:Meter { ECHO; return METER; }
+<LOGFILE>command:Event { ECHO; return EVENT; }
+<LOGFILE>unknown: { return UNKNOWN; }
+<LOGFILE>submitted: { ECHO; return SUBMITTED; }
+<LOGFILE>aborted: { ECHO; return ABORTED; }
+<LOGFILE>set: { ECHO; return SET; }
+<LOGFILE>clear: { ECHO; return CLEAR; }
+<LOGFILE>cancel: { ECHO; return CANCEL; }
+
+<LOGFILE>command:.*$ { ECHO; return JUNK; }
+<LOGFILE>check:.*$ { ECHO; return JUNK; }
+<LOGFILE>checkpoint:.*$ { ECHO; return JUNK; }
+<LOGFILE>label:.*$ { ECHO; return JUNK; }
+<LOGFILE>abort:.*$ { ECHO; return JUNK; }
+<LOGFILE>midnight:.*$ { ECHO; return JUNK; }
+<LOGFILE>"autorepeat date":.*$ { ECHO; return JUNK; }
+<LOGFILE>autocancel:.*$ { ECHO; return JUNK; }
+<LOGFILE>run:.*$ { ECHO; return JUNK; }
+<LOGFILE>order:.*$ { ECHO; return JUNK; }
+<LOGFILE>login:.*$ { ECHO; return JUNK; }
+<LOGFILE>logout:.*$ { ECHO; return JUNK; }
+<LOGFILE>recover:.*$ { ECHO; return JUNK; }
+<LOGFILE>resubmit:.*$ { ECHO; return JUNK; }
+<LOGFILE>requeue:.*$ { ECHO; return JUNK; }
+<LOGFILE>suspend:.*$ { ECHO; return JUNK; }
+<LOGFILE>resume:.*$ { ECHO; return JUNK; }
+<LOGFILE>timeout:.*$ { ECHO; return JUNK; }
+<LOGFILE>dir:.*$ { ECHO; return JUNK; }
+<LOGFILE>send:.*$ { ECHO; return JUNK; }
+<LOGFILE>send(.*):.*$ { ECHO; return JUNK; }
+<LOGFILE>time:.*$ { ECHO; return JUNK; }
+<LOGFILE>manual:.*$ { ECHO; return JUNK; }
+<LOGFILE>file:.*$ { ECHO; return JUNK; }
+<LOGFILE>editfile:.*$ { ECHO; return JUNK; }
+<LOGFILE>edit:.*$ { ECHO; return JUNK; }
+<LOGFILE>translate:.*$ { ECHO; return JUNK; }
+<LOGFILE>force:.*$ { ECHO; return JUNK; }
+<LOGFILE>force(.*):.*$ { ECHO; return JUNK; }
+<LOGFILE>play:.*$ { ECHO; return JUNK; }
+<LOGFILE>begin:.*$ { ECHO; return JUNK; }
+<LOGFILE>late:.*$ { ECHO; return JUNK; }
+<LOGFILE>delete:.*$ { ECHO; return JUNK; }
+<LOGFILE>alter:.*$ { ECHO; return JUNK; }
+<LOGFILE>event:.*$ { ECHO; return JUNK; }
+<LOGFILE>setev:.*$ { ECHO; return JUNK; }
+<LOGFILE>dependencies:.*$ { ECHO; return JUNK; }
+<LOGFILE>time-used:.*$ { ECHO; return JUNK; }
+<LOGFILE>PID.*$ { ECHO; return JUNK; }
+<LOGFILE>--force.*$ { ECHO; return JUNK; }
+<LOGFILE>--ping.*$ { ECHO; return JUNK; }
+<LOGFILE>--news.*$ { ECHO; return JUNK; }
+<LOGFILE>svr:.*$ { ECHO; return JUNK; }
+
+<LOGFILE>" <--- still suspended" ;
+<LOGFILE>" by rule" ;
+<LOGFILE>command:.*$ { return JUNK; }
+<LOGFILE>try-no.*$ { return JUNK; }
+
+<LOGFILE>{NUMBER} { ECHO; return NUMBER; }
+<LOGFILE>{IDENT} { ECHO; return IDENT;}
+<LOGFILE>{NODE} { ECHO; return NODE_NAME;}
+<LOGFILE>[ \t] ECHO;
+<LOGFILE>. { ECHO; return *yytext; }
+<INITIAL>[ \t] ;
+<INITIAL>. return *yytext;
+\n { BEGIN INITIAL; NEWLINE; }
+<LOGFILE>job_size:.*$ { return ANY; }
+
+%
diff --git a/view/src/menus.cc b/view/src/menus.cc
new file mode 100644
index 0000000..f073f27
--- /dev/null
+++ b/view/src/menus.cc
@@ -0,0 +1,796 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #17 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#ifndef menus_H
+#include "menus.h"
+#endif
+
+#ifndef selection_H
+#include "selection.h"
+#endif
+
+#ifndef flags_H
+#include "flags.h"
+#endif
+
+#ifndef tip_H
+#include "tip.h"
+#endif
+
+#ifndef xec_H
+#include "xec.h"
+#endif
+
+#ifndef collector_H
+#include "collector.h"
+#endif
+
+#ifndef confirm_H
+#include "confirm.h"
+#endif
+
+#ifndef panel_window_H
+#include "panel_window.h"
+#endif
+
+#ifndef parser_H
+#include "parser.h"
+#endif
+
+#ifndef directory_H
+#include "directory.h"
+#endif
+
+#include "log_event.h"
+
+#include <unistd.h>
+#include <fstream>
+#include <iostream>
+
+#include <Xm/Label.h>
+#include <Xm/PushB.h>
+#include <Xm/RowColumn.h>
+#include <Xm/Separator.h>
+#include <Xm/CascadeBG.h>
+#include <Xm/PushBG.h>
+#include <Xm/SeparatoG.h>
+#include <Xm/ToggleBG.h>
+#include <Xm/RowColumnP.h>
+
+extern "C"
+{
+#include "xec.h"
+}
+
+#ifndef node_H
+#include "node.h"
+#endif
+
+#ifndef host_H
+#include "host.h"
+#endif
+
+#include "ecflowview.h"
+#undef XECFDEBUG
+#define XECFDEBUG if(0)
+#define MENU_REL 1
+#define MENU_MAJ 0
+#define MENU_MIN 0
+
+#define NUM_MENUS 2
+static Widget cmd_menu_popup[NUM_MENUS] = { 0, 0, };
+static Widget cmd_menu_name[NUM_MENUS] = { 0, 0, };
+
+static char* defaultMenu[] = {
+#include "ecflowview.menu.h"
+};
+
+static char* xcdpMenu[] = {
+#include "xcdp.menu.h"
+};
+
+/* #define YYDEBUG 1 */
+
+class node;
+class item;
+#include <string>
+class menu {
+ friend int script_menus(node*, const char *cmd);
+ static menu *root_[NUM_MENUS];
+ std::string name_;
+ item *item_;
+ menu *next_;
+ Widget widget_;
+ int page_;
+ static int init(int page, bool def);
+public:
+ static int num_;
+
+ menu(std::string name, item * i)
+ : name_(name), item_(i), next_(0), widget_(0), page_(num_)
+ { XECFDEBUG printf("# menu creation: %s\n", name.c_str());
+ if (root_[page_] == NULL) root_[page_] = this; }
+
+ menu *chain(menu * n);
+ void create(Widget);
+ void update(node *);
+ void merge(item *);
+ void fill(Widget list,int depth);
+
+ static menu *find(const char *, int page=-1, bool verb=true);
+ static void root(menu *m);
+};
+
+menu *menu::chain(menu * n)
+{
+ if (n) {
+ menu *m = menu::find(n->name_.c_str(), n->page_, false);
+ if (m) {
+ m->merge(n->item_); delete n;
+ XECFDEBUG printf("# menu already there (chain) %s\n", n->name_.c_str());
+ } else if (n->page_ == page_)
+ next_ = n;
+ }
+ return this;
+}
+
+void menu::root(menu *m) {
+ if (root_[num_] == NULL) root_[num_] = m;
+ else if (m) {
+ menu *men = menu::find(m->name_.c_str(), m->page_);
+ XECFDEBUG {
+ if (!men) printf("# menu chained %s\n", m->name_.c_str());
+ else printf("# menu already there %s\n", m->name_.c_str()); }
+ }
+}
+
+class action {
+protected:
+ Widget widget_;
+ item* item_;
+
+ action() : widget_(0),item_(0) {}
+public:
+ virtual ~action() {}
+ void owner(item* i) { item_ = i; }
+
+ virtual void create(Widget, item *) = 0;
+ virtual void fill(Widget, int) {}
+
+ Widget widget() { return widget_; }
+ virtual void run(node *) { }
+};
+
+class command : public action {
+ char *name_;
+ virtual void create(Widget, item *);
+public:
+ command(char *name): name_(name) { }
+ virtual void run(node *);
+};
+
+class window_cmd : public action {
+ char *name_;
+ virtual void create(Widget, item *);
+public:
+ window_cmd(char *name): name_(name) { }
+ virtual void run(node *);
+};
+
+typedef void (*nodeproc)(node*);
+typedef void (*nodeproc_a_b)(node*, const char* a, const char* b);
+
+class internal: public action {
+ nodeproc proc_;
+ virtual void create(Widget, item *);
+public:
+ internal(nodeproc p): proc_(p) { }
+ virtual void run(node *);
+};
+
+class internal_a_b: public action {
+ nodeproc_a_b proc_;
+ const std::string a_, b_;
+ virtual void create(Widget, item *);
+public:
+ internal_a_b(nodeproc_a_b p, const char* a, const char*b)
+ : proc_(p)
+ , a_(a)
+ , b_(b)
+ { }
+ virtual void run(node *);
+};
+
+
+class sub_menu : public action {
+ virtual void create(Widget, item *);
+ virtual void fill(Widget, int);
+public:
+ sub_menu() { }
+};
+
+class separator : public action {
+ virtual void create(Widget, item *);
+};
+
+menu *menu::root_[NUM_MENUS] = { 0, 0, };
+
+class item {
+public:
+ item *next_;
+private:
+ friend int script_menus(node*, const char *cmd);
+ flags *visible_;
+ flags *enabled_;
+ char *title_;
+ action *action_;
+ char *question_;
+ Boolean answer_;
+ int page_;
+
+public:
+
+ int page() const { return page_; }
+
+ item(flags * visible,flags * enabled,
+ char *title, action * action, char *question, Boolean answer)
+ : next_(0), visible_(visible), enabled_(enabled)
+ , title_(title), action_(action), question_(question)
+ , answer_(answer), page_(menu::num_)
+ { if(action_) action_->owner(this); }
+
+ void update(node *);
+
+ void create(Widget parent)
+ {
+ action_->create(parent, this);
+ if(next_)
+ next_->create(parent);
+ }
+
+ item *chain(item * n)
+ {
+ if (n->page_ == page_)
+ next_ = n;
+ return this;
+ }
+
+ char *title() { return title_; }
+
+ item *find(const char* name);
+
+ void run(node * n)
+ {
+ str question = n->substitute(question_);
+ if(question_[0] == 0 || confirm::ask(answer_,question))
+ action_->run(n);
+ }
+
+ void fill(Widget list,int depth)
+ {
+ XECFDEBUG printf("# item::fill %p %d\n",list,depth);
+ char buf[1024];
+ memset(buf,' ',depth);
+ sprintf(buf+depth,"%s",title_);
+ xec_AddListItem(list,buf);
+ action_->fill(list,depth);
+ if(next_)
+ next_->fill(list,depth);
+ }
+};
+
+item* item::find(const char* title)
+{
+ for (item* run=this; run; run=run->next_)
+ if (!strcmp(run->title(),title)) return run;
+ return 0;
+}
+
+menus::menus()
+{
+}
+
+menus::~menus()
+{
+}
+
+void menus::write()
+{
+ int lineno = 0;
+ char *line;
+ std::ofstream outfile;
+ std::string fname = directory::user() + std::string("/ecflowview.menu");
+ outfile.open(fname.c_str());
+ std::cerr << "# creating menu file " << fname << "\n";
+ while ((line = defaultMenu[lineno])) {
+ outfile << line << "\n";
+ lineno++;
+ }
+}
+
+void menus::fillList(Widget list)
+{
+ XECFDEBUG printf("# menus::fill %p\n",list);
+ menu *m = menu::find("MAIN"); if(m) m->fill(list,0);
+}
+
+void menu::fill(Widget list,int depth)
+{
+ item_->fill(list,depth);
+}
+
+void menus::show(Widget parent, XEvent * event_node, node * n)
+{
+
+ if (parent==NULL) fprintf(stderr, "menus::show null widget\n");
+ if(n == 0 || !n->menus())
+ {
+ selection::menu_node(0);
+ return;
+ }
+
+ selection::menu_node(n);
+ int page = n->__node__() ? 0 : 1;
+
+ if(cmd_menu_popup[page] == 0)
+ {
+ cmd_menu_popup[page] = XmCreatePopupMenu(parent, "cmd_menu_popup", 0, 0);
+ cmd_menu_name[page] = XmCreateLabel(cmd_menu_popup[page], "name", 0, 0);
+ Widget w = XmCreateSeparator(cmd_menu_popup[page], "-", 0, 0);
+
+ XtManageChild(cmd_menu_name[page]);
+ XtManageChild(w);
+
+ XtAddCallback(cmd_menu_popup[page], XmNentryCallback, menus::entryCB, 0);
+ tip::makeTips(cmd_menu_popup[page]);
+ }
+
+ menu *m = menu::find("MAIN", page);
+ if(m)
+ {
+ m->create(cmd_menu_popup[page]);
+ m->update(n);
+ }
+
+ xec_VaSetLabel(cmd_menu_name[page], "%s %s",n->type_name(),n->node_name().c_str());
+ xec_SetColor(cmd_menu_name[page], n->color(), XmNbackground);
+
+ XmMenuPosition(cmd_menu_popup[page],(XButtonPressedEvent *) event_node);
+ XtManageChild(cmd_menu_popup[page]);
+
+}
+
+int menu::num_ = 0;
+
+int menus::version(int rel, int maj, int min) {
+ if (rel > MENU_REL || (rel == MENU_REL && maj > MENU_MAJ)) {
+ std::cerr << "# menus definition file(s) shall be upgraded\n";
+ std::cerr << "# app is "
+ << MENU_REL << " "
+ << MENU_MAJ << " "
+ << MENU_MIN;
+ std::cerr << "\n# file is " << rel << " " << maj << " " << min;
+ std::cerr << "\n";
+
+ return 1;
+ } // else { std::cout << "# menus version compatible " << rel << " " << maj << " " << min << "\n"; }
+ return 0;
+}
+
+int menu::init(int page, bool def) {
+#ifndef BRIDGE
+ page = 0;
+#endif
+ const char* name = page ? "xcdp.menu" : "ecflowview.menu";
+ bool read = false;
+ num_ = page;
+ /* 0: ecflowview menu
+ 1: xcdp menu
+
+ system\user 0 1
+ 0 tmp user
+ 1 sys both, user overwrites
+ */
+ std::string path = directory::user();
+ path += "/";
+ path += name;
+ const char* fname = path.c_str();
+ if(!def && !access(fname,F_OK)) {
+ std::cout << "# reading menu file: " << fname << "\n";
+ parser::parse(fname);
+ read = true;
+ } else std::cerr << "# menu file not found: " << fname << "\n";
+
+ path = directory::system();
+ path += "/";
+ path += name;
+ fname = path.c_str();
+
+ if (!def && !access(fname,F_OK)) {
+ std::cout << "# reading menu file: " << fname << "\n";
+ parser::parse(fname);
+ read = true;
+ } else std::cerr << "# menu file not found: " << fname << "\n";
+
+ if(!read) {
+ char* tmp = getenv("TMPDIR");
+ path = tmp ? tmp : "/tmp";
+ path += "/";
+ path += name;
+ fname = path.c_str();
+
+ // if(access(fname,F_OK)) /* create if not already there */
+ { /* create always */
+ std::cerr << "# creating menu file " << fname << "\n";
+ std::ofstream outfile;
+ outfile.open(fname);
+ int lineno = 0;
+ char *line;
+ while ((line = (page ? xcdpMenu[lineno] : defaultMenu[lineno]))) {
+ outfile << line << "\n";
+ lineno++;
+ }
+ outfile.close();
+ }
+ std::cout << "# menu file read: " << fname << "\n";
+ parser::parse(fname);
+ }
+ return TRUE;
+}
+
+menu *menu::find(const char *name, int page, bool verb)
+{
+#ifndef BRIDGE
+ page = 0;
+#endif
+ if (page >= NUM_MENUS || page < 0) page = 0;
+
+ if(root_[page] == NULL) init(page, false);
+ if(root_[page] == NULL) init(page, true);
+ menu *m = root_[page];
+ while(m) {
+ if(m->name_ == name)
+ return m;
+ m = m->next_;
+ }
+ if (verb) printf("# Cannot find menu called %s\n", name);
+ return 0;
+}
+
+void menu::create(Widget parent)
+{
+ widget_ = parent;
+ XECFDEBUG printf("# menu::create %p %p\n",widget_,parent);
+ if(item_)
+ item_->create(parent);
+ tip::makeTips(parent);
+}
+
+void sub_menu::create(Widget parent, item * i)
+{
+ if(widget_ == 0) {
+ Arg arg;
+ Widget sub = XmCreatePulldownMenu(parent, i->title(), 0, 0);
+ menu *m = menu::find(i->title(), i->page());
+ if(m)
+ m->create(sub);
+ XtSetArg(arg, XmNsubMenuId, sub);
+ widget_ = XmCreateCascadeButtonGadget(parent, i->title(), &arg, 1);
+ XtManageChild(widget_);
+ xec_SetUserData(widget_, i);
+ XtAddCallback(sub, XmNentryCallback, menus::entryCB, 0);
+ }
+}
+
+void sub_menu::fill(Widget list,int depth)
+{
+ menu *m = menu::find(item_->title(), item_->page());
+ if(m)
+ m->fill(list,depth+3);
+}
+
+void command::create(Widget parent, item * i)
+{
+ if(widget_ == 0) {
+ widget_ = XmCreatePushButtonGadget(parent, i->title(), 0, 0);
+ XtManageChild(widget_);
+ xec_SetUserData(widget_, i);
+ }
+}
+
+void window_cmd::create(Widget parent, item * i)
+{
+ if(widget_ == 0) {
+ widget_ = XmCreatePushButtonGadget(parent, i->title(), 0, 0);
+ XtManageChild(widget_);
+ xec_SetUserData(widget_, i);
+ }
+}
+
+void internal::create(Widget parent, item * i)
+{
+ if(widget_ == 0) {
+ widget_ = XmCreatePushButtonGadget(parent, i->title(), 0, 0);
+ XtManageChild(widget_);
+ xec_SetUserData(widget_, i);
+ }
+}
+
+void internal_a_b::create(Widget parent, item * i) /* internal:: */
+{
+ if(widget_ == 0) {
+ widget_ = XmCreatePushButtonGadget(parent, i->title(), 0, 0);
+ XtManageChild(widget_);
+ xec_SetUserData(widget_, i);
+ }
+}
+
+void separator::create(Widget parent, item * i)
+{
+ if(widget_ == 0) {
+ widget_ = XmCreateSeparatorGadget(parent, "-", 0, 0);
+ XtManageChild(widget_);
+ xec_SetUserData(widget_, i);
+ }
+}
+
+void menu::update(node * n)
+{
+ if(item_) item_->update(n);
+ if(next_) next_->update(n);
+ if(!widget_) return;
+
+ int cnt = 0;
+ Widget last = 0;
+
+ CompositeWidget c = CompositeWidget(widget_);
+
+ XECFDEBUG printf("# menu::update %d\n",c->composite.num_children);
+
+ for(unsigned i = 0 ; i < c->composite.num_children; i++)
+ {
+ Widget p = c->composite.children[i];
+ if(!XtIsManaged(p)) continue;
+
+ XECFDEBUG printf("# %s ",XtName(p));
+
+ if(XtName(p)[0] == '-')
+ {
+ XtUnmanageChild(p);
+ last = p;
+ XECFDEBUG printf("# sep\n");
+ }
+ else
+ {
+ if(last)
+ {
+ XECFDEBUG printf("# (%d) ",cnt);
+ if(cnt) XtManageChild(last);
+ cnt = 0;
+ last = 0;
+ }
+ cnt++;
+ XECFDEBUG printf("# %d\n",cnt);
+ }
+ }
+ XECFDEBUG printf("# menu::update\n");
+}
+
+void item::update(node * n)
+{
+ if(!action_->widget())
+ return;
+ int page = n->__node__() ? 0 : 1;
+#ifndef BRIDGE
+ page = 0;
+#endif
+ if (page_ != page) XtUnmanageChild(action_->widget()); else
+ if(visible_->eval(n))
+ XtManageChild(action_->widget());
+ else
+ XtUnmanageChild(action_->widget());
+
+ XtSetSensitive(action_->widget(),enabled_->eval(n));
+
+ if(next_) next_->update(n);
+}
+
+void menus::entryCB(Widget w, XtPointer, XtPointer cb_data)
+{
+ XmRowColumnCallbackStruct *cb =(XmRowColumnCallbackStruct *) cb_data;
+ item *i =(item *) xec_GetUserData(cb->widget);
+ if(i && selection::menu_node())
+ i->run(selection::menu_node());
+}
+
+void command::run(node* n)
+{
+ n->command(name_);
+}
+
+void window_cmd::run(node* n)
+{
+ if (n != 0 && strncmp("Collect", name_, 7) == 0) collector::show(*n); else
+ panel_window::new_window(n,name_,true,true);
+}
+
+void internal::run(node* n)
+{
+ proc_(n);
+}
+
+void internal_a_b::run(node* n)
+{
+ proc_(n, a_.c_str(), b_.c_str());
+}
+
+void menus::root(menu* m)
+{
+ menu::root(m);
+}
+
+menu* menus::chain(menu* a,menu* b)
+{
+ return a->chain(b);
+}
+
+item* menus::chain(item* a,item* b)
+{
+ return a->chain(b);
+}
+
+menu* menus::create(char* a,item* b)
+{
+ XECFDEBUG printf("# create menus %s\n", a);
+ return new menu(a,b);
+}
+
+item* menus::create(flags* a,flags* b,char* c,action* d,char* e,bool f)
+{
+ XECFDEBUG printf("# create item %d %d %s %s %d\n",
+ a->eval(0) ? 1 : 0, b->eval(0) ? 1 : 0,
+ c, e, f ? 1:0);
+ return new item(a,b,c,d,e,f);
+}
+
+action* menus::command(char* a)
+{
+ return new ::command(a);
+}
+
+action* menus::separator()
+{
+ return new ::separator();
+}
+
+action* menus::sub_menu()
+{
+ return new ::sub_menu();
+}
+
+action* menus::window(char* a)
+{
+ return new ::window_cmd(a);
+}
+
+action* menus::internal(nodeproc a)
+{
+ return new ::internal(a);
+}
+
+action* menus::internal_a_b(nodeproc_a_b a, const char*b, const char *c)
+{
+ return new ::internal_a_b(a, b, c);
+}
+
+void menu::merge(item *i) {
+ if (!i) return;
+ /* menu is old original menu,
+ its items are moved away,
+ new items take place
+ only the old items not found are kept */
+ if (!item_) { item_ = i; return; }
+ item *run, *next, *old = item_, *last = i;
+ while (last->next_) { last = last->next_; }
+ item_ = i;
+ for (run = old; run; ) {
+ next = run->next_; run->next_ = 0;
+ if (!item_->find(run->title())) { last->next_ = run; last = run; }
+ run = next;
+ }
+ last->next_ = 0;
+}
+
+extern "C" {
+// The stuff is here because in some os, lex and yacc are broken with c++
+
+int menus_version(int rel, int maj, int min) { return menus::version(rel, maj, min); }
+menu* menus_chain_menus(menu *a,menu *b) { return menus::chain(a,b); }
+item* menus_chain_items(item *a,item *b) { return menus::chain(a,b); }
+void menus_root(menu *m) { menus::root(m); }
+menu* menus_create_2(char* a,item* b) { return menus::create(a,b); }
+item* menus_create_6(flags* a,flags* b,char* c,action* d,char* e,int f)
+ { return menus::create(a,b,c,d,e,f); }
+
+action* menus_command(char* a) { return menus::command(a); }
+action* menus_window(char* a) { return menus::window(a); }
+action* menus_separator() { return menus::separator(); }
+action* menus_sub_menu() { return menus::sub_menu(); }
+
+flags* new_flagNone() { return new flagNone(); }
+flags* new_typeFlag(int a) { return new typeFlag(a); }
+flags* new_flagNot(flags* a) { return new flagNot(a); }
+flags* new_flagOr(flags* a,flags* b) { return new flagOr(a,b); }
+flags* new_flagAnd(flags* a,flags* b) { return new flagAnd(a,b); }
+
+flags* new_flagAll() { return new flagAll(); }
+flags* new_eventFlag(int a) { return new eventFlag(a); }
+flags* new_selectionFlag() { return new selectionFlag(); }
+flags* new_statusFlag(int a) { return new statusFlag(a); }
+flags* new_userFlag(int a) { return new userFlag(a); }
+
+flags* new_procFlag_node_hasTriggers() { return new procFlag(&node::hasTriggers); }
+flags* new_procFlag_node_hasDate() { return new procFlag(&node::hasDate); }
+flags* new_procFlag_node_hasTime() { return new procFlag(&node::hasTimeHolding); }
+flags* new_procFlag_node_isMigrated() { return new procFlag(&node::isMigrated); }
+flags* new_procFlag_node_isLocked() { return new procFlag(&node::isLocked); }
+flags* new_procFlag_node_hasText() { return new procFlag(&node::hasText); }
+flags* new_procFlag_node_isZombie() { return new procFlag(&node::isZombie); }
+
+action* menus_internal_host_plug() { return menus::internal(&host::plug); }
+action* menus_internal_host_comp(const char*a, const char*b) {
+ return menus::internal_a_b(&host::comp, a, b); }
+
+void log_event_meter_event(const DateTime& a,node* b,int c) {
+ log_event::meter_event(a,b,c); }
+void log_event_event_event(const DateTime& a,node* b,int c) {
+ log_event::event_event(a,b,c); }
+void log_event_status_event(const DateTime& a,node* b,int c) {
+ log_event::status_event(a,b,c); }
+const node *log_event_find(char* a) { return log_event::find(a); }
+}
+
+int script_menus(node*, const char *cmd)
+{
+ menu *m = menu::find("MAIN");
+ if (!m) { std::cerr << "# no menu available!"; return 1; }
+ node *n = selection::current_node();
+ const char* arg = cmd + 5;
+ unsigned int size = arg? strlen(arg) : 0;
+ if (!n) { std::cerr << "# no node selected!"; return 1; }
+ while (m) {
+ item *i = m->item_;
+ while (i) {
+ if (i->visible_ && i->visible_->eval(n)) {
+ if (i->enabled_ && i->enabled_->eval(n)) {
+ if (i->action_) {
+ if (size && !strncasecmp(arg, i->title_, size)) {
+ std::cout << "# cmd issued: " << i->title_ << "\n";
+ i->action_->run(n);
+ } else
+ std::cout << "# item: " << i->title_ << "\n";
+ } else
+ std::cout << "# item enabled: " << i->title_ << "\n";
+ } else
+ std::cout << "# item visible: " << i->title_ << "\n";
+ }
+ i = i->next_;
+ }
+ m = m->next_;
+ }
+
+ return 0;
+}
+
diff --git a/view/src/menus.h b/view/src/menus.h
new file mode 100644
index 0000000..79a1d59
--- /dev/null
+++ b/view/src/menus.h
@@ -0,0 +1,73 @@
+#ifndef menus_H
+#define menus_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #9 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#ifdef NO_BOOL
+#include "bool.h"
+#endif
+
+#include <Xm/Xm.h>
+
+class node;
+class menu;
+class item;
+class action;
+class flags;
+
+class menus {
+public:
+
+ menus();
+ ~menus(); // Change to virtual if base class
+
+ static void entryCB(Widget,XtPointer,XtPointer);
+
+ static void show(Widget,XEvent*,node*);
+
+ static void root(menu*);
+ static menu* chain(menu*,menu*);
+ static item* chain(item*,item*);
+ static menu* create(char*,item*);
+ static item* create(flags*,flags*,char*,action*,char*,bool);
+ static action* command(char*);
+ static action* separator();
+ static action* sub_menu();
+ static action* internal( void (*)(node*) );
+ static action* internal_a_b( void (*)(node*, const char*, const char*),
+ const char *a, const char *b);
+ static action* window(char*);
+
+ static void install(Widget,const char*);
+
+ static void fillList(Widget);
+
+ static void realize();
+ static void write();
+
+ static int version(int rel, int maj, int min);
+
+private:
+
+ menus(const menus&);
+ menus& operator=(const menus&);
+};
+
+inline void destroy(menus**) {}
+
+int script_menus(node*, const char *cmd);
+
+#endif
diff --git a/view/src/menuy.c b/view/src/menuy.c
new file mode 100644
index 0000000..991f7bb
--- /dev/null
+++ b/view/src/menuy.c
@@ -0,0 +1,2380 @@
+/* A Bison parser, made by GNU Bison 2.7. */
+
+/* Bison implementation for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.7"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
+
+
+
+/* Copy the first part of user declarations. */
+/* Line 371 of yacc.c */
+#line 16 "menuy.y"
+
+#include "lexyacc.h"
+#include "ecflow.h"
+int yyone = 0;
+extern int yylineno;
+
+#ifdef __cplusplus
+ void yylex(void);
+#endif
+
+#if defined(_AIX)
+ extern char yytext[];
+ int yydebug;
+#elif defined(hpux)
+ void yyerror(char * msg);
+ int yydebug;
+#elif defined(YYBISON)
+ extern char yytext[]; /* ARRAY */
+ void yyerror(char * msg);
+ int yydebug;
+#elif defined (linux)
+ extern char yytext[];
+ void yyerror(char * msg);
+ int yydebug;
+#elif defined(alpha) || defined(SGI)
+ extern char yytext[]; /* ARRAY */
+#elif defined(SVR4)
+ extern char yytext[]; /* ARRAY */
+#elif defined(alpha)
+ extern unsigned char yytext[];
+#else
+ extern char yytext[];
+ void yyerror(char * msg);
+ int yydebug;
+#endif
+
+/* Line 371 of yacc.c */
+#line 105 "y.tab.c"
+
+# ifndef YY_NULL
+# if defined __cplusplus && 201103L <= __cplusplus
+# define YY_NULL nullptr
+# else
+# define YY_NULL 0
+# endif
+# endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int yydebug;
+#endif
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ VERSION = 258,
+ MENU = 259,
+ IDENT = 260,
+ NONE = 261,
+ ALL = 262,
+ UNKNOWN = 263,
+ SUSPENDED = 264,
+ COMPLETE = 265,
+ QUEUED = 266,
+ SUBMITTED = 267,
+ ACTIVE = 268,
+ ABORTED = 269,
+ CLEAR = 270,
+ SET = 271,
+ SHUTDOWN = 272,
+ HALTED = 273,
+ LOCKED = 274,
+ MIGRATED = 275,
+ SELECTION = 276,
+ SERVER = 277,
+ SMS = 278,
+ NODE = 279,
+ SUITE = 280,
+ FAMILY = 281,
+ TASK = 282,
+ EVENT = 283,
+ LABEL = 284,
+ METER = 285,
+ REPEAT = 286,
+ VARIABLE = 287,
+ TRIGGER = 288,
+ LIMIT = 289,
+ ALIAS = 290,
+ HAS_TRIGGERS = 291,
+ HAS_TIME = 292,
+ HAS_DATE = 293,
+ HAS_TEXT = 294,
+ IS_ZOMBIE = 295,
+ SEPARATOR = 296,
+ STRING = 297,
+ DEFAULT_YES = 298,
+ DEFAULT_NO = 299,
+ WINDOW = 300,
+ PLUG = 301,
+ COMP = 302,
+ USER = 303,
+ OPER = 304,
+ ADMIN = 305,
+ NUMBER = 306,
+ JUNK = 307,
+ EOL = 308,
+ NODE_NAME = 309,
+ CANCEL = 310,
+ ANY = 311
+ };
+#endif
+/* Tokens. */
+#define VERSION 258
+#define MENU 259
+#define IDENT 260
+#define NONE 261
+#define ALL 262
+#define UNKNOWN 263
+#define SUSPENDED 264
+#define COMPLETE 265
+#define QUEUED 266
+#define SUBMITTED 267
+#define ACTIVE 268
+#define ABORTED 269
+#define CLEAR 270
+#define SET 271
+#define SHUTDOWN 272
+#define HALTED 273
+#define LOCKED 274
+#define MIGRATED 275
+#define SELECTION 276
+#define SERVER 277
+#define SMS 278
+#define NODE 279
+#define SUITE 280
+#define FAMILY 281
+#define TASK 282
+#define EVENT 283
+#define LABEL 284
+#define METER 285
+#define REPEAT 286
+#define VARIABLE 287
+#define TRIGGER 288
+#define LIMIT 289
+#define ALIAS 290
+#define HAS_TRIGGERS 291
+#define HAS_TIME 292
+#define HAS_DATE 293
+#define HAS_TEXT 294
+#define IS_ZOMBIE 295
+#define SEPARATOR 296
+#define STRING 297
+#define DEFAULT_YES 298
+#define DEFAULT_NO 299
+#define WINDOW 300
+#define PLUG 301
+#define COMP 302
+#define USER 303
+#define OPER 304
+#define ADMIN 305
+#define NUMBER 306
+#define JUNK 307
+#define EOL 308
+#define NODE_NAME 309
+#define CANCEL 310
+#define ANY 311
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+/* Line 387 of yacc.c */
+#line 140 "menuy.y"
+
+ char *str;
+ long num;
+ flags *flg;
+ item *itm;
+ menu *men;
+ action *act;
+ node* nod;
+ double dbl;
+ DateTime dti;
+
+
+/* Line 387 of yacc.c */
+#line 270 "y.tab.c"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+extern YYSTYPE yylval;
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* Copy the second part of user declarations. */
+
+/* Line 390 of yacc.c */
+#line 298 "y.tab.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(Msgid) dgettext ("bison-runtime", Msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(Msgid) Msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(E) ((void) (E))
+#else
+# define YYUSE(E) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(N) (N)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+ int yyi;
+#endif
+{
+ return yyi;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+ /* Use EXIT_SUCCESS as a witness for stdlib.h. */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined EXIT_SUCCESS \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss_alloc;
+ YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+# define YYCOPY_NEEDED 1
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from SRC to DST. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(Dst, Src, Count) \
+ __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
+# else
+# define YYCOPY(Dst, Src, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (Dst)[yyi] = (Src)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 22
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 200
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 70
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 22
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 91
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 153
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 311
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 65, 2,
+ 60, 62, 2, 2, 61, 2, 68, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 67, 57,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 66, 2, 69, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 58, 64, 59, 63, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint16 yyprhs[] =
+{
+ 0, 0, 3, 6, 8, 10, 12, 18, 21, 23,
+ 26, 32, 34, 36, 39, 41, 55, 65, 68, 70,
+ 72, 74, 76, 78, 80, 82, 84, 86, 88, 90,
+ 92, 94, 96, 98, 100, 102, 104, 106, 108, 110,
+ 112, 114, 116, 118, 120, 122, 124, 126, 128, 130,
+ 132, 134, 136, 138, 140, 142, 144, 148, 152, 156,
+ 158, 160, 162, 164, 166, 171, 173, 180, 182, 184,
+ 186, 188, 190, 193, 194, 198, 200, 202, 215, 219,
+ 223, 227, 232, 236, 240, 244, 248, 252, 260, 263,
+ 265, 267
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int8 yyrhs[] =
+{
+ 71, 0, -1, 72, 73, -1, 73, -1, 89, -1,
+ 84, -1, 3, 75, 75, 75, 57, -1, 74, 73,
+ -1, 74, -1, 74, 1, -1, 4, 75, 58, 76,
+ 59, -1, 5, -1, 42, -1, 77, 76, -1, 77,
+ -1, 60, 79, 61, 79, 61, 80, 61, 81, 61,
+ 82, 61, 83, 62, -1, 60, 79, 61, 79, 61,
+ 80, 61, 81, 62, -1, 63, 78, -1, 6, -1,
+ 7, -1, 8, -1, 9, -1, 10, -1, 11, -1,
+ 12, -1, 13, -1, 14, -1, 15, -1, 16, -1,
+ 17, -1, 18, -1, 22, -1, 23, -1, 25, -1,
+ 26, -1, 27, -1, 24, -1, 28, -1, 29, -1,
+ 30, -1, 31, -1, 32, -1, 33, -1, 35, -1,
+ 34, -1, 36, -1, 38, -1, 37, -1, 39, -1,
+ 40, -1, 20, -1, 19, -1, 48, -1, 49, -1,
+ 50, -1, 21, -1, 60, 79, 62, -1, 78, 64,
+ 79, -1, 78, 65, 79, -1, 78, -1, 42, -1,
+ 42, -1, 41, -1, 4, -1, 45, 60, 75, 62,
+ -1, 46, -1, 47, 60, 75, 61, 75, 62, -1,
+ 42, -1, 43, -1, 44, -1, 85, -1, 86, -1,
+ 85, 86, -1, -1, 88, 91, 91, -1, 89, -1,
+ 1, -1, 66, 91, 67, 91, 67, 91, 91, 68,
+ 91, 68, 91, 69, -1, 87, 10, 90, -1, 87,
+ 11, 90, -1, 87, 13, 90, -1, 87, 12, 90,
+ 56, -1, 87, 12, 90, -1, 87, 14, 90, -1,
+ 87, 8, 90, -1, 87, 16, 90, -1, 87, 15,
+ 90, -1, 87, 30, 66, 90, 91, 90, 69, -1,
+ 87, 52, -1, 52, -1, 54, -1, 51, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 155, 155, 156, 157, 158, 161, 165, 166, 167,
+ 170, 173, 174, 177, 178, 181, 183, 187, 188, 189,
+ 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
+ 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
+ 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
+ 220, 221, 222, 223, 224, 225, 226, 229, 230, 231,
+ 234, 237, 238, 239, 240, 241, 242, 245, 248, 249,
+ 254, 257, 258, 261, 262, 263, 264, 267, 274, 275,
+ 276, 277, 279, 281, 282, 283, 284, 285, 288, 289,
+ 292, 295
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || 0
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "VERSION", "MENU", "IDENT", "NONE",
+ "ALL", "UNKNOWN", "SUSPENDED", "COMPLETE", "QUEUED", "SUBMITTED",
+ "ACTIVE", "ABORTED", "CLEAR", "SET", "SHUTDOWN", "HALTED", "LOCKED",
+ "MIGRATED", "SELECTION", "SERVER", "SMS", "NODE", "SUITE", "FAMILY",
+ "TASK", "EVENT", "LABEL", "METER", "REPEAT", "VARIABLE", "TRIGGER",
+ "LIMIT", "ALIAS", "HAS_TRIGGERS", "HAS_TIME", "HAS_DATE", "HAS_TEXT",
+ "IS_ZOMBIE", "SEPARATOR", "STRING", "DEFAULT_YES", "DEFAULT_NO",
+ "WINDOW", "PLUG", "COMP", "USER", "OPER", "ADMIN", "NUMBER", "JUNK",
+ "EOL", "NODE_NAME", "CANCEL", "ANY", "';'", "'{'", "'}'", "'('", "','",
+ "')'", "'~'", "'|'", "'&'", "'['", "':'", "'.'", "']'", "$accept",
+ "first", "version", "menus", "menu", "name", "menu_items", "menu_item",
+ "flag", "flags", "title", "action", "question", "answer", "logfile",
+ "loglines", "logline", "date", "event", "junk", "node_name", "number", YY_NULL
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
+ 295, 296, 297, 298, 299, 300, 301, 302, 303, 304,
+ 305, 306, 307, 308, 309, 310, 311, 59, 123, 125,
+ 40, 44, 41, 126, 124, 38, 91, 58, 46, 93
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 70, 71, 71, 71, 71, 72, 73, 73, 73,
+ 74, 75, 75, 76, 76, 77, 77, 78, 78, 78,
+ 78, 78, 78, 78, 78, 78, 78, 78, 78, 78,
+ 78, 78, 78, 78, 78, 78, 78, 78, 78, 78,
+ 78, 78, 78, 78, 78, 78, 78, 78, 78, 78,
+ 78, 78, 78, 78, 78, 78, 78, 79, 79, 79,
+ 80, 81, 81, 81, 81, 81, 81, 82, 83, 83,
+ 84, 85, 85, 86, 86, 86, 86, 87, 88, 88,
+ 88, 88, 88, 88, 88, 88, 88, 88, 89, 89,
+ 90, 91
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 2, 1, 1, 1, 5, 2, 1, 2,
+ 5, 1, 1, 2, 1, 13, 9, 2, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 3, 3, 3, 1,
+ 1, 1, 1, 1, 4, 1, 6, 1, 1, 1,
+ 1, 1, 2, 0, 3, 1, 1, 12, 3, 3,
+ 3, 4, 3, 3, 3, 3, 3, 7, 2, 1,
+ 1, 1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
+ Performed when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 0, 76, 0, 0, 89, 0, 0, 0, 3, 0,
+ 5, 0, 71, 0, 0, 75, 11, 12, 0, 0,
+ 91, 0, 1, 2, 9, 7, 72, 75, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 88, 0, 0,
+ 0, 0, 90, 84, 78, 79, 82, 80, 83, 86,
+ 85, 0, 74, 0, 0, 0, 14, 0, 81, 0,
+ 6, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+ 27, 28, 29, 30, 51, 50, 55, 31, 32, 36,
+ 33, 34, 35, 37, 38, 39, 40, 41, 42, 44,
+ 43, 45, 47, 46, 48, 49, 52, 53, 54, 0,
+ 0, 59, 0, 10, 13, 0, 0, 0, 17, 0,
+ 0, 0, 0, 0, 56, 57, 58, 0, 0, 87,
+ 0, 0, 60, 0, 0, 0, 0, 63, 62, 61,
+ 0, 65, 0, 0, 0, 0, 0, 0, 16, 77,
+ 0, 0, 67, 0, 64, 0, 0, 0, 68, 69,
+ 0, 66, 15
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
+{
+ -1, 6, 7, 8, 9, 18, 55, 56, 101, 102,
+ 123, 133, 143, 150, 10, 11, 12, 13, 14, 15,
+ 43, 21
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -47
+static const yytype_int16 yypact[] =
+{
+ 9, -47, 6, 6, -47, -31, 26, 33, -47, 18,
+ -47, 16, -47, 19, -31, 44, -47, -47, 6, -11,
+ -47, -22, -47, -47, -47, -47, -47, -47, -4, -4,
+ -4, -4, -4, -4, -4, -4, -12, -47, -31, 6,
+ -2, -31, -47, -47, -47, -47, 3, -47, -47, -47,
+ -47, -4, -47, 5, 137, 1, -2, 0, -47, -31,
+ -47, -47, -47, -47, -47, -47, -47, -47, -47, -47,
+ -47, -47, -47, -47, -47, -47, -47, -47, -47, -47,
+ -47, -47, -47, -47, -47, -47, -47, -47, -47, -47,
+ -47, -47, -47, -47, -47, -47, -47, -47, -47, 137,
+ 137, -26, 8, -47, -47, -31, -4, 4, -47, 137,
+ 137, 137, -31, 7, -47, -47, -47, 11, 2, -47,
+ 31, -31, -47, 13, 12, 10, -31, -47, -47, -47,
+ 17, -47, 21, -21, 15, 6, 6, 36, -47, -47,
+ 23, 22, -47, 25, -47, 6, -1, 27, -47, -47,
+ 28, -47, -47
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int8 yypgoto[] =
+{
+ -47, -47, -47, 14, -47, -3, 32, -47, -9, -46,
+ -47, -47, -47, -47, -47, -47, 76, -47, -47, 82,
+ -27, -13
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -74
+static const yytype_int16 yytable[] =
+{
+ 19, 38, 44, 45, 46, 47, 48, 49, 50, -73,
+ 1, 16, 2, 3, 127, 39, -70, 1, -8, 24,
+ 20, 23, 3, 25, 59, 52, 22, 28, 57, 29,
+ 30, 31, 32, 33, 34, 35, 53, 3, 109, 110,
+ 137, 138, 148, 149, -4, 41, 106, 40, 17, 36,
+ 42, 128, 129, 107, 51, 130, 131, 132, 54, 58,
+ 103, 4, 60, 115, 116, 117, 114, 105, 4, 111,
+ 121, 37, 120, 122, 125, 5, 119, 135, 142, 113,
+ 126, 136, 5, 145, 139, 144, 146, 26, 104, 151,
+ 152, 108, 112, 27, 0, 0, 0, 0, 0, 118,
+ 0, 0, 0, 0, 0, 0, 0, 0, 124, 0,
+ 0, 0, 0, 134, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 140, 141, 0, 0, 0, 0, 0, 0,
+ 0, 0, 147, 61, 62, 63, 64, 65, 66, 67,
+ 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
+ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87,
+ 88, 89, 90, 91, 92, 93, 94, 95, 0, 0,
+ 0, 0, 0, 0, 0, 96, 97, 98, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 99, 0, 0,
+ 100
+};
+
+#define yypact_value_is_default(Yystate) \
+ (!!((Yystate) == (-47)))
+
+#define yytable_value_is_error(Yytable_value) \
+ YYID (0)
+
+static const yytype_int16 yycheck[] =
+{
+ 3, 14, 29, 30, 31, 32, 33, 34, 35, 0,
+ 1, 5, 3, 4, 4, 18, 0, 1, 0, 1,
+ 51, 7, 4, 9, 51, 38, 0, 8, 41, 10,
+ 11, 12, 13, 14, 15, 16, 39, 4, 64, 65,
+ 61, 62, 43, 44, 0, 67, 59, 58, 42, 30,
+ 54, 41, 42, 99, 66, 45, 46, 47, 60, 56,
+ 59, 52, 57, 109, 110, 111, 62, 67, 52, 61,
+ 68, 52, 61, 42, 61, 66, 69, 60, 42, 106,
+ 68, 60, 66, 61, 69, 62, 61, 11, 56, 62,
+ 62, 100, 105, 11, -1, -1, -1, -1, -1, 112,
+ -1, -1, -1, -1, -1, -1, -1, -1, 121, -1,
+ -1, -1, -1, 126, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 135, 136, -1, -1, -1, -1, -1, -1,
+ -1, -1, 145, 6, 7, 8, 9, 10, 11, 12,
+ 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40, -1, -1,
+ -1, -1, -1, -1, -1, 48, 49, 50, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 60, -1, -1,
+ 63
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 1, 3, 4, 52, 66, 71, 72, 73, 74,
+ 84, 85, 86, 87, 88, 89, 5, 42, 75, 75,
+ 51, 91, 0, 73, 1, 73, 86, 89, 8, 10,
+ 11, 12, 13, 14, 15, 16, 30, 52, 91, 75,
+ 58, 67, 54, 90, 90, 90, 90, 90, 90, 90,
+ 90, 66, 91, 75, 60, 76, 77, 91, 56, 90,
+ 57, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 48, 49, 50, 60,
+ 63, 78, 79, 59, 76, 67, 91, 79, 78, 64,
+ 65, 61, 91, 90, 62, 79, 79, 79, 91, 69,
+ 61, 68, 42, 80, 91, 61, 68, 4, 41, 42,
+ 45, 46, 47, 81, 91, 60, 60, 61, 62, 69,
+ 75, 75, 42, 82, 62, 61, 61, 75, 43, 44,
+ 83, 62, 62
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. However,
+ YYFAIL appears to be in use. Nevertheless, it is formally deprecated
+ in Bison 2.4.2's NEWS entry, where a plan to phase it out is
+ discussed. */
+
+#define YYFAIL goto yyerrlab
+#if defined YYFAIL
+ /* This is here to suppress warnings from the GCC cpp's
+ -Wunused-macros. Normally we don't worry about that warning, but
+ some users do, and we want to make it easy for users to remove
+ YYFAIL uses, which will produce warnings from Bison 2.5. */
+#endif
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ YYPOPSTACK (yylen); \
+ yystate = *yyssp; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+/* Error token number */
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* This macro is provided for backward compatibility. */
+#ifndef YY_LOCATION_PRINT
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ FILE *yyo = yyoutput;
+ YYUSE (yyo);
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+#else
+static void
+yy_stack_print (yybottom, yytop)
+ yytype_int16 *yybottom;
+ yytype_int16 *yytop;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+ YYSTYPE *yyvsp;
+ int yyrule;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ YYFPRINTF (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+ about the unexpected token YYTOKEN for the state stack whose top is
+ YYSSP.
+
+ Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is
+ not large enough to hold the message. In that case, also set
+ *YYMSG_ALLOC to the required number of bytes. Return 2 if the
+ required number of bytes is too large to store. */
+static int
+yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+ yytype_int16 *yyssp, int yytoken)
+{
+ YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]);
+ YYSIZE_T yysize = yysize0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ /* Internationalized format string. */
+ const char *yyformat = YY_NULL;
+ /* Arguments of yyformat. */
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ /* Number of reported tokens (one for the "unexpected", one per
+ "expected"). */
+ int yycount = 0;
+
+ /* There are many possibilities here to consider:
+ - Assume YYFAIL is not used. It's too flawed to consider. See
+ <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
+ for details. YYERROR is fine as it does not invoke this
+ function.
+ - If this state is a consistent state with a default action, then
+ the only way this function was invoked is if the default action
+ is an error action. In that case, don't check for expected
+ tokens because there are none.
+ - The only way there can be no lookahead present (in yychar) is if
+ this state is a consistent state with a default action. Thus,
+ detecting the absence of a lookahead is sufficient to determine
+ that there is no unexpected or expected token to report. In that
+ case, just report a simple "syntax error".
+ - Don't assume there isn't a lookahead just because this state is a
+ consistent state with a default action. There might have been a
+ previous inconsistent state, consistent state with a non-default
+ action, or user semantic action that manipulated yychar.
+ - Of course, the expected token list depends on states to have
+ correct lookahead information, and it depends on the parser not
+ to perform extra reductions after fetching a lookahead from the
+ scanner and before detecting a syntax error. Thus, state merging
+ (from LALR or IELR) and default reductions corrupt the expected
+ token list. However, the list is correct for canonical LR with
+ one exception: it will still contain any token that will not be
+ accepted due to an error action in a later state.
+ */
+ if (yytoken != YYEMPTY)
+ {
+ int yyn = yypact[*yyssp];
+ yyarg[yycount++] = yytname[yytoken];
+ if (!yypact_value_is_default (yyn))
+ {
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. In other words, skip the first -YYN actions for
+ this state because they are default actions. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yyx;
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
+ && !yytable_value_is_error (yytable[yyx + yyn]))
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ {
+ YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]);
+ if (! (yysize <= yysize1
+ && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
+ }
+ }
+ }
+
+ switch (yycount)
+ {
+# define YYCASE_(N, S) \
+ case N: \
+ yyformat = S; \
+ break
+ YYCASE_(0, YY_("syntax error"));
+ YYCASE_(1, YY_("syntax error, unexpected %s"));
+ YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+ YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+ YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+ YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+# undef YYCASE_
+ }
+
+ {
+ YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
+ if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
+
+ if (*yymsg_alloc < yysize)
+ {
+ *yymsg_alloc = 2 * yysize;
+ if (! (yysize <= *yymsg_alloc
+ && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+ *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+ return 1;
+ }
+
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ {
+ char *yyp = *yymsg;
+ int yyi = 0;
+ while ((*yyp = *yyformat) != '\0')
+ if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyformat += 2;
+ }
+ else
+ {
+ yyp++;
+ yyformat++;
+ }
+ }
+ return 0;
+}
+#endif /* YYERROR_VERBOSE */
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ YYUSE (yyvaluep);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+
+
+/* The lookahead symbol. */
+int yychar;
+
+
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval YY_INITIAL_VALUE(yyval_default);
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+ int yystate;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+
+ /* The stacks and their tools:
+ `yyss': related to states.
+ `yyvs': related to semantic values.
+
+ Refer to the stacks through separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs;
+ YYSTYPE *yyvsp;
+
+ YYSIZE_T yystacksize;
+
+ int yyn;
+ int yyresult;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken = 0;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ yyssp = yyss = yyssa;
+ yyvsp = yyvs = yyvsa;
+ yystacksize = YYINITDEPTH;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to lookahead token. */
+ yyn = yypact[yystate];
+ if (yypact_value_is_default (yyn))
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yytable_value_is_error (yyn))
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 2:
+/* Line 1792 of yacc.c */
+#line 155 "menuy.y"
+ { menus_root((yyvsp[(2) - (2)].men)); }
+ break;
+
+ case 3:
+/* Line 1792 of yacc.c */
+#line 156 "menuy.y"
+ { menus_root((yyvsp[(1) - (1)].men)); }
+ break;
+
+ case 6:
+/* Line 1792 of yacc.c */
+#line 162 "menuy.y"
+ { (yyval.num) = menus_version(atol((yyvsp[(2) - (5)].str)), atol((yyvsp[(3) - (5)].str)), atol((yyvsp[(4) - (5)].str))); }
+ break;
+
+ case 7:
+/* Line 1792 of yacc.c */
+#line 165 "menuy.y"
+ { (yyval.men) = menus_chain_menus((yyvsp[(1) - (2)].men),(yyvsp[(2) - (2)].men)); }
+ break;
+
+ case 9:
+/* Line 1792 of yacc.c */
+#line 167 "menuy.y"
+ { (yyval.men) = (yyvsp[(1) - (2)].men); }
+ break;
+
+ case 10:
+/* Line 1792 of yacc.c */
+#line 170 "menuy.y"
+ { (yyval.men) = menus_create_2((yyvsp[(2) - (5)].str),(yyvsp[(4) - (5)].itm)); }
+ break;
+
+ case 11:
+/* Line 1792 of yacc.c */
+#line 173 "menuy.y"
+ { (yyval.str) = strdup(yytext); }
+ break;
+
+ case 12:
+/* Line 1792 of yacc.c */
+#line 174 "menuy.y"
+ { (yyval.str) = strdup(yytext); }
+ break;
+
+ case 13:
+/* Line 1792 of yacc.c */
+#line 177 "menuy.y"
+ { (yyval.itm) = menus_chain_items((yyvsp[(1) - (2)].itm),(yyvsp[(2) - (2)].itm)); }
+ break;
+
+ case 15:
+/* Line 1792 of yacc.c */
+#line 182 "menuy.y"
+ { (yyval.itm) = menus_create_6((yyvsp[(2) - (13)].flg),(yyvsp[(4) - (13)].flg),(yyvsp[(6) - (13)].str),(yyvsp[(8) - (13)].act),(yyvsp[(10) - (13)].str),(yyvsp[(12) - (13)].num)); }
+ break;
+
+ case 16:
+/* Line 1792 of yacc.c */
+#line 184 "menuy.y"
+ { (yyval.itm) = menus_create_6((yyvsp[(2) - (9)].flg),(yyvsp[(4) - (9)].flg),(yyvsp[(6) - (9)].str),(yyvsp[(8) - (9)].act),"",1); }
+ break;
+
+ case 17:
+/* Line 1792 of yacc.c */
+#line 187 "menuy.y"
+ { (yyval.flg) = new_flagNot((yyvsp[(2) - (2)].flg)); }
+ break;
+
+ case 18:
+/* Line 1792 of yacc.c */
+#line 188 "menuy.y"
+ { (yyval.flg) = new_flagNone(); }
+ break;
+
+ case 19:
+/* Line 1792 of yacc.c */
+#line 189 "menuy.y"
+ { (yyval.flg) = new_flagAll(); }
+ break;
+
+ case 20:
+/* Line 1792 of yacc.c */
+#line 190 "menuy.y"
+ { (yyval.flg) = new_statusFlag(STATUS_UNKNOWN); }
+ break;
+
+ case 21:
+/* Line 1792 of yacc.c */
+#line 191 "menuy.y"
+ { (yyval.flg) = new_statusFlag(STATUS_SUSPENDED); }
+ break;
+
+ case 22:
+/* Line 1792 of yacc.c */
+#line 192 "menuy.y"
+ { (yyval.flg) = new_statusFlag(STATUS_COMPLETE); }
+ break;
+
+ case 23:
+/* Line 1792 of yacc.c */
+#line 193 "menuy.y"
+ { (yyval.flg) = new_statusFlag(STATUS_QUEUED); }
+ break;
+
+ case 24:
+/* Line 1792 of yacc.c */
+#line 194 "menuy.y"
+ { (yyval.flg) = new_statusFlag(STATUS_SUBMITTED); }
+ break;
+
+ case 25:
+/* Line 1792 of yacc.c */
+#line 195 "menuy.y"
+ { (yyval.flg) = new_statusFlag(STATUS_ACTIVE); }
+ break;
+
+ case 26:
+/* Line 1792 of yacc.c */
+#line 196 "menuy.y"
+ { (yyval.flg) = new_statusFlag(STATUS_ABORTED); }
+ break;
+
+ case 27:
+/* Line 1792 of yacc.c */
+#line 197 "menuy.y"
+ { (yyval.flg) = new_eventFlag(0); }
+ break;
+
+ case 28:
+/* Line 1792 of yacc.c */
+#line 198 "menuy.y"
+ { (yyval.flg) = new_eventFlag(1); }
+ break;
+
+ case 29:
+/* Line 1792 of yacc.c */
+#line 199 "menuy.y"
+ { (yyval.flg) = new_statusFlag(STATUS_SHUTDOWN); }
+ break;
+
+ case 30:
+/* Line 1792 of yacc.c */
+#line 200 "menuy.y"
+ { (yyval.flg) = new_statusFlag(STATUS_HALTED); }
+ break;
+
+ case 31:
+/* Line 1792 of yacc.c */
+#line 201 "menuy.y"
+ { (yyval.flg) = new_typeFlag(NODE_SUPER) ; }
+ break;
+
+ case 32:
+/* Line 1792 of yacc.c */
+#line 202 "menuy.y"
+ { (yyval.flg) = new_typeFlag(NODE_SUPER) ; }
+ break;
+
+ case 33:
+/* Line 1792 of yacc.c */
+#line 203 "menuy.y"
+ { (yyval.flg) = new_typeFlag(NODE_SUITE) ; }
+ break;
+
+ case 34:
+/* Line 1792 of yacc.c */
+#line 204 "menuy.y"
+ { (yyval.flg) = new_typeFlag(NODE_FAMILY) ; }
+ break;
+
+ case 35:
+/* Line 1792 of yacc.c */
+#line 205 "menuy.y"
+ { (yyval.flg) = new_typeFlag(NODE_TASK) ; }
+ break;
+
+ case 36:
+/* Line 1792 of yacc.c */
+#line 206 "menuy.y"
+ { (yyval.flg) = new_flagOr(new_flagOr(new_typeFlag(NODE_SUITE),new_typeFlag(NODE_FAMILY)),new_typeFlag(NODE_TASK)); }
+ break;
+
+ case 37:
+/* Line 1792 of yacc.c */
+#line 207 "menuy.y"
+ { (yyval.flg) = new_typeFlag(NODE_EVENT) ; }
+ break;
+
+ case 38:
+/* Line 1792 of yacc.c */
+#line 208 "menuy.y"
+ { (yyval.flg) = new_typeFlag(NODE_LABEL) ; }
+ break;
+
+ case 39:
+/* Line 1792 of yacc.c */
+#line 209 "menuy.y"
+ { (yyval.flg) = new_typeFlag(NODE_METER) ; }
+ break;
+
+ case 40:
+/* Line 1792 of yacc.c */
+#line 210 "menuy.y"
+ { (yyval.flg) = new_typeFlag(NODE_REPEAT) ; }
+ break;
+
+ case 41:
+/* Line 1792 of yacc.c */
+#line 211 "menuy.y"
+ { (yyval.flg) = new_typeFlag(NODE_VARIABLE) ; }
+ break;
+
+ case 42:
+/* Line 1792 of yacc.c */
+#line 212 "menuy.y"
+ { (yyval.flg) = new_typeFlag(NODE_TRIGGER) ; }
+ break;
+
+ case 43:
+/* Line 1792 of yacc.c */
+#line 213 "menuy.y"
+ { (yyval.flg) = new_typeFlag(NODE_ALIAS) ; }
+ break;
+
+ case 44:
+/* Line 1792 of yacc.c */
+#line 214 "menuy.y"
+ { (yyval.flg) = new_typeFlag(NODE_LIMIT) ; }
+ break;
+
+ case 45:
+/* Line 1792 of yacc.c */
+#line 215 "menuy.y"
+ { (yyval.flg) = new_procFlag_node_hasTriggers(); }
+ break;
+
+ case 46:
+/* Line 1792 of yacc.c */
+#line 216 "menuy.y"
+ { (yyval.flg) = new_procFlag_node_hasDate(); }
+ break;
+
+ case 47:
+/* Line 1792 of yacc.c */
+#line 217 "menuy.y"
+ { (yyval.flg) = new_procFlag_node_hasTime(); }
+ break;
+
+ case 48:
+/* Line 1792 of yacc.c */
+#line 218 "menuy.y"
+ { (yyval.flg) = new_procFlag_node_hasText(); }
+ break;
+
+ case 49:
+/* Line 1792 of yacc.c */
+#line 219 "menuy.y"
+ { (yyval.flg) = new_procFlag_node_isZombie(); }
+ break;
+
+ case 50:
+/* Line 1792 of yacc.c */
+#line 220 "menuy.y"
+ { (yyval.flg) = new_procFlag_node_isMigrated(); }
+ break;
+
+ case 51:
+/* Line 1792 of yacc.c */
+#line 221 "menuy.y"
+ { (yyval.flg) = new_procFlag_node_isLocked(); }
+ break;
+
+ case 52:
+/* Line 1792 of yacc.c */
+#line 222 "menuy.y"
+ { (yyval.flg) = new_userFlag(0); }
+ break;
+
+ case 53:
+/* Line 1792 of yacc.c */
+#line 223 "menuy.y"
+ { (yyval.flg) = new_userFlag(1); }
+ break;
+
+ case 54:
+/* Line 1792 of yacc.c */
+#line 224 "menuy.y"
+ { (yyval.flg) = new_userFlag(2); }
+ break;
+
+ case 55:
+/* Line 1792 of yacc.c */
+#line 225 "menuy.y"
+ { (yyval.flg) = new_selectionFlag(); }
+ break;
+
+ case 56:
+/* Line 1792 of yacc.c */
+#line 226 "menuy.y"
+ { (yyval.flg) = (yyvsp[(2) - (3)].flg); }
+ break;
+
+ case 57:
+/* Line 1792 of yacc.c */
+#line 229 "menuy.y"
+ { (yyval.flg) = new_flagOr((yyvsp[(1) - (3)].flg),(yyvsp[(3) - (3)].flg)); }
+ break;
+
+ case 58:
+/* Line 1792 of yacc.c */
+#line 230 "menuy.y"
+ { (yyval.flg) = new_flagAnd((yyvsp[(1) - (3)].flg),(yyvsp[(3) - (3)].flg)); }
+ break;
+
+ case 60:
+/* Line 1792 of yacc.c */
+#line 234 "menuy.y"
+ { (yyval.str) = strdup(yytext); }
+ break;
+
+ case 61:
+/* Line 1792 of yacc.c */
+#line 237 "menuy.y"
+ { (yyval.act) = menus_command(strdup(yytext)); }
+ break;
+
+ case 62:
+/* Line 1792 of yacc.c */
+#line 238 "menuy.y"
+ { (yyval.act) = menus_separator(); }
+ break;
+
+ case 63:
+/* Line 1792 of yacc.c */
+#line 239 "menuy.y"
+ { (yyval.act) = menus_sub_menu(); }
+ break;
+
+ case 64:
+/* Line 1792 of yacc.c */
+#line 240 "menuy.y"
+ { (yyval.act) = menus_window((yyvsp[(3) - (4)].str)); }
+ break;
+
+ case 65:
+/* Line 1792 of yacc.c */
+#line 241 "menuy.y"
+ { (yyval.act) = menus_internal_host_plug(); }
+ break;
+
+ case 66:
+/* Line 1792 of yacc.c */
+#line 242 "menuy.y"
+ { (yyval.act) = menus_internal_host_comp((yyvsp[(3) - (6)].str), (yyvsp[(5) - (6)].str)); }
+ break;
+
+ case 67:
+/* Line 1792 of yacc.c */
+#line 245 "menuy.y"
+ { (yyval.str) = strdup(yytext); }
+ break;
+
+ case 68:
+/* Line 1792 of yacc.c */
+#line 248 "menuy.y"
+ { (yyval.num) = 1; }
+ break;
+
+ case 69:
+/* Line 1792 of yacc.c */
+#line 249 "menuy.y"
+ { (yyval.num) = 0; }
+ break;
+
+ case 74:
+/* Line 1792 of yacc.c */
+#line 262 "menuy.y"
+ { if(yyone) return 0; }
+ break;
+
+ case 76:
+/* Line 1792 of yacc.c */
+#line 264 "menuy.y"
+ { /* extern int yylineno; printf("error line %d [%s]\n",yylineno, yytext); */ }
+ break;
+
+ case 77:
+/* Line 1792 of yacc.c */
+#line 268 "menuy.y"
+ {
+ (yyval.dti).date = ((yyvsp[(11) - (12)].num) * 10000 + (yyvsp[(9) - (12)].num) * 100 + (yyvsp[(7) - (12)].num));
+ (yyval.dti).time = ((yyvsp[(2) - (12)].num) * 10000 + (yyvsp[(4) - (12)].num) * 100 + (yyvsp[(6) - (12)].num));
+ }
+ break;
+
+ case 78:
+/* Line 1792 of yacc.c */
+#line 274 "menuy.y"
+ { log_event_status_event(&(yyvsp[(1) - (3)].dti),(yyvsp[(3) - (3)].nod),STATUS_COMPLETE); }
+ break;
+
+ case 79:
+/* Line 1792 of yacc.c */
+#line 275 "menuy.y"
+ { log_event_status_event(&(yyvsp[(1) - (3)].dti),(yyvsp[(3) - (3)].nod),STATUS_QUEUED); }
+ break;
+
+ case 80:
+/* Line 1792 of yacc.c */
+#line 276 "menuy.y"
+ { log_event_status_event(&(yyvsp[(1) - (3)].dti),(yyvsp[(3) - (3)].nod),STATUS_ACTIVE); }
+ break;
+
+ case 81:
+/* Line 1792 of yacc.c */
+#line 278 "menuy.y"
+ { log_event_status_event(&(yyvsp[(1) - (4)].dti),(yyvsp[(3) - (4)].nod),STATUS_SUBMITTED); }
+ break;
+
+ case 82:
+/* Line 1792 of yacc.c */
+#line 280 "menuy.y"
+ { log_event_status_event(&(yyvsp[(1) - (3)].dti),(yyvsp[(3) - (3)].nod),STATUS_SUBMITTED); }
+ break;
+
+ case 83:
+/* Line 1792 of yacc.c */
+#line 281 "menuy.y"
+ { log_event_status_event(&(yyvsp[(1) - (3)].dti),(yyvsp[(3) - (3)].nod),STATUS_ABORTED);}
+ break;
+
+ case 84:
+/* Line 1792 of yacc.c */
+#line 282 "menuy.y"
+ { log_event_status_event(&(yyvsp[(1) - (3)].dti),(yyvsp[(3) - (3)].nod),STATUS_UNKNOWN);}
+ break;
+
+ case 85:
+/* Line 1792 of yacc.c */
+#line 283 "menuy.y"
+ { log_event_event_event(&(yyvsp[(1) - (3)].dti),(yyvsp[(3) - (3)].nod),1); }
+ break;
+
+ case 86:
+/* Line 1792 of yacc.c */
+#line 284 "menuy.y"
+ { log_event_event_event(&(yyvsp[(1) - (3)].dti),(yyvsp[(3) - (3)].nod),0); }
+ break;
+
+ case 87:
+/* Line 1792 of yacc.c */
+#line 285 "menuy.y"
+ { log_event_meter_event(&(yyvsp[(1) - (7)].dti),(yyvsp[(6) - (7)].nod),(yyvsp[(5) - (7)].num)); }
+ break;
+
+ case 90:
+/* Line 1792 of yacc.c */
+#line 292 "menuy.y"
+ { (yyval.nod) = log_event_find(yytext); }
+ break;
+
+ case 91:
+/* Line 1792 of yacc.c */
+#line 295 "menuy.y"
+ { (yyval.num) = atol(yytext); }
+ break;
+
+
+/* Line 1792 of yacc.c */
+#line 2118 "y.tab.c"
+ default: break;
+ }
+ /* User semantic actions sometimes alter yychar, and that requires
+ that yytoken be updated with the new translation. We take the
+ approach of translating immediately before every use of yytoken.
+ One alternative is translating here after every semantic action,
+ but that translation would be missed if the semantic action invokes
+ YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+ if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
+ incorrect destructor might then be invoked immediately. In the
+ case of YYERROR or YYBACKUP, subsequent parser actions might lead
+ to an incorrect destructor call or verbose syntax error message
+ before the lookahead is translated. */
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
+
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
+ yyssp, yytoken)
+ {
+ char const *yymsgp = YY_("syntax error");
+ int yysyntax_error_status;
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ if (yysyntax_error_status == 0)
+ yymsgp = yymsg;
+ else if (yysyntax_error_status == 1)
+ {
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
+ if (!yymsg)
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ yysyntax_error_status = 2;
+ }
+ else
+ {
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ yymsgp = yymsg;
+ }
+ }
+ yyerror (yymsgp);
+ if (yysyntax_error_status == 2)
+ goto yyexhaustedlab;
+ }
+# undef YYSYNTAX_ERROR
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (!yypact_value_is_default (yyn))
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#if !defined yyoverflow || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEMPTY)
+ {
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = YYTRANSLATE (yychar);
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ }
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
+/* Line 2055 of yacc.c */
+#line 298 "menuy.y"
+
+
+#include "menul.c"
+
+int yywrap() {
+ return 1;
+}
+
+#ifdef AIX
+int yyerror(char * msg)
+#else
+void yyerror(char * msg)
+#endif
+{
+ /* printf("!menu parsing issue?\n");
+ printf("%s line %d last token <%s>\n",msg,yylineno,yytext); */
+ if (!strncmp("MSG:", yytext, 4)) {}
+ else if (!strncmp("DBG:", yytext, 4)) {}
+ else if (!strncmp("ERR:", yytext, 4)) {}
+ else if (!strncmp("WAR:", yytext, 4)) {}
+ else if (!strncmp("try-no:", yytext, 6)) {}
+ else if (!strncmp("File", yytext, 4)) {}
+ else if (!strncmp("Variable", yytext, 8)) {}
+ else if (!strncmp("Directory", yytext, 9)) {}
+ else if (!strncmp("Search", yytext, 6)) {}
+ else if (*yytext == '[') {}
+ else if (*yytext == ':') {}
+ else if (*yytext == '/') {}
+ else printf("!%s:%d:<%s>\n",msg,yylineno,yytext);
+}
+
diff --git a/view/src/menuy.y b/view/src/menuy.y
new file mode 100644
index 0000000..45438e0
--- /dev/null
+++ b/view/src/menuy.y
@@ -0,0 +1,328 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #17 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+%{
+#include "lexyacc.h"
+#include "ecflow.h"
+int yyone = 0;
+extern int yylineno;
+
+#ifdef __cplusplus
+ void yylex(void);
+#endif
+
+#if defined(_AIX)
+ extern char yytext[];
+ int yydebug;
+#elif defined(hpux)
+ void yyerror(char * msg);
+ int yydebug;
+#elif defined(YYBISON)
+ extern char yytext[]; /* ARRAY */
+ void yyerror(char * msg);
+ int yydebug;
+#elif defined (linux)
+ extern char yytext[];
+ void yyerror(char * msg);
+ int yydebug;
+#elif defined(alpha) || defined(SGI)
+ extern char yytext[]; /* ARRAY */
+#elif defined(SVR4)
+ extern char yytext[]; /* ARRAY */
+#elif defined(alpha)
+ extern unsigned char yytext[];
+#else
+ extern char yytext[];
+ void yyerror(char * msg);
+ int yydebug;
+#endif
+%}
+
+%token VERSION
+%token MENU
+%token IDENT
+%token NONE
+%token ALL
+%token UNKNOWN
+%token SUSPENDED
+%token COMPLETE
+%token QUEUED
+%token SUBMITTED
+%token ACTIVE
+%token ABORTED
+%token CLEAR
+%token SET
+%token SHUTDOWN
+%token HALTED
+%token LOCKED
+%token MIGRATED
+%token SELECTION
+
+%token SERVER
+%token SMS
+%token NODE
+%token SUITE
+%token FAMILY
+%token TASK
+%token EVENT
+%token LABEL
+%token METER
+%token REPEAT
+%token VARIABLE
+%token TRIGGER
+%token LIMIT
+%token ALIAS
+
+%token HAS_TRIGGERS
+%token HAS_TIME
+%token HAS_DATE
+%token HAS_TEXT
+
+%token IS_ZOMBIE
+
+%token SEPARATOR
+%token STRING
+%token DEFAULT_YES
+%token DEFAULT_NO
+
+%token WINDOW
+%token PLUG
+%token COMP
+
+%token USER
+%token OPER
+%token ADMIN
+
+
+%token NUMBER
+%token JUNK
+%token EOL
+%token NODE_NAME
+%token CANCEL
+%token ANY
+
+%type<flg> flags;
+%type<flg> flag;
+
+%type<str> question;
+%type<str> title;
+%type<act> action;
+%type<str> name;
+%type<num> answer;
+%type<num> version;
+
+%type<itm> menu_items;
+%type<itm> menu_item;
+
+%type<men> menu;
+%type<men> menus;
+
+%type<nod> node_name;
+%type<num> number;
+
+%type<dti> date;
+
+
+%start first
+
+%union {
+ char *str;
+ long num;
+ flags *flg;
+ item *itm;
+ menu *men;
+ action *act;
+ node* nod;
+ double dbl;
+ DateTime dti;
+};
+
+
+%%
+
+first : version menus { menus_root($2); }
+ | menus { menus_root($1); }
+ | junk
+ | logfile
+ ;
+
+version : VERSION name name name ';'
+ { $$ = menus_version(atol($2), atol($3), atol($4)); }
+ ;
+
+menus : menu menus { $$ = menus_chain_menus($1,$2); }
+ | menu
+ | menu error { $$ = $1; }
+ ;
+
+menu : MENU name '{' menu_items '}' { $$ = menus_create_2($2,$4); }
+ ;
+
+name : IDENT { $$ = strdup(yytext); }
+ | STRING { $$ = strdup(yytext); }
+ ;
+
+menu_items : menu_item menu_items { $$ = menus_chain_items($1,$2); }
+ | menu_item
+ ;
+
+menu_item : '(' flags ',' flags ',' title ',' action ',' question ',' answer ')'
+ { $$ = menus_create_6($2,$4,$6,$8,$10,$12); }
+ | '(' flags ',' flags ',' title ',' action ')'
+ { $$ = menus_create_6($2,$4,$6,$8,"",1); }
+ ;
+
+flag : '~' flag { $$ = new_flagNot($2); }
+ | NONE { $$ = new_flagNone(); }
+ | ALL { $$ = new_flagAll(); }
+ | UNKNOWN { $$ = new_statusFlag(STATUS_UNKNOWN); }
+ | SUSPENDED { $$ = new_statusFlag(STATUS_SUSPENDED); }
+ | COMPLETE { $$ = new_statusFlag(STATUS_COMPLETE); }
+ | QUEUED { $$ = new_statusFlag(STATUS_QUEUED); }
+ | SUBMITTED { $$ = new_statusFlag(STATUS_SUBMITTED); }
+ | ACTIVE { $$ = new_statusFlag(STATUS_ACTIVE); }
+ | ABORTED { $$ = new_statusFlag(STATUS_ABORTED); }
+ | CLEAR { $$ = new_eventFlag(0); }
+ | SET { $$ = new_eventFlag(1); }
+ | SHUTDOWN { $$ = new_statusFlag(STATUS_SHUTDOWN); }
+ | HALTED { $$ = new_statusFlag(STATUS_HALTED); }
+ | SERVER { $$ = new_typeFlag(NODE_SUPER) ; }
+ | SMS { $$ = new_typeFlag(NODE_SUPER) ; }
+ | SUITE { $$ = new_typeFlag(NODE_SUITE) ; }
+ | FAMILY { $$ = new_typeFlag(NODE_FAMILY) ; }
+ | TASK { $$ = new_typeFlag(NODE_TASK) ; }
+ | NODE { $$ = new_flagOr(new_flagOr(new_typeFlag(NODE_SUITE),new_typeFlag(NODE_FAMILY)),new_typeFlag(NODE_TASK)); }
+ | EVENT { $$ = new_typeFlag(NODE_EVENT) ; }
+ | LABEL { $$ = new_typeFlag(NODE_LABEL) ; }
+ | METER { $$ = new_typeFlag(NODE_METER) ; }
+ | REPEAT { $$ = new_typeFlag(NODE_REPEAT) ; }
+ | VARIABLE { $$ = new_typeFlag(NODE_VARIABLE) ; }
+ | TRIGGER { $$ = new_typeFlag(NODE_TRIGGER) ; }
+ | ALIAS { $$ = new_typeFlag(NODE_ALIAS) ; }
+ | LIMIT { $$ = new_typeFlag(NODE_LIMIT) ; }
+ | HAS_TRIGGERS { $$ = new_procFlag_node_hasTriggers(); }
+ | HAS_DATE { $$ = new_procFlag_node_hasDate(); }
+ | HAS_TIME { $$ = new_procFlag_node_hasTime(); }
+ | HAS_TEXT { $$ = new_procFlag_node_hasText(); }
+ | IS_ZOMBIE { $$ = new_procFlag_node_isZombie(); }
+ | MIGRATED { $$ = new_procFlag_node_isMigrated(); }
+ | LOCKED { $$ = new_procFlag_node_isLocked(); }
+ | USER { $$ = new_userFlag(0); }
+ | OPER { $$ = new_userFlag(1); }
+ | ADMIN { $$ = new_userFlag(2); }
+ | SELECTION { $$ = new_selectionFlag(); }
+ | '(' flags ')' { $$ = $2; }
+;
+
+flags : flag '|' flags { $$ = new_flagOr($1,$3); }
+ | flag '&' flags { $$ = new_flagAnd($1,$3); }
+ | flag
+ ;
+
+title : STRING { $$ = strdup(yytext); }
+ ;
+
+action : STRING { $$ = menus_command(strdup(yytext)); }
+ | SEPARATOR { $$ = menus_separator(); }
+ | MENU { $$ = menus_sub_menu(); }
+ | WINDOW '(' name ')' { $$ = menus_window($3); }
+ | PLUG { $$ = menus_internal_host_plug(); }
+ | COMP '(' name ',' name ')' { $$ = menus_internal_host_comp($3, $5); }
+ ;
+
+question: STRING { $$ = strdup(yytext); }
+ ;
+
+answer : DEFAULT_YES { $$ = 1; }
+ | DEFAULT_NO { $$ = 0; }
+ ;
+
+/*-------------------------------------------------------------*/
+
+logfile : loglines
+ ;
+
+loglines: logline
+ | loglines logline
+ ;
+
+logline :
+| event number number { if(yyone) return 0; }
+| junk
+| error { /* extern int yylineno; printf("error line %d [%s]\n",yylineno, yytext); */ }
+;
+
+date : '[' number ':' number ':' number number '.' number '.' number ']'
+ {
+ $$.date = ($11 * 10000 + $9 * 100 + $7);
+ $$.time = ($2 * 10000 + $4 * 100 + $6);
+ }
+ ;
+
+event : date COMPLETE node_name { log_event_status_event(&$1,$3,STATUS_COMPLETE); }
+ | date QUEUED node_name { log_event_status_event(&$1,$3,STATUS_QUEUED); }
+ | date ACTIVE node_name { log_event_status_event(&$1,$3,STATUS_ACTIVE); }
+ | date SUBMITTED node_name ANY
+ { log_event_status_event(&$1,$3,STATUS_SUBMITTED); }
+ | date SUBMITTED node_name
+ { log_event_status_event(&$1,$3,STATUS_SUBMITTED); }
+ | date ABORTED node_name { log_event_status_event(&$1,$3,STATUS_ABORTED);}
+ | date UNKNOWN node_name { log_event_status_event(&$1,$3,STATUS_UNKNOWN);}
+ | date SET node_name { log_event_event_event(&$1,$3,1); }
+ | date CLEAR node_name { log_event_event_event(&$1,$3,0); }
+ | date METER '[' node_name number node_name ']' { log_event_meter_event(&$1,$6,$5); }
+;
+
+junk : date JUNK
+ | JUNK
+ ;
+
+node_name : NODE_NAME { $$ = log_event_find(yytext); }
+ ;
+
+number : NUMBER { $$ = atol(yytext); }
+ ;
+
+%%
+
+#include "menul.c"
+
+int yywrap() {
+ return 1;
+}
+
+#ifdef AIX
+int yyerror(char * msg)
+#else
+void yyerror(char * msg)
+#endif
+{
+ /* printf("!menu parsing issue?\n");
+ printf("%s line %d last token <%s>\n",msg,yylineno,yytext); */
+ if (!strncmp("MSG:", yytext, 4)) {}
+ else if (!strncmp("DBG:", yytext, 4)) {}
+ else if (!strncmp("ERR:", yytext, 4)) {}
+ else if (!strncmp("WAR:", yytext, 4)) {}
+ else if (!strncmp("try-no:", yytext, 6)) {}
+ else if (!strncmp("File", yytext, 4)) {}
+ else if (!strncmp("Variable", yytext, 8)) {}
+ else if (!strncmp("Directory", yytext, 9)) {}
+ else if (!strncmp("Search", yytext, 6)) {}
+ else if (*yytext == '[') {}
+ else if (*yytext == ':') {}
+ else if (*yytext == '/') {}
+ else printf("!%s:%d:<%s>\n",msg,yylineno,yytext);
+}
+
diff --git a/view/src/messages.cc b/view/src/messages.cc
new file mode 100644
index 0000000..34da635
--- /dev/null
+++ b/view/src/messages.cc
@@ -0,0 +1,78 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "messages.h"
+#include "node.h"
+#include "host.h"
+#include "selection.h"
+#include "tmp_file.h"
+#include "Hyper.h"
+#include <stdio.h>
+extern "C" {
+#include "xec.h"
+}
+
+messages::messages(panel_window& w)
+ :panel(w)
+ ,text_window(false)
+{
+}
+
+messages::~messages()
+{
+}
+
+void messages::create (Widget parent, char *widget_name )
+{
+ messages_form_c::create(parent,widget_name);
+}
+
+
+void messages::clear()
+{
+ text_window::clear();
+}
+
+struct ml : public lister<ecf_list> {
+ FILE* f_;
+ void next(ecf_list& l) { if (f_) fprintf(f_,"%s\n",l.name().c_str()); }
+public:
+ ml(FILE* f): f_(f) {}
+};
+
+void messages::show(node& n)
+{
+ tmp_file tmp(tmpnam(0));
+ FILE *f = fopen(tmp.c_str(),"w");
+ if(!f) { return; }
+
+ const std::vector<std::string>& l = n.messages();
+ std::vector<std::string>::const_iterator it = l.begin();
+
+ while (it != l.end()) {
+ fprintf(f, "%s\n", it->c_str());
+ ++it;
+ }
+ fclose(f);
+
+ load(tmp);
+}
+
+Boolean messages::enabled(node& n)
+{
+ return n.hasMessages();
+}
+
+// static panel_maker<messages> maker(PANEL_MESSAGES);
diff --git a/view/src/messages.h b/view/src/messages.h
new file mode 100644
index 0000000..e7e7a5b
--- /dev/null
+++ b/view/src/messages.h
@@ -0,0 +1,68 @@
+#ifndef messages_H
+#define messages_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "uimessages.h"
+
+#ifndef panel_H
+#include "panel.h"
+#endif
+
+#ifndef text_window_H
+#include "text_window.h"
+#endif
+
+//
+
+class messages : public panel, public messages_form_c, public text_window {
+public:
+
+ messages(panel_window&);
+
+ ~messages(); // Change to virtual if base class
+
+ virtual const char* name() const { return "Messages"; }
+ virtual void show(node&);
+ virtual void clear();
+ virtual Widget widget() { return messages_form_c::xd_rootwidget(); }
+ virtual Boolean enabled(node&);
+
+ virtual Widget tools() { return tools_; }
+ virtual Widget text() { return text_; }
+ virtual void create (Widget parent, char *widget_name = 0 );
+
+
+
+private:
+
+ messages(const messages&);
+ messages& operator=(const messages&);
+
+ virtual void externalCB(Widget ,XtPointer )
+ { text_window::open_viewer();}
+
+ virtual void searchCB(Widget ,XtPointer )
+ { text_window::open_search();}
+
+ virtual bool can_print() { return true; }
+ virtual bool can_save() { return true; }
+ virtual void print() { text_window::print(); }
+ virtual void save() { text_window::save(); }
+};
+
+inline void destroy(messages**) {}
+#endif
diff --git a/view/src/meter_node.cc b/view/src/meter_node.cc
new file mode 100644
index 0000000..5cabf0f
--- /dev/null
+++ b/view/src/meter_node.cc
@@ -0,0 +1,160 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #22 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "show.h"
+#include "meter_node.h"
+#include "text_lister.h"
+#include "ecf_node.h"
+#include "ecflowview.h"
+#include "NodeAttr.hpp"
+
+#ifdef BRIDGE
+meter_node::meter_node(host& h,sms_node* n, char b)
+ : node (h,n,b)
+ , name_ (n ? n->name : "STEP")
+{}
+#endif
+
+meter_node::meter_node(host& h,ecf_node* n)
+ : node (h,n)
+ , name_ (n ? n->name() : "STEP")
+{
+}
+
+const Meter& meter_node::get() const {
+ ecf_concrete_node<const Meter>* base =
+ dynamic_cast<ecf_concrete_node<const Meter>*> (owner_);
+ if (base) return *(base->get());
+ if (parent() && parent()->__node__())
+ return parent()->__node__()->get_meter(name_);
+ return Meter::EMPTY();
+}
+
+xmstring meter_node::make_label_tree()
+{
+ char buff[80], name[80];
+ snprintf(name,80, " %s: ", name_.c_str());
+ snprintf(buff,80, "%d", value());
+ return xmstring(name,"bold") + xmstring(buff);
+}
+
+void meter_node::drawNode(Widget w,XRectangle* r,bool tree)
+{
+ drawBackground(w,r,tree);
+
+ XmString s = tree?labelTree():labelTrigger();
+ XRectangle x = *r;
+ int width,mark;
+
+ x.x += (x.height - 10)/2;
+ x.height = 10;
+ x.width = 50;
+
+ width = (float)x.width / (float)(maximum() - minimum())
+ * (float)(value() - minimum());
+
+ mark = (float)x.width / (float)(maximum() - minimum())
+ * (float)(threshold() - minimum());
+
+ XFillRectangles(XtDisplay(w),XtWindow(w),colorGC(0),&x,1);
+
+ if (value() > threshold())
+ XFillRectangle(XtDisplay(w),XtWindow(w),gui::colorGC(STATUS_MAX+1),x.x,x.y,width,x.height);
+ else
+ XFillRectangle(XtDisplay(w),XtWindow(w),gui::colorGC(STATUS_MAX),x.x,x.y,width,x.height);
+
+ shadow(w,&x);
+
+ if(mark < width)
+ {
+ x.width = mark;
+ shadow(w,&x);
+ }
+
+ XmStringDraw(XtDisplay(w),XtWindow(w),
+ smallfont(),
+ s,
+ blackGC(),
+ r->x + 52,
+ r->y,
+ r->width - 52,
+ XmALIGNMENT_CENTER, XmSTRING_DIRECTION_L_TO_R, NULL);
+
+ node::update(-1,-1,-1);
+}
+
+void meter_node::sizeNode(Widget w,XRectangle* r,bool tree)
+{
+ XmString s = tree?labelTree():labelTrigger();
+ r->height = XmStringHeight(smallfont(),s);
+ r->width = XmStringWidth(smallfont(),s) + 54 ;
+ if(r->height<10) r->height = 10;
+}
+
+const char* meter_node::status_name() const
+{
+ static char buf[10];
+ sprintf(buf,"%d",value());
+ return buf;
+}
+
+void meter_node::info(std::ostream& f)
+{
+ node::info(f);
+ f << "value : " << value() << "\n";
+ f << "minimum : " << minimum() << "\n";
+ f << "maximum : " << maximum() << "\n";
+ f << "threshold: " << threshold() << "\n";
+}
+
+int meter_node::minimum()
+{
+#ifdef BRIDGE
+ if (tree_) return ((sms_meter*) tree_)->min;
+#endif
+ return get().min();
+}
+
+int meter_node::maximum()
+{
+#ifdef BRIDGE
+ if (tree_) return ((sms_meter*) tree_)->max;
+#endif
+ return get().max();
+}
+
+int meter_node::value() const
+{
+#ifdef BRIDGE
+ if (tree_) return ((sms_meter*) tree_)-> status;
+#endif
+ return get().value();
+}
+
+int meter_node::threshold()
+{
+#ifdef BRIDGE
+ if (tree_) return ((sms_meter*) tree_)->color;
+#endif
+ return get().colorChange();
+}
+
+void meter_node::perlify(FILE* f)
+{
+}
+
+Boolean meter_node::visible() const { return show::want(show::meter); }
+
+
diff --git a/view/src/meter_node.h b/view/src/meter_node.h
new file mode 100644
index 0000000..f5a4cf9
--- /dev/null
+++ b/view/src/meter_node.h
@@ -0,0 +1,59 @@
+#ifndef meter_node_H
+#define meter_node_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #11 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#ifndef node_H
+#include "node.h"
+#endif
+
+
+class meter_node : public node {
+public:
+
+ const std::string name_;
+ meter_node(host& h,ecf_node* n);
+#ifdef BRIDGE
+ meter_node(host& h,sms_node* n, char b);
+#endif
+ int minimum();
+ int maximum();
+ int value() const;
+ int threshold();
+
+protected:
+
+ virtual void perlify(FILE*);
+
+private:
+
+ meter_node(const meter_node&);
+ meter_node& operator=(const meter_node&);
+
+ virtual void info(std::ostream&);
+ virtual void drawNode(Widget w,XRectangle* r,bool);
+ virtual void sizeNode(Widget w,XRectangle* r,bool);
+ virtual xmstring make_label_tree();
+
+ virtual Boolean visible() const;
+ virtual const char* status_name() const;
+
+ const Meter& get() const;
+};
+
+inline void destroy(meter_node**) {}
+
+#endif
diff --git a/view/src/node.cc b/view/src/node.cc
new file mode 100644
index 0000000..319bdd4
--- /dev/null
+++ b/view/src/node.cc
@@ -0,0 +1,1089 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #49 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "node.h"
+#include "gui.h"
+#include <Xm/ManagerP.h>
+#include <Xm/DrawP.h>
+#include <algorithm>
+#include <typeinfo>
+#include <Flag.hpp>
+
+#ifndef node_lister_H
+#include "node_lister.h"
+#endif
+
+#include "dummy_node.h"
+#include "variable_node.h"
+
+#ifndef ecf_node_
+#include "ecf_node.h"
+#endif
+
+#ifndef globals_H
+#include "globals.h"
+#endif
+
+#ifndef host_H
+#include "host.h"
+#endif
+
+#include "trigger_lister.h"
+#include "selection.h"
+#include "substitute.h"
+#include "relation.h"
+#include "str.h"
+#include "option.h"
+#include "array.h"
+#include <Suite.hpp>
+
+class node_data {
+
+ xmstring labelTrigger_;
+ array<node*> triggered_;
+ array<node*> triggers_;
+ array<node_info*> info_;
+
+public:
+ node_data();
+ ~node_data();
+
+ const xmstring& labelTrigger() { return labelTrigger_; }
+ void labelTrigger(const xmstring&);
+
+ void add_triggered(node*,node*);
+ void triggered(trigger_lister&);
+
+ void add(node_info*);
+ void remove(node_info*);
+ void remove(const str& s) { remove(get(s)); }
+ node_info* get(const str&);
+};
+
+
+node_data::node_data():
+ labelTrigger_()
+{
+}
+
+node_data::~node_data()
+{
+ labelTrigger(xmstring());
+ for(int i = 0; i < info_.count(); i++)
+ delete info_[i];
+}
+
+void node_data::add(node_info* n)
+{
+ for(int i = 0; i < info_.count(); i++)
+ {
+ if(info_[i]->name() == n->name())
+ {
+ delete info_[i];
+ info_[i] = n;
+ return;
+ }
+ }
+ info_.add(n);
+}
+
+void node_data::remove(node_info *n)
+{
+ info_.remove(n);
+}
+
+node_info* node_data::get(const str& s)
+{
+ for(int i = 0; i < info_.count(); i++)
+ if(info_[i]->name() == s)
+ return info_[i];
+ return 0;
+}
+
+
+void node_data::labelTrigger(const xmstring& s)
+{
+ labelTrigger_ = s;
+}
+
+void node_data::add_triggered(node* n,node* t)
+{
+ triggered_.add(n);
+ triggers_.add(t);
+}
+
+void node_data::triggered(trigger_lister& l)
+{
+ for(int i = 0; i < triggered_.count(); i++)
+ l.next_node(*triggered_[i],0,trigger_lister::normal,triggers_[i]);
+}
+
+int node::status() const
+{
+#ifdef BRIDGE
+ if (tree_) return tree_->status;
+#endif
+ return owner_ ? owner_->status() : STATUS_UNKNOWN;
+}
+
+node_data* node::get_node_data()
+{
+ if(data_ == 0)
+ data_ = new node_data();
+ return data_;
+}
+
+template<class T>
+inline node* _node_of(T* n)
+{
+ return n ? n->xnode() : 0x0;
+}
+
+node::node(host& h,ecf_node* owner)
+ :
+ xnode(this)
+ ,type_(owner ? owner->type() : NODE_UNKNOWN)
+ ,tree_(0) // BRIDGE
+ ,next_(0)
+ ,kids_(0)
+ ,owner_(owner)
+ ,host_(h)
+ ,folded_(True)
+ ,labelTree_()
+ ,helper_(0)
+ ,data_(0)
+ ,triggered_(false)
+{
+}
+
+node::~node()
+{
+ // std::cerr << "# node del: " << full_name() << std::endl;
+ if (data_) delete data_;
+ data_ = 0x0;
+}
+
+void node::reset()
+{
+ if(data_)
+ data_->labelTrigger(xmstring());
+
+ labelTree_ = xmstring();
+
+ if(kids_) kids_->reset();
+ if(next_) next_->reset();
+
+ redraw();
+}
+
+void node::scan(node* first,node *current)
+{
+ node *n = current;
+ if (n)
+ if(n && n->name() != name()) {
+ n = first;
+ while(n && n->name() != name()) {
+ n = n->next_;
+ }
+ }
+
+ if(n) {
+ adopt(n);
+ if(kids_)
+ kids_->scan(n->kids_,n->kids_);
+ } else {
+ create();
+ if(kids_)
+ kids_->scan(0,0);
+ }
+
+ if(next_)
+ next_->scan(first,n);
+}
+
+void node::adopt(node* old)
+{
+ folded_ = old->folded_;
+ old->notify_adoption(this);
+ notify_observers();
+}
+
+void node::create()
+{
+}
+
+#ifdef BRIDGE
+node_builder* node_builder::builders_[NODE_MAX] = { 0, };
+
+node* node::find(sms_node* n)
+{ return (node*) (n ? n->user_ptr : 0x0); }
+
+node::node(host& h,sms_node* owner,char b)
+ : xnode(this)
+ , type_(owner ? owner->type : NODE_UNKNOWN)
+ , name_ (owner->name ? owner->name : "/")
+ , full_name_ (sms_node_full_name(owner))
+ , tree_(owner)
+ , next_(0)
+ , kids_(0)
+ , owner_(new ecf_concrete_node<node>((int)0, 0))
+ , host_(h)
+ , folded_(True)
+ , labelTree_()
+ , helper_(0)
+ , data_(0)
+ , triggered_(false)
+{
+ if (owner) {
+ // if (owner->name) name_ = owner->name;
+ kids_ = node::create(h,owner->kids,b);
+ next_ = node::create(h,owner->next,b);
+ owner->user_ptr = this;
+ }
+}
+
+node* node_builder::build(host& h,sms_node* n,char b)
+{
+ if(n->type >= 0 &&
+ n->type < NODE_MAX && builders_[n->type] != 0) {
+ if (builders_[n->type] != 0x0)
+ return builders_[n->type]->make(h,n,b);
+ else
+ std::cerr << "unregistered type " << n->type << "\n";
+ }
+ return 0;
+}
+
+node* node::create(host& h, sms_node* n, char b)
+{
+ if(!n) return 0x0;
+ node* p = node_builder::build(h,n,b);
+ return p?p:node::create(h,n->next,b);
+}
+
+void node::schanged(sms_node *n,int oldstatus,int oldtryno,int oldflags,void*)
+{
+ node* p = 0x0;
+ if (n) p = (node*) n->user_ptr;
+ if(p) {
+ try {
+ p->update(oldstatus,oldtryno,oldflags);
+ p->notify_observers();
+ p->redraw();
+ } catch (...) {
+ printf(" exception in node::changed\n");
+ }
+ } else {
+ if (n->type >= NODE_MAX) return;
+ printf("# Got NID for %s",::ecf_node_name(n->type));
+ // while(n) {printf("# %s",n->full_name().c_str()); n = n->parent; }
+ printf("# --- \n");
+ }
+}
+
+#endif
+
+void node::destroy(node* n)
+{
+ while(n) {
+ Widget w = n->widget();
+ node* next = n->next_;
+ CompositeWidget c = (CompositeWidget)w;
+ if (c) XtUnmanageChildren(c->composite.children,
+ c->composite.num_children);
+
+ destroy(n->kids_);
+ n->kids_ = 0x0;
+ if (n->owner_)
+ n->owner_->adopt(0x0);
+
+ delete n;
+ n = next;
+ }
+ // n = 0x0;
+}
+
+void node::drawBackground(Widget w,XRectangle* r,bool tree)
+{
+ if(!tree)
+ XClearArea(XtDisplay(w),XtWindow(w),
+ r->x,r->y,r->width,r->height,False);
+}
+
+void node::drawNode(Widget w,XRectangle* r,bool tree)
+{
+ drawBackground(w,r,tree);
+
+ XmString s = tree ? labelTree() : labelTrigger();
+ XmFontList f = smallfont();
+
+ XmStringDraw(XtDisplay(w),XtWindow(w),
+ f,
+ s,
+ blackGC(),
+ r->x,
+ r->y+2,
+ r->width,
+ XmALIGNMENT_CENTER, XmSTRING_DIRECTION_L_TO_R, r);
+}
+
+void node::sizeNode(Widget w,XRectangle* r,bool tree)
+{
+ XmString s = tree ? labelTree() : labelTrigger();
+ XmFontList f = smallfont();
+ r->width = XmStringWidth(f,s) + 4;
+ r->height = XmStringHeight(f,s) + 4;
+}
+
+void node::shadow(Widget w,XRectangle *r,bool out)
+{
+ XmManagerWidget m = (XmManagerWidget)w;
+ _XmDrawShadows(XtDisplay(w),XtWindow(w),
+ m->manager.top_shadow_GC,
+ m->manager.bottom_shadow_GC,
+ r->x,
+ r->y,
+ r->width,
+ r->height,
+ 1,out?XmSHADOW_OUT:XmSHADOW_IN);
+}
+
+
+const xmstring& node::labelTree()
+{
+ if(labelTree_ == 0)
+ labelTree_ = make_label_tree();
+ return labelTree_;
+}
+
+xmstring node::make_label_tree()
+{
+ return xmstring(name().c_str());
+}
+
+const xmstring& node::labelTrigger()
+{
+ node_data* d = get_node_data();
+ if(d->labelTrigger() == 0)
+ d->labelTrigger(make_label_trigger());
+ return d->labelTrigger();
+}
+
+xmstring node::make_label_trigger()
+{
+ return xmstring(full_name().c_str());
+}
+
+void node::append(node* n)
+{
+ if (!n) return;
+ node *k = kids_;
+ node *p = 0;
+ while(k) {
+ p = k;
+ k = k->next_;
+ }
+ if(p) p->next_ = n;
+ else kids_ = n;
+}
+
+void node::insert(node* n)
+{
+ if (!n) return;
+ node* k = kids_; kids_ = n; append(k);
+}
+
+void node::changed(ecf_node *n,int oldstatus,int oldtryno,int oldflags,void*)
+{
+ node* p = _node_of(n);
+ if (!n) return;
+ if(p) {
+ try {
+ p->update(oldstatus,oldtryno,oldflags);
+ p->notify_observers();
+ p->redraw();
+ } catch (...) { printf(" exception in node::changed\n"); }
+ } else {
+#ifdef BRIDGE
+ if (n->type() >= NODE_MAX) return;
+ printf("# Got NID for %s",::ecf_node_name(n->type()));
+ while(n) {
+ printf("# %s",n->full_name().c_str());
+ n = n->parent();
+ }
+ printf("# --- \n");
+#endif
+ }
+}
+
+void node::update(int,int,int)
+{
+ labelTree_ = xmstring();
+ if(data_) data_->labelTrigger(xmstring());
+}
+
+Boolean node::visible() const
+{
+ return True;
+}
+
+int node::type() const {
+ return type_;
+}
+
+Boolean node::show_it() const
+{
+ return this == selection::current_node();
+}
+
+const std::string& node::name() const
+{
+#ifdef BRIDGE
+ if (tree_) { return name_; }
+#endif
+ if (owner_)
+ return owner_->name();
+ return ecf_node::no_owner();
+}
+
+const std::string& node::full_name() const
+{
+#ifdef BRIDGE
+ if (tree_) { return full_name_; }
+#endif
+ if (owner_)
+ return owner_->full_name();
+ return ecf_node::no_owner();
+}
+
+const std::string& node::net_name() const
+{
+#ifdef BRIDGE
+ if (tree_) { static std::string fn = sms_node_full_name(tree_); return fn; }
+#endif
+ if (owner_)
+ return owner_->full_name();
+ return ecf_node::no_owner();
+}
+
+Pixel node::color() const
+{
+ return colors(STATUS_UNKNOWN);
+}
+
+
+void node::search(node_lister& s)
+{
+ node *n = this;
+ while(n) {
+ s.next(*n);
+ node* k = n->kids();
+ if(k) k->search(s);
+ n = n->next();
+ }
+}
+
+std::string node::variable(const std::string& name, bool substitute)
+{
+ for (node* run = kids(); run; run = run->next())
+ if (run->type() == NODE_VARIABLE && run->name() == name) {
+ return ((variable_node*) run)->get_var(substitute);
+ }
+
+ return ecf_node::none();
+}
+
+node* node::find(ecf_node* n)
+{
+ return _node_of(n);
+}
+
+static node* finder(const std::string& name, const node* start) {
+ node *n = const_cast<node*> (start);
+ while (n) {
+ if (n->type() == NODE_TRIGGER || n->type() == NODE_COMPLETE) {
+ if (n->definition() == name)
+ return n;
+ else if (n->__node__()->name() == name)
+ return n;
+ else if (n->__node__()->toString() == name)
+ return n;
+ ecf_node *owner = n->__node__();
+ if (owner) {
+ ExpressionWrapper *exp = dynamic_cast<ecf_concrete_node<ExpressionWrapper>*> (owner)
+ ->get();
+ if (exp && exp->expression() == name)
+ return n;
+ }
+ }
+ node *k = 0;
+ if ((k = finder(name, n->kids())))
+ return k;
+ n = n->next();
+ }
+ return 0;
+}
+
+node* node::find_trigger(const std::string& name) const
+{
+ node* k = finder(name, this);
+ return k ? k : &dummy_node::get(name);
+}
+
+node* node::find_limit(const std::string& path, const std::string& name)
+{
+ node *f = this;
+ // if (!strncmp("/", path.c_str(), 1))
+ if (!path.empty() && path[0] == '/')
+ if (! (f = serv().top()->find(path)))
+ return &dummy_node::get(path + ":" + name);
+
+ for (node *n = f->kids(); n != 0; n = n->next()) {
+ if (n->type() == NODE_LIMIT && n->name() == name)
+ return n;
+ }
+
+ for (node *p = f->parent()->kids(); p != 0; p = p->next()) {
+ if (p->type() == NODE_FAMILY || p->type() == NODE_TASK || p->type() == NODE_SUITE)
+ if (p->name() == path.substr(0, p->name().size())) {
+ std::string::size_type next = path.find('/');
+ if (next != std::string::npos)
+ return p->find_limit(path.substr(next+1, path.size()), name);
+ }
+ }
+
+ return &dummy_node::get(path + ":" + name);
+}
+
+// Trigger proccessing
+
+struct triggered_lister : public trigger_lister {
+ node* n_;
+public:
+ triggered_lister(node* n) : n_(n) {}
+
+ void next_node(node& n,node*,int,node* t)
+ { n.add_triggered(n_,t); }
+};
+
+void node::add_triggered(node* n,node* t)
+{
+ if(data_ == 0) data_ = new node_data();
+ data_->add_triggered(n,t);
+}
+
+void node::gather_triggered(node* p)
+{
+ while(p) {
+ triggered_lister tl(p);
+ p->triggers(tl);
+ p->triggered_ = true;
+ gather_triggered(p->kids());
+ p = p->next();
+ }
+}
+
+struct kids_triggered_lister : public trigger_lister {
+ trigger_lister& l_;
+ node* k_;
+ node* n_;
+public:
+ kids_triggered_lister(node *n, node* k,trigger_lister& l):
+ l_(l), k_(k), n_(n) {}
+
+ void next_node(node& n,node* p,int,node* t) {
+ if(!n.is_my_parent(n_))
+ l_.next_node(n,k_,trigger_lister::child,t);
+ }
+};
+
+static void triggered_by_kids(node* n,node *k,trigger_lister& l)
+{
+ while(k) {
+ kids_triggered_lister ktl(n,k,l);
+ k->triggered(ktl);
+ triggered_by_kids(n,k->kids(),l);
+ k = k->next();
+ }
+}
+
+struct parent_triggered_lister : public trigger_lister {
+ node* n_;
+ node* p_;
+ trigger_lister& l_;
+public:
+ parent_triggered_lister(node *n, node* p,trigger_lister& l):
+ n_(n), p_(p), l_(l) {}
+
+ void next_node(node& n,node* p,int,node* t) {
+ l_.next_node(n,p_,trigger_lister::parent,t);
+ }
+};
+
+static void triggered_by_parent(node* n,node *p,trigger_lister& l)
+{
+ while(p) {
+ parent_triggered_lister ptl(n,p,l);
+ p->triggered(ptl);
+ p = p->parent();
+ }
+}
+
+void node::triggered(trigger_lister& l)
+{
+ if(!triggered_) // Scan all tree
+ gather_triggered(serv().top());
+
+ if(data_) data_->triggered(l);
+
+ if(l.kids()) triggered_by_kids(this,kids(),l);
+ if(l.parents()) triggered_by_parent(this,parent(),l);
+}
+
+void node::triggers(trigger_lister&)
+{
+}
+
+//============================================================
+
+const std::vector<std::string>& node::messages() const
+{
+#ifdef BRIDGE
+ if (tree_) return serv().messages(*this);
+#endif
+ return serv().messages(*this);
+}
+
+//============================================================
+node* node_find(node* n, std::string path) {
+ std::string::size_type pos = path.find("/");
+ std::string::size_type beg = 0;
+ if (!n) return n;
+ while (path[beg] == '/') ++beg;
+ node *kid = n->kids();
+ while (kid) {
+ if (kid->type() != NODE_SUITE &&
+ kid->type() != NODE_FAMILY &&
+ kid->type() != NODE_TASK ) {kid = kid->next(); continue;}
+ if (kid->name() == path.substr(beg, pos-beg)) {
+ if (pos == std::string::npos)
+ return kid;
+ else
+ return node_find(kid, path.substr(pos));
+ }
+ kid = kid->next();
+ }
+ return kid;
+}
+
+node* node::find(const std::string name)
+{
+ node * top = 0x0;
+ node_ptr ptr;
+ std::string::size_type pos = name.find(":");
+ if (pos == std::string::npos) { // not an attribute
+ ecf_concrete_node<Defs> * ecfn = 0x0;
+ if (0x0 != (top = serv().top())) {
+ ecfn = dynamic_cast<ecf_concrete_node<Defs>*>(top->__node__());
+ if (0x0 != ecfn) // ok with a node, NOK with attribute
+ try {
+ if (const_cast<Defs*>(ecfn->get()))
+ ptr = const_cast<Defs*>(ecfn->get())->findAbsNode(name);
+ } catch (...) {
+ fprintf(stderr, "exception with node.cc:find %s\n", name.c_str());
+ }
+ }
+ } else {
+ const char* fname = full_name().c_str();
+ size_t len1 = name.size(), len2 = strlen(fname);
+ if (len1==len2 && !strcmp(name.c_str(), fname)) return this;
+ if (len2 < len1 && !strncmp(name.c_str(), fname, len2)
+ && kids_) return kids_->find(name);
+ if (next_) return next_->find(name);
+ return 0x0;
+ }
+ if (0x0 != ptr.get()) {
+ return (node*) ptr.get()->graphic_ptr();
+ }
+ else if (name == "/")
+ return serv().top();
+
+ return node_find(serv().top(), name);
+ /* if (item == 0x0)
+ std::cout << "# not found:" << name << "\n";
+ return item; */
+}
+
+//============================================================
+
+node* node::parent() const
+{
+#ifdef BRIDGE
+ if (tree_) if (tree_->parent) return (node*) tree_->parent->user_ptr;
+#endif
+ if (owner_) {
+ ecf_node *p = owner_->parent();
+ return p ? p->xnode() : 0x0;
+ }
+ return 0x0;
+}
+
+const char* node::type_name() const
+{
+
+ return ecf_node_name(type());
+}
+
+const char* node::status_name() const
+{
+ return "??";
+}
+
+//============================================================
+
+node* node::variableOwner(const char *name)
+{
+ std::vector<Variable>::const_iterator it;
+ node *m = this;
+ while(m) {
+ { std::vector<Variable> var; m->variables(var);
+ for (it = var.begin(); it != var.end(); ++it)
+ if (it->name() == name) return m;
+ }
+ { std::vector<Variable> var; m->genvars(var);
+ for (it = var.begin(); it != var.end(); ++it)
+ if (it->name() == name) return m;
+ }
+ m = m->parent();
+ }
+ return 0;
+}
+
+Boolean node::isGenVariable(const char *name) { return False; }
+
+void node::folded(Boolean f)
+{
+ if(f) {
+ folded_ = false;
+ node *k = kids_;
+ while(k) {
+ if(k->visible() || k->show_it()) {
+ folded_ = true;
+ break;
+ }
+ k = k->next();
+ }
+ } else
+ folded_ = f;
+
+ redraw();
+}
+
+void node::why(std::ostream&)
+{
+}
+
+bool node::evaluate() const
+{
+ return false;
+}
+
+void node::tell_me_why(std::ostream&)
+{
+}
+
+void node::suspended(std::ostream&)
+{
+}
+
+void node::aborted(std::ostream&)
+{
+}
+
+void node::queued(std::ostream&)
+{
+}
+
+bool node::is_my_parent(node* p) const
+{
+ const node* n = this;
+ while(n) {
+ if(n == p)
+ return true;
+ n = n->parent();
+ }
+ return false;
+}
+
+#include <boost/date_time/posix_time/posix_time.hpp>
+void node::info(std::ostream& f)
+{
+ using namespace boost::posix_time;
+ using namespace boost::gregorian;
+
+ f << "name : " << name() << "\n";
+ f << "type : " << type_name() << "\n";
+ f << "status : " << status_name() << "\n";
+
+ if (owner_) {
+ // if (owner_->type() == NODE_TASKtas )
+ {
+ boost::posix_time::ptime state_change_time = owner_->status_time();
+ if (!state_change_time.is_special()) {
+ f << "at : " << to_simple_string(state_change_time) << "\n"; // https://software.ecmwf.int/issues/browse/SUP-649
+ }
+ }
+ }
+ f << "----------\n";
+ // 1234567890
+}
+
+const std::string node::toString() const
+{
+#ifdef BRIDGE
+ if (tree_) { return sms_node_full_name(tree_); }
+#endif
+ if (owner_) return owner_->toString();
+ return ecf_node::none();
+}
+
+node* node::find_match(const char* p)
+{
+ if (p == NULL) return 0;
+ const char* found = find_name(p);
+ if (found == NULL) return 0;
+ return find(found);
+}
+
+const char* node::find_name(const char* p)
+{
+ static char name[1024];
+ strcpy(name,p);
+
+ char *q = name;
+
+ while(*q && *q != '/') q++;
+ if(*q) {
+ char* r = q;
+ while(*q && *q != ' ' && *q != '\t') q++;
+ *q = 0;
+ return r;
+ }
+ return 0;
+}
+
+time_t node::suite_time()
+{
+ node *xnode = this;
+ while(xnode) {
+ if(xnode->type() == NODE_SUITE)
+ return 0; // FILL
+ xnode = xnode->parent();
+ }
+ return 0;
+}
+
+bool node::match(const char* n)
+{
+ return strstr(name().c_str(),n) != 0;
+}
+
+void node::command(const char* cmd)
+{
+ serv().command(substitute(cmd));
+}
+
+std::string node::substitute(const char* cmd)
+{
+ try {
+ return substitute::scan(cmd,this);
+ } catch ( std::exception& e ) {
+ return cmd;
+ }
+
+}
+
+void node::edit(node_editor&)
+{
+}
+
+void node::apply(node_editor&)
+{
+}
+
+node_info* node::get_node_info(const str& s)
+{
+ return data_?data_->get(s):0;
+}
+
+void node::add_node_info(node_info* n)
+{
+ get_node_data()->add(n);
+}
+
+void node::remove_node_info(node_info* n)
+{
+ if(data_) data_->remove(n);
+}
+
+void node::remove_node_info(const str& n)
+{
+ if(data_) data_->remove(n);
+}
+
+const char* node::html_page(url& u)
+{
+ return "node.html";
+}
+
+void node::html_name(FILE* f,url& u)
+{
+ fprintf(f,"<a href=\"%s\">%s</a>",net_name().c_str()+1,name().c_str());
+}
+
+void node::html_title(FILE* f,url& u)
+{
+ if(parent()) parent()->html_title(f,u);
+ fprintf(f,"/<a href=\"%s\">%s</a>",net_name().c_str()+1,name().c_str());
+}
+
+bool node::is_json = false; // set by url.cc
+void node::as_perl(FILE* f,bool full)
+{
+ if (node::is_json) {
+ fprintf(f,"{\n");
+ } else
+ fprintf(f,"bless({\n");
+
+ perl_member(f,"name",name());
+ perl_member(f,"full", full_name());
+ perl_member(f,"status", status());
+ perl_member(f,"status_name", status_name());
+
+ if(full) perlify(f);
+
+ if (node::is_json) {
+ fprintf(f,"\"class\": \"%s\" }", perl_class());
+ } else fprintf(f,"},'ecf::node::%s')",perl_class());
+}
+
+void node::perl_member(FILE* f,const char* p,const char* v)
+{
+ if(v) {
+ if (node::is_json) {
+ unsigned int i = 0; char *c; char bak[1024]; strncpy(bak, v, 1024);
+ for (c = bak; i<strlen(v) && i<1024; c++, i++) {
+ if (*c == '"') *c = '\'';
+ }
+ fprintf(f,"\"%s\": \"%s\",\n",p,bak); } else
+ fprintf(f,"%s=>'%s',\n",p,v);
+ }
+}
+
+void node::perl_member(FILE* f,const std::string& p,const std::string&v)
+{
+ perl_member(f, p.c_str(), v.c_str()); /*
+ if (node::is_json) {
+ std::string bak = v;
+ for (unsigned int i=0; i<bak.size(); i++) {
+ if (bak[i] == '"') bak[i] = '\'';
+ }
+ fprintf(f,"\"%s\": \"%s\",\n",p.c_str(),bak.c_str()); } else
+ { fprintf(f,"%s=>%s,\n",p.c_str(),v.c_str()); } */
+}
+
+void node::perl_member(FILE* f,const char * p, int v)
+{
+ if (node::is_json) fprintf(f,"\"%s\": \"%d\",\n",p,v); else
+ fprintf(f,"%s=>%d,\n",p,v);
+}
+
+void node::perl_member(FILE* f,const char* p,ecf_list* v)
+{
+ if (node::is_json) {
+ fprintf(f,"\"%s\": [\n",p);
+ while(v) {
+ fprintf(f,"'name': '%s',\n",v->name().c_str());
+ v = v->next;
+ }
+ fprintf(f,"\n],\n");
+ return; }
+
+ fprintf(f,"%s=>[\n",p);
+ while(v) {
+ fprintf(f,"'%s',",v->name().c_str());
+ v = v->next;
+ }
+ fprintf(f,"\n],\n");
+}
+
+static proc_substitute s_full_name("<full_name>",&node::full_name);
+static proc_substitute s_node_name("<node_name>",&node::node_name);
+static proc_substitute s_parent_name("<parent_name>",&node::parent_name);
+
+void node::check() {
+ if (__node__() == 0x0)
+ std::cerr << "# node: no owner: " << name() << "\n";
+ if (parent() == 0x0)
+ std::cerr << "# node: no parent: " << name() << "\n";
+ node *n;
+ for(n = kids(); n; n = n->next())
+ { n->check(); }
+ if ((n = next())) n->check();
+}
+
+bool node::ondemand(bool full)
+{
+ // ecf_node *ec = owner_;
+ // if (0 == ec) return false;
+ // else if (0 != kids()) return false; // gen variables at least
+ // printf("demanding\n");
+ // ec->make_subtree(); node *xnode = ec->create_tree(serv()); ec->adopt(xnode);
+ // serv().redraw();
+ return false;
+}
+
+const std::string& node::parent_name() const
+{
+ if (parent())
+ return parent()->full_name();
+ return ecf_node::none();
+}
+
+void node::delvars() {
+}
+
+void node::unlink(bool detach) {
+ if (__node__()) __node__()->unlink(detach);
+ for (node *run = kids(); run; run = run->next())
+ { run->unlink(detach); }
+}
+
+void node::remove() {
+ node *top = parent();
+ if (!top) return;
+ node *run = top->kids_;
+
+ if (run == this) {
+ top->kids_ = this->next_;
+ } else
+ while (run) {
+ if (run->next_ == this) {
+ run->next_ = this->next_;
+ break;
+ }
+ run = run->next_;
+ }
+}
diff --git a/view/src/node.h b/view/src/node.h
new file mode 100644
index 0000000..66f4539
--- /dev/null
+++ b/view/src/node.h
@@ -0,0 +1,350 @@
+#ifndef node_H
+#define node_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #33 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "ecflowview.h"
+
+class host;
+class node;
+class trigger_lister;
+class node_lister;
+class node_editor;
+class node_data;
+class ostream;
+class url;
+#include "ecf_node.h" // class ecf_node;
+
+#ifndef xnode_H
+#include "xnode.h"
+#endif
+
+#ifndef observable_H
+#include "observable.h"
+#endif
+
+#ifndef gui_H
+#include "gui.h"
+#endif
+
+#ifndef str_H
+#include "str.h"
+#endif
+
+#ifndef xmstring_H
+#include "xmstring.h"
+#endif
+
+#ifdef BRIDGE
+extern "C" {
+#define new _new
+#define delete _delete
+#undef NODE_MAX
+#include "sms.h"
+#include "smsproto.h"
+#undef new
+#undef delete
+}
+#endif
+
+template<class T>
+class lister;
+
+class node_info {
+public:
+ virtual ~node_info() {}
+ virtual const str& name() = 0;
+};
+
+class node : public observable, public xnode {
+ friend class ecf_node;
+ friend class tree;
+ int type_;
+public:
+
+ static bool is_json;
+
+ void scan(node* n) { scan(n,n); }
+
+ virtual void update(int,int,int);
+ void remove();
+
+ node* next() const { return next_; }
+ node* kids() const { return kids_; }
+ host& serv() const { return host_; }
+
+ virtual node* parent() const;
+
+ virtual Boolean visible() const;
+ virtual Boolean show_it() const;
+ virtual Boolean visible_kid() const { return false; }
+
+ virtual Boolean menus() { return True; }
+ virtual Boolean selectable() { return True; }
+
+ virtual const std::string& name() const;
+ virtual const std::string& full_name() const;
+ virtual const std::string& node_name() const { return name(); }
+ virtual const std::string& net_name() const;
+ virtual const std::string& parent_name() const;
+ virtual const std::string& definition() const { return full_name(); }
+
+ virtual void adopt(node*);
+ virtual void create();
+
+#ifdef BRIDGE
+ const std::string name_;
+ const std::string full_name_;
+ static node* create(host&h,sms_node* n,char = 0);
+ static void schanged(sms_node*,int,int,int,void*);
+ static node* find(sms_node*);
+
+ protected:
+ node(host& h,sms_node* owner, char b);
+ sms_node
+#else
+ protected:
+ void
+#endif
+ *tree_;
+ public:
+ virtual void reset();
+ void delvars();
+
+ virtual void search(node_lister&);
+ virtual void info(std::ostream&);
+ virtual const std::string toString() const;
+ virtual std::string substitute(const char*);
+ virtual void command(const char*);
+
+ virtual void tell_me_why(std::ostream&);
+ virtual void why(std::ostream&);
+ virtual bool evaluate() const;
+ virtual void suspended(std::ostream&);
+ virtual void aborted(std::ostream&);
+ virtual void queued(std::ostream&);
+
+ virtual void triggers(trigger_lister&);
+ virtual void triggered(trigger_lister&);
+
+ Boolean folded() { return folded_; }
+ virtual void folded(Boolean f);
+
+ virtual Boolean ecfFlag(int) const { return False; }
+
+ virtual void genvars(std::vector<Variable>&) {};
+ virtual void variables(std::vector<Variable>&) {};
+
+ virtual const char* type_name() const;
+ virtual const char* status_name() const;
+
+ void insert(node*);
+
+ virtual int type() const;
+ virtual int status() const;
+ virtual boost::posix_time::ptime status_time() const
+ { return boost::posix_time::ptime(); }
+
+ virtual int tryno() const { return 0; }
+ virtual int flags() const { return 0; }
+ const std::vector<std::string>& messages() const;
+
+ virtual Boolean isSimpleNode()const { return False; }
+ virtual Boolean hasTriggers() const { return False; }
+ virtual Boolean hasDate() const { return False; }
+ virtual Boolean hasTime() const { return False; }
+
+ virtual Boolean hasTimeHolding() const { return False; }
+
+ virtual Boolean hasManual() const { return False; }
+ virtual Boolean hasInfo() const { return True; }
+ virtual Boolean isMigrated() const { return False; }
+ virtual Boolean isLate() const { return False; }
+ virtual Boolean isWaiting() const { return False; }
+ virtual Boolean hasMessages() const { return False; }
+ virtual Boolean isTimeDependent() const { return False; }
+ virtual Boolean isRerun() const { return False; }
+ virtual Boolean isLocked() const { return False; }
+
+ virtual Boolean isDefComplete() const { return False; }
+ virtual Boolean isZombie() const { return False; }
+ virtual Boolean hasZombieAttr() const { return False; }
+ virtual Boolean isToBeChecked() const { return False; }
+ virtual Boolean hasText() const { return False; }
+
+ virtual Boolean isForceAbort() const { return False; }
+ virtual Boolean isUserEdit() const { return False; }
+ virtual Boolean isTaskAbort() const { return False; }
+ virtual Boolean isEditFailed() const { return False; }
+ virtual Boolean isCmdFailed() const { return False; }
+ virtual Boolean isScriptMissing() const { return False; }
+ virtual Boolean isKilled() const { return False; }
+ virtual Boolean isByRule() const { return False; }
+ virtual Boolean isQueueLimit() const { return False; }
+
+ Boolean isFolded() const { return folded_; }
+
+ virtual void active(bool) {}
+ virtual void up_to_date() {}
+
+ virtual bool trigger_kids() const { return false; }
+ virtual bool trigger_parent() const { return false; }
+ virtual bool show_in_dependancies() const { return false; }
+ virtual void add_triggered(node*,node*);
+ void unlink(bool detach=true);
+
+ void check();
+// ---------------------------
+
+ time_t suite_time();
+ node* find_trigger(const std::string& name) const;
+ node* find_limit(const std::string& path, const std::string& name);
+ node* find(const std::string n);
+ static const char* find_name(const char* name);
+ node* find_match(const char* name);
+
+// ---------------------------
+
+ virtual Pixel color() const;
+
+ virtual void drawNode(Widget,XRectangle*,bool);
+ virtual void sizeNode(Widget,XRectangle*,bool);
+ virtual void drawBackground(Widget,XRectangle*,bool);
+
+// ---------------
+
+ virtual void edit(node_editor&);
+ virtual void apply(node_editor&);
+
+// ---------------
+
+ virtual std::string variable(const std::string&, bool substitute=false);
+ virtual node* variableOwner(const char*);
+ virtual Boolean isGenVariable(const char*);
+
+ virtual bool is_my_parent(node*) const;
+
+ virtual bool match(const char*);
+
+ virtual node* graph_node() { return this; }
+
+// ----------------
+
+ virtual bool show_in_html(url&) { return false; }
+
+ virtual const char* html_page(url&);
+
+ virtual void html_name(FILE*,url&);
+ virtual void html_title(FILE*,url&);
+
+ virtual void html_why(FILE*,url&) {}
+ virtual void html_output(FILE*,url&) {}
+ virtual void html_manual(FILE*,url&) {}
+ virtual void html_script(FILE*,url&) {}
+ virtual void html_job(FILE*,url&) {}
+ virtual void html_jobstatus(FILE*,url&) {}
+ virtual void html_kids(FILE*,url&) {}
+ virtual void html_variables(FILE*,url&) {}
+
+ // ------------------------------
+ virtual void as_perl(FILE*,bool);
+ virtual void perlify(FILE*) = 0;
+ virtual const char* perl_class() { return type_name(); }
+
+ void perl_member(FILE*,const char*,const char*);
+ void perl_member(FILE*,const std::string&,const std::string&);
+ void perl_member(FILE*,const char*,int);
+ void perl_member(FILE*,const char*,ecf_list*);
+
+ static void destroy(node*);
+ static void changed(ecf_node*,int a=-1,int b=-1,int c=-1,void *d=0x0);
+ static node* find(ecf_node*);
+
+ static GC blackGC() { return gui::blackGC(); }
+ static GC blueGC() { return gui::blueGC(); }
+ static GC redGC() { return gui::redGC(); }
+ static XmFontList smallfont() { return gui::smallfont(); }
+ static XmFontList fontlist() { return gui::fontlist(); }
+ static Pixel colors(int n) { return gui::colors(n); }
+ static GC colorGC(int n) { return gui::colorGC(n); }
+
+ void helper(void* h) { helper_ = h; }
+ void* helper() { return helper_; }
+
+ node_info* get_node_info(const str&);
+ void add_node_info(node_info*);
+ void remove_node_info(const str&);
+ void remove_node_info(node_info*);
+
+ ecf_node* __node__() const { if (tree_) return 0x0; return owner_; }
+ bool ondemand(bool full=false);
+protected:
+ node(host&,ecf_node*);
+
+ virtual ~node(); // Change to virtual if base class
+
+ node* next_;
+ node* kids_;
+ ecf_node *owner_;
+ host& host_;
+ Boolean folded_;
+
+ void append(node*);
+ const xmstring& labelTree();
+ const xmstring& labelTrigger();
+ static void shadow(Widget,XRectangle*,bool = true);
+
+ protected:
+ xmstring labelTree_;
+
+private:
+
+ node(const node&);
+ node& operator=(const node&);
+
+ void* helper_;
+ node_data* data_;
+ bool triggered_;
+
+ node_data* get_node_data();
+
+ void scan(node*,node*);
+ void gather_triggered(node*);
+
+ virtual xmstring make_label_tree();
+ virtual xmstring make_label_trigger();
+
+ virtual void draw(Widget w,XRectangle* r) { drawNode(w,r,true); }
+ virtual void size(Widget w,XRectangle* r) { sizeNode(w,r,true); }
+};
+
+#ifdef BRIDGE
+class node_builder {
+protected:
+ static node_builder* builders_[NODE_MAX];
+public:
+ virtual node* make(host&,sms_node* n,char) = 0;
+ static node* build(host& h,sms_node* n,char b);
+};
+
+template<class T> class node_maker : public node_builder {
+public:
+ node_maker(int n) { builders_[n] = this; }
+ virtual node* make(host& h,sms_node* n,char b) { return new T(h,n,b); }
+};
+#endif
+#endif
+
diff --git a/view/src/node_alert.cc b/view/src/node_alert.cc
new file mode 100644
index 0000000..7cf821f
--- /dev/null
+++ b/view/src/node_alert.cc
@@ -0,0 +1,112 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <stdio.h>
+#include <stdarg.h>
+#include "node_alert.h"
+#include "gui.h"
+#include "ecflowview.h"
+#include "node.h"
+#include "host.h"
+#include "selection.h"
+#include "collector.h"
+#include <Xm/List.h>
+extern "C" {
+#include "xec.h"
+}
+
+template<class T>
+node_alert<T>::node_alert(const char* title,int bg)
+ : alert_(getenv("ecflow_view_alert"))
+ , title_(title)
+ , bg_ (bg)
+{
+ create(gui::top());
+ set_menu(title);
+ XtVaSetValues(_xd_rootwidget,XmNtitle,title,NULL);
+ xec_SetLabel(label_,title);
+ if(bg != -1) {
+ XtVaSetValues(label_,XmNbackground,gui::colors(bg),NULL);
+ /* XtVaSetValues(form_,XmNforeground,gui::colors(bg),0); */
+ /* XtVaSetValues(list_,XmNbackground,gui::colors(bg),0); */
+ /* XtVaSetValues(list_,XmNforeground,gui::colors(bg),0); */
+ }
+}
+
+
+template<class T>
+node_alert<T>::~node_alert()
+{}
+
+
+template<class T>
+void node_alert<T>::browseCB(Widget,XtPointer data)
+{
+ XmListCallbackStruct *cb = (XmListCallbackStruct *) data;
+ selection::notify_new_selection(find(cb->item));
+}
+
+
+
+template<class T>
+void node_alert<T>::clearCloseCB(Widget,XtPointer)
+{
+ reset();
+ XtUnmanageChild(form_);
+}
+
+template<class T>
+void node_alert<T>::closeCB(Widget,XtPointer)
+{
+ XtUnmanageChild(form_);
+}
+
+template<class T>
+void node_alert<T>::collectCB(Widget,XtPointer)
+{
+ XmString* items = 0;
+ int count = 0;
+
+ XtVaGetValues(list_,XmNitems,&items,XmNitemCount,&count,NULL);
+
+ for(int i = 0; i < count ; i++)
+ {
+ node *n = find(items[i]);
+ if(n) collector::show(*n);
+ }
+}
+
+template<class T>
+void node_alert<T>::notify_system(node* n) {
+#ifdef linux
+/*
+ export ecflow_view_alert=1
+ notify-send -i 'dialog-information' 'Summary' \
+ '<b><font color=red>Message body.'
+ */
+ if(1 && alert_) {
+ char buff[1024];
+ const char *cmd = "kdialog --title ecFlowview::%s --passivepopup '<b><font color=%s> %s' 5; %s";
+ const char *sound = "play -q /usr/share/xemacs/xemacs-packages/etc/sounds/boing.wav";
+ snprintf(buff, 1024, cmd,
+ title_.c_str(),
+ bg_ == STATUS_ABORTED ? "red" : "black",
+ n ? name(n) : "",
+ bg_ == STATUS_ABORTED ? sound : ""
+ );
+ if (system(buff)) { std::cerr << "#node_alert!\n"; }
+ }
+#endif
+ }
diff --git a/view/src/node_alert.h b/view/src/node_alert.h
new file mode 100644
index 0000000..c7120a8
--- /dev/null
+++ b/view/src/node_alert.h
@@ -0,0 +1,76 @@
+#ifndef node_alert_H
+#define node_alert_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "uinode_alert.h"
+#include "window.h"
+#include "singleton.h"
+#include "node_list.h"
+#include "gui.h"
+#include "node.h"
+
+class node;
+
+template<class T>
+class node_alert : public node_alert_shell_c, public window,
+ public singleton<T>, public node_list {
+
+ const char* alert_;
+ void notify_system(node* n);
+ public:
+
+ node_alert(const char*,int = -1);
+
+ virtual ~node_alert(); // Change to virtual if base class
+
+ virtual Widget shell() { return _xd_rootwidget; }
+ virtual Widget list() { return list_; }
+ virtual Widget form() { return form_; }
+
+ // HP compiler wants the 'singleton<T>::' specifier :-(
+ static void show()
+ { if(gui::visible()) { singleton<T>::instance().add(0);singleton<T>::instance().notify_system(0);}}
+
+ static void show(node& n)
+ { if(gui::visible()) { singleton<T>::instance().add(&n);singleton<T>::instance().notify_system(&n); }}
+
+ static void hide(node& n)
+ { if(gui::visible()) singleton<T>::instance().remove(&n); }
+
+ static void clear()
+ { if(gui::visible()) singleton<T>::instance().reset(); }
+
+private:
+
+ node_alert(const node_alert<T>&);
+ node_alert<T>& operator=(const node_alert<T>&);
+
+ std::string title_;
+ int bg_;
+
+ void browseCB(Widget,XtPointer);
+ void clearCloseCB( Widget, XtPointer ) ;
+ void closeCB( Widget, XtPointer ) ;
+ void collectCB( Widget, XtPointer ) ;
+};
+
+
+#if defined(__GNUC__) || defined(hpux) || defined(_AIX)
+#include "node_alert.cc"
+#endif
+
+#endif
diff --git a/view/src/node_editor.cc b/view/src/node_editor.cc
new file mode 100644
index 0000000..98d72dd
--- /dev/null
+++ b/view/src/node_editor.cc
@@ -0,0 +1,66 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "node_editor.h"
+
+#ifndef translator_H
+#include "translator.h"
+#endif
+
+#include <Xm/Text.h>
+#include <Xm/TextF.h>
+#include <Xm/Label.h>
+#include "xec.h"
+
+template<class T>
+static void node_editor_set(node_editor& e,const char* name, const T& t)
+{
+ str v = translator<T,str>()(t);
+ e.set(name,v);
+}
+
+template<class T>
+static void node_editor_get(node_editor& e,const char* name, T& t)
+{
+ str v;
+ e.get(name,v);
+ t = translator<str,T>()(v);
+}
+
+void node_editor::set(const char* name,int value)
+{
+ node_editor_set(*this,name,value);
+}
+
+void node_editor::get(const char* name,int& value)
+{
+ node_editor_get(*this,name,value);
+}
+
+void node_editor::set(const char* name,const str& value)
+{
+ Widget w = find(name); if(!w) return;
+ if(XmIsLabel(w)) xec_SetLabel(w,(char*)value.c_str());
+ if(XmIsText(w)) XmTextSetString(w,(char*)value.c_str());
+ if(XmIsTextField(w)) XmTextSetString(w,(char*)value.c_str());
+}
+
+void node_editor::get(const char* name,str& value)
+{
+ Widget w = find(name); if(!w) return;
+ char* p = XmTextGetString(w);
+ value = str(p);
+ XtFree(p);
+}
diff --git a/view/src/node_editor.h b/view/src/node_editor.h
new file mode 100644
index 0000000..1042677
--- /dev/null
+++ b/view/src/node_editor.h
@@ -0,0 +1,134 @@
+#ifndef node_editor_H
+#define node_editor_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+// Headers
+// #ifndef machine_H
+// #include <machine.h>
+// #endif
+
+// Forward declarations
+
+// class ostream;
+// typedef class _Pvts os_typespec; // Remove if not persistant
+
+//
+
+#ifndef str_H
+#include "str.h"
+#endif
+
+#ifndef editor_H
+#include "editor.h"
+#endif
+
+
+class node_editor : public editor {
+public:
+
+// -- Exceptions
+ // None
+
+// -- Contructors
+
+ node_editor() {}
+
+// -- Destructor
+
+ virtual ~node_editor() {} // Change to virtual if base class
+
+// -- Convertors
+ // None
+
+// -- Operators
+ // None
+
+// -- Methods
+
+ virtual void set(const char*,const str&);
+ virtual void get(const char*,str&);
+
+ virtual void set(const char*,int);
+ virtual void get(const char*,int&);
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+ // Uncomment for persistent, remove otherwise
+ // static os_typespec* get_os_typespec();
+
+protected:
+
+// -- Members
+ // None
+
+// -- Methods
+
+ // void print(ostream&) const; // Change to virtual if base class
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+private:
+
+// No copy allowed
+
+ node_editor(const node_editor&);
+ node_editor& operator=(const node_editor&);
+
+// -- Members
+ // None
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+// -- Friends
+
+ //friend ostream& operator<<(ostream& s,const node_editor& p)
+ // { p.print(s); return s; }
+
+};
+
+inline void destroy(node_editor**) {}
+
+// If persistent, uncomment, otherwise remove
+//#ifdef _ODI_OSSG_
+//OS_MARK_SCHEMA_TYPE(node_editor);
+//#endif
+
+#endif
diff --git a/view/src/node_list.cc b/view/src/node_list.cc
new file mode 100644
index 0000000..20233e2
--- /dev/null
+++ b/view/src/node_list.cc
@@ -0,0 +1,129 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #8 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "node_list.h"
+#include "opener.h"
+#include "node.h"
+#include "host.h"
+#include "str.h"
+#include "gui.h"
+#include "relation.h"
+#include "counted.h"
+#include "opener.h"
+#include <Xm/List.h>
+
+extern "C" {
+#include "xec.h"
+}
+
+class node_list_data : public counted {
+ str name_;
+public:
+ node_list_data(const char* n) : name_(n) {}
+ const char* name() { return name_.c_str(); }
+};
+
+node_list::node_list()
+{
+}
+
+node_list::~node_list()
+{
+}
+
+
+void node_list::remove(node* n)
+{
+ if (forget(n))
+ xec_RemoveListItem(list(),(char*)name(n));
+}
+
+
+void node_list::add(node* n,bool sel)
+{
+ if(n) {
+ const char *p = name(n);
+ if(xec_AddListItemUnique(list(),(char*)p,sel)) {
+ observe(n);
+ relation::set_data(this,n,new node_list_data(p));
+ }
+ }
+
+ static opener o;
+ o.show(form());
+ gui::raise();
+}
+
+
+void node_list::reset()
+{
+ forget_all();
+ XmListDeleteAllItems(list());
+}
+
+
+node* node_list::find(XmString s)
+{
+ char *p = xec_GetString(s);
+ char *q = p;
+
+ while(*q != ' ') q++;
+ *q = 0; q++;
+ while(*q == ' ') *q++ = 0;
+
+ node* n = host::find(p,q);
+
+ if(!n) {
+ printf("node_list::find cannot find <%s> <%s>\n",p,q);
+ }
+
+ XtFree(p);
+ return n;
+}
+
+node* node_list::find(const char *p)
+{
+ xmstring s(p);
+ return find(s);
+}
+
+
+const char* node_list::name(node* n)
+{
+ static char buf[1024];
+ sprintf(buf,"%-8s %s",n->serv().name(),n->full_name().c_str());
+ return buf;
+}
+
+
+void node_list::notification(observable* o)
+{
+ node* n = (node*)o;
+ if(!keep(n))
+ remove(n);
+}
+
+void node_list::adoption(observable*,observable* o)
+{
+ node* n = (node*)o;
+ if(!keep(n))
+ remove(n);
+}
+
+void node_list::gone(observable* o)
+{
+ node_list_data* p = (node_list_data*)relation::get_data(this,o);
+ if(p) xec_RemoveListItem(list(),(char*)p->name());
+}
diff --git a/view/src/node_list.h b/view/src/node_list.h
new file mode 100644
index 0000000..6fdc410
--- /dev/null
+++ b/view/src/node_list.h
@@ -0,0 +1,62 @@
+#ifndef node_list_H
+#define node_list_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#ifdef NO_BOOL
+#include "bool.h"
+#endif
+
+class node;
+
+#include <Xm/Xm.h>
+#ifndef observer_H
+#include "observer.h"
+#endif
+
+class node_list : public observer {
+public:
+
+ node_list();
+
+ ~node_list(); // Change to virtual if base class
+
+ virtual Widget list() = 0;
+ virtual Widget form() = 0;
+ virtual bool keep(node*) = 0;
+
+ virtual void add(node* n,bool sel = false);
+ virtual void remove(node* n);
+ virtual void reset();
+
+protected:
+
+ node* find(XmString);
+ node* find(const char*);
+ const char* name(node*);
+
+private:
+
+ node_list(const node_list&);
+ node_list& operator=(const node_list&);
+
+ virtual void notification(observable*);
+ virtual void adoption(observable*,observable*);
+ virtual void gone(observable*);
+};
+
+inline void destroy(node_list**) {}
+#endif
diff --git a/view/src/node_lister.h b/view/src/node_lister.h
new file mode 100644
index 0000000..5d3a577
--- /dev/null
+++ b/view/src/node_lister.h
@@ -0,0 +1,41 @@
+#ifndef node_lister_H
+#define node_lister_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#ifndef observer_H
+#include "observer.h"
+#endif
+
+#include <string>
+class node;
+
+class node_lister {
+public:
+
+ node_lister() {}
+
+ virtual ~node_lister() {}
+
+ virtual void next(node&) = 0;
+ virtual void next(const std::string) {}
+private:
+ node_lister(const node_lister&);
+ node_lister& operator=(const node_lister&);
+};
+
+inline void destroy(node_lister**) {}
+#endif
diff --git a/view/src/node_window.cc b/view/src/node_window.cc
new file mode 100644
index 0000000..70afa47
--- /dev/null
+++ b/view/src/node_window.cc
@@ -0,0 +1,253 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "node_window.h"
+#include "menus.h"
+#include <Xm/Frame.h>
+#include <Xm/Label.h>
+#include <Xm/RowColumn.h>
+#include "xnode.h"
+#include "collector.h"
+#include "host.h"
+#ifdef AIX
+#include <X11/keysym.h>
+#endif
+node_window::node_window()
+{
+}
+
+node_window::~node_window()
+{
+}
+
+void node_window::linkCB(Widget w,XtPointer from,XtPointer cb_data)
+{
+ LinkCallbackStruct* cb = (LinkCallbackStruct*)cb_data;
+ node_window* t = (node_window*)from;
+
+
+ xnode* x1 = (xnode*)cb->data1;
+ xnode* x2 = (xnode*)cb->data2;
+
+ node* n1 = x1?x1->get_node():0;
+ node* n2 = x2?x2->get_node():0;
+
+ t->link(cb->event,n1,n2);
+}
+
+void node_window::inputCB(Widget w,XtPointer from,XtPointer cb_data)
+{
+ XmDrawingAreaCallbackStruct* cb = (XmDrawingAreaCallbackStruct*)cb_data;
+
+ // printf("inputCB %d\n", cb->event->type);
+ if(cb->event->type == ButtonPress || cb->event->type == KeyPress) {
+ node_window* t = (node_window*)from;
+ t->click(cb->event);
+ }
+}
+
+void node_window::click1(node* n,Boolean shift,Boolean control)
+{
+ // printf("raw_click1 %p %d %d\n",n,shift,control);
+ if(control && n) collector::show(*n);
+ else if (shift && n) this->click2(n,0,control);
+ else selection::notify_new_selection(n);
+}
+
+void node_window::click2(node* n,Boolean shift,Boolean control)
+{
+}
+
+void node_window::click3(node* n,Boolean shift,Boolean control)
+{
+}
+
+void node_window::raw_click1(XEvent* event,xnode* x)
+{
+ node* n = x ? x->get_node() : 0;
+ selection::menu_node(n);
+ unsigned int modifiers = event->xbutton.state;
+ Boolean shift = (modifiers & ShiftMask) != 0;
+ Boolean control = (modifiers & ControlMask) != 0;
+ click1(n,shift,control);
+}
+
+void node_window::raw_click2(XEvent* event,xnode* x)
+{
+ node* n = x ? x->get_node() : 0;
+ selection::menu_node(n);
+ unsigned int modifiers = event->xbutton.state;
+ Boolean shift = (modifiers & ShiftMask) != 0;
+ Boolean control = (modifiers & ControlMask) != 0;
+ if(n) this->click2(n,shift,control);
+}
+
+void node_window::raw_click3(XEvent* event,xnode* x)
+{
+ node* n = x ? x->get_node() : 0;
+ selection::menu_node(n);
+ unsigned int modifiers = event->xbutton.state;
+ Boolean shift = (modifiers & ShiftMask) != 0;
+ Boolean control = (modifiers & ControlMask) != 0;
+
+ if(n) click3(n,shift,control);
+ if( shift && n)
+ {
+ XmMenuPosition(menu2(),(XButtonPressedEvent*)event);
+ XtManageChild(menu2());
+ }
+ else if(n)
+ {
+ // menus::show(node_widget(),event,n); // 20141119
+ menus::show(menu1(),event,n);
+ //XmMenuPosition(g_cmd_menu,(XButtonPressedEvent*)event);
+ //XtManageChild(g_cmd_menu);
+ } else {
+ XmMenuPosition(menu1(),(XButtonPressedEvent*)event);
+ XtManageChild(menu1());
+ }
+}
+
+node* next_node(node* n)
+{
+ node *out = n;
+ while (n) {
+ if (n->type() == NODE_TASK ||
+ n->type() == NODE_FAMILY ||
+ n->type() == NODE_SUITE ||
+ n->type() == NODE_ALIAS)
+ return n;
+ n = n->next();
+ }
+ return out;
+}
+
+node* next_host(node* n, bool first) {
+ host *h = 0x0;
+ if (!n) return n;
+ if (first) h = extent<host>::first();
+ else h = &n->serv();
+ while ((h= h->extent<host>::next())) {
+ if (h->top())
+ return h->top();
+ }
+ if (first) return n;
+ return next_host(n, true);
+}
+
+void node_window::keypress(XEvent* event)
+{
+ xnode* x = (xnode*)NodeFind(node_widget(),event);
+ node* n = 0x0;
+ KeySym keysym = XLookupKeysym(&(event->xkey), 0);
+
+ if (keysym == XK_KP_Space || keysym == XK_space) {
+ raw_click1(event,x);
+ // } else if (keysym == XK_F2) { raw_click2(event,x);
+ } else if (keysym == XK_KP_Enter || keysym == XK_Return) {
+ if ((event->xbutton.state & ShiftMask) != 0)
+ n = selection::current_node();
+ if (n)
+ menus::show(node_widget(),event,n);
+ else
+ raw_click3(event,x);
+ } else if (keysym == XK_Up) {
+ node* first = n = selection::current_node();
+ if (!n) return;
+ n = n->parent();
+
+ if (!n) /* reach server node */
+ n = next_host(selection::current_node(), true);
+
+ if (!n) return;
+ selection::notify_new_selection(n);
+
+ n = n->kids();
+ if (n==first) n = n->parent();
+
+ if (n) click1(n,0,0);
+ } else if (keysym == XK_Down) {
+ n = selection::current_node();
+ if (!n) return;
+ n = n->next();
+ if (!n) {
+ n = selection::current_node()->parent();
+ if (n) n = n->next();
+ }
+ if (!n) /* reach server node */
+ n = next_host(selection::current_node(), false);
+ if (n) click1(n,0,0);
+ } else if (keysym == XK_Left) {
+ n = selection::current_node();
+ if (!n) return;
+ n = n->parent();
+ if (!n) /* reach server node */
+ n = next_host(selection::current_node(), true);
+ if (!n) return;
+ click2(n,0,0);
+ click1(n,0,0);
+ } else if (keysym == XK_Right) {
+ n = selection::current_node();
+ if (!n) return;
+ click2(n,0,0);
+ if (n->kids()) n = n->kids();
+ else n = n->next();
+ n = next_node(n);
+ if (n) click1(n,0,0);
+ }
+}
+
+void node_window::click(XEvent* event)
+{
+ int button = event->xbutton.button;
+ xnode* x = (xnode*)NodeFind(node_widget(),event);
+
+ switch(button) {
+ case 1: raw_click1(event,x); break;
+ case 2: raw_click2(event,x); break;
+ case 3: raw_click3(event,x); break;
+ default: keypress(event);
+ }
+}
+
+void node_window::show_node(node&)
+{
+}
+
+void node_window::new_selection(node& n)
+{
+ xnode* x = xnode_of(n);
+ if(x && x->widget() == node_widget() ) {
+ show_node(n);
+ x->select();
+ }
+ else
+ selection_cleared();
+}
+
+void node_window::selection_cleared()
+{
+ XtVaSetValues(node_widget(),XtNselected,-1,NULL);
+}
+
+void node_window::add_input_CB()
+{
+ XtAddCallback( node_widget(), XmNinputCallback, inputCB, this);
+ XtAddCallback( node_widget(), XtNlinkCallback, linkCB, this);
+}
+
+void node_window::link(XEvent*,node*,node*)
+{
+}
diff --git a/view/src/node_window.h b/view/src/node_window.h
new file mode 100644
index 0000000..ad25574
--- /dev/null
+++ b/view/src/node_window.h
@@ -0,0 +1,73 @@
+#ifndef node_window_H
+#define node_window_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#ifndef node_H
+#include "node.h"
+#endif
+
+#ifndef selection_H
+#include "selection.h"
+#endif
+
+class xnode;
+
+class node_window : public selection {
+public:
+ node_window();
+
+ ~node_window(); // Change to virtual if base class
+
+ void add_input_CB();
+
+ virtual xnode* xnode_of(node&) = 0;
+ virtual Widget node_widget() = 0;
+
+ virtual void new_selection(node&);
+ virtual void selection_cleared();
+
+protected:
+
+ virtual void show_node(node&);
+ virtual void click(XEvent*);
+
+ virtual void link(XEvent*,node*,node*);
+
+ virtual void keypress(XEvent* event);
+ virtual void click1(node*,Boolean,Boolean);
+ virtual void click2(node*,Boolean,Boolean);
+ virtual void click3(node*,Boolean,Boolean);
+
+ virtual void raw_click1(XEvent* event,xnode*);
+ virtual void raw_click2(XEvent* event,xnode*);
+ virtual void raw_click3(XEvent* event,xnode*);
+
+ virtual Widget menu1() = 0;
+ virtual Widget menu2() = 0;
+
+ static void inputCB(Widget,XtPointer,XtPointer);
+ static void linkCB(Widget,XtPointer,XtPointer);
+
+private:
+
+ node_window(const node_window&);
+ node_window& operator=(const node_window&);
+
+};
+
+inline void destroy(node_window**) {}
+#endif
diff --git a/view/src/not_enqueued.cc b/view/src/not_enqueued.cc
new file mode 100644
index 0000000..dbab254
--- /dev/null
+++ b/view/src/not_enqueued.cc
@@ -0,0 +1,32 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "not_enqueued.h"
+#include "node.h"
+
+
+not_enqueued::not_enqueued(): node_alert<not_enqueued>("Not_Enqueued tasks")
+{
+}
+
+not_enqueued::~not_enqueued()
+{
+}
+
+bool not_enqueued::keep(node* n)
+{
+ return false; // return n->isNotEnqueued();
+}
diff --git a/view/src/not_enqueued.h b/view/src/not_enqueued.h
new file mode 100644
index 0000000..881efec
--- /dev/null
+++ b/view/src/not_enqueued.h
@@ -0,0 +1,45 @@
+#ifndef not_enqueued_H
+#define not_enqueued_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "node_alert.h"
+
+class node;
+
+class not_enqueued : public node_alert<not_enqueued> {
+public:
+ not_enqueued();
+ ~not_enqueued(); // Change to virtual if base class
+
+protected:
+
+private:
+
+// No copy allowed
+
+ not_enqueued(const not_enqueued&);
+ not_enqueued& operator=(const not_enqueued&);
+
+ //
+
+ virtual bool keep(node*);
+
+};
+
+inline void destroy(not_enqueued**) {}
+
+#endif
diff --git a/view/src/observable.cc b/view/src/observable.cc
new file mode 100644
index 0000000..4daf853
--- /dev/null
+++ b/view/src/observable.cc
@@ -0,0 +1,79 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#ifndef observable_H
+#include "observable.h"
+#endif
+
+#ifndef relation_H
+#include "relation.h"
+#endif
+
+#include "observer.h"
+
+observable::observable()
+ : observed_(false)
+{
+}
+
+struct gone_iter : public observer_iterator {
+ observable* o_;
+ void next(observer* o) { o->gone(o_); }
+public:
+ gone_iter(observable* o) : o_(o) {}
+};
+
+observable::~observable()
+{
+ if(observed_) {
+ gone_iter gi(this);
+ relation::scan(this,gi);
+ relation::remove(this);
+ }
+}
+
+
+struct notify_iter : public observer_iterator {
+ observable* o_;
+ void next(observer* o) { o->notification(o_); }
+public:
+ notify_iter(observable* o) : o_(o) {}
+};
+
+void observable::notify_observers()
+{
+ if(observed_) {
+ notify_iter ni(this);
+ relation::scan(this,ni);
+ }
+}
+
+struct adopt_iter : public observer_iterator {
+ observable* o_;
+ observable* n_;
+ void next(observer* o) { o->adoption(o_,n_); }
+public:
+ adopt_iter(observable* o,observable* n) : o_(o), n_(n) {}
+};
+
+void observable::notify_adoption(observable* n)
+{
+ if(observed_ && n) {
+ adopt_iter ai(this,n);
+ relation::scan(this,ai);
+ relation::replace(this,n);
+ n->observed_ = true;
+ }
+}
diff --git a/view/src/observable.h b/view/src/observable.h
new file mode 100644
index 0000000..bdb0393
--- /dev/null
+++ b/view/src/observable.h
@@ -0,0 +1,45 @@
+#ifndef observable_H
+#define observable_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#ifdef NO_BOOL
+#include "bool.h"
+#endif
+
+class observable {
+public:
+
+ observable();
+
+ virtual ~observable(); // Change to virtual if base class
+
+ void notify_observers();
+ void notify_adoption(observable*);
+
+private:
+
+ observable(const observable&);
+ observable& operator=(const observable&);
+
+ bool observed_;
+
+ friend class relation;
+};
+
+/* #include "observable.cc" */
+
+#endif
diff --git a/view/src/observer.cc b/view/src/observer.cc
new file mode 100644
index 0000000..43ea1cf
--- /dev/null
+++ b/view/src/observer.cc
@@ -0,0 +1,48 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#ifndef observer_H
+#include "observer.h"
+#endif
+
+#ifndef relation_H
+#include "relation.h"
+#endif
+
+
+observer::observer()
+{
+}
+
+observer::~observer()
+{
+ relation::remove(this);
+}
+
+void observer::observe(observable* t)
+{
+ relation::add(this,t);
+}
+
+int observer::forget(observable* t)
+{
+ return relation::remove(this,t);
+}
+
+void observer::forget_all()
+{
+ relation::remove(this);
+}
+
diff --git a/view/src/observer.h b/view/src/observer.h
new file mode 100644
index 0000000..8980464
--- /dev/null
+++ b/view/src/observer.h
@@ -0,0 +1,48 @@
+#ifndef observer_H
+#define observer_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+class observable;
+class relation_data;
+
+class observer {
+public:
+
+ observer();
+
+ virtual ~observer(); // Change to virtual if base class
+
+ void observe(observable*);
+ int forget(observable*);
+ void forget_all();
+
+ virtual void notification(observable*) = 0;
+ virtual void adoption(observable*,observable*) = 0;
+ virtual void gone(observable*) = 0;
+
+ void set_data(observable*,relation_data*);
+ relation_data* get_data(observable*);
+
+private:
+
+ observer(const observer&);
+ observer& operator=(const observer&);
+};
+
+/* #include "observer.cc" */
+
+#endif
diff --git a/view/src/opener.h b/view/src/opener.h
new file mode 100644
index 0000000..2984bea
--- /dev/null
+++ b/view/src/opener.h
@@ -0,0 +1,126 @@
+#ifndef opener_H
+#define opener_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+// Headers
+// #ifndef machine_H
+// #include <machine.h>
+// #endif
+
+// Forward declarations
+
+// class ostream;
+// typedef class _Pvts os_typespec; // Remove if not persistant
+
+//
+
+#include <Xm/Xm.h>
+#include "runnable.h"
+
+class opener : public runnable {
+public:
+
+// -- Exceptions
+ // None
+
+// -- Contructors
+
+ opener() : widget_(0) {}
+
+// -- Destructor
+
+
+// -- Convertors
+ // None
+
+// -- Operators
+ // None
+
+// -- Methods
+
+ void show(Widget w) { widget_ = w; enable(); }
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+ // Uncomment for persistent, remove otherwise
+ // static os_typespec* get_os_typespec();
+
+protected:
+
+// -- Members
+ // None
+
+// -- Methods
+
+ // void print(ostream&) const; // Change to virtual if base class
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+private:
+
+// No copy allowed
+
+ opener(const opener&);
+ opener& operator=(const opener&);
+
+// -- Members
+
+ Widget widget_;
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+
+ void run() { if(!XtIsManaged(widget_)) XtManageChild(widget_); disable();}
+
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+// -- Friends
+
+ //friend ostream& operator<<(ostream& s,const opener& p)
+ // { p.print(s); return s; }
+
+};
+
+inline void destroy(opener**) {}
+
+// If persistent, uncomment, otherwise remove
+//#ifdef _ODI_OSSG_
+//OS_MARK_SCHEMA_TYPE(opener);
+//#endif
+
+#endif
diff --git a/view/src/option.cc b/view/src/option.cc
new file mode 100644
index 0000000..f2f16c3
--- /dev/null
+++ b/view/src/option.cc
@@ -0,0 +1,205 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string>
+#include <list>
+
+#ifndef option_H
+#include "option.h"
+#endif
+
+#ifndef translator_H
+#include "translator.h"
+#endif
+
+#ifndef choice_H
+#include "choice.h"
+#endif
+
+
+#include <Xm/Text.h>
+#include <Xm/ToggleB.h>
+
+#ifdef NO_BOOL
+#include "bool.h"
+#endif
+
+#include "ecflow.h"
+
+template<class T>
+option<T>::option(configurable* o,const str& name,const T& val):
+ resource(o,name,translator<T,str>()(val))
+{
+ value_ = translator<str,T>()(get());
+}
+
+template<class T>
+option<T>::~option()
+{
+}
+
+template<class T>
+bool option<T>::changed()
+{
+ T old = value_;
+ value_ = translator<str,T>()(get());
+ return old != value_;
+}
+
+
+template<class T>
+void option<T>::put(const T& v)
+{
+ set(translator<T,str>()(v));
+}
+
+//==========================================================
+
+inline
+void init_widget(Widget w,const str& s)
+{
+ XmTextSetString(w,(char*)s.c_str());
+}
+
+inline
+void init_widget(Widget w,int n)
+{
+ str s = translator<int,str>()(n);
+ XmTextSetString(w,(char*)s.c_str());
+}
+
+inline
+void init_widget(Widget w,long n)
+{
+ str s = translator<long,str>()(n);
+ XmTextSetString(w,(char*)s.c_str());
+}
+
+inline
+void init_widget(Widget w,uint64_t n)
+{
+ str s = translator<uint64_t,str>()(n);
+ XmTextSetString(w,(char*)s.c_str());
+}
+
+inline
+void init_widget(Widget w,bool v)
+{
+ XmToggleButtonSetState(w,v,False);
+}
+
+inline
+void init_widget(Widget,std::vector< std::string >&)
+{
+}
+
+inline
+void init_widget(Widget w,const choice& c)
+{
+ WidgetList wl = 0;
+ int count = 0;
+
+ XtVaGetValues(w, XmNchildren,&wl, XtNnumChildren,&count, NULL);
+
+ for(int i = 0; i < count; i++)
+ XmToggleButtonSetState(wl[i],i == c,False);
+}
+
+
+inline
+str read_widget(Widget w,const str&)
+{
+ char* p = XmTextGetString(w);
+ str b(p);
+ XtFree(p);
+ return b;
+}
+
+inline
+int read_widget(Widget w,int)
+{
+ char* p = XmTextGetString(w);
+ int n = atol(p);
+ XtFree(p);
+ return n;
+}
+
+inline
+long read_widget(Widget w,long)
+{
+ char* p = XmTextGetString(w);
+ long n = atol(p);
+ XtFree(p);
+ return n;
+}
+
+inline
+long read_widget(Widget w,uint64_t)
+{
+ char* p = XmTextGetString(w);
+ uint64_t n = atoll(p);
+ XtFree(p);
+ return n;
+}
+
+inline
+bool read_widget(Widget w,bool)
+{
+ return XmToggleButtonGetState(w);
+}
+
+inline
+ecf_list* read_widget(Widget,ecf_list*)
+{
+ return 0;
+}
+
+inline
+std::vector< std::string > read_widget(Widget,std::vector< std::string >&)
+{
+ std::vector< std::string > out;
+ return out;
+}
+
+inline
+int read_widget(Widget w,const choice& c)
+{
+ WidgetList wl = 0;
+ int count = 0;
+
+ XtVaGetValues(w, XmNchildren,&wl, XtNnumChildren,&count, NULL);
+
+ for(int i = 0; i < count; i++)
+ if(XmToggleButtonGetState(wl[i]) )
+ return i;
+ return c;
+}
+
+template<class T>
+void option<T>::initWidget(Widget w)
+{
+ init_widget(w,value_);
+}
+
+template<class T>
+bool option<T>::readWidget(Widget w)
+{
+ T b = read_widget(w,value_);
+ bool x = (b != value_);
+ if(x) put(b);
+ return x;
+}
diff --git a/view/src/option.h b/view/src/option.h
new file mode 100644
index 0000000..9ca2cc9
--- /dev/null
+++ b/view/src/option.h
@@ -0,0 +1,48 @@
+#ifndef option_H
+#define option_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "resource.h"
+
+template<class T>
+class option : public resource {
+public:
+ option(configurable*,const str&,const T&);
+
+ ~option(); // Change to virtual if base class
+
+ operator const T&() const { return value_; }
+ const T& operator=(const T& v) { put(v); return value_; }
+
+ virtual void initWidget(Widget);
+ virtual bool readWidget(Widget);
+ virtual bool changed();
+
+private:
+
+ option(const option<T>&);
+ option<T>& operator=(const option<T>&);
+
+ T value_;
+
+ void put(const T&);
+};
+
+#if defined(__GNUC__) || defined(hpux) || defined(_AIX)
+#include "option.cc"
+#endif
+#endif
diff --git a/view/src/option_panel.cc b/view/src/option_panel.cc
new file mode 100644
index 0000000..a1cf117
--- /dev/null
+++ b/view/src/option_panel.cc
@@ -0,0 +1,60 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "option_panel.h"
+#include "node.h"
+#include "host.h"
+#include "ecflowview.h"
+#include <Xm/Label.h>
+#include <Xm/Text.h>
+#include <Xm/ToggleB.h>
+extern "C" {
+#include "xec.h"
+}
+
+option_panel::option_panel(panel_window& w):
+ panel(w)
+{
+}
+
+option_panel::~option_panel()
+{
+}
+
+void option_panel::create (Widget parent, char *widget_name )
+{
+ option_form_c::create(parent,widget_name);
+}
+
+void option_panel::clear()
+{
+}
+
+void option_panel::show(node& n)
+{
+ resource::init(n.serv(),*this);
+ freeze();
+}
+
+Boolean option_panel::enabled(node& n)
+{
+ return n.type() == NODE_SUPER;
+}
+
+configurable* option_panel::owner()
+{
+ return get_node() ? &(get_node()->serv()) : 0;
+}
+
diff --git a/view/src/option_panel.h b/view/src/option_panel.h
new file mode 100644
index 0000000..9829533
--- /dev/null
+++ b/view/src/option_panel.h
@@ -0,0 +1,58 @@
+#ifndef option_panel_H
+#define option_panel_H
+
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "uioption.h"
+
+#ifndef panel_H
+#include "panel.h"
+#endif
+
+#ifndef pref_editor_H
+#include "pref_editor.h"
+#endif
+
+class option_panel : public panel, public option_form_c , public pref_editor{
+public:
+
+ option_panel(panel_window&);
+
+ ~option_panel(); // Change to virtual if base class
+
+ virtual const char* name() const { return "Options"; }
+ virtual void show(node&);
+ virtual void clear();
+ virtual Boolean enabled(node&);
+
+ virtual Widget widget() { return option_form_c::xd_rootwidget(); }
+
+ virtual void create (Widget parent, char *widget_name = NULL);
+
+private:
+
+ option_panel(const option_panel&);
+ option_panel& operator=(const option_panel&);
+
+ virtual void changedCB( Widget w, XtPointer ) { pref_editor::changed(w); }
+ virtual void useCB( Widget w, XtPointer ) { pref_editor::use(w); }
+
+ virtual Widget form() { return form_; }
+ virtual configurable* owner();
+};
+
+inline void destroy(option_panel**) {}
+#endif
diff --git a/view/src/output.cc b/view/src/output.cc
new file mode 100644
index 0000000..c3f97e7
--- /dev/null
+++ b/view/src/output.cc
@@ -0,0 +1,226 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #18 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "output.h"
+#include "node.h"
+#include "host.h"
+#include <Xm/Text.h>
+#include <Xm/TextStrSoP.h>
+#include <Xm/List.h>
+#include "ecf_node.h"
+extern "C" {
+#include "xec.h"
+}
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+output::output(panel_window& w):
+ text_window(true),
+ panel(w),
+ file_(0x0)
+{
+}
+
+output::~output()
+{
+ if(file_)
+ free(file_);
+}
+
+void output::create (Widget parent, char *widget_name )
+{
+ output_form_c::create(parent,widget_name);
+}
+
+void output::clear()
+{
+ if(file_) free(file_);
+ file_ = 0x0;
+ XmTextSetString(name_,(char*) "");
+ XmListDeleteAllItems(list_);
+ //active(False);
+ text_window::clear();
+}
+
+class output_lister : public lister<ecf_dir> {
+ Widget list_;
+ bool sort() { return true; }
+ bool compare(ecf_dir&,ecf_dir&);
+ void next(ecf_dir&);
+public:
+ output_lister(Widget l) : list_(l) {}
+};
+
+void output_lister::next(ecf_dir& d)
+{
+ if(S_ISREG(d.mode))
+ {
+ time_t t = d.mtime;
+ time_t now = time(0);
+
+ int delta = now - t;
+ if(delta<0) delta = 0;
+
+ char buf[80];
+ strcpy(buf,"Right now");
+
+ if(delta >=1 && delta < 60)
+ {
+ sprintf(buf,"%d second%s ago",delta,delta>1?"s":"");
+ }
+
+ if(delta >= 60 && delta < 60*60)
+ {
+ sprintf(buf,"%d minute%s ago",delta/60,delta/60>1?"s":"");
+ }
+
+ if(delta >= 60*60 && delta < 60*60*24)
+ {
+ sprintf(buf,"%d hour%s ago",delta/60/60,delta/60/60>1?"s":"");
+ }
+
+ if(delta >= 60*60*24)
+ {
+ sprintf(buf,"%d day%s ago",delta/60/60/24,delta/60/60/24>1?"s":"");
+ }
+
+ xec_VaAddListItem(list_,(char*) "%-60s (%s)",d.name_,buf);
+ }
+}
+
+bool output_lister::compare(ecf_dir& a,ecf_dir& b)
+{
+ return a.mtime > b.mtime;
+}
+
+class search_me : public runnable {
+ find& find_;
+
+ void run() {
+ /* text case regexp back wrap */
+ find_.search("System Billing Units",true,false,false,true);
+ find_.search("smscomplete",true,false,false,true);
+ find_.search("smsabort",true,false,false,true);
+ // display init but not appreciated when updating for tail:
+ // find_.search("ecflow_client",true,false,false,true);
+ find_.search("xcomplete",true,false,false,true);
+ find_.search("xabort",true,false,false,true);
+ find_.search("--complete",true,false,false,true);
+ find_.search("--abort",true,false,false,true);
+ find_.no_message();
+ find_.pending(0);
+ delete this;
+ }
+
+public:
+ search_me(find& f) : find_(f) { find_.pending(this); enable();}
+};
+
+void output::show(node& n)
+{
+ std::string jobout = n.variable("ECF_JOBOUT");
+ if (!n.__node__())
+ jobout = n.variable("SMSJOBOUT");
+ else if (!n.__node__()) return;
+ else if (!n.__node__()->get_node()) return;
+ else n.__node__()->get_node()->variableSubsitution(jobout);
+
+ if(jobout == ecf_node::none()) {
+ clear();
+ return;
+ }
+
+ /* output variable may contain micro */
+
+ if(file_) free(file_);
+ file_ = strdup(jobout.c_str());
+ load(n);
+ XmListDeleteAllItems(list_);
+
+ output_lister ol(list_);
+ n.serv().dir(n,file_,ol);
+
+ std::string remote = n.variable("ECF_OUT");
+ std::string job = n.variable("ECF_JOB");
+ if (!n.__node__()) {
+ remote = n.variable("SMSOUT");
+ job = n.variable("SMSJOB");
+ }
+ if (!remote.empty() && !job.empty()) {
+ /* display both remote and local dir */
+ if (remote == job) {
+ output_lister rem(list_);
+ n.serv().dir(n,job.c_str(),rem);
+ }
+ }
+ new search_me(*this);
+}
+
+struct dup_slash { // INT-74
+ bool operator() (char x, char y) const {
+ return x=='/' && y=='/';
+ };
+};
+
+void output::load(node& n)
+{
+ if(file_) {
+ std::string name (file_);
+ name.erase(std::unique(name.begin(), name.end(), dup_slash()), name.end()); // INT-74
+ XmTextSetString(name_,(char*)name.c_str()); /* ??? */
+ tmp_file f = n.serv().file(n,name);
+ text_window::load(f);
+ } else {
+ clear();
+ tmp_file f = n.serv().output(n);
+ text_window::load(f);
+ }
+}
+
+void output::updateCB(Widget,XtPointer data)
+{
+ if(get_node())
+ show(*get_node());
+ else
+ clear();
+ XmTextShowPosition(text_,XmTextGetLastPosition(text_));
+}
+
+void output::browseCB(Widget,XtPointer data)
+{
+ XmListCallbackStruct *cb = (XmListCallbackStruct *) data;
+ if(file_) free(file_);
+
+ char *p = xec_GetString(cb->item);
+ char buf[1024];
+ sscanf(p,"%s",buf);
+ XtFree(p);
+
+ file_ = strdup(buf);
+
+ if(get_node())
+ load(*get_node());
+ else
+ clear();
+}
+
+Boolean output::enabled(node& n)
+{
+ if (n.type() != NODE_TASK && n.type() != NODE_ALIAS) return False;
+ if (!n.__node__())
+ return n.variable("SMSJOBOUT") != ecf_node::none();
+ return n.variable("ECF_JOBOUT") != ecf_node::none();
+}
diff --git a/view/src/output.h b/view/src/output.h
new file mode 100644
index 0000000..f041211
--- /dev/null
+++ b/view/src/output.h
@@ -0,0 +1,67 @@
+#ifndef output_H
+#define output_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "uioutput.h"
+
+#ifndef panel_H
+#include "panel.h"
+#endif
+
+#include "host.h"
+#include "text_window.h"
+
+
+class output : public output_form_c, public text_window, public panel {
+public:
+ output(panel_window&);
+
+ ~output(); // Change to virtual if base class
+
+ virtual const char* name() const { return "Output"; }
+ virtual void show(node&);
+ virtual void clear();
+ virtual Boolean enabled(node&);
+ virtual Widget widget() { return output_form_c::xd_rootwidget(); }
+
+ virtual Widget tools() { return tools_; }
+ virtual Widget text() { return text_; }
+ virtual void create (Widget parent, char *widget_name = 0 );
+
+private:
+ output(const output&);
+ output& operator=(const output&);
+
+ char *file_;
+
+ void load(node&);
+
+ virtual void browseCB(Widget,XtPointer);
+ virtual void updateCB(Widget,XtPointer);
+ virtual void externalCB(Widget ,XtPointer )
+ { text_window::open_viewer();}
+ virtual void searchCB(Widget ,XtPointer )
+ { text_window::open_search();}
+
+ virtual bool can_print() { return true; }
+ virtual bool can_save() { return true; }
+ virtual void print() { text_window::print(); }
+ virtual void save() { text_window::save(); }
+};
+
+inline void destroy(output**) {}
+#endif
diff --git a/view/src/panel.cc b/view/src/panel.cc
new file mode 100644
index 0000000..340f2f3
--- /dev/null
+++ b/view/src/panel.cc
@@ -0,0 +1,125 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <stdio.h>
+#include <Xm/Xm.h>
+#include "Hyper.h"
+
+
+#include "panel.h"
+#include "node.h"
+#include "host.h"
+#include "panel_window.h"
+#include "tip.h"
+extern "C" {
+#include "xec.h"
+}
+
+panel::panel(panel_window& owner):
+ next_(0),
+ node_(0),
+ owner_(owner)
+{
+}
+
+panel::~panel()
+{
+ delete next_;
+}
+
+panel_factory* panel_factory::factories_[PANEL_MAX_FACTORIES];
+
+panel_factory::panel_factory(int n)
+{
+ if(n < 0 || n >= PANEL_MAX_FACTORIES || factories_[n])
+ fprintf(stderr, "panel_factory::panel_factory: internal error %d\n",n);
+ factories_[n] = this;
+}
+
+panel* panel_factory::create_all(panel_window& w,Widget parent)
+{
+ panel *first = 0;
+ for(int i = 0; i < PANEL_MAX_FACTORIES ; i++)
+ if(factories_[i])
+ {
+ panel* x = factories_[i]->create(w,parent);
+ XtManageChild(x->widget());
+
+ if(x->tools())
+ tip::makeTips(x->tools());
+
+ x->next_ = first;
+ first = x;
+ }
+ return first;
+}
+
+void panel::update()
+{
+ if(owner_.frozen())
+ return;
+
+ if(node_)
+ show(*node_);
+ else
+ clear();
+}
+
+void panel::post_update()
+{
+ if(!owner_.frozen())
+ enable();
+}
+
+void panel::run()
+{
+ update();
+ disable();
+}
+
+void panel::detach()
+{
+ owner_.detach();
+}
+
+void panel::freeze()
+{
+ owner_.freeze();
+}
+
+void panel::hyper(Widget,XtPointer data,node *n)
+{
+ hyperCallbackStruct* cb = (hyperCallbackStruct*)data;
+ if(n == 0) n = get_node();
+ if(n) n = n->find(cb->text);
+
+ if(n == 0)
+ {
+ host* h = host::find(cb->text);
+ if(h) n = h->top();
+ }
+
+ if(n) {
+ if(cb->event->xbutton.button == 2)
+ owner_.new_window(n);
+ else
+ selection::notify_new_selection(n);
+ }
+}
+
+void panel::submit()
+{
+ owner_.submit();
+}
diff --git a/view/src/panel.h b/view/src/panel.h
new file mode 100644
index 0000000..2b140cb
--- /dev/null
+++ b/view/src/panel.h
@@ -0,0 +1,110 @@
+#ifndef panel_H
+#define panel_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "ecflowview.h"
+#include "runnable.h"
+#include "observer.h"
+
+class node;
+class panel_window;
+
+class panel : public runnable, public observer {
+public:
+
+ panel(panel_window&);
+
+ virtual ~panel(); // Change to virtual if base class
+
+ virtual void update();
+ virtual void detach();
+ virtual void freeze();
+ virtual void submit();
+ virtual void post_update();
+
+ virtual void copy(panel*) {}
+
+ virtual void clear() = 0;
+ virtual void show(node&) = 0;
+ virtual void changed(node& n) { show(n); }
+ virtual Boolean enabled(node& n) { return False; }
+
+ virtual const char* name() const { return "(none)"; };
+ virtual Widget widget() = 0;
+ virtual Widget menus(Widget) { return 0; }
+ virtual Widget tools() { return 0; }
+
+
+ virtual void print() {}
+ virtual void save() {}
+
+ virtual bool can_print() { return false; }
+ virtual bool can_save() { return false; }
+
+protected:
+
+ node* get_node() { return node_; }
+ void hyper(Widget,XtPointer, node* = 0);
+
+private:
+
+ panel(const panel&);
+ panel& operator=(const panel&);
+
+ panel* next_;
+ node* node_;
+ panel_window& owner_;
+
+ void run();
+ void notification(observable*) { post_update(); }
+ void gone(observable*) { post_update(); }
+ void adoption(observable*,observable*) { post_update(); }
+
+ friend class panel_factory;
+ friend class panel_window;
+};
+
+inline void destroy(panel**) {}
+
+#ifndef panel_factories_H
+#include "panel_factories.h"
+#endif
+
+class panel_factory {
+ static panel_factory* factories_[PANEL_MAX_FACTORIES];
+public:
+ panel_factory(int);
+ virtual panel* create(panel_window&,Widget) = 0;
+ static panel* create_all(panel_window&,Widget);
+};
+
+template<class T>
+class panel_maker : public panel_factory {
+public:
+ panel_maker(int n) : panel_factory(n) {}
+ virtual panel* create(panel_window&,Widget);
+};
+
+template<class T>
+panel* panel_maker<T>::create(panel_window& w,Widget parent)
+{
+ T* p = new T(w);
+ p->create(parent,(char*)p->name());
+ return p;
+}
+
+#endif
diff --git a/view/src/panel_factories.h b/view/src/panel_factories.h
new file mode 100644
index 0000000..d53b0c6
--- /dev/null
+++ b/view/src/panel_factories.h
@@ -0,0 +1,40 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #4 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#define PANEL_INFO 0
+#define PANEL_MANUAL (PANEL_INFO+1)
+#define PANEL_SCRIPT (PANEL_MANUAL+1)
+#define PANEL_JOB (PANEL_SCRIPT+1)
+#define PANEL_JOBSTATUS (PANEL_JOB+1)
+#define PANEL_OUTPUT (PANEL_JOBSTATUS+1)
+#define PANEL_WHY (PANEL_OUTPUT+1)
+#define PANEL_TRIGGER (PANEL_WHY+1)
+#define PANEL_JOBCHECK (PANEL_TRIGGER+1)
+#define PANEL_TIMETABLE (PANEL_JOBCHECK+1)
+#define PANEL_VARIABLES (PANEL_TIMETABLE+1)
+#define PANEL_EDIT_TASK (PANEL_VARIABLES+1)
+#define PANEL_EDIT_LABEL (PANEL_EDIT_TASK+1)
+#define PANEL_EDIT_LIMIT (PANEL_EDIT_LABEL+1)
+#define PANEL_EDIT_VARIABLE (PANEL_EDIT_LIMIT+1)
+#define PANEL_EDIT_METER (PANEL_EDIT_VARIABLE+1)
+#define PANEL_EDIT_REPEAT (PANEL_EDIT_METER+1)
+#define PANEL_HISTORY (PANEL_EDIT_REPEAT+1)
+#define PANEL_MESSAGES (PANEL_HISTORY+1)
+#define PANEL_SUITES (PANEL_MESSAGES+1)
+#define PANEL_USERS (PANEL_SUITES+1)
+#define PANEL_ZOMBIES (PANEL_USERS+1)
+#define PANEL_ECF_OPTIONS (PANEL_ZOMBIES+1)
+
+#define PANEL_MAX_FACTORIES (PANEL_ECF_OPTIONS+1)
diff --git a/view/src/panel_window.cc b/view/src/panel_window.cc
new file mode 100644
index 0000000..c7c17cf
--- /dev/null
+++ b/view/src/panel_window.cc
@@ -0,0 +1,432 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <stdio.h>
+#include "gui.h"
+#include "panel_window.h"
+#include "panel.h"
+#include "node.h"
+#include "globals.h"
+#include "Tab.h"
+#include <Xm/ToggleB.h>
+#include <Xm/PushB.h>
+
+const char* kDefault = "Info";
+
+extern "C" {
+#include "xec.h"
+}
+
+panel_window::panel_window():
+ panels_(0),
+ node_(0),
+ current_(0)
+{
+ create(gui::top());
+ set_node(0,"Info",true);
+ load_size();
+ XtRealizeWidget(panel_top);
+}
+
+panel_window::panel_window(panel_window* other):
+ panels_(0),
+ node_(0),
+ current_(0)
+{
+ create(gui::top());
+
+ panel* p = panels_;
+ panel* o = other->panels_;
+
+ while(p && o)
+ {
+ p->copy(o);
+ p = p->next_;
+ o = o->next_;
+ }
+
+ other->save_size();
+ set_node(other->node_,XtName(TabGetCurrent(other->tab_)),true);
+ load_size();
+ XtRealizeWidget(panel_top);
+ XmToggleButtonSetState(detached_,other->detached(),True);
+ XmToggleButtonSetState(frozen_,other->frozen(),True);
+ XmToggleButtonSetState(close_on_apply_,
+ XmToggleButtonGetState(other->close_on_apply_),True);
+}
+
+panel_window::panel_window(node* n,bool detached,bool frozen,const char* tab):
+ panels_(0),
+ node_(0),
+ current_(0)
+{
+ create(gui::top());
+ set_node(n,tab,true);
+ load_size();
+ XtRealizeWidget(panel_top);
+ XmToggleButtonSetState(detached_,detached,True);
+ XmToggleButtonSetState(frozen_,frozen,True);
+}
+
+panel_window::panel_window(panel_window* other,node* n,bool detached,bool frozen):
+ panels_(0),
+ node_(0),
+ current_(0)
+{
+ create(gui::top());
+
+ panel* p = panels_;
+ panel* o = other->panels_;
+
+ while(p && o)
+ {
+ p->copy(o);
+ p = p->next_;
+ o = o->next_;
+ }
+
+ other->save_size();
+ set_node(n,XtName(TabGetCurrent(other->tab_)),true);
+ load_size();
+ XtRealizeWidget(panel_top);
+ XmToggleButtonSetState(detached_,detached,True);
+ XmToggleButtonSetState(frozen_,frozen,True);
+}
+
+
+panel_window::~panel_window()
+{
+ save_size();
+ delete panels_;
+ XtDestroyWidget(xd_rootwidget());
+}
+
+void panel_window::save_size()
+{
+ Dimension w,h;
+
+ XtVaGetValues(form_,
+ XmNwidth, &w,
+ XmNheight,&h,
+ NULL);
+
+ char *n = XtName(TabGetCurrent(tab_));
+ char wname[1024]; sprintf(wname,"panel_%s_width", n);
+ char hname[1024]; sprintf(hname,"panel_%s_heigth",n);
+
+ globals::set_resource(wname,w);
+ globals::set_resource(hname,h);
+}
+
+void panel_window::load_size()
+{
+ Dimension w,h;
+
+ char *n = XtName(TabGetCurrent(tab_));
+ char wname[1024]; sprintf(wname,"panel_%s_width", n);
+ char hname[1024]; sprintf(hname,"panel_%s_heigth",n);
+
+ w = globals::get_resource(wname,500);
+ h = globals::get_resource(hname,500);
+
+ XtVaSetValues(form_,
+ XmNwidth, w,
+ XmNheight,h,
+ NULL);
+}
+
+void panel_window::create (Widget parent, char *widget_name)
+{
+ panel_top_c::create(parent,widget_name);
+ panels_ = panel_factory::create_all(*this,tab_);
+ XtAddCallback(tab_, XmNvalueChangedCallback, tabCB, this);
+}
+
+void panel_window::tabCB(Widget w,XtPointer call)
+{
+ TabCallbackStruct* cb = (TabCallbackStruct*)call;
+ set(find(cb->widget));
+ if (!current_) return;
+ if(node_)
+ current_->show(*node_);
+ else
+ current_->clear();
+}
+
+void panel_window::set_tab(const char* tab)
+{
+ panel *p = find(tab);
+ if (p) {
+ TabSetCurrent(tab_,p->widget(),False);
+ current_ = p;
+ }
+}
+
+void panel_window::tabCB(Widget w, XtPointer client, XtPointer call)
+{
+ panel_window* i = (panel_window*)client;
+ i->tabCB(w,call);
+}
+
+void panel_window::selection_cleared()
+{
+ if(detached()) return;
+ set_node(0,0,true);
+}
+
+void panel_window::title()
+{
+ std::string name;
+ name = node_ ? node_->node_name() : "-";
+ if(detached()) name += " (detached)";
+ if(frozen()) name += " (frozen)";
+ XtVaSetValues(xd_rootwidget(),XmNtitle,name.c_str(),NULL);
+
+ if (!current_) return;
+
+ name = std::string(current_->name()) + ":";
+ if (node_)
+ name += node_->node_name();
+ else
+ name += "-";
+ set_menu(name.c_str());
+}
+
+void panel_window::new_selection(node& n)
+{
+ if(detached()) return;
+ set_node(&n,0,true);
+}
+
+void panel_window::set(panel* c)
+{
+ if (!c) return;
+
+ if(current_ && current_ != c)
+ current_->clear();
+
+ current_ = c;
+
+ XtUnmanageChild(tab_);
+
+ Widget w = current_->widget();
+
+ panel* p = panels_;
+ while(p) {
+
+ bool ok = (node_?p->enabled(*node_):false);
+ if(ok)
+ XtManageChild(p->widget());
+ else
+ XtUnmanageChild(p->widget());
+ p = p->next_;
+ }
+
+ if(w && !XtIsManaged(w))
+ {
+ current_ = find(kDefault);
+ w = current_->widget();
+ XtManageChild(w);
+ }
+
+ TabSetCurrent(tab_,w,False);
+
+ p = panels_;
+ while(p) {
+ Widget m = p->menus(menubar_);
+ if(m) {
+ if(p == current_)
+ XtManageChild(m);
+ else
+ XtUnmanageChild(m);
+ }
+ p = p->next_;
+ }
+
+ XtManageChild(tab_);
+
+ XtSetSensitive(save_,current_->can_save());
+ XtSetSensitive(print_,current_->can_print());
+}
+
+void panel_window::cloneCB(Widget w,XtPointer)
+{
+ panel_window *p = new panel_window(this);
+ p->xd_show();
+}
+
+void panel_window::unmapCB(Widget,XtPointer)
+{
+ delete this;
+}
+
+void panel_window::mapCB(Widget,XtPointer)
+{
+}
+
+void panel_window::nodeCB(Widget,XtPointer data)
+{
+// XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct*) data;
+ /* detached_ = !cb->set; */
+ title();
+}
+
+void panel_window::freezeCB(Widget,XtPointer data)
+{
+// XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct*) data;
+ /* frozen_ = !cb->set; */
+ title();
+}
+
+void panel_window::xd_show()
+{
+ Map();
+}
+
+void panel_window::notification(observable* n)
+{
+ set(current_);
+ current_->changed(*node_);
+}
+
+void panel_window::gone(observable* n)
+{
+ set_node(0,0,true);
+}
+
+void panel_window::adoption(observable* o,observable *n)
+{
+ set_node((node*)n,0,!frozen());
+}
+
+panel* panel_window::find(Widget w)
+{
+ if(!w) w = TabGetCurrent(tab_);
+ panel* p = panels_;
+ while(p)
+ {
+ if(p->widget() == w)
+ return p;
+ p = p->next_;
+ }
+ return 0;
+}
+
+void panel_window::set_node(node* n,const char* tab,bool update)
+{
+ // if(n == node_) return;
+
+ forget(node_);
+
+ panel* p = panels_;
+ while(p)
+ {
+ p->node_ = n;
+ p = p->next_;
+ }
+ node_ = n;
+ observe(node_);
+
+ if(tab) set_tab(tab);
+ if(n && !current_->enabled(*n))
+ set_tab(kDefault);
+
+ if(update) {
+ if(n)
+ current_->show(*n);
+ else
+ current_->clear();
+ set(current_);
+ title();
+ }
+}
+
+void panel_window::detach()
+{
+ XmToggleButtonSetState(detached_,True, True);
+}
+
+void panel_window::freeze()
+{
+ XmToggleButtonSetState(detached_,True, True);
+ XmToggleButtonSetState(frozen_,True,True);
+}
+
+
+void panel_window::new_window(node* n,const char* tab,bool detached,bool frozen)
+{
+ panel_window *p = new panel_window(n,detached,frozen,tab);
+ p->xd_show();
+}
+
+void panel_window::new_window(node* n)
+{
+ panel_window *p = new panel_window(this,n,true,true);
+ p->xd_show();
+}
+
+panel* panel_window::find(const char* name)
+{
+ panel* p = panels_;
+ while(p)
+ {
+ bool ok = node_?p->enabled(*node_):false;
+ if(ok && (strcmp(p->name(),name) == 0))
+ return p;
+ p = p->next_;
+ }
+
+ p = panels_;
+ while(p)
+ {
+ if(strcmp(p->name(),kDefault) == 0)
+ return p;
+ p = p->next_;
+ }
+
+ abort();
+ return 0;
+}
+
+void panel_window::submit()
+{
+ if(XmToggleButtonGetState(close_on_apply_))
+ delete this;
+}
+
+void panel_window::resizeCB(Widget,XtPointer)
+{
+ save_size();
+}
+
+bool panel_window::frozen()
+{
+ return XmToggleButtonGetState(frozen_);
+}
+
+bool panel_window::detached()
+{
+ return XmToggleButtonGetState(detached_);
+}
+
+void panel_window::printCB(Widget,XtPointer)
+{
+ current_->print();
+}
+
+void panel_window::saveCB(Widget,XtPointer)
+{
+ current_->save();
+}
diff --git a/view/src/panel_window.h b/view/src/panel_window.h
new file mode 100644
index 0000000..8f240ca
--- /dev/null
+++ b/view/src/panel_window.h
@@ -0,0 +1,118 @@
+#ifndef panel_window_H
+#define panel_window_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#ifndef uipanel_H
+#include "uipanel.h"
+#endif
+
+#ifndef selection_H
+#include "selection.h"
+#endif
+
+#ifndef panel_H
+#include "panel.h"
+#endif
+
+#ifndef observer_H
+#include "observer.h"
+#endif
+
+#ifndef window_H
+#include "window.h"
+#endif
+
+
+class panel_window
+ : public panel_top_c
+ , public selection
+ , public observer
+ , public window
+{
+public:
+ panel_window();
+ panel_window(node*,bool,bool,const char*);
+ panel_window(panel_window*);
+ panel_window(panel_window*,node*,bool,bool);
+
+ ~panel_window(); // Change to virtual if base class
+
+ bool frozen();
+ bool detached();
+
+ void detach();
+ void freeze();
+
+ void title();
+ void show(const char*);
+ void new_window( node*);
+ void submit();
+
+ virtual void create (Widget parent, char *widget_name = 0);
+ virtual Widget shell() { return _xd_rootwidget; }
+
+ // From selection
+ virtual void new_selection(node&);
+ virtual void selection_cleared();
+
+ // From panel_top_c
+ void cloneCB(Widget,XtPointer);
+ void unmapCB(Widget,XtPointer);
+ void mapCB(Widget,XtPointer);
+ void nodeCB(Widget,XtPointer);
+ void freezeCB(Widget,XtPointer);
+ void resizeCB(Widget,XtPointer);
+
+ virtual void xd_show();
+
+ static panel_window* find(node*);
+ static void new_window(node*,const char*,bool,bool);
+
+private:
+ panel_window(const panel_window&);
+ panel_window& operator=(const panel_window&);
+
+ panel* panels_;
+ node* node_;
+ panel* current_;
+
+ void set(panel*);
+ void set_tab(const char*);
+ void copy(panel_window&);
+ virtual void tabCB(Widget,XtPointer);
+
+ void set_node(node*,const char*,bool);
+
+ panel* find(const char*);
+ panel* find(Widget);
+
+ void save_size();
+ void load_size();
+
+ // From observer<node>
+ virtual void notification(observable*);
+ virtual void gone(observable*);
+ virtual void adoption(observable*,observable*);
+
+ virtual void printCB(Widget,XtPointer);
+ virtual void saveCB(Widget,XtPointer);
+
+ static void tabCB(Widget,XtPointer,XtPointer);
+};
+
+inline void destroy(panel_window**) {}
+#endif
diff --git a/view/src/parser.cc b/view/src/parser.cc
new file mode 100644
index 0000000..d4f0484
--- /dev/null
+++ b/view/src/parser.cc
@@ -0,0 +1,101 @@
+
+#ifndef parser_H
+#include "parser.h"
+#endif
+
+#ifndef gui_H
+#include "gui.h"
+#endif
+
+#ifndef menus_H
+#include "menus.h"
+#endif
+
+#ifndef log_event_H
+#include "log_event.h"
+#endif
+
+#if 0
+#ifndef __sgi
+inline const char* gettxt(const char* a,const char* b) { return b; }
+#endif
+#endif
+
+/* #define YYDEBUG */
+/* #ifdef linux
+#undef YYDEBUG
+#endif
+*/
+#ifndef error_H
+#include "error.h"
+#endif
+
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+extern "C" {
+ extern int yylineno;
+ extern int yydebug;
+ extern int yyone;
+ extern FILE* yyin;
+ extern int yyparse();
+}
+
+void parser::parse(const char* fname)
+{
+ char buf[1024];
+
+ yydebug = getenv("YYDEBUG") != 0;
+ yylineno = 0;
+
+ int z = strlen(fname);
+ if(fname[z-1] == 'Z' && fname[z-2] == '.')
+ {
+ sprintf(buf,"|zcat %s",fname);
+ fname = buf;
+ }
+
+ if(fname[z-1] == 'z' && fname[z-2] == 'g' && fname[z-3] == '.')
+ {
+ sprintf(buf,"|zcat %s",fname);
+ fname = buf;
+ }
+
+ yyin = (fname[0] == '|') ? popen(fname+1,"r") : fopen(fname, "r");
+ if(yyin)
+ {
+ yyparse();
+ if(fname[0] == '|') pclose(yyin); else fclose(yyin);
+ }
+ else gui::syserr(fname);
+}
+
+void parser::parse(FILE *f)
+{
+ extern int yylineno;
+ yylineno = 0;
+ yydebug = getenv("YYDEBUG") != 0;
+ yyin = f;
+ yyparse();
+}
+
+void parser::parse1(FILE *f)
+{
+ yyone = 1;
+ yydebug = getenv("YYDEBUG") != 0;
+ yyparse();
+ yyone = 0;
+}
diff --git a/view/src/parser.h b/view/src/parser.h
new file mode 100644
index 0000000..fabe619
--- /dev/null
+++ b/view/src/parser.h
@@ -0,0 +1,125 @@
+#ifndef parser_H
+#define parser_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+// Headers
+// #ifndef machine_H
+// #include <machine.h>
+// #endif
+
+// Forward declarations
+
+// class ostream;
+// typedef class _Pvts os_typespec; // Remove if not persistant
+
+//
+
+#include <stdio.h>
+
+class parser {
+public:
+
+// -- Exceptions
+ // None
+
+// -- Contructors
+
+ parser();
+
+// -- Destructor
+
+ ~parser(); // Change to virtual if base class
+
+// -- Convertors
+ // None
+
+// -- Operators
+ // None
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+
+ static void parse(const char*);
+ static void parse(FILE*);
+ static void parse1(FILE*);
+
+// -- Class methods
+ // None
+
+ // Uncomment for persistent, remove otherwise
+ // static os_typespec* get_os_typespec();
+
+protected:
+
+// -- Members
+ // None
+
+// -- Methods
+
+ // void print(ostream&) const; // Change to virtual if base class
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+private:
+
+// No copy allowed
+
+ parser(const parser&);
+ parser& operator=(const parser&);
+
+// -- Members
+ // None
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+// -- Friends
+
+ //friend ostream& operator<<(ostream& s,const parser& p)
+ // { p.print(s); return s; }
+
+};
+
+inline void destroy(parser**) {}
+
+// If persistent, uncomment, otherwise remove
+//#ifdef _ODI_OSSG_
+//OS_MARK_SCHEMA_TYPE(parser);
+//#endif
+
+#endif
diff --git a/view/src/passwrd.cc b/view/src/passwrd.cc
new file mode 100644
index 0000000..72a9f91
--- /dev/null
+++ b/view/src/passwrd.cc
@@ -0,0 +1,71 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <stdio.h>
+#include <stdarg.h>
+#include "passwrd.h"
+#include "gui.h"
+#include "str.h"
+extern "C" {
+#include "xec.h"
+}
+#include "ecflowview.h"
+
+#include <Xm/Text.h>
+
+#ifdef linux
+extern "C" char* cuserid(char*);
+#endif
+
+
+passwrd::passwrd()
+{
+ create(gui::top());
+}
+
+passwrd::~passwrd()
+{
+}
+
+
+Boolean passwrd::ask(const str& title,str& user,str& pass)
+{
+ return instance().prompt(title,user,pass);
+}
+
+Boolean passwrd::prompt(const str& title,str& user,str& pass)
+{
+
+ XmTextSetString(user_,(char*)(user.c_str()[0]?user.c_str():cuserid(0)));
+ XmTextSetString(passwd_,(char*)(pass.c_str()));
+
+ if(modal(title.c_str(),True))
+ {
+ char *p = XmTextGetString(user_);
+ user = p;
+ XtFree(p);
+
+ p = XmTextGetString(passwd_);
+ pass = p;
+ XtFree(p);
+ return True;
+ }
+
+ return False;
+}
+
+void passwrd::modifyCB( Widget, XtPointer )
+{
+}
diff --git a/view/src/passwrd.h b/view/src/passwrd.h
new file mode 100644
index 0000000..028776f
--- /dev/null
+++ b/view/src/passwrd.h
@@ -0,0 +1,116 @@
+#ifndef passwrd_H
+#define passwrd_H
+
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "uipasswd.h"
+#include "dialog.h"
+
+class str;
+
+class passwrd : public dialog<passwrd,passwd_shell_c> {
+public:
+
+// -- Exceptions
+ // None
+
+// -- Contructors
+
+ passwrd();
+
+// -- Destructor
+
+ ~passwrd(); // Change to virtual if base class
+
+// -- Convertors
+ // None
+
+// -- Operators
+ // None
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+
+ static Boolean ask(const str&,str&,str&);
+
+ // Uncomment for persistent, remove otherwise
+ // static os_typespec* get_os_typespec();
+
+protected:
+
+// -- Members
+ // None
+
+// -- Methods
+
+ // void print(ostream&) const; // Change to virtual if base class
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+private:
+
+// No copy allowed
+
+ passwrd(const passwrd&);
+ passwrd& operator=(const passwrd&);
+
+
+
+// -- Methods
+
+ Boolean prompt(const str&,str&,str&);
+
+// -- Overridden methods
+
+ virtual void modifyCB( Widget, XtPointer );
+
+// -- Class members
+
+
+// -- Class methods
+ // None
+
+// -- Friends
+
+ //friend ostream& operator<<(ostream& s,const passwrd& p)
+ // { p.print(s); return s; }
+
+};
+
+inline void destroy(passwrd**) {}
+
+// If persistent, uncomment, otherwise remove
+//#ifdef _ODI_OSSG_
+//OS_MARK_SCHEMA_TYPE(passwrd);
+//#endif
+
+#endif
diff --git a/ecflow_4_0_7/view/src/patch.pl b/view/src/patch.pl
similarity index 100%
rename from ecflow_4_0_7/view/src/patch.pl
rename to view/src/patch.pl
diff --git a/view/src/persist.cc b/view/src/persist.cc
new file mode 100644
index 0000000..519fabe
--- /dev/null
+++ b/view/src/persist.cc
@@ -0,0 +1,149 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "ecflowview.h"
+#include "persist.h"
+
+persist::persist(const char* kind,const char* name):
+ kind_(kind),
+ name_(name),
+ f_(0),
+ write_(0)
+{
+}
+
+persist::~persist()
+{
+ close();
+}
+
+void persist::close()
+{
+ if(f_) {
+ if(fclose(f_))
+ perror("persist::~persist");
+ }
+}
+
+bool persist::open(bool w)
+{
+ if(w != write_ || f_ == 0)
+ {
+ close();
+
+ char buf[1024];
+ const char * rcdir = getenv("ECFLOWRC") ? getenv("ECFLOWRC") : "ecflowrc";
+
+ sprintf(buf,"%s/.%s/%s.%s",rcdir, getenv("HOME"),kind_,name_);
+
+ f_ = fopen(buf, w ? "w" : "r");
+ if(!f_) perror(buf);
+
+ write_ = w;
+
+ }
+ return f_ != 0;
+}
+
+
+void persist::set(const char* p,int n)
+{
+ if(!open(true)) return;
+ fprintf(f_,"%s: %d\n",p,n);
+}
+
+void persist::set(const char* p,const char* s)
+{
+ if(!open(true)) return;
+ fprintf(f_,"%s: %s\n",p,s);
+}
+
+/*
+void persist::set(const char* p,sms_list* l)
+{
+ if(!open(true)) return;
+
+ while(l)
+ {
+ fprintf(f_,"%s: %s\n",p,l->name);
+ l = l->next;
+ }
+}
+
+bool persist::get(const char* p,sms_list*& l)
+{
+ if(!open(false)) return false;
+ rewind(f_);
+
+ l = 0;
+ const char* x;
+ while(( x = read(p)))
+ {
+ sms_list *m = (sms_list*)ecf_node_create((char*)x);
+ m->next = l;
+ l = m;
+ }
+
+ return l != 0;
+
+}
+*/
+
+bool persist::get(const char* p,int& n)
+{
+ if(!open(false)) return false;
+ rewind(f_);
+
+ const char* x;
+
+ if(( x = read(p)))
+ {
+ n = atoi(x);
+ return true;
+ }
+ return false;
+}
+
+bool persist::get(const char* p, char* n)
+{
+ if(!open(false)) return false;
+ rewind(f_);
+ const char* x;
+ if(( x = read(p)))
+ {
+ strcpy(n,x);
+ return true;
+ }
+ return false;
+}
+
+const char* persist::read(const char* p)
+{
+
+ static char line[1024];
+ int len = strlen(p);
+
+ for(;;)
+ {
+ if(!fgets(line,sizeof(line),f_))
+ return 0;
+
+ line[strlen(line)-1] = 0;
+
+ if(line[len] == ':' && strncmp(line,p,len) == 0)
+ return line + len + 2;
+
+ }
+}
diff --git a/view/src/persist.h b/view/src/persist.h
new file mode 100644
index 0000000..daafc59
--- /dev/null
+++ b/view/src/persist.h
@@ -0,0 +1,139 @@
+#ifndef persist_H
+#define persist_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+// Headers
+// #ifndef machine_H
+// #include <machine.h>
+// #endif
+
+// Forward declarations
+
+// class ostream;
+// typedef class _Pvts os_typespec; // Remove if not persistant
+
+//
+#ifdef NO_BOOL
+#include "bool.h"
+#endif
+
+struct sms_list;
+
+class persist {
+public:
+
+// -- Exceptions
+ // None
+
+// -- Contructors
+
+ persist(const char* kind,const char* name);
+
+// -- Destructor
+
+ ~persist(); // Change to virtual if base class
+
+// -- Convertors
+ // None
+
+// -- Operators
+ // None
+
+// -- Methods
+
+ void set(const char*,const char*);
+ void set(const char*,int);
+ void set(const char*,sms_list*);
+
+ bool get(const char*,char*);
+ bool get(const char*,int&);
+ bool get(const char*,sms_list*&);
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+ // Uncomment for persistent, remove otherwise
+ // static os_typespec* get_os_typespec();
+
+protected:
+
+// -- Members
+ // None
+
+// -- Methods
+
+ // void print(ostream&) const; // Change to virtual if base class
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+private:
+
+// No copy allowed
+
+ persist(const persist&);
+ persist& operator=(const persist&);
+
+// -- Members
+
+ const char* kind_;
+ const char* name_;
+ FILE *f_;
+ bool write_;
+
+// -- Methods
+
+ bool open(bool);
+ void close();
+ const char* read(const char*);
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+// -- Friends
+
+ //friend ostream& operator<<(ostream& s,const persist& p)
+ // { p.print(s); return s; }
+
+};
+
+inline void destroy(persist**) {}
+
+// If persistent, uncomment, otherwise remove
+//#ifdef _ODI_OSSG_
+//OS_MARK_SCHEMA_TYPE(persist);
+//#endif
+
+#endif
diff --git a/view/src/pixmap.cc b/view/src/pixmap.cc
new file mode 100644
index 0000000..620b92a
--- /dev/null
+++ b/view/src/pixmap.cc
@@ -0,0 +1,103 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <X11/xpm.h>
+#include <ctype.h>
+#include "pixmap.h"
+#include "gui.h"
+#include "directory.h"
+
+pixmap::pixmap(const char* name):
+ pixmap_(0),
+ name_(clean(name)),
+ bits_(0)
+{
+}
+
+pixmap::pixmap(const char* name,const char** bits):
+ pixmap_(0),
+ name_(clean(name)),
+ bits_(bits)
+{
+}
+
+
+pixmap::~pixmap()
+{
+}
+
+pixmap& pixmap::find(const char* name)
+{
+ pixmap *r = first();
+ const char* n = clean(name);
+ while(r)
+ {
+ if(strcmp(n,r->name_.c_str()) == 0)
+ return *r;
+ r = r->next();
+ }
+ return *(new pixmap(name));
+}
+
+void pixmap::set_label(Widget w)
+{
+ XtVaSetValues(w,
+ XmNlabelType, XmPIXMAP,
+ XmNlabelPixmap,pixels(),
+ NULL);
+}
+
+Pixmap pixmap::pixels()
+{
+ if(pixmap_) return pixmap_;
+
+ XpmAttributes xpm_attributes;
+ xpm_attributes.valuemask = XpmCloseness;
+ xpm_attributes.closeness = 65535;
+
+ Display* dpy = XtDisplay(gui::top());
+
+ if(bits_)
+ {
+ if(XpmCreatePixmapFromData(dpy,
+ DefaultRootWindow(dpy),
+ (char**)bits_,&pixmap_,0,&xpm_attributes))
+ pixmap_ = XmUNSPECIFIED_PIXMAP;
+ }
+ else {
+ char buf[1024];
+ sprintf(buf,"%s/icons/%s.xpm",directory::system(),name_.c_str());
+
+ if(XpmReadFileToPixmap(dpy,
+ DefaultRootWindow(dpy),
+ buf, &pixmap_, 0, &xpm_attributes))
+ {
+ pixmap_ = XmUNSPECIFIED_PIXMAP;
+ }
+ }
+
+ return pixmap_;
+}
+
+const char* pixmap::clean(const char* s)
+{
+ static char n[1024];
+ strcpy(n,s);
+ char *p = n;
+ while(*p) { if(!isalnum(*p)) *p = '_'; p++; }
+ return n;
+}
+
+IMP(pixmap)
diff --git a/view/src/pixmap.h b/view/src/pixmap.h
new file mode 100644
index 0000000..5b5c025
--- /dev/null
+++ b/view/src/pixmap.h
@@ -0,0 +1,53 @@
+#ifndef pixmap_H
+#define pixmap_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include <Xm/Xm.h>
+
+#ifndef extent_H
+#include "extent.h"
+#endif
+
+#ifndef str_H
+#include "str.h"
+#endif
+
+
+class pixmap : public extent<pixmap> {
+public:
+ pixmap(const char*);
+ pixmap(const char*,const char**);
+ ~pixmap(); // Change to virtual if base class
+
+ Pixmap pixels();
+ void set_label(Widget);
+
+ static pixmap& find(const char*);
+
+private:
+ pixmap(const pixmap&);
+ pixmap& operator=(const pixmap&);
+
+ Pixmap pixmap_;
+ str name_;
+ const char** bits_;
+
+ static const char* clean(const char*);
+};
+
+inline void destroy(pixmap**) {}
+#endif
diff --git a/view/src/pref_editor.cc b/view/src/pref_editor.cc
new file mode 100644
index 0000000..b401d13
--- /dev/null
+++ b/view/src/pref_editor.cc
@@ -0,0 +1,87 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "pref_editor.h"
+#include "node.h"
+#include "host.h"
+#include "ecflowview.h"
+#include "str.h"
+#include <Xm/Label.h>
+#include <Xm/Text.h>
+#include <Xm/ToggleB.h>
+extern "C" {
+#include "xec.h"
+}
+
+
+void pref_editor::init(resource& x)
+{
+ Widget w = find(x.name().c_str()); if(!w) return;
+ x.initWidget(w);
+ sensitive(w,x.name().c_str(),x.isSet());
+}
+
+void pref_editor::sensitive(Widget w, const char* n, bool set)
+{
+ Widget p = toggle(n); if(!p) return;
+ XtSetSensitive(w,set);
+ XmToggleButtonSetState(p,!set,False);
+}
+
+Widget pref_editor::toggle(const char* n)
+{
+ char buf[1024];
+ sprintf(buf,"@%s",n);
+ return find(buf);
+}
+
+bool pref_editor::modified(resource& x)
+{
+ Widget w = find(x.name().c_str()); if(!w) return false;
+ bool on = XtIsSensitive(w);
+
+ if(on != x.isSet())
+ {
+ x.setset(on);
+ if(on) x.readWidget(w);
+ return true;
+ }
+
+
+ return on ? x.readWidget(w) : false;
+}
+
+void pref_editor::changed(Widget w)
+{
+ configurable* c = owner();
+ if(c)
+ {
+ resource::modified(*c,*this);
+ resource::init(*c,*this);
+ }
+}
+
+void pref_editor::use(Widget w)
+{
+ bool s = XmToggleButtonGetState(w);
+ char* p = XtName(w);
+
+
+ Widget z = find(p+1);
+ if(z) XtSetSensitive(z,!s);
+
+ changed(w);
+}
+
diff --git a/view/src/pref_editor.h b/view/src/pref_editor.h
new file mode 100644
index 0000000..c09d2aa
--- /dev/null
+++ b/view/src/pref_editor.h
@@ -0,0 +1,55 @@
+#ifndef pref_editor_H
+#define pref_editor_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include <Xm/Xm.h>
+
+#ifndef option_H
+#include "option.h"
+#endif
+
+#ifndef configurator_H
+#include "configurator.h"
+#endif
+
+#ifndef editor_H
+#include "editor.h"
+#endif
+
+class configurable;
+
+class pref_editor : public configurator, public editor {
+public:
+
+ virtual configurable* owner() = 0;
+
+ virtual void init(resource&);
+ virtual bool modified(resource&);
+
+protected:
+
+ void changed(Widget);
+ void use(Widget);
+
+private:
+
+ void sensitive(Widget,const char*,bool);
+ Widget toggle(const char* n);
+};
+
+inline void destroy(pref_editor**) {}
+#endif
diff --git a/view/src/pref_window.cc b/view/src/pref_window.cc
new file mode 100644
index 0000000..fe6863e
--- /dev/null
+++ b/view/src/pref_window.cc
@@ -0,0 +1,54 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "pref_window.h"
+#include "gui.h"
+#include "prefs.h"
+
+pref_window& pref_window::instance()
+{
+ static pref_window *m = new pref_window();
+ return *m;
+}
+
+pref_window::pref_window()
+{
+ create(gui::top());
+ prefs::create_all(tab_);
+}
+
+pref_window::~pref_window()
+{
+}
+
+void pref_window::closeCB(Widget,XtPointer)
+{
+ XtUnmanageChild(form_);
+}
+
+void pref_window::mapCB(Widget,XtPointer)
+{
+}
+
+void pref_window::raise()
+{
+ XtManageChild(form_);
+ XMapRaised(XtDisplay(_xd_rootwidget),XtWindow(_xd_rootwidget));
+}
+
+void pref_window::show()
+{
+ instance().raise();
+}
diff --git a/view/src/pref_window.h b/view/src/pref_window.h
new file mode 100644
index 0000000..fd3eba3
--- /dev/null
+++ b/view/src/pref_window.h
@@ -0,0 +1,51 @@
+#ifndef pref_window_H
+#define pref_window_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "uipref.h"
+
+class pref_window : public pref_shell_c {
+public:
+
+ pref_window();
+
+ ~pref_window(); // Change to virtual if base class
+
+ static void show();
+
+private:
+
+ pref_window(const pref_window&);
+ pref_window& operator=(const pref_window&);
+
+ void raise();
+
+ static pref_window& instance();
+
+ void closeCB(Widget,XtPointer);
+ void mapCB(Widget,XtPointer);
+
+ /* void searchCB(Widget,XtPointer); */
+ /* void whatCB(Widget,XtPointer); */
+ /* void whereCB(Widget,XtPointer); */
+ /* void statusCB(Widget,XtPointer); */
+ /* void typeCB(Widget,XtPointer); */
+ /* void specialCB(Widget,XtPointer); */
+};
+
+inline void destroy(pref_window**) {}
+#endif
diff --git a/view/src/prefs.cc b/view/src/prefs.cc
new file mode 100644
index 0000000..e4a81c1
--- /dev/null
+++ b/view/src/prefs.cc
@@ -0,0 +1,41 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "prefs.h"
+#include "globals.h"
+#include "resource.h"
+
+void prefs::create_all(Widget w)
+{
+ prefs* p = first();
+ while(p)
+ {
+ p->create(w);
+ XtManageChild(p->widget());
+ p = p->next();
+ }
+}
+
+void prefs::setup(Widget w)
+{
+ resource::init(*owner(),*this);
+}
+
+configurable* prefs::owner()
+{
+ return globals::instance();
+}
+
+IMP(prefs)
diff --git a/view/src/prefs.h b/view/src/prefs.h
new file mode 100644
index 0000000..22f30cc
--- /dev/null
+++ b/view/src/prefs.h
@@ -0,0 +1,126 @@
+#ifndef prefs_H
+#define prefs_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+// Headers
+// #ifndef machine_H
+// #include <machine.h>
+// #endif
+
+// Forward declarations
+
+// class ostream;
+// typedef class _Pvts os_typespec; // Remove if not persistant
+
+//
+
+#ifndef extent_H
+#include "extent.h"
+#endif
+
+#ifndef pref_editor_H
+#include "pref_editor.h"
+#endif
+
+
+class prefs : public extent<prefs>, public pref_editor {
+public:
+
+// -- Exceptions
+ // None
+
+// -- Contructors
+
+ prefs() {};
+
+// -- Destructor
+
+
+// -- Convertors
+ // None
+
+// -- Operators
+ // None
+
+// -- Methods
+
+ virtual void create(Widget,char* = 0) = 0;
+ virtual Widget widget() = 0;
+
+
+ void setup(Widget);
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+
+ static void create_all(Widget);
+
+ // Uncomment for persistent, remove otherwise
+ // static os_typespec* get_os_typespec();
+
+protected:
+
+// -- Members
+
+
+// -- Methods
+
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+private:
+
+// No copy allowed
+
+ prefs(const prefs&);
+ prefs& operator=(const prefs&);
+
+// -- Members
+
+// -- Methods
+
+
+// -- Overridden methods
+ // None
+
+ virtual Widget form() { return widget(); }
+ virtual configurable* owner();
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+// -- Friends
+
+
+};
+
+#endif
diff --git a/view/src/re.h b/view/src/re.h
new file mode 100644
index 0000000..422ff6b
--- /dev/null
+++ b/view/src/re.h
@@ -0,0 +1,54 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#if defined(linux) || defined(alpha)
+#include <regex.h>
+
+
+class re {
+ regex_t re_;
+ char *loc_;
+public:
+ re(const char* r): loc_(0) { regcomp(&re_,r,0); }
+
+ ~re() { regfree(&re_); }
+
+ char* match(char* a,char* b)
+ {
+ regmatch_t pmatch;
+ if(!regexec(&re_,a,1,&pmatch,0))
+ return 0;
+
+ loc_ = a+pmatch.rm_so;
+ return a+pmatch.rm_eo;
+ }
+
+ char* loc() { return loc_; }
+};
+
+#else
+#include <stdlib.h>
+#include <libgen.h>
+
+class re {
+ char *re_;
+public:
+ re(const char* r) : re_(::regcmp(r,0)) {}
+ ~re() { ::free(re_); }
+ char* match(char* a,char* b) { return ::regex(a,b); }
+ char* loc() { return ::__loc1; }
+};
+
+#endif
diff --git a/view/src/reach.cc b/view/src/reach.cc
new file mode 100644
index 0000000..914e1a8
--- /dev/null
+++ b/view/src/reach.cc
@@ -0,0 +1,255 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "arch.h"
+#include "reach.h"
+#include "node.h"
+#include "array.h"
+#include "node_lister.h"
+#include "trigger_lister.h"
+#include "host.h"
+
+struct path {
+
+ bool use_;
+ bool mark_;
+ bool ignore_;
+
+ node* from_;
+ node* to_;
+ node* through_;
+ int mode_;
+ node* trigger_;
+
+ path(node* from = 0, node* to = 0,node* through = 0, int mode = 0,node *trigger = 0):
+ use_(false), mark_(false), ignore_(false), from_(from),to_(to),through_(through),mode_(mode), trigger_(trigger)
+ {}
+
+#ifdef AIX
+ bool operator==(const path&) { return 0; }
+#endif
+};
+
+struct trigger_collector : public trigger_lister {
+
+static array<path> paths_;
+
+ array<node*> nodes_;
+ int count_;
+ bool triggered_;
+ node* current_;
+
+ trigger_collector(node *n): count_(0),triggered_(0),current_(0)
+ { add(n); add_all(n->kids()); }
+
+ void next_node(node& n,node*,int,node*);
+ void add(node*);
+ void add_all(node*);
+ void add(node*,node*,node*,int,node*);
+
+ void mode(node* c,bool t) { current_ = c; triggered_ = t; }
+
+ Boolean kids() { return True; }
+ Boolean parents() { return True; }
+};
+
+array<path> trigger_collector::paths_;
+
+void trigger_collector::next_node(node& n,node* th,int mode,node* tr)
+{
+ add(&n);
+ if(triggered_)
+ add(current_,&n,th,mode,tr);
+ else
+ add(&n,current_,th,mode,tr);
+}
+
+void trigger_collector::add(node* from, node* to,node* through, int mode,node *trigger)
+{
+#if 0
+ if(through)
+ {
+ if(from->is_my_parent(through) || through->is_my_parent(from))
+ paths_.add( path(from,through,0,trigger_lister::hierarchy,0) );
+ else
+ paths_.add( path(from,through,0,mode,trigger) );
+
+ if(to->is_my_parent(through) || through->is_my_parent(to))
+ paths_.add( path(through,to,0,trigger_lister::hierarchy,0) );
+ else
+ paths_.add( path(through,to,0,mode,trigger) );
+
+ }
+ else
+#endif
+ paths_.add( path(from,to,through,mode,trigger) );
+}
+
+void trigger_collector::add(node* n)
+{
+ for(int i = 0; i < nodes_.count(); i++)
+ if(nodes_[i] == n)
+ return;
+ nodes_.add(n);
+}
+
+void trigger_collector::add_all(node* k)
+{
+ while(k)
+ {
+ add(k);
+ add_all(k->kids());
+ k = k->next();
+ }
+}
+
+/*
+static bool sect(trigger_collector& a,trigger_collector& b)
+{
+ for(int i = 0; i < a.nodes_.count(); i++)
+ for(int j = 0; j < b.nodes_.count(); j++)
+ if(a.nodes_[i] == b.nodes_[j])
+ return true;
+ return false;
+}
+*/
+static bool can_reach(node* from,node* to)
+{
+ bool ok = false;
+
+ if(from == to)
+ return true;
+
+ for(int i = 0; i < trigger_collector::paths_.count(); i++)
+ {
+ path& p = trigger_collector::paths_[i];
+ if(!p.ignore_ && !p.mark_ && from == p.from_) {
+ if(p.use_)
+ ok = true;
+ else
+ {
+ p.mark_ = true;
+ if(can_reach(p.to_,to))
+ ok = p.use_ = true;
+ else
+ p.ignore_ = true;
+ p.mark_ = false;
+ }
+ }
+ }
+ return ok;
+}
+
+// Not used ?
+//static void fill(node* p,node* k)
+//{
+// while(k)
+// {
+//
+// trigger_collector::paths_.add( path(p,k,0,
+// trigger_lister::hierarchy,0) );
+// trigger_collector::paths_.add( path(k,p,0,
+// trigger_lister::hierarchy,0) );
+// fill(k,k->kids());
+// k = k->next();
+// }
+//}
+
+bool reach::join(node* a,node* b,reach_lister& rl)
+{
+
+ if(!a || !b) return false;
+
+ trigger_collector::paths_.clear();
+
+ node* top = a->serv().top();
+ if(top != b->serv().top())
+ return false;
+
+ trigger_collector ta(a);
+ trigger_collector tb(b);
+
+ /* while( ! sect(ta,tb) ) */
+ for(;;)
+ {
+ printf("0\n");
+
+ int abefore = ta.count_;
+ int bbefore = tb.count_;
+
+ ta.count_ = ta.nodes_.count();
+ tb.count_ = tb.nodes_.count();
+
+ int aafter = ta.count_;
+ int bafter = tb.count_;
+ int i;
+
+ for(i = abefore ; i < aafter; i++)
+ {
+ ta.mode(ta.nodes_[i],true);
+ ta.nodes_[i]->triggered(ta);
+ }
+
+ for(i = bbefore ; i < bafter; i++)
+ {
+ tb.mode(tb.nodes_[i],false);
+ tb.nodes_[i]->triggers(tb);
+ }
+
+ printf("%d %d %d %d\n",abefore,aafter,bbefore,bafter);
+
+ if(abefore == aafter && bbefore == bafter)
+ {
+ /* trigger_collector::paths_.clear(); */
+ break;
+ //return false;
+ }
+ }
+
+
+ printf("1\n");
+ can_reach(a,b);
+ printf("2\n");
+#if 0
+ for(int i = 0; i < ta.nodes_.count(); i++)
+ rl.next(ta.nodes_[i]);
+
+ for( i = 0; i < tb.nodes_.count(); i++)
+ rl.next(tb.nodes_[i]);
+#endif
+
+ int x =0;
+ int i;
+ for(i = 0; i < trigger_collector::paths_.count(); i++)
+ {
+ path& p = trigger_collector::paths_[i];
+ if(p.use_)
+ x++;
+ }
+
+ printf("paths %d\n",x);
+
+ for(i = 0; i < trigger_collector::paths_.count(); i++)
+ {
+ path& p = trigger_collector::paths_[i];
+ if(p.use_)
+ rl.next(p.from_,p.to_,p.through_,p.mode_,p.trigger_);
+
+ }
+ trigger_collector::paths_.clear();
+ return false;
+}
+
+
diff --git a/view/src/reach.h b/view/src/reach.h
new file mode 100644
index 0000000..4c2ed66
--- /dev/null
+++ b/view/src/reach.h
@@ -0,0 +1,48 @@
+#ifndef reach_H
+#define reach_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#ifdef NO_BOOL
+#include "bool.h"
+#endif
+
+// Headers
+// #ifndef machine_H
+// #include <machine.h>
+// #endif
+
+// Forward declarations
+
+// class ostream;
+// typedef class _Pvts os_typespec; // Remove if not persistant
+
+//
+
+class node;
+class reach_lister {
+public:
+ virtual void next(node*,node*,node*,int,node*) = 0;
+};
+
+class reach {
+public:
+
+ static bool join(node*,node*,reach_lister&);
+
+};
+
+#endif
diff --git a/view/src/relation.cc b/view/src/relation.cc
new file mode 100644
index 0000000..9feb005
--- /dev/null
+++ b/view/src/relation.cc
@@ -0,0 +1,186 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "runnable.h"
+#include "relation.h"
+#include "observable.h"
+#include "counted.h"
+#include <stdio.h>
+
+class run_gc : public runnable {
+ void run() { if(!relation::gc()) disable();}
+};
+
+
+static run_gc dogc;
+
+relation::relation(observer* a,observable* b):
+ observer_(a),
+ observable_(b),
+ data_(0),
+ valid_(true)
+{
+}
+
+relation::~relation()
+{
+ if(data_)
+ data_->detach();
+}
+
+void relation::add(observer* a,observable* b)
+{
+ if(a && b) {
+ b->observed_ = true;
+ new relation(a,b);
+ }
+}
+
+void relation::stats(const char* p)
+{
+ relation* r = first();
+ int c = 0; int v = 0;
+ while(r) {
+ relation* n = r->next();
+ c++;
+ if(r->valid_) v++;
+ r = n;
+ }
+
+ // printf("relation::stat %s %d relation(s) %d valid(s)\n",p,c,v);
+}
+
+int relation::remove(observer* a,observable* b)
+{
+ int rc = 0;
+ relation* r = first();
+ while(r) {
+ relation* n = r->next();
+ if(r->observer_ == a && r->observable_ == b) {
+ r->valid_ = false;
+ rc++;
+ }
+ r = n;
+ }
+
+ dogc.enable();
+ return rc;
+}
+
+int relation::remove(observer* a)
+{
+ int rc = 0;
+ relation* r = first();
+ while(r) {
+ relation* n = r->next();
+ if(r->observer_ == a) {
+ r->valid_ = false;
+ rc++;
+ }
+ r = n;
+ }
+
+ dogc.enable();
+ return rc;
+}
+
+int relation::remove(observable* b)
+{
+ int rc = 0;
+ relation* r = first();
+ while(r) {
+ relation* n = r->next();
+ if(r->observable_ == b) {
+ r->valid_ = false;
+ rc++;
+ }
+ r = n;
+ }
+
+ dogc.enable();
+ return rc;
+}
+
+void relation::replace(observable* o,observable* x)
+{
+ relation* r = first();
+ while(r) {
+ relation* n = r->next();
+ if(r->observable_ == o)
+ r->observable_ = x;
+ r = n;
+ }
+}
+
+void relation::scan(observable* b,observer_iterator& i)
+{
+ relation* r = first();
+
+ while(r) {
+ relation* n = r->next();
+ if(r->observable_ == b && r->valid_)
+ i.next(r->observer_);
+ r = n;
+ }
+}
+
+bool relation::gc()
+{
+ relation* r = first();
+
+ stats("relation::gc");
+
+ while(r) {
+ relation* n = r->next();
+ if(!r->valid_) {
+ delete r;
+ return true;
+ }
+ r = n;
+ }
+
+ return false;
+}
+
+void relation::set_data(observer* a,observable* b,counted* x)
+{
+ relation* r = first();
+ while(r) {
+ relation* n = r->next();
+ if(r->observer_ == a && r->observable_ == b) {
+ if(x != r->data_) {
+ if(r->data_) r->data_->detach();
+ r->data_ = x;
+ if(r->data_) r->data_->attach();
+ }
+ return;
+ }
+ r = n;
+ }
+}
+
+counted* relation::get_data(observer* a,observable* b)
+{
+ relation* r = first();
+ while(r) {
+ relation* n = r->next();
+ if(r->observer_ == a && r->observable_ == b)
+ return r->data_;
+ r = n;
+ }
+ return 0;
+}
+
+IMP(relation)
diff --git a/view/src/relation.h b/view/src/relation.h
new file mode 100644
index 0000000..f2fd4bb
--- /dev/null
+++ b/view/src/relation.h
@@ -0,0 +1,74 @@
+#ifndef relation_H
+#define relation_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#ifdef NO_BOOL
+#include "bool.h"
+#endif
+
+#ifndef extent_H
+#include "extent.h"
+#endif
+
+class observer;
+class observable;
+class counted;
+
+class observer_iterator {
+public:
+ virtual void next(observer*) = 0;
+};
+
+class observable_iterator {
+public:
+ virtual void next(observable*) = 0;
+};
+
+
+class relation : public extent<relation> {
+public:
+ relation(observer*,observable*);
+
+ ~relation(); // Change to virtual if base class
+
+ static void add(observer*,observable*);
+ static int remove(observer*,observable*);
+ static int remove(observer*);
+ static int remove(observable*);
+ static void replace(observable*,observable*);
+
+ static void scan(observer*, observable_iterator&);
+ static void scan(observable*,observer_iterator& );
+ static bool gc();
+
+
+ static void set_data(observer*,observable*,counted*);
+ static counted* get_data(observer*,observable*);
+
+ static void stats(const char*);
+
+private:
+
+ relation(const relation&);
+ relation& operator=(const relation&);
+
+ observer* observer_;
+ observable* observable_;
+ counted* data_;
+ bool valid_;
+};
+#endif
diff --git a/view/src/repeat.h b/view/src/repeat.h
new file mode 100644
index 0000000..35c1e2f
--- /dev/null
+++ b/view/src/repeat.h
@@ -0,0 +1,168 @@
+#ifndef REPEAT_H
+#define REPEAT_H
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #23 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include "repeat_node.h"
+
+/**********************************************/
+class repeat_date_node : public repeat_node {
+ virtual int last() const {
+ return (ecf_repeat_date_to_julian(repeat_node::last()) -
+ ecf_repeat_date_to_julian(repeat_node::start())) / step() + ink;
+ }
+
+ virtual int current() const {
+ if (owner_ && get()) {
+ int cur = (ecf_repeat_date_to_julian(get()->index_or_value()) -
+ ecf_repeat_date_to_julian(start())) / step();
+ int gui = ecf_repeat_julian_to_date(ecf_repeat_date_to_julian(start()) + cur * step());
+
+ if (get()->index_or_value() != gui) {
+ std::stringstream ss;
+ ss << "# WAR repeat value does not match: "
+ << get()->index_or_value()
+ << ", gui " << gui
+ << ", index " << cur
+ << ", start " << start()
+ << ", last " << last()
+ << ", step " << step() << "\n";
+
+ std::string msg (ss.str());
+ serv().command(clientName, "--msg", msg.c_str(), NULL);
+ std::cerr << ss;
+ }
+ return cur;
+ }
+ return repeat_node::current(); }
+
+ virtual void value(char* n,int i) const {
+ if (n) {
+ sprintf(n,"%ld",
+ (ecf_repeat_julian_to_date
+ (ecf_repeat_date_to_julian(start()) + i * step())));
+ }
+ }
+ virtual const char* perl_class() { return "repeat::date"; }
+
+public:
+ repeat_date_node(host& h,ecf_node* r) : repeat_node(h,r) {}
+};
+
+/**********************************************/
+class repeat_integer_node : public repeat_node {
+ virtual int last() const {
+ return (repeat_node::last() - repeat_node::start()) / step() + ink; }
+ virtual int current() const {
+ return (repeat_node::current() - repeat_node::start()) / step(); }
+ virtual void value(char*n,int i) const {
+ if (n) sprintf(n,"%d",start() + i*step()); }
+ virtual const char* perl_class() {
+ return "repeat::integer"; }
+
+public:
+ repeat_integer_node(host& h,ecf_node* r) : repeat_node(h,r) {}
+};
+
+/**********************************************/
+class repeat_day_node : public repeat_node {
+ virtual int last() const {
+ return (repeat_node::last() - repeat_node::start()) / step() + ink; }
+ virtual int current() const {
+ return step(); }
+ virtual void value(char*n,int i) const {
+ if (n) sprintf(n,"%d",step()); }
+ virtual const char* perl_class() {
+ return "repeat::day"; }
+
+public:
+ repeat_day_node(host& h,ecf_node* r) : repeat_node(h,r) {}
+};
+
+/**********************************************/
+class repeat_string_node : public repeat_node {
+ virtual int last() const {
+ if (owner_)
+ return repeat_node::last() + ink;
+ return repeat_node::last(); }
+ virtual int current() const {
+ return repeat_node::current(); }
+ virtual void value(char* n,int i) const {
+ if (n && get())
+ sprintf(n,"%s",get()->value_as_string(i).c_str()); }
+ virtual int index(const char*) const {
+ return current(); }
+ virtual bool can_use_text() {
+ return false; }
+ virtual void perlify(FILE* f) {
+ if (get())
+ perl_member(f, "values",get()->toString().c_str());
+ repeat_node::perlify(f); }
+ virtual const char* perl_class() {
+ return "repeat::string"; }
+
+public:
+ repeat_string_node(host& h,ecf_node* r) : repeat_node(h,r) {}
+};
+
+/**********************************************/
+class repeat_enumerated_node : public repeat_node {
+ virtual int last() const {
+ if (owner_)
+ return repeat_node::last() + ink;
+ return repeat_node::last(); }
+ virtual int current() const {
+ return repeat_node::current(); }
+ virtual void value(char* n,int i) const {
+ if (n && get()) sprintf(n,"%s",get()->value_as_string(i).c_str()); }
+ virtual int index(const char*) const {
+ return current(); }
+ virtual bool can_use_text() {
+ return false; }
+
+ virtual void perlify(FILE* f) {
+ if (get())
+ perl_member(f, "values",get()->toString().c_str());
+ repeat_node::perlify(f); }
+
+ virtual const char* perl_class() {
+ return "repeat::enumerated"; }
+
+public:
+ repeat_enumerated_node(host& h,ecf_node *r) : repeat_node(h,r) {}
+};
+
+/**********************************************/
+#ifdef BRIDGE
+class repeat_node_maker : public node_maker<repeat_node> {
+ protected:
+ static std::map<std::string, repeat_node_maker*> map_;
+ public:
+ repeat_node_maker() : node_maker<repeat_node>(NODE_REPEAT) {}
+ virtual node* make(host& h,ecf_node* n) {
+ return map_[n->type_name()]->make(h, n); }
+};
+
+std::map<std::string, repeat_node_maker*> repeat_node_maker::map_;
+
+template <class T, class W>
+class repeat_node_builder : public repeat_node_maker {
+public:
+ repeat_node_builder() {
+ map_[typeid(T).name()] = this; }
+ ~repeat_node_builder() {}
+};
+#endif
+#endif
diff --git a/view/src/repeat_node.cc b/view/src/repeat_node.cc
new file mode 100644
index 0000000..91f968d
--- /dev/null
+++ b/view/src/repeat_node.cc
@@ -0,0 +1,309 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #36 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+// .AUTHOR Baudouin Raoult
+// .DATE 28-JUN-2001 / 28-JUN-2001
+
+#include "arch.h"
+#include "repeat_node.h"
+#include "show.h"
+#include "host.h"
+const int REPEAT_SHOWN = 3;
+#include "ecflowview.h"
+
+#ifndef ecf_node_
+#include "ecf_node.h"
+#endif
+
+const int kPixSize = 8;
+const int kHMargins = 4;
+const int kVMargins = 2;
+
+repeat_node::repeat_node(host& h,ecf_node* n)
+ : node(h,n)
+ , name_("none")
+{
+ if (get())
+ name_ = get()->name();
+ else if (n)
+ name_ = n->name();
+ if (n) {
+ if (n->parent() && n->parent()->get_node())
+ full_name_ = n->parent()->get_node()->absNodePath();
+ full_name_ += ":";
+ full_name_ += n->name();
+ }
+}
+
+#ifdef BRIDGE
+repeat_node::repeat_node(host& h,sms_node* n,char b)
+ : node(h,n,b)
+ , name_(n ? n->name : "unknown")
+{
+ full_name_ = n ? sms_node_full_name(n) : "unknown";
+}
+#endif
+
+/**********************************************/
+
+RepeatBase* repeat_node::get() const
+{
+ if (parent())
+ if (parent()->__node__())
+ return parent()->__node__()->get_repeat().repeatBase();
+ Node * nnn = 0x0;
+
+ if (nnn)
+ return nnn->findRepeat(full_name_).repeatBase();
+ return 0x0;
+}
+
+ void repeat_node::drawNode(Widget w,XRectangle* r,bool tree) {
+ node::update(-1,-1,-1);
+ node::drawNode(w,r,true);
+ sizeNode(w,r,tree);
+}
+
+void repeat_node::sizeNode(Widget w,XRectangle* r,bool tree) {
+ int extra = 0;
+ XmString s = tree?labelTree():labelTrigger();
+ r->width = XmStringWidth(smallfont(),s) + 2*kHMargins + extra * kPixSize;
+ r->height = XmStringHeight(smallfont(),s) + 2*kVMargins;
+ if(r->height < kPixSize + 2*kVMargins) r->height = kPixSize + 2*kVMargins;
+}
+
+int repeat_node::start() const
+{
+#ifdef BRIDGE
+ if (tree_)
+ return ((sms_repeat*) tree_)->start;
+#endif
+ if (get())
+ return get()->start();
+ return 0;
+}
+
+int repeat_node::last() const
+{
+#ifdef BRIDGE
+ if (tree_) {
+ sms_repeat* r = (sms_repeat*)tree_;
+ switch (r->mode) {
+ case REPEAT_INTEGER:
+ return (r->end - r->start)/r->step + 1;
+ case REPEAT_ENUMERATED:
+ case REPEAT_STRING: { int n = 0; sms_list *l = r->str;
+ while(l) { n++; l = l->next; }
+ return n; }
+ case REPEAT_DATE: {
+ return (ecf_repeat_date_to_julian(r->end) -
+ ecf_repeat_date_to_julian(r->start))/
+ r->step + 1; }
+ default:
+ return r->end;
+ }
+ }
+#endif
+ if (get())
+ return get()->end();
+ return 0;
+}
+
+int repeat_node::step() const
+{
+#ifdef BRIDGE
+ if (tree_)
+ return ((sms_repeat*) tree_)->step;
+#endif
+ if (get())
+ return get()->step() > 0 ? get()->step() : 1;
+ return 1;
+}
+
+int repeat_node::current() const
+{
+#ifdef BRIDGE
+ if (tree_) {
+ sms_repeat* r = (sms_repeat*)tree_;
+ switch (r->mode) {
+ case REPEAT_INTEGER:
+ return (r->status - r->start)/r->step;
+ case REPEAT_ENUMERATED: { int rc = 0;
+ sms_list *item = r->str;
+ char current[255];
+ while (item) {
+ sprintf(current,"%d",r->status);
+ if (!strcmp(item->name, current))
+ return rc;
+ rc++; item = item->next;
+ }
+ return rc; }
+ case REPEAT_STRING:
+ return r->status;
+ case REPEAT_DATE:
+ return (ecf_repeat_date_to_julian(r->status) -
+ ecf_repeat_date_to_julian(r->start))/r->step;
+ default:
+ return r->status;
+ }
+ }
+#endif
+ if (get()) {
+ return get()->index_or_value();
+ }
+ return 0;
+}
+
+void repeat_node::value(char* n,int i) const
+{
+#ifdef BRIDGE
+ if (tree_) {
+ sms_repeat* r = (sms_repeat*)tree_;
+ switch (r->mode) {
+ case REPEAT_INTEGER: {
+ sprintf(n,"%d",r->start + i*r->step);
+ return; }
+ case REPEAT_ENUMERATED:
+ case REPEAT_STRING: { int j = 0; sms_list *l = r->str;
+ while(l && j != i) { j++; l = l->next; } if(l) strcpy(n,l->name);
+ return; }
+ case REPEAT_DATE: {
+ sprintf(n,"%ld",ecf_repeat_julian_to_date
+ (ecf_repeat_date_to_julian(r->start) + i*r->step));
+ return; }
+ default:
+ return;
+ }
+ }
+#endif
+ if (get() && n) {
+ sprintf(n,"%s",get()->value_as_string(i).c_str());
+ }
+}
+
+//===============================================================
+
+xmstring repeat_node::make_label_tree()
+{
+ str80 vals[REPEAT_SHOWN];
+ str80 buf;
+ int end = last();
+ int curr = current();
+ int first = curr - REPEAT_SHOWN/2;
+ static xmstring space(" ");
+ {
+ if(first<0) first = 0;
+ if(end -first<REPEAT_SHOWN) first = end - REPEAT_SHOWN;
+ if(end <=REPEAT_SHOWN) first = 0;
+
+ int m = MIN(REPEAT_SHOWN,end);
+ int i;
+
+ for(i = 0 ; i < REPEAT_SHOWN ; i++)
+ vals[i][0] = 0;
+
+ for(i=0 ; i < m ; i++)
+ value(vals[i],i+first);
+
+ if(first>0)
+ strcpy(vals[0], "...");
+
+ if( first+REPEAT_SHOWN < end)
+ strcpy(vals[REPEAT_SHOWN-1],"...");
+
+ curr = curr - first;
+
+ strcpy(buf,name_.c_str());
+ strcat(buf,"=");
+
+ xmstring s(buf);
+
+ m = 0;
+ for(i = 0; i < REPEAT_SHOWN ; i ++)
+ {
+ if(m != 0)
+ s += space;
+
+ s += xmstring(vals[i], (i==curr)?"bold":"normal" );
+
+ m = strlen(vals[i]);
+ }
+
+ return s;
+ }
+}
+
+void repeat_node::info(std::ostream& f)
+{
+ if (get()) {
+ f << get()->toString() << "\n";
+ }
+ f << "Values are:\n";
+ f << "-----------\n";
+
+ str80 buf;
+
+ int end = last();
+ int cur = current();
+ int i;
+
+ if(end > 50) {
+ for(i=0 ; i < 22 ; i++) {
+ value(buf,i);
+ f << char( (i == cur) ? '>' : ' ') << buf << "\n";
+ }
+
+ f << "...\n";
+
+ for(i= end-22 ; i < end ; i++) {
+ value(buf,i);
+ f << char( (i == cur) ? '>' : ' ') << buf << "\n";
+ }
+ return;
+ }
+
+ for(i=0 ; i < end ; i++) {
+ value(buf,i);
+ f << char( (i == cur) ? '>' : ' ') << buf << "\n";
+ }
+ f << "-----------" << "\n";
+}
+
+const char* repeat_node::status_name() const
+{
+ static char buf[80];
+ int end = last();
+ int cur = current();
+
+ if(cur < 0)
+ return "not started";
+ if(cur >= end)
+ return "finished";
+
+ value(buf,cur);
+ return buf;
+}
+
+void repeat_node::perlify(FILE* f)
+{
+ perl_member(f,"start", start());
+ perl_member(f,"end", last());
+ perl_member(f,"step", step());
+ perl_member(f,"current",current());
+}
+
+Boolean repeat_node::visible() const {
+ return show::want(show::repeat);
+}
diff --git a/view/src/repeat_node.h b/view/src/repeat_node.h
new file mode 100644
index 0000000..768e89b
--- /dev/null
+++ b/view/src/repeat_node.h
@@ -0,0 +1,66 @@
+#ifndef repeat_node_H
+#define repeat_node_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #18 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#ifndef node_H
+#include "node.h"
+#endif
+typedef char str80[80];
+#include <RepeatAttr.hpp>
+class repeat_node : public node {
+public:
+ // const Repeat& get();
+ RepeatBase* get() const;
+
+ repeat_node(host& h,ecf_node* n);
+#ifdef BRIDGE
+ repeat_node(host& h,sms_node* n,char b);
+#endif
+ virtual int start() const;
+ virtual int last() const;
+ virtual int step() const;
+ virtual int current() const;
+ virtual void value(char*,int) const;
+ virtual int index(const char* p) const { return atol(p); }
+ virtual bool can_use_text() { return true; }
+ virtual void perlify(FILE*);
+
+ virtual void drawNode(Widget w,XRectangle* r,bool);
+ virtual void sizeNode(Widget w,XRectangle* r,bool);
+
+ protected:
+ static const int ink = 1;
+private:
+ std::string name_,full_name_;
+
+ repeat_node(const repeat_node&);
+ repeat_node& operator=(const repeat_node&);
+
+ virtual void info(std::ostream&);
+ virtual xmstring make_label_tree();
+
+ virtual const char* status_name() const;
+
+ virtual const std::string& full_name() const { return full_name_; }
+ virtual const std::string& name() const { return name_; }
+
+ virtual bool is_my_parent(node*) const { return false; }
+ virtual Boolean visible() const;
+};
+
+inline void destroy(repeat_node**) {}
+#endif
diff --git a/view/src/resource.cc b/view/src/resource.cc
new file mode 100644
index 0000000..0e824af
--- /dev/null
+++ b/view/src/resource.cc
@@ -0,0 +1,112 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <strings.h>
+
+#ifndef option_H
+#include "option.h"
+#endif
+
+#ifndef base_H
+#include "base.h"
+#endif
+
+#include "configurable.h"
+#include "configurator.h"
+
+resource::resource(configurable* o,const str& name,const str& value):
+ owner_(o),
+ base_(base::lookup(o->name())),
+ name_(name),
+ value_(value),
+ set_(0)
+{
+ base_->attach();
+ base_->defaults(name_,value_);
+ set_ = base_->fetch(name_,value_);
+}
+
+resource::~resource()
+{
+ base_->detach();
+}
+
+void resource::setset(bool on)
+{
+ set_ = on;
+
+ if(on)
+ base_->store(name_,value_,true);
+ else
+ base_->remove(name_);
+
+ base_->fetch(name_,value_);
+
+ resource* r = first();
+ while(r)
+ {
+ if(r->name() == name_)
+ if(r->changed())
+ r->owner_->changed(*r);
+ r = r->next();
+ }
+}
+
+void resource::set(const str& v)
+{
+
+ value_ = v;
+ base_->store(name_,value_,true);
+ set_ = true;
+
+ resource* r = first();
+ while(r)
+ {
+ if(r->name() == name_)
+ if(r->changed())
+ r->owner_->changed(*r);
+ r = r->next();
+ }
+}
+
+const str& resource::get()
+{
+ base_->fetch(name_,value_);
+ return value_;
+}
+
+void resource::init(configurable& a, configurator& c)
+{
+ resource* r = first();
+ while(r)
+ {
+ if(r->owner_ == &a) c.init(*r);
+ r = r->next();
+ }
+}
+
+void resource::modified(configurable& a, configurator& c)
+{
+ resource* r = first();
+ while(r)
+ {
+ if(r->owner_ == &a)
+ if(c.modified(*r))
+ a.changed(*r);
+ r = r->next();
+ }
+}
+
+IMP(resource)
diff --git a/view/src/resource.h b/view/src/resource.h
new file mode 100644
index 0000000..e06b5c5
--- /dev/null
+++ b/view/src/resource.h
@@ -0,0 +1,71 @@
+#ifndef resource_H
+#define resource_H
+
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#ifndef configurable_H
+#include "configurable.h"
+#endif
+
+#ifndef str_H
+#include "str.h"
+#endif
+
+#include <Xm/Xm.h>
+
+class base;
+
+#ifndef resource_H
+#include "resource.h"
+#endif
+#include "extent.h"
+
+class resource : public extent<resource> {
+public:
+
+ resource(configurable*,const str&,const str&);
+
+ virtual ~resource(); // Change to virtual if base class
+
+ const str name() const { return name_; }
+
+ virtual void initWidget(Widget) = 0;
+ virtual bool readWidget(Widget) = 0;
+ virtual bool changed() = 0;
+
+ virtual void set(const str&);
+ virtual const str& get();
+
+ virtual bool isSet() { return set_; }
+ virtual void setset(bool);
+
+ static void init(configurable&,configurator&);
+ static void modified(configurable&,configurator&);
+
+private:
+
+ resource(const resource&);
+ resource& operator=(const resource&);
+
+ configurable* owner_;
+ base* base_;
+ str name_;
+ str value_;
+ bool set_;
+};
+
+inline void destroy(resource**) {}
+#endif
diff --git a/view/src/restart.cc b/view/src/restart.cc
new file mode 100644
index 0000000..022f4a5
--- /dev/null
+++ b/view/src/restart.cc
@@ -0,0 +1,32 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "restart.h"
+#include "node.h"
+
+
+restart::restart():
+ node_alert<restart>("Restarted tasks",STATUS_SUBMITTED)
+{
+}
+
+restart::~restart()
+{
+}
+
+bool restart::keep(node* n)
+{
+ return n->isRerun();
+}
diff --git a/view/src/restart.h b/view/src/restart.h
new file mode 100644
index 0000000..c1edb3a
--- /dev/null
+++ b/view/src/restart.h
@@ -0,0 +1,109 @@
+#ifndef restart_H
+#define restart_H
+
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "node_alert.h"
+
+class node;
+
+class restart : public node_alert<restart> {
+public:
+
+// -- Exceptions
+ // None
+
+// -- Contructors
+
+ restart();
+
+// -- Destructor
+
+ ~restart(); // Change to virtual if base class
+
+// -- Convertors
+ // None
+
+// -- Operators
+ // None
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+
+ // Uncomment for persistent, remove otherwise
+ // static os_typespec* get_os_typespec();
+
+protected:
+
+// -- Members
+ // None
+
+// -- Methods
+
+ // void print(ostream&) const; // Change to virtual if base class
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+private:
+
+// No copy allowed
+
+ restart(const restart&);
+ restart& operator=(const restart&);
+
+// -- Methods
+
+
+// -- Overridden methods
+
+ virtual bool keep(node*);
+
+// -- Class members
+
+
+// -- Class methods
+ // None
+
+// -- Friends
+
+ //friend ostream& operator<<(ostream& s,const restart& p)
+ // { p.print(s); return s; }
+
+};
+
+inline void destroy(restart**) {}
+
+// If persistent, uncomment, otherwise remove
+//#ifdef _ODI_OSSG_
+//OS_MARK_SCHEMA_TYPE(restart);
+//#endif
+
+#endif
diff --git a/view/src/result.cc b/view/src/result.cc
new file mode 100644
index 0000000..13c3e5c
--- /dev/null
+++ b/view/src/result.cc
@@ -0,0 +1,32 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "result.h"
+
+result::result():
+ node_alert<result>("Search results")
+{
+}
+
+result::~result()
+{
+}
+
+
+bool result::keep(node* n)
+{
+ return true;
+}
+
diff --git a/view/src/result.h b/view/src/result.h
new file mode 100644
index 0000000..cdc8815
--- /dev/null
+++ b/view/src/result.h
@@ -0,0 +1,38 @@
+#ifndef result_H
+#define result_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "node_alert.h"
+
+class node;
+
+class result : public node_alert<result> {
+public:
+
+ result();
+ ~result(); // Change to virtual if base class
+
+private:
+
+ result(const result&);
+ result& operator=(const result&);
+
+ virtual bool keep(node*);
+};
+
+inline void destroy(result**) {}
+#endif
diff --git a/view/src/runnable.cc b/view/src/runnable.cc
new file mode 100644
index 0000000..42e5043
--- /dev/null
+++ b/view/src/runnable.cc
@@ -0,0 +1,64 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "ecflowview.h"
+#include "runnable.h"
+
+/* do a process in the "background" */
+
+Boolean runnable::workCB(XtPointer)
+{
+ runnable *p = first();
+ int active = 0;
+ while(p) {
+ runnable* n = p->next();
+
+ if(p->actived_) {
+ active++;
+ p->run();
+ }
+
+ p = n;
+ }
+ return (active == 0);
+}
+
+runnable::runnable():
+ actived_(False)
+{
+}
+
+runnable::~runnable()
+{
+}
+
+void runnable::enable()
+{
+ if(actived_) return;
+
+ extern XtAppContext app_context;
+ if(app_context != 0)
+ XtAppAddWorkProc(app_context,workCB,NULL);
+
+ actived_ = True;
+}
+
+
+void runnable::disable()
+{
+ actived_ = False;
+}
+
+IMP(runnable)
diff --git a/view/src/runnable.h b/view/src/runnable.h
new file mode 100644
index 0000000..d885eb4
--- /dev/null
+++ b/view/src/runnable.h
@@ -0,0 +1,49 @@
+#ifndef runnable_H
+#define runnable_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include <Xm/Xm.h>
+
+#ifdef NO_BOOL
+#include "bool.h"
+#endif
+
+#ifndef extent_H
+#include "extent.h"
+#endif
+
+class runnable : public extent<runnable> {
+public:
+ runnable();
+
+ virtual ~runnable(); // Change to virtual if base class
+
+ void enable();
+ void disable();
+ bool actived() { return actived_; }
+
+ virtual void run() = 0;
+
+private:
+ runnable(const runnable&);
+ runnable& operator=(const runnable&);
+
+ Boolean actived_;
+
+ static Boolean workCB(XtPointer);
+};
+#endif
diff --git a/view/src/script_panel.cc b/view/src/script_panel.cc
new file mode 100644
index 0000000..d8eebeb
--- /dev/null
+++ b/view/src/script_panel.cc
@@ -0,0 +1,61 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "script_panel.h"
+#include "node.h"
+#include "host.h"
+#include "ecf_node.h"
+#include "variable_node.h"
+#include <Xm/Text.h>
+extern "C" {
+#include "xec.h"
+}
+
+script_panel::script_panel(panel_window& w)
+ :panel(w)
+ ,text_window(false)
+{
+}
+
+script_panel::~script_panel()
+{
+}
+
+void script_panel::clear()
+{
+ XmTextSetString(name_,(char*)"");
+ text_window::clear();
+}
+
+void script_panel::show(node& n)
+{
+ std::string p = n.variable("ECF_SCRIPT");
+ if (!n.__node__()) p = n.variable("SMSSCRIPT");
+ XmTextSetString(name_,p.empty() ? (char*) "" : (char*)p.c_str());
+ load(n.serv().script(n));
+}
+
+Boolean script_panel::enabled(node& n)
+{
+ if (n.type() != NODE_TASK && n.type() != NODE_ALIAS) return False;
+ if (!n.__node__())
+ return n.variable("SMSSCRIPT").size() > 7;
+ return n.variable("ECF_SCRIPT").size() > 7;
+}
+
+void script_panel::create (Widget parent, char *widget_name )
+{
+ script_form_c::create(parent,widget_name);
+}
diff --git a/view/src/script_panel.h b/view/src/script_panel.h
new file mode 100644
index 0000000..95b1530
--- /dev/null
+++ b/view/src/script_panel.h
@@ -0,0 +1,64 @@
+#ifndef script_panel_H
+#define script_panel_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "uiscript.h"
+
+#ifndef panel_H
+#include "panel.h"
+#endif
+
+#ifndef text_window_H
+#include "text_window.h"
+#endif
+
+class script_panel : public panel, public script_form_c, public text_window {
+public:
+
+ script_panel(panel_window&);
+
+ ~script_panel(); // Change to virtual if base class
+
+ virtual const char* name() const { return "Script"; }
+ virtual void show(node&);
+ virtual Boolean enabled(node&);
+ virtual void clear();
+ virtual Widget widget() { return script_form_c::xd_rootwidget(); }
+ virtual Widget tools() { return tools_; }
+ virtual Widget text() { return text_; }
+ virtual void create (Widget parent, char *widget_name = 0 );
+
+private:
+
+ script_panel(const script_panel&);
+ script_panel& operator=(const script_panel&);
+
+ virtual void externalCB(Widget ,XtPointer )
+ { text_window::open_viewer();}
+
+ virtual void searchCB(Widget ,XtPointer )
+ { text_window::open_search();}
+
+ virtual bool can_print() { return true; }
+ virtual bool can_save() { return true; }
+ virtual void print() { text_window::print(); }
+ virtual void save() { text_window::save(); }
+};
+
+inline void destroy(script_panel**) {}
+
+#endif
diff --git a/view/src/scripting.cc b/view/src/scripting.cc
new file mode 100644
index 0000000..f1f02ca
--- /dev/null
+++ b/view/src/scripting.cc
@@ -0,0 +1,390 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #11 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <stdio.h>
+#include <strings.h>
+#include "ecflowview.h"
+#include "scripting.h"
+#include "directory.h"
+#include "input.h"
+// cmd
+#include "gui.h"
+#include "node.h"
+#include "host.h"
+#include "selection.h"
+#include "panel_window.h"
+#include "uitop.h"
+#include "menus.h"
+
+// #include <sys/types.h>
+// #include <sys/stat.h>
+#include <fcntl.h>
+#include "ecflowview.h"
+
+int select_cmd(const char *host_name, const char *node_name)
+{
+ gui::raise();
+ host::login(host_name);
+ node* n = host::find(host_name,node_name);
+ if(n) selection::notify_new_selection(n);
+ return True;
+}
+
+int order_cmd(const char *path, const char *kind)
+{
+ gui::raise();
+ char *c = (char*) path; // host:/path
+ const char* host_name = 0x0;
+ const char* node_name = path;
+ while (c) {
+ if (*c == ':') { *c = '\0'; node_name = ++c; } else {++c;}}
+ if (!host_name) host_name="localhost";
+ host::login(host_name);
+ node* xnode = host::find(host_name,node_name);
+ if(xnode) {
+ selection::notify_new_selection(xnode);
+ xnode->serv().command(clientName, "--order", node_name, kind, NULL);
+ }
+ return True;
+}
+
+int menu_cmd(const char *cmd)
+{
+ return script_menus(0, cmd);
+}
+
+int window_cmd(const char *name, int detached, int frozen)
+{
+ panel_window::new_window(selection::current_node(),name,detached,frozen);
+ return True;
+}
+
+int login_cmd(const char *name)
+{
+ host::login(name);
+ return True;
+}
+
+int logout_cmd(const char *name)
+{
+ host::logout(name);
+ return True;
+}
+
+int quit_cmd()
+{
+ top_shell_c::quitCB(0x0, 0x0, 0x0);
+ return True;
+}
+
+int process_command(const char *cmd) {
+ if (!cmd) return 1;
+
+ if (!strncmp("select", cmd, 6)) {
+ char host[80] = { 0, };
+ char node[1024] = { 0, };
+ sscanf(cmd, "select %s %s", host, node);
+ if (host[0] != 0 && node[0] != 0) {
+ select_cmd(host, node);
+ } else {
+ std::cerr << "#CMD (scripting): err: " << cmd << "\n";
+ return 1;
+ }
+
+ } else if (!strncmp("order", cmd, 5)) {
+ char kind[80] = { 0, };
+ char node[1024] = { 0, };
+ sscanf(cmd, "order %s %s", node, kind);
+ if (kind[0] != 0 && node[0] != 0) {
+ order_cmd(node, kind);
+ } else {
+ std::cerr << "#CMD (scripting): err: " << cmd << "\n";
+ return 1;
+ }
+
+ } else if (!strncmp("menu", cmd, 4)) {
+ menu_cmd(cmd);
+
+ } else if (!strncmp("quit", cmd, 4)) {
+ quit_cmd();
+
+ } else if (!strncmp("login", cmd, 5)) {
+ char host[80] = { 0, };
+ sscanf(cmd, "login %s", host);
+ if (host[0] != 0) {
+ login_cmd(host);
+ }
+
+ } else if (!strncmp("logout", cmd, 6)) {
+ char host[80] = { 0, };
+ sscanf(cmd, "logout %s", host);
+ if (host[0] != 0) {
+ logout_cmd(host);
+ }
+
+ } else if (!strncmp("window", cmd, 6)) {
+ int detached = 0;
+ int frozen = 0;
+ int len;
+ char name[32] = { 0, };
+ const char *ptr = cmd;
+ while ((sscanf(ptr, "%31[^ ]%n", name, &len) == 1)) {
+ std::cerr << "#field: " << name << "\n";
+ ptr += len;
+ if (!strncmp("-d", name, 2)) detached = 1;
+ if (!strncmp("-f", name, 2)) frozen = 1;
+ if (*ptr != ' ') { break; /* skip separator */ }
+ ptr++;
+ std::cerr << "#CMD (scripting): process: " << name << "\n";
+ }
+ if (name[0] != 0) {
+ window_cmd(name, detached, frozen);
+ } else {
+ std::cerr << "#CMD (scripting): err: " << cmd << "\n";
+ return 1;
+ }
+ } else if (!strncmp("\n", cmd, 1)) {
+
+ } else {
+ std::cerr << "#CMD (scripting): ignored: " << cmd << "\n";
+ return 1;
+ }
+
+ std::cout << "#CMD (scripting): " << cmd << "\n";
+ return 0;
+}
+
+#undef SCRIPT_PYTHON
+#ifdef SCRIPT_PYTHON
+#ifdef linux
+#undef _POSIX_C_SOURCE
+#undef _XOPEN_SOURCE
+#include <boost/python.hpp>
+#include <boost/python/module.hpp>
+#include <boost/detail/lightweight_test.hpp>
+using namespace boost::python;
+namespace python = boost::python;
+
+void runit(std::string const &script)
+{
+ python::dict global;
+ // python::object result =
+ python::exec(oost::python::str(script), global, global);
+ // BOOST_TEST(python::extract<int>(global["number"]) == 42);
+}
+
+BOOST_PYTHON_MODULE(ecflowView)
+{
+ def("window", window_cmd, args("name", "detached", "frozen"), "open a window detached/frozen");
+ def("select", select_cmd, args("host", "node"), "select a node");
+}
+
+#endif
+#endif
+
+extern XtAppContext app_context;
+
+class ecflowview_input {
+ std::string name_;
+ XtInputId id_;
+ int fd_;
+ std::string line_;
+
+public:
+
+ ecflowview_input(const char* name):
+ name_(name),
+ fd_(-1)
+ {
+ open();
+ }
+
+ ~ecflowview_input()
+ {
+ if(fd_ >= 0) XtRemoveInput(id_);
+ }
+
+ void done()
+ {
+ if(fd_ >= 0) XtRemoveInput(id_);
+ ::close(fd_);
+ fd_ = -1;
+ // We should check if its a pipe
+
+ struct stat st;
+ if(stat(name_.c_str(),&st) == 0)
+ {
+ if(S_ISFIFO(st.st_mode))
+ open();
+ else
+ delete this;
+ }
+ else {
+ perror(name_.c_str());
+ delete this;
+ }
+ }
+
+ void open()
+ {
+ fd_ = ::open(name_.c_str(),O_RDONLY|O_NONBLOCK); // |O_NDELAY);
+ if(fd_ < 0) {
+ perror(name_.c_str());
+ delete this;
+ return;
+ }
+
+ id_ = XtAppAddInput(app_context,fd_, XtPointer(XtInputReadMask),
+ inputCB,this);
+ }
+
+ void input()
+ {
+ char c[2];
+ if(::read(fd_,&c[0],1) != 1)
+ {
+ done();
+ }
+ if(c[0] == '\n')
+ {
+#ifdef SCRIPT_PYTHON
+#ifdef linux
+ // Py_Initialize();
+ init_module_ecflowView(); // thanks to boost macro
+ bool error_expected = false;
+ // Py_InitModule("ecflowView", ecflowViewMethods);
+ std::cout << line_.c_str() << "\n";
+ if ( // python::handle_exception(exec_test) ||
+ python::handle_exception(boost::bind(runit, line_)))
+ {
+ if (PyErr_Occurred())
+ {
+ if (!error_expected)
+ std::cerr << "Python Error detected";
+ PyErr_Print();
+ }
+ else
+ {
+ std::cerr << "A C++ exception was thrown for which "
+ << "there was no exception translator registered.";
+ }
+ }
+ // Boost.Python doesn't support Py_Finalize yet, so don't call it!
+ line_ = "";
+ return; // boost::report_errors();
+ // PyRun_SimpleString(line_.c_str());
+ // Py_Finalize(); // not supported by Boost
+#endif
+#else
+ process_command(line_.c_str());
+ line_ = "";
+ return;
+#endif
+ }
+ else {
+ c[1] = 0;
+ line_ += c;
+ }
+ }
+
+ static void inputCB(XtPointer data,int*,XtInputId*)
+ {
+ ecflowview_input* p = ((ecflowview_input*)data);
+ p->input();
+ }
+};
+
+scripting::scripting(const char* name):
+ name_(name)
+{
+}
+
+scripting::~scripting()
+{
+}
+
+void scripting::init()
+{
+ char buf[1024];
+
+ sprintf(buf,"%s/startup.script",directory::system());
+ run(buf);
+
+ sprintf(buf,"%s/startup.script",directory::user());
+ run(buf);
+
+ const char* file = getenv("ECFLOWVIEW_INPUT");
+ if(file != 0) { new ecflowview_input(file);
+ std::cout << "# ecflowview listening: " << file << "\n";
+ }
+}
+
+void scripting::run(const char* file)
+{
+ FILE* f = fopen(file,"r");
+ if(!f) {
+ //perror(file);
+ return;
+ }
+
+ char line[1024];
+ while(fgets(line,sizeof(line),f))
+ {
+ if(line[0]) line[strlen(line)-1] = 0;
+ execute(line);
+ }
+ fclose(f);
+}
+
+void scripting::execute(const char* cmd)
+{
+#ifdef SCRIPT_PYTHON
+#ifdef linux
+ // Py_Initialize();
+ init_module_ecflowView();
+ // Py_InitModule("ecflowView", ecflowViewMethods);
+ std::cout << cmd << "\n";
+ python::handle_exception(boost::bind(runit, cmd));
+ // PyRun_SimpleString(cmd);
+ // Py_Finalize();
+#endif
+#else
+
+ process_command(cmd);
+
+#endif
+}
+
+scripting* scripting::find(const char* name)
+{
+ scripting* s = first();
+ while(s)
+ {
+ if(strcmp(s->name_,name) == 0)
+ return s;
+ s = s->next();
+ }
+ return 0;
+}
+
+int scripting::dispatch(int argc,char **argv)
+{
+ scripting* s = find(argv[0]);
+ if(s) return s->execute(argc,argv);
+ fprintf(stderr,"cannot find command %s\n",argv[0]);
+ return 1;
+}
+
+IMP(scripting)
diff --git a/view/src/scripting.h b/view/src/scripting.h
new file mode 100644
index 0000000..2202730
--- /dev/null
+++ b/view/src/scripting.h
@@ -0,0 +1,49 @@
+#ifndef scripting_H
+#define scripting_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#ifndef extent_H
+#include "extent.h"
+#endif
+
+class scripting : public extent<scripting> {
+public:
+
+ scripting(const char*);
+
+ ~scripting(); // Change to virtual if base class
+
+ virtual int execute(int,char**) = 0;
+
+ static void init();
+ static void run(const char*);
+ static void execute(const char*);
+
+ static scripting* find(const char* name);
+
+ static int dispatch(int,char**);
+
+private:
+
+ scripting(const scripting&);
+ scripting& operator=(const scripting&);
+
+ const char* name_;
+};
+
+inline void destroy(scripting**) {}
+#endif
diff --git a/view/src/search.cc b/view/src/search.cc
new file mode 100644
index 0000000..ef60341
--- /dev/null
+++ b/view/src/search.cc
@@ -0,0 +1,288 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+//=============================================================================================
+
+#include "search.h"
+#include "host.h"
+#include "runnable.h"
+#include <Xm/List.h>
+#include <Xm/Text.h>
+#include <Xm/ToggleB.h>
+#include "gui.h"
+#include "extent.h"
+#include "flags.h"
+#include "result.h"
+#include <X11/IntrinsicP.h>
+
+
+extern "C" {
+#include "xec.h"
+}
+
+search& search::instance()
+{
+ static search *m = new search();
+ return *m;
+}
+
+search::search():
+ name_(0)
+ , timed_since_(0)
+ , timed_from_(86400*3) // 3 days
+{
+ create(gui::top());
+}
+
+search::~search()
+{
+}
+
+
+void search::searchCB(Widget,XtPointer)
+{
+ if(name_) XtFree(name_);
+ name_ = 0;
+
+ if(XmToggleButtonGetState(what_)) {
+ char* p = XmTextGetString(what_text_);
+ if(*p)
+ name_ = XtNewString(p);
+ else
+ name_ = 0;
+ XtFree(p);
+ }
+
+ type_flags_.clear();
+ if(XmToggleButtonGetState(type_))
+ scan(type_rowcol_,type_flags_);
+
+ status_flags_.clear();
+ if(XmToggleButtonGetState(status_))
+ scan(status_rowcol_,status_flags_);
+
+ special_flags_.clear();
+ if(XmToggleButtonGetState(special_))
+ scan(special_rowcol_,special_flags_);
+
+ if(XmToggleButtonGetState(timed_)) {
+ char *since = XmTextGetString(timed_text_since_);
+ char *from = XmTextGetString(timed_text_from_);
+ if(since)
+ timed_since_ = atoi(since);
+ if(from)
+ timed_from_ = atoi(from);
+ fprintf (stdout, "# from: %d\tsince: %d\n", timed_from_, timed_since_);
+ XtFree(since);
+ XtFree(from);
+ } else {
+ timed_from_ = 86400;
+ timed_since_ = 0;
+ }
+
+ if(XmToggleButtonGetState(misc_)) {
+ icas_ = XmToggleButtonGetState(icase_);
+ rege_ = XmToggleButtonGetState(toggle11_);
+ glob_ = XmToggleButtonGetState(toggle12_);
+ subs_ = XmToggleButtonGetState(toggle13_);
+ } else { icas_ = true; subs_ = true; rege_ = glob_ = false; }
+
+ result::clear();
+ searchable::look_for(*this, !XmToggleButtonGetState(where_));
+ result::show();
+}
+
+void search::closeCB(Widget,XtPointer)
+{
+ XtUnmanageChild(form_);
+}
+
+void search::mapCB(Widget,XtPointer)
+{
+ searchable::parent(where_rowcol_);
+}
+
+void search::raise()
+{
+ XtManageChild(form_);
+ XMapRaised(XtDisplay(_xd_rootwidget),XtWindow(_xd_rootwidget));
+}
+
+void search::show()
+{
+ instance().raise();
+}
+
+#include <sys/types.h>
+#include <regex.h>
+#include <boost/algorithm/string.hpp>
+#include <fnmatch.h>
+
+void search::next(node& n)
+{
+ bool ok = true;
+ ok &= check(n,type_flags_);
+ if (ok) ok &= check(n,status_flags_);
+ if (ok) ok &= check(n,special_flags_);
+ if (ok && name_) {
+ if (subs_) {
+ bool res = n.match(name_);
+ if (icas_)
+ res |= !strncasecmp(name_, n.name().c_str(), strlen(name_));
+ else
+ res |= !strncmp(name_, n.name().c_str(), strlen(name_));
+ ok &= res;
+ } else if (glob_) {
+ std::string path (n.name());
+ std::string pattern (name_);
+ if (name_[0] == '/')
+ path = n.full_name();
+ if (icas_) {
+ boost::algorithm::to_lower(path);
+ boost::algorithm::to_lower(pattern);
+ }
+ ok &= 0==fnmatch(pattern.c_str(), path.c_str(), 0);
+ } else if (rege_) {
+ regex_t exp; int flags = REG_EXTENDED;
+ std::string path (n.name());
+ std::string pattern (name_);
+ if (name_[0] == '/')
+ path = n.full_name();
+ if (icas_)
+ flags &= REG_ICASE;
+ int rv = regcomp(&exp, pattern.c_str(), flags);
+ if (rv!=0)
+ std::cerr << "regcomp failed %d" << rv << "\n";
+ else
+ ok &= 0==regexec(&exp, path.c_str(), 0, NULL, 0);
+ regfree(&exp);
+ } else if (icas_) { // ignore case
+ ok &= strcasestr(n.name().c_str(),name_) != 0;
+ } else { // case sensitive, accept longest names
+ ok &= n.match(name_);
+ }
+ // }
+ }
+ if (ok && XmToggleButtonGetState(timed_))
+ if (n.type() == NODE_TASK || n.type() == NODE_FAMILY || n.type() == NODE_SUITE) {
+ boost::posix_time::ptime now(boost::posix_time::second_clock::local_time());
+ int diff = (now - n.status_time()).total_seconds();
+ ok &= (-1 < timed_since_ && timed_since_ < diff) && diff < timed_from_;
+ }
+ if(ok) result::show(n);
+}
+
+bool search::check(node& n,array<flags*>& f)
+{
+ int c = f.count();
+ bool ok = (c == 0);
+ for(int i = 0; i < c ; i++)
+ ok = ok || f[i]->eval(&n);
+ return ok;
+}
+
+
+void search::whatCB(Widget,XtPointer)
+{
+ if(XmToggleButtonGetState(what_))
+ XtManageChild(what_text_);
+ else
+ XtUnmanageChild(what_text_);
+}
+
+void search::whereCB(Widget,XtPointer)
+{
+ if(XmToggleButtonGetState(where_))
+ XtManageChild(where_rowcol_);
+ else
+ XtUnmanageChild(where_rowcol_);
+}
+
+void search::statusCB(Widget,XtPointer)
+{
+ if(XmToggleButtonGetState(status_))
+ XtManageChild(status_rowcol_);
+ else
+ XtUnmanageChild(status_rowcol_);
+}
+
+void search::typeCB(Widget,XtPointer)
+{
+ if(XmToggleButtonGetState(type_))
+ XtManageChild(type_rowcol_);
+ else
+ XtUnmanageChild(type_rowcol_);
+}
+
+void search::specialCB(Widget,XtPointer)
+{
+ if(XmToggleButtonGetState(special_))
+ XtManageChild(special_rowcol_);
+ else
+ XtUnmanageChild(special_rowcol_);
+}
+
+void search::timedCB(Widget,XtPointer)
+{
+ if(XmToggleButtonGetState(timed_)) {
+ XtManageChild(timed_rowcol_);
+ XtManageChild(timed_text_from_);
+ XtManageChild(timed_text_since_);
+ } else {
+ XtUnmanageChild(timed_rowcol_);
+ XtUnmanageChild(timed_text_from_);
+ XtUnmanageChild(timed_text_since_);
+ }
+}
+
+void search::radioCB(Widget w, XtPointer data) {
+ rege_ = XmToggleButtonGetState(toggle11_);
+ glob_ = XmToggleButtonGetState(toggle12_);
+ subs_ = XmToggleButtonGetState(toggle13_);
+}
+
+void search::miscCB(Widget,XtPointer)
+{
+ if(XmToggleButtonGetState(misc_)) {
+ XmToggleButtonSetState(icase_, True, False);
+ // XmToggleButtonSetState(toggle12_, True, False); // glob
+ XmToggleButtonSetState(toggle13_, True, False); // substring
+ XtManageChild(misc_rowcol_);
+ XtManageChild(fname_);
+ XtManageChild(icase_);
+ } else {
+ XtUnmanageChild(misc_rowcol_);
+ XtUnmanageChild(icase_);
+ XtUnmanageChild(fname_);
+ }
+}
+
+void search::scan(Widget w,array<flags*>& f)
+{
+ f.clear();
+ CompositeWidget c = (CompositeWidget)w;
+ for(unsigned int i = 0 ; i < c->composite.num_children; i++) {
+ Widget p = c->composite.children[i];
+ if(XmIsToggleButton(p)) {
+ flags *s = (flags*)xec_GetUserData(p);
+ if(s && XmToggleButtonGetState(p)) {
+ f.add(s);
+ }
+ }
+ }
+}
+/*
+^[^#]\s*\w+\s*:(?<data>.*?)$
+
+*/
diff --git a/view/src/search.h b/view/src/search.h
new file mode 100644
index 0000000..f0db39e
--- /dev/null
+++ b/view/src/search.h
@@ -0,0 +1,82 @@
+#ifndef search_H
+#define search_H
+
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#ifdef NO_BOOL
+#include "bool.h"
+#endif
+
+#include "uisearch.h"
+#include "node_lister.h"
+#include "array.h"
+
+class flags;
+
+class search : public search_shell_c, public node_lister {
+public:
+
+ search();
+
+ ~search(); // Change to virtual if base class
+
+ static void show();
+
+private:
+
+ search(const search&);
+ search& operator=(const search&);
+
+ char *name_;
+ array<flags*> status_flags_;
+ array<flags*> special_flags_;
+ array<flags*> type_flags_;
+ int timed_since_, timed_from_, subs_, rege_, icas_, glob_ ;
+
+// -- Methods
+
+ void raise();
+ void scan(Widget,array<flags*>&);
+
+
+// -- Overridden methods
+
+ void next(node&);
+ bool check(node&,array<flags*>&);
+
+// -- Class members
+
+ static search& instance();
+
+// -- Class methods
+
+ void closeCB(Widget,XtPointer);
+ void searchCB(Widget,XtPointer);
+ void mapCB(Widget,XtPointer);
+
+ void whatCB(Widget,XtPointer);
+ void whereCB(Widget,XtPointer);
+ void statusCB(Widget,XtPointer);
+ void typeCB(Widget,XtPointer);
+ void specialCB(Widget,XtPointer);
+ void timedCB(Widget,XtPointer);
+ void miscCB(Widget,XtPointer);
+ void radioCB(Widget,XtPointer);
+};
+
+inline void destroy(search**) {}
+
+#endif
diff --git a/view/src/searchable.cc b/view/src/searchable.cc
new file mode 100644
index 0000000..e603844
--- /dev/null
+++ b/view/src/searchable.cc
@@ -0,0 +1,151 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "top.h"
+#include "searchable.h"
+#include <Xm/Text.h>
+#include <Xm/ToggleB.h>
+
+Widget searchable::parent_ = 0;
+
+searchable::searchable():
+ toggle_(0),
+ active_(False)
+{
+}
+
+searchable::~searchable()
+{
+ if(toggle_)
+ XtDestroyWidget(toggle_);
+}
+
+void searchable::look_for(node_lister& p,bool all)
+{
+ searchable* s = first();
+ while(s)
+ {
+ if( all || (s->toggle_ && XtIsManaged(s->toggle_) &&
+ XmToggleButtonGetState(s->toggle_)))
+ s->search(p);
+ s = s->next();
+ }
+}
+
+void searchable::parent(Widget w)
+{
+ parent_ = w;
+
+ searchable* s = first();
+ while(s)
+ {
+ if(s->toggle_ == 0)
+ {
+ s->toggle_ = XmCreateToggleButton(parent_,(char*)s->name(),0,0);
+ if(s->active_) XtManageChild(s->toggle_);
+ }
+ s = s->next();
+ }
+}
+
+void searchable::active(Boolean a)
+{
+ active_ = a;
+
+ if(!toggle_ && parent_)
+ parent(parent_);
+
+ if(toggle_) {
+ if(active_)
+ XtManageChild(toggle_);
+ else
+ XtUnmanageChild(toggle_);
+ }
+}
+
+IMP(searchable)
+
+
+
+#if 0
+static char sccsid[] = "%W% %E% B.Raoult";
+
+#include "ecflowview.h"
+#include <Xm/List.h>
+#include <Xm/Text.h>
+
+static Widget text;
+static int ignorecase = TRUE;
+static Widget last_shell = NULL;
+
+void search_set_text_callback(Widget w,Widget t,XtPointer cb)
+{
+ char *p;
+ Arg arg;
+
+ text = t;
+ while(!XtIsShell(t))
+ t = XtParent(t);
+
+ last_shell = t;
+
+ XtSetArg(arg,XmNtitle,&p);
+ XtGetValues(t,&arg,1);
+
+ xec_SetLabel(label_search_text,p);
+
+ XtManageChild(search_form);
+ XMapRaised(XtDisplay(search),XtWindow(search));
+
+}
+
+void hide_search_callback(Widget w,XtPointer cd,XtPointer cb)
+{
+
+ while(!XtIsShell(w))
+ w = XtParent(w);
+
+ if(last_shell == w)
+ {
+ XtUnmanageChild(search_form);
+ last_shell = NULL;
+ }
+}
+
+
+void search_case_callback(Widget w,int nocase,
+XmToggleButtonCallbackStruct *cb)
+{
+ if(cb->set) ignorecase = nocase;
+}
+
+void search_next_callback(Widget w,XtPointer cd,XtPointer cb)
+{
+ char *p = (char*)XmTextGetString(search_text);
+ Boolean (*f)(Widget,char*,Boolean,Boolean,Boolean);
+
+ if(!*p) return;
+ if(XmIsList(text))
+ f = xec_ListSearch;
+ else
+ if(XmIsText(text))
+ f = xec_TextSearch;
+ else f = help_search;
+
+ if(!(*f)(text,p,ignorecase,FALSE,TRUE)) ring(1);
+
+ XtFree((XtPointer)p);
+}
+#endif
diff --git a/view/src/searchable.h b/view/src/searchable.h
new file mode 100644
index 0000000..e034280
--- /dev/null
+++ b/view/src/searchable.h
@@ -0,0 +1,61 @@
+#ifndef searchable_H
+#define searchable_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#ifdef NO_BOOL
+#include "bool.h"
+#endif
+
+#ifndef ecflowview_H
+#include "ecflowview.h"
+#endif
+
+#ifndef extent_H
+#include "extent.h"
+#endif
+
+class node_lister;
+
+class searchable : public extent<searchable> {
+public:
+ searchable();
+
+ virtual ~searchable(); // Change to virtual if base class
+
+ void active(Boolean);
+
+ virtual const char* name() const = 0;
+ virtual void search(node_lister&) = 0;
+
+ static void look_for(node_lister&,bool);
+ static void parent(Widget);
+
+protected:
+
+ Widget toggle_;
+ Boolean active_;
+
+private:
+
+ searchable(const searchable&);
+ searchable& operator=(const searchable&);
+
+ static Widget parent_;
+};
+
+inline void destroy(searchable**) {}
+#endif
diff --git a/view/src/selection.cc b/view/src/selection.cc
new file mode 100644
index 0000000..c8f1601
--- /dev/null
+++ b/view/src/selection.cc
@@ -0,0 +1,153 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #9 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "selection.h"
+#include "node.h"
+#include "observer.h"
+#include "host.h"
+
+class selection_observer :public observer {
+ node* n_;
+ void gone(observable*);
+ void adoption(observable*,observable*);
+ void notification(observable*);
+
+ std::string location, top;
+
+public:
+
+ selection_observer() : n_(0), location ("") {}
+ void set(node*);
+ node* get() { return n_; }
+ const std::string path() { return location; }
+ const std::string server() { return top; }
+};
+
+static selection_observer current;
+static selection_observer menu;
+
+void selection_observer::set(node* n)
+{
+ if(n == n_)
+ return;
+
+ if(n_)
+ forget(&(n_->serv()));
+
+ forget(n_);
+ n_ = n;
+ observe(n_);
+
+ if(n_) {
+ observe((&n_->serv()));
+ top = n_->serv().name();
+ location = n_->full_name();
+ }
+}
+
+void selection_observer::adoption(observable* o,observable* n)
+{
+ if(o == n_)
+ n_ = (node*)n;
+ else
+ fprintf(stderr, "Selection adoption: bad value\n");
+}
+
+void selection_observer::gone(observable*)
+{
+ // printf("Selection gone\n");
+ n_ = 0;
+}
+
+void selection_observer::notification(observable*)
+{
+}
+
+
+selection::selection()
+{
+}
+
+selection::~selection()
+{
+}
+
+void selection::notify_new_selection(node* n)
+{
+ if(n == current.get())
+ return;
+
+ if(n == 0) {
+ notify_selection_cleared();
+ return;
+ }
+
+ // printf("selection is %s %s %02d\n", n->full_name().c_str(), n->type_name(), n->type());
+
+ // if(!n->selectable()) return;
+
+ selection* w = first();
+
+ current.set(n);
+
+ while(w) {
+ w->new_selection(*n);
+ w = w->next();
+ }
+}
+
+void selection::notify_selection_cleared()
+{
+ if(current.get() == 0)
+ return;
+
+ // printf("selection is cleared\n");
+
+ selection* w = first();
+
+ current.set(0);
+
+ while(w)
+ {
+ w->selection_cleared();
+ w = w->next();
+ }
+}
+
+void selection::menu_node(node* n)
+{
+ menu.set(n);
+}
+
+node *selection::menu_node()
+{
+ return menu.get();
+}
+
+node *selection::current_node()
+{
+ return current.get();
+}
+
+const std::string selection::current_path()
+{
+ return current.path();
+}
+
+const std::string selection::server()
+{
+ return current.server();
+}
+IMP(selection)
diff --git a/view/src/selection.h b/view/src/selection.h
new file mode 100644
index 0000000..18a03b8
--- /dev/null
+++ b/view/src/selection.h
@@ -0,0 +1,56 @@
+#ifndef selection_H
+#define selection_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#ifndef extent_H
+#include "extent.h"
+#endif
+#include <string>
+
+class host;
+class node;
+class ecf_node;
+
+class selection : public extent<selection> {
+public:
+
+ selection();
+
+ virtual ~selection(); // Change to virtual if base class
+
+ virtual void selection_cleared() = 0;
+ virtual void new_selection(node&) = 0;
+
+ static void notify_new_selection(node*);
+ static void notify_selection_cleared();
+
+ static node* menu_node();
+ static void menu_node(node*);
+ static node* current_node();
+ static const std::string current_path();
+ static const std::string server();
+
+private:
+
+ selection(const selection&);
+ selection& operator=(const selection&);
+
+ friend class selection_observer;
+};
+
+inline void destroy(selection**) {}
+#endif
diff --git a/view/src/server.cc b/view/src/server.cc
new file mode 100644
index 0000000..5ae4810
--- /dev/null
+++ b/view/src/server.cc
@@ -0,0 +1,179 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#ifndef server_H
+#include "server.h"
+#endif
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <string.h>
+
+
+#ifdef AIX
+#include <memory.h>
+#endif
+
+#define FAIL(a) do { perror(a); exit(1); } while(0)
+
+server::server(int port):
+ soc_(-1)
+{
+ int flg;
+ struct sockaddr_in sin;
+
+#ifdef SO_LINGER
+ struct linger ling;
+#endif
+
+ soc_ = socket(AF_INET, SOCK_STREAM, 0);
+
+ if (soc_ < 0)
+ FAIL("socket");
+
+ flg = 1 ;
+ if(setsockopt(soc_, SOL_SOCKET, SO_REUSEADDR, &flg, sizeof(flg))<0)
+ FAIL("setsockopt SO_REUSEADDR");
+
+ flg = 1 ;
+ if(setsockopt(soc_, SOL_SOCKET, SO_KEEPALIVE, &flg, sizeof(flg))<0)
+ FAIL("setsockopt SO_KEEPALIVE");
+
+#ifdef SO_REUSEPORT
+ flg = 1 ;
+ if(setsockopt(soc_, SOL_SOCKET, SO_REUSEPORT, &flg, sizeof(flg))<0)
+ FAIL("setsockopt SO_REUSEPORT");
+#endif
+
+#ifdef SO_LINGER
+ ling.l_onoff = 0;
+ ling.l_linger = 0;
+ if(setsockopt(soc_, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling))<0)
+ FAIL("setsockopt SO_LINGER");
+#else
+#ifdef SO_DONTLINGER
+ if(setsockopt(soc_, SOL_SOCKET, SO_DONTLINGER, NULL, 0)<0)
+ FAIL("setsockopt SO_DONTLINGER");
+#endif
+#endif
+
+
+ memset(&sin, 0, sizeof(struct sockaddr_in));
+ sin.sin_port = htons(port);
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = INADDR_ANY;
+
+ while (bind(soc_, (struct sockaddr*)&sin, sizeof(struct sockaddr_in)) == -1)
+ {
+ FAIL("bind");
+ sleep(5);
+ }
+
+ /* socket_buffers(s); */
+
+ if(listen(soc_, 5)==-1)
+ {
+ close(soc_);
+ FAIL("listen");
+ }
+
+ signal(SIGPIPE,SIG_IGN);
+}
+
+server::~server()
+{
+ close(soc_);
+}
+
+void server::run()
+{
+ struct sockaddr_in from;
+//#ifdef AIX
+// unsigned long fromlen;
+//#else
+ socklen_t fromlen; // int fromlen;
+//#endif
+ int cnt = 0;
+ int clients = 0;
+
+ /* Start real server */
+
+ if(soc_ < 0) FAIL("Exiting server");
+
+ /* Dont't get killed by pipes */
+ signal(SIGPIPE,SIG_IGN);
+
+ /* Ignore hang up */
+ signal(SIGHUP,SIG_IGN);
+
+ for(;;)
+ {
+ int snew;
+ fromlen = sizeof(from);
+ if((snew = accept(soc_, (struct sockaddr*)&from, &fromlen))<0)
+ {
+ if(errno != EINTR)
+ /* Interrupted system call : got on SIGCHLD signals */
+ FAIL("accept");
+ }
+ else
+ {
+
+ if(from.sin_family != AF_INET)
+ {
+ FAIL("connection is not from internet");
+ close(snew);
+ continue;
+ }
+
+ fflush(0);
+ sighold(SIGCHLD);
+
+ if(!fork_)
+ {
+ serve(snew);
+ close(snew);
+ }
+ else switch(fork())
+ {
+ case 0:
+ close(soc_);
+ serve(snew);
+ exit(0);
+ break;
+
+ case -1:
+ FAIL("Cannot fork");
+ close(snew);
+ break;
+
+ default:
+ cnt++;
+ clients++;
+ close(snew);
+ break;
+ }
+ sigrelse(SIGCHLD);
+ }
+ }
+}
diff --git a/view/src/server.h b/view/src/server.h
new file mode 100644
index 0000000..b3180c3
--- /dev/null
+++ b/view/src/server.h
@@ -0,0 +1,40 @@
+#ifndef server_H
+#define server_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+class server {
+public:
+
+ server(int port);
+ virtual ~server();
+
+ void run();
+ virtual void serve(int) = 0;
+
+private:
+
+ server(const server&);
+ server& operator=(const server&);
+
+ int soc_;
+ bool fork_;
+
+};
+
+inline void destroy(server**) {}
+
+#endif
diff --git a/view/src/servers_prefs.cc b/view/src/servers_prefs.cc
new file mode 100644
index 0000000..c09cd0d
--- /dev/null
+++ b/view/src/servers_prefs.cc
@@ -0,0 +1,259 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #8 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "servers_prefs.h"
+#include "host.h"
+#include "observer.h"
+#include "gui.h"
+#include "xec.h"
+#include "extent.h"
+#include <ctype.h>
+#include <Xm/Text.h>
+#include <Xm/ToggleB.h>
+#include <Xm/List.h>
+
+/* user hosts are added in map order in the 'servers' file:
+ order then appears as different according to creation order and
+ alphabetic/map order
+*/
+static bool valid_name(const str& n)
+{
+ const char* p = n.c_str();
+
+ if(*p == 0) return true;
+
+ while(*p) {
+ if(*p != '_' && !isalnum(*p))
+ return false;
+ p++;
+ }
+
+ return true;
+}
+
+static bool valid_host(const str& n)
+{
+ const char* p = n.c_str();
+
+ if(*p == 0) return false;
+
+ while(*p) {
+ if(*p != '-' && *p != '.' && !isalnum(*p))
+ return false;
+ p++;
+ }
+
+ return true;
+}
+
+static bool valid_num(int)
+{
+ return true;
+}
+
+void servers_prefs::add_host(const std::string& h)
+{
+ str host = h;
+ instance().add(host);
+}
+
+void servers_prefs::create(Widget w,char*)
+{
+ servers_form_c::create(w);
+ prefs::setup(w);
+ build_list();
+}
+
+void servers_prefs::build_list()
+{
+ XmListDeleteAllItems(list_);
+
+ array<str> x = hosts_;
+ hosts_.clear();
+
+ for(int i = 0; i < x.count(); i++) {
+ add(x[i]);
+ }
+ xec_ListItemSelect(list_,current_.c_str());
+}
+
+void servers_prefs::add(str&h)
+{
+ hosts_.add(h);
+ if(_xd_rootwidget == 0)
+ return;
+
+ host *x = host::find(h.c_str());
+ if(x)
+ xec_AddListItem(list_,(char*)h.c_str());
+}
+
+void servers_prefs::serversCB(Widget,XtPointer)
+{
+ host::broadcast(true);
+}
+
+str servers_prefs::name()
+{
+ char *p = XmTextGetString(name_);
+ char *h = XmTextGetString(host_);
+
+ str x(*p?p:h);
+
+ XtFree(p);
+ XtFree(h);
+
+ return x;
+}
+
+str servers_prefs::machine()
+{
+ char *p = XmTextGetString(name_);
+ char *h = XmTextGetString(host_);
+
+ str x(*h?h:p);
+
+ XtFree(p);
+ XtFree(h);
+
+ return x;
+}
+
+int servers_prefs::number()
+{
+
+ char *n = XmTextGetString(number_);
+ int x = atol(n);
+ XtFree(n);
+
+ return x?x: 3141 ;
+}
+
+void servers_prefs::addCB(Widget,XtPointer)
+{
+ str p = name();
+ str h = machine();
+ int n = number();
+
+ host* y = host::find(p.c_str());
+
+ int v = valid_name(p) && valid_host(h) && valid_num(n);
+
+ if(v && (y == 0))
+ {
+ host::new_host(p.c_str(),h.c_str(),n);
+ current_ = p;
+ xec_ListItemSelect(list_,p.c_str());
+
+ build_list(); // TBD
+ XtSetSensitive(update_,false);
+ XtSetSensitive(add_,false);
+ XtSetSensitive(remove_,true);
+ ecf_nick_write(); // TBD
+ }
+}
+
+void servers_prefs::removeCB(Widget,XtPointer)
+{
+ xec_RemoveListItem(list_,(char*)current_.c_str());
+ host::remove_host(current_.c_str());
+
+ hosts_.remove(current_);
+ current_ = "";
+
+ XtSetSensitive(remove_,false);
+ XtSetSensitive(update_,false);
+ XtSetSensitive(add_,false);
+
+ XmTextSetString(name_,"");
+ XmTextSetString(host_,"");
+ XmTextSetString(number_,"");
+
+ ecf_nick_write();
+}
+
+void servers_prefs::check_remove()
+{
+}
+
+void servers_prefs::browseCB(Widget,XtPointer data)
+{
+ XmListCallbackStruct *cb = (XmListCallbackStruct *) data;
+ char *p = xec_GetString(cb->item);
+
+ current_ = p;
+
+ host *x = host::find(p);
+ if(x)
+ {
+ changing_ = true;
+ XmTextSetString(name_,(char*)x->name());
+ XmTextSetString(host_,(char*)x->machine());
+
+ char buf[80];
+ sprintf(buf,"%d",x->number());
+ XmTextSetString(number_,buf);
+ changing_ = false;
+ }
+
+ XtFree(p);
+
+ XtSetSensitive(remove_,true);
+ XtSetSensitive(update_,false);
+ XtSetSensitive(add_,false);
+}
+
+void servers_prefs::changedCB(Widget,XtPointer data)
+{
+ if(changing_) return;
+
+ str p = name();
+ str h = machine();
+ int n = number();
+
+ host* x = host::find(current_.c_str());
+ host* y = host::find(p.c_str());
+
+ int v = valid_name(p) && valid_host(h) && valid_num(n);
+
+ if(x) {
+ bool c = (current_ != p) || (h != str(x->machine())) ||
+ (n != x->number());
+ XtSetSensitive(update_,v && (y == x || y == 0) && c);
+ }
+
+ XtSetSensitive(add_,v && (y == 0));
+}
+
+void servers_prefs::updateCB(Widget,XtPointer data)
+{
+ str p = name();
+ str h = machine();
+ int n = number();
+
+ host* x = host::find(current_.c_str());
+ host* y = host::find(p.c_str());
+
+ int v = valid_name(p) && valid_host(h) && valid_num(n);
+ if(v && x && (x == y || y == 0))
+ {
+ x->change(p.c_str(),h.c_str(),n);
+ xec_ReplaceListItem(list_,current_.c_str(),p.c_str());
+ xec_ListItemSelect(list_,p.c_str());
+ current_ = p;
+ XtSetSensitive(update_,false);
+ XtSetSensitive(add_,false);
+ }
+}
diff --git a/view/src/servers_prefs.h b/view/src/servers_prefs.h
new file mode 100644
index 0000000..1821c26
--- /dev/null
+++ b/view/src/servers_prefs.h
@@ -0,0 +1,79 @@
+#ifndef servers_prefs_H
+#define servers_prefs_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#ifndef prefs_H
+#include "prefs.h"
+#endif
+
+#ifndef uiservers
+#include "uiservers.h"
+#endif
+
+#ifndef str_H
+#include "str.h"
+#endif
+
+#ifndef array_H
+#include "array.h"
+#endif
+
+#ifndef Singleton_H
+#include "singleton.h"
+#endif
+
+class servers_prefs : public singleton<servers_prefs>, public prefs
+ , public servers_form_c {
+public:
+
+ servers_prefs() : changing_(false) {}
+
+ ~servers_prefs() {}
+
+ void check_remove();
+
+ virtual Widget widget() { return _xd_rootwidget; }
+
+ static void add_host(const std::string&);
+private:
+
+ servers_prefs(const servers_prefs&);
+ servers_prefs& operator=(const servers_prefs&);
+
+ array<str> hosts_;
+ bool changing_;
+ str current_;
+
+ int number();
+ str name();
+ str machine();
+
+ void add(str&);
+ void build_list();
+
+ virtual void browseCB( Widget w, XtPointer );
+ virtual void serversCB( Widget w, XtPointer );
+ virtual void addCB( Widget w, XtPointer );
+ virtual void removeCB( Widget w, XtPointer );
+ virtual void updateCB( Widget w, XtPointer );
+ virtual void changedCB( Widget w, XtPointer );
+ virtual void create(Widget w,char*);
+};
+
+inline void destroy(servers_prefs**) {}
+
+#endif
diff --git a/view/src/show.cc b/view/src/show.cc
new file mode 100644
index 0000000..c04ff53
--- /dev/null
+++ b/view/src/show.cc
@@ -0,0 +1,93 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "show.h"
+#include "globals.h"
+option<int> show::status32_ (globals::instance(), "show_mask32", 0);
+
+option<int> show::status_ (globals::instance(), "show_mask",
+ (1<<show::unknown)
+ |(1<<show::suspended)
+ |(1<<show::complete)
+ |(1<<show::queued)
+ |(1<<show::submitted)
+ |(1<<show::active)
+ |(1<<show::aborted)
+ |(1<<show::time_dependant)
+ |(1<<show::late_nodes)
+ // |(1<<show::migrated_nodes)
+ |(1<<show::rerun_tasks)
+ |(1<<show::nodes_with_messages)
+ |(1<<show::label)
+ |(1<<show::meter)
+ |(1<<show::event)
+ |(1<<show::repeat)
+ |(1<<show::time)
+ |(1<<show::date)
+ |(1<<show::late)
+ |(1<<show::inlimit)
+ |(1<<show::limit)
+ |(1<<show::trigger)
+ // & (~(1<<show::variable))
+ // & (~(1<<show::genvar))
+ |(1<<show::time_icon)
+ |(1<<show::date_icon)
+ |(1<<show::late_icon)
+ |(1<<show::waiting_icon)
+ |(1<<show::rerun_icon)
+ // |(1<<show::migrated_icon)
+ |(1<<show::message_icon)
+ // & (~(1<<show::defstatus_icon)) & (~(1<<show::zombie_icon))
+ );
+
+show::show(int f) : flag_(f) {
+ status_ = status_ & (~(1<<show::variable));
+ status_ = status_ & (~(1<<show::genvar));
+}
+
+show::~show() {}
+
+void show::on()
+{
+ if (flag_ > 31) {
+ status32_ = int(status32_) | (1<<(flag_-32));
+ } else {
+ status_ = int(status_ ) | (1<<(flag_));
+ }
+}
+
+void show::off()
+{
+ if (flag_ == show::all) {
+ status_ = 0xFFFF ; status32_ = 0xFFFF;
+ status32_ = (int) (status32_) & (~(1<<(show::none-32)));
+ status32_ = (int) (status32_) & (~(1<<(show::all -32)));
+ } else if (flag_ == show::none) {
+ status_ = 0; status32_ = 0;
+ } else if (flag_ > 31) {
+ status32_ = int(status32_) & (~(1<<(flag_-32)));
+ } else {
+ status_ = int(status_) & (~(1<<flag_));
+ }
+}
+
+bool show::wanted()
+{
+ if (flag_ > 31) {
+ return (int(status32_) & (1<<(flag_-32))) != 0;
+ } else {
+ return (int(status_ ) & (1<<flag_)) != 0;
+ }
+}
diff --git a/view/src/show.h b/view/src/show.h
new file mode 100644
index 0000000..3d17c0b
--- /dev/null
+++ b/view/src/show.h
@@ -0,0 +1,104 @@
+#ifndef show_H
+#define show_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+// #include <inttypes.h>
+
+#ifndef option_H
+#include "option.h"
+#endif
+
+#ifdef WITH_INT128
+#define VLONG uint128
+#else
+// #define VLONG uint64_t
+// #define VLONG unsigned long long
+// #define VLONG __int64
+#define VLONG int
+#endif
+
+
+class show {
+ int flag_;
+ static option< VLONG > status_;
+ static option< VLONG > status32_;
+
+public:
+
+ enum {
+ unknown ,
+ suspended ,
+ complete ,
+ queued ,
+ submitted ,
+ active ,
+ aborted ,
+ time_dependant ,
+ late_nodes ,
+ waiting_nodes ,
+ migrated_nodes ,
+ rerun_tasks ,
+ nodes_with_messages ,
+ label ,
+ meter,
+ event ,
+ repeat ,
+ time ,
+ date ,
+ late ,
+ trigger,
+ variable,
+ genvar,
+ limit,
+ inlimit,
+ time_icon,
+ date_icon,
+ late_icon,
+ waiting_icon,
+ rerun_icon,
+ migrated_icon,
+ message_icon,
+
+ defstatus_icon, zombie_icon, // time_holding_icon, date_holding_icon
+ all, none
+ };
+
+ // show(int f) : flag_(f) {};
+ show(int f);
+ ~show();
+
+ void on();
+ void off();
+ bool wanted();
+
+ static inline bool want(int flag) {
+ return (flag > 31) ?
+ (int(status32_) & (1<<(flag-32))) != 0 :
+ (int(status_) & (1<<flag))!=0; }
+
+ static inline bool want32(int flag)
+ { return (flag > 31) ?
+ (int(status32_) & (1<<(flag-32))) != 0 :
+ false; }
+
+ static inline VLONG status() { return int(status_); }
+
+ VLONG flag() const { return flag_; }
+private:
+ show(const show&);
+ show& operator=(const show&);
+};
+#endif
diff --git a/view/src/simple_node.cc b/view/src/simple_node.cc
new file mode 100644
index 0000000..de79413
--- /dev/null
+++ b/view/src/simple_node.cc
@@ -0,0 +1,1085 @@
+//===================================================================================(variable_node* run==========
+// Name :
+// Author :
+// Revision : $Revision: #53 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "arch.h"
+#include "simple_node.h"
+#include "host.h"
+#include "show.h"
+#include "flags.h"
+#include "external.h"
+#include "selection.h"
+#include "pixmap.h"
+#include "url.h"
+#include "tree.h"
+#include "variable_node.h"
+#include "tip.h"
+
+#ifndef FLAG_HPP_
+#include "Flag.hpp"
+#endif
+#include "RepeatAttr.hpp"
+
+#include <X11/X.h>
+#include <Xm/ManagerP.h>
+#include <Xm/DrawP.h>
+#include <sstream>
+
+#include "trigger_lister.h"
+#include "text_lister.h"
+#include "html_lister.h"
+
+#ifndef events_H
+#include "events.h"
+#endif
+#include "dummy_node.h"
+
+#ifndef ecf_node_
+#include "ecf_node.h"
+#endif
+
+namespace ecf {
+const char *status_name[10]
+ = { "unknown", "suspended", "complete", "queued", "submitted", "active",
+ "aborted", "shutdown", "halted" , NULL };
+}
+
+const int kHMargins = 4;
+const int kVMargins = 1;
+
+static struct {
+ char* name_;
+ int vers_;
+ pixmap* pixmap_;
+ flags* flag_;
+ int show_;
+} pix[] = {
+ {(char*)"waiting", 0, 0, new procFlag(&node::isWaiting), show::waiting_icon},
+
+ {(char*)"clock", 0, 0, new procFlag(&node::hasTimeHolding), show::time_icon},
+ {(char*)"calendar", 0, 0, new procFlag(&node::hasDate), show::date_icon},
+
+ {(char*)"late", 0, 0, new procFlag(&node::isLate), show::late_icon},
+
+ {(char*)"rerun", 0, 0, new procFlag(&node::isRerun), show::rerun_icon},
+
+ {(char*)"migrated", 0, 0, new procFlag(&node::isMigrated),
+ show::migrated_icon},
+
+ {(char*)"message", 0, 0, new procFlag(&node::hasMessages),
+ show::message_icon},
+
+ {(char*)"defstatus", 0, 0, new procFlag(&node::isDefComplete),
+ show::defstatus_icon},
+
+ {(char*)"Zbw", 1, 0, new procFlag(&node::hasZombieAttr), show::zombie_icon},
+
+ {(char*)"Z", 1, 0, new procFlag(&node::isZombie), show::zombie_icon},
+
+ {(char*)"force_abort", 1, 0, new procFlag(&node::isForceAbort), 1},
+ {(char*)"user_edit", 1, 0, new procFlag(&node::isUserEdit), 1},
+ {(char*)"task_aborted", 1, 0, new procFlag(&node::isTaskAbort), 1},
+ {(char*)"edit_failed", 1, 0, new procFlag(&node::isEditFailed), 1},
+ {(char*)"cmd_failed", 1, 0, new procFlag(&node::isCmdFailed), 1},
+ {(char*)"no_script", 1, 0, new procFlag(&node::isScriptMissing), 1},
+ {(char*)"killed", 1, 0, new procFlag(&node::isKilled), 1},
+ {(char*)"byrule", 1, 0, new procFlag(&node::isByRule), 1},
+ {(char*)"queuelimit", 1, 0, new procFlag(&node::isQueueLimit), 1},
+
+ {(char*)"folded", 0, 0, new procFlag(&node::isFolded), 0},
+
+ {(char*)"locked", 0, 0, new procFlag(&node::isLocked), 0}, /* --- shall appear last */
+
+ {(char*)"clock_free", 0, 0, new procFlag(&node::hasTime), show::time_icon},
+
+};
+
+simple_node::simple_node(host& h,ecf_node* n) : node(h,n)
+ , old_status_(-1)
+ , old_tryno_(-1)
+ , old_flags_(-1)
+{
+ old_flags_ = flags();
+ old_status_ = status();
+ old_tryno_ = tryno();
+}
+
+const int kPixSize = 16;
+
+#ifdef BRIDGE
+simple_node::simple_node(host& h,sms_node* n, char b)
+ : node(h,n,b)
+ , old_status_(-1)
+ , old_tryno_(-1)
+ , old_flags_(-1)
+{
+ insert(node::create(h,(sms_node*)n->label));
+ insert(node::create(h,(sms_node*)n->meter));
+ insert(node::create(h,(sms_node*)n->event));
+ if (n->complete)
+ insert(node::create(h,(sms_node*)n->complete,'c'));
+ insert(node::create(h,(sms_node*)n->trigger, 't'));
+
+ insert(node::create(h,(sms_node*)n->repeat));
+ insert(node::create(h,(sms_node*)n->genvars,'g'));
+ insert(node::create(h,(sms_node*)n->variable));
+
+ insert(node::create(h,(sms_node*)n->limit));
+ insert(node::create(h,(sms_node*)n->inlimit));
+
+ insert(node::create(h,(sms_node*)n->date));
+ insert(node::create(h,(sms_node*)n->time));
+ insert(node::create(h,(sms_node*)n->autocm,'c'));
+
+ // if(n->late) n->late->parent = owner_;
+ insert(node::create(h,(sms_node*)n->late,'l'));
+}
+
+/* void simple_node::scan(sms_tree* m,text_lister& f,bool b) {} */
+
+ void simple_node::scan(sms_tree* m,trigger_lister& f,bool b) {}
+
+#endif
+
+simple_node::~simple_node()
+{
+}
+
+inline bool wanted(int n)
+{
+ return (n == 0 || show::want(n));
+}
+
+void simple_node::sizeNode(Widget w,XRectangle* r,bool tree)
+{
+ if(!tree) {
+ node::sizeNode(w,r,false);
+ return;
+ }
+
+ int extra = 0;
+ unsigned int i;
+
+ if(pix[0].pixmap_ == 0)
+ {
+ for(i = 0; i < XtNumber(pix); i++)
+ pix[i].pixmap_ = &(pixmap::find(pix[i].name_));
+ }
+
+ for(i = 0; i < XtNumber(pix) ; i++)
+ if(wanted(pix[i].show_) && pix[i].flag_->eval(this))
+ extra++;
+
+ XmString s = tree?labelTree():labelTrigger();
+ XmFontList f = tree?fontlist():smallfont();
+
+ r->width = XmStringWidth(f,s) + 2*kHMargins + extra * kPixSize;
+ r->height = XmStringHeight(f,s) + 2*kVMargins;
+ if(r->height < kPixSize + 2*kVMargins) r->height = kPixSize + 2*kVMargins;
+}
+
+void simple_node::drawBackground(Widget w,XRectangle* r,bool tree)
+{
+ node::drawBackground(w,r,tree);
+ GC gc = colorGC(status());
+ XFillRectangles(XtDisplay(w),XtWindow(w),gc,r,1);
+}
+
+void simple_node::drawNode(Widget w,XRectangle* r,bool tree)
+{
+ if(!tree) {
+ node::drawNode(w,r,tree);
+ shadow(w,r);
+ return;
+ }
+
+ unsigned int extra = 0;
+ Pixmap images[XtNumber(pix)];
+
+ XmString s = tree?labelTree():labelTrigger();
+ XmFontList f = tree?fontlist():smallfont();
+ unsigned int i;
+
+ for(i = 0; i < XtNumber(pix) ; i++)
+ if(wanted(pix[i].show_) && pix[i].flag_->eval(this))
+ images[extra++] = pix[i].pixmap_->pixels();
+
+ XRectangle x = *r;
+ x.width = XmStringWidth(f,s) + 2*kHMargins;
+ XRectangle y = x; // *r;
+
+ drawBackground(w,&y,tree);
+
+
+ XmStringDraw(XtDisplay(w),XtWindow(w),
+ f,
+ s,
+ blackGC(),
+ r->x /*+ kHMargins*/,
+ r->y + kVMargins,
+ x.width,
+ XmALIGNMENT_CENTER,
+ XmSTRING_DIRECTION_L_TO_R, r);
+
+ for(i = 0 ; i < extra ; i++)
+ {
+ /* XSetClipMask(XtDisplay(w),blackGC(),masks[i]); */
+ XCopyArea(XtDisplay(w),
+ images[i],
+ XtWindow(w),
+ blackGC(),
+ 0,0,kPixSize,kPixSize,
+ r->x + x.width + (i*kPixSize),
+ r->y + (r->height - kPixSize) / 2);
+ /* XSetClipMask(XtDisplay(w),blackGC(),None); */
+ }
+
+ shadow(w,&y);
+}
+
+
+Pixel simple_node::color() const
+{
+ return colors(status());
+}
+
+int simple_node::tryno() const {
+#ifdef BRIDGE
+ if (tree_) return tree_->tryno;
+#endif
+ return owner_ ? owner_->tryno() : -1;
+}
+
+Boolean simple_node::hasTriggers() const
+{
+#ifdef BRIDGE
+ if (tree_) return tree_->trigger != 0;
+#endif
+ return owner_ ? owner_->hasTrigger() : False;
+}
+
+Boolean simple_node::hasTime() const /* time is free , yellow background icon */
+{
+#ifdef BRIDGE
+ if (tree_) return tree_->time != 0;
+#endif
+ if (hasTimeHolding()) return False;
+ return owner_ ? owner_->hasTime() : False;
+}
+
+Boolean simple_node::hasDate() const
+{
+#ifdef BRIDGE
+ if (tree_) return tree_->date != 0;
+#endif
+ return owner_ ? owner_->hasDate() : False;
+}
+
+Boolean simple_node::hasTimeHolding() const /* grey */
+{
+ if (owner_)
+ if (owner_->hasTime()) {
+ Node *node = owner_->get_node();
+ if (!node) return False;
+ TimeDepAttrs *attr = node->get_time_dep_attrs();
+ if (!attr) return False;
+ return !attr->time_today_cron_is_free();
+ }
+ return False;
+}
+
+Boolean simple_node::hasZombieAttr() const
+{
+#ifdef BRIDGE
+ if (tree_) return ecfFlag(FLAG_ZOMBIE);
+#endif
+ return owner_ ? owner_->hasZombieAttr() : False;
+}
+
+Boolean simple_node::hasManual() const
+{ return True; }
+
+Boolean simple_node::isDefComplete() const {
+#ifdef BRIDGE
+ if (tree_) {
+ if (tree_->defstatus == STATUS_COMPLETE)
+ return True;
+ // else if (tree_ && sms_variable_getvar("SMSNOSCRIPT", tree_))
+ // return True;
+ else if (tree_->complete != 0 &&
+ (sms_status_trigger(tree_->complete) == FALSE))
+ return True;
+ }
+#endif
+ if (!owner_) return False;
+ else if (!owner_)
+ return False;
+ else if (owner_->defstatus() == STATUS_COMPLETE)
+ return True;
+ Node* ecf = __node__() ? __node__()->get_node() : 0;
+ if (ecf) {
+ AstTop* t = ecf->completeAst();
+ if (t)
+ if (t->evaluate())
+ return True;
+ }
+ return False;
+}
+
+std::string simple_node::variable(const std::string& name, bool substitute)
+{
+ if (__node__())
+ if (__node__()->get_node()) {
+ std::string value;
+ const Variable & var = __node__()->get_node()->findVariable(name);
+ if (!var.empty()) {
+ value = var.theValue();
+ if (substitute) {
+ __node__()->get_node()->update_generated_variables();
+ __node__()->get_node()->variableSubsitution(value);
+ }
+ return value;
+ } else {
+ __node__()->get_node()->findParentVariableValue(name, value);
+ if (substitute) {
+ __node__()->get_node()->update_generated_variables();
+ __node__()->get_node()->variableSubsitution(value);
+ }
+ if (!value.empty()) return value;
+ }
+ }
+ for (node *run = kids(); run; run = run->next()) {
+ if (run->type() == NODE_VARIABLE && run->name() == name) {
+ variable_node *nvar = (variable_node*) run;
+ if (nvar->get_var() != ecf_node::none())
+ return nvar->get_var();
+ }
+ }
+ if (!parent())
+ return ecf_node::none();
+ return parent()->variable(name, substitute);
+}
+
+void simple_node::info(std::ostream& f)
+{
+ static const std::string inc = " ";
+ node::info(f);
+ f << type_name() << " " << name() << "\n";
+ {
+ if (owner_) {
+
+ if (owner_->type() == NODE_SUITE) {
+ Suite* suite = dynamic_cast<Suite*>(owner_->get_node());
+ // f << "clock : ";
+ if (suite->clockAttr()) {
+ suite->clockAttr().get()->print(f); // f << "\n";
+ }
+ }
+
+ int defs = owner_->defstatus();
+ if (defs != STATUS_QUEUED && defs != STATUS_UNKNOWN)
+ f << inc << "defstatus " << ecf::status_name[defs] << "\n";
+
+ Node* node = owner_->get_node();
+ if (node) {
+ // if (node->repeat().toString() != "") // repeat // duplicated on suite node
+ // f << inc << node->repeat().toString() << "\n";
+
+ /* zombies attribute */
+ const std::vector<ZombieAttr> & vect = node->zombies();
+ std::vector<ZombieAttr>::const_iterator it;
+ for (it = vect.begin(); it != vect.end(); ++it)
+ f << inc << it->toString() << "\n";
+
+ /* autocancel */
+ if (node->hasAutoCancel() && node->get_autocancel())
+ f << inc << node->get_autocancel()->toString() << "\n";
+ }
+ }
+ if(status() == STATUS_SUSPENDED)
+ f << inc << "# " << type_name() << " " << this->name() << " is " << status_name()
+ << "\n";
+ }
+ {
+ std::vector<Variable> gvar;
+ std::vector<Variable>::const_iterator it, gvar_end;
+ ecf_node* prox = __node__();
+ if (!prox) return;
+
+ Defs* defs = 0;
+ Node* ecf = 0;
+ if (dynamic_cast<ecf_concrete_node<Node>*>(prox)) {
+ ecf = dynamic_cast<ecf_concrete_node<Node>*>(prox)->get();
+ }
+ else if (dynamic_cast<ecf_concrete_node<Task>*>(prox)) {
+ ecf = dynamic_cast<ecf_concrete_node<Task>*>(prox)->get();
+ }
+ else if (dynamic_cast<ecf_concrete_node<Family>*>(prox)) {
+ ecf = dynamic_cast<ecf_concrete_node<Family>*>(prox)->get();
+ }
+ else if (dynamic_cast<ecf_concrete_node<Suite>*>(prox)) {
+ ecf = dynamic_cast<ecf_concrete_node<Suite>*>(prox)->get();
+ }
+ else if (dynamic_cast<ecf_concrete_node<Defs>*>(prox)) {
+ defs = dynamic_cast<ecf_concrete_node<Defs>*>(prox)->get();
+ }
+ if (!ecf && !defs) {
+ return;
+ }
+
+ if (ecf ) {
+ gvar.clear();
+
+ DState::State defstatus = ecf->defStatus();
+ if (defstatus != DState::QUEUED && defstatus != DState::UNKNOWN)
+ f << inc << "# defstatus " << DState::toString(defstatus) << "\n";
+
+ if (ecf->hasTimeDependencies()) {
+ f << inc << "# time-date-dependencies: ";
+ if (ecf->isTimeFree()) f << "free\n";
+ else f << "holding\n";
+ }
+ ecf->gen_variables(gvar);
+ for(it = gvar.begin(); it != gvar.end(); ++it) {
+ f << inc << "# edit " << (*it).name() << " '" << (*it).theValue() << "'\n";
+ }
+
+ gvar = ecf->variables();
+ for(it = gvar.begin(); it != gvar.end(); ++it) {
+ f << inc << "edit " << (*it).name() << " '" << (*it).theValue() << "'\n";
+ }
+ }
+ if (defs) {
+ const std::vector<Variable>& gvar = defs->server().user_variables();
+ for(it = gvar.begin(); it != gvar.end(); ++it) {
+ f << inc << "# edit " << (*it).name() << " '" << (*it).theValue() << "'\n";
+ }
+ const std::vector<Variable>& var = defs->server().server_variables();
+ for(it = var.begin(); it != var.end(); ++it) {
+ f << inc << "edit " << (*it).name() << " '" << (*it).theValue() << "'\n";
+ }
+ }}
+
+ for (node *run=kids(); run; run=run->next())
+ if (run->type() == NODE_VARIABLE) {
+ /* variable_node *var = dynamic_cast<variable_node*> (run);
+ if (var && var->name() == "") { f << inc << "# empty variable!" << "\n"; continue; }
+ if (var->isGenVariable(0x0))
+ f << inc << "# edit " << run->name() << " '" << var->get_var() << "'" << "\n";
+ else
+ f << inc << "edit " << run->name() << " '" << var->get_var() << "'" << "\n";*/
+ } else {
+ f << inc;
+ int i = run->type();
+ if (!owner_ || (i == NODE_SUITE || i == NODE_FAMILY ||
+ i == NODE_TASK || i == NODE_ALIAS))
+ f << run->type_name() << " ";
+ f << run->toString() << "\n";
+ // f << run->dump() << "\n";
+ }
+ f << "end" << type_name() << " # " << name() << "\n";
+}
+
+void simple_node::scan(Ast *m,trigger_lister& tlr,node* trg)
+{
+ if(!m) return;
+ std::string path = "";
+ { AstNode *an = dynamic_cast<AstNode*> (m);
+ if(an) { path = an->nodePath(); path = m->expression(); } }
+ { AstVariable *an = dynamic_cast<AstVariable*> (m);
+ if(an) { path = an->nodePath(); path = m->expression(); } }
+
+ if (path != "") {
+ node* n = parent() ? parent()->find(path) : node::find(path);
+
+ if(n) {
+ tlr.next_node(*n,0,trigger_lister::normal,trg);
+ } else if (external::is_external(path))
+ tlr.next_node(external::get(path),0,trigger_lister::normal,trg);
+ }
+ {
+ scan(m->left(), tlr,trg);
+ scan(m->right(),tlr,trg);
+ }
+}
+
+/*******************************/
+
+class fik : public trigger_lister {
+ node* n_;
+ node* k_;
+ trigger_lister& l_;
+public:
+
+ fik(node* n,node* k,trigger_lister& l): n_(n),k_(k),l_(l) {};
+
+ void next_node(node& n, node*,int type,node *t) {
+ if(!n.is_my_parent(n_)) {
+ // k is a kid of n whose trigger_panel is outside its subtree
+ l_.next_node(n,k_,trigger_lister::child,t);
+ }
+ }
+};
+
+class fip : public trigger_lister {
+ node* p_;
+ trigger_lister& l_;
+
+public:
+ fip(node* p,trigger_lister& l) : p_(p), l_(l) {}
+
+ void next_node(node& n, node*,int type,node *t)
+ { l_.next_node(n,p_,trigger_lister::parent,t); }
+};
+
+/*******************************/
+
+static void find_in_kids(node& n,node* k,trigger_lister& tlr)
+{
+ while(k) {
+ fik f(&n,k,tlr);
+ k->triggers(f);
+ find_in_kids(n,k->kids(),tlr);
+ k = k->next();
+ }
+}
+#include <ExprAstVisitor.hpp>
+
+class AstCollateXNodesVisitor : public ecf::ExprAstVisitor {
+public:
+ AstCollateXNodesVisitor( std::set<node*>& );
+ virtual ~AstCollateXNodesVisitor();
+
+ virtual void visitTop(AstTop*){}
+ virtual void visitRoot(AstRoot*){}
+ virtual void visitAnd(AstAnd*){}
+ virtual void visitNot(AstNot*){}
+ virtual void visitPlus(AstPlus*){}
+ virtual void visitMinus(AstMinus*){}
+ virtual void visitDivide(AstDivide*){}
+ virtual void visitMultiply(AstMultiply*){}
+ virtual void visitModulo(AstModulo*){}
+ virtual void visitOr(AstOr*){}
+ virtual void visitEqual(AstEqual*){}
+ virtual void visitNotEqual(AstNotEqual*){}
+ virtual void visitLessEqual(AstLessEqual*){}
+ virtual void visitGreaterEqual(AstGreaterEqual*){}
+ virtual void visitGreaterThan(AstGreaterThan*){}
+ virtual void visitLessThan(AstLessThan*){}
+ virtual void visitLeaf(AstLeaf*){}
+ virtual void visitInteger(AstInteger*){}
+ virtual void visitString(AstString*){}
+ virtual void visitNodeState(AstNodeState*){}
+ virtual void visitEventState(AstEventState*);
+ virtual void visitNode(AstNode*);
+ virtual void visitVariable(AstVariable*);
+
+private:
+ std::set<node*>& theSet_;
+};
+
+
+AstCollateXNodesVisitor::AstCollateXNodesVisitor( std::set<node*>& s) : theSet_(s) {}
+AstCollateXNodesVisitor::~AstCollateXNodesVisitor() {}
+
+void AstCollateXNodesVisitor::visitEventState(AstEventState* astNode)
+{
+}
+
+void AstCollateXNodesVisitor::visitNode(AstNode* astNode)
+{
+ Node* referencedNode = astNode->referencedNode();
+ node* xnode = NULL;
+ if (referencedNode)
+ xnode = (node*) referencedNode->graphic_ptr();
+ if ( xnode ) theSet_.insert(xnode);
+}
+
+void AstCollateXNodesVisitor::visitVariable(AstVariable* astVar)
+{
+ Node* referencedNode = astVar->referencedNode();
+ if (referencedNode) {
+ simple_node* xnode = (simple_node*) referencedNode->graphic_ptr();
+ if (0 == xnode) return;
+
+ int type;
+ node* run;
+ for (run = xnode->kids(); 0 != run; run = run->next()) {
+ if (run->name() == astVar->name()) {
+ type = run->type();
+ if (type == NODE_EVENT
+ || type == NODE_METER
+ || type == NODE_VARIABLE) {
+ theSet_.insert(run);
+ }
+ }
+ }
+ }
+}
+
+void simple_node::triggers(trigger_lister& tlr)
+{
+ if(tlr.self()) {
+#ifdef BRIDGE
+ if (tree_) {
+ sms_node* ow = tree_;
+ if(ow->trigger)
+ scan(((sms_trigger*)ow->trigger)->math,tlr,node::find((sms_node*) ow->trigger));
+
+ if(ow->complete)
+ scan(((sms_trigger*)ow->complete)->math,tlr,node::find((sms_node*) ow->complete));
+
+ sms_limit* x = (sms_limit*) (ow->inlimit);
+ while(x)
+ {
+ node* n = node::find((sms_node*) x->limit);
+ if(n) tlr.next_node(*n,0,trigger_lister::normal,n);
+ x = x->next;
+ }
+
+ sms_date* d = ow->date;
+ while(d) {
+ node* n = node::find((sms_node*) d);
+ if(n) tlr.next_node(*n,0,trigger_lister::normal,n);
+ d = d->next;
+ }
+
+ sms_time* t = ow->time;
+ while(t) {
+ node* n = node::find((sms_node*) t);
+ if(n) tlr.next_node(*n,0,trigger_lister::normal,n);
+ t = t->next;
+ }
+ }
+ else
+#endif
+ if (owner_) {
+ if (type() != NODE_SUPER && type() != NODE_SUITE) {
+ Node* ecf = __node__() ? __node__()->get_node() : 0;
+ std::set<node*> theSet;
+ std::set<node*>::iterator sit;
+ AstCollateXNodesVisitor astVisitor(theSet);
+
+ if (ecf) {
+ if (ecf->completeAst()) {
+ ecf->completeAst()->accept(astVisitor);
+ }
+ if (ecf->triggerAst()) {
+ ecf->triggerAst()->accept(astVisitor);
+ }
+ }
+ for (sit = theSet.begin(); sit != theSet.end(); ++sit)
+ tlr.next_node( *(*sit), 0, trigger_lister::normal, *sit);
+ }
+
+ for (node *n = this->kids(); n ; n = n->next()) {
+ int type = n->type();
+ {
+ ecf_concrete_node<InLimit const> *c =
+ dynamic_cast<ecf_concrete_node<InLimit const>*> (n->__node__());
+ InLimit const * i = c ? c->get() : 0;
+ if (i) {
+ node *xn = 0;
+ if ((xn = find_limit(i->pathToNode(), i->name())))
+ tlr.next_node(*xn,0,trigger_lister::normal,xn);
+ }
+ }
+ if (type == NODE_DATE || type == NODE_TIME)
+ tlr.next_node(*n,0,trigger_lister::normal,n);
+ }
+ }
+ }
+ if(tlr.parents()) {
+ node* p = parent();
+ while(p) {
+ fip f(p,tlr);
+ p->triggers(f);
+ p = p->parent();
+ }
+ }
+
+ if(tlr.kids())
+ find_in_kids(*this,kids(),tlr);
+ }
+
+boost::posix_time::ptime simple_node::status_time() const {
+ if (owner_) return owner_->status_time();
+ return boost::posix_time::ptime();
+}
+
+int simple_node::flags() const {
+#ifdef BRIDGE
+ if (tree_) return tree_->flags;
+#endif
+ // FIXME defs
+ return owner_ ? owner_->flags() : 0;
+}
+
+Boolean simple_node::ecfFlag(int n) const
+{
+ return (flags() & (1<<n)) != 0;
+}
+
+Boolean simple_node::show_it() const
+{
+ if(show::want(show::time_dependant) && (hasDate() || hasTime()))
+ return True;
+
+ if(show::want(show::late_nodes) && isLate())
+ return True;
+
+ if(show::want(show::migrated_nodes) && isMigrated())
+ return True;
+
+ if(show::want(show::rerun_tasks) && tryno() > 1)
+ return True;
+
+ if(show::want(show::nodes_with_messages) && hasMessages())
+ return True;
+
+ if(show::want(show::waiting_nodes) && isWaiting())
+ return True;
+
+ if(show::want(show::defstatus_icon) && isDefComplete())
+ return True;
+
+ if(show::want(show::zombie_icon) && isZombie())
+ return True;
+
+ node* k = kids();
+ while(k) {
+ if(k->show_it())
+ return True;
+ k = k->next();
+ }
+
+ return False;
+}
+
+Boolean simple_node::visible() const
+{
+ int wanted = status() - STATUS_UNKNOWN + show::unknown;
+ try {
+ if(selection::current_node())
+ if (selection::current_node()->full_name() == this->full_name())
+ return True;
+ if(this == selection::current_node())
+ return True;
+ }
+ catch ( std::exception& e ) {
+ gui::message("# problem with selection?");
+ gui::message(e.what());
+ }
+
+ if((wanted < 32 && (show::want(wanted))) || show::want32(wanted))
+ return True;
+
+ node* n = kids_;
+ while(n) {
+ if(n->visible_kid()) return True;
+ n = n->next();
+ }
+ return False;
+}
+
+Boolean simple_node::visible_kid() const
+{
+ return visible();
+}
+
+
+const char* simple_node::status_name() const
+{
+#ifdef BRIDGE
+ if (tree_) return ecf::status_name[tree_->status];
+#endif
+ return ecf::status_name[owner_ ? owner_->status() : 0];
+}
+
+void simple_node::why(std::ostream& f)
+{
+ if (owner_)
+ owner_->why(f);
+ else if(status() == STATUS_SUSPENDED) {
+ f << type_name() << " " << this << " is " << status_name() << "\n";
+ }
+}
+
+void simple_node::scan_limit(Ast* m,std::ostream& f)
+{
+ if(!m) return;
+
+ AstNode *an = dynamic_cast<AstNode*> (m);
+ if(an) {
+ const node* n = node::find(an->nodePath());
+ if(!n)
+ f << "limit_node not found??\n";
+ else if(n->evaluate())
+ f << n->type_name() << " " << n->name() << " is " << n->status_name() << "\n";
+ } else {
+ scan_limit(m->left(),f);
+ scan_limit(m->right(),f);
+ }
+}
+
+int kind(Ast *t) {
+ int rc = 0;
+ if (!t) return rc;
+
+ ++rc ; if (t->type() == "or") return rc;
+ ++rc ; if (t->type() == "and") return rc;
+ ++rc ; if (t->type() == "equal") return rc;
+ ++rc ; if (t->type() == "not-equal") return rc;
+ ++rc ; if (t->type() == "less-than") return rc;
+ ++rc ; if (t->type() == "less-equal") return rc;
+ ++rc ; if (t->type() == "greater-than") return rc;
+ ++rc ; if (t->type() == "greater-equal") return rc;
+ ++rc ; if (t->type() == "plus") return rc;
+ ++rc ; if (t->type() == "minus") return rc;
+ ++rc ; // if (t->type == "multiply") return rc;
+ ++rc ; // if (t->type == "divide") return rc;
+ ++rc ; // if (t->type == "mod") return rc;
+ ++rc ; // if (t->type == "pow") return rc;
+ ++rc ; if (t->type() == "not") return rc;
+ ++rc ; if (t->type() == "unary") return rc;
+ ++rc ; if (t->type() == "open") return rc;
+ ++rc ; if (t->type() == "close") return rc;
+ ++rc ; if (t->type() == "node") return rc;
+ if (t->type() == "variable") return rc;
+ if (t->type() == "event_state") return rc;
+ return 0;
+}
+
+static struct {
+ int eval_;
+ int print_;
+ char* pos_;
+ char* neg_;
+} names [] = {
+ {0,0,(char*)"",(char*)"",}, // M_NIL
+ {1,0,(char*)"",(char*)"",}, // M_OR
+ {1,0,(char*)"",(char*)"",}, // M_AND
+ {1,1,(char*)"is", (char*)"is not",}, // M_EQ
+ {1,1,(char*)"is not", (char*)"is",}, // M_NE
+ {1,1,(char*)"is less than", (char*)"is greater or equal to",}, // M_LT
+ {1,1,(char*)"is less or equal to", (char*)"is greater than",}, // M_LE
+ {1,1,(char*)"is greater than", (char*)"is less or equal to",}, // M_GT
+ {1,1,(char*)"is greater or equal to",(char*)"is less than",}, // M_GE
+ {0,1,(char*)" + ",(char*)" + ",}, // M_ADD
+ {0,1,(char*)" - ",(char*)" - ",}, // M_SUB
+ {0,0,(char*)"",(char*)"",}, // M_MUL
+ {0,0,(char*)"",(char*)"",}, // M_DIV
+ {0,0,(char*)"",(char*)"",}, // M_MOD
+ {0,0,(char*)"",(char*)"",}, // M_POW
+ {0,0,(char*)"",(char*)"",}, // M_NOT
+ {0,0,(char*)"",(char*)"",}, // M_UNARY
+ {0,0,(char*)"",(char*)"",}, // M_OPEN
+ {0,0,(char*)"",(char*)"",}, // M_CLOSE
+ {0,0,(char*)"",(char*)"",}, // M_NAME
+};
+
+void simple_node::scan(Ast* m,std::ostream& f,bool b)
+{
+ if(m == 0) return;
+ std::cout << "# scan:" << m->expression() << "\n";
+ std::string cp = "";
+
+ { AstNode *an = dynamic_cast<AstNode*> (m);
+ if(an) { cp = an->nodePath(); cp = m->expression();} }
+ { AstVariable *an = dynamic_cast<AstVariable*> (m);
+ if(an) { cp = an->nodePath(); cp = m->expression();} }
+
+ if(cp != "") {
+ const node* n = node::find(cp);
+ if(!n) {
+ if(external::is_external(cp))
+ f << " (unknown)";
+ else
+ f << cp << " (not found?)";
+ return;
+ }
+
+ f << n->type_name() << ' ' << n->name() << '(' << n->status_name() << ')';
+ // node* s = f.source(); if(s && n->is_my_parent(s)) f << cancel;
+ } else {
+ if(external::is_external(cp))
+ f << " (unknown)";
+ }
+
+ if(m->type() == "not")
+ b = !b;
+
+ scan(m->left(),f,b);
+
+ f << ' ' << (b ? names[kind(m)].pos_ : names[kind(m)].neg_) << ' ';
+
+ scan(m->right(),f,b);
+
+ if(names[kind(m)].print_)
+ f << "\n";
+}
+
+class why_triggers : public trigger_lister {
+ std::ostream& f_;
+
+public:
+
+ virtual Boolean self() { return False; }
+ virtual Boolean kids() { return True; }
+ virtual Boolean parents() { return True; }
+
+ why_triggers(std::ostream& f) : f_(f) {}
+
+ void next_node(node& n, node* p,int type,node*) {
+ if(p && p->status() == STATUS_QUEUED)
+ p->why(f_);
+ }
+};
+
+void simple_node::tell_me_why(std::ostream& f)
+{
+ this->why(f);
+ // if (0x0 != parent()) parent()->tell_me_why(f);
+}
+
+void simple_node::queued(std::ostream& f)
+{
+ // Check parents
+ node* p = this;
+ p->why(f);
+
+ // Check for suspended kids
+ suspended(f);
+
+ // Other triggers
+ why_triggers wp(f);
+ triggers(wp);
+}
+
+void simple_node::aborted(std::ostream& f)
+{
+ node* k = kids();
+ while(k) {
+ k->aborted(f);
+ k = k->next();
+ }
+}
+
+void simple_node::suspended(std::ostream& f)
+{
+ if (type() != NODE_FAMILY && type() != NODE_TASK)
+ return;
+
+ if(status() == STATUS_SUSPENDED)
+ f << " # " << type_name() << ' ' << this->name() << " is suspended\n";
+
+ node* k = kids();
+ while(k) {
+ k->suspended(f);
+ k = k->next();
+ }
+}
+
+void simple_node::perlify(FILE* f)
+{
+ if (node::is_json)
+ fprintf(f,"\"kids\": [\n");
+ else
+ fprintf(f,"kids => [\n");
+
+ node* k = kids();
+ while(k) {
+ k->as_perl(f,!k->isSimpleNode());
+ fprintf(f,",\n");
+ k = k->next();
+ }
+
+ if (node::is_json)
+ fprintf(f,"{} ],\n");
+ else
+ fprintf(f,"],\n");
+}
+
+Boolean simple_node::isZombie() const
+{
+ return ecfFlag(FLAG_ZOMBIE);
+}
+
+Boolean simple_node::isToBeChecked() const
+{
+ int s = status();
+ return s == STATUS_SUSPENDED || s == STATUS_ACTIVE || s == STATUS_SUBMITTED;
+}
+
+Boolean suite_node::visible () const { return show_it() ; }
+
+Boolean suite_node::show_it() const {
+ if (serv().suites().empty())
+ return True; // show_all
+
+ std::vector<std::string>::const_iterator it;
+ for (it = serv().suites().begin(); it != serv().suites().end(); ++it)
+ if (*it == name())
+ return simple_node::visible();
+
+ return False;
+}
+
+Boolean simple_node::isGenVariable(const char *name) {
+ for (node *run = kids(); 0 != run; run = run->next()) {
+ if (run->type() == NODE_VARIABLE)
+ if (run->name() == name)
+ return run->isGenVariable(name);
+ }
+ return False;
+}
+
+void simple_node::genvars(std::vector<Variable>& var)
+{
+ for (node *run = kids(); run; run = run->next()) {
+ if (run->type() == NODE_VARIABLE) {
+ if (run->name() == "") std::cerr << "# empty variable!\n";
+ else if (run->isGenVariable(0))
+ var.push_back(Variable(run->name(), ((variable_node*) run)->get_var(), false/*dont check names*/));
+ }
+ }
+ return;
+}
+
+void simple_node::variables(std::vector<Variable>& var)
+{
+ for (node *run = kids(); 0 != run; run = run->next()) {
+ if (run->type() == NODE_VARIABLE){
+ if (run->name() == "") std::cerr << "# empty variable!\n";
+ else if (!run->isGenVariable(0)) {
+ var.push_back(Variable(run->name(), ((variable_node*) run)->get_var(), false/*dont check names*/));
+ }
+ }
+}
+}
+
+Boolean simple_node::hasMessages() const
+{
+ if (ecfFlag(FLAG_MESSAGE)) return True;
+ // FIXME // cannot call this below while it is called during node redraw
+ if (type() == NODE_SUPER)
+ return True;
+ // return serv().messages(*this).size() > 0;
+ return False; // serv().messages(*this).size() > 0;
+}
+
+// void simple_node::unlink() {
+// if (__node__()) __node__()->unlink();
+// for (node *run = kids(); run; run = run->next()) { run->unlink(); }
+// }
diff --git a/view/src/simple_node.h b/view/src/simple_node.h
new file mode 100644
index 0000000..6de3fd9
--- /dev/null
+++ b/view/src/simple_node.h
@@ -0,0 +1,158 @@
+#ifndef simple_node_H
+#define simple_node_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #18 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#ifndef node_H
+#include "node.h"
+#endif
+
+class simple_node : public node {
+public:
+ simple_node(host&,ecf_node*);
+#ifdef BRIDGE
+ simple_node(host&,sms_node*,char);
+#endif
+ ~simple_node();
+
+ virtual std::string variable(const std::string&, bool substitute=false);
+ virtual const char* status_name() const;
+
+ virtual void info(std::ostream&);
+ virtual void triggers(trigger_lister&);
+
+ virtual Boolean hasTriggers() const;
+ virtual Boolean hasDate() const;
+ virtual Boolean hasTime() const;
+
+ virtual Boolean hasTimeHolding() const;
+
+ virtual Boolean hasManual() const;
+ virtual Boolean isSimpleNode() const { return True; }
+ virtual Boolean isGenVariable(const char*);
+ virtual void genvars(std::vector<Variable>&);
+ virtual void variables(std::vector<Variable>&);
+
+ virtual Boolean visible() const;
+ virtual Boolean visible_kid() const;
+ virtual Boolean show_it() const;
+
+ virtual void tell_me_why(std::ostream&);
+ virtual void why(std::ostream&);
+ virtual void suspended(std::ostream&);
+ virtual void aborted(std::ostream&);
+ virtual void queued(std::ostream&);
+
+ virtual int tryno() const;
+ virtual int flags() const;
+ virtual boost::posix_time::ptime status_time() const;
+
+ virtual Boolean isMigrated() const { return ecfFlag(FLAG_MIGRATED); }
+ virtual Boolean isLate() const { return ecfFlag(FLAG_LATE); }
+ virtual Boolean isWaiting() const { return ecfFlag(FLAG_WAIT); }
+ virtual Boolean hasMessages() const;
+
+ virtual Boolean isTimeDependent() const { return hasDate() || hasTime(); }
+
+ virtual Boolean isForceAbort() const { return ecfFlag(FLAG_FORCE_ABORT); }
+ virtual Boolean isUserEdit() const { return ecfFlag(FLAG_USER_EDIT); }
+ virtual Boolean isTaskAbort() const { return ecfFlag(FLAG_TASK_ABORTED); }
+ virtual Boolean isEditFailed() const { return ecfFlag(FLAG_EDIT_FAILED); }
+ virtual Boolean isCmdFailed() const { return ecfFlag(FLAG_CMD_FAILED); }
+ virtual Boolean isScriptMissing() const { return ecfFlag(FLAG_NO_SCRIPT); }
+ virtual Boolean isKilled() const { return ecfFlag(FLAG_KILLED); }
+ virtual Boolean isByRule() const { return ecfFlag(FLAG_BYRULE); }
+ virtual Boolean isQueueLimit() const { return ecfFlag(FLAG_QUEUELIMIT); }
+
+ virtual Boolean isRerun() const { return tryno() > 1; }
+ virtual Boolean isZombie() const;
+ virtual Boolean hasZombieAttr() const;
+ virtual Boolean isToBeChecked() const;
+ virtual Boolean isDefComplete() const;
+
+ virtual bool trigger_kids() const { return true; }
+ virtual bool trigger_parent() const { return true; }
+
+ virtual Boolean ecfFlag(int) const;
+
+ // void unlink();
+
+ protected:
+
+ virtual void perlify(FILE*);
+ int old_status_, old_tryno_, old_flags_;
+ private:
+
+ simple_node(const simple_node&);
+ simple_node& operator=(const simple_node&);
+
+ virtual void drawNode(Widget,XRectangle*,bool);
+ virtual void sizeNode(Widget,XRectangle*,bool);
+ virtual void drawBackground(Widget,XRectangle*,bool);
+
+ void scan(Ast*,trigger_lister&,node*);
+ void scan(Ast*,std::ostream&,bool);
+ void scan(node*,std::ostream&);
+#ifdef BRIDGE
+ void scan(sms_tree* m,trigger_lister& f,bool b);
+ void scan(sms_tree* m,std::ostream& f,bool b);
+ // void scan(sms_tree* m,std::ostream& f,bool b);
+#endif
+ void scan_limit(Ast*,std::ostream&);
+
+ virtual Pixel color() const;
+};
+
+inline void destroy(simple_node**) {}
+
+class suite_node : public simple_node {
+ public:
+ suite_node(host& h,ecf_node* n) : simple_node(h,n) {}
+#ifdef BRIDGE
+ suite_node(host& h,sms_node* n,char b) : simple_node(h,n,b) {}
+#endif
+ virtual Boolean show_it() const;
+ virtual Boolean visible() const;
+
+ // virtual void info(std::ostream&);
+};
+#define FLAG_ISSET(flag) (1<<(flag))
+#include "late.h"
+
+class family_node : public simple_node {
+ virtual bool trigger_kids() const { return false; }
+ virtual bool trigger_parent() const { return false; }
+public:
+ family_node(host& h,ecf_node* n) : simple_node(h,n) {}
+#ifdef BRIDGE
+ family_node(host& h,sms_node* n,char b) : simple_node(h,n,b) {}
+#endif
+ void update(int oldstatus,int oldtryno,int oldflags) {
+ bool is_late = flags() & FLAG_ISSET(FLAG_LATE);
+ bool was_late = old_flags_ & FLAG_ISSET(FLAG_LATE);
+ simple_node::update(oldstatus,oldtryno,oldflags);
+ if(is_late != was_late) {
+ if(is_late)
+ serv().late(*this);
+ else
+ late::hide(*this);
+ }
+ old_flags_ = flags();
+}
+
+};
+
+#endif
diff --git a/view/src/singleton.h b/view/src/singleton.h
new file mode 100644
index 0000000..a7b0cf8
--- /dev/null
+++ b/view/src/singleton.h
@@ -0,0 +1,32 @@
+#ifndef singleton_H
+#define singleton_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+template<class T>
+class singleton {
+public:
+ static T& instance();
+};
+
+template<class T>
+T& singleton<T>::instance()
+{
+ static T p;
+ return p;
+}
+
+#endif
diff --git a/ecflow_4_0_7/view/src/std.h b/view/src/std.h
similarity index 100%
rename from ecflow_4_0_7/view/src/std.h
rename to view/src/std.h
diff --git a/ecflow_4_0_7/view/src/stl.h b/view/src/stl.h
similarity index 100%
rename from ecflow_4_0_7/view/src/stl.h
rename to view/src/stl.h
diff --git a/view/src/str.cc b/view/src/str.cc
new file mode 100644
index 0000000..8bae69c
--- /dev/null
+++ b/view/src/str.cc
@@ -0,0 +1,99 @@
+#ifndef str_H
+#include "str.h"
+#endif
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <string.h>
+#include <strings.h>
+#include <stdio.h>
+
+str_imp::str_imp(const char* p):
+ str_ (new char[strlen(p) + 1])
+{
+ //if(!str_) { printf("Out of memory"); exit(1); }
+ strcpy(str_,p);
+}
+
+str_imp::~str_imp()
+{
+ delete[] str_;
+}
+
+
+str::str()
+{
+ static str empty("");
+ imp_ = empty.imp_;
+ imp_->attach();
+}
+
+str::~str()
+{
+ imp_->detach();
+}
+
+str::str(const char* n):
+ imp_(new str_imp(n))
+{
+ imp_->attach();
+}
+
+str::str(const str& other):
+ imp_(other.imp_)
+{
+ imp_->attach();
+}
+
+str::str(const std::string& other):
+ imp_(new str_imp(other.c_str()))
+{
+ imp_->attach();
+}
+
+str& str::operator=(const str& other)
+{
+ other.imp_->attach();
+ imp_->detach();
+ imp_ = other.imp_;
+ return *this;
+}
+
+
+bool str::operator==(const str& other) const
+{
+ return strcmp(c_str(),other.c_str()) == 0;
+}
+
+bool str::operator!=(const str& other) const
+{
+ return strcmp(c_str(),other.c_str()) != 0;
+}
+
+str operator+(const str& a,const str& b)
+{
+ char* p = new char[strlen(a.c_str()) + strlen(b.c_str()) + 1 ];
+ strcpy(p,a.c_str());
+ strcat(p,b.c_str());
+ str s(p);
+ delete[] p;
+ return s;
+}
+
+str& str::operator+=(const str& s)
+{
+ *this = *this + s;
+ return *this;
+}
diff --git a/view/src/str.h b/view/src/str.h
new file mode 100644
index 0000000..cc522ee
--- /dev/null
+++ b/view/src/str.h
@@ -0,0 +1,59 @@
+#ifndef str_H
+#define str_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include <string>
+#ifdef NO_BOOL
+#include "bool.h"
+#endif
+
+#include "counted.h"
+
+struct str_imp : public counted {
+ char* str_;
+ str_imp(const char*);
+ ~str_imp();
+};
+
+class str {
+public:
+ str();
+ str(const char*);
+ str(const str&);
+ str(const std::string&);
+
+ ~str(); // Change to virtual if base class
+
+ str& operator=(const str&);
+
+ bool operator==(const str&) const;
+ bool operator!=(const str&) const;
+
+ str& operator+=(const str&);
+
+ const char* c_str() const { return imp_->str_; }
+
+private:
+
+ str_imp* imp_;
+};
+
+str operator+(const str&,const str&);
+str operator+(const char*,const str&);
+str operator+(const str&,const char*);
+
+#endif
diff --git a/view/src/substitute.cc b/view/src/substitute.cc
new file mode 100644
index 0000000..040a234
--- /dev/null
+++ b/view/src/substitute.cc
@@ -0,0 +1,139 @@
+
+#ifndef substitute_H
+#include "substitute.h"
+#endif
+
+#ifndef node_H
+#include "node.h"
+#endif
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <strings.h>
+
+#include <Xm/PushB.h>
+
+extern "C" {
+#include "xec.h"
+}
+
+static char* debug = getenv("DEBUG");
+substitute::substitute(const std::string& name):
+ name_(name)
+{
+}
+
+substitute::~substitute()
+{
+}
+
+const char* substitute::scan(const char* cmd,node* n)
+{
+ static char buf[1024];
+ int i = 0, j = 0, k= 0, cont = 1;
+ char word[1024], edit[1024];
+ bool var = false, col = false;
+ substitute* s;
+ word[0] = 0; edit[0] = 0;
+
+ if (debug) std::cout << "# substituted1:" << cmd << "\n";
+ std::string replace (cmd);
+ if (replace.find("%") != std::string::npos) {
+ if (n->__node__()) {
+ if (n->__node__()->type() == NODE_SUPER) {
+ ecf_concrete_node<Defs> *ecfn = dynamic_cast<ecf_concrete_node<Defs>*>(n->__node__());
+ if (0x0 != ecfn) // ok with a node, NOK with attribute
+ if (const_cast<Defs*>(ecfn->get())) {
+ const_cast<Defs*>(ecfn->get())-> variableSubsitution(replace);
+ strcat(buf, replace.c_str());
+ return buf;
+ }
+ } else if (n->__node__()-> get_node()) {
+ n->__node__()-> get_node()-> variableSubsitution(replace);
+ strcat(buf, replace.c_str());
+ if (debug) std::cout << "# substituted2:" << replace << "\n";
+ if (debug) std::cout << "# substituted2:" << buf << "\n";
+ return buf;
+ }
+ }
+ return cmd;
+ }
+
+ while(*cmd && cont) {
+ switch(*cmd) {
+ case '<':
+ var = true;
+ j = 0;
+ word[j++] = '<';
+ break;
+
+ case '>':
+ var = false;
+ word[j++] = '>';
+ word[j] = 0;
+
+ s = first();
+ while(s) {
+ if(s->name_ == word) {
+ strcpy(word,s->eval(n).c_str());
+ break;
+ }
+ s = s->next();
+ }
+
+ buf[i] = 0;
+ strcat(buf,word);
+ i += strlen(word);
+ if (debug) std::cout << "# substituted:" << buf << "-" << word <<"-\n";
+ j = 0;
+ break;
+
+ default:
+ if (col) edit[k++] = *cmd;
+ else if(var)
+ word[j++] = *cmd;
+ else
+ buf[i++] = *cmd;
+ break;
+ }
+
+ cmd++;
+ }
+
+ if(k) {
+ buf[i] = 0;
+ strcat(buf,edit);
+ i += strlen(edit);
+ } else if(j) {
+ buf[i] = 0;
+ strcat(buf,word);
+ i += strlen(word);
+ }
+
+ if (debug) std::cout << "# substituted:" << buf << "-" << word << "-" << edit <<"-\n";
+ buf[i] = 0;
+ return buf;
+}
+
+void substitute::fill(Widget w)
+{
+ substitute* s = first();
+ while(s) {
+ XtManageChild(XmCreatePushButton(w,(char*)s->name_.c_str(),0,0));
+ s = s->next();
+ }
+}
+
+IMP(substitute)
diff --git a/view/src/substitute.h b/view/src/substitute.h
new file mode 100644
index 0000000..129deba
--- /dev/null
+++ b/view/src/substitute.h
@@ -0,0 +1,55 @@
+#ifndef substitute_H
+#define substitute_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#ifndef extent_H
+#include "extent.h"
+#endif
+
+#include <Xm/Xm.h>
+
+#ifndef node_H
+#include "node.h"
+#endif
+
+class substitute : public extent<substitute> {
+public:
+ substitute(const std::string&);
+
+ ~substitute(); // Change to virtual if base class
+ virtual const std::string eval(node*) = 0;
+
+ static const char* scan(const char*, node*);
+ static void fill(Widget);
+
+private:
+ substitute(const substitute&);
+ substitute& operator=(const substitute&);
+
+ const std::string name_;
+};
+
+inline void destroy(substitute**) {}
+
+class proc_substitute : public substitute {
+ typedef const std::string& (node::*procc)() const; procc procc_;
+ const std::string eval(node* n) { return (n->*procc_)(); }
+public:
+ proc_substitute(const std::string& name,procc p): substitute(name), procc_(p)
+ {}
+};
+#endif
diff --git a/view/src/suites_panel.cc b/view/src/suites_panel.cc
new file mode 100644
index 0000000..4b71e70
--- /dev/null
+++ b/view/src/suites_panel.cc
@@ -0,0 +1,146 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #9 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "suites_panel.h"
+#include "node.h"
+#include "host.h"
+#include "ecflowview.h"
+#include <Xm/Label.h>
+#include <Xm/Text.h>
+#include <Xm/List.h>
+extern "C" {
+#include "xec.h"
+}
+
+suites_panel::suites_panel(panel_window& w):
+ panel(w)
+ , done (false)
+{
+}
+
+suites_panel::~suites_panel()
+{
+}
+
+void suites_panel::create (Widget parent, char *widget_name )
+{
+ suites_form_c::create(parent,widget_name);
+}
+
+void suites_panel::clear()
+{
+ if (done) return;
+ XmListDeleteAllItems(list_);
+}
+
+struct suite_lister1 {
+ Widget list_;
+ unsigned int pos_;
+ std::vector<std::string> suites_;
+ void next(suite_lister1&);
+ std::string name()
+ { return (pos_ < suites_.size()) ? suites_[pos_] : ""; }
+ void run()
+ { for (unsigned int i=0; i<suites_.size(); ++i) next(*this); }
+
+public:
+ suite_lister1(Widget list, std::vector<std::string> suites)
+ : list_(list), pos_(0), suites_(suites) {
+ std::sort(suites_.begin(), suites_.end());
+ }
+};
+
+void suite_lister1::next(suite_lister1& l)
+{
+ if (pos_ < suites_.size() && suites_[pos_] != "*") {
+ xec_AddListItem(list_,(char*)name().c_str());
+ }
+ ++pos_;
+}
+
+struct suite_lister2 {
+ Widget list_;
+ unsigned int pos_;
+ std::vector<std::string> suites_;
+ void next(suite_lister2& l);
+ std::string name()
+ { return (pos_ < suites_.size()) ? suites_[pos_] : ""; }
+ void run()
+ { for (unsigned int i=0; i<suites_.size(); ++i) next(*this); };
+
+public:
+ suite_lister2(Widget list, std::vector<std::string> suites)
+ : list_(list), pos_(0), suites_(suites) {}
+};
+
+void suite_lister2::next(suite_lister2&)
+{
+ if (pos_ < suites_.size() && suites_[pos_] != "*") {
+ XmString s = XmStringCreateSimple((char*)name().c_str());
+ XmListSelectItem(list_,s,False);
+ XmStringFree(s);
+ }
+ ++pos_;
+}
+
+void suites_panel::show(node& n)
+{
+ if (done) return; done = true; clear();
+ // XmListDeleteAllItems(list_);
+ { std::vector<std::string> sv1; n.serv().suites(SUITES_LIST,sv1);
+ suite_lister1 sl1(list_, sv1); sl1.run(); }
+ { std::vector<std::string> sv2; n.serv().suites(SUITES_MINE,sv2);
+ suite_lister2 sl2(list_, sv2); sl2.run(); }
+}
+
+Boolean suites_panel::enabled(node& n)
+{
+ return n.type() == NODE_SUPER;
+}
+
+void suites_panel::tellCB( Widget, XtPointer )
+{
+ XmString *items;
+ int count;
+ std::vector<std::string> l;
+
+ XtVaGetValues(list_,
+ XmNselectedItems, &items,
+ XmNselectedItemCount,&count,
+ NULL);
+
+ for(int i = 0; i < count ; ++i) {
+ char* p = xec_GetString(items[i]);
+ l.push_back(std::string (p));
+ XtFree(p);
+ }
+ if(get_node())
+ get_node()->serv().suites(SUITES_REG, l);
+ else
+ clear();
+ submit();
+}
+
+void suites_panel::offCB( Widget, XtPointer )
+{
+ XmListDeselectAllItems(list_);
+}
+
+void suites_panel::onCB( Widget, XtPointer )
+{
+ xec_ListSelectAll(list_);
+}
+
+// static panel_maker<suites_panel> maker(PANEL_SUITES);
diff --git a/view/src/suites_panel.h b/view/src/suites_panel.h
new file mode 100644
index 0000000..987a539
--- /dev/null
+++ b/view/src/suites_panel.h
@@ -0,0 +1,54 @@
+#ifndef suites_panel_H
+#define suites_panel_H
+
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "uisuites.h"
+
+#ifndef panel_H
+#include "panel.h"
+#endif
+
+class suites_panel : public panel, public suites_form_c {
+public:
+
+ suites_panel(panel_window&);
+
+ ~suites_panel(); // Change to virtual if base class
+
+ virtual const char* name() const { return "Suites"; }
+ virtual void show(node&);
+ virtual void clear();
+ virtual Boolean enabled(node&);
+ virtual Widget widget() { return suites_form_c::xd_rootwidget(); }
+ virtual Widget tools() { return tools_; }
+
+ virtual void create (Widget parent, char *widget_name = NULL);
+
+private:
+
+ bool done;
+
+ suites_panel(const suites_panel&);
+ suites_panel& operator=(const suites_panel&);
+
+ virtual void tellCB( Widget, XtPointer );
+ virtual void offCB( Widget, XtPointer );
+ virtual void onCB( Widget, XtPointer );
+};
+
+inline void destroy(suites_panel**) {}
+#endif
diff --git a/view/src/super_node.cc b/view/src/super_node.cc
new file mode 100644
index 0000000..34f060f
--- /dev/null
+++ b/view/src/super_node.cc
@@ -0,0 +1,96 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "simple_node.h"
+#include "host.h"
+#include "timeout.h"
+
+#include "super_node.h"
+
+void super_node::why(std::ostream &w)
+{
+ if(isLocked())
+ w << "The server " << this << " is locked\n";
+ if (owner_)
+ owner_->why(w);
+}
+
+void super_node::run()
+{
+ decay_++;
+ /* printf("node run .. %s %d\n",node_name(),decay_); */
+ redraw();
+}
+
+void super_node::active(bool b)
+{
+ /* printf("node activate %s %d\n",node_name(),int(b)); */
+ if(b != active_) {
+ active_ = b;
+ redraw();
+ }
+}
+
+void super_node::up_to_date()
+{
+ frequency(60); // This will reset the timeout
+ if(decay_) {
+ decay_ = 0;
+ redraw();
+ }
+}
+
+void super_node::drawBackground(Widget w,XRectangle* r,bool)
+{
+ if(true /*active_*/ ) {
+ XRectangle a = *r;
+
+ // All grey after 1 hours
+ double x = a.width * ( decay_ / 60.0 );
+
+ if(x > a.width) x = a.width;
+
+ a.width -= x;
+
+ /* printf("%d %d\n",r->width,a.width); */
+ /* a.width -= x + 0.5; a.x += x/2.0 + 0.5; */
+ /* a.height -= y + 0.5; a.y += y/2.0 + 0.5; */
+
+#if 0
+ printf("%d x y = %g %g %d.%d.%d.%d %d.%d.%d.%d\n", decay_, x , y ,
+ r->x,r->y,r->width,r->height,
+ a.x,a.y,a.width,a.height
+ );
+#endif
+
+ GC gc = colorGC(STATUS_UNKNOWN);
+ XFillRectangles(XtDisplay(w),XtWindow(w),gc,r,1);
+
+ gc = colorGC(status());
+ XFillRectangles(XtDisplay(w),XtWindow(w),gc,&a,1);
+ }
+ else {
+ GC gc = colorGC(STATUS_UNKNOWN);
+ XFillRectangles(XtDisplay(w),XtWindow(w),gc,r,1);
+ }
+}
+
+void super_node::info(std::ostream& f)
+{
+ serv().stats(f);
+ simple_node::info(f);
+}
+
+// static node_maker<super_node> super_maker(NODE_SUPER);
diff --git a/view/src/super_node.h b/view/src/super_node.h
new file mode 100644
index 0000000..1e77c6c
--- /dev/null
+++ b/view/src/super_node.h
@@ -0,0 +1,72 @@
+#ifndef super_node_H
+#define super_node_H
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #12 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+
+#ifndef simple_node_H
+#include "simple_node.h"
+#endif
+#ifndef host_H
+#include "host.h"
+#endif
+#ifndef timeout_H
+#include "timeout.h"
+#endif
+class super_node : public simple_node, public timeout {
+ virtual void why(std::ostream&);
+ virtual Boolean visible() const { return True; }
+ virtual Boolean show_it() const { return True; }
+ virtual const std::string& name() const { return serv().name_ref(); }
+ virtual const std::string& node_name() const { return serv().name_ref(); }
+ virtual const char* type_name() const { return "server"; }
+ virtual void run();
+ virtual void up_to_date();
+ virtual void active(bool);
+ virtual void drawBackground(Widget w,XRectangle* r,bool);
+ virtual void info(std::ostream&);
+
+ virtual bool trigger_kids() const { return false; }
+ virtual bool trigger_parent() const { return false; }
+ virtual bool timeTable() { return true; }
+
+ Boolean isLocked() const { return ecfFlag(FLAG_LOCKED); }
+
+ virtual Boolean hasManual() const { return False; }
+ virtual Boolean hasTriggers() const { return False; }
+ virtual Boolean hasInfo() const { return True; }
+
+ bool active_;
+ int decay_;
+
+public:
+ super_node(host& h,ecf_node* n)
+ : simple_node(h,n)
+ , timeout(60)
+ , active_(true)
+ , decay_(0)
+ { folded_ = False; enable(); }
+
+#ifdef BRIDGE
+ super_node(host& h,sms_node* n, char b)
+ : simple_node(h,n,b)
+ , timeout(60)
+ , active_(true)
+ , decay_(0)
+ { folded_ = False; enable(); }
+#endif
+};
+
+#endif
diff --git a/view/src/task_node.cc b/view/src/task_node.cc
new file mode 100644
index 0000000..bd093ed
--- /dev/null
+++ b/view/src/task_node.cc
@@ -0,0 +1,280 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #15 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "task_node.h"
+#include "text_lister.h"
+#include "late.h"
+#include "zombie.h"
+#include "to_check.h"
+#include "host.h"
+#include "url.h"
+#include "re.h"
+#include "ecf_node.h"
+
+char *ecf_flag_name[] = { (char*)"has been forced to aborted",
+ (char*)"user edit failed",
+ (char*)"the job failed",
+ (char*)"editing failed (.job file can not be created)",
+ (char*)"job could not be submitted (ECF_CMD failed)",
+ (char*)"ECF could not find the script",
+ (char*)"killed by user",
+ (char*)"", // has been migrated",
+ (char*)"is late",
+ (char*)"has user messages",
+ (char*)"complete by rule",
+ (char*)"queue limit reached",
+ (char*)"running task is waiting for trigger",
+ (char*)"node is locked by a user",
+ (char*)"zombie is trying to communicate",
+ (char*)"task is submitted or active (ecf) but not matching job visible",
+ NULL };
+
+#ifdef BRIDGE
+task_node::task_node(host& h,sms_node* n, char b):
+ simple_node(h,n, b)
+{}
+#endif
+
+task_node::task_node(host& h,ecf_node* n):
+ simple_node(h,n)
+{
+ if (kids_ == 0x0) {
+ folded_ = False;
+ } else {
+ folded_ = True;
+ }
+}
+
+
+task_node::~task_node()
+{
+}
+
+void task_node::info(std::ostream& f) {
+ simple_node::info(f);
+ if (0 == owner_) return;
+ if (status() == STATUS_ABORTED && owner_->get_node()) {
+ f << owner_->get_node()->abortedReason() << "\n";
+ }
+ f << owner_->toString() << "\n";
+}
+
+void task_node::update(int oldstatus,int oldtryno,int oldflags)
+{
+ simple_node::update(oldstatus,oldtryno,oldflags);
+ check(oldstatus,oldtryno,oldflags);
+}
+
+void task_node::adopt(node* n)
+{
+ simple_node::adopt(n);
+ check(0,0,0);
+}
+
+void task_node::create()
+{
+ simple_node::create();
+ check(0,0,0);
+}
+
+#ifdef FLAG_ISSET
+#undef FLAG_ISSET
+#endif
+#define FLAG_ISSET(flag) (1<<(flag))
+inline bool is_late(int f) { return (f & FLAG_ISSET(FLAG_LATE)); }
+inline bool is_zombie(int f) { return (f & FLAG_ISSET(FLAG_ZOMBIE)); }
+inline bool is_to_check(int f) { return (f& FLAG_ISSET(FLAG_TO_CHECK));}
+
+void task_node::check(int,int,int)
+{
+ int new_status = status();
+ int new_flags = flags();
+ int new_try_no = tryno();
+
+ if(new_status != old_status_ && new_status == STATUS_ABORTED)
+ serv().aborted(*this);
+
+ if(new_try_no > 1 && new_try_no != old_tryno_ && (
+ new_status == STATUS_SUBMITTED ||
+ new_status == STATUS_ACTIVE))
+ serv().restarted(*this);
+
+ bool new_is_late = is_late(new_flags);
+ if(new_is_late != is_late(old_flags_)) {
+ if(new_is_late)
+ serv().late(*this);
+ else
+ late::hide(*this);
+ }
+
+ bool new_is_zombie = is_zombie(new_flags);
+ if(new_is_zombie != is_zombie(old_flags_)) {
+ if(new_is_zombie)
+ serv().zombie(*this);
+ else
+ zombie::hide(*this);
+ }
+
+//
+// if(is_to_check(new_flags) != is_to_check(old_flags_)) {
+// if(is_to_check(new_flags))
+// serv().to_check(*this);
+// else
+// to_check::hide(*this);
+// }
+
+ old_flags_ = new_flags;
+ old_status_ = new_status;
+ old_tryno_ = new_try_no;
+}
+
+void task_node::aborted(std::ostream& f)
+{
+ if(status() == STATUS_ABORTED)
+ {
+ f << "task " << this << " is aborted";
+ long flg = flags();
+ int i = 0;
+ while(flg>0)
+ {
+ if(flg%2)
+ {
+ f << " (" << ::ecf_flag_name[i] << ")";
+ }
+ flg /= 2;
+ i++;
+ }
+ f << "\n";
+ }
+ simple_node::aborted(f);
+}
+
+const char* task_node::html_page(url& u)
+{
+ return "node.html";
+}
+
+
+void task_node::html_name(FILE* f,url& u)
+{
+ node::html_name(f,u);
+}
+
+
+class cpp_translator: public url_translator {
+ re re_;
+ node* n_;
+public:
+ cpp_translator(node* n);
+ ~cpp_translator();
+
+ virtual void save(FILE*,const char *line);
+};
+
+cpp_translator::cpp_translator(node* n):
+ re_("%([^%]+)$0%"),
+ n_(n)
+{
+}
+
+cpp_translator::~cpp_translator()
+{
+}
+
+void cpp_translator::save(FILE* f,const char *line)
+{
+ if(strncmp(line,"%manual",7) == 0)
+ {
+ fprintf(f,"<b>");
+ url_translator::save(f,line);
+ fprintf(f,"</b>");
+ fprintf(f,"<i>");
+ return;
+ }
+
+ if(strncmp(line,"%end",4) == 0)
+ {
+ fprintf(f,"</i>");
+ fprintf(f,"<b>");
+ url_translator::save(f,line);
+ fprintf(f,"</b>");
+ return;
+ }
+
+ if(strncmp(line,"%include",8) == 0)
+ {
+ fprintf(f,"<b>");
+ url_translator::save(f,line);
+ fprintf(f,"</b>");
+ return;
+ }
+
+
+ char val[1024];
+ char buf[1024];
+
+ strcpy(buf,line);
+ char *p = buf;
+ char *q;
+
+ while((q = re_.match(p,val)))
+ {
+ char *loc = re_.loc();
+ char w = *loc;
+ *loc = 0;
+ url_translator::save(f,p);
+ *loc = w;
+
+ node *n = n_->variableOwner(val);
+ if(n == 0) n = n_;
+
+ url_translator::save(f,val);
+ fprintf(f,"%%</a></b>");
+ p = q;
+ }
+
+ url_translator::save(f,p);
+}
+
+void task_node::html_script(FILE* f,url& u)
+{
+ cpp_translator cpp(this);
+ tmp_file tmp = serv().script(*this);
+ u.add(tmp,cpp);
+}
+
+void task_node::html_output(FILE* f,url& u)
+{
+ url_translator t;
+ tmp_file tmp = serv().output(*this);
+ u.add(tmp,t);
+}
+
+void task_node::html_job(FILE* f,url& u)
+{
+ url_translator t;
+ tmp_file tmp = serv().job(*this);
+ u.add(tmp,t);
+}
+
+void task_node::html_jobstatus(FILE* f,url& u)
+{
+ url_translator t;
+ std::string job = variable("ECF_JOB");
+ std::string stat = job + ".stat";
+ serv().jobstatus(*this, "");
+ tmp_file tmp (stat);
+ u.add(tmp,t);
+}
diff --git a/view/src/task_node.h b/view/src/task_node.h
new file mode 100644
index 0000000..5b43c4d
--- /dev/null
+++ b/view/src/task_node.h
@@ -0,0 +1,58 @@
+#ifndef task_node_H
+#define task_node_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #8 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "simple_node.h"
+
+class task_node : public simple_node {
+public:
+ task_node(host& h,ecf_node* n);
+#ifdef BRIDGE
+ task_node(host& h,sms_node* n, char b);
+#endif
+ ~task_node(); // Change to virtual if base class
+
+private:
+ task_node(const task_node&);
+ task_node& operator=(const task_node&);
+
+ virtual void adopt(node*);
+ virtual void create();
+ virtual void update(int,int,int);
+ virtual void check(int,int,int);
+ virtual void info(std::ostream&);
+
+ virtual void aborted(std::ostream&);
+ virtual void html_output(FILE*,url&);
+ virtual void html_script(FILE*,url&);
+ virtual void html_job(FILE*,url&);
+ virtual void html_jobstatus(FILE*,url&);
+ virtual void html_name(FILE*,url&);
+ virtual const char* html_page(url&);
+};
+
+class alias_node : public task_node {
+ void why(std::ostream&);
+public:
+ alias_node(host& h,ecf_node* n);
+#ifdef BRIDGE
+ alias_node(host& h,sms_node* n, char b);
+#endif
+ ~alias_node();
+};
+
+#endif
diff --git a/view/src/text_layout.cc b/view/src/text_layout.cc
new file mode 100644
index 0000000..a9efa47
--- /dev/null
+++ b/view/src/text_layout.cc
@@ -0,0 +1,123 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "text_layout.h"
+#include "node.h"
+#include "trigger_panel.h"
+#include "Hyper.h"
+#include "tmp_file.h"
+#include <stdio.h>
+#include "error.h"
+#include "trigger_lister.h"
+
+text_layout::text_layout(trigger_panel& t,Widget w):
+ layout(t,w)
+{
+}
+
+text_layout::~text_layout()
+{
+}
+
+void text_layout::clear()
+{
+ owner().forget_all();
+ HyperSetText(widget_,"");
+}
+
+struct info_lister : public trigger_lister {
+ panel& p_;
+ FILE* f_;
+ char* t_;
+ Boolean e_;
+public:
+ info_lister(panel& p,FILE* f,char *t,Boolean e) : p_(p),f_(f), t_(t), e_(e) {}
+ void next_node(node& n, node*,int,node*);
+ Boolean parents() { return e_; }
+ Boolean kids() { return e_; }
+};
+
+void info_lister::next_node(node& n, node* p,int mode,node*)
+{
+ // Title
+ if(t_) {
+ int n = fprintf(f_,"\n%s:\n",t_) - 2;
+ while(n--) fputc('-',f_);
+ fputc('\n',f_);
+ t_ = 0;
+ }
+
+ p_.observe(&n);
+ fprintf(f_,"%s {%s}",n.type_name(), n.full_name().c_str());
+ if(p) {
+ fprintf(f_," through ");
+ p_.observe(p);
+
+ switch(mode)
+ {
+ case trigger_lister::parent: fprintf(f_,"parent "); break;
+ case trigger_lister::child: fprintf(f_,"child "); break;
+ }
+
+ fprintf(f_,"%s {%s}",p->type_name(),p->full_name().c_str());
+ }
+ fputc('\n',f_);
+}
+
+
+void text_layout::show(node& n)
+{
+ owner().forget_all();
+
+ tmp_file tmp(tmpnam(0));
+
+ FILE *f = fopen(tmp.c_str(),"w");
+
+ if(!f)
+ {
+ gui::syserr(tmp.c_str());
+ return;
+ }
+
+ info_lister i1(owner(),f,"Nodes triggering this node",owner().extended());
+ if(owner().triggers())
+ n.triggers(i1);
+
+ info_lister i2(owner(),f,"Nodes triggered by this node",owner().extended());
+ if(owner().triggered())
+ n.triggered(i2);
+
+ fclose(f);
+
+ HyperLoadFile(widget_,(char*)tmp.c_str());
+}
+
+void text_layout::adoption(observable*,observable*)
+{
+}
+
+void text_layout::gone(observable*)
+{
+}
+
+void text_layout::notification(observable*)
+{
+}
+
+void text_layout::reach(node* n1,node* n2)
+{
+ clear();
+ HyperSetText(widget_,"This functionality is only available in graphic mode.");
+}
diff --git a/view/src/text_layout.h b/view/src/text_layout.h
new file mode 100644
index 0000000..c5b9386
--- /dev/null
+++ b/view/src/text_layout.h
@@ -0,0 +1,143 @@
+#ifndef text_layout_H
+#define text_layout_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+// Headers
+// #ifndef machine_H
+// #include <machine.h>
+// #endif
+
+// Forward declarations
+
+// class ostream;
+// typedef class _Pvts os_typespec; // Remove if not persistant
+
+
+
+#ifndef layout_H
+#include "layout.h"
+#endif
+
+#ifndef observer_H
+#include "observer.h"
+#endif
+
+
+//
+
+class text_layout : public layout, public observer {
+public:
+
+// -- Exceptions
+ // None
+
+// -- Contructors
+
+ text_layout(trigger_panel&,Widget);
+
+// -- Destructor
+
+ ~text_layout(); // Change to virtual if base class
+
+// -- Convertors
+ // None
+
+// -- Operators
+ // None
+
+// -- Methods
+ // None
+
+
+// -- Overridden methods
+
+ virtual void show(node&);
+ virtual void clear();
+ virtual void reach(node*,node*);
+
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+ // Uncomment for persistent, remove otherwise
+ // static os_typespec* get_os_typespec();
+
+protected:
+
+// -- Members
+ // None
+
+// -- Methods
+
+ // void print(ostream&) const; // Change to virtual if base class
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+private:
+
+// No copy allowed
+
+ text_layout(const text_layout&);
+ text_layout& operator=(const text_layout&);
+
+// -- Members
+
+
+// -- Methods
+
+
+ void notification(observable*);
+ void adoption(observable*,observable*);
+ void gone(observable*);
+
+// -- Overridden methods
+
+ // From triigers_menu_c
+
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+// -- Friends
+
+ //friend ostream& operator<<(ostream& s,const text_layout& p)
+ // { p.print(s); return s; }
+
+};
+
+inline void destroy(text_layout**) {}
+
+// If persistent, uncomment, otherwise remove
+//#ifdef _ODI_OSSG_
+//OS_MARK_SCHEMA_TYPE(text_layout);
+//#endif
+
+
+#endif
diff --git a/view/src/text_lister.h b/view/src/text_lister.h
new file mode 100644
index 0000000..411de3f
--- /dev/null
+++ b/view/src/text_lister.h
@@ -0,0 +1,79 @@
+#ifndef text_lister_H
+#define text_lister_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #9 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include <stdio.h>
+
+class node;
+
+class text_lister {
+public:
+
+ text_lister() {}
+
+ virtual node* source() const = 0;
+ virtual void push(node*) = 0;
+ // virtual void pusher(node*) = 0;
+ virtual void push(const char*,...) = 0;
+ virtual void push(const std::string&) = 0;
+ virtual void endline() = 0;
+ virtual void cancel() = 0;
+
+ virtual FILE* file() { return 0; }
+
+private:
+
+ text_lister(const text_lister&);
+ text_lister& operator=(const text_lister&);
+};
+
+inline
+text_lister& operator<<(text_lister& s,int n)
+{ s.push("%d",n); return s; }
+
+inline
+text_lister& operator<<(text_lister& s,char n)
+{ s.push("%c",n); return s; }
+
+inline
+text_lister& operator<<(text_lister& s,double n)
+{ s.push("%g",n); return s; }
+
+inline
+text_lister& operator<<(text_lister& s,const char* n)
+{ s.push("%s",n); return s; }
+inline
+text_lister& operator<<(text_lister& s,const std::string n)
+{ s.push("%s",n.c_str()); return s; }
+
+inline
+text_lister& operator<<(text_lister& s,node* n)
+{ s.push(n); return s; }
+
+inline
+text_lister& operator<<(text_lister& s,node& n)
+{ s.push(&n); return s; }
+
+inline
+text_lister& operator<<(text_lister& s, void (*proc)(text_lister&))
+{ proc(s); return s; }
+
+inline void cancel(text_lister& s) { s.cancel(); }
+inline void endl(text_lister& s) { s.endline(); }
+
+
+#endif
diff --git a/view/src/text_window.cc b/view/src/text_window.cc
new file mode 100644
index 0000000..7430a71
--- /dev/null
+++ b/view/src/text_window.cc
@@ -0,0 +1,194 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "text_window.h"
+#include <string>
+#include "viewer.h"
+#include "fsb.h"
+#include "ask.h"
+#include "globals.h"
+#include <Xm/Text.h>
+extern "C" {
+#include "xec.h"
+}
+
+text_window::text_window(bool map_it):
+ file_(0,false),
+ text_map_(0),
+ map_it_(map_it)
+{
+#if 1
+ map_it_ = 0;
+#endif
+}
+
+
+text_window::~text_window()
+{
+ xec_UnmapText(text_map_);
+ text_map_ = 0;
+}
+
+void text_window::clear()
+{
+ find::hide();
+ xec_UnmapText(text_map_);
+ text_map_ = 0;
+ XmTextSetString(text(),"");
+ file_ = tmp_file(0,false);
+}
+
+
+void text_window::load(const tmp_file& x)
+{
+ file_ = x;
+ xec_UnmapText(text_map_); text_map_ = 0;
+ const int MAXLEN = 512;
+ char cmsg[MAXLEN];
+ snprintf(cmsg, MAXLEN, "Could not load file %s", file_.c_str());
+
+ if(file_.c_str())
+ {
+ int zeros = 0;
+ if(map_it_) {
+ text_map_ = xec_MapText(text(),file_.c_str(),&zeros);
+ if(text_map_ == 0)
+ XmTextSetString(text(),cmsg);
+ if(zeros) {
+ find::make(text());
+ find::message("This file contains %d null character%s.\n"
+ "The find will not work properly.",
+ zeros,
+ zeros>1?"s":""
+ );
+ }
+ else {
+ find::no_message();
+ }
+ }
+ else {
+ int err = xec_LoadText(text(),file_.c_str(),False);
+ if(err)
+ XmTextSetString(text(),cmsg);
+ }
+ }
+ else
+ XmTextSetString(text(),cmsg);
+}
+
+class text_viewer : public viewer {
+ tmp_file tmp_;
+public:
+ text_viewer(const tmp_file& t);
+};
+
+text_viewer::text_viewer(const tmp_file& t)
+ : tmp_(t)
+{
+ if (!tmp_.c_str()) return;
+ char buf[1024];
+ const char* xpager = getenv("XPAGER");
+ if (xpager)
+ sprintf(buf,"${XPAGER:=xterm -e more} %s",tmp_.c_str());
+ else
+ sprintf(buf,"xterm -e ${PAGER:=more} %s",tmp_.c_str());
+ FILE *f = popen(buf,"r");
+ if(!f) {
+ std::cerr << "# error: " << buf << "\n";
+ return;
+ }
+ start(f);
+}
+
+void text_window::open_viewer()
+{
+ new text_viewer(file_);
+}
+
+
+void text_window::search(const char* p,bool case_sens,bool regex,
+ bool back,bool wrap)
+{
+
+ bool found = xec_TextSearch(text(),(char*)p,!case_sens,regex,back,
+ false,wrap);
+
+ if(!found)
+ message("Text not found");
+ else
+ no_message();
+}
+
+
+void text_window::open_search()
+{
+ find::raise(text());
+}
+
+
+//-------------------------------------------------------
+
+class text_saver : public viewer {
+ tmp_file tmp_;
+public:
+ text_saver(const tmp_file& t);
+};
+
+text_saver::text_saver(const tmp_file& t):
+ tmp_(t)
+{
+ const char* p = fsb::ask("Save as:");
+ if(p)
+ {
+ char buf[2048];
+ sprintf(buf,"cp %s %s 2>&1",tmp_.c_str(),p);
+ show(buf);
+ }
+ else delete this;
+}
+
+void text_window::save()
+{
+ new text_saver(file_);
+}
+
+//-------------------------------------------------------
+
+class text_printer : public viewer {
+ tmp_file tmp_;
+public:
+ text_printer(const tmp_file& t);
+};
+
+text_printer::text_printer(const tmp_file& t):
+ tmp_(t)
+{
+ static option<str> cmd(globals::instance(),"print_command","lpr");
+
+ str c = cmd;
+
+ if(ask::show(c,"Print command:"))
+ {
+ cmd = c;
+ char buf[2048];
+ sprintf(buf,"%s %s 2>&1",c.c_str(),tmp_.c_str());
+ show(buf);
+ }
+}
+
+void text_window::print()
+{
+ new text_printer(file_);
+}
diff --git a/view/src/text_window.h b/view/src/text_window.h
new file mode 100644
index 0000000..732e83d
--- /dev/null
+++ b/view/src/text_window.h
@@ -0,0 +1,65 @@
+#ifndef text_window_H
+#define text_window_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#ifndef panel_H
+#include "panel.h"
+#endif
+
+#ifndef find_H
+#include "find.h"
+#endif
+
+#ifndef tmp_file_H
+#include "tmp_file.h"
+#endif
+
+
+class text_window : public find {
+public:
+
+ text_window(bool);
+
+ ~text_window(); // Change to virtual if base class
+
+ void load(const tmp_file&);
+ void clear();
+
+ void print();
+ void save();
+
+ virtual Widget text() = 0;
+
+protected:
+
+ void open_search();
+ void open_viewer();
+
+ virtual void search(const char*,bool,bool,bool,bool);
+
+private:
+
+ text_window(const text_window&);
+ text_window& operator=(const text_window&);
+
+ tmp_file file_;
+ void* text_map_;
+ bool map_it_;
+
+};
+
+#endif
diff --git a/view/src/time.cc b/view/src/time.cc
new file mode 100644
index 0000000..81c40dd
--- /dev/null
+++ b/view/src/time.cc
@@ -0,0 +1,163 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #14 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <string>
+#include "time_node.h"
+
+#ifndef ecf_node_
+#include "ecf_node.h"
+#endif
+
+#ifdef BRIDGE
+
+static char *week[] = {
+ (char*)"sunday",(char*) "monday",(char*)"tueday",
+ (char*)"wednesday",(char*)"thursday", (char*)"friday",
+ (char*)"saturday"};
+
+static char *month[] = {
+ (char*)"january", (char*)"february", (char*)"march",
+ (char*)"april", (char*)"may", (char*)"june",
+ (char*)"july", (char*)"august", (char*)"september",
+ (char*)"october", (char*)"november", (char*)"december",
+};
+
+static char* ext[] = {
+ (char*)"st",(char*)"nd",(char*)"rd",(char*)"th",(char*)"th",
+ (char*)"th",(char*)"th",(char*)"th",(char*)"th",(char*)"th",
+ (char*)"th",(char*)"th",(char*)"th",(char*)"th",(char*)"th",
+ (char*)"th",(char*)"th",(char*)"th",(char*)"th",(char*)"th",
+ (char*)"st",(char*)"nd",(char*)"rd",(char*)"th",(char*)"th",
+ (char*)"th",(char*)"th",(char*)"th",(char*)"th",(char*)"th",
+ (char*)"st",
+};
+
+time_node::time_node(host& h,sms_node* n, char b)
+ : node(h,n,b)
+ , time_("time")
+{
+}
+#endif
+
+time_node::time_node(host& h,ecf_node* n)
+ : node(h,n)
+ , time_("time")
+{
+ full_name_ = parent()->full_name();
+ full_name_ += ":";
+ if (owner_) full_name_ += owner_->toString();
+}
+
+char* time_node::string(char* s)
+{
+ s[0] = 0;
+#ifdef BRIDGE
+ if (tree_) {
+ sms_time *t = (sms_time*)tree_;
+
+ char buf[1024];
+ s[0] = 0;
+
+ sprintf(buf,t->hour[0]<0?"*":"%02d",t->hour[0]);
+ strcat(s,buf);
+
+ strcat(s,":");
+
+ sprintf(buf,t->minute[0]<0?"*":"%02d",t->minute[0]);
+ strcat(s,buf);
+
+ if(t->repeat)
+ {
+ sprintf(buf," to %02d:%02d",t->hour[1],t->minute[1]);
+ strcat(s,buf);
+
+ sprintf(buf," by %02d:%02d",t->hour[2],t->minute[2]);
+ strcat(s,buf);
+ }
+
+
+ if(t->iscron)
+ {
+ long w = t->weekdays;
+ int n = 0;
+ while(w)
+ {
+ if(w%2)
+ {
+ sprintf(buf," %s",week[n]);
+ strcat(s,buf);
+ }
+ w >>= 1;
+ n++;
+ }
+
+ w = t->monthdays;
+ n = 0;
+ while(w)
+ {
+ if(w%2)
+ {
+ sprintf(buf," %d%s",n+1,ext[n]);
+ strcat(s,buf);
+ }
+ n++;
+ w >>= 1;
+ }
+
+ w = t->months;
+ n = 0;
+ while(w)
+ {
+ if(w%2)
+ {
+ sprintf(buf," %s",month[n]);
+ strcat(s,buf);
+ }
+ w >>= 1;
+ n++;
+ }
+ }
+ return s;
+}
+#endif
+ if (owner_) { sprintf(s, owner_->toString().c_str()); return s; }
+ return s;
+}
+
+xmstring time_node::make_label_tree()
+{
+ char s[1024];
+#ifdef BRIDGE
+ sms_time *t = (sms_time*)tree_;
+ if (t && t->iscron)
+ {
+ xmstring c("cron: ","bold");
+ xmstring x(this->string(s));
+ return c + x;
+ }
+#endif
+ return xmstring(this->string(s));
+}
+
+void time_node::perlify(FILE* f)
+{
+ char buf[1034];
+ perl_member(f,"value",string(buf));
+}
+
+node* time_node::graph_node()
+{
+ return &dummy_node::get(full_name());
+}
diff --git a/view/src/time_node.h b/view/src/time_node.h
new file mode 100644
index 0000000..332d865
--- /dev/null
+++ b/view/src/time_node.h
@@ -0,0 +1,49 @@
+#ifndef TIME_H
+#define TIME_H
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #10 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+#include "node.h"
+#include "show.h"
+#include "dummy_node.h"
+
+class time_node : public node {
+ std::string time_, full_name_;
+ virtual node* graph_node();
+
+ virtual bool is_my_parent(node*) const { return false; }
+ virtual void info(std::ostream&) {}
+
+ virtual xmstring make_label_tree();
+ virtual xmstring make_label_trigger() {
+ return make_label_tree();
+ }
+
+ virtual const std::string& name() const { return time_; }
+ const std::string& full_name() const { return full_name_; }
+ virtual Boolean menus() { return False; }
+ virtual Boolean selectable() { return False; }
+
+ virtual Boolean visible() const { return show::want(show::time); }
+
+ char* string(char*);
+ virtual void perlify(FILE*);
+
+public:
+ time_node(host& h,ecf_node* n);
+#ifdef BRIDGE
+ time_node(host& h,sms_node* n, char b);
+#endif
+};
+#endif
diff --git a/view/src/timeout.cc b/view/src/timeout.cc
new file mode 100644
index 0000000..e46c731
--- /dev/null
+++ b/view/src/timeout.cc
@@ -0,0 +1,86 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "ecflowview.h"
+#include "timeout.h"
+
+extern XtAppContext app_context;
+
+void timeout::timeoutCB(XtPointer data,XtIntervalId* id)
+{
+ timeout* t = (timeout*)data;
+
+ if(t->actived_)
+ {
+ t->running_ = True;
+ t->run();
+ t->running_ = False;
+ }
+
+ if(t->actived_)
+ t->id_ = XtAppAddTimeOut(app_context,t->frequency_*1000,timeoutCB,t);
+}
+
+timeout::timeout(double frequency):
+ actived_(False),
+ frequency_(frequency),
+ id_(0),
+ running_(False)
+{
+}
+
+timeout::~timeout()
+{
+ disable();
+}
+
+void timeout::enable()
+{
+ if(!actived_ && app_context)
+ {
+ id_ = XtAppAddTimeOut(app_context,frequency_*1000,timeoutCB,this);
+ actived_ = True;
+ }
+}
+
+
+void timeout::disable()
+{
+ if(actived_ && id_)
+ {
+ XtRemoveTimeOut(id_);
+ id_ = 0;
+ actived_ = False;
+ }
+}
+
+void timeout::frequency(double n)
+{
+ frequency_ = n;
+ if(!running_ && actived_)
+ {
+ disable();
+ enable();
+ }
+}
+
+void timeout::drift(double n,double maximum)
+{
+ double x = frequency_ + n;
+ if(x>maximum) x = maximum;
+ frequency(x);
+}
+
+IMP(timeout)
diff --git a/view/src/timeout.h b/view/src/timeout.h
new file mode 100644
index 0000000..d36418d
--- /dev/null
+++ b/view/src/timeout.h
@@ -0,0 +1,53 @@
+#ifndef timeout_H
+#define timeout_H
+
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <Xm/Xm.h>
+
+#ifndef extent_H
+#include "extent.h"
+#endif
+
+class timeout : public extent<timeout> {
+public:
+
+ timeout(double);
+
+ virtual ~timeout(); // Change to virtual if base class
+
+ void enable();
+ void disable();
+ void frequency(double);
+ void drift(double,double);
+
+ virtual void run() = 0;
+
+private:
+
+ timeout(const timeout&);
+ timeout& operator=(const timeout&);
+
+ Boolean actived_;
+ double frequency_;
+ XtIntervalId id_;
+ int running_;
+
+ static void timeoutCB(XtPointer,XtIntervalId*);
+
+};
+
+#endif
diff --git a/view/src/timetable_panel.cc b/view/src/timetable_panel.cc
new file mode 100644
index 0000000..475ef2d
--- /dev/null
+++ b/view/src/timetable_panel.cc
@@ -0,0 +1,731 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #7 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <stdlib.h>
+#include "arch.h"
+#include "timetable_panel.h"
+#include "node.h"
+#include "host.h"
+#include "fsb.h"
+#include "gui.h"
+#include "xnode.h"
+#include "xmstring.h"
+#include "globals.h"
+#include "tmp_file.h"
+#include <Xm/Text.h>
+#include <Xm/ToggleB.h>
+
+#include "log_event.h"
+extern "C" {
+#include "SimpleTime.h"
+#include "Hyper.h"
+}
+
+namespace timetatble_status {
+const char *status_name[10]
+ = { "unknown", "suspended", "complete", "queued", "submitted", "active",
+ "aborted", "shutdown", "halted" , NULL };
+}
+
+extern "C" {
+#include "xec.h"
+}
+static void date2str(char* buf,const DateTime& dt)
+{
+ int ddd = dt.date;
+ int ttt = dt.time;
+
+ int yy = ddd / 10000; ddd %= 10000;
+ int mm = ddd / 100; ddd %= 100;
+ int dd = ddd;
+ int HH = ttt / 10000; ttt %= 10000;
+ int MM = ttt / 100; ttt %= 100;
+ int ss = ttt ;
+ sprintf(buf,"%04d-%02d-%02d %02d:%02d:%02d",
+ yy,mm,dd,HH,MM,ss);
+}
+
+
+static int sec2str(char* buf,int s)
+{
+ buf[0] = 0;
+ if(s) {
+
+ long x = s>0?s:-s;
+ long n;
+ char sec[20];
+ char min[20];
+ char hou[20];
+ char day[20];
+
+ *sec = *min = *hou = *day = 0;
+ if((n = x % 60)) sprintf(sec,"%ld sec ",n);
+ x /= 60;
+ if((n = x % 60)) sprintf(min,"%ld min ",n);
+ x /= 60;
+ if((n = x % 24)) sprintf(hou,"%ld hour ",n);
+ x /= 24;
+ if((n = x)) sprintf(day,"%ld day ",n);
+
+ sprintf(buf,"%s%s%s%s", day,hou,min,sec);
+ }
+ return s;
+}
+
+static int range2str(char* buf,const DateTime& dt1,const DateTime& dt2)
+{
+ return sec2str(buf,TimeDiff(dt1,dt2));
+}
+
+static void date2widget(Widget w,DateTime& x)
+{
+ char buf[80];
+ if(x == kSmallDate)
+ strcpy(buf,"-infinite");
+ else if(x == kLargeDate)
+ strcpy(buf,"+infinite");
+ else
+ {
+ TimeAdd(&x,0);
+ date2str(buf,x);
+ }
+
+ XmTextSetString(w,buf);
+}
+
+class timetable_node : public xnode {
+#if 1
+ // important: and alos in log_event
+ void notification(observable*) { redraw(); }
+ void adoption(observable* o,observable* n) { node_ = (node*)n; }
+ void gone(observable*) { owner_.remove(this); delete this; }
+#endif
+protected:
+ timetable_panel& owner_;
+ log_event* event_;
+public:
+ timetable_node(Widget w,timetable_panel& t,log_event* e);
+ virtual ~timetable_node();
+ log_event* event() { return event_; }
+ virtual DateTime date() { return event_->time(); }
+ virtual char* text(char* b) { return event_->text(b); }
+ virtual bool is_name() { return false; }
+ virtual bool change_fold() { return false; }
+};
+
+timetable_node::timetable_node(Widget w,timetable_panel& o,log_event* e):
+ xnode(e->get_node()), owner_(o), event_(e)
+{
+ event_->attach();
+}
+
+timetable_node::~timetable_node()
+{
+ event_->detach();
+}
+
+//====================================================================
+
+class time_event_node : public timetable_node {
+protected:
+
+ void draw(Widget w,XRectangle* r) { event_->draw(w,r); }
+ void size(Widget w,XRectangle* r) { event_->size(w,r); }
+
+public:
+ time_event_node(Widget w,timetable_panel&,log_event*);
+ ~time_event_node() {}
+};
+
+time_event_node::time_event_node(Widget w,timetable_panel& o,log_event* e):
+ timetable_node(w,o,e)
+{
+ TimeSetTime(w,getBox(w),e->time());
+}
+
+//====================================================================
+
+class time_name_node : public timetable_node {
+ bool fold_;
+ void draw(Widget w,XRectangle* r);
+ void size(Widget w,XRectangle* r);
+public:
+ time_name_node(Widget w,timetable_panel&,log_event*);
+ ~time_name_node() {}
+ virtual char* text(char* b) {
+ strcpy(b,node_->full_name().c_str());return b; }
+ virtual bool is_name() { return true; }
+ virtual bool change_fold() { fold_ = !fold_; redraw(); return fold_; }
+};
+
+time_name_node::time_name_node(Widget w,timetable_panel& o,log_event* e):
+ timetable_node(w,o,e),
+ fold_(false)
+{
+ node_ = e->owner();
+ getBox(w);
+}
+
+void time_name_node::draw(Widget w,XRectangle* r)
+{
+ xmstring s(node_->full_name().c_str(),fold_?"bold":"normal");
+
+ XmFontList f = gui::tinyfont();
+ XmStringDraw(XtDisplay(w),XtWindow(w),
+ f,
+ s,
+ gui::blackGC(),
+ r->x,
+ r->y,
+ r->width,
+ XmALIGNMENT_CENTER, XmSTRING_DIRECTION_L_TO_R, r);
+}
+
+void time_name_node::size(Widget w,XRectangle* r)
+{
+ xmstring s(node_->full_name().c_str(),fold_?"bold":"normal");
+
+ XmFontList f = gui::tinyfont();
+ r->width = XmStringWidth(f,s);
+ r->height = XmStringHeight(f,s);
+}
+
+
+//====================================================================
+
+timetable_panel::timetable_panel(panel_window& w):
+ panel(w),
+ last_(kSmallDate),
+ min_time_(kSmallDate),
+ max_time_(kLargeDate)
+{
+ sorted_by_time_ = globals::get_resource("timeline_sorted_by_time",false);
+ tasks_only_ = globals::get_resource("timeline_tasks_only",false);
+}
+
+timetable_panel::~timetable_panel()
+{
+ clear();
+}
+
+void timetable_panel::create(Widget parent, char *widget_name )
+{
+ timetable_form_c::create(parent,widget_name);
+
+ add_input_CB();
+
+ date2widget(from_,min_time_);
+ date2widget(to_,max_time_);
+
+ XmToggleButtonSetState(by_time_,sorted_by_time_,False);
+ XmToggleButtonSetState(by_name_,!sorted_by_time_,False);
+
+ XmToggleButtonSetState(all_,!tasks_only_,False);
+ XmToggleButtonSetState(tasks_,tasks_only_,False);
+}
+
+void timetable_panel::clear()
+{
+ NodeReset(time_);
+ for(int i = 0; i < nodes_.count(); i++)
+ delete nodes_[i];
+ nodes_.clear();
+ XmTextSetString(file_,"");
+ last_ = kSmallDate;
+ depend::hide();
+}
+
+void timetable_panel::show(node& n)
+{
+ clear();
+ reload(false);
+}
+
+void timetable_panel::reload(bool reset)
+{
+ if(get_node())
+ load(get_node()->serv().timefile().c_str(),reset);
+ else
+ clear();
+}
+
+void timetable_panel::changed(node& n)
+{
+}
+
+void timetable_panel::remove(timetable_node *t)
+{
+ nodes_.remove(t);
+}
+
+void timetable_panel::next(log_event* n)
+{
+ if(n->time() < min_time_ || n->time() > max_time_)
+ return;
+
+ if(tasks_only_ && n->owner()->type() != NODE_TASK) return;
+
+ time_event_node *t = new time_event_node(time_,*this,n);
+ int c = nodes_.count();
+ bool found = false;
+
+ for(int i = c-1 ; i >= 0; i--)
+ if(nodes_[i]->event()->owner() == n->owner())
+ {
+ nodes_[i]->relation(t);
+ found = true;
+ break;
+ }
+
+ if(!found) {
+ time_name_node *x = new time_name_node(time_,*this,n);
+ nodes_.add(x);
+ x->relation(t);
+ x->visibility(true);
+ }
+
+ t->visibility(true);
+ nodes_.add(t);
+
+}
+
+Boolean timetable_panel::enabled(node& n)
+{
+ return TRUE;
+}
+
+struct sort_by_name : public event_sorter {
+public:
+ int compare(log_event* a,log_event* b) {
+ char sa[1024];
+ char sb[1024];
+
+ node *nodea = a->get_node();
+ node *nodeb = b->get_node();
+
+ const char *ca = nodea ? nodea->full_name().c_str() : "none";
+ const char *cb = nodeb ? nodeb->full_name().c_str() : "none";
+
+ strcpy(sa,ca);
+ strcpy(sb,cb);
+ return strcmp(sa,sb);
+ }
+};
+
+struct sort_by_time : public event_sorter {
+public:
+ int compare(log_event* a,log_event* b) {
+ return TimeDiff(a->time(),b->time());
+ }
+};
+
+
+static DateTime widget2date(Widget w)
+{
+ char *p = XmTextGetString(w);
+ char buf[80];
+ char *q = p;
+ int i = 0;
+ int j = 0;
+
+ while(*q)
+ {
+ if(*q >= '0' && *q <= '9') buf[i++] = *q;
+ if(*q == ' ') { buf[i++] = 0; j = i; }
+ q++;
+ }
+
+ buf[i] = 0;
+ XtFree(p);
+
+ DateTime dt;
+ dt.date = atol(buf);
+ dt.time = atol(buf+j);
+
+ TimeAdd(&dt,0);
+
+ return dt;
+}
+
+void timetable_panel::load(const char* fname,bool reset)
+{
+ clear();
+ if(get_node())
+ {
+ str path = fname;
+
+ if(!reset && path != get_node()->serv().timefile())
+ path = path + str(" ") + str(fname);
+
+ get_node()->serv().timefile(path);
+
+ min_time_ = widget2date(from_);
+ max_time_ = widget2date(to_);
+
+ if(min_time_ < kSmallDate) min_time_ = kSmallDate;
+ if(max_time_ < kSmallDate) max_time_ = kLargeDate;
+
+ date2widget(from_,min_time_);
+ date2widget(to_,max_time_);
+
+
+ XmTextSetString(file_,(char*)path.c_str());
+ log_event::load(get_node()->serv(),path.c_str(),reset);
+
+
+ if(sorted_by_time_)
+ {
+ sort_by_time sbt;
+ log_event::sort(sbt);
+ }
+ else
+ {
+ sort_by_name sbn;
+ log_event::sort(sbn);
+ }
+
+ log_event::scan(get_node(),*this);
+
+ }
+}
+
+void timetable_panel::load(bool reset)
+{
+ const char* p = 0;
+ if((p = fsb::ask("Load a timefile")))
+ load(p,reset);
+}
+
+void timetable_panel::chooseCB( Widget, XtPointer data)
+{
+ load(true);
+}
+
+void timetable_panel::loadCB( Widget, XtPointer data)
+{
+ load(true);
+}
+
+void timetable_panel::mergeCB( Widget, XtPointer data)
+{
+ load(false);
+}
+
+void timetable_panel::activateCB(Widget w, XtPointer data)
+{
+ char* p = XmTextGetString(file_);
+ load(p, w == file_);
+ str s(p);
+ XtFree(p);
+}
+
+
+void timetable_panel::updateCB( Widget, XtPointer data)
+{
+ reload(true);
+}
+
+
+void timetable_panel::hyperCB(Widget w, XtPointer data)
+{
+ panel::hyper(w,data);
+}
+
+static int compare(const void* a,const void *b)
+{
+ timetable_node** ta = (timetable_node**)a;
+ timetable_node** tb = (timetable_node**)b;
+
+ return TimeDiff( (*ta)->event()->time(), (*tb)->event()->time());
+}
+
+void timetable_panel::raw_click1(XEvent* e,xnode* x)
+{
+ char buf[1024];
+
+ if(x == 0) x = (xnode*)TimeFindByY(time_,e);
+
+ timetable_node* t = main((timetable_node*)x);
+ if(!t) return;
+
+
+ node *m = t->get_node();
+
+ tmp_file tmp(tmpnam(0));
+ FILE *f = fopen(tmp.c_str(),"w");
+ if(!f) return;
+
+ range(t,dt1_,dt2_);
+
+ if (m) fprintf(f,"{%s}",m->full_name().c_str());
+ if(range2str(buf,dt1_,dt2_))
+ fprintf(f," total time: %s",buf);
+ fprintf(f,"\n\n");
+
+ timetable_node** nodes = new timetable_node*[nodes_.count()];
+ int count = 0;
+ int i;
+
+ for(i = 0; i < nodes_.count(); i++)
+ if(!nodes_[i]->is_name() && nodes_[i]->event()->owner() == m)
+ nodes[count++] = nodes_[i];
+
+ qsort(nodes,count,sizeof(nodes[0]),compare);
+
+
+ bool ok = false;
+ int elapsed[STATUS_MAX];
+ for(i = 0; i < STATUS_MAX; i++)
+ elapsed[i] = 0;
+
+ int prev_i = -1;
+
+ for(i = 0; i < count; i++)
+ {
+ date2str(buf,nodes[i]->event()->time());
+ fprintf(f,"%s",buf);
+ fprintf(f," %s",nodes[i]->text(buf));
+
+ if(i)
+ {
+ if(range2str(buf,
+ nodes[i-1]->event()->time(),
+ nodes[i]->event()->time()))
+ fprintf(f," (%slater)",buf);
+
+ }
+
+ if(prev_i >= 0 && nodes[i]->event()->status() >= 0)
+ {
+ elapsed[nodes[prev_i]->event()->status()] +=
+ TimeDiff(nodes[i]->event()->time(),
+ nodes[prev_i]->event()->time());
+ ok = true;
+ }
+
+ int s = nodes[i]->event()->status();
+ if(s >= 0) prev_i = i;
+
+ fprintf(f,"\n");
+ }
+
+ delete[] nodes;
+
+ if(ok) {
+ fprintf(f,"\nSummary:");
+ fprintf(f,"\n--------\n");
+
+ for(i = 0; i < STATUS_MAX; i++)
+ if(elapsed[i])
+ {
+ sec2str(buf,elapsed[i]);
+ fprintf(f,"%-10s: %s\n",timetatble_status::status_name[i],buf);
+ }
+ }
+
+ fclose(f);
+ depend::make(widget());
+ HyperLoadFile(hyper_,(char*)tmp.c_str());
+ depend::raise(widget());
+}
+
+void timetable_panel::setToCB(Widget,XtPointer)
+{
+ date2widget(to_,dt2_);
+ reload(false);
+}
+
+void timetable_panel::setFromCB(Widget,XtPointer)
+{
+ date2widget(from_,dt1_);
+ reload(false);
+}
+
+void timetable_panel::setBothCB(Widget,XtPointer)
+{
+ date2widget(from_,dt1_);
+ date2widget(to_,dt2_);
+ reload(false);
+}
+
+void timetable_panel::resetCB(Widget w,XtPointer d)
+{
+ dt1_ = kSmallDate; dt2_ = kLargeDate;
+ setBothCB(w,d);
+}
+
+void timetable_panel::raw_click2(XEvent* e,xnode* x)
+{
+ timetable_node *t = (timetable_node*)x;
+
+ if(t && t->is_name())
+ {
+ node *m = t->get_node();
+ bool x = !t->change_fold();
+
+ for(int i = 0; i < nodes_.count(); i++)
+ if(nodes_[i]->get_node() != m)
+ if(nodes_[i]->get_node())
+ if(nodes_[i]->get_node()->is_my_parent(m))
+ nodes_[i]->visibility(x);
+ NodeUpdate(time_);
+ }
+ else {
+ }
+}
+
+timetable_node* timetable_panel::main(timetable_node* t)
+{
+ if(!t) return 0;
+
+ node *m = t->get_node();
+ for(int i = 0; i < nodes_.count(); i++)
+ if(nodes_[i]->is_name() && nodes_[i]->get_node() == m)
+ return nodes_[i];
+ return 0;
+}
+
+
+
+void timetable_panel::range(timetable_node* z,DateTime& dt1,DateTime& dt2)
+{
+
+ dt1 = dt2 = z->event()->time();
+
+ if(z->is_name())
+ {
+
+ node *m = z->get_node();
+
+ for(int i = 0; i < nodes_.count(); i++)
+ if(!nodes_[i]->is_name() && nodes_[i]->get_node() == m)
+ {
+ DateTime t = nodes_[i]->event()->time();
+ if(t < dt1) dt1 = t;
+ if(t > dt2) dt2 = t;
+ }
+ }
+
+}
+
+void timetable_panel::raw_click3(XEvent* e,xnode* x)
+{
+ char buf[1024];
+
+
+ timetable_node* z = (timetable_node*)x;
+
+ xmstring s("-");
+ static xmstring cr("\n");
+
+ XtUnmanageChild(set_both_);
+ XtManageChild(set_to_);
+ XtManageChild(set_from_);
+
+
+ if(z) {
+
+ z->text(buf);
+ range(z,dt1_,dt2_);
+
+ s = xmstring(buf);
+
+ if(z->is_name())
+ {
+ date2str(buf,dt1_);
+ s += cr;
+ s += xmstring("From : ","bold");
+ s += xmstring(buf);
+
+ date2str(buf,dt2_);
+ s += cr;
+ s += xmstring("To : ","bold");
+ s += xmstring(buf);
+
+ if(range2str(buf,dt1_,dt2_))
+ {
+ s += cr;
+ s += xmstring("Elapsed: ","bold");
+ s += xmstring(buf);
+ }
+
+ XtManageChild(set_both_);
+ XtUnmanageChild(set_to_);
+ XtUnmanageChild(set_from_);
+
+ }
+ else {
+
+ date2str(buf,dt1_);
+ s = xmstring(buf) + cr + s;
+
+ if(last_ != kSmallDate)
+ {
+ if(range2str(buf,last_,dt1_))
+ {
+ s += cr;
+ s += xmstring("From last click: ","bold");
+ s += xmstring(buf);
+ }
+ }
+
+ last_ = dt1_;
+
+ }
+ }
+ else {
+ TimeEventTime(time_,e,&dt1_);
+ date2str(buf,dt1_);
+ s = xmstring(buf);
+ dt2_ = dt1_;
+ last_ = kSmallDate;
+ }
+
+ XtVaSetValues(label_, XmNlabelString, XmString(s), NULL);
+
+ node_window::raw_click3(e,0);
+}
+
+
+Widget timetable_panel::menu1()
+{
+ return menu_;
+}
+
+Widget timetable_panel::menu2()
+{
+ return menu1();
+}
+
+xnode* timetable_panel::xnode_of(node& n)
+{
+#if 0
+ for(int i = 0; i < nodes_.count(); i++)
+ if(nodes_[i]->get_node() == &n)
+ return nodes_[i];
+#endif
+ return 0;
+}
+
+void timetable_panel::optionsCB(Widget,XtPointer)
+{
+ globals::set_resource("timeline_sorted_by_time",
+ sorted_by_time_ = XmToggleButtonGetState(by_time_));
+
+ globals::set_resource("timeline_tasks_only",
+ tasks_only_ = XmToggleButtonGetState(tasks_));
+
+ reload(false);
+}
diff --git a/view/src/timetable_panel.h b/view/src/timetable_panel.h
new file mode 100644
index 0000000..1609ff2
--- /dev/null
+++ b/view/src/timetable_panel.h
@@ -0,0 +1,123 @@
+#ifndef timetable_panel_H
+#define timetable_panel_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "uitimetable.h"
+
+#ifndef panel_H
+#include "panel.h"
+#endif
+
+#ifndef node_window_H
+#include "node_window.h"
+#endif
+
+#ifndef str_H
+#include "str.h"
+#endif
+
+#ifndef array_H
+#include "array.h"
+#endif
+
+#ifndef log_event_H
+#include "log_event.h"
+#endif
+
+#ifndef depend_H
+#include "depend.h"
+#endif
+
+class layout;
+class host;
+class timetable_node;
+
+class timetable_panel : public panel
+ , public node_window
+ , public depend
+ , public event_lister
+ , public timetable_form_c {
+public:
+
+ timetable_panel(panel_window&);
+
+ ~timetable_panel(); // Change to virtual if base class
+
+ void remove(timetable_node*);
+
+ virtual void create (Widget parent, char *widget_name = NULL);
+ virtual void show(node&);
+ virtual void changed(node&);
+ virtual Boolean enabled(node&);
+ virtual void clear();
+ virtual const char* name() const { return "Time line"; }
+ virtual Widget widget() { return timetable_form_c::xd_rootwidget(); }
+ virtual Widget tools() { return tools_; }
+
+private:
+
+ timetable_panel(const timetable_panel&);
+ timetable_panel& operator=(const timetable_panel&);
+
+ array<timetable_node*> nodes_;
+
+ DateTime last_;
+ DateTime min_time_;
+ DateTime max_time_;
+
+ bool sorted_by_time_;
+ bool tasks_only_;
+
+ DateTime dt1_;
+ DateTime dt2_;
+
+ void load(bool);
+ void load(const char*,bool);
+ timetable_node* add(log_event*);
+ void range(timetable_node*,DateTime&,DateTime&);
+ timetable_node* main(timetable_node*);
+
+ void reload(bool);
+
+ virtual void chooseCB( Widget, XtPointer );
+ virtual void loadCB( Widget, XtPointer );
+ virtual void mergeCB( Widget, XtPointer );
+ virtual void updateCB( Widget, XtPointer );
+ virtual void activateCB( Widget, XtPointer );
+ virtual void optionsCB( Widget, XtPointer );
+
+ virtual void setFromCB( Widget, XtPointer );
+ virtual void setToCB( Widget, XtPointer );
+ virtual void setBothCB( Widget, XtPointer );
+ virtual void resetCB( Widget, XtPointer );
+ virtual void hyperCB( Widget, XtPointer );
+
+ // From node_window
+ virtual xnode* xnode_of(node &);
+ virtual Widget node_widget() { return time_; }
+ virtual Widget menu1();
+ virtual Widget menu2();
+
+ virtual void raw_click1(XEvent*,xnode*);
+ virtual void raw_click2(XEvent*,xnode*);
+ virtual void raw_click3(XEvent*,xnode*);
+
+ virtual void next(log_event*);
+};
+
+inline void destroy(timetable_panel**) {}
+#endif
diff --git a/view/src/tip.cc b/view/src/tip.cc
new file mode 100644
index 0000000..81dbaec
--- /dev/null
+++ b/view/src/tip.cc
@@ -0,0 +1,114 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #9 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <X11/IntrinsicP.h>
+#include <Xm/Xm.h>
+#include <Xm/PushB.h>
+#include <stdio.h>
+#include "tip.h"
+#include "gui.h"
+#include "pixmap.h"
+extern "C" {
+#include "xec.h"
+}
+
+tip::tip(Widget w):
+ timeout(0.5),
+ in_(false),
+ widget_(w)
+{
+ if(XmIsPushButton(w)) {
+ XtAddEventHandler(w,EnterWindowMask,False,enterCB,this);
+ XtAddEventHandler(w,LeaveWindowMask|ButtonPressMask,False,leaveCB,this);
+ }
+
+ create(gui::top(),NULL);
+ xec_SetLabel(label_,XtName(w));
+ XtRealizeWidget(_xd_rootwidget);
+
+ pixmap::find(XtName(w)).set_label(w);
+}
+
+tip::~tip()
+{
+}
+
+void tip::enter()
+{
+ if (1) {
+ in_ = true;
+ enable();
+ }
+ else
+ in_ = false;
+}
+
+void tip::leave()
+{
+ in_ = false;
+ disable();
+ XUnmapWindow(XtDisplay(_xd_rootwidget),XtWindow(_xd_rootwidget));
+}
+
+void tip::enterCB(Widget w,XtPointer data,XEvent*,Boolean*)
+{
+ ((tip*)data)->enter();
+}
+
+void tip::leaveCB(Widget w,XtPointer data,XEvent*,Boolean*)
+{
+ ((tip*)data)->leave();
+}
+
+#include <Xm/XmP.h>
+
+void tip::makeTips(Widget w)
+{
+ CompositeWidget c = (CompositeWidget)w;
+ for(unsigned int i = 0 ; i < c->composite.num_children; i++)
+ {
+ Widget p = c->composite.children[i];
+ if(XmIsPushButton(p)) new tip(p);
+ // else { printf("# xtname: %s\n", XtName(p)); new tip(p); }
+ }
+}
+
+void tip::run()
+{
+ Position x,y;
+ Dimension h,w,lw,lh;
+ XmString ls;
+
+ if (widget_==NULL) return;
+ XtTranslateCoords(widget_,0,0,&x,&y);
+
+ if (0) {
+ XtVaGetValues(widget_,XmNheight,&h,NULL);
+ XtVaSetValues(tip_shell,XmNx,x,XmNy,y + h, NULL);
+ } else {
+ XmFontList fl = NULL;
+ XtVaGetValues(widget_, XmNfontList, &fl, NULL);
+ if (fl == NULL) return; /* ??? 20120119 */
+ ls = XmStringCreateSimple(XtName(widget_));
+ lw = XmStringWidth(fl, ls)+6;
+ lh = XmStringHeight(fl, ls)+6;
+ XmStringFree(ls);
+ XtVaGetValues(widget_,XmNheight,&h,XmNwidth,&w,NULL);
+ XtVaSetValues(tip_shell, XmNx,x + w,XmNy,y + h,
+ XmNwidth,lw,XmNheight,lh,NULL);
+ }
+ XMapRaised(XtDisplay(_xd_rootwidget),XtWindow(_xd_rootwidget));
+ disable();
+}
diff --git a/view/src/tip.h b/view/src/tip.h
new file mode 100644
index 0000000..3deaf0c
--- /dev/null
+++ b/view/src/tip.h
@@ -0,0 +1,52 @@
+#ifndef tip_H
+#define tip_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#ifndef timeout_H
+#include "timeout.h"
+#endif
+
+#include "uitip.h"
+
+class tip : public timeout, public tip_shell_c {
+public:
+
+ tip(Widget);
+
+ ~tip(); // Change to virtual if base class
+
+ static void makeTips(Widget);
+
+private:
+
+ tip(const tip&);
+ tip& operator=(const tip&);
+
+ Boolean in_;
+ Widget widget_;
+
+ void enter();
+ void leave();
+ void run();
+
+ static void enterCB(Widget,XtPointer,XEvent*,Boolean*);
+ static void leaveCB(Widget,XtPointer,XEvent*,Boolean*);
+};
+
+inline void destroy(tip**) {}
+
+#endif
diff --git a/view/src/tmp_file.cc b/view/src/tmp_file.cc
new file mode 100644
index 0000000..9cecfa0
--- /dev/null
+++ b/view/src/tmp_file.cc
@@ -0,0 +1,109 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "tmp_file.h"
+#include <iostream>
+#include <fstream>
+#include <ecflowview.h>
+
+tmp_file_imp::tmp_file_imp(const char* p,bool del):
+ str_(p ? strdup(p) : 0),
+ del_(del)
+{
+}
+
+tmp_file_imp::~tmp_file_imp()
+{
+ if(str_) {
+ if(del_) {
+ unlink(str_);
+ }
+ free(str_);
+ }
+}
+
+const char* tmp_file_imp::str()
+{
+ return str_;
+}
+
+tmp_file::tmp_file(const char* p,bool del):
+ imp_(new tmp_file_imp(p,del))
+{
+ imp_->attach();
+}
+
+tmp_file::tmp_file(const std::string& p,bool del):
+ imp_(new tmp_file_imp(tmpnam((char*)tmpName),del))
+{
+ imp_->attach();
+ std::ofstream f (imp_->str());
+ if (f.is_open())
+ {
+ f << p;
+ f.close();
+ }
+}
+
+const char* tmp_file::c_str() {
+ if (imp_) return imp_->str();
+ return 0x0;
+}
+
+tmp_file::~tmp_file()
+{
+ if(imp_)
+ imp_->detach();
+}
+
+tmp_file::tmp_file(const tmp_file& other):
+ imp_(other.imp_)
+{
+ imp_->attach();
+}
+
+tmp_file& tmp_file::operator=(const tmp_file& other)
+{
+ if (other.imp_)
+ other.imp_->attach();
+ if (imp_) {
+ imp_->detach();
+ }
+ imp_ = other.imp_;
+ return *this;
+}
+
+#if defined(linux) || defined(_AIX)
+
+char * tmpnam(char *) __THROW {
+ char *path = getenv("SCRATCH");
+ char *s = (char*) malloc(128);
+ if (!path || !access(path, R_OK))
+ path=getenv("TMPDIR");
+ if (!path || !access(path, R_OK))
+ path=(char*)"/tmp";
+ snprintf(s, 128, "%s/%sXXXXXX", path, appName);
+ // int fid =
+ mkstemp(s);
+ // return s = tempnam(path, appName);
+ return s;
+}
+
+#endif
+
diff --git a/view/src/tmp_file.h b/view/src/tmp_file.h
new file mode 100644
index 0000000..1b50bea
--- /dev/null
+++ b/view/src/tmp_file.h
@@ -0,0 +1,83 @@
+#ifndef tmp_file_H
+#define tmp_file_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#ifdef NO_BOOL
+#include "bool.h"
+#endif
+
+#ifndef counted_H
+#include "counted.h"
+#endif
+
+#include <string>
+
+/** char * tmpnam(s) char *s;
+ * enable P_tmpdir local definition to change default /tmp directory
+ * enable using new location up to 44 char
+ */
+
+#ifndef __THROW
+#define __THROW
+#endif
+#ifdef linux
+
+extern "C" {
+ extern char * tempnam(const char *d, const char* s) __THROW;
+}
+
+#ifndef tmpnam1
+#include <stdlib.h>
+#define tmpnam1
+char * tmpnam(char *) __THROW;
+#endif
+
+#endif
+
+class tmp_file_imp : public counted {
+ char* str_;
+ bool del_;
+public:
+ tmp_file_imp(const char*,bool);
+ ~tmp_file_imp();
+ const char* str();
+};
+
+class tmp_file {
+ public:
+
+ tmp_file(const char* str,bool = true);
+
+ // str input IS the file content, not filename
+ tmp_file(const std::string& str,bool = true);
+ tmp_file(const tmp_file&);
+
+ ~tmp_file();
+
+ tmp_file& operator=(const tmp_file&);
+
+ const char* c_str(); /* { if (imp_) return imp_->str();
+ return load.c_str();} */
+
+private:
+
+ tmp_file_imp* imp_;
+};
+
+inline void destroy(tmp_file**) {}
+
+#endif
diff --git a/view/src/tmpnam.c b/view/src/tmpnam.c
new file mode 100644
index 0000000..ea026b1
--- /dev/null
+++ b/view/src/tmpnam.c
@@ -0,0 +1,63 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <stdio.h>
+
+/*
+ * Use /tmp instead of /usr/tmp, because L_tmpname is only 14 chars
+ * on some machines (like NeXT machines) and /usr/tmp will cause
+ * buffer overflows.
+ */
+
+#ifdef P_tmpdir
+# undef P_tmpdir
+#endif
+#define P_tmpdir "/tmp"
+
+char *
+tmpnam(s)
+ char *s;
+{
+ static char name[50];
+ char * file_name;
+ char *mktemp();
+
+ if (!s)
+ s = name;
+
+ file_name = getenv ("TMPDIR");
+
+ if (file_name && strlen (file_name) < 42)
+ (void)sprintf(s, "%s/XXXXXX", file_name);
+ else
+ (void)sprintf(s, "%s/XXXXXX", P_tmpdir);
+
+ if (mkstemp(s))
+ return s;
+ else
+ return NULL;
+}
+
+#if UTEST
+
+int main (int argc, char ** argv)
+{
+ char *name = tmpnam (NULL);
+ printf ("%s\n", name);
+};
+#endif
diff --git a/view/src/to_check.h b/view/src/to_check.h
new file mode 100644
index 0000000..8ed81b3
--- /dev/null
+++ b/view/src/to_check.h
@@ -0,0 +1,40 @@
+#ifndef to_check_H
+#define to_check_H
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #4 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+
+#include "node_alert.h"
+
+class node;
+
+class to_check : public node_alert<to_check> {
+public:
+ to_check();
+
+ ~to_check(); // Change to virtual if base class
+
+private:
+
+ to_check(const to_check&);
+ to_check& operator=(const to_check&);
+
+ virtual bool keep(node* n);
+
+};
+
+inline void destroy(to_check**) {}
+
+#endif
diff --git a/view/src/top.cc b/view/src/top.cc
new file mode 100644
index 0000000..2a438be
--- /dev/null
+++ b/view/src/top.cc
@@ -0,0 +1,512 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #20 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "top.h"
+#include "ecflowview.h"
+#include "gui.h"
+#include "mail.h"
+#include "servers_prefs.h"
+#ifndef tree_H
+#include "tree.h"
+#endif
+#include <Xm/PushB.h>
+
+#ifndef panel_window_H
+#include "panel_window.h"
+#endif
+
+#ifndef window_H
+#include "window.h"
+#endif
+
+#ifndef error_H
+#include "error.h"
+#endif
+
+
+#ifndef runnable_H
+#include "runnable.h"
+#endif
+
+#ifndef init_H
+#include "init.h"
+#endif
+
+#ifndef show_H
+#include "show.h"
+#endif
+
+#ifndef host_H
+#include "host.h"
+#endif
+
+#ifndef tip_H
+#include "tip.h"
+#endif
+
+#ifndef search_H
+#include "search.h"
+#endif
+
+#ifndef option_H
+#include "option.h"
+#endif
+
+#ifndef pref_window_H
+#include "pref_window.h"
+#endif
+
+#ifndef ask_H
+#include "ask.h"
+#endif
+
+
+#ifndef error_H
+#include "error.h"
+#endif
+
+
+#include "late.h"
+#include "restart.h"
+#include "aborted.h"
+
+extern "C" {
+#include "xec.h"
+}
+
+#include <X11/IntrinsicP.h>
+#include <Xm/ToggleB.h>
+
+#ifndef globals_H
+#include "globals.h"
+#endif
+
+#include "Version.hpp"
+
+static option<int> top_width(globals::instance(), "top_width",500);
+static option<int> top_height(globals::instance(),"top_height",500);
+static option<int> top_xoff(globals::instance(),"top_xoff",0);
+static option<int> top_yoff(globals::instance(),"top_yoff",0);
+
+top::top():
+ timeout(60)
+{
+}
+
+
+top::~top()
+{
+ Dimension w,h;
+ Position x,y;
+
+ XtVaGetValues(this->form_,
+ XmNwidth, &w,
+ XmNheight,&h,
+ XmNx,&x,
+ XmNy,&y,
+ NULL);
+
+ top_width = w;
+ top_height = h;
+ top_xoff = x;
+ top_yoff = y;
+}
+
+class initor : public runnable {
+
+ int argc_;
+ char **argv_;
+
+ void run() {
+ disable();
+ init::initialize(argc_,argv_);
+ delete this;
+ }
+
+public:
+ initor(int argc,char** argv) : argc_(argc),argv_(argv) { enable(); }
+};
+
+static void set_show(Widget w, int flag)
+{
+ CompositeWidget c = CompositeWidget(w);
+ for(unsigned i = 0 ; i < c->composite.num_children; i++) {
+ Widget p = c->composite.children[i];
+ if(XmIsToggleButton(p)) {
+ show *s = (show*)xec_GetUserData(p);
+ Boolean b = False;
+ bool wanted = s->wanted();
+ if (flag == show::all) {
+ b = True; wanted = true; }
+ if ((s->flag() == show::all) || (s->flag() == show::none)) {
+ b = False; wanted = false; }
+ XmToggleButtonSetState(p,wanted,b);
+ }
+ }
+}
+
+static int xerror(Display *d, XErrorEvent *e)
+{
+ char buf[1024];
+ XGetErrorText(d,e->error_code,buf,sizeof(buf));
+ printf("xerror %s\n",buf);
+ return 0;
+}
+
+void top::create(Display *display, char *app_name,
+ int app_argc, char **app_argv, char *app_class_name)
+{
+
+#if 1
+ // XSynchronize should *only* be enabled for debug, it should not be enabled in the production build.
+ // See: [JIRA] (SUP-349) ecflowview performance slow with ecflow 3_1_rc1
+ // It can cause refresh issues when displaying synchronisation enabled.
+ // XSynchronize(display,1);
+ XSetErrorHandler(xerror);
+#endif
+
+#include "xresources.h"
+
+ XrmDatabase db = XrmGetStringDatabase(xresources);
+ XrmSetDatabase(display,db);
+
+ top_shell_c::create(display,app_name,app_argc,app_argv,app_class_name);
+
+ Dimension w,h;
+ Position x,y, ac = 0;
+ char color[20];
+ snprintf(color, 20, "#e5e5e5e5e5e5");
+
+ w = top_width;
+ h = top_height;
+ x = top_xoff;
+ y = top_yoff;
+
+ while (ac < app_argc) {
+ /* accept command line directives for display */
+ if (!strncmp("-geometry=",app_argv[ac],10)) {
+ int ww=0, hh=0, xx=0, yy=0;
+ sscanf(app_argv[ac], "-geometry=%dx%d+%d+%d", &ww, &hh, &xx, &yy);
+ fprintf(stdout, "# geometry: %dx%d+%d+%d\n", ww, hh, xx, yy);
+ w=ww; h=hh; x=xx; y=yy;
+ } else if (!strncmp("-b",app_argv[ac],2)) {
+ if (!strncmp("-bg=",app_argv[ac],4)) {
+ sscanf(app_argv[ac], "-bg=%s", color);
+ } else if (!strncmp("-background=",app_argv[ac],12)) {
+ sscanf(app_argv[ac], "-background=%s", color);
+ }
+
+ std::string res = "ecFlowview*background: ";
+ res += color;
+ std::cout << "# bg color change: " << res << "\n";
+ db = XrmGetStringDatabase(res.c_str());
+ XrmSetDatabase(display,db);
+ } else if (!strncmp("-rc=",app_argv[ac],4)) {
+ char rcdir[1024] = { 0 };
+ sscanf(app_argv[1], "-rc=%s", rcdir);
+ if (rcdir[0] != 0) {
+ std::string var = "ECFLOWRC="; var += rcdir;
+ putenv((char*) var.c_str());
+ fprintf(stdout, "# rcdir: %s\n", rcdir);
+ }
+ }
+ ac++;
+ }
+
+ XtVaSetValues(this->form_,
+ XmNwidth, w,
+ XmNheight,h,
+ XmNx, x,
+ XmNy, y,
+// XmNbackground, (int)pixel(color),
+// XtVaTypedArg, XmNbackground, XmRString, color.c_str(), size, // 201403
+ NULL);
+#if 0
+ XtGetApplicationResources(_xd_rootwidget,
+ (XtPointer)&globals,
+ resources,
+ XtNumber(resources),
+ NULL,NULL);
+
+ XtGCMask valuemask = (GCForeground | GCFont);
+ XFontStruct* font = XLoadQueryFont(XtDisplay(_xd_rootwidget),"fixed");
+
+ XGCValues values;
+ values.font = font->fid;
+ values.foreground = globals.black;
+
+ globals.blackGC = XtGetGC(_xd_rootwidget,valuemask,&values);
+ values.foreground = globals.blue;
+ globals.blueGC = XtGetGC(_xd_rootwidget,valuemask,&values);
+
+ for(int j=0;j<STATUS_MAX;j++)
+ {
+ values.foreground = globals.colors[j];
+ globals.colGC[j] = XtGetGC(_xd_rootwidget,valuemask,&values);
+ }
+#endif
+ set_show(show0_,0); set_show(show1_,0);
+ set_show(show2_,0); set_show(show3_,0);
+
+ tip::makeTips(tools_);
+ //==========================================
+
+ new initor(app_argc,app_argv);
+
+ // Update and start clock
+ run();
+ enable();
+}
+
+void top::serverCB(Widget,XtPointer)
+{
+ host::broadcast();
+}
+
+static void hostCB(Widget w,XtPointer,XtPointer cb_data)
+{
+ XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct*)cb_data;
+ char* name = XtName(w);
+ if(cb->set)
+ host::login(name);
+ else
+ host::logout(name);
+}
+
+void top::add_host(const std::string& host)
+{
+ Widget w;
+ if(!(w=XtNameToWidget(servers_menu_,host.c_str())))
+ {
+ w = XmCreateToggleButton(servers_menu_,
+ (char*)host.c_str(),NULL,0);
+ XtAddCallback(w,XmNvalueChangedCallback,hostCB,NULL);
+ }
+ XtManageChild(w);
+ servers_prefs::add_host(host);
+}
+
+void top::remove_host(const std::string& host)
+{
+ Widget w = XtNameToWidget(servers_menu_,host.c_str());
+ XtUnmanageChild(w);
+}
+
+void top::login(const char* host)
+{
+ Widget w = XtNameToWidget(servers_menu_,host);
+ if(w)
+ XmToggleButtonSetState(w,True,False);
+ mail::login(host);
+}
+
+void top::logout(const char* host)
+{
+ Widget w = XtNameToWidget(servers_menu_,host);
+ if(w) XmToggleButtonSetState(w,False,False);
+ mail::logout(host);
+}
+
+class reset_message : public runnable {
+ void run() { gui::clear(); disable(); }
+};
+
+void top::clear()
+{
+ run();
+}
+
+void top::message(const char* buf)
+{
+ static reset_message reset;
+ xec_SetLabel(message_,buf);
+ XmUpdateDisplay(message_);
+ reset.enable();
+}
+
+
+Widget top::top_shell()
+{
+ return xd_rootwidget();
+}
+
+Widget top::trees()
+{
+ return trees_;
+}
+
+Widget top::windows()
+{
+ return windows_menu_;
+}
+
+void top::run()
+{
+ time_t t = time(0);
+ char buf[1024];
+ // strftime(buf,sizeof(buf),"%Y-%m-%d %H:%M" ,gmtime(&t));
+ strftime(buf,sizeof(buf),"%Y-%m-%d %H:%M:%S" ,gmtime(&t));
+ xec_SetLabel(message_,buf);
+}
+
+void top::watch(Boolean)
+{
+}
+
+void top::quitCB(Widget,XtPointer)
+{
+ extent<host>::delete_all();
+ delete this;
+ exit(0);
+}
+
+void top::snapshotCB( Widget w, XtPointer p )
+{
+ char cmd[1024];
+ FILE *f = 0;
+
+ gui::message("using SNAPSHOT ; press button \n");
+ sprintf(cmd,"${SNAPSHOT:=import} %s\n", snapshotName);
+
+ f = popen(cmd,"r");
+ if(!f) {
+ gui::error("Cannot create snapshot : %s", cmd);
+ return;
+ }
+ else if (!pclose(f)) {
+ gui::message("%s # generated\n", snapshotName);
+ sprintf(cmd,"${SNAPVISU:=firefox} %s\n", snapshotName);
+ f = popen(cmd,"r");
+ }
+ else {
+ gui::error("Cannot create snapshot : %s", cmd);
+ return;
+ }
+}
+
+void top::statusCB(Widget,XtPointer data)
+{
+ XmPushButtonCallbackStruct* cb = (XmPushButtonCallbackStruct*)data;
+ host::status((cb->event->xbutton.state & ShiftMask) != 0);
+}
+
+void top::windowCB(Widget w,XtPointer data)
+{
+ XmPushButtonCallbackStruct *cb = (XmPushButtonCallbackStruct *) data;
+
+ panel_window::new_window
+ (selection::current_node(),
+ XtName(w),
+ (cb->event->xbutton.state & ShiftMask) != 0,
+ (cb->event->xbutton.state & ShiftMask) != 0
+ );
+}
+
+void top::showCB(Widget w,XtPointer data)
+{
+ XmRowColumnCallbackStruct *cb = (XmRowColumnCallbackStruct *) data;
+ show *s = (show*)xec_GetUserData(cb->widget);
+ if(s && XmIsToggleButton(cb->widget)) {
+ int flag = s->flag();
+ if (((flag == show::none) | (flag == show::all))) {
+ s->off();
+ set_show(show0_, flag); set_show(show1_, flag);
+ set_show(show2_, flag); set_show(show3_, flag);
+ XmToggleButtonSetState(cb->widget,false,False);
+ } else if (XmToggleButtonGetState(cb->widget))
+ s->on();
+ else
+ s->off();
+ tree::update_all(true);
+ }
+}
+
+void top::chatCB(Widget w,XtPointer)
+{
+ host::chat();
+}
+
+void top::windowsCB(Widget,XtPointer data)
+{
+ XmRowColumnCallbackStruct *cb = (XmRowColumnCallbackStruct *) data;
+ window *w = (window*) xec_GetUserData (cb->widget);
+ w->raise();
+}
+
+void top::searchCB(Widget w,XtPointer)
+{
+ search::show();
+}
+
+void top::releaseCB(Widget w,XtPointer)
+{
+ std::string version = "version " + ecf::Version::raw();
+ gui::message(version.c_str());
+ char cmd[1024];
+ snprintf(cmd, 1024, "${ECFLOWVIEW_HELP:=firefox --new-tab %s}\n", urlRef);
+ // snprintf(cmd, 1024, "%s %s\n", browserName, urlRef);
+ std::cerr << "#INF: " << cmd;
+ if (system(cmd)) { std::cerr << "#ERR release\n"; }
+ // execlp(browserName, urlRef, NULL);
+ sleep (1);
+}
+
+void top::helpCB(Widget w,XtPointer)
+{
+ const char *link="http://intra.ecmwf.int/metapps/manuals/ecflow/index.html";
+ // const char *jira="http://software.ecmwf.int/issues/browse/ECFLOW";
+ // const char *link="http://wedit.ecmwf.int/publications/manuals/ecFlow";
+ char cmd[1024];
+
+ gui::message("ecFlowView help (ECFLOWVIEW_HELP); press button\n");
+ snprintf(cmd, 1024, "${ECFLOWVIEW_HELP:=firefox --new-tab %s}\n", link);
+ std::cerr << "#INF: " << cmd;
+
+ if (1) {
+ if (system(cmd)) { std::cerr << "#ERR system\n"; }
+ } else {
+ FILE* f = popen(cmd,"r");
+ if(!f) {
+ gui::error("Cannot access : %s", link);
+ return;
+ } else if (!pclose(f)) {
+ } else {
+ gui::error("Cannot access : %s", link);
+ return;
+ }
+ }
+}
+
+void top::prefCB(Widget w,XtPointer)
+{
+ pref_window::show();
+}
+
+void top::loginCB(Widget w,XtPointer)
+{
+ static str s;
+ if(ask::show(s,"Login to (host [port]): ")) {
+ char h[80] = { 0 };
+ int n = 3141;
+ sscanf(s.c_str(),"%s %d",h,&n);
+ if (h[0] != 0)
+ host::login(h,n);
+ }
+}
+
+void top::error(const char* msg)
+{
+ error::show(msg);
+}
diff --git a/view/src/top.h b/view/src/top.h
new file mode 100644
index 0000000..508a4d0
--- /dev/null
+++ b/view/src/top.h
@@ -0,0 +1,72 @@
+#ifndef top_H
+#define top_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "uitop.h"
+#include "timeout.h"
+#include "interface.h"
+
+class top : public top_shell_c, public timeout, public interface {
+public:
+
+ top();
+ ~top(); // Change to virtual if base class
+
+ virtual void create (Display *display, char *app_name,
+ int app_argc, char **app_argv,
+ char *app_class_name = NULL);
+
+ virtual void run();
+
+ virtual void clear();
+ virtual void message(const char*);
+ virtual void watch(Boolean);
+
+ virtual void add_host(const std::string&);
+ virtual void remove_host(const std::string&);
+ virtual void rename_host(const std::string&,const std::string&) {}
+
+ virtual void login(const char*);
+ virtual void logout(const char*);
+
+ virtual Widget top_shell();
+ virtual Widget trees();
+ virtual Widget windows();
+
+ virtual void error(const char*);
+private:
+
+ top(const top&);
+ top& operator=(const top&);
+
+ virtual void quitCB(Widget,XtPointer);
+ virtual void serverCB(Widget,XtPointer);
+ virtual void statusCB(Widget,XtPointer);
+ virtual void windowCB(Widget,XtPointer);
+ virtual void showCB(Widget,XtPointer);
+ virtual void chatCB(Widget,XtPointer);
+ virtual void windowsCB(Widget,XtPointer);
+ virtual void searchCB(Widget,XtPointer);
+ virtual void helpCB(Widget,XtPointer);
+ virtual void prefCB(Widget,XtPointer);
+ virtual void loginCB(Widget,XtPointer);
+ virtual void releaseCB(Widget,XtPointer);
+ virtual void snapshotCB(Widget,XtPointer);
+};
+
+inline void destroy(top**) {}
+#endif
diff --git a/ecflow_4_0_7/view/src/trans.sh b/view/src/trans.sh
similarity index 100%
rename from ecflow_4_0_7/view/src/trans.sh
rename to view/src/trans.sh
diff --git a/view/src/translator.cc b/view/src/translator.cc
new file mode 100644
index 0000000..9b2c94a
--- /dev/null
+++ b/view/src/translator.cc
@@ -0,0 +1,211 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#ifndef translator_H
+#include "translator.h"
+#endif
+
+#ifndef str_H
+#include "str.h"
+#endif
+
+#ifndef choice_H
+#include "choice.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string>
+
+str translator<int,str>::operator()(int n)
+{
+ char buf[80];
+ sprintf(buf,"%d",n);
+ return str(buf);
+}
+
+const str& translator<str,str>::operator()(const str& x)
+{
+ return x;
+}
+
+int translator<str,int>::operator()(const str& x)
+{
+ return atol(x.c_str());
+}
+
+str translator<long long int,str>::operator()(long long int n)
+{
+ char buf[80];
+ sprintf(buf,"%lld",n);
+ return str(buf);
+}
+
+long long int translator<str,long long int>::operator()(const str& x)
+{
+ return atoll(x.c_str());
+}
+
+str translator<uint64_t,str>::operator()(uint64_t n)
+{
+ char buf[80];
+ sprintf(buf,"%ld",n);
+ return str(buf);
+}
+
+uint64_t translator<str,uint64_t>::operator()(const str& x)
+{
+ return atoll(x.c_str());
+}
+
+#ifdef WITH_INT128
+str translator<uint128,str>::operator()(uint128 n)
+{
+ char buf[80];
+ sprintf(buf,"%lld",n);
+ return str(buf);
+}
+
+uint128 translator<str,uint128>::operator()(const str& x)
+{
+ return atoll(x.c_str());
+}
+#endif
+
+str translator<ULL,str>::operator()(ULL n)
+{
+ char buf[80];
+ sprintf(buf,"%ulld",n);
+ return str(buf);
+}
+ULL translator<str,ULL>::operator()(const str& x)
+{
+ return atoll(x.c_str());
+}
+
+
+const str& translator<bool,str>::operator()(bool n)
+{
+ static str t("true");
+ static str f("false");
+
+ return n ? t : f;
+}
+
+bool translator<str,bool>::operator()(const str& x)
+{
+ char z = x.c_str()[0];
+ return z == 't' || z == 'T' || z == '1';
+}
+
+ecf_list* translator<str,ecf_list*>::operator()(const str& x)
+{
+ ecf_list* l = 0;
+ const char* p = x.c_str();
+ char word[1024];
+ int i = 0;
+
+ while(*p)
+ {
+ if(*p == ' ')
+ {
+ word[i] = 0;
+ if(i) {
+ ecf_list *z = ecf_node_create(word);
+ z->next = l;
+ l = z;
+ }
+ i = 0;
+ }
+ else {
+ word[i++] = *p;
+ }
+ p++;
+
+ }
+
+ word[i] = 0;
+ if(i) {
+ ecf_list *z = ecf_node_create(word);
+ z->next = l;
+ l = z;
+ }
+ return l;
+}
+
+str translator<ecf_list*,str>::operator()(ecf_list* x)
+{
+ str s;
+ str space = " ";
+ while(x)
+ {
+ s = s + str(x->name().c_str());
+ if(x->next) s = s + space;
+ x = x->next;
+ }
+ return s;
+}
+
+#define t_vs std::vector<std::string>
+t_vs translator<str,t_vs >::operator()(const str& x)
+{
+ t_vs l;
+ const char* p = x.c_str();
+ char word[1024];
+ int i = 0;
+
+ while(*p) {
+ if(*p == ' ') {
+ word[i] = 0;
+ if(i) {
+ l.push_back(std::string(word));
+ }
+ i = 0;
+ } else {
+ word[i++] = *p;
+ }
+ p++;
+ }
+
+ word[i] = 0;
+ if(i) {
+ l.push_back(std::string(word));
+ }
+ return l;
+}
+
+// translator<str, std::vector<std::string> >::operator()(str const&)
+
+str translator<t_vs, str>::operator()(t_vs x)
+{
+ str s, space = " ";
+ t_vs::iterator j;
+ for (j = x.begin(); j != x.end(); ++j) {
+ s += str(j->c_str());
+ if(j != x.end())
+ s += space;
+ }
+ return s;
+}
+
+str translator<choice,str>::operator()(const choice& n)
+{
+ return translator<int,str>()(n);
+}
+
+choice translator<str,choice>::operator()(const str& x)
+{
+ return choice(atol(x.c_str()));
+}
diff --git a/view/src/translator.h b/view/src/translator.h
new file mode 100644
index 0000000..ef99722
--- /dev/null
+++ b/view/src/translator.h
@@ -0,0 +1,114 @@
+#ifndef translator_H
+#define translator_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include <vector>
+// #include <inttypes.h>
+
+#ifdef NO_BOOL
+#include "bool.h"
+#endif
+#include "ecflow.h"
+class str;
+class choice;
+#include "gen_translator.h"
+
+template<> class translator<str,str> {
+public:
+ const str& operator()(const str& x);
+};
+
+template<> class translator<str,bool> {
+public:
+ bool operator()(const str&);
+};
+
+template<> class translator<bool,str> {
+public:
+ const str& operator()(bool x);
+};
+
+template<> class translator<str,int> {
+public:
+ int operator()(const str&);
+};
+
+template<> class translator<int,str> {
+public:
+ str operator()(int x);
+};
+
+template<> class translator<str,long long int> {
+public:
+ long long int operator()(const str&);
+};
+template<> class translator<long long int,str> {
+public:
+ str operator()(long long int x);
+};
+
+// #define ULL long long
+// #define ULL uint64_t
+#define ULL unsigned int
+template<> class translator<str,ULL> {public: ULL operator()(const str&); };
+template<> class translator<ULL,str> {public: str operator()(ULL x); };
+
+template<> class translator<str,uint64_t> {
+public:
+ uint64_t operator()(const str&);
+};
+template<> class translator<uint64_t,str> {
+public:
+ str operator()(uint64_t x);
+};
+
+#ifdef WITH_INT128
+template<> class translator<uint128,str> {public: str operator()(uint128 x);};
+template<> class translator<str,uint128> {public: uint128 operator()(const str&); };
+#endif
+
+template<> class translator<str,std::vector<std::string> > {
+public:
+ std::vector<std::string> operator()(const str&);
+};
+
+template<> class translator<std::vector<std::string> ,str> {
+public:
+ str operator()(std::vector<std::string> );
+};
+
+template<> class translator<str,ecf_list*> {
+public:
+ ecf_list* operator()(const str&);
+};
+
+template<> class translator<ecf_list*,str> {
+public:
+ str operator()(ecf_list*);
+};
+
+template<> class translator<str,choice> {
+public:
+ choice operator()(const str&);
+};
+
+template<> class translator<choice,str> {
+public:
+ str operator()(const choice&);
+};
+
+#endif
diff --git a/view/src/tree.cc b/view/src/tree.cc
new file mode 100644
index 0000000..2610483
--- /dev/null
+++ b/view/src/tree.cc
@@ -0,0 +1,340 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #11 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <stdio.h>
+
+#ifndef tree_H
+#include "tree.h"
+#endif
+
+#ifndef init_H
+#include "init.h"
+#endif
+
+#ifndef ecflowview_H
+#include "ecflowview.h"
+#endif
+
+#ifndef host_H
+#include "host.h"
+#endif
+
+#ifndef menus_H
+#include "menus.h"
+#endif
+
+#ifndef gui_H
+#include "gui.h"
+#endif
+
+#ifndef tmp_file_H
+#include "tmp_file.h"
+#endif
+#ifndef globals_H
+#include "globals.h"
+#endif
+
+#include "ecf_node.h"
+
+extern "C" {
+#include "xec.h"
+#include "SimpleTree.h"
+}
+
+#include <Xm/Frame.h>
+#include <Xm/Label.h>
+#include <Xm/RowColumn.h>
+
+
+//===========================================
+
+
+tree::tree(host* h):
+ host_(h)
+{
+ observe(h);
+
+#if 0
+ XtAddCallback( tree, XmNhelpCallback, help_callback,
+ (XtPointer) 0 );
+#endif
+
+ tree_c::create(gui::trees(),(char*)h->name());
+
+ add_input_CB();
+}
+
+tree::~tree()
+{
+ XtDestroyWidget(tree_);
+}
+
+void tree::xd_show()
+{
+ XtManageChild(tree_);
+}
+
+void tree::xd_hide()
+{
+ XtUnmanageChild(tree_);
+}
+
+void tree::build_tree(node* n,int p)
+{
+ while(n) {
+ int w = n->getBox(tree_);
+ NodeAddRelation(tree_,p,w);
+ build_tree(n->kids(),w);
+ n = n->next();
+ }
+}
+
+int tree::count(node* n)
+{
+ int c = 0;
+ while(n)
+ {
+ c += count(n->kids()) + 1;
+ n = n->next();
+ }
+ return c;
+}
+
+void tree::notification(observable* o)
+{
+ host* h = (host*)o;
+
+ NodeReset(tree_);
+
+ NodeReserve(tree_,count(h->top()));
+
+ build_tree(h->top(),-1);
+
+ if (!h->top()) return;
+ if (h->name() == selection::server()) {
+ node* n = h->top()->find(selection::current_path());
+ if(n) show_node(*n);
+ }
+ update_all(false);
+}
+
+void tree::selection_cleared()
+{
+ XtSetSensitive(show_current_,False);
+ XtSetSensitive(fold_around_,False);
+ XtSetSensitive(hide_other_,False);
+ node_window::selection_cleared();
+}
+
+void tree::new_selection(node& n)
+{
+ XtSetSensitive(show_current_,True);
+ XtSetSensitive(fold_around_,True);
+ XtSetSensitive(hide_other_,True);
+ node_window::new_selection(n);
+}
+
+tree* tree::new_tree(host* h)
+{
+ if(gui::trees() == 0)
+ return 0;
+
+ Widget w = XtNameToWidget(gui::trees(),h->name());
+ tree* t = 0;
+
+ if(w == 0)
+ t = new tree(h);
+ else
+ t = (tree*)xec_GetUserData(w);
+
+ return t;
+}
+
+long tree::update_tree(node* n,bool visible)
+{
+ long changes = 0;
+
+ while(n) {
+ Boolean vis = visible && ( n->visible() || n->show_it());
+ Boolean old = n->visibility(vis);
+
+ if(old != vis) changes++;
+
+ changes += update_tree(n->kids(),vis && !n->folded());
+
+ n = n->next();
+ }
+
+ return changes;
+}
+
+void tree::update_tree(bool redraw)
+{
+ long changes = host_ ? update_tree(host_->top(),True) : 0;
+ if(redraw) NodeNewSizeAll(tree_);
+ if(changes) NodeUpdate(tree_);
+}
+
+void tree::fold_unfold_all(node *n,Boolean folding)
+{
+ while(n) {
+ n->folded(folding);
+ // n->ondemand(false); // 20120705
+ fold_unfold_all(n->kids(),folding);
+ n = n->next();
+ }
+}
+
+void tree::click2(node* n,Boolean shift,Boolean control)
+{
+ if(!n) return;
+
+ // n->ondemand(true); build_tree(n, -1); update_tree(true); // 20120705
+
+ if (shift && control)
+ fold_unfold_all(n,!n->folded());
+ else if(shift) {
+ tmp_file f = n->serv().host::output(*n);
+ char buf[10240];
+ const char *p = getenv("PAGER");
+ const char *fname = f.c_str();
+ if (!fname) return;
+ sprintf(buf,"xterm -e %s %s&",p?p:"more",fname);
+ system(buf);
+ return;
+ }
+ else if(control)
+ NodeTreeFlip(tree_,n->getBox(tree_));
+ else n->folded(!n->folded());
+
+ update_tree(false);
+}
+
+xnode* tree::xnode_of(node& n)
+{
+ return &n;
+}
+
+void tree::show_node(node& n)
+{
+ node* p = n.parent();
+ while(p)
+ {
+ p->folded(False);
+ // 201207 update_tree(true); // p->serv().redraw(); // 201107
+ p = p->parent();
+ }
+ update_tree(false);
+ n.select();
+}
+void tree::hideOtherCB( Widget w, XtPointer p )
+{
+ node* n = selection::current_node();
+ if(!n) return;
+
+ if(n->serv().where() != this)
+ n->serv().where()->hideOtherCB(w,p);
+ else
+ n->serv().suites(n);
+}
+
+void tree::snapshotCB( Widget w, XtPointer p )
+{
+ char cmd[1024];
+ FILE *f = 0;
+
+ gui::message("using SNAPSHOT ; press button \n");
+ sprintf(cmd,"${SNAPSHOT:=import} %s\n", snapshotName);
+
+ f = popen(cmd,"r");
+ if(!f) {
+ gui::error("Cannot create snapshot : %s", cmd);
+ return;
+ } else if (!pclose(f)) {
+ gui::message("%s # generated\n", snapshotName);
+ sprintf(cmd,"${SNAPVISU:=firefox} %s\n", snapshotName);
+ f = popen(cmd,"r");
+ }
+ else {
+ gui::error("Cannot create snapshot : %s", cmd);
+ return;
+ }
+}
+
+void tree::aroundCB( Widget w, XtPointer p)
+{
+ node* n = selection::current_node();
+ if(!n) return;
+
+ if(n->serv().where() != this)
+ n->serv().where()->aroundCB(w,p);
+ else
+ {
+ if (host_) fold_unfold_all(host_->top(),True);
+ show_node(*n);
+ fold_unfold_all(n,False);
+ n->select();
+ update_tree(false);
+ }
+}
+
+void tree::foldCB( Widget, XtPointer )
+{
+ if (host_) fold_unfold_all(host_->top(),True);
+ update_tree(false);
+}
+
+void tree::unfoldCB( Widget, XtPointer )
+{
+ if (host_) {
+ fold_unfold_all(host_->top(),False);
+ // 201207 build_tree(host_->top(), -1);
+ }
+ update_tree(true);
+}
+
+void tree::showCB( Widget, XtPointer )
+{
+ node* n = selection::current_node();
+ if(n) {
+ tree* t = n->serv().where();
+ t->show_node(*n);
+ n->select();
+ }
+}
+
+void tree::connected(Boolean ok)
+{
+ if(ok) {
+ XtVaSetValues(tree_,XmNbackgroundPixmap,XmUNSPECIFIED_PIXMAP,NULL);
+ } else {
+ Pixel fg,bg;
+ XtVaGetValues(tree_,XmNforeground, &fg, XmNbackground, &bg,NULL);
+ XtVaSetValues(tree_,XmNbackgroundPixmap,
+ XmGetPixmap(XtScreen(tree_),"25_foreground",fg,bg),NULL);
+ }
+}
+
+void tree::update_all(bool redraw)
+{
+ tree *t = extent<tree>::first();
+ while(t)
+ {
+ t->update_tree(redraw);
+ t = t->extent<tree>::next();
+ }
+}
+
+IMP(tree)
diff --git a/view/src/tree.h b/view/src/tree.h
new file mode 100644
index 0000000..e620252
--- /dev/null
+++ b/view/src/tree.h
@@ -0,0 +1,105 @@
+#ifndef tree_H
+#define tree_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #8 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "uitop.h"
+
+#ifndef node_H
+#include "node.h"
+#endif
+
+#ifndef node_window_H
+#include "node_window.h"
+#endif
+
+#ifndef observer_H
+#include "observer.h"
+#endif
+
+#ifndef uitree_H
+#include "uitree.h"
+#endif
+
+#ifndef extent_H
+#include "extent.h"
+#endif
+
+class tree_node;
+
+class tree : public node_window
+ , public tree_c
+ , public extent<tree>
+ , public observer {
+ public:
+ tree(host*);
+
+ ~tree(); // Change to virtual if base class
+
+ void xd_show();
+ void xd_hide();
+
+ void connected(Boolean);
+ void update_tree(bool);
+
+ virtual xnode* xnode_of(node& n);
+
+ static tree* new_tree(host*);
+ static void update_all(bool);
+
+ virtual void click2(node*,Boolean,Boolean);
+private:
+ // void ondemand(node&, bool full=false);
+
+ tree(const tree&);
+ tree& operator=(const tree&);
+
+ host* host_;
+
+ void build_tree(node*,int);
+ int count(node*);
+
+ void fold_unfold_all(node*,Boolean);
+ long update_tree(node*,bool);
+
+ // From node window
+ virtual void show_node(node&);
+
+ virtual Widget menu1() { return see_menu_; }
+ virtual Widget menu2() { return why_menu_; }
+
+ // From observer<host>
+ void notification(observable*);
+
+ void gone(observable*) {}
+ void adoption(observable*,observable*) {}
+
+ virtual void new_selection(node&);
+ virtual void selection_cleared();
+
+ Widget node_widget() { return tree_; }
+
+ virtual void hideOtherCB( Widget, XtPointer );
+ virtual void aroundCB( Widget, XtPointer );
+ virtual void foldCB( Widget, XtPointer );
+ virtual void unfoldCB( Widget, XtPointer );
+ virtual void showCB( Widget, XtPointer );
+
+ virtual void snapshotCB( Widget, XtPointer );
+};
+
+inline void destroy(tree**) {}
+#endif
diff --git a/view/src/trigger_lister.h b/view/src/trigger_lister.h
new file mode 100644
index 0000000..0e0b3bf
--- /dev/null
+++ b/view/src/trigger_lister.h
@@ -0,0 +1,41 @@
+#ifndef trigger_lister_H
+#define trigger_lister_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+class trigger_lister {
+public:
+
+ trigger_lister() {}
+
+ enum { normal = 0, // Normal trigger_node
+ parent = 1, // Through parent
+ child = 2, // Through child
+ hierarchy = 3 // Through child
+ };
+
+ virtual void next_node(node&, node*,int,node*) = 0;
+ virtual Boolean parents() { return False; }
+ virtual Boolean kids() { return False; }
+ virtual Boolean self() { return True; }
+
+private:
+ trigger_lister(const trigger_lister&);
+ trigger_lister& operator=(const trigger_lister&);
+};
+
+inline void destroy(trigger_lister**) {}
+#endif
diff --git a/view/src/trigger_node.cc b/view/src/trigger_node.cc
new file mode 100644
index 0000000..2dd6628
--- /dev/null
+++ b/view/src/trigger_node.cc
@@ -0,0 +1,274 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #17 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "trigger_node.h"
+#include "ExprAst.hpp"
+// #include "text_lister.h"
+
+trigger_node::trigger_node(host& h,ecf_node* n)
+ : node(h,n)
+ , expression_ ("empty")
+ , full_name_ ("empty")
+ , complete_ (false)
+{
+ if (!n) return;
+ complete_ = (n->kind() == 'c');
+ expression_ = n->toString();
+ full_name_ = n->parent()->full_name();
+ full_name_ += ":trigger";
+}
+
+const AstTop* trigger_node::get() const
+{
+ if (!owner_) return 0x0;
+ return dynamic_cast<ecf_concrete_node<ExpressionWrapper>*>
+ (owner_)->get()->get_ast_top();
+}
+
+xmstring trigger_node::make_label_tree()
+{
+ int inc = 0;
+ if (expression_.size() > 9) {
+ inc = complete_ ? 9 : 8;
+ }
+#ifdef BRIDGE
+ if (tree_) inc = 0;
+#endif
+ return xmstring(expression_.c_str() + inc);
+}
+
+void trigger_node::drawNode(Widget w,XRectangle* r,bool tree)
+{
+ XmStringDraw(XtDisplay(w),XtWindow(w),
+ smallfont(),
+ tree?labelTree():labelTrigger(),
+ complete_?blueGC():blackGC(),
+ r->x+2,
+ r->y+2,
+ r->width,
+ XmALIGNMENT_BEGINNING, XmSTRING_DIRECTION_L_TO_R, NULL);
+
+ shadow(w,r);
+}
+
+void trigger_node::info(std::ostream& f)
+{
+ const AstTop *ast = get();
+ if (ast) {
+ std::string str = ast->expression(true);
+ f << str << "\n";
+ }
+}
+
+// const std::string& trigger_node::definition() const { return expression_; }
+
+const std::string& trigger_node::name() const
+{
+ static std::string trigger_ = "trigger";
+ return trigger_;
+}
+
+void trigger_node::perlify(FILE* f)
+{
+ perl_member(f, "math", expression_.c_str());
+}
+
+#ifdef BRIDGE
+#define K_NIL 0
+#define K_OR 1
+#define K_AND 2
+#define K_EQ 3
+#define K_NE 4
+#define K_LT 5
+#define K_LE 6
+#define K_GT 7
+#define K_GE 8
+#define K_ADD 9
+#define K_SUB 10
+#define K_MUL 11
+#define K_DIV 12
+#define K_MOD 13
+#define K_POW 14
+#define K_NOT 15
+#define K_UNARY 16
+#define K_OPEN 17
+#define K_CLOSE 18
+#define K_NAME 19
+#define K_PRECEDENCE 9
+
+static std::string buf;
+
+inline void add(char* s,char* p,Boolean done)
+{
+ strcat(s,p);
+}
+
+static bool match_math(const Ast *m, sms_tree *t, const char* n)
+{
+ if (m) return m->evaluate();
+ else if (t) {
+ if (t->mtype == K_NAME) return strstr(t->name, n) != 0;
+ return match_math(0, t->left, n) || match_math(0, t->right, n);
+ }
+ return false;
+}
+
+bool trigger_node::match(const char* n)
+{
+ return match_math(get(),(sms_tree*)tree_, n);
+}
+
+static void print_math(char* s,sms_tree *m,Boolean done)
+{
+ if(!m) return;
+
+ if(m->mtype == K_NAME) {
+ add(s,m->name,done);
+ return;
+ }
+
+ switch(m->mtype) {
+
+ case K_NAME:
+ add(s,m->name,done);
+ break;
+
+ case K_OR :
+ print_math(s,m->left,done);
+ add(s,(char*)" or ",done);
+ print_math(s,m->right,done);
+ break;
+
+ case K_AND :
+ print_math(s,m->left,done);
+ add(s,(char*)" and ",done);
+ print_math(s,m->right,done);
+ break;
+
+ case K_EQ :
+ print_math(s,m->left,done);
+ add(s,(char*)" == ",done);
+ print_math(s,m->right,done);
+ break;
+
+ case K_NE :
+ print_math(s,m->left,done);
+ add(s,(char*)" != ",done);
+ print_math(s,m->right,done);
+ break;
+
+ case K_LT :
+ print_math(s,m->left,done);
+ add(s,(char*)" < ",done);
+ print_math(s,m->right,done);
+ break;
+
+ case K_LE :
+ print_math(s,m->left,done);
+ add(s,(char*)" <= ",done);
+ print_math(s,m->right,done);
+ break;
+
+ case K_GT :
+ print_math(s,m->left,done);
+ add(s,(char*)" > ",done);
+ print_math(s,m->right,done);
+ break;
+
+ case K_GE :
+ print_math(s,m->left,done);
+ add(s,(char*)" >= ",done);
+ print_math(s,m->right,done);
+ break;
+
+ case K_ADD :
+ print_math(s,m->left,done);
+ add(s,(char*)" + ",done);
+ print_math(s,m->right,done);
+ break;
+
+ case K_SUB :
+ print_math(s,m->left,done);
+ add(s,(char*)" - ",done);
+ print_math(s,m->right,done);
+ break;
+
+ case K_MUL :
+ print_math(s,m->left,done);
+ add(s,(char*)" * ",done);
+ print_math(s,m->right,done);
+ break;
+
+ case K_DIV :
+ print_math(s,m->left,done);
+ add(s,(char*)" / ",done);
+ print_math(s,m->right,done);
+ break;
+
+ case K_MOD :
+ print_math(s,m->left,done);
+ add(s,(char*)" % ",done);
+ print_math(s,m->right,done);
+ break;
+
+ case K_POW :
+ print_math(s,m->left,done);
+ add(s,(char*)" ** ",done);
+ print_math(s,m->right,done);
+ break;
+
+ case K_NOT :
+ add(s,(char*)"not ",done);
+ print_math(s,m->right,done);
+ break;
+
+ case K_UNARY:
+ add(s,(char*)"- ",done);
+ print_math(s,m->right,done);
+ break;
+
+ case K_OPEN :
+ add(s,(char*)"(",done);
+ print_math(s,m->right,done);
+ add(s,(char*)")",done);
+ break;
+
+ default :
+ add(s,(char*)"--\?\?\?--",done);
+ break;
+ }
+}
+
+extern "C" {
+#define new _new
+#define delete _delete
+#include "smsproto.h"
+}
+
+trigger_node::trigger_node(host& h,sms_node* n, char b)
+ : node(h,n,b)
+ , expression_ ()
+ , complete_ (b == 'c')
+{
+ char buf[10240] = { 0 };
+ sms_trigger* trg = (sms_trigger*) n;
+ if (!trg) return;
+ tree_ = (sms_node*) trg->math;
+ print_math(buf, (sms_tree*) trg->math, False);
+ expression_ = buf;
+ full_name_ = sms_node_full_name(n->parent);
+ full_name_ += ":trigger";
+}
+#endif
diff --git a/view/src/trigger_node.h b/view/src/trigger_node.h
new file mode 100644
index 0000000..aebb6b7
--- /dev/null
+++ b/view/src/trigger_node.h
@@ -0,0 +1,59 @@
+#ifndef TRIGGER_NODE_H
+#define TRIGGER_NODE_H
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #13 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+
+#include "node.h"
+#include "show.h"
+
+#ifndef ecf_node_
+#include "ecf_node.h"
+#endif
+
+class trigger_node : public node {
+ std::string expression_;
+ std::string full_name_;
+ bool complete_;
+
+ const AstTop* get() const;
+
+ virtual xmstring make_label_tree();
+ void drawNode(Widget w,XRectangle* r,bool);
+
+ virtual const std::string& name() const;
+ virtual const std::string& full_name() const { return full_name_; }
+ virtual const std::string& definition() const { return expression_; }
+ virtual Boolean menus() { return False; }
+ virtual Boolean selectable() { return True; }
+
+ virtual Boolean visible() const { return show::want(show::trigger); }
+
+ virtual void triggered(trigger_lister&) {}
+ virtual void triggers(trigger_lister&) {}
+ virtual void perlify(FILE*);
+
+public:
+ trigger_node(host& h,ecf_node* n);
+ ~trigger_node() {}
+
+ virtual void info(std::ostream&);
+
+#ifdef BRIDGE
+ virtual bool match(const char*);
+ trigger_node(host& h,sms_node* n, char b);
+#endif
+};
+#endif
diff --git a/view/src/trigger_panel.cc b/view/src/trigger_panel.cc
new file mode 100644
index 0000000..bf3a6e0
--- /dev/null
+++ b/view/src/trigger_panel.cc
@@ -0,0 +1,160 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "trigger_panel.h"
+#include "node.h"
+#include "graph_layout.h"
+#include "text_layout.h"
+#include "selection.h"
+#include "Hyper.h"
+#include <Xm/ToggleB.h>
+
+extern "C" {
+#include "xec.h"
+}
+
+trigger_panel::trigger_panel(panel_window& w):
+ panel(w),
+ full_(True),
+ triggers_(True),
+ triggered_(True),
+ depend_(False),
+ layout_(0)
+{
+}
+
+trigger_panel::~trigger_panel()
+{
+ delete (layout*)xec_GetUserData(tgraph_);
+ delete (layout*)xec_GetUserData(ttext_);
+}
+
+void trigger_panel::create(Widget parent, char *widget_name )
+{
+ triggers_form_c::create(parent,widget_name);
+ xec_SetUserData(tgraph_,layout_ = new graph_layout(*this,graph_));
+ xec_SetUserData(ttext_,new text_layout(*this,text_));
+}
+
+void trigger_panel::clear()
+{
+ layout_->clear();
+ hide();
+}
+
+void trigger_panel::show(node& n)
+{
+ layout_->show(n);
+}
+
+Boolean trigger_panel::enabled(node& n)
+{
+ return True;
+}
+
+Widget trigger_panel::menus(Widget bar)
+{
+ if(triggers_menu_c::xd_rootwidget() == 0)
+ triggers_menu_c::create(bar,(char*)name());
+ return triggers_menu_c::xd_rootwidget();
+}
+
+void trigger_panel::fullCB( Widget, XtPointer data)
+{
+ XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct*) data;
+ full_ = cb->set;
+ update();
+}
+
+void trigger_panel::triggeredCB( Widget, XtPointer data)
+{
+ XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct*) data;
+ triggered_ = cb->set;
+ update();
+}
+
+void trigger_panel::triggersCB( Widget, XtPointer data)
+{
+ XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct*) data;
+ triggers_ = cb->set;
+ update();
+}
+
+void trigger_panel::dependCB( Widget, XtPointer data)
+{
+ XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct*) data;
+ depend_ = cb->set;
+ clear();
+ update();
+}
+
+void trigger_panel::entryCB(Widget, XtPointer data)
+{
+ XmRowColumnCallbackStruct* cb = (XmRowColumnCallbackStruct*)data;
+
+ if(XmToggleButtonGetState(cb->widget))
+ {
+ layout *l = (layout*)xec_GetUserData(cb->widget);
+ XtUnmanageChild(layout_->layout_widget());
+ XtManageChild(l->layout_widget());
+ layout_ = l;
+ if(get_node())
+ l->show(*get_node());
+ else
+ l->clear();
+ }
+ hide();
+}
+
+void trigger_panel::hyperCB(Widget w,XtPointer data)
+{
+ panel::hyper(w,data);
+}
+
+void trigger_panel::reachCB(Widget w,XtPointer data)
+{
+ XmToggleButtonSetState(dependencies_button_,True,False);
+ XmToggleButtonSetState(triggers_button_,True,False);
+ XmToggleButtonSetState(triggered_button_,True,False);
+
+ depend_ = triggers_ = triggered_ = true;
+ clear();
+ layout_->reach(get_node(),selection::current_node());
+}
+
+void trigger_panel::linkCB(Widget w,XtPointer data)
+{
+ XmRowColumnCallbackStruct* cb = (XmRowColumnCallbackStruct*)data;
+ node* n = (node*)xec_GetUserData(cb->widget);
+ layout_->selectNode(n);
+}
+
+void trigger_panel::showDependWindow()
+{
+ depend::raise(widget());
+}
+
+Widget trigger_panel::dependHyperText()
+{
+ depend::make(widget());
+ return depend::hyper_;
+}
+
+void trigger_panel::hideDependWindow()
+{
+ depend::hide();
+}
+
+// static panel_maker<trigger_panel> maker(PANEL_TRIGGER);
diff --git a/view/src/trigger_panel.h b/view/src/trigger_panel.h
new file mode 100644
index 0000000..373ceb9
--- /dev/null
+++ b/view/src/trigger_panel.h
@@ -0,0 +1,85 @@
+#ifndef trigger_panel_H
+#define trigger_panel_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "uitriggers.h"
+
+#ifndef panel_H
+#include "panel.h"
+#endif
+
+#ifndef node_window_H
+#include "node_window.h"
+#endif
+
+#ifndef depend_H
+#include "depend.h"
+#endif
+
+class layout;
+
+class trigger_panel : public panel,
+ public depend,
+ public triggers_form_c ,
+ public triggers_menu_c {
+public:
+ trigger_panel(panel_window&);
+
+ ~trigger_panel(); // Change to virtual if base class
+
+ virtual void create (Widget parent, char *widget_name = NULL);
+ virtual void show(node&);
+ virtual Boolean enabled(node&);
+ virtual void clear();
+ virtual const char* name() const { return "Triggers"; }
+ Widget menus(Widget);
+ virtual Widget widget() { return triggers_form_c::xd_rootwidget(); }
+
+ Boolean triggers() { return triggers_; }
+ Boolean triggered() { return triggered_; }
+ Boolean extended() { return depend_; }
+
+ Widget infoMenu() { return info_menu_; }
+ Widget linkMenu() { return link_menu_; }
+
+ void showDependWindow();
+ void hideDependWindow();
+ Widget dependHyperText();
+
+private:
+
+ trigger_panel(const trigger_panel&);
+ trigger_panel& operator=(const trigger_panel&);
+
+ Boolean full_;
+ Boolean triggers_;
+ Boolean triggered_;
+ Boolean depend_;
+ layout* layout_;
+
+ virtual void fullCB( Widget, XtPointer );
+ virtual void triggeredCB( Widget, XtPointer );
+ virtual void triggersCB( Widget, XtPointer );
+ virtual void dependCB( Widget, XtPointer );
+ virtual void entryCB( Widget, XtPointer );
+ virtual void hyperCB( Widget, XtPointer );
+ virtual void reachCB( Widget, XtPointer );
+
+ virtual void linkCB( Widget, XtPointer );
+};
+
+inline void destroy(trigger_panel**) {}
+#endif
diff --git a/view/src/url.cc b/view/src/url.cc
new file mode 100644
index 0000000..5dbcd59
--- /dev/null
+++ b/view/src/url.cc
@@ -0,0 +1,240 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "url.h"
+#include "re.h"
+#include "tmp_file.h"
+#include "str.h"
+#include "node.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+url::url(int soc):
+ soc_(soc),
+ code_(200),
+ in_(fdopen(soc_,"r")),
+ out_(fdopen(soc_,"w")),
+ tmp_(tmpfile())
+{
+ char line[1024];
+ method_[0] = what_[0] = 0;
+
+ while(fgets(line,sizeof(line),in_))
+ {
+ if(method_[0] == 0)
+ sscanf(line,"%s %s",method_,what_);
+ printf("url->%s<-",line);
+ if(strlen(line) == 2) break;
+ }
+
+ char *p = what_;
+ char *s = what_;
+
+ while(*s)
+ {
+ if(*s == '+')
+ {
+ *p = ' ';
+ }
+ else if(*s == '%')
+ {
+ char h = s[1]; if(!h) break;
+ char l = s[2]; if(!l) break;
+
+ unsigned int a = (h>='A')?(h-'A'+10):(h-'0');
+ unsigned int b = (l>='A')?(l-'A'+10):(l-'0');
+
+ *p = char(a * 16 + b);
+ s += 2;
+ }
+ else *p = *s;
+
+ p++;
+ s++;
+ }
+ *p = 0;
+}
+
+void url::process(node* n)
+{
+ if (! node::is_json) {
+
+ fprintf(out_,"\nHTTP/1.0 %d Document follows\r\n",code_);
+ fprintf(out_,"MIME-Version: 1.0\r\n");
+ fprintf(out_,"Content-Type: text/html\r\n");
+ fprintf(out_,"\r\n");
+
+ if(n) {
+ n->as_perl(out_,true);
+ } else
+ fprintf(out_,"bless({},'ecflow::node::error')");
+ } else {
+ if (n) {
+ n->as_perl(out_,true);
+ } else
+ fprintf(out_,"{ }");
+ }
+
+ fflush(out_);
+}
+
+url::~url()
+{
+
+ fflush(tmp_);
+ long len = ftell(tmp_);
+ rewind(tmp_);
+
+ if (!node::is_json) {
+ fprintf(out_,"\n");
+ fprintf(out_,"HTTP/1.0 %d Document follows\r\n",code_);
+ fprintf(out_,"MIME-Version: 1.0\r\n");
+ fprintf(out_,"Content-Type: text/html\r\n");
+ fprintf(out_,"Content-Length: %ld\r\n",len);
+ fprintf(out_,"\r\n");
+ }
+ copy(tmp_,out_);
+
+ fflush(out_);
+
+ if(in_) fclose(in_);
+ if(out_) fclose(out_);
+ if(tmp_) fclose(tmp_);
+}
+
+
+void url::add(tmp_file& t,text_translator& trans)
+{
+ FILE* f = fopen(t.c_str(),"r");
+ if(f)
+ {
+ char line[1024];
+ while(fgets(line,sizeof(line),f))
+ trans.save(tmp_,line);
+ fclose(f);
+ }
+ else {
+ fprintf(tmp_,"Cannot open %s\n",t.c_str());
+ }
+}
+
+void url::add(tmp_file& t)
+{
+ url_translator trans;
+ add(t,trans);
+}
+
+void url::copy(FILE* in,FILE* out)
+{
+ char line[1024];
+ long len;
+
+ while( (len = fread(line,1,sizeof(line),in)) > 0)
+ fwrite(line,1,len,out);
+}
+
+void url_translator::save(FILE* f,const char* p)
+{
+ while(*p)
+ {
+ switch(*p)
+ {
+ /* case '\n': fprintf(f,"<br>\n"); break; */
+
+ case '<': fprintf(f,"<"); break;
+ case '>': fprintf(f,">"); break;
+ case '&': fprintf(f,"&"); break;
+
+ default: fputc(*p,f); break;
+ }
+
+ p++;
+
+ }
+}
+
+class scan_translator: public text_translator {
+ re re_;
+ node* n_;
+ url& u_;
+public:
+ scan_translator(node* n,url& u);
+ ~scan_translator();
+
+ virtual void save(FILE*,const char *line);
+};
+
+scan_translator::scan_translator(node* n,url& u):
+ re_("<!-- wcdp ([^ ]*)$0 -->"),
+ n_(n),
+ u_(u)
+{
+}
+
+scan_translator::~scan_translator()
+{
+}
+
+void scan_translator::save(FILE* f,const char *line)
+{
+ char val[1024];
+ char buf[1024];
+
+ strcpy(buf,line);
+ char *p = buf;
+ char *q;
+
+ while((q = re_.match(p,val)))
+ {
+ char *loc = re_.loc();
+ char w = *loc;
+ *loc = 0;
+ fprintf(f,"%s",buf);
+ *loc = w;
+
+ // We need a factory here
+
+ if(strcmp(val,"title") == 0) n_->html_title(u_,u_);
+ if(strcmp(val,"kids") == 0) n_->html_kids(u_,u_);
+ if(strcmp(val,"output") == 0) n_->html_output(u_,u_);
+ if(strcmp(val,"script") == 0) n_->html_script(u_,u_);
+ if(strcmp(val,"name") == 0) n_->html_name(u_,u_);
+ if(strcmp(val,"why") == 0) n_->html_why(u_,u_);
+
+
+ p = q;
+ }
+ fprintf(f,"%s",p);
+}
+
+void url::scan(node* n)
+{
+ tmp_file page(n->html_page(*this),false);
+ scan_translator s(n,*this);
+ add(page,s);
+}
+
+
+/*
+perl -e'print q|{"foo":"XX","bar":1234567890000000000000000}|' |\
+ json_pp -f json -t dumper -json_opt pretty,utf8,allow_bignum
+
+wget http://127.0.0.1:8081/lhost/elaw_37r3
+cat elaw_37r3 | grep -v -E '(HTTP|MIME|Content-)' | json_pp -f eval -t json -json_opt pretty,utf8,allow_bignum
+
+/tmp/map/work/PythonWeb.org/examples/ecflow
+
+*/
diff --git a/view/src/url.h b/view/src/url.h
new file mode 100644
index 0000000..16033f2
--- /dev/null
+++ b/view/src/url.h
@@ -0,0 +1,142 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#ifndef url_H
+#define url_H
+
+#include <stdio.h>
+class tmp_file;
+class node;
+
+class text_translator {
+public:
+ virtual ~text_translator() {}
+ virtual void save(FILE*,const char*) = 0;
+};
+
+class url_translator: public text_translator {
+public:
+ virtual void save(FILE*,const char*);
+};
+
+class url {
+public:
+
+// -- Exceptions
+ // None
+
+// -- Contructors
+
+ url(int);
+
+// -- Destructor
+
+ ~url(); // Change to virtual if base class
+
+// -- Convertors
+ // None
+
+// -- Operators
+
+ operator FILE*() { return tmp_; }
+
+// -- Methods
+
+ void process(node*);
+ void scan(node*);
+
+ const char* method() const { return method_; }
+ const char* what() const { return what_; }
+
+ void not_found() { code_ = 404; }
+
+ void add(tmp_file&);
+ void add(tmp_file&,text_translator&);
+ void copy(FILE*,FILE*);
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+ // Uncomment for persistent, remove otherwise
+ // static os_typespec* get_os_typespec();
+
+protected:
+
+// -- Members
+ // None
+
+// -- Methods
+
+ // void print(ostream&) const; // Change to virtual if base class
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+private:
+
+// No copy allowed
+
+ url(const url&);
+ url& operator=(const url&);
+
+// -- Members
+
+ char method_[1024];
+ char what_[1024];
+ int soc_;
+ int code_;
+ FILE* in_;
+ FILE* out_;
+ FILE* tmp_;
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+// -- Friends
+
+ //friend ostream& operator<<(ostream& s,const url& p)
+ // { p.print(s); return s; }
+
+};
+
+inline void destroy(url**) {}
+
+// If persistent, uncomment, otherwise remove
+//#ifdef _ODI_OSSG_
+//OS_MARK_SCHEMA_TYPE(url);
+//#endif
+
+#endif
diff --git a/view/src/user_prefs.cc b/view/src/user_prefs.cc
new file mode 100644
index 0000000..6cf50df
--- /dev/null
+++ b/view/src/user_prefs.cc
@@ -0,0 +1,24 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "user_prefs.h"
+
+void user_prefs::create(Widget w,char*)
+{
+ user_form_c::create(w);
+ prefs::setup(w);
+}
+
+// static user_prefs hp;
diff --git a/view/src/user_prefs.h b/view/src/user_prefs.h
new file mode 100644
index 0000000..05cb435
--- /dev/null
+++ b/view/src/user_prefs.h
@@ -0,0 +1,49 @@
+#ifndef user_prefs_H
+#define user_prefs_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#ifndef prefs_H
+#include "prefs.h"
+#endif
+
+#ifndef uiuser
+#include "uiuser.h"
+#endif
+
+
+class user_prefs : public prefs, public user_form_c {
+public:
+
+ user_prefs() {}
+
+ ~user_prefs() {}
+
+ virtual Widget widget() { return _xd_rootwidget; }
+
+private:
+
+ user_prefs(const user_prefs&);
+ user_prefs& operator=(const user_prefs&);
+
+ virtual void changedCB( Widget w, XtPointer ) { pref_editor::changed(w); }
+ virtual void useCB( Widget w, XtPointer ) { pref_editor::use(w); }
+
+ virtual void create(Widget w,char*);
+};
+
+inline void destroy(user_prefs**) {}
+#endif
diff --git a/view/src/users.cc b/view/src/users.cc
new file mode 100644
index 0000000..9db9917
--- /dev/null
+++ b/view/src/users.cc
@@ -0,0 +1,62 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "users.h"
+#include "node.h"
+#include "host.h"
+#include "ecflowview.h"
+#include <Xm/Label.h>
+#include <Xm/Text.h>
+#include <Xm/List.h>
+extern "C" {
+#include "xec.h"
+}
+
+users::users(panel_window& w):
+ panel(w)
+{
+}
+
+users::~users()
+{
+}
+
+void users::create (Widget parent, char *widget_name )
+{
+ users_form_c::create(parent,widget_name);
+}
+
+void users::clear()
+{
+ XmListDeleteAllItems(list_);
+}
+
+void users::show(node& n)
+{
+ XmListDeleteAllItems(list_);
+}
+
+Boolean users::enabled(node& n)
+{
+ return False;
+ // return n.type() == NODE_SUPER;
+}
+
+
+void users::sendCB( Widget, XtPointer )
+{
+}
+
+// static panel_maker<users> maker(PANEL_USERS);
diff --git a/view/src/users.h b/view/src/users.h
new file mode 100644
index 0000000..70ff9c3
--- /dev/null
+++ b/view/src/users.h
@@ -0,0 +1,136 @@
+#ifndef users_H
+#define users_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+// Headers
+// #ifndef machine_H
+// #include <machine.h>
+// #endif
+
+// Forward declarations
+
+// class ostream;
+// typedef class _Pvts os_typespec; // Remove if not persistant
+
+
+#include "uiusers.h"
+
+#ifndef panel_H
+#include "panel.h"
+#endif
+
+//
+
+class users : public panel, public users_form_c {
+public:
+
+// -- Exceptions
+ // None
+
+// -- Contructors
+
+ users(panel_window&);
+
+// -- Destructor
+
+ ~users(); // Change to virtual if base class
+
+// -- Convertors
+ // None
+
+// -- Operators
+ // None
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+
+ virtual const char* name() const { return "Users"; }
+ virtual void show(node&);
+ virtual void clear();
+ virtual Boolean enabled(node&);
+ virtual Widget widget() { return users_form_c::xd_rootwidget(); }
+
+ virtual void create (Widget parent, char *widget_name = NULL);
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+ // Uncomment for persistent, remove otherwise
+ // static os_typespec* get_os_typespec();
+
+protected:
+
+// -- Members
+ // None
+
+// -- Methods
+
+ // void print(ostream&) const; // Change to virtual if base class
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+private:
+
+// No copy allowed
+
+ users(const users&);
+ users& operator=(const users&);
+
+// -- Members
+
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+
+ virtual void sendCB( Widget, XtPointer );
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+// -- Friends
+
+ //friend ostream& operator<<(ostream& s,const users& p)
+ // { p.print(s); return s; }
+
+};
+
+inline void destroy(users**) {}
+
+// If persistent, uncomment, otherwise remove
+//#ifdef _ODI_OSSG_
+//OS_MARK_SCHEMA_TYPE(users);
+//#endif
+
+
+#endif
diff --git a/view/src/variable_node.cc b/view/src/variable_node.cc
new file mode 100644
index 0000000..599a9f6
--- /dev/null
+++ b/view/src/variable_node.cc
@@ -0,0 +1,135 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #17 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "variable_node.h"
+
+#ifndef ecf_node_
+#include "ecf_node.h"
+#endif
+struct ecf_variable {
+ int type;
+ char *name;
+ struct ecf_variable *next;
+ int status;
+ int nid;
+ int act_no;
+ class ecf_node *parent;
+ void* user_ptr;
+ int user_int;
+ class ecf_node *kids;
+ char *value;
+};
+typedef struct ecf_variable ecf_variable;
+
+const xmstring& variable_node::labelTree()
+{
+ labelTree_ = make_label_tree();
+ return labelTree_;
+}
+
+#ifdef BRIDGE
+variable_node::variable_node(host& h,sms_node* n, char b)
+ : node(h,n,b)
+ , generated_(b == 'g')
+{}
+#endif
+
+variable_node::variable_node(host& h,ecf_node* n)
+ : node(h,n)
+ , generated_(false)
+{
+ generated_ = n ? (n->kind() == 'g') : false;
+}
+
+std::string variable_node::get_var(bool substitute) {
+#ifdef BRIDGE
+ if (tree_) {
+ ecf_variable *var = (ecf_variable*) tree_;
+ if (var) return var->value;
+ } else
+#endif
+ if (parent())
+ if (parent()->__node__())
+ return parent()->__node__()->get_var(name(),
+ generated_,
+ substitute);
+ return ecf_node::none();
+}
+
+xmstring variable_node::make_label_tree()
+{
+ const std::string& v = get_var();
+ return xmstring(name().c_str()) + xmstring("=") + xmstring(v.c_str());
+}
+
+void variable_node::drawNode(Widget w,XRectangle *r,bool)
+{
+ XmStringDraw(XtDisplay(w),XtWindow(w),
+ smallfont(),
+ labelTree(),
+ generated_?blueGC():blackGC(),
+ r->x+2,
+ r->y+2,
+ r->width,
+ XmALIGNMENT_BEGINNING, XmSTRING_DIRECTION_L_TO_R, NULL);
+ /* shadow(w,r); */
+}
+
+Boolean variable_node::visible() const
+{
+ return
+ generated_ ?
+ show::want(show::genvar) :
+ show::want(show::variable);
+}
+
+void variable_node::info(std::ostream&f)
+{
+ if (generated_)
+ f << " # ( " << name() << "\t: " << get_var() + ")\n";
+ else
+ f << " edit " << name() << "\t" << get_var() << "\n";
+}
+
+bool variable_node::match(const char* p)
+{
+ return (strstr(name().c_str(),p) != 0)
+ || (strstr(get_var().c_str(),p) != 0);
+}
+
+void variable_node::edit(node_editor& e)
+{
+ e.set("name", str(name()));
+ e.set("value",str(get_var()));
+}
+
+void variable_node::apply(node_editor& e)
+{
+ str value;
+ e.get("value",value);
+ const char* name = this->name().c_str();
+ const char* kind = "add";
+ for (node* n = parent()->kids(); n; n = n->next())
+ if (n->type() == NODE_VARIABLE && n->name() == name)
+ { kind = "change"; break; }
+ serv().command(clientName,"--alter", kind, "variable",
+ name, value.c_str(), parent()->full_name().c_str(),
+ NULL);
+}
+
+void variable_node::perlify(FILE* f)
+{
+ perl_member(f,"value",get_var().c_str());
+}
diff --git a/view/src/variable_node.h b/view/src/variable_node.h
new file mode 100644
index 0000000..6ecce29
--- /dev/null
+++ b/view/src/variable_node.h
@@ -0,0 +1,54 @@
+#ifndef VARIABLE_NODE
+#define VARIABLE_NODE
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #12 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+
+#include "node.h"
+#include "show.h"
+#include "host.h"
+#include "node_editor.h"
+
+class variable_node : public node {
+
+ bool generated_;
+
+ virtual void info(std::ostream&);
+ virtual const xmstring& labelTree();
+ virtual xmstring make_label_tree();
+ virtual void drawNode(Widget w,XRectangle *r,bool);
+
+ virtual Boolean visible() const;
+ virtual bool match(const char*);
+
+ virtual void edit(node_editor&);
+ virtual void apply(node_editor&);
+
+ virtual void triggered(trigger_lister&) {}
+ virtual void triggers(trigger_lister&) {}
+
+ virtual void perlify(FILE*);
+
+public:
+ variable_node(host& h,ecf_node* n);
+ Boolean isGenVariable(const char *name) { return generated_; }
+ std::string get_var(bool subsitute=false);
+#ifdef BRIDGE
+ variable_node(host& h,sms_node* n, char b);
+#endif
+
+};
+
+#endif
diff --git a/view/src/variables.cc b/view/src/variables.cc
new file mode 100644
index 0000000..551e156
--- /dev/null
+++ b/view/src/variables.cc
@@ -0,0 +1,442 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #19 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "variables.h"
+#include "variable_node.h"
+#include "node.h"
+#include "host.h"
+#include "ecf_node.h"
+
+#include <Xm/List.h>
+#include <Xm/Text.h>
+#include "confirm.h"
+
+extern "C" {
+#include "xec.h"
+}
+
+variables::variables( panel_window& w )
+ : panel(w), loading_(false)
+{
+}
+
+variables::~variables()
+{
+ clear();
+}
+
+void variables::clear()
+{
+ loading_ = true;
+ XmListDeleteAllItems(list_);
+ XtSetSensitive(edit_, False);
+ XmTextSetString(name_, (char*) "");
+ XmTextSetString(value_, (char*) "");
+ loading_ = false;
+}
+
+struct cless_than {
+ inline bool operator()( const Variable& v1, const Variable& v2 )
+ {
+ return (v1.name() < v2.name());
+ }
+};
+
+void variables::show( node& n )
+{
+ loading_ = true;
+
+ int varsize = 0;
+ int valsize = 0;
+ char fmt1[256];
+ char fmt2[256];
+ char fmt3[256];
+ node* m = &n;
+
+ XtSetSensitive(edit_, True);
+ XmListDeleteAllItems(list_);
+ std::vector<Variable> gvar;
+ std::vector<Variable>::const_iterator it, gvar_end;
+ ecf_node* prox;
+
+ while ( m != 0 ) {
+ /* for (node* run = m->kids(); run; run = run->next())
+ if (run->type() == NODE_VARIABLE) {
+ varsize = std::max(varsize, (int) run->name().size());
+ valsize = std::max(valsize, (int) ((variable_node*) run)->get_var().size());
+ } */
+ {
+ prox = m->__node__();
+ if (!prox) return;
+
+ Defs* defs = 0;
+ Node* ecf = 0;
+ if (dynamic_cast<ecf_concrete_node<Node>*>(prox)) {
+ ecf = dynamic_cast<ecf_concrete_node<Node>*>(prox)->get();
+ }
+ else if (dynamic_cast<ecf_concrete_node<Task>*>(prox)) {
+ ecf = dynamic_cast<ecf_concrete_node<Task>*>(prox)->get();
+ }
+ else if (dynamic_cast<ecf_concrete_node<Family>*>(prox)) {
+ ecf = dynamic_cast<ecf_concrete_node<Family>*>(prox)->get();
+ }
+ else if (dynamic_cast<ecf_concrete_node<Suite>*>(prox)) {
+ ecf = dynamic_cast<ecf_concrete_node<Suite>*>(prox)->get();
+ }
+ else if (dynamic_cast<ecf_concrete_node<Defs>*>(prox)) {
+ defs = dynamic_cast<ecf_concrete_node<Defs>*>(prox)->get();
+ }
+ if (!ecf && !defs) {
+ break;
+ }
+
+ if (ecf ) {
+ gvar.clear();
+ ecf->gen_variables(gvar);
+ for(it = gvar.begin(); it != gvar.end(); ++it) {
+ varsize = std::max(varsize, (int) (*it).name().size());
+ valsize = std::max(valsize, (int) (*it).theValue().size());
+ }
+
+ gvar = ecf->variables();
+ for(it = gvar.begin(); it != gvar.end(); ++it) {
+ varsize = std::max(varsize, (int) (*it).name().size());
+ valsize = std::max(valsize, (int) (*it).theValue().size());
+ }
+ }
+ if (defs) {
+ const std::vector<Variable>& gvar = defs->server().user_variables();
+ for(it = gvar.begin(); it != gvar.end(); ++it) {
+ varsize = std::max(varsize, (int) (*it).name().size());
+ valsize = std::max(valsize, (int) (*it).theValue().size());
+ }
+ const std::vector<Variable>& var = defs->server().server_variables();
+ for(it = var.begin(); it != var.end(); ++it) {
+ varsize = std::max(varsize, (int) (*it).name().size());
+ valsize = std::max(valsize, (int) (*it).theValue().size());
+ }
+ }
+ }
+ m = m->parent();
+ }
+
+ if (!varsize) return;
+ snprintf(fmt1, 256, "(%%-%ds = %%-%ds)", varsize, valsize);
+ snprintf(fmt2, 256, " %%-%ds = %%-%ds ", varsize, valsize);
+ snprintf(fmt3, 256, "[%%-%ds = %%-%ds]", varsize, valsize);
+ {
+ std::vector<std::string> shown;
+ char buffer[1024];
+ node *m = &n;
+ while ( m != 0 ) {
+ snprintf(buffer, 1024, "Variables defined for %s %s", m->type_name(), m->name().c_str());
+ xec_AddFontListItem(list_, buffer, 1);
+ {
+ prox = m->__node__();
+ if (!prox) break;
+
+ Defs* defs = 0;
+ Node* ecf = 0;
+ if (dynamic_cast<ecf_concrete_node<Node>*>(prox)) {
+ ecf = dynamic_cast<ecf_concrete_node<Node>*>(prox)->get();
+ }
+ else if (dynamic_cast<ecf_concrete_node<Task>*>(prox)) {
+ ecf = dynamic_cast<ecf_concrete_node<Task>*>(prox)->get();
+ }
+ else if (dynamic_cast<ecf_concrete_node<Family>*>(prox)) {
+ ecf = dynamic_cast<ecf_concrete_node<Family>*>(prox)->get();
+ }
+ else if (dynamic_cast<ecf_concrete_node<Suite>*>(prox)) {
+ ecf = dynamic_cast<ecf_concrete_node<Suite>*>(prox)->get();
+ }
+ else if (dynamic_cast<ecf_concrete_node<Defs>*>(prox)) {
+ defs = dynamic_cast<ecf_concrete_node<Defs>*>(prox)->get();
+ }
+ if (!ecf && !defs) break;
+
+
+ if (ecf) {
+ gvar.clear();
+ gvar = ecf->variables();
+ std::sort(gvar.begin(), gvar.end(), cless_than());
+ gvar_end = gvar.end();
+ for(it = gvar.begin(); it != gvar_end; ++it) {
+ const std::string& name = (*it).name();
+ if (std::find(shown.begin(), shown.end(), name) == shown.end()) {
+ snprintf(buffer, 1024, fmt2, name.c_str(), (*it).theValue().c_str());
+ xec_AddFontListItem(list_, buffer, 0);
+ shown.push_back(name); }
+ }
+
+ ecf->gen_variables(gvar);
+ for(it = gvar.begin(); it != gvar.end(); ++it) {
+ if ((*it).name() == "" ||
+ *it == Variable::EMPTY() ||
+ (*it).name() == "ECF_PASS")
+ continue;
+ const std::string& name = (*it).name();
+ if (std::find(shown.begin(), shown.end(), name) == shown.end()) {
+ snprintf(buffer, 1024, fmt1, name.c_str(), (*it).theValue().c_str());
+ xec_AddFontListItem(list_, buffer, 0);
+ shown.push_back(name); }
+ }
+ }
+
+ if (defs) {
+ gvar = defs->server().user_variables();
+ std::sort(gvar.begin(), gvar.end(), cless_than());
+ for(it = gvar.begin(); it != gvar.end(); ++it) {
+ const std::string& name = (*it).name();
+ if (std::find(shown.begin(), shown.end(), name) == shown.end()) {
+ snprintf(buffer, 1024, fmt2, name.c_str(), (*it).theValue().c_str());
+ xec_AddFontListItem(list_, buffer, 0);
+ shown.push_back(name); }
+ }
+
+ gvar = defs->server().server_variables();
+ for(it = gvar.begin(); it != gvar.end(); ++it) {
+ const std::string& name = (*it).name();
+ if (std::find(shown.begin(), shown.end(), name) == shown.end()) {
+ bool readOnly = name=="ECF_NODE" || name=="ECF_PORT" ||
+ name=="ECF_LISTS" || // security ???
+ name=="ECF_PID" || name=="ECF_VERSION";
+ snprintf(buffer, 1024, readOnly ? fmt3 : fmt1,
+ name.c_str(), (*it).theValue().c_str());
+ xec_AddFontListItem(list_, buffer, 0);
+ shown.push_back(name); }
+ }
+ }
+ }
+ m = m->parent();
+ }
+ }
+ loading_ = false;
+}
+
+Boolean variables::enabled( node& n )
+{
+ int type = n.type();
+ if (type == NODE_SUPER || type == NODE_FAMILY || type == NODE_TASK
+ || type == NODE_ALIAS)
+ return True;
+ for(node* run = n.kids(); run; run = run->next())
+ if (run->type() == NODE_VARIABLE)
+ return True;
+ return False;
+}
+
+void variables::browseCB( Widget w, XtPointer data )
+{
+ XmListCallbackStruct *cb = (XmListCallbackStruct *) data;
+ char *p = xec_GetString(cb->item);
+ if (*p == 'V') {
+ XmTextSetString(name_, (char*) "");
+ XmTextSetString(value_, (char*) "");
+ }
+ else {
+ char *q = p + 1;
+ char *r = p + 1;
+
+ while ( *r && *r != '=' )
+ r++;
+
+ *r = 0;
+
+ while ( *q && q[strlen(q) - 1] == ' ' )
+ q[strlen(q) - 1] = 0;
+
+ r += 2;
+
+ if (*p == '(') r[strlen(r) - 1] = 0;
+ if (*p == '[') r[strlen(r) - 1] = 0;
+
+ while ( *r && r[strlen(r) - 1] == ' ' )
+ r[strlen(r) - 1] = 0;
+
+ XmTextSetString(name_, q);
+ XmTextSetString(value_, r);
+ }
+ nameCB(w, data);
+ valueCB(w, data);
+
+ XtFree(p);
+}
+
+/* from: http://www.ist.co.uk/motif/books/vol6A/ch-13.fm.html */
+/* find the item in the list that matches the specified pattern */
+#include <Xm/TextF.h>
+#define _REGEX_RE_COMP
+#include <regex.h>
+void search_item( Widget text_w, XtPointer client_data, XtPointer call_data, Widget nam,
+ Widget val )
+{
+ Widget list_w = (Widget) client_data;
+ char *exp, *text, *newtext = XmTextFieldGetString(text_w);
+ XmString *strlist, *selectlist = NULL;
+ int cnt, j = 0;
+
+ if (!newtext || !*newtext) {
+ XtFree(newtext);
+ return;
+ }
+
+ if ((exp = re_comp(newtext))) {
+ printf("Error with re_comp(%s): %s\n", newtext, exp);
+ XtFree(newtext);
+ return;
+ }
+
+ XtVaGetValues(list_w, XmNitemCount, &cnt, XmNitems, &strlist, NULL);
+
+ while ( cnt-- ) {
+ if (!(text = (char *) xec_GetString(strlist[cnt]))) break;
+
+ if (re_exec(text) > 0) {
+ selectlist = (XmString *) XtRealloc((char *) selectlist, (j + 1) * (sizeof(XmString *)));
+ selectlist[j++] = XmStringCopy(strlist[cnt]);
+
+ char *p = xec_GetString(strlist[cnt]);
+ char *q = p + 1;
+ char *r = p + 1;
+ while ( *r && *r != '=' )
+ r++;
+ *r = 0;
+ while ( *q && q[strlen(q) - 1] == ' ' )
+ q[strlen(q) - 1] = 0;
+ r += 2;
+ if (*p == '(') r[strlen(r) - 1] = 0;
+ if (*p == '[') r[strlen(r) - 1] = 0; // readOnly variables
+ while ( *r && r[strlen(r) - 1] == ' ' )
+ r[strlen(r) - 1] = 0;
+ XmTextSetString(nam, q);
+ XmTextSetString(val, r);
+ *r = '=';
+ XtFree(p);
+ }
+ XtFree(text);
+ }
+ free(exp);
+ XtFree(newtext);
+
+ XtVaSetValues(list_w, XmNselectedItems, selectlist, XmNselectedItemCount, j, NULL);
+
+ while ( j-- )
+ XmStringFree(selectlist[j]);
+ // XmTextFieldSetString (text_w, "");
+}
+/* */
+
+void variables::findCB( Widget, XtPointer )
+{
+ char *name = XmTextGetString(name_);
+ search_item(name_, list_, NULL, name_, value_);
+ XtFree(name);
+}
+
+void variables::deleteCB( Widget, XtPointer )
+{
+ if (get_node()) {
+ char *name = XmTextGetString(name_);
+ const char* fullname = get_node()->full_name().c_str();
+ if (confirm::ask(False, "Delete variable %s for node %s", name, fullname)) {
+ // repeat get_node while suite may have been cancelled by another
+ // while answering this question
+ if (get_node()) {
+ if (get_node()->__node__()) /* ecflow */
+ get_node()->serv().command(clientName, "--alter", "delete", "variable", name,
+ fullname, NULL);
+ else
+ get_node()->serv().command("alter", "-vr", fullname, name, NULL);
+ }
+ }
+ XtFree(name);
+ update();
+ }
+ else
+ clear();
+}
+
+void variables::setCB( Widget, XtPointer )
+{
+ if (get_node()) {
+
+ char *name = XmTextGetString(name_);
+ char *value = XmTextGetString(value_);
+ Boolean ok = True;
+ node* n = get_node()->variableOwner(name);
+
+ if (n != 0 && n != get_node()) {
+ ok = confirm::ask(True, "This variable is already defined in the %s %s\n"
+ "A new variable will be created for the selected node\n"
+ "and hide the previous one\n"
+ "Do you want to proceed?",
+ n->type_name(), n->full_name().c_str());
+ }
+
+ if (n != 0 && n->isGenVariable(name) && ok) {
+ ok = confirm::ask(True, "This variable is a generated variable\n"
+ "Do you want to proceed?");
+ }
+
+ if (ok) {
+ bool add = true;
+ if (get_node()->__node__()) {
+ add = get_node()->__node__()->variable(name) == ecf_node::none();
+ get_node()->serv().command(clientName, "--alter", add ? "add" : "change", "variable",
+ name, value, get_node()->full_name().c_str(), NULL);
+ } else
+ get_node()->serv().command("alter", "-v", get_node()->full_name().c_str(), name, value,
+ NULL);
+ if (add) update();
+ }
+ XtFree(name);
+ XtFree(value);
+ }
+ else
+ clear();
+}
+
+void variables::nameCB( Widget, XtPointer )
+{
+ if (loading_) return;
+
+ char *p = XmTextGetString(name_);
+ if (get_node()) {
+ node *n = get_node()->variableOwner(p);
+ XtSetSensitive(delete_, n != 0 && (!n->isGenVariable(p) || n != get_node()));
+ }
+ else {
+ clear();
+ }
+ XtFree(p);
+}
+
+void variables::valueCB( Widget, XtPointer )
+{
+ if (loading_) return;
+
+ char *p = XmTextGetString(name_);
+ char *v = XmTextGetString(value_);
+ if (get_node()) {
+ const char *x = get_node()->variable(p).c_str();
+ XtSetSensitive(set_, (x == 0 || strcmp(x, v) != 0) && v[0] != 0);
+ }
+ else {
+ clear();
+ }
+ XtFree(v);
+ XtFree(p);
+}
+
diff --git a/view/src/variables.h b/view/src/variables.h
new file mode 100644
index 0000000..74e2bf9
--- /dev/null
+++ b/view/src/variables.h
@@ -0,0 +1,58 @@
+#ifndef variables_H
+#define variables_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "uivariables.h"
+
+#ifndef panel_H
+#include "panel.h"
+#endif
+
+//
+
+class variables : public panel, public variables_form_c {
+public:
+
+ variables(panel_window&);
+
+ ~variables(); // Change to virtual if base class
+
+ virtual const char* name() const { return "Variables"; }
+ virtual void show(node&);
+ virtual Boolean enabled(node&);
+ virtual void clear();
+ virtual Widget widget() { return xd_rootwidget(); }
+
+private:
+
+ variables(const variables&);
+ variables& operator=(const variables&);
+
+ bool loading_;
+
+ virtual void browseCB( Widget, XtPointer ) ;
+ virtual void deleteCB( Widget, XtPointer ) ;
+ virtual void nameCB( Widget, XtPointer ) ;
+ virtual void setCB( Widget, XtPointer ) ;
+ virtual void valueCB( Widget, XtPointer ) ;
+ virtual void findCB( Widget, XtPointer ) ;
+
+};
+
+inline void destroy(variables**) {}
+
+#endif
diff --git a/view/src/viewer.cc b/view/src/viewer.cc
new file mode 100644
index 0000000..c8c9b39
--- /dev/null
+++ b/view/src/viewer.cc
@@ -0,0 +1,57 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#ifndef viewer_H
+#include "viewer.h"
+#endif
+
+#ifndef gui_H
+#include "gui.h"
+#endif
+
+
+viewer::viewer()
+{
+}
+
+bool viewer::show(const char* cmd)
+{
+ FILE *f = popen(cmd,"r");
+ if(!f) {
+ gui::syserr(cmd);
+ return false;
+ }
+ start(f);
+ return true;
+}
+
+void viewer::ready(const char* line)
+{
+ gui::error("%s",line);
+}
+
+void viewer::done(FILE* f)
+{
+ end(pclose(f));
+}
+
+void viewer::end(bool)
+{
+ delete this;
+}
+
+viewer::~viewer()
+{
+}
diff --git a/view/src/viewer.h b/view/src/viewer.h
new file mode 100644
index 0000000..d679803
--- /dev/null
+++ b/view/src/viewer.h
@@ -0,0 +1,134 @@
+#ifndef viewer_H
+#define viewer_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#ifdef NO_BOOL
+#include "bool.h"
+#endif
+
+#ifndef input_H
+#include "input.h"
+#endif
+
+
+
+// Headers
+// #ifndef machine_H
+// #include <machine.h>
+// #endif
+
+// Forward declarations
+
+// class ostream;
+// typedef class _Pvts os_typespec; // Remove if not persistant
+
+//
+
+class viewer : public input {
+public:
+
+// -- Exceptions
+ // None
+
+// -- Contructors
+
+ viewer();
+
+// -- Destructor
+
+ virtual ~viewer();
+
+// -- Convertors
+ // None
+
+// -- Operators
+ // None
+
+// -- Methods
+
+ virtual bool show(const char*);
+ virtual void end(bool);
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+ // Uncomment for persistent, remove otherwise
+ // static os_typespec* get_os_typespec();
+
+protected:
+
+
+// -- Members
+ // None
+
+// -- Methods
+
+ // void print(ostream&) const; // Change to virtual if base class
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+private:
+
+// No copy allowed
+
+ viewer(const viewer&);
+ viewer& operator=(const viewer&);
+
+// -- Members
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+
+ void ready(const char*);
+ void done(FILE*);
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+// -- Friends
+
+ //friend ostream& operator<<(ostream& s,const viewer& p)
+ // { p.print(s); return s; }
+
+};
+
+inline void destroy(viewer**) {}
+
+// If persistent, uncomment, otherwise remove
+//#ifdef _ODI_OSSG_
+//OS_MARK_SCHEMA_TYPE(viewer);
+//#endif
+
+#endif
diff --git a/view/src/why.cc b/view/src/why.cc
new file mode 100644
index 0000000..5eb575f
--- /dev/null
+++ b/view/src/why.cc
@@ -0,0 +1,64 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #11 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "why.h"
+#include "node.h"
+#include "error.h"
+#include "selection.h"
+#include "tmp_file.h"
+#include "Hyper.h"
+#include <stdio.h>
+#include <stdarg.h>
+
+/***********************************/
+
+why::why(panel_window& w):
+ panel(w)
+{
+}
+
+why::~why()
+{
+ forget_all();
+}
+
+void why::clear()
+{
+ forget_all();
+ HyperSetText(text_,"");
+}
+
+void why::show(node& n)
+{
+ forget_all();
+ node* parent = n.parent(); // SUP-421
+ while (parent) {
+ observe(parent);
+ parent = parent->parent();
+ }
+ std::stringstream ss;
+ n.why(ss);
+ HyperSetText(text_,(char*) ss.str().c_str());
+}
+
+void why::hyperCB(Widget w,XtPointer data)
+{
+ panel::hyper(w,data);
+}
+
+Boolean why::enabled(node& n)
+{
+ return n.isSimpleNode();
+}
diff --git a/view/src/why.h b/view/src/why.h
new file mode 100644
index 0000000..aca79df
--- /dev/null
+++ b/view/src/why.h
@@ -0,0 +1,49 @@
+#ifndef why_H
+#define why_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "uiwhy.h"
+
+#ifndef panel_H
+#include "panel.h"
+#endif
+
+#ifndef node_H
+#include "node.h"
+#endif
+
+class why : public panel, public why_form_c {
+public:
+ why(panel_window&);
+
+ ~why(); // Change to virtual if base class
+
+ virtual const char* name() const { return "Why?"; }
+ virtual void show(node&);
+ virtual void clear();
+ virtual Widget widget() { return xd_rootwidget(); }
+ virtual Boolean enabled(node&);
+
+private:
+ why(const why&);
+ why& operator=(const why&);
+
+ virtual void hyperCB(Widget,XtPointer);
+};
+
+inline void destroy(why**) {}
+#endif
diff --git a/view/src/window.cc b/view/src/window.cc
new file mode 100644
index 0000000..48214be
--- /dev/null
+++ b/view/src/window.cc
@@ -0,0 +1,59 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <stdio.h>
+#include "window.h"
+#include <Xm/PushB.h>
+#include <X11/IntrinsicP.h>
+
+
+extern "C" {
+#include "xec.h"
+}
+#include "gui.h"
+
+
+window::window()
+ : menu_(0)
+{
+}
+
+window::~window()
+{
+ if(menu_)
+ XtDestroyWidget(menu_);
+}
+
+void window::raise()
+{
+ CompositeWidget c = (CompositeWidget)shell();
+ for(unsigned int i = 0 ; i < c->composite.num_children; i++)
+ XtManageChild(c->composite.children[i]);
+
+ XMapRaised(XtDisplay(shell()),XtWindow(shell()));
+}
+
+void window::set_menu(const char* name)
+{
+ if(!menu_)
+ {
+ menu_ = XmCreatePushButton(gui::windows(),(char*)"menu",0,0);
+ xec_SetUserData(menu_,this);
+ XtManageChild(menu_);
+ }
+ xec_SetLabel(menu_,name);
+}
+
+IMP(window)
diff --git a/view/src/window.h b/view/src/window.h
new file mode 100644
index 0000000..71b6be4
--- /dev/null
+++ b/view/src/window.h
@@ -0,0 +1,44 @@
+#ifndef window_H
+#define window_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <Xm/Xm.h>
+
+#include "extent.h"
+
+class window : public extent<window> {
+public:
+
+ window();
+
+ ~window(); // Change to virtual if base class
+
+ void raise();
+ virtual Widget shell() = 0;
+
+ void set_menu(const char*);
+
+private:
+
+ window(const window&);
+ window& operator=(const window&);
+
+ Widget menu_;
+};
+
+inline void destroy(window**) {}
+
+#endif
diff --git a/view/src/x.c b/view/src/x.c
new file mode 100644
index 0000000..c254be0
--- /dev/null
+++ b/view/src/x.c
@@ -0,0 +1,19 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+void main()
+{
+ printf("hello\n");
+}
diff --git a/view/src/xcdp.menu b/view/src/xcdp.menu
new file mode 100644
index 0000000..bf508f5
--- /dev/null
+++ b/view/src/xcdp.menu
@@ -0,0 +1,257 @@
+!===========================================================
+! Name :
+! Author :
+! Revision : $Revision: #17 $
+!
+! Copyright 2009-2016 ECMWF.
+! This software is licensed under the terms of the Apache Licence version 2.0
+! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+! In applying this licence, ECMWF does not waive the privileges and immunities
+! granted to it by virtue of its status as an intergovernmental organisation
+! nor does it submit to any jurisdiction.
+!
+! Description :
+! this file may be found in
+! - sources in order to generate xcdp.menu.h
+! - ~/.ecflowrc/xcdp.menu # edit backup remove (reset)
+! - ~/ is preferred to $HOME
+! - menus can call system command
+!===========================================================
+!
+! Format
+!-------
+! menu TITLE
+! {
+! (vis flg,enable flg,title,command,question,answer)
+! }
+!
+!===========================================================
+!
+! Values for the status flags
+!----------------------------
+!
+!NONE ALL UNKNOWN SUSPENDED COMPLETE QUEUED SUBMITTED ACTIVE
+!ABORTED CLEAR SET SHUTDOWN HALTED
+!
+! Values for type flags
+!----------------------
+!
+!NONE ALL SERVER SUITE FAMILY TASK EVENT
+!
+! Values for visible flags
+!-------------------------
+!
+!NONE ALL SERVER SUITE FAMILY TASK EVENT
+!
+! Values for special flags
+!-------------------------
+!
+!NONE ALL HAS_TRIGGERS HAS_TIME HAS_DATE
+!
+!===========================================================
+
+!==============================================================================
+! Main menu
+!==============================================================================
+
+version 1 0 0 ;
+
+menu 'MAIN'
+{
+ (~SUSPENDED & NODE, ALL, 'Suspend', 'suspend <full_name>')
+ (SUSPENDED & NODE, ALL, 'Resume', 'resume <full_name>')
+
+ ( TASK, ~ACTIVE & ~SUBMITTED, 'Rerun', 'force queued <full_name>')
+ ( FAMILY, ~ACTIVE & ~SUBMITTED, 'Rerun', 'run <full_name>')
+
+ (TASK|ALIAS, SUBMITTED|ACTIVE, 'Set complete',
+ 'force complete <full_name>',
+ 'Have you checked that the job is not active anymore (jobstatus) ?', YES)
+ (TASK|ALIAS, UNKNOWN|QUEUED|ABORTED, 'Set complete',
+ 'force complete <full_name>')
+ (TASK|ALIAS, SUBMITTED|ACTIVE, 'Set aborted',
+ 'force aborted <full_name>',
+ 'Have you checked that the job is not active anymore (jobstatus) ?', YES)
+ (TASK|ALIAS, UNKNOWN|QUEUED|COMPLETE, 'Set aborted',
+ 'force aborted <full_name>')
+
+ (TASK|ALIAS, ~ACTIVE & ~SUBMITTED, 'Execute', 'run <full_name>')
+
+ (SUITE|TASK|FAMILY, ~ACTIVE & ~SUBMITTED, 'Requeue',
+ 'requeue -f <full_name>',
+ 'Confirm requeuing of <full_name>', YES)
+
+ (SUITE|FAMILY, ABORTED | SUSPENDED, 'Requeue aborted',
+ 'requeue -a <full_name>',
+ 'Confirm requeuing of aborted tasks from <full_name>', YES)
+
+ (ALL,ALL,'-',SEPARATOR)
+
+ (SUITE|TASK|FAMILY,(QUEUED) & (HAS_TRIGGERS|HAS_TIME|HAS_DATE),'Delete',MENU)
+ (NODE|ALIAS,ALL,'Special', MENU)
+ (NODE& ADMIN, ALL,'Force', MENU)
+ ((NODE|ALIAS)& ADMIN, ALL,'Order', MENU)
+
+ (ALL,ALL,'-',SEPARATOR ,'',YES)
+ (SUITE|FAMILY|TASK, ALL, 'Web...', 'url <full_name> ', '', YES)
+
+ (ALL,ALL,'-',SEPARATOR)
+
+ (SUITE & (OPER|ADMIN) ,UNKNOWN|COMPLETE,'Begin',
+ 'begin <full_name>','',YES)
+
+ (SUITE & (OPER|ADMIN) ,~SUBMITTED & ~ACTIVE,'Cancel',
+ 'cancel -y <full_name>',
+ 'Do you really want to cancel suite <full_name> ?',NO)
+
+! Events
+!---------------------------------
+
+ (EVENT, CLEAR, 'Set' , 'force set <full_name>', '',YES)
+ (EVENT, SET, 'Clear', 'force clear <full_name>', '',YES)
+
+!!-----------------------------------
+
+ (SERVER & (ADMIN|OPER) & LOCKED , ALL , 'Unlock', 'unlock -y',
+ 'Before going further, please check why the server was locked.',NO)
+ (ALL,ALL,'-',SEPARATOR,'',YES)
+
+!!-----------------------------------
+
+ (SERVER,SHUTDOWN|HALTED, 'Restart',
+ 'restart -y','Restart the server in <node_name>?' ,NO)
+ (SERVER,~SHUTDOWN, 'Shutdown',
+ 'shutdown -y','Shutdown the server in <node_name>?',NO)
+ (SERVER,~HALTED, 'Halt',
+ 'halt -y','Halt the server in <node_name>?',NO)
+ (SERVER,HALTED, 'Terminate',
+ 'terminate -y','Terminate the server in <node_name>?',NO)
+ (ALL,ALL,'-',SEPARATOR,'',YES)
+ (SERVER,ALL, 'Checkpoint','check','',YES)
+ (SERVER,HALTED, 'Recover',
+ 'recover -y','Recover the server in <node_name>?',NO)
+
+!!-----------------------------------
+
+ (LIMIT , ALL, 'Reset' ,
+ 'reset <full_name>', 'Confirm resetting <full_name>', YES)
+ (ALIAS , ALL, 'Remove',
+ 'cancel -y <full_name>', 'Confirm remove alias <full_name>', YES)
+
+!!-----------------------------------
+
+ (ALL,ALL,'-',SEPARATOR)
+
+ (TASK|LIMIT|LABEL|METER|REPEAT|VARIABLE, ALL , 'Edit...', WINDOW(Edit))
+ (TASK|ALIAS, ALL , 'Output...', WINDOW(Output) )
+
+ (TASK|ALIAS, SUBMITTED|ACTIVE , 'Status...', WINDOW(Jobstatus))
+ (ALIAS, ALL , 'Job...', WINDOW(Job) )
+ (TASK|ALIAS, ALL , 'Script...', WINDOW(Script) )
+
+ (SERVER, ALL , 'Suites...', WINDOW(Suites) )
+ (SERVER, ALL , 'History...', WINDOW(History) )
+ (SERVER, ALL , 'Zombies...', WINDOW(Zombies) )
+ (ALL,ALL,'-',SEPARATOR)
+ (SERVER, ALL , 'Options...', WINDOW(Options) )
+}
+
+!==============================================================================
+! Status submenu
+!==============================================================================
+
+menu 'Status'
+{
+ (SUITE|TASK|FAMILY, ~SUSPENDED,'Suspend', 'suspend <full_name>', '',YES)
+ (SUITE|TASK|FAMILY, SUSPENDED ,'Resume', 'resume <full_name>', '',YES)
+
+ (ALL,ALL,'-',SEPARATOR)
+
+ (TASK, ~ACTIVE & ~SUBMITTED, 'Rerun', 'force queued <full_name>', '',YES)
+ (TASK, ~COMPLETE, 'Set complete', 'force complete <full_name>', '',YES)
+
+ (SUITE|TASK|FAMILY|ALIAS, ~ACTIVE & ~SUBMITTED,
+ 'Requeue','requeue -f <full_name>', 'Confirm requeuing of <full_name>', YES)
+
+ (SUITE|FAMILY, ABORTED | SUSPENDED,
+ 'Requeue aborted','requeue -a <full_name>',
+ 'Confirm requeuing aborted tasks below <full_name>', YES)
+}
+
+!==============================================================================
+! Suite submenu
+!==============================================================================
+
+menu 'Suite'
+{
+ (SUITE,UNKNOWN|COMPLETE,'Begin','begin <full_name>','',YES)
+
+ (SUITE,ALL,'Cancel','cancel -y <full_name>',
+ 'Do you really want to cancel <full_name> ?',NO)
+
+ (ALL,ALL,'-',SEPARATOR)
+}
+
+!==============================================================================
+! Delete submenu
+!==============================================================================
+
+menu 'Delete'
+{
+ (ALL,HAS_TRIGGERS|HAS_TIME|HAS_DATE, 'All dependencies',
+ 'delete -tdT <full_name>')
+ (ALL,HAS_TRIGGERS, 'Trigger dependencies','delete -T <full_name>')
+ (ALL,HAS_TIME, 'Time dependencies','delete -t <full_name>')
+ (ALL,QUEUED, 'Date dependencies','delete -d <full_name>')
+}
+
+menu "Order"
+{
+ (ALL,ALL,'Top','order -t top <full_name>')
+ (ALL,ALL,'Up','order -t up <full_name>')
+ (ALL,ALL,'Down','order -t down <full_name>')
+ (ALL,ALL,'Bottom','order -t bottom <full_name>')
+ (ALL,ALL,'Alphabetically','order -t alphabetical <full_name>')
+}
+
+menu "Force"
+{
+ (NODE, ~UNKNOWN, 'Unknown', 'force -q -r unknown <full_name>')
+ (NODE, ~COMPLETE & ~ACTIVE & ~SUBMITTED, 'Complete',
+ 'force =q -r complete <full_name>',
+ 'Check running/queued jobs and Confirm force complete of <full_name>', YES)
+ (NODE, ~QUEUED & ~ACTIVE & ~SUBMITTED, 'Queued',
+ 'force -q -r queued <full_name>')
+ (NODE, ~SUBMITTED & ~ACTIVE,'Submitted',
+ 'force -q -r submitted <full_name>')
+ (NODE, ~ACTIVE, 'Active', 'force -q -r active <full_name>')
+ (NODE, ~ABORTED, 'Aborted', 'force -q -r aborted <full_name>',
+ 'Check running/queued jobs and Confirm force submitted of <full_name>', YES)
+}
+
+menu "Special"
+{
+ (SUITE|FAMILY,(ACTIVE|SUBMITTED|ABORTED),'Kill',
+ 'kill <full_name>','',YES)
+ (TASK|ALIAS,(ACTIVE|SUBMITTED),'Kill','kill <full_name>','',YES)
+
+ (ALL,ALL,'Check',WINDOW(Check),'',YES)
+ (TASK|ALIAS,ALL,'Free password','alter -v <full_name> SMSPASS FREE')
+ (TASK|ALIAS,ALL,'ClearZ','alter -F zombie <full_name>')
+ ((SUITE|FAMILY), SELECTION, 'Plug into selected node', PLUG)
+ (SUITE|SERVER, ALL, 'Collect...', WINDOW(Collector))
+ (SERVER|SUITE,ALL,'Windows', MENU)
+ (ALL,ALL,'echo', 'sh echo ok')
+}
+
+menu "Windows"
+{
+ (SERVER, ALL , 'Info...', WINDOW(Info))
+ (SERVER, ALL , 'Man...', WINDOW(Manual))
+ (SERVER, ALL , 'Var...', WINDOW(Variables))
+ (SERVER, ALL , 'Msg...', WINDOW(Messages))
+ (SERVER, ALL , 'Why...', WINDOW(Why))
+ (SERVER, ALL , 'Triggers...', WINDOW(Triggers))
+ (SERVER, ALL , 'Check...', WINDOW(Check))
+ (SERVER, ALL , 'Jobstatus...', WINDOW(Jobstatus))
+}
diff --git a/view/src/xcdp.menu.h b/view/src/xcdp.menu.h
new file mode 100644
index 0000000..f0bcb33
--- /dev/null
+++ b/view/src/xcdp.menu.h
@@ -0,0 +1,258 @@
+(char*) " !=========================================================== ",
+(char*) " ! Name : ",
+(char*) " ! Author : ",
+(char*) " ! Revision : $Revision: #17 $ ",
+(char*) " ! ",
+(char*) " ! Copyright 2009-2016 ECMWF. ",
+(char*) " ! This software is licensed under the terms of the Apache Licence version 2.0 ",
+(char*) " ! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. ",
+(char*) " ! In applying this licence, ECMWF does not waive the privileges and immunities ",
+(char*) " ! granted to it by virtue of its status as an intergovernmental organisation ",
+(char*) " ! nor does it submit to any jurisdiction. ",
+(char*) " ! ",
+(char*) " ! Description : ",
+(char*) " ! this file may be found in ",
+(char*) " ! - sources in order to generate xcdp.menu.h ",
+(char*) " ! - ~/.ecflowrc/xcdp.menu # edit backup remove (reset) ",
+(char*) " ! - ~/ is preferred to $HOME ",
+(char*) " ! - menus can call system command ",
+(char*) " !=========================================================== ",
+(char*) " ! ",
+(char*) " ! Format ",
+(char*) " !------- ",
+(char*) " ! menu TITLE ",
+(char*) " ! { ",
+(char*) " ! (vis flg,enable flg,title,command,question,answer) ",
+(char*) " ! } ",
+(char*) " ! ",
+(char*) " !=========================================================== ",
+(char*) " ! ",
+(char*) " ! Values for the status flags ",
+(char*) " !---------------------------- ",
+(char*) " ! ",
+(char*) " !NONE ALL UNKNOWN SUSPENDED COMPLETE QUEUED SUBMITTED ACTIVE ",
+(char*) " !ABORTED CLEAR SET SHUTDOWN HALTED ",
+(char*) " ! ",
+(char*) " ! Values for type flags ",
+(char*) " !---------------------- ",
+(char*) " ! ",
+(char*) " !NONE ALL SERVER SUITE FAMILY TASK EVENT ",
+(char*) " ! ",
+(char*) " ! Values for visible flags ",
+(char*) " !------------------------- ",
+(char*) " ! ",
+(char*) " !NONE ALL SERVER SUITE FAMILY TASK EVENT ",
+(char*) " ! ",
+(char*) " ! Values for special flags ",
+(char*) " !------------------------- ",
+(char*) " ! ",
+(char*) " !NONE ALL HAS_TRIGGERS HAS_TIME HAS_DATE ",
+(char*) " ! ",
+(char*) " !=========================================================== ",
+(char*) " ",
+(char*) " !============================================================================== ",
+(char*) " ! Main menu ",
+(char*) " !============================================================================== ",
+(char*) " ",
+(char*) " version 1 0 0 ; ",
+(char*) " ",
+(char*) " menu 'MAIN' ",
+(char*) " { ",
+(char*) " (~SUSPENDED & NODE, ALL, 'Suspend', 'suspend <full_name>') ",
+(char*) " (SUSPENDED & NODE, ALL, 'Resume', 'resume <full_name>') ",
+(char*) " ",
+(char*) " ( TASK, ~ACTIVE & ~SUBMITTED, 'Rerun', 'force queued <full_name>') ",
+(char*) " ( FAMILY, ~ACTIVE & ~SUBMITTED, 'Rerun', 'run <full_name>') ",
+(char*) " ",
+(char*) " (TASK|ALIAS, SUBMITTED|ACTIVE, 'Set complete', ",
+(char*) " 'force complete <full_name>', ",
+(char*) " 'Have you checked that the job is not active anymore (jobstatus) ?', YES) ",
+(char*) " (TASK|ALIAS, UNKNOWN|QUEUED|ABORTED, 'Set complete', ",
+(char*) " 'force complete <full_name>') ",
+(char*) " (TASK|ALIAS, SUBMITTED|ACTIVE, 'Set aborted', ",
+(char*) " 'force aborted <full_name>', ",
+(char*) " 'Have you checked that the job is not active anymore (jobstatus) ?', YES) ",
+(char*) " (TASK|ALIAS, UNKNOWN|QUEUED|COMPLETE, 'Set aborted', ",
+(char*) " 'force aborted <full_name>') ",
+(char*) " ",
+(char*) " (TASK|ALIAS, ~ACTIVE & ~SUBMITTED, 'Execute', 'run <full_name>') ",
+(char*) " ",
+(char*) " (SUITE|TASK|FAMILY, ~ACTIVE & ~SUBMITTED, 'Requeue', ",
+(char*) " 'requeue -f <full_name>', ",
+(char*) " 'Confirm requeuing of <full_name>', YES) ",
+(char*) " ",
+(char*) " (SUITE|FAMILY, ABORTED | SUSPENDED, 'Requeue aborted', ",
+(char*) " 'requeue -a <full_name>', ",
+(char*) " 'Confirm requeuing of aborted tasks from <full_name>', YES) ",
+(char*) " ",
+(char*) " (ALL,ALL,'-',SEPARATOR) ",
+(char*) " ",
+(char*) " (SUITE|TASK|FAMILY,(QUEUED) & (HAS_TRIGGERS|HAS_TIME|HAS_DATE),'Delete',MENU) ",
+(char*) " (NODE|ALIAS,ALL,'Special', MENU) ",
+(char*) " (NODE& ADMIN, ALL,'Force', MENU) ",
+(char*) " ((NODE|ALIAS)& ADMIN, ALL,'Order', MENU) ",
+(char*) " ",
+(char*) " (ALL,ALL,'-',SEPARATOR ,'',YES) ",
+(char*) " (SUITE|FAMILY|TASK, ALL, 'Web...', 'url <full_name> ', '', YES) ",
+(char*) " ",
+(char*) " (ALL,ALL,'-',SEPARATOR) ",
+(char*) " ",
+(char*) " (SUITE & (OPER|ADMIN) ,UNKNOWN|COMPLETE,'Begin', ",
+(char*) " 'begin <full_name>','',YES) ",
+(char*) " ",
+(char*) " (SUITE & (OPER|ADMIN) ,~SUBMITTED & ~ACTIVE,'Cancel', ",
+(char*) " 'cancel -y <full_name>', ",
+(char*) " 'Do you really want to cancel suite <full_name> ?',NO) ",
+(char*) " ",
+(char*) " ! Events ",
+(char*) " !--------------------------------- ",
+(char*) " ",
+(char*) " (EVENT, CLEAR, 'Set' , 'force set <full_name>', '',YES) ",
+(char*) " (EVENT, SET, 'Clear', 'force clear <full_name>', '',YES) ",
+(char*) " ",
+(char*) " !!----------------------------------- ",
+(char*) " ",
+(char*) " (SERVER & (ADMIN|OPER) & LOCKED , ALL , 'Unlock', 'unlock -y', ",
+(char*) " 'Before going further, please check why the server was locked.',NO) ",
+(char*) " (ALL,ALL,'-',SEPARATOR,'',YES) ",
+(char*) " ",
+(char*) " !!----------------------------------- ",
+(char*) " ",
+(char*) " (SERVER,SHUTDOWN|HALTED, 'Restart', ",
+(char*) " 'restart -y','Restart the server in <node_name>?' ,NO) ",
+(char*) " (SERVER,~SHUTDOWN, 'Shutdown', ",
+(char*) " 'shutdown -y','Shutdown the server in <node_name>?',NO) ",
+(char*) " (SERVER,~HALTED, 'Halt', ",
+(char*) " 'halt -y','Halt the server in <node_name>?',NO) ",
+(char*) " (SERVER,HALTED, 'Terminate', ",
+(char*) " 'terminate -y','Terminate the server in <node_name>?',NO) ",
+(char*) " (ALL,ALL,'-',SEPARATOR,'',YES) ",
+(char*) " (SERVER,ALL, 'Checkpoint','check','',YES) ",
+(char*) " (SERVER,HALTED, 'Recover', ",
+(char*) " 'recover -y','Recover the server in <node_name>?',NO) ",
+(char*) " ",
+(char*) " !!----------------------------------- ",
+(char*) " ",
+(char*) " (LIMIT , ALL, 'Reset' , ",
+(char*) " 'reset <full_name>', 'Confirm resetting <full_name>', YES) ",
+(char*) " (ALIAS , ALL, 'Remove', ",
+(char*) " 'cancel -y <full_name>', 'Confirm remove alias <full_name>', YES) ",
+(char*) " ",
+(char*) " !!----------------------------------- ",
+(char*) " ",
+(char*) " (ALL,ALL,'-',SEPARATOR) ",
+(char*) " ",
+(char*) " (TASK|LIMIT|LABEL|METER|REPEAT|VARIABLE, ALL , 'Edit...', WINDOW(Edit)) ",
+(char*) " (TASK|ALIAS, ALL , 'Output...', WINDOW(Output) ) ",
+(char*) " ",
+(char*) " (TASK|ALIAS, SUBMITTED|ACTIVE , 'Status...', WINDOW(Jobstatus)) ",
+(char*) " (ALIAS, ALL , 'Job...', WINDOW(Job) ) ",
+(char*) " (TASK|ALIAS, ALL , 'Script...', WINDOW(Script) ) ",
+(char*) " ",
+(char*) " (SERVER, ALL , 'Suites...', WINDOW(Suites) ) ",
+(char*) " (SERVER, ALL , 'History...', WINDOW(History) ) ",
+(char*) " (SERVER, ALL , 'Zombies...', WINDOW(Zombies) ) ",
+(char*) " (ALL,ALL,'-',SEPARATOR) ",
+(char*) " (SERVER, ALL , 'Options...', WINDOW(Options) ) ",
+(char*) " } ",
+(char*) " ",
+(char*) " !============================================================================== ",
+(char*) " ! Status submenu ",
+(char*) " !============================================================================== ",
+(char*) " ",
+(char*) " menu 'Status' ",
+(char*) " { ",
+(char*) " (SUITE|TASK|FAMILY, ~SUSPENDED,'Suspend', 'suspend <full_name>', '',YES) ",
+(char*) " (SUITE|TASK|FAMILY, SUSPENDED ,'Resume', 'resume <full_name>', '',YES) ",
+(char*) " ",
+(char*) " (ALL,ALL,'-',SEPARATOR) ",
+(char*) " ",
+(char*) " (TASK, ~ACTIVE & ~SUBMITTED, 'Rerun', 'force queued <full_name>', '',YES) ",
+(char*) " (TASK, ~COMPLETE, 'Set complete', 'force complete <full_name>', '',YES) ",
+(char*) " ",
+(char*) " (SUITE|TASK|FAMILY|ALIAS, ~ACTIVE & ~SUBMITTED, ",
+(char*) " 'Requeue','requeue -f <full_name>', 'Confirm requeuing of <full_name>', YES) ",
+(char*) " ",
+(char*) " (SUITE|FAMILY, ABORTED | SUSPENDED, ",
+(char*) " 'Requeue aborted','requeue -a <full_name>', ",
+(char*) " 'Confirm requeuing aborted tasks below <full_name>', YES) ",
+(char*) " } ",
+(char*) " ",
+(char*) " !============================================================================== ",
+(char*) " ! Suite submenu ",
+(char*) " !============================================================================== ",
+(char*) " ",
+(char*) " menu 'Suite' ",
+(char*) " { ",
+(char*) " (SUITE,UNKNOWN|COMPLETE,'Begin','begin <full_name>','',YES) ",
+(char*) " ",
+(char*) " (SUITE,ALL,'Cancel','cancel -y <full_name>', ",
+(char*) " 'Do you really want to cancel <full_name> ?',NO) ",
+(char*) " ",
+(char*) " (ALL,ALL,'-',SEPARATOR) ",
+(char*) " } ",
+(char*) " ",
+(char*) " !============================================================================== ",
+(char*) " ! Delete submenu ",
+(char*) " !============================================================================== ",
+(char*) " ",
+(char*) " menu 'Delete' ",
+(char*) " { ",
+(char*) " (ALL,HAS_TRIGGERS|HAS_TIME|HAS_DATE, 'All dependencies', ",
+(char*) " 'delete -tdT <full_name>') ",
+(char*) " (ALL,HAS_TRIGGERS, 'Trigger dependencies','delete -T <full_name>') ",
+(char*) " (ALL,HAS_TIME, 'Time dependencies','delete -t <full_name>') ",
+(char*) " (ALL,QUEUED, 'Date dependencies','delete -d <full_name>') ",
+(char*) " } ",
+(char*) " ",
+(char*) " menu \"Order\" ",
+(char*) " { ",
+(char*) " (ALL,ALL,'Top','order -t top <full_name>') ",
+(char*) " (ALL,ALL,'Up','order -t up <full_name>') ",
+(char*) " (ALL,ALL,'Down','order -t down <full_name>') ",
+(char*) " (ALL,ALL,'Bottom','order -t bottom <full_name>') ",
+(char*) " (ALL,ALL,'Alphabetically','order -t alphabetical <full_name>') ",
+(char*) " } ",
+(char*) " ",
+(char*) " menu \"Force\" ",
+(char*) " { ",
+(char*) " (NODE, ~UNKNOWN, 'Unknown', 'force -q -r unknown <full_name>') ",
+(char*) " (NODE, ~COMPLETE & ~ACTIVE & ~SUBMITTED, 'Complete', ",
+(char*) " 'force =q -r complete <full_name>', ",
+(char*) " 'Check running/queued jobs and Confirm force complete of <full_name>', YES) ",
+(char*) " (NODE, ~QUEUED & ~ACTIVE & ~SUBMITTED, 'Queued', ",
+(char*) " 'force -q -r queued <full_name>') ",
+(char*) " (NODE, ~SUBMITTED & ~ACTIVE,'Submitted', ",
+(char*) " 'force -q -r submitted <full_name>') ",
+(char*) " (NODE, ~ACTIVE, 'Active', 'force -q -r active <full_name>') ",
+(char*) " (NODE, ~ABORTED, 'Aborted', 'force -q -r aborted <full_name>', ",
+(char*) " 'Check running/queued jobs and Confirm force submitted of <full_name>', YES) ",
+(char*) " } ",
+(char*) " ",
+(char*) " menu \"Special\" ",
+(char*) " { ",
+(char*) " (SUITE|FAMILY,(ACTIVE|SUBMITTED|ABORTED),'Kill', ",
+(char*) " 'kill <full_name>','',YES) ",
+(char*) " (TASK|ALIAS,(ACTIVE|SUBMITTED),'Kill','kill <full_name>','',YES) ",
+(char*) " ",
+(char*) " (ALL,ALL,'Check',WINDOW(Check),'',YES) ",
+(char*) " (TASK|ALIAS,ALL,'Free password','alter -v <full_name> SMSPASS FREE') ",
+(char*) " (TASK|ALIAS,ALL,'ClearZ','alter -F zombie <full_name>') ",
+(char*) " ((SUITE|FAMILY), SELECTION, 'Plug into selected node', PLUG) ",
+(char*) " (SUITE|SERVER, ALL, 'Collect...', WINDOW(Collector)) ",
+(char*) " (SERVER|SUITE,ALL,'Windows', MENU) ",
+(char*) " (ALL,ALL,'echo', 'sh echo ok') ",
+(char*) " } ",
+(char*) " ",
+(char*) " menu \"Windows\" ",
+(char*) " { ",
+(char*) " (SERVER, ALL , 'Info...', WINDOW(Info)) ",
+(char*) " (SERVER, ALL , 'Man...', WINDOW(Manual)) ",
+(char*) " (SERVER, ALL , 'Var...', WINDOW(Variables)) ",
+(char*) " (SERVER, ALL , 'Msg...', WINDOW(Messages)) ",
+(char*) " (SERVER, ALL , 'Why...', WINDOW(Why)) ",
+(char*) " (SERVER, ALL , 'Triggers...', WINDOW(Triggers)) ",
+(char*) " (SERVER, ALL , 'Check...', WINDOW(Check)) ",
+(char*) " (SERVER, ALL , 'Jobstatus...', WINDOW(Jobstatus)) ",
+(char*) " } ",
+NULL
diff --git a/view/src/xdclass.h b/view/src/xdclass.h
new file mode 100644
index 0000000..4d64515
--- /dev/null
+++ b/view/src/xdclass.h
@@ -0,0 +1,225 @@
+#ifndef XDCLASS_H
+#define XDCLASS_H
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #4 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#ifdef __cplusplus
+
+#include <Xm/Xm.h>
+#include <stdlib.h>
+#pragma GCC diagnostic ignored "-Wwrite-strings"
+
+class xd_base_c
+{
+ public:
+ xd_base_c() {_xd_rootwidget=NULL;}
+ Widget xd_rootwidget() const {return _xd_rootwidget;}
+ protected:
+ Widget _xd_rootwidget;
+ private:
+ void operator=(xd_base_c&); // No assignment
+ // Certain C++ compilers (eg gcc 2.5) require there to be an
+ // implementation of the copy constructor. If your application
+ // fails to link try using the second version of the constructor
+ //xd_base_c(xd_base_c&) ; // No default copy
+ xd_base_c(xd_base_c&) { abort();} // No default copy
+};
+
+class xd_XtWidget_c: public xd_base_c
+{
+ public:
+ xd_XtWidget_c();
+ void SetValue(String name, XtArgVal value);
+ void SetValues(ArgList args, Cardinal num_args);
+ void VaSetValues(String name,...);
+ void GetValue(String name, void *value);
+ void GetValues(ArgList args, Cardinal num_args);
+ void VaGetValues(String name,...);
+ void Map();
+ void Unmap();
+ virtual void xd_enable();
+ virtual void xd_disable();
+ virtual void xd_destroy();
+};
+
+class xd_TopLevelShell_c: public xd_XtWidget_c
+{
+};
+
+class xd_ApplicationShell_c: public xd_TopLevelShell_c
+{
+ public:
+ void xd_exit(int status=0);
+ void Realize();
+};
+
+class xd_ChildWidget_c: public xd_XtWidget_c
+{
+ public:
+ virtual void xd_show()=0;
+ virtual void xd_hide()=0;
+ void Manage();
+ void Unmanage();
+};
+
+class xd_XmDialog_c: public xd_ChildWidget_c
+{
+ public:
+ xd_XmDialog_c();
+ virtual void xd_show();
+ virtual void xd_hide();
+ void Raise();
+ protected:
+ Widget xd_getchildwidget();
+ Widget xd_childwidget;
+};
+
+class xd_NonShellWidget_c: public xd_ChildWidget_c
+{
+ public:
+ virtual void xd_show();
+ virtual void xd_hide();
+};
+
+class xd_XmLabel_c: public xd_NonShellWidget_c
+{
+};
+
+class xd_XmCascadeButton_c: public xd_NonShellWidget_c
+{
+};
+
+class xd_XmDrawnButton_c: public xd_NonShellWidget_c
+{
+};
+
+class xd_XmPushButton_c: public xd_NonShellWidget_c
+{
+};
+
+class xd_XmToggleButton_c: public xd_NonShellWidget_c
+{
+};
+
+class xd_XmArrowButton_c: public xd_NonShellWidget_c
+{
+};
+
+class xd_XmList_c: public xd_NonShellWidget_c
+{
+};
+
+class xd_XmScrollBar_c: public xd_NonShellWidget_c
+{
+};
+
+class xd_XmSeparator_c: public xd_NonShellWidget_c
+{
+};
+
+class xd_XmText_c: public xd_NonShellWidget_c
+{
+};
+
+class xd_XmTextField_c: public xd_NonShellWidget_c
+{
+};
+
+class xd_XmBulletinBoard_c: public xd_NonShellWidget_c
+{
+};
+
+class xd_XmRowColumn_c: public xd_NonShellWidget_c
+{
+};
+
+class xd_XmRadioBox_c: public xd_NonShellWidget_c
+{
+};
+
+class xd_XmDrawingArea_c: public xd_NonShellWidget_c
+{
+};
+
+class xd_XmPanedWindow_c: public xd_NonShellWidget_c
+{
+};
+
+class xd_XmFrame_c: public xd_NonShellWidget_c
+{
+};
+
+class xd_XmScale_c: public xd_NonShellWidget_c
+{
+};
+
+class xd_XmScrolledWindow_c: public xd_NonShellWidget_c
+{
+};
+
+class xd_XmScrolledText_c: public xd_NonShellWidget_c
+{
+};
+
+class xd_XmScrolledList_c: public xd_NonShellWidget_c
+{
+};
+
+class xd_XmMainWindow: public xd_NonShellWidget_c
+{
+};
+
+class xd_XmSelectionBox_c: public xd_NonShellWidget_c
+{
+};
+
+class xd_XmFileSelectionBox_c: public xd_NonShellWidget_c
+{
+};
+
+class xd_XmCommand_c: public xd_NonShellWidget_c
+{
+};
+
+class xd_XmMessageBox_c: public xd_NonShellWidget_c
+{
+};
+
+class xd_XmMainWindow_c: public xd_NonShellWidget_c
+{
+};
+
+class xd_XmForm_c: public xd_NonShellWidget_c
+{
+};
+
+class xd_XmMenuBar_c: public xd_NonShellWidget_c
+{
+};
+
+class xd_XmPulldownMenu_c: public xd_NonShellWidget_c
+{
+};
+
+class xd_XmPopupMenu_c: public xd_NonShellWidget_c
+{
+};
+
+class xd_XmOptionMenu_c: public xd_NonShellWidget_c
+{
+};
+
+#endif /*__cplusplus*/
+#endif /*XDCLASS_H*/
diff --git a/view/src/xdxmdialog.cc b/view/src/xdxmdialog.cc
new file mode 100644
index 0000000..8efa339
--- /dev/null
+++ b/view/src/xdxmdialog.cc
@@ -0,0 +1,66 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <Xm/DialogS.h>
+
+#include <xdclass.h>
+
+xd_XmDialog_c::xd_XmDialog_c()
+{
+ xd_childwidget=0;
+ return;
+}
+
+Widget xd_XmDialog_c::xd_getchildwidget()
+{
+ if (!xd_childwidget)
+ {
+ Cardinal numchildren;
+ GetValue(XmNnumChildren, &numchildren);
+ if (numchildren!=0)
+ {
+ WidgetList children;
+ GetValue(XmNchildren, &children);
+ xd_childwidget=*children;
+ }
+ }
+ return xd_childwidget;
+}
+
+void xd_XmDialog_c::xd_show()
+{
+ if (!_xd_rootwidget) // Nothing to show
+ return;
+ if (!xd_getchildwidget()) // Nothing to show
+ return;
+ XtManageChild(xd_childwidget);
+ return;
+}
+
+void xd_XmDialog_c::xd_hide()
+{
+ if (!_xd_rootwidget) // Nothing to hide
+ return;
+ if (!xd_getchildwidget()) // Nothing to hide
+ return;
+ XtUnmanageChild(xd_childwidget);
+ return;
+}
+
+void xd_XmDialog_c::Raise()
+{
+ (void) XRaiseWindow(XtDisplay(_xd_rootwidget), XtWindow(_xd_rootwidget));
+ return;
+}
diff --git a/view/src/xdxtclass.cc b/view/src/xdxtclass.cc
new file mode 100644
index 0000000..9eb6f6b
--- /dev/null
+++ b/view/src/xdxtclass.cc
@@ -0,0 +1,223 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include <xdclass.h>
+
+xd_XtWidget_c::xd_XtWidget_c()
+{
+ _xd_rootwidget=0;
+ return;
+}
+
+void xd_XtWidget_c::SetValue(String name, XtArgVal value)
+{
+ Arg al[1];
+ Cardinal ac=0;
+ XtSetArg(al[ac], name, value); ac++;
+ XtSetValues(_xd_rootwidget, al, ac);
+ return;
+}
+
+void xd_XtWidget_c::SetValues(ArgList args, Cardinal num_args)
+{
+ XtSetValues(_xd_rootwidget, args, num_args);
+ return;
+}
+
+void xd_XtWidget_c::VaSetValues(String name,...)
+{
+ String attr;
+ int count=1;
+ va_list ap;
+
+ /* Ignore empty argument list */
+ if (name==NULL)
+ return;
+
+ /* First count the (non-empty) argument list */
+ va_start(ap, name);
+
+ va_arg(ap, XtArgVal); // Pop first value
+ for (attr = va_arg(ap, String); attr != NULL;
+ attr = va_arg(ap, String))
+ {
+ va_arg(ap, XtArgVal); // Pop value
+ ++count;
+ }
+ va_end(ap);
+
+ /* Now transfer values into an ArgList and throw at XtSetValues*/
+
+ ArgList al=new Arg[count];
+ XtArgVal value;
+ Cardinal ac=0;
+
+ va_start(ap, name);
+ value=va_arg(ap, XtArgVal);
+ XtSetArg(al[ac], name, value); ac++;
+ for (attr = va_arg(ap, String); attr != NULL;
+ attr = va_arg(ap, String))
+ {
+ value=va_arg(ap, XtArgVal);
+ if (value)
+ {
+ XtSetArg(al[ac], attr, value); ac++;
+ }
+ }
+ va_end(ap);
+ XtSetValues(_xd_rootwidget, al, ac);
+
+ /* Tidy up - commented out version is for aged compilers */
+ //delete [count]al;
+ delete []al;
+ return;
+}
+
+void xd_XtWidget_c::GetValue(String name, void* value)
+{
+ Arg al[1];
+ Cardinal ac=0;
+ XtSetArg(al[ac], name, value); ac++;
+ XtGetValues(_xd_rootwidget, al, ac);
+ return;
+}
+
+void xd_XtWidget_c::GetValues(ArgList args, Cardinal num_args)
+{
+ XtGetValues(_xd_rootwidget, args, num_args);
+ return;
+}
+
+void xd_XtWidget_c::VaGetValues(String name,...)
+{
+ String attr;
+ int count=1;
+ va_list ap;
+
+ /* Ignore empty argument list */
+ if (name==NULL)
+ return;
+
+ /* First count the (non-empty) argument list */
+ va_start(ap, name);
+
+ va_arg(ap, XtArgVal); // Pop first value
+ for (attr = va_arg(ap, String); attr != NULL;
+ attr = va_arg(ap, String))
+ {
+ va_arg(ap, XtArgVal); // Pop value
+ ++count;
+ }
+ va_end(ap);
+
+ /* Now transfer values into an ArgList and throw at XtGetValues*/
+
+ ArgList al=new Arg[count];
+ XtArgVal value;
+ Cardinal ac=0;
+
+ va_start(ap, name);
+ value=va_arg(ap, XtArgVal);
+ XtSetArg(al[ac], name, value); ac++;
+ for (attr = va_arg(ap, String); attr != NULL;
+ attr = va_arg(ap, String))
+ {
+ value=va_arg(ap, XtArgVal);
+ if (value)
+ {
+ XtSetArg(al[ac], attr, value); ac++;
+ }
+ }
+ va_end(ap);
+ XtGetValues(_xd_rootwidget, al, ac);
+
+ /* Tidy up - commented out version is for aged compilers */
+ //delete [count]al;
+ delete []al;
+ return;
+}
+
+void xd_XtWidget_c::Map()
+{
+ XtMapWidget(_xd_rootwidget);
+ return;
+}
+
+void xd_XtWidget_c::Unmap()
+{
+ XtUnmapWidget(_xd_rootwidget);
+ return;
+}
+
+void xd_XtWidget_c::xd_enable()
+{
+ XtSetSensitive(_xd_rootwidget, TRUE);
+ return;
+}
+
+void xd_XtWidget_c::xd_disable()
+{
+ XtSetSensitive(_xd_rootwidget, FALSE);
+ return;
+}
+
+void xd_XtWidget_c::xd_destroy()
+{
+ if (_xd_rootwidget){
+ XtDestroyWidget(_xd_rootwidget);
+ _xd_rootwidget=0;
+ }
+ return;
+}
+
+void xd_ApplicationShell_c::xd_exit(int status)
+{
+ exit(status);
+ return;
+}
+
+void xd_ApplicationShell_c::Realize()
+{
+ XtRealizeWidget(_xd_rootwidget);
+ return;
+}
+
+void xd_ChildWidget_c::Manage()
+{
+ XtManageChild(_xd_rootwidget);
+ return;
+}
+
+void xd_ChildWidget_c::Unmanage()
+{
+ XtUnmanageChild(_xd_rootwidget);
+ return;
+}
+
+void xd_NonShellWidget_c::xd_show()
+{
+ Map();
+ return;
+}
+
+void xd_NonShellWidget_c::xd_hide()
+{
+ Unmap();
+ return;
+}
diff --git a/view/src/xec.h b/view/src/xec.h
new file mode 100644
index 0000000..f7f09ad
--- /dev/null
+++ b/view/src/xec.h
@@ -0,0 +1,24 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#include <stdio.h>
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+#include "xecp.h"
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
diff --git a/view/src/xecp.h b/view/src/xecp.h
new file mode 100644
index 0000000..f676e51
--- /dev/null
+++ b/view/src/xecp.h
@@ -0,0 +1,75 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #3 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+/* xec_Cursor.c */
+void xec_SetWatchCursor(Widget w);
+void xec_ResetCursor(Widget w);
+
+/* xec_Label.c */
+void xec_SetLabel(Widget w, const char *title);
+void xec_VaSetLabel(Widget w, const char *fmt, ...);
+
+/* xec_List.c */
+void xec_RemoveListItem(Widget w, char *p);
+void xec_AddListMax(Widget w, int max, char *p);
+void xec_VaAddListMax(Widget w, int max, char *fmt, ...);
+void xec_ListSelectAll(Widget w);
+void xec_AddListItem(Widget w, char *p);
+Boolean xec_AddListItemUnique(Widget w, char *p, Boolean sel);
+void xec_VaAddListItem(Widget w, char *fmt, ...);
+void xec_SetListItems(Widget w, XmString list[], int count);
+int xec_DumpList(FILE *f, char *fmt, Widget w);
+Boolean xec_ListSearch(Widget w, char *word, Boolean nocase, Boolean fromstart, Boolean wrap);
+void xec_ListSelect(Widget w, int n);
+void xec_ListItemSelect(Widget w, const char*);
+void xec_AddFontListItem(Widget list, char *buffer, Boolean bold);
+void xec_ReplaceListItem(Widget w,const char* from,const char* to);
+
+/* xec_Regexp.c */
+int xec_compile(char *w);
+int xec_step(char *p);
+
+/* xec_Strings.c */
+XmString xec_NewString(const char *s);
+int xec_BuildXmStringList(XmString **list, char *p, int *count);
+int xec_FreeXmStringList(XmString *list, int count);
+char *xec_GetString(XmString string);
+
+/* xec_Text.c */
+int regexp_find(const char *word, const char *buffer, int nocase, int *from, int *to);
+char *xec_TextGetString(Widget w, long *length);
+void xec_TextFreeString(char *p);
+Boolean xec_TextSearch(Widget w, char *word, Boolean nocase, Boolean regex, Boolean back, Boolean fromstart, Boolean wrap);
+char *xec_GetText(Widget w, char buf[]);
+int xec_LoadText(Widget Text, const char *fname, Boolean include);
+void *xec_MapText(Widget w, const char *fname, int *z);
+void xec_UnmapText(void *x);
+int xec_SaveText(Widget w, char *fname);
+int xec_DumpText(FILE *fp, Widget w);
+void xec_PrintText(Widget w, char *cmd);
+void xec_ReplaceTextSelection(Widget w, char *p, Boolean sel);
+
+/* xec_Toggle.c */
+void xec_SetToggle(Widget w, int set);
+int xec_GetToggle(Widget w);
+
+/* xec_Widget.c */
+void *xec_GetUserData(Widget w);
+void xec_SetUserData(Widget w, void *p);
+void xec_SetColor(Widget w, Pixel p, const char *which);
+void xec_ShowWidget(Widget w);
+void xec_Invert(Widget w);
+void xec_ManageAll(Widget w);
+void xec_UnmanageAll(Widget w);
diff --git a/view/src/xmstring.cc b/view/src/xmstring.cc
new file mode 100644
index 0000000..561d6c5
--- /dev/null
+++ b/view/src/xmstring.cc
@@ -0,0 +1,107 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "xmstring.h"
+
+
+xmstring::xmstring(const char* s,const char* font):
+ str_(0)
+{
+
+ if(!s) return;
+
+ if(font == 0) font = "normal";
+
+
+ if(*s == '\n')
+ {
+ str_ = XmStringSeparatorCreate();
+ *this += xmstring(s+1,font);
+ return;
+ }
+
+
+ if(strchr(s,'\n'))
+ {
+
+ XmString xms1;
+ XmString xms2;
+ XmString line;
+ XmString separator;
+ char *p;
+ char *t = XtNewString(s); /* Make a copy for strtok not to */
+ /* damage the original string */
+
+ separator = XmStringSeparatorCreate();
+ p = strtok(t,"\n");
+ xms1 = XmStringCreateLtoR(p,(char*)font);
+
+ while ((p = strtok(NULL,"\n")))
+ {
+ line = XmStringCreateLtoR(p,(char*)font);
+ xms2 = XmStringConcat(xms1,separator);
+ XmStringFree(xms1);
+ xms1 = XmStringConcat(xms2,line);
+ XmStringFree(xms2);
+ XmStringFree(line);
+ }
+
+ XmStringFree(separator);
+ XtFree(t);
+
+ str_ = xms1;
+ }
+ else str_ = XmStringCreateLtoR((char*)s,(char*)font);
+}
+
+xmstring::~xmstring()
+{
+ if(str_)
+ XmStringFree(str_);
+}
+
+xmstring::xmstring(XmString s):
+ str_(XmStringCopy(s))
+{
+}
+
+xmstring::xmstring(const xmstring& other):
+ str_(other.str_?XmStringCopy(other.str_):0)
+{
+}
+
+xmstring& xmstring::operator=(const xmstring& other)
+{
+ if(str_) XmStringFree(str_);
+ str_ = 0;
+ if(other.str_) str_ = XmStringCopy(other.str_);
+ return *this;
+}
+
+xmstring xmstring::operator+(const xmstring& other) const
+{
+ if(!other.str_) return *this;
+ if(!str_) return other;
+
+ xmstring x;
+ x.str_ = XmStringConcat(str_,other.str_);
+ return x;
+}
+
+xmstring& xmstring::operator+=(const xmstring& other)
+{
+ *this = *this + other;
+ return *this;
+}
diff --git a/view/src/xmstring.h b/view/src/xmstring.h
new file mode 100644
index 0000000..f73f727
--- /dev/null
+++ b/view/src/xmstring.h
@@ -0,0 +1,128 @@
+#ifndef xmstring_H
+#define xmstring_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+// Headers
+// #ifndef machine_H
+// #include <machine.h>
+// #endif
+
+// Forward declarations
+
+// class ostream;
+// typedef class _Pvts os_typespec; // Remove if not persistant
+
+//
+
+#include <Xm/Xm.h>
+
+class xmstring {
+public:
+
+// -- Exceptions
+ // None
+
+// -- Contructors
+
+ xmstring(const char* = 0, const char* set = 0);
+ xmstring(XmString);
+ xmstring(const xmstring&);
+ xmstring& operator=(const xmstring&);
+
+// -- Destructor
+
+ ~xmstring();
+
+// -- Convertors
+ // None
+
+// -- Operators
+
+ operator XmString() const { return str_; }
+
+ xmstring operator+(const xmstring&) const;
+ xmstring& operator+=(const xmstring&);
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+ // Uncomment for persistent, remove otherwise
+ // static os_typespec* get_os_typespec();
+
+protected:
+
+// -- Members
+ // None
+
+// -- Methods
+
+ // void print(ostream&) const; // Change to virtual if base class
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+private:
+
+// No copy allowed
+
+
+// -- Members
+
+ XmString str_;
+
+// -- Methods
+ // None
+
+// -- Overridden methods
+ // None
+
+// -- Class members
+ // None
+
+// -- Class methods
+ // None
+
+// -- Friends
+
+ //friend ostream& operator<<(ostream& s,const xmstring& p)
+ // { p.print(s); return s; }
+
+};
+
+inline void destroy(xmstring**) {}
+
+// If persistent, uncomment, otherwise remove
+//#ifdef _ODI_OSSG_
+//OS_MARK_SCHEMA_TYPE(xmstring);
+//#endif
+
+#endif
diff --git a/view/src/xnode.cc b/view/src/xnode.cc
new file mode 100644
index 0000000..fb4d63f
--- /dev/null
+++ b/view/src/xnode.cc
@@ -0,0 +1,56 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+#include "xnode.h"
+
+xnode::xnode(node *n):
+ widget_(0),
+ node_(n),
+ box_(-1)
+{
+}
+
+xnode::~xnode()
+{
+}
+
+int xnode::getBox(Widget w)
+{
+ if(widget_ && widget_ != w)
+ return -1;
+
+ if(box_ == -1)
+ {
+ widget_ = w;
+ box_ = NodeCreate(w,drawCB,sizeCB,this);
+ }
+ return box_;
+}
+
+void xnode::drawCB(Widget w,XRectangle* r,void *data)
+{
+ if (data) ((xnode*)data)->draw(w,r);
+}
+
+void xnode::sizeCB(Widget w,XRectangle* r,void *data)
+{
+ if (data) ((xnode*)data)->size(w,r);
+}
+
+void xnode::select()
+{
+ XtVaSetValues(widget_,XtNselected,box_,NULL);
+ NodeShow(widget_,box_);
+}
diff --git a/view/src/xnode.h b/view/src/xnode.h
new file mode 100644
index 0000000..e5da6a5
--- /dev/null
+++ b/view/src/xnode.h
@@ -0,0 +1,85 @@
+#ifndef xnode_H
+#define xnode_H
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #6 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include <Xm/Xm.h>
+extern "C" {
+#include "SimpleBase.h"
+}
+
+class node;
+
+class xnode {
+public:
+ xnode(node*);
+
+ virtual ~xnode(); // Change to virtual if base class
+
+ node* get_node() { return node_; }
+
+ virtual int getBox(Widget) ;
+
+ virtual void draw(Widget,XRectangle*) = 0;
+ virtual void size(Widget,XRectangle*) = 0;
+
+ void select();
+
+ Widget widget() { return widget_; }
+
+ Boolean visibility(Boolean vis)
+ { return NodeVisibility(widget_,box_,vis); }
+
+ void relation(xnode* o)
+ { NodeAddRelation(widget_,box_,o->box_); }
+
+ void* relation_data(xnode* o)
+ { return NodeGetRelationData(widget_,box_,o->box_); }
+
+ void* relation_data(xnode* o,void *d)
+ { return NodeSetRelationData(widget_,box_,o->box_,d); }
+
+ GC relation_gc(xnode* o,GC gc)
+ { return NodeSetRelationGC(widget_,box_,o->box_,gc); }
+
+ void redraw() { NodeNewSize(widget_,box_);NodeChanged(widget_,box_); }
+ void show() { NodeShow(widget_,box_); }
+
+ void setFocus() { NodeSetFocus(widget_,box_); }
+
+ int group() { return NodeGetGroup(widget_,box_); }
+ void group(int g) { NodeSetGroup(widget_,box_,g); }
+
+ static void drawCB(Widget,XRectangle*,XtPointer);
+ static void sizeCB(Widget,XRectangle*,XtPointer);
+
+ void *operator new(size_t n) { return XtMalloc(n); }
+ void operator delete(void* d) { XtFree((char*)d); }
+
+protected:
+
+ Widget widget_;
+ node* node_;
+ int box_;
+
+private:
+
+ xnode(const xnode&);
+ xnode& operator=(const xnode&);
+};
+
+inline void destroy(xnode**) {}
+#endif
diff --git a/view/src/xresources.h b/view/src/xresources.h
new file mode 100644
index 0000000..8314957
--- /dev/null
+++ b/view/src/xresources.h
@@ -0,0 +1,659 @@
+/*=============================================================================================*/
+/* Name : */
+/* Author : */
+/* Revision : $Revision: #18 $ */
+/* */
+/* Copyright 2009-2016 ECMWF. */
+/* This software is licensed under the terms of the Apache Licence version 2.0 */
+/* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */
+/* In applying this licence, ECMWF does not waive the privileges and immunities */
+/* granted to it by virtue of its status as an intergovernmental organisation */
+/* nor does it submit to any jurisdiction. */
+/* */
+/* Description : */
+/*=============================================================================================*/
+
+#ifndef BRIDGE
+/*
+"ecFlowview.*DrawingAreaInput.baseTranslations: #augment \
+ <Key>osfUp: scroll-one-line-up()\\n\
+ <Key>osfDown: scroll-one-line-down()\\n\
+ <KeyUp>Prior: previous-page()\\n\
+ <KeyUp>Next: next-page()\\n\
+ <Key>Up: scroll-one-line-up() \\n\
+ <Key>Down: scroll-one-line-down() \\n\
+ <KeyUp>KP_Prior: previous-page()\\n\
+ <KeyUp>KP_Next: next-page()\\n\
+ <KeyUp>KP_Up: scroll-one-line-up() \\n\
+ <KeyUp>KP_Down: scroll-one-line-down() \n\
+ Shift<Btn5Down>: previous-page() \\n\
+ Shift<Btn4Down>: next-page() \\n\
+ <Btn5Down>: scroll-one-line-up() \\n\
+ <Btn4Down>: scroll-one-line-down() \n"
+"*XmSpinBox.accelerators: #augment \
+ <Btn5Down>: SpinBPrior()\\n\
+ <Btn5Up>:SpinBDisarm()\\n\
+ <Btn4Down>: SpinBNext()\\n\
+ <Btn4Up>: SpinBDisarm()\\n\
+ <Key>osfUp:SpinBNext()\\n\
+ <Key>osfDown: SpinBPrior()\\n\
+ <KeyUp>osfUp: SpinBDisarm()\\n\
+ <KeyUp>osfDown: SpinBDisarm()\\n\
+ <Key>osfLeft: SpinBLeft()\\n\
+ <Key>osfRight: SpinBRight()\\n\
+ <KeyUp>osfLeft: SpinBDisarm()\\n\
+ <KeyUp>osfRight: SpinBDisarm()\\n\
+ <Key>osfBeginLine: SpinBFirst()\\n\
+ <Key>osfEndLine: SpinBLast()\n" */
+
+static char* xresources = (char*) "\n"
+"ecFlowview*File.accelerator: Ctrl<Key>f\n"
+"ecFlowview*File.mnemonic: F\n"
+"ecFlowview*Info.accelerator: Ctrl<Key>I\n"
+"ecFlowview*Script.accelerator: Ctrl<Key>S\n"
+"ecFlowview*Manual.accelerator: Ctrl<Key>M\n"
+"ecFlowview*Jobstatus.accelerator: Ctrl<Key>j\n"
+"ecFlowview*Job.accelerator: Ctrl<Key>J\n"
+"ecFlowview*Triggers.accelerator: Ctrl<Key>T\n"
+"ecFlowview*Why?.accelerator: Ctrl<Key>y\n"
+"ecFlowview*Variables.accelerator: Ctrl<Key>V\n"
+"ecFlowview*Messages.accelerator: Ctrl<Key>M\n"
+"ecFlowview*Edit.accelerator: Ctrl<Key>E\n"
+"ecFlowview*Search.accelerator: Ctrl<Key>c\n"
+"ecFlowview*Status.accelerator: Space<Key>\n"
+"ecFlowview*Login.accelerator: Ctrl<Key>L\n"
+"ecFlowview*Login.acceleratorText: Ctrl+L\n"
+"ecFlowview*Login.mnemonic: L\n"
+"ecFlowview*Login.title: Login...\n"
+"ecFlowview*Quit.accelerator: Ctrl<Key>Q\n"
+"ecFlowview*Quit.acceleratorText: Ctrl+Q\n"
+"ecFlowview*Quit.mnemonic: Q\n"
+"ecFlowview*Edit.accelerator: Ctrl<Key>E\n"
+"ecFlowview*Edit.mnemonic: E\n"
+"ecFlowview*pref.accelerator: Ctrl<Key>e\n"
+"ecFlowview*pref.mnemonic: e\n"
+"ecFlowview*pref.title: User preferences...\n"
+
+"ecFlowview*pref_shell.title: Preferences\n"
+
+"ecFlowview*Show.accelerator: Ctrl<Key>S\n"
+"ecFlowview*Show.mnemonic: S\n"
+"ecFlowview*Servers.accelerator: Ctrl<Key>v\n"
+"ecFlowview*Servers.mnemonic: v\n"
+"ecFlowview*Windows.accelerator: Ctrl<Key>W\n"
+"ecFlowview*Windows.mnemonic: W\n"
+"ecFlowview*Help.accelerator: Ctrl<Key>H\n"
+"ecFlowview*Help.mnemonic: H\n"
+
+"ecFlowview*Version.accelerator: Ctrl<Key>V\n"
+"ecFlowview*Version.mnemonic: V\n"
+
+"ecFlowview*file_menu.labelString: File\n"
+"ecFlowview*file_menu.mnemonic: F\n"
+"ecFlowview*Option.mnemonic: O\n"
+"ecFlowview*Print*.mnemonic: P\n"
+"ecFlowview*Save*.mnemonic: S\n"
+"ecFlowview*Close.mnemonic: C\n"
+"ecFlowview*help_menu.mnemonic: H\n"
+
+"ecFlowview*snapshot.accelerator: Ctrl<Key>t\n"
+"ecFlowview*snapshot.labelString: Snapshot\n"
+
+"ecFlowview*file_menu.title: File\n"
+"ecFlowview*file_menu.accelerator: Ctrl<Key>F\n"
+
+"ecFlowview*options_menu.labelString: Options\n"
+"ecFlowview*options_menu.mnemonic: O\n"
+
+"ecFlowview.*SimpleBase.baseTranslations: #augment \
+ Shift<Btn5Down>: increment(-1) \\n\
+ Shift<Btn4Down>: increment(1) \\n\
+ <Btn5Down>: increment(-10) \\n\
+ <Btn4Down>: increment(10) \n"
+
+"ecFlowview.*Hyper.baseTranslations: #augment \
+ Shift<Btn5Down>: increment(-1) \\n\
+ Shift<Btn4Down>: increment(1) \\n\
+ <Btn5Down>: increment(-10) \\n\
+ <Btn4Down>: increment(10) \n"
+
+"ecFlowview.*XmList.baseTranslations: #augment \
+ Shift<Btn5Down>: ListNextPage() \\n\
+ Shift<Btn4Down>: ListPrevPage() \\n\
+ <Btn5Down>: ListNextItem() \\n\
+ <Btn4Down>: ListPrevItem() \n"
+
+"ecFlowview.*XmScrollBar.baseTranslations: #augment \
+ Shift<Btn5Down>: IncrementDownOrRight(0) IncrementDownOrRight(1) \\n\
+ Shift<Btn4Down>: IncrementUpOrLeft(0) IncrementUpOrLeft(1) \\n\
+ <Btn5Down>: PageDownOrRight(0) PageDownOrRight(1) \\n\
+ <Btn4Down>: PageUpOrLeft(0) PageUpOrLeft(1) \n"
+
+"ecFlowview.*XmText.baseTranslations: #augment \
+ <Key>osfUp: scroll-one-line-up()\\n\
+ <Key>osfDown: scroll-one-line-down()\\n\
+ <KeyUp>Prior: previous-page()\\n\
+ <KeyUp>Next: next-page()\\n\
+ <Key>Up: scroll-one-line-up() \\n\
+ <Key>Down: scroll-one-line-down() \\n\
+ <KeyUp>KP_Prior: previous-page()\\n\
+ <KeyUp>KP_Next: next-page()\\n\
+ <KeyUp>KP_Up: scroll-one-line-up() \\n\
+ <KeyUp>KP_Down: scroll-one-line-down() \n\
+ Shift<Btn5Down>: previous-page() \\n\
+ Shift<Btn4Down>: next-page() \\n\
+ <Btn5Down>: scroll-one-line-up() \\n\
+ <Btn4Down>: scroll-one-line-down() \n"
+
+"ecFlowview.*DrawingAreaInput.baseTranslations: #augment \
+ <Key>osfUp: scroll-one-line-up()\\n\
+ <Key>osfDown: scroll-one-line-down()\\n\
+ <KeyUp>Prior: previous-page()\\n\
+ <KeyUp>Next: next-page()\\n\
+ <Key>Up: scroll-one-line-up() \\n\
+ <Key>Down: scroll-one-line-down() \\n\
+ <KeyUp>KP_Prior: previous-page()\\n\
+ <KeyUp>KP_Next: next-page()\\n\
+ <KeyUp>KP_Up: scroll-one-line-up() \\n\
+ <KeyUp>KP_Down: scroll-one-line-down() \n\
+ Shift<Btn5Down>: previous-page() \\n\
+ Shift<Btn4Down>: next-page() \\n\
+ <Btn5Down>: increment(-10) \\n\
+ <Btn4Down>: increment(10) \n"
+"*XmSpinBox.accelerators: #augment \
+ <Btn5Down>: SpinBPrior()\\n\
+ <Btn5Up>:SpinBDisarm()\\n\
+ <Btn4Down>: SpinBNext()\\n\
+ <Btn4Up>: SpinBDisarm()\\n\
+ <Key>osfUp:SpinBNext()\\n\
+ <Key>osfDown: SpinBPrior()\\n\
+ <KeyUp>osfUp: SpinBDisarm()\\n\
+ <KeyUp>osfDown: SpinBDisarm()\\n\
+ <Key>osfLeft: SpinBLeft()\\n\
+ <Key>osfRight: SpinBRight()\\n\
+ <KeyUp>osfLeft: SpinBDisarm()\\n\
+ <KeyUp>osfRight: SpinBDisarm()\\n\
+ <Key>osfBeginLine: SpinBFirst()\\n\
+ <Key>osfEndLine: SpinBLast()\n"
+
+"ecFlowview*@zombied.labelString: Use default settings\n"
+"ecFlowview*@aliases.labelString: Use default settings\n"
+"ecFlowview*@late_family.labelString: Use default settings\n"
+"ecFlowview*zombied.labelString: Zombies\n"
+"ecFlowview*aliases.labelString: Aborted or restarted aliases\n"
+"ecFlowview*late_family.labelString: Late family\n"
+
+"ecFlowview*File.labelString: File\n"
+"ecFlowview*.XmText.background: OldLace\n"
+"ecFlowview*.XmTextField.background: OldLace\n"
+"ecFlowview*.scrollBarDisplayPolicy: STATIC\n"
+"ecFlowview*@aborted.labelString: Use default settings\n"
+"ecFlowview*@color_aborted.labelString: Use default settings\n"
+"ecFlowview*@color_active.labelString: Use default settings\n"
+"ecFlowview*@color_complete.labelString: Use default settings\n"
+"ecFlowview*@color_halted.labelString: Use default settings\n"
+"ecFlowview*@color_queued.labelString: Use default settings\n"
+"ecFlowview*@color_shutdown.labelString: Use default settings\n"
+"ecFlowview*@color_submitted.labelString: Use default settings\n"
+"ecFlowview*@color_suspended.labelString: Use default settings\n"
+"ecFlowview*@color_unknown.labelString: Use default settings\n"
+"ecFlowview*@color_meter_low.labelString: Use default settings\n"
+"ecFlowview*@color_threshold.labelString: Use default settings\n"
+"ecFlowview*@color_event.labelString: Use default settings\n"
+"ecFlowview*@direct_read.labelString: Use default settings\n"
+"ecFlowview*@drift.labelString: Use default settings\n"
+"ecFlowview*@late.labelString: Use default settings\n"
+"ecFlowview*@maximum.labelString: Use default settings\n"
+"ecFlowview*@jobfile_length.labelString: Use default settings\n"
+"ecFlowview*@new_suites.labelString: Use default settings\n"
+"ecFlowview*@normal_font_bold.labelString: Use default settings\n"
+"ecFlowview*@normal_font_plain.labelString: Use default settings\n"
+"ecFlowview*@poll.labelString: Use default settings\n"
+"ecFlowview*@restarted.labelString: Use default settings\n"
+"ecFlowview*@small_font_bold.labelString: Use default settings\n"
+"ecFlowview*@small_font_plain.labelString: Use default settings\n"
+"ecFlowview*@timeout.labelString: Use default settings\n"
+"ecFlowview*@timed_text_since.labelString: 600\n"
+"ecFlowview*@timed_text_from.labelString: 0\n"
+"ecFlowview*timed_text_from.labelString: 0\n"
+"ecFlowview*Aborted.labelString: Aborted\n"
+"ecFlowview*Active.labelString: Active\n"
+"ecFlowview*Apply.labelString: Apply\n"
+"ecFlowview*Backwards.labelString: Backwards\n"
+"ecFlowview*Colours.labelString: Colors\n"
+"ecFlowview*Complete.labelString: Complete\n"
+"ecFlowview*Get server status:.labelString: Getting server status\n"
+"ecFlowview*Hyper*highlightColor: Blue\n"
+"ecFlowview*Hyper*highlightFont: 7x13\n"
+"ecFlowview*Hyper*highlightOnEnter : false\n"
+"ecFlowview*Hyper*highlightThickness : 0\n"
+"ecFlowview*Hyper*navigationType : NONE\n"
+"ecFlowview*Hyper*normalFont: 7x13\n"
+"ecFlowview*Queued.labelString: Queued\n"
+"ecFlowview*Regular expression.labelString: Regular expression\n"
+"ecFlowview*SimpleTime.fontList: -*-*-*-*-*-*-7-*-*-*-*-*-*-*\n"
+"ecFlowview*Submitted.labelString: Submitted\n"
+"ecFlowview*Suspended.labelString: Suspended\n"
+"ecFlowview*Unknown.labelString: Unknown\n"
+"ecFlowview*Update.labelString: Update\n"
+"ecFlowview*Use external editor.labelString: External editor...\n"
+"ecFlowview*Use external viewer.labelString: External viewer...\n"
+"ecFlowview*Waiting nodes.labelString: Waiting nodes\n"
+"ecFlowview*XmList.fontList: 7x13=normal,7x13bold=bold\n"
+"ecFlowview*XmText.fontList: 7x13\n"
+"ecFlowview*XmToggleButton.fillOnSelect: true\n"
+"ecFlowview*XmToggleButton.selectColor: Blue\n"
+"ecFlowview*XmToggleButtonGadget.fillOnSelect: true\n"
+"ecFlowview*XmToggleButtonGadget.fontList: -*-helvetica-medium-r-normal-*-12-*-*-*-*-*-*-*\n"
+"ecFlowview*XmToggleButtonGadget.selectColor: Green\n"
+"ecFlowview*aborted.labelString: Aborted tasks\n"
+"ecFlowview*alias_.labelString: Send as alias\n"
+"ecFlowview*all_off.labelString: All off\n"
+"ecFlowview*all_on.labelString: All on\n"
+"ecFlowview*ask_shell.title: ask\n"
+"ecFlowview*background: #e5e5e5e5e5e5\n"
+"ecFlowview*bottomShadowColor: #7e7e7e7e7e7e\n"
+"ecFlowview*button3.labelString: Help...\n"
+"ecFlowview*button_close.labelString: Close\n"
+"ecFlowview*button_find.labelString: Find...\n"
+"ecFlowview*button_search.labelString: Search...\n"
+"ecFlowview*close.labelString: Close\n"
+"ecFlowview*close_on_apply_.labelString: Close on Apply/Submit\n"
+"ecFlowview*collector_shell.title: Collector (ctrl-click1)\n"
+ /* "ecFlowview*collector_shell.title: Collector\n" */
+"ecFlowview*confirm_shell.title: Confirm\n"
+"ecFlowview*current_node.labelString: Frozen\n"
+"ecFlowview*delete_.labelString: Delete\n"
+"ecFlowview*find_.labelString: Find\n"
+"ecFlowview*depend_shell.title: Details\n"
+"ecFlowview*dependencies_button_.labelString: Dependencies\n"
+"ecFlowview*detached_.labelString: Detached\n"
+"ecFlowview*direct_read.labelString: Read files from disk when possible.\n"
+"ecFlowview*drift.labelString: Reduce call frequency when inactive\n"
+"ecFlowview*error_shell.title: Error\n"
+"ecFlowview*find_message.fontList: -*-helvetica-bold-r-normal-*-12-*-*-*-*-*-*-*\n"
+"ecFlowview*find_message.foreground: red\n"
+"ecFlowview*find_message.labelString: -\n"
+"ecFlowview*find_shell.title: Find...\n"
+"ecFlowview*fold_around_.labelString: Fold around\n"
+"ecFlowview*XmList.fontList: 7x13=normal,7x13bold=bold\n"
+"ecFlowview*XmText.fontList: 7x13\n"
+"ecFlowview*help_menu.labelString: Help\n"
+"ecFlowview*hide_other_.labelString: Hide other suites\n"
+"ecFlowview*indicatorSize: 12\n"
+"ecFlowview*late.labelString: Late tasks\n"
+"ecFlowview*mail_shell.title: Chat\n"
+"ecFlowview*menu_fold_all.labelString: Fold all\n"
+"ecFlowview*menu_show_current.labelString: Show selected node\n"
+"ecFlowview*menu_unfold_all.accelerator: Ctrl<Key>U\n"
+"ecFlowview*menu_unfold_all.labelString: Unfold all\n"
+"ecFlowview*new_suites.labelString: Register to new suites (restart application to consider change)\n"
+"ecFlowview*new_window.labelString: New window...\n"
+"ecFlowview*optionMenu1.labelString: Action:\n"
+"ecFlowview*poll.labelString: Get server status regularly\n"
+"ecFlowview*preprocess_.labelString: Pre-process\n"
+"ecFlowview*restarted.labelString: Restarted tasks\n"
+"ecFlowview*search_shell.title: Search...\n"
+"ecFlowview*set_.labelString: Set\n"
+"ecFlowview*timeline_label.fontList : 7x13=normal,7x13bold=bold\n"
+"ecFlowview*toggle2.labelString: Limits\n"
+"ecFlowview*toggle21.labelString: Suites\n"
+"ecFlowview*toggle22.labelString: Families\n"
+"ecFlowview*toggle23.labelString: Tasks\n"
+"ecFlowview*toggle24.labelString: Aliases\n"
+"ecFlowview*toggle25.labelString: Labels\n"
+"ecFlowview*toggle26.labelString: Meters\n"
+"ecFlowview*toggle27.labelString: Events\n"
+"ecFlowview*toggle28.labelString: Repeats\n"
+"ecFlowview*toggle29.labelString: Times\n"
+"ecFlowview*toggle3.labelString: Full names\n"
+"ecFlowview*toggle3.labelString: Limiters\n"
+"ecFlowview*toggle30.labelString: Dates\n"
+"ecFlowview*toggle31.labelString: Triggers\n"
+"ecFlowview*toggle32.labelString: Variables\n"
+"ecFlowview*toggle41.labelString: Time dependent\n"
+"ecFlowview*toggle42.labelString: Late nodes\n"
+"ecFlowview*toggle43.labelString: Zombie\n"
+"ecFlowview*toggle44.labelString: Rerun tasks\n"
+"ecFlowview*toggle45.labelString: Nodes with messages\n"
+"ecFlowview*toggle66.labelString: Servers\n"
+"ecFlowview*tools_*shadowThickness:1 \n"
+"ecFlowview*topShadowColor: white\n"
+"ecFlowview*triggered.labelString: Show triggered nodes\n"
+"ecFlowview*triggers.labelString: Show triggering nodes\n"
+"ecFlowview*vname.labelString: Variable name:\n"
+"ecFlowview*vvalue.labelString: Variable value:\n"
+"ecFlowview*warn.labelString: Don't forget to hit <return> when you enter a value in a text field.\n"
+"ecFlowview*warn2.labelString: Don't forget to hit <return> when you enter a value in a text field.\n"
+"ecFlowview*what_.labelString: What:\n"
+"ecFlowview*where_.labelString: Where:\n"
+"ecFlowview*why_label_.labelString: Use the Info window...\n"
+"ecFlowview.smallFont: -*-helvetica-medium-r-normal-*-10-*-*-*-*-*-*-*\n"
+"ecFlowview.normalFont: -*-helvetica-medium-r-normal-*-12-*-*-*-*-*-*-*\n"
+"ecFlowview*tools_.Info.accelerator: I\n"
+"ecFlowview*tools_.Script.accelerator: S\n"
+"ecFlowview*tools_.Manual.accelerator: M\n"
+"ecFlowview*tools_.JobStatus.accelerator: J\n"
+"ecFlowview*tools_.Output.accelerator: O\n"
+"ecFlowview*tools_.Triggers.accelerator: T\n"
+"ecFlowview*tools_.Why?.accelerator: W\n"
+"ecFlowview*tools_.Variables.accelerator: V\n"
+"ecFlowview*tools_.Messages.accelerator: M\n"
+"ecFlowview*tools_.Edit.accelerator: E\n"
+"ecFlowview*tools_.Status.accelerator: Return<Key>\n"
+"ecFlowview*tree_.accelerator: C\n"
+"ecFlowview*tree_.accelerator: Z\n"
+"ecFlowview*tree_.baseTranslations: #augment \
+C: collector::show(selection::current_node())\\n\
+A: selection::notify_new_selection(0)\\n\
+"
+
+;
+
+#else
+
+static char* xresources = (char*) "\n"
+"XCdp*File.accelerator: Ctrl<Key>f\n"
+"XCdp*File.mnemonic: F\n"
+"XCdp*Info.accelerator: Ctrl<Key>I\n"
+"XCdp*Script.accelerator: Ctrl<Key>S\n"
+"XCdp*Manual.accelerator: Ctrl<Key>M\n"
+"XCdp*Jobstatus.accelerator: Ctrl<Key>j\n"
+"XCdp*Job.accelerator: Ctrl<Key>J\n"
+"XCdp*Triggers.accelerator: Ctrl<Key>T\n"
+"XCdp*Why?.accelerator: Ctrl<Key>y\n"
+"XCdp*Variables.accelerator: Ctrl<Key>V\n"
+"XCdp*Messages.accelerator: Ctrl<Key>M\n"
+"XCdp*Edit.accelerator: Ctrl<Key>E\n"
+"XCdp*Search.accelerator: Ctrl<Key>c\n"
+"XCdp*Status.accelerator: Space<Key>\n"
+"XCdp*Login.accelerator: Ctrl<Key>L\n"
+"XCdp*Login.acceleratorText: Ctrl+L\n"
+"XCdp*Login.mnemonic: L\n"
+"XCdp*Login.title: Login...\n"
+"XCdp*Quit.accelerator: Ctrl<Key>Q\n"
+"XCdp*Quit.acceleratorText: Ctrl+Q\n"
+"XCdp*Quit.mnemonic: Q\n"
+"XCdp*Edit.accelerator: Ctrl<Key>E\n"
+"XCdp*Edit.mnemonic: E\n"
+"XCdp*pref.accelerator: Ctrl<Key>e\n"
+"XCdp*pref.mnemonic: e\n"
+"XCdp*pref.title: User preferences...\n"
+
+"XCdp*pref_shell.title: Preferences\n"
+
+"XCdp*Show.accelerator: Ctrl<Key>S\n"
+"XCdp*Show.mnemonic: S\n"
+"XCdp*Servers.accelerator: Ctrl<Key>v\n"
+"XCdp*Servers.mnemonic: v\n"
+"XCdp*Windows.accelerator: Ctrl<Key>W\n"
+"XCdp*Windows.mnemonic: W\n"
+"XCdp*Help.accelerator: Ctrl<Key>H\n"
+"XCdp*Help.mnemonic: H\n"
+
+"XCdp*Version.accelerator: Ctrl<Key>V\n"
+"XCdp*Version.mnemonic: V\n"
+
+"XCdp*file_menu.labelString: File\n"
+"XCdp*file_menu.mnemonic: F\n"
+"XCdp*Option.mnemonic: O\n"
+"XCdp*Print*.mnemonic: P\n"
+"XCdp*Save*.mnemonic: S\n"
+"XCdp*close.mnemonic: C\n"
+"XCdp*help_menu.mnemonic: H\n"
+
+"XCdp*snapshot.accelerator: Ctrl<Key>t\n"
+"XCdp*snapshot.labelString: Snapshot\n"
+
+"XCdp*file_menu.title: File\n"
+"XCdp*file_menu.accelerator: Ctrl<Key>F\n"
+
+"XCdp*options_menu.labelString: Options\n"
+"XCdp*options_menu.mnemonic: O\n"
+
+"XCdp.*SimpleBase.baseTranslations: #augment \
+ Shift<Btn5Down>: increment(-1) \\n\
+ Shift<Btn4Down>: increment(1) \\n\
+ <Btn5Down>: increment(-10) \\n\
+ <Btn4Down>: increment(10) \n"
+
+"XCdp.*Hyper.baseTranslations: #augment \
+ Shift<Btn5Down>: increment(-1) \\n\
+ Shift<Btn4Down>: increment(1) \\n\
+ <Btn5Down>: increment(-10) \\n\
+ <Btn4Down>: increment(10) \n"
+
+"XCdp.*XmList.baseTranslations: #augment \
+ Shift<Btn5Down>: ListNextPage() \\n\
+ Shift<Btn4Down>: ListPrevPage() \\n\
+ <Btn5Down>: ListNextItem() \\n\
+ <Btn4Down>: ListPrevItem() \n"
+
+"XCdp.*XmScrollBar.baseTranslations: #augment \
+ Shift<Btn5Down>: IncrementDownOrRight(0) IncrementDownOrRight(1) \\n\
+ Shift<Btn4Down>: IncrementUpOrLeft(0) IncrementUpOrLeft(1) \\n\
+ <Btn5Down>: PageDownOrRight(0) PageDownOrRight(1) \\n\
+ <Btn4Down>: PageUpOrLeft(0) PageUpOrLeft(1) \n"
+
+"XCdp.*XmText.baseTranslations: #augment \
+ <Key>osfUp: scroll-one-line-up()\\n\
+ <Key>osfDown: scroll-one-line-down()\\n\
+ <KeyUp>Prior: previous-page()\\n\
+ <KeyUp>Next: next-page()\\n\
+ <Key>Up: scroll-one-line-up() \\n\
+ <Key>Down: scroll-one-line-down() \\n\
+ <KeyUp>KP_Prior: previous-page()\\n\
+ <KeyUp>KP_Next: next-page()\\n\
+ <KeyUp>KP_Up: scroll-one-line-up() \\n\
+ <KeyUp>KP_Down: scroll-one-line-down() \n\
+ Shift<Btn5Down>: previous-page() \\n\
+ Shift<Btn4Down>: next-page() \\n\
+ <Btn5Down>: scroll-one-line-up() \\n\
+ <Btn4Down>: scroll-one-line-down() \n"
+
+"XCdp.*DrawingAreaInput.baseTranslations: #augment \
+ <Key>osfUp: scroll-one-line-up()\\n\
+ <Key>osfDown: scroll-one-line-down()\\n\
+ <KeyUp>Prior: previous-page()\\n\
+ <KeyUp>Next: next-page()\\n\
+ <Key>Up: scroll-one-line-up() \\n\
+ <Key>Down: scroll-one-line-down() \\n\
+ <KeyUp>KP_Prior: previous-page()\\n\
+ <KeyUp>KP_Next: next-page()\\n\
+ <KeyUp>KP_Up: scroll-one-line-up() \\n\
+ <KeyUp>KP_Down: scroll-one-line-down() \n\
+ Shift<Btn5Down>: previous-page() \\n\
+ Shift<Btn4Down>: next-page() \\n\
+ <Btn5Down>: scroll-one-line-up() \\n\
+ <Btn4Down>: scroll-one-line-down() \n"
+
+"*XmSpinBox.accelerators: #augment \
+ <Btn5Down>: SpinBPrior()\\n\
+ <Btn5Up>:SpinBDisarm()\\n\
+ <Btn4Down>: SpinBNext()\\n\
+ <Btn4Up>: SpinBDisarm()\\n\
+ <Key>osfUp:SpinBNext()\\n\
+ <Key>osfDown: SpinBPrior()\\n\
+ <KeyUp>osfUp: SpinBDisarm()\\n\
+ <KeyUp>osfDown: SpinBDisarm()\\n\
+ <Key>osfLeft: SpinBLeft()\\n\
+ <Key>osfRight: SpinBRight()\\n\
+ <KeyUp>osfLeft: SpinBDisarm()\\n\
+ <KeyUp>osfRight: SpinBDisarm()\\n\
+ <Key>osfBeginLine: SpinBFirst()\\n\
+ <Key>osfEndLine: SpinBLast()\n"
+
+"XCdp*@zombied.labelString: Use default settings\n"
+"XCdp*@aliases.labelString: Use default settings\n"
+"XCdp*@late_family.labelString: Use default settings\n"
+"XCdp*zombied.labelString: Zombies\n"
+"XCdp*aliases.labelString: Aborted or restarted aliases\n"
+"XCdp*late_family.labelString: Late family\n"
+
+"XCdp*File.labelString: File\n"
+"XCdp*.XmText.background: OldLace\n"
+"XCdp*.XmTextField.background: OldLace\n"
+"XCdp*.scrollBarDisplayPolicy: STATIC\n"
+"XCdp*@aborted.labelString: Use default settings\n"
+"XCdp*@color_aborted.labelString: Use default settings\n"
+"XCdp*@color_active.labelString: Use default settings\n"
+"XCdp*@color_complete.labelString: Use default settings\n"
+"XCdp*@color_halted.labelString: Use default settings\n"
+"XCdp*@color_queued.labelString: Use default settings\n"
+"XCdp*@color_shutdown.labelString: Use default settings\n"
+"XCdp*@color_submitted.labelString: Use default settings\n"
+"XCdp*@color_suspended.labelString: Use default settings\n"
+"XCdp*@color_unknown.labelString: Use default settings\n"
+"XCdp*@color_meter_low.labelString: Use default settings\n"
+"XCdp*@color_threshold.labelString: Use default settings\n"
+"XCdp*@color_event.labelString: Use default settings\n"
+"XCdp*@direct_read.labelString: Use default settings\n"
+"XCdp*@drift.labelString: Use default settings\n"
+"XCdp*@late.labelString: Use default settings\n"
+"XCdp*@maximum.labelString: Use default settings\n"
+"XCdp*@jobfile_length.labelString: Use default settings\n"
+"XCdp*@new_suites.labelString: Use default settings\n"
+"XCdp*@normal_font_bold.labelString: Use default settings\n"
+"XCdp*@normal_font_plain.labelString: Use default settings\n"
+"XCdp*@poll.labelString: Use default settings\n"
+"XCdp*@restarted.labelString: Use default settings\n"
+"XCdp*@small_font_bold.labelString: Use default settings\n"
+"XCdp*@small_font_plain.labelString: Use default settings\n"
+"XCdp*@timeout.labelString: Use default settings\n"
+"XCdp*Aborted.labelString: Aborted\n"
+"XCdp*Active.labelString: Active\n"
+"XCdp*Apply.labelString: Apply\n"
+"XCdp*Backwards.labelString: Backwards\n"
+"XCdp*Colours.labelString: Colors\n"
+"XCdp*Complete.labelString: Complete\n"
+"XCdp*Get server status:.labelString: Getting server status\n"
+"XCdp*Hyper*highlightColor: Blue\n"
+"XCdp*Hyper*highlightFont: 7x13\n"
+"XCdp*Hyper*highlightOnEnter : false\n"
+"XCdp*Hyper*highlightThickness : 0\n"
+"XCdp*Hyper*navigationType : NONE\n"
+"XCdp*Hyper*normalFont: 7x13\n"
+"XCdp*Queued.labelString: Queued\n"
+"XCdp*Regular expression.labelString: Regular expression\n"
+"XCdp*SimpleTime.fontList: -*-*-*-*-*-*-7-*-*-*-*-*-*-*\n"
+"XCdp*Submitted.labelString: Submitted\n"
+"XCdp*Suspended.labelString: Suspended\n"
+"XCdp*Unknown.labelString: Unknown\n"
+"XCdp*Update.labelString: Update\n"
+"XCdp*Use external editor.labelString: External editor...\n"
+"XCdp*Use external viewer.labelString: External viewer...\n"
+"XCdp*Waiting nodes.labelString: Waiting nodes\n"
+"XCdp*XmToggleButton.fillOnSelect: true\n"
+"XCdp*XmToggleButton.selectColor: Blue\n"
+"XCdp*XmToggleButtonGadget.fillOnSelect: true\n"
+"XCdp*XmToggleButtonGadget.fontList:-*-helvetica-normal-r-normal-*-12-*-*-*-*-*-*-*\n"
+"XCdp*XmToggleButtonGadget.selectColor: Green\n"
+"XCdp*aborted.labelString: Aborted tasks\n"
+"XCdp*alias_.labelString: Send as alias\n"
+"XCdp*all_off.labelString: All off\n"
+"XCdp*all_on.labelString: All on\n"
+"XCdp*ask_shell.title: ask\n"
+"XCdp*background: #e5e5e5e5e5e5\n"
+"XCdp*bottomShadowColor: #7e7e7e7e7e7e\n"
+"XCdp*button3.labelString: Help...\n"
+"XCdp*button_close.labelString: Close\n"
+"XCdp*button_find.labelString: Find...\n"
+"XCdp*button_search.labelString: Search...\n"
+"XCdp*close.labelString: Close\n"
+"XCdp*close_on_apply_.labelString: Close on Apply/Submit\n"
+"XCdp*collector_shell.title: Collector (ctrl-click1)\n"
+ /* "XCdp*collector_shell.title: Collector\n" */
+"XCdp*confirm_shell.title: Confirm\n"
+"XCdp*current_node.labelString: Frozen\n"
+"XCdp*delete_.labelString: Delete\n"
+"XCdp*find_.labelString: Find\n"
+"XCdp*depend_shell.title: Details\n"
+"XCdp*dependencies_button_.labelString: Dependencies\n"
+"XCdp*detached_.labelString: Detached\n"
+"XCdp*direct_read.labelString: Read output and other files from disk when possible.\n"
+"XCdp*drift.labelString: Reduce call frequency when inactive\n"
+"XCdp*error_shell.title: Error\n"
+"XCdp*find_message.fontList:-*-helvetica-bold-*-normal-*-12-*-*-*-*-*-*-*\n"
+"XCdp*find_message.foreground: red\n"
+"XCdp*find_message.labelString: -\n"
+"XCdp*find_shell.title: Find...\n"
+"XCdp*fold_around_.labelString: Fold around\n"
+"XCdp*XmList.fontList: 7x13=normal,7x13bold=bold\n"
+"XCdp*XmText.fontList: 7x13\n"
+"XCdp*XmText.font*: -*-helvetica-medium-*-normal-*-12-*-*-*-*-*-*-*\n"
+"XCdp*fontList: -*-helvetica-normal-r-normal-*-12-*-*-*-*-*-*-*\n"
+"XCdp*help_menu.labelString: Help\n"
+"XCdp*hide_other_.labelString: Hide other suites\n"
+"XCdp*indicatorSize: 12\n"
+"XCdp*late.labelString: Late tasks\n"
+"XCdp*mail_shell.title: Chat\n"
+"XCdp*menu_fold_all.labelString: Fold all\n"
+"XCdp*menu_show_current.labelString: Show selected node\n"
+"XCdp*menu_unfold_all.accelerator: Ctrl<Key>U\n"
+"XCdp*menu_unfold_all.labelString: Unfold all\n"
+"XCdp*new_suites.labelString: Register to new suites\n"
+"XCdp*new_window.labelString: New window...\n"
+"XCdp*optionMenu1.labelString: Action:\n"
+"XCdp*poll.labelString: Get server status regularly\n"
+"XCdp*preprocess_.labelString: Pre-process\n"
+"XCdp*restarted.labelString: Restarted tasks\n"
+"XCdp*search_shell.title: Search...\n"
+"XCdp*set_.labelString: Set\n"
+"XCdp*timeline_label.fontList : 7x13=normal,7x13bold=bold\n"
+"XCdp*toggle2.labelString: Limits\n"
+"XCdp*toggle21.labelString: Suites\n"
+"XCdp*toggle22.labelString: Families\n"
+"XCdp*toggle23.labelString: Tasks\n"
+"XCdp*toggle24.labelString: Aliases\n"
+"XCdp*toggle25.labelString: Labels\n"
+"XCdp*toggle26.labelString: Meters\n"
+"XCdp*toggle27.labelString: Events\n"
+"XCdp*toggle28.labelString: Repeats\n"
+"XCdp*toggle29.labelString: Times\n"
+"XCdp*toggle3.labelString: Full names\n"
+"XCdp*toggle3.labelString: Limiters\n"
+"XCdp*toggle30.labelString: Dates\n"
+"XCdp*toggle31.labelString: Triggers\n"
+"XCdp*toggle32.labelString: Variables\n"
+"XCdp*toggle41.labelString: Time dependent\n"
+"XCdp*toggle42.labelString: Late nodes\n"
+"XCdp*toggle43.labelString: Zombie\n"
+"XCdp*toggle44.labelString: Rerun tasks\n"
+"XCdp*toggle45.labelString: Nodes with messages\n"
+"XCdp*toggle66.labelString: Servers\n"
+"XCdp*tools_*shadowThickness:1 \n"
+"XCdp*topShadowColor: white\n"
+"XCdp*triggered.labelString: Show triggered nodes\n"
+"XCdp*triggers.labelString: Show triggering nodes\n"
+"XCdp*vname.labelString: Variable name:\n"
+"XCdp*vvalue.labelString: Variable value:\n"
+"XCdp*warn.labelString: Don't forget to hit <return> when you enter a value in a text field.\n"
+"XCdp*warn2.labelString: Don't forget to hit <return> when you enter a value in a text field.\n"
+"XCdp*what_.labelString: What:\n"
+"XCdp*where_.labelString: Where:\n"
+"XCdp*why_label_.labelString: Use the Info window...\n"
+"XCdp.smallFont: -*-helvetica-medium-r-normal-*-11-*-*-*-*-*-*-*\n"
+"XCdp*tools_.Info.accelerator: I\n"
+"XCdp*tools_.Script.accelerator: S\n"
+"XCdp*tools_.Manual.accelerator: M\n"
+"XCdp*tools_.JobStatus.accelerator: J\n"
+"XCdp*tools_.Output.accelerator: O\n"
+"XCdp*tools_.Triggers.accelerator: T\n"
+"XCdp*tools_.Why?.accelerator: W\n"
+"XCdp*tools_.Variables.accelerator: V\n"
+"XCdp*tools_.Messages.accelerator: M\n"
+"XCdp*tools_.Edit.accelerator: E\n"
+"XCdp*tools_.Status.accelerator: Return<Key>\n"
+"XCdp*tree_.accelerator: C\n"
+"XCdp*tree_.accelerator: Z\n"
+"XCdp*tree_.baseTranslations: #augment \
+C: collector::show(selection::current_node())\\n\
+A: selection::notify_new_selection(0)\\n\
+"
+
+;
+
+/*
+ xrdb -merge ~/.Xdefaults
+*/
+#endif
diff --git a/view/src/zombie.h b/view/src/zombie.h
new file mode 100644
index 0000000..dbd14df
--- /dev/null
+++ b/view/src/zombie.h
@@ -0,0 +1,39 @@
+#ifndef zombie_H
+#define zombie_H
+
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #3 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "node_alert.h"
+#include "node.h"
+
+class zombie : public node_alert<zombie> {
+public:
+ zombie() ;
+ ~zombie();
+
+private:
+
+ zombie(const zombie&);
+ zombie& operator=(const zombie&);
+
+ virtual bool keep(node* n); // { return n->isZombie(); }
+
+};
+
+inline void destroy(zombie**) {}
+
+#endif
diff --git a/view/src/zombies_panel.cc b/view/src/zombies_panel.cc
new file mode 100644
index 0000000..1dbe347
--- /dev/null
+++ b/view/src/zombies_panel.cc
@@ -0,0 +1,125 @@
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #11 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+
+#include "zombies_panel.h"
+#include "node.h"
+#include "host.h"
+#include "ecflowview.h"
+#include <Xm/Label.h>
+#include <Xm/Text.h>
+#include <Xm/List.h>
+extern "C" {
+#include "xec.h"
+}
+// #include <sstream>
+
+zombies_panel::zombies_panel(panel_window& w):
+ panel(w),
+ name_(0)
+{
+}
+
+zombies_panel::~zombies_panel()
+{
+ XtFree(name_);
+}
+
+void zombies_panel::create (Widget parent, char *widget_name )
+{
+ zombies_form_c::create(parent,widget_name);
+}
+
+void zombies_panel::clear()
+{
+ selection_.clear();
+ XmListDeleteAllItems(list_);
+ XtSetSensitive(buttons_,False);
+}
+
+void zombies_panel::show(node& n)
+{
+ std::vector<std::string> list;
+ if (!n.serv().get_zombies_list(list)) {
+ return;
+ }
+ clear();
+
+ xec_AddFontListItem(list_,(char*)list[0].c_str(),true);
+ for(unsigned int i= 1; i < list.size(); ++i)
+ xec_AddListItem(list_,(char*)list[i].c_str());
+}
+
+
+Boolean zombies_panel::enabled(node& n)
+{
+ return n.type() == NODE_SUPER;
+}
+
+
+void zombies_panel::browseCB( Widget, XtPointer data)
+{
+ XmListCallbackStruct *cb = (XmListCallbackStruct *) data;
+ char *p = xec_GetString(cb->item);
+ if(name_) XtFree(name_);
+ name_ = XtNewString(node::find_name(p));
+ if (name_)
+ selection_.insert(name_);
+ XtSetSensitive(buttons_,name_ != 0);
+ XtFree(p);
+}
+
+void zombies_panel::deleteCB( Widget, XtPointer data)
+{
+ call(ZOMBIE_DELETE, data);
+}
+
+void zombies_panel::acceptCB( Widget, XtPointer data)
+{
+ call(ZOMBIE_FOB, data);
+}
+
+void zombies_panel::rescueCB( Widget, XtPointer data)
+{
+ call(ZOMBIE_RESCUE, data);
+}
+
+void zombies_panel::terminateCB( Widget, XtPointer data)
+{
+ call(ZOMBIE_FAIL, data);
+}
+
+void zombies_panel::killCB( Widget, XtPointer data)
+{
+ call(ZOMBIE_KILL, data);
+}
+
+void zombies_panel::call(int mode, XtPointer data)
+{
+ if(!name_)
+ XtSetSensitive(buttons_,false);
+
+ if(get_node()) {
+ std::set<std::string>::const_iterator item;
+ for (item = selection_.begin(); item != selection_.end(); ++item)
+ get_node()->serv().zombies(mode, (*item).c_str());
+
+ } else
+ clear();
+
+ post_update();
+}
+
+// static panel_maker<zombies_panel> maker(PANEL_ZOMBIES);
diff --git a/view/src/zombies_panel.h b/view/src/zombies_panel.h
new file mode 100644
index 0000000..0b1adf8
--- /dev/null
+++ b/view/src/zombies_panel.h
@@ -0,0 +1,62 @@
+#ifndef zombies_panel_H
+#define zombies_panel_H
+
+#include "uizombies.h"
+
+#ifndef panel_H
+#include "panel.h"
+#endif
+
+#include <set>
+
+//=============================================================================================
+// Name :
+// Author :
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//=============================================================================================
+
+class zombies_panel : public panel, public zombies_form_c {
+public:
+
+ zombies_panel(panel_window&);
+
+ ~zombies_panel(); // Change to virtual if base class
+
+ virtual const char* name() const { return "Zombies"; }
+ virtual void show(node&);
+ virtual void clear();
+ virtual Boolean enabled(node&);
+ virtual Widget widget() { return zombies_form_c::xd_rootwidget(); }
+
+ virtual void create (Widget parent, char *widget_name = NULL);
+
+private:
+
+ zombies_panel(const zombies_panel&);
+ zombies_panel& operator=(const zombies_panel&);
+
+ char* name_;
+
+ void call(int, XtPointer);
+
+ virtual void browseCB( Widget, XtPointer );
+ virtual void deleteCB( Widget, XtPointer );
+ virtual void acceptCB( Widget, XtPointer );
+ virtual void rescueCB( Widget, XtPointer );
+ virtual void terminateCB( Widget, XtPointer );
+ virtual void killCB( Widget, XtPointer );
+
+ std::set<std::string> selection_;
+};
+
+inline void destroy(zombies_panel**) {}
+#endif
diff --git a/view/test/TestRunner.cpp b/view/test/TestRunner.cpp
new file mode 100644
index 0000000..d25157c
--- /dev/null
+++ b/view/test/TestRunner.cpp
@@ -0,0 +1,21 @@
+#define BOOST_TEST_MODULE TestView
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #4 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description :
+//============================================================================
+#include "ViewTestFixture.hpp"
+#include <boost/test/unit_test.hpp>
+
+// Global test fixture. Dues to boost deficiency this can't be accessed. hence
+// TestFixture makes use of global data.
+BOOST_GLOBAL_FIXTURE( ViewTestFixture );
diff --git a/view/test/TestView.cpp b/view/test/TestView.cpp
new file mode 100644
index 0000000..3e563ac
--- /dev/null
+++ b/view/test/TestView.cpp
@@ -0,0 +1,128 @@
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #5 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//============================================================================
+#include <iostream>
+#include <limits> // for std::numeric_limits<int>::max()
+#include <fstream>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <fcntl.h>
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/path.hpp"
+#include <boost/test/unit_test.hpp>
+#include "ServerTestHarness.hpp"
+#include "TestFixture.hpp"
+#include "DurationTimer.hpp"
+#include "Defs.hpp"
+#include "Suite.hpp"
+#include "Family.hpp"
+#include "Task.hpp"
+#include "File.hpp"
+
+using namespace std;
+using namespace ecf;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE( TestView )
+
+static std::string ECFLOWVIEW_NAME = "ecflowview";
+
+std::string find_ecflowview_path()
+{
+ std::string binDir;
+ fs::path current_path = fs::current_path();
+ if ( current_path.stem() == "Test"
+ || current_path.stem() == "view")
+ binDir = "../view/bin/";
+ else binDir = "view/bin/";
+
+ // We have 3 variants debug,release,profile
+#ifdef DEBUG
+ return File::findPath( binDir, ECFLOWVIEW_NAME, "debug" );
+#else
+ std::string path = File::findPath( binDir, ECFLOWVIEW_NAME, "release" );
+ if (path.empty()) {
+ path = File::findPath( binDir, ECFLOWVIEW_NAME, "profile" );
+ }
+ return path;
+#endif
+}
+
+void send_cmd(int fd, char* cmd) {
+ std::cout << cmd;
+ write(fd, cmd, strlen(cmd));
+ ::sleep(2);
+}
+
+BOOST_AUTO_TEST_CASE( test_view )
+{
+ DurationTimer timer;
+ cout << "View:: ...test_view\n"<< flush;
+
+ std::string theViewInvokePath = find_ecflowview_path();
+ if (theViewInvokePath.empty()) {
+ std::cout << "ecflowview is not generated, test stops silently\n";
+ return;
+ }
+
+ Defs theDefs; {
+ suite_ptr suite = theDefs.add_suite( "test_view" ) ;
+ suite->add_variable("SLEEPTIME","0");
+ task_ptr task_a = suite->add_task("task_a");
+ task_a->addMeter( Meter("meter",0,20,20) );
+ task_a->addEvent( Event(1,"event") );
+ task_a->addLabel( Label("task_a_label","Label1") );
+ }
+
+ // Start server if not already started, load the defs, and start playing
+ // The test harness will create corresponding directory structure & default ecf file
+ ServerTestHarness serverTestHarness;
+ serverTestHarness.run(theDefs,
+ ServerTestHarness::testDataDefsLocation("test_view.def"),
+ 30, // timeout
+ false // do not wait for test completion
+ );
+
+ // Ecflowview set up
+ std::string HOME = getenv("HOME");
+ std::string rcdir = HOME + "/.ecflowrc_test";
+ if ( !fs::exists( rcdir ) ) fs::create_directory(rcdir);
+
+ std::string pipename = "/tmp/ecflowview_pipe";
+ std::string servers = rcdir + "/servers";
+ std::string options = rcdir + "/localhost.options";
+
+ std::string cmd = "echo localhost localhost ${ECF_PORT:-3141} > " + servers;
+ cmd += "\necho -e 'connect:false\nsuites: test_view\n' > " + options;
+ cmd += "\nexport ECFLOWVIEW_INPUT=" + pipename + " ECFLOWRC=" + rcdir;
+ cmd += "\nif [ ! -p $ECFLOWVIEW_INPUT ]; then rm -f $ECFLOWVIEW_INPUT; mknod $ECFLOWVIEW_INPUT p; fi;\n";
+ cmd += theViewInvokePath;
+ cmd += "&";
+
+// std::cout << cmd;
+ if ( system( cmd.c_str() ) != 0) assert(false); // failed
+ ::sleep(2);
+ int fd = open(pipename.c_str(), O_WRONLY);
+ send_cmd(fd, (char*)"login localhost\n");
+ send_cmd(fd, (char*)"logout localhost\n");
+ send_cmd(fd, (char*)"quit\n");
+
+ // remove generated data
+ fs::remove(pipename.c_str());
+ fs::remove_all(rcdir);
+ fs::remove_all(TestFixture::smshome());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/view/test/ViewTestFixture.hpp b/view/test/ViewTestFixture.hpp
new file mode 100644
index 0000000..eff7cf8
--- /dev/null
+++ b/view/test/ViewTestFixture.hpp
@@ -0,0 +1,33 @@
+#ifndef VIEWTESTFIXTURE_HPP_
+#define VIEWTESTFIXTURE_HPP_
+//============================================================================
+// Name :
+// Author : Avi
+// Revision : $Revision: #13 $
+//
+// Copyright 2009-2016 ECMWF.
+// This software is licensed under the terms of the Apache Licence version 2.0
+// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+// In applying this licence, ECMWF does not waive the privileges and immunities
+// granted to it by virtue of its status as an intergovernmental organisation
+// nor does it submit to any jurisdiction.
+//
+// Description : This Fixture facilitates the test of client/server on different platforms
+//
+//============================================================================
+
+#include <string>
+#include "TestFixture.hpp"
+class Defs;
+
+struct ViewTestFixture : public TestFixture {
+
+ // Constructor will invoke the server, destructor will kill the server
+ // Since this class is static, the constructor/destructor can not call
+ // any of BOOST MACRO, since the unit test will not be there.
+ // When running across platforms will will assume server is already running
+ ViewTestFixture() : TestFixture("view") {}
+ ~ViewTestFixture() {}
+};
+
+#endif
diff --git a/ecflow_4_0_7/view/test/test_flags.sh b/view/test/test_flags.sh
similarity index 100%
rename from ecflow_4_0_7/view/test/test_flags.sh
rename to view/test/test_flags.sh
diff --git a/ecflow_4_0_7/view/tool/reload.sdef b/view/tool/reload.sdef
similarity index 100%
rename from ecflow_4_0_7/view/tool/reload.sdef
rename to view/tool/reload.sdef
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/ecflow.git
More information about the debian-science-commits
mailing list